summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:13:47 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:13:47 +0000
commit102b0d2daa97dae68d3eed54d8fe37a9cc38a892 (patch)
treebcf648efac40ca6139842707f0eba5a4496a6dd2
parentInitial commit. (diff)
downloadarm-trusted-firmware-102b0d2daa97dae68d3eed54d8fe37a9cc38a892.tar.xz
arm-trusted-firmware-102b0d2daa97dae68d3eed54d8fe37a9cc38a892.zip
Adding upstream version 2.8.0+dfsg.upstream/2.8.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--.checkpatch.conf91
-rw-r--r--.commitlintrc.js73
-rw-r--r--.cz.json3
-rw-r--r--.editorconfig72
-rw-r--r--.gitignore51
-rw-r--r--.gitreview5
-rw-r--r--.husky/.gitignore1
-rwxr-xr-x.husky/commit-msg7
-rwxr-xr-x.husky/commit-msg.commitlint3
-rwxr-xr-x.husky/commit-msg.gerrit194
-rwxr-xr-x.husky/prepare-commit-msg6
-rwxr-xr-x.husky/prepare-commit-msg.cz28
-rw-r--r--.nvmrc1
-rw-r--r--.versionrc.js113
-rw-r--r--Makefile1594
-rw-r--r--bl1/aarch32/bl1_arch_setup.c15
-rw-r--r--bl1/aarch32/bl1_context_mgmt.c172
-rw-r--r--bl1/aarch32/bl1_entrypoint.S99
-rw-r--r--bl1/aarch32/bl1_exceptions.S165
-rw-r--r--bl1/aarch64/bl1_arch_setup.c35
-rw-r--r--bl1/aarch64/bl1_context_mgmt.c131
-rw-r--r--bl1/aarch64/bl1_entrypoint.S108
-rw-r--r--bl1/aarch64/bl1_exceptions.S289
-rw-r--r--bl1/bl1.ld.S149
-rw-r--r--bl1/bl1.mk32
-rw-r--r--bl1/bl1_fwu.c745
-rw-r--r--bl1/bl1_main.c287
-rw-r--r--bl1/bl1_private.h34
-rw-r--r--bl1/tbbr/tbbr_img_desc.c65
-rw-r--r--bl2/aarch32/bl2_arch_setup.c16
-rw-r--r--bl2/aarch32/bl2_el3_entrypoint.S57
-rw-r--r--bl2/aarch32/bl2_el3_exceptions.S21
-rw-r--r--bl2/aarch32/bl2_entrypoint.S136
-rw-r--r--bl2/aarch32/bl2_run_next_image.S46
-rw-r--r--bl2/aarch64/bl2_arch_setup.c19
-rw-r--r--bl2/aarch64/bl2_el3_entrypoint.S72
-rw-r--r--bl2/aarch64/bl2_el3_exceptions.S131
-rw-r--r--bl2/aarch64/bl2_entrypoint.S141
-rw-r--r--bl2/aarch64/bl2_rme_entrypoint.S67
-rw-r--r--bl2/aarch64/bl2_run_next_image.S45
-rw-r--r--bl2/bl2.ld.S125
-rw-r--r--bl2/bl2.mk50
-rw-r--r--bl2/bl2_el3.ld.S187
-rw-r--r--bl2/bl2_image_load_v2.c110
-rw-r--r--bl2/bl2_main.c149
-rw-r--r--bl2/bl2_private.h24
-rw-r--r--bl2u/aarch32/bl2u_entrypoint.S127
-rw-r--r--bl2u/aarch64/bl2u_entrypoint.S129
-rw-r--r--bl2u/bl2u.ld.S118
-rw-r--r--bl2u/bl2u.mk15
-rw-r--r--bl2u/bl2u_main.c65
-rw-r--r--bl31/aarch64/bl31_entrypoint.S242
-rw-r--r--bl31/aarch64/crash_reporting.S477
-rw-r--r--bl31/aarch64/ea_delegate.S320
-rw-r--r--bl31/aarch64/runtime_exceptions.S631
-rw-r--r--bl31/bl31.ld.S199
-rw-r--r--bl31/bl31.mk179
-rw-r--r--bl31/bl31_context_mgmt.c66
-rw-r--r--bl31/bl31_main.c292
-rw-r--r--bl31/ehf.c533
-rw-r--r--bl31/interrupt_mgmt.c227
-rw-r--r--bl32/optee/optee.mk15
-rw-r--r--bl32/sp_min/aarch32/entrypoint.S382
-rw-r--r--bl32/sp_min/sp_min.ld.S150
-rw-r--r--bl32/sp_min/sp_min.mk77
-rw-r--r--bl32/sp_min/sp_min_main.c249
-rw-r--r--bl32/sp_min/sp_min_private.h14
-rw-r--r--bl32/sp_min/wa_cve_2017_5715_bpiall.S74
-rw-r--r--bl32/sp_min/wa_cve_2017_5715_icache_inv.S75
-rw-r--r--bl32/tsp/aarch64/tsp_entrypoint.S489
-rw-r--r--bl32/tsp/aarch64/tsp_exceptions.S162
-rw-r--r--bl32/tsp/aarch64/tsp_request.S30
-rw-r--r--bl32/tsp/ffa_helpers.c250
-rw-r--r--bl32/tsp/ffa_helpers.h116
-rw-r--r--bl32/tsp/tsp.ld.S123
-rw-r--r--bl32/tsp/tsp.mk43
-rw-r--r--bl32/tsp/tsp_common.c156
-rw-r--r--bl32/tsp/tsp_ffa_main.c655
-rw-r--r--bl32/tsp/tsp_interrupt.c115
-rw-r--r--bl32/tsp/tsp_main.c286
-rw-r--r--bl32/tsp/tsp_private.h145
-rw-r--r--bl32/tsp/tsp_timer.c91
-rw-r--r--changelog.yaml1272
-rw-r--r--common/aarch32/debug.S239
-rw-r--r--common/aarch64/debug.S221
-rw-r--r--common/aarch64/early_exceptions.S129
-rw-r--r--common/backtrace/backtrace.c266
-rw-r--r--common/backtrace/backtrace.mk31
-rw-r--r--common/bl_common.c280
-rw-r--r--common/desc_image_load.c351
-rw-r--r--common/fdt_fixup.c626
-rw-r--r--common/fdt_wrappers.c641
-rw-r--r--common/fdt_wrappers.mk7
-rw-r--r--common/feat_detect.c334
-rw-r--r--common/image_decompress.c80
-rw-r--r--common/runtime_svc.c154
-rw-r--r--common/tf_crc32.c45
-rw-r--r--common/tf_log.c79
-rw-r--r--common/uuid.c158
-rw-r--r--dco.txt37
-rw-r--r--docs/Makefile25
-rw-r--r--docs/_static/css/custom.css15
-rw-r--r--docs/about/acknowledgements.rst22
-rw-r--r--docs/about/contact.rst56
-rw-r--r--docs/about/features.rst128
-rw-r--r--docs/about/index.rst12
-rw-r--r--docs/about/maintainers.rst960
-rw-r--r--docs/about/release-information.rst78
-rw-r--r--docs/change-log.md6850
-rw-r--r--docs/components/activity-monitors.rst34
-rw-r--r--docs/components/arm-sip-service.rst435
-rw-r--r--docs/components/cot-binding.rst332
-rw-r--r--docs/components/debugfs-design.rst125
-rw-r--r--docs/components/el3-spmc.rst597
-rw-r--r--docs/components/exception-handling.rst619
-rw-r--r--docs/components/fconf/amu-bindings.rst142
-rw-r--r--docs/components/fconf/fconf_properties.rst39
-rw-r--r--docs/components/fconf/index.rst149
-rw-r--r--docs/components/fconf/mpmm-bindings.rst48
-rw-r--r--docs/components/ffa-manifest-binding.rst296
-rw-r--r--docs/components/firmware-update.rst497
-rw-r--r--docs/components/granule-protection-tables-design.rst235
-rw-r--r--docs/components/index.rst28
-rw-r--r--docs/components/measured_boot/event_log.rst35
-rw-r--r--docs/components/measured_boot/index.rst12
-rw-r--r--docs/components/mpmm.rst30
-rw-r--r--docs/components/platform-interrupt-controller-API.rst309
-rw-r--r--docs/components/ras.rst242
-rw-r--r--docs/components/realm-management-extension.rst391
-rw-r--r--docs/components/rmm-el3-comms-spec.rst543
-rw-r--r--docs/components/romlib-design.rst155
-rw-r--r--docs/components/sdei.rst369
-rw-r--r--docs/components/secure-partition-manager-mm.rst834
-rw-r--r--docs/components/secure-partition-manager.rst1565
-rw-r--r--docs/components/spd/index.rst11
-rw-r--r--docs/components/spd/optee-dispatcher.rst14
-rw-r--r--docs/components/spd/pnc-dispatcher.rst10
-rw-r--r--docs/components/spd/tlk-dispatcher.rst76
-rw-r--r--docs/components/spd/trusty-dispatcher.rst32
-rw-r--r--docs/components/xlat-tables-lib-v2-design.rst442
-rw-r--r--docs/conf.py95
-rw-r--r--docs/design/alt-boot-flows.rst84
-rw-r--r--docs/design/auth-framework.rst980
-rw-r--r--docs/design/cpu-specific-build-macros.rst742
-rw-r--r--docs/design/firmware-design.rst2766
-rw-r--r--docs/design/index.rst20
-rw-r--r--docs/design/interrupt-framework-design.rst1021
-rw-r--r--docs/design/psci-pd-tree.rst304
-rw-r--r--docs/design/reset-design.rst168
-rw-r--r--docs/design/trusted-board-boot-build.rst122
-rw-r--r--docs/design/trusted-board-boot.rst263
-rw-r--r--docs/design_documents/cmake_framework.rst165
-rw-r--r--docs/design_documents/context_mgmt_rework.rst197
-rw-r--r--docs/design_documents/drtm_poc.rst132
-rw-r--r--docs/design_documents/index.rst15
-rw-r--r--docs/design_documents/measured_boot_poc.rst507
-rw-r--r--docs/getting_started/build-options.rst1164
-rw-r--r--docs/getting_started/docs-build.rst112
-rw-r--r--docs/getting_started/image-terminology.rst192
-rw-r--r--docs/getting_started/index.rst20
-rw-r--r--docs/getting_started/initial-build.rst118
-rw-r--r--docs/getting_started/porting-guide.rst3515
-rw-r--r--docs/getting_started/prerequisites.rst181
-rw-r--r--docs/getting_started/psci-lib-integration-guide.rst536
-rw-r--r--docs/getting_started/rt-svc-writers-guide.rst320
-rw-r--r--docs/getting_started/tools-build.rst179
-rw-r--r--docs/global_substitutions.txt68
-rw-r--r--docs/glossary.rst243
-rw-r--r--docs/index.rst96
-rw-r--r--docs/license.rst90
-rw-r--r--docs/perf/index.rst14
-rw-r--r--docs/perf/performance-monitoring-unit.rst158
-rw-r--r--docs/perf/psci-performance-juno.rst292
-rw-r--r--docs/perf/tsp.rst27
-rw-r--r--docs/plat/allwinner.rst142
-rw-r--r--docs/plat/arm/arm-build-options.rst164
-rw-r--r--docs/plat/arm/arm_fpga/index.rst97
-rw-r--r--docs/plat/arm/corstone1000/index.rst61
-rw-r--r--docs/plat/arm/fvp-ve/index.rst84
-rw-r--r--docs/plat/arm/fvp/index.rst640
-rw-r--r--docs/plat/arm/fvp_r/index.rst46
-rw-r--r--docs/plat/arm/index.rst24
-rw-r--r--docs/plat/arm/juno/index.rst253
-rw-r--r--docs/plat/arm/morello/index.rst33
-rw-r--r--docs/plat/arm/tc/index.rst63
-rw-r--r--docs/plat/brcm-stingray.rst43
-rw-r--r--docs/plat/hikey.rst155
-rw-r--r--docs/plat/hikey960.rst180
-rw-r--r--docs/plat/imx8.rst58
-rw-r--r--docs/plat/imx8m.rst113
-rw-r--r--docs/plat/index.rst82
-rw-r--r--docs/plat/intel-agilex.rst86
-rw-r--r--docs/plat/intel-stratix10.rst94
-rw-r--r--docs/plat/marvell/armada/build.rst476
-rw-r--r--docs/plat/marvell/armada/misc/mvebu-a8k-addr-map.rst49
-rw-r--r--docs/plat/marvell/armada/misc/mvebu-amb.rst58
-rw-r--r--docs/plat/marvell/armada/misc/mvebu-ccu.rst33
-rw-r--r--docs/plat/marvell/armada/misc/mvebu-io-win.rst46
-rw-r--r--docs/plat/marvell/armada/misc/mvebu-iob.rst52
-rw-r--r--docs/plat/marvell/armada/porting.rst158
-rw-r--r--docs/plat/marvell/armada/uart-booting.rst103
-rw-r--r--docs/plat/marvell/index.rst15
-rw-r--r--docs/plat/meson-axg.rst27
-rw-r--r--docs/plat/meson-g12a.rst27
-rw-r--r--docs/plat/meson-gxbb.rst26
-rw-r--r--docs/plat/meson-gxl.rst27
-rw-r--r--docs/plat/mt8183.rst20
-rw-r--r--docs/plat/mt8186.rst21
-rw-r--r--docs/plat/mt8188.rst21
-rw-r--r--docs/plat/mt8192.rst21
-rw-r--r--docs/plat/mt8195.rst21
-rw-r--r--docs/plat/nvidia-tegra.rst148
-rw-r--r--docs/plat/nxp/index.rst17
-rw-r--r--docs/plat/nxp/nxp-layerscape.rst473
-rw-r--r--docs/plat/nxp/nxp-ls-fuse-prov.rst271
-rw-r--r--docs/plat/nxp/nxp-ls-tbbr.rst210
-rw-r--r--docs/plat/poplar.rst176
-rw-r--r--docs/plat/qemu-sbsa.rst56
-rw-r--r--docs/plat/qemu.rst172
-rw-r--r--docs/plat/qti-msm8916.rst116
-rw-r--r--docs/plat/qti.rst43
-rw-r--r--docs/plat/rcar-gen3.rst268
-rw-r--r--docs/plat/rockchip.rst55
-rw-r--r--docs/plat/rpi3.rst466
-rw-r--r--docs/plat/rpi4.rst84
-rw-r--r--docs/plat/rz-g2.rst228
-rw-r--r--docs/plat/socionext-uniphier.rst116
-rw-r--r--docs/plat/stm32mp1.rst280
-rw-r--r--docs/plat/synquacer.rst117
-rw-r--r--docs/plat/ti-k3.rst57
-rw-r--r--docs/plat/warp7.rst210
-rw-r--r--docs/plat/xilinx-versal-net.rst31
-rw-r--r--docs/plat/xilinx-versal.rst55
-rw-r--r--docs/plat/xilinx-zynqmp.rst73
-rw-r--r--docs/process/code-review-guidelines.rst216
-rw-r--r--docs/process/coding-guidelines.rst474
-rw-r--r--docs/process/coding-style.rst470
-rw-r--r--docs/process/commit-style.rst153
-rw-r--r--docs/process/contributing.rst304
-rw-r--r--docs/process/faq.rst80
-rw-r--r--docs/process/index.rst16
-rw-r--r--docs/process/platform-ports-policy.rst51
-rw-r--r--docs/process/security-hardening.rst175
-rw-r--r--docs/process/security.rst89
-rw-r--r--docs/requirements.in5
-rw-r--r--docs/requirements.txt91
-rw-r--r--docs/resources/TrustedFirmware-Logo_standard-white.pngbin0 -> 5826 bytes
-rw-r--r--docs/resources/diagrams/FIP_in_a_GPT_image.pngbin0 -> 250286 bytes
-rw-r--r--docs/resources/diagrams/MMU-600.pngbin0 -> 50836 bytes
-rw-r--r--docs/resources/diagrams/Makefile101
-rw-r--r--docs/resources/diagrams/PSA-FWU.diabin0 -> 3516 bytes
-rw-r--r--docs/resources/diagrams/PSA-FWU.pngbin0 -> 52886 bytes
-rwxr-xr-xdocs/resources/diagrams/arm-cca-software-arch.pngbin0 -> 20577 bytes
-rw-r--r--docs/resources/diagrams/cmake_framework_structure.pngbin0 -> 73277 bytes
-rw-r--r--docs/resources/diagrams/cmake_framework_workflow.pngbin0 -> 49898 bytes
-rw-r--r--docs/resources/diagrams/context_management_abs.pngbin0 -> 10781 bytes
-rw-r--r--docs/resources/diagrams/context_mgmt_existing.pngbin0 -> 52718 bytes
-rw-r--r--docs/resources/diagrams/context_mgmt_proposed.pngbin0 -> 61841 bytes
-rw-r--r--docs/resources/diagrams/default_reset_code.pngbin0 -> 41796 bytes
-rw-r--r--docs/resources/diagrams/draw.io/ehf.svg2
-rw-r--r--docs/resources/diagrams/draw.io/ehf.xml1
-rw-r--r--docs/resources/diagrams/draw.io/ras.svg2
-rw-r--r--docs/resources/diagrams/draw.io/ras.xml1
-rw-r--r--docs/resources/diagrams/ff-a-lsp-at-el3.pngbin0 -> 39282 bytes
-rw-r--r--docs/resources/diagrams/ff-a-spm-at-el3.pngbin0 -> 29978 bytes
-rw-r--r--docs/resources/diagrams/ff-a-spm-sel2.pngbin0 -> 53363 bytes
-rw-r--r--docs/resources/diagrams/ffa-ns-interrupt-handling-managed-exit.pngbin0 -> 86234 bytes
-rw-r--r--docs/resources/diagrams/ffa-ns-interrupt-handling-sp-preemption.pngbin0 -> 70490 bytes
-rwxr-xr-xdocs/resources/diagrams/ffa-secure-interrupt-handling-nwd.pngbin0 -> 48073 bytes
-rwxr-xr-xdocs/resources/diagrams/ffa-secure-interrupt-handling-swd.pngbin0 -> 48364 bytes
-rw-r--r--docs/resources/diagrams/fwu_flow.pngbin0 -> 167225 bytes
-rw-r--r--docs/resources/diagrams/fwu_states.pngbin0 -> 114222 bytes
-rw-r--r--docs/resources/diagrams/int_handling.diabin0 -> 10623 bytes
-rw-r--r--docs/resources/diagrams/non-sec-int-handling.pngbin0 -> 218768 bytes
-rw-r--r--docs/resources/diagrams/partition-package.pngbin0 -> 35971 bytes
-rw-r--r--docs/resources/diagrams/plantuml/bl2-loading-sp.puml44
-rw-r--r--docs/resources/diagrams/plantuml/el3_spm_dfd.puml78
-rw-r--r--docs/resources/diagrams/plantuml/fconf_bl1_load_config.puml78
-rw-r--r--docs/resources/diagrams/plantuml/fconf_bl2_populate.puml49
-rw-r--r--docs/resources/diagrams/plantuml/fip-secure-partitions.puml167
-rw-r--r--docs/resources/diagrams/plantuml/io_arm_class_diagram.puml109
-rw-r--r--docs/resources/diagrams/plantuml/io_dev_init_and_check.puml62
-rw-r--r--docs/resources/diagrams/plantuml/io_dev_registration.puml52
-rw-r--r--docs/resources/diagrams/plantuml/io_framework_usage_overview.puml59
-rw-r--r--docs/resources/diagrams/plantuml/sdei_explicit_dispatch.puml51
-rw-r--r--docs/resources/diagrams/plantuml/sdei_general.puml43
-rw-r--r--docs/resources/diagrams/plantuml/spm_dfd.puml82
-rw-r--r--docs/resources/diagrams/plantuml/tfa_dfd.puml66
-rw-r--r--docs/resources/diagrams/psci-suspend-sequence.pngbin0 -> 427800 bytes
-rw-r--r--docs/resources/diagrams/reset_code_flow.diabin0 -> 4399 bytes
-rw-r--r--docs/resources/diagrams/reset_code_no_boot_type_check.pngbin0 -> 42942 bytes
-rw-r--r--docs/resources/diagrams/reset_code_no_checks.pngbin0 -> 39753 bytes
-rw-r--r--docs/resources/diagrams/reset_code_no_cpu_check.pngbin0 -> 38566 bytes
-rw-r--r--docs/resources/diagrams/rmm_cold_boot_generic.diabin0 -> 2801 bytes
-rw-r--r--docs/resources/diagrams/rmm_cold_boot_generic.pngbin0 -> 31492 bytes
-rw-r--r--docs/resources/diagrams/rmm_el3_manifest_struct.diabin0 -> 2589 bytes
-rw-r--r--docs/resources/diagrams/rmm_el3_manifest_struct.pngbin0 -> 14167 bytes
-rw-r--r--docs/resources/diagrams/romlib_design.diabin0 -> 2985 bytes
-rw-r--r--docs/resources/diagrams/romlib_design.pngbin0 -> 17244 bytes
-rw-r--r--docs/resources/diagrams/romlib_wrapper.diabin0 -> 2543 bytes
-rw-r--r--docs/resources/diagrams/romlib_wrapper.pngbin0 -> 12085 bytes
-rw-r--r--docs/resources/diagrams/rt-svc-descs-layout.pngbin0 -> 77894 bytes
-rw-r--r--docs/resources/diagrams/sec-int-handling.pngbin0 -> 173315 bytes
-rw-r--r--docs/resources/diagrams/secure_sw_stack_sp.pngbin0 -> 34909 bytes
-rw-r--r--docs/resources/diagrams/secure_sw_stack_tos.pngbin0 -> 34202 bytes
-rw-r--r--docs/resources/diagrams/spm-threat-model-trust-boundaries.pngbin0 -> 66389 bytes
-rw-r--r--docs/resources/diagrams/xlat_align.diabin0 -> 2346 bytes
-rw-r--r--docs/resources/diagrams/xlat_align.pngbin0 -> 46712 bytes
-rw-r--r--docs/security_advisories/index.rst16
-rw-r--r--docs/security_advisories/security-advisory-tfv-1.rst162
-rw-r--r--docs/security_advisories/security-advisory-tfv-2.rst61
-rw-r--r--docs/security_advisories/security-advisory-tfv-3.rst86
-rw-r--r--docs/security_advisories/security-advisory-tfv-4.rst124
-rw-r--r--docs/security_advisories/security-advisory-tfv-5.rst57
-rw-r--r--docs/security_advisories/security-advisory-tfv-6.rst148
-rw-r--r--docs/security_advisories/security-advisory-tfv-7.rst107
-rw-r--r--docs/security_advisories/security-advisory-tfv-8.rst103
-rw-r--r--docs/security_advisories/security-advisory-tfv-9.rst124
-rw-r--r--docs/threat_model/index.rst22
-rw-r--r--docs/threat_model/threat_model.rst896
-rw-r--r--docs/threat_model/threat_model_el3_spm.rst650
-rw-r--r--docs/threat_model/threat_model_fvp_r.rst97
-rw-r--r--docs/threat_model/threat_model_spm.rst1161
-rw-r--r--drivers/allwinner/axp/axp803.c25
-rw-r--r--drivers/allwinner/axp/axp805.c35
-rw-r--r--drivers/allwinner/axp/common.c212
-rw-r--r--drivers/allwinner/sunxi_msgbox.c95
-rw-r--r--drivers/allwinner/sunxi_rsb.c138
-rw-r--r--drivers/amlogic/console/aarch64/meson_console.S262
-rw-r--r--drivers/amlogic/crypto/sha_dma.c183
-rw-r--r--drivers/arm/cci/cci.c186
-rw-r--r--drivers/arm/ccn/ccn.c621
-rw-r--r--drivers/arm/ccn/ccn_private.h233
-rw-r--r--drivers/arm/css/mhu/css_mhu.c100
-rw-r--r--drivers/arm/css/mhu/css_mhu_doorbell.c40
-rw-r--r--drivers/arm/css/scmi/scmi_ap_core_proto.c81
-rw-r--r--drivers/arm/css/scmi/scmi_common.c210
-rw-r--r--drivers/arm/css/scmi/scmi_private.h160
-rw-r--r--drivers/arm/css/scmi/scmi_pwr_dmn_proto.c88
-rw-r--r--drivers/arm/css/scmi/scmi_sys_pwr_proto.c78
-rw-r--r--drivers/arm/css/scmi/vendor/scmi_sq.c62
-rw-r--r--drivers/arm/css/scmi/vendor/scmi_sq.h25
-rw-r--r--drivers/arm/css/scp/css_bom_bootloader.c195
-rw-r--r--drivers/arm/css/scp/css_pm_scmi.c499
-rw-r--r--drivers/arm/css/scp/css_pm_scpi.c165
-rw-r--r--drivers/arm/css/scp/css_sds.c95
-rw-r--r--drivers/arm/css/scpi/css_scpi.c272
-rw-r--r--drivers/arm/css/sds/aarch32/sds_helpers.S64
-rw-r--r--drivers/arm/css/sds/aarch64/sds_helpers.S62
-rw-r--r--drivers/arm/css/sds/sds.c259
-rw-r--r--drivers/arm/css/sds/sds_private.h100
-rw-r--r--drivers/arm/dcc/dcc_console.c152
-rw-r--r--drivers/arm/ethosn/ethosn_smc.c229
-rw-r--r--drivers/arm/fvp/fvp_pwrc.c78
-rw-r--r--drivers/arm/gic/common/gic_common.c342
-rw-r--r--drivers/arm/gic/common/gic_common_private.h89
-rw-r--r--drivers/arm/gic/v2/gicdv2_helpers.c340
-rw-r--r--drivers/arm/gic/v2/gicv2.mk15
-rw-r--r--drivers/arm/gic/v2/gicv2_helpers.c220
-rw-r--r--drivers/arm/gic/v2/gicv2_main.c556
-rw-r--r--drivers/arm/gic/v2/gicv2_private.h150
-rw-r--r--drivers/arm/gic/v3/arm_gicv3_common.c115
-rw-r--r--drivers/arm/gic/v3/gic-x00.c232
-rw-r--r--drivers/arm/gic/v3/gic600_multichip.c358
-rw-r--r--drivers/arm/gic/v3/gic600_multichip_private.h114
-rw-r--r--drivers/arm/gic/v3/gic600ae_fmu.c384
-rw-r--r--drivers/arm/gic/v3/gic600ae_fmu_helpers.c304
-rw-r--r--drivers/arm/gic/v3/gicdv3_helpers.c244
-rw-r--r--drivers/arm/gic/v3/gicrv3_helpers.c139
-rw-r--r--drivers/arm/gic/v3/gicv3.mk54
-rw-r--r--drivers/arm/gic/v3/gicv3_helpers.c443
-rw-r--r--drivers/arm/gic/v3/gicv3_main.c1361
-rw-r--r--drivers/arm/gic/v3/gicv3_private.h707
-rw-r--r--drivers/arm/mhu/mhu_v2_x.c379
-rw-r--r--drivers/arm/mhu/mhu_v2_x.h210
-rw-r--r--drivers/arm/mhu/mhu_wrapper_v2_x.c312
-rw-r--r--drivers/arm/pl011/aarch32/pl011_console.S264
-rw-r--r--drivers/arm/pl011/aarch64/pl011_console.S247
-rw-r--r--drivers/arm/pl061/pl061_gpio.c142
-rw-r--r--drivers/arm/rss/rss_comms.c170
-rw-r--r--drivers/arm/rss/rss_comms.mk22
-rw-r--r--drivers/arm/rss/rss_comms_protocol.c75
-rw-r--r--drivers/arm/rss/rss_comms_protocol.h67
-rw-r--r--drivers/arm/rss/rss_comms_protocol_embed.c91
-rw-r--r--drivers/arm/rss/rss_comms_protocol_embed.h47
-rw-r--r--drivers/arm/rss/rss_comms_protocol_pointer_access.c74
-rw-r--r--drivers/arm/rss/rss_comms_protocol_pointer_access.h42
-rw-r--r--drivers/arm/sbsa/sbsa.c42
-rw-r--r--drivers/arm/scu/scu.c51
-rw-r--r--drivers/arm/smmu/smmu_v3.c182
-rw-r--r--drivers/arm/sp804/sp804_delay_timer.c57
-rw-r--r--drivers/arm/sp805/sp805.c51
-rw-r--r--drivers/arm/tzc/tzc380.c104
-rw-r--r--drivers/arm/tzc/tzc400.c360
-rw-r--r--drivers/arm/tzc/tzc_common_private.h204
-rw-r--r--drivers/arm/tzc/tzc_dmc500.c287
-rw-r--r--drivers/arm/tzc/tzc_dmc620.c177
-rw-r--r--drivers/auth/auth_mod.c458
-rw-r--r--drivers/auth/cca/cot.c675
-rw-r--r--drivers/auth/crypto_mod.c175
-rw-r--r--drivers/auth/cryptocell/712/cryptocell_crypto.c306
-rw-r--r--drivers/auth/cryptocell/712/cryptocell_plat_helpers.c113
-rw-r--r--drivers/auth/cryptocell/713/cryptocell_crypto.c276
-rw-r--r--drivers/auth/cryptocell/713/cryptocell_plat_helpers.c109
-rw-r--r--drivers/auth/cryptocell/cryptocell_crypto.mk40
-rw-r--r--drivers/auth/dualroot/cot.c959
-rw-r--r--drivers/auth/img_parser_mod.c126
-rw-r--r--drivers/auth/mbedtls/mbedtls_common.c72
-rw-r--r--drivers/auth/mbedtls/mbedtls_common.mk111
-rw-r--r--drivers/auth/mbedtls/mbedtls_crypto.c394
-rw-r--r--drivers/auth/mbedtls/mbedtls_crypto.mk11
-rw-r--r--drivers/auth/mbedtls/mbedtls_x509.mk9
-rw-r--r--drivers/auth/mbedtls/mbedtls_x509_parser.c478
-rw-r--r--drivers/auth/tbbr/tbbr_cot_bl1.c184
-rw-r--r--drivers/auth/tbbr/tbbr_cot_bl1_r64.c177
-rw-r--r--drivers/auth/tbbr/tbbr_cot_bl2.c688
-rw-r--r--drivers/auth/tbbr/tbbr_cot_common.c126
-rw-r--r--drivers/brcm/chimp.c398
-rw-r--r--drivers/brcm/emmc/emmc_chal_sd.c1017
-rw-r--r--drivers/brcm/emmc/emmc_csl_sdcard.c1089
-rw-r--r--drivers/brcm/emmc/emmc_csl_sdcmd.c842
-rw-r--r--drivers/brcm/emmc/emmc_pboot_hal_memory_drv.c621
-rw-r--r--drivers/brcm/i2c/i2c.c886
-rw-r--r--drivers/brcm/iproc_gpio.c232
-rw-r--r--drivers/brcm/mdio/mdio.c87
-rw-r--r--drivers/brcm/ocotp.c204
-rw-r--r--drivers/brcm/rng.c97
-rw-r--r--drivers/brcm/scp.c100
-rw-r--r--drivers/brcm/sotp.c323
-rw-r--r--drivers/brcm/spi/iproc_qspi.c317
-rw-r--r--drivers/brcm/spi/iproc_qspi.h107
-rw-r--r--drivers/brcm/spi/iproc_spi.c31
-rw-r--r--drivers/brcm/spi_flash.c308
-rw-r--r--drivers/brcm/spi_sf.c60
-rw-r--r--drivers/cadence/uart/aarch64/cdns_console.S220
-rw-r--r--drivers/cfi/v2m/v2m_flash.c196
-rw-r--r--drivers/clk/clk.c65
-rw-r--r--drivers/console/aarch32/skeleton_console.S170
-rw-r--r--drivers/console/aarch64/skeleton_console.S170
-rw-r--r--drivers/console/multi_console.c139
-rw-r--r--drivers/coreboot/cbmem_console/aarch64/cbmem_console.S98
-rw-r--r--drivers/delay_timer/delay_timer.c82
-rw-r--r--drivers/delay_timer/generic_delay_timer.c62
-rw-r--r--drivers/fwu/fwu.c194
-rw-r--r--drivers/fwu/fwu.mk11
-rw-r--r--drivers/gpio/gpio.c93
-rw-r--r--drivers/imx/timer/imx_gpt.c62
-rw-r--r--drivers/imx/timer/imx_gpt.h14
-rw-r--r--drivers/imx/uart/imx_crash_uart.S131
-rw-r--r--drivers/imx/uart/imx_uart.c181
-rw-r--r--drivers/imx/uart/imx_uart.h163
-rw-r--r--drivers/imx/usdhc/imx_usdhc.c302
-rw-r--r--drivers/imx/usdhc/imx_usdhc.h137
-rw-r--r--drivers/intel/soc/stratix10/io/s10_memmap_qspi.c253
-rw-r--r--drivers/io/io_block.c551
-rw-r--r--drivers/io/io_dummy.c155
-rw-r--r--drivers/io/io_encrypted.c244
-rw-r--r--drivers/io/io_fip.c481
-rw-r--r--drivers/io/io_memmap.c251
-rw-r--r--drivers/io/io_mtd.c290
-rw-r--r--drivers/io/io_semihosting.c201
-rw-r--r--drivers/io/io_storage.c328
-rw-r--r--drivers/marvell/amb_adec.c160
-rw-r--r--drivers/marvell/ap807_clocks_init.c109
-rw-r--r--drivers/marvell/cache_llc.c189
-rw-r--r--drivers/marvell/ccu.c417
-rw-r--r--drivers/marvell/comphy.h472
-rw-r--r--drivers/marvell/comphy/comphy-cp110.h914
-rw-r--r--drivers/marvell/comphy/phy-comphy-3700.c1065
-rw-r--r--drivers/marvell/comphy/phy-comphy-3700.h249
-rw-r--r--drivers/marvell/comphy/phy-comphy-common.h167
-rw-r--r--drivers/marvell/comphy/phy-comphy-cp110.c2528
-rw-r--r--drivers/marvell/comphy/phy-comphy-cp110.h102
-rw-r--r--drivers/marvell/comphy/phy-default-porting-layer.h59
-rw-r--r--drivers/marvell/ddr_phy_access.c58
-rw-r--r--drivers/marvell/ddr_phy_access.h15
-rw-r--r--drivers/marvell/gwin.c231
-rw-r--r--drivers/marvell/io_win.c271
-rw-r--r--drivers/marvell/iob.c214
-rw-r--r--drivers/marvell/mc_trustzone/mc_trustzone.c76
-rw-r--r--drivers/marvell/mc_trustzone/mc_trustzone.h27
-rw-r--r--drivers/marvell/mci.c834
-rw-r--r--drivers/marvell/mg_conf_cm3/mg_conf_cm3.c97
-rw-r--r--drivers/marvell/mg_conf_cm3/mg_conf_cm3.h9
-rw-r--r--drivers/marvell/mochi/ap807_setup.c339
-rw-r--r--drivers/marvell/mochi/apn806_setup.c297
-rw-r--r--drivers/marvell/mochi/cp110_setup.c467
-rw-r--r--drivers/marvell/secure_dfx_access/armada_thermal.c253
-rw-r--r--drivers/marvell/secure_dfx_access/dfx.h22
-rw-r--r--drivers/marvell/secure_dfx_access/misc_dfx.c123
-rw-r--r--drivers/marvell/thermal.c54
-rw-r--r--drivers/marvell/uart/a3700_console.S271
-rw-r--r--drivers/measured_boot/event_log/event_log.c321
-rw-r--r--drivers/measured_boot/event_log/event_log.mk41
-rw-r--r--drivers/measured_boot/event_log/event_print.c265
-rw-r--r--drivers/measured_boot/rss/rss_measured_boot.c137
-rw-r--r--drivers/measured_boot/rss/rss_measured_boot.mk32
-rw-r--r--drivers/mentor/i2c/mi2cv.c614
-rw-r--r--drivers/mmc/mmc.c858
-rw-r--r--drivers/mtd/nand/core.c176
-rw-r--r--drivers/mtd/nand/raw_nand.c443
-rw-r--r--drivers/mtd/nand/spi_nand.c324
-rw-r--r--drivers/mtd/nor/spi_nor.c387
-rw-r--r--drivers/mtd/spi-mem/spi_mem.c289
-rw-r--r--drivers/nxp/auth/csf_hdr_parser/cot.c284
-rw-r--r--drivers/nxp/auth/csf_hdr_parser/csf_hdr.mk64
-rw-r--r--drivers/nxp/auth/csf_hdr_parser/csf_hdr_parser.c365
-rw-r--r--drivers/nxp/auth/csf_hdr_parser/input_bl2_ch289
-rw-r--r--drivers/nxp/auth/csf_hdr_parser/input_bl2_ch365
-rw-r--r--drivers/nxp/auth/csf_hdr_parser/input_bl2_ch3_265
-rw-r--r--drivers/nxp/auth/csf_hdr_parser/input_blx_ch230
-rw-r--r--drivers/nxp/auth/csf_hdr_parser/input_blx_ch337
-rw-r--r--drivers/nxp/auth/csf_hdr_parser/input_pbi_ch343
-rw-r--r--drivers/nxp/auth/csf_hdr_parser/input_pbi_ch3_243
-rw-r--r--drivers/nxp/auth/csf_hdr_parser/plat_img_parser.c180
-rw-r--r--drivers/nxp/auth/tbbr/tbbr_cot.c820
-rw-r--r--drivers/nxp/console/16550_console.S319
-rw-r--r--drivers/nxp/console/console.mk46
-rw-r--r--drivers/nxp/console/console_16550.c33
-rw-r--r--drivers/nxp/console/console_pl011.c35
-rw-r--r--drivers/nxp/crypto/caam/caam.mk27
-rw-r--r--drivers/nxp/crypto/caam/src/auth/auth.mk12
-rw-r--r--drivers/nxp/crypto/caam/src/auth/hash.c155
-rw-r--r--drivers/nxp/crypto/caam/src/auth/nxp_crypto.c123
-rw-r--r--drivers/nxp/crypto/caam/src/auth/rsa.c179
-rw-r--r--drivers/nxp/crypto/caam/src/caam.c339
-rw-r--r--drivers/nxp/crypto/caam/src/hw_key_blob.c81
-rw-r--r--drivers/nxp/crypto/caam/src/jobdesc.c236
-rw-r--r--drivers/nxp/crypto/caam/src/rng.c251
-rw-r--r--drivers/nxp/crypto/caam/src/sec_hw_specific.c635
-rw-r--r--drivers/nxp/crypto/caam/src/sec_jr_driver.c241
-rw-r--r--drivers/nxp/csu/csu.c34
-rw-r--r--drivers/nxp/csu/csu.mk26
-rw-r--r--drivers/nxp/dcfg/dcfg.c156
-rw-r--r--drivers/nxp/dcfg/dcfg.mk26
-rw-r--r--drivers/nxp/ddr/fsl-mmdc/ddr.mk19
-rw-r--r--drivers/nxp/ddr/fsl-mmdc/fsl_mmdc.c176
-rw-r--r--drivers/nxp/ddr/nxp-ddr/README.odt31
-rw-r--r--drivers/nxp/ddr/nxp-ddr/ddr.c931
-rw-r--r--drivers/nxp/ddr/nxp-ddr/ddr.mk80
-rw-r--r--drivers/nxp/ddr/nxp-ddr/ddrc.c594
-rw-r--r--drivers/nxp/ddr/nxp-ddr/dimm.c399
-rw-r--r--drivers/nxp/ddr/nxp-ddr/regs.c1394
-rw-r--r--drivers/nxp/ddr/nxp-ddr/utility.c288
-rw-r--r--drivers/nxp/ddr/phy-gen1/phy.c97
-rw-r--r--drivers/nxp/ddr/phy-gen2/csr.h151
-rw-r--r--drivers/nxp/ddr/phy-gen2/ddr4fw.h2897
-rw-r--r--drivers/nxp/ddr/phy-gen2/ddrphy.mk20
-rw-r--r--drivers/nxp/ddr/phy-gen2/input.h106
-rw-r--r--drivers/nxp/ddr/phy-gen2/messages.h2909
-rw-r--r--drivers/nxp/ddr/phy-gen2/phy.c2678
-rw-r--r--drivers/nxp/ddr/phy-gen2/phy.h334
-rw-r--r--drivers/nxp/ddr/phy-gen2/pie.h632
-rw-r--r--drivers/nxp/drivers.mk99
-rw-r--r--drivers/nxp/flexspi/nor/flexspi_nor.c25
-rw-r--r--drivers/nxp/flexspi/nor/flexspi_nor.h15
-rw-r--r--drivers/nxp/flexspi/nor/flexspi_nor.mk35
-rw-r--r--drivers/nxp/flexspi/nor/fspi.c853
-rw-r--r--drivers/nxp/flexspi/nor/fspi.h385
-rw-r--r--drivers/nxp/flexspi/nor/test_fspi.c91
-rw-r--r--drivers/nxp/gic/gic.mk46
-rw-r--r--drivers/nxp/gic/ls_gicv2.c76
-rw-r--r--drivers/nxp/gic/ls_gicv3.c78
-rw-r--r--drivers/nxp/gpio/gpio.mk28
-rw-r--r--drivers/nxp/gpio/nxp_gpio.c144
-rw-r--r--drivers/nxp/i2c/i2c.c257
-rw-r--r--drivers/nxp/i2c/i2c.mk25
-rw-r--r--drivers/nxp/ifc/nand/ifc.h329
-rw-r--r--drivers/nxp/ifc/nand/ifc_nand.c658
-rw-r--r--drivers/nxp/ifc/nand/ifc_nand.mk29
-rw-r--r--drivers/nxp/ifc/nor/ifc_nor.c18
-rw-r--r--drivers/nxp/ifc/nor/ifc_nor.mk28
-rw-r--r--drivers/nxp/interconnect/interconnect.mk44
-rw-r--r--drivers/nxp/interconnect/ls_cci.c38
-rw-r--r--drivers/nxp/interconnect/ls_ccn.c31
-rw-r--r--drivers/nxp/pmu/pmu.c45
-rw-r--r--drivers/nxp/pmu/pmu.mk26
-rw-r--r--drivers/nxp/qspi/qspi.c29
-rw-r--r--drivers/nxp/qspi/qspi.mk26
-rw-r--r--drivers/nxp/sd/sd_mmc.c1496
-rw-r--r--drivers/nxp/sd/sd_mmc.mk26
-rw-r--r--drivers/nxp/sec_mon/sec_mon.mk25
-rw-r--r--drivers/nxp/sec_mon/snvs.c186
-rw-r--r--drivers/nxp/sfp/fuse_prov.c462
-rw-r--r--drivers/nxp/sfp/sfp.c167
-rw-r--r--drivers/nxp/sfp/sfp.mk33
-rw-r--r--drivers/nxp/timer/nxp_timer.c143
-rw-r--r--drivers/nxp/timer/timer.mk25
-rw-r--r--drivers/nxp/tzc/plat_tzc380.c152
-rw-r--r--drivers/nxp/tzc/plat_tzc400.c187
-rw-r--r--drivers/nxp/tzc/tzc.mk40
-rw-r--r--drivers/partition/gpt.c65
-rw-r--r--drivers/partition/partition.c303
-rw-r--r--drivers/rambus/trng_ip_76.c249
-rw-r--r--drivers/renesas/common/auth/auth_mod.c172
-rw-r--r--drivers/renesas/common/avs/avs_driver.c630
-rw-r--r--drivers/renesas/common/avs/avs_driver.h20
-rw-r--r--drivers/renesas/common/common.c38
-rw-r--r--drivers/renesas/common/console/rcar_console.S93
-rw-r--r--drivers/renesas/common/console/rcar_printf.c108
-rw-r--r--drivers/renesas/common/console/rcar_printf.h15
-rw-r--r--drivers/renesas/common/ddr/boot_init_dram.h18
-rw-r--r--drivers/renesas/common/ddr/ddr.mk17
-rw-r--r--drivers/renesas/common/ddr/ddr_a/boot_init_dram_regdef.h8
-rw-r--r--drivers/renesas/common/ddr/ddr_a/ddr_a.mk13
-rw-r--r--drivers/renesas/common/ddr/ddr_a/ddr_init_d3.c735
-rw-r--r--drivers/renesas/common/ddr/ddr_a/ddr_init_e3.c1712
-rw-r--r--drivers/renesas/common/ddr/ddr_a/ddr_init_v3m.c339
-rw-r--r--drivers/renesas/common/ddr/ddr_b/boot_init_dram.c4484
-rw-r--r--drivers/renesas/common/ddr/ddr_b/boot_init_dram_config.c2108
-rw-r--r--drivers/renesas/common/ddr/ddr_b/boot_init_dram_regdef.h95
-rw-r--r--drivers/renesas/common/ddr/ddr_b/ddr_b.mk7
-rw-r--r--drivers/renesas/common/ddr/ddr_b/ddr_regdef.h5887
-rw-r--r--drivers/renesas/common/ddr/ddr_b/init_dram_tbl_h3.h441
-rw-r--r--drivers/renesas/common/ddr/ddr_b/init_dram_tbl_h3ver2.h538
-rw-r--r--drivers/renesas/common/ddr/ddr_b/init_dram_tbl_m3.h468
-rw-r--r--drivers/renesas/common/ddr/ddr_b/init_dram_tbl_m3n.h587
-rw-r--r--drivers/renesas/common/ddr/dram_sub_func.c165
-rw-r--r--drivers/renesas/common/ddr/dram_sub_func.h17
-rw-r--r--drivers/renesas/common/ddr_regs.h257
-rw-r--r--drivers/renesas/common/delay/micro_delay.c31
-rw-r--r--drivers/renesas/common/delay/micro_delay.h15
-rw-r--r--drivers/renesas/common/dma/dma_driver.c153
-rw-r--r--drivers/renesas/common/emmc/emmc_cmd.c493
-rw-r--r--drivers/renesas/common/emmc/emmc_config.h20
-rw-r--r--drivers/renesas/common/emmc/emmc_def.h78
-rw-r--r--drivers/renesas/common/emmc/emmc_hal.h535
-rw-r--r--drivers/renesas/common/emmc/emmc_init.c163
-rw-r--r--drivers/renesas/common/emmc/emmc_interrupt.c217
-rw-r--r--drivers/renesas/common/emmc/emmc_mount.c686
-rw-r--r--drivers/renesas/common/emmc/emmc_read.c130
-rw-r--r--drivers/renesas/common/emmc/emmc_registers.h215
-rw-r--r--drivers/renesas/common/emmc/emmc_std.h475
-rw-r--r--drivers/renesas/common/emmc/emmc_utility.c226
-rw-r--r--drivers/renesas/common/iic_dvfs/iic_dvfs.c600
-rw-r--r--drivers/renesas/common/iic_dvfs/iic_dvfs.h23
-rw-r--r--drivers/renesas/common/io/io_common.h16
-rw-r--r--drivers/renesas/common/io/io_emmcdrv.c179
-rw-r--r--drivers/renesas/common/io/io_emmcdrv.h13
-rw-r--r--drivers/renesas/common/io/io_memdrv.c154
-rw-r--r--drivers/renesas/common/io/io_memdrv.h13
-rw-r--r--drivers/renesas/common/io/io_private.h20
-rw-r--r--drivers/renesas/common/io/io_rcar.c665
-rw-r--r--drivers/renesas/common/io/io_rcar.h14
-rw-r--r--drivers/renesas/common/pfc_regs.h230
-rw-r--r--drivers/renesas/common/pwrc/call_sram.S48
-rw-r--r--drivers/renesas/common/pwrc/pwrc.c917
-rw-r--r--drivers/renesas/common/pwrc/pwrc.h78
-rw-r--r--drivers/renesas/common/qos_reg.h133
-rw-r--r--drivers/renesas/common/rom/rom_api.c106
-rw-r--r--drivers/renesas/common/rom/rom_api.h31
-rw-r--r--drivers/renesas/common/rpc/rpc_driver.c57
-rw-r--r--drivers/renesas/common/rpc/rpc_registers.h25
-rw-r--r--drivers/renesas/common/scif/scif.S341
-rw-r--r--drivers/renesas/common/watchdog/swdt.c169
-rw-r--r--drivers/renesas/rcar/board/board.c101
-rw-r--r--drivers/renesas/rcar/board/board.h37
-rw-r--r--drivers/renesas/rcar/cpld/ulcb_cpld.c114
-rw-r--r--drivers/renesas/rcar/cpld/ulcb_cpld.h12
-rw-r--r--drivers/renesas/rcar/pfc/D3/pfc_init_d3.c667
-rw-r--r--drivers/renesas/rcar/pfc/D3/pfc_init_d3.h12
-rw-r--r--drivers/renesas/rcar/pfc/E3/pfc_init_e3.c651
-rw-r--r--drivers/renesas/rcar/pfc/E3/pfc_init_e3.h12
-rw-r--r--drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.c1183
-rw-r--r--drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.h12
-rw-r--r--drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.c1216
-rw-r--r--drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.h12
-rw-r--r--drivers/renesas/rcar/pfc/M3/pfc_init_m3.c1311
-rw-r--r--drivers/renesas/rcar/pfc/M3/pfc_init_m3.h12
-rw-r--r--drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.c1218
-rw-r--r--drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.h12
-rw-r--r--drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c906
-rw-r--r--drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.h13
-rw-r--r--drivers/renesas/rcar/pfc/pfc.mk69
-rw-r--r--drivers/renesas/rcar/pfc/pfc_init.c199
-rw-r--r--drivers/renesas/rcar/qos/D3/qos_init_d3.c147
-rw-r--r--drivers/renesas/rcar/qos/D3/qos_init_d3.h13
-rw-r--r--drivers/renesas/rcar/qos/D3/qos_init_d3_mstat.h244
-rw-r--r--drivers/renesas/rcar/qos/E3/qos_init_e3_v10.c142
-rw-r--r--drivers/renesas/rcar/qos/E3/qos_init_e3_v10.h12
-rw-r--r--drivers/renesas/rcar/qos/E3/qos_init_e3_v10_mstat390.h241
-rw-r--r--drivers/renesas/rcar/qos/E3/qos_init_e3_v10_mstat780.h241
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3_v10.c104
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3_v10.h12
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3_v10_mstat.h221
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3_v11.c200
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3_v11.h12
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3_v11_mstat.h221
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3_v20.c234
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3_v20.h12
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3_v20_mstat195.h231
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3_v20_mstat390.h231
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3_v20_qoswt195.h231
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3_v20_qoswt390.h231
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3_v30.c236
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3_v30.h12
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3_v30_mstat195.h231
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3_v30_mstat390.h231
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3_v30_qoswt195.h231
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3_v30_qoswt390.h231
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.c230
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.h12
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_mstat195.h231
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_mstat390.h231
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_qoswt195.h231
-rw-r--r--drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_qoswt390.h231
-rw-r--r--drivers/renesas/rcar/qos/M3/qos_init_m3_v10.c149
-rw-r--r--drivers/renesas/rcar/qos/M3/qos_init_m3_v10.h12
-rw-r--r--drivers/renesas/rcar/qos/M3/qos_init_m3_v10_mstat.h227
-rw-r--r--drivers/renesas/rcar/qos/M3/qos_init_m3_v11.c223
-rw-r--r--drivers/renesas/rcar/qos/M3/qos_init_m3_v11.h12
-rw-r--r--drivers/renesas/rcar/qos/M3/qos_init_m3_v11_mstat195.h225
-rw-r--r--drivers/renesas/rcar/qos/M3/qos_init_m3_v11_mstat390.h225
-rw-r--r--drivers/renesas/rcar/qos/M3/qos_init_m3_v11_qoswt195.h225
-rw-r--r--drivers/renesas/rcar/qos/M3/qos_init_m3_v11_qoswt390.h225
-rw-r--r--drivers/renesas/rcar/qos/M3/qos_init_m3_v30.c209
-rw-r--r--drivers/renesas/rcar/qos/M3/qos_init_m3_v30.h12
-rw-r--r--drivers/renesas/rcar/qos/M3/qos_init_m3_v30_mstat195.h225
-rw-r--r--drivers/renesas/rcar/qos/M3/qos_init_m3_v30_mstat390.h225
-rw-r--r--drivers/renesas/rcar/qos/M3/qos_init_m3_v30_qoswt195.h225
-rw-r--r--drivers/renesas/rcar/qos/M3/qos_init_m3_v30_qoswt390.h225
-rw-r--r--drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.c203
-rw-r--r--drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.h12
-rw-r--r--drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_mstat195.h241
-rw-r--r--drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_mstat390.h241
-rw-r--r--drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_qoswt195.h241
-rw-r--r--drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_qoswt390.h241
-rw-r--r--drivers/renesas/rcar/qos/V3M/qos_init_v3m.c111
-rw-r--r--drivers/renesas/rcar/qos/V3M/qos_init_v3m.h13
-rw-r--r--drivers/renesas/rcar/qos/V3M/qos_init_v3m_mstat.h98
-rw-r--r--drivers/renesas/rcar/qos/qos.mk106
-rw-r--r--drivers/renesas/rcar/qos/qos_common.h142
-rw-r--r--drivers/renesas/rcar/qos/qos_init.c394
-rw-r--r--drivers/renesas/rcar/qos/qos_init.h13
-rw-r--r--drivers/renesas/rzg/board/board.c97
-rw-r--r--drivers/renesas/rzg/board/board.h33
-rw-r--r--drivers/renesas/rzg/pfc/G2E/pfc_init_g2e.c700
-rw-r--r--drivers/renesas/rzg/pfc/G2E/pfc_init_g2e.h12
-rw-r--r--drivers/renesas/rzg/pfc/G2H/pfc_init_g2h.c1310
-rw-r--r--drivers/renesas/rzg/pfc/G2H/pfc_init_g2h.h12
-rw-r--r--drivers/renesas/rzg/pfc/G2M/pfc_init_g2m.c1300
-rw-r--r--drivers/renesas/rzg/pfc/G2M/pfc_init_g2m.h12
-rw-r--r--drivers/renesas/rzg/pfc/G2N/pfc_init_g2n.c1306
-rw-r--r--drivers/renesas/rzg/pfc/G2N/pfc_init_g2n.h12
-rw-r--r--drivers/renesas/rzg/pfc/pfc.mk41
-rw-r--r--drivers/renesas/rzg/pfc/pfc_init.c129
-rw-r--r--drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10.c140
-rw-r--r--drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10.h12
-rw-r--r--drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10_mstat390.h245
-rw-r--r--drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10_mstat780.h246
-rw-r--r--drivers/renesas/rzg/qos/G2H/qos_init_g2h_mstat195.h236
-rw-r--r--drivers/renesas/rzg/qos/G2H/qos_init_g2h_mstat390.h236
-rw-r--r--drivers/renesas/rzg/qos/G2H/qos_init_g2h_qoswt195.h236
-rw-r--r--drivers/renesas/rzg/qos/G2H/qos_init_g2h_qoswt390.h236
-rw-r--r--drivers/renesas/rzg/qos/G2H/qos_init_g2h_v30.c217
-rw-r--r--drivers/renesas/rzg/qos/G2H/qos_init_g2h_v30.h12
-rw-r--r--drivers/renesas/rzg/qos/G2M/qos_init_g2m_v10.c148
-rw-r--r--drivers/renesas/rzg/qos/G2M/qos_init_g2m_v10.h12
-rw-r--r--drivers/renesas/rzg/qos/G2M/qos_init_g2m_v10_mstat.h232
-rw-r--r--drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11.c218
-rw-r--r--drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11.h12
-rw-r--r--drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11_mstat195.h230
-rw-r--r--drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11_mstat390.h230
-rw-r--r--drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11_qoswt195.h230
-rw-r--r--drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11_qoswt390.h230
-rw-r--r--drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30.c210
-rw-r--r--drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30.h12
-rw-r--r--drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30_mstat195.h230
-rw-r--r--drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30_mstat390.h230
-rw-r--r--drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30_qoswt195.h230
-rw-r--r--drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30_qoswt390.h230
-rw-r--r--drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10.c196
-rw-r--r--drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10.h12
-rw-r--r--drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10_mstat195.h245
-rw-r--r--drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10_mstat390.h245
-rw-r--r--drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10_qoswt195.h245
-rw-r--r--drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10_qoswt390.h245
-rw-r--r--drivers/renesas/rzg/qos/qos.mk60
-rw-r--r--drivers/renesas/rzg/qos/qos_common.h105
-rw-r--r--drivers/renesas/rzg/qos/qos_init.c267
-rw-r--r--drivers/renesas/rzg/qos/qos_init.h13
-rw-r--r--drivers/rpi3/gpio/rpi3_gpio.c164
-rw-r--r--drivers/rpi3/mailbox/rpi3_mbox.c82
-rw-r--r--drivers/rpi3/rng/rpi3_rng.c75
-rw-r--r--drivers/rpi3/sdhost/rpi3_sdhost.c679
-rw-r--r--drivers/scmi-msg/base.c193
-rw-r--r--drivers/scmi-msg/base.h75
-rw-r--r--drivers/scmi-msg/clock.c381
-rw-r--r--drivers/scmi-msg/clock.h150
-rw-r--r--drivers/scmi-msg/common.h144
-rw-r--r--drivers/scmi-msg/entry.c91
-rw-r--r--drivers/scmi-msg/power_domain.c239
-rw-r--r--drivers/scmi-msg/power_domain.h72
-rw-r--r--drivers/scmi-msg/reset_domain.c197
-rw-r--r--drivers/scmi-msg/reset_domain.h122
-rw-r--r--drivers/scmi-msg/smt.c206
-rw-r--r--drivers/st/bsec/bsec2.c961
-rw-r--r--drivers/st/clk/clk-stm32-core.c1096
-rw-r--r--drivers/st/clk/clk-stm32-core.h393
-rw-r--r--drivers/st/clk/clk-stm32mp13.c2332
-rw-r--r--drivers/st/clk/stm32mp1_clk.c2373
-rw-r--r--drivers/st/clk/stm32mp_clkfunc.c377
-rw-r--r--drivers/st/crypto/stm32_hash.c364
-rw-r--r--drivers/st/crypto/stm32_pka.c707
-rw-r--r--drivers/st/crypto/stm32_rng.c269
-rw-r--r--drivers/st/crypto/stm32_saes.c913
-rw-r--r--drivers/st/ddr/stm32mp1_ddr.c764
-rw-r--r--drivers/st/ddr/stm32mp1_ddr_helpers.c26
-rw-r--r--drivers/st/ddr/stm32mp1_ram.c151
-rw-r--r--drivers/st/ddr/stm32mp_ddr.c106
-rw-r--r--drivers/st/ddr/stm32mp_ddr_test.c148
-rw-r--r--drivers/st/ddr/stm32mp_ram.c60
-rw-r--r--drivers/st/etzpc/etzpc.c246
-rw-r--r--drivers/st/fmc/stm32_fmc2_nand.c934
-rw-r--r--drivers/st/gpio/stm32_gpio.c323
-rw-r--r--drivers/st/i2c/stm32_i2c.c982
-rw-r--r--drivers/st/io/io_mmc.c143
-rw-r--r--drivers/st/iwdg/stm32_iwdg.c157
-rw-r--r--drivers/st/mmc/stm32_sdmmc2.c798
-rw-r--r--drivers/st/pmic/stm32mp_pmic.c526
-rw-r--r--drivers/st/pmic/stpmic1.c937
-rw-r--r--drivers/st/regulator/regulator_core.c560
-rw-r--r--drivers/st/regulator/regulator_fixed.c87
-rw-r--r--drivers/st/reset/stm32mp1_reset.c69
-rw-r--r--drivers/st/spi/stm32_qspi.c508
-rw-r--r--drivers/st/uart/aarch32/stm32_console.S261
-rw-r--r--drivers/st/uart/stm32_uart.c439
-rw-r--r--drivers/st/usb/stm32mp1_usb.c1091
-rw-r--r--drivers/synopsys/emmc/dw_mmc.c432
-rw-r--r--drivers/synopsys/ufs/dw_ufs.c202
-rw-r--r--drivers/ti/uart/aarch32/16550_console.S274
-rw-r--r--drivers/ti/uart/aarch64/16550_console.S267
-rw-r--r--drivers/ufs/ufs.c911
-rw-r--r--drivers/usb/usb_device.c845
-rw-r--r--fdts/a5ds.dts158
-rw-r--r--fdts/arm_fpga.dts108
-rw-r--r--fdts/corstone700.dtsi161
-rw-r--r--fdts/corstone700_fpga.dts34
-rw-r--r--fdts/corstone700_fvp.dts40
-rw-r--r--fdts/cot_descriptors.dtsi320
-rw-r--r--fdts/fvp-base-gicv2-psci.dts18
-rw-r--r--fdts/fvp-base-gicv2.dtsi21
-rw-r--r--fdts/fvp-base-gicv3-psci-1t.dts18
-rw-r--r--fdts/fvp-base-gicv3-psci-dynamiq-2t.dts23
-rw-r--r--fdts/fvp-base-gicv3-psci-dynamiq-common.dtsi10
-rw-r--r--fdts/fvp-base-gicv3-psci-dynamiq.dts23
-rw-r--r--fdts/fvp-base-gicv3-psci.dts18
-rw-r--r--fdts/fvp-base-gicv3.dtsi31
-rw-r--r--fdts/fvp-base-psci-common.dtsi251
-rw-r--r--fdts/fvp-defs-dynamiq.dtsi289
-rw-r--r--fdts/fvp-defs.dtsi382
-rw-r--r--fdts/fvp-foundation-gicv2-psci.dts151
-rw-r--r--fdts/fvp-foundation-gicv3-psci.dts160
-rw-r--r--fdts/fvp-foundation-motherboard.dtsi184
-rw-r--r--fdts/fvp-ve-Cortex-A5x1.dts167
-rw-r--r--fdts/fvp-ve-Cortex-A7x1.dts102
-rw-r--r--fdts/juno-ethosn.dtsi76
-rw-r--r--fdts/juno.dts15
-rw-r--r--fdts/morello-fvp.dts167
-rw-r--r--fdts/morello-soc.dts268
-rw-r--r--fdts/morello.dtsi106
-rw-r--r--fdts/n1sdp-multi-chip.dts122
-rw-r--r--fdts/n1sdp-single-chip.dts92
-rw-r--r--fdts/n1sdp.dtsi210
-rw-r--r--fdts/rtsm_ve-motherboard.dtsi260
-rw-r--r--fdts/stm32mp1-cot-descriptors.dtsi156
-rw-r--r--fdts/stm32mp13-bl2.dtsi85
-rw-r--r--fdts/stm32mp13-ddr.dtsi184
-rw-r--r--fdts/stm32mp13-ddr3-1x4Gb-1066-binF.dtsi100
-rw-r--r--fdts/stm32mp13-fw-config.dtsi51
-rw-r--r--fdts/stm32mp13-pinctrl.dtsi103
-rw-r--r--fdts/stm32mp131.dtsi584
-rw-r--r--fdts/stm32mp133.dtsi7
-rw-r--r--fdts/stm32mp135.dtsi7
-rw-r--r--fdts/stm32mp135f-dk-fw-config.dts7
-rw-r--r--fdts/stm32mp135f-dk.dts331
-rw-r--r--fdts/stm32mp13xa.dtsi5
-rw-r--r--fdts/stm32mp13xc.dtsi27
-rw-r--r--fdts/stm32mp13xd.dtsi5
-rw-r--r--fdts/stm32mp13xf.dtsi26
-rw-r--r--fdts/stm32mp15-bl2.dtsi115
-rw-r--r--fdts/stm32mp15-bl32.dtsi46
-rw-r--r--fdts/stm32mp15-ddr.dtsi112
-rw-r--r--fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi107
-rw-r--r--fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi107
-rw-r--r--fdts/stm32mp15-ddr3-dhsom-2x4Gb-1066-binG.dtsi108
-rw-r--r--fdts/stm32mp15-fw-config.dtsi83
-rw-r--r--fdts/stm32mp15-pinctrl.dtsi413
-rw-r--r--fdts/stm32mp151.dtsi689
-rw-r--r--fdts/stm32mp153.dtsi19
-rw-r--r--fdts/stm32mp157.dtsi7
-rw-r--r--fdts/stm32mp157a-avenger96-fw-config.dts7
-rw-r--r--fdts/stm32mp157a-avenger96.dts303
-rw-r--r--fdts/stm32mp157a-dhcor-avenger96-fw-config.dts7
-rw-r--r--fdts/stm32mp157a-dhcor-avenger96.dts24
-rw-r--r--fdts/stm32mp157a-dk1-fw-config.dts7
-rw-r--r--fdts/stm32mp157a-dk1.dts27
-rw-r--r--fdts/stm32mp157a-ed1-fw-config.dts7
-rw-r--r--fdts/stm32mp157a-ev1-fw-config.dts7
-rw-r--r--fdts/stm32mp157c-dhcom-pdk2-fw-config.dts7
-rw-r--r--fdts/stm32mp157c-dhcom-pdk2.dts26
-rw-r--r--fdts/stm32mp157c-dk2-fw-config.dts7
-rw-r--r--fdts/stm32mp157c-dk2.dts33
-rw-r--r--fdts/stm32mp157c-ed1-fw-config.dts7
-rw-r--r--fdts/stm32mp157c-ed1.dts342
-rw-r--r--fdts/stm32mp157c-ev1-fw-config.dts7
-rw-r--r--fdts/stm32mp157c-ev1.dts63
-rw-r--r--fdts/stm32mp157c-lxa-mc1-fw-config.dts7
-rw-r--r--fdts/stm32mp157c-lxa-mc1.dts93
-rw-r--r--fdts/stm32mp157c-odyssey-fw-config.dts7
-rw-r--r--fdts/stm32mp157c-odyssey-som.dtsi322
-rw-r--r--fdts/stm32mp157c-odyssey.dts40
-rw-r--r--fdts/stm32mp157d-dk1-fw-config.dts7
-rw-r--r--fdts/stm32mp157d-ed1-fw-config.dts7
-rw-r--r--fdts/stm32mp157d-ev1-fw-config.dts7
-rw-r--r--fdts/stm32mp157f-dk2-fw-config.dts7
-rw-r--r--fdts/stm32mp157f-ed1-fw-config.dts7
-rw-r--r--fdts/stm32mp157f-ev1-fw-config.dts7
-rw-r--r--fdts/stm32mp15xc.dtsi18
-rw-r--r--fdts/stm32mp15xx-dhcom-pdk2.dtsi44
-rw-r--r--fdts/stm32mp15xx-dhcom-som.dtsi336
-rw-r--r--fdts/stm32mp15xx-dhcor-avenger96.dtsi100
-rw-r--r--fdts/stm32mp15xx-dhcor-io1v8.dtsi28
-rw-r--r--fdts/stm32mp15xx-dhcor-som.dtsi286
-rw-r--r--fdts/stm32mp15xx-dkx.dtsi341
-rw-r--r--fdts/stm32mp15xx-osd32.dtsi278
-rw-r--r--fdts/stm32mp15xxaa-pinctrl.dtsi85
-rw-r--r--fdts/stm32mp15xxab-pinctrl.dtsi57
-rw-r--r--fdts/stm32mp15xxac-pinctrl.dtsi73
-rw-r--r--fdts/stm32mp15xxad-pinctrl.dtsi57
-rw-r--r--fdts/tc.dts567
-rw-r--r--include/arch/aarch32/arch.h784
-rw-r--r--include/arch/aarch32/arch_features.h26
-rw-r--r--include/arch/aarch32/arch_helpers.h474
-rw-r--r--include/arch/aarch32/asm_macros.S237
-rw-r--r--include/arch/aarch32/assert_macros.S26
-rw-r--r--include/arch/aarch32/console_macros.S51
-rw-r--r--include/arch/aarch32/el3_common_macros.S458
-rw-r--r--include/arch/aarch32/smccc_helpers.h177
-rw-r--r--include/arch/aarch32/smccc_macros.S241
-rw-r--r--include/arch/aarch64/arch.h1316
-rw-r--r--include/arch/aarch64/arch_features.h268
-rw-r--r--include/arch/aarch64/arch_helpers.h671
-rw-r--r--include/arch/aarch64/asm_macros.S244
-rw-r--r--include/arch/aarch64/assert_macros.S29
-rw-r--r--include/arch/aarch64/console_macros.S54
-rw-r--r--include/arch/aarch64/el2_common_macros.S422
-rw-r--r--include/arch/aarch64/el3_common_macros.S570
-rw-r--r--include/arch/aarch64/smccc_helpers.h144
-rw-r--r--include/bl1/bl1.h102
-rw-r--r--include/bl1/tbbr/tbbr_img_desc.h14
-rw-r--r--include/bl2/bl2.h18
-rw-r--r--include/bl2u/bl2u.h12
-rw-r--r--include/bl31/bl31.h27
-rw-r--r--include/bl31/ea_handle.h24
-rw-r--r--include/bl31/ehf.h92
-rw-r--r--include/bl31/interrupt_mgmt.h155
-rw-r--r--include/bl32/payloads/tlk.h72
-rw-r--r--include/bl32/pnc/pnc.h29
-rw-r--r--include/bl32/sp_min/platform_sp_min.h28
-rw-r--r--include/bl32/tsp/platform_tsp.h17
-rw-r--r--include/bl32/tsp/tsp.h112
-rw-r--r--include/common/asm_macros_common.S113
-rw-r--r--include/common/bl_common.h195
-rw-r--r--include/common/bl_common.ld.h231
-rw-r--r--include/common/debug.h119
-rw-r--r--include/common/desc_image_load.h48
-rw-r--r--include/common/ep_info.h68
-rw-r--r--include/common/fdt_fixup.h38
-rw-r--r--include/common/fdt_wrappers.h61
-rw-r--r--include/common/feat_detect.h32
-rw-r--r--include/common/image_decompress.h24
-rw-r--r--include/common/interrupt_props.h29
-rw-r--r--include/common/nv_cntr_ids.h9
-rw-r--r--include/common/param_header.h35
-rw-r--r--include/common/romlib.h16
-rw-r--r--include/common/runtime_svc.h138
-rw-r--r--include/common/tbbr/cot_def.h57
-rw-r--r--include/common/tbbr/tbbr_img_def.h37
-rw-r--r--include/common/tf_crc32.h16
-rw-r--r--include/common/uuid.h18
-rw-r--r--include/drivers/allwinner/axp.h59
-rw-r--r--include/drivers/allwinner/sunxi_rsb.h20
-rw-r--r--include/drivers/amlogic/crypto/sha_dma.h36
-rw-r--r--include/drivers/amlogic/meson_console.h30
-rw-r--r--include/drivers/arm/arm_gicv3_common.h28
-rw-r--r--include/drivers/arm/cci.h125
-rw-r--r--include/drivers/arm/ccn.h113
-rw-r--r--include/drivers/arm/cryptocell/712/cc_crypto_boot_defs.h34
-rw-r--r--include/drivers/arm/cryptocell/712/cc_pal_sb_plat.h33
-rw-r--r--include/drivers/arm/cryptocell/712/cc_pal_types.h40
-rw-r--r--include/drivers/arm/cryptocell/712/cc_pal_types_plat.h25
-rw-r--r--include/drivers/arm/cryptocell/712/cc_sec_defs.h34
-rw-r--r--include/drivers/arm/cryptocell/712/crypto_driver.h35
-rw-r--r--include/drivers/arm/cryptocell/712/nvm.h55
-rw-r--r--include/drivers/arm/cryptocell/712/nvm_otp.h59
-rw-r--r--include/drivers/arm/cryptocell/712/rsa.h57
-rw-r--r--include/drivers/arm/cryptocell/712/sbrom_bsv_api.h72
-rw-r--r--include/drivers/arm/cryptocell/712/secureboot_base_func.h49
-rw-r--r--include/drivers/arm/cryptocell/712/secureboot_gen_defs.h66
-rw-r--r--include/drivers/arm/cryptocell/712/util.h72
-rw-r--r--include/drivers/arm/cryptocell/713/bsv_api.h221
-rw-r--r--include/drivers/arm/cryptocell/713/bsv_crypto_api.h76
-rw-r--r--include/drivers/arm/cryptocell/713/bsv_crypto_asym_api.h100
-rw-r--r--include/drivers/arm/cryptocell/713/bsv_crypto_defs.h94
-rw-r--r--include/drivers/arm/cryptocell/713/bsv_error.h161
-rw-r--r--include/drivers/arm/cryptocell/713/cc_address_defs.h50
-rw-r--r--include/drivers/arm/cryptocell/713/cc_boot_defs.h52
-rw-r--r--include/drivers/arm/cryptocell/713/cc_pal_types.h100
-rw-r--r--include/drivers/arm/cryptocell/713/cc_pal_types_plat.h25
-rw-r--r--include/drivers/arm/cryptocell/713/cc_pka_hw_plat_defs.h62
-rw-r--r--include/drivers/arm/cryptocell/713/cc_sec_defs.h70
-rw-r--r--include/drivers/arm/cryptocell/cc_rotpk.h13
-rw-r--r--include/drivers/arm/css/css_mhu.h19
-rw-r--r--include/drivers/arm/css/css_mhu_doorbell.h44
-rw-r--r--include/drivers/arm/css/css_scp.h52
-rw-r--r--include/drivers/arm/css/css_scpi.h109
-rw-r--r--include/drivers/arm/css/scmi.h176
-rw-r--r--include/drivers/arm/css/sds.h90
-rw-r--r--include/drivers/arm/dcc.h19
-rw-r--r--include/drivers/arm/ethosn.h62
-rw-r--r--include/drivers/arm/fvp/fvp_pwrc.h55
-rw-r--r--include/drivers/arm/gic600_multichip.h55
-rw-r--r--include/drivers/arm/gic600ae_fmu.h157
-rw-r--r--include/drivers/arm/gic_common.h99
-rw-r--r--include/drivers/arm/gicv2.h200
-rw-r--r--include/drivers/arm/gicv3.h605
-rw-r--r--include/drivers/arm/mhu.h86
-rw-r--r--include/drivers/arm/nic_400.h16
-rw-r--r--include/drivers/arm/pl011.h99
-rw-r--r--include/drivers/arm/pl061_gpio.h15
-rw-r--r--include/drivers/arm/rss_comms.h15
-rw-r--r--include/drivers/arm/sbsa.h24
-rw-r--r--include/drivers/arm/scu.h20
-rw-r--r--include/drivers/arm/smmu_v3.h71
-rw-r--r--include/drivers/arm/sp804_delay_timer.h28
-rw-r--r--include/drivers/arm/sp805.h36
-rw-r--r--include/drivers/arm/tzc380.h164
-rw-r--r--include/drivers/arm/tzc400.h160
-rw-r--r--include/drivers/arm/tzc_common.h89
-rw-r--r--include/drivers/arm/tzc_dmc500.h151
-rw-r--r--include/drivers/arm/tzc_dmc620.h104
-rw-r--r--include/drivers/auth/auth_common.h120
-rw-r--r--include/drivers/auth/auth_mod.h92
-rw-r--r--include/drivers/auth/crypto_mod.h155
-rw-r--r--include/drivers/auth/img_parser_mod.h64
-rw-r--r--include/drivers/auth/mbedtls/mbedtls_common.h12
-rw-r--r--include/drivers/auth/mbedtls/mbedtls_config.h152
-rw-r--r--include/drivers/auth/tbbr_cot_common.h29
-rw-r--r--include/drivers/brcm/chimp.h94
-rw-r--r--include/drivers/brcm/chimp_nv_defs.h419
-rw-r--r--include/drivers/brcm/dmu.h35
-rw-r--r--include/drivers/brcm/emmc/bcm_emmc.h104
-rw-r--r--include/drivers/brcm/emmc/emmc_api.h47
-rw-r--r--include/drivers/brcm/emmc/emmc_brcm_rdb_sd4_top.h1116
-rw-r--r--include/drivers/brcm/emmc/emmc_chal_sd.h202
-rw-r--r--include/drivers/brcm/emmc/emmc_chal_types.h20
-rw-r--r--include/drivers/brcm/emmc/emmc_csl_sd.h96
-rw-r--r--include/drivers/brcm/emmc/emmc_csl_sdcmd.h168
-rw-r--r--include/drivers/brcm/emmc/emmc_csl_sdprot.h435
-rw-r--r--include/drivers/brcm/emmc/emmc_pboot_hal_memory_drv.h94
-rw-r--r--include/drivers/brcm/fru.h144
-rw-r--r--include/drivers/brcm/i2c/i2c.h161
-rw-r--r--include/drivers/brcm/i2c/i2c_regs.h271
-rw-r--r--include/drivers/brcm/iproc_gpio.h20
-rw-r--r--include/drivers/brcm/mdio/mdio.h31
-rw-r--r--include/drivers/brcm/ocotp.h27
-rw-r--r--include/drivers/brcm/scp.h14
-rw-r--r--include/drivers/brcm/sf.h90
-rw-r--r--include/drivers/brcm/sotp.h71
-rw-r--r--include/drivers/brcm/spi.h21
-rw-r--r--include/drivers/brcm/spi_flash.h18
-rw-r--r--include/drivers/brcm/usbh_xhci_regs.h4809
-rw-r--r--include/drivers/cadence/cdns_uart.h44
-rw-r--r--include/drivers/cfi/v2m_flash.h45
-rw-r--r--include/drivers/clk.h28
-rw-r--r--include/drivers/console.h83
-rw-r--r--include/drivers/console_assertions.h29
-rw-r--r--include/drivers/coreboot/cbmem_console.h25
-rw-r--r--include/drivers/delay_timer.h53
-rw-r--r--include/drivers/dw_ufs.h110
-rw-r--r--include/drivers/fwu/fwu.h16
-rw-r--r--include/drivers/fwu/fwu_metadata.h74
-rw-r--r--include/drivers/generic_delay_timer.h16
-rw-r--r--include/drivers/gpio.h40
-rw-r--r--include/drivers/io/io_block.h28
-rw-r--r--include/drivers/io/io_driver.h59
-rw-r--r--include/drivers/io/io_dummy.h12
-rw-r--r--include/drivers/io/io_encrypted.h15
-rw-r--r--include/drivers/io/io_fip.h15
-rw-r--r--include/drivers/io/io_memmap.h14
-rw-r--r--include/drivers/io/io_mtd.h70
-rw-r--r--include/drivers/io/io_semihosting.h14
-rw-r--r--include/drivers/io/io_storage.h103
-rw-r--r--include/drivers/marvell/addr_map.h21
-rw-r--r--include/drivers/marvell/amb_adec.h36
-rw-r--r--include/drivers/marvell/ap807_clocks_init.h14
-rw-r--r--include/drivers/marvell/aro.h49
-rw-r--r--include/drivers/marvell/cache_llc.h62
-rw-r--r--include/drivers/marvell/ccu.h53
-rw-r--r--include/drivers/marvell/gwin.h19
-rw-r--r--include/drivers/marvell/i2c.h20
-rw-r--r--include/drivers/marvell/io_win.h21
-rw-r--r--include/drivers/marvell/iob.h31
-rw-r--r--include/drivers/marvell/mci.h18
-rw-r--r--include/drivers/marvell/mochi/ap_setup.h18
-rw-r--r--include/drivers/marvell/mochi/cp110_setup.h66
-rw-r--r--include/drivers/marvell/thermal.h31
-rw-r--r--include/drivers/marvell/uart/a3700_console.h74
-rw-r--r--include/drivers/measured_boot/event_log/event_log.h127
-rw-r--r--include/drivers/measured_boot/event_log/tcg.h309
-rw-r--r--include/drivers/measured_boot/rss/rss_measured_boot.h55
-rw-r--r--include/drivers/mentor/mi2cv.h40
-rw-r--r--include/drivers/mmc.h272
-rw-r--r--include/drivers/nand.h67
-rw-r--r--include/drivers/nxp/auth/csf_hdr_parser/csf_hdr.h155
-rw-r--r--include/drivers/nxp/console/plat_console.h38
-rw-r--r--include/drivers/nxp/crypto/caam/caam.h53
-rw-r--r--include/drivers/nxp/crypto/caam/caam_io.h56
-rw-r--r--include/drivers/nxp/crypto/caam/hash.h85
-rw-r--r--include/drivers/nxp/crypto/caam/jobdesc.h56
-rw-r--r--include/drivers/nxp/crypto/caam/jr_driver_config.h205
-rw-r--r--include/drivers/nxp/crypto/caam/rsa.h40
-rw-r--r--include/drivers/nxp/crypto/caam/sec_hw_specific.h503
-rw-r--r--include/drivers/nxp/crypto/caam/sec_jr_driver.h178
-rw-r--r--include/drivers/nxp/csu/csu.h42
-rw-r--r--include/drivers/nxp/dcfg/dcfg.h103
-rw-r--r--include/drivers/nxp/dcfg/dcfg_lsch2.h85
-rw-r--r--include/drivers/nxp/dcfg/dcfg_lsch3.h80
-rw-r--r--include/drivers/nxp/dcfg/scfg.h65
-rw-r--r--include/drivers/nxp/ddr/ddr.h151
-rw-r--r--include/drivers/nxp/ddr/ddr_io.h38
-rw-r--r--include/drivers/nxp/ddr/dimm.h330
-rw-r--r--include/drivers/nxp/ddr/fsl-mmdc/fsl_mmdc.h173
-rw-r--r--include/drivers/nxp/ddr/immap.h125
-rw-r--r--include/drivers/nxp/ddr/opts.h119
-rw-r--r--include/drivers/nxp/ddr/regs.h109
-rw-r--r--include/drivers/nxp/ddr/utility.h24
-rw-r--r--include/drivers/nxp/flexspi/flash_info.h89
-rw-r--r--include/drivers/nxp/flexspi/fspi_api.h122
-rw-r--r--include/drivers/nxp/flexspi/xspi_error_codes.h28
-rw-r--r--include/drivers/nxp/gic/gicv2/plat_gic.h72
-rw-r--r--include/drivers/nxp/gic/gicv3/plat_gic.h120
-rw-r--r--include/drivers/nxp/gpio/nxp_gpio.h53
-rw-r--r--include/drivers/nxp/i2c/i2c.h52
-rw-r--r--include/drivers/nxp/ifc/ifc_nand.h19
-rw-r--r--include/drivers/nxp/ifc/ifc_nor.h14
-rw-r--r--include/drivers/nxp/interconnect/ls_interconnect.h19
-rw-r--r--include/drivers/nxp/pmu/pmu.h75
-rw-r--r--include/drivers/nxp/qspi/qspi.h30
-rw-r--r--include/drivers/nxp/sd/sd_mmc.h337
-rw-r--r--include/drivers/nxp/sec_mon/snvs.h86
-rw-r--r--include/drivers/nxp/sfp/fuse_prov.h83
-rw-r--r--include/drivers/nxp/sfp/sfp.h100
-rw-r--r--include/drivers/nxp/sfp/sfp_error_codes.h40
-rw-r--r--include/drivers/nxp/smmu/nxp_smmu.h30
-rw-r--r--include/drivers/nxp/timer/nxp_timer.h35
-rw-r--r--include/drivers/nxp/tzc/plat_tzc380.h47
-rw-r--r--include/drivers/nxp/tzc/plat_tzc400.h55
-rw-r--r--include/drivers/partition/efi.h37
-rw-r--r--include/drivers/partition/gpt.h52
-rw-r--r--include/drivers/partition/mbr.h29
-rw-r--r--include/drivers/partition/partition.h54
-rw-r--r--include/drivers/rambus/trng_ip_76.h18
-rw-r--r--include/drivers/raw_nand.h188
-rw-r--r--include/drivers/renesas/rcar/console/console.h25
-rw-r--r--include/drivers/rpi3/gpio/rpi3_gpio.h34
-rw-r--r--include/drivers/rpi3/mailbox/rpi3_mbox.h39
-rw-r--r--include/drivers/rpi3/rng/rpi3_rng.h12
-rw-r--r--include/drivers/rpi3/sdhost/rpi3_sdhost.h123
-rw-r--r--include/drivers/scmi-msg.h207
-rw-r--r--include/drivers/scmi.h29
-rw-r--r--include/drivers/spi_mem.h130
-rw-r--r--include/drivers/spi_nand.h49
-rw-r--r--include/drivers/spi_nor.h58
-rw-r--r--include/drivers/st/bsec.h129
-rw-r--r--include/drivers/st/bsec2_reg.h106
-rw-r--r--include/drivers/st/etzpc.h38
-rw-r--r--include/drivers/st/io_mmc.h18
-rw-r--r--include/drivers/st/regulator.h108
-rw-r--r--include/drivers/st/regulator_fixed.h12
-rw-r--r--include/drivers/st/stm32_console.h27
-rw-r--r--include/drivers/st/stm32_fmc2_nand.h12
-rw-r--r--include/drivers/st/stm32_gpio.h63
-rw-r--r--include/drivers/st/stm32_hash.h32
-rw-r--r--include/drivers/st/stm32_i2c.h321
-rw-r--r--include/drivers/st/stm32_iwdg.h19
-rw-r--r--include/drivers/st/stm32_pka.h46
-rw-r--r--include/drivers/st/stm32_qspi.h12
-rw-r--r--include/drivers/st/stm32_rng.h15
-rw-r--r--include/drivers/st/stm32_saes.h59
-rw-r--r--include/drivers/st/stm32_sdmmc2.h35
-rw-r--r--include/drivers/st/stm32_uart.h159
-rw-r--r--include/drivers/st/stm32_uart_regs.h199
-rw-r--r--include/drivers/st/stm32mp13_rcc.h1878
-rw-r--r--include/drivers/st/stm32mp15_rcc.h2328
-rw-r--r--include/drivers/st/stm32mp1_clk.h38
-rw-r--r--include/drivers/st/stm32mp1_ddr.h134
-rw-r--r--include/drivers/st/stm32mp1_ddr_helpers.h12
-rw-r--r--include/drivers/st/stm32mp1_ddr_regs.h196
-rw-r--r--include/drivers/st/stm32mp1_pwr.h32
-rw-r--r--include/drivers/st/stm32mp1_ram.h12
-rw-r--r--include/drivers/st/stm32mp1_rcc.h12
-rw-r--r--include/drivers/st/stm32mp1_usb.h16
-rw-r--r--include/drivers/st/stm32mp_clkfunc.h36
-rw-r--r--include/drivers/st/stm32mp_ddr.h69
-rw-r--r--include/drivers/st/stm32mp_ddr_test.h17
-rw-r--r--include/drivers/st/stm32mp_ddrctrl_regs.h265
-rw-r--r--include/drivers/st/stm32mp_pmic.h58
-rw-r--r--include/drivers/st/stm32mp_ram.h33
-rw-r--r--include/drivers/st/stm32mp_reset.h50
-rw-r--r--include/drivers/st/stpmic1.h198
-rw-r--r--include/drivers/synopsys/dw_mmc.h24
-rw-r--r--include/drivers/ti/uart/uart_16550.h94
-rw-r--r--include/drivers/ufs.h569
-rw-r--r--include/drivers/usb_device.h278
-rw-r--r--include/dt-bindings/clock/stm32mp1-clks.h12
-rw-r--r--include/dt-bindings/clock/stm32mp1-clksrc.h11
-rw-r--r--include/dt-bindings/clock/stm32mp13-clks.h230
-rw-r--r--include/dt-bindings/clock/stm32mp13-clksrc.h394
-rw-r--r--include/dt-bindings/clock/stm32mp15-clks.h278
-rw-r--r--include/dt-bindings/clock/stm32mp15-clksrc.h282
-rw-r--r--include/dt-bindings/interrupt-controller/arm-gic.h26
-rw-r--r--include/dt-bindings/interrupt-controller/irq.h23
-rw-r--r--include/dt-bindings/pinctrl/stm32-pinfunc.h42
-rw-r--r--include/dt-bindings/reset/stm32mp1-resets.h11
-rw-r--r--include/dt-bindings/reset/stm32mp13-resets.h96
-rw-r--r--include/dt-bindings/reset/stm32mp15-resets.h123
-rw-r--r--include/dt-bindings/soc/st,stm32-etzpc.h20
-rw-r--r--include/dt-bindings/soc/stm32mp13-tzc400.h35
-rw-r--r--include/dt-bindings/soc/stm32mp15-tzc400.h36
-rw-r--r--include/export/README33
-rw-r--r--include/export/common/bl_common_exp.h95
-rw-r--r--include/export/common/ep_info_exp.h119
-rw-r--r--include/export/common/param_header_exp.h42
-rw-r--r--include/export/common/tbbr/tbbr_img_def_exp.h119
-rw-r--r--include/export/drivers/gpio_exp.h23
-rw-r--r--include/export/lib/bl_aux_params/bl_aux_params_exp.h89
-rw-r--r--include/export/lib/utils_def_exp.h37
-rw-r--r--include/export/plat/mediatek/common/plat_params_exp.h19
-rw-r--r--include/export/plat/rockchip/common/plat_params_exp.h35
-rw-r--r--include/lib/bakery_lock.h105
-rw-r--r--include/lib/bl_aux_params/bl_aux_params.h30
-rw-r--r--include/lib/cassert.h23
-rw-r--r--include/lib/coreboot.h45
-rw-r--r--include/lib/cpus/aarch32/aem_generic.h15
-rw-r--r--include/lib/cpus/aarch32/cortex_a12.h22
-rw-r--r--include/lib/cpus/aarch32/cortex_a15.h30
-rw-r--r--include/lib/cpus/aarch32/cortex_a17.h27
-rw-r--r--include/lib/cpus/aarch32/cortex_a32.h22
-rw-r--r--include/lib/cpus/aarch32/cortex_a5.h22
-rw-r--r--include/lib/cpus/aarch32/cortex_a53.h73
-rw-r--r--include/lib/cpus/aarch32/cortex_a57.h84
-rw-r--r--include/lib/cpus/aarch32/cortex_a7.h22
-rw-r--r--include/lib/cpus/aarch32/cortex_a72.h58
-rw-r--r--include/lib/cpus/aarch32/cortex_a9.h33
-rw-r--r--include/lib/cpus/aarch32/cpu_macros.S230
-rw-r--r--include/lib/cpus/aarch64/a64fx.h15
-rw-r--r--include/lib/cpus/aarch64/aem_generic.h18
-rw-r--r--include/lib/cpus/aarch64/cortex_a35.h29
-rw-r--r--include/lib/cpus/aarch64/cortex_a510.h41
-rw-r--r--include/lib/cpus/aarch64/cortex_a53.h85
-rw-r--r--include/lib/cpus/aarch64/cortex_a55.h48
-rw-r--r--include/lib/cpus/aarch64/cortex_a57.h88
-rw-r--r--include/lib/cpus/aarch64/cortex_a65.h31
-rw-r--r--include/lib/cpus/aarch64/cortex_a65ae.h31
-rw-r--r--include/lib/cpus/aarch64/cortex_a710.h65
-rw-r--r--include/lib/cpus/aarch64/cortex_a72.h79
-rw-r--r--include/lib/cpus/aarch64/cortex_a73.h45
-rw-r--r--include/lib/cpus/aarch64/cortex_a75.h55
-rw-r--r--include/lib/cpus/aarch64/cortex_a76.h50
-rw-r--r--include/lib/cpus/aarch64/cortex_a76ae.h28
-rw-r--r--include/lib/cpus/aarch64/cortex_a77.h45
-rw-r--r--include/lib/cpus/aarch64/cortex_a78.h54
-rw-r--r--include/lib/cpus/aarch64/cortex_a78_ae.h31
-rw-r--r--include/lib/cpus/aarch64/cortex_a78c.h44
-rw-r--r--include/lib/cpus/aarch64/cortex_hayes.h23
-rw-r--r--include/lib/cpus/aarch64/cortex_hunter.h26
-rw-r--r--include/lib/cpus/aarch64/cortex_hunter_elp_arm.h26
-rw-r--r--include/lib/cpus/aarch64/cortex_makalu.h26
-rw-r--r--include/lib/cpus/aarch64/cortex_x1.h32
-rw-r--r--include/lib/cpus/aarch64/cortex_x2.h62
-rw-r--r--include/lib/cpus/aarch64/cortex_x3.h32
-rw-r--r--include/lib/cpus/aarch64/cpu_macros.S314
-rw-r--r--include/lib/cpus/aarch64/cpuamu.h48
-rw-r--r--include/lib/cpus/aarch64/denver.h54
-rw-r--r--include/lib/cpus/aarch64/dsu_def.h42
-rw-r--r--include/lib/cpus/aarch64/generic.h18
-rw-r--r--include/lib/cpus/aarch64/neoverse_e1.h31
-rw-r--r--include/lib/cpus/aarch64/neoverse_n1.h70
-rw-r--r--include/lib/cpus/aarch64/neoverse_n2.h61
-rw-r--r--include/lib/cpus/aarch64/neoverse_n_common.h18
-rw-r--r--include/lib/cpus/aarch64/neoverse_poseidon.h27
-rw-r--r--include/lib/cpus/aarch64/neoverse_v1.h44
-rw-r--r--include/lib/cpus/aarch64/neoverse_v2.h26
-rw-r--r--include/lib/cpus/aarch64/qemu_max.h22
-rw-r--r--include/lib/cpus/aarch64/rainier.h66
-rw-r--r--include/lib/cpus/errata_report.h36
-rw-r--r--include/lib/cpus/wa_cve_2017_5715.h12
-rw-r--r--include/lib/cpus/wa_cve_2018_3639.h12
-rw-r--r--include/lib/cpus/wa_cve_2022_23960.h12
-rw-r--r--include/lib/debugfs.h83
-rw-r--r--include/lib/el3_runtime/aarch32/context.h70
-rw-r--r--include/lib/el3_runtime/aarch64/context.h567
-rw-r--r--include/lib/el3_runtime/context_mgmt.h89
-rw-r--r--include/lib/el3_runtime/cpu_data.h237
-rw-r--r--include/lib/el3_runtime/pubsub.h106
-rw-r--r--include/lib/el3_runtime/pubsub_events.h43
-rw-r--r--include/lib/extensions/amu.h47
-rw-r--r--include/lib/extensions/brbe.h12
-rw-r--r--include/lib/extensions/mpam.h14
-rw-r--r--include/lib/extensions/pauth.h18
-rw-r--r--include/lib/extensions/ras.h203
-rw-r--r--include/lib/extensions/ras_arch.h265
-rw-r--r--include/lib/extensions/sme.h27
-rw-r--r--include/lib/extensions/spe.h16
-rw-r--r--include/lib/extensions/sve.h15
-rw-r--r--include/lib/extensions/sys_reg_trace.h18
-rw-r--r--include/lib/extensions/trbe.h12
-rw-r--r--include/lib/extensions/trf.h12
-rw-r--r--include/lib/fconf/fconf.h70
-rw-r--r--include/lib/fconf/fconf_amu_getter.h20
-rw-r--r--include/lib/fconf/fconf_dyn_cfg_getter.h39
-rw-r--r--include/lib/fconf/fconf_mpmm_getter.h20
-rw-r--r--include/lib/fconf/fconf_tbbr_getter.h32
-rw-r--r--include/lib/gpt_rme/gpt_rme.h280
-rw-r--r--include/lib/libc/aarch32/endian_.h146
-rw-r--r--include/lib/libc/aarch32/float.h100
-rw-r--r--include/lib/libc/aarch32/inttypes_.h28
-rw-r--r--include/lib/libc/aarch32/limits_.h26
-rw-r--r--include/lib/libc/aarch32/stddef_.h15
-rw-r--r--include/lib/libc/aarch32/stdint_.h28
-rw-r--r--include/lib/libc/aarch32/stdio_.h15
-rw-r--r--include/lib/libc/aarch64/endian_.h128
-rw-r--r--include/lib/libc/aarch64/float.h94
-rw-r--r--include/lib/libc/aarch64/inttypes_.h28
-rw-r--r--include/lib/libc/aarch64/limits_.h26
-rw-r--r--include/lib/libc/aarch64/setjmp_.h30
-rw-r--r--include/lib/libc/aarch64/stddef_.h15
-rw-r--r--include/lib/libc/aarch64/stdint_.h31
-rw-r--r--include/lib/libc/aarch64/stdio_.h15
-rw-r--r--include/lib/libc/arm_acle.h24
-rw-r--r--include/lib/libc/assert.h34
-rw-r--r--include/lib/libc/cdefs.h38
-rw-r--r--include/lib/libc/endian.h191
-rw-r--r--include/lib/libc/errno.h169
-rw-r--r--include/lib/libc/inttypes.h41
-rw-r--r--include/lib/libc/limits.h19
-rw-r--r--include/lib/libc/setjmp.h20
-rw-r--r--include/lib/libc/stdarg.h20
-rw-r--r--include/lib/libc/stdbool.h17
-rw-r--r--include/lib/libc/stddef.h27
-rw-r--r--include/lib/libc/stdint.h122
-rw-r--r--include/lib/libc/stdio.h31
-rw-r--r--include/lib/libc/stdlib.h32
-rw-r--r--include/lib/libc/string.h32
-rw-r--r--include/lib/libc/sys/cdefs.h922
-rw-r--r--include/lib/libc/time.h18
-rw-r--r--include/lib/libfdt/fdt.h66
-rw-r--r--include/lib/libfdt/libfdt.h2147
-rw-r--r--include/lib/libfdt/libfdt_env.h96
-rw-r--r--include/lib/mmio.h76
-rw-r--r--include/lib/mpmm/mpmm.h57
-rw-r--r--include/lib/object_pool.h79
-rw-r--r--include/lib/optee_utils.h20
-rw-r--r--include/lib/pmf/aarch32/pmf_asm_macros.S28
-rw-r--r--include/lib/pmf/aarch64/pmf_asm_macros.S30
-rw-r--r--include/lib/pmf/pmf.h75
-rw-r--r--include/lib/pmf/pmf_helpers.h256
-rw-r--r--include/lib/psa/delegated_attestation.h109
-rw-r--r--include/lib/psa/measured_boot.h77
-rw-r--r--include/lib/psa/psa/client.h102
-rw-r--r--include/lib/psa/psa/error.h42
-rw-r--r--include/lib/psa/psa_manifest/sid.h17
-rw-r--r--include/lib/psci/psci.h355
-rw-r--r--include/lib/psci/psci_lib.h99
-rw-r--r--include/lib/runtime_instr.h25
-rw-r--r--include/lib/semihosting.h60
-rw-r--r--include/lib/smccc.h226
-rw-r--r--include/lib/spinlock.h29
-rw-r--r--include/lib/utils.h94
-rw-r--r--include/lib/utils_def.h178
-rw-r--r--include/lib/xlat_mpu/xlat_mpu.h27
-rw-r--r--include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h72
-rw-r--r--include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h96
-rw-r--r--include/lib/xlat_tables/xlat_mmu_helpers.h94
-rw-r--r--include/lib/xlat_tables/xlat_tables.h99
-rw-r--r--include/lib/xlat_tables/xlat_tables_arch.h31
-rw-r--r--include/lib/xlat_tables/xlat_tables_compat.h16
-rw-r--r--include/lib/xlat_tables/xlat_tables_defs.h183
-rw-r--r--include/lib/xlat_tables/xlat_tables_v2.h416
-rw-r--r--include/lib/xlat_tables/xlat_tables_v2_helpers.h180
-rw-r--r--include/lib/zlib/tf_gunzip.h16
-rw-r--r--include/plat/arm/board/common/board_css_def.h79
-rw-r--r--include/plat/arm/board/common/v2m_def.h140
-rw-r--r--include/plat/arm/board/fvp_r/fvp_r_bl1.h13
-rw-r--r--include/plat/arm/common/aarch64/arm_macros.S104
-rw-r--r--include/plat/arm/common/aarch64/cci_macros.S37
-rw-r--r--include/plat/arm/common/arm_config.h43
-rw-r--r--include/plat/arm/common/arm_def.h780
-rw-r--r--include/plat/arm/common/arm_dyn_cfg_helpers.h17
-rw-r--r--include/plat/arm/common/arm_fconf_getter.h29
-rw-r--r--include/plat/arm/common/arm_fconf_io_storage.h19
-rw-r--r--include/plat/arm/common/arm_pas_def.h103
-rw-r--r--include/plat/arm/common/arm_reclaim_init.ld.S43
-rw-r--r--include/plat/arm/common/arm_sip_svc.h38
-rw-r--r--include/plat/arm/common/arm_spm_def.h103
-rw-r--r--include/plat/arm/common/arm_tzc_dram.ld.S30
-rw-r--r--include/plat/arm/common/fconf_arm_sp_getter.h33
-rw-r--r--include/plat/arm/common/fconf_ethosn_getter.h63
-rw-r--r--include/plat/arm/common/fconf_nv_cntr_getter.h17
-rw-r--r--include/plat/arm/common/fconf_sdei_getter.h31
-rw-r--r--include/plat/arm/common/fconf_sec_intr_config.h27
-rw-r--r--include/plat/arm/common/plat_arm.h363
-rw-r--r--include/plat/arm/common/smccc_def.h13
-rw-r--r--include/plat/arm/css/common/aarch64/css_macros.S25
-rw-r--r--include/plat/arm/css/common/css_def.h205
-rw-r--r--include/plat/arm/css/common/css_pm.h64
-rw-r--r--include/plat/arm/soc/common/soc_css.h22
-rw-r--r--include/plat/arm/soc/common/soc_css_def.h86
-rw-r--r--include/plat/brcm/common/bcm_console.h15
-rw-r--r--include/plat/brcm/common/bcm_elog.h38
-rw-r--r--include/plat/brcm/common/brcm_def.h153
-rw-r--r--include/plat/brcm/common/plat_brcm.h41
-rw-r--r--include/plat/common/common_def.h127
-rw-r--r--include/plat/common/plat_drtm.h74
-rw-r--r--include/plat/common/plat_trng.h18
-rw-r--r--include/plat/common/platform.h424
-rw-r--r--include/plat/marvell/armada/a3k/common/armada_common.h17
-rw-r--r--include/plat/marvell/armada/a3k/common/board_marvell_def.h74
-rw-r--r--include/plat/marvell/armada/a3k/common/marvell_def.h188
-rw-r--r--include/plat/marvell/armada/a3k/common/plat_marvell.h105
-rw-r--r--include/plat/marvell/armada/a8k/common/armada_common.h129
-rw-r--r--include/plat/marvell/armada/a8k/common/board_marvell_def.h74
-rw-r--r--include/plat/marvell/armada/a8k/common/efuse_def.h33
-rw-r--r--include/plat/marvell/armada/a8k/common/marvell_def.h222
-rw-r--r--include/plat/marvell/armada/a8k/common/plat_marvell.h138
-rw-r--r--include/plat/marvell/armada/a8k/common/plat_pm_trace.h99
-rw-r--r--include/plat/marvell/armada/common/aarch64/cci_macros.S39
-rw-r--r--include/plat/marvell/armada/common/aarch64/marvell_macros.S134
-rw-r--r--include/plat/marvell/armada/common/marvell_plat_priv.h34
-rw-r--r--include/plat/marvell/armada/common/marvell_pm.h26
-rw-r--r--include/plat/marvell/armada/common/mvebu.h39
-rw-r--r--include/services/arm_arch_svc.h20
-rw-r--r--include/services/drtm_svc.h241
-rw-r--r--include/services/el3_spmc_ffa_memory.h258
-rw-r--r--include/services/el3_spmc_logical_sp.h60
-rw-r--r--include/services/ffa_svc.h341
-rw-r--r--include/services/pci_svc.h59
-rw-r--r--include/services/rmm_core_manifest.h49
-rw-r--r--include/services/rmmd_svc.h188
-rw-r--r--include/services/sdei.h143
-rw-r--r--include/services/sdei_flags.h56
-rw-r--r--include/services/spm_core_manifest.h53
-rw-r--r--include/services/spm_mm_partition.h50
-rw-r--r--include/services/spm_mm_svc.h114
-rw-r--r--include/services/spmc_svc.h40
-rw-r--r--include/services/spmd_svc.h40
-rw-r--r--include/services/std_svc.h30
-rw-r--r--include/services/trng_svc.h55
-rw-r--r--include/services/trp/platform_trp.h17
-rw-r--r--include/services/trp/trp_helpers.h43
-rw-r--r--include/tools_share/cca_oid.h28
-rw-r--r--include/tools_share/dualroot_oid.h19
-rw-r--r--include/tools_share/firmware_encrypted.h42
-rw-r--r--include/tools_share/firmware_image_package.h110
-rw-r--r--include/tools_share/tbbr_oid.h166
-rw-r--r--include/tools_share/uuid.h74
-rw-r--r--lib/aarch32/arm32_aeabi_divmod.c156
-rw-r--r--lib/aarch32/arm32_aeabi_divmod_a32.S30
-rw-r--r--lib/aarch32/armclang_printf.S19
-rw-r--r--lib/aarch32/cache_helpers.S233
-rw-r--r--lib/aarch32/misc_helpers.S315
-rw-r--r--lib/aarch64/armclang_printf.S25
-rw-r--r--lib/aarch64/cache_helpers.S276
-rw-r--r--lib/aarch64/misc_helpers.S613
-rw-r--r--lib/bl_aux_params/bl_aux_params.c35
-rw-r--r--lib/compiler-rt/LICENSE.TXT91
-rw-r--r--lib/compiler-rt/builtins/arm/aeabi_ldivmod.S45
-rw-r--r--lib/compiler-rt/builtins/arm/aeabi_memcpy.S29
-rw-r--r--lib/compiler-rt/builtins/arm/aeabi_uldivmod.S45
-rw-r--r--lib/compiler-rt/builtins/assembly.h292
-rw-r--r--lib/compiler-rt/builtins/ctzdi2.c35
-rw-r--r--lib/compiler-rt/builtins/divdi3.c22
-rw-r--r--lib/compiler-rt/builtins/divmoddi4.c28
-rw-r--r--lib/compiler-rt/builtins/int_div_impl.inc95
-rw-r--r--lib/compiler-rt/builtins/int_endianness.h114
-rw-r--r--lib/compiler-rt/builtins/int_lib.h171
-rw-r--r--lib/compiler-rt/builtins/int_math.h98
-rw-r--r--lib/compiler-rt/builtins/int_types.h198
-rw-r--r--lib/compiler-rt/builtins/int_util.h47
-rw-r--r--lib/compiler-rt/builtins/lshrdi3.c38
-rw-r--r--lib/compiler-rt/builtins/popcountdi2.c32
-rw-r--r--lib/compiler-rt/builtins/popcountsi2.c29
-rw-r--r--lib/compiler-rt/builtins/udivmoddi4.c200
-rw-r--r--lib/compiler-rt/compiler-rt.mk43
-rw-r--r--lib/coreboot/coreboot.mk22
-rw-r--r--lib/coreboot/coreboot_table.c156
-rw-r--r--lib/cpus/aarch32/aem_generic.S55
-rw-r--r--lib/cpus/aarch32/cortex_a12.S84
-rw-r--r--lib/cpus/aarch32/cortex_a15.S191
-rw-r--r--lib/cpus/aarch32/cortex_a17.S185
-rw-r--r--lib/cpus/aarch32/cortex_a32.S132
-rw-r--r--lib/cpus/aarch32/cortex_a5.S84
-rw-r--r--lib/cpus/aarch32/cortex_a53.S316
-rw-r--r--lib/cpus/aarch32/cortex_a57.S618
-rw-r--r--lib/cpus/aarch32/cortex_a7.S84
-rw-r--r--lib/cpus/aarch32/cortex_a72.S278
-rw-r--r--lib/cpus/aarch32/cortex_a9.S121
-rw-r--r--lib/cpus/aarch32/cpu_helpers.S264
-rw-r--r--lib/cpus/aarch64/a64fx.S49
-rw-r--r--lib/cpus/aarch64/aem_generic.S113
-rw-r--r--lib/cpus/aarch64/cortex_a35.S196
-rw-r--r--lib/cpus/aarch64/cortex_a510.S500
-rw-r--r--lib/cpus/aarch64/cortex_a53.S409
-rw-r--r--lib/cpus/aarch64/cortex_a55.S353
-rw-r--r--lib/cpus/aarch64/cortex_a57.S686
-rw-r--r--lib/cpus/aarch64/cortex_a65.S81
-rw-r--r--lib/cpus/aarch64/cortex_a65ae.S81
-rw-r--r--lib/cpus/aarch64/cortex_a710.S668
-rw-r--r--lib/cpus/aarch64/cortex_a715.S113
-rw-r--r--lib/cpus/aarch64/cortex_a72.S374
-rw-r--r--lib/cpus/aarch64/cortex_a73.S305
-rw-r--r--lib/cpus/aarch64/cortex_a75.S261
-rw-r--r--lib/cpus/aarch64/cortex_a75_pubsub.c28
-rw-r--r--lib/cpus/aarch64/cortex_a76.S846
-rw-r--r--lib/cpus/aarch64/cortex_a76ae.S113
-rw-r--r--lib/cpus/aarch64/cortex_a77.S417
-rw-r--r--lib/cpus/aarch64/cortex_a78.S492
-rw-r--r--lib/cpus/aarch64/cortex_a78_ae.S312
-rw-r--r--lib/cpus/aarch64/cortex_a78c.S268
-rw-r--r--lib/cpus/aarch64/cortex_hayes.S77
-rw-r--r--lib/cpus/aarch64/cortex_hunter.S113
-rw-r--r--lib/cpus/aarch64/cortex_hunter_elp_arm.S113
-rw-r--r--lib/cpus/aarch64/cortex_x1.S217
-rw-r--r--lib/cpus/aarch64/cortex_x2.S432
-rw-r--r--lib/cpus/aarch64/cortex_x3.S149
-rw-r--r--lib/cpus/aarch64/cpu_helpers.S456
-rw-r--r--lib/cpus/aarch64/cpuamu.c70
-rw-r--r--lib/cpus/aarch64/cpuamu_helpers.S99
-rw-r--r--lib/cpus/aarch64/denver.S386
-rw-r--r--lib/cpus/aarch64/dsu_helpers.S195
-rw-r--r--lib/cpus/aarch64/generic.S89
-rw-r--r--lib/cpus/aarch64/neoverse_e1.S81
-rw-r--r--lib/cpus/aarch64/neoverse_n1.S745
-rw-r--r--lib/cpus/aarch64/neoverse_n1_pubsub.c28
-rw-r--r--lib/cpus/aarch64/neoverse_n2.S639
-rw-r--r--lib/cpus/aarch64/neoverse_n_common.S26
-rw-r--r--lib/cpus/aarch64/neoverse_poseidon.S113
-rw-r--r--lib/cpus/aarch64/neoverse_v1.S628
-rw-r--r--lib/cpus/aarch64/neoverse_v2.S112
-rw-r--r--lib/cpus/aarch64/qemu_max.S81
-rw-r--r--lib/cpus/aarch64/rainier.S175
-rw-r--r--lib/cpus/aarch64/wa_cve_2017_5715_bpiall.S368
-rw-r--r--lib/cpus/aarch64/wa_cve_2017_5715_mmu.S152
-rw-r--r--lib/cpus/aarch64/wa_cve_2022_23960_bhb.S30
-rw-r--r--lib/cpus/aarch64/wa_cve_2022_23960_bhb_vector.S108
-rw-r--r--lib/cpus/cpu-ops.mk1358
-rw-r--r--lib/cpus/errata_report.c101
-rw-r--r--lib/debugfs/blobs.h12
-rw-r--r--lib/debugfs/debugfs.mk13
-rw-r--r--lib/debugfs/debugfs_smc.c209
-rw-r--r--lib/debugfs/dev.c853
-rw-r--r--lib/debugfs/dev.h120
-rw-r--r--lib/debugfs/devc.c20
-rw-r--r--lib/debugfs/devfip.c321
-rw-r--r--lib/debugfs/devroot.c97
-rw-r--r--lib/el3_runtime/aarch32/context_mgmt.c343
-rw-r--r--lib/el3_runtime/aarch32/cpu_data.S42
-rw-r--r--lib/el3_runtime/aarch64/context.S1136
-rw-r--r--lib/el3_runtime/aarch64/context_mgmt.c1098
-rw-r--r--lib/el3_runtime/aarch64/cpu_data.S48
-rw-r--r--lib/el3_runtime/cpu_data_array.c13
-rw-r--r--lib/extensions/amu/aarch32/amu.c421
-rw-r--r--lib/extensions/amu/aarch32/amu_helpers.S271
-rw-r--r--lib/extensions/amu/aarch64/amu.c655
-rw-r--r--lib/extensions/amu/aarch64/amu_helpers.S389
-rw-r--r--lib/extensions/amu/amu.mk24
-rw-r--r--lib/extensions/amu/amu_private.h38
-rw-r--r--lib/extensions/brbe/brbe.c27
-rw-r--r--lib/extensions/mpam/mpam.c38
-rw-r--r--lib/extensions/mtpmu/aarch32/mtpmu.S105
-rw-r--r--lib/extensions/mtpmu/aarch64/mtpmu.S96
-rw-r--r--lib/extensions/pauth/pauth_helpers.S141
-rw-r--r--lib/extensions/ras/ras_common.c184
-rw-r--r--lib/extensions/ras/std_err_record.c79
-rw-r--r--lib/extensions/sme/sme.c109
-rw-r--r--lib/extensions/spe/spe.c98
-rw-r--r--lib/extensions/sve/sve.c70
-rw-r--r--lib/extensions/sys_reg_trace/aarch32/sys_reg_trace.c36
-rw-r--r--lib/extensions/sys_reg_trace/aarch64/sys_reg_trace.c37
-rw-r--r--lib/extensions/trbe/trbe.c55
-rw-r--r--lib/extensions/trf/aarch32/trf.c35
-rw-r--r--lib/extensions/trf/aarch64/trf.c36
-rw-r--r--lib/fconf/fconf.c78
-rw-r--r--lib/fconf/fconf.mk19
-rw-r--r--lib/fconf/fconf_amu_getter.c142
-rw-r--r--lib/fconf/fconf_cot_getter.c497
-rw-r--r--lib/fconf/fconf_dyn_cfg_getter.c155
-rw-r--r--lib/fconf/fconf_mpmm_getter.c80
-rw-r--r--lib/fconf/fconf_tbbr_getter.c84
-rw-r--r--lib/gpt_rme/gpt_rme.c1260
-rw-r--r--lib/gpt_rme/gpt_rme.mk8
-rw-r--r--lib/gpt_rme/gpt_rme_private.h261
-rw-r--r--lib/libc/aarch32/memset.S74
-rw-r--r--lib/libc/aarch64/memset.S64
-rw-r--r--lib/libc/aarch64/setjmp.S61
-rw-r--r--lib/libc/abort.c15
-rw-r--r--lib/libc/assert.c35
-rw-r--r--lib/libc/exit.c26
-rw-r--r--lib/libc/libc.mk41
-rw-r--r--lib/libc/libc_asm.mk44
-rw-r--r--lib/libc/memchr.c21
-rw-r--r--lib/libc/memcmp.c25
-rw-r--r--lib/libc/memcpy.c19
-rw-r--r--lib/libc/memmove.c31
-rw-r--r--lib/libc/memrchr.c24
-rw-r--r--lib/libc/memset.c51
-rw-r--r--lib/libc/printf.c206
-rw-r--r--lib/libc/putchar.c14
-rw-r--r--lib/libc/puts.c24
-rw-r--r--lib/libc/snprintf.c270
-rw-r--r--lib/libc/strchr.c53
-rw-r--r--lib/libc/strcmp.c52
-rw-r--r--lib/libc/strlcat.c56
-rw-r--r--lib/libc/strlcpy.c52
-rw-r--r--lib/libc/strlen.c17
-rw-r--r--lib/libc/strncmp.c53
-rw-r--r--lib/libc/strnlen.c46
-rw-r--r--lib/libc/strrchr.c49
-rw-r--r--lib/libc/strtok.c83
-rw-r--r--lib/libc/strtol.c133
-rw-r--r--lib/libc/strtoll.c134
-rw-r--r--lib/libc/strtoul.c112
-rw-r--r--lib/libc/strtoull.c112
-rw-r--r--lib/libfdt/fdt.c335
-rw-r--r--lib/libfdt/fdt_addresses.c101
-rw-r--r--lib/libfdt/fdt_empty_tree.c38
-rw-r--r--lib/libfdt/fdt_overlay.c867
-rw-r--r--lib/libfdt/fdt_ro.c859
-rw-r--r--lib/libfdt/fdt_rw.c500
-rw-r--r--lib/libfdt/fdt_strerror.c60
-rw-r--r--lib/libfdt/fdt_sw.c384
-rw-r--r--lib/libfdt/fdt_wip.c94
-rw-r--r--lib/libfdt/libfdt.mk19
-rw-r--r--lib/libfdt/libfdt_internal.h192
-rw-r--r--lib/locks/bakery/bakery_lock_coherent.c168
-rw-r--r--lib/locks/bakery/bakery_lock_normal.c250
-rw-r--r--lib/locks/exclusive/aarch32/spinlock.S43
-rw-r--r--lib/locks/exclusive/aarch64/spinlock.S75
-rw-r--r--lib/mpmm/mpmm.c86
-rw-r--r--lib/mpmm/mpmm.mk29
-rw-r--r--lib/optee/optee_utils.c247
-rw-r--r--lib/pmf/pmf_main.c256
-rw-r--r--lib/pmf/pmf_smc.c63
-rw-r--r--lib/psa/delegated_attestation.c230
-rw-r--r--lib/psa/measured_boot.c134
-rw-r--r--lib/psa/measured_boot_private.h24
-rw-r--r--lib/psci/aarch32/psci_helpers.S148
-rw-r--r--lib/psci/aarch64/psci_helpers.S130
-rw-r--r--lib/psci/psci_common.c1052
-rw-r--r--lib/psci/psci_lib.mk35
-rw-r--r--lib/psci/psci_main.c545
-rw-r--r--lib/psci/psci_mem_protect.c41
-rw-r--r--lib/psci/psci_off.c181
-rw-r--r--lib/psci/psci_on.c233
-rw-r--r--lib/psci/psci_private.h347
-rw-r--r--lib/psci/psci_setup.c315
-rw-r--r--lib/psci/psci_stat.c250
-rw-r--r--lib/psci/psci_suspend.c335
-rw-r--r--lib/psci/psci_system_off.c85
-rw-r--r--lib/romlib/Makefile98
-rwxr-xr-xlib/romlib/gen_combined_bl1_romlib.sh53
-rw-r--r--lib/romlib/init.s36
-rw-r--r--lib/romlib/jmptbl.i44
-rw-r--r--lib/romlib/romlib.ld.S44
-rwxr-xr-xlib/romlib/romlib_generator.py277
-rw-r--r--lib/romlib/templates/jmptbl_entry_function.S6
-rw-r--r--lib/romlib/templates/jmptbl_entry_function_bti.S7
-rw-r--r--lib/romlib/templates/jmptbl_entry_reserved.S6
-rw-r--r--lib/romlib/templates/jmptbl_entry_reserved_bti.S7
-rw-r--r--lib/romlib/templates/jmptbl_glob_var.S9
-rw-r--r--lib/romlib/templates/jmptbl_header.S8
-rw-r--r--lib/romlib/templates/wrapper.S12
-rw-r--r--lib/romlib/templates/wrapper_bti.S13
-rw-r--r--lib/semihosting/aarch32/semihosting_call.S14
-rw-r--r--lib/semihosting/aarch64/semihosting_call.S14
-rw-r--r--lib/semihosting/semihosting.c235
-rw-r--r--lib/stack_protector/aarch32/asm_stack_protector.S34
-rw-r--r--lib/stack_protector/aarch64/asm_stack_protector.S34
-rw-r--r--lib/stack_protector/stack_protector.c32
-rw-r--r--lib/stack_protector/stack_protector.mk28
-rw-r--r--lib/utils/mem_region.c139
-rw-r--r--lib/xlat_mpu/aarch64/enable_mpu.S53
-rw-r--r--lib/xlat_mpu/aarch64/xlat_mpu_arch.c69
-rw-r--r--lib/xlat_mpu/ro_xlat_mpu.mk14
-rw-r--r--lib/xlat_mpu/xlat_mpu.mk19
-rw-r--r--lib/xlat_mpu/xlat_mpu_context.c65
-rw-r--r--lib/xlat_mpu/xlat_mpu_core.c408
-rw-r--r--lib/xlat_mpu/xlat_mpu_private.h103
-rw-r--r--lib/xlat_mpu/xlat_mpu_utils.c83
-rw-r--r--lib/xlat_tables/aarch32/nonlpae_tables.c566
-rw-r--r--lib/xlat_tables/aarch32/xlat_tables.c141
-rw-r--r--lib/xlat_tables/aarch64/xlat_tables.c227
-rw-r--r--lib/xlat_tables/xlat_tables_common.c417
-rw-r--r--lib/xlat_tables/xlat_tables_private.h41
-rw-r--r--lib/xlat_tables_v2/aarch32/enable_mmu.S120
-rw-r--r--lib/xlat_tables_v2/aarch32/xlat_tables_arch.c260
-rw-r--r--lib/xlat_tables_v2/aarch64/enable_mmu.S97
-rw-r--r--lib/xlat_tables_v2/aarch64/xlat_tables_arch.c324
-rw-r--r--lib/xlat_tables_v2/ro_xlat_tables.mk41
-rw-r--r--lib/xlat_tables_v2/xlat_tables.mk19
-rw-r--r--lib/xlat_tables_v2/xlat_tables_context.c270
-rw-r--r--lib/xlat_tables_v2/xlat_tables_core.c1244
-rw-r--r--lib/xlat_tables_v2/xlat_tables_private.h110
-rw-r--r--lib/xlat_tables_v2/xlat_tables_utils.c592
-rw-r--r--lib/zlib/adler32.c186
-rw-r--r--lib/zlib/crc32.c1125
-rw-r--r--lib/zlib/crc32.h9446
-rw-r--r--lib/zlib/inffast.c323
-rw-r--r--lib/zlib/inffast.h11
-rw-r--r--lib/zlib/inffixed.h94
-rw-r--r--lib/zlib/inflate.c1595
-rw-r--r--lib/zlib/inflate.h126
-rw-r--r--lib/zlib/inftrees.c304
-rw-r--r--lib/zlib/inftrees.h62
-rw-r--r--lib/zlib/tf_gunzip.c115
-rw-r--r--lib/zlib/zconf.h547
-rw-r--r--lib/zlib/zlib.h1935
-rw-r--r--lib/zlib/zlib.mk25
-rw-r--r--lib/zlib/zutil.c327
-rw-r--r--lib/zlib/zutil.h275
-rw-r--r--license.rst1
-rw-r--r--licenses/LICENSE.MIT21
-rw-r--r--make_helpers/arch_features.mk36
-rw-r--r--make_helpers/armv7-a-cpus.mk58
-rw-r--r--make_helpers/build_env.mk72
-rw-r--r--make_helpers/build_macros.mk633
-rw-r--r--make_helpers/cygwin.mk19
-rw-r--r--make_helpers/defaults.mk486
-rw-r--r--make_helpers/msys.mk20
-rw-r--r--make_helpers/plat_helpers.mk38
-rw-r--r--make_helpers/tbbr/tbbr_tools.mk140
-rw-r--r--make_helpers/unix.mk60
-rw-r--r--make_helpers/windows.mk91
-rw-r--r--package-lock.json7075
-rw-r--r--package.json23
-rw-r--r--plat/allwinner/common/allwinner-common.mk114
-rw-r--r--plat/allwinner/common/arisc_off.S115
-rw-r--r--plat/allwinner/common/include/mentor_i2c_plat.h28
-rw-r--r--plat/allwinner/common/include/plat_macros.S27
-rw-r--r--plat/allwinner/common/include/platform_def.h84
-rw-r--r--plat/allwinner/common/include/sunxi_def.h26
-rw-r--r--plat/allwinner/common/include/sunxi_private.h61
-rw-r--r--plat/allwinner/common/plat_helpers.S49
-rw-r--r--plat/allwinner/common/sunxi_bl31_setup.c204
-rw-r--r--plat/allwinner/common/sunxi_common.c187
-rw-r--r--plat/allwinner/common/sunxi_cpu_ops.c108
-rw-r--r--plat/allwinner/common/sunxi_native_pm.c81
-rw-r--r--plat/allwinner/common/sunxi_pm.c60
-rw-r--r--plat/allwinner/common/sunxi_prepare_dtb.c52
-rw-r--r--plat/allwinner/common/sunxi_scpi_pm.c207
-rw-r--r--plat/allwinner/common/sunxi_security.c40
-rw-r--r--plat/allwinner/common/sunxi_topology.c39
-rw-r--r--plat/allwinner/sun50i_a64/include/core_off_arisc.h39
-rw-r--r--plat/allwinner/sun50i_a64/include/sunxi_ccu.h14
-rw-r--r--plat/allwinner/sun50i_a64/include/sunxi_cpucfg.h39
-rw-r--r--plat/allwinner/sun50i_a64/include/sunxi_mmap.h74
-rw-r--r--plat/allwinner/sun50i_a64/include/sunxi_spc.h16
-rw-r--r--plat/allwinner/sun50i_a64/platform.mk17
-rw-r--r--plat/allwinner/sun50i_a64/sunxi_idle_states.c27
-rw-r--r--plat/allwinner/sun50i_a64/sunxi_power.c259
-rw-r--r--plat/allwinner/sun50i_h6/include/sunxi_ccu.h14
-rw-r--r--plat/allwinner/sun50i_h6/include/sunxi_cpucfg.h35
-rw-r--r--plat/allwinner/sun50i_h6/include/sunxi_mmap.h63
-rw-r--r--plat/allwinner/sun50i_h6/include/sunxi_spc.h16
-rw-r--r--plat/allwinner/sun50i_h6/platform.mk14
-rw-r--r--plat/allwinner/sun50i_h6/sunxi_idle_states.c11
-rw-r--r--plat/allwinner/sun50i_h6/sunxi_power.c119
-rw-r--r--plat/allwinner/sun50i_h616/include/sunxi_ccu.h14
-rw-r--r--plat/allwinner/sun50i_h616/include/sunxi_cpucfg.h35
-rw-r--r--plat/allwinner/sun50i_h616/include/sunxi_mmap.h46
-rw-r--r--plat/allwinner/sun50i_h616/include/sunxi_spc.h16
-rw-r--r--plat/allwinner/sun50i_h616/platform.mk22
-rw-r--r--plat/allwinner/sun50i_h616/sunxi_idle_states.c11
-rw-r--r--plat/allwinner/sun50i_h616/sunxi_power.c121
-rw-r--r--plat/allwinner/sun50i_r329/include/sunxi_ccu.h14
-rw-r--r--plat/allwinner/sun50i_r329/include/sunxi_cpucfg.h31
-rw-r--r--plat/allwinner/sun50i_r329/include/sunxi_mmap.h55
-rw-r--r--plat/allwinner/sun50i_r329/include/sunxi_spc.h17
-rw-r--r--plat/allwinner/sun50i_r329/platform.mk20
-rw-r--r--plat/allwinner/sun50i_r329/sunxi_idle_states.c11
-rw-r--r--plat/allwinner/sun50i_r329/sunxi_power.c27
-rw-r--r--plat/amlogic/axg/axg_bl31_setup.c170
-rw-r--r--plat/amlogic/axg/axg_common.c115
-rw-r--r--plat/amlogic/axg/axg_def.h129
-rw-r--r--plat/amlogic/axg/axg_pm.c166
-rw-r--r--plat/amlogic/axg/include/platform_def.h66
-rw-r--r--plat/amlogic/axg/platform.mk95
-rw-r--r--plat/amlogic/common/aarch64/aml_helpers.S97
-rw-r--r--plat/amlogic/common/aml_console.c33
-rw-r--r--plat/amlogic/common/aml_efuse.c25
-rw-r--r--plat/amlogic/common/aml_mhu.c52
-rw-r--r--plat/amlogic/common/aml_scpi.c234
-rw-r--r--plat/amlogic/common/aml_sip_svc.c99
-rw-r--r--plat/amlogic/common/aml_thermal.c27
-rw-r--r--plat/amlogic/common/aml_topology.c53
-rw-r--r--plat/amlogic/common/include/aml_private.h41
-rw-r--r--plat/amlogic/common/include/plat_macros.S71
-rw-r--r--plat/amlogic/g12a/g12a_bl31_setup.c142
-rw-r--r--plat/amlogic/g12a/g12a_common.c125
-rw-r--r--plat/amlogic/g12a/g12a_def.h135
-rw-r--r--plat/amlogic/g12a/g12a_pm.c215
-rw-r--r--plat/amlogic/g12a/include/platform_def.h63
-rw-r--r--plat/amlogic/g12a/platform.mk91
-rw-r--r--plat/amlogic/gxbb/gxbb_bl31_setup.c144
-rw-r--r--plat/amlogic/gxbb/gxbb_common.c117
-rw-r--r--plat/amlogic/gxbb/gxbb_def.h123
-rw-r--r--plat/amlogic/gxbb/gxbb_pm.c191
-rw-r--r--plat/amlogic/gxbb/include/platform_def.h66
-rw-r--r--plat/amlogic/gxbb/platform.mk75
-rw-r--r--plat/amlogic/gxl/gxl_bl31_setup.c162
-rw-r--r--plat/amlogic/gxl/gxl_common.c117
-rw-r--r--plat/amlogic/gxl/gxl_def.h133
-rw-r--r--plat/amlogic/gxl/gxl_pm.c214
-rw-r--r--plat/amlogic/gxl/include/platform_def.h63
-rw-r--r--plat/amlogic/gxl/platform.mk91
-rw-r--r--plat/arm/board/a5ds/a5ds_bl1_setup.c20
-rw-r--r--plat/arm/board/a5ds/a5ds_bl2_setup.c18
-rw-r--r--plat/arm/board/a5ds/a5ds_common.c56
-rw-r--r--plat/arm/board/a5ds/a5ds_err.c17
-rw-r--r--plat/arm/board/a5ds/a5ds_pm.c75
-rw-r--r--plat/arm/board/a5ds/a5ds_private.h15
-rw-r--r--plat/arm/board/a5ds/a5ds_security.c17
-rw-r--r--plat/arm/board/a5ds/a5ds_topology.c53
-rw-r--r--plat/arm/board/a5ds/aarch32/a5ds_helpers.S126
-rw-r--r--plat/arm/board/a5ds/fdts/a5ds_fw_config.dts27
-rw-r--r--plat/arm/board/a5ds/fdts/a5ds_tb_fw_config.dts16
-rw-r--r--plat/arm/board/a5ds/include/platform_def.h376
-rw-r--r--plat/arm/board/a5ds/platform.mk111
-rw-r--r--plat/arm/board/a5ds/sp_min/a5ds_sp_min_setup.c27
-rw-r--r--plat/arm/board/a5ds/sp_min/sp_min-a5ds.mk22
-rw-r--r--plat/arm/board/arm_fpga/aarch64/fpga_helpers.S167
-rw-r--r--plat/arm/board/arm_fpga/build_axf.ld.S53
-rw-r--r--plat/arm/board/arm_fpga/fpga_bl31_setup.c402
-rw-r--r--plat/arm/board/arm_fpga/fpga_console.c38
-rw-r--r--plat/arm/board/arm_fpga/fpga_def.h39
-rw-r--r--plat/arm/board/arm_fpga/fpga_gicv3.c162
-rw-r--r--plat/arm/board/arm_fpga/fpga_pm.c103
-rw-r--r--plat/arm/board/arm_fpga/fpga_private.h34
-rw-r--r--plat/arm/board/arm_fpga/fpga_topology.c77
-rw-r--r--plat/arm/board/arm_fpga/include/plat_macros.S13
-rw-r--r--plat/arm/board/arm_fpga/include/platform_def.h88
-rw-r--r--plat/arm/board/arm_fpga/kernel_trampoline.S35
-rw-r--r--plat/arm/board/arm_fpga/platform.mk130
-rw-r--r--plat/arm/board/arm_fpga/rom_trampoline.S24
-rw-r--r--plat/arm/board/common/aarch32/board_arm_helpers.S32
-rw-r--r--plat/arm/board/common/aarch64/board_arm_helpers.S34
-rw-r--r--plat/arm/board/common/board_arm_trusted_boot.c263
-rw-r--r--plat/arm/board/common/board_common.mk120
-rw-r--r--plat/arm/board/common/protpk/README14
-rw-r--r--plat/arm/board/common/protpk/arm_dev_protpk.S18
-rw-r--r--plat/arm/board/common/protpk/arm_protprivk_rsa.pem27
-rw-r--r--plat/arm/board/common/rotpk/arm_dev_rotpk.S33
-rw-r--r--plat/arm/board/common/rotpk/arm_rotpk_ecdsa.derbin0 -> 91 bytes
-rw-r--r--plat/arm/board/common/rotpk/arm_rotpk_rsa.derbin0 -> 294 bytes
-rw-r--r--plat/arm/board/common/rotpk/arm_rotprivk_ecdsa.pem5
-rw-r--r--plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem28
-rw-r--r--plat/arm/board/common/swd_rotpk/README14
-rw-r--r--plat/arm/board/common/swd_rotpk/arm_dev_swd_rotpk.S18
-rw-r--r--plat/arm/board/common/swd_rotpk/arm_swd_rotpk_rsa_sha256.bin1
-rw-r--r--plat/arm/board/common/swd_rotpk/arm_swd_rotprivk_rsa.pem27
-rw-r--r--plat/arm/board/corstone1000/common/corstone1000_bl2_mem_params_desc.c85
-rw-r--r--plat/arm/board/corstone1000/common/corstone1000_err.c17
-rw-r--r--plat/arm/board/corstone1000/common/corstone1000_helpers.S67
-rw-r--r--plat/arm/board/corstone1000/common/corstone1000_plat.c126
-rw-r--r--plat/arm/board/corstone1000/common/corstone1000_pm.c37
-rw-r--r--plat/arm/board/corstone1000/common/corstone1000_security.c16
-rw-r--r--plat/arm/board/corstone1000/common/corstone1000_stack_protector.c35
-rw-r--r--plat/arm/board/corstone1000/common/corstone1000_topology.c43
-rw-r--r--plat/arm/board/corstone1000/common/corstone1000_trusted_boot.c53
-rw-r--r--plat/arm/board/corstone1000/common/fdts/corstone1000_spmc_manifest.dts30
-rw-r--r--plat/arm/board/corstone1000/common/include/platform_def.h394
-rw-r--r--plat/arm/board/corstone1000/include/plat_macros.S22
-rw-r--r--plat/arm/board/corstone1000/platform.mk83
-rw-r--r--plat/arm/board/corstone700/common/corstone700_helpers.S100
-rw-r--r--plat/arm/board/corstone700/common/corstone700_plat.c39
-rw-r--r--plat/arm/board/corstone700/common/corstone700_pm.c22
-rw-r--r--plat/arm/board/corstone700/common/corstone700_security.c16
-rw-r--r--plat/arm/board/corstone700/common/corstone700_stack_protector.c35
-rw-r--r--plat/arm/board/corstone700/common/corstone700_topology.c43
-rw-r--r--plat/arm/board/corstone700/common/drivers/mhu/corstone700_mhu.c117
-rw-r--r--plat/arm/board/corstone700/common/drivers/mhu/corstone700_mhu.h37
-rw-r--r--plat/arm/board/corstone700/common/include/platform_def.h282
-rw-r--r--plat/arm/board/corstone700/platform.mk63
-rw-r--r--plat/arm/board/corstone700/sp_min/corstone700_sp_min_setup.c13
-rw-r--r--plat/arm/board/corstone700/sp_min/sp_min-corstone700.mk24
-rw-r--r--plat/arm/board/fvp/aarch32/fvp_helpers.S143
-rw-r--r--plat/arm/board/fvp/aarch64/fvp_helpers.S177
-rw-r--r--plat/arm/board/fvp/aarch64/fvp_ras.c16
-rw-r--r--plat/arm/board/fvp/fconf/fconf_hw_config_getter.c299
-rw-r--r--plat/arm/board/fvp/fconf/fconf_nt_config_getter.c64
-rw-r--r--plat/arm/board/fvp/fdts/event_log.dtsi12
-rw-r--r--plat/arm/board/fvp/fdts/fvp_fw_config.dts55
-rw-r--r--plat/arm/board/fvp/fdts/fvp_nt_fw_config.dts19
-rw-r--r--plat/arm/board/fvp/fdts/fvp_soc_fw_config.dts11
-rw-r--r--plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts89
-rw-r--r--plat/arm/board/fvp/fdts/fvp_spmc_optee_sp_manifest.dts64
-rw-r--r--plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts127
-rw-r--r--plat/arm/board/fvp/fdts/fvp_tsp_fw_config.dts13
-rw-r--r--plat/arm/board/fvp/fdts/fvp_tsp_sp_manifest.dts34
-rw-r--r--plat/arm/board/fvp/fdts/optee_sp_manifest.dts44
-rw-r--r--plat/arm/board/fvp/fvp_bl1_measured_boot.c75
-rw-r--r--plat/arm/board/fvp/fvp_bl1_setup.c89
-rw-r--r--plat/arm/board/fvp/fvp_bl2_el3_setup.c30
-rw-r--r--plat/arm/board/fvp/fvp_bl2_measured_boot.c234
-rw-r--r--plat/arm/board/fvp/fvp_bl2_setup.c105
-rw-r--r--plat/arm/board/fvp/fvp_bl2u_setup.c22
-rw-r--r--plat/arm/board/fvp/fvp_bl31_setup.c156
-rw-r--r--plat/arm/board/fvp/fvp_common.c544
-rw-r--r--plat/arm/board/fvp/fvp_common_measured_boot.c55
-rw-r--r--plat/arm/board/fvp/fvp_console.c54
-rw-r--r--plat/arm/board/fvp/fvp_def.h181
-rw-r--r--plat/arm/board/fvp/fvp_drtm_addr.c36
-rw-r--r--plat/arm/board/fvp/fvp_drtm_dma_prot.c76
-rw-r--r--plat/arm/board/fvp/fvp_drtm_err.c22
-rw-r--r--plat/arm/board/fvp/fvp_drtm_measurement.c29
-rw-r--r--plat/arm/board/fvp/fvp_drtm_stub.c35
-rw-r--r--plat/arm/board/fvp/fvp_el3_spmc.c47
-rw-r--r--plat/arm/board/fvp/fvp_el3_spmc_logical_sp.c61
-rw-r--r--plat/arm/board/fvp/fvp_err.c43
-rw-r--r--plat/arm/board/fvp/fvp_gicv3.c174
-rw-r--r--plat/arm/board/fvp/fvp_io_storage.c174
-rw-r--r--plat/arm/board/fvp/fvp_plat_attest_token.c111
-rw-r--r--plat/arm/board/fvp/fvp_pm.c467
-rw-r--r--plat/arm/board/fvp/fvp_private.h24
-rw-r--r--plat/arm/board/fvp/fvp_realm_attest_key.c36
-rw-r--r--plat/arm/board/fvp/fvp_security.c42
-rw-r--r--plat/arm/board/fvp/fvp_stack_protector.c24
-rw-r--r--plat/arm/board/fvp/fvp_topology.c123
-rw-r--r--plat/arm/board/fvp/fvp_trusted_boot.c71
-rw-r--r--plat/arm/board/fvp/include/fconf_hw_config_getter.h48
-rw-r--r--plat/arm/board/fvp/include/fconf_nt_config_getter.h27
-rw-r--r--plat/arm/board/fvp/include/fvp_critical_data.h23
-rw-r--r--plat/arm/board/fvp/include/plat.ld.S15
-rw-r--r--plat/arm/board/fvp/include/plat_macros.S42
-rw-r--r--plat/arm/board/fvp/include/platform_def.h416
-rw-r--r--plat/arm/board/fvp/jmptbl.i63
-rw-r--r--plat/arm/board/fvp/platform.mk464
-rw-r--r--plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c121
-rw-r--r--plat/arm/board/fvp/sp_min/sp_min-fvp.mk39
-rw-r--r--plat/arm/board/fvp/trp/trp-fvp.mk12
-rw-r--r--plat/arm/board/fvp/tsp/fvp_tsp_setup.c17
-rw-r--r--plat/arm/board/fvp/tsp/tsp-fvp.mk14
-rw-r--r--plat/arm/board/fvp_r/fvp_r_bl1_arch_setup.c35
-rw-r--r--plat/arm/board/fvp_r/fvp_r_bl1_entrypoint.S93
-rw-r--r--plat/arm/board/fvp_r/fvp_r_bl1_exceptions.S120
-rw-r--r--plat/arm/board/fvp_r/fvp_r_bl1_main.c268
-rw-r--r--plat/arm/board/fvp_r/fvp_r_bl1_setup.c248
-rw-r--r--plat/arm/board/fvp_r/fvp_r_common.c289
-rw-r--r--plat/arm/board/fvp_r/fvp_r_context_mgmt.c53
-rw-r--r--plat/arm/board/fvp_r/fvp_r_debug.S47
-rw-r--r--plat/arm/board/fvp_r/fvp_r_def.h103
-rw-r--r--plat/arm/board/fvp_r/fvp_r_err.c48
-rw-r--r--plat/arm/board/fvp_r/fvp_r_helpers.S128
-rw-r--r--plat/arm/board/fvp_r/fvp_r_io_storage.c105
-rw-r--r--plat/arm/board/fvp_r/fvp_r_misc_helpers.S32
-rw-r--r--plat/arm/board/fvp_r/fvp_r_private.h23
-rw-r--r--plat/arm/board/fvp_r/fvp_r_stack_protector.c24
-rw-r--r--plat/arm/board/fvp_r/fvp_r_trusted_boot.c73
-rw-r--r--plat/arm/board/fvp_r/include/fvp_r_arch_helpers.h28
-rw-r--r--plat/arm/board/fvp_r/include/platform_def.h268
-rw-r--r--plat/arm/board/fvp_r/platform.mk99
-rw-r--r--plat/arm/board/fvp_ve/aarch32/fvp_ve_helpers.S62
-rw-r--r--plat/arm/board/fvp_ve/fdts/fvp_ve_fw_config.dts27
-rw-r--r--plat/arm/board/fvp_ve/fdts/fvp_ve_tb_fw_config.dts16
-rw-r--r--plat/arm/board/fvp_ve/fvp_ve_bl1_setup.c33
-rw-r--r--plat/arm/board/fvp_ve/fvp_ve_bl2_setup.c41
-rw-r--r--plat/arm/board/fvp_ve/fvp_ve_common.c63
-rw-r--r--plat/arm/board/fvp_ve/fvp_ve_def.h84
-rw-r--r--plat/arm/board/fvp_ve/fvp_ve_err.c17
-rw-r--r--plat/arm/board/fvp_ve/fvp_ve_pm.c25
-rw-r--r--plat/arm/board/fvp_ve/fvp_ve_private.h18
-rw-r--r--plat/arm/board/fvp_ve/fvp_ve_security.c22
-rw-r--r--plat/arm/board/fvp_ve/fvp_ve_topology.c37
-rw-r--r--plat/arm/board/fvp_ve/include/platform_def.h361
-rw-r--r--plat/arm/board/fvp_ve/platform.mk139
-rw-r--r--plat/arm/board/fvp_ve/sp_min/fvp_ve_sp_min_setup.c15
-rw-r--r--plat/arm/board/fvp_ve/sp_min/sp_min-fvp_ve.mk22
-rw-r--r--plat/arm/board/juno/aarch32/juno_helpers.S176
-rw-r--r--plat/arm/board/juno/aarch64/juno_helpers.S275
-rw-r--r--plat/arm/board/juno/fdts/juno_fw_config.dts27
-rw-r--r--plat/arm/board/juno/fdts/juno_tb_fw_config.dts26
-rw-r--r--plat/arm/board/juno/include/plat_macros.S24
-rw-r--r--plat/arm/board/juno/include/platform_def.h313
-rw-r--r--plat/arm/board/juno/jmptbl.i62
-rw-r--r--plat/arm/board/juno/juno_bl1_setup.c122
-rw-r--r--plat/arm/board/juno/juno_bl2_setup.c73
-rw-r--r--plat/arm/board/juno/juno_bl31_setup.c60
-rw-r--r--plat/arm/board/juno/juno_common.c134
-rw-r--r--plat/arm/board/juno/juno_def.h99
-rw-r--r--plat/arm/board/juno/juno_err.c27
-rw-r--r--plat/arm/board/juno/juno_pm.c17
-rw-r--r--plat/arm/board/juno/juno_security.c166
-rw-r--r--plat/arm/board/juno/juno_stack_protector.c27
-rw-r--r--plat/arm/board/juno/juno_topology.c78
-rw-r--r--plat/arm/board/juno/juno_trng.c108
-rw-r--r--plat/arm/board/juno/juno_trusted_boot.c126
-rw-r--r--plat/arm/board/juno/juno_tzmp1_def.h83
-rw-r--r--plat/arm/board/juno/platform.mk201
-rw-r--r--plat/arm/board/juno/sp_min/sp_min-juno.mk22
-rw-r--r--plat/arm/board/juno/tsp/tsp-juno.mk12
-rw-r--r--plat/arm/board/morello/aarch64/morello_helper.S55
-rw-r--r--plat/arm/board/morello/fdts/morello_fw_config.dts26
-rw-r--r--plat/arm/board/morello/fdts/morello_nt_fw_config.dts26
-rw-r--r--plat/arm/board/morello/fdts/morello_tb_fw_config.dts27
-rw-r--r--plat/arm/board/morello/include/plat_macros.S25
-rw-r--r--plat/arm/board/morello/include/platform_def.h194
-rw-r--r--plat/arm/board/morello/morello_bl1_setup.c19
-rw-r--r--plat/arm/board/morello/morello_bl2_setup.c226
-rw-r--r--plat/arm/board/morello/morello_bl31_setup.c35
-rw-r--r--plat/arm/board/morello/morello_def.h92
-rw-r--r--plat/arm/board/morello/morello_err.c17
-rw-r--r--plat/arm/board/morello/morello_image_load.c185
-rw-r--r--plat/arm/board/morello/morello_interconnect.c33
-rw-r--r--plat/arm/board/morello/morello_plat.c70
-rw-r--r--plat/arm/board/morello/morello_security.c12
-rw-r--r--plat/arm/board/morello/morello_topology.c60
-rw-r--r--plat/arm/board/morello/morello_trusted_boot.c54
-rw-r--r--plat/arm/board/morello/platform.mk110
-rw-r--r--plat/arm/board/n1sdp/aarch64/n1sdp_helper.S78
-rw-r--r--plat/arm/board/n1sdp/fdts/n1sdp_fw_config.dts29
-rw-r--r--plat/arm/board/n1sdp/fdts/n1sdp_nt_fw_config.dts23
-rw-r--r--plat/arm/board/n1sdp/fdts/n1sdp_optee_spmc_manifest.dts30
-rw-r--r--plat/arm/board/n1sdp/fdts/n1sdp_tb_fw_config.dts27
-rw-r--r--plat/arm/board/n1sdp/include/plat_macros.S24
-rw-r--r--plat/arm/board/n1sdp/include/platform_def.h251
-rw-r--r--plat/arm/board/n1sdp/n1sdp_bl1_setup.c19
-rw-r--r--plat/arm/board/n1sdp/n1sdp_bl2_setup.c89
-rw-r--r--plat/arm/board/n1sdp/n1sdp_bl31_setup.c161
-rw-r--r--plat/arm/board/n1sdp/n1sdp_def.h52
-rw-r--r--plat/arm/board/n1sdp/n1sdp_err.c17
-rw-r--r--plat/arm/board/n1sdp/n1sdp_image_load.c143
-rw-r--r--plat/arm/board/n1sdp/n1sdp_interconnect.c33
-rw-r--r--plat/arm/board/n1sdp/n1sdp_plat.c73
-rw-r--r--plat/arm/board/n1sdp/n1sdp_security.c12
-rw-r--r--plat/arm/board/n1sdp/n1sdp_topology.c59
-rw-r--r--plat/arm/board/n1sdp/n1sdp_trusted_boot.c54
-rw-r--r--plat/arm/board/n1sdp/platform.mk111
-rw-r--r--plat/arm/board/rde1edge/fdts/rde1edge_fw_config.dts27
-rw-r--r--plat/arm/board/rde1edge/fdts/rde1edge_nt_fw_config.dts23
-rw-r--r--plat/arm/board/rde1edge/fdts/rde1edge_tb_fw_config.dts28
-rw-r--r--plat/arm/board/rde1edge/include/platform_def.h48
-rw-r--r--plat/arm/board/rde1edge/platform.mk66
-rw-r--r--plat/arm/board/rde1edge/rde1edge_err.c17
-rw-r--r--plat/arm/board/rde1edge/rde1edge_plat.c29
-rw-r--r--plat/arm/board/rde1edge/rde1edge_security.c36
-rw-r--r--plat/arm/board/rde1edge/rde1edge_topology.c36
-rw-r--r--plat/arm/board/rde1edge/rde1edge_trusted_boot.c26
-rw-r--r--plat/arm/board/rdn1edge/fdts/rdn1edge_fw_config.dts27
-rw-r--r--plat/arm/board/rdn1edge/fdts/rdn1edge_nt_fw_config.dts22
-rw-r--r--plat/arm/board/rdn1edge/fdts/rdn1edge_tb_fw_config.dts27
-rw-r--r--plat/arm/board/rdn1edge/include/platform_def.h54
-rw-r--r--plat/arm/board/rdn1edge/platform.mk75
-rw-r--r--plat/arm/board/rdn1edge/rdn1edge_err.c17
-rw-r--r--plat/arm/board/rdn1edge/rdn1edge_plat.c97
-rw-r--r--plat/arm/board/rdn1edge/rdn1edge_security.c36
-rw-r--r--plat/arm/board/rdn1edge/rdn1edge_topology.c54
-rw-r--r--plat/arm/board/rdn1edge/rdn1edge_trusted_boot.c26
-rw-r--r--plat/arm/board/rdn2/fdts/rdn2_fw_config.dts27
-rw-r--r--plat/arm/board/rdn2/fdts/rdn2_nt_fw_config.dts43
-rw-r--r--plat/arm/board/rdn2/fdts/rdn2_tb_fw_config.dts28
-rw-r--r--plat/arm/board/rdn2/include/platform_def.h103
-rw-r--r--plat/arm/board/rdn2/platform.mk90
-rw-r--r--plat/arm/board/rdn2/rdn2_err.c17
-rw-r--r--plat/arm/board/rdn2/rdn2_plat.c138
-rw-r--r--plat/arm/board/rdn2/rdn2_security.c63
-rw-r--r--plat/arm/board/rdn2/rdn2_topology.c97
-rw-r--r--plat/arm/board/rdn2/rdn2_trusted_boot.c26
-rw-r--r--plat/arm/board/rdv1/fdts/rdv1_fw_config.dts27
-rw-r--r--plat/arm/board/rdv1/fdts/rdv1_nt_fw_config.dts22
-rw-r--r--plat/arm/board/rdv1/fdts/rdv1_tb_fw_config.dts28
-rw-r--r--plat/arm/board/rdv1/include/platform_def.h68
-rw-r--r--plat/arm/board/rdv1/platform.mk65
-rw-r--r--plat/arm/board/rdv1/rdv1_err.c17
-rw-r--r--plat/arm/board/rdv1/rdv1_plat.c30
-rw-r--r--plat/arm/board/rdv1/rdv1_security.c22
-rw-r--r--plat/arm/board/rdv1/rdv1_topology.c62
-rw-r--r--plat/arm/board/rdv1/rdv1_trusted_boot.c26
-rw-r--r--plat/arm/board/rdv1mc/fdts/rdv1mc_fw_config.dts27
-rw-r--r--plat/arm/board/rdv1mc/fdts/rdv1mc_nt_fw_config.dts22
-rw-r--r--plat/arm/board/rdv1mc/fdts/rdv1mc_tb_fw_config.dts28
-rw-r--r--plat/arm/board/rdv1mc/include/platform_def.h63
-rw-r--r--plat/arm/board/rdv1mc/platform.mk76
-rw-r--r--plat/arm/board/rdv1mc/rdv1mc_err.c17
-rw-r--r--plat/arm/board/rdv1mc/rdv1mc_plat.c131
-rw-r--r--plat/arm/board/rdv1mc/rdv1mc_security.c64
-rw-r--r--plat/arm/board/rdv1mc/rdv1mc_topology.c78
-rw-r--r--plat/arm/board/rdv1mc/rdv1mc_trusted_boot.c26
-rw-r--r--plat/arm/board/sgi575/fdts/sgi575_fw_config.dts27
-rw-r--r--plat/arm/board/sgi575/fdts/sgi575_nt_fw_config.dts22
-rw-r--r--plat/arm/board/sgi575/fdts/sgi575_tb_fw_config.dts28
-rw-r--r--plat/arm/board/sgi575/include/platform_def.h49
-rw-r--r--plat/arm/board/sgi575/platform.mk67
-rw-r--r--plat/arm/board/sgi575/sgi575_err.c17
-rw-r--r--plat/arm/board/sgi575/sgi575_plat.c30
-rw-r--r--plat/arm/board/sgi575/sgi575_security.c36
-rw-r--r--plat/arm/board/sgi575/sgi575_topology.c32
-rw-r--r--plat/arm/board/sgi575/sgi575_trusted_boot.c26
-rw-r--r--plat/arm/board/tc/fdts/tc_fw_config.dts33
-rw-r--r--plat/arm/board/tc/fdts/tc_spmc_manifest.dts125
-rw-r--r--plat/arm/board/tc/fdts/tc_spmc_optee_sp_manifest.dts124
-rw-r--r--plat/arm/board/tc/fdts/tc_tb_fw_config.dts76
-rw-r--r--plat/arm/board/tc/include/plat_macros.S24
-rw-r--r--plat/arm/board/tc/include/platform_def.h294
-rw-r--r--plat/arm/board/tc/include/tc_helpers.S61
-rw-r--r--plat/arm/board/tc/include/tc_plat.h12
-rw-r--r--plat/arm/board/tc/platform.mk199
-rw-r--r--plat/arm/board/tc/tc_bl1_measured_boot.c55
-rw-r--r--plat/arm/board/tc/tc_bl2_measured_boot.c54
-rw-r--r--plat/arm/board/tc/tc_bl2_setup.c47
-rw-r--r--plat/arm/board/tc/tc_bl31_setup.c73
-rw-r--r--plat/arm/board/tc/tc_common_measured_boot.c35
-rw-r--r--plat/arm/board/tc/tc_err.c17
-rw-r--r--plat/arm/board/tc/tc_interconnect.c35
-rw-r--r--plat/arm/board/tc/tc_plat.c156
-rw-r--r--plat/arm/board/tc/tc_security.c23
-rw-r--r--plat/arm/board/tc/tc_topology.c58
-rw-r--r--plat/arm/board/tc/tc_trusted_boot.c26
-rw-r--r--plat/arm/common/aarch32/arm_bl2_mem_params_desc.c91
-rw-r--r--plat/arm/common/aarch32/arm_helpers.S77
-rw-r--r--plat/arm/common/aarch64/arm_bl2_mem_params_desc.c227
-rw-r--r--plat/arm/common/aarch64/arm_helpers.S136
-rw-r--r--plat/arm/common/aarch64/arm_pauth.c28
-rw-r--r--plat/arm/common/aarch64/arm_sdei.c66
-rw-r--r--plat/arm/common/aarch64/execution_state_switch.c180
-rw-r--r--plat/arm/common/arm_bl1_fwu.c102
-rw-r--r--plat/arm/common/arm_bl1_setup.c258
-rw-r--r--plat/arm/common/arm_bl2_el3_setup.c100
-rw-r--r--plat/arm/common/arm_bl2_setup.c322
-rw-r--r--plat/arm/common/arm_bl2u_setup.c97
-rw-r--r--plat/arm/common/arm_bl31_setup.c435
-rw-r--r--plat/arm/common/arm_cci.c50
-rw-r--r--plat/arm/common/arm_ccn.c57
-rw-r--r--plat/arm/common/arm_common.c243
-rw-r--r--plat/arm/common/arm_common.mk456
-rw-r--r--plat/arm/common/arm_console.c71
-rw-r--r--plat/arm/common/arm_dyn_cfg.c231
-rw-r--r--plat/arm/common/arm_dyn_cfg_helpers.c369
-rw-r--r--plat/arm/common/arm_err.c20
-rw-r--r--plat/arm/common/arm_gicv2.c114
-rw-r--r--plat/arm/common/arm_gicv3.c247
-rw-r--r--plat/arm/common/arm_image_load.c141
-rw-r--r--plat/arm/common/arm_io_storage.c250
-rw-r--r--plat/arm/common/arm_nor_psci_mem_protect.c138
-rw-r--r--plat/arm/common/arm_pm.c210
-rw-r--r--plat/arm/common/arm_sip_svc.c143
-rw-r--r--plat/arm/common/arm_topology.c58
-rw-r--r--plat/arm/common/arm_tzc400.c79
-rw-r--r--plat/arm/common/arm_tzc_dmc500.c79
-rw-r--r--plat/arm/common/fconf/arm_fconf_io.c381
-rw-r--r--plat/arm/common/fconf/arm_fconf_sp.c165
-rw-r--r--plat/arm/common/fconf/fconf_ethosn_getter.c354
-rw-r--r--plat/arm/common/fconf/fconf_nv_cntr_getter.c62
-rw-r--r--plat/arm/common/fconf/fconf_sdei_getter.c103
-rw-r--r--plat/arm/common/fconf/fconf_sec_intr_config.c131
-rw-r--r--plat/arm/common/sp_min/arm_sp_min.mk20
-rw-r--r--plat/arm/common/sp_min/arm_sp_min_setup.c241
-rw-r--r--plat/arm/common/trp/arm_trp.mk12
-rw-r--r--plat/arm/common/trp/arm_trp_setup.c72
-rw-r--r--plat/arm/common/tsp/arm_tsp.mk10
-rw-r--r--plat/arm/common/tsp/arm_tsp_setup.c86
-rw-r--r--plat/arm/css/common/aarch32/css_helpers.S102
-rw-r--r--plat/arm/css/common/aarch64/css_helpers.S120
-rw-r--r--plat/arm/css/common/css_bl1_setup.c22
-rw-r--r--plat/arm/css/common/css_bl2_setup.c86
-rw-r--r--plat/arm/css/common/css_bl2u_setup.c56
-rw-r--r--plat/arm/css/common/css_common.mk97
-rw-r--r--plat/arm/css/common/css_pm.c415
-rw-r--r--plat/arm/css/common/css_topology.c48
-rw-r--r--plat/arm/css/common/sp_min/css_sp_min.mk22
-rw-r--r--plat/arm/css/sgi/aarch64/sgi_helper.S106
-rw-r--r--plat/arm/css/sgi/include/plat_macros.S24
-rw-r--r--plat/arm/css/sgi/include/sgi_base_platform_def.h300
-rw-r--r--plat/arm/css/sgi/include/sgi_dmc620_tzc_regions.h36
-rw-r--r--plat/arm/css/sgi/include/sgi_plat.h13
-rw-r--r--plat/arm/css/sgi/include/sgi_ras.h21
-rw-r--r--plat/arm/css/sgi/include/sgi_sdei.h25
-rw-r--r--plat/arm/css/sgi/include/sgi_soc_css_def.h47
-rw-r--r--plat/arm/css/sgi/include/sgi_soc_css_def_v2.h202
-rw-r--r--plat/arm/css/sgi/include/sgi_soc_platform_def.h33
-rw-r--r--plat/arm/css/sgi/include/sgi_soc_platform_def_v2.h31
-rw-r--r--plat/arm/css/sgi/include/sgi_variant.h49
-rw-r--r--plat/arm/css/sgi/sgi-common.mk86
-rw-r--r--plat/arm/css/sgi/sgi_bl31_setup.c139
-rw-r--r--plat/arm/css/sgi/sgi_image_load.c155
-rw-r--r--plat/arm/css/sgi/sgi_interconnect.c36
-rw-r--r--plat/arm/css/sgi/sgi_plat.c176
-rw-r--r--plat/arm/css/sgi/sgi_plat_v2.c175
-rw-r--r--plat/arm/css/sgi/sgi_ras.c194
-rw-r--r--plat/arm/css/sgi/sgi_topology.c29
-rw-r--r--plat/arm/soc/common/soc_css.mk15
-rw-r--r--plat/arm/soc/common/soc_css_security.c73
-rw-r--r--plat/brcm/board/common/bcm_console.c65
-rw-r--r--plat/brcm/board/common/bcm_elog.c268
-rw-r--r--plat/brcm/board/common/bcm_elog_ddr.c133
-rw-r--r--plat/brcm/board/common/bcm_elog_ddr.h107
-rw-r--r--plat/brcm/board/common/board_arm_trusted_boot.c625
-rw-r--r--plat/brcm/board/common/board_common.c74
-rw-r--r--plat/brcm/board/common/board_common.mk294
-rw-r--r--plat/brcm/board/common/brcm_mbedtls.c12
-rw-r--r--plat/brcm/board/common/chip_id.h37
-rw-r--r--plat/brcm/board/common/cmn_plat_def.h82
-rw-r--r--plat/brcm/board/common/cmn_plat_util.h43
-rw-r--r--plat/brcm/board/common/cmn_sec.c49
-rw-r--r--plat/brcm/board/common/cmn_sec.h19
-rw-r--r--plat/brcm/board/common/err.c37
-rw-r--r--plat/brcm/board/common/plat_setup.c27
-rw-r--r--plat/brcm/board/common/platform_common.c94
-rw-r--r--plat/brcm/board/common/sbl_util.c40
-rw-r--r--plat/brcm/board/common/sbl_util.h19
-rw-r--r--plat/brcm/board/common/timer_sync.c71
-rw-r--r--plat/brcm/board/stingray/aarch64/plat_helpers.S263
-rw-r--r--plat/brcm/board/stingray/bcm958742t-ns3.mk22
-rw-r--r--plat/brcm/board/stingray/bcm958742t.mk19
-rw-r--r--plat/brcm/board/stingray/driver/ddr/soc/include/board_family.h33
-rw-r--r--plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.c302
-rw-r--r--plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.h11
-rw-r--r--plat/brcm/board/stingray/driver/ihost_pll_config.c287
-rw-r--r--plat/brcm/board/stingray/driver/plat_emmc.c109
-rw-r--r--plat/brcm/board/stingray/driver/sr_usb.h135
-rw-r--r--plat/brcm/board/stingray/driver/swreg.c375
-rw-r--r--plat/brcm/board/stingray/driver/usb.c296
-rw-r--r--plat/brcm/board/stingray/driver/usb_phy.c601
-rw-r--r--plat/brcm/board/stingray/include/bl33_info.h38
-rw-r--r--plat/brcm/board/stingray/include/board_info.h38
-rw-r--r--plat/brcm/board/stingray/include/crmu_def.h227
-rw-r--r--plat/brcm/board/stingray/include/ddr_init.h39
-rw-r--r--plat/brcm/board/stingray/include/fsx.h37
-rw-r--r--plat/brcm/board/stingray/include/ihost_pm.h19
-rw-r--r--plat/brcm/board/stingray/include/iommu.h19
-rw-r--r--plat/brcm/board/stingray/include/ncsi.h32
-rw-r--r--plat/brcm/board/stingray/include/paxb.h74
-rw-r--r--plat/brcm/board/stingray/include/paxc.h23
-rw-r--r--plat/brcm/board/stingray/include/plat_macros.S52
-rw-r--r--plat/brcm/board/stingray/include/platform_def.h268
-rw-r--r--plat/brcm/board/stingray/include/platform_sotp.h36
-rw-r--r--plat/brcm/board/stingray/include/platform_usb.h19
-rw-r--r--plat/brcm/board/stingray/include/scp_cmd.h25
-rw-r--r--plat/brcm/board/stingray/include/scp_utils.h34
-rw-r--r--plat/brcm/board/stingray/include/sdio.h247
-rw-r--r--plat/brcm/board/stingray/include/sr_def.h624
-rw-r--r--plat/brcm/board/stingray/include/sr_utils.h42
-rw-r--r--plat/brcm/board/stingray/include/swreg.h36
-rw-r--r--plat/brcm/board/stingray/include/timer_sync.h12
-rw-r--r--plat/brcm/board/stingray/include/usb_phy.h244
-rw-r--r--plat/brcm/board/stingray/platform.mk304
-rw-r--r--plat/brcm/board/stingray/src/bl2_setup.c743
-rw-r--r--plat/brcm/board/stingray/src/bl31_setup.c1071
-rw-r--r--plat/brcm/board/stingray/src/brcm_pm_ops.c408
-rw-r--r--plat/brcm/board/stingray/src/fsx.c477
-rw-r--r--plat/brcm/board/stingray/src/ihost_pm.c355
-rw-r--r--plat/brcm/board/stingray/src/iommu.c536
-rw-r--r--plat/brcm/board/stingray/src/ncsi.c54
-rw-r--r--plat/brcm/board/stingray/src/paxb.c911
-rw-r--r--plat/brcm/board/stingray/src/paxc.c267
-rw-r--r--plat/brcm/board/stingray/src/pm.c131
-rw-r--r--plat/brcm/board/stingray/src/scp_cmd.c60
-rw-r--r--plat/brcm/board/stingray/src/scp_utils.c227
-rw-r--r--plat/brcm/board/stingray/src/sdio.c144
-rw-r--r--plat/brcm/board/stingray/src/sr_paxb_phy.c806
-rw-r--r--plat/brcm/board/stingray/src/topology.c52
-rw-r--r--plat/brcm/board/stingray/src/tz_sec.c153
-rw-r--r--plat/brcm/common/brcm_bl2_mem_params_desc.c106
-rw-r--r--plat/brcm/common/brcm_bl2_setup.c202
-rw-r--r--plat/brcm/common/brcm_bl31_setup.c291
-rw-r--r--plat/brcm/common/brcm_ccn.c36
-rw-r--r--plat/brcm/common/brcm_common.c59
-rw-r--r--plat/brcm/common/brcm_gicv3.c91
-rw-r--r--plat/brcm/common/brcm_image_load.c41
-rw-r--r--plat/brcm/common/brcm_io_storage.c408
-rw-r--r--plat/brcm/common/brcm_mhu.c131
-rw-r--r--plat/brcm/common/brcm_mhu.h19
-rw-r--r--plat/brcm/common/brcm_scpi.c252
-rw-r--r--plat/brcm/common/brcm_scpi.h107
-rw-r--r--plat/common/aarch32/crash_console_helpers.S68
-rw-r--r--plat/common/aarch32/plat_common.c21
-rw-r--r--plat/common/aarch32/plat_sp_min_common.c25
-rw-r--r--plat/common/aarch32/platform_helpers.S89
-rw-r--r--plat/common/aarch32/platform_mp_stack.S47
-rw-r--r--plat/common/aarch32/platform_up_stack.S47
-rw-r--r--plat/common/aarch64/crash_console_helpers.S187
-rw-r--r--plat/common/aarch64/plat_common.c104
-rw-r--r--plat/common/aarch64/plat_ehf.c37
-rw-r--r--plat/common/aarch64/platform_helpers.S122
-rw-r--r--plat/common/aarch64/platform_mp_stack.S61
-rw-r--r--plat/common/aarch64/platform_up_stack.S50
-rw-r--r--plat/common/plat_bl1_common.c117
-rw-r--r--plat/common/plat_bl_common.c137
-rw-r--r--plat/common/plat_gicv2.c336
-rw-r--r--plat/common/plat_gicv3.c370
-rw-r--r--plat/common/plat_log_common.c29
-rw-r--r--plat/common/plat_psci_common.c167
-rw-r--r--plat/common/plat_spmd_manifest.c194
-rw-r--r--plat/common/tbbr/plat_tbbr.c52
-rw-r--r--plat/common/ubsan.c220
-rw-r--r--plat/hisilicon/hikey/aarch64/hikey_common.c128
-rw-r--r--plat/hisilicon/hikey/aarch64/hikey_helpers.S159
-rw-r--r--plat/hisilicon/hikey/hikey_bl1_setup.c165
-rw-r--r--plat/hisilicon/hikey/hikey_bl2_mem_params_desc.c167
-rw-r--r--plat/hisilicon/hikey/hikey_bl2_setup.c329
-rw-r--r--plat/hisilicon/hikey/hikey_bl31_setup.c155
-rw-r--r--plat/hisilicon/hikey/hikey_bl_common.c390
-rw-r--r--plat/hisilicon/hikey/hikey_ddr.c1451
-rw-r--r--plat/hisilicon/hikey/hikey_image_load.c34
-rw-r--r--plat/hisilicon/hikey/hikey_io_storage.c315
-rw-r--r--plat/hisilicon/hikey/hikey_pm.c288
-rw-r--r--plat/hisilicon/hikey/hikey_private.h77
-rw-r--r--plat/hisilicon/hikey/hikey_rotpk.S16
-rw-r--r--plat/hisilicon/hikey/hikey_security.c108
-rw-r--r--plat/hisilicon/hikey/hikey_tbbr.c36
-rw-r--r--plat/hisilicon/hikey/hikey_topology.c66
-rw-r--r--plat/hisilicon/hikey/hisi_dvfs.c781
-rw-r--r--plat/hisilicon/hikey/hisi_ipc.c207
-rw-r--r--plat/hisilicon/hikey/hisi_mcu.c206
-rw-r--r--plat/hisilicon/hikey/hisi_pwrc.c104
-rw-r--r--plat/hisilicon/hikey/hisi_pwrc_sram.S70
-rw-r--r--plat/hisilicon/hikey/hisi_sip_svc.c85
-rw-r--r--plat/hisilicon/hikey/include/hi6220.h77
-rw-r--r--plat/hisilicon/hikey/include/hi6220_regs_acpu.h300
-rw-r--r--plat/hisilicon/hikey/include/hi6220_regs_ao.h334
-rw-r--r--plat/hisilicon/hikey/include/hi6220_regs_peri.h380
-rw-r--r--plat/hisilicon/hikey/include/hi6220_regs_pin.h43
-rw-r--r--plat/hisilicon/hikey/include/hi6220_regs_pmctrl.h101
-rw-r--r--plat/hisilicon/hikey/include/hi6553.h82
-rw-r--r--plat/hisilicon/hikey/include/hikey_def.h106
-rw-r--r--plat/hisilicon/hikey/include/hikey_layout.h122
-rw-r--r--plat/hisilicon/hikey/include/hisi_ipc.h46
-rw-r--r--plat/hisilicon/hikey/include/hisi_mcu.h16
-rw-r--r--plat/hisilicon/hikey/include/hisi_pwrc.h22
-rw-r--r--plat/hisilicon/hikey/include/hisi_sip_svc.h21
-rw-r--r--plat/hisilicon/hikey/include/hisi_sram_map.h327
-rw-r--r--plat/hisilicon/hikey/include/plat_macros.S78
-rw-r--r--plat/hisilicon/hikey/include/platform_def.h85
-rw-r--r--plat/hisilicon/hikey/platform.mk172
-rw-r--r--plat/hisilicon/hikey960/aarch64/hikey960_common.c123
-rw-r--r--plat/hisilicon/hikey960/aarch64/hikey960_helpers.S181
-rw-r--r--plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c206
-rw-r--r--plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c417
-rw-r--r--plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h57
-rw-r--r--plat/hisilicon/hikey960/hikey960_bl1_setup.c265
-rw-r--r--plat/hisilicon/hikey960/hikey960_bl2_mem_params_desc.c183
-rw-r--r--plat/hisilicon/hikey960/hikey960_bl2_setup.c344
-rw-r--r--plat/hisilicon/hikey960/hikey960_bl31_setup.c264
-rw-r--r--plat/hisilicon/hikey960/hikey960_bl_common.c480
-rw-r--r--plat/hisilicon/hikey960/hikey960_boardid.c167
-rw-r--r--plat/hisilicon/hikey960/hikey960_def.h82
-rw-r--r--plat/hisilicon/hikey960/hikey960_el3_spmc_logical_sp.c61
-rw-r--r--plat/hisilicon/hikey960/hikey960_image_load.c55
-rw-r--r--plat/hisilicon/hikey960/hikey960_io_storage.c383
-rw-r--r--plat/hisilicon/hikey960/hikey960_mcu_load.c54
-rw-r--r--plat/hisilicon/hikey960/hikey960_pm.c337
-rw-r--r--plat/hisilicon/hikey960/hikey960_private.h55
-rw-r--r--plat/hisilicon/hikey960/hikey960_rotpk.S16
-rw-r--r--plat/hisilicon/hikey960/hikey960_tbbr.c36
-rw-r--r--plat/hisilicon/hikey960/hikey960_topology.c66
-rw-r--r--plat/hisilicon/hikey960/include/hi3660.h392
-rw-r--r--plat/hisilicon/hikey960/include/hi3660_crg.h179
-rw-r--r--plat/hisilicon/hikey960/include/hi3660_hkadc.h61
-rw-r--r--plat/hisilicon/hikey960/include/hi3660_mem_map.h20
-rw-r--r--plat/hisilicon/hikey960/include/hisi_ipc.h24
-rw-r--r--plat/hisilicon/hikey960/include/plat.ld.S22
-rw-r--r--plat/hisilicon/hikey960/include/plat_macros.S78
-rw-r--r--plat/hisilicon/hikey960/include/platform_def.h150
-rw-r--r--plat/hisilicon/hikey960/platform.mk182
-rw-r--r--plat/hisilicon/poplar/aarch64/platform_common.c79
-rw-r--r--plat/hisilicon/poplar/aarch64/poplar_helpers.S87
-rw-r--r--plat/hisilicon/poplar/bl1_plat_setup.c119
-rw-r--r--plat/hisilicon/poplar/bl2_plat_mem_params_desc.c168
-rw-r--r--plat/hisilicon/poplar/bl2_plat_setup.c219
-rw-r--r--plat/hisilicon/poplar/bl31_plat_setup.c137
-rw-r--r--plat/hisilicon/poplar/include/hi3798cv200.h105
-rw-r--r--plat/hisilicon/poplar/include/plat_macros.S10
-rw-r--r--plat/hisilicon/poplar/include/plat_private.h37
-rw-r--r--plat/hisilicon/poplar/include/platform_def.h171
-rw-r--r--plat/hisilicon/poplar/include/poplar_layout.h132
-rw-r--r--plat/hisilicon/poplar/plat_pm.c173
-rw-r--r--plat/hisilicon/poplar/plat_storage.c254
-rw-r--r--plat/hisilicon/poplar/plat_topology.c33
-rw-r--r--plat/hisilicon/poplar/platform.mk112
-rw-r--r--plat/hisilicon/poplar/poplar_gicv2.c63
-rw-r--r--plat/hisilicon/poplar/poplar_image_load.c34
-rw-r--r--plat/imx/common/aarch32/imx_uart_console.S50
-rw-r--r--plat/imx/common/imx7_clock.c55
-rw-r--r--plat/imx/common/imx8_helpers.S125
-rw-r--r--plat/imx/common/imx8_psci.c62
-rw-r--r--plat/imx/common/imx8_topology.c40
-rw-r--r--plat/imx/common/imx_aips.c57
-rw-r--r--plat/imx/common/imx_caam.c24
-rw-r--r--plat/imx/common/imx_clock.c155
-rw-r--r--plat/imx/common/imx_csu.c19
-rw-r--r--plat/imx/common/imx_ehf.c22
-rw-r--r--plat/imx/common/imx_io_mux.c24
-rw-r--r--plat/imx/common/imx_io_storage.c301
-rw-r--r--plat/imx/common/imx_sdei.c32
-rw-r--r--plat/imx/common/imx_sip_handler.c255
-rw-r--r--plat/imx/common/imx_sip_svc.c85
-rw-r--r--plat/imx/common/imx_snvs.c22
-rw-r--r--plat/imx/common/imx_uart_console.S88
-rw-r--r--plat/imx/common/imx_wdog.c25
-rw-r--r--plat/imx/common/include/imx8_iomux.h25
-rw-r--r--plat/imx/common/include/imx8_lpuart.h61
-rw-r--r--plat/imx/common/include/imx8qm_pads.h293
-rw-r--r--plat/imx/common/include/imx8qx_pads.h198
-rw-r--r--plat/imx/common/include/imx_aips.h22
-rw-r--r--plat/imx/common/include/imx_caam.h70
-rw-r--r--plat/imx/common/include/imx_clock.h1003
-rw-r--r--plat/imx/common/include/imx_csu.h44
-rw-r--r--plat/imx/common/include/imx_hab.h33
-rw-r--r--plat/imx/common/include/imx_io_mux.h652
-rw-r--r--plat/imx/common/include/imx_sip_svc.h94
-rw-r--r--plat/imx/common/include/imx_snvs.h84
-rw-r--r--plat/imx/common/include/imx_uart.h18
-rw-r--r--plat/imx/common/include/imx_wdog.h62
-rw-r--r--plat/imx/common/include/plat_imx8.h35
-rw-r--r--plat/imx/common/include/plat_macros.S34
-rw-r--r--plat/imx/common/include/sci/sci.h21
-rw-r--r--plat/imx/common/include/sci/sci_ipc.h67
-rw-r--r--plat/imx/common/include/sci/sci_rpc.h128
-rw-r--r--plat/imx/common/include/sci/sci_scfw.h36
-rw-r--r--plat/imx/common/include/sci/sci_types.h849
-rw-r--r--plat/imx/common/include/sci/svc/misc/sci_misc_api.h539
-rw-r--r--plat/imx/common/include/sci/svc/pad/sci_pad_api.h572
-rw-r--r--plat/imx/common/include/sci/svc/pm/sci_pm_api.h684
-rw-r--r--plat/imx/common/include/sci/svc/rm/sci_rm_api.h757
-rw-r--r--plat/imx/common/include/sci/svc/timer/sci_timer_api.h358
-rw-r--r--plat/imx/common/lpuart_console.S76
-rw-r--r--plat/imx/common/plat_imx8_gic.c114
-rw-r--r--plat/imx/common/sci/imx8_mu.c73
-rw-r--r--plat/imx/common/sci/imx8_mu.h36
-rw-r--r--plat/imx/common/sci/ipc.c120
-rw-r--r--plat/imx/common/sci/sci_api.mk13
-rw-r--r--plat/imx/common/sci/svc/misc/misc_rpc_clnt.c506
-rw-r--r--plat/imx/common/sci/svc/misc/sci_misc_rpc.h76
-rw-r--r--plat/imx/common/sci/svc/pad/pad_rpc_clnt.c454
-rw-r--r--plat/imx/common/sci/svc/pad/sci_pad_rpc.h66
-rw-r--r--plat/imx/common/sci/svc/pm/pm_rpc_clnt.c459
-rw-r--r--plat/imx/common/sci/svc/pm/sci_pm_rpc.h71
-rw-r--r--plat/imx/common/sci/svc/rm/rm_rpc_clnt.c639
-rw-r--r--plat/imx/common/sci/svc/rm/sci_rm_rpc.h81
-rw-r--r--plat/imx/common/sci/svc/timer/sci_timer_rpc.h69
-rw-r--r--plat/imx/common/sci/svc/timer/timer_rpc_clnt.c396
-rw-r--r--plat/imx/imx7/common/imx7.mk112
-rw-r--r--plat/imx/imx7/common/imx7_bl2_el3_common.c198
-rw-r--r--plat/imx/imx7/common/imx7_bl2_mem_params_desc.c81
-rw-r--r--plat/imx/imx7/common/imx7_helpers.S59
-rw-r--r--plat/imx/imx7/common/imx7_image_load.c24
-rw-r--r--plat/imx/imx7/common/imx7_rotpk.S15
-rw-r--r--plat/imx/imx7/common/imx7_trusted_boot.c36
-rw-r--r--plat/imx/imx7/include/imx7_def.h20
-rw-r--r--plat/imx/imx7/include/imx_hab_arch.h12
-rw-r--r--plat/imx/imx7/include/imx_regs.h108
-rw-r--r--plat/imx/imx7/picopi/include/platform_def.h204
-rw-r--r--plat/imx/imx7/picopi/picopi_bl2_el3_setup.c134
-rw-r--r--plat/imx/imx7/picopi/platform.mk40
-rw-r--r--plat/imx/imx7/warp7/include/platform_def.h218
-rw-r--r--plat/imx/imx7/warp7/platform.mk37
-rw-r--r--plat/imx/imx7/warp7/warp7_bl2_el3_setup.c143
-rw-r--r--plat/imx/imx8m/ddr/clock.c136
-rw-r--r--plat/imx/imx8m/ddr/ddr4_dvfs.c241
-rw-r--r--plat/imx/imx8m/ddr/dram.c263
-rw-r--r--plat/imx/imx8m/ddr/dram_retention.c203
-rw-r--r--plat/imx/imx8m/ddr/lpddr4_dvfs.c292
-rw-r--r--plat/imx/imx8m/gpc_common.c308
-rw-r--r--plat/imx/imx8m/imx8m_caam.c48
-rw-r--r--plat/imx/imx8m/imx8m_csu.c56
-rw-r--r--plat/imx/imx8m/imx8m_dyn_cfg_helpers.c201
-rw-r--r--plat/imx/imx8m/imx8m_image_load.c26
-rw-r--r--plat/imx/imx8m/imx8m_measured_boot.c85
-rw-r--r--plat/imx/imx8m/imx8m_psci_common.c259
-rw-r--r--plat/imx/imx8m/imx8mm/gpc.c414
-rw-r--r--plat/imx/imx8m/imx8mm/imx8mm_bl2_el3_setup.c143
-rw-r--r--plat/imx/imx8m/imx8mm/imx8mm_bl2_mem_params_desc.c94
-rw-r--r--plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c252
-rw-r--r--plat/imx/imx8m/imx8mm/imx8mm_psci.c45
-rw-r--r--plat/imx/imx8m/imx8mm/imx8mm_rotpk.S15
-rw-r--r--plat/imx/imx8m/imx8mm/imx8mm_trusted_boot.c36
-rw-r--r--plat/imx/imx8m/imx8mm/include/gpc_reg.h129
-rw-r--r--plat/imx/imx8m/imx8mm/include/imx8mm_private.h15
-rw-r--r--plat/imx/imx8m/imx8mm/include/imx_sec_def.h216
-rw-r--r--plat/imx/imx8m/imx8mm/include/platform_def.h176
-rw-r--r--plat/imx/imx8m/imx8mm/platform.mk185
-rw-r--r--plat/imx/imx8m/imx8mn/gpc.c207
-rw-r--r--plat/imx/imx8m/imx8mn/imx8mn_bl31_setup.c249
-rw-r--r--plat/imx/imx8m/imx8mn/imx8mn_psci.c44
-rw-r--r--plat/imx/imx8m/imx8mn/include/gpc_reg.h111
-rw-r--r--plat/imx/imx8m/imx8mn/include/imx_sec_def.h210
-rw-r--r--plat/imx/imx8m/imx8mn/include/platform_def.h162
-rw-r--r--plat/imx/imx8m/imx8mn/platform.mk77
-rw-r--r--plat/imx/imx8m/imx8mp/gpc.c385
-rw-r--r--plat/imx/imx8m/imx8mp/imx8mp_bl2_el3_setup.c117
-rw-r--r--plat/imx/imx8m/imx8mp/imx8mp_bl2_mem_params_desc.c94
-rw-r--r--plat/imx/imx8m/imx8mp/imx8mp_bl31_setup.c248
-rw-r--r--plat/imx/imx8m/imx8mp/imx8mp_psci.c44
-rw-r--r--plat/imx/imx8m/imx8mp/imx8mp_rotpk.S15
-rw-r--r--plat/imx/imx8m/imx8mp/imx8mp_trusted_boot.c36
-rw-r--r--plat/imx/imx8m/imx8mp/include/gpc_reg.h151
-rw-r--r--plat/imx/imx8m/imx8mp/include/imx8mp_private.h15
-rw-r--r--plat/imx/imx8m/imx8mp/include/imx_sec_def.h274
-rw-r--r--plat/imx/imx8m/imx8mp/include/platform_def.h203
-rw-r--r--plat/imx/imx8m/imx8mp/platform.mk168
-rw-r--r--plat/imx/imx8m/imx8mq/gpc.c189
-rw-r--r--plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c242
-rw-r--r--plat/imx/imx8m/imx8mq/imx8mq_psci.c133
-rw-r--r--plat/imx/imx8m/imx8mq/include/gpc_reg.h89
-rw-r--r--plat/imx/imx8m/imx8mq/include/imx_sec_def.h249
-rw-r--r--plat/imx/imx8m/imx8mq/include/platform_def.h132
-rw-r--r--plat/imx/imx8m/imx8mq/platform.mk57
-rw-r--r--plat/imx/imx8m/imx_aipstz.c24
-rw-r--r--plat/imx/imx8m/imx_hab.c124
-rw-r--r--plat/imx/imx8m/imx_rdc.c37
-rw-r--r--plat/imx/imx8m/include/ddrc.h336
-rw-r--r--plat/imx/imx8m/include/dram.h78
-rw-r--r--plat/imx/imx8m/include/gpc.h75
-rw-r--r--plat/imx/imx8m/include/imx8m_caam.h35
-rw-r--r--plat/imx/imx8m/include/imx8m_csu.h74
-rw-r--r--plat/imx/imx8m/include/imx8m_measured_boot.h16
-rw-r--r--plat/imx/imx8m/include/imx8m_psci.h24
-rw-r--r--plat/imx/imx8m/include/imx_aipstz.h27
-rw-r--r--plat/imx/imx8m/include/imx_rdc.h73
-rw-r--r--plat/imx/imx8qm/imx8qm_bl31_setup.c415
-rw-r--r--plat/imx/imx8qm/imx8qm_psci.c326
-rw-r--r--plat/imx/imx8qm/include/platform_def.h79
-rw-r--r--plat/imx/imx8qm/include/sec_rsrc.h32
-rw-r--r--plat/imx/imx8qm/platform.mk50
-rw-r--r--plat/imx/imx8qx/imx8qx_bl31_setup.c383
-rw-r--r--plat/imx/imx8qx/imx8qx_psci.c246
-rw-r--r--plat/imx/imx8qx/include/platform_def.h68
-rw-r--r--plat/imx/imx8qx/include/sec_rsrc.h25
-rw-r--r--plat/imx/imx8qx/platform.mk42
-rw-r--r--plat/intel/soc/agilex/bl2_plat_setup.c189
-rw-r--r--plat/intel/soc/agilex/bl31_plat_setup.c160
-rw-r--r--plat/intel/soc/agilex/include/agilex_clock_manager.h131
-rw-r--r--plat/intel/soc/agilex/include/agilex_memory_controller.h163
-rw-r--r--plat/intel/soc/agilex/include/agilex_mmc.h7
-rw-r--r--plat/intel/soc/agilex/include/agilex_pinmux.h20
-rw-r--r--plat/intel/soc/agilex/include/socfpga_plat_def.h40
-rw-r--r--plat/intel/soc/agilex/platform.mk83
-rw-r--r--plat/intel/soc/agilex/soc/agilex_clock_manager.c399
-rw-r--r--plat/intel/soc/agilex/soc/agilex_memory_controller.c399
-rw-r--r--plat/intel/soc/agilex/soc/agilex_mmc.c19
-rw-r--r--plat/intel/soc/agilex/soc/agilex_pinmux.c225
-rw-r--r--plat/intel/soc/common/aarch64/plat_helpers.S150
-rw-r--r--plat/intel/soc/common/aarch64/platform_common.c60
-rw-r--r--plat/intel/soc/common/bl2_plat_mem_params_desc.c96
-rw-r--r--plat/intel/soc/common/drivers/ccu/ncore_ccu.c132
-rw-r--r--plat/intel/soc/common/drivers/ccu/ncore_ccu.h109
-rw-r--r--plat/intel/soc/common/drivers/qspi/cadence_qspi.c822
-rw-r--r--plat/intel/soc/common/drivers/qspi/cadence_qspi.h178
-rw-r--r--plat/intel/soc/common/drivers/wdt/watchdog.c52
-rw-r--r--plat/intel/soc/common/drivers/wdt/watchdog.h39
-rw-r--r--plat/intel/soc/common/include/plat_macros.S22
-rw-r--r--plat/intel/soc/common/include/platform_def.h242
-rw-r--r--plat/intel/soc/common/include/socfpga_emac.h24
-rw-r--r--plat/intel/soc/common/include/socfpga_f2sdram_manager.h39
-rw-r--r--plat/intel/soc/common/include/socfpga_fcs.h308
-rw-r--r--plat/intel/soc/common/include/socfpga_handoff.h135
-rw-r--r--plat/intel/soc/common/include/socfpga_mailbox.h240
-rw-r--r--plat/intel/soc/common/include/socfpga_noc.h95
-rw-r--r--plat/intel/soc/common/include/socfpga_private.h68
-rw-r--r--plat/intel/soc/common/include/socfpga_reset_manager.h125
-rw-r--r--plat/intel/soc/common/include/socfpga_sip_svc.h217
-rw-r--r--plat/intel/soc/common/include/socfpga_system_manager.h54
-rw-r--r--plat/intel/soc/common/sip/socfpga_sip_ecc.c46
-rw-r--r--plat/intel/soc/common/sip/socfpga_sip_fcs.c1739
-rw-r--r--plat/intel/soc/common/soc/socfpga_emac.c38
-rw-r--r--plat/intel/soc/common/soc/socfpga_firewall.c123
-rw-r--r--plat/intel/soc/common/soc/socfpga_handoff.c39
-rw-r--r--plat/intel/soc/common/soc/socfpga_mailbox.c647
-rw-r--r--plat/intel/soc/common/soc/socfpga_reset_manager.c331
-rw-r--r--plat/intel/soc/common/socfpga_delay_timer.c49
-rw-r--r--plat/intel/soc/common/socfpga_image_load.c58
-rw-r--r--plat/intel/soc/common/socfpga_psci.c229
-rw-r--r--plat/intel/soc/common/socfpga_sip_svc.c1131
-rw-r--r--plat/intel/soc/common/socfpga_sip_svc_v2.c174
-rw-r--r--plat/intel/soc/common/socfpga_storage.c193
-rw-r--r--plat/intel/soc/common/socfpga_topology.c51
-rw-r--r--plat/intel/soc/n5x/bl31_plat_setup.c165
-rw-r--r--plat/intel/soc/n5x/include/socfpga_plat_def.h42
-rw-r--r--plat/intel/soc/n5x/platform.mk52
-rw-r--r--plat/intel/soc/stratix10/bl2_plat_setup.c188
-rw-r--r--plat/intel/soc/stratix10/bl31_plat_setup.c173
-rw-r--r--plat/intel/soc/stratix10/include/s10_clock_manager.h99
-rw-r--r--plat/intel/soc/stratix10/include/s10_memory_controller.h160
-rw-r--r--plat/intel/soc/stratix10/include/s10_mmc.h12
-rw-r--r--plat/intel/soc/stratix10/include/s10_pinmux.h20
-rw-r--r--plat/intel/soc/stratix10/include/socfpga_plat_def.h40
-rw-r--r--plat/intel/soc/stratix10/platform.mk80
-rw-r--r--plat/intel/soc/stratix10/soc/s10_clock_manager.c322
-rw-r--r--plat/intel/soc/stratix10/soc/s10_memory_controller.c412
-rw-r--r--plat/intel/soc/stratix10/soc/s10_mmc.c19
-rw-r--r--plat/intel/soc/stratix10/soc/s10_pinmux.c217
-rw-r--r--plat/marvell/armada/a3k/a3700/board/pm_src.c37
-rw-r--r--plat/marvell/armada/a3k/a3700/mvebu_def.h13
-rw-r--r--plat/marvell/armada/a3k/a3700/plat_bl31_setup.c70
-rw-r--r--plat/marvell/armada/a3k/a3700/platform.mk10
-rw-r--r--plat/marvell/armada/a3k/common/a3700_common.mk247
-rw-r--r--plat/marvell/armada/a3k/common/a3700_ea.c78
-rw-r--r--plat/marvell/armada/a3k/common/a3700_sip_svc.c84
-rw-r--r--plat/marvell/armada/a3k/common/aarch64/a3700_clock.S35
-rw-r--r--plat/marvell/armada/a3k/common/aarch64/a3700_common.c53
-rw-r--r--plat/marvell/armada/a3k/common/aarch64/plat_helpers.S68
-rw-r--r--plat/marvell/armada/a3k/common/cm3_system_reset.c62
-rw-r--r--plat/marvell/armada/a3k/common/dram_win.c282
-rw-r--r--plat/marvell/armada/a3k/common/include/a3700_plat_def.h169
-rw-r--r--plat/marvell/armada/a3k/common/include/a3700_pm.h53
-rw-r--r--plat/marvell/armada/a3k/common/include/ddr_info.h14
-rw-r--r--plat/marvell/armada/a3k/common/include/dram_win.h18
-rw-r--r--plat/marvell/armada/a3k/common/include/io_addr_dec.h66
-rw-r--r--plat/marvell/armada/a3k/common/include/plat_macros.S26
-rw-r--r--plat/marvell/armada/a3k/common/include/platform_def.h228
-rw-r--r--plat/marvell/armada/a3k/common/io_addr_dec.c175
-rw-r--r--plat/marvell/armada/a3k/common/marvell_plat_config.c34
-rw-r--r--plat/marvell/armada/a3k/common/plat_cci.c35
-rw-r--r--plat/marvell/armada/a3k/common/plat_pm.c822
-rw-r--r--plat/marvell/armada/a8k/a70x0/board/dram_port.c91
-rw-r--r--plat/marvell/armada/a8k/a70x0/board/marvell_plat_config.c151
-rw-r--r--plat/marvell/armada/a8k/a70x0/mvebu_def.h15
-rw-r--r--plat/marvell/armada/a8k/a70x0/platform.mk20
-rw-r--r--plat/marvell/armada/a8k/a70x0_amc/board/dram_port.c91
-rw-r--r--plat/marvell/armada/a8k/a70x0_amc/board/marvell_plat_config.c148
-rw-r--r--plat/marvell/armada/a8k/a70x0_amc/mvebu_def.h31
-rw-r--r--plat/marvell/armada/a8k/a70x0_amc/platform.mk20
-rw-r--r--plat/marvell/armada/a8k/a70x0_mochabin/board/dram_port.c227
-rw-r--r--plat/marvell/armada/a8k/a70x0_mochabin/board/marvell_plat_config.c145
-rw-r--r--plat/marvell/armada/a8k/a70x0_mochabin/board/phy-porting-layer.h87
-rw-r--r--plat/marvell/armada/a8k/a70x0_mochabin/mvebu_def.h15
-rw-r--r--plat/marvell/armada/a8k/a70x0_mochabin/platform.mk20
-rw-r--r--plat/marvell/armada/a8k/a80x0/board/dram_port.c147
-rw-r--r--plat/marvell/armada/a8k/a80x0/board/marvell_plat_config.c202
-rw-r--r--plat/marvell/armada/a8k/a80x0/board/phy-porting-layer.h192
-rw-r--r--plat/marvell/armada/a8k/a80x0/mvebu_def.h17
-rw-r--r--plat/marvell/armada/a8k/a80x0/platform.mk20
-rw-r--r--plat/marvell/armada/a8k/a80x0_mcbin/board/dram_port.c131
-rw-r--r--plat/marvell/armada/a8k/a80x0_mcbin/board/marvell_plat_config.c200
-rw-r--r--plat/marvell/armada/a8k/a80x0_mcbin/mvebu_def.h17
-rw-r--r--plat/marvell/armada/a8k/a80x0_mcbin/platform.mk20
-rw-r--r--plat/marvell/armada/a8k/a80x0_puzzle/board/dram_port.c140
-rw-r--r--plat/marvell/armada/a8k/a80x0_puzzle/board/marvell_plat_config.c201
-rw-r--r--plat/marvell/armada/a8k/a80x0_puzzle/board/system_power.c59
-rw-r--r--plat/marvell/armada/a8k/a80x0_puzzle/mvebu_def.h17
-rw-r--r--plat/marvell/armada/a8k/a80x0_puzzle/platform.mk20
-rw-r--r--plat/marvell/armada/a8k/common/a8k_common.mk192
-rw-r--r--plat/marvell/armada/a8k/common/aarch64/a8k_common.c70
-rw-r--r--plat/marvell/armada/a8k/common/aarch64/plat_arch_config.c95
-rw-r--r--plat/marvell/armada/a8k/common/aarch64/plat_helpers.S112
-rw-r--r--plat/marvell/armada/a8k/common/ble/ble.ld.S76
-rw-r--r--plat/marvell/armada/a8k/common/ble/ble.mk35
-rw-r--r--plat/marvell/armada/a8k/common/ble/ble_main.c99
-rw-r--r--plat/marvell/armada/a8k/common/ble/ble_mem.S30
-rw-r--r--plat/marvell/armada/a8k/common/include/a8k_plat_def.h195
-rw-r--r--plat/marvell/armada/a8k/common/include/ddr_info.h9
-rw-r--r--plat/marvell/armada/a8k/common/include/mentor_i2c_plat.h33
-rw-r--r--plat/marvell/armada/a8k/common/include/plat_macros.S20
-rw-r--r--plat/marvell/armada/a8k/common/include/platform_def.h196
-rw-r--r--plat/marvell/armada/a8k/common/mss/mss_a8k.mk22
-rw-r--r--plat/marvell/armada/a8k/common/mss/mss_bl2_setup.c165
-rw-r--r--plat/marvell/armada/a8k/common/mss/mss_bl31_setup.c37
-rw-r--r--plat/marvell/armada/a8k/common/mss/mss_defs.h33
-rw-r--r--plat/marvell/armada/a8k/common/mss/mss_pm_ipc.c85
-rw-r--r--plat/marvell/armada/a8k/common/mss/mss_pm_ipc.h35
-rw-r--r--plat/marvell/armada/a8k/common/plat_bl1_setup.c19
-rw-r--r--plat/marvell/armada/a8k/common/plat_bl31_setup.c148
-rw-r--r--plat/marvell/armada/a8k/common/plat_ble_setup.c765
-rw-r--r--plat/marvell/armada/a8k/common/plat_pm.c853
-rw-r--r--plat/marvell/armada/a8k/common/plat_pm_trace.c94
-rw-r--r--plat/marvell/armada/a8k/common/plat_thermal.c130
-rw-r--r--plat/marvell/armada/common/aarch64/marvell_bl2_mem_params_desc.c168
-rw-r--r--plat/marvell/armada/common/aarch64/marvell_common.c137
-rw-r--r--plat/marvell/armada/common/aarch64/marvell_helpers.S259
-rw-r--r--plat/marvell/armada/common/marvell_bl1_setup.c105
-rw-r--r--plat/marvell/armada/common/marvell_bl2_setup.c158
-rw-r--r--plat/marvell/armada/common/marvell_bl31_setup.c237
-rw-r--r--plat/marvell/armada/common/marvell_cci.c52
-rw-r--r--plat/marvell/armada/common/marvell_common.mk99
-rw-r--r--plat/marvell/armada/common/marvell_console.c77
-rw-r--r--plat/marvell/armada/common/marvell_ddr_info.c112
-rw-r--r--plat/marvell/armada/common/marvell_gicv2.c148
-rw-r--r--plat/marvell/armada/common/marvell_gicv3.c210
-rw-r--r--plat/marvell/armada/common/marvell_image_load.c36
-rw-r--r--plat/marvell/armada/common/marvell_io_storage.c227
-rw-r--r--plat/marvell/armada/common/marvell_pm.c60
-rw-r--r--plat/marvell/armada/common/marvell_topology.c84
-rw-r--r--plat/marvell/armada/common/mrvl_sip_svc.c188
-rw-r--r--plat/marvell/armada/common/mss/mss_common.mk20
-rw-r--r--plat/marvell/armada/common/mss/mss_ipc_drv.c113
-rw-r--r--plat/marvell/armada/common/mss/mss_ipc_drv.h120
-rw-r--r--plat/marvell/armada/common/mss/mss_mem.h60
-rw-r--r--plat/marvell/armada/common/mss/mss_scp_bl2_format.h45
-rw-r--r--plat/marvell/armada/common/mss/mss_scp_bootloader.c368
-rw-r--r--plat/marvell/armada/common/mss/mss_scp_bootloader.h20
-rw-r--r--plat/marvell/armada/common/plat_delay_timer.c34
-rw-r--r--plat/marvell/marvell.mk21
-rw-r--r--plat/marvell/octeontx/otx2/t91/t9130/board/dram_port.c158
-rw-r--r--plat/marvell/octeontx/otx2/t91/t9130/board/marvell_plat_config.c192
-rw-r--r--plat/marvell/octeontx/otx2/t91/t9130/board/phy-porting-layer.h145
-rw-r--r--plat/marvell/octeontx/otx2/t91/t9130/mvebu_def.h25
-rw-r--r--plat/marvell/octeontx/otx2/t91/t9130/platform.mk20
-rw-r--r--plat/marvell/octeontx/otx2/t91/t9130_cex7_eval/board/marvell_plat_config.c224
-rw-r--r--plat/marvell/octeontx/otx2/t91/t9130_cex7_eval/platform.mk33
-rw-r--r--plat/mediatek/build_helpers/conditional_eval_options.mk51
-rw-r--r--plat/mediatek/build_helpers/mtk_build_helpers.mk142
-rw-r--r--plat/mediatek/build_helpers/mtk_build_helpers_epilogue.mk30
-rw-r--r--plat/mediatek/build_helpers/options.mk25
-rw-r--r--plat/mediatek/common/common_config.mk34
-rw-r--r--plat/mediatek/common/coreboot_config.mk15
-rw-r--r--plat/mediatek/common/lpm/mt_lp_rm.c110
-rw-r--r--plat/mediatek/common/lpm/mt_lp_rm.h42
-rw-r--r--plat/mediatek/common/lpm/rules.mk14
-rw-r--r--plat/mediatek/common/mtk_bl31_setup.c175
-rw-r--r--plat/mediatek/common/mtk_plat_common.c65
-rw-r--r--plat/mediatek/common/mtk_plat_common.h47
-rw-r--r--plat/mediatek/common/mtk_sip_svc.c129
-rw-r--r--plat/mediatek/common/mtk_smc_handlers.c235
-rw-r--r--plat/mediatek/common/params_setup.c35
-rw-r--r--plat/mediatek/common/plat_params.h17
-rw-r--r--plat/mediatek/common/rules.mk15
-rw-r--r--plat/mediatek/drivers/audio/audio.c43
-rw-r--r--plat/mediatek/drivers/audio/audio.h30
-rw-r--r--plat/mediatek/drivers/audio/mt8188/audio_domain.c44
-rw-r--r--plat/mediatek/drivers/audio/mt8188/mt_audio_private.h20
-rw-r--r--plat/mediatek/drivers/audio/mt8188/rules.mk13
-rw-r--r--plat/mediatek/drivers/audio/rules.mk19
-rw-r--r--plat/mediatek/drivers/cirq/mt_cirq.c549
-rw-r--r--plat/mediatek/drivers/cirq/mt_cirq.h122
-rw-r--r--plat/mediatek/drivers/cirq/rules.mk14
-rw-r--r--plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm.c466
-rw-r--r--plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm.h119
-rw-r--r--plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm_cpc.c253
-rw-r--r--plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm_cpc.h100
-rw-r--r--plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm_mbox.c95
-rw-r--r--plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm_mbox.h78
-rw-r--r--plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_smp.c93
-rw-r--r--plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_smp.h27
-rw-r--r--plat/mediatek/drivers/cpu_pm/cpcv3_2/rules.mk19
-rw-r--r--plat/mediatek/drivers/cpu_pm/rules.mk13
-rw-r--r--plat/mediatek/drivers/dcm/mt8188/mtk_dcm_utils.c402
-rw-r--r--plat/mediatek/drivers/dcm/mt8188/mtk_dcm_utils.h59
-rw-r--r--plat/mediatek/drivers/dcm/mtk_dcm.c84
-rw-r--r--plat/mediatek/drivers/dcm/mtk_dcm.h15
-rw-r--r--plat/mediatek/drivers/dcm/rules.mk17
-rw-r--r--plat/mediatek/drivers/dfd/dfd.c43
-rw-r--r--plat/mediatek/drivers/dfd/dfd.h16
-rw-r--r--plat/mediatek/drivers/dfd/mt8188/plat_dfd.c82
-rw-r--r--plat/mediatek/drivers/dfd/mt8188/plat_dfd.h78
-rw-r--r--plat/mediatek/drivers/dfd/rules.mk17
-rw-r--r--plat/mediatek/drivers/dp/mt_dp.c79
-rw-r--r--plat/mediatek/drivers/dp/mt_dp.h28
-rw-r--r--plat/mediatek/drivers/dp/rules.mk14
-rw-r--r--plat/mediatek/drivers/emi_mpu/emi_mpu.h64
-rw-r--r--plat/mediatek/drivers/emi_mpu/emi_mpu_common.c123
-rw-r--r--plat/mediatek/drivers/emi_mpu/mt8188/emi_mpu.c14
-rw-r--r--plat/mediatek/drivers/emi_mpu/mt8188/emi_mpu_priv.h45
-rw-r--r--plat/mediatek/drivers/emi_mpu/rules.mk16
-rw-r--r--plat/mediatek/drivers/gic600/mt_gic_v3.c208
-rw-r--r--plat/mediatek/drivers/gic600/mt_gic_v3.h28
-rw-r--r--plat/mediatek/drivers/gic600/rules.mk14
-rw-r--r--plat/mediatek/drivers/gpio/mt8188/mtgpio.c38
-rw-r--r--plat/mediatek/drivers/gpio/mt8188/mtgpio.h221
-rw-r--r--plat/mediatek/drivers/gpio/mtgpio_common.c302
-rw-r--r--plat/mediatek/drivers/gpio/mtgpio_common.h109
-rw-r--r--plat/mediatek/drivers/gpio/rules.mk18
-rw-r--r--plat/mediatek/drivers/iommu/mt8188/mtk_iommu_plat.c99
-rw-r--r--plat/mediatek/drivers/iommu/mt8188/mtk_iommu_plat.h24
-rw-r--r--plat/mediatek/drivers/iommu/mtk_iommu_priv.h44
-rw-r--r--plat/mediatek/drivers/iommu/mtk_iommu_smc.c125
-rw-r--r--plat/mediatek/drivers/iommu/rules.mk17
-rw-r--r--plat/mediatek/drivers/mcusys/mcusys.c15
-rw-r--r--plat/mediatek/drivers/mcusys/rules.mk15
-rw-r--r--plat/mediatek/drivers/mcusys/v1/mcucfg.h232
-rw-r--r--plat/mediatek/drivers/msdc/mt8186/mt_msdc_priv.h13
-rw-r--r--plat/mediatek/drivers/msdc/mt_msdc.c19
-rw-r--r--plat/mediatek/drivers/msdc/mt_msdc.h15
-rw-r--r--plat/mediatek/drivers/pmic/pmic.c13
-rw-r--r--plat/mediatek/drivers/pmic/pmic.h15
-rw-r--r--plat/mediatek/drivers/pmic/rules.mk15
-rw-r--r--plat/mediatek/drivers/pmic_wrap/mt8188/pmic_wrap_init.h30
-rw-r--r--plat/mediatek/drivers/pmic_wrap/pmic_wrap_init.c165
-rw-r--r--plat/mediatek/drivers/pmic_wrap/pmic_wrap_init_common.h61
-rw-r--r--plat/mediatek/drivers/pmic_wrap/pmic_wrap_init_v2.c143
-rw-r--r--plat/mediatek/drivers/pmic_wrap/rules.mk20
-rw-r--r--plat/mediatek/drivers/ptp3/mt8188/ptp3_plat.h47
-rw-r--r--plat/mediatek/drivers/ptp3/ptp3_common.c122
-rw-r--r--plat/mediatek/drivers/ptp3/ptp3_common.h21
-rw-r--r--plat/mediatek/drivers/ptp3/rules.mk16
-rw-r--r--plat/mediatek/drivers/rtc/mt8188/rtc.h12
-rw-r--r--plat/mediatek/drivers/rtc/rtc_common.c64
-rw-r--r--plat/mediatek/drivers/rtc/rtc_mt6359p.c148
-rw-r--r--plat/mediatek/drivers/rtc/rtc_mt6359p.h197
-rw-r--r--plat/mediatek/drivers/rtc/rules.mk20
-rw-r--r--plat/mediatek/drivers/timer/mt_timer.c44
-rw-r--r--plat/mediatek/drivers/timer/mt_timer.h35
-rw-r--r--plat/mediatek/drivers/timer/rules.mk14
-rw-r--r--plat/mediatek/drivers/uart/8250_console.S163
-rw-r--r--plat/mediatek/drivers/uart/uart.c112
-rw-r--r--plat/mediatek/drivers/uart/uart.h100
-rw-r--r--plat/mediatek/drivers/uart/uart8250.h38
-rw-r--r--plat/mediatek/helpers/armv8_2/arch_helpers.S118
-rw-r--r--plat/mediatek/helpers/rules.mk12
-rw-r--r--plat/mediatek/include/armv8_2/arch_def.h38
-rw-r--r--plat/mediatek/include/lib/mtk_init/mtk_init.h58
-rw-r--r--plat/mediatek/include/lib/mtk_init/mtk_init_def.h22
-rw-r--r--plat/mediatek/include/mtk_mmap_pool.h58
-rw-r--r--plat/mediatek/include/mtk_sip_def.h25
-rw-r--r--plat/mediatek/include/mtk_sip_svc.h106
-rw-r--r--plat/mediatek/include/plat.ld.rodata.inc30
-rw-r--r--plat/mediatek/include/vendor_pubsub_events.h21
-rw-r--r--plat/mediatek/lib/mtk_init/mtk_init.c39
-rw-r--r--plat/mediatek/lib/mtk_init/mtk_mmap_init.c55
-rw-r--r--plat/mediatek/lib/mtk_init/rules.mk14
-rw-r--r--plat/mediatek/lib/pm/armv8_2/pwr_ctrl.c543
-rw-r--r--plat/mediatek/lib/pm/armv8_2/rules.mk12
-rw-r--r--plat/mediatek/lib/pm/mtk_pm.c120
-rw-r--r--plat/mediatek/lib/pm/mtk_pm.h223
-rw-r--r--plat/mediatek/lib/pm/rules.mk17
-rw-r--r--plat/mediatek/lib/system_reset/reset_cros.c56
-rw-r--r--plat/mediatek/lib/system_reset/rules.mk14
-rw-r--r--plat/mediatek/mt8173/aarch64/plat_helpers.S49
-rw-r--r--plat/mediatek/mt8173/aarch64/platform_common.c89
-rw-r--r--plat/mediatek/mt8173/bl31_plat_setup.c146
-rw-r--r--plat/mediatek/mt8173/drivers/crypt/crypt.c123
-rw-r--r--plat/mediatek/mt8173/drivers/crypt/crypt.h16
-rw-r--r--plat/mediatek/mt8173/drivers/mtcmos/mtcmos.c274
-rw-r--r--plat/mediatek/mt8173/drivers/mtcmos/mtcmos.h18
-rw-r--r--plat/mediatek/mt8173/drivers/pmic/pmic_wrap_init.h169
-rw-r--r--plat/mediatek/mt8173/drivers/rtc/rtc.c26
-rw-r--r--plat/mediatek/mt8173/drivers/rtc/rtc.h60
-rw-r--r--plat/mediatek/mt8173/drivers/spm/spm.c370
-rw-r--r--plat/mediatek/mt8173/drivers/spm/spm.h335
-rw-r--r--plat/mediatek/mt8173/drivers/spm/spm_hotplug.c275
-rw-r--r--plat/mediatek/mt8173/drivers/spm/spm_hotplug.h13
-rw-r--r--plat/mediatek/mt8173/drivers/spm/spm_mcdi.c503
-rw-r--r--plat/mediatek/mt8173/drivers/spm/spm_mcdi.h14
-rw-r--r--plat/mediatek/mt8173/drivers/spm/spm_suspend.c315
-rw-r--r--plat/mediatek/mt8173/drivers/spm/spm_suspend.h16
-rw-r--r--plat/mediatek/mt8173/drivers/timer/mt_cpuxgpt.c34
-rw-r--r--plat/mediatek/mt8173/drivers/timer/mt_cpuxgpt.h16
-rw-r--r--plat/mediatek/mt8173/drivers/wdt/wdt.c115
-rw-r--r--plat/mediatek/mt8173/drivers/wdt/wdt.h20
-rw-r--r--plat/mediatek/mt8173/include/mcucfg.h220
-rw-r--r--plat/mediatek/mt8173/include/mt8173_def.h140
-rw-r--r--plat/mediatek/mt8173/include/plat_macros.S78
-rw-r--r--plat/mediatek/mt8173/include/plat_private.h27
-rw-r--r--plat/mediatek/mt8173/include/plat_sip_calls.h23
-rw-r--r--plat/mediatek/mt8173/include/platform_def.h141
-rw-r--r--plat/mediatek/mt8173/include/power_tracer.h19
-rw-r--r--plat/mediatek/mt8173/include/scu.h13
-rw-r--r--plat/mediatek/mt8173/plat_mt_gic.c30
-rw-r--r--plat/mediatek/mt8173/plat_pm.c603
-rw-r--r--plat/mediatek/mt8173/plat_sip_calls.c115
-rw-r--r--plat/mediatek/mt8173/plat_topology.c60
-rw-r--r--plat/mediatek/mt8173/platform.mk75
-rw-r--r--plat/mediatek/mt8173/power_tracer.c48
-rw-r--r--plat/mediatek/mt8173/scu.c30
-rw-r--r--plat/mediatek/mt8183/aarch64/plat_helpers.S34
-rw-r--r--plat/mediatek/mt8183/aarch64/platform_common.c84
-rw-r--r--plat/mediatek/mt8183/bl31_plat_setup.c181
-rw-r--r--plat/mediatek/mt8183/drivers/devapc/devapc.c231
-rw-r--r--plat/mediatek/mt8183/drivers/devapc/devapc.h499
-rw-r--r--plat/mediatek/mt8183/drivers/emi_mpu/emi_mpu.c147
-rw-r--r--plat/mediatek/mt8183/drivers/emi_mpu/emi_mpu.h106
-rw-r--r--plat/mediatek/mt8183/drivers/gpio/mtgpio.c439
-rw-r--r--plat/mediatek/mt8183/drivers/gpio/mtgpio.h154
-rw-r--r--plat/mediatek/mt8183/drivers/gpio/mtgpio_cfg.h208
-rw-r--r--plat/mediatek/mt8183/drivers/mcdi/mtk_mcdi.c259
-rw-r--r--plat/mediatek/mt8183/drivers/mcdi/mtk_mcdi.h34
-rw-r--r--plat/mediatek/mt8183/drivers/mcsi/mcsi.c211
-rw-r--r--plat/mediatek/mt8183/drivers/mcsi/mcsi.h116
-rw-r--r--plat/mediatek/mt8183/drivers/pmic/pmic.c42
-rw-r--r--plat/mediatek/mt8183/drivers/pmic/pmic.h30
-rw-r--r--plat/mediatek/mt8183/drivers/pmic/pmic_wrap_init.h94
-rw-r--r--plat/mediatek/mt8183/drivers/rtc/rtc.c133
-rw-r--r--plat/mediatek/mt8183/drivers/rtc/rtc.h147
-rw-r--r--plat/mediatek/mt8183/drivers/spm/spm.c363
-rw-r--r--plat/mediatek/mt8183/drivers/spm/spm.h2552
-rw-r--r--plat/mediatek/mt8183/drivers/spm/spm_pmic_wrap.c170
-rw-r--r--plat/mediatek/mt8183/drivers/spm/spm_pmic_wrap.h50
-rw-r--r--plat/mediatek/mt8183/drivers/spm/spm_suspend.c255
-rw-r--r--plat/mediatek/mt8183/drivers/spm/spm_suspend.h13
-rw-r--r--plat/mediatek/mt8183/drivers/spmc/mtspmc.c366
-rw-r--r--plat/mediatek/mt8183/drivers/spmc/mtspmc.h42
-rw-r--r--plat/mediatek/mt8183/drivers/spmc/mtspmc_private.h233
-rw-r--r--plat/mediatek/mt8183/drivers/sspm/sspm.c159
-rw-r--r--plat/mediatek/mt8183/drivers/sspm/sspm.h32
-rw-r--r--plat/mediatek/mt8183/drivers/timer/mt_timer.c29
-rw-r--r--plat/mediatek/mt8183/drivers/timer/mt_timer.h20
-rw-r--r--plat/mediatek/mt8183/include/mcucfg.h568
-rw-r--r--plat/mediatek/mt8183/include/mt_gic_v3.h34
-rw-r--r--plat/mediatek/mt8183/include/plat_dcm.h53
-rw-r--r--plat/mediatek/mt8183/include/plat_debug.h34
-rw-r--r--plat/mediatek/mt8183/include/plat_macros.S78
-rw-r--r--plat/mediatek/mt8183/include/plat_private.h28
-rw-r--r--plat/mediatek/mt8183/include/platform_def.h321
-rw-r--r--plat/mediatek/mt8183/include/power_tracer.h20
-rw-r--r--plat/mediatek/mt8183/include/scu.h13
-rw-r--r--plat/mediatek/mt8183/include/sspm_reg.h41
-rw-r--r--plat/mediatek/mt8183/plat_dcm.c112
-rw-r--r--plat/mediatek/mt8183/plat_debug.c58
-rw-r--r--plat/mediatek/mt8183/plat_mt_gic.c160
-rw-r--r--plat/mediatek/mt8183/plat_pm.c589
-rw-r--r--plat/mediatek/mt8183/plat_topology.c59
-rw-r--r--plat/mediatek/mt8183/platform.mk90
-rw-r--r--plat/mediatek/mt8183/scu.c56
-rw-r--r--plat/mediatek/mt8186/aarch64/plat_helpers.S45
-rw-r--r--plat/mediatek/mt8186/aarch64/platform_common.c44
-rw-r--r--plat/mediatek/mt8186/bl31_plat_setup.c113
-rw-r--r--plat/mediatek/mt8186/drivers/dcm/mtk_dcm.c66
-rw-r--r--plat/mediatek/mt8186/drivers/dcm/mtk_dcm.h14
-rw-r--r--plat/mediatek/mt8186/drivers/dcm/mtk_dcm_utils.c490
-rw-r--r--plat/mediatek/mt8186/drivers/dcm/mtk_dcm_utils.h58
-rw-r--r--plat/mediatek/mt8186/drivers/dfd/plat_dfd.c98
-rw-r--r--plat/mediatek/mt8186/drivers/dfd/plat_dfd.h64
-rw-r--r--plat/mediatek/mt8186/drivers/emi_mpu/emi_mpu.c133
-rw-r--r--plat/mediatek/mt8186/drivers/emi_mpu/emi_mpu.h98
-rw-r--r--plat/mediatek/mt8186/drivers/gpio/mtgpio.c44
-rw-r--r--plat/mediatek/mt8186/drivers/gpio/mtgpio.h230
-rw-r--r--plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.c149
-rw-r--r--plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.h34
-rw-r--r--plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_cpc.c269
-rw-r--r--plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_cpc.h102
-rw-r--r--plat/mediatek/mt8186/drivers/mcdi/mt_lp_irqremain.c74
-rw-r--r--plat/mediatek/mt8186/drivers/mcdi/mt_lp_irqremain.h15
-rw-r--r--plat/mediatek/mt8186/drivers/mcdi/mt_mcdi.c150
-rw-r--r--plat/mediatek/mt8186/drivers/mcdi/mt_mcdi.h12
-rw-r--r--plat/mediatek/mt8186/drivers/pmic/pmic.c23
-rw-r--r--plat/mediatek/mt8186/drivers/pmic/pmic.h19
-rw-r--r--plat/mediatek/mt8186/drivers/pmic/pmic_wrap_init.h61
-rw-r--r--plat/mediatek/mt8186/drivers/rtc/rtc.c133
-rw-r--r--plat/mediatek/mt8186/drivers/rtc/rtc.h145
-rw-r--r--plat/mediatek/mt8186/drivers/spm/build.mk78
-rw-r--r--plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_bus26m.c241
-rw-r--r--plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_cpu_buck_ldo.c105
-rw-r--r--plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_dram.c187
-rw-r--r--plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_internal.h48
-rw-r--r--plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_syspll.c197
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm.c110
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm.h82
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_cond.c212
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_cond.h60
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_conservation.c165
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_conservation.h21
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_constraint.h64
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_extern.c23
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_extern.h12
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_idle.c240
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_idle.h24
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_internal.c623
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_internal.h620
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_pmic_wrap.c166
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_pmic_wrap.h39
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_reg.h2957
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_resource_req.h26
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_suspend.c286
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_suspend.h28
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_vcorefs.c533
-rw-r--r--plat/mediatek/mt8186/drivers/spm/mt_spm_vcorefs.h316
-rw-r--r--plat/mediatek/mt8186/drivers/spm/notifier/mt_spm_notifier.h23
-rw-r--r--plat/mediatek/mt8186/drivers/spm/notifier/mt_spm_sspm_intc.h36
-rw-r--r--plat/mediatek/mt8186/drivers/spm/notifier/mt_spm_sspm_notifier.c41
-rw-r--r--plat/mediatek/mt8186/drivers/spm/pcm_def.h180
-rw-r--r--plat/mediatek/mt8186/drivers/spm/sleep_def.h146
-rw-r--r--plat/mediatek/mt8186/drivers/spmc/mtspmc.c172
-rw-r--r--plat/mediatek/mt8186/drivers/spmc/mtspmc.h31
-rw-r--r--plat/mediatek/mt8186/drivers/spmc/mtspmc_private.h176
-rw-r--r--plat/mediatek/mt8186/include/mcucfg.h255
-rw-r--r--plat/mediatek/mt8186/include/mt_spm_resource_req.h32
-rw-r--r--plat/mediatek/mt8186/include/plat_helpers.h12
-rw-r--r--plat/mediatek/mt8186/include/plat_macros.S37
-rw-r--r--plat/mediatek/mt8186/include/plat_mtk_lpm.h49
-rw-r--r--plat/mediatek/mt8186/include/plat_pm.h128
-rw-r--r--plat/mediatek/mt8186/include/plat_private.h18
-rw-r--r--plat/mediatek/mt8186/include/plat_sip_calls.h15
-rw-r--r--plat/mediatek/mt8186/include/plat_uart.h25
-rw-r--r--plat/mediatek/mt8186/include/platform_def.h161
-rw-r--r--plat/mediatek/mt8186/include/sspm_reg.h21
-rw-r--r--plat/mediatek/mt8186/plat_pm.c400
-rw-r--r--plat/mediatek/mt8186/plat_sip_calls.c49
-rw-r--r--plat/mediatek/mt8186/plat_topology.c70
-rw-r--r--plat/mediatek/mt8186/platform.mk110
-rw-r--r--plat/mediatek/mt8188/include/plat_helpers.h12
-rw-r--r--plat/mediatek/mt8188/include/plat_macros.S38
-rw-r--r--plat/mediatek/mt8188/include/plat_private.h18
-rw-r--r--plat/mediatek/mt8188/include/platform_def.h183
-rw-r--r--plat/mediatek/mt8188/include/spm_reg.h499
-rw-r--r--plat/mediatek/mt8188/plat_config.mk48
-rw-r--r--plat/mediatek/mt8188/plat_mmap.c20
-rw-r--r--plat/mediatek/mt8188/platform.mk65
-rw-r--r--plat/mediatek/mt8192/aarch64/plat_helpers.S49
-rw-r--r--plat/mediatek/mt8192/aarch64/platform_common.c56
-rw-r--r--plat/mediatek/mt8192/bl31_plat_setup.c121
-rw-r--r--plat/mediatek/mt8192/drivers/apusys/mtk_apusys.c68
-rw-r--r--plat/mediatek/mt8192/drivers/apusys/mtk_apusys.h42
-rw-r--r--plat/mediatek/mt8192/drivers/apusys/mtk_apusys_apc.c571
-rw-r--r--plat/mediatek/mt8192/drivers/apusys/mtk_apusys_apc.h12
-rw-r--r--plat/mediatek/mt8192/drivers/apusys/mtk_apusys_apc_def.h110
-rw-r--r--plat/mediatek/mt8192/drivers/dcm/mtk_dcm.c63
-rw-r--r--plat/mediatek/mt8192/drivers/dcm/mtk_dcm.h14
-rw-r--r--plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.c562
-rw-r--r--plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.h68
-rw-r--r--plat/mediatek/mt8192/drivers/devapc/devapc.c2847
-rw-r--r--plat/mediatek/mt8192/drivers/devapc/devapc.h211
-rw-r--r--plat/mediatek/mt8192/drivers/dfd/plat_dfd.c139
-rw-r--r--plat/mediatek/mt8192/drivers/dfd/plat_dfd.h70
-rw-r--r--plat/mediatek/mt8192/drivers/emi_mpu/emi_mpu.c144
-rw-r--r--plat/mediatek/mt8192/drivers/emi_mpu/emi_mpu.h102
-rw-r--r--plat/mediatek/mt8192/drivers/gpio/mtgpio.c53
-rw-r--r--plat/mediatek/mt8192/drivers/gpio/mtgpio.h269
-rw-r--r--plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm.c149
-rw-r--r--plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.c269
-rw-r--r--plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.h106
-rw-r--r--plat/mediatek/mt8192/drivers/mcdi/mt_lp_irqremain.c150
-rw-r--r--plat/mediatek/mt8192/drivers/mcdi/mt_lp_irqremain.h14
-rw-r--r--plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.c151
-rw-r--r--plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.h12
-rw-r--r--plat/mediatek/mt8192/drivers/pmic/pmic_wrap_init.h30
-rw-r--r--plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_common.h48
-rw-r--r--plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_main.c84
-rw-r--r--plat/mediatek/mt8192/drivers/spm/build.mk68
-rw-r--r--plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_bus26m.c230
-rw-r--r--plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_cpu_buck_ldo.c104
-rw-r--r--plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_dram.c191
-rw-r--r--plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_internal.h45
-rw-r--r--plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_syspll.c192
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm.c104
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm.h68
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm_cond.c219
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm_cond.h56
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm_conservation.c155
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm_conservation.h20
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm_constraint.h63
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm_idle.c249
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm_idle.h17
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm_internal.c588
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm_internal.h637
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm_pmic_wrap.c159
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm_pmic_wrap.h45
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm_reg.h2919
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm_resource_req.h25
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm_suspend.c303
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm_suspend.h26
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm_vcorefs.c405
-rw-r--r--plat/mediatek/mt8192/drivers/spm/mt_spm_vcorefs.h135
-rw-r--r--plat/mediatek/mt8192/drivers/spm/notifier/mt_spm_notifier.h21
-rw-r--r--plat/mediatek/mt8192/drivers/spm/notifier/mt_spm_sspm_intc.h33
-rw-r--r--plat/mediatek/mt8192/drivers/spm/notifier/mt_spm_sspm_notifier.c47
-rw-r--r--plat/mediatek/mt8192/drivers/spm/pcm_def.h179
-rw-r--r--plat/mediatek/mt8192/drivers/spm/sleep_def.h151
-rw-r--r--plat/mediatek/mt8192/drivers/spmc/mtspmc.c177
-rw-r--r--plat/mediatek/mt8192/drivers/spmc/mtspmc.h31
-rw-r--r--plat/mediatek/mt8192/drivers/spmc/mtspmc_private.h184
-rw-r--r--plat/mediatek/mt8192/include/mcucfg.h257
-rw-r--r--plat/mediatek/mt8192/include/plat_helpers.h12
-rw-r--r--plat/mediatek/mt8192/include/plat_macros.S38
-rw-r--r--plat/mediatek/mt8192/include/plat_mtk_lpm.h48
-rw-r--r--plat/mediatek/mt8192/include/plat_pm.h38
-rw-r--r--plat/mediatek/mt8192/include/plat_private.h18
-rw-r--r--plat/mediatek/mt8192/include/plat_sip_calls.h15
-rw-r--r--plat/mediatek/mt8192/include/platform_def.h151
-rw-r--r--plat/mediatek/mt8192/include/rtc.h12
-rw-r--r--plat/mediatek/mt8192/plat_pm.c398
-rw-r--r--plat/mediatek/mt8192/plat_sip_calls.c49
-rw-r--r--plat/mediatek/mt8192/plat_topology.c75
-rw-r--r--plat/mediatek/mt8192/platform.mk103
-rw-r--r--plat/mediatek/mt8195/aarch64/plat_helpers.S49
-rw-r--r--plat/mediatek/mt8195/aarch64/platform_common.c56
-rw-r--r--plat/mediatek/mt8195/bl31_plat_setup.c117
-rw-r--r--plat/mediatek/mt8195/drivers/apusys/apupll.c581
-rw-r--r--plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.c341
-rw-r--r--plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.h23
-rw-r--r--plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl_def.h195
-rw-r--r--plat/mediatek/mt8195/drivers/apusys/mtk_apusys.c83
-rw-r--r--plat/mediatek/mt8195/drivers/apusys/mtk_apusys.h51
-rw-r--r--plat/mediatek/mt8195/drivers/dcm/mtk_dcm.c63
-rw-r--r--plat/mediatek/mt8195/drivers/dcm/mtk_dcm.h14
-rw-r--r--plat/mediatek/mt8195/drivers/dcm/mtk_dcm_utils.c483
-rw-r--r--plat/mediatek/mt8195/drivers/dcm/mtk_dcm_utils.h59
-rw-r--r--plat/mediatek/mt8195/drivers/dfd/plat_dfd.c156
-rw-r--r--plat/mediatek/mt8195/drivers/dfd/plat_dfd.h85
-rw-r--r--plat/mediatek/mt8195/drivers/emi_mpu/emi_mpu.c151
-rw-r--r--plat/mediatek/mt8195/drivers/emi_mpu/emi_mpu.h98
-rw-r--r--plat/mediatek/mt8195/drivers/gpio/mtgpio.c44
-rw-r--r--plat/mediatek/mt8195/drivers/gpio/mtgpio.h183
-rw-r--r--plat/mediatek/mt8195/drivers/mcdi/mt_cpu_pm.c150
-rw-r--r--plat/mediatek/mt8195/drivers/mcdi/mt_cpu_pm_cpc.c269
-rw-r--r--plat/mediatek/mt8195/drivers/mcdi/mt_cpu_pm_cpc.h106
-rw-r--r--plat/mediatek/mt8195/drivers/mcdi/mt_lp_irqremain.c69
-rw-r--r--plat/mediatek/mt8195/drivers/mcdi/mt_lp_irqremain.h14
-rw-r--r--plat/mediatek/mt8195/drivers/mcdi/mt_mcdi.c151
-rw-r--r--plat/mediatek/mt8195/drivers/mcdi/mt_mcdi.h12
-rw-r--r--plat/mediatek/mt8195/drivers/pmic/pmic_wrap_init.h30
-rw-r--r--plat/mediatek/mt8195/drivers/ptp3/ptp3_plat.h46
-rw-r--r--plat/mediatek/mt8195/drivers/spm/build.mk68
-rw-r--r--plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_bus26m.c241
-rw-r--r--plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_cpu_buck_ldo.c106
-rw-r--r--plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_dram.c201
-rw-r--r--plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_internal.h43
-rw-r--r--plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_syspll.c200
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm.c98
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm.h68
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm_cond.c235
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm_cond.h73
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm_conservation.c155
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm_conservation.h20
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm_constraint.h63
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm_idle.c346
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm_idle.h17
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm_internal.c550
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm_internal.h583
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm_pmic_wrap.c159
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm_pmic_wrap.h45
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm_reg.h2859
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm_resource_req.h25
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm_suspend.c394
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm_suspend.h26
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm_vcorefs.c526
-rw-r--r--plat/mediatek/mt8195/drivers/spm/mt_spm_vcorefs.h328
-rw-r--r--plat/mediatek/mt8195/drivers/spm/notifier/mt_spm_notifier.h21
-rw-r--r--plat/mediatek/mt8195/drivers/spm/notifier/mt_spm_sspm_intc.h33
-rw-r--r--plat/mediatek/mt8195/drivers/spm/notifier/mt_spm_sspm_notifier.c38
-rw-r--r--plat/mediatek/mt8195/drivers/spm/pcm_def.h179
-rw-r--r--plat/mediatek/mt8195/drivers/spm/sleep_def.h151
-rw-r--r--plat/mediatek/mt8195/drivers/spmc/mtspmc.c166
-rw-r--r--plat/mediatek/mt8195/drivers/spmc/mtspmc.h31
-rw-r--r--plat/mediatek/mt8195/drivers/spmc/mtspmc_private.h183
-rw-r--r--plat/mediatek/mt8195/include/mcucfg.h257
-rw-r--r--plat/mediatek/mt8195/include/plat_helpers.h12
-rw-r--r--plat/mediatek/mt8195/include/plat_macros.S37
-rw-r--r--plat/mediatek/mt8195/include/plat_mtk_lpm.h48
-rw-r--r--plat/mediatek/mt8195/include/plat_pm.h38
-rw-r--r--plat/mediatek/mt8195/include/plat_private.h18
-rw-r--r--plat/mediatek/mt8195/include/plat_sip_calls.h15
-rw-r--r--plat/mediatek/mt8195/include/platform_def.h168
-rw-r--r--plat/mediatek/mt8195/include/rtc.h12
-rw-r--r--plat/mediatek/mt8195/plat_pm.c403
-rw-r--r--plat/mediatek/mt8195/plat_sip_calls.c56
-rw-r--r--plat/mediatek/mt8195/plat_topology.c70
-rw-r--r--plat/mediatek/mt8195/platform.mk113
-rw-r--r--plat/mediatek/topology/armv8_2/topology.c28
-rw-r--r--plat/mediatek/topology/rules.mk12
-rw-r--r--plat/nvidia/tegra/common/aarch64/tegra_helpers.S428
-rw-r--r--plat/nvidia/tegra/common/tegra_bl31_setup.c366
-rw-r--r--plat/nvidia/tegra/common/tegra_common.mk59
-rw-r--r--plat/nvidia/tegra/common/tegra_delay_timer.c57
-rw-r--r--plat/nvidia/tegra/common/tegra_fiq_glue.c149
-rw-r--r--plat/nvidia/tegra/common/tegra_gicv2.c72
-rw-r--r--plat/nvidia/tegra/common/tegra_gicv3.c79
-rw-r--r--plat/nvidia/tegra/common/tegra_io_storage.c20
-rw-r--r--plat/nvidia/tegra/common/tegra_platform.c309
-rw-r--r--plat/nvidia/tegra/common/tegra_pm.c329
-rw-r--r--plat/nvidia/tegra/common/tegra_sdei.c56
-rw-r--r--plat/nvidia/tegra/common/tegra_sip_calls.c158
-rw-r--r--plat/nvidia/tegra/common/tegra_stack_protector.c28
-rw-r--r--plat/nvidia/tegra/drivers/bpmp/bpmp.c231
-rw-r--r--plat/nvidia/tegra/drivers/bpmp_ipc/intf.c345
-rw-r--r--plat/nvidia/tegra/drivers/bpmp_ipc/intf.h127
-rw-r--r--plat/nvidia/tegra/drivers/bpmp_ipc/ivc.c654
-rw-r--r--plat/nvidia/tegra/drivers/bpmp_ipc/ivc.h50
-rw-r--r--plat/nvidia/tegra/drivers/flowctrl/flowctrl.c322
-rw-r--r--plat/nvidia/tegra/drivers/gpcdma/gpcdma.c188
-rw-r--r--plat/nvidia/tegra/drivers/memctrl/memctrl_v1.c212
-rw-r--r--plat/nvidia/tegra/drivers/memctrl/memctrl_v2.c354
-rw-r--r--plat/nvidia/tegra/drivers/pmc/pmc.c153
-rw-r--r--plat/nvidia/tegra/drivers/smmu/smmu.c121
-rw-r--r--plat/nvidia/tegra/drivers/spe/shared_console.S187
-rw-r--r--plat/nvidia/tegra/include/drivers/bpmp.h127
-rw-r--r--plat/nvidia/tegra/include/drivers/bpmp_ipc.h43
-rw-r--r--plat/nvidia/tegra/include/drivers/flowctrl.h98
-rw-r--r--plat/nvidia/tegra/include/drivers/gpcdma.h17
-rw-r--r--plat/nvidia/tegra/include/drivers/mce.h76
-rw-r--r--plat/nvidia/tegra/include/drivers/memctrl.h18
-rw-r--r--plat/nvidia/tegra/include/drivers/memctrl_v1.h57
-rw-r--r--plat/nvidia/tegra/include/drivers/memctrl_v2.h107
-rw-r--r--plat/nvidia/tegra/include/drivers/pmc.h72
-rw-r--r--plat/nvidia/tegra/include/drivers/security_engine.h60
-rw-r--r--plat/nvidia/tegra/include/drivers/smmu.h92
-rw-r--r--plat/nvidia/tegra/include/drivers/spe.h23
-rw-r--r--plat/nvidia/tegra/include/drivers/tegra_gic.h30
-rw-r--r--plat/nvidia/tegra/include/lib/profiler.h20
-rw-r--r--plat/nvidia/tegra/include/plat_macros.S63
-rw-r--r--plat/nvidia/tegra/include/platform_def.h132
-rw-r--r--plat/nvidia/tegra/include/t186/tegra186_private.h12
-rw-r--r--plat/nvidia/tegra/include/t186/tegra_def.h327
-rw-r--r--plat/nvidia/tegra/include/t186/tegra_mc_def.h398
-rw-r--r--plat/nvidia/tegra/include/t194/tegra194_private.h16
-rw-r--r--plat/nvidia/tegra/include/t194/tegra194_ras_private.h263
-rw-r--r--plat/nvidia/tegra/include/t194/tegra_def.h326
-rw-r--r--plat/nvidia/tegra/include/t210/tegra_def.h293
-rw-r--r--plat/nvidia/tegra/include/tegra_platform.h70
-rw-r--r--plat/nvidia/tegra/include/tegra_private.h158
-rw-r--r--plat/nvidia/tegra/lib/debug/profiler.c144
-rw-r--r--plat/nvidia/tegra/platform.mk97
-rw-r--r--plat/nvidia/tegra/scat/bl31.scat284
-rw-r--r--plat/nvidia/tegra/soc/t186/drivers/include/mce_private.h260
-rw-r--r--plat/nvidia/tegra/soc/t186/drivers/include/t18x_ari.h437
-rw-r--r--plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S31
-rw-r--r--plat/nvidia/tegra/soc/t186/drivers/mce/ari.c564
-rw-r--r--plat/nvidia/tegra/soc/t186/drivers/mce/mce.c476
-rw-r--r--plat/nvidia/tegra/soc/t186/drivers/mce/nvg.c256
-rw-r--r--plat/nvidia/tegra/soc/t186/drivers/se/se.c277
-rw-r--r--plat/nvidia/tegra/soc/t186/drivers/se/se_private.h100
-rw-r--r--plat/nvidia/tegra/soc/t186/plat_memctrl.c700
-rw-r--r--plat/nvidia/tegra/soc/t186/plat_psci_handlers.c472
-rw-r--r--plat/nvidia/tegra/soc/t186/plat_secondary.c41
-rw-r--r--plat/nvidia/tegra/soc/t186/plat_setup.c397
-rw-r--r--plat/nvidia/tegra/soc/t186/plat_sip_calls.c159
-rw-r--r--plat/nvidia/tegra/soc/t186/plat_smmu.c22
-rw-r--r--plat/nvidia/tegra/soc/t186/plat_trampoline.S41
-rw-r--r--plat/nvidia/tegra/soc/t186/platform_t186.mk77
-rw-r--r--plat/nvidia/tegra/soc/t194/drivers/include/mce_private.h79
-rw-r--r--plat/nvidia/tegra/soc/t194/drivers/include/se.h15
-rw-r--r--plat/nvidia/tegra/soc/t194/drivers/include/t194_nvg.h429
-rw-r--r--plat/nvidia/tegra/soc/t194/drivers/mce/aarch64/nvg_helpers.S52
-rw-r--r--plat/nvidia/tegra/soc/t194/drivers/mce/mce.c255
-rw-r--r--plat/nvidia/tegra/soc/t194/drivers/mce/nvg.c262
-rw-r--r--plat/nvidia/tegra/soc/t194/drivers/se/se.c511
-rw-r--r--plat/nvidia/tegra/soc/t194/drivers/se/se_private.h165
-rw-r--r--plat/nvidia/tegra/soc/t194/plat_memctrl.c83
-rw-r--r--plat/nvidia/tegra/soc/t194/plat_psci_handlers.c505
-rw-r--r--plat/nvidia/tegra/soc/t194/plat_ras.c493
-rw-r--r--plat/nvidia/tegra/soc/t194/plat_secondary.c75
-rw-r--r--plat/nvidia/tegra/soc/t194/plat_setup.c449
-rw-r--r--plat/nvidia/tegra/soc/t194/plat_sip_calls.c103
-rw-r--r--plat/nvidia/tegra/soc/t194/plat_smmu.c35
-rw-r--r--plat/nvidia/tegra/soc/t194/plat_trampoline.S150
-rw-r--r--plat/nvidia/tegra/soc/t194/platform_t194.mk85
-rw-r--r--plat/nvidia/tegra/soc/t210/drivers/se/se_private.h663
-rw-r--r--plat/nvidia/tegra/soc/t210/drivers/se/security_engine.c1071
-rw-r--r--plat/nvidia/tegra/soc/t210/plat_psci_handlers.c609
-rw-r--r--plat/nvidia/tegra/soc/t210/plat_secondary.c41
-rw-r--r--plat/nvidia/tegra/soc/t210/plat_setup.c318
-rw-r--r--plat/nvidia/tegra/soc/t210/plat_sip_calls.c97
-rw-r--r--plat/nvidia/tegra/soc/t210/platform_t210.mk62
-rw-r--r--plat/nxp/common/aarch64/bl31_data.S558
-rw-r--r--plat/nxp/common/aarch64/ls_helpers.S220
-rw-r--r--plat/nxp/common/fip_handler/common/plat_def_fip_uuid.h51
-rw-r--r--plat/nxp/common/fip_handler/common/plat_tbbr_img_def.h53
-rw-r--r--plat/nxp/common/fip_handler/common/platform_oid.h16
-rw-r--r--plat/nxp/common/fip_handler/ddr_fip/ddr_fip_io.mk38
-rw-r--r--plat/nxp/common/fip_handler/ddr_fip/ddr_io_storage.c232
-rw-r--r--plat/nxp/common/fip_handler/ddr_fip/ddr_io_storage.h26
-rw-r--r--plat/nxp/common/fip_handler/fuse_fip/fuse.mk100
-rw-r--r--plat/nxp/common/fip_handler/fuse_fip/fuse_io.h27
-rw-r--r--plat/nxp/common/fip_handler/fuse_fip/fuse_io_storage.c223
-rw-r--r--plat/nxp/common/img_loadr/img_loadr.mk21
-rw-r--r--plat/nxp/common/img_loadr/load_img.c83
-rw-r--r--plat/nxp/common/img_loadr/load_img.h14
-rw-r--r--plat/nxp/common/include/default/ch_2/soc_default_base_addr.h70
-rw-r--r--plat/nxp/common/include/default/ch_2/soc_default_helper_macros.h83
-rw-r--r--plat/nxp/common/include/default/ch_3/soc_default_base_addr.h100
-rw-r--r--plat/nxp/common/include/default/ch_3/soc_default_helper_macros.h98
-rw-r--r--plat/nxp/common/include/default/ch_3_2/soc_default_base_addr.h88
-rw-r--r--plat/nxp/common/include/default/ch_3_2/soc_default_helper_macros.h87
-rw-r--r--plat/nxp/common/include/default/plat_default_def.h172
-rw-r--r--plat/nxp/common/nv_storage/nv_storage.mk29
-rw-r--r--plat/nxp/common/nv_storage/plat_nv_storage.c121
-rw-r--r--plat/nxp/common/nv_storage/plat_nv_storage.h40
-rw-r--r--plat/nxp/common/ocram/aarch64/ocram.S71
-rw-r--r--plat/nxp/common/ocram/ocram.h13
-rw-r--r--plat/nxp/common/ocram/ocram.mk14
-rw-r--r--plat/nxp/common/plat_make_helper/plat_build_macros.mk11
-rw-r--r--plat/nxp/common/plat_make_helper/plat_common_def.mk103
-rw-r--r--plat/nxp/common/plat_make_helper/soc_common_def.mk117
-rw-r--r--plat/nxp/common/psci/aarch64/psci_utils.S1155
-rw-r--r--plat/nxp/common/psci/include/plat_psci.h145
-rw-r--r--plat/nxp/common/psci/plat_psci.c475
-rw-r--r--plat/nxp/common/psci/psci.mk35
-rw-r--r--plat/nxp/common/setup/aarch64/ls_bl2_mem_params_desc.c103
-rw-r--r--plat/nxp/common/setup/common.mk105
-rw-r--r--plat/nxp/common/setup/core.mk22
-rw-r--r--plat/nxp/common/setup/include/bl31_data.h61
-rw-r--r--plat/nxp/common/setup/include/ls_interrupt_mgmt.h23
-rw-r--r--plat/nxp/common/setup/include/mmu_def.h34
-rw-r--r--plat/nxp/common/setup/include/plat_common.h152
-rw-r--r--plat/nxp/common/setup/include/plat_macros.S22
-rw-r--r--plat/nxp/common/setup/ls_bl2_el3_setup.c303
-rw-r--r--plat/nxp/common/setup/ls_bl31_setup.c212
-rw-r--r--plat/nxp/common/setup/ls_common.c277
-rw-r--r--plat/nxp/common/setup/ls_err.c55
-rw-r--r--plat/nxp/common/setup/ls_image_load.c33
-rw-r--r--plat/nxp/common/setup/ls_interrupt_mgmt.c66
-rw-r--r--plat/nxp/common/setup/ls_io_storage.c556
-rw-r--r--plat/nxp/common/setup/ls_stack_protector.c22
-rw-r--r--plat/nxp/common/sip_svc/aarch64/sipsvc.S152
-rw-r--r--plat/nxp/common/sip_svc/include/sipsvc.h80
-rw-r--r--plat/nxp/common/sip_svc/sip_svc.c194
-rw-r--r--plat/nxp/common/sip_svc/sipsvc.mk35
-rw-r--r--plat/nxp/common/soc_errata/errata.c59
-rw-r--r--plat/nxp/common/soc_errata/errata.h15
-rw-r--r--plat/nxp/common/soc_errata/errata.mk26
-rw-r--r--plat/nxp/common/soc_errata/errata_a008850.c42
-rw-r--r--plat/nxp/common/soc_errata/errata_a009660.c14
-rw-r--r--plat/nxp/common/soc_errata/errata_a010539.c26
-rw-r--r--plat/nxp/common/soc_errata/errata_a050426.c201
-rw-r--r--plat/nxp/common/soc_errata/errata_list.h28
-rw-r--r--plat/nxp/common/tbbr/csf_tbbr.c81
-rw-r--r--plat/nxp/common/tbbr/nxp_rotpk.S21
-rw-r--r--plat/nxp/common/tbbr/tbbr.mk162
-rw-r--r--plat/nxp/common/tbbr/x509_tbbr.c105
-rw-r--r--plat/nxp/common/warm_reset/plat_warm_reset.c121
-rw-r--r--plat/nxp/common/warm_reset/plat_warm_rst.h28
-rw-r--r--plat/nxp/common/warm_reset/warm_reset.mk20
-rw-r--r--plat/nxp/soc-ls1028a/aarch64/ls1028a.S1387
-rw-r--r--plat/nxp/soc-ls1028a/aarch64/ls1028a_helpers.S70
-rw-r--r--plat/nxp/soc-ls1028a/include/soc.h149
-rw-r--r--plat/nxp/soc-ls1028a/ls1028ardb/ddr_init.c185
-rw-r--r--plat/nxp/soc-ls1028a/ls1028ardb/plat_def.h76
-rw-r--r--plat/nxp/soc-ls1028a/ls1028ardb/platform.c28
-rw-r--r--plat/nxp/soc-ls1028a/ls1028ardb/platform.mk33
-rw-r--r--plat/nxp/soc-ls1028a/ls1028ardb/platform_def.h13
-rw-r--r--plat/nxp/soc-ls1028a/ls1028ardb/policy.h16
-rw-r--r--plat/nxp/soc-ls1028a/soc.c432
-rw-r--r--plat/nxp/soc-ls1028a/soc.def97
-rw-r--r--plat/nxp/soc-ls1028a/soc.mk113
-rw-r--r--plat/nxp/soc-ls1043a/aarch64/ls1043a.S1637
-rw-r--r--plat/nxp/soc-ls1043a/aarch64/ls1043a_helpers.S70
-rw-r--r--plat/nxp/soc-ls1043a/include/ns_access.h175
-rw-r--r--plat/nxp/soc-ls1043a/include/soc.h234
-rw-r--r--plat/nxp/soc-ls1043a/ls1043ardb/ddr_init.c163
-rw-r--r--plat/nxp/soc-ls1043a/ls1043ardb/plat_def.h79
-rw-r--r--plat/nxp/soc-ls1043a/ls1043ardb/platform.c28
-rw-r--r--plat/nxp/soc-ls1043a/ls1043ardb/platform.mk40
-rw-r--r--plat/nxp/soc-ls1043a/ls1043ardb/platform_def.h13
-rw-r--r--plat/nxp/soc-ls1043a/ls1043ardb/policy.h16
-rw-r--r--plat/nxp/soc-ls1043a/soc.c435
-rw-r--r--plat/nxp/soc-ls1043a/soc.def107
-rw-r--r--plat/nxp/soc-ls1043a/soc.mk114
-rw-r--r--plat/nxp/soc-ls1046a/aarch64/ls1046a.S937
-rw-r--r--plat/nxp/soc-ls1046a/aarch64/ls1046a_helpers.S92
-rw-r--r--plat/nxp/soc-ls1046a/include/ns_access.h174
-rw-r--r--plat/nxp/soc-ls1046a/include/soc.h125
-rw-r--r--plat/nxp/soc-ls1046a/ls1046afrwy/ddr_init.c177
-rw-r--r--plat/nxp/soc-ls1046a/ls1046afrwy/plat_def.h79
-rw-r--r--plat/nxp/soc-ls1046a/ls1046afrwy/platform.c28
-rw-r--r--plat/nxp/soc-ls1046a/ls1046afrwy/platform.mk39
-rw-r--r--plat/nxp/soc-ls1046a/ls1046afrwy/platform_def.h13
-rw-r--r--plat/nxp/soc-ls1046a/ls1046afrwy/policy.h16
-rw-r--r--plat/nxp/soc-ls1046a/ls1046aqds/ddr_init.c91
-rw-r--r--plat/nxp/soc-ls1046a/ls1046aqds/plat_def.h79
-rw-r--r--plat/nxp/soc-ls1046a/ls1046aqds/platform.c28
-rw-r--r--plat/nxp/soc-ls1046a/ls1046aqds/platform.mk39
-rw-r--r--plat/nxp/soc-ls1046a/ls1046aqds/platform_def.h13
-rw-r--r--plat/nxp/soc-ls1046a/ls1046aqds/policy.h16
-rw-r--r--plat/nxp/soc-ls1046a/ls1046ardb/ddr_init.c267
-rw-r--r--plat/nxp/soc-ls1046a/ls1046ardb/plat_def.h79
-rw-r--r--plat/nxp/soc-ls1046a/ls1046ardb/platform.c28
-rw-r--r--plat/nxp/soc-ls1046a/ls1046ardb/platform.mk38
-rw-r--r--plat/nxp/soc-ls1046a/ls1046ardb/platform_def.h13
-rw-r--r--plat/nxp/soc-ls1046a/ls1046ardb/policy.h16
-rw-r--r--plat/nxp/soc-ls1046a/soc.c395
-rw-r--r--plat/nxp/soc-ls1046a/soc.def107
-rw-r--r--plat/nxp/soc-ls1046a/soc.mk114
-rw-r--r--plat/nxp/soc-ls1088a/aarch64/ls1088a.S1817
-rw-r--r--plat/nxp/soc-ls1088a/aarch64/ls1088a_helpers.S69
-rw-r--r--plat/nxp/soc-ls1088a/include/soc.h229
-rw-r--r--plat/nxp/soc-ls1088a/ls1088aqds/ddr_init.c84
-rw-r--r--plat/nxp/soc-ls1088a/ls1088aqds/plat_def.h81
-rw-r--r--plat/nxp/soc-ls1088a/ls1088aqds/platform.c28
-rw-r--r--plat/nxp/soc-ls1088a/ls1088aqds/platform.mk31
-rw-r--r--plat/nxp/soc-ls1088a/ls1088aqds/platform_def.h13
-rw-r--r--plat/nxp/soc-ls1088a/ls1088aqds/policy.h16
-rw-r--r--plat/nxp/soc-ls1088a/ls1088ardb/ddr_init.c86
-rw-r--r--plat/nxp/soc-ls1088a/ls1088ardb/plat_def.h80
-rw-r--r--plat/nxp/soc-ls1088a/ls1088ardb/platform.c28
-rw-r--r--plat/nxp/soc-ls1088a/ls1088ardb/platform.mk30
-rw-r--r--plat/nxp/soc-ls1088a/ls1088ardb/platform_def.h13
-rw-r--r--plat/nxp/soc-ls1088a/ls1088ardb/policy.h15
-rw-r--r--plat/nxp/soc-ls1088a/soc.c397
-rw-r--r--plat/nxp/soc-ls1088a/soc.def87
-rw-r--r--plat/nxp/soc-ls1088a/soc.mk110
-rw-r--r--plat/nxp/soc-lx2160a/aarch64/lx2160a.S1816
-rw-r--r--plat/nxp/soc-lx2160a/aarch64/lx2160a_helpers.S77
-rw-r--r--plat/nxp/soc-lx2160a/aarch64/lx2160a_warm_rst.S229
-rw-r--r--plat/nxp/soc-lx2160a/ddr_fip.mk97
-rw-r--r--plat/nxp/soc-lx2160a/ddr_sb.mk43
-rw-r--r--plat/nxp/soc-lx2160a/ddr_tbbr.mk95
-rw-r--r--plat/nxp/soc-lx2160a/include/soc.h141
-rw-r--r--plat/nxp/soc-lx2160a/lx2160aqds/ddr_init.c355
-rw-r--r--plat/nxp/soc-lx2160a/lx2160aqds/plat_def.h105
-rw-r--r--plat/nxp/soc-lx2160a/lx2160aqds/platform.c29
-rw-r--r--plat/nxp/soc-lx2160a/lx2160aqds/platform.mk51
-rw-r--r--plat/nxp/soc-lx2160a/lx2160aqds/platform_def.h14
-rw-r--r--plat/nxp/soc-lx2160a/lx2160aqds/policy.h38
-rw-r--r--plat/nxp/soc-lx2160a/lx2160ardb/ddr_init.c212
-rw-r--r--plat/nxp/soc-lx2160a/lx2160ardb/plat_def.h105
-rw-r--r--plat/nxp/soc-lx2160a/lx2160ardb/platform.c29
-rw-r--r--plat/nxp/soc-lx2160a/lx2160ardb/platform.mk51
-rw-r--r--plat/nxp/soc-lx2160a/lx2160ardb/platform_def.h14
-rw-r--r--plat/nxp/soc-lx2160a/lx2160ardb/policy.h38
-rw-r--r--plat/nxp/soc-lx2160a/lx2162aqds/ddr_init.c354
-rw-r--r--plat/nxp/soc-lx2160a/lx2162aqds/plat_def.h105
-rw-r--r--plat/nxp/soc-lx2160a/lx2162aqds/platform.c29
-rw-r--r--plat/nxp/soc-lx2160a/lx2162aqds/platform.mk52
-rw-r--r--plat/nxp/soc-lx2160a/lx2162aqds/platform_def.h14
-rw-r--r--plat/nxp/soc-lx2160a/lx2162aqds/policy.h38
-rw-r--r--plat/nxp/soc-lx2160a/soc.c509
-rw-r--r--plat/nxp/soc-lx2160a/soc.def116
-rw-r--r--plat/nxp/soc-lx2160a/soc.mk174
-rw-r--r--plat/qemu/common/aarch32/plat_helpers.S139
-rw-r--r--plat/qemu/common/aarch64/plat_helpers.S136
-rw-r--r--plat/qemu/common/include/plat_macros.S26
-rw-r--r--plat/qemu/common/qemu_bl1_setup.c62
-rw-r--r--plat/qemu/common/qemu_bl2_mem_params_desc.c150
-rw-r--r--plat/qemu/common/qemu_bl2_setup.c247
-rw-r--r--plat/qemu/common/qemu_bl31_setup.c113
-rw-r--r--plat/qemu/common/qemu_common.c169
-rw-r--r--plat/qemu/common/qemu_console.c23
-rw-r--r--plat/qemu/common/qemu_gicv2.c44
-rw-r--r--plat/qemu/common/qemu_gicv3.c52
-rw-r--r--plat/qemu/common/qemu_image_load.c34
-rw-r--r--plat/qemu/common/qemu_io_storage.c449
-rw-r--r--plat/qemu/common/qemu_pm.c257
-rw-r--r--plat/qemu/common/qemu_private.h51
-rw-r--r--plat/qemu/common/qemu_rotpk.S15
-rw-r--r--plat/qemu/common/qemu_spm.c147
-rw-r--r--plat/qemu/common/qemu_spmd_manifest.c31
-rw-r--r--plat/qemu/common/qemu_stack_protector.c32
-rw-r--r--plat/qemu/common/qemu_trusted_boot.c31
-rw-r--r--plat/qemu/common/sp_min/sp_min-qemu.mk22
-rw-r--r--plat/qemu/common/sp_min/sp_min_setup.c147
-rw-r--r--plat/qemu/common/topology.c57
-rw-r--r--plat/qemu/qemu/include/platform_def.h278
-rw-r--r--plat/qemu/qemu/platform.mk266
-rw-r--r--plat/qemu/qemu/qemu_bl1_measured_boot.c28
-rw-r--r--plat/qemu/qemu/qemu_common_measured_boot.c34
-rw-r--r--plat/qemu/qemu/qemu_helpers.c216
-rw-r--r--plat/qemu/qemu/qemu_measured_boot.c103
-rw-r--r--plat/qemu/qemu_sbsa/include/platform_def.h378
-rw-r--r--plat/qemu/qemu_sbsa/platform.mk127
-rw-r--r--plat/qemu/qemu_sbsa/sbsa_pm.c237
-rw-r--r--plat/qemu/qemu_sbsa/sbsa_private.h17
-rw-r--r--plat/qemu/qemu_sbsa/sbsa_topology.c63
-rw-r--r--plat/qti/common/inc/aarch64/plat_macros.S106
-rw-r--r--plat/qti/common/inc/qti_board_def.h37
-rw-r--r--plat/qti/common/inc/qti_cpu.h22
-rw-r--r--plat/qti/common/inc/qti_interrupt_svc.h12
-rw-r--r--plat/qti/common/inc/qti_plat.h62
-rw-r--r--plat/qti/common/inc/qti_rng.h14
-rw-r--r--plat/qti/common/inc/qti_uart_console.h19
-rw-r--r--plat/qti/common/inc/spmi_arb.h23
-rw-r--r--plat/qti/common/src/aarch64/qti_helpers.S81
-rw-r--r--plat/qti/common/src/aarch64/qti_kryo4_gold.S77
-rw-r--r--plat/qti/common/src/aarch64/qti_kryo4_silver.S71
-rw-r--r--plat/qti/common/src/aarch64/qti_kryo6_gold.S75
-rw-r--r--plat/qti/common/src/aarch64/qti_kryo6_silver.S71
-rw-r--r--plat/qti/common/src/aarch64/qti_uart_console.S102
-rw-r--r--plat/qti/common/src/pm_ps_hold.c41
-rw-r--r--plat/qti/common/src/qti_bl31_setup.c150
-rw-r--r--plat/qti/common/src/qti_common.c203
-rw-r--r--plat/qti/common/src/qti_gic_v3.c169
-rw-r--r--plat/qti/common/src/qti_interrupt_svc.c66
-rw-r--r--plat/qti/common/src/qti_pm.c287
-rw-r--r--plat/qti/common/src/qti_rng.c53
-rw-r--r--plat/qti/common/src/qti_stack_protector.c26
-rw-r--r--plat/qti/common/src/qti_syscall.c386
-rw-r--r--plat/qti/common/src/qti_topology.c48
-rw-r--r--plat/qti/common/src/spmi_arb.c113
-rw-r--r--plat/qti/msm8916/aarch64/msm8916_helpers.S164
-rw-r--r--plat/qti/msm8916/aarch64/uartdm_console.S154
-rw-r--r--plat/qti/msm8916/include/msm8916_mmap.h41
-rw-r--r--plat/qti/msm8916/include/plat_macros.S27
-rw-r--r--plat/qti/msm8916/include/platform_def.h57
-rw-r--r--plat/qti/msm8916/include/uartdm_console.h12
-rw-r--r--plat/qti/msm8916/msm8916_bl31_setup.c219
-rw-r--r--plat/qti/msm8916/msm8916_cpu_boot.c66
-rw-r--r--plat/qti/msm8916/msm8916_gicv2.c59
-rw-r--r--plat/qti/msm8916/msm8916_gicv2.h12
-rw-r--r--plat/qti/msm8916/msm8916_pm.c59
-rw-r--r--plat/qti/msm8916/msm8916_pm.h12
-rw-r--r--plat/qti/msm8916/msm8916_topology.c35
-rw-r--r--plat/qti/msm8916/platform.mk62
-rw-r--r--plat/qti/qtiseclib/inc/qtiseclib_cb_interface.h59
-rw-r--r--plat/qti/qtiseclib/inc/qtiseclib_defs.h104
-rw-r--r--plat/qti/qtiseclib/inc/qtiseclib_interface.h99
-rw-r--r--plat/qti/qtiseclib/inc/sc7180/qtiseclib_defs_plat.h35
-rw-r--r--plat/qti/qtiseclib/inc/sc7280/qtiseclib_defs_plat.h45
-rw-r--r--plat/qti/qtiseclib/src/qtiseclib_cb_interface.c211
-rw-r--r--plat/qti/qtiseclib/src/qtiseclib_interface_stub.c129
-rw-r--r--plat/qti/sc7180/inc/platform_def.h198
-rw-r--r--plat/qti/sc7180/inc/qti_map_chipinfo.h28
-rw-r--r--plat/qti/sc7180/inc/qti_rng_io.h15
-rw-r--r--plat/qti/sc7180/inc/qti_secure_io_cfg.h30
-rw-r--r--plat/qti/sc7180/platform.mk128
-rw-r--r--plat/qti/sc7280/inc/platform_def.h198
-rw-r--r--plat/qti/sc7280/inc/qti_map_chipinfo.h34
-rw-r--r--plat/qti/sc7280/inc/qti_rng_io.h15
-rw-r--r--plat/qti/sc7280/inc/qti_secure_io_cfg.h30
-rw-r--r--plat/qti/sc7280/platform.mk130
-rw-r--r--plat/renesas/common/aarch64/plat_helpers.S396
-rw-r--r--plat/renesas/common/aarch64/platform_common.c271
-rw-r--r--plat/renesas/common/bl2_cpg_init.c408
-rw-r--r--plat/renesas/common/bl2_interrupt_error.c109
-rw-r--r--plat/renesas/common/bl2_plat_mem_params_desc.c88
-rw-r--r--plat/renesas/common/bl2_secure_setting.c362
-rw-r--r--plat/renesas/common/bl31_plat_setup.c133
-rw-r--r--plat/renesas/common/common.mk143
-rw-r--r--plat/renesas/common/include/plat.ld.S36
-rw-r--r--plat/renesas/common/include/plat_macros.S88
-rw-r--r--plat/renesas/common/include/platform_def.h200
-rw-r--r--plat/renesas/common/include/rcar_def.h313
-rw-r--r--plat/renesas/common/include/rcar_private.h108
-rw-r--r--plat/renesas/common/include/rcar_version.h17
-rw-r--r--plat/renesas/common/include/registers/axi_registers.h246
-rw-r--r--plat/renesas/common/include/registers/cpg_registers.h142
-rw-r--r--plat/renesas/common/include/registers/lifec_registers.h144
-rw-r--r--plat/renesas/common/plat_image_load.c38
-rw-r--r--plat/renesas/common/plat_pm.c321
-rw-r--r--plat/renesas/common/plat_storage.c417
-rw-r--r--plat/renesas/common/plat_topology.c47
-rw-r--r--plat/renesas/common/rcar_common.c99
-rw-r--r--plat/renesas/rcar/bl2_plat_setup.c1199
-rw-r--r--plat/renesas/rcar/platform.mk371
-rw-r--r--plat/renesas/rzg/bl2_plat_setup.c1020
-rw-r--r--plat/renesas/rzg/platform.mk274
-rw-r--r--plat/rockchip/common/aarch32/plat_helpers.S164
-rw-r--r--plat/rockchip/common/aarch32/platform_common.c57
-rw-r--r--plat/rockchip/common/aarch32/pmu_sram_cpus_on.S56
-rw-r--r--plat/rockchip/common/aarch64/plat_helpers.S163
-rw-r--r--plat/rockchip/common/aarch64/platform_common.c87
-rw-r--r--plat/rockchip/common/aarch64/pmu_sram_cpus_on.S52
-rw-r--r--plat/rockchip/common/bl31_plat_setup.c102
-rw-r--r--plat/rockchip/common/drivers/parameter/ddr_parameter.c135
-rw-r--r--plat/rockchip/common/drivers/parameter/ddr_parameter.h44
-rw-r--r--plat/rockchip/common/drivers/pmu/pmu_com.h122
-rw-r--r--plat/rockchip/common/include/plat_macros.S118
-rw-r--r--plat/rockchip/common/include/plat_params.h14
-rw-r--r--plat/rockchip/common/include/plat_private.h155
-rw-r--r--plat/rockchip/common/include/rockchip_sip_svc.h27
-rw-r--r--plat/rockchip/common/params_setup.c256
-rw-r--r--plat/rockchip/common/plat_pm.c413
-rw-r--r--plat/rockchip/common/plat_topology.c39
-rw-r--r--plat/rockchip/common/pmusram/cpus_on_fixed_addr.S48
-rw-r--r--plat/rockchip/common/pmusram/cpus_on_fixed_addr.h55
-rw-r--r--plat/rockchip/common/rockchip_gicv2.c81
-rw-r--r--plat/rockchip/common/rockchip_gicv3.c95
-rw-r--r--plat/rockchip/common/rockchip_sip_svc.c84
-rw-r--r--plat/rockchip/common/rockchip_stack_protector.c24
-rw-r--r--plat/rockchip/common/sp_min_plat_setup.c103
-rw-r--r--plat/rockchip/px30/drivers/pmu/plat_pmu_macros.S21
-rw-r--r--plat/rockchip/px30/drivers/pmu/pmu.c1071
-rw-r--r--plat/rockchip/px30/drivers/pmu/pmu.h331
-rw-r--r--plat/rockchip/px30/drivers/secure/secure.c103
-rw-r--r--plat/rockchip/px30/drivers/secure/secure.h65
-rw-r--r--plat/rockchip/px30/drivers/soc/soc.c134
-rw-r--r--plat/rockchip/px30/drivers/soc/soc.h118
-rw-r--r--plat/rockchip/px30/include/plat.ld.S38
-rw-r--r--plat/rockchip/px30/include/plat_sip_calls.h12
-rw-r--r--plat/rockchip/px30/include/platform_def.h118
-rw-r--r--plat/rockchip/px30/plat_sip_calls.c25
-rw-r--r--plat/rockchip/px30/platform.mk73
-rw-r--r--plat/rockchip/px30/px30_def.h176
-rw-r--r--plat/rockchip/rk3288/drivers/pmu/plat_pmu_macros.S17
-rw-r--r--plat/rockchip/rk3288/drivers/pmu/pmu.c391
-rw-r--r--plat/rockchip/rk3288/drivers/pmu/pmu.h151
-rw-r--r--plat/rockchip/rk3288/drivers/secure/secure.c165
-rw-r--r--plat/rockchip/rk3288/drivers/secure/secure.h102
-rw-r--r--plat/rockchip/rk3288/drivers/soc/soc.c223
-rw-r--r--plat/rockchip/rk3288/drivers/soc/soc.h110
-rw-r--r--plat/rockchip/rk3288/include/plat_sip_calls.h12
-rw-r--r--plat/rockchip/rk3288/include/plat_sp_min.ld.S72
-rw-r--r--plat/rockchip/rk3288/include/platform_def.h101
-rw-r--r--plat/rockchip/rk3288/include/shared/bl32_param.h26
-rw-r--r--plat/rockchip/rk3288/plat_sip_calls.c25
-rw-r--r--plat/rockchip/rk3288/platform.mk69
-rw-r--r--plat/rockchip/rk3288/rk3288_def.h127
-rw-r--r--plat/rockchip/rk3288/sp_min/sp_min-rk3288.mk8
-rw-r--r--plat/rockchip/rk3328/drivers/pmu/plat_pmu_macros.S21
-rw-r--r--plat/rockchip/rk3328/drivers/pmu/pmu.c667
-rw-r--r--plat/rockchip/rk3328/drivers/pmu/pmu.h129
-rw-r--r--plat/rockchip/rk3328/drivers/soc/soc.c158
-rw-r--r--plat/rockchip/rk3328/drivers/soc/soc.h111
-rw-r--r--plat/rockchip/rk3328/include/plat.ld.S37
-rw-r--r--plat/rockchip/rk3328/include/platform_def.h117
-rw-r--r--plat/rockchip/rk3328/platform.mk75
-rw-r--r--plat/rockchip/rk3328/rk3328_def.h151
-rw-r--r--plat/rockchip/rk3368/drivers/ddr/ddr_rk3368.c482
-rw-r--r--plat/rockchip/rk3368/drivers/ddr/ddr_rk3368.h247
-rw-r--r--plat/rockchip/rk3368/drivers/pmu/plat_pmu_macros.S17
-rw-r--r--plat/rockchip/rk3368/drivers/pmu/pmu.c373
-rw-r--r--plat/rockchip/rk3368/drivers/pmu/pmu.h207
-rw-r--r--plat/rockchip/rk3368/drivers/soc/soc.c209
-rw-r--r--plat/rockchip/rk3368/drivers/soc/soc.h141
-rw-r--r--plat/rockchip/rk3368/include/plat.ld.S37
-rw-r--r--plat/rockchip/rk3368/include/plat_sip_calls.h12
-rw-r--r--plat/rockchip/rk3368/include/platform_def.h120
-rw-r--r--plat/rockchip/rk3368/plat_sip_calls.c25
-rw-r--r--plat/rockchip/rk3368/platform.mk67
-rw-r--r--plat/rockchip/rk3368/rk3368_def.h116
-rw-r--r--plat/rockchip/rk3399/drivers/dp/cdn_dp.c70
-rw-r--r--plat/rockchip/rk3399/drivers/dp/cdn_dp.h49
-rw-r--r--plat/rockchip/rk3399/drivers/dram/dfs.c2114
-rw-r--r--plat/rockchip/rk3399/drivers/dram/dfs.h50
-rw-r--r--plat/rockchip/rk3399/drivers/dram/dram.c53
-rw-r--r--plat/rockchip/rk3399/drivers/dram/dram.h156
-rw-r--r--plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c1324
-rw-r--r--plat/rockchip/rk3399/drivers/dram/dram_spec_timing.h507
-rw-r--r--plat/rockchip/rk3399/drivers/dram/suspend.c852
-rw-r--r--plat/rockchip/rk3399/drivers/dram/suspend.h28
-rw-r--r--plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c400
-rw-r--r--plat/rockchip/rk3399/drivers/m0/Makefile125
-rw-r--r--plat/rockchip/rk3399/drivers/m0/include/addressmap.h15
-rw-r--r--plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h32
-rw-r--r--plat/rockchip/rk3399/drivers/m0/src/dram.c84
-rw-r--r--plat/rockchip/rk3399/drivers/m0/src/rk3399m0.ld.S26
-rw-r--r--plat/rockchip/rk3399/drivers/m0/src/startup.c92
-rw-r--r--plat/rockchip/rk3399/drivers/m0/src/stopwatch.c74
-rw-r--r--plat/rockchip/rk3399/drivers/m0/src/suspend.c62
-rw-r--r--plat/rockchip/rk3399/drivers/pmu/m0_ctl.c102
-rw-r--r--plat/rockchip/rk3399/drivers/pmu/m0_ctl.h29
-rw-r--r--plat/rockchip/rk3399/drivers/pmu/plat_pmu_macros.S136
-rw-r--r--plat/rockchip/rk3399/drivers/pmu/pmu.c1626
-rw-r--r--plat/rockchip/rk3399/drivers/pmu/pmu.h141
-rw-r--r--plat/rockchip/rk3399/drivers/pmu/pmu_fw.c22
-rw-r--r--plat/rockchip/rk3399/drivers/pwm/pwm.c123
-rw-r--r--plat/rockchip/rk3399/drivers/pwm/pwm.h13
-rw-r--r--plat/rockchip/rk3399/drivers/secure/secure.c167
-rw-r--r--plat/rockchip/rk3399/drivers/secure/secure.h105
-rw-r--r--plat/rockchip/rk3399/drivers/soc/soc.c362
-rw-r--r--plat/rockchip/rk3399/drivers/soc/soc.h289
-rw-r--r--plat/rockchip/rk3399/include/addressmap.h19
-rw-r--r--plat/rockchip/rk3399/include/plat.ld.S98
-rw-r--r--plat/rockchip/rk3399/include/plat_sip_calls.h12
-rw-r--r--plat/rockchip/rk3399/include/platform_def.h104
-rw-r--r--plat/rockchip/rk3399/include/shared/addressmap_shared.h104
-rw-r--r--plat/rockchip/rk3399/include/shared/bl31_param.h26
-rw-r--r--plat/rockchip/rk3399/include/shared/dram_regs.h100
-rw-r--r--plat/rockchip/rk3399/include/shared/m0_param.h25
-rw-r--r--plat/rockchip/rk3399/include/shared/misc_regs.h27
-rw-r--r--plat/rockchip/rk3399/include/shared/pmu_bits.h697
-rw-r--r--plat/rockchip/rk3399/include/shared/pmu_regs.h148
-rw-r--r--plat/rockchip/rk3399/plat_sip_calls.c78
-rw-r--r--plat/rockchip/rk3399/platform.mk113
-rw-r--r--plat/rockchip/rk3399/rk3399_def.h65
-rw-r--r--plat/rpi/common/aarch64/plat_helpers.S244
-rw-r--r--plat/rpi/common/include/rpi_shared.h41
-rw-r--r--plat/rpi/common/rpi3_common.c247
-rw-r--r--plat/rpi/common/rpi3_image_load.c36
-rw-r--r--plat/rpi/common/rpi3_io_storage.c271
-rw-r--r--plat/rpi/common/rpi3_pm.c274
-rw-r--r--plat/rpi/common/rpi3_rotpk.S15
-rw-r--r--plat/rpi/common/rpi3_stack_protector.c29
-rw-r--r--plat/rpi/common/rpi3_topology.c58
-rw-r--r--plat/rpi/common/rpi3_trusted_boot.c36
-rw-r--r--plat/rpi/rpi3/aarch64/rpi3_bl2_mem_params_desc.c136
-rw-r--r--plat/rpi/rpi3/include/plat_macros.S20
-rw-r--r--plat/rpi/rpi3/include/platform_def.h263
-rw-r--r--plat/rpi/rpi3/include/rpi_hw.h114
-rw-r--r--plat/rpi/rpi3/platform.mk221
-rw-r--r--plat/rpi/rpi3/rpi3_bl1_setup.c101
-rw-r--r--plat/rpi/rpi3/rpi3_bl2_setup.c144
-rw-r--r--plat/rpi/rpi3/rpi3_bl31_setup.c226
-rw-r--r--plat/rpi/rpi3/rpi_mbox_board.c56
-rw-r--r--plat/rpi/rpi4/aarch64/armstub8_header.S37
-rw-r--r--plat/rpi/rpi4/include/plat.ld.S23
-rw-r--r--plat/rpi/rpi4/include/plat_macros.S20
-rw-r--r--plat/rpi/rpi4/include/platform_def.h140
-rw-r--r--plat/rpi/rpi4/include/rpi_hw.h114
-rw-r--r--plat/rpi/rpi4/platform.mk116
-rw-r--r--plat/rpi/rpi4/rpi4_bl31_setup.c304
-rw-r--r--plat/rpi/rpi4/rpi4_pci_svc.c215
-rw-r--r--plat/socionext/synquacer/drivers/mhu/sq_mhu.c98
-rw-r--r--plat/socionext/synquacer/drivers/mhu/sq_mhu.h19
-rw-r--r--plat/socionext/synquacer/drivers/scp/sq_scmi.c244
-rw-r--r--plat/socionext/synquacer/drivers/scp/sq_scp.c21
-rw-r--r--plat/socionext/synquacer/drivers/scpi/sq_scpi.c219
-rw-r--r--plat/socionext/synquacer/drivers/scpi/sq_scpi.h83
-rw-r--r--plat/socionext/synquacer/include/plat.ld.S31
-rw-r--r--plat/socionext/synquacer/include/plat_macros.S16
-rw-r--r--plat/socionext/synquacer/include/platform_def.h207
-rw-r--r--plat/socionext/synquacer/include/sq_common.h56
-rw-r--r--plat/socionext/synquacer/platform.mk117
-rw-r--r--plat/socionext/synquacer/sq_bl2_setup.c84
-rw-r--r--plat/socionext/synquacer/sq_bl31_setup.c247
-rw-r--r--plat/socionext/synquacer/sq_ccn.c45
-rw-r--r--plat/socionext/synquacer/sq_gicv3.c94
-rw-r--r--plat/socionext/synquacer/sq_helpers.S115
-rw-r--r--plat/socionext/synquacer/sq_image_desc.c76
-rw-r--r--plat/socionext/synquacer/sq_io_storage.c246
-rw-r--r--plat/socionext/synquacer/sq_psci.c215
-rw-r--r--plat/socionext/synquacer/sq_rotpk.S16
-rw-r--r--plat/socionext/synquacer/sq_spm.c75
-rw-r--r--plat/socionext/synquacer/sq_tbbr.c40
-rw-r--r--plat/socionext/synquacer/sq_topology.c40
-rw-r--r--plat/socionext/synquacer/sq_xlat_setup.c56
-rw-r--r--plat/socionext/uniphier/include/plat_macros.S13
-rw-r--r--plat/socionext/uniphier/include/platform_def.h76
-rw-r--r--plat/socionext/uniphier/platform.mk140
-rw-r--r--plat/socionext/uniphier/tsp/tsp-uniphier.mk9
-rw-r--r--plat/socionext/uniphier/tsp/uniphier_tsp_setup.c34
-rw-r--r--plat/socionext/uniphier/uniphier.h76
-rw-r--r--plat/socionext/uniphier/uniphier_bl2_setup.c166
-rw-r--r--plat/socionext/uniphier/uniphier_bl31_setup.c89
-rw-r--r--plat/socionext/uniphier/uniphier_boot_device.c189
-rw-r--r--plat/socionext/uniphier/uniphier_cci.c81
-rw-r--r--plat/socionext/uniphier/uniphier_console.S65
-rw-r--r--plat/socionext/uniphier/uniphier_console.h25
-rw-r--r--plat/socionext/uniphier/uniphier_console_setup.c92
-rw-r--r--plat/socionext/uniphier/uniphier_emmc.c308
-rw-r--r--plat/socionext/uniphier/uniphier_gicv3.c116
-rw-r--r--plat/socionext/uniphier/uniphier_helpers.S34
-rw-r--r--plat/socionext/uniphier/uniphier_image_desc.c119
-rw-r--r--plat/socionext/uniphier/uniphier_io_storage.c373
-rw-r--r--plat/socionext/uniphier/uniphier_nand.c283
-rw-r--r--plat/socionext/uniphier/uniphier_psci.c167
-rw-r--r--plat/socionext/uniphier/uniphier_rotpk.S16
-rw-r--r--plat/socionext/uniphier/uniphier_scp.c107
-rw-r--r--plat/socionext/uniphier/uniphier_smp.S29
-rw-r--r--plat/socionext/uniphier/uniphier_soc_info.c57
-rw-r--r--plat/socionext/uniphier/uniphier_syscnt.c12
-rw-r--r--plat/socionext/uniphier/uniphier_tbbr.c40
-rw-r--r--plat/socionext/uniphier/uniphier_topology.c40
-rw-r--r--plat/socionext/uniphier/uniphier_usb.c183
-rw-r--r--plat/socionext/uniphier/uniphier_xlat_setup.c81
-rw-r--r--plat/st/common/bl2_io_storage.c731
-rw-r--r--plat/st/common/include/stm32cubeprogrammer.h29
-rw-r--r--plat/st/common/include/stm32mp_common.h129
-rw-r--r--plat/st/common/include/stm32mp_dt.h46
-rw-r--r--plat/st/common/include/stm32mp_efi.h15
-rw-r--r--plat/st/common/include/stm32mp_fconf_getter.h31
-rw-r--r--plat/st/common/include/stm32mp_io_storage.h27
-rw-r--r--plat/st/common/include/stm32mp_shared_resources.h58
-rw-r--r--plat/st/common/include/usb_dfu.h80
-rw-r--r--plat/st/common/stm32cubeprogrammer_uart.c520
-rw-r--r--plat/st/common/stm32cubeprogrammer_usb.c197
-rw-r--r--plat/st/common/stm32mp_common.c279
-rw-r--r--plat/st/common/stm32mp_crypto_lib.c661
-rw-r--r--plat/st/common/stm32mp_dt.c429
-rw-r--r--plat/st/common/stm32mp_fconf_io.c181
-rw-r--r--plat/st/common/stm32mp_trusted_boot.c204
-rw-r--r--plat/st/common/usb_dfu.c538
-rw-r--r--plat/st/stm32mp1/bl2_plat_setup.c562
-rw-r--r--plat/st/stm32mp1/cert_create_tbbr.mk19
-rw-r--r--plat/st/stm32mp1/include/boot_api.h409
-rw-r--r--plat/st/stm32mp1/include/plat_def_fip_uuid.h14
-rw-r--r--plat/st/stm32mp1/include/plat_tbbr_img_def.h40
-rw-r--r--plat/st/stm32mp1/include/platform_def.h218
-rw-r--r--plat/st/stm32mp1/include/stm32mp1_dbgmcu.h16
-rw-r--r--plat/st/stm32mp1/include/stm32mp1_mbedtls_config.h119
-rw-r--r--plat/st/stm32mp1/include/stm32mp1_private.h38
-rw-r--r--plat/st/stm32mp1/include/stm32mp1_shared_resources.h38
-rw-r--r--plat/st/stm32mp1/include/stm32mp1_smc.h67
-rw-r--r--plat/st/stm32mp1/include/tbbr/stm32mp1_tbb_cert.h19
-rw-r--r--plat/st/stm32mp1/plat_bl2_mem_params_desc.c134
-rw-r--r--plat/st/stm32mp1/plat_def_uuid_config.c18
-rw-r--r--plat/st/stm32mp1/plat_fiptool.mk25
-rw-r--r--plat/st/stm32mp1/plat_image_load.c36
-rw-r--r--plat/st/stm32mp1/platform.mk553
-rw-r--r--plat/st/stm32mp1/services/bsec_svc.c60
-rw-r--r--plat/st/stm32mp1/services/bsec_svc.h19
-rw-r--r--plat/st/stm32mp1/services/stm32mp1_svc_setup.c100
-rw-r--r--plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk53
-rw-r--r--plat/st/stm32mp1/sp_min/sp_min_setup.c197
-rw-r--r--plat/st/stm32mp1/stm32mp1.S11
-rw-r--r--plat/st/stm32mp1/stm32mp1.ld.S71
-rw-r--r--plat/st/stm32mp1/stm32mp1_boot_device.c209
-rw-r--r--plat/st/stm32mp1/stm32mp1_dbgmcu.c74
-rw-r--r--plat/st/stm32mp1/stm32mp1_def.h669
-rw-r--r--plat/st/stm32mp1/stm32mp1_fconf_firewall.c128
-rw-r--r--plat/st/stm32mp1/stm32mp1_fip_def.h138
-rw-r--r--plat/st/stm32mp1/stm32mp1_gic.c92
-rw-r--r--plat/st/stm32mp1/stm32mp1_helper.S336
-rw-r--r--plat/st/stm32mp1/stm32mp1_pm.c243
-rw-r--r--plat/st/stm32mp1/stm32mp1_private.c788
-rw-r--r--plat/st/stm32mp1/stm32mp1_scmi.c479
-rw-r--r--plat/st/stm32mp1/stm32mp1_shared_resources.c596
-rw-r--r--plat/st/stm32mp1/stm32mp1_stack_protector.c22
-rw-r--r--plat/st/stm32mp1/stm32mp1_syscfg.c411
-rw-r--r--plat/st/stm32mp1/stm32mp1_tbb_cert.c37
-rw-r--r--plat/st/stm32mp1/stm32mp1_topology.c57
-rw-r--r--plat/st/stm32mp1/stm32mp1_usb_dfu.c423
-rw-r--r--plat/ti/k3/board/generic/board.mk24
-rw-r--r--plat/ti/k3/board/generic/include/board_def.h43
-rw-r--r--plat/ti/k3/board/j784s4/board.mk24
-rw-r--r--plat/ti/k3/board/j784s4/include/board_def.h43
-rw-r--r--plat/ti/k3/board/lite/board.mk24
-rw-r--r--plat/ti/k3/board/lite/include/board_def.h45
-rw-r--r--plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c341
-rw-r--r--plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h82
-rw-r--r--plat/ti/k3/common/drivers/ti_sci/ti_sci.c1739
-rw-r--r--plat/ti/k3/common/drivers/ti_sci/ti_sci.h232
-rw-r--r--plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h734
-rw-r--r--plat/ti/k3/common/k3_bl31_setup.c197
-rw-r--r--plat/ti/k3/common/k3_console.c21
-rw-r--r--plat/ti/k3/common/k3_gicv3.c113
-rw-r--r--plat/ti/k3/common/k3_helpers.S155
-rw-r--r--plat/ti/k3/common/k3_psci.c295
-rw-r--r--plat/ti/k3/common/k3_topology.c46
-rw-r--r--plat/ti/k3/common/plat_common.mk95
-rw-r--r--plat/ti/k3/include/k3_console.h12
-rw-r--r--plat/ti/k3/include/k3_gicv3.h20
-rw-r--r--plat/ti/k3/include/plat_macros.S21
-rw-r--r--plat/ti/k3/include/platform_def.h191
-rw-r--r--plat/ti/k3/platform.mk14
-rw-r--r--plat/xilinx/common/include/ipi.h77
-rw-r--r--plat/xilinx/common/include/plat_startup.h41
-rw-r--r--plat/xilinx/common/include/pm_client.h33
-rw-r--r--plat/xilinx/common/include/pm_common.h62
-rw-r--r--plat/xilinx/common/include/pm_ipi.h36
-rw-r--r--plat/xilinx/common/ipi.c222
-rw-r--r--plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c133
-rw-r--r--plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h39
-rw-r--r--plat/xilinx/common/plat_startup.c260
-rw-r--r--plat/xilinx/common/pm_service/pm_ipi.c300
-rw-r--r--plat/xilinx/versal/aarch64/versal_common.c54
-rw-r--r--plat/xilinx/versal/aarch64/versal_helpers.S73
-rw-r--r--plat/xilinx/versal/bl31_versal_setup.c236
-rw-r--r--plat/xilinx/versal/include/plat_ipi.h55
-rw-r--r--plat/xilinx/versal/include/plat_macros.S110
-rw-r--r--plat/xilinx/versal/include/plat_pm_common.h22
-rw-r--r--plat/xilinx/versal/include/plat_private.h39
-rw-r--r--plat/xilinx/versal/include/platform_def.h104
-rw-r--r--plat/xilinx/versal/include/versal_def.h146
-rw-r--r--plat/xilinx/versal/plat_psci.c249
-rw-r--r--plat/xilinx/versal/plat_topology.c14
-rw-r--r--plat/xilinx/versal/plat_versal.c21
-rw-r--r--plat/xilinx/versal/platform.mk98
-rw-r--r--plat/xilinx/versal/pm_service/pm_api_sys.c589
-rw-r--r--plat/xilinx/versal/pm_service/pm_api_sys.h101
-rw-r--r--plat/xilinx/versal/pm_service/pm_client.c261
-rw-r--r--plat/xilinx/versal/pm_service/pm_defs.h167
-rw-r--r--plat/xilinx/versal/pm_service/pm_node.h192
-rw-r--r--plat/xilinx/versal/pm_service/pm_svc_main.c395
-rw-r--r--plat/xilinx/versal/pm_service/pm_svc_main.h18
-rw-r--r--plat/xilinx/versal/sip_svc_setup.c102
-rw-r--r--plat/xilinx/versal/versal_gicv3.c186
-rw-r--r--plat/xilinx/versal/versal_ipi.c82
-rw-r--r--plat/xilinx/versal_net/aarch64/versal_net_common.c127
-rw-r--r--plat/xilinx/versal_net/aarch64/versal_net_helpers.S110
-rw-r--r--plat/xilinx/versal_net/bl31_versal_net_setup.c223
-rw-r--r--plat/xilinx/versal_net/include/plat_ipi.h58
-rw-r--r--plat/xilinx/versal_net/include/plat_macros.S118
-rw-r--r--plat/xilinx/versal_net/include/plat_pm_common.h25
-rw-r--r--plat/xilinx/versal_net/include/plat_private.h49
-rw-r--r--plat/xilinx/versal_net/include/platform_def.h114
-rw-r--r--plat/xilinx/versal_net/include/versal_net_def.h171
-rw-r--r--plat/xilinx/versal_net/plat_psci.c220
-rw-r--r--plat/xilinx/versal_net/plat_psci_pm.c264
-rw-r--r--plat/xilinx/versal_net/plat_topology.c63
-rw-r--r--plat/xilinx/versal_net/platform.mk102
-rw-r--r--plat/xilinx/versal_net/pm_service/pm_client.c240
-rw-r--r--plat/xilinx/versal_net/sip_svc_setup.c101
-rw-r--r--plat/xilinx/versal_net/versal_net_gicv3.c222
-rw-r--r--plat/xilinx/versal_net/versal_net_ipi.c85
-rw-r--r--plat/xilinx/zynqmp/aarch64/zynqmp_common.c391
-rw-r--r--plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S86
-rw-r--r--plat/xilinx/zynqmp/bl31_zynqmp_setup.c268
-rw-r--r--plat/xilinx/zynqmp/include/plat_ipi.h56
-rw-r--r--plat/xilinx/zynqmp/include/plat_macros.S28
-rw-r--r--plat/xilinx/zynqmp/include/plat_pm_common.h24
-rw-r--r--plat/xilinx/zynqmp/include/plat_private.h33
-rw-r--r--plat/xilinx/zynqmp/include/platform_def.h161
-rw-r--r--plat/xilinx/zynqmp/include/zynqmp_def.h365
-rw-r--r--plat/xilinx/zynqmp/plat_psci.c230
-rw-r--r--plat/xilinx/zynqmp/plat_topology.c13
-rw-r--r--plat/xilinx/zynqmp/plat_zynqmp.c21
-rw-r--r--plat/xilinx/zynqmp/platform.mk143
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_clock.c3048
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_clock.h333
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c767
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h96
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c2112
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h723
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_sys.c1836
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_sys.h197
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_client.c354
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_defs.h363
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_svc_main.c621
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_svc_main.h20
-rw-r--r--plat/xilinx/zynqmp/sip_svc_setup.c105
-rw-r--r--plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk8
-rw-r--r--plat/xilinx/zynqmp/tsp/tsp_plat_setup.c65
-rw-r--r--plat/xilinx/zynqmp/zynqmp_ehf.c24
-rw-r--r--plat/xilinx/zynqmp/zynqmp_ipi.c100
-rw-r--r--plat/xilinx/zynqmp/zynqmp_sdei.c37
-rw-r--r--readme.rst51
-rw-r--r--services/arm_arch_svc/arm_arch_svc_setup.c174
-rw-r--r--services/spd/opteed/opteed.mk18
-rw-r--r--services/spd/opteed/opteed_common.c111
-rw-r--r--services/spd/opteed/opteed_helpers.S79
-rw-r--r--services/spd/opteed/opteed_main.c420
-rw-r--r--services/spd/opteed/opteed_pm.c223
-rw-r--r--services/spd/opteed/opteed_private.h162
-rw-r--r--services/spd/opteed/teesmc_opteed.h123
-rw-r--r--services/spd/opteed/teesmc_opteed_macros.h17
-rw-r--r--services/spd/pncd/pncd.mk24
-rw-r--r--services/spd/pncd/pncd_common.c102
-rw-r--r--services/spd/pncd/pncd_helpers.S79
-rw-r--r--services/spd/pncd/pncd_main.c471
-rw-r--r--services/spd/pncd/pncd_private.h79
-rw-r--r--services/spd/tlkd/tlkd.mk14
-rw-r--r--services/spd/tlkd/tlkd_common.c165
-rw-r--r--services/spd/tlkd/tlkd_helpers.S80
-rw-r--r--services/spd/tlkd/tlkd_main.c546
-rw-r--r--services/spd/tlkd/tlkd_pm.c109
-rw-r--r--services/spd/tlkd/tlkd_private.h124
-rw-r--r--services/spd/trusty/generic-arm64-smcall.c116
-rw-r--r--services/spd/trusty/generic-arm64-smcall.h28
-rw-r--r--services/spd/trusty/sm_err.h22
-rw-r--r--services/spd/trusty/smcall.h82
-rw-r--r--services/spd/trusty/trusty.c541
-rw-r--r--services/spd/trusty/trusty.mk18
-rw-r--r--services/spd/trusty/trusty_helpers.S69
-rw-r--r--services/spd/tspd/tspd.mk46
-rw-r--r--services/spd/tspd/tspd_common.c140
-rw-r--r--services/spd/tspd/tspd_helpers.S79
-rw-r--r--services/spd/tspd/tspd_main.c819
-rw-r--r--services/spd/tspd/tspd_pm.c254
-rw-r--r--services/spd/tspd/tspd_private.h233
-rw-r--r--services/std_svc/drtm/drtm_dma_prot.c263
-rw-r--r--services/std_svc/drtm/drtm_dma_prot.h50
-rw-r--r--services/std_svc/drtm/drtm_main.c839
-rw-r--r--services/std_svc/drtm/drtm_main.h106
-rw-r--r--services/std_svc/drtm/drtm_measurements.c214
-rw-r--r--services/std_svc/drtm/drtm_measurements.h40
-rw-r--r--services/std_svc/drtm/drtm_remediation.c59
-rw-r--r--services/std_svc/drtm/drtm_remediation.h15
-rw-r--r--services/std_svc/drtm/drtm_res_address_map.c88
-rw-r--r--services/std_svc/pci_svc.c113
-rw-r--r--services/std_svc/rmmd/aarch64/rmmd_helpers.S73
-rw-r--r--services/std_svc/rmmd/rmmd.mk19
-rw-r--r--services/std_svc/rmmd/rmmd_attest.c153
-rw-r--r--services/std_svc/rmmd/rmmd_initial_context.h33
-rw-r--r--services/std_svc/rmmd/rmmd_main.c449
-rw-r--r--services/std_svc/rmmd/rmmd_private.h63
-rw-r--r--services/std_svc/rmmd/trp/linker.lds71
-rw-r--r--services/std_svc/rmmd/trp/trp.mk21
-rw-r--r--services/std_svc/rmmd/trp/trp_entry.S121
-rw-r--r--services/std_svc/rmmd/trp/trp_helpers.c58
-rw-r--r--services/std_svc/rmmd/trp/trp_main.c150
-rw-r--r--services/std_svc/rmmd/trp/trp_private.h57
-rw-r--r--services/std_svc/sdei/sdei_dispatch.S26
-rw-r--r--services/std_svc/sdei/sdei_event.c122
-rw-r--r--services/std_svc/sdei/sdei_intr_mgmt.c774
-rw-r--r--services/std_svc/sdei/sdei_main.c1114
-rw-r--r--services/std_svc/sdei/sdei_private.h248
-rw-r--r--services/std_svc/sdei/sdei_state.c150
-rw-r--r--services/std_svc/spm/common/aarch64/spm_helpers.S74
-rw-r--r--services/std_svc/spm/common/include/spm_common.h42
-rw-r--r--services/std_svc/spm/common/spm.mk17
-rw-r--r--services/std_svc/spm/el3_spmc/logical_sp.c107
-rw-r--r--services/std_svc/spm/el3_spmc/spmc.h296
-rw-r--r--services/std_svc/spm/el3_spmc/spmc.mk44
-rw-r--r--services/std_svc/spm/el3_spmc/spmc_main.c1995
-rw-r--r--services/std_svc/spm/el3_spmc/spmc_pm.c283
-rw-r--r--services/std_svc/spm/el3_spmc/spmc_setup.c278
-rw-r--r--services/std_svc/spm/el3_spmc/spmc_shared_mem.c1861
-rw-r--r--services/std_svc/spm/el3_spmc/spmc_shared_mem.h115
-rw-r--r--services/std_svc/spm/spm_mm/aarch64/spm_mm_shim_exceptions.S128
-rw-r--r--services/std_svc/spm/spm_mm/spm_mm.mk34
-rw-r--r--services/std_svc/spm/spm_mm/spm_mm_main.c370
-rw-r--r--services/std_svc/spm/spm_mm/spm_mm_private.h69
-rw-r--r--services/std_svc/spm/spm_mm/spm_mm_setup.c260
-rw-r--r--services/std_svc/spm/spm_mm/spm_mm_shim_private.h26
-rw-r--r--services/std_svc/spm/spm_mm/spm_mm_xlat.c159
-rw-r--r--services/std_svc/spmd/aarch64/spmd_helpers.S73
-rw-r--r--services/std_svc/spmd/spmd.mk26
-rw-r--r--services/std_svc/spmd/spmd_main.c937
-rw-r--r--services/std_svc/spmd/spmd_pm.c156
-rw-r--r--services/std_svc/spmd/spmd_private.h98
-rw-r--r--services/std_svc/std_svc_setup.c238
-rw-r--r--services/std_svc/trng/trng_entropy_pool.c150
-rw-r--r--services/std_svc/trng/trng_entropy_pool.h16
-rw-r--r--services/std_svc/trng/trng_main.c146
-rw-r--r--tools/amlogic/Makefile49
-rw-r--r--tools/amlogic/doimage.c94
-rw-r--r--tools/cert_create/Makefile111
-rw-r--r--tools/cert_create/include/cca/cca_cot.h68
-rw-r--r--tools/cert_create/include/cert.h77
-rw-r--r--tools/cert_create/include/cmd_opt.h33
-rw-r--r--tools/cert_create/include/debug.h59
-rw-r--r--tools/cert_create/include/dualroot/cot.h81
-rw-r--r--tools/cert_create/include/ext.h95
-rw-r--r--tools/cert_create/include/key.h99
-rw-r--r--tools/cert_create/include/sha.h12
-rw-r--r--tools/cert_create/include/tbbr/tbb_cert.h30
-rw-r--r--tools/cert_create/include/tbbr/tbb_ext.h47
-rw-r--r--tools/cert_create/include/tbbr/tbb_key.h25
-rw-r--r--tools/cert_create/src/cca/cot.c439
-rw-r--r--tools/cert_create/src/cca/cot.mk10
-rw-r--r--tools/cert_create/src/cert.c294
-rw-r--r--tools/cert_create/src/cmd_opt.c59
-rw-r--r--tools/cert_create/src/dualroot/cot.c583
-rw-r--r--tools/cert_create/src/dualroot/cot.mk10
-rw-r--r--tools/cert_create/src/ext.c334
-rw-r--r--tools/cert_create/src/key.c318
-rw-r--r--tools/cert_create/src/main.c617
-rw-r--r--tools/cert_create/src/sha.c118
-rw-r--r--tools/cert_create/src/tbbr/tbb_cert.c206
-rw-r--r--tools/cert_create/src/tbbr/tbb_ext.c328
-rw-r--r--tools/cert_create/src/tbbr/tbb_key.c59
-rw-r--r--tools/cert_create/src/tbbr/tbbr.mk29
-rw-r--r--tools/conventional-changelog-tf-a/index.js222
-rw-r--r--tools/conventional-changelog-tf-a/package.json13
-rw-r--r--tools/conventional-changelog-tf-a/templates/commit-section.hbs17
-rw-r--r--tools/conventional-changelog-tf-a/templates/commit.hbs15
-rw-r--r--tools/conventional-changelog-tf-a/templates/footer.hbs0
-rw-r--r--tools/conventional-changelog-tf-a/templates/header.hbs13
-rw-r--r--tools/conventional-changelog-tf-a/templates/note-section.hbs13
-rw-r--r--tools/conventional-changelog-tf-a/templates/note.hbs3
-rw-r--r--tools/conventional-changelog-tf-a/templates/template.hbs9
-rw-r--r--tools/encrypt_fw/Makefile89
-rw-r--r--tools/encrypt_fw/include/cmd_opt.h32
-rw-r--r--tools/encrypt_fw/include/debug.h59
-rw-r--r--tools/encrypt_fw/include/encrypt.h19
-rw-r--r--tools/encrypt_fw/src/cmd_opt.c59
-rw-r--r--tools/encrypt_fw/src/encrypt.c167
-rw-r--r--tools/encrypt_fw/src/main.c224
-rw-r--r--tools/fiptool/Makefile86
-rw-r--r--tools/fiptool/Makefile.msvc37
-rw-r--r--tools/fiptool/fiptool.c1266
-rw-r--r--tools/fiptool/fiptool.h54
-rw-r--r--tools/fiptool/fiptool_platform.h31
-rw-r--r--tools/fiptool/tbbr_config.c194
-rw-r--r--tools/fiptool/tbbr_config.h28
-rw-r--r--tools/fiptool/win_posix.c318
-rw-r--r--tools/fiptool/win_posix.h188
-rw-r--r--tools/marvell/doimage/Makefile48
-rw-r--r--tools/marvell/doimage/doimage.c1764
-rw-r--r--tools/marvell/doimage/doimage.mk15
-rw-r--r--tools/marvell/doimage/secure/aes_key.txt1
-rw-r--r--tools/marvell/doimage/secure/csk_priv_pem0.key27
-rw-r--r--tools/marvell/doimage/secure/csk_priv_pem1.key27
-rw-r--r--tools/marvell/doimage/secure/csk_priv_pem2.key27
-rw-r--r--tools/marvell/doimage/secure/csk_priv_pem3.key27
-rw-r--r--tools/marvell/doimage/secure/kak_priv_pem.key27
-rw-r--r--tools/marvell/doimage/secure/sec_img_7K.cfg29
-rw-r--r--tools/marvell/doimage/secure/sec_img_8K.cfg29
-rwxr-xr-xtools/memory/print_memory_map.py102
-rw-r--r--tools/nxp/cert_create_helper/cert_create_tbbr.mk31
-rw-r--r--tools/nxp/cert_create_helper/include/pdef_tbb_cert.h21
-rw-r--r--tools/nxp/cert_create_helper/include/pdef_tbb_ext.h25
-rw-r--r--tools/nxp/cert_create_helper/include/pdef_tbb_key.h18
-rw-r--r--tools/nxp/cert_create_helper/src/pdef_tbb_cert.c62
-rw-r--r--tools/nxp/cert_create_helper/src/pdef_tbb_ext.c108
-rw-r--r--tools/nxp/cert_create_helper/src/pdef_tbb_key.c18
-rw-r--r--tools/nxp/create_pbl/Makefile61
-rw-r--r--tools/nxp/create_pbl/README65
-rw-r--r--tools/nxp/create_pbl/byte_swap.c113
-rw-r--r--tools/nxp/create_pbl/create_pbl.c998
-rw-r--r--tools/nxp/create_pbl/create_pbl.mk52
-rw-r--r--tools/nxp/create_pbl/pbl_ch2.mk60
-rw-r--r--tools/nxp/create_pbl/pbl_ch3.mk71
-rw-r--r--tools/nxp/plat_fiptool/plat_def_uuid_config.c90
-rw-r--r--tools/nxp/plat_fiptool/plat_fiptool.mk33
-rw-r--r--tools/renesas/rcar_layout_create/makefile121
-rw-r--r--tools/renesas/rcar_layout_create/sa0.c30
-rw-r--r--tools/renesas/rcar_layout_create/sa0.ld.S28
-rw-r--r--tools/renesas/rcar_layout_create/sa6.c185
-rw-r--r--tools/renesas/rcar_layout_create/sa6.ld.S114
-rw-r--r--tools/renesas/rzg_layout_create/makefile118
-rw-r--r--tools/renesas/rzg_layout_create/sa0.c30
-rw-r--r--tools/renesas/rzg_layout_create/sa0.ld.S28
-rw-r--r--tools/renesas/rzg_layout_create/sa6.c236
-rw-r--r--tools/renesas/rzg_layout_create/sa6.ld.S114
-rw-r--r--tools/sptool/Makefile50
-rw-r--r--tools/sptool/sp_mk_generator.py232
-rw-r--r--tools/sptool/spactions.py155
-rwxr-xr-xtools/sptool/sptool.py145
-rw-r--r--tools/stm32image/Makefile49
-rw-r--r--tools/stm32image/stm32image.c361
4069 files changed, 701938 insertions, 0 deletions
diff --git a/.checkpatch.conf b/.checkpatch.conf
new file mode 100644
index 0000000..baa983d
--- /dev/null
+++ b/.checkpatch.conf
@@ -0,0 +1,91 @@
+#
+# 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
diff --git a/.commitlintrc.js b/.commitlintrc.js
new file mode 100644
index 0000000..cfafbed
--- /dev/null
+++ b/.commitlintrc.js
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* eslint-env es6 */
+
+"use strict";
+
+const fs = require("fs");
+const yaml = require("js-yaml");
+
+const { "trailer-exists": trailerExists } = require("@commitlint/rules").default;
+
+/*
+ * The types and scopes accepted by both Commitlint and Commitizen are defined by the changelog
+ * configuration file - `changelog.yaml` - as they decide which section of the changelog commits
+ * with a given type and scope are placed in.
+ */
+
+let changelog;
+
+try {
+ const contents = fs.readFileSync("changelog.yaml", "utf8");
+
+ changelog = yaml.load(contents);
+} catch (err) {
+ console.log(err);
+
+ throw err;
+}
+
+function getTypes(sections) {
+ return sections.map(section => section.type)
+}
+
+function getScopes(subsections) {
+ return subsections.flatMap(subsection => {
+ const scope = subsection.scope ? [ subsection.scope ] : [];
+ const subscopes = getScopes(subsection.subsections || []);
+
+ return scope.concat(subscopes);
+ })
+};
+
+const types = getTypes(changelog.sections).sort(); /* Sort alphabetically */
+const scopes = getScopes(changelog.subsections).sort(); /* Sort alphabetically */
+
+module.exports = {
+ extends: ["@commitlint/config-conventional"],
+ plugins: [
+ {
+ rules: {
+ "signed-off-by-exists": trailerExists,
+ "change-id-exists": trailerExists,
+ },
+ },
+ ],
+ rules: {
+ "header-max-length": [1, "always", 50], /* Warning */
+ "body-max-line-length": [1, "always", 72], /* Warning */
+
+ "change-id-exists": [1, "always", "Change-Id:"], /* Warning */
+ "signed-off-by-exists": [1, "always", "Signed-off-by:"], /* Warning */
+
+ "type-case": [2, "always", "lower-case" ], /* Error */
+ "type-enum": [2, "always", types], /* Error */
+
+ "scope-case": [2, "always", "lower-case"], /* Error */
+ "scope-enum": [1, "always", scopes] /* Warning */
+ },
+};
diff --git a/.cz.json b/.cz.json
new file mode 100644
index 0000000..556c39f
--- /dev/null
+++ b/.cz.json
@@ -0,0 +1,3 @@
+{
+ "path": "@commitlint/cz-commitlint"
+}
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..12f786d
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,72 @@
+#
+# Copyright (c) 2017-2020, 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 100 columns"
+# This is a "soft" requirement for Arm-TF, and should not be the sole
+# reason for changes.
+max_line_length = 100
+
+# [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
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1f4efb6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,51 @@
+# 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/renesas/rzg_layout_create/*.bin
+tools/renesas/rzg_layout_create/*.srec
+tools/renesas/rzg_layout_create/*.map
+tools/renesas/rzg_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/__pycache__/
+
+# GNU GLOBAL files
+GPATH
+GRTAGS
+GSYMS
+GTAGS
+
+# Ctags
+tags
+
+# Node.js
+node_modules/
+
+# common python virtual environment directories
+.env/
+env/
+.venv/
+venv/
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 0000000..afdb74d
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,5 @@
+[gerrit]
+host=review.trustedfirmware.org
+port=29418
+project=TF-A/trusted-firmware-a
+defaultbranch=integration
diff --git a/.husky/.gitignore b/.husky/.gitignore
new file mode 100644
index 0000000..31354ec
--- /dev/null
+++ b/.husky/.gitignore
@@ -0,0 +1 @@
+_
diff --git a/.husky/commit-msg b/.husky/commit-msg
new file mode 100755
index 0000000..c1c9600
--- /dev/null
+++ b/.husky/commit-msg
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# shellcheck source=./_/husky.sh
+. "$(dirname "$0")/_/husky.sh"
+
+"$(dirname "$0")/commit-msg.gerrit" "$@"
+"$(dirname "$0")/commit-msg.commitlint" "$@"
diff --git a/.husky/commit-msg.commitlint b/.husky/commit-msg.commitlint
new file mode 100755
index 0000000..ca25ce1
--- /dev/null
+++ b/.husky/commit-msg.commitlint
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+npx --no-install commitlint --edit "$1"
diff --git a/.husky/commit-msg.gerrit b/.husky/commit-msg.gerrit
new file mode 100755
index 0000000..b8ce477
--- /dev/null
+++ b/.husky/commit-msg.gerrit
@@ -0,0 +1,194 @@
+#!/bin/sh
+# From Gerrit Code Review 2.14.20
+#
+# Part of Gerrit Code Review (https://www.gerritcodereview.com/)
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+unset GREP_OPTIONS
+
+CHANGE_ID_AFTER="Bug|Depends-On|Issue|Test|Feature|Fixes|Fixed"
+MSG="$1"
+
+# Check for, and add if missing, a unique Change-Id
+#
+add_ChangeId() {
+ clean_message=`sed -e '
+ /^diff --git .*/{
+ s///
+ q
+ }
+ /^Signed-off-by:/d
+ /^#/d
+ ' "$MSG" | git stripspace`
+ if test -z "$clean_message"
+ then
+ return
+ fi
+
+ # Do not add Change-Id to temp commits
+ if echo "$clean_message" | head -1 | grep -q '^\(fixup\|squash\)!'
+ then
+ return
+ fi
+
+ if test "false" = "`git config --bool --get gerrit.createChangeId`"
+ then
+ return
+ fi
+
+ # Does Change-Id: already exist? if so, exit (no change).
+ if grep -i '^Change-Id:' "$MSG" >/dev/null
+ then
+ return
+ fi
+
+ id=`_gen_ChangeId`
+ T="$MSG.tmp.$$"
+ AWK=awk
+ if [ -x /usr/xpg4/bin/awk ]; then
+ # Solaris AWK is just too broken
+ AWK=/usr/xpg4/bin/awk
+ fi
+
+ # Get core.commentChar from git config or use default symbol
+ commentChar=`git config --get core.commentChar`
+ commentChar=${commentChar:-#}
+
+ # How this works:
+ # - parse the commit message as (textLine+ blankLine*)*
+ # - assume textLine+ to be a footer until proven otherwise
+ # - exception: the first block is not footer (as it is the title)
+ # - read textLine+ into a variable
+ # - then count blankLines
+ # - once the next textLine appears, print textLine+ blankLine* as these
+ # aren't footer
+ # - in END, the last textLine+ block is available for footer parsing
+ $AWK '
+ BEGIN {
+ if (match(ENVIRON["OS"], "Windows")) {
+ RS="\r?\n" # Required on recent Cygwin
+ }
+ # while we start with the assumption that textLine+
+ # is a footer, the first block is not.
+ isFooter = 0
+ footerComment = 0
+ blankLines = 0
+ }
+
+ # Skip lines starting with commentChar without any spaces before it.
+ /^'"$commentChar"'/ { next }
+
+ # Skip the line starting with the diff command and everything after it,
+ # up to the end of the file, assuming it is only patch data.
+ # If more than one line before the diff was empty, strip all but one.
+ /^diff --git / {
+ blankLines = 0
+ while (getline) { }
+ next
+ }
+
+ # Count blank lines outside footer comments
+ /^$/ && (footerComment == 0) {
+ blankLines++
+ next
+ }
+
+ # Catch footer comment
+ /^\[[a-zA-Z0-9-]+:/ && (isFooter == 1) {
+ footerComment = 1
+ }
+
+ /]$/ && (footerComment == 1) {
+ footerComment = 2
+ }
+
+ # We have a non-blank line after blank lines. Handle this.
+ (blankLines > 0) {
+ print lines
+ for (i = 0; i < blankLines; i++) {
+ print ""
+ }
+
+ lines = ""
+ blankLines = 0
+ isFooter = 1
+ footerComment = 0
+ }
+
+ # Detect that the current block is not the footer
+ (footerComment == 0) && (!/^\[?[a-zA-Z0-9-]+:/ || /^[a-zA-Z0-9-]+:\/\//) {
+ isFooter = 0
+ }
+
+ {
+ # We need this information about the current last comment line
+ if (footerComment == 2) {
+ footerComment = 0
+ }
+ if (lines != "") {
+ lines = lines "\n";
+ }
+ lines = lines $0
+ }
+
+ # Footer handling:
+ # If the last block is considered a footer, splice in the Change-Id at the
+ # right place.
+ # Look for the right place to inject Change-Id by considering
+ # CHANGE_ID_AFTER. Keys listed in it (case insensitive) come first,
+ # then Change-Id, then everything else (eg. Signed-off-by:).
+ #
+ # Otherwise just print the last block, a new line and the Change-Id as a
+ # block of its own.
+ END {
+ unprinted = 1
+ if (isFooter == 0) {
+ print lines "\n"
+ lines = ""
+ }
+ changeIdAfter = "^(" tolower("'"$CHANGE_ID_AFTER"'") "):"
+ numlines = split(lines, footer, "\n")
+ for (line = 1; line <= numlines; line++) {
+ if (unprinted && match(tolower(footer[line]), changeIdAfter) != 1) {
+ unprinted = 0
+ print "Change-Id: I'"$id"'"
+ }
+ print footer[line]
+ }
+ if (unprinted) {
+ print "Change-Id: I'"$id"'"
+ }
+ }' "$MSG" > "$T" && mv "$T" "$MSG" || rm -f "$T"
+}
+_gen_ChangeIdInput() {
+ echo "tree `git write-tree`"
+ if parent=`git rev-parse "HEAD^0" 2>/dev/null`
+ then
+ echo "parent $parent"
+ fi
+ echo "author `git var GIT_AUTHOR_IDENT`"
+ echo "committer `git var GIT_COMMITTER_IDENT`"
+ echo
+ printf '%s' "$clean_message"
+}
+_gen_ChangeId() {
+ _gen_ChangeIdInput |
+ git hash-object -t commit --stdin
+}
+
+
+add_ChangeId
diff --git a/.husky/prepare-commit-msg b/.husky/prepare-commit-msg
new file mode 100755
index 0000000..593dfa8
--- /dev/null
+++ b/.husky/prepare-commit-msg
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# shellcheck source=./_/husky.sh
+. "$(dirname "$0")/_/husky.sh"
+
+"$(dirname "$0")/prepare-commit-msg.cz" "$@"
diff --git a/.husky/prepare-commit-msg.cz b/.husky/prepare-commit-msg.cz
new file mode 100755
index 0000000..724527d
--- /dev/null
+++ b/.husky/prepare-commit-msg.cz
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+file="$1"
+type="$2"
+
+if [ -z "$type" ]; then # only run on new commits
+ #
+ # Save any commit message trailers generated by Git.
+ #
+
+ trailers=$(git interpret-trailers --parse "$file")
+
+ #
+ # Execute the Commitizen hook.
+ #
+
+ (exec < "/dev/tty" && npx --no-install git-cz --hook) || true
+
+ #
+ # Restore any trailers that Commitizen might have overwritten.
+ #
+
+ printf "\n" >> "$file"
+
+ while IFS= read -r trailer; do
+ git interpret-trailers --in-place --trailer "$trailer" "$file"
+ done <<< "$trailers"
+fi
diff --git a/.nvmrc b/.nvmrc
new file mode 100644
index 0000000..e0325e5
--- /dev/null
+++ b/.nvmrc
@@ -0,0 +1 @@
+v16.17.1
diff --git a/.versionrc.js b/.versionrc.js
new file mode 100644
index 0000000..f699a07
--- /dev/null
+++ b/.versionrc.js
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* eslint-env es6 */
+
+"use strict";
+
+const fs = require("fs");
+const yaml = require("js-yaml");
+
+/*
+ * The types and scopes accepted by both Commitlint and Commitizen are defined by the changelog
+ * configuration file - `changelog.yaml` - as they decide which section of the changelog commits
+ * with a given type and scope are placed in.
+ */
+
+let changelog;
+
+try {
+ const contents = fs.readFileSync("changelog.yaml", "utf8");
+
+ changelog = yaml.load(contents);
+} catch (err) {
+ console.log(err);
+
+ throw err;
+}
+
+/*
+ * The next couple of functions are just used to transform the changelog YAML configuration
+ * structure into one accepted by the Conventional Changelog adapter (conventional-changelog-tf-a).
+ */
+
+function getTypes(sections) {
+ return sections.map(section => {
+ return {
+ "type": section.type,
+ "section": section.hidden ? undefined : section.title,
+ "hidden": section.hidden || false,
+ };
+ })
+}
+
+function getSections(subsections) {
+ return subsections.flatMap(subsection => {
+ const scope = subsection.scope ? [ subsection.scope ] : [];
+
+ return {
+ "title": subsection.title,
+ "sections": getSections(subsection.subsections || []),
+ "scopes": scope.concat(subsection.deprecated || []),
+ };
+ })
+};
+
+const types = getTypes(changelog.sections);
+const sections = getSections(changelog.subsections);
+
+module.exports = {
+ "header": "# Change Log & Release Notes\n\nThis document contains a summary of the new features, changes, fixes and known\nissues in each release of Trusted Firmware-A.\n",
+ "preset": {
+ "name": "tf-a",
+ "commitUrlFormat": "https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/{{hash}}",
+ "compareUrlFormat": "https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/{{previousTag}}..refs/tags/{{currentTag}}",
+ "userUrlFormat": "https://github.com/{{user}}",
+
+ "types": types,
+ "sections": sections,
+ },
+ "infile": "docs/change-log.md",
+ "skip": {
+ "commit": true,
+ "tag": true
+ },
+ "bumpFiles": [
+ {
+ "filename": "package.json",
+ "type": "json"
+ },
+ {
+ "filename": "package-lock.json",
+ "type": "json"
+ },
+ {
+ "filename": "tools/conventional-changelog-tf-a/package.json",
+ "type": "json"
+ },
+ {
+ "filename": "Makefile",
+ "updater": {
+ "readVersion": function (contents) {
+ const major = contents.match(/^VERSION_MAJOR\s*:=\s*(\d+?)$/m)[1];
+ const minor = contents.match(/^VERSION_MINOR\s*:=\s*(\d+?)$/m)[1];
+
+ return `${major}.${minor}.0`;
+ },
+
+ "writeVersion": function (contents, version) {
+ const major = version.split(".")[0];
+ const minor = version.split(".")[1];
+
+ contents = contents.replace(/^(VERSION_MAJOR\s*:=\s*)(\d+?)$/m, `$1${major}`);
+ contents = contents.replace(/^(VERSION_MINOR\s*:=\s*)(\d+?)$/m, `$1${minor}`);
+
+ return contents;
+ }
+ }
+ }
+ ]
+};
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..1ddb7b8
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,1594 @@
+#
+# Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+#
+# Trusted Firmware Version
+#
+VERSION_MAJOR := 2
+VERSION_MINOR := 8
+VERSION := ${VERSION_MAJOR}.${VERSION_MINOR}
+
+# 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_ARM_DIRS_TO_CHECK := $(sort $(filter-out \
+ include/drivers/arm/cryptocell, \
+ $(wildcard include/drivers/arm/*)))
+INC_ARM_DIRS_TO_CHECK += include/drivers/arm/cryptocell/*.h
+INC_DRV_DIRS_TO_CHECK := $(sort $(filter-out \
+ include/drivers/arm, \
+ $(wildcard include/drivers/*)))
+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 \
+ include/drivers, \
+ $(wildcard include/*)))
+LIB_DIRS_TO_CHECK := $(sort $(filter-out \
+ lib/compiler-rt \
+ lib/libfdt% \
+ lib/libc, \
+ lib/zlib \
+ $(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} \
+ ${INC_DRV_DIRS_TO_CHECK} \
+ ${INC_ARM_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
+
+# 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 ifeq (${BRANCH_PROTECTION},4)
+ # Turn on branch target identification mechanism
+ BP_OPTION := bti
+ ENABLE_BTI := 1
+else
+ $(error Unknown BRANCH_PROTECTION value ${BRANCH_PROTECTION})
+endif
+
+# FEAT_RME
+ifeq (${ENABLE_RME},1)
+# RME doesn't support PIE
+ifneq (${ENABLE_PIE},0)
+ $(error ENABLE_RME does not support PIE)
+endif
+# RME doesn't support BRBE
+ifneq (${ENABLE_BRBE_FOR_NS},0)
+ $(error ENABLE_RME does not support BRBE.)
+endif
+# RME requires AARCH64
+ifneq (${ARCH},aarch64)
+ $(error ENABLE_RME requires AArch64)
+endif
+# RME requires el2 context to be saved for now.
+CTX_INCLUDE_EL2_REGS := 1
+CTX_INCLUDE_AARCH32_REGS := 0
+ARM_ARCH_MAJOR := 8
+ARM_ARCH_MINOR := 5
+ENABLE_FEAT_ECV = 1
+ENABLE_FEAT_FGT = 1
+
+endif
+
+# USE_SPINLOCK_CAS requires AArch64 build
+ifeq (${USE_SPINLOCK_CAS},1)
+ifneq (${ARCH},aarch64)
+ $(error USE_SPINLOCK_CAS requires AArch64)
+endif
+endif
+
+# USE_DEBUGFS experimental feature recommended only in debug builds
+ifeq (${USE_DEBUGFS},1)
+ifeq (${DEBUG},1)
+ $(warning DEBUGFS experimental feature is enabled.)
+else
+ $(warning DEBUGFS experimental, recommended in DEBUG builds ONLY)
+endif
+endif
+
+ifneq (${DECRYPTION_SUPPORT},none)
+ENC_ARGS += -f ${FW_ENC_STATUS}
+ENC_ARGS += -k ${ENC_KEY}
+ENC_ARGS += -n ${ENC_NONCE}
+FIP_DEPS += enctool
+FWU_FIP_DEPS += enctool
+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_MAJOR ARM_ARCH_MINOR options
+ifeq (${ARM_ARCH_MINOR},0)
+march32-directive = -march=armv${ARM_ARCH_MAJOR}-a
+march64-directive = -march=armv${ARM_ARCH_MAJOR}-a
+else
+march32-directive = -march=armv${ARM_ARCH_MAJOR}.${ARM_ARCH_MINOR}-a
+march64-directive = -march=armv${ARM_ARCH_MAJOR}.${ARM_ARCH_MINOR}-a
+endif
+endif
+
+# Memory tagging is supported in architecture Armv8.5-A AArch64 and onwards
+ifeq ($(ARCH), aarch64)
+# Check if revision is greater than or equal to 8.5
+ifeq "8.5" "$(word 1, $(sort 8.5 $(ARM_ARCH_MAJOR).$(ARM_ARCH_MINOR)))"
+mem_tag_arch_support = yes
+endif
+endif
+
+# Get architecture feature modifiers
+arch-features = ${ARM_ARCH_FEATURE}
+
+# Enable required options for memory stack tagging.
+# Currently, these options are enabled only for clang and armclang compiler.
+ifeq (${SUPPORT_STACK_MEMTAG},yes)
+ifdef mem_tag_arch_support
+# Check for armclang and clang compilers
+ifneq ( ,$(filter $(notdir $(CC)),armclang clang))
+# Add "memtag" architecture feature modifier if not specified
+ifeq ( ,$(findstring memtag,$(arch-features)))
+arch-features := $(arch-features)+memtag
+endif # memtag
+ifeq ($(notdir $(CC)),armclang)
+TF_CFLAGS += -mmemtag-stack
+else ifeq ($(notdir $(CC)),clang)
+TF_CFLAGS += -fsanitize=memtag
+endif # armclang
+endif # armclang clang
+else
+$(error "Error: stack memory tagging is not supported for architecture \
+ ${ARCH},armv${ARM_ARCH_MAJOR}.${ARM_ARCH_MINOR}-a")
+endif # mem_tag_arch_support
+endif # SUPPORT_STACK_MEMTAG
+
+# Set the compiler's architecture feature modifiers
+ifneq ($(arch-features), none)
+# Strip "none+" from arch-features
+arch-features := $(subst none+,,$(arch-features))
+ifeq ($(ARCH), aarch32)
+march32-directive := $(march32-directive)+$(arch-features)
+else
+march64-directive := $(march64-directive)+$(arch-features)
+endif
+# Print features
+$(info Arm Architecture Features specified: $(subst +, ,$(arch-features)))
+endif # arch-features
+
+# Determine if FEAT_RNG is supported
+ENABLE_FEAT_RNG = $(if $(findstring rng,${arch-features}),1,0)
+
+# Determine if FEAT_SB is supported
+ENABLE_FEAT_SB = $(if $(findstring sb,${arch-features}),1,0)
+
+ifneq ($(findstring clang,$(notdir $(CC))),)
+ 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)
+ else
+ TF_CFLAGS_aarch32 = $(target32-directive) $(march32-directive)
+ TF_CFLAGS_aarch64 := -target aarch64-elf $(march64-directive)
+ LD := $(shell $(CC) --print-prog-name ld.lld)
+
+ AR := $(shell $(CC) --print-prog-name llvm-ar)
+ OD := $(shell $(CC) --print-prog-name llvm-objdump)
+ OC := $(shell $(CC) --print-prog-name llvm-objcopy)
+ endif
+
+ CPP := $(CC) -E $(TF_CFLAGS_$(ARCH))
+ PP := $(CC) -E $(TF_CFLAGS_$(ARCH))
+ AS := $(CC) -c -x assembler-with-cpp $(TF_CFLAGS_$(ARCH))
+else ifneq ($(findstring gcc,$(notdir $(CC))),)
+TF_CFLAGS_aarch32 = $(march32-directive)
+TF_CFLAGS_aarch64 = $(march64-directive)
+ifeq ($(ENABLE_LTO),1)
+ # Enable LTO only for aarch64
+ ifeq (${ARCH},aarch64)
+ LTO_CFLAGS = -flto
+ # Use gcc as a wrapper for the ld, recommended for LTO
+ LINKER := ${CROSS_COMPILE}gcc
+ endif
+endif
+LD = $(LINKER)
+else
+TF_CFLAGS_aarch32 = $(march32-directive)
+TF_CFLAGS_aarch64 = $(march64-directive)
+LD = $(LINKER)
+endif
+
+# Process Debug flag
+$(eval $(call add_define,DEBUG))
+ifneq (${DEBUG}, 0)
+ BUILD_TYPE := debug
+ TF_CFLAGS += -g -gdwarf-4
+ ASFLAGS += -g -Wa,-gdwarf-4
+
+ # 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}(${BUILD_TYPE}):${BUILD_STRING}
+
+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)
+
+# General warnings
+WARNINGS := -Wall -Wmissing-include-dirs -Wunused \
+ -Wdisabled-optimization -Wvla -Wshadow \
+ -Wno-unused-parameter -Wredundant-decls
+
+# Additional warnings
+# Level 1
+WARNING1 := -Wextra
+WARNING1 += -Wmissing-format-attribute
+WARNING1 += -Wmissing-prototypes
+WARNING1 += -Wold-style-definition
+
+# Level 2
+WARNING2 := -Waggregate-return
+WARNING2 += -Wcast-align
+WARNING2 += -Wnested-externs
+
+WARNING3 := -Wbad-function-cast
+WARNING3 += -Wcast-qual
+WARNING3 += -Wconversion
+WARNING3 += -Wpacked
+WARNING3 += -Wpointer-arith
+WARNING3 += -Wswitch-default
+
+ifeq (${W},1)
+WARNINGS += $(WARNING1)
+else ifeq (${W},2)
+WARNINGS += $(WARNING1) $(WARNING2)
+else ifeq (${W},3)
+WARNINGS += $(WARNING1) $(WARNING2) $(WARNING3)
+endif
+
+# Compiler specific warnings
+ifeq ($(findstring clang,$(notdir $(CC))),)
+# not using clang
+WARNINGS += -Wunused-but-set-variable -Wmaybe-uninitialized \
+ -Wpacked-bitfield-compat -Wshift-overflow=2 \
+ -Wlogical-op
+else
+# using clang
+WARNINGS += -Wshift-overflow -Wshift-sign-overflow \
+ -Wlogical-op-parentheses
+endif
+
+ifneq (${E},0)
+ERRORS := -Werror
+endif
+
+CPPFLAGS = ${DEFINES} ${INCLUDES} ${MBEDTLS_INC} -nostdinc \
+ $(ERRORS) $(WARNINGS)
+ASFLAGS += $(CPPFLAGS) $(ASFLAGS_$(ARCH)) \
+ -ffreestanding -Wa,--fatal-warnings
+TF_CFLAGS += $(CPPFLAGS) $(TF_CFLAGS_$(ARCH)) \
+ -ffunction-sections -fdata-sections \
+ -ffreestanding -fno-builtin -fno-common \
+ -Os -std=gnu99
+
+$(eval $(call add_define,SVE_VECTOR_LEN))
+
+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)
+
+# LD = armlink
+ifneq ($(findstring armlink,$(notdir $(LD))),)
+TF_LDFLAGS += --diag_error=warning --lto_level=O1
+TF_LDFLAGS += --remove --info=unused,unusedsymbols
+TF_LDFLAGS += $(TF_LDFLAGS_$(ARCH))
+
+# LD = gcc (used when GCC LTO is enabled)
+else ifneq ($(findstring gcc,$(notdir $(LD))),)
+# Pass ld options with Wl or Xlinker switches
+TF_LDFLAGS += -Wl,--fatal-warnings -O1
+TF_LDFLAGS += -Wl,--gc-sections
+ifeq ($(ENABLE_LTO),1)
+ ifeq (${ARCH},aarch64)
+ TF_LDFLAGS += -flto -fuse-linker-plugin
+ endif
+endif
+# GCC automatically adds fix-cortex-a53-843419 flag when used to link
+# which breaks some builds, so disable if errata fix is not explicitly enabled
+ifneq (${ERRATA_A53_843419},1)
+ TF_LDFLAGS += -mno-fix-cortex-a53-843419
+endif
+TF_LDFLAGS += -nostdlib
+TF_LDFLAGS += $(subst --,-Xlinker --,$(TF_LDFLAGS_$(ARCH)))
+
+# LD = gcc-ld (ld) or llvm-ld (ld.lld) or other
+else
+TF_LDFLAGS += --fatal-warnings -O1
+TF_LDFLAGS += --gc-sections
+# ld.lld doesn't recognize the errata flags,
+# therefore don't add those in that case
+ifeq ($(findstring ld.lld,$(notdir $(LD))),)
+TF_LDFLAGS += $(TF_LDFLAGS_$(ARCH))
+endif
+endif
+
+DTC_FLAGS += -I dts -O dtb
+DTC_CPPFLAGS += -P -nostdinc -Iinclude -Ifdts -undef \
+ -x assembler-with-cpp $(DEFINES)
+
+################################################################################
+# Common sources and include directories
+################################################################################
+include ${MAKE_HELPERS_DIRECTORY}arch_features.mk
+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
+
+ifeq (${BUILD_BASE},)
+ BUILD_BASE := ./build
+endif
+BUILD_PLAT := $(abspath ${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
+
+ ifeq (${SPD},spmd)
+ # SPMD is located in std_svc directory
+ SPD_DIR := std_svc
+
+ ifeq ($(SPMD_SPM_AT_SEL2),1)
+ ifeq ($(CTX_INCLUDE_EL2_REGS),0)
+ $(error SPMD with SPM at S-EL2 requires CTX_INCLUDE_EL2_REGS option)
+ endif
+ ifeq ($(SPMC_AT_EL3),1)
+ $(error SPM cannot be enabled in both S-EL2 and EL3.)
+ endif
+ endif
+
+ ifeq ($(findstring optee_sp,$(ARM_SPMC_MANIFEST_DTS)),optee_sp)
+ DTC_CPPFLAGS += -DOPTEE_SP_FW_CONFIG
+ endif
+
+ ifeq ($(TS_SP_FW_CONFIG),1)
+ DTC_CPPFLAGS += -DTS_SP_FW_CONFIG
+ endif
+
+ ifneq ($(ARM_BL2_SP_LIST_DTS),)
+ DTC_CPPFLAGS += -DARM_BL2_SP_LIST_DTS=$(ARM_BL2_SP_LIST_DTS)
+ endif
+
+ ifneq ($(SP_LAYOUT_FILE),)
+ BL2_ENABLE_SP_LOAD := 1
+ endif
+ else
+ # All other SPDs in spd directory
+ SPD_DIR := spd
+ endif
+
+ # We expect to locate an spd.mk under the specified SPD directory
+ SPD_MAKE := $(wildcard services/${SPD_DIR}/${SPD}/${SPD}.mk)
+
+ ifeq (${SPD_MAKE},)
+ $(error Error: No services/${SPD_DIR}/${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 rmmd Makefile if RME is enabled
+################################################################################
+
+ifneq (${ENABLE_RME},0)
+ifneq (${ARCH},aarch64)
+ $(error ENABLE_RME requires AArch64)
+endif
+ifeq ($(SPMC_AT_EL3),1)
+ $(error SPMC_AT_EL3 and ENABLE_RME cannot both be enabled.)
+endif
+include services/std_svc/rmmd/rmmd.mk
+$(warning "RME is an experimental feature")
+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
+
+PIE_FOUND := $(findstring --enable-default-pie,${GCC_V_OUTPUT})
+ifneq ($(PIE_FOUND),)
+ TF_CFLAGS += -fno-PIE
+ifneq ($(findstring gcc,$(notdir $(LD))),)
+ TF_LDFLAGS += -no-pie
+endif
+endif
+
+ifneq ($(findstring gcc,$(notdir $(LD))),)
+ PIE_LDFLAGS += -Wl,-pie -Wl,--no-dynamic-linker
+else
+ PIE_LDFLAGS += -pie --no-dynamic-linker
+endif
+
+ifeq ($(ENABLE_PIE),1)
+ifeq ($(BL2_AT_EL3),1)
+ifneq ($(BL2_IN_XIP_MEM),1)
+ BL2_CFLAGS += -fpie
+ BL2_LDFLAGS += $(PIE_LDFLAGS)
+endif
+endif
+ BL31_CFLAGS += -fpie
+ BL31_LDFLAGS += $(PIE_LDFLAGS)
+ BL32_CFLAGS += -fpie
+ BL32_LDFLAGS += $(PIE_LDFLAGS)
+endif
+
+ifeq (${ARCH},aarch64)
+BL1_CPPFLAGS += -DIMAGE_AT_EL3
+ifeq ($(BL2_AT_EL3),1)
+BL2_CPPFLAGS += -DIMAGE_AT_EL3
+else
+BL2_CPPFLAGS += -DIMAGE_AT_EL1
+endif
+BL2U_CPPFLAGS += -DIMAGE_AT_EL1
+BL31_CPPFLAGS += -DIMAGE_AT_EL3
+BL32_CPPFLAGS += -DIMAGE_AT_EL1
+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_NS),1)
+ $(error For RAS_EXTENSION, HANDLE_EA_EL3_FIRST_NS 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
+
+ifeq ($(MEASURED_BOOT)-$(TRUSTED_BOARD_BOOT),1-1)
+# Support authentication verification and hash calculation
+ CRYPTO_SUPPORT := 3
+else ifeq ($(DRTM_SUPPORT)-$(TRUSTED_BOARD_BOOT),1-1)
+# Support authentication verification and hash calculation
+ CRYPTO_SUPPORT := 3
+else ifneq ($(filter 1,${MEASURED_BOOT} ${DRTM_SUPPORT}),)
+# Support hash calculation only
+ CRYPTO_SUPPORT := 2
+else ifeq (${TRUSTED_BOARD_BOOT},1)
+# Support authentication verification only
+ CRYPTO_SUPPORT := 1
+else
+ CRYPTO_SUPPORT := 0
+endif
+
+# SDEI_IN_FCONF is only supported when SDEI_SUPPORT is enabled.
+ifeq ($(SDEI_SUPPORT)-$(SDEI_IN_FCONF),0-1)
+$(error "SDEI_IN_FCONF is only supported when SDEI_SUPPORT is enabled")
+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)
+ endif
+endif
+
+ifeq ($(CTX_INCLUDE_MTE_REGS),1)
+ ifneq (${ARCH},aarch64)
+ $(error CTX_INCLUDE_MTE_REGS requires AArch64)
+ endif
+endif
+
+ifeq ($(PSA_FWU_SUPPORT),1)
+ $(info PSA_FWU_SUPPORT is an experimental feature)
+endif
+
+ifeq ($(FEATURE_DETECTION),1)
+ $(info FEATURE_DETECTION is an experimental feature)
+endif
+
+ifeq (${ARM_XLAT_TABLES_LIB_V1}, 1)
+ ifeq (${ALLOW_RO_XLAT_TABLES}, 1)
+ $(error "ALLOW_RO_XLAT_TABLES requires translation tables library v2")
+ endif
+endif
+
+ifneq (${DECRYPTION_SUPPORT},none)
+ ifeq (${TRUSTED_BOARD_BOOT}, 0)
+ $(error TRUSTED_BOARD_BOOT must be enabled for DECRYPTION_SUPPORT to be set)
+ endif
+endif
+
+# Ensure that no Aarch64-only features are enabled in Aarch32 build
+ifeq (${ARCH},aarch32)
+
+ # SME/SVE only supported on AArch64
+ ifeq (${ENABLE_SME_FOR_NS},1)
+ $(error "ENABLE_SME_FOR_NS cannot be used with ARCH=aarch32")
+ endif
+ ifeq (${ENABLE_SVE_FOR_NS},1)
+ # Warning instead of error due to CI dependency on this
+ $(error "ENABLE_SVE_FOR_NS cannot be used with ARCH=aarch32")
+ endif
+
+ # BRBE is not supported in AArch32
+ ifeq (${ENABLE_BRBE_FOR_NS},1)
+ $(error "ENABLE_BRBE_FOR_NS cannot be used with ARCH=aarch32")
+ endif
+
+ # FEAT_RNG_TRAP is not supported in AArch32
+ ifeq (${ENABLE_FEAT_RNG_TRAP},1)
+ $(error "ENABLE_FEAT_RNG_TRAP cannot be used with ARCH=aarch32")
+ endif
+endif
+
+# Ensure ENABLE_RME is not used with SME
+ifeq (${ENABLE_RME},1)
+ ifeq (${ENABLE_SME_FOR_NS},1)
+ $(error "ENABLE_SME_FOR_NS cannot be used with ENABLE_RME")
+ endif
+endif
+
+# Secure SME/SVE requires the non-secure component as well
+ifeq (${ENABLE_SME_FOR_SWD},1)
+ ifeq (${ENABLE_SME_FOR_NS},0)
+ $(error "ENABLE_SME_FOR_SWD requires ENABLE_SME_FOR_NS")
+ endif
+endif
+ifeq (${ENABLE_SVE_FOR_SWD},1)
+ ifeq (${ENABLE_SVE_FOR_NS},0)
+ $(error "ENABLE_SVE_FOR_SWD requires ENABLE_SVE_FOR_NS")
+ endif
+endif
+
+# SVE and SME cannot be used with CTX_INCLUDE_FPREGS since secure manager does
+# its own context management including FPU registers.
+ifeq (${CTX_INCLUDE_FPREGS},1)
+ ifeq (${ENABLE_SME_FOR_NS},1)
+ $(error "ENABLE_SME_FOR_NS cannot be used with CTX_INCLUDE_FPREGS")
+ endif
+ ifeq (${ENABLE_SVE_FOR_NS},1)
+ # Warning instead of error due to CI dependency on this
+ $(warning "ENABLE_SVE_FOR_NS cannot be used with CTX_INCLUDE_FPREGS")
+ $(warning "Forced ENABLE_SVE_FOR_NS=0")
+ override ENABLE_SVE_FOR_NS := 0
+ endif
+endif
+
+ifeq ($(DRTM_SUPPORT),1)
+ $(info DRTM_SUPPORT is an experimental feature)
+endif
+
+ifeq (${ENABLE_RME},1)
+ ifneq (${SEPARATE_CODE_AND_RODATA},1)
+ $(error `ENABLE_RME=1` requires `SEPARATE_CODE_AND_RODATA=1`)
+ endif
+endif
+
+################################################################################
+# Process platform overrideable behaviour
+################################################################################
+
+ifdef BL1_SOURCES
+NEED_BL1 := yes
+endif
+
+ifdef BL2_SOURCES
+ NEED_BL2 := yes
+
+ # 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 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
+
+ifdef BL2U_SOURCES
+NEED_BL2U := yes
+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
+
+ifdef FDT_SOURCES
+NEED_FDT := yes
+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 Encryption Tool
+ENCTOOLPATH ?= tools/encrypt_fw
+ENCTOOL ?= ${ENCTOOLPATH}/encrypt_fw${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.py
+SP_MK_GEN ?= ${SPTOOLPATH}/sp_mk_generator.py
+
+# Variables for use with ROMLIB
+ROMLIBPATH ?= lib/romlib
+
+# Variable for use with Python
+PYTHON ?= python3
+
+# Variables for use with PRINT_MEMORY_MAP
+PRINT_MEMORY_MAP_PATH ?= tools/memory
+PRINT_MEMORY_MAP ?= ${PRINT_MEMORY_MAP_PATH}/print_memory_map.py
+
+# Variables for use with documentation build using Sphinx tool
+DOCS_PATH ?= docs
+
+# Defination of SIMICS flag
+SIMICS_BUILD ?= 0
+
+################################################################################
+# Include BL specific makefiles
+################################################################################
+
+ifeq (${NEED_BL1},yes)
+include bl1/bl1.mk
+endif
+
+ifeq (${NEED_BL2},yes)
+include bl2/bl2.mk
+endif
+
+ifeq (${NEED_BL2U},yes)
+include bl2u/bl2u.mk
+endif
+
+ifeq (${NEED_BL31},yes)
+include bl31/bl31.mk
+endif
+
+################################################################################
+# Build options checks
+################################################################################
+
+$(eval $(call assert_booleans,\
+ $(sort \
+ ALLOW_RO_XLAT_TABLES \
+ BL2_ENABLE_SP_LOAD \
+ COLD_BOOT_SINGLE_CPU \
+ CREATE_KEYS \
+ CTX_INCLUDE_AARCH32_REGS \
+ CTX_INCLUDE_FPREGS \
+ CTX_INCLUDE_EL2_REGS \
+ DEBUG \
+ DISABLE_MTPMU \
+ DYN_DISABLE_AUTH \
+ EL3_EXCEPTION_HANDLING \
+ ENABLE_AMU \
+ ENABLE_AMU_AUXILIARY_COUNTERS \
+ ENABLE_AMU_FCONF \
+ AMU_RESTRICT_COUNTERS \
+ ENABLE_ASSERTIONS \
+ ENABLE_PIE \
+ ENABLE_PMF \
+ ENABLE_PSCI_STAT \
+ ENABLE_RUNTIME_INSTRUMENTATION \
+ ENABLE_SME_FOR_NS \
+ ENABLE_SME_FOR_SWD \
+ ENABLE_SPE_FOR_LOWER_ELS \
+ ENABLE_SVE_FOR_NS \
+ ENABLE_SVE_FOR_SWD \
+ ERROR_DEPRECATED \
+ FAULT_INJECTION_SUPPORT \
+ GENERATE_COT \
+ GICV2_G0_FOR_EL3 \
+ HANDLE_EA_EL3_FIRST_NS \
+ HW_ASSISTED_COHERENCY \
+ INVERTED_MEMMAP \
+ MEASURED_BOOT \
+ DRTM_SUPPORT \
+ NS_TIMER_SWITCH \
+ OVERRIDE_LIBC \
+ PL011_GENERIC_UART \
+ PLAT_RSS_NOT_SUPPORTED \
+ PROGRAMMABLE_RESET_ADDRESS \
+ PSCI_EXTENDED_STATE_ID \
+ RESET_TO_BL31 \
+ RESET_TO_BL31_WITH_PARAMS \
+ SAVE_KEYS \
+ SEPARATE_CODE_AND_RODATA \
+ SEPARATE_BL2_NOLOAD_REGION \
+ SEPARATE_NOBITS_REGION \
+ SPIN_ON_BL1_EXIT \
+ SPM_MM \
+ SPMC_AT_EL3 \
+ SPMD_SPM_AT_SEL2 \
+ TRUSTED_BOARD_BOOT \
+ USE_COHERENT_MEM \
+ USE_DEBUGFS \
+ ARM_IO_IN_DTB \
+ SDEI_IN_FCONF \
+ SEC_INT_DESC_IN_FCONF \
+ USE_ROMLIB \
+ USE_TBBR_DEFS \
+ WARMBOOT_ENABLE_DCACHE_EARLY \
+ BL2_AT_EL3 \
+ BL2_IN_XIP_MEM \
+ BL2_INV_DCACHE \
+ USE_SPINLOCK_CAS \
+ ENCRYPT_BL31 \
+ ENCRYPT_BL32 \
+ ERRATA_SPECULATIVE_AT \
+ RAS_TRAP_NS_ERR_REC_ACCESS \
+ COT_DESC_IN_DTB \
+ USE_SP804_TIMER \
+ PSA_FWU_SUPPORT \
+ ENABLE_SYS_REG_TRACE_FOR_NS \
+ ENABLE_MPMM \
+ ENABLE_MPMM_FCONF \
+ SIMICS_BUILD \
+ FEATURE_DETECTION \
+ TRNG_SUPPORT \
+ CONDITIONAL_CMO \
+)))
+
+$(eval $(call assert_numerics,\
+ $(sort \
+ ARM_ARCH_MAJOR \
+ ARM_ARCH_MINOR \
+ BRANCH_PROTECTION \
+ CTX_INCLUDE_PAUTH_REGS \
+ CTX_INCLUDE_MTE_REGS \
+ CTX_INCLUDE_NEVE_REGS \
+ CRYPTO_SUPPORT \
+ ENABLE_BRBE_FOR_NS \
+ ENABLE_TRBE_FOR_NS \
+ ENABLE_BTI \
+ ENABLE_PAUTH \
+ ENABLE_FEAT_AMUv1 \
+ ENABLE_FEAT_AMUv1p1 \
+ ENABLE_FEAT_CSV2_2 \
+ ENABLE_FEAT_DIT \
+ ENABLE_FEAT_ECV \
+ ENABLE_FEAT_FGT \
+ ENABLE_FEAT_HCX \
+ ENABLE_FEAT_PAN \
+ ENABLE_FEAT_RNG \
+ ENABLE_FEAT_RNG_TRAP \
+ ENABLE_FEAT_SB \
+ ENABLE_FEAT_SEL2 \
+ ENABLE_FEAT_VHE \
+ ENABLE_MPAM_FOR_LOWER_ELS \
+ ENABLE_RME \
+ ENABLE_TRF_FOR_NS \
+ FW_ENC_STATUS \
+ NR_OF_FW_BANKS \
+ NR_OF_IMAGES_IN_FW_BANK \
+ RAS_EXTENSION \
+ TWED_DELAY \
+ ENABLE_FEAT_TWED \
+ SVE_VECTOR_LEN \
+)))
+
+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_defines,\
+ $(sort \
+ ALLOW_RO_XLAT_TABLES \
+ ARM_ARCH_MAJOR \
+ ARM_ARCH_MINOR \
+ BL2_ENABLE_SP_LOAD \
+ COLD_BOOT_SINGLE_CPU \
+ CTX_INCLUDE_AARCH32_REGS \
+ CTX_INCLUDE_FPREGS \
+ CTX_INCLUDE_PAUTH_REGS \
+ EL3_EXCEPTION_HANDLING \
+ CTX_INCLUDE_MTE_REGS \
+ CTX_INCLUDE_EL2_REGS \
+ CTX_INCLUDE_NEVE_REGS \
+ DECRYPTION_SUPPORT_${DECRYPTION_SUPPORT} \
+ DISABLE_MTPMU \
+ ENABLE_AMU \
+ ENABLE_AMU_AUXILIARY_COUNTERS \
+ ENABLE_AMU_FCONF \
+ AMU_RESTRICT_COUNTERS \
+ ENABLE_ASSERTIONS \
+ ENABLE_BTI \
+ ENABLE_MPAM_FOR_LOWER_ELS \
+ ENABLE_PAUTH \
+ ENABLE_PIE \
+ ENABLE_PMF \
+ ENABLE_PSCI_STAT \
+ ENABLE_RME \
+ ENABLE_RUNTIME_INSTRUMENTATION \
+ ENABLE_SME_FOR_NS \
+ ENABLE_SME_FOR_SWD \
+ ENABLE_SPE_FOR_LOWER_ELS \
+ ENABLE_SVE_FOR_NS \
+ ENABLE_SVE_FOR_SWD \
+ ENCRYPT_BL31 \
+ ENCRYPT_BL32 \
+ ERROR_DEPRECATED \
+ FAULT_INJECTION_SUPPORT \
+ GICV2_G0_FOR_EL3 \
+ HANDLE_EA_EL3_FIRST_NS \
+ HW_ASSISTED_COHERENCY \
+ LOG_LEVEL \
+ MEASURED_BOOT \
+ DRTM_SUPPORT \
+ NS_TIMER_SWITCH \
+ PL011_GENERIC_UART \
+ PLAT_${PLAT} \
+ PLAT_RSS_NOT_SUPPORTED \
+ PROGRAMMABLE_RESET_ADDRESS \
+ PSCI_EXTENDED_STATE_ID \
+ RAS_EXTENSION \
+ RESET_TO_BL31 \
+ RESET_TO_BL31_WITH_PARAMS \
+ SEPARATE_CODE_AND_RODATA \
+ SEPARATE_BL2_NOLOAD_REGION \
+ SEPARATE_NOBITS_REGION \
+ RECLAIM_INIT_CODE \
+ SPD_${SPD} \
+ SPIN_ON_BL1_EXIT \
+ SPM_MM \
+ SPMC_AT_EL3 \
+ SPMD_SPM_AT_SEL2 \
+ TRUSTED_BOARD_BOOT \
+ CRYPTO_SUPPORT \
+ TRNG_SUPPORT \
+ USE_COHERENT_MEM \
+ USE_DEBUGFS \
+ ARM_IO_IN_DTB \
+ SDEI_IN_FCONF \
+ SEC_INT_DESC_IN_FCONF \
+ USE_ROMLIB \
+ USE_TBBR_DEFS \
+ WARMBOOT_ENABLE_DCACHE_EARLY \
+ BL2_AT_EL3 \
+ BL2_IN_XIP_MEM \
+ BL2_INV_DCACHE \
+ USE_SPINLOCK_CAS \
+ ERRATA_SPECULATIVE_AT \
+ RAS_TRAP_NS_ERR_REC_ACCESS \
+ COT_DESC_IN_DTB \
+ USE_SP804_TIMER \
+ ENABLE_FEAT_RNG \
+ ENABLE_FEAT_RNG_TRAP \
+ ENABLE_FEAT_SB \
+ ENABLE_FEAT_DIT \
+ NR_OF_FW_BANKS \
+ NR_OF_IMAGES_IN_FW_BANK \
+ PSA_FWU_SUPPORT \
+ ENABLE_BRBE_FOR_NS \
+ ENABLE_TRBE_FOR_NS \
+ ENABLE_SYS_REG_TRACE_FOR_NS \
+ ENABLE_TRF_FOR_NS \
+ ENABLE_FEAT_HCX \
+ ENABLE_MPMM \
+ ENABLE_MPMM_FCONF \
+ ENABLE_FEAT_FGT \
+ ENABLE_FEAT_AMUv1 \
+ ENABLE_FEAT_ECV \
+ SIMICS_BUILD \
+ ENABLE_FEAT_AMUv1p1 \
+ ENABLE_FEAT_SEL2 \
+ ENABLE_FEAT_VHE \
+ ENABLE_FEAT_CSV2_2 \
+ ENABLE_FEAT_PAN \
+ FEATURE_DETECTION \
+ TWED_DELAY \
+ ENABLE_FEAT_TWED \
+ CONDITIONAL_CMO \
+)))
+
+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
+
+# Generate and include sp_gen.mk if SPD is spmd and SP_LAYOUT_FILE is defined
+ifeq (${SPD},spmd)
+ifdef SP_LAYOUT_FILE
+ -include $(BUILD_PLAT)/sp_gen.mk
+ FIP_DEPS += sp
+ CRT_DEPS += sp
+ NEED_SP_PKG := yes
+else
+ ifeq (${SPMD_SPM_AT_SEL2},1)
+ $(error "SPMD with SPM at S-EL2 require SP_LAYOUT_FILE")
+ endif
+endif
+endif
+
+################################################################################
+# Build targets
+################################################################################
+
+.PHONY: all msg_start clean realclean distclean cscope locate-checkpatch checkcodebase checkpatch fiptool sptool fip sp fwu_fip certtool dtbs memmap doc enctool
+.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
+endif # !ERROR_DEPRECATED
+
+$(eval $(call MAKE_LIB_DIRS))
+$(eval $(call MAKE_LIB,c))
+
+# Expand build macros for the different images
+ifeq (${NEED_BL1},yes)
+BL1_SOURCES := $(sort ${BL1_SOURCES})
+
+$(eval $(call MAKE_BL,bl1))
+endif
+
+ifeq (${NEED_BL2},yes)
+ifeq (${BL2_AT_EL3}, 0)
+FIP_BL2_ARGS := tb-fw
+endif
+
+BL2_SOURCES := $(sort ${BL2_SOURCES})
+
+$(if ${BL2}, $(eval $(call TOOL_ADD_IMG,bl2,--${FIP_BL2_ARGS})),\
+ $(eval $(call MAKE_BL,bl2,${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}
+# Sort BL31 source files to remove duplicates
+BL31_SOURCES := $(sort ${BL31_SOURCES})
+ifneq (${DECRYPTION_SUPPORT},none)
+$(if ${BL31}, $(eval $(call TOOL_ADD_IMG,bl31,--soc-fw,,$(ENCRYPT_BL31))),\
+ $(eval $(call MAKE_BL,bl31,soc-fw,,$(ENCRYPT_BL31))))
+else
+$(if ${BL31}, $(eval $(call TOOL_ADD_IMG,bl31,--soc-fw)),\
+ $(eval $(call MAKE_BL,bl31,soc-fw)))
+endif
+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)
+# Sort BL32 source files to remove duplicates
+BL32_SOURCES := $(sort ${BL32_SOURCES})
+BUILD_BL32 := $(if $(BL32),,$(if $(BL32_SOURCES),1))
+
+ifneq (${DECRYPTION_SUPPORT},none)
+$(if ${BUILD_BL32}, $(eval $(call MAKE_BL,bl32,tos-fw,,$(ENCRYPT_BL32))),\
+ $(eval $(call TOOL_ADD_IMG,bl32,--tos-fw,,$(ENCRYPT_BL32))))
+else
+$(if ${BUILD_BL32}, $(eval $(call MAKE_BL,bl32,tos-fw)),\
+ $(eval $(call TOOL_ADD_IMG,bl32,--tos-fw)))
+endif
+endif
+
+# If RMM image is needed but RMM is not defined, Test Realm Payload (TRP)
+# needs to be built from RMM_SOURCES.
+ifeq (${NEED_RMM},yes)
+# Sort RMM source files to remove duplicates
+RMM_SOURCES := $(sort ${RMM_SOURCES})
+BUILD_RMM := $(if $(RMM),,$(if $(RMM_SOURCES),1))
+
+$(if ${BUILD_RMM}, $(eval $(call MAKE_BL,rmm,rmm-fw)),\
+ $(eval $(call TOOL_ADD_IMG,rmm,--rmm-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,bl2u,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
+
+# Add Secure Partition packages
+ifeq (${NEED_SP_PKG},yes)
+$(BUILD_PLAT)/sp_gen.mk: ${SP_MK_GEN} ${SP_LAYOUT_FILE} | ${BUILD_PLAT}
+ ${Q}${PYTHON} "$<" "$@" $(filter-out $<,$^) $(BUILD_PLAT) ${COT}
+sp: $(DTBS) $(BUILD_PLAT)/sp_gen.mk $(SP_PKGS)
+ @${ECHO_BLANK_LINE}
+ @echo "Built SP Images successfully"
+ @${ECHO_BLANK_LINE}
+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})
+ifdef UNIX_MK
+ ${Q}${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
+else
+# Clear the MAKEFLAGS as we do not want
+# to pass the gnumake flags to nmake.
+ ${Q}set MAKEFLAGS= && ${MSVC_NMAKE} /nologo /f ${FIPTOOLPATH}/Makefile.msvc FIPTOOLPATH=$(subst /,\,$(FIPTOOLPATH)) FIPTOOL=$(subst /,\,$(FIPTOOL)) clean
+endif
+ ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} clean
+ ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${ENCTOOLPATH} 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.*)
+ifdef UNIX_MK
+ ${Q}${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
+else
+# Clear the MAKEFLAGS as we do not want
+# to pass the gnumake flags to nmake.
+ ${Q}set MAKEFLAGS= && ${MSVC_NMAKE} /nologo /f ${FIPTOOLPATH}/Makefile.msvc FIPTOOLPATH=$(subst /,\,$(FIPTOOLPATH)) FIPTOOL=$(subst /,\,$(FIPTOOL)) realclean
+endif
+ ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} realclean
+ ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${ENCTOOLPATH} realclean
+ ${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 --no-merges $$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}
+
+${CRTTOOL}: FORCE
+ ${Q}${MAKE} PLAT=${PLAT} USE_TBBR_DEFS=${USE_TBBR_DEFS} COT=${COT} OPENSSL_DIR=${OPENSSL_DIR} CRTTOOL=${CRTTOOL} DEBUG=${DEBUG} V=${V} --no-print-directory -C ${CRTTOOLPATH} all
+ @${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}
+ $(eval ${CHECK_FIP_CMD})
+ ${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}
+ $(eval ${CHECK_FWU_FIP_CMD})
+ ${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}
+
+${FIPTOOL}: FORCE
+ifdef UNIX_MK
+ ${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" FIPTOOL=${FIPTOOL} OPENSSL_DIR=${OPENSSL_DIR} DEBUG=${DEBUG} V=${V} --no-print-directory -C ${FIPTOOLPATH} all
+else
+# Clear the MAKEFLAGS as we do not want
+# to pass the gnumake flags to nmake.
+ ${Q}set MAKEFLAGS= && ${MSVC_NMAKE} /nologo /f ${FIPTOOLPATH}/Makefile.msvc FIPTOOLPATH=$(subst /,\,$(FIPTOOLPATH)) FIPTOOL=$(subst /,\,$(FIPTOOL))
+endif
+
+romlib.bin: libraries FORCE
+ ${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
+
+# Call print_memory_map tool
+memmap: all
+ ${Q}${PYTHON} ${PRINT_MEMORY_MAP} ${BUILD_PLAT} ${INVERTED_MEMMAP}
+
+doc:
+ @echo " BUILD DOCUMENTATION"
+ ${Q}${MAKE} --no-print-directory -C ${DOCS_PATH} html
+
+enctool: ${ENCTOOL}
+
+${ENCTOOL}: FORCE
+ ${Q}${MAKE} PLAT=${PLAT} BUILD_INFO=0 OPENSSL_DIR=${OPENSSL_DIR} ENCTOOL=${ENCTOOL} DEBUG=${DEBUG} V=${V} --no-print-directory -C ${ENCTOOLPATH} all
+ @${ECHO_BLANK_LINE}
+ @echo "Built $@ successfully"
+ @${ECHO_BLANK_LINE}
+
+cscope:
+ @echo " CSCOPE"
+ ${Q}find ${CURDIR} -name "*.[chsS]" > cscope.files
+ ${Q}cscope -b -q -k
+
+help:
+ @echo "usage: ${MAKE} [PLAT=<platform>] [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 " enctool Build the Firmware encryption tool"
+ @echo " fiptool Build the Firmware Image Package (FIP) creation tool"
+ @echo " sp Build the Secure Partition Packages"
+ @echo " sptool Build the Secure Partition Package creation tool"
+ @echo " dtbs Build the Device Tree Blobs (if required for the platform)"
+ @echo " memmap Print the memory map of the built binaries"
+ @echo " doc Build html based documentation using Sphinx tool"
+ @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"
+
+.PHONY: FORCE
+FORCE:;
diff --git a/bl1/aarch32/bl1_arch_setup.c b/bl1/aarch32/bl1_arch_setup.c
new file mode 100644
index 0000000..ce04aaa
--- /dev/null
+++ b/bl1/aarch32/bl1_arch_setup.c
@@ -0,0 +1,15 @@
+/*
+ * 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)
+{
+
+}
diff --git a/bl1/aarch32/bl1_context_mgmt.c b/bl1/aarch32/bl1_context_mgmt.c
new file mode 100644
index 0000000..85d35a7
--- /dev/null
+++ b/bl1/aarch32/bl1_context_mgmt.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <context.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+#include <smccc_helpers.h>
+
+#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 *context)
+{
+ assert(context != NULL);
+ bl1_next_cpu_context_ptr = 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 *desc;
+ entry_point_info_t *next_bl_ep;
+
+ /* Get the image descriptor. */
+ desc = bl1_plat_get_image_desc(image_id);
+ assert(desc != NULL);
+
+ /* Get the entry point info. */
+ next_bl_ep = &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()) != 0U)) {
+ 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. */
+ desc->state = IMAGE_STATE_EXECUTED;
+
+ print_entry_point_info(next_bl_ep);
+}
diff --git a/bl1/aarch32/bl1_entrypoint.S b/bl1/aarch32/bl1_entrypoint.S
new file mode 100644
index 0000000..b22015e
--- /dev/null
+++ b/bl1/aarch32/bl1_entrypoint.S
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <context.h>
+#include <el3_common_macros.S>
+#include <smccc_helpers.h>
+#include <smccc_macros.S>
+
+ .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_prefetch_abort /* Prefetch abort */
+ b report_data_abort /* 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 \
+ _pie_fixup_size=0
+
+ /* -----------------------------------------------------
+ * 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
diff --git a/bl1/aarch32/bl1_exceptions.S b/bl1/aarch32/bl1_exceptions.S
new file mode 100644
index 0000000..4a6815f
--- /dev/null
+++ b/bl1/aarch32/bl1_exceptions.S
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <context.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <smccc_helpers.h>
+#include <smccc_macros.S>
+
+ .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}
+ exception_return
+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
+
+ /*
+ * Invalidate `smc_ctx_t` in data cache to prevent dirty data being
+ * used.
+ */
+ mov r0, r6
+ mov r1, #SMC_CTX_SIZE
+ bl inv_dcache_range
+
+ /* 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
diff --git a/bl1/aarch64/bl1_arch_setup.c b/bl1/aarch64/bl1_arch_setup.c
new file mode 100644
index 0000000..0a1cb30
--- /dev/null
+++ b/bl1/aarch64/bl1_arch_setup.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#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);
+}
diff --git a/bl1/aarch64/bl1_context_mgmt.c b/bl1/aarch64/bl1_context_mgmt.c
new file mode 100644
index 0000000..b9a7e5b
--- /dev/null
+++ b/bl1/aarch64/bl1_context_mgmt.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2015-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <context.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+
+#include "../bl1_private.h"
+
+/* Following contains the cpu context pointers. */
+static void *bl1_cpu_context_ptr[2];
+entry_point_info_t *bl2_ep_info;
+
+
+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;
+}
+
+#if ENABLE_RME
+/*******************************************************************************
+ * This function prepares the entry point information to run BL2 in Root world,
+ * i.e. EL3, for the case when FEAT_RME is enabled.
+ ******************************************************************************/
+void bl1_prepare_next_image(unsigned int image_id)
+{
+ image_desc_t *bl2_desc;
+
+ assert(image_id == BL2_IMAGE_ID);
+
+ /* Get the image descriptor. */
+ bl2_desc = bl1_plat_get_image_desc(BL2_IMAGE_ID);
+ assert(bl2_desc != NULL);
+
+ /* Get the entry point info. */
+ bl2_ep_info = &bl2_desc->ep_info;
+
+ bl2_ep_info->spsr = (uint32_t)SPSR_64(MODE_EL3, MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS);
+
+ /*
+ * Flush cache since bl2_ep_info is accessed after MMU is disabled
+ * before jumping to BL2.
+ */
+ flush_dcache_range((uintptr_t)bl2_ep_info, sizeof(entry_point_info_t));
+
+ /* Indicate that image is in execution state. */
+ bl2_desc->state = IMAGE_STATE_EXECUTED;
+
+ /* Print debug info and flush the console before running BL2. */
+ print_entry_point_info(bl2_ep_info);
+}
+#else
+/*******************************************************************************
+ * 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)
+{
+
+ /*
+ * 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];
+
+ unsigned int security_state, mode = MODE_EL1;
+ image_desc_t *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. */
+ desc = bl1_plat_get_image_desc(image_id);
+ assert(desc != NULL);
+
+ /* Get the entry point info. */
+ next_bl_ep = &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) == NULL)
+ 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 = (uint32_t)SPSR_64((uint64_t) mode,
+ (uint64_t)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. */
+ desc->state = IMAGE_STATE_EXECUTED;
+
+ print_entry_point_info(next_bl_ep);
+}
+#endif /* ENABLE_RME */
diff --git a/bl1/aarch64/bl1_entrypoint.S b/bl1/aarch64/bl1_entrypoint.S
new file mode 100644
index 0000000..f61c060
--- /dev/null
+++ b/bl1/aarch64/bl1_entrypoint.S
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <common/bl_common.h>
+#include <el3_common_macros.S>
+
+ .globl bl1_entrypoint
+ .globl bl1_run_bl2_in_root
+
+
+ /* -----------------------------------------------------
+ * 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 \
+ _pie_fixup_size=0
+
+ /* --------------------------------------------------------------------
+ * 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.
+ * --------------------------------------------------
+ */
+#if ENABLE_RME
+ b bl1_run_bl2_in_root
+#else
+ b el3_exit
+#endif
+endfunc bl1_entrypoint
+
+ /* -----------------------------------------------------
+ * void bl1_run_bl2_in_root();
+ * This function runs BL2 in root/EL3 when RME is enabled.
+ * -----------------------------------------------------
+ */
+
+func bl1_run_bl2_in_root
+ /* read bl2_ep_info */
+ adrp x20, bl2_ep_info
+ add x20, x20, :lo12:bl2_ep_info
+ ldr x20, [x20]
+
+ /* ---------------------------------------------
+ * MMU needs to be disabled because BL2 executes
+ * in EL3. It will initialize the address space
+ * according to its own requirements.
+ * ---------------------------------------------
+ */
+ bl disable_mmu_icache_el3
+ tlbi alle3
+
+ 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)]
+ exception_return
+endfunc bl1_run_bl2_in_root
diff --git a/bl1/aarch64/bl1_exceptions.S b/bl1/aarch64/bl1_exceptions.S
new file mode 100644
index 0000000..c54219f
--- /dev/null
+++ b/bl1/aarch64/bl1_exceptions.S
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <context.h>
+
+/* -----------------------------------------------------------------------------
+ * 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)]
+ exception_return
+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 prepare_el3_entry
+
+#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
diff --git a/bl1/bl1.ld.S b/bl1/bl1.ld.S
new file mode 100644
index 0000000..c4ec5fe
--- /dev/null
+++ b/bl1/bl1.ld.S
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * 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.
+ */
+#define DATA_ALIGN 16
+
+#include <common/bl_common.ld.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+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*)
+ *(SORT_BY_ALIGNMENT(.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__ = .;
+ *(SORT_BY_ALIGNMENT(.rodata*))
+
+ RODATA_COMMON
+
+ /*
+ * 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.
+ *
+ * Pad out to 16 bytes though as .data section needs to be 16 byte
+ * aligned and lld does not align the LMA to the aligment specified
+ * on the .data section.
+ */
+ __RODATA_END__ = .;
+ . = ALIGN(16);
+ } >ROM
+#else
+ ro . : {
+ __RO_START__ = .;
+ *bl1_entrypoint.o(.text*)
+ *(SORT_BY_ALIGNMENT(.text*))
+ *(SORT_BY_ALIGNMENT(.rodata*))
+
+ RODATA_COMMON
+
+ *(.vectors)
+ __RO_END__ = .;
+
+ /*
+ * Pad out to 16 bytes as .data section needs to be 16 byte aligned and
+ * lld does not align the LMA to the aligment specified on the .data
+ * section.
+ */
+ . = ALIGN(16);
+ } >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.")
+
+ DATA_SECTION >RAM AT>ROM
+ __DATA_RAM_START__ = __DATA_START__;
+ __DATA_RAM_END__ = __DATA_END__;
+
+ STACK_SECTION >RAM
+ BSS_SECTION >RAM
+ XLAT_TABLE_SECTION >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.")
+}
diff --git a/bl1/bl1.mk b/bl1/bl1.mk
new file mode 100644
index 0000000..9f63fd5
--- /dev/null
+++ b/bl1/bl1.mk
@@ -0,0 +1,32 @@
+#
+# Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BL1_SOURCES += bl1/${ARCH}/bl1_arch_setup.c \
+ bl1/${ARCH}/bl1_context_mgmt.c \
+ bl1/${ARCH}/bl1_entrypoint.S \
+ bl1/${ARCH}/bl1_exceptions.S \
+ bl1/bl1_main.c \
+ 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 (${DISABLE_MTPMU},1)
+BL1_SOURCES += lib/extensions/mtpmu/${ARCH}/mtpmu.S
+endif
+
+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
diff --git a/bl1/bl1_fwu.c b/bl1/bl1_fwu.c
new file mode 100644
index 0000000..b70bffd
--- /dev/null
+++ b/bl1/bl1_fwu.c
@@ -0,0 +1,745 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <drivers/auth/auth_mod.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <smccc_helpers.h>
+
+#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.
+ ******************************************************************************/
+u_register_t bl1_fwu_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,
+ unsigned int flags)
+{
+
+ switch (smc_fid) {
+ case FWU_SMC_IMAGE_COPY:
+ SMC_RET1(handle, bl1_fwu_image_copy((uint32_t)x1, x2,
+ (uint32_t)x3, (uint32_t)x4, flags));
+
+ case FWU_SMC_IMAGE_AUTH:
+ SMC_RET1(handle, bl1_fwu_image_auth((uint32_t)x1, x2,
+ (uint32_t)x3, flags));
+
+ case FWU_SMC_IMAGE_EXECUTE:
+ SMC_RET1(handle, bl1_fwu_image_execute((uint32_t)x1, &handle,
+ flags));
+
+ case FWU_SMC_IMAGE_RESUME:
+ SMC_RET1(handle, bl1_fwu_image_resume((register_t)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((uint32_t)x1, flags));
+
+ case FWU_SMC_UPDATE_DONE:
+ bl1_fwu_done((void *)x1, NULL);
+
+ default:
+ assert(false); /* 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 *desc, *checked_desc;
+ const image_info_t *info, *checked_info;
+
+ uintptr_t image_base, image_end;
+ uintptr_t checked_image_base, checked_image_end;
+
+ checked_desc = bl1_plat_get_image_desc(image_id);
+ checked_info = &checked_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;
+
+ desc = bl1_plat_get_image_desc(bl1_fwu_loaded_ids[i]);
+
+ /* Only check images that are loaded or being loaded. */
+ assert ((desc != NULL) && (desc->state != IMAGE_STATE_RESET));
+
+ info = &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_desc->image_id, 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;
+ image_desc_t *desc;
+
+ /* Get the image descriptor. */
+ desc = bl1_plat_get_image_desc(image_id);
+ if (desc == NULL) {
+ 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(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 ((desc->state != IMAGE_STATE_RESET) &&
+ (desc->state != IMAGE_STATE_COPYING)) {
+ WARN("BL1-FWU: Copy not allowed at this point of the FWU"
+ " process.\n");
+ return -EPERM;
+ }
+
+ if ((image_src == 0U) || (block_size == 0U) ||
+ 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 (desc->state == IMAGE_STATE_COPYING) {
+ /*
+ * There must have been at least 1 copy operation for this image
+ * previously.
+ */
+ assert(desc->copied_size != 0U);
+ /*
+ * The image size must have been recorded in the 1st copy
+ * operation.
+ */
+ image_size = desc->image_info.image_size;
+ assert(image_size != 0);
+ assert(desc->copied_size < image_size);
+
+ INFO("BL1-FWU: Continuing image copy in blocks\n");
+ } else { /* 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 == 0) {
+ 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 > desc->image_info.image_max_size) {
+ WARN("BL1-FWU: Image size out of bounds\n");
+ return -ENOMEM;
+ }
+
+ /* Save the given image size. */
+ desc->image_info.image_size = image_size;
+
+ /* Make sure the image doesn't overlap other images. */
+ if (bl1_fwu_image_check_overlaps(image_id) != 0) {
+ 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.
+ */
+ 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 - 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) != 0) {
+ WARN("BL1-FWU: Source image is not mapped.\n");
+ return -ENOMEM;
+ }
+
+ if (bl1_fwu_add_loaded_id(image_id) != 0) {
+ 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 (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 = desc->image_info.image_base + desc->copied_size;
+ (void)memcpy((void *) dest_addr, (const void *) image_src, block_size);
+ flush_dcache_range(dest_addr, block_size);
+
+ desc->copied_size += block_size;
+ 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;
+ image_desc_t *desc;
+
+ /* Get the image descriptor. */
+ desc = bl1_plat_get_image_desc(image_id);
+ if (desc == NULL)
+ return -EPERM;
+
+ if (GET_SECURITY_STATE(flags) == SECURE) {
+ if (desc->state != IMAGE_STATE_RESET) {
+ WARN("BL1-FWU: Authentication from secure world "
+ "while in invalid state\n");
+ return -EPERM;
+ }
+ } else {
+ if (GET_SECURITY_STATE(desc->ep_info.h.attr) == SECURE) {
+ if (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 (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 (desc->state == IMAGE_STATE_COPIED) {
+ /*
+ * Image is in COPIED state.
+ * Use the stored address and size.
+ */
+ base_addr = desc->image_info.image_base;
+ total_size = desc->image_info.image_size;
+ } else {
+ if ((image_src == 0U) || (image_size == 0U) ||
+ 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, \
+ desc->ep_info.h.attr) != 0) {
+ WARN("BL1-FWU: Authentication arguments source/size not mapped\n");
+ return -ENOMEM;
+ }
+
+ if (bl1_fwu_add_loaded_id(image_id) != 0) {
+ 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. */
+ 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 (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*/
+ 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.
+ */
+ (void)bl1_fwu_remove_loaded_id(image_id);
+ return -EAUTH;
+ }
+
+ /* Indicate that image is in authenticated state. */
+ 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)&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 *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 ((desc == NULL) ||
+ (GET_SECURITY_STATE(flags) == SECURE) ||
+ (GET_SECURITY_STATE(desc->ep_info.h.attr) == NON_SECURE) ||
+ (EP_GET_EXE(desc->ep_info.h.attr) == NON_EXECUTABLE) ||
+ (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 *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. */
+ desc = bl1_plat_get_image_desc(sec_exec_image_id);
+ if (caller_sec_state == NON_SECURE) {
+ if (desc == NULL) {
+ WARN("BL1-FWU: Resume not allowed due to no available"
+ "secure image\n");
+ return -EPERM;
+ }
+ } else {
+ /* desc must be valid for secure world callers */
+ assert(desc != NULL);
+ }
+
+ assert(GET_SECURITY_STATE(desc->ep_info.h.attr) == SECURE);
+ assert(EP_GET_EXE(desc->ep_info.h.attr) == EXECUTABLE);
+
+ if (caller_sec_state == SECURE) {
+ assert(desc->state == IMAGE_STATE_EXECUTED);
+
+ /* Update the flags. */
+ desc->state = IMAGE_STATE_INTERRUPTED;
+ resume_sec_state = NON_SECURE;
+ } else {
+ assert(desc->state == IMAGE_STATE_INTERRUPTED);
+
+ /* Update the flags. */
+ 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 *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 */
+ desc = bl1_plat_get_image_desc(sec_exec_image_id);
+
+ /* desc must correspond to a valid secure executing image */
+ assert(desc != NULL);
+ assert(GET_SECURITY_STATE(desc->ep_info.h.attr) == SECURE);
+ assert(EP_GET_EXE(desc->ep_info.h.attr) == EXECUTABLE);
+ assert(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. */
+ 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(false);
+}
+
+/*******************************************************************************
+ * 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 *desc = bl1_plat_get_image_desc(image_id);
+
+ if ((desc == NULL) || (GET_SECURITY_STATE(flags) == SECURE)) {
+ WARN("BL1-FWU: Reset not allowed due to invalid args\n");
+ return -EPERM;
+ }
+
+ switch (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) != 0) {
+ WARN("BL1-FWU: Image reset couldn't find the image ID\n");
+ return -EPERM;
+ }
+
+ if (desc->copied_size != 0U) {
+ /* Clear the memory if the image is copied */
+ assert(GET_SECURITY_STATE(desc->ep_info.h.attr)
+ == SECURE);
+
+ zero_normalmem((void *)desc->image_info.image_base,
+ desc->copied_size);
+ flush_dcache_range(desc->image_info.image_base,
+ desc->copied_size);
+ }
+
+ /* Reset status variables */
+ desc->copied_size = 0;
+ desc->image_info.image_size = 0;
+ desc->state = IMAGE_STATE_RESET;
+
+ /* Clear authentication state */
+ auth_img_flags[image_id] = 0;
+
+ break;
+
+ case IMAGE_STATE_EXECUTED:
+ default:
+ assert(false); /* Unreachable */
+ break;
+ }
+
+ return 0;
+}
diff --git a/bl1/bl1_main.c b/bl1/bl1_main.c
new file mode 100644
index 0000000..7399bc8
--- /dev/null
+++ b/bl1/bl1_main.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/auth/auth_mod.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/console.h>
+#include <lib/cpus/errata_report.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <smccc_helpers.h>
+#include <tools_share/uuid.h>
+
+#include "bl1_private.h"
+
+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) != 0);
+ assert((val & SCTLR_C_BIT) != 0);
+ assert((val & SCTLR_I_BIT) != 0);
+ /*
+ * 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();
+
+ crypto_mod_init();
+
+ /* Initialize authentication module */
+ auth_mod_init();
+
+ /* Initialize the measured boot */
+ bl1_plat_mboot_init();
+
+ /* 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");
+
+ /* Teardown the measured boot driver */
+ bl1_plat_mboot_finish();
+
+ 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 *desc;
+ image_info_t *info;
+ int err;
+
+ /* Get the image descriptor */
+ desc = bl1_plat_get_image_desc(BL2_IMAGE_ID);
+ assert(desc != NULL);
+
+ /* Get the image info */
+ info = &desc->image_info;
+ INFO("BL1: Loading BL2\n");
+
+ err = bl1_plat_handle_pre_image_load(BL2_IMAGE_ID);
+ if (err != 0) {
+ ERROR("Failure in pre image load handling of BL2 (%d)\n", err);
+ plat_error_handler(err);
+ }
+
+ err = load_auth_image(BL2_IMAGE_ID, info);
+ if (err != 0) {
+ 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 != 0) {
+ 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.
+ ******************************************************************************/
+u_register_t bl1_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,
+ unsigned int flags)
+{
+ /* BL1 Service UUID */
+ DEFINE_SVC_UUID2(bl1_svc_uid,
+ U(0xd46739fd), 0xcb72, 0x9a4d, 0xb5, 0x75,
+ 0x67, 0x15, 0xd6, 0xf4, 0xbb, 0x4a);
+
+
+#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:
+ 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.
+ ******************************************************************************/
+u_register_t bl1_smc_wrapper(uint32_t smc_fid,
+ void *cookie,
+ void *handle,
+ unsigned int flags)
+{
+ u_register_t x1, x2, x3, x4;
+
+ assert(handle != NULL);
+
+ get_smc_params_from_ctx(handle, x1, x2, x3, x4);
+ return bl1_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
+}
diff --git a/bl1/bl1_private.h b/bl1/bl1_private.h
new file mode 100644
index 0000000..e119ba7
--- /dev/null
+++ b/bl1/bl1_private.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BL1_PRIVATE_H
+#define BL1_PRIVATE_H
+
+#include <stdint.h>
+
+#include <common/bl_common.h>
+
+extern entry_point_info_t *bl2_ep_info;
+
+/******************************************
+ * Function prototypes
+ *****************************************/
+void bl1_arch_setup(void);
+void bl1_arch_next_el_setup(void);
+
+void bl1_prepare_next_image(unsigned int image_id);
+void bl1_run_bl2_in_root(void);
+
+u_register_t bl1_fwu_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,
+ unsigned int flags);
+
+#endif /* BL1_PRIVATE_H */
diff --git a/bl1/tbbr/tbbr_img_desc.c b/bl1/tbbr/tbbr_img_desc.c
new file mode 100644
index 0000000..4836712
--- /dev/null
+++ b/bl1/tbbr/tbbr_img_desc.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <bl1/tbbr/tbbr_img_desc.h>
+#include <common/bl_common.h>
+
+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,
+ }
+};
diff --git a/bl2/aarch32/bl2_arch_setup.c b/bl2/aarch32/bl2_arch_setup.c
new file mode 100644
index 0000000..4fd8d07
--- /dev/null
+++ b/bl2/aarch32/bl2_arch_setup.c
@@ -0,0 +1,16 @@
+/*
+ * 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)
+{
+
+}
diff --git a/bl2/aarch32/bl2_el3_entrypoint.S b/bl2/aarch32/bl2_el3_entrypoint.S
new file mode 100644
index 0000000..40154aa
--- /dev/null
+++ b/bl2/aarch32/bl2_el3_entrypoint.S
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <el3_common_macros.S>
+
+ .globl bl2_entrypoint
+
+
+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 \
+ _pie_fixup_size=0
+
+ /*
+ * 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
diff --git a/bl2/aarch32/bl2_el3_exceptions.S b/bl2/aarch32/bl2_el3_exceptions.S
new file mode 100644
index 0000000..eaa2582
--- /dev/null
+++ b/bl2/aarch32/bl2_el3_exceptions.S
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+
+ .globl bl2_vector_table
+
+vector_base bl2_vector_table
+ b bl2_entrypoint
+ b report_exception /* Undef */
+ b report_exception /* SVC call */
+ b report_prefetch_abort /* Prefetch abort */
+ b report_data_abort /* Data abort */
+ b report_exception /* Reserved */
+ b report_exception /* IRQ */
+ b report_exception /* FIQ */
diff --git a/bl2/aarch32/bl2_entrypoint.S b/bl2/aarch32/bl2_entrypoint.S
new file mode 100644
index 0000000..678d9c2
--- /dev/null
+++ b/bl2/aarch32/bl2_entrypoint.S
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+
+ .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_prefetch_abort /* Prefetch abort */
+ b report_data_abort /* 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_END__
+ sub r1, r1, r0
+ bl zeromem
+
+#if USE_COHERENT_MEM
+ ldr r0, =__COHERENT_RAM_START__
+ ldr r1, =__COHERENT_RAM_END_UNALIGNED__
+ sub r1, r1, r0
+ 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
diff --git a/bl2/aarch32/bl2_run_next_image.S b/bl2/aarch32/bl2_run_next_image.S
new file mode 100644
index 0000000..0b3554e
--- /dev/null
+++ b/bl2/aarch32/bl2_run_next_image.S
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+
+ .globl bl2_run_next_image
+
+
+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}
+ exception_return
+endfunc bl2_run_next_image
diff --git a/bl2/aarch64/bl2_arch_setup.c b/bl2/aarch64/bl2_arch_setup.c
new file mode 100644
index 0000000..54052f7
--- /dev/null
+++ b/bl2/aarch64/bl2_arch_setup.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#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));
+}
diff --git a/bl2/aarch64/bl2_el3_entrypoint.S b/bl2/aarch64/bl2_el3_entrypoint.S
new file mode 100644
index 0000000..45bac7d
--- /dev/null
+++ b/bl2/aarch64/bl2_el3_entrypoint.S
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <el3_common_macros.S>
+
+ .globl bl2_entrypoint
+
+#if BL2_IN_XIP_MEM
+#define FIXUP_SIZE 0
+#else
+#define FIXUP_SIZE ((BL2_LIMIT) - (BL2_BASE))
+#endif
+
+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 \
+ _pie_fixup_size=FIXUP_SIZE
+
+ /* ---------------------------------------------
+ * 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
diff --git a/bl2/aarch64/bl2_el3_exceptions.S b/bl2/aarch64/bl2_el3_exceptions.S
new file mode 100644
index 0000000..3d58051
--- /dev/null
+++ b/bl2/aarch64/bl2_el3_exceptions.S
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <context.h>
+
+/* -----------------------------------------------------------------------------
+ * 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
diff --git a/bl2/aarch64/bl2_entrypoint.S b/bl2/aarch64/bl2_entrypoint.S
new file mode 100644
index 0000000..a021e42
--- /dev/null
+++ b/bl2/aarch64/bl2_entrypoint.S
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+
+
+ .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
diff --git a/bl2/aarch64/bl2_rme_entrypoint.S b/bl2/aarch64/bl2_rme_entrypoint.S
new file mode 100644
index 0000000..076e326
--- /dev/null
+++ b/bl2/aarch64/bl2_rme_entrypoint.S
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <el3_common_macros.S>
+
+ .globl bl2_entrypoint
+
+
+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=0 \
+ _warm_boot_mailbox=0 \
+ _secondary_cold_boot=0 \
+ _init_memory=0 \
+ _init_c_runtime=1 \
+ _exception_vectors=bl2_el3_exceptions \
+ _pie_fixup_size=0
+
+ /* ---------------------------------------------
+ * Restore parameters of boot rom
+ * ---------------------------------------------
+ */
+ mov x0, x20
+ mov x1, x21
+ mov x2, x22
+ mov x3, x23
+
+ /* ---------------------------------------------
+ * Perform BL2 setup
+ * ---------------------------------------------
+ */
+ bl bl2_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
diff --git a/bl2/aarch64/bl2_run_next_image.S b/bl2/aarch64/bl2_run_next_image.S
new file mode 100644
index 0000000..f0a8be8
--- /dev/null
+++ b/bl2/aarch64/bl2_run_next_image.S
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+
+ .globl bl2_run_next_image
+
+
+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)]
+ exception_return
+endfunc bl2_run_next_image
diff --git a/bl2/bl2.ld.S b/bl2/bl2.ld.S
new file mode 100644
index 0000000..80cf7db
--- /dev/null
+++ b/bl2/bl2.ld.S
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.ld.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+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__ = .;
+#if ENABLE_RME
+ *bl2_rme_entrypoint.o(.text*)
+#else /* ENABLE_RME */
+ *bl2_entrypoint.o(.text*)
+#endif /* ENABLE_RME */
+ *(SORT_BY_ALIGNMENT(.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__ = .;
+ *(SORT_BY_ALIGNMENT(.rodata*))
+
+ RODATA_COMMON
+
+ . = ALIGN(PAGE_SIZE);
+ __RODATA_END__ = .;
+ } >RAM
+#else
+ ro . : {
+ __RO_START__ = .;
+ *bl2_entrypoint.o(.text*)
+ *(SORT_BY_ALIGNMENT(.text*))
+ *(SORT_BY_ALIGNMENT(.rodata*))
+
+ RODATA_COMMON
+
+ *(.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_SECTION >RAM
+ STACK_SECTION >RAM
+ BSS_SECTION >RAM
+ XLAT_TABLE_SECTION >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.")
+}
diff --git a/bl2/bl2.mk b/bl2/bl2.mk
new file mode 100644
index 0000000..7a973e5
--- /dev/null
+++ b/bl2/bl2.mk
@@ -0,0 +1,50 @@
+#
+# Copyright (c) 2013-2021, 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 (${ENABLE_RME},1)
+# Using RME, run BL2 at EL3
+include lib/gpt_rme/gpt_rme.mk
+
+BL2_SOURCES += bl2/${ARCH}/bl2_rme_entrypoint.S \
+ bl2/${ARCH}/bl2_el3_exceptions.S \
+ bl2/${ARCH}/bl2_run_next_image.S \
+ ${GPT_LIB_SRCS}
+BL2_LINKERFILE := bl2/bl2.ld.S
+
+else ifeq (${BL2_AT_EL3},0)
+# Normal operation, no RME, no BL2 at EL3
+BL2_SOURCES += bl2/${ARCH}/bl2_entrypoint.S
+BL2_LINKERFILE := bl2/bl2.ld.S
+
+else
+# BL2 at EL3, no RME
+BL2_SOURCES += bl2/${ARCH}/bl2_el3_entrypoint.S \
+ bl2/${ARCH}/bl2_el3_exceptions.S \
+ bl2/${ARCH}/bl2_run_next_image.S \
+ lib/cpus/${ARCH}/cpu_helpers.S \
+ lib/cpus/errata_report.c
+
+ifeq (${DISABLE_MTPMU},1)
+BL2_SOURCES += lib/extensions/mtpmu/${ARCH}/mtpmu.S
+endif
+
+ifeq (${ARCH},aarch64)
+BL2_SOURCES += lib/cpus/aarch64/dsu_helpers.S
+endif
+
+BL2_LINKERFILE := bl2/bl2_el3.ld.S
+endif
diff --git a/bl2/bl2_el3.ld.S b/bl2/bl2_el3.ld.S
new file mode 100644
index 0000000..c95706c
--- /dev/null
+++ b/bl2/bl2_el3.ld.S
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.ld.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+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 SEPARATE_BL2_NOLOAD_REGION
+ RAM_NOLOAD (rw!a): ORIGIN = BL2_NOLOAD_START, LENGTH = BL2_NOLOAD_LIMIT - BL2_NOLOAD_START
+#else
+#define RAM_NOLOAD RAM
+#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__ = .;
+ *(SORT_BY_ALIGNMENT(.text*))
+ *(.vectors)
+ . = ALIGN(PAGE_SIZE);
+ __TEXT_END__ = .;
+ } >ROM
+
+ .rodata . : {
+ __RODATA_START__ = .;
+ *(SORT_BY_ALIGNMENT(.rodata*))
+
+ RODATA_COMMON
+
+ . = 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__ = .;
+ *(SORT_BY_ALIGNMENT(.text*))
+ *(SORT_BY_ALIGNMENT(.rodata*))
+
+ RODATA_COMMON
+
+ *(.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_SECTION >RAM AT>ROM
+ __DATA_RAM_START__ = __DATA_START__;
+ __DATA_RAM_END__ = __DATA_END__;
+
+ RELA_SECTION >RAM
+#if SEPARATE_BL2_NOLOAD_REGION
+ SAVED_ADDR = .;
+ . = BL2_NOLOAD_START;
+ __BL2_NOLOAD_START__ = .;
+#endif
+ STACK_SECTION >RAM_NOLOAD
+ BSS_SECTION >RAM_NOLOAD
+ XLAT_TABLE_SECTION >RAM_NOLOAD
+#if SEPARATE_BL2_NOLOAD_REGION
+ __BL2_NOLOAD_END__ = .;
+ . = SAVED_ADDR;
+#endif
+
+#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__ = .;
+
+ /DISCARD/ : {
+ *(.dynsym .dynstr .hash .gnu.hash)
+ }
+
+#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
+}
diff --git a/bl2/bl2_image_load_v2.c b/bl2/bl2_image_load_v2.c
new file mode 100644
index 0000000..dee3fc2
--- /dev/null
+++ b/bl2/bl2_image_load_v2.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include "bl2_private.h"
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/auth/auth_mod.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.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 != NULL);
+ assert(bl2_load_info->head != NULL);
+ 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 != NULL) {
+ /*
+ * 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) != 0U) {
+ if (plat_setup_done != 0) {
+ 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 != 0) {
+ 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) == 0U) {
+ INFO("BL2: Loading image id %u\n", bl2_node_info->image_id);
+ err = load_auth_image(bl2_node_info->image_id,
+ bl2_node_info->image_info);
+ if (err != 0) {
+ ERROR("BL2: Failed to load image id %u (%i)\n",
+ bl2_node_info->image_id, err);
+ plat_error_handler(err);
+ }
+ } else {
+ INFO("BL2: Skip loading image id %u\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 != 0) {
+ 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 != NULL);
+ assert(bl2_to_next_bl_params->head != NULL);
+ 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 != NULL);
+
+ /* 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;
+}
diff --git a/bl2/bl2_main.c b/bl2/bl2_main.c
new file mode 100644
index 0000000..5da8037
--- /dev/null
+++ b/bl2/bl2_main.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <arch_features.h>
+#include <bl1/bl1.h>
+#include <bl2/bl2.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/auth/auth_mod.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/console.h>
+#include <drivers/fwu/fwu.h>
+#include <lib/extensions/pauth.h>
+#include <plat/common/platform.h>
+
+#include "bl2_private.h"
+
+#ifdef __aarch64__
+#define NEXT_IMAGE "BL31"
+#else
+#define NEXT_IMAGE "BL32"
+#endif
+
+#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 */
+}
+#else /* BL2_AT_EL3 */
+/*******************************************************************************
+ * Setup function for BL2 when BL2_AT_EL3=0
+ ******************************************************************************/
+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 */
+}
+#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 PSA_FWU_SUPPORT
+ fwu_init();
+#endif /* PSA_FWU_SUPPORT */
+
+ crypto_mod_init();
+
+ /* Initialize authentication module */
+ auth_mod_init();
+
+ /* Initialize the Measured Boot backend */
+ bl2_plat_mboot_init();
+
+ /* Initialize boot source */
+ bl2_plat_preload_setup();
+
+ /* Load the subsequent bootloader images. */
+ next_bl_ep_info = bl2_load_images();
+
+ /* Teardown the Measured Boot backend */
+ bl2_plat_mboot_finish();
+
+#if !BL2_AT_EL3 && !ENABLE_RME
+#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 || ENABLE_RME */
+ 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 && ENABLE_RME */
+}
diff --git a/bl2/bl2_private.h b/bl2/bl2_private.h
new file mode 100644
index 0000000..b1704d2
--- /dev/null
+++ b/bl2/bl2_private.h
@@ -0,0 +1,24 @@
+/*
+ * 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 <common/bl_common.h>
+
+/******************************************
+ * 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 */
diff --git a/bl2u/aarch32/bl2u_entrypoint.S b/bl2u/aarch32/bl2u_entrypoint.S
new file mode 100644
index 0000000..1063789
--- /dev/null
+++ b/bl2u/aarch32/bl2u_entrypoint.S
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+
+ .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_prefetch_abort /* Prefetch abort */
+ b report_data_abort /* 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_END__
+ sub r1, r1, r0
+ 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
diff --git a/bl2u/aarch64/bl2u_entrypoint.S b/bl2u/aarch64/bl2u_entrypoint.S
new file mode 100644
index 0000000..15978b6
--- /dev/null
+++ b/bl2u/aarch64/bl2u_entrypoint.S
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+
+ .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.
+ * ---------------------------------------------
+ */
+ 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
+
+ /* --------------------------------------------
+ * 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
diff --git a/bl2u/bl2u.ld.S b/bl2u/bl2u.ld.S
new file mode 100644
index 0000000..a7752a4
--- /dev/null
+++ b/bl2u/bl2u.ld.S
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.ld.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+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*)
+ *(SORT_BY_ALIGNMENT(.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__ = .;
+ *(SORT_BY_ALIGNMENT(.rodata*))
+
+ RODATA_COMMON
+
+ . = ALIGN(PAGE_SIZE);
+ __RODATA_END__ = .;
+ } >RAM
+#else
+ ro . : {
+ __RO_START__ = .;
+ *bl2u_entrypoint.o(.text*)
+ *(SORT_BY_ALIGNMENT(.text*))
+ *(SORT_BY_ALIGNMENT(.rodata*))
+
+ RODATA_COMMON
+
+ *(.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_SECTION >RAM
+ STACK_SECTION >RAM
+ BSS_SECTION >RAM
+ XLAT_TABLE_SECTION >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.")
+}
diff --git a/bl2u/bl2u.mk b/bl2u/bl2u.mk
new file mode 100644
index 0000000..b4d7634
--- /dev/null
+++ b/bl2u/bl2u.mk
@@ -0,0 +1,15 @@
+#
+# 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
diff --git a/bl2u/bl2u_main.c b/bl2u/bl2u_main.c
new file mode 100644
index 0000000..fcb73b9
--- /dev/null
+++ b/bl2u/bl2u_main.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <bl1/bl1.h>
+#include <bl2u/bl2u.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/auth/auth_mod.h>
+#include <drivers/console.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * 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 != 0) {
+ 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();
+}
diff --git a/bl31/aarch64/bl31_entrypoint.S b/bl31/aarch64/bl31_entrypoint.S
new file mode 100644
index 0000000..b0c46dc
--- /dev/null
+++ b/bl31/aarch64/bl31_entrypoint.S
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <common/bl_common.h>
+#include <el3_common_macros.S>
+#include <lib/pmf/aarch64/pmf_asm_macros.S>
+#include <lib/runtime_instr.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+
+ .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 !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 \
+ _pie_fixup_size=BL31_LIMIT - BL31_BASE
+#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 \
+ _pie_fixup_size=BL31_LIMIT - BL31_BASE
+
+#if !RESET_TO_BL31_WITH_PARAMS
+ /* ---------------------------------------------------------------------
+ * 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_WITH_PARAMS */
+#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.
+ * --------------------------------------------------------------------
+ */
+ adrp x0, __DATA_START__
+ add x0, x0, :lo12:__DATA_START__
+ adrp x1, __DATA_END__
+ add x1, x1, :lo12:__DATA_END__
+ sub x1, x1, x0
+ bl clean_dcache_range
+
+ 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 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 \
+ _pie_fixup_size=0
+
+ /*
+ * 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_RME
+ /*
+ * At warm boot GPT data structures have already been initialized in RAM
+ * but the sysregs for this CPU need to be initialized. Note that the GPT
+ * accesses are controlled attributes in GPCCR and do not depend on the
+ * SCR_EL3.C bit.
+ */
+ bl gpt_enable
+ cbz x0, 1f
+ no_ret plat_panic_handler
+1:
+#endif
+
+#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
diff --git a/bl31/aarch64/crash_reporting.S b/bl31/aarch64/crash_reporting.S
new file mode 100644
index 0000000..d56b513
--- /dev/null
+++ b/bl31/aarch64/crash_reporting.S
@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_macros.S>
+#include <platform_def.h>
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <context.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/utils_def.h>
+
+ .globl report_unhandled_exception
+ .globl report_unhandled_interrupt
+ .globl el3_panic
+ .globl elx_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:
+ .ascii "Unhandled Interrupt Exception in EL3.\n"
+x30_msg:
+ .asciz "x30"
+excpt_msg_el:
+ .asciz "Unhandled Exception from EL"
+
+ /*
+ * 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 from the lower
+ * exception level (if crash reporting is enabled) when
+ * panic() is invoked from C Runtime.
+ * It prints the CPU state via the crash console making
+ * use of 'cpu_context' structure where general purpose
+ * registers are saved and the crash buf.
+ * This function will not return.
+ *
+ * x0: Exception level
+ * -----------------------------------------------------
+ */
+func elx_panic
+ msr spsel, #MODE_SP_ELX
+ mov x8, x0
+
+ /* Print the crash message */
+ adr x4, excpt_msg_el
+ bl asm_print_str
+
+ /* Print exception level */
+ add x0, x8, #'0'
+ bl plat_crash_console_putc
+ bl asm_print_newline
+
+ /* Report x0 - x29 values stored in 'gpregs_ctx' structure */
+ /* Store the ascii list pointer in x6 */
+ adr x6, gp_regs
+ add x7, sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0
+
+print_next:
+ ldrb w4, [x6]
+ /* Test whether we are at end of list */
+ cbz w4, print_x30
+ 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 print_next
+
+print_x30:
+ adr x4, x30_msg
+ bl asm_print_str
+
+ /* Print spaces to align "x30" string */
+ mov x0, #4
+ bl print_alignment
+
+ /* Report x30 */
+ ldr x4, [x7]
+
+ /* ----------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------
+ */
+ cmp x8, #MODE_EL2
+ b.lt from_el1 /* EL1 */
+ mrs x2, sctlr_el2
+ mrs x1, tcr_el2
+
+ /* ----------------------------------------------------------------
+ * Check if pointer authentication is enabled at the specified EL.
+ * If it isn't, we can then skip stripping a PAC code.
+ * ----------------------------------------------------------------
+ */
+test_pauth:
+ tst x2, #(SCTLR_EnIA_BIT | SCTLR_EnIB_BIT)
+ b.eq no_pauth
+
+ /* Demangle address */
+ and x1, x1, #0x3F /* T0SZ = TCR_ELx[5:0] */
+ sub x1, x1, #64
+ neg x1, x1 /* bottom_pac_bit = 64 - T0SZ */
+ mov x2, #-1
+ lsl x2, x2, x1
+ bic x4, x4, x2
+
+no_pauth:
+ bl asm_print_hex
+ bl asm_print_newline
+
+ /* 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
+
+ /* Print the rest of crash dump */
+ b print_el3_sys_regs
+
+from_el1:
+ mrs x2, sctlr_el1
+ mrs x1, tcr_el1
+ b test_pauth
+endfunc elx_panic
+
+ /* -----------------------------------------------------
+ * 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
+ /* Fall through to 'do_crash_reporting' */
+
+ /* ------------------------------------------------------------
+ * 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.
+ * ------------------------------------------------------------
+ */
+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]
+
+#if ENABLE_PAUTH
+ /* Demangle address */
+ xpaci x4
+#endif
+ 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 */
+print_el3_sys_regs:
+ 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 el3_panic
+
+#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
diff --git a/bl31/aarch64/ea_delegate.S b/bl31/aarch64/ea_delegate.S
new file mode 100644
index 0000000..dbb3234
--- /dev/null
+++ b/bl31/aarch64/ea_delegate.S
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#include <assert_macros.S>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <bl31/ea_handle.h>
+#include <context.h>
+#include <lib/extensions/ras_arch.h>
+#include <cpu_macros.S>
+#include <context.h>
+
+ .globl handle_lower_el_ea_esb
+ .globl handle_lower_el_async_ea
+ .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:
+ /*
+ * 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.
+ * Also set the PSTATE to a known state.
+ */
+ bl prepare_el3_entry
+
+#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
+ bl delegate_sync_ea
+
+ /* el3_exit assumes SP_EL0 on entry */
+ msr spsel, #MODE_SP_EL0
+ b el3_exit
+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]
+
+ /* 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]
+
+handle_lower_el_async_ea:
+ /*
+ * 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.
+ * Also set the PSTATE to a known state.
+ */
+ bl prepare_el3_entry
+
+#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
+ bl delegate_async_ea
+
+ /* el3_exit assumes SP_EL0 on entry */
+ msr spsel, #MODE_SP_EL0
+ b el3_exit
+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 Exception Class to ensure SError, as this function should
+ * only be invoked for SError. If that is not the case, which implies
+ * either an HW error or programming error, panic.
+ */
+ ubfx x2, x1, #ESR_EC_SHIFT, #ESR_EC_LENGTH
+ cmp x2, EC_SERROR
+ b.ne do_panic
+ /*
+ * 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
+
+ /* AET only valid when DFSC is 0x11 */
+ ubfx x2, x1, #EABORT_DFSC_SHIFT, #EABORT_DFSC_WIDTH
+ cmp x2, #DFSC_SERROR
+ b.ne 1f
+
+ /*
+ * Check for Uncontainable error type. If so, route to the platform
+ * fatal error handler rather than the generic EA one.
+ */
+ ubfx x3, x1, #EABORT_AET_SHIFT, #EABORT_AET_WIDTH
+ cmp x3, #ERROR_STATUS_UET_UC
+ 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
diff --git a/bl31/aarch64/runtime_exceptions.S b/bl31/aarch64/runtime_exceptions.S
new file mode 100644
index 0000000..0283553
--- /dev/null
+++ b/bl31/aarch64/runtime_exceptions.S
@@ -0,0 +1,631 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <bl31/ea_handle.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/runtime_svc.h>
+#include <context.h>
+#include <el3_common_macros.S>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/smccc.h>
+
+ .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 synchronizes pending errors using
+ * a DSB, unmasks Asynchronous External Aborts and saves X30 before
+ * setting the flag CTX_IS_IN_EL3.
+ */
+ .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.
+ * Also set the PSTATE to a known state.
+ */
+ bl prepare_el3_entry
+
+ bl handle_lower_el_ea_esb
+
+ /* Restore general purpose, PMCR_EL0 and ARMv8.3-PAuth registers */
+ bl restore_gp_pmcr_pauth_regs
+1:
+#else
+ /*
+ * For SoCs which do not implement RAS, use DSB as a barrier to
+ * synchronize pending external aborts.
+ */
+ dsb sy
+
+ /* Unmask the SError interrupt */
+ msr daifclr, #DAIF_ABT_BIT
+
+ /* Use ISB for the above unmask operation to take effect immediately */
+ isb
+
+ /*
+ * Refer Note 1. No need to restore X30 as both handle_sync_exception
+ * and handle_interrupt_exception macro which follow this macro modify
+ * X30 anyway.
+ */
+ str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+ mov x30, #1
+ str x30, [sp, #CTX_EL3STATE_OFFSET + CTX_IS_IN_EL3]
+ dmb sy
+#endif
+ .endm
+
+#if !RAS_EXTENSION
+ /*
+ * Note 1: The explicit DSB at the entry of various exception vectors
+ * for handling exceptions from lower ELs can inadvertently trigger an
+ * SError exception in EL3 due to pending asynchronous aborts in lower
+ * ELs. This will end up being handled by serror_sp_elx which will
+ * ultimately panic and die.
+ * The way to workaround is to update a flag to indicate if the exception
+ * truly came from EL3. This flag is allocated in the cpu_context
+ * structure and located at offset "CTX_EL3STATE_OFFSET + CTX_IS_IN_EL3"
+ * This is not a bullet proof solution to the problem at hand because
+ * we assume the instructions following "isb" that help to update the
+ * flag execute without causing further exceptions.
+ */
+
+ /* ---------------------------------------------------------------------
+ * This macro handles Asynchronous External Aborts.
+ * ---------------------------------------------------------------------
+ */
+ .macro handle_async_ea
+ /*
+ * Use a barrier to synchronize pending external aborts.
+ */
+ dsb sy
+
+ /* Unmask the SError interrupt */
+ msr daifclr, #DAIF_ABT_BIT
+
+ /* Use ISB for the above unmask operation to take effect immediately */
+ isb
+
+ /* Refer Note 1 */
+ str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+ mov x30, #1
+ str x30, [sp, #CTX_EL3STATE_OFFSET + CTX_IS_IN_EL3]
+ dmb sy
+
+ b handle_lower_el_async_ea
+ .endm
+
+ /*
+ * This macro checks if the exception was taken due to SError in EL3 or
+ * because of pending asynchronous external aborts from lower EL that got
+ * triggered due to explicit synchronization in EL3. Refer Note 1.
+ */
+ .macro check_if_serror_from_EL3
+ /* Assumes SP_EL3 on entry */
+ str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+ ldr x30, [sp, #CTX_EL3STATE_OFFSET + CTX_IS_IN_EL3]
+ cbnz x30, exp_from_EL3
+
+ /* Handle asynchronous external abort from lower EL */
+ b handle_lower_el_async_ea
+
+exp_from_EL3:
+ /* Jump to plat_handle_el3_ea which does not return */
+ .endm
+#endif
+
+ /* ---------------------------------------------------------------------
+ * 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.
+ * Also set the PSTATE to a known state.
+ */
+ bl prepare_el3_entry
+
+#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
+#if !RAS_EXTENSION
+ check_if_serror_from_EL3
+#endif
+ 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.
+ */
+ apply_at_speculative_wa
+ check_and_unmask_ea
+ handle_sync_exception
+end_vector_entry sync_exception_aarch64
+
+vector_entry irq_aarch64
+ apply_at_speculative_wa
+ check_and_unmask_ea
+ handle_interrupt_exception irq_aarch64
+end_vector_entry irq_aarch64
+
+vector_entry fiq_aarch64
+ apply_at_speculative_wa
+ check_and_unmask_ea
+ handle_interrupt_exception fiq_aarch64
+end_vector_entry fiq_aarch64
+
+vector_entry serror_aarch64
+ apply_at_speculative_wa
+#if RAS_EXTENSION
+ msr daifclr, #DAIF_ABT_BIT
+ b enter_lower_el_async_ea
+#else
+ handle_async_ea
+#endif
+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.
+ */
+ apply_at_speculative_wa
+ check_and_unmask_ea
+ handle_sync_exception
+end_vector_entry sync_exception_aarch32
+
+vector_entry irq_aarch32
+ apply_at_speculative_wa
+ check_and_unmask_ea
+ handle_interrupt_exception irq_aarch32
+end_vector_entry irq_aarch32
+
+vector_entry fiq_aarch32
+ apply_at_speculative_wa
+ check_and_unmask_ea
+ handle_interrupt_exception fiq_aarch32
+end_vector_entry fiq_aarch32
+
+vector_entry serror_aarch32
+ apply_at_speculative_wa
+#if RAS_EXTENSION
+ msr daifclr, #DAIF_ABT_BIT
+ b enter_lower_el_async_ea
+#else
+ handle_async_ea
+#endif
+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.
+ * Also set the PSTATE to a known state.
+ */
+ bl prepare_el3_entry
+
+#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]
+
+ /* Clear flag register */
+ mov x7, xzr
+
+#if ENABLE_RME
+ /* Copy SCR_EL3.NSE bit to the flag to indicate caller's security */
+ ubfx x7, x18, #SCR_NSE_SHIFT, 1
+
+ /*
+ * Shift copied SCR_EL3.NSE bit by 5 to create space for
+ * SCR_EL3.NS bit. Bit 5 of the flag corresponds to
+ * the SCR_EL3.NSE bit.
+ */
+ lsl x7, x7, #5
+#endif /* ENABLE_RME */
+
+ /* Copy SCR_EL3.NS bit to the flag to indicate caller's security */
+ bfi x7, x18, #0, #1
+
+ /*
+ * Per SMCCCv1.3 a caller can set the SVE hint bit in the SMC FID
+ * passed through x0. Copy the SVE hint bit to flags and mask the
+ * bit in smc_fid passed to the standard service dispatcher.
+ * A service/dispatcher can retrieve the SVE hint bit state from
+ * flags using the appropriate helper.
+ */
+ bfi x7, x0, #FUNCID_SVE_HINT_SHIFT, #FUNCID_SVE_HINT_MASK
+ bic x0, x0, #(FUNCID_SVE_HINT_MASK << FUNCID_SVE_HINT_SHIFT)
+
+ 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 */
+ adrp x14, rt_svc_descs_indices
+ add x14, x14, :lo12: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:
+ restore_ptw_el1_sys_regs
+ ldp x28, x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X28]
+ ldr x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+ mov x0, #SMC_UNK
+ exception_return
+
+#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 */
diff --git a/bl31/bl31.ld.S b/bl31/bl31.ld.S
new file mode 100644
index 0000000..309e752
--- /dev/null
+++ b/bl31/bl31.ld.S
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.ld.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
+OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
+ENTRY(bl31_entrypoint)
+
+
+MEMORY {
+ RAM (rwx): ORIGIN = BL31_BASE, LENGTH = BL31_LIMIT - BL31_BASE
+#if SEPARATE_NOBITS_REGION
+ NOBITS (rw!a): ORIGIN = BL31_NOBITS_BASE, LENGTH = BL31_NOBITS_LIMIT - BL31_NOBITS_BASE
+#else
+#define NOBITS RAM
+#endif
+}
+
+#ifdef PLAT_EXTRA_LD_SCRIPT
+#include <plat.ld.S>
+#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*)
+ *(SORT_BY_ALIGNMENT(SORT(.text*)))
+ *(.vectors)
+ . = ALIGN(PAGE_SIZE);
+ __TEXT_END__ = .;
+ } >RAM
+
+ .rodata . : {
+ __RODATA_START__ = .;
+ *(SORT_BY_ALIGNMENT(.rodata*))
+
+#if PLAT_EXTRA_RODATA_INCLUDES
+#include <plat.ld.rodata.inc>
+#endif
+
+ RODATA_COMMON
+
+ /* Place pubsub sections for events */
+ . = ALIGN(8);
+#include <lib/el3_runtime/pubsub_events.h>
+
+ . = ALIGN(PAGE_SIZE);
+ __RODATA_END__ = .;
+ } >RAM
+#else
+ ro . : {
+ __RO_START__ = .;
+ *bl31_entrypoint.o(.text*)
+ *(SORT_BY_ALIGNMENT(.text*))
+ *(SORT_BY_ALIGNMENT(.rodata*))
+
+ RODATA_COMMON
+
+ /* Place pubsub sections for events */
+ . = ALIGN(8);
+#include <lib/el3_runtime/pubsub_events.h>
+
+ *(.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 SPM_MM
+#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_SECTION >RAM
+ RELA_SECTION >RAM
+
+#ifdef BL31_PROGBITS_LIMIT
+ ASSERT(. <= BL31_PROGBITS_LIMIT, "BL31 progbits has exceeded its limit.")
+#endif
+
+#if SEPARATE_NOBITS_REGION
+ /*
+ * Define a linker symbol to mark end of the RW memory area for this
+ * image.
+ */
+ . = ALIGN(PAGE_SIZE);
+ __RW_END__ = .;
+ __BL31_END__ = .;
+
+ ASSERT(. <= BL31_LIMIT, "BL31 image has exceeded its limit.")
+
+ . = BL31_NOBITS_BASE;
+ ASSERT(. == ALIGN(PAGE_SIZE),
+ "BL31 NOBITS base address is not aligned on a page boundary.")
+
+ __NOBITS_START__ = .;
+#endif
+
+ STACK_SECTION >NOBITS
+ BSS_SECTION >NOBITS
+ XLAT_TABLE_SECTION >NOBITS
+
+#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__ = .;
+ } >NOBITS
+#endif
+
+#if SEPARATE_NOBITS_REGION
+ /*
+ * Define a linker symbol to mark end of the NOBITS memory area for this
+ * image.
+ */
+ __NOBITS_END__ = .;
+
+ ASSERT(. <= BL31_NOBITS_LIMIT, "BL31 NOBITS region has exceeded its limit.")
+#else
+ /*
+ * 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.")
+#endif
+
+ /DISCARD/ : {
+ *(.dynsym .dynstr .hash .gnu.hash)
+ }
+}
diff --git a/bl31/bl31.mk b/bl31/bl31.mk
new file mode 100644
index 0000000..4c93a55
--- /dev/null
+++ b/bl31/bl31.mk
@@ -0,0 +1,179 @@
+#
+# Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+################################################################################
+# Include Makefile for the SPM-MM implementation
+################################################################################
+ifeq (${SUPPORT_UNKNOWN_MPID},1)
+ ifeq (${DEBUG},0)
+ $(warning WARNING: SUPPORT_UNKNOWN_MPID enabled)
+ endif
+endif
+
+ifeq (${SPM_MM},1)
+ ifeq (${EL3_EXCEPTION_HANDLING},0)
+ $(error EL3_EXCEPTION_HANDLING must be 1 for SPM-MM support)
+ else
+ $(info Including SPM Management Mode (MM) makefile)
+ include services/std_svc/spm/common/spm.mk
+ include services/std_svc/spm/spm_mm/spm_mm.mk
+ endif
+endif
+
+include lib/extensions/amu/amu.mk
+include lib/mpmm/mpmm.mk
+
+ifeq (${SPMC_AT_EL3},1)
+ $(warning "EL3 SPMC is an experimental feature")
+ $(info Including EL3 SPMC makefile)
+ include services/std_svc/spm/common/spm.mk
+ include services/std_svc/spm/el3_spmc/spmc.mk
+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} \
+ ${SPMD_SOURCES} \
+ ${SPM_MM_SOURCES} \
+ ${SPMC_SOURCES} \
+ ${SPM_SOURCES}
+
+ifeq (${DISABLE_MTPMU},1)
+BL31_SOURCES += lib/extensions/mtpmu/aarch64/mtpmu.S
+endif
+
+ifeq (${ENABLE_PMF}, 1)
+BL31_SOURCES += lib/pmf/pmf_main.c
+endif
+
+include lib/debugfs/debugfs.mk
+ifeq (${USE_DEBUGFS},1)
+ BL31_SOURCES += $(DEBUGFS_SRCS)
+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 (${TRNG_SUPPORT},1)
+BL31_SOURCES += services/std_svc/trng/trng_main.c \
+ services/std_svc/trng/trng_entropy_pool.c
+endif
+
+ifeq (${ENABLE_SPE_FOR_LOWER_ELS},1)
+BL31_SOURCES += lib/extensions/spe/spe.c
+endif
+
+ifeq (${ENABLE_AMU},1)
+BL31_SOURCES += ${AMU_SOURCES}
+endif
+
+ifeq (${ENABLE_MPMM},1)
+BL31_SOURCES += ${MPMM_SOURCES}
+endif
+
+ifeq (${ENABLE_SME_FOR_NS},1)
+BL31_SOURCES += lib/extensions/sme/sme.c
+BL31_SOURCES += lib/extensions/sve/sve.c
+else
+ifeq (${ENABLE_SVE_FOR_NS},1)
+BL31_SOURCES += lib/extensions/sve/sve.c
+endif
+endif
+
+ifeq (${ENABLE_MPAM_FOR_LOWER_ELS},1)
+BL31_SOURCES += lib/extensions/mpam/mpam.c
+endif
+
+ifeq (${ENABLE_TRBE_FOR_NS},1)
+BL31_SOURCES += lib/extensions/trbe/trbe.c
+endif
+
+ifeq (${ENABLE_BRBE_FOR_NS},1)
+BL31_SOURCES += lib/extensions/brbe/brbe.c
+endif
+
+ifeq (${ENABLE_SYS_REG_TRACE_FOR_NS},1)
+BL31_SOURCES += lib/extensions/sys_reg_trace/aarch64/sys_reg_trace.c
+endif
+
+ifeq (${ENABLE_TRF_FOR_NS},1)
+BL31_SOURCES += lib/extensions/trf/aarch64/trf.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
+
+ifeq ($(SMC_PCI_SUPPORT),1)
+BL31_SOURCES += services/std_svc/pci_svc.c
+endif
+
+ifeq (${ENABLE_RME},1)
+include lib/gpt_rme/gpt_rme.mk
+
+BL31_SOURCES += ${GPT_LIB_SRCS} \
+ ${RMMD_SOURCES}
+endif
+
+ifeq ($(FEATURE_DETECTION),1)
+BL31_SOURCES += common/feat_detect.c
+endif
+
+ifeq (${DRTM_SUPPORT},1)
+BL31_SOURCES += services/std_svc/drtm/drtm_main.c \
+ services/std_svc/drtm/drtm_dma_prot.c \
+ services/std_svc/drtm/drtm_res_address_map.c \
+ services/std_svc/drtm/drtm_measurements.c \
+ services/std_svc/drtm/drtm_remediation.c \
+ ${MBEDTLS_SOURCES}
+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_booleans,\
+ $(sort \
+ CRASH_REPORTING \
+ EL3_EXCEPTION_HANDLING \
+ SDEI_SUPPORT \
+)))
+
+$(eval $(call add_defines,\
+ $(sort \
+ CRASH_REPORTING \
+ EL3_EXCEPTION_HANDLING \
+ SDEI_SUPPORT \
+)))
diff --git a/bl31/bl31_context_mgmt.c b/bl31/bl31_context_mgmt.c
new file mode 100644
index 0000000..34f69ad
--- /dev/null
+++ b/bl31/bl31_context_mgmt.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/el3_runtime/cpu_data.h>
+
+/*******************************************************************************
+ * 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(sec_state_is_valid(security_state));
+
+ return get_cpu_data(cpu_context[get_cpu_context_index(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(sec_state_is_valid(security_state));
+
+ set_cpu_data(cpu_context[get_cpu_context_index(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[get_cpu_context_index(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[get_cpu_context_index(security_state)],
+ context);
+}
diff --git a/bl31/bl31_main.c b/bl31/bl31_main.c
new file mode 100644
index 0000000..2a3d838
--- /dev/null
+++ b/bl31/bl31_main.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <bl31/ehf.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/feat_detect.h>
+#include <common/runtime_svc.h>
+#include <drivers/console.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/pmf/pmf.h>
+#include <lib/runtime_instr.h>
+#include <plat/common/platform.h>
+#include <services/std_svc.h>
+
+#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);
+
+/*****************************************************************************
+ * Function used to initialise RMM if RME is enabled
+ *****************************************************************************/
+#if ENABLE_RME
+static int32_t (*rmm_init)(void);
+#endif
+
+/*******************************************************************************
+ * 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;
+
+#ifdef SUPPORT_UNKNOWN_MPID
+/*
+ * Flag to know whether an unsupported MPID has been detected. To avoid having it
+ * landing on the .bss section, it is initialized to a non-zero value, this way
+ * we avoid potential WAW hazards during system bring up.
+ * */
+volatile uint32_t unsupported_mpid_flag = 1;
+#endif
+
+/*
+ * 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 ENABLE_FEAT_HCX
+ /*
+ * Assert that FEAT_HCX is supported on this system, without this check
+ * an exception would occur during context save/restore if enabled but
+ * not supported.
+ */
+ assert(is_feat_hcx_present());
+#endif /* ENABLE_FEAT_HCX */
+
+#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);
+
+#if FEATURE_DETECTION
+ /* Detect if features enabled during compilation are supported by PE. */
+ detect_arch_features();
+#endif /* FEATURE_DETECTION */
+
+#ifdef SUPPORT_UNKNOWN_MPID
+ if (unsupported_mpid_flag == 0) {
+ NOTICE("Unsupported MPID detected!\n");
+ }
+#endif
+
+ /* 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 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. Similarly, if RME is
+ * enabled and a function is registered to initialize RMM, control is
+ * transferred to RMM in R-EL2. After RMM initialization, control is
+ * returned 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");
+ }
+ }
+
+ /*
+ * If RME is enabled and init hook is registered, initialize RMM
+ * in R-EL2.
+ */
+#if ENABLE_RME
+ if (rmm_init != NULL) {
+ INFO("BL31: Initializing RMM\n");
+
+ int32_t rc = (*rmm_init)();
+
+ if (rc == 0) {
+ WARN("BL31: RMM initialization failed\n");
+ }
+ }
+#endif
+
+ /*
+ * 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);
+
+ /*
+ * If we are entering the Non-secure world, use
+ * 'cm_prepare_el3_exit_ns' to exit.
+ */
+ if (image_type == NON_SECURE) {
+ cm_prepare_el3_exit_ns();
+ } else {
+ 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;
+}
+
+#if ENABLE_RME
+/*******************************************************************************
+ * This function initializes the pointer to RMM init function. This is expected
+ * to be called by the RMMD after it finishes all its initialization
+ ******************************************************************************/
+void bl31_register_rmm_init(int32_t (*func)(void))
+{
+ rmm_init = func;
+}
+#endif
diff --git a/bl31/ehf.c b/bl31/ehf.c
new file mode 100644
index 0000000..b328380
--- /dev/null
+++ b/bl31/ehf.c
@@ -0,0 +1,533 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Exception handlers at EL3, their priority levels, and management.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <bl31/ehf.h>
+#include <bl31/interrupt_mgmt.h>
+#include <context.h>
+#include <common/debug.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/el3_runtime/pubsub_events.h>
+#include <plat/common/platform.h>
+
+/* 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 Non-secure. */
+ set_interrupt_rm_flag(flags, NON_SECURE);
+
+ /*
+ * Route EL3 interrupts when in secure, only when SPMC is not present
+ * in S-EL2.
+ */
+#if !(defined(SPD_spmd) && (SPMD_SPM_AT_SEL2 == 1))
+ set_interrupt_rm_flag(flags, SECURE);
+#endif /* !(defined(SPD_spmd) && (SPMD_SPM_AT_SEL2 == 1)) */
+
+ /* 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);
diff --git a/bl31/interrupt_mgmt.c b/bl31/interrupt_mgmt.c
new file mode 100644
index 0000000..b8cc3de
--- /dev/null
+++ b/bl31/interrupt_mgmt.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <common/bl_common.h>
+#include <bl31/interrupt_mgmt.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * Local structure and corresponding array to keep track of the state of the
+ * registered interrupt handlers for each interrupt type.
+ * The field descriptions are:
+ *
+ * '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.
+ *
+ * '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.
+ ******************************************************************************/
+typedef struct intr_type_desc {
+ interrupt_type_handler_t handler;
+ u_register_t scr_el3[2];
+ uint32_t flags;
+} 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.
+ ******************************************************************************/
+u_register_t get_scr_el3_from_routing_model(uint32_t security_state)
+{
+ u_register_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] = (u_register_t)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;
+}
+
diff --git a/bl32/optee/optee.mk b/bl32/optee/optee.mk
new file mode 100644
index 0000000..c8aa7ce
--- /dev/null
+++ b/bl32/optee/optee.mk
@@ -0,0 +1,15 @@
+#
+# 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)
diff --git a/bl32/sp_min/aarch32/entrypoint.S b/bl32/sp_min/aarch32/entrypoint.S
new file mode 100644
index 0000000..f102967
--- /dev/null
+++ b/bl32/sp_min/aarch32/entrypoint.S
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <common/runtime_svc.h>
+#include <context.h>
+#include <el3_common_macros.S>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/pmf/aarch32/pmf_asm_macros.S>
+#include <lib/runtime_instr.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <smccc_helpers.h>
+#include <smccc_macros.S>
+
+ .globl sp_min_vector_table
+ .globl sp_min_entrypoint
+ .globl sp_min_warm_entrypoint
+ .globl sp_min_handle_smc
+ .globl sp_min_handle_fiq
+
+#define FIXUP_SIZE ((BL32_LIMIT) - (BL32_BASE))
+
+ .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 report_prefetch_abort /* Prefetch abort */
+ b report_data_abort /* 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 \
+ _pie_fixup_size=FIXUP_SIZE
+
+ /* ---------------------------------------------------------------------
+ * 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 \
+ _pie_fixup_size=FIXUP_SIZE
+
+ /* ---------------------------------------------------------------------
+ * 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]
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+ /*
+ * Read the timestamp value and store it on top of the C runtime stack.
+ * The value will be saved to the per-cpu data once the C stack is
+ * available, as a valid stack is needed to call _cpu_data()
+ */
+ strd r0, r1, [sp, #SMC_CTX_GPREG_R0]
+ ldcopr16 r0, r1, CNTPCT_64
+ ldr lr, [sp, #SMC_CTX_SP_MON]
+ strd r0, r1, [lr, #-8]!
+ str lr, [sp, #SMC_CTX_SP_MON]
+ ldrd r0, r1, [sp, #SMC_CTX_GPREG_R0]
+#endif
+
+ 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]
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+ /* Save handle to a callee saved register */
+ mov r6, r2
+
+ /*
+ * Restore 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.
+ */
+ ldrd r4, r5, [sp], #8
+ bl _cpu_data
+ strd r4, r5, [r0, #CPU_DATA_PMF_TS0_OFFSET]
+
+ /* Restore handle */
+ mov r2, r6
+#endif
+
+ 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
+#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
+ ldcopr16 r2, r3, CNTPCT_64
+ strd r2, r3, [r0]
+#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/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 \
+ _pie_fixup_size=0
+
+ /*
+ * 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` */
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+ /* Save smc_ctx_t */
+ mov r5, r0
+
+ pmf_calc_timestamp_addr rt_instr_svc, RT_INSTR_EXIT_PSCI
+ mov r4, r0
+
+ /*
+ * 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 r1, #PMF_TS_SIZE
+ bl inv_dcache_range
+
+ ldcopr16 r0, r1, CNTPCT_64
+ strd r0, r1, [r4]
+
+ /* Restore smc_ctx_t */
+ mov r0, r5
+#endif
+
+ 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
diff --git a/bl32/sp_min/sp_min.ld.S b/bl32/sp_min/sp_min.ld.S
new file mode 100644
index 0000000..475affa
--- /dev/null
+++ b/bl32/sp_min/sp_min.ld.S
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.ld.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+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 <plat_sp_min.ld.S>
+#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*)
+ *(SORT_BY_ALIGNMENT(.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__ = .;
+ *(SORT_BY_ALIGNMENT(.rodata*))
+
+ RODATA_COMMON
+
+ /* Place pubsub sections for events */
+ . = ALIGN(8);
+#include <lib/el3_runtime/pubsub_events.h>
+
+ . = ALIGN(PAGE_SIZE);
+ __RODATA_END__ = .;
+ } >RAM
+#else
+ ro . : {
+ __RO_START__ = .;
+ *entrypoint.o(.text*)
+ *(SORT_BY_ALIGNMENT(.text*))
+ *(SORT_BY_ALIGNMENT(.rodata*))
+
+ RODATA_COMMON
+
+ /* Place pubsub sections for events */
+ . = ALIGN(8);
+#include <lib/el3_runtime/pubsub_events.h>
+
+ *(.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.")
+ /*
+ * Define a linker symbol to mark start of the RW memory area for this
+ * image.
+ */
+ __RW_START__ = . ;
+
+ DATA_SECTION >RAM
+ RELA_SECTION >RAM
+
+#ifdef BL32_PROGBITS_LIMIT
+ ASSERT(. <= BL32_PROGBITS_LIMIT, "BL32 progbits has exceeded its limit.")
+#endif
+
+ STACK_SECTION >RAM
+ BSS_SECTION >RAM
+ XLAT_TABLE_SECTION >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 the end of the RW memory area for this
+ * image.
+ */
+ __RW_END__ = .;
+
+ __BL32_END__ = .;
+
+ /DISCARD/ : {
+ *(.dynsym .dynstr .hash .gnu.hash)
+ }
+
+ ASSERT(. <= BL32_LIMIT, "BL32 image has exceeded its limit.")
+}
diff --git a/bl32/sp_min/sp_min.mk b/bl32/sp_min/sp_min.mk
new file mode 100644
index 0000000..ab1287d
--- /dev/null
+++ b/bl32/sp_min/sp_min.mk
@@ -0,0 +1,77 @@
+#
+# Copyright (c) 2016-2022, 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/extensions/amu/amu.mk
+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 (${DISABLE_MTPMU},1)
+BL32_SOURCES += lib/extensions/mtpmu/aarch32/mtpmu.S
+endif
+
+ifeq (${ENABLE_PMF}, 1)
+BL32_SOURCES += lib/pmf/pmf_main.c
+endif
+
+ifeq (${ENABLE_AMU},1)
+BL32_SOURCES += ${AMU_SOURCES}
+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
+else
+ifeq (${WORKAROUND_CVE_2022_23960},1)
+BL32_SOURCES += bl32/sp_min/wa_cve_2017_5715_icache_inv.S
+endif
+endif
+
+ifeq (${TRNG_SUPPORT},1)
+BL32_SOURCES += services/std_svc/trng/trng_main.c \
+ services/std_svc/trng/trng_entropy_pool.c
+endif
+
+ifeq (${ENABLE_SYS_REG_TRACE_FOR_NS},1)
+BL32_SOURCES += lib/extensions/sys_reg_trace/aarch32/sys_reg_trace.c
+endif
+
+ifeq (${ENABLE_TRF_FOR_NS},1)
+BL32_SOURCES += lib/extensions/trf/aarch32/trf.c
+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))
diff --git a/bl32/sp_min/sp_min_main.c b/bl32/sp_min/sp_min_main.c
new file mode 100644
index 0000000..f050160
--- /dev/null
+++ b/bl32/sp_min/sp_min_main.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <context.h>
+#include <drivers/console.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/pmf/pmf.h>
+#include <lib/psci/psci.h>
+#include <lib/runtime_instr.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <platform_sp_min.h>
+#include <services/std_svc.h>
+#include <smccc_helpers.h>
+
+#include "sp_min_private.h"
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+PMF_REGISTER_SERVICE_SMC(rt_instr_svc, PMF_RT_INSTR_SVC_ID,
+ RT_INSTR_TOTAL_IDS, PMF_STORE_ENABLE)
+#endif
+
+/* 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 */
diff --git a/bl32/sp_min/sp_min_private.h b/bl32/sp_min/sp_min_private.h
new file mode 100644
index 0000000..628581a
--- /dev/null
+++ b/bl32/sp_min/sp_min_private.h
@@ -0,0 +1,14 @@
+/*
+ * 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 */
diff --git a/bl32/sp_min/wa_cve_2017_5715_bpiall.S b/bl32/sp_min/wa_cve_2017_5715_bpiall.S
new file mode 100644
index 0000000..385f3d4
--- /dev/null
+++ b/bl32/sp_min/wa_cve_2017_5715_bpiall.S
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+ .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 */
diff --git a/bl32/sp_min/wa_cve_2017_5715_icache_inv.S b/bl32/sp_min/wa_cve_2017_5715_icache_inv.S
new file mode 100644
index 0000000..d0a4625
--- /dev/null
+++ b/bl32/sp_min/wa_cve_2017_5715_icache_inv.S
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+ .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 */
diff --git a/bl32/tsp/aarch64/tsp_entrypoint.S b/bl32/tsp/aarch64/tsp_entrypoint.S
new file mode 100644
index 0000000..e5ea88c
--- /dev/null
+++ b/bl32/tsp/aarch64/tsp_entrypoint.S
@@ -0,0 +1,489 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <bl32/tsp/tsp.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <smccc_helpers.h>
+
+#include "../tsp_private.h"
+
+
+ .globl tsp_entrypoint
+ .globl tsp_vector_table
+#if SPMC_AT_EL3
+ .globl tsp_cpu_on_entry
+#endif
+
+
+
+ /* ---------------------------------------------
+ * 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, #SMC_ARG6]
+ ldp x4, x5, [x0, #SMC_ARG4]
+ ldp x2, x3, [x0, #SMC_ARG2]
+ ldp x0, x1, [x0, #SMC_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
+
+#if ENABLE_PIE
+ /*
+ * ------------------------------------------------------------
+ * If PIE is enabled fixup the Global descriptor Table only
+ * once during primary core cold boot path.
+ *
+ * Compile time base address, required for fixup, is calculated
+ * using "pie_fixup" label present within first page.
+ * ------------------------------------------------------------
+ */
+ pie_fixup:
+ ldr x0, =pie_fixup
+ and x0, x0, #~(PAGE_SIZE_MASK)
+ mov_imm x1, (BL32_LIMIT - BL32_BASE)
+ add x1, x1, x0
+ bl fixup_gdt_reloc
+#endif /* ENABLE_PIE */
+
+ /* ---------------------------------------------
+ * 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. If PIE
+ * is enabled however, RO sections including the
+ * GOT may be modified during pie fixup.
+ * Therefore, to be on the safe side, invalidate
+ * the entire image region if PIE is enabled.
+ * ---------------------------------------------
+ */
+#if ENABLE_PIE
+#if SEPARATE_CODE_AND_RODATA
+ adrp x0, __TEXT_START__
+ add x0, x0, :lo12:__TEXT_START__
+#else
+ adrp x0, __RO_START__
+ add x0, x0, :lo12:__RO_START__
+#endif /* SEPARATE_CODE_AND_RODATA */
+#else
+ adrp x0, __RW_START__
+ add x0, x0, :lo12:__RW_START__
+#endif /* ENABLE_PIE */
+ adrp x1, __RW_END__
+ add x1, x1, :lo12:__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 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
diff --git a/bl32/tsp/aarch64/tsp_exceptions.S b/bl32/tsp/aarch64/tsp_exceptions.S
new file mode 100644
index 0000000..4c6a56a
--- /dev/null
+++ b/bl32/tsp/aarch64/tsp_exceptions.S
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <bl32/tsp/tsp.h>
+#include <common/bl_common.h>
+
+ /* ----------------------------------------------------
+ * 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
+ exception_return
+ .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
diff --git a/bl32/tsp/aarch64/tsp_request.S b/bl32/tsp/aarch64/tsp_request.S
new file mode 100644
index 0000000..6e238ea
--- /dev/null
+++ b/bl32/tsp/aarch64/tsp_request.S
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <bl32/tsp/tsp.h>
+
+ .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
+ /* Load arguments */
+ ldr w0, _tsp_fid_get_magic
+
+ /* Raise SMC */
+ smc #0
+
+ /* Return arguments in x1:x0 */
+ ret
+endfunc tsp_get_magic
+
+ .align 2
+_tsp_fid_get_magic:
+ .word TSP_GET_ARGS
diff --git a/bl32/tsp/ffa_helpers.c b/bl32/tsp/ffa_helpers.c
new file mode 100644
index 0000000..3639c22
--- /dev/null
+++ b/bl32/tsp/ffa_helpers.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include "ffa_helpers.h"
+#include <services/ffa_svc.h>
+#include "tsp_private.h"
+
+/*******************************************************************************
+ * Wrapper function to send a direct request.
+ ******************************************************************************/
+smc_args_t ffa_msg_send_direct_req(ffa_endpoint_id16_t sender,
+ ffa_endpoint_id16_t receiver,
+ uint32_t arg3,
+ uint32_t arg4,
+ uint32_t arg5,
+ uint32_t arg6,
+ uint32_t arg7)
+{
+ uint32_t src_dst_ids = (sender << FFA_DIRECT_MSG_SOURCE_SHIFT) |
+ (receiver << FFA_DIRECT_MSG_DESTINATION_SHIFT);
+
+
+ /* Send Direct Request. */
+ return smc_helper(FFA_MSG_SEND_DIRECT_REQ_SMC64, src_dst_ids,
+ 0, arg3, arg4, arg5, arg6, arg7);
+}
+
+/*******************************************************************************
+ * Wrapper function to send a direct response.
+ ******************************************************************************/
+smc_args_t *ffa_msg_send_direct_resp(ffa_endpoint_id16_t sender,
+ ffa_endpoint_id16_t receiver,
+ uint32_t arg3,
+ uint32_t arg4,
+ uint32_t arg5,
+ uint32_t arg6,
+ uint32_t arg7)
+{
+ uint32_t src_dst_ids = (sender << FFA_DIRECT_MSG_SOURCE_SHIFT) |
+ (receiver << FFA_DIRECT_MSG_DESTINATION_SHIFT);
+
+ return set_smc_args(FFA_MSG_SEND_DIRECT_RESP_SMC64, src_dst_ids,
+ 0, arg3, arg4, arg5, arg6, arg7);
+}
+
+/*******************************************************************************
+ * Memory Management Helpers.
+ ******************************************************************************/
+
+/**
+ * Initialises the header of the given `ffa_mtd`, not including the
+ * composite memory region offset.
+ */
+static void ffa_memory_region_init_header(
+ struct ffa_mtd *memory_region, ffa_endpoint_id16_t sender,
+ ffa_mem_attr16_t attributes, ffa_mtd_flag32_t flags,
+ uint64_t handle, uint64_t tag, ffa_endpoint_id16_t *receivers,
+ uint32_t receiver_count, ffa_mem_perm8_t permissions)
+{
+ struct ffa_emad_v1_0 *emad;
+
+ memory_region->emad_offset = sizeof(struct ffa_mtd);
+ memory_region->emad_size = sizeof(struct ffa_emad_v1_0);
+ emad = (struct ffa_emad_v1_0 *)
+ ((uint8_t *) memory_region +
+ memory_region->emad_offset);
+ memory_region->sender_id = sender;
+ memory_region->memory_region_attributes = attributes;
+ memory_region->reserved_36_39 = 0;
+ memory_region->flags = flags;
+ memory_region->handle = handle;
+ memory_region->tag = tag;
+ memory_region->reserved_40_47 = 0;
+ memory_region->emad_count = receiver_count;
+ for (uint32_t i = 0U; i < receiver_count; i++) {
+ emad[i].mapd.endpoint_id = receivers[i];
+ emad[i].mapd.memory_access_permissions = permissions;
+ emad[i].mapd.flags = 0;
+ emad[i].comp_mrd_offset = 0;
+ emad[i].reserved_8_15 = 0;
+ }
+}
+/**
+ * Initialises the given `ffa_mtd` to be used for an
+ * `FFA_MEM_RETRIEVE_REQ` by the receiver of a memory transaction.
+ * TODO: Support differing attributes per receiver.
+ *
+ * Returns the size of the descriptor written.
+ */
+static uint32_t ffa_memory_retrieve_request_init(
+ struct ffa_mtd *memory_region, uint64_t handle,
+ ffa_endpoint_id16_t sender, ffa_endpoint_id16_t *receivers, uint32_t receiver_count,
+ uint64_t tag, ffa_mtd_flag32_t flags,
+ ffa_mem_perm8_t permissions,
+ ffa_mem_attr16_t attributes)
+{
+ ffa_memory_region_init_header(memory_region, sender, attributes, flags,
+ handle, tag, receivers,
+ receiver_count, permissions);
+
+ return sizeof(struct ffa_mtd) +
+ memory_region->emad_count * sizeof(struct ffa_emad_v1_0);
+}
+
+/* Relinquish access to memory region. */
+bool ffa_mem_relinquish(void)
+{
+ smc_args_t ret;
+
+ ret = smc_helper(FFA_MEM_RELINQUISH, 0, 0, 0, 0, 0, 0, 0);
+ if (ffa_func_id(ret) != FFA_SUCCESS_SMC32) {
+ ERROR("%s failed to relinquish memory! error: (%x) %x\n",
+ __func__, ffa_func_id(ret), ffa_error_code(ret));
+ return false;
+ }
+ return true;
+}
+
+/* Retrieve memory shared by another partition. */
+smc_args_t ffa_mem_retrieve_req(uint32_t descriptor_length,
+ uint32_t fragment_length)
+{
+ return smc_helper(FFA_MEM_RETRIEVE_REQ_SMC32,
+ descriptor_length,
+ fragment_length,
+ 0, 0, 0, 0, 0);
+}
+
+/* Retrieve the next memory descriptor fragment. */
+smc_args_t ffa_mem_frag_rx(uint64_t handle, uint32_t recv_length)
+{
+ return smc_helper(FFA_MEM_FRAG_RX,
+ FFA_MEM_HANDLE_LOW(handle),
+ FFA_MEM_HANDLE_HIGH(handle),
+ recv_length,
+ 0, 0, 0, 0);
+}
+
+bool memory_retrieve(struct mailbox *mb,
+ struct ffa_mtd **retrieved,
+ uint64_t handle, ffa_endpoint_id16_t sender,
+ ffa_endpoint_id16_t *receivers, uint32_t receiver_count,
+ ffa_mtd_flag32_t flags, uint32_t *frag_length,
+ uint32_t *total_length)
+{
+ smc_args_t ret;
+ uint32_t descriptor_size;
+ struct ffa_mtd *memory_region = (struct ffa_mtd *)mb->tx_buffer;
+
+ if (retrieved == NULL || mb == NULL) {
+ ERROR("Invalid parameters!\n");
+ return false;
+ }
+
+ /* Clear TX buffer. */
+ memset(memory_region, 0, PAGE_SIZE);
+
+ /* Clear local buffer. */
+ memset(mem_region_buffer, 0, REGION_BUF_SIZE);
+
+ descriptor_size = ffa_memory_retrieve_request_init(
+ memory_region, handle, sender, receivers, receiver_count, 0, flags,
+ FFA_MEM_PERM_RW | FFA_MEM_PERM_NX,
+ FFA_MEM_ATTR_NORMAL_MEMORY_CACHED_WB |
+ FFA_MEM_ATTR_INNER_SHAREABLE);
+
+ ret = ffa_mem_retrieve_req(descriptor_size, descriptor_size);
+
+ if (ffa_func_id(ret) == FFA_ERROR) {
+ ERROR("Couldn't retrieve the memory page. Error: %x\n",
+ ffa_error_code(ret));
+ return false;
+ }
+
+ /*
+ * Following total_size and fragment_size are useful to keep track
+ * of the state of transaction. When the sum of all fragment_size of all
+ * fragments is equal to total_size, the memory transaction has been
+ * completed.
+ */
+ *total_length = ret._regs[1];
+ *frag_length = ret._regs[2];
+
+ /* Validate frag_length is less than total_length and mailbox size. */
+ if (*frag_length == 0U || *total_length == 0U ||
+ *frag_length > *total_length || *frag_length > (mb->rxtx_page_count * PAGE_SIZE)) {
+ ERROR("Invalid parameters!\n");
+ return false;
+ }
+
+ /* Copy response to local buffer. */
+ memcpy(mem_region_buffer, mb->rx_buffer, *frag_length);
+
+ if (ffa_rx_release()) {
+ ERROR("Failed to release buffer!\n");
+ return false;
+ }
+
+ *retrieved = (struct ffa_mtd *) mem_region_buffer;
+
+ if ((*retrieved)->emad_count > MAX_MEM_SHARE_RECIPIENTS) {
+ VERBOSE("SPMC memory sharing supports max of %u receivers!\n",
+ MAX_MEM_SHARE_RECIPIENTS);
+ return false;
+ }
+
+ /*
+ * We are sharing memory from the normal world therefore validate the NS
+ * bit was set by the SPMC.
+ */
+ if (((*retrieved)->memory_region_attributes & FFA_MEM_ATTR_NS_BIT) == 0U) {
+ ERROR("SPMC has not set the NS bit! 0x%x\n",
+ (*retrieved)->memory_region_attributes);
+ return false;
+ }
+
+ VERBOSE("Memory Descriptor Retrieved!\n");
+
+ return true;
+}
+
+/* Relinquish the memory region. */
+bool memory_relinquish(struct ffa_mem_relinquish_descriptor *m, uint64_t handle,
+ ffa_endpoint_id16_t id)
+{
+ ffa_mem_relinquish_init(m, handle, 0, id);
+ return ffa_mem_relinquish();
+}
+
+/* Query SPMC that the rx buffer of the partition can be released. */
+bool ffa_rx_release(void)
+{
+ smc_args_t ret;
+
+ ret = smc_helper(FFA_RX_RELEASE, 0, 0, 0, 0, 0, 0, 0);
+ return ret._regs[SMC_ARG0] != FFA_SUCCESS_SMC32;
+}
+
+/* Map the provided buffers with the SPMC. */
+bool ffa_rxtx_map(uintptr_t send, uintptr_t recv, uint32_t pages)
+{
+ smc_args_t ret;
+
+ ret = smc_helper(FFA_RXTX_MAP_SMC64, send, recv, pages, 0, 0, 0, 0);
+ return ret._regs[0] != FFA_SUCCESS_SMC32;
+}
diff --git a/bl32/tsp/ffa_helpers.h b/bl32/tsp/ffa_helpers.h
new file mode 100644
index 0000000..e650a07
--- /dev/null
+++ b/bl32/tsp/ffa_helpers.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FFA_HELPERS_H
+#define FFA_HELPERS_H
+
+#include <stdint.h>
+
+#include "../../services/std_svc/spm/el3_spmc/spmc.h"
+#include "../../services/std_svc/spm/el3_spmc/spmc_shared_mem.h"
+#include <services/el3_spmc_ffa_memory.h>
+#include <services/ffa_svc.h>
+#include "tsp_private.h"
+
+static inline uint32_t ffa_func_id(smc_args_t val)
+{
+ return (uint32_t) val._regs[0];
+}
+
+static inline int32_t ffa_error_code(smc_args_t val)
+{
+ return (uint32_t) val._regs[2];
+}
+
+extern uint8_t mem_region_buffer[4096 * 2] __aligned(PAGE_SIZE);
+#define REGION_BUF_SIZE sizeof(mem_region_buffer)
+
+/** The maximum number of recipients a memory region may be sent to. */
+#define MAX_MEM_SHARE_RECIPIENTS 2U
+
+/* FFA Memory Management mode flags. */
+#define FFA_FLAG_SHARE_MEMORY (1U << 3)
+#define FFA_FLAG_LEND_MEMORY (1U << 4)
+
+#define FFA_FLAG_MEMORY_MASK (3U << 3)
+
+#define FFA_MEM_HANDLE_LOW(x) (x & 0xFFFFFFFF)
+#define FFA_MEM_HANDLE_HIGH(x) (x >> 32)
+
+#define FFA_MEM_PERM_DATA_OFFSET 0
+#define FFA_MEM_PERM_DATA_MASK 0x3
+
+static inline uint32_t ffa_mem_relinquish_init(
+ struct ffa_mem_relinquish_descriptor *relinquish_request,
+ uint64_t handle, ffa_mtd_flag32_t flags,
+ ffa_endpoint_id16_t sender)
+{
+ relinquish_request->handle = handle;
+ relinquish_request->flags = flags;
+ relinquish_request->endpoint_count = 1;
+ relinquish_request->endpoint_array[0] = sender;
+
+ return sizeof(struct ffa_mem_relinquish_descriptor) + sizeof(ffa_endpoint_id16_t);
+}
+
+/**
+ * Gets the `ffa_comp_mrd` for the given receiver from an
+ * `ffa_mtd`, or NULL if it is not valid.
+ */
+static inline struct ffa_comp_mrd *
+ffa_memory_region_get_composite(struct ffa_mtd *memory_region,
+ uint32_t receiver_index)
+{
+ struct ffa_emad_v1_0 *receivers;
+ uint32_t offset;
+
+ receivers = (struct ffa_emad_v1_0 *)
+ ((uint8_t *) memory_region +
+ memory_region->emad_offset +
+ (memory_region->emad_size * receiver_index));
+ offset = receivers->comp_mrd_offset;
+
+ if (offset == 0U) {
+ return NULL;
+ }
+
+ return (struct ffa_comp_mrd *)
+ ((uint8_t *) memory_region + offset);
+}
+
+static inline uint32_t ffa_get_data_access_attr(ffa_mem_perm8_t perm)
+{
+ return ((perm >> FFA_MEM_PERM_DATA_OFFSET) & FFA_MEM_PERM_DATA_MASK);
+}
+
+smc_args_t ffa_mem_frag_rx(uint64_t handle, uint32_t recv_length);
+bool ffa_mem_relinquish(void);
+bool ffa_rx_release(void);
+bool memory_relinquish(struct ffa_mem_relinquish_descriptor *m, uint64_t handle,
+ ffa_endpoint_id16_t id);
+bool ffa_rxtx_map(uintptr_t send, uintptr_t recv, uint32_t pages);
+bool memory_retrieve(struct mailbox *mb,
+ struct ffa_mtd **retrieved,
+ uint64_t handle, ffa_endpoint_id16_t sender,
+ ffa_endpoint_id16_t *receivers, uint32_t receiver_count,
+ ffa_mtd_flag32_t flags, uint32_t *frag_length,
+ uint32_t *total_length);
+
+smc_args_t ffa_msg_send_direct_req(ffa_endpoint_id16_t sender,
+ ffa_endpoint_id16_t receiver,
+ uint32_t arg3,
+ uint32_t arg4,
+ uint32_t arg5,
+ uint32_t arg6,
+ uint32_t arg7);
+smc_args_t *ffa_msg_send_direct_resp(ffa_endpoint_id16_t sender,
+ ffa_endpoint_id16_t receiver,
+ uint32_t arg3,
+ uint32_t arg4,
+ uint32_t arg5,
+ uint32_t arg6,
+ uint32_t arg7);
+#endif /* FFA_HELPERS_H */
diff --git a/bl32/tsp/tsp.ld.S b/bl32/tsp/tsp.ld.S
new file mode 100644
index 0000000..d86ae55
--- /dev/null
+++ b/bl32/tsp/tsp.ld.S
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.ld.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+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*)
+
+ RODATA_COMMON
+
+ . = ALIGN(PAGE_SIZE);
+ __RODATA_END__ = .;
+ } >RAM
+#else
+ ro . : {
+ __RO_START__ = .;
+ *tsp_entrypoint.o(.text*)
+ *(.text*)
+ *(.rodata*)
+
+ RODATA_COMMON
+
+ *(.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_SECTION >RAM
+ RELA_SECTION >RAM
+
+#ifdef TSP_PROGBITS_LIMIT
+ ASSERT(. <= TSP_PROGBITS_LIMIT, "TSP progbits has exceeded its limit.")
+#endif
+
+ STACK_SECTION >RAM
+ BSS_SECTION >RAM
+ XLAT_TABLE_SECTION >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__ = .;
+
+ /DISCARD/ : {
+ *(.dynsym .dynstr .hash .gnu.hash)
+ }
+
+ __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.")
+}
diff --git a/bl32/tsp/tsp.mk b/bl32/tsp/tsp.mk
new file mode 100644
index 0000000..c31b9b5
--- /dev/null
+++ b/bl32/tsp/tsp.mk
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+INCLUDES += -Iinclude/bl32/tsp
+
+ifeq (${SPMC_AT_EL3},1)
+ BL32_SOURCES += bl32/tsp/tsp_ffa_main.c \
+ bl32/tsp/ffa_helpers.c
+else
+ BL32_SOURCES += bl32/tsp/tsp_main.c
+endif
+
+BL32_SOURCES += 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 \
+ bl32/tsp/tsp_common.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
diff --git a/bl32/tsp/tsp_common.c b/bl32/tsp/tsp_common.c
new file mode 100644
index 0000000..908b4ff
--- /dev/null
+++ b/bl32/tsp/tsp_common.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <bl32/tsp/tsp.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/spinlock.h>
+#include <plat/common/platform.h>
+#include <platform_tsp.h>
+#include "tsp_private.h"
+
+#include <platform_def.h>
+
+/*******************************************************************************
+ * 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 smc_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];
+
+smc_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;
+ smc_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, SMC_ARG0, arg0);
+ write_sp_arg(pcpu_smc_args, SMC_ARG1, arg1);
+ write_sp_arg(pcpu_smc_args, SMC_ARG2, arg2);
+ write_sp_arg(pcpu_smc_args, SMC_ARG3, arg3);
+ write_sp_arg(pcpu_smc_args, SMC_ARG4, arg4);
+ write_sp_arg(pcpu_smc_args, SMC_ARG5, arg5);
+ write_sp_arg(pcpu_smc_args, SMC_ARG6, arg6);
+ write_sp_arg(pcpu_smc_args, SMC_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 */
+}
+
+/*******************************************************************************
+ * 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).
+ ******************************************************************************/
+smc_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++;
+
+ 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);
+
+ /* 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).
+ ******************************************************************************/
+smc_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++;
+
+ 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);
+
+ /* 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 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.
+ ******************************************************************************/
+smc_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);
+}
diff --git a/bl32/tsp/tsp_ffa_main.c b/bl32/tsp/tsp_ffa_main.c
new file mode 100644
index 0000000..53dbd03
--- /dev/null
+++ b/bl32/tsp/tsp_ffa_main.c
@@ -0,0 +1,655 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+#include "../../services/std_svc/spm/el3_spmc/spmc.h"
+#include "../../services/std_svc/spm/el3_spmc/spmc_shared_mem.h"
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <bl32/tsp/tsp.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include "ffa_helpers.h"
+#include <lib/psci/psci.h>
+#include <lib/spinlock.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#include <platform_tsp.h>
+#include <services/ffa_svc.h>
+#include "tsp_private.h"
+
+#include <platform_def.h>
+
+static ffa_endpoint_id16_t tsp_id, spmc_id;
+uint8_t mem_region_buffer[4096 * 2] __aligned(PAGE_SIZE);
+
+/* Partition Mailbox. */
+static uint8_t send_page[PAGE_SIZE] __aligned(PAGE_SIZE);
+static uint8_t recv_page[PAGE_SIZE] __aligned(PAGE_SIZE);
+
+/*
+ * Declare a global mailbox for use within the TSP.
+ * This will be initialized appropriately when the buffers
+ * are mapped with the SPMC.
+ */
+static struct mailbox mailbox;
+
+/*******************************************************************************
+ * This enum is used to handle test cases driven from the FF-A Test Driver.
+ ******************************************************************************/
+/* Keep in Sync with FF-A Test Driver. */
+enum message_t {
+ /* Partition Only Messages. */
+ FF_A_RELAY_MESSAGE = 0,
+
+ /* Basic Functionality. */
+ FF_A_ECHO_MESSAGE,
+ FF_A_RELAY_MESSAGE_EL3,
+
+ /* Memory Sharing. */
+ FF_A_MEMORY_SHARE,
+ FF_A_MEMORY_SHARE_FRAGMENTED,
+ FF_A_MEMORY_LEND,
+ FF_A_MEMORY_LEND_FRAGMENTED,
+
+ FF_A_MEMORY_SHARE_MULTI_ENDPOINT,
+ FF_A_MEMORY_LEND_MULTI_ENDPOINT,
+
+ LAST,
+ FF_A_RUN_ALL = 255,
+ FF_A_OP_MAX = 256
+};
+
+#if SPMC_AT_EL3
+extern void tsp_cpu_on_entry(void);
+#endif
+
+/*******************************************************************************
+ * Test Functions.
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Enable the TSP to forward the received message to another partition and ask
+ * it to echo the value back in order to validate direct messages functionality.
+ ******************************************************************************/
+static int ffa_test_relay(uint64_t arg0,
+ uint64_t arg1,
+ uint64_t arg2,
+ uint64_t arg3,
+ uint64_t arg4,
+ uint64_t arg5,
+ uint64_t arg6,
+ uint64_t arg7)
+{
+ smc_args_t ffa_forward_result;
+ ffa_endpoint_id16_t receiver = arg5;
+
+ ffa_forward_result = ffa_msg_send_direct_req(ffa_endpoint_source(arg1),
+ receiver,
+ FF_A_ECHO_MESSAGE, arg4,
+ 0, 0, 0);
+ return ffa_forward_result._regs[3];
+}
+
+/*******************************************************************************
+ * This function handles memory management tests, currently share and lend.
+ * This test supports the use of FRAG_RX to use memory descriptors that do not
+ * fit in a single 4KB buffer.
+ ******************************************************************************/
+static int test_memory_send(ffa_endpoint_id16_t sender, uint64_t handle,
+ ffa_mtd_flag32_t flags, bool multi_endpoint)
+{
+ struct ffa_mtd *m;
+ struct ffa_emad_v1_0 *receivers;
+ struct ffa_comp_mrd *composite;
+ int ret, status = 0;
+ unsigned int mem_attrs;
+ char *ptr;
+ ffa_endpoint_id16_t source = sender;
+ uint32_t total_length, recv_length = 0;
+
+ /*
+ * In the case that we're testing multiple endpoints choose a partition
+ * ID that resides in the normal world so the SPMC won't detect it as
+ * invalid.
+ * TODO: Should get endpoint receiver id and flag as input from NWd.
+ */
+ uint32_t receiver_count = multi_endpoint ? 2 : 1;
+ ffa_endpoint_id16_t test_receivers[2] = { tsp_id, 0x10 };
+
+ /* Ensure that the sender ID resides in the normal world. */
+ if (ffa_is_secure_world_id(sender)) {
+ ERROR("Invalid sender ID 0x%x.\n", sender);
+ return FFA_ERROR_DENIED;
+ }
+
+ if (!memory_retrieve(&mailbox, &m, handle, source, test_receivers,
+ receiver_count, flags, &recv_length,
+ &total_length)) {
+ return FFA_ERROR_INVALID_PARAMETER;
+ }
+
+ receivers = (struct ffa_emad_v1_0 *)
+ ((uint8_t *) m + m->emad_offset);
+ while (total_length != recv_length) {
+ smc_args_t ffa_return;
+ uint32_t frag_length;
+
+ ffa_return = ffa_mem_frag_rx(handle, recv_length);
+
+ if (ffa_return._regs[0] == FFA_ERROR) {
+ WARN("TSP: failed to resume mem with handle %lx\n",
+ handle);
+ return ffa_return._regs[2];
+ }
+ frag_length = ffa_return._regs[3];
+
+ /* Validate frag_length is less than total_length and mailbox size. */
+ if (frag_length > total_length ||
+ frag_length > (mailbox.rxtx_page_count * PAGE_SIZE)) {
+ ERROR("Invalid parameters!\n");
+ return FFA_ERROR_INVALID_PARAMETER;
+ }
+
+ /* Validate frag_length is less than remaining mem_region_buffer size. */
+ if (frag_length + recv_length >= REGION_BUF_SIZE) {
+ ERROR("Out of memory!\n");
+ return FFA_ERROR_INVALID_PARAMETER;
+ }
+
+ memcpy(&mem_region_buffer[recv_length], mailbox.rx_buffer,
+ frag_length);
+
+ if (ffa_rx_release()) {
+ ERROR("Failed to release buffer!\n");
+ return FFA_ERROR_DENIED;
+ }
+
+ recv_length += frag_length;
+
+ assert(recv_length <= total_length);
+ }
+
+ composite = ffa_memory_region_get_composite(m, 0);
+ if (composite == NULL) {
+ WARN("Failed to get composite descriptor!\n");
+ return FFA_ERROR_INVALID_PARAMETER;
+ }
+
+ VERBOSE("Address: %p; page_count: %x %lx\n",
+ (void *)composite->address_range_array[0].address,
+ composite->address_range_array[0].page_count, PAGE_SIZE);
+
+ /* This test is only concerned with RW permissions. */
+ if (ffa_get_data_access_attr(
+ receivers[0].mapd.memory_access_permissions) != FFA_MEM_PERM_RW) {
+ ERROR("Data permission in retrieve response %x does not match share/lend %x!\n",
+ ffa_get_data_access_attr(receivers[0].mapd.memory_access_permissions),
+ FFA_MEM_PERM_RW);
+ return FFA_ERROR_INVALID_PARAMETER;
+ }
+
+ mem_attrs = MT_RW_DATA | MT_EXECUTE_NEVER;
+
+ /* Only expecting to be sent memory from NWd so map accordingly. */
+ mem_attrs |= MT_NS;
+
+ for (uint32_t i = 0U; i < composite->address_range_count; i++) {
+ size_t size = composite->address_range_array[i].page_count * PAGE_SIZE;
+
+ ptr = (char *) composite->address_range_array[i].address;
+ ret = mmap_add_dynamic_region(
+ (uint64_t)ptr,
+ (uint64_t)ptr,
+ size, mem_attrs);
+
+ if (ret != 0) {
+ ERROR("Failed [%u] mmap_add_dynamic_region %u (%lx) (%lx) (%x)!\n",
+ i, ret,
+ (uint64_t)composite->address_range_array[i].address,
+ size, mem_attrs);
+
+ /* Remove mappings created in this transaction. */
+ for (i--; i >= 0U; i--) {
+ ret = mmap_remove_dynamic_region(
+ (uint64_t)ptr,
+ composite->address_range_array[i].page_count * PAGE_SIZE);
+
+ if (ret != 0) {
+ ERROR("Failed [%d] mmap_remove_dynamic_region!\n", i);
+ panic();
+ }
+ }
+ return FFA_ERROR_NO_MEMORY;
+ }
+
+ /* Increment memory region for validation purposes. */
+ ++(*ptr);
+
+ /*
+ * Read initial magic number from memory region for
+ * validation purposes.
+ */
+ if (!i) {
+ status = *ptr;
+ }
+ }
+
+ for (uint32_t i = 0U; i < composite->address_range_count; i++) {
+ ret = mmap_remove_dynamic_region(
+ (uint64_t)composite->address_range_array[i].address,
+ composite->address_range_array[i].page_count * PAGE_SIZE);
+
+ if (ret != 0) {
+ ERROR("Failed [%d] mmap_remove_dynamic_region!\n", i);
+ return FFA_ERROR_NO_MEMORY;
+ }
+ }
+
+ if (!memory_relinquish((struct ffa_mem_relinquish_descriptor *)mailbox.tx_buffer,
+ m->handle, tsp_id)) {
+ ERROR("Failed to relinquish memory region!\n");
+ return FFA_ERROR_INVALID_PARAMETER;
+ }
+ return status;
+}
+
+static smc_args_t *send_ffa_pm_success(void)
+{
+ return set_smc_args(FFA_MSG_SEND_DIRECT_RESP_SMC32,
+ ((tsp_id & FFA_DIRECT_MSG_ENDPOINT_ID_MASK)
+ << FFA_DIRECT_MSG_SOURCE_SHIFT) | spmc_id,
+ FFA_FWK_MSG_BIT |
+ (FFA_PM_MSG_PM_RESP & FFA_FWK_MSG_MASK),
+ 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.
+ ******************************************************************************/
+smc_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++;
+
+ 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);
+
+ return send_ffa_pm_success();
+}
+
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+smc_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++;
+
+ 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);
+
+ return send_ffa_pm_success();
+}
+
+/*******************************************************************************
+ * This function performs any bookkeeping in the test secure payload after this
+ * cpu's architectural state has been restored after wakeup from an earlier psci
+ * cpu_suspend request.
+ ******************************************************************************/
+smc_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++;
+
+ INFO("TSP: cpu 0x%lx resumed. maximum off power level %" PRId64 "\n",
+ read_mpidr(), max_off_pwrlvl);
+ INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu resume requests\n",
+ read_mpidr(),
+ tsp_stats[linear_id].smc_count,
+ tsp_stats[linear_id].eret_count,
+ tsp_stats[linear_id].cpu_resume_count);
+
+ return send_ffa_pm_success();
+}
+
+/*******************************************************************************
+ * This function handles framework messages. Currently only PM.
+ ******************************************************************************/
+static smc_args_t *handle_framework_message(uint64_t arg0,
+ uint64_t arg1,
+ uint64_t arg2,
+ uint64_t arg3,
+ uint64_t arg4,
+ uint64_t arg5,
+ uint64_t arg6,
+ uint64_t arg7)
+{
+ /* Check if it is a power management message from the SPMC. */
+ if (ffa_endpoint_source(arg1) != spmc_id) {
+ goto err;
+ }
+
+ /* Check if it is a PM request message. */
+ if ((arg2 & FFA_FWK_MSG_MASK) == FFA_FWK_MSG_PSCI) {
+ /* Check if it is a PSCI CPU_OFF request. */
+ if (arg3 == PSCI_CPU_OFF) {
+ return tsp_cpu_off_main(arg0, arg1, arg2, arg3,
+ arg4, arg5, arg6, arg7);
+ } else if (arg3 == PSCI_CPU_SUSPEND_AARCH64) {
+ return tsp_cpu_suspend_main(arg0, arg1, arg2, arg3,
+ arg4, arg5, arg6, arg7);
+ }
+ } else if ((arg2 & FFA_FWK_MSG_MASK) == FFA_PM_MSG_WB_REQ) {
+ /* Check it is a PSCI Warm Boot request. */
+ if (arg3 == FFA_WB_TYPE_NOTS2RAM) {
+ return tsp_cpu_resume_main(arg0, arg1, arg2, arg3,
+ arg4, arg5, arg6, arg7);
+ }
+ }
+
+err:
+ ERROR("%s: Unknown framework message!\n", __func__);
+ panic();
+}
+
+/*******************************************************************************
+ * Handles partition messages. Exercised from the FF-A Test Driver.
+ ******************************************************************************/
+static smc_args_t *handle_partition_message(uint64_t arg0,
+ uint64_t arg1,
+ uint64_t arg2,
+ uint64_t arg3,
+ uint64_t arg4,
+ uint64_t arg5,
+ uint64_t arg6,
+ uint64_t arg7)
+{
+ uint16_t sender = ffa_endpoint_source(arg1);
+ uint16_t receiver = ffa_endpoint_destination(arg1);
+ int status = -1;
+ const bool multi_endpoint = true;
+
+ switch (arg3) {
+ case FF_A_MEMORY_SHARE:
+ INFO("TSP Tests: Memory Share Request--\n");
+ status = test_memory_send(sender, arg4, FFA_FLAG_SHARE_MEMORY, !multi_endpoint);
+ break;
+
+ case FF_A_MEMORY_LEND:
+ INFO("TSP Tests: Memory Lend Request--\n");
+ status = test_memory_send(sender, arg4, FFA_FLAG_LEND_MEMORY, !multi_endpoint);
+ break;
+
+ case FF_A_MEMORY_SHARE_MULTI_ENDPOINT:
+ INFO("TSP Tests: Multi Endpoint Memory Share Request--\n");
+ status = test_memory_send(sender, arg4, FFA_FLAG_SHARE_MEMORY, multi_endpoint);
+ break;
+
+ case FF_A_MEMORY_LEND_MULTI_ENDPOINT:
+ INFO("TSP Tests: Multi Endpoint Memory Lend Request--\n");
+ status = test_memory_send(sender, arg4, FFA_FLAG_LEND_MEMORY, multi_endpoint);
+ break;
+ case FF_A_RELAY_MESSAGE:
+ INFO("TSP Tests: Relaying message--\n");
+ status = ffa_test_relay(arg0, arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7);
+ break;
+
+ case FF_A_ECHO_MESSAGE:
+ INFO("TSP Tests: echo message--\n");
+ status = arg4;
+ break;
+
+ default:
+ INFO("TSP Tests: Unknown request ID %d--\n", (int) arg3);
+ }
+
+ /* Swap the sender and receiver in the response. */
+ return ffa_msg_send_direct_resp(receiver, sender, status, 0, 0, 0, 0);
+}
+
+/*******************************************************************************
+ * This function implements the event loop for handling FF-A ABI invocations.
+ ******************************************************************************/
+static smc_args_t *tsp_event_loop(uint64_t smc_fid,
+ uint64_t arg1,
+ uint64_t arg2,
+ uint64_t arg3,
+ uint64_t arg4,
+ uint64_t arg5,
+ uint64_t arg6,
+ uint64_t arg7)
+{
+ /* Panic if the SPMC did not forward an FF-A call. */
+ if (!is_ffa_fid(smc_fid)) {
+ ERROR("%s: Unknown SMC FID (0x%lx)\n", __func__, smc_fid);
+ panic();
+ }
+
+ switch (smc_fid) {
+ case FFA_INTERRUPT:
+ /*
+ * IRQs were enabled upon re-entry into the TSP. The interrupt
+ * must have been handled by now. Return to the SPMC indicating
+ * the same.
+ */
+ return set_smc_args(FFA_MSG_WAIT, 0, 0, 0, 0, 0, 0, 0);
+
+ case FFA_MSG_SEND_DIRECT_REQ_SMC64:
+ case FFA_MSG_SEND_DIRECT_REQ_SMC32:
+ /* Check if a framework message, handle accordingly. */
+ if ((arg2 & FFA_FWK_MSG_BIT)) {
+ return handle_framework_message(smc_fid, arg1, arg2, arg3,
+ arg4, arg5, arg6, arg7);
+ }
+ return handle_partition_message(smc_fid, arg1, arg2, arg3,
+ arg4, arg5, arg6, arg7);
+ }
+
+ ERROR("%s: Unsupported FF-A FID (0x%lx)\n", __func__, smc_fid);
+ panic();
+}
+
+static smc_args_t *tsp_loop(smc_args_t *args)
+{
+ smc_args_t ret;
+
+ do {
+ /* --------------------------------------------
+ * Mask FIQ interrupts to avoid preemption
+ * in case EL3 SPMC delegates an IRQ next or a
+ * managed exit. Lastly, unmask IRQs so that
+ * they can be handled immediately upon re-entry.
+ * ---------------------------------------------
+ */
+ write_daifset(DAIF_FIQ_BIT);
+ write_daifclr(DAIF_IRQ_BIT);
+ ret = smc_helper(args->_regs[0], args->_regs[1], args->_regs[2],
+ args->_regs[3], args->_regs[4], args->_regs[5],
+ args->_regs[6], args->_regs[7]);
+ args = tsp_event_loop(ret._regs[0], ret._regs[1], ret._regs[2],
+ ret._regs[3], ret._regs[4], ret._regs[5],
+ ret._regs[6], ret._regs[7]);
+ } while (1);
+
+ /* Not Reached. */
+ return NULL;
+}
+
+/*******************************************************************************
+ * 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)
+{
+ smc_args_t smc_args = {0};
+
+ 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();
+
+ /* Register secondary entrypoint with the SPMC. */
+ smc_args = smc_helper(FFA_SECONDARY_EP_REGISTER_SMC64,
+ (uint64_t) tsp_cpu_on_entry,
+ 0, 0, 0, 0, 0, 0);
+ if (smc_args._regs[SMC_ARG0] != FFA_SUCCESS_SMC32) {
+ ERROR("TSP could not register secondary ep (0x%lx)\n",
+ smc_args._regs[2]);
+ panic();
+ }
+ /* Get TSP's endpoint id. */
+ smc_args = smc_helper(FFA_ID_GET, 0, 0, 0, 0, 0, 0, 0);
+ if (smc_args._regs[SMC_ARG0] != FFA_SUCCESS_SMC32) {
+ ERROR("TSP could not get own ID (0x%lx) on core%d\n",
+ smc_args._regs[2], linear_id);
+ panic();
+ }
+
+ tsp_id = smc_args._regs[2];
+ INFO("TSP FF-A endpoint id = 0x%x\n", tsp_id);
+
+ /* Get the SPMC ID. */
+ smc_args = smc_helper(FFA_SPM_ID_GET, 0, 0, 0, 0, 0, 0, 0);
+ if (smc_args._regs[SMC_ARG0] != FFA_SUCCESS_SMC32) {
+ ERROR("TSP could not get SPMC ID (0x%lx) on core%d\n",
+ smc_args._regs[2], linear_id);
+ panic();
+ }
+
+ spmc_id = smc_args._regs[2];
+
+ /* Call RXTX_MAP to map a 4k RX and TX buffer. */
+ if (ffa_rxtx_map((uintptr_t) send_page,
+ (uintptr_t) recv_page, 1)) {
+ ERROR("TSP could not map it's RX/TX Buffers\n");
+ panic();
+ }
+
+ mailbox.tx_buffer = send_page;
+ mailbox.rx_buffer = recv_page;
+ mailbox.rxtx_page_count = 1;
+
+ /* Update this cpu's statistics. */
+ tsp_stats[linear_id].smc_count++;
+ tsp_stats[linear_id].eret_count++;
+ tsp_stats[linear_id].cpu_on_count++;
+
+ 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);
+
+ /* Tell SPMD that we are done initialising. */
+ tsp_loop(set_smc_args(FFA_MSG_WAIT, 0, 0, 0, 0, 0, 0, 0));
+
+ /* Not reached. */
+ return 0;
+}
+
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+smc_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++;
+ 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);
+ /* ---------------------------------------------
+ * Jump to the main event loop to return to EL3
+ * and be ready for the next request on this cpu.
+ * ---------------------------------------------
+ */
+ return tsp_loop(set_smc_args(FFA_MSG_WAIT, 0, 0, 0, 0, 0, 0, 0));
+}
diff --git a/bl32/tsp/tsp_interrupt.c b/bl32/tsp/tsp_interrupt.c
new file mode 100644
index 0000000..a847b6c
--- /dev/null
+++ b/bl32/tsp/tsp_interrupt.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2014-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl32/tsp/tsp.h>
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+#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++;
+
+ VERBOSE("TSP: cpu 0x%lx sync s-el1 interrupt request from 0x%" PRIx64 "\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);
+}
+
+/******************************************************************************
+ * 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++;
+ VERBOSE("TSP: cpu 0x%lx: %d preempt interrupt requests\n",
+ read_mpidr(), tsp_stats[linear_id].preempt_intr_count);
+ 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) {
+#if SPMC_AT_EL3
+ /*
+ * With the EL3 FF-A SPMC we expect only Timer secure interrupt to fire in
+ * the TSP, so panic if any other interrupt does.
+ */
+ ERROR("Unexpected interrupt id %u\n", id);
+ panic();
+#else
+ return tsp_handle_preemption();
+#endif
+ }
+
+ /*
+ * 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++;
+ 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);
+ return 0;
+}
diff --git a/bl32/tsp/tsp_main.c b/bl32/tsp/tsp_main.c
new file mode 100644
index 0000000..df9903b
--- /dev/null
+++ b/bl32/tsp/tsp_main.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <bl32/tsp/tsp.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/spinlock.h>
+#include <plat/common/platform.h>
+#include <platform_tsp.h>
+#include "tsp_private.h"
+
+#include <platform_def.h>
+
+/*******************************************************************************
+ * 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++;
+
+ 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);
+ 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.
+ ******************************************************************************/
+smc_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++;
+
+ 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);
+ /* 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.
+ ******************************************************************************/
+smc_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++;
+
+ 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);
+
+ /* 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.
+ ******************************************************************************/
+smc_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++;
+
+ 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);
+
+ /* 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.
+ ******************************************************************************/
+smc_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++;
+
+ INFO("TSP: cpu 0x%lx resumed. maximum off power level %" PRId64 "\n",
+ read_mpidr(), max_off_pwrlvl);
+ INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu resume requests\n",
+ read_mpidr(),
+ tsp_stats[linear_id].smc_count,
+ tsp_stats[linear_id].eret_count,
+ tsp_stats[linear_id].cpu_resume_count);
+ /* Indicate to the SPD that we have completed this request */
+ return set_smc_args(TSP_RESUME_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.
+ ******************************************************************************/
+smc_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)
+{
+ uint128_t service_args;
+ uint64_t service_arg0;
+ uint64_t service_arg1;
+ uint64_t results[2];
+ uint32_t linear_id = plat_my_core_pos();
+ u_register_t dit;
+
+ /* 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%" PRIx64 "\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 returns and thereafter resumes execution.
+ */
+ service_args = tsp_get_magic();
+ service_arg0 = (uint64_t)service_args;
+ service_arg1 = (uint64_t)(service_args >> 64U);
+
+#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_arg0;
+ results[1] += service_arg1;
+ break;
+ case TSP_SUB:
+ results[0] -= service_arg0;
+ results[1] -= service_arg1;
+ break;
+ case TSP_MUL:
+ results[0] *= service_arg0;
+ results[1] *= service_arg1;
+ break;
+ case TSP_DIV:
+ results[0] /= service_arg0 ? service_arg0 : 1;
+ results[1] /= service_arg1 ? service_arg1 : 1;
+ break;
+ case TSP_CHECK_DIT:
+ if (!is_armv8_4_dit_present()) {
+ ERROR("DIT not supported\n");
+ results[0] = 0;
+ results[1] = 0xffff;
+ break;
+ }
+ dit = read_dit();
+ results[0] = dit == service_arg0;
+ results[1] = dit;
+ /* Toggle the dit bit */
+ write_dit(service_arg0 != 0U ? 0 : DIT_BIT);
+ break;
+ default:
+ break;
+ }
+
+ return set_smc_args(func, 0,
+ results[0],
+ results[1],
+ 0, 0, 0, 0);
+}
diff --git a/bl32/tsp/tsp_private.h b/bl32/tsp/tsp_private.h
new file mode 100644
index 0000000..66873e2
--- /dev/null
+++ b/bl32/tsp/tsp_private.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2014-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TSP_PRIVATE_H
+#define TSP_PRIVATE_H
+
+/*******************************************************************************
+ * 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)
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+#include <bl32/tsp/tsp.h>
+#include <lib/cassert.h>
+#include <lib/spinlock.h>
+#include <smccc_helpers.h>
+
+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;
+
+/* 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)
+
+uint128_t tsp_get_magic(void);
+
+smc_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);
+smc_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);
+smc_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);
+smc_args_t *tsp_cpu_on_main(void);
+smc_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 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);
+
+smc_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);
+
+smc_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);
+
+smc_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);
+
+smc_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 */
diff --git a/bl32/tsp/tsp_timer.c b/bl32/tsp/tsp_timer.c
new file mode 100644
index 0000000..d1ff2b0
--- /dev/null
+++ b/bl32/tsp/tsp_timer.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <plat/common/platform.h>
+
+#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);
+}
diff --git a/changelog.yaml b/changelog.yaml
new file mode 100644
index 0000000..cfb2bb5
--- /dev/null
+++ b/changelog.yaml
@@ -0,0 +1,1272 @@
+#
+# Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+#
+# The following block describes the top-level sections of the changelog. Commits are categorized
+# into these top-level sections based on the commit message "type":
+#
+# feat(xyz): add the xyz feature
+# ^^^^
+#
+
+sections:
+ - title: New Features
+ description: A new feature
+ type: feat
+
+ - title: Resolved Issues
+ description: A bug fix
+ type: fix
+
+ - title: Build System
+ description: Changes that affect the build system or external dependencies
+ type: build
+ hidden: true
+
+ - title: Continuous Integration
+ description: Changes to our CI configuration files and scripts
+ type: ci
+ hidden: true
+
+ - title: Documentation
+ description: Documentation-only changes
+ type: docs
+ hidden: true
+
+ - title: Performance Improvements
+ description: A code change that improves performance
+ type: perf
+ hidden: true
+
+ - title: Code Refactoring
+ description: A code change that neither fixes a bug nor adds a feature
+ type: refactor
+ hidden: true
+
+ - title: Reverted Changes
+ description: Changes that revert a previous change
+ type: revert
+ hidden: true
+
+ - title: Style
+ description: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc.)
+ type: style
+ hidden: true
+
+ - title: Tests
+ description: Adding missing tests or correcting existing tests
+ type: test
+ hidden: true
+
+ - title: Miscellaneous
+ description: Any other change
+ type: chore
+ hidden: true
+
+#
+# The following block describes the sub-sections of the changelog. These sub-sections may appear in
+# any of the top-level sections, and describe the individual components that a change may relate to.
+#
+# Sub-sections have an optional associated commit message "scope":
+#
+# feat(xyz): add the xyz feature
+# ^^^
+#
+# This file also describes deprecated scopes, which are scopes that were used before we introduced
+# scope enforcement. These will not pass CI checks when used, but they will be used to generate the
+# changelog.
+#
+# Please note that new scopes should be kebab-case: https://en.wiktionary.org/wiki/kebab_case
+#
+
+subsections:
+ - title: Architecture
+
+ subsections:
+ - title: Activity Monitors Extension (FEAT_AMU)
+ scope: amu
+
+ - title: Branch Record Buffer Extension (FEAT_BRBE)
+ scope: brbe
+
+ - title: Branch Target Identification Extension
+ scope: bti
+
+ - title: Confidential Compute Architecture (CCA)
+ scope: cca
+
+ - title: Extended Cache Index (FEAT_CCIDX)
+ scope: ccidx
+
+ - title: Support for the `HCRX_EL2` register (FEAT_HCX)
+ scope: hcx
+
+ - title: Memory Partitioning and Monitoring (MPAM) Extension (FEAT_MPAM)
+ scope: mpam
+
+ - title: Memory Tagging Extension
+ scope: mte
+
+ - title: Pointer Authentication Extension
+ scope: pauth
+
+ - title: Performance Monitors Extension (FEAT_PMUv3)
+ scope: pmu
+
+ - title: Trapping support for RNDR/RNDRRS (FEAT_RNG_TRAP)
+ scope: rng-trap
+
+ - title: Scalable Matrix Extension (FEAT_SME)
+ scope: sme
+
+ - title: Statistical profiling Extension (FEAT_SPE)
+ scope: spe
+
+ - title: Scalable Vector Extension (FEAT_SVE)
+ scope: sve
+
+ - title: System Register Trace Extensions (FEAT_ETMv4, FEAT_ETE and FEAT_ETEv1.1)
+ scope: sys-reg-trace
+
+ deprecated:
+ - sys_reg_trace
+
+ - title: Trace Buffer Extension (FEAT_TRBE)
+ scope: trbe
+
+ - title: Self-hosted Trace Extensions (FEAT_TRF)
+ scope: trf
+
+ - title: Platforms
+
+ subsections:
+ - title: Allwinner
+ scope: allwinner
+
+ deprecated:
+ - plat/allwinner
+
+ - title: Arm
+ scope: arm
+
+ deprecated:
+ - plat/arm
+
+ subsections:
+ - title: CSS
+ scope: css
+
+ deprecated:
+ - plat/arm/css
+
+ - title: FPGA
+ scope: fpga
+
+ deprecated:
+ - arm_fgpa
+ - arm_fpga
+ - plat/arm_fpga
+
+ - title: FVP
+ scope: fvp
+
+ deprecated:
+ - plat/fvp
+ - fvp/tsp_manifest
+
+ - title: FVP-R
+ scope: fvp-r
+
+ deprecated:
+ - fvp_r
+
+ - title: FVP Versatile Express
+ scope: fvp_ve
+
+ - title: Juno
+ scope: juno
+
+ - title: Morello
+ scope: morello
+
+ - title: N1SDP
+ scope: n1sdp
+
+ - title: RD
+ scope: rd
+
+ subsections:
+ - title: RD-N2
+ scope: rdn2
+
+ deprecated:
+ - board/rdn2
+
+ - title: SGI
+ scope: sgi
+
+ deprecated:
+ - plat/sgi
+ - plat/arm/sgi
+
+ - title: TC
+ scope: tc
+
+ subsections:
+ - title: TC0
+ scope: tc0
+
+ deprecated:
+ - plat/tc0
+
+ - title: Corstone-1000
+ scope: corstone-1000
+
+ - title: Broadcom
+ scope: brcm
+
+ - title: HiSilicon
+ scope: hisilicon
+
+ subsections:
+ - title: HiKey
+ scope: hikey
+
+ - title: HiKey960
+ scope: hikey960
+
+ - title: Intel
+ scope: intel
+
+ subsections:
+ - title: SoC
+ scope: soc
+
+ - title: Marvell
+ scope: marvell
+
+ deprecated:
+ - plat/marvell
+
+ subsections:
+ - title: Armada
+ scope: armada
+
+ deprecated:
+ - plat/marvell/armada
+
+ subsections:
+ - title: A3K
+ scope: a3k
+
+ deprecated:
+ - plat/marvell/a3k
+
+ - title: A8K
+ scope: a8k
+
+ deprecated:
+ - plat/marvell/a8k
+
+ - title: MediaTek
+ scope: mediatek
+
+ deprecated:
+ - plat/mediatek/common
+ - plat/mediatek
+
+ subsections:
+ - title: MT8183
+ scope: mt8183
+
+ deprecated:
+ - plat/mediatek/mt8183
+
+ - title: MT8186
+ scope: mt8186
+
+ deprecated:
+ - plat/mediatek/mt8186
+ - mt8186-emi-mpu
+
+ - title: MT8188
+ scope: mt8188
+
+ - title: MT8192
+ scope: mt8192
+
+ deprecated:
+ - plat/mdeiatek/mt8192
+
+ - title: MT8195
+ scope: mt8195
+
+ deprecated:
+ - plat/mediatek/me8195
+ - plat/mediatek/mt8195
+ - plat/mdeiatek/mt8195
+
+ - title: NVIDIA
+ scope: nvidia
+
+ subsections:
+ - title: Tegra
+ scope: tegra
+
+ deprecated:
+ - plat/tegra
+
+ subsections:
+ - title: Tegra 132
+ scope: tegra132
+
+ - title: Tegra 194
+ scope: tegra194
+
+ - title: NXP
+ scope: nxp
+
+ deprecated:
+ - plat/nxp
+ - plat/nxp/common
+
+ subsections:
+ - title: i.MX
+ scope: imx
+
+ deprecated:
+ - plat/imx
+ - plat/imx/imx
+
+ subsections:
+ - title: i.MX 8M
+ scope: imx8m
+
+ deprecated:
+ - plat/imx8m
+ - plat/imx/imx8m
+
+ subsections:
+ - title: i.MX 8M Nano
+ scope: imx8mn
+
+ deprecated:
+ - plat/imx/imx8m/imx8mn
+
+ - title: i.MX 8M Mini
+ scope: imx8mm
+
+ deprecated:
+ - plat/imx/imx8m/imx8mm
+
+ - title: i.MX 8M Plus
+ scope: imx8mp
+
+ deprecated:
+ - plat/imx/imx8m/imx8mp
+
+ - title: i.MX 8Q
+ scope: imx8mq
+
+ deprecated:
+ - plat/imx/imx8m/imx8mq
+
+ - title: Layerscape
+ scope: layerscape
+
+ deprecated:
+ - docs/nxp/layerscape
+
+ subsections:
+ - title: LS1028A
+ scope: ls1028a
+
+ deprecated:
+ - plat/nxp/ls1028a
+
+ subsections:
+ - title: LS1028ARDB
+ scope: ls1028ardb
+
+ deprecated:
+ - plat/nxp/ls1028ardb
+
+ - title: LS1043A
+ scope: ls1043a
+
+ deprecated:
+ - plat/nxp/ls1043a
+
+ subsections:
+ - title: LS1043ARDB
+ scope: ls1043ardb
+
+ deprecated:
+ - plat/nxp/ls1043ardb
+
+ - title: LX2
+ scope: lx2
+
+ deprecated:
+ - plat/nxp/lx2
+
+ subsections:
+ - title: LX216
+ scope: lx216
+
+ deprecated:
+ - plat/nxp/lx216x
+
+ subsections:
+ - title: LX2160
+ scope: lx2160
+
+ deprecated:
+ - plat/soc-lx2160
+
+ - title: LS1046A
+ scope: ls1046a
+
+ subsections:
+ - title: LS1046ARDB
+ scope: ls1046ardb
+
+ - title: LS1046AFRWY
+ scope: ls1046afrwy
+
+ - title: LS1046AQDS
+ scope: ls1046aqds
+
+ - title: LS1088A
+ scope: ls1088a
+
+ subsections:
+ - title: LS1088ARDB
+ scope: ls1088ardb
+
+ - title: LS1088AQDS
+ scope: ls1088aqds
+
+ - title: QEMU
+ scope: qemu
+
+ deprecated:
+ - plat/qemu
+
+ - title: QTI
+ scope: qti
+
+ deprecated:
+ - plat/qti
+
+ subsections:
+ - title: SC1780
+ scope: sc7180
+
+ deprecated:
+ - plat/qti/sc7180
+
+ - title: SC7280
+ scope: sc7280
+
+ deprecated:
+ - plat/qti/sc7280
+
+ - title: MSM8916
+ scope: msm8916
+
+ - title: Raspberry Pi
+ scope: rpi
+
+ subsections:
+ - title: Raspberry Pi 3
+ scope: rpi3
+
+ - title: Raspberry Pi 4
+ scope: rpi4
+
+ - title: Renesas
+ scope: renesas
+
+ subsections:
+ - title: R-Car
+ scope: rcar
+
+ deprecated:
+ - plat/rcar
+
+ subsections:
+ - title: R-Car 3
+ scope: rcar3
+
+ deprecated:
+ - plat/rcar3
+
+ - title: Rockchip
+ scope: rockchip
+
+ subsections:
+ - title: RK3399
+ scope: rk3399
+
+ deprecated:
+ - rockchip/rk3399
+ - rk3399/suspend
+
+ - title: Socionext
+ scope: socionext
+
+ subsections:
+ - title: Synquacer
+ scope: synquacer
+
+ deprecated:
+ - plat/synquacer
+
+ - title: ST
+ scope: st
+
+ deprecated:
+ - plat/st
+
+ subsections:
+ - title: STM32MP1
+ scope: stm32mp1
+
+ deprecated:
+ - plat/st/stm32mp1
+
+ subsections:
+ - title: STM32MP13
+ scope: stm32mp13
+
+ - title: STM32MP15
+ scope: stm32mp15
+
+ - title: Texas Instruments
+ scope: ti
+
+ subsections:
+ - title: K3
+ scope: k3
+
+ deprecated:
+ - ti-k3
+
+ - title: Xilinx
+ scope: xilinx
+
+ deprecated:
+ - plat/xilinx
+
+ subsections:
+ - title: Versal
+ scope: versal
+
+ deprecated:
+ - plat/xilinx/versal/include
+ - plat/xilinx/versal
+ - plat/versal
+
+ subsections:
+ - title: Versal NET
+ scope: versal-net
+
+ deprecated:
+ - versal_net
+
+ - title: ZynqMP
+ scope: zynqmp
+
+ deprecated:
+ - plat/zynqmp
+ - plat/xilinx/zynqmp
+
+ - title: Bootloader Images
+ scope: bl
+
+ deprecated:
+ - bl_common
+
+ subsections:
+ - title: BL1
+ scope: bl1
+
+ - title: BL2
+ scope: bl2
+
+ - title: BL31
+ scope: bl31
+
+ - title: BL32
+ scope: bl32
+
+ subsections:
+ - title: TSP
+ scope: tsp
+
+ - title: Services
+ scope: services
+
+ subsections:
+ - title: FF-A
+ scope: ff-a
+
+ deprecated:
+ - ffa
+
+ - title: RME
+ scope: rme
+
+ deprecated:
+ - rme/fid
+
+ subsections:
+ - title: TRP
+ scope: trp
+
+ - title: RMMD
+ scope: rmmd
+
+ - title: SPM
+ scope: spm
+
+ subsections:
+ - title: EL3 SPMC
+ scope: el3-spmc
+
+ deprecated:
+ - spmc
+
+ - title: SPMD
+ scope: spmd
+
+ - title: SPM MM
+ scope: spm-mm
+
+ - title: DRTM
+ scope: drtm
+
+ - title: TRNG
+ scope: trng
+
+ - title: Libraries
+
+ subsections:
+ - title: CPU Support
+ scope: cpus
+
+ deprecated:
+ - cpu
+ - errata
+ - errata_report
+
+ - title: EL3 Runtime
+ scope: el3-runtime
+
+ deprecated:
+ - el3_runtime
+
+ subsections:
+ - title: Context Management
+ scope: cm
+
+ - title: RAS
+ scope: ras
+
+ - title: FCONF
+ scope: fconf
+
+ - title: MPMM
+ scope: mpmm
+
+ - title: OP-TEE
+ scope: optee
+
+ deprecated:
+ - lib/optee
+
+ - title: PSCI
+ scope: psci
+
+ - title: GPT
+ scope: gpt
+
+ deprecated:
+ - gpt_rme
+
+ - title: SMCCC
+ scope: smccc
+
+ - title: Translation Tables
+ scope: xlat
+
+ - title: C Standard Library
+ scope: libc
+
+ - title: Locks
+ scope: locks
+
+ - title: PSA
+ scope: psa
+
+ deprecated:
+ - lib/psa
+
+ - title: Context Management
+ scope: context-mgmt
+
+ deprecated:
+ - context mgmt
+
+ - title: Semihosting
+ scope: semihosting
+
+ - title: Drivers
+
+ subsections:
+ - title: Authentication
+ scope: auth
+
+ deprecated:
+ - driver/auth
+
+ subsections:
+ - title: CryptoCell-713
+ scope: cc-713
+
+ - title: Crypto
+ scope: crypto
+
+ - title: mbedTLS
+ scope: mbedtls
+
+ - title: Generic Clock
+ scope: clk
+
+ - title: FWU
+ scope: fwu
+
+ deprecated:
+ - fwu_metadata
+
+ - title: I/O
+ scope: io
+
+ subsections:
+ - title: MTD
+ scope: mtd
+
+ deprecated:
+ - io_mtd
+
+ - title: Measured Boot
+ scope: measured-boot
+
+ deprecated:
+ - measured boot
+ - measured_boot
+
+ - title: MMC
+ scope: mmc
+
+ deprecated:
+ - drivers/mmc
+
+ - title: MTD
+ scope: mtd
+
+ deprecated:
+ - drivers/mtd
+
+ subsections:
+ - title: NAND
+ scope: nand
+
+ subsections:
+ - title: SPI NAND
+ scope: spi-nand
+
+ deprecated:
+ - spi_nand
+
+ - title: GUID Partition Tables Support
+ scope: guid-partition
+
+ - title: SCMI
+ scope: scmi
+
+ deprecated:
+ - scmi_common
+ - drivers/scmi-msg
+ - scmi-msg
+
+ - title: UFS
+ scope: ufs
+
+ - title: Arm
+ scope: arm-drivers
+
+ subsections:
+ - title: Ethos-N
+ scope: ethos-n
+
+ deprecated:
+ - drivers/arm/ethosn
+
+ - title: GIC
+ scope: gic
+
+ subsections:
+ - title: GICv3
+ scope: gicv3
+
+ deprecated:
+ - gicv3/multichip
+
+ subsections:
+ - title: GIC-600
+ scope: gic600
+
+ - title: GIC-600AE
+ scope: gic600ae
+
+ - title: SMMU
+ scope: smmu
+
+ - title: MHU
+ scope: mhu
+
+ deprecated:
+ - drivers/arm/mhu
+
+ - title: RSS
+ scope: rss
+
+ deprecated:
+ - drivers/arm/rss
+
+ - title: TZC
+ scope: tzc
+
+ subsections:
+ - title: TZC-400
+ scope: tzc400
+
+ deprecated:
+ - drivers/tzc400
+
+ - title: TZC-380
+ scope: tzc380
+
+ deprecated:
+ - drivers/tzc380
+
+ - title: Marvell
+ scope: marvell-drivers
+
+ subsections:
+ - title: COMPHY
+ scope: marvell-comphy
+
+ deprecated:
+ - drivers/marvell/comphy
+
+ subsections:
+ - title: Armada 3700
+ scope: marvell-comphy-3700
+
+ deprecated:
+ - drivers/marvell/comphy-3700
+
+ - title: CP110
+ scope: marvell-comphy-cp110
+
+ deprecated:
+ - drivers/marvell/comphy-cp110
+
+ - title: UART
+ scope: marvell-uart
+
+ deprecated:
+ - plat/marvell/uart
+
+ - title: Armada
+ scope: armada-drivers
+
+ subsections:
+ - title: A3K
+ scope: a3k-drivers
+
+ subsections:
+ - title: A3720
+ scope: a3720-uart
+
+ deprecated:
+ - plat/marvell/a3720/uart
+
+ - title: MediaTek
+ scope: mediatek-drivers
+
+ subsections:
+ - title: APU
+ scope: mediatek-apu
+
+ deprecated:
+ - plat/mediatek/apu
+
+ - title: EMI MPU
+ scope: mediatek-emi-mpu
+
+ deprecated:
+ - plat/mediatek/mpu
+
+ - title: PMIC Wrapper
+ scope: mediatek-pmic-wrapper
+
+ deprecated:
+ - plat/mediatek/pmic_wrap
+
+ - title: MT8192
+ scope: mt8192-drivers
+
+ subsections:
+ - title: SPM
+ scope: mt8192-spm
+
+ deprecated:
+ - mediatek/mt8192/spm
+
+ - title: NXP
+ scope: nxp-drivers
+
+ subsections:
+ - title: DCFG
+ scope: nxp-dcfg
+
+ deprecated:
+ - driver/nxp/dcfg
+
+ - title: FLEXSPI
+ scope: flexspi
+
+ deprecated:
+ - include/drivers/flexspi
+ - driver/nxp/xspi
+
+ - title: SCFG
+ scope: nxp-scfg
+
+ deprecated:
+ - nxp/scfg
+
+ - title: SFP
+ scope: nxp-sfp
+
+ deprecated:
+ - drivers/nxp/sfp
+
+ - title: QSPI
+ scope: nxp-qspi
+
+ - title: NXP Crypto
+ scope: nxp-crypto
+
+ - title: DDR
+ scope: nxp-ddr
+
+ - title: GIC
+ scope: nxp-gic
+
+ - title: CSU
+ scope: nxp-csu
+
+ - title: IFC NAND
+ scope: nxp-ifc-nand
+
+ - title: IFC NOR
+ scope: nxp-ifc-nor
+
+ - title: TZC-380
+ scope: nxp-tzc380
+
+ - title: Renesas
+ scope: renesas-drivers
+
+ subsections:
+ - title: R-Car3
+ scope: rcar3-drivers
+
+ deprecated:
+ - drivers/rcar3
+
+ - title: ST
+ scope: st-drivers
+
+ deprecated:
+ - drivers/st
+
+ subsections:
+ - title: BSEC
+ scope: st-bsec
+
+ - title: Clock
+ scope: st-clock
+
+ deprecated:
+ - stm32mp_clk
+ - drivers/st/clk
+ - stm32mp1_clk
+
+ - title: Crypto
+ scope: st-crypto
+
+ - title: DDR
+ scope: st-ddr
+
+ - title: I/O
+ scope: st-io-drivers
+
+ subsections:
+ - title: STM32 Image
+ scope: st-io-stm32image
+
+ deprecated:
+ - io-stm32image
+ - io_stm32image
+
+ - title: I2C
+ scope: st-i2c
+
+ - title: FMC
+ scope: st-fmc
+
+ - title: GPIO
+ scope: st-gpio
+
+ - title: SDMMC2
+ scope: st-sdmmc2
+
+ deprecated:
+ - stm32_sdmmc2
+
+ - title: ST PMIC
+ scope: st-pmic
+
+ deprecated:
+ - drivers/st/pmic
+
+ - title: STPMIC1
+ scope: stpmic1
+
+ - title: Regulator
+ scope: st-regulator
+
+ - title: Reset
+ scope: st-reset
+
+ - title: SPI
+ scope: st-spi
+
+ - title: UART
+ scope: st-uart
+
+ subsections:
+ - title: STM32 Console
+ scope: stm32-console
+
+ deprecated:
+ - stm32_console
+
+ - title: USB
+ scope: st-usb
+
+ deprecated:
+ - drivers/st/usb
+
+ - title: Watchdog
+ scope: st-iwdg
+
+ - title: USB
+ scope: usb
+
+ deprecated:
+ - drivers/usb
+
+ - title: Miscellaneous
+
+ subsections:
+ - title: AArch64
+ scope: aarch64
+
+ - title: Debug
+ scope: debug
+
+ deprecated:
+ - common/debug
+
+ - title: CRC32
+ scope: crc32
+
+ subsections:
+ - title: Hardware CRC32
+ scope: hw-crc32
+
+ deprecated:
+ - hw_crc
+ - hw_crc32
+
+ - title: Software CRC32
+ scope: sw-crc32
+
+ deprecated:
+ - sw_crc32
+
+ - title: DT Bindings
+ scope: dt-bindings
+
+ - title: FDT Wrappers
+ scope: fdt-wrappers
+
+ - title: FDTs
+ scope: fdts
+
+ deprecated:
+ - fdt
+
+ subsections:
+ - title: Morello
+ scope: morello-fdts
+
+ deprecated:
+ - fdts/morello
+
+ - title: STM32MP1
+ scope: stm32mp1-fdts
+
+ deprecated:
+ - fdts stm32mp1
+
+ subsections:
+ - title: STM32MP13
+ scope: stm32mp13-fdts
+
+ - title: STM32MP15
+ scope: stm32mp15-fdts
+
+ - title: PIE
+ scope: pie
+
+ - title: Security
+ scope: security
+
+ - title: SDEI
+ scope: sdei
+
+ - title: TBBR
+ scope: tbbr
+
+ - title: NXP
+
+ subsections:
+ - title: OCRAM
+ scope: nxp-ocram
+
+ deprecated:
+ - nxp/common/ocram
+
+ - title: PSCI
+ scope: nxp-psci
+
+ deprecated:
+ - plat/nxp/common/psci
+
+ - title: Documentation
+ scope: docs
+
+ deprecated:
+ - doc
+
+ subsections:
+ - title: Changelog
+ scope: changelog
+
+ - title: Commit Style
+ scope: commit-style
+
+ - title: Contribution Guidelines
+ scope: contributing
+
+ deprecated:
+ - contribution-guidelines
+ - docs-contributing.rst
+
+ - title: Maintainers
+ scope: maintainers
+
+ - title: Prerequisites
+ scope: prerequisites
+
+ - title: Threat Model
+ scope: threat-model
+
+ - title: Build System
+ scope: build
+
+ deprecated:
+ - makefile
+ - Makefile
+
+ subsections:
+ - title: Git Hooks
+ scope: hooks
+
+ - title: Tools
+
+ subsections:
+ - title: STM32 Image
+ scope: stm32image
+
+ deprecated:
+ - tools/stm32image
+
+ - title: NXP Tools
+ scope: nxp-tools
+
+ - title: Firmware Image Package Tool
+ scope: fiptool
+
+ - title: Secure Partition Tool
+ scope: sptool
+
+ - title: Certificate Creation Tool
+ scope: cert-create
+
+ deprecated:
+ - cert_create
+
+ - title: Dependencies
+ scope: deps
+
+ subsections:
+ - title: checkpatch
+ scope: checkpatch
+
+ - title: commitlint
+ scope: commitlint
+
+ - title: Compiler runtime libraries
+ scope: compiler-rt
+
+ - title: libfdt
+ scope: libfdt
+
+ - title: Node Package Manager (NPM)
+ scope: npm
+
+ - title: zlib
+ scope: zlib
+
diff --git a/common/aarch32/debug.S b/common/aarch32/debug.S
new file mode 100644
index 0000000..ae0bb7a
--- /dev/null
+++ b/common/aarch32/debug.S
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/debug.h>
+
+ .globl asm_print_str
+ .globl asm_print_hex
+ .globl asm_print_hex_bits
+ .globl asm_assert
+ .globl do_panic
+ .globl report_exception
+ .globl report_prefetch_abort
+ .globl report_data_abort
+
+/* 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'
+
+#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 "
+
+ /*
+ * 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: r4 = the decimal to print.
+ * Clobber: lr, r0, r1, r2, r5, r6
+ */
+ .macro asm_print_line_dec
+ mov r6, #10 /* Divide by 10 after every loop iteration */
+ ldr r5, =MAX_DEC_DIVISOR
+dec_print_loop:
+ udiv r0, r4, r5 /* Get the quotient */
+ mls r4, r0, r5, r4 /* Find the 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
+ .endm
+#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
+
+ /* Ensure the console is initialized */
+ bl plat_crash_console_init
+
+ /* Check if the console is initialized */
+ cmp r0, #0
+ beq _assert_loop
+
+ /* The console is initialized */
+ ldr r4, =assert_msg1
+ bl asm_print_str
+ mov r4, r5
+ bl asm_print_str
+ ldr r4, =assert_msg2
+ bl asm_print_str
+
+ /* Check if line number higher than max permitted */
+ ldr r4, =~0xffff
+ tst r6, r4
+ bne _assert_loop
+ 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
+ asm_print_line_dec
+#endif
+ 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 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 r5, #32 /* No of bits to convert to ascii */
+
+ /* Convert to ascii number of bits in r5 */
+asm_print_hex_bits:
+ mov r3, lr
+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
+
+ /***********************************************************
+ * The common implementation of do_panic for all BL stages
+ ***********************************************************/
+
+.section .rodata.panic_str, "aS"
+ panic_msg: .asciz "PANIC at PC : 0x"
+ panic_end: .asciz "\r\n"
+
+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
+
+ /* Check if the console is initialized */
+ cmp r0, #0
+ beq _panic_handler
+
+ /* The console is initialized */
+ 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
+
+_panic_handler:
+ 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
+
+ /***********************************************************
+ * This function is called from the vector table for
+ * unhandled exceptions. The lr_abt is given as an
+ * argument to platform handler.
+ ***********************************************************/
+func report_prefetch_abort
+#if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION)
+ b report_exception
+#else
+ mrs r0, lr_abt
+ bl plat_report_prefetch_abort
+ no_ret plat_panic_handler
+#endif
+endfunc report_prefetch_abort
+
+ /***********************************************************
+ * This function is called from the vector table for
+ * unhandled exceptions. The lr_abt is given as an
+ * argument to platform handler.
+ ***********************************************************/
+func report_data_abort
+#if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION)
+ b report_exception
+#else
+ mrs r0, lr_abt
+ bl plat_report_data_abort
+ no_ret plat_panic_handler
+#endif
+endfunc report_data_abort
diff --git a/common/aarch64/debug.S b/common/aarch64/debug.S
new file mode 100644
index 0000000..742e022
--- /dev/null
+++ b/common/aarch64/debug.S
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/debug.h>
+
+ .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
+ .weak elx_panic
+
+func do_panic
+#if CRASH_REPORTING
+ str x0, [sp, #-0x10]!
+ mrs x0, currentel
+ ubfx x0, x0, #MODE_EL_SHIFT, #MODE_EL_WIDTH
+ cmp x0, #MODE_EL3
+#if !HANDLE_EA_EL3_FIRST_NS
+ ldr x0, [sp], #0x10
+ b.eq el3_panic
+#else
+ b.ne to_panic_common
+
+ /* Check EL the exception taken from */
+ mrs x0, spsr_el3
+ ubfx x0, x0, #SPSR_EL_SHIFT, #SPSR_EL_WIDTH
+ cmp x0, #MODE_EL3
+ b.ne elx_panic
+ ldr x0, [sp], #0x10
+ b el3_panic
+
+to_panic_common:
+ ldr x0, [sp], #0x10
+#endif /* HANDLE_EA_EL3_FIRST_NS */
+#endif /* CRASH_REPORTING */
+
+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
+
+ /* Print new line */
+ bl asm_print_newline
+
+ 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
diff --git a/common/aarch64/early_exceptions.S b/common/aarch64/early_exceptions.S
new file mode 100644
index 0000000..36a8724
--- /dev/null
+++ b/common/aarch64/early_exceptions.S
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <common/bl_common.h>
+
+/* -----------------------------------------------------------------------------
+ * 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
diff --git a/common/backtrace/backtrace.c b/common/backtrace/backtrace.c
new file mode 100644
index 0000000..f994ae5
--- /dev/null
+++ b/common/backtrace/backtrace.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+
+/* 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;
+};
+
+static inline uintptr_t extract_address(uintptr_t address)
+{
+ uintptr_t ret = address;
+
+#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.
+ */
+
+ xpaci(ret);
+#endif
+
+ return ret;
+}
+
+/*
+ * 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 address)
+{
+ unsigned int el = get_current_el();
+ uintptr_t addr = extract_address(address);
+
+ if (el == 3U) {
+ ats1e3r(addr);
+ } else if (el == 2U) {
+ ats1e2r(addr);
+ } else {
+ AT(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;
+ }
+
+ call_site = extract_address(fr->return_addr);
+ if (call_site != 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 = extract_address(fr->return_addr) - 4U;
+
+ /*
+ * 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 */
+ 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);
+}
diff --git a/common/backtrace/backtrace.mk b/common/backtrace/backtrace.mk
new file mode 100644
index 0000000..e669331
--- /dev/null
+++ b/common/backtrace/backtrace.mk
@@ -0,0 +1,31 @@
+#
+# 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))
diff --git a/common/bl_common.c b/common/bl_common.c
new file mode 100644
index 0000000..8fce02f
--- /dev/null
+++ b/common/bl_common.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/auth/auth_mod.h>
+#include <drivers/io/io_storage.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/common/platform.h>
+
+#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_MASK) != 0U) {
+ value &= ~PAGE_SIZE_MASK;
+ 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;
+}
+
+#if TRUSTED_BOARD_BOOT
+/*
+ * This function uses recursion to authenticate the parent images up to the root
+ * of trust.
+ */
+static int load_auth_image_recursive(unsigned int image_id,
+ image_info_t *image_data,
+ int is_parent_image)
+{
+ int rc;
+ 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_recursive(parent_id, image_data, 1);
+ if (rc != 0) {
+ return rc;
+ }
+ }
+
+ /* Load the image */
+ rc = load_image(image_id, image_data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ /* 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;
+ }
+
+ return 0;
+}
+#endif /* TRUSTED_BOARD_BOOT */
+
+static int load_auth_image_internal(unsigned int image_id,
+ image_info_t *image_data)
+{
+#if TRUSTED_BOARD_BOOT
+ if (dyn_is_auth_disabled() == 0) {
+ return load_auth_image_recursive(image_id, image_data, 0);
+ }
+#endif
+
+ return load_image(image_id, image_data);
+}
+
+/*******************************************************************************
+ * 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 (if TBB is enabled).
+ ******************************************************************************/
+int load_auth_image(unsigned int image_id, image_info_t *image_data)
+{
+ int err;
+
+/*
+ * All firmware banks should be part of the same non-volatile storage as per
+ * PSA FWU specification, hence don't check for any alternate boot source
+ * when PSA FWU is enabled.
+ */
+#if PSA_FWU_SUPPORT
+ err = load_auth_image_internal(image_id, image_data);
+#else
+ do {
+ err = load_auth_image_internal(image_id, image_data);
+ } while ((err != 0) && (plat_try_next_boot_source() != 0));
+#endif /* PSA_FWU_SUPPORT */
+
+ if (err == 0) {
+ /*
+ * If loading of the image gets passed (along with its
+ * authentication in case of Trusted-Boot flow) then measure
+ * it (if MEASURED_BOOT flag is enabled).
+ */
+ err = plat_mboot_measure_image(image_id, image_data);
+ if (err != 0) {
+ return err;
+ }
+
+ /*
+ * Flush the image to main memory so that it can be executed
+ * later by any CPU, regardless of cache and MMU state.
+ */
+ flush_dcache_range(image_data->image_base,
+ image_data->image_size);
+ }
+
+ 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
+}
+
+/*
+ * This function is for returning the TF-A version
+ */
+const char *get_version(void)
+{
+ extern const char version[];
+ return version;
+}
diff --git a/common/desc_image_load.c b/common/desc_image_load.c
new file mode 100644
index 0000000..30b97e0
--- /dev/null
+++ b/common/desc_image_load.c
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <common/tbbr/tbbr_img_def.h>
+
+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 fw_config_base;
+ bl_mem_params_node_t *mem_params;
+ uintptr_t hw_config_base = 0;
+
+ 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:
+ /*
+ * At the moment, OPTEE cannot accept a DTB in secure memory,
+ * so fall back and use NT_FW_CONFIG instead.
+ * This MUST be fixed as soon as OPTEE has support to
+ * receive DTBs in secure memory.
+ */
+#ifndef SPD_opteed
+ fw_config_id = TOS_FW_CONFIG_ID;
+ break;
+#endif
+ 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;
+ }
+ }
+
+#ifdef SPD_opteed
+ /*
+ * If SPD_opteed is enabled, arg[0,2] are populated by
+ * parse_optee_header(), which is called by
+ * arm_bl2_handle_post_image_load(). The meaning of the
+ * arguments are:
+ * arg0 <-- MODE_RW
+ * arg1 <-- Paged image base
+ * arg2 <-- Paged image size
+ */
+ if (params_node->image_id == BL32_IMAGE_ID) {
+ params_node->ep_info->args.arg3 = fw_config_base;
+ } else {
+#endif
+ /*
+ * 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;
+ }
+#ifdef SPD_opteed
+ }
+#endif
+ }
+}
+
+/*******************************************************************************
+ * 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 != NULL)
+ *bl32_ep_info_out = *v1->bl32_ep_info;
+ if (bl33_ep_info_out != NULL)
+ *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 != NULL; node = node->next_params_info) {
+ if (node->image_id == BL32_IMAGE_ID)
+ if (bl32_ep_info_out != NULL)
+ *bl32_ep_info_out = *node->ep_info;
+ if (node->image_id == BL33_IMAGE_ID)
+ if (bl33_ep_info_out != NULL)
+ *bl33_ep_info_out = *node->ep_info;
+ }
+}
diff --git a/common/fdt_fixup.c b/common/fdt_fixup.c
new file mode 100644
index 0000000..1bad74f
--- /dev/null
+++ b/common/fdt_fixup.c
@@ -0,0 +1,626 @@
+/*
+ * Copyright (c) 2016-2022, 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 <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <libfdt.h>
+
+#include <arch.h>
+#include <common/debug.h>
+#include <common/fdt_fixup.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/console.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+
+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 negative values 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;
+ int ret;
+
+ prop = fdt_getprop(fdt, offs, "device_type", &len);
+ if (prop == NULL)
+ continue;
+ if ((strcmp(prop, "cpu") != 0) || (len != 4))
+ continue;
+
+ /* Ignore any nodes which already use "psci". */
+ prop = fdt_getprop(fdt, offs, "enable-method", &len);
+ if ((prop != NULL) &&
+ (strcmp(prop, "psci") == 0) && (len == 5))
+ continue;
+
+ ret = fdt_setprop_string(fdt, offs, "enable-method", "psci");
+ if (ret < 0)
+ return ret;
+ /*
+ * 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.
+ * According to this binding, the address-cells and size-cells must match
+ * those of the root node.
+ *
+ * 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[4];
+ int ac, sc;
+ unsigned int idx = 0;
+
+ ac = fdt_address_cells(dtb, 0);
+ sc = fdt_size_cells(dtb, 0);
+ 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", ac);
+ fdt_setprop_u32(dtb, offs, "#size-cells", sc);
+ fdt_setprop(dtb, offs, "ranges", NULL, 0);
+ }
+
+ if (ac > 1) {
+ addresses[idx] = cpu_to_fdt32(HIGH_BITS(base));
+ idx++;
+ }
+ addresses[idx] = cpu_to_fdt32(base & 0xffffffff);
+ idx++;
+ if (sc > 1) {
+ addresses[idx] = cpu_to_fdt32(HIGH_BITS(size));
+ idx++;
+ }
+ addresses[idx] = cpu_to_fdt32(size & 0xffffffff);
+ idx++;
+ offs = fdt_add_subnode(dtb, offs, node_name);
+ fdt_setprop(dtb, offs, "no-map", NULL, 0);
+ fdt_setprop(dtb, offs, "reg", addresses, idx * sizeof(uint32_t));
+
+ return 0;
+}
+
+/*******************************************************************************
+ * fdt_add_cpu() Add a new CPU node to the DT
+ * @dtb: Pointer to the device tree blob in memory
+ * @parent: Offset of the parent node
+ * @mpidr: MPIDR for the current CPU
+ *
+ * Create and add a new cpu node to a DTB.
+ *
+ * Return the offset of the new node or a negative value in case of error
+ ******************************************************************************/
+
+static int fdt_add_cpu(void *dtb, int parent, u_register_t mpidr)
+{
+ int cpu_offs;
+ int err;
+ char snode_name[15];
+ uint64_t reg_prop;
+
+ reg_prop = mpidr & MPID_MASK & ~MPIDR_MT_MASK;
+
+ snprintf(snode_name, sizeof(snode_name), "cpu@%x",
+ (unsigned int)reg_prop);
+
+ cpu_offs = fdt_add_subnode(dtb, parent, snode_name);
+ if (cpu_offs < 0) {
+ ERROR ("FDT: add subnode \"%s\" failed: %i\n",
+ snode_name, cpu_offs);
+ return cpu_offs;
+ }
+
+ err = fdt_setprop_string(dtb, cpu_offs, "compatible", "arm,armv8");
+ if (err < 0) {
+ ERROR ("FDT: write to \"%s\" property of node at offset %i failed\n",
+ "compatible", cpu_offs);
+ return err;
+ }
+
+ err = fdt_setprop_u64(dtb, cpu_offs, "reg", reg_prop);
+ if (err < 0) {
+ ERROR ("FDT: write to \"%s\" property of node at offset %i failed\n",
+ "reg", cpu_offs);
+ return err;
+ }
+
+ err = fdt_setprop_string(dtb, cpu_offs, "device_type", "cpu");
+ if (err < 0) {
+ ERROR ("FDT: write to \"%s\" property of node at offset %i failed\n",
+ "device_type", cpu_offs);
+ return err;
+ }
+
+ err = fdt_setprop_string(dtb, cpu_offs, "enable-method", "psci");
+ if (err < 0) {
+ ERROR ("FDT: write to \"%s\" property of node at offset %i failed\n",
+ "enable-method", cpu_offs);
+ return err;
+ }
+
+ return cpu_offs;
+}
+
+/******************************************************************************
+ * fdt_add_cpus_node() - Add the cpus node to the DTB
+ * @dtb: pointer to the device tree blob in memory
+ * @afflv0: Maximum number of threads per core (affinity level 0).
+ * @afflv1: Maximum number of CPUs per cluster (affinity level 1).
+ * @afflv2: Maximum number of clusters (affinity level 2).
+ *
+ * Iterate over all the possible MPIDs given the maximum affinity levels and
+ * add a cpus node to the DTB with all the valid CPUs on the system.
+ * If there is already a /cpus node, exit gracefully
+ *
+ * A system with two CPUs would generate a node equivalent or similar to:
+ *
+ * cpus {
+ * #address-cells = <2>;
+ * #size-cells = <0>;
+ *
+ * cpu0: cpu@0 {
+ * compatible = "arm,armv8";
+ * reg = <0x0 0x0>;
+ * device_type = "cpu";
+ * enable-method = "psci";
+ * };
+ * cpu1: cpu@10000 {
+ * compatible = "arm,armv8";
+ * reg = <0x0 0x100>;
+ * device_type = "cpu";
+ * enable-method = "psci";
+ * };
+ * };
+ *
+ * Full documentation about the CPU bindings can be found at:
+ * https://www.kernel.org/doc/Documentation/devicetree/bindings/arm/cpus.txt
+ *
+ * Return the offset of the node or a negative value on error.
+ ******************************************************************************/
+
+int fdt_add_cpus_node(void *dtb, unsigned int afflv0,
+ unsigned int afflv1, unsigned int afflv2)
+{
+ int offs;
+ int err;
+ unsigned int i, j, k;
+ u_register_t mpidr;
+ int cpuid;
+
+ if (fdt_path_offset(dtb, "/cpus") >= 0) {
+ return -EEXIST;
+ }
+
+ offs = fdt_add_subnode(dtb, 0, "cpus");
+ if (offs < 0) {
+ ERROR ("FDT: add subnode \"cpus\" node to parent node failed");
+ return offs;
+ }
+
+ err = fdt_setprop_u32(dtb, offs, "#address-cells", 2);
+ if (err < 0) {
+ ERROR ("FDT: write to \"%s\" property of node at offset %i failed\n",
+ "#address-cells", offs);
+ return err;
+ }
+
+ err = fdt_setprop_u32(dtb, offs, "#size-cells", 0);
+ if (err < 0) {
+ ERROR ("FDT: write to \"%s\" property of node at offset %i failed\n",
+ "#size-cells", offs);
+ return err;
+ }
+
+ /*
+ * Populate the node with the CPUs.
+ * As libfdt prepends subnodes within a node, reverse the index count
+ * so the CPU nodes would be better ordered.
+ */
+ for (i = afflv2; i > 0U; i--) {
+ for (j = afflv1; j > 0U; j--) {
+ for (k = afflv0; k > 0U; k--) {
+ mpidr = ((i - 1) << MPIDR_AFF2_SHIFT) |
+ ((j - 1) << MPIDR_AFF1_SHIFT) |
+ ((k - 1) << MPIDR_AFF0_SHIFT) |
+ (read_mpidr_el1() & MPIDR_MT_MASK);
+
+ cpuid = plat_core_pos_by_mpidr(mpidr);
+ if (cpuid >= 0) {
+ /* Valid MPID found */
+ err = fdt_add_cpu(dtb, offs, mpidr);
+ if (err < 0) {
+ ERROR ("FDT: %s 0x%08x\n",
+ "error adding CPU",
+ (uint32_t)mpidr);
+ return err;
+ }
+ }
+ }
+ }
+ }
+
+ return offs;
+}
+
+/*******************************************************************************
+ * fdt_add_cpu_idle_states() - add PSCI CPU idle states to cpu nodes in the DT
+ * @dtb: pointer to the device tree blob in memory
+ * @states: array of idle state descriptions, ending with empty element
+ *
+ * Add information about CPU idle states to the devicetree. This function
+ * assumes that CPU idle states are not already present in the devicetree, and
+ * that all CPU states are equally applicable to all CPUs.
+ *
+ * See arm/idle-states.yaml and arm/psci.yaml in the (Linux kernel) DT binding
+ * documentation for more details.
+ *
+ * Return: 0 on success, a negative error value otherwise.
+ ******************************************************************************/
+int fdt_add_cpu_idle_states(void *dtb, const struct psci_cpu_idle_state *state)
+{
+ int cpu_node, cpus_node, idle_states_node, ret;
+ uint32_t count, phandle;
+
+ ret = fdt_find_max_phandle(dtb, &phandle);
+ phandle++;
+ if (ret < 0) {
+ return ret;
+ }
+
+ cpus_node = fdt_path_offset(dtb, "/cpus");
+ if (cpus_node < 0) {
+ return cpus_node;
+ }
+
+ /* Create the idle-states node and its child nodes. */
+ idle_states_node = fdt_add_subnode(dtb, cpus_node, "idle-states");
+ if (idle_states_node < 0) {
+ return idle_states_node;
+ }
+
+ ret = fdt_setprop_string(dtb, idle_states_node, "entry-method", "psci");
+ if (ret < 0) {
+ return ret;
+ }
+
+ for (count = 0U; state->name != NULL; count++, phandle++, state++) {
+ int idle_state_node;
+
+ idle_state_node = fdt_add_subnode(dtb, idle_states_node,
+ state->name);
+ if (idle_state_node < 0) {
+ return idle_state_node;
+ }
+
+ fdt_setprop_string(dtb, idle_state_node, "compatible",
+ "arm,idle-state");
+ fdt_setprop_u32(dtb, idle_state_node, "arm,psci-suspend-param",
+ state->power_state);
+ if (state->local_timer_stop) {
+ fdt_setprop_empty(dtb, idle_state_node,
+ "local-timer-stop");
+ }
+ fdt_setprop_u32(dtb, idle_state_node, "entry-latency-us",
+ state->entry_latency_us);
+ fdt_setprop_u32(dtb, idle_state_node, "exit-latency-us",
+ state->exit_latency_us);
+ fdt_setprop_u32(dtb, idle_state_node, "min-residency-us",
+ state->min_residency_us);
+ if (state->wakeup_latency_us) {
+ fdt_setprop_u32(dtb, idle_state_node,
+ "wakeup-latency-us",
+ state->wakeup_latency_us);
+ }
+ fdt_setprop_u32(dtb, idle_state_node, "phandle", phandle);
+ }
+
+ if (count == 0U) {
+ return 0;
+ }
+
+ /* Link each cpu node to the idle state nodes. */
+ fdt_for_each_subnode(cpu_node, dtb, cpus_node) {
+ const char *device_type;
+ fdt32_t *value;
+
+ /* Only process child nodes with device_type = "cpu". */
+ device_type = fdt_getprop(dtb, cpu_node, "device_type", NULL);
+ if (device_type == NULL || strcmp(device_type, "cpu") != 0) {
+ continue;
+ }
+
+ /* Allocate space for the list of phandles. */
+ ret = fdt_setprop_placeholder(dtb, cpu_node, "cpu-idle-states",
+ count * sizeof(phandle),
+ (void **)&value);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* Fill in the phandles of the idle state nodes. */
+ for (uint32_t i = 0U; i < count; ++i) {
+ value[i] = cpu_to_fdt32(phandle - count + i);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * fdt_adjust_gic_redist() - Adjust GICv3 redistributor size
+ * @dtb: Pointer to the DT blob in memory
+ * @nr_cores: Number of CPU cores on this system.
+ * @gicr_base: Base address of the first GICR frame, or ~0 if unchanged
+ * @gicr_frame_size: Size of the GICR frame per core
+ *
+ * On a GICv3 compatible interrupt controller, the redistributor provides
+ * a number of 64k pages per each supported core. So with a dynamic topology,
+ * this size cannot be known upfront and thus can't be hardcoded into the DTB.
+ *
+ * Find the DT node describing the GICv3 interrupt controller, and adjust
+ * the size of the redistributor to match the number of actual cores on
+ * this system.
+ * A GICv4 compatible redistributor uses four 64K pages per core, whereas GICs
+ * without support for direct injection of virtual interrupts use two 64K pages.
+ * The @gicr_frame_size parameter should be 262144 and 131072, respectively.
+ * Also optionally allow adjusting the GICR frame base address, when this is
+ * different due to ITS frames between distributor and redistributor.
+ *
+ * Return: 0 on success, negative error value otherwise.
+ */
+int fdt_adjust_gic_redist(void *dtb, unsigned int nr_cores,
+ uintptr_t gicr_base, unsigned int gicr_frame_size)
+{
+ int offset = fdt_node_offset_by_compatible(dtb, 0, "arm,gic-v3");
+ uint64_t reg_64;
+ uint32_t reg_32;
+ void *val;
+ int parent, ret;
+ int ac, sc;
+
+ if (offset < 0) {
+ return offset;
+ }
+
+ parent = fdt_parent_offset(dtb, offset);
+ if (parent < 0) {
+ return parent;
+ }
+ ac = fdt_address_cells(dtb, parent);
+ sc = fdt_size_cells(dtb, parent);
+ if (ac < 0 || sc < 0) {
+ return -EINVAL;
+ }
+
+ if (gicr_base != INVALID_BASE_ADDR) {
+ if (ac == 1) {
+ reg_32 = cpu_to_fdt32(gicr_base);
+ val = &reg_32;
+ } else {
+ reg_64 = cpu_to_fdt64(gicr_base);
+ val = &reg_64;
+ }
+ /*
+ * The redistributor base address is the second address in
+ * the "reg" entry, so we have to skip one address and one
+ * size cell.
+ */
+ ret = fdt_setprop_inplace_namelen_partial(dtb, offset,
+ "reg", 3,
+ (ac + sc) * 4,
+ val, ac * 4);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ if (sc == 1) {
+ reg_32 = cpu_to_fdt32(nr_cores * gicr_frame_size);
+ val = &reg_32;
+ } else {
+ reg_64 = cpu_to_fdt64(nr_cores * (uint64_t)gicr_frame_size);
+ val = &reg_64;
+ }
+
+ /*
+ * The redistributor is described in the second "reg" entry.
+ * So we have to skip one address and one size cell, then another
+ * address cell to get to the second size cell.
+ */
+ return fdt_setprop_inplace_namelen_partial(dtb, offset, "reg", 3,
+ (ac + sc + ac) * 4,
+ val, sc * 4);
+}
+/**
+ * fdt_set_mac_address () - store MAC address in device tree
+ * @dtb: pointer to the device tree blob in memory
+ * @eth_idx: number of Ethernet interface in /aliases node
+ * @mac_addr: pointer to 6 byte MAC address to store
+ *
+ * Use the generic local-mac-address property in a network device DT node
+ * to define the MAC address this device should be using. Many platform
+ * network devices lack device-specific non-volatile storage to hold this
+ * address, and leave it up to firmware to find and store a unique MAC
+ * address in the DT.
+ * The MAC address could be read from some board or firmware defined storage,
+ * or could be derived from some other unique property like a serial number.
+ *
+ * Return: 0 on success, a negative libfdt error value otherwise.
+ */
+int fdt_set_mac_address(void *dtb, unsigned int ethernet_idx,
+ const uint8_t *mac_addr)
+{
+ char eth_alias[12];
+ const char *path;
+ int node;
+
+ if (ethernet_idx > 9U) {
+ return -FDT_ERR_BADVALUE;
+ }
+ snprintf(eth_alias, sizeof(eth_alias), "ethernet%d", ethernet_idx);
+
+ path = fdt_get_alias(dtb, eth_alias);
+ if (path == NULL) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ node = fdt_path_offset(dtb, path);
+ if (node < 0) {
+ ERROR("Path \"%s\" not found in DT: %d\n", path, node);
+ return node;
+ }
+
+ return fdt_setprop(dtb, node, "local-mac-address", mac_addr, 6);
+}
diff --git a/common/fdt_wrappers.c b/common/fdt_wrappers.c
new file mode 100644
index 0000000..1b065b1
--- /dev/null
+++ b/common/fdt_wrappers.c
@@ -0,0 +1,641 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Helper functions to offer easier navigation of Device Tree Blob */
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <libfdt.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <common/uuid.h>
+
+/*
+ * Read cells from a given property of the given node. Any number of 32-bit
+ * cells of the property can be read. Returns 0 on success, or a negative
+ * FDT error value otherwise.
+ */
+int fdt_read_uint32_array(const void *dtb, int node, const char *prop_name,
+ unsigned int cells, uint32_t *value)
+{
+ const fdt32_t *prop;
+ int value_len;
+
+ assert(dtb != NULL);
+ assert(prop_name != NULL);
+ assert(value != NULL);
+ assert(node >= 0);
+
+ /* Access property and obtain its length (in bytes) */
+ prop = fdt_getprop(dtb, node, prop_name, &value_len);
+ if (prop == NULL) {
+ VERBOSE("Couldn't find property %s in dtb\n", prop_name);
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ /* Verify that property length can fill the entire array. */
+ if (NCELLS((unsigned int)value_len) < cells) {
+ WARN("Property length mismatch\n");
+ return -FDT_ERR_BADVALUE;
+ }
+
+ for (unsigned int i = 0U; i < cells; i++) {
+ value[i] = fdt32_to_cpu(prop[i]);
+ }
+
+ return 0;
+}
+
+int fdt_read_uint32(const void *dtb, int node, const char *prop_name,
+ uint32_t *value)
+{
+ return fdt_read_uint32_array(dtb, node, prop_name, 1, value);
+}
+
+uint32_t fdt_read_uint32_default(const void *dtb, int node,
+ const char *prop_name, uint32_t dflt_value)
+{
+ uint32_t ret = dflt_value;
+ int err = fdt_read_uint32(dtb, node, prop_name, &ret);
+
+ if (err < 0) {
+ return dflt_value;
+ }
+
+ return ret;
+}
+
+int fdt_read_uint64(const void *dtb, int node, const char *prop_name,
+ uint64_t *value)
+{
+ uint32_t array[2] = {0, 0};
+ int ret;
+
+ ret = fdt_read_uint32_array(dtb, node, prop_name, 2, array);
+ if (ret < 0) {
+ return ret;
+ }
+
+ *value = ((uint64_t)array[0] << 32) | array[1];
+ return 0;
+}
+
+/*
+ * Read bytes from a given property of the given node. Any number of
+ * bytes of the property can be read. The fdt pointer is updated.
+ * Returns 0 on success, and -1 on error.
+ */
+int fdtw_read_bytes(const void *dtb, int node, const char *prop,
+ unsigned int length, void *value)
+{
+ const void *ptr;
+ int value_len;
+
+ assert(dtb != NULL);
+ assert(prop != NULL);
+ assert(value != NULL);
+ assert(node >= 0);
+
+ /* Access property and obtain its length (in bytes) */
+ ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop),
+ &value_len);
+ if (ptr == NULL) {
+ WARN("Couldn't find property %s in dtb\n", prop);
+ return -1;
+ }
+
+ /* Verify that property length is not less than number of bytes */
+ if ((unsigned int)value_len < length) {
+ WARN("Property length mismatch\n");
+ return -1;
+ }
+
+ (void)memcpy(value, ptr, length);
+
+ 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;
+}
+
+/*
+ * Read UUID from a given property of the given node. Returns 0 on success,
+ * and a negative value upon error.
+ */
+int fdtw_read_uuid(const void *dtb, int node, const char *prop,
+ unsigned int length, uint8_t *uuid)
+{
+ /* Buffer for UUID string (plus NUL terminator) */
+ char uuid_string[UUID_STRING_LENGTH + 1U];
+ int err;
+
+ assert(dtb != NULL);
+ assert(prop != NULL);
+ assert(uuid != NULL);
+ assert(node >= 0);
+
+ if (length < UUID_BYTES_LENGTH) {
+ return -EINVAL;
+ }
+
+ err = fdtw_read_string(dtb, node, prop, uuid_string,
+ UUID_STRING_LENGTH + 1U);
+ if (err != 0) {
+ return err;
+ }
+
+ if (read_uuid(uuid, uuid_string) != 0) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ 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;
+}
+
+/*
+ * Write bytes in place to a given property of the given node.
+ * Any number of bytes of the property can be written.
+ * Returns 0 on success, and < 0 on error.
+ */
+int fdtw_write_inplace_bytes(void *dtb, int node, const char *prop,
+ unsigned int length, const void *data)
+{
+ const void *ptr;
+ int namelen, value_len, err;
+
+ assert(dtb != NULL);
+ assert(prop != NULL);
+ assert(data != NULL);
+ assert(node >= 0);
+
+ namelen = (int)strlen(prop);
+
+ /* Access property and obtain its length in bytes */
+ ptr = fdt_getprop_namelen(dtb, node, prop, namelen, &value_len);
+ if (ptr == NULL) {
+ WARN("Couldn't find property %s in dtb\n", prop);
+ return -1;
+ }
+
+ /* Verify that property length is not less than number of bytes */
+ if ((unsigned int)value_len < length) {
+ WARN("Property length mismatch\n");
+ return -1;
+ }
+
+ /* Set property value in place */
+ err = fdt_setprop_inplace_namelen_partial(dtb, node, prop,
+ namelen, 0,
+ data, (int)length);
+ if (err != 0) {
+ WARN("Set property %s failed with error %d\n", prop, err);
+ }
+
+ return err;
+}
+
+static uint64_t fdt_read_prop_cells(const fdt32_t *prop, int nr_cells)
+{
+ uint64_t reg = fdt32_to_cpu(prop[0]);
+
+ if (nr_cells > 1) {
+ reg = (reg << 32) | fdt32_to_cpu(prop[1]);
+ }
+
+ return reg;
+}
+
+int fdt_get_reg_props_by_index(const void *dtb, int node, int index,
+ uintptr_t *base, size_t *size)
+{
+ const fdt32_t *prop;
+ int parent, len;
+ int ac, sc;
+ int cell;
+
+ parent = fdt_parent_offset(dtb, node);
+ if (parent < 0) {
+ return -FDT_ERR_BADOFFSET;
+ }
+
+ ac = fdt_address_cells(dtb, parent);
+ sc = fdt_size_cells(dtb, parent);
+
+ cell = index * (ac + sc);
+
+ prop = fdt_getprop(dtb, node, "reg", &len);
+ if (prop == NULL) {
+ WARN("Couldn't find \"reg\" property in dtb\n");
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ if (((cell + ac + sc) * (int)sizeof(uint32_t)) > len) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ if (base != NULL) {
+ *base = (uintptr_t)fdt_read_prop_cells(&prop[cell], ac);
+ }
+
+ if (size != NULL) {
+ *size = (size_t)fdt_read_prop_cells(&prop[cell + ac], sc);
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ * This function fills reg node info (base & size) with an index found by
+ * checking the reg-names node.
+ * Returns 0 on success and a negative FDT error code on failure.
+ ******************************************************************************/
+int fdt_get_reg_props_by_name(const void *dtb, int node, const char *name,
+ uintptr_t *base, size_t *size)
+{
+ int index;
+
+ index = fdt_stringlist_search(dtb, node, "reg-names", name);
+ if (index < 0) {
+ return index;
+ }
+
+ return fdt_get_reg_props_by_index(dtb, node, index, base, size);
+}
+
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+int fdt_get_stdout_node_offset(const void *dtb)
+{
+ int node;
+ const char *prop, *path;
+ int len;
+
+ /* The /secure-chosen node takes precedence over the standard one. */
+ node = fdt_path_offset(dtb, "/secure-chosen");
+ if (node < 0) {
+ node = fdt_path_offset(dtb, "/chosen");
+ if (node < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+ }
+
+ prop = fdt_getprop(dtb, node, "stdout-path", NULL);
+ if (prop == NULL) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ /* Determine the actual path length, as a colon terminates the path. */
+ path = strchr(prop, ':');
+ if (path == NULL) {
+ len = strlen(prop);
+ } else {
+ len = path - prop;
+ }
+
+ /* Aliases cannot start with a '/', so it must be the actual path. */
+ if (prop[0] == '/') {
+ return fdt_path_offset_namelen(dtb, prop, len);
+ }
+
+ /* Lookup the alias, as this contains the actual path. */
+ path = fdt_get_alias_namelen(dtb, prop, len);
+ if (path == NULL) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ return fdt_path_offset(dtb, path);
+}
+
+
+/*******************************************************************************
+ * Only devices which are direct children of root node use CPU address domain.
+ * All other devices use addresses that are local to the device node and cannot
+ * directly used by CPU. Device tree provides an address translation mechanism
+ * through "ranges" property which provides mappings from local address space to
+ * parent address space. Since a device could be a child of a child node to the
+ * root node, there can be more than one level of address translation needed to
+ * map the device local address space to CPU address space.
+ * fdtw_translate_address() API performs address translation of a local address
+ * to a global address with help of various helper functions.
+ ******************************************************************************/
+
+static bool fdtw_xlat_hit(const uint32_t *value, int child_addr_size,
+ int parent_addr_size, int range_size, uint64_t base_address,
+ uint64_t *translated_addr)
+{
+ uint64_t local_address, parent_address, addr_range;
+
+ local_address = fdt_read_prop_cells(value, child_addr_size);
+ parent_address = fdt_read_prop_cells(value + child_addr_size,
+ parent_addr_size);
+ addr_range = fdt_read_prop_cells(value + child_addr_size +
+ parent_addr_size,
+ range_size);
+ VERBOSE("DT: Address %" PRIx64 " mapped to %" PRIx64 " with range %" PRIx64 "\n",
+ local_address, parent_address, addr_range);
+
+ /* Perform range check */
+ if ((base_address < local_address) ||
+ (base_address >= local_address + addr_range)) {
+ return false;
+ }
+
+ /* Found hit for the addr range that needs to be translated */
+ *translated_addr = parent_address + (base_address - local_address);
+ VERBOSE("DT: child address %" PRIx64 "mapped to %" PRIx64 " in parent bus\n",
+ local_address, parent_address);
+ return true;
+}
+
+#define ILLEGAL_ADDR ULL(~0)
+
+static uint64_t fdtw_search_all_xlat_entries(const void *dtb,
+ const struct fdt_property *ranges_prop,
+ int local_bus, uint64_t base_address)
+{
+ uint64_t translated_addr;
+ const uint32_t *next_entry;
+ int parent_bus_node, nxlat_entries, length;
+ int self_addr_cells, parent_addr_cells, self_size_cells, ncells_xlat;
+
+ /*
+ * The number of cells in one translation entry in ranges is the sum of
+ * the following values:
+ * self#address-cells + parent#address-cells + self#size-cells
+ * Ex: the iofpga ranges property has one translation entry with 4 cells
+ * They represent iofpga#addr-cells + motherboard#addr-cells + iofpga#size-cells
+ * = 1 + 2 + 1
+ */
+
+ parent_bus_node = fdt_parent_offset(dtb, local_bus);
+ self_addr_cells = fdt_address_cells(dtb, local_bus);
+ self_size_cells = fdt_size_cells(dtb, local_bus);
+ parent_addr_cells = fdt_address_cells(dtb, parent_bus_node);
+
+ /* Number of cells per translation entry i.e., mapping */
+ ncells_xlat = self_addr_cells + parent_addr_cells + self_size_cells;
+
+ assert(ncells_xlat > 0);
+
+ /*
+ * Find the number of translations(mappings) specified in the current
+ * `ranges` property. Note that length represents number of bytes and
+ * is stored in big endian mode.
+ */
+ length = fdt32_to_cpu(ranges_prop->len);
+ nxlat_entries = (length/sizeof(uint32_t))/ncells_xlat;
+
+ assert(nxlat_entries > 0);
+
+ next_entry = (const uint32_t *)ranges_prop->data;
+
+ /* Iterate over the entries in the "ranges" */
+ for (int i = 0; i < nxlat_entries; i++) {
+ if (fdtw_xlat_hit(next_entry, self_addr_cells,
+ parent_addr_cells, self_size_cells, base_address,
+ &translated_addr)){
+ return translated_addr;
+ }
+ next_entry = next_entry + ncells_xlat;
+ }
+
+ INFO("DT: No translation found for address %" PRIx64 " in node %s\n",
+ base_address, fdt_get_name(dtb, local_bus, NULL));
+ return ILLEGAL_ADDR;
+}
+
+
+/*******************************************************************************
+ * address mapping needs to be done recursively starting from current node to
+ * root node through all intermediate parent nodes.
+ * Sample device tree is shown here:
+
+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>;
+
+ motherboard {
+ arm,v2m-memory-map = "rs1";
+ compatible = "arm,vexpress,v2m-p1", "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges;
+
+ iofpga@3,00000000 {
+ compatible = "arm,amba-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 3 0 0x200000>;
+ 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";
+ };
+ };
+};
+
+ * As seen above, there are 3 levels of address translations needed. An empty
+ * `ranges` property denotes identity mapping (as seen in `motherboard` node).
+ * Each ranges property can map a set of child addresses to parent bus. Hence
+ * there can be more than 1 (translation) entry in the ranges property as seen
+ * in the `smb` node which has 6 translation entries.
+ ******************************************************************************/
+
+/* Recursive implementation */
+uint64_t fdtw_translate_address(const void *dtb, int node,
+ uint64_t base_address)
+{
+ int length, local_bus_node;
+ const char *node_name;
+ uint64_t global_address;
+
+ local_bus_node = fdt_parent_offset(dtb, node);
+ node_name = fdt_get_name(dtb, local_bus_node, NULL);
+
+ /*
+ * In the example given above, starting from the leaf node:
+ * uart@a000 represents the current node
+ * iofpga@3,00000000 represents the local bus
+ * motherboard represents the parent bus
+ */
+
+ /* Read the ranges property */
+ const struct fdt_property *property = fdt_get_property(dtb,
+ local_bus_node, "ranges", &length);
+
+ if (property == NULL) {
+ if (local_bus_node == 0) {
+ /*
+ * root node doesn't have range property as addresses
+ * are in CPU address space.
+ */
+ return base_address;
+ }
+ INFO("DT: Couldn't find ranges property in node %s\n",
+ node_name);
+ return ILLEGAL_ADDR;
+ } else if (length == 0) {
+ /* empty ranges indicates identity map to parent bus */
+ return fdtw_translate_address(dtb, local_bus_node, base_address);
+ }
+
+ VERBOSE("DT: Translation lookup in node %s at offset %d\n", node_name,
+ local_bus_node);
+ global_address = fdtw_search_all_xlat_entries(dtb, property,
+ local_bus_node, base_address);
+
+ if (global_address == ILLEGAL_ADDR) {
+ return ILLEGAL_ADDR;
+ }
+
+ /* Translate the local device address recursively */
+ return fdtw_translate_address(dtb, local_bus_node, global_address);
+}
+
+/*
+ * For every CPU node (`/cpus/cpu@n`) in an FDT, execute a callback passing a
+ * pointer to the FDT and the offset of the CPU node. If the return value of the
+ * callback is negative, it is treated as an error and the loop is aborted. In
+ * this situation, the value of the callback is returned from the function.
+ *
+ * Returns `0` on success, or a negative integer representing an error code.
+ */
+int fdtw_for_each_cpu(const void *dtb,
+ int (*callback)(const void *dtb, int node, uintptr_t mpidr))
+{
+ int ret = 0;
+ int parent, node = 0;
+
+ parent = fdt_path_offset(dtb, "/cpus");
+ if (parent < 0) {
+ return parent;
+ }
+
+ fdt_for_each_subnode(node, dtb, parent) {
+ const char *name;
+ int len;
+
+ uintptr_t mpidr = 0U;
+
+ name = fdt_get_name(dtb, node, &len);
+ if (strncmp(name, "cpu@", 4) != 0) {
+ continue;
+ }
+
+ ret = fdt_get_reg_props_by_index(dtb, node, 0, &mpidr, NULL);
+ if (ret < 0) {
+ break;
+ }
+
+ ret = callback(dtb, node, mpidr);
+ if (ret < 0) {
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Find a given node in device tree. If not present, add it.
+ * Returns offset of node found/added on success, and < 0 on error.
+ */
+int fdtw_find_or_add_subnode(void *fdt, int parentoffset, const char *name)
+{
+ int offset;
+
+ offset = fdt_subnode_offset(fdt, parentoffset, name);
+
+ if (offset == -FDT_ERR_NOTFOUND) {
+ offset = fdt_add_subnode(fdt, parentoffset, name);
+ }
+
+ if (offset < 0) {
+ ERROR("%s: %s: %s\n", __func__, name, fdt_strerror(offset));
+ }
+
+ return offset;
+}
diff --git a/common/fdt_wrappers.mk b/common/fdt_wrappers.mk
new file mode 100644
index 0000000..62b8c6e
--- /dev/null
+++ b/common/fdt_wrappers.mk
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+FDT_WRAPPERS_SOURCES := common/fdt_wrappers.c
diff --git a/common/feat_detect.c b/common/feat_detect.c
new file mode 100644
index 0000000..ee34588
--- /dev/null
+++ b/common/feat_detect.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/feat_detect.h>
+
+/*******************************************************************************
+ * This section lists the wrapper modules for each feature to evaluate the
+ * feature states (FEAT_STATE_1 and FEAT_STATE_2) and perform necessary action
+ * as below:
+ *
+ * It verifies whether the FEAT_XXX (eg: FEAT_SB) is supported by the PE or not.
+ * Without this check an exception would occur during context save/restore
+ * routines, if the feature is enabled but not supported by PE.
+ ******************************************************************************/
+
+/******************************************
+ * Feature : FEAT_SB (Speculation Barrier)
+ *****************************************/
+static void read_feat_sb(void)
+{
+#if (ENABLE_FEAT_SB == FEAT_STATE_1)
+ feat_detect_panic(is_armv8_0_feat_sb_present(), "SB");
+#endif
+}
+
+/******************************************************
+ * Feature : FEAT_CSV2_2 (Cache Speculation Variant 2)
+ *****************************************************/
+static void read_feat_csv2_2(void)
+{
+#if (ENABLE_FEAT_CSV2_2 == FEAT_STATE_1)
+ feat_detect_panic(is_armv8_0_feat_csv2_2_present(), "CSV2_2");
+#endif
+}
+
+/***********************************************
+ * Feature : FEAT_PAN (Privileged Access Never)
+ **********************************************/
+static void read_feat_pan(void)
+{
+#if (ENABLE_FEAT_PAN == FEAT_STATE_1)
+ feat_detect_panic(is_armv8_1_pan_present(), "PAN");
+#endif
+}
+
+/******************************************************
+ * Feature : FEAT_VHE (Virtualization Host Extensions)
+ *****************************************************/
+static void read_feat_vhe(void)
+{
+#if (ENABLE_FEAT_VHE == FEAT_STATE_1)
+ feat_detect_panic(is_armv8_1_vhe_present(), "VHE");
+#endif
+}
+
+/*******************************************************************************
+ * Feature : FEAT_RAS (Reliability, Availability, and Serviceability Extension)
+ ******************************************************************************/
+static void read_feat_ras(void)
+{
+#if (RAS_EXTENSION == FEAT_STATE_1)
+ feat_detect_panic(is_armv8_2_feat_ras_present(), "RAS");
+#endif
+}
+
+/************************************************
+ * Feature : FEAT_PAUTH (Pointer Authentication)
+ ***********************************************/
+static void read_feat_pauth(void)
+{
+#if (ENABLE_PAUTH == FEAT_STATE_1) || (CTX_INCLUDE_PAUTH_REGS == FEAT_STATE_1)
+ feat_detect_panic(is_armv8_3_pauth_present(), "PAUTH");
+#endif
+}
+
+/************************************************************
+ * Feature : FEAT_DIT (Data Independent Timing Instructions)
+ ***********************************************************/
+static void read_feat_dit(void)
+{
+#if (ENABLE_FEAT_DIT == FEAT_STATE_1)
+ feat_detect_panic(is_armv8_4_feat_dit_present(), "DIT");
+#endif
+}
+
+/*********************************************************
+ * Feature : FEAT_AMUv1 (Activity Monitors Extensions v1)
+ ********************************************************/
+static void read_feat_amuv1(void)
+{
+#if (ENABLE_FEAT_AMUv1 == FEAT_STATE_1)
+ feat_detect_panic(is_armv8_4_feat_amuv1_present(), "AMUv1");
+#endif
+}
+
+/****************************************************************************
+ * Feature : FEAT_MPAM (Memory Partitioning and Monitoring (MPAM) Extension)
+ ***************************************************************************/
+static void read_feat_mpam(void)
+{
+#if (ENABLE_MPAM_FOR_LOWER_ELS == FEAT_STATE_1)
+ feat_detect_panic(get_mpam_version() != 0U, "MPAM");
+#endif
+}
+
+/**************************************************************
+ * Feature : FEAT_NV2 (Enhanced Nested Virtualization Support)
+ *************************************************************/
+static void read_feat_nv2(void)
+{
+#if (CTX_INCLUDE_NEVE_REGS == FEAT_STATE_1)
+ unsigned int nv = get_armv8_4_feat_nv_support();
+
+ feat_detect_panic((nv == ID_AA64MMFR2_EL1_NV2_SUPPORTED), "NV2");
+#endif
+}
+
+/***********************************
+ * Feature : FEAT_SEL2 (Secure EL2)
+ **********************************/
+static void read_feat_sel2(void)
+{
+#if (ENABLE_FEAT_SEL2 == FEAT_STATE_1)
+ feat_detect_panic(is_armv8_4_sel2_present(), "SEL2");
+#endif
+}
+
+/****************************************************
+ * Feature : FEAT_TRF (Self-hosted Trace Extensions)
+ ***************************************************/
+static void read_feat_trf(void)
+{
+#if (ENABLE_TRF_FOR_NS == FEAT_STATE_1)
+ feat_detect_panic(is_arm8_4_feat_trf_present(), "TRF");
+#endif
+}
+
+/************************************************
+ * Feature : FEAT_MTE (Memory Tagging Extension)
+ ***********************************************/
+static void read_feat_mte(void)
+{
+#if (CTX_INCLUDE_MTE_REGS == FEAT_STATE_1)
+ unsigned int mte = get_armv8_5_mte_support();
+
+ feat_detect_panic((mte != MTE_UNIMPLEMENTED), "MTE");
+#endif
+}
+
+/***********************************************
+ * Feature : FEAT_RNG (Random Number Generator)
+ **********************************************/
+static void read_feat_rng(void)
+{
+#if (ENABLE_FEAT_RNG == FEAT_STATE_1)
+ feat_detect_panic(is_armv8_5_rng_present(), "RNG");
+#endif
+}
+
+/****************************************************
+ * Feature : FEAT_BTI (Branch Target Identification)
+ ***************************************************/
+static void read_feat_bti(void)
+{
+#if (ENABLE_BTI == FEAT_STATE_1)
+ feat_detect_panic(is_armv8_5_bti_present(), "BTI");
+#endif
+}
+
+/****************************************
+ * Feature : FEAT_FGT (Fine Grain Traps)
+ ***************************************/
+static void read_feat_fgt(void)
+{
+#if (ENABLE_FEAT_FGT == FEAT_STATE_1)
+ feat_detect_panic(is_armv8_6_fgt_present(), "FGT");
+#endif
+}
+
+/***********************************************
+ * Feature : FEAT_AMUv1p1 (AMU Extensions v1.1)
+ **********************************************/
+static void read_feat_amuv1p1(void)
+{
+#if (ENABLE_FEAT_AMUv1p1 == FEAT_STATE_1)
+ feat_detect_panic(is_armv8_6_feat_amuv1p1_present(), "AMUv1p1");
+#endif
+}
+
+/*******************************************************
+ * Feature : FEAT_ECV (Enhanced Counter Virtualization)
+ ******************************************************/
+static void read_feat_ecv(void)
+{
+#if (ENABLE_FEAT_ECV == FEAT_STATE_1)
+ unsigned int ecv = get_armv8_6_ecv_support();
+
+ feat_detect_panic(((ecv == ID_AA64MMFR0_EL1_ECV_SUPPORTED) ||
+ (ecv == ID_AA64MMFR0_EL1_ECV_SELF_SYNCH)), "ECV");
+#endif
+}
+
+/***********************************************************
+ * Feature : FEAT_TWED (Delayed Trapping of WFE Instruction)
+ **********************************************************/
+static void read_feat_twed(void)
+{
+#if (ENABLE_FEAT_TWED == FEAT_STATE_1)
+ feat_detect_panic(is_armv8_6_twed_present(), "TWED");
+#endif
+}
+
+/******************************************************************
+ * Feature : FEAT_HCX (Extended Hypervisor Configuration Register)
+ *****************************************************************/
+static void read_feat_hcx(void)
+{
+#if (ENABLE_FEAT_HCX == FEAT_STATE_1)
+ feat_detect_panic(is_feat_hcx_present(), "HCX");
+#endif
+}
+
+/**************************************************
+ * Feature : FEAT_RME (Realm Management Extension)
+ *************************************************/
+static void read_feat_rme(void)
+{
+#if (ENABLE_RME == FEAT_STATE_1)
+ feat_detect_panic((get_armv9_2_feat_rme_support() !=
+ ID_AA64PFR0_FEAT_RME_NOT_SUPPORTED), "RME");
+#endif
+}
+
+/******************************************************
+ * Feature : FEAT_BRBE (Branch Record Buffer Extension)
+ *****************************************************/
+static void read_feat_brbe(void)
+{
+#if (ENABLE_BRBE_FOR_NS == FEAT_STATE_1)
+ feat_detect_panic(is_feat_brbe_present(), "BRBE");
+#endif
+}
+
+/******************************************************
+ * Feature : FEAT_TRBE (Trace Buffer Extension)
+ *****************************************************/
+static void read_feat_trbe(void)
+{
+#if (ENABLE_TRBE_FOR_NS == FEAT_STATE_1)
+ feat_detect_panic(is_feat_trbe_present(), "TRBE");
+#endif
+}
+
+/******************************************************************
+ * Feature : FEAT_RNG_TRAP (Trapping support for RNDR/RNDRRS)
+ *****************************************************************/
+static void read_feat_rng_trap(void)
+{
+#if (ENABLE_FEAT_RNG_TRAP == FEAT_STATE_1)
+ feat_detect_panic(is_feat_rng_trap_present(), "RNG_TRAP");
+#endif
+}
+
+/***********************************************************************************
+ * TF-A supports many Arm architectural features starting from arch version
+ * (8.0 till 8.7+). These features are mostly enabled through build flags. This
+ * mechanism helps in validating these build flags in the early boot phase
+ * either in BL1 or BL31 depending on the platform and assists in identifying
+ * and notifying the features which are enabled but not supported by the PE.
+ *
+ * It reads all the enabled features ID-registers and ensures the features
+ * are supported by the PE.
+ * In case if they aren't it stops booting at an early phase and logs the error
+ * messages, notifying the platforms about the features that are not supported.
+ *
+ * Further the procedure is implemented with a tri-state approach for each feature:
+ * ENABLE_FEAT_xxx = 0 : The feature is disabled statically at compile time
+ * ENABLE_FEAT_xxx = 1 : The feature is enabled and must be present in hardware.
+ * There will be panic if feature is not present at cold boot.
+ * ENABLE_FEAT_xxx = 2 : The feature is enabled but dynamically enabled at runtime
+ * depending on hardware capability.
+ *
+ * For better readability, state values are defined with macros namely:
+ * { FEAT_STATE_0, FEAT_STATE_1, FEAT_STATE_2 } taking values as their naming.
+ **********************************************************************************/
+void detect_arch_features(void)
+{
+ /* v8.0 features */
+ read_feat_sb();
+ read_feat_csv2_2();
+
+ /* v8.1 features */
+ read_feat_pan();
+ read_feat_vhe();
+
+ /* v8.2 features */
+ read_feat_ras();
+
+ /* v8.3 features */
+ read_feat_pauth();
+
+ /* v8.4 features */
+ read_feat_dit();
+ read_feat_amuv1();
+ read_feat_mpam();
+ read_feat_nv2();
+ read_feat_sel2();
+ read_feat_trf();
+
+ /* v8.5 features */
+ read_feat_mte();
+ read_feat_rng();
+ read_feat_bti();
+ read_feat_rng_trap();
+
+ /* v8.6 features */
+ read_feat_amuv1p1();
+ read_feat_fgt();
+ read_feat_ecv();
+ read_feat_twed();
+
+ /* v8.7 features */
+ read_feat_hcx();
+
+ /* v9.0 features */
+ read_feat_brbe();
+ read_feat_trbe();
+
+ /* v9.2 features */
+ read_feat_rme();
+}
diff --git a/common/image_decompress.c b/common/image_decompress.c
new file mode 100644
index 0000000..a4586ae
--- /dev/null
+++ b/common/image_decompress.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/image_decompress.h>
+
+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;
+}
diff --git a/common/runtime_svc.c b/common/runtime_svc.c
new file mode 100644
index 0000000..a2c0c09
--- /dev/null
+++ b/common/runtime_svc.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+
+/*******************************************************************************
+ * 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;
+ }
+}
diff --git a/common/tf_crc32.c b/common/tf_crc32.c
new file mode 100644
index 0000000..b33d36e
--- /dev/null
+++ b/common/tf_crc32.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdarg.h>
+#include <assert.h>
+
+#include <arm_acle.h>
+#include <common/debug.h>
+#include <common/tf_crc32.h>
+
+/* compute CRC using Arm intrinsic function
+ *
+ * This function is useful for the platforms with the CPU ARMv8.0
+ * (with CRC instructions supported), and onwards.
+ * Platforms with CPU ARMv8.0 should make sure to add a compile switch
+ * '-march=armv8-a+crc" for successful compilation of this file.
+ *
+ * @crc: previous accumulated CRC
+ * @buf: buffer base address
+ * @size: the size of the buffer
+ *
+ * Return calculated CRC value
+ */
+uint32_t tf_crc32(uint32_t crc, const unsigned char *buf, size_t size)
+{
+ assert(buf != NULL);
+
+ uint32_t calc_crc = ~crc;
+ const unsigned char *local_buf = buf;
+ size_t local_size = size;
+
+ /*
+ * calculate CRC over byte data
+ */
+ while (local_size != 0UL) {
+ calc_crc = __crc32b(calc_crc, *local_buf);
+ local_buf++;
+ local_size--;
+ }
+
+ return ~calc_crc;
+}
diff --git a/common/tf_log.c b/common/tf_log.c
new file mode 100644
index 0000000..68f1be4
--- /dev/null
+++ b/common/tf_log.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdarg.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+/* 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);
+}
+
+void tf_log_newline(const char log_fmt[2])
+{
+ unsigned int log_level = log_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;
+
+ putchar('\n');
+}
+
+/*
+ * 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;
+}
diff --git a/common/uuid.c b/common/uuid.c
new file mode 100644
index 0000000..3e47eb4
--- /dev/null
+++ b/common/uuid.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/uuid.h>
+
+/* Return the hex nibble value of a char */
+static int8_t hex_val(char hex)
+{
+ int8_t val = 0;
+
+ if ((hex >= '0') && (hex <= '9')) {
+ val = (int8_t)(hex - '0');
+ } else if ((hex >= 'a') && (hex <= 'f')) {
+ val = (int8_t)(hex - 'a' + 0xa);
+ } else if ((hex >= 'A') && (hex <= 'F')) {
+ val = (int8_t)(hex - 'A' + 0xa);
+ } else {
+ val = -1;
+ }
+
+ return val;
+}
+
+/*
+ * Read hex_src_len hex characters from hex_src, convert to bytes and
+ * store in buffer pointed to by dest
+ */
+static int read_hex(uint8_t *dest, char *hex_src, unsigned int hex_src_len)
+{
+ int8_t nibble;
+ uint8_t byte;
+
+ /*
+ * The string length must be a multiple of 2 to represent an
+ * exact number of bytes.
+ */
+ assert((hex_src_len % 2U) == 0U);
+
+ for (unsigned int i = 0U; i < (hex_src_len / 2U); i++) {
+ nibble = 0;
+ byte = 0U;
+
+ nibble = hex_val(hex_src[2U * i]);
+ if (nibble < 0) {
+ return -1;
+ }
+ byte = (uint8_t)nibble;
+ byte <<= 4U;
+
+ nibble = hex_val(hex_src[(2U * i) + 1U]);
+ if (nibble < 0) {
+ return -1;
+ }
+ byte |= (uint8_t)nibble;
+
+ *dest = byte;
+ dest++;
+ }
+
+ return 0;
+}
+
+/* Parse UUIDs of the form aabbccdd-eeff-4099-8877-665544332211 */
+int read_uuid(uint8_t *dest, char *uuid)
+{
+ int err;
+ uint8_t *dest_start = dest;
+
+ /* Check that we have enough characters */
+ if (strnlen(uuid, UUID_STRING_LENGTH) != UUID_STRING_LENGTH) {
+ WARN("UUID string is too short\n");
+ return -EINVAL;
+ }
+
+ /* aabbccdd */
+ err = read_hex(dest, uuid, 8);
+ uuid += 8;
+ dest += 4;
+
+ /* Check for '-' */
+ err |= ((*uuid == '-') ? 0 : -1);
+ uuid++;
+
+ /* eeff */
+ err |= read_hex(dest, uuid, 4);
+ uuid += 4;
+ dest += 2;
+
+ /* Check for '-' */
+ err |= ((*uuid == '-') ? 0 : -1);
+ uuid++;
+
+ /* 4099 */
+ err |= read_hex(dest, uuid, 4);
+ uuid += 4;
+ dest += 2;
+
+ /* Check for '-' */
+ err |= ((*uuid == '-') ? 0 : -1);
+ uuid++;
+
+ /* 8877 */
+ err |= read_hex(dest, uuid, 4);
+ uuid += 4;
+ dest += 2;
+
+ /* Check for '-' */
+ err |= ((*uuid == '-') ? 0 : -1);
+ uuid++;
+
+ /* 665544332211 */
+ err |= read_hex(dest, uuid, 12);
+ uuid += 12;
+ dest += 6;
+
+ if (err < 0) {
+ WARN("Error parsing UUID\n");
+ /* Clear the buffer on error */
+ memset((void *)dest_start, '\0', UUID_BYTES_LENGTH * sizeof(uint8_t));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Helper function to check if 2 UUIDs match.
+ */
+bool uuid_match(uint32_t *uuid1, uint32_t *uuid2)
+{
+ return !memcmp(uuid1, uuid2, sizeof(uint32_t) * 4);
+}
+
+/*
+ * Helper function to copy from one UUID struct to another.
+ */
+void copy_uuid(uint32_t *to_uuid, uint32_t *from_uuid)
+{
+ to_uuid[0] = from_uuid[0];
+ to_uuid[1] = from_uuid[1];
+ to_uuid[2] = from_uuid[2];
+ to_uuid[3] = from_uuid[3];
+}
+
+bool is_null_uuid(uint32_t *uuid)
+{
+ return (uuid[0] == 0 && uuid[1] == 0 &&
+ uuid[2] == 0 && uuid[3] == 0);
+}
diff --git a/dco.txt b/dco.txt
new file mode 100644
index 0000000..8201f99
--- /dev/null
+++ b/dco.txt
@@ -0,0 +1,37 @@
+Developer 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.
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..3dd7ebc
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,25 @@
+#
+# Copyright (c) 2019-2020, 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 = -W
+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)
diff --git a/docs/_static/css/custom.css b/docs/_static/css/custom.css
new file mode 100644
index 0000000..f6f5fa0
--- /dev/null
+++ b/docs/_static/css/custom.css
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Set the white-space property of tables to normal.
+ * With this setting sequences of whitespace inside
+ * a table will collapse into a single whitespace,
+ * and text will wrap when necessary.
+ */
+.wy-table-responsive table td {
+white-space: normal;
+}
diff --git a/docs/about/acknowledgements.rst b/docs/about/acknowledgements.rst
new file mode 100644
index 0000000..dfc66c8
--- /dev/null
+++ b/docs/about/acknowledgements.rst
@@ -0,0 +1,22 @@
+Contributor 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.*
diff --git a/docs/about/contact.rst b/docs/about/contact.rst
new file mode 100644
index 0000000..4f482bd
--- /dev/null
+++ b/docs/about/contact.rst
@@ -0,0 +1,56 @@
+Support & 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.
+
+Open Tech Forum Call
+^^^^^^^^^^^^^^^^^^^^
+
+Every other week, we organize a call with all interested TF-A contributors.
+Anyone is welcome to join. This is an opportunity to discuss any technical
+topic within the community. More details can be found `here`_.
+
+.. _here: https://www.trustedfirmware.org/meetings/tf-a-technical-forum/
+
+Issue Tracker
+^^^^^^^^^^^^^
+
+Bug reports may be filed on the `issue tracker`_ on the TrustedFirmware.org
+website. Using this tracker gives everyone visibility of the known issues in
+TF-A.
+
+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/mailman3/lists/tf-a.lists.trustedfirmware.org/
+.. _`TF-A-Tests development`: https://lists.trustedfirmware.org/mailman3/lists/tf-a-tests.lists.trustedfirmware.org/
+.. _`summary of all the lists`: https://lists.trustedfirmware.org/mailman3/lists/
+
+--------------
+
+*Copyright (c) 2019-2022, Arm Limited. All rights reserved.*
diff --git a/docs/about/features.rst b/docs/about/features.rst
new file mode 100644
index 0000000..cb8b552
--- /dev/null
+++ b/docs/about/features.rst
@@ -0,0 +1,128 @@
+Feature 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`_,
+ `Trusty Secure OS`_ and `ProvenCore 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.
+ This feature is now incorporated inside the firmware configuration framework
+ (fconf).
+
+- 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.
+
+- Support for the Secure Partition Manager Dispatcher (SPMD) component as a
+ new standard service.
+
+- 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.
+
+- Position-Independent Executable (PIE) support. Currently for BL2, BL31, and
+ TSP, 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 FF-A v1.0 (formally known as 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: https://developer.arm.com/docs/den0028/latest
+.. _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
+.. _ProvenCore Secure OS: https://provenrun.com/products/provencore/
+
+--------------
+
+*Copyright (c) 2019-2021, Arm Limited. All rights reserved.*
diff --git a/docs/about/index.rst b/docs/about/index.rst
new file mode 100644
index 0000000..06973ef
--- /dev/null
+++ b/docs/about/index.rst
@@ -0,0 +1,12 @@
+About
+=====
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents
+
+ features
+ release-information
+ maintainers
+ contact
+ acknowledgements
diff --git a/docs/about/maintainers.rst b/docs/about/maintainers.rst
new file mode 100644
index 0000000..9a2ae73
--- /dev/null
+++ b/docs/about/maintainers.rst
@@ -0,0 +1,960 @@
+Project Maintenance
+===================
+
+Trusted Firmware-A (TF-A) is an open governance community project. All
+contributions are ultimately merged by the maintainers listed below. Technical
+ownership of most parts of the codebase falls on the code owners listed
+below. An acknowledgement from these code owners is required before the
+maintainers merge a contribution.
+
+More details may be found in the `Project Maintenance Process`_ document.
+
+.. |M| replace:: **Mail**
+.. |G| replace:: **GitHub ID**
+.. |F| replace:: **Files**
+
+.. _maintainers:
+
+Maintainers
+-----------
+
+:|M|: Dan Handley <dan.handley@arm.com>
+:|G|: `danh-arm`_
+:|M|: Soby Mathew <soby.mathew@arm.com>
+:|G|: `soby-mathew`_
+:|M|: Sandrine Bailleux <sandrine.bailleux@arm.com>
+:|G|: `sandrine-bailleux-arm`_
+:|M|: Alexei Fedorov <Alexei.Fedorov@arm.com>
+:|G|: `AlexeiFedorov`_
+:|M|: Manish Pandey <manish.pandey2@arm.com>
+:|G|: `manish-pandey-arm`_
+:|M|: Mark Dykes <mark.dykes@arm.com>
+:|G|: `mardyk01`_
+:|M|: Olivier Deprez <olivier.deprez@arm.com>
+:|G|: `odeprez`_
+:|M|: Bipin Ravi <bipin.ravi@arm.com>
+:|G|: `bipinravi-arm`_
+:|M|: Joanna Farley <joanna.farley@arm.com>
+:|G|: `joannafarley-arm`_
+:|M|: Julius Werner <jwerner@chromium.org>
+:|G|: `jwerner-chromium`_
+:|M|: Varun Wadekar <vwadekar@nvidia.com>
+:|G|: `vwadekar`_
+:|M|: Andre Przywara <andre.przywara@arm.com>
+:|G|: `Andre-ARM`_
+:|M|: Lauren Wehrmeister <Lauren.Wehrmeister@arm.com>
+:|G|: `laurenw-arm`_
+:|M|: Madhukar Pappireddy <Madhukar.Pappireddy@arm.com>
+:|G|: `madhukar-Arm`_
+:|M|: Raghu Krishnamurthy <raghu.ncstate@icloud.com>
+:|G|: `raghuncstate`_
+:|M|: Manish Badarkhe <manish.badarkhe@arm.com>
+:|G|: `ManishVB-Arm`_
+
+LTS Maintainers
+---------------
+
+:|M|: Bipin Ravi <bipin.ravi@arm.com>
+:|G|: `bipinravi-arm`_
+:|M|: Joanna Farley <joanna.farley@arm.com>
+:|G|: `joannafarley-arm`_
+:|M|: Okash Khawaja <okash@google.com>
+:|G|: `bytefire`_
+:|M|: Varun Wadekar <vwadekar@nvidia.com>
+:|G|: `vwadekar`_
+
+.. _code owners:
+
+Code owners
+-----------
+
+Common Code
+~~~~~~~~~~~
+
+Armv7-A architecture port
+^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Etienne Carriere <etienne.carriere@linaro.org>
+:|G|: `etienne-lms`_
+
+Build Definitions for CMake Build System
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Chris Kay <chris.kay@arm.com>
+:|G|: `CJKay`_
+:|F|: /
+
+Software Delegated Exception Interface (SDEI)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Jayanth Dodderi Chidanand <jayanthdodderi.chidanand@arm.com>
+:|G|: `jayanthchidanand-arm`_
+:|M|: Manish Pandey <manish.pandey2@arm.com>
+:|G|: `manish-pandey-arm`_
+:|F|: services/std_svc/sdei/
+
+Trusted Boot
+^^^^^^^^^^^^
+:|M|: Sandrine Bailleux <sandrine.bailleux@arm.com>
+:|G|: `sandrine-bailleux-arm`_
+:|M|: Manish Badarkhe <manish.badarkhe@arm.com>
+:|G|: `ManishVB-Arm`_
+:|M|: Lauren Wehrmeister <Lauren.Wehrmeister@arm.com>
+:|G|: `laurenw-arm`_
+:|F|: drivers/auth/
+
+Secure Partition Manager Core (EL3 FF-A SPMC)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Marc Bonnici <marc.bonnici@arm.com>
+:|G|: `marcbonnici`_
+:|F|: services/std_svc/spm/el3_spmc/\*
+
+Secure Partition Manager Dispatcher (SPMD)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Olivier Deprez <olivier.deprez@arm.com>
+:|G|: `odeprez`_
+:|M|: Joao Alves <Joao.Alves@arm.com>
+:|G|: `J-Alves`_
+:|F|: services/std_svc/spmd/\*
+
+Exception Handling Framework (EHF)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Jayanth Dodderi Chidanand <jayanthdodderi.chidanand@arm.com>
+:|G|: `jayanthchidanand-arm`_
+:|M|: Manish Pandey <manish.pandey2@arm.com>
+:|G|: `manish-pandey-arm`_
+:|F|: bl31/ehf.c
+
+Realm Management Monitor Dispatcher (RMMD)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Javier Almansa Sobrino <javier.almansasobrino@arm.com>
+:|G|: `javieralso-arm`_
+:|M|: Alexei Fedorov <Alexei.Fedorov@arm.com>
+:|G|: `AlexeiFedorov`_
+:|F|: services/std_svc/rmmd/\*
+:|F|: include/services/rmmd_svc.h
+:|F|: include/services/rmm_core_manifest.h
+
+Realm Management Extension (RME)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Javier Almansa Sobrino <javier.almansasobrino@arm.com>
+:|G|: `javieralso-arm`_
+:|M|: Alexei Fedorov <Alexei.Fedorov@arm.com>
+:|G|: `AlexeiFedorov`_
+
+Drivers, Libraries and Framework Code
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Console API framework
+^^^^^^^^^^^^^^^^^^^^^
+:|M|: Julius Werner <jwerner@chromium.org>
+:|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 <jwerner@chromium.org>
+:|G|: `jwerner-chromium`_
+:|F|: drivers/coreboot/
+:|F|: include/drivers/coreboot/
+:|F|: include/lib/coreboot.h
+:|F|: lib/coreboot/
+
+eMMC/UFS drivers
+^^^^^^^^^^^^^^^^
+:|M|: Haojian Zhuang <haojian.zhuang@linaro.org>
+:|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
+
+Arm® Ethos™-N NPU driver
+^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Joshua Slater <joshua.slater@arm.com>
+:|G|: `jslater8`_
+:|M|: Mikael Olsson <mikael.olsson@arm.com>
+:|G|: `mikaelolsson-arm`_
+:|F|: drivers/arm/ethosn/
+:|F|: include/drivers/arm/ethosn.h
+:|F|: plat/arm/common/fconf/fconf_ethosn_getter.c
+:|F|: include/plat/arm/common/fconf_ethosn_getter.h
+:|F|: fdts/juno-ethosn.dtsi
+
+JTAG DCC console driver
+^^^^^^^^^^^^^^^^^^^^^^^
+:M: Michal Simek <michal.simek@amd.com>
+:G: `michalsimek`_
+:M: Venkatesh Yadav Abbarapu <venkatesh.abbarapu@amd.com>
+:G: `venkatesh`_
+:F: drivers/arm/dcc/
+:F: include/drivers/arm/dcc.h
+
+Power State Coordination Interface (PSCI)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Manish Pandey <manish.pandey2@arm.com>
+:|G|: `manish-pandey-arm`_
+:|M|: Madhukar Pappireddy <Madhukar.Pappireddy@arm.com>
+:|G|: `madhukar-Arm`_
+:|M|: Lauren Wehrmeister <Lauren.Wehrmeister@arm.com>
+:|G|: `laurenw-arm`_
+:|F|: lib/psci/
+
+DebugFS
+^^^^^^^
+:|M|: Olivier Deprez <olivier.deprez@arm.com>
+:|G|: `odeprez`_
+:|F|: lib/debugfs/
+
+Firmware Configuration Framework (FCONF)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Madhukar Pappireddy <Madhukar.Pappireddy@arm.com>
+:|G|: `madhukar-Arm`_
+:|M|: Manish Badarkhe <manish.badarkhe@arm.com>
+:|G|: `ManishVB-Arm`_
+:|M|: Lauren Wehrmeister <Lauren.Wehrmeister@arm.com>
+:|G|: `laurenw-arm`_
+:|F|: lib/fconf/
+
+Performance Measurement Framework (PMF)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Joao Alves <Joao.Alves@arm.com>
+:|G|: `J-Alves`_
+:|F|: lib/pmf/
+
+Errata Management
+^^^^^^^^^^^^^^^^^
+:|M|: Bipin Ravi <bipin.ravi@arm.com>
+:|G|: `bipinravi-arm`_
+:|M|: Lauren Wehrmeister <Lauren.Wehrmeister@arm.com>
+:|G|: `laurenw-arm`_
+
+Arm CPU libraries
+^^^^^^^^^^^^^^^^^
+:|M|: Bipin Ravi <bipin.ravi@arm.com>
+:|G|: `bipinravi-arm`_
+:|M|: Lauren Wehrmeister <Lauren.Wehrmeister@arm.com>
+:|G|: `laurenw-arm`_
+:|F|: lib/cpus/
+
+Reliability Availability Serviceabilty (RAS) framework
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Manish Pandey <manish.pandey2@arm.com>
+:|G|: `manish-pandey-arm`_
+:|M|: Olivier Deprez <olivier.deprez@arm.com>
+:|G|: `odeprez`_
+:|F|: lib/extensions/ras/
+
+Activity Monitors Unit (AMU) extensions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Alexei Fedorov <Alexei.Fedorov@arm.com>
+:|G|: `AlexeiFedorov`_
+:|M|: Chris Kay <chris.kay@arm.com>
+:|G|: `CJKay`_
+:|F|: lib/extensions/amu/
+
+Memory Partitioning And Monitoring (MPAM) extensions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Manish Pandey <manish.pandey2@arm.com>
+:|G|: `manish-pandey-arm`_
+:|F|: lib/extensions/mpam/
+
+Pointer Authentication (PAuth) and Branch Target Identification (BTI) extensions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Alexei Fedorov <Alexei.Fedorov@arm.com>
+:|G|: `AlexeiFedorov`_
+:|F|: lib/extensions/pauth/
+
+Statistical Profiling Extension (SPE)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Manish Pandey <manish.pandey2@arm.com>
+:|G|: `manish-pandey-arm`_
+:|F|: lib/extensions/spe/
+
+Standard C library
+^^^^^^^^^^^^^^^^^^
+:|M|: Chris Kay <chris.kay@arm.com>
+:|G|: `CJKay`_
+:|M|: Madhukar Pappireddy <Madhukar.Pappireddy@arm.com>
+:|G|: `madhukar-Arm`_
+:|F|: lib/libc/
+
+Library At ROM (ROMlib)
+^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Madhukar Pappireddy <Madhukar.Pappireddy@arm.com>
+:|G|: `madhukar-Arm`_
+:|F|: lib/romlib/
+
+Translation tables (``xlat_tables``) library
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Manish Badarkhe <manish.badarkhe@arm.com>
+:|G|: `ManishVB-Arm`_
+:|M|: Joao Alves <Joao.Alves@arm.com>
+:|G|: `J-Alves`_
+:|F|: lib/xlat\_tables_\*/
+
+IO abstraction layer
+^^^^^^^^^^^^^^^^^^^^
+:|M|: Manish Pandey <manish.pandey2@arm.com>
+:|G|: `manish-pandey-arm`_
+:|M|: Olivier Deprez <olivier.deprez@arm.com>
+:|G|: `odeprez`_
+:|F|: drivers/io/
+
+GIC driver
+^^^^^^^^^^
+:|M|: Alexei Fedorov <Alexei.Fedorov@arm.com>
+:|G|: `AlexeiFedorov`_
+:|M|: Manish Pandey <manish.pandey2@arm.com>
+:|G|: `manish-pandey-arm`_
+:|M|: Madhukar Pappireddy <Madhukar.Pappireddy@arm.com>
+:|G|: `madhukar-Arm`_
+:|M|: Olivier Deprez <olivier.deprez@arm.com>
+:|G|: `odeprez`_
+:|F|: drivers/arm/gic/
+
+Message Handling Unit (MHU) driver
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: David Vincze <david.vincze@arm.com>
+:|G|: `davidvincze`_
+:|F|: include/drivers/arm/mhu.h
+:|F|: drivers/arm/mhu
+
+Runtime Security Subsystem (RSS) comms driver
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: David Vincze <david.vincze@arm.com>
+:|G|: `davidvincze`_
+:|F|: include/drivers/arm/rss_comms.h
+:|F|: drivers/arm/rss
+
+Libfdt wrappers
+^^^^^^^^^^^^^^^
+:|M|: Madhukar Pappireddy <Madhukar.Pappireddy@arm.com>
+:|G|: `madhukar-Arm`_
+:|M|: Manish Badarkhe <manish.badarkhe@arm.com>
+:|G|: `ManishVB-Arm`_
+:|F|: common/fdt_wrappers.c
+
+Firmware Encryption Framework
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Sumit Garg <sumit.garg@linaro.org>
+:|G|: `b49020`_
+:|F|: drivers/io/io_encrypted.c
+:|F|: include/drivers/io/io_encrypted.h
+:|F|: include/tools_share/firmware_encrypted.h
+
+Measured Boot
+^^^^^^^^^^^^^
+:|M|: Sandrine Bailleux <sandrine.bailleux@arm.com>
+:|G|: `sandrine-bailleux-arm`_
+:|M|: Manish Badarkhe <manish.badarkhe@arm.com>
+:|G|: `ManishVB-Arm`_
+:|F|: drivers/measured_boot
+:|F|: include/drivers/measured_boot
+:|F|: docs/components/measured_boot
+:|F|: plat/arm/board/fvp/fvp\*_measured_boot.c
+
+DRTM
+^^^^
+:|M|: Manish Badarkhe <manish.badarkhe@arm.com>
+:|G|: `ManishVB-Arm`_
+:|M|: Manish Pandey <manish.pandey2@arm.com>
+:|G|: `manish-pandey-arm`_
+:|F|: services/std_svc/drtm
+
+PSA Firmware Update
+^^^^^^^^^^^^^^^^^^^
+:|M|: Manish Badarkhe <manish.badarkhe@arm.com>
+:|G|: `ManishVB-Arm`_
+:|M|: Sandrine Bailleux <sandrine.bailleux@arm.com>
+:|G|: `sandrine-bailleux-arm`_
+:|F|: drivers/fwu
+:|F|: include/drivers/fwu
+
+Platform Security Architecture (PSA) APIs
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Sandrine Bailleux <sandrine.bailleux@arm.com>
+:|G|: `sandrine-bailleux-arm`_
+:|F|: include/lib/psa
+:|F|: lib/psa
+
+System Control and Management Interface (SCMI) Server
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Etienne Carriere <etienne.carriere@st.com>
+:|G|: `etienne-lms`_
+:|M|: Peng Fan <peng.fan@nxp.com>
+:|G|: `MrVan`_
+:|F|: drivers/scmi-msg
+:|F|: include/drivers/scmi\*
+
+Max Power Mitigation Mechanism (MPMM)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Chris Kay <chris.kay@arm.com>
+:|G|: `CJKay`_
+:|F|: include/lib/mpmm/
+:|F|: lib/mpmm/
+
+Granule Protection Tables Library (GPT-RME)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Soby Mathew <soby.mathew@arm.com>
+:|G|: `soby-mathew`_
+:|M|: Javier Almansa Sobrino <javier.almansasobrino@arm.com>
+:|G|: `javieralso-arm`_
+:|F|: lib/gpt_rme
+:|F|: include/lib/gpt_rme
+
+Platform Ports
+~~~~~~~~~~~~~~
+
+Allwinner ARMv8 platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Andre Przywara <andre.przywara@arm.com>
+:|G|: `Andre-ARM`_
+:|M|: Samuel Holland <samuel@sholland.org>
+:|G|: `smaeul`_
+:|F|: docs/plat/allwinner.rst
+:|F|: plat/allwinner/
+:|F|: drivers/allwinner/
+
+Amlogic Meson S905 (GXBB) platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Andre Przywara <andre.przywara@arm.com>
+:|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 <repk@triplefau.lt>
+:|G|: `remi-triplefault`_
+:|F|: docs/plat/meson-gxl.rst
+:|F|: plat/amlogic/gxl/
+
+Amlogic Meson S905X2 (G12A) platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Carlo Caione <ccaione@baylibre.com>
+:|G|: `carlocaione`_
+:|F|: docs/plat/meson-g12a.rst
+:|F|: plat/amlogic/g12a/
+
+Amlogic Meson A113D (AXG) platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Carlo Caione <ccaione@baylibre.com>
+:|G|: `carlocaione`_
+:|F|: docs/plat/meson-axg.rst
+:|F|: plat/amlogic/axg/
+
+Arm FPGA platform port
+^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Andre Przywara <andre.przywara@arm.com>
+:|G|: `Andre-ARM`_
+:|M|: Javier Almansa Sobrino <Javier.AlmansaSobrino@arm.com>
+:|G|: `javieralso-arm`_
+:|F|: plat/arm/board/arm_fpga
+
+Arm FVP Platform port
+^^^^^^^^^^^^^^^^^^^^^
+:|M|: Manish Pandey <manish.pandey2@arm.com>
+:|G|: `manish-pandey-arm`_
+:|M|: Madhukar Pappireddy <Madhukar.Pappireddy@arm.com>
+:|G|: `madhukar-Arm`_
+:|F|: plat/arm/board/fvp
+
+Arm Juno Platform port
+^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Manish Pandey <manish.pandey2@arm.com>
+:|G|: `manish-pandey-arm`_
+:|M|: Chris Kay <chris.kay@arm.com>
+:|G|: `CJKay`_
+:|F|: plat/arm/board/juno
+
+Arm Morello and N1SDP Platform ports
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Manoj Kumar <manoj.kumar3@arm.com>
+:|G|: `manojkumar-arm`_
+:|M|: Chandni Cherukuri <chandni.cherukuri@arm.com>
+:|G|: `chandnich`_
+:|F|: plat/arm/board/morello
+:|F|: plat/arm/board/n1sdp
+
+Arm Rich IoT Platform ports
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+:|G|: `abdellatif-elkhlifi`_
+:|M|: Vishnu Banavath <vishnu.banavath@arm.com>
+:|G|: `vishnu-banavath`_
+:|F|: plat/arm/board/corstone700
+:|F|: plat/arm/board/a5ds
+:|F|: plat/arm/board/corstone1000
+
+Arm Reference Design platform ports
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Thomas Abraham <thomas.abraham@arm.com>
+:|G|: `thomas-arm`_
+:|M|: Vijayenthiran Subramaniam <vijayenthiran.subramaniam@arm.com>
+:|G|: `vijayenthiran-arm`_
+:|F|: plat/arm/css/sgi/
+:|F|: plat/arm/board/rde1edge/
+:|F|: plat/arm/board/rdn1edge/
+:|F|: plat/arm/board/rdn2/
+:|F|: plat/arm/board/rdv1/
+:|F|: plat/arm/board/rdv1mc/
+:|F|: plat/arm/board/sgi575/
+
+Arm Total Compute platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Anders Dellien <anders.dellien@arm.com>
+:|G|: `andersdellien-arm`_
+:|F|: plat/arm/board/tc
+
+HiSilicon HiKey and HiKey960 platform ports
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Haojian Zhuang <haojian.zhuang@linaro.org>
+:|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 <shawn.guo@linaro.org>
+:|G|: `shawnguo2`_
+:|F|: docs/plat/poplar.rst
+:|F|: plat/hisilicon/poplar/
+
+Intel SocFPGA platform ports
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Sieu Mun Tang <sieu.mun.tang@intel.com>
+:|G|: `sieumunt`_
+:|M|: Benjamin Jit Loon Lim <jit.loon.lim@intel.com>
+:|G|: `BenjaminLimJL`_
+:|F|: plat/intel/soc/
+:|F|: drivers/intel/soc/
+
+MediaTek platform ports
+^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Rex-BC Chen <rex-bc.chen@mediatek.com>
+:|G|: `mtk-rex-bc-chen`_
+:|M|: Leon Chen <leon.chen@mediatek.com>
+:|G|: `leon-chen-mtk`_
+:|F|: docs/plat/mt\*.rst
+:|F|: plat/mediatek/
+
+Marvell platform ports and SoC drivers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Konstantin Porotchkin <kostap@marvell.com>
+:|G|: `kostapr`_
+:|F|: docs/plat/marvell/
+:|F|: plat/marvell/
+:|F|: drivers/marvell/
+:|F|: tools/marvell/
+
+NVidia platform ports
+^^^^^^^^^^^^^^^^^^^^^
+:|M|: Varun Wadekar <vwadekar@nvidia.com>
+:|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 i.MX 7 WaRP7 platform port and SoC drivers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
+:|G|: `bryanodonoghue`_
+:|M|: Jun Nie <jun.nie@linaro.org>
+:|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|: Peng Fan <peng.fan@nxp.com>
+:|G|: `MrVan`_
+:|F|: docs/plat/imx8.rst
+:|F|: plat/imx/
+
+NXP i.MX8M platform port
+^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Jacky Bai <ping.bai@nxp.com>
+:|G|: `JackyBai`_
+:|F|: docs/plat/imx8m.rst
+:|F|: plat/imx/imx8m/
+
+NXP QorIQ Layerscape common code for platform ports
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Pankaj Gupta <pankaj.gupta@nxp.com>
+:|G|: `pangupta`_
+:|M|: Jiafei Pan <jiafei.pan@nxp.com>
+:|G|: `JiafeiPan`_
+:|F|: docs/plat/nxp/
+:|F|: plat/nxp/
+:|F|: drivers/nxp/
+:|F|: tools/nxp/
+
+NXP SoC Part LX2160A and its platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Pankaj Gupta <pankaj.gupta@nxp.com>
+:|G|: `pangupta`_
+:|F|: plat/nxp/soc-lx2160a
+:|F|: plat/nxp/soc-lx2160a/lx2162aqds
+:|F|: plat/nxp/soc-lx2160a/lx2160aqds
+:|F|: plat/nxp/soc-lx2160a/lx2160ardb
+
+NXP SoC Part LS1028A and its platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Jiafei Pan <jiafei.pan@nxp.com>
+:|G|: `JiafeiPan`_
+:|F|: plat/nxp/soc-ls1028a
+:|F|: plat/nxp/soc-ls1028a/ls1028ardb
+
+NXP SoC Part LS1043A and its platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Jiafei Pan <jiafei.pan@nxp.com>
+:|G|: `JiafeiPan`_
+:|F|: plat/nxp/soc-ls1043a
+:|F|: plat/nxp/soc-ls1043a/ls1043ardb
+
+NXP SoC Part LS1046A and its platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Jiafei Pan <jiafei.pan@nxp.com>
+:|G|: `JiafeiPan`_
+:|F|: plat/nxp/soc-ls1046a
+:|F|: plat/nxp/soc-ls1046a/ls1046ardb
+:|F|: plat/nxp/soc-ls1046a/ls1046afrwy
+:|F|: plat/nxp/soc-ls1046a/ls1046aqds
+
+NXP SoC Part LS1088A and its platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Jiafei Pan <jiafei.pan@nxp.com>
+:|G|: `JiafeiPan`_
+:|F|: plat/nxp/soc-ls1088a
+:|F|: plat/nxp/soc-ls1088a/ls1088ardb
+:|F|: plat/nxp/soc-ls1088a/ls1088aqds
+
+QEMU platform port
+^^^^^^^^^^^^^^^^^^
+:|M|: Jens Wiklander <jens.wiklander@linaro.org>
+:|G|: `jenswi-linaro`_
+:|F|: docs/plat/qemu.rst
+:|F|: plat/qemu/
+
+QTI platform port
+^^^^^^^^^^^^^^^^^
+:|M|: Saurabh Gorecha <sgorecha@codeaurora.org>
+:|G|: `sgorecha`_
+:|M|: Lachit Patel <lpatel@codeaurora.org>
+:|G|: `lachitp`_
+:|M|: Sreevyshanavi Kare <skare@codeaurora.org>
+:|G|: `sreekare`_
+:|M|: Muhammad Arsath K F <quic_mkf@quicinc.com>
+:|G|: `quic_mkf`_
+:|M|: QTI TF Maintainers <qti.trustedfirmware.maintainers@codeaurora.org>
+:|F|: docs/plat/qti.rst
+:|F|: plat/qti/
+
+QTI MSM8916 platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Stephan Gerhold <stephan@gerhold.net>
+:|G|: `stephan-gh`_
+:|M|: Nikita Travkin <nikita@trvn.ru>
+:|G|: `TravMurav`_
+:|F|: docs/plat/qti-msm8916.rst
+:|F|: plat/qti/msm8916/
+
+Raspberry Pi 3 platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+:|G|: `grandpaul`_
+:|F|: docs/plat/rpi3.rst
+:|F|: plat/rpi/rpi3/
+:|F|: plat/rpi/common/
+:|F|: drivers/rpi3/
+:|F|: include/drivers/rpi3/
+
+Raspberry Pi 4 platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Andre Przywara <andre.przywara@arm.com>
+:|G|: `Andre-ARM`_
+:|F|: docs/plat/rpi4.rst
+:|F|: plat/rpi/rpi4/
+:|F|: plat/rpi/common/
+:|F|: drivers/rpi3/
+:|F|: include/drivers/rpi3/
+
+Renesas rcar-gen3 platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Jorge Ramirez-Ortiz <jramirez@baylibre.com>
+:|G|: `ldts`_
+:|M|: Marek Vasut <marek.vasut@gmail.com>
+:|G|: `marex`_
+:|F|: docs/plat/rcar-gen3.rst
+:|F|: plat/renesas/common
+:|F|: plat/renesas/rcar
+:|F|: drivers/renesas/common
+:|F|: drivers/renesas/rcar
+:|F|: tools/renesas/rcar_layout_create
+
+Renesas RZ/G2 platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Biju Das <biju.das.jz@bp.renesas.com>
+:|G|: `bijucdas`_
+:|M|: Marek Vasut <marek.vasut@gmail.com>
+:|G|: `marex`_
+:|M|: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+:|G|: `prabhakarlad`_
+:|F|: docs/plat/rz-g2.rst
+:|F|: plat/renesas/common
+:|F|: plat/renesas/rzg
+:|F|: drivers/renesas/common
+:|F|: drivers/renesas/rzg
+:|F|: tools/renesas/rzg_layout_create
+
+RockChip platform port
+^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Tony Xie <tony.xie@rock-chips.com>
+:|G|: `TonyXie06`_
+:|G|: `rockchip-linux`_
+:|M|: Heiko Stuebner <heiko@sntech.de>
+:|G|: `mmind`_
+:|M|: Julius Werner <jwerner@chromium.org>
+:|G|: `jwerner-chromium`_
+:|F|: plat/rockchip/
+
+STM32MP1 platform port
+^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Yann Gautier <yann.gautier@st.com>
+:|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 <sumit.garg@linaro.org>
+:|G|: `b49020`_
+:|F|: docs/plat/synquacer.rst
+:|F|: plat/socionext/synquacer/
+
+Texas Instruments platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Nishanth Menon <nm@ti.com>
+:|G|: `nmenon`_
+:|F|: docs/plat/ti-k3.rst
+:|F|: plat/ti/
+
+UniPhier platform port
+^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Orphan
+:|F|: docs/plat/socionext-uniphier.rst
+:|F|: plat/socionext/uniphier/
+
+Xilinx platform port
+^^^^^^^^^^^^^^^^^^^^
+:|M|: Michal Simek <michal.simek@amd.com>
+:|G|: `michalsimek`_
+:|M|: Venkatesh Yadav Abbarapu <venkatesh.abbarapu@amd.com>
+:|G|: `venkatesh`_
+:|F|: docs/plat/xilinx\*
+:|F|: plat/xilinx/
+
+
+Secure Payloads and Dispatchers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+OP-TEE dispatcher
+^^^^^^^^^^^^^^^^^
+:|M|: Jens Wiklander <jens.wiklander@linaro.org>
+:|G|: `jenswi-linaro`_
+:|F|: docs/components/spd/optee-dispatcher.rst
+:|F|: services/spd/opteed/
+
+TLK
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Varun Wadekar <vwadekar@nvidia.com>
+:|G|: `vwadekar`_
+:|F|: docs/components/spd/tlk-dispatcher.rst
+:|F|: include/bl32/payloads/tlk.h
+:|F|: services/spd/tlkd/
+
+Trusty secure payloads
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Arve Hjønnevåg <arve@android.com>
+:|G|: `arve-android`_
+:|M|: Marco Nelissen <marcone@google.com>
+:|G|: `marcone`_
+:|M|: Varun Wadekar <vwadekar@nvidia.com>
+:|G|: `vwadekar`_
+:|F|: docs/components/spd/trusty-dispatcher.rst
+:|F|: services/spd/trusty/
+
+
+Test Secure Payload (TSP)
+^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Manish Badarkhe <manish.badarkhe@arm.com>
+:|G|: `ManishVB-Arm`_
+:|F|: bl32/tsp/
+:|F|: services/spd/tspd/
+
+ProvenCore Secure Payload Dispatcher
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Jérémie Corbier <jeremie.corbier@provenrun.com>
+:|G|: `jcorbier`_
+:|F|: docs/components/spd/pnc-dispatcher.rst
+:|F|: services/spd/pncd/
+
+Tools
+~~~~~
+
+Fiptool
+^^^^^^^
+:|M|: Manish Badarkhe <manish.badarkhe@arm.com>
+:|G|: `ManishVB-Arm`_
+:|M|: Joao Alves <Joao.Alves@arm.com>
+:|G|: `J-Alves`_
+:|F|: tools/fiptool/
+
+Cert_create tool
+^^^^^^^^^^^^^^^^
+:|M|: Sandrine Bailleux <sandrine.bailleux@arm.com>
+:|G|: `sandrine-bailleux-arm`_
+:|M|: Manish Badarkhe <manish.badarkhe@arm.com>
+:|G|: `ManishVB-Arm`_
+:|M|: Lauren Wehrmeister <Lauren.Wehrmeister@arm.com>
+:|G|: `laurenw-arm`_
+:|F|: tools/cert_create/
+
+Encrypt_fw tool
+^^^^^^^^^^^^^^^
+:|M|: Sumit Garg <sumit.garg@linaro.org>
+:|G|: `b49020`_
+:|F|: tools/encrypt_fw/
+
+Sptool
+^^^^^^
+:|M|: Manish Pandey <manish.pandey2@arm.com>
+:|G|: `manish-pandey-arm`_
+:|M|: Joao Alves <Joao.Alves@arm.com>
+:|G|: `J-Alves`_
+:|F|: tools/sptool/
+
+Build system
+^^^^^^^^^^^^
+:|M|: Chris Kay <chris.kay@arm.com>
+:|G|: `CJKay`_
+:|M|: Manish Pandey <manish.pandey2@arm.com>
+:|G|: `manish-pandey-arm`_
+:|F|: Makefile
+:|F|: make_helpers/
+
+Threat Model
+~~~~~~~~~~~~~
+:|M|: Sandrine Bailleux <sandrine.bailleux@arm.com>
+:|G|: `sandrine-bailleux-arm`_
+:|M|: Joanna Farley <joanna.farley@arm.com>
+:|G|: `joannafarley-arm`_
+:|M|: Raghu Krishnamurthy <raghu.ncstate@icloud.com>
+:|G|: `raghuncstate`_
+:|M|: Varun Wadekar <vwadekar@nvidia.com>
+:|G|: `vwadekar`_
+:|F|: docs/threat_model/
+
+Conventional Changelog Extensions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+:|M|: Chris Kay <chris.kay@arm.com>
+:|G|: `CJKay`_
+:|F|: tools/conventional-changelog-tf-a
+
+.. _AlexeiFedorov: https://github.com/AlexeiFedorov
+.. _andersdellien-arm: https://github.com/andersdellien-arm
+.. _Andre-ARM: https://github.com/Andre-ARM
+.. _Anson-Huang: https://github.com/Anson-Huang
+.. _bijucdas: https://github.com/bijucdas
+.. _bryanodonoghue: https://github.com/bryanodonoghue
+.. _b49020: https://github.com/b49020
+.. _carlocaione: https://github.com/carlocaione
+.. _danh-arm: https://github.com/danh-arm
+.. _davidvincze: https://github.com/davidvincze
+.. _etienne-lms: https://github.com/etienne-lms
+.. _glneo: https://github.com/glneo
+.. _grandpaul: https://github.com/grandpaul
+.. _hzhuang1: https://github.com/hzhuang1
+.. _JackyBai: https://github.com/JackyBai
+.. _jcorbier: https://github.com/jcorbier
+.. _jenswi-linaro: https://github.com/jenswi-linaro
+.. _jslater8: https://github.com/jslater8
+.. _jwerner-chromium: https://github.com/jwerner-chromium
+.. _kostapr: https://github.com/kostapr
+.. _lachitp: https://github.com/lachitp
+.. _ldts: https://github.com/ldts
+.. _marex: https://github.com/marex
+.. _masahir0y: https://github.com/masahir0y
+.. _michalsimek: https://github.com/michalsimek
+.. _mikaelolsson-arm: https://github.com/mikaelolsson-arm
+.. _mmind: https://github.com/mmind
+.. _MrVan: https://github.com/MrVan
+.. _mtk-rex-bc-chen: https://github.com/mtk-rex-bc-chen
+.. _leon-chen-mtk: https://github.com/leon-chen-mtk
+.. _niej: https://github.com/niej
+.. _npoushin: https://github.com/npoushin
+.. _prabhakarlad: https://github.com/prabhakarlad
+.. _quic_mkf: https://github.com/quicmkf
+.. _remi-triplefault: https://github.com/repk
+.. _rockchip-linux: https://github.com/rockchip-linux
+.. _sandrine-bailleux-arm: https://github.com/sandrine-bailleux-arm
+.. _sgorecha: https://github.com/sgorecha
+.. _shawnguo2: https://github.com/shawnguo2
+.. _smaeul: https://github.com/smaeul
+.. _soby-mathew: https://github.com/soby-mathew
+.. _sreekare: https://github.com/sreekare
+.. _stephan-gh: https://github.com/stephan-gh
+.. _sieumunt: https://github.com/sieumunt
+.. _BenjaminLimJL: https://github.com/BenjaminLimJL
+.. _thomas-arm: https://github.com/thomas-arm
+.. _TonyXie06: https://github.com/TonyXie06
+.. _TravMurav: https://github.com/TravMurav
+.. _vwadekar: https://github.com/vwadekar
+.. _venkatesh: https://github.com/vabbarap
+.. _Yann-lms: https://github.com/Yann-lms
+.. _manish-pandey-arm: https://github.com/manish-pandey-arm
+.. _mardyk01: https://github.com/mardyk01
+.. _odeprez: https://github.com/odeprez
+.. _bipinravi-arm: https://github.com/bipinravi-arm
+.. _joannafarley-arm: https://github.com/joannafarley-arm
+.. _ManishVB-Arm: https://github.com/ManishVB-Arm
+.. _max-shvetsov: https://github.com/max-shvetsov
+.. _javieralso-arm: https://github.com/javieralso-arm
+.. _laurenw-arm: https://github.com/laurenw-arm
+.. _J-Alves: https://github.com/J-Alves
+.. _madhukar-Arm: https://github.com/madhukar-Arm
+.. _raghuncstate: https://github.com/raghuncstate
+.. _CJKay: https://github.com/cjkay
+.. _nmenon: https://github.com/nmenon
+.. _manojkumar-arm: https://github.com/manojkumar-arm
+.. _chandnich: https://github.com/chandnich
+.. _abdellatif-elkhlifi: https://github.com/abdellatif-elkhlifi
+.. _vishnu-banavath: https://github.com/vishnu-banavath
+.. _vijayenthiran-arm: https://github.com/vijayenthiran-arm
+.. _arugan02: https://github.com/arugan02
+.. _uarif1: https://github.com/uarif1
+.. _pangupta: https://github.com/pangupta
+.. _JiafeiPan: https://github.com/JiafeiPan
+.. _arve-android: https://github.com/arve-android
+.. _marcone: https://github.com/marcone
+.. _marcbonnici: https://github.com/marcbonnici
+.. _jayanthchidanand-arm: https://github.com/jayanthchidanand-arm
+.. _bytefire: https://github.com/bytefire
+
+.. _Project Maintenance Process: https://developer.trustedfirmware.org/w/collaboration/project-maintenance-process/
diff --git a/docs/about/release-information.rst b/docs/about/release-information.rst
new file mode 100644
index 0000000..dead4f7
--- /dev/null
+++ b/docs/about/release-information.rst
@@ -0,0 +1,78 @@
+Release 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 Apr '20 | 1st week of Apr '20 |
++-----------------+---------------------------+------------------------------+
+| v2.4 | 2nd week of Nov '20 | 4th week of Oct '20 |
++-----------------+---------------------------+------------------------------+
+| v2.5 | 3rd week of May '21 | 5th week of Apr '21 |
++-----------------+---------------------------+------------------------------+
+| v2.6 | 4th week of Nov '21 | 2nd week of Nov '21 |
++-----------------+---------------------------+------------------------------+
+| v2.7 | 5th week of May '22 | 3rd week of May '22 |
++-----------------+---------------------------+------------------------------+
+| v2.8 | 5th week of Nov '22 | 3rd week of Nov '22 |
++-----------------+---------------------------+------------------------------+
+| v2.9 | 1st week of May '23 | 3rd week of Apr '23 |
++-----------------+---------------------------+------------------------------+
+
+Removal of Deprecated Interfaces
+--------------------------------
+
+As mentioned in the :ref:`Platform Ports 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 | |
++================================+=============+=========+=========================================================+
+| plat_convert_pk() function | Nov'22 | Next | Platform conversion to manage specific PK hash |
+| | | release | |
+| | | after | |
+| | | 2.8 | |
++--------------------------------+-------------+---------+---------------------------------------------------------+
+
+--------------
+
+*Copyright (c) 2018-2022, Arm Limited and Contributors. All rights reserved.*
diff --git a/docs/change-log.md b/docs/change-log.md
new file mode 100644
index 0000000..bb05afb
--- /dev/null
+++ b/docs/change-log.md
@@ -0,0 +1,6850 @@
+# Change Log & Release Notes
+
+This document contains a summary of the new features, changes, fixes and known
+issues in each release of Trusted Firmware-A.
+
+## [2.8.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/v2.7.0..refs/tags/v2.8.0) (2022-11-15)
+
+### âš  BREAKING CHANGES
+
+- **Drivers**
+
+ - **Arm**
+
+ - **Ethos-N**
+
+ - add support for SMMU streams
+
+ **See:** add support for SMMU streams ([b139f1c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b139f1cf975f9968eb8bd1182a173b976ecf06f9))
+
+### New Features
+
+- **Architecture**
+
+ - pass SMCCCv1.3 SVE hint bit to dispatchers ([0fe7b9f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0fe7b9f2bcdf754c483399c841e5f0ec71e53ef3))
+
+ - **Branch Record Buffer Extension (FEAT_BRBE)**
+
+ - add brbe under feature detection mechanism ([1298f2f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1298f2f13d6d97dfcac120a2ee68d5eea3797068))
+
+ - **Confidential Compute Architecture (CCA)**
+
+ - introduce new "cca" chain of trust ([56b741d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/56b741d3e41cd6b2f6863a372a9489c819e2b0e9))
+
+ - **Pointer Authentication Extension**
+
+ - add/modify helpers to support QARMA3 ([9ff5f75](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9ff5f754aea00d0e86ba5191839fc0faef949fe0))
+
+ - **Trapping support for RNDR/RNDRRS (FEAT_RNG_TRAP)**
+
+ - add EL3 support for FEAT_RNG_TRAP ([ff86e0b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ff86e0b4e6c34d28b8642dd8eb9cbdd517bad195))
+
+ - **Scalable Matrix Extension (FEAT_SME)**
+
+ - fall back to SVE if SME is not there ([26a3351](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/26a3351edab1501d7e19ae96540c34b2700ac32f))
+
+ - **Scalable Vector Extension (FEAT_SVE)**
+
+ - support full SVE vector length ([bebcf27](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bebcf27f1c75f48cc129e8608cba113d0db32ef8))
+
+ - **Trace Buffer Extension (FEAT_TRBE)**
+
+ - add trbe under feature detection mechanism ([47c681b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/47c681b7d7f03e77f6cdd7b5d116ae64671ab8ca))
+
+- **Platforms**
+
+ - **Arm**
+
+ - add support for cca CoT ([f242379](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f24237921e3fa61e64fa1ec845e14e2748d04a2b))
+ - forbid running RME-enlightened BL31 from DRAM ([1164a59](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1164a59cb16a9bbc672fa6d07895bc6fa0361bcb))
+ - provide some swd rotpk files ([98662a7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/98662a73c903b06f53c9f9da6a9404187fc10352))
+ - retrieve the right ROTPK for cca ([50b4497](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/50b449776df11cac06347e8ef1af5dae701a0e3a))
+
+ - **CSS**
+
+ - add interrupt handler for reboot request ([f1fe144](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f1fe1440db197d514b5484e780cfb90f504c62b9))
+ - add per-cpu power down support for warm reset ([158ed58](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/158ed580bdf5736abfa9f16f61be1ca1609e0e41))
+
+ - **FVP**
+
+ - add example manifest for TSP ([3cf080e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3cf080ed61e90668f0c44ca7f577e51c081e5c7c))
+ - add crypto support in BL31 ([c9bd1ba](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c9bd1bacffd9697ec4ebac77e45588cf6c261a3b))
+ - add plat API to set and get the DRTM error ([586f60c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/586f60cc571f0f3b6d20eb5033717e9b0cc66af4))
+ - add plat API to validate that passed region is non-secure ([d5f225d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d5f225d95d3dc7473340ffebfcb9068b54f91a17))
+ - add platform hooks for DRTM DMA protection ([d72c486](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d72c486b52dc654e4216d41dcc1b0f87bdbdf3e9))
+ - build delegated attestation in BL31 ([0271edd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0271eddb0c00b01033bf651f0eeaf659c0c2dd39))
+ - dts: drop 32-bit .dts files ([b920330](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b92033075aa27031091e184b54f4dc278ecb27bc))
+ - fdts: update rtsm_ve DT files from the Linux kernel ([2716bd3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2716bd33e318821c373b3d4dce88110a340a740d))
+ - increase BL31's stack size for DRTM support ([44df105](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/44df105ff867aeb2aa5d20faa3e8389866099956))
+ - increase MAX_XLAT_TABLES entries for DRTM support ([8a8dace](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8a8dace5a5cd3a51d67df3cea86628f29cc96013))
+ - support building RSS comms driver ([29e6fc5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/29e6fc5cc7d0c8bc4ba615fd97df4cb65d3c7ba3))
+
+ - **RD**
+
+ - **RD-N2**
+
+ - add a new 'isolated-cpu-list' property ([afa4157](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/afa41571b856509c25c66c331737b895144b681b))
+ - add SPI ID ranges for RD-N2 multichip platform ([9f0835e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9f0835e9156f13b56336a47a4b51e90719a852ff))
+ - enable extended SPI support ([108488f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/108488f9ac026f036c0de2b824b339a30f9a0cbb))
+
+ - **SGI**
+
+ - increase memory reserved for bl31 image ([a62cc91](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a62cc91aeedbdcfb3396983ed165eb35b8d4c3fa))
+ - read isolated cpu mpid list from sds ([4243ef4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4243ef41d480fd8e870f74defe263156a6c02c8d))
+ - add page table translation entry for secure uart ([2a7e080](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2a7e080cc50be5739afcfb3b7db59e4d610a7d53))
+ - bump bl1 rw size ([94df8da](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/94df8da3ab520330b2e7d276603f33e284c27b3f))
+ - configure SRAM and BL31 size for sgi platform ([8fd820f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8fd820ffb918ad8fdc1f2c72cc64dad5eaff77aa))
+ - deviate from arm css common uart related definitions ([173674a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/173674ae428aa23e8f2a38d5542d0ea52eed7e80))
+ - enable css implementation of warm reset ([18884c0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/18884c002e6c298f27d6e4792eab2c9f4d89bddb))
+ - remove override for `ARM_BL31_IN_DRAM` build-option ([a371327](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a371327ba9fc2e1c5988ac1436b29c42aab8dfd8))
+ - route TF-A logs via secure uart ([0601083](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0601083f0ce0045bd957c1343d2196be0887973b))
+
+ - **TC**
+
+ - add MHU addresses for AP-RSS comms on TC2 ([6299c3a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6299c3a0f7c8220b0bf15723ec8995b72bf97677))
+ - add RSS-AP message size macro ([445130b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/445130b127f411bdf4958fa10f292a930c9ae57d))
+ - add RTC PL031 device tree node ([a816de5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a816de564f927ebb72ab7692b8b3f46073179310))
+ - enable RSS backend based measured boot ([6cb5d32](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6cb5d3268fa41d15480c4e070a51577b333767fe))
+ - increase maximum BL1/BL2/BL31 sizes ([e6c1316](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e6c131655fa168ffd1ae738a74ba25e5f850036c))
+ - introduce TC2 platform ([eebd2c3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/eebd2c3f61c90942fb186fa43fbb4c4a543d8b55))
+ - move start address for BL1 to 0x1000 ([9335c28](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9335c28a019ee2d9ab7a0f9276b91415f3c9f1bc))
+
+ - **HiSilicon**
+
+ - **HiKey960**
+
+ - add a FF-A logical partition ([25a357f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/25a357f1932cf2b0d125dd98b82eeacad14005ea))
+ - add memory sharing hooks for SPMC_AT_EL3 ([5f905a2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5f905a249839e9e20ebf44c22d95caaf3a2e5611))
+ - add plat-defines for SPMC_AT_EL3 ([feebd4c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/feebd4c7a86b6f0fcc1eb5008ba5f7d44e75beaf))
+ - add SP manifest for SPMC_AT_EL3 ([6971642](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6971642d23d0c5e33e507eb78b7c569045e2f85d))
+ - define a datastore for SPMC_AT_EL3 ([e618c62](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e618c621b3ece7a0262ff9245027132982e6207c))
+ - increase secure workspace to 64MB ([e0eea33](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e0eea337b32e37bbef9bad1310b96b9c0d86f7b9))
+ - read serial number from UFS ([c371b83](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c371b83f0c5b503c21bd1b6092bc0230032329ce))
+ - upgrade to xlat_tables_v2 ([6cfc807](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6cfc8078d032d278e09523e236ab5b36f69f2ec0))
+
+ - **MediaTek**
+
+ - add more flexibility of mtk_pm.c ([6ca2046](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6ca2046ef15dcf19fbda5f12cbfe1004d340c969))
+ - add more options for build helper ([5b95e43](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5b95e439c745dcf94899238b82826d8f1d32acbe))
+ - add smcc call for MSDC ([4dbe24c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4dbe24cf7d2b04c552f394062f42c30fee7e26a6))
+ - extend SiP vendor subscription events ([99d30b7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/99d30b72c02502731ecf116acfda44ee3c2c9e5e))
+ - implement generic platform port ([394b920](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/394b92084d53e2bf8960731be7a79c999871f127))
+ - introduce mtk init framework ([52035de](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/52035dee1ae7b0f2f0d5f16c734ca7a5cea127b7))
+ - move dp drivers to common folder ([d150b62](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d150b6296e6960f2548b265b8b23e6cdb502d3b7))
+ - move lpm drivers back to common ([cd7890d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cd7890d79e9d508e82f3078f02e8277f8c8df181))
+ - move mtk_cirq.c drivers to cirq folder ([cc76896](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cc76896d9e416b15548b2d6bf068e5d3f9b4064a))
+ - support coreboot BL31 loading ([ef988ae](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ef988aed9e09a4108b87decb14dee5f2d23230a4))
+
+ - **MT8186**
+
+ - add EMI MPU support for SCP and DSP ([3d4b6f9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3d4b6f932444c7b0f70f8654b92193b294527056))
+
+ - **MT8188**
+
+ - add armv8.2 support ([45711e4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/45711e4e1614fbed75ea645777cc2bb11d4be96f))
+ - add audio support ([c70f567](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c70f567ad75c30a990cb60c71b6c0b02538366fd))
+ - add cpu_pm driver ([4fe7e6a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4fe7e6a8d9f09c40d087167432cb07621c175b3f))
+ - add DCM driver ([bc9410e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bc9410e2376e0b6355ea6440aa90ad968fc5f3b3))
+ - add DFD control in SiP service ([7079a94](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7079a942bd9705fd9e0cd220324f7dfd9c53dcad))
+ - add display port control in SiP service ([a4e5023](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a4e502319d136d8854ef2ed4aaa6d5368541e551))
+ - add EMI MPU basic drivers ([8454f0d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8454f0d65eeb85b72f454376faa0f7a15226e240))
+ - add IOMMU enable control in SiP service ([be45724](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/be457248c6b0a7f3c61bd95af58372938d13decd))
+ - add LPM driver support ([f604e4e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f604e4ef6e306c6d87e17e77e50a68aad0510110))
+ - add MCUSYS support ([4cc1ff7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4cc1ff7ef2c3544ef1aabeb2973a2d8f7800776b))
+ - add pinctrl support ([ec4cfb9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ec4cfb91fc197a024d1edb9fae5e9ce100e5b200))
+ - add pmic and pwrap support ([e9310c3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e9310c34b018944a6c29a8f408f0a34b43a0df6d))
+ - add reset and poweroff functions ([a72b9e7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a72b9e7754a27e6ebccf79f0cc4fb7cc5a0a8a5e))
+ - add RTC support ([af5d8e0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/af5d8e07955ddef9000c64de94deb2703e6ffcf0))
+ - add support for PTP3 ([44a1051](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/44a10511c9e5a66b3a33abba44856a7a5dc5e655))
+ - apply ERRATA for CA-78 ([abb995a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/abb995abbe45874a397351cbb134ae32d4cc545b))
+ - enable MTK_PUBEVENT_ENABLE ([0b1186a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0b1186a3e6fd6daffaef3f6cf59650bb9121191c))
+ - initialize GIC ([cfb0516](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cfb0516f3cc36e3d0ec9b0bdabf1eb6ea2b275c1))
+ - initialize platform for MediaTek MT8188 ([de310e1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/de310e1e5f0b76b9de2b93759344540e0109c8eb))
+ - initialize systimer ([215869c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/215869c693c136192505a004ec368f503f146505))
+
+ - **NXP**
+
+ - **i.MX**
+
+ - **i.MX 8M**
+
+ - add dram retention flow for imx8m family ([c71793c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c71793c6476fa2828f866b8d7b272289f0d9a15c))
+ - add support for high assurance boot ([720e7b6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/720e7b66f2353ef7ed32a8f85f8396fbc0766ffc))
+ - add the anamix pll override setting ([66d399e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/66d399e454b160ce358346cfa9142a24d8493a41))
+ - add the ddr frequency change support for imx8m family ([9c336f6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9c336f6118a94970f4045641a971fd1e24dba462))
+ - add the PU power domain support on imx8mm/mn ([44dea54](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/44dea5444b087acd758b1c8370999be635e17e43))
+ - keep pu domains in default state during boot stage ([9d3249d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9d3249de8078e33b90193d8f91f4914acc36c6ec))
+ - make psci common code pie compatible ([5d2d332](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5d2d3328db88846accd179c96d71bab79a150937))
+
+ - **i.MX 8M Nano**
+
+ - add BL31 PIE support ([62d37a4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/62d37a4362456694bdae6d8921c2c7572a0d99a4))
+ - add hab and map required memory blocks ([b5f06d3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b5f06d3dfad8c27bdf528b083ef919ce4022c52d))
+ - enable dram retention suuport on imx8mn ([2003fa9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2003fa94dc9b9eda575ebfd686308c6f87c366f0))
+
+ - **i.MX 8M Mini**
+
+ - add BL31 PIE support ([a8e6a2c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a8e6a2c83ce511dad88eb68f98a3191fa93564d4))
+ - add hab and map required memory blocks ([5941f37](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5941f37288a5ceac495cbdbd3e3d02f1a3c55e0a))
+ - enable dram retention suuport on imx8mm ([b7abf48](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b7abf485ee15c3e5b16522bb91dd6b0c24bfbfc0))
+
+ - **i.MX 8M Plus**
+
+ - add BL31 PIE support ([7a443fe](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7a443fefa4eaef65332a38c8189573b5b4b4a1e3))
+ - add hab and map required memory blocks ([62a93aa](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/62a93aa7afcd022f06d322c36979f0aa02713beb))
+
+ - **i.MX 8Q**
+
+ - add 100us delay after USB OTG SRC bit 0 clear ([66345b8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/66345b8b13dc32bcd9f6af3c04f60532e7d82858))
+
+ - **Layerscape**
+
+ - **LS1043A**
+
+ - **LS1043ARDB**
+
+ - update ddr configure for ls1043ardb-pd ([18af644](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/18af644279b36e841068db0e1c857dedf1456b38))
+
+ - **QEMU**
+
+ - increase size of bl31 ([0e6977e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0e6977eee178a6436e4a7e1503ea854989316ff4))
+
+ - **QTI**
+
+ - fix to support cpu errata ([6cc743c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6cc743cf0fa9b216f2af8ff87c716dcc0bb6f6a0))
+ - updated soc version for sc7180 and sc7280 ([39fdd3d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/39fdd3d85d1165cd1b876288532000c5c6eb1ecb))
+
+ - **Socionext**
+
+ - **Synquacer**
+
+ - add BL2 support ([48ab390](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/48ab390444e1dabb669430ace9b8e5a80348eed0))
+ - add FWU Multi Bank Update support ([a193825](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a19382521c583b3dde89df14678b011960097f6c))
+ - add TBBR support ([19aaeea](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/19aaeea00bc4fba94af7aca508af878136930f4a))
+
+ - **ST**
+
+ - add trace for early console ([00606df](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/00606df01201fcad509ea9ddff89d5f176bee793))
+ - enable MMC_FLAG_SD_CMD6 for SD-cards ([53d5b8f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/53d5b8ff50d322f764b1f5a8c882b9ee1ba952c9))
+ - properly manage early console ([5223d88](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5223d88032dcecb880d620e63bfa70799dc6cc1a))
+ - search pinctrl node by compatible ([b14d3e2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b14d3e22b4964ce589d107e7fd68601bf070f44c))
+
+ - **STM32MP1**
+
+ - add a check on TRUSTED_BOARD_BOOT with secure chip ([54007c3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/54007c37d560dd170efa52a79feb206aefb90ed4))
+ - add a stm32mp crypto library ([ad3e46a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ad3e46a35cb208e16adfe3d753214739583dca10))
+ - add define for external scratch buffer for nand devices ([9ee2510](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9ee2510b62ef9428d767523ddb9c5a39b7a2b954))
+ - add early console in SP_min ([14a0704](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/14a070408d9231dc1c487dfe36058b93faf5915c))
+ - add plat_report_*_abort functions ([0423868](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0423868373026a667f0c004e4d365fa12fd734ef))
+ - add RNG initialization in BL2 for STM32MP13 ([2742374](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2742374414c5891ac37fd4d42ba62c3cff1474c6))
+ - add the decryption support ([cd79116](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cd791164a9ad2f42d25d24012715bbe763b41e1c))
+ - add the platform specific build for tools ([461d631](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/461d631acae9daec77c9668216280cbf66240249))
+ - add the TRUSTED_BOARD_BOOT support ([beb625f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/beb625f90bfd1858b9d413cae67457e57c79a118))
+ - allow to override MTD base offset ([e0bbc19](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e0bbc190d500e53ee0566af85639d3cdbbe7177d))
+ - configure the serial boot load address ([4b2f23e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4b2f23e55f27b6baccf3e858234e69685d51fcf4))
+ - extend STM32MP_EMMC_BOOT support to FIP format ([95e4908](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/95e4908e17fbb44aed1f8612fefdd6d21fef8f49))
+ - manage second NAND OTP on STM32MP13 ([d3434dc](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d3434dca0b3acb902fe3a6cf39065ba917f69b1c))
+ - manage STM32MP13 rev.Y ([a3f97f6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a3f97f66c36e987a6617f1f39c3b9e64b763212c))
+ - optionally use paged OP-TEE ([c4dbcb8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c4dbcb885201c89a44df203661af007945782993))
+ - remove unused function from boot API ([f30034a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f30034a298a8d7260464cbcf2d2306bff533d6dd))
+ - retrieve FIP partition by type UUID ([1dab28f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1dab28f99dfa03dc11538056a90f00f37bfb1085))
+ - save boot auth status and partition info ([ab2b325](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ab2b325c1ab895e626d4e11a9f26b9e7c968f8d8))
+ - update ROM code API for header v2 management ([89c0774](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/89c07747d0396b92c83af8736ff49ef8c09bc176))
+
+ - **STM32MP13**
+
+ - change BL33 memory mapping ([10f6dc7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/10f6dc789350ed5915a474b2d411890261b741ae))
+
+ - **STM32MP15**
+
+ - manage OP-TEE shared memory ([722ca35](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/722ca35ecc1c5de8682ca8df315a6369d0c21946))
+
+ - **Texas Instruments**
+
+ - **K3**
+
+ - add support for J784S4 SoCs ([4a566b2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4a566b26ae6135d4c13deab9d3f1c40c1cb8960a))
+
+ - **Xilinx**
+
+ - **Versal**
+
+ - add infrastructure to handle multiple interrupts ([e497421](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e497421d7f1e13d15313d1ca71a8e91f370cce1e))
+ - get the handoff params using IPI ([205c7ad](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/205c7ad4cd73e5c091b03f23a3a3be74da5c8aea))
+ - resolve the misra 10.1 warnings ([b86e1aa](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b86e1aade1c0953bd60ae0b35f1c3571ee8bae3f))
+ - update macro name to generic and move to common place ([f99306d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f99306d49ba074279c5402a0a34e6bc9797d77de))
+
+ - **Versal NET**
+
+ - add support for QEMU COSIM platform ([6a079ef](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6a079efd909b459448f561618df24fa94038dbad))
+ - add documentation for Versal NET SoC ([4efdc48](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4efdc488961502033262613b6f20abcee68bbf84))
+ - add SMP support for Versal NET ([8529c76](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8529c7694f8d614e76dcc80b394ec8a6751df44c))
+ - add support for IPI ([0bf622d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0bf622de68cd353a8406f76647b6afd8791d675d))
+ - add support for platform management ([0654ab7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0654ab7f75449307c79789e12be7aab2338edcc3))
+ - add support for Xilinx Versal NET platform ([1d333e6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1d333e69091f0c71854a224e8cfec08695b7d1f3))
+
+ - **ZynqMP**
+
+ - optimization on pinctrl_functions ([314f9f7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/314f9f7957fbab12dc8d073cf054b99520372e0e))
+ - add support for ProvenCore ([358aa6b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/358aa6b21118ae4eedf816f663aa950b58f7fd4e))
+ - add support for xck24 silicon ([86869f9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/86869f99d0c144ed18fb947866554a4a56b67741))
+ - protect eFuses from non-secure access ([d0b7286](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d0b7286e48f0a34e7e9a8db3948caf1809193430))
+ - resolve the misra 10.1 warnings ([bfd7c88](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bfd7c881905702082e3c2a56d5228ccf5fe98f11))
+
+- **Bootloader Images**
+
+ - add interface to query TF-A semantic ver ([dddf428](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/dddf4283b043ad0a81d27bd5bb2f0c647c511e11))
+
+ - **BL32**
+
+ - **TSP**
+
+ - add FF-A support to the TSP ([4a8bfdb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4a8bfdb90956ecec02ba5e189fe5452817a65179))
+ - add ffa_helpers to enable more FF-A functionality ([e9b1f30](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e9b1f300a974a7e82190b95899c3128b73088488))
+ - enable test cases for EL3 SPMC ([15ca1ee](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/15ca1ee342a4dcd8a73a4ae158d245cd4266c832))
+ - increase stack size for tsp ([5b7bd2a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5b7bd2af0b2972dfffeaa674947c0082d6b5126b))
+
+- **Services**
+
+ - add a SPD for ProvenCore ([b0980e5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b0980e584398fc5adc908cd68f1a6deefa943d29))
+
+ - **RME**
+
+ - **RMMD**
+
+ - add support for RMM Boot interface ([8c980a4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8c980a4a468aeabb9e49875fec395c625a0c2b2b))
+ - add support to create a boot manifest ([1d0ca40](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1d0ca40e9084903d21e570bb312646626aaf574b))
+
+ - **SPM**
+
+ - add tpm event log node to spmc manifest ([054f0fe](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/054f0fe1361ba0cb339fb0902470988a82a24cf7))
+
+ - **SPMD**
+
+ - avoid spoofing in FF-A direct request ([5519f07](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5519f07cd46a4139615a3e8f5e57d1834b23a6f8))
+
+ - **DRTM**
+
+ - add a few DRTM DMA protection APIs ([2b13a98](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2b13a985994213f766ada197427f96e064f1b59b))
+ - add DRTM parameters structure version check ([c503ded](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c503ded2c5d9ceec9fba4cc0901805307a14af3d))
+ - add Event Log driver support for DRTM ([4081426](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/40814266d53b7154daf5d212de481b397db43823))
+ - add PCR entries for DRTM ([ff1e42e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ff1e42e20aa247ba11cf81742abff07ece376ba8))
+ - add platform functions for DRTM ([2a1cdee](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2a1cdee4f5e6fe0b90399e442075880acad1869e))
+ - add remediation driver support in DRTM ([1436e37](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1436e37dcb894a539a22da48a34ef01566ae728b))
+ - add standard DRTM service ([e62748e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e62748e3f1f16934f0ef2d5742f3ca0b125eaea2))
+ - check drtm arguments during dynamic launch ([40e1fad](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/40e1fad69b9f28ab5e57cea33261bf629b05519c))
+ - ensure that no SDEI event registered during dynamic launch ([b1392f4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b1392f429cdd368ea2b8e183a1ac0fb31deaf694))
+ - ensure that passed region lies within Non-Secure region of DRAM ([764aa95](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/764aa951b2ca451694c74791964a712d423d8206))
+ - flush dcache before DLME launch ([67471e7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/67471e75b3cf48c361e71894a666bce4395bbb35))
+ - introduce drtm dynamic launch function ([bd6cc0b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bd6cc0b2388c52f2b232427be61ff52c042d724a))
+ - invalidate icache before DLME launch ([2c26597](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2c265975a76977c6373636f5f28e114d1b73e10e))
+ - prepare DLME data for DLME launch ([d42119c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d42119cc294fbca2afc263fe5e44538a0ca5e7b8))
+ - prepare EL state during dynamic launch ([d1747e1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d1747e1b8e617ad024456791ce0ab8950bb282ca))
+ - retrieve DRTM features ([e9467af](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e9467afb2d483ccec8f816902624d848e8f21d86))
+ - take DRTM components measurements before DLME launch ([2090e55](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2090e55283c4bf85c7a61735ca0e872745c55896))
+ - update drtm setup function ([d54792b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d54792bd93f76b943bf0559c8373b898e0e3b93c))
+
+- **Libraries**
+
+ - **CPU Support**
+
+ - add library support for Hunter ELP ([8c87bec](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8c87becbc64f2e233ac905aa006d5e15a63a9a8b))
+ - add a64fx cpu to tf-a ([74ec90e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/74ec90e69bbd0e932a61f5461eedc4abd1b99d44))
+ - make cache ops conditional ([04c7303](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/04c7303b9c3d2215eebc3d59431519990abe03d0))
+ - remove plat_can_cmo check for aarch32 ([92f8be8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/92f8be8fd1e77be67e9c9711afa8705204758304))
+ - update doc and check for plat_can_cmo ([a2e0123](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a2e0123484e62df8ed9f2943dbd158471bf31221))
+
+ - **OP-TEE**
+
+ - check paged_image_info ([c0a11cd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c0a11cd8698394e1d3d3d7c9cedb19846ba59223))
+
+ - **PSCI**
+
+ - add a helper function to ensure that non-boot PEs are offline ([ce14a12](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ce14a12f8b8f02b7221f37c7c4b46f909c1a4346))
+
+ - **C Standard Library**
+
+ - introduce __maybe_unused ([351f9cd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/351f9cd8897fd3ea52db2421721a152494b16328))
+
+ - **PSA**
+
+ - add delegated attestation partition API ([4b09ffe](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4b09ffef49663ebc8c8f5c3da19636208fe2fa06))
+ - remove initial attestation partition API ([420deb5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/420deb5a0dbbd35962e5449f82434c703e7a1179))
+
+- **Drivers**
+
+ - **Authentication**
+
+ - allow to verify PublicKey with platform format PK ([40f9f64](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/40f9f644e8af34e745dbaec73d7128c0a4902e54))
+ - enable MBEDTLS_CHECK_RETURN_WARNING ([a4e485d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a4e485d7bf1c428d64e90e9821e4b1a109d10626))
+
+ - **Crypto**
+
+ - update crypto module for DRTM support ([e43caf3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e43caf3890817e91b3d35b5ae1149a208f1a4016))
+
+ - **mbedTLS**
+
+ - update mbedTLS driver for DRTM support ([8b65390](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8b653909b7e2371c6dcddbeac112b9671c886f34))
+
+ - **I/O**
+
+ - **MTD**
+
+ - add platform function to allow using external buffer ([f29c070](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f29c0702d2e7a67327b67766f91793d8ae6d0f73))
+
+ - **MMC**
+
+ - get boot partition size ([f462c12](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f462c1249ac41f43423011bb12ace38cbeb0af4c))
+ - manage SD Switch Function for high speed mode ([e5b267b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e5b267bba14c55e7906d120c52d4e8e8bbb68df6))
+
+ - **MTD**
+
+ - add platform function to allow using external buffer ([f29c070](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f29c0702d2e7a67327b67766f91793d8ae6d0f73))
+
+ - **GUID Partition Tables Support**
+
+ - allow to find partition by type UUID ([564f5d4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/564f5d477663bc007916a11c48bdd8b9be4ad369))
+
+ - **SCMI**
+
+ - send powerdown request to online secondary cpus ([14a2892](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/14a289230918b23b0985e215d38614dc7480bd02))
+ - set warm reboot entry point ([5cf9cc1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5cf9cc130a90fd8c4503c57ec4af235b469fd473))
+
+ - **Arm**
+
+ - **Ethos-N**
+
+ - add support for SMMU streams ([b139f1c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b139f1cf975f9968eb8bd1182a173b976ecf06f9))
+
+ - **GIC**
+
+ - add APIs to raise NS and S-EL1 SGIs ([dcb31ff](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/dcb31ff79096fc88b45df8068e5de83b93f833ed))
+
+ - **GICv3**
+
+ - validate multichip data for GIC-700 ([a78b3b3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a78b3b382b07675a89a66ddffe926ed225eeb245))
+
+ - **RSS**
+
+ - add new comms protocols ([3125901](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/31259019235aebf7aa533d5c893940f597fb1a8b))
+
+ - **ST**
+
+ - **Crypto**
+
+ - add AES decrypt/auth by SAES IP ([4bb4e83](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4bb4e836498b0131feefbba3f857a0bf3b89e543))
+ - add ECDSA signature check with PKA ([b0fbc02](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b0fbc02aea76d31e749444da63b084e6b2bd089b))
+ - add STM32 RNG driver ([af8dee2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/af8dee20d5fee29f34ccd9b9556e0c23655ff549))
+ - remove BL32 HASH driver usage ([6b5fc19](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6b5fc19227ff8935b1352c0e4c0d716ebee60aa2))
+ - update HASH for new hardware version used in STM32MP13 ([68039f2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/68039f2d14626adce09512871d6cde20ff45e1d9))
+
+ - **SDMMC2**
+
+ - define FIFO size ([b46f74d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b46f74d4e68ee08b6e912cd7f855a16cc5e79a6a))
+ - make reset property optional ([8324b16](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8324b16cd5e0b1ae2f85264a74f879e8fb1bca2a))
+ - manage CMD6 ([3deebd4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3deebd4ccf39904d7fe777f53e9dbaa86691d653))
+
+ - **UART**
+
+ - add initialization with the device tree ([d99998f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d99998f76ed2e8676be25e31e9479a90c16c7098))
+ - manage STM32MP_RECONFIGURE_CONSOLE ([ea69dcd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ea69dcdc737d8b48fec769042922914e988153ef))
+
+- **Miscellaneous**
+
+ - **Debug**
+
+ - add AARCH32 CP15 fault registers ([bb22891](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bb2289142cbf0f3546c1034e0500b5dc32aef740))
+ - add helpers for aborts on AARCH32 ([6dc5979](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6dc5979a6cb2121e4c16e7bd62e24030e0f42755))
+
+ - **FDTs**
+
+ - **STM32MP1**
+
+ - add CoT and fuse references for authentication ([928fa66](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/928fa66272a0985c900c996912b54904c64d0520))
+ - change pin-controller to pinctrl ([44fea93](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/44fea93bf729f631f6ae47e06ac7b6012a795791))
+
+ - **STM32MP13**
+
+ - use STM32MP_DDR_S_SIZE in fw-config ([936f29f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/936f29f6b51b3c7f37fd34e30a7f1f7c3944b361))
+
+ - **STM32MP15**
+
+ - add Avenger96 board with STM32MP157A DHCOR SoM ([51e2230](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/51e223058fe70b311542178f1865514745fa7874))
+ - add support for STM32MP157C based DHCOM SoM on PDK2 board ([eef485a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/eef485abb13b6df9a94137edd82904aab0ecf02d))
+
+ - **SDEI**
+
+ - add a function to return total number of events registered ([e6381f9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e6381f9cf8c0c62c32d5a4765aaf166f50786914))
+
+ - **TBBR**
+
+ - increase PK_DER_LEN size ([1ef303f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1ef303f9f79020330bbd8e48ac652e8f2121a41b))
+
+- **Tools**
+
+ - **Firmware Image Package Tool**
+
+ - add cca, core_swd, plat cert in FIP ([147f52f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/147f52f3e81f7ccf1dae90bc5687ec137feeb46c))
+
+ - **Certificate Creation Tool**
+
+ - define the cca chain of trust ([0a6bf81](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0a6bf811d7f873a180ef4b9f96f5596b26d270c6))
+ - update for ECDSA brainpoolP256r/t1 support ([e78ba69](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e78ba69e3525c968118eb91f443b1e9db9eee5f5))
+
+- **Dependencies**
+
+ - **Compiler runtime libraries**
+
+ - update compiler-rt source files ([8a6a956](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8a6a9560b5dcccfb68064c0c8c9b4b47981c6ac7))
+
+ - **libfdt**
+
+ - add function to set MAC addresses ([1aa7e30](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1aa7e302a84bbf46a97bcfbb54b6b6d57de76cee))
+ - upgrade libfdt source files ([94b2f94](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/94b2f94bd63258c300b53ad421488c3c4455712b))
+
+ - **zlib**
+
+ - update zlib source files ([a194255](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a194255d75ed9e2ef56bd6e14349a3e7d86af934))
+
+### Resolved Issues
+
+- **Architecture**
+
+ - **Performance Monitors Extension (FEAT_PMUv3)**
+
+ - add sensible default for MDCR_EL2 ([7f85619](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7f8561985778cbe5cdc7d57984c818119e87adaf))
+
+ - **Scalable Matrix Extension (FEAT_SME)**
+
+ - add missing ISBs ([46e92f2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/46e92f2862326cbe57acecb2d0f3c2ffbcc176d2))
+
+- **Platforms**
+
+ - **Arm**
+
+ - **FVP**
+
+ - fdts: Fix idle-states entry method ([0e3d880](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0e3d88070f69c6aa7cc51a2847cbba3535992397))
+ - fdts: fix memtimer subframe addressing ([3fd12bb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3fd12bb8c622917d8491082b1472c39efb89c0cf))
+ - fdts: unify and fix PSCI nodes ([6b2721c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6b2721c01691743a65475e82944e2f8868bf0159))
+
+ - **FVP Versatile Express**
+
+ - fdts: Fix vexpress,config-bus subnode names ([60da130](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/60da130a8c5ac29bc35870180c35ca04db506e0f))
+
+ - **Morello**
+
+ - dts: add model names ([30df890](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/30df8904d0f6973bbce1ecb51f14c1e4725ddf0b))
+ - dts: fix DP SMMU IRQ ordering ([fba729b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fba729b0ca22be379792ce677296cda075036753))
+ - dts: fix DT node naming ([41c310b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/41c310b4f691c1eefcd0234619bc751966389297))
+ - dts: fix GICv3 compatible string ([982f258](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/982f2585bb27b58c017af70d852a433f36711db1))
+ - dts: fix SCMI shmem/mboxes grouping ([8aeb1fc](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8aeb1fcf832d4e06157a1bed1d18ba244c1fe9ee))
+ - dts: fix SMMU IRQ ordering ([5016ee4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5016ee44a740127f7865dc26ed0efbbff1481c7e))
+ - dts: fix stdout-path target ([67a8a5c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/67a8a5c92e7c65108b3cdf6f4f9dd2de7e22f3cd))
+ - dts: remove #a-c and #s-c from memory node ([f33e113](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f33e113c7a7dffd8ed219f25191907fd64bcf19f))
+ - dts: use documented DPU compatible string ([3169572](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3169572ed1bf0de17bb813583cab7ea295a8ec8d))
+ - move BL31 to run from DRAM space ([05330a4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/05330a49cd91c346a8b9dc3aff35d0032db4d413))
+
+ - **N1SDP**
+
+ - add numa node id for pcie controllers ([2974d2f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2974d2f2d03e842ed5e01e2e04dd3de6c1d07277))
+ - mapping Run-time UART to IOFPGA UART0 ([4a81e91](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4a81e91f2752a817364e1fccedb08bb453ad5a56))
+ - replace non-inclusive terms from dts file ([e6ffafb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e6ffafbeeae8c78abac37475f19899f0c98523ca))
+
+ - **TC**
+
+ - resolve the static-checks errors ([066450a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/066450abf326f1a68a21cdddf29f62eff95041a9))
+ - tc2 bl1 start address shifted by one page ([8597a8c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8597a8cbc23f0f03a15d013dd44a4ed59c991872))
+
+ - **Intel**
+
+ - fix asynchronous read response by copying data to input buffer ([dd7adcf](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/dd7adcf3a89a75973a88118eeb867d1c212c4ad0))
+ - fix Mac verify update and finalize for return response data ([fbf7aef](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fbf7aef408a9f67fabc712bbfd52438290364879))
+
+ - **MediaTek**
+
+ - remove unused cold_boot.[c|h] ([8cd3b69](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8cd3b693d6d5d3db2433a96c5f2905d92a387cc4))
+ - switch console to runtime state before leaving BL31 ([fcf4dd9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fcf4dd9f794b28bbfff3ee7d66bac8d5e260f46a))
+ - use uppercase for definition ([810d568](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/810d568141050db7d500c5f5ad91efaff93d2036))
+ - wrap cold_boot.h with MTK_SIP_KERNEL_BOOT_ENABLE ([24476b2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/24476b2e6128dae2ca2ac46344e18f6f02eae7bf))
+
+ - **MT8186**
+
+ - fix SCP permission ([8a998b5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8a998b5aca3ca895a7722e7496a7fd18cd838f94))
+ - fix EMI_MPU domain setting for DSP ([28a8b73](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/28a8b738feaade74f23af0e889005e687fde38b5))
+ - fix the DRAM voltage after the system resumes ([600f168](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/600f168172a9281a0061f84e4da5318e08762aa1))
+ - move SSPM base register definition to platform_def.h ([2a2b51d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2a2b51d8f76e2acdabb431e928beb90e0a30c87c))
+
+ - **MT8188**
+
+ - add mmap entry for CPU idle SRAM ([32071c0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/32071c0263899e0e7a4b7f2c754e6363547f33b1))
+ - refine c-state power domain for extensibility ([e35f4cb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e35f4cbf80ba671c42644c1ac7f8f6541042c6e5))
+ - refine gic init flow after system resume ([210ebbb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/210ebbb0a6a0520cb3a5930c4fefa94baee33462))
+
+ - **NXP**
+
+ - **i.MX**
+
+ - **i.MX 8M**
+
+ - correct serial output for HAB JR0 ([6e24d79](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6e24d795094e7fac1edc13336ce0bfd39d98e66f))
+ - fix dram retention fsp_table access ([6c8f523](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6c8f523138cd94bc0608708e821a09b02c8c2f5a))
+ - move caam init after serial init ([901d74b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/901d74b2d46cbd8b1d27477fa16388520fdabab1))
+ - update poweroff related SNVS_LPCR bits only ([ad6eb19](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ad6eb1951b986f30635025bbdf29e257b6b1e362))
+
+ - **i.MX 8Q**
+
+ - correct architected counter frequency ([21189b8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/21189b8e21062b71c9056ac1cf60d25bb018007c))
+
+ - **QEMU**
+
+ - enable SVE and SME ([337ff4f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/337ff4f1dd6604738d79fd3fa275ae74d74256b2))
+
+ - **QTI**
+
+ - adding secure rm flag ([b5959ab](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b5959ab029fb0a8a271967b0bd7ef438d59061bd))
+
+ - **Raspberry Pi**
+
+ - **Raspberry Pi 3**
+
+ - tighten platform pwr_domain_pwr_down_wfi behaviour ([028c4e4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/028c4e42d8f632d40081b88f66d0d05c7d7c9b23))
+
+ - **Renesas**
+
+ - **R-Car**
+
+ - **R-Car 3**
+
+ - fix RPC-IF device node name ([08ae247](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/08ae2471b1417f1d8083a79771338aa2a00b6711))
+
+ - **Rockchip**
+
+ - align fdt buffer on 8 bytes ([621acbd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/621acbd055d712ab8bf79054911155598fdb74d0))
+
+ - **RK3399**
+
+ - explicitly define the sys_sleep_flag_sram type ([7a5e90a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7a5e90a89d91d6662d3e468893e07c91b3a165ee))
+
+ - **Socionext**
+
+ - **Synquacer**
+
+ - increase size of BL33 ([a12a66d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a12a66d0d6d4732d41a27b1ecbc8874731c78101))
+
+ - **ST**
+
+ - add max size for FIP in eMMC boot part ([e7cb4a8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e7cb4a86b884d2922984d3cd4651fb905650cfd6))
+ - add missing string.h include ([0d33d38](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0d33d38334cae909a66c74187a36b5833afb8093))
+
+ - **STM32MP1**
+
+ - enable crash console in FIQ handler ([484e846](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/484e846a03a1af5f88e2e28835b6349cc5977935))
+ - fdts: stm32mp1: align DDR regulators with new driver ([9eed71b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9eed71b7221c5fc7ed887f1087e42c9f1a62f581))
+ - update the FIP load address for serial boot ([32f2ca0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/32f2ca04bfd2d93329f2f17d9c9d134f339710f9))
+
+ - **STM32MP13**
+
+ - correct USART addresses ([de1ab9f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/de1ab9fe052deba06a0904b10a6e0312ca49658e))
+
+ - **Xilinx**
+
+ - include missing header ([28ba140](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/28ba1400216d7c7195929d1bd53f059a440a89a2))
+ - miscellaneous fixes for xilinx platforms ([bfc514f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bfc514f10393fb7f4641ad5e75049f3acc246dd2))
+ - remove unnecessary header include ([0ee2dc1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0ee2dc118c34ceacc921fee196a4ba9102bdfbea))
+ - update define for ZynqMP specific functions ([24b5b53](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/24b5b53a5922de40e53f0a7ecf65d3d0acc30a0d))
+
+ - **Versal**
+
+ - add SGI register call version check ([5897e13](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5897e135445e2bf3345297fbe9971a113506d714))
+ - enable a72 erratum 859971 and 1319367 ([769446a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/769446a6899d840df8aa5746ec32bf7530fc9826))
+ - fix code indentation issues ([72583f9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/72583f92e6cc1d691b709e05c3ae280dce016fef))
+ - fix macro coding style issues ([80806aa](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/80806aa1234606bb55af40ae0667cdf4d44423be))
+ - fix Misra-C violations in bl31_setup and pm_svc_main ([68ffcd1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/68ffcd1bb22f2c2eac6c3329a1974b3e8ec6f515))
+ - remove clock related macros ([47f8145](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/47f8145324181b86b6f460fb0c92144ef43e4e14))
+ - resolve misra 10.1 warnings ([19f92c4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/19f92c4cfe014c5495f3073917119385b0014eda))
+ - resolve misra 15.6 warnings ([1117a16](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1117a16e0379986ea68581c02fb2fee40937452b))
+ - resolve misra 8.13 warnings ([3d2ebe7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3d2ebe756a50c27a00a03ae7f0109ed04681ac96))
+ - resolve the misra 4.6 warnings ([f7c48d9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f7c48d9e30e9444f1fdb808ae5d06ed675e335fa))
+ - resolve the misra 4.6 warnings ([912b7a6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/912b7a6fe46619e5df55dbd0b95d306f7bb2695c))
+ - route GIC IPI interrupts during setup ([04cc91b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/04cc91b43c1d10fcba563e18f06336987e6e3a24))
+ - use only one space for indentation ([dee5885](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/dee588591328b96d9b9ef908869c8b42bd2632f2))
+
+ - **Versal NET**
+
+ - Enable a78 errata workarounds ([bcc6e4a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bcc6e4a02a88056b9c45ff28f405e09444433528))
+ - add default values for silicon ([faa22d4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/faa22d48d9929d57975b84ab76cb595afdcf57f4))
+ - use api_id directly without FUNCID_MASK ([b0eb6d1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b0eb6d124b1764264778d17b1519bfe62b7b9337))
+
+ - **ZynqMP**
+
+ - fix coverity scan warnings ([1ac6af1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1ac6af1199e2d14492a9d75aaba69bc775e55bd8))
+ - ensure memory write finish with dsb() ([ac6c135](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ac6c135c83fe4efa4d6e9b9c06e899b57ce5647a))
+ - fix for incorrect afi write mask value ([4264bd3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4264bd33e718023c62a2776e3ca40db88fce8b08))
+ - move bl31 with DEBUG=1 back to OCM ([389594d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/389594dfa7e60a720d60f0d55296f91ba1610de5))
+ - move debug bl31 based address back to OCM ([0ba3d7a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0ba3d7a4ca04486f45d062fab54238d9a554a682))
+ - remove additional 0x in %p print ([05a6107](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/05a6107ff18b03f4ca33496268398133abf04aaa))
+ - resolve misra 4.6 warnings ([cdb6211](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cdb62114cfcdaeb85e64bcde459342a0a95f58e3))
+ - resolve misra 8.13 warnings ([8695ffc](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8695ffcfcb3801ea287fae7652ba1c350636831f))
+ - resolve MISRA-C:2012 R.10.1 warnings ([c889088](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c889088386432af69e3ca853825c4219884c1cc1))
+ - resolve the misra 4.6 warnings ([15dc3e4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/15dc3e4f8d9730ce58cc599fb9970d486c8b9202))
+ - resolve the misra 4.6 warnings ([ffa9103](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ffa910312c371080f4d0d50eb1354ad05b7be7a8))
+ - resolve the misra 8.6 warnings ([7b1a6a0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7b1a6a08ccc7522687f66e6e989bbc597d08ab06))
+
+- **Bootloader Images**
+
+ - **BL31**
+
+ - allow use of EHF with S-EL2 SPMC ([7c2fe62](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7c2fe62f1347bb94d82e9fdd3bc5eaebedaf0bc7))
+ - harden check in delegate_async_ea ([d435238](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d435238dc364f0c9f0e41661365f83d83899829d))
+ - pass the EA bit to 'delegate_sync_ea' ([df56e9d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/df56e9d199939c571b3fd8f539d213fc36e14494))
+
+- **Services**
+
+ - **RME**
+
+ - refactor RME fid macros ([fb00dc4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fb00dc4a7b208cf416d082bb4367b54286bc8e3b))
+ - relax RME compiler requirements ([7670ddb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7670ddb1fb5d4fa5e2e234375f7a4c0763f1c57a))
+ - update FVP platform token ([364b4cd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/364b4cddbab859a56e63813aab4e983433187191))
+ - use RMM shared buffer for attest SMCs ([dc65ae4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/dc65ae46439f4d1be06e3a016fe76319d7a62954))
+ - xlat table setup fails for bl2 ([e516ba6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e516ba6de5e248e93156b5261cedbff811226e0e))
+
+ - **RMMD**
+
+ - return X4 output value ([8e51ccc](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8e51cccaefc1e0e79ac2f0667ffec1cc46cf7665))
+
+ - **SPM**
+
+ - **EL3 SPMC**
+
+ - check descriptor size for overflow ([eed15e4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/eed15e4310a7bcd90bf6d66b00037e05186329bb))
+ - compute full FF-A V1.1 desc size ([be075c3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/be075c3edf634a2df1065597266c3e41d284287b))
+ - deadlock when relinquishing memory ([ac568b2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ac568b2bccb9da71f2bd7f1c7204189d1ff678d9))
+ - error handling in allocation ([cee8bb3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cee8bb3b38ea266a5008719548965352ec695cae))
+ - fix detection of overlapping memory regions ([0dc3518](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0dc35186669ddaedb3a932e103c3976bc3bf75d6))
+ - fix incomplete reclaim validation ([c4adbe6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c4adbe6e67617bb2d4f0ffb1c1daa3395f7ac227))
+ - fix location of fragment length check ([21ed9ea](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/21ed9ea32325fc556fa7e907e4995888bd3a3b45))
+ - fix relinquish validation check ([b4c3621](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b4c3621e0dc8e7ec6d3229253e0326f12c8fe5a9))
+
+- **Libraries**
+
+ - **CPU Support**
+
+ - fix cpu version check for Neoverse N2, V1 ([03ebf40](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/03ebf409c711e9f2006cedded7dc415dfe566975))
+ - workaround for Cortex-A510 erratum 2666669 ([afb5d06](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/afb5d069a6fa049f18e90fa50e714b8a4acc55f4))
+ - workaround for Cortex-A710 2216384 ([b781fcf](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b781fcf139c3a609f1adffb8097a23eadbed53a9))
+ - workaround for Cortex-A710 erratum 2291219 ([888eafa](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/888eafa00b99aa06b4ff688407336811a7ff439a))
+ - workaround for Cortex-A76 erratum 2743102 ([4927309](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/49273098a5ccd87a2084a85f9e47d74fa3ecfc90))
+ - workaround for Cortex-A77 erratum 2743100 ([4fdeaff](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4fdeaffe860a998e8503b847ecceec60dcddcdc5))
+ - workaround for Cortex-A78C erratum 2376749 ([5d3c1f5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5d3c1f58905d3b7350e02c4687dceaf0971700b3))
+ - workaround for Cortex-X3 erratum 2313909 ([7954412](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/79544126943a90d31d81177655be11f75330ffed))
+ - workaround for Neoverse N1 erratum 2743102 ([8ce4050](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8ce40503ad00fe0dd35de6e51551da2b4f08a848))
+ - workaround for Neoverse-N2 erratum 2326639 ([43438ad](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/43438ad1ad6651964e9ae75d35f40aed8d86d088))
+ - workaround for Neoverse-N2 erratum 2388450 ([884d515](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/884d515625aa09b22245c32db2fcc9222c7f34fd))
+ - workaround for Cortex A78C erratum 2242638 ([6979f47](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6979f47fecfd34ac1405117c23f2e36ecb552a20))
+ - workaround for Cortex-A510 erratum 2347730 ([11d448c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/11d448c93463180d03b46e9ba204124ff7ad5116))
+ - workaround for Cortex-A510 erratum 2371937 ([a67c1b1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a67c1b1b2b521c888790c68e4201ecce0836a0e9))
+ - workaround for Cortex-A710 erratum 2147715 ([3280e5e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3280e5e655ad64b6e299e18624d9c586e6b37cb1))
+ - workaround for Cortex-A710 erratum 2371105 ([3220f05](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3220f05ef900addccb6e444d6746e4ed28c9804f))
+ - workaround for Cortex-A77 erratum 2356587 ([7bf1a7a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7bf1a7aaaa41034587e43d5805b42da83090b85b))
+ - workaround for Cortex-A78C 2132064 ([8008bab](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8008babd58f60c91a88ad79df3d32f63596b433a))
+ - workaround for Cortex-A78C erratum 2395411 ([4b6f002](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4b6f0026ea2622b3f46cdef5b468853ddd281b39))
+ - workaround for Cortex-X2 erratum 2371105 ([bc0f84d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bc0f84de40d4f1efddfb50071fff09d32f0ea9b2))
+ - workaround for Neoverse-N2 erratum 2376738 ([e6602d4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e6602d4b153b81b49b39c22e70f052f9018687b7))
+ - workaround for Neoverse-V1 erratum 1618635 ([14a6fed](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/14a6fed5ac14035f578a75a9758f9df7ba4d7496))
+ - workaround for Neoverse-V1 erratum 2294912 ([39eb5dd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/39eb5ddbbf98bdb6c012a9d852f489f2f8e15c05))
+ - workaround for Neoverse-V1 erratum 2372203 ([57b73d5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/57b73d553305d89da7098f9b53b0a2356ca7ff8b))
+
+ - **EL3 Runtime**
+
+ - **RAS**
+
+ - restrict RAS support for NS world ([46cc41d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/46cc41d5592a16f702f7f0c0c41f8948a3e11cda))
+ - trap "RAS error record" accesses only for NS ([00e8f79](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/00e8f79c15d36f65f6c7f127177105e02177cbc0))
+
+ - **FCONF**
+
+ - fix type error displaying disable_auth ([381f465](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/381f465ca92f7c9759e85c1bfb4c95ceda26581e))
+
+ - **PSCI**
+
+ - fix MISRA failure - Memory - illegal accesses ([0551aac](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0551aac5637a638d4b9d8865a2c20ec5153de3bf))
+
+ - **GPT**
+
+ - correct the GPC enable sequence ([14cddd7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/14cddd7a58799c8a9d349a4adc0136c1ab5d0b6c))
+
+ - **C Standard Library**
+
+ - pri*ptr macros for aarch64 ([d307229](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d307229d754ae4d833ed50be50420aaf070065bf))
+
+ - **PSA**
+
+ - fix Null pointer dereference error ([c32ab75](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c32ab75c41adfe28a60f1ff159012a7d78e72fdc))
+ - update measured boot handle ([4d879e1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4d879e1e5a40cefae5b5e13086a16741bf3f6d67))
+ - add missing semicolon ([d219ead](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d219ead1db5ca02ec7c7905ac01d7b268c5026ae))
+ - align with original API in tf-m-extras ([471c989](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/471c9895a630560561717067113e4c4d7127bb9f))
+ - extend measured boot logging ([901b0a3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/901b0a3015a652d9eb66c063b0984fade9adf08f))
+
+ - **Context Management**
+
+ - remove explicit ICC_SRE_EL2 register read ([2b28727](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2b28727e6dafdaa08a517b5a97bda5de26cc8919))
+
+ - **Semihosting**
+
+ - fix seek call failure check ([7c49438](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7c4943887477754024f0f736461d9543d502efcc))
+
+- **Drivers**
+
+ - **Authentication**
+
+ - correct sign-compare warning ([ed38366](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ed38366f1dfeb0b0789fd69b400728598ae3c64e))
+
+ - **Measured Boot**
+
+ - add SP entries to event_log_metadata ([e637a5e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e637a5e19da72599229fd2c70e793c123aaf14ca))
+ - clear the entire digest array of Startup Locality event ([70b1c02](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/70b1c025003452602f68feb13402c705e44145aa))
+ - fix verbosity level of RSS digests traces ([2abd317](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2abd317d27a26bbfa3da7fe3fe709da3fa0f09af))
+
+ - **MMC**
+
+ - remove broken, unsecure, unused eMMC RPMB handling ([86b015e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/86b015eb1be57439c2a01cb35d800c7f1b5c8467))
+ - resolve the build error ([ccf8392](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ccf8392ccb105638fe710901d3c7ed6594d9450e))
+
+ - **SCMI**
+
+ - base: fix protocol list querying ([cad90b5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cad90b569db7c547470cca922bd93207adcadfad))
+ - base: fix protocol list response size ([d323f0c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d323f0cf000f1d999bf78d89c0037af76b6bf8d8))
+
+ - **UFS**
+
+ - add retries to ufs_read_capacity ([28645eb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/28645ebd706fe6ac9f34db9f7be5657fe4cffc1a))
+ - fix slot base address computation ([7d9648d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7d9648dd6cf3b1dcd90b6917d9d0b545b1c4c975))
+ - init utrlba/utrlbau with desc_base ([9d6d1a9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9d6d1a94c99c3a0e89792c5cc118a1d8c8a9dbb7))
+ - point utrlbau to header instead of upiu ([9d3f6c4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9d3f6c4b6068b3a4747f5d1dc650607876eff583))
+ - removes dp and run-stop polling loops ([660c208](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/660c208d9bd2770f295005fc26a9b6f788567f41))
+ - retry commands on unit attention ([3d30955](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3d309556c75bcdb59fd4e4178fa2b79aa472dc90))
+
+ - **Arm**
+
+ - **GIC**
+
+ - **GICv3**
+
+ - fix overflow caused by left shift ([6aea762](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6aea7624a01cc39c19d4237c4b108659270a61c5))
+ - update the affinity mask to 8 bit ([e689048](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e689048e20af70983e0d384301c408fc725cb5eb))
+
+ - **GIC-600**
+
+ - implement workaround to forward highest priority interrupt ([e1b15b0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e1b15b09a530f2a0b0edc4384e977452d6b389eb))
+
+ - **RSS**
+
+ - clear the message buffer ([e3a6fb8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e3a6fb84f523e68d2f1398348d1ae2635f3e57bc))
+ - determine the size of sw_type in RSS mboot metadata ([2c8f2a9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2c8f2a9ad45023354516d419dc9fda2a4f02812b))
+ - fix build issues with comms protocol ([ab545ef](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ab545efddcdbf5d08ad3b1e8f4ea15a0faf168a7))
+ - reduce input validation for measured boot ([13a129e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/13a129e8dcea358033f3c83b2d81b25129e02d43))
+ - remove dependency on attestation header ([6aa7154](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6aa71542f35047ea0b537e3a6016de6c579c9d6b))
+ - rename AP-RSS message size macro ([70247dd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/70247ddbbd0a55a1ddf1d02f2a35b5cad3949dd1))
+
+ - **NXP**
+
+ - **DDR**
+
+ - fix firmware buffer re-mapping issue ([742c23a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/742c23aab79a21803472c5b4314b43057f1d3e84))
+
+ - **ST**
+
+ - **Clock**
+
+ - correct MISRA C2012 15.6 ([56f895e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/56f895ede3a2a4a97c0e4f8270050aff20a167bc))
+ - correctly check ready bit ([3b06a53](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3b06a53044e754979cb0608fd93a137a5879a6a0))
+
+- **Miscellaneous**
+
+ - **AArch64**
+
+ - make AArch64 FGT feature detection more robust ([c687776](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c6877763cd3a286983df160c8207368174c1b820))
+
+ - **Debug**
+
+ - backtrace stack unwind misses lr adjustment ([a149eb4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a149eb4d87453f58418ad32c570090739a3e0dd6))
+ - decouple "get_el_str()" from backtrace ([0ae4a3a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0ae4a3a3f0cd841b83f2944dde9837ea67f08813))
+
+ - **FDTs**
+
+ - **STM32MP1**
+
+ - **STM32MP13**
+
+ - align sdmmc pins with kernel ([c7ac7d6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c7ac7d65a7d1ee1b656bf1260ede6b8e2226bbac))
+ - cleanup DT files ([4c07deb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4c07deb53e0e7daafc93bc67fdcbb3de7b73d730))
+ - correct PLL nodes name ([93ed4f0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/93ed4f0801f5b3571abdd7e039d09d508c987063))
+ - remove secure status ([8ef8e0e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8ef8e0e30e301e6b2595d571f004ae86b1a1ce06))
+ - update SDMMC max frequency ([c9a4cb5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c9a4cb552cdd168fcab2c0383b8fbe30dc99092f))
+
+ - **Security**
+
+ - optimisations for CVE-2022-23960 ([e74d658](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e74d658181e5e69b6b5e16b40adc1ffef4c1efb9))
+
+- **Documentation**
+
+ - document missing RMM-EL3 runtime services ([e50fedb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e50fedbc869341d044d4cb3479a0ab3d4edaf225))
+ - add LTS maintainers ([ab0d4d9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ab0d4d9d44fe54535a0ae647092a3cfff368f126))
+ - update maintainers list ([f23ce63](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f23ce639050481cda939b9e4738ed01d46481ee3))
+
+ - **Changelog**
+
+ - fix the broken link to commitlintrc.js ([c1284a7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c1284a7f93309c88fd781d2b4720f742e147284e))
+
+- **Build System**
+
+ - disable default PIE when linking ([7b59241](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7b5924184566bcdcc01966905ffdcabcd6ea4b32))
+ - discard sections also with SEPARATE_NOBITS_REGION ([64207f8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/64207f858f5cbf44aa6528be19a863acc4444568))
+ - ensure that the correct rule is called for tools ([598b166](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/598b166bbc2f09fc219d44ecff0c870854bfa093))
+ - fix arch32 build issue for clang ([94eb127](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/94eb127719881f39c7f235c887fb2c0b82341696))
+ - make TF-A use provided OpenSSL binary ([e95abc4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e95abc4c01822ef43e9e874d63d6596dc0b57279))
+
+- **Tools**
+
+ - **Secure Partition Tool**
+
+ - fix concurrency issue for SP packages ([0aaa382](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0aaa382fe2395c82c9491b199b6b82819afd368f))
+ - operators "is/is not" in sp_mk_gen.py ([1a28f29](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1a28f290b8224eb1d78a2476faaedc5154f82208))
+ - 'sp_mk_generator.py' reference to undef var ([0be2475](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0be2475f6990a37d2d54b7ed06bac9cb46f4660d))
+
+- **Dependencies**
+
+ - add missing aeabi_memcpy.S ([93cec69](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/93cec697deb654303379cae8f25a31dc8b90cd31))
+
+## [2.7.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/v2.6..refs/tags/v2.7.0) (2022-05-20)
+
+### New Features
+
+- **Architecture**
+
+ - **Statistical profiling Extension (FEAT_SPE)**
+
+ - add support for FEAT_SPEv1p2 ([f20eb89](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f20eb893a072bb9b404eedb886e8c65fe76ffb45))
+
+ - **Branch Record Buffer Extension (FEAT_BRBE)**
+
+ - add BRBE support for NS world ([744ad97](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/744ad97445ce7aa65adaef376d0b5bafc12a90d3))
+
+ - **Extended Cache Index (FEAT_CCIDX)**
+
+ - update the do_dcsw_op function to support FEAT_CCIDX ([d0ec1cc](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d0ec1cc437c59e64ecba44710dbce82a04ff892d))
+
+- **Platforms**
+
+ - add SZ_* macros ([1af59c4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1af59c457010e6e3e6536752736eb02115bca543))
+
+ - **Allwinner**
+
+ - add SMCCC SOCID support ([436cd75](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/436cd754f2b0f9c0ce3094961bd1e179eeff2fc1))
+ - allow to skip PMIC regulator setup ([67412e4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/67412e4d7ae3defaac78ef5e351c63e06cfd907a))
+ - apx803: add aldo1 regulator ([a29f6e7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a29f6e76cbf76d509c00f84f068b59864d210dfd))
+ - choose PSCI states to avoid translation ([159c36f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/159c36fd2fc5afbe979e5028b9e845ed4b7a40f1))
+ - provide CPU idle states to the rich OS ([e2b1877](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e2b18771fc2a0528dda18dbdaac08dd8530df25a))
+ - simplify CPU_SUSPEND power state encoding ([52466ec](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/52466ec38ef312da62ad062720a03a183329f831))
+
+ - **Arm**
+
+ - **FVP**
+
+ - measure critical data ([cf21064](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cf21064ec8a1889f64de48e30e38285227d27745))
+ - update HW_CONFIG DT loading mechanism ([39f0b86](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/39f0b86a76534d0b7c71dd0c8b34f1a74480386b))
+ - enable RSS backend based measured boot ([c44e50b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c44e50b72567205650c6455f3a258f36af0c84dd))
+
+ - **Morello**
+
+ - add changes to enable TBBR boot ([4af5397](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4af53977533bee7b5763d3efad1448545c2ebef7))
+ - add DTS for Morello SoC platform ([572c8ce](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/572c8ce255397f7cff9640676e510817a8e4c6a3))
+ - add support for nt_fw_config ([6ad6465](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6ad6465e5ce452688cac079f16d26f64e9f4ce3c))
+ - add TARGET_PLATFORM flag ([8840711](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8840711f33131969ec6b62ca3da079cf0573ac8b))
+ - configure DMC-Bing mode ([9b8c431](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9b8c431e2b2d656da7f8c4158e3d32e104446fec))
+ - expose scmi protocols in fdts ([87639aa](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/87639aab0b6a30d4f49d069c0ea06900b11072a6))
+ - split platform_info sds struct ([4a7a9da](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4a7a9dafbc953089957a0cc1a7183731a5b003e1))
+ - zero out the DDR memory space ([2d39b39](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2d39b39704c1e4f2a189543ac4ff05ae58e5f5c8))
+
+ - **N1SDP**
+
+ - add support for nt_fw_config ([cf85030](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cf85030efe73439e06295f8185b0a6bebf7b5eae))
+ - enable trusted board boot on n1sdp ([fe2b37f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fe2b37f6858168a56c3d393bc72f560468d02165))
+
+ - **RD**
+
+ - **RD-N2**
+
+ - add board support for rdn2cfg2 variant ([efeb438](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/efeb43808d2e3ed23e1d51d5e86460db92971e96))
+ - add support for rdedmunds variant ([ef515f0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ef515f0d3466a8beded4fd662718abbd97391b13))
+
+ - **SGI**
+
+ - add page table translation entry for secure uart ([33d10ac](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/33d10ac8bf134519f303fd7ce5fb5d583be2f515))
+ - deviate from arm css common uart related definitions ([f2cccca](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f2ccccaa81ec14a80fedb48c37226e5d852ada7a))
+ - enable fpregs context save and restore ([18fa43f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/18fa43f753b79cfc3cc5426a3ef50b04efbf6206))
+ - route TF-A logs via secure uart ([987e2b7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/987e2b7c20eb4ab4215ff5289b715300f5cec054))
+
+ - **TC**
+
+ - add reserved memory region for Gralloc ([ad60a42](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ad60a42cd79713984065dca8540c091c49755f32))
+ - enable CI-700 PMU for profiling ([fbfc598](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fbfc59840f9cd0ea53921c7f6fb9f4850a3b42ee))
+ - enable GPU ([82117bb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/82117bb48180175c25936b0ff9e33563e25e18f4))
+ - enable SMMU for DPU ([4a6ebee](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4a6ebeeca37ece34a58982c8b6ebdc8cfd70814b))
+ - enable tracing ([59da207](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/59da207e2f2f028c9051c89bc5a05e95d996c18c))
+
+ - **Corstone-1000**
+
+ - identify bank to load fip ([cf89fd5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cf89fd57ed3286d7842eef41cd72a3977eb6d317))
+ - implement platform specific psci reset ([a599c80](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a599c80d063975cbeedbc86cfb619fca8545c487))
+ - made changes to accommodate 3MB for optee ([854d1c1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/854d1c103a9b73bbde7ef1b89b06b29e3cc053bb))
+
+ - **Intel**
+
+ - add macro to switch between different UART PORT ([447e699](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/447e699f70f1a1d1b85a8136b445eba689166c5d))
+ - add RSU 'Max Retry' SiP SMC services ([4c26957](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4c26957be253a7ab3acb316f42bf3ee10c409ed2))
+ - add SiP service for DCMF status ([984e236](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/984e236e0dee46708534a23c637271a931ceb67e))
+ - add SMC for enquiring firmware version ([c34b2a7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c34b2a7a1a38dba88b6b668a81bd07c757525830))
+ - add SMC support for Get USERCODE ([93a5b97](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/93a5b97ec9e97207769db18ae34886e6b8bf2ea4))
+ - add SMC support for HWMON voltage and temp sensor ([52cf9c2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/52cf9c2cd4882534d02e8996e4ff1143ee59290e))
+ - add SMC support for ROM Patch SHA384 mailbox ([77902fc](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/77902fca8fe7449473b09198e1fe197f7b4765d7))
+ - add SMC/PSCI services for DCMF version support ([44eb782](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/44eb782e15c9af532f2455b37bd53ca93830f6e2))
+ - add SMPLSEL and DRVSEL setup for Stratix 10 MMC ([bb0fcc7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bb0fcc7e011ec4319a79734ba44353015860e39f))
+ - add support for F2S and S2F bridge SMC with mask to enable, disable and reset bridge ([11f4f03](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/11f4f03043ef05762f4d6337804c39dc8f9af54f))
+ - allow to access all register addresses if DEBUG=1 ([7e954df](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7e954dfc2ba83262f7596dd0f17de75163e49e5e))
+ - create source file for firewall configuration ([afa0b1a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/afa0b1a82a404c616da2da8f52cdcd587938955f))
+ - enable firewall for OCRAM in BL31 ([ae19fef](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ae19fef33707700a91b0b672aa784e084a6ca500))
+ - enable SMC SoC FPGA bridges enable/disable ([b7f3044](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b7f3044e8725d9af997999547630892cf9e2f0ad))
+ - extend attestation service to Agilex family ([581182c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/581182c1916df03860744d8e32941c72b2cc3fda))
+ - implement timer init divider via cpu frequency. ([#1](https://review.trustedfirmware.org:29418/TF-A/trusted-firmware-a/issues/1)) ([f65bdf3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f65bdf3a54eed8f7651761c25bf6cc7437f4474b))
+ - initial commit for attestation service ([d174083](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d17408316db10db611e23716e8a5b9b9f53ad509))
+ - single certificate feature enablement ([7facace](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7facacec6328e505b243a4974d045d45fe068afd))
+ - support AES Crypt Service ([6726390](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6726390eb02e9659cfaf2d3598be9bf12fbc5901))
+ - support crypto service key operation ([342a061](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/342a0618c7ff89327ac5b34dc0713509ffae609b))
+ - support crypto service session ([6dc00c2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6dc00c24ab0100a2aae0f416c72470f8ed17e149))
+ - support ECDH request ([4944686](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/49446866a515c2db855d456f39df3d586b2084b7))
+ - support ECDSA Get Public Key ([d2fee94](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d2fee94afa6ba7e76508e6bead7eb2936c5eafb8))
+ - support ECDSA HASH Signing ([6925410](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/692541051b8cb0f435ae46c5d7351231ee292319))
+ - support ECDSA HASH Verification ([7e25eb8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7e25eb87016ba8355cf0a3a5f71fb8b8785de044))
+ - support ECDSA SHA-2 Data Signature Verification ([5830506](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/583050607e43cef8b544a5700386a019e54c422f))
+ - support ECDSA SHA-2 Data Signing ([07912da](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/07912da1b7663451493fb5e40e4c33deeb18a639))
+ - support extended random number generation ([24f9dc8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/24f9dc8a43fea350416ca9312a78ab4e786da8ad))
+ - support HMAC SHA-2 MAC verify request ([c05ea29](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c05ea2969070be90a7dbb2d0344c66d89401edf6))
+ - support session based SDOS encrypt and decrypt ([537ff05](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/537ff052579862a4865d36d06940feaa796d16da))
+ - support SHA-2 hash digest generation on a blob ([7e8249a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7e8249a2dbacfa751990c47644f0403311c6e260))
+ - support SiP SVC version ([f0c40b8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f0c40b897f8a25bc50c53239dcf750dd395ebabf))
+ - support version 2 SiP SVC SMC function ID for mailbox commands ([c436707](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c436707bc6eed31ab61408ef40db6063d05f0912))
+ - support version 2 SiP SVC SMC function ID for non-mailbox commands ([ad47f14](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ad47f1422f3f9aa4a622e08b71fc8f5caab98a98))
+ - update to support maximum response data size ([b703fac](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b703facaaae1e3fe5afa4742b436bb07e065b5e9))
+
+ - **Marvell**
+
+ - **Armada**
+
+ - **A3K**
+
+ - add north and south bridge reset registers ([a4d35ff](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a4d35ff381c625d61bcc22f9f9a1a45d8663b19d))
+
+ - **MediaTek**
+
+ - introduce mtk makefile ([500d40d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/500d40d877617653d347fb6308144973d4297ab9))
+
+ - **MT8195**
+
+ - apply erratas of CA78 for MT8195 ([c21a736](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c21a736d6f3fa9fb0647bff404b0174ebf1acd91))
+ - add EMI MPU surppot for SCP and DSP ([690cb12](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/690cb1265ea84851bd6405a0a6a57d2f1c9f03a3))
+ - dump EMI MPU configurations ([20ef588](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/20ef588e86ad8f3cf13382c164463046db261feb))
+ - improve SPM wakeup log ([ab45305](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ab45305062f50f81e5c3f800ef4c6cef5097cb04))
+
+ - **MT8186**
+
+ - add DFD control in SiP service ([e46e9df](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e46e9df0d0e05f2aaee613fc4f697fcc8d79c0b3))
+ - add SPM suspend driver ([7ac6a76](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7ac6a76c47d429778723aa804b64c48220a10f11))
+ - add Vcore DVFS driver ([635e6b1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/635e6b108e773daf37c00f46e6fbb1cae4e78f96))
+ - disable 26MHz clock while suspending ([9457cec](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9457cec8c02f78ba56fd9298dd795766c89281a2))
+ - initialize platform for MediaTek MT8186 ([27132f1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/27132f13ca871dc3cf1aa6938995284cf5016e00))
+ - add power-off function for PSCI ([a68346a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a68346a772859ee6971ec14c6473d2a853e9c66f))
+ - add CPU hotplug ([1da57e5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1da57e54b2270b3b49710afa6fd947b01d61b261))
+ - add DCM driver ([95ea87f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/95ea87ffc2445c77f070e6a2f78ffa424810faed))
+ - add EMI MPU basic driver ([1b17e34](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1b17e34c5d7740a357b2027d88aef7760b346616))
+ - add MCDI drivers ([06cb65e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/06cb65ef079941d0525dca75dd0e110e9330906d))
+ - add pinctrl support ([af5a0c4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/af5a0c40aff21c4b8771365f19dcb01d6086b30d))
+ - add pwrap and pmic driver ([5bc88ec](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5bc88ec61c75ed42b41d84817aa4d6ee68a2efc8))
+ - add reboot function for PSCI ([24dd5a7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/24dd5a7b71544c503446e58cb23c0cfd09245a3c))
+ - add RTC drivers ([6e5d76b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6e5d76bac8786120d037953f5a6fd67aaff035c1))
+ - add SiP service ([5aab27d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5aab27dc4294110a6c0b69bf5ec5343e7df883a7))
+ - add sys_cirq support ([109b91e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/109b91e38c8d4f73941c8574759560a1f1636d05))
+ - apply erratas for MT8186 ([572f8ad](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/572f8adbb062c36835fbb82944dd2ed772134bfd))
+ - initialize delay_timer ([d73e15e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d73e15e66a33398c8fc51c83f975a3f35494faf5))
+ - initialize GIC ([206f125](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/206f125cc177bc110eb87d40ffc7fa18b28c01ce))
+ - initialize systimer ([a6a0af5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a6a0af57c3369dfc6fc2f25877d812a24e9be311))
+
+ - **NXP**
+
+ - add SoC erratum a008850 ([3d14a30](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3d14a30b88762e901e134acc89c6ac4fa9e3f321))
+ - add ifc nor and nand as io devices ([b759727](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b759727f5936a687314168dd8912d30897a8c6be))
+ - add RCPM2 registers definition ([d374060](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d374060abe9b63296f63f1e3c811aeeddb7a093c))
+ - add CORTEX A53 helper functions ([3ccc8ac](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3ccc8ac3e5da48819a2fc90ec48a175515de38cb))
+
+ - **i.MX**
+
+ - **i.MX 8M**
+
+ - add a simple csu driver for imx8m family ([71c40d3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/71c40d3bb7c90a6c36d5c49d0830ca95aba65a2f))
+ - add imx csu/rdc enum type defines for imx8m ([0c6dfc4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0c6dfc47847608b6ade0c00716e93afc6725362c))
+ - enable conditional build for SDEI ([d2a339d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d2a339dfa1665edf87a30a4318af954e764c205c))
+ - enable the coram_s tz by default on imx8mn/mp ([d5ede92](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d5ede92d78c829d8a3adad0759219b79e0dc0707))
+ - enable the csu init on imx8m ([0a76495](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0a76495bc2cb0c5291027020a3cd2d3adf31c8ed))
+ - do not release JR0 to NS if HAB is using it ([77850c9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/77850c96f23bcdc76ecb0ecd27a982c00fde5d9d))
+ - switch to xlat_tables_v2 ([4f8d5b0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4f8d5b018efc42d1ffa76fca8efb0d16a57f5edd))
+
+ - **i.MX 8M Mini**
+
+ - enable optee fdt overlay support ([9d0eed1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9d0eed111cb1294605b6d82291fef16a51d35e46))
+ - enable Trusty OS on imx8mm ([ff3acfe](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ff3acfe3cc1658917376152913a9d1b5b9b8de34))
+ - add support for measured boot ([cb2c4f9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cb2c4f93c18b948fbfde9d50ab7d30362be0e00a))
+
+ - **i.MX 8M Plus**
+
+ - add trusty for imx8mp ([8b9c21b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8b9c21b480dd5c3265be1105a9462b3f5657a6b1))
+ - enable BL32 fdt overlay support on imx8mp ([aeff146](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/aeff14640a91f6d33bfdbc0dc7b0e920f6d14b91))
+
+ - **i.MX 8M Nano**
+
+ - enable optee fdt overlay support ([2612891](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/26128912884b26fab67bce9d87ba0e1c85a0be1e))
+ - enable Trusty OS for imx8mn ([99349c8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/99349c8ecba910dabbaa72b9be91f3ed762036f5))
+
+ - **i.MX 8M Q**
+
+ - enable optee fdt overlay support ([023750c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/023750c6a898e77c185839f5e56f8e23538f718a))
+ - enable trusty for imx8mq ([a18e393](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a18e393339e1d481f4fdf0d621fe4f39ce93a4fe))
+
+ - **Layerscape**
+
+ - add CHASSIS 3 support for tbbr ([9550ce9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9550ce9ddd7729a961f51ed61ea4b2030e284dcb))
+ - add new soc errata a009660 support ([785ee93](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/785ee93cc3bd9b43d88fee5acefbd131bf6f2756))
+ - add new soc errata a010539 support ([85bd092](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/85bd0929433875e0b84fdc2046d9ec2cf0164903))
+ - add soc helper macro definition for chassis 3 ([602cf53](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/602cf53b6f507cea88f4af5c07bed9325bc7a9b8))
+ - define more chassis 3 hardware address ([0d396d6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0d396d6455a659c4e679f02fae1f9043713474b0))
+ - print DDR errata information ([3412716](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3412716b30260958b30d1fa2e1c6d8cce195cd7d))
+
+ - **LS1043A**
+
+ - add ls1043a soc support ([3b0de91](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3b0de9182501fae9de372efd1faaf35a7bf74f68))
+
+ - **LS1043ARDB**
+
+ - add ls1043ardb board support ([e4bd65f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e4bd65fed8a12d06181c1343cf786ac91badb6b0)
+
+ - **LX2**
+
+ - enable DDR erratas for lx2 platforms ([cd960f5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cd960f5009ee062bba9c479505caee6bbe644649))
+
+ - **LS1046A**
+
+ - add new SoC platform ls1046a ([cc70859](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cc708597fa72094c5a01df60e6538e4a7429c2a0))
+
+ - **LS1046ARDB**
+
+ - add ls1046ardb board support ([bb52f75](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bb52f7560b62043ed08a753f399dc80e8c1582d3))
+
+ - **LS1046AFRWY**
+
+ - add ls1046afrwy board support ([b51dc56](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b51dc56ab9ea79e4709f0d0ce965525d0d3da918))
+
+ - **LS1046AQDS**
+
+ - add board ls1046aqds support ([16662dc](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/16662dc40dd2578d3000528ece090ed39ed18b9c))
+
+ - **LS1088A**
+
+ - add new SoC platform ls1088a ([9df5ba0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9df5ba05b4fe4cd44157363a897b73553ba6e2f1))
+
+ - **LS1088ARDB**
+
+ - add ls1088ardb board support ([2771dd0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2771dd0293b6cda6811e8bed95f2354a3ee0124e))
+
+ - **LS1088AQDS**
+
+ - add ls1088aqds board support ([0b0e676](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0b0e67669814139c6818e61e03d0d0e3314fdc99))
+
+ - **QEMU**
+
+ - add SPMD support with SPMC at S-EL1 ([f58237c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f58237ccd9fd2350730d60ab7de59b5c376bfb35))
+ - add support for measured boot ([5e69026](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5e690269d579d9461be3c5f5e3f59d4c666863a0))
+
+ - **QTI**
+
+ - **MSM8916**
+
+ - allow booting secondary CPU cores ([a758c0b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a758c0b65c6730fb07846899d6436ba257484d34))
+ - initial platform port ([dddba19](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/dddba19a6a3cb7a1039beaffc3169c4eb3291afd))
+ - setup hardware for non-secure world ([af64473](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/af6447315c8534331513ca6b6556af661e0ba88b))
+
+ - **Renesas**
+
+ - **R-Car**
+
+ - **R-Car 3**
+
+ - modify sequence for update value for WUPMSKCA57/53 ([d9912cf](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d9912cf3d1022fc6d38a6059290040985de56e63))
+ - modify type for Internal function argument ([ffb725b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ffb725be98ffd010c851629a6da75bf57f770c7f))
+ - update IPL and Secure Monitor Rev.3.0.3 ([14d9727](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/14d9727e334300b3f5f57e76a9f6e21431e6c6b5))
+
+ - **ST**
+
+ - add a function to configure console ([53612f7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/53612f72938f37244a5f10ae7c57abe7358c221f))
+ - add STM32CubeProgrammer support on UART ([fb3e798](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fb3e7985c9b657c535c02b722ecc413f643e671e))
+ - add STM32MP_UART_PROGRAMMER target ([9083fa1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9083fa11ead67272b94329e8f84257de6658620d))
+ - add early console in BL2 ([c768b2b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c768b2b22f4fb16cf8be8b4815a1984b29918c20))
+ - disable authentication based on part_number ([49abdfd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/49abdfd8cececb91a4bc7e7b29a30c09dce461c7))
+ - get pin_count from the gpio-ranges property ([d0f2cf3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d0f2cf3b148df75d5cbbd42dfa18012043e5d1f4))
+ - map 2MB for ROM code ([1697ad8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1697ad8cc81307972d31cec3b27d58f589eeeb3f))
+ - protect UART during platform init ([acf28c2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/acf28c267b3679a0770b2010f2ec3fb3c2d19975))
+ - update stm32image tool for header v2 ([2d8886a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2d8886aceed613b9be25f20900914cacc8bb0fb9))
+ - update the security based on new compatible ([812daf9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/812daf916c9c977a4f6d7d745d22b90c8492fc71))
+ - use newly introduced clock framework ([33667d2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/33667d299bd5398ca549f542345e0f321b483d17))
+
+ - **ST32MP1**
+
+ - adaptations for STM32MP13 image header ([a530874](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a5308745ee3ab3b77ca942052e60968bcc01340d))
+ - add "Boot mode" management for STM32MP13 ([296ac80](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/296ac8012b77ea84079b38cc60ee786a5f91857f))
+ - add a second fixed regulator ([225ce48](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/225ce4822ccf2e7c7c1fca6cf3918d4399158613))
+ - add GUID values for updatable images ([8d6b476](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8d6b4764f3e54431c3d01342d39d1efa70c3dbf9))
+ - add GUID's for identifying firmware images to be booted ([41bd8b9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/41bd8b9e2ad3b755505684601f07d4f7f8ec04c4))
+ - add helper to enable high speed mode in low voltage ([dea02f4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/dea02f4eaed855c2f05d8a1d7eefca313e98e5b4))
+ - add logic to pass the boot index to the Update Agent ([ba02add](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ba02add9ea8fb9a8b0a533c1065a77c7dda4f2a6))
+ - add logic to select the images to be booted ([8dd7553](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8dd755314fdfa077465bd6cd5e248be392d90378))
+ - add NVMEM layout compatibility definition ([dfbdbd0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/dfbdbd0625990267c6742268118ea748e77c6123))
+ - add part numbers for STM32MP13 ([30eea11](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/30eea116cdd66b3fa1e1208e185eb7285a83d898))
+ - add regulator framework compilation ([bba9fde](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bba9fdee589fb9a7aca5963f53b7ce67c30520b3))
+ - add sdmmc compatible in platform define ([3331d36](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3331d3637c295993a78f22afe7463cf1c334d329))
+ - add sign-compare warning ([c10f3a4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c10f3a4559ebf7a654a9719fec619e81e6ee1d69))
+ - add stm32_get_boot_interface function ([a6bfa75](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a6bfa75cf25241a486ab371ae105ea7ebf2d34d8))
+ - add support for building the FWU feature ([ad216c1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ad216c106682f1d2565b2a08e11a601b418dc8a4))
+ - add support for reading the metadata partition ([0ca180f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0ca180f6416160a523ff442f1ad0b768a9a3a948))
+ - add timeout in IO compensation ([de02e9b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/de02e9b0ec29548b8ce5ef6ee9adcd9c5edb0518))
+ - allow configuration of DDR AXI ports number ([88f4fb8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/88f4fb8fa759b1761954067346ee674b454bdfde))
+ - call pmic_voltages_init() in platform init ([ffd1b88](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ffd1b889225a8aec124df9e330f41dc638fd7180))
+ - chip rev. Z is 0x1001 on STM32MP13 ([ef0b8a6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ef0b8a6c1b1a0eab3626041f3168f82bdb410836))
+ - enable BL2_IN_XIP_MEM to remove relocation sections ([d958d10](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d958d10eb360024e15f3c921dc3863a0cee98830))
+ - enable format-signedness warning ([cff26c1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cff26c19169dd94857e8180cc46b7aa4ccac574a))
+ - get CPU info from SYSCFG on STM32MP13 ([6512c3a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6512c3a62a4a7baaf32597284b242bc7172b7e26))
+ - introduce new flag for STM32MP13 ([bdec516](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bdec516ee862bfadc25a4d0c02a3b8d859c1fa25))
+ - manage HSLV on STM32MP13 ([fca10a8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fca10a8f1b47231ef92634a0adf1a26cbfc97c2a))
+ - manage monotonic counter ([f5a3688](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f5a3688b8608df0f269a0b6df18632ebb9e26a01))
+ - new way to access platform OTP ([ae3ce8b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ae3ce8b28eac73e9a41fdb28424d9f0f4b5f200e))
+ - preserve the PLL4 settings for USB boot ([bf1af15](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bf1af154db2c89028a8a551c18885add35d38966))
+ - register fixed regulator ([967a8e6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/967a8e63c33822680e3a4631430dcd9a4a64becd))
+ - remove unsupported features on STM32MP13 ([111a384](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/111a384c90afc629e644e7a8284abbd4311cc6b3))
+ - retry 3 times FWU trial boot ([f87de90](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f87de907c87e5b2091592c131c4d3d2f737bef01))
+ - select platform compilation either by flag or DT ([99a5d8d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/99a5d8d01d38474b056766651bd746a4fe93ab20))
+ - skip TOS_FW_CONFIG if not in FIP ([b706608](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b7066086424c2f6fd04880db852306d6f487962e))
+ - stm32mp_is_single_core() for STM32MP13 ([7b48a9f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7b48a9f3286b8f174acf8821fec48fd2e4771514))
+ - update BACKUP_BOOT_MODE for STM32MP13 ([4b031ab](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4b031ab4c50d0b9f7127daa7f4eec634f39de970))
+ - update boot API for header v2.0 ([5f52eb1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5f52eb15970e57d2777d114948fc1110e3dd3f6c))
+ - update CFG0 OTP for STM32MP13 ([1c37d0c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1c37d0c1d378769249c797de5b13d73cf6f17a53))
+ - update console management for SP_min ([aafff04](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/aafff0435448c8409935132be41758e0031f0822))
+ - update IO compensation on STM32MP13 ([8e07ab5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8e07ab5f705b213af28831f7c3e9878154e07df0))
+ - update IP addresses for STM32MP13 ([52ac998](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/52ac9983d67522b6b821391941c8b0d01fd68941))
+ - update memory mapping for STM32MP13 ([48ede66](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/48ede6615168118c674288f2e4f8ee1b11d2fa02))
+ - updates for STM32MP13 device tree compilation ([d38eaf9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d38eaf99d327bc1400f51c87b6d8a2f92cd828c6))
+ - usb descriptor update for STM32MP13 ([d59b9d5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d59b9d53b9cfb2443575c62c6716eb5508374a7b))
+ - use clk_enable/disable functions ([c7a66e7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c7a66e720ae1a1a5ef98eaf9ff327cd352549010))
+ - use only one filter for TZC400 on STM32MP13 ([b7d0058](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b7d0058a3a9153a3863cf76a6763ea751b3ab48d))
+ - warn when debug enabled on secure chip ([ac4b8b0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ac4b8b06eb23134d2a9002834541d33f8d43661b))
+
+ - **Texas Instruments**
+
+ - add enter sleep method ([cf5868b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cf5868b8cd7239dee69bdf6ba3ab87bd06bf15f5))
+ - add gic save and restore calls ([b40a467](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b40a467783e5911f97d6e92ebdeb34ca2f005552))
+ - add PSCI handlers for system suspend ([2393c27](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2393c27680a1ec636e413051e87e986df5a866fe))
+ - allow build config of low power mode support ([a9f46fa](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a9f46fad82b807a9f0a967245e3ac10ee8dd0ef1))
+ - increase SEC_SRAM_SIZE to 128k ([38164e6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/38164e64bd853a8329475e9168c5fcb94ecc528b))
+
+ - **Xilinx**
+
+ - **Versal**
+
+ - add SPP/EMU platform support for versal ([be73459](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/be73459a945d8fa781fcc864943ccd0a8d92421c))
+ - add common interfaces to handle EEMI commands ([1397967](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1397967490c9f0ebff0d20a566260d1475fe065e))
+ - add SMCCC call TF_A_PM_REGISTER_SGI ([fcf6f46](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fcf6f469318d693a024d42ae2d0f4afb26c1e85d))
+ - add support to reset SGI ([bf70449](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bf70449ba2d1ffd20b01741c491dc0f565009b3d))
+ - add UART1 as console ([2c79149](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2c791499c26b40c31ce7f68c3bf0dca777fc62de))
+ - enhance PM_IOCTL EEMI API to support additional arg ([d34a5db](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d34a5db8a76abdfc8fa68f43b24b971699086a06))
+ - get version for ATF related EEMI APIs ([da6e654](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/da6e654bc8b03ee784d0e96a71c4e591e63930f2))
+ - remove the time stamp configuration ([18e2a79](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/18e2a79f8a5eaa72a2a7e641c2481beb9f827dce))
+
+ - **ZynqMP**
+
+ - disable the -mbranch-protection flag ([67abd47](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/67abd4762bd563be94e734bb0fe4087e88d5d446))
+ - fix section `coherent_ram' will not fit in region `RAM' ([9b4ed0a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9b4ed0af02a8ff1fd9a81af5213fde16d3eb8d92))
+ - add feature check support ([223a628](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/223a6284b8a0a3ead884a7f0cf333a464d32e319))
+ - add support to get info of xilfpga ([cc077c2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cc077c22273075db328bd30fa12c28abf9eef052))
+ - add uart1 as console ([ea66e4a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ea66e4af0baf5d5b905e72f824a672f16a6e0f98))
+ - increase the max xlat tables when debug build is enabled ([4c4b961](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4c4b9615b1d9512a4a89aa08e722547cc491a07b))
+ - pass ioctl calls to firmware ([76ff8c4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/76ff8c459e9e6d105e614d68648bd6680806f93e))
+ - pm_api_clock_get_num_clocks cleanup ([e682d38](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e682d38b56854e1586b25d929dbc83543b4c66e4))
+
+- **Bootloader Images**
+
+ - add XLAT tables symbols in linker script ([bb5b942](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bb5b942e6f133198daedcca0b74ec598af260a54))
+
+ - **BL2**
+
+ - add support to separate no-loadable sections ([96a8ed1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/96a8ed14b74cca33a8caf567d0f0a2d3b2483a3b))
+
+ - **BL31**
+
+ - aarch64: RESET_TO_BL31_WITH_PARAMS ([25844ff](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/25844ff728e4a0e5430ba2032457aba7b780a701))
+
+- **Services**
+
+ - **RME**
+
+ - add dummy platform token to RMMD ([0f9159b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0f9159b7ebb7e784a8ed998869ff21095fa105b1))
+ - add dummy realm attestation key to RMMD ([a043510](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a0435105f229a65c7861b5997793f905cf90b823))
+
+ - **SPM**
+
+ - update ff-a boot protocol documentation ([573ac37](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/573ac37373d3e8b2c31b3aaeed759e4656e060ec))
+
+ - **EL3 SPMC**
+
+ - allow BL32 specific defines to be used by SPMC_AT_EL3 ([2d65ea1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2d65ea1930d4ce26cc176a8c60e9401d0b4f862a))
+ - add plat hook for memory transactions ([a8be4cd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a8be4cd057bce5f0b4ac6af396c0c870474d1ef4))
+ - add EL3 SPMC #defines ([44639ab](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/44639ab73e43e0b79da834dff8c85266d68e5066))
+ - introduce accessor function to obtain datastore ([6a0788b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6a0788bc0e704283e52c80990aa2bb6e047a0cc2))
+ - add FF-A secure partition manager core ([5096aeb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5096aeb2ba646548a7a6ab59e975b996e6c9026a))
+ - add FFA_FEATURES handler ([55a2963](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/55a296387b9720855df429a08c886f47a4a45057))
+ - add FFA_PARTITION_INFO_GET handler ([f74e277](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f74e27723bb54ad1318fa462fbcff70af555b2e6))
+ - add FFA_RUN handler ([aad20c8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/aad20c85cb6f4bc91318d3c6488cf72a20fdbe96))
+ - add FFA_RX_RELEASE handler ([f0c25a0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f0c25a082fc8b891d4d21518028118561caa4735))
+ - add function to determine the return path from the SPMC ([20fae0a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/20fae0a7ce7fd407cd3efb7745017ee6ab605159))
+ - add helper function to obtain endpoint mailbox ([f16b6ee](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f16b6ee3deac93706efe465f399c9542e12d5eeb))
+ - add helper function to obtain hyp structure ([a7c0050](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a7c00505f85684326a223535a319c170d14826f6))
+ - add helper to obtain a partitions FF-A version ([c2b1434](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c2b1434369292081f907c548e496f59e197eb2f1))
+ - add partition mailbox structs ([e1df600](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e1df6008d9b4a00da25ec08fbdcbd3a5967fdb54))
+ - add support for direct req/resp ([9741327](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9741327df577c3f43db42b26bda607429e62af0b))
+ - add support for FF-A power mgmt. messages in the EL3 SPMC ([59bd2ad](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/59bd2ad83c13ed3c84bb9b841032c95927358890))
+ - add support for FFA_MSG_WAIT ([c4db76f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c4db76f066f236fe490ebc7a50833a04e08f5151))
+ - add support for FFA_SPM_ID_GET ([46872e0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/46872e01f5efb555fef8367595b59e5d2f75cec0))
+ - add support for forwarding a secure interrupt to the SP ([729d779](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/729d7793f830781ff8ed44d144c3346c6e4251a3))
+ - add support for handling FFA_ERROR ABI ([d663fe7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d663fe7a3002ff028c190eb732278b878e78b7b7))
+ - add support for v1.1 FF-A boot protocol ([2e21921](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2e21921502b1317031cf2a2f69c5d47ac88a505d))
+ - add support for v1.1 FF-A memory data structures ([7e804f9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7e804f9695c48681c91e9e6fc6175eb6997df867))
+ - enable building of the SPMC at EL3 ([1d63ae4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1d63ae4d0d8374a732113565be90d58861506e39))
+ - enable checking of execution ctx count ([5b0219d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5b0219ddd5da42413f4c2be9302224b5b71295ff))
+ - enable handling FF-A RX/TX Mapping ABIs ([1a75224](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1a752245ecae6487844c57667e24b704e6df8079))
+ - enable handling FFA_VERSION ABI ([0c7707f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0c7707fdf21fc2a8658f5a4bdfd2f8883d02ada5))
+ - enable handling of the NS bit ([0560b53](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0560b53e71ab6daefa8e75665a718605478746a4))
+ - enable parsing of messaging methods from manifest ([3de378f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3de378ff8c9430c964cbe9b0c58fa5afc4d237ce))
+ - enable parsing of UUID from SP Manifest ([857f579](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/857f5790da3770a9ca52416274eec4e545c9be53))
+ - enable the SPMC to pass the linear core ID in a register ([f014300](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f0143004e548582760aacd6f15f5499b18081a69))
+ - prevent read only xlat tables with the EL3 SPMC ([70d986d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/70d986ddbbf56a20c7550c079dd4dc9462332594))
+ - support FFA_ID_GET ABI ([d5fe923](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d5fe92350cb018ae7083ed26a6a16508ccd82a86))
+ - allow forwarding of FFA_FRAG_RX/TX calls ([642db98](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/642db9840712044b9c496e04a7acd60580e54117))
+ - enable handling of FF-A SMCs with the SPMC at EL3 ([bb01a67](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bb01a67306f47271adde051e541c760028c1a0f1))
+ - update SPMC init flow to use EL3 implementation ([6da7607](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6da76075bf4b953d621aa15c379e62a5f785de3f))
+ - add logical partition framework ([7affa25](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7affa25cad400101c016082be2d102be0f4fce80))
+ - add FF-A memory management code ([e0b1a6d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e0b1a6d59e57c0dbe87f5b8f8166f1123664f058))
+ - prevent duplicated sharing of memory regions ([fef85e1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fef85e1e53fcf44e8d9ed50c89d8a764bf1b7738))
+ - support multiple endpoints in memory transactions ([f0244e5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f0244e5dd1b8cbab75ef00c1b9b56eed5b3cad4b))
+
+ - **SPMD**
+
+ - forward FFA_VERSION from SPMD to SPMC ([9944f55](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9944f55761c4d5cc1feefaf5e33bf7fb83d8f5f3))
+ - enable SPMD to forward FFA_VERSION to EL3 SPMC ([9576fa9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9576fa93a2effc23a533b80dce41d7104a8d200b))
+ - add FFA_MSG_SEND2 forwarding in SPMD ([c2eba07](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c2eba07c47f8d831629104eeffcec11ed7d3b0a5))
+ - add FFA_RX_ACQUIRE forwarding in SPMD ([d555233](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d555233fe5a04dfd99fd6ac30bacc5284285c131))
+
+ - **SPM MM**
+
+ - add support to save and restore fp regs ([15dd6f1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/15dd6f19da8ee4b20ba525e0a742d0df9e46e071))
+
+- **Libraries**
+
+ - **CPU Support**
+
+ - add library support for Poseidon CPU ([1471475](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1471475516cbf1b4a411d5ef853bd92d0edd542e))
+ - add support for Cortex-X1 ([6e8eca7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6e8eca78e5db966e10e2fa2737e9be4d5af51fa9))
+ - add L1PCTL macro definiton for CPUACTLR_EL1 ([8bbb1d8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8bbb1d80a58dbdf96fcabbdebbfbd21d2d5344a4))
+
+ - **EL3 Runtime**
+
+ - add arch-features detection mechanism ([6a0da73](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6a0da73647546aea1d10b4b2347bac9d532bcb43))
+ - replace ARM_ARCH_AT_LEAST macro with FEAT flags ([0ce220a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0ce220afb24f0511332b251952019d7011ccc282))
+
+ - **FCONF**
+
+ - add a helper to get image index ([9e3f409](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9e3f409398af447b1d03001dd981007a9bb1617e))
+ - add NS load address in configuration DTB nodes ([ed4bf52](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ed4bf52c33b6860d58a2ffc946bd293ec76bbdaa))
+
+ - **Standard C Library**
+
+ - add support for length specifiers ([701e94b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/701e94b08f382691b0deabd4df882abd87e17ab5))
+
+ - **PSA**
+
+ - add initial attestation API ([0848565](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/084856513d6730a50a3d65ac9c3bdae465117c40))
+ - add measured boot API ([758c647](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/758c64715b691be92de623f81032494e38a43cc8))
+ - mock PSA APIs ([0ce2072](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0ce2072d9b9f419bb19595454395a33a5857ca2f))
+
+- **Drivers**
+
+ - **Generic Clock**
+
+ - add a minimal clock framework ([847c6bc](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/847c6bc8e6d55b1c0f31a52407aa61515cd6c612))
+
+ - **FWU**
+
+ - add a function to pass metadata structure to platforms ([9adce87](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9adce87efc8acc947b8b49d700c9773a7f071e02))
+ - add basic definitions for GUID handling ([19d63df](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/19d63df1af72b312109b827cca793625ba6fcd16))
+ - add platform hook for getting the boot index ([40c175e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/40c175e75bc442674a5dc793c601b09681158ab9))
+ - pass a const metadata structure to platform routines ([6aaf257](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6aaf257de4a4070ebc233f35a09bce4c39ea038c))
+ - simplify the assert to check for fwu init ([40b085b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/40b085bddf60cf8c533b379ccb41e6668c5080dd))
+
+ - **Measured Boot**
+
+ - add RSS backend ([0442ebd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0442ebd2e9bcf5fa4344d8fa8ef4b69a3b249e33))
+
+ - **GUID Partition Tables Support**
+
+ - add a function to identify a partition by GUID ([3cb1065](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3cb1065581f6d9a8507af8dbca3779d139aa0ca7))
+ - cleanup partition and gpt headers ([2029f93](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2029f930097b0c3b1b1faa660032d16ed01a5c86))
+ - copy the partition GUID into the partition structure ([7585ec4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7585ec4d36ebb7e286cfec959b2de084eded8201))
+ - make provision to store partition GUID value ([938e8a5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/938e8a500a25a949cfd25f0cb79f6c1359c9b40c))
+ - verify crc while loading gpt header ([a283d19](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a283d19f82ddb635d9d9fa061e7fd956167ebe60))
+
+ - **Arm**
+
+ - **GIC**
+
+ - allow overriding GICD_PIDR2_GICV2 address ([a7521bd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a7521bd5d887bfd69d99a55a81416e38ba9ebc97))
+
+ - **GIC-600AE**
+
+ - disable SMID for unavailable blocks ([3f0094c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3f0094c15d433cd3de413a4633a4ac2b8e1d1f2e))
+ - enable all GICD, PPI, ITS SMs ([6a1c17c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6a1c17c770139c00395783e7568220d61264c247))
+ - introduce support for RAS error handling ([308dce4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/308dce40679f63db504cd3d746a0c37a2a05f473))
+
+ - **SMMU**
+
+ - add SMMU abort transaction function ([6c5c532](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6c5c5320511ab8202fb9eccce9e66b4e4e0d9a33))
+ - configure SMMU Root interface ([52a314a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/52a314af254966a604e192fcc3326737354f217a))
+
+ - **MHU**
+
+ - add MHU driver ([af26d7d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/af26d7d6f01068809f17cc2d49a9b3d573c640a9))
+
+ - **RSS**
+
+ - add RSS communication driver ([ce0c40e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ce0c40edc93aa403cdd2eb6c630ad23e28b01c3e))
+
+ - **TZC**
+
+ - **TZC-380**
+
+ - add sub-region register definition ([fdafe2b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fdafe2b5ead66a1b5175db77bcc7cedafa14a059))
+
+ - **Marvell**
+
+ - **Armada**
+
+ - **A3K**
+
+ - **A3720**
+
+ - preserve x1/x2 regs in console_a3700_core_init() ([7c85a75](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7c85a7572960efbaabe20c9db037bcec66be3e98))
+
+ - **MediaTek**
+
+ - **APU**
+
+ - add mt8195 APU clock and pll SiP call ([296b590](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/296b590206aa6db51e5c82b1a97a4f9707b49c4d))
+ - add mt8195 APU iommap regions ([339e492](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/339e4924a7a3fd11bc176e0bf3e01d76133d364c))
+ - add mt8195 APU mcu boot and stop SiP call ([88906b4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/88906b443734399be5c07a5bd690b63d3d82cefa))
+
+ - **NXP**
+
+ - **DCFG**
+
+ - add Chassis 3 support ([df02aee](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/df02aeeec640d2358301e903d9c8c473d455be9e))
+ - add gic address align register definition ([3a8c9d7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3a8c9d78d4c65544d789bd64bd005ac10b5b352d))
+ - add some macro definition ([1b29fe5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1b29fe534b8732193850fced2da1dc449450bd3b))
+
+ - **NXP Crypto**
+
+ - add chassis 3 support ([d60364d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d60364d48e31b33b57049d848b7462eb0e0de612))
+
+ - **DDR**
+
+ - add rawcard 1F support ([f2de48c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f2de48cb143c20ccd7a9c141df3d34cae74049de))
+ - add workaround for errata A050958 ([291adf5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/291adf521a54a365e54964bff4dae53d51c65936))
+
+ - **GIC**
+
+ - add some macros definition for gicv3 ([9755fd2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9755fd2ec2894323136715848910b13053cfe0ce))
+
+ - **CSU**
+
+ - add bypass bit mask definition ([ec5fc50](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ec5fc501f15922967bf5d8260072ba1f9aec9640))
+
+ - **IFC NAND**
+
+ - add IFC NAND flash driver ([28279cf](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/28279cf2c141caf5e4e7156f874cde6f5a0d271b))
+
+ - **IFC NOR**
+
+ - add IFC nor flash driver ([e2fdc77](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e2fdc77ba4eee91f0d1490e34f0fff552fc55dc9))
+
+ - **TZC-380**
+
+ - add tzc380 platform driver support ([de9e57f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/de9e57ff1f3769e770eac44b94127eb7239a63f2))
+
+ - **ST**
+
+ - introduce fixed regulator driver ([5d6a264](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5d6a2646f7759a5a2b3daed0d8aef4588c552ba4))
+
+ - **Clock**
+
+ - add clock driver for STM32MP13 ([9be88e7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9be88e75c198b08c508d8e470964720a781294b3))
+ - assign clocks to the correct BL ([7418cf3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7418cf397916c97cb4ecf159b1f497a84299b695))
+ - check HSE configuration in serial boot ([31e9750](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/31e9750bc17bd472d4f2a3db297461efc301be51))
+ - define secure and non-secure gate clocks ([aaa09b7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/aaa09b713c6f539fb5b2ee7e2dfd75f2d46875f5))
+ - do not refcount on non-secure clocks in bl32 ([3d69149](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3d69149a7e9e9a899d57f48bee26f98614f88935))
+ - manage disabled oscillator ([bcccdac](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bcccdacc7e7b7b985df942b3fae26cb9038a2574))
+
+ - **DDR**
+
+ - add read valid training support ([5def13e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5def13eb01ebac5656031bdc388a215d012fdaf8))
+
+ - **GPIO**
+
+ - allow to set a gpio in output mode ([53584e1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/53584e1d5b2b843ea3bb9e01e3f01ea7c364ee6a))
+ - do not apply secure config in BL2 ([fc0aa10](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fc0aa10a2cd3cab887a8baa602891d1f45db2537))
+ - add a function to reset a pin ([737ad29](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/737ad29bf992a7a79d538d1e0b47c7f38d9a4b9d))
+
+ - **SDMMC2**
+
+ - allow compatible to be defined in platform code ([6481a8f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6481a8f1e045ac80f0325b8bfe7089ba23deaf7b))
+ - manage cards power cycle ([258bef9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/258bef913aa76ead1b10c257d1695d9c0ef1c79d))
+
+ - **ST PMIC**
+
+ - add pmic_voltages_init() function ([5278ec3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5278ec3faf2010fd6aea1d8cd4294dd229c5c21d))
+ - register the PMIC to regulator framework ([85fb175](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/85fb175b5ef854bc4607db98a4cfb5f35d822cee))
+
+ - **STPMIC1**
+
+ - add new services ([ea552bf](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ea552bf5a57b573a6b09e396e3466b3c4af727f0))
+ - add USB OTG regulators ([13fbfe0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/13fbfe046e71393961d2c70a4f748a15f9c15f77))
+
+ - **Regulator**
+
+ - add support for regulator-always-on ([9b4ca70](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9b4ca70d97d9a2556752b511ff9fe52012faff02))
+ - add a regulator framework ([d5b4a2c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d5b4a2c4e7fd0bcb9f08584b242e69a2e591fb71))
+
+ - **UART**
+
+ - manage oversampling by 8 ([1f60d1b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1f60d1bd33d434b0c82a74e276699ee5a2f63833))
+ - add uart driver for STM32MP1 ([165ad55](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/165ad5561ef598ea6261ba082610eeff3f208df7))
+
+- **Miscellaneous**
+
+ - **Debug**
+
+ - update print_memory_map.py ([d16bfe0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d16bfe0feffe6a20399fb91d86fd8f7282b941dd))
+
+ - **DT Bindings**
+
+ - add bindings for STM32MP13 ([1b8898e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1b8898eb32c3872a34fc59f4216736f23af0c6ea))
+ - add TZC400 bindings for STM32MP13 ([24d3da7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/24d3da76d221390bb47d501c2ed77a1a7d2b42e7))
+
+ - **FDT Wrappers**
+
+ - add function to find or add a sudnode ([dea8ee0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/dea8ee0d3f13f8d1638745b76e86bd7617bf92e7))
+
+ - **FDTs**
+
+ - add the ability to supply idle state information ([2b2b565](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2b2b565717cc0299e75e8806004d1a3548e9fbf7))
+
+ - **STM32MP1**
+
+ - add DDR support for STM32MP13 ([e6fddbc](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e6fddbc995947d4e5a5dc6607c76cd46fdd840e2))
+ - add DT files for STM32MP13 ([3b99ab6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3b99ab6e370a01caec14bc5422a86001eaf291b8))
+ - add nvmem_layout node and OTP definitions ([ff8767c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ff8767cbfc2bb851a2f6cc32fbe3693ddbfb7d12))
+ - add st-io_policies node for STM32MP13 ([2bea351](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2bea35122d102492f18c427535ce6c9b7016e356))
+ - add support for STM32MP13 DK board ([2b7f7b7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2b7f7b751f4b0f7a8a0f4a35407af22cc269e529))
+ - update NVMEM nodes ([375b79b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/375b79bb4a773fe6a5dd971272c72bf12155050e))
+
+- **Documentation**
+
+ - context management refactor proposal ([3274226](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/327422633bef112a10579d4daeca0f596cd02911))
+
+ - **Threat Model**
+
+ - Threat Model for TF-A v8-R64 Support ([dc66922](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/dc669220d5666c2c808bc11ba81c86a9b071271a))
+
+- **Tools**
+
+ - **Secure Partition Tool**
+
+ - add python SpSetupActions framework ([b1e6a41](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b1e6a41572240839e62099aa00298174b18c696a))
+ - delete c version of the sptool ([f4ec476](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f4ec47613fef8db8037195147dc2ac6fb6f154ff))
+ - python version of the sptool ([2e82874](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2e82874cc9b7922e000dd4d7718e3153e347b1d7)
+ - use python version of sptool ([822c727](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/822c72791f791d26e233df0c15a655c3dbd8b117))
+
+### Resolved Issues
+
+- **Architecture**
+
+ - **Activity Monitors Extension (FEAT_AMU)**
+
+ - add default value for ENABLE_FEAT_FGT and ENABLE_FEAT_ECV flags ([820371b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/820371b13028a6f620a62cf73a951883d051666b))
+ - fault handling on EL2 context switch ([f74cb0b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f74cb0be8ac80eb3072555cb04eb09375d4cb31f))
+ - limit virtual offset register access to NS world ([a4c3945](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a4c394561af31ae0417ed9ff3b3152adb7cd5355))
+
+ - **Scalable Vector Extension (FEAT_SVE)**
+
+ - disable ENABLE_SVE_FOR_NS for AARCH32 ([24ab2c0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/24ab2c0af74be174acf755a36b3ebba867184e60))
+
+- **Platforms**
+
+ - **Allwinner**
+
+ - improve DTB patching error handling ([79808f1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/79808f10c32d441572666551b1545846079af15b))
+
+ - **Arm**
+
+ - fix fvp and juno build with USE_ROMLIB option ([861250c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/861250c3b26d64f859f5f37686e453d5074fa976))
+ - increase ARM_BL_REGIONS count ([dcb1959](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/dcb1959161935aa58d2bb852f3cef0b96458a4e1))
+ - remove reclamation of functions starting with "init" ([6c87abd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6c87abdda400354ebf4f5351086c32a4620475c9))
+ - use PLAT instead of TARGET_PLATFORM ([c5f3de8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c5f3de8dabc9b955b6051a6c6116d40b10a84f5d))
+ - fix SP count limit without dual root CoT ([9ce15fe](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9ce15fe8910580efca46b9f102e117402ce769db))
+
+ - **FVP**
+
+ - FCONF Trace Not Shown ([0c55c10](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0c55c10305df6217fd978d58ce203dbad3edd4d5))
+ - disable reclaiming init code by default ([fdb9166](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fdb9166b9494402eb2da7e0b004c121b322725e0))
+ - extend memory map to include all DRAM memory regions ([e803542](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e80354212f591c8813dec27353e8241e03155b4c))
+ - fix NULL pointer dereference issue ([a42b426](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a42b426b8548e3304e995f1a49d2470d71072949))
+ - op-tee sp manifest doesn't map gicd ([69cde5c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/69cde5cd9563f0c665862f1e405ae8e8d2818c6e))
+
+ - **Morello**
+
+ - change the AP runtime UART address ([07302a2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/07302a23ec1af856b3d4de0439161a8c23414f84))
+ - fix SoC reference clock frequency ([e8b7a80](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e8b7a80436c2bc81c61fc4703d6580f2fe9226a9))
+ - include errata workaround for 1868343 ([f94c84b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f94c84baa2a2bad75397b0ec6a0922fe8a475847))
+
+ - **SGI**
+
+ - disable SVE for NS to support SPM_MM builds ([78d7e81](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/78d7e819798ace643b6e22025dc76aedb199bbd5))
+
+ - **TC**
+
+ - remove the bootargs node ([68fe3ce](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/68fe3cec25bc9ea4e1bafdb1d9f5315e245d650b))
+
+ - **Corstone-1000**
+
+ - change base address of FIP in the flash ([1559450](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1559450132c5e712f4d6896e53e4f1cb521fa465))
+
+ - **Broadcom**
+
+ - allow build to specify mbedTLS absolute path ([903d574](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/903d5742953d9d4b224e71d8b1e62635e83f44a9))
+ - fix the build failure with mbedTLS config ([95b5c01](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/95b5c0126b802b894ea0177d973978e06b6a254d))
+
+ - **Intel**
+
+ - add flash dcache after return response for INTEL_SIP_SMC_MBOX_SEND_CMD ([ac097fd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ac097fdf07ad63b567ca751dc518f8445a0baef6))
+ - allow non-secure access to FPGA Crypto Services (FCS) ([4837a64](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4837a640934630f8034ceec1bb84cc40673d8a6b))
+ - always set doorbell to SDM after sending command ([e93551b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e93551bb3bd8ac43779fa70c7363ee2568da45ca))
+ - assert if bl_mem_params is NULL pointer ([35fe7f4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/35fe7f400a7f1d65ff2fee5531d20f6c2f3e6f39))
+ - bit-wise configuration flag handling ([276a436](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/276a43663e8e315fa1bf0aa4824051d88705858b))
+ - change SMC return arguments for INTEL_SIP_SMC_MBOX_SEND_CMD ([108514f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/108514ff7160a86efb791449a4635ffe0f9fdf2c))
+ - configuration status based on start request ([e40910e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e40910e2dc3fa59bcce83ec1cf9a33b3e85012c4))
+ - define macros to handle buffer entries ([7db1895](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7db1895f0be2f8c6710bf51d8441d5e53e3ef0fe))
+ - enable HPS QSPI access by default ([000267b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/000267be22d3c0077c0fd0a8377ceeed5aada4c3))
+ - extend SDM command to return the SDM firmware version ([c026dfe](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c026dfe38cfae379457a6ef53130bd5ebc9d7808))
+ - extending to support large file size for AES encryption and decryption ([dcb144f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/dcb144f1fbcef73ddcc448d5ed6134aa279069b6))
+ - extending to support large file size for SHA-2 ECDSA data signing and signature verifying ([1d97dd7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1d97dd74cd128edd7ad45b725603444333c7b262))
+ - extending to support large file size for SHA2/HMAC get digest and verifying ([70a7e6a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/70a7e6af958f3541476a8de6baac8e376fcc67f9))
+ - fix bit masking issue in intel_secure_reg_update ([c9c0709](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c9c070994caedf123212aad23b6942122c5dd793))
+ - fix configuration status based on start request ([673afd6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/673afd6f8e7266900b00a7cbeb275fe1a3d69cce))
+ - fix ddr address range checker ([12d71ac](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/12d71ac6627bb6822a0314e737794a8503df79dd))
+ - fix ECC Double Bit Error handling ([c703d75](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c703d752cce4fd101599378e72db66ccf53644fa))
+ - fix fpga config write return mechanism ([ef51b09](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ef51b097bfa906bf1cee8ee641a1b7bcc8c5f3c0))
+ - flush dcache before sending certificate to mailbox ([49d44ec](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/49d44ec5f357b1bcf8eae9e91fbd72aef09e00dd))
+ - get config status OK status ([07915a4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/07915a4fd5848fbac69dcbf28f00353eed10a942))
+ - introduce a generic response error code ([651841f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/651841f20110ce6fac650e3ac47b0a9cce18e6f3))
+ - make FPGA memory configurations platform specific ([f571183](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f571183b066b1a91b7fb178c3aad9d6360d1918c))
+ - modify how configuration type is handled ([ec4f28e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ec4f28ecec8887a685d6119c096ad346da1ea53e))
+ - null pointer handling for resp_len ([a250c04](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a250c04b0cc807f626df92a7091ff13b3a3aa9ed))
+ - refactor NOC header ([bc1a573](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bc1a573d5519f121cb872fce1d88fe2e0db07b2c))
+ - reject non 4-byte align request size for FPGA Crypto Service (FCS) ([52ed157](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/52ed157fd66812debb13a792c21f763de01aef70))
+ - remove redundant NOC header declarations ([58690cd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/58690cd629b4ccdefe5313f805219598074a3501))
+ - remove unused printout ([0d19eda](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0d19eda0dd2ffae27d0551b1f0a06a2b8f96c853))
+ - update certificate mask for FPGA Attestation ([fe5637f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fe5637f27aebfdab42915c2ced2c34d8685ee2bb))
+ - update encryption and decryption command logic ([02d3ef3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/02d3ef333d4a0a07a3e40defb12a8cde3a7cba03))
+ - use macro as return value ([e0fc2d1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e0fc2d1907b1c8a062c44a435be77a12ffeed84b))
+
+ - **Marvell**
+
+ - **Armada**
+
+ - **A3K**
+
+ - change fatal error to warning when CM3 reset is not implemented ([30cdbe7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/30cdbe7043832f7bd96b40294ac062a8fc9c540f))
+ - fix comment about BootROM address range ([5a60efa](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5a60efa12a57cde98240f861e45609cb9b94d58d))
+
+ - **Mediatek**
+
+ - **MT8186**
+
+ - remove unused files in drivers/mcdi ([bc714ba](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bc714bafe7ae8ca29075ba9bf3985c0e15ae0f64))
+ - extend MMU region size ([0fe7ae9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0fe7ae9c64aa6f6d5b06a80de9c88081057d5dbe))
+
+ - **NVIDIA**
+
+ - **Tegra**
+
+ - **Tegra 194**
+
+ - remove incorrect erxctlr assert ([e272c61](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e272c61ce8185deb397dcf168ec72bdaa5926a33))
+
+ - **NXP**
+
+ - fix total dram size checking ([0259a3e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0259a3e8282ed17c1d378a27f820f44b3bebab07))
+ - increase soc name maximum length ([3ccd7e4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3ccd7e45a2c3ff9fa7794f0284c9d0298e7cb982))
+
+ - **i.MX**
+
+ - **i.MX 8M**
+
+ - check the validation of domain id ([eb7fb93](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/eb7fb938c3ce34ccfb143ae8ba695df899098436))
+
+ - **i.MX 8M Plus**
+
+ - change the BL31 physical load address ([32d5042](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/32d5042204e8b41caa4c0c1ed5b48bad9f1cb1b5))
+
+ - **Layerscape**
+
+ - fix build issue of mmap_add_ddr_region_dynamically ([e2818d0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e2818d0afc20a60d302f85f4c915e4ae4cc3cb9c))
+ - fix coverity issue ([5161cfd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5161cfde9bfaa3a715d160fcd4870f276adad332))
+ - update WA for Errata A-050426 ([72feaad](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/72feaad980cdc472868bc95914202bf57ed51b2d))
+
+ - **LX2**
+
+ - drop erratum A-009810 ([e36b0e4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e36b0e4910aea56f90a6ab9b8cf3dc4008220031))
+
+ - **Renesas**
+
+ - **R-Car**
+
+ - **R-Car 3**
+
+ - change stack size of BL31 ([d544dfc](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d544dfcc4959d203b06dbfb85fb0ad895178b379))
+ - fix SYSTEM_OFF processing for R-Car D3 ([1b49ba0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1b49ba0fde5eb9e47fe50152c192579101feb718))
+ - fix to bit operation for WUPMSKCA57/53 ([82bb6c2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/82bb6c2e88314a5b3f2326c95095c3b20a389947))
+
+ - **Socionext**
+
+ - **Synquacer**
+
+ - initialise CNTFRQ in Non Secure CNTBaseN ([4d4911d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4d4911d77d4d59c7dd18d7fc3724ddb1fa3582b7))
+
+ - **ST**
+
+ - add missing header include ([b1391b2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b1391b294ca7803f46bc47048b4a02a15dda9a16))
+ - don't try to read boot partition on SD cards ([9492b39](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9492b391a35c66e1e7630e95347259191b28314d))
+ - fix NULL pointer dereference issues ([2deff90](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2deff904a953c6a87331ab6830ab80e3889d9e23))
+ - manage UART clock and reset only in BL2 ([9e52d45](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9e52d45fdf619561e0a7a833b77aaacc947a4dfd))
+ - remove extra chars from dtc version ([03d2077](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/03d20776efc20a04a5191a4f39965079a4d60b3c))
+
+ - **ST32MP1**
+
+ - add missing debug.h ([356ed96](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/356ed961184847dcd088cfcda44b71eeb0ef2377))
+ - correct dtc version check ([429f10e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/429f10e3367748abd33b4f6f9ee362c0ba74dd95))
+ - correct include order ([ff7675e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ff7675ebf94999618dbde14bb59741cefb2b2edd))
+ - correct types in messages ([43bbdca](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/43bbdca04f5a20bb4e648e18fc63061b6a6e4ecf))
+ - deconfigure UART RX pins ([d7176f0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d7176f0319cd399aae9a906e5d78e67b32e183f5))
+ - do not reopen debug features ([21cfa45](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/21cfa4531a76a7c3cad00e874400b97e2f68723c))
+ - fix enum prints ([ceab2fc](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ceab2fc3442dbda1c4beaff3c4fe708a04c02303))
+ - include assert.h to fix build failure ([570c71b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/570c71b20a195ade510f5d584c69325d2634c50b))
+ - remove interrupt_provider warning for dtc ([ca88c76](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ca88c761d34854ed3e0b16b9c5f39b0790d320ab))
+ - restrict DEVICE2 mapping in BL2 ([db3e0ec](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/db3e0ece7157181a3529d14172368003eb63dc30))
+ - rework switch/case for MISRA ([f7130e8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f7130e81cf9c3682232bb9319b1798184b44920f))
+ - set reset pulse duration to 31ms ([9a73a56](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9a73a56c353d32742e03b828647562bdbe2ddbb2))
+
+ - **Xilinx**
+
+ - fix coding style violations ([bb1768c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bb1768c67ea06ac466e2cdc7e5338c3d23dac79d))
+ - fix mismatching function prototype ([81333ea](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/81333eac716b25a9fd112cc4f5990e069f3bdb40))
+
+ - **Versal**
+
+ - resolve misra R10.1 in pm services ([775bf1b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/775bf1bbd32c2df47f4ff597eb8a452d2983e590))
+ - resolve misra R10.3 ([b2bb3ef](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b2bb3efb8f590f31b1205c51d56be1dd6f473fbb))
+ - resolve misra R10.3 in pm services ([5d1c211](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5d1c211e225d40d2926bf34483c90f907a6c5dc3))
+ - resolve misra R10.6 ([93d4625](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/93d462562727f4f428e6f975a972226dafbfd305))
+ - resolve misra R10.6 in pm services ([fa98d7f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fa98d7f2f8752e37f740b43f533547288552a393))
+ - resolve misra R14.4 ([a62c40d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a62c40d42703d5f60a8d80938d2cff721ee131bd))
+ - resolve misra R15.6 ([b9fa2d9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b9fa2d9fc154feffe78e677ace54b0e34f011439))
+ - resolve misra R15.6 in pm services ([4156719](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4156719550ceddf5b1b4a47464fb32f7506e0dca))
+ - resolve misra R15.7 ([bc2637e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bc2637e3799dbc9642447ddb719e0262347b1309))
+ - resolve misra R16.3 in pm services ([27ae531](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/27ae5310883b0db7d4e2dd4fbc1fd58e675f75b5))
+ - resolve misra R17.7 ([526a1fd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/526a1fd1472874561988777f8ecd8b87734a0671))
+ - resolve misra R20.7 in pm services ([5dada62](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5dada6227b949ef702bfab7986bc083689afdaf7))
+ - resolve misra R7.2 ([0623dce](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0623dcea0f6e7a5c9d65413445df8a96a2b40d42))
+ - fix coverity scan warnings ([0b15187](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0b15187225a9134e3acbc7693646b21d43617b3b))
+ - fix the incorrect log message ([ea04b3f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ea04b3fe183b6661f656b4cc38cb93a73d9bc202))
+
+ - **ZynqMP**
+
+ - define and enable ARM_XLAT_TABLES_LIB_V1 ([c884c9a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c884c9a55b167383ff3d96d2d0a30ac6842bcc86))
+ - query node status to power up APU ([b35b556](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b35b556718b60b78cb5d96b0c137e2fe82eb0086))
+ - resolve misra 7.2 warnings ([5bcbd2d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5bcbd2de127292f3ad076217e08468388c6844b0))
+ - resolve misra 8.3 warnings ([944e7ea](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/944e7ea94f2594e2b128c671cf7415265302596b))
+ - resolve misra R10.3 ([2b57da6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2b57da6c91ebe14588e63e5a24f31ef32711eca2))
+ - resolve misra R14.4 warnings ([dd1fe71](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/dd1fe7178b578916b1e133b7c65c183e1f994371))
+ - resolve misra R15.6 warnings ([eb0d2b1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/eb0d2b17722c01a22bf3ec1123f7bed2bf891b09))
+ - resolve misra R15.7 warnings ([16de22d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/16de22d037644359ef2a04058134f9c326b36633))
+ - resolve misra R16.3 warnings ([e7e5d30](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e7e5d30308ccfb931f7b6d0afa6c5c23971e95c0))
+ - resolve misra R8.4 warnings ([610eeac](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/610eeac89438d603435bde694eb4ddab07f46e45))
+ - update the log message to verbose ([1277af9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1277af9bacca36b46d7aa341187bb3abef84332f))
+ - use common interface for eemi apis ([a469c1e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a469c1e1f4c1cd69f98ce45d6e0709de091b8cb3))
+
+- **Bootloader Images**
+
+ - **BL1**
+
+ - invalidate SP in data cache during secure SMC ([f1cbbd6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f1cbbd6332bb85672dc72cbcc4ac7023323c6936))
+
+ - **BL2**
+
+ - correct messages with image_id ([e4c77db](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e4c77db9c80d87009611a3079454877e6ce45a04))
+ - define RAM_NOLOAD for XIP ([cc562e7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cc562e74101d800b0b0ee3422fb7f4f8321ae2b7))
+
+- **Services**
+
+ - **RME**
+
+ - enable/disable SVE/FPU for Realms ([a4cc85c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a4cc85c129d031d9c887cf59b1baeaef18a43010))
+ - align RMI and GTSI FIDs with SMCCC ([b9fd2d3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b9fd2d3ce3d4e543a2e04dc237cd4e7ff7765c7a))
+ - preserve x4-x7 as per SMCCCv1.1 ([1157830](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/11578303fd04a8da36fddb5e6de44f026bf4d24c))
+
+ - **TRP**
+
+ - Distinguish between cold and warm boot ([00e8113](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/00e8113145aa12d89db72068bdd3157f08575d14))
+
+ - **SPM**
+
+ - **EL3 SPMC**
+
+ - fix incorrect FF-A version usage ([25eb2d4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/25eb2d41a6d2ede1e945bbc67ae3f740b92a40bb))
+ - fix FF-A memory transaction validation ([3954bc3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3954bc3c03439dbdc7029cf2418c79a037918ce4))
+
+- **Libraries**
+
+ - **CPU Support**
+
+ - workaround for Cortex-A710 2282622 ([ef934cd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ef934cd17c30dcc39cd9022a1c4e9523ec8ba617))
+ - workaround for Cortex-A710 erratum 2267065 ([cfe1a8f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cfe1a8f7123f0dc8376b2075cc6e8e32b13739b2))
+ - workaround for Cortex A78 AE erratum 2376748 ([92e8708](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/92e870843e9bd654fd1041d66f284c19ca9c0d4f))
+ - workaround for Cortex A78 AE erratum 2395408 ([3f4d81d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3f4d81dfd26649fbcbbbe993a9f0236f5bb07c8a))
+ - workaround for Cortex X2 erratum 2002765 ([34ee76d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/34ee76dbdfeee85f123cb903ea95dbee5e9a44a5))
+ - workaround for Cortex X2 erratum 2058056 ([e16045d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e16045de50e8b430e6601ba0e1e47097d8310f3d))
+ - workaround for Cortex X2 erratum 2083908 ([1db6cd6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1db6cd60279e2d082876692a65cf9c532f506a69))
+ - workaround for Cortex-A510 erratum 1922240 ([8343563](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/83435637bfafbf1ce642a5fabb52e8d7b2819e36))
+ - workaround for Cortex-A510 erratum 2041909 ([e72bbe4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e72bbe47ba7f2a0087654fd99ae24b5b7b444943))
+ - workaround for Cortex-A510 erratum 2042739 ([d48088a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d48088acbe400133037ae74acf1b722b059119bb))
+ - workaround for Cortex-A510 erratum 2172148 ([c0959d2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c0959d2c460cbf7c14e7ba2a57d69ecddae80fd8))
+ - workaround for Cortex-A510 erratum 2218950 ([cc79018](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cc79018b71e45acb524fc5d429d394497ad53646))
+ - workaround for Cortex-A510 erratum 2250311 ([7f304b0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7f304b02a802b7293d7a8b4f4030c5ff00158404))
+ - workaround for Cortex-A510 erratum 2288014 ([d5e2512](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d5e2512c6b86409686f5d1282922ebdf72459fc2))
+ - workaround for Cortex-A710 erratum 2008768 ([af220eb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/af220ebbe467aa580e6b9ba554676f78ffec930f))
+ - workaround for Cortex-A710 erratum 2136059 ([8a855bd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8a855bd24329e081cf13a257c7d2dc3ab4e5dcca))
+ - workaround for Cortex-A78 erratum 2376745 ([5d796b3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5d796b3a25150faff68013880f5a9350cbc53889))
+ - workaround for Cortex-A78 erratum 2395406 ([3b577ed](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3b577ed53d104cfb324390b7519da5e7744d1001))
+ - workaround for Cortex-X2 errata 2017096 ([e7ca443](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e7ca4433fa591233e7e2912b689ab56e531f9775))
+ - workaround for Cortex-X2 errata 2081180 ([c060b53](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c060b5337a43cd42f55b99d83096bb44b51b5335))
+ - workaround for Cortex-X2 erratum 2147715 ([63446c2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/63446c27d11453faacfddecffa44d3880615d412))
+ - workaround for Cortex-X2 erratum 2216384 ([4dff759](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4dff7594f94f1e788aef709cc5b3d079693b6242))
+ - workaround for DSU-110 erratum 2313941 ([7e3273e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7e3273e8e4dca44e7cb88a827b94e662fa8f83e9))
+ - workaround for Rainier erratum 1868343 ([a72144f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a72144fb7a30c2782a583a3b0064e741d1fe2c9f))
+ - workarounds for cortex-x1 errata ([7b76c20](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7b76c20d8eb4271b381371ce0d510fbe6ad825bf))
+ - use CPU_NO_EXTRA3_FUNC for all variants ([b2ed998](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b2ed99894d326993961680fb8e786c267a712400))
+
+ - **EL3 Runtime**
+
+ - set unset pstate bits to default ([7d33ffe](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7d33ffe4c116506ed63e820d5b6edad81680cd11))
+
+ - **Context Management**
+
+ - add barrier before el3 ns exit ([0482503](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/04825031b2384a08504821f39e98e23bb6f93f11))
+ - remove registers accessible only from secure state from EL2 context ([7f41bcc](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7f41bcc76d8857b4678c90796ebd85794ff3ee5f))
+ - refactor the cm_setup_context function ([2bbad1d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2bbad1d126248435e26f9d0d9f5920d8806148d7))
+ - remove initialization of EL2 registers when EL2 is used ([fd5da7a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fd5da7a84731e9687f56c263ff3aa8ebed75075a))
+ - add cm_prepare_el3_exit_ns function ([8b95e84](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8b95e8487006ff77a7d84fba5bd20ba7e68d8330))
+ - refactor initialization of EL1 context registers ([b515f54](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b515f5414b00a8b7ca9b21363886ea976bd19914))
+
+ - **FCONF**
+
+ - correct image_id type in messages ([cec2fb2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cec2fb2b1a8359bf1f349a5b8c8a91a1845f4ca1))
+
+ - **PSCI**
+
+ - correct parent_node type in messages ([b9338ee](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b9338eee7fbcac7f4b55f27b064572e847810422))
+
+ - **GPT**
+
+ - rework delegating/undelegating sequence ([6a00e9b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6a00e9b0c8c37fc446f83ef63e95a75353e31e8b))
+
+ - **Translation Tables**
+
+ - fix bug on VERBOSE trace ([956d76f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/956d76f69d0c96829784c5a6d16aa79e4e0ecab1))
+
+ - **Standard C Library**
+
+ - correct some messages ([a211fde](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a211fde940d4dbd8e95e4f352af2a066a4f89f30))
+ - fix snprintf corner cases ([c1f5a09](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c1f5a0925ddf84981d9e176d146bfddb48eb45d1))
+ - limit snprintf radix value ([b30dd40](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b30dd4030dcef950eac05393013ee019c3cb3205))
+ - snprintf: include stdint.h ([410c925](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/410c925ab31693dc74d654ff9167c8eed3ec5a62))
+
+ - **Locks**
+
+ - add __unused for clang ([5a030ce](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5a030ce4aed271344087bca723903e10fef59ac9))
+
+- **Drivers**
+
+ - **FWU**
+
+ - rename is_fwu_initialized ([aae7c96](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/aae7c96de63914c954f0fc64cd795844832483fc))
+
+ - **I/O**
+
+ - **MTD**
+
+ - correct types in messages ([6e86b46](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6e86b462490429fee6db877338a649b0e199b0ec))
+
+ - **Measured Boot**
+
+ - add RMM entry to event_log_metadata ([f4e3e1e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f4e3e1e85f64d8930e89c1396bc9785512f656bd))
+
+ - **MTD**
+
+ - correct types in messages ([6e86b46](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6e86b462490429fee6db877338a649b0e199b0ec))
+
+ - **SCMI**
+
+ - add missing \n in ERROR message ([0dc9f52](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0dc9f52a2a9f0b9686c65dd60c84e0bcca552144))
+ - make msg_header variable volatile ([99477f0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/99477f051ef857a1e0600cb98858fc74c007e1ff))
+ - use same type for message_id ([2355ebf](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2355ebff6f6312086868f44b8ad7f821f6385208))
+
+ - **UFS**
+
+ - delete call to inv_dcache_range for utrd ([c5ee858](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c5ee8588bf9a36075723e5aacceefa93fd2de8c9))
+ - disables controller if enabled ([b3f03b2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b3f03b20135fc5fcd5e6ec7e5ca49f1e59b5602e))
+ - don't zero out buf before ufs read ([2ef6b8d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2ef6b8d378e7f7c1b1eb7abe176989c3f996f2dc))
+ - don't zero out the write buffer ([cd3ea90](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cd3ea90b200534b8c9d81619731c9ce198478a3c))
+ - fix cache maintenance issues ([38a5ecb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/38a5ecb756e217a80ed951747797ab150449ee9b))
+ - move nutrs assignment to ufs_init ([0956319](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0956319b580726029ddc4e00cde6c5a348b99052))
+ - read and write attribute based on spec ([a475518](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a475518337e15935469543b1cce353e5b337ef52))
+
+ - **Arm**
+
+ - **GIC**
+
+ - **GICv3**
+
+ - fix iroute value wrong issue ([65bc2d2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/65bc2d224b836c230888796c4eda455997dccd8b))
+
+ - **TZC**
+
+ - **TZC-400**
+
+ - correct message with filter ([bdc88d2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bdc88d2154448957f452cb472ff95ccec5808ca1))
+
+ - **Marvell**
+
+ - **COMPHY**
+
+ - change reg_set() / reg_set16() to update semantics ([95c26d6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/95c26d6489bd8b2fc8b8e14bc2da5d2918055acc))
+
+ - **Armada 3700**
+
+ - drop MODE_REFDIV constant ([9fdecc7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9fdecc72f0fce17ca2cd8e4c3b26c01262166d10))
+ - fix comment about COMPHY status register ([4bcfd8c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4bcfd8c02e3e3aa27b55dedeed11fb16bac991a9))
+ - fix comments about selector register values ([71183ef](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/71183ef6654c2a485458307a84ce7c473524689a))
+ - fix Generation Setting registers names ([e5a2aac](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e5a2aac5bbc6dedb20edcc8e7850be2813cb668b))
+ - fix PIN_PU_IVREF register name ([c9f138e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c9f138ebfef90d5b7b5651f06efd81bcbc55366b))
+ - fix reference clock selection value names ([6ba97f8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6ba97f83dbb314b076588b97415a4078924e1903))
+ - fix SerDes frequency register value name ([bdcf44f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bdcf44f1af496e06b693b781fe16bbc2a05fa365))
+ - use reg_set() according to update semantics ([4d01bfe](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4d01bfe66522b13f0d9042206e986551c94fc01e))
+
+ - **Armada**
+
+ - **A3K**
+
+ - **A3720**
+
+ - configure UART after TX FIFO reset ([15546db](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/15546dbf40e5ea81a982a1e6d1e5ba729b06ae51))
+ - do external reset during initialization ([0ee80f3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0ee80f35a28d651d243a6d56678800f9697d14c0))
+
+ - **NXP**
+
+ - ddr: corrects mapping of HNFs nodes ([e3a2349](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e3a234971abb2402cbf376eca6fcb657a7709fae))
+
+ - **QSPI**
+
+ - fix include path for QSPI driver ([ae95b17](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ae95b1782b7a3ab9bbe46ae9ab31f48fb6ebe137))
+
+ - **NXP Crypto**
+
+ - refine code to avoid hang issue for some of toolchain ([fa7fdfa](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fa7fdfabf07d91439b0869ffd8e805f0166294bf))
+
+ - **DDR**
+
+ - fix coverity issue ([f713e59](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f713e5954e0906443cd20ae97e229ddbb9ab7005))
+
+ - **ST**
+
+ - **Clock**
+
+ - check _clk_stm32_get_parent return ([b8eab51](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b8eab512bf9d253f96b0333ee0f1bffa1afc3170))
+ - correct stm32_clk_parse_fdt_by_name ([7417cda](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7417cda6aeaf6abf48dfbe22dc965b626f61c613))
+ - correct types in error messages ([44fb470](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/44fb470b7f298645ac31ada4491553824d77d934))
+ - initialize pllcfg table ([175758b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/175758b2777eb6df3c4aefd79448e97e76a15272))
+ - print enums as unsigned ([9fa9a0c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9fa9a0c55cc830e609415d2cedd2d34fcbec1008))
+
+ - **DDR**
+
+ - add missing debug.h ([15ca2c5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/15ca2c5e14abe415e70d08fb595973dd3e3b0af9))
+ - correct DDR warnings ([a078134](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a078134e2305ca5695731bc275a5ca892cc38880))
+
+ - **FMC**
+
+ - fix type in message ([afcdc9d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/afcdc9d8d71e2b60071d3d34704f0e598e67a514))
+
+ - **SDMMC2**
+
+ - check regulator enable/disable return ([d50e7a7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d50e7a71cb5f8ecfbe2eb69c163d532bab82cbf0))
+ - correct cmd_idx type in messages ([bc1c98a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bc1c98a8c79b6f72395123ea8ed857a488746d4b))
+
+ - **ST PMIC**
+
+ - add static const to pmic_ops ([57e6018](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/57e6018305a97f4e3627d16d8b1886419f274b4a))
+ - correct verbose message ([47065ff](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/47065ffe44c701b231322ec7160c8624d50a9deb))
+
+ - **SPI**
+
+ - always check SR_TCF flags in stm32_qspi_wait_cmd() ([55de583](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/55de58323e458b38b455439a8846cb663deb5508))
+ - remove SR_BUSY bit check before sending command ([5993b91](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5993b9157fd049d06194083032771ffcf73da086))
+
+ - **UART**
+
+ - correctly fill BRR register ([af7775a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/af7775ab535138ff49643f749110dca143d4122c))
+
+ - **USB**
+
+ - correct type in message ([bd9cd63](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bd9cd63ba096cb16161efa4df40f957421660df1))
+
+- **Miscellaneous**
+
+ - **AArch64**
+
+ - fix encodings for MPAMVPM* registers ([e926558](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e92655849d0a9e5893eb2d7e5f42cf8b931d4db6))
+
+ - **FDTs**
+
+ - **STM32MP1**
+
+ - correct memory mapping for STM32MP13 ([99605fb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/99605fb1166794db1dedf1b7280cb184945c229c))
+ - remove mmc1 alias if not needed ([a0e9724](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a0e972438b99012da422411c8e504a19bdad44a2))
+
+ - **PIE**
+
+ - align fixup_gdt_reloc() for aarch64 ([5ecde2a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5ecde2a271ac0f3762c16f5a277a70e55e172f0b))
+ - do not skip __RW_END__ address during relocation ([4f1a658](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4f1a658f899a169e702b1c7146b59f7c04b0338b))
+
+ - **Security**
+
+ - apply SMCCC_ARCH_WORKAROUND_3 to A73/A75/A72/A57 ([9b2510b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9b2510b69de26cc7f571731b415f6dec82669b6c))
+ - loop workaround for CVE-2022-23960 for Cortex-A76 ([a10a5cb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a10a5cb609045de216c01111ec3fcf09a092da0b))
+ - report CVE 2022 23960 missing for aarch32 A57 and A72 ([2e5d7a4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2e5d7a4b6b26d9d8b6c8e580c33d877e591b1fb3))
+ - update Cortex-A15 CPU lib files for CVE-2022-23960 ([187a617](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/187a61761ef5d59bed0c94cca725bd6f116f64d0))
+ - workaround for CVE-2022-23960 ([c2a1521](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c2a15217c3053117f4d39233002cb1830fa96670))
+ - workaround for CVE-2022-23960 ([1fe4a9d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1fe4a9d181ead0dcb2bc494e90552d3e7f0aaf4c))
+ - workaround for CVE-2022-23960 for A76AE, A78AE, A78C ([5f802c8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5f802c8832f3c5824ca6de17593205ebbf8bf585))
+ - workaround for CVE-2022-23960 for Cortex-A57, Cortex-A72 ([be9121f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/be9121fd311ff48c94f3d90fe7efcf84586119e4))
+ - workaround for CVE-2022-23960 for Cortex-X1 ([e81e999](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e81e999b9da33ab5d2d3e5185b1ad7c46046329c))
+
+- **Tools**
+
+ - **NXP Tools**
+
+ - fix create_pbl print log ([31af441](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/31af441a0445d4a5e88ddcc371c51b3701c25839))
+ - fix tool location path for byte_swape ([a89412a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a89412a649020367a3ed0f87658ee131cd3dcd18))
+
+ - **Firmware Image Package Tool**
+
+ - avoid packing the zero size images in the FIP ([ab556c9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ab556c9c646f1b5f1b500449a5813a4eecdc0302))
+ - respect OPENSSL_DIR ([0a956f8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0a956f81805b46b1530f30dd79d16950dc491a7b)
+
+ - **Secure Partition Tool**
+
+ - add leading zeroes in UUID conversion ([b06344a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b06344a3f2c5a0fede3646627f37d1fce3d3d585))
+ - update Optee FF-A manifest ([ca0fdbd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ca0fdbd8e0d625ece0f87ca16eacabf13db70921))
+
+ - **Certificate Creation Tool**
+
+ - let distclean Makefile target remove the cert_create tool ([e15591a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e15591aaf47ab45941f0d7a03abf3e4a830ac1d9))
+
+- **Dependencies**
+
+ - **commitlint**
+
+ - change scope-case to lower-case ([804e52e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/804e52e9a770de72913f27b5bc9e7dd965e114c5))
+
+## [2.6.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/v2.5..refs/tags/v2.6) (2021-11-22)
+
+### âš  BREAKING CHANGES
+
+- **Architecture**
+
+ - **Activity Monitors Extension (FEAT_AMU)**
+
+ - The public AMU API has been reduced to enablement only
+ to facilitate refactoring work. These APIs were not previously used.
+
+ **See:** privatize unused AMU APIs ([b4b726e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b4b726ea868359cf683c07337b69fe91a2a6929a))
+
+ - The `PLAT_AMU_GROUP1_COUNTERS_MASK` platform definition
+ has been removed. Platforms should specify per-core AMU counter masks
+ via FCONF or a platform-specific mechanism going forward.
+
+ **See:** remove `PLAT_AMU_GROUP1_COUNTERS_MASK` ([6c8dda1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6c8dda19e5f484f8544365fd71d965f0afc39244))
+
+- **Libraries**
+
+ - **FCONF**
+
+ - FCONF is no longer added to BL1 and BL2 automatically
+ when the FCONF Makefile (`fconf.mk`) is included. When including this
+ Makefile, consider whether you need to add `${FCONF_SOURCES}` and
+ `${FCONF_DYN_SOURCES}` to `BL1_SOURCES` and `BL2_SOURCES`.
+
+ **See:** clean up source collection ([e04da4c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e04da4c8e132f43218f18ad3b41479ca54bb9263))
+
+- **Drivers**
+
+ - **Arm**
+
+ - **Ethos-N**
+
+ - multi-device support
+
+ **See:** multi-device support ([1c65989](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1c65989e70c9734defc666e824628620b2060b92))
+
+### New Features
+
+- **Architecture**
+
+ - **Activity Monitors Extension (FEAT_AMU)**
+
+ - enable per-core AMU auxiliary counters ([742ca23](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/742ca2307f4e9f82cb2c21518819425e5bcc0f90))
+
+ - **Support for the `HCRX_EL2` register (FEAT_HCX)**
+
+ - add build option to enable FEAT_HCX ([cb4ec47](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cb4ec47b5c73e04472984acf821e6be41b98064f))
+
+ - **Scalable Matrix Extension (FEAT_SME)**
+
+ - enable SME functionality ([dc78e62](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/dc78e62d80e64bf4fe5d5bf4844a7bd1696b7c92))
+
+ - **Scalable Vector Extension (FEAT_SVE)**
+
+ - enable SVE for the secure world ([0c5e7d1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0c5e7d1ce376cabcebebc43dbf238fe4482ab2dc))
+
+ - **System Register Trace Extensions (FEAT_ETMv4, FEAT_ETE and FEAT_ETEv1.1)**
+
+ - enable trace system registers access from lower NS ELs ([d4582d3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d4582d30885673987240cf01fd4f5d2e6780e84c))
+ - initialize trap settings of trace system registers access ([2031d61](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2031d6166a58623ae59034bc2353fcd2fabe9c30))
+
+ - **Trace Buffer Extension (FEAT_TRBE)**
+
+ - enable access to trace buffer control registers from lower NS EL ([813524e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/813524ea9d2e4138246b8f77a772299e52fb33bc))
+ - initialize trap settings of trace buffer control registers access ([40ff907](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/40ff90747098ed9d2a09894d1a886c10ca76cee6))
+
+ - **Self-hosted Trace Extension (FEAT_TRF)**
+
+ - enable trace filter control register access from lower NS EL ([8fcd3d9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8fcd3d9600bb2cb6809c6fc68f945ce3ad89633d))
+ - initialize trap settings of trace filter control registers access ([5de20ec](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5de20ece38f782c8459f546a08c6a97b9e0f5bc5))
+
+ - **RME**
+
+ - add context management changes for FEAT_RME ([c5ea4f8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c5ea4f8a6679131010636eb524d2a15b709d0196))
+ - add ENABLE_RME build option and support for RMM image ([5b18de0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5b18de09e80f87963df9a2e451c47e2321b8643a))
+ - add GPT Library ([1839012](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1839012d5b5d431f7ec307230eae9890a5fe7477))
+ - add Realm security state definition ([4693ff7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4693ff7225faadc5ad1bcd1c2fb3fbbb8fe1aed0))
+ - add register definitions and helper functions for FEAT_RME ([81c272b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/81c272b3b71af38bc5cfb10bbe5722e328a1578e))
+ - add RMM dispatcher (RMMD) ([77c2775](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/77c2775323a5ff8b77230f05c0cc57f830e9f153))
+ - add Test Realm Payload (TRP) ([50a3056](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/50a3056a3cd33d395e8712e1d1e67a8840bf3db1))
+ - add xlat table library changes for FEAT_RME ([3621823](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/362182386bafbda9e6671be921fa30cc20610d30))
+ - disable Watchdog for Arm platforms if FEAT_RME enabled ([07e96d1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/07e96d1d2958b6f121476fd391ac67bf8c2c4735))
+ - run BL2 in root world when FEAT_RME is enabled ([6c09af9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6c09af9f8b36cdfa1dc4d5052f7e4792f63fa88a))
+
+- **Platforms**
+
+ - **Allwinner**
+
+ - add R329 support ([13bacd3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/13bacd3bc3e6b76009adf9183e5396b6457eb12c))
+
+ - **Arm**
+
+ - add FWU support in Arm platforms ([2f1177b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2f1177b2b9ebec3b2fe92607cd771bda1dc9cbfc))
+ - add GPT initialization code for Arm platforms ([deb4b3a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/deb4b3a63e3a52f2e9823865a1932f6289ccb7ac))
+ - add GPT parser support ([ef1daa4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ef1daa420f7b2920b2ee35379de2aefed6ab2605))
+ - enable PIE when RESET_TO_SP_MIN=1 ([7285fd5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7285fd5f9aa6d9cc0e0f1dc9c71785b46a88d999))
+
+ - **FPGA**
+
+ - add ITS autodetection ([d7e39c4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d7e39c43f2f58aabb085ed7b8f461f9ece6002d0))
+ - add kernel trampoline ([de9fdb9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/de9fdb9b5925ae08137d4212a85e9a1d319509c9))
+ - determine GICR base by probing ([93b785f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/93b785f5ae66a6418581c304c83a346e8baa5aa3))
+ - query PL011 to learn system frequency ([d850169](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d850169c9c233c4bc413d8319196557b54683688))
+ - support GICv4 images ([c69f815](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c69f815b09ab85d3ace8fd2979ffafb1184ec76c))
+ - write UART baud base clock frequency into DTB ([422b44f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/422b44fb56db7ca8b1a2f9f706733d7d4c2fdeb1))
+
+ - **FVP**
+
+ - enable external SP images in BL2 config ([33993a3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/33993a3737737a03ee5a9d386d0a027bdc947c9c))
+ - add memory map for FVP platform for FEAT_RME ([c872072](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c8720729726faffc39ec64f3a02440a48c8c305a))
+ - add RMM image support for FVP platform ([9d870b7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9d870b79c16ef09b0c4a9db18e071c2fa235d1ad))
+ - enable trace extension features by default ([cd3f0ae](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cd3f0ae6f855b2998bc09e5c3a458528c92acb90))
+ - pass Event Log addr and size from BL1 to BL2 ([0500f44](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0500f4479eb1d0d5ab9e83dac42b633a5ff677dd))
+
+ - **FVP-R**
+
+ - support for TB-R has been added
+ - configure system registers to boot rich OS ([28bbbf3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/28bbbf3bf583e0c85004727e694455dfcabd50a4))
+
+ - **RD**
+
+ - **RD-N2**
+
+ - add support for variant 1 of rd-n2 platform ([fe5d5bb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fe5d5bbfe6bd0f386f92bdc419a7e04d885d5b43))
+ - add tzc master source ids for soc dma ([3139270](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3139270693ab0fc6d66fed4fe11e183829b47e2e))
+
+ - **SGI**
+
+ - add CPU specific handler for Neoverse N2 ([d932a58](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d932a5831e26620d61d171d0fd8bc2f14938e6f1))
+ - add CPU specific handler for Neoverse V1 ([cbee43e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cbee43ebd69377bce1c4fa8d40c6fd67f2be2ee4))
+ - increase max BL2 size ([7186a29](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7186a29bbfe3044d5e8001ddfe1d9238578e0944))
+ - enable AMU for RD-V1-MC ([e8b119e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e8b119e03ad9de5fc440e5929287c94c22fc3946))
+ - enable use of PSCI extended state ID format ([7bd64c7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7bd64c70e91f73a236b84fb51d5045e308479b5a))
+ - introduce platform variant build option ([cfe1506](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cfe1506ee8303d9e0714b3a5b2cd165f76ad5d11))
+
+ - **TC**
+
+ - enable MPMM ([c19a82b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c19a82bef08df58350f1b6668e0604ff8a5bd46d))
+ - Enable SVE for both secure and non-secure world ([10198ea](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/10198eab3aa7b0eeba10d9667197816b052ba3e4))
+ - populate HW_CONFIG in BL31 ([34a87d7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/34a87d74d9fbbe8037431ea5101110a9f1cf30e1))
+ - introduce TC1 platform ([6ec0c65](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6ec0c65b09745fd0f4cee44ee3aa99870303f448))
+ - add DRAM2 to TZC non-secure region ([76b4a6b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/76b4a6bb208c22b1c5971964a209ff7d54982348))
+
+ - add bootargs node ([4a840f2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4a840f27cd7a05d8e3687aa325adcd019c0d22ee))
+ - add cpu capacity to provide scheduling information ([309f593](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/309f5938e610c73cb51b3ba175fed971f49d0888))
+ - add Ivy partition ([a19bd32](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a19bd32ed14c33571f3715198d47bac9d0f2808e))
+ - add support for trusted services ([ca93248](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ca9324819ee308f9b3a4bb004f02a512c8f301f6))
+ - update Matterhorn ELP DVFS clock index ([a2f6294](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a2f6294c98935895d4592ef7e30058ca6e995f4b))
+ - update mhuv2 dts node to align with upstream driver ([63067ce](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/63067ce87e4afa193b2c7f6a4917d1e54b61b000))
+
+ - **Diphda**
+
+ - adding the diphda platform ([bf3ce99](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bf3ce9937182e5d8d91e058baabb8213acedacdb))
+ - disabling non volatile counters in diphda ([7f70cd2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7f70cd29235cc5e96ff6b5f509c7e4260bec5610))
+ - enabling stack protector for diphda ([c7e4f1c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c7e4f1cfb84136a7521f26e403a6635ffdce4a2b))
+
+ - **Marvell**
+
+ - introduce t9130_cex7_eval ([d01139f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d01139f3b59a1bc6542e74f52ff3fb26eea23c69))
+
+ - **Armada**
+
+ - **A8K**
+
+ - allow overriding default paths ([0b702af](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0b702afc3aabc349a513a5b00397b58a62fea634))
+
+ - **MediaTek**
+
+ - enable software reset for CIRQ ([b3b162f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b3b162f3b48e087f6656513862a6f9e1fa0757b1))
+
+ - **MT8192**
+
+ - add DFD control in SiP service ([5183e63](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5183e637a0496ad8dfbd8c892bc874ac6a1531bf))
+
+ - **MT8195**
+
+ - add DFD control in SiP service ([3b994a7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3b994a75306cc487144dd8e2e15433799e62e6f2))
+ - add display port control in SiP service ([7eb4223](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7eb42237575eb3f241c9b22efc5fe91368470aa6))
+ - remove adsp event from wakeup source ([c260b32](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c260b3246b6be27c7463d36ce7f76368c94a8540))
+ - add DCM driver ([49d3bd8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/49d3bd8c4c80ecd19ecfd74812ff1eaa01478cdd))
+ - add EMI MPU basic drivers ([75edd34](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/75edd34ade8efaa8a76c5fd59103454023632989))
+ - add SPM suspend driver ([859e346](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/859e346b89461f31df17b76ef25ce9e8d2a7279d))
+ - add support for PTP3 ([0481896](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/048189637ead887787bd5bc47b1dfab98f321705))
+ - add vcore-dvfs support ([d562130](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d562130ea9637b885135a5efe41cb98f2365754f))
+ - support MCUSYS off when system suspend ([d336e09](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d336e093dd9ec917ce69484eae8914d98efa328d))
+
+ - **NXP**
+
+ - add build macro for BOOT_MODE validation checking ([cd1280e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cd1280ea2e5c8be6f28485a2d5054d06e54e74c1))
+ - add CCI and EPU address definition ([6cad59c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6cad59c429b4382ad62aee3a67fa1b3fd4ad38b7))
+ - add EESR register definition ([8bfb168](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8bfb16813aff9b3dcbeaa2f77027d44b97f04b6d))
+ - add SecMon register definition for ch_3_2 ([66f7884](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/66f7884b5229b1d2977d73d105af1c34cb55f95d))
+ - define common macro for ARM registers ([35efe7a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/35efe7a4cea4b3c55b661aac49ef1a85ca8feaa9))
+ - define default PSCI features if not defined ([a204785](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a2047853224083328ef67cacbc17a2001ba14701))
+ - define default SD buffer ([4225ce8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4225ce8b87635287ecf5cd3baaf31ea703a2640b))
+
+ - **i.MX**
+
+ - **i.MX 8M**
+
+ - add sdei support for i.MX8MN ([ce2be32](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ce2be321e8a5865871810b36c580181ea95a1a64))
+ - add sdei support for i.MX8MP ([6b63125](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6b63125c415491417e1c389e4015be5ebdee2841))
+ - add SiP call for secondary boot ([9ce232f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9ce232fe985a0bb308af459ede8a22629255d4e7))
+ - add system_reset2 implementation ([60a0dde](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/60a0dde91bd03f4011c1d52d4d3aea8166e939a0))
+
+ - **i.MX 8M Mini**
+
+ - enlarge BL33 (U-boot) size in FIP ([d53c9db](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d53c9dbf9ff9c435552b62f47fb95bfe86d025e3))
+
+ - **i.MX 8M Plus**
+
+ - add imx8mp_private.h to the build ([91566d6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/91566d663b26434813fa674412bb695be1965557))
+ - add in BL2 with FIP ([75fbf55](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/75fbf5546b7beca93e4782bc35906f9536392e04))
+ - add initial definition to facilitate FIP layout ([f696843](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f696843eab5cf0547b6c6307eaccea25678654c4))
+ - enable Trusted Boot ([a16ecd2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a16ecd2cff36b3a8a76d223f4e272e165c941b31))
+
+ - **Layerscape**
+
+ - add ls1028a soc and board support ([52a1e9f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/52a1e9ff37251987b71b743951038cd8d1fa0ba4))
+
+ - **LX2**
+
+ - add SUPPORTED_BOOT_MODE definition ([28b3221](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/28b3221aebdd48577e2288a75cd2f7547da514e9))
+
+ - **LS1028A**
+
+ - add ls1028a soc support ([9d250f0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9d250f03d7a38cac86655495879b2151b877db0d))
+
+ - **LS1028ARDB**
+
+ - add ls1028ardb board support ([34e2112](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/34e2112d1a3a8e4ea33a24bdc6505518266333a9))
+
+ - **QTI**
+
+ - **SC7280**
+
+ - add support for pmk7325 ([b8a0511](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b8a05116ed2a87a9689c4f9be6218a4bce88034a))
+ - support for qti sc7280 plat ([46ee50e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/46ee50e0b34e19d383a28bc3b3dadbfb4c07b270))
+
+ - **Renesas**
+
+ - **R-Car**
+
+ - change process for Suspend To RAM ([731aa26](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/731aa26f38d76645b6d50077c28dffb9b02dd08a))
+
+ - **R-Car 3**
+
+ - add a DRAM size setting for M3N ([f95d551](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f95d551217a287bd909aa3c82f4ade4986ad7244))
+ - add new board revision for Salvator-XS/H3ULCB ([4379a3e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4379a3e9744cf3b0844446335aca40357a889b9a))
+ - add optional support for gzip-compressed BL33 ([ddf2ca0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ddf2ca03979ea9fad305b1bc59beb6e27f0e1c02))
+ - add process of SSCG setting for R-Car D3 ([14f0a08](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/14f0a0817297905c03ddf2c4c6040482ef71d744))
+ - add process to back up X6 and X7 register's value ([7d58aed](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7d58aed3b05fa8c677a7c823c1ca5017a462a3d3))
+ - add SYSCEXTMASK bit set/clear in scu_power_up ([63a7a34](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/63a7a34706eedba4d13ce6fc661a634801cf8909))
+ - apply ERRATA_A53_1530924 and ERRATA_A57_1319537 ([2892fed](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2892fedaf27d8bbc68780a4a2c506c768e81b9f1))
+ - change the memory map for OP-TEE ([a4d821a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a4d821a5a625d941f95ec39fb51ac4fc07c46c5c))
+ - emit RPC status to DT fragment if RPC unlocked ([12c75c8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/12c75c8886a0ee69d7e279a48cbeb8d1602826b3))
+ - keep RWDT enabled ([8991086](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/899108601a0c3b08ead5e686d92ea0794700ff35))
+ - modify LifeC register setting for R-Car D3 ([5460f82](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5460f82806752e419fdd6862e8ca9c5fefbee3f2))
+ - modify operation register from SYSCISR to SYSCISCR ([d10f876](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d10f87674ecee54cffe1ab554cc05733fd16c7f0))
+ - modify SWDT counter setting for R-Car D3 ([053c134](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/053c134683cf74fbf4efad311815b806821f1436))
+ - remove access to RMSTPCRn registers in R-Car D3 ([71f2239](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/71f2239f53cd3137ad6abdaf0334dc53f2f21cb1))
+ - update DDR setting for R-Car D3 ([042d710](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/042d710d1d917357c5142b340c79978264d3afb1))
+ - update IPL and Secure Monitor Rev.3.0.0 ([c5f5bb1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c5f5bb17abfcf6c0eeb3e6c3d70499de0bd6abc0))
+ - use PRR cut to determine DRAM size on M3 ([42ffd27](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/42ffd279dd1a686b19e2f1b69d2e35413d5efeba))
+
+ - **ST**
+
+ - add a new DDR firewall management ([4584e01](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4584e01dc643665038004f6c8a4f8bd64e14dacb))
+ - add a USB DFU stack ([efbd65f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/efbd65fa7b5cf70f20d6b18152741ccdf8a65bb6))
+ - add helper to save boot interface ([7e87ba2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7e87ba2598a07facdeb73237dcb350a261ac17b6))
+ - add STM32CubeProgrammer support on USB ([afad521](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/afad5214a79259f56bc2003b00859abfe8a18d4d))
+ - add STM32MP_EMMC_BOOT option ([214c8a8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/214c8a8d08b2b3c24f12cbc69f497f44851ca524))
+ - create new helper for DT access ([ea97bbf](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ea97bbf6a001b270fd0a25b4b0d0c382e277f3f8))
+ - implement platform functions for SMCCC_ARCH_SOC_ID ([3d20178](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3d201787e8246022b1f193283c12e7cb4bfc83ff))
+ - improve FIP image loading from MMC ([18b415b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/18b415be9d631b3e0c3a3caacc5f02edb9413f6b))
+ - manage io_policies with FCONF ([d5a84ee](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d5a84eeaac2c8ce14d3f2662dc9523b4abf41516))
+ - use FCONF to configure platform ([29332bc](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/29332bcd680ce7e5f864813d9a900360f5e35d41))
+ - use FIP to load images ([1d204ee](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1d204ee4ab12893fceb12097bd4f0a074be253b2))
+
+ - **ST32MP1**
+
+ - add STM32MP_USB_PROGRAMMER target ([fa92fef](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fa92fef0a024cdb537fe56c84a0156cc48c1ac2d))
+ - add USB DFU support for STM32MP1 ([942f6be](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/942f6be211d4816ad2568d30d807b8fd53d7f981))
+
+ - **Xilinx**
+
+ - **Versal**
+
+ - add support for SLS mitigation ([302b4df](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/302b4dfb8fb0041959b8593a098ccae6c61e3238))
+
+ - **ZynqMP**
+
+ - add support for runtime feature config ([578f468](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/578f468ac058bbb60b08f78e2aa2c20cdc601620))
+ - sync IOCTL IDs ([38c0b25](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/38c0b2521a0ea0951f4e1ee678ccdbce5fc07a98))
+ - add SDEI support ([4143268](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4143268a5ca8f91f1014e0d83edf766946ffff76))
+ - add support for XCK26 silicon ([7a30e08](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7a30e08b70e7fbb745554d500182bb6e258c5ab8))
+ - extend DT description by TF-A ([0a8143d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0a8143dd636d4234dd2e79d32cb49dc80675c68f))
+
+- **Bootloader Images**
+
+ - import BL_NOBITS_{BASE,END} when defined ([9aedca0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9aedca021d917c7435aa2a0405972aa9d44493a2))
+
+- **Services**
+
+ - **FF-A**
+
+ - adding notifications SMC IDs ([fc3f480](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fc3f480023e3a52460add25f18dd550dde44d9ff))
+ - change manifest messaging method ([bb320db](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bb320dbc4751f7ea0c37ffba07d14628e58081d0))
+ - feature retrieval through FFA_FEATURES call ([96b71eb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/96b71eb9597efbf4857216cac1caeefc9e8bbf3e))
+ - update FF-A version to v1.1 ([e1c732d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e1c732d46fa91231b39209621ead1e5a5fb2c497))
+ - add Ivy partition to tb fw config ([1bc02c2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1bc02c2e0f63b6a7863e10cf6189292d42e693db))
+ - add support for FFA_SPM_ID_GET ([70c121a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/70c121a258e43dc2462ed528b44d92594ffb27b3))
+ - route secure interrupts to SPMC ([8cb99c3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8cb99c3fc3539bb9926e73a1c33fd72f424fc453))
+
+- **Libraries**
+
+ - **CPU Support**
+
+ - add support for Hayes CPU ([7bd8dfb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7bd8dfb85a8bf5c22d6a39f4538b89cc748090d1))
+ - add support for Hunter CPU ([fb9e5f7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fb9e5f7bb76e9764b3ecd7973668c851015fa1b4))
+ - add support for Demeter CPU ([f4616ef](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f4616efafbc1004f1330f515b898e7617e338875))
+ - workaround for Cortex A78 AE erratum 1941500 ([47d6f5f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/47d6f5ff16d1f2ad009d630a381054b10fa0a06f))
+ - workaround for Cortex A78 AE erratum 1951502 ([8913047](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8913047a52e646877812617a2d98cff99494487b))
+
+ - **MPMM**
+
+ - add support for MPMM ([6812078](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/68120783d6d6f99c605e9f746ee0e91e2908feb1))
+
+ - **OP-TEE**
+
+ - introduce optee_header_is_valid() ([b84a850](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b84a850864c05fef587fcbb301f955428966de64))
+
+ - **PSCI**
+
+ - require validate_power_state to expose CPU_SUSPEND ([a1d5ac6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a1d5ac6a5aa5d9d18a481de20d272f64a71391f7))
+
+ - **SMCCC**
+
+ - add bit definition for SMCCC_ARCH_SOC_ID ([96b0596](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/96b0596ea25e1f03b862a5bfaa92add6c3e51a33))
+
+- **Drivers**
+
+ - **FWU**
+
+ - add FWU metadata header and build options ([5357f83](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5357f83d4ee89fb831d7e4f6149ae2f652e1b9af))
+ - add FWU driver ([0ec3ac6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0ec3ac60d86b75d132e7a63fc09ea47e67f90bbd))
+ - avoid booting with an alternate boot source ([4b48f7b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4b48f7b56577a78cdc9a2b47280cb62cbae0f7c3))
+ - avoid NV counter upgrade in trial run state ([c0bfc88](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c0bfc88f8e8e03974834cbcacbbfbd5f202a2857))
+ - initialize FWU driver in BL2 ([396b339](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/396b339dc20b97ddd75146e03467a255e28f31b9))
+ - introduce FWU platform-specific functions declarations ([efb2ced](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/efb2ced256dacbab71ca11cbc87f70f413ca6729))
+
+ - **I/O**
+
+ - **MTD**
+
+ - offset management for FIP usage ([9a9ea82](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9a9ea82948fd2f1459b6351cb0641f3f77b4e6de))
+
+ - **Measured Boot**
+
+ - add documentation to build and run PoC ([a125c55](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a125c556230501ee0f5ec9f8b0b721625d484a41))
+ - move init and teardown functions to platform layer ([47bf3ac](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/47bf3ac31ec84d4b221fdef760c04b5f4416cba4))
+ - image hash measurement and recording in BL1 ([48ba034](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/48ba0345f7b42880ec4442d7e90e3e1af95feadd))
+ - update tb_fw_config with event log properties ([e742bcd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e742bcdae0d28dc14a2aa0b4ca30f50420bb5ebe))
+
+ - **MMC**
+
+ - boot partition read support ([5014b52](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5014b52dec0c2527ca85c0fbe9c9281a24cc7b10))
+
+ - **MTD**
+
+ - **NAND**
+
+ - count bad blocks before a given offset ([bc3eebb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bc3eebb25d5ee340e56047d0e46b81d5af85ff17))
+
+ - **SCMI**
+
+ - add power domain protocol ([7e4833c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7e4833cdde8235d228f1f1c40f52b989ad5aa98a))
+
+ - **Arm**
+
+ - **Ethos-N**
+
+ - multi-device support ([1c65989](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1c65989e70c9734defc666e824628620b2060b92))
+
+ - **GIC**
+
+ - **GICv3**
+
+ - detect GICv4 feature at runtime ([858f40e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/858f40e379684fefc8b52c7b9e60576bc3794a69))
+ - introduce GIC component identification ([73a643e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/73a643eed9d88910a09ca666bc7ab7f5e532324e))
+ - multichip: detect GIC-700 at runtime ([feb7081](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/feb7081863f454b9e465efc074ca669f7a4c783d))
+
+ - **GIC-600AE**
+
+ - introduce support for Fault Management Unit ([2c248ad](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2c248ade2e958eed33127b4ea767fbb7499f31a7))
+
+ - **TZC**
+
+ - **TZC-400**
+
+ - update filters by region ([ce7ef9d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ce7ef9d146ce5ca6b9be5ef049377b3817d53d10))
+
+ - **MediaTek**
+
+ - **APU**
+
+ - add mt8192 APU device apc driver ([f46e1f1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f46e1f18539d6d992c82ae605c2cd2a1d0757fa4))
+ - add mt8192 APU iommap regions ([2671f31](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2671f3187249d641c55929c812d6691aeeff502a))
+ - add mt8192 APU SiP call support ([ca4c0c2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ca4c0c2e78eb19d442de4608d9096a755b540a37))
+ - setup mt8192 APU_S_S_4 and APU_S_S_5 permission ([77b6801](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/77b6801966d203e09ca118fad42543e934d73e6f))
+
+ - **EMI MPU**
+
+ - add MPU support for DSP ([6c4973b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6c4973b0a9a75aa83233b696c97d573426eebd98))
+
+ - **NXP**
+
+ - **DCFG**
+
+ - define RSTCR_RESET_REQ ([6c5d140](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6c5d140ed99cfec47b239acc242c0f3db1e3bf7c))
+
+ - **FLEXSPI**
+
+ - add MT35XU02G flash info ([a4f5015](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a4f5015a0080134251e9272719f5dad1ce2aa842))
+
+ - **Renesas**
+
+ - **R-Car3**
+
+ - add extra offset if booting B-side ([993d809](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/993d809cc115ce23dd2df1df19dc8bb548cc19cd))
+ - add function to judge a DDR rank ([726050b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/726050b8e2d2ee2234e103e2df55f9c7f262c851))
+
+ - **ST**
+
+ - manage boot part in io_mmc ([f3d2750](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f3d2750aa2293c0279bc447a85771827ca8b74c1))
+
+ - **USB**
+
+ - add device driver for STM32MP1 ([9a138eb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9a138eb5f29f6747e181a1b3b4199ad57721a3e0))
+
+ - **USB**
+
+ - add a USB device stack ([859bfd8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/859bfd8d42341c6dea2b193db79dc4828e074ad7))
+
+- **Miscellaneous**
+
+ - **Debug**
+
+ - add new macro ERROR_NL() to print just a newline ([fd1360a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fd1360a339e84ccd49f8a2d8a42e4c131a681b3c))
+
+ - **CRC32**
+
+ - **Hardware CRC32**
+
+ - add support for HW computed CRC ([a1cedad](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a1cedadf73863ff103fecd64fa188334e1541337))
+
+ - **Software CRC32**
+
+ - add software CRC32 support ([f216937](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f21693704a7bac275e12b44ae30fd210bc317175))
+
+ - **DT Bindings**
+
+ - add STM32MP1 TZC400 bindings ([43de546](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/43de546b909947ab44f104aaee02b98fba70f44c))
+
+ - **FDT Wrappers**
+
+ - add CPU enumeration utility function ([2d9ea36](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2d9ea360350303e37a8dd39f3599ac88aaef0ff9))
+
+ - **FDTs**
+
+ - add for_each_compatible_node macro ([ff76614](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ff766148b52bfecf09728a83fc3becc7941d943c))
+ - introduce wrapper function to read DT UUIDs ([d13dbb6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d13dbb6f1d5e28737a3319af035a6cb991bc6f8f))
+ - add firewall regions into STM32MP1 DT ([86b43c5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/86b43c58a4105c8cef13d860dd73fa9bd560526a))
+ - add IO policies for STM32MP1 ([21e002f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/21e002fb777fad9d02a94dc961f077fb444517fa))
+ - add STM32MP1 fw-config DT files ([d9e0586](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d9e0586b619b331eb2db75911ca82f927e20bd1c))
+
+ - **STM32MP1**
+
+ - align DT with latest kernel ([e8a953a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e8a953a9b85806f7324c8c7245435d5b9226c279))
+ - delete nodes for non-used boot devices ([4357db5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4357db5b17ce6ba7357dd99276f34ab497ce60ef))
+
+ - **NXP**
+
+ - **OCRAM**
+
+ - add driver for OCRAM initialization ([10b1e13](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/10b1e13bd200849ff134dd8d2fde341a8526f563))
+
+ - **PSCI**
+
+ - define CPUECTLR_TIMER_2TICKS ([3a2cc2e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3a2cc2e262890cffee1fc46835e85be6055189e8))
+
+- **Dependencies**
+
+ - **libfdt**
+
+ - also allow changing base address ([4d585fe](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4d585fe52feb231d5e73ec50a505122d5e9bf450))
+
+### Resolved Issues
+
+- **Architecture**
+
+- **Platforms**
+
+ - print newline before fatal abort error message ([a5fea81](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a5fea8105887d0dd15edf94aebd591b1b6b5ef05))
+
+ - **Allwinner**
+
+ - delay after enabling CPU power ([86a7429](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/86a7429e477786dad6fab002538aef825f4ca35a))
+
+ - **Arm**
+
+ - correct UUID strings in FVP DT ([748bdd1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/748bdd19aa27c15438d829bdba42fe4062a265a1))
+ - fix a VERBOSE trace ([5869ebd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5869ebd0e87f1de987e51994103440fa8c77b26f))
+ - remove unused memory node ([be42c4b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/be42c4b4bf3c44f2970b7a1658c46b8d5863cad1))
+
+ - **FPGA**
+
+ - allow build after MAKE_* changes ([9d38a3e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9d38a3e698331e3c8192cc3e0cc8584e6ed987d9))
+ - avoid re-linking from executable ELF file ([a67ac76](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a67ac7648cd814ed8f8d4ece1b265c6d48c6dc81))
+ - Change PL011 UART IRQ ([195381a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/195381a91313bc0bce2cfa087f3c55136a9e8496))
+ - limit BL31 memory usage ([d457230](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d4572303ed45faceffed859955b0e71724fddfd2))
+ - reserve BL31 memory ([13e16fe](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/13e16fee86451e2f871c2aac757b32299fe5ead6))
+ - streamline generated axf file ([9177e4f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9177e4fd9356b0f249be8b6fe14f222e10f1e6cd))
+ - enable AMU extension ([d810e30](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d810e30dd6b47e0725dccbcb42ca0a0c5215ee34))
+ - increase initrd size ([c3ce73b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c3ce73be0bfe31fa28805fe92b3e727232ffd37a))
+
+ - **FVP**
+
+ - fix fvp_cpu_standby() function ([3202ce8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3202ce8bbb4af8580736d2a1634ad45c3f89d931))
+ - spmc optee manifest remove SMC allowlist ([183725b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/183725b39d75e362a32b3c5d0be110c255c56bdd))
+ - allow changing the kernel DTB load address ([672d669](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/672d669d6c72f92c6b81464d1d421e392bc1aa3e))
+ - bump BL2 stack size ([d22f1d3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d22f1d358731f0f55f2f392fa587f0fa8d315aa5))
+ - provide boot files via semihosting ([749d0fa](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/749d0fa80d1c7ca30b4092a381a06deeeaf1747f))
+ - OP-TEE SP manifest per latest SPMC changes ([b7bc51a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b7bc51a7a747bf40d219b2041e5b3ce56737a71b))
+
+ - **FVP-R**
+
+ - fix compilation error in release mode ([7d96e79](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7d96e79a1a2efdf85f1ed46cdd5c577b58054f53))
+
+ - **Morello**
+
+ - initialise CNTFRQ in Non Secure CNTBaseN ([7f2d23d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7f2d23d9d790df90021de6c5165ef10fe5cc5590))
+
+ - **TC**
+
+ - enable AMU extension ([b5863ca](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b5863cab9adb3fed0c1e4dfb92cf906794e7bdb4))
+ - change UUID to string format ([1c19536](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1c1953653c20b4a8c61a7deb3fc493d496d8c478))
+ - remove "arm,psci" from psci node ([814646b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/814646b4cb792ab14df04e28360fefd168399b3c))
+ - remove ffa and optee device tree node ([f1b44a9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f1b44a9050fbc12e8c260107bfff2930476df062))
+ - set cactus-tertiary vcpu count to 1 ([05f667f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/05f667f0c670ba9682050714561309f00210c282))
+
+ - **SGI**
+
+ - avoid redefinition of 'efi_guid' structure ([f34322c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f34322c1cea1e355aeb4133df6aa601d719be5a3))
+
+ - **Marvell**
+
+ - Check the required libraries before building doimage ([dd47809](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/dd47809e9ea75188060bf8b294efa8578d255c63))
+
+ - **Armada**
+
+ - select correct pcie reference clock source ([371648e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/371648e1c76b5230bf8e153629064c02086365c9))
+ - fix MSS loader for A8K family ([dceac43](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/dceac436f620e60cd0149194377871b225216079))
+
+ - **A3K**
+
+ - disable HANDLE_EA_EL3_FIRST by default ([3017e93](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3017e932768c7357a1a41493c58323419e9a1ec9))
+ - enable workaround for erratum 1530924 ([975563d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/975563dbfc012b6e8a7765dd8e48220e1bc53dec))
+ - Fix building uart-images.tgz.bin archive ([d3f8db0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d3f8db07b618e79c05805a1598e5e834e42fea98))
+ - Fix check for external dependences ([2baf503](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2baf50385ba2b460afef4a7919b13b3a350fd03a))
+ - fix printing info messages on output ([9f6d154](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9f6d15408340af07ed3c2500202b147189eaa7ef))
+ - update information about PCIe abort hack ([068fe91](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/068fe919613197bf221c00fb84a1d94c66a7a8ca))
+ - Remove encryption password ([076374c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/076374c9b97d47b10ba5c6034817866c08d66ed4))
+
+ - **A8K**
+
+ - Add missing build dependency for BLE target ([04738e6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/04738e69917f8e8790bf4cf83ceb05f85e1f45bb))
+ - Correctly set include directories for individual targets ([559ab2d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/559ab2df4a35cd82b2a67a0bebeb3028544a6766))
+ - Require that MV_DDR_PATH is correctly set ([528dafc](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/528dafc367c4f49d4904c4335422502dacf469bf))
+ - fix number of CPU power switches. ([5cf6faf](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5cf6fafe223da89c60e2323c242ea188b17e98c3))
+
+ - **MediaTek**
+
+ - **MT8183**
+
+ - fix out-of-bound access ([420c26b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/420c26b33a29c8328a1806ccb2f5a5885041fdfc))
+
+ - **MT8195**
+
+ - use correct print format for uint64_t ([964ee4e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/964ee4e6be70ef638d6c875a761ab5ca359d84fe))
+ - fix error setting for SPM ([1f81ccc](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1f81cccedd40cb397813b0fa826ea1d793b02089))
+ - extend MMU region size ([9ff8b8c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9ff8b8ca9393e31e790eb2c8e7ea5c5f41f45198))
+ - fix coverity fail ([85e4d14](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/85e4d14df157b5641421ea2b844c146ddc230152))
+
+ - **NXP**
+
+ - **i.MX**
+
+ - do not keep mmc_device_info in stack ([99d37c8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/99d37c8cb8196a7296311fb4f97f80f086021c74))
+
+ - **i.MX 8M**
+
+ - **i.MX 8M Mini**
+
+ - fix FTBFS on SPD=opteed ([10bfc77](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/10bfc77e7b3afce17185114ac66361a0914f7784))
+
+ - **Layerscape**
+
+ - **LX2**
+
+ - **LS1028A**
+
+ - define endianness of scfg and gpio ([2475f63](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2475f63bdec6c24c13f7d6ec7f70275b1bde5c15))
+ - fix compile error when enable fuse provision ([a0da9c4](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a0da9c4bd296ec1a47683a1ee05f5d1ed71828c7))
+
+ - **QEMU**
+
+ - (NS_DRAM0_BASE + NS_DRAM0_SIZE) ADDR overflow 32bit ([325716c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/325716c97b7835b8d249f12c1461556bab8c53a0))
+ - reboot/shutdown with low to high gpio ([bd2ad12](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bd2ad12ef10f558a5b15f5768b66e7b2606c6498))
+
+ - **QTI**
+
+ - **SC1780**
+
+ - qti smc addition ([cc35a37](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cc35a3771d28a96906f8d0f393ff664924a2d4dc))
+
+ - **Raspberry Pi**
+
+ - **Raspberry Pi 4**
+
+ - drop /memreserve/ region ([5d2793a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5d2793a61aded9602af86e90a571f64ff07f93b3))
+
+ - **Renesas**
+
+ - **R-Car**
+
+ - change process that copy code to system ram ([49593cc](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/49593cc1ce0d0471aeef7ca24a5415da2dd55bea))
+ - fix cache maintenance process of reading cert header ([c77ab18](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c77ab18ec7c8e0f3d953177b835e004a9b53515f))
+ - fix to load image when option BL2_DCACHE_ENABLE is enabled ([d2ece8d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d2ece8dba2f31091b1fa6c302d4255495bb15705))
+
+ - **R-Car 3**
+
+ - fix disabling MFIS write protection for R-Car D3 ([a8c0c3e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a8c0c3e9d0df2215ed3b9ef66f4596787d957566))
+ - fix eMMC boot support for R-Car D3 ([77ab366](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/77ab3661e55c39694c7ee81de2d1615775711b64))
+ - fix source file to make about GICv2 ([fb3406b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fb3406b6b573cb0b35138ca3c89c5641d3d7b790))
+ - fix version judgment for R-Car D3 ([c3d192b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c3d192b8e52823dcbc32e21e47c30693d38bb49f))
+ - generate two memory nodes for larger than 2 GiB channel 0 ([21924f2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/21924f2466b9b5e1243c142932e6f498da5633e9))
+
+ - **Rockchip**
+
+ - **RK3399**
+
+ - correct LPDDR4 resume sequence ([2c4b0c0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2c4b0c05c6546e24eb7209ffb3bb465d4feed164))
+ - fix dram section placement ([f943b7c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f943b7c8e292e3aad2fcbdd0a37505f62b3b4c87))
+
+ - **Socionext**
+
+ - **Synquacer**
+
+ - update scmi power domain off handling ([f7f5d2c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f7f5d2c4cd209c2d21244da4fa442050eb4531ab))
+
+ - **ST**
+
+ - add STM32IMAGE_SRC ([f223505](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f22350583c2e26ea291eae3dc54db867fdf0d9af))
+ - add UART reset in crash console init ([b38e2ed](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b38e2ed29ef791dad0cb61fed81b74d612f58b01))
+ - apply security at the end of BL2 ([99080bd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/99080bd1273331007f0b2d6f64fed51ac6861bcd))
+ - correct BSEC error code management ([72c7884](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/72c7884092684af4cc3c49e08f913b3ffed783ba))
+ - correct IO compensation disabling ([c2d18ca](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c2d18ca80f4bd32f58ba07f53d9bb2586df18fc0))
+ - correct signedness comparison issue ([5657dec](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5657decc7ffa1376c0a97b6d14ea1428877f5af4))
+ - improve DDR get size function ([91ffc1d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/91ffc1deffa2c1c64efe4dfaf27b78f2621a8b0b))
+ - only check header major when booting ([8ce8918](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8ce89187459ec77dd9ffdffba3a2b77838d51b6d))
+ - panic if boot interface is wrong ([71693a6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/71693a66341e7d9d683ef32981243cb4c4439351))
+ - remove double space ([306dcd6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/306dcd6b0d1981b75e103c560a4034bdaa6862d5))
+
+ - **ST32MP1**
+
+ - add bl prefix for internal linker script ([7684ddd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7684dddcfb14c45bad33b091410a0bf14a3a9830))
+
+ - **Xilinx**
+
+ - **Versal**
+
+ - correct IPI buffer offset ([e1e5b13](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e1e5b1339b9f73f7f1893d8a6d4dfe4b19ba0ad1))
+ - use sync method for blocking calls ([fa58171](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fa58171534976f94b93a44184afd050d8225e404))
+
+ - **ZynqMP**
+
+ - use sync method for blocking calls ([c063c5a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c063c5a4f92d5787536e595ca4906b458b0f26cb))
+
+- **Services**
+
+ - drop warning on unimplemented calls ([67fad51](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/67fad514ee974dcf0252fa0e9219eb3c580eb714))
+
+ - **RME**
+
+ - fixes a shift by 64 bits bug in the RME GPT library ([322b344](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/322b344e30cb87b9293060d5946b3c17fe3b9133))
+
+ - **SPM**
+
+ - do not compile if SVE/SME is enabled ([4333f95](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4333f95bedb5f2b53dcb62e0e9c563794ec33c07))
+ - error macro to use correct print format ([0c23e6f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0c23e6f44d41593b6e7f97594c12b5791bd75189))
+ - revert workaround hafnium as hypervisor ([3221fce](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3221fce842c0b5aea984bb8dbc1393082bd88a58))
+ - fixing coverity issue for SPM Core. ([f7fb0bf](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f7fb0bf77f3434bfb67411cad65e704fdef27f76))
+
+- **Libraries**
+
+ - **LIBC**
+
+ - use long for 64-bit types on aarch64 ([4ce3e99](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4ce3e99a336b74611349595ea7fd5ed0277c3eeb))
+
+ - **CPU Support**
+
+ - correct Demeter CPU name ([4cb576a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4cb576a0c5bd2e7669606996a9f79602596df07c))
+ - workaround for Cortex A78 erratum 2242635 ([1ea9190](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1ea9190c6a4d2299c6dc19adc0bbe93d4f051eff))
+ - workaround for Cortex-A710 erratum 2058056 ([744bdbf](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/744bdbf732ffd2abf84b2431624051e93bc29f7b))
+ - workaround for Neoverse V1 erratum 2216392 ([4c8fe6b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4c8fe6b17fa994a630b2a30f8666df103f2e370d))
+ - workaround for Neoverse-N2 erratum 2138953 ([ef8f0c5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ef8f0c52ddf83e815a029319971682d7a26b6a6f))
+ - workaround for Neoverse-N2 erratum 2138958 ([c948185](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c948185c973c13df36c62c4bcb50e22b14d6e06a))
+ - workaround for Neoverse-N2 erratum 2242400 ([603806d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/603806d1376c4b18211fb1d4cc338153de026c32))
+ - workaround for Neoverse-N2 erratum 2242415 ([5819e23](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5819e23bc47c860872141caf42bddddb1b8679a5))
+ - workaround for Neoverse-N2 erratum 2280757 ([0d2d999](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0d2d99924e1be548e75c46cfd536f7503cf863e0))
+ - rename Matterhorn, Matterhorn ELP, and Klein CPUs ([c6ac4df](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c6ac4df622befb5bb42ac136745094e1498c91d8))
+
+ - **EL3 Runtime**
+
+ - correct CASSERT for pauth ([b4f8d44](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b4f8d44597faf641177134ee08db7c3fcef5aa14))
+ - fix SVE and AMU extension enablement flags ([68ac5ed](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/68ac5ed0493b24e6a0a178171a47db75a31cc423))
+ - random typos in tf-a code base ([2e61d68](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2e61d6871cc310e9404fe5cfa10b9828f1c869a7))
+ - Remove save/restore of EL2 timer registers ([a7cf274](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a7cf2743f3eb487912302aafc748c81bbd1fc603))
+
+ - **OP-TEE**
+
+ - correct signedness comparison ([21d2be8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/21d2be83a2eabb328071e857e538ced3c8351874))
+
+ - **GPT**
+
+ - add necessary barriers and remove cache clean ([77612b9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/77612b90acaffc82cea712f4a431c727bbb968ec))
+ - use correct print format for uint64_t ([2461bd3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2461bd3a89f7f2cdf4a7302536746733970cfe53))
+
+ - **Translation Tables**
+
+ - remove always true check in assert ([74d720a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/74d720a026735263d2f290fd05370dad0d4c7219))
+
+- **Drivers**
+
+ - **Authentication**
+
+ - avoid NV counter upgrade without certificate validation ([a2a5a94](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a2a5a9456969266dc68d5845f31e05be0c3ff2e3))
+
+ - **CryptoCell-713**
+
+ - fix a build failure with CC-713 library ([e5fbee5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e5fbee5085c682ac3438e6f66c8bdaffb6076fa2))
+
+ - **MTD**
+
+ - fix MISRA issues and logic improvement ([5130ad1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5130ad14d52a0196422fed8a7d08e25659890b15))
+ - macronix quad enable bit issue ([c332740](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c3327408eb4b5852c0ed9d8933c35aaa6de34c21))
+
+ - **NAND**
+
+ - **SPI NAND**
+
+ - check correct manufacturer id ([4490b79](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4490b7963303fbe59b07a66c8498a803eb5c239c))
+ - check that parameters have been set ([bc453ab](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bc453ab1b2fd4267d34f2b9587f73b8940ee1538))
+
+ - **SCMI**
+
+ - entry: add weak functions ([b3c8fd5](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b3c8fd5d778144340d289ad4825123106aac4a96))
+ - smt: fix build for aarch64 ([0e223c6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0e223c6a9e5a2d92cae00fdd16a02a3f8971b114))
+ - mention "SCMI" in driver initialisation message ([e0baae7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/e0baae7316bfdf3e49e5e158f79eb80cd51fc700))
+ - relax requirement for exact protocol version ([125868c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/125868c94150f52ff85cdb59aee623ab1f9f259d))
+
+ - **UFS**
+
+ - add reset before DME_LINKSTARTUP ([905635d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/905635d5e74e3c7b7b2412a673009c8aaabb73e1))
+
+ - **Arm**
+
+ - **GIC**
+
+ - **GICv3**
+
+ - add dsb in both disable and enable function of gicv3_cpuif ([5a5e0aa](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5a5e0aac398989536dc4be790820af89da3d093a))
+
+ - **GIC-600AE**
+
+ - fix timeout calculation ([7f322f2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7f322f228e76caa5480f827af0aa6751f00fc1c4))
+
+ - **TZC**
+
+ - **TZC-400**
+
+ - never disable filter 0 ([ef378d3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ef378d3ec1ef9d7c28baef32ed409688e962542b))
+
+ - **Marvell**
+
+ - **COMPHY**
+
+ - fix name of 3.125G SerDes mode ([a669983](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a669983c78828e3f4a4f14b9e5a6ee79dcfde20f))
+
+ - **Armada 3700**
+
+ - configure phy selector also for PCIe ([0f3a122](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0f3a1221093256999af5f2a80e9b3d7231b9f5fb))
+ - fix address overflow ([c074f70](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c074f70ce5d85e1735b589b323fac99d7eb988b5))
+ - handle failures in power functions ([49b664e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/49b664e75f43fda08dddef4f0510d346bdd25565))
+
+ - **CP110**
+
+ - fix error code in pcie power on ([c0a909c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c0a909cdcce2d9a2ceefe672ad2fc1cae7e39ec4))
+
+ - **Armada**
+
+ - **A3K**
+
+ - **A3720**
+
+ - fix configuring UART clock ([b9185c7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b9185c75f7ec2b600ebe0d49281e216a2456b764))
+ - fix UART clock rate value and divisor calculation ([66a7752](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/66a7752834382595d26214783ae4698fd1f00bd6))
+ - fix UART parent clock rate determination ([5a91c43](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5a91c439cbeb1f64b8b9830de91efad5113d3c89))
+
+ - **MediaTek**
+
+ - **PMIC Wrapper**
+
+ - update idle flow ([9ed4e6f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/9ed4e6fb669b8fcafc4e8acfa6a36db305d27ac8))
+
+ - **MT8192**
+
+ - **SPM**
+
+ - add missing bit define for debug purpose ([310c3a2](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/310c3a26e17d99aafc73b3504d0b6dfbdb97fd4c))
+
+ - **NXP**
+
+ - **FLEXSPI**
+
+ - fix warm boot wait time for MT35XU512A ([1ff7e46](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/1ff7e46b092b74891bc2dc7263e4dfae947b2223))
+
+ - **SCFG**
+
+ - fix endianness checking ([fb90cfd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fb90cfd4eee504f1d16aa143728af427dc6e0ed8))
+
+ - **SFP**
+
+ - fix compile warning ([3239a17](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3239a17561c124df7095391c0d64e86910660cdc))
+
+ - **Renesas**
+
+ - **R-Car3**
+
+ - console: fix a return value of console_rcar_init ([bb273e3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bb273e3be1c4f1cddeac9ceaac95fb56e41e6b98))
+ - ddr: update DDR setting for H3, M3, M3N ([ec767c1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ec767c1b99675fbb50ef1b2fdb2d38e881e4789d))
+ - emmc: remove CPG_CPGWPR redefinition ([36d5645](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/36d5645aec947ab00b925b21141e59e58e1efd8c))
+ - fix CPG registers redefinition ([0dae56b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0dae56bb2f0aa1f89ec98ebe3931fb19751a5c72))
+ - i2c_dvfs: fix I2C operation ([b757d3a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b757d3a1d901bee9b7ad430702575adba04889ba))
+
+ - **ST**
+
+ - **Clock**
+
+ - use correct return value ([8f97c4f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8f97c4fab1769b3f7f37a2a7a01ade36e5c94eaa))
+ - correctly manage RTC clock source ([1550909](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/15509093f0ba9a10f97c6f92bc3bb9fcf79a48ce))
+ - fix MCU/AXI parent clock ([b8fe48b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/b8fe48b6f2b07fce49363cb3c0f8dac9e286439b))
+ - fix MPU clock rate ([602ae2f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/602ae2f23c2bc9d79a9ab2b7c5dde1932fffc984))
+ - fix RTC clock rating ([cbd2e8a](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cbd2e8a6afdd05c4b404d7998134a3f60cc15518))
+ - keep RTC clock always on ([5b111c7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5b111c74795ea5e9c8a12d0e6b18d77e431311ed))
+ - keep RTCAPB clock always on ([373f06b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/373f06be4ee1114369b96763481b58885623aea4))
+ - set other clocks as always on ([bf39318](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/bf39318d93c270ff72bda4b46e4771aba7aea313))
+
+ - **I/O**
+
+ - **STM32 Image**
+
+ - invalidate cache on local buf ([a5bcf82](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a5bcf82402ff415326b4dba42aae95c499821e94))
+ - uninitialized variable warning ([c1d732d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c1d732d0db2463998036c678619007da79a25b3f))
+
+ - **ST PMIC**
+
+ - initialize i2c_state ([4282284](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/42822844bfed2e9ffaeae850cc60f5c3d4d9d654))
+ - missing error check ([a4bcfe9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a4bcfe94e73db89ce2ebbb23c8e33e51eea5026a))
+
+ - **STPMIC1**
+
+ - fix power switches activation ([0161991](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0161991184e5feacacc679bdb9c92681b85235eb))
+ - update error cases return ([ed6a852](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/ed6a85234653c5ee2520389b769ff47e321df8a4))
+
+ - **UART**
+
+ - **STM32 Console**
+
+ - do not skip init for crash console ([49c7f0c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/49c7f0cef4cc864185828750f1f61f3f33f284f7))
+
+ - **USB**
+
+ - add a optional ops get_other_speed_config_desc ([216c122](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/216c1223c2c65bd1c119a28b9406f70a9ee7b063))
+ - fix Null pointer dereferences in usb_core_set_config ([0cb9870](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0cb9870ddfa1b2fec50debe6d6333cbcb3df1e7e))
+ - remove deadcode when USBD_EP_NB = 1 ([7ca4928](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7ca49284be083b03ae11aa348b40358876ee5d4b))
+ - remove unnecessary cast ([025f5ef](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/025f5ef201a39ba7285f368139e690bbd7a44653))
+
+- **Miscellaneous**
+
+ - use correct printf format for uint64_t ([4ef449c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4ef449c15a4055d92632cb7e72267f525a7e2fca))
+
+ - **DT Bindings**
+
+ - fix static checks ([0861fcd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0861fcdd3e3f2625e133de3dae9c548de7c1ee48))
+
+ - **FDTs**
+
+ - avoid output on missing DT property ([49e789e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/49e789e353efaf97f84eca016c6a1b8a2b3e3d98))
+ - fix OOB write in uuid parsing function ([d0d6424](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d0d642450f1f3a0f43e0e156ef57a0c460dd48cf))
+
+ - **Morello**
+
+ - fix scmi clock specifier to cluster mappings ([387a906](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/387a9065a271ecde0e47dc5a9f9d037637502beb))
+
+ - **STM32MP1**
+
+ - correct copyright dates ([8d26029](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8d26029168fe70a86de524ed68c56e8666823714))
+ - set ETH clock on PLL4P on ST boards ([3e881a8](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/3e881a8834a955f1e552300bdbf1dafd02ea8f1c))
+ - update PLL nodes for ED1/EV1 boards ([cdbbb9f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/cdbbb9f7ecd4687fa52e1c655b631377c24862b9))
+ - use 'kHz' as kilohertz abbreviation ([4955d08](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4955d08de7aa664387d2e5f690e78b85ac23a402))
+
+ - **PIE**
+
+ - invalidate data cache in the entire image range if PIE is enabled ([596d20d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/596d20d9e4d50c02b5a0cce8cad2a1c205cd687a))
+
+ - **Security**
+
+ - Set MDCR_EL3.MCCD bit ([12f6c06](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/12f6c0649732a35a7ed45ba350a963f09a5710ca))
+
+ - **SDEI**
+
+ - fix assert while kdump issue ([d39db26](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d39db2695ba626b9c0ee38652fe160b4e84b15d9))
+ - print event number in hex format ([6b94356](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6b94356b577744d425476a029c47bd35eb13c148))
+ - set SPSR for SDEI based on TakeException ([37596fc](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/37596fcb43e34ed4bcf1bd3e86d8dec1011edab8))
+
+- **Documentation**
+
+ - fix TF-A v2.6 release date in the release information page ([c90fa47](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/c90fa47202b762fe8f54e9c0561e94d37907b6ad))
+ - fix `FF-A` substitution ([a61940c](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/a61940ca739eb89be7c1bb2408a9178c2da5cb70))
+ - fix typos in v2.5 release documentation ([481c7b6](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/481c7b6b9107a3f71ee750f89cacdd8f9c729838))
+ - remove "experimental" tag for stable features ([700e768](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/700e7685dd4682a929645a79de39f503c9140b2d))
+
+ - **Contribution Guidelines**
+
+ - fix formatting for code snippet ([d0bbe81](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d0bbe8150eb35fe2bac1567751bf84a8f073dd39))
+
+- **Build System**
+
+ - use space in WARNINGS list ([34b508b](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/34b508be9f021831423a8a14f56dff547e24c743))
+
+ - **Git Hooks**
+
+ - downgrade `package-lock.json` version ([7434b65](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7434b65208175bdf3f44e0e62aaaeabc9c494ee3))
+
+- **Tools**
+
+ - **STM32 Image**
+
+ - improve the tool ([8d0036d](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8d0036d3d8c8ac1524539ea90382acafb1e524c0))
+
+ - **SPTOOL**
+
+ - SP UUID little to big endian in TF-A build ([dcdbcdd](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/dcdbcddebdee8d4d2c6c8316f615b428758b22ac))
+
+ - **DOIMAGE**
+
+ - Fix doimage syntax breaking secure mode build ([6d55ef1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/6d55ef1a24dc92a3b737aaa02141f550caaace06))
+
+- **Dependencies**
+
+ - **checkpatch**
+
+ - do not check merge commits ([77a0a7f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/77a0a7f1d96b188849d1d8d8884b3c93857d3f69))
+
+## [2.5.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/v2.4..refs/tags/v2.5) (2021-05-17)
+
+### New Features
+
+- Architecture support
+
+ - Added support for speculation barrier(`FEAT_SB`) for non-Armv8.5 platforms
+ starting from Armv8.0
+ - Added support for Activity Monitors Extension version 1.1(`FEAT_AMUv1p1`)
+ - Added helper functions for Random number generator(`FEAT_RNG`) registers
+ - Added support for Armv8.6 Multi-threaded PMU extensions (`FEAT_MTPMU`)
+ - Added support for MTE Asymmetric Fault Handling extensions(`FEAT_MTE3`)
+ - Added support for Privileged Access Never extensions(`FEAT_PANx`)
+
+- Bootloader images
+
+ - Added PIE support for AArch32 builds
+ - Enable Trusted Random Number Generator service for BL32(sp_min)
+
+- Build System
+
+ - Added build option for Arm Feature Modifiers
+
+- Drivers
+
+ - Added support for interrupts in TZC-400 driver
+ - Broadcom
+ - Added support for I2C, MDIO and USB drivers
+ - Marvell
+ - Added support for secure read/write of dfc register-set
+ - Added support for thermal sensor driver
+ - Implement a3700_core_getc API in console driver
+ - Added rx training on 10G port
+ - Marvell Mochi
+ - Added support for cn913x in PCIe mode
+ - Marvell Armada A8K
+ - Added support for TRNG-IP-76 driver and accessing RNG register
+ - Mediatek MT8192
+ - Added support for following drivers
+ - MPU configuration for SCP/PCIe
+ - SPM suspend
+ - Vcore DVFS
+ - LPM
+ - PTP3
+ - UART save and restore
+ - Power-off
+ - PMIC
+ - CPU hotplug and MCDI support
+ - SPMC
+ - MPU
+ - Mediatek MT8195
+ - Added support for following drivers
+ - GPIO, NCDI, SPMC drivers
+ - Power-off
+ - CPU hotplug, reboot and MCDI
+ - Delay timer and sys timer
+ - GIC
+ - NXP
+ - Added support for
+ - non-volatile storage API
+ - chain of trust and trusted board boot using two modes: MBEDTLS and CSF
+ - fip-handler necessary for DDR initialization
+ - SMMU and console drivers
+ - crypto hardware accelerator driver
+ - following drivers: SD, EMMC, QSPI, FLEXSPI, GPIO, GIC, CSU, PMU, DDR
+ - NXP Security Monitor and SFP driver
+ - interconnect config APIs using ARM CCN-CCI driver
+ - TZC APIs to configure DDR region
+ - generic timer driver
+ - Device configuration driver
+ - IMX
+ - Added support for image loading and io-storage driver for TBBR fip booting
+ - Renesas
+ - Added support for PFC and EMMC driver
+ - RZ Family:
+ - G2N, G2E and G2H SoCs
+ - Added support for watchdog, QoS, PFC and DRAM initialization
+ - RZG Family:
+ - G2M
+ - Added support for QoS and DRAM initialization
+ - Xilinx
+ - Added JTAG DCC support for Versal and ZynqMP SoC family.
+
+- Libraries
+
+ - C standard library
+ - Added support to print `%` in `snprintf()` and `printf()` APIs
+ - Added support for strtoull, strtoll, strtoul, strtol APIs from FreeBSD
+ project
+ - CPU support
+ - Added support for
+ - Cortex_A78C CPU
+ - Makalu ELP CPU
+ - Makalu CPU
+ - Matterhorn ELP CPU
+ - Neoverse-N2 CPU
+ - CPU Errata
+ - Arm Cortex-A76: Added workaround for erratum 1946160
+ - Arm Cortex-A77: Added workaround for erratum 1946167
+ - Arm Cortex-A78: Added workaround for erratum 1941498 and 1951500
+ - Arm Neoverse-N1: Added workaround for erratum 1946160
+ - Flattened device tree(libfdt)
+ - Added support for wrapper function to read UUIDs in string format from dtb
+
+- Platforms
+
+ - Added support for MediaTek MT8195
+ - Added support for Arm RD-N2 board
+ - Allwinner
+ - Added support for H616 SoC
+ - Arm
+ - Added support for GPT parser
+ - Protect GICR frames for fused/unused cores
+ - Arm Morello
+ - Added VirtIO network device to Morello FVP fdts
+ - Arm RD-N2
+ - Added support for variant 1 of RD-N2 platform
+ - Enable AMU support
+ - Arm RD-V1
+ - Enable AMU support
+ - Arm SGI
+ - Added support for platform variant build option
+ - Arm TC0
+ - Added Matterhorn ELP CPU support
+ - Added support for opteed
+ - Arm Juno
+ - Added support to use hw_config in BL31
+ - Use TRNG entropy source for SMCCC TRNG interface
+ - Condition Juno entropy source with CRC instructions
+ - Marvell Mochi
+ - Added support for detection of secure mode
+ - Marvell ARMADA
+ - Added support for new compile option A3720_DB_PM_WAKEUP_SRC
+ - Added support doing system reset via CM3 secure coprocessor
+ - Made several makefile enhancements required to build WTMI_MULTI_IMG and
+ TIMDDRTOOL
+ - Added support for building DOIMAGETOOL tool
+ - Added new target mrvl_bootimage
+ - Mediatek MT8192
+ - Added support for rtc power off sequence
+ - Mediatek MT8195
+ - Added support for SiP service
+ - STM32MP1
+ - Added support for
+ - Seeed ODYSSEY SoM and board
+ - SDMMC2 and I2C2 pins in pinctrl
+ - I2C2 peripheral in DTS
+ - PIE for BL32
+ - TZC-400 interrupt managament
+ - Linux Automation MC-1 board
+ - Renesas RZG
+ - Added support for identifying EK874 RZ/G2E board
+ - Added support for identifying HopeRun HiHope RZ/G2H and RZ/G2H boards
+ - Rockchip
+ - Added support for stack protector
+ - QEMU
+ - Added support for `max` CPU
+ - Added Cortex-A72 support to `virt` platform
+ - Enabled trigger reboot from secure pl061
+ - QEMU SBSA
+ - Added support for sbsa-ref Embedded Controller
+ - NXP
+ - Added support for warm reset to retain ddr content
+ - Added support for image loader necessary for loading fip image
+ - lx2160a SoC Family
+ - Added support for
+ - new platform lx2160a-aqds
+ - new platform lx2160a-rdb
+ - new platform lx2162a-aqds
+ - errata handling
+ - IMX imx8mm
+ - Added support for trusted board boot
+ - TI K3
+ - Added support for lite device board
+ - Enabled Cortex-A72 erratum 1319367
+ - Enabled Cortex-A53 erratum 1530924
+ - Xilinx ZynqMP
+ - Added support for PS and system reset on WDT restart
+ - Added support for error management
+ - Enable support for log messages necessary for debug
+ - Added support for PM API SMC call for efuse and register access
+
+- Processes
+
+ - Introduced process for platform deprecation
+ - Added documentation for TF-A threat model
+ - Provided a copy of the MIT license to comply with the license requirements
+ of the arm-gic.h source file (originating from the Linux kernel project and
+ re-distributed in TF-A).
+
+- Services
+
+ - Added support for TRNG firmware interface service
+ - Arm
+ - Added SiP service to configure Ethos-N NPU
+ - SPMC
+ - Added documentation for SPM(Hafnium) SMMUv3 driver
+ - SPMD
+ - Added support for
+ - FFA_INTERRUPT forwading ABI
+ - FFA_SECONDARY_EP_REGISTER ABI
+ - FF-A v1.0 boot time power management, SPMC secondary core boot and early
+ run-time power management
+
+- Tools
+
+ - FIPTool
+ - Added mechanism to allow platform specific image UUID
+ - git hooks
+ - Added support for conventional commits through commitlint hook, commitizen
+ hook and husky configuration files.
+ - NXP tool
+ - Added support for a tool that creates pbl file from BL2
+ - Renesas RZ/G2
+ - Added tool support for creating bootparam and cert_header images
+ - CertCreate
+ - Added support for platform-defined certificates, keys, and extensions
+ using the platform's makefile
+ - shared tools
+ - Added EFI_GUID representation to uuid helper data structure
+
+### Changed
+
+- Common components
+
+ - Print newline after hex address in aarch64 el3_panic function
+ - Use proper `#address-cells` and `#size-cells` for reserved-memory in dtbs
+
+- Drivers
+
+ - Move SCMI driver from ST platform directory and make it common to all
+ platforms
+ - Arm GICv3
+ - Shift eSPI register offset in GICD_OFFSET_64()
+ - Use mpidr to probe GICR for current CPU
+ - Arm TZC-400
+ - Adjust filter tag if it set to FILTER_BIT_ALL
+ - Cadence
+ - Enhance UART driver APIs to put characters to fifo
+ - Mediatek MT8192
+ - Move timer driver to common folder
+ - Enhanced sys_cirq driver to add more IC services
+ - Renesas
+ - Move ddr and delay driver to common directory
+ - Renesas rcar
+ - Treat log as device memory in console driver
+ - Renesas RZ Family:
+ - G2N and G2H SoCs
+ - Select MMC_CH1 for eMMC channel
+ - Marvell
+ - Added support for checking if TRNG unit is present
+ - Marvell A3K
+ - Set TXDCLK_2X_SEL bit during PCIe initialization
+ - Set mask parameter for every reg_set call
+ - Marvell Mochi
+ - Added missing stream IDs configurations
+ - MbedTLS
+ - Migrated to Mbed TLS v2.26.0
+ - IMX imx8mp
+ - Change the bl31 physical load address
+ - QEMU SBSA
+ - Enable secure variable storage
+ - SCMI
+ - Update power domain protocol version to 2.0
+ - STM32
+ - Remove dead code from nand FMC driver
+
+- Libraries
+
+ - C Standard Library
+ - Use macros to reduce duplicated code between snprintf and printf
+ - CPU support
+ - Sanity check pointers before use in AArch32 builds
+ - Arm Cortex-A78
+ - Remove rainier cpu workaround for errata 1542319
+ - Arm Makalu ELP
+ - Added "\_arm" suffix to Makalu ELP CPU lib
+
+- Miscellaneous
+
+ - Editorconfig
+ - set max line length to 100
+
+- Platforms
+
+ - Allwinner
+ - Added reserved-memory node to DT
+ - Express memmap more dynamically
+ - Move SEPARATE_NOBITS_REGION to platforms
+ - Limit FDT checks to reduce code size
+ - Use CPUIDLE hardware when available
+ - Allow conditional compilation of SCPI and native PSCI ops
+ - Always use a 3MHz RSB bus clock
+ - Enable workaround for Cortex-A53 erratum 1530924
+ - Fixed non-default PRELOADED_BL33_BASE
+ - Leave CPU power alone during BL31 setup
+ - Added several psci hooks enhancements to improve system shutdown/reset
+ sequence
+ - Return the PMIC to I2C mode after use
+ - Separate code to power off self and other CPUs
+ - Split native and SCPI-based PSCI implementations
+ - Allwinner H6
+ - Added R_PRCM security setup for H6 board
+ - Added SPC security setup for H6 board
+ - Use RSB for the PMIC connection on H6
+ - Arm
+ - Store UUID as a string, rather than ints
+ - Replace FIP base and size macro with a generic name
+ - Move compile time switch from source to dt file
+ - Don't provide NT_FW_CONFIG when booting hafnium
+ - Do not setup 'disabled' regulator
+ - Increase SP max size
+ - Remove false dependency of ARM_LINUX_KERNEL_AS_BL33 on RESET_TO_BL31 and
+ allow it to be enabled independently
+ - Arm FVP
+ - Do not map GIC region in BL1 and BL2
+ - Arm Juno
+ - Refactor juno_getentropy() to return 64 bits on each call
+ - Arm Morello
+ - Remove "virtio-rng" from Morello FVP
+ - Enable virtIO P9 device for Morello fvp
+ - Arm RDV1
+ - Allow all PSCI callbacks on RD-V1
+ - Rename rddaniel to rdv1
+ - Arm RDV1MC
+ - Rename rddanielxlr to rdv1mc
+ - Initialize TZC-400 controllers
+ - Arm TC0
+ - Updated GICR base address
+ - Use scmi_dvfs clock index 1 for cores 4-7 through fdt
+ - Added reserved-memory node for OP-TEE fdts
+ - Enabled Theodul DSU in TC platform
+ - OP-TEE as S-EL1 SP with SPMC at S-EL2
+ - Update Matterhorm ELP DVFS clock index
+ - Arm SGI
+ - Allow access to TZC controller on all chips
+ - Define memory regions for multi-chip platforms
+ - Allow access to nor2 flash and system registers from S-EL0
+ - Define default list of memory regions for DMC-620 TZC
+ - Improve macros defining cper buffer memory region
+ - Refactor DMC-620 error handling SMC function id
+ - Refactor SDEI specific macros
+ - Added platform id value for RDN2 platform
+ - Refactored header file inclusions and inclusion of memory mapping
+ - Arm RDN2
+ - Allow usage of secure partitions on RDN2 platform
+ - Update GIC redistributor and TZC base address
+ - Arm SGM775
+ - Deprecate Arm sgm775 FVP platform
+ - Marvell
+ - Increase TX FIFO EMPTY timeout from 2ms to 3ms
+ - Update delay code to be compatible with 1200 MHz CPU
+ - Marvell ARMADA
+ - Postpone MSS CPU startup to BL31 stage
+ - Allow builds without MSS support
+ - Use MSS SRAM in secure mode
+ - Added missing FORCE, .PHONY and clean targets
+ - Cleanup MSS SRAM if used for copy
+ - Move definition of mrvl_flash target to common marvell_common.mk file
+ - Show informative build messages and blank lines
+ - Marvell ARMADA A3K
+ - Added a new target mrvl_uart which builds UART image
+ - Added checks that WTP, MV_DDR_PATH and CRYPTOPP_PATH are correctly defined
+ - Allow use of the system Crypto++ library
+ - Build \$(WTMI_ENC_IMG) in \$(BUILD_PLAT) directory
+ - Build intermediate files in \$(BUILD_PLAT) directory
+ - Build UART image files directly in \$(BUILD_UART) subdirectory
+ - Correctly set DDR_TOPOLOGY and CLOCKSPRESET for WTMI
+ - Do not use 'echo -e' in Makefile
+ - Improve 4GB DRAM usage from 3.375 GB to 3.75 GB
+ - Remove unused variable WTMI_SYSINIT_IMG from Makefile
+ - Simplify check if WTP variable is defined
+ - Split building \$(WTMI_MULTI_IMG) and \$(TIMDDRTOOL)
+ - Marvell ARMADA A8K
+ - Allow CP1/CP2 mapping at BLE stage
+ - Mediatek MT8183
+ - Added timer V20 compensation
+ - Nvidia Tegra
+ - Rename SMC API
+ - TI K3
+ - Make plat_get_syscnt_freq2 helper check CNT_FID0 register
+ - Fill non-message data fields in sec_proxy with 0x0
+ - Update ti_sci_msg_req_reboot ABI to include domain
+ - Enable USE_COHERENT_MEM only for the generic board
+ - Explicitly map SEC_SRAM_BASE to 0x0
+ - Use BL31_SIZE instead of computing
+ - Define the correct number of max table entries and increase SRAM size to
+ account for additional table
+ - Raspberry Pi4
+ - Switch to gicv2.mk and GICV2_SOURCES
+ - Renesas
+ - Move headers and assembly files to common folder
+ - Renesas rzg
+ - Added device tree memory node enhancements
+ - Rockchip
+ - Switch to using common gicv3.mk
+ - STM32MP1
+ - Set BL sizes regardless of flags
+ - QEMU
+ - Include gicv2.mk for compiling GICv2 source files
+ - Change DEVICE2 definition for MMU
+ - Added helper to calculate the position shift from MPIDR
+ - QEMU SBSA
+ - Include libraries for Cortex-A72
+ - Increase SHARED_RAM_SIZE
+ - Addes support in spm_mm for upto 512 cores
+ - Added support for topology handling
+ - QTI
+ - Mandate SMC implementation
+ - Xilinx
+ - Rename the IPI CRC checksum macro
+ - Use fno-jump-tables flag in CPPFLAGS
+ - Xilinx versal
+ - Added the IPI CRC checksum macro support
+ - Mark IPI calls secure/non-secure
+ - Enable sgi to communicate with linux using IPI
+ - Remove Cortex-A53 compilation
+ - Xilinx ZynqMP
+ - Configure counter frequency during initialization
+ - Filter errors related to clock gate permissions
+ - Implement pinctrl request/release EEMI API
+ - Reimplement pinctrl get/set config parameter EEMI API calls
+ - Reimplement pinctrl set/get function EEMI API
+ - Update error codes to match Linux and PMU Firmware
+ - Update PM version and support PM version check
+ - Update return type in query functions
+ - Added missing ids for 43/46/47dr devices
+ - Checked for DLL status before doing reset
+ - Disable ITAPDLYENA bit for zero ITAP delay
+ - Include GICv2 makefile
+ - Remove the custom crash implementation
+
+- Services
+
+ - SPMD
+ - Lock the g_spmd_pm structure
+ - Declare third cactus instance as UP SP
+ - Provide number of vCPUs and VM size for first SP
+ - Remove `chosen` node from SPMC manifests
+ - Move OP-TEE SP manifest DTS to FVP platform
+ - Update OP-TEE SP manifest with device-regions node
+ - Remove device-memory node from SPMC manifests
+ - SPM_MM
+ - Use sp_boot_info to set SP context
+ - SDEI
+ - Updata the affinity of shared event
+
+- Tools
+
+ - FIPtool
+ - Do not print duplicate verbose lines about building fiptool
+ - CertCreate
+ - Updated tool for platform defined certs, keys & extensions
+ - Create only requested certificates
+ - Avoid duplicates in extension stack
+
+### Resolved Issues
+
+- Several fixes for typos and mis-spellings in documentation
+
+- Build system
+
+ - Fixed \$\{FIP_NAME} to be rebuilt only when needed in Makefile
+ - Do not mark file targets as .PHONY target in Makefile
+
+- Drivers
+
+ - Authorization
+ - Avoid NV counter upgrade without certificate validation
+ - Arm GICv3
+ - Fixed logical issue for num_eints
+ - Limit SPI ID to avoid misjudgement in GICD_OFFSET()
+ - Fixed potential GICD context override with ESPI enabled
+ - Marvell A3700
+ - Fixed configuring polarity invert bits
+ - Arm TZC-400
+ - Correct FAIL_CONTROL Privileged bit
+ - Fixed logical error in FILTER_BIT definitions
+ - Renesas rcar
+ - Fixed several coding style violations reported by checkpatch
+
+- Libraries
+
+ - Arch helpers
+ - Fixed assertions in processing dynamic relocations for AArch64 builds
+ - C standard library
+ - Fixed MISRA issues in memset() ABI
+ - RAS
+ - Fixed bug of binary search in RAS interrupt handler
+
+- Platforms
+
+ - Arm
+ - Fixed missing copyrights in arm-gic.h file
+ - Fixed the order of header files in several dts files
+ - Fixed error message printing in board makefile
+ - Fixed bug of overriding the last node in image load helper API
+ - Fixed stdout-path in fdts files of TC0 and N1SDP platforms
+ - Turn ON/OFF redistributor in sync with GIC CPU interface ON/OFF for css
+ platforms
+ - Arm FVP
+ - Fixed Generic Timer interrupt types in platform dts files
+ - Arm Juno
+ - Fixed parallel build issue for romlib config
+ - Arm SGI
+ - Fixed bug in SDEI receive event of RAS handler
+ - Intel Agilex
+ - Fixed PLAT_MAX_PWR_LVL value
+ - Marvell
+ - Fixed SPD handling in dram port
+ - Marvell ARMADA
+ - Fixed TRNG return SMC handling
+ - Fixed the logic used for LD selector mask
+ - Fixed MSS firmware loader for A8K family
+ - ST
+ - Fixed few violations reported by coverity static checks
+ - STM32MP1
+ - Fixed SELFREF_TO_X32 mask in ddr driver
+ - Do not keep mmc_device_info in stack
+ - Correct plat_crash_console_flush()
+ - QEMU SBSA
+ - Fixed memory type of secure NOR flash
+ - QTI
+ - Fixed NUM_APID and REG_APID_MAP() argument in SPMI driver
+ - Intel
+ - Do not keep mmc_device_info in stack
+ - Hisilicon
+ - Do not keep mmc_device_info in stack
+
+- Services
+
+ - EL3 runtime
+ - Fixed the EL2 context save/restore routine by removing EL2 generic timer
+ system registers
+ - Added fix for exception handler in BL31 by synchronizing pending EA using
+ DSB barrier
+ - SPMD
+ - Fixed error codes to use int32_t type
+ - TSPD
+ - Added bug fix in tspd interrupt handling when TSP_NS_INTR_ASYNC_PREEMPT is
+ enabled
+ - TRNG
+ - Fixed compilation errors with -O0 compile option
+ - DebugFS
+ - Checked channel index before calling clone function
+ - PSCI
+ - Fixed limit of 256 CPUs caused by cast to unsigned char
+ - TSP
+ - Fixed compilation erros when built with GCC 11.0.0 toolchain
+
+- Tools
+
+ - FIPtool
+ - Do not call `make clean` for `all` target
+ - CertCreate
+ - Fixed bug to avoid cleaning when building the binary
+ - Used preallocated parts of the HASH struct to avoid leaking HASH struct
+ fields
+ - Free arguments copied with strdup
+ - Free keys after use
+ - Free X509_EXTENSION structures on stack to avoid leaking them
+ - Optimized the code to avoid unnecessary attempts to create non-requested
+ certificates
+
+## [2.4.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/v2.3..refs/tags/v2.4) (2020-11-17)
+
+### New Features
+
+- Architecture support
+ - Armv8.6-A
+ - Added support for Armv8.6 Enhanced Counter Virtualization (ECV)
+ - Added support for Armv8.6 Fine Grained Traps (FGT)
+ - Added support for Armv8.6 WFE trap delays
+- Bootloader images
+ - Added support for Measured Boot
+- Build System
+ - Added build option `COT_DESC_IN_DTB` to create Chain of Trust at runtime
+ - Added build option `OPENSSL_DIR` to direct tools to OpenSSL libraries
+ - Added build option `RAS_TRAP_LOWER_EL_ERR_ACCESS` to enable trapping RAS
+ register accesses from EL1/EL2 to EL3
+ - Extended build option `BRANCH_PROTECTION` to support branch target
+ identification
+- Common components
+ - Added support for exporting CPU nodes to the device tree
+ - Added support for single and dual-root Chains of Trust in secure partitions
+- Drivers
+ - Added Broadcom RNG driver
+ - Added Marvell `mg_conf_cm3` driver
+ - Added System Control and Management Interface (SCMI) driver
+ - Added STMicroelectronics ETZPC driver
+ - Arm GICv3
+ - Added support for detecting topology at runtime
+ - Dual Root
+ - Added support for platform certificates
+ - Marvell Cache LLC
+ - Added support for mapping the entire LLC into SRAM
+ - Marvell CCU
+ - Added workaround for erratum 3033912
+ - Marvell CP110 COMPHY
+ - Added support for SATA COMPHY polarity inversion
+ - Added support for USB COMPHY polarity inversion
+ - Added workaround for erratum IPCE_COMPHY-1353
+ - STM32MP1 Clocks
+ - Added `RTC` as a gateable clock
+ - Added support for shifted clock selector bit masks
+ - Added support for using additional clocks as parents
+- Libraries
+ - C standard library
+ - Added support for hexadecimal and pointer format specifiers in `snprint()`
+ - Added assembly alternatives for various library functions
+ - CPU support
+ - Arm Cortex-A53
+ - Added workaround for erratum 1530924
+ - Arm Cortex-A55
+ - Added workaround for erratum 1530923
+ - Arm Cortex-A57
+ - Added workaround for erratum 1319537
+ - Arm Cortex-A76
+ - Added workaround for erratum 1165522
+ - Added workaround for erratum 1791580
+ - Added workaround for erratum 1868343
+ - Arm Cortex-A72
+ - Added workaround for erratum 1319367
+ - Arm Cortex-A77
+ - Added workaround for erratum 1508412
+ - Added workaround for erratum 1800714
+ - Added workaround for erratum 1925769
+ - Arm Neoverse-N1
+ - Added workaround for erratum 1868343
+ - EL3 Runtime
+ - Added support for saving/restoring registers related to nested
+ virtualization in EL2 context switches if the architecture supports it
+ - FCONF
+ - Added support for Measured Boot
+ - Added support for populating Chain of Trust properties
+ - Added support for loading the `fw_config` image
+ - Measured Boot
+ - Added support for event logging
+- Platforms
+ - Added support for Arm Morello
+ - Added support for Arm TC0
+ - Added support for iEi PUZZLE-M801
+ - Added support for Marvell OCTEON TX2 T9130
+ - Added support for MediaTek MT8192
+ - Added support for NXP i.MX 8M Nano
+ - Added support for NXP i.MX 8M Plus
+ - Added support for QTI CHIP SC7180
+ - Added support for STM32MP151F
+ - Added support for STM32MP153F
+ - Added support for STM32MP157F
+ - Added support for STM32MP151D
+ - Added support for STM32MP153D
+ - Added support for STM32MP157D
+ - Arm
+ - Added support for platform-owned SPs
+ - Added support for resetting to BL31
+ - Arm FPGA
+ - Added support for Klein
+ - Added support for Matterhorn
+ - Added support for additional CPU clusters
+ - Arm FVP
+ - Added support for performing SDEI platform setup at runtime
+ - Added support for SMCCC's `SMCCC_ARCH_SOC_ID` command
+ - Added an `id` field under the NV-counter node in the device tree to
+ differentiate between trusted and non-trusted NV-counters
+ - Added support for extracting the clock frequency from the timer node in
+ the device tree
+ - Arm Juno
+ - Added support for SMCCC's `SMCCC_ARCH_SOC_ID` command
+ - Arm N1SDP
+ - Added support for cross-chip PCI-e
+ - Marvell
+ - Added support for AVS reduction
+ - Marvell ARMADA
+ - Added support for twin-die combined memory device
+ - Marvell ARMADA A8K
+ - Added support for DDR with 32-bit bus width (both ECC and non-ECC)
+ - Marvell AP806
+ - Added workaround for erratum FE-4265711
+ - Marvell AP807
+ - Added workaround for erratum 3033912
+ - Nvidia Tegra
+ - Added debug printouts indicating SC7 entry sequence completion
+ - Added support for SDEI
+ - Added support for stack protection
+ - Added support for GICv3
+ - Added support for SMCCC's `SMCCC_ARCH_SOC_ID` command
+ - Nvidia Tegra194
+ - Added support for RAS exception handling
+ - Added support for SPM
+ - NXP i.MX
+ - Added support for SDEI
+ - QEMU SBSA
+ - Added support for the Secure Partition Manager
+ - QTI
+ - Added RNG driver
+ - Added SPMI PMIC arbitrator driver
+ - Added support for SMCCC's `SMCCC_ARCH_SOC_ID` command
+ - STM32MP1
+ - Added support for exposing peripheral interfaces to the non-secure world
+ at runtime
+ - Added support for SCMI clock and reset services
+ - Added support for STM32MP15x CPU revision Z
+ - Added support for SMCCC services in `SP_MIN`
+- Services
+ - Secure Payload Dispatcher
+ - Added a provision to allow clients to retrieve the service UUID
+ - SPMC
+ - Added secondary core endpoint information to the SPMC context structure
+ - SPMD
+ - Added support for booting OP-TEE as a guest S-EL1 Secure Partition on top
+ of Hafnium in S-EL2
+ - Added a provision for handling SPMC messages to register secondary core
+ entry points
+ - Added support for power management operations
+- Tools
+ - CertCreate
+ - Added support for secure partitions
+ - CertTool
+ - Added support for the `fw_config` image
+ - FIPTool
+ - Added support for the `fw_config` image
+
+### Changed
+
+- Architecture support
+- Bootloader images
+- Build System
+ - The top-level Makefile now supports building FipTool on Windows
+ - The default value of `KEY_SIZE` has been changed to to 2048 when RSA is in
+ use
+ - The previously-deprecated macro `__ASSEMBLY__` has now been removed
+- Common components
+ - Certain functions that flush the console will no longer return error
+ information
+- Drivers
+ - Arm GIC
+ - Usage of `drivers/arm/gic/common/gic_common.c` has now been deprecated in
+ favour of `drivers/arm/gic/vX/gicvX.mk`
+ - Added support for detecting the presence of a GIC600-AE
+ - Added support for detecting the presence of a GIC-Clayton
+ - Marvell MCI
+ - Now performs link tuning for all MCI interfaces to improve performance
+ - Marvell MoChi
+ - PIDI masters are no longer forced into a non-secure access level when
+ `LLC_SRAM` is enabled
+ - The SD/MMC controllers are now accessible from guest virtual machines
+ - Mbed TLS
+ - Migrated to Mbed TLS v2.24.0
+ - STM32 FMC2 NAND
+ - Adjusted FMC node bindings to include an EBI controller node
+ - STM32 Reset
+ - Added an optional timeout argument to assertion functions
+ - STM32MP1 Clocks
+ - Enabled several additional system clocks during initialization
+- Libraries
+ - C Standard Library
+ - Improved `memset` performance by avoiding single-byte writes
+ - Added optimized assembly variants of `memset`
+ - CPU support
+ - Renamed Cortex-Hercules to Cortex-A78
+ - Renamed Cortex-Hercules AE to Cortex-A78 AE
+ - Renamed Neoverse Zeus to Neoverse V1
+ - Coreboot
+ - Updated ‘coreboot_get_memory_type’ API to take an extra argument as a
+ ’memory size’ that used to return a valid memory type.
+ - libfdt
+ - Updated to latest upstream version
+- Platforms
+ - Allwinner
+ - Disabled non-secure access to PRCM power control registers
+ - Arm
+ - `BL32_BASE` is now platform-dependent when `SPD_spmd` is enabled
+ - Added support for loading the Chain of Trust from the device tree
+ - The firmware update check is now executed only once
+ - NV-counter base addresses are now loaded from the device tree when
+ `COT_DESC_IN_DTB` is enabled
+ - Now loads and populates `fw_config` and `tb_fw_config`
+ - FCONF population now occurs after caches have been enabled in order to
+ reduce boot times
+ - Arm Corstone-700
+ - Platform support has been split into both an FVP and an FPGA variant
+ - Arm FPGA
+ - DTB and BL33 load addresses have been given sensible default values
+ - Now reads generic timer counter frequency, GICD and GICR base addresses,
+ and UART address from DT
+ - Now treats the primary PL011 UART as an SBSA Generic UART
+ - Arm FVP
+ - Secure interrupt descriptions, UART parameters, clock frequencies and
+ GICv3 parameters are now queried through FCONF
+ - UART parameters are now queried through the device tree
+ - Added an owner field to Cactus secure partitions
+ - Increased the maximum size of BL2 when the Chain of Trust is loaded from
+ the device tree
+ - Reduces the maximum size of BL31
+ - The `FVP_USE_SP804_TIMER` and `FVP_VE_USE_SP804_TIMER` build options have
+ been removed in favour of a common `USE_SP804_TIMER` option
+ - Added a third Cactus partition to manifests
+ - Device tree nodes now store UUIDs in big-endian
+ - Arm Juno
+ - Increased the maximum size of BL2 when optimizations have not been applied
+ - Reduced the maximum size of BL31 and BL32
+ - Marvell AP807
+ - Enabled snoop filters
+ - Marvell ARMADA A3K
+ - UART recovery images are now suffixed with `.bin`
+ - Marvell ARMADA A8K
+ - Option `BL31_CACHE_DISABLE` is now disabled (`0`) by default
+ - Nvidia Tegra
+ - Added VPR resize supported check when processing video memory resize
+ requests
+ - Added SMMU verification to prevent potential issues caused by undetected
+ corruption of the SMMU configuration during boot
+ - The GIC CPU interface is now properly disabled after CPU off
+ - The GICv2 sources list and the `BL31_SIZE` definition have been made
+ platform-specific
+ - The SPE driver will no longer flush the console when writing individual
+ characters
+ - Nvidia Tegra194
+ - TZDRAM setup has been moved to platform-specific early boot handlers
+ - Increased verbosity of debug prints for RAS SErrors
+ - Support for powering down CPUs during CPU suspend has been removed
+ - Now verifies firewall settings before using resources
+ - TI K3
+ - The UART number has been made configurable through `K3_USART`
+ - Rockchip RK3368
+ - The maximum number of memory map regions has been increased to 20
+ - Socionext Uniphier
+ - The maximum size of BL33 has been increased to support larger bootloaders
+ - STM32
+ - Removed platform-specific DT functions in favour of using existing generic
+ alternatives
+ - STM32MP1
+ - Increased verbosity of exception reports in debug builds
+ - Device trees have been updated to align with the Linux kernel
+ - Now uses the ETZPC driver to configure secure-aware interfaces for
+ assignment to the non-secure world
+ - Finished good variants have been added to the board identifier
+ enumerations
+ - Non-secure access to clocks and reset domains now depends on their state
+ of registration
+ - NEON is now disabled in `SP_MIN`
+ - The last page of `SYSRAM` is now used as SCMI shared memory
+ - Checks to verify platform compatibility have been added to verify that an
+ image is compatible with the chip ID of the running platform
+ - QEMU SBSA
+ - Removed support for Arm's Cortex-A53
+- Services
+ - Renamed SPCI to FF-A
+ - SPMD
+ - No longer forwards requests to the non-secure world when retrieving
+ partition information
+ - SPMC manifest size is now retrieved directly from SPMD instead of the
+ device tree
+ - The FF-A version handler now returns SPMD's version when the origin of the
+ call is secure, and SPMC's version when the origin of the call is
+ non-secure
+ - SPMC
+ - Updated the manifest to declare CPU nodes in descending order as per the
+ SPM (Hafnium) multicore requirement
+ - Updated the device tree to mark 2GB as device memory for the first
+ partition excluding trusted DRAM region (which is reserved for SPMC)
+ - Increased the number of EC contexts to the maximum number of PEs as per
+ the FF-A specification
+- Tools
+ - FIPTool
+ - Now returns `0` on `help` and `help <command>`
+ - Marvell DoImage
+ - Updated Mbed TLS support to v2.8
+ - SPTool
+ - Now appends CertTool arguments
+
+### Resolved Issues
+
+- Bootloader images
+ - Fixed compilation errors for dual-root Chains of Trust caused by symbol
+ collision
+ - BL31
+ - Fixed compilation errors on platforms with fewer than 4 cores caused by
+ initialization code exceeding the end of the stacks
+ - Fixed compilation errors when building a position-independent image
+- Build System
+ - Fixed invalid empty version strings
+ - Fixed compilation errors on Windows caused by a non-portable architecture
+ revision comparison
+- Drivers
+ - Arm GIC
+ - Fixed spurious interrupts caused by a missing barrier
+ - STM32 Flexible Memory Controller 2 (FMC2) NAND driver
+ - Fixed runtime instability caused by incorrect error detection logic
+ - STM32MP1 Clock driver
+ - Fixed incorrectly-formatted log messages
+ - Fixed runtime instability caused by improper clock gating procedures
+ - STMicroelectronics Raw NAND driver
+ - Fixed runtime instability caused by incorrect unit conversion when waiting
+ for NAND readiness
+- Libraries
+ - AMU
+ - Fixed timeout errors caused by excess error logging
+ - EL3 Runtime
+ - Fixed runtime instability caused by improper register save/restore routine
+ in EL2
+ - FCONF
+ - Fixed failure to initialize GICv3 caused by overly-strict device tree
+ requirements
+ - Measured Boot
+ - Fixed driver errors caused by a missing default value for the `HASH_ALG`
+ build option
+ - SPE
+ - Fixed feature detection check that prevented CPUs supporting SVE from
+ detecting support for SPE in the non-secure world
+ - Translation Tables
+ - Fixed various MISRA-C 2012 static analysis violations
+- Platforms
+ - Allwinner A64
+ - Fixed USB issues on certain battery-powered device caused by improperly
+ activated USB power rail
+ - Arm
+ - Fixed compilation errors caused by increase in BL2 size
+ - Fixed compilation errors caused by missing Makefile dependencies to
+ generated files when building the FIP
+ - Fixed MISRA-C 2012 static analysis violations caused by unused structures
+ in include directives intended to be feature-gated
+ - Arm FPGA
+ - Fixed initialization issues caused by incorrect MPIDR topology mapping
+ logic
+ - Arm RD-N1-edge
+ - Fixed compilation errors caused by mismatched parentheses in Makefile
+ - Arm SGI
+ - Fixed crashes due to the flash memory used for cold reboot attack
+ protection not being mapped
+ - Intel Agilex
+ - Fixed initialization issues caused by several compounding bugs
+ - Marvell
+ - Fixed compilation warnings caused by multiple Makefile inclusions
+ - Marvell ARMADA A3K
+ - Fixed boot issue in debug builds caused by checks on the BL33 load address
+ that are not appropriate for this platform
+ - Nvidia Tegra
+ - Fixed incorrect delay timer reads
+ - Fixed spurious interrupts in the non-secure world during cold boot caused
+ by the arbitration bit in the memory controller not being cleared
+ - Fixed faulty video memory resize sequence
+ - Nvidia Tegra194
+ - Fixed incorrect alignment of TZDRAM base address
+ - NXP iMX8M
+ - Fixed CPU hot-plug issues caused by race condition
+ - STM32MP1
+ - Fixed compilation errors in highly-parallel builds caused by incorrect
+ Makefile dependencies
+ - STM32MP157C-ED1
+ - Fixed initialization issues caused by missing device tree hash node
+ - Raspberry Pi 3
+ - Fixed compilation errors caused by incorrect dependency ordering in
+ Makefile
+ - Rockchip
+ - Fixed initialization issues caused by non-critical errors when parsing FDT
+ being treated as critical
+ - Rockchip RK3368
+ - Fixed runtime instability caused by incorrect CPUID shift value
+ - QEMU
+ - Fixed compilation errors caused by incorrect dependency ordering in
+ Makefile
+ - QEMU SBSA
+ - Fixed initialization issues caused by FDT exceeding reserved memory size
+ - QTI
+ - Fixed compilation errors caused by inclusion of a non-existent file
+- Services
+ - FF-A (previously SPCI)
+ - Fixed SPMD aborts caused by incorrect behaviour when the manifest is
+ page-aligned
+- Tools
+ - Fixed compilation issues when compiling tools from within their respective
+ directories
+ - FIPTool
+ - Fixed command line parsing issues on Windows when using arguments whose
+ names also happen to be a subset of another's
+ - Marvell DoImage
+ - Fixed PKCS signature verification errors at boot on some platforms caused
+ by generation of misaligned images
+
+### Known Issues
+
+- Platforms
+ - NVIDIA Tegra
+ - Signed comparison compiler warnings occurring in libfdt are currently
+ being worked around by disabling the warning for the platform until the
+ underlying issue is resolved in libfdt
+
+## [2.3.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/v2.2..refs/tags/v2.3) (2020-04-20)
+
+### New Features
+
+- Arm Architecture
+ - Add support for Armv8.4-SecEL2 extension through the SPCI defined SPMD/SPMC
+ components.
+ - Build option to support EL2 context save and restore in the secure world
+ (CTX_INCLUDE_EL2_REGS).
+ - Add support for SMCCC v1.2 (introducing the new SMCCC_ARCH_SOC_ID SMC). Note
+ that the support is compliant, but the SVE registers save/restore will be
+ done as part of future S-EL2/SPM development.
+- BL-specific
+ - Enhanced BL2 bootloader flow to load secure partitions based on firmware
+ configuration data (fconf).
+ - Changes necessary to support SEPARATE_NOBITS_REGION feature
+ - TSP and BL2_AT_EL3: Add Position Independent Execution `PIE` support
+- Build System
+ - Add support for documentation build as a target in Makefile
+ - Add `COT` build option to select the Chain of Trust to use when the Trusted
+ Boot feature is enabled (default: `tbbr`).
+ - Added creation and injection of secure partition packages into the FIP.
+ - Build option to support SPMC component loading and run at S-EL1 or S-EL2
+ (SPMD_SPM_AT_SEL2).
+ - Enable MTE support
+ - Enable Link Time Optimization in GCC
+ - Enable -Wredundant-decls warning check
+ - Makefile: Add support to optionally encrypt BL31 and BL32
+ - Add support to pass the nt_fw_config DTB to OP-TEE.
+ - Introduce per-BL `CPPFLAGS`, `ASFLAGS`, and `LDFLAGS`
+ - build_macros: Add CREATE_SEQ function to generate sequence of numbers
+- CPU Support
+ - cortex-a57: Enable higher performance non-cacheable load forwarding
+ - Hercules: Workaround for Errata 1688305
+ - Klein: Support added for Klein CPU
+ - Matterhorn: Support added for Matterhorn CPU
+- Drivers
+ - auth: Add `calc_hash` function for hash calculation. Used for authentication
+ of images when measured boot is enabled.
+ - cryptocell: Add authenticated decryption framework, and support for
+ CryptoCell-713 and CryptoCell-712 RSA 3K
+ - gic600: Add support for multichip configuration and Clayton
+ - gicv3: Introduce makefile, Add extended PPI and SPI range, Add support for
+ probing multiple GIC Redistributor frames
+ - gicv4: Add GICv4 extension for GIC driver
+ - io: Add an IO abstraction layer to load encrypted firmwares
+ - mhu: Derive doorbell base address
+ - mtd: Add SPI-NOR, SPI-NAND, SPI-MEM, and raw NAND framework
+ - scmi: Allow use of multiple SCMI channels
+ - scu: Add a driver for snoop control unit
+- Libraries
+ - coreboot: Add memory range parsing and use generic base address
+ - compiler_rt: Import popcountdi2.c and popcountsi2.c files, aeabi_ldivmode.S
+ file and dependencies
+ - debugFS: Add DebugFS functionality
+ - el3_runtime: Add support for enabling S-EL2
+ - fconf: Add Firmware Configuration Framework (fconf) (experimental).
+ - libc: Add memrchr function
+ - locks: bakery: Use is_dcache_enabled() helper and add a DMB to the
+ 'read_cache_op' macro
+ - psci: Add support to enable different personality of the same soc.
+ - xlat_tables_v2: Add support to pass shareability attribute for normal memory
+ region, use get_current_el_maybe_constant() in is_dcache_enabled(),
+ read-only xlat tables for BL31 memory, and add enable_mmu()
+- New Platforms Support
+ - arm/arm_fpga: New platform support added for FPGA
+ - arm/rddaniel: New platform support added for rd-daniel platform
+ - brcm/stingray: New platform support added for Broadcom stingray platform
+ - nvidia/tegra194: New platform support for Nvidia Tegra194 platform
+- Platforms
+ - allwinner: Implement PSCI system suspend using SCPI, add a msgbox driver for
+ use with SCPI, and reserve and map space for the SCP firmware
+ - allwinner: axp: Add AXP805 support
+ - allwinner: power: Add DLDO4 power rail
+ - amlogic: axg: Add a build flag when using ATOS as BL32 and support for the
+ A113D (AXG) platform
+ - arm/a5ds: Add ethernet node and L2 cache node in devicetree
+ - arm/common: Add support for the new `dualroot` chain of trust
+ - arm/common: Add support for SEPARATE_NOBITS_REGION
+ - arm/common: Re-enable PIE when RESET_TO_BL31=1
+ - arm/common: Allow boards to specify second DRAM Base address and to define
+ PLAT_ARM_TZC_FILTERS
+ - arm/corstone700: Add support for mhuv2 and stack protector
+ - arm/fvp: Add support for fconf in BL31 and SP_MIN. Populate power domain
+ descriptor dynamically by leveraging fconf APIs.
+ - arm/fvp: Add Cactus/Ivy Secure Partition information and use two instances
+ of Cactus at S-EL1
+ - arm/fvp: Add support to run BL32 in TDRAM and BL31 in secure DRAM
+ - arm/fvp: Add support for GICv4 extension and BL2 hash calculation in BL1
+ - arm/n1sdp: Setup multichip gic routing table, update platform macros for
+ dual-chip setup, introduce platform information SDS region, add support to
+ update presence of External LLC, and enable the NEOVERSE_N1_EXTERNAL_LLC
+ flag
+ - arm/rdn1edge: Add support for dual-chip configuration and use CREATE_SEQ
+ helper macro to compare chip count
+ - arm/sgm: Always use SCMI for SGM platforms
+ - arm/sgm775: Add support for dynamic config using fconf
+ - arm/sgi: Add multi-chip mode parameter in HW_CONFIG dts, macros for remote
+ chip device region, chip_id and multi_chip_mode to platform variant info,
+ and introduce number of chips macro
+ - brcm: Add BL2 and BL31 support common across Broadcom platforms
+ - brcm: Add iproc SPI Nor flash support, spi driver, emmc driver, and support
+ to retrieve plat_toc_flags
+ - hisilicon: hikey960: Enable system power off callback
+ - intel: Enable bridge access, SiP SMC secure register access, and uboot
+ entrypoint support
+ - intel: Implement platform specific system reset 2
+ - intel: Introduce mailbox response length handling
+ - imx: console: Use CONSOLE_T_BASE for UART base address and generic console_t
+ data structure
+ - imx8mm: Provide uart base as build option and add the support for opteed spd
+ on imx8mq/imx8mm
+ - imx8qx: Provide debug uart num as build
+ - imx8qm: Apply clk/pinmux configuration for DEBUG_CONSOLE and provide debug
+ uart num as build param
+ - marvell: a8k: Implement platform specific power off and add support for
+ loading MG CM3 images
+ - mediatek: mt8183: Add Vmodem/Vcore DVS init level
+ - qemu: Support optional encryption of BL31 and BL32 images and
+ ARM_LINUX_KERNEL_AS_BL33 to pass FDT address
+ - qemu: Define ARMV7_SUPPORTS_VFP
+ - qemu: Implement PSCI_CPU_OFF and qemu_system_off via semihosting
+ - renesas: rcar_gen3: Add new board revision for M3ULCB
+ - rockchip: Enable workaround for erratum 855873, claim a macro to enable hdcp
+ feature for DP, enable power domains of rk3399 before reset, add support for
+ UART3 as serial output, and initialize reset and poweroff GPIOs with known
+ invalid value
+ - rpi: Implement PSCI CPU_OFF, use MMIO accessor, autodetect Mini-UART vs.
+ PL011 configuration, and allow using PL011 UART for RPi3/RPi4
+ - rpi3: Include GPIO driver in all BL stages and use same "clock-less" setup
+ scheme as RPi4
+ - rpi3/4: Add support for offlining CPUs
+ - st: stm32mp1: platform.mk: Support generating multiple images in one build,
+ migrate to implicit rules, derive map file name from target name, generate
+ linker script with fixed name, and use PHONY for the appropriate targets
+ - st: stm32mp1: Add support for SPI-NOR, raw NAND, and SPI-NAND boot device,
+ QSPI, FMC2 driver
+ - st: stm32mp1: Use stm32mp_get_ddr_ns_size() function, set XN attribute for
+ some areas in BL2, dynamically map DDR later and non-cacheable during its
+ test, add a function to get non-secure DDR size, add DT helper for reg by
+ name, and add compilation flags for boot devices
+ - socionext: uniphier: Turn on ENABLE_PIE
+ - ti: k3: Add PIE support
+ - xilinx: versal: Add set wakeup source, client wakeup, query data, request
+ wakeup, PM_INIT_FINALIZE, PM_GET_TRUSTZONE_VERSION, PM IOCTL, support for
+ suspend related, and Get_ChipID APIs
+ - xilinx: versal: Implement power down/restart related EEMI, SMC handler for
+ EEMI, PLL related PM, clock related PM, pin control related PM, reset
+ related PM, device related PM , APIs
+ - xilinx: versal: Enable ipi mailbox service
+ - xilinx: versal: Add get_api_version support and support to send PM API to
+ PMC using IPI
+ - xilinx: zynqmp: Add checksum support for IPI data, GET_CALLBACK_DATA
+ function, support to query max divisor, CLK_SET_RATE_PARENT in gem clock
+ node, support for custom type flags, LPD WDT clock to the pm_clock
+ structure, idcodes for new RFSoC silicons ZU48DR and ZU49DR, and id for new
+ RFSoC device ZU39DR
+- Security
+ - Use Speculation Barrier instruction for v8.5+ cores
+ - Add support for optional firmware encryption feature (experimental).
+ - Introduce a new `dualroot` chain of trust.
+ - aarch64: Prevent speculative execution past ERET
+ - aarch32: Stop speculative execution past exception returns.
+- SPCI
+ - Introduced the Secure Partition Manager Dispatcher (SPMD) component as a new
+ standard service.
+- Tools
+ - cert_create: Introduce CoT build option and TBBR CoT makefile, and define
+ the dualroot CoT
+ - encrypt_fw: Add firmware authenticated encryption tool
+ - memory: Add show_memory script that prints a representation of the memory
+ layout for the latest build
+
+### Changed
+
+- Arm Architecture
+ - PIE: Make call to GDT relocation fixup generalized
+- BL-Specific
+ - Increase maximum size of BL2 image
+ - BL31: Discard .dynsym .dynstr .hash sections to make ENABLE_PIE work
+ - BL31: Split into two separate memory regions
+ - Unify BL linker scripts and reduce code duplication.
+- Build System
+ - Changes to drive cert_create for dualroot CoT
+ - Enable -Wlogical-op always
+ - Enable -Wshadow always
+ - Refactor the warning flags
+ - PIE: Pass PIE options only to BL31
+ - Reduce space lost to object alignment
+ - Set lld as the default linker for Clang builds
+ - Remove -Wunused-const-variable and -Wpadded warning
+ - Remove -Wmissing-declarations warning from WARNING1 level
+- Drivers
+ - authentication: Necessary fix in drivers to upgrade to mbedtls-2.18.0
+ - console: Integrate UART base address in generic console_t
+ - gicv3: Change API for GICR_IPRIORITYR accessors and separate GICD and GICR
+ accessor functions
+ - io: Change seek offset to signed long long and panic in case of io setup
+ failure
+ - smmu: SMMUv3: Changed retry loop to delay timer
+ - tbbr: Reduce size of hash and ECDSA key buffers when possible
+- Library Code
+ - libc: Consolidate the size_t, unified, and NULL definitions, and unify
+ intmax_t and uintmax_t on AArch32/64
+ - ROMLIB: Optimize memory layout when ROMLIB is used
+ - xlat_tables_v2: Use ARRAY_SIZE in REGISTER_XLAT_CONTEXT_FULL_SPEC, merge
+ REGISTER_XLAT_CONTEXT\_{FULL_SPEC,RO_BASE_TABLE}, and simplify end address
+ checks in mmap_add_region_check()
+- Platforms
+ - allwinner: Adjust SRAM A2 base to include the ARISC vectors, clean up MMU
+ setup, reenable USE_COHERENT_MEM, remove unused include path, move the
+ NOBITS region to SRAM A1, convert AXP803 regulator setup code into a driver,
+ enable clock before resetting I2C/RSB
+ - allwinner: h6: power: Switch to using the AXP driver
+ - allwinner: a64: power: Use fdt_for_each_subnode, remove obsolete register
+ check, remove duplicate DT check, and make sunxi_turn_off_soc static
+ - allwinner: Build PMIC bus drivers only in BL31, clean up PMIC-related error
+ handling, and synchronize PMIC enumerations
+ - arm/a5ds: Change boot address to point to DDR address
+ - arm/common: Check for out-of-bound accesses in the platform io policies
+ - arm/corstone700: Updating the kernel arguments to support initramfs, use
+ fdts DDR memory and XIP rootfs, and set UART clocks to 32MHz
+ - arm/fvp: Modify multithreaded dts file of DynamIQ FVPs, slightly bump the
+ stack size for bl1 and bl2, remove re-definition of topology related build
+ options, stop reclaiming init code with Clang builds, and map only the
+ needed DRAM region statically in BL31/SP_MIN
+ - arm/juno: Maximize space allocated to SCP_BL2
+ - arm/sgi: Bump bl1 RW limit, mark remote chip shared ram as non-cacheable,
+ move GIC related constants to board files, include AFF3 affinity in core
+ position calculation, move bl31_platform_setup to board file, and move
+ topology information to board folder
+ - common: Refactor load_auth_image_internal().
+ - hisilicon: Remove uefi-tools in hikey and hikey960 documentation
+ - intel: Modify non secure access function, BL31 address mapping, mailbox's
+ get_config_status, and stratix10 BL31 parameter handling
+ - intel: Remove un-needed checks for qspi driver r/w and s10 unused source
+ code
+ - intel: Change all global sip function to static
+ - intel: Refactor common platform code
+ - intel: Create SiP service header file
+ - marvell: armada: scp_bl2: Allow loading up to 8 images
+ - marvell: comphy-a3700: Support SGMII COMPHY power off and fix USB3 powering
+ on when on lane 2
+ - marvell: Consolidate console register calls
+ - mediatek: mt8183: Protect 4GB~8GB dram memory, refine GIC driver for low
+ power scenarios, and switch PLL/CLKSQ/ck_off/axi_26m control to SPM
+ - qemu: Update flash address map to keep FIP in secure FLASH0
+ - renesas: rcar_gen3: Update IPL and Secure Monitor Rev.2.0.6, update DDR
+ setting for H3, M3, M3N, change fixed destination address of BL31 and BL32,
+ add missing #{address,size}-cells into generated DT, pass DT to OpTee OS,
+ and move DDR drivers out of staging
+ - rockchip: Make miniloader ddr_parameter handling optional, cleanup securing
+ of ddr regions, move secure init to separate file, use base+size for secure
+ ddr regions, bring TZRAM_SIZE values in lined, and prevent macro expansion
+ in paths
+ - rpi: Move plat_helpers.S to common
+ - rpi3: gpio: Simplify GPIO setup
+ - rpi4: Skip UART initialisation
+ - st: stm32m1: Use generic console_t data structure, remove second QSPI flash
+ instance, update for FMC2 pin muxing, and reduce MAX_XLAT_TABLES to 4
+ - socionext: uniphier: Make on-chip SRAM and I/O register regions configurable
+ - socionext: uniphier: Make PSCI related, counter control, UART, pinmon, NAND
+ controller, and eMMC controller base addresses configurable
+ - socionext: uniphier: Change block_addressing flag and the return value type
+ of .is_usb_boot() to bool
+ - socionext: uniphier: Run BL33 at EL2, call uniphier_scp_is_running() only
+ when on-chip STM is supported, define PLAT_XLAT_TABLES_DYNAMIC only for BL2,
+ support read-only xlat tables, use enable_mmu() in common function, shrink
+ UNIPHIER_ROM_REGION_SIZE, prepare uniphier_soc_info() for next SoC, extend
+ boot device detection for future SoCs, make all BL images completely
+ position-independent, make uniphier_mmap_setup() work with PIE, pass SCP
+ base address as a function parameter, set buffer offset and length for
+ io_block dynamically, and use more mmap_add_dynamic_region() for loading
+ images
+ - spd/trusty: Disable error messages seen during boot, allow gic base to be
+ specified with GICD_BASE, and allow getting trusty memsize from
+ BL32_MEM_SIZE instead of TSP_SEC_MEM_SIZE
+ - ti: k3: common: Enable ARM cluster power down and rename device IDs to be
+ more consistent
+ - ti: k3: drivers: ti_sci: Put sequence number in coherent memory and remove
+ indirect structure of const data
+ - xilinx: Move ipi mailbox svc to xilinx common
+ - xilinx: zynqmp: Use GIC framework for warm restart
+ - xilinx: zynqmp: pm: Move custom clock flags to typeflags, remove
+ CLK_TOPSW_LSBUS from invalid clock list and rename FPD WDT clock ID
+ - xilinx: versal: Increase OCM memory size for DEBUG builds and adjust cpu
+ clock, Move versal_def.h and versal_private to include directory
+- Tools
+ - sptool: Updated sptool to accommodate building secure partition packages.
+
+### Resolved Issues
+
+- Arm Architecture
+ - Fix crash dump for lower EL
+- BL-Specific
+ - Bug fix: Protect TSP prints with lock
+ - Fix boot failures on some builds linked with ld.lld.
+- Build System
+ - Fix clang build if CC is not in the path.
+ - Fix 'BL stage' comment for build macros
+- Code Quality
+ - coverity: Fix various MISRA violations including null pointer violations, C
+ issues in BL1/BL2/BL31 and FDT helper functions, using boolean essential,
+ type, and removing unnecessary header file and comparisons to LONG_MAX in
+ debugfs devfip
+ - Based on coding guidelines, replace all `unsigned long` depending on if
+ fixed based on AArch32 or AArch64.
+ - Unify type of "cpu_idx" and Platform specific defines across PSCI module.
+- Drivers
+ - auth: Necessary fix in drivers to upgrade to mbedtls-2.18.0
+ - delay_timer: Fix non-standard frequency issue in udelay
+ - gicv3: Fix compiler dependent behavior
+ - gic600: Fix include ordering according to the coding style and power up
+ sequence
+- Library Code
+ - el3_runtime: Fix stack pointer maintenance on EA handling path, fixup
+ 'cm_setup_context' prototype, and adds TPIDR_EL2 register to the context
+ save restore routines
+ - libc: Fix SIZE_MAX on AArch32
+ - locks: T589: Fix insufficient ordering guarantees in bakery lock
+ - pmf: Fix 'tautological-constant-compare' error, Make the runtime
+ instrumentation work on AArch32, and Simplify PMF helper macro definitions
+ across header files
+ - xlat_tables_v2: Fix assembler warning of PLAT_RO_XLAT_TABLES
+- Platforms
+ - allwinner: Fix H6 GPIO and CCU memory map addresses and incorrect ARISC code
+ patch offset check
+ - arm/a5ds: Correct system freq and Cache Writeback Granule, and cleanup
+ enable-method in devicetree
+ - arm/fvp: Fix incorrect GIC mapping, BL31 load address and image size for
+ RESET_TO_BL31=1, topology description of cpus for DynamIQ based FVP, and
+ multithreaded FVP power domain tree
+ - arm/fvp: spm-mm: Correcting instructions to build SPM for FVP
+ - arm/common: Fix ROTPK hash generation for ECDSA encryption, BL2 bug in
+ dynamic configuration initialisation, and current RECLAIM_INIT_CODE behavior
+ - arm/rde1edge: Fix incorrect topology tree description
+ - arm/sgi: Fix the incorrect check for SCMI channel ID
+ - common: Flush dcache when storing timestamp
+ - intel: Fix UEFI decompression issue, memory calibration, SMC SIP service,
+ mailbox config return status, mailbox driver logic, FPGA manager on
+ reconfiguration, and mailbox send_cmd issue
+ - imx: Fix shift-overflow errors, the rdc memory region slot's offset,
+ multiple definition of ipc_handle, missing inclusion of cdefs.h, and correct
+ the SGIs that used for secure interrupt
+ - mediatek: mt8183: Fix AARCH64 init fail on CPU0
+ - rockchip: Fix definition of struct param_ddr_usage
+ - rpi4: Fix documentation of armstub config entry
+ - st: Correct io possible NULL pointer dereference and device_size type, nand
+ xor_ecc.val assigned value, static analysis tool issues, and fix incorrect
+ return value and correctly check pwr-regulators node
+ - xilinx: zynqmp: Correct syscnt freq for QEMU and fix clock models and IDs of
+ GEM-related clocks
+
+### Known Issues
+
+- Build System
+ - 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.
+
+ - Intermittent assertion firing `ASSERT: services/spd/tspd/tspd_main.c:105`
+- Coverity
+ - Intermittent Race condition in Coverity Jenkins Build Job
+- Platforms
+ - 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
+
+## [2.2.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/v2.1..refs/tags/v2.2) (2019-10-22)
+
+### 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-Hercules/HerculesAE: Support added for Cortex-Hercules and
+ Cortex-HerculesAE CPUs
+ - cortex-Hercules/HerculesAE: Enable AMU for Cortex-Hercules and
+ Cortex-HerculesAE
+ - 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
+
+## [2.1.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/v2.0..refs/tags/v2.1) (2019-03-29)
+
+### 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=<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 `<name>_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
+
+## [2.0.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/v1.6..refs/tags/v2.0) (2018-10-02)
+
+### 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.
+
+## [1.6.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/v1.5..refs/tags/v1.6) (2018-09-21)
+
+### 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.
+
+## [1.5.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/v1.4..refs/tags/v1.5) (2018-03-20)
+
+### 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.
+
+## [1.4.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/v1.3..refs/tags/v1.4) (2017-07-07)
+
+### 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.
+
+## [1.3.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/v1.2..refs/tags/v1.3) (2016-10-13)
+
+### 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.
+
+## [1.2.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/v1.1..refs/tags/v1.2) (2015-12-22)
+
+### 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.
+
+## [1.1.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/v1.0..refs/tags/v1.1) (2015-02-04)
+
+### 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.
+
+## [1.0.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/v0.4..refs/tags/v1.0) (2014-08-28)
+
+### 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 `<SimName>` reported by the FVP in this
+ version has changed. For example, for the Cortex-A57x4-A53x4 Base FVP, the
+ `<SimName>` 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:
+
+ ```
+ <SimName>System Generator:FVP_Base_A57x4_A53x4</SimName>
+ ```
+
+ to System Generator:FVP_Base_Cortex-A57x4_A53x4
+
+ A similar change can be made to the other Cortex-A57-A53 Base FVP variants.
+
+## [0.4.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/v0.3..refs/tags/v0.4) (2014-06-03)
+
+### 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.
+
+## [0.3.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/v0.2..refs/tags/v0.3) (2014-02-28)
+
+### 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.
+
+## [0.2.0](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/4b825dc642cb6eb9a060e54bf8d69288fbee4904..refs/tags/v0.2) (2013-10-25)
+
+### 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-2022, Arm Limited and Contributors. All rights reserved.*
+
+[mbed tls releases]: https://tls.mbed.org/tech-updates/releases
+[pr#1002]: https://github.com/ARM-software/arm-trusted-firmware/pull/1002#issuecomment-312650193
+[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
diff --git a/docs/components/activity-monitors.rst b/docs/components/activity-monitors.rst
new file mode 100644
index 0000000..dd45c43
--- /dev/null
+++ b/docs/components/activity-monitors.rst
@@ -0,0 +1,34 @@
+Activity Monitors
+=================
+
+FEAT_AMUv1 of the Armv8-A architecture introduces the Activity Monitors
+extension. This extension describes the architecture for the Activity Monitor
+Unit (|AMU|), an optional non-invasive component for monitoring core events
+through a set of 64-bit counters.
+
+When the ``ENABLE_AMU=1`` build option is provided, Trusted Firmware-A sets up
+the |AMU| prior to its exit from EL3, and will save and restore architected
+|AMU| counters as necessary upon suspend and resume.
+
+.. _Activity Monitor Auxiliary Counters:
+
+Auxiliary counters
+------------------
+
+FEAT_AMUv1 describes a set of implementation-defined auxiliary counters (also
+known as group 1 counters), controlled by the ``ENABLE_AMU_AUXILIARY_COUNTERS``
+build option.
+
+As a security precaution, Trusted Firmware-A does not enable these by default.
+Instead, platforms may configure their auxiliary counters through one of two
+possible mechanisms:
+
+- |FCONF|, controlled by the ``ENABLE_AMU_FCONF`` build option.
+- A platform implementation of the ``plat_amu_topology`` function (the default).
+
+See :ref:`Activity Monitor Unit (AMU) Bindings` for documentation on the |FCONF|
+device tree bindings.
+
+--------------
+
+*Copyright (c) 2021, Arm Limited. All rights reserved.*
diff --git a/docs/components/arm-sip-service.rst b/docs/components/arm-sip-service.rst
new file mode 100644
index 0000000..b51a94d
--- /dev/null
+++ b/docs/components/arm-sip-service.rst
@@ -0,0 +1,435 @@
+Arm 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
+- DebugFS interface
+
+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 <firmware_design_pmf>`
+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.
+
+DebugFS interface
+-----------------
+
+The optional DebugFS interface is accessed through an SMC SiP service. Refer
+to the component documentation for details.
+
+String parameters are passed through a shared buffer using a specific union:
+
+.. code:: c
+
+ union debugfs_parms {
+ struct {
+ char fname[MAX_PATH_LEN];
+ } open;
+
+ struct mount {
+ char srv[MAX_PATH_LEN];
+ char where[MAX_PATH_LEN];
+ char spec[MAX_PATH_LEN];
+ } mount;
+
+ struct {
+ char path[MAX_PATH_LEN];
+ dir_t dir;
+ } stat;
+
+ struct {
+ char oldpath[MAX_PATH_LEN];
+ char newpath[MAX_PATH_LEN];
+ } bind;
+ };
+
+Format of the dir_t structure as such:
+
+.. code:: c
+
+ typedef struct {
+ char name[NAMELEN];
+ long length;
+ unsigned char mode;
+ unsigned char index;
+ unsigned char dev;
+ qid_t qid;
+ } dir_t;
+
+
+* Identifiers
+
+======================== =============================================
+SMC_OK 0
+SMC_UNK -1
+DEBUGFS_E_INVALID_PARAMS -2
+======================== =============================================
+
+======================== =============================================
+MOUNT 0
+CREATE 1
+OPEN 2
+CLOSE 3
+READ 4
+WRITE 5
+SEEK 6
+BIND 7
+STAT 8
+INIT 10
+VERSION 11
+======================== =============================================
+
+MOUNT
+~~~~~
+
+Description
+^^^^^^^^^^^
+This operation mounts a blob of data pointed to by path stored in `src`, at
+filesystem location pointed to by path stored in `where`, using driver pointed
+to by path in `spec`.
+
+Parameters
+^^^^^^^^^^
+======== ============================================================
+uint32_t FunctionID (0x82000030 / 0xC2000030)
+uint32_t ``MOUNT``
+======== ============================================================
+
+Return values
+^^^^^^^^^^^^^
+
+=============== ==========================================================
+int32_t w0 == SMC_OK on success
+
+ w0 == DEBUGFS_E_INVALID_PARAMS if mount operation failed
+=============== ==========================================================
+
+OPEN
+~~~~
+
+Description
+^^^^^^^^^^^
+This operation opens the file path pointed to by `fname`.
+
+Parameters
+^^^^^^^^^^
+
+======== ============================================================
+uint32_t FunctionID (0x82000030 / 0xC2000030)
+uint32_t ``OPEN``
+uint32_t mode
+======== ============================================================
+
+mode can be one of:
+
+.. code:: c
+
+ enum mode {
+ O_READ = 1 << 0,
+ O_WRITE = 1 << 1,
+ O_RDWR = 1 << 2,
+ O_BIND = 1 << 3,
+ O_DIR = 1 << 4,
+ O_STAT = 1 << 5
+ };
+
+Return values
+^^^^^^^^^^^^^
+
+=============== ==========================================================
+int32_t w0 == SMC_OK on success
+
+ w0 == DEBUGFS_E_INVALID_PARAMS if open operation failed
+
+uint32_t w1: file descriptor id on success.
+=============== ==========================================================
+
+CLOSE
+~~~~~
+
+Description
+^^^^^^^^^^^
+
+This operation closes a file described by a file descriptor obtained by a
+previous call to OPEN.
+
+Parameters
+^^^^^^^^^^
+
+======== ============================================================
+uint32_t FunctionID (0x82000030 / 0xC2000030)
+uint32_t ``CLOSE``
+uint32_t File descriptor id returned by OPEN
+======== ============================================================
+
+Return values
+^^^^^^^^^^^^^
+=============== ==========================================================
+int32_t w0 == SMC_OK on success
+
+ w0 == DEBUGFS_E_INVALID_PARAMS if close operation failed
+=============== ==========================================================
+
+READ
+~~~~
+
+Description
+^^^^^^^^^^^
+
+This operation reads a number of bytes from a file descriptor obtained by
+a previous call to OPEN.
+
+Parameters
+^^^^^^^^^^
+
+======== ============================================================
+uint32_t FunctionID (0x82000030 / 0xC2000030)
+uint32_t ``READ``
+uint32_t File descriptor id returned by OPEN
+uint32_t Number of bytes to read
+======== ============================================================
+
+Return values
+^^^^^^^^^^^^^
+
+On success, the read data is retrieved from the shared buffer after the
+operation.
+
+=============== ==========================================================
+int32_t w0 == SMC_OK on success
+
+ w0 == DEBUGFS_E_INVALID_PARAMS if read operation failed
+
+uint32_t w1: number of bytes read on success.
+=============== ==========================================================
+
+SEEK
+~~~~
+
+Description
+^^^^^^^^^^^
+
+Move file pointer for file described by given `file descriptor` of given
+`offset` related to `whence`.
+
+Parameters
+^^^^^^^^^^
+
+======== ============================================================
+uint32_t FunctionID (0x82000030 / 0xC2000030)
+uint32_t ``SEEK``
+uint32_t File descriptor id returned by OPEN
+sint32_t offset in the file relative to whence
+uint32_t whence
+======== ============================================================
+
+whence can be one of:
+
+========= ============================================================
+KSEEK_SET 0
+KSEEK_CUR 1
+KSEEK_END 2
+========= ============================================================
+
+Return values
+^^^^^^^^^^^^^
+
+=============== ==========================================================
+int32_t w0 == SMC_OK on success
+
+ w0 == DEBUGFS_E_INVALID_PARAMS if seek operation failed
+=============== ==========================================================
+
+BIND
+~~~~
+
+Description
+^^^^^^^^^^^
+
+Create a link from `oldpath` to `newpath`.
+
+Parameters
+^^^^^^^^^^
+
+======== ============================================================
+uint32_t FunctionID (0x82000030 / 0xC2000030)
+uint32_t ``BIND``
+======== ============================================================
+
+Return values
+^^^^^^^^^^^^^
+
+=============== ==========================================================
+int32_t w0 == SMC_OK on success
+
+ w0 == DEBUGFS_E_INVALID_PARAMS if bind operation failed
+=============== ==========================================================
+
+STAT
+~~~~
+
+Description
+^^^^^^^^^^^
+
+Perform a stat operation on provided file `name` and returns the directory
+entry statistics into `dir`.
+
+Parameters
+^^^^^^^^^^
+
+======== ============================================================
+uint32_t FunctionID (0x82000030 / 0xC2000030)
+uint32_t ``STAT``
+======== ============================================================
+
+Return values
+^^^^^^^^^^^^^
+
+=============== ==========================================================
+int32_t w0 == SMC_OK on success
+
+ w0 == DEBUGFS_E_INVALID_PARAMS if stat operation failed
+=============== ==========================================================
+
+INIT
+~~~~
+
+Description
+^^^^^^^^^^^
+Initial call to setup the shared exchange buffer. Notice if successful once,
+subsequent calls fail after a first initialization. The caller maps the same
+page frame in its virtual space and uses this buffer to exchange string
+parameters with filesystem primitives.
+
+Parameters
+^^^^^^^^^^
+
+======== ============================================================
+uint32_t FunctionID (0x82000030 / 0xC2000030)
+uint32_t ``INIT``
+uint64_t Physical address of the shared buffer.
+======== ============================================================
+
+Return values
+^^^^^^^^^^^^^
+
+=============== ======================================================
+int32_t w0 == SMC_OK on success
+
+ w0 == DEBUGFS_E_INVALID_PARAMS if already initialized,
+ or internal error occurred.
+=============== ======================================================
+
+VERSION
+~~~~~~~
+
+Description
+^^^^^^^^^^^
+Returns the debugfs interface version if implemented in TF-A.
+
+Parameters
+^^^^^^^^^^
+
+======== ============================================================
+uint32_t FunctionID (0x82000030 / 0xC2000030)
+uint32_t ``VERSION``
+======== ============================================================
+
+Return values
+^^^^^^^^^^^^^
+
+=============== ======================================================
+int32_t w0 == SMC_OK on success
+
+ w0 == SMC_UNK if interface is not implemented
+
+uint32_t w1: On success, debugfs interface version, 32 bits
+ value with major version number in upper 16 bits and
+ minor version in lower 16 bits.
+=============== ======================================================
+
+* CREATE(1) and WRITE (5) command identifiers are unimplemented and
+ return `SMC_UNK`.
+
+--------------
+
+*Copyright (c) 2017-2020, Arm Limited and Contributors. All rights reserved.*
+
+.. _SMC Calling Convention: https://developer.arm.com/docs/den0028/latest
diff --git a/docs/components/cot-binding.rst b/docs/components/cot-binding.rst
new file mode 100644
index 0000000..4f8c8b7
--- /dev/null
+++ b/docs/components/cot-binding.rst
@@ -0,0 +1,332 @@
+Chain of trust bindings
+=======================
+
+The device tree allows to describe the chain of trust with the help of
+'cot' node which contain 'manifests' and 'images' as sub-nodes.
+'manifests' and 'images' nodes contains number of sub-nodes (i.e. 'certificate'
+and 'image' nodes) mentioning properties of the certificate and image respectively.
+
+Also, device tree describes 'non-volatile-counters' node which contains number of
+sub-nodes mentioning properties of all non-volatile-counters used in the chain of trust.
+
+cot
+------------------------------------------------------------------
+This is root node which contains 'manifests' and 'images' as sub-nodes
+
+
+Manifests and Certificate node bindings definition
+----------------------------------------------------------------
+
+- Manifests node
+ Description: Container of certificate nodes.
+
+ PROPERTIES
+
+ - compatible:
+ Usage: required
+
+ Value type: <string>
+
+ Definition: must be "arm, cert-descs"
+
+- Certificate node
+ Description:
+
+ Describes certificate properties which are used
+ during the authentication process.
+
+ PROPERTIES
+
+ - root-certificate
+ Usage:
+
+ Required for the certificate with no parent.
+ In other words, certificates which are validated
+ using root of trust public key.
+
+ Value type: <boolean>
+
+ - image-id
+ Usage: Required for every certificate with unique id.
+
+ Value type: <u32>
+
+ - parent
+ Usage:
+
+ It refers to their parent image, which typically contains
+ information to authenticate the certificate.
+ This property is required for all non-root certificates.
+
+ This property is not required for root-certificates
+ as root-certificates are validated using root of trust
+ public key provided by platform.
+
+ Value type: <phandle>
+
+ - signing-key
+ Usage:
+
+ This property is used to refer public key node present in
+ parent certificate node and it is required property for all
+ non-root certificates which are authenticated using public-key
+ present in parent certificate.
+
+ This property is not required for root-certificates
+ as root-certificates are validated using root of trust
+ public key provided by platform.
+
+ Value type: <phandle>
+
+ - antirollback-counter
+ Usage:
+
+ This property is used by all certificates which are
+ protected against rollback attacks using a non-volatile
+ counter and it is an optional property.
+
+ This property is used to refer one of the non-volatile
+ counter sub-node present in 'non-volatile counters' node.
+
+ Value type: <phandle>
+
+
+ SUBNODES
+ - Description:
+
+ Hash and public key information present in the certificate
+ are shown by these nodes.
+
+ - public key node
+ Description: Provide public key information in the certificate.
+
+ PROPERTIES
+
+ - oid
+ Usage:
+
+ This property provides the Object ID of public key
+ provided in the certificate which the help of which
+ public key information can be extracted.
+
+ Value type: <string>
+
+ - hash node
+ Description: Provide the hash information in the certificate.
+
+ PROPERTIES
+
+ - oid
+ Usage:
+
+ This property provides the Object ID of hash provided in
+ the certificate which the help of which hash information
+ can be extracted.
+
+ Value type: <string>
+
+Example:
+
+.. code:: c
+
+ cot {
+ manifests {
+ compatible = "arm, cert-descsâ€
+
+ trusted-key-cert: trusted-key-cert {
+ root-certificate;
+ image-id = <TRUSTED_KEY_CERT_ID>;
+ antirollback-counter = <&trusted_nv_counter>;
+
+ trusted-world-pk: trusted-world-pk {
+ oid = TRUSTED_WORLD_PK_OID;
+ };
+ non-trusted-world-pk: non-trusted-world-pk {
+ oid = NON_TRUSTED_WORLD_PK_OID;
+ };
+ };
+
+ scp_fw_key_cert: scp_fw_key_cert {
+ image-id = <SCP_FW_KEY_CERT_ID>;
+ parent = <&trusted-key-cert>;
+ signing-key = <&trusted_world_pk>;
+ antirollback-counter = <&trusted_nv_counter>;
+
+ scp_fw_content_pk: scp_fw_content_pk {
+ oid = SCP_FW_CONTENT_CERT_PK_OID;
+ };
+ };
+ .
+ .
+ .
+
+ next-certificate {
+
+ };
+ };
+ };
+
+Images and Image node bindings definition
+-----------------------------------------
+
+- Images node
+ Description: Container of image nodes
+
+ PROPERTIES
+
+ - compatible:
+ Usage: required
+
+ Value type: <string>
+
+ Definition: must be "arm, img-descs"
+
+- Image node
+ Description:
+
+ Describes image properties which will be used during
+ authentication process.
+
+ PROPERTIES
+
+ - image-id
+ Usage: Required for every image with unique id.
+
+ Value type: <u32>
+
+ - parent
+ Usage:
+
+ Required for every image to provide a reference to
+ its parent image, which contains the necessary information
+ to authenticate it.
+
+ Value type: <phandle>
+
+ - hash
+ Usage:
+
+ Required for all images which are validated using
+ hash method. This property is used to refer hash
+ node present in parent certificate node.
+
+ Value type: <phandle>
+
+ Note:
+
+ Currently, all images are validated using 'hash'
+ method. In future, there may be multiple methods can
+ be used to validate the image.
+
+Example:
+
+.. code:: c
+
+ cot {
+ images {
+ compatible = "arm, img-descs";
+
+ scp_bl2_image {
+ image-id = <SCP_BL2_IMAGE_ID>;
+ parent = <&scp_fw_content_cert>;
+ hash = <&scp_fw_hash>;
+ };
+
+ .
+ .
+ .
+
+ next-img {
+
+ };
+ };
+ };
+
+non-volatile counter node binding definition
+--------------------------------------------
+
+- non-volatile counters node
+ Description: Contains properties for non-volatile counters.
+
+ PROPERTIES
+
+ - compatible:
+ Usage: required
+
+ Value type: <string>
+
+ Definition: must be "arm, non-volatile-counter"
+
+ - #address-cells
+ Usage: required
+
+ Value type: <u32>
+
+ Definition:
+
+ Must be set according to address size
+ of non-volatile counter register
+
+ - #size-cells
+ Usage: required
+
+ Value type: <u32>
+
+ Definition: must be set to 0
+
+ SUBNODE
+ - counters node
+ Description: Contains various non-volatile counters present in the platform.
+
+ PROPERTIES
+ - id
+ Usage: Required for every nv-counter with unique id.
+
+ Value type: <u32>
+
+ - reg
+ Usage:
+
+ Register base address of non-volatile counter and it is required
+ property.
+
+ Value type: <u32>
+
+ - oid
+ Usage:
+
+ This property provides the Object ID of non-volatile counter
+ provided in the certificate and it is required property.
+
+ Value type: <string>
+
+Example:
+Below is non-volatile counters example for ARM platform
+
+.. code:: c
+
+ non_volatile_counters: non_volatile_counters {
+ compatible = "arm, non-volatile-counter";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ trusted-nv-counter: trusted_nv_counter {
+ id = <TRUSTED_NV_CTR_ID>;
+ reg = <TFW_NVCTR_BASE>;
+ oid = TRUSTED_FW_NVCOUNTER_OID;
+ };
+
+ non_trusted_nv_counter: non_trusted_nv_counter {
+ id = <NON_TRUSTED_NV_CTR_ID>;
+ reg = <NTFW_CTR_BASE>;
+ oid = NON_TRUSTED_FW_NVCOUNTER_OID;
+ };
+ };
+
+Future update to chain of trust binding
+---------------------------------------
+
+This binding document needs to be revisited to generalise some terminologies
+which are currently specific to X.509 certificates for e.g. Object IDs.
+
+*Copyright (c) 2020, Arm Limited. All rights reserved.*
diff --git a/docs/components/debugfs-design.rst b/docs/components/debugfs-design.rst
new file mode 100644
index 0000000..2536515
--- /dev/null
+++ b/docs/components/debugfs-design.rst
@@ -0,0 +1,125 @@
+========
+Debug FS
+========
+
+.. contents::
+
+Overview
+--------
+
+The *DebugFS* feature is primarily aimed at exposing firmware debug data to
+higher SW layers such as a non-secure component. Such component can be the
+TFTF test payload or a Linux kernel module.
+
+Virtual filesystem
+------------------
+
+The core functionality lies in a virtual file system based on a 9p file server
+interface (`Notes on the Plan 9 Kernel Source`_ and
+`Linux 9p remote filesystem protocol`_).
+The implementation permits exposing virtual files, firmware drivers, and file blobs.
+
+Namespace
+~~~~~~~~~
+
+Two namespaces are exposed:
+
+ - # is used as root for drivers (e.g. #t0 is the first uart)
+ - / is used as root for virtual "files" (e.g. /fip, or /dev/uart)
+
+9p interface
+~~~~~~~~~~~~
+
+The associated primitives are:
+
+- Unix-like:
+
+ - open(): create a file descriptor that acts as a handle to the file passed as
+ an argument.
+ - close(): close the file descriptor created by open().
+ - read(): read from a file to a buffer.
+ - write(): write from a buffer to a file.
+ - seek(): set the file position indicator of a file descriptor either to a
+ relative or an absolute offset.
+ - stat(): get information about a file (type, mode, size, ...).
+
+.. code:: c
+
+ int open(const char *name, int flags);
+ int close(int fd);
+ int read(int fd, void *buf, int n);
+ int write(int fd, void *buf, int n);
+ int seek(int fd, long off, int whence);
+ int stat(char *path, dir_t *dir);
+
+- Specific primitives :
+
+ - mount(): create a link between a driver and spec.
+ - create(): create a file in a specific location.
+ - bind(): expose the content of a directory to another directory.
+
+.. code:: c
+
+ int mount(char *srv, char *mnt, char *spec);
+ int create(const char *name, int flags);
+ int bind(char *path, char *where);
+
+This interface is embedded into the BL31 run-time payload when selected by build
+options. The interface multiplexes drivers or emulated "files":
+
+- Debug data can be partitioned into different virtual files e.g. expose PMF
+ measurements through a file, and internal firmware state counters through
+ another file.
+- This permits direct access to a firmware driver, mainly for test purposes
+ (e.g. a hardware device that may not be accessible to non-privileged/
+ non-secure layers, or for which no support exists in the NS side).
+
+SMC interface
+-------------
+
+The communication with the 9p layer in BL31 is made through an SMC conduit
+(`SMC Calling Convention`_), using a specific SiP Function Id. An NS
+shared buffer is used to pass path string parameters, or e.g. to exchange
+data on a read operation. Refer to :ref:`ARM SiP Services <arm sip services>`
+for a description of the SMC interface.
+
+Security considerations
+-----------------------
+
+- Due to the nature of the exposed data, the feature is considered experimental
+ and importantly **shall only be used in debug builds**.
+- Several primitive imply string manipulations and usage of string formats.
+- Special care is taken with the shared buffer to avoid TOCTOU attacks.
+
+Limitations
+-----------
+
+- In order to setup the shared buffer, the component consuming the interface
+ needs to allocate a physical page frame and transmit its address.
+- In order to map the shared buffer, BL31 requires enabling the dynamic xlat
+ table option.
+- Data exchange is limited by the shared buffer length. A large read operation
+ might be split into multiple read operations of smaller chunks.
+- On concurrent access, a spinlock is implemented in the BL31 service to protect
+ the internal work buffer, and re-entrancy into the filesystem layers.
+- Notice, a physical device driver if exposed by the firmware may conflict with
+ the higher level OS if the latter implements its own driver for the same
+ physical device.
+
+Applications
+------------
+
+The SMC interface is accessible from an NS environment, that is:
+
+- a test payload, bootloader or hypervisor running at NS-EL2
+- a Linux kernel driver running at NS-EL1
+- a Linux userspace application through the kernel driver
+
+--------------
+
+*Copyright (c) 2019-2020, Arm Limited and Contributors. All rights reserved.*
+
+.. _SMC Calling Convention: https://developer.arm.com/docs/den0028/latest
+.. _Notes on the Plan 9 Kernel Source: http://lsub.org/who/nemo/9.pdf
+.. _Linux 9p remote filesystem protocol: https://www.kernel.org/doc/Documentation/filesystems/9p.txt
+.. _ARM SiP Services: arm-sip-service.rst
diff --git a/docs/components/el3-spmc.rst b/docs/components/el3-spmc.rst
new file mode 100644
index 0000000..1a2d427
--- /dev/null
+++ b/docs/components/el3-spmc.rst
@@ -0,0 +1,597 @@
+EL3 Secure Partition Manager
+****************************
+
+.. contents::
+
+Foreword
+========
+
+This document describes the design of the EL3 SPMC based on the FF-A specification.
+EL3 SPMC provides reference FF-A compliant implementation without S-EL2 virtualization support,
+to help adopt and migrate to FF-A early.
+EL3 SPMC implementation in TF-A:
+
+- Manages a single S-EL1 Secure Partition
+- Provides a standard protocol for communication and memory sharing between FF-A endpoints.
+- Provides support for EL3 Logical Partitions to support easy migration from EL3 to S-EL1.
+
+Sample reference stack
+======================
+
+The following diagram illustrates a possible configuration when the
+FEAT_SEL2 architecture extension is not implemented, showing the SPMD
+and SPMC at EL3, one S-EL1 secure partition, with an optional
+Hypervisor:
+
+.. image:: ../resources/diagrams/ff-a-spm-at-el3.png
+
+TF-A build options
+==================
+
+This section explains the TF-A build options involved in building
+an FF-A based SPM where the SPMD and SPMC are located at EL3:
+
+- **SPD=spmd**: this option selects the SPMD component to relay the FF-A
+ protocol from NWd to SWd back and forth. It is not possible to
+ enable another Secure Payload Dispatcher when this option is chosen.
+- **SPMC_AT_EL3**: this option adjusts the SPMC exception level to being
+ at EL3.
+- **ARM_SPMC_MANIFEST_DTS**: this option specifies a manifest file
+ providing SP description. It is required when
+ ``SPMC_AT_EL3`` is enabled, the secure partitions are loaded
+ by BL2 on behalf of the SPMC.
+
+Notes:
+
+- BL32 option is re-purposed to specify the S-EL1 TEE or SP image.
+ BL32 option can be omitted if using TF-A Test Secure Payload as SP.
+- BL33 option can specify the TFTF binary or a normal world loader
+ such as U-Boot or the UEFI framework payload.
+
+Sample TF-A build command line when the SPMC is located at EL3:
+
+.. code:: shell
+
+ make \
+ CROSS_COMPILE=aarch64-none-elf- \
+ SPD=spmd \
+ SPMD_SPM_AT_SEL2=0 \
+ SPMC_AT_EL3=1 \
+ BL32=<path-to-tee-binary> (opt for TSP) \
+ BL33=<path-to-bl33-binary> \
+ PLAT=fvp \
+ all fip
+
+FVP model invocation
+====================
+
+Sample FVP command line invocation:
+
+.. code:: shell
+
+ <path-to-fvp-model>/FVP_Base_RevC-2xAEMvA -C pctl.startup=0.0.0.0 \
+ -C cluster0.NUM_CORES=4 -C cluster1.NUM_CORES=4 -C bp.secure_memory=1 \
+ -C bp.secureflashloader.fname=trusted-firmware-a/build/fvp/debug/bl1.bin \
+ -C bp.flashloader0.fname=trusted-firmware-a/build/fvp/debug/fip.bin \
+ -C bp.pl011_uart0.out_file=fvp-uart0.log -C bp.pl011_uart1.out_file=fvp-uart1.log \
+ -C bp.pl011_uart2.out_file=fvp-uart2.log -C bp.vis.disable_visualisation=1
+
+
+Platform Guide
+==============
+
+- Platform Hooks See - `[4]`_
+
+ - plat_spmc_shmem_begin
+ - plat_spmc_shmem_reclaim
+
+SPMC provides platform hooks related to memory management interfaces.
+These hooks can be used for platform specific implementations like
+for managing access control, programming TZ Controller or MPUs.
+These hooks are called by SPMC before the initial share request completes,
+and after the final reclaim has been completed.
+
+- Datastore
+
+ - plat_spmc_shmem_datastore_get
+
+ EL3 SPMC uses datastore for tracking memory transaction descriptors.
+ On FVP platform datastore is allocated from TZC DRAM section.
+ Other platforms need to allocate a similar secure memory region
+ to be used as shared memory datastore.
+
+ The accessor function is used during SPMC initialization to obtain
+ address and size of the datastore.
+ SPMC will also zero out the provided memory region.
+
+- Platform Defines See - `[5]`_
+
+ - SECURE_PARTITION_COUNT
+ Number of Secure Partitions supported: must be 1.
+
+ - NS_PARTITION_COUNT
+ Number of NWd Partitions supported.
+
+ - MAX_EL3_LP_DESCS_COUNT
+ Number of Logical Partitions supported.
+
+Logical Secure Partition (LSP)
+==============================
+
+- The SPMC provides support for statically allocated EL3 Logical Secure Partitions
+ as per FF-A v1.1 specification.
+- The DECLARE_LOGICAL_PARTITION macro can be used to add a LSP.
+- For reference implementation See - `[2]`_
+
+.. image:: ../resources/diagrams/ff-a-lsp-at-el3.png
+
+SPMC boot
+=========
+
+The SPMD and SPMC are built into the BL31 image along with TF-A's runtime components.
+BL2 loads the BL31 image as a part of (secure) boot process.
+
+The SPMC manifest is loaded by BL2 as the ``TOS_FW_CONFIG`` image `[9]`_.
+
+BL2 passes the SPMC manifest address to BL31 through a register.
+
+At boot time, the SPMD in BL31 runs from the primary core, initializes the core
+contexts and launches the SPMC passing the following information through
+registers:
+
+- X0 holds the SPMC manifest blob address.
+- X4 holds the currently running core linear id.
+
+Parsing SP partition manifests
+------------------------------
+
+SPMC consumes the SP manifest, as defined in `[7]`_.
+SP manifest fields align with Hafnium SP manifest for easy porting.
+
+.. code:: shell
+
+ compatible = "arm,ffa-manifest-1.0";
+
+ ffa-version = <0x00010001>; /* 31:16 - Major, 15:0 - Minor */
+ id = <0x8001>;
+ uuid = <0x6b43b460 0x74a24b78 0xade24502 0x40682886>;
+ messaging-method = <0x3>; /* Direct Messaging Only */
+ exception-level = <0x2>; /* S-EL1 */
+ execution-state = <0>;
+ execution-ctx-count = <8>;
+ gp-register-num = <0>;
+ power-management-messages = <0x7>;
+
+
+Passing boot data to the SP
+---------------------------
+
+In `[1]`_ , the section "Boot information protocol" defines a method for passing
+data to the SPs at boot time. It specifies the format for the boot information
+descriptor and boot information header structures, which describe the data to be
+exchanged between SPMC and SP.
+The specification also defines the types of data that can be passed.
+The aggregate of both the boot info structures and the data itself is designated
+the boot information blob, and is passed to a Partition as a contiguous memory
+region.
+
+Currently, the SPM implementation supports the FDT type which is used to pass the
+partition's DTB manifest.
+
+The region for the boot information blob is statically allocated (4K) by SPMC.
+BLOB contains Boot Info Header, followed by SP Manifest contents.
+
+The configuration of the boot protocol is done in the SP manifest. As defined by
+the specification, the manifest field 'gp-register-num' configures the GP register
+which shall be used to pass the address to the partitions boot information blob when
+booting the partition.
+
+Supported interfaces
+====================
+
+The following interfaces are exposed to SPs only:
+
+- ``FFA_MSG_WAIT``
+- ``FFA_MEM_RETRIEVE_REQ``
+- ``FFA_MEM_RETRIEVE_RESP``
+- ``FFA_MEM_RELINQUISH``
+- ``FFA_SECONDARY_EP_REGISTER``
+
+The following interfaces are exposed to both NS Client and SPs:
+
+- ``FFA_VERSION``
+- ``FFA_FEATURES``
+- ``FFA_RX_RELEASE``
+- ``FFA_RXTX_MAP``
+- ``FFA_RXTX_UNMAP``
+- ``FFA_PARTITION_INFO_GET``
+- ``FFA_ID_GET``
+- ``FFA_MSG_SEND_DIRECT_REQ``
+- ``FFA_MSG_SEND_DIRECT_RESP``
+- ``FFA_MEM_FRAG_TX``
+- ``FFA_SPM_ID_GET``
+
+The following additional interfaces are forwarded from SPMD to support NS Client:
+
+- ``FFA_RUN``
+- ``FFA_MEM_LEND``
+- ``FFA_MEM_SHARE``
+- ``FFA_MEM_FRAG_RX``
+- ``FFA_MEM_RECLAIM``
+
+
+FFA_VERSION
+-----------
+
+``FFA_VERSION`` requires a *requested_version* parameter from the caller.
+SPMD forwards call to SPMC, the SPMC returns its own implemented version.
+SPMC asserts SP and SPMC are at same FF-A Version.
+
+FFA_FEATURES
+------------
+
+FF-A features supported by the SPMC may be discovered by secure partitions at
+boot (that is prior to NWd is booted) or run-time.
+
+The SPMC calling FFA_FEATURES at secure physical FF-A instance always get
+FFA_SUCCESS from the SPMD.
+
+The request made by an Hypervisor or OS kernel is forwarded to the SPMC and
+the response relayed back to the NWd.
+
+
+FFA_RXTX_MAP
+------------
+
+FFA_RXTX_UNMAP
+--------------
+
+When invoked from a secure partition FFA_RXTX_MAP maps the provided send and
+receive buffers described by their PAs to the EL3 translation regime
+as secure buffers in the MMU descriptors.
+
+When invoked from the Hypervisor or OS kernel, the buffers are mapped into the
+SPMC EL3 translation regime and marked as NS buffers in the MMU
+descriptors.
+
+The FFA_RXTX_UNMAP unmaps the RX/TX pair from the translation regime of the
+caller, either it being the Hypervisor or OS kernel, as well as a secure
+partition.
+
+FFA_PARTITION_INFO_GET
+----------------------
+
+Partition info get call can originate:
+
+- from SP to SPMC
+- from Hypervisor or OS kernel to SPMC. The request is relayed by the SPMD.
+
+The format (v1.0 or v1.1) of the populated data structure returned is based upon the
+FFA version of the calling entity.
+
+EL3 SPMC also supports returning only the count of partitions deployed.
+
+All LSPs and SP are discoverable from FFA_PARTITION_INFO_GET call made by
+either SP or NWd entities.
+
+FFA_ID_GET
+----------
+
+The FF-A ID space is split into a non-secure space and secure space:
+
+- FF-A ID with bit 15 clear relates to VMs.
+- FF-A ID with bit 15 set related to SPs or LSPs.
+- FF-A IDs 0, 0xffff, 0x8000 are assigned respectively to the Hypervisor
+ (or OS Kernel if Hyp is absent), SPMD and SPMC.
+
+This convention helps the SPM to determine the origin and destination worlds in
+an FF-A ABI invocation. In particular the SPM shall filter unauthorized
+transactions in its world switch routine. It must not be permitted for a VM to
+use a secure FF-A ID as origin world by spoofing:
+
+- A VM-to-SP direct request/response shall set the origin world to be non-secure
+ (FF-A ID bit 15 clear) and destination world to be secure (FF-A ID bit 15
+ set).
+- Similarly, an SP-to-LSP direct request/response shall set the FF-A ID bit 15
+ for both origin and destination IDs.
+
+An incoming direct message request arriving at SPMD from NWd is forwarded to
+SPMC without a specific check. The SPMC is resumed through eret and "knows" the
+message is coming from normal world in this specific code path. Thus the origin
+endpoint ID must be checked by SPMC for being a normal world ID.
+
+An SP sending a direct message request must have bit 15 set in its origin
+endpoint ID and this can be checked by the SPMC when the SP invokes the ABI.
+
+The SPMC shall reject the direct message if the claimed world in origin endpoint
+ID is not consistent:
+
+- It is either forwarded by SPMD and thus origin endpoint ID must be a "normal
+ world ID",
+- or initiated by an SP and thus origin endpoint ID must be a "secure world ID".
+
+
+FFA_MSG_SEND_DIRECT_REQ
+-----------------------
+
+FFA_MSG_SEND_DIRECT_RESP
+------------------------
+
+This is a mandatory interface for secure partitions participating in direct request
+and responses with the following rules:
+
+- An SP can send a direct request to LSP.
+- An LSP can send a direct response to SP.
+- An SP cannot send a direct request to an Hypervisor or OS kernel.
+- An Hypervisor or OS kernel can send a direct request to an SP or LSP.
+- An SP and LSP can send a direct response to an Hypervisor or OS kernel.
+- SPMD can send direct request to SPMC.
+
+FFA_SPM_ID_GET
+--------------
+
+Returns the FF-A ID allocated to an SPM component which can be one of SPMD
+or SPMC.
+
+At initialization, the SPMC queries the SPMD for the SPMC ID, using the
+FFA_ID_GET interface, and records it. The SPMC can also query the SPMD ID using
+the FFA_SPM_ID_GET interface at the secure physical FF-A instance.
+
+Secure partitions call this interface at the virtual FF-A instance, to which
+the SPMC returns the SPMC ID.
+
+The Hypervisor or OS kernel can issue the FFA_SPM_ID_GET call handled by the
+SPMD, which returns the SPMC ID.
+
+FFA_ID_GET
+----------
+
+Returns the FF-A ID of the calling endpoint.
+
+FFA_MEM_SHARE
+-------------
+
+FFA_MEM_LEND
+------------
+
+- If SP is borrower in the memory transaction, these calls are forwarded to SPMC.
+ SPMC performs Relayer responsibilities, caches the memory descriptors in the datastore,
+ and allocates FF-A memory handle.
+- If format of descriptor was v1.0, SPMC converts the descriptor to v1.1 before caching.
+ In case of fragmented sharing, conversion of memory descriptors happens after last
+ fragment has been received.
+- Multiple borrowers (including NWd endpoint) and fragmented memory sharing are supported.
+
+FFA_MEM_RETRIEVE_REQ
+--------------------
+
+FFA_MEM_RETRIEVE_RESP
+---------------------
+
+- Memory retrieve is supported only from SP.
+- SPMC fetches the cached memory descriptor from the datastore,
+- Performs Relayer responsiilities and sends FFA_MEM_RETRIEVE_RESP back to SP.
+- If descriptor size is more than RX buffer size, SPMC will send the descriptor in fragments.
+- SPMC will set NS Bit to 1 in memory descriptor response.
+
+FFA_MEM_FRAG_RX
+---------------
+
+FFA_MEM_FRAG_TX
+---------------
+
+FFA_MEM_FRAG_RX is to be used by:
+
+- SP if FFA_MEM_RETRIEVE_RESP returned descriptor with fragment length less than total length.
+- or by SPMC if FFA_MEM_SHARE/FFA_MEM_LEND is called with fragment length less than total length.
+
+SPMC validates handle and Endpoint ID and returns response with FFA_MEM_FRAG_TX.
+
+FFA_SECONDARY_EP_REGISTER
+-------------------------
+
+When the SPMC boots, secure partition is initialized on its primary
+Execution Context.
+
+The FFA_SECONDARY_EP_REGISTER interface is to be used by a secure partition
+from its first execution context, to provide the entry point address for
+secondary execution contexts.
+
+A secondary EC is first resumed either upon invocation of PSCI_CPU_ON from
+the NWd or by invocation of FFA_RUN.
+
+Power management
+================
+
+In platforms with or without secure virtualization:
+
+- The NWd owns the platform PM policy.
+- The Hypervisor or OS kernel is the component initiating PSCI service calls.
+- The EL3 PSCI library is in charge of the PM coordination and control
+ (eventually writing to platform registers).
+- While coordinating PM events, the PSCI library calls backs into the Secure
+ Payload Dispatcher for events the latter has statically registered to.
+
+When using the SPMD as a Secure Payload Dispatcher:
+
+- A power management event is relayed through the SPD hook to the SPMC.
+- In the current implementation CPU_ON (svc_on_finish), CPU_OFF
+ (svc_off), CPU_SUSPEND (svc_suspend) and CPU_SUSPEND_RESUME (svc_suspend_finish)
+ hooks are registered.
+
+Secure partitions scheduling
+============================
+
+The FF-A specification `[1]`_ provides two ways to relinquinsh CPU time to
+secure partitions. For this a VM (Hypervisor or OS kernel), or SP invokes one of:
+
+- the FFA_MSG_SEND_DIRECT_REQ interface.
+- the FFA_RUN interface.
+
+Additionally a secure interrupt can pre-empt the normal world execution and give
+CPU cycles by transitioning to EL3.
+
+Partition Runtime State and Model
+=================================
+
+EL3 SPMC implements Partition runtime states are described in v1.1 FF-A specification `[1]`_
+
+An SP can be in one of the following state:
+
+- RT_STATE_WAITING
+- RT_STATE_RUNNING
+- RT_STATE_PREEMPTED
+- RT_STATE_BLOCKED
+
+An SP will transition to one of the following runtime model when not in waiting state:
+
+- RT_MODEL_DIR_REQ
+- RT_MODEL_RUN
+- RT_MODEL_INIT
+- RT_MODEL_INTR
+
+Platform topology
+=================
+
+SPMC only supports a single Pinned MP S-EL1 SP. The *execution-ctx-count*
+SP manifest field should match the number of physical PE.
+
+Interrupt handling
+==================
+
+Secure Interrupt handling
+-------------------------
+
+- SPMC is capable of forwarding Secure interrupt to S-EL1 SP
+ which has preempted the normal world.
+- Interrupt is forwarded to SP using FFA_INTERRUPT interface.
+- Interrupt Number is not passed, S-EL1 SP can access the GIC registers directly.
+- Upon completion of Interrupt handling SP is expected to return to
+ SPMC using FFA_MSG_WAIT interface.
+- SPMC returns to normal world after interrupt handling is completed.
+
+In the scenario when secure interrupt occurs while the secure partition is running,
+the SPMC is not involved and the handling is implementation defined in the TOS.
+
+Non-Secure Interrupt handling
+-----------------------------
+
+The 'managed exit' scenario is the responsibility of the TOS and the SPMC is not involved.
+
+Test Secure Payload (TSP)
+=========================
+
+- TSP provides reference implementation of FF-A programming model.
+- TSP has the following support:
+
+ - SP initialization on all CPUs.
+ - Consuming Power Messages including CPU_ON, CPU_OFF, CPU_SUSPEND, CPU_SUSPEND_RESUME.
+ - Event Loop to receive Direct Requests.
+ - Sending Direct Response.
+ - Memory Sharing helper library.
+ - Ability to handle secure interrupt (timer).
+
+TSP Tests in CI
+---------------
+
+- TSP Tests are exercised in the TF-A CI using prebuilt FF-A Linux Test driver in NWd.
+- Expected output:
+
+.. code:: shell
+
+ #ioctl 255
+ Test: Echo Message to SP.
+ Status: Completed Test Case: 1
+ Test Executed Successfully
+
+ Test: Message Relay vis SP to EL3 LSP.
+ Status: Completed Test Case: 2
+ Test Executed Successfully
+
+ Test: Memory Send.
+ Verified 1 constituents successfully
+ Status: Completed Test Case: 3
+ Test Executed Successfully
+
+ Test: Memory Send in Fragments.
+ Verified 256 constituents successfully
+ Status: Completed Test Case: 4
+ Test Executed Successfully
+
+ Test: Memory Lend.
+ Verified 1 constituents successfully
+ Status: Completed Test Case: 5
+ Test Executed Successfully
+
+ Test: Memory Lend in Fragments.
+ Verified 256 constituents successfully
+ Status: Completed Test Case: 6
+ Test Executed Successfully
+
+ Test: Memory Send with Multiple Endpoints.
+ random: fast init done
+ Verified 256 constituents successfully
+ Status: Completed Test Case: 7
+ Test Executed Successfully
+
+ Test: Memory Lend with Multiple Endpoints.
+ Verified 256 constituents successfully
+ Status: Completed Test Case: 8
+ Test Executed Successfully
+
+ Test: Ensure Duplicate Memory Send Requests are Rejected.
+ Status: Completed Test Case: 9
+ Test Executed Successfully
+
+ Test: Ensure Duplicate Memory Lend Requests are Rejected.
+ Status: Completed Test Case: 10
+ Test Executed Successfully
+
+ 0 Tests Failed
+
+ Exiting Test Application - Total Failures: 0
+
+
+References
+==========
+
+.. _[1]:
+
+[1] `Arm Firmware Framework for Arm A-profile <https://developer.arm.com/docs/den0077/latest>`__
+
+.. _[2]:
+
+[2] https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/plat/arm/board/fvp/fvp_el3_spmc_logical_sp.c
+
+.. _[3]:
+
+[3] `Trusted Boot Board Requirements
+Client <https://developer.arm.com/documentation/den0006/d/>`__
+
+.. _[4]:
+
+[4] https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/plat/arm/board/fvp/fvp_el3_spmc.c
+
+.. _[5]:
+
+[5] https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/plat/arm/board/fvp/include/platform_def.h
+
+.. _[6]:
+
+[6] https://trustedfirmware-a.readthedocs.io/en/latest/components/ffa-manifest-binding.html
+
+.. _[7]:
+
+[7] https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/plat/arm/board/fvp/fdts/fvp_tsp_sp_manifest.dts
+
+.. _[8]:
+
+[8] https://lists.trustedfirmware.org/archives/list/tf-a@lists.trustedfirmware.org/thread/CFQFGU6H2D5GZYMUYGTGUSXIU3OYZP6U/
+
+.. _[9]:
+
+[9] https://trustedfirmware-a.readthedocs.io/en/latest/design/firmware-design.html#dynamic-configuration-during-cold-boot
+
+--------------
+
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
diff --git a/docs/components/exception-handling.rst b/docs/components/exception-handling.rst
new file mode 100644
index 0000000..6f223c6
--- /dev/null
+++ b/docs/components/exception-handling.rst
@@ -0,0 +1,619 @@
+Exception 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 :ref:`Firmware Design document <handling-an-smc>`. However, the
+|EHF| changes the semantics of `Interrupt handling`_ and :ref:`synchronous
+exceptions <Effect on SMC calls>` other than SMCs.
+
+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 :ref:`Secure Payload Dispatcher
+ <firmware_design_sel1_spd>`, which is an EL3 component that operates in EL3
+ on behalf of Secure OS.
+
+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:
+
+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 :ref:`CSS=0, TEL3=0 <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 :ref:`synchronously <sp-synchronous-int>`
+ handled over to S-EL1.
+
+- 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:
+
+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 :ref:`Firmware Design guide<configuring-secure-interrupts>` 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.
+
+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 :ref:`EL3 interrupt handler
+<el3-runtime-firmware>`.
+
+The :ref:`SDEI dispatcher<SDEI: Software Delegated Exception Interface>`, 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.
+
+Interrupt handling example
+--------------------------
+
+The following annotated snippet demonstrates how a platform might choose to
+assign interrupts to fictitious dispatchers:
+
+.. code:: c
+
+ #include <common/interrupt_props.h>
+ #include <drivers/arm/gic_common.h>
+ #include <exception_mgmt.h>
+
+ ...
+
+ /*
+ * 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:
+
+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 :ref:`SDEI
+explicit dispatches <explicit-dispatch-of-events>`, this has to be done via
+calling ``ehf_activate_priority()``. See `Run-time flow`_.
+
+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:
+
+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`__).
+
+.. __: https://developer.arm.com/docs/den0028/latest
+
+- *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 :ref:`Interrupt Management Framework<el3-runtime-firmware>` for EL3
+ interrupts. This also results in setting the routing bits in ``SCR_EL3``.
+
+#. 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-2020, 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
diff --git a/docs/components/fconf/amu-bindings.rst b/docs/components/fconf/amu-bindings.rst
new file mode 100644
index 0000000..047f75e
--- /dev/null
+++ b/docs/components/fconf/amu-bindings.rst
@@ -0,0 +1,142 @@
+Activity Monitor Unit (AMU) Bindings
+====================================
+
+To support platform-defined Activity Monitor Unit (|AMU|) auxiliary counters
+through FCONF, the ``HW_CONFIG`` device tree accepts several |AMU|-specific
+nodes and properties.
+
+Bindings
+^^^^^^^^
+
+.. contents::
+ :local:
+
+``/cpus/cpus/cpu*`` node properties
+"""""""""""""""""""""""""""""""""""
+
+The ``cpu`` node has been augmented to support a handle to an associated |AMU|
+view, which should describe the counters offered by the core.
+
++---------------+-------+---------------+-------------------------------------+
+| Property name | Usage | Value type | Description |
++===============+=======+===============+=====================================+
+| ``amu`` | O | ``<phandle>`` | If present, indicates that an |AMU| |
+| | | | is available and its counters are |
+| | | | described by the node provided. |
++---------------+-------+---------------+-------------------------------------+
+
+``/cpus/amus`` node properties
+""""""""""""""""""""""""""""""
+
+The ``amus`` node describes the |AMUs| implemented by the cores in the system.
+This node does not have any properties.
+
+``/cpus/amus/amu*`` node properties
+"""""""""""""""""""""""""""""""""""
+
+An ``amu`` node describes the layout and meaning of the auxiliary counter
+registers of one or more |AMUs|, and may be shared by multiple cores.
+
++--------------------+-------+------------+------------------------------------+
+| Property name | Usage | Value type | Description |
++====================+=======+============+====================================+
+| ``#address-cells`` | R | ``<u32>`` | Value shall be 1. Specifies that |
+| | | | the ``reg`` property array of |
+| | | | children of this node uses a |
+| | | | single cell. |
++--------------------+-------+------------+------------------------------------+
+| ``#size-cells`` | R | ``<u32>`` | Value shall be 0. Specifies that |
+| | | | no size is required in the ``reg`` |
+| | | | property in children of this node. |
++--------------------+-------+------------+------------------------------------+
+
+``/cpus/amus/amu*/counter*`` node properties
+""""""""""""""""""""""""""""""""""""""""""""
+
+A ``counter`` node describes an auxiliary counter belonging to the parent |AMU|
+view.
+
++-------------------+-------+-------------+------------------------------------+
+| Property name | Usage | Value type | Description |
++===================+=======+=============+====================================+
+| ``reg`` | R | array | Represents the counter register |
+| | | | index, and must be a single cell. |
++-------------------+-------+-------------+------------------------------------+
+| ``enable-at-el3`` | O | ``<empty>`` | The presence of this property |
+| | | | indicates that this counter should |
+| | | | be enabled prior to EL3 exit. |
++-------------------+-------+-------------+------------------------------------+
+
+Example
+^^^^^^^
+
+An example system offering four cores made up of two clusters, where the cores
+of each cluster share different |AMUs|, may use something like the following:
+
+.. code-block::
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ amus {
+ amu0: amu-0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ counterX: counter@0 {
+ reg = <0>;
+
+ enable-at-el3;
+ };
+
+ counterY: counter@1 {
+ reg = <1>;
+
+ enable-at-el3;
+ };
+ };
+
+ amu1: amu-1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ counterZ: counter@0 {
+ reg = <0>;
+
+ enable-at-el3;
+ };
+ };
+ };
+
+ cpu0@00000 {
+ ...
+
+ amu = <&amu0>;
+ };
+
+ cpu1@00100 {
+ ...
+
+ amu = <&amu0>;
+ };
+
+ cpu2@10000 {
+ ...
+
+ amu = <&amu1>;
+ };
+
+ cpu3@10100 {
+ ...
+
+ amu = <&amu1>;
+ };
+ }
+
+In this situation, ``cpu0`` and ``cpu1`` (the two cores in the first cluster),
+share the view of their AMUs defined by ``amu0``. Likewise, ``cpu2`` and
+``cpu3`` (the two cores in the second cluster), share the view of their |AMUs|
+defined by ``amu1``. This will cause ``counterX`` and ``counterY`` to be enabled
+for both ``cpu0`` and ``cpu1``, and ``counterZ`` to be enabled for both ``cpu2``
+and ``cpu3``.
diff --git a/docs/components/fconf/fconf_properties.rst b/docs/components/fconf/fconf_properties.rst
new file mode 100644
index 0000000..20cc758
--- /dev/null
+++ b/docs/components/fconf/fconf_properties.rst
@@ -0,0 +1,39 @@
+DTB binding for FCONF properties
+================================
+
+This document describes the device tree format of |FCONF| properties. These
+properties are not related to a specific platform and can be queried from
+common code.
+
+Dynamic configuration
+~~~~~~~~~~~~~~~~~~~~~
+
+The |FCONF| framework expects a *dtb-registry* node with the following field:
+
+- compatible [mandatory]
+ - value type: <string>
+ - Must be the string "fconf,dyn_cfg-dtb_registry".
+
+Then a list of subnodes representing a configuration |DTB|, which can be used
+by |FCONF|. Each subnode should be named according to the information it
+contains, and must be formed with the following fields:
+
+- load-address [mandatory]
+ - value type: <u64>
+ - Physical loading base address of the configuration.
+
+- max-size [mandatory]
+ - value type: <u32>
+ - Maximum size of the configuration.
+
+- id [mandatory]
+ - value type: <u32>
+ - Image ID of the configuration.
+
+- ns-load-address [optional]
+ - value type: <u64>
+ - Physical loading base address of the configuration in the non-secure
+ memory.
+ Only needed by those configuration files which require being loaded
+ in secure memory (at load-address) as well as in non-secure memory
+ e.g. HW_CONFIG
diff --git a/docs/components/fconf/index.rst b/docs/components/fconf/index.rst
new file mode 100644
index 0000000..029f324
--- /dev/null
+++ b/docs/components/fconf/index.rst
@@ -0,0 +1,149 @@
+Firmware Configuration Framework
+================================
+
+This document provides an overview of the |FCONF| framework.
+
+Introduction
+~~~~~~~~~~~~
+
+The Firmware CONfiguration Framework (|FCONF|) is an abstraction layer for
+platform specific data, allowing a "property" to be queried and a value
+retrieved without the requesting entity knowing what backing store is being used
+to hold the data.
+
+It is used to bridge new and old ways of providing platform-specific data.
+Today, information like the Chain of Trust is held within several, nested
+platform-defined tables. In the future, it may be provided as part of a device
+blob, along with the rest of the information about images to load.
+Introducing this abstraction layer will make migration easier and will preserve
+functionality for platforms that cannot / don't want to use device tree.
+
+Accessing properties
+~~~~~~~~~~~~~~~~~~~~
+
+Properties defined in the |FCONF| are grouped around namespaces and
+sub-namespaces: a.b.property.
+Examples namespace can be:
+
+- (|TBBR|) Chain of Trust data: tbbr.cot.trusted_boot_fw_cert
+- (|TBBR|) dynamic configuration info: tbbr.dyn_config.disable_auth
+- Arm io policies: arm.io_policies.bl2_image
+- GICv3 properties: hw_config.gicv3_config.gicr_base
+
+Properties can be accessed with the ``FCONF_GET_PROPERTY(a,b,property)`` macro.
+
+Defining properties
+~~~~~~~~~~~~~~~~~~~
+
+Properties composing the |FCONF| have to be stored in C structures. If
+properties originate from a different backend source such as a device tree,
+then the platform has to provide a ``populate()`` function which essentially
+captures the property and stores them into a corresponding |FCONF| based C
+structure.
+
+Such a ``populate()`` function is usually platform specific and is associated
+with a specific backend source. For example, a populator function which
+captures the hardware topology of the platform from the HW_CONFIG device tree.
+Hence each ``populate()`` function must be registered with a specific
+``config_type`` identifier. It broadly represents a logical grouping of
+configuration properties which is usually a device tree file.
+
+Example:
+ - FW_CONFIG: properties related to base address, maximum size and image id
+ of other DTBs etc.
+ - TB_FW: properties related to trusted firmware such as IO policies,
+ mbedtls heap info etc.
+ - HW_CONFIG: properties related to hardware configuration of the SoC
+ such as topology, GIC controller, PSCI hooks, CPU ID etc.
+
+Hence the ``populate()`` callback must be registered to the (|FCONF|) framework
+with the ``FCONF_REGISTER_POPULATOR()`` macro. This ensures that the function
+would be called inside the generic ``fconf_populate()`` function during
+initialization.
+
+::
+
+ int fconf_populate_topology(uintptr_t config)
+ {
+ /* read hw config dtb and fill soc_topology struct */
+ }
+
+ FCONF_REGISTER_POPULATOR(HW_CONFIG, topology, fconf_populate_topology);
+
+Then, a wrapper has to be provided to match the ``FCONF_GET_PROPERTY()`` macro:
+
+::
+
+ /* generic getter */
+ #define FCONF_GET_PROPERTY(a,b,property) a##__##b##_getter(property)
+
+ /* my specific getter */
+ #define hw_config__topology_getter(prop) soc_topology.prop
+
+This second level wrapper can be used to remap the ``FCONF_GET_PROPERTY()`` to
+anything appropriate: structure, array, function, etc..
+
+To ensure a good interpretation of the properties, this documentation must
+explain how the properties are described for a specific backend. Refer to the
+:ref:`binding-document` section for more information and example.
+
+Loading the property device tree
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``fconf_load_config(image_id)`` must be called to load fw_config and
+tb_fw_config devices tree containing the properties' values. This must be done
+after the io layer is initialized, as the |DTB| is stored on an external
+device (FIP).
+
+.. uml:: ../../resources/diagrams/plantuml/fconf_bl1_load_config.puml
+
+Populating the properties
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Once a valid device tree is available, the ``fconf_populate(config)`` function
+can be used to fill the C data structure with the data from the config |DTB|.
+This function will call all the ``populate()`` callbacks which have been
+registered with ``FCONF_REGISTER_POPULATOR()`` as described above.
+
+.. uml:: ../../resources/diagrams/plantuml/fconf_bl2_populate.puml
+
+Namespace guidance
+~~~~~~~~~~~~~~~~~~
+
+As mentioned above, properties are logically grouped around namespaces and
+sub-namespaces. The following concepts should be considered when adding new
+properties/namespaces.
+The framework differentiates two types of properties:
+
+ - Properties used inside common code.
+ - Properties used inside platform specific code.
+
+The first category applies to properties being part of the firmware and shared
+across multiple platforms. They should be globally accessible and defined
+inside the ``lib/fconf`` directory. The namespace must be chosen to reflect the
+feature/data abstracted.
+
+Example:
+ - |TBBR| related properties: tbbr.cot.bl2_id
+ - Dynamic configuration information: dyn_cfg.dtb_info.hw_config_id
+
+The second category should represent the majority of the properties defined
+within the framework: Platform specific properties. They must be accessed only
+within the platform API and are defined only inside the platform scope. The
+namespace must contain the platform name under which the properties defined
+belong.
+
+Example:
+ - Arm io framework: arm.io_policies.bl31_id
+
+.. _binding-document:
+
+Properties binding information
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. toctree::
+ :maxdepth: 1
+
+ fconf_properties
+ amu-bindings
+ mpmm-bindings
diff --git a/docs/components/fconf/mpmm-bindings.rst b/docs/components/fconf/mpmm-bindings.rst
new file mode 100644
index 0000000..d3cc857
--- /dev/null
+++ b/docs/components/fconf/mpmm-bindings.rst
@@ -0,0 +1,48 @@
+Maximum Power Mitigation Mechanism (MPMM) Bindings
+==================================================
+
+|MPMM| support cannot be determined at runtime by the firmware. Instead, these
+DTB bindings allow the platform to communicate per-core support for |MPMM| via
+the ``HW_CONFIG`` device tree blob.
+
+Bindings
+^^^^^^^^
+
+.. contents::
+ :local:
+
+``/cpus/cpus/cpu*`` node properties
+"""""""""""""""""""""""""""""""""""
+
+The ``cpu`` node has been augmented to allow the platform to indicate support
+for |MPMM| on a given core.
+
++-------------------+-------+-------------+------------------------------------+
+| Property name | Usage | Value type | Description |
++===================+=======+=============+====================================+
+| ``supports-mpmm`` | O | ``<empty>`` | If present, indicates that |MPMM| |
+| | | | is available on this core. |
++-------------------+-------+-------------+------------------------------------+
+
+Example
+^^^^^^^
+
+An example system offering two cores, one with support for |MPMM| and one
+without, can be described as follows:
+
+.. code-block::
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu0@00000 {
+ ...
+
+ supports-mpmm;
+ };
+
+ cpu1@00100 {
+ ...
+ };
+ }
diff --git a/docs/components/ffa-manifest-binding.rst b/docs/components/ffa-manifest-binding.rst
new file mode 100644
index 0000000..7483c90
--- /dev/null
+++ b/docs/components/ffa-manifest-binding.rst
@@ -0,0 +1,296 @@
+FF-A manifest binding to device tree
+========================================
+
+This document defines the nodes and properties used to define a partition,
+according to the FF-A specification.
+
+Partition Properties
+--------------------
+
+- compatible [mandatory]
+ - value type: <string>
+ - Must be the string "arm,ffa-manifest-X.Y" which specifies the major and
+ minor versions of the device tree binding for the FFA manifest represented
+ by this node. The minor number is incremented if the binding changes in a
+ backwards compatible manner.
+
+ - X is an integer representing the major version number of this document.
+ - Y is an integer representing the minor version number of this document.
+
+- ffa-version [mandatory]
+ - value type: <u32>
+ - Must be two 16 bits values (X, Y), concatenated as 31:16 -> X,
+ 15:0 -> Y, where:
+
+ - X is the major version of FF-A expected by the partition at the FFA
+ instance it will execute.
+ - Y is the minor version of FF-A expected by the partition at the FFA
+ instance it will execute.
+
+- uuid [mandatory]
+ - value type: <prop-encoded-array>
+ - An array consisting of 4 <u32> values, identifying the UUID of the service
+ implemented by this partition. The UUID format is described in RFC 4122.
+
+- id
+ - value type: <u32>
+ - Pre-allocated partition ID.
+
+- auxiliary-id
+ - value type: <u32>
+ - Pre-allocated ID that could be used in memory management transactions.
+
+- description
+ - value type: <string>
+ - Name of the partition e.g. for debugging purposes.
+
+- execution-ctx-count [mandatory]
+ - value type: <u32>
+ - Number of vCPUs that a VM or SP wants to instantiate.
+
+ - In the absence of virtualization, this is the number of execution
+ contexts that a partition implements.
+ - If value of this field = 1 and number of PEs > 1 then the partition is
+ treated as UP & migrate capable.
+ - If the value of this field > 1 then the partition is treated as a MP
+ capable partition irrespective of the number of PEs.
+
+- exception-level [mandatory]
+ - value type: <u32>
+ - The target exception level for the partition:
+
+ - 0x0: EL1
+ - 0x1: S_EL0
+ - 0x2: S_EL1
+
+- execution-state [mandatory]
+ - value type: <u32>
+ - The target execution state of the partition:
+
+ - 0: AArch64
+ - 1: AArch32
+
+- load-address
+ - value type: <u64>
+ - Physical base address of the partition in memory. Absence of this field
+ indicates that the partition is position independent and can be loaded at
+ any address chosen at boot time.
+
+- entrypoint-offset
+ - value type: <u64>
+ - Offset from the base of the partition's binary image to the entry point of
+ the partition. Absence of this field indicates that the entry point is at
+ offset 0x0 from the base of the partition's binary.
+
+- xlat-granule [mandatory]
+ - value type: <u32>
+ - Translation granule used with the partition:
+
+ - 0x0: 4k
+ - 0x1: 16k
+ - 0x2: 64k
+
+- boot-order
+ - value type: <u32>
+ - A unique number amongst all partitions that specifies if this partition
+ must be booted before others. The partition with the smaller number will be
+ booted first.
+
+- rx-tx-buffer
+ - value type: "memory-regions" node
+ - Specific "memory-regions" nodes that describe the RX/TX buffers expected
+ by the partition.
+ The "compatible" must be the string "arm,ffa-manifest-rx_tx-buffer".
+
+- messaging-method [mandatory]
+ - value type: <u8>
+ - Specifies which messaging methods are supported by the partition, set bit
+ means the feature is supported, clear bit - not supported:
+
+ - Bit[0]: partition can receive direct requests if set
+ - Bit[1]: partition can send direct requests if set
+ - Bit[2]: partition can send and receive indirect messages
+
+- managed-exit
+ - value type: <empty>
+ - Specifies if managed exit is supported.
+ - This field is deprecated in favor of ns-interrupts-action field in the FF-A
+ v1.1 EAC0 spec.
+
+- ns-interrupts-action [mandatory]
+ - value type: <u32>
+ - Specifies the action that the SPMC must take in response to a Non-secure
+ physical interrupt.
+
+ - 0x0: Non-secure interrupt is queued
+ - 0x1: Non-secure interrupt is signaled after a managed exit
+ - 0x2: Non-secure interrupt is signaled
+
+ - This field supersedes the managed-exit field in the FF-A v1.0 spec.
+
+- has-primary-scheduler
+ - value type: <empty>
+ - Presence of this field indicates that the partition implements the primary
+ scheduler. If so, run-time EL must be EL1.
+
+- run-time-model
+ - value type: <u32>
+ - Run time model that the SPM must enforce for this SP:
+
+ - 0x0: Run to completion
+ - 0x1: Preemptible
+
+- time-slice-mem
+ - value type: <empty>
+ - Presence of this field indicates that the partition doesn't expect the
+ partition manager to time slice long running memory management functions.
+
+- gp-register-num
+ - value type: <u32>
+ - The field specifies the general purpose register number but not its width.
+ The width is derived from the partition's execution state, as specified in
+ the partition properties. For example, if the number value is 1 then the
+ general-purpose register used will be x1 in AArch64 state and w1 in AArch32
+ state.
+ Presence of this field indicates that the partition expects the address of
+ the FF-A boot information blob to be passed in the specified general purpose
+ register.
+
+- stream-endpoint-ids
+ - value type: <prop-encoded-array>
+ - List of <u32> tuples, identifying the IDs this partition is acting as
+ proxy for.
+
+- power-management-messages
+ - value type: <u32>
+ - Specifies which power management messages a partition subscribes to.
+ A set bit means the partition should be informed of the power event, clear
+ bit - should not be informed of event:
+
+ - Bit[0]: CPU_OFF
+ - Bit[1]: CPU_SUSPEND
+ - Bit[2]: CPU_SUSPEND_RESUME
+
+Memory Regions
+--------------
+
+- compatible [mandatory]
+ - value type: <string>
+ - Must be the string "arm,ffa-manifest-memory-regions".
+
+- description
+ - value type: <string>
+ - Name of the memory region e.g. for debugging purposes.
+
+- pages-count [mandatory]
+ - value type: <u32>
+ - Count of pages of memory region as a multiple of the translation granule
+ size
+
+- attributes [mandatory]
+ - value type: <u32>
+ - Mapping modes: ORed to get required permission
+
+ - 0x1: Read
+ - 0x2: Write
+ - 0x4: Execute
+ - 0x8: Security state
+
+- base-address
+ - value type: <u64>
+ - Base address of the region. The address must be aligned to the translation
+ granule size.
+ The address given may be a Physical Address (PA), Virtual Address (VA), or
+ Intermediate Physical Address (IPA). Refer to the FF-A specification for
+ more information on the restrictions around the address type.
+ If the base address is omitted then the partition manager must map a memory
+ region of the specified size into the partition's translation regime and
+ then communicate the region properties (including the base address chosen
+ by the partition manager) to the partition.
+
+Device Regions
+--------------
+
+- compatible [mandatory]
+ - value type: <string>
+ - Must be the string "arm,ffa-manifest-device-regions".
+
+- description
+ - value type: <string>
+ - Name of the device region e.g. for debugging purposes.
+
+- pages-count [mandatory]
+ - value type: <u32>
+ - Count of pages of memory region as a multiple of the translation granule
+ size
+
+- attributes [mandatory]
+ - value type: <u32>
+ - Mapping modes: ORed to get required permission
+
+ - 0x1: Read
+ - 0x2: Write
+ - 0x4: Execute
+ - 0x8: Security state
+
+- base-address [mandatory]
+ - value type: <u64>
+ - Base address of the region. The address must be aligned to the translation
+ granule size.
+ The address given may be a Physical Address (PA), Virtual Address (VA), or
+ Intermediate Physical Address (IPA). Refer to the FF-A specification for
+ more information on the restrictions around the address type.
+
+- smmu-id
+ - value type: <u32>
+ - On systems with multiple System Memory Management Units (SMMUs) this
+ identifier is used to inform the partition manager which SMMU the device is
+ upstream of. If the field is omitted then it is assumed that the device is
+ not upstream of any SMMU.
+
+- stream-ids
+ - value type: <prop-encoded-array>
+ - A list of (id, mem-manage) pair, where:
+
+ - id: A unique <u32> value amongst all devices assigned to the partition.
+
+- interrupts [mandatory]
+ - value type: <prop-encoded-array>
+ - A list of (id, attributes) pair describing the device interrupts, where:
+
+ - id: The <u32> interrupt IDs.
+ - attributes: A <u32> value, containing attributes for each interrupt ID:
+
+ +----------------------+----------+
+ |Field | Bit(s) |
+ +----------------------+----------+
+ | Priority | 7:0 |
+ +----------------------+----------+
+ | Security state | 8 |
+ +----------------------+----------+
+ | Config(Edge/Level) | 9 |
+ +----------------------+----------+
+ | Type(SPI/PPI/SGI) | 11:10 |
+ +----------------------+----------+
+
+ Security state:
+ - Secure: 1
+ - Non-secure: 0
+
+ Configuration:
+ - Edge triggered: 0
+ - Level triggered: 1
+
+ Type:
+ - SPI: 0b10
+ - PPI: 0b01
+ - SGI: 0b00
+
+- exclusive-access
+ - value type: <empty>
+ - Presence of this field implies that this endpoint must be granted exclusive
+ access and ownership of this device's MMIO region.
+
+--------------
+
+*Copyright (c) 2019-2022, Arm Limited and Contributors. All rights reserved.*
diff --git a/docs/components/firmware-update.rst b/docs/components/firmware-update.rst
new file mode 100644
index 0000000..1ba1e1c
--- /dev/null
+++ b/docs/components/firmware-update.rst
@@ -0,0 +1,497 @@
+Firmware Update (FWU)
+=====================
+
+This document describes the design of the various Firmware Update (FWU)
+mechanisms available in TF-A.
+
+1. PSA Firmware Update (PSA FWU)
+2. TBBR Firmware Update (TBBR FWU)
+
+PSA Firmware Update implements the specification of the same name (Arm document
+IHI 0093), which defines a standard firmware interface for installing firmware
+updates.
+On the other hand, TBBR Firmware Update only covers firmware recovery. Arguably,
+its name is somewhat misleading but the TBBR specification and terminology
+predates PSA FWU. Both mechanisms are complementary in the sense that PSA FWU
+assumes that the device has a backup or recovery capability in the event of a
+failed update, which can be fulfilled with TBBR FWU implementation.
+
+.. _PSA Firmware Update:
+
+PSA Firmware Update (PSA FWU)
+-----------------------------
+
+Introduction
+~~~~~~~~~~~~
+The `PSA FW update specification`_ defines the concepts of ``Firmware Update
+Client`` and ``Firmware Update Agent``.
+The new firmware images are provided by the ``Client`` to the ``Update Agent``
+to flash them in non-volatile storage.
+
+A common system design will place the ``Update Agent`` in the Secure-world
+while the ``Client`` executes in the Normal-world.
+The `PSA FW update specification`_ provides ABIs meant for a Normal-world
+entity aka ``Client`` to transmit the firmware images to the ``Update Agent``.
+
+Scope
+~~~~~
+The design of the ``Client`` and ``Update Agent`` is out of scope of this
+document.
+This document mainly covers ``Platform Boot`` details i.e. the role of
+the second stage Bootloader after FWU has been done by ``Client`` and
+``Update Agent``.
+
+Overview
+~~~~~~~~
+
+There are active and update banks in the non-volatile storage identified
+by the ``active_index`` and the ``update_index`` respectively.
+An active bank stores running firmware, whereas an update bank contains
+firmware updates.
+
+Once Firmwares are updated in the update bank of the non-volatile
+storage, then ``Update Agent`` marks the update bank as the active bank,
+and write updated FWU metadata in non-volatile storage.
+On subsequent reboot, the second stage Bootloader (BL2) performs the
+following actions:
+
+- Read FWU metadata in memory
+- Retrieve the image specification (offset and length) of updated images
+ present in non-volatile storage with the help of FWU metadata
+- Set these image specification in the corresponding I/O policies of the
+ updated images using the FWU platform functions
+ ``plat_fwu_set_images_source()`` and ``plat_fwu_set_metadata_image_source()``,
+ please refer :ref:`Porting Guide`
+- Use these I/O policies to read the images from this address into the memory
+
+By default, the platform uses the active bank of non-volatile storage to boot
+the images in ``trial state``. If images pass through the authentication check
+and also if the system successfully booted the Normal-world image then
+``Update Agent`` marks this update as accepted after further sanitisation
+checking at Normal-world.
+
+The second stage Bootloader (BL2) avoids upgrading the platform NV-counter until
+it's been confirmed that given update is accepted.
+
+The following sequence diagram shows platform-boot flow:
+
+.. image:: ../resources/diagrams/PSA-FWU.png
+
+If the platform fails to boot from active bank due to any reasons such
+as authentication failure or non-fuctionality of Normal-world software then the
+watchdog will reset to give a chance to the platform to fix the issue. This
+boot failure & reset sequence might be repeated up to ``trial state`` times.
+After that, the platform can decide to boot from the ``previous_active_index``
+bank.
+
+If the images still does not boot successfully from the ``previous_active_index``
+bank (e.g. due to ageing effect of non-volatile storage) then the platform can
+choose firmware recovery mechanism :ref:`TBBR Firmware Update` to bring system
+back to life.
+
+.. _TBBR Firmware Update:
+
+TBBR Firmware Update (TBBR FWU)
+-------------------------------
+
+Introduction
+~~~~~~~~~~~~
+
+This technique 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.
+
+It can be used as a last resort when all firmware updates that are carried out
+as part of the :ref:`PSA Firmware Update` procedure have failed to function.
+
+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.
+
+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-2022, 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
+.. _PSA FW update specification: https://developer.arm.com/documentation/den0118/a/
diff --git a/docs/components/granule-protection-tables-design.rst b/docs/components/granule-protection-tables-design.rst
new file mode 100644
index 0000000..07637dd
--- /dev/null
+++ b/docs/components/granule-protection-tables-design.rst
@@ -0,0 +1,235 @@
+Granule Protection Tables Library
+=================================
+
+This document describes the design of the granule protection tables (GPT)
+library used by Trusted Firmware-A (TF-A). This library provides the APIs needed
+to initialize the GPTs based on a data structure containing information about
+the systems memory layout, configure the system registers to enable granule
+protection checks based on these tables, and transition granules between
+different PAS (physical address spaces) at runtime.
+
+Arm CCA adds two new security states for a total of four: root, realm, secure, and
+non-secure. In addition to new security states, corresponding physical address
+spaces have been added to control memory access for each state. The PAS access
+allowed to each security state can be seen in the table below.
+
+.. list-table:: Security states and PAS access rights
+ :widths: 25 25 25 25 25
+ :header-rows: 1
+
+ * -
+ - Root state
+ - Realm state
+ - Secure state
+ - Non-secure state
+ * - Root PAS
+ - yes
+ - no
+ - no
+ - no
+ * - Realm PAS
+ - yes
+ - yes
+ - no
+ - no
+ * - Secure PAS
+ - yes
+ - no
+ - yes
+ - no
+ * - Non-secure PAS
+ - yes
+ - yes
+ - yes
+ - yes
+
+The GPT can function as either a 1 level or 2 level lookup depending on how a
+PAS region is configured. The first step is the level 0 table, each entry in the
+level 0 table controls access to a relatively large region in memory (block
+descriptor), and the entire region can belong to a single PAS when a one step
+mapping is used, or a level 0 entry can link to a level 1 table where relatively
+small regions (granules) of memory can be assigned to different PAS with a 2
+step mapping. The type of mapping used for each PAS is determined by the user
+when setting up the configuration structure.
+
+Design Concepts and Interfaces
+------------------------------
+
+This section covers some important concepts and data structures used in the GPT
+library.
+
+There are three main parameters that determine how the tables are organized and
+function: the PPS (protected physical space) which is the total amount of
+protected physical address space in the system, PGS (physical granule size)
+which is how large each level 1 granule is, and L0GPTSZ (level 0 GPT size) which
+determines how much physical memory is governed by each level 0 entry. A granule
+is the smallest unit of memory that can be independently assigned to a PAS.
+
+L0GPTSZ is determined by the hardware and is read from the GPCCR_EL3 register.
+PPS and PGS are passed into the APIs at runtime and can be determined in
+whatever way is best for a given platform, either through some algorithm or hard
+coded in the firmware.
+
+GPT setup is split into two parts: table creation and runtime initialization. In
+the table creation step, a data structure containing information about the
+desired PAS regions is passed into the library which validates the mappings,
+creates the tables in memory, and enables granule protection checks. In the
+runtime initialization step, the runtime firmware locates the existing tables in
+memory using the GPT register configuration and saves important data to a
+structure used by the granule transition service which will be covered more
+below.
+
+In the reference implementation for FVP models, you can find an example of PAS
+region definitions in the file ``include/plat/arm/common/arm_pas_def.h``. Table
+creation API calls can be found in ``plat/arm/common/arm_bl2_setup.c`` and
+runtime initialization API calls can be seen in
+``plat/arm/common/arm_bl31_setup.c``.
+
+Defining PAS regions
+~~~~~~~~~~~~~~~~~~~~
+
+A ``pas_region_t`` structure is a way to represent a physical address space and
+its attributes that can be used by the GPT library to initialize the tables.
+
+This structure is composed of the following:
+
+#. The base physical address
+#. The region size
+#. The desired attributes of this memory region (mapping type, PAS type)
+
+See the ``pas_region_t`` type in ``include/lib/gpt_rme/gpt_rme.h``.
+
+The programmer should provide the API with an array containing ``pas_region_t``
+structures, then the library will check the desired memory access layout for
+validity and create tables to implement it.
+
+``pas_region_t`` is a public type, however it is recommended that the macros
+``GPT_MAP_REGION_BLOCK`` and ``GPT_MAP_REGION_GRANULE`` be used to populate
+these structures instead of doing it manually to reduce the risk of future
+compatibility issues. These macros take the base physical address, region size,
+and PAS type as arguments to generate the pas_region_t structure. As the names
+imply, ``GPT_MAP_REGION_BLOCK`` creates a region using only L0 mapping while
+``GPT_MAP_REGION_GRANULE`` creates a region using L0 and L1 mappings.
+
+Level 0 and Level 1 Tables
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The GPT initialization APIs require memory to be passed in for the tables to be
+constructed, ``gpt_init_l0_tables`` takes a memory address and size for building
+the level 0 tables and ``gpt_init_pas_l1_tables`` takes an address and size for
+building the level 1 tables which are linked from level 0 descriptors. The
+tables should have PAS type ``GPT_GPI_ROOT`` and a typical system might place
+its level 0 table in SRAM and its level 1 table(s) in DRAM.
+
+Granule Transition Service
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The Granule Transition Service allows memory mapped with GPT_MAP_REGION_GRANULE
+ownership to be changed using SMC calls. Non-secure granules can be transitioned
+to either realm or secure space, and realm and secure granules can be
+transitioned back to non-secure. This library only allows memory mapped as
+granules to be transitioned, memory mapped as blocks have their GPIs fixed after
+table creation.
+
+Library APIs
+------------
+
+The public APIs and types can be found in ``include/lib/gpt_rme/gpt_rme.h`` and this
+section is intended to provide additional details and clarifications.
+
+To create the GPTs and enable granule protection checks the APIs need to be
+called in the correct order and at the correct time during the system boot
+process.
+
+#. Firmware must enable the MMU.
+#. Firmware must call ``gpt_init_l0_tables`` to initialize the level 0 tables to
+ a default state, that is, initializing all of the L0 descriptors to allow all
+ accesses to all memory. The PPS is provided to this function as an argument.
+#. DDR discovery and initialization by the system, the discovered DDR region(s)
+ are then added to the L1 PAS regions to be initialized in the next step and
+ used by the GTSI at runtime.
+#. Firmware must call ``gpt_init_pas_l1_tables`` with a pointer to an array of
+ ``pas_region_t`` structures containing the desired memory access layout. The
+ PGS is provided to this function as an argument.
+#. Firmware must call ``gpt_enable`` to enable granule protection checks by
+ setting the correct register values.
+#. In systems that make use of the granule transition service, runtime
+ firmware must call ``gpt_runtime_init`` to set up the data structures needed
+ by the GTSI to find the tables and transition granules between PAS types.
+
+API Constraints
+~~~~~~~~~~~~~~~
+
+The values allowed by the API for PPS and PGS are enumerated types
+defined in the file ``include/lib/gpt_rme/gpt_rme.h``.
+
+Allowable values for PPS along with their corresponding size.
+
+* ``GPCCR_PPS_4GB`` (4GB protected space, 0x100000000 bytes)
+* ``GPCCR_PPS_64GB`` (64GB protected space, 0x1000000000 bytes)
+* ``GPCCR_PPS_1TB`` (1TB protected space, 0x10000000000 bytes)
+* ``GPCCR_PPS_4TB`` (4TB protected space, 0x40000000000 bytes)
+* ``GPCCR_PPS_16TB`` (16TB protected space, 0x100000000000 bytes)
+* ``GPCCR_PPS_256TB`` (256TB protected space, 0x1000000000000 bytes)
+* ``GPCCR_PPS_4PB`` (4PB protected space, 0x10000000000000 bytes)
+
+Allowable values for PGS along with their corresponding size.
+
+* ``GPCCR_PGS_4K`` (4KB granules, 0x1000 bytes)
+* ``GPCCR_PGS_16K`` (16KB granules, 0x4000 bytes)
+* ``GPCCR_PGS_64K`` (64KB granules, 0x10000 bytes)
+
+Allowable values for L0GPTSZ along with the corresponding size.
+
+* ``GPCCR_L0GPTSZ_30BITS`` (1GB regions, 0x40000000 bytes)
+* ``GPCCR_L0GPTSZ_34BITS`` (16GB regions, 0x400000000 bytes)
+* ``GPCCR_L0GPTSZ_36BITS`` (64GB regions, 0x1000000000 bytes)
+* ``GPCCR_L0GPTSZ_39BITS`` (512GB regions, 0x8000000000 bytes)
+
+Note that the value of the PPS, PGS, and L0GPTSZ definitions is an encoded value
+corresponding to the size, not the size itself. The decoded hex representations
+of the sizes have been provided for convenience.
+
+The L0 table memory has some constraints that must be taken into account.
+
+* The L0 table must be aligned to either the table size or 4096 bytes, whichever
+ is greater. L0 table size is the total protected space (PPS) divided by the
+ size of each L0 region (L0GPTSZ) multiplied by the size of each L0 descriptor
+ (8 bytes). ((PPS / L0GPTSZ) * 8)
+* The L0 memory size must be greater than or equal to the table size.
+* The L0 memory must fall within a PAS of type GPT_GPI_ROOT.
+
+The L1 memory also has some constraints.
+
+* The L1 tables must be aligned to their size. The size of each L1 table is the
+ size of each L0 region (L0GPTSZ) divided by the granule size (PGS) divided by
+ the granules controlled in each byte (2). ((L0GPTSZ / PGS) / 2)
+* There must be enough L1 memory supplied to build all requested L1 tables.
+* The L1 memory must fall within a PAS of type GPT_GPI_ROOT.
+
+If an invalid combination of parameters is supplied, the APIs will print an
+error message and return a negative value. The return values of APIs should be
+checked to ensure successful configuration.
+
+Sample Calculation for L0 memory size and alignment
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Let PPS=GPCCR_PPS_4GB and L0GPTSZ=GPCCR_L0GPTSZ_30BITS
+
+We can find the total L0 table size with ((PPS / L0GPTSZ) * 8)
+
+Substitute values to get this: ((0x100000000 / 0x40000000) * 8)
+
+And solve to get 32 bytes. In this case, 4096 is greater than 32, so the L0
+tables must be aligned to 4096 bytes.
+
+Sample calculation for L1 table size and alignment
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Let PGS=GPCCR_PGS_4K and L0GPTSZ=GPCCR_L0GPTSZ_30BITS
+
+We can find the size of each L1 table with ((L0GPTSZ / PGS) / 2).
+
+Substitute values: ((0x40000000 / 0x1000) / 2)
+
+And solve to get 0x20000 bytes per L1 table.
diff --git a/docs/components/index.rst b/docs/components/index.rst
new file mode 100644
index 0000000..30d80fc
--- /dev/null
+++ b/docs/components/index.rst
@@ -0,0 +1,28 @@
+Components
+==========
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents
+
+ spd/index
+ activity-monitors
+ arm-sip-service
+ debugfs-design
+ exception-handling
+ fconf/index
+ firmware-update
+ measured_boot/index
+ mpmm
+ platform-interrupt-controller-API
+ ras
+ romlib-design
+ sdei
+ secure-partition-manager
+ el3-spmc
+ secure-partition-manager-mm
+ xlat-tables-lib-v2-design
+ cot-binding
+ realm-management-extension
+ rmm-el3-comms-spec
+ granule-protection-tables-design
diff --git a/docs/components/measured_boot/event_log.rst b/docs/components/measured_boot/event_log.rst
new file mode 100644
index 0000000..0881248
--- /dev/null
+++ b/docs/components/measured_boot/event_log.rst
@@ -0,0 +1,35 @@
+DTB binding for Event Log properties
+====================================
+
+This document describes the device tree format of Event Log properties.
+These properties are not related to a specific platform and can be queried
+from common code.
+
+Dynamic configuration for Event Log
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Measured Boot driver expects a *tpm_event_log* node with the following field
+in 'tb_fw_config', 'nt_fw_config' and 'tsp_fw_config' DTS files:
+
+- compatible [mandatory]
+ - value type: <string>
+ - Must be the string "arm,tpm_event_log".
+
+Then a list of properties representing Event Log configuration, which
+can be used by Measured Boot driver. Each property is named according
+to the information it contains:
+
+- tpm_event_log_sm_addr [fvp_nt_fw_config.dts with OP-TEE]
+ - value type: <u64>
+ - Event Log base address in secure memory.
+
+Note. Currently OP-TEE does not support reading DTBs from Secure memory
+and this property should be removed when this feature is supported.
+
+- tpm_event_log_addr [mandatory]
+ - value type: <u64>
+ - Event Log base address in non-secure memory.
+
+- tpm_event_log_size [mandatory]
+ - value type: <u32>
+ - Event Log size.
diff --git a/docs/components/measured_boot/index.rst b/docs/components/measured_boot/index.rst
new file mode 100644
index 0000000..e7f2634
--- /dev/null
+++ b/docs/components/measured_boot/index.rst
@@ -0,0 +1,12 @@
+Measured Boot Driver (MBD)
+==========================
+
+.. _measured-boot-document:
+
+Properties binding information
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. toctree::
+ :maxdepth: 1
+
+ event_log
diff --git a/docs/components/mpmm.rst b/docs/components/mpmm.rst
new file mode 100644
index 0000000..1b1c6d8
--- /dev/null
+++ b/docs/components/mpmm.rst
@@ -0,0 +1,30 @@
+Maximum Power Mitigation Mechanism (MPMM)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+|MPMM| is an optional microarchitectural power management mechanism supported by
+some Arm Armv9-A cores, beginning with the Cortex-X2, Cortex-A710 and
+Cortex-A510 cores. This mechanism detects and limits high-activity events to
+assist in |SoC| processor power domain dynamic power budgeting and limit the
+triggering of whole-rail (i.e. clock chopping) responses to overcurrent
+conditions.
+
+|MPMM| is enabled on a per-core basis by the EL3 runtime firmware. The presence
+of |MPMM| cannot be determined at runtime by the firmware, and therefore the
+platform must expose this information through one of two possible mechanisms:
+
+- |FCONF|, controlled by the ``ENABLE_MPMM_FCONF`` build option.
+- A platform implementation of the ``plat_mpmm_topology`` function (the
+ default).
+
+See :ref:`Maximum Power Mitigation Mechanism (MPMM) Bindings` for documentation
+on the |FCONF| device tree bindings.
+
+.. warning::
+
+ |MPMM| exposes gear metrics through the auxiliary |AMU| counters. An
+ external power controller can use these metrics to budget SoC power by
+ limiting the number of cores that can execute higher-activity workloads or
+ switching to a different DVFS operating point. When this is the case, the
+ |AMU| counters that make up the |MPMM| gears must be enabled by the EL3
+ runtime firmware - please see :ref:`Activity Monitor Auxiliary Counters` for
+ documentation on enabling auxiliary |AMU| counters.
diff --git a/docs/components/platform-interrupt-controller-API.rst b/docs/components/platform-interrupt-controller-API.rst
new file mode 100644
index 0000000..069c87b
--- /dev/null
+++ b/docs/components/platform-interrupt-controller-API.rst
@@ -0,0 +1,309 @@
+Platform 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 <porting_guide_imf_in_bl31>`.
+
+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.
+
+.. _plat_ic_get_interrupt_id:
+
+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.*
diff --git a/docs/components/ras.rst b/docs/components/ras.rst
new file mode 100644
index 0000000..871be2d
--- /dev/null
+++ b/docs/components/ras.rst
@@ -0,0 +1,242 @@
+Reliability, 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 in
+Non-secure world 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 :ref:`error handling
+use-cases <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_NS`` must also
+be set ``1``. ``RAS_TRAP_NS_ERR_REC_ACCESS`` controls the access to the RAS
+error record registers from Non-secure.
+
+.. _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 :ref:`RAS Porting Guide <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 :ref:`top-level exception handler
+<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_NS=1`` enables routing of External Aborts and SErrors,
+ resulting from errors in NS world, 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 :ref:`priority level <Partitioning
+priority levels>` 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.
+
+Handling of both :ref:`interrupt <interrupt-flow>` and :ref:`non-interrupt
+<non-interrupt-flow>` 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 :ref:`EHF APIs
+<Activating and Deactivating priorities>`.
+
+--------------
+
+*Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.*
diff --git a/docs/components/realm-management-extension.rst b/docs/components/realm-management-extension.rst
new file mode 100644
index 0000000..6fc0c2e
--- /dev/null
+++ b/docs/components/realm-management-extension.rst
@@ -0,0 +1,391 @@
+
+Realm Management Extension (RME)
+====================================
+
+FEAT_RME (or RME for short) is an Armv9-A extension and is one component of the
+`Arm Confidential Compute Architecture (Arm CCA)`_. TF-A supports RME starting
+from version 2.6. This chapter discusses the changes to TF-A to support RME and
+provides instructions on how to build and run TF-A with RME.
+
+RME support in TF-A
+---------------------
+
+The following diagram shows an Arm CCA software architecture with TF-A as the
+EL3 firmware. In the Arm CCA architecture there are two additional security
+states and address spaces: ``Root`` and ``Realm``. TF-A firmware runs in the
+Root world. In the realm world, a Realm Management Monitor firmware (RMM)
+manages the execution of Realm VMs and their interaction with the hypervisor.
+
+.. image:: ../resources/diagrams/arm-cca-software-arch.png
+
+RME is the hardware extension to support Arm CCA. To support RME, various
+changes have been introduced to TF-A. We discuss those changes below.
+
+Changes to translation tables library
+***************************************
+RME adds Root and Realm Physical address spaces. To support this, two new
+memory type macros, ``MT_ROOT`` and ``MT_REALM``, have been added to the
+:ref:`Translation (XLAT) Tables Library`. These macros are used to configure
+memory regions as Root or Realm respectively.
+
+.. note::
+
+ Only version 2 of the translation tables library supports the new memory
+ types.
+
+Changes to context management
+*******************************
+A new CPU context for the Realm world has been added. The existing
+:ref:`CPU context management API<PSCI Library Integration guide for Armv8-A
+AArch32 systems>` can be used to manage Realm context.
+
+Boot flow changes
+*******************
+In a typical TF-A boot flow, BL2 runs at Secure-EL1. However when RME is
+enabled, TF-A runs in the Root world at EL3. Therefore, the boot flow is
+modified to run BL2 at EL3 when RME is enabled. In addition to this, a
+Realm-world firmware (RMM) is loaded by BL2 in the Realm physical address
+space.
+
+The boot flow when RME is enabled looks like the following:
+
+1. BL1 loads and executes BL2 at EL3
+2. BL2 loads images including RMM
+3. BL2 transfers control to BL31
+4. BL31 initializes SPM (if SPM is enabled)
+5. BL31 initializes RMM
+6. BL31 transfers control to Normal-world software
+
+Granule Protection Tables (GPT) library
+*****************************************
+Isolation between the four physical address spaces is enforced by a process
+called Granule Protection Check (GPC) performed by the MMU downstream any
+address translation. GPC makes use of Granule Protection Table (GPT) in the
+Root world that describes the physical address space assignment of every
+page (granule). A GPT library that provides APIs to initialize GPTs and to
+transition granules between different physical address spaces has been added.
+More information about the GPT library can be found in the
+:ref:`Granule Protection Tables Library` chapter.
+
+RMM Dispatcher (RMMD)
+************************
+RMMD is a new standard runtime service that handles the switch to the Realm
+world. It initializes the RMM and handles Realm Management Interface (RMI)
+SMC calls from Non-secure and Realm worlds.
+
+There is a contract between RMM and RMMD that defines the arguments that the
+former needs to take in order to initialize and also the possible return values.
+This contract is defined in the RMM Boot Interface, which can be found at
+:ref:`rmm_el3_boot_interface`.
+
+There is also a specification of the runtime services provided by TF-A
+to RMM. This can be found at :ref:`runtime_services_and_interface`.
+
+Test Realm Payload (TRP)
+*************************
+TRP is a small test payload that runs at R-EL2 and implements a subset of
+the Realm Management Interface (RMI) commands to primarily test EL3 firmware
+and the interface between R-EL2 and EL3. When building TF-A with RME enabled,
+if a path to an RMM image is not provided, TF-A builds the TRP by default
+and uses it as RMM image.
+
+Building and running TF-A with RME
+------------------------------------
+
+This section describes how you can build and run TF-A with RME enabled.
+We assume you have all the :ref:`Prerequisites` to build TF-A.
+
+The following instructions show you how to build and run TF-A with RME
+for two scenarios:
+
+- Three-world execution: TF-A with TF-A Tests or Linux.
+
+ - NS (TF-A Test or Linux),
+ - Root (TF-A)
+ - Realm (RMM or TRP)
+
+- Four-world execution: TF-A, Hafnium and TF-A Tests or Linux.
+
+ - NS (TF-A Test or Linux),
+ - Root (TF-A)
+ - Realm (RMM or TRP)
+ - SPM (Hafnium)
+
+To run the tests, you need an FVP model. Please use the :ref:`latest version
+<Arm Fixed Virtual Platforms (FVP)>` of *FVP_Base_RevC-2xAEMvA* model.
+
+Three World Testing with TF-A Tests
+*************************************
+
+**1. Obtain and build TF-A Tests with Realm Payload**
+
+The full set of instructions to setup build host and build options for
+TF-A-Tests can be found in the `TFTF Getting Started`_.
+
+Use the following instructions to build TF-A with `TF-A Tests`_ as the
+non-secure payload (BL33).
+
+.. code:: shell
+
+ git clone https://git.trustedfirmware.org/TF-A/tf-a-tests.git
+ cd tf-a-tests
+ make CROSS_COMPILE=aarch64-none-elf- PLAT=fvp DEBUG=1 all pack_realm
+
+This produces a TF-A Tests binary (**tftf.bin**) with Realm payload packaged
+and **sp_layout.json** in the **build/fvp/debug** directory.
+
+**2. Obtain and build RMM Image**
+
+Please refer to the `RMM Getting Started`_ on how to setup
+Host Environment and build RMM.
+
+The below command shows how to build RMM using the default build options for FVP.
+
+.. code:: shell
+
+ git clone --recursive https://git.trustedfirmware.org/TF-RMM/tf-rmm.git
+ cd tf-rmm
+ cmake -DRMM_CONFIG=fvp_defcfg -S . -B build
+ cmake --build build
+
+This will generate **rmm.img** in **build** folder.
+
+**3. Build TF-A**
+
+The `TF-A Getting Started`_ has the necessary instructions to setup Host
+machine and build TF-A.
+
+To build for RME, set ``ENABLE_RME`` build option to 1 and provide the path to
+the RMM binary using the ``RMM`` build option.
+Currently, this feature is only supported for the FVP platform.
+
+.. note::
+
+ ENABLE_RME build option is currently experimental.
+
+If the ``RMM`` option is not used, then the Test Realm Payload (TRP) in TF-A
+will be built and used as the RMM.
+
+.. code:: shell
+
+ git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
+ cd trusted-firmware-a
+ make CROSS_COMPILE=aarch64-none-elf- \
+ PLAT=fvp \
+ ENABLE_RME=1 \
+ RMM=<path/to/rmm.img> \
+ FVP_HW_CONFIG_DTS=fdts/fvp-base-gicv3-psci-1t.dts \
+ DEBUG=1 \
+ BL33=<path/to/tftf.bin> \
+ all fip
+
+This produces **bl1.bin** and **fip.bin** binaries in the **build/fvp/debug** directory.
+
+Running the tests for a 3 world FVP setup
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use the following command to run the tests on FVP. TF-A Tests should boot
+and run the default tests including Realm world tests.
+
+.. code:: shell
+
+ FVP_Base_RevC-2xAEMvA \
+ -C bp.refcounter.non_arch_start_at_default=1 \
+ -C bp.secureflashloader.fname=<path/to/bl1.bin> \
+ -C bp.flashloader0.fname=<path/to/fip.bin> \
+ -C bp.refcounter.use_real_time=0 \
+ -C bp.ve_sysregs.exit_on_shutdown=1 \
+ -C cache_state_modelled=1 \
+ -C bp.dram_size=2 \
+ -C bp.secure_memory=1 \
+ -C pci.pci_smmuv3.mmu.SMMU_ROOT_IDR0=3 \
+ -C pci.pci_smmuv3.mmu.SMMU_ROOT_IIDR=0x43B \
+ -C pci.pci_smmuv3.mmu.root_register_page_offset=0x20000 \
+ -C cluster0.NUM_CORES=4 \
+ -C cluster0.PA_SIZE=48 \
+ -C cluster0.ecv_support_level=2 \
+ -C cluster0.gicv3.cpuintf-mmap-access-level=2 \
+ -C cluster0.gicv3.without-DS-support=1 \
+ -C cluster0.gicv4.mask-virtual-interrupt=1 \
+ -C cluster0.has_arm_v8-6=1 \
+ -C cluster0.has_amu=1 \
+ -C cluster0.has_branch_target_exception=1 \
+ -C cluster0.rme_support_level=2 \
+ -C cluster0.has_rndr=1 \
+ -C cluster0.has_v8_7_pmu_extension=2 \
+ -C cluster0.max_32bit_el=-1 \
+ -C cluster0.stage12_tlb_size=1024 \
+ -C cluster0.check_memory_attributes=0 \
+ -C cluster0.ish_is_osh=1 \
+ -C cluster0.restriction_on_speculative_execution=2 \
+ -C cluster0.restriction_on_speculative_execution_aarch32=2 \
+ -C cluster1.NUM_CORES=4 \
+ -C cluster1.PA_SIZE=48 \
+ -C cluster1.ecv_support_level=2 \
+ -C cluster1.gicv3.cpuintf-mmap-access-level=2 \
+ -C cluster1.gicv3.without-DS-support=1 \
+ -C cluster1.gicv4.mask-virtual-interrupt=1 \
+ -C cluster1.has_arm_v8-6=1 \
+ -C cluster1.has_amu=1 \
+ -C cluster1.has_branch_target_exception=1 \
+ -C cluster1.rme_support_level=2 \
+ -C cluster1.has_rndr=1 \
+ -C cluster1.has_v8_7_pmu_extension=2 \
+ -C cluster1.max_32bit_el=-1 \
+ -C cluster1.stage12_tlb_size=1024 \
+ -C cluster1.check_memory_attributes=0 \
+ -C cluster1.ish_is_osh=1 \
+ -C cluster1.restriction_on_speculative_execution=2 \
+ -C cluster1.restriction_on_speculative_execution_aarch32=2 \
+ -C pctl.startup=0.0.0.0 \
+ -C bp.smsc_91c111.enabled=1 \
+ -C bp.hostbridge.userNetworking=1
+
+The bottom of the output from *uart0* should look something like the following.
+
+.. code-block:: shell
+
+ ...
+
+ > Test suite 'FF-A Interrupt'
+ Passed
+ > Test suite 'SMMUv3 tests'
+ Passed
+ > Test suite 'PMU Leakage'
+ Passed
+ > Test suite 'DebugFS'
+ Passed
+ > Test suite 'RMI and SPM tests'
+ Passed
+ > Test suite 'Realm payload at EL1'
+ Passed
+ > Test suite 'Invalid memory access'
+ Passed
+ ...
+
+Building TF-A with RME enabled Linux Kernel
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If an RME enabled Linux kernel and filesystem is available for testing,
+and a suitable NS boot loader is not available, then this option can be used to
+launch kernel directly after BL31:
+
+.. code-block:: shell
+
+ cd trusted-firmware-a
+ make CROSS_COMPILE=aarch64-none-elf- \
+ PLAT=fvp \
+ ENABLE_RME=1 \
+ RMM=<path/to/rmm.img> \
+ FVP_HW_CONFIG_DTS=fdts/fvp-base-gicv3-psci-1t.dts \
+ DEBUG=1 \
+ ARM_LINUX_KERNEL_AS_BL33=1 \
+ PRELOADED_BL33_BASE=0x84000000 \
+ all fip
+
+Boot and run the RME enabled Linux Kernel
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use the following additional arguments to boot the kernel on FVP.
+
+.. code-block:: shell
+
+ --data cluster0.cpu0=<path_to_kernel_Image>@0x84000000 \
+ -C bp.virtioblockdevice.image_path=<path_to_rootfs.ext4>
+
+.. tip::
+
+ Set the FVP option `cache_state_modelled=0` to run Linux based tests much faster.
+
+Four-world execution with Hafnium and TF-A Tests
+*************************************************
+
+Four-world execution involves software components in each security state: root,
+secure, realm and non-secure. This section describes how to build TF-A
+with four-world support.
+
+We use TF-A as the root firmware, `Hafnium SPM`_ is the reference Secure world component
+and the software components for the other 2 worlds (Realm and Non-Secure)
+are as described in the previous section.
+
+**1. Obtain and build Hafnium**
+
+.. code:: shell
+
+ git clone --recurse-submodules https://git.trustedfirmware.org/hafnium/hafnium.git
+ cd hafnium
+ # Use the default prebuilt LLVM/clang toolchain
+ PATH=$PWD/prebuilts/linux-x64/clang/bin:$PWD/prebuilts/linux-x64/dtc:$PATH
+
+Feature MTE needs to be disabled in Hafnium build, apply following patch to
+project/reference submodule
+
+.. code:: diff
+
+ diff --git a/BUILD.gn b/BUILD.gn
+ index cc6a78f..234b20a 100644
+ --- a/BUILD.gn
+ +++ b/BUILD.gn
+ @@ -83,7 +83,6 @@ aarch64_toolchains("secure_aem_v8a_fvp") {
+ pl011_base_address = "0x1c090000"
+ smmu_base_address = "0x2b400000"
+ smmu_memory_size = "0x100000"
+ - enable_mte = "1"
+ plat_log_level = "LOG_LEVEL_INFO"
+ }
+ }
+
+.. code:: shell
+
+ make PROJECT=reference
+
+The Hafnium binary should be located at
+*out/reference/secure_aem_v8a_fvp_clang/hafnium.bin*
+
+**2. Build TF-A**
+
+Build TF-A with RME as well as SPM enabled.
+
+Use sp_layout.json previously generated in tf-a-test build.
+
+.. code:: shell
+
+ make CROSS_COMPILE=aarch64-none-elf- \
+ PLAT=fvp \
+ ENABLE_RME=1 \
+ FVP_HW_CONFIG_DTS=fdts/fvp-base-gicv3-psci-1t.dts \
+ SPD=spmd \
+ SPMD_SPM_AT_SEL2=1 \
+ BRANCH_PROTECTION=1 \
+ CTX_INCLUDE_PAUTH_REGS=1 \
+ DEBUG=1 \
+ SP_LAYOUT_FILE=<path/to/sp_layout.json> \
+ BL32=<path/to/hafnium.bin> \
+ BL33=<path/to/tftf.bin> \
+ RMM=<path/to/rmm.img> \
+ all fip
+
+Running the tests for a 4 world FVP setup
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use the following arguments in addition to
+`Running the tests for a 3 world FVP setup`_ to run tests for 4 world setup.
+
+.. code:: shell
+
+ -C pci.pci_smmuv3.mmu.SMMU_AIDR=2 \
+ -C pci.pci_smmuv3.mmu.SMMU_IDR0=0x0046123B \
+ -C pci.pci_smmuv3.mmu.SMMU_IDR1=0x00600002 \
+ -C pci.pci_smmuv3.mmu.SMMU_IDR3=0x1714 \
+ -C pci.pci_smmuv3.mmu.SMMU_IDR5=0xFFFF0475 \
+ -C pci.pci_smmuv3.mmu.SMMU_S_IDR1=0xA0000002 \
+ -C pci.pci_smmuv3.mmu.SMMU_S_IDR2=0 \
+ -C pci.pci_smmuv3.mmu.SMMU_S_IDR3=0
+
+.. _Arm Confidential Compute Architecture (Arm CCA): https://www.arm.com/why-arm/architecture/security-features/arm-confidential-compute-architecture
+.. _Arm Architecture Models website: https://developer.arm.com/tools-and-software/simulation-models/fixed-virtual-platforms/arm-ecosystem-models
+.. _TF-A Getting Started: https://trustedfirmware-a.readthedocs.io/en/latest/getting_started/index.html
+.. _TF-A Tests: https://trustedfirmware-a-tests.readthedocs.io/en/latest
+.. _TFTF Getting Started: https://trustedfirmware-a-tests.readthedocs.io/en/latest/getting_started/index.html
+.. _Hafnium SPM: https://www.trustedfirmware.org/projects/hafnium
+.. _RMM Getting Started: https://git.trustedfirmware.org/TF-RMM/tf-rmm.git/tree/docs/getting_started/index.rst
diff --git a/docs/components/rmm-el3-comms-spec.rst b/docs/components/rmm-el3-comms-spec.rst
new file mode 100644
index 0000000..8070ff4
--- /dev/null
+++ b/docs/components/rmm-el3-comms-spec.rst
@@ -0,0 +1,543 @@
+RMM-EL3 Communication interface
+*******************************
+
+This document defines the communication interface between RMM and EL3.
+There are two parts in this interface: the boot interface and the runtime
+interface.
+
+The Boot Interface defines the ABI between EL3 and RMM when the CPU enters
+R-EL2 for the first time after boot. The cold boot interface defines the ABI
+for the cold boot path and the warm boot interface defines the same for the
+warm path.
+
+The RMM-EL3 runtime interface defines the ABI for EL3 services which can be
+invoked by RMM as well as the register save-restore convention when handling an
+SMC call from NS.
+
+The below sections discuss these interfaces more in detail.
+
+.. _rmm_el3_ifc_versioning:
+
+RMM-EL3 Interface versioning
+____________________________
+
+The RMM Boot and Runtime Interface uses a version number to check
+compatibility with the register arguments passed as part of Boot Interface and
+RMM-EL3 runtime interface.
+
+The Boot Manifest, discussed later in section :ref:`rmm_el3_boot_manifest`,
+uses a separate version number but with the same scheme.
+
+The version number is a 32-bit type with the following fields:
+
+.. csv-table::
+ :header: "Bits", "Value"
+
+ [0:15],``VERSION_MINOR``
+ [16:30],``VERSION_MAJOR``
+ [31],RES0
+
+The version numbers are sequentially increased and the rules for updating them
+are explained below:
+
+ - ``VERSION_MAJOR``: This value is increased when changes break
+ compatibility with previous versions. If the changes
+ on the ABI are compatible with the previous one, ``VERSION_MAJOR``
+ remains unchanged.
+
+ - ``VERSION_MINOR``: This value is increased on any change that is backwards
+ compatible with the previous version. When ``VERSION_MAJOR`` is increased,
+ ``VERSION_MINOR`` must be set to 0.
+
+ - ``RES0``: Bit 31 of the version number is reserved 0 as to maintain
+ consistency with the versioning schemes used in other parts of RMM.
+
+This document specifies the 0.1 version of Boot Interface ABI and RMM-EL3
+services specification and the 0.1 version of the Boot Manifest.
+
+.. _rmm_el3_boot_interface:
+
+RMM Boot Interface
+__________________
+
+This section deals with the Boot Interface part of the specification.
+
+One of the goals of the Boot Interface is to allow EL3 firmware to pass
+down into RMM certain platform specific information dynamically. This allows
+RMM to be less platform dependent and be more generic across platform
+variations. It also allows RMM to be decoupled from the other boot loader
+images in the boot sequence and remain agnostic of any particular format used
+for configuration files.
+
+The Boot Interface ABI defines a set of register conventions and
+also a memory based manifest file to pass information from EL3 to RMM. The
+boot manifest and the associated platform data in it can be dynamically created
+by EL3 and there is no restriction on how the data can be obtained (e.g by DTB,
+hoblist or other).
+
+The register convention and the manifest are versioned separately to manage
+future enhancements and compatibility.
+
+RMM completes the boot by issuing the ``RMM_BOOT_COMPLETE`` SMC (0xC40001CF)
+back to EL3. After the RMM has finished the boot process, it can only be
+entered from EL3 as part of RMI handling.
+
+If RMM returns an error during boot (in any CPU), then RMM must not be entered
+from any CPU.
+
+.. _rmm_cold_boot_interface:
+
+Cold Boot Interface
+~~~~~~~~~~~~~~~~~~~
+
+During cold boot RMM expects the following register values:
+
+.. csv-table::
+ :header: "Register", "Value"
+ :widths: 1, 5
+
+ x0,Linear index of this PE. This index starts from 0 and must be less than the maximum number of CPUs to be supported at runtime (see x2).
+ x1,Version for this Boot Interface as defined in :ref:`rmm_el3_ifc_versioning`.
+ x2,Maximum number of CPUs to be supported at runtime. RMM should ensure that it can support this maximum number.
+ x3,Base address for the shared buffer used for communication between EL3 firmware and RMM. This buffer must be of 4KB size (1 page). The boot manifest must be present at the base of this shared buffer during cold boot.
+
+During cold boot, EL3 firmware needs to allocate a 4K page that will be
+passed to RMM in x3. This memory will be used as shared buffer for communication
+between EL3 and RMM. It must be assigned to Realm world and must be mapped with
+Normal memory attributes (IWB-OWB-ISH) at EL3. At boot, this memory will be
+used to populate the Boot Manifest. Since the Boot Manifest can be accessed by
+RMM prior to enabling its MMU, EL3 must ensure that proper cache maintenance
+operations are performed after the Boot Manifest is populated.
+
+EL3 should also ensure that this shared buffer is always available for use by RMM
+during the lifetime of the system and that it can be used for runtime
+communication between RMM and EL3. For example, when RMM invokes attestation
+service commands in EL3, this buffer can be used to exchange data between RMM
+and EL3. It is also allowed for RMM to invoke runtime services provided by EL3
+utilizing this buffer during the boot phase, prior to return back to EL3 via
+RMM_BOOT_COMPLETE SMC.
+
+RMM should map this memory page into its Stage 1 page-tables using Normal
+memory attributes.
+
+During runtime, it is the RMM which initiates any communication with EL3. If that
+communication requires the use of the shared area, it is expected that RMM needs
+to do the necessary concurrency protection to prevent the use of the same buffer
+by other PEs.
+
+The following sequence diagram shows how a generic EL3 Firmware would boot RMM.
+
+.. image:: ../resources/diagrams/rmm_cold_boot_generic.png
+
+Warm Boot Interface
+~~~~~~~~~~~~~~~~~~~
+
+At warm boot, RMM is already initialized and only some per-CPU initialization
+is still pending. The only argument that is required by RMM at this stage is
+the CPU Id, which will be passed through register x0 whilst x1 to x3 are RES0.
+This is summarized in the following table:
+
+.. csv-table::
+ :header: "Register", "Value"
+ :widths: 1, 5
+
+ x0,Linear index of this PE. This index starts from 0 and must be less than the maximum number of CPUs to be supported at runtime (see x2).
+ x1 - x3,RES0
+
+Boot error handling and return values
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+After boot up and initialization, RMM returns control back to EL3 through a
+``RMM_BOOT_COMPLETE`` SMC call. The only argument of this SMC call will
+be returned in x1 and it will encode a signed integer with the error reason
+as per the following table:
+
+.. csv-table::
+ :header: "Error code", "Description", "ID"
+ :widths: 2 4 1
+
+ ``E_RMM_BOOT_SUCCESS``,Boot successful,0
+ ``E_RMM_BOOT_ERR_UNKNOWN``,Unknown error,-1
+ ``E_RMM_BOOT_VERSION_NOT_VALID``,Boot Interface version reported by EL3 is not supported by RMM,-2
+ ``E_RMM_BOOT_CPUS_OUT_OF_RAGE``,Number of CPUs reported by EL3 larger than maximum supported by RMM,-3
+ ``E_RMM_BOOT_CPU_ID_OUT_OF_RAGE``,Current CPU Id is higher or equal than the number of CPUs supported by RMM,-4
+ ``E_RMM_BOOT_INVALID_SHARED_BUFFER``,Invalid pointer to shared memory area,-5
+ ``E_RMM_BOOT_MANIFEST_VERSION_NOT_SUPPORTED``,Version reported by the boot manifest not supported by RMM,-6
+ ``E_RMM_BOOT_MANIFEST_DATA_ERROR``,Error parsing core boot manifest,-7
+
+For any error detected in RMM during cold or warm boot, RMM will return back to
+EL3 using ``RMM_BOOT_COMPLETE`` SMC with an appropriate error code. It is
+expected that EL3 will take necessary action to disable Realm world for further
+entry from NS Host on receiving an error. This will be done across all the PEs
+in the system so as to present a symmetric view to the NS Host. Any further
+warm boot by any PE should not enter RMM using the warm boot interface.
+
+.. _rmm_el3_boot_manifest:
+
+Boot Manifest
+~~~~~~~~~~~~~
+
+During cold boot, EL3 Firmware passes a memory boot manifest to RMM containing
+platform information.
+
+This boot manifest is versioned independently of the boot interface, to help
+evolve the boot manifest independent of the rest of Boot Manifest.
+The current version for the boot manifest is ``v0.1`` and the rules explained
+in :ref:`rmm_el3_ifc_versioning` apply on this version as well.
+
+The boot manifest is divided into two different components:
+
+ - Core Manifest: This is the generic parameters passed to RMM by EL3 common to all platforms.
+ - Platform data: This is defined by the platform owner and contains information specific to that platform.
+
+For the current version of the manifest, the core manifest contains a pointer
+to the platform data. EL3 must ensure that the whole boot manifest,
+including the platform data, if available, fits inside the RMM EL3 shared
+buffer.
+
+For the type specification of the RMM Boot Manifest v0.1, refer to
+:ref:`rmm_el3_manifest_struct`
+
+.. _runtime_services_and_interface:
+
+RMM-EL3 Runtime Interface
+__________________________
+
+This section defines the RMM-EL3 runtime interface which specifies the ABI for
+EL3 services expected by RMM at runtime as well as the register save and
+restore convention between EL3 and RMM as part of RMI call handling. It is
+important to note that RMM is allowed to invoke EL3-RMM runtime interface
+services during the boot phase as well. The EL3 runtime service handling must
+not result in a world switch to another world unless specified. Both the RMM
+and EL3 are allowed to make suitable optimizations based on this assumption.
+
+If the interface requires the use of memory, then the memory references should
+be within the shared buffer communicated as part of the boot interface. See
+:ref:`rmm_cold_boot_interface` for properties of this shared buffer which both
+EL3 and RMM must adhere to.
+
+RMM-EL3 runtime service return codes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The return codes from EL3 to RMM is a 32 bit signed integer which encapsulates
+error condition as described in the following table:
+
+.. csv-table::
+ :header: "Error code", "Description", "ID"
+ :widths: 2 4 1
+
+ ``E_RMM_OK``,No errors detected,0
+ ``E_RMM_UNK``,Unknown/Generic error,-1
+ ``E_RMM_BAD_ADDR``,The value of an address used as argument was invalid,-2
+ ``E_RMM_BAD_PAS``,Incorrect PAS,-3
+ ``E_RMM_NOMEM``,Not enough memory to perform an operation,-4
+ ``E_RMM_INVAL``,The value of an argument was invalid,-5
+
+If multiple failure conditions are detected in an RMM to EL3 command, then EL3
+is allowed to return an error code corresponding to any of the failure
+conditions.
+
+RMM-EL3 runtime services
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following table summarizes the RMM runtime services that need to be
+implemented by EL3 Firmware.
+
+.. csv-table::
+ :header: "FID", "Command"
+ :widths: 2 5
+
+ 0xC400018F,``RMM_RMI_REQ_COMPLETE``
+ 0xC40001B0,``RMM_GTSI_DELEGATE``
+ 0xC40001B1,``RMM_GTSI_UNDELEGATE``
+ 0xC40001B2,``RMM_ATTEST_GET_REALM_KEY``
+ 0xC40001B3,``RMM_ATTEST_GET_PLAT_TOKEN``
+
+RMM_RMI_REQ_COMPLETE command
+============================
+
+Notifies the completion of an RMI call to the Non-Secure world.
+
+This call is the only function currently in RMM-EL3 runtime interface which
+results in a world switch to NS. This call is the reply to the original RMI
+call and it is forwarded by EL3 to the NS world.
+
+FID
+---
+
+``0xC400018F``
+
+Input values
+------------
+
+.. csv-table::
+ :header: "Name", "Register", "Field", "Type", "Description"
+ :widths: 1 1 1 1 5
+
+ fid,x0,[63:0],UInt64,Command FID
+ err_code,x1,[63:0],RmiCommandReturnCode,Error code returned by the RMI service invoked by NS World. See Realm Management Monitor specification for more info
+
+Output values
+-------------
+
+This call does not return.
+
+Failure conditions
+------------------
+
+Since this call does not return to RMM, there is no failure condition which
+can be notified back to RMM.
+
+RMM_GTSI_DELEGATE command
+=========================
+
+Delegate a memory granule by changing its PAS from Non-Secure to Realm.
+
+FID
+---
+
+``0xC40001B0``
+
+Input values
+------------
+
+.. csv-table::
+ :header: "Name", "Register", "Field", "Type", "Description"
+ :widths: 1 1 1 1 5
+
+ fid,x0,[63:0],UInt64,Command FID
+ base_pa,x1,[63:0],Address,PA of the start of the granule to be delegated
+
+Output values
+-------------
+
+.. csv-table::
+ :header: "Name", "Register", "Field", "Type", "Description"
+ :widths: 1 1 1 2 4
+
+ Result,x0,[63:0],Error Code,Command return status
+
+Failure conditions
+------------------
+
+The table below shows all the possible error codes returned in ``Result`` upon
+a failure. The errors are ordered by condition check.
+
+.. csv-table::
+ :header: "ID", "Condition"
+ :widths: 1 5
+
+ ``E_RMM_BAD_ADDR``,``PA`` does not correspond to a valid granule address
+ ``E_RMM_BAD_PAS``,The granule pointed by ``PA`` does not belong to Non-Secure PAS
+ ``E_RMM_OK``,No errors detected
+
+RMM_GTSI_UNDELEGATE command
+===========================
+
+Undelegate a memory granule by changing its PAS from Realm to Non-Secure.
+
+FID
+---
+
+``0xC40001B1``
+
+Input values
+------------
+
+.. csv-table::
+ :header: "Name", "Register", "Field", "Type", "Description"
+ :widths: 1 1 1 1 5
+
+ fid,x0,[63:0],UInt64,Command FID
+ base_pa,x1,[63:0],Address,PA of the start of the granule to be undelegated
+
+Output values
+-------------
+
+.. csv-table::
+ :header: "Name", "Register", "Field", "Type", "Description"
+ :widths: 1 1 1 2 4
+
+ Result,x0,[63:0],Error Code,Command return status
+
+Failure conditions
+------------------
+
+The table below shows all the possible error codes returned in ``Result`` upon
+a failure. The errors are ordered by condition check.
+
+.. csv-table::
+ :header: "ID", "Condition"
+ :widths: 1 5
+
+ ``E_RMM_BAD_ADDR``,``PA`` does not correspond to a valid granule address
+ ``E_RMM_BAD_PAS``,The granule pointed by ``PA`` does not belong to Realm PAS
+ ``E_RMM_OK``,No errors detected
+
+RMM_ATTEST_GET_REALM_KEY command
+================================
+
+Retrieve the Realm Attestation Token Signing key from EL3.
+
+FID
+---
+
+``0xC40001B2``
+
+Input values
+------------
+
+.. csv-table::
+ :header: "Name", "Register", "Field", "Type", "Description"
+ :widths: 1 1 1 1 5
+
+ fid,x0,[63:0],UInt64,Command FID
+ buf_pa,x1,[63:0],Address,PA where the Realm Attestation Key must be stored by EL3. The PA must belong to the shared buffer
+ buf_size,x2,[63:0],Size,Size in bytes of the Realm Attestation Key buffer. ``bufPa + bufSize`` must lie within the shared buffer
+ ecc_curve,x3,[63:0],Enum,Type of the elliptic curve to which the requested attestation key belongs to. See :ref:`ecc_curves`
+
+Output values
+-------------
+
+.. csv-table::
+ :header: "Name", "Register", "Field", "Type", "Description"
+ :widths: 1 1 1 1 5
+
+ Result,x0,[63:0],Error Code,Command return status
+ keySize,x1,[63:0],Size,Size of the Realm Attestation Key
+
+Failure conditions
+------------------
+
+The table below shows all the possible error codes returned in ``Result`` upon
+a failure. The errors are ordered by condition check.
+
+.. csv-table::
+ :header: "ID", "Condition"
+ :widths: 1 5
+
+ ``E_RMM_BAD_ADDR``,``PA`` is outside the shared buffer
+ ``E_RMM_INVAL``,``PA + BSize`` is outside the shared buffer
+ ``E_RMM_INVAL``,``Curve`` is not one of the listed in :ref:`ecc_curves`
+ ``E_RMM_UNK``,An unknown error occurred whilst processing the command
+ ``E_RMM_OK``,No errors detected
+
+.. _ecc_curves:
+
+Supported ECC Curves
+--------------------
+
+.. csv-table::
+ :header: "ID", "Curve"
+ :widths: 1 5
+
+ 0,ECC SECP384R1
+
+RMM_ATTEST_GET_PLAT_TOKEN command
+=================================
+
+Retrieve the Platform Token from EL3.
+
+FID
+---
+
+``0xC40001B3``
+
+Input values
+------------
+
+.. csv-table::
+ :header: "Name", "Register", "Field", "Type", "Description"
+ :widths: 1 1 1 1 5
+
+ fid,x0,[63:0],UInt64,Command FID
+ buf_pa,x1,[63:0],Address,PA of the platform attestation token. The challenge object is passed in this buffer. The PA must belong to the shared buffer
+ buf_size,x2,[63:0],Size,Size in bytes of the platform attestation token buffer. ``bufPa + bufSize`` must lie within the shared buffer
+ c_size,x3,[63:0],Size,Size in bytes of the challenge object. It corresponds to the size of one of the defined SHA algorithms
+
+Output values
+-------------
+
+.. csv-table::
+ :header: "Name", "Register", "Field", "Type", "Description"
+ :widths: 1 1 1 1 5
+
+ Result,x0,[63:0],Error Code,Command return status
+ tokenSize,x1,[63:0],Size,Size of the platform token
+
+Failure conditions
+------------------
+
+The table below shows all the possible error codes returned in ``Result`` upon
+a failure. The errors are ordered by condition check.
+
+.. csv-table::
+ :header: "ID", "Condition"
+ :widths: 1 5
+
+ ``E_RMM_BAD_ADDR``,``PA`` is outside the shared buffer
+ ``E_RMM_INVAL``,``PA + BSize`` is outside the shared buffer
+ ``E_RMM_INVAL``,``CSize`` does not represent the size of a supported SHA algorithm
+ ``E_RMM_UNK``,An unknown error occurred whilst processing the command
+ ``E_RMM_OK``,No errors detected
+
+RMM-EL3 world switch register save restore convention
+_____________________________________________________
+
+As part of NS world switch, EL3 is expected to maintain a register context
+specific to each world and will save and restore the registers
+appropriately. This section captures the contract between EL3 and RMM on the
+register set to be saved and restored.
+
+EL3 must maintain a separate register context for the following:
+
+ #. General purpose registers (x0-x30) and ``sp_el0``, ``sp_el2`` stack pointers
+ #. EL2 system register context for all enabled features by EL3. These include system registers with the ``_EL2`` prefix. The EL2 physical and virtual timer registers must not be included in this.
+
+As part of SMC forwarding between the NS world and Realm world, EL3 allows x0-x7 to be passed
+as arguments to Realm and x0-x4 to be used for return arguments back to Non Secure.
+As per SMCCCv1.2, x4 must be preserved if not being used as return argument by the SMC function
+and it is the responsibility of RMM to preserve this or use this as a return argument.
+EL3 will always copy x0-x4 from Realm context to NS Context.
+
+EL3 will not save some registers as mentioned in the below list. It is the
+responsibility of RMM to ensure that these are appropriately saved if the
+Realm World makes use of them:
+
+ #. FP/SIMD registers
+ #. SVE registers
+ #. SME registers
+ #. EL1/0 registers
+
+It is the responsibility of EL3 that any other registers other than the ones mentioned above
+will not be leaked to the NS Host and to maintain the confidentiality of the Realm World.
+
+SMCCC v1.3 allows NS world to specify whether SVE context is in use. In this
+case, RMM could choose to not save the incoming SVE context but must ensure
+to clear SVE registers if they have been used in Realm World. The same applies
+to SME registers.
+
+Types
+_____
+
+.. _rmm_el3_manifest_struct:
+
+RMM-EL3 Boot Manifest Version
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The RMM-EL3 Boot Manifest structure contains platform boot information passed
+from EL3 to RMM. The width of the Boot Manifest is 128 bits
+
+.. image:: ../resources/diagrams/rmm_el3_manifest_struct.png
+
+The members of the RMM-EL3 Boot Manifest structure are shown in the following
+table:
+
+.. csv-table::
+ :header: "Name", "Range", "Type", Description
+ :widths: 2 1 1 4
+
+ ``Version Minor``,15:0,uint16_t,Version Minor part of the Boot Manifest Version.
+ ``Version Major``,30:16,uint16_t,Version Major part of the Boot Manifest Version.
+ ``RES0``,31,bit,Reserved. Set to 0.
+ ``Platform Data``,127:64,Address,Pointer to the Platform Data section of the Boot Manifest.
diff --git a/docs/components/romlib-design.rst b/docs/components/romlib-design.rst
new file mode 100644
index 0000000..d34b3cc
--- /dev/null
+++ b/docs/components/romlib-design.rst
@@ -0,0 +1,155 @@
+Library 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 ``<fn_name>.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
+
+Memory impact
+~~~~~~~~~~~~~
+
+Using library at ROM will modify the memory layout of the BL images:
+
+- The ROM library needs a page aligned RAM section to hold the RW data. This
+ section is defined by the ROMLIB_RW_BASE and ROMLIB_RW_END macros.
+ On Arm platforms a section of 1 page (0x1000) is allocated at the top of SRAM.
+ This will have for effect to shift down all the BL images by 1 page.
+
+- Depending on the functions moved to the ROM library, the size of the BL images
+ will be reduced.
+ For example: moving MbedTLS function into the ROM library reduces BL1 and
+ BL2, but not BL31.
+
+- This change in BL images size can be taken into consideration to optimize the
+ memory layout when defining the BLx_BASE macros.
+
+Build library at ROM
+~~~~~~~~~~~~~~~~~~~~~
+
+The environment variable ``CROSS_COMPILE`` must be set appropriately. Refer to
+:ref:`Performing an Initial Build` for more information about setting this
+variable.
+
+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=</path/to/mbedtls/> \
+ TRUSTED_BOARD_BOOT=1 GENERATE_COT=1 \
+ ARM_ROTPK_LOCATION=devel_rsa \
+ ROT_KEY=plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem \
+ BL33=</path/to/bl33.bin> \
+ USE_ROMLIB=1 \
+ all fip
+
+--------------
+
+*Copyright (c) 2019, Arm Limited. All rights reserved.*
diff --git a/docs/components/sdei.rst b/docs/components/sdei.rst
new file mode 100644
index 0000000..60259c8
--- /dev/null
+++ b/docs/components/sdei.rst
@@ -0,0 +1,369 @@
+SDEI: 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:
+
+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 <porting_guide_sdei_requirements>`.
+
+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`_
diff --git a/docs/components/secure-partition-manager-mm.rst b/docs/components/secure-partition-manager-mm.rst
new file mode 100644
index 0000000..4cdb96c
--- /dev/null
+++ b/docs/components/secure-partition-manager-mm.rst
@@ -0,0 +1,834 @@
+Secure Partition Manager (MM)
+*****************************
+
+Foreword
+========
+
+Two implementations of a Secure Partition Manager co-exist in the TF-A codebase:
+
+- SPM based on the FF-A specification (:ref:`Secure Partition Manager`).
+- SPM based on the MM interface.
+
+Both implementations differ in their architectures and only one can be selected
+at build time.
+
+This document describes the latter implementation where the Secure Partition Manager
+resides at EL3 and management services run from isolated Secure Partitions at S-EL0.
+The communication protocol is established through the Management Mode (MM) interface.
+
+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 ``SPM_MM=1``, along with ``EL3_EXCEPTION_HANDLING=1`` and ``ENABLE_SVE_FOR_NS=0``.
+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 SPM_MM=1 EL3_EXCEPTION_HANDLING=1 ENABLE_SVE_FOR_NS=0 ARM_BL31_IN_DRAM=1 all fip
+
+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
+ ``spm_mm_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_MM_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
+``MM_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
+``MM_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.
+
+``MM_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 ``MM_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
+``MM_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.
+
+``MM_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 ``MM_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.
+
+``MM_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
+ ``MM_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 ``MM_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-2021, 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: https://developer.arm.com/docs/den0028/latest
+
+.. |Image 1| image:: ../resources/diagrams/secure_sw_stack_tos.png
+.. |Image 2| image:: ../resources/diagrams/secure_sw_stack_sp.png
diff --git a/docs/components/secure-partition-manager.rst b/docs/components/secure-partition-manager.rst
new file mode 100644
index 0000000..cd439ad
--- /dev/null
+++ b/docs/components/secure-partition-manager.rst
@@ -0,0 +1,1565 @@
+Secure Partition Manager
+************************
+
+.. contents::
+
+.. toctree::
+ ffa-manifest-binding
+
+Acronyms
+========
+
++--------+--------------------------------------+
+| CoT | Chain of Trust |
++--------+--------------------------------------+
+| DMA | Direct Memory Access |
++--------+--------------------------------------+
+| DTB | Device Tree Blob |
++--------+--------------------------------------+
+| DTS | Device Tree Source |
++--------+--------------------------------------+
+| EC | Execution Context |
++--------+--------------------------------------+
+| FIP | Firmware Image Package |
++--------+--------------------------------------+
+| FF-A | Firmware Framework for Arm A-profile |
++--------+--------------------------------------+
+| IPA | Intermediate Physical Address |
++--------+--------------------------------------+
+| JOP | Jump-Oriented Programming |
++--------+--------------------------------------+
+| NWd | Normal World |
++--------+--------------------------------------+
+| ODM | Original Design Manufacturer |
++--------+--------------------------------------+
+| OEM | Original Equipment Manufacturer |
++--------+--------------------------------------+
+| PA | Physical Address |
++--------+--------------------------------------+
+| PE | Processing Element |
++--------+--------------------------------------+
+| PM | Power Management |
++--------+--------------------------------------+
+| PVM | Primary VM |
++--------+--------------------------------------+
+| ROP | Return-Oriented Programming |
++--------+--------------------------------------+
+| SMMU | System Memory Management Unit |
++--------+--------------------------------------+
+| SP | Secure Partition |
++--------+--------------------------------------+
+| SPD | Secure Payload Dispatcher |
++--------+--------------------------------------+
+| SPM | Secure Partition Manager |
++--------+--------------------------------------+
+| SPMC | SPM Core |
++--------+--------------------------------------+
+| SPMD | SPM Dispatcher |
++--------+--------------------------------------+
+| SiP | Silicon Provider |
++--------+--------------------------------------+
+| SWd | Secure World |
++--------+--------------------------------------+
+| TLV | Tag-Length-Value |
++--------+--------------------------------------+
+| TOS | Trusted Operating System |
++--------+--------------------------------------+
+| VM | Virtual Machine |
++--------+--------------------------------------+
+
+Foreword
+========
+
+Three implementations of a Secure Partition Manager co-exist in the TF-A
+codebase:
+
+#. S-EL2 SPMC based on the FF-A specification `[1]`_, enabling virtualization in
+ the secure world, managing multiple S-EL1 or S-EL0 partitions.
+#. EL3 SPMC based on the FF-A specification, managing a single S-EL1 partition
+ without virtualization in the secure world.
+#. EL3 SPM based on the MM specification, legacy implementation managing a
+ single S-EL0 partition `[2]`_.
+
+These implementations differ in their respective SW architecture and only one
+can be selected at build time. This document:
+
+- describes the implementation from bullet 1. when the SPMC resides at S-EL2.
+- is not an architecture specification and it might provide assumptions
+ on sections mandated as implementation-defined in the specification.
+- covers the implications to TF-A used as a bootloader, and Hafnium used as a
+ reference code base for an S-EL2/SPMC secure firmware on platforms
+ implementing the FEAT_SEL2 architecture extension.
+
+Terminology
+-----------
+
+- The term Hypervisor refers to the NS-EL2 component managing Virtual Machines
+ (or partitions) in the normal world.
+- The term SPMC refers to the S-EL2 component managing secure partitions in
+ the secure world when the FEAT_SEL2 architecture extension is implemented.
+- Alternatively, SPMC can refer to an S-EL1 component, itself being a secure
+ partition and implementing the FF-A ABI on platforms not implementing the
+ FEAT_SEL2 architecture extension.
+- The term VM refers to a normal world Virtual Machine managed by an Hypervisor.
+- The term SP refers to a secure world "Virtual Machine" managed by an SPMC.
+
+Support for legacy platforms
+----------------------------
+
+The SPM is split into a dispatcher and a core component (respectively SPMD and
+SPMC) residing at different exception levels. To permit the FF-A specification
+adoption and a smooth migration, the SPMD supports an SPMC residing either at
+S-EL1 or S-EL2:
+
+- The SPMD is located at EL3 and mainly relays the FF-A protocol from NWd
+ (Hypervisor or OS kernel) to the SPMC.
+- The same SPMD component is used for both S-EL1 and S-EL2 SPMC configurations.
+- The SPMC exception level is a build time choice.
+
+TF-A supports both cases:
+
+- S-EL1 SPMC for platforms not supporting the FEAT_SEL2 architecture
+ extension. The SPMD relays the FF-A protocol from EL3 to S-EL1.
+- S-EL2 SPMC for platforms implementing the FEAT_SEL2 architecture
+ extension. The SPMD relays the FF-A protocol from EL3 to S-EL2.
+
+Sample reference stack
+======================
+
+The following diagram illustrates a possible configuration when the
+FEAT_SEL2 architecture extension is implemented, showing the SPMD
+and SPMC, one or multiple secure partitions, with an optional
+Hypervisor:
+
+.. image:: ../resources/diagrams/ff-a-spm-sel2.png
+
+TF-A build options
+==================
+
+This section explains the TF-A build options involved in building with
+support for an FF-A based SPM where the SPMD is located at EL3 and the
+SPMC located at S-EL1, S-EL2 or EL3:
+
+- **SPD=spmd**: this option selects the SPMD component to relay the FF-A
+ protocol from NWd to SWd back and forth. It is not possible to
+ enable another Secure Payload Dispatcher when this option is chosen.
+- **SPMD_SPM_AT_SEL2**: this option adjusts the SPMC exception
+ level to being at S-EL2. It defaults to enabled (value 1) when
+ SPD=spmd is chosen.
+- **SPMC_AT_EL3**: this option adjusts the SPMC exception level to being
+ at EL3.
+- If neither ``SPMD_SPM_AT_SEL2`` or ``SPMC_AT_EL3`` are enabled the SPMC
+ exception level is set to S-EL1.
+- **CTX_INCLUDE_EL2_REGS**: this option permits saving (resp.
+ restoring) the EL2 system register context before entering (resp.
+ after leaving) the SPMC. It is mandatorily enabled when
+ ``SPMD_SPM_AT_SEL2`` is enabled. The context save/restore routine
+ and exhaustive list of registers is visible at `[4]`_.
+- **SP_LAYOUT_FILE**: this option specifies a text description file
+ providing paths to SP binary images and manifests in DTS format
+ (see `Describing secure partitions`_). It
+ is required when ``SPMD_SPM_AT_SEL2`` is enabled hence when multiple
+ secure partitions are to be loaded by BL2 on behalf of the SPMC.
+
++---------------+----------------------+------------------+-------------+
+| | CTX_INCLUDE_EL2_REGS | SPMD_SPM_AT_SEL2 | SPMC_AT_EL3 |
++---------------+----------------------+------------------+-------------+
+| SPMC at S-EL1 | 0 | 0 | 0 |
++---------------+----------------------+------------------+-------------+
+| SPMC at S-EL2 | 1 | 1 (default when | 0 |
+| | | SPD=spmd) | |
++---------------+----------------------+------------------+-------------+
+| SPMC at EL3 | 0 | 0 | 1 |
++---------------+----------------------+------------------+-------------+
+
+Other combinations of such build options either break the build or are not
+supported.
+
+Notes:
+
+- Only Arm's FVP platform is supported to use with the TF-A reference software
+ stack.
+- When ``SPMD_SPM_AT_SEL2=1``, the reference software stack assumes enablement
+ of FEAT_PAuth, FEAT_BTI and FEAT_MTE architecture extensions.
+- The ``CTX_INCLUDE_EL2_REGS`` option provides the generic support for
+ barely saving/restoring EL2 registers from an Arm arch perspective. As such
+ it is decoupled from the ``SPD=spmd`` option.
+- BL32 option is re-purposed to specify the SPMC image. It can specify either
+ the Hafnium binary path (built for the secure world) or the path to a TEE
+ binary implementing FF-A interfaces.
+- BL33 option can specify the TFTF binary or a normal world loader
+ such as U-Boot or the UEFI framework payload.
+
+Sample TF-A build command line when the SPMC is located at S-EL1
+(e.g. when the FEAT_SEL2 architecture extension is not implemented):
+
+.. code:: shell
+
+ make \
+ CROSS_COMPILE=aarch64-none-elf- \
+ SPD=spmd \
+ SPMD_SPM_AT_SEL2=0 \
+ BL32=<path-to-tee-binary> \
+ BL33=<path-to-bl33-binary> \
+ PLAT=fvp \
+ all fip
+
+Sample TF-A build command line when FEAT_SEL2 architecture extension is
+implemented and the SPMC is located at S-EL2:
+.. code:: shell
+
+ make \
+ CROSS_COMPILE=aarch64-none-elf- \
+ PLAT=fvp \
+ SPD=spmd \
+ CTX_INCLUDE_EL2_REGS=1 \
+ ARM_ARCH_MINOR=5 \
+ BRANCH_PROTECTION=1 \
+ CTX_INCLUDE_PAUTH_REGS=1 \
+ CTX_INCLUDE_MTE_REGS=1 \
+ BL32=<path-to-hafnium-binary> \
+ BL33=<path-to-bl33-binary> \
+ SP_LAYOUT_FILE=sp_layout.json \
+ all fip
+
+Sample TF-A build command line when FEAT_SEL2 architecture extension is
+implemented, the SPMC is located at S-EL2, and enabling secure boot:
+.. code:: shell
+
+ make \
+ CROSS_COMPILE=aarch64-none-elf- \
+ PLAT=fvp \
+ SPD=spmd \
+ CTX_INCLUDE_EL2_REGS=1 \
+ ARM_ARCH_MINOR=5 \
+ BRANCH_PROTECTION=1 \
+ CTX_INCLUDE_PAUTH_REGS=1 \
+ CTX_INCLUDE_MTE_REGS=1 \
+ BL32=<path-to-hafnium-binary> \
+ BL33=<path-to-bl33-binary> \
+ SP_LAYOUT_FILE=sp_layout.json \
+ MBEDTLS_DIR=<path-to-mbedtls-lib> \
+ TRUSTED_BOARD_BOOT=1 \
+ COT=dualroot \
+ ARM_ROTPK_LOCATION=devel_rsa \
+ ROT_KEY=plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem \
+ GENERATE_COT=1 \
+ all fip
+
+Sample TF-A build command line when the SPMC is located at EL3:
+
+.. code:: shell
+
+ make \
+ CROSS_COMPILE=aarch64-none-elf- \
+ SPD=spmd \
+ SPMD_SPM_AT_SEL2=0 \
+ SPMC_AT_EL3=1 \
+ BL32=<path-to-tee-binary> \
+ BL33=<path-to-bl33-binary> \
+ PLAT=fvp \
+ all fip
+
+FVP model invocation
+====================
+
+The FVP command line needs the following options to exercise the S-EL2 SPMC:
+
++---------------------------------------------------+------------------------------------+
+| - cluster0.has_arm_v8-5=1 | Implements FEAT_SEL2, FEAT_PAuth, |
+| - cluster1.has_arm_v8-5=1 | and FEAT_BTI. |
++---------------------------------------------------+------------------------------------+
+| - pci.pci_smmuv3.mmu.SMMU_AIDR=2 | Parameters required for the |
+| - pci.pci_smmuv3.mmu.SMMU_IDR0=0x0046123B | SMMUv3.2 modeling. |
+| - pci.pci_smmuv3.mmu.SMMU_IDR1=0x00600002 | |
+| - pci.pci_smmuv3.mmu.SMMU_IDR3=0x1714 | |
+| - pci.pci_smmuv3.mmu.SMMU_IDR5=0xFFFF0472 | |
+| - pci.pci_smmuv3.mmu.SMMU_S_IDR1=0xA0000002 | |
+| - pci.pci_smmuv3.mmu.SMMU_S_IDR2=0 | |
+| - pci.pci_smmuv3.mmu.SMMU_S_IDR3=0 | |
++---------------------------------------------------+------------------------------------+
+| - cluster0.has_branch_target_exception=1 | Implements FEAT_BTI. |
+| - cluster1.has_branch_target_exception=1 | |
++---------------------------------------------------+------------------------------------+
+| - cluster0.has_pointer_authentication=2 | Implements FEAT_PAuth |
+| - cluster1.has_pointer_authentication=2 | |
++---------------------------------------------------+------------------------------------+
+| - cluster0.memory_tagging_support_level=2 | Implements FEAT_MTE2 |
+| - cluster1.memory_tagging_support_level=2 | |
+| - bp.dram_metadata.is_enabled=1 | |
++---------------------------------------------------+------------------------------------+
+
+Sample FVP command line invocation:
+
+.. code:: shell
+
+ <path-to-fvp-model>/FVP_Base_RevC-2xAEMvA -C pctl.startup=0.0.0.0 \
+ -C cluster0.NUM_CORES=4 -C cluster1.NUM_CORES=4 -C bp.secure_memory=1 \
+ -C bp.secureflashloader.fname=trusted-firmware-a/build/fvp/debug/bl1.bin \
+ -C bp.flashloader0.fname=trusted-firmware-a/build/fvp/debug/fip.bin \
+ -C bp.pl011_uart0.out_file=fvp-uart0.log -C bp.pl011_uart1.out_file=fvp-uart1.log \
+ -C bp.pl011_uart2.out_file=fvp-uart2.log \
+ -C cluster0.has_arm_v8-5=1 -C cluster1.has_arm_v8-5=1 \
+ -C cluster0.has_pointer_authentication=2 -C cluster1.has_pointer_authentication=2 \
+ -C cluster0.has_branch_target_exception=1 -C cluster1.has_branch_target_exception=1 \
+ -C cluster0.memory_tagging_support_level=2 -C cluster1.memory_tagging_support_level=2 \
+ -C bp.dram_metadata.is_enabled=1 \
+ -C pci.pci_smmuv3.mmu.SMMU_AIDR=2 -C pci.pci_smmuv3.mmu.SMMU_IDR0=0x0046123B \
+ -C pci.pci_smmuv3.mmu.SMMU_IDR1=0x00600002 -C pci.pci_smmuv3.mmu.SMMU_IDR3=0x1714 \
+ -C pci.pci_smmuv3.mmu.SMMU_IDR5=0xFFFF0472 -C pci.pci_smmuv3.mmu.SMMU_S_IDR1=0xA0000002 \
+ -C pci.pci_smmuv3.mmu.SMMU_S_IDR2=0 -C pci.pci_smmuv3.mmu.SMMU_S_IDR3=0
+
+Boot process
+============
+
+Loading Hafnium and secure partitions in the secure world
+---------------------------------------------------------
+
+TF-A BL2 is the bootlader for the SPMC and SPs in the secure world.
+
+SPs may be signed by different parties (SiP, OEM/ODM, TOS vendor, etc.).
+Thus they are supplied as distinct signed entities within the FIP flash
+image. The FIP image itself is not signed hence this provides the ability
+to upgrade SPs in the field.
+
+Booting through TF-A
+--------------------
+
+SP manifests
+~~~~~~~~~~~~
+
+An SP manifest describes SP attributes as defined in `[1]`_
+(partition manifest at virtual FF-A instance) in DTS format. It is
+represented as a single file associated with the SP. A sample is
+provided by `[5]`_. A binding document is provided by `[6]`_.
+
+Secure Partition packages
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Secure partitions are bundled as independent package files consisting
+of:
+
+- a header
+- a DTB
+- an image payload
+
+The header starts with a magic value and offset values to SP DTB and
+image payload. Each SP package is loaded independently by BL2 loader
+and verified for authenticity and integrity.
+
+The SP package identified by its UUID (matching FF-A uuid property) is
+inserted as a single entry into the FIP at end of the TF-A build flow
+as shown:
+
+.. code:: shell
+
+ Trusted Boot Firmware BL2: offset=0x1F0, size=0x8AE1, cmdline="--tb-fw"
+ EL3 Runtime Firmware BL31: offset=0x8CD1, size=0x13000, cmdline="--soc-fw"
+ Secure Payload BL32 (Trusted OS): offset=0x1BCD1, size=0x15270, cmdline="--tos-fw"
+ Non-Trusted Firmware BL33: offset=0x30F41, size=0x92E0, cmdline="--nt-fw"
+ HW_CONFIG: offset=0x3A221, size=0x2348, cmdline="--hw-config"
+ TB_FW_CONFIG: offset=0x3C569, size=0x37A, cmdline="--tb-fw-config"
+ SOC_FW_CONFIG: offset=0x3C8E3, size=0x48, cmdline="--soc-fw-config"
+ TOS_FW_CONFIG: offset=0x3C92B, size=0x427, cmdline="--tos-fw-config"
+ NT_FW_CONFIG: offset=0x3CD52, size=0x48, cmdline="--nt-fw-config"
+ B4B5671E-4A90-4FE1-B81F-FB13DAE1DACB: offset=0x3CD9A, size=0xC168, cmdline="--blob"
+ D1582309-F023-47B9-827C-4464F5578FC8: offset=0x48F02, size=0xC168, cmdline="--blob"
+
+.. uml:: ../resources/diagrams/plantuml/fip-secure-partitions.puml
+
+Describing secure partitions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A json-formatted description file is passed to the build flow specifying paths
+to the SP binary image and associated DTS partition manifest file. The latter
+is processed by the dtc compiler to generate a DTB fed into the SP package.
+Optionally, the partition's json description can contain offsets for both
+the image and partition manifest within the SP package. Both offsets need to be
+4KB aligned, because it is the translation granule supported by Hafnium SPMC.
+These fields can be leveraged to support SPs with S1 translation granules that
+differ from 4KB, and to configure the regions allocated within the SP package,
+as well as to comply with the requirements for the implementation of the boot
+information protocol (see `Passing boot data to the SP`_ for more details). In
+case the offsets are absent in their json node, they default to 0x1000 and
+0x4000 for the manifest offset and image offset respectively.
+This file also specifies the SP owner (as an optional field) identifying the
+signing domain in case of dual root CoT.
+The SP owner can either be the silicon or the platform provider. The
+corresponding "owner" field value can either take the value of "SiP" or "Plat".
+In absence of "owner" field, it defaults to "SiP" owner.
+The UUID of the partition can be specified as a field in the description file or
+if it does not exist there the UUID is extracted from the DTS partition
+manifest.
+
+.. code:: shell
+
+ {
+ "tee1" : {
+ "image": "tee1.bin",
+ "pm": "tee1.dts",
+ "owner": "SiP",
+ "uuid": "1b1820fe-48f7-4175-8999-d51da00b7c9f"
+ },
+
+ "tee2" : {
+ "image": "tee2.bin",
+ "pm": "tee2.dts",
+ "owner": "Plat"
+ },
+
+ "tee3" : {
+ "image": {
+ "file": "tee3.bin",
+ "offset":"0x2000"
+ },
+ "pm": {
+ "file": "tee3.dts",
+ "offset":"0x6000"
+ },
+ "owner": "Plat"
+ },
+ }
+
+SPMC manifest
+~~~~~~~~~~~~~
+
+This manifest contains the SPMC *attribute* node consumed by the SPMD at boot
+time. It implements `[1]`_ (SP manifest at physical FF-A instance) and serves
+two different cases:
+
+- The SPMC resides at S-EL1: the SPMC manifest is used by the SPMD to setup a
+ SP that co-resides with the SPMC and executes at S-EL1 or Secure Supervisor
+ mode.
+- The SPMC resides at S-EL2: the SPMC manifest is used by the SPMD to setup
+ the environment required by the SPMC to run at S-EL2. SPs run at S-EL1 or
+ S-EL0.
+
+.. code:: shell
+
+ attribute {
+ spmc_id = <0x8000>;
+ maj_ver = <0x1>;
+ min_ver = <0x1>;
+ exec_state = <0x0>;
+ load_address = <0x0 0x6000000>;
+ entrypoint = <0x0 0x6000000>;
+ binary_size = <0x60000>;
+ };
+
+- *spmc_id* defines the endpoint ID value that SPMC can query through
+ ``FFA_ID_GET``.
+- *maj_ver/min_ver*. SPMD checks provided version versus its internal
+ version and aborts if not matching.
+- *exec_state* defines the SPMC execution state (AArch64 or AArch32).
+ Notice Hafnium used as a SPMC only supports AArch64.
+- *load_address* and *binary_size* are mostly used to verify secondary
+ entry points fit into the loaded binary image.
+- *entrypoint* defines the cold boot primary core entry point used by
+ SPMD (currently matches ``BL32_BASE``) to enter the SPMC.
+
+Other nodes in the manifest are consumed by Hafnium in the secure world.
+A sample can be found at `[7]`_:
+
+- The *hypervisor* node describes SPs. *is_ffa_partition* boolean attribute
+ indicates a FF-A compliant SP. The *load_address* field specifies the load
+ address at which BL2 loaded the SP package.
+- *cpus* node provide the platform topology and allows MPIDR to VMPIDR mapping.
+ Note the primary core is declared first, then secondary cores are declared
+ in reverse order.
+- The *memory* node provides platform information on the ranges of memory
+ available to the SPMC.
+
+SPMC boot
+~~~~~~~~~
+
+The SPMC is loaded by BL2 as the BL32 image.
+
+The SPMC manifest is loaded by BL2 as the ``TOS_FW_CONFIG`` image `[9]`_.
+
+BL2 passes the SPMC manifest address to BL31 through a register.
+
+At boot time, the SPMD in BL31 runs from the primary core, initializes the core
+contexts and launches the SPMC (BL32) passing the following information through
+registers:
+
+- X0 holds the ``TOS_FW_CONFIG`` physical address (or SPMC manifest blob).
+- X1 holds the ``HW_CONFIG`` physical address.
+- X4 holds the currently running core linear id.
+
+Loading of SPs
+~~~~~~~~~~~~~~
+
+At boot time, BL2 loads SPs sequentially in addition to the SPMC as depicted
+below:
+
+.. uml:: ../resources/diagrams/plantuml/bl2-loading-sp.puml
+
+Note this boot flow is an implementation sample on Arm's FVP platform.
+Platforms not using TF-A's *Firmware CONFiguration* framework would adjust to a
+different boot flow. The flow restricts to a maximum of 8 secure partitions.
+
+Secure boot
+~~~~~~~~~~~
+
+The SP content certificate is inserted as a separate FIP item so that BL2 loads SPMC,
+SPMC manifest, secure partitions and verifies them for authenticity and integrity.
+Refer to TBBR specification `[3]`_.
+
+The multiple-signing domain feature (in current state dual signing domain `[8]`_) allows
+the use of two root keys namely S-ROTPK and NS-ROTPK:
+
+- SPMC (BL32) and SPMC manifest are signed by the SiP using the S-ROTPK.
+- BL33 may be signed by the OEM using NS-ROTPK.
+- An SP may be signed either by SiP (using S-ROTPK) or by OEM (using NS-ROTPK).
+- A maximum of 4 partitions can be signed with the S-ROTPK key and 4 partitions
+ signed with the NS-ROTPK key.
+
+Also refer to `Describing secure partitions`_ and `TF-A build options`_ sections.
+
+Hafnium in the secure world
+===========================
+
+General considerations
+----------------------
+
+Build platform for the secure world
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In the Hafnium reference implementation specific code parts are only relevant to
+the secure world. Such portions are isolated in architecture specific files
+and/or enclosed by a ``SECURE_WORLD`` macro.
+
+Secure partitions scheduling
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The FF-A specification `[1]`_ provides two ways to relinquinsh CPU time to
+secure partitions. For this a VM (Hypervisor or OS kernel), or SP invokes one of:
+
+- the FFA_MSG_SEND_DIRECT_REQ interface.
+- the FFA_RUN interface.
+
+Additionally a secure interrupt can pre-empt the normal world execution and give
+CPU cycles by transitioning to EL3 and S-EL2.
+
+Platform topology
+~~~~~~~~~~~~~~~~~
+
+The *execution-ctx-count* SP manifest field can take the value of one or the
+total number of PEs. The FF-A specification `[1]`_ recommends the
+following SP types:
+
+- Pinned MP SPs: an execution context matches a physical PE. MP SPs must
+ implement the same number of ECs as the number of PEs in the platform.
+- Migratable UP SPs: a single execution context can run and be migrated on any
+ physical PE. Such SP declares a single EC in its SP manifest. An UP SP can
+ receive a direct message request originating from any physical core targeting
+ the single execution context.
+
+Parsing SP partition manifests
+------------------------------
+
+Hafnium consumes SP manifests as defined in `[1]`_ and `SP manifests`_.
+Note the current implementation may not implement all optional fields.
+
+The SP manifest may contain memory and device regions nodes. In case of
+an S-EL2 SPMC:
+
+- Memory regions are mapped in the SP EL1&0 Stage-2 translation regime at
+ load time (or EL1&0 Stage-1 for an S-EL1 SPMC). A memory region node can
+ specify RX/TX buffer regions in which case it is not necessary for an SP
+ to explicitly invoke the ``FFA_RXTX_MAP`` interface.
+- Device regions are mapped in the SP EL1&0 Stage-2 translation regime (or
+ EL1&0 Stage-1 for an S-EL1 SPMC) as peripherals and possibly allocate
+ additional resources (e.g. interrupts).
+
+For the S-EL2 SPMC, base addresses for memory and device region nodes are IPAs
+provided the SPMC identity maps IPAs to PAs within SP EL1&0 Stage-2 translation
+regime.
+
+Note: in the current implementation both VTTBR_EL2 and VSTTBR_EL2 point to the
+same set of page tables. It is still open whether two sets of page tables shall
+be provided per SP. The memory region node as defined in the specification
+provides a memory security attribute hinting to map either to the secure or
+non-secure EL1&0 Stage-2 table if it exists.
+
+Passing boot data to the SP
+---------------------------
+
+In `[1]`_ , the section "Boot information protocol" defines a method for passing
+data to the SPs at boot time. It specifies the format for the boot information
+descriptor and boot information header structures, which describe the data to be
+exchanged between SPMC and SP.
+The specification also defines the types of data that can be passed.
+The aggregate of both the boot info structures and the data itself is designated
+the boot information blob, and is passed to a Partition as a contiguous memory
+region.
+
+Currently, the SPM implementation supports the FDT type which is used to pass the
+partition's DTB manifest.
+
+The region for the boot information blob is allocated through the SP package.
+
+.. image:: ../resources/diagrams/partition-package.png
+
+To adjust the space allocated for the boot information blob, the json description
+of the SP (see section `Describing secure partitions`_) shall be updated to contain
+the manifest offset. If no offset is provided the manifest offset defaults to 0x1000,
+which is the page size in the Hafnium SPMC.
+
+The configuration of the boot protocol is done in the SPs manifest. As defined by
+the specification, the manifest field 'gp-register-num' configures the GP register
+which shall be used to pass the address to the partitions boot information blob when
+booting the partition.
+In addition, the Hafnium SPMC implementation requires the boot information arguments
+to be listed in a designated DT node:
+
+.. code:: shell
+
+ boot-info {
+ compatible = "arm,ffa-manifest-boot-info";
+ ffa_manifest;
+ };
+
+The whole secure partition package image (see `Secure Partition packages`_) is
+mapped to the SP secure EL1&0 Stage-2 translation regime. As such, the SP can
+retrieve the address for the boot information blob in the designated GP register,
+process the boot information header and descriptors, access its own manifest
+DTB blob and extract its partition manifest properties.
+
+SP Boot order
+-------------
+
+SP manifests provide an optional boot order attribute meant to resolve
+dependencies such as an SP providing a service required to properly boot
+another SP. SPMC boots the SPs in accordance to the boot order attribute,
+lowest to the highest value. If the boot order attribute is absent from the FF-A
+manifest, the SP is treated as if it had the highest boot order value
+(i.e. lowest booting priority).
+
+It is possible for an SP to call into another SP through a direct request
+provided the latter SP has already been booted.
+
+Boot phases
+-----------
+
+Primary core boot-up
+~~~~~~~~~~~~~~~~~~~~
+
+Upon boot-up, BL31 hands over to the SPMC (BL32) on the primary boot physical
+core. The SPMC performs its platform initializations and registers the SPMC
+secondary physical core entry point physical address by the use of the
+`FFA_SECONDARY_EP_REGISTER`_ interface (SMC invocation from the SPMC to the SPMD
+at secure physical FF-A instance).
+
+The SPMC then creates secure partitions based on SP packages and manifests. Each
+secure partition is launched in sequence (`SP Boot order`_) on their "primary"
+execution context. If the primary boot physical core linear id is N, an MP SP is
+started using EC[N] on PE[N] (see `Platform topology`_). If the partition is a
+UP SP, it is started using its unique EC0 on PE[N].
+
+The SP primary EC (or the EC used when the partition is booted as described
+above):
+
+- Performs the overall SP boot time initialization, and in case of a MP SP,
+ prepares the SP environment for other execution contexts.
+- In the case of a MP SP, it invokes the FFA_SECONDARY_EP_REGISTER at secure
+ virtual FF-A instance (SMC invocation from SP to SPMC) to provide the IPA
+ entry point for other execution contexts.
+- Exits through ``FFA_MSG_WAIT`` to indicate successful initialization or
+ ``FFA_ERROR`` in case of failure.
+
+Secondary cores boot-up
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Once the system is started and NWd brought up, a secondary physical core is
+woken up by the ``PSCI_CPU_ON`` service invocation. The TF-A SPD hook mechanism
+calls into the SPMD on the newly woken up physical core. Then the SPMC is
+entered at the secondary physical core entry point.
+
+In the current implementation, the first SP is resumed on the coresponding EC
+(the virtual CPU which matches the physical core). The implication is that the
+first SP must be a MP SP.
+
+In a linux based system, once secure and normal worlds are booted but prior to
+a NWd FF-A driver has been loaded:
+
+- The first SP has initialized all its ECs in response to primary core boot up
+ (at system initialization) and secondary core boot up (as a result of linux
+ invoking PSCI_CPU_ON for all secondary cores).
+- Other SPs have their first execution context initialized as a result of secure
+ world initialization on the primary boot core. Other ECs for those SPs have to
+ be run first through ffa_run to complete their initialization (which results
+ in the EC completing with FFA_MSG_WAIT).
+
+Refer to `Power management`_ for further details.
+
+Notifications
+-------------
+
+The FF-A v1.1 specification `[1]`_ defines notifications as an asynchronous
+communication mechanism with non-blocking semantics. It allows for one FF-A
+endpoint to signal another for service provision, without hindering its current
+progress.
+
+Hafnium currently supports 64 notifications. The IDs of each notification define
+a position in a 64-bit bitmap.
+
+The signaling of notifications can interchangeably happen between NWd and SWd
+FF-A endpoints.
+
+The SPMC is in charge of managing notifications from SPs to SPs, from SPs to
+VMs, and from VMs to SPs. An hypervisor component would only manage
+notifications from VMs to VMs. Given the SPMC has no visibility of the endpoints
+deployed in NWd, the Hypervisor or OS kernel must invoke the interface
+FFA_NOTIFICATION_BITMAP_CREATE to allocate the notifications bitmap per FF-A
+endpoint in the NWd that supports it.
+
+A sender can signal notifications once the receiver has provided it with
+permissions. Permissions are provided by invoking the interface
+FFA_NOTIFICATION_BIND.
+
+Notifications are signaled by invoking FFA_NOTIFICATION_SET. Henceforth
+they are considered to be in a pending sate. The receiver can retrieve its
+pending notifications invoking FFA_NOTIFICATION_GET, which, from that moment,
+are considered to be handled.
+
+Per the FF-A v1.1 spec, each FF-A endpoint must be associated with a scheduler
+that is in charge of donating CPU cycles for notifications handling. The
+FF-A driver calls FFA_NOTIFICATION_INFO_GET to retrieve the information about
+which FF-A endpoints have pending notifications. The receiver scheduler is
+called and informed by the FF-A driver, and it should allocate CPU cycles to the
+receiver.
+
+There are two types of notifications supported:
+
+- Global, which are targeted to a FF-A endpoint and can be handled within any of
+ its execution contexts, as determined by the scheduler of the system.
+- Per-vCPU, which are targeted to a FF-A endpoint and to be handled within a
+ a specific execution context, as determined by the sender.
+
+The type of a notification is set when invoking FFA_NOTIFICATION_BIND to give
+permissions to the sender.
+
+Notification signaling resorts to two interrupts:
+
+- Schedule Receiver Interrupt: non-secure physical interrupt to be handled by
+ the FF-A driver within the receiver scheduler. At initialization the SPMC
+ donates a SGI ID chosen from the secure SGI IDs range and configures it as
+ non-secure. The SPMC triggers this SGI on the currently running core when
+ there are pending notifications, and the respective receivers need CPU cycles
+ to handle them.
+- Notifications Pending Interrupt: virtual interrupt to be handled by the
+ receiver of the notification. Set when there are pending notifications for the
+ given secure partition. The NPI is pended when the NWd relinquishes CPU cycles
+ to an SP.
+
+The notifications receipt support is enabled in the partition FF-A manifest.
+
+Mandatory interfaces
+--------------------
+
+The following interfaces are exposed to SPs:
+
+- ``FFA_VERSION``
+- ``FFA_FEATURES``
+- ``FFA_RX_RELEASE``
+- ``FFA_RXTX_MAP``
+- ``FFA_RXTX_UNMAP``
+- ``FFA_PARTITION_INFO_GET``
+- ``FFA_ID_GET``
+- ``FFA_MSG_WAIT``
+- ``FFA_MSG_SEND_DIRECT_REQ``
+- ``FFA_MSG_SEND_DIRECT_RESP``
+- ``FFA_MEM_DONATE``
+- ``FFA_MEM_LEND``
+- ``FFA_MEM_SHARE``
+- ``FFA_MEM_RETRIEVE_REQ``
+- ``FFA_MEM_RETRIEVE_RESP``
+- ``FFA_MEM_RELINQUISH``
+- ``FFA_MEM_FRAG_RX``
+- ``FFA_MEM_FRAG_TX``
+- ``FFA_MEM_RECLAIM``
+- ``FFA_RUN``
+
+As part of the FF-A v1.1 support, the following interfaces were added:
+
+ - ``FFA_NOTIFICATION_BITMAP_CREATE``
+ - ``FFA_NOTIFICATION_BITMAP_DESTROY``
+ - ``FFA_NOTIFICATION_BIND``
+ - ``FFA_NOTIFICATION_UNBIND``
+ - ``FFA_NOTIFICATION_SET``
+ - ``FFA_NOTIFICATION_GET``
+ - ``FFA_NOTIFICATION_INFO_GET``
+ - ``FFA_SPM_ID_GET``
+ - ``FFA_SECONDARY_EP_REGISTER``
+ - ``FFA_MEM_PERM_GET``
+ - ``FFA_MEM_PERM_SET``
+ - ``FFA_MSG_SEND2``
+ - ``FFA_RX_ACQUIRE``
+
+FFA_VERSION
+~~~~~~~~~~~
+
+``FFA_VERSION`` requires a *requested_version* parameter from the caller.
+The returned value depends on the caller:
+
+- Hypervisor or OS kernel in NS-EL1/EL2: the SPMD returns the SPMC version
+ specified in the SPMC manifest.
+- SP: the SPMC returns its own implemented version.
+- SPMC at S-EL1/S-EL2: the SPMD returns its own implemented version.
+
+FFA_FEATURES
+~~~~~~~~~~~~
+
+FF-A features supported by the SPMC may be discovered by secure partitions at
+boot (that is prior to NWd is booted) or run-time.
+
+The SPMC calling FFA_FEATURES at secure physical FF-A instance always get
+FFA_SUCCESS from the SPMD.
+
+The request made by an Hypervisor or OS kernel is forwarded to the SPMC and
+the response relayed back to the NWd.
+
+FFA_RXTX_MAP/FFA_RXTX_UNMAP
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When invoked from a secure partition FFA_RXTX_MAP maps the provided send and
+receive buffers described by their IPAs to the SP EL1&0 Stage-2 translation
+regime as secure buffers in the MMU descriptors.
+
+When invoked from the Hypervisor or OS kernel, the buffers are mapped into the
+SPMC EL2 Stage-1 translation regime and marked as NS buffers in the MMU
+descriptors. The provided addresses may be owned by a VM in the normal world,
+which is expected to receive messages from the secure world. The SPMC will in
+this case allocate internal state structures to facilitate RX buffer access
+synchronization (through FFA_RX_ACQUIRE interface), and to permit SPs to send
+messages.
+
+The FFA_RXTX_UNMAP unmaps the RX/TX pair from the translation regime of the
+caller, either it being the Hypervisor or OS kernel, as well as a secure
+partition.
+
+FFA_PARTITION_INFO_GET
+~~~~~~~~~~~~~~~~~~~~~~
+
+Partition info get call can originate:
+
+- from SP to SPMC
+- from Hypervisor or OS kernel to SPMC. The request is relayed by the SPMD.
+
+FFA_ID_GET
+~~~~~~~~~~
+
+The FF-A id space is split into a non-secure space and secure space:
+
+- FF-A ID with bit 15 clear relates to VMs.
+- FF-A ID with bit 15 set related to SPs.
+- FF-A IDs 0, 0xffff, 0x8000 are assigned respectively to the Hypervisor, SPMD
+ and SPMC.
+
+The SPMD returns:
+
+- The default zero value on invocation from the Hypervisor.
+- The ``spmc_id`` value specified in the SPMC manifest on invocation from
+ the SPMC (see `SPMC manifest`_)
+
+This convention helps the SPMC to determine the origin and destination worlds in
+an FF-A ABI invocation. In particular the SPMC shall filter unauthorized
+transactions in its world switch routine. It must not be permitted for a VM to
+use a secure FF-A ID as origin world by spoofing:
+
+- A VM-to-SP direct request/response shall set the origin world to be non-secure
+ (FF-A ID bit 15 clear) and destination world to be secure (FF-A ID bit 15
+ set).
+- Similarly, an SP-to-SP direct request/response shall set the FF-A ID bit 15
+ for both origin and destination IDs.
+
+An incoming direct message request arriving at SPMD from NWd is forwarded to
+SPMC without a specific check. The SPMC is resumed through eret and "knows" the
+message is coming from normal world in this specific code path. Thus the origin
+endpoint ID must be checked by SPMC for being a normal world ID.
+
+An SP sending a direct message request must have bit 15 set in its origin
+endpoint ID and this can be checked by the SPMC when the SP invokes the ABI.
+
+The SPMC shall reject the direct message if the claimed world in origin endpoint
+ID is not consistent:
+
+- It is either forwarded by SPMD and thus origin endpoint ID must be a "normal
+ world ID",
+- or initiated by an SP and thus origin endpoint ID must be a "secure world ID".
+
+
+FFA_MSG_SEND_DIRECT_REQ/FFA_MSG_SEND_DIRECT_RESP
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is a mandatory interface for secure partitions consisting in direct request
+and responses with the following rules:
+
+- An SP can send a direct request to another SP.
+- An SP can receive a direct request from another SP.
+- An SP can send a direct response to another SP.
+- An SP cannot send a direct request to an Hypervisor or OS kernel.
+- An Hypervisor or OS kernel can send a direct request to an SP.
+- An SP can send a direct response to an Hypervisor or OS kernel.
+
+FFA_NOTIFICATION_BITMAP_CREATE/FFA_NOTIFICATION_BITMAP_DESTROY
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The secure partitions notifications bitmap are statically allocated by the SPMC.
+Hence, this interface is not to be issued by secure partitions.
+
+At initialization, the SPMC is not aware of VMs/partitions deployed in the
+normal world. Hence, the Hypervisor or OS kernel must use both ABIs for SPMC
+to be prepared to handle notifications for the provided VM ID.
+
+FFA_NOTIFICATION_BIND/FFA_NOTIFICATION_UNBIND
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Pair of interfaces to manage permissions to signal notifications. Prior to
+handling notifications, an FF-A endpoint must allow a given sender to signal a
+bitmap of notifications.
+
+If the receiver doesn't have notification support enabled in its FF-A manifest,
+it won't be able to bind notifications, hence forbidding it to receive any
+notifications.
+
+FFA_NOTIFICATION_SET/FFA_NOTIFICATION_GET
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+FFA_NOTIFICATION_GET retrieves all pending global notifications and
+per-vCPU notifications targeted to the current vCPU.
+
+Hafnium maintains a global count of pending notifications which gets incremented
+and decremented when handling FFA_NOTIFICATION_SET and FFA_NOTIFICATION_GET
+respectively. A delayed SRI is triggered if the counter is non-zero when the
+SPMC returns to normal world.
+
+FFA_NOTIFICATION_INFO_GET
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Hafnium maintains a global count of pending notifications whose information
+has been retrieved by this interface. The count is incremented and decremented
+when handling FFA_NOTIFICATION_INFO_GET and FFA_NOTIFICATION_GET respectively.
+It also tracks notifications whose information has been retrieved individually,
+such that it avoids duplicating returned information for subsequent calls to
+FFA_NOTIFICATION_INFO_GET. For each notification, this state information is
+reset when receiver called FFA_NOTIFICATION_GET to retrieve them.
+
+FFA_SPM_ID_GET
+~~~~~~~~~~~~~~
+
+Returns the FF-A ID allocated to an SPM component which can be one of SPMD
+or SPMC.
+
+At initialization, the SPMC queries the SPMD for the SPMC ID, using the
+FFA_ID_GET interface, and records it. The SPMC can also query the SPMD ID using
+the FFA_SPM_ID_GET interface at the secure physical FF-A instance.
+
+Secure partitions call this interface at the virtual FF-A instance, to which
+the SPMC returns the priorly retrieved SPMC ID.
+
+The Hypervisor or OS kernel can issue the FFA_SPM_ID_GET call handled by the
+SPMD, which returns the SPMC ID.
+
+FFA_SECONDARY_EP_REGISTER
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When the SPMC boots, all secure partitions are initialized on their primary
+Execution Context.
+
+The FFA_SECONDARY_EP_REGISTER interface is to be used by a secure partition
+from its first execution context, to provide the entry point address for
+secondary execution contexts.
+
+A secondary EC is first resumed either upon invocation of PSCI_CPU_ON from
+the NWd or by invocation of FFA_RUN.
+
+FFA_RX_ACQUIRE/FFA_RX_RELEASE
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The RX buffers can be used to pass information to an FF-A endpoint in the
+following scenarios:
+
+ - When it was targetted by a FFA_MSG_SEND2 invokation from another endpoint.
+ - Return the result of calling ``FFA_PARTITION_INFO_GET``.
+ - In a memory share operation, as part of the ``FFA_MEM_RETRIEVE_RESP``,
+ with the memory descriptor of the shared memory.
+
+If a normal world VM is expected to exchange messages with secure world,
+its RX/TX buffer addresses are forwarded to the SPMC via FFA_RXTX_MAP ABI,
+and are from this moment owned by the SPMC.
+The hypervisor must call the FFA_RX_ACQUIRE interface before attempting
+to use the RX buffer, in any of the aforementioned scenarios. A successful
+call to FFA_RX_ACQUIRE transfers ownership of RX buffer to hypervisor, such
+that it can be safely used.
+
+The FFA_RX_RELEASE interface is used after the FF-A endpoint is done with
+processing the data received in its RX buffer. If the RX buffer has been
+acquired by the hypervisor, the FFA_RX_RELEASE call must be forwarded to
+the SPMC to reestablish SPMC's RX ownership.
+
+An attempt from an SP to send a message to a normal world VM whose RX buffer
+was acquired by the hypervisor fails with error code FFA_BUSY, to preserve
+the RX buffer integrity.
+The operation could then be conducted after FFA_RX_RELEASE.
+
+FFA_MSG_SEND2
+~~~~~~~~~~~~~
+
+Hafnium copies a message from the sender TX buffer into receiver's RX buffer.
+For messages from SPs to VMs, operation is only possible if the SPMC owns
+the receiver's RX buffer.
+
+Both receiver and sender need to enable support for indirect messaging,
+in their respective partition manifest. The discovery of support
+of such feature can be done via FFA_PARTITION_INFO_GET.
+
+On a successful message send, Hafnium pends an RX buffer full framework
+notification for the receiver, to inform it about a message in the RX buffer.
+
+The handling of framework notifications is similar to that of
+global notifications. Binding of these is not necessary, as these are
+reserved to be used by the hypervisor or SPMC.
+
+SPMC-SPMD direct requests/responses
+-----------------------------------
+
+Implementation-defined FF-A IDs are allocated to the SPMC and SPMD.
+Using those IDs in source/destination fields of a direct request/response
+permits SPMD to SPMC communication and either way.
+
+- SPMC to SPMD direct request/response uses SMC conduit.
+- SPMD to SPMC direct request/response uses ERET conduit.
+
+This is used in particular to convey power management messages.
+
+PE MMU configuration
+--------------------
+
+With secure virtualization enabled (``HCR_EL2.VM = 1``) and for S-EL1
+partitions, two IPA spaces (secure and non-secure) are output from the
+secure EL1&0 Stage-1 translation.
+The EL1&0 Stage-2 translation hardware is fed by:
+
+- A secure IPA when the SP EL1&0 Stage-1 MMU is disabled.
+- One of secure or non-secure IPA when the secure EL1&0 Stage-1 MMU is enabled.
+
+``VTCR_EL2`` and ``VSTCR_EL2`` provide configuration bits for controlling the
+NS/S IPA translations. The following controls are set up:
+``VSTCR_EL2.SW = 0`` , ``VSTCR_EL2.SA = 0``, ``VTCR_EL2.NSW = 0``,
+``VTCR_EL2.NSA = 1``:
+
+- Stage-2 translations for the NS IPA space access the NS PA space.
+- Stage-2 translation table walks for the NS IPA space are to the secure PA space.
+
+Secure and non-secure IPA regions (rooted to by ``VTTBR_EL2`` and ``VSTTBR_EL2``)
+use the same set of Stage-2 page tables within a SP.
+
+The ``VTCR_EL2/VSTCR_EL2/VTTBR_EL2/VSTTBR_EL2`` virtual address space
+configuration is made part of a vCPU context.
+
+For S-EL0 partitions with VHE enabled, a single secure EL2&0 Stage-1 translation
+regime is used for both Hafnium and the partition.
+
+Schedule modes and SP Call chains
+---------------------------------
+
+An SP execution context is said to be in SPMC scheduled mode if CPU cycles are
+allocated to it by SPMC. Correspondingly, an SP execution context is said to be
+in Normal world scheduled mode if CPU cycles are allocated by the normal world.
+
+A call chain represents all SPs in a sequence of invocations of a direct message
+request. When execution on a PE is in the secure state, only a single call chain
+that runs in the Normal World scheduled mode can exist. FF-A v1.1 spec allows
+any number of call chains to run in the SPMC scheduled mode but the Hafnium
+SPMC restricts the number of call chains in SPMC scheduled mode to only one for
+keeping the implementation simple.
+
+Partition runtime models
+------------------------
+
+The runtime model of an endpoint describes the transitions permitted for an
+execution context between various states. These are the four partition runtime
+models supported (refer to `[1]`_ section 7):
+
+ - RTM_FFA_RUN: runtime model presented to an execution context that is
+ allocated CPU cycles through FFA_RUN interface.
+ - RTM_FFA_DIR_REQ: runtime model presented to an execution context that is
+ allocated CPU cycles through FFA_MSG_SEND_DIRECT_REQ interface.
+ - RTM_SEC_INTERRUPT: runtime model presented to an execution context that is
+ allocated CPU cycles by SPMC to handle a secure interrupt.
+ - RTM_SP_INIT: runtime model presented to an execution context that is
+ allocated CPU cycles by SPMC to initialize its state.
+
+If an endpoint execution context attempts to make an invalid transition or a
+valid transition that could lead to a loop in the call chain, SPMC denies the
+transition with the help of above runtime models.
+
+Interrupt management
+--------------------
+
+GIC ownership
+~~~~~~~~~~~~~
+
+The SPMC owns the GIC configuration. Secure and non-secure interrupts are
+trapped at S-EL2. The SPMC manages interrupt resources and allocates interrupt
+IDs based on SP manifests. The SPMC acknowledges physical interrupts and injects
+virtual interrupts by setting the use of vIRQ/vFIQ bits before resuming a SP.
+
+Abbreviations:
+
+ - NS-Int: A non-secure physical interrupt. It requires a switch to the normal
+ world to be handled if it triggers while execution is in secure world.
+ - Other S-Int: A secure physical interrupt targeted to an SP different from
+ the one that is currently running.
+ - Self S-Int: A secure physical interrupt targeted to the SP that is currently
+ running.
+
+Non-secure interrupt handling
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section documents the actions supported in SPMC in response to a non-secure
+interrupt as per the guidance provided by FF-A v1.1 EAC0 specification.
+An SP specifies one of the following actions in its partition manifest:
+
+ - Non-secure interrupt is signaled.
+ - Non-secure interrupt is signaled after a managed exit.
+ - Non-secure interrupt is queued.
+
+An SP execution context in a call chain could specify a less permissive action
+than subsequent SP execution contexts in the same call chain. The less
+permissive action takes precedence over the more permissive actions specified
+by the subsequent execution contexts. Please refer to FF-A v1.1 EAC0 section
+8.3.1 for further explanation.
+
+Secure interrupt handling
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section documents the support implemented for secure interrupt handling in
+SPMC as per the guidance provided by FF-A v1.1 EAC0 specification.
+The following assumptions are made about the system configuration:
+
+ - In the current implementation, S-EL1 SPs are expected to use the para
+ virtualized ABIs for interrupt management rather than accessing the virtual
+ GIC interface.
+ - Unless explicitly stated otherwise, this support is applicable only for
+ S-EL1 SPs managed by SPMC.
+ - Secure interrupts are configured as G1S or G0 interrupts.
+ - All physical interrupts are routed to SPMC when running a secure partition
+ execution context.
+ - All endpoints with multiple execution contexts have their contexts pinned
+ to corresponding CPUs. Hence, a secure virtual interrupt cannot be signaled
+ to a target vCPU that is currently running or blocked on a different
+ physical CPU.
+
+A physical secure interrupt could trigger while CPU is executing in normal world
+or secure world.
+The action of SPMC for a secure interrupt depends on: the state of the target
+execution context of the SP that is responsible for handling the interrupt;
+whether the interrupt triggered while execution was in normal world or secure
+world.
+
+Secure interrupt signaling mechanisms
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Signaling refers to the mechanisms used by SPMC to indicate to the SP execution
+context that it has a pending virtual interrupt and to further run the SP
+execution context, such that it can handle the virtual interrupt. SPMC uses
+either the FFA_INTERRUPT interface with ERET conduit or vIRQ signal for signaling
+to S-EL1 SPs. When normal world execution is preempted by a secure interrupt,
+the SPMD uses the FFA_INTERRUPT ABI with ERET conduit to signal interrupt to SPMC
+running in S-EL2.
+
++-----------+---------+---------------+---------------------------------------+
+| SP State | Conduit | Interface and | Description |
+| | | parameters | |
++-----------+---------+---------------+---------------------------------------+
+| WAITING | ERET, | FFA_INTERRUPT,| SPMC signals to SP the ID of pending |
+| | vIRQ | Interrupt ID | interrupt. It pends vIRQ signal and |
+| | | | resumes execution context of SP |
+| | | | through ERET. |
++-----------+---------+---------------+---------------------------------------+
+| BLOCKED | ERET, | FFA_INTERRUPT | SPMC signals to SP that an interrupt |
+| | vIRQ | | is pending. It pends vIRQ signal and |
+| | | | resumes execution context of SP |
+| | | | through ERET. |
++-----------+---------+---------------+---------------------------------------+
+| PREEMPTED | vIRQ | NA | SPMC pends the vIRQ signal but does |
+| | | | not resume execution context of SP. |
++-----------+---------+---------------+---------------------------------------+
+| RUNNING | ERET, | NA | SPMC pends the vIRQ signal and resumes|
+| | vIRQ | | execution context of SP through ERET. |
++-----------+---------+---------------+---------------------------------------+
+
+Secure interrupt completion mechanisms
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A SP signals secure interrupt handling completion to the SPMC through the
+following mechanisms:
+
+ - ``FFA_MSG_WAIT`` ABI if it was in WAITING state.
+ - ``FFA_RUN`` ABI if its was in BLOCKED state.
+
+This is a remnant of SPMC implementation based on the FF-A v1.0 specification.
+In the current implementation, S-EL1 SPs use the para-virtualized HVC interface
+implemented by SPMC to perform priority drop and interrupt deactivation (SPMC
+configures EOImode = 0, i.e. priority drop and deactivation are done together).
+The SPMC performs checks to deny the state transition upon invocation of
+either FFA_MSG_WAIT or FFA_RUN interface if the SP didn't perform the
+deactivation of the secure virtual interrupt.
+
+If the current SP execution context was preempted by a secure interrupt to be
+handled by execution context of target SP, SPMC resumes current SP after signal
+completion by target SP execution context.
+
+Actions for a secure interrupt triggered while execution is in normal world
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
++-------------------+----------+-----------------------------------------------+
+| State of target | Action | Description |
+| execution context | | |
++-------------------+----------+-----------------------------------------------+
+| WAITING | Signaled | This starts a new call chain in SPMC scheduled|
+| | | mode. |
++-------------------+----------+-----------------------------------------------+
+| PREEMPTED | Queued | The target execution must have been preempted |
+| | | by a non-secure interrupt. SPMC queues the |
+| | | secure virtual interrupt now. It is signaled |
+| | | when the target execution context next enters |
+| | | the RUNNING state. |
++-------------------+----------+-----------------------------------------------+
+| BLOCKED, RUNNING | NA | The target execution context is blocked or |
+| | | running on a different CPU. This is not |
+| | | supported by current SPMC implementation and |
+| | | execution hits panic. |
++-------------------+----------+-----------------------------------------------+
+
+If normal world execution was preempted by a secure interrupt, SPMC uses
+FFA_NORMAL_WORLD_RESUME ABI to indicate completion of secure interrupt handling
+and further returns execution to normal world.
+
+The following figure describes interrupt handling flow when a secure interrupt
+triggers while execution is in normal world:
+
+.. image:: ../resources/diagrams/ffa-secure-interrupt-handling-nwd.png
+
+A brief description of the events:
+
+ - 1) Secure interrupt triggers while normal world is running.
+ - 2) FIQ gets trapped to EL3.
+ - 3) SPMD signals secure interrupt to SPMC at S-EL2 using FFA_INTERRUPT ABI.
+ - 4) SPMC identifies target vCPU of SP and injects virtual interrupt (pends
+ vIRQ).
+ - 5) Assuming SP1 vCPU is in WAITING state, SPMC signals virtual interrupt
+ using FFA_INTERRUPT with interrupt id as an argument and resumes the SP1
+ vCPU using ERET in SPMC scheduled mode.
+ - 6) Execution traps to vIRQ handler in SP1 provided that the virtual
+ interrupt is not masked i.e., PSTATE.I = 0
+ - 7) SP1 queries for the pending virtual interrupt id using a paravirtualized
+ HVC call. SPMC clears the pending virtual interrupt state management
+ and returns the pending virtual interrupt id.
+ - 8) SP1 services the virtual interrupt and invokes the paravirtualized
+ de-activation HVC call. SPMC de-activates the physical interrupt,
+ clears the fields tracking the secure interrupt and resumes SP1 vCPU.
+ - 9) SP1 performs secure interrupt completion through FFA_MSG_WAIT ABI.
+ - 10) SPMC returns control to EL3 using FFA_NORMAL_WORLD_RESUME.
+ - 11) EL3 resumes normal world execution.
+
+Actions for a secure interrupt triggered while execution is in secure world
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
++-------------------+----------+------------------------------------------------+
+| State of target | Action | Description |
+| execution context | | |
++-------------------+----------+------------------------------------------------+
+| WAITING | Signaled | This starts a new call chain in SPMC scheduled |
+| | | mode. |
++-------------------+----------+------------------------------------------------+
+| PREEMPTED by Self | Signaled | The target execution context reenters the |
+| S-Int | | RUNNING state to handle the secure virtual |
+| | | interrupt. |
++-------------------+----------+------------------------------------------------+
+| PREEMPTED by | Queued | SPMC queues the secure virtual interrupt now. |
+| NS-Int | | It is signaled when the target execution |
+| | | context next enters the RUNNING state. |
++-------------------+----------+------------------------------------------------+
+| BLOCKED | Signaled | Both preempted and target execution contexts |
+| | | must have been part of the Normal world |
+| | | scheduled call chain. Refer scenario 1 of |
+| | | Table 8.4 in the FF-A v1.1 EAC0 spec. |
++-------------------+----------+------------------------------------------------+
+| RUNNING | NA | The target execution context is running on a |
+| | | different CPU. This scenario is not supported |
+| | | by current SPMC implementation and execution |
+| | | hits panic. |
++-------------------+----------+------------------------------------------------+
+
+The following figure describes interrupt handling flow when a secure interrupt
+triggers while execution is in secure world. We assume OS kernel sends a direct
+request message to SP1. Further, SP1 sends a direct request message to SP2. SP1
+enters BLOCKED state and SPMC resumes SP2.
+
+.. image:: ../resources/diagrams/ffa-secure-interrupt-handling-swd.png
+
+A brief description of the events:
+
+ - 1) Secure interrupt triggers while SP2 is running.
+ - 2) SP2 gets preempted and execution traps to SPMC as IRQ.
+ - 3) SPMC finds the target vCPU of secure partition responsible for handling
+ this secure interrupt. In this scenario, it is SP1.
+ - 4) SPMC pends vIRQ for SP1 and signals through FFA_INTERRUPT interface.
+ SPMC further resumes SP1 through ERET conduit. Note that SP1 remains in
+ Normal world schedule mode.
+ - 6) Execution traps to vIRQ handler in SP1 provided that the virtual
+ interrupt is not masked i.e., PSTATE.I = 0
+ - 7) SP1 queries for the pending virtual interrupt id using a paravirtualized
+ HVC call. SPMC clears the pending virtual interrupt state management
+ and returns the pending virtual interrupt id.
+ - 8) SP1 services the virtual interrupt and invokes the paravirtualized
+ de-activation HVC call. SPMC de-activates the physical interrupt and
+ clears the fields tracking the secure interrupt and resumes SP1 vCPU.
+ - 9) Since SP1 direct request completed with FFA_INTERRUPT, it resumes the
+ direct request to SP2 by invoking FFA_RUN.
+ - 9) SPMC resumes the pre-empted vCPU of SP2.
+
+Power management
+----------------
+
+In platforms with or without secure virtualization:
+
+- The NWd owns the platform PM policy.
+- The Hypervisor or OS kernel is the component initiating PSCI service calls.
+- The EL3 PSCI library is in charge of the PM coordination and control
+ (eventually writing to platform registers).
+- While coordinating PM events, the PSCI library calls backs into the Secure
+ Payload Dispatcher for events the latter has statically registered to.
+
+When using the SPMD as a Secure Payload Dispatcher:
+
+- A power management event is relayed through the SPD hook to the SPMC.
+- In the current implementation only cpu on (svc_on_finish) and cpu off
+ (svc_off) hooks are registered.
+- The behavior for the cpu on event is described in `Secondary cores boot-up`_.
+ The SPMC is entered through its secondary physical core entry point.
+- The cpu off event occurs when the NWd calls PSCI_CPU_OFF. The PM event is
+ signaled to the SPMC through a power management framework message.
+ It consists in a SPMD-to-SPMC direct request/response (`SPMC-SPMD direct
+ requests/responses`_) conveying the event details and SPMC response.
+ The SPMD performs a synchronous entry into the SPMC. The SPMC is entered and
+ updates its internal state to reflect the physical core is being turned off.
+ In the current implementation no SP is resumed as a consequence. This behavior
+ ensures a minimal support for CPU hotplug e.g. when initiated by the NWd linux
+ userspace.
+
+Arm architecture extensions for security hardening
+==================================================
+
+Hafnium supports the following architecture extensions for security hardening:
+
+- Pointer authentication (FEAT_PAuth): the extension permits detection of forged
+ pointers used by ROP type of attacks through the signing of the pointer
+ value. Hafnium is built with the compiler branch protection option to permit
+ generation of a pointer authentication code for return addresses (pointer
+ authentication for instructions). The APIA key is used while Hafnium runs.
+ A random key is generated at boot time and restored upon entry into Hafnium
+ at run-time. APIA and other keys (APIB, APDA, APDB, APGA) are saved/restored
+ in vCPU contexts permitting to enable pointer authentication in VMs/SPs.
+- Branch Target Identification (FEAT_BTI): the extension permits detection of
+ unexpected indirect branches used by JOP type of attacks. Hafnium is built
+ with the compiler branch protection option, inserting land pads at function
+ prologues that are reached by indirect branch instructions (BR/BLR).
+ Hafnium code pages are marked as guarded in the EL2 Stage-1 MMU descriptors
+ such that an indirect branch must always target a landpad. A fault is
+ triggered otherwise. VMs/SPs can (independently) mark their code pages as
+ guarded in the EL1&0 Stage-1 translation regime.
+- Memory Tagging Extension (FEAT_MTE): the option permits detection of out of
+ bound memory array accesses or re-use of an already freed memory region.
+ Hafnium enables the compiler option permitting to leverage MTE stack tagging
+ applied to core stacks. Core stacks are marked as normal tagged memory in the
+ EL2 Stage-1 translation regime. A synchronous data abort is generated upon tag
+ check failure on load/stores. A random seed is generated at boot time and
+ restored upon entry into Hafnium. MTE system registers are saved/restored in
+ vCPU contexts permitting MTE usage from VMs/SPs.
+
+SMMUv3 support in Hafnium
+=========================
+
+An SMMU is analogous to an MMU in a CPU. It performs address translations for
+Direct Memory Access (DMA) requests from system I/O devices.
+The responsibilities of an SMMU include:
+
+- Translation: Incoming DMA requests are translated from bus address space to
+ system physical address space using translation tables compliant to
+ Armv8/Armv7 VMSA descriptor format.
+- Protection: An I/O device can be prohibited from read, write access to a
+ memory region or allowed.
+- Isolation: Traffic from each individial device can be independently managed.
+ The devices are differentiated from each other using unique translation
+ tables.
+
+The following diagram illustrates a typical SMMU IP integrated in a SoC with
+several I/O devices along with Interconnect and Memory system.
+
+.. image:: ../resources/diagrams/MMU-600.png
+
+SMMU has several versions including SMMUv1, SMMUv2 and SMMUv3. Hafnium provides
+support for SMMUv3 driver in both normal and secure world. A brief introduction
+of SMMUv3 functionality and the corresponding software support in Hafnium is
+provided here.
+
+SMMUv3 features
+---------------
+
+- SMMUv3 provides Stage1, Stage2 translation as well as nested (Stage1 + Stage2)
+ translation support. It can either bypass or abort incoming translations as
+ well.
+- Traffic (memory transactions) from each upstream I/O peripheral device,
+ referred to as Stream, can be independently managed using a combination of
+ several memory based configuration structures. This allows the SMMUv3 to
+ support a large number of streams with each stream assigned to a unique
+ translation context.
+- Support for Armv8.1 VMSA where the SMMU shares the translation tables with
+ a Processing Element. AArch32(LPAE) and AArch64 translation table format
+ are supported by SMMUv3.
+- SMMUv3 offers non-secure stream support with secure stream support being
+ optional. Logically, SMMUv3 behaves as if there is an indepdendent SMMU
+ instance for secure and non-secure stream support.
+- It also supports sub-streams to differentiate traffic from a virtualized
+ peripheral associated with a VM/SP.
+- Additionally, SMMUv3.2 provides support for PEs implementing Armv8.4-A
+ extensions. Consequently, SPM depends on Secure EL2 support in SMMUv3.2
+ for providing Secure Stage2 translation support to upstream peripheral
+ devices.
+
+SMMUv3 Programming Interfaces
+-----------------------------
+
+SMMUv3 has three software interfaces that are used by the Hafnium driver to
+configure the behaviour of SMMUv3 and manage the streams.
+
+- Memory based data strutures that provide unique translation context for
+ each stream.
+- Memory based circular buffers for command queue and event queue.
+- A large number of SMMU configuration registers that are memory mapped during
+ boot time by Hafnium driver. Except a few registers, all configuration
+ registers have independent secure and non-secure versions to configure the
+ behaviour of SMMUv3 for translation of secure and non-secure streams
+ respectively.
+
+Peripheral device manifest
+--------------------------
+
+Currently, SMMUv3 driver in Hafnium only supports dependent peripheral devices.
+These devices are dependent on PE endpoint to initiate and receive memory
+management transactions on their behalf. The acccess to the MMIO regions of
+any such device is assigned to the endpoint during boot. Moreover, SMMUv3 driver
+uses the same stage 2 translations for the device as those used by partition
+manager on behalf of the PE endpoint. This ensures that the peripheral device
+has the same visibility of the physical address space as the endpoint. The
+device node of the corresponding partition manifest (refer to `[1]`_ section 3.2
+) must specify these additional properties for each peripheral device in the
+system :
+
+- smmu-id: This field helps to identify the SMMU instance that this device is
+ upstream of.
+- stream-ids: List of stream IDs assigned to this device.
+
+.. code:: shell
+
+ smmuv3-testengine {
+ base-address = <0x00000000 0x2bfe0000>;
+ pages-count = <32>;
+ attributes = <0x3>;
+ smmu-id = <0>;
+ stream-ids = <0x0 0x1>;
+ interrupts = <0x2 0x3>, <0x4 0x5>;
+ exclusive-access;
+ };
+
+SMMUv3 driver limitations
+-------------------------
+
+The primary design goal for the Hafnium SMMU driver is to support secure
+streams.
+
+- Currently, the driver only supports Stage2 translations. No support for
+ Stage1 or nested translations.
+- Supports only AArch64 translation format.
+- No support for features such as PCI Express (PASIDs, ATS, PRI), MSI, RAS,
+ Fault handling, Performance Monitor Extensions, Event Handling, MPAM.
+- No support for independent peripheral devices.
+
+S-EL0 Partition support
+=======================
+The SPMC (Hafnium) has limited capability to run S-EL0 FF-A partitions using
+FEAT_VHE (mandatory with ARMv8.1 in non-secure state, and in secure world
+with ARMv8.4 and FEAT_SEL2).
+
+S-EL0 partitions are useful for simple partitions that don't require full
+Trusted OS functionality. It is also useful to reduce jitter and cycle
+stealing from normal world since they are more lightweight than VMs.
+
+S-EL0 partitions are presented, loaded and initialized the same as S-EL1 VMs by
+the SPMC. They are differentiated primarily by the 'exception-level' property
+and the 'execution-ctx-count' property in the SP manifest. They are host apps
+under the single EL2&0 Stage-1 translation regime controlled by the SPMC and
+call into the SPMC through SVCs as opposed to HVCs and SMCs. These partitions
+can use FF-A defined services (FFA_MEM_PERM_*) to update or change permissions
+for memory regions.
+
+S-EL0 partitions are required by the FF-A specification to be UP endpoints,
+capable of migrating, and the SPMC enforces this requirement. The SPMC allows
+a S-EL0 partition to accept a direct message from secure world and normal world,
+and generate direct responses to them.
+All S-EL0 partitions must use AArch64. AArch32 S-EL0 partitions are not supported.
+
+Memory sharing, indirect messaging, and notifications functionality with S-EL0
+partitions is supported.
+
+Interrupt handling is not supported with S-EL0 partitions and is work in
+progress.
+
+References
+==========
+
+.. _[1]:
+
+[1] `Arm Firmware Framework for Arm A-profile <https://developer.arm.com/docs/den0077/latest>`__
+
+.. _[2]:
+
+[2] :ref:`Secure Partition Manager using MM interface<Secure Partition Manager (MM)>`
+
+.. _[3]:
+
+[3] `Trusted Boot Board Requirements
+Client <https://developer.arm.com/documentation/den0006/d/>`__
+
+.. _[4]:
+
+[4] https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/lib/el3_runtime/aarch64/context.S#n45
+
+.. _[5]:
+
+[5] https://git.trustedfirmware.org/TF-A/tf-a-tests.git/tree/spm/cactus/plat/arm/fvp/fdts/cactus.dts
+
+.. _[6]:
+
+[6] https://trustedfirmware-a.readthedocs.io/en/latest/components/ffa-manifest-binding.html
+
+.. _[7]:
+
+[7] https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
+
+.. _[8]:
+
+[8] https://lists.trustedfirmware.org/archives/list/tf-a@lists.trustedfirmware.org/thread/CFQFGU6H2D5GZYMUYGTGUSXIU3OYZP6U/
+
+.. _[9]:
+
+[9] https://trustedfirmware-a.readthedocs.io/en/latest/design/firmware-design.html#dynamic-configuration-during-cold-boot
+
+--------------
+
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
diff --git a/docs/components/spd/index.rst b/docs/components/spd/index.rst
new file mode 100644
index 0000000..6857806
--- /dev/null
+++ b/docs/components/spd/index.rst
@@ -0,0 +1,11 @@
+Secure Payload Dispatcher (SPD)
+===============================
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents
+
+ optee-dispatcher
+ tlk-dispatcher
+ trusty-dispatcher
+ pnc-dispatcher
diff --git a/docs/components/spd/optee-dispatcher.rst b/docs/components/spd/optee-dispatcher.rst
new file mode 100644
index 0000000..63baccc
--- /dev/null
+++ b/docs/components/spd/optee-dispatcher.rst
@@ -0,0 +1,14 @@
+OP-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
diff --git a/docs/components/spd/pnc-dispatcher.rst b/docs/components/spd/pnc-dispatcher.rst
new file mode 100644
index 0000000..5be2fc7
--- /dev/null
+++ b/docs/components/spd/pnc-dispatcher.rst
@@ -0,0 +1,10 @@
+ProvenCore Dispatcher
+=====================
+
+ProvenCore dispatcher (PnC-D) adds support for ProvenRun's ProvenCore micro-kernel
+to work with Trusted Firmware-A (TF-A).
+
+ProvenCore is a secure OS developed by ProvenRun S.A.S. using deductive formal methods.
+
+Once a BL32 is ready, PnC-D can be included in the image by adding "SPD=pncd"
+to the build command.
diff --git a/docs/components/spd/tlk-dispatcher.rst b/docs/components/spd/tlk-dispatcher.rst
new file mode 100644
index 0000000..a6c658c
--- /dev/null
+++ b/docs/components/spd/tlk-dispatcher.rst
@@ -0,0 +1,76 @@
+Trusted 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
diff --git a/docs/components/spd/trusty-dispatcher.rst b/docs/components/spd/trusty-dispatcher.rst
new file mode 100644
index 0000000..a3cb829
--- /dev/null
+++ b/docs/components/spd/trusty-dispatcher.rst
@@ -0,0 +1,32 @@
+Trusty 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.
diff --git a/docs/components/xlat-tables-lib-v2-design.rst b/docs/components/xlat-tables-lib-v2-design.rst
new file mode 100644
index 0000000..cac32f5
--- /dev/null
+++ b/docs/components/xlat-tables-lib-v2-design.rst
@@ -0,0 +1,442 @@
+Translation (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
+ upon 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, version 2 and MPU libraries
+--------------------------------------------
+
+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. ``lib/xlat_mpu``, which configures Arm's MPU
+equivalently, is also addressed here. The ``lib/xlat_mpu`` is experimental,
+meaning that its API may change. It currently strives for consistency and
+code-reuse with xlat_tables_v2. Future versions may be more MPU-specific (e.g.,
+removing all mentions of virtual addresses). Although potential bug fixes will
+be applied to all versions of the xlat_* libs, future feature enhancements will
+focus on version 2 and might not be back-ported to version 1 and MPU versions.
+Therefore, it is recommended to use version 2, especially for new platform
+ports (unless the platform uses an MPU).
+
+However, please note that version 2 and the MPU version are 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, unless stated otherwise.
+
+
+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).
+
+The MPU library also uses ``struct mmap_region`` to specify translations, but
+the MPU's translations are limited to specification of valid addresses and
+access permissions. If the requested virtual and physical addresses mismatch
+the system will panic. Being register-based for deterministic memory-reference
+timing, the MPU hardware does not involve memory-resident translation tables.
+
+Currently, the MPU library is also limited to MPU translation at EL2 with no
+MMU translation at other ELs. These limitations, however, are expected to be
+overcome in future library versions.
+
+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. Using ``MAP_REGION_FLAT()`` only
+to define regions for the MPU library is strongly recommended.
+
+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.
+
+This mapping algorithm does not apply to the MPU library, since the MPU hardware
+directly maps regions by "base" and "limit" (bottom and top) addresses.
+
+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.
+
+Regarding enabling and disabling memory management, for the MPU library, to
+reduce confusion, calls to enable or disable the MPU use ``mpu`` in their names
+in place of ``mmu``. For example, the ``enable_mmu_el2()`` call is changed to
+``enable_mpu_el2()``.
+
+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-2021, Arm Limited and Contributors. All rights reserved.*
+
+.. |Alignment Example| image:: ../resources/diagrams/xlat_align.png
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 0000000..371632a
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,95 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2019-2021, 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 = ['myst_parser', '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 = ['.md', '.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 = "en"
+
+# 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 .
+# Don't try to build the venv in case it's placed with the sources
+exclude_patterns = [".env", "env", ".venv", "venv"]
+
+# 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
+}
+
+# Path to _static directory
+html_static_path = ['_static']
+
+# Path to css file relative to html_static_path
+html_css_files = [
+ 'css/custom.css',
+]
+
+# -- Options for autosectionlabel --------------------------------------------
+
+# Only generate automatic section labels for document titles
+autosectionlabel_maxdepth = 1
+
+# -- Options for plantuml ----------------------------------------------------
+
+plantuml_output_format = 'svg_img'
diff --git a/docs/design/alt-boot-flows.rst b/docs/design/alt-boot-flows.rst
new file mode 100644
index 0000000..b44c061
--- /dev/null
+++ b/docs/design/alt-boot-flows.rst
@@ -0,0 +1,84 @@
+Alternative Boot Flows
+======================
+
+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.
+
+.. _alt_boot_flows_el3_payload:
+
+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.
+
+
+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
+
+--------------
+
+*Copyright (c) 2019, Arm Limited. All rights reserved.*
diff --git a/docs/design/auth-framework.rst b/docs/design/auth-framework.rst
new file mode 100644
index 0000000..6913e66
--- /dev/null
+++ b/docs/design/auth-framework.rst
@@ -0,0 +1,980 @@
+Authentication 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
+~~~~~~~~~~~~
+
+CoT specific to BL1 and BL2 can be found in ``drivers/auth/tbbr/tbbr_cot_bl1.c``
+and ``drivers/auth/tbbr/tbbr_cot_bl2.c`` respectively. The common CoT used across
+BL1 and BL2 can be found in ``drivers/auth/tbbr/tbbr_cot_common.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 ``trusted_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
+``trusted_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 ``trusted_world_pk``. Once this certificate
+has been authenticated, we have to extract the BL31 public key, stored in the
+extension specified by ``soc_fw_content_pk``. This key will be copied to the
+``content_pk_buf`` 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 ``soc_fw_content_pk`` as public key.
+After authentication, we need to extract the BL31 hash, stored in the extension
+specified by ``soc_fw_hash``. This hash will be copied to the
+``soc_fw_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, ``soc_fw_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
+four 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);
+ int auth_decrypt(enum crypto_dec_algo dec_algo, void *data_ptr,
+ size_t len, const void *key, unsigned int key_len,
+ unsigned int key_flags, const void *iv,
+ unsigned int iv_len, const void *tag,
+ unsigned int tag_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.
+
+- ``TF_MBEDTLS_USE_AES_GCM`` enables the authenticated decryption support based
+ on AES-GCM algorithm. Valid values are 0 and 1.
+
+.. 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-2020, 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
diff --git a/docs/design/cpu-specific-build-macros.rst b/docs/design/cpu-specific-build-macros.rst
new file mode 100644
index 0000000..55e265c
--- /dev/null
+++ b/docs/design/cpu-specific-build-macros.rst
@@ -0,0 +1,742 @@
+Arm 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.
+
+- ``WORKAROUND_CVE_2022_23960``: Enables mitigation for `CVE-2022-23960`_.
+ This build option should be set to 1 if the target platform contains at
+ least 1 CPU that requires this mitigation. Defaults to 1.
+
+.. _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_<Processor name>_<ID>``, 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.
+
+- ``ERRATA_A53_1530924``: This applies errata 1530924 workaround to all
+ revisions of Cortex-A53 CPU.
+
+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.
+
+- ``ERRATA_A55_1530923``: This applies errata 1530923 workaround to all
+ revisions of Cortex-A55 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.
+
+- ``ERRATA_A57_1319537``: This applies errata 1319537 workaround to all
+ revisions of Cortex-A57 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.
+
+- ``ERRATA_A72_1319367``: This applies errata 1319367 workaround to all
+ revisions of Cortex-A72 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.
+
+- ``ERRATA_A76_1791580``: This applies errata 1791580 workaround to Cortex-A76
+ CPU. This needs to be enabled only for revision <= r4p0 of the CPU.
+
+- ``ERRATA_A76_1165522``: This applies errata 1165522 workaround to all
+ revisions of Cortex-A76 CPU. This errata is fixed in r3p0 but due to
+ limitation of errata framework this errata is applied to all revisions
+ of Cortex-A76 CPU.
+
+- ``ERRATA_A76_1868343``: This applies errata 1868343 workaround to Cortex-A76
+ CPU. This needs to be enabled only for revision <= r4p0 of the CPU.
+
+- ``ERRATA_A76_1946160``: This applies errata 1946160 workaround to Cortex-A76
+ CPU. This needs to be enabled only for revisions r3p0 - r4p1 of the CPU.
+
+- ``ERRATA_A76_2743102``: This applies errata 2743102 workaround to Cortex-A76
+ CPU. This needs to be enabled for all revisions <= r4p1 of the CPU and is
+ still open.
+
+For Cortex-A77, the following errata build flags are defined :
+
+- ``ERRATA_A77_1508412``: This applies errata 1508412 workaround to Cortex-A77
+ CPU. This needs to be enabled only for revision <= r1p0 of the CPU.
+
+- ``ERRATA_A77_1925769``: This applies errata 1925769 workaround to Cortex-A77
+ CPU. This needs to be enabled only for revision <= r1p1 of the CPU.
+
+- ``ERRATA_A77_1946167``: This applies errata 1946167 workaround to Cortex-A77
+ CPU. This needs to be enabled only for revision <= r1p1 of the CPU.
+
+- ``ERRATA_A77_1791578``: This applies errata 1791578 workaround to Cortex-A77
+ CPU. This needs to be enabled for r0p0, r1p0, and r1p1, it is still open.
+
+- ``ERRATA_A77_2356587``: This applies errata 2356587 workaround to Cortex-A77
+ CPU. This needs to be enabled for r0p0, r1p0, and r1p1, it is still open.
+
+ - ``ERRATA_A77_1800714``: This applies errata 1800714 workaround to Cortex-A77
+ CPU. This needs to be enabled for revisions <= r1p1 of the CPU.
+
+ - ``ERRATA_A77_2743100``: This applies errata 2743100 workaround to Cortex-A77
+ CPU. This needs to be enabled for r0p0, r1p0, and r1p1, it is still open.
+
+For Cortex-A78, the following errata build flags are defined :
+
+- ``ERRATA_A78_1688305``: This applies errata 1688305 workaround to Cortex-A78
+ CPU. This needs to be enabled only for revision r0p0 - r1p0 of the CPU.
+
+- ``ERRATA_A78_1941498``: This applies errata 1941498 workaround to Cortex-A78
+ CPU. This needs to be enabled for revisions r0p0, r1p0, and r1p1 of the CPU.
+
+- ``ERRATA_A78_1951500``: This applies errata 1951500 workaround to Cortex-A78
+ CPU. This needs to be enabled for revisions r1p0 and r1p1, r0p0 has the same
+ issue but there is no workaround for that revision.
+
+- ``ERRATA_A78_1821534``: This applies errata 1821534 workaround to Cortex-A78
+ CPU. This needs to be enabled for revisions r0p0 and r1p0.
+
+- ``ERRATA_A78_1952683``: This applies errata 1952683 workaround to Cortex-A78
+ CPU. This needs to be enabled for revision r0p0, it is fixed in r1p0.
+
+- ``ERRATA_A78_2132060``: This applies errata 2132060 workaround to Cortex-A78
+ CPU. This needs to be enabled for revisions r0p0, r1p0, r1p1, and r1p2. It
+ is still open.
+
+- ``ERRATA_A78_2242635``: This applies errata 2242635 workaround to Cortex-A78
+ CPU. This needs to be enabled for revisions r1p0, r1p1, and r1p2. The issue
+ is present in r0p0 but there is no workaround. It is still open.
+
+- ``ERRATA_A78_2376745``: This applies errata 2376745 workaround to Cortex-A78
+ CPU. This needs to be enabled for revisions r0p0, r1p0, r1p1, and r1p2, and
+ it is still open.
+
+- ``ERRATA_A78_2395406``: This applies errata 2395406 workaround to Cortex-A78
+ CPU. This needs to be enabled for revisions r0p0, r1p0, r1p1, and r1p2, and
+ it is still open.
+
+For Cortex-A78 AE, the following errata build flags are defined :
+
+- ``ERRATA_A78_AE_1941500`` : This applies errata 1941500 workaround to
+ Cortex-A78 AE CPU. This needs to be enabled for revisions r0p0 and r0p1.
+ This erratum is still open.
+
+- ``ERRATA_A78_AE_1951502`` : This applies errata 1951502 workaround to
+ Cortex-A78 AE CPU. This needs to be enabled for revisions r0p0 and r0p1. This
+ erratum is still open.
+
+- ``ERRATA_A78_AE_2376748`` : This applies errata 2376748 workaround to
+ Cortex-A78 AE CPU. This needs to be enabled for revisions r0p0 and r0p1. This
+ erratum is still open.
+
+- ``ERRATA_A78_AE_2395408`` : This applies errata 2395408 workaround to
+ Cortex-A78 AE CPU. This needs to be enabled for revisions r0p0 and r0p1. This
+ erratum is still open.
+
+For Cortex-A78C, the following errata build flags are defined :
+
+- ``ERRATA_A78C_2132064`` : This applies errata 2132064 workaround to
+ Cortex-A78C CPU. This needs to be enabled for revisions r0p1, r0p2 and
+ it is still open.
+
+- ``ERRATA_A78C_2242638`` : This applies errata 2242638 workaround to
+ Cortex-A78C CPU. This needs to be enabled for revisions r0p1, r0p2 and
+ it is still open.
+
+- ``ERRATA_A78C_2376749`` : This applies errata 2376749 workaround to
+ Cortex-A78C CPU. This needs to be enabled for revisions r0p1 and r0p2. This
+ erratum is still open.
+
+- ``ERRATA_A78C_2395411`` : This applies errata 2395411 workaround to
+ Cortex-A78C CPU. This needs to be enabled for revisions r0p1 and r0p2. This
+ erratum is still open.
+
+For Cortex-X1 CPU, the following errata build flags are defined:
+
+- ``ERRATA_X1_1821534`` : This applies errata 1821534 workaround to Cortex-X1
+ CPU. This needs to be enabled only for revision <= r1p0 of the CPU.
+
+- ``ERRATA_X1_1688305`` : This applies errata 1688305 workaround to Cortex-X1
+ CPU. This needs to be enabled only for revision <= r1p0 of the CPU.
+
+- ``ERRATA_X1_1827429`` : This applies errata 1827429 workaround to Cortex-X1
+ CPU. This needs to be enabled only for revision <= r1p0 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.
+
+- ``ERRATA_N1_1868343``: This applies errata 1868343 workaround to Neoverse-N1
+ CPU. This needs to be enabled only for revision <= r4p0 of the CPU.
+
+- ``ERRATA_N1_1946160``: This applies errata 1946160 workaround to Neoverse-N1
+ CPU. This needs to be enabled for revisions r3p0, r3p1, r4p0, and r4p1, for
+ revisions r0p0, r1p0, and r2p0 there is no workaround.
+
+- ``ERRATA_N1_2743102``: This applies errata 2743102 workaround to Neoverse-N1
+ CPU. This needs to be enabled for all revisions <= r4p1 of the CPU and is
+ still open.
+
+For Neoverse V1, the following errata build flags are defined :
+
+- ``ERRATA_V1_1618635``: This applies errata 1618635 workaround to Neoverse-V1
+ CPU. This needs to be enabled for revision r0p0 of the CPU, it is fixed in
+ r1p0.
+
+- ``ERRATA_V1_1774420``: This applies errata 1774420 workaround to Neoverse-V1
+ CPU. This needs to be enabled only for revisions r0p0 and r1p0, it is fixed
+ in r1p1.
+
+- ``ERRATA_V1_1791573``: This applies errata 1791573 workaround to Neoverse-V1
+ CPU. This needs to be enabled only for revisions r0p0 and r1p0, it is fixed
+ in r1p1.
+
+- ``ERRATA_V1_1852267``: This applies errata 1852267 workaround to Neoverse-V1
+ CPU. This needs to be enabled only for revisions r0p0 and r1p0, it is fixed
+ in r1p1.
+
+- ``ERRATA_V1_1925756``: This applies errata 1925756 workaround to Neoverse-V1
+ CPU. This needs to be enabled for r0p0, r1p0, and r1p1, it is still open.
+
+- ``ERRATA_V1_1940577``: This applies errata 1940577 workaround to Neoverse-V1
+ CPU. This needs to be enabled only for revision r1p0 and r1p1 of the
+ CPU.
+
+- ``ERRATA_V1_1966096``: This applies errata 1966096 workaround to Neoverse-V1
+ CPU. This needs to be enabled for revisions r1p0 and r1p1 of the CPU, the
+ issue is present in r0p0 as well but there is no workaround for that
+ revision. It is still open.
+
+- ``ERRATA_V1_2139242``: This applies errata 2139242 workaround to Neoverse-V1
+ CPU. This needs to be enabled for revisions r0p0, r1p0, and r1p1 of the
+ CPU. It is still open.
+
+- ``ERRATA_V1_2108267``: This applies errata 2108267 workaround to Neoverse-V1
+ CPU. This needs to be enabled for revisions r0p0, r1p0, and r1p1 of the CPU.
+ It is still open.
+
+- ``ERRATA_V1_2216392``: This applies errata 2216392 workaround to Neoverse-V1
+ CPU. This needs to be enabled for revisions r1p0 and r1p1 of the CPU, the
+ issue is present in r0p0 as well but there is no workaround for that
+ revision. It is still open.
+
+- ``ERRATA_V1_2294912``: This applies errata 2294912 workaround to Neoverse-V1
+ CPU. This needs to be enabled for revisions r0p0, r1p0, and r1p1 of the CPU.
+
+- ``ERRATA_V1_2372203``: This applies errata 2372203 workaround to Neoverse-V1
+ CPU. This needs to be enabled for revisions r0p0, r1p0 and r1p1 of the CPU.
+ It is still open.
+
+For Cortex-A710, the following errata build flags are defined :
+
+- ``ERRATA_A710_1987031``: This applies errata 1987031 workaround to
+ Cortex-A710 CPU. This needs to be enabled only for revisions r0p0, r1p0 and
+ r2p0 of the CPU. It is still open.
+
+- ``ERRATA_A710_2081180``: This applies errata 2081180 workaround to
+ Cortex-A710 CPU. This needs to be enabled only for revisions r0p0, r1p0 and
+ r2p0 of the CPU. It is still open.
+
+- ``ERRATA_A710_2055002``: This applies errata 2055002 workaround to
+ Cortex-A710 CPU. This needs to be enabled for revisions r1p0, r2p0 of the CPU
+ and is still open.
+
+- ``ERRATA_A710_2017096``: This applies errata 2017096 workaround to
+ Cortex-A710 CPU. This needs to be enabled for revisions r0p0, r1p0 and r2p0
+ of the CPU and is still open.
+
+- ``ERRATA_A710_2083908``: This applies errata 2083908 workaround to
+ Cortex-A710 CPU. This needs to be enabled for revision r2p0 of the CPU and
+ is still open.
+
+- ``ERRATA_A710_2058056``: This applies errata 2058056 workaround to
+ Cortex-A710 CPU. This needs to be enabled for revisions r0p0, r1p0 and r2p0
+ of the CPU and is still open.
+
+- ``ERRATA_A710_2267065``: This applies errata 2267065 workaround to
+ Cortex-A710 CPU. This needs to be enabled for revisions r0p0, r1p0 and r2p0
+ of the CPU and is fixed in r2p1.
+
+- ``ERRATA_A710_2136059``: This applies errata 2136059 workaround to
+ Cortex-A710 CPU. This needs to be enabled for revisions r0p0, r1p0 and r2p0
+ of the CPU and is fixed in r2p1.
+
+- ``ERRATA_A710_2147715``: This applies errata 2147715 workaround to
+ Cortex-A710 CPU. This needs to be enabled for revision r2p0 of the CPU
+ and is fixed in r2p1.
+
+- ``ERRATA_A710_2216384``: This applies errata 2216384 workaround to
+ Cortex-A710 CPU. This needs to be enabled for revisions r0p0, r1p0 and r2p0
+ of the CPU and is fixed in r2p1.
+
+- ``ERRATA_A710_2282622``: This applies errata 2282622 workaround to
+ Cortex-A710 CPU. This needs to be enabled for revisions r0p0, r1p0 and r2p0
+ of the CPU and is fixed in r2p1.
+
+- ``ERRATA_A710_2291219``: This applies errata 2291219 workaround to
+ Cortex-A710 CPU. This needs to be enabled for revisions r0p0, r1p0 and r2p0
+ of the CPU and is fixed in r2p1.
+
+- ``ERRATA_A710_2008768``: This applies errata 2008768 workaround to
+ Cortex-A710 CPU. This needs to be enabled for revisions r0p0, r1p0 and r2p0
+ of the CPU and is fixed in r2p1.
+
+- ``ERRATA_A710_2371105``: This applies errata 2371105 workaround to
+ Cortex-A710 CPU. This needs to be enabled for revisions r0p0, r1p0 and r2p0
+ of the CPU and is fixed in r2p1.
+
+For Neoverse N2, the following errata build flags are defined :
+
+- ``ERRATA_N2_2002655``: This applies errata 2002655 workaround to Neoverse-N2
+ CPU. This needs to be enabled for revision r0p0 of the CPU, it is still open.
+
+- ``ERRATA_N2_2067956``: This applies errata 2067956 workaround to Neoverse-N2
+ CPU. This needs to be enabled for revision r0p0 of the CPU and is still open.
+
+- ``ERRATA_N2_2025414``: This applies errata 2025414 workaround to Neoverse-N2
+ CPU. This needs to be enabled for revision r0p0 of the CPU and is still open.
+
+- ``ERRATA_N2_2189731``: This applies errata 2189731 workaround to Neoverse-N2
+ CPU. This needs to be enabled for revision r0p0 of the CPU and is still open.
+
+- ``ERRATA_N2_2138956``: This applies errata 2138956 workaround to Neoverse-N2
+ CPU. This needs to be enabled for revision r0p0 of the CPU and is still open.
+
+- ``ERRATA_N2_2138953``: This applies errata 2138953 workaround to Neoverse-N2
+ CPU. This needs to be enabled for revision r0p0 of the CPU and is still open.
+
+- ``ERRATA_N2_2242415``: This applies errata 2242415 workaround to Neoverse-N2
+ CPU. This needs to be enabled for revision r0p0 of the CPU and is still open.
+
+- ``ERRATA_N2_2138958``: This applies errata 2138958 workaround to Neoverse-N2
+ CPU. This needs to be enabled for revision r0p0 of the CPU and is still open.
+
+- ``ERRATA_N2_2242400``: This applies errata 2242400 workaround to Neoverse-N2
+ CPU. This needs to be enabled for revision r0p0 of the CPU and is still open.
+
+- ``ERRATA_N2_2280757``: This applies errata 2280757 workaround to Neoverse-N2
+ CPU. This needs to be enabled for revision r0p0 of the CPU and is still open.
+
+- ``ERRATA_N2_2326639``: This applies errata 2326639 workaround to Neoverse-N2
+ CPU. This needs to be enabled for revision r0p0 of the CPU, it is fixed in
+ r0p1.
+
+- ``ERRATA_N2_2376738``: This applies errata 2376738 workaround to Neoverse-N2
+ CPU. This needs to be enabled for revision r0p0 of the CPU, it is fixed in
+ r0p1.
+
+- ``ERRATA_N2_2388450``: This applies errata 2388450 workaround to Neoverse-N2
+ CPU. This needs to be enabled for revision r0p0 of the CPU, it is fixed in
+ r0p1.
+
+For Cortex-X2, the following errata build flags are defined :
+
+- ``ERRATA_X2_2002765``: This applies errata 2002765 workaround to Cortex-X2
+ CPU. This needs to be enabled for revisions r0p0, r1p0, and r2p0 of the CPU,
+ it is still open.
+
+- ``ERRATA_X2_2058056``: This applies errata 2058056 workaround to Cortex-X2
+ CPU. This needs to be enabled for revisions r0p0, r1p0, and r2p0 of the CPU,
+ it is still open.
+
+- ``ERRATA_X2_2083908``: This applies errata 2083908 workaround to Cortex-X2
+ CPU. This needs to be enabled for revision r2p0 of the CPU, it is still open.
+
+- ``ERRATA_X2_2017096``: This applies errata 2017096 workaround to
+ Cortex-X2 CPU. This needs to be enabled only for revisions r0p0, r1p0 and
+ r2p0 of the CPU, it is fixed in r2p1.
+
+- ``ERRATA_X2_2081180``: This applies errata 2081180 workaround to
+ Cortex-X2 CPU. This needs to be enabled only for revisions r0p0, r1p0 and
+ r2p0 of the CPU, it is fixed in r2p1.
+
+- ``ERRATA_X2_2216384``: This applies errata 2216384 workaround to
+ Cortex-X2 CPU. This needs to be enabled only for revisions r0p0, r1p0 and
+ r2p0 of the CPU, it is fixed in r2p1.
+
+- ``ERRATA_X2_2147715``: This applies errata 2147715 workaround to
+ Cortex-X2 CPU. This needs to be enabled only for revision r2p0 of the CPU,
+ it is fixed in r2p1.
+
+- ``ERRATA_X2_2371105``: This applies errata 2371105 workaround to
+ Cortex-X2 CPU. This needs to be enabled for revisions r0p0, r1p0 and r2p0
+ of the CPU and is fixed in r2p1.
+
+For Cortex-X3, the following errata build flags are defined :
+
+- ``ERRATA_X3_2313909``: This applies errata 2313909 workaround to
+ Cortex-X3 CPU. This needs to be enabled only for revisions r0p0 and r1p0
+ of the CPU, it is fixed in r1p1.
+
+For Cortex-A510, the following errata build flags are defined :
+
+- ``ERRATA_A510_1922240``: This applies errata 1922240 workaround to
+ Cortex-A510 CPU. This needs to be enabled only for revision r0p0, it is
+ fixed in r0p1.
+
+- ``ERRATA_A510_2288014``: This applies errata 2288014 workaround to
+ Cortex-A510 CPU. This needs to be enabled only for revisions r0p0, r0p1,
+ r0p2, r0p3 and r1p0, it is fixed in r1p1.
+
+- ``ERRATA_A510_2042739``: This applies errata 2042739 workaround to
+ Cortex-A510 CPU. This needs to be enabled only for revisions r0p0, r0p1 and
+ r0p2, it is fixed in r0p3.
+
+- ``ERRATA_A510_2041909``: This applies errata 2041909 workaround to
+ Cortex-A510 CPU. This needs to be enabled only for revision r0p2 and is fixed
+ in r0p3. The issue is also present in r0p0 and r0p1 but there is no
+ workaround for those revisions.
+
+- ``ERRATA_A510_2250311``: This applies errata 2250311 workaround to
+ Cortex-A510 CPU. This needs to be enabled for revisions r0p0, r0p1, r0p2,
+ r0p3 and r1p0, it is fixed in r1p1. This workaround disables MPMM even if
+ ENABLE_MPMM=1.
+
+- ``ERRATA_A510_2218950``: This applies errata 2218950 workaround to
+ Cortex-A510 CPU. This needs to be enabled for revisions r0p0, r0p1, r0p2,
+ r0p3 and r1p0, it is fixed in r1p1.
+
+- ``ERRATA_A510_2172148``: This applies errata 2172148 workaround to
+ Cortex-A510 CPU. This needs to be enabled for revisions r0p0, r0p1, r0p2,
+ r0p3 and r1p0, it is fixed in r1p1.
+
+- ``ERRATA_A510_2347730``: This applies errata 2347730 workaround to
+ Cortex-A510 CPU. This needs to be enabled for revisions r0p0, r0p1, r0p2,
+ r0p3, r1p0 and r1p1. It is fixed in r1p2.
+
+- ``ERRATA_A510_2371937``: This applies errata 2371937 workaround to
+ Cortex-A510 CPU. This needs to applied for revisions r0p0, r0p1, r0p2,
+ r0p3, r1p0, r1p1, and is fixed in r1p2.
+
+- ``ERRATA_A510_2666669``: This applies errata 2666669 workaround to
+ Cortex-A510 CPU. This needs to applied for revisions r0p0, r0p1, r0p2,
+ r0p3, r1p0, r1p1. It is fixed in r1p2.
+
+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_<ID>``. 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.
+
+- ``ERRATA_DSU_2313941``: This applies errata 2313941 workaround for the
+ affected DSU configurations. This errata applies for those DSUs with
+ revisions r0p0, r1p0, r2p0, r2p1, r3p0, r3p1 and is still open. 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`_.
+
+- ''A57_ENABLE_NON_CACHEABLE_LOAD_FWD'': This flag enables non-cacheable
+ streaming enhancement feature for Cortex-A57 CPUs. Platforms can set
+ this bit only if their memory system meets the requirement that cache
+ line fill requests from the Cortex-A57 processor are atomic. Each
+ Cortex-A57 based platform must make its own decision on whether to use
+ the optimization. This flag is disabled by default.
+
+- ``NEOVERSE_Nx_EXTERNAL_LLC``: This flag indicates that an external last
+ level cache(LLC) is present in the system, and that the DataSource field
+ on the master CHI interface indicates when data is returned from the LLC.
+ This is used to control how the LL_CACHE* PMU events count.
+ Default value is 0 (Disabled).
+
+GIC Errata Workarounds
+----------------------
+- ``GIC600_ERRATA_WA_2384374``: This flag applies part 2 of errata 2384374
+ workaround for the affected GIC600 and GIC600-AE implementations. It applies
+ to implementations of GIC600 and GIC600-AE with revisions less than or equal
+ to r1p6 and r0p2 respectively. If the platform sets GICV3_SUPPORT_GIC600,
+ then this flag is enabled; otherwise, it is 0 (Disabled).
+
+--------------
+
+*Copyright (c) 2014-2022, 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
+.. _CVE-2022-23960: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23960
+.. _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
diff --git a/docs/design/firmware-design.rst b/docs/design/firmware-design.rst
new file mode 100644
index 0000000..84bba18
--- /dev/null
+++ b/docs/design/firmware-design.rst
@@ -0,0 +1,2766 @@
+Firmware 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.
+
+.. note::
+
+ The descriptions in this chapter are for the Arm TrustZone architecture.
+ For changes to the firmware design for the
+ `Arm Confidential Compute Architecture (Arm CCA)`_ please refer to the
+ chapter :ref:`Realm Management Extension (RME)`.
+
+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:
+
+- FW_CONFIG - The firmware configuration file. Holds properties shared across
+ all BLx images.
+ An example is the "dtb-registry" node, which contains the information about
+ the other device tree configurations (load-address, size, image_id).
+- 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,
+
+ - FW_CONFIG is loaded by BL1, then its address is passed in ``arg0`` to BL2.
+ - TB_FW_CONFIG address is retrieved by BL2 from FW_CONFIG device tree.
+ - 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``.
+ - In case of the Arm FVP platform, FW_CONFIG address passed in ``arg1`` to
+ BL31/SP_MIN, and the SOC_FW_CONFIG and HW_CONFIG details are retrieved
+ from FW_CONFIG device tree.
+
+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 setting 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`_ 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
+:ref:`firmware_design_sel1_spd` 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
+ :ref:`firmware_design_sel1_spd` 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:
+
+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. The ``flags`` parameter indicates the security state of the caller
+and the state of the SVE hint bit per the SMCCCv1.3. 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-X7 as needed
+before restoring the stack and CPU state and returning from the original SMC.
+
+Exception Handling Framework
+----------------------------
+
+Please refer to the :ref:`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 = 0x000000002a4a0000
+ x1 = 0x0000000000000001
+ x2 = 0x0000000000000002
+ x3 = 0x0000000000000003
+ x4 = 0x0000000000000004
+ x5 = 0x0000000000000005
+ x6 = 0x0000000000000006
+ x7 = 0x0000000000000007
+ x8 = 0x0000000000000008
+ x9 = 0x0000000000000009
+ x10 = 0x0000000000000010
+ x11 = 0x0000000000000011
+ x12 = 0x0000000000000012
+ x13 = 0x0000000000000013
+ x14 = 0x0000000000000014
+ x15 = 0x0000000000000015
+ x16 = 0x0000000000000016
+ x17 = 0x0000000000000017
+ x18 = 0x0000000000000018
+ x19 = 0x0000000000000019
+ x20 = 0x0000000000000020
+ x21 = 0x0000000000000021
+ x22 = 0x0000000000000022
+ x23 = 0x0000000000000023
+ x24 = 0x0000000000000024
+ x25 = 0x0000000000000025
+ x26 = 0x0000000000000026
+ x27 = 0x0000000000000027
+ x28 = 0x0000000000000028
+ x29 = 0x0000000000000029
+ x30 = 0x0000000088000b78
+ scr_el3 = 0x000000000003073d
+ sctlr_el3 = 0x00000000b0cd183f
+ cptr_el3 = 0x0000000000000000
+ tcr_el3 = 0x000000008080351c
+ daif = 0x00000000000002c0
+ mair_el3 = 0x00000000004404ff
+ spsr_el3 = 0x0000000060000349
+ elr_el3 = 0x0000000088000114
+ ttbr0_el3 = 0x0000000004018201
+ esr_el3 = 0x00000000be000000
+ far_el3 = 0x0000000000000000
+ spsr_el1 = 0x0000000000000000
+ elr_el1 = 0x0000000000000000
+ spsr_abt = 0x0000000000000000
+ spsr_und = 0x0000000000000000
+ spsr_irq = 0x0000000000000000
+ spsr_fiq = 0x0000000000000000
+ sctlr_el1 = 0x0000000030d00800
+ actlr_el1 = 0x0000000000000000
+ cpacr_el1 = 0x0000000000000000
+ csselr_el1 = 0x0000000000000000
+ sp_el1 = 0x0000000000000000
+ esr_el1 = 0x0000000000000000
+ ttbr0_el1 = 0x0000000000000000
+ ttbr1_el1 = 0x0000000000000000
+ mair_el1 = 0x0000000000000000
+ amair_el1 = 0x0000000000000000
+ tcr_el1 = 0x0000000000000000
+ tpidr_el1 = 0x0000000000000000
+ tpidr_el0 = 0x0000000000000000
+ tpidrro_el0 = 0x0000000000000000
+ par_el1 = 0x0000000000000000
+ mpidr_el1 = 0x0000000080000000
+ afsr0_el1 = 0x0000000000000000
+ afsr1_el1 = 0x0000000000000000
+ contextidr_el1 = 0x0000000000000000
+ vbar_el1 = 0x0000000000000000
+ cntp_ctl_el0 = 0x0000000000000000
+ cntp_cval_el0 = 0x0000000000000000
+ cntv_ctl_el0 = 0x0000000000000000
+ cntv_cval_el0 = 0x0000000000000000
+ cntkctl_el1 = 0x0000000000000000
+ sp_el0 = 0x0000000004014940
+ isr_el1 = 0x0000000000000000
+ dacr32_el2 = 0x0000000000000000
+ ifsr32_el2 = 0x0000000000000000
+ icc_hppir0_el1 = 0x00000000000003ff
+ icc_hppir1_el1 = 0x00000000000003ff
+ icc_ctlr_el3 = 0x0000000000080400
+ gicd_ispendr regs (Offsets 0x200-0x278)
+ Offset Value
+ 0x200: 0x0000000000000000
+ 0x208: 0x0000000000000000
+ 0x210: 0x0000000000000000
+ 0x218: 0x0000000000000000
+ 0x220: 0x0000000000000000
+ 0x228: 0x0000000000000000
+ 0x230: 0x0000000000000000
+ 0x238: 0x0000000000000000
+ 0x240: 0x0000000000000000
+ 0x248: 0x0000000000000000
+ 0x250: 0x0000000000000000
+ 0x258: 0x0000000000000000
+ 0x260: 0x0000000000000000
+ 0x268: 0x0000000000000000
+ 0x270: 0x0000000000000000
+ 0x278: 0x0000000000000000
+
+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:
+
+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.
+
+For BL31, a platform can specify an alternate location for NOBITS sections
+(other than immediately following PROGBITS sections) by setting
+``SEPARATE_NOBITS_REGION`` to 1 and defining ``BL31_NOBITS_BASE`` and
+``BL31_NOBITS_LIMIT``.
+
+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.
+
+- ``__<SECTION>_START__``
+
+ Start address of a given section named ``<SECTION>``.
+
+- ``__<SECTION>_END__``
+
+ End address of a given section named ``<SECTION>``. If there is an alignment
+ constraint on the section's end address then ``__<SECTION>_END__`` corresponds
+ to the end address of the section's actual contents, rounded up to the right
+ boundary. Refer to the value of ``__<SECTION>_UNALIGNED_END__`` to know the
+ actual end address of the section's contents.
+
+- ``__<SECTION>_UNALIGNED_END__``
+
+ End address of a given section named ``<SECTION>`` without any padding or
+ rounding up due to some alignment constraint.
+
+- ``__<SECTION>_SIZE__``
+
+ Size (in bytes) of a given section named ``<SECTION>``. If there is an
+ alignment constraint on the section's end address then ``__<SECTION>_SIZE__``
+ corresponds to the size of the section's actual contents, rounded up to the
+ right boundary. In other words, ``__<SECTION>_SIZE__ = __<SECTION>_END__ - _<SECTION>_START__``. Refer to the value of ``__<SECTION>_UNALIGNED_SIZE__``
+ to know the actual size of the section's contents.
+
+- ``__<SECTION>_UNALIGNED_SIZE__``
+
+ Size (in bytes) of a given section named ``<SECTION>`` without any padding or
+ rounding up due to some alignment constraint. In other words,
+ ``__<SECTION>_UNALIGNED_SIZE__ = __<SECTION>_UNALIGNED_END__ - __<SECTION>_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/<platform>/<build-type>/bl<x>/bl<x>.map``, with ``<x>``
+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, tb_fw_config and fw_config.
+
+**FVP with TSP in Trusted SRAM with firmware configs :**
+(These diagrams only cover the AArch64 case)
+
+::
+
+ DRAM
+ 0xffffffff +----------+
+ : :
+ 0x82100000 |----------|
+ |HW_CONFIG |
+ 0x82000000 |----------| (non-secure)
+ | |
+ 0x80000000 +----------+
+
+ Trusted DRAM
+ 0x08000000 +----------+
+ |HW_CONFIG |
+ 0x07f00000 |----------|
+ : :
+ | |
+ 0x06000000 +----------+
+
+ Trusted SRAM
+ 0x04040000 +----------+ loaded by BL2 +----------------+
+ | BL1 (rw) | <<<<<<<<<<<<< | |
+ |----------| <<<<<<<<<<<<< | BL31 NOBITS |
+ | BL2 | <<<<<<<<<<<<< | |
+ |----------| <<<<<<<<<<<<< |----------------|
+ | | <<<<<<<<<<<<< | BL31 PROGBITS |
+ | | <<<<<<<<<<<<< |----------------|
+ | | <<<<<<<<<<<<< | BL32 |
+ 0x04003000 +----------+ +----------------+
+ | CONFIG |
+ 0x04001000 +----------+
+ | Shared |
+ 0x04000000 +----------+
+
+ Trusted ROM
+ 0x04000000 +----------+
+ | BL1 (ro) |
+ 0x00000000 +----------+
+
+**FVP with TSP in Trusted DRAM with firmware configs (default option):**
+
+::
+
+ DRAM
+ 0xffffffff +--------------+
+ : :
+ 0x82100000 |--------------|
+ | HW_CONFIG |
+ 0x82000000 |--------------| (non-secure)
+ | |
+ 0x80000000 +--------------+
+
+ Trusted DRAM
+ 0x08000000 +--------------+
+ | HW_CONFIG |
+ 0x07f00000 |--------------|
+ : :
+ | BL32 |
+ 0x06000000 +--------------+
+
+ Trusted SRAM
+ 0x04040000 +--------------+ loaded by BL2 +----------------+
+ | BL1 (rw) | <<<<<<<<<<<<< | |
+ |--------------| <<<<<<<<<<<<< | BL31 NOBITS |
+ | BL2 | <<<<<<<<<<<<< | |
+ |--------------| <<<<<<<<<<<<< |----------------|
+ | | <<<<<<<<<<<<< | BL31 PROGBITS |
+ | | +----------------+
+ 0x04003000 +--------------+
+ | 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 +----------+
+ | |
+ 0x82100000 |----------|
+ |HW_CONFIG |
+ 0x82000000 |----------| (non-secure)
+ | |
+ 0x80000000 +----------+
+
+ Trusted DRAM
+ 0x08000000 +----------+
+ |HW_CONFIG |
+ 0x7f000000 |----------|
+ : :
+ | |
+ 0x06000000 +----------+
+
+ Trusted SRAM
+ 0x04040000 +----------+ loaded by BL2 +----------------+
+ | BL1 (rw) | <<<<<<<<<<<<< | |
+ |----------| <<<<<<<<<<<<< | BL31 NOBITS |
+ | BL2 | <<<<<<<<<<<<< | |
+ |----------| <<<<<<<<<<<<< |----------------|
+ | | <<<<<<<<<<<<< | BL31 PROGBITS |
+ | | +----------------+
+ 0x04003000 +----------+
+ | 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 +----------+
+
+.. _firmware_design_fip:
+
+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
+ | <Padding> |
+ +-------------------+
+ | Exception vectors |
+ +-------------------+ 2 KB boundary
+ | <Padding> |
+ +-------------------+
+ | 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
+ | <Padding> |
+ +-------------------+
+ | Read-only data |
+ +-------------------+ Page boundary
+ | <Padding> |
+ +-------------------+
+ | Exception vectors |
+ +-------------------+ 2 KB boundary
+ | <Padding> |
+ +-------------------+
+ | 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.
+
+.. seealso:: :ref:`Build Options`
+
+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.
+
+ 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.
+
+- 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<X> = 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<x>`` 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`_
+
+- :ref:`Interrupt Management Framework`
+
+--------------
+
+*Copyright (c) 2013-2022, 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: https://developer.arm.com/docs/den0028/latest
+.. _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: https://developer.arm.com/docs/ddi0487/latest
+.. _SMC Calling Convention: https://developer.arm.com/docs/den0028/latest
+.. _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
+.. _Arm Confidential Compute Architecture (Arm CCA): https://www.arm.com/why-arm/architecture/security-features/arm-confidential-compute-architecture
+
+.. |Image 1| image:: ../resources/diagrams/rt-svc-descs-layout.png
diff --git a/docs/design/index.rst b/docs/design/index.rst
new file mode 100644
index 0000000..17ef756
--- /dev/null
+++ b/docs/design/index.rst
@@ -0,0 +1,20 @@
+System Design
+=============
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents
+
+ alt-boot-flows
+ auth-framework
+ cpu-specific-build-macros
+ firmware-design
+ interrupt-framework-design
+ psci-pd-tree
+ reset-design
+ trusted-board-boot
+ trusted-board-boot-build
+
+--------------
+
+*Copyright (c) 2019, Arm Limited. All rights reserved.*
diff --git a/docs/design/interrupt-framework-design.rst b/docs/design/interrupt-framework-design.rst
new file mode 100644
index 0000000..dfb2eac
--- /dev/null
+++ b/docs/design/interrupt-framework-design.rst
@@ -0,0 +1,1021 @@
+Interrupt 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:
+
+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 :ref:`exception
+ handling<interrupt-handling>` documentation.
+
+#. **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:
+
+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|
+
+.. _sp-synchronous-int:
+
+Secure payload interrupt handling
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+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 :ref:`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-2020, Arm Limited and Contributors. All rights reserved.*
+
+.. _SMC calling convention: https://developer.arm.com/docs/den0028/latest
+
+.. |Image 1| image:: ../resources/diagrams/sec-int-handling.png
+.. |Image 2| image:: ../resources/diagrams/non-sec-int-handling.png
diff --git a/docs/design/psci-pd-tree.rst b/docs/design/psci-pd-tree.rst
new file mode 100644
index 0000000..56a6d6f
--- /dev/null
+++ b/docs/design/psci-pd-tree.rst
@@ -0,0 +1,304 @@
+PSCI 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.*
diff --git a/docs/design/reset-design.rst b/docs/design/reset-design.rst
new file mode 100644
index 0000000..666ee4f
--- /dev/null
+++ b/docs/design/reset-design.rst
@@ -0,0 +1,168 @@
+CPU 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:`Arm Fixed Virtual Platforms (FVP)` 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 should be 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.
+
+.. note::
+ Some platforms that configure ``RESET_TO_BL31`` might still be able to
+ receive parameters in registers depending on their actual boot sequence. On
+ those occasions, and in addition to ``RESET_TO_BL31``, these platforms should
+ set ``RESET_TO_BL31_WITH_PARAMS`` to avoid the input registers from being
+ zeroed before entering BL31.
+
+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-2022, 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
diff --git a/docs/design/trusted-board-boot-build.rst b/docs/design/trusted-board-boot-build.rst
new file mode 100644
index 0000000..c3f3a2f
--- /dev/null
+++ b/docs/design/trusted-board-boot-build.rst
@@ -0,0 +1,122 @@
+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. See the :ref:`Prerequisites` document for the appropriate
+ version of mbed TLS to use.
+
+ 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=<path of the directory containing mbed TLS sources>``
+ - ``TRUSTED_BOARD_BOOT=1``
+ - ``GENERATE_COT=1``
+
+ By default, this will use the Chain of Trust described in the TBBR-client
+ document. To select a different one, use the ``COT`` build option.
+
+ If using a custom build of OpenSSL, set the ``OPENSSL_DIR`` variable
+ accordingly so it points at the OpenSSL installation path, as explained in
+ :ref:`Build Options`. In addition, set the ``LD_LIBRARY_PATH`` variable
+ when running to point at the custom OpenSSL path, so the OpenSSL libraries
+ are loaded from that path instead of the default OS path. Export this
+ variable if necessary.
+
+ In the case of Arm platforms, the location of the ROTPK hash must also be
+ specified at build time. The following 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, these
+ registers are read-only. On FVP Base and Cortex models, the registers
+ are also read-only, but the value can be specified using the command line
+ option ``bp.trusted_key_storage.public_key`` when launching the model.
+ On Juno board, 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 default hash located in
+ ``plat/arm/board/common/rotpk/arm_rotpk_rsa_sha256.bin``. Enforce
+ generation of the new hash if ``ROT_KEY`` is specified.
+
+ - ``ARM_ROTPK_LOCATION=devel_ecdsa``: use the default hash located in
+ ``plat/arm/board/common/rotpk/arm_rotpk_ecdsa_sha256.bin``. Enforce
+ generation of the new hash if ``ROT_KEY`` is specified.
+
+ Example of command line using RSA development keys:
+
+ .. code:: shell
+
+ MBEDTLS_DIR=<path of the directory containing mbed TLS sources> \
+ make PLAT=<platform> TRUSTED_BOARD_BOOT=1 GENERATE_COT=1 \
+ ARM_ROTPK_LOCATION=devel_rsa \
+ ROT_KEY=plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem \
+ BL33=<path-to>/<bl33_image> OPENSSL_DIR=<path-to>/<openssl> \
+ 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 selected Chain of
+ Trust. 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=<path of the directory containing mbed TLS sources> \
+ 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=<path-to>/<bl33_image> OPENSSL_DIR=<path-to>/<openssl> \
+ SCP_BL2=<path-to>/<scp_bl2_image> \
+ SCP_BL2U=<path-to>/<scp_bl2u_image> \
+ NS_BL2U=<path-to>/<ns_bl2u_image> \
+ 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=<path-to>/<bl2u_image>``
+ 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
+ selected Chain of Trust. These certificates can also be found in the output
+ build directory.
+
+--------------
+
+*Copyright (c) 2019-2022, Arm Limited. All rights reserved.*
+
+.. _mbed TLS Repository: https://github.com/ARMmbed/mbedtls.git
+.. _mbed TLS Security Center: https://tls.mbed.org/security
diff --git a/docs/design/trusted-board-boot.rst b/docs/design/trusted-board-boot.rst
new file mode 100644
index 0000000..46177d7
--- /dev/null
+++ b/docs/design/trusted-board-boot.rst
@@ -0,0 +1,263 @@
+Trusted 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. Alternatively, a development ROTPK might
+ be used and its hash embedded into the BL1 and BL2 images (only for
+ development purposes).
+
+- 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, different signature schemes are available,
+please refer to the :ref:`Build Options` for more details.
+
+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. Various hash algorithms
+are supported to calculate all hashes, please refer to the :ref:`Build Options`
+for more details.. 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.
+
+- **BL3X keys**
+
+ For each of SCP_BL2, BL31, BL32 and BL33, the private part is used to
+ sign the content certificate for the BL3X 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
+:ref:`Build Options`.
+
+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 output build directory.
+
+The tool resides in the ``tools/cert_create`` directory. It uses the OpenSSL SSL
+library version to generate the X.509 certificates. The specific version of the
+library that is required is given in the :ref:`Prerequisites` document.
+
+Instructions for building and using the tool can be found at
+:ref:`tools_build_cert_create`.
+
+Authenticated Encryption Framework
+----------------------------------
+
+The authenticated encryption framework included in TF-A provides support to
+implement the optional firmware encryption feature. This feature can be
+optionally enabled on platforms to implement the optional requirement:
+R060_TBBR_FUNCTION as specified in the `Trusted Board Boot Requirements (TBBR)`_
+document.
+
+Firmware Encryption Tool
+------------------------
+
+The ``encrypt_fw`` tool is built and runs on the host machine as part of the
+TF-A build process when ``DECRYPTION_SUPPORT != none``. It takes the plain
+firmware image as input and generates the encrypted firmware image which can
+then be passed as input to the ``fiptool`` utility for creating the FIP.
+
+The encrypted firmwares are also stored individually in the output build
+directory.
+
+The tool resides in the ``tools/encrypt_fw`` directory. It uses OpenSSL SSL
+library version 1.0.1 or later to do authenticated encryption operation.
+Instructions for building and using the tool can be found in the
+:ref:`tools_build_enctool`.
+
+--------------
+
+*Copyright (c) 2015-2020, 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
diff --git a/docs/design_documents/cmake_framework.rst b/docs/design_documents/cmake_framework.rst
new file mode 100644
index 0000000..d88942e
--- /dev/null
+++ b/docs/design_documents/cmake_framework.rst
@@ -0,0 +1,165 @@
+TF-A CMake buildsystem
+======================
+
+:Author: Balint Dobszay
+:Organization: Arm Limited
+:Contact: Balint Dobszay <balint.dobszay@arm.com>
+:Status: Accepted
+
+.. contents:: Table of Contents
+
+Abstract
+--------
+This document presents a proposal for a new buildsystem for TF-A using CMake,
+and as part of this a reusable CMake framework for embedded projects. For a
+summary about the proposal, please see the `Phabricator wiki page
+<https://developer.trustedfirmware.org/w/tf_a/cmake-buildsystem-proposal/>`_. As
+mentioned there, the proposal consists of two phases. The subject of this
+document is the first phase only.
+
+Introduction
+------------
+The current Makefile based buildsystem of TF-A has become complicated and hard
+to maintain, there is a need for a new, more flexible solution. The proposal is
+to use CMake language for the new buildsystem. The main reasons of this decision
+are the following:
+
+* It is a well-established, mature tool, widely accepted by open-source
+ projects.
+* TF-M is already using CMake, reducing fragmentation for tf.org projects can be
+ beneficial.
+* CMake has various advantages over Make, e.g.:
+
+ * Host and target system agnostic project.
+ * CMake project is scalable, supports project modularization.
+ * Supports software integration.
+ * Out-of-the-box support for integration with several tools (e.g. project
+ generation for various IDEs, integration with cppcheck, etc).
+
+Of course there are drawbacks too:
+
+* Language is problematic (e.g. variable scope).
+* Not embedded approach.
+
+To overcome these and other problems, we need to create workarounds for some
+tasks, wrap CMake functions, etc. Since this functionality can be useful in
+other embedded projects too, it is beneficial to collect the new code into a
+reusable framework and store this in a separate repository. The following
+diagram provides an overview of the framework structure:
+
+|Framework structure|
+
+Main features
+-------------
+
+Structured configuration description
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+In the current Makefile system the build configuration description, validation,
+processing, and the target creation, source file description are mixed and
+spread across several files. One of the goals of the framework is to organize
+this.
+
+The framework provides a solution to describe the input build parameters, flags,
+macros, etc. in a structured way. It contains two utilities for this purpose:
+
+* Map: simple key-value pair implementation.
+* Group: collection of related maps.
+
+The related parameters shall be packed into a group (or "setting group"). The
+setting groups shall be defined and filled with content in config files.
+Currently the config files are created and edited manually, but later a
+configuration management tool (e.g. Kconfig) shall be used to generate these
+files. Therefore, the framework does not contain parameter validation and
+conflict checking, these shall be handled by the configuration tool.
+
+Target description
+^^^^^^^^^^^^^^^^^^
+The framework provides an API called STGT ('simple target') to describe the
+targets, i.e. what is the build output, what source files are used, what
+libraries are linked, etc. The API wraps the CMake target functions, and also
+extends the built-in functionality, it can use the setting groups described in
+the previous section. A group can be applied onto a target, i.e. a collection of
+macros, flags, etc. can be applied onto the given output executable/library.
+This provides a more granular way than the current Makefile system where most of
+these are global and applied onto each target.
+
+Compiler abstraction
+^^^^^^^^^^^^^^^^^^^^
+Apart from the built-in CMake usage of the compiler, there are some common tasks
+that CMake does not solve (e.g. preprocessing a file). For these tasks the
+framework uses wrapper functions instead of direct calls to the compiler. This
+way it is not tied to one specific compiler.
+
+External tools
+^^^^^^^^^^^^^^
+In the TF-A buildsystem some external tools are used, e.g. fiptool for image
+generation or dtc for device tree compilation. These tools have to be found
+and/or built by the framework. For this, the CMake find_package functionality is
+used, any other necessary tools can be added later.
+
+Workflow
+--------
+The following diagram demonstrates the development workflow using the framework:
+
+|Framework workflow|
+
+The process can be split into two main phases:
+
+In the provisioning phase, first we have to obtain the necessary resources, i.e.
+clone the code repository and other dependencies. Next we have to do the
+configuration, preferably using a config tool like KConfig.
+
+In the development phase first we run CMake, which will generate the buildsystem
+using the selected generator backend (currently only the Makefile generator is
+supported). After this we run the selected build tool which in turn calls the
+compiler, linker, packaging tool, etc. Finally we can run and debug the output
+executables.
+
+Usually during development only the steps in this second phase have to be
+repeated, while the provisioning phase needs to be done only once (or rarely).
+
+Example
+-------
+This is a short example for the basic framework usage.
+
+First, we create a setting group called *mem_conf* and fill it with several
+parameters. It is worth noting the difference between *CONFIG* and *DEFINE*
+types: the former is only a CMake domain option, the latter is only a C language
+macro.
+
+Next, we create a target called *fw1* and add the *mem_conf* setting group to
+it. This means that all source and header files used by the target will have all
+the parameters declared in the setting group. Then we set the target type to
+executable, and add some source files. Since the target has the parameters from
+the settings group, we can use it for conditionally adding source files. E.g.
+*dram_controller.c* will only be added if MEM_TYPE equals dram.
+
+.. code-block:: cmake
+
+ group_new(NAME mem_conf)
+ group_add(NAME mem_conf TYPE DEFINE KEY MEM_SIZE VAL 1024)
+ group_add(NAME mem_conf TYPE CONFIG DEFINE KEY MEM_TYPE VAL dram)
+ group_add(NAME mem_conf TYPE CFLAG KEY -Os)
+
+ stgt_create(NAME fw1)
+ stgt_add_setting(NAME fw1 GROUPS mem_conf)
+ stgt_set_target(NAME fw1 TYPE exe)
+
+ stgt_add_src(NAME fw1 SRC
+ ${CMAKE_SOURCE_DIR}/main.c
+ )
+
+ stgt_add_src_cond(NAME fw1 KEY MEM_TYPE VAL dram SRC
+ ${CMAKE_SOURCE_DIR}/dram_controller.c
+ )
+
+.. |Framework structure| image::
+ ../resources/diagrams/cmake_framework_structure.png
+ :width: 75 %
+
+.. |Framework workflow| image::
+ ../resources/diagrams/cmake_framework_workflow.png
+
+--------------
+
+*Copyright (c) 2019-2020, Arm Limited and Contributors. All rights reserved.*
diff --git a/docs/design_documents/context_mgmt_rework.rst b/docs/design_documents/context_mgmt_rework.rst
new file mode 100644
index 0000000..59f9d4e
--- /dev/null
+++ b/docs/design_documents/context_mgmt_rework.rst
@@ -0,0 +1,197 @@
+Enhance Context Management library for EL3 firmware
+===================================================
+
+:Authors: Soby Mathew & Zelalem Aweke
+:Organization: Arm Limited
+:Contact: Soby Mathew <soby.mathew@arm.com> & Zelalem Aweke <zelalem.aweke@arm.com>
+:Status: RFC
+
+.. contents:: Table of Contents
+
+Introduction
+------------
+The context management library in TF-A provides the basic CPU context
+initialization and management routines for use by different components
+in EL3 firmware. The original design of the library was done keeping in
+mind the 2 world switch and hence this design pattern has been extended to
+keep up with growing requirements of EL3 firmware. With the introduction
+of a new Realm world and a separate Root world for EL3 firmware, it is clear
+that this library needs to be refactored to cater for future enhancements and
+reduce chances of introducing error in code. This also aligns with the overall
+goal of reducing EL3 firmware complexity and footprint.
+
+It is expected that the suggestions below could have legacy implications and
+hence we are mainly targeting SPM/RMM based systems. It is expected that these
+legacy issues will need to be sorted out as part of implementation on a case
+by case basis.
+
+Design Principles
+-----------------
+The below section lays down the design principles for re-factoring the context
+management library :
+
+(1) **Decentralized model for context mgmt**
+
+ Both the Secure and Realm worlds have associated dispatcher component in
+ EL3 firmware to allow management of their respective worlds. Allowing the
+ dispatcher to own the context for their respective world and moving away
+ from a centralized policy management by context management library will
+ remove the world differentiation code in the library. This also means that
+ the library will not be responsible for CPU feature enablement for
+ Secure and Realm worlds. See point 3 and 4 for more details.
+
+ The Non Secure world does not have a dispatcher component and hence EL3
+ firmware (BL31)/context management library needs to have routines to help
+ initialize the Non Secure world context.
+
+(2) **EL3 should only initialize immediate used lower EL**
+
+ Due to the way TF-A evolved, from EL3 interacting with an S-EL1 payload to
+ SPM in S-EL2, there is some code initializing S-EL1 registers which is
+ probably redundant when SPM is present in S-EL2. As a principle, EL3
+ firmware should only initialize the next immediate lower EL in use.
+ If EL2 needs to be skipped and is not to be used at runtime, then
+ EL3 can do the bare minimal EL2 init and init EL1 to prepare for EL3 exit.
+ It is expected that this skip EL2 configuration is only needed for NS
+ world to support legacy Android deployments. It is worth removing this
+ `skip EL2 for Non Secure` config support if this is no longer used.
+
+(3) **Maintain EL3 sysregs which affect lower EL within CPU context**
+
+ The CPU context contains some EL3 sysregs and gets applied on a per-world
+ basis (eg: cptr_el3, scr_el3, zcr_el3 is part of the context
+ because different settings need to be applied between each world).
+ But this design pattern is not enforced in TF-A. It is possible to directly
+ modify EL3 sysreg dynamically during the transition between NS and Secure
+ worlds. Having multiple ways of manipulating EL3 sysregs for different
+ values between the worlds is flaky and error prone. The proposal is to
+ enforce the rule that any EL3 sysreg which can be different between worlds
+ is maintained in the CPU Context. Once the context is initialized the
+ EL3 sysreg values corresponding to the world being entered will be restored.
+
+(4) **Allow more flexibility for Dispatchers to select feature set to save and restore**
+
+ The current functions for EL2 CPU context save and restore is a single
+ function which takes care of saving and restoring all the registers for
+ EL2. This method is inflexible and it does not allow to dynamically detect
+ CPU features to select registers to save and restore. It also assumes that
+ both Realm and Secure world will have the same feature set enabled from
+ EL3 at runtime and makes it hard to enable different features for each
+ world. The framework should cater for selective save and restore of CPU
+ registers which can be controlled by the dispatcher.
+
+ For the implementation, this could mean that there is a separate assembly
+ save and restore routine corresponding to Arch feature. The memory allocation
+ within the CPU Context for each set of registers will be controlled by a
+ FEAT_xxx build option. It is a valid configuration to have
+ context memory allocated but not used at runtime based on feature detection
+ at runtime or the platform owner has decided not to enable the feature
+ for the particular world.
+
+Context Allocation and Initialization
+-------------------------------------
+
+|context_mgmt_abs|
+
+.. |context_mgmt_abs| image::
+ ../resources/diagrams/context_management_abs.png
+
+The above figure shows how the CPU context is allocated within TF-A. The
+allocation for Secure and Realm world is by the respective dispatcher. In the case
+of NS world, the context is allocated by the PSCI lib. This scheme allows TF-A
+to be built in various configurations (with or without Secure/Realm worlds) and
+will result in optimal memory footprint. The Secure and Realm world contexts are
+initialized by invoking context management library APIs which then initialize
+each world based on conditional evaluation of the security state of the
+context. The proposal here is to move the conditional initialization
+of context for Secure and Realm worlds to their respective dispatchers and
+have the library do only the common init needed. The library can export
+helpers to initialize registers corresponding to certain features but
+should not try to do different initialization between the worlds. The library
+can also export helpers for initialization of NS CPU Context since there is no
+dispatcher for that world.
+
+This implies that any world specific code in context mgmt lib should now be
+migrated to the respective "owners". To maintain compatibility with legacy, the
+current functions can be retained in the lib and perhaps define new ones for
+use by SPMD and RMMD. The details of this can be worked out during
+implementation.
+
+Introducing Root Context
+------------------------
+Till now, we have been ignoring the fact that Root world (or EL3) itself could
+have some settings which are distinct from NS/S/Realm worlds. In this case,
+Root world itself would need to maintain some sysregs settings for its own
+execution and would need to use sysregs of lower EL (eg: PAuth, pmcr) to enable
+some functionalities in EL3. The current sequence for context save and restore
+in TF-A is as given below:
+
+|context_mgmt_existing|
+
+.. |context_mgmt_existing| image::
+ ../resources/diagrams/context_mgmt_existing.png
+
+Note1: The EL3 CPU context is not a homogenous collection of EL3 sysregs but
+a collection of EL3 and some other lower EL registers. The save and restore
+is also not done homogenously but based on the objective of using the
+particular register.
+
+Note2: The EL1 context save and restore can possibly be removed when switching
+to S-EL2 as SPM can take care of saving the incoming NS EL1 context.
+
+It can be seen that the EL3 sysreg values applied while the execution is in Root
+world corresponds to the world it came from (eg: if entering EL3 from NS world,
+the sysregs correspond to the values in NS context). There is a case that EL3
+itself may have some settings to apply for various reasons. A good example for
+this is the cptr_el3 regsiter. Although FPU traps need to be disabled for
+Non Secure, Secure and Realm worlds, the EL3 execution itself may keep the trap
+enabled for the sake of robustness. Another example is, if the MTE feature
+is enabled for a particular world, this feature will be enabled for Root world
+as well when entering EL3 from that world. The firmware at EL3 may not
+be expecting this feature to be enabled and may cause unwanted side-effects
+which could be problematic. Thus it would be more robust if Root world is not
+subject to EL3 sysreg values from other worlds but maintains its own values
+which is stable and predictable throughout root world execution.
+
+There is also the case that when EL3 would like to make use of some
+Architectural feature(s) or do some security hardening, it might need
+programming of some lower EL sysregs. For example, if EL3 needs to make
+use of Pointer Authentication (PAuth) feature, it needs to program
+its own PAuth Keys during execution at EL3. Hence EL3 needs its
+own copy of PAuth registers which needs to be restored on every
+entry to EL3. A similar case can be made for DIT bit in PSTATE,
+or use of SP_EL0 for C Runtime Stack at EL3.
+
+The proposal here is to maintain a separate root world CPU context
+which gets applied for Root world execution. This is not the full
+CPU_Context, but subset of EL3 sysregs (`el3_sysreg`) and lower EL
+sysregs (`root_exc_context`) used by EL3. The save and restore
+sequence for this Root context would need to be done in
+an optimal way. The `el3_sysreg` does not need to be saved
+on EL3 Exit and possibly only some registers in `root_exc_context`
+of Root world context would need to be saved on EL3 exit (eg: SP_EL0).
+
+The new sequence for world switch including Root world context would
+be as given below :
+
+|context_mgmt_proposed|
+
+.. |context_mgmt_proposed| image::
+ ../resources/diagrams/context_mgmt_proposed.png
+
+Having this framework in place will allow Root world to make use of lower EL
+registers easily for its own purposes and also have a fixed EL3 sysreg setting
+which is not affected by the settings of other worlds. This will unify the
+Root world register usage pattern for its own execution and remove some
+of the adhoc usages in code.
+
+Conclusion
+----------
+Of all the proposals, the introduction of Root world context would likely need
+further prototyping to confirm the design and we will need to measure the
+performance and memory impact of this change. Other changes are incremental
+improvements which are thought to have negligible impact on EL3 performance.
+
+--------------
+
+*Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.*
diff --git a/docs/design_documents/drtm_poc.rst b/docs/design_documents/drtm_poc.rst
new file mode 100644
index 0000000..79e1142
--- /dev/null
+++ b/docs/design_documents/drtm_poc.rst
@@ -0,0 +1,132 @@
+DRTM Proof of Concept
+=====================
+
+Dynamic Root of Trust for Measurement (DRTM) begins a new trust environment
+by measuring and executing a protected payload.
+
+Static Root of Trust for Measurement (SRTM)/Measured Boot implementation,
+currently used by TF-A covers all firmwares, from the boot ROM to the normal
+world bootloader. As a whole, they make up the system's TCB. These boot
+measurements allow attesting to what software is running on the system and
+enable enforcing security policies.
+
+As the boot chain grows or firmware becomes dynamically extensible,
+establishing an attestable TCB becomes more challenging. DRTM provides a
+solution to this problem by allowing measurement chains to be started at
+any time. As these measurements are stored separately from the boot-time
+measurements, they reduce the size of the TCB, which helps reduce the attack
+surface and the risk of untrusted code executing, which could compromise
+the security of the system.
+
+Components
+~~~~~~~~~~
+
+ - **DCE-Preamble**: The DCE Preamble prepares the platform for DRTM by
+ doing any needed configuration, loading the target payload image(DLME),
+ and preparing input parameters needed by DRTM. Finally, it invokes the
+ DL Event to start the dynamic launch.
+
+ - **D-CRTM**: The D-CRTM is the trust anchor (or root of trust) for the
+ DRTM boot sequence and is where the dynamic launch starts. The D-CRTM
+ must be implemented as a trusted agent in the system. The D-CRTM
+ initializes the TPM for DRTM and prepares the environment for the next
+ stage of DRTM, the DCE. The D-CRTM measures the DCE, verifies its
+ signature, and transfers control to it.
+
+ - **DCE**: The DCE executes on an application core. The DCE verifies the
+ system’s state, measures security-critical attributes of the system,
+ prepares the memory region for the target payload, measures the payload,
+ and finally transfers control to the payload.
+
+ - **DLME**: The protected payload is referred to as the Dynamically Launched
+ Measured Environment, or DLME. The DLME begins execution in a safe state,
+ with a single thread of execution, DMA protections, and interrupts
+ disabled. The DCE provides data to the DLME that it can use to verify the
+ configuration of the system.
+
+In this proof of concept, DCE and D-CRTM are implemented in BL31 and
+DCE-Preamble and DLME are implemented in UEFI application. A DL Event is
+triggered as a SMC by DCE-Preamble and handled by D-CRTM, which launches the
+DLME via DCE.
+
+This manual provides instructions to build TF-A code with pre-buit EDK2
+and DRTM UEFI application.
+
+Building the PoC for the Arm FVP platform
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+(1) Use the below command to clone TF-A source code -
+
+.. code:: shell
+
+ $ git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
+
+(2) There are prebuilt binaries required to execute the DRTM implementation
+ in the `prebuilts-drtm-bins`_.
+ Download EDK2 *FVP_AARCH64_EFI.fd* and UEFI DRTM application *test-disk.img*
+ binary from `prebuilts-drtm-bins`_.
+
+(3) Build the TF-A code using below command
+
+.. code:: shell
+
+ $ make CROSS_COMPILE=aarch64-none-elf- ARM_ROTPK_LOCATION=devel_rsa
+ DEBUG=1 V=1 BL33=</path/to/FVP_AARCH64_EFI.fd> DRTM_SUPPORT=1
+ MBEDTLS_DIR=</path/to/mbedTLS-source> USE_ROMLIB=1 all fip
+
+Running DRTM UEFI application on the Armv8-A AEM FVP
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+To run the DRTM test application along with DRTM implementation in BL31,
+you need an FVP model. Please use the version of FVP_Base_RevC-2xAEMvA model
+advertised in the TF-A documentation.
+
+.. code:: shell
+
+ FVP_Base_RevC-2xAEMvA \
+ --data cluster0.cpu0=</path/to/romlib.bin>@0x03ff2000 \
+ --stat \
+ -C bp.flashloader0.fname=<path/to/fip.bin> \
+ -C bp.secureflashloader.fname=<path/to/bl1.bin> \
+ -C bp.ve_sysregs.exit_on_shutdown=1 \
+ -C bp.virtioblockdevice.image_path=<path/to/test-disk.img> \
+ -C cache_state_modelled=1 \
+ -C cluster0.check_memory_attributes=0 \
+ -C cluster0.cpu0.etm-present=0 \
+ -C cluster0.cpu1.etm-present=0 \
+ -C cluster0.cpu2.etm-present=0 \
+ -C cluster0.cpu3.etm-present=0 \
+ -C cluster0.stage12_tlb_size=1024 \
+ -C cluster1.check_memory_attributes=0 \
+ -C cluster1.cpu0.etm-present=0 \
+ -C cluster1.cpu1.etm-present=0 \
+ -C cluster1.cpu2.etm-present=0 \
+ -C cluster1.cpu3.etm-present=0 \
+ -C cluster1.stage12_tlb_size=1024 \
+ -C pctl.startup=0.0.0.0 \
+ -Q 1000 \
+ "$@"
+
+The bottom of the output from *uart1* should look something like the
+following to indicate that the last SMC to unprotect memory has been fired
+successfully.
+
+.. code-block:: shell
+
+ ...
+
+ INFO: DRTM service handler: version
+ INFO: ++ DRTM service handler: TPM features
+ INFO: ++ DRTM service handler: Min. mem. requirement features
+ INFO: ++ DRTM service handler: DMA protection features
+ INFO: ++ DRTM service handler: Boot PE ID features
+ INFO: ++ DRTM service handler: TCB-hashes features
+ INFO: DRTM service handler: dynamic launch
+ WARNING: DRTM service handler: close locality is not supported
+ INFO: DRTM service handler: unprotect mem
+
+--------------
+
+*Copyright (c) 2022, Arm Limited. All rights reserved.*
+
+.. _prebuilts-drtm-bins: https://downloads.trustedfirmware.org/tf-a/drtm
+.. _DRTM-specification: https://developer.arm.com/documentation/den0113/a
diff --git a/docs/design_documents/index.rst b/docs/design_documents/index.rst
new file mode 100644
index 0000000..3e20c07
--- /dev/null
+++ b/docs/design_documents/index.rst
@@ -0,0 +1,15 @@
+Design Documents
+================
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents
+
+ cmake_framework
+ context_mgmt_rework
+ measured_boot_poc
+ drtm_poc
+
+--------------
+
+*Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.*
diff --git a/docs/design_documents/measured_boot_poc.rst b/docs/design_documents/measured_boot_poc.rst
new file mode 100644
index 0000000..3ae539b
--- /dev/null
+++ b/docs/design_documents/measured_boot_poc.rst
@@ -0,0 +1,507 @@
+Interaction between Measured Boot and an fTPM (PoC)
+===================================================
+
+Measured Boot is the process of cryptographically measuring the code and
+critical data used at boot time, for example using a TPM, so that the
+security state can be attested later.
+
+The current implementation of the driver included in Trusted Firmware-A
+(TF-A) stores the measurements into a `TGC event log`_ in secure
+memory. No other means of recording measurements (such as a discrete TPM) is
+supported right now.
+
+The driver also provides mechanisms to pass the Event Log to normal world if
+needed.
+
+This manual provides instructions to build a proof of concept (PoC) with the
+sole intention of showing how Measured Boot can be used in conjunction with
+a firmware TPM (fTPM) service implemented on top of OP-TEE.
+
+.. note::
+ The instructions given in this document are meant to be used to build
+ a PoC to show how Measured Boot on TF-A can interact with a third
+ party (f)TPM service and they try to be as general as possible. Different
+ platforms might have different needs and configurations (e.g. different
+ SHA algorithms) and they might also use different types of TPM services
+ (or even a different type of service to provide the attestation)
+ and therefore the instuctions given here might not apply in such scenarios.
+
+Components
+~~~~~~~~~~
+
+The PoC is built on top of the `OP-TEE Toolkit`_, which has support to build
+TF-A with support for Measured Boot enabled (and run it on a Foundation Model)
+since commit cf56848.
+
+The aforementioned toolkit builds a set of images that contain all the components
+needed to test that the Event Log was properly created. One of these images will
+contain a third party fTPM service which in turn will be used to process the
+Event Log.
+
+The reason to choose OP-TEE Toolkit to build our PoC around it is mostly
+for convenience. As the fTPM service used is an OP-TEE TA, it was easy to add
+build support for it to the toolkit and then build the PoC around it.
+
+The most relevant components installed in the image that are closely related to
+Measured Boot/fTPM functionality are:
+
+ - **OP-TEE**: As stated earlier, the fTPM service used in this PoC is built as an
+ OP-TEE TA and therefore we need to include the OP-TEE OS image.
+ Support to interfacing with Measured Boot was added to version 3.9.0 of
+ OP-TEE by implementing the ``PTA_SYSTEM_GET_TPM_EVENT_LOG`` syscall, which
+ allows the former to pass a copy of the Event Log to any TA requesting it.
+ OP-TEE knows the location of the Event Log by reading the DTB bindings
+ received from TF-A. Visit :ref:`DTB binding for Event Log properties`
+ for more details on this.
+
+ - **fTPM Service**: We use a third party fTPM service in order to validate
+ the Measured Boot functionality. The chosen fTPM service is a sample
+ implementation for Aarch32 architecture included on the `ms-tpm-20-ref`_
+ reference implementation from Microsoft. The service was updated in order
+ to extend the Measured Boot Event Log at boot up and it uses the
+ aforementioned ``PTA_SYSTEM_GET_TPM_EVENT_LOG`` call to retrieve a copy
+ of the former.
+
+ .. note::
+ Arm does not provide an fTPM implementation. The fTPM service used here
+ is a third party one which has been updated to support Measured Boot
+ service as provided by TF-A. As such, it is beyond the scope of this
+ manual to test and verify the correctness of the output generated by the
+ fTPM service.
+
+ - **TPM Kernel module**: In order to interact with the fTPM service, we need
+ a kernel module to forward the request from user space to the secure world.
+
+ - `tpm2-tools`_: This is a set of tools that allow to interact with the
+ fTPM service. We use this in order to read the PCRs with the measurements.
+
+Building the PoC for the Arm FVP platform
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+As mentioned before, this PoC is based on the OP-TEE Toolkit with some
+extensions to enable Measured Boot and an fTPM service. Therefore, we can rely
+on the instructions to build the original OP-TEE Toolkit. As a general rule,
+the following steps should suffice:
+
+(1) Start by following the `Get and build the solution`_ instructions to build
+ the OP-TEE toolkit. On step 3, you need to get the manifest for FVP
+ platform from the main branch:
+
+ .. code:: shell
+
+ $ repo init -u https://github.com/OP-TEE/manifest.git -m fvp.xml
+
+ Then proceed synching the repos as stated in step 3. Continue following
+ the instructions and stop before step 5.
+
+(2) Next you should obtain the `Armv8-A Foundation Platform (For Linux Hosts Only)`_.
+ The binary should be untar'ed to the root of the repo tree, i.e., like
+ this: ``<fvp-project>/Foundation_Platformpkg``. In the end, after cloning
+ all source code, getting the toolchains and "installing"
+ Foundation_Platformpkg, you should have a folder structure that looks like
+ this:
+
+ .. code:: shell
+
+ $ ls -la
+ total 80
+ drwxrwxr-x 20 tf-a_user tf-a_user 4096 Jul 1 12:16 .
+ drwxr-xr-x 23 tf-a_user tf-a_user 4096 Jul 1 10:40 ..
+ drwxrwxr-x 12 tf-a_user tf-a_user 4096 Jul 1 10:45 build
+ drwxrwxr-x 16 tf-a_user tf-a_user 4096 Jul 1 12:16 buildroot
+ drwxrwxr-x 51 tf-a_user tf-a_user 4096 Jul 1 10:45 edk2
+ drwxrwxr-x 6 tf-a_user tf-a_user 4096 Jul 1 12:14 edk2-platforms
+ drwxr-xr-x 7 tf-a_user tf-a_user 4096 Jul 1 10:52 Foundation_Platformpkg
+ drwxrwxr-x 17 tf-a_user tf-a_user 4096 Jul 2 10:40 grub
+ drwxrwxr-x 25 tf-a_user tf-a_user 4096 Jul 2 10:39 linux
+ drwxrwxr-x 15 tf-a_user tf-a_user 4096 Jul 1 10:45 mbedtls
+ drwxrwxr-x 6 tf-a_user tf-a_user 4096 Jul 1 10:45 ms-tpm-20-ref
+ drwxrwxr-x 8 tf-a_user tf-a_user 4096 Jul 1 10:45 optee_client
+ drwxrwxr-x 10 tf-a_user tf-a_user 4096 Jul 1 10:45 optee_examples
+ drwxrwxr-x 12 tf-a_user tf-a_user 4096 Jul 1 12:13 optee_os
+ drwxrwxr-x 8 tf-a_user tf-a_user 4096 Jul 1 10:45 optee_test
+ drwxrwxr-x 7 tf-a_user tf-a_user 4096 Jul 1 10:45 .repo
+ drwxrwxr-x 4 tf-a_user tf-a_user 4096 Jul 1 12:12 toolchains
+ drwxrwxr-x 21 tf-a_user tf-a_user 4096 Jul 1 12:15 trusted-firmware-a
+
+(3) Now enter into ``ms-tpm-20-ref`` and get its dependencies:
+
+ .. code:: shell
+
+ $ cd ms-tpm-20-ref
+ $ git submodule init
+ $ git submodule update
+ Submodule path 'external/wolfssl': checked out '9c87f979a7f1d3a6d786b260653d566c1d31a1c4'
+
+(4) Now, you should be able to continue with step 5 in "`Get and build the solution`_"
+ instructions. In order to enable support for Measured Boot, you need to
+ set the ``MEASURED_BOOT`` build option:
+
+ .. code:: shell
+
+ $ MEASURED_BOOT=y make -j `nproc`
+
+ .. note::
+ The build process will likely take a long time. It is strongly recommended to
+ pass the ``-j`` option to make to run the process faster.
+
+ After this step, you should be ready to run the image.
+
+Running and using the PoC on the Armv8-A Foundation AEM FVP
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+With everything built, you can now run the image:
+
+.. code:: shell
+
+ $ make run-only
+
+.. note::
+ Using ``make run`` will build and run the image and it can be used instead
+ of simply ``make``. However, once the image is built, it is recommended to
+ use ``make run-only`` to avoid re-running all the building rules, which
+ would take time.
+
+When FVP is launched, two terminal windows will appear. ``FVP terminal_0``
+is the userspace terminal whereas ``FVP terminal_1`` is the counterpart for
+the secure world (where TAs will print their logs, for instance).
+
+Log into the image shell with user ``root``, no password will be required.
+Then we can issue the ``ftpm`` command, which is an alias that
+
+(1) loads the ftpm kernel module and
+
+(2) calls ``tpm2_pcrread``, which will access the fTPM service to read the
+ PCRs.
+
+When loading the ftpm kernel module, the fTPM TA is loaded into the secure
+world. This TA then requests a copy of the Event Log generated during the
+booting process so it can retrieve all the entries on the log and record them
+first thing.
+
+.. note::
+ For this PoC, nothing loaded after BL33 and NT_FW_CONFIG is recorded
+ in the Event Log.
+
+The secure world terminal should show the debug logs for the fTPM service,
+including all the measurements available in the Event Log as they are being
+processed:
+
+.. code:: shell
+
+ M/TA: Preparing to extend the following TPM Event Log:
+ M/TA: TCG_EfiSpecIDEvent:
+ M/TA: PCRIndex : 0
+ M/TA: EventType : 3
+ M/TA: Digest : 00
+ M/TA: : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ M/TA: : 00 00 00
+ M/TA: EventSize : 33
+ M/TA: Signature : Spec ID Event03
+ M/TA: PlatformClass : 0
+ M/TA: SpecVersion : 2.0.2
+ M/TA: UintnSize : 1
+ M/TA: NumberOfAlgorithms : 1
+ M/TA: DigestSizes :
+ M/TA: #0 AlgorithmId : SHA256
+ M/TA: DigestSize : 32
+ M/TA: VendorInfoSize : 0
+ M/TA: PCR_Event2:
+ M/TA: PCRIndex : 0
+ M/TA: EventType : 3
+ M/TA: Digests Count : 1
+ M/TA: #0 AlgorithmId : SHA256
+ M/TA: Digest : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ M/TA: : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ M/TA: EventSize : 17
+ M/TA: Signature : StartupLocality
+ M/TA: StartupLocality : 0
+ M/TA: PCR_Event2:
+ M/TA: PCRIndex : 0
+ M/TA: EventType : 1
+ M/TA: Digests Count : 1
+ M/TA: #0 AlgorithmId : SHA256
+ M/TA: Digest : 58 26 32 6e 64 45 64 da 45 de 35 db 96 fd ed 63
+ M/TA: : 2a 6a d4 0d aa 94 b0 b1 55 e4 72 e7 1f 0a e0 d5
+ M/TA: EventSize : 5
+ M/TA: Event : BL_2
+ M/TA: PCR_Event2:
+ M/TA: PCRIndex : 0
+ M/TA: EventType : 1
+ M/TA: Digests Count : 1
+ M/TA: #0 AlgorithmId : SHA256
+ M/TA: Digest : cf f9 7d a3 5c 73 ac cb 7b a0 25 80 6a 6e 50 a5
+ M/TA: : 6b 2e d2 8c c9 36 92 7d 46 c5 b9 c3 a4 6c 51 7c
+ M/TA: EventSize : 6
+ M/TA: Event : BL_31
+ M/TA: PCR_Event2:
+ M/TA: PCRIndex : 0
+ M/TA: EventType : 1
+ M/TA: Digests Count : 1
+ M/TA: #0 AlgorithmId : SHA256
+ M/TA: Digest : 23 b0 a3 5d 54 d9 43 1a 5c b9 89 63 1c da 06 c2
+ M/TA: : e5 de e7 7e 99 17 52 12 7d f7 45 ca 4f 4a 39 c0
+ M/TA: EventSize : 10
+ M/TA: Event : HW_CONFIG
+ M/TA: PCR_Event2:
+ M/TA: PCRIndex : 0
+ M/TA: EventType : 1
+ M/TA: Digests Count : 1
+ M/TA: #0 AlgorithmId : SHA256
+ M/TA: Digest : 4e e4 8e 5a e6 50 ed e0 b5 a3 54 8a 1f d6 0e 8a
+ M/TA: : ea 0e 71 75 0e a4 3f 82 76 ce af cd 7c b0 91 e0
+ M/TA: EventSize : 14
+ M/TA: Event : SOC_FW_CONFIG
+ M/TA: PCR_Event2:
+ M/TA: PCRIndex : 0
+ M/TA: EventType : 1
+ M/TA: Digests Count : 1
+ M/TA: #0 AlgorithmId : SHA256
+ M/TA: Digest : 01 b0 80 47 a1 ce 86 cd df 89 d2 1f 2e fc 6c 22
+ M/TA: : f8 19 ec 6e 1e ec 73 ba 5a be d0 96 e3 5f 6d 75
+ M/TA: EventSize : 6
+ M/TA: Event : BL_32
+ M/TA: PCR_Event2:
+ M/TA: PCRIndex : 0
+ M/TA: EventType : 1
+ M/TA: Digests Count : 1
+ M/TA: #0 AlgorithmId : SHA256
+ M/TA: Digest : 5d c6 ef 35 5a 90 81 b4 37 e6 3b 52 da 92 ab 8e
+ M/TA: : d9 6e 93 98 2d 40 87 96 1b 5a a7 ee f1 f4 40 63
+ M/TA: EventSize : 18
+ M/TA: Event : BL32_EXTRA1_IMAGE
+ M/TA: PCR_Event2:
+ M/TA: PCRIndex : 0
+ M/TA: EventType : 1
+ M/TA: Digests Count : 1
+ M/TA: #0 AlgorithmId : SHA256
+ M/TA: Digest : 39 b7 13 b9 93 db 32 2f 1b 48 30 eb 2c f2 5c 25
+ M/TA: : 00 0f 38 dc 8e c8 02 cd 79 f2 48 d2 2c 25 ab e2
+ M/TA: EventSize : 6
+ M/TA: Event : BL_33
+ M/TA: PCR_Event2:
+ M/TA: PCRIndex : 0
+ M/TA: EventType : 1
+ M/TA: Digests Count : 1
+ M/TA: #0 AlgorithmId : SHA256
+ M/TA: Digest : 25 10 60 5d d4 bc 9d 82 7a 16 9f 8a cc 47 95 a6
+ M/TA: : fd ca a0 c1 2b c9 99 8f 51 20 ff c6 ed 74 68 5a
+ M/TA: EventSize : 13
+ M/TA: Event : NT_FW_CONFIG
+
+These logs correspond to the measurements stored by TF-A during the measured
+boot process and therefore, they should match the logs dumped by the former
+during the boot up process. These can be seen on the terminal_0:
+
+.. code:: shell
+
+ NOTICE: Booting Trusted Firmware
+ NOTICE: BL1: v2.5(release):v2.5
+ NOTICE: BL1: Built : 10:41:20, Jul 2 2021
+ NOTICE: BL1: Booting BL2
+ NOTICE: BL2: v2.5(release):v2.5
+ NOTICE: BL2: Built : 10:41:20, Jul 2 2021
+ NOTICE: TCG_EfiSpecIDEvent:
+ NOTICE: PCRIndex : 0
+ NOTICE: EventType : 3
+ NOTICE: Digest : 00
+ NOTICE: : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ NOTICE: : 00 00 00
+ NOTICE: EventSize : 33
+ NOTICE: Signature : Spec ID Event03
+ NOTICE: PlatformClass : 0
+ NOTICE: SpecVersion : 2.0.2
+ NOTICE: UintnSize : 1
+ NOTICE: NumberOfAlgorithms : 1
+ NOTICE: DigestSizes :
+ NOTICE: #0 AlgorithmId : SHA256
+ NOTICE: DigestSize : 32
+ NOTICE: VendorInfoSize : 0
+ NOTICE: PCR_Event2:
+ NOTICE: PCRIndex : 0
+ NOTICE: EventType : 3
+ NOTICE: Digests Count : 1
+ NOTICE: #0 AlgorithmId : SHA256
+ NOTICE: Digest : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ NOTICE: : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ NOTICE: EventSize : 17
+ NOTICE: Signature : StartupLocality
+ NOTICE: StartupLocality : 0
+ NOTICE: PCR_Event2:
+ NOTICE: PCRIndex : 0
+ NOTICE: EventType : 1
+ NOTICE: Digests Count : 1
+ NOTICE: #0 AlgorithmId : SHA256
+ NOTICE: Digest : 58 26 32 6e 64 45 64 da 45 de 35 db 96 fd ed 63
+ NOTICE: : 2a 6a d4 0d aa 94 b0 b1 55 e4 72 e7 1f 0a e0 d5
+ NOTICE: EventSize : 5
+ NOTICE: Event : BL_2
+ NOTICE: PCR_Event2:
+ NOTICE: PCRIndex : 0
+ NOTICE: EventType : 1
+ NOTICE: Digests Count : 1
+ NOTICE: #0 AlgorithmId : SHA256
+ NOTICE: Digest : cf f9 7d a3 5c 73 ac cb 7b a0 25 80 6a 6e 50 a5
+ NOTICE: : 6b 2e d2 8c c9 36 92 7d 46 c5 b9 c3 a4 6c 51 7c
+ NOTICE: EventSize : 6
+ NOTICE: Event : BL_31
+ NOTICE: PCR_Event2:
+ NOTICE: PCRIndex : 0
+ NOTICE: EventType : 1
+ NOTICE: Digests Count : 1
+ NOTICE: #0 AlgorithmId : SHA256
+ NOTICE: Digest : 23 b0 a3 5d 54 d9 43 1a 5c b9 89 63 1c da 06 c2
+ NOTICE: : e5 de e7 7e 99 17 52 12 7d f7 45 ca 4f 4a 39 c0
+ NOTICE: EventSize : 10
+ NOTICE: Event : HW_CONFIG
+ NOTICE: PCR_Event2:
+ NOTICE: PCRIndex : 0
+ NOTICE: EventType : 1
+ NOTICE: Digests Count : 1
+ NOTICE: #0 AlgorithmId : SHA256
+ NOTICE: Digest : 4e e4 8e 5a e6 50 ed e0 b5 a3 54 8a 1f d6 0e 8a
+ NOTICE: : ea 0e 71 75 0e a4 3f 82 76 ce af cd 7c b0 91 e0
+ NOTICE: EventSize : 14
+ NOTICE: Event : SOC_FW_CONFIG
+ NOTICE: PCR_Event2:
+ NOTICE: PCRIndex : 0
+ NOTICE: EventType : 1
+ NOTICE: Digests Count : 1
+ NOTICE: #0 AlgorithmId : SHA256
+ NOTICE: Digest : 01 b0 80 47 a1 ce 86 cd df 89 d2 1f 2e fc 6c 22
+ NOTICE: : f8 19 ec 6e 1e ec 73 ba 5a be d0 96 e3 5f 6d 75
+ NOTICE: EventSize : 6
+ NOTICE: Event : BL_32
+ NOTICE: PCR_Event2:
+ NOTICE: PCRIndex : 0
+ NOTICE: EventType : 1
+ NOTICE: Digests Count : 1
+ NOTICE: #0 AlgorithmId : SHA256
+ NOTICE: Digest : 5d c6 ef 35 5a 90 81 b4 37 e6 3b 52 da 92 ab 8e
+ NOTICE: : d9 6e 93 98 2d 40 87 96 1b 5a a7 ee f1 f4 40 63
+ NOTICE: EventSize : 18
+ NOTICE: Event : BL32_EXTRA1_IMAGE
+ NOTICE: PCR_Event2:
+ NOTICE: PCRIndex : 0
+ NOTICE: EventType : 1
+ NOTICE: Digests Count : 1
+ NOTICE: #0 AlgorithmId : SHA256
+ NOTICE: Digest : 39 b7 13 b9 93 db 32 2f 1b 48 30 eb 2c f2 5c 25
+ NOTICE: : 00 0f 38 dc 8e c8 02 cd 79 f2 48 d2 2c 25 ab e2
+ NOTICE: EventSize : 6
+ NOTICE: Event : BL_33
+ NOTICE: PCR_Event2:
+ NOTICE: PCRIndex : 0
+ NOTICE: EventType : 1
+ NOTICE: Digests Count : 1
+ NOTICE: #0 AlgorithmId : SHA256
+ NOTICE: Digest : 25 10 60 5d d4 bc 9d 82 7a 16 9f 8a cc 47 95 a6
+ NOTICE: : fd ca a0 c1 2b c9 99 8f 51 20 ff c6 ed 74 68 5a
+ NOTICE: EventSize : 13
+ NOTICE: Event : NT_FW_CONFIG
+ NOTICE: BL1: Booting BL31
+ NOTICE: BL31: v2.5(release):v2.5
+ NOTICE: BL31: Built : 10:41:20, Jul 2 2021
+
+Following up with the fTPM startup process, we can see that all the
+measurements in the Event Log are extended and recorded in the appropriate PCR:
+
+.. code:: shell
+
+ M/TA: TPM2_PCR_EXTEND_COMMAND returned value:
+ M/TA: ret_tag = 0x8002, size = 0x00000013, rc = 0x00000000
+ M/TA: TPM2_PCR_EXTEND_COMMAND returned value:
+ M/TA: ret_tag = 0x8002, size = 0x00000013, rc = 0x00000000
+ M/TA: TPM2_PCR_EXTEND_COMMAND returned value:
+ M/TA: ret_tag = 0x8002, size = 0x00000013, rc = 0x00000000
+ M/TA: TPM2_PCR_EXTEND_COMMAND returned value:
+ M/TA: ret_tag = 0x8002, size = 0x00000013, rc = 0x00000000
+ M/TA: TPM2_PCR_EXTEND_COMMAND returned value:
+ M/TA: ret_tag = 0x8002, size = 0x00000013, rc = 0x00000000
+ M/TA: TPM2_PCR_EXTEND_COMMAND returned value:
+ M/TA: ret_tag = 0x8002, size = 0x00000013, rc = 0x00000000
+ M/TA: TPM2_PCR_EXTEND_COMMAND returned value:
+ M/TA: ret_tag = 0x8002, size = 0x00000013, rc = 0x00000000
+ M/TA: TPM2_PCR_EXTEND_COMMAND returned value:
+ M/TA: ret_tag = 0x8002, size = 0x00000013, rc = 0x00000000
+ M/TA: TPM2_PCR_EXTEND_COMMAND returned value:
+ M/TA: ret_tag = 0x8002, size = 0x00000013, rc = 0x00000000
+ M/TA: 9 Event logs processed
+
+After the fTPM TA is loaded, the call to ``insmod`` issued by the ``ftpm``
+alias to load the ftpm kernel module returns, and then the TPM PCRs are read
+by means of ``tpm_pcrread`` command. Note that we are only interested in the
+SHA256 logs here, as this is the algorithm we used on TF-A for the measurements
+(see the field ``AlgorithmId`` on the logs above):
+
+.. code:: shell
+
+ sha256:
+ 0 : 0xA6EB3A7417B8CFA9EBA2E7C22AD5A4C03CDB8F3FBDD7667F9C3EF2EA285A8C9F
+ 1 : 0x0000000000000000000000000000000000000000000000000000000000000000
+ 2 : 0x0000000000000000000000000000000000000000000000000000000000000000
+ 3 : 0x0000000000000000000000000000000000000000000000000000000000000000
+ 4 : 0x0000000000000000000000000000000000000000000000000000000000000000
+ 5 : 0x0000000000000000000000000000000000000000000000000000000000000000
+ 6 : 0x0000000000000000000000000000000000000000000000000000000000000000
+ 7 : 0x0000000000000000000000000000000000000000000000000000000000000000
+ 8 : 0x0000000000000000000000000000000000000000000000000000000000000000
+ 9 : 0x0000000000000000000000000000000000000000000000000000000000000000
+ 10: 0x0000000000000000000000000000000000000000000000000000000000000000
+ 11: 0x0000000000000000000000000000000000000000000000000000000000000000
+ 12: 0x0000000000000000000000000000000000000000000000000000000000000000
+ 13: 0x0000000000000000000000000000000000000000000000000000000000000000
+ 14: 0x0000000000000000000000000000000000000000000000000000000000000000
+ 15: 0x0000000000000000000000000000000000000000000000000000000000000000
+ 16: 0x0000000000000000000000000000000000000000000000000000000000000000
+ 17: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ 18: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ 19: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ 20: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ 21: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ 22: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ 23: 0x0000000000000000000000000000000000000000000000000000000000000000
+
+In this PoC we are only interested in PCR0, which must be non-null. This is
+because the boot process records all the images in this PCR (see field ``PCRIndex``
+on the Event Log above). The rest of the records must be 0 at this point.
+
+.. note::
+ The fTPM service used has support only for 16 PCRs, therefore the content
+ of PCRs above 15 can be ignored.
+
+.. note::
+ As stated earlier, Arm does not provide an fTPM implementation and therefore
+ we do not validate here if the content of PCR0 is correct or not. For this
+ PoC, we are only focused on the fact that the event log could be passed to a third
+ party fTPM and its records were properly extended.
+
+Fine-tuning the fTPM TA
+~~~~~~~~~~~~~~~~~~~~~~~
+
+As stated earlier, the OP-TEE Toolkit includes support to build a third party fTPM
+service. The build options for this service are tailored for the PoC and defined in
+the build environment variable ``FTPM_FLAGS`` (see ``<toolkit_home>/build/common.mk``)
+but they can be modified if needed to better adapt it to a specific scenario.
+
+The most relevant options for Measured Boot support are:
+
+ - **CFG_TA_DEBUG**: Enables debug logs in the Terminal_1 console.
+ - **CFG_TEE_TA_LOG_LEVEL**: Defines the log level used for the debug messages.
+ - **CFG_TA_MEASURED_BOOT**: Enables support for measured boot on the fTPM.
+ - **CFG_TA_EVENT_LOG_SIZE**: Defines the size, in bytes, of the larger event log that
+ the fTPM is able to store, as this buffer is allocated at build time. This must be at
+ least the same as the size of the event log generated by TF-A. If this build option
+ is not defined, the fTPM falls back to a default value of 1024 bytes, which is enough
+ for this PoC, so this variable is not defined in FTPM_FLAGS.
+
+--------------
+
+*Copyright (c) 2021, Arm Limited. All rights reserved.*
+
+.. _OP-TEE Toolkit: https://github.com/OP-TEE/build
+.. _ms-tpm-20-ref: https://github.com/microsoft/ms-tpm-20-ref
+.. _Get and build the solution: https://optee.readthedocs.io/en/latest/building/gits/build.html#get-and-build-the-solution
+.. _Armv8-A Foundation Platform (For Linux Hosts Only): https://developer.arm.com/tools-and-software/simulation-models/fixed-virtual-platforms/arm-ecosystem-models
+.. _tpm2-tools: https://github.com/tpm2-software/tpm2-tools
+.. _TGC event log: https://trustedcomputinggroup.org/resource/tcg-efi-platform-specification/
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
new file mode 100644
index 0000000..402de13
--- /dev/null
+++ b/docs/getting_started/build-options.rst
@@ -0,0 +1,1164 @@
+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.
+
+.. _build_options_common:
+
+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 ``<aarch32_sp-value>.mk``.
+
+- ``AMU_RESTRICT_COUNTERS``: Register reads to the group 1 counters will return
+ zero at all but the highest implemented exception level. Reads from the
+ memory mapped view are unaffected by this control.
+
+- ``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_FEATURE``: Optional Arm Architecture build option which specifies
+ one or more feature modifiers. This option has the form ``[no]feature+...``
+ and defaults to ``none``. It translates into compiler option
+ ``-march=armvX[.Y]-a+[no]feature+...``. See compiler's documentation for the
+ list of supported feature modifiers.
+
+- ``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_ENABLE_SP_LOAD``: Boolean option to enable loading SP packages from the
+ FIP. Automatically enabled if ``SP_LAYOUT_FILE`` is provided.
+
+- ``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'.
+
+- ``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 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
+- 4: Turn on branch target identification mechanism
+
+ 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 |
+ +-------+--------------+-------+-----+
+ | 4 | bti | N | Y |
+ +-------+--------------+-------+-----+
+
+ This option defaults to 0.
+ 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.
+
+- ``BUILD_BASE``: Output directory for the build. Defaults to ``./build``
+
+- ``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.
+
+- ``COT``: When Trusted Boot is enabled, selects the desired chain of trust.
+ Defaults to ``tbbr``.
+
+- ``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_EL2_REGS`` : This boolean option provides context save/restore
+ operations when entering/exiting an EL2 execution context. This is of primary
+ interest when Armv8.4-SecEL2 extension is implemented. Default is 0 (disabled).
+ This option must be equal to 1 (enabled) when ``SPD=spmd`` and
+ ``SPMD_SPM_AT_SEL2`` is set.
+
+- ``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``: Numeric value to include Memory Tagging Extension
+ registers in cpu context. This must be enabled, if the platform wants to use
+ this feature in the Secure world and MTE is enabled at ELX. This flag can
+ take values 0 to 2, to align with the ``FEATURE_DETECTION`` mechanism.
+ Default value is 0.
+
+- ``CTX_INCLUDE_NEVE_REGS``: Numeric value, when set will cause the Armv8.4-NV
+ registers to be saved/restored when entering/exiting an EL2 execution
+ context. This flag can take values 0 to 2, to align with the
+ ``FEATURE_DETECTION`` mechanism. Default value is 0.
+
+- ``CTX_INCLUDE_PAUTH_REGS``: Numeric value to enable the 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. This flag can take values 0 to 2, to align with ``FEATURE_DETECTION``
+ mechanism. Default value is 0.
+
+ 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.
+
+- ``DECRYPTION_SUPPORT``: This build flag enables the user to select the
+ authenticated decryption algorithm to be used to decrypt firmware/s during
+ boot. It accepts 2 values: ``aes_gcm`` and ``none``. The default value of
+ this flag is ``none`` to disable firmware decryption which is an optional
+ feature as per TBBR.
+
+- ``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.
+
+- ``DISABLE_MTPMU``: Boolean option to disable FEAT_MTPMU if implemented
+ (Armv8.6 onwards). Its default value is 0 to keep consistency with platforms
+ that do not implement FEAT_MTPMU. For more information on FEAT_MTPMU,
+ check the latest Arm ARM.
+
+- ``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_AMU_AUXILIARY_COUNTERS``: Enables support for AMU auxiliary counters
+ (also known as group 1 counters). These are implementation-defined counters,
+ and as such require additional platform configuration. Default is 0.
+
+- ``ENABLE_AMU_FCONF``: Enables configuration of the AMU through FCONF, which
+ allows platforms with auxiliary counters to describe them via the
+ ``HW_CONFIG`` device tree blob. 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 enable 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_FEAT_AMUv1``: Numeric value to enable access to the HAFGRTR_EL2
+ (Hypervisor Activity Monitors Fine-Grained Read Trap Register) during EL2
+ to EL3 context save/restore operations. This flag can take the values 0 to 2,
+ to align with the ``FEATURE_DETECTION`` mechanism. It is an optional feature
+ available on v8.4 and onwards and must be set to either 1 or 2 alongside
+ ``ENABLE_FEAT_FGT``, to access the HAFGRTR_EL2 register.
+ Default value is ``0``.
+
+- ``ENABLE_FEAT_AMUv1p1``: Numeric value to enable the ``FEAT_AMUv1p1``
+ extension. ``FEAT_AMUv1p1`` is an optional feature available on Arm v8.6
+ onwards. This flag can take the values 0 to 2, to align with the
+ ``FEATURE_DETECTION`` mechanism. Default value is ``0``.
+
+- ``ENABLE_FEAT_CSV2_2``: Numeric value to enable the ``FEAT_CSV2_2``
+ extension. It allows access to the SCXTNUM_EL2 (Software Context Number)
+ register during EL2 context save/restore operations. ``FEAT_CSV2_2`` is an
+ optional feature available on Arm v8.0 onwards. This flag can take values
+ 0 to 2, to align with the ``FEATURE_DETECTION`` mechanism.
+ Default value is ``0``.
+
+- ``ENABLE_FEAT_DIT``: Numeric value to enable ``FEAT_DIT`` (Data Independent
+ Timing) extension. It allows setting the ``DIT`` bit of PSTATE in EL3.
+ ``FEAT_DIT`` is a mandatory architectural feature and is enabled from v8.4
+ and upwards. This flag can take the values 0 to 2, to align with the
+ ``FEATURE_DETECTION`` mechanism. Default value is ``0``.
+
+- ``ENABLE_FEAT_ECV``: Numeric value to enable support for the Enhanced Counter
+ Virtualization feature, allowing for access to the CNTPOFF_EL2 (Counter-timer
+ Physical Offset register) during EL2 to EL3 context save/restore operations.
+ Its a mandatory architectural feature and is enabled from v8.6 and upwards.
+ This flag can take the values 0 to 2, to align with the ``FEATURE_DETECTION``
+ mechanism. Default value is ``0``.
+
+- ``ENABLE_FEAT_FGT``: Numeric value to enable support for FGT (Fine Grain Traps)
+ feature allowing for access to the HDFGRTR_EL2 (Hypervisor Debug Fine-Grained
+ Read Trap Register) during EL2 to EL3 context save/restore operations.
+ Its a mandatory architectural feature and is enabled from v8.6 and upwards.
+ This flag can take the values 0 to 2, to align with the ``FEATURE_DETECTION``
+ mechanism. Default value is ``0``.
+
+- ``ENABLE_FEAT_HCX``: Numeric value to set the bit SCR_EL3.HXEn in EL3 to
+ allow access to HCRX_EL2 (extended hypervisor control register) from EL2 as
+ well as adding HCRX_EL2 to the EL2 context save/restore operations. Its a
+ mandatory architectural feature and is enabled from v8.7 and upwards. This
+ flag can take the values 0 to 2, to align with the ``FEATURE_DETECTION``
+ mechanism. Default value is ``0``.
+
+- ``ENABLE_FEAT_PAN``: Numeric value to enable the ``FEAT_PAN`` (Privileged
+ Access Never) extension. ``FEAT_PAN`` adds a bit to PSTATE, generating a
+ permission fault for any privileged data access from EL1/EL2 to virtual
+ memory address, accessible at EL0, provided (HCR_EL2.E2H=1). It is a
+ mandatory architectural feature and is enabled from v8.1 and upwards. This
+ flag can take values 0 to 2, to align with the ``FEATURE_DETECTION``
+ mechanism. Default value is ``0``.
+
+- ``ENABLE_FEAT_RNG``: Numeric value to enable the ``FEAT_RNG`` extension.
+ ``FEAT_RNG`` is an optional feature available on Arm v8.5 onwards. This
+ flag can take the values 0 to 2, to align with the ``FEATURE_DETECTION``
+ mechanism. Default value is ``0``.
+
+- ``ENABLE_FEAT_RNG_TRAP``: Numeric value to enable the ``FEAT_RNG_TRAP``
+ extension. This feature is only supported in AArch64 state. This flag can
+ take values 0 to 2, to align with the ``FEATURE_DETECTION`` mechanism.
+ Default value is ``0``. ``FEAT_RNG_TRAP`` is an optional feature from
+ Armv8.5 onwards.
+
+- ``ENABLE_FEAT_SB``: Numeric value to enable the ``FEAT_SB`` (Speculation
+ Barrier) extension allowing access to ``sb`` instruction. ``FEAT_SB`` is an
+ optional feature and defaults to ``0`` for pre-Armv8.5 CPUs but are mandatory
+ for Armv8.5 or later CPUs. This flag can take values 0 to 2, to align with
+ ``FEATURE_DETECTION`` mechanism. It is enabled from v8.5 and upwards and if
+ needed could be overidden from platforms explicitly. Default value is ``0``.
+
+- ``ENABLE_FEAT_SEL2``: Numeric value to enable the ``FEAT_SEL2`` (Secure EL2)
+ extension. ``FEAT_SEL2`` is a mandatory feature available on Arm v8.4.
+ This flag can take values 0 to 2, to align with the ``FEATURE_DETECTION``
+ mechanism. Default is ``0``.
+
+- ``ENABLE_FEAT_TWED``: Numeric value to enable the ``FEAT_TWED`` (Delayed
+ trapping of WFE Instruction) extension. ``FEAT_TWED`` is a optional feature
+ available on Arm v8.6. This flag can take values 0 to 2, to align with the
+ ``FEATURE_DETECTION`` mechanism. Default is ``0``.
+
+ When ``ENABLE_FEAT_TWED`` is set to ``1``, WFE instruction trapping gets
+ delayed by the amount of value in ``TWED_DELAY``.
+
+- ``ENABLE_FEAT_VHE``: Numeric value to enable the ``FEAT_VHE`` (Virtualization
+ Host Extensions) extension. It allows access to CONTEXTIDR_EL2 register
+ during EL2 context save/restore operations.``FEAT_VHE`` is a mandatory
+ architectural feature and is enabled from v8.1 and upwards. It can take
+ values 0 to 2, to align with the ``FEATURE_DETECTION`` mechanism.
+ Default value is ``0``.
+
+- ``ENABLE_LTO``: Boolean option to enable Link Time Optimization (LTO)
+ support in GCC for TF-A. This option is currently only supported for
+ AArch64. Default is 0.
+
+- ``ENABLE_MPAM_FOR_LOWER_ELS``: Numeric value 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.
+
+ This flag can take values 0 to 2, to align with the ``FEATURE_DETECTION``
+ mechanism. When this option is set to ``1`` or ``2``, 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_MPMM``: Boolean option to enable support for the Maximum Power
+ Mitigation Mechanism supported by certain Arm cores, which allows the SoC
+ firmware to detect and limit high activity events to assist in SoC processor
+ power domain dynamic power budgeting and limit the triggering of whole-rail
+ (i.e. clock chopping) responses to overcurrent conditions. Defaults to ``0``.
+
+- ``ENABLE_MPMM_FCONF``: Enables configuration of MPMM through FCONF, which
+ allows platforms with cores supporting MPMM to describe them via the
+ ``HW_CONFIG`` device tree blob. Default is 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 BL2_AT_EL3, BL31, and BL32 (TSP) for AARCH64 binaries, and in BL32
+ (SP_min) for AARCH32. 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_RME``: Numeric value to enable support for the ARMv9 Realm
+ Management Extension. This flag can take the values 0 to 2, to align with
+ the ``FEATURE_DETECTION`` mechanism. Default value is 0. This is currently
+ an experimental feature.
+
+- ``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_SME_FOR_NS``: Boolean option to enable Scalable Matrix Extension
+ (SME), SVE, and FPU/SIMD for the non-secure world only. These features share
+ registers so are enabled together. Using this option without
+ ENABLE_SME_FOR_SWD=1 will cause SME, SVE, and FPU/SIMD instructions in secure
+ world to trap to EL3. SME is an optional architectural feature for AArch64
+ and TF-A support is experimental. At this time, this build option cannot be
+ used on systems that have SPD=spmd/SPM_MM or ENABLE_RME, and attempting to
+ build with these options will fail. Default is 0.
+
+- ``ENABLE_SME_FOR_SWD``: Boolean option to enable the Scalable Matrix
+ Extension for secure world use along with SVE and FPU/SIMD, ENABLE_SME_FOR_NS
+ must also be set to use this. If enabling this, the secure world MUST
+ handle context switching for SME, SVE, and FPU/SIMD registers to ensure that
+ no data is leaked to non-secure world. This is experimental. 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_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 by
+ default and controlled with ENABLE_SVE_FOR_SWD.
+ 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 ENABLE_SME_FOR_NS=1
+ since SME encompasses SVE. At this time, this build option cannot be used on
+ systems that have SPM_MM enabled.
+
+- ``ENABLE_SVE_FOR_SWD``: Boolean option to enable SVE for the Secure world.
+ SVE is an optional architectural feature for AArch64. Note that this option
+ requires ENABLE_SVE_FOR_NS to be enabled. The default is 0 and it
+ 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``.
+
+- ``ENCRYPT_BL31``: Binary flag to enable encryption of BL31 firmware. This
+ flag depends on ``DECRYPTION_SUPPORT`` build flag.
+
+- ``ENCRYPT_BL32``: Binary flag to enable encryption of Secure BL32 payload.
+ This flag depends on ``DECRYPTION_SUPPORT`` build flag.
+
+- ``ENC_KEY``: A 32-byte (256-bit) symmetric key in hex string format. It could
+ either be SSK or BSSK depending on ``FW_ENC_STATUS`` flag. This value depends
+ on ``DECRYPTION_SUPPORT`` build flag.
+
+- ``ENC_NONCE``: A 12-byte (96-bit) encryption nonce or Initialization Vector
+ (IV) in hex string format. This value depends on ``DECRYPTION_SUPPORT``
+ build flag.
+
+- ``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. The exception to this rule is when
+ ``SPMD_SPM_AT_SEL2`` is set to ``1``, in which case, only exceptions
+ occuring during normal world execution, are trapped to EL3. Any exception
+ trapped during secure world execution are trapped to the SPMC. This is
+ supported only for AArch64 builds.
+
+- ``EVENT_LOG_LEVEL``: Chooses the log level to use for Measured Boot when
+ ``MEASURED_BOOT`` is enabled. For a list of valid values, see ``LOG_LEVEL``.
+ Default value is 40 (LOG_LEVEL_INFO).
+
+- ``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.
+
+- ``FEATURE_DETECTION``: Boolean option to enable the architectural features
+ detection mechanism. It detects whether the Architectural features enabled
+ through feature specific build flags are supported by the PE or not by
+ validating them either at boot phase or at runtime based on the value
+ possessed by the feature flag (0 to 2) and report error messages at an early
+ stage.
+
+ This prevents and benefits us from EL3 runtime exceptions during context save
+ and restore routines guarded by these build flags. Henceforth validating them
+ before their usage provides more control on the actions taken under them.
+
+ The mechanism permits the build flags to take values 0, 1 or 2 and
+ evaluates them accordingly.
+
+ Lets consider ``ENABLE_FEAT_HCX``, build flag for ``FEAT_HCX`` as an example:
+
+ ::
+
+ ENABLE_FEAT_HCX = 0: Feature disabled statically at compile time.
+ ENABLE_FEAT_HCX = 1: Feature Enabled and the flag is validated at boottime.
+ ENABLE_FEAT_HCX = 2: Feature Enabled and the flag is validated at runtime.
+
+ In the above example, if the feature build flag, ``ENABLE_FEAT_HCX`` set to
+ 0, feature is disabled statically during compilation. If it is defined as 1,
+ feature is validated, wherein FEAT_HCX is detected at boot time. In case not
+ implemented by the PE, a hard panic is generated. Finally, if the flag is set
+ to 2, feature is validated at runtime.
+
+ Note that the entire implementation is divided into two phases, wherein as
+ as part of phase-1 we are supporting the values 0,1. Value 2 is currently not
+ supported and is planned to be handled explicilty in phase-2 implementation.
+
+ FEATURE_DETECTION macro is disabled by default, and is currently an
+ experimental procedure. Platforms can explicitly make use of this by
+ mechanism, by enabling it to validate whether they have set their build flags
+ properly at an early phase.
+
+- ``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``.
+
+- ``FW_ENC_STATUS``: Top level firmware's encryption numeric flag, values:
+
+ ::
+
+ 0: Encryption is done with Secret Symmetric Key (SSK) which is common
+ for a class of devices.
+ 1: Encryption is done with Binding Secret Symmetric Key (BSSK) which is
+ unique per device.
+
+ This flag depends on ``DECRYPTION_SUPPORT`` build flag.
+
+- ``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 :ref:`platform abstraction layer<platform Interrupt Controller API>` and
+ :ref:`Interrupt Management Framework<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.
+
+- ``HANDLE_EA_EL3_FIRST_NS``: When set to ``1``, External Aborts and SError
+ Interrupts, resulting from errors in NS world, 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.
+
+- ``INVERTED_MEMMAP``: memmap tool print by default lower addresses at the
+ bottom, higher addresses at the top. This build flag can be set to '1' to
+ invert this behavior. Lower addresses will be printed at the top and higher
+ addresses at the bottom.
+
+- ``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 5 values: ``rsa``, ``rsa_1_5``, ``ecdsa``, ``ecdsa-brainpool-regular``
+ and ``ecdsa-brainpool-twisted``. The option ``rsa_1_5`` is the legacy PKCS#1
+ RSA 1.5 algorithm which is not TBBR compliant and is retained only for
+ compatibility. 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 and the cryptographic module.
+
+ +---------------------------+------------------------------------+
+ | KEY_ALG | Possible key sizes |
+ +===========================+====================================+
+ | rsa | 1024 , 2048 (default), 3072, 4096* |
+ +---------------------------+------------------------------------+
+ | ecdsa | unavailable |
+ +---------------------------+------------------------------------+
+ | ecdsa-brainpool-regular | unavailable |
+ +---------------------------+------------------------------------+
+ | ecdsa-brainpool-twisted | unavailable |
+ +---------------------------+------------------------------------+
+
+
+ * Only 2048 bits size is available with CryptoCell 712 SBROM release 1.
+ Only 3072 bits size is available with CryptoCell 712 SBROM release 2.
+
+- ``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.
+
+- ``MEASURED_BOOT``: Boolean flag to include support for the Measured Boot
+ feature. This flag can be enabled with ``TRUSTED_BOARD_BOOT`` in order to
+ provide trust that the code taking the measurements and recording them has
+ not been tampered with.
+
+ This option defaults to 0.
+
+- ``DRTM_SUPPORT``: Boolean flag to enable support for Dynamic Root of Trust
+ for Measurement (DRTM). This feature has trust dependency on BL31 for taking
+ the measurements and recording them as per `PSA DRTM specification`_. For
+ platforms which use BL2 to load/authenticate BL31 ``TRUSTED_BOARD_BOOT`` can
+ be used and for the platforms which use ``RESET_TO_BL31`` platform owners
+ should have mechanism to authenticate BL31.
+
+ This option defaults to 0.
+
+- ``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``: Numeric value to 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. This flag can take the values 0 to 2, to align with the
+ ``FEATURE_DETECTION`` mechanism.
+
+ When ``RAS_EXTENSION`` is set to ``1``, ``HANDLE_EA_EL3_FIRST_NS`` 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_BL31_WITH_PARAMS``: If ``RESET_TO_BL31`` has been enabled, setting
+ this additional option guarantees that the input registers are not cleared
+ therefore allowing parameters to be passed to the 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 and enforces public key
+ hash generation. If ``SAVE_KEYS=1``, this
+ file name will be used to save the key.
+
+- ``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.
+
+- ``SEPARATE_NOBITS_REGION``: Setting this option to ``1`` allows the NOBITS
+ sections of BL31 (.bss, stacks, page tables, and coherent memory) to be
+ allocated in RAM discontiguous from the loaded firmware image. When set, the
+ platform is expected to provide definitions for ``BL31_NOBITS_BASE`` and
+ ``BL31_NOBITS_LIMIT``. When the option is ``0`` (the default), NOBITS
+ sections are placed in RAM immediately following the loaded firmware image.
+
+- ``SEPARATE_BL2_NOLOAD_REGION``: Setting this option to ``1`` allows the
+ NOLOAD sections of BL2 (.bss, stacks, page tables) to be allocated in RAM
+ discontiguous from loaded firmware images. When set, the platform need to
+ provide definitions of ``BL2_NOLOAD_START`` and ``BL2_NOLOAD_LIMIT``. This
+ flag is disabled by default and NOLOAD sections are placed in RAM immediately
+ following the loaded firmware image.
+
+- ``SMC_PCI_SUPPORT``: This option allows platforms to handle PCI configuration
+ access requests via a standard SMCCC defined in `DEN0115`_. When combined with
+ UEFI+ACPI this can provide a certain amount of OS forward compatibility
+ with newer platforms that aren't ECAM compliant.
+
+- ``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
+ ``<spd-value>.mk``. The SPM Dispatcher standard service is located in
+ services/std_svc/spmd and enabled by ``SPD=spmd``. The SPM Dispatcher
+ cannot be enabled when the ``SPM_MM`` option is enabled.
+
+- ``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.
+
+- ``SPMC_AT_EL3`` : This boolean option is used jointly with the SPM
+ Dispatcher option (``SPD=spmd``). When enabled (1) it indicates the SPMC
+ component runs at the EL3 exception level. The default value is ``0`` (
+ disabled). This configuration supports pre-Armv8.4 platforms (aka not
+ implementing the ``FEAT_SEL2`` extension). This is an experimental feature.
+
+- ``SPMD_SPM_AT_SEL2`` : This boolean option is used jointly with the SPM
+ Dispatcher option (``SPD=spmd``). When enabled (1) it indicates the SPMC
+ component runs at the S-EL2 exception level provided by the ``FEAT_SEL2``
+ extension. This is the default when enabling the SPM Dispatcher. When
+ disabled (0) it indicates the SPMC component runs at the S-EL1 execution
+ state or at EL3 if ``SPMC_AT_EL3`` is enabled. The latter configurations
+ support pre-Armv8.4 platforms (aka not implementing the ``FEAT_SEL2``
+ extension).
+
+- ``SPM_MM`` : Boolean option to enable the Management Mode (MM)-based Secure
+ Partition Manager (SPM) implementation. The default value is ``0``
+ (disabled). This option cannot be enabled (``1``) when SPM Dispatcher is
+ enabled (``SPD=spmd``).
+
+- ``SP_LAYOUT_FILE``: Platform provided path to JSON file containing the
+ description of secure partitions. The build system will parse this file and
+ package all secure partition blobs into the FIP. This file is not
+ necessarily part of TF-A tree. Only available when ``SPD=spmd``.
+
+- ``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.
+
+- ``SVE_VECTOR_LEN``: SVE vector length to configure in ZCR_EL3.
+ Platforms can configure this if they need to lower the hardware
+ limit, for example due to asymmetric configuration or limitations of
+ software run at lower ELs. The default is the architectural maximum
+ of 2048 which should be suitable for most configurations, the
+ hardware will limit the effective VL to the maximum physically supported
+ VL.
+
+- ``TRNG_SUPPORT``: Setting this to ``1`` enables support for True
+ Random Number Generator Interface to BL31 image. This defaults to ``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``.
+
+- ``TWED_DELAY``: Numeric value to be set in order to delay the trapping of
+ WFE instruction. ``ENABLE_FEAT_TWED`` build option must be enabled to set
+ this delay. It can take values in the range (0-15). Default value is ``0``
+ and based on this value, 2^(TWED_DELAY + 8) cycles will be delayed.
+ Platforms need to explicitly update this value based on their requirements.
+
+- ``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_DEBUGFS``: When set to 1 this option activates an EXPERIMENTAL feature
+ exposing a virtual filesystem interface through BL31 as a SiP SMC function.
+ Default is 0.
+
+- ``ARM_IO_IN_DTB``: This flag determines whether to use IO based on the
+ firmware configuration framework. This will move the io_policies into a
+ configuration device tree, instead of static structure in the code base.
+
+- ``COT_DESC_IN_DTB``: This flag determines whether to create COT descriptors
+ at runtime using fconf. If this flag is enabled, COT descriptors are
+ statically captured in tb_fw_config file in the form of device tree nodes
+ and properties. Currently, COT descriptors used by BL2 are moved to the
+ device tree and COT descriptors used by BL1 are retained in the code
+ base statically.
+
+- ``SDEI_IN_FCONF``: This flag determines whether to configure SDEI setup in
+ runtime using firmware configuration framework. The platform specific SDEI
+ shared and private events configuration is retrieved from device tree rather
+ than static C structures at compile time. This is only supported if
+ SDEI_SUPPORT build flag is enabled.
+
+- ``SEC_INT_DESC_IN_FCONF``: This flag determines whether to configure Group 0
+ and Group1 secure interrupts using the firmware configuration framework. The
+ platform specific secure interrupt property descriptor is retrieved from
+ device tree in runtime rather than depending on static C structure at compile
+ time.
+
+- ``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.
+
+- ``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.
+
+- ``SUPPORT_STACK_MEMTAG``: This flag determines whether to enable memory
+ tagging for stack or not. It accepts 2 values: ``yes`` and ``no``. The
+ default value of this flag is ``no``. Note this option must be enabled only
+ for ARM architecture greater than Armv8.5-A.
+
+- ``ERRATA_SPECULATIVE_AT``: This flag determines whether to enable ``AT``
+ speculative errata workaround or not. It accepts 2 values: ``1`` and ``0``.
+ The default value of this flag is ``0``.
+
+ ``AT`` speculative errata workaround disables stage1 page table walk for
+ lower ELs (EL1 and EL0) in EL3 so that ``AT`` speculative fetch at any point
+ produces either the correct result or failure without TLB allocation.
+
+ This boolean option enables errata for all below CPUs.
+
+ +---------+--------------+-------------------------+
+ | Errata | CPU | Workaround Define |
+ +=========+==============+=========================+
+ | 1165522 | Cortex-A76 | ``ERRATA_A76_1165522`` |
+ +---------+--------------+-------------------------+
+ | 1319367 | Cortex-A72 | ``ERRATA_A72_1319367`` |
+ +---------+--------------+-------------------------+
+ | 1319537 | Cortex-A57 | ``ERRATA_A57_1319537`` |
+ +---------+--------------+-------------------------+
+ | 1530923 | Cortex-A55 | ``ERRATA_A55_1530923`` |
+ +---------+--------------+-------------------------+
+ | 1530924 | Cortex-A53 | ``ERRATA_A53_1530924`` |
+ +---------+--------------+-------------------------+
+
+ .. note::
+ This option is enabled by build only if platform sets any of above defines
+ mentioned in ’Workaround Define' column in the table.
+ If this option is enabled for the EL3 software then EL2 software also must
+ implement this workaround due to the behaviour of the errata mentioned
+ in new SDEN document which will get published soon.
+
+- ``RAS_TRAP_NS_ERR_REC_ACCESS``: This flag enables/disables the SCR_EL3.TERR
+ bit, to trap access to the RAS ERR and RAS ERX registers from lower ELs.
+ This flag is disabled by default.
+
+- ``OPENSSL_DIR``: This option is used to provide the path to a directory on the
+ host machine where a custom installation of OpenSSL is located, which is used
+ to build the certificate generation, firmware encryption and FIP tools. If
+ this option is not set, the default OS installation will be used.
+
+- ``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.
+
+- ``ENABLE_BRBE_FOR_NS``: Numeric value to enable access to the branch record
+ buffer registers from NS ELs when FEAT_BRBE is implemented. BRBE is an
+ optional architectural feature for AArch64. This flag can take the values
+ 0 to 2, to align with the ``FEATURE_DETECTION`` mechanism. The default is 0
+ and it is automatically disabled when the target architecture is AArch32.
+
+- ``ENABLE_TRBE_FOR_NS``: Numeric value to enable access of trace buffer
+ control registers from NS ELs, NS-EL2 or NS-EL1(when NS-EL2 is implemented
+ but unused) when FEAT_TRBE is implemented. TRBE is an optional architectural
+ feature for AArch64. This flag can take the values 0 to 2, to align with the
+ ``FEATURE_DETECTION`` mechanism. The default is 0 and it is automatically
+ disabled when the target architecture is AArch32.
+
+- ``ENABLE_SYS_REG_TRACE_FOR_NS``: Boolean option to enable trace system
+ registers access from NS ELs, NS-EL2 or NS-EL1 (when NS-EL2 is implemented
+ but unused). This feature is available if trace unit such as ETMv4.x, and
+ ETE(extending ETM feature) is implemented. This flag is disabled by default.
+
+- ``ENABLE_TRF_FOR_NS``: Numeric value to enable trace filter control registers
+ access from NS ELs, NS-EL2 or NS-EL1 (when NS-EL2 is implemented but unused),
+ if FEAT_TRF is implemented. This flag can take the values 0 to 2, to align
+ with the ``FEATURE_DETECTION`` mechanism. This flag is disabled by default.
+
+- ``PLAT_RSS_NOT_SUPPORTED``: Boolean option to enable the usage of the PSA
+ APIs on platforms that doesn't support RSS (providing Arm CCA HES
+ functionalities). When enabled (``1``), a mocked version of the APIs are used.
+ The default value is 0.
+
+- ``CONDITIONAL_CMO``: Boolean option to enable call to platform-defined routine
+ ``plat_can_cmo`` which will return zero if cache management operations should
+ be skipped and non-zero otherwise. By default, this option is disabled which
+ means platform hook won't be checked and CMOs will always be performed when
+ related functions are called.
+
+GICv3 driver options
+--------------------
+
+GICv3 driver files are included using directive:
+
+``include drivers/arm/gic/v3/gicv3.mk``
+
+The driver can be configured with the following options set in the platform
+makefile:
+
+- ``GICV3_SUPPORT_GIC600``: Add support for the GIC-600 variants of GICv3.
+ Enabling this option will add runtime detection support for the
+ GIC-600, so is safe to select even for a GIC500 implementation.
+ This option defaults to 0.
+
+- ``GICV3_SUPPORT_GIC600AE_FMU``: Add support for the Fault Management Unit
+ for GIC-600 AE. Enabling this option will introduce support to initialize
+ the FMU. Platforms should call the init function during boot to enable the
+ FMU and its safety mechanisms. This option defaults to 0.
+
+- ``GICV3_IMPL_GIC600_MULTICHIP``: Selects GIC-600 variant with multichip
+ functionality. This option defaults to 0
+
+- ``GICV3_OVERRIDE_DISTIF_PWR_OPS``: Allows override of default implementation
+ of ``arm_gicv3_distif_pre_save`` and ``arm_gicv3_distif_post_restore``
+ functions. This is required for FVP platform which need to simulate GIC save
+ and restore during SYSTEM_SUSPEND without powering down GIC. Default is 0.
+
+- ``GIC_ENABLE_V4_EXTN`` : Enables GICv4 related changes in GICv3 driver.
+ This option defaults to 0.
+
+- ``GIC_EXT_INTID``: When set to ``1``, GICv3 driver will support extended
+ PPI (1056-1119) and SPI (4096-5119) range. This option defaults to 0.
+
+Debugging options
+-----------------
+
+To compile a debug version and make the build more verbose use
+
+.. code:: shell
+
+ make PLAT=<platform> DEBUG=1 V=1 all
+
+AArch64 GCC 11 uses DWARF version 5 debugging symbols by default. Some tools
+(for example Arm-DS) 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-<version>`` flag, with the version being set to 2, 3, 4 or 5. Setting
+the version to 4 is recommended for Arm-DS.
+
+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=<platform> 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 :ref:`build_options_common`
+section. In this case, the developer may take control of the target using a
+debugger when indicated by the console output. When using Arm-DS, 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
+
+Firmware update options
+-----------------------
+
+- ``NR_OF_FW_BANKS``: Define the number of firmware banks. This flag is used
+ in defining the firmware update metadata structure. This flag is by default
+ set to '2'.
+
+- ``NR_OF_IMAGES_IN_FW_BANK``: Define the number of firmware images in each
+ firmware bank. Each firmware bank must have the same number of images as per
+ the `PSA FW update specification`_.
+ This flag is used in defining the firmware update metadata structure. This
+ flag is by default set to '1'.
+
+- ``PSA_FWU_SUPPORT``: Enable the firmware update mechanism as per the
+ `PSA FW update specification`_. The default value is 0, and this is an
+ experimental feature.
+ PSA firmware update implementation has some limitations, such as BL2 is
+ not part of the protocol-updatable images, if BL2 needs to be updated, then
+ it should be done through another platform-defined mechanism, and it assumes
+ that the platform's hardware supports CRC32 instructions.
+
+--------------
+
+*Copyright (c) 2019-2022, Arm Limited. All rights reserved.*
+
+.. _DEN0115: https://developer.arm.com/docs/den0115/latest
+.. _PSA FW update specification: https://developer.arm.com/documentation/den0118/a/
+.. _PSA DRTM specification: https://developer.arm.com/documentation/den0113/a
diff --git a/docs/getting_started/docs-build.rst b/docs/getting_started/docs-build.rst
new file mode 100644
index 0000000..4a48059
--- /dev/null
+++ b/docs/getting_started/docs-build.rst
@@ -0,0 +1,112 @@
+Building 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:
+
+- Python 3 (3.5 or later)
+- PlantUML (1.2017.15 or later)
+- Python modules specified in ``docs/requirements.txt``
+
+ You can install these with ``pip3`` (the Python Package Installer) by
+ passing it the requirements file above (with ``-r``). An optional ``--user``
+ argument will install them locally, but you have to add their location to
+ $PATH (pip will emit a warning). Alternatively, they can be installed
+ globally (but will probably require root privileges).
+
+ .. note::
+ Although not necessary, it is recommended you use a virtual environment.
+ More advanced usage instructions for *pip* are beyond the scope of this
+ document but you can refer to the `pip homepage`_ for detailed guides.
+
+- Optionally, the `Dia`_ application can be installed if you need to edit
+ existing ``.dia`` diagram files, or create new ones.
+
+An example set of installation commands for Ubuntu follows, assuming that the
+working directory is ``docs``:
+
+.. code:: shell
+
+ sudo apt install python3 python3-pip plantuml [dia]
+ 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.
+
+Building rendered documentation
+-------------------------------
+
+Documents can be built into HTML-formatted pages from project root directory by
+running the following command.
+
+.. code:: shell
+
+ make doc
+
+Output from the build process will be placed in:
+
+::
+
+ docs/build/html
+
+We also support building documentation in other formats. From the ``docs``
+directory of the project, run the following command to see the supported
+formats. It is important to note that you will not get the correct result if
+the command is run from the project root directory, as that would invoke the
+top-level Makefile for |TF-A| itself.
+
+.. code:: shell
+
+ make help
+
+Building rendered documentation from a container
+------------------------------------------------
+
+There may be cases where you can not either install or upgrade required
+dependencies to generate the documents, so in this case, one way to
+create the documentation is through a docker container. The first step is
+to check if `docker`_ is installed in your host, otherwise check main docker
+page for installation instructions. Once installed, run the following script
+from project root directory
+
+.. code:: shell
+
+ docker run --rm -v $PWD:/TF sphinxdoc/sphinx \
+ bash -c 'cd /TF && \
+ pip3 install plantuml -r ./docs/requirements.txt && make doc'
+
+The above command fetches the ``sphinxdoc/sphinx`` container from `docker
+hub`_, launches the container, installs documentation requirements and finally
+creates the documentation. Once done, exit the container and 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/
+.. _Dia: https://wiki.gnome.org/Apps/Dia
+.. _docker: https://www.docker.com/
+.. _docker hub: https://hub.docker.com/repository/docker/sphinxdoc/sphinx
diff --git a/docs/getting_started/image-terminology.rst b/docs/getting_started/image-terminology.rst
new file mode 100644
index 0000000..66f47e8
--- /dev/null
+++ b/docs/getting_started/image-terminology.rst
@@ -0,0 +1,192 @@
+Image Terminology
+=================
+
+This page contains the current name, abbreviated name and purpose of the various
+images referred to in the Trusted Firmware project.
+
+Common Image Features
+---------------------
+
+- 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
+-----------------------
+
+Firmware Image Package: ``FIP``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This 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).
+
+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``.
+
+Realm Monitor Management Firmware: ``RMM``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the Realm-EL2 firmware. It is required if
+:ref:`Realm Management Extension (RME)` feature is enabled. If a path to RMM
+image is not provided, TF-A builds Test Realm Payload (TRP) image by default
+and uses it as the RMM image.
+
+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``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/getting_started/index.rst b/docs/getting_started/index.rst
new file mode 100644
index 0000000..3fbf48d
--- /dev/null
+++ b/docs/getting_started/index.rst
@@ -0,0 +1,20 @@
+Getting Started
+===============
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents
+
+ prerequisites
+ docs-build
+ initial-build
+ tools-build
+ build-options
+ image-terminology
+ porting-guide
+ psci-lib-integration-guide
+ rt-svc-writers-guide
+
+--------------
+
+*Copyright (c) 2019, Arm Limited. All rights reserved.*
diff --git a/docs/getting_started/initial-build.rst b/docs/getting_started/initial-build.rst
new file mode 100644
index 0000000..4f41be4
--- /dev/null
+++ b/docs/getting_started/initial-build.rst
@@ -0,0 +1,118 @@
+Performing an Initial Build
+===========================
+
+- Before building TF-A, the environment variable ``CROSS_COMPILE`` must point
+ to your cross compiler.
+
+ For AArch64:
+
+ .. code:: shell
+
+ export CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-none-elf-
+
+ For AArch32:
+
+ .. code:: shell
+
+ export CROSS_COMPILE=<path-to-aarch32-gcc>/bin/arm-none-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. Arm Compiler 6 will be selected
+ when the base name of the path assigned to ``CC`` matches the string
+ 'armclang'. GNU binutils are required since the TF-A build system doesn't
+ currently support Arm Scatter files. Meaning the GNU linker is used by
+ default for Arm Compiler 6. Because of this dependency, ``CROSS_COMPILE``
+ should be set as described above.
+
+ For AArch64 using Arm Compiler 6:
+
+ .. code:: shell
+
+ export CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-none-elf-
+ make CC=<path-to-armclang>/bin/armclang PLAT=<platform> all
+
+ On the other hand, Clang uses LLVM linker (LLD) and other LLVM binutils by
+ default instead of GNU utilities (LLVM linker (LLD) 14.0.0 is known to
+ work with TF-A). ``CROSS_COMPILE`` need not be set for Clang. Please note,
+ that the default linker may be manually overridden using the ``LD`` variable.
+
+ 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
+
+ make CC=<path-to-clang>/bin/clang PLAT=<platform> all
+
+- Change to the root directory of the TF-A source tree and build.
+
+ For AArch64:
+
+ .. code:: shell
+
+ make PLAT=<platform> all
+
+ For AArch32:
+
+ .. code:: shell
+
+ make PLAT=<platform> ARCH=aarch32 AARCH32_SP=sp_min all
+
+ Notes:
+
+ - If ``PLAT`` is not specified, ``fvp`` is assumed by default. See the
+ :ref:`Build Options` document for more information on available build
+ options.
+
+ - (AArch32 only) Currently only ``PLAT=fvp`` is supported.
+
+ - (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
+ :ref:`Test Secure Payload (TSP) and Dispatcher (TSPD)` document for
+ details on building the TSP.
+
+ - 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/<platform>/<build-type>/bl1.bin``
+ - ``build/<platform>/<build-type>/bl2.bin``
+ - ``build/<platform>/<build-type>/bl31.bin`` (AArch64 only)
+ - ``build/<platform>/<build-type>/bl32.bin`` (mandatory for AArch32)
+
+ where ``<platform>`` is the name of the chosen platform and ``<build-type>``
+ 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=<D> PLAT=<platform> clean
+
+ ... where ``<D>`` is ``0`` or ``1``, as specified when building.
+
+ The build tree can be removed completely using:
+
+ .. code:: shell
+
+ make realclean
+
+--------------
+
+*Copyright (c) 2020-2022, Arm Limited. All rights reserved.*
diff --git a/docs/getting_started/porting-guide.rst b/docs/getting_started/porting-guide.rst
new file mode 100644
index 0000000..aa57e1d
--- /dev/null
+++ b/docs/getting_started/porting-guide.rst
@@ -0,0 +1,3515 @@
+Porting 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.
+
+Please refer to the :ref:`Platform Ports 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.
+
+.. _platform_def_mandatory:
+
+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 bytes 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.
+
+- **#define : PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE**
+
+ Defines the maximum message size between AP and RSS. Need to define if
+ platform supports RSS.
+
+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 DRTM feature, the following constants must be
+defined:
+
+- **#define : PLAT_DRTM_EVENT_LOG_MAX_SIZE**
+
+ Maximum Event Log size used by the platform. Platform can decide the maximum
+ size of the Event Log buffer, depending upon the highest hash algorithm
+ chosen and the number of components selected to measure during the DRTM
+ execution flow.
+
+- **#define : PLAT_DRTM_MMAP_ENTRIES**
+
+ Number of the MMAP entries used by the DRTM implementation to calculate the
+ size of address map region of the platform.
+
+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/<plat_name>/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.
+
+Function: plat_convert_pk()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void *, unsigned int, void **, unsigned int *
+ Return : int
+
+This function is optional when Trusted Board Boot is enabled, and only
+used if the platform saves a hash of the ROTPK.
+First argument is the Distinguished Encoding Rules (DER) ROTPK.
+Second argument is its size.
+Third argument is used to return a pointer to a buffer, which hash should
+be the one saved in OTP.
+Fourth argument is a pointer to return its size.
+
+Most platforms save the hash of the ROTPK, but some may save slightly different
+information - e.g the hash of the ROTPK plus some related information.
+Defining this function allows to transform the ROTPK used to verify
+the signature to the buffer (a platform specific public key) which
+hash is saved in OTP.
+
+The default implementation copies the input key and length to the output without
+modification.
+
+The function returns 0 on success. Any other value means the expected
+public key buffer cannot be extracted.
+
+Dynamic Root of Trust for Measurement support (in BL31)
+-------------------------------------------------------
+
+The functions mentioned in this section are mandatory, when platform enables
+DRTM_SUPPORT build flag.
+
+Function : plat_get_addr_mmap()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : const mmap_region_t *
+
+This function is used to return the address of the platform *address-map* table,
+which describes the regions of normal memory, memory mapped I/O
+and non-volatile memory.
+
+Function : plat_has_non_host_platforms()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : bool
+
+This function returns *true* if the platform has any trusted devices capable of
+DMA, otherwise returns *false*.
+
+Function : plat_has_unmanaged_dma_peripherals()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : bool
+
+This function returns *true* if platform uses peripherals whose DMA is not
+managed by an SMMU, otherwise returns *false*.
+
+Note -
+If the platform has peripherals that are not managed by the SMMU, then the
+platform should investigate such peripherals to determine whether they can
+be trusted, and such peripherals should be moved under "Non-host platforms"
+if they can be trusted.
+
+Function : plat_get_total_num_smmus()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : unsigned int
+
+This function returns the total number of SMMUs in the platform.
+
+Function : plat_enumerate_smmus()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+::
+
+
+ Argument : void
+ Return : const uintptr_t *, size_t
+
+This function returns an array of SMMU addresses and the actual number of SMMUs
+reported by the platform.
+
+Function : plat_drtm_get_dma_prot_features()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : const plat_drtm_dma_prot_features_t*
+
+This function returns the address of plat_drtm_dma_prot_features_t structure
+containing the maximum number of protected regions and bitmap with the types
+of DMA protection supported by the platform.
+For more details see section 3.3 Table 6 of `DRTM`_ specification.
+
+Function : plat_drtm_dma_prot_get_max_table_bytes()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : uint64_t
+
+This function returns the maximum size of DMA protected regions table in
+bytes.
+
+Function : plat_drtm_get_tpm_features()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : const plat_drtm_tpm_features_t*
+
+This function returns the address of *plat_drtm_tpm_features_t* structure
+containing PCR usage schema, TPM-based hash, and firmware hash algorithm
+supported by the platform.
+
+Function : plat_drtm_get_min_size_normal_world_dce()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : uint64_t
+
+This function returns the size normal-world DCE of the platform.
+
+Function : plat_drtm_get_imp_def_dlme_region_size()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : uint64_t
+
+This function returns the size of implementation defined DLME region
+of the platform.
+
+Function : plat_drtm_get_tcb_hash_table_size()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : uint64_t
+
+This function returns the size of TCB hash table of the platform.
+
+Function : plat_drtm_get_tcb_hash_features()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : uint64_t
+
+This function returns the Maximum number of TCB hashes recorded by the
+platform.
+For more details see section 3.3 Table 6 of `DRTM`_ specification.
+
+Function : plat_drtm_validate_ns_region()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : uintptr_t, uintptr_t
+ Return : int
+
+This function validates that given region is within the Non-Secure region
+of DRAM. This function takes a region start address and size an input
+arguments, and returns 0 on success and -1 on failure.
+
+Function : plat_set_drtm_error()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : uint64_t
+ Return : int
+
+This function writes a 64 bit error code received as input into
+non-volatile storage and returns 0 on success and -1 on failure.
+
+Function : plat_get_drtm_error()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : uint64_t*
+ Return : int
+
+This function reads a 64 bit error code from the non-volatile storage
+into the received address, and returns 0 on success and -1 on failure.
+
+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.
+
+Function : plat_get_enc_key_info() [when FW_ENC_STATUS == 0 or 1]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Arguments : enum fw_enc_status_t fw_enc_status, uint8_t *key,
+ size_t *key_len, unsigned int *flags, const uint8_t *img_id,
+ size_t img_id_len
+ Return : int
+
+This function provides a symmetric key (either SSK or BSSK depending on
+fw_enc_status) which is invoked during runtime decryption of encrypted
+firmware images. `plat/common/plat_bl_common.c` provides a dummy weak
+implementation for testing purposes which must be overridden by the platform
+trying to implement a real world firmware encryption use-case.
+
+It also allows the platform to pass symmetric key identifier rather than
+actual symmetric key which is useful in cases where the crypto backend provides
+secure storage for the symmetric key. So in this case ``ENC_KEY_IS_IDENTIFIER``
+flag must be set in ``flags``.
+
+In addition to above a platform may also choose to provide an image specific
+symmetric key/identifier using img_id.
+
+On success the function should return 0 and a negative error code otherwise.
+
+Note that this API depends on ``DECRYPTION_SUPPORT`` build flag.
+
+Function : plat_fwu_set_images_source() [when PSA_FWU_SUPPORT == 1]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : const struct fwu_metadata *metadata
+ Return : void
+
+This function is mandatory when PSA_FWU_SUPPORT is enabled.
+It provides a means to retrieve image specification (offset in
+non-volatile storage and length) of active/updated images using the passed
+FWU metadata, and update I/O policies of active/updated images using retrieved
+image specification information.
+Further I/O layer operations such as I/O open, I/O read, etc. on these
+images rely on this function call.
+
+In Arm platforms, this function is used to set an I/O policy of the FIP image,
+container of all active/updated secure and non-secure images.
+
+Function : plat_fwu_set_metadata_image_source() [when PSA_FWU_SUPPORT == 1]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : unsigned int image_id, uintptr_t *dev_handle,
+ uintptr_t *image_spec
+ Return : int
+
+This function is mandatory when PSA_FWU_SUPPORT is enabled. It is
+responsible for setting up the platform I/O policy of the requested metadata
+image (either FWU_METADATA_IMAGE_ID or BKUP_FWU_METADATA_IMAGE_ID) that will
+be used to load this image from the platform's non-volatile storage.
+
+FWU metadata can not be always stored as a raw image in non-volatile storage
+to define its image specification (offset in non-volatile storage and length)
+statically in I/O policy.
+For example, the FWU metadata image is stored as a partition inside the GUID
+partition table image. Its specification is defined in the partition table
+that needs to be parsed dynamically.
+This function provides a means to retrieve such dynamic information to set
+the I/O policy of the FWU metadata image.
+Further I/O layer operations such as I/O open, I/O read, etc. on FWU metadata
+image relies on this function call.
+
+It returns '0' on success, otherwise a negative error value on error.
+Alongside, returns device handle and image specification from the I/O policy
+of the requested FWU metadata image.
+
+Function : plat_fwu_get_boot_idx() [when PSA_FWU_SUPPORT == 1]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : uint32_t
+
+This function is mandatory when PSA_FWU_SUPPORT is enabled. It provides the
+means to retrieve the boot index value from the platform. The boot index is the
+bank from which the platform has booted the firmware images.
+
+By default, the platform will read the metadata structure and try to boot from
+the active bank. If the platform fails to boot from the active bank due to
+reasons like an Authentication failure, or on crossing a set number of watchdog
+resets while booting from the active bank, the platform can then switch to boot
+from a different bank. This function then returns the bank that the platform
+should boot its images from.
+
+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_system_reset()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : void
+
+This function is used by the platform to resets the system. It can be used
+in any specific use-case where system needs to be resetted. For example,
+in case of DRTM implementation this function reset the system after
+writing the DRTM error code in the non-volatile storage. This function
+never returns. Failure in reset results in panic.
+
+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.
+
+Function : plat_get_soc_version()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : int32_t
+
+This function returns soc version which mainly consist of below fields
+
+::
+
+ soc_version[30:24] = JEP-106 continuation code for the SiP
+ soc_version[23:16] = JEP-106 identification code with parity bit for the SiP
+ soc_version[15:0] = Implementation defined SoC ID
+
+Function : plat_get_soc_revision()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : int32_t
+
+This function returns soc revision in below format
+
+::
+
+ soc_revision[0:30] = SOC revision of specific SOC
+
+Function : plat_is_smccc_feature_available()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : u_register_t
+ Return : int32_t
+
+This function returns SMC_ARCH_CALL_SUCCESS if the platform supports
+the SMCCC function specified in the argument; otherwise returns
+SMC_ARCH_CALL_NOT_SUPPORTED.
+
+Function : plat_mboot_measure_image()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : unsigned int, image_info_t *
+ Return : int
+
+When the MEASURED_BOOT flag is enabled:
+
+- This function measures the given image and records its measurement using
+ the measured boot backend driver.
+- On the Arm FVP port, this function measures the given image using its
+ passed id and information and then records that measurement in the
+ Event Log buffer.
+- This function must return 0 on success, a signed integer error code
+ otherwise.
+
+When the MEASURED_BOOT flag is disabled, this function doesn't do anything.
+
+Function : plat_mboot_measure_critical_data()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : unsigned int, const void *, size_t
+ Return : int
+
+When the MEASURED_BOOT flag is enabled:
+
+- This function measures the given critical data structure and records its
+ measurement using the measured boot backend driver.
+- This function must return 0 on success, a signed integer error code
+ otherwise.
+
+When the MEASURED_BOOT flag is disabled, this function doesn't do anything.
+
+Function : plat_can_cmo()
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : uint64_t
+
+When CONDITIONAL_CMO flag is enabled:
+
+- This function indicates whether cache management operations should be
+ performed. It returns 0 if CMOs should be skipped and non-zero
+ otherwise.
+- The function must not clobber x1, x2 and x3. It's also not safe to rely on
+ stack. Otherwise obey AAPCS.
+
+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.
+
+Function : bl1_plat_mboot_init() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : void
+
+When the MEASURED_BOOT flag is enabled:
+
+- This function is used to initialize the backend driver(s) of measured boot.
+- On the Arm FVP port, this function is used to initialize the Event Log
+ backend driver, and also to write header information in the Event Log buffer.
+
+When the MEASURED_BOOT flag is disabled, this function doesn't do anything.
+
+Function : bl1_plat_mboot_finish() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : void
+
+When the MEASURED_BOOT flag is enabled:
+
+- This function is used to finalize the measured boot backend driver(s),
+ and also, set the information for the next bootloader component to
+ extend the measurement if needed.
+- On the Arm FVP port, this function is used to pass the base address of
+ the Event Log buffer and its size to BL2 via tb_fw_config to extend the
+ Event Log buffer with the measurement of various images loaded by BL2.
+ It results in panic on error.
+
+When the MEASURED_BOOT flag is disabled, this function doesn't do anything.
+
+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 FW_CONFIG
+
+ 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.
+
+Function : bl2_plat_mboot_init() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : void
+
+When the MEASURED_BOOT flag is enabled:
+
+- This function is used to initialize the backend driver(s) of measured boot.
+- On the Arm FVP port, this function is used to initialize the Event Log
+ backend driver with the Event Log buffer information (base address and
+ size) received from BL1. It results in panic on error.
+
+When the MEASURED_BOOT flag is disabled, this function doesn't do anything.
+
+Function : bl2_plat_mboot_finish() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : void
+
+When the MEASURED_BOOT flag is enabled:
+
+- This function is used to finalize the measured boot backend driver(s),
+ and also, set the information for the next bootloader component to extend
+ the measurement if needed.
+- On the Arm FVP port, this function is used to pass the Event Log buffer
+ information (base address and size) to non-secure(BL33) and trusted OS(BL32)
+ via nt_fw and tos_fw config respectively. It results in panic on error.
+
+When the MEASURED_BOOT flag is disabled, this function doesn't do anything.
+
+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
+ except in case of Arm FVP and Juno platform.
+
+ In case of Arm FVP and Juno platform, points to load address
+ of FW_CONFIG.
+
+ 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 : plat_rmmd_get_cca_attest_token() [mandatory when ENABLE_RME == 1]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : uintptr_t, size_t *, uintptr_t, size_t
+ Return : int
+
+This function returns the Platform attestation token.
+
+The parameters of the function are:
+
+ arg0 - A pointer to the buffer where the Platform token should be copied by
+ this function. The buffer must be big enough to hold the Platform
+ token.
+
+ arg1 - Contains the size (in bytes) of the buffer passed in arg0. The
+ function returns the platform token length in this parameter.
+
+ arg2 - A pointer to the buffer where the challenge object is stored.
+
+ arg3 - The length of the challenge object in bytes. Possible values are 32,
+ 48 and 64.
+
+The function returns 0 on success, -EINVAL on failure.
+
+Function : plat_rmmd_get_cca_realm_attest_key() [mandatory when ENABLE_RME == 1]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : uintptr_t, size_t *, unsigned int
+ Return : int
+
+This function returns the delegated realm attestation key which will be used to
+sign Realm attestation token. The API currently only supports P-384 ECC curve
+key.
+
+The parameters of the function are:
+
+ arg0 - A pointer to the buffer where the attestation key should be copied
+ by this function. The buffer must be big enough to hold the
+ attestation key.
+
+ arg1 - Contains the size (in bytes) of the buffer passed in arg0. The
+ function returns the attestation key length in this parameter.
+
+ arg2 - The type of the elliptic curve to which the requested attestation key
+ belongs.
+
+The function returns 0 on success, -EINVAL on failure.
+
+Function : plat_rmmd_get_el3_rmm_shared_mem() [when ENABLE_RME == 1]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : uintptr_t *
+ Return : size_t
+
+This function returns the size of the shared area between EL3 and RMM (or 0 on
+failure). A pointer to the shared area (or a NULL pointer on failure) is stored
+in the pointer passed as argument.
+
+Function : plat_rmmd_load_manifest() [when ENABLE_RME == 1]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Arguments : rmm_manifest_t *manifest
+ Return : int
+
+When ENABLE_RME is enabled, this function populates a boot manifest for the
+RMM image and stores it in the area specified by manifest.
+
+When ENABLE_RME is disabled, this function is not used.
+
+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() [optional]
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+ Argument: uintptr_t ep, unsigned int client_mode
+ Return: int
+
+This function validates the entry point address of the event handler provided by
+the client for both event registration and *Complete and Resume* |SDEI| calls.
+The function ensures that the address is valid in the client translation regime.
+
+The second argument is the exception level that the client is executing in. It
+can be Non-Secure EL1 or Non-Secure EL2.
+
+The function must return ``0`` for successful validation, or ``-1`` upon failure.
+
+The default implementation always returns ``0``. On Arm platforms, this function
+translates the entry point address within the client translation regime and
+further ensures that the resulting physical 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.
+
+.. _porting_guide_trng_requirements:
+
+TRNG porting requirements
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The |TRNG| backend requires the platform to provide the following values
+and mandatory functions.
+
+Values
+......
+
+value: uuid_t plat_trng_uuid [mandatory]
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This value must be defined to the UUID of the TRNG backend that is specific to
+the hardware after ``plat_entropy_setup`` function is called. This value must
+conform to the SMCCC calling convention; The most significant 32 bits of the
+UUID must not equal ``0xffffffff`` or the signed integer ``-1`` as this value in
+w0 indicates failure to get a TRNG source.
+
+Functions
+.........
+
+Function: void plat_entropy_setup(void) [mandatory]
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+ Argument: none
+ Return: none
+
+This function is expected to do platform-specific initialization of any TRNG
+hardware. This may include generating a UUID from a hardware-specific seed.
+
+Function: bool plat_get_entropy(uint64_t \*out) [mandatory]
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+ Argument: uint64_t *
+ Return: bool
+ Out : when the return value is true, the entropy has been written into the
+ storage pointed to
+
+This function writes entropy into storage provided by the caller. If no entropy
+is available, it must return false and the storage must not be written.
+
+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 *, unsigned 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 (by calling wfi in an infinite loop to ensure
+some CPUs power down mitigations work properly).
+
+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 :ref:`build_options_arm_fvp_platform` for more
+details).
+
+See also: :ref:`Interrupt Controller Abstraction APIs<Platform Interrupt Controller API>`.
+
+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()<plat_ic_get_interrupt_id>`.
+
+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.
+
+Common helper functions
+-----------------------
+
+Function : do_panic()
+~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : void
+
+This API is called from assembly files when encountering a critical failure that
+cannot be recovered from. It also invokes elx_panic() which allows to report a
+crash from lower exception level. This function assumes that it is invoked from
+a C runtime environment i.e. valid stack exists. This call **must not** return.
+
+Function : panic()
+~~~~~~~~~~~~~~~~~~
+
+::
+
+ Argument : void
+ Return : void
+
+This API called from C files when encountering a critical failure that cannot
+be recovered from. This function in turn prints backtrace (if enabled) and calls
+do_panic(). This call **must not** return.
+
+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 : void
+
+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.
+
+.. _External Abort handling and RAS Support:
+
+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.
+
+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
+
+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 :ref:`firmware_design_fip`).
+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-2022, 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/
+.. _DRTM: https://developer.arm.com/documentation/den0113/a
diff --git a/docs/getting_started/prerequisites.rst b/docs/getting_started/prerequisites.rst
new file mode 100644
index 0000000..3723294
--- /dev/null
+++ b/docs/getting_started/prerequisites.rst
@@ -0,0 +1,181 @@
+Prerequisites
+=============
+
+This document describes the software requirements for building |TF-A| for
+AArch32 and AArch64 target platforms.
+
+It may possible to build |TF-A| with combinations of software packages that are
+different from those listed below, however only the software described in this
+document can be officially supported.
+
+Build Host
+----------
+
+|TF-A| can be built using either a Linux or a Windows machine as the build host.
+
+A relatively recent Linux distribution is recommended for building |TF-A|. We
+have performed tests using Ubuntu 20.04 LTS (64-bit) but other distributions
+should also work fine as a base, provided that the necessary tools and libraries
+can be installed.
+
+.. _prerequisites_toolchain:
+
+Toolchain
+---------
+
+|TF-A| can be built with any of the following *cross-compiler* toolchains that
+target the Armv7-A or Armv8-A architectures:
+
+- GCC >= 11.3.Rel1 (from the `Arm Developer website`_)
+
+ You will need the targets ``arm-none-eabi`` and ``aarch64-none-elf`` for
+ AArch32 and AArch64 builds respectively.
+
+- Clang >= 14.0.0
+- Arm Compiler >= 6.18
+
+In addition, a native compiler is required to build the supporting tools.
+
+.. note::
+ 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.
+
+.. note::
+ For instructions on how to select the cross compiler refer to
+ :ref:`Performing an Initial Build`.
+
+.. _prerequisites_software_and_libraries:
+
+Software and Libraries
+----------------------
+
+The following tools are required to obtain and build |TF-A|:
+
+- An appropriate toolchain (see :ref:`prerequisites_toolchain`)
+- GNU Make
+- Git
+
+The following libraries must be available to build one or more components or
+supporting tools:
+
+- OpenSSL >= 1.1.1 (v3.0.0 to v3.0.6 highly discouraged due to security issues)
+
+ Required to build the cert_create, encrypt_fw, and fiptool tools.
+
+ .. note::
+
+ If using OpenSSL 3, older Linux versions may require it to be built from
+ source code, as it may not be available in the default package repositories.
+ Please refer to the OpenSSL project documentation for more information.
+
+The following libraries are required for Trusted Board Boot and Measured Boot
+support:
+
+- mbed TLS == 2.28.1 (tag: ``mbedtls-2.28.1``)
+
+These tools are optional:
+
+- Device Tree Compiler (DTC) >= 1.4.6
+
+ Needed if you want to rebuild the provided Flattened Device Tree (FDT)
+ source files (``.dts`` files). DTC is available for Linux through the package
+ repositories of most distributions.
+
+- Arm `Development Studio (Arm-DS)`_
+
+ The standard software package used for debugging software on Arm development
+ platforms and |FVP| models.
+
+- Node.js >= 16
+
+ Highly recommended, and necessary in order to install and use the packaged
+ Git hooks and helper tools. Without these tools you will need to rely on the
+ CI for feedback on commit message conformance.
+
+Package Installation (Linux)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you are using the recommended Ubuntu distribution then you can install the
+required packages with the following command:
+
+.. code:: shell
+
+ sudo apt install build-essential git
+
+The optional packages can be installed using:
+
+.. code:: shell
+
+ sudo apt install device-tree-compiler
+
+Additionally, to install a version of Node.js compatible with TF-A's repository
+scripts, you can use the `Node Version Manager`_. To install both NVM and an
+appropriate version of Node.js, run the following **from the root directory of
+the repository**:
+
+.. code:: shell
+
+ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
+ exec "$SHELL" -ic "nvm install; exec $SHELL"
+
+.. _Node Version Manager: https://github.com/nvm-sh/nvm#install--update-script
+
+Supporting Files
+----------------
+
+TF-A has been tested with pre-built binaries and file systems from `Linaro
+Release 20.01`_. Alternatively, you can build the binaries from source using
+instructions in :ref:`Performing an Initial Build`.
+
+.. _prerequisites_get_source:
+
+Getting the TF-A Source
+-----------------------
+
+Source code for |TF-A| is maintained in a Git repository hosted on
+TrustedFirmware.org. To clone this repository from the server, run the following
+in your shell:
+
+.. code:: shell
+
+ git clone "https://review.trustedfirmware.org/TF-A/trusted-firmware-a"
+
+Additional Steps for Contributors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you are planning on contributing back to TF-A, there are some things you'll
+want to know.
+
+TF-A is hosted by a `Gerrit Code Review`_ server. Gerrit requires that all
+commits include a ``Change-Id`` footer, and this footer is typically
+automatically generated by a Git hook installed by you, the developer.
+
+If you have Node.js installed already, you can automatically install this hook,
+along with any additional hooks and Javascript-based tooling that we use, by
+running from within your newly-cloned repository:
+
+.. code:: shell
+
+ npm install --no-save
+
+If you have opted **not** to install Node.js, you can install the Gerrit hook
+manually by running:
+
+.. code:: shell
+
+ curl -Lo $(git rev-parse --git-dir)/hooks/commit-msg https://review.trustedfirmware.org/tools/hooks/commit-msg
+ chmod +x $(git rev-parse --git-dir)/hooks/commit-msg
+
+You can read more about Git hooks in the *githooks* page of the Git
+documentation, available `here <https://git-scm.com/docs/githooks>`_.
+
+--------------
+
+*Copyright (c) 2021-2022, Arm Limited. All rights reserved.*
+
+.. _Arm Developer website: https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/downloads
+.. _Gerrit Code Review: https://www.gerritcodereview.com/
+.. _Linaro Release Notes: https://community.arm.com/dev-platforms/w/docs/226/old-release-notes
+.. _Linaro instructions: https://community.arm.com/dev-platforms/w/docs/304/arm-reference-platforms-deliverables
+.. _Development Studio (Arm-DS): https://developer.arm.com/Tools%20and%20Software/Arm%20Development%20Studio
+.. _Linaro Release 20.01: http://releases.linaro.org/members/arm/platforms/20.01
diff --git a/docs/getting_started/psci-lib-integration-guide.rst b/docs/getting_started/psci-lib-integration-guide.rst
new file mode 100644
index 0000000..4d690a9
--- /dev/null
+++ b/docs/getting_started/psci-lib-integration-guide.rst
@@ -0,0 +1,536 @@
+PSCI 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).
+
+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-2020, 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://developer.arm.com/docs/den0028/latest
+.. _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
diff --git a/docs/getting_started/rt-svc-writers-guide.rst b/docs/getting_started/rt-svc-writers-guide.rst
new file mode 100644
index 0000000..5a4be4d
--- /dev/null
+++ b/docs/getting_started/rt-svc-writers-guide.rst
@@ -0,0 +1,320 @@
+EL3 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 <name of the 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 Non-secure, Secure or Realm worlds and
+ the framework will forward all calls to the service handler.
+
+ The ``flags`` parameter to this function indicates the caller security state
+ in bits 0 and 5. The ``is_caller_secure(flags)``, ``is_caller_non_secure(flags)``
+ and ``is_caller_realm(flags)`` helper functions can be used to determine whether
+ the caller's security state is Secure, Non-secure or Realm respectively.
+
+ 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. Based on `SMCCC`_ spec, results are
+ returned in W0-W7(X0-X7) registers for SMC32(SMC64) calls from AArch64
+ state. Results are returned in R0-R7 registers for SMC32 calls from AArch32
+ state. The framework provides a family of macros to set the multi-register
+ return value and complete the handler:
+
+ .. code:: c
+
+ AArch64 state:
+
+ SMC_RET1(handle, x0);
+ SMC_RET2(handle, x0, x1);
+ SMC_RET3(handle, x0, x1, x2);
+ SMC_RET4(handle, x0, x1, x2, x3);
+ SMC_RET5(handle, x0, x1, x2, x3, x4);
+ SMC_RET6(handle, x0, x1, x2, x3, x4, x5);
+ SMC_RET7(handle, x0, x1, x2, x3, x4, x5, x6);
+ SMC_RET8(handle, x0, x1, x2, x3, x4, x5, x6, x7);
+
+ AArch32 state:
+
+ SMC_RET1(handle, r0);
+ SMC_RET2(handle, r0, r1);
+ SMC_RET3(handle, r0, r1, r2);
+ SMC_RET4(handle, r0, r1, r2, r3);
+ SMC_RET5(handle, r0, r1, r2, r3, r4);
+ SMC_RET6(handle, r0, r1, r2, r3, r4, r5);
+ SMC_RET7(handle, r0, r1, r2, r3, r4, r5, r6);
+ SMC_RET8(handle, r0, r1, r2, r3, r4, r5, r6, r7);
+
+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-2021, Arm Limited and Contributors. All rights reserved.*
+
+.. _SMCCC: https://developer.arm.com/docs/den0028/latest
+.. _PSCI: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf
diff --git a/docs/getting_started/tools-build.rst b/docs/getting_started/tools-build.rst
new file mode 100644
index 0000000..166b527
--- /dev/null
+++ b/docs/getting_started/tools-build.rst
@@ -0,0 +1,179 @@
+Building Supporting Tools
+=========================
+
+.. note::
+
+ OpenSSL 3.0 is needed in order to build the tools. A custom installation
+ can be used if not updating the OpenSSL version on the OS. In order to do
+ this, use the ``OPENSSL_DIR`` variable after the ``make`` command to
+ indicate the location of the custom OpenSSL build. Then, to run the tools,
+ use the ``LD_LIBRARY_PATH`` to indicate the location of the built
+ libraries. More info about ``OPENSSL_DIR`` can be found at
+ :ref:`Build Options`.
+
+Building and using the FIP tool
+-------------------------------
+
+The following snippets build a :ref:`FIP<Image Terminology>` for the FVP
+platform. While it is not an intrinsic part of the FIP format, a BL33 image is
+required for these examples. For the purposes of experimentation, `Trusted
+Firmware-A Tests`_ (`tftf.bin``) may be used. Refer to to the `TFTF
+documentation`_ for instructions on building a TFTF binary.
+
+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=<path-to>/bl33.bin fip
+
+For AArch32:
+
+.. code:: shell
+
+ make PLAT=fvp ARCH=aarch32 AARCH32_SP=sp_min BL33=<path-to>/bl33.bin fip
+
+The resulting FIP may be found in:
+
+::
+
+ build/fvp/<build-type>/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/<platform>/<build-type>/bl2.bin \
+ --soc-fw build/<platform>/<build-type>/bl31.bin \
+ fip.bin
+
+Example 2: view the contents of an existing Firmware package:
+
+.. code:: shell
+
+ ./tools/fiptool/fiptool info <path-to>/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/<platform>/release/bl2.bin \
+ build/<platform>/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 <path-to>/fip.bin
+
+Example 5: remove an entry from an existing Firmware package:
+
+.. code:: shell
+
+ ./tools/fiptool/fiptool remove \
+ --tb-fw build/<platform>/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.
+
+.. _tools_build_cert_create:
+
+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=<platform> [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=<platform> 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
+
+.. _tools_build_enctool:
+
+Building the Firmware Encryption Tool
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``encrypt_fw`` tool is built as part of the TF-A build process when the
+``fip`` make target is specified, DECRYPTION_SUPPORT and TBB are enabled, but
+it can also be built separately with the following command:
+
+.. code:: shell
+
+ make PLAT=<platform> [DEBUG=1] [V=1] enctool
+
+``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/encrypt_fw/encrypt_fw -h
+
+Note that the enctool in its current implementation only supports encryption
+key to be provided in plain format. A typical implementation can very well
+extend this tool to support custom techniques to protect encryption key.
+
+Also, a user may choose to provide encryption key or nonce as an input file
+via using ``cat <filename>`` instead of a hex string.
+
+--------------
+
+*Copyright (c) 2019-2022, Arm Limited. All rights reserved.*
+
+.. _Trusted Firmware-A Tests: https://git.trustedfirmware.org/TF-A/tf-a-tests.git/
+.. _TFTF documentation: https://trustedfirmware-a-tests.readthedocs.io/en/latest/
diff --git a/docs/global_substitutions.txt b/docs/global_substitutions.txt
new file mode 100644
index 0000000..0cf2946
--- /dev/null
+++ b/docs/global_substitutions.txt
@@ -0,0 +1,68 @@
+.. |AArch32| replace:: :term:`AArch32`
+.. |AArch64| replace:: :term:`AArch64`
+.. |AMU| replace:: :term:`AMU`
+.. |AMUs| replace:: :term:`AMUs <AMU>`
+.. |API| replace:: :term:`API`
+.. |BTI| replace:: :term:`BTI`
+.. |CoT| replace:: :term:`CoT`
+.. |COT| replace:: :term:`COT`
+.. |CSS| replace:: :term:`CSS`
+.. |CVE| replace:: :term:`CVE`
+.. |DTB| replace:: :term:`DTB`
+.. |DS-5| replace:: :term:`DS-5`
+.. |DSU| replace:: :term:`DSU`
+.. |DT| replace:: :term:`DT`
+.. |EL| replace:: :term:`EL`
+.. |EHF| replace:: :term:`EHF`
+.. |FCONF| replace:: :term:`FCONF`
+.. |FDT| replace:: :term:`FDT`
+.. |FF-A| replace:: :term:`FF-A`
+.. |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`
+.. |MPMM| replace:: :term:`MPMM`
+.. |MPIDR| replace:: :term:`MPIDR`
+.. |MTE| replace:: :term:`MTE`
+.. |OEN| replace:: :term:`OEN`
+.. |OP-TEE| replace:: :term:`OP-TEE`
+.. |OTE| replace:: :term:`OTE`
+.. |PDD| replace:: :term:`PDD`
+.. |PAUTH| replace:: :term:`PAUTH`
+.. |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`
+.. |SPD| replace:: :term:`SPD`
+.. |SPM| replace:: :term:`SPM`
+.. |SSBS| replace:: :term:`SSBS`
+.. |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`
+.. |TRNG| replace:: :term:`TRNG`
+.. |TSP| replace:: :term:`TSP`
+.. |TZC| replace:: :term:`TZC`
+.. |UBSAN| replace:: :term:`UBSAN`
+.. |UEFI| replace:: :term:`UEFI`
+.. |WDOG| replace:: :term:`WDOG`
+.. |XLAT| replace:: :term:`XLAT`
diff --git a/docs/glossary.rst b/docs/glossary.rst
new file mode 100644
index 0000000..e6b0239
--- /dev/null
+++ b/docs/glossary.rst
@@ -0,0 +1,243 @@
+Glossary
+========
+
+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
+
+ AMU
+ Activity Monitor Unit, a hardware monitoring unit introduced by FEAT_AMUv1
+ that exposes CPU core runtime metrics as a set of counter registers.
+
+ API
+ Application Programming Interface
+
+ AT
+ Address Translation
+
+ BTI
+ Branch Target Identification. An Armv8.5 extension providing additional
+ control flow integrity around indirect branches and their targets.
+
+ 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.
+
+ DCE
+ DRTM Configuration Environment
+
+ D-CRTM
+ Dynamic Code Root of Trust for Measurement
+
+ DLME
+ Dynamically Launched Measured Environment
+
+ DRTM
+ Dynamic Root of Trust for Measurement
+
+ DS-5
+ Arm Development Studio 5
+
+ DSU
+ DynamIQ Shared Unit
+
+ DT
+ Device Tree
+
+ DTB
+ Device Tree Blob
+
+ EL
+ Exception Level
+
+ EHF
+ Exception Handling Framework
+
+ FCONF
+ Firmware Configuration Framework
+
+ FDT
+ Flattened Device Tree
+
+ FF-A
+ Firmware Framework for Arm A-profile
+
+ 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.
+
+ LSP
+ A logical secure partition managed by SPM
+
+ MMU
+ Memory Management Unit
+
+ MPAM
+ Memory Partitioning And Monitoring. An optional Armv8.4 extension.
+
+ MPMM
+ Maximum Power Mitigation Mechanism, an optional power management mechanism
+ supported by some Arm Armv9-A cores.
+
+ MPIDR
+ Multiprocessor Affinity Register
+
+ MTE
+ Memory Tagging Extension. An optional Armv8.5 extension that enables
+ hardware-assisted memory tagging.
+
+ 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
+
+ PAUTH
+ Pointer Authentication. An optional extension introduced in Armv8.3.
+
+ PMF
+ Performance Measurement Framework
+
+ PSA
+ Platform Security Architecture
+
+ 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
+
+ SPD
+ Secure Payload Dispatcher
+
+ SPM
+ Secure Partition Manager
+
+ SSBS
+ Speculative Store Bypass Safe. Introduced in Armv8.5, this configuration
+ bit can be set by software to allow or prevent the hardware from
+ performing speculative operations.
+
+ SVE
+ Scalable Vector Extension
+
+ TBB
+ Trusted Board Boot
+
+ TBBR
+ Trusted Board Boot Requirements
+
+ TCB
+ Trusted Compute Base
+
+ 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.
+
+ TRNG
+ True Randon Number Generator (hardware based)
+
+ TSP
+ Test Secure Payload
+
+ TZC
+ TrustZone Controller
+
+ UBSAN
+ Undefined Behavior Sanitizer
+
+ UEFI
+ Unified Extensible Firmware Interface
+
+ WDOG
+ Watchdog
+
+ XLAT
+ Translation (abbr.). For example, "XLAT table".
+
+.. _`Arm Glossary`: https://developer.arm.com/support/arm-glossary
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 0000000..3860199
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,96 @@
+Trusted Firmware-A Documentation
+================================
+
+.. toctree::
+ :maxdepth: 1
+ :numbered:
+
+ Home<self>
+ about/index
+ getting_started/index
+ process/index
+ components/index
+ design/index
+ plat/index
+ perf/index
+ security_advisories/index
+ design_documents/index
+ threat_model/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)`_
+- `PSA FW update specification`_
+
+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-2021, 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: https://developer.arm.com/docs/den0028/latest
+.. _PSA FW update specification: https://developer.arm.com/documentation/den0118/a/
diff --git a/docs/license.rst b/docs/license.rst
new file mode 100644
index 0000000..80f1118
--- /dev/null
+++ b/docs/license.rst
@@ -0,0 +1,90 @@
+License
+=======
+
+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, <OWNER>. 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.
+
+- Some source files originating from the Linux source tree, which are
+ disjunctively dual licensed (GPL-2.0 OR MIT), are redistributed under the
+ terms of the MIT license. These files are:
+
+ - ``include/dt-bindings/interrupt-controller/arm-gic.h``
+ - ``include/dt-bindings/interrupt-controller/irq.h``
+
+ See the original `Linux MIT license`_.
+
+.. _FreeBSD: http://www.freebsd.org
+.. _Linux MIT license: https://raw.githubusercontent.com/torvalds/linux/master/LICENSES/preferred/MIT
+.. _SCC: http://www.simple-cc.org/
diff --git a/docs/perf/index.rst b/docs/perf/index.rst
new file mode 100644
index 0000000..bccad00
--- /dev/null
+++ b/docs/perf/index.rst
@@ -0,0 +1,14 @@
+Performance & Testing
+=====================
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents
+
+ psci-performance-juno
+ tsp
+ performance-monitoring-unit
+
+--------------
+
+*Copyright (c) 2019-2020, Arm Limited. All rights reserved.*
diff --git a/docs/perf/performance-monitoring-unit.rst b/docs/perf/performance-monitoring-unit.rst
new file mode 100644
index 0000000..5dd1af5
--- /dev/null
+++ b/docs/perf/performance-monitoring-unit.rst
@@ -0,0 +1,158 @@
+Performance Monitoring Unit
+===========================
+
+The Performance Monitoring Unit (PMU) allows recording of architectural and
+microarchitectural events for profiling purposes.
+
+This document gives an overview of the PMU counter configuration to assist with
+implementation and to complement the PMU security guidelines given in the
+:ref:`Secure Development Guidelines` document.
+
+.. note::
+ This section applies to Armv8-A implementations which have version 3
+ of the Performance Monitors Extension (PMUv3).
+
+PMU Counters
+------------
+
+The PMU makes 32 counters available at all privilege levels:
+
+- 31 programmable event counters: ``PMEVCNTR<n>``, where ``n`` is ``0`` to
+ ``30``.
+- A dedicated cycle counter: ``PMCCNTR``.
+
+Architectural mappings
+~~~~~~~~~~~~~~~~~~~~~~
+
++--------------+---------+----------------------------+
+| Counters | State | System Register Name |
++==============+=========+============================+
+| | AArch64 | ``PMEVCNTR<n>_EL0[63*:0]`` |
+| Programmable +---------+----------------------------+
+| | AArch32 | ``PMEVCNTR<n>[31:0]`` |
++--------------+---------+----------------------------+
+| | AArch64 | ``PMCCNTR_EL0[63:0]`` |
+| Cycle +---------+----------------------------+
+| | AArch32 | ``PMCCNTR[63:0]`` |
++--------------+---------+----------------------------+
+
+.. note::
+ Bits [63:32] are only available if ARMv8.5-PMU is implemented. Refer to the
+ `Arm ARM`_ for a detailed description of ARMv8.5-PMU features.
+
+Configuring the PMU for counting events
+---------------------------------------
+
+Each programmable counter has an associated register, ``PMEVTYPER<n>`` which
+configures it. The cycle counter has the ``PMCCFILTR_EL0`` register, which has
+an identical function and bit field layout as ``PMEVTYPER<n>``. In addition,
+the counters are enabled (permitted to increment) via the ``PMCNTENSET`` and
+``PMCR`` registers. These can be accessed at all privilege levels.
+
+Architectural mappings
+~~~~~~~~~~~~~~~~~~~~~~
+
++-----------------------------+------------------------+
+| AArch64 | AArch32 |
++=============================+========================+
+| ``PMEVTYPER<n>_EL0[63*:0]`` | ``PMEVTYPER<n>[31:0]`` |
++-----------------------------+------------------------+
+| ``PMCCFILTR_EL0[63*:0]`` | ``PMCCFILTR[31:0]`` |
++-----------------------------+------------------------+
+| ``PMCNTENSET_EL0[63*:0]`` | ``PMCNTENSET[31:0]`` |
++-----------------------------+------------------------+
+| ``PMCR_EL0[63*:0]`` | ``PMCR[31:0]`` |
++-----------------------------+------------------------+
+
+.. note::
+ Bits [63:32] are reserved.
+
+Relevant register fields
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+For ``PMEVTYPER<n>_EL0``/``PMEVTYPER<n>`` and ``PMCCFILTR_EL0/PMCCFILTR``, the
+most important fields are:
+
+- ``P``:
+
+ - Bit 31.
+ - If set to ``0``, will increment the associated ``PMEVCNTR<n>`` at EL1.
+
+- ``NSK``:
+
+ - Bit 29.
+ - If equal to the ``P`` bit it enables the associated ``PMEVCNTR<n>`` at
+ Non-secure EL1.
+ - Reserved if EL3 not implemented.
+
+- ``NSH``:
+
+ - Bit 27.
+ - If set to ``1``, will increment the associated ``PMEVCNTR<n>`` at EL2.
+ - Reserved if EL2 not implemented.
+
+- ``SH``:
+
+ - Bit 24.
+ - If different to the ``NSH`` bit it enables the associated ``PMEVCNTR<n>``
+ at Secure EL2.
+ - Reserved if Secure EL2 not implemented.
+
+- ``M``:
+
+ - Bit 26.
+ - If equal to the ``P`` bit it enables the associated ``PMEVCNTR<n>`` at
+ EL3.
+
+- ``evtCount[15:10]``:
+
+ - Extension to ``evtCount[9:0]``. Reserved unless ARMv8.1-PMU implemented.
+
+- ``evtCount[9:0]``:
+
+ - The event number that the associated ``PMEVCNTR<n>`` will count.
+
+For ``PMCNTENSET_EL0``/``PMCNTENSET``, the most important fields are:
+
+- ``P[30:0]``:
+
+ - Setting bit ``P[n]`` to ``1`` enables counter ``PMEVCNTR<n>``.
+ - The effects of ``PMEVTYPER<n>`` are applied on top of this.
+ In other words, the counter will not increment at any privilege level or
+ security state unless it is enabled here.
+
+- ``C``:
+
+ - Bit 31.
+ - If set to ``1`` enables the cycle counter ``PMCCNTR``.
+
+For ``PMCR``/``PMCR_EL0``, the most important fields are:
+
+- ``DP``:
+
+ - Bit 5.
+ - If set to ``1`` it disables the cycle counter ``PMCCNTR`` where event
+ counting (by ``PMEVCNTR<n>``) is prohibited (e.g. EL2 and the Secure
+ world).
+ - If set to ``0``, ``PMCCNTR`` will not be affected by this bit and
+ therefore will be able to count where the programmable counters are
+ prohibited.
+
+- ``E``:
+
+ - Bit 0.
+ - Enables/disables counting altogether.
+ - The effects of ``PMCNTENSET`` and ``PMCR.DP`` are applied on top of this.
+ In other words, if this bit is ``0`` then no counters will increment
+ regardless of how the other PMU system registers or bit fields are
+ configured.
+
+.. rubric:: References
+
+- `Arm ARM`_
+
+--------------
+
+*Copyright (c) 2019-2020, Arm Limited and Contributors. All rights reserved.*
+
+.. _Arm ARM: https://developer.arm.com/docs/ddi0487/latest
diff --git a/docs/perf/psci-performance-juno.rst b/docs/perf/psci-performance-juno.rst
new file mode 100644
index 0000000..eab3e4d
--- /dev/null
+++ b/docs/perf/psci-performance-juno.rst
@@ -0,0 +1,292 @@
+PSCI 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=<path/to/scp-fw.bin> \
+ BL33=<path/to/test-fw.bin> \
+ 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-2020, Arm Limited and Contributors. All rights reserved.*
+
+.. _Juno R1 platform: https://static.docs.arm.com/100122/0100/arm_versatile_express_juno_r1_development_platform_(v2m_juno_r1)_technical_reference_manual_100122_0100_05_en.pdf
+.. _TF master as of 31/01/2017: https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/?id=c38b36d
diff --git a/docs/perf/tsp.rst b/docs/perf/tsp.rst
new file mode 100644
index 0000000..f8b0048
--- /dev/null
+++ b/docs/perf/tsp.rst
@@ -0,0 +1,27 @@
+Test Secure Payload (TSP) and Dispatcher (TSPD)
+===============================================
+
+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:`firmware_design_sel1_spd` section in the :ref:`Firmware Design`.
+
+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=<platform> SPD=tspd all
+
+An additional boot loader binary file is created in the ``build`` directory:
+
+::
+
+ build/<platform>/<build-type>/bl32.bin
+
+--------------
+
+*Copyright (c) 2019, Arm Limited. All rights reserved.*
diff --git a/docs/plat/allwinner.rst b/docs/plat/allwinner.rst
new file mode 100644
index 0000000..3e9ce51
--- /dev/null
+++ b/docs/plat/allwinner.rst
@@ -0,0 +1,142 @@
+Allwinner 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.
+
+Building TF-A
+-------------
+
+There is one build target per supported SoC:
+
++------+-------------------+
+| SoC | TF-A build target |
++======+===================+
+| A64 | sun50i_a64 |
++------+-------------------+
+| H5 | sun50i_a64 |
++------+-------------------+
+| H6 | sun50i_h6 |
++------+-------------------+
+| H616 | sun50i_h616 |
++------+-------------------+
+| H313 | sun50i_h616 |
++------+-------------------+
+| R329 | sun50i_r329 |
++------+-------------------+
+
+To build with the default settings for a particular SoC:
+
+.. code:: shell
+
+ make CROSS_COMPILE=aarch64-linux-gnu- PLAT=<build target> DEBUG=1
+
+So for instance to build for a board with the Allwinner A64 SoC::
+
+ make CROSS_COMPILE=aarch64-linux-gnu- PLAT=sun50i_a64 DEBUG=1
+
+Platform-specific build options
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The default build options should generate a working firmware image. There are
+some build options that allow to fine-tune the firmware, or to disable support
+for optional features.
+
+- ``SUNXI_PSCI_USE_NATIVE`` : Support direct control of the CPU cores powerdown
+ and powerup sequence by BL31. This requires either support for a code snippet
+ to be loaded into the ARISC SCP (A64, H5), or the power sequence control
+ registers to be programmed directly (H6, H616). This supports only basic
+ control, like core on/off and system off/reset.
+ This option defaults to 1. If an active SCP supporting the SCPI protocol
+ is detected at runtime, this control scheme will be ignored, and SCPI
+ will be used instead, unless support has been explicitly disabled.
+
+- ``SUNXI_PSCI_USE_SCPI`` : Support control of the CPU cores powerdown and
+ powerup sequence by talking to the SCP processor via the SCPI protocol.
+ This allows more advanced power saving techniques, like suspend to RAM.
+ This option defaults to 1 on SoCs that feature an SCP. If no SCP firmware
+ using the SCPI protocol is detected, the native sequence will be used
+ instead. If both native and SCPI methods are included, SCPI will be favoured
+ if SCP support is detected.
+
+- ``SUNXI_SETUP_REGULATORS`` : On SoCs that typically ship with a PMIC
+ power management controller, BL31 tries to set up all needed power rails,
+ programming them to their respective voltages. That allows bootloader
+ software like U-Boot to ignore power control via the PMIC.
+ This setting defaults to 1. In some situations that enables too many
+ regulators, or some regulators need to be enabled in a very specific
+ sequence. To avoid problems with those boards, ``SUNXI_SETUP_REGULATORS``
+ can bet set to ``0`` on the build command line, to skip the PMIC setup
+ entirely. Any bootloader or OS would need to setup the PMIC on its own then.
+
+Installation
+------------
+
+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).
+
+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.
+
+.. _U-Boot documentation: https://gitlab.denx.de/u-boot/u-boot/-/blob/master/board/sunxi/README.sunxi64
+
+Memory layout
+-------------
+
+A64, H5 and H6 SoCs
+~~~~~~~~~~~~~~~~~~~
+
+BL31 lives in SRAM A2, which is documented to be accessible from secure
+world only. Since this SRAM region is very limited (48 KB), we take
+several measures to reduce memory consumption. One of them is to confine
+BL31 to only 28 bits of virtual address space, which reduces the number
+of required page tables (each occupying 4KB of memory).
+The mapping we use on those SoCs is as follows:
+
+::
+
+ 0 64K 16M 1GB 1G+160M physical address
+ +-+------+-+---+------+--...---+-------+----+------+----------
+ |B| |S|///| |//...///| |////| |
+ |R| SRAM |C|///| dev |//...///| (sec) |////| BL33 | DRAM ...
+ |O| |P|///| MMIO |//...///| DRAM |////| |
+ |M| | |///| |//...///| (32M) |////| |
+ +-+------+-+---+------+--...---+-------+----+------+----------
+ | | | | | | / / / /
+ | | | | | | / / / /
+ | | | | | | / / / /
+ | | | | | | / // /
+ | | | | | | / / /
+ +-+------+-+---+------+--+-------+------+
+ |B| |S|///| |//| | |
+ |R| SRAM |C|///| dev |//| sec | BL33 |
+ |O| |P|///| MMIO |//| DRAM | |
+ |M| | |///| |//| | |
+ +-+------+-+---+------+--+-------+------+
+ 0 64K 16M 160M 192M 256M virtual address
+
+
+H616 SoC
+~~~~~~~~
+
+The H616 lacks the secure SRAM region present on the other SoCs, also
+lacks the "ARISC" management processor (SCP) we use. BL31 thus needs to
+run from DRAM, which prevents our compressed virtual memory map described
+above. Since running in DRAM also lifts the restriction of the limited
+SRAM size, we use the normal 1:1 mapping with 32 bits worth of virtual
+address space. So the virtual addresses used in BL31 match the physical
+addresses as presented above.
+
+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).
diff --git a/docs/plat/arm/arm-build-options.rst b/docs/plat/arm/arm-build-options.rst
new file mode 100644
index 0000000..407c04b
--- /dev/null
+++ b/docs/plat/arm/arm-build-options.rst
@@ -0,0 +1,164 @@
+Arm Development Platform Build Options
+======================================
+
+Arm Platform 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<N>``
+ frame registers by setting the ``CNTCTLBase.CNTACR<N>`` register bits. The
+ frame number ``<N>`` 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.
+ - ``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_ROTPK_HASH``: used when ``ARM_ROTPK_LOCATION=devel_*``. Specifies the
+ location of the ROTPK hash. Not expected to be a build option. This defaults to
+ ``plat/arm/board/common/rotpk/*_sha256.bin`` depending on the specified algorithm.
+ Providing ``ROT_KEY`` enforces generation of the hash from the ``ROT_KEY`` and
+ overwrites the default hash file.
+
+- ``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.
+
+- ``ARM_ETHOSN_NPU_DRIVER``: boolean option to enable a SiP service that can
+ configure an Arm® Ethos™-N NPU. To use this service the target platform's
+ ``HW_CONFIG`` must include the device tree nodes for the NPU. Currently, only
+ the Arm Juno platform has this included in its ``HW_CONFIG`` and the platform
+ only loads the ``HW_CONFIG`` in AArch64 builds. Default is 0.
+
+- ``ARM_SPMC_MANIFEST_DTS`` : path to an alternate manifest file used as the
+ SPMC Core manifest. Valid when ``SPD=spmd`` is selected.
+
+- ``ARM_BL2_SP_LIST_DTS``: Path to DTS file snippet to override the hardcoded
+ SP nodes in tb_fw_config.
+
+- ``OPTEE_SP_FW_CONFIG``: DTC build flag to include OP-TEE as SP in tb_fw_config
+ device tree. This flag is defined only when ``ARM_SPMC_MANIFEST_DTS`` manifest
+ file name contains pattern optee_sp.
+
+- ``TS_SP_FW_CONFIG``: DTC build flag to include Trusted Services (Crypto and
+ internal-trusted-storage) as SP in tb_fw_config device tree.
+
+- ``ARM_GPT_SUPPORT``: Enable GPT parser to get the entry address and length of
+ the various partitions present in the GPT image. This support is available
+ only for the BL2 component, and it is disabled by default.
+ The following diagram shows the view of the FIP partition inside the GPT
+ image:
+
+ |FIP in a GPT image|
+
+For a better understanding of these options, the Arm development platform memory
+map is explained in the :ref:`Firmware Design`.
+
+.. _build_options_arm_css_platform:
+
+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.
+
+ - ``CSS_SGI_CHIP_COUNT``: Configures the number of chips on a SGI/RD platform
+ which supports multi-chip operation. If ``CSS_SGI_CHIP_COUNT`` is set to any
+ valid value greater than 1, the platform code performs required configuration
+ to support multi-chip operation.
+
+- ``CSS_SGI_PLATFORM_VARIANT``: Selects the variant of a SGI/RD platform. A
+ particular SGI/RD platform may have multiple variants which may differ in
+ core count, cluster count or other peripherals. This build option is used
+ to select the appropriate platform variant for the build. The range of
+ valid values is platform specific.
+
+- ``CSS_SYSTEM_GRACEFUL_RESET``: Build option to enable graceful powerdown of
+ CPU core on reset. This build option can be used on CSS platforms that
+ require all the CPUs to execute the CPU specific power down sequence to
+ complete a warm reboot sequence in which only the CPUs are power cycled.
+
+--------------
+
+.. |FIP in a GPT image| image:: ../../resources/diagrams/FIP_in_a_GPT_image.png
+
+*Copyright (c) 2019-2021, Arm Limited. All rights reserved.*
diff --git a/docs/plat/arm/arm_fpga/index.rst b/docs/plat/arm/arm_fpga/index.rst
new file mode 100644
index 0000000..5427c1d
--- /dev/null
+++ b/docs/plat/arm/arm_fpga/index.rst
@@ -0,0 +1,97 @@
+Arm FPGA Platform
+=================
+
+This platform supports FPGA images used internally in Arm Ltd., for
+testing and bringup of new cores. With that focus, peripheral support is
+minimal: there is no mass storage or display output, for instance. Also
+this port ignores any power management features of the platform.
+Some interconnect setup is done internally by the platform, so the TF-A code
+just needs to setup UART and GIC.
+
+The FPGA platform requires to pass on a DTB for the non-secure payload
+(mostly Linux), so we let TF-A use information from the DTB for dynamic
+configuration: the UART and GIC base addresses are read from there.
+
+As a result this port is a fairly generic BL31-only port, which can serve
+as a template for a minimal new (and possibly DT-based) platform port.
+
+The aim of this port is to support as many FPGA images as possible with
+a single build. Image specific data must be described in the DTB or should
+be auto-detected at runtime.
+
+As the number and topology layout of the CPU cores differs significantly
+across the various images, this is detected at runtime by BL31.
+The /cpus node in the DT will be added and filled accordingly, as long as
+it does not exist already.
+
+Platform-specific build options
+-------------------------------
+
+- ``SUPPORT_UNKNOWN_MPID`` : Boolean option to allow unknown MPIDR registers.
+ Normally TF-A panics if it encounters a MPID value not matched to its
+ internal list, but for new or experimental cores this creates a lot of
+ churn. With this option, the code will fall back to some basic CPU support
+ code (only architectural system registers, and no errata).
+ Default value of this flag is 1.
+
+- ``PRELOADED_BL33_BASE`` : Physical address of the BL33 non-secure payload.
+ It must have been loaded into DRAM already, typically this is done by
+ the script that also loads BL31 and the DTB.
+ It defaults to 0x80080000, which is the traditional load address for an
+ arm64 Linux kernel.
+
+- ``FPGA_PRELOADED_DTB_BASE`` : Physical address of the flattened device
+ tree blob (DTB). This DT will be used by TF-A for dynamic configuration,
+ so it must describe at least the UART and a GICv3 interrupt controller.
+ The DT gets amended by the code, to potentially add a command line and
+ fill the CPU topology nodes. It will also be passed on to BL33, by
+ putting its address into the x0 register before jumping to the entry
+ point (following the Linux kernel boot protocol).
+ It defaults to 0x80070000, which is 64KB before the BL33 load address.
+
+- ``FPGA_PRELOADED_CMD_LINE`` : Physical address of the command line to
+ put into the devicetree blob. Due to the lack of a proper bootloader,
+ a command line can be put somewhere into memory, so that BL31 will
+ detect it and copy it into the DTB passed on to BL33.
+ To avoid random garbage, there needs to be a "CMD:" signature before the
+ actual command line.
+ Defaults to 0x1000, which is normally in the "ROM" space of the typical
+ FPGA image (which can be written by the FPGA payload uploader, but is
+ read-only to the CPU). The FPGA payload tool should be given a text file
+ containing the desired command line, prefixed by the "CMD:" signature.
+
+Building the TF-A image
+-----------------------
+
+ .. code:: shell
+
+ make PLAT=arm_fgpa DEBUG=1
+
+ This will use the default load addresses as described above. When those
+ addresses need to differ for a certain setup, they can be passed on the
+ make command line:
+
+ .. code:: shell
+
+ make PLAT=arm_fgpa DEBUG=1 PRELOADED_BL33_BASE=0x80200000 FPGA_PRELOADED_DTB_BASE=0x80180000 bl31
+
+Running the TF-A image
+----------------------
+
+After building TF-A, the actual TF-A code will be located in ``bl31.bin`` in
+the build directory.
+Additionally there is a ``bl31.axf`` ELF file, which contains BL31, as well
+as some simple ROM trampoline code (required by the Arm FPGA boot flow) and
+a generic DTB to support most of the FPGA images. This can be simply handed
+over to the FPGA payload uploader, which will take care of loading the
+components at their respective load addresses. In addition to this file
+you need at least a BL33 payload (typically a Linux kernel image), optionally
+a Linux initrd image file and possibly a command line:
+
+ .. code:: shell
+
+ fpga-run ... -m bl31.axf -l auto -m Image -l 0x80080000 -m initrd.gz -l 0x84000000 -m cmdline.txt -l 0x1000
+
+--------------
+
+*Copyright (c) 2020, Arm Limited. All rights reserved.*
diff --git a/docs/plat/arm/corstone1000/index.rst b/docs/plat/arm/corstone1000/index.rst
new file mode 100644
index 0000000..b889b7f
--- /dev/null
+++ b/docs/plat/arm/corstone1000/index.rst
@@ -0,0 +1,61 @@
+Corstone1000 Platform
+==========================
+
+Some of the features of the Corstone1000 platform referenced in TF-A include:
+
+- Cortex-A35 application processor (64-bit mode)
+- Secure Enclave
+- GIC-400
+- Trusted Board Boot
+
+Boot Sequence
+-------------
+
+The board boot relies on CoT (chain of trust). The trusted-firmware-a
+BL2 is extracted from the FIP and verified by the Secure Enclave
+processor. BL2 verification relies on the signature area at the
+beginning of the BL2 image. This area is needed by the SecureEnclave
+bootloader.
+
+Then, the application processor is released from reset and starts by
+executing BL2.
+
+BL2 performs the actions described in the trusted-firmware-a TBB design
+document.
+
+Build Procedure (TF-A only)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Obtain AArch64 ELF bare-metal target `toolchain <https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads>`_.
+ Set the CROSS_COMPILE environment variable to point to the toolchain folder.
+
+- Build TF-A:
+
+ .. code:: shell
+
+ make LD=aarch64-none-elf-ld \
+ CC=aarch64-none-elf-gcc \
+ V=1 \
+ BUILD_BASE=<path to the build folder> \
+ PLAT=corstone1000 \
+ SPD=spmd \
+ SPMD_SPM_AT_SEL2=0 \
+ DEBUG=1 \
+ MBEDTLS_DIR=mbedtls \
+ OPENSSL_DIR=<path to openssl usr folder> \
+ RUNTIME_SYSROOT=<path to the sysroot> \
+ ARCH=aarch64 \
+ TARGET_PLATFORM=<fpga or fvp> \
+ ENABLE_PIE=1 \
+ BL2_AT_EL3=1 \
+ CREATE_KEYS=1 \
+ GENERATE_COT=1 \
+ TRUSTED_BOARD_BOOT=1 \
+ COT=tbbr \
+ ARM_ROTPK_LOCATION=devel_rsa \
+ ROT_KEY=plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem \
+ BL32=<path to optee binary> \
+ BL33=<path to u-boot binary> \
+ bl2
+
+*Copyright (c) 2021, Arm Limited. All rights reserved.*
diff --git a/docs/plat/arm/fvp-ve/index.rst b/docs/plat/arm/fvp-ve/index.rst
new file mode 100644
index 0000000..8ac0741
--- /dev/null
+++ b/docs/plat/arm/fvp-ve/index.rst
@@ -0,0 +1,84 @@
+Arm 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 <https://git.linaro.org/landing-teams/working/arm/u-boot.git>`__
+
+- `Trusted Firmware-A <https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git>`__
+
+Build Procedure
+~~~~~~~~~~~~~~~
+
+- Obtain arm toolchain. The software stack has been verified with linaro 6.2
+ `arm-linux-gnueabihf <https://releases.linaro.org/components/toolchain/binaries/6.2-2016.11/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=<path_to_u-boot.bin> 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=<path_to_u-boot.bin> 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
+
+ ./<path_to_model> <path_to_bl1.elf> \
+ -C motherboard.flashloader1.fname=<path_to_fip.bin> \
+ --data cluster.cpu0=<path_to_zImage>@0x80080000 \
+ --data cluster.cpu0=<path_to_ramdisk>@0x84000000
+
+--------------
+
+*Copyright (c) 2019, Arm Limited. All rights reserved.*
diff --git a/docs/plat/arm/fvp/index.rst b/docs/plat/arm/fvp/index.rst
new file mode 100644
index 0000000..42c0eda
--- /dev/null
+++ b/docs/plat/arm/fvp/index.rst
@@ -0,0 +1,640 @@
+Arm Fixed Virtual Platforms (FVP)
+=================================
+
+Fixed Virtual Platform (FVP) Support
+------------------------------------
+
+This section lists the supported Arm |FVP| platforms. Please refer to the FVP
+documentation for a detailed description of the model parameter options.
+
+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.19 Build 14, unless otherwise stated.
+
+- ``Foundation_Platform``
+- ``FVP_Base_AEMv8A-AEMv8A-AEMv8A-AEMv8A-CCN502`` (Version 11.17/21)
+- ``FVP_Base_AEMv8A-GIC600AE`` (Version 11.17/21)
+- ``FVP_Base_AEMvA``
+- ``FVP_Base_AEMvA-AEMvA``
+- ``FVP_Base_Cortex-A32x4`` (Version 11.12/38)
+- ``FVP_Base_Cortex-A35x4``
+- ``FVP_Base_Cortex-A53x4``
+- ``FVP_Base_Cortex-A55``
+- ``FVP_Base_Cortex-A55x4+Cortex-A75x4``
+- ``FVP_Base_Cortex-A55x4+Cortex-A76x2``
+- ``FVP_Base_Cortex-A57x1-A53x1``
+- ``FVP_Base_Cortex-A57x2-A53x4``
+- ``FVP_Base_Cortex-A57x4``
+- ``FVP_Base_Cortex-A57x4-A53x4``
+- ``FVP_Base_Cortex-A65``
+- ``FVP_Base_Cortex-A65AE``
+- ``FVP_Base_Cortex-A710x4`` (Version 11.17/21)
+- ``FVP_Base_Cortex-A72x4``
+- ``FVP_Base_Cortex-A72x4-A53x4``
+- ``FVP_Base_Cortex-A73x4``
+- ``FVP_Base_Cortex-A73x4-A53x4``
+- ``FVP_Base_Cortex-A75``
+- ``FVP_Base_Cortex-A76``
+- ``FVP_Base_Cortex-A76AE``
+- ``FVP_Base_Cortex-A77``
+- ``FVP_Base_Cortex-A78``
+- ``FVP_Base_Cortex-A78C``
+- ``FVP_Base_Cortex-X2x4`` (Version 11.17/21)
+- ``FVP_Base_Neoverse-E1``
+- ``FVP_Base_Neoverse-N1``
+- ``FVP_Base_Neoverse-N2x4`` (Version 11.16/16)
+- ``FVP_Base_Neoverse-V1``
+- ``FVP_Base_RevC-2xAEMvA``
+- ``FVP_Morello`` (Version 0.11/33)
+- ``FVP_RD_E1_edge`` (Version 11.17/29)
+- ``FVP_RD_V1`` (Version 11.17/29)
+- ``FVP_TC0`` (Version 11.17/18)
+- ``FVP_TC1`` (Version 11.17/33)
+- ``FVP_TC2`` (Version 11.18/28)
+
+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_AEMvA``
+- ``FVP_Base_AEMvA-AEMvA``
+- ``FVP_Base_Cortex-A32x4``
+
+.. note::
+ The ``FVP_Base_RevC-2xAEMvA`` FVP only supports shifted affinities, which
+ is not compatible with legacy GIC configurations. Therefore this FVP does not
+ support these legacy GIC configurations.
+
+The *Foundation* and *Base* FVPs can be downloaded free of charge. See the `Arm
+FVP website`_. The Cortex-A models listed above are also available to download
+from `Arm's website`_.
+
+.. 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="<path-to>/<file-system-image>`` 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.
+
+All the above platforms have been tested with `Linaro Release 20.01`_.
+
+.. _build_options_arm_fvp_platform:
+
+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_GICV2`` : The GICv2 only driver is selected
+ - ``FVP_GICV3`` : The GICv3 only driver is selected (default option)
+
+- ``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.
+
+- ``FVP_GICR_REGION_PROTECTION``: Mark the redistributor pages of
+ inactive/fused CPU cores as read-only. The default value of this option
+ is ``0``, which means the redistributor pages of all CPU cores are marked
+ as read and write.
+
+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.
+
+The additional fip images must be loaded with:
+
+::
+
+ --data cluster0.cpu0="<path_to>/ns_bl1u.bin"@0x0beb8000 [ns_bl1u_base_address]
+ --data cluster0.cpu0="<path_to>/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.
+
+Booting an EL3 payload
+----------------------
+
+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="<path-to>/<el3-payload>"
+
+ 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 <path-to>/el3-payload.elf
+
+#. The EL3 payload may be pre-loaded in volatile memory using the following
+ model parameters:
+
+ ::
+
+ --data cluster0.cpu0="<path-to>/el3-payload>"@address [Base FVPs]
+ --data="<path-to>/<el3-payload>"@address [Foundation FVP]
+
+ The address provided to the FVP must match the ``EL3_PAYLOAD_BASE`` address
+ used when building TF-A.
+
+Booting a preloaded kernel image (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-none-elf- \
+ 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>/<fdt>
+ # Path to the output DTB
+ PATCHED_KERNEL_DTB=<path-to>/<patched-fdt>
+ # Base address of the ramdisk
+ INITRD_BASE=0x84000000
+ # Path to the ramdisk
+ INITRD=<path-to>/<ramdisk.img>
+
+ # 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
+
+ <path-to>/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=0x04001000 \
+ -C cluster0.cpu1.RVBAR=0x04001000 \
+ -C cluster0.cpu2.RVBAR=0x04001000 \
+ -C cluster0.cpu3.RVBAR=0x04001000 \
+ -C cluster1.cpu0.RVBAR=0x04001000 \
+ -C cluster1.cpu1.RVBAR=0x04001000 \
+ -C cluster1.cpu2.RVBAR=0x04001000 \
+ -C cluster1.cpu3.RVBAR=0x04001000 \
+ --data cluster0.cpu0="<path-to>/bl31.bin"@0x04001000 \
+ --data cluster0.cpu0="<path-to>/<patched-fdt>"@0x82000000 \
+ --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000 \
+ --data cluster0.cpu0="<path-to>/<ramdisk.img>"@0x84000000
+
+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
+:ref:`build_options_arm_fvp_platform` for details on the options).
+
+- ``fvp-base-gicv2-psci.dts``
+
+ For use with models such as the Cortex-A57-A53 or Cortex-A32 Base FVPs
+ without shifted affinities and with Base memory map configuration.
+
+- ``fvp-base-gicv3-psci.dts``
+
+ For use with models such as the Cortex-A57-A53 or Cortex-A32 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-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
+
+ <path-to>/Foundation_Platform \
+ --cores=4 \
+ --arm-v8.0 \
+ --secure-memory \
+ --visualization \
+ --gicv3 \
+ --data="<path-to>/<bl1-binary>"@0x0 \
+ --data="<path-to>/<FIP-binary>"@0x08000000 \
+ --data="<path-to>/<kernel-binary>"@0x80080000 \
+ --data="<path-to>/<ramdisk-binary>"@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 ``load-address`` property in the ``hw-config`` node of
+ `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
+
+ <path-to>/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="<path-to>/<bl1-binary>" \
+ -C bp.flashloader0.fname="<path-to>/<FIP-binary>" \
+ --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000 \
+ --data cluster0.cpu0="<path-to>/<ramdisk>"@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
+
+ <path-to>/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="<path-to>/<bl1-binary>" \
+ -C bp.flashloader0.fname="<path-to>/<FIP-binary>" \
+ --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000 \
+ --data cluster0.cpu0="<path-to>/<ramdisk>"@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
+
+ <path-to>/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="<path-to>/<bl1-binary>" \
+ -C bp.flashloader0.fname="<path-to>/<FIP-binary>" \
+ --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000 \
+ --data cluster0.cpu0="<path-to>/<ramdisk>"@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
+
+ <path-to>/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="<path-to>/<bl1-binary>" \
+ -C bp.flashloader0.fname="<path-to>/<FIP-binary>" \
+ --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000 \
+ --data cluster0.cpu0="<path-to>/<ramdisk>"@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
+
+ <path-to>/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="<path-to>/<bl31-binary>"@0x04010000 \
+ --data cluster0.cpu0="<path-to>/<bl32-binary>"@0xff000000 \
+ --data cluster0.cpu0="<path-to>/<bl33-binary>"@0x88000000 \
+ --data cluster0.cpu0="<path-to>/<fdt>"@0x82000000 \
+ --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000 \
+ --data cluster0.cpu0="<path-to>/<ramdisk>"@0x84000000
+
+Notes:
+
+- Position Independent Executable (PIE) support is enabled in this
+ config allowing BL31 to be loaded at any valid address for execution.
+
+- Since a FIP is not loaded when using BL31 as reset entrypoint, the
+ ``--data="<path-to><bl31|bl32|bl33-binary>"@<base-address-of-binary>``
+ 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="<path-to>/<fdt>"@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<X>.cpu<Y>.RVBAR=@<base-address-of-bl31>`` 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="<path-to><bl32-binary>"@<base-address-of-bl32>`` 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
+
+ <path-to>/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="<path-to>/<bl32-binary>"@0x04002000 \
+ --data cluster0.cpu0="<path-to>/<bl33-binary>"@0x88000000 \
+ --data cluster0.cpu0="<path-to>/<fdt>"@0x82000000 \
+ --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000 \
+ --data cluster0.cpu0="<path-to>/<ramdisk>"@0x84000000
+
+.. note::
+ Position Independent Executable (PIE) support is enabled in this
+ config allowing SP_MIN to be loaded at any valid address for execution.
+
+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
+
+ <path-to>/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="<path-to>/<bl31-binary>"@0x04010000 \
+ --data cluster0.cpu0="<path-to>/<bl32-binary>"@0xff000000 \
+ --data cluster0.cpu0="<path-to>/<bl33-binary>"@0x88000000 \
+ --data cluster0.cpu0="<path-to>/<fdt>"@0x82000000 \
+ --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000 \
+ --data cluster0.cpu0="<path-to>/<ramdisk>"@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
+
+ <path-to>/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="<path-to>/<bl32-binary>"@0x04002000 \
+ --data cluster0.cpu0="<path-to>/<bl33-binary>"@0x88000000 \
+ --data cluster0.cpu0="<path-to>/<fdt>"@0x82000000 \
+ --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000 \
+ --data cluster0.cpu0="<path-to>/<ramdisk>"@0x84000000
+
+--------------
+
+*Copyright (c) 2019-2022, Arm Limited. All rights reserved.*
+
+.. _FW_CONFIG for FVP: https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/plat/arm/board/fvp/fdts/fvp_fw_config.dts
+.. _Arm's website: `FVP models`_
+.. _FVP models: https://developer.arm.com/products/system-design/fixed-virtual-platforms
+.. _Linaro Release 20.01: http://releases.linaro.org/members/arm/platforms/20.01
+.. _Arm FVP website: https://developer.arm.com/products/system-design/fixed-virtual-platforms
diff --git a/docs/plat/arm/fvp_r/index.rst b/docs/plat/arm/fvp_r/index.rst
new file mode 100644
index 0000000..8af16ba
--- /dev/null
+++ b/docs/plat/arm/fvp_r/index.rst
@@ -0,0 +1,46 @@
+ARM V8-R64 Fixed Virtual Platform (FVP)
+=======================================
+
+Some of the features of Armv8-R AArch64 FVP platform referenced in Trusted
+Boot R-class include:
+
+- Secure World Support Only
+- EL2 as Maximum EL support (No EL3)
+- MPU Support only at EL2
+- MPU or MMU Support at EL0/EL1
+- AArch64 Support Only
+- Trusted Board Boot
+
+Further information on v8-R64 FVP is available at `info <https://developer.arm.com/documentation/ddi0600/latest/>`_
+
+Boot Sequence
+-------------
+
+BL1 –> BL33
+
+The execution begins from BL1 which loads the BL33 image, a boot-wrapped (bootloader + Operating System)
+Operating System, from FIP to DRAM.
+
+Build Procedure
+~~~~~~~~~~~~~~~
+
+- Obtain arm `toolchain <https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads>`_.
+ Set the CROSS_COMPILE environment variable to point to the toolchain folder.
+
+- Build TF-A:
+
+ .. code:: shell
+
+ make PLAT=fvp_r BL33=<path_to_os.bin> all fip
+
+ Enable TBBR by adding the following options to the make command:
+
+ .. code:: shell
+
+ MBEDTLS_DIR=<path_to_mbedtls_directory> \
+ TRUSTED_BOARD_BOOT=1 \
+ GENERATE_COT=1 \
+ ARM_ROTPK_LOCATION=devel_rsa \
+ ROT_KEY=plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem
+
+*Copyright (c) 2021, Arm Limited. All rights reserved.*
diff --git a/docs/plat/arm/index.rst b/docs/plat/arm/index.rst
new file mode 100644
index 0000000..2f68522
--- /dev/null
+++ b/docs/plat/arm/index.rst
@@ -0,0 +1,24 @@
+Arm Development Platforms
+=========================
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents
+
+ juno/index
+ fvp/index
+ fvp_r/index
+ fvp-ve/index
+ tc/index
+ arm_fpga/index
+ arm-build-options
+ morello/index
+ corstone1000/index
+
+This chapter holds documentation related to Arm's development platforms,
+including both software models (FVPs) and hardware development boards
+such as Juno.
+
+--------------
+
+*Copyright (c) 2019-2021, Arm Limited. All rights reserved.*
diff --git a/docs/plat/arm/juno/index.rst b/docs/plat/arm/juno/index.rst
new file mode 100644
index 0000000..91e681f
--- /dev/null
+++ b/docs/plat/arm/juno/index.rst
@@ -0,0 +1,253 @@
+Arm Juno Development Platform
+=============================
+
+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.
+
+Running software on Juno
+------------------------
+
+This version of TF-A has been tested on variants r0, r1 and r2 of Juno.
+
+To run TF-A on Juno, you need to first prepare an SD card with Juno software
+stack that includes TF-A. This version of TF-A is tested with pre-built
+`Linaro release software stack`_ version 20.01. You can alternatively
+build the software stack yourself by following the
+`Juno platform software user guide`_. Once you prepare the software stack
+on an SD card, you can replace the ``bl1.bin`` and ``fip.bin``
+binaries in the ``SOFTWARE/`` directory with custom built TF-A binaries.
+
+Preparing TF-A images
+---------------------
+
+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 software stack 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.
+
+#. Clean the working directory
+
+ .. code:: shell
+
+ make realclean
+
+#. Obtain SCP binaries (Juno)
+
+ This version of TF-A is tested with SCP version 2.8.0 on Juno. You can
+ download pre-built SCP binaries (``scp_bl1.bin`` and ``scp_bl2.bin``)
+ from `TF-A downloads page`_. Alternatively, you can `build
+ the binaries from source`_.
+
+#. Obtain BL33 (all platforms)
+
+ Use the fiptool to extract the BL33 image 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 <path-to-linaro-release>/[SOFTWARE]/fip.bin
+
+ The unpack operation will result in a set of binary images extracted to the
+ current working directory. 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_bl2.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 Linaro cross compiler.
+
+ .. code:: shell
+
+ export CROSS_COMPILE=<path-to-aarch32-gcc>/bin/arm-linux-gnueabihf-
+
+ - 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 <path-to-build>/bl32.bin <path-to-temporary>
+ make realclean
+
+ - Before building BL1 and BL2, the environment variable ``CROSS_COMPILE``
+ must point to the AArch64 Linaro cross compiler.
+
+ .. code:: shell
+
+ export CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-none-elf-
+
+ - 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_bl2.bin \
+ BL32=<path-to-temporary>/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
+
+After building TF-A, the files ``bl1.bin``, ``fip.bin`` and ``scp_bl1.bin``
+need to be copied to the ``SOFTWARE/`` directory on the Juno SD card.
+
+Booting Firmware Update images
+------------------------------
+
+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.
+
+.. _plat_juno_booting_el3_payload:
+
+Booting an EL3 payload
+----------------------
+
+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.
+
+For more information on EL3 payloads in general, see
+:ref:`alt_boot_flows_el3_payload`.
+
+Booting a preloaded kernel image
+--------------------------------
+
+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
+`plat_juno_booting_el3_payload`_.
+
+Testing System Suspend
+----------------------
+
+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.
+
+Additional Resources
+--------------------
+
+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.
+
+--------------
+
+*Copyright (c) 2019-2022, Arm Limited. All rights reserved.*
+
+.. _Linaro release software stack: http://releases.linaro.org/members/arm/platforms/
+.. _Juno platform software user guide: https://git.linaro.org/landing-teams/working/arm/arm-reference-platforms.git/about/docs/juno/user-guide.rst
+.. _TF-A downloads page: https://downloads.trustedfirmware.org/tf-a/css_scp_2.8.0/juno/
+.. _build the binaries from source: https://github.com/ARM-software/SCP-firmware/blob/master/user_guide.md#scp-firmware-user-guide
+.. _Arm Platforms Portal: https://community.arm.com/dev-platforms/
+.. _Juno Getting Started Guide: https://developer.arm.com/documentation/den0928/f/?lang=en
+.. _PSCI: http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf
+.. _Juno Arm Development Platform: http://www.arm.com/products/tools/development-boards/versatile-express/juno-arm-development-platform.php
diff --git a/docs/plat/arm/morello/index.rst b/docs/plat/arm/morello/index.rst
new file mode 100644
index 0000000..b18001c
--- /dev/null
+++ b/docs/plat/arm/morello/index.rst
@@ -0,0 +1,33 @@
+Morello Platform
+================
+
+Morello is an ARMv8-A platform that implements the capability architecture extension.
+The platform port present at `site <https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git>`_
+provides ARMv8-A architecture enablement.
+
+Capability architecture specific changes will be added `here <https://git.morello-project.org/morello>`_
+
+Further information on Morello Platform is available at `info <https://developer.arm.com/architectures/cpu-architecture/a-profile/morello>`_
+
+Boot Sequence
+-------------
+
+The execution begins from SCP_BL1 which loads the SCP_BL2 and starts its
+execution. SCP_BL2 powers up the AP which starts execution at AP_BL31. The AP
+then continues executing and hands off execution to Non-secure world (UEFI).
+
+Build Procedure (TF-A only)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Obtain arm `toolchain <https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads>`_.
+ Set the CROSS_COMPILE environment variable to point to the toolchain folder.
+
+- Build TF-A:
+
+ .. code:: shell
+
+ export CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-none-elf-
+
+ make PLAT=morello all
+
+*Copyright (c) 2020, Arm Limited. All rights reserved.*
diff --git a/docs/plat/arm/tc/index.rst b/docs/plat/arm/tc/index.rst
new file mode 100644
index 0000000..df1847d
--- /dev/null
+++ b/docs/plat/arm/tc/index.rst
@@ -0,0 +1,63 @@
+TC Total Compute Platform
+==========================
+
+Some of the features of TC platform referenced in TF-A include:
+
+- A `System Control Processor <https://github.com/ARM-software/SCP-firmware>`_
+ to abstract power and system management tasks away from application
+ processors. The RAM firmware for SCP is included in the TF-A FIP and is
+ loaded by AP BL2 from FIP in flash to SRAM for copying by SCP (SCP has access
+ to AP SRAM).
+- GICv4
+- Trusted Board Boot
+- SCMI
+- MHUv2
+
+Currently, the main difference between TC0 (TARGET_PLATFORM=0), TC1
+(TARGET_PLATFORM=1), TC2 (TARGET_PLATFORM=2) platforms w.r.t to TF-A
+is the CPUs supported as below:
+
+- TC0 has support for Cortex A510, Cortex A710 and Cortex X2.
+- TC1 has support for Cortex A510, Cortex Makalu and Cortex X3.
+- TC2 has support for Hayes and Hunter Arm CPUs.
+
+
+Boot Sequence
+-------------
+
+The execution begins from SCP_BL1. SCP_BL1 powers up the AP which starts
+executing AP_BL1 and then executes AP_BL2 which loads the SCP_BL2 from
+FIP to SRAM. The SCP has access to AP SRAM. The address and size of SCP_BL2
+is communicated to SCP using SDS. SCP copies SCP_BL2 from SRAM to its own
+RAM and starts executing it. The AP then continues executing the rest of TF-A
+stages including BL31 runtime stage and hands off executing to
+Non-secure world (u-boot).
+
+Build Procedure (TF-A only)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Obtain `Arm toolchain`_ and set the CROSS_COMPILE environment variable to
+ point to the toolchain folder.
+
+- Build TF-A:
+
+ .. code:: shell
+
+ make PLAT=tc BL33=<path_to_uboot.bin> \
+ SCP_BL2=<path_to_scp_ramfw.bin> TARGET_PLATFORM={0,1,2} all fip
+
+ Enable TBBR by adding the following options to the make command:
+
+ .. code:: shell
+
+ MBEDTLS_DIR=<path_to_mbedtls_directory> \
+ TRUSTED_BOARD_BOOT=1 \
+ GENERATE_COT=1 \
+ ARM_ROTPK_LOCATION=devel_rsa \
+ ROT_KEY=plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem
+
+--------------
+
+*Copyright (c) 2020-2022, Arm Limited. All rights reserved.*
+
+.. _Arm Toolchain: https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/downloads
diff --git a/docs/plat/brcm-stingray.rst b/docs/plat/brcm-stingray.rst
new file mode 100644
index 0000000..95029cc
--- /dev/null
+++ b/docs/plat/brcm-stingray.rst
@@ -0,0 +1,43 @@
+Broadcom Stingray
+=================
+
+Description
+-----------
+Broadcom's Stingray(BCM958742t) is a multi-core processor with 8 Cortex-A72 cores.
+Trusted Firmware-A (TF-A) is used to implement secure world firmware, supporting
+BL2 and BL31 for Broadcom Stingray SoCs.
+
+On Poweron, Boot ROM will load bl2 image and Bl2 will initialize the hardware,
+then loads bl31 and bl33 into DDR and boots to bl33.
+
+Boot Sequence
+-------------
+
+Bootrom --> TF-A BL2 --> TF-A BL31 --> BL33(u-boot)
+
+Code Locations
+~~~~~~~~~~~~~~
+- Trusted Firmware-A:
+ `link <https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/>`__
+
+How to build
+------------
+
+Build Procedure
+~~~~~~~~~~~~~~~
+
+- Prepare AARCH64 toolchain.
+
+- Build u-boot first, and get the binary image: u-boot.bin,
+
+- Build TF-A
+
+ Build fip:
+
+ .. code:: shell
+
+ make CROSS_COMPILE=aarch64-linux-gnu- PLAT=stingray BOARD_CFG=bcm958742t all fip BL33=u-boot.bin
+
+Deploy TF-A Images
+~~~~~~~~~~~~~~~~~~
+The u-boot will be upstreamed soon, this doc will be updated once they are ready, and the link will be posted.
diff --git a/docs/plat/hikey.rst b/docs/plat/hikey.rst
new file mode 100644
index 0000000..6c488b8
--- /dev/null
+++ b/docs/plat/hikey.rst
@@ -0,0 +1,155 @@
+HiKey
+=====
+
+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 <https://github.com/ARM-software/arm-trusted-firmware>`__
+
+- OP-TEE
+ `link <https://github.com/OP-TEE/optee_os>`__
+
+- edk2:
+ `link <https://github.com/96boards-hikey/edk2/tree/testing/hikey960_v2.5>`__
+
+- OpenPlatformPkg:
+ `link <https://github.com/96boards-hikey/OpenPlatformPkg/tree/testing/hikey960_v1.3.4>`__
+
+- l-loader:
+ `link <https://github.com/96boards-hikey/l-loader/tree/testing/hikey960_v1.2>`__
+
+- atf-fastboot:
+ `link <https://github.com/96boards-hikey/atf-fastboot/tree/master>`__
+
+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://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 *OpenPlatformPkg/Platforms/Hisilicon/HiKey/HiKey.dsc* first. *(optional)*
+ console on hikey.**
+
+ .. code:: shell
+
+ DEFINE SERIAL_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
+
+ cd {BUILD_PATH}/arm-trusted-firmware
+ sh ../l-loader/build_uefi.sh 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 <http://releases.linaro.org/96boards/>`__.
+
+ .. 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 <https://github.com/96boards-hikey/tools-images-hikey960/blob/master/build-from-source/README-ATF-UEFI-build-from-source.md>`__
+
+.. _link: https://www.96boards.org/documentation/consumer/hikey/
diff --git a/docs/plat/hikey960.rst b/docs/plat/hikey960.rst
new file mode 100644
index 0000000..982c2c8
--- /dev/null
+++ b/docs/plat/hikey960.rst
@@ -0,0 +1,180 @@
+HiKey960
+========
+
+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 <https://github.com/ARM-software/arm-trusted-firmware>`__
+
+- OP-TEE:
+ `link <https://github.com/OP-TEE/optee_os>`__
+
+- edk2:
+ `link <https://github.com/96boards-hikey/edk2/tree/testing/hikey960_v2.5>`__
+
+- OpenPlatformPkg:
+ `link <https://github.com/96boards-hikey/OpenPlatformPkg/tree/testing/hikey960_v1.3.4>`__
+
+- l-loader:
+ `link <https://github.com/96boards-hikey/l-loader/tree/testing/hikey960_v1.2>`__
+
+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
+
+- 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 *OpenPlatformPkg/Platforms/Hisilicon/HiKey960/HiKey960.dsc* first. *(optional)*
+
+ .. code:: shell
+
+ DEFINE SERIAL_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
+
+ cd {BUILD_PATH}/arm-trusted-firmware
+ sh ../l-loader/build_uefi.sh 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 <https://github.com/96boards-hikey/tools-images-hikey960>`__
+
+- 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 <https://github.com/96boards-hikey/tools-images-hikey960/blob/master/build-from-source/README-ATF-UEFI-build-from-source.md>`__
+
+.. _link: https://www.96boards.org/documentation/consumer/hikey/hikey960
diff --git a/docs/plat/imx8.rst b/docs/plat/imx8.rst
new file mode 100644
index 0000000..49ba374
--- /dev/null
+++ b/docs/plat/imx8.rst
@@ -0,0 +1,58 @@
+NXP 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=<Target_SoC> 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
diff --git a/docs/plat/imx8m.rst b/docs/plat/imx8m.rst
new file mode 100644
index 0000000..f8071f7
--- /dev/null
+++ b/docs/plat/imx8m.rst
@@ -0,0 +1,113 @@
+NXP 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.
+
+imx8mq is dropped in TF-A CI build due to the small OCRAM size, but still actively
+maintained in NXP official release.
+
+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=<Target_SoC> bl31
+
+ Target_SoC should be "imx8mq" for i.MX8MQ SoC.
+ Target_SoC should be "imx8mm" for i.MX8MM SoC.
+ Target_SoC should be "imx8mn" for i.MX8MN SoC.
+ Target_SoC should be "imx8mp" for i.MX8MP 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.
+
+TBBR Boot Sequence
+------------------
+
+When setting NEED_BL2=1 on imx8mm. We support an alternative way of
+boot sequence to support TBBR.
+
+Bootrom --> SPL --> BL2 --> BL31 --> BL33(u-boot with UEFI) --> grub
+
+This helps us to fulfill the SystemReady EBBR standard.
+BL2 will be in the FIT image and SPL will verify it.
+All of the BL3x will be put in the FIP image. BL2 will verify them.
+In U-boot we turn on the UEFI secure boot features so it can verify
+grub. And we use grub to verify linux kernel.
+
+Measured Boot
+-------------
+
+When setting MEASURED_BOOT=1 on imx8mm we can let TF-A generate event logs
+with a DTB overlay. The overlay will be put at PLAT_IMX8M_DTO_BASE with
+maximum size PLAT_IMX8M_DTO_MAX_SIZE. Then in U-boot we can apply the DTB
+overlay and let U-boot to parse the event log and update the PCRs.
+
+High Assurance Boot (HABv4)
+---------------------------
+
+All actively maintained platforms have a support for High Assurance
+Boot (HABv4), which is implemented via ROM Vector Table (RVT) API to
+extend the Root-of-Trust beyond the SPL. Those calls are done via SMC
+and are executed in EL3, with results returned back to original caller.
+
+Note on DRAM Memory Mapping
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There is a special case of mapping the DRAM: entire DRAM available on the
+platform is mapped into the EL3 with MT_RW attributes.
+
+Mapping the entire DRAM allows the usage of 2MB block mapping in Level-2
+Translation Table entries, which use less Page Table Entries (PTEs). If
+Level-3 PTE mapping is used instead then additional PTEs would be required,
+which leads to the increase of translation table size.
+
+Due to the fact that the size of SRAM is limited on some platforms in the
+family it should rather be avoided creating additional Level-3 mapping and
+introduce more PTEs, hence the implementation uses Level-2 mapping which
+maps entire DRAM space.
+
+The reason for the MT_RW attribute mapping scheme is the fact that the SMC
+API to get the status and events is called from NS world passing destination
+pointers which are located in DRAM. Mapping DRAM without MT_RW permissions
+causes those locations not to be filled, which in turn causing EL1&0 software
+not to receive replies.
+
+Therefore, DRAM mapping is done with MT_RW attributes, as it is required for
+data exchange between EL3 and EL1&0 software.
+
+Reference Documentation
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Details on HABv4 usage and implementation could be found in following documents:
+
+- AN4581: "i.MX Secure Boot on HABv4 Supported Devices", Rev. 4 - June 2020
+- AN12263: "HABv4 RVT Guidelines and Recommendations", Rev. 1 - 06/2020
+- "HABv4 API Reference Manual". This document in the part of NXP Code Signing Tool (CST) distribution.
+
diff --git a/docs/plat/index.rst b/docs/plat/index.rst
new file mode 100644
index 0000000..a4e2067
--- /dev/null
+++ b/docs/plat/index.rst
@@ -0,0 +1,82 @@
+Platform Ports
+==============
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents
+ :hidden:
+
+ allwinner
+ arm/index
+ meson-axg
+ meson-gxbb
+ meson-gxl
+ meson-g12a
+ hikey
+ hikey960
+ intel-agilex
+ intel-stratix10
+ marvell/index
+ mt8183
+ mt8186
+ mt8188
+ mt8192
+ mt8195
+ nvidia-tegra
+ warp7
+ imx8
+ imx8m
+ nxp/index
+ poplar
+ qemu
+ qemu-sbsa
+ qti
+ qti-msm8916
+ rpi3
+ rpi4
+ rcar-gen3
+ rz-g2
+ rockchip
+ socionext-uniphier
+ synquacer
+ stm32mp1
+ ti-k3
+ xilinx-versal-net
+ xilinx-versal
+ xilinx-zynqmp
+ brcm-stingray
+
+This section provides a list of supported upstream *platform ports* and the
+documentation associated with them.
+
+.. 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 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
+ - MediaTek MT8173 SoCs
+
+Deprecated platforms
+--------------------
+
++----------------+----------------+--------------------+--------------------+
+| Platform | Vendor | Deprecated version | Deleted version |
++================+================+====================+====================+
+| sgm775 | Arm | 2.5 | 2.7 |
++----------------+----------------+--------------------+--------------------+
+| mt6795 | MTK | 2.5 | 2.7 |
++----------------+----------------+--------------------+--------------------+
+| sgi575 | Arm | 2.8 | 3.0 |
++----------------+----------------+--------------------+--------------------+
+| rdn1edge | Arm | 2.8 | 3.0 |
++----------------+----------------+--------------------+--------------------+
+| tc0 | Arm | 2.8 | 3.0 |
++----------------+----------------+--------------------+--------------------+
+
+--------------
+
+*Copyright (c) 2019-2022, Arm Limited. All rights reserved.*
diff --git a/docs/plat/intel-agilex.rst b/docs/plat/intel-agilex.rst
new file mode 100644
index 0000000..ff27b6b
--- /dev/null
+++ b/docs/plat/intel-agilex.rst
@@ -0,0 +1,86 @@
+Intel 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 <https://github.com/ARM-software/arm-trusted-firmware>`__
+
+- UEFI (to be updated with new upstreamed UEFI):
+ `link <https://github.com/altera-opensource/uefi-socfpga>`__
+
+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 <quartus_generated_sof> <output_sof_with_bl2>
+
+- Configure SOF to board
+
+.. code:: bash
+
+ nios2-configure-sof <output_sof_with_bl2>
+
+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
diff --git a/docs/plat/intel-stratix10.rst b/docs/plat/intel-stratix10.rst
new file mode 100644
index 0000000..7f8d18e
--- /dev/null
+++ b/docs/plat/intel-stratix10.rst
@@ -0,0 +1,94 @@
+Intel 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 <https://github.com/ARM-software/arm-trusted-firmware>`__
+
+- UEFI (to be updated with new upstreamed UEFI):
+ `link <https://github.com/altera-opensource/uefi-socfpga>`__
+
+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 <quartus_generated_sof> <output_sof_with_bl2>
+
+- Configure SOF to board
+
+.. code:: bash
+
+ nios2-configure-sof <output_sof_with_bl2>
+
+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)
diff --git a/docs/plat/marvell/armada/build.rst b/docs/plat/marvell/armada/build.rst
new file mode 100644
index 0000000..8cb3fdf
--- /dev/null
+++ b/docs/plat/marvell/armada/build.rst
@@ -0,0 +1,476 @@
+TF-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 A7K/A8K/CN913x when MSS_SUPPORT=1)
+
+ .. 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:
+
+- PLAT
+
+ Supported Marvell platforms are:
+
+ - a3700 - A3720 DB, EspressoBin and Turris MOX
+ - a70x0
+ - a70x0_amc - AMC board
+ - a70x0_mochabin - Globalscale MOCHAbin
+ - a80x0
+ - a80x0_mcbin - MacchiatoBin
+ - a80x0_puzzle - IEI Puzzle-M801
+ - t9130 - CN913x
+ - t9130_cex7_eval - CN913x CEx7 Evaluation Board
+
+- DEBUG
+
+ Default is without debug information (=0). in order to enable it use ``DEBUG=1``.
+ Can be enabled also when building UART recovery images, there is no issue with it.
+
+ Production TF-A images should be built without this debug option!
+
+- LOG_LEVEL
+
+ Defines the level of logging which will be purged to the default output port.
+
+ - 0 - LOG_LEVEL_NONE
+ - 10 - LOG_LEVEL_ERROR
+ - 20 - LOG_LEVEL_NOTICE (default for DEBUG=0)
+ - 30 - LOG_LEVEL_WARNING
+ - 40 - LOG_LEVEL_INFO (default for DEBUG=1)
+ - 50 - LOG_LEVEL_VERBOSE
+
+- USE_COHERENT_MEM
+
+ This flag determines whether to include the coherent memory region in the
+ BL memory map or not. Enabled by default.
+
+- LLC_ENABLE
+
+ Flag defining the LLC (L3) cache state. The cache is enabled by default (``LLC_ENABLE=1``).
+
+- LLC_SRAM
+
+ Flag enabling the LLC (L3) cache SRAM support. The LLC SRAM is activated and used
+ by Trusted OS (OP-TEE OS, BL32). The TF-A only prepares CCU address translation windows
+ for SRAM address range at BL31 execution stage with window target set to DRAM-0.
+ When Trusted OS activates LLC SRAM, the CCU window target is changed to SRAM.
+ There is no reason to enable this feature if OP-TEE OS built with CFG_WITH_PAGER=n.
+ Only set LLC_SRAM=1 if OP-TEE OS is built with CFG_WITH_PAGER=y.
+
+- MARVELL_SECURE_BOOT
+
+ Build trusted(=1)/non trusted(=0) image, default is non trusted.
+ This parameter is used only for ``mrvl_flash`` and ``mrvl_uart`` targets.
+
+- MV_DDR_PATH
+
+ This parameter is required for ``mrvl_flash`` and ``mrvl_uart`` targets.
+ For A7K/A8K/CN913x it is used for BLE build and for Armada37x0 it used
+ for ddr_tool build.
+
+ Specify path to the full checkout of Marvell mv-ddr-marvell git
+ repository. Checkout must contain also .git subdirectory because
+ mv-ddr build process calls git commands.
+
+ Do not remove any parts of git checkout becuase build process and other
+ applications need them for correct building and version determination.
+
+
+CN913x specific build options:
+
+- CP_NUM
+
+ Total amount of CPs (South Bridge) connected to AP. When the parameter is omitted,
+ the build uses the default number of CPs, which is a number of embedded CPs inside the
+ package: 1 or 2 depending on the SoC used. The parameter is valid for OcteonTX2 CN913x SoC
+ family (PLAT=t9130), which can have external CPs connected to the MCI ports. Valid
+ values with CP_NUM are in a range of 1 to 3.
+
+
+A7K/A8K/CN913x specific build options:
+
+- BLE_PATH
+
+ Points to BLE (Binary ROM extension) sources folder.
+ The parameter is optional, its default value is ``plat/marvell/armada/a8k/common/ble``
+ which uses TF-A in-tree BLE implementation.
+
+- MSS_SUPPORT
+
+ When ``MSS_SUPPORT=1``, then TF-A includes support for Management SubSystem (MSS).
+ When enabled it is required to specify path to the MSS firmware image via ``SCP_BL2``
+ option.
+
+ This option is by default enabled.
+
+- SCP_BL2
+
+ Specify path to the MSS fimware image binary which will run on Cortex-M3 coprocessor.
+ It is available in Marvell binaries-marvell git repository. Required when ``MSS_SUPPORT=1``.
+
+Globalscale MOCHAbin specific build options:
+
+- DDR_TOPOLOGY
+
+ The DDR topology map index/name, default is 0.
+
+ Supported Options:
+ - 0 - DDR4 1CS 2GB
+ - 1 - DDR4 1CS 4GB
+ - 2 - DDR4 2CS 8GB
+
+Armada37x0 specific build options:
+
+- HANDLE_EA_EL3_FIRST_NS
+
+ When ``HANDLE_EA_EL3_FIRST_NS=1``, External Aborts and SError Interrupts, resulting from errors
+ in NS world, will be always trapped in TF-A. TF-A in this case enables dirty hack / workaround for
+ a bug found in U-Boot and Linux kernel PCIe controller driver pci-aardvark.c, traps and then masks
+ SError interrupt caused by AXI SLVERR on external access (syndrome 0xbf000002).
+
+ Otherwise when ``HANDLE_EA_EL3_FIRST_NS=0``, these exceptions will be trapped in the current
+ exception level (or in EL1 if the current exception level is EL0). So exceptions caused by
+ U-Boot will be trapped in U-Boot, exceptions caused by Linux kernel (or user applications)
+ will be trapped in Linux kernel.
+
+ Mentioned bug in pci-aardvark.c driver is fixed in U-Boot version v2021.07 and Linux kernel
+ version v5.13 (workarounded since Linux kernel version 5.9) and also backported in Linux
+ kernel stable releases since versions v5.12.13, v5.10.46, v5.4.128, v4.19.198, v4.14.240.
+
+ If target system has already patched version of U-Boot and Linux kernel then it is strongly
+ recommended to not enable this workaround as it disallows propagating of all External Aborts
+ to running Linux kernel and makes correctable errors as fatal aborts.
+
+ This option is now disabled by default. In past this option has different name "HANDLE_EA_EL3_FIRST" and
+ was enabled by default in TF-A versions v2.2, v2.3, v2.4 and v2.5.
+
+- CM3_SYSTEM_RESET
+
+ When ``CM3_SYSTEM_RESET=1``, the Cortex-M3 secure coprocessor will be used for system reset.
+
+ TF-A will send command 0x0009 with a magic value via the rWTM mailbox interface to the
+ Cortex-M3 secure coprocessor.
+ The firmware running in the coprocessor must either implement this functionality or
+ ignore the 0x0009 command (which is true for the firmware from A3700-utils-marvell
+ repository). If this option is enabled but the firmware does not support this command,
+ an error message will be printed prior trying to reboot via the usual way.
+
+ This option is needed on Turris MOX as a workaround to a HW bug which causes reset to
+ sometime hang the board.
+
+- A3720_DB_PM_WAKEUP_SRC
+
+ For Armada 3720 Development Board only, when ``A3720_DB_PM_WAKEUP_SRC=1``,
+ TF-A will setup PM wake up src configuration. This option is disabled by default.
+
+
+Armada37x0 specific build options for ``mrvl_flash`` and ``mrvl_uart`` targets:
+
+- DDR_TOPOLOGY
+
+ The DDR topology map index/name, default is 0.
+
+ Supported Options:
+ - 0 - DDR3 1CS 512MB (DB-88F3720-DDR3-Modular, EspressoBin V3-V5)
+ - 1 - DDR4 1CS 512MB (DB-88F3720-DDR4-Modular)
+ - 2 - DDR3 2CS 1GB (EspressoBin V3-V5)
+ - 3 - DDR4 2CS 4GB (DB-88F3720-DDR4-Modular)
+ - 4 - DDR3 1CS 1GB (DB-88F3720-DDR3-Modular, EspressoBin V3-V5)
+ - 5 - DDR4 1CS 1GB (EspressoBin V7, EspressoBin-Ultra)
+ - 6 - DDR4 2CS 2GB (EspressoBin V7)
+ - 7 - DDR3 2CS 2GB (EspressoBin V3-V5)
+ - CUST - CUSTOMER BOARD (Customer board settings)
+
+- CLOCKSPRESET
+
+ 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
+
+ Look at Armada37x0 chip package marking on board to identify correct CPU frequency.
+ The last line on package marking (next line after the 88F37x0 line) should contain:
+
+ - C080 or I080 - chip with 800 MHz CPU - use ``CLOCKSPRESET=CPU_800_DDR_800``
+ - C100 or I100 - chip with 1000 MHz CPU - use ``CLOCKSPRESET=CPU_1000_DDR_800``
+ - C120 - chip with 1200 MHz CPU - use ``CLOCKSPRESET=CPU_1200_DDR_750``
+
+- BOOTDEV
+
+ 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
+
+ Image needs to be stored at disk LBA 0 or at disk partition with
+ MBR type 0x4d (ASCII 'M' as in Marvell) or at disk partition with
+ GPT partition type GUID ``6828311A-BA55-42A4-BCDE-A89BB5EDECAE``.
+
+- PARTNUM
+
+ 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
+
+ The path of the binary can point to an image which
+ does nothing, an image which supports EFUSE or a customized CM3 firmware
+ binary. The default image is ``fuse.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.
+
+ Please note that this is not a full WTMI image, just a main loop without
+ hardware initialization code. Final WTMI image is built from this WTMI_IMG
+ binary and sys-init code from the WTP directory which sets DDR and CPU
+ clocks according to DDR_TOPOLOGY and CLOCKSPRESET options.
+
+ CZ.NIC as part of Turris project released free and open source WTMI
+ application firmware ``wtmi_app.bin`` for all Armada 3720 devices.
+ This firmware includes additional features like access to Hardware
+ Random Number Generator of Armada 3720 SoC which original Marvell's
+ ``fuse.bin`` image does not have.
+
+ CZ.NIC's Armada 3720 Secure Firmware is available at website:
+
+ https://gitlab.nic.cz/turris/mox-boot-builder/
+
+- WTP
+
+ Specify path to the full checkout of Marvell A3700-utils-marvell git
+ repository. Checkout must contain also .git subdirectory because WTP
+ build process calls git commands.
+
+ WTP build process uses also Marvell mv-ddr-marvell git repository
+ specified in MV_DDR_PATH option.
+
+ Do not remove any parts of git checkout becuase build process and other
+ applications need them for correct building and version determination.
+
+- CRYPTOPP_PATH
+
+ Use this parameter to point to Crypto++ source code
+ directory. If this option is specified then Crypto++ source code in
+ CRYPTOPP_PATH directory will be automatically compiled. Crypto++ library
+ is required for building WTP image tool. Either CRYPTOPP_PATH or
+ CRYPTOPP_LIBDIR with CRYPTOPP_INCDIR needs to be specified for Armada37x0.
+
+- CRYPTOPP_LIBDIR
+
+ Use this parameter to point to the directory with
+ compiled Crypto++ library. By default it points to the CRYPTOPP_PATH.
+
+ On Debian systems it is possible to install system-wide Crypto++ library
+ via command ``apt install libcrypto++-dev`` and specify CRYPTOPP_LIBDIR
+ to ``/usr/lib/``.
+
+- CRYPTOPP_INCDIR
+
+ Use this parameter to point to the directory with
+ header files of Crypto++ library. By default it points to the CRYPTOPP_PATH.
+
+ On Debian systems it is possible to install system-wide Crypto++ library
+ via command ``apt install libcrypto++-dev`` and specify CRYPTOPP_INCDIR
+ to ``/usr/include/crypto++/``.
+
+
+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=<MARVELL_PLATFORM> mrvl_flash
+
+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 \
+ MV_DDR_PATH=/path/to/mv-ddr-marvell/ WTP=/path/to/A3700-utils-marvell/ \
+ CRYPTOPP_PATH=/path/to/cryptopp/ BL33=/path/to/u-boot.bin \
+ all fip mrvl_bootimage mrvl_flash mrvl_uart
+
+To build just TF-A without WTMI image (useful for A3720 Turris MOX board), run following command:
+
+.. code:: shell
+
+ > make USE_COHERENT_MEM=0 PLAT=a3700 CM3_SYSTEM_RESET=1 BL33=/path/to/u-boot.bin \
+ CROSS_COMPILE=aarch64-linux-gnu- mrvl_bootimage
+
+Here is full example how to build production release of Marvell firmware image (concatenated
+binary of Marvell's A3720 sys-init, CZ.NIC's Armada 3720 Secure Firmware, TF-A and U-Boot) for
+EspressoBin board (PLAT=a3700) with 1GHz CPU (CLOCKSPRESET=CPU_1000_DDR_800) and
+1GB DDR4 RAM (DDR_TOPOLOGY=5):
+
+.. code:: shell
+
+ > git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
+ > git clone https://source.denx.de/u-boot/u-boot.git
+ > git clone https://github.com/weidai11/cryptopp.git
+ > git clone https://github.com/MarvellEmbeddedProcessors/mv-ddr-marvell.git
+ > git clone https://github.com/MarvellEmbeddedProcessors/A3700-utils-marvell.git
+ > git clone https://gitlab.nic.cz/turris/mox-boot-builder.git
+ > make -C u-boot CROSS_COMPILE=aarch64-linux-gnu- mvebu_espressobin-88f3720_defconfig u-boot.bin
+ > make -C mox-boot-builder CROSS_CM3=arm-linux-gnueabi- wtmi_app.bin
+ > make -C trusted-firmware-a CROSS_COMPILE=aarch64-linux-gnu- CROSS_CM3=arm-linux-gnueabi- \
+ USE_COHERENT_MEM=0 PLAT=a3700 CLOCKSPRESET=CPU_1000_DDR_800 DDR_TOPOLOGY=5 \
+ MV_DDR_PATH=$PWD/mv-ddr-marvell/ WTP=$PWD/A3700-utils-marvell/ \
+ CRYPTOPP_PATH=$PWD/cryptopp/ BL33=$PWD/u-boot/u-boot.bin \
+ WTMI_IMG=$PWD/mox-boot-builder/wtmi_app.bin FIP_ALIGN=0x100 mrvl_flash
+
+Produced Marvell firmware flash image: ``trusted-firmware-a/build/a3700/release/flash-image.bin``
+
+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
+ A7K/A8K/CN913x because of hardware limitation (boot from secondary image
+ can interrupt UART recovery process). This MACRO definition is set in
+ ``plat/marvell/armada/a8k/common/include/platform_def.h`` file.
+
+- DDR32
+ In order to work in 32bit DDR, instead of the default 64bit ECC DDR,
+ this flag should be set to 1.
+
+For more information about build options, please refer to the
+:ref:`Build Options` document.
+
+
+Build output
+------------
+Marvell's TF-A compilation generates 8 files:
+
+ - ble.bin - BLe image (not available for Armada37x0)
+ - 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 - Flashable Marvell firmware image. For Armada37x0 it
+ contains TIM, WTMI and boot-image.bin images. For other platforms it contains
+ BLe and boot-image.bin images. Should be placed on the boot flash/device.
+ - uart-images.tgz.bin - GZIPed TAR archive which contains Armada37x0 images
+ for booting via UART. Could be loaded via Marvell's WtpDownload tool from
+ A3700-utils-marvell repository.
+
+Additional make target ``mrvl_bootimage`` produce ``boot-image.bin`` file. Target
+``mrvl_flash`` produce final ``flash-image.bin`` file and target ``mrvl_uart``
+produce ``uart-images.tgz.bin`` file.
+
+
+Tools and external components installation
+------------------------------------------
+
+Armada37x0 Builds require installation of additional 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 "master" branch):
+
+ https://github.com/MarvellEmbeddedProcessors/mv-ddr-marvell.git
+
+(3) Armada3700 tools available at the following repository
+ (use the "master" branch):
+
+ https://github.com/MarvellEmbeddedProcessors/A3700-utils-marvell.git
+
+(4) Crypto++ library available at the following repository:
+
+ https://github.com/weidai11/cryptopp.git
+
+(5) Optional CZ.NIC's Armada 3720 Secure Firmware:
+
+ https://gitlab.nic.cz/turris/mox-boot-builder.git
+
+Armada70x0, Armada80x0 and CN913x Builds require installation of additional components
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+(1) DDR initialization library sources (mv_ddr) available at the following repository
+ (use the "master" branch):
+
+ https://github.com/MarvellEmbeddedProcessors/mv-ddr-marvell.git
+
+(2) MSS Management SubSystem Firmware available at the following repository
+ (use the "binaries-marvell-armada-SDK10.0.1.0" branch):
+
+ https://github.com/MarvellEmbeddedProcessors/binaries-marvell.git
diff --git a/docs/plat/marvell/armada/misc/mvebu-a8k-addr-map.rst b/docs/plat/marvell/armada/misc/mvebu-a8k-addr-map.rst
new file mode 100644
index 0000000..e88a458
--- /dev/null
+++ b/docs/plat/marvell/armada/misc/mvebu-a8k-addr-map.rst
@@ -0,0 +1,49 @@
+Address 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 | | | | | +-------------------+ |
+ | +------------------+ +------------+ +------------+ |
+ | |
+ +--------------------------------------------------------------------------------------------------+
diff --git a/docs/plat/marvell/armada/misc/mvebu-amb.rst b/docs/plat/marvell/armada/misc/mvebu-amb.rst
new file mode 100644
index 0000000..d734003
--- /dev/null
+++ b/docs/plat/marvell/armada/misc/mvebu-amb.rst
@@ -0,0 +1,58 @@
+AMB - 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},
+ };
diff --git a/docs/plat/marvell/armada/misc/mvebu-ccu.rst b/docs/plat/marvell/armada/misc/mvebu-ccu.rst
new file mode 100644
index 0000000..12118e9
--- /dev/null
+++ b/docs/plat/marvell/armada/misc/mvebu-ccu.rst
@@ -0,0 +1,33 @@
+Marvell CCU address decoding bindings
+=====================================
+
+CCU configuration 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 */
+ };
diff --git a/docs/plat/marvell/armada/misc/mvebu-io-win.rst b/docs/plat/marvell/armada/misc/mvebu-io-win.rst
new file mode 100644
index 0000000..7498291
--- /dev/null
+++ b/docs/plat/marvell/armada/misc/mvebu-io-win.rst
@@ -0,0 +1,46 @@
+Marvell IO WIN address decoding bindings
+========================================
+
+IO Window configuration 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*/
+ };
diff --git a/docs/plat/marvell/armada/misc/mvebu-iob.rst b/docs/plat/marvell/armada/misc/mvebu-iob.rst
new file mode 100644
index 0000000..aa41822
--- /dev/null
+++ b/docs/plat/marvell/armada/misc/mvebu-iob.rst
@@ -0,0 +1,52 @@
+Marvell IOB address decoding bindings
+=====================================
+
+IO bridge configuration 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 */
+ };
diff --git a/docs/plat/marvell/armada/porting.rst b/docs/plat/marvell/armada/porting.rst
new file mode 100644
index 0000000..ba8736d
--- /dev/null
+++ b/docs/plat/marvell/armada/porting.rst
@@ -0,0 +1,158 @@
+TF-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/armada/<soc family>/<soc>_cust``
+ (e.g. 'plat/marvell/armada/a8k/a7040_cust').
+- The platform name for build purposes is called ``<soc>_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/armada/<soc family>/<soc>_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/plat/marvell/armada/misc/mvebu-[ccu/iob/amb/io-win].rst`` 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/armada/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/armada/a8k/<platform>/board`` directory.
+
+Please refer to '<path_to_mv_ddr_sources>/doc/porting_guide.txt' for detailed
+porting description.
+
+The build target directory is "build/<platform>/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.
+
+ 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/armada/<soc
+ family>/<platform>/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/armada/a8k/a80x0/board/phy-porting-layer.h`` "plat/marvell/armada/<soc family>/<platform>/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/armada/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".
diff --git a/docs/plat/marvell/armada/uart-booting.rst b/docs/plat/marvell/armada/uart-booting.rst
new file mode 100644
index 0000000..04ce464
--- /dev/null
+++ b/docs/plat/marvell/armada/uart-booting.rst
@@ -0,0 +1,103 @@
+TF-A UART Booting Instructions for Marvell Platforms
+====================================================
+
+This section describes how to temporary boot the Trusted Firmware-A (TF-A) project over UART
+without flashing it to non-volatile storage for Marvell's platforms.
+
+See :ref:`TF-A Build Instructions for Marvell Platforms` how to build ``mrvl_uart`` and
+``mrvl_flash`` targets used in this section.
+
+Armada37x0 UART image downloading
+---------------------------------
+
+There are two options how to download UART image into any Armada37x0 board.
+
+Marvell Wtpdownloader
+~~~~~~~~~~~~~~~~~~~~~
+
+Marvell Wtpdownloader works only with UART images stored in separate files and supports only upload
+speed with 115200 bauds. Target ``mrvl_uart`` produces GZIPed TAR archive ``uart-images.tgz.bin``
+with either three files ``TIM_ATF.bin``, ``wtmi_h.bin`` and ``boot-image_h.bin`` for non-secure
+boot or with four files ``TIM_ATF_TRUSTED.bin``, ``TIMN_ATF_TRUSTED.bin``, ``wtmi_h.bin`` and
+``boot-image_h.bin`` when secure boot is enabled.
+
+Compilation:
+
+.. code:: shell
+
+ > git clone https://github.com/MarvellEmbeddedProcessors/A3700-utils-marvell.git
+ > make -C A3700-utils-marvell/wtptp/src/Wtpdownloader_Linux -f makefile.mk
+
+It produces executable binary ``A3700-utils-marvell/wtptp/src/Wtpdownloader_Linux/WtpDownload_linux``
+
+To download images from ``uart-images.tgz.bin`` archive unpack it and for non-secure boot variant run:
+
+.. code:: shell
+
+ > stty -F /dev/ttyUSB<port#> clocal
+ > WtpDownload_linux -P UART -C <port#> -E -B TIM_ATF.bin -I wtmi_h.bin -I boot-image_h.bin
+
+After that immediately start terminal on ``/dev/ttyUSB<port#>`` to see boot output.
+
+CZ.NIC mox-imager
+~~~~~~~~~~~~~~~~~
+
+CZ.NIC mox-imager supports all Armada37x0 boards (not only Turris MOX as name suggests). It works
+with either with separate files from ``uart-images.tgz.bin`` archive (like Marvell Wtpdownloader)
+produced by ``mrvl_uart`` target or also with ``flash-image.bin`` file produced by ``mrvl_flash``
+target, which is the exactly same file as used for flashing. So when using CZ.NIC mox-imager there
+is no need to build separate files for UART flashing like in case with Marvell Wtpdownloader.
+
+CZ.NIC mox-imager moreover supports higher upload speeds up to the 6000000 bauds (which seems to
+be limit of Armada37x0 SoC) which is much higher and faster than Marvell Wtpdownloader.
+
+Compilation:
+
+.. code:: shell
+
+ > git clone https://gitlab.nic.cz/turris/mox-imager.git
+ > make -C mox-imager
+
+It produces executable binary ``mox-imager/mox-imager``
+
+To download single file image built by ``mrvl_flash`` target at the highest speed, run:
+
+.. code:: shell
+
+ > mox-imager -D /dev/ttyUSB<port#> -E -b 6000000 -t flash-image.bin
+
+To download images from ``uart-images.tgz.bin`` archive built by ``mrvl_uart`` target for
+non-secure boot variant (like Wtpdownloader) but at the highest speed, first unpack
+``uart-images.tgz.bin`` archive and then run:
+
+.. code:: shell
+
+ > mox-imager -D /dev/ttyUSB<port#> -E -b 6000000 -t TIM_ATF.bin wtmi_h.bin boot-image_h.bin
+
+CZ.NIC mox-imager after successful download will start its own mini terminal (option ``-t``) to
+not loose any boot output. It also prints boot output which is sent either by image files or by
+bootrom during transferring of image files. This mini terminal can be quit by CTRL-\\ + C keypress.
+
+
+A7K/A8K/CN913x UART image downloading
+-------------------------------------
+
+A7K/A8K/CN913x uses same image ``flash-image.bin`` for both flashing and booting over UART.
+For downloading image over UART it is possible to use mvebu64boot tool.
+
+Compilation:
+
+.. code:: shell
+
+ > git clone https://github.com/pali/mvebu64boot.git
+ > make -C mvebu64boot
+
+It produces executable binary ``mvebu64boot/mvebu64boot``
+
+To download ``flash-image.bin`` image run:
+
+.. code:: shell
+
+ > mvebu64boot -t -b flash-image.bin /dev/ttyUSB0
+
+After successful download it will start own mini terminal (option ``-t``) like CZ.NIC mox-imager.
diff --git a/docs/plat/marvell/index.rst b/docs/plat/marvell/index.rst
new file mode 100644
index 0000000..2d5cdeb
--- /dev/null
+++ b/docs/plat/marvell/index.rst
@@ -0,0 +1,15 @@
+Marvell
+=======
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents
+
+ armada/build
+ armada/uart-booting
+ armada/porting
+ armada/misc/mvebu-a8k-addr-map
+ armada/misc/mvebu-amb
+ armada/misc/mvebu-ccu
+ armada/misc/mvebu-io-win
+ armada/misc/mvebu-iob
diff --git a/docs/plat/meson-axg.rst b/docs/plat/meson-axg.rst
new file mode 100644
index 0000000..6f6732e
--- /dev/null
+++ b/docs/plat/meson-axg.rst
@@ -0,0 +1,27 @@
+Amlogic Meson A113D (AXG)
+===========================
+
+The Amlogic Meson A113D is a SoC with a quad core Arm Cortex-A53 running at
+~1.2GHz. 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-none-elf- make DEBUG=1 PLAT=axg [SPD=opteed]
+ [AML_USE_ATOS=1 when using ATOS as BL32]
+
+This port has been tested on a A113D board. After building it, follow the
+instructions in the `U-Boot repository`_, replacing the mentioned **bl31.img**
+by the one built from this port.
+
+.. _U-Boot repository: https://github.com/u-boot/u-boot/blob/master/doc/board/amlogic/s400.rst
diff --git a/docs/plat/meson-g12a.rst b/docs/plat/meson-g12a.rst
new file mode 100644
index 0000000..9588ec4
--- /dev/null
+++ b/docs/plat/meson-g12a.rst
@@ -0,0 +1,27 @@
+Amlogic 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/doc/board/amlogic/sei510.rst
diff --git a/docs/plat/meson-gxbb.rst b/docs/plat/meson-gxbb.rst
new file mode 100644
index 0000000..dbd83e0
--- /dev/null
+++ b/docs/plat/meson-gxbb.rst
@@ -0,0 +1,26 @@
+Amlogic 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://gitlab.denx.de/u-boot/u-boot/-/blob/master/board/amlogic/p200/README.odroid-c2
diff --git a/docs/plat/meson-gxl.rst b/docs/plat/meson-gxl.rst
new file mode 100644
index 0000000..0751f1d
--- /dev/null
+++ b/docs/plat/meson-gxl.rst
@@ -0,0 +1,27 @@
+Amlogic 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/doc/board/amlogic/p212.rst
diff --git a/docs/plat/mt8183.rst b/docs/plat/mt8183.rst
new file mode 100644
index 0000000..c639be1
--- /dev/null
+++ b/docs/plat/mt8183.rst
@@ -0,0 +1,20 @@
+MediaTek 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
diff --git a/docs/plat/mt8186.rst b/docs/plat/mt8186.rst
new file mode 100644
index 0000000..16b833a
--- /dev/null
+++ b/docs/plat/mt8186.rst
@@ -0,0 +1,21 @@
+MediaTek 8186
+=============
+
+MediaTek 8186 (MT8186) is a 64-bit ARM SoC introduced by MediaTek in 2021.
+The chip incorporates eight cores - six Cortex-A55 little cores and two Cortex-A76.
+Cortex-A76 can operate at up to 2.05 GHz.
+Cortex-A55 can operate at up to 2.0 GHz.
+
+Boot Sequence
+-------------
+
+::
+
+ Boot Rom --> Coreboot --> TF-A BL31 --> Depthcharge --> Linux Kernel
+
+How to Build
+------------
+
+.. code:: shell
+
+ make CROSS_COMPILE=aarch64-linux-gnu- PLAT=mt8186 DEBUG=1 COREBOOT=1
diff --git a/docs/plat/mt8188.rst b/docs/plat/mt8188.rst
new file mode 100644
index 0000000..93abaa5
--- /dev/null
+++ b/docs/plat/mt8188.rst
@@ -0,0 +1,21 @@
+MediaTek 8188
+=============
+
+MediaTek 8188 (MT8188) is a 64-bit ARM SoC introduced by MediaTek in 2022.
+The chip incorporates eight cores - six Cortex-A55 little cores and two Cortex-A78.
+Cortex-A78 can operate at up to 2.6 GHz.
+Cortex-A55 can operate at up to 2.0 GHz.
+
+Boot Sequence
+-------------
+
+::
+
+ Boot Rom --> Coreboot --> TF-A BL31 --> Depthcharge --> Linux Kernel
+
+ How to Build
+ ------------
+
+ .. code:: shell
+
+ make CROSS_COMPILE=aarch64-linux-gnu- LD=aarch64-linux-gnu-gcc PLAT=mt8188 DEBUG=1 COREBOOT=1
diff --git a/docs/plat/mt8192.rst b/docs/plat/mt8192.rst
new file mode 100644
index 0000000..369afcf
--- /dev/null
+++ b/docs/plat/mt8192.rst
@@ -0,0 +1,21 @@
+MediaTek 8192
+=============
+
+MediaTek 8192 (MT8192) is a 64-bit ARM SoC introduced by MediaTek in 2020.
+The chip incorporates eight cores - four Cortex-A55 little cores and Cortex-A76.
+Cortex-A76 can operate at up to 2.2 GHz.
+Cortex-A55 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=mt8192 DEBUG=1 COREBOOT=1
diff --git a/docs/plat/mt8195.rst b/docs/plat/mt8195.rst
new file mode 100644
index 0000000..b2aeea2
--- /dev/null
+++ b/docs/plat/mt8195.rst
@@ -0,0 +1,21 @@
+MediaTek 8195
+=============
+
+MediaTek 8195 (MT8195) is a 64-bit ARM SoC introduced by MediaTek in 2021.
+The chip incorporates eight cores - four Cortex-A55 little cores and Cortex-A76.
+Cortex-A76 can operate at up to 2.2 GHz.
+Cortex-A55 can operate at up to 2.0 GHz.
+
+Boot Sequence
+-------------
+
+::
+
+ Boot Rom --> Coreboot --> TF-A BL31 --> Depthcharge --> Linux Kernel
+
+How to Build
+------------
+
+.. code:: shell
+
+ make CROSS_COMPILE=aarch64-linux-gnu- PLAT=mt8195 DEBUG=1 COREBOOT=1
diff --git a/docs/plat/nvidia-tegra.rst b/docs/plat/nvidia-tegra.rst
new file mode 100644
index 0000000..391c7c8
--- /dev/null
+++ b/docs/plat/nvidia-tegra.rst
@@ -0,0 +1,148 @@
+NVIDIA Tegra
+============
+
+- .. rubric:: T194
+ :name: t194
+
+T194 has eight NVIDIA Carmel CPU cores in a coherent multi-processor
+configuration. The Carmel cores support the ARM Architecture version 8.2,
+executing both 64-bit AArch64 code, and 32-bit AArch32 code. The Carmel
+processors are organized as four dual-core clusters, where each cluster has
+a dedicated 2 MiB Level-2 unified cache. A high speed coherency fabric connects
+these processor complexes and allows heterogeneous multi-processing with all
+eight cores if required.
+
+- .. 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 Denver2 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.
+
+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.
+
+- .. 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.
+
+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.
+
+- Tegra210: TLK and Trusty
+- Tegra186: Trusty
+- Tegra194: 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=<path-to-aarch64-gcc>/bin/aarch64-none-elf- make PLAT=tegra \
+ TARGET_SOC=<target-soc e.g. t194|t186|t210> SPD=<dispatcher e.g. trusty|tlkd>
+ bl31
+
+Platforms wanting to use different TZDRAM\_BASE, can add ``TZDRAM_BASE=<value>``
+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.
diff --git a/docs/plat/nxp/index.rst b/docs/plat/nxp/index.rst
new file mode 100644
index 0000000..8546887
--- /dev/null
+++ b/docs/plat/nxp/index.rst
@@ -0,0 +1,17 @@
+NXP Reference Development Platforms
+===================================
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents
+
+ nxp-layerscape
+ nxp-ls-fuse-prov
+ nxp-ls-tbbr
+
+This chapter holds documentation related to NXP reference development platforms.
+It includes details on image flashing, fuse provisioning and trusted board boot-up.
+
+--------------
+
+*Copyright (c) 2021, NXP Limited. All rights reserved.*
diff --git a/docs/plat/nxp/nxp-layerscape.rst b/docs/plat/nxp/nxp-layerscape.rst
new file mode 100644
index 0000000..cd5874b
--- /dev/null
+++ b/docs/plat/nxp/nxp-layerscape.rst
@@ -0,0 +1,473 @@
+NXP SoCs - Overview
+=====================
+.. section-numbering::
+ :suffix: .
+
+The QorIQ family of ARM based SoCs that are supported on TF-A are:
+
+1. LX2160A
+
+- SoC Overview:
+
+The LX2160A multicore processor, the highest-performance member of the
+Layerscape family, combines FinFET process technology's low power and
+sixteen Arm® Cortex®-A72 cores with datapath acceleration optimized for
+L2/3 packet processing, together with security offload, robust traffic
+management and quality of service.
+
+Details about LX2160A can be found at `lx2160a`_.
+
+- LX2160ARDB Board:
+
+The LX2160A reference design board provides a comprehensive platform
+that enables design and evaluation of the LX2160A or LX2162A processors. It
+comes preloaded with a board support package (BSP) based on a standard Linux
+kernel.
+
+Board details can be fetched from the link: `lx2160ardb`_.
+
+2. LS1028A
+
+- SoC Overview:
+
+The Layerscape LS1028A applications processor for industrial and
+automotive includes a time-sensitive networking (TSN) -enabled Ethernet
+switch and Ethernet controllers to support converged IT and OT networks.
+Two powerful 64-bit Arm®v8 cores support real-time processing for
+industrial control and virtual machines for edge computing in the IoT.
+The integrated GPU and LCD controller enable Human-Machine Interface
+(HMI) systems with next-generation interfaces.
+
+Details about LS1028A can be found at `ls1028a`_.
+
+- LS1028ARDB Board:
+
+The LS1028A reference design board (RDB) is a computing, evaluation,
+and development platform that supports industrial IoT applications, human
+machine interface solutions, and industrial networking.
+
+Details about LS1028A RDB board can be found at `ls1028ardb`_.
+
+3. LS1043A
+
+- SoC Overview:
+
+The Layerscape 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.
+
+Details about LS1043A can be found at `ls1043a`_.
+
+- LS1043ARDB Board:
+
+The LS1043A reference design board (RDB) is a computing, evaluation, and
+development platform that supports the Layerscape LS1043A architecture
+processor. The LS1043A-RDB can help shorten your time to market by providing
+the following features:
+
+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
+
+Details about LS1043A RDB board can be found at `ls1043ardb`_.
+
+4. LS1046A
+
+- SoC Overview:
+
+The LS1046A is a cost-effective, power-efficient, and highly integrated
+system-on-chip (SoC) design that extends the reach of the NXP value-performance
+line of QorIQ communications processors. Featuring power-efficient 64-bit
+Arm Cortex-A72 cores with ECC-protected L1 and L2 cache memories for high
+reliability, running up to 1.8 GHz.
+
+Details about LS1046A can be found at `ls1046a`_.
+
+- LS1046ARDB Board:
+
+The LS1046A reference design board (RDB) is a high-performance computing,
+evaluation, and development platform that supports the Layerscape LS1046A
+architecture processor. The LS1046ARDB board supports the Layerscape LS1046A
+processor and is optimized to support the DDR4 memory and a full complement
+of high-speed SerDes ports.
+
+Details about LS1046A RDB board can be found at `ls1046ardb`_.
+
+- LS1046AFRWY Board:
+
+The LS1046A Freeway board (FRWY) is a high-performance computing, evaluation,
+and development platform that supports the LS1046A architecture processor
+capable of support more than 32,000 CoreMark performance. The FRWY-LS1046A
+board supports the LS1046A processor, onboard DDR4 memory, multiple Gigabit
+Ethernet, USB3.0 and M2_Type_E interfaces for Wi-Fi, FRWY-LS1046A-AC includes
+the Wi-Fi card.
+
+Details about LS1046A FRWY board can be found at `ls1046afrwy`_.
+
+5. LS1088A
+
+- SoC Overview:
+
+The LS1088A family of multicore communications processors combines up to and eight
+Arm Cortex-A53 cores with the advanced, high-performance data path and network
+peripheral interfaces required for wireless access points, networking infrastructure,
+intelligent edge access, including virtual customer premise equipment (vCPE) and
+high-performance industrial applications.
+
+Details about LS1088A can be found at `ls1088a`_.
+
+- LS1088ARDB Board:
+
+The LS1088A reference design board provides a comprehensive platform that
+enables design and evaluation of the product (LS1088A processor). This RDB
+comes pre-loaded with a board support package (BSP) based on a standard
+Linux kernel.
+
+Details about LS1088A RDB board can be found at `ls1088ardb`_.
+
+Table of supported boot-modes by each platform & platform that needs FIP-DDR:
+-----------------------------------------------------------------------------
+
++---------------------+---------------------------------------------------------------------+-----------------+
+| | BOOT_MODE | |
+| PLAT +-------+--------+-------+-------+-------+-------------+--------------+ fip_ddr_needed |
+| | sd | qspi | nor | nand | emmc | flexspi_nor | flexspi_nand | |
++=====================+=======+========+=======+=======+=======+=============+==============+=================+
+| lx2160ardb | yes | | | | yes | yes | | yes |
++---------------------+-------+--------+-------+-------+-------+-------------+--------------+-----------------+
+| ls1028ardb | yes | | | | yes | yes | | no |
++---------------------+-------+--------+-------+-------+-------+-------------+--------------+-----------------+
+| ls1043ardb | yes | | yes | yes | | | | no |
++---------------------+-------+--------+-------+-------+-------+-------------+--------------+-----------------+
+| ls1046ardb | yes | yes | | | yes | | | no |
++---------------------+-------+--------+-------+-------+-------+-------------+--------------+-----------------+
+| ls1046afrwy | yes | yes | | | | | | no |
++---------------------+-------+--------+-------+-------+-------+-------------+--------------+-----------------+
+| ls1088ardb | yes | yes | | | | | | no |
++---------------------+-------+--------+-------+-------+-------+-------------+--------------+-----------------+
+
+
+Boot Sequence
+-------------
+::
+
++ Secure World | Normal World
++ EL0 |
++ |
++ EL1 BL32(Tee OS) | kernel
++ ^ | | ^
++ | | | |
++ EL2 | | | BL33(u-boot)
++ | | | ^
++ | v | /
++ EL3 BootROM --> BL2 --> BL31 ---------------/
++
+
+Boot Sequence with FIP-DDR
+--------------------------
+::
+
++ Secure World | Normal World
++ EL0 |
++ |
++ EL1 fip-ddr BL32(Tee OS) | kernel
++ ^ | ^ | | ^
++ | | | | | |
++ EL2 | | | | | BL33(u-boot)
++ | | | | | ^
++ | v | v | /
++ EL3 BootROM --> BL2 -----> BL31 ---------------/
++
+
+DDR Memory Layout
+--------------------------
+
+NXP Platforms divide DRAM into banks:
+
+- DRAM0 Bank: Maximum size of this bank is fixed to 2GB, DRAM0 size is defined in platform_def.h if it is less than 2GB.
+
+- DRAM1 ~ DRAMn Bank: Greater than 2GB belongs to DRAM1 and following banks, and size of DRAMn Bank varies for one platform to others.
+
+The following diagram is default DRAM0 memory layout in which secure memory is at top of DRAM0.
+
+::
+
+ high +---------------------------------------------+
+ | |
+ | Secure EL1 Payload Shared Memory (2 MB) |
+ | |
+ +---------------------------------------------+
+ | |
+ | Secure Memory (64 MB) |
+ | |
+ +---------------------------------------------+
+ | |
+ | Non Secure Memory |
+ | |
+ low +---------------------------------------------+
+
+How to build
+=============
+
+Code Locations
+--------------
+
+- OP-TEE:
+ `link <https://source.codeaurora.org/external/qoriq/qoriq-components/optee_os>`__
+
+- U-Boot:
+ `link <https://source.codeaurora.org/external/qoriq/qoriq-components/u-boot>`__
+
+- RCW:
+ `link <https://source.codeaurora.org/external/qoriq/qoriq-components/rcw>`__
+
+- ddr-phy-binary: Required by platforms that need fip-ddr.
+ `link <https:://github.com/NXP/ddr-phy-binary>`__
+
+- cst: Required for TBBR.
+ `link <https:://source.codeaurora.org/external/qoriq/qoriq-components/cst>`__
+
+Build Procedure
+---------------
+
+- Fetch all the above repositories into local host.
+
+- Prepare AARCH64 toolchain and set the environment variable "CROSS_COMPILE".
+
+ .. code:: shell
+
+ export CROSS_COMPILE=.../bin/aarch64-linux-gnu-
+
+- Build RCW. Refer README from the respective cloned folder for more details.
+
+- Build u-boot and OPTee firstly, and get binary images: u-boot.bin and tee.bin.
+ For u-boot you can use the <platform>_tfa_defconfig for build.
+
+- Copy/clone the repo "ddr-phy-binary" to the tfa directory for platform needing ddr-fip.
+
+- Below are the steps to build TF-A images for the supported platforms.
+
+Compilation steps without BL32
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+BUILD BL2:
+
+-To compile
+ .. code:: shell
+
+ make PLAT=$PLAT \
+ BOOT_MODE=<platform_supported_boot_mode> \
+ RCW=$RCW_BIN \
+ pbl
+
+BUILD FIP:
+
+ .. code:: shell
+
+ make PLAT=$PLAT \
+ BOOT_MODE=<platform_supported_boot_mode> \
+ RCW=$RCW_BIN \
+ BL33=$UBOOT_SECURE_BIN \
+ pbl \
+ fip
+
+Compilation steps with BL32
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+BUILD BL2:
+
+-To compile
+ .. code:: shell
+
+ make PLAT=$PLAT \
+ BOOT_MODE=<platform_supported_boot_mode> \
+ RCW=$RCW_BIN \
+ BL32=$TEE_BIN SPD=opteed\
+ pbl
+
+BUILD FIP:
+
+ .. code:: shell
+
+ make PLAT=$PLAT \
+ BOOT_MODE=<platform_supported_boot_mode> \
+ RCW=$RCW_BIN \
+ BL32=$TEE_BIN SPD=opteed\
+ BL33=$UBOOT_SECURE_BIN \
+ pbl \
+ fip
+
+
+BUILD fip-ddr (Mandatory for certain platforms, refer table above):
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+-To compile additional fip-ddr for selected platforms(Refer above table if the platform needs fip-ddr).
+ .. code:: shell
+
+ make PLAT=<platform_name> fip-ddr
+
+
+Deploy ATF Images
+=================
+
+Note: The size in the standard uboot commands for copy to nor, qspi, nand or sd
+should be modified based on the binary size of the image to be copied.
+
+- Deploy ATF images on flexspi-Nor or QSPI flash Alt Bank from U-Boot prompt.
+
+ -- Commands to flash images for bl2_xxx.pbl and fip.bin
+
+ Notes: ls1028ardb has no flexspi-Nor Alt Bank, so use "sf probe 0:0" for current bank.
+
+ .. code:: shell
+
+ tftp 82000000 $path/bl2_xxx.pbl;
+
+ i2c mw 66 50 20;sf probe 0:1; sf erase 0 +$filesize; sf write 0x82000000 0x0 $filesize;
+
+ tftp 82000000 $path/fip.bin;
+ i2c mw 66 50 20;sf probe 0:1; sf erase 0x100000 +$filesize; sf write 0x82000000 0x100000 $filesize;
+
+ -- Next step is valid for platform where FIP-DDR is needed.
+
+ .. code:: shell
+
+ tftp 82000000 $path/ddr_fip.bin;
+ i2c mw 66 50 20;sf probe 0:1; sf erase 0x800000 +$filesize; sf write 0x82000000 0x800000 $filesize;
+
+ -- Then reset to alternate bank to boot up ATF.
+
+ Command for lx2160a, ls1088a and ls1028a platforms:
+
+ .. code:: shell
+
+ qixisreset altbank;
+
+ Command for ls1046a platforms:
+
+ .. code:: shell
+
+ cpld reset altbank;
+
+- Deploy ATF images on SD/eMMC from U-Boot prompt.
+ -- file_size_in_block_sizeof_512 = (Size_of_bytes_tftp / 512)
+
+ .. code:: shell
+
+ mmc dev <idx>; (idx = 1 for eMMC; idx = 0 for SD)
+
+ tftp 82000000 $path/bl2_<sd>_or_<emmc>.pbl;
+ mmc write 82000000 8 <file_size_in_block_sizeof_512>;
+
+ tftp 82000000 $path/fip.bin;
+ mmc write 82000000 0x800 <file_size_in_block_sizeof_512>;
+
+ -- Next step is valid for platform that needs FIP-DDR.
+
+ .. code:: shell
+
+ tftp 82000000 $path/ddr_fip.bin;
+ mmc write 82000000 0x4000 <file_size_in_block_sizeof_512>;
+
+ -- Then reset to sd/emmc to boot up ATF from sd/emmc as boot-source.
+
+ Command for lx2160A, ls1088a and ls1028a platforms:
+
+ .. code:: shell
+
+ qixisreset <sd or emmc>;
+
+ Command for ls1043a and ls1046a platform:
+
+ .. code:: shell
+
+ cpld reset <sd or emmc>;
+
+- Deploy ATF images on IFC nor flash from U-Boot prompt.
+
+ .. code:: shell
+
+ tftp 82000000 $path/bl2_nor.pbl;
+ protect off 64000000 +$filesize; erase 64000000 +$filesize; cp.b 82000000 64000000 $filesize;
+
+ tftp 82000000 $path/fip.bin;
+ protect off 64100000 +$filesize; erase 64100000 +$filesize; cp.b 82000000 64100000 $filesize;
+
+ -- Then reset to alternate bank to boot up ATF.
+
+ Command for ls1043a platform:
+
+ .. code:: shell
+
+ cpld reset altbank;
+
+- Deploy ATF images on IFC nand flash from U-Boot prompt.
+
+ .. code:: shell
+
+ tftp 82000000 $path/bl2_nand.pbl;
+ nand erase 0x0 $filesize; nand write 82000000 0x0 $filesize;
+
+ tftp 82000000 $path/fip.bin;
+ nand erase 0x100000 $filesize;nand write 82000000 0x100000 $filesize;
+
+ -- Then reset to nand flash to boot up ATF.
+
+ Command for ls1043a platform:
+
+ .. code:: shell
+
+ cpld reset nand;
+
+
+
+Trusted Board Boot:
+===================
+
+For TBBR, the binary name changes:
+
++-------------+--------------------------+---------+-------------------+
+| Boot Type | BL2 | FIP | FIP-DDR |
++=============+==========================+=========+===================+
+| Normal Boot | bl2_<boot_mode>.pbl | fip.bin | ddr_fip.bin |
++-------------+--------------------------+---------+-------------------+
+| TBBR Boot | bl2_<boot_mode>_sec.pbl | fip.bin | ddr_fip_sec.bin |
++-------------+--------------------------+---------+-------------------+
+
+Refer `nxp-ls-tbbr.rst`_ for detailed user steps.
+
+
+.. _lx2160a: https://www.nxp.com/products/processors-and-microcontrollers/arm-processors/layerscape-processors/layerscape-lx2160a-lx2120a-lx2080a-processors:LX2160A
+.. _lx2160ardb: https://www.nxp.com/products/processors-and-microcontrollers/arm-processors/layerscape-communication-process/layerscape-lx2160a-multicore-communications-processor:LX2160A
+.. _ls1028a: https://www.nxp.com/products/processors-and-microcontrollers/arm-processors/layerscape-processors/layerscape-1028a-applications-processor:LS1028A
+.. _ls1028ardb: https://www.nxp.com/design/qoriq-developer-resources/layerscape-ls1028a-reference-design-board:LS1028ARDB
+.. _ls1043a: https://www.nxp.com/products/processors-and-microcontrollers/arm-processors/layerscape-processors/layerscape-1043a-and-1023a-processors:LS1043A
+.. _ls1043ardb: https://www.nxp.com/design/qoriq-developer-resources/layerscape-ls1043a-reference-design-board:LS1043A-RDB
+.. _ls1046a: https://www.nxp.com/products/processors-and-microcontrollers/arm-processors/layerscape-processors/layerscape-1046a-and-1026a-processors:LS1046A
+.. _ls1046ardb: https://www.nxp.com/design/qoriq-developer-resources/layerscape-ls1046a-reference-design-board:LS1046A-RDB
+.. _ls1046afrwy: https://www.nxp.com/design/qoriq-developer-resources/ls1046a-freeway-board:FRWY-LS1046A
+.. _ls1088a: https://www.nxp.com/products/processors-and-microcontrollers/arm-processors/layerscape-processors/layerscape-1088a-and-1048a-processor:LS1088A
+.. _ls1088ardb: https://www.nxp.com/design/qoriq-developer-resources/layerscape-ls1088a-reference-design-board:LS1088A-RDB
+.. _nxp-ls-tbbr.rst: ./nxp-ls-tbbr.rst
diff --git a/docs/plat/nxp/nxp-ls-fuse-prov.rst b/docs/plat/nxp/nxp-ls-fuse-prov.rst
new file mode 100644
index 0000000..64e1c6f
--- /dev/null
+++ b/docs/plat/nxp/nxp-ls-fuse-prov.rst
@@ -0,0 +1,271 @@
+
+Steps to blow fuses on NXP LS SoC:
+==================================
+
+
+- Enable POVDD
+ -- Refer board GSG(Getting Started Guide) for the steps to enable POVDD.
+ -- Once the POVDD is enabled, make sure to set variable POVDD_ENABLE := yes, in the platform.mk.
+
++---+-----------------+-----------+------------+-----------------+-----------------------------+
+| | Platform | Jumper | Switch | LED to Verify | Through GPIO Pin (=number) |
++===+=================+===========+============+=================+=============================+
+| 1.| lx2160ardb | J9 | | | no |
++---+-----------------+-----------+------------+-----------------+-----------------------------+
+| 2.| lx2160aqds | J35 | | | no |
++---+-----------------+-----------+------------+-----------------+-----------------------------+
+| 3.| lx2162aqds | J35 | SW9[4] = 1 | D15 | no |
++---+-----------------+-----------+------------+-----------------+-----------------------------+
+
+- SFP registers to be written to:
+
++---+----------------------------------+----------------------+----------------------+
+| | Platform | OTPMKR0..OTPMKR7 | SRKHR0..SRKHR7 |
++===+==================================+======================+======================+
+| 1.| lx2160ardb/lx2160aqds/lx2162aqds | 0x1e80234..0x1e80250 | 0x1e80254..0x1e80270 |
++---+----------------------------------+----------------------+----------------------+
+
+- At U-Boot prompt, verify that SNVS register - HPSR, whether OTPMK was written, already:
+
++---+----------------------------------+-------------------------------------------+---------------+
+| | Platform | OTPMK_ZERO_BIT(=value) | SNVS_HPSR_REG |
++===+==================================+===========================================+===============+
+| 1.| lx2160ardb/lx2160aqds/lx2162aqds | 27 (= 1 means not blown, =0 means blown) | 0x01E90014 |
++---+----------------------------------+-------------------------------------------+---------------+
+
+From u-boot prompt:
+
+ -- Check for the OTPMK.
+ .. code:: shell
+
+ md $SNVS_HPSR_REG
+
+ Command Output:
+ 01e90014: 88000900
+
+ In case it is read as 00000000, then read this register using jtag (in development mode only through CW tap).
+ +0 +4 +8 +C
+ [0x01E90014] 88000900
+
+ Note: OTPMK_ZERO_BIT is 1, indicating that the OTPMK is not blown.
+
+ -- Check for the SRK Hash.
+ .. code:: shell
+
+ md $SRKHR0 0x10
+
+ Command Output:
+ 01e80254: 00000000 00000000 00000000 00000000 ................
+ 01e80264: 00000000 00000000 00000000 00000000 ................
+
+ Note: Zero means that SRK hash is not blown.
+
+- If not blown, then from the U-Boot prompt, using following commands:
+ -- Provision the OTPMK.
+
+ .. code:: shell
+
+ mw.l $OTPMKR0 <OTMPKR_0_32Bit_val>
+ mw.l $OTPMKR1 <OTMPKR_1_32Bit_val>
+ mw.l $OTPMKR2 <OTMPKR_2_32Bit_val>
+ mw.l $OTPMKR3 <OTMPKR_3_32Bit_val>
+ mw.l $OTPMKR4 <OTMPKR_4_32Bit_val>
+ mw.l $OTPMKR5 <OTMPKR_5_32Bit_val>
+ mw.l $OTPMKR6 <OTMPKR_6_32Bit_val>
+ mw.l $OTPMKR7 <OTMPKR_7_32Bit_val>
+
+ -- Provision the SRK Hash.
+
+ .. code:: shell
+
+ mw.l $SRKHR0 <SRKHR_0_32Bit_val>
+ mw.l $SRKHR1 <SRKHR_1_32Bit_val>
+ mw.l $SRKHR2 <SRKHR_2_32Bit_val>
+ mw.l $SRKHR3 <SRKHR_3_32Bit_val>
+ mw.l $SRKHR4 <SRKHR_4_32Bit_val>
+ mw.l $SRKHR5 <SRKHR_5_32Bit_val>
+ mw.l $SRKHR6 <SRKHR_6_32Bit_val>
+ mw.l $SRKHR7 <SRKHR_7_32Bit_val>
+
+ Note: SRK Hash should be carefully written keeping in mind the SFP Block Endianness.
+
+- At U-Boot prompt, verify that SNVS registers for OTPMK are correctly written:
+
+ -- Check for the OTPMK.
+ .. code:: shell
+
+ md $SNVS_HPSR_REG
+
+ Command Output:
+ 01e90014: 80000900
+
+ OTPMK_ZERO_BIT is zero, indicating that the OTPMK is blown.
+
+ Note: In case it is read as 00000000, then read this register using jtag (in development mode only through CW tap).
+
+ .. code:: shell
+
+ md $OTPMKR0 0x10
+
+ Command Output:
+ 01e80234: ffffffff ffffffff ffffffff ffffffff ................
+ 01e80244: ffffffff ffffffff ffffffff ffffffff ................
+
+ Note: OTPMK will never be visible in plain.
+
+ -- Check for the SRK Hash. For example, if following SRK hash is written:
+
+ SFP SRKHR0 = fdc2fed4
+ SFP SRKHR1 = 317f569e
+ SFP SRKHR2 = 1828425c
+ SFP SRKHR3 = e87b5cfd
+ SFP SRKHR4 = 34beab8f
+ SFP SRKHR5 = df792a70
+ SFP SRKHR6 = 2dff85e1
+ SFP SRKHR7 = 32a29687,
+
+ then following would be the value on dumping SRK hash.
+
+ .. code:: shell
+
+ md $SRKHR0 0x10
+
+ Command Output:
+ 01e80254: d4fec2fd 9e567f31 5c422818 fd5c7be8 ....1.V..(B\.{\.
+ 01e80264: 8fabbe34 702a79df e185ff2d 8796a232 4....y*p-...2...
+
+ Note: SRK Hash is visible in plain based on the SFP Block Endianness.
+
+- Caution: Donot proceed to the next step, until you are sure that OTPMK and SRKH are correctly blown from above steps.
+ -- After the next step, there is no turning back.
+ -- Fuses will be burnt, which cannot be undo.
+
+- Write SFP_INGR[INST] with the PROGFB(0x2) instruction to blow the fuses.
+ -- User need to save the SRK key pair and OTPMK Key forever, to continue using this board.
+
++---+----------------------------------+-------------------------------------------+-----------+
+| | Platform | SFP_INGR_REG | SFP_WRITE_DATE_FRM_MIRROR_REG_TO_FUSE |
++===+==================================+=======================================================+
+| 1.| lx2160ardb/lx2160aqds/lx2162aqds | 0x01E80020 | 0x2 |
++---+----------------------------------+--------------+----------------------------------------+
+
+ .. code:: shell
+
+ md $SFP_INGR_REG $SFP_WRITE_DATE_FRM_MIRROR_REG_TO_FUSE
+
+- On reset, if the SFP register were read from u-boot, it will show the following:
+ -- Check for the OTPMK.
+
+ .. code:: shell
+
+ md $SNVS_HPSR_REG
+
+ Command Output:
+ 01e90014: 80000900
+
+ In case it is read as 00000000, then read this register using jtag (in development mode only through CW tap).
+ +0 +4 +8 +C
+ [0x01E90014] 80000900
+
+ Note: OTPMK_ZERO_BIT is zero, indicating that the OTPMK is blown.
+
+ .. code:: shell
+
+ md $OTPMKR0 0x10
+
+ Command Output:
+ 01e80234: ffffffff ffffffff ffffffff ffffffff ................
+ 01e80244: ffffffff ffffffff ffffffff ffffffff ................
+
+ Note: OTPMK will never be visible in plain.
+
+ -- SRK Hash
+
+ .. code:: shell
+
+ md $SRKHR0 0x10
+
+ Command Output:
+ 01e80254: d4fec2fd 9e567f31 5c422818 fd5c7be8 ....1.V..(B\.{\.
+ 01e80264: 8fabbe34 702a79df e185ff2d 8796a232 4....y*p-...2...
+
+ Note: SRK Hash is visible in plain based on the SFP Block Endianness.
+
+Second method to do the fuse provsioning:
+=========================================
+
+This method is used for quick way to provision fuses.
+Typically used by those who needs to provision number of boards.
+
+- Enable POVDD:
+ -- Refer the table above to enable POVDD.
+
+ Note: If GPIO Pin supports enabling POVDD, it can be done through the below input_fuse_file.
+
+ -- Once the POVDD is enabled, make sure to set variable POVDD_ENABLE := yes, in the platform.mk.
+
+- User need to populate the "input_fuse_file", corresponding to the platform for:
+
+ -- OTPMK
+ -- SRKH
+
+ Table of fuse provisioning input file for every supported platform:
+
++---+----------------------------------+-----------------------------------------------------------------+
+| | Platform | FUSE_PROV_FILE |
++===+==================================+=================================================================+
+| 1.| lx2160ardb/lx2160aqds/lx2162aqds | ${CST_DIR}/input_files/gen_fusescr/ls2088_1088/input_fuse_file |
++---+----------------------------------+--------------+--------------------------------------------------+
+
+- Create the TF-A binary with FUSE_PROG=1.
+
+ .. code:: shell
+
+ make PLAT=$PLAT FUSE_PROG=1\
+ BOOT_MODE=<platform_supported_boot_mode> \
+ RCW=$RCW_BIN \
+ BL32=$TEE_BIN SPD=opteed\
+ BL33=$UBOOT_SECURE_BIN \
+ pbl \
+ fip \
+ fip_fuse \
+ FUSE_PROV_FILE=../../apps/security/cst/input_files/gen_fusescr/ls2088_1088/input_fuse_file
+
+- Deployment:
+ -- Refer the nxp-layerscape.rst for deploying TF-A images.
+ -- Deploying fip_fuse.bin:
+
+ For Flexspi-Nor:
+
+ .. code:: shell
+
+ tftp 82000000 $path/fuse_fip.bin;
+ i2c mw 66 50 20;sf probe 0:0; sf erase 0x880000 +$filesize; sf write 0x82000000 0x880000 $filesize;
+
+ For SD or eMMC [file_size_in_block_sizeof_512 = (Size_of_bytes_tftp / 512)]:
+
+ .. code:: shell
+
+ tftp 82000000 $path/fuse_fip.bin;
+ mmc write 82000000 0x4408 <file_size_in_block_sizeof_512>;
+
+- Valiation:
+
++---+----------------------------------+---------------------------------------------------+
+| | Platform | Error_Register | Error_Register_Address |
++===+==================================+===================================================+
+| 1.| lx2160ardb/lx2160aqds/lx2162aqds | DCFG scratch 4 register | 0x01EE020C |
++---+----------------------------------+---------------------------------------------------+
+
+ At the U-Boot prompt, check DCFG scratch 4 register for any error.
+
+ .. code:: shell
+
+ md $Error_Register_Address 1
+
+ Command Ouput:
+ 01ee020c: 00000000
+
+ Note:
+ - 0x00000000 shows no error, then fuse provisioning is successful.
+ - For non-zero value, refer the code header file ".../drivers/nxp/sfp/sfp_error_codes.h"
diff --git a/docs/plat/nxp/nxp-ls-tbbr.rst b/docs/plat/nxp/nxp-ls-tbbr.rst
new file mode 100644
index 0000000..43e15f7
--- /dev/null
+++ b/docs/plat/nxp/nxp-ls-tbbr.rst
@@ -0,0 +1,210 @@
+
+--------------
+NXP Platforms:
+--------------
+TRUSTED_BOARD_BOOT option can be enabled by specifying TRUSTED_BOARD_BOOT=1 on command line during make.
+
+
+
+Bare-Minimum Preparation to run TBBR on NXP Platforms:
+=======================================================
+- OTPMK(One Time Programable Key) needs to be burnt in fuses.
+ -- It is the 256 bit key that stores a secret value used by the NXP SEC 4.0 IP in Trusted or Secure mode.
+
+ Note: It is primarily for the purpose of decrypting additional secrets stored in system non-volatile memory.
+
+ -- NXP CST tool gives an option to generate it.
+
+ Use the below command from directory 'cst', with correct options.
+
+ .. code:: shell
+
+ ./gen_otpmk_drbg
+
+- SRKH (Super Root Key Hash) needs to be burnt in fuses.
+ -- It is the 256 bit hash of the list of the public keys of the SRK key pair.
+ -- NXP CST tool gives an option to generate the RSA key pair and its hash.
+
+ Use the below command from directory 'cst', with correct options.
+
+ .. code:: shell
+
+ ./gen_keys
+
+Refer fuse frovisioning readme 'nxp-ls-fuse-prov.rst' for steps to blow these keys.
+
+
+
+Two options are provided for TRUSTED_BOARD_BOOT:
+================================================
+
+-------------------------------------------------------------------------
+Option 1: CoT using X 509 certificates
+-------------------------------------------------------------------------
+
+- This CoT is as provided by ARM.
+
+- To use this option user needs to specify mbedtld dir path in MBEDTLS_DIR.
+
+- To generate CSF header, path of CST repository needs to be specified as CST_DIR
+
+- CSF header is embedded to each of the BL2 image.
+
+- GENERATE_COT=1 adds the tool 'cert_create' to the build environment to generate:
+ -- X509 Certificates as (.crt) files.
+ -- X509 Pem key file as (.pem) files.
+
+- SAVE_KEYS=1 saves the keys and certificates, if GENERATE_COT=1.
+ -- For this to work, file name for cert and keys are provided as part of compilation or build command.
+
+ --- default file names will be used, incase not provided as part compilation or build command.
+ --- default folder 'BUILD_PLAT' will be used to store them.
+
+- ROTPK for x.509 certificates is generated and embedded in bl2.bin and
+ verified as part of CoT by Boot ROM during secure boot.
+
+- Compilation steps:
+
+All Images
+ .. code:: shell
+
+ make PLAT=$PLAT TRUSTED_BOARD_BOOT=1 GENERATE_COT=1 MBEDTLS_DIR=$MBEDTLS_PATH CST_DIR=$CST_DIR_PATH \
+ BOOT_MODE=<platform_supported_boot_mode> \
+ RCW=$RCW_BIN \
+ BL32=$TEE_BIN SPD=opteed\
+ BL33=$UBOOT_SECURE_BIN \
+ pbl \
+ fip
+
+Additional FIP_DDR Image (For NXP platforms like lx2160a)
+ .. code:: shell
+
+ make PLAT=$PLAT TRUSTED_BOARD_BOOT=1 GENERATE_COT=1 MBEDTLS_DIR=$MBEDTLS_PATH fip_ddr
+
+ Note: make target 'fip_ddr' should never be combine with other make target 'fip', 'pbl' & 'bl2'.
+
+-------------------------------------------------------------------------
+Option 2: CoT using NXP CSF headers.
+-------------------------------------------------------------------------
+
+- This option is automatically selected when TRUSTED_BOARD_BOOT is set but MBEDTLS_DIR path is not specified.
+
+- CSF header is embedded to each of the BL31, BL32 and BL33 image.
+
+- To generate CSF header, path of CST repository needs to be specified as CST_DIR
+
+- Default input files for CSF header generation is added in this repo.
+
+- Default input file requires user to generate RSA key pair named
+ -- srk.pri, and
+ -- srk.pub, and add them in ATF repo.
+ -- These keys can be generated using gen_keys tool of CST.
+
+- To change the input file , user can use the options BL33_INPUT_FILE, BL32_INPUT_FILE, BL31_INPUT_FILE
+
+- There are 2 paths in secure boot flow :
+ -- Development Mode (sb_en in RCW = 1, SFP->OSPR, ITS = 0)
+
+ --- In this flow , even on ROTPK comparison failure, flow would continue.
+ --- However SNVS is transitioned to non-secure state
+
+ -- Production mode (SFP->OSPR, ITS = 1)
+
+ --- Any failure is fatal failure
+
+- Compilation steps:
+
+All Images
+ .. code:: shell
+
+ make PLAT=$PLAT TRUSTED_BOARD_BOOT=1 CST_DIR=$CST_DIR_PATH \
+ BOOT_MODE=<platform_supported_boot_mode> \
+ RCW=$RCW_BIN \
+ BL32=$TEE_BIN SPD=opteed\
+ BL33=$UBOOT_SECURE_BIN \
+ pbl \
+ fip
+
+Additional FIP_DDR Image (For NXP platforms like lx2160a)
+ .. code:: shell
+
+ make PLAT=$PLAT TRUSTED_BOARD_BOOT=1 CST_DIR=$CST_DIR_PATH fip_ddr
+
+- Compilation Steps with build option for generic image processing filters to prepend CSF header:
+ -- Generic image processing filters to prepend CSF header
+
+ BL32_INPUT_FILE = < file name>
+ BL33_INPUT_FILE = <file name>
+
+ .. code:: shell
+
+ make PLAT=$PLAT TRUSTED_BOARD_BOOT=1 CST_DIR=$CST_DIR_PATH \
+ BOOT_MODE=<platform_supported_boot_mode> \
+ RCW=$RCW_BIN \
+ BL32=$TEE_BIN SPD=opteed\
+ BL33=$UBOOT_SECURE_BIN \
+ BL33_INPUT_FILE = <ip file> \
+ BL32_INPUT_FILE = <ip_file> \
+ BL31_INPUT_FILE = <ip file> \
+ pbl \
+ fip
+
+
+Deploy ATF Images
+=================
+Same steps as mentioned in the readme "nxp-layerscape.rst".
+
+
+
+Verification to check if Secure state is achieved:
+==================================================
+
++---+----------------+-----------------+------------------------+----------------------------------+-------------------------------+
+| | Platform | SNVS_HPSR_REG | SYS_SECURE_BIT(=value) | SYSTEM_SECURE_CONFIG_BIT(=value) | SSM_STATE |
++===+================+=================+========================+==================================+===============================+
+| 1.| lx2160ardb or | 0x01E90014 | 15 | 14-12 | 11-8 |
+| | lx2160aqds or | | ( = 1, BootROM Booted) | ( = 010 means Intent to Secure, | (=1111 means secure boot) |
+| | lx2162aqds | | | ( = 000 Unsecure) | (=1011 means Non-secure Boot) |
++---+----------------+-----------------+------------------------+----------------------------------+-------------------------------+
+
+- Production mode (SFP->OSPR, ITS = 1)
+ -- Linux prompt will successfully come. if the TBBR is successful.
+
+ --- Else, Linux boot will be successful.
+
+ -- For secure-boot status, read SNVS Register $SNVS_HPSR_REG from u-boot prompt:
+
+ .. code:: shell
+
+ md $SNVS_HPSR_REG
+
+ Command Output:
+ 1e90014: 8000AF00
+
+ In case it is read as 00000000, then read this register using jtag (in development mode only through CW tap).
+ +0 +4 +8 +C
+ [0x01E90014] 8000AF00
+
+
+- Development Mode (sb_en in RCW = 1, SFP->OSPR, ITS = 0)
+ -- Refer the SoC specific table to read the register to interpret whether the secure boot is achieved or not.
+ -- Using JTAG (in development environment only, using CW tap):
+
+ --- For secure-boot status, read SNVS Register $SNVS_HPSR_REG
+
+ .. code:: shell
+
+ ccs::display_regs 86 0x01E90014 4 0 1
+
+ Command Output:
+ Using the SAP chain position number 86, following is the output.
+
+ +0 +4 +8 +C
+ [0x01E90014] 8000AF00
+
+ Note: Chain position number will vary from one SoC to other SoC.
+
+- Interpretation of the value:
+
+ -- 0xA indicates BootROM booted, with intent to secure.
+ -- 0xF = secure boot, as SSM_STATE.
diff --git a/docs/plat/poplar.rst b/docs/plat/poplar.rst
new file mode 100644
index 0000000..215f551
--- /dev/null
+++ b/docs/plat/poplar.rst
@@ -0,0 +1,176 @@
+Poplar
+======
+
+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 <https://github.com/ARM-software/arm-trusted-firmware>`__
+
+- l-loader:
+ `link <https://github.com/Linaro/poplar-l-loader.git>`__
+
+- u-boot:
+ `link <http://git.denx.de/u-boot.git>`__
+
+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...
+ =>
diff --git a/docs/plat/qemu-sbsa.rst b/docs/plat/qemu-sbsa.rst
new file mode 100644
index 0000000..bc82ae5
--- /dev/null
+++ b/docs/plat/qemu-sbsa.rst
@@ -0,0 +1,56 @@
+QEMU 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
+
+To build TF-A:
+
+::
+
+ git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git tfa
+ cd tfa
+ export CROSS_COMPILE=aarch64-none-elf-
+ make PLAT=qemu_sbsa all fip
+
+To build TF-A with BL32 and SPM enabled(StandaloneMM as a Secure Payload):
+
+::
+
+ git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git tfa
+ cd tfa
+ export CROSS_COMPILE=aarch64-none-elf-
+ make PLAT=qemu_sbsa BL32=../STANDALONE_MM.fd SPM_MM=1 EL3_EXCEPTION_HANDLING=1 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
+
diff --git a/docs/plat/qemu.rst b/docs/plat/qemu.rst
new file mode 100644
index 0000000..6986326
--- /dev/null
+++ b/docs/plat/qemu.rst
@@ -0,0 +1,172 @@
+QEMU 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.
+
+If ``ARM_LINUX_KERNEL_AS_BL33`` is set to 1 then this FDT will be passed to BL33
+via register x0, as expected by a Linux kernel. This allows a Linux kernel image
+to be booted directly as BL33 rather than using a bootloader.
+
+An ARM64 defconfig v5.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
+
+Getting non-TF images
+---------------------
+
+``QEMU_EFI.fd`` can be downloaded from
+http://snapshots.linaro.org/components/kernel/leg-virt-tianocore-edk2-upstream/latest/QEMU-KERNEL-AARCH64/RELEASE_GCC5/QEMU_EFI.fd
+
+or, can be built as follows:
+
+.. code:: shell
+
+ git clone https://github.com/tianocore/edk2.git
+ cd edk2
+ git submodule update --init
+ make -C BaseTools
+ source edksetup.sh
+ export GCC5_AARCH64_PREFIX=aarch64-linux-gnu-
+ build -a AARCH64 -t GCC5 -p ArmVirtPkg/ArmVirtQemuKernel.dsc
+
+````
+
+Then, you will get ``Build/ArmVirtQemuKernel-AARCH64/DEBUG_GCC5/FV/QEMU_EFI.fd``
+
+Please note you do not need to use GCC 5 in spite of the environment variable
+``GCC5_AARCH64_PREFIX``
+
+The rootfs can be built by using Buildroot as follows:
+
+.. code:: shell
+
+ git clone git://git.buildroot.net/buildroot.git
+ cd buildroot
+ make qemu_aarch64_virt_defconfig
+ utils/config -e BR2_TARGET_ROOTFS_CPIO
+ utils/config -e BR2_TARGET_ROOTFS_CPIO_GZIP
+ make olddefconfig
+ make
+
+Then, you will get ``output/images/rootfs.cpio.gz``.
+
+Booting via semi-hosting option
+-------------------------------
+
+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/arch/arm64/boot/Image
+
+To build:
+
+.. code:: shell
+
+ make CROSS_COMPILE=aarch64-none-elf- PLAT=qemu
+
+To start (QEMU v5.0.0):
+
+.. code:: shell
+
+ qemu-system-aarch64 -nographic -machine virt,secure=on -cpu cortex-a57 \
+ -kernel Image \
+ -append "console=ttyAMA0,38400 keep_bootcon" \
+ -initrd rootfs.cpio.gz -smp 2 -m 1024 -bios bl1.bin \
+ -d unimp -semihosting-config enable,target=native
+
+Booting via flash based firmwares
+---------------------------------
+
+Boot firmwares are loaded via secure FLASH0 device so ``bl1.bin`` and
+``fip.bin`` should be concatenated to create a ``flash.bin`` that is flashed
+onto secure FLASH0.
+
+- ``bl32.bin`` -> BL32 (``tee-header_v2.bin``)
+- ``bl32_extra1.bin`` -> BL32 Extra1 (``tee-pager_v2.bin``)
+- ``bl32_extra2.bin`` -> BL32 Extra2 (``tee-pageable_v2.bin``)
+- ``bl33.bin`` -> BL33 (``QEMU_EFI.fd``)
+- ``Image`` -> linux/arch/arm64/boot/Image
+
+To build:
+
+.. code:: shell
+
+ make CROSS_COMPILE=aarch64-linux-gnu- PLAT=qemu BL32=bl32.bin \
+ BL32_EXTRA1=bl32_extra1.bin BL32_EXTRA2=bl32_extra2.bin \
+ BL33=bl33.bin BL32_RAM_LOCATION=tdram SPD=opteed all fip
+
+To build with TBBR enabled, BL31 and BL32 encrypted with test key:
+
+.. code:: shell
+
+ make CROSS_COMPILE=aarch64-linux-gnu- PLAT=qemu BL32=bl32.bin \
+ BL32_EXTRA1=bl32_extra1.bin BL32_EXTRA2=bl32_extra2.bin \
+ BL33=bl33.bin BL32_RAM_LOCATION=tdram SPD=opteed all fip \
+ MBEDTLS_DIR=<path-to-mbedtls-repo> TRUSTED_BOARD_BOOT=1 \
+ GENERATE_COT=1 DECRYPTION_SUPPORT=aes_gcm FW_ENC_STATUS=0 \
+ ENCRYPT_BL31=1 ENCRYPT_BL32=1
+
+To build flash.bin:
+
+.. code:: shell
+
+ dd if=build/qemu/release/bl1.bin of=flash.bin bs=4096 conv=notrunc
+ dd if=build/qemu/release/fip.bin of=flash.bin seek=64 bs=4096 conv=notrunc
+
+To start (QEMU v5.0.0):
+
+.. code:: shell
+
+ qemu-system-aarch64 -nographic -machine virt,secure=on -cpu cortex-a57 \
+ -kernel Image -no-acpi \
+ -append 'console=ttyAMA0,38400 keep_bootcon' \
+ -initrd rootfs.cpio.gz -smp 2 -m 1024 -bios flash.bin \
+ -d unimp
+
+Running QEMU in OpenCI
+-----------------------
+
+Linaro's continuous integration platform OpenCI supports running emulated tests
+on QEMU. The tests are kicked off on Jenkins and deployed through the Linaro
+Automation and Validation Architecture `LAVA`_.
+
+There are a set of Linux boot tests provided in OpenCI. They rely on prebuilt
+`binaries`_ for UEFI, the kernel, root file system, as well as, any other TF-A
+dependencies, and are run as part of the OpenCI TF-A `daily job`_. To run them
+manually, a `builder`_ job may be triggered with the test configuration
+``qemu-boot-tests``.
+
+
+You may see the following warning repeated several times in the boot logs:
+
+.. code:: shell
+
+ pflash_write: Write to buffer emulation is flawed
+
+Please ignore this as it is an unresolved `issue in QEMU`_, it is an internal
+QEMU warning that logs flawed use of "write to buffer".
+
+.. note::
+ For more information on how to trigger jobs in OpenCI, please refer to
+ Linaro's CI documentation, which explains how to trigger a `manual job`_.
+
+.. _binaries: https://downloads.trustedfirmware.org/tf-a/linux_boot/
+.. _daily job: https://ci.trustedfirmware.org/view/TF-A/job/tf-a-main/
+.. _builder: https://ci.trustedfirmware.org/view/TF-A/job/tf-a-builder/
+.. _LAVA: https://tf.validation.linaro.org/
+.. _manual job: https://tf-ci-users-guide.readthedocs.io/en/latest/#manual-job-trigger
+.. _issue in QEMU: https://git.qemu.org/?p=qemu.git;a=blob;f=hw/block/pflash_cfi01.c;h=0cbc2fb4cbf62c9a033b8dd89012374ff74ed610;hb=refs/heads/master#l500
diff --git a/docs/plat/qti-msm8916.rst b/docs/plat/qti-msm8916.rst
new file mode 100644
index 0000000..09a79b7
--- /dev/null
+++ b/docs/plat/qti-msm8916.rst
@@ -0,0 +1,116 @@
+Qualcomm Snapdragon 410 (MSM8916/APQ8016)
+=========================================
+
+The `Qualcomm Snapdragon 410`_ is Qualcomm's first 64-bit SoC, released in 2014
+with four ARM Cortex-A53 cores. There are differents variants (MSM8916,
+APQ8016(E), ...) that are all very similar. A popular device based on APQ8016E
+is the `DragonBoard 410c`_ single-board computer, but the SoC is also used in
+various mid-range smartphones/tablets.
+
+The TF-A/BL31 port for MSM8916 provides a minimal, community-maintained
+EL3 firmware. It is primarily based on information from the public
+`Snapdragon 410E Technical Reference Manual`_ combined with a lot of
+trial and error to actually make it work.
+
+.. note::
+ Unlike the :doc:`QTI SC7180/SC7280 <qti>` ports, this port does **not**
+ make use of a proprietary binary components (QTISECLIB). It is fully
+ open-source but therefore limited to publicly documented hardware
+ components.
+
+Functionality
+-------------
+
+The BL31 port is much more minimal compared to the original firmware and
+therefore expects the non-secure world (e.g. Linux) to manage more hardware,
+such as the SMMUs and all remote processors (RPM, WCNSS, Venus, Modem).
+Everything except modem is currently functional with a slightly modified version
+of mainline Linux.
+
+.. warning::
+ This port is **not secure**. There is no special secure memory and the
+ used DRAM is available from both the non-secure and secure worlds.
+ Unfortunately, the hardware used for memory protection is not described
+ in the APQ8016E documentation.
+
+The port is primarily intended as a minimal PSCI implementation (without a
+separate secure world) where this limitation is not a big problem. Booting
+secondary CPU cores (PSCI ``CPU_ON``) is supported. Basic CPU core power
+management (``CPU_SUSPEND``) is functional but still work-in-progress and
+will be added later once ready.
+
+Boot Flow
+---------
+BL31 replaces the original ``tz`` firmware in the boot flow::
+
+ Boot ROM (PBL) -> SBL -> BL31 (EL3) -> U-Boot (EL2) -> Linux (EL2)
+
+By default, BL31 enters the non-secure world in EL2 AArch64 state at address
+``0x8f600000``. The original hypervisor firmware (``hyp``) is not used, you can
+use KVM or another hypervisor. The entry address is fixed in the BL31 binary
+but can be changed using the ``PRELOADED_BL33_BASE`` make file parameter.
+
+Using an AArch64 bootloader (such as `U-Boot for DragonBoard 410c`_) is
+recommended. AArch32 bootloaders (such as the original Little Kernel bootloader
+from Qualcomm) are not directly supported, although it is possible to use an EL2
+shim loader to temporarily switch to AArch32 state.
+
+Installation
+------------
+First, setup the cross compiler for AArch64 and build TF-A for ``msm8916``::
+
+ $ make CROSS_COMPILE=aarch64-linux-gnu- PLAT=msm8916
+
+The BL31 ELF image is generated in ``build/msm8916/release/bl31/bl31.elf``.
+This image must be "signed" before flashing it, even if the board has secure
+boot disabled. In this case the signature does not provide any security,
+but it provides the firmware with required metadata.
+
+The `DragonBoard 410c`_ does not have secure boot enabled by default. In this
+case you can simply sign the ELF image using a randomly generated key. You can
+use e.g. `qtestsign`_::
+
+ $ ./qtestsign.py tz build/msm8916/release/bl31/bl31.elf
+
+Then install the resulting ``build/msm8916/release/bl31/bl31-test-signed.mbn``
+to the ``tz`` partition on the device. BL31 should be running after a reboot.
+
+.. warning::
+ Do not flash incorrectly signed firmware on devices that have secure
+ boot enabled! Make sure that you have a way to recover the board in case
+ of problems (e.g. using EDL).
+
+Boot Trace
+----------
+BL31 prints some lines on the debug console UART2, which will usually look like
+this (with ``DEBUG=1``, otherwise only the ``NOTICE`` lines are shown)::
+
+ ...
+ S - DDR Frequency, 400 MHz
+ NOTICE: BL31: v2.6(debug):v2.6
+ NOTICE: BL31: Built : 20:00:00, Dec 01 2021
+ INFO: BL31: Platform setup start
+ INFO: ARM GICv2 driver initialized
+ INFO: BL31: Platform setup done
+ INFO: BL31: Initializing runtime services
+ INFO: BL31: cortex_a53: CPU workaround for 819472 was applied
+ INFO: BL31: cortex_a53: CPU workaround for 824069 was applied
+ INFO: BL31: cortex_a53: CPU workaround for 826319 was applied
+ INFO: BL31: cortex_a53: CPU workaround for 827319 was applied
+ INFO: BL31: cortex_a53: CPU workaround for 835769 was applied
+ INFO: BL31: cortex_a53: CPU workaround for disable_non_temporal_hint was applied
+ INFO: BL31: cortex_a53: CPU workaround for 843419 was applied
+ INFO: BL31: cortex_a53: CPU workaround for 1530924 was applied
+ INFO: BL31: Preparing for EL3 exit to normal world
+ INFO: Entry point address = 0x8f600000
+ INFO: SPSR = 0x3c9
+
+ U-Boot 2021.10 (Dec 01 2021 - 20:00:00 +0000)
+ Qualcomm-DragonBoard 410C
+ ...
+
+.. _Qualcomm Snapdragon 410: https://www.qualcomm.com/products/snapdragon-processors-410
+.. _DragonBoard 410c: https://www.96boards.org/product/dragonboard410c/
+.. _Snapdragon 410E Technical Reference Manual: https://developer.qualcomm.com/download/sd410/snapdragon-410e-technical-reference-manual.pdf
+.. _U-Boot for DragonBoard 410c: https://u-boot.readthedocs.io/en/latest/board/qualcomm/dragonboard410c.html
+.. _qtestsign: https://github.com/msm8916-mainline/qtestsign
diff --git a/docs/plat/qti.rst b/docs/plat/qti.rst
new file mode 100644
index 0000000..1d483e7
--- /dev/null
+++ b/docs/plat/qti.rst
@@ -0,0 +1,43 @@
+Qualcomm Technologies, Inc.
+===========================
+
+Trusted Firmware-A (TF-A) implements the EL3 firmware layer for QTI SC7180,
+SC7280.
+
+Boot Trace
+-------------
+
+Bootrom --> BL1/BL2 --> BL31 --> BL33 --> Linux kernel
+
+BL1/2 and BL33 can currently be supplied from Coreboot + Depthcharge
+
+How to build
+------------
+
+Code Locations
+~~~~~~~~~~~~~~
+
+- Trusted Firmware-A:
+ `link <https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git>`__
+
+Build Procedure
+~~~~~~~~~~~~~~~
+
+QTI SoC expects TF-A's BL31 to get integrated with other boot software
+Coreboot, so only bl31.elf need to get build from the TF-A repository.
+
+The build command looks like
+
+ make CROSS_COMPILE=aarch64-linux-gnu- PLAT=sc7180 COREBOOT=1
+
+update value of CROSS_COMPILE argument with your cross-compilation toolchain.
+
+Additional QTISECLIB_PATH=<path to qtiseclib> can be added in build command.
+if QTISECLIB_PATH is not added in build command stub implementation of qtiseclib
+is picked. qtiseclib with stub implementation doesn't boot device. This was
+added to satisfy compilation.
+
+QTISELIB for SC7180 is available at
+`link <https://github.com/coreboot/qc_blobs/blob/master/sc7180/qtiseclib/libqtisec.a?raw=true>`__
+QTISELIB for SC7280 is available at
+`link <https://github.com/coreboot/qc_blobs/blob/master/sc7280/qtiseclib/libqtisec.a?raw=true>`__
diff --git a/docs/plat/rcar-gen3.rst b/docs/plat/rcar-gen3.rst
new file mode 100644
index 0000000..7107bea
--- /dev/null
+++ b/docs/plat/rcar-gen3.rst
@@ -0,0 +1,268 @@
+Renesas 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 <https://elinux.org/R-Car>`__
+
+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 <simon.butcher@arm.com>
+ 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 <jramirez@baylibre.com>
+ Date: Thu Aug 30 16:49:49 2018 +0200
+ plat-rcar: cpu-suspend: handle the power level
+ Signed-off-by: Jorge Ramirez-Ortiz <jramirez@baylibre.com>
+
+* u-boot:
+ The port has beent tested using mainline uboot.
+
+ commit 4cdeda511f8037015b568396e6dcc3d8fb41e8c0
+ Author: Fabio Estevam <festevam@gmail.com>
+ Date: Tue Sep 4 10:23:12 2018 -0300
+
+* linux:
+ The port has beent tested using mainline kernel.
+
+ commit 7876320f88802b22d4e2daf7eb027dd14175a0f8
+ Author: Linus Torvalds <torvalds@linux-foundation.org>
+ 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
+ =>
diff --git a/docs/plat/rockchip.rst b/docs/plat/rockchip.rst
new file mode 100644
index 0000000..b7c43fb
--- /dev/null
+++ b/docs/plat/rockchip.rst
@@ -0,0 +1,55 @@
+Rockchip 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.
diff --git a/docs/plat/rpi3.rst b/docs/plat/rpi3.rst
new file mode 100644
index 0000000..38c3dfa
--- /dev/null
+++ b/docs/plat/rpi3.rst
@@ -0,0 +1,466 @@
+Raspberry 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 <https://github.com/OP-TEE/optee_os>`__.
+ 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 <https://github.com/ARMmbed/mbedtls>`__.
+ ``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/
diff --git a/docs/plat/rpi4.rst b/docs/plat/rpi4.rst
new file mode 100644
index 0000000..6e83fd7
--- /dev/null
+++ b/docs/plat/rpi4.rst
@@ -0,0 +1,84 @@
+Raspberry 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, 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 components 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.
diff --git a/docs/plat/rz-g2.rst b/docs/plat/rz-g2.rst
new file mode 100644
index 0000000..e7ae620
--- /dev/null
+++ b/docs/plat/rz-g2.rst
@@ -0,0 +1,228 @@
+Renesas RZ/G
+============
+
+The "RZ/G" Family of high-end 64-bit Arm®-based microprocessors (MPUs)
+enables the solutions required for the smart society of the future.
+Through a variety of Arm Cortex®-A53 and A57-based devices, engineers can
+easily implement high-resolution human machine interfaces (HMI), embedded
+vision, embedded artificial intelligence (e-AI) and real-time control and
+industrial ethernet connectivity.
+
+The scalable RZ/G 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 RZ/G2 reference platforms:
+----------------------------------
+
++--------------+----------------------------------------------------------------------------------+
+| Board | Details |
++==============+===============+==================================================================+
+| hihope-rzg2h | "96 boards" compatible board from Hoperun equipped with Renesas RZ/G2H SoC |
+| +----------------------------------------------------------------------------------+
+| | http://hihope.org/product/musashi |
++--------------+----------------------------------------------------------------------------------+
+| hihope-rzg2m | "96 boards" compatible board from Hoperun equipped with Renesas RZ/G2M SoC |
+| +----------------------------------------------------------------------------------+
+| | http://hihope.org/product/musashi |
++--------------+----------------------------------------------------------------------------------+
+| hihope-rzg2n | "96 boards" compatible board from Hoperun equipped with Renesas RZ/G2N SoC |
+| +----------------------------------------------------------------------------------+
+| | http://hihope.org/product/musashi |
++--------------+----------------------------------------------------------------------------------+
+| ek874 | "96 boards" compatible board from Silicon Linux equipped with Renesas RZ/G2E SoC |
+| +----------------------------------------------------------------------------------+
+| | https://www.si-linux.co.jp/index.php?CAT%2FCAT874 |
++--------------+----------------------------------------------------------------------------------+
+
+`boards info <https://www.renesas.com/us/en/products/rzg-linux-platform/rzg-marcketplace/board-solutions.html#rzg2>`__
+
+The current TF-A port has been tested on the HiHope RZ/G2M
+SoC_id r8a774a1 revision ES1.3.
+
+
+::
+
+ ARM CA57 (ARMv8) 1.5 GHz dual core, with NEON/VFPv4, L1$ I/D 48K/32K, L2$ 1MB
+ 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(32-bit bus mode)
+ Two- and three-dimensional graphics engines,
+ Video processing units,
+ Display Output,
+ Video Input,
+ SD card host interface,
+ USB3.0 and USB2.0 interfaces,
+ CAN interfaces,
+ Ethernet AVB,
+ Wi-Fi + BT,
+ PCI Express Interfaces,
+ Memories
+ INTERNAL 384KB SYSTEM RAM
+ DDR 4 GB LPDDR4
+ QSPI FLASH 64MB
+ EMMC 32 GB EMMC (HS400 240 MBYTES/S)
+ MICROSD-CARD SLOT (SDR104 100 MBYTES/S)
+
+Overview
+--------
+On RZ/G2 SoCs 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 before determining the boot reason (cold or warm).
+
+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).
+
+[1] https://github.com/renesas-rz/meta-rzg2/tree/BSP-1.0.5/recipes-bsp/arm-trusted-firmware/files
+
+
+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 HiHope RZ/G2M development kit used in this port.
+
+Build Tested:
+~~~~~~~~~~~~~
+
+.. code:: bash
+
+ make bl2 bl31 rzg LOG_LEVEL=40 PLAT=rzg LSI=G2M RCAR_DRAM_SPLIT=2\
+ RCAR_LOSSY_ENABLE=1 SPD="none" MBEDTLS_DIR=$mbedtls
+
+System Tested:
+~~~~~~~~~~~~~~
+* mbed_tls:
+ git@github.com:ARMmbed/mbedtls.git [devel]
+
+| commit 72ca39737f974db44723760623d1b29980c00a88
+| Merge: ef94c4fcf dd9ec1c57
+| Author: Janos Follath <janos.follath@arm.com>
+| Date: Wed Oct 7 09:21:01 2020 +0100
+
+* u-boot:
+ The port has beent tested using mainline uboot with HiHope RZ/G2M board
+ specific patches.
+
+| commit 46ce9e777c1314ccb78906992b94001194eaa87b
+| Author: Heiko Schocher <hs@denx.de>
+| Date: Tue Nov 3 15:22:36 2020 +0100
+
+* linux:
+ The port has beent tested using mainline kernel.
+
+| commit f8394f232b1eab649ce2df5c5f15b0e528c92091
+| Author: Linus Torvalds <torvalds@linux-foundation.org>
+| Date: Sun Nov 8 16:10:16 2020 -0800
+| Linux 5.10-rc3
+
+TF-A Build Procedure
+~~~~~~~~~~~~~~~~~~~~
+
+- Fetch all the above 3 repositories.
+
+- Prepare the AARCH64 toolchain.
+
+- Build u-boot using hihope_rzg2_defconfig.
+
+ Result: u-boot-elf.srec
+
+.. code:: bash
+
+ make CROSS_COMPILE=aarch64-linux-gnu-
+ hihope_rzg2_defconfig
+
+ make CROSS_COMPILE=aarch64-linux-gnu-
+
+- Build TF-A
+
+ Result: bootparam_sa0.srec, cert_header_sa6.srec, bl2.srec, bl31.srec
+
+.. code:: bash
+
+ make bl2 bl31 rzg LOG_LEVEL=40 PLAT=rzg LSI=G2M RCAR_DRAM_SPLIT=2\
+ RCAR_LOSSY_ENABLE=1 SPD="none" MBEDTLS_DIR=$mbedtls
+
+
+Install Procedure
+~~~~~~~~~~~~~~~~~
+
+- Boot the board in Mini-monitor mode and enable access to the
+ QSPI flash.
+
+
+- Use the flash_writer utility[2] to flash all the SREC files.
+
+[2] https://github.com/renesas-rz/rzg2_flash_writer
+
+
+Boot trace
+----------
+::
+
+ INFO: ARM GICv2 driver initialized
+ NOTICE: BL2: RZ/G2 Initial Program Loader(CA57) Rev.2.0.6
+ NOTICE: BL2: PRR is RZ/G2M Ver.1.3
+ NOTICE: BL2: Board is HiHope RZ/G2M Rev.4.0
+ NOTICE: BL2: Boot device is QSPI Flash(40MHz)
+ NOTICE: BL2: LCM state is unknown
+ NOTICE: BL2: DDR3200(rev.0.40)
+ NOTICE: BL2: [COLD_BOOT]
+ NOTICE: BL2: DRAM Split is 2ch
+ NOTICE: BL2: QoS is default setting(rev.0.19)
+ NOTICE: BL2: DRAM refresh interval 1.95 usec
+ NOTICE: BL2: Periodic Write DQ Training
+ NOTICE: BL2: CH0: 400000000 - 47fffffff, 2 GiB
+ NOTICE: BL2: CH2: 600000000 - 67fffffff, 2 GiB
+ 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: FDT at 0xe631db30
+ NOTICE: BL2: v2.3(release):v2.4-rc0-2-g1433701e5
+ NOTICE: BL2: Built : 13:45:26, Nov 7 2020
+ NOTICE: BL2: Normal boot
+ INFO: BL2: Doing platform setup
+ INFO: BL2: Loading image id 3
+ NOTICE: BL2: dst=0xe631d200 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 5
+ INFO: Loading image id=5 at address 0x50000000
+ NOTICE: rcar_file_len: len: 0x00100000
+ NOTICE: BL2: dst=0x50000000 src=0x8300000 len=1048576(0x100000)
+ INFO: Image id=5 loaded: 0x50000000 - 0x50100000
+ NOTICE: BL2: Booting BL31
+ INFO: Entry point address = 0x44000000
+ INFO: SPSR = 0x3cd
+
+
+ U-Boot 2021.01-rc1-00244-gac37e14fbd (Nov 04 2020 - 20:03:34 +0000)
+
+ CPU: Renesas Electronics R8A774A1 rev 1.3
+ Model: HopeRun HiHope RZ/G2M with sub board
+ DRAM: 3.9 GiB
+ MMC: mmc@ee100000: 0, mmc@ee160000: 1
+ 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
+ =>
diff --git a/docs/plat/socionext-uniphier.rst b/docs/plat/socionext-uniphier.rst
new file mode 100644
index 0000000..9288193
--- /dev/null
+++ b/docs/plat/socionext-uniphier.rst
@@ -0,0 +1,116 @@
+Socionext 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) <Trusted Board Boot>` 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=<gcc-prefix> PLAT=uniphier BL33=<path-to-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:`Prerequisites` document 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=<path-to-mbedtls>
+
+- 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=<path-to-SCP>
+
+- BL32 (Secure Payload)
+
+ To enable BL32, add the following options to the build command::
+
+ SPD=<spd> BL32=<path-to-BL32>
+
+ If you use TSP for BL32, ``BL32=<path-to-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/
diff --git a/docs/plat/stm32mp1.rst b/docs/plat/stm32mp1.rst
new file mode 100644
index 0000000..23ea25a
--- /dev/null
+++ b/docs/plat/stm32mp1.rst
@@ -0,0 +1,280 @@
+STMicroelectronics STM32MP1
+===========================
+
+STM32MP1 is a microprocessor designed by STMicroelectronics
+based on Arm Cortex-A7.
+It is an Armv7-A platform, using dedicated code from TF-A.
+More information can be found on `STM32MP1 Series`_ page.
+
+
+STM32MP1 Versions
+-----------------
+
+There are 2 variants for STM32MP1: STM32MP13 and STM32MP15
+
+STM32MP13 Versions
+~~~~~~~~~~~~~~~~~~
+The STM32MP13 series is available in 3 different lines which are pin-to-pin compatible:
+
+- STM32MP131: Single Cortex-A7 core
+- STM32MP133: STM32MP131 + 2*CAN, ETH2(GMAC), ADC1
+- STM32MP135: STM32MP133 + DCMIPP, LTDC
+
+Each line comes with a security option (cryptography & secure boot) and a Cortex-A frequency option:
+
+- A Cortex-A7 @ 650 MHz
+- C Secure Boot + HW Crypto + Cortex-A7 @ 650 MHz
+- D Cortex-A7 @ 900 MHz
+- F Secure Boot + HW Crypto + Cortex-A7 @ 900 MHz
+
+STM32MP15 Versions
+~~~~~~~~~~~~~~~~~~
+The STM32MP15 series is available in 3 different lines which are pin-to-pin compatible:
+
+- STM32MP157: Dual Cortex-A7 cores, Cortex-M4 core @ 209 MHz, 3D GPU, DSI display interface and CAN FD
+- STM32MP153: Dual Cortex-A7 cores, Cortex-M4 core @ 209 MHz and CAN FD
+- STM32MP151: Single Cortex-A7 core, Cortex-M4 core @ 209 MHz
+
+Each line comes with a security option (cryptography & secure boot) and a Cortex-A frequency option:
+
+- A Basic + Cortex-A7 @ 650 MHz
+- C Secure Boot + HW Crypto + Cortex-A7 @ 650 MHz
+- D Basic + Cortex-A7 @ 800 MHz
+- F Secure Boot + HW Crypto + Cortex-A7 @ 800 MHz
+
+The `STM32MP1 part number codification`_ page gives more information about part numbers.
+
+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.
+
+Boot with FIP
+~~~~~~~~~~~~~
+The use of FIP is now the recommended way to boot STM32MP1 platform.
+Only BL2 (with STM32 header) is loaded by ROM code. The other binaries are
+inside the FIP binary: BL32 (SP_min or OP-TEE), U-Boot and their respective
+device tree blobs.
+
+
+Memory mapping
+~~~~~~~~~~~~~~
+
+::
+
+ 0x00000000 +-----------------+
+ | | ROM
+ 0x00020000 +-----------------+
+ | |
+ | ... |
+ | |
+ 0x2FFC0000 +-----------------+ \
+ | BL32 DTB | |
+ 0x2FFC5000 +-----------------+ |
+ | BL32 | |
+ 0x2FFDF000 +-----------------+ |
+ | ... | |
+ 0x2FFE3000 +-----------------+ |
+ | BL2 DTB | | Embedded SRAM
+ 0x2FFEA000 +-----------------+ |
+ | BL2 | |
+ 0x2FFFF000 +-----------------+ |
+ | SCMI mailbox | |
+ 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
+------------------
+Boot media(s) supported by BL2 must be specified in the build command.
+Available storage medias are:
+
+- ``STM32MP_SDMMC``
+- ``STM32MP_EMMC``
+- ``STM32MP_RAW_NAND``
+- ``STM32MP_SPI_NAND``
+- ``STM32MP_SPI_NOR``
+
+Serial boot devices:
+
+- ``STM32MP_UART_PROGRAMMER``
+- ``STM32MP_USB_PROGRAMMER``
+
+
+Other configuration flags:
+
+- | ``DTB_FILE_NAME``: to precise board device-tree blob to be used.
+ | Default: stm32mp157c-ev1.dtb
+- | ``DWL_BUFFER_BASE``: the 'serial boot' load address of FIP,
+ | default location (end of the first 128MB) is used when absent
+- | ``STM32MP_EARLY_CONSOLE``: to enable early traces before clock driver is setup.
+ | Default: 0 (disabled)
+- | ``STM32MP_RECONFIGURE_CONSOLE``: to re-configure crash console (especially after BL2).
+ | Default: 0 (disabled)
+- | ``STM32MP_UART_BAUDRATE``: to select UART baud rate.
+ | Default: 115200
+- | ``STM32_TF_VERSION``: to manage BL2 monotonic counter.
+ | Default: 0
+- | ``STM32MP13``: to select STM32MP13 variant configuration.
+ | Default: 0
+- | ``STM32MP15``: to select STM32MP15 variant configuration.
+ | Default: 1
+
+
+Boot with FIP
+~~~~~~~~~~~~~
+You need to build BL2, BL32 (SP_min or OP-TEE) and BL33 (U-Boot) before building FIP binary.
+
+U-Boot
+______
+
+.. code:: bash
+
+ cd <u-boot_directory>
+ make stm32mp15_trusted_defconfig
+ make DEVICE_TREE=stm32mp157c-ev1 all
+
+OP-TEE (optional)
+_________________
+
+.. code:: bash
+
+ cd <optee_directory>
+ make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm PLATFORM=stm32mp1 \
+ CFG_EMBED_DTB_SOURCE_FILE=stm32mp157c-ev1.dts
+
+
+TF-A BL32 (SP_min)
+__________________
+If you choose not to use OP-TEE, you can use TF-A SP_min.
+To build TF-A BL32, and its device tree file:
+
+.. code:: bash
+
+ make CROSS_COMPILE=arm-none-eabi- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 \
+ AARCH32_SP=sp_min DTB_FILE_NAME=stm32mp157c-ev1.dtb bl32 dtbs
+
+TF-A BL2
+________
+To build TF-A BL2 with its STM32 header for SD-card boot:
+
+.. code:: bash
+
+ make CROSS_COMPILE=arm-none-eabi- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 \
+ DTB_FILE_NAME=stm32mp157c-ev1.dtb STM32MP_SDMMC=1
+
+For other boot devices, you have to replace STM32MP_SDMMC in the previous command
+with the desired device flag.
+
+This BL2 is independent of the BL32 used (SP_min or OP-TEE)
+
+
+FIP
+___
+With BL32 SP_min:
+
+.. code:: bash
+
+ make CROSS_COMPILE=arm-none-eabi- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 \
+ AARCH32_SP=sp_min \
+ DTB_FILE_NAME=stm32mp157c-ev1.dtb \
+ BL33=<u-boot_directory>/u-boot-nodtb.bin \
+ BL33_CFG=<u-boot_directory>/u-boot.dtb \
+ fip
+
+With OP-TEE:
+
+.. code:: bash
+
+ make CROSS_COMPILE=arm-none-eabi- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 \
+ AARCH32_SP=optee \
+ DTB_FILE_NAME=stm32mp157c-ev1.dtb \
+ BL33=<u-boot_directory>/u-boot-nodtb.bin \
+ BL33_CFG=<u-boot_directory>/u-boot.dtb \
+ BL32=<optee_directory>/tee-header_v2.bin \
+ BL32_EXTRA1=<optee_directory>/tee-pager_v2.bin
+ BL32_EXTRA2=<optee_directory>/tee-pageable_v2.bin
+ fip
+
+Trusted Boot Board
+__________________
+
+.. code:: shell
+
+ tools/cert_create/cert_create -n --rot-key "build/stm32mp1/debug/rot_key.pem" \
+ --tfw-nvctr 0 \
+ --ntfw-nvctr 0 \
+ --key-alg ecdsa --hash-alg sha256 \
+ --trusted-key-cert build/stm32mp1/cert_images/trusted-key-cert.key-crt \
+ --tos-fw <optee_directory>/tee-header_v2.bin \
+ --tos-fw-extra1 <optee_directory>/tee-pager_v2.bin \
+ --tos-fw-extra2 <optee_directory>/tee-pageable_v2.bin \
+ --tos-fw-cert build/stm32mp1/cert_images/tee-header_v2.bin.crt \
+ --tos-fw-key-cert build/stm32mp1/cert_images/tee-header_v2.bin.key-crt \
+ --nt-fw <u-boot_directory>/u-boot-nodtb.bin \
+ --nt-fw-cert build/stm32mp1/cert_images/u-boot.bin.crt \
+ --nt-fw-key-cert build/stm32mp1/cert_images/u-boot.bin.key-crt \
+ --hw-config <u-boot_directory>/u-boot.dtb \
+ --fw-config build/stm32mp1/debug/fdts/fw-config.dtb \
+ --stm32mp-cfg-cert build/stm32mp1/cert_images/stm32mp_cfg_cert.crt
+
+ tools/fiptool/fiptool create --tos-fw <optee_directory>/tee-header_v2.bin \
+ --tos-fw-extra1 <optee_directory>/tee-pager_v2.bin \
+ --tos-fw-extra2 <optee_directory>/tee-pageable_v2.bin \
+ --nt-fw <u-boot_directory>/u-boot-nodtb.bin \
+ --hw-config <u-boot_directory>/u-boot.dtb \
+ --fw-config build/stm32mp1/debug/fdts/fw-config.dtb \
+ --tos-fw-cert build/stm32mp1/cert_images/tee-header_v2.bin.crt \
+ --tos-fw-key-cert build/stm32mp1/cert_images/tee-header_v2.bin.key-crt \
+ --nt-fw-cert build/stm32mp1/cert_images/u-boot.bin.crt \
+ --nt-fw-key-cert build/stm32mp1/cert_images/u-boot.bin.key-crt \
+ --stm32mp-cfg-cert build/stm32mp1/cert_images/stm32mp_cfg_cert.crt stm32mp1.fip
+
+
+
+Populate SD-card
+----------------
+
+Boot with FIP
+~~~~~~~~~~~~~
+The SD-card has to be formatted with GPT.
+It should contain at least those partitions:
+
+- fsbl: to copy the tf-a-stm32mp157c-ev1.stm32 binary (BL2)
+- fip: which contains the FIP 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
+.. _STM32MP1 part number codification: https://wiki.st.com/stm32mpu/wiki/STM32MP15_microprocessor#Part_number_codification
diff --git a/docs/plat/synquacer.rst b/docs/plat/synquacer.rst
new file mode 100644
index 0000000..dd29d29
--- /dev/null
+++ b/docs/plat/synquacer.rst
@@ -0,0 +1,117 @@
+Socionext 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 <https://github.com/ARM-software/arm-trusted-firmware>`__
+
+- edk2:
+ `link <https://github.com/tianocore/edk2>`__
+
+- edk2-platforms:
+ `link <https://github.com/tianocore/edk2-platforms>`__
+
+- edk2-non-osi:
+ `link <https://github.com/tianocore/edk2-non-osi>`__
+
+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
diff --git a/docs/plat/ti-k3.rst b/docs/plat/ti-k3.rst
new file mode 100644
index 0000000..4843227
--- /dev/null
+++ b/docs/plat/ti-k3.rst
@@ -0,0 +1,57 @@
+Texas 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=<path to 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=<path> TEE=<path>
+
+Deploy Images
+-------------
+
+.. code:: shell
+
+ cp tiboot3.bin tispl.bin u-boot.img /sdcard/boot/
diff --git a/docs/plat/warp7.rst b/docs/plat/warp7.rst
new file mode 100644
index 0000000..f98a76f
--- /dev/null
+++ b/docs/plat/warp7.rst
@@ -0,0 +1,210 @@
+NXP 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/
diff --git a/docs/plat/xilinx-versal-net.rst b/docs/plat/xilinx-versal-net.rst
new file mode 100644
index 0000000..5d2e663
--- /dev/null
+++ b/docs/plat/xilinx-versal-net.rst
@@ -0,0 +1,31 @@
+Xilinx Versal NET
+=================
+
+Trusted Firmware-A implements the EL3 firmware layer for Xilinx Versal NET.
+The platform only uses the runtime part of TF-A as Xilinx Versal NET 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_net bl31
+```
+
+Xilinx Versal NET platform specific build options
+-------------------------------------------------
+
+* `VERSAL_NET_ATF_MEM_BASE`: Specifies the base address of the bl31 binary.
+* `VERSAL_NET_ATF_MEM_SIZE`: Specifies the size of the memory region of the bl31 binary.
+* `VERSAL_NET_BL32_MEM_BASE`: Specifies the base address of the bl32 binary.
+* `VERSAL_NET_BL32_MEM_SIZE`: Specifies the size of the memory region of the bl32 binary.
+
+* `VERSAL_NET_CONSOLE`: Select the console driver. Options:
+ - `pl011`, `pl011_0`: ARM pl011 UART 0
+ - `pl011_1` : ARM pl011 UART 1
+
+* `TFA_NO_PM` : Platform Management support.
+ - 0 : Enable Platform Management (Default)
+ - 1 : Disable Platform Management
diff --git a/docs/plat/xilinx-versal.rst b/docs/plat/xilinx-versal.rst
new file mode 100644
index 0000000..09a6ee2
--- /dev/null
+++ b/docs/plat/xilinx-versal.rst
@@ -0,0 +1,55 @@
+Xilinx 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 (supported are "silicon"(default) and "versal_virt")
+```bash
+make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal VERSAL_PLATFORM=versal_virt bl31
+```
+
+To build TF-A for JTAG DCC console
+```bash
+make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal bl31 VERSAL_CONSOLE=dcc
+```
+
+To build TF-A with Straight-Line Speculation(SLS)
+```bash
+make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal bl31 HARDEN_SLS_ALL=1
+```
+
+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
+ - `spp_itr6` : SPP ITR6
+ - `emu_itr6` : EMU ITR6
+
+# PLM->TF-A Parameter Passing
+------------------------------
+The PLM populates a data structure with image information for the TF-A. The TF-A
+uses that data to hand off to the loaded images. The address of the handoff
+data structure is passed in the ```PMC_GLOBAL_GLOB_GEN_STORAGE4``` register.
+The register is free to be used by other software once the TF-A is bringing up
+further firmware images.
diff --git a/docs/plat/xilinx-zynqmp.rst b/docs/plat/xilinx-zynqmp.rst
new file mode 100644
index 0000000..af1cb22
--- /dev/null
+++ b/docs/plat/xilinx-zynqmp.rst
@@ -0,0 +1,73 @@
+Xilinx 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 RESET_TO_BL31=1 bl31
+
+To build bl32 TSP you have to rebuild bl31 too:
+
+.. code:: bash
+
+ make CROSS_COMPILE=aarch64-none-elf- PLAT=zynqmp SPD=tspd RESET_TO_BL31=1 bl31 bl32
+
+To build TF-A for JTAG DCC console:
+
+.. code:: bash
+
+ make CROSS_COMPILE=aarch64-none-elf- PLAT=zynqmp RESET_TO_BL31=1 bl31 ZYNQMP_CONSOLE=dcc
+
+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.
diff --git a/docs/process/code-review-guidelines.rst b/docs/process/code-review-guidelines.rst
new file mode 100644
index 0000000..67a211f
--- /dev/null
+++ b/docs/process/code-review-guidelines.rst
@@ -0,0 +1,216 @@
+Code Review Guidelines
+======================
+
+This document provides TF-A specific details about the project's code review
+process. It should be read in conjunction with the `Project Maintenance
+Process`_, which it supplements.
+
+
+Why do we do code reviews?
+--------------------------
+
+The main goal of code reviews is to improve the code quality. By reviewing each
+other's code, we can help catch issues that were missed by the author
+before they are integrated in the source tree. Different people bring different
+perspectives, depending on their past work, experiences and their current use
+cases of TF-A in their products.
+
+Code reviews also play a key role in sharing knowledge within the
+community. People with more expertise in one area of the code base can
+help those that are less familiar with it.
+
+Code reviews are meant to benefit everyone through team work. It is not about
+unfairly criticizing or belittling the work of any contributor.
+
+
+Good practices
+--------------
+
+To ensure the code review gives the greatest possible benefit, participants in
+the project should:
+
+- Be considerate of other people and their needs. Participants may be working
+ to different timescales, and have different priorities. Keep this in
+ mind - be gracious while waiting for action from others, and timely in your
+ actions when others are waiting for you.
+
+- Review other people's patches where possible. The more active reviewers there
+ are, the more quickly new patches can be reviewed and merged. Contributing to
+ code review helps everyone in the long run, as it creates a culture of
+ participation which serves everyone's interests.
+
+
+Guidelines for patch contributors
+---------------------------------
+
+In addition to the rules outlined in the :ref:`Contributor's Guide`, as a patch
+contributor you are expected to:
+
+- Answer all comments from people who took the time to review your
+ patches.
+
+- Be patient and resilient. It is quite common for patches to go through
+ several rounds of reviews and rework before they get approved, especially
+ for larger features.
+
+ In the event that a code review takes longer than you would hope for, you
+ may try the following actions to speed it up:
+
+ - Ping the reviewers on Gerrit or on the mailing list. If it is urgent,
+ explain why. Please remain courteous and do not abuse this.
+
+ - If one code owner has become unresponsive, ask the other code owners for
+ help progressing the patch.
+
+ - If there is only one code owner and they have become unresponsive, ask one
+ of the project maintainers for help.
+
+- Do the right thing for the project, not the fastest thing to get code merged.
+
+ For example, if some existing piece of code - say a driver - does not quite
+ meet your exact needs, go the extra mile and extend the code with the missing
+ functionality you require - as opposed to copying the code into some other
+ directory to have the freedom to change it in any way. This way, your changes
+ benefit everyone and will be maintained over time.
+
+
+Guidelines for all reviewers
+----------------------------
+
+There are no good or bad review comments. If you have any doubt about a patch or
+need some clarifications, it's better to ask rather than letting a potential
+issue slip. Examples of review comments could be:
+
+- Questions ("Why do you need to do this?", "What if X happens?")
+- Bugs ("I think you need a logical \|\| rather than a bitwise \|.")
+- Design issues ("This won't scale well when we introduce feature X.")
+- Improvements ("Would it be better if we did Y instead?")
+
+
+Guidelines for code owners
+--------------------------
+
+Code owners are listed on the :ref:`Project Maintenance<code owners>` page,
+along with the module(s) they look after.
+
+When reviewing a patch, code owners are expected to check the following:
+
+- The patch looks good from a technical point of view. For example:
+
+ - The structure of the code is clear.
+
+ - It complies with the relevant standards or technical documentation (where
+ applicable).
+
+ - It leverages existing interfaces rather than introducing new ones
+ unnecessarily.
+
+ - It fits well in the design of the module.
+
+ - It adheres to the security model of the project. In particular, it does not
+ increase the attack surface (e.g. new SMCs) without justification.
+
+- The patch adheres to the TF-A :ref:`Coding Style`. The CI system should help
+ catch coding style violations.
+
+- (Only applicable to generic code) The code is MISRA-compliant (see
+ :ref:`misra-compliance`). The CI system should help catch violations.
+
+- Documentation is provided/updated (where applicable).
+
+- The patch has had an appropriate level of testing. Testing details are
+ expected to be provided by the patch author. If they are not, do not hesitate
+ to request this information.
+
+- All CI automated tests pass.
+
+If a code owner is happy with a patch, they should give their approval
+through the ``Code-Owner-Review+1`` label in Gerrit. If instead, they have
+concerns, questions, or any other type of blocking comment, they should set
+``Code-Owner-Review-1``.
+
+Code owners are expected to behave professionally and responsibly. Here are some
+guidelines for them:
+
+- Once you are engaged in a review, make sure you stay involved until the patch
+ is merged. Rejecting a patch and going away is not very helpful. You are
+ expected to monitor the patch author's answers to your review comments,
+ answer back if needed and review new revisions of their patch.
+
+- Provide constructive feedback. Just saying, "This is wrong, you should do X
+ instead." is usually not very helpful. The patch author is unlikely to
+ understand why you are requesting this change and might feel personally
+ attacked.
+
+- Be mindful when reviewing a patch. As a code owner, you are viewed as
+ the expert for the relevant module. By approving a patch, you are partially
+ responsible for its quality and the effects it has for all TF-A users. Make
+ sure you fully understand what the implications of a patch might be.
+
+
+Guidelines for maintainers
+--------------------------
+
+Maintainers are listed on the :ref:`Project Maintenance<maintainers>` page.
+
+When reviewing a patch, maintainers are expected to check the following:
+
+- The general structure of the patch looks good. This covers things like:
+
+ - Code organization.
+
+ - Files and directories, names and locations.
+
+ For example, platform code should be added under the ``plat/`` directory.
+
+ - Naming conventions.
+
+ For example, platform identifiers should be properly namespaced to avoid
+ name clashes with generic code.
+
+ - API design.
+
+- Interaction of the patch with other modules in the code base.
+
+- The patch aims at complying with any standard or technical documentation
+ that applies.
+
+- New files must have the correct license and copyright headers. See :ref:`this
+ paragraph<copyright-license-guidance>` for more information. The CI system
+ should help catch files with incorrect or no copyright/license headers.
+
+- There is no third party code or binary blobs with potential IP concerns.
+ Maintainers should look for copyright or license notices in code, and use
+ their best judgement. If they are unsure about a patch, they should ask
+ other maintainers for help.
+
+- Generally speaking, new driver code should be placed in the generic
+ layer. There are cases where a driver has to stay into the platform layer but
+ this should be the exception, rather than the rule.
+
+- Existing common drivers (in particular for Arm IPs like the GIC driver) should
+ not be copied into the platform layer to cater for platform quirks. This
+ type of code duplication hurts the maintainability of the project. The
+ duplicate driver is less likely to benefit from bug fixes and future
+ enhancements. In most cases, it is possible to rework a generic driver to
+ make it more flexible and fit slightly different use cases. That way, these
+ enhancements benefit everyone.
+
+- When a platform specific driver really is required, the burden lies with the
+ patch author to prove the need for it. A detailed justification should be
+ posted via the commit message or on the mailing list.
+
+- Before merging a patch, verify that all review comments have been addressed.
+ If this is not the case, encourage the patch author and the relevant
+ reviewers to resolve these together.
+
+If a maintainer is happy with a patch, they should give their approval
+through the ``Maintainer-Review+1`` label in Gerrit. If instead, they have
+concerns, questions, or any other type of blocking comment, they should set
+``Maintainer-Review-1``.
+
+--------------
+
+*Copyright (c) 2020, Arm Limited. All rights reserved.*
+
+.. _Project Maintenance Process: https://developer.trustedfirmware.org/w/collaboration/project-maintenance-process/
diff --git a/docs/process/coding-guidelines.rst b/docs/process/coding-guidelines.rst
new file mode 100644
index 0000000..26c272d
--- /dev/null
+++ b/docs/process/coding-guidelines.rst
@@ -0,0 +1,474 @@
+Coding Guidelines
+=================
+
+This document provides some additional guidelines to consider when writing
+|TF-A| code. These are not intended to be strictly-enforced rules like the
+contents of the :ref:`Coding Style`.
+
+Automatic Editor Configuration
+------------------------------
+
+Many of the rules given below (such as indentation size, use of tabs, and
+newlines) can be set automatically using the `EditorConfig`_ configuration file
+in the root of the repository: ``.editorconfig``. With a supported editor, the
+rules set out in this file can be automatically applied when you are editing
+files in the |TF-A| repository.
+
+Several editors include built-in support for EditorConfig files, and many others
+support its functionality through plugins.
+
+Use of the EditorConfig file is suggested but is not required.
+
+.. _automatic-compliance-checking:
+
+Automatic Compliance Checking
+-----------------------------
+
+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=<path-to-linux>/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=<path-to-linux>/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``.
+
+Ignored Checkpatch Warnings
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+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 legimate uses of the
+ volatile keyword within the TF codebase.
+
+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:
+
+.. code:: shell
+
+ 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.
+
+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 <cassert.h>
+
+ 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.
+
+Use of built-in *C* and *libc* data types
+-----------------------------------------
+
+The |TF-A| 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.
+
+ - Avoid pointer arithmetic generally (as this violates MISRA C 2012 rule
+ 18.4) and especially on void pointers (as this is only supported via
+ language extensions and is considered non-standard). In TF-A, setting the
+ ``W`` build flag to ``W=3`` enables the *-Wpointer-arith* compiler flag and
+ this will emit warnings where pointer arithmetic is used.
+
+ - 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.
+
+Favor C language over assembly language
+---------------------------------------
+
+Generally, prefer code written in C over assembly. Assembly code is less
+portable, harder to understand, maintain and audit security wise. Also, static
+analysis tools generally don't analyze assembly code.
+
+There are, however, legitimate uses of assembly language. These include:
+
+ - Early boot code executed before the C runtime environment is setup.
+
+ - Exception handling code.
+
+ - Low-level code where the exact sequence of instructions executed on the CPU
+ matters, such as CPU reset sequences.
+
+ - Low-level code where specific system-level instructions must be used, such
+ as cache maintenance operations.
+
+--------------
+
+*Copyright (c) 2020, 2022, Arm Limited and Contributors. All rights reserved.*
+
+.. _`Linux master tree`: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/
+.. _`Procedure Call Standard for the Arm Architecture`: https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst
+.. _`Procedure Call Standard for the Arm 64-bit Architecture`: https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst
+.. _`EditorConfig`: http://editorconfig.org/
+.. _`Why the “volatile†type class should not be used`: https://www.kernel.org/doc/html/latest/process/volatile-considered-harmful.html
+.. _`MISRA C:2012 Guidelines`: https://www.misra.org.uk/Activities/MISRAC/tabid/160/Default.aspx
+.. _`a spreadsheet`: https://developer.trustedfirmware.org/file/download/lamajxif3w7c4mpjeoo5/PHID-FILE-fp7c7acszn6vliqomyhn/MISRA-and-TF-Analysis-v1.3.ods
diff --git a/docs/process/coding-style.rst b/docs/process/coding-style.rst
new file mode 100644
index 0000000..be13b14
--- /dev/null
+++ b/docs/process/coding-style.rst
@@ -0,0 +1,470 @@
+Coding Style
+============
+
+The following sections outline the |TF-A| coding style for *C* code. The style
+is based on the `Linux kernel coding style`_, with a few modifications.
+
+The style should not be considered *set in stone*. Feel free to provide feedback
+and suggestions.
+
+.. note::
+ You will almost certainly find code in the |TF-A| repository that does not
+ follow the style. The intent is for all code to do so eventually.
+
+File Encoding
+-------------
+
+The source code must use the **UTF-8** character encoding. Comments and
+documentation may use non-ASCII characters when required (e.g. Greek letters
+used for units) but code itself is still limited to ASCII characters.
+
+Newlines must be in **Unix** style, which means that only the Line Feed (``LF``)
+character is used to break a line and reset to the first column.
+
+Language
+--------
+
+The primary language for comments and naming must be International English. In
+cases where there is a conflict between the American English and British English
+spellings of a word, the American English spelling is used.
+
+Exceptions are made when referring directly to something that does not use
+international style, such as the name of a company. In these cases the existing
+name should be used as-is.
+
+C Language Standard
+-------------------
+
+The C language mode used for TF-A is *GNU99*. This is the "GNU dialect of ISO
+C99", which implies the *ISO C99* standard with GNU extensions.
+
+Both GCC and Clang compiler toolchains have support for *GNU99* mode, though
+Clang does lack support for a small number of GNU extensions. These
+missing extensions are rarely used, however, and should not pose a problem.
+
+.. _misra-compliance:
+
+MISRA Compliance
+----------------
+
+TF-A attempts to comply with the `MISRA C:2012 Guidelines`_. Coverity
+Static Analysis is used to regularly generate a report of current MISRA defects
+and to prevent the addition of new ones.
+
+It is not possible for the project to follow all MISRA guidelines. We maintain
+`a spreadsheet`_ that lists all rules and directives and whether we aim to
+comply with them or not. A rationale is given for each deviation.
+
+.. note::
+ Enforcing a rule does not mean that the codebase is free of defects
+ of that rule, only that they would ideally be removed.
+
+.. note::
+ Third-party libraries are not considered in our MISRA analysis and we do not
+ intend to modify them to make them MISRA compliant.
+
+Indentation
+-----------
+
+Use **tabs** for indentation. The use of spaces for indentation is forbidden
+except in the case where a term is being indented to a boundary that cannot be
+achieved using tabs alone.
+
+Tab spacing should be set to **8 characters**.
+
+Trailing whitespace is not allowed and must be trimmed.
+
+Spacing
+-------
+
+Single spacing should be used around most operators, including:
+
+- Arithmetic operators (``+``, ``-``, ``/``, ``*``)
+- Assignment operators (``=``, ``+=``, etc)
+- Boolean operators (``&&``, ``||``)
+- Comparison operators (``<``, ``>``, ``==``, etc)
+
+A space should also be used to separate parentheses and braces when they are not
+already separated by a newline, such as for the ``if`` statement in the
+following example:
+
+.. code:: c
+
+ int function_foo(bool bar)
+ {
+ if (bar) {
+ function_baz();
+ }
+ }
+
+Note that there is no space between the name of a function and the following
+parentheses.
+
+Control statements (``if``, ``for``, ``switch``, ``while``, etc) must be
+separated from the following open parenthesis by a single space. The previous
+example illustrates this for an ``if`` statement.
+
+Line Length
+-----------
+
+Line length *should* be at most **80 characters**. This limit does not include
+non-printing characters such as the line feed.
+
+This rule is a *should*, not a must, and it is acceptable to exceed the limit
+**slightly** where the readability of the code would otherwise be significantly
+reduced. Use your judgement in these cases.
+
+Blank Lines
+-----------
+
+Functions are usually separated by a single blank line. In certain cases it is
+acceptable to use additional blank lines for clarity, if required.
+
+The file must end with a single newline character. Many editors have the option
+to insert this automatically and to trim multiple blank lines at the end of the
+file.
+
+Braces
+------
+
+Opening Brace Placement
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Braces follow the **Kernighan and Ritchie (K&R)** style, where the opening brace
+is **not** placed on a new line.
+
+Example for a ``while`` loop:
+
+.. code:: c
+
+ while (condition) {
+ foo();
+ bar();
+ }
+
+This style applies to all blocks except for functions which, following the Linux
+style, **do** place the opening brace on a new line.
+
+Example for a function:
+
+.. code:: c
+
+ int my_function(void)
+ {
+ int a;
+
+ a = 1;
+ return a;
+ }
+
+Conditional Statement Bodies
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Where conditional statements (such as ``if``, ``for``, ``while`` and ``do``) are
+used, braces must be placed around the statements that form the body of the
+conditional. This is the case regardless of the number of statements in the
+body.
+
+.. note::
+ This is a notable departure from the Linux coding style that has been
+ adopted to follow MISRA guidelines more closely and to help prevent errors.
+
+For example, use the following style:
+
+.. code:: c
+
+ if (condition) {
+ foo++;
+ }
+
+instead of omitting the optional braces around a single statement:
+
+.. code:: c
+
+ /* This is violating MISRA C 2012: Rule 15.6 */
+ if (condition)
+ foo++;
+
+The reason for this is to prevent accidental changes to control flow when
+modifying the body of the conditional. For example, at a quick glance it is easy
+to think that the value of ``bar`` is only incremented if ``condition``
+evaluates to ``true`` but this is not the case - ``bar`` will always be
+incremented regardless of the condition evaluation. If the developer forgets to
+add braces around the conditional body when adding the ``bar++;`` statement then
+the program execution will not proceed as intended.
+
+.. code:: c
+
+ /* This is violating MISRA C 2012: Rule 15.6 */
+ if (condition)
+ foo++;
+ bar++;
+
+Naming
+------
+
+Functions
+^^^^^^^^^
+
+Use lowercase for function names, separating multiple words with an underscore
+character (``_``). This is sometimes referred to as *Snake Case*. An example is
+given below:
+
+.. code:: c
+
+ void bl2_arch_setup(void)
+ {
+ ...
+ }
+
+Local Variables and Parameters
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Local variables and function parameters use the same format as function names:
+lowercase with underscore separation between multiple words. An example is
+given below:
+
+.. code:: c
+
+ static void set_scr_el3_from_rm(uint32_t type,
+ uint32_t interrupt_type_flags,
+ uint32_t security_state)
+ {
+ uint32_t flag, bit_pos;
+
+ ...
+
+ }
+
+Preprocessor Macros
+^^^^^^^^^^^^^^^^^^^
+
+Identifiers that are defined using preprocessor macros are written in all
+uppercase text.
+
+.. code:: c
+
+ #define BUFFER_SIZE_BYTES 64
+
+Function Attributes
+-------------------
+
+Place any function attributes after the function type and before the function
+name.
+
+.. code:: c
+
+ void __init plat_arm_interconnect_init(void);
+
+Alignment
+---------
+
+Alignment should be performed primarily with tabs, adding spaces if required to
+achieve a granularity that is smaller than the tab size. For example, with a tab
+size of eight columns it would be necessary to use one tab character and two
+spaces to indent text by ten columns.
+
+Switch Statement Alignment
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When using ``switch`` statements, align each ``case`` statement with the
+``switch`` so that they are in the same column.
+
+.. code:: c
+
+ switch (condition) {
+ case A:
+ foo();
+ case B:
+ bar();
+ default:
+ baz();
+ }
+
+Pointer Alignment
+^^^^^^^^^^^^^^^^^
+
+The reference and dereference operators (ampersand and *pointer star*) must be
+aligned with the name of the object on which they are operating, as opposed to
+the type of the object.
+
+.. code:: c
+
+ uint8_t *foo;
+
+ foo = &bar;
+
+
+Comments
+--------
+
+The general rule for comments is that the double-slash style of comment (``//``)
+is not allowed. Examples of the allowed comment formats are shown below:
+
+.. code:: c
+
+ /*
+ * This example illustrates the first allowed style for multi-line comments.
+ *
+ * Blank lines within multi-lines are allowed when they add clarity or when
+ * they separate multiple contexts.
+ *
+ */
+
+.. code:: c
+
+ /**************************************************************************
+ * This is the second allowed style for multi-line comments.
+ *
+ * In this style, the first and last lines use asterisks that run the full
+ * width of the comment at its widest point.
+ *
+ * This style can be used for additional emphasis.
+ *
+ *************************************************************************/
+
+.. code:: c
+
+ /* Single line comments can use this format */
+
+.. code:: c
+
+ /***************************************************************************
+ * This alternative single-line comment style can also be used for emphasis.
+ **************************************************************************/
+
+Headers and inclusion
+---------------------
+
+Header guards
+^^^^^^^^^^^^^
+
+For a header file called "some_driver.h" the style used by |TF-A| is:
+
+.. code:: c
+
+ #ifndef SOME_DRIVER_H
+ #define SOME_DRIVER_H
+
+ <header content>
+
+ #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-A| are *project* includes.
+
+#. *Platform* includes: Header files relating to a single, specific platform,
+ and which are located under the ``plat/<platform_name>`` directory within
+ |TF-A|, 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 <string.h>
+
+ #include <a_dir/example/a_header.h>
+ #include <a_dir/example/b_header.h>
+ #include <a_dir/test/a_header.h>
+ #include <b_dir/example/a_header.h>
+
+ #include "a_header.h"
+
+Include statement variants
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Two variants of the ``#include`` directive are acceptable in the |TF-A|
+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 <assert.h>
+ #include <errno.h>
+ #include <string.h>
+
+ #include "bl1_private.h"
+
+Typedefs
+--------
+
+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
+
+ struct my_struct;
+ void my_func(struct my_struct *arg);
+
+instead of:
+
+.. code:: c
+
+ #include <my_struct.h>
+ void my_func(my_struct_t *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.
+
+--------------
+
+*Copyright (c) 2020, Arm Limited. All rights reserved.*
+
+.. _`Linux kernel coding style`: https://www.kernel.org/doc/html/latest/process/coding-style.html
+.. _`MISRA C:2012 Guidelines`: https://www.misra.org.uk/Activities/MISRAC/tabid/160/Default.aspx
+.. _`a spreadsheet`: https://developer.trustedfirmware.org/file/download/lamajxif3w7c4mpjeoo5/PHID-FILE-fp7c7acszn6vliqomyhn/MISRA-and-TF-Analysis-v1.3.ods
diff --git a/docs/process/commit-style.rst b/docs/process/commit-style.rst
new file mode 100644
index 0000000..d7e937b
--- /dev/null
+++ b/docs/process/commit-style.rst
@@ -0,0 +1,153 @@
+Commit Style
+============
+
+When writing commit messages, please think carefully about the purpose and scope
+of the change you are making: describe briefly what the change does, and
+describe in detail why it does it. This helps to ensure that changes to the
+code-base are transparent and approachable to reviewers, and it allows us to
+keep a more accurate changelog. You may use Markdown in commit messages.
+
+A good commit message provides all the background information needed for
+reviewers to understand the intent and rationale of the patch. This information
+is also useful for future reference.
+
+For example:
+
+- What does the patch do?
+- What motivated it?
+- What impact does it have?
+- How was it tested?
+- Have alternatives been considered? Why did you choose this approach over
+ another one?
+- If it fixes an `issue`_, include a reference.
+
+|TF-A| follows the `Conventional Commits`_ specification. All commits to the
+main repository are expected to adhere to these guidelines, so it is
+**strongly** recommended that you read at least the `quick summary`_ of the
+specification.
+
+To briefly summarize, commit messages are expected to be of the form:
+
+.. code::
+
+ <type>[optional scope]: <description>
+
+ [optional body]
+
+ [optional footer(s)]
+
+The following example commit message demonstrates the use of the
+``refactor`` type and the ``amu`` scope:
+
+.. code::
+
+ refactor(amu): factor out register accesses
+
+ This change introduces a small set of register getters and setters to
+ avoid having to repeatedly mask and shift in complex code.
+
+ Change-Id: Ia372f60c5efb924cd6eeceb75112e635ad13d942
+ Signed-off-by: Chris Kay <chris.kay@arm.com>
+
+The following `types` are permissible and are strictly enforced:
+
++--------------+---------------------------------------------------------------+
+| Scope | Description |
++==============+===============================================================+
+| ``feat`` | A new feature |
++--------------+---------------------------------------------------------------+
+| ``fix`` | A bug fix |
++--------------+---------------------------------------------------------------+
+| ``build`` | Changes that affect the build system or external dependencies |
++--------------+---------------------------------------------------------------+
+| ``ci`` | Changes to our CI configuration files and scripts |
++--------------+---------------------------------------------------------------+
+| ``docs`` | Documentation-only changes |
++--------------+---------------------------------------------------------------+
+| ``perf`` | A code change that improves performance |
++--------------+---------------------------------------------------------------+
+| ``refactor`` | A code change that neither fixes a bug nor adds a feature |
++--------------+---------------------------------------------------------------+
+| ``revert`` | Changes that revert a previous change |
++--------------+---------------------------------------------------------------+
+| ``style`` | Changes that do not affect the meaning of the code |
+| | (white-space, formatting, missing semi-colons, etc.) |
++--------------+---------------------------------------------------------------+
+| ``test`` | Adding missing tests or correcting existing tests |
++--------------+---------------------------------------------------------------+
+| ``chore`` | Any other change |
++--------------+---------------------------------------------------------------+
+
+The permissible `scopes` are more flexible, and we maintain a list of them in
+our :download:`changelog configuration file <../../changelog.yaml>`. Scopes in
+this file are organized by their changelog section, where each changelog section
+has a single scope that is considered to be blessed, and possibly several
+deprecated scopes. Please avoid using deprecated scopes.
+
+While we don't enforce scopes strictly, we do ask that commits use these if they
+can, or add their own if no appropriate one exists (see :ref:`Adding Scopes`).
+
+It's highly recommended that you use the tooling installed by the optional steps
+in the :ref:`prerequisites <Prerequisites>` guide to validate commit messages
+locally, as commitlint reports a live list of the acceptable scopes.
+
+.. _Adding Scopes:
+
+Adding Scopes
+-------------
+
+Scopes that are not present in the changelog configuration file are considered
+to be deprecated, and should be avoided. If you are adding a new component that
+does not yet have a designated scope, please add one.
+
+For example, if you are adding or making modifications to `Foo`'s latest and
+greatest new platform `Bar` then you would add it to the `Platforms` changelog
+sub-section, and the hierarchy should look something like this:
+
+.. code:: yaml
+
+ - title: Platforms
+
+ subsections:
+ - title: Foo
+ scope: foo
+
+ subsections:
+ - title: Bar
+ scope: bar
+
+When creating new scopes, try to keep them short and succinct, and use kebab
+case (``this-is-kebab-case``). Components with a product name (i.e. most
+platforms and some drivers) should use that name (e.g. ``gic600ae``,
+``flexspi``, ``stpmic1``), otherwise use a name that uniquely represents the
+component (e.g. ``marvell-comphy-3700``, ``rcar3-drivers``, ``a3720-uart``).
+
+Mandated Trailers
+-----------------
+
+Commits are expected to be signed off with the ``Signed-off-by:`` trailer using
+your real name and email address. You can do this automatically by committing
+with Git's ``-s`` flag. By adding this line the contributor certifies the
+contribution is made under the terms of the :download:`Developer Certificate of
+Origin <../../dco.txt>`.
+
+There may be multiple ``Signed-off-by:`` lines depending on the history of the
+patch, but one **must** be the committer. 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
+followed optional steps in the prerequisites to either install the Node.js tools
+or clone the repository using the "`Clone with commit-msg hook`" clone method,
+then this should be done automatically for you.
+
+More details may be found in the `Gerrit Change-Ids documentation`_.
+
+--------------
+
+*Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.*
+
+.. _Conventional Commits: https://www.conventionalcommits.org/en/v1.0.0
+.. _Gerrit Change-Ids documentation: https://review.trustedfirmware.org/Documentation/user-changeid.html
+.. _Gerrit Signed-off-by Lines guidelines: https://review.trustedfirmware.org/Documentation/user-signedoffby.html
+.. _issue: https://developer.trustedfirmware.org/project/board/1/
+.. _quick summary: https://www.conventionalcommits.org/en/v1.0.0/#summary
diff --git a/docs/process/contributing.rst b/docs/process/contributing.rst
new file mode 100644
index 0000000..ef9ebd3
--- /dev/null
+++ b/docs/process/contributing.rst
@@ -0,0 +1,304 @@
+Contributor's Guide
+*******************
+
+Getting Started
+===============
+
+- Make sure you have a Github account and you are logged on both
+ `developer.trustedfirmware.org`_ and `review.trustedfirmware.org`_.
+
+- If you plan to contribute a major piece of work, it is usually a good idea to
+ start a discussion around it on the mailing list. This gives everyone
+ visibility of what is coming up, you might learn that somebody else is
+ already working on something similar or the community might be able to
+ provide some early input to help shaping the design of the feature.
+
+ If you intend to include Third Party IP in your contribution, please mention
+ it explicitly in the email thread and ensure that the changes that include
+ Third Party IP are made in a separate patch (or patch series).
+
+- Clone `Trusted Firmware-A`_ on your own machine as described in
+ :ref:`prerequisites_get_source`.
+
+- Create a local topic branch based on the `Trusted Firmware-A`_ ``master``
+ branch.
+
+Making Changes
+==============
+
+- Ensure commits adhere to the the project's :ref:`Commit Style`.
+
+- Make commits of logical units. See these general `Git guidelines`_ for
+ contributing to a project.
+
+- Keep the commits on topic. If you need to fix another bug or make another
+ enhancement, please address it on a separate topic branch.
+
+- Split the patch in manageable units. Small patches are usually easier to
+ review so this will speed up the review process.
+
+- 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.
+
+- Follow the :ref:`Coding Style` and :ref:`Coding Guidelines`.
+
+ - Use the checkpatch.pl script provided with the Linux source tree. A
+ Makefile target is provided for convenience, see :ref:`this
+ section<automatic-compliance-checking>` for more details.
+
+- Where appropriate, please update the documentation.
+
+ - Consider whether the :ref:`Porting Guide`, :ref:`Firmware Design` document
+ or other in-source documentation needs updating.
+
+ - If you are submitting new files that you intend to be the code owner for
+ (for example, a new platform port), then also update the
+ :ref:`code owners` 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.
+
+.. _copyright-license-guidance:
+
+- 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 the
+ following format:
+
+ ::
+
+ Portions copyright (c) [XXXX-]YYYY, <OWNER>. All rights reserved.
+
+ where XXXX is the year of first contribution (if different to YYYY) and YYYY
+ is the year of most recent contribution. <OWNER> is your name or your company
+ name.
+
+- Ensure that each patch in the patch series compiles in all supported
+ configurations. Patches which do not compile will not be merged.
+
+- Please test your changes. As a minimum, ensure that Linux boots on the
+ Foundation FVP. See :ref:`Arm Fixed Virtual Platforms (FVP)` for more
+ information. For more extensive testing, consider running the `TF-A Tests`_
+ against your patches.
+
+- Ensure that all CI automated tests pass. Failures should be fixed. They might
+ block a patch, depending on how critical they are.
+
+Submitting Changes
+==================
+
+- Submit your changes for review at https://review.trustedfirmware.org
+ targeting the ``integration`` branch.
+
+- Add reviewers for your patch:
+
+ - At least one code owner for each module modified by the patch. See the list
+ of modules and their :ref:`code owners`.
+
+ - At least one maintainer. See the list of :ref:`maintainers`.
+
+ - If some module has no code owner, try to identify a suitable (non-code
+ owner) reviewer. Running ``git blame`` on the module's source code can
+ help, as it shows who has been working the most recently on this area of
+ the code.
+
+ Alternatively, if it is impractical to identify such a reviewer, you might
+ send an email to the `TF-A mailing list`_ to broadcast your review request
+ to the community.
+
+ Note that self-reviewing a patch is prohibited, even if the patch author is
+ the only code owner of a module modified by the patch. Getting a second pair
+ of eyes on the code is essential to keep up with the quality standards the
+ project aspires to.
+
+- The changes will then undergo further review by the designated people. Any
+ review comments will be made directly on your patch. This may require you to
+ do some rework. For controversial changes, the discussion might be moved to
+ the `TF-A mailing list`_ to involve more of the community.
+
+ Refer to the `Gerrit Uploading Changes documentation`_ for more details.
+
+- The patch submission rules are the following. For a patch to be approved
+ and merged in the tree, it must get:
+
+ - One ``Code-Owner-Review+1`` for each of the modules modified by the patch.
+ - A ``Maintainer-Review+1``.
+
+ In the case where a code owner could not be found for a given module,
+ ``Code-Owner-Review+1`` is substituted by ``Code-Review+1``.
+
+ In addition to these various code review labels, the patch must also get a
+ ``Verified+1``. This is usually set by the Continuous Integration (CI) bot
+ when all automated tests passed on the patch. Sometimes, some of these
+ automated tests may fail for reasons unrelated to the patch. In this case,
+ the maintainers might (after analysis of the failures) override the CI bot
+ score to certify that the patch has been correctly tested.
+
+ In the event where the CI system lacks proper tests for a patch, the patch
+ author or a reviewer might agree to perform additional manual tests
+ in their review and the reviewer incorporates the review of the additional
+ testing in the ``Code-Review+1`` or ``Code-Owner-Review+1`` as applicable to
+ attest that the patch works as expected. Where possible additional tests should
+ be added to the CI system as a follow up task. For example, for a
+ platform-dependent patch where the said platform is not available in the CI
+ system's board farm.
+
+- 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 ``integration`` 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
+ :ref:`maintainers` will request your help to solve the issue. They may
+ revert your patches and ask you to resubmit a reworked version of them or
+ they may ask you to provide a fix-up patch.
+
+Add CI Configurations
+=====================
+
+- TF-A uses Jenkins tool for Continuous Integration and testing activities.
+ Various CI Jobs are deployed which run tests on every patch before being
+ merged. So each of your patches go through a series of checks before they
+ get merged on to the master branch. Kindly ensure, that everytime you add
+ new files under your platform, they are covered under the following two sections:
+
+Coverity Scan
+-------------
+
+- ``Coverity Scan analysis`` is one of the tests we perform on our source code
+ at regular intervals. We maintain a build script ``tf-cov-make`` which contains the
+ build configurations of various platforms in order to cover the entire source
+ code being analysed by Coverity.
+
+- When you submit your patches for review containing new source files, please
+ ensure to include them for the ``Coverity Scan analysis`` by adding the
+ respective build configurations in the ``tf-cov-make`` build script.
+
+- In this section you find the details on how to append your new build
+ configurations for Coverity scan analysis illustrated with examples:
+
+#. We maintain a separate repository named `tf-a-ci-scripts repository`_
+ for placing all the test scripts which will be executed by the CI Jobs.
+
+#. In this repository, ``tf-cov-make`` script is located at
+ ``tf-a-ci-scripts/script/tf-coverity/tf-cov-make``
+
+#. Edit `tf-cov-make`_ script by appending all the possible build configurations with
+ the specific ``build-flags`` relevant to your platform, so that newly added
+ source files get built and analysed by Coverity.
+
+#. For better understanding follow the below specified examples listed in the
+ ``tf-cov-make`` script.
+
+.. code:: shell
+
+ Example 1:
+ #Intel
+ make PLAT=stratix10 $(common_flags) all
+ make PLAT=agilex $(common_flags) all
+
+- In the above example there are two different SoCs ``stratix`` and ``agilex``
+ under the Intel platform and the build configurations has been added suitably
+ to include most of their source files.
+
+.. code:: shell
+
+ Example 2:
+ #Hikey
+ make PLAT=hikey $(common_flags) ${TBB_OPTIONS} ENABLE_PMF=1 all
+ make PLAT=hikey960 $(common_flags) ${TBB_OPTIONS} all
+ make PLAT=poplar $(common_flags) all
+
+- In this case for ``Hikey`` boards additional ``build-flags`` has been included
+ along with the ``commom_flags`` to cover most of the files relevant to it.
+
+- Similar to this you can still find many other different build configurations
+ of various other platforms listed in the ``tf-cov-make`` script. Kindly refer
+ them and append your build configurations respectively.
+
+Test Build Configuration (``tf-l1-build-plat``)
+-----------------------------------------------
+
+- Coverity Scan analysis, runs on a daily basis and will not be triggered for
+ every individual trusted-firmware patch.
+
+- Considering this, we have other distinguished CI jobs which run a set of test
+ configurations on every patch, before they are being passed to ``Coverity scan analysis``.
+
+- ``tf-l1-build-plat`` is the test group, which holds the test configurations
+ to build all the platforms. So be kind enough to verify that your newly added
+ files are built as part of one of the existing platform configurations present
+ in ``tf-l1-build-plat`` test group.
+
+- In this section you find the details on how to add the appropriate files,
+ needed to build your newly introduced platform as part of ``tf-l1-build-plat``
+ test group, illustrated with an example:
+
+- Lets consider ``Hikey`` platform:
+ In the `tf-a-ci-scripts repository`_ we need to add a build configuration file ``hikey-default``
+ under tf_config folder, ``tf_config/hikey-default`` listing all the build parameters
+ relevant to it.
+
+.. code:: shell
+
+ #Hikey Build Parameters
+ CROSS_COMPILE=aarch64-none-elf-
+ PLAT=hikey
+
+- Further a test-configuration file ``hikey-default:nil`` need to be added under the
+ test group, ``tf-l1-build-plat`` located at ``tf-a-ci-scripts/group/tf-l1-build-plat``,
+ to allow the platform to be built as part of this group.
+
+.. code:: shell
+
+ #
+ # Copyright (c) 2019-2022 Arm Limited. All rights reserved.
+ #
+ # SPDX-License-Identifier: BSD-3-Clause
+ #
+
+- As illustrated above, you need to add the similar files supporting your platform.
+
+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 <tf-binaries-readme_>`_ 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/<vendor>`` directory) may rely on
+ binary components. Generic code must always be fully open-source.
+
+--------------
+
+*Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.*
+
+.. _developer.trustedfirmware.org: https://developer.trustedfirmware.org
+.. _review.trustedfirmware.org: https://review.trustedfirmware.org
+.. _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
+.. _TF-A Tests: https://trustedfirmware-a-tests.readthedocs.io
+.. _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
+.. _TF-A mailing list: https://lists.trustedfirmware.org/mailman3/lists/tf-a.lists.trustedfirmware.org/
+.. _tf-a-ci-scripts repository: https://git.trustedfirmware.org/ci/tf-a-ci-scripts.git/
+.. _tf-cov-make: https://git.trustedfirmware.org/ci/tf-a-ci-scripts.git/tree/script/tf-coverity/tf-cov-make
diff --git a/docs/process/faq.rst b/docs/process/faq.rst
new file mode 100644
index 0000000..daab198
--- /dev/null
+++ b/docs/process/faq.rst
@@ -0,0 +1,80 @@
+Frequently-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`_.
+
+--------------
+
+*Copyright (c) 2019-2020, 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/
diff --git a/docs/process/index.rst b/docs/process/index.rst
new file mode 100644
index 0000000..7914a4e
--- /dev/null
+++ b/docs/process/index.rst
@@ -0,0 +1,16 @@
+Processes & Policies
+====================
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents
+
+ security
+ platform-ports-policy
+ commit-style
+ coding-style
+ coding-guidelines
+ contributing
+ code-review-guidelines
+ faq
+ security-hardening
diff --git a/docs/process/platform-ports-policy.rst b/docs/process/platform-ports-policy.rst
new file mode 100644
index 0000000..7983749
--- /dev/null
+++ b/docs/process/platform-ports-policy.rst
@@ -0,0 +1,51 @@
+Platform Ports Policy
+=====================
+
+This document clarifies a couple of policy points around platform ports
+management.
+
+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.
+
+Platform deprecation policy
+---------------------------
+
+If a platform is no longer maintained, it is best to deprecate it to keep the
+projects' source tree clean and healthy. Deprecation can be a 1-stage or 2-stage
+process (up to the platform maintainers).
+
+ - *2-stage*: The platform's source code can be kept in the repository for a
+ cooling off period before deleting it (typically 2 release cycles). In this
+ case, we keep track ot the *Deprecated* version separately from the *Deleted*
+ version.
+
+ - *1-stage*: The platform's source code can be deleted straight away. In this
+ case, both versions are the same.
+
+The :ref:`Platform Ports` page provides a list of all deprecated/deleted
+platform ports (or soon to be) to this day.
+
+--------------
+
+*Copyright (c) 2018-2022, Arm Limited and Contributors. All rights reserved.*
+
+.. _TF-A public mailing list: https://lists.trustedfirmware.org/mailman3/lists/tf-a.lists.trustedfirmware.org/
diff --git a/docs/process/security-hardening.rst b/docs/process/security-hardening.rst
new file mode 100644
index 0000000..507046f
--- /dev/null
+++ b/docs/process/security-hardening.rst
@@ -0,0 +1,175 @@
+Secure Development Guidelines
+=============================
+
+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.
+
+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.
+
+Preventing Secure-world timing information leakage via PMU counters
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The Secure world needs to implement some defenses to prevent the Non-secure
+world from making it leak timing information. In general, higher privilege
+levels must defend from those below when the PMU is treated as an attack
+vector.
+
+Refer to the :ref:`Performance Monitoring Unit` guide for detailed information
+on the PMU registers.
+
+Timing leakage attacks from the Non-secure world
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Since the Non-secure world has access to the ``PMCR`` register, it can
+configure the PMU to increment counters at any exception level and in both
+Secure and Non-secure state. Thus, it attempts to leak timing information from
+the Secure world.
+
+Shown below is an example of such a configuration:
+
+- ``PMEVTYPER0_EL0`` and ``PMCCFILTR_EL0``:
+
+ - Set ``P`` to ``0``.
+ - Set ``NSK`` to ``1``.
+ - Set ``M`` to ``0``.
+ - Set ``NSH`` to ``0``.
+ - Set ``SH`` to ``1``.
+
+- ``PMCNTENSET_EL0``:
+
+ - Set ``P[0]`` to ``1``.
+ - Set ``C`` to ``1``.
+
+- ``PMCR_EL0``:
+
+ - Set ``DP`` to ``0``.
+ - Set ``E`` to ``1``.
+
+This configuration instructs ``PMEVCNTR0_EL0`` and ``PMCCNTR_EL0`` to increment
+at Secure EL1, Secure EL2 (if implemented) and EL3.
+
+Since the Non-secure world has fine-grained control over where (at which
+exception levels) it instructs counters to increment, obtaining event counts
+would allow it to carry out side-channel timing attacks against the Secure
+world. Examples include Spectre, Meltdown, as well as extracting secrets from
+cryptographic algorithms with data-dependent variations in their execution
+time.
+
+Secure world mitigation strategies
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``MDCR_EL3`` register allows EL3 to configure the PMU (among other things).
+The `Arm ARM`_ details all of the bit fields in this register, but for the PMU
+there are two bits which determine the permissions of the counters:
+
+- ``SPME`` for the programmable counters.
+- ``SCCD`` for the cycle counter.
+
+Depending on the implemented features, the Secure world can prohibit counting
+in AArch64 state via the following:
+
+- ARMv8.2-Debug not implemented:
+
+ - Prohibit general event counters and the cycle counter:
+ ``MDCR_EL3.SPME == 0 && PMCR_EL0.DP == 1 && !ExternalSecureNoninvasiveDebugEnabled()``.
+
+ - ``MDCR_EL3.SPME`` resets to ``0``, so by default general events should
+ not be counted in the Secure world.
+ - The ``PMCR_EL0.DP`` bit therefore needs to be set to ``1`` when EL3 is
+ entered and ``PMCR_EL0`` needs to be saved and restored in EL3.
+ - ``ExternalSecureNoninvasiveDebugEnabled()`` is an authentication
+ interface which is implementation-defined unless ARMv8.4-Debug is
+ implemented. The `Arm ARM`_ has detailed information on this topic.
+
+ - The only other way is to disable the ``PMCR_EL0.E`` bit upon entering
+ EL3, which disables counting altogether.
+
+- ARMv8.2-Debug implemented:
+
+ - Prohibit general event counters: ``MDCR_EL3.SPME == 0``.
+ - Prohibit cycle counter: ``MDCR_EL3.SPME == 0 && PMCR_EL0.DP == 1``.
+ ``PMCR_EL0`` therefore needs to be saved and restored in EL3.
+
+- ARMv8.5-PMU implemented:
+
+ - Prohibit general event counters: as in ARMv8.2-Debug.
+ - Prohibit cycle counter: ``MDCR_EL3.SCCD == 1``
+
+In Aarch32 execution state the ``MDCR_EL3`` alias is the ``SDCR`` register,
+which has some of the bit fields of ``MDCR_EL3``, most importantly the ``SPME``
+and ``SCCD`` bits.
+
+Build options
+-------------
+
+Several build options can be used to check for security issues. Refer to the
+:ref:`Build Options` for detailed information on these.
+
+- 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-format-attribute``, ``Wmissing-prototypes``,
+ ``Wold-style-definition`` and ``Wunused-const-variable``.
+
+ - W=2
+
+ Adds ``Waggregate-return``, ``Wcast-align``, ``Wnested-externs``,
+ ``Wshadow``, ``Wlogical-op``.
+
+ - W=3
+
+ Adds ``Wbad-function-cast``, ``Wcast-qual``, ``Wconversion``, ``Wpacked``,
+ ``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.
+
+.. rubric:: References
+
+- `Arm ARM`_
+
+--------------
+
+*Copyright (c) 2019-2020, Arm Limited. All rights reserved.*
+
+.. _Arm ARM: https://developer.arm.com/docs/ddi0487/latest
diff --git a/docs/process/security.rst b/docs/process/security.rst
new file mode 100644
index 0000000..e15783b
--- /dev/null
+++ b/docs/process/security.rst
@@ -0,0 +1,89 @@
+Security 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.
+
+.. warning::
+ If you think you have found a security vulnerability, please **do not**
+ report it in the `issue tracker`_ or on the `mailing list`_. Instead, please
+ follow the `TrustedFirmware.org security incident process`_.
+
+One of the goals of this process is to ensure providers of products that use
+TF-A have a chance to consider the implications of the vulnerability and its
+remedy before it is made public. As such, please follow the disclosure plan
+outlined in the process. We do our best to respond and fix any issues quickly.
+
+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/
+.. _mailing list: https://lists.trustedfirmware.org/mailman3/lists/tf-a.lists.trustedfirmware.org/
+
+.. |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)`
+
+.. _TrustedFirmware.org security incident process: https://developer.trustedfirmware.org/w/collaboration/security_center/
+
+--------------
+
+*Copyright (c) 2019-2022, Arm Limited. All rights reserved.*
diff --git a/docs/requirements.in b/docs/requirements.in
new file mode 100644
index 0000000..5d771e5
--- /dev/null
+++ b/docs/requirements.in
@@ -0,0 +1,5 @@
+myst-parser==0.15.2
+pip-tools==6.4.0
+sphinx==4.2.0
+sphinx-rtd-theme==1.0.0
+sphinxcontrib-plantuml==0.22
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 0000000..03b1189
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1,91 @@
+#
+# This file is autogenerated by pip-compile with python 3.8
+# To update, run:
+#
+# pip-compile
+#
+alabaster==0.7.12
+ # via sphinx
+attrs==21.2.0
+ # via markdown-it-py
+babel==2.9.1
+ # via sphinx
+certifi==2021.5.30
+ # via requests
+charset-normalizer==2.0.4
+ # via requests
+click==8.0.1
+ # via pip-tools
+docutils==0.16
+ # via
+ # myst-parser
+ # sphinx
+ # sphinx-rtd-theme
+idna==3.2
+ # via requests
+imagesize==1.2.0
+ # via sphinx
+jinja2==3.0.1
+ # via
+ # myst-parser
+ # sphinx
+markdown-it-py==1.1.0
+ # via
+ # mdit-py-plugins
+ # myst-parser
+markupsafe==2.0.1
+ # via jinja2
+mdit-py-plugins==0.2.8
+ # via myst-parser
+myst-parser==0.15.2
+ # via -r requirements.in
+packaging==21.0
+ # via sphinx
+pep517==0.11.0
+ # via pip-tools
+pip-tools==6.4.0
+ # via -r requirements.in
+pygments==2.10.0
+ # via sphinx
+pyparsing==2.4.7
+ # via packaging
+pytz==2021.1
+ # via babel
+pyyaml==6.0
+ # via myst-parser
+requests==2.26.0
+ # via sphinx
+snowballstemmer==2.1.0
+ # via sphinx
+sphinx==4.2.0
+ # via
+ # -r requirements.in
+ # myst-parser
+ # sphinx-rtd-theme
+ # sphinxcontrib-plantuml
+sphinx-rtd-theme==1.0.0
+ # via -r requirements.in
+sphinxcontrib-applehelp==1.0.2
+ # via sphinx
+sphinxcontrib-devhelp==1.0.2
+ # via sphinx
+sphinxcontrib-htmlhelp==2.0.0
+ # via sphinx
+sphinxcontrib-jsmath==1.0.1
+ # via sphinx
+sphinxcontrib-plantuml==0.22
+ # via -r requirements.in
+sphinxcontrib-qthelp==1.0.3
+ # via sphinx
+sphinxcontrib-serializinghtml==1.1.5
+ # via sphinx
+tomli==1.2.1
+ # via pep517
+urllib3==1.26.6
+ # via requests
+wheel==0.37.0
+ # via pip-tools
+
+# The following packages are considered to be unsafe in a requirements file:
+# pip
+# setuptools
diff --git a/docs/resources/TrustedFirmware-Logo_standard-white.png b/docs/resources/TrustedFirmware-Logo_standard-white.png
new file mode 100644
index 0000000..e7bff71
--- /dev/null
+++ b/docs/resources/TrustedFirmware-Logo_standard-white.png
Binary files differ
diff --git a/docs/resources/diagrams/FIP_in_a_GPT_image.png b/docs/resources/diagrams/FIP_in_a_GPT_image.png
new file mode 100644
index 0000000..4bafed9
--- /dev/null
+++ b/docs/resources/diagrams/FIP_in_a_GPT_image.png
Binary files differ
diff --git a/docs/resources/diagrams/MMU-600.png b/docs/resources/diagrams/MMU-600.png
new file mode 100644
index 0000000..9cbc243
--- /dev/null
+++ b/docs/resources/diagrams/MMU-600.png
Binary files differ
diff --git a/docs/resources/diagrams/Makefile b/docs/resources/diagrams/Makefile
new file mode 100644
index 0000000..c951754
--- /dev/null
+++ b/docs/resources/diagrams/Makefile
@@ -0,0 +1,101 @@
+#
+# Copyright (c) 2015-2022, 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 =
+
+RMM_DIA = rmm_cold_boot_generic.dia
+RMM_PNG = rmm_cold_boot_generic.png
+
+rmm_cold_boot_generic_layers = "background"
+rmm_cold_boot_generic_opts =
+
+RMM_EL3_MANIFEST_DIA = rmm_el3_manifest_struct.dia
+RMM_EL3_MANIFEST_PNG = rmm_el3_manifest_struct.png
+
+rmm_el3_manifest_struct_layers = "Background"
+rmm_el3_manifest_struct_opts =
+
+PSA_FWU_DIA = PSA-FWU.dia
+PSA_FWU_PNG = PSA-FWU.png
+
+FWU-update_struct_layers = "background"
+FWU-update_struct_opts =
+
+all:$(RESET_PNGS) $(INT_PNGS) $(XLAT_PNG) $(RMM_PNG) $(RMM_EL3_MANIFEST_PNG) $(PSA_FWU_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
+
+$(RMM_PNG):$(RMM_DIA)
+ $(call generate_image,$($(patsubst %.png,%_layers,$@)),$@,png,$($(patsubst %.png,%_opts,$@)),$<)
+
+$(RMM_EL3_MANIFEST_PNG):$(RMM_EL3_MANIFEST_DIA)
+ $(call generate_image,$($(patsubst %.png,%_layers,$@)),$@,png,$($(patsubst %.png,%_opts,$@)),$<)
+
+$(PSA_FWU_PNG):$(PSA_FWU_DIA)
+ $(call generate_image,$($(patsubst %.png,%_layers,$@)),$@,png,$($(patsubst %.png,%_opts,$@)),$<)
diff --git a/docs/resources/diagrams/PSA-FWU.dia b/docs/resources/diagrams/PSA-FWU.dia
new file mode 100644
index 0000000..aac5276
--- /dev/null
+++ b/docs/resources/diagrams/PSA-FWU.dia
Binary files differ
diff --git a/docs/resources/diagrams/PSA-FWU.png b/docs/resources/diagrams/PSA-FWU.png
new file mode 100644
index 0000000..d58ba86
--- /dev/null
+++ b/docs/resources/diagrams/PSA-FWU.png
Binary files differ
diff --git a/docs/resources/diagrams/arm-cca-software-arch.png b/docs/resources/diagrams/arm-cca-software-arch.png
new file mode 100755
index 0000000..979e083
--- /dev/null
+++ b/docs/resources/diagrams/arm-cca-software-arch.png
Binary files differ
diff --git a/docs/resources/diagrams/cmake_framework_structure.png b/docs/resources/diagrams/cmake_framework_structure.png
new file mode 100644
index 0000000..6006f1c
--- /dev/null
+++ b/docs/resources/diagrams/cmake_framework_structure.png
Binary files differ
diff --git a/docs/resources/diagrams/cmake_framework_workflow.png b/docs/resources/diagrams/cmake_framework_workflow.png
new file mode 100644
index 0000000..7311529
--- /dev/null
+++ b/docs/resources/diagrams/cmake_framework_workflow.png
Binary files differ
diff --git a/docs/resources/diagrams/context_management_abs.png b/docs/resources/diagrams/context_management_abs.png
new file mode 100644
index 0000000..717ecec
--- /dev/null
+++ b/docs/resources/diagrams/context_management_abs.png
Binary files differ
diff --git a/docs/resources/diagrams/context_mgmt_existing.png b/docs/resources/diagrams/context_mgmt_existing.png
new file mode 100644
index 0000000..5170960
--- /dev/null
+++ b/docs/resources/diagrams/context_mgmt_existing.png
Binary files differ
diff --git a/docs/resources/diagrams/context_mgmt_proposed.png b/docs/resources/diagrams/context_mgmt_proposed.png
new file mode 100644
index 0000000..41ae92f
--- /dev/null
+++ b/docs/resources/diagrams/context_mgmt_proposed.png
Binary files differ
diff --git a/docs/resources/diagrams/default_reset_code.png b/docs/resources/diagrams/default_reset_code.png
new file mode 100644
index 0000000..d8675e4
--- /dev/null
+++ b/docs/resources/diagrams/default_reset_code.png
Binary files differ
diff --git a/docs/resources/diagrams/draw.io/ehf.svg b/docs/resources/diagrams/draw.io/ehf.svg
new file mode 100644
index 0000000..c98090f
--- /dev/null
+++ b/docs/resources/diagrams/draw.io/ehf.svg
@@ -0,0 +1,2 @@
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" style="background-color: rgb(255, 255, 255);" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1002px" height="512px" viewBox="-0.5 -0.5 1002 512" content="&lt;mxfile userAgent=&quot;Mozilla/5.0 (X11; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0&quot; version=&quot;9.4.6&quot; editor=&quot;www.draw.io&quot; type=&quot;device&quot;&gt;&lt;diagram id=&quot;5e4d6047-f7e8-a748-3faa-493b1a8db8b3&quot; name=&quot;Page-1&quot;&gt;7Vxbc9o4FP41PMaj++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=&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><rect x="1" y="1" width="1000" height="510" fill="none" stroke="#000000" stroke-width="2" pointer-events="none"/><rect x="121.02" y="161" width="100" height="100" fill="#d4e1f5" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(122.5,189.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="95" height="41" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 95px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Interrupt Management Framework</div></div></foreignObject><text x="48" y="27" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Interrupt Management Framework</text></switch></g><path d="M 321 161.07 L 321 86 L 412.76 86" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 418.76 86 L 410.76 90 L 412.76 86 L 410.76 82 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 321.07 161 L 371.09 211 L 321.07 261 L 271.06 211 Z" fill="#d4e1f5" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(297.5,196.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="45" height="27" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 46px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><div>Interrupt <br /></div><div>Type</div></div></div></foreignObject><text x="23" y="20" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><path d="M 221.02 211 L 262.83 211" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 268.83 211 L 260.83 215 L 262.83 211 L 260.83 207 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 21 211 L 112.76 211" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 118.76 211 L 110.76 215 L 112.76 211 L 110.76 207 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(50.5,195.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="41" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;background-color:#ffffff;">Interrupt</div></div></foreignObject><text x="21" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Interrupt</text></switch></g><rect x="421.1" y="61" width="75.02" height="50" fill="#dae8fc" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(449.5,79.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="17" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 18px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">NS</div></div></foreignObject><text x="9" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">NS</text></switch></g><rect x="421.1" y="186" width="75.02" height="50" fill="#dae8fc" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(440.5,204.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="34" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 35px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">S-EL1</div></div></foreignObject><text x="17" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">S-EL1</text></switch></g><path d="M 371.09 211 L 412.86 211" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 418.86 211 L 410.86 215 L 412.86 211 L 410.86 207 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="421.1" y="311" width="75.02" height="50" fill="#fff2cc" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(446.5,329.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="22" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 23px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">EL3</div></div></foreignObject><text x="11" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">EL3</text></switch></g><path d="M 321 260.93 L 321 336 L 412.76 336" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 418.76 336 L 410.76 340 L 412.76 336 L 410.76 332 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="542.38" y="61" width="100.02" height="175" fill="#ffffff" stroke="#000000" stroke-width="2" stroke-dasharray="6 6" pointer-events="none"/><g transform="translate(553.5,141.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="76" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 77px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">SPD handlers</div></div></foreignObject><text x="38" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">SPD handlers</text></switch></g><path d="M 496.12 86 L 534.14 86" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 540.14 86 L 532.14 90 L 534.14 86 L 532.14 82 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 496.12 211 L 534.14 211" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 540.14 211 L 532.14 215 L 534.14 211 L 532.14 207 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="542.38" y="348.5" width="100.02" height="112.5" fill="#fff2cc" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(543.5,383.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="95" height="41" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 95px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Exception Handling Framework</div></div></foreignObject><text x="48" y="27" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Exception Handling Framework</text></switch></g><path d="M 496.12 336 L 521 336 L 521 405 L 533.76 405" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 539.76 405 L 531.76 409 L 533.76 405 L 531.76 401 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 592 320.49 L 592 332 L 592 329 L 592 340.26" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 592 314.49 L 596 322.49 L 592 320.49 L 588 322.49 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 592 346.26 L 588 338.26 L 592 340.26 L 596 338.26 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="542.38" y="261" width="100.02" height="51.25" fill="#d5e8d4" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(565.5,279.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="51" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 52px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">GIC PMR</div></div></foreignObject><text x="26" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">GIC PMR</text></switch></g><rect x="722.42" y="411" width="100.02" height="50" fill="#fff2cc" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(758.5,429.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="25" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 26px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">RAS</div></div></foreignObject><text x="13" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">RAS</text></switch></g><rect x="722.42" y="361" width="100.02" height="50" fill="#fff2cc" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(758.5,379.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="26" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 27px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><div>SPM</div></div></div></foreignObject><text x="13" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><rect x="722.42" y="311" width="100.02" height="50" fill="#fff2cc" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(736.5,329.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="69" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 70px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">SDEI Critical</div></div></foreignObject><text x="35" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">SDEI Critical</text></switch></g><rect x="722.42" y="261" width="100.02" height="50" fill="#fff2cc" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(735.5,279.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="71" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 72px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">SDEI Normal</div></div></foreignObject><text x="36" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">SDEI Normal</text></switch></g><rect x="722.42" y="61" width="100.02" height="200" fill="#f5f5f5" stroke="#666666" stroke-width="2" pointer-events="none"/><g transform="translate(737.5,154.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="67" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 68px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">NS priorities</div></div></foreignObject><text x="34" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">NS priorities</text></switch></g><path d="M 684.91 354.75 L 685 336 L 714.19 336" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 720.19 336 L 712.19 340 L 714.19 336 L 712.19 332 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 684.91 367.25 L 685 436 L 713.76 436" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 719.76 436 L 711.76 440 L 713.76 436 L 711.76 432 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><ellipse cx="685" cy="361" rx="6.25" ry="6.25" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="none"/><path d="M 642.4 405 L 662 405 L 662 361 L 679 361" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 691 361 L 709 361 L 709 386 L 713.76 386" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 719.76 386 L 711.76 390 L 713.76 386 L 711.76 382 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(826.5,60.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="27" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 28px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">0xFF</div></div></foreignObject><text x="14" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">0xFF</text></switch></g><g transform="translate(826.5,449.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="20" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 21px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><div>0x0</div></div></div></foreignObject><text x="10" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><g transform="translate(642.5,312.5)rotate(-90,24,13.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="48" height="27" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 48px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><div>Interrupt Priority</div></div></div></foreignObject><text x="24" y="20" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><path d="M 864.28 347.38 L 844.11 293.71" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 842 288.09 L 848.56 294.17 L 844.11 293.71 L 841.07 296.99 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 866 361.17 L 846.99 341.87" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 842.78 337.59 L 851.24 340.49 L 846.99 341.87 L 845.54 346.1 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 866 361.17 L 847.03 380.17" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 842.79 384.42 L 845.61 375.93 L 847.03 380.17 L 851.27 381.58 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 865.14 374.1 L 844.18 428.32" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 842.02 433.91 L 841.17 425.01 L 844.18 428.32 L 848.63 427.89 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 387.86 436 L 346.08 436" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 393.86 436 L 385.86 440 L 387.86 436 L 385.86 432 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="396.09" y="423.5" width="100.02" height="25" fill="#ffb570" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(419.5,429.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="52" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 53px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">EHF APIs</div></div></foreignObject><text x="26" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">EHF APIs</text></switch></g><path d="M 496.12 435.5 L 534.1 435.77" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 540.1 435.82 L 532.07 439.76 L 534.1 435.77 L 532.13 431.76 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(58.5,422.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="286" height="27" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 286px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Non-interrupt exceptions use EHF APIs to program GIC PMR to arbitrate priority levels</div></div></foreignObject><text x="143" y="20" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Non-interrupt exceptions use EHF APIs to program GIC PMR to arbitrate priority levels</text></switch></g><path d="M 940.24 461 L 940.24 69.24" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 940.24 63.24 L 944.24 71.24 L 940.24 69.24 L 936.24 71.24 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(871.5,254.5)rotate(-90,52,6)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="104" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 105px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Decreasing Priority</div></div></foreignObject><text x="52" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Decreasing Priority</text></switch></g><g transform="translate(820.5,348.5)rotate(-90,57.5,6)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="115" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 116px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Secure Priority levels</div></div></foreignObject><text x="58" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Secure Priority levels</text></switch></g><path d="M 685 355 L 685 286 L 713.76 286" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 719.76 286 L 711.76 290 L 713.76 286 L 711.76 282 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/></svg> \ No newline at end of file
diff --git a/docs/resources/diagrams/draw.io/ehf.xml b/docs/resources/diagrams/draw.io/ehf.xml
new file mode 100644
index 0000000..db1f91d
--- /dev/null
+++ b/docs/resources/diagrams/draw.io/ehf.xml
@@ -0,0 +1 @@
+<mxfile userAgent="Mozilla/5.0 (X11; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0" version="9.4.6" editor="www.draw.io" type="device"><diagram id="5e4d6047-f7e8-a748-3faa-493b1a8db8b3" name="Page-1">7Vxbc9o4FP41PMaj++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=</diagram></mxfile> \ No newline at end of file
diff --git a/docs/resources/diagrams/draw.io/ras.svg b/docs/resources/diagrams/draw.io/ras.svg
new file mode 100644
index 0000000..ff58198
--- /dev/null
+++ b/docs/resources/diagrams/draw.io/ras.svg
@@ -0,0 +1,2 @@
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" style="background-color: rgb(255, 255, 255);" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1050px" height="392px" viewBox="-0.5 -0.5 1050 392" content="&lt;mxfile userAgent=&quot;Mozilla/5.0 (X11; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0&quot; version=&quot;9.4.6&quot; editor=&quot;www.draw.io&quot; type=&quot;device&quot;&gt;&lt;diagram id=&quot;f2d74f7d-2b47-d0f0-3260-3a0b726db48c&quot; name=&quot;Page-1&quot;&gt;5VtLc6M4EP41rto9rAs9eB2TjD0zVbtVqclhd05TipFtNhhRQk7i/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=&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><rect x="408" y="30" width="240" height="360" fill="none" stroke="#000000" stroke-width="2" stroke-dasharray="6 6" pointer-events="none"/><path d="M 208 90 L 439.76 90" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 445.76 90 L 437.76 94 L 439.76 90 L 437.76 86 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 79.76 90 L 8 90" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 85.76 90 L 77.76 94 L 79.76 90 L 77.76 86 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(47.5,84.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="1" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;background-color:#ffffff;"><div><br /></div></div></div></foreignObject><text x="0" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">&lt;div&gt;&lt;br&gt;&lt;/div&gt;</text></switch></g><rect x="88" y="70" width="120" height="40" fill="#d4e1f5" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(98.5,83.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="98" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 99px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">plat_ea_handler()</div></div></foreignObject><text x="49" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">plat_ea_handler()</text></switch></g><path d="M 608 90 L 669.76 90" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 675.76 90 L 667.76 94 L 669.76 90 L 667.76 86 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="448" y="70" width="160" height="40" fill="#d4e1f5" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(479.5,83.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="95" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 96px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">ras_ea_handler()</div></div></foreignObject><text x="48" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">ras_ea_handler()</text></switch></g><path d="M 608 329.5 L 669.76 329.5" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 675.76 329.5 L 667.76 333.5 L 669.76 329.5 L 667.76 325.5 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="448" y="309.5" width="160" height="40" fill="#ffe599" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(464.5,322.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="126" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 127px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">ras_interrupt_handler()</div></div></foreignObject><text x="63" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">ras_interrupt_handler()</text></switch></g><path d="M 79.64 326 L 48 326 L 7.88 326.25" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 85.64 326 L 77.64 330 L 79.64 326 L 77.64 322 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="87.88" y="270" width="100.02" height="112.5" fill="#ffe599" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(89.5,304.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="95" height="41" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 95px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Exception Handling Framework</div></div></foreignObject><text x="48" y="27" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Exception Handling Framework</text></switch></g><ellipse cx="227" cy="284" rx="6.25" ry="6.25" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="none"/><path d="M 187.9 326 L 208 326 L 208 284 L 221 284" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 368.95 362 L 388 362 L 388 330 L 439.76 330" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 445.76 330 L 437.76 334 L 439.76 330 L 437.76 326 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="268.92" y="338.5" width="100.02" height="50" fill="#ffe599" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(270.5,342.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="95" height="41" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 95px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><div>RAS</div><div>priority level handler<br /></div></div></div></foreignObject><text x="48" y="27" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><path d="M 228 290 L 228 300 L 228 364 L 260.76 364" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 266.76 364 L 258.76 368 L 260.76 364 L 258.76 360 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 758 198.24 L 758 221.76" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 4" pointer-events="none"/><path d="M 758 192.24 L 762 200.24 L 758 198.24 L 754 200.24 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 758 227.76 L 754 219.76 L 758 221.76 L 762 219.76 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 758 150 L 758 118.24" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 758 112.24 L 762 120.24 L 758 118.24 L 754 120.24 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="678" y="150" width="160" height="40" fill="#ffe599" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(708.5,163.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="98" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 99px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">RAS error records</div></div></foreignObject><text x="49" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">RAS error records</text></switch></g><path d="M 758 270 L 758 290 L 758 301.76" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 758 307.76 L 754 299.76 L 758 301.76 L 762 299.76 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="678" y="230" width="160" height="40" fill="#ffe599" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(702.5,243.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="110" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 111px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">RAS interrupts array</div></div></foreignObject><text x="55" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">RAS interrupts array</text></switch></g><g transform="translate(485.5,3.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="85" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 86px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">RAS framework</div></div></foreignObject><text x="43" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">RAS framework</text></switch></g><path d="M 838 90 L 879.76 90" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 885.76 90 L 877.76 94 L 879.76 90 L 877.76 86 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="678" y="70" width="160" height="40" fill="#d4e1f5" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(710.5,83.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="93" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 94px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><i>Iterate and probe</i></div></div></foreignObject><text x="47" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">&lt;i&gt;Iterate and probe&lt;/i&gt;</text></switch></g><rect x="888" y="70" width="160" height="40" fill="none" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(931.5,83.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="72" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 73px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Error handler</div></div></foreignObject><text x="36" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Error handler</text></switch></g><path d="M 838 329.5 L 879.76 329.5" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 885.76 329.5 L 877.76 333.5 L 879.76 329.5 L 877.76 325.5 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="678" y="309.5" width="160" height="40" fill="#ffe599" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(708.5,322.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="97" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 98px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><i>Bisect and lookup</i></div></div></foreignObject><text x="49" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">&lt;i&gt;Bisect and lookup&lt;/i&gt;</text></switch></g><rect x="888" y="309.5" width="160" height="40" fill="none" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(931.5,322.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="72" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 73px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Error handler</div></div></foreignObject><text x="36" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Error handler</text></switch></g><path d="M 608 170 L 669.76 170" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 675.76 170 L 667.76 174 L 669.76 170 L 667.76 166 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="448" y="150" width="160" height="40" fill="#d4e1f5" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(492.5,163.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="69" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 70px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">SER helpers</div></div></foreignObject><text x="35" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">SER helpers</text></switch></g><rect x="268.92" y="288" width="100.02" height="50" fill="none" stroke="#000000" stroke-width="2" stroke-dasharray="6 6" pointer-events="none"/><rect x="268.92" y="238" width="100.02" height="50" fill="none" stroke="#000000" stroke-width="2" stroke-dasharray="6 6" pointer-events="none"/><g transform="translate(24.5,56.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="46" height="27" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 46px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">External Abort</div></div></foreignObject><text x="23" y="20" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">External Abort</text></switch></g><g transform="translate(21.5,307.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="45" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 46px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><div>Interrupt</div></div></div></foreignObject><text x="23" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><g transform="translate(204.5,246.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="46" height="27" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 46px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Interrupt Priority</div></div></foreignObject><text x="23" y="20" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Interrupt Priority</text></switch></g><path d="M 138 110 L 138 150 L 138 261.76" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 138 267.76 L 134 259.76 L 138 261.76 L 142 259.76 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(140.5,176.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="38" height="27" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 38px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">EHF APIs</div></div></foreignObject><text x="19" y="20" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">EHF APIs</text></switch></g></svg> \ No newline at end of file
diff --git a/docs/resources/diagrams/draw.io/ras.xml b/docs/resources/diagrams/draw.io/ras.xml
new file mode 100644
index 0000000..ce6df3a
--- /dev/null
+++ b/docs/resources/diagrams/draw.io/ras.xml
@@ -0,0 +1 @@
+<mxfile userAgent="Mozilla/5.0 (X11; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0" version="9.4.6" editor="www.draw.io" type="device"><diagram id="f2d74f7d-2b47-d0f0-3260-3a0b726db48c" name="Page-1">5VtLc6M4EP41rto9rAs9eB2TjD0zVbtVqclhd05TipFtNhhRQk7i/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=</diagram></mxfile> \ No newline at end of file
diff --git a/docs/resources/diagrams/ff-a-lsp-at-el3.png b/docs/resources/diagrams/ff-a-lsp-at-el3.png
new file mode 100644
index 0000000..7cff34f
--- /dev/null
+++ b/docs/resources/diagrams/ff-a-lsp-at-el3.png
Binary files differ
diff --git a/docs/resources/diagrams/ff-a-spm-at-el3.png b/docs/resources/diagrams/ff-a-spm-at-el3.png
new file mode 100644
index 0000000..3b263b0
--- /dev/null
+++ b/docs/resources/diagrams/ff-a-spm-at-el3.png
Binary files differ
diff --git a/docs/resources/diagrams/ff-a-spm-sel2.png b/docs/resources/diagrams/ff-a-spm-sel2.png
new file mode 100644
index 0000000..605fd9b
--- /dev/null
+++ b/docs/resources/diagrams/ff-a-spm-sel2.png
Binary files differ
diff --git a/docs/resources/diagrams/ffa-ns-interrupt-handling-managed-exit.png b/docs/resources/diagrams/ffa-ns-interrupt-handling-managed-exit.png
new file mode 100644
index 0000000..0619cf2
--- /dev/null
+++ b/docs/resources/diagrams/ffa-ns-interrupt-handling-managed-exit.png
Binary files differ
diff --git a/docs/resources/diagrams/ffa-ns-interrupt-handling-sp-preemption.png b/docs/resources/diagrams/ffa-ns-interrupt-handling-sp-preemption.png
new file mode 100644
index 0000000..f110028
--- /dev/null
+++ b/docs/resources/diagrams/ffa-ns-interrupt-handling-sp-preemption.png
Binary files differ
diff --git a/docs/resources/diagrams/ffa-secure-interrupt-handling-nwd.png b/docs/resources/diagrams/ffa-secure-interrupt-handling-nwd.png
new file mode 100755
index 0000000..c318610
--- /dev/null
+++ b/docs/resources/diagrams/ffa-secure-interrupt-handling-nwd.png
Binary files differ
diff --git a/docs/resources/diagrams/ffa-secure-interrupt-handling-swd.png b/docs/resources/diagrams/ffa-secure-interrupt-handling-swd.png
new file mode 100755
index 0000000..b62000d
--- /dev/null
+++ b/docs/resources/diagrams/ffa-secure-interrupt-handling-swd.png
Binary files differ
diff --git a/docs/resources/diagrams/fwu_flow.png b/docs/resources/diagrams/fwu_flow.png
new file mode 100644
index 0000000..534095f
--- /dev/null
+++ b/docs/resources/diagrams/fwu_flow.png
Binary files differ
diff --git a/docs/resources/diagrams/fwu_states.png b/docs/resources/diagrams/fwu_states.png
new file mode 100644
index 0000000..fda4d8f
--- /dev/null
+++ b/docs/resources/diagrams/fwu_states.png
Binary files differ
diff --git a/docs/resources/diagrams/int_handling.dia b/docs/resources/diagrams/int_handling.dia
new file mode 100644
index 0000000..12aa186
--- /dev/null
+++ b/docs/resources/diagrams/int_handling.dia
Binary files differ
diff --git a/docs/resources/diagrams/non-sec-int-handling.png b/docs/resources/diagrams/non-sec-int-handling.png
new file mode 100644
index 0000000..64082c9
--- /dev/null
+++ b/docs/resources/diagrams/non-sec-int-handling.png
Binary files differ
diff --git a/docs/resources/diagrams/partition-package.png b/docs/resources/diagrams/partition-package.png
new file mode 100644
index 0000000..3367422
--- /dev/null
+++ b/docs/resources/diagrams/partition-package.png
Binary files differ
diff --git a/docs/resources/diagrams/plantuml/bl2-loading-sp.puml b/docs/resources/diagrams/plantuml/bl2-loading-sp.puml
new file mode 100644
index 0000000..3cf7c36
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/bl2-loading-sp.puml
@@ -0,0 +1,44 @@
+/'
+ ' Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ '
+ ' SPDX-License-Identifier: BSD-3-Clause
+ '/
+
+@startuml
+participant bl1
+participant FIP
+
+bl1 -> FIP : read(FW_CONFIG)
+create FW_CONFIG
+bl1 -> FW_CONFIG : load
+
+bl1 -> FIP : read(bl2)
+create bl2
+bl1 -> bl2 : load
+bl1 --> bl2 : hand off (FW_CONFIG)
+
+bl2 -> FW_CONFIG : read_node(SPKs)
+loop for each spkg subnode
+ bl2 -> FW_CONFIG : read(UUID)
+ bl2 -> FW_CONFIG : read(load_address)
+ bl2 -> FIP : read(spkg@UUID)
+ create SPKG
+ bl2 -> SPKG : load
+end loop
+
+bl2 -> FW_CONFIG : read_node(TOS_FW_CONFIG)
+create TOS_FW_CONFIG
+bl2 -> TOS_FW_CONFIG : load
+
+bl2 -> FIP : read(bl32/SPMC)
+create SPMC
+bl2 -> SPMC : load
+
+bl2 -> FIP : read(bl31)
+create bl31
+bl2 -> bl31 : load
+bl2 --> bl31 : hand off (TOS_FW_CONFIG)
+
+bl31 --> SPMC : hand off (TOS_FW_CONFIG)
+
+@enduml
diff --git a/docs/resources/diagrams/plantuml/el3_spm_dfd.puml b/docs/resources/diagrams/plantuml/el3_spm_dfd.puml
new file mode 100644
index 0000000..c716180
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/el3_spm_dfd.puml
@@ -0,0 +1,78 @@
+/'
+ ' Copyright (c) 2022, Arm Limited. All rights reserved.
+ '
+ ' SPDX-License-Identifier: BSD-3-Clause
+ '/
+
+/'
+TF-A EL3 SPMC Data Flow Diagram
+'/
+
+@startuml
+digraph tfa_el3_dfd {
+
+ # Allow arrows to end on cluster boundaries
+ compound=true
+ concentrate=false
+ newrank=true
+
+ # Default settings for edges and nodes
+ edge [minlen=2 color="#8c1b07"]
+ node [fillcolor="#ffb866" style=filled shape=box fixedsize=true width=1.6 height=0.7]
+
+ # Nodes outside of the trust boundary
+ nsec [label="NS Client"]
+ ddr [label="External memory (DDR)"]
+
+ {rank="same" smmu, spmd}
+ # Trust boundary cluster
+ subgraph cluster_trusted {
+ graph [style=dashed color="#f22430"]
+ concentrate=false
+
+ # HW IPs cluster
+ subgraph cluster_ip {
+ label ="Hardware IPs";
+ graph [style=filled color="#000000" fillcolor="#ffd29e"]
+
+ rank="same"
+ gic [label="GIC" width=1.2 height=0.5]
+ smmu [label="SMMU" width=1.2 height=0.5]
+ uart [label="UART" width=1.2 height=0.5]
+ pe [label="PE" width=1.2 height=0.5]
+ }
+
+ # TF-A cluster
+ subgraph cluster_tfa {
+ label ="EL3 monitor";
+ graph [style=filled color="#000000" fillcolor="#faf9cd"]
+ {rank="same" spmc, bl31}
+ {rank="same" spmd, lsp}
+ spmc [label="SPMC" fillcolor="#ddffb3"]
+ bl31 [label="BL31" fillcolor="#ddffb3"];
+ spmd [label="SPMD" fillcolor="#ddffb3"]
+ lsp[label="LSP1" fillcolor="#ddffb3"]
+ }
+ bl2 [label="BL2" width=1.2 height=0.5]
+ }
+
+ # Secure Partitions cluster
+ subgraph cluster_sp {
+ label ="Secure Partitions";
+ graph [style=filled color="#000000" fillcolor="#faf9cd"]
+
+ sp1 [label="SP1" fillcolor="#ddffb3"]
+ }
+
+ sp1 -> spmc [dir="both" label="DF1"]
+ lsp -> spmc [dir="both" label="DF4"]
+ spmc -> spmd [dir="both" label="DF2"]
+ spmd -> nsec [dir="both" label="DF3"]
+ spmc -> smmu [lhead=cluster_spmc label="DF5"]
+ bl2 -> spmc [lhead=cluster_spmc label="DF6"]
+ bl2 -> sp1 [lhead=cluster_spmc label="DF6"]
+ sp1 -> ddr [dir="both" label="DF7"]
+ spmc -> ddr [dir="both" label="DF7"]
+}
+
+@enduml
diff --git a/docs/resources/diagrams/plantuml/fconf_bl1_load_config.puml b/docs/resources/diagrams/plantuml/fconf_bl1_load_config.puml
new file mode 100644
index 0000000..e513ed4
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/fconf_bl1_load_config.puml
@@ -0,0 +1,78 @@
+@startuml
+
+box "BL1 common code"
+ participant bl1_main
+ participant bl_common
+end box
+
+box "arm platform code" #LightBlue
+ participant fvp_bl1_setup
+ participant arm_bl1_setup
+ participant arm_io_storage
+end box
+
+box "platform common code"
+ participant plat_bl1_common
+ participant fconf_dyn_cfg_getter
+ participant fconf
+end box
+
+bl1_main -> fvp_bl1_setup : bl1_platform_setup()
+fvp_bl1_setup -> arm_bl1_setup : arm_bl1_platform_setup()
+arm_bl1_setup -> arm_io_storage : plat_arm_io_setup()
+note over arm_io_storage : register and setup fip
+arm_bl1_setup -> fconf : set_fw_config_info(fw_config_base, max_size)
+note over fconf
+ set fw_config information
+ (address, size, image_id)
+ in global dtb_infos array.
+end note
+activate fconf
+ arm_bl1_setup -> fconf : fconf_load_config(FW_CONFIG_ID)
+ fconf -> fconf : FCONF_GET_PROPERTY(dyn_cfg, dtb, FW_CONFIG_ID)
+ fconf -> fconf_dyn_cfg_getter: dyn_cfg_dtb_info_getter(FW_CONFIG_ID)
+ fconf_dyn_cfg_getter -> fconf: fw_config_info
+ fconf -> bl_common : load_auth_image(FW_CONFIG_ID, &image_info)
+ activate bl_common
+ note over bl_common
+ load and auth image from fip
+ with info from plat_io_policy
+ end note
+ bl_common -> arm_io_storage
+ arm_io_storage -> fconf: FCONF_GET_PROPERTY(arm, arm_io_policies, FW_CONFIG_ID)
+ note over fconf: use statically defined policies in bl1
+ fconf <- bl_common : image_info
+ deactivate bl_common
+ note over fconf : get fw_config_dtb from image_info
+ arm_bl1_setup -> fconf: FCONF_GET_PROPERTY(dyn_cfg, dtb, FW_CONFIG_ID)
+ fconf -> fconf_dyn_cfg_getter: dyn_cfg_dtb_info_getter(FW_CONFIG_ID)
+ fconf_dyn_cfg_getter -> arm_bl1_setup: fw_config_info
+ arm_bl1_setup -> fconf_dyn_cfg_getter: populate_dtb_registry(uintptr_t dtb)
+ arm_bl1_setup -> fconf: fconf_load_config(TB_FW_CONFIG_ID)
+ fconf -> fconf : FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID)
+ fconf -> fconf_dyn_cfg_getter: dyn_cfg_dtb_info_getter(TB_FW_CONFIG_ID)
+ fconf_dyn_cfg_getter -> fconf: tb_fw_config_info
+ fconf -> bl_common : load_auth_image(TB_FW_CONFIG_ID, &image_info)
+ activate bl_common
+ note over bl_common
+ load and auth image from fip
+ with info from plat_io_policy
+ end note
+ bl_common -> arm_io_storage
+ arm_io_storage -> fconf: FCONF_GET_PROPERTY(arm, arm_io_policies, TB_FW_CONFIG_ID)
+ note over fconf: use statically defined policies in bl1
+ fconf <- bl_common : image_info
+ deactivate bl_common
+ note over fconf : get tb_fw_config_dtb from image_info
+ fconf -> arm_bl1_setup
+ arm_bl1_setup -> plat_bl1_common : bl1_plat_get_image_desc(BL2_IMAGE_ID)
+ arm_bl1_setup <- plat_bl1_common : BL2_IMAGE_DESC
+ note over arm_bl1_setup
+ set ep_info.args.arg0 of BL2_IMAGE_DESC
+ to FW_CONFIG base address
+ end note
+deactivate fconf
+
+== load & auth, prepare and jump to BL2 ==
+
+@enduml
diff --git a/docs/resources/diagrams/plantuml/fconf_bl2_populate.puml b/docs/resources/diagrams/plantuml/fconf_bl2_populate.puml
new file mode 100644
index 0000000..c536ee0
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/fconf_bl2_populate.puml
@@ -0,0 +1,49 @@
+@startuml
+
+box "BL2 common code"
+ participant bl2_entrypoint
+ participant bl2_main
+end box
+
+box "platform common code"
+ participant fconf
+ participant fconf_tbbr_getter
+participant fconf_dyn_cfg_getter
+end box
+
+box "arm platform code" #LightBlue
+ participant arm_bl2_setup
+ participant arm_io_storage
+ participant arm_fconf_io
+end box
+
+== bl2 setup ==
+bl2_entrypoint -> bl2_main : bl2_setup()
+bl2_main -> arm_bl2_setup : bl2_early_platform_setup2(\n\t arg0, arg1, arg2, arg3)
+note over arm_bl2_setup
+ arg0 = fw_config
+ arg1 = mem_layout
+end note
+arm_bl2_setup -> arm_bl2_setup : arm_bl2_early_platform_setup(\n\t fw_config, mem_layout)
+activate arm_bl2_setup
+ arm_bl2_setup -> fconf: fconf_populate("FW_CONFIG", fw_config)
+ activate fconf
+ fconf -> fconf_dyn_cfg_getter: populate_dtb_registry(uintptr_t dtb)
+ note over fconf_dyn_cfg_getter: read dtb_registry properties from dtb
+ fconf_dyn_cfg_getter -> arm_bl2_setup
+ arm_bl2_setup -> fconf: FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID)
+ fconf -> fconf_dyn_cfg_getter: dyn_cfg_dtb_info_getter(TB_FW_CONFIG_ID)
+ fconf_dyn_cfg_getter -> arm_bl2_setup: tb_fw_config_info
+ arm_bl2_setup -> fconf: fconf_populate("TB_FW_CONFIG", tb_fw_config)
+ fconf -> fconf_tbbr_getter: fconf_populate_tbbr_dyn_config(uintptr_t dtb)
+ note over fconf_tbbr_getter: read tbbr properties from dtb
+ fconf -> arm_fconf_io: fconf_populate_arm_io_policies(uintptr_t dtb)
+ note over arm_fconf_io: read arm io propeties from dtb
+ deactivate fconf
+ arm_bl2_setup -> arm_io_storage : plat_arm_io_setup()
+ note over arm_io_storage: use populated properties
+deactivate arm_bl2_setup
+
+== bl2 main ==
+
+@enduml
diff --git a/docs/resources/diagrams/plantuml/fip-secure-partitions.puml b/docs/resources/diagrams/plantuml/fip-secure-partitions.puml
new file mode 100644
index 0000000..9457e32
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/fip-secure-partitions.puml
@@ -0,0 +1,167 @@
+/'
+ ' Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ '
+ ' SPDX-License-Identifier: BSD-3-Clause
+ '/
+
+@startuml
+
+folder SP_vendor_1 {
+ artifact sp_binary_1
+ artifact sp_manifest_1 [
+ sp_manifest_1
+ ===
+ UUID = xxx
+ load_address = 0xaaa
+ owner = "Sip"
+ ...
+ ]
+}
+
+folder SP_vendor_2 {
+ artifact sp_binary_2
+ artifact sp_manifest_2 [
+ sp_manifest_2
+ ===
+ UUID = yyy
+ load_address = 0xbbb
+ owner = "Plat"
+ ]
+}
+
+artifact tb_fw_config.dts [
+ tb_fw_config.dts
+ ----
+ secure-partitions
+ ===
+ spkg_1 UUID
+ spkg_1 load_address
+ ---
+ spkg_2 UUID
+ spkg_2 load_address
+ ---
+ ...
+ ===
+ ...<rest of the nodes>
+]
+
+artifact config.json [
+ SP_LAYOUT.json
+ ===
+ path to sp_binary_1
+ path to sp_manifest_1
+ ---
+ path to sp_binary_2
+ path to sp_manifest_2
+ ---
+ ...
+]
+
+control sp_mk_generator
+
+artifact sp_gen [
+ sp_gen.mk
+ ===
+ FDT_SOURCE = ...
+ SPTOOL_ARGS = ...
+ FIP_ARGS = ...
+ CRT_ARGS = ...
+]
+
+control dtc
+control sptool
+
+artifact tb_fw_config.dtb
+
+artifact spkg_1 [
+ sp1.pkg
+ ===
+ <i>header</i>
+ ---
+ manifest
+ ---
+ binary
+]
+
+artifact spkg_2 [
+ sp2.pkg
+ ===
+ <i>header</i>
+ ---
+ manifest
+ ---
+ binary
+]
+
+artifact signed_tb_fw_config.dtb [
+ tb_fw_config.dtb (signed)
+]
+
+artifact signed_spkg_1 [
+ sp1.pkg (signed)
+ ===
+ <i>header</i>
+ ---
+ manifest
+ ---
+ binary
+ ---
+ <i>signature</I>
+]
+
+artifact signed_spkg_2 [
+ sp2.pkg (signed)
+ ===
+ <i>header</i>
+ ---
+ manifest
+ ---
+ binary
+ ---
+ <i>signature</I>
+]
+
+control crttool
+control fiptool
+
+artifact fip [
+ fip.bin
+ ===
+ tb_fw_config.dtb (signed)
+ ---
+ ...
+ ---
+ sp1.pkg (signed & SiP owned)
+ ---
+ sp2.pkg (signed & Platform owned)
+ ---
+ ...
+]
+
+config.json .up.> SP_vendor_1
+config.json .up.> SP_vendor_2
+config.json --> sp_mk_generator
+sp_mk_generator --> sp_gen
+sp_gen --> fiptool
+sp_gen --> cert_create
+sp_gen --> sptool
+
+sptool --> spkg_1
+sptool --> spkg_2
+
+spkg_1 --> cert_create
+spkg_2 --> cert_create
+cert_create --> signed_spkg_1
+cert_create --> signed_spkg_2
+
+tb_fw_config.dts --> dtc
+dtc --> tb_fw_config.dtb
+tb_fw_config.dtb --> cert_create
+cert_create --> signed_tb_fw_config.dtb
+
+signed_tb_fw_config.dtb --> fiptool
+signed_spkg_1 -down-> fiptool
+signed_spkg_2 -down-> fiptool
+fiptool -down-> fip
+
+@enduml
diff --git a/docs/resources/diagrams/plantuml/io_arm_class_diagram.puml b/docs/resources/diagrams/plantuml/io_arm_class_diagram.puml
new file mode 100644
index 0000000..53594c2
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/io_arm_class_diagram.puml
@@ -0,0 +1,109 @@
+@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
diff --git a/docs/resources/diagrams/plantuml/io_dev_init_and_check.puml b/docs/resources/diagrams/plantuml/io_dev_init_and_check.puml
new file mode 100644
index 0000000..b7289a2
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/io_dev_init_and_check.puml
@@ -0,0 +1,62 @@
+@startuml
+
+participant arm_io_storage
+participant io_storage
+
+ -> 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
diff --git a/docs/resources/diagrams/plantuml/io_dev_registration.puml b/docs/resources/diagrams/plantuml/io_dev_registration.puml
new file mode 100644
index 0000000..c6f330e
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/io_dev_registration.puml
@@ -0,0 +1,52 @@
+@startuml
+
+participant arm_io_storage
+participant io_storage
+participant io_fip
+participant io_memmap
+
+ -> 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
diff --git a/docs/resources/diagrams/plantuml/io_framework_usage_overview.puml b/docs/resources/diagrams/plantuml/io_framework_usage_overview.puml
new file mode 100644
index 0000000..b21a0ae
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/io_framework_usage_overview.puml
@@ -0,0 +1,59 @@
+@startuml
+
+participant bl_common
+participant arm_io_storage
+participant io_storage
+
+== 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
diff --git a/docs/resources/diagrams/plantuml/sdei_explicit_dispatch.puml b/docs/resources/diagrams/plantuml/sdei_explicit_dispatch.puml
new file mode 100644
index 0000000..90ff23c
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/sdei_explicit_dispatch.puml
@@ -0,0 +1,51 @@
+/'
+ ' Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ '
+ ' SPDX-License-Identifier: BSD-3-Clause
+ '/
+
+@startuml
+
+autonumber "<b>[#]</b>"
+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
+
+... <<Business as usual>> ...
+
+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
+
+... <<Normal execution resumes>> ...
+
+@enduml
diff --git a/docs/resources/diagrams/plantuml/sdei_general.puml b/docs/resources/diagrams/plantuml/sdei_general.puml
new file mode 100644
index 0000000..ab6929a
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/sdei_general.puml
@@ -0,0 +1,43 @@
+/'
+ ' Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ '
+ ' SPDX-License-Identifier: BSD-3-Clause
+ '/
+
+@startuml
+
+autonumber "<b>[#]</b>"
+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
+
+... <<Business as usual>> ...
+
+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
+
+... <<Normal execution resumes>> ...
+
+@enduml
diff --git a/docs/resources/diagrams/plantuml/spm_dfd.puml b/docs/resources/diagrams/plantuml/spm_dfd.puml
new file mode 100644
index 0000000..ad4996e
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/spm_dfd.puml
@@ -0,0 +1,82 @@
+/'
+ ' Copyright (c) 2021, Arm Limited. All rights reserved.
+ '
+ ' SPDX-License-Identifier: BSD-3-Clause
+ '/
+
+/'
+TF-A SPMC Data Flow Diagram
+'/
+
+@startuml
+digraph tfa_dfd {
+
+ # Allow arrows to end on cluster boundaries
+ compound=true
+
+ # Default settings for edges and nodes
+ edge [minlen=2 color="#8c1b07"]
+ node [fillcolor="#ffb866" style=filled shape=box fixedsize=true width=1.6 height=0.7]
+
+ # Nodes outside of the trust boundary
+ nsec [label="NS Client"]
+ ddr [label="External memory (DDR)"]
+
+ # Trust boundary cluster
+ subgraph cluster_trusted {
+ graph [style=dashed color="#f22430"]
+
+ # HW IPs cluster
+ subgraph cluster_ip {
+ label ="Hardware IPs";
+ graph [style=filled color="#000000" fillcolor="#ffd29e"]
+
+ rank="same"
+ gic [label="GIC" width=1.2 height=0.5]
+ smmu [label="SMMU" width=1.2 height=0.5]
+ uart [label="UART" width=1.2 height=0.5]
+ pe [label="PE" width=1.2 height=0.5]
+ }
+
+ # TF-A cluster
+ subgraph cluster_tfa {
+ label ="EL3 monitor";
+ graph [style=filled color="#000000" fillcolor="#faf9cd"]
+
+ bl31 [label="BL31" fillcolor="#ddffb3"];
+ spmd [label="SPMD" fillcolor="#ddffb3" height=1]
+ }
+
+ # SPMC cluster
+ subgraph cluster_spmc {
+ label ="SPMC";
+ graph [style=filled color="#000000" fillcolor="#faf9cd"]
+
+ spmc [label="SPMC" fillcolor="#ddffb3" height=1]
+ }
+ bl2 [label="BL2" width=1.2 height=0.5]
+ }
+
+ # Secure Partitions cluster
+ subgraph cluster_sp {
+ label ="Secure Partitions";
+ graph [style=filled color="#000000" fillcolor="#faf9cd"]
+
+ sp1 [label="SP1" fillcolor="#ddffb3" height=1]
+ sp2 [label="SP2" fillcolor="#ddffb3" height=1]
+ spn [label="SP..." fillcolor="#ddffb3" height=1]
+ }
+
+ # Interactions between nodes
+ sp1 -> spmc [dir="both" label="DF1"]
+ spmc -> spmd [dir="both" label="DF2"]
+ spmd -> nsec [dir="both" label="DF3"]
+ sp1 -> sp2 [dir="both" label="DF4"]
+ spmc -> smmu [lhead=cluster_spmc label="DF5"]
+ bl2 -> spmc [lhead=cluster_spmc label="DF6"]
+ bl2 -> spn [lhead=cluster_spmc label="DF6"]
+ sp1 -> ddr [dir="both" label="DF7"]
+ spmc -> ddr [dir="both" label="DF7"]
+}
+
+@enduml
diff --git a/docs/resources/diagrams/plantuml/tfa_dfd.puml b/docs/resources/diagrams/plantuml/tfa_dfd.puml
new file mode 100644
index 0000000..0007911
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/tfa_dfd.puml
@@ -0,0 +1,66 @@
+/'
+ ' Copyright (c) 2021, Arm Limited. All rights reserved.
+ '
+ ' SPDX-License-Identifier: BSD-3-Clause
+ '/
+
+/'
+TF-A Data Flow Diagram
+'/
+
+@startuml
+digraph tfa_dfd {
+
+ # Arrange nodes from left to right
+ rankdir="LR"
+
+ # Allow arrows to end on cluster boundaries
+ compound=true
+
+ # Default settings for edges and nodes
+ edge [minlen=2 color="#8c1b07"]
+ node [fillcolor="#ffb866" style=filled shape=box fixedsize=true width=1.6 height=0.7]
+
+ # Nodes outside of the trust boundary
+ nsec [label="Non-secure\nClients"]
+ sec [label="Secure\nClients"]
+ dbg [label="Debug & Trace"]
+ logs [label="Logs\n(UART)"]
+ nvm [label="Non-volatile\nMemory"]
+
+ # Trust boundary cluster
+ subgraph cluster_trusted{
+ graph [style=dashed color="#f22430"]
+
+ # HW IPs cluster
+ subgraph cluster_ip{
+ label ="Hardware IPs";
+ graph [style=filled color="#000000" fillcolor="#ffd29e"]
+
+ rank="same"
+ gic [label="GIC" width=1.2 height=0.5]
+ tzc [label="TZ\nController" width=1.2 height=0.5]
+ etc [label="..." shape=none style=none height=0.5]
+ }
+
+ # TF-A cluster
+ subgraph cluster_tfa{
+ label ="TF-A";
+ graph [style=filled color="#000000" fillcolor="#faf9cd"]
+
+ bl1 [label="Boot ROM\n(BL1)" fillcolor="#ddffb3"];
+ bl2 [label="Trusted Boot\nFirmware\n(BL2)" fillcolor="#ddffb3" height=1]
+ bl31 [label="TF-A Runtime\n(BL31)" fillcolor="#ddffb3"]
+ }
+ }
+
+ # Interactions between nodes
+ nvm -> bl31 [lhead=cluster_tfa label="DF1"]
+ logs -> bl31 [dir="back" lhead=cluster_tfa label="DF2"]
+ dbg -> bl2 [dir="both" lhead=cluster_tfa label="DF3"]
+ sec -> bl2 [dir="both" lhead=cluster_tfa label="DF4"]
+ nsec -> bl1 [dir="both" lhead=cluster_tfa, label="DF5"]
+ bl2 -> tzc [dir="both" ltail=cluster_tfa lhead=cluster_ip label="DF6" minlen=1]
+}
+
+@enduml
diff --git a/docs/resources/diagrams/psci-suspend-sequence.png b/docs/resources/diagrams/psci-suspend-sequence.png
new file mode 100644
index 0000000..1703ea6
--- /dev/null
+++ b/docs/resources/diagrams/psci-suspend-sequence.png
Binary files differ
diff --git a/docs/resources/diagrams/reset_code_flow.dia b/docs/resources/diagrams/reset_code_flow.dia
new file mode 100644
index 0000000..133c9cf
--- /dev/null
+++ b/docs/resources/diagrams/reset_code_flow.dia
Binary files differ
diff --git a/docs/resources/diagrams/reset_code_no_boot_type_check.png b/docs/resources/diagrams/reset_code_no_boot_type_check.png
new file mode 100644
index 0000000..23e865f
--- /dev/null
+++ b/docs/resources/diagrams/reset_code_no_boot_type_check.png
Binary files differ
diff --git a/docs/resources/diagrams/reset_code_no_checks.png b/docs/resources/diagrams/reset_code_no_checks.png
new file mode 100644
index 0000000..26a179b
--- /dev/null
+++ b/docs/resources/diagrams/reset_code_no_checks.png
Binary files differ
diff --git a/docs/resources/diagrams/reset_code_no_cpu_check.png b/docs/resources/diagrams/reset_code_no_cpu_check.png
new file mode 100644
index 0000000..4150dbe
--- /dev/null
+++ b/docs/resources/diagrams/reset_code_no_cpu_check.png
Binary files differ
diff --git a/docs/resources/diagrams/rmm_cold_boot_generic.dia b/docs/resources/diagrams/rmm_cold_boot_generic.dia
new file mode 100644
index 0000000..739a1df
--- /dev/null
+++ b/docs/resources/diagrams/rmm_cold_boot_generic.dia
Binary files differ
diff --git a/docs/resources/diagrams/rmm_cold_boot_generic.png b/docs/resources/diagrams/rmm_cold_boot_generic.png
new file mode 100644
index 0000000..df4c1ba
--- /dev/null
+++ b/docs/resources/diagrams/rmm_cold_boot_generic.png
Binary files differ
diff --git a/docs/resources/diagrams/rmm_el3_manifest_struct.dia b/docs/resources/diagrams/rmm_el3_manifest_struct.dia
new file mode 100644
index 0000000..7b7a9c2
--- /dev/null
+++ b/docs/resources/diagrams/rmm_el3_manifest_struct.dia
Binary files differ
diff --git a/docs/resources/diagrams/rmm_el3_manifest_struct.png b/docs/resources/diagrams/rmm_el3_manifest_struct.png
new file mode 100644
index 0000000..8b5776c
--- /dev/null
+++ b/docs/resources/diagrams/rmm_el3_manifest_struct.png
Binary files differ
diff --git a/docs/resources/diagrams/romlib_design.dia b/docs/resources/diagrams/romlib_design.dia
new file mode 100644
index 0000000..d12eec0
--- /dev/null
+++ b/docs/resources/diagrams/romlib_design.dia
Binary files differ
diff --git a/docs/resources/diagrams/romlib_design.png b/docs/resources/diagrams/romlib_design.png
new file mode 100644
index 0000000..bfffcde
--- /dev/null
+++ b/docs/resources/diagrams/romlib_design.png
Binary files differ
diff --git a/docs/resources/diagrams/romlib_wrapper.dia b/docs/resources/diagrams/romlib_wrapper.dia
new file mode 100644
index 0000000..30cfbd8
--- /dev/null
+++ b/docs/resources/diagrams/romlib_wrapper.dia
Binary files differ
diff --git a/docs/resources/diagrams/romlib_wrapper.png b/docs/resources/diagrams/romlib_wrapper.png
new file mode 100644
index 0000000..ec3a441
--- /dev/null
+++ b/docs/resources/diagrams/romlib_wrapper.png
Binary files differ
diff --git a/docs/resources/diagrams/rt-svc-descs-layout.png b/docs/resources/diagrams/rt-svc-descs-layout.png
new file mode 100644
index 0000000..1a9fa5b
--- /dev/null
+++ b/docs/resources/diagrams/rt-svc-descs-layout.png
Binary files differ
diff --git a/docs/resources/diagrams/sec-int-handling.png b/docs/resources/diagrams/sec-int-handling.png
new file mode 100644
index 0000000..fa5c340
--- /dev/null
+++ b/docs/resources/diagrams/sec-int-handling.png
Binary files differ
diff --git a/docs/resources/diagrams/secure_sw_stack_sp.png b/docs/resources/diagrams/secure_sw_stack_sp.png
new file mode 100644
index 0000000..5cb2ca7
--- /dev/null
+++ b/docs/resources/diagrams/secure_sw_stack_sp.png
Binary files differ
diff --git a/docs/resources/diagrams/secure_sw_stack_tos.png b/docs/resources/diagrams/secure_sw_stack_tos.png
new file mode 100644
index 0000000..1f2d555
--- /dev/null
+++ b/docs/resources/diagrams/secure_sw_stack_tos.png
Binary files differ
diff --git a/docs/resources/diagrams/spm-threat-model-trust-boundaries.png b/docs/resources/diagrams/spm-threat-model-trust-boundaries.png
new file mode 100644
index 0000000..58898c5
--- /dev/null
+++ b/docs/resources/diagrams/spm-threat-model-trust-boundaries.png
Binary files differ
diff --git a/docs/resources/diagrams/xlat_align.dia b/docs/resources/diagrams/xlat_align.dia
new file mode 100644
index 0000000..bd88c0c
--- /dev/null
+++ b/docs/resources/diagrams/xlat_align.dia
Binary files differ
diff --git a/docs/resources/diagrams/xlat_align.png b/docs/resources/diagrams/xlat_align.png
new file mode 100644
index 0000000..cffd3c1
--- /dev/null
+++ b/docs/resources/diagrams/xlat_align.png
Binary files differ
diff --git a/docs/security_advisories/index.rst b/docs/security_advisories/index.rst
new file mode 100644
index 0000000..b80ba34
--- /dev/null
+++ b/docs/security_advisories/index.rst
@@ -0,0 +1,16 @@
+Security Advisories
+===================
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents
+
+ 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
+ security-advisory-tfv-9.rst
diff --git a/docs/security_advisories/security-advisory-tfv-1.rst b/docs/security_advisories/security-advisory-tfv-1.rst
new file mode 100644
index 0000000..9d58d08
--- /dev/null
+++ b/docs/security_advisories/security-advisory-tfv-1.rst
@@ -0,0 +1,162 @@
+Advisory 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
diff --git a/docs/security_advisories/security-advisory-tfv-2.rst b/docs/security_advisories/security-advisory-tfv-2.rst
new file mode 100644
index 0000000..0ed2a7f
--- /dev/null
+++ b/docs/security_advisories/security-advisory-tfv-2.rst
@@ -0,0 +1,61 @@
+Advisory 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
diff --git a/docs/security_advisories/security-advisory-tfv-3.rst b/docs/security_advisories/security-advisory-tfv-3.rst
new file mode 100644
index 0000000..b395f13
--- /dev/null
+++ b/docs/security_advisories/security-advisory-tfv-3.rst
@@ -0,0 +1,86 @@
+Advisory 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
diff --git a/docs/security_advisories/security-advisory-tfv-4.rst b/docs/security_advisories/security-advisory-tfv-4.rst
new file mode 100644
index 0000000..66dd542
--- /dev/null
+++ b/docs/security_advisories/security-advisory-tfv-4.rst
@@ -0,0 +1,124 @@
+Advisory 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
diff --git a/docs/security_advisories/security-advisory-tfv-5.rst b/docs/security_advisories/security-advisory-tfv-5.rst
new file mode 100644
index 0000000..97f7cd9
--- /dev/null
+++ b/docs/security_advisories/security-advisory-tfv-5.rst
@@ -0,0 +1,57 @@
+Advisory 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, updated on 04 Nov 2019 |
++----------------+-------------------------------------------------------------+
+| Versions | All, up to and including v2.1 |
+| Affected | |
++----------------+-------------------------------------------------------------+
+| Configurations | All |
+| Affected | |
++----------------+-------------------------------------------------------------+
+| Impact | Leakage of sensitive secure world timing information |
++----------------+-------------------------------------------------------------+
+| Fix Version | `Pull Request #1127`_ (merged on 18 October 2017) |
+| | |
+| | `Commit e290a8fcbc`_ (merged on 23 August 2019) |
+| | |
+| | `Commit c3e8b0be9b`_ (merged on 27 September 2019) |
++----------------+-------------------------------------------------------------+
+| Credit | Arm, Marek Bykowski |
++----------------+-------------------------------------------------------------+
+
+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 TF-A 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 both when entering EL3 and also
+transitioning to S-EL1.
+
+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.
+
+NOTE: The original pull request referenced above only fixed the issue for S-EL1
+whereas the EL3 was fixed in the later commits.
+
+.. _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
+.. _Commit e290a8fcbc: https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/commit/?id=e290a8fcbc
+.. _Commit c3e8b0be9b: https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/commit/?id=c3e8b0be9b
+
diff --git a/docs/security_advisories/security-advisory-tfv-6.rst b/docs/security_advisories/security-advisory-tfv-6.rst
new file mode 100644
index 0000000..9eeaeec
--- /dev/null
+++ b/docs/security_advisories/security-advisory-tfv-6.rst
@@ -0,0 +1,148 @@
+Advisory 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
diff --git a/docs/security_advisories/security-advisory-tfv-7.rst b/docs/security_advisories/security-advisory-tfv-7.rst
new file mode 100644
index 0000000..8e06762
--- /dev/null
+++ b/docs/security_advisories/security-advisory-tfv-7.rst
@@ -0,0 +1,107 @@
+Advisory 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
diff --git a/docs/security_advisories/security-advisory-tfv-8.rst b/docs/security_advisories/security-advisory-tfv-8.rst
new file mode 100644
index 0000000..ebe324e
--- /dev/null
+++ b/docs/security_advisories/security-advisory-tfv-8.rst
@@ -0,0 +1,103 @@
+Advisory 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: https://developer.arm.com/docs/den0028/latest
+.. _Pull Request #1710: https://github.com/ARM-software/arm-trusted-firmware/pull/1710
diff --git a/docs/security_advisories/security-advisory-tfv-9.rst b/docs/security_advisories/security-advisory-tfv-9.rst
new file mode 100644
index 0000000..d73e74b
--- /dev/null
+++ b/docs/security_advisories/security-advisory-tfv-9.rst
@@ -0,0 +1,124 @@
+Advisory TFV-9 (CVE-2022-23960)
+============================================================
+
++----------------+-------------------------------------------------------------+
+| Title | Trusted Firmware-A exposure to speculative processor |
+| | vulnerabilities with branch prediction target reuse |
++================+=============================================================+
+| CVE ID | `CVE-2022-23960`_ |
++----------------+-------------------------------------------------------------+
+| Date | 08 Mar 2022 |
++----------------+-------------------------------------------------------------+
+| Versions | All, up to and including v2.6 |
+| Affected | |
++----------------+-------------------------------------------------------------+
+| Configurations | All |
+| Affected | |
++----------------+-------------------------------------------------------------+
+| Impact | Potential leakage of secure world data to normal world |
+| | if an attacker is able to find a TF-A exfiltration primitive|
+| | that can be predicted as a valid branch target, and somehow |
+| | induce misprediction onto that primitive. There are |
+| | currently no known exploits. |
++----------------+-------------------------------------------------------------+
+| Fix Version | `Gerrit topic #spectre_bhb`_ |
++----------------+-------------------------------------------------------------+
+| Credit | Systems and Network Security Group at Vrije Universiteit |
+| | Amsterdam for CVE-2022-23960, Arm for patches |
++----------------+-------------------------------------------------------------+
+
+This security advisory describes the current understanding of the Trusted
+Firmware-A exposure to the new speculative processor vulnerability.
+To understand the background and wider impact of these vulnerabilities on Arm
+systems, please refer to the `Arm Processor Security Update`_. The whitepaper
+referred to below describes the Spectre attack and mitigation in more detail
+including implementation specific mitigation details for all impacted Arm CPUs.
+
+
+`CVE-2022-23960`_
+-----------------
+
+Where possible on vulnerable CPUs that implement FEAT_CSV2, Arm recommends
+inserting a loop workaround with implementation specific number of iterations
+that will discard the branch history on exception entry to a higher exception
+level for the given CPU. This is done as early as possible on entry into EL3,
+before any branch instruction is executed. This is sufficient to mitigate
+Spectre-BHB on behalf of all secure world code, assuming that no secure world
+code is under attacker control.
+
+The below table lists the CPUs that mitigate against this vulnerability in
+TF-A using the loop workaround(all cores that implement FEAT_CSV2 except the
+revisions of Cortex-A73 and Cortex-A75 that implements FEAT_CSV2).
+
++----------------------+
+| Core |
++----------------------+
+| Cortex-A72(from r1p0)|
++----------------------+
+| Cortex-A76 |
++----------------------+
+| Cortex-A76AE |
++----------------------+
+| Cortex-A77 |
++----------------------+
+| Cortex-A78 |
++----------------------+
+| Cortex-A78AE |
++----------------------+
+| Cortex-A78C |
++----------------------+
+| Cortex-X1 |
++----------------------+
+| Cortex-X2 |
++----------------------+
+| Cortex-X3 |
++----------------------+
+| Cortex-A710 |
++----------------------+
+| Cortex-A715 |
++----------------------+
+| Cortex-Hunter |
++----------------------+
+| Neoverse-N1 |
++----------------------+
+| Neoverse-N2 |
++----------------------+
+| Neoverse-V1 |
++----------------------+
+| Neoverse-V2 |
++----------------------+
+| Neoverse-Poseidon |
++----------------------+
+
+For all other cores impacted by Spectre-BHB, some of which that do not implement
+FEAT_CSV2 and some that do e.g. Cortex-A73, the recommended mitigation is to
+flush all branch predictions via an implementation specific route.
+
+In case local workaround is not feasible, the Rich OS can invoke the SMC
+(``SMCCC_ARCH_WORKAROUND_3``) to apply the workaround. Refer to `SMCCC Calling
+Convention specification`_ for more details.
+
+`Gerrit topic #spectre_bhb`_ This patchset implements the Spectre-BHB loop
+workaround for CPUs mentioned in the above table. For CPUs supporting
+speculative barrier instruction, the loop workaround is optimised by using SB
+in place of the common DSB and ISB sequence. It also mitigates against
+this vulnerability for Cortex-A72 CPU versions that support the CSV2 feature
+(from r1p0). The patch stack also includes an implementation for a specified
+`CVE-2022-23960`_ workaround SMC(``SMCCC_ARCH_WORKAROUND_3``) for use by normal
+world privileged software. Details of ``SMCCC_ARCH_WORKAROUND_3`` can be found
+in the `SMCCC Calling Convention specification`_. The specification and
+implementation also enables the normal world to discover the presence of this
+firmware service. This patch also implements ``SMCCC_ARCH_WORKAROUND_3`` for
+Cortex-A57, Coxtex-A72, Cortex-A73 and Cortex-A75 using the existing workaround.
+for CVE-2017-5715. Cortex-A15 patch extends Spectre V2 mitigation to Spectre-BHB.
+
+The above workaround is enabled by default (on vulnerable CPUs only). Platforms
+can choose to disable them at compile time if they do not require them.
+
+For more information about non-Arm CPUs, please contact the CPU vendor.
+
+.. _Arm Processor Security Update: http://www.arm.com/security-update
+.. _CVE-2022-23960: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23960
+.. _Gerrit topic #spectre_bhb: https://review.trustedfirmware.org/q/topic:"spectre_bhb"+(status:open%20OR%20status:merged)
+.. _CVE-2022-23960 mitigation specification: https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability
+.. _SMCCC Calling Convention specification: https://developer.arm.com/documentation/den0028/latest
diff --git a/docs/threat_model/index.rst b/docs/threat_model/index.rst
new file mode 100644
index 0000000..ad8b82a
--- /dev/null
+++ b/docs/threat_model/index.rst
@@ -0,0 +1,22 @@
+Threat Model
+============
+
+Threat modeling is an important part of Secure Development Lifecycle (SDL)
+that helps us identify potential threats and mitigations affecting a system.
+
+In the next sections, we first give a description of the target of evaluation
+using a data flow diagram. Then we provide a list of threats we have identified
+based on the data flow diagram and potential threat mitigations.
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents
+
+ threat_model
+ threat_model_spm
+ threat_model_el3_spm
+ threat_model_fvp_r
+
+--------------
+
+*Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.*
diff --git a/docs/threat_model/threat_model.rst b/docs/threat_model/threat_model.rst
new file mode 100644
index 0000000..38e5c87
--- /dev/null
+++ b/docs/threat_model/threat_model.rst
@@ -0,0 +1,896 @@
+Generic Threat Model
+********************
+
+************
+Introduction
+************
+
+This document provides a generic threat model for TF-A firmware.
+
+.. note::
+
+ This threat model doesn't consider Root and Realm worlds introduced by
+ :ref:`Realm Management Extension (RME)`.
+
+********************
+Target of Evaluation
+********************
+
+In this threat model, the target of evaluation is the Trusted
+Firmware for A-class Processors (TF-A). This includes the boot ROM (BL1),
+the trusted boot firmware (BL2) and the runtime EL3 firmware (BL31) as
+shown on Figure 1. Everything else on Figure 1 is outside of the scope of
+the evaluation.
+
+TF-A can be configured in various ways. In this threat model we consider
+only the most basic configuration. To that end we make the following
+assumptions:
+
+- All TF-A images are run from either ROM or on-chip trusted SRAM. This means
+ TF-A is not vulnerable to an attacker that can probe or tamper with off-chip
+ memory.
+
+- Trusted boot is enabled. This means an attacker can't boot arbitrary images
+ that are not approved by platform providers.
+
+- There is no Secure-EL2. We don't consider threats that may come with
+ Secure-EL2 software.
+
+- Measured boot is disabled. We do not consider the threats nor the mitigations
+ that may come with it.
+
+- No experimental features are enabled. We do not consider threats that may come
+ from them.
+
+Data Flow Diagram
+=================
+
+Figure 1 shows a high-level data flow diagram for TF-A. The diagram
+shows a model of the different components of a TF-A-based system and
+their interactions with TF-A. A description of each diagram element
+is given on Table 1. On the diagram, the red broken lines indicate
+trust boundaries. Components outside of the broken lines
+are considered untrusted by TF-A.
+
+.. uml:: ../resources/diagrams/plantuml/tfa_dfd.puml
+ :caption: Figure 1: TF-A Data Flow Diagram
+
+.. table:: Table 1: TF-A Data Flow Diagram Description
+
+ +-----------------+--------------------------------------------------------+
+ | Diagram Element | Description |
+ +=================+========================================================+
+ | DF1 | | At boot time, images are loaded from non-volatile |
+ | | memory and verified by TF-A boot firmware. These |
+ | | images include TF-A BL2 and BL31 images, as well as |
+ | | other secure and non-secure images. |
+ +-----------------+--------------------------------------------------------+
+ | DF2 | | TF-A log system framework outputs debug messages |
+ | | over a UART interface. |
+ +-----------------+--------------------------------------------------------+
+ | DF3 | | Debug and trace IP on a platform can allow access |
+ | | to registers and memory of TF-A. |
+ +-----------------+--------------------------------------------------------+
+ | DF4 | | Secure world software (e.g. trusted OS) interact |
+ | | with TF-A through SMC call interface and/or shared |
+ | | memory. |
+ +-----------------+--------------------------------------------------------+
+ | DF5 | | Non-secure world software (e.g. rich OS) interact |
+ | | with TF-A through SMC call interface and/or shared |
+ | | memory. |
+ +-----------------+--------------------------------------------------------+
+ | DF6 | | This path represents the interaction between TF-A and|
+ | | various hardware IPs such as TrustZone controller |
+ | | and GIC. At boot time TF-A configures/initializes the|
+ | | IPs and interacts with them at runtime through |
+ | | interrupts and registers. |
+ +-----------------+--------------------------------------------------------+
+
+
+***************
+Threat Analysis
+***************
+
+In this section we identify and provide assessment of potential threats to TF-A
+firmware. The threats are identified for each diagram element on the
+data flow diagram above.
+
+For each threat, we identify the *asset* that is under threat, the
+*threat agent* and the *threat type*. Each threat is given a *risk rating*
+that represents the impact and likelihood of that threat. We also discuss
+potential mitigations.
+
+Assets
+======
+
+We have identified the following assets for TF-A:
+
+.. table:: Table 2: TF-A Assets
+
+ +--------------------+---------------------------------------------------+
+ | Asset | Description |
+ +====================+===================================================+
+ | Sensitive Data | | These include sensitive data that an attacker |
+ | | must not be able to tamper with (e.g. the Root |
+ | | of Trust Public Key) or see (e.g. secure logs, |
+ | | debugging information such as crash reports). |
+ +--------------------+---------------------------------------------------+
+ | Code Execution | | This represents the requirement that the |
+ | | platform should run only TF-A code approved by |
+ | | the platform provider. |
+ +--------------------+---------------------------------------------------+
+ | Availability | | This represents the requirement that TF-A |
+ | | services should always be available for use. |
+ +--------------------+---------------------------------------------------+
+
+Threat Agents
+=============
+
+To understand the attack surface, it is important to identify potential
+attackers, i.e. attack entry points. The following threat agents are
+in scope of this threat model.
+
+.. table:: Table 3: Threat Agents
+
+ +-------------------+-------------------------------------------------------+
+ | Threat Agent | Description |
+ +===================+=======================================================+
+ | NSCode | | Malicious or faulty code running in the Non-secure |
+ | | world, including NS-EL0 NS-EL1 and NS-EL2 levels |
+ +-------------------+-------------------------------------------------------+
+ | SecCode | | Malicious or faulty code running in the secure |
+ | | world, including S-EL0 and S-EL1 levels |
+ +-------------------+-------------------------------------------------------+
+ | AppDebug | | Physical attacker using debug signals to access |
+ | | TF-A resources |
+ +-------------------+-------------------------------------------------------+
+ | PhysicalAccess | | Physical attacker having access to external device |
+ | | communication bus and to external flash |
+ | | communication bus using common hardware |
+ +-------------------+-------------------------------------------------------+
+
+.. note::
+
+ In this threat model an advanced physical attacker that has the capability
+ to tamper with a hardware (e.g. "rewiring" a chip using a focused
+ ion beam (FIB) workstation or decapsulate the chip using chemicals) is
+ considered out-of-scope.
+
+Threat Types
+============
+
+In this threat model we categorize threats using the `STRIDE threat
+analysis technique`_. In this technique a threat is categorized as one
+or more of these types: ``Spoofing``, ``Tampering``, ``Repudiation``,
+``Information disclosure``, ``Denial of service`` or
+``Elevation of privilege``.
+
+Threat Risk Ratings
+===================
+
+For each threat identified, a risk rating that ranges
+from *informational* to *critical* is given based on the likelihood of the
+threat occuring if a mitigation is not in place, and the impact of the
+threat (i.e. how severe the consequences could be). Table 4 explains each
+rating in terms of score, impact and likelihood.
+
+.. table:: Table 4: Rating and score as applied to impact and likelihood
+
+ +-----------------------+-------------------------+---------------------------+
+ | **Rating (Score)** | **Impact** | **Likelihood** |
+ +=======================+=========================+===========================+
+ | Critical (5) | | Extreme impact to | | Threat is almost |
+ | | entire organization | certain to be exploited.|
+ | | if exploited. | |
+ | | | | Knowledge of the threat |
+ | | | and how to exploit it |
+ | | | are in the public |
+ | | | domain. |
+ +-----------------------+-------------------------+---------------------------+
+ | High (4) | | Major impact to entire| | Threat is relatively |
+ | | organization or single| easy to detect and |
+ | | line of business if | exploit by an attacker |
+ | | exploited | with little skill. |
+ +-----------------------+-------------------------+---------------------------+
+ | Medium (3) | | Noticeable impact to | | A knowledgeable insider |
+ | | line of business if | or expert attacker could|
+ | | exploited. | exploit the threat |
+ | | | without much difficulty.|
+ +-----------------------+-------------------------+---------------------------+
+ | Low (2) | | Minor damage if | | Exploiting the threat |
+ | | exploited or could | would require |
+ | | be used in conjunction| considerable expertise |
+ | | with other | and resources |
+ | | vulnerabilities to | |
+ | | perform a more serious| |
+ | | attack | |
+ +-----------------------+-------------------------+---------------------------+
+ | Informational (1) | | Poor programming | | Threat is not likely |
+ | | practice or poor | to be exploited on its |
+ | | design decision that | own, but may be used to |
+ | | may not represent an | gain information for |
+ | | immediate risk on its | launching another |
+ | | own, but may have | attack |
+ | | security implications | |
+ | | if multiplied and/or | |
+ | | combined with other | |
+ | | threats. | |
+ +-----------------------+-------------------------+---------------------------+
+
+Aggregate risk scores are assigned to identified threats;
+specifically, the impact score multiplied by the likelihood score.
+For example, a threat with high likelihood and low impact would have an
+aggregate risk score of eight (8); that is, four (4) for high likelihood
+multiplied by two (2) for low impact. The aggregate risk score determines
+the finding's overall risk level, as shown in the following table.
+
+.. table:: Table 5: Overall risk levels and corresponding aggregate scores
+
+ +---------------------+-----------------------------------+
+ | Overall Risk Level | Aggregate Risk Score |
+ | | (Impact multiplied by Likelihood) |
+ +=====================+===================================+
+ | Critical | 20–25 |
+ +---------------------+-----------------------------------+
+ | High | 12–19 |
+ +---------------------+-----------------------------------+
+ | Medium | 6–11 |
+ +---------------------+-----------------------------------+
+ | Low | 2–5 |
+ +---------------------+-----------------------------------+
+ | Informational | 1 |
+ +---------------------+-----------------------------------+
+
+The likelihood and impact of a threat depends on the
+target environment in which TF-A is running. For example, attacks
+that require physical access are unlikely in server environments while
+they are more common in Internet of Things(IoT) environments.
+In this threat model we consider three target environments:
+``Internet of Things(IoT)``, ``Mobile`` and ``Server``.
+
+Threat Assessment
+=================
+
+The following threats were identified by applying STRIDE analysis on
+each diagram element of the data flow diagram.
+
+For each threat, we strive to indicate whether the mitigations are currently
+implemented or not. However, the answer to this question is not always straight
+forward. Some mitigations are partially implemented in the generic code but also
+rely on the platform code to implement some bits of it. This threat model aims
+to be platform-independent and it is important to keep in mind that such threats
+only get mitigated if the platform code properly fulfills its responsibilities.
+
+Also, some mitigations require enabling specific features, which must be
+explicitly turned on via a build flag.
+
+These are highlighted in the ``Mitigations implemented?`` box.
+
++------------------------+----------------------------------------------------+
+| ID | 01 |
++========================+====================================================+
+| Threat | | **An attacker can mangle firmware images to |
+| | execute arbitrary code** |
+| | |
+| | | Some TF-A images are loaded from external |
+| | storage. It is possible for an attacker to access|
+| | the external flash memory and change its contents|
+| | physically, through the Rich OS, or using the |
+| | updating mechanism to modify the non-volatile |
+| | images to execute arbitrary code. |
++------------------------+----------------------------------------------------+
+| Diagram Elements | DF1, DF4, DF5 |
++------------------------+----------------------------------------------------+
+| Affected TF-A | BL2, BL31 |
+| Components | |
++------------------------+----------------------------------------------------+
+| Assets | Code Execution |
++------------------------+----------------------------------------------------+
+| Threat Agent | PhysicalAccess, NSCode, SecCode |
++------------------------+----------------------------------------------------+
+| Threat Type | Tampering, Elevation of Privilege |
++------------------------+------------------+-----------------+---------------+
+| Application | Server | IoT | Mobile |
++------------------------+------------------+-----------------+---------------+
+| Impact | Critical (5) | Critical (5) | Critical (5) |
++------------------------+------------------+-----------------+---------------+
+| Likelihood | Critical (5) | Critical (5) | Critical (5) |
++------------------------+------------------+-----------------+---------------+
+| Total Risk Rating | Critical (25) | Critical (25) | Critical (25) |
++------------------------+------------------+-----------------+---------------+
+| Mitigations | | 1) Implement the `Trusted Board Boot (TBB)`_ |
+| | feature which prevents malicious firmware from |
+| | running on the platform by authenticating all |
+| | firmware images. |
+| | |
+| | | 2) Perform extra checks on unauthenticated data, |
+| | such as FIP metadata, prior to use. |
++------------------------+----------------------------------------------------+
+| Mitigations | | 1) Yes, provided that the ``TRUSTED_BOARD_BOOT`` |
+| implemented? | build option is set to 1. |
+| | |
+| | | 2) Yes. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 02 |
++========================+====================================================+
+| Threat | | **An attacker may attempt to boot outdated, |
+| | potentially vulnerable firmware image** |
+| | |
+| | | When updating firmware, an attacker may attempt |
+| | to rollback to an older version that has unfixed |
+| | vulnerabilities. |
++------------------------+----------------------------------------------------+
+| Diagram Elements | DF1, DF4, DF5 |
++------------------------+----------------------------------------------------+
+| Affected TF-A | BL2, BL31 |
+| Components | |
++------------------------+----------------------------------------------------+
+| Assets | Code Execution |
++------------------------+----------------------------------------------------+
+| Threat Agent | PhysicalAccess, NSCode, SecCode |
++------------------------+----------------------------------------------------+
+| Threat Type | Tampering |
++------------------------+------------------+-----------------+---------------+
+| Application | Server | IoT | Mobile |
++------------------------+------------------+-----------------+---------------+
+| Impact | Critical (5) | Critical (5) | Critical (5) |
++------------------------+------------------+-----------------+---------------+
+| Likelihood | Critical (5) | Critical (5) | Critical (5) |
++------------------------+------------------+-----------------+---------------+
+| Total Risk Rating | Critical (25) | Critical (25) | Critical (25) |
++------------------------+------------------+-----------------+---------------+
+| Mitigations | Implement anti-rollback protection using |
+| | non-volatile counters (NV counters) as required |
+| | by `TBBR-Client specification`_. |
++------------------------+----------------------------------------------------+
+| Mitigations | | Yes / Platform specific. |
+| implemented? | |
+| | | After a firmware image is validated, the image |
+| | revision number taken from a certificate |
+| | extension field is compared with the |
+| | corresponding NV counter stored in hardware to |
+| | make sure the new counter value is larger than |
+| | the current counter value. |
+| | |
+| | | **Platforms must implement this protection using |
+| | platform specific hardware NV counters.** |
++------------------------+----------------------------------------------------+
+
++------------------------+-------------------------------------------------------+
+| ID | 03 |
++========================+=======================================================+
+| Threat | | **An attacker can use Time-of-Check-Time-of-Use |
+| | (TOCTOU) attack to bypass image authentication |
+| | during the boot process** |
+| | |
+| | | Time-of-Check-Time-of-Use (TOCTOU) threats occur |
+| | when the security check is produced before the time |
+| | the resource is accessed. If an attacker is sitting |
+| | in the middle of the off-chip images, they could |
+| | change the binary containing executable code right |
+| | after the integrity and authentication check has |
+| | been performed. |
++------------------------+-------------------------------------------------------+
+| Diagram Elements | DF1 |
++------------------------+-------------------------------------------------------+
+| Affected TF-A | BL1, BL2 |
+| Components | |
++------------------------+-------------------------------------------------------+
+| Assets | Code Execution, Sensitive Data |
++------------------------+-------------------------------------------------------+
+| Threat Agent | PhysicalAccess |
++------------------------+-------------------------------------------------------+
+| Threat Type | Elevation of Privilege |
++------------------------+---------------------+-----------------+---------------+
+| Application | Server | IoT | Mobile |
++------------------------+---------------------+-----------------+---------------+
+| Impact | N/A | Critical (5) | Critical (5) |
++------------------------+---------------------+-----------------+---------------+
+| Likelihood | N/A | Medium (3) | Medium (3) |
++------------------------+---------------------+-----------------+---------------+
+| Total Risk Rating | N/A | High (15) | High (15) |
++------------------------+---------------------+-----------------+---------------+
+| Mitigations | Copy image to on-chip memory before authenticating |
+| | it. |
++------------------------+-------------------------------------------------------+
+| Mitigations | | Platform specific. |
+| implemented? | |
+| | | The list of images to load and their location is |
+| | platform specific. Platforms are responsible for |
+| | arranging images to be loaded in on-chip memory. |
++------------------------+-------------------------------------------------------+
+
++------------------------+-------------------------------------------------------+
+| ID | 04 |
++========================+=======================================================+
+| Threat | | **An attacker with physical access can execute |
+| | arbitrary image by bypassing the signature |
+| | verification stage using glitching techniques** |
+| | |
+| | | Glitching (Fault injection) attacks attempt to put |
+| | a hardware into a undefined state by manipulating an|
+| | environmental variable such as power supply. |
+| | |
+| | | TF-A relies on a chain of trust that starts with the|
+| | ROTPK, which is the key stored inside the chip and |
+| | the root of all validation processes. If an attacker|
+| | can break this chain of trust, they could execute |
+| | arbitrary code on the device. This could be |
+| | achieved with physical access to the device by |
+| | attacking the normal execution flow of the |
+| | process using glitching techniques that target |
+| | points where the image is validated against the |
+| | signature. |
++------------------------+-------------------------------------------------------+
+| Diagram Elements | DF1 |
++------------------------+-------------------------------------------------------+
+| Affected TF-A | BL1, BL2 |
+| Components | |
++------------------------+-------------------------------------------------------+
+| Assets | Code Execution |
++------------------------+-------------------------------------------------------+
+| Threat Agent | PhysicalAccess |
++------------------------+-------------------------------------------------------+
+| Threat Type | Tampering, Elevation of Privilege |
++------------------------+---------------------+-----------------+---------------+
+| Application | Server | IoT | Mobile |
++------------------------+---------------------+-----------------+---------------+
+| Impact | N/A | Critical (5) | Critical (5) |
++------------------------+---------------------+-----------------+---------------+
+| Likelihood | N/A | Medium (3) | Medium (3) |
++------------------------+---------------------+-----------------+---------------+
+| Total Risk Rating | N/A | High (15) | High (15) |
++------------------------+---------------------+-----------------+---------------+
+| Mitigations | Mechanisms to detect clock glitch and power |
+| | variations. |
++------------------------+-------------------------------------------------------+
+| Mitigations | | No. |
+| implemented? | |
+| | | The most effective mitigation is adding glitching |
+| | detection and mitigation circuit at the hardware |
+| | level. |
+| | |
+| | | However, software techniques, such as adding |
+| | redundant checks when performing conditional |
+| | branches that are security sensitive, can be used |
+| | to harden TF-A against such attacks. |
+| | **At the moment TF-A doesn't implement such |
+| | mitigations.** |
++------------------------+-------------------------------------------------------+
+
++------------------------+---------------------------------------------------+
+| ID | 05 |
++========================+===================================================+
+| Threat | | **Information leak via UART logs** |
+| | |
+| | | During the development stages of software it is |
+| | common to print all sorts of information on the |
+| | console, including sensitive or confidential |
+| | information such as crash reports with detailed |
+| | information of the CPU state, current registers |
+| | values, privilege level or stack dumps. |
+| | |
+| | | This information is useful when debugging |
+| | problems before releasing the production |
+| | version but it could be used by an attacker |
+| | to develop a working exploit if left enabled in |
+| | the production version. |
+| | |
+| | | This happens when directly logging sensitive |
+| | information and more subtly when logging |
+| | side-channel information that can be used by an |
+| | attacker to learn about sensitive information. |
++------------------------+---------------------------------------------------+
+| Diagram Elements | DF2 |
++------------------------+---------------------------------------------------+
+| Affected TF-A | BL1, BL2, BL31 |
+| Components | |
++------------------------+---------------------------------------------------+
+| Assets | Sensitive Data |
++------------------------+---------------------------------------------------+
+| Threat Agent | AppDebug |
++------------------------+---------------------------------------------------+
+| Threat Type | Information Disclosure |
++------------------------+------------------+----------------+---------------+
+| Application | Server | IoT | Mobile |
++------------------------+------------------+----------------+---------------+
+| Impact | N/A | Low (2) | Low (2) |
++------------------------+------------------+----------------+---------------+
+| Likelihood | N/A | High (4) | High (4) |
++------------------------+------------------+----------------+---------------+
+| Total Risk Rating | N/A | Medium (8) | Medium (8) |
++------------------------+------------------+----------------+---------------+
+| Mitigations | | Remove sensitive information logging in |
+| | production releases. |
+| | |
+| | | Do not conditionally log information depending |
+| | on potentially sensitive data. |
+| | |
+| | | Do not log high precision timing information. |
++------------------------+---------------------------------------------------+
+| Mitigations | | Yes / Platform Specific. |
+| implemented? | Requires the right build options to be used. |
+| | |
+| | | Crash reporting is only enabled for debug |
+| | builds by default, see ``CRASH_REPORTING`` |
+| | build option. |
+| | |
+| | | The log level can be tuned at build time, from |
+| | very verbose to no output at all. See |
+| | ``LOG_LEVEL`` build option. By default, release |
+| | builds are a lot less verbose than debug ones |
+| | but still produce some output. |
+| | |
+| | | Messages produced by the platform code should |
+| | use the appropriate level of verbosity so as |
+| | not to leak sensitive information in production |
+| | builds. |
++------------------------+---------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 06 |
++========================+====================================================+
+| Threat | | **An attacker can read sensitive data and |
+| | execute arbitrary code through the external |
+| | debug and trace interface** |
+| | |
+| | | Arm processors include hardware-assisted debug |
+| | and trace features that can be controlled without|
+| | the need for software operating on the platform. |
+| | If left enabled without authentication, this |
+| | feature can be used by an attacker to inspect and|
+| | modify TF-A registers and memory allowing the |
+| | attacker to read sensitive data and execute |
+| | arbitrary code. |
++------------------------+----------------------------------------------------+
+| Diagram Elements | DF3 |
++------------------------+----------------------------------------------------+
+| Affected TF-A | BL1, BL2, BL31 |
+| Components | |
++------------------------+----------------------------------------------------+
+| Assets | Code Execution, Sensitive Data |
++------------------------+----------------------------------------------------+
+| Threat Agent | AppDebug |
++------------------------+----------------------------------------------------+
+| Threat Type | Tampering, Information Disclosure, |
+| | Elevation of privilege |
++------------------------+------------------+---------------+-----------------+
+| Application | Server | IoT | Mobile |
++------------------------+------------------+---------------+-----------------+
+| Impact | N/A | High (4) | High (4) |
++------------------------+------------------+---------------+-----------------+
+| Likelihood | N/A | Critical (5) | Critical (5) |
++------------------------+------------------+---------------+-----------------+
+| Total Risk Rating | N/A | Critical (20) | Critical (20) |
++------------------------+------------------+---------------+-----------------+
+| Mitigations | Disable the debug and trace capability for |
+| | production releases or enable proper debug |
+| | authentication as recommended by [`DEN0034`_]. |
++------------------------+----------------------------------------------------+
+| Mitigations | | Platform specific. |
+| implemented? | |
+| | | Configuration of debug and trace capabilities is |
+| | entirely platform specific. |
++------------------------+----------------------------------------------------+
+
++------------------------+------------------------------------------------------+
+| ID | 07 |
++========================+======================================================+
+| Threat | | **An attacker can perform a denial-of-service |
+| | attack by using a broken SMC call that causes the |
+| | system to reboot or enter into unknown state.** |
+| | |
+| | | Secure and non-secure clients access TF-A services |
+| | through SMC calls. Malicious code can attempt to |
+| | place the TF-A runtime into an inconsistent state |
+| | by calling unimplemented SMC call or by passing |
+| | invalid arguments. |
++------------------------+------------------------------------------------------+
+| Diagram Elements | DF4, DF5 |
++------------------------+------------------------------------------------------+
+| Affected TF-A | BL31 |
+| Components | |
++------------------------+------------------------------------------------------+
+| Assets | Availability |
++------------------------+------------------------------------------------------+
+| Threat Agent | NSCode, SecCode |
++------------------------+------------------------------------------------------+
+| Threat Type | Denial of Service |
++------------------------+-------------------+----------------+-----------------+
+| Application | Server | IoT | Mobile |
++------------------------+-------------------+----------------+-----------------+
+| Impact | Medium (3) | Medium (3) | Medium (3) |
++------------------------+-------------------+----------------+-----------------+
+| Likelihood | High (4) | High (4) | High (4) |
++------------------------+-------------------+----------------+-----------------+
+| Total Risk Rating | High (12) | High (12) | High (12) |
++------------------------+-------------------+----------------+-----------------+
+| Mitigations | Validate SMC function ids and arguments before using |
+| | them. |
++------------------------+------------------------------------------------------+
+| Mitigations | | Yes / Platform specific. |
+| implemented? | |
+| | | For standard services, all input is validated. |
+| | |
+| | | Platforms that implement SiP services must also |
+| | validate SMC call arguments. |
++------------------------+------------------------------------------------------+
+
++------------------------+------------------------------------------------------+
+| ID | 08 |
++========================+======================================================+
+| Threat | | **Memory corruption due to memory overflows and |
+| | lack of boundary checking when accessing resources |
+| | could allow an attacker to execute arbitrary code, |
+| | modify some state variable to change the normal |
+| | flow of the program, or leak sensitive |
+| | information** |
+| | |
+| | | Like in other software, TF-A has multiple points |
+| | where memory corruption security errors can arise. |
+| | |
+| | | Some of the errors include integer overflow, |
+| | buffer overflow, incorrect array boundary checks, |
+| | and incorrect error management. |
+| | Improper use of asserts instead of proper input |
+| | validations might also result in these kinds of |
+| | errors in release builds. |
++------------------------+------------------------------------------------------+
+| Diagram Elements | DF4, DF5 |
++------------------------+------------------------------------------------------+
+| Affected TF-A | BL1, BL2, BL31 |
+| Components | |
++------------------------+------------------------------------------------------+
+| Assets | Code Execution, Sensitive Data |
++------------------------+------------------------------------------------------+
+| Threat Agent | NSCode, SecCode |
++------------------------+------------------------------------------------------+
+| Threat Type | Tampering, Information Disclosure, |
+| | Elevation of Privilege |
++------------------------+-------------------+-----------------+----------------+
+| Application | Server | IoT | Mobile |
++------------------------+-------------------+-----------------+----------------+
+| Impact | Critical (5) | Critical (5) | Critical (5) |
++------------------------+-------------------+-----------------+----------------+
+| Likelihood | Medium (3 | Medium (3) | Medium (3) |
++------------------------+-------------------+-----------------+----------------+
+| Total Risk Rating | High (15) | High (15) | High (15) |
++------------------------+-------------------+-----------------+----------------+
+| Mitigations | | 1) Use proper input validation. |
+| | |
+| | | 2) Code reviews, testing. |
++------------------------+------------------------------------------------------+
+| Mitigations | | 1) Yes. |
+| implemented? | Data received from normal world, such as addresses |
+| | and sizes identifying memory regions, are |
+| | sanitized before being used. These security checks |
+| | make sure that the normal world software does not |
+| | access memory beyond its limit. |
+| | |
+| | | By default *asserts* are only used to check for |
+| | programming errors in debug builds. Other types of |
+| | errors are handled through condition checks that |
+| | remain enabled in release builds. See |
+| | `TF-A error handling policy`_. TF-A provides an |
+| | option to use *asserts* in release builds, however |
+| | we recommend using proper runtime checks instead |
+| | of relying on asserts in release builds. |
+| | |
+| | | 2) Yes. |
+| | TF-A uses a combination of manual code reviews |
+| | and automated program analysis and testing to |
+| | detect and fix memory corruption bugs. All TF-A |
+| | code including platform code go through manual |
+| | code reviews. Additionally, static code analysis |
+| | is performed using Coverity Scan on all TF-A code. |
+| | The code is also tested with |
+| | `Trusted Firmware-A Tests`_ on Juno and FVP |
+| | platforms. |
++------------------------+------------------------------------------------------+
+
++------------------------+------------------------------------------------------+
+| ID | 09 |
++========================+======================================================+
+| Threat | | **Improperly handled SMC calls can leak register |
+| | contents** |
+| | |
+| | | When switching between worlds, TF-A register state |
+| | can leak to software in different security |
+| | contexts. |
++------------------------+------------------------------------------------------+
+| Diagram Elements | DF4, DF5 |
++------------------------+------------------------------------------------------+
+| Affected TF-A | BL31 |
+| Components | |
++------------------------+------------------------------------------------------+
+| Assets | Sensitive Data |
++------------------------+------------------------------------------------------+
+| Threat Agent | NSCode, SecCode |
++------------------------+------------------------------------------------------+
+| Threat Type | Information Disclosure |
++------------------------+-------------------+----------------+-----------------+
+| Application | Server | IoT | Mobile |
++------------------------+-------------------+----------------+-----------------+
+| Impact | Medium (3) | Medium (3) | Medium (3) |
++------------------------+-------------------+----------------+-----------------+
+| Likelihood | High (4) | High (4) | High (4) |
++------------------------+-------------------+----------------+-----------------+
+| Total Risk Rating | High (12) | High (12) | High (12) |
++------------------------+-------------------+----------------+-----------------+
+| Mitigations | Save and restore registers when switching contexts. |
++------------------------+------------------------------------------------------+
+| Mitigations | | Yes. |
+| implemented? | |
+| | | This is the default behaviour in TF-A. |
+| | Build options are also provided to save/restore |
+| | additional registers such as floating-point |
+| | registers. These should be enabled if required. |
++------------------------+------------------------------------------------------+
+
++------------------------+-----------------------------------------------------+
+| ID | 10 |
++========================+=====================================================+
+| Threat | | **SMC calls can leak sensitive information from |
+| | TF-A memory via microarchitectural side channels**|
+| | |
+| | | Microarchitectural side-channel attacks such as |
+| | `Spectre`_ can be used to leak data across |
+| | security boundaries. An attacker might attempt to |
+| | use this kind of attack to leak sensitive |
+| | data from TF-A memory. |
++------------------------+-----------------------------------------------------+
+| Diagram Elements | DF4, DF5 |
++------------------------+-----------------------------------------------------+
+| Affected TF-A | BL31 |
+| Components | |
++------------------------+-----------------------------------------------------+
+| Assets | Sensitive Data |
++------------------------+-----------------------------------------------------+
+| Threat Agent | SecCode, NSCode |
++------------------------+-----------------------------------------------------+
+| Threat Type | Information Disclosure |
++------------------------+-------------------+----------------+----------------+
+| Application | Server | IoT | Mobile |
++------------------------+-------------------+----------------+----------------+
+| Impact | Medium (3) | Medium (3) | Medium (3) |
++------------------------+-------------------+----------------+----------------+
+| Likelihood | Medium (3) | Medium (3) | Medium (3) |
++------------------------+-------------------+----------------+----------------+
+| Total Risk Rating | Medium (9) | Medium (9) | Medium (9) |
++------------------------+-------------------+----------------+----------------+
+| Mitigations | Enable appropriate side-channel protections. |
++------------------------+-----------------------------------------------------+
+| Mitigations | | Yes / Platform specific. |
+| implemented? | |
+| | | TF-A implements software mitigations for Spectre |
+| | type attacks as recommended by `Cache Speculation |
+| | Side-channels`_ for the generic code. |
+| | |
+| | | SiPs should implement similar mitigations for |
+| | code that is deemed to be vulnerable to such |
+| | attacks. |
++------------------------+-----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 11 |
++========================+====================================================+
+| Threat | | **Misconfiguration of the Memory Management Unit |
+| | (MMU) may allow a normal world software to |
+| | access sensitive data or execute arbitrary |
+| | code** |
+| | |
+| | | A misconfiguration of the MMU could |
+| | lead to an open door for software running in the |
+| | normal world to access sensitive data or even |
+| | execute code if the proper security mechanisms |
+| | are not in place. |
++------------------------+----------------------------------------------------+
+| Diagram Elements | DF5, DF6 |
++------------------------+----------------------------------------------------+
+| Affected TF-A | BL1, BL2, BL31 |
+| Components | |
++------------------------+----------------------------------------------------+
+| Assets | Sensitive Data, Code execution |
++------------------------+----------------------------------------------------+
+| Threat Agent | NSCode |
++------------------------+----------------------------------------------------+
+| Threat Type | Information Disclosure, Elevation of Privilege |
++------------------------+-----------------+-----------------+----------------+
+| Application | Server | IoT | Mobile |
++------------------------+-----------------+-----------------+----------------+
+| Impact | Critical (5) | Critical (5) | Critical (5) |
++------------------------+-----------------+-----------------+----------------+
+| Likelihood | High (4) | High (4) | High (4) |
++------------------------+-----------------+-----------------+----------------+
+| Total Risk Rating | Critical (20) | Critical (20) | Critical (20) |
++------------------------+-----------------+-----------------+----------------+
+| Mitigations | When configuring access permissions, the |
+| | principle of least privilege ought to be |
+| | enforced. This means we should not grant more |
+| | privileges than strictly needed, e.g. code |
+| | should be read-only executable, read-only data |
+| | should be read-only execute-never, and so on. |
++------------------------+----------------------------------------------------+
+| Mitigations | | Platform specific. |
+| implemented? | |
+| | | MMU configuration is platform specific, |
+| | therefore platforms need to make sure that the |
+| | correct attributes are assigned to memory |
+| | regions. |
+| | |
+| | | TF-A provides a library which abstracts the |
+| | low-level details of MMU configuration. It |
+| | provides well-defined and tested APIs. |
+| | Platforms are encouraged to use it to limit the |
+| | risk of misconfiguration. |
++------------------------+----------------------------------------------------+
+
++------------------------+-----------------------------------------------------+
+| ID | 12 |
++========================+=====================================================+
+| Threat | | **Incorrect configuration of Performance Monitor |
+| | Unit (PMU) counters can allow an attacker to |
+| | mount side-channel attacks using information |
+| | exposed by the counters** |
+| | |
+| | | Non-secure software can configure PMU registers |
+| | to count events at any exception level and in |
+| | both Secure and Non-secure states. This allows |
+| | a Non-secure software (or a lower-level Secure |
+| | software) to potentially carry out |
+| | side-channel timing attacks against TF-A. |
++------------------------+-----------------------------------------------------+
+| Diagram Elements | DF5, DF6 |
++------------------------+-----------------------------------------------------+
+| Affected TF-A | BL31 |
+| Components | |
++------------------------+-----------------------------------------------------+
+| Assets | Sensitive Data |
++------------------------+-----------------------------------------------------+
+| Threat Agent | NSCode |
++------------------------+-----------------------------------------------------+
+| Threat Type | Information Disclosure |
++------------------------+-------------------+----------------+----------------+
+| Impact | Medium (3) | Medium (3) | Medium (3) |
++------------------------+-------------------+----------------+----------------+
+| Likelihood | Low (2) | Low (2) | Low (2) |
++------------------------+-------------------+----------------+----------------+
+| Total Risk Rating | Medium (6) | Medium (6) | Medium (6) |
++------------------------+-------------------+----------------+----------------+
+| Mitigations | Follow mitigation strategies as described in |
+| | `Secure Development Guidelines`_. |
++------------------------+-----------------------------------------------------+
+| Mitigations | | Yes / platform specific. |
+| implemented? | |
+| | | General events and cycle counting in the Secure |
+| | world is prohibited by default when applicable. |
+| | |
+| | | However, on some implementations (e.g. PMUv3) |
+| | Secure world event counting depends on external |
+| | debug interface signals, i.e. Secure world event |
+| | counting is enabled if external debug is enabled. |
+| | |
+| | | Configuration of debug signals is platform |
+| | specific, therefore platforms need to make sure |
+| | that external debug is disabled in production or |
+| | proper debug authentication is in place. This |
+| | should be the case if threat #06 is properly |
+| | mitigated. |
++------------------------+-----------------------------------------------------+
+
+--------------
+
+*Copyright (c) 2021-2022, Arm Limited. All rights reserved.*
+
+
+.. _STRIDE threat analysis technique: https://docs.microsoft.com/en-us/azure/security/develop/threat-modeling-tool-threats#stride-model
+.. _DEN0034: https://developer.arm.com/documentation/den0034/latest
+.. _Cache Speculation Side-channels: https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability
+.. _Spectre: https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability
+.. _TBBR-Client specification: https://developer.arm.com/documentation/den0006/d/
+.. _Trusted Board Boot (TBB): https://trustedfirmware-a.readthedocs.io/en/latest/design/trusted-board-boot.html
+.. _TF-A error handling policy: https://trustedfirmware-a.readthedocs.io/en/latest/process/coding-guidelines.html#error-handling-and-robustness
+.. _Secure Development Guidelines: https://trustedfirmware-a.readthedocs.io/en/latest/process/security-hardening.html#secure-development-guidelines
+.. _Trusted Firmware-A Tests: https://git.trustedfirmware.org/TF-A/tf-a-tests.git/about/
diff --git a/docs/threat_model/threat_model_el3_spm.rst b/docs/threat_model/threat_model_el3_spm.rst
new file mode 100644
index 0000000..c3af7a2
--- /dev/null
+++ b/docs/threat_model/threat_model_el3_spm.rst
@@ -0,0 +1,650 @@
+EL3 SPMC Threat Model
+*********************
+
+************
+Introduction
+************
+This document provides a threat model for the TF-A `EL3 Secure Partition Manager`_
+(EL3 SPM) implementation. The EL3 SPM implementation is based on the
+`Arm Firmware Framework for Arm A-profile`_ specification.
+
+********************
+Target of Evaluation
+********************
+In this threat model, the target of evaluation is the ``Secure Partition Manager Core``
+component (SPMC) within the EL3 firmware.
+The monitor and SPMD at EL3 are covered by the `Generic TF-A threat model`_.
+
+The scope for this threat model is:
+
+- The TF-A implementation for the EL3 SPMC
+- The implementation complies with the FF-A v1.1 specification.
+- Secure partition is statically provisioned at boot time.
+- Focus on the run-time part of the life-cycle (no specific emphasis on boot
+ time, factory firmware provisioning, firmware udpate etc.)
+- Not covering advanced or invasive physical attacks such as decapsulation,
+ FIB etc.
+
+Data Flow Diagram
+=================
+Figure 1 shows a high-level data flow diagram for the SPM split into an SPMD
+and SPMC component at EL3. The SPMD mostly acts as a relayer/pass-through between
+the normal world and the secure world. It is assumed to expose small attack surface.
+
+A description of each diagram element is given in Table 1. In the diagram, the
+red broken lines indicate trust boundaries.
+
+Components outside of the broken lines are considered untrusted.
+
+.. uml:: ../resources/diagrams/plantuml/el3_spm_dfd.puml
+ :caption: Figure 1: EL3 SPMC Data Flow Diagram
+
+.. table:: Table 1: EL3 SPMC Data Flow Diagram Description
+
+ +---------------------+--------------------------------------------------------+
+ | Diagram Element | Description |
+ +=====================+========================================================+
+ | DF1 | SP to SPMC communication. FF-A function invocation or |
+ | | implementation-defined Hypervisor call. |
+ | | |
+ | | Note:- To communicate with LSP, SP1 performs a direct |
+ | | message request to SPMC targeting LSP as destination. |
+ +---------------------+--------------------------------------------------------+
+ | DF2 | SPMC to SPMD communication. |
+ +---------------------+--------------------------------------------------------+
+ | DF3 | SPMD to NS forwarding. |
+ +---------------------+--------------------------------------------------------+
+ | DF4 | SPMC to LSP communication. |
+ | | NWd to LSP communication happens through SPMC. |
+ | | LSP can send direct response SP1 or NWd through SPMC. |
+ +---------------------+--------------------------------------------------------+
+ | DF5 | HW control. |
+ +---------------------+--------------------------------------------------------+
+ | DF6 | Bootloader image loading. |
+ +---------------------+--------------------------------------------------------+
+ | DF7 | External memory access. |
+ +---------------------+--------------------------------------------------------+
+
+
+***************
+Threat Analysis
+***************
+
+This threat model follows a similar methodology to the `Generic TF-A threat model`_.
+The following sections define:
+
+- Trust boundaries
+- Assets
+- Theat agents
+- Threat types
+
+Trust boundaries
+================
+
+- Normal world is untrusted.
+- Secure world and normal world are separate trust boundaries.
+- EL3 monitor, SPMD and SPMC are trusted.
+- Bootloaders (in particular BL1/BL2 if using TF-A) and run-time BL31 are
+ implicitely trusted by the usage of trusted boot.
+- EL3 monitor, SPMD, SPMC do not trust SPs.
+
+Assets
+======
+
+The following assets are identified:
+
+- SPMC state.
+- SP state.
+- Information exchange between endpoints (partition messages).
+- SPMC secrets (e.g. pointer authentication key when enabled)
+- SP secrets (e.g. application keys).
+- Scheduling cycles.
+- Shared memory.
+
+Threat Agents
+=============
+
+The following threat agents are identified:
+
+- Non-secure endpoint (referred NS-Endpoint later): normal world client at
+ NS-EL2 (Hypervisor) or NS-EL1 (VM or OS kernel).
+- Secure endpoint (referred as S-Endpoint later): typically a secure partition.
+- Hardware attacks (non-invasive) requiring a physical access to the device,
+ such as bus probing or DRAM stress.
+
+Threat types
+============
+
+The following threat categories as exposed in the `Generic TF-A threat model`_
+are re-used:
+
+- Spoofing
+- Tampering
+- Repudiation
+- Information disclosure
+- Denial of service
+- Elevation of privileges
+
+Similarly this threat model re-uses the same threat risk ratings. The risk
+analysis is evaluated based on the environment being ``Server`` or ``Mobile``.
+IOT is not evaluated as the EL3 SPMC is primarily meant for use in Client.
+
+Threat Assessment
+=================
+
+The following threats are identified by applying STRIDE analysis on each diagram
+element of the data flow diagram.
+
++------------------------+----------------------------------------------------+
+| ID | 01 |
++========================+====================================================+
+| Threat | **An endpoint impersonates the sender |
+| | FF-A ID in a direct request/response invocation.** |
++------------------------+----------------------------------------------------+
+| Diagram Elements | DF1, DF2, DF3, DF4 |
++------------------------+----------------------------------------------------+
+| Affected TF-A | SPMD, SPMC |
+| Components | |
++------------------------+----------------------------------------------------+
+| Assets | SP state |
++------------------------+----------------------------------------------------+
+| Threat Agent | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| Threat Type | Spoofing |
++------------------------+--------------------------+-------------------------+
+| Application | Server | Mobile |
++------------------------+--------------------------++------------------------+
+| Impact | Critical(5) | Critical(5) |
++------------------------+--------------------------++------------------------+
+| Likelihood | Critical(5) | Critical(5) |
++------------------------+--------------------------++------------------------+
+| Total Risk Rating | Critical(25) | Critical(25) |
++------------------------+--------------------------+-------------------------+
+| Mitigations | SPMC must be able to correctly identify an |
+| | endpoint and enforce checks to disallow spoofing. |
++------------------------+----------------------------------------------------+
+| Mitigations | Yes. |
+| implemented? | The SPMC enforces checks in the direct message |
+| | request/response interfaces such an endpoint cannot|
+| | spoof the origin and destination worlds (e.g. a NWd|
+| | originated message directed to the SWd cannot use a|
+| | SWd ID as the sender ID). |
+| | Also enforces check for direct response being sent |
+| | only to originator of request. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 02 |
++========================+====================================================+
+| Threat | **An endpoint impersonates the receiver |
+| | FF-A ID in a direct request/response invocation.** |
++------------------------+----------------------------------------------------+
+| Diagram Elements | DF1, DF2, DF3, DF4 |
++------------------------+----------------------------------------------------+
+| Affected TF-A | SPMD, SPMC |
+| Components | |
++------------------------+----------------------------------------------------+
+| Assets | SP state |
++------------------------+----------------------------------------------------+
+| Threat Agent | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| Threat Type | Spoofing, Denial of Service |
++------------------------+--------------------------+-------------------------+
+| Application | Server | Mobile |
++------------------------+--------------------------++------------------------+
+| Impact | Critical(5) | Critical(5) |
++------------------------+--------------------------++------------------------+
+| Likelihood | Critical(5) | Critical(5) |
++------------------------+--------------------------++------------------------+
+| Total Risk Rating | Critical(25) | Critical(25) |
++------------------------+--------------------------+-------------------------+
+| Mitigations | Validate if endpoind has permission to send |
+| | request to other endpoint by implementation |
+| | defined means. |
++------------------------+----------------------------------------------------+
+| Mitigations | Platform specific. |
+| implemented? | |
+| | The guidance below is left for a system integrator |
+| | to implement as necessary. |
+| | |
+| | Additionally a software component residing in the |
+| | SPMC can be added for the purpose of direct |
+| | request/response filtering. |
+| | |
+| | It can be configured with the list of known IDs |
+| | and about which interaction can occur between one |
+| | and another endpoint (e.g. which NWd endpoint ID |
+| | sends a direct request to which SWd endpoint ID). |
+| | |
+| | This component checks the sender/receiver fields |
+| | for a legitimate communication between endpoints. |
+| | |
+| | A similar component can exist in the OS kernel |
+| | driver, or Hypervisor although it remains untrusted|
+| | by the SPMD/SPMC. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 03 |
++========================+====================================================+
+| Threat | **Tampering with memory shared between an endpoint |
+| | and the SPMC.** |
+| | |
+| | A malicious endpoint may attempt tampering with its|
+| | RX/TX buffer contents while the SPMC is processing |
+| | it (TOCTOU). |
++------------------------+----------------------------------------------------+
+| Diagram Elements | DF1, DF3, DF7 |
++------------------------+----------------------------------------------------+
+| Affected TF-A | SPMC |
+| Components | |
++------------------------+----------------------------------------------------+
+| Assets | Shared memory, Information exchange |
++------------------------+----------------------------------------------------+
+| Threat Agent | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| Threat Type | Tampering |
++------------------------+--------------------------+-------------------------+
+| Application | Server | Mobile |
++------------------------+--------------------------+-------------------------+
+| Impact | High (4) | High (4) |
++------------------------+--------------------------+-------------------------+
+| Likelihood | High (4) | High (4) |
++------------------------+--------------------------+-------------------------+
+| Total Risk Rating | High (16) | High (16) |
++------------------------+--------------------------+-------------------------+
+| Mitigations | Validate all inputs, copy before use. |
++------------------------+----------------------------------------------------+
+| Mitigations | Yes. In context of FF-A v1.1 this is the case of |
+| implemented? | sharing the RX/TX buffer pair and usage in the |
+| | PARTITION_INFO_GET or memory sharing primitives. |
+| | |
+| | The SPMC copies the contents of the TX buffer |
+| | to an internal temporary buffer before processing |
+| | its contents. The SPMC implements hardened input |
+| | validation on data transmitted through the TX |
+| | buffer by an untrusted endpoint. |
+| | |
+| | The TF-A SPMC enforces |
+| | checks on data transmitted through RX/TX buffers. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 04 |
++========================+====================================================+
+| Threat | **An endpoint may tamper with its own state or the |
+| | state of another endpoint.** |
+| | |
+| | A malicious endpoint may attempt violating: |
+| | |
+| | - its own or another SP state by using an unusual |
+| | combination (or out-of-order) FF-A function |
+| | invocations. |
+| | This can also be an endpoint emitting FF-A |
+| | function invocations to another endpoint while |
+| | the latter in not in a state to receive it (e.g. |
+| | SP sends a direct request to the normal world |
+| | early while the normal world is not booted yet). |
+| | - the SPMC state itself by employing unexpected |
+| | transitions in FF-A memory sharing, direct |
+| | requests and responses, or handling of interrupts|
+| | This can be led by random stimuli injection or |
+| | fuzzing. |
++------------------------+----------------------------------------------------+
+| Diagram Elements | DF1, DF2, DF3 |
++------------------------+----------------------------------------------------+
+| Affected TF-A | SPMD, SPMC |
+| Components | |
++------------------------+----------------------------------------------------+
+| Assets | SP state, SPMC state |
++------------------------+----------------------------------------------------+
+| Threat Agent | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| Threat Type | Tampering |
++------------------------+--------------------------+-------------------------+
+| Application | Server | Mobile |
++------------------------+--------------------------+-------------------------+
+| Impact | High (4) | High (4) |
++------------------------+--------------------------+-------------------------+
+| Likelihood | Medium (3) | Medium (3) |
++------------------------+--------------------------+-------------------------+
+| Total Risk Rating | High (12) | High (12) |
++------------------------+------------------+-----------------+---------------+
+| Mitigations | Follow guidelines in FF-A v1.1 specification on |
+| | state transitions (run-time model). |
++------------------------+----------------------------------------------------+
+| Mitigations | Yes. The TF-A SPMC is hardened to follow this |
+| implemented? | guidance. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 05 |
++========================+====================================================+
+| Threat | **Replay fragments of past communication between |
+| | endpoints.** |
+| | |
+| | A malicious endpoint may replay a message exchange |
+| | that occurred between two legitimate endpoints as |
+| | a matter of triggering a malfunction or extracting |
+| | secrets from the receiving endpoint. In particular |
+| | the memory sharing operation with fragmented |
+| | messages between an endpoint and the SPMC may be |
+| | replayed by a malicious agent as a matter of |
+| | getting access or gaining permissions to a memory |
+| | region which does not belong to this agent. |
++------------------------+----------------------------------------------------+
+| Diagram Elements | DF2, DF3 |
++------------------------+----------------------------------------------------+
+| Affected TF-A | SPMC |
+| Components | |
++------------------------+----------------------------------------------------+
+| Assets | Information exchange |
++------------------------+----------------------------------------------------+
+| Threat Agent | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| Threat Type | Repudiation |
++------------------------+--------------------------+-------------------------+
+| Application | Server | Mobile |
++------------------------+--------------------------+-------------------------+
+| Impact | Medium (3) | Medium (3) |
++------------------------+--------------------------+-------------------------+
+| Likelihood | High (4) | High (4) |
++------------------------+--------------------------+-------------------------+
+| Total Risk Rating | High (12) | High (12) |
++------------------------+--------------------------+-------------------------+
+| Mitigations | Strict input validation and state tracking. |
++------------------------+----------------------------------------------------+
+| Mitigations | Platform specific. |
+| implemented? | |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 06 |
++========================+====================================================+
+| Threat | **A malicious endpoint may attempt to extract data |
+| | or state information by the use of invalid or |
+| | incorrect input arguments.** |
+| | |
+| | Lack of input parameter validation or side effects |
+| | of maliciously forged input parameters might affect|
+| | the SPMC. |
++------------------------+----------------------------------------------------+
+| Diagram Elements | DF1, DF2, DF3 |
++------------------------+----------------------------------------------------+
+| Affected TF-A | SPMD, SPMC |
+| Components | |
++------------------------+----------------------------------------------------+
+| Assets | SP secrets, SPMC secrets, SP state, SPMC state |
++------------------------+----------------------------------------------------+
+| Threat Agent | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| Threat Type | Information discolure |
++------------------------+--------------------------+-------------------------+
+| Application | Server | Mobile |
++------------------------+--------------------------+-------------------------+
+| Impact | High (4) | High (4) |
++------------------------+--------------------------+-------------------------+
+| Likelihood | Medium (3) | Medium (3) |
++------------------------+--------------------------+-------------------------+
+| Total Risk Rating | High (12) | High (12) |
++------------------------+--------------------------+-------------------------+
+| Mitigations | SPMC must be prepared to receive incorrect input |
+| | data from secure partitions and reject them |
+| | appropriately. |
+| | The use of software (canaries) or hardware |
+| | hardening techniques (XN, WXN, pointer |
+| | authentication) helps detecting and stopping |
+| | an exploitation early. |
++------------------------+----------------------------------------------------+
+| Mitigations | Yes. The TF-A SPMC mitigates this threat by |
+| implemented? | implementing stack protector, pointer |
+| | authentication, XN, WXN, security hardening |
+| | techniques. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 07 |
++========================+====================================================+
+| Threat | **A malicious endpoint may forge a direct message |
+| | request such that it reveals the internal state of |
+| | another endpoint through the direct message |
+| | response.** |
+| | |
+| | The secure partition or SPMC replies to a partition|
+| | message by a direct message response with |
+| | information which may reveal its internal state |
+| | (e.g. partition message response outside of |
+| | allowed bounds). |
++------------------------+----------------------------------------------------+
+| Diagram Elements | DF1, DF2, DF3 |
++------------------------+----------------------------------------------------+
+| Affected TF-A | SPMC |
+| Components | |
++------------------------+----------------------------------------------------+
+| Assets | SPMC or SP state |
++------------------------+----------------------------------------------------+
+| Threat Agent | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| Threat Type | Information discolure |
++------------------------+--------------------------+-------------------------+
+| Application | Server | Mobile |
++------------------------+--------------------------+-------------------------+
+| Impact | Medium (3) | Medium (3) |
++------------------------+--------------------------+-------------------------+
+| Likelihood | Low (2) | Low (2) |
++------------------------+--------------------------+-------------------------+
+| Total Risk Rating | Medium (6) | Medium (6) |
++------------------------+--------------------------+-------------------------+
+| Mitigations | Follow FF-A specification about state transitions, |
+| | run time model, do input validation. |
++------------------------+----------------------------------------------------+
+| Mitigations | Yes. For the specific case of direct requests |
+| implemented? | targeting the SPMC, the latter is hardened to |
+| | prevent its internal state or the state of an SP |
+| | to be revealed through a direct message response. |
+| | Further FF-A v1.1 guidance about run time models |
+| | and partition states is followed. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 08 |
++========================+====================================================+
+| Threat | **Probing the FF-A communication between |
+| | endpoints.** |
+| | |
+| | SPMC and SPs are typically loaded to external |
+| | memory (protected by a TrustZone memory |
+| | controller). A malicious agent may use non invasive|
+| | methods to probe the external memory bus and |
+| | extract the traffic between an SP and the SPMC or |
+| | among SPs when shared buffers are held in external |
+| | memory. |
++------------------------+----------------------------------------------------+
+| Diagram Elements | DF7 |
++------------------------+----------------------------------------------------+
+| Affected TF-A | SPMC |
+| Components | |
++------------------------+----------------------------------------------------+
+| Assets | SP/SPMC state, SP/SPMC secrets |
++------------------------+----------------------------------------------------+
+| Threat Agent | Hardware attack |
++------------------------+----------------------------------------------------+
+| Threat Type | Information disclosure |
++------------------------+--------------------------+-------------------------+
+| Application | Server | Mobile |
++------------------------+--------------------------+-------------------------+
+| Impact | Medium (3) | Medium (3) |
++------------------------+--------------------------+-------------------------+
+| Likelihood | Low (2) | Medium (3) |
++------------------------+--------------------------+-------------------------+
+| Total Risk Rating | Medium (6) | Medium (9) |
++------------------------+--------------------------+-------------------------+
+| Mitigations | Implement DRAM protection techniques using |
+| | hardware countermeasures at platform or chip level.|
++------------------------+--------------------------+-------------------------+
+| Mitigations | Platform specific. |
+| implemented? | |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 09 |
++========================+====================================================+
+| Threat | **A malicious agent may attempt revealing the SPMC |
+| | state or secrets by the use of software-based cache|
+| | side-channel attack techniques.** |
++------------------------+----------------------------------------------------+
+| Diagram Elements | DF7 |
++------------------------+----------------------------------------------------+
+| Affected TF-A | SPMC |
+| Components | |
++------------------------+----------------------------------------------------+
+| Assets | SP or SPMC state |
++------------------------+----------------------------------------------------+
+| Threat Agent | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| Threat Type | Information disclosure |
++------------------------+--------------------------+-------------------------+
+| Application | Server | Mobile |
++------------------------+--------------------------+-------------------------+
+| Impact | Medium (3) | Medium (3) |
++------------------------+--------------------------+-------------------------+
+| Likelihood | Low (2) | Low (2) |
++------------------------+--------------------------+-------------------------+
+| Total Risk Rating | Medium (6) | Medium (6) |
++------------------------+--------------------------+-------------------------+
+| Mitigations | The SPMC may be hardened further with SW |
+| | mitigations (e.g. speculation barriers) for the |
+| | cases not covered in HW. Usage of hardened |
+| | compilers and appropriate options, code inspection |
+| | are recommended ways to mitigate Spectre types of |
+| | attacks. |
++------------------------+----------------------------------------------------+
+| Mitigations | No. |
+| implemented? | |
++------------------------+----------------------------------------------------+
+
+
++------------------------+----------------------------------------------------+
+| ID | 10 |
++========================+====================================================+
+| Threat | **A malicious endpoint may attempt flooding the |
+| | SPMC with requests targeting a service within an |
+| | endpoint such that it denies another endpoint to |
+| | access this service.** |
+| | |
+| | Similarly, the malicious endpoint may target a |
+| | a service within an endpoint such that the latter |
+| | is unable to request services from another |
+| | endpoint. |
++------------------------+----------------------------------------------------+
+| Diagram Elements | DF1, DF2, DF3 |
++------------------------+----------------------------------------------------+
+| Affected TF-A | SPMC |
+| Components | |
++------------------------+----------------------------------------------------+
+| Assets | SPMC state, Scheduling cycles |
++------------------------+----------------------------------------------------+
+| Threat Agent | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| Threat Type | Denial of service |
++------------------------+--------------------------+-------------------------+
+| Application | Server | Mobile |
++------------------------+--------------------------+-------------------------+
+| Impact | Medium (3) | Medium (3) |
++------------------------+--------------------------+-------------------------+
+| Likelihood | Medium (3) | Medium (3) |
++------------------------+--------------------------+-------------------------+
+| Total Risk Rating | Medium (9) | Medium (9) |
++------------------------+--------------------------+-------------------------+
+| Mitigations | Bounding the time for operations to complete can |
+| | be achieved by the usage of a trusted watchdog. |
+| | Other quality of service monitoring can be achieved|
+| | in the SPMC such as counting a number of operations|
+| | in a limited timeframe. |
++------------------------+----------------------------------------------------+
+| Mitigations | Platform specific. |
+| implemented? | |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 11 |
++========================+====================================================+
+| Threat | **Denying a lender endpoint to make progress if |
+| | borrower endpoint encountered a fatal exception. |
+| | Denying a new sender endpoint to make progress |
+| | if receiver encountered a fatal exception.** |
++------------------------+----------------------------------------------------+
+| Diagram Elements | DF1, DF2, DF3 |
++------------------------+----------------------------------------------------+
+| Affected TF-A | SPMC |
+| Components | |
++------------------------+----------------------------------------------------+
+| Assets | Shared resources, Scheduling cycles. |
++------------------------+----------------------------------------------------+
+| Threat Agent | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| Threat Type | Denial of service |
++------------------------+--------------------------+-------------------------+
+| Application | Server | Mobile |
++------------------------+--------------------------+-------------------------+
+| Impact | Medium (3) | Medium (3) |
++------------------------+--------------------------+-------------------------+
+| Likelihood | Medium (3) | Medium (3) |
++------------------------+--------------------------+-------------------------+
+| Total Risk Rating | Medium (9) | Medium (9) |
++------------------------+--------------------------+-------------------------+
+| Mitigations | SPMC must be able to detect fatal error in SP and |
+| | take ownership of shared resources. It should |
+| | be able to relinquish the access to shared memory |
+| | regions to allow lender to proceed. |
+| | SPMC must return ABORTED if new direct requests are|
+| | targeted to SP which has had a fatal error. |
++------------------------+----------------------------------------------------+
+| Mitigations | Platform specific. |
+| implemented? | |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 12 |
++========================+====================================================+
+| Threat | **A malicious endpoint may attempt to donate, |
+| | share, lend, relinquish or reclaim unauthorized |
+| | memory region.** |
++------------------------+----------------------------------------------------+
+| Diagram Elements | DF1, DF2, DF3 |
++------------------------+----------------------------------------------------+
+| Affected TF-A | SPMC |
+| Components | |
++------------------------+----------------------------------------------------+
+| Assets | SP secrets, SPMC secrets, SP state, SPMC state |
++------------------------+----------------------------------------------------+
+| Threat Agent | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| Threat Type | Elevation of Privilege |
++------------------------+--------------------------+-------------------------+
+| Application | Server | Mobile |
++------------------------+--------------------------+-------------------------+
+| Impact | High (4) | High (4) |
++------------------------+--------------------------+-------------------------+
+| Likelihood | High (4) | High (4) |
++------------------------+--------------------------+-------------------------+
+| Total Risk Rating | High (16) | High (16) |
++------------------------+--------------------------+-------------------------+
+| Mitigations | Follow FF-A specification guidelines |
+| | on Memory management transactions. |
++------------------------+----------------------------------------------------+
+| Mitigations | Yes. The SPMC tracks ownership and access state |
+| implemented? | for memory transactions appropriately, and |
+| | validating the same for all operations. |
+| | SPMC follows FF-A v1.1 |
+| | guidance for memory transaction lifecycle. |
++------------------------+----------------------------------------------------+
+
+---------------
+
+*Copyright (c) 2022, Arm Limited. All rights reserved.*
+
+.. _Arm Firmware Framework for Arm A-profile: https://developer.arm.com/docs/den0077/latest
+.. _EL3 Secure Partition Manager: ../components/el3-spmc.html
+.. _Generic TF-A threat model: ./threat_model.html#threat-analysis
+.. _FF-A ACS: https://github.com/ARM-software/ff-a-acs/releases
diff --git a/docs/threat_model/threat_model_fvp_r.rst b/docs/threat_model/threat_model_fvp_r.rst
new file mode 100644
index 0000000..c1462bb
--- /dev/null
+++ b/docs/threat_model/threat_model_fvp_r.rst
@@ -0,0 +1,97 @@
+fvp_r-Platform Threat Model
+***************************
+
+************************
+Introduction
+************************
+This document provides a threat model for TF-A fvp_r platform.
+
+************************
+Target of Evaluation
+************************
+In this threat model, the target of evaluation is the fvp_r platform of Trusted
+Firmware for A-class Processors (TF-A). The fvp_r platform provides limited
+support of AArch64 R-class Processors (v8-R64).
+
+This is a delta document, only pointing out differences from the general TF-A
+threat-model document, :ref:`Generic Threat Model`
+
+BL1 Only
+========
+The most fundamental difference between the threat model for the current fvp_r
+implementation compared to the general TF-A threat model, is that fvp_r is
+currently limited to BL1 only. Any threats from the general TF-A threat model
+unrelated to BL1 are therefore not relevant to the fvp_r implementation.
+
+The fvp_r BL1 implementation directly loads a customer/partner-defined runtime
+system. The threat model for that runtime system, being partner-defined, is
+out-of-scope for this threat-model.
+
+Relatedly, all exceptions, synchronous and asynchronous, are disabled during BL1
+execution. So, any references to exceptions are not relevant.
+
+EL3 is Unsupported and All Secure
+=================================
+v8-R64 cores do not support EL3, and (essentially) all operation is defined as
+Secure-mode. Therefore:
+
+ - Any threats regarding NS operation are not relevant.
+
+ - Any mentions of SMCs are also not relevant.
+
+ - Anything otherwise-relevant code running in EL3 is instead run in EL2.
+
+MPU instead of MMU
+==================
+v8-R64 cores, running in EL2, use an MPU for memory management, rather than an
+MMU. The MPU in the fvp_r implementation is configured to function effectively
+identically with the MMU for the usual BL1 implementation. There are
+memory-map differences, but the MPU configuration is functionally equivalent.
+
+No AArch32 Support
+==================
+Another substantial difference between v8-A and v8-R64 cores is that v8-R64 does
+not support AArch32. However, this is not believed to have any threat-modeling
+ramifications.
+
+
+Threat Assessment
+=================
+For this section, please reference the Threat Assessment under the general TF-A
+threat-model document, :ref:`Generic Threat Model`
+
+The following threats from that document are still relevant to the fvp_r
+implementation:
+
+ - ID 01: An attacker can mangle firmware images to execute arbitrary code.
+
+ - ID 03: An attacker can use Time-of-Check-Time-of-Use (TOCTOU) attack to
+ bypass image authentication during the boot process.
+
+ - ID 04: An attacker with physical access can execute arbitrary image by
+ bypassing the signature verification stage using clock- or power-glitching
+ techniques.
+
+ - ID 05: Information leak via UART logs such as crashes
+
+ - ID 06: An attacker can read sensitive data and execute arbitrary code
+ through the external debug and trace interface.
+
+ - ID 08: Memory corruption due to memory overflows and lack of boundary
+ checking when accessing resources could allow an attacker to execute
+ arbitrary code, modify some state variable to change the normal flow of
+ the program, or leak sensitive.
+
+ - ID 11: Misconfiguration of the Memory Protection Unit (MPU) may allow
+ normal world software to access sensitive data or execute arbitrary code.
+ Arguably, MPUs having fewer memory regions, there may be a temptation to
+ share memory regions, making this a greater threat. However, since the
+ fvp_r implementation is limited to BL1, since BL1's regions are fixed,
+ and since the MPU configuration is equivalent with that for the fvp
+ platform and others, this is not expected to be a concern.
+
+
+
+--------------
+
+*Copyright (c) 2021, Arm Limited. All rights reserved.*
diff --git a/docs/threat_model/threat_model_spm.rst b/docs/threat_model/threat_model_spm.rst
new file mode 100644
index 0000000..98dbf76
--- /dev/null
+++ b/docs/threat_model/threat_model_spm.rst
@@ -0,0 +1,1161 @@
+SPMC Threat Model
+*****************
+
+************************
+Introduction
+************************
+This document provides a threat model for the TF-A `Secure Partition Manager`_
+(SPM) implementation or more generally the S-EL2 reference firmware running on
+systems implementing the FEAT_SEL2 (formerly Armv8.4 Secure EL2) architecture
+extension. The SPM implementation is based on the `Arm Firmware Framework for
+Arm A-profile`_ specification.
+
+In brief, the broad FF-A specification and S-EL2 firmware implementation
+provide:
+
+- Isolation of mutually mistrusting SW components, or endpoints in the FF-A
+ terminology.
+- Distinct sandboxes in the secure world called secure partitions. This permits
+ isolation of services from multiple vendors.
+- A standard protocol for communication and memory sharing between FF-A
+ endpoints.
+- Mutual isolation of the normal world and the secure world (e.g. a Trusted OS
+ is prevented to map an arbitrary NS physical memory region such as the kernel
+ or the Hypervisor).
+
+************************
+Target of Evaluation
+************************
+In this threat model, the target of evaluation is the S-EL2 firmware or the
+``Secure Partition Manager Core`` component (SPMC).
+The monitor and SPMD at EL3 are covered by the `Generic TF-A threat model`_.
+
+The scope for this threat model is:
+
+- The TF-A implementation for the S-EL2 SPMC based on the Hafnium hypervisor
+ running in the secure world of TrustZone (at S-EL2 exception level).
+ The threat model is not related to the normal world Hypervisor or VMs.
+ The S-EL1 SPMC solution is not covered.
+- The implementation complies with the FF-A v1.0 specification, and a few
+ features of FF-A v1.1 specification.
+- Secure partitions are statically provisioned at boot time.
+- Focus on the run-time part of the life-cycle (no specific emphasis on boot
+ time, factory firmware provisioning, firmware udpate etc.)
+- Not covering advanced or invasive physical attacks such as decapsulation,
+ FIB etc.
+- Assumes secure boot or in particular TF-A trusted boot (TBBR or dual CoT) is
+ enabled. An attacker cannot boot arbitrary images that are not approved by the
+ SiP or platform providers.
+
+Data Flow Diagram
+======================
+Figure 1 shows a high-level data flow diagram for the SPM split into an SPMD
+component at EL3 and an SPMC component at S-EL2. The SPMD mostly acts as a
+relayer/pass-through between the normal world and the secure world. It is
+assumed to expose small attack surface.
+
+A description of each diagram element is given in Table 1. In the diagram, the
+red broken lines indicate trust boundaries.
+
+Components outside of the broken lines are considered untrusted.
+
+.. uml:: ../resources/diagrams/plantuml/spm_dfd.puml
+ :caption: Figure 1: SPMC Data Flow Diagram
+
+.. table:: Table 1: SPMC Data Flow Diagram Description
+
+ +---------------------+--------------------------------------------------------+
+ | Diagram Element | Description |
+ +=====================+========================================================+
+ | ``DF1`` | SP to SPMC communication. FF-A function invocation or |
+ | | implementation-defined Hypervisor call. |
+ +---------------------+--------------------------------------------------------+
+ | ``DF2`` | SPMC to SPMD FF-A call. |
+ +---------------------+--------------------------------------------------------+
+ | ``DF3`` | SPMD to NS forwarding. |
+ +---------------------+--------------------------------------------------------+
+ | ``DF4`` | SP to SP FF-A direct message request/response. |
+ | | Note as a matter of simplifying the diagram |
+ | | the SP to SP communication happens through the SPMC |
+ | | (SP1 performs a direct message request to the |
+ | | SPMC targeting SP2 as destination. And similarly for |
+ | | the direct message response from SP2 to SP1). |
+ +---------------------+--------------------------------------------------------+
+ | ``DF5`` | HW control. |
+ +---------------------+--------------------------------------------------------+
+ | ``DF6`` | Bootloader image loading. |
+ +---------------------+--------------------------------------------------------+
+ | ``DF7`` | External memory access. |
+ +---------------------+--------------------------------------------------------+
+
+*********************
+Threat Analysis
+*********************
+
+This threat model follows a similar methodology to the `Generic TF-A threat model`_.
+The following sections define:
+
+- Trust boundaries
+- Assets
+- Theat agents
+- Threat types
+
+Trust boundaries
+============================
+
+- Normal world is untrusted.
+- Secure world and normal world are separate trust boundaries.
+- EL3 monitor, SPMD and SPMC are trusted.
+- Bootloaders (in particular BL1/BL2 if using TF-A) and run-time BL31 are
+ implicitely trusted by the usage of secure boot.
+- EL3 monitor, SPMD, SPMC do not trust SPs.
+
+.. figure:: ../resources/diagrams/spm-threat-model-trust-boundaries.png
+
+ Figure 2: Trust boundaries
+
+Assets
+============================
+
+The following assets are identified:
+
+- SPMC state.
+- SP state.
+- Information exchange between endpoints (partition messages).
+- SPMC secrets (e.g. pointer authentication key when enabled)
+- SP secrets (e.g. application keys).
+- Scheduling cycles.
+- Shared memory.
+
+Threat Agents
+============================
+
+The following threat agents are identified:
+
+- NS-Endpoint identifies a non-secure endpoint: normal world client at NS-EL2
+ (Hypervisor) or NS-EL1 (VM or OS kernel).
+- S-Endpoint identifies a secure endpoint typically a secure partition.
+- Hardware attacks (non-invasive) requiring a physical access to the device,
+ such as bus probing or DRAM stress.
+
+Threat types
+============================
+
+The following threat categories as exposed in the `Generic TF-A threat model`_
+are re-used:
+
+- Spoofing
+- Tampering
+- Repudiation
+- Information disclosure
+- Denial of service
+- Elevation of privileges
+
+Similarly this threat model re-uses the same threat risk ratings. The risk
+analysis is evaluated based on the environment being ``Server`` or ``Mobile``.
+
+Threat Assessment
+============================
+
+The following threats are identified by applying STRIDE analysis on each diagram
+element of the data flow diagram.
+
++------------------------+----------------------------------------------------+
+| ID | 01 |
++========================+====================================================+
+| ``Threat`` | **An endpoint impersonates the sender or receiver |
+| | FF-A ID in a direct request/response invocation.** |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF2, DF3, DF4 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMD, SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SP state |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Spoofing |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------++----------------+---------------+
+| ``Impact`` | Critical(5) | Critical(5) | |
++------------------------+------------------++----------------+---------------+
+| ``Likelihood`` | Critical(5) | Critical(5) | |
++------------------------+------------------++----------------+---------------+
+| ``Total Risk Rating`` | Critical(25) | Critical(25) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | The TF-A SPMC does not mitigate this threat. |
+| | The guidance below is left for a system integrator |
+| | to implemented as necessary. |
+| | The SPMC must enforce checks in the direct message |
+| | request/response interfaces such an endpoint cannot|
+| | spoof the origin and destination worlds (e.g. a NWd|
+| | originated message directed to the SWd cannot use a|
+| | SWd ID as the sender ID). |
+| | Additionally a software component residing in the |
+| | SPMC can be added for the purpose of direct |
+| | request/response filtering. |
+| | It can be configured with the list of known IDs |
+| | and about which interaction can occur between one |
+| | and another endpoint (e.g. which NWd endpoint ID |
+| | sends a direct request to which SWd endpoint ID). |
+| | This component checks the sender/receiver fields |
+| | for a legitimate communication between endpoints. |
+| | A similar component can exist in the OS kernel |
+| | driver, or Hypervisor although it remains untrusted|
+| | by the SPMD/SPMC. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 02 |
++========================+====================================================+
+| ``Threat`` | **Tampering with memory shared between an endpoint |
+| | and the SPMC.** |
+| | A malicious endpoint may attempt tampering with its|
+| | RX/TX buffer contents while the SPMC is processing |
+| | it (TOCTOU). |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF3, DF4, DF7 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | Shared memory, Information exchange |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Tampering |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+-----------------+---------------+
+| ``Impact`` | High (4) | High (4) | |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood`` | High (4) | High (4) | |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating`` | High (16) | High (16) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | In context of FF-A v1.0 this is the case of sharing|
+| | the RX/TX buffer pair and usage in the |
+| | PARTITION_INFO_GET or mem sharing primitives. |
+| | The SPMC must copy the contents of the TX buffer |
+| | to an internal temporary buffer before processing |
+| | its contents. The SPMC must implement hardened |
+| | input validation on data transmitted through the TX|
+| | buffer by an untrusted endpoint. |
+| | The TF-A SPMC mitigates this threat by enforcing |
+| | checks on data transmitted through RX/TX buffers. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 03 |
++========================+====================================================+
+| ``Threat`` | **An endpoint may tamper with its own state or the |
+| | state of another endpoint.** |
+| | A malicious endpoint may attempt violating: |
+| | - its own or another SP state by using an unusual |
+| | combination (or out-of-order) FF-A function |
+| | invocations. |
+| | This can also be an endpoint emitting |
+| | FF-A function invocations to another endpoint while|
+| | the latter is not in a state to receive it (e.g. a |
+| | SP sends a direct request to the normal world early|
+| | while the normal world is not booted yet). |
+| | - the SPMC state itself by employing unexpected |
+| | transitions in FF-A memory sharing, direct requests|
+| | and responses, or handling of interrupts. |
+| | This can be led by random stimuli injection or |
+| | fuzzing. |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF2, DF3, DF4 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMD, SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SP state, SPMC state |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Tampering |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+-----------------+---------------+
+| ``Impact`` | High (4) | High (4) | |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood`` | Medium (3) | Medium (3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating`` | High (12) | High (12) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | The TF-A SPMC provides mitigation against such |
+| | threat by following the guidance for partition |
+| | runtime models as described in FF-A v1.1 EAC0 spec.|
+| | The SPMC performs numerous checks in runtime to |
+| | prevent illegal state transitions by adhering to |
+| | the partition runtime model. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 04 |
++========================+====================================================+
+| ``Threat`` | *An attacker may attempt injecting errors by the |
+| | use of external DRAM stress techniques.** |
+| | A malicious agent may attempt toggling an SP |
+| | Stage-2 MMU descriptor bit within the page tables |
+| | that the SPMC manages. This can happen in Rowhammer|
+| | types of attack. |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF7 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SP or SPMC state |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | Hardware attack |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Tampering |
++------------------------+------------------+---------------+-----------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+---------------+-----------------+
+| ``Impact`` | High (4) | High (4) | |
++------------------------+------------------+---------------+-----------------+
+| ``Likelihood`` | Low (2) | Medium (3) | |
++------------------------+------------------+---------------+-----------------+
+| ``Total Risk Rating`` | Medium (8) | High (12) | |
++------------------------+------------------+---------------+-----------------+
+| ``Mitigations`` | The TF-A SPMC does not provide mitigations to this |
+| | type of attack. It can be addressed by the use of |
+| | dedicated HW circuity or hardening at the chipset |
+| | or platform level left to the integrator. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 05 |
++========================+====================================================+
+| ``Threat`` | **Protection of the SPMC from a DMA capable device |
+| | upstream to an SMMU.** |
+| | A device may attempt to tamper with the internal |
+| | SPMC code/data sections. |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF5 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SPMC or SP state |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Tampering, Elevation of privileges |
++------------------------+------------------+---------------+-----------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+---------------+-----------------+
+| ``Impact`` | High (4) | High (4) | |
++------------------------+------------------+---------------+-----------------+
+| ``Likelihood`` | Medium (3) | Medium (3) | |
++------------------------+------------------+---------------+-----------------+
+| ``Total Risk Rating`` | High (12) | High (12) | |
++------------------------+------------------+---------------+-----------------+
+| ``Mitigations`` | A platform may prefer assigning boot time, |
+| | statically alocated memory regions through the SMMU|
+| | configuration and page tables. The FF-A v1.1 |
+| | specification provisions this capability through |
+| | static DMA isolation. |
+| | The TF-A SPMC does not mitigate this threat. |
+| | It will adopt the static DMA isolation approach in |
+| | a future release. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 06 |
++========================+====================================================+
+| ``Threat`` | **Replay fragments of past communication between |
+| | endpoints.** |
+| | A malicious endpoint may replay a message exchange |
+| | that occured between two legitimate endpoint as |
+| | a matter of triggering a malfunction or extracting |
+| | secrets from the receiving endpoint. In particular |
+| | the memory sharing operation with fragmented |
+| | messages between an endpoint and the SPMC may be |
+| | replayed by a malicious agent as a matter of |
+| | getting access or gaining permissions to a memory |
+| | region which does not belong to this agent. |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF2, DF3 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | Information exchange |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Repdudiation |
++------------------------+------------------+---------------+-----------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+---------------+-----------------+
+| ``Impact`` | Medium (3) | Medium (3) | |
++------------------------+------------------+---------------+-----------------+
+| ``Likelihood`` | High (4) | High (4) | |
++------------------------+------------------+---------------+-----------------+
+| ``Total Risk Rating`` | High (12) | High (12) | |
++------------------------+------------------+---------------+-----------------+
+| ``Mitigations`` | The TF-A SPMC does not mitigate this threat. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 07 |
++========================+====================================================+
+| ``Threat`` | **A malicious endpoint may attempt to extract data |
+| | or state information by the use of invalid or |
+| | incorrect input arguments.** |
+| | Lack of input parameter validation or side effects |
+| | of maliciously forged input parameters might affect|
+| | the SPMC. |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF2, DF3, DF4 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMD, SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SP secrets, SPMC secrets, SP state, SPMC state |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Information discolure |
++------------------------+------------------+---------------+-----------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+---------------+-----------------+
+| ``Impact`` | High (4) | High (4) | |
++------------------------+------------------+---------------+-----------------+
+| ``Likelihood`` | Medium (3) | Medium (3) | |
++------------------------+------------------+---------------+-----------------+
+| ``Total Risk Rating`` | High (12) | High (12) | |
++------------------------+------------------+---------------+-----------------+
+| ``Mitigations`` | Secure Partitions must follow security standards |
+| | and best practises as a way to mitigate the risk |
+| | of common vulnerabilities to be exploited. |
+| | The use of software (canaries) or hardware |
+| | hardening techniques (XN, WXN, BTI, pointer |
+| | authentication, MTE) helps detecting and stopping |
+| | an exploitation early. |
+| | The TF-A SPMC mitigates this threat by implementing|
+| | stack protector, pointer authentication, BTI, XN, |
+| | WXN, security hardening techniques. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 08 |
++========================+====================================================+
+| ``Threat`` | **A malicious endpoint may forge a direct message |
+| | request such that it reveals the internal state of |
+| | another endpoint through the direct message |
+| | response.** |
+| | The secure partition or SPMC replies to a partition|
+| | message by a direct message response with |
+| | information which may reveal its internal state |
+| | (.e.g. partition message response outside of |
+| | allowed bounds). |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF2, DF3, DF4 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SPMC or SP state |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Information discolure |
++------------------------+------------------+---------------+-----------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+---------------+-----------------+
+| ``Impact`` | Medium (3) | Medium (3) | |
++------------------------+------------------+---------------+-----------------+
+| ``Likelihood`` | Low (2) | Low (2) | |
++------------------------+------------------+---------------+-----------------+
+| ``Total Risk Rating`` | Medium (6) | Medium (6) | |
++------------------------+------------------+---------------+-----------------+
+| ``Mitigations`` | For the specific case of direct requests targeting |
+| | the SPMC, the latter is hardened to prevent |
+| | its internal state or the state of an SP to be |
+| | revealed through a direct message response. |
+| | Further, SPMC performs numerous checks in runtime |
+| | on the basis of the rules established by partition |
+| | runtime models to stop any malicious attempts by |
+| | an endpoint to extract internal state of another |
+| | endpoint. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 09 |
++========================+====================================================+
+| ``Threat`` | **Probing the FF-A communication between |
+| | endpoints.** |
+| | SPMC and SPs are typically loaded to external |
+| | memory (protected by a TrustZone memory |
+| | controller). A malicious agent may use non invasive|
+| | methods to probe the external memory bus and |
+| | extract the traffic between an SP and the SPMC or |
+| | among SPs when shared buffers are held in external |
+| | memory. |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF7 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SP/SPMC state, SP/SPMC secrets |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | Hardware attack |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Information disclosure |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+-----------------+---------------+
+| ``Impact`` | Medium (3) | Medium (3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood`` | Low (2) | Medium (3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating`` | Medium (6) | Medium (9) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | It is expected the platform or chipset provides |
+| | guarantees in protecting the DRAM contents. |
+| | The TF-A SPMC does not mitigate this class of |
+| | attack and this is left to the integrator. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 10 |
++========================+====================================================+
+| ``Threat`` | **A malicious agent may attempt revealing the SPMC |
+| | state or secrets by the use of software-based cache|
+| | side-channel attack techniques.** |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF7 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SP or SPMC state |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Information disclosure |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+-----------------+---------------+
+| ``Impact`` | Medium (3) | Medium (3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood`` | Low (2) | Low (2) | |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating`` | Medium (6) | Medium (6) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | From an integration perspective it is assumed |
+| | platforms consuming the SPMC component at S-EL2 |
+| | (hence implementing the Armv8.4 FEAT_SEL2 |
+| | architecture extension) implement mitigations to |
+| | Spectre, Meltdown or other cache timing |
+| | side-channel type of attacks. |
+| | The TF-A SPMC implements one mitigation (barrier |
+| | preventing speculation past exeception returns). |
+| | The SPMC may be hardened further with SW |
+| | mitigations (e.g. speculation barriers) for the |
+| | cases not covered in HW. Usage of hardened |
+| | compilers and appropriate options, code inspection |
+| | are recommended ways to mitigate Spectre types of |
+| | attacks. For non-hardened cores, the usage of |
+| | techniques such a kernel page table isolation can |
+| | help mitigating Meltdown type of attacks. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 11 |
++========================+====================================================+
+| ``Threat`` | **A malicious endpoint may attempt flooding the |
+| | SPMC with requests targeting a service within an |
+| | endpoint such that it denies another endpoint to |
+| | access this service.** |
+| | Similarly, the malicious endpoint may target a |
+| | a service within an endpoint such that the latter |
+| | is unable to request services from another |
+| | endpoint. |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF2, DF3, DF4 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SPMC state |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Denial of service |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+-----------------+---------------+
+| ``Impact`` | Medium (3) | Medium (3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood`` | Medium (3) | Medium (3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating`` | Medium (9) | Medium (9) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | The TF-A SPMC does not mitigate this threat. |
+| | Bounding the time for operations to complete can |
+| | be achieved by the usage of a trusted watchdog. |
+| | Other quality of service monitoring can be achieved|
+| | in the SPMC such as counting a number of operations|
+| | in a limited timeframe. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 12 |
++========================+====================================================+
+| ``Threat`` | **A malicious endpoint may attempt to allocate |
+| | notifications bitmaps in the SPMC, through the |
+| | FFA_NOTIFICATION_BITMAP_CREATE.** |
+| | This might be an attempt to exhaust SPMC's memory, |
+| | or to allocate a bitmap for a VM that was not |
+| | intended to receive notifications from SPs. Thus |
+| | creating the possibility for a channel that was not|
+| | meant to exist. |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF2, DF3 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SPMC state |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Denial of service, Spoofing |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+-----------------+---------------+
+| ``Impact`` | Medium(3) | Medium(3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood`` | Medium(3) | Medium(3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating`` | Medium(9) | Medium(9) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | The TF-A SPMC mitigates this threat by defining a |
+| | a fixed size pool for bitmap allocation. |
+| | It also limits the designated FF-A calls to be used|
+| | from NWd endpoints. |
+| | In the NWd the hypervisor is supposed to limit the |
+| | access to the designated FF-A call. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 13 |
++========================+====================================================+
+| ``Threat`` | **A malicious endpoint may attempt to destroy the |
+| | notifications bitmaps in the SPMC, through the |
+| | FFA_NOTIFICATION_BITMAP_DESTROY.** |
+| | This might be an attempt to tamper with the SPMC |
+| | state such that a partition isn't able to receive |
+| | notifications. |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF2, DF3 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SPMC state |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Tampering |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+-----------------+---------------+
+| ``Impact`` | Low(2) | Low(2) | |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood`` | Low(2) | Low(2) | |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating`` | Low(4) | Low(4) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | The TF-A SPMC mitigates this issue by limiting the |
+| | designated FF-A call to be issued by the NWd. |
+| | Also, the notifications bitmap can't be destroyed |
+| | if there are pending notifications. |
+| | In the NWd, the hypervisor must restrict the |
+| | NS-endpoints that can issue the designated call. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 14 |
++========================+====================================================+
+| ``Threat`` | **A malicious endpoint might attempt to give |
+| | permissions to an unintended sender to set |
+| | notifications targeting another receiver using the |
+| | FF-A call FFA_NOTIFICATION_BIND.** |
+| | This might be an attempt to tamper with the SPMC |
+| | state such that an unintended, and possibly |
+| | malicious, communication channel is established. |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF2, DF3 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SPMC state |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Tampering, Spoofing |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+-----------------+---------------+
+| ``Impact`` | Low(2) | Low(2) | |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood`` | Medium(3) | Medium(3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating`` | Medium(6) | Medium(6) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | The TF-A SPMC mitigates this by restricting |
+| | designated FFA_NOTIFICATION_BIND call to be issued |
+| | by the receiver only. The receiver is responsible |
+| | for allocating the notifications IDs to one |
+| | specific partition. |
+| | Also, receivers that are not meant to receive |
+| | notifications, must have notifications receipt |
+| | disabled in the respective partition's manifest. |
+| | As for calls coming from NWd, if the NWd VM has had|
+| | its bitmap allocated at initialization, the TF-A |
+| | SPMC can't guarantee this threat won't happen. |
+| | The Hypervisor must mitigate in the NWd, similarly |
+| | to SPMC for calls in SWd. Though, if the Hypervisor|
+| | has been compromised, the SPMC won't be able to |
+| | mitigate it for calls forwarded from NWd. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 15 |
++========================+====================================================+
+| ``Threat`` | **A malicious partition endpoint might attempt to |
+| | set notifications that are not bound to it.** |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF2, DF3 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SPMC state |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Spoofing |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+-----------------+---------------+
+| ``Impact`` | Low(2) | Low(2) | |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood`` | Low(2) | Low(2) | |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating`` | Low(4) | Low(4) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | The TF-A SPMC mitigates this by checking the |
+| | sender's ID provided in the input to the call |
+| | FFA_NOTIFICATION_SET. The SPMC keeps track of which|
+| | notifications are bound to which sender, for a |
+| | given receiver. If the sender is an SP, the |
+| | provided sender ID must match the ID of the |
+| | currently running partition. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 16 |
++========================+====================================================+
+| ``Threat`` | **A malicious partition endpoint might attempt to |
+| | get notifications that are not targeted to it.** |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF2, DF3 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SPMC state |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Spoofing |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+-----------------+---------------+
+| ``Impact`` | Informational(1) | Informational(1)| |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood`` | Low(2) | Low(2) | |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating`` | Low(2) | Low(2) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | The TF-A SPMC mitigates this by checking the |
+| | receiver's ID provided in the input to the call |
+| | FFA_NOTIFICATION_GET. The SPMC keeps track of which|
+| | notifications are pending for each receiver. |
+| | The provided receiver ID must match the ID of the |
+| | currently running partition, if it is an SP. |
+| | For calls forwarded from NWd, the SPMC will return |
+| | the pending notifications if the receiver had its |
+| | bitmap created, and has pending notifications. |
+| | If Hypervisor or OS kernel are compromised, the |
+| | SPMC won't be able to mitigate calls from rogue NWd|
+| | endpoints. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 17 |
++========================+====================================================+
+| ``Threat`` | **A malicious partition endpoint might attempt to |
+| | get the information about pending notifications, |
+| | through the FFA_NOTIFICATION_INFO_GET call.** |
+| | This call is meant to be used by the NWd FF-A |
+| | driver. |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF2, DF3 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SPMC state |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Information disclosure |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+-----------------+---------------+
+| ``Impact`` | Low(2) | Low(2) | |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood`` | Medium(3) | Medium(3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating`` | Medium(6) | Medium(6) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | The TF-A SPMC mitigates this by returning error to |
+| | calls made by SPs to FFA_NOTIFICATION_INFO_GET. |
+| | If Hypervisor or OS kernel are compromised, the |
+| | SPMC won't be able mitigate calls from rogue NWd |
+| | endpoints. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 18 |
++========================+====================================================+
+| ``Threat`` | **A malicious partition endpoint might attempt to |
+| | flood another partition endpoint with notifications|
+| | hindering its operation.** |
+| | The intent of the malicious endpoint could be to |
+| | interfere with both the receiver's and/or primary |
+| | endpoint execution, as they can both be preempted |
+| | by the NPI and SRI, respectively. |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF2, DF3, DF4 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SPMC state, SP state, CPU cycles |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | DoS |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+-----------------+---------------+
+| ``Impact`` | Low(2) | Low(2) | |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood`` | Medium(3) | Medium(3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating`` | Medium(6) | Medium(6) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | The TF-A SPMC does not mitigate this threat. |
+| | However, the impact is limited due to the |
+| | architecture: |
+| | - Notifications are not queued, one that has been |
+| | signaled needs to be retrieved by the receiver, |
+| | until it can be sent again. |
+| | - Both SRI and NPI can't be pended until handled |
+| | which limits the amount of spurious interrupts. |
+| | - A given receiver could only bind a maximum number|
+| | of notifications to a given sender, within a given |
+| | execution context. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 19 |
++========================+====================================================+
+| ``Threat`` | **A malicious endpoint may abuse FFA_RUN call to |
+| | resume or turn on other endpoint execution |
+| | contexts, attempting to alter the internal state of|
+| | SPMC and SPs, potentially leading to illegal state |
+| | transitions and deadlocks.** |
+| | An endpoint can call into another endpoint |
+| | execution context using FFA_MSG_SEND_DIRECT_REQ |
+| | ABI to create a call chain. A malicious endpoint |
+| | could abuse this to form loops in a call chain that|
+| | could lead to potential deadlocks. |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF2, DF4 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC, SPMD |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SPMC state, SP state, Scheduling cycles |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Tampering, Denial of Service |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+-----------------+---------------+
+| ``Impact`` | Medium (3) | Medium (3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood`` | Medium (3) | Medium (3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating`` | Medium (9) | Medium (9) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | The TF-A SPMC provides mitigation against such |
+| | threats by following the guidance for partition |
+| | runtime models as described in FF-A v1.1 EAC0 spec.|
+| | The SPMC performs numerous checks in runtime to |
+| | prevent illegal state transitions by adhering to |
+| | the partition runtime model. Further, if the |
+| | receiver endpoint is a predecessor of current |
+| | endpoint in the present call chain, the SPMC denies|
+| | any attempts to form loops by returning FFA_DENIED |
+| | error code. Only the primary scheduler is allowed |
+| | to turn on execution contexts of other partitions |
+| | though SPMC does not have the ability to |
+| | scrutinize its identity. Secure partitions have |
+| | limited ability to resume execution contexts of |
+| | other partitions based on the runtime model. Such |
+| | attempts cannot compromise the integrity of the |
+| | SPMC. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 20 |
++========================+====================================================+
+| ``Threat`` | **A malicious endpoint can perform a |
+| | denial-of-service attack by using FFA_INTERRUPT |
+| | call that could attempt to cause the system to |
+| | crash or enter into an unknown state as no physical|
+| | interrupt could be pending for it to be handled in |
+| | the SPMC.** |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF2, DF5 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC, SPMD |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SPMC state, SP state, Scheduling cycles |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint, S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Tampering, Denial of Service |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+-----------------+---------------+
+| ``Impact`` | Medium (3) | Medium (3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood`` | Medium (3) | Medium (3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating`` | Medium (9) | Medium (9) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | The TF-A SPMC provides mitigation against such |
+| | attack by detecting invocations from partitions |
+| | and simply returning FFA_ERROR status interface. |
+| | SPMC only allows SPMD to use FFA_INTERRUPT ABI to |
+| | communicate a pending secure interrupt triggered |
+| | while execution was in normal world. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 21 |
++========================+====================================================+
+| ``Threat`` | **A malicious secure endpoint might deactivate a |
+| | (virtual) secure interrupt that was not originally |
+| | signaled by SPMC, thereby attempting to alter the |
+| | state of the SPMC and potentially lead to system |
+| | crash.** |
+| | SPMC maps the virtual interrupt ids to the physical|
+| | interrupt ids to keep the implementation of virtual|
+| | interrupt driver simple. |
+| | Similarly, a malicious secure endpoint might invoke|
+| | the deactivation ABI more than once for a secure |
+| | interrupt. Moreover, a malicious secure endpoint |
+| | might attempt to deactivate a (virtual) secure |
+| | interrupt that was signaled to another endpoint |
+| | execution context by the SPMC even before secure |
+| | interrupt was handled. |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF5 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SPMC state, SP state |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Tampering |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+-----------------+---------------+
+| ``Impact`` | Medium (3) | Medium (3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood`` | Medium (3) | Medium (3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating`` | Medium (9) | Medium (9) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | At initialization, the TF-A SPMC parses the |
+| | partition manifests to find the target execution |
+| | context responsible for handling the various |
+| | secure physical interrupts. The TF-A SPMC provides |
+| | mitigation against above mentioned threats by: |
+| | |
+| | - Keeping track of each pending virtual interrupt |
+| | signaled to an execution context of a secure |
+| | secure partition. |
+| | - Denying any deactivation call from SP if there is|
+| | no pending physical interrupt mapped to the |
+| | given virtual interrupt. |
+| | - Denying any deactivation call from SP if the |
+| | virtual interrupt has not been signaled to the |
+| | current execution context. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 22 |
++========================+====================================================+
+| ``Threat`` | **A malicious secure endpoint might not deactivate |
+| | a virtual interrupt signaled to it by the SPMC but |
+| | perform secure interrupt signal completion. This |
+| | attempt to corrupt the internal state of the SPMC |
+| | could lead to an unknown state and further lead to |
+| | system crash.** |
+| | Similarly, a malicious secure endpoint could |
+| | deliberately not perform either interrupt |
+| | deactivation or interrupt completion signal. Since,|
+| | the SPMC can only process one secure interrupt at a|
+| | time, this could choke the system where all |
+| | interrupts are indefinitely masked which could |
+| | potentially lead to system crash or reboot. |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF5 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SPMC state, SP state, Scheduling cycles |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | S-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Tampering, Denial of Service |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+-----------------+---------------+
+| ``Impact`` | Medium (3) | Medium (3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood`` | Medium (3) | Medium (3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating`` | Medium (9) | Medium (9) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | The TF-A SPMC does not provide mitigation against |
+| | such threat. This is a limitation of the current |
+| | SPMC implementation and needs to be handled in the |
+| | future releases. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 23 |
++========================+====================================================+
+| ``Threat`` | **A malicious endpoint could leverage non-secure |
+| | interrupts to preempt a secure endpoint, thereby |
+| | attempting to render it unable to handle a secure |
+| | virtual interrupt targetted for it. This could lead|
+| | to priority inversion as secure virtual interrupts |
+| | are kept pending while non-secure interrupts are |
+| | handled by normal world VMs.** |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF2, DF3, DF5 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC, SPMD |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SPMC state, SP state, Scheduling cycles |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Denial of Service |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+-----------------+---------------+
+| ``Impact`` | Medium (3) | Medium (3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood`` | Medium (3) | Medium (3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating`` | Medium (9) | Medium (9) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | The TF-A SPMC alone does not provide mitigation |
+| | against such threats. System integrators must take |
+| | necessary high level design decisions that takes |
+| | care of interrupt prioritization. The SPMC performs|
+| | its role of enabling SPs to specify appropriate |
+| | action towards non-secure interrupt with the help |
+| | of partition manifest based on the guidance in the |
+| | FF-A v1.1 EAC0 specification. |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID | 24 |
++========================+====================================================+
+| ``Threat`` | **A secure endpoint depends on primary scheduler |
+| | for CPU cycles. A malicious endpoint could delay |
+| | the secure endpoint from being scheduled. Secure |
+| | interrupts, if not handled timely, could compromise|
+| | the state of SP and SPMC, thereby rendering the |
+| | system unresponsive.** |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements`` | DF1, DF2, DF3, DF5 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A | SPMC, SPMD |
+| Components`` | |
++------------------------+----------------------------------------------------+
+| ``Assets`` | SPMC state, SP state, Scheduling cycles |
++------------------------+----------------------------------------------------+
+| ``Threat Agent`` | NS-Endpoint |
++------------------------+----------------------------------------------------+
+| ``Threat Type`` | Denial of Service |
++------------------------+------------------+-----------------+---------------+
+| ``Application`` | ``Server`` | ``Mobile`` | |
++------------------------+------------------+-----------------+---------------+
+| ``Impact`` | Medium (3) | Medium (3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood`` | Medium (3) | Medium (3) | |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating`` | Medium (9) | Medium (9) | |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations`` | The TF-A SPMC does not provide full mitigation |
+| | against such threats. However, based on the |
+| | guidance provided in the FF-A v1.1 EAC0 spec, SPMC |
+| | provisions CPU cycles to run a secure endpoint |
+| | execution context in SPMC schedule mode which |
+| | cannot be preempted by a non-secure interrupt. |
+| | This reduces the dependency on primary scheduler |
+| | for cycle allocation. Moreover, all further |
+| | interrupts are masked until pending secure virtual |
+| | interrupt on current CPU is handled. This allows SP|
+| | execution context to make progress even upon being |
+| | interrupted. |
++------------------------+----------------------------------------------------+
+
+--------------
+
+*Copyright (c) 2021-2022, Arm Limited. All rights reserved.*
+
+.. _Arm Firmware Framework for Arm A-profile: https://developer.arm.com/docs/den0077/latest
+.. _Secure Partition Manager: ../components/secure-partition-manager.html
+.. _Generic TF-A threat model: ./threat_model.html#threat-analysis
+.. _FF-A ACS: https://github.com/ARM-software/ff-a-acs/releases
diff --git a/drivers/allwinner/axp/axp803.c b/drivers/allwinner/axp/axp803.c
new file mode 100644
index 0000000..19a9549
--- /dev/null
+++ b/drivers/allwinner/axp/axp803.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/allwinner/axp.h>
+
+const uint8_t axp_chip_id = AXP803_CHIP_ID;
+const char *const axp_compatible = "x-powers,axp803";
+
+#if SUNXI_SETUP_REGULATORS == 1
+const struct axp_regulator axp_regulators[] = {
+ {"aldo1", 700, 3300, 100, NA, 0x28, 0x13, 5},
+ {"dcdc1", 1600, 3400, 100, NA, 0x20, 0x10, 0},
+ {"dcdc5", 800, 1840, 10, 32, 0x24, 0x10, 4},
+ {"dcdc6", 600, 1520, 10, 50, 0x25, 0x10, 5},
+ {"dldo1", 700, 3300, 100, NA, 0x15, 0x12, 3},
+ {"dldo2", 700, 4200, 100, 27, 0x16, 0x12, 4},
+ {"dldo3", 700, 3300, 100, NA, 0x17, 0x12, 5},
+ {"dldo4", 700, 3300, 100, NA, 0x18, 0x12, 6},
+ {"fldo1", 700, 1450, 50, NA, 0x1c, 0x13, 2},
+ {}
+};
+#endif
diff --git a/drivers/allwinner/axp/axp805.c b/drivers/allwinner/axp/axp805.c
new file mode 100644
index 0000000..3a03fec
--- /dev/null
+++ b/drivers/allwinner/axp/axp805.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/allwinner/axp.h>
+
+const uint8_t axp_chip_id = AXP805_CHIP_ID;
+const char *const axp_compatible = "x-powers,axp805";
+
+#if SUNXI_SETUP_REGULATORS == 1
+/*
+ * The "dcdcd" split changes the step size by a factor of 5, not 2;
+ * disallow values above the split to maintain accuracy.
+ */
+const struct axp_regulator axp_regulators[] = {
+ {"dcdca", 600, 1520, 10, 50, 0x12, 0x10, 0},
+ {"dcdcb", 1000, 2550, 50, NA, 0x13, 0x10, 1},
+ {"dcdcc", 600, 1520, 10, 50, 0x14, 0x10, 2},
+ {"dcdcd", 600, 1500, 20, NA, 0x15, 0x10, 3},
+ {"dcdce", 1100, 3400, 100, NA, 0x16, 0x10, 4},
+ {"aldo1", 700, 3300, 100, NA, 0x17, 0x10, 5},
+ {"aldo2", 700, 3300, 100, NA, 0x18, 0x10, 6},
+ {"aldo3", 700, 3300, 100, NA, 0x19, 0x10, 7},
+ {"bldo1", 700, 1900, 100, NA, 0x20, 0x11, 0},
+ {"bldo2", 700, 1900, 100, NA, 0x21, 0x11, 1},
+ {"bldo3", 700, 1900, 100, NA, 0x22, 0x11, 2},
+ {"bldo4", 700, 1900, 100, NA, 0x23, 0x11, 3},
+ {"cldo1", 700, 3300, 100, NA, 0x24, 0x11, 4},
+ {"cldo2", 700, 4200, 100, 27, 0x25, 0x11, 5},
+ {"cldo3", 700, 3300, 100, NA, 0x26, 0x11, 6},
+ {}
+};
+#endif
diff --git a/drivers/allwinner/axp/common.c b/drivers/allwinner/axp/common.c
new file mode 100644
index 0000000..f1250b0
--- /dev/null
+++ b/drivers/allwinner/axp/common.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <libfdt.h>
+
+#include <common/debug.h>
+#include <drivers/allwinner/axp.h>
+
+int axp_check_id(void)
+{
+ int ret;
+
+ ret = axp_read(0x03);
+ if (ret < 0)
+ return ret;
+
+ ret &= 0xcf;
+ if (ret != axp_chip_id) {
+ ERROR("PMIC: Found unknown PMIC %02x\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int axp_clrsetbits(uint8_t reg, uint8_t clr_mask, uint8_t set_mask)
+{
+ uint8_t val;
+ int ret;
+
+ ret = axp_read(reg);
+ if (ret < 0)
+ return ret;
+
+ val = (ret & ~clr_mask) | set_mask;
+
+ return axp_write(reg, val);
+}
+
+void axp_power_off(void)
+{
+ /* Set "power disable control" bit */
+ axp_setbits(0x32, BIT(7));
+}
+
+#if SUNXI_SETUP_REGULATORS == 1
+/*
+ * 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;
+}
+
+static int setup_regulator(const void *fdt, int node,
+ const struct axp_regulator *reg)
+{
+ uint8_t val;
+ int mvolt;
+
+ mvolt = fdt_get_regulator_millivolt(fdt, node);
+ if (mvolt < reg->min_volt || mvolt > reg->max_volt)
+ return -EINVAL;
+
+ val = (mvolt / reg->step) - (reg->min_volt / reg->step);
+ if (val > reg->split)
+ val = ((val - reg->split) / 2) + reg->split;
+
+ axp_write(reg->volt_reg, val);
+ axp_setbits(reg->switch_reg, BIT(reg->switch_bit));
+
+ INFO("PMIC: %s voltage: %d.%03dV\n", reg->dt_name,
+ mvolt / 1000, mvolt % 1000);
+
+ return 0;
+}
+
+static bool is_node_disabled(const void *fdt, int node)
+{
+ const char *cell;
+ cell = fdt_getprop(fdt, node, "status", NULL);
+ if (cell == NULL) {
+ return false;
+ }
+ return strcmp(cell, "okay") != 0;
+}
+
+static bool should_enable_regulator(const void *fdt, int node)
+{
+ if (is_node_disabled(fdt, node)) {
+ return false;
+ }
+ if (fdt_getprop(fdt, node, "phandle", NULL) != NULL) {
+ return true;
+ }
+ if (fdt_getprop(fdt, node, "regulator-always-on", NULL) != NULL) {
+ return true;
+ }
+ return false;
+}
+
+static bool board_uses_usb0_host_mode(const void *fdt)
+{
+ int node, length;
+ const char *prop;
+
+ node = fdt_node_offset_by_compatible(fdt, -1,
+ "allwinner,sun8i-a33-musb");
+ if (node < 0) {
+ return false;
+ }
+
+ prop = fdt_getprop(fdt, node, "dr_mode", &length);
+ if (!prop) {
+ return false;
+ }
+
+ return !strncmp(prop, "host", length);
+}
+
+void axp_setup_regulators(const void *fdt)
+{
+ int node;
+ bool sw = false;
+
+ if (fdt == NULL)
+ return;
+
+ /* locate the PMIC DT node, bail out if not found */
+ node = fdt_node_offset_by_compatible(fdt, -1, axp_compatible);
+ if (node < 0) {
+ WARN("PMIC: No PMIC DT node, skipping setup\n");
+ return;
+ }
+
+ /* This applies to AXP803 only. */
+ if (fdt_getprop(fdt, node, "x-powers,drive-vbus-en", NULL) &&
+ board_uses_usb0_host_mode(fdt)) {
+ axp_clrbits(0x8f, BIT(4));
+ axp_setbits(0x30, BIT(2));
+ INFO("PMIC: Enabling DRIVEVBUS\n");
+ }
+
+ /* descend into the "regulators" subnode */
+ node = fdt_subnode_offset(fdt, node, "regulators");
+ if (node < 0) {
+ WARN("PMIC: No regulators DT node, skipping setup\n");
+ return;
+ }
+
+ /* iterate over all regulators to find used ones */
+ fdt_for_each_subnode(node, 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);
+
+ /* Enable the switch last to avoid overheating. */
+ if (!strncmp(name, "dc1sw", length) ||
+ !strncmp(name, "sw", length)) {
+ sw = true;
+ continue;
+ }
+
+ for (reg = axp_regulators; reg->dt_name; reg++) {
+ if (!strncmp(name, reg->dt_name, length)) {
+ setup_regulator(fdt, node, reg);
+ break;
+ }
+ }
+ }
+
+ /*
+ * On the AXP803, if DLDO2 is enabled after DC1SW, the PMIC overheats
+ * and shuts down. So always enable DC1SW as the very last regulator.
+ */
+ if (sw) {
+ INFO("PMIC: Enabling DC SW\n");
+ if (axp_chip_id == AXP803_CHIP_ID)
+ axp_setbits(0x12, BIT(7));
+ if (axp_chip_id == AXP805_CHIP_ID)
+ axp_setbits(0x11, BIT(7));
+ }
+}
+#endif /* SUNXI_SETUP_REGULATORS */
diff --git a/drivers/allwinner/sunxi_msgbox.c b/drivers/allwinner/sunxi_msgbox.c
new file mode 100644
index 0000000..cc4a6ff
--- /dev/null
+++ b/drivers/allwinner/sunxi_msgbox.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <drivers/delay_timer.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include <sunxi_mmap.h>
+
+#define REMOTE_IRQ_EN_REG 0x0040
+#define REMOTE_IRQ_STAT_REG 0x0050
+#define LOCAL_IRQ_EN_REG 0x0060
+#define LOCAL_IRQ_STAT_REG 0x0070
+
+#define RX_IRQ(n) BIT(0 + 2 * (n))
+#define TX_IRQ(n) BIT(1 + 2 * (n))
+
+#define FIFO_STAT_REG(n) (0x0100 + 0x4 * (n))
+#define FIFO_STAT_MASK GENMASK(0, 0)
+
+#define MSG_STAT_REG(n) (0x0140 + 0x4 * (n))
+#define MSG_STAT_MASK GENMASK(2, 0)
+
+#define MSG_DATA_REG(n) (0x0180 + 0x4 * (n))
+
+#define RX_CHAN 1
+#define TX_CHAN 0
+
+#define MHU_MAX_SLOT_ID 31
+
+#define MHU_TIMEOUT_DELAY 10
+#define MHU_TIMEOUT_ITERS 10000
+
+static DEFINE_BAKERY_LOCK(mhu_secure_message_lock);
+
+static bool sunxi_msgbox_last_tx_done(unsigned int chan)
+{
+ uint32_t stat = mmio_read_32(SUNXI_MSGBOX_BASE + REMOTE_IRQ_STAT_REG);
+
+ return (stat & RX_IRQ(chan)) == 0U;
+}
+
+static bool sunxi_msgbox_peek_data(unsigned int chan)
+{
+ uint32_t stat = mmio_read_32(SUNXI_MSGBOX_BASE + MSG_STAT_REG(chan));
+
+ return (stat & MSG_STAT_MASK) != 0U;
+}
+
+void mhu_secure_message_start(unsigned int slot_id __unused)
+{
+ uint32_t timeout = MHU_TIMEOUT_ITERS;
+
+ bakery_lock_get(&mhu_secure_message_lock);
+
+ /* Wait for all previous messages to be acknowledged. */
+ while (!sunxi_msgbox_last_tx_done(TX_CHAN) && --timeout)
+ udelay(MHU_TIMEOUT_DELAY);
+}
+
+void mhu_secure_message_send(unsigned int slot_id)
+{
+ mmio_write_32(SUNXI_MSGBOX_BASE + MSG_DATA_REG(TX_CHAN), BIT(slot_id));
+}
+
+uint32_t mhu_secure_message_wait(void)
+{
+ uint32_t timeout = MHU_TIMEOUT_ITERS;
+ uint32_t msg = 0;
+
+ /* Wait for a message from the SCP. */
+ while (!sunxi_msgbox_peek_data(RX_CHAN) && --timeout)
+ udelay(MHU_TIMEOUT_DELAY);
+
+ /* Return the most recent message in the FIFO. */
+ while (sunxi_msgbox_peek_data(RX_CHAN))
+ msg = mmio_read_32(SUNXI_MSGBOX_BASE + MSG_DATA_REG(RX_CHAN));
+
+ return msg;
+}
+
+void mhu_secure_message_end(unsigned int slot_id)
+{
+ /* Acknowledge a response by clearing the IRQ status. */
+ mmio_write_32(SUNXI_MSGBOX_BASE + LOCAL_IRQ_STAT_REG, RX_IRQ(RX_CHAN));
+
+ bakery_lock_release(&mhu_secure_message_lock);
+}
diff --git a/drivers/allwinner/sunxi_rsb.c b/drivers/allwinner/sunxi_rsb.c
new file mode 100644
index 0000000..67f5b7e
--- /dev/null
+++ b/drivers/allwinner/sunxi_rsb.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2017-2018 ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <sunxi_mmap.h>
+
+#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");
+}
diff --git a/drivers/amlogic/console/aarch64/meson_console.S b/drivers/amlogic/console/aarch64/meson_console.S
new file mode 100644
index 0000000..6d0a2d6
--- /dev/null
+++ b/drivers/amlogic/console/aarch64/meson_console.S
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console_macros.S>
+#include <drivers/amlogic/meson_console.h>
+
+ .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_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_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_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_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_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_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_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
+
+ /* ---------------------------------------------
+ * void console_meson_flush(console_t *console)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * In : x0 - pointer to console_t structure
+ * Out : void.
+ * 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_BASE]
+ b console_meson_core_flush
+endfunc console_meson_flush
+
+ /* ---------------------------------------------
+ * void 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 : void.
+ * 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
+ ret
+endfunc console_meson_core_flush
diff --git a/drivers/amlogic/crypto/sha_dma.c b/drivers/amlogic/crypto/sha_dma.c
new file mode 100644
index 0000000..5c16d49
--- /dev/null
+++ b/drivers/amlogic/crypto/sha_dma.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2019, Remi Pommarel <repk@triplefau.lt>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <crypto/sha_dma.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#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);
+}
diff --git a/drivers/arm/cci/cci.c b/drivers/arm/cci/cci.c
new file mode 100644
index 0000000..2adfe17
--- /dev/null
+++ b/drivers/arm/cci/cci.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <lib/mmio.h>
+
+#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 & (1UL << slave_if_id)) != 0U) {
+ ERROR("Multiple masters are assigned same slave interface ID\n");
+ return false;
+ }
+ valid_cci_map |= 1UL << 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)
+ ;
+}
+
diff --git a/drivers/arm/ccn/ccn.c b/drivers/arm/ccn/ccn.c
new file mode 100644
index 0000000..5b13250
--- /dev/null
+++ b/drivers/arm/ccn/ccn.c
@@ -0,0 +1,621 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <arch.h>
+#include <common/debug.h>
+#include <drivers/arm/ccn.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#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] = <number of master interfaces>
+ ******************************************************************************/
+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;
+}
diff --git a/drivers/arm/ccn/ccn_private.h b/drivers/arm/ccn/ccn_private.h
new file mode 100644
index 0000000..8a936d9
--- /dev/null
+++ b/drivers/arm/ccn/ccn_private.h
@@ -0,0 +1,233 @@
+/*
+ * 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 */
diff --git a/drivers/arm/css/mhu/css_mhu.c b/drivers/arm/css/mhu/css_mhu.c
new file mode 100644
index 0000000..b7faf7e
--- /dev/null
+++ b/drivers/arm/css/mhu/css_mhu.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <drivers/arm/css/css_mhu.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <plat/arm/common/plat_arm.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
+
+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();
+}
diff --git a/drivers/arm/css/mhu/css_mhu_doorbell.c b/drivers/arm/css/mhu/css_mhu_doorbell.c
new file mode 100644
index 0000000..c51f3b1
--- /dev/null
+++ b/drivers/arm/css/mhu/css_mhu_doorbell.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <drivers/arm/css/css_mhu_doorbell.h>
+#include <drivers/arm/css/scmi.h>
+
+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)
+{
+ uintptr_t mhuv2_base = plat_info->db_reg_addr & MHU_V2_FRAME_BASE_MASK;
+
+ /* wake receiver */
+ MHU_V2_ACCESS_REQUEST(mhuv2_base);
+
+ /* wait for receiver to acknowledge its ready */
+ while (MHU_V2_IS_ACCESS_READY(mhuv2_base) == 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);
+
+ return;
+}
diff --git a/drivers/arm/css/scmi/scmi_ap_core_proto.c b/drivers/arm/css/scmi/scmi_ap_core_proto.c
new file mode 100644
index 0000000..5941b87
--- /dev/null
+++ b/drivers/arm/css/scmi/scmi_ap_core_proto.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/scmi.h>
+
+#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;
+}
diff --git a/drivers/arm/css/scmi/scmi_common.c b/drivers/arm/css/scmi/scmi_common.c
new file mode 100644
index 0000000..ec749fb
--- /dev/null
+++ b/drivers/arm/css/scmi/scmi_common.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/scmi.h>
+
+#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\n");
+ 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\n",
+ 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\n");
+ 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\n",
+ 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;
+}
diff --git a/drivers/arm/css/scmi/scmi_private.h b/drivers/arm/css/scmi/scmi_private.h
new file mode 100644
index 0000000..a684ca5
--- /dev/null
+++ b/drivers/arm/css/scmi/scmi_private.h
@@ -0,0 +1,160 @@
+/*
+ * 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 <lib/mmio.h>
+
+/*
+ * 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;
+ volatile 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 */
diff --git a/drivers/arm/css/scmi/scmi_pwr_dmn_proto.c b/drivers/arm/css/scmi/scmi_pwr_dmn_proto.c
new file mode 100644
index 0000000..a342aa8
--- /dev/null
+++ b/drivers/arm/css/scmi/scmi_pwr_dmn_proto.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/scmi.h>
+
+#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;
+}
diff --git a/drivers/arm/css/scmi/scmi_sys_pwr_proto.c b/drivers/arm/css/scmi/scmi_sys_pwr_proto.c
new file mode 100644
index 0000000..c8e62d1
--- /dev/null
+++ b/drivers/arm/css/scmi/scmi_sys_pwr_proto.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/scmi.h>
+
+#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;
+}
diff --git a/drivers/arm/css/scmi/vendor/scmi_sq.c b/drivers/arm/css/scmi/vendor/scmi_sq.c
new file mode 100644
index 0000000..f185424
--- /dev/null
+++ b/drivers/arm/css/scmi/vendor/scmi_sq.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/scmi.h>
+
+#include "scmi_private.h"
+#include "scmi_sq.h"
+
+#include <sq_common.h>
+
+/* 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;
+}
diff --git a/drivers/arm/css/scmi/vendor/scmi_sq.h b/drivers/arm/css/scmi/vendor/scmi_sq.h
new file mode 100644
index 0000000..aee1a3a
--- /dev/null
+++ b/drivers/arm/css/scmi/vendor/scmi_sq.h
@@ -0,0 +1,25 @@
+/*
+ * 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 <stddef.h>
+#include <stdint.h>
+
+#include <sq_common.h>
+
+/* 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 */
diff --git a/drivers/arm/css/scp/css_bom_bootloader.c b/drivers/arm/css/scp/css_bom_bootloader.c
new file mode 100644
index 0000000..74121b4
--- /dev/null
+++ b/drivers/arm/css/scp/css_bom_bootloader.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_mhu.h>
+#include <drivers/arm/css/css_scp.h>
+#include <drivers/arm/css/css_scpi.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+/* 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 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_FW_CONFIG_LIMIT, assert_scp_bl2_overflow);
+CASSERT(SCP_BL2U_BASE >= ARM_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();
+}
diff --git a/drivers/arm/css/scp/css_pm_scmi.c b/drivers/arm/css/scp/css_pm_scmi.c
new file mode 100644
index 0000000..9fe8b37
--- /dev/null
+++ b/drivers/arm/css/scp/css_pm_scmi.c
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_scp.h>
+#include <drivers/arm/css/scmi.h>
+#include <lib/mmio.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+/*
+ * 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 handles for invoking the SCMI driver APIs after the driver
+ * has been initialized.
+ */
+static void *scmi_handles[PLAT_ARM_SCMI_CHANNEL_COUNT];
+
+/* The global SCMI channels array */
+static scmi_channel_t scmi_channels[PLAT_ARM_SCMI_CHANNEL_COUNT];
+
+/*
+ * Channel ID for the default SCMI channel.
+ * The default channel is used to issue SYSTEM level SCMI requests and is
+ * initialized to the channel which has the boot cpu as its resource.
+ */
+static uint32_t default_scmi_channel_id;
+
+/*
+ * TODO: Allow use of channel specific lock instead of using a single lock for
+ * all the channels.
+ */
+ARM_SCMI_INSTANTIATE_LOCK;
+
+/*
+ * Function to obtain the SCMI Domain ID and SCMI Channel number from the linear
+ * core position. The SCMI Channel number is encoded in the upper 16 bits and
+ * the Domain ID is encoded in the lower 16 bits in each entry of the mapping
+ * array exported by the platform.
+ */
+static void css_scp_core_pos_to_scmi_channel(unsigned int core_pos,
+ unsigned int *scmi_domain_id, unsigned int *scmi_channel_id)
+{
+ unsigned int composite_id;
+
+ composite_id = plat_css_core_pos_to_scmi_dmn_id_map[core_pos];
+
+ *scmi_channel_id = GET_SCMI_CHANNEL_ID(composite_id);
+ *scmi_domain_id = GET_SCMI_DOMAIN_ID(composite_id);
+}
+
+/*
+ * 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 on all SCMI channels */
+ ret = scmi_sys_pwr_state_set(
+ scmi_handles[default_scmi_channel_id],
+ 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, channel_id, domain_id;
+ 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);
+
+ css_scp_core_pos_to_scmi_channel(plat_my_core_pos(),
+ &domain_id, &channel_id);
+ ret = scmi_pwr_state_set(scmi_handles[channel_id],
+ domain_id, 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, channel_id, domain_id;
+ 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);
+
+ css_scp_core_pos_to_scmi_channel(plat_my_core_pos(),
+ &domain_id, &channel_id);
+ ret = scmi_pwr_state_set(scmi_handles[channel_id],
+ domain_id, 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, channel_id, core_pos, domain_id;
+ int ret;
+ 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 = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+ assert(core_pos < PLATFORM_CORE_COUNT);
+
+ css_scp_core_pos_to_scmi_channel(core_pos, &domain_id,
+ &channel_id);
+ ret = scmi_pwr_state_set(scmi_handles[channel_id],
+ domain_id, 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;
+ uint32_t scmi_pwr_state = 0, lvl_state;
+ unsigned int channel_id, cpu_idx, domain_id;
+
+ /* 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 = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+ assert(cpu_idx < PLATFORM_CORE_COUNT);
+
+ css_scp_core_pos_to_scmi_channel(cpu_idx, &domain_id, &channel_id);
+ ret = scmi_pwr_state_get(scmi_handles[channel_id],
+ domain_id, &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;
+}
+
+/*
+ * Callback function to raise a SGI designated to trigger the CPU power down
+ * sequence on all the online secondary cores.
+ */
+static void css_raise_pwr_down_interrupt(u_register_t mpidr)
+{
+#if CSS_SYSTEM_GRACEFUL_RESET
+ plat_ic_raise_el3_sgi(CSS_CPU_PWR_DOWN_REQ_INTR, mpidr);
+#endif
+}
+
+void __dead2 css_scp_system_off(int state)
+{
+ int ret;
+
+ /*
+ * Before issuing the system power down command, set the trusted mailbox
+ * to 0. This will ensure that in the case of a warm/cold reset, the
+ * primary CPU executes from the cold boot sequence.
+ */
+ mmio_write_64(PLAT_ARM_TRUSTED_MAILBOX_BASE, 0U);
+
+ /*
+ * Send powerdown request to online secondary core(s)
+ */
+ ret = psci_stop_other_cores(0, css_raise_pwr_down_interrupt);
+ if (ret != PSCI_E_SUCCESS) {
+ ERROR("Failed to powerdown secondary core(s)\n");
+ }
+
+ /*
+ * Disable GIC CPU interface to prevent pending interrupt from waking
+ * up the AP from WFI.
+ */
+ plat_arm_gic_cpuif_disable();
+ plat_arm_gic_redistif_off();
+
+ /*
+ * Issue SCMI command. First issue a graceful
+ * request and if that fails force the request.
+ */
+ ret = scmi_sys_pwr_state_set(scmi_handles[default_scmi_channel_id],
+ 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();
+ }
+
+ /* Powerdown of primary core */
+ psci_pwrdown_cpu(PLAT_MAX_PWR_LVL);
+ 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)
+{
+ unsigned int composite_id, idx;
+
+ for (idx = 0; idx < PLAT_ARM_SCMI_CHANNEL_COUNT; idx++) {
+ INFO("Initializing SCMI driver on channel %d\n", idx);
+
+ scmi_channels[idx].info = plat_css_get_scmi_info(idx);
+ scmi_channels[idx].lock = ARM_SCMI_LOCK_GET_INSTANCE;
+ scmi_handles[idx] = scmi_init(&scmi_channels[idx]);
+
+ if (scmi_handles[idx] == NULL) {
+ ERROR("SCMI Initialization failed on channel %d\n", idx);
+ panic();
+ }
+
+ if (scmi_ap_core_init(&scmi_channels[idx]) < 0) {
+ ERROR("SCMI AP core protocol initialization failed\n");
+ panic();
+ }
+ }
+
+ composite_id = plat_css_core_pos_to_scmi_dmn_id_map[plat_my_core_pos()];
+ default_scmi_channel_id = GET_SCMI_CHANNEL_ID(composite_id);
+}
+
+/******************************************************************************
+ * 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;
+ void *scmi_handle = scmi_handles[default_scmi_channel_id];
+
+ 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, i;
+
+ for (i = 0; i < PLAT_ARM_SCMI_CHANNEL_COUNT; i++) {
+ assert(scmi_handles[i]);
+
+ ret = scmi_ap_core_set_reset_addr(scmi_handles[i], address,
+ SCMI_AP_CORE_LOCK_ATTR);
+ if (ret != SCMI_E_SUCCESS) {
+ ERROR("CSS: Failed to program reset address: %d\n", ret);
+ panic();
+ }
+ }
+}
+#endif
diff --git a/drivers/arm/css/scp/css_pm_scpi.c b/drivers/arm/css/scp/css_pm_scpi.c
new file mode 100644
index 0000000..b4019ce
--- /dev/null
+++ b/drivers/arm/css/scp/css_pm_scpi.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_scp.h>
+#include <drivers/arm/css/css_scpi.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
+
+/*
+ * 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();
+}
diff --git a/drivers/arm/css/scp/css_sds.c b/drivers/arm/css/scp/css_sds.c
new file mode 100644
index 0000000..e42ee10
--- /dev/null
+++ b/drivers/arm/css/scp/css_sds.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_scp.h>
+#include <drivers/arm/css/sds.h>
+#include <drivers/delay_timer.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+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();
+}
diff --git a/drivers/arm/css/scpi/css_scpi.c b/drivers/arm/css/scpi/css_scpi.c
new file mode 100644
index 0000000..416356b
--- /dev/null
+++ b/drivers/arm/css/scpi/css_scpi.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_mhu.h>
+#include <drivers/arm/css/css_scpi.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#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 int 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);
+ return -1;
+ }
+
+ /*
+ * 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));
+
+ return 0;
+}
+
+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;
+ int rc;
+
+ VERBOSE("Waiting for SCP_READY command...\n");
+
+ /* Get a message from the SCP */
+ scpi_secure_message_start();
+ rc = scpi_secure_message_receive(&scpi_cmd);
+ scpi_secure_message_end();
+
+ /* If no message was received, don't send a response */
+ if (rc != 0)
+ return rc;
+
+ /* 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);
+ if (scpi_secure_message_receive(&response) != 0)
+ goto exit;
+
+ 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));
+
+ /* If no response is received, fill in an error status */
+ if (scpi_secure_message_receive(&response) != 0)
+ response.status = SCP_E_TIMEOUT;
+
+ scpi_secure_message_end();
+
+ return response.status;
+}
diff --git a/drivers/arm/css/sds/aarch32/sds_helpers.S b/drivers/arm/css/sds/aarch32/sds_helpers.S
new file mode 100644
index 0000000..13ff0e1
--- /dev/null
+++ b/drivers/arm/css/sds/aarch32/sds_helpers.S
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/css/sds.h>
+#include <platform_def.h>
+
+#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
diff --git a/drivers/arm/css/sds/aarch64/sds_helpers.S b/drivers/arm/css/sds/aarch64/sds_helpers.S
new file mode 100644
index 0000000..3256c2b
--- /dev/null
+++ b/drivers/arm/css/sds/aarch64/sds_helpers.S
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/css/sds.h>
+#include <platform_def.h>
+
+#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
diff --git a/drivers/arm/css/sds/sds.c b/drivers/arm/css/sds/sds.c
new file mode 100644
index 0000000..1fb196c
--- /dev/null
+++ b/drivers/arm/css/sds/sds.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/sds.h>
+#include <platform_def.h>
+
+#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;
+}
diff --git a/drivers/arm/css/sds/sds_private.h b/drivers/arm/css/sds/sds_private.h
new file mode 100644
index 0000000..d801a04
--- /dev/null
+++ b/drivers/arm/css/sds/sds_private.h
@@ -0,0 +1,100 @@
+/*
+ * 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 <stddef.h>
+#include <stdint.h>
+
+/* 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 */
diff --git a/drivers/arm/dcc/dcc_console.c b/drivers/arm/dcc/dcc_console.c
new file mode 100644
index 0000000..0b7e541
--- /dev/null
+++ b/drivers/arm/dcc/dcc_console.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2015-2021, Xilinx Inc.
+ * Written by Michal Simek.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * 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.
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <arch_helpers.h>
+#include <drivers/arm/dcc.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+/* DCC Status Bits */
+#define DCC_STATUS_RX BIT(30)
+#define DCC_STATUS_TX BIT(29)
+#define TIMEOUT_COUNT_US U(0x10624)
+
+struct dcc_console {
+ struct console console;
+};
+
+static inline uint32_t __dcc_getstatus(void)
+{
+ return read_mdccsr_el0();
+}
+
+static inline char __dcc_getchar(void)
+{
+ char c;
+
+ c = read_dbgdtrrx_el0();
+
+ return c;
+}
+
+static inline void __dcc_putchar(char c)
+{
+ /*
+ * The typecast is to make absolutely certain that 'c' is
+ * zero-extended.
+ */
+ write_dbgdtrtx_el0((unsigned char)c);
+}
+
+static int32_t dcc_status_timeout(uint32_t mask)
+{
+ const unsigned int timeout_count = TIMEOUT_COUNT_US;
+ uint64_t timeout;
+ unsigned int status;
+
+ timeout = timeout_init_us(timeout_count);
+
+ do {
+ status = (__dcc_getstatus() & mask);
+ if (timeout_elapsed(timeout)) {
+ return -ETIMEDOUT;
+ }
+ } while ((status != 0U));
+
+ return 0;
+}
+
+static int32_t dcc_console_putc(int32_t ch, struct console *console)
+{
+ unsigned int status;
+
+ status = dcc_status_timeout(DCC_STATUS_TX);
+ if (status != 0U) {
+ return status;
+ }
+ __dcc_putchar(ch);
+
+ return ch;
+}
+
+static int32_t dcc_console_getc(struct console *console)
+{
+ unsigned int status;
+
+ status = dcc_status_timeout(DCC_STATUS_RX);
+ if (status != 0U) {
+ return status;
+ }
+
+ return __dcc_getchar();
+}
+
+int32_t dcc_console_init(unsigned long base_addr, uint32_t uart_clk,
+ uint32_t baud_rate)
+{
+ return 0; /* No init needed */
+}
+
+/**
+ * dcc_console_flush() - Function to force a write of all buffered data
+ * that hasn't been output.
+ * @console Console struct
+ *
+ */
+static void dcc_console_flush(struct console *console)
+{
+ unsigned int status;
+
+ status = dcc_status_timeout(DCC_STATUS_TX);
+ if (status != 0U) {
+ return;
+ }
+}
+
+static struct dcc_console dcc_console = {
+ .console = {
+ .flags = CONSOLE_FLAG_BOOT |
+ CONSOLE_FLAG_RUNTIME,
+ .putc = dcc_console_putc,
+ .getc = dcc_console_getc,
+ .flush = dcc_console_flush,
+ },
+};
+
+int console_dcc_register(void)
+{
+ return console_register(&dcc_console.console);
+}
diff --git a/drivers/arm/ethosn/ethosn_smc.c b/drivers/arm/ethosn/ethosn_smc.c
new file mode 100644
index 0000000..915a0d8
--- /dev/null
+++ b/drivers/arm/ethosn/ethosn_smc.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <drivers/arm/ethosn.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <plat/arm/common/fconf_ethosn_getter.h>
+
+/*
+ * Number of Arm(R) Ethos(TM)-N NPU (NPU) devices available
+ */
+#define ETHOSN_NUM_DEVICES \
+ FCONF_GET_PROPERTY(hw_config, ethosn_config, num_devices)
+
+#define ETHOSN_GET_DEVICE(dev_idx) \
+ FCONF_GET_PROPERTY(hw_config, ethosn_device, dev_idx)
+
+/* NPU core sec registry address */
+#define ETHOSN_CORE_SEC_REG(core_addr, reg_offset) \
+ (core_addr + reg_offset)
+
+/* Reset timeout in us */
+#define ETHOSN_RESET_TIMEOUT_US U(10 * 1000 * 1000)
+#define ETHOSN_RESET_WAIT_US U(1)
+
+#define SEC_DEL_REG U(0x0004)
+#define SEC_DEL_VAL U(0x81C)
+#define SEC_DEL_EXCC_MASK U(0x20)
+
+#define SEC_SECCTLR_REG U(0x0010)
+#define SEC_SECCTLR_VAL U(0x3)
+
+#define SEC_DEL_ADDR_EXT_REG U(0x201C)
+#define SEC_DEL_ADDR_EXT_VAL U(0x15)
+
+#define SEC_SYSCTRL0_REG U(0x0018)
+#define SEC_SYSCTRL0_SOFT_RESET U(3U << 29)
+#define SEC_SYSCTRL0_HARD_RESET U(1U << 31)
+
+#define SEC_MMUSID_REG_BASE U(0x3008)
+#define SEC_MMUSID_OFFSET U(0x1000)
+
+static bool ethosn_get_device_and_core(uintptr_t core_addr,
+ const struct ethosn_device_t **dev_match,
+ const struct ethosn_core_t **core_match)
+{
+ uint32_t dev_idx;
+ uint32_t core_idx;
+
+ for (dev_idx = 0U; dev_idx < ETHOSN_NUM_DEVICES; ++dev_idx) {
+ const struct ethosn_device_t *dev = ETHOSN_GET_DEVICE(dev_idx);
+
+ for (core_idx = 0U; core_idx < dev->num_cores; ++core_idx) {
+ const struct ethosn_core_t *core = &(dev->cores[core_idx]);
+
+ if (core->addr == core_addr) {
+ *dev_match = dev;
+ *core_match = core;
+ return true;
+ }
+ }
+ }
+
+ WARN("ETHOSN: Unknown core address given to SMC call.\n");
+ return false;
+}
+
+static void ethosn_configure_smmu_streams(const struct ethosn_device_t *device,
+ const struct ethosn_core_t *core,
+ uint32_t asset_alloc_idx)
+{
+ const struct ethosn_main_allocator_t *main_alloc =
+ &(core->main_allocator);
+ const struct ethosn_asset_allocator_t *asset_alloc =
+ &(device->asset_allocators[asset_alloc_idx]);
+ const uint32_t streams[9] = {
+ main_alloc->firmware.stream_id,
+ main_alloc->working_data.stream_id,
+ asset_alloc->command_stream.stream_id,
+ 0U, /* Not used*/
+ main_alloc->firmware.stream_id,
+ asset_alloc->weight_data.stream_id,
+ asset_alloc->buffer_data.stream_id,
+ asset_alloc->intermediate_data.stream_id,
+ asset_alloc->buffer_data.stream_id
+ };
+ size_t i;
+
+ for (i = 0U; i < ARRAY_SIZE(streams); ++i) {
+ const uintptr_t reg_addr = SEC_MMUSID_REG_BASE +
+ (SEC_MMUSID_OFFSET * i);
+ mmio_write_32(ETHOSN_CORE_SEC_REG(core->addr, reg_addr),
+ streams[i]);
+ }
+}
+
+static void ethosn_delegate_to_ns(uintptr_t core_addr)
+{
+ mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_SECCTLR_REG),
+ SEC_SECCTLR_VAL);
+
+ mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_REG),
+ SEC_DEL_VAL);
+
+ mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_ADDR_EXT_REG),
+ SEC_DEL_ADDR_EXT_VAL);
+}
+
+static int ethosn_is_sec(uintptr_t core_addr)
+{
+ if ((mmio_read_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_REG))
+ & SEC_DEL_EXCC_MASK) != 0U) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static bool ethosn_reset(uintptr_t core_addr, int hard_reset)
+{
+ unsigned int timeout;
+ const uintptr_t sysctrl0_reg =
+ ETHOSN_CORE_SEC_REG(core_addr, SEC_SYSCTRL0_REG);
+ const uint32_t reset_val = (hard_reset != 0) ? SEC_SYSCTRL0_HARD_RESET
+ : SEC_SYSCTRL0_SOFT_RESET;
+
+ mmio_write_32(sysctrl0_reg, reset_val);
+
+ /* Wait for reset to complete */
+ for (timeout = 0U; timeout < ETHOSN_RESET_TIMEOUT_US;
+ timeout += ETHOSN_RESET_WAIT_US) {
+
+ if ((mmio_read_32(sysctrl0_reg) & reset_val) == 0U) {
+ break;
+ }
+
+ udelay(ETHOSN_RESET_WAIT_US);
+ }
+
+ return timeout < ETHOSN_RESET_TIMEOUT_US;
+}
+
+uintptr_t ethosn_smc_handler(uint32_t smc_fid,
+ u_register_t core_addr,
+ u_register_t asset_alloc_idx,
+ u_register_t x3,
+ u_register_t x4,
+ void *cookie,
+ void *handle,
+ u_register_t flags)
+{
+ int hard_reset = 0;
+ const struct ethosn_device_t *device = NULL;
+ const struct ethosn_core_t *core = NULL;
+ const uint32_t fid = smc_fid & FUNCID_NUM_MASK;
+
+ /* Only SiP fast calls are expected */
+ if ((GET_SMC_TYPE(smc_fid) != SMC_TYPE_FAST) ||
+ (GET_SMC_OEN(smc_fid) != OEN_SIP_START)) {
+ SMC_RET1(handle, SMC_UNK);
+ }
+
+ /* Truncate parameters to 32-bits for SMC32 */
+ if (GET_SMC_CC(smc_fid) == SMC_32) {
+ core_addr &= 0xFFFFFFFF;
+ asset_alloc_idx &= 0xFFFFFFFF;
+ x3 &= 0xFFFFFFFF;
+ x4 &= 0xFFFFFFFF;
+ }
+
+ if (!is_ethosn_fid(smc_fid) ||
+ (fid < ETHOSN_FNUM_VERSION || fid > ETHOSN_FNUM_SOFT_RESET)) {
+ WARN("ETHOSN: Unknown SMC call: 0x%x\n", smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+ }
+
+ /* Commands that do not require a valid core address */
+ switch (fid) {
+ case ETHOSN_FNUM_VERSION:
+ SMC_RET2(handle, ETHOSN_VERSION_MAJOR, ETHOSN_VERSION_MINOR);
+ }
+
+ if (!ethosn_get_device_and_core(core_addr, &device, &core)) {
+ SMC_RET1(handle, ETHOSN_UNKNOWN_CORE_ADDRESS);
+ }
+
+ /* Commands that require a valid core address */
+ switch (fid) {
+ case ETHOSN_FNUM_IS_SEC:
+ SMC_RET1(handle, ethosn_is_sec(core->addr));
+ }
+
+ if (!device->has_reserved_memory &&
+ asset_alloc_idx >= device->num_allocators) {
+ WARN("ETHOSN: Unknown asset allocator index given to SMC call.\n");
+ SMC_RET1(handle, ETHOSN_UNKNOWN_ALLOCATOR_IDX);
+ }
+
+ /* Commands that require a valid device, core and asset allocator */
+ switch (fid) {
+ case ETHOSN_FNUM_HARD_RESET:
+ hard_reset = 1;
+ /* Fallthrough */
+ case ETHOSN_FNUM_SOFT_RESET:
+ if (!ethosn_reset(core->addr, hard_reset)) {
+ SMC_RET1(handle, ETHOSN_FAILURE);
+ }
+
+ if (!device->has_reserved_memory) {
+ ethosn_configure_smmu_streams(device, core,
+ asset_alloc_idx);
+ }
+
+ ethosn_delegate_to_ns(core->addr);
+ SMC_RET1(handle, ETHOSN_SUCCESS);
+ default:
+ WARN("ETHOSN: Unimplemented SMC call: 0x%x\n", fid);
+ SMC_RET1(handle, SMC_UNK);
+ }
+}
diff --git a/drivers/arm/fvp/fvp_pwrc.c b/drivers/arm/fvp/fvp_pwrc.c
new file mode 100644
index 0000000..75a2b66
--- /dev/null
+++ b/drivers/arm/fvp/fvp_pwrc.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/fvp/fvp_pwrc.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+/*
+ * 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();
+}
+
+
+
diff --git a/drivers/arm/gic/common/gic_common.c b/drivers/arm/gic/common/gic_common.c
new file mode 100644
index 0000000..bf6405f
--- /dev/null
+++ b/drivers/arm/gic/common/gic_common.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#pragma message __FILE__ " is deprecated, use gicv2.mk instead"
+
+#include <assert.h>
+
+#include <drivers/arm/gic_common.h>
+#include <lib/mmio.h>
+
+#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);
+}
diff --git a/drivers/arm/gic/common/gic_common_private.h b/drivers/arm/gic/common/gic_common_private.h
new file mode 100644
index 0000000..1ab1bdb
--- /dev/null
+++ b/drivers/arm/gic/common/gic_common_private.h
@@ -0,0 +1,89 @@
+/*
+ * 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 <stdint.h>
+
+#include <drivers/arm/gic_common.h>
+#include <lib/mmio.h>
+
+/*******************************************************************************
+ * 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 */
diff --git a/drivers/arm/gic/v2/gicdv2_helpers.c b/drivers/arm/gic/v2/gicdv2_helpers.c
new file mode 100644
index 0000000..db9ba87
--- /dev/null
+++ b/drivers/arm/gic/v2/gicdv2_helpers.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <drivers/arm/gic_common.h>
+#include <lib/mmio.h>
+
+#include "../common/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);
+}
diff --git a/drivers/arm/gic/v2/gicv2.mk b/drivers/arm/gic/v2/gicv2.mk
new file mode 100644
index 0000000..49996bb
--- /dev/null
+++ b/drivers/arm/gic/v2/gicv2.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (c) 2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# No support for extended PPI and SPI range
+GIC_EXT_INTID := 0
+
+GICV2_SOURCES += drivers/arm/gic/v2/gicv2_main.c \
+ drivers/arm/gic/v2/gicv2_helpers.c \
+ drivers/arm/gic/v2/gicdv2_helpers.c
+
+# Set GICv2 build option
+$(eval $(call add_define,GIC_EXT_INTID)) \ No newline at end of file
diff --git a/drivers/arm/gic/v2/gicv2_helpers.c b/drivers/arm/gic/v2/gicv2_helpers.c
new file mode 100644
index 0000000..751316c
--- /dev/null
+++ b/drivers/arm/gic/v2/gicv2_helpers.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+
+#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);
+}
diff --git a/drivers/arm/gic/v2/gicv2_main.c b/drivers/arm/gic/v2/gicv2_main.c
new file mode 100644
index 0000000..1925a13
--- /dev/null
+++ b/drivers/arm/gic/v2/gicv2_main.c
@@ -0,0 +1,556 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Portions copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/spinlock.h>
+
+#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);
+
+ /*
+ * Ensure the write to peripheral registers are *complete* before the write
+ * to GIC_EOIR.
+ *
+ * Note: The completion gurantee depends on various factors of system design
+ * and the barrier is the best core can do by which execution of further
+ * instructions waits till the barrier is alive.
+ */
+ dsbishst();
+ 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(proc_num < GICV2_MAX_TARGET_PE);
+ assert(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, bool ns, int proc_num)
+{
+ unsigned int sgir_val, target;
+
+ assert(driver_data != NULL);
+ assert(proc_num >= 0);
+ assert(proc_num < (int)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(proc_num < (int)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, ns, 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(proc_num < (int)GICV2_MAX_TARGET_PE);
+ assert(driver_data->target_masks_num < INT_MAX);
+ assert(proc_num < (int)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);
+}
diff --git a/drivers/arm/gic/v2/gicv2_private.h b/drivers/arm/gic/v2/gicv2_private.h
new file mode 100644
index 0000000..0fbdab0
--- /dev/null
+++ b/drivers/arm/gic/v2/gicv2_private.h
@@ -0,0 +1,150 @@
+/*
+ * 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 <stdint.h>
+
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+
+/*******************************************************************************
+ * 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 */
diff --git a/drivers/arm/gic/v3/arm_gicv3_common.c b/drivers/arm/gic/v3/arm_gicv3_common.c
new file mode 100644
index 0000000..4489892
--- /dev/null
+++ b/drivers/arm/gic/v3/arm_gicv3_common.c
@@ -0,0 +1,115 @@
+/*
+ * 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 <assert.h>
+
+#include <arch_helpers.h>
+#include <drivers/arm/arm_gicv3_common.h>
+#include <drivers/arm/gicv3.h>
+
+#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)
+ ;
+}
+
diff --git a/drivers/arm/gic/v3/gic-x00.c b/drivers/arm/gic/v3/gic-x00.c
new file mode 100644
index 0000000..83ef32f
--- /dev/null
+++ b/drivers/arm/gic/v3/gic-x00.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Driver for GIC-500 and GIC-600 specific features. This driver only
+ * overrides APIs that are different to those generic ones in GICv3
+ * driver.
+ *
+ * GIC-600 supports independently power-gating redistributor interface.
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/arm_gicv3_common.h>
+#include <drivers/arm/gicv3.h>
+
+#include "gicv3_private.h"
+
+/* GIC-600 specific register offsets */
+#define GICR_PWRR 0x24U
+
+/* GICR_PWRR fields */
+#define PWRR_RDPD_SHIFT 0
+#define PWRR_RDAG_SHIFT 1
+#define PWRR_RDGPD_SHIFT 2
+#define PWRR_RDGPO_SHIFT 3
+
+#define PWRR_RDPD (1U << PWRR_RDPD_SHIFT)
+#define PWRR_RDAG (1U << PWRR_RDAG_SHIFT)
+#define PWRR_RDGPD (1U << PWRR_RDGPD_SHIFT)
+#define PWRR_RDGPO (1U << PWRR_RDGPO_SHIFT)
+
+/*
+ * Values to write to GICR_PWRR register to power redistributor
+ * for operating through the core (GICR_PWRR.RDAG = 0)
+ */
+#define PWRR_ON (0U << PWRR_RDPD_SHIFT)
+#define PWRR_OFF (1U << PWRR_RDPD_SHIFT)
+
+static bool gic600_errata_wa_2384374 __unused;
+
+#if GICV3_SUPPORT_GIC600
+
+/* GIC-600/700 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 void gicr_wait_group_not_in_transit(uintptr_t base)
+{
+ uint32_t pwrr;
+
+ do {
+ pwrr = gicr_read_pwrr(base);
+
+ /* Check group not transitioning: RDGPD == RDGPO */
+ } while (((pwrr & PWRR_RDGPD) >> PWRR_RDGPD_SHIFT) !=
+ ((pwrr & PWRR_RDGPO) >> PWRR_RDGPO_SHIFT));
+}
+
+static void gic600_pwr_on(uintptr_t base)
+{
+ do { /* Wait until group not transitioning */
+ gicr_wait_group_not_in_transit(base);
+
+ /* Power on redistributor */
+ gicr_write_pwrr(base, PWRR_ON);
+
+ /*
+ * Wait until the power on state is reflected.
+ * If RDPD == 0 then powered on.
+ */
+ } while ((gicr_read_pwrr(base) & PWRR_RDPD) != PWRR_ON);
+}
+
+static void gic600_pwr_off(uintptr_t base)
+{
+ /* Wait until group not transitioning */
+ gicr_wait_group_not_in_transit(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 and RDGPD = 1.
+ * 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) != 0U) {
+ /* Wait until group not transitioning */
+ gicr_wait_group_not_in_transit(base);
+ }
+}
+
+static uintptr_t get_gicr_base(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);
+
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+ assert(gicr_base != 0UL);
+
+ return gicr_base;
+}
+
+static bool gicv3_redists_need_power_mgmt(uintptr_t gicr_base)
+{
+ uint32_t reg = mmio_read_32(gicr_base + GICR_IIDR);
+
+ /*
+ * The Arm GIC-600 and GIC-700 models have their redistributors
+ * powered down at reset.
+ */
+ return (((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600) ||
+ ((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600AE) ||
+ ((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_700));
+}
+
+#endif /* GICV3_SUPPORT_GIC600 */
+
+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 GIC-600 redistributor (if configured and detected)
+ */
+void gicv3_rdistif_off(unsigned int proc_num)
+{
+#if GICV3_SUPPORT_GIC600
+ uintptr_t gicr_base = get_gicr_base(proc_num);
+
+ /* Attempt to power redistributor off */
+ if (gicv3_redists_need_power_mgmt(gicr_base)) {
+ gic600_pwr_off(gicr_base);
+ }
+#endif
+}
+
+/*
+ * Power on GIC-600 redistributor (if configured and detected)
+ */
+void gicv3_rdistif_on(unsigned int proc_num)
+{
+#if GICV3_SUPPORT_GIC600
+ uintptr_t gicr_base = get_gicr_base(proc_num);
+
+ /* Power redistributor on */
+ if (gicv3_redists_need_power_mgmt(gicr_base)) {
+ gic600_pwr_on(gicr_base);
+ }
+#endif
+}
+
+#if GIC600_ERRATA_WA_2384374
+/*******************************************************************************
+ * Apply part 2 of workaround for errata-2384374 as per SDEN:
+ * https://developer.arm.com/documentation/sden892601/latest/
+ ******************************************************************************/
+void gicv3_apply_errata_wa_2384374(uintptr_t gicr_base)
+{
+ if (gic600_errata_wa_2384374) {
+ uint32_t gicr_ctlr_val = gicr_read_ctlr(gicr_base);
+
+ gicr_write_ctlr(gicr_base, gicr_ctlr_val |
+ (GICR_CTLR_DPG0_BIT | GICR_CTLR_DPG1NS_BIT |
+ GICR_CTLR_DPG1S_BIT));
+ gicr_write_ctlr(gicr_base, gicr_ctlr_val &
+ ~(GICR_CTLR_DPG0_BIT | GICR_CTLR_DPG1NS_BIT |
+ GICR_CTLR_DPG1S_BIT));
+ }
+}
+#endif /* GIC600_ERRATA_WA_2384374 */
+
+void gicv3_check_erratas_applies(uintptr_t gicd_base)
+{
+ unsigned int gic_prod_id;
+ uint8_t gic_rev;
+
+ assert(gicd_base != 0UL);
+
+ gicv3_get_component_prodid_rev(gicd_base, &gic_prod_id, &gic_rev);
+
+ /*
+ * This workaround applicable only to GIC600 and GIC600AE products with
+ * revision less than r1p6 and r0p2 respectively.
+ * As per GIC600/GIC600AE specification -
+ * r1p6 = 0x17 => GICD_IIDR[19:12]
+ * r0p2 = 0x04 => GICD_IIDR[19:12]
+ */
+ if ((gic_prod_id == GIC_PRODUCT_ID_GIC600) ||
+ (gic_prod_id == GIC_PRODUCT_ID_GIC600AE)) {
+ if (((gic_prod_id == GIC_PRODUCT_ID_GIC600) &&
+ (gic_rev <= GIC_REV(GIC_VARIANT_R1, GIC_REV_P6))) ||
+ ((gic_prod_id == GIC_PRODUCT_ID_GIC600AE) &&
+ (gic_rev <= GIC_REV(GIC_VARIANT_R0, GIC_REV_P2)))) {
+#if GIC600_ERRATA_WA_2384374
+ gic600_errata_wa_2384374 = true;
+ VERBOSE("%s applies\n",
+ "GIC600/GIC600AE errata workaround 2384374");
+#else
+ WARN("%s missing\n",
+ "GIC600/GIC600AE errata workaround 2384374");
+#endif /* GIC600_ERRATA_WA_2384374 */
+ } else {
+ VERBOSE("%s not applies\n",
+ "GIC600/GIC600AE errata workaround 2384374");
+ }
+ }
+}
diff --git a/drivers/arm/gic/v3/gic600_multichip.c b/drivers/arm/gic/v3/gic600_multichip.c
new file mode 100644
index 0000000..e85dbc1
--- /dev/null
+++ b/drivers/arm/gic/v3/gic600_multichip.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2022, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * GIC-600 driver extension for multichip setup
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/arm/arm_gicv3_common.h>
+#include <drivers/arm/gic600_multichip.h>
+#include <drivers/arm/gicv3.h>
+
+#include "../common/gic_common_private.h"
+#include "gic600_multichip_private.h"
+
+/*******************************************************************************
+ * GIC-600 multichip operation related helper functions
+ ******************************************************************************/
+static void gicd_dchipr_wait_for_power_update_progress(uintptr_t base)
+{
+ unsigned int retry = GICD_PUP_UPDATE_RETRIES;
+
+ while ((read_gicd_dchipr(base) & GICD_DCHIPR_PUP_BIT) != 0U) {
+ if (retry-- == 0) {
+ ERROR("GIC-600 connection to Routing Table Owner timed "
+ "out\n");
+ panic();
+ }
+ }
+}
+
+/*******************************************************************************
+ * Sets up the routing table owner.
+ ******************************************************************************/
+static void set_gicd_dchipr_rt_owner(uintptr_t base, unsigned int rt_owner)
+{
+ /*
+ * Ensure that Group enables in GICD_CTLR are disabled and no pending
+ * register writes to GICD_CTLR.
+ */
+ if ((gicd_read_ctlr(base) &
+ (CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1S_BIT |
+ CTLR_ENABLE_G1NS_BIT | GICD_CTLR_RWP_BIT)) != 0) {
+ ERROR("GICD_CTLR group interrupts are either enabled or have "
+ "pending writes. Cannot set RT owner.\n");
+ panic();
+ }
+
+ /* Poll till PUP is zero before intiating write */
+ gicd_dchipr_wait_for_power_update_progress(base);
+
+ write_gicd_dchipr(base, read_gicd_dchipr(base) |
+ (rt_owner << GICD_DCHIPR_RT_OWNER_SHIFT));
+
+ /* Poll till PUP is zero to ensure write is complete */
+ gicd_dchipr_wait_for_power_update_progress(base);
+}
+
+/*******************************************************************************
+ * Configures the Chip Register to make connections to GICDs on
+ * a multichip platform.
+ ******************************************************************************/
+static void set_gicd_chipr_n(uintptr_t base,
+ unsigned int chip_id,
+ uint64_t chip_addr,
+ unsigned int spi_id_min,
+ unsigned int spi_id_max)
+{
+ unsigned int spi_block_min, spi_blocks;
+ unsigned int gicd_iidr_val = gicd_read_iidr(base);
+ uint64_t chipr_n_val;
+
+ /*
+ * Ensure that group enables in GICD_CTLR are disabled and no pending
+ * register writes to GICD_CTLR.
+ */
+ if ((gicd_read_ctlr(base) &
+ (CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1S_BIT |
+ CTLR_ENABLE_G1NS_BIT | GICD_CTLR_RWP_BIT)) != 0) {
+ ERROR("GICD_CTLR group interrupts are either enabled or have "
+ "pending writes. Cannot set CHIPR register.\n");
+ panic();
+ }
+
+ /*
+ * spi_id_min and spi_id_max of value 0 is used to intidicate that the
+ * chip doesn't own any SPI block. Re-assign min and max values as SPI
+ * id starts from 32.
+ */
+ if (spi_id_min == 0 && spi_id_max == 0) {
+ spi_id_min = GIC600_SPI_ID_MIN;
+ spi_id_max = GIC600_SPI_ID_MIN;
+ }
+
+ switch ((gicd_iidr_val & IIDR_MODEL_MASK)) {
+ case IIDR_MODEL_ARM_GIC_600:
+ spi_block_min = SPI_BLOCK_MIN_VALUE(spi_id_min);
+ spi_blocks = SPI_BLOCKS_VALUE(spi_id_min, spi_id_max);
+
+ chipr_n_val = GICD_CHIPR_VALUE_GIC_600(chip_addr,
+ spi_block_min,
+ spi_blocks);
+ break;
+ case IIDR_MODEL_ARM_GIC_700:
+ /* Calculate the SPI_ID_MIN value for ESPI */
+ if (spi_id_min >= GIC700_ESPI_ID_MIN) {
+ spi_block_min = ESPI_BLOCK_MIN_VALUE(spi_id_min);
+ spi_block_min += SPI_BLOCKS_VALUE(GIC700_SPI_ID_MIN,
+ GIC700_SPI_ID_MAX);
+ } else {
+ spi_block_min = SPI_BLOCK_MIN_VALUE(spi_id_min);
+ }
+
+ /* Calculate the total number of blocks */
+ spi_blocks = SPI_BLOCKS_VALUE(spi_id_min, spi_id_max);
+
+ chipr_n_val = GICD_CHIPR_VALUE_GIC_700(chip_addr,
+ spi_block_min,
+ spi_blocks);
+ break;
+ default:
+ ERROR("Unsupported GIC model 0x%x for multichip setup.\n",
+ gicd_iidr_val);
+ panic();
+ break;
+ }
+ chipr_n_val |= GICD_CHIPRx_SOCKET_STATE;
+
+ /*
+ * Wait for DCHIPR.PUP to be zero before commencing writes to
+ * GICD_CHIPRx.
+ */
+ gicd_dchipr_wait_for_power_update_progress(base);
+
+ /*
+ * Assign chip addr, spi min block, number of spi blocks and bring chip
+ * online by setting SocketState.
+ */
+ write_gicd_chipr_n(base, chip_id, chipr_n_val);
+
+ /*
+ * Poll until DCHIP.PUP is zero to verify connection to rt_owner chip
+ * is complete.
+ */
+ gicd_dchipr_wait_for_power_update_progress(base);
+
+ /*
+ * Ensure that write to GICD_CHIPRx is successful and the chip_n came
+ * online.
+ */
+ if (read_gicd_chipr_n(base, chip_id) != chipr_n_val) {
+ ERROR("GICD_CHIPR%u write failed\n", chip_id);
+ panic();
+ }
+
+ /* Ensure that chip is in consistent state */
+ if (((read_gicd_chipsr(base) & GICD_CHIPSR_RTS_MASK) >>
+ GICD_CHIPSR_RTS_SHIFT) !=
+ GICD_CHIPSR_RTS_STATE_CONSISTENT) {
+ ERROR("Chip %u routing table is not in consistent state\n",
+ chip_id);
+ panic();
+ }
+}
+
+/*******************************************************************************
+ * Validates the GIC-600 Multichip data structure passed by the platform.
+ ******************************************************************************/
+static void gic600_multichip_validate_data(
+ struct gic600_multichip_data *multichip_data)
+{
+ unsigned int i, spi_id_min, spi_id_max, blocks_of_32;
+ unsigned int multichip_spi_blocks = 0;
+
+ assert(multichip_data != NULL);
+
+ if (multichip_data->chip_count > GIC600_MAX_MULTICHIP) {
+ ERROR("GIC-600 Multichip count should not exceed %d\n",
+ GIC600_MAX_MULTICHIP);
+ panic();
+ }
+
+ for (i = 0; i < multichip_data->chip_count; i++) {
+ spi_id_min = multichip_data->spi_ids[i][SPI_MIN_INDEX];
+ spi_id_max = multichip_data->spi_ids[i][SPI_MAX_INDEX];
+
+ if ((spi_id_min != 0) || (spi_id_max != 0)) {
+
+ /* SPI IDs range check */
+ if (!(spi_id_min >= GIC600_SPI_ID_MIN) ||
+ !(spi_id_max < GIC600_SPI_ID_MAX) ||
+ !(spi_id_min <= spi_id_max) ||
+ !((spi_id_max - spi_id_min + 1) % 32 == 0)) {
+ ERROR("Invalid SPI IDs {%u, %u} passed for "
+ "Chip %u\n", spi_id_min,
+ spi_id_max, i);
+ panic();
+ }
+
+ /* SPI IDs overlap check */
+ blocks_of_32 = BLOCKS_OF_32(spi_id_min, spi_id_max);
+ if ((multichip_spi_blocks & blocks_of_32) != 0) {
+ ERROR("SPI IDs of Chip %u overlapping\n", i);
+ panic();
+ }
+ multichip_spi_blocks |= blocks_of_32;
+ }
+ }
+}
+
+/*******************************************************************************
+ * Validates the GIC-700 Multichip data structure passed by the platform.
+ ******************************************************************************/
+static void gic700_multichip_validate_data(
+ struct gic600_multichip_data *multichip_data)
+{
+ unsigned int i, spi_id_min, spi_id_max, blocks_of_32;
+ unsigned int multichip_spi_blocks = 0U, multichip_espi_blocks = 0U;
+
+ assert(multichip_data != NULL);
+
+ if (multichip_data->chip_count > GIC600_MAX_MULTICHIP) {
+ ERROR("GIC-700 Multichip count (%u) should not exceed %u\n",
+ multichip_data->chip_count, GIC600_MAX_MULTICHIP);
+ panic();
+ }
+
+ for (i = 0U; i < multichip_data->chip_count; i++) {
+ spi_id_min = multichip_data->spi_ids[i][SPI_MIN_INDEX];
+ spi_id_max = multichip_data->spi_ids[i][SPI_MAX_INDEX];
+
+ if ((spi_id_min == 0U) || (spi_id_max == 0U)) {
+ continue;
+ }
+
+ /* MIN SPI ID check */
+ if ((spi_id_min < GIC700_SPI_ID_MIN) ||
+ ((spi_id_min >= GIC700_SPI_ID_MAX) &&
+ (spi_id_min < GIC700_ESPI_ID_MIN))) {
+ ERROR("Invalid MIN SPI ID {%u} passed for "
+ "Chip %u\n", spi_id_min, i);
+ panic();
+ }
+
+ if ((spi_id_min > spi_id_max) ||
+ ((spi_id_max - spi_id_min + 1) % 32 != 0)) {
+ ERROR("Unaligned SPI IDs {%u, %u} passed for "
+ "Chip %u\n", spi_id_min,
+ spi_id_max, i);
+ panic();
+ }
+
+ /* ESPI IDs range check */
+ if ((spi_id_min >= GIC700_ESPI_ID_MIN) &&
+ (spi_id_max > GIC700_ESPI_ID_MAX)) {
+ ERROR("Invalid ESPI IDs {%u, %u} passed for "
+ "Chip %u\n", spi_id_min,
+ spi_id_max, i);
+ panic();
+
+ }
+
+ /* SPI IDs range check */
+ if (((spi_id_min < GIC700_SPI_ID_MAX) &&
+ (spi_id_max > GIC700_SPI_ID_MAX))) {
+ ERROR("Invalid SPI IDs {%u, %u} passed for "
+ "Chip %u\n", spi_id_min,
+ spi_id_max, i);
+ panic();
+ }
+
+ /* SPI IDs overlap check */
+ if (spi_id_max < GIC700_SPI_ID_MAX) {
+ blocks_of_32 = BLOCKS_OF_32(spi_id_min, spi_id_max);
+ if ((multichip_spi_blocks & blocks_of_32) != 0) {
+ ERROR("SPI IDs of Chip %u overlapping\n", i);
+ panic();
+ }
+ multichip_spi_blocks |= blocks_of_32;
+ }
+
+ /* ESPI IDs overlap check */
+ if (spi_id_max > GIC700_ESPI_ID_MIN) {
+ blocks_of_32 = BLOCKS_OF_32(spi_id_min - GIC700_ESPI_ID_MIN,
+ spi_id_max - GIC700_ESPI_ID_MIN);
+ if ((multichip_espi_blocks & blocks_of_32) != 0) {
+ ERROR("SPI IDs of Chip %u overlapping\n", i);
+ panic();
+ }
+ multichip_espi_blocks |= blocks_of_32;
+ }
+ }
+}
+
+/*******************************************************************************
+ * Intialize GIC-600 and GIC-700 Multichip operation.
+ ******************************************************************************/
+void gic600_multichip_init(struct gic600_multichip_data *multichip_data)
+{
+ unsigned int i;
+ uint32_t gicd_iidr_val = gicd_read_iidr(multichip_data->rt_owner_base);
+
+ if ((gicd_iidr_val & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600) {
+ gic600_multichip_validate_data(multichip_data);
+ }
+
+ if ((gicd_iidr_val & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_700) {
+ gic700_multichip_validate_data(multichip_data);
+ }
+
+ /*
+ * Ensure that G0/G1S/G1NS interrupts are disabled. This also ensures
+ * that GIC-600 Multichip configuration is done first.
+ */
+ if ((gicd_read_ctlr(multichip_data->rt_owner_base) &
+ (CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1S_BIT |
+ CTLR_ENABLE_G1NS_BIT | GICD_CTLR_RWP_BIT)) != 0) {
+ ERROR("GICD_CTLR group interrupts are either enabled or have "
+ "pending writes.\n");
+ panic();
+ }
+
+ /* Ensure that the routing table owner is in disconnected state */
+ if (((read_gicd_chipsr(multichip_data->rt_owner_base) &
+ GICD_CHIPSR_RTS_MASK) >> GICD_CHIPSR_RTS_SHIFT) !=
+ GICD_CHIPSR_RTS_STATE_DISCONNECTED) {
+ ERROR("GIC-600 routing table owner is not in disconnected "
+ "state to begin multichip configuration\n");
+ panic();
+ }
+
+ /* Initialize the GICD which is marked as routing table owner first */
+ set_gicd_dchipr_rt_owner(multichip_data->rt_owner_base,
+ multichip_data->rt_owner);
+
+ set_gicd_chipr_n(multichip_data->rt_owner_base, multichip_data->rt_owner,
+ multichip_data->chip_addrs[multichip_data->rt_owner],
+ multichip_data->
+ spi_ids[multichip_data->rt_owner][SPI_MIN_INDEX],
+ multichip_data->
+ spi_ids[multichip_data->rt_owner][SPI_MAX_INDEX]);
+
+ for (i = 0; i < multichip_data->chip_count; i++) {
+ if (i == multichip_data->rt_owner)
+ continue;
+
+ set_gicd_chipr_n(multichip_data->rt_owner_base, i,
+ multichip_data->chip_addrs[i],
+ multichip_data->spi_ids[i][SPI_MIN_INDEX],
+ multichip_data->spi_ids[i][SPI_MAX_INDEX]);
+ }
+}
diff --git a/drivers/arm/gic/v3/gic600_multichip_private.h b/drivers/arm/gic/v3/gic600_multichip_private.h
new file mode 100644
index 0000000..414bd5b
--- /dev/null
+++ b/drivers/arm/gic/v3/gic600_multichip_private.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GIC600_MULTICHIP_PRIVATE_H
+#define GIC600_MULTICHIP_PRIVATE_H
+
+#include <drivers/arm/gic600_multichip.h>
+
+#include "gicv3_private.h"
+
+/* GIC600 GICD multichip related offsets */
+#define GICD_CHIPSR U(0xC000)
+#define GICD_DCHIPR U(0xC004)
+#define GICD_CHIPR U(0xC008)
+
+/* GIC600 GICD multichip related masks */
+#define GICD_CHIPRx_PUP_BIT BIT_64(1)
+#define GICD_CHIPRx_SOCKET_STATE BIT_64(0)
+#define GICD_DCHIPR_PUP_BIT BIT_32(0)
+#define GICD_CHIPSR_RTS_MASK (BIT_32(4) | BIT_32(5))
+
+/* GIC600 GICD multichip related shifts */
+#define GICD_CHIPRx_ADDR_SHIFT 16
+#define GICD_CHIPSR_RTS_SHIFT 4
+#define GICD_DCHIPR_RT_OWNER_SHIFT 4
+
+/* Other shifts and masks remain the same between GIC-600 and GIC-700. */
+#define GIC_700_SPI_BLOCK_MIN_SHIFT 9
+#define GIC_700_SPI_BLOCKS_SHIFT 3
+#define GIC_600_SPI_BLOCK_MIN_SHIFT 10
+#define GIC_600_SPI_BLOCKS_SHIFT 5
+
+#define GICD_CHIPSR_RTS_STATE_DISCONNECTED U(0)
+#define GICD_CHIPSR_RTS_STATE_UPDATING U(1)
+#define GICD_CHIPSR_RTS_STATE_CONSISTENT U(2)
+
+/* SPI interrupt id minimum and maximum range */
+#define GIC600_SPI_ID_MIN 32
+#define GIC600_SPI_ID_MAX 960
+
+#define GIC700_SPI_ID_MIN 32
+#define GIC700_SPI_ID_MAX 991
+#define GIC700_ESPI_ID_MIN 4096
+#define GIC700_ESPI_ID_MAX 5119
+
+/* Number of retries for PUP update */
+#define GICD_PUP_UPDATE_RETRIES 10000
+
+#define SPI_MIN_INDEX 0
+#define SPI_MAX_INDEX 1
+
+#define SPI_BLOCK_MIN_VALUE(spi_id_min) \
+ (((spi_id_min) - GIC600_SPI_ID_MIN) / \
+ GIC600_SPI_ID_MIN)
+#define SPI_BLOCKS_VALUE(spi_id_min, spi_id_max) \
+ (((spi_id_max) - (spi_id_min) + 1) / \
+ GIC600_SPI_ID_MIN)
+#define ESPI_BLOCK_MIN_VALUE(spi_id_min) \
+ (((spi_id_min) - GIC700_ESPI_ID_MIN + 1) / \
+ GIC700_SPI_ID_MIN)
+#define GICD_CHIPR_VALUE_GIC_700(chip_addr, spi_block_min, spi_blocks) \
+ (((chip_addr) << GICD_CHIPRx_ADDR_SHIFT) | \
+ ((spi_block_min) << GIC_700_SPI_BLOCK_MIN_SHIFT) | \
+ ((spi_blocks) << GIC_700_SPI_BLOCKS_SHIFT))
+#define GICD_CHIPR_VALUE_GIC_600(chip_addr, spi_block_min, spi_blocks) \
+ (((chip_addr) << GICD_CHIPRx_ADDR_SHIFT) | \
+ ((spi_block_min) << GIC_600_SPI_BLOCK_MIN_SHIFT) | \
+ ((spi_blocks) << GIC_600_SPI_BLOCKS_SHIFT))
+
+/*
+ * Multichip data assertion macros
+ */
+/* Set bits from 0 to ((spi_id_max + 1) / 32) */
+#define SPI_BLOCKS_TILL_MAX(spi_id_max) \
+ ((1ULL << (((spi_id_max) + 1) >> 5)) - 1)
+/* Set bits from 0 to (spi_id_min / 32) */
+#define SPI_BLOCKS_TILL_MIN(spi_id_min) ((1 << ((spi_id_min) >> 5)) - 1)
+/* Set bits from (spi_id_min / 32) to ((spi_id_max + 1) / 32) */
+#define BLOCKS_OF_32(spi_id_min, spi_id_max) \
+ SPI_BLOCKS_TILL_MAX(spi_id_max) ^ \
+ SPI_BLOCKS_TILL_MIN(spi_id_min)
+
+/*******************************************************************************
+ * GIC-600 multichip operation related helper functions
+ ******************************************************************************/
+static inline uint32_t read_gicd_dchipr(uintptr_t base)
+{
+ return mmio_read_32(base + GICD_DCHIPR);
+}
+
+static inline uint64_t read_gicd_chipr_n(uintptr_t base, uint8_t n)
+{
+ return mmio_read_64(base + (GICD_CHIPR + (8U * n)));
+}
+
+static inline uint32_t read_gicd_chipsr(uintptr_t base)
+{
+ return mmio_read_32(base + GICD_CHIPSR);
+}
+
+static inline void write_gicd_dchipr(uintptr_t base, uint32_t val)
+{
+ mmio_write_32(base + GICD_DCHIPR, val);
+}
+
+static inline void write_gicd_chipr_n(uintptr_t base, uint8_t n, uint64_t val)
+{
+ mmio_write_64(base + (GICD_CHIPR + (8U * n)), val);
+}
+
+#endif /* GIC600_MULTICHIP_PRIVATE_H */
diff --git a/drivers/arm/gic/v3/gic600ae_fmu.c b/drivers/arm/gic/v3/gic600ae_fmu.c
new file mode 100644
index 0000000..0262f48
--- /dev/null
+++ b/drivers/arm/gic/v3/gic600ae_fmu.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2021-2022, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Driver for GIC-600AE Fault Management Unit
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gic600ae_fmu.h>
+#include <drivers/arm/gicv3.h>
+
+/* GIC-600 AE FMU specific register offsets */
+
+/* GIC-600 AE FMU specific macros */
+#define FMU_ERRIDR_NUM U(44)
+#define FMU_ERRIDR_NUM_MASK U(0xFFFF)
+
+/* Safety mechanisms for GICD block */
+static char *gicd_sm_info[] = {
+ "Reserved",
+ "GICD dual lockstep error",
+ "GICD AXI4 slave interface error",
+ "GICD-PPI AXI4-Stream interface error",
+ "GICD-ITS AXI4-Stream interface error",
+ "GICD-SPI-Collator AXI4-Stream interface error",
+ "GICD AXI4 master interface error",
+ "SPI RAM DED error",
+ "SGI RAM DED error",
+ "Reserved",
+ "LPI RAM DED error",
+ "GICD-remote-GICD AXI4-Stream interface error",
+ "GICD Q-Channel interface error",
+ "GICD P-Channel interface error",
+ "SPI RAM address decode error",
+ "SGI RAM address decode error",
+ "Reserved",
+ "LPI RAM address decode error",
+ "FMU dual lockstep error",
+ "FMU ping ACK error",
+ "FMU APB parity error",
+ "GICD-Wake AXI4-Stream interface error",
+ "GICD PageOffset or Chip ID error",
+ "MBIST REQ error",
+ "SPI RAM SEC error",
+ "SGI RAM SEC error",
+ "Reserved",
+ "LPI RAM SEC error",
+ "User custom SM0 error",
+ "User custom SM1 error",
+ "GICD-ITS Monolithic switch error",
+ "GICD-ITS Q-Channel interface error",
+ "GICD-ITS Monolithic interface error",
+ "GICD FMU ClkGate override"
+};
+
+/* Safety mechanisms for PPI block */
+static char *ppi_sm_info[] = {
+ "Reserved",
+ "PPI dual lockstep error",
+ "PPI-GICD AXI4-Stream interface error",
+ "PPI-CPU-IF AXI4-Stream interface error",
+ "PPI Q-Channel interface error",
+ "PPI RAM DED error",
+ "PPI RAM address decode error",
+ "PPI RAM SEC error",
+ "PPI User0 SM",
+ "PPI User1 SM",
+ "MBIST REQ error",
+ "PPI interrupt parity protection error",
+ "PPI FMU ClkGate override"
+};
+
+/* Safety mechanisms for ITS block */
+static char *its_sm_info[] = {
+ "Reserved",
+ "ITS dual lockstep error",
+ "ITS-GICD AXI4-Stream interface error",
+ "ITS AXI4 slave interface error",
+ "ITS AXI4 master interface error",
+ "ITS Q-Channel interface error",
+ "ITS RAM DED error",
+ "ITS RAM address decode error",
+ "Bypass ACE switch error",
+ "ITS RAM SEC error",
+ "ITS User0 SM",
+ "ITS User1 SM",
+ "ITS-GICD Monolithic interface error",
+ "MBIST REQ error",
+ "ITS FMU ClkGate override"
+};
+
+/* Safety mechanisms for SPI Collator block */
+static char *spicol_sm_info[] = {
+ "Reserved",
+ "SPI Collator dual lockstep error",
+ "SPI-Collator-GICD AXI4-Stream interface error",
+ "SPI Collator Q-Channel interface error",
+ "SPI Collator Q-Channel clock error",
+ "SPI interrupt parity error"
+};
+
+/* Safety mechanisms for Wake Request block */
+static char *wkrqst_sm_info[] = {
+ "Reserved",
+ "Wake dual lockstep error",
+ "Wake-GICD AXI4-Stream interface error"
+};
+
+/* Helper function to find detailed information for a specific IERR */
+static char __unused *ras_ierr_to_str(unsigned int blkid, unsigned int ierr)
+{
+ char *str = NULL;
+
+ /* Find the correct record */
+ switch (blkid) {
+ case FMU_BLK_GICD:
+ assert(ierr < ARRAY_SIZE(gicd_sm_info));
+ str = gicd_sm_info[ierr];
+ break;
+
+ case FMU_BLK_SPICOL:
+ assert(ierr < ARRAY_SIZE(spicol_sm_info));
+ str = spicol_sm_info[ierr];
+ break;
+
+ case FMU_BLK_WAKERQ:
+ assert(ierr < ARRAY_SIZE(wkrqst_sm_info));
+ str = wkrqst_sm_info[ierr];
+ break;
+
+ case FMU_BLK_ITS0...FMU_BLK_ITS7:
+ assert(ierr < ARRAY_SIZE(its_sm_info));
+ str = its_sm_info[ierr];
+ break;
+
+ case FMU_BLK_PPI0...FMU_BLK_PPI31:
+ assert(ierr < ARRAY_SIZE(ppi_sm_info));
+ str = ppi_sm_info[ierr];
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ return str;
+}
+
+/*
+ * Probe for error in memory-mapped registers containing error records.
+ * Upon detecting an error, set probe data to the index of the record
+ * in error, and return 1; otherwise, return 0.
+ */
+int gic600_fmu_probe(uint64_t base, int *probe_data)
+{
+ uint64_t gsr;
+
+ assert(base != 0UL);
+
+ /*
+ * Read ERR_GSR to find the error record 'M'
+ */
+ gsr = gic_fmu_read_errgsr(base);
+ if (gsr == U(0)) {
+ return 0;
+ }
+
+ /* Return the index of the record in error */
+ if (probe_data != NULL) {
+ *probe_data = (int)__builtin_ctzll(gsr);
+ }
+
+ return 1;
+}
+
+/*
+ * The handler function to read RAS records and find the safety
+ * mechanism with the error.
+ */
+int gic600_fmu_ras_handler(uint64_t base, int probe_data)
+{
+ uint64_t errstatus;
+ unsigned int blkid = (unsigned int)probe_data, ierr, serr;
+
+ assert(base != 0UL);
+
+ /*
+ * FMU_ERRGSR indicates the ID of the GIC
+ * block that faulted.
+ */
+ assert(blkid <= FMU_BLK_PPI31);
+
+ /*
+ * Find more information by reading FMU_ERR<M>STATUS
+ * register
+ */
+ errstatus = gic_fmu_read_errstatus(base, blkid);
+
+ /*
+ * If FMU_ERR<M>STATUS.V is set to 0, no RAS records
+ * need to be scanned.
+ */
+ if ((errstatus & FMU_ERRSTATUS_V_BIT) == U(0)) {
+ return 0;
+ }
+
+ /*
+ * FMU_ERR<M>STATUS.IERR indicates which Safety Mechanism
+ * reported the error.
+ */
+ ierr = (errstatus >> FMU_ERRSTATUS_IERR_SHIFT) &
+ FMU_ERRSTATUS_IERR_MASK;
+
+ /*
+ * FMU_ERR<M>STATUS.SERR indicates architecturally
+ * defined primary error code.
+ */
+ serr = errstatus & FMU_ERRSTATUS_SERR_MASK;
+
+ ERROR("**************************************\n");
+ ERROR("RAS %s Error detected by GIC600 AE FMU\n",
+ ((errstatus & FMU_ERRSTATUS_UE_BIT) != 0U) ?
+ "Uncorrectable" : "Corrected");
+ ERROR("\tStatus = 0x%lx \n", errstatus);
+ ERROR("\tBlock ID = 0x%x\n", blkid);
+ ERROR("\tSafety Mechanism ID = 0x%x (%s)\n", ierr,
+ ras_ierr_to_str(blkid, ierr));
+ ERROR("\tArchitecturally defined primary error code = 0x%x\n",
+ serr);
+ ERROR("**************************************\n");
+
+ /* Clear FMU_ERR<M>STATUS */
+ gic_fmu_write_errstatus(base, probe_data, errstatus);
+
+ return 0;
+}
+
+/*
+ * Initialization sequence for the FMU
+ *
+ * 1. enable error detection for error records that are passed in the blk_present_mask
+ * 2. enable MBIST REQ and FMU Clk Gate override safety mechanisms for error records
+ * that are present on the platform
+ *
+ * The platforms are expected to pass `errctlr_ce_en` and `errctlr_ue_en`.
+ */
+void gic600_fmu_init(uint64_t base, uint64_t blk_present_mask,
+ bool errctlr_ce_en, bool errctlr_ue_en)
+{
+ unsigned int num_blk = gic_fmu_read_erridr(base) & FMU_ERRIDR_NUM_MASK;
+ uint64_t errctlr;
+ uint32_t smen;
+
+ INFO("GIC600-AE FMU supports %d error records\n", num_blk);
+
+ assert(num_blk == FMU_ERRIDR_NUM);
+
+ /* sanitize block present mask */
+ blk_present_mask &= FMU_BLK_PRESENT_MASK;
+
+ /* Enable error detection for all error records */
+ for (unsigned int i = 0U; i < num_blk; i++) {
+
+ /*
+ * Disable all safety mechanisms for blocks that are not
+ * present and skip the next steps.
+ */
+ if ((blk_present_mask & BIT(i)) == 0U) {
+ gic_fmu_disable_all_sm_blkid(base, i);
+ continue;
+ }
+
+ /* Read the error record control register */
+ errctlr = gic_fmu_read_errctlr(base, i);
+
+ /* Enable error reporting and logging, if it is disabled */
+ if ((errctlr & FMU_ERRCTLR_ED_BIT) == 0U) {
+ errctlr |= FMU_ERRCTLR_ED_BIT;
+ }
+
+ /* Enable client provided ERRCTLR settings */
+ errctlr |= (errctlr_ce_en ? (FMU_ERRCTLR_CI_BIT | FMU_ERRCTLR_CE_EN_BIT) : 0);
+ errctlr |= (errctlr_ue_en ? FMU_ERRCTLR_UI_BIT : 0U);
+
+ gic_fmu_write_errctlr(base, i, errctlr);
+ }
+
+ /*
+ * Enable MBIST REQ error and FMU CLK gate override safety mechanisms for
+ * all blocks
+ *
+ * GICD, SMID 23 and SMID 33
+ * PPI, SMID 10 and SMID 12
+ * ITS, SMID 13 and SMID 14
+ */
+ if ((blk_present_mask & BIT(FMU_BLK_GICD)) != 0U) {
+ smen = (GICD_MBIST_REQ_ERROR << FMU_SMEN_SMID_SHIFT) |
+ (FMU_BLK_GICD << FMU_SMEN_BLK_SHIFT) |
+ FMU_SMEN_EN_BIT;
+ gic_fmu_write_smen(base, smen);
+
+ smen = (GICD_FMU_CLKGATE_ERROR << FMU_SMEN_SMID_SHIFT) |
+ (FMU_BLK_GICD << FMU_SMEN_BLK_SHIFT) |
+ FMU_SMEN_EN_BIT;
+ gic_fmu_write_smen(base, smen);
+ }
+
+ for (unsigned int i = FMU_BLK_PPI0; i < FMU_BLK_PPI31; i++) {
+ if ((blk_present_mask & BIT(i)) != 0U) {
+ smen = (PPI_MBIST_REQ_ERROR << FMU_SMEN_SMID_SHIFT) |
+ (i << FMU_SMEN_BLK_SHIFT) |
+ FMU_SMEN_EN_BIT;
+ gic_fmu_write_smen(base, smen);
+
+ smen = (PPI_FMU_CLKGATE_ERROR << FMU_SMEN_SMID_SHIFT) |
+ (i << FMU_SMEN_BLK_SHIFT) |
+ FMU_SMEN_EN_BIT;
+ gic_fmu_write_smen(base, smen);
+ }
+ }
+
+ for (unsigned int i = FMU_BLK_ITS0; i < FMU_BLK_ITS7; i++) {
+ if ((blk_present_mask & BIT(i)) != 0U) {
+ smen = (ITS_MBIST_REQ_ERROR << FMU_SMEN_SMID_SHIFT) |
+ (i << FMU_SMEN_BLK_SHIFT) |
+ FMU_SMEN_EN_BIT;
+ gic_fmu_write_smen(base, smen);
+
+ smen = (ITS_FMU_CLKGATE_ERROR << FMU_SMEN_SMID_SHIFT) |
+ (i << FMU_SMEN_BLK_SHIFT) |
+ FMU_SMEN_EN_BIT;
+ gic_fmu_write_smen(base, smen);
+ }
+ }
+}
+
+/*
+ * This function enable the GICD background ping engine. The GICD sends ping
+ * messages to each remote GIC block, and expects a PING_ACK back within the
+ * specified timeout. Pings need to be enabled after programming the timeout
+ * value.
+ */
+void gic600_fmu_enable_ping(uint64_t base, uint64_t blk_present_mask,
+ unsigned int timeout_val, unsigned int interval_diff)
+{
+ /*
+ * Populate the PING Mask to skip a specific block while generating
+ * background ping messages and enable the ping mechanism.
+ */
+ gic_fmu_write_pingmask(base, ~blk_present_mask);
+ gic_fmu_write_pingctlr(base, (interval_diff << FMU_PINGCTLR_INTDIFF_SHIFT) |
+ (timeout_val << FMU_PINGCTLR_TIMEOUTVAL_SHIFT) | FMU_PINGCTLR_EN_BIT);
+}
+
+/* Print the safety mechanism description for a given block */
+void gic600_fmu_print_sm_info(uint64_t base, unsigned int blk, unsigned int smid)
+{
+ if (blk == FMU_BLK_GICD && smid <= FMU_SMID_GICD_MAX) {
+ INFO("GICD, SMID %d: %s\n", smid, gicd_sm_info[smid]);
+ }
+
+ if (blk == FMU_BLK_SPICOL && smid <= FMU_SMID_SPICOL_MAX) {
+ INFO("SPI Collator, SMID %d: %s\n", smid, spicol_sm_info[smid]);
+ }
+
+ if (blk == FMU_BLK_WAKERQ && (smid <= FMU_SMID_WAKERQ_MAX)) {
+ INFO("Wake Request, SMID %d: %s\n", smid, wkrqst_sm_info[smid]);
+ }
+
+ if (((blk >= FMU_BLK_ITS0) && (blk <= FMU_BLK_ITS7)) && (smid <= FMU_SMID_ITS_MAX)) {
+ INFO("ITS, SMID %d: %s\n", smid, its_sm_info[smid]);
+ }
+
+ if (((blk >= FMU_BLK_PPI0) && (blk <= FMU_BLK_PPI31)) && (smid <= FMU_SMID_PPI_MAX)) {
+ INFO("PPI, SMID %d: %s\n", smid, ppi_sm_info[smid]);
+ }
+}
diff --git a/drivers/arm/gic/v3/gic600ae_fmu_helpers.c b/drivers/arm/gic/v3/gic600ae_fmu_helpers.c
new file mode 100644
index 0000000..09806dc
--- /dev/null
+++ b/drivers/arm/gic/v3/gic600ae_fmu_helpers.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2021-2022, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <drivers/arm/gic600ae_fmu.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#define GICFMU_IDLE_TIMEOUT_US U(2000000)
+
+/* Macro to write 32-bit FMU registers */
+#define GIC_FMU_WRITE_32(base, reg, val) \
+ do { \
+ /* \
+ * This register receives the unlock key that is required for \
+ * writes to FMU registers to be successful. \
+ */ \
+ mmio_write_32(base + GICFMU_KEY, 0xBE); \
+ /* Perform the actual write */ \
+ mmio_write_32((base) + (reg), (val)); \
+ } while (false)
+
+/* Macro to write 64-bit FMU registers */
+#define GIC_FMU_WRITE_64(base, reg, n, val) \
+ do { \
+ /* \
+ * This register receives the unlock key that is required for \
+ * writes to FMU registers to be successful. \
+ */ \
+ mmio_write_32(base + GICFMU_KEY, 0xBE); \
+ /* \
+ * APB bus is 32-bit wide; so split the 64-bit write into \
+ * two 32-bit writes \
+ */ \
+ mmio_write_32((base) + reg##_LO + (n * 64), (val)); \
+ mmio_write_32((base) + reg##_HI + (n * 64), (val)); \
+ } while (false)
+
+/* Helper function to wait until FMU is ready to accept the next command */
+static void wait_until_fmu_is_idle(uintptr_t base)
+{
+ uint32_t timeout_count = GICFMU_IDLE_TIMEOUT_US;
+ uint64_t status;
+
+ /* wait until status is 'busy' */
+ do {
+ status = (gic_fmu_read_status(base) & BIT(0));
+
+ if (timeout_count-- == 0U) {
+ ERROR("GIC600 AE FMU is not responding\n");
+ panic();
+ }
+
+ udelay(1U);
+
+ } while (status == U(0));
+}
+
+#define GIC_FMU_WRITE_ON_IDLE_32(base, reg, val) \
+ do { \
+ /* Wait until FMU is ready */ \
+ wait_until_fmu_is_idle(base); \
+ /* Actual register write */ \
+ GIC_FMU_WRITE_32(base, reg, val); \
+ /* Wait until FMU is ready */ \
+ wait_until_fmu_is_idle(base); \
+ } while (false)
+
+#define GIC_FMU_WRITE_ON_IDLE_64(base, reg, n, val) \
+ do { \
+ /* Wait until FMU is ready */ \
+ wait_until_fmu_is_idle(base); \
+ /* Actual register write */ \
+ GIC_FMU_WRITE_64(base, reg, n, val); \
+ /* Wait until FMU is ready */ \
+ wait_until_fmu_is_idle(base); \
+ } while (false)
+
+/*******************************************************************************
+ * GIC FMU functions for accessing the Fault Management Unit registers
+ ******************************************************************************/
+
+/*
+ * Accessors to read the Error Record Feature Register bits corresponding
+ * to an error record 'n'
+ */
+uint64_t gic_fmu_read_errfr(uintptr_t base, unsigned int n)
+{
+ /*
+ * APB bus is 32-bit wide; so split the 64-bit read into
+ * two 32-bit reads
+ */
+ uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRFR_LO + n * 64U);
+
+ reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRFR_HI + n * 64U) << 32);
+ return reg_val;
+}
+
+/*
+ * Accessors to read the Error Record Control Register bits corresponding
+ * to an error record 'n'
+ */
+uint64_t gic_fmu_read_errctlr(uintptr_t base, unsigned int n)
+{
+ /*
+ * APB bus is 32-bit wide; so split the 64-bit read into
+ * two 32-bit reads
+ */
+ uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRCTLR_LO + n * 64U);
+
+ reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRCTLR_HI + n * 64U) << 32);
+ return reg_val;
+}
+
+/*
+ * Accessors to read the Error Record Primary Status Register bits
+ * corresponding to an error record 'n'
+ */
+uint64_t gic_fmu_read_errstatus(uintptr_t base, unsigned int n)
+{
+ /*
+ * APB bus is 32-bit wide; so split the 64-bit read into
+ * two 32-bit reads
+ */
+ uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRSTATUS_LO + n * 64U);
+
+ reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRSTATUS_HI + n * 64U) << 32);
+ return reg_val;
+}
+
+/*
+ * Accessors to read the Error Group Status Register
+ */
+uint64_t gic_fmu_read_errgsr(uintptr_t base)
+{
+ /*
+ * APB bus is 32-bit wide; so split the 64-bit read into
+ * two 32-bit reads
+ */
+ uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRGSR_LO);
+
+ reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRGSR_HI) << 32);
+ return reg_val;
+}
+
+/*
+ * Accessors to read the Ping Control Register
+ */
+uint32_t gic_fmu_read_pingctlr(uintptr_t base)
+{
+ return mmio_read_32(base + GICFMU_PINGCTLR);
+}
+
+/*
+ * Accessors to read the Ping Now Register
+ */
+uint32_t gic_fmu_read_pingnow(uintptr_t base)
+{
+ return mmio_read_32(base + GICFMU_PINGNOW);
+}
+
+/*
+ * Accessors to read the Ping Mask Register
+ */
+uint64_t gic_fmu_read_pingmask(uintptr_t base)
+{
+ /*
+ * APB bus is 32-bit wide; so split the 64-bit read into
+ * two 32-bit reads
+ */
+ uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_PINGMASK_LO);
+
+ reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_PINGMASK_HI) << 32);
+ return reg_val;
+}
+
+/*
+ * Accessors to read the FMU Status Register
+ */
+uint32_t gic_fmu_read_status(uintptr_t base)
+{
+ return mmio_read_32(base + GICFMU_STATUS);
+}
+
+/*
+ * Accessors to read the Error Record ID Register
+ */
+uint32_t gic_fmu_read_erridr(uintptr_t base)
+{
+ return mmio_read_32(base + GICFMU_ERRIDR);
+}
+
+/*
+ * Accessors to write a 64 bit value to the Error Record Control Register
+ */
+void gic_fmu_write_errctlr(uintptr_t base, unsigned int n, uint64_t val)
+{
+ GIC_FMU_WRITE_64(base, GICFMU_ERRCTLR, n, val);
+}
+
+/*
+ * Accessors to write a 64 bit value to the Error Record Primary Status
+ * Register
+ */
+void gic_fmu_write_errstatus(uintptr_t base, unsigned int n, uint64_t val)
+{
+ /* Wait until FMU is ready before writing */
+ GIC_FMU_WRITE_ON_IDLE_64(base, GICFMU_ERRSTATUS, n, val);
+}
+
+/*
+ * Accessors to write a 32 bit value to the Ping Control Register
+ */
+void gic_fmu_write_pingctlr(uintptr_t base, uint32_t val)
+{
+ GIC_FMU_WRITE_32(base, GICFMU_PINGCTLR, val);
+}
+
+/*
+ * Accessors to write a 32 bit value to the Ping Now Register
+ */
+void gic_fmu_write_pingnow(uintptr_t base, uint32_t val)
+{
+ /* Wait until FMU is ready before writing */
+ GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_PINGNOW, val);
+}
+
+/*
+ * Accessors to write a 32 bit value to the Safety Mechanism Enable Register
+ */
+void gic_fmu_write_smen(uintptr_t base, uint32_t val)
+{
+ /* Wait until FMU is ready before writing */
+ GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_SMEN, val);
+}
+
+/*
+ * Accessors to write a 32 bit value to the Safety Mechanism Inject Error
+ * Register
+ */
+void gic_fmu_write_sminjerr(uintptr_t base, uint32_t val)
+{
+ /* Wait until FMU is ready before writing */
+ GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_SMINJERR, val);
+}
+
+/*
+ * Accessors to write a 64 bit value to the Ping Mask Register
+ */
+void gic_fmu_write_pingmask(uintptr_t base, uint64_t val)
+{
+ GIC_FMU_WRITE_64(base, GICFMU_PINGMASK, 0, val);
+}
+
+/*
+ * Helper function to disable all safety mechanisms for a given block
+ */
+void gic_fmu_disable_all_sm_blkid(uintptr_t base, unsigned int blkid)
+{
+ uint32_t smen, max_smid = U(0);
+
+ /* Sanity check block ID */
+ assert((blkid >= FMU_BLK_GICD) && (blkid <= FMU_BLK_PPI31));
+
+ /* Find the max safety mechanism ID for the block */
+ switch (blkid) {
+ case FMU_BLK_GICD:
+ max_smid = FMU_SMID_GICD_MAX;
+ break;
+
+ case FMU_BLK_SPICOL:
+ max_smid = FMU_SMID_SPICOL_MAX;
+ break;
+
+ case FMU_BLK_WAKERQ:
+ max_smid = FMU_SMID_WAKERQ_MAX;
+ break;
+
+ case FMU_BLK_ITS0...FMU_BLK_ITS7:
+ max_smid = FMU_SMID_ITS_MAX;
+ break;
+
+ case FMU_BLK_PPI0...FMU_BLK_PPI31:
+ max_smid = FMU_SMID_PPI_MAX;
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ /* Disable all Safety Mechanisms for a given block id */
+ for (unsigned int i = 0U; i < max_smid; i++) {
+ smen = (blkid << FMU_SMEN_BLK_SHIFT) | (i << FMU_SMEN_SMID_SHIFT);
+ gic_fmu_write_smen(base, smen);
+ }
+}
diff --git a/drivers/arm/gic/v3/gicdv3_helpers.c b/drivers/arm/gic/v3/gicdv3_helpers.c
new file mode 100644
index 0000000..987be69
--- /dev/null
+++ b/drivers/arm/gic/v3/gicdv3_helpers.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include "gicv3_private.h"
+
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+
+/*
+ * Accessors to set the bits corresponding to interrupt ID
+ * in GIC Distributor ICFGR and ICFGRE.
+ */
+void gicd_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg)
+{
+ /* Interrupt configuration is a 2-bit field */
+ unsigned int bit_shift = BIT_NUM(ICFG, id) << 1U;
+
+ /* Clear the field, and insert required configuration */
+ mmio_clrsetbits_32(base + GICD_OFFSET(ICFG, id),
+ (uint32_t)GIC_CFG_MASK << bit_shift,
+ (cfg & GIC_CFG_MASK) << bit_shift);
+}
+
+/*
+ * Accessors to get/set/clear the bit corresponding to interrupt ID
+ * in GIC Distributor IGROUPR and IGROUPRE.
+ */
+unsigned int gicd_get_igroupr(uintptr_t base, unsigned int id)
+{
+ return GICD_GET_BIT(IGROUP, base, id);
+}
+
+void gicd_set_igroupr(uintptr_t base, unsigned int id)
+{
+ GICD_SET_BIT(IGROUP, base, id);
+}
+
+void gicd_clr_igroupr(uintptr_t base, unsigned int id)
+{
+ GICD_CLR_BIT(IGROUP, base, id);
+}
+
+/*
+ * Accessors to get/set/clear the bit corresponding to interrupt ID
+ * in GIC Distributor IGRPMODR and IGRPMODRE.
+ */
+unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id)
+{
+ return GICD_GET_BIT(IGRPMOD, base, id);
+}
+
+void gicd_set_igrpmodr(uintptr_t base, unsigned int id)
+{
+ GICD_SET_BIT(IGRPMOD, base, id);
+}
+
+void gicd_clr_igrpmodr(uintptr_t base, unsigned int id)
+{
+ GICD_CLR_BIT(IGRPMOD, base, id);
+}
+
+/*
+ * Accessors to set the bit corresponding to interrupt ID
+ * in GIC Distributor ICENABLER and ICENABLERE.
+ */
+void gicd_set_icenabler(uintptr_t base, unsigned int id)
+{
+ GICD_WRITE_BIT(ICENABLE, base, id);
+}
+
+/*
+ * Accessors to set the bit corresponding to interrupt ID
+ * in GIC Distributor ICPENDR and ICPENDRE.
+ */
+void gicd_set_icpendr(uintptr_t base, unsigned int id)
+{
+ GICD_WRITE_BIT(ICPEND, base, id);
+}
+
+/*
+ * Accessors to get/set the bit corresponding to interrupt ID
+ * in GIC Distributor ISACTIVER and ISACTIVERE.
+ */
+unsigned int gicd_get_isactiver(uintptr_t base, unsigned int id)
+{
+ return GICD_GET_BIT(ISACTIVE, base, id);
+}
+
+void gicd_set_isactiver(uintptr_t base, unsigned int id)
+{
+ GICD_WRITE_BIT(ISACTIVE, base, id);
+}
+
+/*
+ * Accessors to set the bit corresponding to interrupt ID
+ * in GIC Distributor ISENABLER and ISENABLERE.
+ */
+void gicd_set_isenabler(uintptr_t base, unsigned int id)
+{
+ GICD_WRITE_BIT(ISENABLE, base, id);
+}
+
+/*
+ * Accessors to set the bit corresponding to interrupt ID
+ * in GIC Distributor ISPENDR and ISPENDRE.
+ */
+void gicd_set_ispendr(uintptr_t base, unsigned int id)
+{
+ GICD_WRITE_BIT(ISPEND, base, id);
+}
+
+/*
+ * Accessors to set the bit corresponding to interrupt ID
+ * in GIC Distributor IPRIORITYR and IPRIORITYRE.
+ */
+void gicd_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri)
+{
+ GICD_WRITE_8(IPRIORITY, base, id, (uint8_t)(pri & GIC_PRI_MASK));
+}
+
+/*******************************************************************************
+ * GIC Distributor interface accessors for reading/writing entire registers
+ ******************************************************************************/
+
+/*
+ * Accessors to read/write the GIC Distributor ICGFR and ICGFRE
+ * corresponding to the interrupt ID, 16 interrupt IDs at a time.
+ */
+unsigned int gicd_read_icfgr(uintptr_t base, unsigned int id)
+{
+ return GICD_READ(ICFG, base, id);
+}
+
+void gicd_write_icfgr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ GICD_WRITE(ICFG, base, id, val);
+}
+
+/*
+ * Accessors to read/write the GIC Distributor IGROUPR and IGROUPRE
+ * corresponding to the interrupt ID, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_igroupr(uintptr_t base, unsigned int id)
+{
+ return GICD_READ(IGROUP, base, id);
+}
+
+void gicd_write_igroupr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ GICD_WRITE(IGROUP, base, id, val);
+}
+
+/*
+ * Accessors to read/write the GIC Distributor IGRPMODR and IGRPMODRE
+ * corresponding to the interrupt ID, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_igrpmodr(uintptr_t base, unsigned int id)
+{
+ return GICD_READ(IGRPMOD, base, id);
+}
+
+void gicd_write_igrpmodr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ GICD_WRITE(IGRPMOD, base, id, val);
+}
+
+/*
+ * Accessors to read/write the GIC Distributor IPRIORITYR and IPRIORITYRE
+ * corresponding to the interrupt ID, 4 interrupt IDs at a time.
+ */
+unsigned int gicd_read_ipriorityr(uintptr_t base, unsigned int id)
+{
+ return GICD_READ(IPRIORITY, base, id);
+}
+
+void gicd_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ GICD_WRITE(IPRIORITY, base, id, val);
+}
+
+/*
+ * Accessors to read/write the GIC Distributor ISACTIVER and ISACTIVERE
+ * corresponding to the interrupt ID, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_isactiver(uintptr_t base, unsigned int id)
+{
+ return GICD_READ(ISACTIVE, base, id);
+}
+
+void gicd_write_isactiver(uintptr_t base, unsigned int id, unsigned int val)
+{
+ GICD_WRITE(ISACTIVE, base, id, val);
+}
+
+/*
+ * Accessors to read/write the GIC Distributor ISENABLER and ISENABLERE
+ * corresponding to the interrupt ID, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id)
+{
+ return GICD_READ(ISENABLE, base, id);
+}
+
+void gicd_write_isenabler(uintptr_t base, unsigned int id, unsigned int val)
+{
+ GICD_WRITE(ISENABLE, base, id, val);
+}
+
+/*
+ * Accessors to read/write the GIC Distributor ISPENDR and ISPENDRE
+ * corresponding to the interrupt ID, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_ispendr(uintptr_t base, unsigned int id)
+{
+ return GICD_READ(ISPEND, base, id);
+}
+
+void gicd_write_ispendr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ GICD_WRITE(ISPEND, base, id, val);
+}
+
+/*
+ * Accessors to read/write the GIC Distributor NSACR and NSACRE
+ * corresponding to the interrupt ID, 16 interrupt IDs at a time.
+ */
+unsigned int gicd_read_nsacr(uintptr_t base, unsigned int id)
+{
+ return GICD_READ(NSAC, base, id);
+}
+
+void gicd_write_nsacr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ GICD_WRITE(NSAC, base, id, val);
+}
diff --git a/drivers/arm/gic/v3/gicrv3_helpers.c b/drivers/arm/gic/v3/gicrv3_helpers.c
new file mode 100644
index 0000000..3004054
--- /dev/null
+++ b/drivers/arm/gic/v3/gicrv3_helpers.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include "gicv3_private.h"
+
+/*******************************************************************************
+ * GIC Redistributor functions
+ * Note: The raw register values correspond to multiple interrupt `id`s and
+ * the number of interrupt `id`s involved depends on the register accessed.
+ ******************************************************************************/
+
+/*
+ * Accessors to read/write the GIC Redistributor IPRIORITYR and IPRIORITYRE
+ * register corresponding to the interrupt `id`, 4 interrupts IDs at a time.
+ */
+unsigned int gicr_read_ipriorityr(uintptr_t base, unsigned int id)
+{
+ return GICR_READ(IPRIORITY, base, id);
+}
+
+void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ GICR_WRITE(IPRIORITY, base, id, val);
+}
+
+/*
+ * Accessor to set the byte corresponding to interrupt `id`
+ * in GIC Redistributor IPRIORITYR and IPRIORITYRE.
+ */
+void gicr_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri)
+{
+ GICR_WRITE_8(IPRIORITY, base, id, (uint8_t)(pri & GIC_PRI_MASK));
+}
+
+/*
+ * Accessors to get/set/clear the bit corresponding to interrupt `id`
+ * from GIC Redistributor IGROUPR0 and IGROUPRE
+ */
+unsigned int gicr_get_igroupr(uintptr_t base, unsigned int id)
+{
+ return GICR_GET_BIT(IGROUP, base, id);
+}
+
+void gicr_set_igroupr(uintptr_t base, unsigned int id)
+{
+ GICR_SET_BIT(IGROUP, base, id);
+}
+
+void gicr_clr_igroupr(uintptr_t base, unsigned int id)
+{
+ GICR_CLR_BIT(IGROUP, base, id);
+}
+
+/*
+ * Accessors to get/set/clear the bit corresponding to interrupt `id`
+ * from GIC Redistributor IGRPMODR0 and IGRPMODRE
+ */
+unsigned int gicr_get_igrpmodr(uintptr_t base, unsigned int id)
+{
+ return GICR_GET_BIT(IGRPMOD, base, id);
+}
+
+void gicr_set_igrpmodr(uintptr_t base, unsigned int id)
+{
+ GICR_SET_BIT(IGRPMOD, base, id);
+}
+
+void gicr_clr_igrpmodr(uintptr_t base, unsigned int id)
+{
+ GICR_CLR_BIT(IGRPMOD, base, id);
+}
+
+/*
+ * Accessor to write the bit corresponding to interrupt `id`
+ * in GIC Redistributor ISENABLER0 and ISENABLERE
+ */
+void gicr_set_isenabler(uintptr_t base, unsigned int id)
+{
+ GICR_WRITE_BIT(ISENABLE, base, id);
+}
+
+/*
+ * Accessor to write the bit corresponding to interrupt `id`
+ * in GIC Redistributor ICENABLER0 and ICENABLERE
+ */
+void gicr_set_icenabler(uintptr_t base, unsigned int id)
+{
+ GICR_WRITE_BIT(ICENABLE, base, id);
+}
+
+/*
+ * Accessor to get the bit corresponding to interrupt `id`
+ * in GIC Redistributor ISACTIVER0 and ISACTIVERE
+ */
+unsigned int gicr_get_isactiver(uintptr_t base, unsigned int id)
+{
+ return GICR_GET_BIT(ISACTIVE, base, id);
+}
+
+/*
+ * Accessor to clear the bit corresponding to interrupt `id`
+ * in GIC Redistributor ICPENDR0 and ICPENDRE
+ */
+void gicr_set_icpendr(uintptr_t base, unsigned int id)
+{
+ GICR_WRITE_BIT(ICPEND, base, id);
+}
+
+/*
+ * Accessor to write the bit corresponding to interrupt `id`
+ * in GIC Redistributor ISPENDR0 and ISPENDRE
+ */
+void gicr_set_ispendr(uintptr_t base, unsigned int id)
+{
+ GICR_WRITE_BIT(ISPEND, base, id);
+}
+
+/*
+ * Accessor to set the bit fields corresponding to interrupt `id`
+ * in GIC Redistributor ICFGR0, ICFGR1 and ICFGRE
+ */
+void gicr_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg)
+{
+ /* Interrupt configuration is a 2-bit field */
+ unsigned int bit_shift = BIT_NUM(ICFG, id) << 1U;
+
+ /* Clear the field, and insert required configuration */
+ mmio_clrsetbits_32(base + GICR_OFFSET(ICFG, id),
+ (uint32_t)GIC_CFG_MASK << bit_shift,
+ (cfg & GIC_CFG_MASK) << bit_shift);
+}
diff --git a/drivers/arm/gic/v3/gicv3.mk b/drivers/arm/gic/v3/gicv3.mk
new file mode 100644
index 0000000..1d20ff3
--- /dev/null
+++ b/drivers/arm/gic/v3/gicv3.mk
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021, NVIDIA Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Default configuration values
+GICV3_SUPPORT_GIC600 ?= 0
+GICV3_SUPPORT_GIC600AE_FMU ?= 0
+GICV3_IMPL_GIC600_MULTICHIP ?= 0
+GICV3_OVERRIDE_DISTIF_PWR_OPS ?= 0
+GIC_ENABLE_V4_EXTN ?= 0
+GIC_EXT_INTID ?= 0
+GIC600_ERRATA_WA_2384374 ?= ${GICV3_SUPPORT_GIC600}
+
+GICV3_SOURCES += drivers/arm/gic/v3/gicv3_main.c \
+ drivers/arm/gic/v3/gicv3_helpers.c \
+ drivers/arm/gic/v3/gicdv3_helpers.c \
+ drivers/arm/gic/v3/gicrv3_helpers.c
+
+ifeq (${GICV3_SUPPORT_GIC600AE_FMU}, 1)
+GICV3_SOURCES += drivers/arm/gic/v3/gic600ae_fmu.c \
+ drivers/arm/gic/v3/gic600ae_fmu_helpers.c
+endif
+
+ifeq (${GICV3_OVERRIDE_DISTIF_PWR_OPS}, 0)
+GICV3_SOURCES += drivers/arm/gic/v3/arm_gicv3_common.c
+endif
+
+GICV3_SOURCES += drivers/arm/gic/v3/gic-x00.c
+ifeq (${GICV3_IMPL_GIC600_MULTICHIP}, 1)
+GICV3_SOURCES += drivers/arm/gic/v3/gic600_multichip.c
+endif
+
+# Set GIC-600 support
+$(eval $(call assert_boolean,GICV3_SUPPORT_GIC600))
+$(eval $(call add_define,GICV3_SUPPORT_GIC600))
+
+# Set GIC-600AE FMU support
+$(eval $(call assert_boolean,GICV3_SUPPORT_GIC600AE_FMU))
+$(eval $(call add_define,GICV3_SUPPORT_GIC600AE_FMU))
+
+# Set GICv4 extension
+$(eval $(call assert_boolean,GIC_ENABLE_V4_EXTN))
+$(eval $(call add_define,GIC_ENABLE_V4_EXTN))
+
+# Set support for extended PPI and SPI range
+$(eval $(call assert_boolean,GIC_EXT_INTID))
+$(eval $(call add_define,GIC_EXT_INTID))
+
+# Set errata workaround for GIC600/GIC600AE
+$(eval $(call assert_boolean,GIC600_ERRATA_WA_2384374))
+$(eval $(call add_define,GIC600_ERRATA_WA_2384374))
diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c
new file mode 100644
index 0000000..446d0ad
--- /dev/null
+++ b/drivers/arm/gic/v3/gicv3_helpers.c
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gic_common.h>
+
+#include <platform_def.h>
+
+#include "../common/gic_common_private.h"
+#include "gicv3_private.h"
+
+/******************************************************************************
+ * 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 += gicv3_redist_size(typer_val);
+ } while ((typer_val & TYPER_LAST_BIT) == 0U);
+}
+
+/*******************************************************************************
+ * Helper function to get the maximum SPI INTID + 1.
+ ******************************************************************************/
+unsigned int gicv3_get_spi_limit(uintptr_t gicd_base)
+{
+ unsigned int spi_limit;
+ unsigned int typer_reg = gicd_read_typer(gicd_base);
+
+ /* (maximum SPI INTID + 1) is equal to 32 * (GICD_TYPER.ITLinesNumber+1) */
+ spi_limit = ((typer_reg & TYPER_IT_LINES_NO_MASK) + 1U) << 5;
+
+ /* Filter out special INTIDs 1020-1023 */
+ if (spi_limit > (MAX_SPI_ID + 1U)) {
+ return MAX_SPI_ID + 1U;
+ }
+
+ return spi_limit;
+}
+
+#if GIC_EXT_INTID
+/*******************************************************************************
+ * Helper function to get the maximum ESPI INTID + 1.
+ ******************************************************************************/
+unsigned int gicv3_get_espi_limit(uintptr_t gicd_base)
+{
+ unsigned int typer_reg = gicd_read_typer(gicd_base);
+
+ /* Check if extended SPI range is implemented */
+ if ((typer_reg & TYPER_ESPI) != 0U) {
+ /*
+ * (maximum ESPI INTID + 1) is equal to
+ * 32 * (GICD_TYPER.ESPI_range + 1) + 4096
+ */
+ return ((((typer_reg >> TYPER_ESPI_RANGE_SHIFT) &
+ TYPER_ESPI_RANGE_MASK) + 1U) << 5) + MIN_ESPI_ID;
+ }
+
+ return 0U;
+}
+#endif /* GIC_EXT_INTID */
+
+/*******************************************************************************
+ * Helper function to configure the default attributes of (E)SPIs.
+ ******************************************************************************/
+void gicv3_spis_config_defaults(uintptr_t gicd_base)
+{
+ unsigned int i, num_ints;
+#if GIC_EXT_INTID
+ unsigned int num_eints;
+#endif
+
+ num_ints = gicv3_get_spi_limit(gicd_base);
+ INFO("Maximum SPI INTID supported: %u\n", num_ints - 1);
+
+ /* Treat all (E)SPIs as G1NS by default. We do 32 at a time. */
+ for (i = MIN_SPI_ID; i < num_ints; i += (1U << IGROUPR_SHIFT)) {
+ gicd_write_igroupr(gicd_base, i, ~0U);
+ }
+
+#if GIC_EXT_INTID
+ num_eints = gicv3_get_espi_limit(gicd_base);
+ if (num_eints != 0U) {
+ INFO("Maximum ESPI INTID supported: %u\n", num_eints - 1);
+
+ for (i = MIN_ESPI_ID; i < num_eints;
+ i += (1U << IGROUPR_SHIFT)) {
+ gicd_write_igroupr(gicd_base, i, ~0U);
+ }
+ } else {
+ INFO("ESPI range is not implemented.\n");
+ }
+#endif
+
+ /* Setup the default (E)SPI priorities doing four at a time */
+ for (i = MIN_SPI_ID; i < num_ints; i += (1U << IPRIORITYR_SHIFT)) {
+ gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL);
+ }
+
+#if GIC_EXT_INTID
+ for (i = MIN_ESPI_ID; i < num_eints;
+ i += (1U << IPRIORITYR_SHIFT)) {
+ gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL);
+ }
+#endif
+ /*
+ * Treat all (E)SPIs as level triggered by default, write 16 at a time
+ */
+ for (i = MIN_SPI_ID; i < num_ints; i += (1U << ICFGR_SHIFT)) {
+ gicd_write_icfgr(gicd_base, i, 0U);
+ }
+
+#if GIC_EXT_INTID
+ for (i = MIN_ESPI_ID; i < num_eints; i += (1U << ICFGR_SHIFT)) {
+ gicd_write_icfgr(gicd_base, i, 0U);
+ }
+#endif
+}
+
+/*******************************************************************************
+ * Helper function to configure properties of secure (E)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];
+
+ unsigned int intr_num = current_prop->intr_num;
+
+ /* Skip SGI, (E)PPI and LPI interrupts */
+ if (!IS_SPI(intr_num)) {
+ continue;
+ }
+
+ /* Configure this interrupt as a secure interrupt */
+ gicd_clr_igroupr(gicd_base, 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, intr_num);
+ ctlr_enable |= CTLR_ENABLE_G1S_BIT;
+ } else {
+ gicd_clr_igrpmodr(gicd_base, intr_num);
+ ctlr_enable |= CTLR_ENABLE_G0_BIT;
+ }
+
+ /* Set interrupt configuration */
+ gicd_set_icfgr(gicd_base, intr_num, current_prop->intr_cfg);
+
+ /* Set the priority of this interrupt */
+ gicd_set_ipriorityr(gicd_base, intr_num,
+ current_prop->intr_pri);
+
+ /* Target (E)SPIs to the primary CPU */
+ gic_affinity_val =
+ gicd_irouter_val_from_mpidr(read_mpidr(), 0U);
+ gicd_write_irouter(gicd_base, intr_num,
+ gic_affinity_val);
+
+ /* Enable this interrupt */
+ gicd_set_isenabler(gicd_base, intr_num);
+ }
+
+ return ctlr_enable;
+}
+
+/*******************************************************************************
+ * Helper function to configure the default attributes of (E)SPIs
+ ******************************************************************************/
+void gicv3_ppi_sgi_config_defaults(uintptr_t gicr_base)
+{
+ unsigned int i, ppi_regs_num, regs_num;
+
+#if GIC_EXT_INTID
+ /* Calculate number of PPI registers */
+ ppi_regs_num = (unsigned int)((gicr_read_typer(gicr_base) >>
+ TYPER_PPI_NUM_SHIFT) & TYPER_PPI_NUM_MASK) + 1;
+ /* All other values except PPInum [0-2] are reserved */
+ if (ppi_regs_num > 3U) {
+ ppi_regs_num = 1U;
+ }
+#else
+ ppi_regs_num = 1U;
+#endif
+ /*
+ * Disable all SGIs (imp. def.)/(E)PPIs before configuring them.
+ * This is a more scalable approach as it avoids clearing
+ * the enable bits in the GICD_CTLR.
+ */
+ for (i = 0U; i < ppi_regs_num; ++i) {
+ gicr_write_icenabler(gicr_base, i, ~0U);
+ }
+
+ /* Wait for pending writes to GICR_ICENABLER */
+ gicr_wait_for_pending_write(gicr_base);
+
+ /* 32 interrupt IDs per GICR_IGROUPR register */
+ for (i = 0U; i < ppi_regs_num; ++i) {
+ /* Treat all SGIs/(E)PPIs as G1NS by default */
+ gicr_write_igroupr(gicr_base, i, ~0U);
+ }
+
+ /* 4 interrupt IDs per GICR_IPRIORITYR register */
+ regs_num = ppi_regs_num << 3;
+ for (i = 0U; i < regs_num; ++i) {
+ /* Setup the default (E)PPI/SGI priorities doing 4 at a time */
+ gicr_write_ipriorityr(gicr_base, i, GICD_IPRIORITYR_DEF_VAL);
+ }
+
+ /* 16 interrupt IDs per GICR_ICFGR register */
+ regs_num = ppi_regs_num << 1;
+ for (i = (MIN_PPI_ID >> ICFGR_SHIFT); i < regs_num; ++i) {
+ /* Configure all (E)PPIs as level triggered by default */
+ gicr_write_icfgr(gicr_base, i, 0U);
+ }
+}
+
+/*******************************************************************************
+ * Helper function to configure properties of secure G0 and G1S (E)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];
+
+ unsigned int intr_num = current_prop->intr_num;
+
+ /* Skip (E)SPI interrupt */
+ if (!IS_SGI_PPI(intr_num)) {
+ continue;
+ }
+
+ /* Configure this interrupt as a secure interrupt */
+ gicr_clr_igroupr(gicr_base, 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_igrpmodr(gicr_base, intr_num);
+ ctlr_enable |= CTLR_ENABLE_G1S_BIT;
+ } else {
+ gicr_clr_igrpmodr(gicr_base, intr_num);
+ ctlr_enable |= CTLR_ENABLE_G0_BIT;
+ }
+
+ /* Set the priority of this interrupt */
+ gicr_set_ipriorityr(gicr_base, intr_num,
+ current_prop->intr_pri);
+
+ /*
+ * Set interrupt configuration for (E)PPIs.
+ * Configurations for SGIs 0-15 are ignored.
+ */
+ if (intr_num >= MIN_PPI_ID) {
+ gicr_set_icfgr(gicr_base, intr_num,
+ current_prop->intr_cfg);
+ }
+
+ /* Enable this interrupt */
+ gicr_set_isenabler(gicr_base, intr_num);
+ }
+
+ return ctlr_enable;
+}
+
+/**
+ * gicv3_rdistif_get_number_frames() - determine size of GICv3 GICR region
+ * @gicr_frame: base address of the GICR region to check
+ *
+ * This iterates over the GICR_TYPER registers of multiple GICR frames in
+ * a GICR region, to find the instance which has the LAST bit set. For most
+ * systems this corresponds to the number of cores handled by a redistributor,
+ * but there could be disabled cores among them.
+ * It assumes that each GICR region is fully accessible (till the LAST bit
+ * marks the end of the region).
+ * If a platform has multiple GICR regions, this function would need to be
+ * called multiple times, providing the respective GICR base address each time.
+ *
+ * Return: number of valid GICR frames (at least 1, up to PLATFORM_CORE_COUNT)
+ ******************************************************************************/
+unsigned int gicv3_rdistif_get_number_frames(const uintptr_t gicr_frame)
+{
+ uintptr_t rdistif_base = gicr_frame;
+ unsigned int count;
+
+ for (count = 1U; count < PLATFORM_CORE_COUNT; count++) {
+ uint64_t typer_val = gicr_read_typer(rdistif_base);
+
+ if ((typer_val & TYPER_LAST_BIT) != 0U) {
+ break;
+ }
+ rdistif_base += gicv3_redist_size(typer_val);
+ }
+
+ return count;
+}
+
+unsigned int gicv3_get_component_partnum(const uintptr_t gic_frame)
+{
+ unsigned int part_id;
+
+ /*
+ * The lower 8 bits of PIDR0, complemented by the lower 4 bits of
+ * PIDR1 contain a part number identifying the GIC component at a
+ * particular base address.
+ */
+ part_id = mmio_read_32(gic_frame + GICD_PIDR0_GICV3) & 0xff;
+ part_id |= (mmio_read_32(gic_frame + GICD_PIDR1_GICV3) << 8) & 0xf00;
+
+ return part_id;
+}
+
+/*******************************************************************************
+ * Helper function to return product ID and revision of GIC
+ * @gicd_base: base address of the GIC distributor
+ * @gic_prod_id: retrieved product id of GIC
+ * @gic_rev: retrieved revision of GIC
+ ******************************************************************************/
+void gicv3_get_component_prodid_rev(const uintptr_t gicd_base,
+ unsigned int *gic_prod_id,
+ uint8_t *gic_rev)
+{
+ unsigned int gicd_iidr;
+ uint8_t gic_variant;
+
+ gicd_iidr = gicd_read_iidr(gicd_base);
+ *gic_prod_id = gicd_iidr >> IIDR_PRODUCT_ID_SHIFT;
+ *gic_prod_id &= IIDR_PRODUCT_ID_MASK;
+
+ gic_variant = gicd_iidr >> IIDR_VARIANT_SHIFT;
+ gic_variant &= IIDR_VARIANT_MASK;
+
+ *gic_rev = gicd_iidr >> IIDR_REV_SHIFT;
+ *gic_rev &= IIDR_REV_MASK;
+
+ /*
+ * pack gic variant and gic_rev in 1 byte
+ * gic_rev = gic_variant[7:4] and gic_rev[0:3]
+ */
+ *gic_rev = *gic_rev | gic_variant << 0x4;
+
+}
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
new file mode 100644
index 0000000..bc93f93
--- /dev/null
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -0,0 +1,1361 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/spinlock.h>
+
+#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
+
+/* Check interrupt ID for SGI/(E)PPI and (E)SPIs */
+static bool is_sgi_ppi(unsigned int id);
+
+/*
+ * Helper macros to save and restore GICR and GICD registers
+ * corresponding to their numbers to and from the context
+ */
+#define RESTORE_GICR_REG(base, ctx, name, i) \
+ gicr_write_##name((base), (i), (ctx)->gicr_##name[(i)])
+
+#define SAVE_GICR_REG(base, ctx, name, i) \
+ (ctx)->gicr_##name[(i)] = gicr_read_##name((base), (i))
+
+/* 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##R_SHIFT)) { \
+ gicd_write_##reg((base), int_id, \
+ (ctx)->gicd_##reg[(int_id - MIN_SPI_ID) >> \
+ REG##R_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##R_SHIFT)) { \
+ (ctx)->gicd_##reg[(int_id - MIN_SPI_ID) >> \
+ REG##R_SHIFT] = gicd_read_##reg((base), int_id); \
+ } \
+ } while (false)
+
+#if GIC_EXT_INTID
+#define RESTORE_GICD_EREGS(base, ctx, intr_num, reg, REG) \
+ do { \
+ for (unsigned int int_id = MIN_ESPI_ID; int_id < (intr_num);\
+ int_id += (1U << REG##R_SHIFT)) { \
+ gicd_write_##reg((base), int_id, \
+ (ctx)->gicd_##reg[(int_id - (MIN_ESPI_ID - \
+ round_up(TOTAL_SPI_INTR_NUM, 1U << REG##R_SHIFT)))\
+ >> REG##R_SHIFT]); \
+ } \
+ } while (false)
+
+#define SAVE_GICD_EREGS(base, ctx, intr_num, reg, REG) \
+ do { \
+ for (unsigned int int_id = MIN_ESPI_ID; int_id < (intr_num);\
+ int_id += (1U << REG##R_SHIFT)) { \
+ (ctx)->gicd_##reg[(int_id - (MIN_ESPI_ID - \
+ round_up(TOTAL_SPI_INTR_NUM, 1U << REG##R_SHIFT)))\
+ >> REG##R_SHIFT] = gicd_read_##reg((base), int_id);\
+ } \
+ } while (false)
+#else
+#define SAVE_GICD_EREGS(base, ctx, intr_num, reg, REG)
+#define RESTORE_GICD_EREGS(base, ctx, intr_num, reg, REG)
+#endif /* GIC_EXT_INTID */
+
+/*******************************************************************************
+ * 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__ */
+
+ gic_version = gicd_read_pidr2(plat_driver_data->gicd_base);
+ gic_version >>= PIDR2_ARCH_REV_SHIFT;
+ gic_version &= PIDR2_ARCH_REV_MASK;
+
+ /* Check GIC version */
+#if !GIC_ENABLE_V4_EXTN
+ assert(gic_version == ARCH_REV_GICV3);
+#endif
+ /*
+ * 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
+ gicv3_check_erratas_applies(plat_driver_data->gicd_base);
+
+ INFO("GICv%u with%s legacy support detected.\n", gic_version,
+ (gicv2_compat == 0U) ? "" : "out");
+ INFO("ARM GICv%u driver initialized in EL3\n", gic_version);
+}
+
+/*******************************************************************************
+ * 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;
+
+ 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 (E)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 (E)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;
+ 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 (E)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)
+{
+}
+
+void gicv3_rdistif_on(unsigned int proc_num)
+{
+}
+
+/*******************************************************************************
+ * 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;
+ u_register_t 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 = 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();
+ /* Add DSB to ensure visibility of System register writes */
+ dsb();
+}
+
+/*******************************************************************************
+ * 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();
+ /* Add DSB to ensure visibility of System register writes */
+ dsb();
+
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+ assert(gicr_base != 0UL);
+
+ /*
+ * dsb() already issued previously after clearing the CPU group
+ * enabled, apply below workaround to toggle the "DPG*"
+ * bits of GICR_CTLR register for unblocking event.
+ */
+ gicv3_apply_errata_wa_2384374(gicr_base);
+
+ /* Mark the connected core as asleep */
+ 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;
+ }
+
+ /* Check interrupt ID */
+ if (is_sgi_ppi(id)) {
+ /* SGIs: 0-15, PPIs: 16-31, EPPIs: 1056-1119 */
+ assert(gicv3_driver_data->rdistif_base_addrs != NULL);
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+ igroup = gicr_get_igroupr(gicr_base, id);
+ grpmodr = gicr_get_igrpmodr(gicr_base, id);
+ } else {
+ /* SPIs: 32-1019, ESPIs: 4096-5119 */
+ 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 = 0U; 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 = 0U; 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 i, ppi_regs_num, regs_num;
+
+ 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];
+
+#if GIC_EXT_INTID
+ /* Calculate number of PPI registers */
+ ppi_regs_num = (unsigned int)((gicr_read_typer(gicr_base) >>
+ TYPER_PPI_NUM_SHIFT) & TYPER_PPI_NUM_MASK) + 1;
+ /* All other values except PPInum [0-2] are reserved */
+ if (ppi_regs_num > 3U) {
+ ppi_regs_num = 1U;
+ }
+#else
+ ppi_regs_num = 1U;
+#endif
+ /*
+ * 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);
+
+ /* 32 interrupt IDs per register */
+ for (i = 0U; i < ppi_regs_num; ++i) {
+ SAVE_GICR_REG(gicr_base, rdist_ctx, igroupr, i);
+ SAVE_GICR_REG(gicr_base, rdist_ctx, isenabler, i);
+ SAVE_GICR_REG(gicr_base, rdist_ctx, ispendr, i);
+ SAVE_GICR_REG(gicr_base, rdist_ctx, isactiver, i);
+ SAVE_GICR_REG(gicr_base, rdist_ctx, igrpmodr, i);
+ }
+
+ /* 16 interrupt IDs per GICR_ICFGR register */
+ regs_num = ppi_regs_num << 1;
+ for (i = 0U; i < regs_num; ++i) {
+ SAVE_GICR_REG(gicr_base, rdist_ctx, icfgr, i);
+ }
+
+ rdist_ctx->gicr_nsacr = gicr_read_nsacr(gicr_base);
+
+ /* 4 interrupt IDs per GICR_IPRIORITYR register */
+ regs_num = ppi_regs_num << 3;
+ for (i = 0U; i < regs_num; ++i) {
+ rdist_ctx->gicr_ipriorityr[i] =
+ gicr_ipriorityr_read(gicr_base, i);
+ }
+
+ /*
+ * 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 i, ppi_regs_num, regs_num;
+
+ 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];
+
+#if GIC_EXT_INTID
+ /* Calculate number of PPI registers */
+ ppi_regs_num = (unsigned int)((gicr_read_typer(gicr_base) >>
+ TYPER_PPI_NUM_SHIFT) & TYPER_PPI_NUM_MASK) + 1;
+ /* All other values except PPInum [0-2] are reserved */
+ if (ppi_regs_num > 3U) {
+ ppi_regs_num = 1U;
+ }
+#else
+ ppi_regs_num = 1U;
+#endif
+ /* 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.)/(E)PPIs before configuring them.
+ * This is a more scalable approach as it avoids clearing the enable
+ * bits in the GICD_CTLR.
+ */
+ for (i = 0U; i < ppi_regs_num; ++i) {
+ gicr_write_icenabler(gicr_base, i, ~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);
+
+ /* 32 interrupt IDs per register */
+ for (i = 0U; i < ppi_regs_num; ++i) {
+ RESTORE_GICR_REG(gicr_base, rdist_ctx, igroupr, i);
+ RESTORE_GICR_REG(gicr_base, rdist_ctx, igrpmodr, i);
+ }
+
+ /* 4 interrupt IDs per GICR_IPRIORITYR register */
+ regs_num = ppi_regs_num << 3;
+ for (i = 0U; i < regs_num; ++i) {
+ gicr_ipriorityr_write(gicr_base, i,
+ rdist_ctx->gicr_ipriorityr[i]);
+ }
+
+ /* 16 interrupt IDs per GICR_ICFGR register */
+ regs_num = ppi_regs_num << 1;
+ for (i = 0U; i < regs_num; ++i) {
+ RESTORE_GICR_REG(gicr_base, rdist_ctx, icfgr, i);
+ }
+
+ gicr_write_nsacr(gicr_base, rdist_ctx->gicr_nsacr);
+
+ /* Restore after group and priorities are set.
+ * 32 interrupt IDs per register
+ */
+ for (i = 0U; i < ppi_regs_num; ++i) {
+ RESTORE_GICR_REG(gicr_base, rdist_ctx, ispendr, i);
+ RESTORE_GICR_REG(gicr_base, rdist_ctx, isactiver, i);
+ }
+
+ /*
+ * Wait for all writes to the Distributor to complete before enabling
+ * the SGI and (E)PPIs.
+ */
+ gicr_wait_for_upstream_pending_write(gicr_base);
+
+ /* 32 interrupt IDs per GICR_ISENABLER register */
+ for (i = 0U; i < ppi_regs_num; ++i) {
+ RESTORE_GICR_REG(gicr_base, rdist_ctx, isenabler, i);
+ }
+
+ /*
+ * 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)
+{
+ 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;
+ unsigned int num_ints = gicv3_get_spi_limit(gicd_base);
+#if GIC_EXT_INTID
+ unsigned int num_eints = gicv3_get_espi_limit(gicd_base);
+#endif
+
+ /* 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, IGROUP);
+
+ /* Save GICD_IGROUPRE for INTIDs 4096 - 5119 */
+ SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, igroupr, IGROUP);
+
+ /* Save GICD_ISENABLER for INT_IDs 32 - 1019 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLE);
+
+ /* Save GICD_ISENABLERE for INT_IDs 4096 - 5119 */
+ SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, isenabler, ISENABLE);
+
+ /* Save GICD_ISPENDR for INTIDs 32 - 1019 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPEND);
+
+ /* Save GICD_ISPENDRE for INTIDs 4096 - 5119 */
+ SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, ispendr, ISPEND);
+
+ /* Save GICD_ISACTIVER for INTIDs 32 - 1019 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVE);
+
+ /* Save GICD_ISACTIVERE for INTIDs 4096 - 5119 */
+ SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, isactiver, ISACTIVE);
+
+ /* Save GICD_IPRIORITYR for INTIDs 32 - 1019 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITY);
+
+ /* Save GICD_IPRIORITYRE for INTIDs 4096 - 5119 */
+ SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, ipriorityr, IPRIORITY);
+
+ /* Save GICD_ICFGR for INTIDs 32 - 1019 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFG);
+
+ /* Save GICD_ICFGRE for INTIDs 4096 - 5119 */
+ SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, icfgr, ICFG);
+
+ /* Save GICD_IGRPMODR for INTIDs 32 - 1019 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMOD);
+
+ /* Save GICD_IGRPMODRE for INTIDs 4096 - 5119 */
+ SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, igrpmodr, IGRPMOD);
+
+ /* Save GICD_NSACR for INTIDs 32 - 1019 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSAC);
+
+ /* Save GICD_NSACRE for INTIDs 4096 - 5119 */
+ SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, nsacr, NSAC);
+
+ /* Save GICD_IROUTER for INTIDs 32 - 1019 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTE);
+
+ /* Save GICD_IROUTERE for INTIDs 4096 - 5119 */
+ SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, irouter, IROUTE);
+
+ /*
+ * GICD_ITARGETSR<n> and GICD_SPENDSGIR<n> 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)
+{
+ 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);
+
+ unsigned int num_ints = gicv3_get_spi_limit(gicd_base);
+#if GIC_EXT_INTID
+ unsigned int num_eints = gicv3_get_espi_limit(gicd_base);
+#endif
+ /* Restore GICD_IGROUPR for INTIDs 32 - 1019 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUP);
+
+ /* Restore GICD_IGROUPRE for INTIDs 4096 - 5119 */
+ RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, igroupr, IGROUP);
+
+ /* Restore GICD_IPRIORITYR for INTIDs 32 - 1019 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITY);
+
+ /* Restore GICD_IPRIORITYRE for INTIDs 4096 - 5119 */
+ RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, ipriorityr, IPRIORITY);
+
+ /* Restore GICD_ICFGR for INTIDs 32 - 1019 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFG);
+
+ /* Restore GICD_ICFGRE for INTIDs 4096 - 5119 */
+ RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, icfgr, ICFG);
+
+ /* Restore GICD_IGRPMODR for INTIDs 32 - 1019 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMOD);
+
+ /* Restore GICD_IGRPMODRE for INTIDs 4096 - 5119 */
+ RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, igrpmodr, IGRPMOD);
+
+ /* Restore GICD_NSACR for INTIDs 32 - 1019 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSAC);
+
+ /* Restore GICD_NSACRE for INTIDs 4096 - 5119 */
+ RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, nsacr, NSAC);
+
+ /* Restore GICD_IROUTER for INTIDs 32 - 1019 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTE);
+
+ /* Restore GICD_IROUTERE for INTIDs 4096 - 5119 */
+ RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, irouter, IROUTE);
+
+ /*
+ * Restore ISENABLER(E), ISPENDR(E) and ISACTIVER(E) after
+ * the interrupts are configured.
+ */
+
+ /* Restore GICD_ISENABLER for INT_IDs 32 - 1019 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLE);
+
+ /* Restore GICD_ISENABLERE for INT_IDs 4096 - 5119 */
+ RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, isenabler, ISENABLE);
+
+ /* Restore GICD_ISPENDR for INTIDs 32 - 1019 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPEND);
+
+ /* Restore GICD_ISPENDRE for INTIDs 4096 - 5119 */
+ RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, ispendr, ISPEND);
+
+ /* Restore GICD_ISACTIVER for INTIDs 32 - 1019 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVE);
+
+ /* Restore GICD_ISACTIVERE for INTIDs 4096 - 5119 */
+ RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, isactiver, ISACTIVE);
+
+ /* 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 (E)PPI and programs the corresponding Redistributor
+ * interface.
+ ******************************************************************************/
+unsigned int gicv3_get_interrupt_active(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);
+
+ /* Check interrupt ID */
+ if (is_sgi_ppi(id)) {
+ /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
+ return gicr_get_isactiver(
+ gicv3_driver_data->rdistif_base_addrs[proc_num], id);
+ }
+
+ /* For SPIs: 32-1019 and ESPIs: 4096-5119 */
+ return gicd_get_isactiver(gicv3_driver_data->gicd_base, id);
+}
+
+/*******************************************************************************
+ * 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);
+
+ /*
+ * Ensure that any shared variable updates depending on out of band
+ * interrupt trigger are observed before enabling interrupt.
+ */
+ dsbishst();
+
+ /* Check interrupt ID */
+ if (is_sgi_ppi(id)) {
+ /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
+ gicr_set_isenabler(
+ gicv3_driver_data->rdistif_base_addrs[proc_num], id);
+ } else {
+ /* For SPIs: 32-1019 and ESPIs: 4096-5119 */
+ 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);
+
+ /*
+ * Disable interrupt, and ensure that any shared variable updates
+ * depending on out of band interrupt trigger are observed afterwards.
+ */
+
+ /* Check interrupt ID */
+ if (is_sgi_ppi(id)) {
+ /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
+ gicr_set_icenabler(
+ 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 {
+ /* For SPIs: 32-1019 and ESPIs: 4096-5119 */
+ 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);
+
+ /* Check interrupt ID */
+ if (is_sgi_ppi(id)) {
+ /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+ gicr_set_ipriorityr(gicr_base, id, priority);
+ } else {
+ /* For SPIs: 32-1019 and ESPIs: 4096-5119 */
+ 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 (E)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;
+ }
+
+ /* Check interrupt ID */
+ if (is_sgi_ppi(id)) {
+ /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+
+ igroup ? gicr_set_igroupr(gicr_base, id) :
+ gicr_clr_igroupr(gicr_base, id);
+ grpmod ? gicr_set_igrpmodr(gicr_base, id) :
+ gicr_clr_igrpmodr(gicr_base, id);
+ } else {
+ /* For SPIs: 32-1019 and ESPIs: 4096-5119 */
+
+ /* Serialize read-modify-write to Distributor registers */
+ spin_lock(&gic_lock);
+
+ igroup ? gicd_set_igroupr(gicv3_driver_data->gicd_base, id) :
+ gicd_clr_igroupr(gicv3_driver_data->gicd_base, id);
+ grpmod ? gicd_set_igrpmodr(gicv3_driver_data->gicd_base, id) :
+ gicd_clr_igrpmodr(gicv3_driver_data->gicd_base, id);
+
+ spin_unlock(&gic_lock);
+ }
+}
+
+/*******************************************************************************
+ * This function raises the specified SGI of the specified group.
+ *
+ * The target parameter must be a valid MPIDR in the system.
+ ******************************************************************************/
+void gicv3_raise_sgi(unsigned int sgi_num, gicv3_irq_group_t group,
+ 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();
+
+ switch (group) {
+ case GICV3_G0:
+ write_icc_sgi0r_el1(sgi_val);
+ break;
+ case GICV3_G1NS:
+ write_icc_asgi1r(sgi_val);
+ break;
+ case GICV3_G1S:
+ write_icc_sgi1r(sgi_val);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ isb();
+}
+
+/*******************************************************************************
+ * This function sets the interrupt routing for the given (E)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(IS_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 (E)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.
+ */
+
+ /* Check interrupt ID */
+ if (is_sgi_ppi(id)) {
+ /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
+ gicr_set_icpendr(
+ gicv3_driver_data->rdistif_base_addrs[proc_num], id);
+ } else {
+ /* For SPIs: 32-1019 and ESPIs: 4096-5119 */
+ 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();
+
+ /* Check interrupt ID */
+ if (is_sgi_ppi(id)) {
+ /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
+ gicr_set_ispendr(
+ gicv3_driver_data->rdistif_base_addrs[proc_num], id);
+ } else {
+ /* For SPIs: 32-1019 and ESPIs: 4096-5119 */
+ 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 = (unsigned int)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, mpidr_self;
+ unsigned int proc_num;
+ 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__ */
+
+ mpidr_self = read_mpidr_el1() & MPIDR_AFFINITY_MASK;
+ rdistif_base = gicr_frame;
+ do {
+ typer_val = gicr_read_typer(rdistif_base);
+ mpidr = mpidr_from_gicr_typer(typer_val);
+ if (gicv3_driver_data->mpidr_to_core_pos != NULL) {
+ 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 (mpidr == mpidr_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 += gicv3_redist_size(typer_val);
+ } 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 */
+}
+
+/******************************************************************************
+ * This function checks the interrupt ID and returns true for SGIs and (E)PPIs
+ * and false for (E)SPIs IDs.
+ *****************************************************************************/
+static bool is_sgi_ppi(unsigned int id)
+{
+ /* SGIs: 0-15, PPIs: 16-31, EPPIs: 1056-1119 */
+ if (IS_SGI_PPI(id)) {
+ return true;
+ }
+
+ /* SPIs: 32-1019, ESPIs: 4096-5119 */
+ if (IS_SPI(id)) {
+ return false;
+ }
+
+ assert(false);
+ panic();
+}
diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h
new file mode 100644
index 0000000..3af0500
--- /dev/null
+++ b/drivers/arm/gic/v3/gicv3_private.h
@@ -0,0 +1,707 @@
+/*
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GICV3_PRIVATE_H
+#define GICV3_PRIVATE_H
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/mmio.h>
+
+#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)
+
+/* Calculate GIC register bit number corresponding to its interrupt ID */
+#define BIT_NUM(REG, id) \
+ ((id) & ((1U << REG##R_SHIFT) - 1U))
+
+/*
+ * Calculate 8, 32 and 64-bit GICD register offset
+ * corresponding to its interrupt ID
+ */
+#if GIC_EXT_INTID
+ /* GICv3.1 */
+#define GICD_OFFSET_8(REG, id) \
+ (((id) <= MAX_SPI_ID) ? \
+ GICD_##REG##R + (uintptr_t)(id) : \
+ GICD_##REG##RE + (uintptr_t)(id) - MIN_ESPI_ID)
+
+#define GICD_OFFSET(REG, id) \
+ (((id) <= MAX_SPI_ID) ? \
+ GICD_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 2) : \
+ GICD_##REG##RE + ((((uintptr_t)(id) - MIN_ESPI_ID) >> \
+ REG##R_SHIFT) << 2))
+
+#define GICD_OFFSET_64(REG, id) \
+ (((id) <= MAX_SPI_ID) ? \
+ GICD_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 3) : \
+ GICD_##REG##RE + ((((uintptr_t)(id) - MIN_ESPI_ID) >> \
+ REG##R_SHIFT) << 3))
+
+#else /* GICv3 */
+#define GICD_OFFSET_8(REG, id) \
+ (GICD_##REG##R + (uintptr_t)(id))
+
+#define GICD_OFFSET(REG, id) \
+ (GICD_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 2))
+
+#define GICD_OFFSET_64(REG, id) \
+ (GICD_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 3))
+#endif /* GIC_EXT_INTID */
+
+/*
+ * Read/Write 8, 32 and 64-bit GIC Distributor register
+ * corresponding to its interrupt ID
+ */
+#define GICD_READ(REG, base, id) \
+ mmio_read_32((base) + GICD_OFFSET(REG, (id)))
+
+#define GICD_READ_64(REG, base, id) \
+ mmio_read_64((base) + GICD_OFFSET_64(REG, (id)))
+
+#define GICD_WRITE_8(REG, base, id, val) \
+ mmio_write_8((base) + GICD_OFFSET_8(REG, (id)), (val))
+
+#define GICD_WRITE(REG, base, id, val) \
+ mmio_write_32((base) + GICD_OFFSET(REG, (id)), (val))
+
+#define GICD_WRITE_64(REG, base, id, val) \
+ mmio_write_64((base) + GICD_OFFSET_64(REG, (id)), (val))
+
+/*
+ * Bit operations on GIC Distributor register corresponding
+ * to its interrupt ID
+ */
+/* Get bit in GIC Distributor register */
+#define GICD_GET_BIT(REG, base, id) \
+ ((mmio_read_32((base) + GICD_OFFSET(REG, (id))) >> \
+ BIT_NUM(REG, (id))) & 1U)
+
+/* Set bit in GIC Distributor register */
+#define GICD_SET_BIT(REG, base, id) \
+ mmio_setbits_32((base) + GICD_OFFSET(REG, (id)), \
+ ((uint32_t)1 << BIT_NUM(REG, (id))))
+
+/* Clear bit in GIC Distributor register */
+#define GICD_CLR_BIT(REG, base, id) \
+ mmio_clrbits_32((base) + GICD_OFFSET(REG, (id)), \
+ ((uint32_t)1 << BIT_NUM(REG, (id))))
+
+/* Write bit in GIC Distributor register */
+#define GICD_WRITE_BIT(REG, base, id) \
+ mmio_write_32((base) + GICD_OFFSET(REG, (id)), \
+ ((uint32_t)1 << BIT_NUM(REG, (id))))
+
+/*
+ * Calculate 8 and 32-bit GICR register offset
+ * corresponding to its interrupt ID
+ */
+#if GIC_EXT_INTID
+ /* GICv3.1 */
+#define GICR_OFFSET_8(REG, id) \
+ (((id) <= MAX_PPI_ID) ? \
+ GICR_##REG##R + (uintptr_t)(id) : \
+ GICR_##REG##R + (uintptr_t)(id) - (MIN_EPPI_ID - MIN_SPI_ID))
+
+#define GICR_OFFSET(REG, id) \
+ (((id) <= MAX_PPI_ID) ? \
+ GICR_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 2) : \
+ GICR_##REG##R + ((((uintptr_t)(id) - (MIN_EPPI_ID - MIN_SPI_ID))\
+ >> REG##R_SHIFT) << 2))
+#else /* GICv3 */
+#define GICR_OFFSET_8(REG, id) \
+ (GICR_##REG##R + (uintptr_t)(id))
+
+#define GICR_OFFSET(REG, id) \
+ (GICR_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 2))
+#endif /* GIC_EXT_INTID */
+
+/* Read/Write GIC Redistributor register corresponding to its interrupt ID */
+#define GICR_READ(REG, base, id) \
+ mmio_read_32((base) + GICR_OFFSET(REG, (id)))
+
+#define GICR_WRITE_8(REG, base, id, val) \
+ mmio_write_8((base) + GICR_OFFSET_8(REG, (id)), (val))
+
+#define GICR_WRITE(REG, base, id, val) \
+ mmio_write_32((base) + GICR_OFFSET(REG, (id)), (val))
+
+/*
+ * Bit operations on GIC Redistributor register
+ * corresponding to its interrupt ID
+ */
+/* Get bit in GIC Redistributor register */
+#define GICR_GET_BIT(REG, base, id) \
+ ((mmio_read_32((base) + GICR_OFFSET(REG, (id))) >> \
+ BIT_NUM(REG, (id))) & 1U)
+
+/* Write bit in GIC Redistributor register */
+#define GICR_WRITE_BIT(REG, base, id) \
+ mmio_write_32((base) + GICR_OFFSET(REG, (id)), \
+ ((uint32_t)1 << BIT_NUM(REG, (id))))
+
+/* Set bit in GIC Redistributor register */
+#define GICR_SET_BIT(REG, base, id) \
+ mmio_setbits_32((base) + GICR_OFFSET(REG, (id)), \
+ ((uint32_t)1 << BIT_NUM(REG, (id))))
+
+/* Clear bit in GIC Redistributor register */
+#define GICR_CLR_BIT(REG, base, id) \
+ mmio_clrbits_32((base) + GICR_OFFSET(REG, (id)), \
+ ((uint32_t)1 << BIT_NUM(REG, (id))))
+
+/*
+ * 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 & MPIDR_AFFINITY_MASK) |
+ ((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_igrpmodr(uintptr_t base, unsigned int id);
+unsigned int gicr_get_igroupr(uintptr_t base, unsigned int id);
+unsigned int gicr_get_isactiver(uintptr_t base, unsigned int id);
+void gicd_set_igrpmodr(uintptr_t base, unsigned int id);
+void gicr_set_igrpmodr(uintptr_t base, unsigned int id);
+void gicr_set_isenabler(uintptr_t base, unsigned int id);
+void gicr_set_icenabler(uintptr_t base, unsigned int id);
+void gicr_set_ispendr(uintptr_t base, unsigned int id);
+void gicr_set_icpendr(uintptr_t base, unsigned int id);
+void gicr_set_igroupr(uintptr_t base, unsigned int id);
+void gicd_clr_igrpmodr(uintptr_t base, unsigned int id);
+void gicr_clr_igrpmodr(uintptr_t base, unsigned int id);
+void gicr_clr_igroupr(uintptr_t base, unsigned int id);
+void gicr_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri);
+void gicr_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg);
+
+/*******************************************************************************
+ * Private GICv3 helper function prototypes
+ ******************************************************************************/
+unsigned int gicv3_get_spi_limit(uintptr_t gicd_base);
+unsigned int gicv3_get_espi_limit(uintptr_t gicd_base);
+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[7:4] - the ARE bits, E1NWF bit and DS bit
+ * GICD_ICENABLER<n> - 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 uint32_t gicd_read_pidr2(uintptr_t base)
+{
+ return mmio_read_32(base + GICD_PIDR2_GICV3);
+}
+
+static inline uint64_t gicd_read_irouter(uintptr_t base, unsigned int id)
+{
+ assert(id >= MIN_SPI_ID);
+ return GICD_READ_64(IROUTE, base, id);
+}
+
+static inline void gicd_write_irouter(uintptr_t base,
+ unsigned int id,
+ uint64_t affinity)
+{
+ assert(id >= MIN_SPI_ID);
+ GICD_WRITE_64(IROUTE, base, id, 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 uint64_t gicr_read_typer(uintptr_t base)
+{
+ return mmio_read_64(base + GICR_TYPER);
+}
+
+static inline uint32_t gicr_read_waker(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_WAKER);
+}
+
+static inline void gicr_write_waker(uintptr_t base, uint32_t val)
+{
+ mmio_write_32(base + GICR_WAKER, val);
+}
+
+/*
+ * Wait for updates to:
+ * GICR_ICENABLER0
+ * GICR_CTLR.DPG1S
+ * GICR_CTLR.DPG1NS
+ * GICR_CTLR.DPG0
+ * GICR_CTLR, which clears EnableLPIs from 1 to 0
+ */
+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 Redistributor 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.
+ ******************************************************************************/
+
+/*
+ * Accessors to read/write GIC Redistributor ICENABLER0 register
+ */
+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);
+}
+
+/*
+ * Accessors to read/write GIC Redistributor ICENABLER0 and ICENABLERE
+ * register corresponding to its number
+ */
+static inline unsigned int gicr_read_icenabler(uintptr_t base,
+ unsigned int reg_num)
+{
+ return mmio_read_32(base + GICR_ICENABLER + (reg_num << 2));
+}
+
+static inline void gicr_write_icenabler(uintptr_t base, unsigned int reg_num,
+ unsigned int val)
+{
+ mmio_write_32(base + GICR_ICENABLER + (reg_num << 2), val);
+}
+
+/*
+ * Accessors to read/write GIC Redistributor ICFGR0, ICFGR1 registers
+ */
+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);
+}
+
+/*
+ * Accessors to read/write GIC Redistributor ICFGR0, ICFGR1 and ICFGRE
+ * register corresponding to its number
+ */
+static inline unsigned int gicr_read_icfgr(uintptr_t base, unsigned int reg_num)
+{
+ return mmio_read_32(base + GICR_ICFGR + (reg_num << 2));
+}
+
+static inline void gicr_write_icfgr(uintptr_t base, unsigned int reg_num,
+ unsigned int val)
+{
+ mmio_write_32(base + GICR_ICFGR + (reg_num << 2), val);
+}
+
+/*
+ * Accessor to write GIC Redistributor ICPENDR0 register
+ */
+static inline void gicr_write_icpendr0(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_ICPENDR0, val);
+}
+
+/*
+ * Accessor to write GIC Redistributor ICPENDR0 and ICPENDRE
+ * register corresponding to its number
+ */
+static inline void gicr_write_icpendr(uintptr_t base, unsigned int reg_num,
+ unsigned int val)
+{
+ mmio_write_32(base + GICR_ICPENDR + (reg_num << 2), val);
+}
+
+/*
+ * Accessors to read/write GIC Redistributor IGROUPR0 register
+ */
+static inline unsigned int gicr_read_igroupr0(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_IGROUPR0);
+}
+
+static inline void gicr_write_igroupr0(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_IGROUPR0, val);
+}
+
+/*
+ * Accessors to read/write GIC Redistributor IGROUPR0 and IGROUPRE
+ * register corresponding to its number
+ */
+static inline unsigned int gicr_read_igroupr(uintptr_t base,
+ unsigned int reg_num)
+{
+ return mmio_read_32(base + GICR_IGROUPR + (reg_num << 2));
+}
+
+static inline void gicr_write_igroupr(uintptr_t base, unsigned int reg_num,
+ unsigned int val)
+{
+ mmio_write_32(base + GICR_IGROUPR + (reg_num << 2), val);
+}
+
+/*
+ * Accessors to read/write GIC Redistributor IGRPMODR0 register
+ */
+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);
+}
+
+/*
+ * Accessors to read/write GIC Redistributor IGRPMODR0 and IGRPMODRE
+ * register corresponding to its number
+ */
+static inline unsigned int gicr_read_igrpmodr(uintptr_t base,
+ unsigned int reg_num)
+{
+ return mmio_read_32(base + GICR_IGRPMODR + (reg_num << 2));
+}
+
+static inline void gicr_write_igrpmodr(uintptr_t base, unsigned int reg_num,
+ unsigned int val)
+{
+ mmio_write_32(base + GICR_IGRPMODR + (reg_num << 2), val);
+}
+
+/*
+ * Accessors to read/write the GIC Redistributor IPRIORITYR(E) register
+ * corresponding to its number, 4 interrupts IDs at a time.
+ */
+static inline unsigned int gicr_ipriorityr_read(uintptr_t base,
+ unsigned int reg_num)
+{
+ return mmio_read_32(base + GICR_IPRIORITYR + (reg_num << 2));
+}
+
+static inline void gicr_ipriorityr_write(uintptr_t base, unsigned int reg_num,
+ unsigned int val)
+{
+ mmio_write_32(base + GICR_IPRIORITYR + (reg_num << 2), val);
+}
+
+/*
+ * Accessors to read/write GIC Redistributor ISACTIVER0 register
+ */
+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);
+}
+
+/*
+ * Accessors to read/write GIC Redistributor ISACTIVER0 and ISACTIVERE
+ * register corresponding to its number
+ */
+static inline unsigned int gicr_read_isactiver(uintptr_t base,
+ unsigned int reg_num)
+{
+ return mmio_read_32(base + GICR_ISACTIVER + (reg_num << 2));
+}
+
+static inline void gicr_write_isactiver(uintptr_t base, unsigned int reg_num,
+ unsigned int val)
+{
+ mmio_write_32(base + GICR_ISACTIVER + (reg_num << 2), val);
+}
+
+/*
+ * Accessors to read/write GIC Redistributor ISENABLER0 register
+ */
+static inline unsigned int gicr_read_isenabler0(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_ISENABLER0);
+}
+
+static inline void gicr_write_isenabler0(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_ISENABLER0, val);
+}
+
+/*
+ * Accessors to read/write GIC Redistributor ISENABLER0 and ISENABLERE
+ * register corresponding to its number
+ */
+static inline unsigned int gicr_read_isenabler(uintptr_t base,
+ unsigned int reg_num)
+{
+ return mmio_read_32(base + GICR_ISENABLER + (reg_num << 2));
+}
+
+static inline void gicr_write_isenabler(uintptr_t base, unsigned int reg_num,
+ unsigned int val)
+{
+ mmio_write_32(base + GICR_ISENABLER + (reg_num << 2), val);
+}
+
+/*
+ * Accessors to read/write GIC Redistributor ISPENDR0 register
+ */
+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);
+}
+
+/*
+ * Accessors to read/write GIC Redistributor ISPENDR0 and ISPENDRE
+ * register corresponding to its number
+ */
+static inline unsigned int gicr_read_ispendr(uintptr_t base,
+ unsigned int reg_num)
+{
+ return mmio_read_32(base + GICR_ISPENDR + (reg_num << 2));
+}
+
+static inline void gicr_write_ispendr(uintptr_t base, unsigned int reg_num,
+ unsigned int val)
+{
+ mmio_write_32(base + GICR_ISPENDR + (reg_num << 2), val);
+}
+
+/*
+ * Accessors to read/write GIC Redistributor NSACR register
+ */
+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);
+}
+
+/*
+ * Accessors to read/write GIC Redistributor PROPBASER register
+ */
+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);
+}
+
+/*
+ * Accessors to read/write GIC Redistributor PENDBASER register
+ */
+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, uint32_t 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 */
diff --git a/drivers/arm/mhu/mhu_v2_x.c b/drivers/arm/mhu/mhu_v2_x.c
new file mode 100644
index 0000000..3103b92
--- /dev/null
+++ b/drivers/arm/mhu/mhu_v2_x.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "mhu_v2_x.h"
+
+#define MHU_V2_X_MAX_CHANNELS 124
+#define MHU_V2_1_MAX_CHCOMB_INT 4
+#define ENABLE 0x1
+#define DISABLE 0x0
+#define CLEAR_INTR 0x1
+#define CH_PER_CH_COMB 0x20
+#define SEND_FRAME(p_mhu) ((struct mhu_v2_x_send_frame_t *)p_mhu)
+#define RECV_FRAME(p_mhu) ((struct mhu_v2_x_recv_frame_t *)p_mhu)
+
+#define MHU_MAJOR_REV_V2 0x1u
+#define MHU_MINOR_REV_2_0 0x0u
+#define MHU_MINOR_REV_2_1 0x1u
+
+struct mhu_v2_x_send_ch_window_t {
+ /* Offset: 0x00 (R/ ) Channel Status */
+ volatile uint32_t ch_st;
+ /* Offset: 0x04 (R/ ) Reserved */
+ volatile uint32_t reserved_0;
+ /* Offset: 0x08 (R/ ) Reserved */
+ volatile uint32_t reserved_1;
+ /* Offset: 0x0C ( /W) Channel Set */
+ volatile uint32_t ch_set;
+ /* Offset: 0x10 (R/ ) Channel Interrupt Status (Reserved in 2.0) */
+ volatile uint32_t ch_int_st;
+ /* Offset: 0x14 ( /W) Channel Interrupt Clear (Reserved in 2.0) */
+ volatile uint32_t ch_int_clr;
+ /* Offset: 0x18 (R/W) Channel Interrupt Enable (Reserved in 2.0) */
+ volatile uint32_t ch_int_en;
+ /* Offset: 0x1C (R/ ) Reserved */
+ volatile uint32_t reserved_2;
+};
+
+struct mhu_v2_x_send_frame_t {
+ /* Offset: 0x000 ( / ) Sender Channel Window 0 -123 */
+ struct mhu_v2_x_send_ch_window_t send_ch_window[MHU_V2_X_MAX_CHANNELS];
+ /* Offset: 0xF80 (R/ ) Message Handling Unit Configuration */
+ volatile uint32_t mhu_cfg;
+ /* Offset: 0xF84 (R/W) Response Configuration */
+ volatile uint32_t resp_cfg;
+ /* Offset: 0xF88 (R/W) Access Request */
+ volatile uint32_t access_request;
+ /* Offset: 0xF8C (R/ ) Access Ready */
+ volatile uint32_t access_ready;
+ /* Offset: 0xF90 (R/ ) Interrupt Status */
+ volatile uint32_t int_st;
+ /* Offset: 0xF94 ( /W) Interrupt Clear */
+ volatile uint32_t int_clr;
+ /* Offset: 0xF98 (R/W) Interrupt Enable */
+ volatile uint32_t int_en;
+ /* Offset: 0xF9C (R/ ) Reserved */
+ volatile uint32_t reserved_0;
+ /* Offset: 0xFA0 (R/W) Channel Combined IRQ Stat (Reserved in 2.0) */
+ volatile uint32_t ch_comb_int_st[MHU_V2_1_MAX_CHCOMB_INT];
+ /* Offset: 0xFC4 (R/ ) Reserved */
+ volatile uint32_t reserved_1[6];
+ /* Offset: 0xFC8 (R/ ) Implementer Identification Register */
+ volatile uint32_t iidr;
+ /* Offset: 0xFCC (R/ ) Architecture Identification Register */
+ volatile uint32_t aidr;
+ /* Offset: 0xFD0 (R/ ) */
+ volatile uint32_t pid_1[4];
+ /* Offset: 0xFE0 (R/ ) */
+ volatile uint32_t pid_0[4];
+ /* Offset: 0xFF0 (R/ ) */
+ volatile uint32_t cid[4];
+};
+
+struct mhu_v2_x_rec_ch_window_t {
+ /* Offset: 0x00 (R/ ) Channel Status */
+ volatile uint32_t ch_st;
+ /* Offset: 0x04 (R/ ) Channel Status Masked */
+ volatile uint32_t ch_st_msk;
+ /* Offset: 0x08 ( /W) Channel Clear */
+ volatile uint32_t ch_clr;
+ /* Offset: 0x0C (R/ ) Reserved */
+ volatile uint32_t reserved_0;
+ /* Offset: 0x10 (R/ ) Channel Mask Status */
+ volatile uint32_t ch_msk_st;
+ /* Offset: 0x14 ( /W) Channel Mask Set */
+ volatile uint32_t ch_msk_set;
+ /* Offset: 0x18 ( /W) Channel Mask Clear */
+ volatile uint32_t ch_msk_clr;
+ /* Offset: 0x1C (R/ ) Reserved */
+ volatile uint32_t reserved_1;
+};
+
+struct mhu_v2_x_recv_frame_t {
+ /* Offset: 0x000 ( / ) Receiver Channel Window 0 -123 */
+ struct mhu_v2_x_rec_ch_window_t rec_ch_window[MHU_V2_X_MAX_CHANNELS];
+ /* Offset: 0xF80 (R/ ) Message Handling Unit Configuration */
+ volatile uint32_t mhu_cfg;
+ /* Offset: 0xF84 (R/ ) Reserved */
+ volatile uint32_t reserved_0[3];
+ /* Offset: 0xF90 (R/ ) Interrupt Status (Reserved in 2.0) */
+ volatile uint32_t int_st;
+ /* Offset: 0xF94 (R/ ) Interrupt Clear (Reserved in 2.0) */
+ volatile uint32_t int_clr;
+ /* Offset: 0xF98 (R/W) Interrupt Enable (Reserved in 2.0) */
+ volatile uint32_t int_en;
+ /* Offset: 0xF9C (R/ ) Reserved */
+ volatile uint32_t reserved_1;
+ /* Offset: 0xFA0 (R/ ) Channel Combined IRQ Stat (Reserved in 2.0) */
+ volatile uint32_t ch_comb_int_st[MHU_V2_1_MAX_CHCOMB_INT];
+ /* Offset: 0xFB0 (R/ ) Reserved */
+ volatile uint32_t reserved_2[6];
+ /* Offset: 0xFC8 (R/ ) Implementer Identification Register */
+ volatile uint32_t iidr;
+ /* Offset: 0xFCC (R/ ) Architecture Identification Register */
+ volatile uint32_t aidr;
+ /* Offset: 0xFD0 (R/ ) */
+ volatile uint32_t pid_1[4];
+ /* Offset: 0xFE0 (R/ ) */
+ volatile uint32_t pid_0[4];
+ /* Offset: 0xFF0 (R/ ) */
+ volatile uint32_t cid[4];
+};
+
+union mhu_v2_x_frame {
+ struct mhu_v2_x_send_frame_t send_frame;
+ struct mhu_v2_x_recv_frame_t recv_frame;
+};
+
+enum mhu_v2_x_error_t mhu_v2_x_driver_init(struct mhu_v2_x_dev_t *dev,
+ enum mhu_v2_x_supported_revisions rev)
+{
+ uint32_t AIDR = 0;
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (dev->is_initialized) {
+ return MHU_V_2_X_ERR_ALREADY_INIT;
+ }
+
+ if (rev == MHU_REV_READ_FROM_HW) {
+ /* Read revision from HW */
+ if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ AIDR = p_mhu->recv_frame.aidr;
+ } else {
+ AIDR = p_mhu->send_frame.aidr;
+ }
+
+ /* Get bits 7:4 to read major revision */
+ if (((AIDR >> 4) & 0b1111) != MHU_MAJOR_REV_V2) {
+ /* Unsupported MHU version */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ } /* No need to save major version, driver only supports MHUv2 */
+
+ /* Get bits 3:0 to read minor revision */
+ dev->subversion = AIDR & 0b1111;
+
+ if (dev->subversion != MHU_MINOR_REV_2_0 &&
+ dev->subversion != MHU_MINOR_REV_2_1) {
+ /* Unsupported subversion */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }
+ } else {
+ /* Revisions were provided by caller */
+ if (rev == MHU_REV_2_0) {
+ dev->subversion = MHU_MINOR_REV_2_0;
+ } else if (rev == MHU_REV_2_1) {
+ dev->subversion = MHU_MINOR_REV_2_1;
+ } else {
+ /* Unsupported subversion */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ } /* No need to save major version, driver only supports MHUv2 */
+ }
+
+ dev->is_initialized = true;
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+uint32_t mhu_v2_x_get_num_channel_implemented(const struct mhu_v2_x_dev_t *dev)
+{
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (!(dev->is_initialized)) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame == MHU_V2_X_SENDER_FRAME) {
+ return (SEND_FRAME(p_mhu))->mhu_cfg;
+ } else {
+ assert(dev->frame == MHU_V2_X_RECEIVER_FRAME);
+ return (RECV_FRAME(p_mhu))->mhu_cfg;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_send(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel, uint32_t val)
+{
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (!(dev->is_initialized)) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame == MHU_V2_X_SENDER_FRAME) {
+ (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_set = val;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_poll(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel, uint32_t *value)
+{
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (!(dev->is_initialized)) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame == MHU_V2_X_SENDER_FRAME) {
+ *value = (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_st;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_clear(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel)
+{
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (!(dev->is_initialized)) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_clr = UINT32_MAX;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_receive(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t *value)
+{
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (!(dev->is_initialized)) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ *value = (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_st;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_set(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask)
+{
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (!(dev->is_initialized)) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_msk_set = mask;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_clear(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask)
+{
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (!(dev->is_initialized)) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_msk_clr = mask;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+enum mhu_v2_x_error_t mhu_v2_x_initiate_transfer(
+ const struct mhu_v2_x_dev_t *dev)
+{
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (!(dev->is_initialized)) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame != MHU_V2_X_SENDER_FRAME) {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ (SEND_FRAME(p_mhu))->access_request = ENABLE;
+
+ while (!((SEND_FRAME(p_mhu))->access_ready)) {
+ /* Wait in a loop for access ready signal to be high */
+ ;
+ }
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_close_transfer(const struct mhu_v2_x_dev_t *dev)
+{
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (!(dev->is_initialized)) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame != MHU_V2_X_SENDER_FRAME) {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ (SEND_FRAME(p_mhu))->access_request = DISABLE;
+
+ return MHU_V_2_X_ERR_NONE;
+}
diff --git a/drivers/arm/mhu/mhu_v2_x.h b/drivers/arm/mhu/mhu_v2_x.h
new file mode 100644
index 0000000..10247d2
--- /dev/null
+++ b/drivers/arm/mhu/mhu_v2_x.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MHU_V2_X_H
+#define MHU_V2_X_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define MHU_2_X_INTR_NR2R_OFF (0x0u)
+#define MHU_2_X_INTR_R2NR_OFF (0x1u)
+#define MHU_2_1_INTR_CHCOMB_OFF (0x2u)
+
+#define MHU_2_X_INTR_NR2R_MASK (0x1u << MHU_2_X_INTR_NR2R_OFF)
+#define MHU_2_X_INTR_R2NR_MASK (0x1u << MHU_2_X_INTR_R2NR_OFF)
+#define MHU_2_1_INTR_CHCOMB_MASK (0x1u << MHU_2_1_INTR_CHCOMB_OFF)
+
+enum mhu_v2_x_frame_t {
+ MHU_V2_X_SENDER_FRAME = 0x0u,
+ MHU_V2_X_RECEIVER_FRAME = 0x1u,
+};
+
+enum mhu_v2_x_supported_revisions {
+ MHU_REV_READ_FROM_HW = 0,
+ MHU_REV_2_0,
+ MHU_REV_2_1,
+};
+
+struct mhu_v2_x_dev_t {
+ uintptr_t base;
+ enum mhu_v2_x_frame_t frame;
+ uint32_t subversion; /*!< Hardware subversion: v2.X */
+ bool is_initialized; /*!< Indicates if the MHU driver
+ * is initialized and enabled
+ */
+};
+
+/**
+ * MHU v2 error enumeration types.
+ */
+enum mhu_v2_x_error_t {
+ MHU_V_2_X_ERR_NONE = 0,
+ MHU_V_2_X_ERR_NOT_INIT = -1,
+ MHU_V_2_X_ERR_ALREADY_INIT = -2,
+ MHU_V_2_X_ERR_UNSUPPORTED_VERSION = -3,
+ MHU_V_2_X_ERR_INVALID_ARG = -4,
+ MHU_V_2_X_ERR_GENERAL = -5
+};
+
+/**
+ * Initializes the driver.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ * rev MHU revision (if can't be identified from HW).
+ *
+ * Reads the MHU hardware version.
+ *
+ * Returns mhu_v2_x_error_t error code.
+ *
+ * MHU revision only has to be specified when versions can't be read
+ * from HW (ARCH_MAJOR_REV reg reads as 0x0).
+ *
+ * This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_driver_init(struct mhu_v2_x_dev_t *dev,
+ enum mhu_v2_x_supported_revisions rev);
+
+/**
+ * Returns the number of channels implemented.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ *
+ * This function doesn't check if dev is NULL.
+ */
+uint32_t mhu_v2_x_get_num_channel_implemented(
+ const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * Sends the value over a channel.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ * channel Channel to send the value over.
+ * val Value to send.
+ *
+ * Sends the value over a channel.
+ *
+ * Returns mhu_v2_x_error_t error code.
+ *
+ * This function doesn't check if dev is NULL.
+ * This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_send(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel, uint32_t val);
+
+/**
+ * Polls sender channel status.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ * channel Channel to poll the status of.
+ * value Pointer to variable that will store the value.
+ *
+ * Polls sender channel status.
+ *
+ * Returns mhu_v2_x_error_t error code.
+ *
+ * This function doesn't check if dev is NULL.
+ * This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_poll(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel, uint32_t *value);
+
+/**
+ * Clears the channel after the value is send over it.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ * channel Channel to clear.
+ *
+ * Clears the channel after the value is send over it.
+ *
+ * Returns mhu_v2_x_error_t error code..
+ *
+ * This function doesn't check if dev is NULL.
+ * This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_clear(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel);
+
+/**
+ * Receives the value over a channel.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ * channel Channel to receive the value from.
+ * value Pointer to variable that will store the value.
+ *
+ * Receives the value over a channel.
+ *
+ * Returns mhu_v2_x_error_t error code.
+ *
+ * This function doesn't check if dev is NULL.
+ * This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_receive(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t *value);
+
+/**
+ * Sets bits in the Channel Mask.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ * channel Which channel's mask to set.
+ * mask Mask to be set over a receiver frame.
+ *
+ * Sets bits in the Channel Mask.
+ *
+ * Returns mhu_v2_x_error_t error code..
+ *
+ * This function doesn't check if dev is NULL.
+ * This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_set(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask);
+
+/**
+ * Clears bits in the Channel Mask.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ * channel Which channel's mask to clear.
+ * mask Mask to be clear over a receiver frame.
+ *
+ * Clears bits in the Channel Mask.
+ *
+ * Returns mhu_v2_x_error_t error code.
+ *
+ * This function doesn't check if dev is NULL.
+ * This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_clear(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask);
+
+/**
+ * Initiates a MHU transfer with the handshake signals.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ *
+ * Initiates a MHU transfer with the handshake signals in a blocking mode.
+ *
+ * Returns mhu_v2_x_error_t error code.
+ *
+ * This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_initiate_transfer(
+ const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * Closes a MHU transfer with the handshake signals.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ *
+ * Closes a MHU transfer with the handshake signals in a blocking mode.
+ *
+ * Returns mhu_v2_x_error_t error code.
+ *
+ * This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_close_transfer(
+ const struct mhu_v2_x_dev_t *dev);
+
+#endif /* MHU_V2_X_H */
diff --git a/drivers/arm/mhu/mhu_wrapper_v2_x.c b/drivers/arm/mhu/mhu_wrapper_v2_x.c
new file mode 100644
index 0000000..60de1d3
--- /dev/null
+++ b/drivers/arm/mhu/mhu_wrapper_v2_x.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <drivers/arm/mhu.h>
+
+#include "mhu_v2_x.h"
+
+#define MHU_NOTIFY_VALUE (1234u)
+
+/*
+ * MHU devices for host:
+ * HSE: Host to Secure Enclave (sender device)
+ * SEH: Secure Enclave to Host (receiver device)
+ */
+struct mhu_v2_x_dev_t MHU1_HSE_DEV = {0, MHU_V2_X_SENDER_FRAME};
+struct mhu_v2_x_dev_t MHU1_SEH_DEV = {0, MHU_V2_X_RECEIVER_FRAME};
+
+static enum mhu_error_t error_mapping_to_mhu_error_t(enum mhu_v2_x_error_t err)
+{
+ switch (err) {
+ case MHU_V_2_X_ERR_NONE:
+ return MHU_ERR_NONE;
+ case MHU_V_2_X_ERR_NOT_INIT:
+ return MHU_ERR_NOT_INIT;
+ case MHU_V_2_X_ERR_ALREADY_INIT:
+ return MHU_ERR_ALREADY_INIT;
+ case MHU_V_2_X_ERR_UNSUPPORTED_VERSION:
+ return MHU_ERR_UNSUPPORTED_VERSION;
+ case MHU_V_2_X_ERR_INVALID_ARG:
+ return MHU_ERR_INVALID_ARG;
+ case MHU_V_2_X_ERR_GENERAL:
+ return MHU_ERR_GENERAL;
+ default:
+ return MHU_ERR_GENERAL;
+ }
+}
+
+static enum mhu_v2_x_error_t signal_and_wait_for_clear(void)
+{
+ enum mhu_v2_x_error_t err;
+ struct mhu_v2_x_dev_t *dev = &MHU1_HSE_DEV;
+ uint32_t val = MHU_NOTIFY_VALUE;
+ /* Using the last channel for notifications */
+ uint32_t channel_notify = mhu_v2_x_get_num_channel_implemented(dev) - 1;
+
+ err = mhu_v2_x_channel_send(dev, channel_notify, val);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return err;
+ }
+
+ do {
+ err = mhu_v2_x_channel_poll(dev, channel_notify, &val);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ break;
+ }
+ } while (val != 0);
+
+ return err;
+}
+
+static enum mhu_v2_x_error_t wait_for_signal(void)
+{
+ enum mhu_v2_x_error_t err;
+ struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV;
+ uint32_t val = 0;
+ /* Using the last channel for notifications */
+ uint32_t channel_notify = mhu_v2_x_get_num_channel_implemented(dev) - 1;
+
+ do {
+ err = mhu_v2_x_channel_receive(dev, channel_notify, &val);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ break;
+ }
+ } while (val != MHU_NOTIFY_VALUE);
+
+ return err;
+}
+
+static enum mhu_v2_x_error_t clear_and_wait_for_next_signal(void)
+{
+ enum mhu_v2_x_error_t err;
+ struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV;
+ uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev);
+ uint32_t i;
+
+ /* Clear all channels */
+ for (i = 0; i < num_channels; ++i) {
+ err = mhu_v2_x_channel_clear(dev, i);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return err;
+ }
+ }
+
+ return wait_for_signal();
+}
+
+enum mhu_error_t mhu_init_sender(uintptr_t mhu_sender_base)
+{
+ enum mhu_v2_x_error_t err;
+
+ assert(mhu_sender_base != (uintptr_t)NULL);
+
+ MHU1_HSE_DEV.base = mhu_sender_base;
+
+ err = mhu_v2_x_driver_init(&MHU1_HSE_DEV, MHU_REV_READ_FROM_HW);
+ return error_mapping_to_mhu_error_t(err);
+}
+
+enum mhu_error_t mhu_init_receiver(uintptr_t mhu_receiver_base)
+{
+ enum mhu_v2_x_error_t err;
+ uint32_t num_channels, i;
+
+ assert(mhu_receiver_base != (uintptr_t)NULL);
+
+ MHU1_SEH_DEV.base = mhu_receiver_base;
+
+ err = mhu_v2_x_driver_init(&MHU1_SEH_DEV, MHU_REV_READ_FROM_HW);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ num_channels = mhu_v2_x_get_num_channel_implemented(&MHU1_SEH_DEV);
+
+ /* Mask all channels except the notifying channel */
+ for (i = 0; i < (num_channels - 1); ++i) {
+ err = mhu_v2_x_channel_mask_set(&MHU1_SEH_DEV, i, UINT32_MAX);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ }
+
+ /* The last channel is used for notifications */
+ err = mhu_v2_x_channel_mask_clear(
+ &MHU1_SEH_DEV, (num_channels - 1), UINT32_MAX);
+ return error_mapping_to_mhu_error_t(err);
+}
+
+/*
+ * Public function. See mhu.h
+ *
+ * The basic steps of transferring a message:
+ * 1. Initiate MHU transfer.
+ * 2. Send over the size of the payload on Channel 1. It is the very first
+ * 4 Bytes of the transfer. Continue with Channel 2.
+ * 3. Send over the payload, writing the channels one after the other
+ * (4 Bytes each). The last available channel is reserved for controlling
+ * the transfer.
+ * When the last channel is reached or no more data is left, STOP.
+ * 4. Notify the receiver using the last channel and wait for acknowledge.
+ * If there is still data to transfer, jump to step 3. Otherwise, proceed.
+ * 5. Close MHU transfer.
+ *
+ */
+enum mhu_error_t mhu_send_data(const uint8_t *send_buffer, size_t size)
+{
+ enum mhu_v2_x_error_t err;
+ struct mhu_v2_x_dev_t *dev = &MHU1_HSE_DEV;
+ uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev);
+ uint32_t chan = 0;
+ uint32_t i;
+ uint32_t *p;
+
+ /* For simplicity, require the send_buffer to be 4-byte aligned */
+ if ((uintptr_t)send_buffer & 0x3U) {
+ return MHU_ERR_INVALID_ARG;
+ }
+
+ err = mhu_v2_x_initiate_transfer(dev);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ /* First send over the size of the actual message */
+ err = mhu_v2_x_channel_send(dev, chan, (uint32_t)size);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ chan++;
+
+ p = (uint32_t *)send_buffer;
+ for (i = 0; i < size; i += 4) {
+ err = mhu_v2_x_channel_send(dev, chan, *p++);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ if (++chan == (num_channels - 1)) {
+ err = signal_and_wait_for_clear();
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ chan = 0;
+ }
+ }
+
+ /* Signal the end of transfer.
+ * It's not required to send a signal when the message was
+ * perfectly-aligned (num_channels - 1 channels were used in the last
+ * round) preventing it from signaling twice at the end of transfer.
+ */
+ if (chan != 0) {
+ err = signal_and_wait_for_clear();
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ }
+
+ err = mhu_v2_x_close_transfer(dev);
+ return error_mapping_to_mhu_error_t(err);
+}
+
+/*
+ * Public function. See mhu.h
+ *
+ * The basic steps of receiving a message:
+ * 1. Read the size of the payload from Channel 1. It is the very first
+ * 4 Bytes of the transfer. Continue with Channel 2.
+ * 2. Receive the payload, read the channels one after the other
+ * (4 Bytes each). The last available channel is reserved for controlling
+ * the transfer.
+ * When the last channel is reached clear all the channels
+ * (also sending an acknowledge on the last channel).
+ * 3. If there is still data to receive wait for a notification on the last
+ * channel and jump to step 2 as soon as it arrived. Otherwise, proceed.
+ * 4. End of transfer.
+ *
+ */
+enum mhu_error_t mhu_receive_data(uint8_t *receive_buffer, size_t *size)
+{
+ enum mhu_v2_x_error_t err;
+ struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV;
+ uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev);
+ uint32_t chan = 0;
+ uint32_t message_len;
+ uint32_t i;
+ uint32_t *p;
+
+ /* For simplicity, require:
+ * - the receive_buffer to be 4-byte aligned,
+ * - the buffer size to be a multiple of 4.
+ */
+ if (((uintptr_t)receive_buffer & 0x3U) || (*size & 0x3U)) {
+ return MHU_ERR_INVALID_ARG;
+ }
+
+ /* Busy wait for incoming reply */
+ err = wait_for_signal();
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ /* The first word is the length of the actual message */
+ err = mhu_v2_x_channel_receive(dev, chan, &message_len);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ chan++;
+
+ if (message_len > *size) {
+ /* Message buffer too small */
+ *size = message_len;
+ return MHU_ERR_BUFFER_TOO_SMALL;
+ }
+
+ p = (uint32_t *)receive_buffer;
+ for (i = 0; i < message_len; i += 4) {
+ err = mhu_v2_x_channel_receive(dev, chan, p++);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ /* Only wait for next transfer if there is still missing data */
+ if (++chan == (num_channels - 1) && (message_len - i) > 4) {
+ /* Busy wait for next transfer */
+ err = clear_and_wait_for_next_signal();
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ chan = 0;
+ }
+ }
+
+ /* Clear all channels */
+ for (i = 0; i < num_channels; ++i) {
+ err = mhu_v2_x_channel_clear(dev, i);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ }
+
+ *size = message_len;
+
+ return MHU_ERR_NONE;
+}
+
+size_t mhu_get_max_message_size(void)
+{
+ struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV;
+ uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev);
+
+ assert(num_channels != 0);
+
+ return num_channels * sizeof(uint32_t);
+}
diff --git a/drivers/arm/pl011/aarch32/pl011_console.S b/drivers/arm/pl011/aarch32/pl011_console.S
new file mode 100644
index 0000000..9caeb0c
--- /dev/null
+++ b/drivers/arm/pl011/aarch32/pl011_console.S
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console_macros.S>
+#include <drivers/arm/pl011.h>
+
+ /*
+ * "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_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_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_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_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_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_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_BASE]
+ b console_pl011_core_getc
+endfunc console_pl011_getc
+
+ /* ---------------------------------------------
+ * void 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 : void
+ * Clobber list : r0, r1
+ * ---------------------------------------------
+ */
+func console_pl011_core_flush
+#if ENABLE_ASSERTIONS
+ cmp r0, #0
+ ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
+1:
+ /* Loop while the transmit FIFO is busy */
+ ldr r1, [r0, #UARTFR]
+ tst r1, #PL011_UARTFR_BUSY
+ bne 1b
+
+ bx lr
+endfunc console_pl011_core_flush
+
+ /* ---------------------------------------------
+ * void console_pl011_flush(console_t *console)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * In : r0 - pointer to console_t structure
+ * Out : void
+ * 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_BASE]
+ b console_pl011_core_flush
+endfunc console_pl011_flush
diff --git a/drivers/arm/pl011/aarch64/pl011_console.S b/drivers/arm/pl011/aarch64/pl011_console.S
new file mode 100644
index 0000000..861d2ed
--- /dev/null
+++ b/drivers/arm/pl011/aarch64/pl011_console.S
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console_macros.S>
+#include <drivers/arm/pl011.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_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_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_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_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_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_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_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_BASE]
+ b console_pl011_core_getc
+endfunc console_pl011_getc
+
+ /* ---------------------------------------------
+ * void 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 : void.
+ * 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
+ ret
+endfunc console_pl011_core_flush
+
+ /* ---------------------------------------------
+ * void console_pl011_flush(console_t *console)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * In : x0 - pointer to console_t structure
+ * Out : void
+ * 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_BASE]
+ b console_pl011_core_flush
+endfunc console_pl011_flush
diff --git a/drivers/arm/pl061/pl061_gpio.c b/drivers/arm/pl061/pl061_gpio.c
new file mode 100644
index 0000000..97013e8
--- /dev/null
+++ b/drivers/arm/pl061/pl061_gpio.c
@@ -0,0 +1,142 @@
+/*
+ * 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 <assert.h>
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/arm/pl061_gpio.h>
+#include <drivers/gpio.h>
+#include <lib/cassert.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+
+#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);
+}
diff --git a/drivers/arm/rss/rss_comms.c b/drivers/arm/rss/rss_comms.c
new file mode 100644
index 0000000..5e224e1
--- /dev/null
+++ b/drivers/arm/rss/rss_comms.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/arm/mhu.h>
+#include <drivers/arm/rss_comms.h>
+#include <psa/client.h>
+#include <rss_comms_protocol.h>
+
+/* Union as message space and reply space are never used at the same time, and this saves space as
+ * we can overlap them.
+ */
+union __packed __attribute__((aligned(4))) rss_comms_io_buffer_t {
+ struct serialized_rss_comms_msg_t msg;
+ struct serialized_rss_comms_reply_t reply;
+};
+
+static uint8_t select_protocol_version(const psa_invec *in_vec, size_t in_len,
+ const psa_outvec *out_vec, size_t out_len)
+{
+ size_t comms_mhu_msg_size;
+ size_t comms_embed_msg_min_size;
+ size_t comms_embed_reply_min_size;
+ size_t in_size_total = 0;
+ size_t out_size_total = 0;
+ size_t i;
+
+ for (i = 0U; i < in_len; ++i) {
+ in_size_total += in_vec[i].len;
+ }
+ for (i = 0U; i < out_len; ++i) {
+ out_size_total += out_vec[i].len;
+ }
+
+ comms_mhu_msg_size = mhu_get_max_message_size();
+
+ comms_embed_msg_min_size = sizeof(struct serialized_rss_comms_header_t) +
+ sizeof(struct rss_embed_msg_t) -
+ PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE;
+
+ comms_embed_reply_min_size = sizeof(struct serialized_rss_comms_header_t) +
+ sizeof(struct rss_embed_reply_t) -
+ PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE;
+
+ /* Use embed if we can pack into one message and reply, else use
+ * pointer_access. The underlying MHU transport protocol uses a
+ * single uint32_t to track the length, so the amount of data that
+ * can be in a message is 4 bytes less than mhu_get_max_message_size
+ * reports.
+ *
+ * TODO tune this with real performance numbers, it's possible a
+ * pointer_access message is less performant than multiple embed
+ * messages due to ATU configuration costs to allow access to the
+ * pointers.
+ */
+ if ((comms_embed_msg_min_size + in_size_total > comms_mhu_msg_size - sizeof(uint32_t))
+ || (comms_embed_reply_min_size + out_size_total > comms_mhu_msg_size) - sizeof(uint32_t)) {
+ return RSS_COMMS_PROTOCOL_POINTER_ACCESS;
+ } else {
+ return RSS_COMMS_PROTOCOL_EMBED;
+ }
+}
+
+psa_status_t psa_call(psa_handle_t handle, int32_t type, const psa_invec *in_vec, size_t in_len,
+ psa_outvec *out_vec, size_t out_len)
+{
+ /* Declared statically to avoid using huge amounts of stack space. Maybe revisit if
+ * functions not being reentrant becomes a problem.
+ */
+ static union rss_comms_io_buffer_t io_buf;
+ enum mhu_error_t err;
+ psa_status_t status;
+ static uint8_t seq_num = 1U;
+ size_t msg_size;
+ size_t reply_size = sizeof(io_buf.reply);
+ psa_status_t return_val;
+ size_t idx;
+
+ if (type > INT16_MAX || type < INT16_MIN || in_len > PSA_MAX_IOVEC
+ || out_len > PSA_MAX_IOVEC) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ io_buf.msg.header.seq_num = seq_num,
+ /* No need to distinguish callers (currently concurrent calls are not supported). */
+ io_buf.msg.header.client_id = 1U,
+ io_buf.msg.header.protocol_ver = select_protocol_version(in_vec, in_len, out_vec, out_len);
+
+ status = rss_protocol_serialize_msg(handle, type, in_vec, in_len, out_vec,
+ out_len, &io_buf.msg, &msg_size);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ VERBOSE("[RSS-COMMS] Sending message\n");
+ VERBOSE("protocol_ver=%u\n", io_buf.msg.header.protocol_ver);
+ VERBOSE("seq_num=%u\n", io_buf.msg.header.seq_num);
+ VERBOSE("client_id=%u\n", io_buf.msg.header.client_id);
+ for (idx = 0; idx < in_len; idx++) {
+ VERBOSE("in_vec[%lu].len=%lu\n", idx, in_vec[idx].len);
+ VERBOSE("in_vec[%lu].buf=%p\n", idx, (void *)in_vec[idx].base);
+ }
+
+ err = mhu_send_data((uint8_t *)&io_buf.msg, msg_size);
+ if (err != MHU_ERR_NONE) {
+ return PSA_ERROR_COMMUNICATION_FAILURE;
+ }
+
+#if DEBUG
+ /*
+ * Poisoning the message buffer (with a known pattern).
+ * Helps in detecting hypothetical RSS communication bugs.
+ */
+ memset(&io_buf.msg, 0xA5, msg_size);
+#endif
+
+ err = mhu_receive_data((uint8_t *)&io_buf.reply, &reply_size);
+ if (err != MHU_ERR_NONE) {
+ return PSA_ERROR_COMMUNICATION_FAILURE;
+ }
+
+ VERBOSE("[RSS-COMMS] Received reply\n");
+ VERBOSE("protocol_ver=%u\n", io_buf.reply.header.protocol_ver);
+ VERBOSE("seq_num=%u\n", io_buf.reply.header.seq_num);
+ VERBOSE("client_id=%u\n", io_buf.reply.header.client_id);
+
+ status = rss_protocol_deserialize_reply(out_vec, out_len, &return_val,
+ &io_buf.reply, reply_size);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ VERBOSE("return_val=%d\n", return_val);
+ for (idx = 0U; idx < out_len; idx++) {
+ VERBOSE("out_vec[%lu].len=%lu\n", idx, out_vec[idx].len);
+ VERBOSE("out_vec[%lu].buf=%p\n", idx, (void *)out_vec[idx].base);
+ }
+
+ /* Clear the MHU message buffer to remove assets from memory */
+ memset(&io_buf, 0x0, sizeof(io_buf));
+
+ seq_num++;
+
+ return return_val;
+}
+
+int rss_comms_init(uintptr_t mhu_sender_base, uintptr_t mhu_receiver_base)
+{
+ enum mhu_error_t err;
+
+ err = mhu_init_sender(mhu_sender_base);
+ if (err != MHU_ERR_NONE) {
+ ERROR("[RSS-COMMS] Host to RSS MHU driver initialization failed: %d\n", err);
+ return -1;
+ }
+
+ err = mhu_init_receiver(mhu_receiver_base);
+ if (err != MHU_ERR_NONE) {
+ ERROR("[RSS-COMMS] RSS to Host MHU driver initialization failed: %d\n", err);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/drivers/arm/rss/rss_comms.mk b/drivers/arm/rss/rss_comms.mk
new file mode 100644
index 0000000..c1c994b
--- /dev/null
+++ b/drivers/arm/rss/rss_comms.mk
@@ -0,0 +1,22 @@
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+$(warning "RSS driver is an experimental feature")
+
+RSS_COMMS_SOURCES := $(addprefix drivers/arm/rss/, \
+ rss_comms.c \
+ rss_comms_protocol.c \
+ rss_comms_protocol_embed.c \
+ rss_comms_protocol_pointer_access.c \
+ )
+
+RSS_COMMS_SOURCES += $(addprefix drivers/arm/mhu/, \
+ mhu_v2_x.c \
+ mhu_wrapper_v2_x.c \
+ )
+
+PLAT_INCLUDES += -Idrivers/arm/rss \
+ -Idrivers/arm/mhu
diff --git a/drivers/arm/rss/rss_comms_protocol.c b/drivers/arm/rss/rss_comms_protocol.c
new file mode 100644
index 0000000..a1b1b58
--- /dev/null
+++ b/drivers/arm/rss/rss_comms_protocol.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <assert.h>
+
+#include <common/debug.h>
+#include "rss_comms_protocol.h"
+
+psa_status_t rss_protocol_serialize_msg(psa_handle_t handle,
+ int16_t type,
+ const psa_invec *in_vec,
+ uint8_t in_len,
+ const psa_outvec *out_vec,
+ uint8_t out_len,
+ struct serialized_rss_comms_msg_t *msg,
+ size_t *msg_len)
+{
+ psa_status_t status;
+
+ assert(msg != NULL);
+ assert(msg_len != NULL);
+ assert(in_vec != NULL);
+
+ switch (msg->header.protocol_ver) {
+ case RSS_COMMS_PROTOCOL_EMBED:
+ status = rss_protocol_embed_serialize_msg(handle, type, in_vec, in_len, out_vec,
+ out_len, &msg->msg.embed, msg_len);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ break;
+ case RSS_COMMS_PROTOCOL_POINTER_ACCESS:
+ status = rss_protocol_pointer_access_serialize_msg(handle, type, in_vec, in_len,
+ out_vec, out_len,
+ &msg->msg.pointer_access,
+ msg_len);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ break;
+ default:
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ *msg_len += sizeof(struct serialized_rss_comms_header_t);
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t rss_protocol_deserialize_reply(psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct serialized_rss_comms_reply_t *reply,
+ size_t reply_size)
+{
+ assert(reply != NULL);
+ assert(return_val != NULL);
+
+ switch (reply->header.protocol_ver) {
+ case RSS_COMMS_PROTOCOL_EMBED:
+ return rss_protocol_embed_deserialize_reply(out_vec, out_len, return_val,
+ &reply->reply.embed, reply_size);
+ case RSS_COMMS_PROTOCOL_POINTER_ACCESS:
+ return rss_protocol_pointer_access_deserialize_reply(out_vec, out_len, return_val,
+ &reply->reply.pointer_access,
+ reply_size);
+ default:
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ return PSA_SUCCESS;
+}
diff --git a/drivers/arm/rss/rss_comms_protocol.h b/drivers/arm/rss/rss_comms_protocol.h
new file mode 100644
index 0000000..9a38057
--- /dev/null
+++ b/drivers/arm/rss/rss_comms_protocol.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __RSS_COMMS_PROTOCOL_H__
+#define __RSS_COMMS_PROTOCOL_H__
+
+#include <cdefs.h>
+#include <stdint.h>
+
+#include <psa/client.h>
+#include "rss_comms_protocol_embed.h"
+#include "rss_comms_protocol_pointer_access.h"
+
+enum rss_comms_protocol_version_t {
+ RSS_COMMS_PROTOCOL_EMBED = 0,
+ RSS_COMMS_PROTOCOL_POINTER_ACCESS = 1,
+};
+
+struct __packed serialized_rss_comms_header_t {
+ uint8_t protocol_ver;
+ uint8_t seq_num;
+ uint16_t client_id;
+};
+
+/* MHU message passed from Host to RSS to deliver a PSA client call */
+struct __packed serialized_rss_comms_msg_t {
+ struct serialized_rss_comms_header_t header;
+ union __packed {
+ struct rss_embed_msg_t embed;
+ struct rss_pointer_access_msg_t pointer_access;
+ } msg;
+};
+
+/* MHU reply message to hold the PSA client reply result returned by RSS */
+struct __packed serialized_rss_comms_reply_t {
+ struct serialized_rss_comms_header_t header;
+ union __packed {
+ struct rss_embed_reply_t embed;
+ struct rss_pointer_access_reply_t pointer_access;
+ } reply;
+};
+
+/* in_len and out_len are uint8_ts, therefore if there are more than 255 iovecs
+ * an error may occur.
+ */
+CASSERT(PSA_MAX_IOVEC <= UINT8_MAX, assert_rss_comms_max_iovec_too_large);
+
+psa_status_t rss_protocol_serialize_msg(psa_handle_t handle,
+ int16_t type,
+ const psa_invec *in_vec,
+ uint8_t in_len,
+ const psa_outvec *out_vec,
+ uint8_t out_len,
+ struct serialized_rss_comms_msg_t *msg,
+ size_t *msg_len);
+
+psa_status_t rss_protocol_deserialize_reply(psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct serialized_rss_comms_reply_t *reply,
+ size_t reply_size);
+
+#endif /* __RSS_COMMS_PROTOCOL_H__ */
diff --git a/drivers/arm/rss/rss_comms_protocol_embed.c b/drivers/arm/rss/rss_comms_protocol_embed.c
new file mode 100644
index 0000000..801b7cc
--- /dev/null
+++ b/drivers/arm/rss/rss_comms_protocol_embed.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include "rss_comms_protocol_embed.h"
+
+#define TYPE_OFFSET (16U)
+#define TYPE_MASK (0xFFFFUL << TYPE_OFFSET)
+#define IN_LEN_OFFSET (8U)
+#define IN_LEN_MASK (0xFFUL << IN_LEN_OFFSET)
+#define OUT_LEN_OFFSET (0U)
+#define OUT_LEN_MASK (0xFFUL << OUT_LEN_OFFSET)
+
+#define PARAM_PACK(type, in_len, out_len) \
+ (((((uint32_t)type) << TYPE_OFFSET) & TYPE_MASK) | \
+ ((((uint32_t)in_len) << IN_LEN_OFFSET) & IN_LEN_MASK) | \
+ ((((uint32_t)out_len) << OUT_LEN_OFFSET) & OUT_LEN_MASK))
+
+psa_status_t rss_protocol_embed_serialize_msg(psa_handle_t handle,
+ int16_t type,
+ const psa_invec *in_vec,
+ uint8_t in_len,
+ const psa_outvec *out_vec,
+ uint8_t out_len,
+ struct rss_embed_msg_t *msg,
+ size_t *msg_len)
+{
+ uint32_t payload_size = 0;
+ uint32_t i;
+
+ assert(msg != NULL);
+ assert(msg_len != NULL);
+ assert(in_vec != NULL);
+
+ msg->ctrl_param = PARAM_PACK(type, in_len, out_len);
+ msg->handle = handle;
+
+ /* Fill msg iovec lengths */
+ for (i = 0U; i < in_len; ++i) {
+ msg->io_size[i] = in_vec[i].len;
+ }
+ for (i = 0U; i < out_len; ++i) {
+ msg->io_size[in_len + i] = out_vec[i].len;
+ }
+
+ for (i = 0U; i < in_len; ++i) {
+ if (in_vec[i].len > sizeof(msg->trailer) - payload_size) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ memcpy(msg->trailer + payload_size, in_vec[i].base, in_vec[i].len);
+ payload_size += in_vec[i].len;
+ }
+
+ /* Output the actual size of the message, to optimize sending */
+ *msg_len = sizeof(*msg) - sizeof(msg->trailer) + payload_size;
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t rss_protocol_embed_deserialize_reply(psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct rss_embed_reply_t *reply,
+ size_t reply_size)
+{
+ uint32_t payload_offset = 0;
+ uint32_t i;
+
+ assert(reply != NULL);
+ assert(return_val != NULL);
+
+ for (i = 0U; i < out_len; ++i) {
+ if (sizeof(reply) - sizeof(reply->trailer) + payload_offset > reply_size) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ memcpy(out_vec[i].base, reply->trailer + payload_offset, out_vec[i].len);
+ payload_offset += out_vec[i].len;
+ }
+
+ *return_val = reply->return_val;
+
+ return PSA_SUCCESS;
+}
diff --git a/drivers/arm/rss/rss_comms_protocol_embed.h b/drivers/arm/rss/rss_comms_protocol_embed.h
new file mode 100644
index 0000000..c81c795
--- /dev/null
+++ b/drivers/arm/rss/rss_comms_protocol_embed.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __RSS_COMMS_PROTOCOL_EMBED_H__
+#define __RSS_COMMS_PROTOCOL_EMBED_H__
+
+#include <cdefs.h>
+
+#include <psa/client.h>
+
+#include <platform_def.h>
+
+
+
+struct __packed rss_embed_msg_t {
+ psa_handle_t handle;
+ uint32_t ctrl_param; /* type, in_len, out_len */
+ uint16_t io_size[PSA_MAX_IOVEC];
+ uint8_t trailer[PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE];
+};
+
+struct __packed rss_embed_reply_t {
+ int32_t return_val;
+ uint16_t out_size[PSA_MAX_IOVEC];
+ uint8_t trailer[PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE];
+};
+
+psa_status_t rss_protocol_embed_serialize_msg(psa_handle_t handle,
+ int16_t type,
+ const psa_invec *in_vec,
+ uint8_t in_len,
+ const psa_outvec *out_vec,
+ uint8_t out_len,
+ struct rss_embed_msg_t *msg,
+ size_t *msg_len);
+
+psa_status_t rss_protocol_embed_deserialize_reply(psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct rss_embed_reply_t *reply,
+ size_t reply_size);
+
+#endif /* __RSS_COMMS_PROTOCOL_EMBED_H__ */
diff --git a/drivers/arm/rss/rss_comms_protocol_pointer_access.c b/drivers/arm/rss/rss_comms_protocol_pointer_access.c
new file mode 100644
index 0000000..5007b9d
--- /dev/null
+++ b/drivers/arm/rss/rss_comms_protocol_pointer_access.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <assert.h>
+
+#include "rss_comms_protocol_pointer_access.h"
+
+#define TYPE_OFFSET (16U)
+#define TYPE_MASK (0xFFFFUL << TYPE_OFFSET)
+#define IN_LEN_OFFSET (8U)
+#define IN_LEN_MASK (0xFFUL << IN_LEN_OFFSET)
+#define OUT_LEN_OFFSET (0U)
+#define OUT_LEN_MASK (0xFFUL << OUT_LEN_OFFSET)
+
+#define PARAM_PACK(type, in_len, out_len) \
+ (((((uint32_t)type) << TYPE_OFFSET) & TYPE_MASK) | \
+ ((((uint32_t)in_len) << IN_LEN_OFFSET) & IN_LEN_MASK) | \
+ ((((uint32_t)out_len) << OUT_LEN_OFFSET) & OUT_LEN_MASK))
+
+psa_status_t rss_protocol_pointer_access_serialize_msg(psa_handle_t handle,
+ int16_t type,
+ const psa_invec *in_vec,
+ uint8_t in_len,
+ const psa_outvec *out_vec,
+ uint8_t out_len,
+ struct rss_pointer_access_msg_t *msg,
+ size_t *msg_len)
+{
+ unsigned int i;
+
+ assert(msg != NULL);
+ assert(msg_len != NULL);
+ assert(in_vec != NULL);
+
+ msg->ctrl_param = PARAM_PACK(type, in_len, out_len);
+ msg->handle = handle;
+
+ /* Fill msg iovec lengths */
+ for (i = 0U; i < in_len; ++i) {
+ msg->io_sizes[i] = in_vec[i].len;
+ msg->host_ptrs[i] = (uint64_t)in_vec[i].base;
+ }
+ for (i = 0U; i < out_len; ++i) {
+ msg->io_sizes[in_len + i] = out_vec[i].len;
+ msg->host_ptrs[in_len + i] = (uint64_t)out_vec[i].base;
+ }
+
+ *msg_len = sizeof(*msg);
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t rss_protocol_pointer_access_deserialize_reply(psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct rss_pointer_access_reply_t *reply,
+ size_t reply_size)
+{
+ unsigned int i;
+
+ assert(reply != NULL);
+ assert(return_val != NULL);
+
+ for (i = 0U; i < out_len; ++i) {
+ out_vec[i].len = reply->out_sizes[i];
+ }
+
+ *return_val = reply->return_val;
+
+ return PSA_SUCCESS;
+}
diff --git a/drivers/arm/rss/rss_comms_protocol_pointer_access.h b/drivers/arm/rss/rss_comms_protocol_pointer_access.h
new file mode 100644
index 0000000..a4d054b
--- /dev/null
+++ b/drivers/arm/rss/rss_comms_protocol_pointer_access.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __RSS_COMMS_PROTOCOL_POINTER_ACCESS_H__
+#define __RSS_COMMS_PROTOCOL_POINTER_ACCESS_H__
+
+#include <cdefs.h>
+
+#include <psa/client.h>
+
+struct __packed rss_pointer_access_msg_t {
+ psa_handle_t handle;
+ uint32_t ctrl_param;
+ uint32_t io_sizes[PSA_MAX_IOVEC];
+ uint64_t host_ptrs[PSA_MAX_IOVEC];
+};
+
+struct __packed rss_pointer_access_reply_t {
+ int32_t return_val;
+ uint32_t out_sizes[PSA_MAX_IOVEC];
+};
+
+psa_status_t rss_protocol_pointer_access_serialize_msg(psa_handle_t handle,
+ int16_t type,
+ const psa_invec *in_vec,
+ uint8_t in_len,
+ const psa_outvec *out_vec,
+ uint8_t out_len,
+ struct rss_pointer_access_msg_t *msg,
+ size_t *msg_len);
+
+psa_status_t rss_protocol_pointer_access_deserialize_reply(psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct rss_pointer_access_reply_t *reply,
+ size_t reply_size);
+
+#endif /* __RSS_COMMS_PROTOCOL_POINTER_ACCESS_H__ */
diff --git a/drivers/arm/sbsa/sbsa.c b/drivers/arm/sbsa/sbsa.c
new file mode 100644
index 0000000..79c6f26
--- /dev/null
+++ b/drivers/arm/sbsa/sbsa.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <drivers/arm/sbsa.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+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));
+}
diff --git a/drivers/arm/scu/scu.c b/drivers/arm/scu/scu.c
new file mode 100644
index 0000000..aceac92
--- /dev/null
+++ b/drivers/arm/scu/scu.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <drivers/arm/scu.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <stdint.h>
+
+/*******************************************************************************
+ * Turn ON snoop control unit. This is needed to synchronize the data between
+ * CPU's.
+ ******************************************************************************/
+void enable_snoop_ctrl_unit(uintptr_t base)
+{
+ uint32_t scu_ctrl;
+
+ INFO("[SCU]: enabling snoop control unit ... \n");
+
+ assert(base != 0U);
+ scu_ctrl = mmio_read_32(base + SCU_CTRL_REG);
+
+ /* already enabled? */
+ if ((scu_ctrl & SCU_ENABLE_BIT) != 0) {
+ return;
+ }
+
+ scu_ctrl |= SCU_ENABLE_BIT;
+ mmio_write_32(base + SCU_CTRL_REG, scu_ctrl);
+}
+
+/*******************************************************************************
+ * Snoop Control Unit configuration register. This is read-only register and
+ * contains information such as
+ * - number of CPUs present
+ * - is a particular CPU operating in SMP mode or AMP mode
+ * - data cache size of a particular CPU
+ * - does SCU has ACP port
+ * - is L2CPRESENT
+ * NOTE: user of this API should interpert the bits in this register according
+ * to the TRM
+ ******************************************************************************/
+uint32_t read_snoop_ctrl_unit_cfg(uintptr_t base)
+{
+ assert(base != 0U);
+
+ return mmio_read_32(base + SCU_CFG_REG);
+}
diff --git a/drivers/arm/smmu/smmu_v3.c b/drivers/arm/smmu/smmu_v3.c
new file mode 100644
index 0000000..6c6f978
--- /dev/null
+++ b/drivers/arm/smmu/smmu_v3.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <cdefs.h>
+#include <drivers/arm/smmu_v3.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <arch_features.h>
+
+/* SMMU poll number of retries */
+#define SMMU_POLL_TIMEOUT_US U(1000)
+
+static int smmuv3_poll(uintptr_t smmu_reg, uint32_t mask,
+ uint32_t value)
+{
+ uint32_t reg_val;
+ uint64_t timeout;
+
+ /* Set 1ms timeout value */
+ timeout = timeout_init_us(SMMU_POLL_TIMEOUT_US);
+ do {
+ reg_val = mmio_read_32(smmu_reg);
+ if ((reg_val & mask) == value)
+ return 0;
+ } while (!timeout_elapsed(timeout));
+
+ ERROR("Timeout polling 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;
+
+#if ENABLE_RME
+
+ if (get_armv9_2_feat_rme_support() != 0U) {
+ if ((mmio_read_32(smmu_base + SMMU_ROOT_IDR0) &
+ SMMU_ROOT_IDR0_ROOT_IMPL) == 0U) {
+ WARN("Skip SMMU GPC configuration.\n");
+ } else {
+ uint64_t gpccr_el3 = read_gpccr_el3();
+ uint64_t gptbr_el3 = read_gptbr_el3();
+
+ /* SMMU_ROOT_GPT_BASE_CFG[16] is RES0. */
+ gpccr_el3 &= ~(1UL << 16);
+
+ /*
+ * TODO: SMMU_ROOT_GPT_BASE_CFG is 64b in the spec,
+ * but SMMU model only accepts 32b access.
+ */
+ mmio_write_32(smmu_base + SMMU_ROOT_GPT_BASE_CFG,
+ gpccr_el3);
+
+ /*
+ * pa_gpt_table_base[51:12] maps to GPTBR_EL3[39:0]
+ * whereas it maps to SMMU_ROOT_GPT_BASE[51:12]
+ * hence needs a 12 bit left shit.
+ */
+ mmio_write_64(smmu_base + SMMU_ROOT_GPT_BASE,
+ gptbr_el3 << 12);
+
+ /*
+ * ACCESSEN=1: SMMU- and client-originated accesses are
+ * not terminated by this mechanism.
+ * GPCEN=1: All clients and SMMU-originated accesses,
+ * except GPT-walks, are subject to GPC.
+ */
+ mmio_setbits_32(smmu_base + SMMU_ROOT_CR0,
+ SMMU_ROOT_CR0_GPCEN |
+ SMMU_ROOT_CR0_ACCESSEN);
+
+ /* Poll for ACCESSEN and GPCEN ack bits. */
+ if (smmuv3_poll(smmu_base + SMMU_ROOT_CR0ACK,
+ SMMU_ROOT_CR0_GPCEN |
+ SMMU_ROOT_CR0_ACCESSEN,
+ SMMU_ROOT_CR0_GPCEN |
+ SMMU_ROOT_CR0_ACCESSEN) != 0) {
+ WARN("Failed enabling SMMU GPC.\n");
+
+ /*
+ * Do not return in error, but fall back to
+ * invalidating all entries through the secure
+ * register file.
+ */
+ }
+ }
+ }
+
+#endif /* ENABLE_RME */
+
+ /*
+ * 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.
+ * Arm SMMU Arch RME supplement, section 3.4: all SMMU registers
+ * specified to be accessible only in secure physical address space are
+ * additionally accessible in root physical address space in an SMMU
+ * with RME.
+ * Section 3.3: as GPT information is permitted to be cached in a TLB,
+ * the SMMU_S_INIT.INV_ALL mechanism also invalidates GPT information
+ * cached in TLBs.
+ */
+ 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);
+}
+
+int smmuv3_ns_set_abort_all(uintptr_t smmu_base)
+{
+ /* Attribute update has completed when SMMU_GBPA.Update bit is 0 */
+ if (smmuv3_poll(smmu_base + SMMU_GBPA, SMMU_GBPA_UPDATE, 0U) != 0U) {
+ return -1;
+ }
+
+ /*
+ * Set GBPA's ABORT bit. Other GBPA fields are presumably ignored then,
+ * so simply preserve their value.
+ */
+ 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;
+ }
+
+ /* Disable the SMMU to engage the GBPA fields previously configured. */
+ mmio_clrbits_32(smmu_base + SMMU_CR0, SMMU_CR0_SMMUEN);
+ if (smmuv3_poll(smmu_base + SMMU_CR0ACK, SMMU_CR0_SMMUEN, 0U) != 0U) {
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/drivers/arm/sp804/sp804_delay_timer.c b/drivers/arm/sp804/sp804_delay_timer.c
new file mode 100644
index 0000000..9c5e762
--- /dev/null
+++ b/drivers/arm/sp804/sp804_delay_timer.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <drivers/arm/sp804_delay_timer.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+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);
+}
diff --git a/drivers/arm/sp805/sp805.c b/drivers/arm/sp805/sp805.c
new file mode 100644
index 0000000..ffca1ce
--- /dev/null
+++ b/drivers/arm/sp805/sp805.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <drivers/arm/sp805.h>
+#include <lib/mmio.h>
+
+/* 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);
+}
diff --git a/drivers/arm/tzc/tzc380.c b/drivers/arm/tzc/tzc380.c
new file mode 100644
index 0000000..9518748
--- /dev/null
+++ b/drivers/arm/tzc/tzc380.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+
+#include <common/debug.h>
+#include <drivers/arm/tzc380.h>
+#include <lib/mmio.h>
+
+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);
+}
diff --git a/drivers/arm/tzc/tzc400.c b/drivers/arm/tzc/tzc400.c
new file mode 100644
index 0000000..759824d
--- /dev/null
+++ b/drivers/arm/tzc/tzc400.c
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+
+#include <common/debug.h>
+#include <drivers/arm/tzc400.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#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_UPDATE_FILTERS(400, 400)
+DEFINE_TZC_COMMON_CONFIGURE_REGION0(400)
+DEFINE_TZC_COMMON_CONFIGURE_REGION(400)
+
+static void _tzc400_clear_it(uintptr_t base, uint32_t filter)
+{
+ mmio_write_32(base + INT_CLEAR, BIT_32(filter));
+}
+
+static uint32_t _tzc400_get_int_by_filter(uintptr_t base, uint32_t filter)
+{
+ return mmio_read_32(base + INT_STATUS) & BIT_32(filter);
+}
+
+#if DEBUG
+static unsigned long _tzc400_get_fail_address(uintptr_t base, uint32_t filter)
+{
+ unsigned long fail_address;
+
+ fail_address = mmio_read_32(base + FAIL_ADDRESS_LOW_OFF +
+ (filter * FILTER_OFFSET));
+#ifdef __aarch64__
+ fail_address += (unsigned long)mmio_read_32(base + FAIL_ADDRESS_HIGH_OFF +
+ (filter * FILTER_OFFSET)) << 32;
+#endif
+
+ return fail_address;
+}
+
+static uint32_t _tzc400_get_fail_id(uintptr_t base, uint32_t filter)
+{
+ return mmio_read_32(base + FAIL_ID + (filter * FILTER_OFFSET));
+}
+
+static uint32_t _tzc400_get_fail_control(uintptr_t base, uint32_t filter)
+{
+ return mmio_read_32(base + FAIL_CONTROL_OFF + (filter * FILTER_OFFSET));
+}
+
+static void _tzc400_dump_fail_filter(uintptr_t base, uint32_t filter)
+{
+ uint32_t control_fail;
+ uint32_t fail_id;
+ unsigned long address_fail;
+
+ address_fail = _tzc400_get_fail_address(base, filter);
+ ERROR("Illegal access to 0x%lx:\n", address_fail);
+
+ fail_id = _tzc400_get_fail_id(base, filter);
+ ERROR("\tFAIL_ID = 0x%x\n", fail_id);
+
+ control_fail = _tzc400_get_fail_control(base, filter);
+ if (((control_fail & BIT_32(FAIL_CONTROL_NS_SHIFT)) >> FAIL_CONTROL_NS_SHIFT) ==
+ FAIL_CONTROL_NS_NONSECURE) {
+ ERROR("\tNon-Secure\n");
+ } else {
+ ERROR("\tSecure\n");
+ }
+
+ if (((control_fail & BIT_32(FAIL_CONTROL_PRIV_SHIFT)) >> FAIL_CONTROL_PRIV_SHIFT) ==
+ FAIL_CONTROL_PRIV_PRIV) {
+ ERROR("\tPrivilege\n");
+ } else {
+ ERROR("\tUnprivilege\n");
+ }
+
+ if (((control_fail & BIT_32(FAIL_CONTROL_DIR_SHIFT)) >> FAIL_CONTROL_DIR_SHIFT) ==
+ FAIL_CONTROL_DIR_WRITE) {
+ ERROR("\tWrite\n");
+ } else {
+ ERROR("\tRead\n");
+ }
+}
+#endif /* DEBUG */
+
+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 |= (1UL << filter);
+ else
+ open_status &= ~(1UL << 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);
+
+ _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), except that
+ * the value TZC_400_REGION_ATTR_FILTER_BIT_ALL selects all filters, based on
+ * the value of tzc400.num_filters.
+ * 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);
+
+ /* Adjust filter mask by real filter number */
+ if (filters == TZC_400_REGION_ATTR_FILTER_BIT_ALL) {
+ filters = (1U << tzc400.num_filters) - 1U;
+ }
+
+ /* 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_update_filters(unsigned int region, unsigned int filters)
+{
+ /* Do range checks on filters and regions. */
+ assert(((filters >> tzc400.num_filters) == 0U) &&
+ (region < tzc400.num_regions));
+
+ _tzc400_update_filters(tzc400.base, region, tzc400.num_filters, filters);
+}
+
+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) {
+ /* Filter 0 is special and cannot be disabled.
+ * So here we allow it being already enabled. */
+ if (filter == 0U) {
+ continue;
+ }
+ /*
+ * 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 %u Gatekeeper already enabled.\n",
+ filter);
+ panic();
+ }
+ _tzc400_set_gate_keeper(tzc400.base, filter, 1);
+ }
+}
+
+void tzc400_disable_filters(void)
+{
+ unsigned int filter;
+ unsigned int state;
+ unsigned int start = 0U;
+
+ assert(tzc400.base != 0U);
+
+ /* Filter 0 is special and cannot be disabled. */
+ state = _tzc400_get_gate_keeper(tzc400.base, 0);
+ if (state != 0U) {
+ start++;
+ }
+ for (filter = start; filter < tzc400.num_filters; filter++)
+ _tzc400_set_gate_keeper(tzc400.base, filter, 0);
+}
+
+int tzc400_it_handler(void)
+{
+ uint32_t filter;
+ uint32_t filter_it_pending = tzc400.num_filters;
+
+ assert(tzc400.base != 0U);
+
+ for (filter = 0U; filter < tzc400.num_filters; filter++) {
+ if (_tzc400_get_int_by_filter(tzc400.base, filter) != 0U) {
+ filter_it_pending = filter;
+ break;
+ }
+ }
+
+ if (filter_it_pending == tzc400.num_filters) {
+ ERROR("TZC-400: No interrupt pending!\n");
+ return -1;
+ }
+
+#if DEBUG
+ _tzc400_dump_fail_filter(tzc400.base, filter_it_pending);
+#endif
+
+ _tzc400_clear_it(tzc400.base, filter_it_pending);
+
+ return 0;
+}
diff --git a/drivers/arm/tzc/tzc_common_private.h b/drivers/arm/tzc/tzc_common_private.h
new file mode 100644
index 0000000..2090944
--- /dev/null
+++ b/drivers/arm/tzc/tzc_common_private.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TZC_COMMON_PRIVATE_H
+#define TZC_COMMON_PRIVATE_H
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <drivers/arm/tzc_common.h>
+#include <lib/mmio.h>
+
+#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, \
+ (u_register_t)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, \
+ (u_register_t)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, \
+ (u_register_t)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, \
+ (u_register_t)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, \
+ (u_register_t)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, \
+ (u_register_t)region_no) + \
+ TZC_##macro_name##_REGION_ID_ACCESS_0_OFFSET, \
+ val); \
+ }
+
+/*
+ * It is used to modify the filters status for a defined region.
+ */
+#define DEFINE_TZC_COMMON_UPDATE_FILTERS(fn_name, macro_name) \
+ static inline void _tzc##fn_name##_update_filters( \
+ uintptr_t base, \
+ unsigned int region_no, \
+ unsigned int nbfilters, \
+ unsigned int filters) \
+ { \
+ uint32_t filters_mask = GENMASK(nbfilters - 1U, 0); \
+ \
+ mmio_clrsetbits_32(base + \
+ TZC_REGION_OFFSET( \
+ TZC_##macro_name##_REGION_SIZE, \
+ region_no) + \
+ TZC_##macro_name##_REGION_ATTR_0_OFFSET, \
+ filters_mask << TZC_REGION_ATTR_F_EN_SHIFT, \
+ filters << TZC_REGION_ATTR_F_EN_SHIFT); \
+ }
+
+/*
+ * 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 */
diff --git a/drivers/arm/tzc/tzc_dmc500.c b/drivers/arm/tzc/tzc_dmc500.c
new file mode 100644
index 0000000..e45fbf8
--- /dev/null
+++ b/drivers/arm/tzc/tzc_dmc500.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/arm/tzc_dmc500.h>
+#include <drivers/arm/tzc_common.h>
+#include <lib/mmio.h>
+
+#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;
+}
diff --git a/drivers/arm/tzc/tzc_dmc620.c b/drivers/arm/tzc/tzc_dmc620.c
new file mode 100644
index 0000000..7e307ee
--- /dev/null
+++ b/drivers/arm/tzc/tzc_dmc620.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/arm/tzc_dmc620.h>
+#include <lib/mmio.h>
+
+/* 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)
+{
+ unsigned int dmc_inst, dmc_count, 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;
+ unsigned int 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 >= 0) && (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 = (uint32_t)((region_base & MASK_31_16) | sec_attr);
+ min_47_32 = (uint32_t)((region_base & MASK_47_32)
+ >> DMC620_ACC_ADDR_WIDTH);
+ max_31_00 = (uint32_t)(region_top & MASK_31_16);
+ max_47_32 = (uint32_t)((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)
+{
+ unsigned int 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)
+{
+ unsigned int 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)
+{
+ uint8_t 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");
+}
diff --git a/drivers/auth/auth_mod.c b/drivers/auth/auth_mod.c
new file mode 100644
index 0000000..fa9509a
--- /dev/null
+++ b/drivers/auth/auth_mod.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <common/tbbr/cot_def.h>
+#include <drivers/auth/auth_common.h>
+#include <drivers/auth/auth_mod.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/auth/img_parser_mod.h>
+#include <drivers/fwu/fwu.h>
+#include <lib/fconf/fconf_tbbr_getter.h>
+#include <plat/common/platform.h>
+
+/* 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
+#pragma weak plat_convert_pk
+
+
+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 {
+ /* platform may store the hash of a prefixed, suffixed or modified pk */
+ rc = plat_convert_pk(pk_ptr, pk_len, &pk_ptr, &pk_len);
+ return_if_error(rc);
+
+ /* 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
+ * (provided it has been authenticated).
+ *
+ * Return: 0 = success, Otherwise = error
+ * Returns additionally,
+ * cert_nv_ctr -> NV counter value present in the certificate
+ * need_nv_ctr_upgrade = 0 -> platform NV counter upgrade is not needed
+ * need_nv_ctr_upgrade = 1 -> platform NV counter upgrade is needed
+ */
+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,
+ unsigned int *cert_nv_ctr,
+ bool *need_nv_ctr_upgrade)
+{
+ char *p;
+ void *data_ptr = NULL;
+ unsigned int data_len, len, i;
+ unsigned int plat_nv_ctr;
+ int rc = 0;
+ bool is_trial_run = false;
+
+ /* 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) {
+#if PSA_FWU_SUPPORT && IMAGE_BL2
+ is_trial_run = fwu_is_trial_run_state();
+#endif /* PSA_FWU_SUPPORT && IMAGE_BL2 */
+ *need_nv_ctr_upgrade = !is_trial_run;
+ }
+
+ 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);
+}
+
+int plat_convert_pk(void *full_pk_ptr, unsigned int full_pk_len,
+ void **hashed_pk_ptr, unsigned int *hashed_pk_len)
+{
+ *hashed_pk_ptr = full_pk_ptr;
+ *hashed_pk_len = full_pk_len;
+
+ return 0;
+}
+
+/*
+ * 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 = FCONF_GET_PROPERTY(tbbr, cot, 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);
+
+ /* 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;
+ unsigned int cert_nv_ctr = 0;
+ bool need_nv_ctr_upgrade = false;
+ bool sig_auth_done = false;
+ const auth_method_param_nv_ctr_t *nv_ctr_param = NULL;
+
+ /* Get the image descriptor from the chain of trust */
+ img_desc = FCONF_GET_PROPERTY(tbbr, cot, 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);
+ sig_auth_done = true;
+ break;
+ case AUTH_METHOD_NV_CTR:
+ nv_ctr_param = &auth_method->param.nv_ctr;
+ rc = auth_nvctr(nv_ctr_param,
+ img_desc, img_ptr, img_len,
+ &cert_nv_ctr, &need_nv_ctr_upgrade);
+ break;
+ default:
+ /* Unknown authentication method */
+ rc = 1;
+ break;
+ }
+ return_if_error(rc);
+ }
+
+ /*
+ * Do platform NV counter upgrade only if the certificate gets
+ * authenticated, and platform NV-counter upgrade is needed.
+ */
+ if (need_nv_ctr_upgrade && sig_auth_done) {
+ rc = plat_set_nv_ctr2(nv_ctr_param->plat_nv_ctr->cookie,
+ img_desc, cert_nv_ctr);
+ 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, &param_ptr, &param_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;
+}
diff --git a/drivers/auth/cca/cot.c b/drivers/auth/cca/cot.c
new file mode 100644
index 0000000..d3f3087
--- /dev/null
+++ b/drivers/auth/cca/cot.c
@@ -0,0 +1,675 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <drivers/auth/auth_mod.h>
+#include MBEDTLS_CONFIG_FILE
+#include <tools_share/cca_oid.h>
+
+#include <platform_def.h>
+
+/*
+ * Allocate static buffers to store the authentication parameters extracted from
+ * the certificates.
+ */
+static unsigned char fw_config_hash_buf[HASH_DER_LEN];
+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 soc_fw_hash_buf[HASH_DER_LEN];
+static unsigned char soc_fw_config_hash_buf[HASH_DER_LEN];
+static unsigned char rmm_hash_buf[HASH_DER_LEN];
+
+#ifdef IMAGE_BL2
+static unsigned char nt_world_bl_hash_buf[HASH_DER_LEN];
+static unsigned char tos_fw_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];
+#if defined(SPD_spmd)
+static unsigned char sp_pkg_hash_buf[MAX_SP_IDS][HASH_DER_LEN];
+#endif /* SPD_spmd */
+
+static unsigned char core_swd_pk_buf[PK_DER_LEN];
+static unsigned char plat_pk_buf[PK_DER_LEN];
+#endif /* IMAGE_BL2 */
+
+/*
+ * 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);
+static auth_param_type_desc_t fw_config_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, FW_CONFIG_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 rmm_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, RMM_HASH_OID);
+
+#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 prot_pk = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_PUB_KEY, PROT_PK_OID);
+static auth_param_type_desc_t swd_rot_pk = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_PUB_KEY, SWD_ROT_PK_OID);
+static auth_param_type_desc_t core_swd_pk = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_PUB_KEY, CORE_SWD_PK_OID);
+static auth_param_type_desc_t plat_pk = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_PUB_KEY, PLAT_PK_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 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);
+#if defined(SPD_spmd)
+static auth_param_type_desc_t sp_pkg1_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG1_HASH_OID);
+static auth_param_type_desc_t sp_pkg2_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG2_HASH_OID);
+static auth_param_type_desc_t sp_pkg3_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG3_HASH_OID);
+static auth_param_type_desc_t sp_pkg4_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG4_HASH_OID);
+static auth_param_type_desc_t sp_pkg5_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG5_HASH_OID);
+static auth_param_type_desc_t sp_pkg6_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG6_HASH_OID);
+static auth_param_type_desc_t sp_pkg7_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG7_HASH_OID);
+static auth_param_type_desc_t sp_pkg8_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG8_HASH_OID);
+#endif /* SPD_spmd */
+#endif /* IMAGE_BL2 */
+
+/* CCA Content Certificate */
+static const auth_img_desc_t cca_content_cert = {
+ .img_id = CCA_CONTENT_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 = &fw_config_hash,
+ .data = {
+ .ptr = (void *)fw_config_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [3] = {
+ .type_desc = &hw_config_hash,
+ .data = {
+ .ptr = (void *)hw_config_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [4] = {
+ .type_desc = &soc_fw_hash,
+ .data = {
+ .ptr = (void *)soc_fw_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [5] = {
+ .type_desc = &soc_fw_config_hash,
+ .data = {
+ .ptr = (void *)soc_fw_config_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [6] = {
+ .type_desc = &rmm_hash,
+ .data = {
+ .ptr = (void *)rmm_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 = &cca_content_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
+ }
+ }
+ }
+};
+
+static const auth_img_desc_t tb_fw_config = {
+ .img_id = TB_FW_CONFIG_ID,
+ .img_type = IMG_RAW,
+ .parent = &cca_content_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
+ }
+ }
+ }
+};
+
+static const auth_img_desc_t fw_config = {
+ .img_id = FW_CONFIG_ID,
+ .img_type = IMG_RAW,
+ .parent = &cca_content_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &fw_config_hash
+ }
+ }
+ }
+};
+#endif /* IMAGE_BL1 */
+
+#ifdef IMAGE_BL2
+/* HW Config */
+static const auth_img_desc_t hw_config = {
+ .img_id = HW_CONFIG_ID,
+ .img_type = IMG_RAW,
+ .parent = &cca_content_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
+ }
+ }
+ }
+};
+
+/* BL31 */
+static const auth_img_desc_t bl31_image = {
+ .img_id = BL31_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &cca_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
+ }
+ }
+ }
+};
+
+/* BL31 Config */
+static const auth_img_desc_t soc_fw_config = {
+ .img_id = SOC_FW_CONFIG_ID,
+ .img_type = IMG_RAW,
+ .parent = &cca_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
+ }
+ }
+ }
+};
+
+/* RMM */
+static const auth_img_desc_t rmm_image = {
+ .img_id = RMM_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &cca_content_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &rmm_hash
+ }
+ }
+ }
+};
+
+/* Core SWD Key Certificate */
+static const auth_img_desc_t core_swd_key_cert = {
+ .img_id = CORE_SWD_KEY_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = NULL, /* SWD ROOT CERT */
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &swd_rot_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 = &core_swd_pk,
+ .data = {
+ .ptr = (void *)core_swd_pk_buf,
+ .len = (unsigned int)PK_DER_LEN
+ }
+ }
+ }
+};
+
+/* SPMC Content Certificate */
+static const auth_img_desc_t trusted_os_fw_content_cert = {
+ .img_id = TRUSTED_OS_FW_CONTENT_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = &core_swd_key_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &core_swd_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_config_hash,
+ .data = {
+ .ptr = (void *)tos_fw_config_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ }
+ }
+};
+
+/* SPMC */
+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
+ }
+ }
+ }
+};
+
+/* SPM 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
+ }
+ }
+ }
+};
+
+/* Platform Key Certificate */
+static const auth_img_desc_t plat_key_cert = {
+ .img_id = PLAT_KEY_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = NULL, /* PLATFORM ROOT CERT */
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &prot_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 = &plat_pk,
+ .data = {
+ .ptr = (void *)plat_pk_buf,
+ .len = (unsigned int)PK_DER_LEN
+ }
+ }
+ }
+};
+
+/* Non-Trusted Firmware */
+static const auth_img_desc_t non_trusted_fw_content_cert = {
+ .img_id = NON_TRUSTED_FW_CONTENT_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = &plat_key_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &plat_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
+ }
+ }
+ }
+};
+
+/*
+ * Secure Partitions
+ */
+#if defined(SPD_spmd)
+static const auth_img_desc_t sip_sp_content_cert = {
+ .img_id = SIP_SP_CONTENT_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = &core_swd_key_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &core_swd_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 = &sp_pkg1_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[0],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [1] = {
+ .type_desc = &sp_pkg2_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[1],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [2] = {
+ .type_desc = &sp_pkg3_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[2],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [3] = {
+ .type_desc = &sp_pkg4_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[3],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ }
+ }
+};
+
+DEFINE_SIP_SP_PKG(1);
+DEFINE_SIP_SP_PKG(2);
+DEFINE_SIP_SP_PKG(3);
+DEFINE_SIP_SP_PKG(4);
+
+static const auth_img_desc_t plat_sp_content_cert = {
+ .img_id = PLAT_SP_CONTENT_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = &plat_key_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &plat_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 = &sp_pkg5_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[4],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [1] = {
+ .type_desc = &sp_pkg6_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[5],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [2] = {
+ .type_desc = &sp_pkg7_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[6],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [3] = {
+ .type_desc = &sp_pkg8_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[7],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ }
+ }
+};
+
+DEFINE_PLAT_SP_PKG(5);
+DEFINE_PLAT_SP_PKG(6);
+DEFINE_PLAT_SP_PKG(7);
+DEFINE_PLAT_SP_PKG(8);
+#endif /* SPD_spmd */
+#endif /* IMAGE_BL2 */
+/*
+ * Chain of trust definition
+ */
+#ifdef IMAGE_BL1
+static const auth_img_desc_t * const cot_desc[] = {
+ [CCA_CONTENT_CERT_ID] = &cca_content_cert,
+ [BL2_IMAGE_ID] = &bl2_image,
+ [TB_FW_CONFIG_ID] = &tb_fw_config,
+ [FW_CONFIG_ID] = &fw_config,
+};
+#else /* IMAGE_BL2 */
+static const auth_img_desc_t * const cot_desc[] = {
+ [CCA_CONTENT_CERT_ID] = &cca_content_cert,
+ [HW_CONFIG_ID] = &hw_config,
+ [BL31_IMAGE_ID] = &bl31_image,
+ [SOC_FW_CONFIG_ID] = &soc_fw_config,
+ [RMM_IMAGE_ID] = &rmm_image,
+ [CORE_SWD_KEY_CERT_ID] = &core_swd_key_cert,
+ [TRUSTED_OS_FW_CONTENT_CERT_ID] = &trusted_os_fw_content_cert,
+ [BL32_IMAGE_ID] = &bl32_image,
+ [TOS_FW_CONFIG_ID] = &tos_fw_config,
+ [PLAT_KEY_CERT_ID] = &plat_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,
+#if defined(SPD_spmd)
+ [SIP_SP_CONTENT_CERT_ID] = &sip_sp_content_cert,
+ [PLAT_SP_CONTENT_CERT_ID] = &plat_sp_content_cert,
+ [SP_PKG1_ID] = &sp_pkg1,
+ [SP_PKG2_ID] = &sp_pkg2,
+ [SP_PKG3_ID] = &sp_pkg3,
+ [SP_PKG4_ID] = &sp_pkg4,
+ [SP_PKG5_ID] = &sp_pkg5,
+ [SP_PKG6_ID] = &sp_pkg6,
+ [SP_PKG7_ID] = &sp_pkg7,
+ [SP_PKG8_ID] = &sp_pkg8,
+#endif
+};
+#endif /* IMAGE_BL1 */
+
+/* Register the CoT in the authentication module */
+REGISTER_COT(cot_desc);
diff --git a/drivers/auth/crypto_mod.c b/drivers/auth/crypto_mod.c
new file mode 100644
index 0000000..fa1adb4
--- /dev/null
+++ b/drivers/auth/crypto_mod.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+
+/* 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);
+#if CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+ assert(crypto_lib_desc.verify_signature != NULL);
+ assert(crypto_lib_desc.verify_hash != NULL);
+#endif /* CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
+ CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
+
+#if CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+ assert(crypto_lib_desc.calc_hash != NULL);
+#endif /* CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+ CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
+
+ /* Initialize the cryptographic library */
+ crypto_lib_desc.init();
+ INFO("Using crypto library '%s'\n", crypto_lib_desc.name);
+}
+
+#if CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+/*
+ * 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);
+}
+#endif /* CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
+ CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
+
+#if CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+/*
+ * Calculate a hash
+ *
+ * Parameters:
+ *
+ * alg: message digest algorithm
+ * data_ptr, data_len: data to be hashed
+ * output: resulting hash
+ */
+int crypto_mod_calc_hash(enum crypto_md_algo alg, void *data_ptr,
+ unsigned int data_len,
+ unsigned char output[CRYPTO_MD_MAX_SIZE])
+{
+ assert(data_ptr != NULL);
+ assert(data_len != 0);
+ assert(output != NULL);
+
+ return crypto_lib_desc.calc_hash(alg, data_ptr, data_len, output);
+}
+#endif /* CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+ CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
+
+/*
+ * Authenticated decryption of data
+ *
+ * Parameters:
+ *
+ * dec_algo: authenticated decryption algorithm
+ * data_ptr, len: data to be decrypted (inout param)
+ * key, key_len, key_flags: symmetric decryption key
+ * iv, iv_len: initialization vector
+ * tag, tag_len: authentication tag
+ */
+int crypto_mod_auth_decrypt(enum crypto_dec_algo dec_algo, void *data_ptr,
+ size_t len, const void *key, unsigned int key_len,
+ unsigned int key_flags, const void *iv,
+ unsigned int iv_len, const void *tag,
+ unsigned int tag_len)
+{
+ assert(crypto_lib_desc.auth_decrypt != NULL);
+ assert(data_ptr != NULL);
+ assert(len != 0U);
+ assert(key != NULL);
+ assert(key_len != 0U);
+ assert(iv != NULL);
+ assert((iv_len != 0U) && (iv_len <= CRYPTO_MAX_IV_SIZE));
+ assert(tag != NULL);
+ assert((tag_len != 0U) && (tag_len <= CRYPTO_MAX_TAG_SIZE));
+
+ return crypto_lib_desc.auth_decrypt(dec_algo, data_ptr, len, key,
+ key_len, key_flags, iv, iv_len, tag,
+ tag_len);
+}
diff --git a/drivers/auth/cryptocell/712/cryptocell_crypto.c b/drivers/auth/cryptocell/712/cryptocell_crypto.c
new file mode 100644
index 0000000..c7ee36f
--- /dev/null
+++ b/drivers/auth/cryptocell/712/cryptocell_crypto.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/cryptocell/712/crypto_driver.h>
+#include <drivers/arm/cryptocell/712/rsa.h>
+#include <drivers/arm/cryptocell/712/sbrom_bsv_api.h>
+#include <drivers/arm/cryptocell/712/secureboot_base_func.h>
+#include <drivers/arm/cryptocell/712/secureboot_gen_defs.h>
+#include <drivers/arm/cryptocell/712/util.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/auth/mbedtls/mbedtls_common.h>
+#include <lib/utils.h>
+
+#include <mbedtls/oid.h>
+#include <mbedtls/x509.h>
+
+#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, &params);
+ 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(&params, &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);
+ 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, &params);
+ 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, NULL);
+
diff --git a/drivers/auth/cryptocell/712/cryptocell_plat_helpers.c b/drivers/auth/cryptocell/712/cryptocell_plat_helpers.c
new file mode 100644
index 0000000..53d77db
--- /dev/null
+++ b/drivers/auth/cryptocell/712/cryptocell_plat_helpers.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <plat/common/platform.h>
+#include <tools_share/tbbr_oid.h>
+
+#include <common/debug.h>
+#include <drivers/arm/cryptocell/712/sbrom_bsv_api.h>
+#include <drivers/arm/cryptocell/712/nvm.h>
+#include <drivers/arm/cryptocell/712/nvm_otp.h>
+
+/*
+ * 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);
+}
+
diff --git a/drivers/auth/cryptocell/713/cryptocell_crypto.c b/drivers/auth/cryptocell/713/cryptocell_crypto.c
new file mode 100644
index 0000000..3ac16af
--- /dev/null
+++ b/drivers/auth/cryptocell/713/cryptocell_crypto.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2017-2020 ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <drivers/arm/cryptocell/713/bsv_api.h>
+#include <drivers/arm/cryptocell/713/bsv_crypto_asym_api.h>
+#include <drivers/auth/crypto_mod.h>
+
+#include <mbedtls/oid.h>
+#include <mbedtls/x509.h>
+
+#define LIB_NAME "CryptoCell 713 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_BsvInit((uintptr_t)PLAT_CRYPTOCELL_BASE);
+ if (ret != CC_OK) {
+ ERROR("CryptoCell CC_BsvInit() error %x\n", ret);
+ panic();
+ }
+
+ /* Initialize lifecycle state */
+ ret = CC_BsvGetAndInitLcs((uintptr_t)PLAT_CRYPTOCELL_BASE, &lcs);
+ if (ret != CC_OK) {
+ ERROR("CryptoCell CC_BsvGetAndInitLcs() error %x\n", ret);
+ 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;
+ CCBsvNBuff_t NBuff;
+ CCBsvSignature_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;
+ CCHashResult_t digest;
+ CCBool_t is_verified;
+ /* This is a rather large array, we don't want it on stack */
+ static uint32_t workspace[BSV_RSA_WORKSPACE_MIN_SIZE];
+
+ /* 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, &params);
+ 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(&params, &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 != BSV_CERT_RSA_KEY_SIZE_IN_BYTES || ((p + len) > end))
+ return CRYPTO_ERR_SIGNATURE;
+
+ /*
+ * Copy N from certificate.
+ */
+ memcpy(NBuff, p, BSV_CERT_RSA_KEY_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;
+
+ /* 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 != BSV_CERT_RSA_KEY_SIZE_IN_BYTES || ((p + len) > end))
+ return CRYPTO_ERR_SIGNATURE;
+
+ /*
+ * Copy the signature (in BE format)
+ */
+ memcpy((uint8_t *)signature, p, BSV_CERT_RSA_KEY_SIZE_IN_BYTES);
+
+ error = CC_BsvSha256((uintptr_t)PLAT_CRYPTOCELL_BASE,
+ data_ptr, data_len, digest);
+ if (error != CC_OK)
+ return CRYPTO_ERR_SIGNATURE;
+
+ /* Verify the signature */
+ error = CC_BsvRsaPssVerify((uintptr_t)PLAT_CRYPTOCELL_BASE, NBuff,
+ NULL, signature, digest, workspace,
+ BSV_RSA_WORKSPACE_MIN_SIZE, &is_verified);
+ if ((error != CC_OK) || (is_verified != CC_TRUE))
+ 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, &params);
+ 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;
+
+ hash = p;
+ error = CC_BsvSha256((uintptr_t)PLAT_CRYPTOCELL_BASE, 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, NULL);
diff --git a/drivers/auth/cryptocell/713/cryptocell_plat_helpers.c b/drivers/auth/cryptocell/713/cryptocell_plat_helpers.c
new file mode 100644
index 0000000..17e1280
--- /dev/null
+++ b/drivers/auth/cryptocell/713/cryptocell_plat_helpers.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2017-2020 ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <plat/common/platform.h>
+#include <tools_share/tbbr_oid.h>
+
+#include <lib/libc/endian.h>
+#include <drivers/arm/cryptocell/713/bsv_api.h>
+#include <drivers/arm/cryptocell/713/bsv_error.h>
+
+/*
+ * Return the ROTPK hash
+ *
+ * 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;
+ int i;
+ uint32_t *key = (uint32_t *)dst;
+
+ assert(dst != NULL);
+ assert(len >= HASH_RESULT_SIZE_IN_WORDS);
+ assert(flags != NULL);
+
+ error = CC_BsvLcsGet(PLAT_CRYPTOCELL_BASE, &lcs);
+ if (error != CC_OK)
+ return 1;
+
+ if ((lcs == CC_BSV_CHIP_MANUFACTURE_LCS) || (lcs == CC_BSV_RMA_LCS)) {
+ *flags = ROTPK_NOT_DEPLOYED;
+ return 0;
+ }
+
+ error = CC_BsvPubKeyHashGet(PLAT_CRYPTOCELL_BASE,
+ CC_SB_HASH_BOOT_KEY_256B,
+ key, HASH_RESULT_SIZE_IN_WORDS);
+
+ if (error == CC_BSV_HASH_NOT_PROGRAMMED_ERR) {
+ *flags = ROTPK_NOT_DEPLOYED;
+ return 0;
+ }
+
+ if (error == CC_OK) {
+
+ /* Keys are stored in OTP in little-endian format */
+ for (i = 0; i < HASH_RESULT_SIZE_IN_WORDS; i++)
+ key[i] = le32toh(key[i]);
+
+ *flags = ROTPK_IS_HASH;
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * 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 = CC_BsvSwVersionGet(PLAT_CRYPTOCELL_BASE,
+ CC_SW_VERSION_TRUSTED, nv_ctr);
+ } else if (strcmp(cookie, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) {
+ error = CC_BsvSwVersionGet(PLAT_CRYPTOCELL_BASE,
+ CC_SW_VERSION_NON_TRUSTED, 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 = CC_BsvSwVersionSet(PLAT_CRYPTOCELL_BASE,
+ CC_SW_VERSION_TRUSTED, nv_ctr);
+ } else if (strcmp(cookie, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) {
+ error = CC_BsvSwVersionSet(PLAT_CRYPTOCELL_BASE,
+ CC_SW_VERSION_NON_TRUSTED, nv_ctr);
+ }
+
+ return (error != CC_OK);
+}
+
diff --git a/drivers/auth/cryptocell/cryptocell_crypto.mk b/drivers/auth/cryptocell/cryptocell_crypto.mk
new file mode 100644
index 0000000..db39047
--- /dev/null
+++ b/drivers/auth/cryptocell/cryptocell_crypto.mk
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2017-2020, 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))
+
+$(eval $(call add_define,KEY_SIZE))
+
+# 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 ifeq (${CRYPTOCELL_VERSION},713)
+ CCSBROM_LIB_FILENAME := cc_713bsv
+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}
diff --git a/drivers/auth/dualroot/cot.c b/drivers/auth/dualroot/cot.c
new file mode 100644
index 0000000..8368503
--- /dev/null
+++ b/drivers/auth/dualroot/cot.c
@@ -0,0 +1,959 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <platform_def.h>
+
+#include MBEDTLS_CONFIG_FILE
+#include <drivers/auth/auth_mod.h>
+#include <tools_share/dualroot_oid.h>
+
+/*
+ * Allocate static buffers to store the authentication parameters extracted from
+ * the certificates.
+ */
+static unsigned char fw_config_hash_buf[HASH_DER_LEN];
+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 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];
+#if defined(SPD_spmd)
+static unsigned char sp_pkg_hash_buf[MAX_SP_IDS][HASH_DER_LEN];
+#endif /* SPD_spmd */
+
+static unsigned char trusted_world_pk_buf[PK_DER_LEN];
+static unsigned char content_pk_buf[PK_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);
+static auth_param_type_desc_t fw_config_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, FW_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 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 prot_pk = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_PUB_KEY, PROT_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);
+#if defined(SPD_spmd)
+static auth_param_type_desc_t sp_pkg1_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG1_HASH_OID);
+static auth_param_type_desc_t sp_pkg2_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG2_HASH_OID);
+static auth_param_type_desc_t sp_pkg3_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG3_HASH_OID);
+static auth_param_type_desc_t sp_pkg4_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG4_HASH_OID);
+static auth_param_type_desc_t sp_pkg5_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG5_HASH_OID);
+static auth_param_type_desc_t sp_pkg6_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG6_HASH_OID);
+static auth_param_type_desc_t sp_pkg7_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG7_HASH_OID);
+static auth_param_type_desc_t sp_pkg8_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG8_HASH_OID);
+#endif /* SPD_spmd */
+#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
+ }
+ },
+ [3] = {
+ .type_desc = &fw_config_hash,
+ .data = {
+ .ptr = (void *)fw_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
+ }
+ }
+ }
+};
+
+static const auth_img_desc_t fw_config = {
+ .img_id = 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 = &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
+ }
+ },
+ }
+};
+
+/* 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_content_cert = {
+ .img_id = NON_TRUSTED_FW_CONTENT_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = NULL, /* Root certificate. */
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &prot_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
+ }
+ }
+ }
+};
+
+/*
+ * Secure Partitions
+ */
+#if defined(SPD_spmd)
+static const auth_img_desc_t sip_sp_content_cert = {
+ .img_id = SIP_SP_CONTENT_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 = &sp_pkg1_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[0],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [1] = {
+ .type_desc = &sp_pkg2_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[1],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [2] = {
+ .type_desc = &sp_pkg3_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[2],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [3] = {
+ .type_desc = &sp_pkg4_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[3],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ }
+ }
+};
+
+DEFINE_SIP_SP_PKG(1);
+DEFINE_SIP_SP_PKG(2);
+DEFINE_SIP_SP_PKG(3);
+DEFINE_SIP_SP_PKG(4);
+
+static const auth_img_desc_t plat_sp_content_cert = {
+ .img_id = PLAT_SP_CONTENT_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 = &prot_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 = &sp_pkg5_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[4],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [1] = {
+ .type_desc = &sp_pkg6_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[5],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [2] = {
+ .type_desc = &sp_pkg7_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[6],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [3] = {
+ .type_desc = &sp_pkg8_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[7],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ }
+ }
+};
+
+DEFINE_PLAT_SP_PKG(5);
+DEFINE_PLAT_SP_PKG(6);
+DEFINE_PLAT_SP_PKG(7);
+DEFINE_PLAT_SP_PKG(8);
+#endif /* SPD_spmd */
+
+#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 */
+
+/*
+ * 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,
+ [FW_CONFIG_ID] = &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_CONTENT_CERT_ID] = &non_trusted_fw_content_cert,
+ [BL33_IMAGE_ID] = &bl33_image,
+ [NT_FW_CONFIG_ID] = &nt_fw_config,
+#if defined(SPD_spmd)
+ [SIP_SP_CONTENT_CERT_ID] = &sip_sp_content_cert,
+ [PLAT_SP_CONTENT_CERT_ID] = &plat_sp_content_cert,
+ [SP_PKG1_ID] = &sp_pkg1,
+ [SP_PKG2_ID] = &sp_pkg2,
+ [SP_PKG3_ID] = &sp_pkg3,
+ [SP_PKG4_ID] = &sp_pkg4,
+ [SP_PKG5_ID] = &sp_pkg5,
+ [SP_PKG6_ID] = &sp_pkg6,
+ [SP_PKG7_ID] = &sp_pkg7,
+ [SP_PKG8_ID] = &sp_pkg8,
+#endif
+};
+#endif
+
+/* Register the CoT in the authentication module */
+REGISTER_COT(cot_desc);
diff --git a/drivers/auth/img_parser_mod.c b/drivers/auth/img_parser_mod.c
new file mode 100644
index 0000000..535695d
--- /dev/null
+++ b/drivers/auth/img_parser_mod.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/auth/auth_common.h>
+#include <drivers/auth/img_parser_mod.h>
+#include <lib/utils_def.h>
+
+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);
+}
diff --git a/drivers/auth/mbedtls/mbedtls_common.c b/drivers/auth/mbedtls/mbedtls_common.c
new file mode 100644
index 0000000..a12e49c
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_common.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+
+/* mbed TLS headers */
+#include <mbedtls/memory_buffer_alloc.h>
+#include <mbedtls/platform.h>
+
+#include <common/debug.h>
+#include <drivers/auth/mbedtls/mbedtls_common.h>
+#include MBEDTLS_CONFIG_FILE
+#include <plat/common/platform.h>
+
+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;
+}
diff --git a/drivers/auth/mbedtls/mbedtls_common.mk b/drivers/auth/mbedtls/mbedtls_common.mk
new file mode 100644
index 0000000..16ce65f
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_common.mk
@@ -0,0 +1,111 @@
+#
+# Copyright (c) 2015-2022, Arm Limited. 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 ?= "<drivers/auth/mbedtls/mbedtls_config.h>"
+$(eval $(call add_define,MBEDTLS_CONFIG_FILE))
+
+MBEDTLS_SOURCES += drivers/auth/mbedtls/mbedtls_common.c
+
+
+LIBMBEDTLS_SRCS := $(addprefix ${MBEDTLS_DIR}/library/, \
+ aes.c \
+ asn1parse.c \
+ asn1write.c \
+ cipher.c \
+ cipher_wrap.c \
+ memory_buffer_alloc.c \
+ oid.c \
+ platform.c \
+ platform_util.c \
+ bignum.c \
+ gcm.c \
+ md.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 \
+ constant_time.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
+
+ifeq (${DECRYPTION_SUPPORT}, aes_gcm)
+ TF_MBEDTLS_USE_AES_GCM := 1
+else
+ TF_MBEDTLS_USE_AES_GCM := 0
+endif
+
+# Needs to be set to drive mbed TLS configuration correctly
+$(eval $(call add_defines,\
+ $(sort \
+ TF_MBEDTLS_KEY_ALG_ID \
+ TF_MBEDTLS_KEY_SIZE \
+ TF_MBEDTLS_HASH_ALG_ID \
+ TF_MBEDTLS_USE_AES_GCM \
+)))
+
+$(eval $(call MAKE_LIB,mbedtls))
+
+endif
diff --git a/drivers/auth/mbedtls/mbedtls_crypto.c b/drivers/auth/mbedtls/mbedtls_crypto.c
new file mode 100644
index 0000000..d231179
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_crypto.c
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+/* mbed TLS headers */
+#include <mbedtls/gcm.h>
+#include <mbedtls/md.h>
+#include <mbedtls/memory_buffer_alloc.h>
+#include <mbedtls/oid.h>
+#include <mbedtls/platform.h>
+#include <mbedtls/x509.h>
+
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/auth/mbedtls/mbedtls_common.h>
+#include <drivers/auth/mbedtls/mbedtls_config.h>
+#include <plat/common/platform.h>
+
+#define LIB_NAME "mbed TLS"
+
+#if CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+/*
+ * CRYPTO_MD_MAX_SIZE value is as per current stronger algorithm available
+ * so make sure that mbed TLS MD maximum size must be lesser than this.
+ */
+CASSERT(CRYPTO_MD_MAX_SIZE >= MBEDTLS_MD_MAX_SIZE,
+ assert_mbedtls_md_size_overflow);
+
+#endif /* CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+ CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
+
+/*
+ * 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();
+}
+
+#if CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+/*
+ * 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, &params);
+ 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;
+}
+#endif /* CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
+ CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
+
+#if CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+/*
+ * Map a generic crypto message digest algorithm to the corresponding macro used
+ * by Mbed TLS.
+ */
+static inline mbedtls_md_type_t md_type(enum crypto_md_algo algo)
+{
+ switch (algo) {
+ case CRYPTO_MD_SHA512:
+ return MBEDTLS_MD_SHA512;
+ case CRYPTO_MD_SHA384:
+ return MBEDTLS_MD_SHA384;
+ case CRYPTO_MD_SHA256:
+ return MBEDTLS_MD_SHA256;
+ default:
+ /* Invalid hash algorithm. */
+ return MBEDTLS_MD_NONE;
+ }
+}
+
+/*
+ * Calculate a hash
+ *
+ * output points to the computed hash
+ */
+static int calc_hash(enum crypto_md_algo md_algo, void *data_ptr,
+ unsigned int data_len,
+ unsigned char output[CRYPTO_MD_MAX_SIZE])
+{
+ const mbedtls_md_info_t *md_info;
+
+ md_info = mbedtls_md_info_from_type(md_type(md_algo));
+ if (md_info == NULL) {
+ return CRYPTO_ERR_HASH;
+ }
+
+ /*
+ * Calculate the hash of the data, it is safe to pass the
+ * 'output' hash buffer pointer considering its size is always
+ * bigger than or equal to MBEDTLS_MD_MAX_SIZE.
+ */
+ return mbedtls_md(md_info, data_ptr, data_len, output);
+}
+#endif /* CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+ CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
+
+#if TF_MBEDTLS_USE_AES_GCM
+/*
+ * Stack based buffer allocation for decryption operation. It could
+ * be configured to balance stack usage vs execution speed.
+ */
+#define DEC_OP_BUF_SIZE 128
+
+static int aes_gcm_decrypt(void *data_ptr, size_t len, const void *key,
+ unsigned int key_len, const void *iv,
+ unsigned int iv_len, const void *tag,
+ unsigned int tag_len)
+{
+ mbedtls_gcm_context ctx;
+ mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES;
+ unsigned char buf[DEC_OP_BUF_SIZE];
+ unsigned char tag_buf[CRYPTO_MAX_TAG_SIZE];
+ unsigned char *pt = data_ptr;
+ size_t dec_len;
+ int diff, i, rc;
+
+ mbedtls_gcm_init(&ctx);
+
+ rc = mbedtls_gcm_setkey(&ctx, cipher, key, key_len * 8);
+ if (rc != 0) {
+ rc = CRYPTO_ERR_DECRYPTION;
+ goto exit_gcm;
+ }
+
+ rc = mbedtls_gcm_starts(&ctx, MBEDTLS_GCM_DECRYPT, iv, iv_len, NULL, 0);
+ if (rc != 0) {
+ rc = CRYPTO_ERR_DECRYPTION;
+ goto exit_gcm;
+ }
+
+ while (len > 0) {
+ dec_len = MIN(sizeof(buf), len);
+
+ rc = mbedtls_gcm_update(&ctx, dec_len, pt, buf);
+ if (rc != 0) {
+ rc = CRYPTO_ERR_DECRYPTION;
+ goto exit_gcm;
+ }
+
+ memcpy(pt, buf, dec_len);
+ pt += dec_len;
+ len -= dec_len;
+ }
+
+ rc = mbedtls_gcm_finish(&ctx, tag_buf, sizeof(tag_buf));
+ if (rc != 0) {
+ rc = CRYPTO_ERR_DECRYPTION;
+ goto exit_gcm;
+ }
+
+ /* Check tag in "constant-time" */
+ for (diff = 0, i = 0; i < tag_len; i++)
+ diff |= ((const unsigned char *)tag)[i] ^ tag_buf[i];
+
+ if (diff != 0) {
+ rc = CRYPTO_ERR_DECRYPTION;
+ goto exit_gcm;
+ }
+
+ /* GCM decryption success */
+ rc = CRYPTO_SUCCESS;
+
+exit_gcm:
+ mbedtls_gcm_free(&ctx);
+ return rc;
+}
+
+/*
+ * Authenticated decryption of an image
+ */
+static int auth_decrypt(enum crypto_dec_algo dec_algo, void *data_ptr,
+ size_t len, const void *key, unsigned int key_len,
+ unsigned int key_flags, const void *iv,
+ unsigned int iv_len, const void *tag,
+ unsigned int tag_len)
+{
+ int rc;
+
+ assert((key_flags & ENC_KEY_IS_IDENTIFIER) == 0);
+
+ switch (dec_algo) {
+ case CRYPTO_GCM_DECRYPT:
+ rc = aes_gcm_decrypt(data_ptr, len, key, key_len, iv, iv_len,
+ tag, tag_len);
+ if (rc != 0)
+ return rc;
+ break;
+ default:
+ return CRYPTO_ERR_DECRYPTION;
+ }
+
+ return CRYPTO_SUCCESS;
+}
+#endif /* TF_MBEDTLS_USE_AES_GCM */
+
+/*
+ * Register crypto library descriptor
+ */
+#if CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+#if TF_MBEDTLS_USE_AES_GCM
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, calc_hash,
+ auth_decrypt);
+#else
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, calc_hash,
+ NULL);
+#endif
+#elif CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY
+#if TF_MBEDTLS_USE_AES_GCM
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash,
+ auth_decrypt);
+#else
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, NULL);
+#endif
+#elif CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY
+REGISTER_CRYPTO_LIB(LIB_NAME, init, calc_hash);
+#endif /* CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
diff --git a/drivers/auth/mbedtls/mbedtls_crypto.mk b/drivers/auth/mbedtls/mbedtls_crypto.mk
new file mode 100644
index 0000000..2a9fbbf
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_crypto.mk
@@ -0,0 +1,11 @@
+#
+# 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
+
+
diff --git a/drivers/auth/mbedtls/mbedtls_x509.mk b/drivers/auth/mbedtls/mbedtls_x509.mk
new file mode 100644
index 0000000..a0557e2
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_x509.mk
@@ -0,0 +1,9 @@
+#
+# 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
diff --git a/drivers/auth/mbedtls/mbedtls_x509_parser.c b/drivers/auth/mbedtls/mbedtls_x509_parser.c
new file mode 100644
index 0000000..993ef12
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_x509_parser.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2015-2022, 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 <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+/* mbed TLS headers */
+#include <mbedtls/asn1.h>
+#include <mbedtls/oid.h>
+#include <mbedtls/platform.h>
+
+#include <arch_helpers.h>
+#include <drivers/auth/img_parser_mod.h>
+#include <drivers/auth/mbedtls/mbedtls_common.h>
+#include <lib/utils.h>
+
+/* 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) || (oid_len < 0)) {
+ return IMG_PARSER_ERR;
+ }
+ if (((size_t)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);
diff --git a/drivers/auth/tbbr/tbbr_cot_bl1.c b/drivers/auth/tbbr/tbbr_cot_bl1.c
new file mode 100644
index 0000000..44f8638
--- /dev/null
+++ b/drivers/auth/tbbr/tbbr_cot_bl1.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <platform_def.h>
+#include MBEDTLS_CONFIG_FILE
+
+#include <drivers/auth/auth_mod.h>
+#include <drivers/auth/tbbr_cot_common.h>
+#if USE_TBBR_DEFS
+#include <tools_share/tbbr_oid.h>
+#else
+#include <platform_oid.h>
+#endif
+
+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);
+
+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
+ }
+ }
+ }
+};
+
+/*
+ * 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
+ }
+ }
+ }
+};
+/*
+ * TB_FW_CONFIG
+ */
+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
+ }
+ }
+ }
+};
+
+static const auth_img_desc_t fw_config = {
+ .img_id = 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 = &fw_config_hash
+ }
+ }
+ }
+};
+
+/*
+ * TBBR Chain of trust definition
+ */
+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,
+ [FW_CONFIG_ID] = &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
+};
+
+/* Register the CoT in the authentication module */
+REGISTER_COT(cot_desc);
diff --git a/drivers/auth/tbbr/tbbr_cot_bl1_r64.c b/drivers/auth/tbbr/tbbr_cot_bl1_r64.c
new file mode 100644
index 0000000..78e38f6
--- /dev/null
+++ b/drivers/auth/tbbr/tbbr_cot_bl1_r64.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <drivers/auth/auth_mod.h>
+#include MBEDTLS_CONFIG_FILE
+#include <drivers/auth/tbbr_cot_common.h>
+
+#if USE_TBBR_DEFS
+#include <tools_share/tbbr_oid.h>
+#else
+#include <platform_oid.h>
+#endif
+#include <platform_def.h>
+
+
+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 nt_fw_config_hash_buf[HASH_DER_LEN];
+
+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 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 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);
+/*
+ * 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
+ }
+ }
+ }
+};
+/*
+ * 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
+ }
+ }
+ }
+};
+
+static const auth_img_desc_t * const cot_desc[] = {
+ [TRUSTED_KEY_CERT_ID] = &trusted_key_cert,
+ [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,
+};
+
+/* Register the CoT in the authentication module */
+REGISTER_COT(cot_desc);
diff --git a/drivers/auth/tbbr/tbbr_cot_bl2.c b/drivers/auth/tbbr/tbbr_cot_bl2.c
new file mode 100644
index 0000000..11e2f46
--- /dev/null
+++ b/drivers/auth/tbbr/tbbr_cot_bl2.c
@@ -0,0 +1,688 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <platform_def.h>
+#include MBEDTLS_CONFIG_FILE
+
+#include <drivers/auth/auth_mod.h>
+#include <drivers/auth/tbbr_cot_common.h>
+#if USE_TBBR_DEFS
+#include <tools_share/tbbr_oid.h>
+#else
+#include <platform_oid.h>
+#endif
+
+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];
+#if defined(SPD_spmd)
+static unsigned char sp_pkg_hash_buf[MAX_SP_IDS][HASH_DER_LEN];
+#endif /* SPD_spmd */
+
+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);
+#if defined(SPD_spmd)
+static auth_param_type_desc_t sp_pkg1_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG1_HASH_OID);
+static auth_param_type_desc_t sp_pkg2_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG2_HASH_OID);
+static auth_param_type_desc_t sp_pkg3_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG3_HASH_OID);
+static auth_param_type_desc_t sp_pkg4_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG4_HASH_OID);
+static auth_param_type_desc_t sp_pkg5_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG5_HASH_OID);
+static auth_param_type_desc_t sp_pkg6_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG6_HASH_OID);
+static auth_param_type_desc_t sp_pkg7_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG7_HASH_OID);
+static auth_param_type_desc_t sp_pkg8_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG8_HASH_OID);
+#endif /* SPD_spmd */
+
+/*
+ * 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
+ }
+ }
+ }
+};
+/* Secure Partitions */
+#if defined(SPD_spmd)
+static const auth_img_desc_t sip_sp_content_cert = {
+ .img_id = SIP_SP_CONTENT_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 = &sp_pkg1_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[0],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [1] = {
+ .type_desc = &sp_pkg2_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[1],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [2] = {
+ .type_desc = &sp_pkg3_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[2],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [3] = {
+ .type_desc = &sp_pkg4_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[3],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [4] = {
+ .type_desc = &sp_pkg5_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[4],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [5] = {
+ .type_desc = &sp_pkg6_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[5],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [6] = {
+ .type_desc = &sp_pkg7_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[6],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [7] = {
+ .type_desc = &sp_pkg8_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[7],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ }
+ }
+};
+
+DEFINE_SIP_SP_PKG(1);
+DEFINE_SIP_SP_PKG(2);
+DEFINE_SIP_SP_PKG(3);
+DEFINE_SIP_SP_PKG(4);
+DEFINE_SIP_SP_PKG(5);
+DEFINE_SIP_SP_PKG(6);
+DEFINE_SIP_SP_PKG(7);
+DEFINE_SIP_SP_PKG(8);
+#endif /* SPD_spmd */
+
+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,
+#if defined(SPD_spmd)
+ [SIP_SP_CONTENT_CERT_ID] = &sip_sp_content_cert,
+ [SP_PKG1_ID] = &sp_pkg1,
+ [SP_PKG2_ID] = &sp_pkg2,
+ [SP_PKG3_ID] = &sp_pkg3,
+ [SP_PKG4_ID] = &sp_pkg4,
+ [SP_PKG5_ID] = &sp_pkg5,
+ [SP_PKG6_ID] = &sp_pkg6,
+ [SP_PKG7_ID] = &sp_pkg7,
+ [SP_PKG8_ID] = &sp_pkg8,
+#endif
+};
+
+/* Register the CoT in the authentication module */
+REGISTER_COT(cot_desc);
diff --git a/drivers/auth/tbbr/tbbr_cot_common.c b/drivers/auth/tbbr/tbbr_cot_common.c
new file mode 100644
index 0000000..0983d42
--- /dev/null
+++ b/drivers/auth/tbbr/tbbr_cot_common.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <platform_def.h>
+#include MBEDTLS_CONFIG_FILE
+
+#include <drivers/auth/auth_mod.h>
+#include <drivers/auth/tbbr_cot_common.h>
+#if USE_TBBR_DEFS
+#include <tools_share/tbbr_oid.h>
+#else
+#include <platform_oid.h>
+#endif
+
+/*
+ * 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 fw_config_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];
+unsigned char tb_fw_hash_buf[HASH_DER_LEN];
+unsigned char scp_fw_hash_buf[HASH_DER_LEN];
+unsigned char nt_world_bl_hash_buf[HASH_DER_LEN];
+
+/*
+ * common Parameter type descriptors across BL1 and BL2
+ */
+auth_param_type_desc_t trusted_nv_ctr = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_NV_CTR, TRUSTED_FW_NVCOUNTER_OID);
+auth_param_type_desc_t subject_pk = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_PUB_KEY, 0);
+auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_SIG, 0);
+auth_param_type_desc_t sig_alg = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_SIG_ALG, 0);
+auth_param_type_desc_t raw_data = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_RAW_DATA, 0);
+
+/* common hash used across BL1 and BL2 */
+auth_param_type_desc_t tb_fw_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, TRUSTED_BOOT_FW_HASH_OID);
+auth_param_type_desc_t tb_fw_config_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, TRUSTED_BOOT_FW_CONFIG_HASH_OID);
+auth_param_type_desc_t fw_config_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, FW_CONFIG_HASH_OID);
+static auth_param_type_desc_t hw_config_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, HW_CONFIG_HASH_OID);
+
+/* trusted_boot_fw_cert */
+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
+ }
+ },
+ [3] = {
+ .type_desc = &fw_config_hash,
+ .data = {
+ .ptr = (void *)fw_config_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ }
+ }
+};
+
+/* HW Config */
+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
+ }
+ }
+ }
+};
diff --git a/drivers/brcm/chimp.c b/drivers/brcm/chimp.c
new file mode 100644
index 0000000..81767bb
--- /dev/null
+++ b/drivers/brcm/chimp.c
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <drivers/delay_timer.h>
+
+#include <chimp.h>
+#include <chimp_nv_defs.h>
+
+#define CHIMP_DEFAULT_STARTUP_ADDR 0xb4300000
+
+/* ChiMP's view of APE scratchpad memory for fastboot */
+#define CHIMP_FASTBOOT_ADDR 0x61000000
+
+#define CHIMP_PREPARE_ACCESS_WINDOW(addr) \
+ (\
+ mmio_write_32(\
+ NIC400_NITRO_CHIMP_S_IDM_IO_CONTROL_DIRECT, \
+ addr & 0xffc00000)\
+ )
+#define CHIMP_INDIRECT_TGT_ADDR(addr) \
+ (CHIMP_INDIRECT_BASE + (addr & CHIMP_INDIRECT_ADDR_MASK))
+
+#define CHIMP_CTRL_ADDR(x) (CHIMP_REG_CTRL_BASE + x)
+
+/* For non-PAXC builds */
+#ifndef CHIMP_FB1_ENTRY
+#define CHIMP_FB1_ENTRY 0
+#endif
+
+#define CHIMP_DBG VERBOSE
+
+void bcm_chimp_write(uintptr_t addr, uint32_t value)
+{
+ CHIMP_PREPARE_ACCESS_WINDOW(addr);
+ mmio_write_32(CHIMP_INDIRECT_TGT_ADDR(addr), value);
+}
+
+uint32_t bcm_chimp_read(uintptr_t addr)
+{
+ CHIMP_PREPARE_ACCESS_WINDOW(addr);
+ return mmio_read_32(CHIMP_INDIRECT_TGT_ADDR(addr));
+}
+
+void bcm_chimp_clrbits(uintptr_t addr, uint32_t bits)
+{
+ CHIMP_PREPARE_ACCESS_WINDOW(addr);
+ mmio_clrbits_32(CHIMP_INDIRECT_TGT_ADDR(addr), bits);
+}
+
+void bcm_chimp_setbits(uintptr_t addr, uint32_t bits)
+{
+ CHIMP_PREPARE_ACCESS_WINDOW(addr);
+ mmio_setbits_32(CHIMP_INDIRECT_TGT_ADDR(addr), bits);
+}
+
+int bcm_chimp_is_nic_mode(void)
+{
+ uint32_t val;
+
+ /* Check if ChiMP straps are set */
+ val = mmio_read_32(CDRU_CHIP_STRAP_DATA_LSW);
+ val &= CDRU_CHIP_STRAP_DATA_LSW__NIC_MODE_MASK;
+
+ return val == CDRU_CHIP_STRAP_DATA_LSW__NIC_MODE_MASK;
+}
+
+void bcm_chimp_fru_prog_done(bool is_done)
+{
+ uint32_t val;
+
+ val = is_done ? (1 << CHIMP_FRU_PROG_DONE_BIT) : 0;
+ bcm_chimp_setbits(CHIMP_REG_ECO_RESERVED, val);
+}
+
+int bcm_chimp_handshake_done(void)
+{
+ uint32_t value;
+
+ value = bcm_chimp_read(CHIMP_REG_ECO_RESERVED);
+ value &= (1 << CHIMP_FLASH_ACCESS_DONE_BIT);
+
+ return value != 0;
+}
+
+int bcm_chimp_wait_handshake(void)
+{
+ uint32_t timeout = CHIMP_HANDSHAKE_TIMEOUT_MS;
+ uint32_t status;
+
+ INFO("Waiting for ChiMP handshake...\n");
+ do {
+ if (bcm_chimp_handshake_done())
+ break;
+ /* No need to wait if ChiMP reported an error */
+ status = bcm_chimp_read_ctrl(CHIMP_REG_CTRL_BPE_STAT_REG);
+ if (status & CHIMP_ERROR_MASK) {
+ ERROR("ChiMP error 0x%x. Wait aborted\n", status);
+ break;
+ }
+ mdelay(1);
+ } while (--timeout);
+
+ if (!bcm_chimp_handshake_done()) {
+ if (timeout == 0) {
+ WARN("Timeout waiting for ChiMP handshake\n");
+ }
+ } else {
+ INFO("Got handshake from ChiMP!\n");
+ }
+
+ return bcm_chimp_handshake_done();
+}
+
+uint32_t bcm_chimp_read_ctrl(uint32_t offset)
+{
+ return bcm_chimp_read(CHIMP_CTRL_ADDR(offset));
+}
+
+static int bcm_chimp_nitro_reset(void)
+{
+ uint32_t timeout;
+
+ /* Perform tasks done by M0 in NIC mode */
+ CHIMP_DBG("Taking Nitro out of reset\n");
+ mmio_setbits_32(CDRU_MISC_RESET_CONTROL,
+ /* MHB_RESET_N */
+ (1 << CDRU_MISC_RESET_CONTROL__CDRU_MHB_RESET_N_R) |
+ /* PCI_RESET_N */
+ (1 << CDRU_MISC_RESET_CONTROL__CDRU_PCIE_RESET_N_R) |
+ /* PM_RESET_N */
+ (1 << CDRU_MISC_RESET_CONTROL__CDRU_PM_RESET_N_R) |
+ /* NIC_RESET_N */
+ (1 << CDRU_MISC_RESET_CONTROL__CDRU_NITRO_RESET_N_R)
+ );
+
+ /* Wait until Nitro is out of reset */
+ timeout = NIC_RESET_RELEASE_TIMEOUT_US;
+ do {
+ uint32_t value;
+
+ value = bcm_chimp_read_ctrl(CHIMP_REG_CTRL_BPE_MODE_REG);
+ if ((value & CHIMP_BPE_MODE_ID_MASK) ==
+ CHIMP_BPE_MODE_ID_PATTERN)
+ break;
+ udelay(1);
+ } while (--timeout);
+
+ if (timeout == 0) {
+ ERROR("NIC reset release timed out\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void bcm_nitro_secure_mode_enable(void)
+{
+ mmio_setbits_32(CDRU_NITRO_CONTROL,
+ (1 << CDRU_NITRO_CONTROL__CDRU_NITRO_SEC_MODE_R) |
+ (1 << CDRU_NITRO_CONTROL__CDRU_NITRO_SEC_OVERRIDE_R));
+ mmio_write_32(NITRO_TZPC_TZPCDECPROT0clr,
+ /* NITRO_TZPC */
+ 1 << NITRO_TZPC_TZPCDECPROT0clr__DECPROT0_chimp_m_clr_R);
+}
+
+static int bcm_chimp_reset_and_initial_setup(void)
+{
+
+ int err;
+ uint32_t handshake_reg;
+
+ err = bcm_chimp_nitro_reset();
+ if (err)
+ return err;
+
+ /* Enable Nitro secure mode */
+ bcm_nitro_secure_mode_enable();
+
+ /* Force ChiMP back into reset */
+ bcm_chimp_setbits(CHIMP_CTRL_ADDR(CHIMP_REG_CTRL_BPE_MODE_REG),
+ 1 << CHIMP_REG_CHIMP_REG_CTRL_BPE_MODE_REG__cm3_rst_R);
+
+ handshake_reg = (1 << SR_IN_SMARTNIC_MODE_BIT);
+
+ /* Get OTP secure Chimp boot status */
+ if (mmio_read_32(CRMU_OTP_STATUS) & (1 << CRMU_OTP_STATUS_BIT))
+ handshake_reg |= (1 << SR_CHIMP_SECURE_BOOT_BIT);
+
+ bcm_chimp_write(CHIMP_REG_ECO_RESERVED, handshake_reg);
+
+ CHIMP_DBG("ChiMP reset and initial handshake parameters set\n");
+
+ return 0;
+}
+
+static void bcm_nitro_chimp_release_reset(void)
+{
+ bcm_chimp_clrbits(CHIMP_CTRL_ADDR(CHIMP_REG_CTRL_BPE_MODE_REG),
+ 1 << CHIMP_REG_CHIMP_REG_CTRL_BPE_MODE_REG__cm3_rst_R);
+
+ CHIMP_DBG("Nitro Reset Released\n");
+}
+
+static void bcm_chimp_set_fastboot(int mode)
+{
+ uint32_t fb_entry;
+
+ /* 1. Enable fastboot */
+ bcm_chimp_setbits(CHIMP_CTRL_ADDR(CHIMP_REG_CTRL_BPE_MODE_REG),
+ (1 << CHIMP_FAST_BOOT_MODE_BIT));
+ fb_entry = CHIMP_FASTBOOT_ADDR | mode;
+ if (mode == CHIMP_FASTBOOT_JUMP_IN_PLACE)
+ fb_entry = CHIMP_FB1_ENTRY;
+ /* 2. Write startup address and mode */
+ INFO("Setting fastboot type %d entry to 0x%x\n", mode, fb_entry);
+ bcm_chimp_write(
+ CHIMP_CTRL_ADDR(CHIMP_REG_CTRL_FSTBOOT_PTR_REG),
+ fb_entry);
+}
+
+#ifndef CHIMPFW_USE_SIDELOAD
+static void bcm_chimp_load_fw_from_spi(uintptr_t spi_addr, size_t size)
+{
+ uintptr_t ape_scpad;
+ uintptr_t dest;
+ size_t bytes_left;
+
+ ape_scpad = CHIMP_REG_CHIMP_APE_SCPAD;
+ dest = CHIMP_INDIRECT_TGT_ADDR(CHIMP_REG_CHIMP_APE_SCPAD);
+ bytes_left = size;
+
+ while (bytes_left) {
+ uint32_t delta;
+
+ delta = bytes_left > CHIMP_WINDOW_SIZE ?
+ bytes_left - CHIMP_WINDOW_SIZE : bytes_left;
+ CHIMP_PREPARE_ACCESS_WINDOW(ape_scpad);
+ INFO("Transferring %d byte(s) from 0x%lx to 0x%lx\n",
+ delta, spi_addr, dest);
+ /*
+ * This single memcpy call takes significant amount of time
+ * on Palladium. Be patient
+ */
+ memcpy((void *)dest, (void *)spi_addr, delta);
+ bytes_left -= delta;
+ INFO("Transferred %d byte(s) from 0x%lx to 0x%lx (%lu%%)\n",
+ delta, spi_addr, dest,
+ ((size - bytes_left) * 100)/size);
+ spi_addr += delta;
+ dest += delta;
+ ape_scpad += delta;
+ }
+}
+
+static int bcm_chimp_find_fw_in_spi(uintptr_t *addr, size_t *size)
+{
+ int i;
+ bnxnvm_master_block_header_t *master_block_hdr;
+ bnxnvm_directory_block_header_t *dir_block_hdr;
+ bnxnvm_directory_entry_t *dir_entry;
+ int found;
+
+ found = 0;
+
+ /* Read the master block */
+ master_block_hdr =
+ (bnxnvm_master_block_header_t *)(uintptr_t)QSPI_BASE_ADDR;
+ if (master_block_hdr->sig != BNXNVM_MASTER_BLOCK_SIG) {
+ WARN("Invalid masterblock 0x%x (expected 0x%x)\n",
+ master_block_hdr->sig,
+ BNXNVM_MASTER_BLOCK_SIG);
+ return -NV_NOT_NVRAM;
+ }
+ if ((master_block_hdr->block_size > NV_MAX_BLOCK_SIZE) ||
+ (master_block_hdr->directory_offset >=
+ master_block_hdr->nvram_size)) {
+ WARN("Invalid masterblock block size 0x%x or directory offset 0x%x\n",
+ master_block_hdr->block_size,
+ master_block_hdr->directory_offset);
+ return -NV_BAD_MB;
+ }
+
+ /* Skip to the Directory block start */
+ dir_block_hdr =
+ (bnxnvm_directory_block_header_t *)
+ ((uintptr_t)QSPI_BASE_ADDR +
+ master_block_hdr->directory_offset);
+ if (dir_block_hdr->sig != BNXNVM_DIRECTORY_BLOCK_SIG) {
+ WARN("Invalid directory header 0x%x (expected 0x%x)\n",
+ dir_block_hdr->sig,
+ BNXNVM_DIRECTORY_BLOCK_SIG);
+ return -NV_BAD_DIR_HEADER;
+ }
+
+ /* Locate the firmware */
+ for (i = 0; i < dir_block_hdr->entries; i++) {
+ *addr = ((uintptr_t)dir_block_hdr + dir_block_hdr->length +
+ i * dir_block_hdr->entry_length);
+ dir_entry = (bnxnvm_directory_entry_t *)(*addr);
+ if ((dir_entry->type == BNX_DIR_TYPE_BOOTCODE) ||
+ (dir_entry->type == BNX_DIR_TYPE_BOOTCODE_2)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return -NV_FW_NOT_FOUND;
+
+ *addr = QSPI_BASE_ADDR + dir_entry->item_location;
+ *size = dir_entry->data_length;
+
+ INFO("Found chimp firmware at 0x%lx, size %lu byte(s)\n",
+ *addr, *size);
+
+ return NV_OK;
+}
+#endif
+
+int bcm_chimp_initiate_fastboot(int fastboot_type)
+{
+ int err;
+
+ if ((fastboot_type != CHIMP_FASTBOOT_NITRO_RESET) &&
+ (fastboot_type <= CHIMP_FASTBOOT_JUMP_DECOMPRESS)) {
+ CHIMP_DBG("Initiating ChiMP fastboot type %d\n", fastboot_type);
+ }
+
+ /*
+ * If we are here, M0 did not setup Nitro because NIC mode
+ * strap was not present
+ */
+ err = bcm_chimp_reset_and_initial_setup();
+ if (err)
+ return err;
+
+ if (fastboot_type > CHIMP_FASTBOOT_JUMP_DECOMPRESS) {
+ WARN("ChiMP setup deferred\n");
+ return -1;
+ }
+
+ if (fastboot_type != CHIMP_FASTBOOT_NITRO_RESET) {
+
+ if ((fastboot_type == CHIMP_FASTBOOT_JUMP_IN_PLACE) &&
+ (CHIMP_FB1_ENTRY == 0)) {
+ ERROR("Missing ESAL entry point for fastboot type 1.\n"
+ "Fastboot failed\n");
+ return -1;
+ }
+
+ /*
+ * TODO: We need to think of the way to load the ChiMP fw.
+ * This could be SPI, NAND, etc.
+ * For now we temporarily stick to the SPI load unless
+ * CHIMPFW_USE_SIDELOAD is defined. Note that for the SPI NVRAM
+ * image we need to parse directory and get the image.
+ * When we load image from other media there is no need to
+ * parse because fw image can be directly placed into the APE's
+ * scratchpad.
+ * For sideload method we simply reset the ChiMP, set bpe_reg
+ * to do fastboot with the type we define, and release from
+ * reset so that ROM loader would initiate fastboot immediately
+ */
+#ifndef CHIMPFW_USE_SIDELOAD
+ {
+ uintptr_t spi_addr;
+ size_t size;
+
+ err = bcm_chimp_find_fw_in_spi(&spi_addr, &size);
+ if (!err) {
+ INFO("Loading ChiMP firmware, addr 0x%lx, size %lu byte(s)\n",
+ spi_addr, size);
+ bcm_chimp_load_fw_from_spi(spi_addr, size);
+ } else {
+ ERROR("Error %d ChiMP firmware not in NVRAM directory!\n",
+ err);
+ }
+ }
+#else
+ INFO("Skip ChiMP QSPI fastboot type %d due to sideload requested\n",
+ fastboot_type);
+#endif
+ if (!err) {
+ INFO("Instruct ChiMP to fastboot\n");
+ bcm_chimp_set_fastboot(fastboot_type);
+ INFO("Fastboot mode set\n");
+ }
+ }
+
+ bcm_nitro_chimp_release_reset();
+
+ return err;
+}
diff --git a/drivers/brcm/emmc/emmc_chal_sd.c b/drivers/brcm/emmc/emmc_chal_sd.c
new file mode 100644
index 0000000..34d761c
--- /dev/null
+++ b/drivers/brcm/emmc/emmc_chal_sd.c
@@ -0,0 +1,1017 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+#include "bcm_emmc.h"
+#include "emmc_chal_types.h"
+#include "emmc_chal_sd.h"
+#include "emmc_pboot_hal_memory_drv.h"
+
+extern void emmc_soft_reset(void);
+
+#define SD_VDD_WINDOW_1_6_TO_1_7 0x00000010 // 1.6 V to 1.7 Volts
+#define SD_VDD_WINDOW_1_7_TO_1_8 0x00000020 // 1.7 V to 1.8 Volts
+#define SD_VDD_WINDOW_1_8_TO_1_9 0x00000040 // 1.8 V to 1.9 Volts
+#define SD_VDD_WINDOW_1_9_TO_2_0 0x00000080 // 1.9 V to 2.0 Volts
+#define SD_VDD_WINDOW_2_0_TO_2_1 0x00000100 // 2.0 V to 2.1 Volts
+#define SD_VDD_WINDOW_2_1_TO_2_2 0x00000200 // 2.1 V to 2.2 Volts
+#define SD_VDD_WINDOW_2_2_TO_2_3 0x00000400 // 2.2 V to 2.3 Volts
+#define SD_VDD_WINDOW_2_3_TO_2_4 0x00000800 // 2.3 V to 2.4 Volts
+#define SD_VDD_WINDOW_2_4_TO_2_5 0x00001000 // 2.4 V to 2.5 Volts
+#define SD_VDD_WINDOW_2_5_TO_2_6 0x00002000 // 2.5 V to 2.6 Volts
+#define SD_VDD_WINDOW_2_6_TO_2_7 0x00004000 // 2.6 V to 2.7 Volts
+#define SD_VDD_WINDOW_2_7_TO_2_8 0x00008000 // 2.7 V to 2.8 Volts
+#define SD_VDD_WINDOW_2_8_TO_2_9 0x00010000 // 2.8 V to 2.9 Volts
+#define SD_VDD_WINDOW_2_9_TO_3_0 0x00020000 // 2.9 V to 3.0 Volts
+#define SD_VDD_WINDOW_3_0_TO_3_1 0x00040000 // 3.0 V to 3.1 Volts
+#define SD_VDD_WINDOW_3_1_TO_3_2 0x00080000 // 3.1 V to 3.2 Volts
+#define SD_VDD_WINDOW_3_2_TO_3_3 0x00100000 // 3.2 V to 3.3 Volts
+#define SD_VDD_WINDOW_3_3_TO_3_4 0x00200000 // 3.3 V to 3.4 Volts
+#define SD_VDD_WINDOW_3_4_TO_3_5 0x00400000 // 3.4 V to 3.5 Volts
+#define SD_VDD_WINDOW_3_5_TO_3_6 0x00800000 // 3.5 V to 3.6 Volts
+
+#define SD_VDD_WINDOW_1_6_TO_2_6 (SD_VDD_WINDOW_1_6_TO_1_7 | \
+ SD_VDD_WINDOW_1_7_TO_1_8 | \
+ SD_VDD_WINDOW_1_8_TO_1_9 | \
+ SD_VDD_WINDOW_1_9_TO_2_0 | \
+ SD_VDD_WINDOW_2_0_TO_2_1 | \
+ SD_VDD_WINDOW_2_1_TO_2_2 | \
+ SD_VDD_WINDOW_2_2_TO_2_3 | \
+ SD_VDD_WINDOW_2_3_TO_2_4 | \
+ SD_VDD_WINDOW_2_4_TO_2_5 | \
+ SD_VDD_WINDOW_2_5_TO_2_6)
+
+#define SD_VDD_WINDOW_2_6_TO_3_2 (SD_VDD_WINDOW_2_6_TO_2_7 | \
+ SD_VDD_WINDOW_2_7_TO_2_8 | \
+ SD_VDD_WINDOW_2_8_TO_2_9 | \
+ SD_VDD_WINDOW_2_9_TO_3_0 | \
+ SD_VDD_WINDOW_3_0_TO_3_1 | \
+ SD_VDD_WINDOW_3_1_TO_3_2)
+
+#define SD_VDD_WINDOW_3_2_TO_3_6 (SD_VDD_WINDOW_3_2_TO_3_3 | \
+ SD_VDD_WINDOW_3_3_TO_3_4 | \
+ SD_VDD_WINDOW_3_4_TO_3_5 | \
+ SD_VDD_WINDOW_3_5_TO_3_6)
+
+
+static int32_t chal_sd_set_power(struct sd_dev *handle,
+ uint32_t voltage, uint32_t state);
+
+static void chal_sd_set_dma_boundary(struct sd_dev *handle, uint32_t boundary);
+
+static int32_t chal_sd_setup_handler(struct sd_dev *handle,
+ uint32_t sdBbase, uint32_t hostBase);
+
+/*
+ * Configure host controller pwr settings,
+ * to match voltage requirements by SD Card
+ */
+static int32_t chal_sd_set_power(struct sd_dev *handle,
+ uint32_t voltage, uint32_t state)
+{
+ int32_t rc, rval = SD_FAIL;
+ uint32_t time = 0;
+
+ if (handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ mmio_clrsetbits_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_CTRL_OFFSET,
+ (SD4_EMMC_TOP_CTRL_SDVSELVDD1_MASK |
+ SD4_EMMC_TOP_CTRL_SDPWR_MASK),
+ (voltage << 9));
+
+ /*
+ * Long delay is required here in emulation. Without this, the initial
+ * commands sent to the eMMC card timeout. We don't know if this
+ * delay is necessary with silicon, leaving in for safety.
+ * It is observed that 403ms on emulation system and as per the clock
+ * calculations it is expected to complete with in 1ms on chip
+ */
+ do {
+ rc = mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_INTR_OFFSET);
+
+ if ((rc & SD4_EMMC_TOP_INTR_CRDINS_MASK) ==
+ SD4_EMMC_TOP_INTR_CRDINS_MASK)
+ break;
+
+ mdelay(1);
+ } while (time++ < EMMC_CARD_DETECT_TIMEOUT_MS);
+
+ if (time >= EMMC_CARD_DETECT_TIMEOUT_MS) {
+ ERROR("EMMC: Card insert event detection timeout\n");
+ return rval;
+ }
+
+ VERBOSE("EMMC: Card detection delay: %dms\n", time);
+
+ if (state)
+ mmio_setbits_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CTRL_OFFSET,
+ SD4_EMMC_TOP_CTRL_SDPWR_MASK);
+
+ /* dummy write & ack to verify if the sdio is ready to send commads */
+ mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_ARG_OFFSET, 0);
+ mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CMD_OFFSET, 0);
+
+ /*
+ * 63ms observed on emulation system, As per clock calculations
+ * it will complete < 1ms on chip.
+ */
+ time = 0;
+ do {
+ rc = mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_INTR_OFFSET);
+
+ if (rc & SD4_EMMC_TOP_INTR_ERRIRQ_MASK)
+ break;
+
+ if ((rc & SD4_EMMC_TOP_INTR_CMDDONE_MASK) ==
+ SD4_EMMC_TOP_INTR_CMDDONE_MASK)
+ break;
+
+ mdelay(1);
+ } while (time++ < EMMC_CMD_TIMEOUT_MS);
+
+ if (time >= EMMC_CMD_TIMEOUT_MS) {
+ WARN("%s %d Initial dummy command timeout is happened\n",
+ __func__, __LINE__);
+ return rval;
+ }
+
+ VERBOSE("EMMC: Dummy Command delay: %dms\n", time);
+
+ return SD_OK;
+}
+
+/*
+ * Configure DMA Boundaries
+ */
+static void chal_sd_set_dma_boundary(struct sd_dev *handle, uint32_t boundary)
+{
+ if (handle == NULL)
+ return;
+
+ mmio_clrsetbits_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_BLOCK_OFFSET,
+ SD4_EMMC_TOP_BLOCK_HSBS_MASK, boundary);
+}
+
+static int32_t chal_sd_setup_handler(struct sd_dev *handle, uint32_t sdBase,
+ uint32_t hostBase)
+{
+ if (handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle->ctrl.sdRegBaseAddr = sdBase;
+ handle->ctrl.hostRegBaseAddr = hostBase;
+ handle->ctrl.present = 0;
+ handle->ctrl.rca = 0;
+ handle->ctrl.blkGapEnable = 0;
+ handle->ctrl.cmdStatus = 0;
+
+ return SD_OK;
+}
+
+/*
+ * Initialize SD Host controller
+ */
+int32_t chal_sd_init(CHAL_HANDLE *sd_handle)
+{
+ uint32_t cap_val_l = 0;
+ uint32_t ctl_val, voltage;
+ uint32_t timeout_val;
+ struct sd_dev *handle;
+ uint32_t reg_val;
+ int32_t rval = SD_FAIL;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *)sd_handle;
+
+ /*
+ * Set SDIO Host Controller capabilities register
+ */
+ EMMC_TRACE("Set Host Controller Capabilities register\n");
+
+ reg_val = 0;
+ reg_val |= (1 << ICFG_SDIO0_CAP0__SLOT_TYPE_R);
+ reg_val |= (0 << ICFG_SDIO0_CAP0__INT_MODE_R);
+ reg_val |= (0 << ICFG_SDIO0_CAP0__SYS_BUS_64BIT_R);
+ reg_val |= (1 << ICFG_SDIO0_CAP0__VOLTAGE_1P8V_R);
+ reg_val |= (1 << ICFG_SDIO0_CAP0__VOLTAGE_3P0V_R);
+ reg_val |= (1 << ICFG_SDIO0_CAP0__VOLTAGE_3P3V_R);
+ reg_val |= (1 << ICFG_SDIO0_CAP0__SUSPEND_RESUME_R);
+ reg_val |= (1 << ICFG_SDIO0_CAP0__SDMA_R);
+ reg_val |= (1 << ICFG_SDIO0_CAP0__HIGH_SPEED_R);
+ reg_val |= (1 << ICFG_SDIO0_CAP0__ADMA2_R);
+ reg_val |= (1 << ICFG_SDIO0_CAP0__EXTENDED_MEDIA_R);
+ reg_val |= (2 << ICFG_SDIO0_CAP0__MAX_BLOCK_LEN_R);
+ reg_val |= (0xd0 << ICFG_SDIO0_CAP0__BASE_CLK_FREQ_R);
+ reg_val |= (1 << ICFG_SDIO0_CAP0__TIMEOUT_UNIT_R);
+ reg_val |= (0x30 << ICFG_SDIO0_CAP0__TIMEOUT_CLK_FREQ_R);
+
+ mmio_write_32(ICFG_SDIO0_CAP0, reg_val);
+
+ reg_val = 0;
+ reg_val |= (1 << ICFG_SDIO0_CAP1__SPI_BLOCK_MODE_R);
+ reg_val |= (1 << ICFG_SDIO0_CAP1__SPI_MODE_R);
+ reg_val |= (0 << ICFG_SDIO0_CAP1__CLK_MULT_R);
+ reg_val |= (0 << ICFG_SDIO0_CAP1__RETUNING_MODE_R);
+ reg_val |= (1 << ICFG_SDIO0_CAP1__TUNE_SDR50_R);
+ reg_val |= (1 << ICFG_SDIO0_CAP1__TIME_RETUNE_R);
+ reg_val |= (1 << ICFG_SDIO0_CAP1__DRIVER_D_R);
+ reg_val |= (1 << ICFG_SDIO0_CAP1__DRIVER_C_R);
+ reg_val |= (1 << ICFG_SDIO0_CAP1__DRIVER_A_R);
+ reg_val |= (1 << ICFG_SDIO0_CAP1__DDR50_R);
+ reg_val |= (1 << ICFG_SDIO0_CAP1__SDR104_R);
+ reg_val |= (1 << ICFG_SDIO0_CAP1__SDR50_R);
+
+ mmio_write_32(ICFG_SDIO0_CAP1, reg_val);
+
+ /* Reset the SDIO controller */
+ chal_sd_stop();
+
+ /* Turn on SD clock */
+ chal_sd_set_clock(sd_handle,
+ chal_sd_freq_2_div_ctrl_setting(INIT_CLK_FREQ), 1);
+
+ /* program data time out value to the max */
+ timeout_val = SD_HOST_CORE_TIMEOUT;
+
+ ctl_val = mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_CTRL1_OFFSET);
+ ctl_val |= ((timeout_val & 0xf) << SD4_EMMC_TOP_CTRL1_DTCNT_SHIFT);
+
+ mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CTRL1_OFFSET,
+ ctl_val);
+
+ /* enable all interrupt status */
+ mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_INTREN1_OFFSET,
+ 0);
+ mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_INTREN2_OFFSET,
+ 0);
+
+ SD_US_DELAY(100);
+
+ mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_INTREN1_OFFSET,
+ SD_NOR_INTERRUPTS | SD_ERR_INTERRUPTS);
+ mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_INTREN2_OFFSET,
+ SD_NOR_INTERRUPTS | SD_ERR_INTERRUPTS);
+
+ /* Select SD bus voltage */
+ cap_val_l = mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_CAPABILITIES1_OFFSET);
+ handle->cfg.voltage = 0;
+ voltage = 0x7;
+
+ if (cap_val_l & SD4_EMMC_TOP_CAPABILITIES1_V33_MASK) {
+ handle->cfg.voltage |= SD_VDD_WINDOW_3_3_TO_3_4;
+ voltage = 0x7;
+ } else if (cap_val_l & SD4_EMMC_TOP_CAPABILITIES1_V3_MASK) {
+ handle->cfg.voltage |= SD_VDD_WINDOW_3_0_TO_3_1;
+ voltage = 0x6;
+ } else if (cap_val_l & SD4_EMMC_TOP_CAPABILITIES1_V18_MASK) {
+ handle->cfg.voltage |= SD_VDD_WINDOW_1_8_TO_1_9;
+ voltage = 0x5;
+ }
+
+ rval = chal_sd_set_power(handle, voltage, SD4_EMMC_TOP_CTRL_SDPWR_MASK);
+
+ ctl_val = mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_HCVERSIRQ_OFFSET);
+ handle->ctrl.version = ((ctl_val >> 16) & 0xFF);
+
+ return rval;
+}
+
+void chal_sd_set_speed(CHAL_HANDLE *sd_handle, uint32_t speed)
+{
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return;
+
+ handle = (struct sd_dev *) sd_handle;
+
+ if (speed) {
+ EMMC_TRACE("enable HighSpeed\n");
+ mmio_setbits_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_CTRL_OFFSET,
+ SD4_EMMC_TOP_CTRL_HSEN_MASK);
+ } else {
+ EMMC_TRACE("disable HighSpeed\n");
+ mmio_clrbits_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_CTRL_OFFSET,
+ SD4_EMMC_TOP_CTRL_HSEN_MASK);
+ }
+}
+
+int32_t chal_sd_stop(void)
+{
+ uintptr_t idm_rst_ctrl_addr = EMMC_IDM_RESET_CTRL_ADDR;
+
+ /* Configure IO pins */
+ emmc_soft_reset();
+
+ /* Reset the SDIO controller */
+ mmio_write_32(idm_rst_ctrl_addr, 1);
+ SD_US_DELAY(100);
+ mmio_write_32(idm_rst_ctrl_addr, 0);
+ SD_US_DELAY(100);
+
+ return SD_OK;
+}
+
+/*
+ * Check if host supports specified capability
+ * returns -ve val on error, 0 if capability not supported else 1.
+ */
+int32_t chal_sd_check_cap(CHAL_HANDLE *sd_handle, uint32_t caps)
+{
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *) sd_handle;
+
+ if (caps & mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_CAPABILITIES1_OFFSET))
+ return 1;
+ else
+ return 0;
+}
+
+int32_t chal_sd_start(CHAL_HANDLE *sd_handle,
+ uint32_t mode, uint32_t sd_base, uint32_t host_base)
+{
+
+ struct sd_dev *handle;
+ int32_t rval = SD_FAIL;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *) sd_handle;
+
+ handle->cfg.mode = SD_PIO_MODE; /* set to PIO mode first for init */
+ handle->cfg.dma = SD_DMA_OFF;
+
+ chal_sd_setup_handler(handle, sd_base, host_base);
+
+ /* init and start hw */
+ rval = chal_sd_init(sd_handle);
+ if (rval != SD_OK)
+ return rval;
+
+ chal_sd_clear_pending_irq(sd_handle);
+
+ handle->ctrl.eventList = 0;
+ handle->cfg.mode = mode;
+
+ return SD_OK;
+}
+
+/*
+ * Function to check 8bits of err generated from auto CMD12
+ */
+int32_t chal_sd_get_atuo12_error(CHAL_HANDLE *sd_handle)
+{
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *) sd_handle;
+
+ return (mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_ERRSTAT_OFFSET) & 0xFF);
+}
+
+/*
+ * Read present state register
+ */
+uint32_t chal_sd_get_present_status(CHAL_HANDLE *sd_handle)
+{
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *) sd_handle;
+
+ return mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_PSTATE_OFFSET);
+}
+
+/*
+ * Set SD bus width
+ */
+int32_t chal_sd_config_bus_width(CHAL_HANDLE *sd_handle, int32_t width)
+{
+ uint32_t ctl_val;
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *)sd_handle;
+
+ ctl_val = mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_CTRL_OFFSET);
+
+ switch (width) {
+#ifdef DRIVER_EMMC_ENABLE_DATA_WIDTH_8BIT
+ case SD_BUS_DATA_WIDTH_8BIT:
+ ctl_val &= ~SD_BUS_DATA_WIDTH_4BIT;
+ ctl_val |= SD_BUS_DATA_WIDTH_8BIT;
+ break;
+#endif
+ case SD_BUS_DATA_WIDTH_4BIT:
+ ctl_val &= ~SD_BUS_DATA_WIDTH_8BIT;
+ ctl_val |= SD_BUS_DATA_WIDTH_4BIT;
+ break;
+ case SD_BUS_DATA_WIDTH_1BIT:
+ ctl_val &= ~(SD_BUS_DATA_WIDTH_4BIT | SD_BUS_DATA_WIDTH_8BIT);
+ break;
+ default:
+ return SD_INV_DATA_WIDTH;
+ };
+
+ mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CTRL_OFFSET,
+ ctl_val);
+
+ return SD_OK;
+}
+
+/*
+ * Function to enable or disable DMA control.
+ */
+int32_t chal_sd_set_dma(CHAL_HANDLE *sd_handle, uint32_t mode)
+{
+ uint32_t val;
+ struct sd_dev *handle;
+ int32_t rc;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *)sd_handle;
+
+ if (mode) {
+ rc = chal_sd_check_cap(sd_handle,
+ SD4_EMMC_TOP_CAPABILITIES1_SDMA_MASK |
+ SD4_EMMC_TOP_CAPABILITIES1_ADMA2_MASK);
+ if (rc < 0)
+ return rc;
+
+ if (rc) {
+
+ handle->cfg.dma = mode;
+ val = mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_CTRL_OFFSET);
+ val &= ~(SD4_EMMC_TOP_CTRL_DMASEL_MASK);
+ val |= handle->cfg.dma - 1;
+ mmio_write_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_CTRL_OFFSET, val);
+ return SD_OK;
+ }
+ }
+ handle->cfg.dma = 0;
+
+ return SD_FAIL;
+}
+
+/*
+ * Get current DMA address.
+ * Called only when there is no data transaction activity.
+ */
+uintptr_t chal_sd_get_dma_addr(CHAL_HANDLE *sd_handle)
+{
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *) sd_handle;
+
+ if (handle->cfg.dma == SD_DMA_OFF)
+ return 0;
+
+ return (uintptr_t)mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_SYSADDR_OFFSET);
+}
+
+int32_t chal_sd_send_cmd(CHAL_HANDLE *sd_handle, uint32_t cmd_idx,
+ uint32_t argument, uint32_t options)
+{
+ uint32_t cmd_mode_reg = 0;
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *) sd_handle;
+
+ EMMC_TRACE("%s %d cmd:%d argReg:%x options:%x\n",
+ __func__, __LINE__, cmd_idx, argument, options);
+
+ /* Configure the value for command and mode registers */
+ cmd_mode_reg = (cmd_idx << 24) | options;
+
+ /*
+ * 1. Write block size reg & block count reg,
+ * this is done in the tx or rx setup
+ */
+ mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_BLOCK_OFFSET,
+ handle->ctrl.blkReg);
+
+ /* 2. Write argument reg */
+ mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_ARG_OFFSET,
+ argument);
+ handle->ctrl.argReg = argument;
+
+ /*
+ * 3. Write transfer mode reg & command reg, check the DMA bit which is
+ * set before this function call if it is selected.
+ */
+ if (cmd_idx == 24 || cmd_idx == 25 || cmd_idx == 18 || cmd_idx == 17 ||
+ cmd_idx == 42 || cmd_idx == 51 || cmd_idx == 53)
+ cmd_mode_reg |= ((handle->cfg.dma) ? 1 : 0);
+
+ mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CMD_OFFSET,
+ cmd_mode_reg);
+
+ handle->ctrl.cmdIndex = cmd_idx;
+
+ return SD_OK;
+}
+
+int32_t chal_sd_set_dma_addr(CHAL_HANDLE *sd_handle, uintptr_t address)
+{
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *) sd_handle;
+
+ if (handle->cfg.dma == SD_DMA_OFF)
+ return SD_FAIL;
+
+ mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_SYSADDR_OFFSET,
+ address);
+ return SD_OK;
+}
+
+uint32_t chal_sd_freq_2_div_ctrl_setting(uint32_t desired_freq)
+{
+ /*
+ * Divider control setting represents 1/2 of the actual divider value.
+ *
+ * DesiredFreq = BaseClockFreq / (2 * div_ctrl_setting)
+ *
+ * ==> div_ctrl_setting = BaseClockFreq / (2 * DesiredFreq)
+ */
+ uint32_t div_ctrl_setting;
+ uint32_t actual_freq;
+
+ assert(desired_freq != 0);
+
+ /* Special case, 0 = divider of 1. */
+ if (desired_freq >= BASE_CLK_FREQ)
+ return 0;
+
+ /* Normal case, desired_freq < BASE_CLK_FREQ */
+ div_ctrl_setting = BASE_CLK_FREQ / (2 * desired_freq);
+
+ actual_freq = BASE_CLK_FREQ / (2 * div_ctrl_setting);
+
+ if (actual_freq > desired_freq) {
+ /*
+ * Division does not result in exact freqency match.
+ * Make sure resulting frequency does not exceed requested freq.
+ */
+ div_ctrl_setting++;
+ }
+
+ return div_ctrl_setting;
+}
+
+int32_t chal_sd_set_clock(CHAL_HANDLE *sd_handle, uint32_t div_ctrl_setting,
+ uint32_t on)
+{
+ uint32_t value;
+ struct sd_dev *handle;
+ uint32_t time;
+ uint32_t clk_sel_high_byte = 0xFF & (div_ctrl_setting >> 8);
+ uint32_t clk_sel_low_byte = 0xFF & div_ctrl_setting;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ EMMC_TRACE("set_clock(div_ctrl_setting=%d,on=%d)\n",
+ div_ctrl_setting, on);
+
+ handle = (struct sd_dev *) sd_handle;
+
+ /* Read control register content. */
+ value = mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_CTRL1_OFFSET);
+
+ /* Disable Clock */
+ value &= ~(SD4_EMMC_TOP_CTRL1_SDCLKEN_MASK);
+
+ mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CTRL1_OFFSET,
+ value);
+
+ /* Clear bits of interest. */
+ value &= ~(SD4_EMMC_TOP_CTRL1_SDCLKSEL_MASK |
+ SD4_EMMC_TOP_CTRL1_SDCLKSEL_UP_MASK);
+
+ /* Set bits of interest to new value. */
+ value |= (SD4_EMMC_TOP_CTRL1_SDCLKSEL_MASK &
+ (clk_sel_low_byte << SD4_EMMC_TOP_CTRL1_SDCLKSEL_SHIFT));
+ value |= (SD4_EMMC_TOP_CTRL1_SDCLKSEL_UP_MASK &
+ (clk_sel_high_byte << SD4_EMMC_TOP_CTRL1_SDCLKSEL_UP_SHIFT));
+ value |= SD4_EMMC_TOP_CTRL1_ICLKEN_MASK;
+
+ /* Write updated value back to control register. */
+ mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CTRL1_OFFSET,
+ value);
+
+ time = 0;
+ do {
+ value = mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_CTRL1_OFFSET);
+
+ if ((value & SD4_EMMC_TOP_CTRL1_ICLKSTB_MASK) ==
+ SD4_EMMC_TOP_CTRL1_ICLKSTB_MASK)
+ break;
+
+ mdelay(1);
+ } while (time++ < EMMC_CLOCK_SETTING_TIMEOUT_MS);
+
+ if (time >= EMMC_CLOCK_SETTING_TIMEOUT_MS)
+ WARN("%s %d clock settings timeout happenedi (%dms)\n",
+ __func__, __LINE__, time);
+
+ VERBOSE("EMMC: clock settings delay: %dms\n", time);
+
+ value = mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_CTRL1_OFFSET);
+
+ if (on)
+ value |= SD4_EMMC_TOP_CTRL1_SDCLKEN_MASK;
+
+ mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CTRL1_OFFSET,
+ value);
+
+ return SD_OK;
+}
+
+/*
+ * function to setup DMA buffer and data length, calculates block
+ * size and the number of blocks to be transferred and return
+ * the DMA buffer address.
+ */
+int32_t chal_sd_setup_xfer(CHAL_HANDLE *sd_handle,
+ uint8_t *data, uint32_t length, int32_t dir)
+{
+ uint32_t blocks = 0;
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *) sd_handle;
+
+ if (length <= handle->cfg.blockSize) {
+ handle->ctrl.blkReg = length | handle->cfg.dmaBoundary;
+ } else {
+ blocks = length / handle->cfg.blockSize;
+ handle->ctrl.blkReg = (blocks << 16) | handle->cfg.blockSize |
+ handle->cfg.dmaBoundary;
+ }
+
+ if (handle->cfg.dma != SD_DMA_OFF) {
+ /* For DMA target address setting, physical address should be used */
+ mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_SYSADDR_OFFSET,
+ (uintptr_t)data);
+ }
+
+ return SD_OK;
+}
+
+#ifdef INCLUDE_EMMC_DRIVER_WRITE_CODE
+/*
+ * function to write one block data directly to the
+ * host controller's FIFO which is 1K uint8_t or
+ * 2K uint8_t in size.
+ * It is used in Non-DMA mode for data transmission.
+ */
+int32_t chal_sd_write_buffer(CHAL_HANDLE *sd_handle, uint32_t length,
+ uint8_t *data)
+{
+ uint32_t i, leftOver = 0, blockSize, size, value = 0;
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *) sd_handle;
+
+ blockSize = handle->cfg.blockSize;
+
+ if (length == 0)
+ return SD_OK;
+
+ /* PIO mode, push into fifo word by word */
+ if (length >= blockSize) {
+ size = blockSize;
+ } else {
+ size = ((length >> 2) << 2);
+ leftOver = length % 4;
+ }
+
+ for (i = 0; i < size; i += 4) {
+ value = *(uint32_t *)(data + i);
+ mmio_write_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_BUFDAT_OFFSET, value);
+ }
+/*
+ * BUG ALERT:
+ * This implementation has TWO issues that must be addressed before you
+ * can safely INCLUDE_EMMC_DRIVER_WRITE_CODE.
+ *
+ * (1) For the last leftOver bytes, driver writes full word, which means
+ * some of the eMMC content (i.e. "4 - leftOver" will be erroneously
+ * overwritten).
+ * (2) eMMC is a block device. What happens when less than a full block of
+ * data is submitted???
+ */
+ if (leftOver > 0) {
+ value = ((*(uint32_t *)(data + i)) << (4 - leftOver));
+ mmio_write_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_BUFDAT_OFFSET, value);
+ }
+
+ return SD_OK;
+}
+#endif /* INCLUDE_EMMC_DRIVER_WRITE_CODE */
+
+/*
+ * Function to read maximal one block data directly
+ * from the data port of the host controller (FIFO). It is used
+ * in Non-DMA mode for data transmission.
+ */
+int32_t chal_sd_read_buffer(CHAL_HANDLE *sd_handle, uint32_t length,
+ uint8_t *data)
+{
+ uint32_t i, size, leftOver, blockSize, value;
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *)sd_handle;
+
+ value = 0;
+
+ blockSize = handle->cfg.blockSize;
+
+ /* PIO mode, extract fifo word by word */
+ if (length >= blockSize) {
+ size = blockSize;
+ leftOver = 0;
+ } else {
+ leftOver = length % 4;
+ size = ((length >> 2) << 2);
+ }
+
+ for (i = 0; i < size; i += 4) {
+ value =
+ mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_BUFDAT_OFFSET);
+ memcpy((void *)(data + i), &value, sizeof(uint32_t));
+ }
+
+ if (leftOver > 0) {
+ value = mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_BUFDAT_OFFSET);
+
+ /*
+ * Copy remaining non-full word bytes.
+ * (We run ARM as Little Endian)
+ */
+ uint8_t j = 0;
+
+ for (j = 0; j < leftOver; j++) {
+ data[i + j] = (value >> (j * 8)) & 0xFF;
+ }
+ }
+
+ return SD_OK;
+}
+
+/*
+ * Resets both DAT or CMD line.
+ */
+int32_t chal_sd_reset_line(CHAL_HANDLE *sd_handle, uint32_t line)
+{
+ uint32_t control, flag;
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *) sd_handle;
+
+ flag = SD4_EMMC_TOP_CTRL1_CMDRST_MASK | SD4_EMMC_TOP_CTRL1_DATRST_MASK;
+
+ if (flag != (line | flag))
+ return SD_FAIL;
+
+ control = mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_CTRL1_OFFSET);
+ control |= line;
+ mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CTRL1_OFFSET,
+ control);
+
+ /* reset CMD and DATA line should always work, no need to timed out */
+ do {
+ control = mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_CTRL1_OFFSET);
+ } while (control & line);
+
+ return SD_OK;
+}
+
+/*
+ * Function to be called once a SD command is done to read
+ * back it's response data.
+ */
+int32_t chal_sd_get_response(CHAL_HANDLE *sd_handle, uint32_t *resp)
+{
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *) sd_handle;
+ resp[0] = mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_RESP0_OFFSET);
+ resp[1] = mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_RESP2_OFFSET);
+ resp[2] = mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_RESP4_OFFSET);
+ resp[3] = mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_RESP6_OFFSET);
+
+ return SD_OK;
+}
+
+/*
+ * The function is called to clean all the pending interrupts.
+ */
+int32_t chal_sd_clear_pending_irq(CHAL_HANDLE *sd_handle)
+{
+ uint32_t status = SD_OK;
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *)sd_handle;
+
+ /* Make sure clean all interrupts */
+ do {
+ mmio_write_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_INTR_OFFSET, 0xFFFFFFFF);
+ SD_US_DELAY(10);
+ } while (mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_INTR_OFFSET));
+
+ return status;
+}
+
+/*
+ * The function returns interrupt status register value.
+ */
+int32_t chal_sd_get_irq_status(CHAL_HANDLE *sd_handle)
+{
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *) sd_handle;
+
+ return (mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_INTR_OFFSET));
+}
+
+/*
+ * The function clears interrupt(s) specified in the mask.
+ */
+int32_t chal_sd_clear_irq(CHAL_HANDLE *sd_handle, uint32_t mask)
+{
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *) sd_handle;
+
+ /* Make sure clean masked interrupts */
+ do {
+ mmio_write_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_INTR_OFFSET, mask);
+ SD_US_DELAY(10);
+ } while (mask &
+ mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_INTR_OFFSET));
+
+ return SD_OK;
+}
+
+/*
+ * Description: The function configures the SD host controller.
+ */
+int32_t chal_sd_config(CHAL_HANDLE *sd_handle, uint32_t speed, uint32_t retry,
+ uint32_t boundary, uint32_t blkSize, uint32_t dma)
+{
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return SD_INVALID_HANDLE;
+
+ handle = (struct sd_dev *) sd_handle;
+
+ handle->cfg.speedMode = speed;
+ handle->cfg.retryLimit = retry;
+ handle->cfg.dmaBoundary = boundary;
+ handle->cfg.blockSize = blkSize;
+
+ chal_sd_set_dma(sd_handle, dma);
+ SD_US_DELAY(100);
+ chal_sd_set_dma_boundary(handle, boundary);
+ SD_US_DELAY(100);
+
+ chal_sd_set_speed(sd_handle, speed);
+
+ SD_US_DELAY(100);
+ return SD_OK;
+}
+
+/*
+ * Cleans up HC FIFO.
+ */
+void chal_sd_dump_fifo(CHAL_HANDLE *sd_handle)
+{
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return;
+
+ handle = (struct sd_dev *)sd_handle;
+
+ /* in case there still data in the host buffer */
+ while (mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_PSTATE_OFFSET) & 0x800) {
+ mmio_read_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_BUFDAT_OFFSET);
+ };
+}
+
+/*
+ * Enable or disable a SD interrupt signal.
+ */
+void chal_sd_set_irq_signal(CHAL_HANDLE *sd_handle, uint32_t mask,
+ uint32_t state)
+{
+ struct sd_dev *handle;
+
+ if (sd_handle == NULL)
+ return;
+
+ handle = (struct sd_dev *)sd_handle;
+
+ if (state)
+ mmio_setbits_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_INTREN2_OFFSET, mask);
+ else
+ mmio_clrbits_32(handle->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_INTREN2_OFFSET, mask);
+}
diff --git a/drivers/brcm/emmc/emmc_csl_sdcard.c b/drivers/brcm/emmc/emmc_csl_sdcard.c
new file mode 100644
index 0000000..9e2c618
--- /dev/null
+++ b/drivers/brcm/emmc/emmc_csl_sdcard.c
@@ -0,0 +1,1089 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+
+#include "bcm_emmc.h"
+#include "emmc_chal_types.h"
+#include "emmc_csl_sdprot.h"
+#include "emmc_chal_sd.h"
+#include "emmc_csl_sdcmd.h"
+#include "emmc_csl_sd.h"
+#include "emmc_pboot_hal_memory_drv.h"
+
+#define SD_CARD_BUSY 0x80000000
+#define SD_CARD_RETRY_LIMIT 1000
+#define SD_CARD_HIGH_SPEED_PS 13
+#define SD_CHK_HIGH_SPEED_MODE 0x00FFFFF1
+#define SD_SET_HIGH_SPEED_MODE 0x80FFFFF1
+#define SD_MMC_ENABLE_HIGH_SPEED 0x03b90100 //0x03b90103
+#define SD_MMC_8BIT_MODE 0x03b70200
+#define SD_MMC_4BIT_MODE 0x03b70100
+#define SD_MMC_1BIT_MODE 0x03b70000
+
+#define SD_MMC_BOOT_8BIT_MODE 0x03b10200
+#define SD_MMC_BOOT_4BIT_MODE 0x03b10100
+#define SD_MMC_BOOT_1BIT_MODE 0x03b10000
+#define SDIO_HW_EMMC_EXT_CSD_BOOT_CNF 0X03B30000
+
+#ifdef USE_EMMC_FIP_TOC_CACHE
+/*
+ * Cache size mirrors the size of the global eMMC temp buffer
+ * which is used for non-image body reads such as headers, ToC etc.
+ */
+#define CACHE_SIZE ((EMMC_BLOCK_SIZE) * 2)
+#define PARTITION_BLOCK_ADDR ((PLAT_FIP_ATTEMPT_OFFSET)/(EMMC_BLOCK_SIZE))
+
+static uint32_t cached_partition_block;
+static uint8_t cached_block[CACHE_SIZE];
+#endif
+
+static int set_card_data_width(struct sd_handle *handle, int width);
+static int abort_err(struct sd_handle *handle);
+static int err_recovery(struct sd_handle *handle, uint32_t errors);
+static int xfer_data(struct sd_handle *handle, uint32_t mode, uint32_t addr,
+ uint32_t length, uint8_t *base);
+
+int set_boot_config(struct sd_handle *handle, uint32_t config)
+{
+ return mmc_cmd6(handle, SDIO_HW_EMMC_EXT_CSD_BOOT_CNF | config);
+}
+
+void process_csd_mmc_speed(struct sd_handle *handle, uint32_t csd_mmc_speed)
+{
+ uint32_t div_ctrl_setting;
+
+ /* CSD field TRAN_SPEED:
+ * Bits [2:0] 0 = 100 KHz
+ * 1 = 1 MHz
+ * 2 = 10 MHz
+ * 3 = 100 MHz
+ * 4...7 Reserved.
+ * Bits [6:3] 0 = Reserved
+ * 1 = 1.0
+ * 2 = 1.2
+ * 3 = 1.3
+ * 4 = 1.5
+ * 5 = 2.0
+ * 6 = 2.6
+ * 7 = 3.0
+ * 8 = 3.5
+ * 9 = 4.0
+ * A = 4.5
+ * B = 5.2
+ * C = 5.5
+ * D = 6.0
+ * E = 7.0
+ * F = 8.0
+ * For cards supporting version 4.0, 4.1, and 4.2 of the standard,
+ * the value shall be 20 MHz (0x2A).
+ * For cards supporting version 4.3 , the value shall be 26 MHz (0x32)
+ */
+
+ switch (csd_mmc_speed & 0x7F) {
+ case 0x2A:
+ EMMC_TRACE("Speeding up eMMC clock to 20MHz\n");
+ div_ctrl_setting =
+ chal_sd_freq_2_div_ctrl_setting(20 * 1000 * 1000);
+ break;
+ case 0x32:
+ EMMC_TRACE("Speeding up eMMC clock to 26MHz\n");
+ div_ctrl_setting =
+ chal_sd_freq_2_div_ctrl_setting(26 * 1000 * 1000);
+ break;
+ default:
+ /* Unknown */
+ return;
+ }
+
+ chal_sd_set_clock((CHAL_HANDLE *) handle->device, div_ctrl_setting, 0);
+
+ chal_sd_set_clock((CHAL_HANDLE *) handle->device, div_ctrl_setting, 1);
+
+ SD_US_DELAY(1000);
+}
+
+
+/*
+ * The function changes SD/SDIO/MMC card data width if
+ * the card support configurable data width. The host controller
+ * and the card has to be in the same bus data width.
+ */
+int set_card_data_width(struct sd_handle *handle, int width)
+{
+ uint32_t data_width = 0;
+ int is_valid_arg = 1;
+ int rc = SD_FAIL;
+ char *bitwidth_str = " ";
+ char *result_str = "failed";
+
+ switch (width) {
+#ifdef DRIVER_EMMC_ENABLE_DATA_WIDTH_8BIT
+ case SD_BUS_DATA_WIDTH_8BIT:
+ data_width = SD_MMC_8BIT_MODE;
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ bitwidth_str = "8_BIT";
+#endif
+ break;
+#endif
+ case SD_BUS_DATA_WIDTH_4BIT:
+ data_width = SD_MMC_4BIT_MODE;
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ bitwidth_str = "4_BIT";
+#endif
+ break;
+
+ case SD_BUS_DATA_WIDTH_1BIT:
+ data_width = SD_MMC_1BIT_MODE;
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ bitwidth_str = "1_BIT";
+#endif
+ break;
+
+ default:
+ is_valid_arg = 0;
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ bitwidth_str = "unknown";
+#endif
+ break;
+ }
+
+ if (is_valid_arg) {
+ rc = mmc_cmd6(handle, data_width);
+ if (rc == SD_OK) {
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ result_str = "succeeded";
+#endif
+ chal_sd_config_bus_width((CHAL_HANDLE *) handle->device,
+ width);
+ } else {
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ result_str = "failed";
+#endif
+ }
+ } else {
+ rc = SD_FAIL;
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ result_str = "ignored";
+#endif
+ }
+
+ VERBOSE("SDIO Data Width(%s) %s.\n", bitwidth_str, result_str);
+
+ return rc;
+}
+
+
+/*
+ * Error handling routine. Does abort data
+ * transmission if error is found.
+ */
+static int abort_err(struct sd_handle *handle)
+{
+ uint32_t present, options, event, rel = 0;
+ struct sd_resp cmdRsp;
+
+ handle->device->ctrl.argReg = 0;
+ handle->device->ctrl.cmdIndex = SD_CMD_STOP_TRANSMISSION;
+
+ options = (SD_CMD_STOP_TRANSMISSION << 24) |
+ (SD_CMDR_RSP_TYPE_R1b_5b << SD_CMDR_RSP_TYPE_S) |
+ SD4_EMMC_TOP_CMD_CRC_EN_MASK |
+ SD4_EMMC_TOP_CMD_CCHK_EN_MASK;
+
+ chal_sd_send_cmd((CHAL_HANDLE *) handle->device,
+ handle->device->ctrl.cmdIndex,
+ handle->device->ctrl.argReg, options);
+
+ event = wait_for_event(handle,
+ SD4_EMMC_TOP_INTR_CMDDONE_MASK |
+ SD_ERR_INTERRUPTS,
+ handle->device->cfg.wfe_retry);
+
+ if (event & SD_CMD_ERROR_INT) {
+ rel = SD_ERROR_NON_RECOVERABLE;
+ } else {
+ if (event & SD_DAT_TIMEOUT) {
+ return SD_ERROR_NON_RECOVERABLE;
+ }
+
+ chal_sd_get_response((CHAL_HANDLE *) handle->device,
+ (uint32_t *)&cmdRsp);
+
+ process_cmd_response(handle, handle->device->ctrl.cmdIndex,
+ cmdRsp.data.r2.rsp1, cmdRsp.data.r2.rsp2,
+ cmdRsp.data.r2.rsp3, cmdRsp.data.r2.rsp4,
+ &cmdRsp);
+
+ SD_US_DELAY(2000);
+
+ present =
+ chal_sd_get_present_status((CHAL_HANDLE *) handle->device);
+
+ if ((present & 0x00F00000) == 0x00F00000)
+ rel = SD_ERROR_RECOVERABLE;
+ else
+ rel = SD_ERROR_NON_RECOVERABLE;
+ }
+
+ return rel;
+}
+
+
+/*
+ * The function handles real data transmission on both DMA and
+ * none DMA mode, In None DMA mode the data transfer starts
+ * when the command is sent to the card, data has to be written
+ * into the host contollers buffer at this time one block
+ * at a time.
+ * In DMA mode, the real data transfer is done by the DMA engine
+ * and this functions just waits for the data transfer to complete.
+ *
+ */
+int process_data_xfer(struct sd_handle *handle, uint8_t *buffer, uint32_t addr,
+ uint32_t length, int dir)
+{
+ if (dir == SD_XFER_HOST_TO_CARD) {
+#ifdef INCLUDE_EMMC_DRIVER_WRITE_CODE
+ if (handle->device->cfg.dma == SD_DMA_OFF) {
+ /*
+ * In NON DMA mode, the real data xfer starts from here
+ */
+ if (write_buffer(handle, length, buffer))
+ return SD_WRITE_ERROR;
+ } else {
+ wait_for_event(handle,
+ SD4_EMMC_TOP_INTR_TXDONE_MASK |
+ SD_ERR_INTERRUPTS,
+ handle->device->cfg.wfe_retry);
+
+ if (handle->device->ctrl.cmdStatus == SD_OK)
+ return SD_OK;
+
+ check_error(handle, handle->device->ctrl.cmdStatus);
+ return SD_WRITE_ERROR;
+ }
+#else
+ return SD_WRITE_ERROR;
+#endif
+ } else { /* SD_XFER_CARD_TO_HOST */
+
+ if (handle->device->cfg.dma == SD_DMA_OFF) {
+ /* In NON DMA mode, the real data
+ * transfer starts from here
+ */
+ if (read_buffer(handle, length, buffer))
+ return SD_READ_ERROR;
+
+ } else { /* for DMA mode */
+
+ /*
+ * once the data transmission is done
+ * copy data to the host buffer.
+ */
+ wait_for_event(handle,
+ SD4_EMMC_TOP_INTR_TXDONE_MASK |
+ SD_ERR_INTERRUPTS,
+ handle->device->cfg.wfe_retry);
+
+ if (handle->device->ctrl.cmdStatus == SD_OK)
+ return SD_OK;
+
+ check_error(handle, handle->device->ctrl.cmdStatus);
+ return SD_READ_ERROR;
+ }
+ }
+ return SD_OK;
+}
+
+
+/*
+ * The function sets block size for the next SD/SDIO/MMC
+ * card read/write command.
+ */
+int select_blk_sz(struct sd_handle *handle, uint16_t size)
+{
+ return sd_cmd16(handle, size);
+}
+
+
+/*
+ * The function initalizes the SD/SDIO/MMC/CEATA and detects
+ * the card according to the flag of detection.
+ * Once this function is called, the card is put into ready state
+ * so application can do data transfer to and from the card.
+ */
+int init_card(struct sd_handle *handle, int detection)
+{
+ /*
+ * After Reset, eMMC comes up in 1 Bit Data Width by default.
+ * Set host side to match.
+ */
+ chal_sd_config_bus_width((CHAL_HANDLE *) handle->device,
+ SD_BUS_DATA_WIDTH_1BIT);
+
+#ifdef USE_EMMC_FIP_TOC_CACHE
+ cached_partition_block = 0;
+#endif
+ handle->device->ctrl.present = 0; /* init card present to be no card */
+
+ init_mmc_card(handle);
+
+ handle->device->ctrl.present = 1; /* card is detected */
+
+ /* switch the data width back */
+ if (handle->card->type != SD_CARD_MMC)
+ return SD_FAIL;
+
+ /*
+ * Dynamically set Data Width to highest supported value.
+ * Try different data width settings (highest to lowest).
+ * Verify each setting by reading EXT_CSD and comparing
+ * against the EXT_CSD contents previously read in call to
+ * init_mmc_card() earlier. Stop at first verified data width
+ * setting.
+ */
+ {
+#define EXT_CSD_PROPERTIES_SECTION_START_INDEX 192
+#define EXT_CSD_PROPERTIES_SECTION_END_INDEX 511
+ uint8_t buffer[EXT_CSD_SIZE];
+#ifdef DRIVER_EMMC_ENABLE_DATA_WIDTH_8BIT
+ /* Try 8 Bit Data Width */
+ chal_sd_config_bus_width((CHAL_HANDLE *) handle->device,
+ SD_BUS_DATA_WIDTH_8BIT);
+ if ((!set_card_data_width(handle, SD_BUS_DATA_WIDTH_8BIT)) &&
+ (!mmc_cmd8(handle, buffer)) &&
+ (!memcmp(&buffer[EXT_CSD_PROPERTIES_SECTION_START_INDEX],
+ &(emmc_global_buf_ptr->u.Ext_CSD_storage[EXT_CSD_PROPERTIES_SECTION_START_INDEX]),
+ EXT_CSD_PROPERTIES_SECTION_END_INDEX - EXT_CSD_PROPERTIES_SECTION_START_INDEX + 1)))
+
+ return SD_OK;
+#endif
+ /* Fall back to 4 Bit Data Width */
+ chal_sd_config_bus_width((CHAL_HANDLE *) handle->device,
+ SD_BUS_DATA_WIDTH_4BIT);
+ if ((!set_card_data_width(handle, SD_BUS_DATA_WIDTH_4BIT)) &&
+ (!mmc_cmd8(handle, buffer)) &&
+ (!memcmp(&buffer[EXT_CSD_PROPERTIES_SECTION_START_INDEX],
+ &(emmc_global_buf_ptr->u.Ext_CSD_storage[EXT_CSD_PROPERTIES_SECTION_START_INDEX]),
+ EXT_CSD_PROPERTIES_SECTION_END_INDEX - EXT_CSD_PROPERTIES_SECTION_START_INDEX + 1)))
+
+ return SD_OK;
+
+ /* Fall back to 1 Bit Data Width */
+ chal_sd_config_bus_width((CHAL_HANDLE *) handle->device,
+ SD_BUS_DATA_WIDTH_1BIT);
+ /* Just use 1 Bit Data Width then. */
+ if (!set_card_data_width(handle, SD_BUS_DATA_WIDTH_1BIT))
+ return SD_OK;
+
+ }
+ return SD_CARD_INIT_ERROR;
+}
+
+
+/*
+ * The function handles MMC/CEATA card initalization.
+ */
+int init_mmc_card(struct sd_handle *handle)
+{
+ uint32_t ocr = 0, newOcr, rc, limit = 0;
+ uint32_t cmd1_option = 0x40300000;
+ uint32_t sec_count;
+
+ handle->card->type = SD_CARD_MMC;
+
+ do {
+ SD_US_DELAY(1000);
+ newOcr = 0;
+ ocr = 0;
+ rc = sd_cmd1(handle, cmd1_option, &newOcr);
+ limit++;
+
+ if (rc == SD_OK)
+ ocr = newOcr;
+
+ } while (((ocr & SD_CARD_BUSY) == 0) && (limit < SD_CARD_RETRY_LIMIT));
+
+ if (limit >= SD_CARD_RETRY_LIMIT) {
+ handle->card->type = SD_CARD_UNKNOWN;
+ EMMC_TRACE("CMD1 Timeout: Device is not ready\n");
+ return SD_CARD_UNKNOWN;
+ }
+
+ /* Save the ocr register */
+ handle->device->ctrl.ocr = ocr;
+
+ /* Ready State */
+ rc = sd_cmd2(handle);
+ if (rc != SD_OK) {
+ handle->card->type = SD_CARD_UNKNOWN;
+ return SD_CARD_UNKNOWN;
+ }
+
+ rc = sd_cmd3(handle);
+ if (rc != SD_OK) {
+ handle->card->type = SD_CARD_UNKNOWN;
+ return SD_CARD_UNKNOWN;
+ }
+ /* read CSD */
+ rc = sd_cmd9(handle, &emmc_global_vars_ptr->cardData);
+ if (rc != SD_OK) {
+ handle->card->type = SD_CARD_UNKNOWN;
+ return SD_CARD_UNKNOWN;
+ }
+
+ /* Increase clock frequency according to what the card advertises */
+ EMMC_TRACE("From CSD... cardData.csd.mmc.speed = 0x%X\n",
+ emmc_global_vars_ptr->cardData.csd.mmc.speed);
+ process_csd_mmc_speed(handle,
+ emmc_global_vars_ptr->cardData.csd.mmc.speed);
+
+ /* goto transfer mode */
+ rc = sd_cmd7(handle, handle->device->ctrl.rca);
+ if (rc != SD_OK) {
+ handle->card->type = SD_CARD_UNKNOWN;
+ return SD_CARD_UNKNOWN;
+ }
+
+ rc = mmc_cmd8(handle, emmc_global_buf_ptr->u.Ext_CSD_storage);
+ if (rc == SD_OK) {
+ /* calcul real capacity */
+ sec_count = emmc_global_buf_ptr->u.Ext_CSD_storage[212] |
+ emmc_global_buf_ptr->u.Ext_CSD_storage[213] << 8 |
+ emmc_global_buf_ptr->u.Ext_CSD_storage[214] << 16 |
+ emmc_global_buf_ptr->u.Ext_CSD_storage[215] << 24;
+
+ EMMC_TRACE("Device density = %ldMBytes\n",
+ handle->card->size / (1024 * 1024));
+
+ if (sec_count > 0) {
+ handle->card->size = (uint64_t)sec_count * 512;
+
+ EMMC_TRACE("Updated Device density = %ldMBytes\n",
+ handle->card->size / (1024 * 1024));
+ }
+
+ if (sec_count > (2u * 1024 * 1024 * 1024) / 512) {
+ handle->device->ctrl.ocr |= SD_CARD_HIGH_CAPACITY;
+ handle->device->cfg.blockSize = 512;
+ }
+
+ if (handle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY)
+ EMMC_TRACE("Sector addressing\n");
+ else
+ EMMC_TRACE("Byte addressing\n");
+
+ EMMC_TRACE("Ext_CSD_storage[162]: 0x%02X Ext_CSD_storage[179]: 0x%02X\n",
+ emmc_global_buf_ptr->u.Ext_CSD_storage[162],
+ emmc_global_buf_ptr->u.Ext_CSD_storage[179]);
+ }
+
+ return handle->card->type;
+}
+
+
+/*
+ * The function send reset command to the card.
+ * The card will be in ready status after the reset.
+ */
+int reset_card(struct sd_handle *handle)
+{
+ int res = SD_OK;
+
+ /* on reset, card's RCA should return to 0 */
+ handle->device->ctrl.rca = 0;
+
+ res = sd_cmd0(handle);
+
+ if (res != SD_OK)
+ return SD_RESET_ERROR;
+
+ return res;
+}
+
+
+/*
+ * The function sends command to the card and starts
+ * data transmission.
+ */
+static int xfer_data(struct sd_handle *handle,
+ uint32_t mode,
+ uint32_t addr, uint32_t length, uint8_t *base)
+{
+ int rc = SD_OK;
+
+ VERBOSE("XFER: dest: 0x%" PRIx64 ", addr: 0x%x, size: 0x%x bytes\n",
+ (uint64_t)base, addr, length);
+
+ if ((length / handle->device->cfg.blockSize) > 1) {
+ if (mode == SD_OP_READ) {
+ inv_dcache_range((uintptr_t)base, (uint64_t)length);
+ rc = sd_cmd18(handle, addr, length, base);
+ } else {
+#ifdef INCLUDE_EMMC_DRIVER_WRITE_CODE
+ flush_dcache_range((uintptr_t)base, (uint64_t)length);
+ rc = sd_cmd25(handle, addr, length, base);
+#else
+ rc = SD_DATA_XFER_ERROR;
+#endif
+ }
+ } else {
+ if (mode == SD_OP_READ) {
+ inv_dcache_range((uintptr_t)base, (uint64_t)length);
+ rc = sd_cmd17(handle, addr,
+ handle->device->cfg.blockSize, base);
+ } else {
+#ifdef INCLUDE_EMMC_DRIVER_WRITE_CODE
+ flush_dcache_range((uintptr_t)base, (uint64_t)length);
+ rc = sd_cmd24(handle, addr,
+ handle->device->cfg.blockSize, base);
+#else
+ rc = SD_DATA_XFER_ERROR;
+#endif
+ }
+ }
+
+ if (rc != SD_OK)
+ return SD_DATA_XFER_ERROR;
+
+ return SD_OK;
+}
+
+#ifdef INCLUDE_EMMC_DRIVER_ERASE_CODE
+int erase_card(struct sd_handle *handle, uint32_t addr, uint32_t blocks)
+{
+ uint32_t end_addr;
+
+ INFO("ERASE: addr: 0x%x, num of sectors: 0x%x\n", addr, blocks);
+
+ if (sd_cmd35(handle, addr) != SD_OK)
+ return SD_FAIL;
+
+ end_addr = addr + blocks - 1;
+ if (sd_cmd36(handle, end_addr) != SD_OK)
+ return SD_FAIL;
+
+ if (sd_cmd38(handle) != SD_OK)
+ return SD_FAIL;
+
+ return SD_OK;
+}
+#endif
+
+/*
+ * The function reads block data from a card.
+ */
+#ifdef USE_EMMC_FIP_TOC_CACHE
+int read_block(struct sd_handle *handle,
+ uint8_t *dst, uint32_t addr, uint32_t len)
+{
+ int rel = SD_OK;
+
+ /*
+ * Avoid doing repeated reads of the partition block
+ * by caching.
+ */
+ if (cached_partition_block &&
+ addr == PARTITION_BLOCK_ADDR &&
+ len == CACHE_SIZE) {
+ memcpy(dst, cached_block, len);
+ } else {
+ rel = xfer_data(handle, SD_OP_READ, addr, len, dst);
+
+ if (len == CACHE_SIZE && addr == PARTITION_BLOCK_ADDR) {
+ cached_partition_block = 1;
+ memcpy(cached_block, dst, len);
+ }
+ }
+
+ return rel;
+}
+#else
+int read_block(struct sd_handle *handle,
+ uint8_t *dst, uint32_t addr, uint32_t len)
+{
+ return xfer_data(handle, SD_OP_READ, addr, len, dst);
+}
+#endif
+
+#ifdef INCLUDE_EMMC_DRIVER_WRITE_CODE
+
+/*
+ * The function writes block data to a card.
+ */
+int write_block(struct sd_handle *handle,
+ uint8_t *src, uint32_t addr, uint32_t len)
+{
+ int rel = SD_OK;
+
+ /*
+ * Current HC has problem to get response of cmd16 after cmd12,
+ * the delay is necessary to sure the next cmd16 will not be timed out.
+ * The delay has to be at least 4 ms.
+ * The code removed cmd16 and use cmd13 to get card status before
+ * sending cmd18 or cmd25 to make sure the card is ready and thus
+ * no need to have delay here.
+ */
+
+ rel = xfer_data(handle, SD_OP_WRITE, addr, len, src);
+
+ EMMC_TRACE("wr_blk addr:0x%08X src:0x%08X len:0x%08X result:%d\n",
+ addr, src, len, rel);
+
+ return rel;
+}
+
+
+/*
+ * The function is called to write one block data directly to
+ * a card's data buffer.
+ * it is used in Non-DMA mode for card data transmission.
+ */
+int write_buffer(struct sd_handle *handle, uint32_t length, uint8_t *data)
+{
+ uint32_t rem, blockSize, event;
+ uint8_t *pData = data;
+
+ blockSize = handle->device->cfg.blockSize;
+ rem = length;
+
+ if (rem == 0)
+ return SD_OK;
+
+ while (rem > 0) {
+
+ event = wait_for_event(handle,
+ SD4_EMMC_TOP_INTR_BWRDY_MASK |
+ SD_ERR_INTERRUPTS,
+ handle->device->cfg.wfe_retry);
+
+ if (handle->device->ctrl.cmdStatus) {
+ check_error(handle, handle->device->ctrl.cmdStatus);
+ return SD_WRITE_ERROR;
+ }
+
+ if (rem >= blockSize)
+ chal_sd_write_buffer((CHAL_HANDLE *) handle->device,
+ blockSize, pData);
+ else
+ chal_sd_write_buffer((CHAL_HANDLE *) handle->device,
+ rem, pData);
+
+ if (rem > blockSize) {
+ rem -= blockSize;
+ pData += blockSize;
+ } else {
+ pData += rem;
+ rem = 0;
+ }
+ }
+
+ if ((event & SD4_EMMC_TOP_INTR_TXDONE_MASK) !=
+ SD4_EMMC_TOP_INTR_TXDONE_MASK) {
+ event = wait_for_event(handle,
+ SD4_EMMC_TOP_INTR_TXDONE_MASK |
+ SD_ERR_INTERRUPTS,
+ handle->device->cfg.wfe_retry);
+
+ if (handle->device->ctrl.cmdStatus != SD_OK) {
+ check_error(handle, handle->device->ctrl.cmdStatus);
+ return SD_WRITE_ERROR;
+ }
+ } else {
+ handle->device->ctrl.eventList &= ~SD4_EMMC_TOP_INTR_TXDONE_MASK;
+ }
+
+ return SD_OK;
+}
+#endif /* INCLUDE_EMMC_DRIVER_WRITE_CODE */
+
+
+/*
+ * The function is called to read maximal one block data
+ * directly from a card
+ * It is used in Non-DMA mode for card data transmission.
+ */
+int read_buffer(struct sd_handle *handle, uint32_t length, uint8_t *data)
+{
+ uint32_t rem, blockSize, event = 0;
+ uint8_t *pData = data;
+
+ blockSize = handle->device->cfg.blockSize;
+ rem = length;
+
+ if (rem == 0)
+ return SD_OK;
+
+ while (rem > 0) {
+ event = wait_for_event(handle,
+ SD4_EMMC_TOP_INTR_BRRDY_MASK |
+ SD_ERR_INTERRUPTS,
+ handle->device->cfg.wfe_retry);
+
+ if (handle->device->ctrl.cmdStatus) {
+ check_error(handle, handle->device->ctrl.cmdStatus);
+ return SD_READ_ERROR;
+ }
+
+ if (rem >= blockSize)
+ chal_sd_read_buffer((CHAL_HANDLE *) handle->device,
+ blockSize, pData);
+ else
+ chal_sd_read_buffer((CHAL_HANDLE *) handle->device, rem,
+ pData);
+
+ if (rem > blockSize) {
+ rem -= blockSize;
+ pData += blockSize;
+ } else {
+ pData += rem;
+ rem = 0;
+ }
+ }
+
+ /* In case, there are extra data in the SD FIFO, just dump them. */
+ chal_sd_dump_fifo((CHAL_HANDLE *) handle->device);
+
+ if ((event & SD4_EMMC_TOP_INTR_TXDONE_MASK) !=
+ SD4_EMMC_TOP_INTR_TXDONE_MASK) {
+ event = wait_for_event(handle, SD4_EMMC_TOP_INTR_TXDONE_MASK,
+ handle->device->cfg.wfe_retry);
+
+ if (handle->device->ctrl.cmdStatus) {
+ check_error(handle, handle->device->ctrl.cmdStatus);
+ return SD_READ_ERROR;
+ }
+ } else {
+ handle->device->ctrl.eventList &= ~SD4_EMMC_TOP_INTR_TXDONE_MASK;
+ }
+
+ return SD_OK;
+}
+
+
+/*
+ * Error handling routine.
+ * The function just reset the DAT
+ * and CMD line if an error occures during data transmission.
+ */
+int check_error(struct sd_handle *handle, uint32_t ints)
+{
+ uint32_t rel;
+
+ chal_sd_set_irq_signal((CHAL_HANDLE *) handle->device,
+ SD_ERR_INTERRUPTS, 0);
+
+ if (ints & SD4_EMMC_TOP_INTR_CMDERROR_MASK) {
+
+ chal_sd_reset_line((CHAL_HANDLE *) handle->device,
+ SD4_EMMC_TOP_CTRL1_CMDRST_MASK);
+ rel = abort_err(handle);
+
+ chal_sd_reset_line((CHAL_HANDLE *) handle->device,
+ SD4_EMMC_TOP_CTRL1_DATRST_MASK);
+ chal_sd_set_irq_signal((CHAL_HANDLE *) handle->device,
+ SD_ERR_INTERRUPTS, 1);
+
+ return (rel == SD_ERROR_NON_RECOVERABLE) ?
+ SD_ERROR_NON_RECOVERABLE : SD_ERROR_RECOVERABLE;
+ } else {
+ rel = err_recovery(handle, ints);
+ }
+
+ chal_sd_set_irq_signal((CHAL_HANDLE *) handle->device,
+ SD_ERR_INTERRUPTS, 1);
+
+ return rel;
+}
+
+
+/*
+ * Error recovery routine.
+ * Try to recover from the error.
+ */
+static int err_recovery(struct sd_handle *handle, uint32_t errors)
+{
+ uint32_t rel = 0;
+
+ /*
+ * In case of timeout error, the cmd line and data line maybe
+ * still active or stuck at atcitve so it is needed to reset
+ * either data line or cmd line to make sure a new cmd can be sent.
+ */
+
+ if (errors & SD_CMD_ERROR_INT)
+ chal_sd_reset_line((CHAL_HANDLE *) handle->device,
+ SD4_EMMC_TOP_CTRL1_CMDRST_MASK);
+
+ if (errors & SD_DAT_ERROR_INT)
+ chal_sd_reset_line((CHAL_HANDLE *) handle->device,
+ SD4_EMMC_TOP_CTRL1_DATRST_MASK);
+
+ /* Abort transaction by sending out stop command */
+ if ((handle->device->ctrl.cmdIndex == 18) ||
+ (handle->device->ctrl.cmdIndex == 25))
+ rel = abort_err(handle);
+
+ return rel;
+}
+
+
+/*
+ * The function is called to read one block data directly from a card.
+ * It is used in Non-DMA mode for card data transmission.
+ */
+int process_cmd_response(struct sd_handle *handle,
+ uint32_t cmdIndex,
+ uint32_t rsp0,
+ uint32_t rsp1,
+ uint32_t rsp2, uint32_t rsp3, struct sd_resp *resp)
+{
+ int result = SD_OK;
+
+ /* R6 */
+ uint32_t rca = (rsp0 >> 16) & 0xffff;
+ uint32_t cardStatus = rsp0;
+
+ /* R4 */
+ uint32_t cBit = (rsp0 >> 31) & 0x1;
+ uint32_t funcs = (rsp0 >> 28) & 0x7;
+ uint32_t memPresent = (rsp0 >> 27) & 0x1;
+
+ resp->r1 = 0x3f;
+ resp->cardStatus = cardStatus;
+
+ if (cmdIndex == SD_CMD_IO_SEND_OP_COND) {
+ resp->data.r4.cardReady = cBit;
+ resp->data.r4.funcs = funcs;
+ resp->data.r4.memPresent = memPresent;
+ resp->data.r4.ocr = cardStatus;
+ }
+
+ if (cmdIndex == SD_CMD_MMC_SET_RCA) {
+ resp->data.r6.rca = rca;
+ resp->data.r6.cardStatus = cardStatus & 0xFFFF;
+ }
+
+ if (cmdIndex == SD_CMD_SELECT_DESELECT_CARD) {
+ resp->data.r7.rca = rca;
+ }
+
+ if (cmdIndex == SD_CMD_IO_RW_DIRECT) {
+ if (((rsp0 >> 16) & 0xffff) != 0)
+ result = SD_CMD_ERR_INVALID_RESPONSE;
+
+ resp->data.r5.data = rsp0 & 0xff;
+ }
+
+ if (cmdIndex == SD_CMD_IO_RW_EXTENDED) {
+ if (((rsp0 >> 16) & 0xffff) != 0)
+ result = SD_CMD_ERR_INVALID_RESPONSE;
+
+ resp->data.r5.data = rsp0 & 0xff;
+ }
+
+ if (cmdIndex == SD_ACMD_SD_SEND_OP_COND ||
+ cmdIndex == SD_CMD_SEND_OPCOND)
+ resp->data.r3.ocr = cardStatus;
+
+ if (cmdIndex == SD_CMD_SEND_CSD ||
+ cmdIndex == SD_CMD_SEND_CID ||
+ cmdIndex == SD_CMD_ALL_SEND_CID) {
+ resp->data.r2.rsp4 = rsp3;
+ resp->data.r2.rsp3 = rsp2;
+ resp->data.r2.rsp2 = rsp1;
+ resp->data.r2.rsp1 = rsp0;
+ }
+
+ if ((cmdIndex == SD_CMD_READ_EXT_CSD) &&
+ (handle->card->type == SD_CARD_SD)) {
+ if ((resp->cardStatus & 0xAA) != 0xAA) {
+ result = SD_CMD_ERR_INVALID_RESPONSE;
+ }
+ }
+
+ return result;
+}
+
+
+/*
+ * The function sets DMA buffer and data length, process
+ * block size and the number of blocks to be transferred.
+ * It returns the DMA buffer address.
+ * It copies dma data from user buffer to the DMA buffer
+ * if the operation is to write data to the SD card.
+ */
+void data_xfer_setup(struct sd_handle *handle, uint8_t *data, uint32_t length,
+ int dir)
+{
+ chal_sd_setup_xfer((CHAL_HANDLE *)handle->device, data, length, dir);
+}
+
+
+/*
+ * The function does soft reset the host SD controller. After
+ * the function call all host controller's register are reset
+ * to default vallue;
+ *
+ * Note This function only resets the host controller it does not
+ * reset the controller's handler.
+ */
+int reset_host_ctrl(struct sd_handle *handle)
+{
+ chal_sd_stop();
+
+ return SD_OK;
+}
+
+static void pstate_log(struct sd_handle *handle)
+{
+ ERROR("PSTATE: 0x%x\n", mmio_read_32
+ (handle->device->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_PSTATE_SD4_OFFSET));
+ ERROR("ERRSTAT: 0x%x\n", mmio_read_32
+ (handle->device->ctrl.sdRegBaseAddr +
+ SD4_EMMC_TOP_ERRSTAT_OFFSET));
+}
+
+/*
+ * The function waits for one or a group of interrupts specified
+ * by mask. The function returns if any one the interrupt status
+ * is set. If interrupt mode is not enabled then it will poll
+ * the interrupt status register until a interrupt status is set
+ * an error interrupt happens. If interrupt mode is enabled then
+ * this function should be called after the interrupt
+ * is received by ISR routine.
+ */
+uint32_t wait_for_event(struct sd_handle *handle,
+ uint32_t mask, uint32_t retry)
+{
+ uint32_t regval, cmd12, time = 0;
+
+ handle->device->ctrl.cmdStatus = 0; /* no error */
+ EMMC_TRACE("%s %d mask:0x%x timeout:%d irq_status:0x%x\n",
+ __func__, __LINE__, mask, retry,
+ chal_sd_get_irq_status((CHAL_HANDLE *)handle->device));
+
+ /* Polling mode */
+ do {
+ regval = chal_sd_get_irq_status((CHAL_HANDLE *)handle->device);
+
+ if (regval & SD4_EMMC_TOP_INTR_DMAIRQ_MASK) {
+ chal_sd_set_dma_addr((CHAL_HANDLE *)handle->device,
+ (uintptr_t)
+ chal_sd_get_dma_addr((CHAL_HANDLE *)
+ handle->device));
+ chal_sd_clear_irq((CHAL_HANDLE *)handle->device,
+ SD4_EMMC_TOP_INTR_DMAIRQ_MASK);
+ }
+
+ if (time++ > retry) {
+ ERROR("EMMC: No response (cmd%d) after %dus.\n",
+ handle->device->ctrl.cmdIndex,
+ time * EMMC_WFE_RETRY_DELAY_US);
+ handle->device->ctrl.cmdStatus = SD_CMD_MISSING;
+ pstate_log(handle);
+ ERROR("EMMC: INT[0x%x]\n", regval);
+ break;
+ }
+
+ if (regval & SD4_EMMC_TOP_INTR_CTOERR_MASK) {
+ ERROR("EMMC: Cmd%d timeout INT[0x%x]\n",
+ handle->device->ctrl.cmdIndex, regval);
+ handle->device->ctrl.cmdStatus =
+ SD4_EMMC_TOP_INTR_CTOERR_MASK;
+ pstate_log(handle);
+ break;
+ }
+ if (regval & SD_CMD_ERROR_FLAGS) {
+ ERROR("EMMC: Cmd%d error INT[0x%x]\n",
+ handle->device->ctrl.cmdIndex, regval);
+ handle->device->ctrl.cmdStatus = SD_CMD_ERROR_FLAGS;
+ pstate_log(handle);
+ break;
+ }
+
+ cmd12 = chal_sd_get_atuo12_error((CHAL_HANDLE *)handle->device);
+ if (cmd12) {
+ ERROR("EMMC: Cmd%d auto cmd12 err:0x%x\n",
+ handle->device->ctrl.cmdIndex, cmd12);
+ handle->device->ctrl.cmdStatus = cmd12;
+ pstate_log(handle);
+ break;
+ }
+
+ if (SD_DATA_ERROR_FLAGS & regval) {
+ ERROR("EMMC: Data for cmd%d error, INT[0x%x]\n",
+ handle->device->ctrl.cmdIndex, regval);
+ handle->device->ctrl.cmdStatus =
+ (SD_DATA_ERROR_FLAGS & regval);
+ pstate_log(handle);
+ break;
+ }
+
+ if ((regval & mask) == 0)
+ udelay(EMMC_WFE_RETRY_DELAY_US);
+
+ } while ((regval & mask) == 0);
+
+ /* clear the interrupt since it is processed */
+ chal_sd_clear_irq((CHAL_HANDLE *)handle->device, (regval & mask));
+
+ return (regval & mask);
+}
+
+int32_t set_config(struct sd_handle *handle, uint32_t speed, uint32_t retry,
+ uint32_t dma, uint32_t dmaBound, uint32_t blkSize,
+ uint32_t wfe_retry)
+{
+ int32_t rel = 0;
+
+ if (handle == NULL)
+ return SD_FAIL;
+
+ handle->device->cfg.wfe_retry = wfe_retry;
+
+ rel = chal_sd_config((CHAL_HANDLE *)handle->device, speed, retry,
+ dmaBound, blkSize, dma);
+ return rel;
+
+}
+
+int mmc_cmd1(struct sd_handle *handle)
+{
+ uint32_t newOcr, res;
+ uint32_t cmd1_option = MMC_OCR_OP_VOLT | MMC_OCR_SECTOR_ACCESS_MODE;
+
+ /*
+ * After Reset, eMMC comes up in 1 Bit Data Width by default.
+ * Set host side to match.
+ */
+ chal_sd_config_bus_width((CHAL_HANDLE *) handle->device,
+ SD_BUS_DATA_WIDTH_1BIT);
+
+#ifdef USE_EMMC_FIP_TOC_CACHE
+ cached_partition_block = 0;
+#endif
+ handle->device->ctrl.present = 0; /* init card present to be no card */
+
+ handle->card->type = SD_CARD_MMC;
+
+ res = sd_cmd1(handle, cmd1_option, &newOcr);
+
+ if (res != SD_OK) {
+ EMMC_TRACE("CMD1 Timeout: Device is not ready\n");
+ res = SD_CARD_UNKNOWN;
+ }
+ return res;
+}
diff --git a/drivers/brcm/emmc/emmc_csl_sdcmd.c b/drivers/brcm/emmc/emmc_csl_sdcmd.c
new file mode 100644
index 0000000..c62886c
--- /dev/null
+++ b/drivers/brcm/emmc/emmc_csl_sdcmd.c
@@ -0,0 +1,842 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+
+#include "bcm_emmc.h"
+#include "emmc_chal_types.h"
+#include "emmc_chal_sd.h"
+#include "emmc_csl_sdprot.h"
+#include "emmc_csl_sdcmd.h"
+#include "emmc_csl_sd.h"
+#include "emmc_chal_sd.h"
+#include "emmc_pboot_hal_memory_drv.h"
+
+int sd_cmd0(struct sd_handle *handle)
+{
+ int res;
+ uint32_t argument = 0x0; /* Go to IDLE state. */
+
+ /* send cmd and parse result */
+ res = send_cmd(handle, SD_CMD_GO_IDLE_STATE, argument, 0, NULL);
+
+ if (res == SD_OK) {
+ /* Clear all other interrupts */
+ chal_sd_clear_irq((void *)handle->device, 0xffffffff);
+ }
+
+ return res;
+}
+
+int sd_cmd1(struct sd_handle *handle, uint32_t ocr, uint32_t *ocr_output)
+{
+ int res;
+ uint32_t options;
+ struct sd_resp resp;
+
+ options = SD_CMDR_RSP_TYPE_R3_4 << SD_CMDR_RSP_TYPE_S;
+
+ if (ocr_output == NULL) {
+ EMMC_TRACE("Invalid args\n");
+ return SD_FAIL;
+ }
+
+ /* send cmd and parse result */
+ res = send_cmd(handle, SD_CMD_SEND_OPCOND, ocr, options, &resp);
+
+ if (res == SD_OK)
+ *ocr_output = resp.data.r3.ocr;
+
+ return res;
+}
+
+int sd_cmd2(struct sd_handle *handle)
+{
+ uint32_t options;
+ struct sd_resp resp;
+
+ /* send cmd and parse result */
+ options = SD_CMDR_RSP_TYPE_R2 << SD_CMDR_RSP_TYPE_S;
+
+ return send_cmd(handle, SD_CMD_ALL_SEND_CID, 0, options, &resp);
+}
+
+int sd_cmd3(struct sd_handle *handle)
+{
+ int res;
+ uint32_t options = 0;
+ uint32_t argument;
+ struct sd_resp resp;
+
+ /* use non zero and non 0x1 value for rca */
+ handle->device->ctrl.rca = 0x5;
+ argument = handle->device->ctrl.rca << SD_CMD7_ARG_RCA_SHIFT;
+
+ options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
+ SD4_EMMC_TOP_CMD_CCHK_EN_MASK |
+ SD4_EMMC_TOP_CMD_CRC_EN_MASK;
+
+ /* send cmd and parse result */
+ res = send_cmd(handle, SD_CMD_MMC_SET_RCA, argument, options, &resp);
+
+ if (res != SD_OK)
+ handle->device->ctrl.rca = 0;
+
+ return res;
+}
+
+int sd_cmd7(struct sd_handle *handle, uint32_t rca)
+{
+ int res;
+ uint32_t argument, options;
+ struct sd_resp resp;
+
+ argument = (rca << SD_CMD7_ARG_RCA_SHIFT);
+
+ /*
+ * Response to CMD7 is:
+ * R1 while selectiing from Stand-By State to Transfer State
+ * R1b while selecting from Disconnected State to Programming State.
+ *
+ * In this driver, we only issue a CMD7 once, to go to transfer mode
+ * during init_mmc_card().
+ */
+ options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
+ SD4_EMMC_TOP_CMD_CCHK_EN_MASK |
+ SD4_EMMC_TOP_CMD_CRC_EN_MASK;
+
+ /* send cmd and parse result */
+ res = send_cmd(handle, SD_CMD_SELECT_DESELECT_CARD, argument, options,
+ &resp);
+
+ if (res == SD_OK)
+ /* Clear all other interrupts */
+ chal_sd_clear_irq((void *)handle->device, 0xffffffff);
+
+ return res;
+}
+
+
+/*
+ * CMD8 Get CSD_EXT
+ */
+int mmc_cmd8(struct sd_handle *handle, uint8_t *extCsdReg)
+{
+ uint32_t res, options;
+ struct sd_resp resp;
+
+ data_xfer_setup(handle, extCsdReg, CEATA_EXT_CSDBLOCK_SIZE,
+ SD_XFER_CARD_TO_HOST);
+
+ options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
+ SD4_EMMC_TOP_CMD_DPS_MASK | SD4_EMMC_TOP_CMD_DTDS_MASK |
+ SD4_EMMC_TOP_CMD_CCHK_EN_MASK | SD4_EMMC_TOP_CMD_CRC_EN_MASK;
+
+ /* send cmd and parse result */
+ res = send_cmd(handle, SD_CMD_READ_EXT_CSD, 0, options, &resp);
+
+ if (res == SD_OK)
+ res = process_data_xfer(handle, extCsdReg, 0,
+ CEATA_EXT_CSDBLOCK_SIZE,
+ SD_XFER_CARD_TO_HOST);
+
+ return res;
+}
+
+int sd_cmd9(struct sd_handle *handle, struct sd_card_data *card)
+{
+ int res;
+ uint32_t argument, options, iBlkNum, multiFactor = 1;
+ uint32_t maxReadBlockLen = 1, maxWriteBlockLen = 1;
+ struct sd_resp resp;
+
+ argument = handle->device->ctrl.rca << SD_CMD7_ARG_RCA_SHIFT;
+
+ options = SD_CMDR_RSP_TYPE_R2 << SD_CMDR_RSP_TYPE_S |
+ SD4_EMMC_TOP_CMD_CRC_EN_MASK;
+
+ /* send cmd and parse result */
+ res = send_cmd(handle, SD_CMD_SEND_CSD, argument, options, &resp);
+
+ if (res != SD_OK)
+ return res;
+
+ if (handle->card->type == SD_CARD_MMC) {
+ card->csd.mmc.structure = (resp.data.r2.rsp4 >> 22) & 0x3;
+ card->csd.mmc.csdSpecVer = (resp.data.r2.rsp4 >> 18) & 0x0f;
+ card->csd.mmc.taac = (resp.data.r2.rsp4 >> 8) & 0xff;
+ card->csd.mmc.nsac = resp.data.r2.rsp4 & 0xff;
+ card->csd.mmc.speed = resp.data.r2.rsp3 >> 24;
+ card->csd.mmc.classes = (resp.data.r2.rsp3 >> 12) & 0xfff;
+ card->csd.mmc.rdBlkLen = (resp.data.r2.rsp3 >> 8) & 0xf;
+ card->csd.mmc.rdBlkPartial = (resp.data.r2.rsp3 >> 7) & 0x01;
+ card->csd.mmc.wrBlkMisalign = (resp.data.r2.rsp3 >> 6) & 0x1;
+ card->csd.mmc.rdBlkMisalign = (resp.data.r2.rsp3 >> 5) & 0x1;
+ card->csd.mmc.dsr = (resp.data.r2.rsp2 >> 4) & 0x01;
+ card->csd.mmc.size =
+ ((resp.data.r2.rsp3 & 0x3) << 10) +
+ ((resp.data.r2.rsp2 >> 22) & 0x3ff);
+ card->csd.mmc.vddRdCurrMin = (resp.data.r2.rsp2 >> 19) & 0x7;
+ card->csd.mmc.vddRdCurrMax = (resp.data.r2.rsp2 >> 16) & 0x7;
+ card->csd.mmc.vddWrCurrMin = (resp.data.r2.rsp2 >> 13) & 0x7;
+ card->csd.mmc.vddWrCurrMax = (resp.data.r2.rsp2 >> 10) & 0x7;
+ card->csd.mmc.devSizeMulti = (resp.data.r2.rsp2 >> 7) & 0x7;
+ card->csd.mmc.eraseGrpSize = (resp.data.r2.rsp2 >> 2) & 0x1f;
+ card->csd.mmc.eraseGrpSizeMulti =
+ ((resp.data.r2.rsp2 & 0x3) << 3) +
+ ((resp.data.r2.rsp1 >> 29) & 0x7);
+ card->csd.mmc.wrProtGroupSize =
+ ((resp.data.r2.rsp1 >> 24) & 0x1f);
+ card->csd.mmc.wrProtGroupEnable =
+ (resp.data.r2.rsp1 >> 23) & 0x1;
+ card->csd.mmc.manuDefEcc = (resp.data.r2.rsp1 >> 21) & 0x3;
+ card->csd.mmc.wrSpeedFactor = (resp.data.r2.rsp1 >> 18) & 0x7;
+ card->csd.mmc.wrBlkLen = (resp.data.r2.rsp1 >> 14) & 0xf;
+ card->csd.mmc.wrBlkPartial = (resp.data.r2.rsp1 >> 13) & 0x1;
+ card->csd.mmc.protAppl = (resp.data.r2.rsp1 >> 8) & 0x1;
+ card->csd.mmc.copyFlag = (resp.data.r2.rsp1 >> 7) & 0x1;
+ card->csd.mmc.permWrProt = (resp.data.r2.rsp1 >> 6) & 0x1;
+ card->csd.mmc.tmpWrProt = (resp.data.r2.rsp1 >> 5) & 0x1;
+ card->csd.mmc.fileFormat = (resp.data.r2.rsp1 >> 4) & 0x03;
+ card->csd.mmc.eccCode = resp.data.r2.rsp1 & 0x03;
+ maxReadBlockLen <<= card->csd.mmc.rdBlkLen;
+ maxWriteBlockLen <<= card->csd.mmc.wrBlkLen;
+
+ iBlkNum = card->csd.mmc.size + 1;
+ multiFactor = (1 << (card->csd.mmc.devSizeMulti + 2));
+
+ handle->card->size =
+ iBlkNum * multiFactor * (1 << card->csd.mmc.rdBlkLen);
+ }
+
+ handle->card->maxRdBlkLen = maxReadBlockLen;
+ handle->card->maxWtBlkLen = maxWriteBlockLen;
+
+ if (handle->card->size < 0xA00000) {
+ /*
+ * 10MB Too small size mean, cmd9 response is wrong,
+ * Use default value 1G
+ */
+ handle->card->size = 0x40000000;
+ handle->card->maxRdBlkLen = 512;
+ handle->card->maxWtBlkLen = 512;
+ }
+
+ if ((handle->card->maxRdBlkLen > 512) ||
+ (handle->card->maxWtBlkLen > 512)) {
+ handle->card->maxRdBlkLen = 512;
+ handle->card->maxWtBlkLen = 512;
+ } else if ((handle->card->maxRdBlkLen == 0) ||
+ (handle->card->maxWtBlkLen == 0)) {
+ handle->card->maxRdBlkLen = 512;
+ handle->card->maxWtBlkLen = 512;
+ }
+
+ handle->device->cfg.blockSize = handle->card->maxRdBlkLen;
+
+ return res;
+}
+
+int sd_cmd13(struct sd_handle *handle, uint32_t *status)
+{
+ int res;
+ uint32_t argument, options;
+ struct sd_resp resp;
+
+ argument = handle->device->ctrl.rca << SD_CMD7_ARG_RCA_SHIFT;
+
+ options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
+ SD4_EMMC_TOP_CMD_CCHK_EN_MASK |
+ SD4_EMMC_TOP_CMD_CRC_EN_MASK;
+
+ /* send cmd and parse result */
+ res = send_cmd(handle, SD_CMD_SEND_STATUS, argument, options, &resp);
+
+ if (res == SD_OK) {
+ *status = resp.cardStatus;
+ }
+
+ return res;
+}
+
+int sd_cmd16(struct sd_handle *handle, uint32_t length)
+{
+ int res;
+ uint32_t argument, options, ntry;
+ struct sd_resp resp;
+
+ argument = length;
+
+ options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
+ SD4_EMMC_TOP_CMD_CRC_EN_MASK |
+ SD4_EMMC_TOP_CMD_CCHK_EN_MASK;
+
+ ntry = 0;
+ do {
+ res = sd_cmd13(handle, &resp.cardStatus);
+ if (res != SD_OK) {
+ EMMC_TRACE(
+ "cmd13 failed before cmd16: rca 0x%0x, return %d, response 0x%0x\n",
+ handle->device->ctrl.rca, res, resp.cardStatus);
+ return res;
+ }
+
+ if (resp.cardStatus & 0x100)
+ break;
+
+ EMMC_TRACE("cmd13 rsp:0x%08x before cmd16\n", resp.cardStatus);
+
+ if (ntry > handle->device->cfg.retryLimit) {
+ EMMC_TRACE("cmd13 retry reach limit %d\n",
+ handle->device->cfg.retryLimit);
+ return SD_CMD_TIMEOUT;
+ }
+
+ ntry++;
+ EMMC_TRACE("cmd13 retry %d\n", ntry);
+
+ SD_US_DELAY(1000);
+
+ } while (1);
+
+ /* send cmd and parse result */
+ res = send_cmd(handle, SD_CMD_SET_BLOCKLEN, argument, options, &resp);
+
+ return res;
+}
+
+int sd_cmd17(struct sd_handle *handle,
+ uint32_t addr, uint32_t len, uint8_t *buffer)
+{
+ int res;
+ uint32_t argument, options, ntry;
+ struct sd_resp resp;
+
+ ntry = 0;
+ do {
+ res = sd_cmd13(handle, &resp.cardStatus);
+ if (res != SD_OK) {
+ EMMC_TRACE(
+ "cmd 13 failed before cmd17: rca 0x%0x, return %d, response 0x%0x\n",
+ handle->device->ctrl.rca, res, resp.cardStatus);
+ return res;
+ }
+
+ if (resp.cardStatus & 0x100)
+ break;
+
+ EMMC_TRACE("cmd13 rsp:0x%08x before cmd17\n", resp.cardStatus);
+
+ if (ntry > handle->device->cfg.retryLimit) {
+ EMMC_TRACE("cmd13 retry reach limit %d\n",
+ handle->device->cfg.retryLimit);
+ return SD_CMD_TIMEOUT;
+ }
+
+ ntry++;
+ EMMC_TRACE("cmd13 retry %d\n", ntry);
+
+ SD_US_DELAY(1000);
+
+ } while (1);
+
+ data_xfer_setup(handle, buffer, len, SD_XFER_CARD_TO_HOST);
+
+ /* send cmd and parse result */
+ argument = addr;
+ options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
+ SD4_EMMC_TOP_CMD_DPS_MASK | SD4_EMMC_TOP_CMD_DTDS_MASK |
+ SD4_EMMC_TOP_CMD_CRC_EN_MASK | SD4_EMMC_TOP_CMD_CCHK_EN_MASK;
+
+ res = send_cmd(handle, SD_CMD_READ_SINGLE_BLOCK, argument, options,
+ &resp);
+
+ if (res != SD_OK)
+ return res;
+
+ res = process_data_xfer(handle, buffer, addr, len, SD_XFER_CARD_TO_HOST);
+
+ return res;
+}
+
+int sd_cmd18(struct sd_handle *handle,
+ uint32_t addr, uint32_t len, uint8_t *buffer)
+{
+ int res;
+ uint32_t argument, options, ntry;
+ struct sd_resp resp;
+
+ ntry = 0;
+ do {
+ res = sd_cmd13(handle, &resp.cardStatus);
+ if (res != SD_OK) {
+ EMMC_TRACE(
+ "cmd 13 failed before cmd18: rca 0x%0x, return %d, response 0x%0x\n",
+ handle->device->ctrl.rca, res, resp.cardStatus);
+ return res;
+ }
+
+ if (resp.cardStatus & 0x100)
+ break;
+
+ EMMC_TRACE("cmd13 rsp:0x%08x before cmd18\n", resp.cardStatus);
+
+ if (ntry > handle->device->cfg.retryLimit) {
+ EMMC_TRACE("cmd13 retry reach limit %d\n",
+ handle->device->cfg.retryLimit);
+ return SD_CMD_TIMEOUT;
+ }
+
+ ntry++;
+ EMMC_TRACE("cmd13 retry %d\n", ntry);
+
+ SD_US_DELAY(1000);
+ } while (1);
+
+ data_xfer_setup(handle, buffer, len, SD_XFER_CARD_TO_HOST);
+
+ argument = addr;
+
+ options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
+ SD4_EMMC_TOP_CMD_DPS_MASK | SD4_EMMC_TOP_CMD_DTDS_MASK |
+ SD4_EMMC_TOP_CMD_MSBS_MASK | SD4_EMMC_TOP_CMD_CCHK_EN_MASK |
+ SD4_EMMC_TOP_CMD_BCEN_MASK | SD4_EMMC_TOP_CMD_CRC_EN_MASK |
+ BIT(SD4_EMMC_TOP_CMD_ACMDEN_SHIFT);
+
+ /* send cmd and parse result */
+ res = send_cmd(handle, SD_CMD_READ_MULTIPLE_BLOCK, argument, options,
+ &resp);
+
+ if (res != SD_OK)
+ return res;
+
+ res = process_data_xfer(handle, buffer, addr, len, SD_XFER_CARD_TO_HOST);
+
+ return res;
+}
+
+#ifdef INCLUDE_EMMC_DRIVER_ERASE_CODE
+static int card_sts_resp(struct sd_handle *handle, uint32_t *status)
+{
+ int res;
+ uint32_t ntry = 0;
+
+ do {
+ res = sd_cmd13(handle, status);
+ if (res != SD_OK) {
+ EMMC_TRACE(
+ "cmd 13 failed before cmd35: rca 0x%0x, return %d\n",
+ handle->device->ctrl.rca, res);
+ return res;
+ }
+
+ if (*status & 0x100)
+ break;
+
+ EMMC_TRACE("cmd13 rsp:0x%08x before cmd35\n", resp.cardStatus);
+
+ if (ntry > handle->device->cfg.retryLimit) {
+ EMMC_TRACE("cmd13 retry reach limit %d\n",
+ handle->device->cfg.retryLimit);
+ return SD_CMD_TIMEOUT;
+ }
+
+ ntry++;
+ EMMC_TRACE("cmd13 retry %d\n", ntry);
+
+ SD_US_DELAY(1000);
+ } while (1);
+
+ return SD_OK;
+}
+
+int sd_cmd35(struct sd_handle *handle, uint32_t start)
+{
+ int res;
+ uint32_t argument, options;
+ struct sd_resp resp;
+
+ res = card_sts_resp(handle, &resp.cardStatus);
+ if (res != SD_OK)
+ return res;
+
+ argument = start;
+
+ options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
+ SD4_EMMC_TOP_CMD_CRC_EN_MASK |
+ SD4_EMMC_TOP_CMD_CCHK_EN_MASK;
+
+ /* send cmd and parse result */
+ res = send_cmd(handle, SD_CMD_ERASE_GROUP_START,
+ argument, options, &resp);
+
+ if (res != SD_OK)
+ return res;
+
+ return res;
+}
+
+int sd_cmd36(struct sd_handle *handle, uint32_t end)
+{
+ int res;
+ uint32_t argument, options;
+ struct sd_resp resp;
+
+ res = card_sts_resp(handle, &resp.cardStatus);
+ if (res != SD_OK)
+ return res;
+
+ argument = end;
+
+ options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
+ SD4_EMMC_TOP_CMD_CRC_EN_MASK |
+ SD4_EMMC_TOP_CMD_CCHK_EN_MASK;
+
+ /* send cmd and parse result */
+ res = send_cmd(handle, SD_CMD_ERASE_GROUP_END,
+ argument, options, &resp);
+
+ if (res != SD_OK)
+ return res;
+
+ return res;
+}
+
+int sd_cmd38(struct sd_handle *handle)
+{
+ int res;
+ uint32_t argument, options;
+ struct sd_resp resp;
+
+ res = card_sts_resp(handle, &resp.cardStatus);
+ if (res != SD_OK)
+ return res;
+
+ argument = 0;
+
+ options = (SD_CMDR_RSP_TYPE_R1b_5b << SD_CMDR_RSP_TYPE_S) |
+ SD4_EMMC_TOP_CMD_CRC_EN_MASK |
+ SD4_EMMC_TOP_CMD_CCHK_EN_MASK;
+
+ /* send cmd and parse result */
+ res = send_cmd(handle, SD_CMD_ERASE, argument, options, &resp);
+
+ if (res != SD_OK)
+ return res;
+
+ return res;
+}
+#endif
+
+#ifdef INCLUDE_EMMC_DRIVER_WRITE_CODE
+
+int sd_cmd24(struct sd_handle *handle,
+ uint32_t addr, uint32_t len, uint8_t *buffer)
+{
+ int res;
+ uint32_t argument, options, ntry;
+ struct sd_resp resp;
+
+ ntry = 0;
+ do {
+ res = sd_cmd13(handle, &resp.cardStatus);
+ if (res != SD_OK) {
+ EMMC_TRACE(
+ "cmd 13 failed before cmd24: rca 0x%0x, return %d, response 0x%0x\n",
+ handle->device->ctrl.rca, res, &resp.cardStatus);
+ return res;
+ }
+
+ if (resp.cardStatus & 0x100)
+ break;
+
+ EMMC_TRACE("cmd13 rsp:0x%08x before cmd24\n", resp.cardStatus);
+
+ if (ntry > handle->device->cfg.retryLimit) {
+ EMMC_TRACE("cmd13 retry reach limit %d\n",
+ handle->device->cfg.retryLimit);
+ return SD_CMD_TIMEOUT;
+ }
+
+ ntry++;
+ EMMC_TRACE("cmd13 retry %d\n", ntry);
+
+ SD_US_DELAY(1000);
+
+ } while (1);
+
+ data_xfer_setup(handle, buffer, len, SD_XFER_HOST_TO_CARD);
+
+ argument = addr;
+
+ options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
+ SD4_EMMC_TOP_CMD_DPS_MASK | SD4_EMMC_TOP_CMD_CRC_EN_MASK |
+ SD4_EMMC_TOP_CMD_CCHK_EN_MASK;
+
+ /* send cmd and parse result */
+ res = send_cmd(handle, SD_CMD_WRITE_BLOCK, argument, options, &resp);
+
+ if (res != SD_OK)
+ return res;
+
+ res = process_data_xfer(handle, buffer, addr, len, SD_XFER_HOST_TO_CARD);
+
+ return res;
+}
+
+int sd_cmd25(struct sd_handle *handle,
+ uint32_t addr, uint32_t len, uint8_t *buffer)
+{
+ int res = SD_OK;
+ uint32_t argument, options, ntry;
+ struct sd_resp resp;
+
+ ntry = 0;
+ do {
+ res = sd_cmd13(handle, &resp.cardStatus);
+ if (res != SD_OK) {
+ EMMC_TRACE(
+ "cmd 13 failed before cmd25: rca 0x%0x, return %d, response 0x%0x\n",
+ handle->device->ctrl.rca, res, &resp.cardStatus);
+ return res;
+ }
+
+ if (resp.cardStatus & 0x100)
+ break;
+
+ EMMC_TRACE("cmd13 rsp:0x%08x before cmd25\n", resp.cardStatus);
+
+ if (ntry > handle->device->cfg.retryLimit) {
+ EMMC_TRACE("cmd13 retry reach limit %d\n",
+ handle->device->cfg.retryLimit);
+ return SD_CMD_TIMEOUT;
+ }
+
+ ntry++;
+ EMMC_TRACE("cmd13 retry %d\n", ntry);
+
+ SD_US_DELAY(1000);
+ } while (1);
+
+ data_xfer_setup(handle, buffer, len, SD_XFER_HOST_TO_CARD);
+
+ argument = addr;
+
+ options = SD_CMDR_RSP_TYPE_R1_5_6 << SD_CMDR_RSP_TYPE_S |
+ SD4_EMMC_TOP_CMD_DPS_MASK | SD4_EMMC_TOP_CMD_MSBS_MASK |
+ SD4_EMMC_TOP_CMD_CCHK_EN_MASK | SD4_EMMC_TOP_CMD_BCEN_MASK |
+ SD4_EMMC_TOP_CMD_CRC_EN_MASK |
+ BIT(SD4_EMMC_TOP_CMD_ACMDEN_SHIFT);
+
+ /* send cmd and parse result */
+ res = send_cmd(handle, SD_CMD_WRITE_MULTIPLE_BLOCK,
+ argument, options, &resp);
+
+ if (res != SD_OK)
+ return res;
+
+ res = process_data_xfer(handle, buffer, addr, len, SD_XFER_HOST_TO_CARD);
+
+ return res;
+}
+#endif /* INCLUDE_EMMC_DRIVER_WRITE_CODE */
+
+int mmc_cmd6(struct sd_handle *handle, uint32_t argument)
+{
+ int res;
+ uint32_t options;
+ struct sd_resp resp;
+
+ options = SD_CMDR_RSP_TYPE_R1b_5b << SD_CMDR_RSP_TYPE_S |
+ SD4_EMMC_TOP_CMD_CCHK_EN_MASK | SD4_EMMC_TOP_CMD_CRC_EN_MASK;
+
+ EMMC_TRACE("Sending CMD6 with argument 0x%X\n", argument);
+
+ /* send cmd and parse result */
+ res = send_cmd(handle, SD_ACMD_SET_BUS_WIDTH, argument, options, &resp);
+
+ /*
+ * For R1b type response:
+ * controller issues a COMMAND COMPLETE interrupt when the R1
+ * response is received,
+ * then controller monitors DAT0 for busy status,
+ * controller issues a TRANSFER COMPLETE interrupt when busy signal
+ * clears.
+ */
+ wait_for_event(handle,
+ SD4_EMMC_TOP_INTR_TXDONE_MASK | SD_ERR_INTERRUPTS,
+ handle->device->cfg.wfe_retry);
+
+ if (res == SD_OK) {
+ /* Check result of Cmd6 using Cmd13 to check card status */
+
+ /* Check status using Cmd13 */
+ res = sd_cmd13(handle, &resp.cardStatus);
+
+ if (res == SD_OK) {
+ /* Check bit 7 (SWITCH_ERROR) in card status */
+ if ((resp.cardStatus & 0x80) != 0) {
+ EMMC_TRACE("cmd6 failed: SWITCH_ERROR\n");
+ res = SD_FAIL;
+ }
+ } else {
+ EMMC_TRACE("cmd13 failed after cmd6: ");
+ EMMC_TRACE("rca 0x%0x, return %d, response 0x%0x\n",
+ handle->device->ctrl.rca, res, resp.cardStatus);
+ }
+ }
+
+ return res;
+}
+
+
+#define SD_BUSY_CHECK 0x00203000
+#define DAT0_LEVEL_MASK 0x100000 /* bit20 in PSTATE */
+#define DEV_BUSY_TIMEOUT 600000 /* 60 Sec : 600000 * 100us */
+
+int send_cmd(struct sd_handle *handle, uint32_t cmdIndex, uint32_t argument,
+ uint32_t options, struct sd_resp *resp)
+{
+ int status = SD_OK;
+ uint32_t event = 0, present, timeout = 0, retry = 0, mask = 3;
+ uint32_t temp_resp[4];
+
+ if (handle == NULL) {
+ EMMC_TRACE("Invalid handle for cmd%d\n", cmdIndex);
+ return SD_INVALID_HANDLE;
+ }
+
+ mask = (SD_BUSY_CHECK & options) ? 3 : 1;
+
+RETRY_WRITE_CMD:
+ do {
+ /* Make sure it is ok to send command */
+ present =
+ chal_sd_get_present_status((CHAL_HANDLE *) handle->device);
+ timeout++;
+
+ if (present & mask)
+ SD_US_DELAY(1000);
+ else
+ break;
+
+ } while (timeout < EMMC_BUSY_CMD_TIMEOUT_MS);
+
+ if (timeout >= EMMC_BUSY_CMD_TIMEOUT_MS) {
+ status = SD_CMD_MISSING;
+ EMMC_TRACE("cmd%d timedout %dms\n", cmdIndex, timeout);
+ }
+
+ /* Reset both DAT and CMD line if only of them are stuck */
+ if (present & mask)
+ check_error(handle, SD4_EMMC_TOP_INTR_CMDERROR_MASK);
+
+ handle->device->ctrl.argReg = argument;
+ chal_sd_send_cmd((CHAL_HANDLE *) handle->device, cmdIndex,
+ handle->device->ctrl.argReg, options);
+
+ handle->device->ctrl.cmdIndex = cmdIndex;
+
+ event = wait_for_event(handle,
+ (SD4_EMMC_TOP_INTR_CMDDONE_MASK |
+ SD_ERR_INTERRUPTS),
+ handle->device->cfg.wfe_retry);
+
+ if (handle->device->ctrl.cmdStatus == SD_CMD_MISSING) {
+ retry++;
+
+ if (retry >= handle->device->cfg.retryLimit) {
+ status = SD_CMD_MISSING;
+ EMMC_TRACE("cmd%d retry reaches the limit %d\n",
+ cmdIndex, retry);
+ } else {
+ /* reset both DAT & CMD line if one of them is stuck */
+ present = chal_sd_get_present_status((CHAL_HANDLE *)
+ handle->device);
+
+ if (present & mask)
+ check_error(handle,
+ SD4_EMMC_TOP_INTR_CMDERROR_MASK);
+
+ EMMC_TRACE("cmd%d retry %d PSTATE[0x%08x]\n",
+ cmdIndex, retry,
+ chal_sd_get_present_status((CHAL_HANDLE *)
+ handle->device));
+ goto RETRY_WRITE_CMD;
+ }
+ }
+
+ if (handle->device->ctrl.cmdStatus == SD_OK) {
+ if (resp != NULL) {
+ status =
+ chal_sd_get_response((CHAL_HANDLE *) handle->device,
+ temp_resp);
+ process_cmd_response(handle,
+ handle->device->ctrl.cmdIndex,
+ temp_resp[0], temp_resp[1],
+ temp_resp[2], temp_resp[3], resp);
+ }
+
+ /* Check Device busy after CMD */
+ if ((cmdIndex == 5) || (cmdIndex == 6) || (cmdIndex == 7) ||
+ (cmdIndex == 28) || (cmdIndex == 29) || (cmdIndex == 38)) {
+
+ timeout = 0;
+ do {
+ present =
+ chal_sd_get_present_status((CHAL_HANDLE *)
+ handle->device);
+
+ timeout++;
+
+ /* Dat[0]:bit20 low means device busy */
+ if ((present & DAT0_LEVEL_MASK) == 0) {
+ EMMC_TRACE("Device busy: ");
+ EMMC_TRACE(
+ "cmd%d arg:0x%08x: PSTATE[0x%08x]\n",
+ cmdIndex, argument, present);
+ SD_US_DELAY(100);
+ } else {
+ break;
+ }
+ } while (timeout < DEV_BUSY_TIMEOUT);
+ }
+ } else if (handle->device->ctrl.cmdStatus &&
+ handle->device->ctrl.cmdStatus != SD_CMD_MISSING) {
+ retry++;
+ status = check_error(handle, handle->device->ctrl.cmdStatus);
+
+ EMMC_TRACE(
+ "cmd%d error: cmdStatus:0x%08x error_status:0x%08x\n",
+ cmdIndex, handle->device->ctrl.cmdStatus, status);
+
+ if ((handle->device->ctrl.cmdIndex == 1) ||
+ (handle->device->ctrl.cmdIndex == 5)) {
+ status = event;
+ } else if ((handle->device->ctrl.cmdIndex == 7) ||
+ (handle->device->ctrl.cmdIndex == 41)) {
+ status = event;
+ } else if ((status == SD_ERROR_RECOVERABLE) &&
+ (retry < handle->device->cfg.retryLimit)) {
+ EMMC_TRACE("cmd%d recoverable error ", cmdIndex);
+ EMMC_TRACE("retry %d PSTATE[0x%08x].\n", retry,
+ chal_sd_get_present_status((CHAL_HANDLE *)
+ handle->device));
+ goto RETRY_WRITE_CMD;
+ } else {
+ EMMC_TRACE("cmd%d retry reaches the limit %d\n",
+ cmdIndex, retry);
+ status = event;
+ }
+ }
+
+ handle->device->ctrl.blkReg = 0;
+ /* clear error status for next command */
+ handle->device->ctrl.cmdStatus = 0;
+
+ return status;
+}
diff --git a/drivers/brcm/emmc/emmc_pboot_hal_memory_drv.c b/drivers/brcm/emmc/emmc_pboot_hal_memory_drv.c
new file mode 100644
index 0000000..68f93e7
--- /dev/null
+++ b/drivers/brcm/emmc/emmc_pboot_hal_memory_drv.c
@@ -0,0 +1,621 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <emmc_api.h>
+#include <cmn_plat_util.h>
+
+#define MAX_CMD_RETRY 10
+
+#if EMMC_USE_DMA
+#define USE_DMA 1
+#else
+#define USE_DMA 0
+#endif
+
+struct emmc_global_buffer emmc_global_buf;
+struct emmc_global_buffer *emmc_global_buf_ptr = &emmc_global_buf;
+
+struct emmc_global_vars emmc_global_vars;
+struct emmc_global_vars *emmc_global_vars_ptr = &emmc_global_vars;
+
+static struct sd_handle *sdio_gethandle(void);
+static uint32_t sdio_idle(struct sd_handle *p_sdhandle);
+
+static uint32_t sdio_read(struct sd_handle *p_sdhandle,
+ uintptr_t mem_addr,
+ uintptr_t storage_addr,
+ size_t storage_size,
+ size_t bytes_to_read);
+
+#ifdef INCLUDE_EMMC_DRIVER_WRITE_CODE
+static uint32_t sdio_write(struct sd_handle *p_sdhandle,
+ uintptr_t mem_addr,
+ uintptr_t data_addr,
+ size_t bytes_to_write);
+#endif
+
+static struct sd_handle *sdio_init(void);
+static int32_t bcm_emmc_card_ready_state(struct sd_handle *p_sdhandle);
+
+static void init_globals(void)
+{
+ memset((void *)emmc_global_buf_ptr, 0, sizeof(*emmc_global_buf_ptr));
+ memset((void *)emmc_global_vars_ptr, 0, sizeof(*emmc_global_vars_ptr));
+}
+
+/*
+ * This function is used to change partition
+ */
+uint32_t emmc_partition_select(uint32_t partition)
+{
+ int rc;
+ struct sd_handle *sd_handle = sdio_gethandle();
+
+ if (sd_handle->device == 0) {
+ EMMC_TRACE("eMMC init is not done");
+ return 0;
+ }
+
+ switch (partition) {
+ case EMMC_BOOT_PARTITION1:
+ rc = set_boot_config(sd_handle,
+ SDIO_HW_EMMC_EXT_CSD_BOOT_ACC_BOOT1);
+ EMMC_TRACE(
+ "Change to Boot Partition 1 result:%d (0 means SD_OK)\n",
+ rc);
+ break;
+
+ case EMMC_BOOT_PARTITION2:
+ rc = set_boot_config(sd_handle,
+ SDIO_HW_EMMC_EXT_CSD_BOOT_ACC_BOOT2);
+ EMMC_TRACE(
+ "Change to Boot Partition 2 result:%d (0 means SD_OK)\n",
+ rc);
+ break;
+
+ case EMMC_USE_CURRENT_PARTITION:
+ rc = SD_OK;
+ EMMC_TRACE("Stay on current partition");
+ break;
+
+ case EMMC_USER_AREA:
+ default:
+ rc = set_boot_config(sd_handle,
+ SDIO_HW_EMMC_EXT_CSD_BOOT_ACC_USER);
+ EMMC_TRACE("Change to User area result:%d (0 means SD_OK)\n",
+ rc);
+ break;
+
+ }
+ return (rc == SD_OK);
+}
+
+/*
+ * Initialize emmc controller for eMMC
+ * Returns 0 on fail condition
+ */
+uint32_t bcm_emmc_init(bool card_rdy_only)
+{
+ struct sd_handle *p_sdhandle;
+ uint32_t result = 0;
+
+ EMMC_TRACE("Enter emmc_controller_init()\n");
+
+ /* If eMMC is already initialized, skip init */
+ if (emmc_global_vars_ptr->init_done)
+ return 1;
+
+ init_globals();
+
+ p_sdhandle = sdio_init();
+
+ if (p_sdhandle == NULL) {
+ ERROR("eMMC init failed");
+ return result;
+ }
+
+ if (card_rdy_only) {
+ /* Put the card in Ready state, Not complete init */
+ result = bcm_emmc_card_ready_state(p_sdhandle);
+ return !result;
+ }
+
+ if (sdio_idle(p_sdhandle) == EMMC_BOOT_OK) {
+ set_config(p_sdhandle, SD_NORMAL_SPEED, MAX_CMD_RETRY, USE_DMA,
+ SD_DMA_BOUNDARY_256K, EMMC_BLOCK_SIZE,
+ EMMC_WFE_RETRY);
+
+ if (!select_blk_sz(p_sdhandle,
+ p_sdhandle->device->cfg.blockSize)) {
+ emmc_global_vars_ptr->init_done = 1;
+ result = 1;
+ } else {
+ ERROR("Select Block Size failed\n");
+ }
+ } else {
+ ERROR("eMMC init failed");
+ }
+
+ /* Initialization is failed, so deinit HW setting */
+ if (result == 0)
+ emmc_deinit();
+
+ return result;
+}
+
+/*
+ * Function to de-init SDIO controller for eMMC
+ */
+void emmc_deinit(void)
+{
+ emmc_global_vars_ptr->init_done = 0;
+ emmc_global_vars_ptr->sdHandle.card = 0;
+ emmc_global_vars_ptr->sdHandle.device = 0;
+}
+
+/*
+ * Read eMMC memory
+ * Returns read_size
+ */
+uint32_t emmc_read(uintptr_t mem_addr, uintptr_t storage_addr,
+ size_t storage_size, size_t bytes_to_read)
+{
+ struct sd_handle *sd_handle = sdio_gethandle();
+
+ if (sd_handle->device == 0) {
+ EMMC_TRACE("eMMC init is not done");
+ return 0;
+ }
+
+ return sdio_read(sdio_gethandle(), mem_addr, storage_addr,
+ storage_size, bytes_to_read);
+}
+
+#ifdef INCLUDE_EMMC_DRIVER_ERASE_CODE
+#define EXT_CSD_ERASE_GRP_SIZE 224
+
+static int emmc_block_erase(uintptr_t mem_addr, size_t blocks)
+{
+ struct sd_handle *sd_handle = sdio_gethandle();
+
+ if (sd_handle->device == 0) {
+ ERROR("eMMC init is not done");
+ return -1;
+ }
+
+ return erase_card(sdio_gethandle(), mem_addr, blocks);
+}
+
+int emmc_erase(uintptr_t mem_addr, size_t num_of_blocks, uint32_t partition)
+{
+ int err = 0;
+ size_t block_count = 0, blocks = 0;
+ size_t erase_group = 0;
+
+ erase_group =
+ emmc_global_buf_ptr->u.Ext_CSD_storage[EXT_CSD_ERASE_GRP_SIZE]*1024;
+
+ INFO("eMMC Erase Group Size=0x%lx\n", erase_group);
+
+ emmc_partition_select(partition);
+
+ while (block_count < num_of_blocks) {
+ blocks = ((num_of_blocks - block_count) > erase_group) ?
+ erase_group : (num_of_blocks - block_count);
+ err = emmc_block_erase(mem_addr + block_count, blocks);
+ if (err)
+ break;
+
+ block_count += blocks;
+ }
+
+ if (err == 0)
+ INFO("eMMC Erase of partition %d successful\n", partition);
+ else
+ ERROR("eMMC Erase of partition %d Failed(%i)\n", partition, err);
+
+ return err;
+}
+#endif
+
+#ifdef INCLUDE_EMMC_DRIVER_WRITE_CODE
+/*
+ * Write to eMMC memory
+ * Returns written_size
+ */
+uint32_t emmc_write(uintptr_t mem_addr, uintptr_t data_addr,
+ size_t bytes_to_write)
+{
+ struct sd_handle *sd_handle = sdio_gethandle();
+
+ if (sd_handle->device == 0) {
+ EMMC_TRACE("eMMC init is not done");
+ return 0;
+ }
+
+ return sdio_write(sd_handle, mem_addr, data_addr, bytes_to_write);
+}
+#endif
+
+/*
+ * Send SDIO Cmd
+ * Return 0 for pass condition
+ */
+uint32_t send_sdio_cmd(uint32_t cmdIndex, uint32_t argument,
+ uint32_t options, struct sd_resp *resp)
+{
+ struct sd_handle *sd_handle = sdio_gethandle();
+
+ if (sd_handle->device == 0) {
+ EMMC_TRACE("eMMC init is not done");
+ return 1;
+ }
+
+ return send_cmd(sd_handle, cmdIndex, argument, options, resp);
+}
+
+
+/*
+ * This function return SDIO handle
+ */
+struct sd_handle *sdio_gethandle(void)
+{
+ return &emmc_global_vars_ptr->sdHandle;
+}
+
+/*
+ * Initialize SDIO controller
+ */
+struct sd_handle *sdio_init(void)
+{
+ uint32_t SDIO_base;
+ struct sd_handle *p_sdhandle = &emmc_global_vars_ptr->sdHandle;
+
+ SDIO_base = EMMC_CTRL_REGS_BASE_ADDR;
+
+ if (SDIO_base == SDIO0_EMMCSDXC_SYSADDR)
+ EMMC_TRACE(" ---> for SDIO 0 Controller\n\n");
+
+ memset(p_sdhandle, 0, sizeof(struct sd_handle));
+
+ p_sdhandle->device = &emmc_global_vars_ptr->sdDevice;
+ p_sdhandle->card = &emmc_global_vars_ptr->sdCard;
+
+ memset(p_sdhandle->device, 0, sizeof(struct sd_dev));
+ memset(p_sdhandle->card, 0, sizeof(struct sd_card_info));
+
+ if (chal_sd_start((CHAL_HANDLE *) p_sdhandle->device,
+ SD_PIO_MODE, SDIO_base, SDIO_base) != SD_OK)
+ return NULL;
+
+ set_config(p_sdhandle, SD_NORMAL_SPEED, MAX_CMD_RETRY, SD_DMA_OFF,
+ SD_DMA_BOUNDARY_4K, EMMC_BLOCK_SIZE, EMMC_WFE_RETRY);
+
+ return &emmc_global_vars_ptr->sdHandle;
+}
+
+uint32_t sdio_idle(struct sd_handle *p_sdhandle)
+{
+ reset_card(p_sdhandle);
+
+ SD_US_DELAY(1000);
+
+ if (init_card(p_sdhandle, SD_CARD_DETECT_MMC) != SD_OK) {
+ reset_card(p_sdhandle);
+ reset_host_ctrl(p_sdhandle);
+ return EMMC_BOOT_NO_CARD;
+ }
+
+ return EMMC_BOOT_OK;
+}
+
+/*
+ * This function read eMMC
+ */
+uint32_t sdio_read(struct sd_handle *p_sdhandle,
+ uintptr_t mem_addr,
+ uintptr_t storage_addr,
+ size_t storage_size, size_t bytes_to_read)
+{
+ uint32_t offset = 0, blockAddr, readLen = 0, rdCount;
+ uint32_t remSize, manual_copy_size;
+ uint8_t *outputBuf = (uint8_t *) storage_addr;
+ const size_t blockSize = p_sdhandle->device->cfg.blockSize;
+
+ VERBOSE("EMMC READ: dst=0x%lx, src=0x%lx, size=0x%lx\n",
+ storage_addr, mem_addr, bytes_to_read);
+
+ if (storage_size < bytes_to_read)
+ /* Don't have sufficient storage to complete the operation */
+ return 0;
+
+ /* Range check non high capacity memory */
+ if ((p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY) == 0) {
+ if (mem_addr > 0x80000000)
+ return 0;
+ }
+
+ /* High capacity card use block address mode */
+ if (p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY) {
+ blockAddr = (uint32_t) (mem_addr / blockSize);
+ offset = (uint32_t) (mem_addr - (blockAddr * blockSize));
+ } else {
+ blockAddr = (uint32_t) (mem_addr / blockSize) * blockSize;
+ offset = (uint32_t) (mem_addr - blockAddr);
+ }
+
+ remSize = bytes_to_read;
+
+ rdCount = 0;
+
+ /* Process first unaligned block of MAX_READ_LENGTH */
+ if (offset > 0) {
+ if (!read_block(p_sdhandle, emmc_global_buf_ptr->u.tempbuf,
+ blockAddr, SD_MAX_READ_LENGTH)) {
+
+ if (remSize < (blockSize - offset)) {
+ rdCount += remSize;
+ manual_copy_size = remSize;
+ remSize = 0; /* read is done */
+ } else {
+ remSize -= (blockSize - offset);
+ rdCount += (blockSize - offset);
+ manual_copy_size = blockSize - offset;
+ }
+
+ /* Check for overflow */
+ if (manual_copy_size > storage_size ||
+ (((uintptr_t)outputBuf + manual_copy_size) >
+ (storage_addr + storage_size))) {
+ ERROR("EMMC READ: Overflow 1\n");
+ return 0;
+ }
+
+ memcpy(outputBuf,
+ (void *)((uintptr_t)
+ (emmc_global_buf_ptr->u.tempbuf + offset)),
+ manual_copy_size);
+
+ /* Update Physical address */
+ outputBuf += manual_copy_size;
+
+ if (p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY)
+ blockAddr++;
+ else
+ blockAddr += blockSize;
+ } else {
+ return 0;
+ }
+ }
+
+ while (remSize >= blockSize) {
+
+ if (remSize >= SD_MAX_BLK_TRANSFER_LENGTH)
+ readLen = SD_MAX_BLK_TRANSFER_LENGTH;
+ else
+ readLen = (remSize / blockSize) * blockSize;
+
+ /* Check for overflow */
+ if ((rdCount + readLen) > storage_size ||
+ (((uintptr_t) outputBuf + readLen) >
+ (storage_addr + storage_size))) {
+ ERROR("EMMC READ: Overflow\n");
+ return 0;
+ }
+
+ if (!read_block(p_sdhandle, outputBuf, blockAddr, readLen)) {
+ if (p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY)
+ blockAddr += (readLen / blockSize);
+ else
+ blockAddr += readLen;
+
+ remSize -= readLen;
+ rdCount += readLen;
+
+ /* Update Physical address */
+ outputBuf += readLen;
+ } else {
+ return 0;
+ }
+ }
+
+ /* process the last unaligned block reading */
+ if (remSize > 0) {
+ if (!read_block(p_sdhandle, emmc_global_buf_ptr->u.tempbuf,
+ blockAddr, SD_MAX_READ_LENGTH)) {
+
+ rdCount += remSize;
+ /* Check for overflow */
+ if (rdCount > storage_size ||
+ (((uintptr_t) outputBuf + remSize) >
+ (storage_addr + storage_size))) {
+ ERROR("EMMC READ: Overflow\n");
+ return 0;
+ }
+
+ memcpy(outputBuf,
+ emmc_global_buf_ptr->u.tempbuf, remSize);
+
+ /* Update Physical address */
+ outputBuf += remSize;
+ } else {
+ rdCount = 0;
+ }
+ }
+
+ return rdCount;
+}
+
+#ifdef INCLUDE_EMMC_DRIVER_WRITE_CODE
+static uint32_t sdio_write(struct sd_handle *p_sdhandle, uintptr_t mem_addr,
+ uintptr_t data_addr, size_t bytes_to_write)
+{
+
+ uint32_t offset, blockAddr, writeLen, wtCount = 0;
+ uint32_t remSize, manual_copy_size = 0;
+
+ uint8_t *inputBuf = (uint8_t *)data_addr;
+
+ /* range check non high capacity memory */
+ if ((p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY) == 0) {
+ if (mem_addr > 0x80000000)
+ return 0;
+ }
+
+ /* the high capacity card use block address mode */
+ if (p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY) {
+ blockAddr =
+ (uint32_t)(mem_addr / p_sdhandle->device->cfg.blockSize);
+ offset =
+ (uint32_t)(mem_addr -
+ blockAddr * p_sdhandle->device->cfg.blockSize);
+ } else {
+ blockAddr =
+ ((uint32_t)mem_addr / p_sdhandle->device->cfg.blockSize) *
+ p_sdhandle->device->cfg.blockSize;
+ offset = (uint32_t) mem_addr - blockAddr;
+ }
+
+ remSize = bytes_to_write;
+
+ wtCount = 0;
+
+ /* process first unaligned block */
+ if (offset > 0) {
+ if (!read_block(p_sdhandle, emmc_global_buf_ptr->u.tempbuf,
+ blockAddr, p_sdhandle->device->cfg.blockSize)) {
+
+ if (remSize <
+ (p_sdhandle->device->cfg.blockSize - offset))
+ manual_copy_size = remSize;
+ else
+ manual_copy_size =
+ p_sdhandle->device->cfg.blockSize - offset;
+
+ memcpy((void *)((uintptr_t)
+ (emmc_global_buf_ptr->u.tempbuf + offset)),
+ inputBuf,
+ manual_copy_size);
+
+ /* Update Physical address */
+
+ if (!write_block(p_sdhandle,
+ emmc_global_buf_ptr->u.tempbuf,
+ blockAddr,
+ p_sdhandle->device->cfg.blockSize)) {
+
+ if (remSize <
+ (p_sdhandle->device->cfg.blockSize -
+ offset)) {
+ wtCount += remSize;
+ manual_copy_size = remSize;
+ remSize = 0; /* read is done */
+ } else {
+ remSize -=
+ (p_sdhandle->device->cfg.blockSize -
+ offset);
+ wtCount +=
+ (p_sdhandle->device->cfg.blockSize -
+ offset);
+ manual_copy_size =
+ p_sdhandle->device->cfg.blockSize -
+ offset;
+ }
+
+ inputBuf += manual_copy_size;
+
+ if (p_sdhandle->device->ctrl.ocr &
+ SD_CARD_HIGH_CAPACITY)
+ blockAddr++;
+ else
+ blockAddr +=
+ p_sdhandle->device->cfg.blockSize;
+ } else
+ return 0;
+ } else {
+ return 0;
+ }
+ }
+
+ /* process block writing */
+ while (remSize >= p_sdhandle->device->cfg.blockSize) {
+ if (remSize >= SD_MAX_READ_LENGTH) {
+ writeLen = SD_MAX_READ_LENGTH;
+ } else {
+ writeLen =
+ (remSize / p_sdhandle->device->cfg.blockSize) *
+ p_sdhandle->device->cfg.blockSize;
+ }
+
+ if (!write_block(p_sdhandle, inputBuf, blockAddr, writeLen)) {
+ if (p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY)
+ blockAddr +=
+ (writeLen /
+ p_sdhandle->device->cfg.blockSize);
+ else
+ blockAddr += writeLen;
+
+ remSize -= writeLen;
+ wtCount += writeLen;
+ inputBuf += writeLen;
+ } else {
+ return 0;
+ }
+ }
+
+ /* process the last unaligned block reading */
+ if (remSize > 0) {
+ if (!read_block(p_sdhandle,
+ emmc_global_buf_ptr->u.tempbuf,
+ blockAddr, p_sdhandle->device->cfg.blockSize)) {
+
+ memcpy(emmc_global_buf_ptr->u.tempbuf,
+ inputBuf, remSize);
+
+ /* Update Physical address */
+
+ if (!write_block(p_sdhandle,
+ emmc_global_buf_ptr->u.tempbuf,
+ blockAddr,
+ p_sdhandle->device->cfg.blockSize)) {
+ wtCount += remSize;
+ inputBuf += remSize;
+ } else {
+ return 0;
+ }
+ } else {
+ wtCount = 0;
+ }
+ }
+
+ return wtCount;
+}
+#endif
+
+/*
+ * Function to put the card in Ready state by sending CMD0 and CMD1
+ */
+static int32_t bcm_emmc_card_ready_state(struct sd_handle *p_sdhandle)
+{
+ int32_t result = 0;
+ uint32_t argument = MMC_CMD_IDLE_RESET_ARG; /* Exit from Boot mode */
+
+ if (p_sdhandle) {
+ send_sdio_cmd(SD_CMD_GO_IDLE_STATE, argument, 0, NULL);
+
+ result = reset_card(p_sdhandle);
+ if (result != SD_OK) {
+ EMMC_TRACE("eMMC Reset error\n");
+ return SD_RESET_ERROR;
+ }
+ SD_US_DELAY(2000);
+ result = mmc_cmd1(p_sdhandle);
+ }
+
+ return result;
+}
diff --git a/drivers/brcm/i2c/i2c.c b/drivers/brcm/i2c/i2c.c
new file mode 100644
index 0000000..2096a82
--- /dev/null
+++ b/drivers/brcm/i2c/i2c.c
@@ -0,0 +1,886 @@
+/*
+ * Copyright (c) 2016 - 2021, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <i2c.h>
+#include <i2c_regs.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+/* Max instances */
+#define MAX_I2C 2U
+
+/* Transaction error codes defined in Master command register (0x30) */
+#define MSTR_STS_XACT_SUCCESS 0U
+#define MSTR_STS_LOST_ARB 1U
+#define MSTR_STS_NACK_FIRST_BYTE 2U
+ /* NACK on a byte other than the first byte */
+#define MSTR_STS_NACK_NON_FIRST_BYTE 3U
+
+#define MSTR_STS_TTIMEOUT_EXCEEDED 4U
+#define MSTR_STS_TX_TLOW_MEXT_EXCEEDED 5U
+#define MSTR_STS_RX_TLOW_MEXT_EXCEEDED 6U
+
+/* SMBUS protocol values defined in register 0x30 */
+#define SMBUS_PROT_QUICK_CMD 0U
+#define SMBUS_PROT_SEND_BYTE 1U
+#define SMBUS_PROT_RECV_BYTE 2U
+#define SMBUS_PROT_WR_BYTE 3U
+#define SMBUS_PROT_RD_BYTE 4U
+#define SMBUS_PROT_WR_WORD 5U
+#define SMBUS_PROT_RD_WORD 6U
+#define SMBUS_PROT_BLK_WR 7U
+#define SMBUS_PROT_BLK_RD 8U
+#define SMBUS_PROT_PROC_CALL 9U
+#define SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL 10U
+
+/* Number can be changed later */
+#define BUS_BUSY_COUNT 100000U
+
+#define IPROC_I2C_INVALID_ADDR 0xFFU
+
+#define I2C_SMBUS_BLOCK_MAX 32U
+
+/*
+ * Enum to specify clock speed. The user will provide it during initialization.
+ * If needed, it can be changed dynamically
+ */
+typedef enum iproc_smb_clk_freq {
+ IPROC_SMB_SPEED_100KHz = 0,
+ IPROC_SMB_SPEED_400KHz = 1,
+ IPROC_SMB_SPEED_INVALID = 255
+} smb_clk_freq_t;
+
+/* Structure used to pass information to read/write functions. */
+struct iproc_xact_info {
+ /* Bus Identifier */
+ uint32_t bus_id;
+ /* Device Address */
+ uint8_t devaddr;
+ /* Passed by caller to send SMBus command cod e*/
+ uint8_t command;
+ /* actual data passed by the caller */
+ uint8_t *data;
+ /* Size of data buffer passed */
+ uint32_t size;
+ /* Sent by caller specifying PEC, 10-bit addresses */
+ uint16_t flags;
+ /* SMBus protocol to use to perform transaction */
+ uint8_t smb_proto;
+ /* true if command field below is valid. Otherwise, false */
+ uint32_t cmd_valid;
+};
+
+static const uintptr_t smbus_base_reg_addr[MAX_I2C] = {
+ SMBUS0_REGS_BASE,
+ SMBUS1_REGS_BASE
+};
+
+/* Function to read a value from specified register. */
+static uint32_t iproc_i2c_reg_read(uint32_t bus_id, unsigned long reg_addr)
+{
+ uint32_t val;
+ uintptr_t smbus;
+
+ smbus = smbus_base_reg_addr[bus_id];
+
+ val = mmio_read_32(smbus + reg_addr);
+ VERBOSE("i2c %u: reg %p read 0x%x\n", bus_id,
+ (void *)(smbus + reg_addr), val);
+ return val;
+}
+
+/* Function to write a value ('val') in to a specified register. */
+static void iproc_i2c_reg_write(uint32_t bus_id,
+ unsigned long reg_addr,
+ uint32_t val)
+{
+ uintptr_t smbus;
+
+ smbus = smbus_base_reg_addr[bus_id];
+
+ mmio_write_32((smbus + reg_addr), val);
+ VERBOSE("i2c %u: reg %p wrote 0x%x\n", bus_id,
+ (void *)(smbus + reg_addr), val);
+}
+
+/* Function to clear and set bits in a specified register. */
+static void iproc_i2c_reg_clearset(uint32_t bus_id,
+ unsigned long reg_addr,
+ uint32_t clear,
+ uint32_t set)
+{
+ uintptr_t smbus;
+
+ smbus = smbus_base_reg_addr[bus_id];
+
+ mmio_clrsetbits_32((smbus + reg_addr), clear, set);
+ VERBOSE("i2c %u: reg %p clear 0x%x, set 0x%x\n", bus_id,
+ (void *)(smbus + reg_addr), clear, set);
+}
+
+/* Function to dump all SMBUS register */
+#ifdef BCM_I2C_DEBUG
+static int iproc_dump_i2c_regs(uint32_t bus_id)
+{
+ uint32_t regval;
+
+ if (bus_id > MAX_I2C) {
+ return -1;
+ }
+
+ INFO("----------------------------------------------\n");
+ INFO("%s: Dumping SMBus %u registers...\n", __func__, bus_id);
+
+ regval = iproc_i2c_reg_read(bus_id, SMB_CFG_REG);
+ INFO("SMB_CFG_REG=0x%x\n", regval);
+
+ regval = iproc_i2c_reg_read(bus_id, SMB_TIMGCFG_REG);
+ INFO("SMB_TIMGCFG_REG=0x%x\n", regval);
+
+ regval = iproc_i2c_reg_read(bus_id, SMB_ADDR_REG);
+ INFO("SMB_ADDR_REG=0x%x\n", regval);
+
+ regval = iproc_i2c_reg_read(bus_id, SMB_MSTRFIFOCTL_REG);
+ INFO("SMB_MSTRFIFOCTL_REG=0x%x\n", regval);
+
+ regval = iproc_i2c_reg_read(bus_id, SMB_SLVFIFOCTL_REG);
+ INFO("SMB_SLVFIFOCTL_REG=0x%x\n", regval);
+
+ regval = iproc_i2c_reg_read(bus_id, SMB_BITBANGCTL_REG);
+ INFO("SMB_BITBANGCTL_REG=0x%x\n", regval);
+
+ regval = iproc_i2c_reg_read(bus_id, SMB_MSTRCMD_REG);
+ INFO("SMB_MSTRCMD_REG=0x%x\n", regval);
+
+ regval = iproc_i2c_reg_read(bus_id, SMB_SLVCMD_REG);
+ INFO("SMB_SLVCMD_REG=0x%x\n", regval);
+
+ regval = iproc_i2c_reg_read(bus_id, SMB_EVTEN_REG);
+ INFO("SMB_EVTEN_REG=0x%x\n", regval);
+
+ regval = iproc_i2c_reg_read(bus_id, SMB_EVTSTS_REG);
+ INFO("SMB_EVTSTS_REG=0x%x\n", regval);
+
+ regval = iproc_i2c_reg_read(bus_id, SMB_MSTRDATAWR_REG);
+ INFO("SMB_MSTRDATAWR_REG=0x%x\n", regval);
+
+ regval = iproc_i2c_reg_read(bus_id, SMB_MSTRDATARD_REG);
+ INFO("SMB_MSTRDATARD_REG=0x%x\n", regval);
+
+ regval = iproc_i2c_reg_read(bus_id, SMB_SLVDATAWR_REG);
+ INFO("SMB_SLVDATAWR_REG=0x%x\n", regval);
+
+ regval = iproc_i2c_reg_read(bus_id, SMB_SLVDATARD_REG);
+ INFO("SMB_SLVDATARD_REG=0x%x\n", regval);
+
+ INFO("----------------------------------------------\n");
+ return 0;
+}
+#endif
+
+/*
+ * Function to ensure that the previous transaction was completed before
+ * initiating a new transaction. It can also be used in polling mode to
+ * check status of completion of a command
+ */
+static int iproc_i2c_startbusy_wait(uint32_t bus_id)
+{
+ uint32_t regval;
+ uint32_t retry = 0U;
+
+ /*
+ * Check if an operation is in progress. During probe it won't be.
+ * Want to make sure that the transaction in progress is completed.
+ */
+ do {
+ udelay(1U);
+ regval = iproc_i2c_reg_read(bus_id, SMB_MSTRCMD_REG);
+ regval &= SMB_MSTRSTARTBUSYCMD_MASK;
+ if (retry++ > BUS_BUSY_COUNT) {
+ ERROR("%s: START_BUSY bit didn't clear, exiting\n",
+ __func__);
+ return -1;
+ }
+
+ } while (regval != 0U);
+
+ return 0;
+}
+
+/*
+ * This function copies data to SMBus's Tx FIFO. Valid for write transactions
+ * info: Data to copy in to Tx FIFO. For read commands, the size should be
+ * set to zero by the caller
+ */
+static void iproc_i2c_write_trans_data(struct iproc_xact_info *info)
+{
+ uint32_t regval;
+ uint8_t devaddr;
+ uint32_t i;
+ uint32_t num_data_bytes = 0U;
+
+#ifdef BCM_I2C_DEBUG
+ INFO("%s:dev_addr=0x%x,cmd_valid=%d, cmd=0x%x, size=%u proto=%d\n",
+ __func__, info->devaddr, info->cmd_valid, info->command,
+ info->size, info->smb_proto);
+#endif
+ /* Shift devaddr by 1 bit since SMBus uses the low bit[0] for R/W_n */
+ devaddr = (info->devaddr << 1);
+
+ /*
+ * Depending on the SMBus protocol, we need to write additional
+ * transaction data in to Tx FIFO. Refer to section 5.5 of SMBus spec
+ * for sequence for a transaction
+ */
+ switch (info->smb_proto) {
+ case SMBUS_PROT_RECV_BYTE:
+ /* No additional data to be written */
+ iproc_i2c_reg_write(info->bus_id, SMB_MSTRDATAWR_REG,
+ devaddr | 0x1U | SMB_MSTRWRSTS_MASK);
+ break;
+ case SMBUS_PROT_SEND_BYTE:
+ num_data_bytes = info->size;
+ iproc_i2c_reg_write(info->bus_id, SMB_MSTRDATAWR_REG,
+ devaddr);
+ break;
+ case SMBUS_PROT_RD_BYTE:
+ case SMBUS_PROT_RD_WORD:
+ case SMBUS_PROT_BLK_RD:
+ /* Write slave address with R/W~ set (bit #0) */
+ iproc_i2c_reg_write(info->bus_id, SMB_MSTRDATAWR_REG,
+ devaddr | 0x1U);
+ break;
+ case SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL:
+ iproc_i2c_reg_write(info->bus_id, SMB_MSTRDATAWR_REG,
+ devaddr | 0x1U | SMB_MSTRWRSTS_MASK);
+ break;
+ case SMBUS_PROT_WR_BYTE:
+ case SMBUS_PROT_WR_WORD:
+ iproc_i2c_reg_write(info->bus_id, SMB_MSTRDATAWR_REG,
+ devaddr);
+ /*
+ * No additional bytes to be written. Data portion is written
+ * in the 'for' loop below
+ */
+ num_data_bytes = info->size;
+ break;
+ case SMBUS_PROT_BLK_WR:
+ iproc_i2c_reg_write(info->bus_id, SMB_MSTRDATAWR_REG,
+ devaddr);
+ /* 3rd byte is byte count */
+ iproc_i2c_reg_write(info->bus_id, SMB_MSTRDATAWR_REG,
+ info->size);
+ num_data_bytes = info->size;
+ break;
+ default:
+ return;
+ }
+
+ /* If the protocol needs command code, copy it */
+ if (info->cmd_valid) {
+ iproc_i2c_reg_write(info->bus_id, SMB_MSTRDATAWR_REG,
+ info->command);
+ }
+
+ /*
+ * Copy actual data from caller. In general, for reads,
+ * no data is copied.
+ */
+ for (i = 0U; num_data_bytes; --num_data_bytes, i++) {
+ /* For the last byte, set MASTER_WR_STATUS bit */
+ regval = (num_data_bytes == 1U) ?
+ info->data[i] | SMB_MSTRWRSTS_MASK : info->data[i];
+ iproc_i2c_reg_write(info->bus_id, SMB_MSTRDATAWR_REG,
+ regval);
+ }
+}
+
+/*
+ * This function writes to the master command register and
+ * then polls for completion
+ */
+static int iproc_i2c_write_master_command(uint32_t mastercmd,
+ struct iproc_xact_info *info)
+{
+ uint32_t retry = 0U;
+ uint32_t regval;
+
+ iproc_i2c_reg_write(info->bus_id, SMB_MSTRCMD_REG, mastercmd);
+
+ /* Check for Master Busy status */
+ regval = iproc_i2c_reg_read(info->bus_id, SMB_MSTRCMD_REG);
+ while ((regval & SMB_MSTRSTARTBUSYCMD_MASK) != 0U) {
+ udelay(1U);
+ if (retry++ > BUS_BUSY_COUNT) {
+ ERROR("%s: START_BUSY bit didn't clear, exiting\n",
+ __func__);
+ return -1;
+ }
+ regval = iproc_i2c_reg_read(info->bus_id, SMB_MSTRCMD_REG);
+ }
+
+ /* If start_busy bit cleared, check if there are any errors */
+ if (!(regval & SMB_MSTRSTARTBUSYCMD_MASK)) {
+ /* start_busy bit cleared, check master_status field now */
+ regval &= SMB_MSTRSTS_MASK;
+ regval >>= SMB_MSTRSTS_SHIFT;
+ if (regval != MSTR_STS_XACT_SUCCESS) {
+ /* Error We can flush Tx FIFO here */
+ ERROR("%s: ERROR: %u exiting\n", __func__, regval);
+ return -1;
+ }
+ }
+ return 0;
+
+}
+/* Function to initiate data send and verify completion status */
+static int iproc_i2c_data_send(struct iproc_xact_info *info)
+{
+ int rc;
+ uint32_t mastercmd;
+
+ /* Make sure the previous transaction completed */
+ rc = iproc_i2c_startbusy_wait(info->bus_id);
+
+ if (rc < 0) {
+ WARN("%s: Send: bus is busy, exiting\n", __func__);
+ return rc;
+ }
+ /* Write transaction bytes to Tx FIFO */
+ iproc_i2c_write_trans_data(info);
+
+ /*
+ * Program master command register (0x30) with protocol type and set
+ * start_busy_command bit to initiate the write transaction
+ */
+ mastercmd = (info->smb_proto << SMB_MSTRSMBUSPROTO_SHIFT) |
+ SMB_MSTRSTARTBUSYCMD_MASK;
+
+ if (iproc_i2c_write_master_command(mastercmd, info)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Function to initiate data receive, verify completion status,
+ * and read from SMBUS Read FIFO
+ */
+static int iproc_i2c_data_recv(struct iproc_xact_info *info,
+ uint32_t *num_bytes_read)
+{
+ int rc;
+ uint32_t mastercmd;
+ uint32_t regval;
+
+ /* Make sure the previous transaction completed */
+ rc = iproc_i2c_startbusy_wait(info->bus_id);
+
+ if (rc < 0) {
+ WARN("%s: Receive: Bus is busy, exiting\n", __func__);
+ return rc;
+ }
+
+ /* Program all transaction bytes into master Tx FIFO */
+ iproc_i2c_write_trans_data(info);
+
+ /*
+ * Program master command register (0x30) with protocol type and set
+ * start_busy_command bit to initiate the write transaction
+ */
+ mastercmd = (info->smb_proto << SMB_MSTRSMBUSPROTO_SHIFT) |
+ SMB_MSTRSTARTBUSYCMD_MASK | info->size;
+
+ if (iproc_i2c_write_master_command(mastercmd, info)) {
+ return -1;
+ }
+
+ /* Read received byte(s), after TX out address etc */
+ regval = iproc_i2c_reg_read(info->bus_id, SMB_MSTRDATARD_REG);
+
+ /* For block read, protocol (hw) returns byte count,as the first byte */
+ if (info->smb_proto == SMBUS_PROT_BLK_RD) {
+ uint32_t i;
+
+ *num_bytes_read = regval & SMB_MSTRRDDATA_MASK;
+ /*
+ * Limit to reading a max of 32 bytes only; just a safeguard.
+ * If # bytes read is a number > 32, check transaction set up,
+ * and contact hw engg.
+ * Assumption: PEC is disabled
+ */
+ for (i = 0U; (i < *num_bytes_read) &&
+ (i < I2C_SMBUS_BLOCK_MAX); i++) {
+ /* Read Rx FIFO for data bytes */
+ regval = iproc_i2c_reg_read(info->bus_id,
+ SMB_MSTRDATARD_REG);
+ info->data[i] = regval & SMB_MSTRRDDATA_MASK;
+ }
+ } else {
+ /* 1 Byte data */
+ *info->data = regval & SMB_MSTRRDDATA_MASK;
+ *num_bytes_read = 1U;
+ }
+
+ return 0;
+}
+
+/*
+ * This function set clock frequency for SMBus block. As per hardware
+ * engineering, the clock frequency can be changed dynamically.
+ */
+static int iproc_i2c_set_clk_freq(uint32_t bus_id, smb_clk_freq_t freq)
+{
+ uint32_t val;
+
+ switch (freq) {
+ case IPROC_SMB_SPEED_100KHz:
+ val = 0U;
+ break;
+ case IPROC_SMB_SPEED_400KHz:
+ val = 1U;
+ break;
+ default:
+ return -1;
+ }
+
+ iproc_i2c_reg_clearset(bus_id, SMB_TIMGCFG_REG,
+ SMB_TIMGCFG_MODE400_MASK,
+ val << SMB_TIMGCFG_MODE400_SHIFT);
+
+ return 0;
+}
+
+/* Helper function to fill the iproc_xact_info structure */
+static void iproc_i2c_fill_info(struct iproc_xact_info *info, uint32_t bus_id,
+ uint8_t devaddr, uint8_t cmd, uint8_t *value,
+ uint8_t smb_proto, uint32_t cmd_valid)
+{
+ info->bus_id = bus_id;
+ info->devaddr = devaddr;
+ info->command = (uint8_t)cmd;
+ info->smb_proto = smb_proto;
+ info->data = value;
+ info->size = 1U;
+ info->flags = 0U;
+ info->cmd_valid = cmd_valid;
+}
+
+/* This function initializes the SMBUS */
+static void iproc_i2c_init(uint32_t bus_id, int speed)
+{
+ uint32_t regval;
+
+#ifdef BCM_I2C_DEBUG
+ INFO("%s: Enter Init\n", __func__);
+#endif
+
+ /* Put controller in reset */
+ regval = iproc_i2c_reg_read(bus_id, SMB_CFG_REG);
+ regval |= BIT(SMB_CFG_RST_SHIFT);
+ regval &= ~(BIT(SMB_CFG_SMBEN_SHIFT));
+ iproc_i2c_reg_write(bus_id, SMB_CFG_REG, regval);
+
+ /* Wait 100 usec per spec */
+ udelay(100U);
+
+ /* Bring controller out of reset */
+ regval &= ~(BIT(SMB_CFG_RST_SHIFT));
+ iproc_i2c_reg_write(bus_id, SMB_CFG_REG, regval);
+
+ /*
+ * Flush Tx, Rx FIFOs. Note we are setting the Rx FIFO threshold to 0.
+ * May be OK since we are setting RX_EVENT and RX_FIFO_FULL interrupts
+ */
+ regval = SMB_MSTRRXFIFOFLSH_MASK | SMB_MSTRTXFIFOFLSH_MASK;
+ iproc_i2c_reg_write(bus_id, SMB_MSTRFIFOCTL_REG, regval);
+
+ /*
+ * Enable SMbus block. Note, we are setting MASTER_RETRY_COUNT to zero
+ * since there will be only one master
+ */
+
+ regval = iproc_i2c_reg_read(bus_id, SMB_CFG_REG);
+ regval |= SMB_CFG_SMBEN_MASK;
+ iproc_i2c_reg_write(bus_id, SMB_CFG_REG, regval);
+ /* Wait a minimum of 50 Usec, as per SMB hw doc. But we wait longer */
+ mdelay(10U);
+
+ /* If error then set default speed */
+ if (i2c_set_bus_speed(bus_id, speed)) {
+ i2c_set_bus_speed(bus_id, I2C_SPEED_DEFAULT);
+ }
+
+ /* Disable intrs */
+ regval = 0x0U;
+ iproc_i2c_reg_write(bus_id, SMB_EVTEN_REG, regval);
+
+ /* Clear intrs (W1TC) */
+ regval = iproc_i2c_reg_read(bus_id, SMB_EVTSTS_REG);
+ iproc_i2c_reg_write(bus_id, SMB_EVTSTS_REG, regval);
+
+#ifdef BCM_I2C_DEBUG
+ iproc_dump_i2c_regs(bus_id);
+
+ INFO("%s: Exit Init Successfully\n", __func__);
+#endif
+}
+
+/*
+ * Function Name: i2c_init
+ *
+ * Description:
+ * This function initializes the SMBUS.
+ *
+ * Parameters:
+ * bus_id - I2C bus ID
+ * speed - I2C bus speed in Hz
+ *
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+int i2c_init(uint32_t bus_id, int speed)
+{
+ if (bus_id > MAX_I2C) {
+ WARN("%s: Invalid Bus %u\n", __func__, bus_id);
+ return -1;
+ }
+
+ iproc_i2c_init(bus_id, speed);
+ return 0U;
+}
+
+/*
+ * Function Name: i2c_probe
+ *
+ * Description:
+ * This function probes the I2C bus for the existence of the specified
+ * device.
+ *
+ * Parameters:
+ * bus_id - I2C bus ID
+ * devaddr - Device Address
+ *
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+int i2c_probe(uint32_t bus_id, uint8_t devaddr)
+{
+ uint32_t regval;
+ int rc;
+
+ /*
+ * i2c_init() Initializes internal regs, disable intrs (and then clear intrs),
+ * set fifo thresholds, etc.
+ * Shift devaddr by 1 bit since SMBus uses the low bit[0] for R/W_n
+ */
+ regval = (devaddr << 1U);
+ iproc_i2c_reg_write(bus_id, SMB_MSTRDATAWR_REG, regval);
+
+ regval = ((SMBUS_PROT_QUICK_CMD << SMB_MSTRSMBUSPROTO_SHIFT) |
+ SMB_MSTRSTARTBUSYCMD_MASK);
+ iproc_i2c_reg_write(bus_id, SMB_MSTRCMD_REG, regval);
+
+ rc = iproc_i2c_startbusy_wait(bus_id);
+
+ if (rc < 0) {
+ WARN("%s: Probe: bus is busy, exiting\n", __func__);
+ return rc;
+ }
+
+ regval = iproc_i2c_reg_read(bus_id, SMB_MSTRCMD_REG);
+ if (((regval & SMB_MSTRSTS_MASK) >> SMB_MSTRSTS_SHIFT) == 0)
+ VERBOSE("i2c device address: 0x%x\n", devaddr);
+ else
+ return -1;
+
+#ifdef BCM_I2C_DEBUG
+ iproc_dump_i2c_regs(bus_id);
+#endif
+ return 0;
+}
+
+/*
+ * Function Name: i2c_recv_byte
+ *
+ * Description:
+ * This function reads I2C data from a device without specifying
+ * a command regsiter.
+ *
+ * Parameters:
+ * bus_id - I2C bus ID
+ * devaddr - Device Address
+ * value - Data Read
+ *
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+int i2c_recv_byte(uint32_t bus_id, uint8_t devaddr, uint8_t *value)
+{
+ int rc;
+ struct iproc_xact_info info;
+ uint32_t num_bytes_read = 0;
+
+ iproc_i2c_fill_info(&info, bus_id, devaddr, 0U, value,
+ SMBUS_PROT_RECV_BYTE, 0U);
+
+ /* Refer to i2c_smbus_read_byte for params passed. */
+ rc = iproc_i2c_data_recv(&info, &num_bytes_read);
+
+ if (rc < 0) {
+ printf("%s: %s error accessing device 0x%x\n",
+ __func__, "Read", devaddr);
+ }
+
+ return rc;
+}
+
+/*
+ * Function Name: i2c_send_byte
+ *
+ * Description:
+ * This function send I2C data to a device without specifying
+ * a command regsiter.
+ *
+ * Parameters:
+ * bus_id - I2C bus ID
+ * devaddr - Device Address
+ * value - Data Send
+ *
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+int i2c_send_byte(uint32_t bus_id, uint8_t devaddr, uint8_t value)
+{
+ int rc;
+ struct iproc_xact_info info;
+
+ iproc_i2c_fill_info(&info, bus_id, devaddr, 0U, &value,
+ SMBUS_PROT_SEND_BYTE, 0U);
+
+ /* Refer to i2c_smbus_write_byte params passed. */
+ rc = iproc_i2c_data_send(&info);
+
+ if (rc < 0) {
+ ERROR("%s: %s error accessing device 0x%x\n",
+ __func__, "Write", devaddr);
+ }
+
+ return rc;
+}
+
+/* Helper function to read a single byte */
+static int i2c_read_byte(uint32_t bus_id,
+ uint8_t devaddr,
+ uint8_t regoffset,
+ uint8_t *value)
+{
+ int rc;
+ struct iproc_xact_info info;
+ uint32_t num_bytes_read = 0U;
+
+ iproc_i2c_fill_info(&info, bus_id, devaddr, regoffset, value,
+ SMBUS_PROT_RD_BYTE, 1U);
+
+ /* Refer to i2c_smbus_read_byte for params passed. */
+ rc = iproc_i2c_data_recv(&info, &num_bytes_read);
+
+ if (rc < 0) {
+ ERROR("%s: %s error accessing device 0x%x\n",
+ __func__, "Read", devaddr);
+ }
+ return rc;
+}
+
+/*
+ * Function Name: i2c_read
+ *
+ * Description:
+ * This function reads I2C data from a device with a designated
+ * command register
+ *
+ * Parameters:
+ * bus_id - I2C bus ID
+ * devaddr - Device Address
+ * addr - Register Offset
+ * alen - Address Length, 1 for byte, 2 for word (not supported)
+ * buffer - Data Buffer
+ * len - Data Length in bytes
+ *
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+int i2c_read(uint32_t bus_id,
+ uint8_t devaddr,
+ uint32_t addr,
+ int alen,
+ uint8_t *buffer,
+ int len)
+{
+ uint32_t i;
+
+ if (alen > 1) {
+ WARN("I2C read: addr len %d not supported\n", alen);
+ return -1;
+ }
+
+ if (addr + len > 256) {
+ WARN("I2C read: address out of range\n");
+ return -1;
+ }
+
+ for (i = 0U; i < len; i++) {
+ if (i2c_read_byte(bus_id, devaddr, addr + i, &buffer[i])) {
+ ERROR("I2C read: I/O error\n");
+ iproc_i2c_init(bus_id, i2c_get_bus_speed(bus_id));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* Helper function to write a single byte */
+static int i2c_write_byte(uint32_t bus_id,
+ uint8_t devaddr,
+ uint8_t regoffset,
+ uint8_t value)
+{
+ int rc;
+ struct iproc_xact_info info;
+
+ iproc_i2c_fill_info(&info, bus_id, devaddr, regoffset, &value,
+ SMBUS_PROT_WR_BYTE, 1U);
+
+ /* Refer to i2c_smbus_write_byte params passed. */
+ rc = iproc_i2c_data_send(&info);
+
+ if (rc < 0) {
+ ERROR("%s: %s error accessing device 0x%x\n",
+ __func__, "Write", devaddr);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Function Name: i2c_write
+ *
+ * Description:
+ * This function write I2C data to a device with a designated
+ * command register
+ *
+ * Parameters:
+ * bus_id - I2C bus ID
+ * devaddr - Device Address
+ * addr - Register Offset
+ * alen - Address Length, 1 for byte, 2 for word (not supported)
+ * buffer - Data Buffer
+ * len - Data Length in bytes
+ *
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+int i2c_write(uint32_t bus_id,
+ uint8_t devaddr,
+ uint32_t addr,
+ int alen,
+ uint8_t *buffer,
+ int len)
+{
+ uint32_t i;
+
+ if (alen > 1) {
+ WARN("I2C write: addr len %d not supported\n", alen);
+ return -1;
+ }
+
+ if (addr + len > 256U) {
+ WARN("I2C write: address out of range\n");
+ return -1;
+ }
+
+ for (i = 0U; i < len; i++) {
+ if (i2c_write_byte(bus_id, devaddr, addr + i, buffer[i])) {
+ ERROR("I2C write: I/O error\n");
+ iproc_i2c_init(bus_id, i2c_get_bus_speed(bus_id));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Function Name: i2c_set_bus_speed
+ *
+ * Description:
+ * This function configures the SMBUS speed
+ *
+ * Parameters:
+ * bus_id - I2C bus ID
+ * speed - I2C bus speed in Hz
+ *
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+int i2c_set_bus_speed(uint32_t bus_id, uint32_t speed)
+{
+ switch (speed) {
+ case I2C_SPEED_100KHz:
+ iproc_i2c_set_clk_freq(bus_id, IPROC_SMB_SPEED_100KHz);
+ break;
+
+ case I2C_SPEED_400KHz:
+ iproc_i2c_set_clk_freq(bus_id, IPROC_SMB_SPEED_400KHz);
+ break;
+
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Function Name: i2c_get_bus_speed
+ *
+ * Description:
+ * This function returns the SMBUS speed.
+ *
+ * Parameters:
+ * bus_id - I2C bus ID
+ *
+ * Return:
+ * Bus speed in Hz, 0 on failure
+ */
+uint32_t i2c_get_bus_speed(uint32_t bus_id)
+{
+ uint32_t regval;
+ uint32_t retval = 0U;
+
+ regval = iproc_i2c_reg_read(bus_id, SMB_TIMGCFG_REG);
+ regval &= SMB_TIMGCFG_MODE400_MASK;
+ regval >>= SMB_TIMGCFG_MODE400_SHIFT;
+
+ switch (regval) {
+ case IPROC_SMB_SPEED_100KHz:
+ retval = I2C_SPEED_100KHz;
+ break;
+
+ case IPROC_SMB_SPEED_400KHz:
+ retval = I2C_SPEED_400KHz;
+ break;
+
+ default:
+ break;
+ }
+ return retval;
+}
+
diff --git a/drivers/brcm/iproc_gpio.c b/drivers/brcm/iproc_gpio.c
new file mode 100644
index 0000000..f61a3bc
--- /dev/null
+++ b/drivers/brcm/iproc_gpio.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <drivers/gpio.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <iproc_gpio.h>
+#include <platform_def.h>
+
+#define IPROC_GPIO_DATA_IN_OFFSET 0x00
+#define IPROC_GPIO_DATA_OUT_OFFSET 0x04
+#define IPROC_GPIO_OUT_EN_OFFSET 0x08
+#define IPROC_GPIO_PAD_RES_OFFSET 0x34
+#define IPROC_GPIO_RES_EN_OFFSET 0x38
+
+#define PINMUX_OFFSET(gpio) ((gpio) * 4)
+#define PINCONF_OFFSET(gpio) ((gpio) * 4)
+#define PINCONF_PULL_UP BIT(4)
+#define PINCONF_PULL_DOWN BIT(5)
+
+/*
+ * iProc GPIO bank is always 0x200 per bank,
+ * with each bank supporting 32 GPIOs.
+ */
+#define GPIO_BANK_SIZE 0x200
+#define NGPIOS_PER_BANK 32
+#define GPIO_BANK(pin) ((pin) / NGPIOS_PER_BANK)
+
+#define IPROC_GPIO_REG(pin, reg) (GPIO_BANK(pin) * GPIO_BANK_SIZE + (reg))
+#define IPROC_GPIO_SHIFT(pin) ((pin) % NGPIOS_PER_BANK)
+
+#define MUX_GPIO_MODE 0x3
+
+/*
+ * @base: base address of the gpio controller
+ * @pinconf_base: base address of the pinconf
+ * @pinmux_base: base address of the mux controller
+ * @nr_gpios: maxinum number of GPIOs
+ */
+struct iproc_gpio {
+ uintptr_t base;
+ uintptr_t pinconf_base;
+ uintptr_t pinmux_base;
+ int nr_gpios;
+};
+
+static struct iproc_gpio iproc_gpio;
+
+static void gpio_set_bit(uintptr_t base, unsigned int reg, int gpio, bool set)
+{
+ unsigned int offset = IPROC_GPIO_REG(gpio, reg);
+ unsigned int shift = IPROC_GPIO_SHIFT(gpio);
+ uint32_t val;
+
+ val = mmio_read_32(base + offset);
+ if (set)
+ val |= BIT(shift);
+ else
+ val &= ~BIT(shift);
+
+ mmio_write_32(base + offset, val);
+}
+
+static bool gpio_get_bit(uintptr_t base, unsigned int reg, int gpio)
+{
+ unsigned int offset = IPROC_GPIO_REG(gpio, reg);
+ unsigned int shift = IPROC_GPIO_SHIFT(gpio);
+
+ return !!(mmio_read_32(base + offset) & BIT(shift));
+}
+
+static void mux_to_gpio(struct iproc_gpio *g, int gpio)
+{
+ /* mux pad to GPIO if IOPAD configuration is mandatory */
+ if (g->pinmux_base)
+ mmio_write_32(g->pinmux_base + PINMUX_OFFSET(gpio),
+ MUX_GPIO_MODE);
+}
+
+static void set_direction(int gpio, int direction)
+{
+ struct iproc_gpio *g = &iproc_gpio;
+ bool dir = (direction == GPIO_DIR_OUT) ? true : false;
+
+ assert(gpio < g->nr_gpios);
+
+ mux_to_gpio(g, gpio);
+ gpio_set_bit(g->base, IPROC_GPIO_OUT_EN_OFFSET, gpio, dir);
+}
+
+static int get_direction(int gpio)
+{
+ struct iproc_gpio *g = &iproc_gpio;
+ int dir;
+
+ assert(gpio < g->nr_gpios);
+
+ mux_to_gpio(g, gpio);
+ dir = gpio_get_bit(g->base, IPROC_GPIO_OUT_EN_OFFSET, gpio) ?
+ GPIO_DIR_OUT : GPIO_DIR_IN;
+
+ return dir;
+}
+
+static int get_value(int gpio)
+{
+ struct iproc_gpio *g = &iproc_gpio;
+ unsigned int offset;
+
+ assert(gpio < g->nr_gpios);
+
+ mux_to_gpio(g, gpio);
+
+ /*
+ * If GPIO is configured as output, read from the GPIO_OUT register;
+ * otherwise, read from the GPIO_IN register
+ */
+ offset = gpio_get_bit(g->base, IPROC_GPIO_OUT_EN_OFFSET, gpio) ?
+ IPROC_GPIO_DATA_OUT_OFFSET : IPROC_GPIO_DATA_IN_OFFSET;
+
+ return gpio_get_bit(g->base, offset, gpio);
+}
+
+static void set_value(int gpio, int val)
+{
+ struct iproc_gpio *g = &iproc_gpio;
+
+ assert(gpio < g->nr_gpios);
+
+ mux_to_gpio(g, gpio);
+
+ /* make sure GPIO is configured to output, and then set the value */
+ gpio_set_bit(g->base, IPROC_GPIO_OUT_EN_OFFSET, gpio, true);
+ gpio_set_bit(g->base, IPROC_GPIO_DATA_OUT_OFFSET, gpio, !!(val));
+}
+
+static int get_pull(int gpio)
+{
+ struct iproc_gpio *g = &iproc_gpio;
+ uint32_t val;
+
+ assert(gpio < g->nr_gpios);
+ mux_to_gpio(g, gpio);
+
+ /* when there's a valid pinconf_base, use it */
+ if (g->pinconf_base) {
+ val = mmio_read_32(g->pinconf_base + PINCONF_OFFSET(gpio));
+
+ if (val & PINCONF_PULL_UP)
+ return GPIO_PULL_UP;
+ else if (val & PINCONF_PULL_DOWN)
+ return GPIO_PULL_DOWN;
+ else
+ return GPIO_PULL_NONE;
+ }
+
+ /* no pinconf_base. fall back to GPIO internal pull control */
+ if (!gpio_get_bit(g->base, IPROC_GPIO_RES_EN_OFFSET, gpio))
+ return GPIO_PULL_NONE;
+
+ return gpio_get_bit(g->base, IPROC_GPIO_PAD_RES_OFFSET, gpio) ?
+ GPIO_PULL_UP : GPIO_PULL_DOWN;
+}
+
+static void set_pull(int gpio, int pull)
+{
+ struct iproc_gpio *g = &iproc_gpio;
+ uint32_t val;
+
+ assert(gpio < g->nr_gpios);
+ mux_to_gpio(g, gpio);
+
+ /* when there's a valid pinconf_base, use it */
+ if (g->pinconf_base) {
+ val = mmio_read_32(g->pinconf_base + PINCONF_OFFSET(gpio));
+
+ if (pull == GPIO_PULL_NONE) {
+ val &= ~(PINCONF_PULL_UP | PINCONF_PULL_DOWN);
+ } else if (pull == GPIO_PULL_UP) {
+ val |= PINCONF_PULL_UP;
+ val &= ~PINCONF_PULL_DOWN;
+ } else if (pull == GPIO_PULL_DOWN) {
+ val |= PINCONF_PULL_DOWN;
+ val &= ~PINCONF_PULL_UP;
+ } else {
+ return;
+ }
+ mmio_write_32(g->pinconf_base + PINCONF_OFFSET(gpio), val);
+ }
+
+ /* no pinconf_base. fall back to GPIO internal pull control */
+ if (pull == GPIO_PULL_NONE) {
+ gpio_set_bit(g->base, IPROC_GPIO_RES_EN_OFFSET, gpio, false);
+ return;
+ }
+
+ /* enable pad register and pull up or down */
+ gpio_set_bit(g->base, IPROC_GPIO_RES_EN_OFFSET, gpio, true);
+ gpio_set_bit(g->base, IPROC_GPIO_PAD_RES_OFFSET, gpio,
+ !!(pull == GPIO_PULL_UP));
+}
+
+const gpio_ops_t iproc_gpio_ops = {
+ .get_direction = get_direction,
+ .set_direction = set_direction,
+ .get_value = get_value,
+ .set_value = set_value,
+ .get_pull = get_pull,
+ .set_pull = set_pull,
+};
+
+void iproc_gpio_init(uintptr_t base, int nr_gpios, uintptr_t pinmux_base,
+ uintptr_t pinconf_base)
+{
+ iproc_gpio.base = base;
+ iproc_gpio.nr_gpios = nr_gpios;
+
+ /* pinmux/pinconf base is optional for some SoCs */
+ if (pinmux_base)
+ iproc_gpio.pinmux_base = pinmux_base;
+
+ if (pinconf_base)
+ iproc_gpio.pinconf_base = pinconf_base;
+
+ gpio_init(&iproc_gpio_ops);
+}
diff --git a/drivers/brcm/mdio/mdio.c b/drivers/brcm/mdio/mdio.c
new file mode 100644
index 0000000..1cf9d66
--- /dev/null
+++ b/drivers/brcm/mdio/mdio.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016 - 2021, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <mdio.h>
+
+static int mdio_op_status(uint32_t result)
+{
+ uint32_t timeout = 1000000U; /* loop for 1s */
+ uint32_t val;
+
+ do {
+ val = mmio_read_32(CMIC_MIIM_STAT);
+ if ((val & MDIO_STAT_DONE) == result) {
+ return 0;
+ }
+
+ udelay(1U);
+ } while (timeout-- != 0U);
+ return -1;
+}
+
+static int mdio_op(uint16_t busid, uint16_t phyid, uint32_t reg,
+ uint16_t val, uint8_t op)
+{
+ uint32_t param;
+ int ret;
+
+ mmio_write_32(CMIC_MIIM_CTRL, 0U);
+ ret = mdio_op_status(0U);
+ if (ret != 0) {
+ goto err;
+ }
+
+ param = 0U;
+ param |= 1U << MDIO_PARAM_INTERNAL_SEL;
+ param |= (busid & MDIO_PARAM_BUSID_MASK) << MDIO_PARAM_BUSID;
+ param |= (phyid & MDIO_PARAM_PHYID_MASK) << MDIO_PARAM_PHYID;
+ param |= (val & MDIO_PARAM_DATA_MASK) << MDIO_PARAM_DATA;
+
+ mmio_write_32(CMIC_MIIM_PARAM, param);
+
+ mmio_write_32(CMIC_MIIM_ADDRESS, reg);
+
+ mmio_write_32(CMIC_MIIM_CTRL, op);
+
+ ret = mdio_op_status(1U);
+ if (ret != 0) {
+ goto err;
+ }
+
+ if (op == MDIO_CTRL_READ_OP) {
+ ret = mmio_read_32(CMIC_MIIM_READ_DATA) & MDIO_READ_DATA_MASK;
+ }
+err:
+ return ret;
+}
+
+int mdio_write(uint16_t busid, uint16_t phyid, uint32_t reg, uint16_t val)
+{
+ int ret;
+
+ ret = mdio_op(busid, phyid, reg, val, MDIO_CTRL_WRITE_OP);
+ if (ret == -1) {
+ INFO("MDIO write fail\n");
+ }
+ return ret;
+}
+
+int mdio_read(uint16_t busid, uint16_t phyid, uint32_t reg)
+{
+ int ret;
+
+ ret = mdio_op(busid, phyid, reg, 0U, MDIO_CTRL_READ_OP);
+ if (ret == -1) {
+ INFO("MDIO read fail\n");
+ }
+ return ret;
+}
diff --git a/drivers/brcm/ocotp.c b/drivers/brcm/ocotp.c
new file mode 100644
index 0000000..6ff8554
--- /dev/null
+++ b/drivers/brcm/ocotp.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <ocotp.h>
+#include <platform_def.h>
+
+#define OTP_MAP 2
+#define OTP_NUM_WORDS 2048
+/*
+ * # of tries for OTP Status. The time to execute a command varies. The slowest
+ * commands are writes which also vary based on the # of bits turned on. Writing
+ * 0xffffffff takes ~3800 us.
+ */
+#define OTPC_RETRIES_US 5000
+
+/* Sequence to enable OTP program */
+#define OTPC_PROG_EN_SEQ { 0xf, 0x4, 0x8, 0xd }
+
+/* OTPC Commands */
+#define OTPC_CMD_READ 0x0
+#define OTPC_CMD_OTP_PROG_ENABLE 0x2
+#define OTPC_CMD_OTP_PROG_DISABLE 0x3
+#define OTPC_CMD_PROGRAM 0x8
+#define OTPC_CMD_ECC 0x10
+#define OTPC_ECC_ADDR 0x1A
+#define OTPC_ECC_VAL 0x00EC0000
+
+/* OTPC Status Bits */
+#define OTPC_STAT_CMD_DONE BIT(1)
+#define OTPC_STAT_PROG_OK BIT(2)
+
+/* OTPC register definition */
+#define OTPC_MODE_REG_OFFSET 0x0
+#define OTPC_MODE_REG_OTPC_MODE 0
+#define OTPC_COMMAND_OFFSET 0x4
+#define OTPC_COMMAND_COMMAND_WIDTH 6
+#define OTPC_CMD_START_OFFSET 0x8
+#define OTPC_CMD_START_START 0
+#define OTPC_CPU_STATUS_OFFSET 0xc
+#define OTPC_CPUADDR_REG_OFFSET 0x28
+#define OTPC_CPUADDR_REG_OTPC_CPU_ADDRESS_WIDTH 16
+#define OTPC_CPU_WRITE_REG_OFFSET 0x2c
+
+#define OTPC_CMD_MASK (BIT(OTPC_COMMAND_COMMAND_WIDTH) - 1)
+#define OTPC_ADDR_MASK (BIT(OTPC_CPUADDR_REG_OTPC_CPU_ADDRESS_WIDTH) - 1)
+
+#define OTPC_MODE_REG OCOTP_REGS_BASE
+
+struct chip_otp_cfg {
+ uint32_t base;
+ uint32_t num_words;
+};
+
+struct chip_otp_cfg ocotp_cfg = {
+ .base = OTPC_MODE_REG,
+ .num_words = 2048,
+};
+
+struct otpc_priv {
+ uint32_t base;
+ struct otpc_map *map;
+ int size;
+ int state;
+};
+
+struct otpc_priv otpc_info;
+
+static inline void set_command(uint32_t base, uint32_t command)
+{
+ mmio_write_32(base + OTPC_COMMAND_OFFSET, command & OTPC_CMD_MASK);
+}
+
+static inline void set_cpu_address(uint32_t base, uint32_t addr)
+{
+ mmio_write_32(base + OTPC_CPUADDR_REG_OFFSET, addr & OTPC_ADDR_MASK);
+}
+
+static inline void set_start_bit(uint32_t base)
+{
+ mmio_write_32(base + OTPC_CMD_START_OFFSET, 1 << OTPC_CMD_START_START);
+}
+
+static inline void reset_start_bit(uint32_t base)
+{
+ mmio_write_32(base + OTPC_CMD_START_OFFSET, 0);
+}
+
+static inline void write_cpu_data(uint32_t base, uint32_t value)
+{
+ mmio_write_32(base + OTPC_CPU_WRITE_REG_OFFSET, value);
+}
+
+static int poll_cpu_status(uint32_t base, uint32_t value)
+{
+ uint32_t status;
+ uint32_t retries;
+
+ for (retries = 0; retries < OTPC_RETRIES_US; retries++) {
+ status = mmio_read_32(base + OTPC_CPU_STATUS_OFFSET);
+ if (status & value)
+ break;
+ udelay(1);
+ }
+ if (retries == OTPC_RETRIES_US)
+ return -1;
+
+ return 0;
+}
+
+static int bcm_otpc_ecc(uint32_t enable)
+{
+ struct otpc_priv *priv = &otpc_info;
+ int ret;
+
+ set_command(priv->base, OTPC_CMD_ECC);
+ set_cpu_address(priv->base, OTPC_ECC_ADDR);
+
+ if (!enable)
+ write_cpu_data(priv->base, OTPC_ECC_VAL);
+ else
+ write_cpu_data(priv->base, ~OTPC_ECC_VAL);
+
+ set_start_bit(priv->base);
+ ret = poll_cpu_status(priv->base, OTPC_STAT_CMD_DONE);
+ if (ret) {
+ ERROR("otp ecc op error: 0x%x", ret);
+ return -1;
+ }
+ reset_start_bit(priv->base);
+
+ return 0;
+}
+
+/*
+ * bcm_otpc_read read otp data in the size of 8 byte rows.
+ * bytes has to be the multiple of 8.
+ * return -1 in error case, return read bytes in success.
+ */
+int bcm_otpc_read(unsigned int offset, void *val, uint32_t bytes,
+ uint32_t ecc_flag)
+{
+ struct otpc_priv *priv = &otpc_info;
+ uint32_t *buf = val;
+ uint32_t bytes_read;
+ uint32_t address = offset / priv->map->word_size;
+ int i, ret;
+
+ if (!priv->state) {
+ ERROR("OCOTP read failed\n");
+ return -1;
+ }
+
+ bcm_otpc_ecc(ecc_flag);
+
+ for (bytes_read = 0; (bytes_read + priv->map->word_size) <= bytes;) {
+ set_command(priv->base, OTPC_CMD_READ);
+ set_cpu_address(priv->base, address++);
+ set_start_bit(priv->base);
+ ret = poll_cpu_status(priv->base, OTPC_STAT_CMD_DONE);
+ if (ret) {
+ ERROR("otp read error: 0x%x", ret);
+ return -1;
+ }
+
+ for (i = 0; i < priv->map->otpc_row_size; i++) {
+ *buf++ = mmio_read_32(priv->base +
+ priv->map->data_r_offset[i]);
+ bytes_read += sizeof(*buf);
+ }
+
+ reset_start_bit(priv->base);
+ }
+
+ return bytes_read;
+}
+
+int bcm_otpc_init(struct otpc_map *map)
+{
+ struct otpc_priv *priv;
+
+ priv = &otpc_info;
+ priv->base = ocotp_cfg.base;
+ priv->map = map;
+
+ priv->size = 4 * ocotp_cfg.num_words;
+
+ /* Enable CPU access to OTPC. */
+ mmio_setbits_32(priv->base + OTPC_MODE_REG_OFFSET,
+ BIT(OTPC_MODE_REG_OTPC_MODE));
+ reset_start_bit(priv->base);
+ priv->state = 1;
+ VERBOSE("OTPC Initialization done\n");
+
+ return 0;
+}
diff --git a/drivers/brcm/rng.c b/drivers/brcm/rng.c
new file mode 100644
index 0000000..ee2e656
--- /dev/null
+++ b/drivers/brcm/rng.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#define RNG_CTRL_REG (RNG_BASE_ADDR + 0x00)
+#define RNG_CTRL_MASK 0x00001FFF
+#define RNG_CTRL_ENABLE 0x00000001
+#define RNG_CTRL_DISABLE 0x00000000
+
+#define RNG_SOFT_RESET_REG (RNG_BASE_ADDR + 0x04)
+#define RNG_SOFT_RESET_MASK 0x00000001
+
+#define RNG_FIFO_DATA_REG (RNG_BASE_ADDR + 0x20)
+
+#define RNG_FIFO_COUNT_REG (RNG_BASE_ADDR + 0x24)
+#define RNG_FIFO_COUNT_MASK 0x000000FF
+
+#define RNG_FIFO_WORDS_MAX 16
+#define MAX_WAIT_COUNT_50US 20000
+
+
+static void rng_reset(void)
+{
+ /* Disable RBG */
+ mmio_clrbits_32(RNG_CTRL_REG, RNG_CTRL_MASK);
+
+ /* Reset RNG and RBG */
+ mmio_setbits_32(RNG_SOFT_RESET_REG, RNG_SOFT_RESET_MASK);
+
+ /* Take all out of reset */
+ mmio_clrbits_32(RNG_SOFT_RESET_REG, RNG_SOFT_RESET_MASK);
+}
+
+static void rng_enable(void)
+{
+ /* Setup RNG. */
+ mmio_clrsetbits_32(RNG_CTRL_REG, RNG_CTRL_MASK, RNG_CTRL_ENABLE);
+}
+
+int rng_init(void)
+{
+ rng_reset();
+
+ rng_enable();
+
+ return 0;
+}
+
+int rng_read(uint32_t *p_out, uint32_t *words_read)
+{
+ uint32_t available_words;
+ uint32_t i;
+ uint32_t word_processed = 0;
+ uint32_t wait_count = MAX_WAIT_COUNT_50US;
+
+ if (*words_read == 0) {
+ ERROR("RNG Parameter: No word requested\n");
+ return -1;
+ }
+
+ do {
+ available_words = mmio_read_32(RNG_FIFO_COUNT_REG);
+ available_words &= RNG_FIFO_COUNT_MASK;
+
+ if (available_words != 0) {
+ available_words = MIN(available_words,
+ *words_read - word_processed);
+
+ for (i = 0; i < available_words; i++)
+ p_out[word_processed + i] =
+ mmio_read_32(RNG_FIFO_DATA_REG);
+ word_processed += available_words;
+ } else {
+ udelay(50);
+ }
+
+ if (word_processed == *words_read)
+ break;
+
+ } while (--wait_count);
+
+ if (word_processed != *words_read) {
+ ERROR("RNG Timeout: requested %d word(s) got %d\n",
+ *words_read, word_processed);
+ *words_read = word_processed;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/drivers/brcm/scp.c b/drivers/brcm/scp.c
new file mode 100644
index 0000000..6196073
--- /dev/null
+++ b/drivers/brcm/scp.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+/* MCU binary image structure: <header> <data>
+ *
+ * Header structure:
+ * <magic-start>
+ * <num-sections>
+ * {<src-offset> <src-size> <dst-addr>}*
+ * <magic-end>
+ *
+ * MCU data (<data>) consists of several sections of code/data, to be
+ * installed (copied) into MCU memories.
+ * Header (<header>) gives information about sections contained in <data>.
+ *
+ * The installer code iterates over sections in MCU binary.
+ * For each section, it copies the section into MCU memory.
+ *
+ * The header contains:
+ * - <magic-start> - 32-bit magic number to mark header start
+ * - <num-sections> - number of sections in <data>
+ * - <num-sections> tuples. Each tuple describes a section.
+ * A tuple contains three 32-bit words.
+ * - <magic-end> - 32-bit magic number to mark header end
+ *
+ * Each section is describes by a tuple, consisting of three 32-bit words:
+ * - offset of section within MCU binary (relative to beginning of <data>)
+ * - section size (in bytes) in MCU binary
+ * - target address (in MCU memory). Section is copied to this location.
+ *
+ * All fields are 32-bit unsigned integers in little endian format.
+ * All sizes are assumed to be 32-bit aligned.
+ */
+
+#define SCP_BIN_HEADER_MAGIC_START 0xfa587D01
+#define SCP_BIN_HEADER_MAGIC_END 0xf3e06a85
+
+int download_scp_patch(void *image, unsigned int image_size)
+{
+ unsigned int *pheader = (unsigned int *)(image);
+ unsigned int header_size;
+ unsigned char *pdata;
+ void *dest;
+ unsigned int num_sections;
+ unsigned int section_src_offset;
+ unsigned int section_size;
+
+ if (pheader && (pheader[0] != SCP_BIN_HEADER_MAGIC_START)) {
+ ERROR("SCP: Could not find SCP header.\n");
+ return -1;
+ }
+
+ num_sections = pheader[1];
+ INFO("...Number of sections: %d\n", num_sections);
+ header_size = 4 * (1 + 1 + 3 * num_sections + 1);
+
+ if (image_size < header_size) {
+ ERROR("SCP: Wrong size.\n");
+ return -1;
+ }
+
+ if (*(pheader + header_size/4 - 1) != SCP_BIN_HEADER_MAGIC_END) {
+ ERROR("SCP: Could not find SCP footer.\n");
+ return -1;
+ }
+
+ VERBOSE("SCP image header validated successfully\n");
+ pdata = (unsigned char *)pheader + header_size;
+
+ for (pheader += 2; num_sections > 0; num_sections--) {
+
+ section_src_offset = pheader[0];
+ section_size = pheader[1];
+ dest = (void *)(unsigned long)pheader[2];
+
+ INFO("section: src:0x%x, size:%d, dst:0x%x\n",
+ section_src_offset, section_size, pheader[2]);
+
+ if ((section_src_offset + section_size) > image_size) {
+ ERROR("SCP: Section points to outside of patch.\n");
+ return -1;
+ }
+
+ /* copy from source to target section */
+ memcpy(dest, pdata + section_src_offset, section_size);
+ flush_dcache_range((uintptr_t)dest, section_size);
+
+ /* next section */
+ pheader += 3;
+ }
+ return 0;
+}
diff --git a/drivers/brcm/sotp.c b/drivers/brcm/sotp.c
new file mode 100644
index 0000000..63c4820
--- /dev/null
+++ b/drivers/brcm/sotp.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2016-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <sotp.h>
+
+#include <platform_def.h>
+#include <platform_sotp.h>
+
+#ifdef USE_SOFT_SOTP
+extern uint64_t soft_sotp[];
+#endif
+
+#define SOTP_PROG_CONTROL (SOTP_REGS_OTP_BASE + 0x0000)
+#define SOTP_PROG_CONTROL__OTP_CPU_MODE_EN 15
+#define SOTP_PROG_CONTROL__OTP_DISABLE_ECC 9
+#define SOTP_PROG_CONTROL__OTP_ECC_WREN 8
+
+#define SOTP_WRDATA_0 (SOTP_REGS_OTP_BASE + 0x0004)
+#define SOTP_WRDATA_1 (SOTP_REGS_OTP_BASE + 0x0008)
+
+#define SOTP_ADDR (SOTP_REGS_OTP_BASE + 0x000c)
+#define SOTP_ADDR__OTP_ROW_ADDR_R 6
+#define SOTP_ADDR_MASK 0x3FF
+
+#define SOTP_CTRL_0 (SOTP_REGS_OTP_BASE + 0x0010)
+#define SOTP_CTRL_0__START 0
+#define SOTP_CTRL_0__OTP_CMD 1
+
+#define SOTP_STATUS_0 (SOTP_REGS_OTP_BASE + 0x0018)
+#define SOTP_STATUS__FDONE 3
+
+#define SOTP_STATUS_1 (SOTP_REGS_OTP_BASE + 0x001c)
+#define SOTP_STATUS_1__CMD_DONE 1
+#define SOTP_STATUS_1__ECC_DET 17
+
+#define SOTP_RDDATA_0 (SOTP_REGS_OTP_BASE + 0x0020)
+#define SOTP_RDDATA_1 (SOTP_REGS_OTP_BASE + 0x0024)
+
+#define SOTP_READ 0
+
+#define SOTP_PROG_WORD 10
+#define SOTP_STATUS__PROGOK 2
+#define SOTP_PROG_ENABLE 2
+
+#define SOTP_ROW_DATA_MASK 0xffffffff
+#define SOTP_ECC_ERR_BITS_MASK 0x1ff00000000
+
+#define SOTP_CHIP_CTRL_SW_OVERRIDE_CHIP_STATES 4
+#define SOTP_CHIP_CTRL_SW_MANU_PROG 5
+#define SOTP_CHIP_CTRL_SW_CID_PROG 6
+#define SOTP_CHIP_CTRL_SW_AB_DEVICE 8
+#define SOTP_CHIP_CTRL_SW_AB_DEV_MODE 9
+#define CHIP_STATE_UNPROGRAMMED 0x1
+#define CHIP_STATE_UNASSIGNED 0x2
+
+uint64_t sotp_mem_read(uint32_t offset, uint32_t sotp_add_ecc)
+{
+#ifdef USE_SOFT_SOTP
+ (void)sotp_add_ecc;
+
+ return soft_sotp[offset];
+#else
+ uint64_t read_data = 0;
+ uint64_t read_data1 = 0;
+ uint64_t read_data2 = 0;
+
+ /* Check for FDONE status */
+ while ((mmio_read_32(SOTP_STATUS_0) & BIT(SOTP_STATUS__FDONE)) !=
+ BIT(SOTP_STATUS__FDONE))
+ ;
+
+ /* Enable OTP access by CPU */
+ mmio_setbits_32(SOTP_PROG_CONTROL,
+ BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN));
+
+ if (sotp_add_ecc == 1) {
+ mmio_clrbits_32(SOTP_PROG_CONTROL,
+ BIT(SOTP_PROG_CONTROL__OTP_DISABLE_ECC));
+ }
+
+ if (sotp_add_ecc == 0) {
+ mmio_setbits_32(SOTP_PROG_CONTROL,
+ BIT(SOTP_PROG_CONTROL__OTP_DISABLE_ECC));
+ }
+
+ mmio_write_32(SOTP_ADDR,
+ ((offset & SOTP_ADDR_MASK) << SOTP_ADDR__OTP_ROW_ADDR_R));
+ mmio_write_32(SOTP_CTRL_0, (SOTP_READ << SOTP_CTRL_0__OTP_CMD));
+
+ /* Start bit to tell SOTP to send command to the OTP controller */
+ mmio_setbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
+
+ /* Wait for SOTP command done to be set */
+ while ((mmio_read_32(SOTP_STATUS_1) & BIT(SOTP_STATUS_1__CMD_DONE)) !=
+ BIT(SOTP_STATUS_1__CMD_DONE))
+ ;
+
+ /* Clr Start bit after command done */
+ mmio_clrbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
+
+ if ((offset > SOTP_DEVICE_SECURE_CFG3_ROW) &&
+ (mmio_read_32(SOTP_STATUS_1) & BIT(SOTP_STATUS_1__ECC_DET))) {
+ ERROR("SOTP ECC ERROR Detected row offset %d\n", offset);
+ read_data = SOTP_ECC_ERR_DETECT;
+ } else {
+ read_data1 = (uint64_t)mmio_read_32(SOTP_RDDATA_0);
+ read_data1 = read_data1 & 0xFFFFFFFF;
+ read_data2 = (uint64_t)mmio_read_32(SOTP_RDDATA_1);
+ read_data2 = (read_data2 & 0x1ff) << 32;
+ read_data = read_data1 | read_data2;
+ }
+
+ /* Command done is cleared */
+ mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE));
+
+ /* disable OTP access by CPU */
+ mmio_clrbits_32(SOTP_PROG_CONTROL,
+ BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN));
+
+ return read_data;
+#endif
+}
+
+void sotp_mem_write(uint32_t addr, uint32_t sotp_add_ecc, uint64_t wdata)
+{
+#ifdef USE_SOFT_SOTP
+ (void)sotp_add_ecc;
+
+ soft_sotp[addr] = wdata;
+#else
+ uint32_t loop;
+ uint8_t prog_array[4] = { 0x0F, 0x04, 0x08, 0x0D };
+
+ uint32_t chip_state_default =
+ (CHIP_STATE_UNASSIGNED|CHIP_STATE_UNPROGRAMMED);
+ uint32_t chip_state = mmio_read_32(SOTP_REGS_SOTP_CHIP_STATES);
+ uint32_t chip_ctrl_default = 0;
+
+ /*
+ * The override settings is required to allow the customer to program
+ * the application specific keys into SOTP, before the conversion to
+ * one of the AB modes.
+ * At the end of write operation, the chip ctrl settings will restored
+ * to the state prior to write call
+ */
+ if (chip_state & chip_state_default) {
+ uint32_t chip_ctrl;
+
+ chip_ctrl_default = mmio_read_32(SOTP_CHIP_CTRL);
+ INFO("SOTP: enable special prog mode\n");
+
+ chip_ctrl = BIT(SOTP_CHIP_CTRL_SW_OVERRIDE_CHIP_STATES) |
+ BIT(SOTP_CHIP_CTRL_SW_MANU_PROG) |
+ BIT(SOTP_CHIP_CTRL_SW_CID_PROG) |
+ BIT(SOTP_CHIP_CTRL_SW_AB_DEVICE);
+ mmio_write_32(SOTP_CHIP_CTRL, chip_ctrl);
+ }
+
+ /* Check for FDONE status */
+ while ((mmio_read_32(SOTP_STATUS_0) & BIT(SOTP_STATUS__FDONE)) !=
+ BIT(SOTP_STATUS__FDONE))
+ ;
+
+ /* Enable OTP acces by CPU */
+ mmio_setbits_32(SOTP_PROG_CONTROL,
+ BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN));
+
+ if (addr > SOTP_DEVICE_SECURE_CFG3_ROW) {
+ if (sotp_add_ecc == 0) {
+ mmio_clrbits_32(SOTP_PROG_CONTROL,
+ BIT(SOTP_PROG_CONTROL__OTP_ECC_WREN));
+ }
+ if (sotp_add_ecc == 1) {
+ mmio_setbits_32(SOTP_PROG_CONTROL,
+ BIT(SOTP_PROG_CONTROL__OTP_ECC_WREN));
+ }
+ } else {
+ mmio_clrbits_32(SOTP_PROG_CONTROL,
+ BIT(SOTP_PROG_CONTROL__OTP_ECC_WREN));
+ }
+
+ mmio_write_32(SOTP_CTRL_0, (SOTP_PROG_ENABLE << 1));
+
+ /*
+ * In order to avoid unintentional writes / programming of the OTP
+ * array, the OTP Controller must be put into programming mode before
+ * it will accept program commands. This is done by writing 0xF, 0x4,
+ * 0x8, 0xD with program commands prior to starting the actual
+ * programming sequence
+ */
+ for (loop = 0; loop < 4; loop++) {
+ mmio_write_32(SOTP_WRDATA_0, prog_array[loop]);
+
+ /*
+ * Start bit to tell SOTP to send command to the OTP controller
+ */
+ mmio_setbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
+
+ /* Wait for SOTP command done to <-- be set */
+ while ((mmio_read_32(SOTP_STATUS_1) &
+ BIT(SOTP_STATUS_1__CMD_DONE)) !=
+ BIT(SOTP_STATUS_1__CMD_DONE))
+ ;
+
+ /* Command done is cleared w1c */
+ mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE));
+
+ /* Clr Start bit after command done */
+ mmio_clrbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
+ }
+
+ /* Check for PROGOK */
+ while ((mmio_read_32(SOTP_STATUS_0) & 0x4) != BIT(SOTP_STATUS__PROGOK))
+ ;
+
+ /* Set 10 bit row address */
+ mmio_write_32(SOTP_ADDR,
+ ((addr & SOTP_ADDR_MASK) << SOTP_ADDR__OTP_ROW_ADDR_R));
+
+ /* Set SOTP Row data */
+ mmio_write_32(SOTP_WRDATA_0, (wdata & SOTP_ROW_DATA_MASK));
+
+ /* Set SOTP ECC and error bits */
+ mmio_write_32(SOTP_WRDATA_1, ((wdata & SOTP_ECC_ERR_BITS_MASK) >> 32));
+
+ /* Set prog_word command */
+ mmio_write_32(SOTP_CTRL_0, (SOTP_PROG_WORD << 1));
+
+ /* Start bit to tell SOTP to send command to the OTP controller */
+ mmio_setbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
+
+ /* Wait for SOTP command done to be set */
+ while ((mmio_read_32(SOTP_STATUS_1) & BIT(SOTP_STATUS_1__CMD_DONE)) !=
+ BIT(SOTP_STATUS_1__CMD_DONE))
+ ;
+
+ /* Command done is cleared w1c */
+ mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE));
+
+ /* disable OTP acces by CPU */
+ mmio_clrbits_32(SOTP_PROG_CONTROL,
+ BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN));
+
+ /* Clr Start bit after command done */
+ mmio_clrbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
+
+ if (chip_state & chip_state_default)
+ mmio_write_32(SOTP_CHIP_CTRL, chip_ctrl_default);
+
+#endif
+}
+
+int sotp_read_key(uint8_t *key, size_t keysize, int start_row, int end_row)
+{
+ int row;
+ uint32_t status = 0;
+ uint32_t status2 = 0xFFFFFFFF;
+ uint64_t row_data;
+ uint32_t data;
+ uint32_t *temp_key = (uint32_t *)key;
+
+ row = start_row;
+ while ((keysize > 0) && (row <= end_row)) {
+ row_data = sotp_mem_read(row, SOTP_ROW_ECC);
+ if (!(row_data & (SOTP_ECC_ERR_DETECT | SOTP_FAIL_BITS))) {
+ memcpy(temp_key++, &row_data, sizeof(uint32_t));
+ keysize -= sizeof(uint32_t);
+ data = (uint32_t)(row_data & SOTP_ROW_DATA_MASK);
+ status |= data;
+ status2 &= data;
+ }
+ row++;
+ }
+
+ if ((status2 == 0xFFFFFFFF) || (status == 0) || (row > end_row))
+ return -1;
+
+ return 0;
+}
+
+int sotp_key_erased(void)
+{
+ uint64_t row_data;
+ int status = 0;
+
+ row_data = sotp_mem_read(SOTP_DEVICE_SECURE_CFG0_ROW, 0);
+ if (row_data & SOTP_DEVICE_SECURE_CFG0_OTP_ERASED_MASK)
+ status = 1;
+
+ else if (mmio_read_32(SOTP_REGS_SOTP_CHIP_STATES) &
+ SOTP_REGS_SOTP_CHIP_STATES_OTP_ERASED_MASK)
+ status = 1;
+
+ return status;
+}
+
+/*
+ * This function optimise the SOTP redundancy
+ * by considering the 00- zero and 01,10,11 - one
+ */
+uint32_t sotp_redundancy_reduction(uint32_t sotp_row_data)
+{
+ uint32_t opt_data;
+ uint32_t opt_loop;
+ uint32_t temp_data;
+
+ opt_data = 0;
+
+ for (opt_loop = 0; opt_loop < 16; opt_loop = opt_loop + 1) {
+ temp_data = ((sotp_row_data >> (opt_loop * 2)) & 0x3);
+
+ if (temp_data != 0x0)
+ opt_data = (opt_data | (1 << opt_loop));
+ }
+ return opt_data;
+}
diff --git a/drivers/brcm/spi/iproc_qspi.c b/drivers/brcm/spi/iproc_qspi.c
new file mode 100644
index 0000000..4c533d5
--- /dev/null
+++ b/drivers/brcm/spi/iproc_qspi.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <endian.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+#include <spi.h>
+
+#include "iproc_qspi.h"
+
+struct bcmspi_priv spi_cfg;
+
+/* Redefined by platform to force appropriate information */
+#pragma weak plat_spi_init
+int plat_spi_init(uint32_t *max_hz)
+{
+ return 0;
+}
+
+/* Initialize & setup iproc qspi controller */
+int iproc_qspi_setup(uint32_t bus, uint32_t cs, uint32_t max_hz, uint32_t mode)
+{
+ struct bcmspi_priv *priv = NULL;
+ uint32_t spbr;
+
+ priv = &spi_cfg;
+ priv->spi_mode = mode;
+ priv->state = QSPI_STATE_DISABLED;
+ priv->bspi_hw = QSPI_BSPI_MODE_REG_BASE;
+ priv->mspi_hw = QSPI_MSPI_MODE_REG_BASE;
+
+ /* Initialize clock and platform specific */
+ if (plat_spi_init(&max_hz) != 0)
+ return -1;
+
+ priv->max_hz = max_hz;
+
+ /* MSPI: Basic hardware initialization */
+ mmio_write_32(priv->mspi_hw + MSPI_SPCR1_LSB_REG, 0);
+ mmio_write_32(priv->mspi_hw + MSPI_SPCR1_MSB_REG, 0);
+ mmio_write_32(priv->mspi_hw + MSPI_NEWQP_REG, 0);
+ mmio_write_32(priv->mspi_hw + MSPI_ENDQP_REG, 0);
+ mmio_write_32(priv->mspi_hw + MSPI_SPCR2_REG, 0);
+
+ /* MSPI: SCK configuration */
+ spbr = (QSPI_AXI_CLK - 1) / (2 * priv->max_hz) + 1;
+ spbr = MIN(spbr, SPBR_DIV_MAX);
+ spbr = MAX(spbr, SPBR_DIV_MIN);
+ mmio_write_32(priv->mspi_hw + MSPI_SPCR0_LSB_REG, spbr);
+
+ /* MSPI: Mode configuration (8 bits by default) */
+ priv->mspi_16bit = 0;
+ mmio_write_32(priv->mspi_hw + MSPI_SPCR0_MSB_REG,
+ BIT(MSPI_SPCR0_MSB_REG_MSTR_SHIFT) | /* Master */
+ MSPI_SPCR0_MSB_REG_16_BITS_PER_WD_SHIFT | /* 16 bits per word */
+ (priv->spi_mode & MSPI_SPCR0_MSB_REG_MODE_MASK)); /* mode: CPOL / CPHA */
+
+ /* Display bus info */
+ VERBOSE("SPI: SPCR0_LSB: 0x%x\n",
+ mmio_read_32(priv->mspi_hw + MSPI_SPCR0_LSB_REG));
+ VERBOSE("SPI: SPCR0_MSB: 0x%x\n",
+ mmio_read_32(priv->mspi_hw + MSPI_SPCR0_MSB_REG));
+ VERBOSE("SPI: SPCR1_LSB: 0x%x\n",
+ mmio_read_32(priv->mspi_hw + MSPI_SPCR1_LSB_REG));
+ VERBOSE("SPI: SPCR1_MSB: 0x%x\n",
+ mmio_read_32(priv->mspi_hw + MSPI_SPCR1_MSB_REG));
+ VERBOSE("SPI: SPCR2: 0x%x\n",
+ mmio_read_32(priv->mspi_hw + MSPI_SPCR2_REG));
+ VERBOSE("SPI: CLK: %d\n", priv->max_hz);
+
+ return 0;
+}
+
+void bcmspi_enable_bspi(struct bcmspi_priv *priv)
+{
+ if (priv->state != QSPI_STATE_BSPI) {
+ /* Switch to BSPI */
+ mmio_write_32(priv->bspi_hw + BSPI_MAST_N_BOOT_CTRL_REG, 0);
+
+ priv->state = QSPI_STATE_BSPI;
+ }
+}
+
+static int bcmspi_disable_bspi(struct bcmspi_priv *priv)
+{
+ uint32_t retry;
+
+ if (priv->state == QSPI_STATE_MSPI)
+ return 0;
+
+ /* Switch to MSPI if not yet */
+ if ((mmio_read_32(priv->bspi_hw + BSPI_MAST_N_BOOT_CTRL_REG) &
+ MSPI_CTRL_MASK) == 0) {
+ retry = QSPI_RETRY_COUNT_US_MAX;
+ do {
+ if ((mmio_read_32(
+ priv->bspi_hw + BSPI_BUSY_STATUS_REG) &
+ BSPI_BUSY_MASK) == 0) {
+ mmio_write_32(priv->bspi_hw +
+ BSPI_MAST_N_BOOT_CTRL_REG,
+ MSPI_CTRL_MASK);
+ udelay(1);
+ break;
+ }
+ udelay(1);
+ } while (retry--);
+
+ if ((mmio_read_32(priv->bspi_hw + BSPI_MAST_N_BOOT_CTRL_REG) &
+ MSPI_CTRL_MASK) != MSPI_CTRL_MASK) {
+ ERROR("QSPI: Switching to QSPI error.\n");
+ return -1;
+ }
+ }
+
+ /* Update state */
+ priv->state = QSPI_STATE_MSPI;
+
+ return 0;
+}
+
+int iproc_qspi_claim_bus(void)
+{
+ struct bcmspi_priv *priv = &spi_cfg;
+
+ /* Switch to MSPI by default */
+ if (bcmspi_disable_bspi(priv) != 0)
+ return -1;
+
+ return 0;
+}
+
+void iproc_qspi_release_bus(void)
+{
+ struct bcmspi_priv *priv = &spi_cfg;
+
+ /* Switch to BSPI by default */
+ bcmspi_enable_bspi(priv);
+}
+
+static int mspi_xfer(struct bcmspi_priv *priv, uint32_t bytes,
+ const uint8_t *tx, uint8_t *rx, uint32_t flag)
+{
+ uint32_t retry;
+ uint32_t mode = CDRAM_PCS0;
+
+ if (flag & SPI_XFER_QUAD) {
+ mode |= CDRAM_QUAD_MODE;
+ VERBOSE("SPI: QUAD mode\n");
+
+ if (!tx) {
+ VERBOSE("SPI: 4 lane input\n");
+ mode |= CDRAM_RBIT_INPUT;
+ }
+ }
+
+ /* Use 8-bit queue for odd-bytes transfer */
+ if (bytes & 1)
+ priv->mspi_16bit = 0;
+ else {
+ priv->mspi_16bit = 1;
+ mode |= CDRAM_BITS_EN;
+ }
+
+ while (bytes) {
+ uint32_t chunk;
+ uint32_t queues;
+ uint32_t i;
+
+ /* Separate code for 16bit and 8bit transfers for performance */
+ if (priv->mspi_16bit) {
+ VERBOSE("SPI: 16 bits xfer\n");
+ /* Determine how many bytes to process this time */
+ chunk = MIN(bytes, NUM_CDRAM_BYTES * 2);
+ queues = (chunk - 1) / 2 + 1;
+ bytes -= chunk;
+
+ /* Fill CDRAMs */
+ for (i = 0; i < queues; i++)
+ mmio_write_32(priv->mspi_hw + MSPI_CDRAM_REG +
+ (i << 2), mode | CDRAM_CONT);
+
+ /* Fill TXRAMs */
+ for (i = 0; i < chunk; i++)
+ if (tx)
+ mmio_write_32(priv->mspi_hw +
+ MSPI_TXRAM_REG +
+ (i << 2), tx[i]);
+ } else {
+ VERBOSE("SPI: 8 bits xfer\n");
+ /* Determine how many bytes to process this time */
+ chunk = MIN(bytes, NUM_CDRAM_BYTES);
+ queues = chunk;
+ bytes -= chunk;
+
+ /* Fill CDRAMs and TXRAMS */
+ for (i = 0; i < chunk; i++) {
+ mmio_write_32(priv->mspi_hw + MSPI_CDRAM_REG +
+ (i << 2), mode | CDRAM_CONT);
+ if (tx)
+ mmio_write_32(priv->mspi_hw +
+ MSPI_TXRAM_REG +
+ (i << 3), tx[i]);
+ }
+ }
+
+ /* Advance pointers */
+ if (tx)
+ tx += chunk;
+
+ /* Setup queue pointers */
+ mmio_write_32(priv->mspi_hw + MSPI_NEWQP_REG, 0);
+ mmio_write_32(priv->mspi_hw + MSPI_ENDQP_REG, queues - 1);
+
+ /* Remove CONT on the last byte command */
+ if (bytes == 0 && (flag & SPI_XFER_END))
+ mmio_write_32(priv->mspi_hw + MSPI_CDRAM_REG +
+ ((queues - 1) << 2), mode);
+
+ /* Kick off */
+ mmio_write_32(priv->mspi_hw + MSPI_STATUS_REG, 0);
+ if (bytes == 0 && (flag & SPI_XFER_END))
+ mmio_write_32(priv->mspi_hw + MSPI_SPCR2_REG, MSPI_SPE);
+ else
+ mmio_write_32(priv->mspi_hw + MSPI_SPCR2_REG,
+ MSPI_SPE | MSPI_CONT_AFTER_CMD);
+
+ /* Wait for completion */
+ retry = QSPI_RETRY_COUNT_US_MAX;
+ do {
+ if (mmio_read_32(priv->mspi_hw + MSPI_STATUS_REG) &
+ MSPI_CMD_COMPLETE_MASK)
+ break;
+ udelay(1);
+ } while (retry--);
+
+ if ((mmio_read_32(priv->mspi_hw + MSPI_STATUS_REG) &
+ MSPI_CMD_COMPLETE_MASK) == 0) {
+ ERROR("SPI: Completion timeout.\n");
+ return -1;
+ }
+
+ /* Read data out */
+ if (rx) {
+ if (priv->mspi_16bit) {
+ for (i = 0; i < chunk; i++) {
+ rx[i] = mmio_read_32(priv->mspi_hw +
+ MSPI_RXRAM_REG +
+ (i << 2))
+ & 0xff;
+ }
+ } else {
+ for (i = 0; i < chunk; i++) {
+ rx[i] = mmio_read_32(priv->mspi_hw +
+ MSPI_RXRAM_REG +
+ (((i << 1) + 1) << 2))
+ & 0xff;
+ }
+ }
+ rx += chunk;
+ }
+ }
+
+ return 0;
+}
+
+int iproc_qspi_xfer(uint32_t bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct bcmspi_priv *priv;
+ const uint8_t *tx = dout;
+ uint8_t *rx = din;
+ uint32_t bytes = bitlen / 8;
+ int ret = 0;
+
+ priv = &spi_cfg;
+
+ if (priv->state == QSPI_STATE_DISABLED) {
+ ERROR("QSPI: state disabled\n");
+ return -1;
+ }
+
+ /* we can only do 8 bit transfers */
+ if (bitlen % 8) {
+ ERROR("QSPI: Only support 8 bit transfers (requested %d)\n",
+ bitlen);
+ return -1;
+ }
+
+ /* MSPI: Enable write lock at the beginning */
+ if (flags & SPI_XFER_BEGIN) {
+ /* Switch to MSPI if not yet */
+ if (bcmspi_disable_bspi(priv) != 0) {
+ ERROR("QSPI: Switch to MSPI failed\n");
+ return -1;
+ }
+
+ mmio_write_32(priv->mspi_hw + MSPI_WRITE_LOCK_REG, 1);
+ }
+
+ /* MSPI: Transfer it */
+ if (bytes)
+ ret = mspi_xfer(priv, bytes, tx, rx, flags);
+
+ /* MSPI: Disable write lock if it's done */
+ if (flags & SPI_XFER_END)
+ mmio_write_32(priv->mspi_hw + MSPI_WRITE_LOCK_REG, 0);
+
+ return ret;
+}
diff --git a/drivers/brcm/spi/iproc_qspi.h b/drivers/brcm/spi/iproc_qspi.h
new file mode 100644
index 0000000..7a8bd91
--- /dev/null
+++ b/drivers/brcm/spi/iproc_qspi.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IPROC_QSPI_H
+#define IPROC_QSPI_H
+
+#include <platform_def.h>
+
+/*SPI configuration enable*/
+#define IPROC_QSPI_CLK_SPEED 62500000
+#define SPI_CPHA (1 << 0)
+#define SPI_CPOL (1 << 1)
+#define IPROC_QSPI_MODE0 0
+#define IPROC_QSPI_MODE3 (SPI_CPOL|SPI_CPHA)
+
+#define IPROC_QSPI_BUS 0
+#define IPROC_QSPI_CS 0
+#define IPROC_QSPI_BASE_REG QSPI_CTRL_BASE_ADDR
+#define IPROC_QSPI_CRU_CONTROL_REG QSPI_CLK_CTRL
+
+#define QSPI_AXI_CLK 200000000
+
+#define QSPI_RETRY_COUNT_US_MAX 200000
+
+/* Chip attributes */
+#define QSPI_REG_BASE IPROC_QSPI_BASE_REG
+#define CRU_CONTROL_REG IPROC_QSPI_CRU_CONTROL_REG
+#define SPBR_DIV_MIN 8U
+#define SPBR_DIV_MAX 255U
+#define NUM_CDRAM_BYTES 16U
+
+/* Register fields */
+#define MSPI_SPCR0_MSB_BITS_8 0x00000020
+
+/* Flash opcode and parameters */
+#define CDRAM_PCS0 2
+#define CDRAM_CONT (1 << 7)
+#define CDRAM_BITS_EN (1 << 6)
+#define CDRAM_QUAD_MODE (1 << 8)
+#define CDRAM_RBIT_INPUT (1 << 10)
+
+/* MSPI registers */
+#define QSPI_MSPI_MODE_REG_BASE (QSPI_REG_BASE + 0x200)
+#define MSPI_SPCR0_LSB_REG 0x000
+#define MSPI_SPCR0_MSB_REG 0x004
+#define MSPI_SPCR1_LSB_REG 0x008
+#define MSPI_SPCR1_MSB_REG 0x00c
+#define MSPI_NEWQP_REG 0x010
+#define MSPI_ENDQP_REG 0x014
+#define MSPI_SPCR2_REG 0x018
+#define MSPI_STATUS_REG 0x020
+#define MSPI_CPTQP_REG 0x024
+#define MSPI_TXRAM_REG 0x040
+#define MSPI_RXRAM_REG 0x0c0
+#define MSPI_CDRAM_REG 0x140
+#define MSPI_WRITE_LOCK_REG 0x180
+#define MSPI_DISABLE_FLUSH_GEN_REG 0x184
+
+#define MSPI_SPCR0_MSB_REG_MSTR_SHIFT 7
+#define MSPI_SPCR0_MSB_REG_16_BITS_PER_WD_SHIFT (0 << 2)
+#define MSPI_SPCR0_MSB_REG_MODE_MASK 0x3
+
+/* BSPI registers */
+#define QSPI_BSPI_MODE_REG_BASE QSPI_REG_BASE
+#define BSPI_MAST_N_BOOT_CTRL_REG 0x008
+#define BSPI_BUSY_STATUS_REG 0x00c
+
+#define MSPI_CMD_COMPLETE_MASK 1
+#define BSPI_BUSY_MASK 1
+#define MSPI_CTRL_MASK 1
+
+#define MSPI_SPE (1 << 6)
+#define MSPI_CONT_AFTER_CMD (1 << 7)
+
+/* State */
+enum bcm_qspi_state {
+ QSPI_STATE_DISABLED,
+ QSPI_STATE_MSPI,
+ QSPI_STATE_BSPI
+};
+
+/* QSPI private data */
+struct bcmspi_priv {
+ /* Specified SPI parameters */
+ uint32_t max_hz;
+ uint32_t spi_mode;
+
+ /* State */
+ enum bcm_qspi_state state;
+ int mspi_16bit;
+
+ /* Registers */
+ uintptr_t mspi_hw;
+ uintptr_t bspi_hw;
+};
+
+int iproc_qspi_setup(uint32_t bus, uint32_t cs,
+ uint32_t max_hz, uint32_t mode);
+int iproc_qspi_claim_bus(void);
+void iproc_qspi_release_bus(void);
+int iproc_qspi_xfer(uint32_t bitlen, const void *dout,
+ void *din, unsigned long flags);
+
+#endif /* _IPROC_QSPI_H_ */
diff --git a/drivers/brcm/spi/iproc_spi.c b/drivers/brcm/spi/iproc_spi.c
new file mode 100644
index 0000000..551e587
--- /dev/null
+++ b/drivers/brcm/spi/iproc_spi.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <spi.h>
+
+#include "iproc_qspi.h"
+
+int spi_init(void)
+{
+ return iproc_qspi_setup(IPROC_QSPI_BUS, IPROC_QSPI_CS,
+ IPROC_QSPI_CLK_SPEED, IPROC_QSPI_MODE0);
+}
+
+int spi_claim_bus(void)
+{
+ return iproc_qspi_claim_bus();
+}
+
+void spi_release_bus(void)
+{
+ iproc_qspi_release_bus();
+}
+
+int spi_xfer(uint32_t bitlen, const void *dout,
+ void *din, uint32_t flags)
+{
+ return iproc_qspi_xfer(bitlen, dout, din, flags);
+}
diff --git a/drivers/brcm/spi_flash.c b/drivers/brcm/spi_flash.c
new file mode 100644
index 0000000..336d230
--- /dev/null
+++ b/drivers/brcm/spi_flash.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <errno.h>
+
+#include <sf.h>
+#include <spi.h>
+
+#define SPI_FLASH_CMD_LEN 4
+#define QSPI_WAIT_TIMEOUT_US 200000U /* usec */
+
+#define FINFO(jedec_id, ext_id, _sector_size, _n_sectors, _page_size, _flags) \
+ .id = { \
+ ((jedec_id) >> 16) & 0xff, \
+ ((jedec_id) >> 8) & 0xff, \
+ (jedec_id) & 0xff, \
+ ((ext_id) >> 8) & 0xff, \
+ (ext_id) & 0xff, \
+ }, \
+ .id_len = (!(jedec_id) ? 0 : (3 + ((ext_id) ? 2 : 0))), \
+ .sector_size = (_sector_size), \
+ .n_sectors = (_n_sectors), \
+ .page_size = _page_size, \
+ .flags = (_flags),
+
+/* SPI/QSPI flash device params structure */
+const struct spi_flash_info spi_flash_ids[] = {
+ {"W25Q64CV", FINFO(0xef4017, 0x0, 64 * 1024, 128, 256, WR_QPP | SECT_4K)},
+ {"W25Q64DW", FINFO(0xef6017, 0x0, 64 * 1024, 128, 256, WR_QPP | SECT_4K)},
+ {"W25Q32", FINFO(0xef4016, 0x0, 64 * 1024, 64, 256, SECT_4K)},
+ {"MX25l3205D", FINFO(0xc22016, 0x0, 64 * 1024, 64, 256, SECT_4K)},
+};
+
+static void spi_flash_addr(uint32_t addr, uint8_t *cmd)
+{
+ /*
+ * cmd[0] holds a SPI Flash command, stored earlier
+ * cmd[1/2/3] holds 24bit flash address
+ */
+ cmd[1] = addr >> 16;
+ cmd[2] = addr >> 8;
+ cmd[3] = addr >> 0;
+}
+
+static const struct spi_flash_info *spi_flash_read_id(void)
+{
+ const struct spi_flash_info *info;
+ uint8_t id[SPI_FLASH_MAX_ID_LEN];
+ int ret;
+
+ ret = spi_flash_cmd(CMD_READ_ID, id, SPI_FLASH_MAX_ID_LEN);
+ if (ret < 0) {
+ ERROR("SF: Error %d reading JEDEC ID\n", ret);
+ return NULL;
+ }
+
+ for (info = spi_flash_ids; info->name != NULL; info++) {
+ if (info->id_len) {
+ if (!memcmp(info->id, id, info->id_len))
+ return info;
+ }
+ }
+
+ printf("SF: unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
+ id[0], id[1], id[2]);
+ return NULL;
+}
+
+/* Enable writing on the SPI flash */
+static inline int spi_flash_cmd_write_enable(struct spi_flash *flash)
+{
+ return spi_flash_cmd(CMD_WRITE_ENABLE, NULL, 0);
+}
+
+static int spi_flash_cmd_wait(struct spi_flash *flash)
+{
+ uint8_t cmd;
+ uint32_t i;
+ uint8_t status;
+ int ret;
+
+ i = 0;
+ while (1) {
+ cmd = CMD_RDSR;
+ ret = spi_flash_cmd_read(&cmd, 1, &status, 1);
+ if (ret < 0) {
+ ERROR("SF: cmd wait failed\n");
+ break;
+ }
+ if (!(status & STATUS_WIP))
+ break;
+
+ i++;
+ if (i >= QSPI_WAIT_TIMEOUT_US) {
+ ERROR("SF: cmd wait timeout\n");
+ ret = -1;
+ break;
+ }
+ udelay(1);
+ }
+
+ return ret;
+}
+
+static int spi_flash_write_common(struct spi_flash *flash, const uint8_t *cmd,
+ size_t cmd_len, const void *buf,
+ size_t buf_len)
+{
+ int ret;
+
+ ret = spi_flash_cmd_write_enable(flash);
+ if (ret < 0) {
+ ERROR("SF: enabling write failed\n");
+ return ret;
+ }
+
+ ret = spi_flash_cmd_write(cmd, cmd_len, buf, buf_len);
+ if (ret < 0) {
+ ERROR("SF: write cmd failed\n");
+ return ret;
+ }
+
+ ret = spi_flash_cmd_wait(flash);
+ if (ret < 0) {
+ ERROR("SF: write timed out\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int spi_flash_read_common(const uint8_t *cmd, size_t cmd_len,
+ void *data, size_t data_len)
+{
+ int ret;
+
+ ret = spi_flash_cmd_read(cmd, cmd_len, data, data_len);
+ if (ret < 0) {
+ ERROR("SF: read cmd failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int spi_flash_read(struct spi_flash *flash, uint32_t offset,
+ uint32_t len, void *data)
+{
+ uint32_t read_len = 0, read_addr;
+ uint8_t cmd[SPI_FLASH_CMD_LEN];
+ int ret;
+
+ ret = spi_claim_bus();
+ if (ret) {
+ ERROR("SF: unable to claim SPI bus\n");
+ return ret;
+ }
+
+ cmd[0] = CMD_READ_NORMAL;
+ while (len) {
+ read_addr = offset;
+ read_len = MIN(flash->page_size, (len - read_len));
+ spi_flash_addr(read_addr, cmd);
+
+ ret = spi_flash_read_common(cmd, sizeof(cmd), data, read_len);
+ if (ret < 0) {
+ ERROR("SF: read failed\n");
+ break;
+ }
+
+ offset += read_len;
+ len -= read_len;
+ data += read_len;
+ }
+ SPI_DEBUG("SF read done\n");
+
+ spi_release_bus();
+ return ret;
+}
+
+int spi_flash_write(struct spi_flash *flash, uint32_t offset,
+ uint32_t len, void *buf)
+{
+ unsigned long byte_addr, page_size;
+ uint8_t cmd[SPI_FLASH_CMD_LEN];
+ uint32_t chunk_len, actual;
+ uint32_t write_addr;
+ int ret;
+
+ ret = spi_claim_bus();
+ if (ret) {
+ ERROR("SF: unable to claim SPI bus\n");
+ return ret;
+ }
+
+ page_size = flash->page_size;
+
+ cmd[0] = flash->write_cmd;
+ for (actual = 0; actual < len; actual += chunk_len) {
+ write_addr = offset;
+ byte_addr = offset % page_size;
+ chunk_len = MIN(len - actual,
+ (uint32_t)(page_size - byte_addr));
+ spi_flash_addr(write_addr, cmd);
+
+ SPI_DEBUG("SF:0x%p=>cmd:{0x%02x 0x%02x%02x%02x} chunk_len:%d\n",
+ buf + actual, cmd[0], cmd[1],
+ cmd[2], cmd[3], chunk_len);
+
+ ret = spi_flash_write_common(flash, cmd, sizeof(cmd),
+ buf + actual, chunk_len);
+ if (ret < 0) {
+ ERROR("SF: write cmd failed\n");
+ break;
+ }
+
+ offset += chunk_len;
+ }
+ SPI_DEBUG("SF write done\n");
+
+ spi_release_bus();
+ return ret;
+}
+
+int spi_flash_erase(struct spi_flash *flash, uint32_t offset, uint32_t len)
+{
+ uint8_t cmd[SPI_FLASH_CMD_LEN];
+ uint32_t erase_size, erase_addr;
+ int ret;
+
+ erase_size = flash->erase_size;
+
+ if (offset % erase_size || len % erase_size) {
+ ERROR("SF: Erase offset/length not multiple of erase size\n");
+ return -1;
+ }
+
+ ret = spi_claim_bus();
+ if (ret) {
+ ERROR("SF: unable to claim SPI bus\n");
+ return ret;
+ }
+
+ cmd[0] = flash->erase_cmd;
+ while (len) {
+ erase_addr = offset;
+ spi_flash_addr(erase_addr, cmd);
+
+ SPI_DEBUG("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1],
+ cmd[2], cmd[3], erase_addr);
+
+ ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0);
+ if (ret < 0) {
+ ERROR("SF: erase failed\n");
+ break;
+ }
+
+ offset += erase_size;
+ len -= erase_size;
+ }
+ SPI_DEBUG("sf erase done\n");
+
+ spi_release_bus();
+ return ret;
+}
+
+int spi_flash_probe(struct spi_flash *flash)
+{
+ const struct spi_flash_info *info = NULL;
+ int ret;
+
+ ret = spi_claim_bus();
+ if (ret) {
+ ERROR("SF: Unable to claim SPI bus\n");
+ ERROR("SF: probe failed\n");
+ return ret;
+ }
+
+ info = spi_flash_read_id();
+ if (!info)
+ goto probe_fail;
+
+ INFO("Flash Name: %s sectors %x, sec size %x\n",
+ info->name, info->n_sectors,
+ info->sector_size);
+ flash->size = info->n_sectors * info->sector_size;
+ flash->sector_size = info->sector_size;
+ flash->page_size = info->page_size;
+ flash->flags = info->flags;
+
+ flash->read_cmd = CMD_READ_NORMAL;
+ flash->write_cmd = CMD_PAGE_PROGRAM;
+ flash->erase_cmd = CMD_ERASE_64K;
+ flash->erase_size = ERASE_SIZE_64K;
+
+probe_fail:
+ spi_release_bus();
+ return ret;
+}
diff --git a/drivers/brcm/spi_sf.c b/drivers/brcm/spi_sf.c
new file mode 100644
index 0000000..8bbb09f
--- /dev/null
+++ b/drivers/brcm/spi_sf.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+
+#include <spi.h>
+
+#define BITS_PER_BYTE 8
+#define CMD_LEN1 1
+
+static int spi_flash_read_write(const uint8_t *cmd,
+ size_t cmd_len,
+ const uint8_t *data_out,
+ uint8_t *data_in,
+ size_t data_len)
+{
+ unsigned long flags = SPI_XFER_BEGIN;
+ int ret;
+
+ if (data_len == 0)
+ flags |= SPI_XFER_END;
+
+ ret = spi_xfer(cmd_len * BITS_PER_BYTE, cmd, NULL, flags);
+ if (ret) {
+ ERROR("SF: Failed to send command (%zu bytes): %d\n",
+ cmd_len, ret);
+ } else if (data_len != 0) {
+ ret = spi_xfer(data_len * BITS_PER_BYTE, data_out,
+ data_in, SPI_XFER_END);
+ if (ret)
+ ERROR("SF: Failed to transfer %zu bytes of data: %d\n",
+ data_len, ret);
+ }
+
+ return ret;
+}
+
+int spi_flash_cmd_read(const uint8_t *cmd,
+ size_t cmd_len,
+ void *data,
+ size_t data_len)
+{
+ return spi_flash_read_write(cmd, cmd_len, NULL, data, data_len);
+}
+
+int spi_flash_cmd(uint8_t cmd, void *response, size_t len)
+{
+ return spi_flash_cmd_read(&cmd, CMD_LEN1, response, len);
+}
+
+int spi_flash_cmd_write(const uint8_t *cmd,
+ size_t cmd_len,
+ const void *data,
+ size_t data_len)
+{
+ return spi_flash_read_write(cmd, cmd_len, data, NULL, data_len);
+}
diff --git a/drivers/cadence/uart/aarch64/cdns_console.S b/drivers/cadence/uart/aarch64/cdns_console.S
new file mode 100644
index 0000000..4c1a80e
--- /dev/null
+++ b/drivers/cadence/uart/aarch64/cdns_console.S
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console_macros.S>
+#include <drivers/cadence/cdns_uart.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_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_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_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_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 empty */
+ ldr w2, [x1, #R_UART_SR]
+ tbz w2, #UART_SR_INTR_TEMPTY_BIT, 1b
+ mov w2, #0xD
+ str w2, [x1, #R_UART_TX]
+2:
+ /* Check if the transmit FIFO is empty */
+ ldr w2, [x1, #R_UART_SR]
+ tbz w2, #UART_SR_INTR_TEMPTY_BIT, 2b
+ str w0, [x1, #R_UART_TX]
+ ret
+endfunc console_cdns_core_putc
+
+ /* --------------------------------------------------------
+ * int console_cdns_putc(int c, console_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_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_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_BASE]
+ b console_cdns_core_getc
+endfunc console_cdns_getc
+
+ /* ---------------------------------------------
+ * void 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 : void
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func console_cdns_core_flush
+#if ENABLE_ASSERTIONS
+ cmp x0, #0
+ ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+ /* Placeholder */
+ ret
+endfunc console_cdns_core_flush
+
+ /* ---------------------------------------------
+ * void console_cdns_flush(console_t *console)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * In : x0 - pointer to console_t structure
+ * Out : void.
+ * 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_BASE]
+ b console_cdns_core_flush
+endfunc console_cdns_flush
diff --git a/drivers/cfi/v2m/v2m_flash.c b/drivers/cfi/v2m/v2m_flash.c
new file mode 100644
index 0000000..6690189
--- /dev/null
+++ b/drivers/cfi/v2m/v2m_flash.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <drivers/cfi/v2m_flash.h>
+#include <lib/mmio.h>
+
+/*
+ * 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;
+}
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644
index 0000000..4cbc0f7
--- /dev/null
+++ b/drivers/clk/clk.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ * Author(s): Ludovic Barre, <ludovic.barre@st.com> for STMicroelectronics.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <drivers/clk.h>
+
+static const struct clk_ops *ops;
+
+int clk_enable(unsigned long id)
+{
+ assert((ops != NULL) && (ops->enable != NULL));
+
+ return ops->enable(id);
+}
+
+void clk_disable(unsigned long id)
+{
+ assert((ops != NULL) && (ops->disable != NULL));
+
+ ops->disable(id);
+}
+
+unsigned long clk_get_rate(unsigned long id)
+{
+ assert((ops != NULL) && (ops->get_rate != NULL));
+
+ return ops->get_rate(id);
+}
+
+int clk_get_parent(unsigned long id)
+{
+ assert((ops != NULL) && (ops->get_parent != NULL));
+
+ return ops->get_parent(id);
+}
+
+bool clk_is_enabled(unsigned long id)
+{
+ assert((ops != NULL) && (ops->is_enabled != NULL));
+
+ return ops->is_enabled(id);
+}
+
+/*
+ * Initialize the clk. The fields in the provided clk
+ * ops pointer must be valid.
+ */
+void clk_register(const struct clk_ops *ops_ptr)
+{
+ assert((ops_ptr != NULL) &&
+ (ops_ptr->enable != NULL) &&
+ (ops_ptr->disable != NULL) &&
+ (ops_ptr->get_rate != NULL) &&
+ (ops_ptr->get_parent != NULL) &&
+ (ops_ptr->is_enabled != NULL));
+
+ ops = ops_ptr;
+}
diff --git a/drivers/console/aarch32/skeleton_console.S b/drivers/console/aarch32/skeleton_console.S
new file mode 100644
index 0000000..a9e13ec
--- /dev/null
+++ b/drivers/console/aarch32/skeleton_console.S
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <asm_macros.S>
+#include <console_macros.S>
+
+ /*
+ * 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_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_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_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: void
+ * 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_BASE]
+
+ /*
+ * Flush all remaining output from hardware FIFOs. Do not return until
+ * all data has been flushed or there was an unrecoverable error.
+ */
+
+ bx lr
+endfunc console_xxx_flush
diff --git a/drivers/console/aarch64/skeleton_console.S b/drivers/console/aarch64/skeleton_console.S
new file mode 100644
index 0000000..7ea2eec
--- /dev/null
+++ b/drivers/console/aarch64/skeleton_console.S
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <asm_macros.S>
+#include <console_macros.S>
+
+ /*
+ * 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_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_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_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
+
+ /* ---------------------------------------------
+ * void 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: void
+ * 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_BASE]
+
+ /*
+ * Flush all remaining output from hardware FIFOs. Do not return until
+ * all data has been flushed or there was an unrecoverable error.
+ */
+
+ ret
+endfunc console_xxx_flush
diff --git a/drivers/console/multi_console.c b/drivers/console/multi_console.c
new file mode 100644
index 0000000..e3fb749
--- /dev/null
+++ b/drivers/console/multi_console.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <drivers/console.h>
+
+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 != NULL)) {
+ int ret = do_putc(c, console);
+ if ((err == ERROR_NO_VALID_CONSOLE) || (ret < err))
+ err = ret;
+ }
+ return err;
+}
+
+int putchar(int c)
+{
+ if (console_putc(c) == 0)
+ return c;
+ else
+ return EOF;
+}
+
+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 != NULL)) {
+ 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;
+}
+
+void console_flush(void)
+{
+ console_t *console;
+
+ for (console = console_list; console != NULL; console = console->next)
+ if ((console->flags & console_state) && (console->flush != NULL)) {
+ console->flush(console);
+ }
+}
diff --git a/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S b/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S
new file mode 100644
index 0000000..db07e6c
--- /dev/null
+++ b/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <console_macros.S>
+#include <drivers/coreboot/cbmem_console.h>
+
+/*
+ * This driver implements access to coreboot's in-memory console
+ * (CBMEM console). For the original implementation, see
+ * <coreboot>/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_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_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
+
+ /* -----------------------------------------------
+ * void 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: void
+ * Clobber list: x0, x1, x2, x3
+ * -----------------------------------------------
+ */
+func console_cbmc_flush
+ ldr x1, [x0, #CONSOLE_T_CBMC_SIZE]
+ ldr x0, [x0, #CONSOLE_T_BASE]
+ add x1, x1, #8 /* add size of console header */
+ b clean_dcache_range /* (clobbers x2 and x3) */
+endfunc console_cbmc_flush
diff --git a/drivers/delay_timer/delay_timer.c b/drivers/delay_timer/delay_timer.c
new file mode 100644
index 0000000..a3fd7bf
--- /dev/null
+++ b/drivers/delay_timer/delay_timer.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <drivers/delay_timer.h>
+#include <lib/utils_def.h>
+
+/***********************************************************
+ * 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;
+ uint64_t total_delta;
+
+ assert(usec < (UINT64_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((uint64_t)usec * timer_ops->clk_div,
+ timer_ops->clk_mult) + 1U;
+ /*
+ * Precaution for the total_delta ~ UINT32_MAX and the fact that we
+ * cannot catch every tick of the timer.
+ * For example 100MHz timer over 25MHz APB will miss at least 4 ticks.
+ * 1000U is an arbitrary big number which is believed to be sufficient.
+ */
+ assert(total_delta < (UINT32_MAX - 1000U));
+
+ do {
+ /*
+ * If the timer value wraps around, the subtraction will
+ * overflow and it will still give the correct result.
+ * delta is decreasing counter
+ */
+ delta = start - timer_ops->get_timer_value();
+
+ } 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)
+{
+ assert((msec * 1000UL) < UINT32_MAX);
+ 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;
+}
diff --git a/drivers/delay_timer/generic_delay_timer.c b/drivers/delay_timer/generic_delay_timer.c
new file mode 100644
index 0000000..ca522e0
--- /dev/null
+++ b/drivers/delay_timer/generic_delay_timer.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+
+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);
+}
+
diff --git a/drivers/fwu/fwu.c b/drivers/fwu/fwu.c
new file mode 100644
index 0000000..ff432be
--- /dev/null
+++ b/drivers/fwu/fwu.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/tf_crc32.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/fwu/fwu.h>
+#include <drivers/fwu/fwu_metadata.h>
+#include <drivers/io/io_storage.h>
+
+#include <plat/common/platform.h>
+
+/*
+ * Assert that crc_32 is the first member of fwu_metadata structure.
+ * It avoids accessing data outside of the metadata structure during
+ * CRC32 computation if the crc_32 field gets moved due the structure
+ * member(s) addition in the future.
+ */
+CASSERT((offsetof(struct fwu_metadata, crc_32) == 0),
+ crc_32_must_be_first_member_of_structure);
+
+static struct fwu_metadata metadata;
+static bool is_metadata_initialized __unused;
+
+/*******************************************************************************
+ * Compute CRC32 of the FWU metadata, and check it against the CRC32 value
+ * present in the FWU metadata.
+ *
+ * return -1 on error, otherwise 0
+ ******************************************************************************/
+static int fwu_metadata_crc_check(void)
+{
+ unsigned char *data = (unsigned char *)&metadata;
+
+ uint32_t calc_crc = tf_crc32(0U, data + sizeof(metadata.crc_32),
+ (sizeof(metadata) -
+ sizeof(metadata.crc_32)));
+
+ if (metadata.crc_32 != calc_crc) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Check the sanity of FWU metadata.
+ *
+ * return -1 on error, otherwise 0
+ ******************************************************************************/
+static int fwu_metadata_sanity_check(void)
+{
+ /* ToDo: add more conditions for sanity check */
+ if ((metadata.active_index >= NR_OF_FW_BANKS) ||
+ (metadata.previous_active_index >= NR_OF_FW_BANKS)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Verify and load specified FWU metadata image to local FWU metadata structure.
+ *
+ * @image_id: FWU metadata image id (either FWU_METADATA_IMAGE_ID or
+ * BKUP_FWU_METADATA_IMAGE_ID)
+ *
+ * return a negative value on error, otherwise 0
+ ******************************************************************************/
+static int fwu_metadata_load(unsigned int image_id)
+{
+ int result;
+ uintptr_t dev_handle, image_handle, image_spec;
+ size_t bytes_read;
+
+ assert((image_id == FWU_METADATA_IMAGE_ID) ||
+ (image_id == BKUP_FWU_METADATA_IMAGE_ID));
+
+ result = plat_fwu_set_metadata_image_source(image_id,
+ &dev_handle,
+ &image_spec);
+ if (result != 0) {
+ WARN("Failed to set 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 load image id id=%u (%i)\n",
+ image_id, result);
+ return result;
+ }
+
+ result = io_read(image_handle, (uintptr_t)&metadata,
+ sizeof(struct fwu_metadata), &bytes_read);
+
+ if (result != 0) {
+ WARN("Failed to read image id=%u (%i)\n", image_id, result);
+ goto exit;
+ }
+
+ if (sizeof(struct fwu_metadata) != bytes_read) {
+ /* return -1 in case of partial/no read */
+ result = -1;
+ WARN("Read bytes (%zu) instead of expected (%zu) bytes\n",
+ bytes_read, sizeof(struct fwu_metadata));
+ goto exit;
+ }
+
+ /* sanity check on loaded parameters */
+ result = fwu_metadata_sanity_check();
+ if (result != 0) {
+ WARN("Sanity %s\n", "check failed on FWU metadata");
+ goto exit;
+ }
+
+ /* CRC check on loaded parameters */
+ result = fwu_metadata_crc_check();
+ if (result != 0) {
+ WARN("CRC %s\n", "check failed on FWU metadata");
+ }
+
+exit:
+ (void)io_close(image_handle);
+
+ return result;
+}
+
+/*******************************************************************************
+ * The system runs in the trial run state if any of the images in the active
+ * firmware bank has not been accepted yet.
+ *
+ * Returns true if the system is running in the trial state.
+ ******************************************************************************/
+bool fwu_is_trial_run_state(void)
+{
+ bool trial_run = false;
+
+ assert(is_metadata_initialized);
+
+ for (unsigned int i = 0U; i < NR_OF_IMAGES_IN_FW_BANK; i++) {
+ struct fwu_image_entry *entry = &metadata.img_entry[i];
+ struct fwu_image_properties *img_props =
+ &entry->img_props[metadata.active_index];
+ if (img_props->accepted == 0) {
+ trial_run = true;
+ break;
+ }
+ }
+
+ return trial_run;
+}
+
+const struct fwu_metadata *fwu_get_metadata(void)
+{
+ assert(is_metadata_initialized);
+
+ return &metadata;
+}
+
+/*******************************************************************************
+ * Load verified copy of FWU metadata image kept in the platform NV storage
+ * into local FWU metadata structure.
+ * Also, update platform I/O policies with the offset address and length of
+ * firmware-updated images kept in the platform NV storage.
+ ******************************************************************************/
+void fwu_init(void)
+{
+ /* Load FWU metadata which will be used to load the images in the
+ * active bank as per PSA FWU specification
+ */
+ int result = fwu_metadata_load(FWU_METADATA_IMAGE_ID);
+
+ if (result != 0) {
+ WARN("loading of FWU-Metadata failed, "
+ "using Bkup-FWU-Metadata\n");
+
+ result = fwu_metadata_load(BKUP_FWU_METADATA_IMAGE_ID);
+ if (result != 0) {
+ ERROR("loading of Bkup-FWU-Metadata failed\n");
+ panic();
+ }
+ }
+
+ is_metadata_initialized = true;
+
+ plat_fwu_set_images_source(&metadata);
+}
diff --git a/drivers/fwu/fwu.mk b/drivers/fwu/fwu.mk
new file mode 100644
index 0000000..f4452e0
--- /dev/null
+++ b/drivers/fwu/fwu.mk
@@ -0,0 +1,11 @@
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+FWU_SRC_DIR := drivers/fwu/
+
+FWU_SRCS := ${FWU_SRC_DIR}fwu.c
+
+BL2_SOURCES += ${FWU_SRCS}
diff --git a/drivers/gpio/gpio.c b/drivers/gpio/gpio.c
new file mode 100644
index 0000000..76612b2
--- /dev/null
+++ b/drivers/gpio/gpio.c
@@ -0,0 +1,93 @@
+/*
+ * 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 <assert.h>
+#include <errno.h>
+
+#include <drivers/gpio.h>
+
+/*
+ * 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;
+}
diff --git a/drivers/imx/timer/imx_gpt.c b/drivers/imx/timer/imx_gpt.c
new file mode 100644
index 0000000..464efe9
--- /dev/null
+++ b/drivers/imx/timer/imx_gpt.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <imx_gpt.h>
+
+#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);
+}
diff --git a/drivers/imx/timer/imx_gpt.h b/drivers/imx/timer/imx_gpt.h
new file mode 100644
index 0000000..2432633
--- /dev/null
+++ b/drivers/imx/timer/imx_gpt.h
@@ -0,0 +1,14 @@
+/*
+ * 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 <stdint.h>
+
+void imx_gpt_ops_init(uintptr_t reg_base);
+
+#endif /* IMX_GPT_H */
diff --git a/drivers/imx/uart/imx_crash_uart.S b/drivers/imx/uart/imx_crash_uart.S
new file mode 100644
index 0000000..aa987b3
--- /dev/null
+++ b/drivers/imx/uart/imx_crash_uart.S
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) Linaro 2018 Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <imx_uart.h>
+#include <platform_def.h>
+
+ .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
diff --git a/drivers/imx/uart/imx_uart.c b/drivers/imx/uart/imx_uart.c
new file mode 100644
index 0000000..dfe2e92
--- /dev/null
+++ b/drivers/imx/uart/imx_uart.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) Linaro 2018 Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <lib/mmio.h>
+
+#include <imx_uart.h>
+
+/* 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 : void
+ * Clobber list : r0, r1
+ * ---------------------------------------------
+ */
+void console_imx_uart_core_flush(uintptr_t base_addr)
+{
+}
+
diff --git a/drivers/imx/uart/imx_uart.h b/drivers/imx/uart/imx_uart.h
new file mode 100644
index 0000000..a133024
--- /dev/null
+++ b/drivers/imx/uart/imx_uart.h
@@ -0,0 +1,163 @@
+/*
+ * 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 <drivers/console.h>
+
+#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__
+
+int console_imx_uart_register(uintptr_t baseaddr,
+ uint32_t clock,
+ uint32_t baud,
+ console_t *console);
+#endif /*__ASSEMBLER__*/
+
+#endif /* IMX_UART_H */
diff --git a/drivers/imx/usdhc/imx_usdhc.c b/drivers/imx/usdhc/imx_usdhc.c
new file mode 100644
index 0000000..07f55b7
--- /dev/null
+++ b/drivers/imx/usdhc/imx_usdhc.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/mmc.h>
+#include <lib/mmio.h>
+
+#include <imx_usdhc.h>
+
+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);
+}
diff --git a/drivers/imx/usdhc/imx_usdhc.h b/drivers/imx/usdhc/imx_usdhc.h
new file mode 100644
index 0000000..e063316
--- /dev/null
+++ b/drivers/imx/usdhc/imx_usdhc.h
@@ -0,0 +1,137 @@
+/*
+ * 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 <drivers/mmc.h>
+
+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 */
diff --git a/drivers/intel/soc/stratix10/io/s10_memmap_qspi.c b/drivers/intel/soc/stratix10/io/s10_memmap_qspi.c
new file mode 100644
index 0000000..dcd1991
--- /dev/null
+++ b/drivers/intel/soc/stratix10/io/s10_memmap_qspi.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <lib/utils.h>
+
+#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;
+ unsigned long long file_pos;
+ unsigned long long 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,
+ signed long long offset);
+static int memmap_block_len(io_entity_t *entity, size_t *length);
+static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
+ size_t length, size_t *length_read);
+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)&current_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,
+ signed long long 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) &&
+ ((unsigned long long)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;
+ unsigned long long 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;
+ unsigned long long 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 *)&current_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;
+}
diff --git a/drivers/io/io_block.c b/drivers/io/io_block.c
new file mode 100644
index 0000000..5d45c2f
--- /dev/null
+++ b/drivers/io/io_block.c
@@ -0,0 +1,551 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+#include <lib/utils.h>
+
+typedef struct {
+ io_block_dev_spec_t *dev_spec;
+ uintptr_t base;
+ unsigned long long file_pos;
+ unsigned long long size;
+} block_dev_state_t;
+
+#define is_power_of_2(x) (((x) != 0U) && (((x) & ((x) - 1U)) == 0U))
+
+io_type_t device_type_block(void);
+
+static int block_open(io_dev_info_t *dev_info, const uintptr_t spec,
+ io_entity_t *entity);
+static int block_seek(io_entity_t *entity, int mode, signed long long offset);
+static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+ size_t *length_read);
+static int block_write(io_entity_t *entity, const uintptr_t buffer,
+ 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, signed long long offset)
+{
+ block_dev_state_t *cur;
+
+ assert(entity->info != (uintptr_t)NULL);
+
+ cur = (block_dev_state_t *)entity->info;
+ assert((offset >= 0) && ((unsigned long long)offset < cur->size));
+
+ switch (mode) {
+ case IO_SEEK_SET:
+ cur->file_pos = (unsigned long long)offset;
+ break;
+ case IO_SEEK_CUR:
+ cur->file_pos += (unsigned long long)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 > 0U) &&
+ (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 > 0U; 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 - 1U);
+
+ /*
+ * 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 - 1U)) &
+ ~(block_size - 1U);
+ }
+ 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 : 0U;
+ 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 > 0U) &&
+ (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 > 0U; 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 - 1U);
+
+ /*
+ * 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 - 1U)) &
+ ~(block_size - 1U);
+ }
+
+ /*
+ * 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 : 0U;
+ 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 > 0U) || (padding > 0U)) {
+ request = ops->read(lba, buf->offset, request);
+ /*
+ * The read may return size less than
+ * requested. Round down to the nearest block
+ * boundary
+ */
+ request &= ~(block_size - 1U);
+ 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 : 0U;
+ 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 : 0U;
+ 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 != 0)
+ 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 > 0U) &&
+ (is_power_of_2(block_size) != 0U) &&
+ ((buffer->offset % block_size) == 0U) &&
+ ((buffer->length % block_size) == 0U));
+
+ *dev_info = info; /* cast away const */
+ (void)block_size;
+ (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;
+}
diff --git a/drivers/io/io_dummy.c b/drivers/io/io_dummy.c
new file mode 100644
index 0000000..4f0cda6
--- /dev/null
+++ b/drivers/io/io_dummy.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_dummy.h>
+#include <drivers/io/io_storage.h>
+
+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)&current_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;
+}
diff --git a/drivers/io/io_encrypted.c b/drivers/io/io_encrypted.c
new file mode 100644
index 0000000..744ca83
--- /dev/null
+++ b/drivers/io/io_encrypted.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2020, Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_encrypted.h>
+#include <drivers/io/io_storage.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <tools_share/firmware_encrypted.h>
+#include <tools_share/uuid.h>
+
+static uintptr_t backend_dev_handle;
+static uintptr_t backend_dev_spec;
+static uintptr_t backend_handle;
+static uintptr_t backend_image_spec;
+
+static io_dev_info_t enc_dev_info;
+
+/* Encrypted firmware driver functions */
+static int enc_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
+static int enc_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
+ io_entity_t *entity);
+static int enc_file_len(io_entity_t *entity, size_t *length);
+static int enc_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+ size_t *length_read);
+static int enc_file_close(io_entity_t *entity);
+static int enc_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params);
+static int enc_dev_close(io_dev_info_t *dev_info);
+
+static inline int is_valid_header(struct fw_enc_hdr *header)
+{
+ if (header->magic == ENC_HEADER_MAGIC)
+ return 1;
+ else
+ return 0;
+}
+
+static io_type_t device_type_enc(void)
+{
+ return IO_TYPE_ENCRYPTED;
+}
+
+static const io_dev_connector_t enc_dev_connector = {
+ .dev_open = enc_dev_open
+};
+
+static const io_dev_funcs_t enc_dev_funcs = {
+ .type = device_type_enc,
+ .open = enc_file_open,
+ .seek = NULL,
+ .size = enc_file_len,
+ .read = enc_file_read,
+ .write = NULL,
+ .close = enc_file_close,
+ .dev_init = enc_dev_init,
+ .dev_close = enc_dev_close,
+};
+
+static int enc_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info)
+{
+ assert(dev_info != NULL);
+
+ enc_dev_info.funcs = &enc_dev_funcs;
+ *dev_info = &enc_dev_info;
+
+ return 0;
+}
+
+static int enc_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params)
+{
+ int result;
+ unsigned int image_id = (unsigned int)init_params;
+
+ /* Obtain a reference to the image by querying the platform layer */
+ result = plat_get_image_source(image_id, &backend_dev_handle,
+ &backend_dev_spec);
+ if (result != 0) {
+ WARN("Failed to obtain reference to image id=%u (%i)\n",
+ image_id, result);
+ return -ENOENT;
+ }
+
+ return result;
+}
+
+static int enc_dev_close(io_dev_info_t *dev_info)
+{
+ backend_dev_handle = (uintptr_t)NULL;
+ backend_dev_spec = (uintptr_t)NULL;
+
+ return 0;
+}
+
+static int enc_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
+ io_entity_t *entity)
+{
+ int result;
+
+ assert(spec != 0);
+ assert(entity != NULL);
+
+ backend_image_spec = spec;
+
+ result = io_open(backend_dev_handle, backend_image_spec,
+ &backend_handle);
+ if (result != 0) {
+ WARN("Failed to open backend device (%i)\n", result);
+ result = -ENOENT;
+ }
+
+ return result;
+}
+
+static int enc_file_len(io_entity_t *entity, size_t *length)
+{
+ int result;
+
+ assert(entity != NULL);
+ assert(length != NULL);
+
+ result = io_size(backend_handle, length);
+ if (result != 0) {
+ WARN("Failed to read blob length (%i)\n", result);
+ return -ENOENT;
+ }
+
+ /*
+ * Encryption header is attached at the beginning of the encrypted file
+ * and is not considered a part of the payload.
+ */
+ if (*length < sizeof(struct fw_enc_hdr))
+ return -EIO;
+
+ *length -= sizeof(struct fw_enc_hdr);
+
+ return result;
+}
+
+static int enc_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+ size_t *length_read)
+{
+ int result;
+ struct fw_enc_hdr header;
+ enum fw_enc_status_t fw_enc_status;
+ size_t bytes_read;
+ uint8_t key[ENC_MAX_KEY_SIZE];
+ size_t key_len = sizeof(key);
+ unsigned int key_flags = 0;
+ const io_uuid_spec_t *uuid_spec = (io_uuid_spec_t *)backend_image_spec;
+
+ assert(entity != NULL);
+ assert(length_read != NULL);
+
+ result = io_read(backend_handle, (uintptr_t)&header, sizeof(header),
+ &bytes_read);
+ if (result != 0) {
+ WARN("Failed to read encryption header (%i)\n", result);
+ return -ENOENT;
+ }
+
+ if (!is_valid_header(&header)) {
+ WARN("Encryption header check failed.\n");
+ return -ENOENT;
+ }
+
+ VERBOSE("Encryption header looks OK.\n");
+ fw_enc_status = header.flags & FW_ENC_STATUS_FLAG_MASK;
+
+ if ((header.iv_len > ENC_MAX_IV_SIZE) ||
+ (header.tag_len > ENC_MAX_TAG_SIZE)) {
+ WARN("Incorrect IV or tag length\n");
+ return -ENOENT;
+ }
+
+ result = io_read(backend_handle, buffer, length, &bytes_read);
+ if (result != 0) {
+ WARN("Failed to read encrypted payload (%i)\n", result);
+ return -ENOENT;
+ }
+
+ *length_read = bytes_read;
+
+ result = plat_get_enc_key_info(fw_enc_status, key, &key_len, &key_flags,
+ (uint8_t *)&uuid_spec->uuid,
+ sizeof(uuid_t));
+ if (result != 0) {
+ WARN("Failed to obtain encryption key (%i)\n", result);
+ return -ENOENT;
+ }
+
+ result = crypto_mod_auth_decrypt(header.dec_algo,
+ (void *)buffer, *length_read, key,
+ key_len, key_flags, header.iv,
+ header.iv_len, header.tag,
+ header.tag_len);
+ memset(key, 0, key_len);
+
+ if (result != 0) {
+ ERROR("File decryption failed (%i)\n", result);
+ return -ENOENT;
+ }
+
+ return result;
+}
+
+static int enc_file_close(io_entity_t *entity)
+{
+ io_close(backend_handle);
+
+ backend_image_spec = (uintptr_t)NULL;
+ entity->info = 0;
+
+ return 0;
+}
+
+/* Exported functions */
+
+/* Register the Encrypted Firmware driver with the IO abstraction */
+int register_io_dev_enc(const io_dev_connector_t **dev_con)
+{
+ int result;
+
+ assert(dev_con != NULL);
+
+ result = io_register_device(&enc_dev_info);
+ if (result == 0)
+ *dev_con = &enc_dev_connector;
+
+ return result;
+}
diff --git a/drivers/io/io_fip.c b/drivers/io/io_fip.c
new file mode 100644
index 0000000..6e15295
--- /dev/null
+++ b/drivers/io/io_fip.c
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_storage.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <tools_share/firmware_image_package.h>
+#include <tools_share/uuid.h>
+
+#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;
+} fip_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;
+ uint16_t plat_toc_flag;
+} fip_dev_state_t;
+
+/*
+ * 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 fip_file_state_t current_fip_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;
+ fip_dev_state_t *state;
+
+ assert(dev_info != NULL);
+
+ state = (fip_dev_state_t *)dev_info->info;
+
+ /* 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");
+ /*
+ * Store 16-bit Platform ToC flags field which occupies
+ * bits [32-47] in fip header.
+ */
+ state->plat_toc_flag = (header.flags >> 32) & 0xffff;
+ }
+ }
+
+ 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;
+ static const uuid_t uuid_null = { {0} }; /* Double braces for clang */
+ 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_fip_file.entry.offset_address != 0U) {
+ WARN("fip_file_open : Only one open file at a time.\n");
+ return -ENFILE;
+ }
+
+ /* 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,
+ (signed long long)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)&current_fip_file.entry,
+ sizeof(current_fip_file.entry),
+ &bytes_read);
+ if (result == 0) {
+ if (compare_uuids(&current_fip_file.entry.uuid,
+ &uuid_spec->uuid) == 0) {
+ found_file = 1;
+ }
+ } else {
+ WARN("Failed to read FIP (%i)\n", result);
+ goto fip_file_open_close;
+ }
+ } while ((found_file == 0) &&
+ (compare_uuids(&current_fip_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_fip_file.entry' holds
+ * the base and size of the file.
+ */
+ current_fip_file.file_pos = 0;
+ entity->info = (uintptr_t)&current_fip_file;
+ } else {
+ /* Did not find the file in the FIP. */
+ current_fip_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 = ((fip_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;
+ fip_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 = (fip_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,
+ (signed long long)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_fip_file.entry.offset_address != 0U) {
+ zeromem(&current_fip_file, sizeof(current_fip_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;
+}
+
+/* Function to retrieve plat_toc_flags, previously saved in FIP dev */
+int fip_dev_get_plat_toc_flag(io_dev_info_t *dev_info, uint16_t *plat_toc_flag)
+{
+ fip_dev_state_t *state;
+
+ assert(dev_info != NULL);
+
+ state = (fip_dev_state_t *)dev_info->info;
+
+ *plat_toc_flag = state->plat_toc_flag;
+
+ return 0;
+}
diff --git a/drivers/io/io_memmap.c b/drivers/io/io_memmap.c
new file mode 100644
index 0000000..eb69163
--- /dev/null
+++ b/drivers/io/io_memmap.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <lib/utils.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;
+ unsigned long long file_pos;
+ unsigned long long size;
+} memmap_file_state_t;
+
+static memmap_file_state_t current_memmap_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,
+ signed long long offset);
+static int memmap_block_len(io_entity_t *entity, size_t *length);
+static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
+ size_t length, size_t *length_read);
+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 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 = &memmap_dev_info;
+ 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_memmap_file.in_use == 0) {
+ assert(block_spec != NULL);
+ assert(entity != NULL);
+
+ current_memmap_file.in_use = 1;
+ current_memmap_file.base = block_spec->offset;
+ /* File cursor offset for seek and incremental reads etc. */
+ current_memmap_file.file_pos = 0;
+ current_memmap_file.size = block_spec->length;
+ entity->info = (uintptr_t)&current_memmap_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,
+ signed long long offset)
+{
+ int result = -ENOENT;
+ memmap_file_state_t *fp;
+
+ /* We only support IO_SEEK_SET for the moment. */
+ if (mode == IO_SEEK_SET) {
+ assert(entity != NULL);
+
+ fp = (memmap_file_state_t *) entity->info;
+
+ /* Assert that new file position is valid */
+ assert((offset >= 0) &&
+ ((unsigned long long)offset < fp->size));
+
+ /* Reset file position */
+ fp->file_pos = (unsigned long long)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 = (size_t)((memmap_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)
+{
+ memmap_file_state_t *fp;
+ unsigned long long pos_after;
+
+ assert(entity != NULL);
+ assert(length_read != NULL);
+
+ fp = (memmap_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 *)((uintptr_t)(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)
+{
+ memmap_file_state_t *fp;
+ unsigned long long pos_after;
+
+ assert(entity != NULL);
+ assert(length_written != NULL);
+
+ fp = (memmap_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 *)((uintptr_t)(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 *)&current_memmap_file, sizeof(current_memmap_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;
+}
diff --git a/drivers/io/io_mtd.c b/drivers/io/io_mtd.c
new file mode 100644
index 0000000..5d86592
--- /dev/null
+++ b/drivers/io/io_mtd.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_mtd.h>
+#include <lib/utils.h>
+
+#include <platform_def.h>
+
+typedef struct {
+ io_mtd_dev_spec_t *dev_spec;
+ uintptr_t base;
+ unsigned long long pos; /* Offset in bytes */
+ unsigned long long size; /* Size of device in bytes */
+ unsigned long long extra_offset; /* Extra offset in bytes */
+} mtd_dev_state_t;
+
+io_type_t device_type_mtd(void);
+
+static int mtd_open(io_dev_info_t *dev_info, const uintptr_t spec,
+ io_entity_t *entity);
+static int mtd_seek(io_entity_t *entity, int mode, signed long long offset);
+static int mtd_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+ size_t *length_read);
+static int mtd_close(io_entity_t *entity);
+static int mtd_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
+static int mtd_dev_close(io_dev_info_t *dev_info);
+
+static const io_dev_connector_t mtd_dev_connector = {
+ .dev_open = mtd_dev_open
+};
+
+static const io_dev_funcs_t mtd_dev_funcs = {
+ .type = device_type_mtd,
+ .open = mtd_open,
+ .seek = mtd_seek,
+ .read = mtd_read,
+ .close = mtd_close,
+ .dev_close = mtd_dev_close,
+};
+
+static mtd_dev_state_t state_pool[MAX_IO_MTD_DEVICES];
+static io_dev_info_t dev_info_pool[MAX_IO_MTD_DEVICES];
+
+io_type_t device_type_mtd(void)
+{
+ return IO_TYPE_MTD;
+}
+
+/* Locate a MTD state in the pool, specified by address */
+static int find_first_mtd_state(const io_mtd_dev_spec_t *dev_spec,
+ unsigned int *index_out)
+{
+ unsigned int index;
+ int result = -ENOENT;
+
+ for (index = 0U; index < MAX_IO_MTD_DEVICES; index++) {
+ /* dev_spec is used as identifier since it's unique */
+ if (state_pool[index].dev_spec == dev_spec) {
+ result = 0;
+ *index_out = index;
+ break;
+ }
+ }
+
+ return result;
+}
+
+/* Allocate a device info from the pool */
+static int allocate_dev_info(io_dev_info_t **dev_info)
+{
+ unsigned int index = 0U;
+ int result;
+
+ result = find_first_mtd_state(NULL, &index);
+ if (result != 0) {
+ return -ENOMEM;
+ }
+
+ dev_info_pool[index].funcs = &mtd_dev_funcs;
+ dev_info_pool[index].info = (uintptr_t)&state_pool[index];
+ *dev_info = &dev_info_pool[index];
+
+ return 0;
+}
+
+/* Release a device info from the pool */
+static int free_dev_info(io_dev_info_t *dev_info)
+{
+ int result;
+ unsigned int index = 0U;
+ mtd_dev_state_t *state;
+
+ state = (mtd_dev_state_t *)dev_info->info;
+ result = find_first_mtd_state(state->dev_spec, &index);
+ if (result != 0) {
+ return result;
+ }
+
+ zeromem(state, sizeof(mtd_dev_state_t));
+ zeromem(dev_info, sizeof(io_dev_info_t));
+
+ return 0;
+}
+
+static int mtd_add_extra_offset(mtd_dev_state_t *cur, size_t *extra_offset)
+{
+ io_mtd_ops_t *ops = &cur->dev_spec->ops;
+ int ret;
+
+ if (ops->seek == NULL) {
+ return 0;
+ }
+
+ ret = ops->seek(cur->base, cur->pos, extra_offset);
+ if (ret != 0) {
+ ERROR("%s: Seek error %d\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mtd_open(io_dev_info_t *dev_info, const uintptr_t spec,
+ io_entity_t *entity)
+{
+ mtd_dev_state_t *cur;
+ io_block_spec_t *region;
+ size_t extra_offset = 0U;
+ int ret;
+
+ assert((dev_info->info != 0UL) && (entity->info == 0UL));
+
+ region = (io_block_spec_t *)spec;
+ cur = (mtd_dev_state_t *)dev_info->info;
+ entity->info = (uintptr_t)cur;
+ cur->base = region->offset;
+ cur->pos = 0U;
+ cur->extra_offset = 0U;
+
+ ret = mtd_add_extra_offset(cur, &extra_offset);
+ if (ret != 0) {
+ return ret;
+ }
+
+ cur->base += extra_offset;
+
+ return 0;
+}
+
+/* Seek to a specific position using offset */
+static int mtd_seek(io_entity_t *entity, int mode, signed long long offset)
+{
+ mtd_dev_state_t *cur;
+ size_t extra_offset = 0U;
+ int ret;
+
+ assert((entity->info != (uintptr_t)NULL) && (offset >= 0));
+
+ cur = (mtd_dev_state_t *)entity->info;
+
+ switch (mode) {
+ case IO_SEEK_SET:
+ if ((offset >= 0) &&
+ ((unsigned long long)offset >= cur->size)) {
+ return -EINVAL;
+ }
+
+ cur->pos = offset;
+ break;
+ case IO_SEEK_CUR:
+ if (((cur->base + cur->pos + (unsigned long long)offset) >=
+ cur->size) ||
+ ((cur->base + cur->pos + (unsigned long long)offset) <
+ cur->base + cur->pos)) {
+ return -EINVAL;
+ }
+
+ cur->pos += (unsigned long long)offset;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = mtd_add_extra_offset(cur, &extra_offset);
+ if (ret != 0) {
+ return ret;
+ }
+
+ cur->extra_offset = extra_offset;
+
+ return 0;
+}
+
+static int mtd_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+ size_t *out_length)
+{
+ mtd_dev_state_t *cur;
+ io_mtd_ops_t *ops;
+ int ret;
+
+ assert(entity->info != (uintptr_t)NULL);
+ assert((length > 0U) && (buffer != (uintptr_t)NULL));
+
+ cur = (mtd_dev_state_t *)entity->info;
+ ops = &cur->dev_spec->ops;
+ assert(ops->read != NULL);
+
+ VERBOSE("Read at %llx into %lx, length %zu\n",
+ cur->base + cur->pos, buffer, length);
+ if ((cur->base + cur->pos + length) > cur->dev_spec->device_size) {
+ return -EINVAL;
+ }
+
+ ret = ops->read(cur->base + cur->pos + cur->extra_offset, buffer,
+ length, out_length);
+ if (ret < 0) {
+ return ret;
+ }
+
+ assert(*out_length == length);
+ cur->pos += *out_length;
+
+ return 0;
+}
+
+static int mtd_close(io_entity_t *entity)
+{
+ entity->info = (uintptr_t)NULL;
+
+ return 0;
+}
+
+static int mtd_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info)
+{
+ mtd_dev_state_t *cur;
+ io_dev_info_t *info;
+ io_mtd_ops_t *ops;
+ int result;
+
+ result = allocate_dev_info(&info);
+ if (result != 0) {
+ return -ENOENT;
+ }
+
+ cur = (mtd_dev_state_t *)info->info;
+ cur->dev_spec = (io_mtd_dev_spec_t *)dev_spec;
+ *dev_info = info;
+ ops = &(cur->dev_spec->ops);
+ if (ops->init != NULL) {
+ result = ops->init(&cur->dev_spec->device_size,
+ &cur->dev_spec->erase_size);
+ }
+
+ if (result == 0) {
+ cur->size = cur->dev_spec->device_size;
+ } else {
+ cur->size = 0ULL;
+ }
+
+ return result;
+}
+
+static int mtd_dev_close(io_dev_info_t *dev_info)
+{
+ return free_dev_info(dev_info);
+}
+
+/* Exported functions */
+
+/* Register the MTD driver in the IO abstraction */
+int register_io_dev_mtd(const io_dev_connector_t **dev_con)
+{
+ int result;
+
+ result = io_register_device(&dev_info_pool[0]);
+ if (result == 0) {
+ *dev_con = &mtd_dev_connector;
+ }
+
+ return result;
+}
diff --git a/drivers/io/io_semihosting.c b/drivers/io/io_semihosting.c
new file mode 100644
index 0000000..1c2f84d
--- /dev/null
+++ b/drivers/io/io_semihosting.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_semihosting.h>
+#include <drivers/io/io_storage.h>
+#include <lib/semihosting.h>
+
+/* 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, signed long long offset);
+static int sh_file_len(io_entity_t *entity, size_t *length);
+static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+ size_t *length_read);
+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 */
+};
+
+
+static 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 = &sh_dev_info;
+ 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, signed long long offset)
+{
+ long file_handle, sh_result;
+
+ assert(entity != NULL);
+
+ file_handle = (long)entity->info;
+
+ sh_result = semihosting_file_seek(file_handle, (ssize_t)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;
+}
diff --git a/drivers/io/io_storage.c b/drivers/io/io_storage.c
new file mode 100644
index 0000000..0534268
--- /dev/null
+++ b/drivers/io/io_storage.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+
+#include <platform_def.h>
+
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+
+/* 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 bool is_valid_dev_connector(const io_dev_connector_t *dev_con)
+{
+ return (dev_con != NULL) && (dev_con->dev_open != NULL);
+}
+
+/* Return a boolean value indicating whether a device handle is valid */
+static bool is_valid_dev(const uintptr_t dev_handle)
+{
+ const io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
+
+ return (dev != NULL) && (dev->funcs != NULL) &&
+ (dev->funcs->type != NULL) &&
+ (dev->funcs->type() < IO_TYPE_MAX);
+}
+
+
+/* Return a boolean value indicating whether an IO entity is valid */
+static bool is_valid_entity(const uintptr_t handle)
+{
+ const io_entity_t *entity = (io_entity_t *)handle;
+
+ return (entity != NULL) &&
+ (is_valid_dev((uintptr_t)entity->dev_handle));
+}
+
+
+/* Return a boolean value indicating whether a seek mode is valid */
+static bool 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 io_storage_dev_open(const io_dev_connector_t *dev_con,
+ const uintptr_t dev_spec,
+ io_dev_info_t **dev_info)
+{
+ assert(dev_info != NULL);
+ assert(is_valid_dev_connector(dev_con));
+
+ return dev_con->dev_open(dev_spec, dev_info);
+}
+
+
+/* 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_pool[index];
+ 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)
+{
+ assert(handle != NULL);
+ return io_storage_dev_open(dev_con, dev_spec, (io_dev_info_t **)handle);
+}
+
+
+/* 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, signed long long 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;
+}
diff --git a/drivers/marvell/amb_adec.c b/drivers/marvell/amb_adec.c
new file mode 100644
index 0000000..d78fa25
--- /dev/null
+++ b/drivers/marvell/amb_adec.c
@@ -0,0 +1,160 @@
+/*
+ * 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 <inttypes.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+#include <mvebu.h>
+#include <mvebu_def.h>
+
+#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%" PRIx64 "\n",
+ win_num, win->base_addr);
+ win->base_addr = AMB_BASE_ADDR_MASK;
+ WARN("Set the base address to 0x%" PRIx64 "\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%" PRIx64 "\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%" PRIx64 ")\n",
+ win_num, win->win_size);
+ win->win_size = ROUND_UP_TO_POW_OF_2(win->win_size);
+ WARN("Rounding size to 0x%" PRIx64 "\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;
+}
diff --git a/drivers/marvell/ap807_clocks_init.c b/drivers/marvell/ap807_clocks_init.c
new file mode 100644
index 0000000..c1f8619
--- /dev/null
+++ b/drivers/marvell/ap807_clocks_init.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <drivers/delay_timer.h>
+#include <drivers/marvell/aro.h>
+#include <lib/mmio.h>
+
+#include <a8k_plat_def.h>
+
+/* 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_FRC_DSCHG (0x2)
+#define AP807_CPU_PLL_CFG_USE_REG_FILE (0x1 << 9)
+
+static void pll_set_freq(unsigned int freq_val)
+{
+ int i;
+
+ if (freq_val != PLL_FREQ_2200)
+ return;
+
+ for (i = 0 ; i < AP807_CLUSTER_NUM ; i++) {
+ /* Set parameter of cluster i PLL to 2.2GHz */
+ mmio_write_32(AP807_CPU_PLL_PARAM(i), freq_val);
+ /* Set apll_lpf_frc_dschg - Control
+ * voltage of internal VCO is discharged
+ */
+ mmio_write_32(AP807_CPU_PLL_CFG(i),
+ AP807_CPU_PLL_FRC_DSCHG);
+ /* Set use_rf_conf load PLL parameter from register */
+ mmio_write_32(AP807_CPU_PLL_CFG(i),
+ AP807_CPU_PLL_FRC_DSCHG |
+ AP807_CPU_PLL_CFG_USE_REG_FILE);
+ /* Un-set apll_lpf_frc_dschg */
+ 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)
+{
+ /* 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.
+ */
+
+ if (freq_option == CPU_2200_DDR_1200_RCLK_1200)
+ pll_set_freq(PLL_FREQ_2200);
+
+ /* Switch from ARO to PLL */
+ aro_to_pll();
+
+}
diff --git a/drivers/marvell/cache_llc.c b/drivers/marvell/cache_llc.c
new file mode 100644
index 0000000..4b06b47
--- /dev/null
+++ b/drivers/marvell/cache_llc.c
@@ -0,0 +1,189 @@
+/*
+ * 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 <assert.h>
+
+#include <arch_helpers.h>
+#include <drivers/marvell/cache_llc.h>
+#include <drivers/marvell/ccu.h>
+#include <lib/mmio.h>
+
+#include <mvebu_def.h>
+
+#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(LLC_CLEAN_INV_WAY(ap_index), LLC_ALL_WAYS_MASK);
+ llc_cache_sync(ap_index);
+}
+
+void llc_clean_all(int ap_index)
+{
+ mmio_write_32(LLC_CLEAN_WAY(ap_index), LLC_ALL_WAYS_MASK);
+ llc_cache_sync(ap_index);
+}
+
+void llc_inv_all(int ap_index)
+{
+ mmio_write_32(LLC_INV_WAY(ap_index), LLC_ALL_WAYS_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);
+}
+
+#if LLC_SRAM
+int llc_sram_enable(int ap_index, int size)
+{
+ uint32_t tc, way, ways_to_allocate;
+ uint32_t way_addr;
+
+ if ((size <= 0) || (size > LLC_SIZE) || (size % LLC_WAY_SIZE))
+ return -1;
+
+ llc_enable(ap_index, 1);
+ llc_inv_all(ap_index);
+
+ ways_to_allocate = size / LLC_WAY_SIZE;
+
+ /* Lockdown all available ways for all traffic classes */
+ for (tc = 0; tc < LLC_TC_NUM; tc++)
+ mmio_write_32(LLC_TCN_LOCK(ap_index, tc), LLC_ALL_WAYS_MASK);
+
+ /* Clear the high bits of SRAM address */
+ mmio_write_32(LLC_BANKED_MNT_AHR(ap_index), 0);
+
+ way_addr = PLAT_MARVELL_TRUSTED_RAM_BASE;
+ for (way = 0; way < ways_to_allocate; way++) {
+ /* Trigger allocation block command */
+ mmio_write_32(LLC_BLK_ALOC(ap_index),
+ LLC_BLK_ALOC_BASE_ADDR(way_addr) |
+ LLC_BLK_ALOC_WAY_DATA_SET |
+ LLC_BLK_ALOC_WAY_ID(way));
+ way_addr += LLC_WAY_SIZE;
+ }
+ return 0;
+}
+
+void llc_sram_disable(int ap_index)
+{
+ uint32_t tc;
+
+ /* Disable the line lockings */
+ for (tc = 0; tc < LLC_TC_NUM; tc++)
+ mmio_write_32(LLC_TCN_LOCK(ap_index, tc), 0);
+
+ /* Invalidate all ways */
+ llc_inv_all(ap_index);
+}
+
+int llc_sram_test(int ap_index, int size, char *msg)
+{
+ uintptr_t addr, end_addr;
+ uint32_t data = 0;
+
+ if ((size <= 0) || (size > LLC_SIZE))
+ return -1;
+
+ INFO("=== LLC SRAM WRITE test %s\n", msg);
+ for (addr = PLAT_MARVELL_TRUSTED_RAM_BASE,
+ end_addr = PLAT_MARVELL_TRUSTED_RAM_BASE + size;
+ addr < end_addr; addr += 4) {
+ mmio_write_32(addr, addr);
+ }
+ INFO("=== LLC SRAM WRITE test %s PASSED\n", msg);
+ INFO("=== LLC SRAM READ test %s\n", msg);
+ for (addr = PLAT_MARVELL_TRUSTED_RAM_BASE,
+ end_addr = PLAT_MARVELL_TRUSTED_RAM_BASE + size;
+ addr < end_addr; addr += 4) {
+ data = mmio_read_32(addr);
+ if (data != addr) {
+ INFO("=== LLC SRAM READ test %s FAILED @ 0x%08lx)\n",
+ msg, addr);
+ return -1;
+ }
+ }
+ INFO("=== LLC SRAM READ test %s PASSED (last read = 0x%08x)\n",
+ msg, data);
+ return 0;
+}
+
+#endif /* LLC_SRAM */
diff --git a/drivers/marvell/ccu.c b/drivers/marvell/ccu.c
new file mode 100644
index 0000000..c206f11
--- /dev/null
+++ b/drivers/marvell/ccu.c
@@ -0,0 +1,417 @@
+/*
+ * 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 <inttypes.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <drivers/marvell/ccu.h>
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+#include <mvebu.h>
+#include <mvebu_def.h>
+
+#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)
+
+/*
+ * Physical address of the highest address of window bits[31:19] = 0x6FF
+ * Physical address of the lowest address of window bits[18:6] = 0x6E0
+ * Unit Id bits [5:2] = 2
+ * RGF Window Enable bit[0] = 1
+ * 0x37f9b809 - 11011111111 0011011100000 0010 0 1
+ */
+#define ERRATA_WA_CCU_WIN4 0x37f9b809U
+
+/*
+ * Physical address of the highest address of window bits[31:19] = 0xFFF
+ * Physical address of the lowest address of window bits[18:6] = 0x800
+ * Unit Id bits [5:2] = 2
+ * RGF Window Enable bit[0] = 1
+ * 0x7ffa0009 - 111111111111 0100000000000 0010 0 1
+ */
+#define ERRATA_WA_CCU_WIN5 0x7ffa0009U
+
+/*
+ * Physical address of the highest address of window bits[31:19] = 0x1FFF
+ * Physical address of the lowest address of window bits[18:6] = 0x1000
+ * Unit Id bits [5:2] = 2
+ * RGF Window Enable bit[0] = 1
+ * 0xfffc000d - 1111111111111 1000000000000 0011 0 1
+ */
+#define ERRATA_WA_CCU_WIN6 0xfffc000dU
+
+#define IS_DRAM_TARGET(tgt) ((((tgt) == DRAM_0_TID) || \
+ ((tgt) == DRAM_1_TID) || \
+ ((tgt) == RAR_TID)) ? 1 : 0)
+
+#define CCU_RGF(win) (MVEBU_CCU_BASE(MVEBU_AP0) + \
+ 0x90 + 4 * (win))
+
+/* 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%d %02x 0x%016" PRIx64 " 0x%016" PRIx64 "\n",
+ win_id, 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%" PRIx64 "\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%" PRIx64 "\n",
+ __func__, win->win_size);
+ }
+}
+
+int ccu_is_win_enabled(int ap_index, uint32_t win_id)
+{
+ return mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id)) &
+ WIN_ENABLE_BIT;
+}
+
+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;
+}
+
+void errata_wa_init(void)
+{
+ /*
+ * EERATA 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, 0x1ff_ffff] to values [0x6e_0000, 0x6f_ffff] and
+ * [0x80_0000, 0xff_ffff] and [0x100_0000, 0x1ff_ffff],that cause
+ * accesses to the segment of [0xf070_0000, 0xf1ff_ffff]
+ * to act as RAZWI.
+ */
+ mmio_write_32(CCU_RGF(4), ERRATA_WA_CCU_WIN4);
+ mmio_write_32(CCU_RGF(5), ERRATA_WA_CCU_WIN5);
+ mmio_write_32(CCU_RGF(6), ERRATA_WA_CCU_WIN6);
+}
diff --git a/drivers/marvell/comphy.h b/drivers/marvell/comphy.h
new file mode 100644
index 0000000..fab564e
--- /dev/null
+++ b/drivers/marvell/comphy.h
@@ -0,0 +1,472 @@
+/*
+ * 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 */
diff --git a/drivers/marvell/comphy/comphy-cp110.h b/drivers/marvell/comphy/comphy-cp110.h
new file mode 100644
index 0000000..af5c715
--- /dev/null
+++ b/drivers/marvell/comphy/comphy-cp110.h
@@ -0,0 +1,914 @@
+/*
+ * 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/Base-X/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_TX_IDLE_OFFSET 2
+#define SD_EXTERNAL_CONFIG1_TX_IDLE_MASK \
+ (0x1 << SD_EXTERNAL_CONFIG1_TX_IDLE_OFFSET)
+#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_SYNC_PATTERN_REG 0x090
+#define HPIPE_SYNC_PATTERN_TXD_INV_OFFSET 10
+#define HPIPE_SYNC_PATTERN_TXD_INV_MASK \
+ (0x1 << HPIPE_SYNC_PATTERN_TXD_INV_OFFSET)
+#define HPIPE_SYNC_PATTERN_RXD_INV_OFFSET 11
+#define HPIPE_SYNC_PATTERN_RXD_INV_MASK \
+ (0x1 << HPIPE_SYNC_PATTERN_RXD_INV_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_CRD_MIDPOINT_PHASE_OS_OFFSET 0
+#define HPIPE_CRD_MIDPOINT_PHASE_OS_MASK \
+ (0x3f << HPIPE_CRD_MIDPOINT_PHASE_OS_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_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_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_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_CONTROL1_REG 0x41c
+#define HPIPE_CRD2_CRD_MIDPOINT_SMALL_THRES_K_OFF 12
+#define HPIPE_CRD2_CRD_MIDPOINT_SMALL_THRES_K_MASK \
+ (0xf << HPIPE_CRD2_CRD_MIDPOINT_SMALL_THRES_K_OFF)
+
+#define HPIPE_CDR_CONTROL2_REG 0x420
+#define HPIPE_CRD2_CRD_MIDPOINT_LARGE_THRES_K_OFF 12
+#define HPIPE_CRD2_CRD_MIDPOINT_LARGE_THRES_K_MASK \
+ (0xf << HPIPE_CRD2_CRD_MIDPOINT_LARGE_THRES_K_OFF)
+
+#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_TRX0_REG 0x4cc /*in doc 0x133*4*/
+#define HPIPE_TRX0_GAIN_TRAIN_WITH_SAMPLER_OFF 2
+#define HPIPE_TRX0_GAIN_TRAIN_WITH_SAMPLER_MASK \
+ (0x1 << HPIPE_TRX0_GAIN_TRAIN_WITH_SAMPLER_OFF)
+#define HPIPE_TRX0_GAIN_TRAIN_WITH_C_OFF 0
+#define HPIPE_TRX0_GAIN_TRAIN_WITH_C_MASK \
+ (0x1 << HPIPE_TRX0_GAIN_TRAIN_WITH_C_OFF)
+
+#define HPIPE_TRX_REG1 0x4d0 /*in doc 0x134*4*/
+#define HPIPE_TRX_REG1_MIN_BOOST_MODE_OFF 3
+#define HPIPE_TRX_REG1_MIN_BOOST_MODE_MASK \
+ (0x1 << HPIPE_TRX_REG1_MIN_BOOST_MODE_OFF)
+#define HPIPE_TRX_REG1_SUMFTAP_EN_OFF 10
+#define HPIPE_TRX_REG1_SUMFTAP_EN_MASK \
+ (0x3f << HPIPE_TRX_REG1_SUMFTAP_EN_OFF)
+
+#define HPIPE_TRX_REG2 0x4d8 /*in doc 0x136*4*/
+#define HPIPE_TRX_REG2_SUMF_BOOST_TARGET_C_OFF 11
+#define HPIPE_TRX_REG2_SUMF_BOOST_TARGET_C_MASK \
+ (0x1f << HPIPE_TRX_REG2_SUMF_BOOST_TARGET_C_OFF)
+#define HPIPE_TRX_REG2_SUMF_BOOST_TARGET_K_OFF 7
+#define HPIPE_TRX_REG2_SUMF_BOOST_TARGET_K_MASK \
+ (0xf << HPIPE_TRX_REG2_SUMF_BOOST_TARGET_K_OFF)
+
+#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 */
diff --git a/drivers/marvell/comphy/phy-comphy-3700.c b/drivers/marvell/comphy/phy-comphy-3700.c
new file mode 100644
index 0000000..1a97753
--- /dev/null
+++ b/drivers/marvell/comphy/phy-comphy-3700.c
@@ -0,0 +1,1065 @@
+/*
+ * Copyright (C) 2018-2021 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+
+#include <mvebu.h>
+#include <mvebu_def.h>
+#include <plat_marvell.h>
+
+#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)
+
+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 */
+};
+
+/* PHY selector configures with corresponding modes */
+static int 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_2500BASEX_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 0;
+error:
+ ERROR("COMPHY[%d] mode[%d] is invalid\n", comphy_index, mode);
+ return -EINVAL;
+}
+
+/*
+ * This is something like the inverse of the previous function: for given
+ * lane it returns COMPHY_*_MODE.
+ *
+ * It is useful when powering the phy off.
+ *
+ * This function returns COMPHY_USB3_MODE even if the phy was configured
+ * with COMPHY_USB3D_MODE or COMPHY_USB3H_MODE. (The usb3 phy initialization
+ * code does not differentiate between these modes.)
+ * Also it returns COMPHY_SGMII_MODE even if the phy was configures with
+ * COMPHY_2500BASEX_MODE. (The sgmii phy initialization code does differentiate
+ * between these modes, but it is irrelevant when powering the phy off.)
+ */
+static int mvebu_a3700_comphy_get_mode(uint8_t comphy_index)
+{
+ uint32_t reg;
+
+ reg = mmio_read_32(MVEBU_COMPHY_REG_BASE + COMPHY_SELECTOR_PHY_REG);
+ switch (comphy_index) {
+ case COMPHY_LANE0:
+ if ((reg & COMPHY_SELECTOR_USB3_GBE1_SEL_BIT) != 0)
+ return COMPHY_USB3_MODE;
+ else
+ return COMPHY_SGMII_MODE;
+ case COMPHY_LANE1:
+ if ((reg & COMPHY_SELECTOR_PCIE_GBE0_SEL_BIT) != 0)
+ return COMPHY_PCIE_MODE;
+ else
+ return COMPHY_SGMII_MODE;
+ case COMPHY_LANE2:
+ if ((reg & COMPHY_SELECTOR_USB3_PHY_SEL_BIT) != 0)
+ return COMPHY_USB3_MODE;
+ else
+ return COMPHY_SATA_MODE;
+ }
+
+ return COMPHY_UNUSED;
+}
+
+/* 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, bool is_sata)
+{
+ /*
+ * 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 (is_sata) {
+ 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 for SATA on comphy lane2. */
+static void comphy_sata_set_indirect(uintptr_t addr, uint32_t reg_offset,
+ uint16_t data, uint16_t mask)
+{
+ comphy_set_indirect(addr, reg_offset, data, mask, true);
+}
+
+/* It is only used for USB3 indirect access on comphy lane2. */
+static void comphy_usb3_set_indirect(uintptr_t addr, uint32_t reg_offset,
+ uint16_t data, uint16_t mask)
+{
+ comphy_set_indirect(addr, reg_offset, data, mask, false);
+}
+
+/* It is only used for 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)
+{
+ reg_set16((reg_offset * PHY_SHFT(USB3) + addr), data, mask);
+}
+
+static void comphy_sgmii_phy_init(uintptr_t sd_ip_addr, bool is_1gbps)
+{
+ 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 (!is_1gbps && 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;
+ uint32_t offset, data = 0, ref_clk;
+ uintptr_t comphy_indir_regs = COMPHY_INDIRECT_REG;
+ int invert = COMPHY_GET_POLARITY_INVERT(comphy_mode);
+
+ debug_enter();
+
+ /* Configure phy selector for SATA */
+ ret = mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode);
+ if (ret) {
+ return ret;
+ }
+
+ /* Clear phy isolation mode to make it work in normal mode */
+ offset = COMPHY_ISOLATION_CTRL + SATAPHY_LANE2_REG_BASE_OFFSET;
+ comphy_sata_set_indirect(comphy_indir_regs, offset, 0, PHY_ISOLATE_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 + SATAPHY_LANE2_REG_BASE_OFFSET;
+ comphy_sata_set_indirect(comphy_indir_regs, offset, data, TXD_INVERT_BIT |
+ RXD_INVERT_BIT);
+
+ /* 1. Select 40-bit data width width */
+ offset = COMPHY_DIG_LOOPBACK_EN + SATAPHY_LANE2_REG_BASE_OFFSET;
+ comphy_sata_set_indirect(comphy_indir_regs, offset, DATA_WIDTH_40BIT,
+ SEL_DATA_WIDTH_MASK);
+
+ /* 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_FREF_SEL_SERDES_40MHZ;
+ else
+ ref_clk = REF_FREF_SEL_SERDES_25MHZ;
+
+ comphy_sata_set_indirect(comphy_indir_regs, offset, ref_clk | PHY_MODE_SATA,
+ REF_FREF_SEL_MASK | PHY_MODE_MASK);
+
+ /* 3. Use maximum PLL rate (no power save) */
+ offset = COMPHY_KVCO_CAL_CTRL + SATAPHY_LANE2_REG_BASE_OFFSET;
+ comphy_sata_set_indirect(comphy_indir_regs, offset, USE_MAX_PLL_RATE_BIT,
+ USE_MAX_PLL_RATE_BIT);
+
+ /* 4. Reset reserved bit */
+ comphy_sata_set_indirect(comphy_indir_regs, COMPHY_RESERVED_REG, 0,
+ PHYCTRL_FRM_PIN_BIT);
+
+ /* 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_DIG_LOOPBACK_EN + 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);
+ if (ret) {
+ return -ETIMEDOUT;
+ }
+
+ debug_exit();
+
+ return 0;
+}
+
+static int mvebu_a3700_comphy_sgmii_power_on(uint8_t comphy_index,
+ uint32_t comphy_mode)
+{
+ int ret;
+ uint32_t mask, data;
+ uintptr_t 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 */
+ ret = mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode);
+ if (ret) {
+ return ret;
+ }
+
+ /* 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_IVREF_BIT | PIN_TX_IDLE_BIT | PIN_RESET_COMPHY_BIT;
+ mask = data | 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_2500BASEX_MODE) {
+ /* 2500Base-X, SerDes speed 3.125G */
+ data |= SD_SPEED_3_125_G << GEN_RX_SEL_OFFSET;
+ data |= SD_SPEED_3_125_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_CTRL0, sd_ip_addr), data, mask);
+
+ /*
+ * 9. Set correct reference clock frequency in COMPHY register
+ * REF_FREF_SEL.
+ */
+ if (get_ref_clk() == 40)
+ data = REF_FREF_SEL_SERDES_50MHZ;
+ else
+ data = REF_FREF_SEL_SERDES_25MHZ;
+
+ 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_DIG_LOOPBACK_EN, 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_2500BASEX_MODE ? "2G5" : "1G");
+ if (get_ref_clk() == 40)
+ comphy_sgmii_phy_init(sd_ip_addr, mode != COMPHY_2500BASEX_MODE);
+
+ /*
+ * 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;
+ mask = TXD_INVERT_BIT | RXD_INVERT_BIT;
+ reg_set16(SGMIIPHY_ADDR(COMPHY_SYNC_PATTERN, sd_ip_addr), data, mask);
+
+ /*
+ * 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);
+ return -ETIMEDOUT;
+ }
+
+ /*
+ * 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, PHY_RX_INIT_BIT);
+
+ 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);
+ return -ETIMEDOUT;
+ }
+
+ 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);
+ return -ETIMEDOUT;
+ }
+
+ debug_exit();
+
+ return 0;
+}
+
+static int mvebu_a3700_comphy_sgmii_power_off(uint8_t comphy_index)
+{
+ uintptr_t offset;
+ uint32_t mask, data;
+
+ debug_enter();
+
+ data = PIN_RESET_CORE_BIT | PIN_RESET_COMPHY_BIT;
+ mask = data;
+ offset = MVEBU_COMPHY_REG_BASE + COMPHY_PHY_CFG1_OFFSET(comphy_index);
+ reg_set(offset, data, mask);
+
+ debug_exit();
+
+ return 0;
+}
+
+static int mvebu_a3700_comphy_usb3_power_on(uint8_t comphy_index,
+ uint32_t comphy_mode)
+{
+ int ret;
+ uintptr_t reg_base = 0;
+ uintptr_t addr;
+ uint32_t mask, data, cfg, ref_clk;
+ void (*usb3_reg_set)(uintptr_t addr, uint32_t reg_offset, uint16_t data,
+ uint16_t mask);
+ int invert = COMPHY_GET_POLARITY_INVERT(comphy_mode);
+
+ debug_enter();
+
+ /* Set phy seclector */
+ ret = mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode);
+ if (ret) {
+ return ret;
+ }
+
+ /* Set usb3 reg access func, Lane2 is indirect access */
+ if (comphy_index == COMPHY_LANE2) {
+ usb3_reg_set = &comphy_usb3_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_LANE_CFG0, PRD_TXDEEMPH0_MASK, mask);
+
+ /*
+ * 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_LANE_CFG0 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_LANE_CFG1, data, mask);
+
+ /*
+ * 3. Set Spread Spectrum Clock Enabled
+ */
+ usb3_reg_set(reg_base, COMPHY_LANE_CFG4,
+ SPREAD_SPECTRUM_CLK_EN, SPREAD_SPECTRUM_CLK_EN);
+
+ /*
+ * 4. Set Override Margining Controls From the MAC:
+ * Use margining signals from lane configuration
+ */
+ usb3_reg_set(reg_base, COMPHY_TEST_MODE_CTRL,
+ MODE_MARGIN_OVERRIDE, REG_16_BIT_MASK);
+
+ /*
+ * 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_CLK_SRC_LO, 0x0,
+ (MODE_CLK_SRC | BUNDLE_PERIOD_SEL |
+ BUNDLE_PERIOD_SCALE_MASK | BUNDLE_SAMPLE_CTRL |
+ PLL_READY_DLY_MASK));
+
+ /*
+ * 6. Set G2 Spread Spectrum Clock Amplitude at 4K
+ */
+ usb3_reg_set(reg_base, COMPHY_GEN2_SET2,
+ GS2_TX_SSC_AMP_VALUE_20, GS2_TX_SSC_AMP_MASK);
+
+ /*
+ * 7. Unset G3 Spread Spectrum Clock Amplitude
+ * set G3 TX and RX Register Master Current Select
+ */
+ mask = GS2_TX_SSC_AMP_MASK | GS2_VREG_RXTX_MAS_ISET_MASK |
+ GS2_RSVD_6_0_MASK;
+ usb3_reg_set(reg_base, COMPHY_GEN3_SET2,
+ GS2_VREG_RXTX_MAS_ISET_60U, mask);
+
+ /*
+ * 8. Check crystal jumper setting and program the Power and PLL Control
+ * accordingly Change RX wait
+ */
+ if (get_ref_clk() == 40) {
+ ref_clk = REF_FREF_SEL_PCIE_USB3_40MHZ;
+ cfg = CFG_PM_RXDLOZ_WAIT_12_UNIT;
+
+ } else {
+ /* 25 MHz */
+ ref_clk = REF_FREF_SEL_PCIE_USB3_25MHZ;
+ 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);
+
+ 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_PWR_MGM_TIM1, data, mask);
+
+ /*
+ * 9. Enable idle sync
+ */
+ data = IDLE_SYNC_EN_DEFAULT_VALUE | IDLE_SYNC_EN;
+ usb3_reg_set(reg_base, COMPHY_IDLE_SYNC_EN, data, REG_16_BIT_MASK);
+
+ /*
+ * 10. Enable the output of 500M clock
+ */
+ data = MISC_CTRL0_DEFAULT_VALUE | CLK500M_EN;
+ usb3_reg_set(reg_base, COMPHY_MISC_CTRL0, data, REG_16_BIT_MASK);
+
+ /*
+ * 11. Set 20-bit data width
+ */
+ usb3_reg_set(reg_base, COMPHY_DIG_LOOPBACK_EN, DATA_WIDTH_20BIT,
+ REG_16_BIT_MASK);
+
+ /*
+ * 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);
+
+ /*
+ * 13. Check the Polarity invert bit
+ */
+ data = 0U;
+ if (invert & COMPHY_POLARITY_TXD_INVERT) {
+ data |= TXD_INVERT_BIT;
+ }
+ if (invert & COMPHY_POLARITY_RXD_INVERT) {
+ data |= RXD_INVERT_BIT;
+ }
+ mask = TXD_INVERT_BIT | RXD_INVERT_BIT;
+ usb3_reg_set(reg_base, COMPHY_SYNC_PATTERN, data, mask);
+
+ /*
+ * 14. Set max speed generation to USB3.0 5Gbps
+ */
+ usb3_reg_set(reg_base, COMPHY_SYNC_MASK_GEN, PHY_GEN_MAX_USB3_5G,
+ PHY_GEN_MAX_MASK);
+
+ /*
+ * 15. Set capacitor value for FFE gain peaking to 0xF
+ */
+ usb3_reg_set(reg_base, COMPHY_GEN2_SET3,
+ GS3_FFE_CAP_SEL_VALUE, GS3_FFE_CAP_SEL_MASK);
+
+ /*
+ * 16. Release SW reset
+ */
+ data = MODE_CORE_CLK_FREQ_SEL | MODE_PIPE_WIDTH_32 | MODE_REFDIV_BY_4;
+ usb3_reg_set(reg_base, COMPHY_RST_CLK_CTRL, data, REG_16_BIT_MASK);
+
+ /* Wait for > 55 us to allow PCLK be enabled */
+ udelay(PLL_SET_DELAY_US);
+
+ if (comphy_index == COMPHY_LANE2) {
+ data = COMPHY_LANE_STAT1 + USB3PHY_LANE2_REG_BASE_OFFSET;
+ mmio_write_32(reg_base + COMPHY_LANE2_INDIR_ADDR_OFFSET,
+ data);
+
+ addr = reg_base + COMPHY_LANE2_INDIR_DATA_OFFSET;
+ ret = polling_with_timeout(addr, TXDCLK_PCLK_EN, TXDCLK_PCLK_EN,
+ COMPHY_PLL_TIMEOUT, REG_32BIT);
+ } else {
+ ret = polling_with_timeout(LANE_STAT1_ADDR(USB3) + reg_base,
+ TXDCLK_PCLK_EN, TXDCLK_PCLK_EN,
+ COMPHY_PLL_TIMEOUT, REG_16BIT);
+ }
+ if (ret) {
+ ERROR("Failed to lock USB3 PLL\n");
+ return -ETIMEDOUT;
+ }
+
+ debug_exit();
+
+ return 0;
+}
+
+static int mvebu_a3700_comphy_pcie_power_on(uint8_t comphy_index,
+ uint32_t comphy_mode)
+{
+ int ret;
+ uint32_t ref_clk;
+ uint32_t mask, data;
+ int invert = COMPHY_GET_POLARITY_INVERT(comphy_mode);
+
+ debug_enter();
+
+ /* Configure phy selector for PCIe */
+ ret = mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode);
+ if (ret) {
+ return ret;
+ }
+
+ /* 1. Enable max PLL. */
+ reg_set16(LANE_CFG1_ADDR(PCIE) + COMPHY_SD_ADDR,
+ USE_MAX_PLL_RATE_EN, USE_MAX_PLL_RATE_EN);
+
+ /* 2. Select 20 bit SERDES interface. */
+ reg_set16(CLK_SRC_LO_ADDR(PCIE) + COMPHY_SD_ADDR,
+ CFG_SEL_20B, CFG_SEL_20B);
+
+ /* 3. Force to use reg setting for PCIe mode */
+ reg_set16(MISC_CTRL1_ADDR(PCIE) + COMPHY_SD_ADDR,
+ SEL_BITS_PCIE_FORCE, SEL_BITS_PCIE_FORCE);
+
+ /* 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(IDLE_SYNC_EN_ADDR(PCIE) + COMPHY_SD_ADDR,
+ IDLE_SYNC_EN_DEFAULT_VALUE | IDLE_SYNC_EN, REG_16_BIT_MASK);
+
+ /* 6. Enable the output of 100M/125M/500M clock */
+ reg_set16(MISC_CTRL0_ADDR(PCIE) + COMPHY_SD_ADDR,
+ MISC_CTRL0_DEFAULT_VALUE | CLK500M_EN | TXDCLK_2X_SEL | 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_FREF_SEL_PCIE_USB3_40MHZ;
+ else
+ ref_clk = REF_FREF_SEL_PCIE_USB3_25MHZ;
+
+ 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 */
+ data = 0U;
+ if (invert & COMPHY_POLARITY_TXD_INVERT) {
+ data |= TXD_INVERT_BIT;
+ }
+ if (invert & COMPHY_POLARITY_RXD_INVERT) {
+ data |= RXD_INVERT_BIT;
+ }
+ mask = TXD_INVERT_BIT | RXD_INVERT_BIT;
+ reg_set16(SYNC_PATTERN_ADDR(PCIE) + COMPHY_SD_ADDR, data, mask);
+
+ /* 11. Release SW reset */
+ data = MODE_CORE_CLK_FREQ_SEL | MODE_PIPE_WIDTH_32;
+ mask = data | SOFT_RESET | MODE_REFDIV_MASK;
+ reg_set16(RST_CLK_CTRL_ADDR(PCIE) + COMPHY_SD_ADDR, data, mask);
+
+ /* Wait for > 55 us to allow PCLK be enabled */
+ udelay(PLL_SET_DELAY_US);
+
+ ret = polling_with_timeout(LANE_STAT1_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");
+ return -ETIMEDOUT;
+ }
+
+ debug_exit();
+
+ return 0;
+}
+
+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_2500BASEX_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(void)
+{
+ uintptr_t comphy_indir_regs = COMPHY_INDIRECT_REG;
+ uint32_t offset;
+
+ debug_enter();
+
+ /* Set phy isolation mode */
+ offset = COMPHY_ISOLATION_CTRL + SATAPHY_LANE2_REG_BASE_OFFSET;
+ comphy_sata_set_indirect(comphy_indir_regs, offset, PHY_ISOLATE_MODE,
+ PHY_ISOLATE_MODE);
+
+ /* Power off PLL, Tx, Rx */
+ offset = COMPHY_POWER_PLL_CTRL + SATAPHY_LANE2_REG_BASE_OFFSET;
+ comphy_sata_set_indirect(comphy_indir_regs, offset, 0,
+ PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT);
+
+ 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();
+
+ if (!mode) {
+ /*
+ * The user did not specify which mode should be powered off.
+ * In this case we can identify this by reading the phy selector
+ * register.
+ */
+ mode = mvebu_a3700_comphy_get_mode(comphy_index);
+ }
+
+ switch (mode) {
+ case(COMPHY_SGMII_MODE):
+ case(COMPHY_2500BASEX_MODE):
+ err = mvebu_a3700_comphy_sgmii_power_off(comphy_index);
+ break;
+ 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();
+ 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_DIG_LOOPBACK_EN + 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;
+}
diff --git a/drivers/marvell/comphy/phy-comphy-3700.h b/drivers/marvell/comphy/phy-comphy-3700.h
new file mode 100644
index 0000000..ed07624
--- /dev/null
+++ b/drivers/marvell/comphy/phy-comphy-3700.h
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2018-2021 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: Lane1 is GbE0; 1: Lane1 is PCIE */
+#define COMPHY_SELECTOR_PCIE_GBE0_SEL_BIT BIT(0)
+/* bit4: 0: Lane0 is GbE1; 1: Lane0 is USB3 */
+#define COMPHY_SELECTOR_USB3_GBE1_SEL_BIT BIT(4)
+/* bit8: 0: Lane0 is USB3 instead of GbE1, 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_FREF_SEL_SERDES_25MHZ (0x1 << REF_FREF_SEL_OFFSET)
+#define REF_FREF_SEL_SERDES_40MHZ (0x3 << REF_FREF_SEL_OFFSET)
+#define REF_FREF_SEL_SERDES_50MHZ (0x4 << REF_FREF_SEL_OFFSET)
+#define REF_FREF_SEL_PCIE_USB3_25MHZ (0x2 << REF_FREF_SEL_OFFSET)
+#define REF_FREF_SEL_PCIE_USB3_40MHZ (0x3 << 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_DIG_LOOPBACK_EN 0x23
+#define DIG_LOOPBACK_EN_ADDR(unit) (COMPHY_DIG_LOOPBACK_EN * \
+ 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 0x24
+#define SYNC_PATTERN_ADDR(unit) (COMPHY_SYNC_PATTERN * PHY_SHFT(unit))
+#define TXD_INVERT_BIT BIT(10)
+#define RXD_INVERT_BIT BIT(11)
+
+#define COMPHY_SYNC_MASK_GEN 0x25
+#define PHY_GEN_MAX_OFFSET 10
+#define PHY_GEN_MAX_MASK (3 << PHY_GEN_MAX_OFFSET)
+#define PHY_GEN_MAX_USB3_5G (1 << PHY_GEN_MAX_OFFSET)
+
+#define COMPHY_ISOLATION_CTRL 0x26
+#define ISOLATION_CTRL_ADDR(unit) (COMPHY_ISOLATION_REG * PHY_SHFT(unit))
+#define PHY_ISOLATE_MODE BIT(15)
+
+#define COMPHY_GEN2_SET2 0x3e
+#define GEN2_SET2_ADDR(unit) (COMPHY_GEN2_SET2 * PHY_SHFT(unit))
+#define GS2_TX_SSC_AMP_VALUE_20 BIT(14)
+#define GS2_TX_SSC_AMP_OFF 9
+#define GS2_TX_SSC_AMP_LEN 7
+#define GS2_TX_SSC_AMP_MASK (((1 << GS2_TX_SSC_AMP_LEN) - 1) << \
+ GS2_TX_SSC_AMP_OFF)
+#define GS2_VREG_RXTX_MAS_ISET_OFF 7
+#define GS2_VREG_RXTX_MAS_ISET_60U (0 << GS2_VREG_RXTX_MAS_ISET_OFF)
+#define GS2_VREG_RXTX_MAS_ISET_80U (1 << GS2_VREG_RXTX_MAS_ISET_OFF)
+#define GS2_VREG_RXTX_MAS_ISET_100U (2 << GS2_VREG_RXTX_MAS_ISET_OFF)
+#define GS2_VREG_RXTX_MAS_ISET_120U (3 << GS2_VREG_RXTX_MAS_ISET_OFF)
+#define GS2_VREG_RXTX_MAS_ISET_MASK (BIT(7) | BIT(8))
+#define GS2_RSVD_6_0_OFF 0
+#define GS2_RSVD_6_0_LEN 7
+#define GS2_RSVD_6_0_MASK (((1 << GS2_RSVD_6_0_LEN) - 1) << \
+ GS2_RSVD_6_0_OFF)
+
+#define COMPHY_GEN3_SET2 0x3f
+#define GEN3_SET2_ADDR(unit) (COMPHY_GEN3_SET2 * PHY_SHFT(unit))
+
+#define COMPHY_IDLE_SYNC_EN 0x48
+#define IDLE_SYNC_EN_ADDR(unit) (COMPHY_IDLE_SYNC_EN * PHY_SHFT(unit))
+#define IDLE_SYNC_EN BIT(12)
+#define IDLE_SYNC_EN_DEFAULT_VALUE 0x60
+
+#define COMPHY_MISC_CTRL0 0x4F
+#define MISC_CTRL0_ADDR(unit) (COMPHY_MISC_CTRL0 * PHY_SHFT(unit))
+#define CLK100M_125M_EN BIT(4)
+#define TXDCLK_2X_SEL BIT(6)
+#define CLK500M_EN BIT(7)
+#define PHY_REF_CLK_SEL BIT(10)
+#define MISC_CTRL0_DEFAULT_VALUE 0xA00D
+
+#define COMPHY_MISC_CTRL1 0x73
+#define MISC_CTRL1_ADDR(unit) (COMPHY_MISC_CTRL1 * PHY_SHFT(unit))
+#define SEL_BITS_PCIE_FORCE BIT(15)
+
+#define COMPHY_GEN2_SET3 0x112
+#define GS3_FFE_CAP_SEL_MASK 0xF
+#define GS3_FFE_CAP_SEL_VALUE 0xF
+
+#define COMPHY_LANE_CFG0 0x180
+#define LANE_CFG0_ADDR(unit) (COMPHY_LANE_CFG0 * 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_LANE_CFG1 0x181
+#define LANE_CFG1_ADDR(unit) (COMPHY_LANE_CFG1 * 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_LANE_STAT1 0x183
+#define LANE_STAT1_ADDR(unit) (COMPHY_LANE_STAT1 * PHY_SHFT(unit))
+#define TXDCLK_PCLK_EN BIT(0)
+
+#define COMPHY_LANE_CFG4 0x188
+#define LANE_CFG4_ADDR(unit) (COMPHY_LANE_CFG4 * PHY_SHFT(unit))
+#define SPREAD_SPECTRUM_CLK_EN BIT(7)
+
+#define COMPHY_RST_CLK_CTRL 0x1C1
+#define RST_CLK_CTRL_ADDR(unit) (COMPHY_RST_CLK_CTRL * PHY_SHFT(unit))
+#define SOFT_RESET BIT(0)
+#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_TEST_MODE_CTRL 0x1C2
+#define TEST_MODE_CTRL_ADDR(unit) (COMPHY_TEST_MODE_CTRL * PHY_SHFT(unit))
+#define MODE_MARGIN_OVERRIDE BIT(2)
+
+#define COMPHY_CLK_SRC_LO 0x1C3
+#define CLK_SRC_LO_ADDR(unit) (COMPHY_CLK_SRC_LO * PHY_SHFT(unit))
+#define MODE_CLK_SRC BIT(0)
+#define BUNDLE_PERIOD_SEL BIT(1)
+#define BUNDLE_PERIOD_SCALE_MASK (BIT(2) | BIT(3))
+#define BUNDLE_SAMPLE_CTRL BIT(4)
+#define PLL_READY_DLY_MASK (BIT(5) | BIT(6) | BIT(7))
+#define CFG_SEL_20B BIT(15)
+
+#define COMPHY_PWR_MGM_TIM1 0x1D0
+#define PWR_MGM_TIM1_ADDR(unit) (COMPHY_PWR_MGM_TIM1 * 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)
+
+/*
+ * This register is not from PHY lane register space. It only exists in the
+ * indirect register space, before the actual PHY lane 2 registers. So the
+ * offset is absolute, not relative to SATAPHY_LANE2_REG_BASE_OFFSET.
+ * It is used only for SATA PHY initialization.
+ */
+#define COMPHY_RESERVED_REG 0x0E
+#define PHYCTRL_FRM_PIN_BIT BIT(13)
+
+/* SGMII */
+#define COMPHY_PHY_CFG1_OFFSET(lane) ((1 - (lane)) * 0x28)
+#define PIN_PU_IVREF_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_3_125_G 0x8
+
+/* COMPHY status reg:
+ * lane0: USB3/GbE1 PHY Status 1
+ * lane1: PCIe/GbE0 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 */
diff --git a/drivers/marvell/comphy/phy-comphy-common.h b/drivers/marvell/comphy/phy-comphy-common.h
new file mode 100644
index 0000000..ba5d255
--- /dev/null
+++ b/drivers/marvell/comphy/phy-comphy-common.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2018-2021 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_2500BASEX_MODE 0x3 /* 2500Base-X */
+#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("<atf>: 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 & mask);
+
+ 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("<atf>: 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 & mask);
+
+ debug("new val 0x%x\n", mmio_read_16(addr));
+}
+
+#endif /* PHY_COMPHY_COMMON_H */
diff --git a/drivers/marvell/comphy/phy-comphy-cp110.c b/drivers/marvell/comphy/phy-comphy-cp110.c
new file mode 100644
index 0000000..fa9fe41
--- /dev/null
+++ b/drivers/marvell/comphy/phy-comphy-cp110.c
@@ -0,0 +1,2528 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* Marvell CP110 SoC COMPHY unit driver */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <mg_conf_cm3/mg_conf_cm3.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+
+#include <mvebu_def.h>
+#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 /* 2500Base-X */
+#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_CP0_OFFSET (30)
+#define SAR_RST_PCIE0_CLOCK_CONFIG_CP0_MASK (0x1UL << \
+ SAR_RST_PCIE0_CLOCK_CONFIG_CP0_OFFSET)
+#define SAR_RST_PCIE1_CLOCK_CONFIG_CP0_OFFSET (31)
+#define SAR_RST_PCIE1_CLOCK_CONFIG_CP0_MASK (0x1UL << \
+ SAR_RST_PCIE1_CLOCK_CONFIG_CP0_OFFSET)
+#define SAR_STATUS_0_REG 0x40600
+#define DFX_FROM_COMPHY_ADDR(x) ((x & ~0xffffff) + DFX_BASE)
+/* Common Phy training */
+#define COMPHY_TRX_TRAIN_COMPHY_OFFS 0x1000
+#define COMPHY_TRX_TRAIN_RX_TRAIN_ENABLE 0x1
+#define COMPHY_TRX_RELATIVE_ADDR(comphy_index) (comphy_train_base + \
+ (comphy_index) * COMPHY_TRX_TRAIN_COMPHY_OFFS)
+
+/* 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%" PRIx64 ", 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/Base-X 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/Base-X Port1, XFI1/SFI1
+ * 0x2 = SGMII/Base-X Port0: XFI0/SFI0, RXAUI_Lane0
+ *
+ * We want to check if 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 too.
+ */
+ /* TODO: need to distinguish between CP110 and CP115
+ * as SFI1/XFI1 available only for CP115.
+ */
+ if ((mode == COMPHY_SGMII_MODE ||
+ mode == COMPHY_2500BASEX_MODE ||
+ mode == COMPHY_SFI_MODE ||
+ mode == COMPHY_XFI_MODE ||
+ mode == COMPHY_AP_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/Base-X 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 void mvebu_cp110_polarity_invert(uintptr_t addr, uint8_t phy_polarity_invert)
+{
+ uint32_t mask, data;
+
+ /* Set RX / TX polarity */
+ data = mask = 0x0U;
+ if ((phy_polarity_invert & COMPHY_POLARITY_TXD_INVERT) != 0) {
+ data |= (1 << HPIPE_SYNC_PATTERN_TXD_INV_OFFSET);
+ mask |= HPIPE_SYNC_PATTERN_TXD_INV_MASK;
+ debug("%s: inverting TX polarity\n", __func__);
+ }
+
+ if ((phy_polarity_invert & COMPHY_POLARITY_RXD_INVERT) != 0) {
+ data |= (1 << HPIPE_SYNC_PATTERN_RXD_INV_OFFSET);
+ mask |= HPIPE_SYNC_PATTERN_RXD_INV_MASK;
+ debug("%s: inverting RX polarity\n", __func__);
+ }
+
+ reg_set(addr, data, mask);
+}
+
+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, phy_polarity_invert;
+ 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];
+
+ phy_polarity_invert = sata_static_values->polarity_invert;
+
+ /* 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);
+
+ if (phy_polarity_invert != 0)
+ mvebu_cp110_polarity_invert(hpipe_addr + HPIPE_SYNC_PATTERN_REG,
+ phy_polarity_invert);
+
+ /* 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) {
+ /* 2500Base-X, 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,
+ uint64_t comphy_train_base)
+{
+ 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;
+ mask |= SD_EXTERNAL_CONFIG1_TX_IDLE_MASK;
+ data |= 0x1 << SD_EXTERNAL_CONFIG1_TX_IDLE_OFFSET;
+ reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+ /* Wait 1ms - until band gap and ref clock ready */
+ mdelay(1);
+
+ /*
+ * Erratum IPCE_COMPHY-1353: toggle TX_IDLE bit in
+ * addition to the PHY reset
+ */
+ mask = SD_EXTERNAL_CONFIG1_TX_IDLE_MASK;
+ data = 0x0U;
+ reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+ /* 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);
+
+ /* Force rx training on 10G port */
+ data = mmio_read_32(COMPHY_TRX_RELATIVE_ADDR(comphy_index));
+ data |= COMPHY_TRX_TRAIN_RX_TRAIN_ENABLE;
+ mmio_write_32(COMPHY_TRX_RELATIVE_ADDR(comphy_index), data);
+ mdelay(200);
+ data &= ~COMPHY_TRX_TRAIN_RX_TRAIN_ENABLE;
+ mmio_write_32(COMPHY_TRX_RELATIVE_ADDR(comphy_index), data);
+
+ 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_CP0_MASK) >>
+ SAR_RST_PCIE1_CLOCK_CONFIG_CP0_OFFSET;
+ else
+ clk_dir = (reg & SAR_RST_PCIE0_CLOCK_CONFIG_CP0_MASK) >>
+ SAR_RST_PCIE0_CLOCK_CONFIG_CP0_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;
+ data = polling_with_timeout(addr, data, mask,
+ PLL_LOCK_TIMEOUT,
+ REG_32BIT);
+ if (data) {
+ ERROR("Failed to lock PCIE PLL\n");
+ ret = -ETIMEDOUT;
+ }
+ }
+ }
+
+ 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;
+ uint8_t ap_nr, cp_nr, phy_polarity_invert;
+ int ret = 0;
+
+ debug_enter();
+
+ /* Configure PIPE selector for USB3 */
+ mvebu_cp110_comphy_set_pipe_selector(comphy_base, comphy_index,
+ comphy_mode);
+
+ mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base);
+
+ const struct usb_params *usb_static_values =
+ &usb_static_values_tab[ap_nr][cp_nr][comphy_index];
+
+ phy_polarity_invert = usb_static_values->polarity_invert;
+
+ 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);
+
+ /* The polarity inversion for USB was not tested due to lack of hw
+ * design which requires it. Support is added for customer needs.
+ */
+ if (phy_polarity_invert)
+ mvebu_cp110_polarity_invert(hpipe_addr + HPIPE_SYNC_PATTERN_REG,
+ phy_polarity_invert);
+
+ /* 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;
+}
+
+static void rx_pre_train(uint64_t comphy_base, uint8_t comphy_index)
+{
+ uintptr_t hpipe_addr;
+ uint32_t mask, data;
+
+ hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+ comphy_index);
+
+ debug("rx_training preparation\n\n");
+
+ mask = HPIPE_TRX0_GAIN_TRAIN_WITH_C_MASK;
+ data = (0x1 << HPIPE_TRX0_GAIN_TRAIN_WITH_C_OFF);
+ mask |= HPIPE_TRX0_GAIN_TRAIN_WITH_SAMPLER_MASK;
+ data |= (0x0 << HPIPE_TRX0_GAIN_TRAIN_WITH_SAMPLER_OFF);
+ reg_set(hpipe_addr + HPIPE_TRX0_REG, data, mask);
+
+
+ mask = HPIPE_TRX_REG2_SUMF_BOOST_TARGET_C_MASK;
+ data = (0x1e << HPIPE_TRX_REG2_SUMF_BOOST_TARGET_C_OFF);
+ mask |= HPIPE_TRX_REG2_SUMF_BOOST_TARGET_K_MASK;
+ data |= (0x0 << HPIPE_TRX_REG2_SUMF_BOOST_TARGET_K_OFF);
+ reg_set(hpipe_addr + HPIPE_TRX_REG2, data, mask);
+
+ mask = HPIPE_TRX_REG1_MIN_BOOST_MODE_MASK;
+ data = (0x1 << HPIPE_TRX_REG1_MIN_BOOST_MODE_OFF);
+ reg_set(hpipe_addr + HPIPE_TRX_REG1, data, mask);
+
+ mask = HPIPE_CRD2_CRD_MIDPOINT_SMALL_THRES_K_MASK;
+ data = (0x8 << HPIPE_CRD2_CRD_MIDPOINT_SMALL_THRES_K_OFF);
+ reg_set(hpipe_addr + HPIPE_CDR_CONTROL1_REG, data, mask);
+
+ mask = HPIPE_CRD2_CRD_MIDPOINT_LARGE_THRES_K_MASK;
+ data = (0x8 << HPIPE_CRD2_CRD_MIDPOINT_LARGE_THRES_K_OFF);
+ reg_set(hpipe_addr + HPIPE_CDR_CONTROL2_REG, data, mask);
+
+ mask = HPIPE_CRD_MIDPOINT_PHASE_OS_MASK;
+ data = (0x0 << HPIPE_CRD_MIDPOINT_PHASE_OS_OFFSET);
+ reg_set(hpipe_addr + HPIPE_CDR_CONTROL_REG, data, mask);
+
+ mask = HPIPE_TRX_REG1_SUMFTAP_EN_MASK;
+ data = (0x38 << HPIPE_TRX_REG1_SUMFTAP_EN_OFF);
+ mask |= HPIPE_TRX_REG2_SUMF_BOOST_TARGET_C_MASK;
+ data |= (0x1e << HPIPE_TRX_REG2_SUMF_BOOST_TARGET_C_OFF);
+ reg_set(hpipe_addr + HPIPE_TRX_REG1, data, mask);
+}
+
+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;
+
+ 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);
+
+ debug_enter();
+
+ rx_pre_train(comphy_base, comphy_index);
+
+ 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("Enable RX training\n\n");
+
+ mask = HPIPE_TRX_RX_TRAIN_EN_MASK;
+ data = 0x1 << HPIPE_TRX_RX_TRAIN_EN_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);
+
+ /* Force DFE resolution (use gen table value) */
+ mask = HPIPE_DFE_RES_FORCE_MASK;
+ data = 0x1 << 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);
+
+ printf("########################################################\n");
+ printf("# To use trained values update the ATF sources:\n");
+ printf("# plat/marvell/armada/a8k/<board_type>/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");
+
+ 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<n> 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 comphy_mode)
+{
+ uint32_t mask, data;
+ uintptr_t comphy_addr = 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_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();
+
+#if MSS_SUPPORT
+ do {
+ uint8_t ap_nr, cp_nr;
+
+ /* start ap fw */
+ mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base);
+ mg_start_ap_fw(cp_nr, comphy_index);
+
+ } while (0);
+#endif
+ 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_2500BASEX_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,
+ uint64_t comphy_train_base)
+{
+ 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_2500BASEX_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,
+ comphy_train_base);
+ 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,
+ comphy_mode);
+ 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;
+}
diff --git a/drivers/marvell/comphy/phy-comphy-cp110.h b/drivers/marvell/comphy/phy-comphy-cp110.h
new file mode 100644
index 0000000..0be6c26
--- /dev/null
+++ b/drivers/marvell/comphy/phy-comphy-cp110.h
@@ -0,0 +1,102 @@
+/*
+ * 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/armada/a8k/<board_type>/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;
+
+ uint8_t polarity_invert;
+
+ _Bool valid;
+};
+
+struct usb_params {
+ uint8_t polarity_invert;
+};
+
+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,
+ uint64_t comphy_train_base);
+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);
+
+#define COMPHY_POLARITY_NO_INVERT 0
+#define COMPHY_POLARITY_TXD_INVERT 1
+#define COMPHY_POLARITY_RXD_INVERT 2
diff --git a/drivers/marvell/comphy/phy-default-porting-layer.h b/drivers/marvell/comphy/phy-default-porting-layer.h
new file mode 100644
index 0000000..3c63c64
--- /dev/null
+++ b/drivers/marvell/comphy/phy-default-porting-layer.h
@@ -0,0 +1,59 @@
+/*
+ * 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,
+ .polarity_invert = COMPHY_POLARITY_NO_INVERT,
+ .valid = 0x1
+ },
+};
+
+static const struct usb_params
+ usb_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
+ [0 ... AP_NUM-1][0 ... CP_NUM-1][0 ... MAX_LANE_NR-1] = {
+ .polarity_invert = COMPHY_POLARITY_NO_INVERT
+ },
+};
+#endif /* PHY_DEFAULT_PORTING_LAYER_H */
diff --git a/drivers/marvell/ddr_phy_access.c b/drivers/marvell/ddr_phy_access.c
new file mode 100644
index 0000000..352d1ef
--- /dev/null
+++ b/drivers/marvell/ddr_phy_access.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include "ddr_phy_access.h"
+#include <lib/mmio.h>
+#include <drivers/marvell/ccu.h>
+#include <errno.h>
+
+#define DDR_PHY_END_ADDRESS 0x100000
+
+#ifdef DDR_PHY_DEBUG
+#define debug_printf(...) printf(__VA_ARGS__)
+#else
+#define debug_printf(...)
+#endif
+
+
+/*
+ * This routine writes 'data' to specified 'address' offset,
+ * with optional debug print support
+ */
+int snps_fw_write(uintptr_t offset, uint16_t data)
+{
+ debug_printf("In %s\n", __func__);
+
+ if (offset < DDR_PHY_END_ADDRESS) {
+ mmio_write_16(DDR_PHY_BASE_ADDR + (2 * offset), data);
+ return 0;
+ }
+ debug_printf("%s: illegal offset value: 0x%x\n", __func__, offset);
+ return -EINVAL;
+}
+
+int snps_fw_read(uintptr_t offset, uint16_t *read)
+{
+ debug_printf("In %s\n", __func__);
+
+ if (offset < DDR_PHY_END_ADDRESS) {
+ *read = mmio_read_16(DDR_PHY_BASE_ADDR + (2 * offset));
+ return 0;
+ }
+ debug_printf("%s: illegal offset value: 0x%x\n", __func__, offset);
+ return -EINVAL;
+}
+
+int mvebu_ddr_phy_write(uintptr_t offset, uint16_t data)
+{
+ return snps_fw_write(offset, data);
+}
+
+int mvebu_ddr_phy_read(uintptr_t offset, uint16_t *read)
+{
+ return snps_fw_read(offset, read);
+}
diff --git a/drivers/marvell/ddr_phy_access.h b/drivers/marvell/ddr_phy_access.h
new file mode 100644
index 0000000..5f9a668
--- /dev/null
+++ b/drivers/marvell/ddr_phy_access.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2021 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <plat_marvell.h>
+
+#define DEVICE_BASE 0xF0000000
+#define DDR_PHY_OFFSET 0x1000000
+#define DDR_PHY_BASE_ADDR (DEVICE_BASE + DDR_PHY_OFFSET)
+
+int mvebu_ddr_phy_write(uintptr_t offset, uint16_t data);
+int mvebu_ddr_phy_read(uintptr_t offset, uint16_t *read);
diff --git a/drivers/marvell/gwin.c b/drivers/marvell/gwin.c
new file mode 100644
index 0000000..fa59cb0
--- /dev/null
+++ b/drivers/marvell/gwin.c
@@ -0,0 +1,231 @@
+/*
+ * 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 <inttypes.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <drivers/marvell/gwin.h>
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+#include <mvebu.h>
+#include <mvebu_def.h>
+
+#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%" PRIx64 "\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%" PRIx64 "\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%016" PRIx64 " 0x%016" PRIx64 "\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;
+}
diff --git a/drivers/marvell/io_win.c b/drivers/marvell/io_win.c
new file mode 100644
index 0000000..124382a
--- /dev/null
+++ b/drivers/marvell/io_win.c
@@ -0,0 +1,271 @@
+/*
+ * 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 <inttypes.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <drivers/marvell/io_win.h>
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+#include <mvebu.h>
+#include <mvebu_def.h>
+
+#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%" PRIx64 "\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%" PRIx64 "\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%016" PRIx64 " 0x%016" PRIx64 "\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;
+}
diff --git a/drivers/marvell/iob.c b/drivers/marvell/iob.c
new file mode 100644
index 0000000..1f39395
--- /dev/null
+++ b/drivers/marvell/iob.c
@@ -0,0 +1,214 @@
+/*
+ * 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 <inttypes.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/marvell/iob.h>
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+#include <mvebu.h>
+#include <mvebu_def.h>
+
+#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))
+
+#define IOB_WIN_DIOB_CR_OFFSET(win) (iob_base + 0x10 + (0x20 * win))
+#define IOB_WIN_XOR0_DIOB_EN BIT(0)
+#define IOB_WIN_XOR1_DIOB_EN BIT(1)
+
+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%" PRIx64 "\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%" PRIx64 "\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;
+ uint32_t reg_en;
+
+ /* move XOR (DMA) to use WIN1 which is used for PCI-EP address space */
+ reg_en = IOB_WIN_XOR0_DIOB_EN | IOB_WIN_XOR1_DIOB_EN;
+ iob_win_reg = mmio_read_32(IOB_WIN_DIOB_CR_OFFSET(0));
+ iob_win_reg &= ~reg_en;
+ mmio_write_32(IOB_WIN_DIOB_CR_OFFSET(0), iob_win_reg);
+
+ iob_win_reg = mmio_read_32(IOB_WIN_DIOB_CR_OFFSET(1));
+ iob_win_reg |= reg_en;
+ mmio_write_32(IOB_WIN_DIOB_CR_OFFSET(1), iob_win_reg);
+
+ 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%016" PRIx64 " 0x%016" PRIx64 "\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;
+}
diff --git a/drivers/marvell/mc_trustzone/mc_trustzone.c b/drivers/marvell/mc_trustzone/mc_trustzone.c
new file mode 100644
index 0000000..648bd0e
--- /dev/null
+++ b/drivers/marvell/mc_trustzone/mc_trustzone.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <inttypes.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <drivers/marvell/addr_map.h>
+#include <lib/mmio.h>
+
+#include <mvebu_def.h>
+
+#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%" PRIx64 " 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%" PRIx64 ", 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)));
+}
diff --git a/drivers/marvell/mc_trustzone/mc_trustzone.h b/drivers/marvell/mc_trustzone/mc_trustzone.h
new file mode 100644
index 0000000..296dce8
--- /dev/null
+++ b/drivers/marvell/mc_trustzone/mc_trustzone.h
@@ -0,0 +1,27 @@
+/*
+ * 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 <drivers/marvell/addr_map.h>
+
+#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 */
diff --git a/drivers/marvell/mci.c b/drivers/marvell/mci.c
new file mode 100644
index 0000000..2b54700
--- /dev/null
+++ b/drivers/marvell/mci.c
@@ -0,0 +1,834 @@
+/*
+ * 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 <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/marvell/mci.h>
+#include <lib/mmio.h>
+
+#include <mvebu.h>
+#include <mvebu_def.h>
+#include <plat_marvell.h>
+
+/* /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(mci_index),
+ 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(mci_index),
+ 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(mci_index),
+ MCI_HB_CTRL_WIN0_DEST_VALID_FLAG(1) |
+ MCI_HB_CTRL_WIN0_DEST_ID(3));
+ mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+ 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(mci_index),
+ MCI_HB_CTRL_WIN0_DEST_VALID_FLAG(1) |
+ MCI_HB_CTRL_WIN0_DEST_ID(1));
+ mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+ 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(mci_index), 0xffffffff);
+ mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+ 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(mci_index), 0xffffffff);
+ mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+ 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(mci_index),
+ 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 for mci%d\n",
+ mci_index);
+ /* 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_link_tune(int mci_index)
+{
+ int ret;
+
+ debug_enter();
+ INFO("MCI%d initialization:\n", mci_index);
+
+ ret = mci_configure(mci_index);
+
+ debug_exit();
+ return ret;
+}
diff --git a/drivers/marvell/mg_conf_cm3/mg_conf_cm3.c b/drivers/marvell/mg_conf_cm3/mg_conf_cm3.c
new file mode 100644
index 0000000..98e1896
--- /dev/null
+++ b/drivers/marvell/mg_conf_cm3/mg_conf_cm3.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2019 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <a8k_plat_def.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mss_scp_bl2_format.h>
+
+/* CONFI REGISTERS */
+#define MG_CM3_CONFI_BASE(CP) (MVEBU_CP_REGS_BASE(CP) + 0x100000)
+#define MG_CM3_SRAM_BASE(CP) MG_CM3_CONFI_BASE(CP)
+#define MG_CM3_CONFI_GLOB_CFG_REG(CP) (MG_CM3_CONFI_BASE(CP) + 0x2B500)
+#define CM3_CPU_EN_BIT BIT(28)
+#define MG_CM3_MG_INT_MFX_REG(CP) (MG_CM3_CONFI_BASE(CP) + 0x2B054)
+#define CM3_SYS_RESET_BIT BIT(0)
+
+#define MG_CM3_SHARED_MEM_BASE(CP) (MG_CM3_SRAM_BASE(CP) + 0x1FC00ULL)
+
+#define MG_SRAM_SIZE 0x20000 /* 128KB */
+
+#define MG_ACK_TIMEOUT 10
+
+/**
+ * struct ap_sharedmem_ctrl - used to pass information between the HOST and CM3
+ * @init_done: Set by CM3 when ap_proces initialzied. Host check if CM3 set
+ * this flag to confirm that the process is running
+ * @lane_nr: Set by Host to mark which comphy lane should be configure. E.g.:
+ * - A8K development board uses comphy lane 2 for eth0
+ * - CN913x development board uses comphy lane 4 for eth0
+ */
+struct ap_sharedmem_ctrl {
+ uint32_t init_done;
+ uint32_t lane_nr;
+};
+
+int mg_image_load(uintptr_t src_addr, uint32_t size, int cp_index)
+{
+ uintptr_t mg_regs = MG_CM3_SRAM_BASE(cp_index);
+
+ if (size > MG_SRAM_SIZE) {
+ ERROR("image is too big to fit into MG CM3 memory\n");
+ return 1;
+ }
+
+ NOTICE("Loading MG image from address 0x%lx Size 0x%x to MG at 0x%lx\n",
+ src_addr, size, mg_regs);
+
+ /* Copy image to MG CM3 SRAM */
+ memcpy((void *)mg_regs, (void *)src_addr, size);
+
+ /* Don't release MG CM3 from reset - it will be done by next step
+ * bootloader (e.g. U-Boot), when appriopriate device-tree setup (which
+ * has enabeld 802.3. auto-neg) will be choosen.
+ */
+
+ return 0;
+}
+
+void mg_start_ap_fw(int cp_nr, uint8_t comphy_index)
+{
+ volatile struct ap_sharedmem_ctrl *ap_shared_ctrl =
+ (void *)MG_CM3_SHARED_MEM_BASE(cp_nr);
+ int timeout = MG_ACK_TIMEOUT;
+
+ if (mmio_read_32(MG_CM3_CONFI_GLOB_CFG_REG(cp_nr)) & CM3_CPU_EN_BIT) {
+ VERBOSE("cm3 already running\n");
+ return; /* cm3 already running */
+ }
+
+ /*
+ * Mark which comphy lane should be used - it will be read via shared
+ * mem by ap process
+ */
+ ap_shared_ctrl->lane_nr = comphy_index;
+ /* Make sure it took place before enabling cm3 */
+ dmbst();
+
+ mmio_setbits_32(MG_CM3_CONFI_GLOB_CFG_REG(cp_nr), CM3_CPU_EN_BIT);
+ mmio_setbits_32(MG_CM3_MG_INT_MFX_REG(cp_nr), CM3_SYS_RESET_BIT);
+
+ /* Check for ap process initialization by fw */
+ while (ap_shared_ctrl->init_done != 1 && timeout--)
+ VERBOSE("Waiting for ap process ack, timeout %d\n", timeout);
+
+ if (timeout == 0) {
+ ERROR("AP process failed, disabling cm3\n");
+ mmio_clrbits_32(MG_CM3_MG_INT_MFX_REG(cp_nr),
+ CM3_SYS_RESET_BIT);
+ mmio_clrbits_32(MG_CM3_CONFI_GLOB_CFG_REG(cp_nr),
+ CM3_CPU_EN_BIT);
+ }
+}
diff --git a/drivers/marvell/mg_conf_cm3/mg_conf_cm3.h b/drivers/marvell/mg_conf_cm3/mg_conf_cm3.h
new file mode 100644
index 0000000..e2756de
--- /dev/null
+++ b/drivers/marvell/mg_conf_cm3/mg_conf_cm3.h
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2019 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+void mg_start_ap_fw(int cp_nr, uint8_t comphy_index);
+int mg_image_load(uintptr_t src_addr, uint32_t size, int cp_index);
diff --git a/drivers/marvell/mochi/ap807_setup.c b/drivers/marvell/mochi/ap807_setup.c
new file mode 100644
index 0000000..75e9654
--- /dev/null
+++ b/drivers/marvell/mochi/ap807_setup.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* AP807 Marvell SoC driver */
+
+#include <common/debug.h>
+#include <drivers/marvell/cache_llc.h>
+#include <drivers/marvell/ccu.h>
+#include <drivers/marvell/io_win.h>
+#include <drivers/marvell/iob.h>
+#include <drivers/marvell/mci.h>
+#include <drivers/marvell/mochi/ap_setup.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include <a8k_plat_def.h>
+
+#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)
+
+
+/* SoC RFU / IHBx4 Control */
+#define MCIX4_807_REG_START_ADDR_REG(unit_id) (MVEBU_RFU_BASE + \
+ 0x4258 + (unit_id * 0x4))
+
+/* 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)
+#define MOCHI_IN_ACC_LEVEL_FORCE_NONSEC (0)
+#define MOCHI_IN_ACC_LEVEL_FORCE_SEC (1)
+#define MOCHI_IN_ACC_LEVEL_LEAVE_ORIG (2)
+#define MOCHI_IN_ACC_LEVEL_MASK_ALL (3)
+#define SEC_MOCHI_IN_ACC_IHB0_LEVEL(l) ((l) << 1)
+#define SEC_MOCHI_IN_ACC_IHB1_LEVEL(l) ((l) << 4)
+#define SEC_MOCHI_IN_ACC_PIDI_LEVEL(l) ((l) << 10)
+
+
+/* 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)
+
+#define XOR_STREAM_ID_REG(ch) (MVEBU_REGS_BASE + 0x410010 + (ch) * 0x20000)
+#define XOR_STREAM_ID_MASK 0xFFFF
+#define SDIO_STREAM_ID_REG (MVEBU_RFU_BASE + 0x4600)
+#define SDIO_STREAM_ID_MASK 0xFF
+
+/* Do not use the default Stream ID 0 */
+#define A807_STREAM_ID_BASE (0x1)
+
+static uintptr_t stream_id_reg[] = {
+ XOR_STREAM_ID_REG(0),
+ XOR_STREAM_ID_REG(1),
+ XOR_STREAM_ID_REG(2),
+ XOR_STREAM_ID_REG(3),
+ SDIO_STREAM_ID_REG,
+ 0
+};
+
+enum axi_attr {
+ AXI_SDIO_ATTR = 0,
+ AXI_DFX_ATTR,
+ AXI_MAX_ATTR,
+};
+
+static void ap_sec_masters_access_en(uint32_t enable)
+{
+ /* Open/Close incoming access for all masters.
+ * The access is disabled in trusted boot mode
+ * Could only be done in EL3
+ */
+ if (enable != 0) {
+ mmio_clrsetbits_32(SEC_MOCHI_IN_ACC_REG, 0x0U, /* no clear */
+ SEC_IN_ACCESS_ENA_ALL_MASTERS);
+#if LLC_SRAM
+ /* Do not change access security level
+ * for PIDI masters
+ */
+ mmio_clrsetbits_32(SEC_MOCHI_IN_ACC_REG,
+ SEC_MOCHI_IN_ACC_PIDI_LEVEL(
+ MOCHI_IN_ACC_LEVEL_MASK_ALL),
+ SEC_MOCHI_IN_ACC_PIDI_LEVEL(
+ MOCHI_IN_ACC_LEVEL_LEAVE_ORIG));
+#endif
+ } else {
+ mmio_clrsetbits_32(SEC_MOCHI_IN_ACC_REG,
+ SEC_IN_ACCESS_ENA_ALL_MASTERS,
+ 0x0U /* no set */);
+#if LLC_SRAM
+ /* Return PIDI access level to the default */
+ mmio_clrsetbits_32(SEC_MOCHI_IN_ACC_REG,
+ SEC_MOCHI_IN_ACC_PIDI_LEVEL(
+ MOCHI_IN_ACC_LEVEL_MASK_ALL),
+ SEC_MOCHI_IN_ACC_PIDI_LEVEL(
+ MOCHI_IN_ACC_LEVEL_FORCE_NONSEC));
+#endif
+ }
+}
+
+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 */
+
+ 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_807_REG_START_ADDR_REG(mci),
+ MVEBU_MCI_REG_BASE_REMAP(mci) >>
+ MCI_REMAP_OFF_SHIFT);
+}
+
+/* Set a unique stream id for all DMA capable devices */
+static void ap807_stream_id_init(void)
+{
+ uint32_t i;
+
+ for (i = 0;
+ stream_id_reg[i] != 0 && i < ARRAY_SIZE(stream_id_reg); i++) {
+ uint32_t mask = stream_id_reg[i] == SDIO_STREAM_ID_REG ?
+ SDIO_STREAM_ID_MASK : XOR_STREAM_ID_MASK;
+
+ mmio_clrsetbits_32(stream_id_reg[i], mask,
+ i + A807_STREAM_ID_BASE);
+ }
+}
+
+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);
+}
+
+/*
+ * By default all external CPs start with configuration address space set to
+ * 0xf200_0000. To overcome this issue, go in the loop and initialize the
+ * CP one by one, using temporary window configuration which allows to access
+ * each CP and update its configuration space according to decoding
+ * windows scheme defined for each platform.
+ */
+void update_cp110_default_win(int cp_id)
+{
+ int mci_id = cp_id - 1;
+ uintptr_t cp110_base, cp110_temp_base;
+
+ /* CP110 default configuration address space */
+ cp110_temp_base = MVEBU_AP_IO_BASE(MVEBU_AP0);
+
+ struct addr_map_win iowin_temp_win = {
+ .base_addr = cp110_temp_base,
+ .win_size = MVEBU_CP_OFFSET,
+ };
+
+ iowin_temp_win.target_id = mci_id;
+ iow_temp_win_insert(0, &iowin_temp_win, 1);
+
+ /* Calculate the new CP110 - base address */
+ cp110_base = MVEBU_CP_REGS_BASE(cp_id);
+ /* Go and update the CP110 configuration address space */
+ iob_cfg_space_update(0, cp_id, cp110_temp_base, cp110_base);
+
+ /* Remove the temporary IO-WIN window */
+ iow_temp_win_remove(0, &iowin_temp_win, 1);
+}
+
+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);
+
+ /* Set the stream IDs for DMA masters */
+ ap807_stream_id_init();
+
+ /* 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;
+}
+
+
diff --git a/drivers/marvell/mochi/apn806_setup.c b/drivers/marvell/mochi/apn806_setup.c
new file mode 100644
index 0000000..5c71fed
--- /dev/null
+++ b/drivers/marvell/mochi/apn806_setup.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* AP806 Marvell SoC driver */
+
+#include <common/debug.h>
+#include <drivers/marvell/ccu.h>
+#include <drivers/marvell/cache_llc.h>
+#include <drivers/marvell/io_win.h>
+#include <drivers/marvell/mci.h>
+#include <drivers/marvell/mochi/ap_setup.h>
+#include <lib/mmio.h>
+
+#include <a8k_plat_def.h>
+
+#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)
+#define MOCHI_IN_ACC_LEVEL_FORCE_NONSEC (0)
+#define MOCHI_IN_ACC_LEVEL_FORCE_SEC (1)
+#define MOCHI_IN_ACC_LEVEL_LEAVE_ORIG (2)
+#define MOCHI_IN_ACC_LEVEL_MASK_ALL (3)
+#define SEC_MOCHI_IN_ACC_IHB0_LEVEL(l) ((l) << 1)
+#define SEC_MOCHI_IN_ACC_IHB1_LEVEL(l) ((l) << 4)
+#define SEC_MOCHI_IN_ACC_PIDI_LEVEL(l) ((l) << 10)
+
+
+/* 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)
+
+#define XOR_STREAM_ID_REG(ch) (MVEBU_REGS_BASE + 0x410010 + (ch) * 0x20000)
+#define XOR_STREAM_ID_MASK 0xFFFF
+#define SDIO_STREAM_ID_REG (MVEBU_RFU_BASE + 0x4600)
+#define SDIO_STREAM_ID_MASK 0xFF
+
+/* Do not use the default Stream ID 0 */
+#define A806_STREAM_ID_BASE (0x1)
+
+static uintptr_t stream_id_reg[] = {
+ XOR_STREAM_ID_REG(0),
+ XOR_STREAM_ID_REG(1),
+ XOR_STREAM_ID_REG(2),
+ XOR_STREAM_ID_REG(3),
+ SDIO_STREAM_ID_REG,
+ 0
+};
+
+enum axi_attr {
+ AXI_SDIO_ATTR = 0,
+ AXI_DFX_ATTR,
+ AXI_MAX_ATTR,
+};
+
+static void apn_sec_masters_access_en(uint32_t enable)
+{
+ /* Open/Close incoming access for all masters.
+ * The access is disabled in trusted boot mode
+ * Could only be done in EL3
+ */
+ if (enable != 0) {
+ mmio_clrsetbits_32(SEC_MOCHI_IN_ACC_REG, 0x0U, /* no clear */
+ SEC_IN_ACCESS_ENA_ALL_MASTERS);
+#if LLC_SRAM
+ /* Do not change access security level
+ * for PIDI masters
+ */
+ mmio_clrsetbits_32(SEC_MOCHI_IN_ACC_REG,
+ SEC_MOCHI_IN_ACC_PIDI_LEVEL(
+ MOCHI_IN_ACC_LEVEL_MASK_ALL),
+ SEC_MOCHI_IN_ACC_PIDI_LEVEL(
+ MOCHI_IN_ACC_LEVEL_LEAVE_ORIG));
+#endif
+ } else {
+ mmio_clrsetbits_32(SEC_MOCHI_IN_ACC_REG,
+ SEC_IN_ACCESS_ENA_ALL_MASTERS,
+ 0x0U /* no set */);
+#if LLC_SRAM
+ /* Return PIDI access level to the default */
+ mmio_clrsetbits_32(SEC_MOCHI_IN_ACC_REG,
+ SEC_MOCHI_IN_ACC_PIDI_LEVEL(
+ MOCHI_IN_ACC_LEVEL_MASK_ALL),
+ SEC_MOCHI_IN_ACC_PIDI_LEVEL(
+ MOCHI_IN_ACC_LEVEL_FORCE_NONSEC));
+#endif
+ }
+}
+
+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 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 */
+
+ 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);
+}
+
+/* Set a unique stream id for all DMA capable devices */
+static void ap806_stream_id_init(void)
+{
+ int i;
+
+ for (i = 0; stream_id_reg[i] != 0; i++) {
+ uint32_t mask = stream_id_reg[i] == SDIO_STREAM_ID_REG ?
+ SDIO_STREAM_ID_MASK : XOR_STREAM_ID_MASK;
+
+ mmio_clrsetbits_32(stream_id_reg[i], mask,
+ i + A806_STREAM_ID_BASE);
+ }
+}
+
+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();
+
+ /* Set the stream IDs for DMA masters */
+ ap806_stream_id_init();
+
+ /* 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;
+}
+
+void update_cp110_default_win(int cp_id)
+{
+}
diff --git a/drivers/marvell/mochi/cp110_setup.c b/drivers/marvell/mochi/cp110_setup.c
new file mode 100644
index 0000000..f12da0e
--- /dev/null
+++ b/drivers/marvell/mochi/cp110_setup.c
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2018-2020 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* CP110 Marvell SoC driver */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/marvell/amb_adec.h>
+#include <drivers/marvell/iob.h>
+#include <drivers/marvell/mochi/cp110_setup.h>
+#include <drivers/rambus/trng_ip_76.h>
+
+#include <efuse_def.h>
+#include <plat_marvell.h>
+
+/*
+ * 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
+
+/*******************************************************************************
+ * TRNG Configuration
+ ******************************************************************************/
+#define MVEBU_TRNG_BASE (0x760000)
+#define MVEBU_EFUSE_TRNG_ENABLE_EFUSE_WORD MVEBU_AP_LDX_220_189_EFUSE_OFFS
+#define MVEBU_EFUSE_TRNG_ENABLE_BIT_OFFSET 13 /* LD0[202] */
+
+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 SDIO_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0x28)
+
+#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)
+
+static 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,
+ SDIO_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 or CN913x */
+ if (cp110_rev_id_get(base) == MVEBU_CP110_REF_ID_A2 ||
+ cp110_device_id_get(base) == MVEBU_CN9130_DEV_ID) {
+ /*
+ * 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);
+}
+
+void cp110_amb_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);
+}
+
+static void cp110_trng_init(uintptr_t base)
+{
+ static bool done;
+ int ret;
+ uint32_t reg_val, efuse;
+
+ /* Set access to LD0 */
+ reg_val = mmio_read_32(MVEBU_AP_EFUSE_SRV_CTRL_REG);
+ reg_val &= ~EFUSE_SRV_CTRL_LD_SELECT_MASK;
+ mmio_write_32(MVEBU_AP_EFUSE_SRV_CTRL_REG, reg_val);
+
+ /* Obtain the AP LD0 bit defining TRNG presence */
+ efuse = mmio_read_32(MVEBU_EFUSE_TRNG_ENABLE_EFUSE_WORD);
+ efuse >>= MVEBU_EFUSE_TRNG_ENABLE_BIT_OFFSET;
+ efuse &= 1;
+
+ if (efuse == 0) {
+ VERBOSE("TRNG is not present, skipping");
+ return;
+ }
+
+ if (!done) {
+ ret = eip76_rng_probe(base + MVEBU_TRNG_BASE);
+ if (ret != 0) {
+ ERROR("Failed to init TRNG @ 0x%lx\n", base);
+ return;
+ }
+ done = true;
+ }
+}
+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*/
+ cp110_amb_init(cp110_base);
+
+ /* Reset RTC if needed */
+ cp110_rtc_init(cp110_base);
+
+ /* TRNG init - for CP0 only */
+ cp110_trng_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);
+
+ cp110_amb_init(cp110_base);
+
+ /* Configure PCIe clock */
+ cp110_pcie_clk_cfg(cp110_base);
+
+ /* Configure PCIe endpoint */
+ ble_plat_pcie_ep_setup();
+#endif
+}
diff --git a/drivers/marvell/secure_dfx_access/armada_thermal.c b/drivers/marvell/secure_dfx_access/armada_thermal.c
new file mode 100644
index 0000000..4f7191b
--- /dev/null
+++ b/drivers/marvell/secure_dfx_access/armada_thermal.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2019 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <mvebu.h>
+#include <stdbool.h>
+#include "dfx.h"
+
+/* #define DEBUG_DFX */
+#ifdef DEBUG_DFX
+#define debug(format...) NOTICE(format)
+#else
+#define debug(format, arg...)
+#endif
+
+#define TSEN_CTRL0 0xf06f8084
+ #define TSEN_CTRL0_START BIT(0)
+ #define TSEN_CTRL0_RESET BIT(1)
+ #define TSEN_CTRL0_ENABLE BIT(2)
+ #define TSEN_CTRL0_AVG_BYPASS BIT(6)
+ #define TSEN_CTRL0_CHAN_SHIFT 13
+ #define TSEN_CTRL0_CHAN_MASK 0xF
+ #define TSEN_CTRL0_OSR_SHIFT 24
+ #define TSEN_CTRL0_OSR_MAX 0x3
+ #define TSEN_CTRL0_MODE_SHIFT 30
+ #define TSEN_CTRL0_MODE_EXTERNAL 0x2U
+ #define TSEN_CTRL0_MODE_MASK 0x3U
+
+#define TSEN_CTRL1 0xf06f8088
+ #define TSEN_CTRL1_INT_EN BIT(25)
+ #define TSEN_CTRL1_HYST_SHIFT 19
+ #define TSEN_CTRL1_HYST_MASK (0x3 << TSEN_CTRL1_HYST_SHIFT)
+ #define TSEN_CTRL1_THRESH_SHIFT 3
+ #define TSEN_CTRL1_THRESH_MASK (0x3ff << TSEN_CTRL1_THRESH_SHIFT)
+
+#define TSEN_STATUS 0xf06f808c
+ #define TSEN_STATUS_VALID_OFFSET 16
+ #define TSEN_STATUS_VALID_MASK (0x1 << TSEN_STATUS_VALID_OFFSET)
+ #define TSEN_STATUS_TEMP_OUT_OFFSET 0
+ #define TSEN_STATUS_TEMP_OUT_MASK (0x3FF << TSEN_STATUS_TEMP_OUT_OFFSET)
+
+#define DFX_SERVER_IRQ_SUM_MASK_REG 0xf06f8104
+ #define DFX_SERVER_IRQ_EN BIT(1)
+
+#define DFX_IRQ_CAUSE_REG 0xf06f8108
+
+#define DFX_IRQ_MASK_REG 0xf06f810c
+ #define DFX_IRQ_TSEN_OVERHEAT_OFFSET BIT(22)
+
+#define THERMAL_SEN_OUTPUT_MSB 512
+#define THERMAL_SEN_OUTPUT_COMP 1024
+
+#define COEF_M 423
+#define COEF_B -150000LL
+
+static void armada_ap806_thermal_read(u_register_t *temp)
+{
+ uint32_t reg;
+
+ reg = mmio_read_32(TSEN_STATUS);
+
+ reg = ((reg & TSEN_STATUS_TEMP_OUT_MASK) >>
+ TSEN_STATUS_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;
+
+ *temp = ((COEF_M * ((signed int)reg)) - COEF_B);
+}
+
+static void armada_ap806_thermal_irq(void)
+{
+ /* Dummy read, register ROC */
+ mmio_read_32(DFX_IRQ_CAUSE_REG);
+}
+
+static void armada_ap806_thermal_overheat_irq_init(void)
+{
+ uint32_t reg;
+
+ /* Clear DFX temperature IRQ cause */
+ reg = mmio_read_32(DFX_IRQ_CAUSE_REG);
+
+ /* Enable DFX Temperature IRQ */
+ reg = mmio_read_32(DFX_IRQ_MASK_REG);
+ reg |= DFX_IRQ_TSEN_OVERHEAT_OFFSET;
+ mmio_write_32(DFX_IRQ_MASK_REG, reg);
+
+ /* Enable DFX server IRQ */
+ reg = mmio_read_32(DFX_SERVER_IRQ_SUM_MASK_REG);
+ reg |= DFX_SERVER_IRQ_EN;
+ mmio_write_32(DFX_SERVER_IRQ_SUM_MASK_REG, reg);
+
+ /* Enable overheat interrupt */
+ reg = mmio_read_32(TSEN_CTRL1);
+ reg |= TSEN_CTRL1_INT_EN;
+ mmio_write_32(TSEN_CTRL1, reg);
+}
+
+static unsigned int armada_mc_to_reg_temp(unsigned int temp_mc)
+{
+ unsigned int sample;
+
+ sample = (temp_mc + COEF_B) / COEF_M;
+
+ return sample & 0x3ff;
+}
+
+/*
+ * The documentation states:
+ * high/low watermark = threshold +/- 0.4761 * 2^(hysteresis + 2)
+ * which is the mathematical derivation for:
+ * 0x0 <=> 1.9°C, 0x1 <=> 3.8°C, 0x2 <=> 7.6°C, 0x3 <=> 15.2°C
+ */
+static unsigned int hyst_levels_mc[] = {1900, 3800, 7600, 15200};
+
+static unsigned int armada_mc_to_reg_hyst(int hyst_mc)
+{
+ int i;
+
+ /*
+ * We will always take the smallest possible hysteresis to avoid risking
+ * the hardware integrity by enlarging the threshold by +8°C in the
+ * worst case.
+ */
+ for (i = ARRAY_SIZE(hyst_levels_mc) - 1; i > 0; i--)
+ if (hyst_mc >= hyst_levels_mc[i])
+ break;
+
+ return i;
+}
+
+static void armada_ap806_thermal_threshold(int thresh_mc, int hyst_mc)
+{
+ uint32_t ctrl1;
+ unsigned int threshold = armada_mc_to_reg_temp(thresh_mc);
+ unsigned int hysteresis = armada_mc_to_reg_hyst(hyst_mc);
+
+ ctrl1 = mmio_read_32(TSEN_CTRL1);
+ /* Set Threshold */
+ if (thresh_mc >= 0) {
+ ctrl1 &= ~(TSEN_CTRL1_THRESH_MASK);
+ ctrl1 |= threshold << TSEN_CTRL1_THRESH_SHIFT;
+ }
+
+ /* Set Hysteresis */
+ if (hyst_mc >= 0) {
+ ctrl1 &= ~(TSEN_CTRL1_HYST_MASK);
+ ctrl1 |= hysteresis << TSEN_CTRL1_HYST_SHIFT;
+ }
+
+ mmio_write_32(TSEN_CTRL1, ctrl1);
+}
+
+static void armada_select_channel(int channel)
+{
+ uint32_t ctrl0;
+
+ /* Stop the measurements */
+ ctrl0 = mmio_read_32(TSEN_CTRL0);
+ ctrl0 &= ~TSEN_CTRL0_START;
+ mmio_write_32(TSEN_CTRL0, ctrl0);
+
+ /* Reset the mode, internal sensor will be automatically selected */
+ ctrl0 &= ~(TSEN_CTRL0_MODE_MASK << TSEN_CTRL0_MODE_SHIFT);
+
+ /* Other channels are external and should be selected accordingly */
+ if (channel) {
+ /* Change the mode to external */
+ ctrl0 |= TSEN_CTRL0_MODE_EXTERNAL <<
+ TSEN_CTRL0_MODE_SHIFT;
+ /* Select the sensor */
+ ctrl0 &= ~(TSEN_CTRL0_CHAN_MASK << TSEN_CTRL0_CHAN_SHIFT);
+ ctrl0 |= (channel - 1) << TSEN_CTRL0_CHAN_SHIFT;
+ }
+
+ /* Actually set the mode/channel */
+ mmio_write_32(TSEN_CTRL0, ctrl0);
+
+ /* Re-start the measurements */
+ ctrl0 |= TSEN_CTRL0_START;
+ mmio_write_32(TSEN_CTRL0, ctrl0);
+}
+
+static void armada_ap806_thermal_init(void)
+{
+ uint32_t reg;
+
+ reg = mmio_read_32(TSEN_CTRL0);
+ reg &= ~TSEN_CTRL0_RESET;
+ reg |= TSEN_CTRL0_START | TSEN_CTRL0_ENABLE;
+
+ /* Sample every ~2ms */
+ reg |= TSEN_CTRL0_OSR_MAX << TSEN_CTRL0_OSR_SHIFT;
+
+ /* Enable average (2 samples by default) */
+ reg &= ~TSEN_CTRL0_AVG_BYPASS;
+
+ mmio_write_32(TSEN_CTRL0, reg);
+
+ debug("thermal: Initialization done\n");
+}
+
+static void armada_is_valid(u_register_t *read)
+{
+ *read = (mmio_read_32(TSEN_STATUS) & TSEN_STATUS_VALID_MASK);
+}
+
+int mvebu_dfx_thermal_handle(u_register_t func, u_register_t *read,
+ u_register_t x2, u_register_t x3)
+{
+ debug_enter();
+
+ switch (func) {
+ case MV_SIP_DFX_THERMAL_INIT:
+ armada_ap806_thermal_init();
+ break;
+ case MV_SIP_DFX_THERMAL_READ:
+ armada_ap806_thermal_read(read);
+ break;
+ case MV_SIP_DFX_THERMAL_IRQ:
+ armada_ap806_thermal_irq();
+ break;
+ case MV_SIP_DFX_THERMAL_THRESH:
+ armada_ap806_thermal_threshold(x2, x3);
+ armada_ap806_thermal_overheat_irq_init();
+ break;
+ case MV_SIP_DFX_THERMAL_IS_VALID:
+ armada_is_valid(read);
+ break;
+ case MV_SIP_DFX_THERMAL_SEL_CHANNEL:
+ armada_select_channel(x2);
+ break;
+ default:
+ ERROR("unsupported dfx func\n");
+ return -EINVAL;
+ }
+
+ debug_exit();
+
+ return 0;
+}
diff --git a/drivers/marvell/secure_dfx_access/dfx.h b/drivers/marvell/secure_dfx_access/dfx.h
new file mode 100644
index 0000000..88c4de8
--- /dev/null
+++ b/drivers/marvell/secure_dfx_access/dfx.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2019 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* DFX sub-FID */
+#define MV_SIP_DFX_THERMAL_INIT 1
+#define MV_SIP_DFX_THERMAL_READ 2
+#define MV_SIP_DFX_THERMAL_IS_VALID 3
+#define MV_SIP_DFX_THERMAL_IRQ 4
+#define MV_SIP_DFX_THERMAL_THRESH 5
+#define MV_SIP_DFX_THERMAL_SEL_CHANNEL 6
+
+#define MV_SIP_DFX_SREAD 20
+#define MV_SIP_DFX_SWRITE 21
+
+int mvebu_dfx_thermal_handle(u_register_t func, u_register_t *read,
+ u_register_t x2, u_register_t x3);
+int mvebu_dfx_misc_handle(u_register_t func, u_register_t *read,
+ u_register_t addr, u_register_t val);
diff --git a/drivers/marvell/secure_dfx_access/misc_dfx.c b/drivers/marvell/secure_dfx_access/misc_dfx.c
new file mode 100644
index 0000000..189105f
--- /dev/null
+++ b/drivers/marvell/secure_dfx_access/misc_dfx.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2021 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include "dfx.h"
+#include <mvebu_def.h>
+#include <mvebu.h>
+#include <errno.h>
+
+/* #define DEBUG_DFX */
+#ifdef DEBUG_DFX
+#define debug(format...) NOTICE(format)
+#else
+#define debug(format, arg...)
+#endif
+
+#define SAR_BASE (MVEBU_REGS_BASE + 0x6F8200)
+#define SAR_SIZE 0x4
+#define AP_DEV_ID_STATUS_REG (MVEBU_REGS_BASE + 0x6F8240)
+#define JTAG_DEV_ID_STATUS_REG (MVEBU_REGS_BASE + 0x6F8244)
+#define EFUSE_CTRL (MVEBU_REGS_BASE + 0x6F8008)
+#define EFUSE_LD_BASE (MVEBU_REGS_BASE + 0x6F8F00)
+#define EFUSE_LD_SIZE 0x1C
+#define EFUSE_HD_BASE (MVEBU_REGS_BASE + 0x6F9000)
+#define EFUSE_HD_SIZE 0x3F8
+
+/* AP806 CPU DFS register mapping*/
+#define AP806_CA72MP2_0_PLL_CR_0_BASE (MVEBU_REGS_BASE + 0x6F8278)
+#define AP806_CA72MP2_0_PLL_CR_1_BASE (MVEBU_REGS_BASE + 0x6F8280)
+#define AP806_CA72MP2_0_PLL_CR_2_BASE (MVEBU_REGS_BASE + 0x6F8284)
+#define AP806_CA72MP2_0_PLL_SR_BASE (MVEBU_REGS_BASE + 0x6F8C94)
+
+/* AP807 CPU DFS register mapping */
+#define AP807_DEVICE_GENERAL_CR_10_BASE (MVEBU_REGS_BASE + 0x6F8278)
+#define AP807_DEVICE_GENERAL_CR_11_BASE (MVEBU_REGS_BASE + 0x6F827C)
+#define AP807_DEVICE_GENERAL_STATUS_6_BASE (MVEBU_REGS_BASE + 0x6F8C98)
+
+#ifdef MVEBU_SOC_AP807
+ #define CLUSTER_OFFSET 0x8
+ #define CLK_DIVIDER_REG AP807_DEVICE_GENERAL_CR_10_BASE
+ #define CLK_FORCE_REG AP807_DEVICE_GENERAL_CR_11_BASE
+ #define CLK_RATIO_REG AP807_DEVICE_GENERAL_CR_11_BASE
+ #define CLK_RATIO_STATE_REG AP807_DEVICE_GENERAL_STATUS_6_BASE
+#else
+ #define CLUSTER_OFFSET 0x14
+ #define CLK_DIVIDER_REG AP806_CA72MP2_0_PLL_CR_0_BASE
+ #define CLK_FORCE_REG AP806_CA72MP2_0_PLL_CR_1_BASE
+ #define CLK_RATIO_REG AP806_CA72MP2_0_PLL_CR_2_BASE
+ #define CLK_RATIO_STATE_REG AP806_CA72MP2_0_PLL_SR_BASE
+#endif /* MVEBU_SOC_AP807 */
+
+static _Bool is_valid(u_register_t addr)
+{
+ switch (addr) {
+ case AP_DEV_ID_STATUS_REG:
+ case JTAG_DEV_ID_STATUS_REG:
+ case SAR_BASE ... (SAR_BASE + SAR_SIZE):
+ case EFUSE_LD_BASE ... (EFUSE_LD_BASE + EFUSE_LD_SIZE):
+ case EFUSE_HD_BASE ... (EFUSE_HD_BASE + EFUSE_HD_SIZE):
+ case EFUSE_CTRL:
+ /* cpu-clk related registers */
+ case CLK_DIVIDER_REG:
+ case CLK_DIVIDER_REG + CLUSTER_OFFSET:
+ case CLK_FORCE_REG:
+ case CLK_FORCE_REG + CLUSTER_OFFSET:
+#ifndef MVEBU_SOC_AP807
+ case CLK_RATIO_REG:
+ case CLK_RATIO_REG + CLUSTER_OFFSET:
+#endif
+ case CLK_RATIO_STATE_REG:
+ case CLK_RATIO_STATE_REG + CLUSTER_OFFSET:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int armada_dfx_sread(u_register_t *read, u_register_t addr)
+{
+ if (!is_valid(addr))
+ return -EINVAL;
+
+ *read = mmio_read_32(addr);
+
+ return 0;
+}
+
+static int armada_dfx_swrite(u_register_t addr, u_register_t val)
+{
+ if (!is_valid(addr))
+ return -EINVAL;
+
+ mmio_write_32(addr, val);
+
+ return 0;
+}
+
+int mvebu_dfx_misc_handle(u_register_t func, u_register_t *read,
+ u_register_t addr, u_register_t val)
+{
+ debug_enter();
+
+ debug("func %ld, addr 0x%lx, val 0x%lx\n", func, addr, val);
+
+ switch (func) {
+ case MV_SIP_DFX_SREAD:
+ return armada_dfx_sread(read, addr);
+ case MV_SIP_DFX_SWRITE:
+ return armada_dfx_swrite(addr, val);
+ default:
+ ERROR("unsupported dfx misc sub-func\n");
+ return -EINVAL;
+ }
+
+ debug_exit();
+
+ return 0;
+}
diff --git a/drivers/marvell/thermal.c b/drivers/marvell/thermal.c
new file mode 100644
index 0000000..a501ab4
--- /dev/null
+++ b/drivers/marvell/thermal.c
@@ -0,0 +1,54 @@
+/*
+ * 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 <common/debug.h>
+#include <drivers/marvell/thermal.h>
+
+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;
+}
diff --git a/drivers/marvell/uart/a3700_console.S b/drivers/marvell/uart/a3700_console.S
new file mode 100644
index 0000000..c7eb165
--- /dev/null
+++ b/drivers/marvell/uart/a3700_console.S
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2016 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <console_macros.S>
+#include <drivers/marvell/uart/a3700_console.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_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, x4
+ * -----------------------------------------------
+ */
+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
+
+ /*
+ * Wait for the TX (THR and TSR) to be empty. If wait for 3ms, the TX FIFO is
+ * still not empty, TX FIFO will reset by all means.
+ */
+ mov w4, #30 /* max time out 30 * 100 us */
+2:
+ /* Check whether TX (THR and TSR) is empty */
+ ldr w3, [x0, #UART_STATUS_REG]
+ and w3, w3, #UARTLSR_TXEMPTY
+ cmp w3, #0
+ b.ne 4f
+
+ /* Delay */
+ mov w3, #60000 /* 60000 cycles of below 3 instructions on 1200 MHz CPU ~~ 100 us */
+3:
+ sub w3, w3, #1
+ cmp w3, #0
+ b.ne 3b
+
+ /* Check whether wait timeout expired */
+ sub w4, w4, #1
+ cmp w4, #0
+ b.ne 2b
+
+4:
+ /* Reset UART via North Bridge Peripheral */
+ mov_imm x4, MVEBU_NB_RESET_REG
+ ldr w3, [x4]
+ bic w3, w3, #MVEBU_NB_RESET_UART_N
+ str w3, [x4]
+ orr w3, w3, #MVEBU_NB_RESET_UART_N
+ str w3, [x4]
+
+ /* Reset FIFO */
+ mov w3, #UART_CTRL_RXFIFO_RESET
+ orr w3, w3, #UART_CTRL_TXFIFO_RESET
+ str w3, [x0, #UART_CTRL_REG]
+
+ /* Delay */
+ mov w3, #2000
+1:
+ sub w3, w3, #1
+ cmp w3, #0
+ b.ne 1b
+
+ /* Program the baudrate */
+ /* Divisor = Round(Uartclock / (16 * baudrate)) */
+ lsl w2, w2, #4
+ add w1, w1, w2, lsr #1
+ udiv w2, w1, w2
+ and w2, w2, #0x3ff /* clear all other bits to use default clock */
+
+ str w2, [x0, #UART_BAUD_REG]/* set baud rate divisor */
+
+ /* Set UART to default 16X scheme */
+ mov w3, #0
+ str w3, [x0, #UART_POSSR_REG]
+
+ /* 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_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_t struct
+ * Out: return 1 on success, 0 on error
+ * Clobber list : x0, x1, x2, x3, x4, x6, x7, x14
+ * -----------------------------------------------
+ */
+func console_a3700_register
+ mov x7, x30
+ mov x6, x3
+ cbz x6, register_fail
+ str x0, [x6, #CONSOLE_T_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_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_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 if no character is available.
+ * In : w0 - console base address
+ * Out : w0 - character if available, else -1
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func console_a3700_core_getc
+ /* Check if there is a pending character */
+ ldr w1, [x0, #UART_STATUS_REG]
+ and w1, w1, #UARTLSR_RXRDY
+ cmp w1, #UARTLSR_RXRDY
+ b.ne getc_no_char
+ ldr w0, [x0, #UART_RX_REG]
+ and w0, w0, #0xff
+ ret
+getc_no_char:
+ mov w0, #ERROR_NO_PENDING_CHAR
+ ret
+endfunc console_a3700_core_getc
+
+ /* ---------------------------------------------
+ * int console_a3700_getc(console_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_BASE]
+ b console_a3700_core_getc
+endfunc console_a3700_getc
+
+ /* ---------------------------------------------
+ * void 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 : void.
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func console_a3700_core_flush
+ /* Wait for the TX (THR and TSR) to be empty */
+1: ldr w1, [x0, #UART_STATUS_REG]
+ and w1, w1, #UARTLSR_TXEMPTY
+ cmp w1, #UARTLSR_TXEMPTY
+ b.ne 1b
+ ret
+endfunc console_a3700_core_flush
+
+ /* ---------------------------------------------
+ * void console_a3700_flush(console_t *console)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * In : x0 - pointer to console_t structure
+ * Out : void.
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func console_a3700_flush
+ ldr x0, [x0, #CONSOLE_T_BASE]
+ b console_a3700_core_flush
+endfunc console_a3700_flush
+
diff --git a/drivers/measured_boot/event_log/event_log.c b/drivers/measured_boot/event_log/event_log.c
new file mode 100644
index 0000000..d661c35
--- /dev/null
+++ b/drivers/measured_boot/event_log/event_log.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <arch_helpers.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/measured_boot/event_log/event_log.h>
+
+#include <plat/common/platform.h>
+
+#if TPM_ALG_ID == TPM_ALG_SHA512
+#define CRYPTO_MD_ID CRYPTO_MD_SHA512
+#elif TPM_ALG_ID == TPM_ALG_SHA384
+#define CRYPTO_MD_ID CRYPTO_MD_SHA384
+#elif TPM_ALG_ID == TPM_ALG_SHA256
+#define CRYPTO_MD_ID CRYPTO_MD_SHA256
+#else
+# error Invalid TPM algorithm.
+#endif /* TPM_ALG_ID */
+
+/* Running Event Log Pointer */
+static uint8_t *log_ptr;
+
+/* Pointer to the first byte past end of the Event Log buffer */
+static uintptr_t log_end;
+
+/* Pointer to event_log_metadata_t */
+static const event_log_metadata_t *plat_metadata_ptr;
+
+/* TCG_EfiSpecIdEvent */
+static const id_event_headers_t id_event_header = {
+ .header = {
+ .pcr_index = PCR_0,
+ .event_type = EV_NO_ACTION,
+ .digest = {0},
+ .event_size = (uint32_t)(sizeof(id_event_struct_t) +
+ (sizeof(id_event_algorithm_size_t) *
+ HASH_ALG_COUNT))
+ },
+
+ .struct_header = {
+ .signature = TCG_ID_EVENT_SIGNATURE_03,
+ .platform_class = PLATFORM_CLASS_CLIENT,
+ .spec_version_minor = TCG_SPEC_VERSION_MINOR_TPM2,
+ .spec_version_major = TCG_SPEC_VERSION_MAJOR_TPM2,
+ .spec_errata = TCG_SPEC_ERRATA_TPM2,
+ .uintn_size = (uint8_t)(sizeof(unsigned int) /
+ sizeof(uint32_t)),
+ .number_of_algorithms = HASH_ALG_COUNT
+ }
+};
+
+static const event2_header_t locality_event_header = {
+ /*
+ * All EV_NO_ACTION events SHALL set
+ * TCG_PCR_EVENT2.pcrIndex = 0, unless otherwise specified
+ */
+ .pcr_index = PCR_0,
+
+ /*
+ * All EV_NO_ACTION events SHALL set
+ * TCG_PCR_EVENT2.eventType = 03h
+ */
+ .event_type = EV_NO_ACTION,
+
+ /*
+ * All EV_NO_ACTION events SHALL set TCG_PCR_EVENT2.digests to all
+ * 0x00's for each allocated Hash algorithm
+ */
+ .digests = {
+ .count = HASH_ALG_COUNT
+ }
+};
+
+/*
+ * Record a measurement as a TCG_PCR_EVENT2 event
+ *
+ * @param[in] hash Pointer to hash data of TCG_DIGEST_SIZE bytes
+ * @param[in] event_type Type of Event, Various Event Types are
+ * mentioned in tcg.h header
+ * @param[in] metadata_ptr Pointer to event_log_metadata_t structure
+ *
+ * There must be room for storing this new event into the event log buffer.
+ */
+void event_log_record(const uint8_t *hash, uint32_t event_type,
+ const event_log_metadata_t *metadata_ptr)
+{
+ void *ptr = log_ptr;
+ uint32_t name_len = 0U;
+
+ assert(hash != NULL);
+ assert(metadata_ptr != NULL);
+ /* event_log_buf_init() must have been called prior to this. */
+ assert(log_ptr != NULL);
+
+ if (metadata_ptr->name != NULL) {
+ name_len = (uint32_t)strlen(metadata_ptr->name) + 1U;
+ }
+
+ /* Check for space in Event Log buffer */
+ assert(((uintptr_t)ptr + (uint32_t)EVENT2_HDR_SIZE + name_len) <
+ log_end);
+
+ /*
+ * As per TCG specifications, firmware components that are measured
+ * into PCR[0] must be logged in the event log using the event type
+ * EV_POST_CODE.
+ */
+ /* TCG_PCR_EVENT2.PCRIndex */
+ ((event2_header_t *)ptr)->pcr_index = metadata_ptr->pcr;
+
+ /* TCG_PCR_EVENT2.EventType */
+ ((event2_header_t *)ptr)->event_type = event_type;
+
+ /* TCG_PCR_EVENT2.Digests.Count */
+ ptr = (uint8_t *)ptr + offsetof(event2_header_t, digests);
+ ((tpml_digest_values *)ptr)->count = HASH_ALG_COUNT;
+
+ /* TCG_PCR_EVENT2.Digests[] */
+ ptr = (uint8_t *)((uintptr_t)ptr +
+ offsetof(tpml_digest_values, digests));
+
+ /* TCG_PCR_EVENT2.Digests[].AlgorithmId */
+ ((tpmt_ha *)ptr)->algorithm_id = TPM_ALG_ID;
+
+ /* TCG_PCR_EVENT2.Digests[].Digest[] */
+ ptr = (uint8_t *)((uintptr_t)ptr + offsetof(tpmt_ha, digest));
+
+ /* Copy digest */
+ (void)memcpy(ptr, (const void *)hash, TCG_DIGEST_SIZE);
+
+ /* TCG_PCR_EVENT2.EventSize */
+ ptr = (uint8_t *)((uintptr_t)ptr + TCG_DIGEST_SIZE);
+ ((event2_data_t *)ptr)->event_size = name_len;
+
+ /* Copy event data to TCG_PCR_EVENT2.Event */
+ if (metadata_ptr->name != NULL) {
+ (void)memcpy((void *)(((event2_data_t *)ptr)->event),
+ (const void *)metadata_ptr->name, name_len);
+ }
+
+ /* End of event data */
+ log_ptr = (uint8_t *)((uintptr_t)ptr +
+ offsetof(event2_data_t, event) + name_len);
+}
+
+void event_log_buf_init(uint8_t *event_log_start, uint8_t *event_log_finish)
+{
+ assert(event_log_start != NULL);
+ assert(event_log_finish > event_log_start);
+
+ log_ptr = event_log_start;
+ log_end = (uintptr_t)event_log_finish;
+}
+
+/*
+ * Initialise Event Log global variables, used during the recording
+ * of various payload measurements into the Event Log buffer
+ *
+ * @param[in] event_log_start Base address of Event Log buffer
+ * @param[in] event_log_finish End address of Event Log buffer,
+ * it is a first byte past end of the
+ * buffer
+ */
+void event_log_init(uint8_t *event_log_start, uint8_t *event_log_finish)
+{
+ event_log_buf_init(event_log_start, event_log_finish);
+
+ /* Get pointer to platform's event_log_metadata_t structure */
+ plat_metadata_ptr = plat_event_log_get_metadata();
+ assert(plat_metadata_ptr != NULL);
+}
+
+void event_log_write_specid_event(void)
+{
+ void *ptr = log_ptr;
+
+ /* event_log_buf_init() must have been called prior to this. */
+ assert(log_ptr != NULL);
+ assert(((uintptr_t)log_ptr + ID_EVENT_SIZE) < log_end);
+
+ /*
+ * Add Specification ID Event first
+ *
+ * Copy TCG_EfiSpecIDEventStruct structure header
+ */
+ (void)memcpy(ptr, (const void *)&id_event_header,
+ sizeof(id_event_header));
+ ptr = (uint8_t *)((uintptr_t)ptr + sizeof(id_event_header));
+
+ /* TCG_EfiSpecIdEventAlgorithmSize structure */
+ ((id_event_algorithm_size_t *)ptr)->algorithm_id = TPM_ALG_ID;
+ ((id_event_algorithm_size_t *)ptr)->digest_size = TCG_DIGEST_SIZE;
+ ptr = (uint8_t *)((uintptr_t)ptr + sizeof(id_event_algorithm_size_t));
+
+ /*
+ * TCG_EfiSpecIDEventStruct.vendorInfoSize
+ * No vendor data
+ */
+ ((id_event_struct_data_t *)ptr)->vendor_info_size = 0;
+ log_ptr = (uint8_t *)((uintptr_t)ptr +
+ offsetof(id_event_struct_data_t, vendor_info));
+}
+
+/*
+ * Initialises Event Log by writing Specification ID and
+ * Startup Locality events
+ */
+void event_log_write_header(void)
+{
+ const char locality_signature[] = TCG_STARTUP_LOCALITY_SIGNATURE;
+ void *ptr;
+
+ event_log_write_specid_event();
+
+ ptr = log_ptr;
+ assert(((uintptr_t)log_ptr + LOC_EVENT_SIZE) < log_end);
+
+ /*
+ * The Startup Locality event should be placed in the log before
+ * any event which extends PCR[0].
+ *
+ * Ref. TCG PC Client Platform Firmware Profile 9.4.5.3
+ */
+
+ /* Copy Startup Locality Event Header */
+ (void)memcpy(ptr, (const void *)&locality_event_header,
+ sizeof(locality_event_header));
+ ptr = (uint8_t *)((uintptr_t)ptr + sizeof(locality_event_header));
+
+ /* TCG_PCR_EVENT2.Digests[].AlgorithmId */
+ ((tpmt_ha *)ptr)->algorithm_id = TPM_ALG_ID;
+
+ /* TCG_PCR_EVENT2.Digests[].Digest[] */
+ (void)memset(&((tpmt_ha *)ptr)->digest, 0, TCG_DIGEST_SIZE);
+ ptr = (uint8_t *)((uintptr_t)ptr +
+ offsetof(tpmt_ha, digest) + TCG_DIGEST_SIZE);
+
+ /* TCG_PCR_EVENT2.EventSize */
+ ((event2_data_t *)ptr)->event_size =
+ (uint32_t)sizeof(startup_locality_event_t);
+ ptr = (uint8_t *)((uintptr_t)ptr + offsetof(event2_data_t, event));
+
+ /* TCG_EfiStartupLocalityEvent.Signature */
+ (void)memcpy(ptr, (const void *)locality_signature,
+ sizeof(TCG_STARTUP_LOCALITY_SIGNATURE));
+
+ /*
+ * TCG_EfiStartupLocalityEvent.StartupLocality = 0:
+ * the platform's boot firmware
+ */
+ ((startup_locality_event_t *)ptr)->startup_locality = 0U;
+ log_ptr = (uint8_t *)((uintptr_t)ptr + sizeof(startup_locality_event_t));
+}
+
+int event_log_measure(uintptr_t data_base, uint32_t data_size,
+ unsigned char hash_data[CRYPTO_MD_MAX_SIZE])
+{
+ /* Calculate hash */
+ return crypto_mod_calc_hash(CRYPTO_MD_ID,
+ (void *)data_base, data_size, hash_data);
+}
+
+/*
+ * Calculate and write hash of image, configuration data, etc.
+ * to Event Log.
+ *
+ * @param[in] data_base Address of data
+ * @param[in] data_size Size of data
+ * @param[in] data_id Data ID
+ * @return:
+ * 0 = success
+ * < 0 = error
+ */
+int event_log_measure_and_record(uintptr_t data_base, uint32_t data_size,
+ uint32_t data_id)
+{
+ unsigned char hash_data[CRYPTO_MD_MAX_SIZE];
+ int rc;
+ const event_log_metadata_t *metadata_ptr = plat_metadata_ptr;
+
+ /* Get the metadata associated with this image. */
+ while ((metadata_ptr->id != EVLOG_INVALID_ID) &&
+ (metadata_ptr->id != data_id)) {
+ metadata_ptr++;
+ }
+ assert(metadata_ptr->id != EVLOG_INVALID_ID);
+
+ /* Measure the payload with algorithm selected by EventLog driver */
+ rc = event_log_measure(data_base, data_size, hash_data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ event_log_record(hash_data, EV_POST_CODE, metadata_ptr);
+
+ return 0;
+}
+
+/*
+ * Get current Event Log buffer size i.e. used space of Event Log buffer
+ *
+ * @param[in] event_log_start Base Pointer to Event Log buffer
+ *
+ * @return: current Size of Event Log buffer
+ */
+size_t event_log_get_cur_size(uint8_t *event_log_start)
+{
+ assert(event_log_start != NULL);
+ assert(log_ptr >= event_log_start);
+
+ return (size_t)((uintptr_t)log_ptr - (uintptr_t)event_log_start);
+}
diff --git a/drivers/measured_boot/event_log/event_log.mk b/drivers/measured_boot/event_log/event_log.mk
new file mode 100644
index 0000000..5ea4c55
--- /dev/null
+++ b/drivers/measured_boot/event_log/event_log.mk
@@ -0,0 +1,41 @@
+#
+# Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Default log level to dump the event log (LOG_LEVEL_INFO)
+EVENT_LOG_LEVEL ?= 40
+
+# Measured Boot hash algorithm.
+# SHA-256 (or stronger) is required for all devices that are TPM 2.0 compliant.
+ifdef TPM_HASH_ALG
+ $(warning "TPM_HASH_ALG is deprecated. Please use MBOOT_EL_HASH_ALG instead.")
+ MBOOT_EL_HASH_ALG := ${TPM_HASH_ALG}
+else
+ MBOOT_EL_HASH_ALG := sha256
+endif
+
+ifeq (${MBOOT_EL_HASH_ALG}, sha512)
+ TPM_ALG_ID := TPM_ALG_SHA512
+ TCG_DIGEST_SIZE := 64U
+else ifeq (${MBOOT_EL_HASH_ALG}, sha384)
+ TPM_ALG_ID := TPM_ALG_SHA384
+ TCG_DIGEST_SIZE := 48U
+else
+ TPM_ALG_ID := TPM_ALG_SHA256
+ TCG_DIGEST_SIZE := 32U
+endif #MBOOT_EL_HASH_ALG
+
+# Set definitions for Measured Boot driver.
+$(eval $(call add_defines,\
+ $(sort \
+ TPM_ALG_ID \
+ TCG_DIGEST_SIZE \
+ EVENT_LOG_LEVEL \
+)))
+
+EVENT_LOG_SRC_DIR := drivers/measured_boot/event_log/
+
+EVENT_LOG_SOURCES := ${EVENT_LOG_SRC_DIR}event_log.c \
+ ${EVENT_LOG_SRC_DIR}event_print.c
diff --git a/drivers/measured_boot/event_log/event_print.c b/drivers/measured_boot/event_log/event_print.c
new file mode 100644
index 0000000..e2ba174
--- /dev/null
+++ b/drivers/measured_boot/event_log/event_print.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/measured_boot/event_log/event_log.h>
+
+#if LOG_LEVEL >= EVENT_LOG_LEVEL
+
+/*
+ * Print TCG_EfiSpecIDEventStruct
+ *
+ * @param[in/out] log_addr Pointer to Event Log
+ * @param[in/out] log_size Pointer to Event Log size
+ */
+static void id_event_print(uint8_t **log_addr, size_t *log_size)
+{
+ unsigned int i;
+ uint8_t info_size, *info_size_ptr;
+ void *ptr = *log_addr;
+ id_event_headers_t *event = (id_event_headers_t *)ptr;
+ id_event_algorithm_size_t *alg_ptr;
+ uint32_t event_size, number_of_algorithms;
+ size_t digest_len;
+#if ENABLE_ASSERTIONS
+ const uint8_t *end_ptr = (uint8_t *)((uintptr_t)*log_addr + *log_size);
+ bool valid = true;
+#endif
+
+ assert(*log_size >= sizeof(id_event_headers_t));
+
+ /* The fields of the event log header are defined to be PCRIndex of 0,
+ * EventType of EV_NO_ACTION, Digest of 20 bytes of 0, and
+ * Event content defined as TCG_EfiSpecIDEventStruct.
+ */
+ LOG_EVENT("TCG_EfiSpecIDEvent:\n");
+ LOG_EVENT(" PCRIndex : %u\n", event->header.pcr_index);
+ assert(event->header.pcr_index == (uint32_t)PCR_0);
+
+ LOG_EVENT(" EventType : %u\n", event->header.event_type);
+ assert(event->header.event_type == EV_NO_ACTION);
+
+ LOG_EVENT(" Digest :");
+ for (i = 0U; i < sizeof(event->header.digest); ++i) {
+ uint8_t val = event->header.digest[i];
+
+ (void)printf(" %02x", val);
+ if ((i & U(0xF)) == 0U) {
+ (void)printf("\n");
+ LOG_EVENT("\t\t :");
+ }
+#if ENABLE_ASSERTIONS
+ if (val != 0U) {
+ valid = false;
+ }
+#endif
+ }
+ if ((i & U(0xF)) != 0U) {
+ (void)printf("\n");
+ }
+
+ assert(valid);
+
+ /* EventSize */
+ event_size = event->header.event_size;
+ LOG_EVENT(" EventSize : %u\n", event_size);
+
+ LOG_EVENT(" Signature : %s\n",
+ event->struct_header.signature);
+ LOG_EVENT(" PlatformClass : %u\n",
+ event->struct_header.platform_class);
+ LOG_EVENT(" SpecVersion : %u.%u.%u\n",
+ event->struct_header.spec_version_major,
+ event->struct_header.spec_version_minor,
+ event->struct_header.spec_errata);
+ LOG_EVENT(" UintnSize : %u\n",
+ event->struct_header.uintn_size);
+
+ /* NumberOfAlgorithms */
+ number_of_algorithms = event->struct_header.number_of_algorithms;
+ LOG_EVENT(" NumberOfAlgorithms : %u\n", number_of_algorithms);
+
+ /* Address of DigestSizes[] */
+ alg_ptr = event->struct_header.digest_size;
+
+ /* Size of DigestSizes[] */
+ digest_len = number_of_algorithms * sizeof(id_event_algorithm_size_t);
+ assert(((uintptr_t)alg_ptr + digest_len) <= (uintptr_t)end_ptr);
+
+ LOG_EVENT(" DigestSizes :\n");
+ for (i = 0U; i < number_of_algorithms; ++i) {
+ LOG_EVENT(" #%u AlgorithmId : SHA", i);
+ uint16_t algorithm_id = alg_ptr[i].algorithm_id;
+
+ switch (algorithm_id) {
+ case TPM_ALG_SHA256:
+ (void)printf("256\n");
+ break;
+ case TPM_ALG_SHA384:
+ (void)printf("384\n");
+ break;
+ case TPM_ALG_SHA512:
+ (void)printf("512\n");
+ break;
+ default:
+ (void)printf("?\n");
+ ERROR("Algorithm 0x%x not found\n", algorithm_id);
+ assert(false);
+ }
+
+ LOG_EVENT(" DigestSize : %u\n",
+ alg_ptr[i].digest_size);
+ }
+
+ /* Address of VendorInfoSize */
+ info_size_ptr = (uint8_t *)((uintptr_t)alg_ptr + digest_len);
+ assert((uintptr_t)info_size_ptr <= (uintptr_t)end_ptr);
+
+ info_size = *info_size_ptr++;
+ LOG_EVENT(" VendorInfoSize : %u\n", info_size);
+
+ /* Check VendorInfo end address */
+ assert(((uintptr_t)info_size_ptr + info_size) <= (uintptr_t)end_ptr);
+
+ /* Check EventSize */
+ assert(event_size == (sizeof(id_event_struct_t) +
+ digest_len + info_size));
+ if (info_size != 0U) {
+ LOG_EVENT(" VendorInfo :");
+ for (i = 0U; i < info_size; ++i) {
+ (void)printf(" %02x", *info_size_ptr++);
+ }
+ (void)printf("\n");
+ }
+
+ *log_size -= (uintptr_t)info_size_ptr - (uintptr_t)*log_addr;
+ *log_addr = info_size_ptr;
+}
+
+/*
+ * Print TCG_PCR_EVENT2
+ *
+ * @param[in/out] log_addr Pointer to Event Log
+ * @param[in/out] log_size Pointer to Event Log size
+ */
+static void event2_print(uint8_t **log_addr, size_t *log_size)
+{
+ uint32_t event_size, count;
+ size_t sha_size, digests_size = 0U;
+ void *ptr = *log_addr;
+#if ENABLE_ASSERTIONS
+ const uint8_t *end_ptr = (uint8_t *)((uintptr_t)*log_addr + *log_size);
+#endif
+
+ assert(*log_size >= sizeof(event2_header_t));
+
+ LOG_EVENT("PCR_Event2:\n");
+ LOG_EVENT(" PCRIndex : %u\n",
+ ((event2_header_t *)ptr)->pcr_index);
+ LOG_EVENT(" EventType : %u\n",
+ ((event2_header_t *)ptr)->event_type);
+
+ count = ((event2_header_t *)ptr)->digests.count;
+ LOG_EVENT(" Digests Count : %u\n", count);
+
+ /* Address of TCG_PCR_EVENT2.Digests[] */
+ ptr = (uint8_t *)ptr + sizeof(event2_header_t);
+ assert(((uintptr_t)ptr <= (uintptr_t)end_ptr) && (count != 0U));
+
+ for (unsigned int i = 0U; i < count; ++i) {
+ /* Check AlgorithmId address */
+ assert(((uintptr_t)ptr +
+ offsetof(tpmt_ha, digest)) <= (uintptr_t)end_ptr);
+
+ LOG_EVENT(" #%u AlgorithmId : SHA", i);
+ switch (((tpmt_ha *)ptr)->algorithm_id) {
+ case TPM_ALG_SHA256:
+ sha_size = SHA256_DIGEST_SIZE;
+ (void)printf("256\n");
+ break;
+ case TPM_ALG_SHA384:
+ sha_size = SHA384_DIGEST_SIZE;
+ (void)printf("384\n");
+ break;
+ case TPM_ALG_SHA512:
+ sha_size = SHA512_DIGEST_SIZE;
+ (void)printf("512\n");
+ break;
+ default:
+ (void)printf("?\n");
+ ERROR("Algorithm 0x%x not found\n",
+ ((tpmt_ha *)ptr)->algorithm_id);
+ panic();
+ }
+
+ /* End of Digest[] */
+ ptr = (uint8_t *)((uintptr_t)ptr + offsetof(tpmt_ha, digest));
+ assert(((uintptr_t)ptr + sha_size) <= (uintptr_t)end_ptr);
+
+ /* Total size of all digests */
+ digests_size += sha_size;
+
+ LOG_EVENT(" Digest :");
+ for (unsigned int j = 0U; j < sha_size; ++j) {
+ (void)printf(" %02x", *(uint8_t *)ptr++);
+ if ((j & U(0xF)) == U(0xF)) {
+ (void)printf("\n");
+ if (j < (sha_size - 1U)) {
+ LOG_EVENT("\t\t :");
+ }
+ }
+ }
+ }
+
+ /* TCG_PCR_EVENT2.EventSize */
+ assert(((uintptr_t)ptr + offsetof(event2_data_t, event)) <= (uintptr_t)end_ptr);
+
+ event_size = ((event2_data_t *)ptr)->event_size;
+ LOG_EVENT(" EventSize : %u\n", event_size);
+
+ /* Address of TCG_PCR_EVENT2.Event[EventSize] */
+ ptr = (uint8_t *)((uintptr_t)ptr + offsetof(event2_data_t, event));
+
+ /* End of TCG_PCR_EVENT2.Event[EventSize] */
+ assert(((uintptr_t)ptr + event_size) <= (uintptr_t)end_ptr);
+
+ if ((event_size == sizeof(startup_locality_event_t)) &&
+ (strcmp((const char *)ptr, TCG_STARTUP_LOCALITY_SIGNATURE) == 0)) {
+ LOG_EVENT(" Signature : %s\n",
+ ((startup_locality_event_t *)ptr)->signature);
+ LOG_EVENT(" StartupLocality : %u\n",
+ ((startup_locality_event_t *)ptr)->startup_locality);
+ } else {
+ LOG_EVENT(" Event : %s\n", (uint8_t *)ptr);
+ }
+
+ *log_size -= (uintptr_t)ptr + event_size - (uintptr_t)*log_addr;
+ *log_addr = (uint8_t *)ptr + event_size;
+}
+#endif /* LOG_LEVEL >= EVENT_LOG_LEVEL */
+
+/*
+ * Print Event Log
+ *
+ * @param[in] log_addr Pointer to Event Log
+ * @param[in] log_size Event Log size
+ */
+void dump_event_log(uint8_t *log_addr, size_t log_size)
+{
+#if LOG_LEVEL >= EVENT_LOG_LEVEL
+ assert(log_addr != NULL);
+
+ /* Print TCG_EfiSpecIDEvent */
+ id_event_print(&log_addr, &log_size);
+
+ while (log_size != 0U) {
+ event2_print(&log_addr, &log_size);
+ }
+#endif
+}
diff --git a/drivers/measured_boot/rss/rss_measured_boot.c b/drivers/measured_boot/rss/rss_measured_boot.c
new file mode 100644
index 0000000..cf545a7
--- /dev/null
+++ b/drivers/measured_boot/rss/rss_measured_boot.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/measured_boot/rss/rss_measured_boot.h>
+#include <lib/psa/measured_boot.h>
+#include <psa/crypto_types.h>
+#include <psa/crypto_values.h>
+#include <psa/error.h>
+
+#define MBOOT_ALG_SHA512 0
+#define MBOOT_ALG_SHA384 1
+#define MBOOT_ALG_SHA256 2
+
+#if MBOOT_ALG_ID == MBOOT_ALG_SHA512
+#define CRYPTO_MD_ID CRYPTO_MD_SHA512
+#define PSA_CRYPTO_MD_ID PSA_ALG_SHA_512
+#elif MBOOT_ALG_ID == MBOOT_ALG_SHA384
+#define CRYPTO_MD_ID CRYPTO_MD_SHA384
+#define PSA_CRYPTO_MD_ID PSA_ALG_SHA_384
+#elif MBOOT_ALG_ID == MBOOT_ALG_SHA256
+#define CRYPTO_MD_ID CRYPTO_MD_SHA256
+#define PSA_CRYPTO_MD_ID PSA_ALG_SHA_256
+#else
+# error Invalid Measured Boot algorithm.
+#endif /* MBOOT_ALG_ID */
+
+/* Pointer to struct rss_mboot_metadata */
+static struct rss_mboot_metadata *plat_metadata_ptr;
+
+/* Functions' declarations */
+void rss_measured_boot_init(void)
+{
+ /* At this point it is expected that communication channel over MHU
+ * is already initialised by platform init.
+ */
+ struct rss_mboot_metadata *metadata_ptr;
+
+ /* Get pointer to platform's struct rss_mboot_metadata structure */
+ plat_metadata_ptr = plat_rss_mboot_get_metadata();
+ assert(plat_metadata_ptr != NULL);
+
+ /* Use a local variable to preserve the value of the global pointer */
+ metadata_ptr = plat_metadata_ptr;
+
+ /* Init the non-const members of the metadata structure */
+ while (metadata_ptr->id != RSS_MBOOT_INVALID_ID) {
+ metadata_ptr->sw_type_size =
+ strlen((const char *)&metadata_ptr->sw_type) + 1;
+ metadata_ptr++;
+ }
+}
+
+int rss_mboot_measure_and_record(uintptr_t data_base, uint32_t data_size,
+ uint32_t data_id)
+{
+ unsigned char hash_data[CRYPTO_MD_MAX_SIZE];
+ int rc;
+ psa_status_t ret;
+ const struct rss_mboot_metadata *metadata_ptr = plat_metadata_ptr;
+
+ /* Get the metadata associated with this image. */
+ while ((metadata_ptr->id != RSS_MBOOT_INVALID_ID) &&
+ (metadata_ptr->id != data_id)) {
+ metadata_ptr++;
+ }
+
+ /* If image is not present in metadata array then skip */
+ if (metadata_ptr->id == RSS_MBOOT_INVALID_ID) {
+ return 0;
+ }
+
+ /* Calculate hash */
+ rc = crypto_mod_calc_hash(CRYPTO_MD_ID,
+ (void *)data_base, data_size, hash_data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ ret = rss_measured_boot_extend_measurement(
+ metadata_ptr->slot,
+ metadata_ptr->signer_id,
+ metadata_ptr->signer_id_size,
+ metadata_ptr->version,
+ metadata_ptr->version_size,
+ PSA_CRYPTO_MD_ID,
+ metadata_ptr->sw_type,
+ metadata_ptr->sw_type_size,
+ hash_data,
+ MBOOT_DIGEST_SIZE,
+ metadata_ptr->lock_measurement);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ return 0;
+}
+
+int rss_mboot_set_signer_id(unsigned int img_id,
+ const void *pk_ptr,
+ size_t pk_len)
+{
+ unsigned char hash_data[CRYPTO_MD_MAX_SIZE];
+ struct rss_mboot_metadata *metadata_ptr = plat_metadata_ptr;
+ int rc;
+
+ /* Get the metadata associated with this image. */
+ while ((metadata_ptr->id != RSS_MBOOT_INVALID_ID) &&
+ (metadata_ptr->id != img_id)) {
+ metadata_ptr++;
+ }
+
+ /* If image is not present in metadata array then skip */
+ if (metadata_ptr->id == RSS_MBOOT_INVALID_ID) {
+ return 0;
+ }
+
+ /* Calculate public key hash */
+ rc = crypto_mod_calc_hash(CRYPTO_MD_ID, (void *)pk_ptr,
+ pk_len, hash_data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ /* Update metadata struct with the received signer_id */
+ (void)memcpy(metadata_ptr->signer_id, hash_data, MBOOT_DIGEST_SIZE);
+ metadata_ptr->signer_id_size = MBOOT_DIGEST_SIZE;
+
+ return 0;
+}
diff --git a/drivers/measured_boot/rss/rss_measured_boot.mk b/drivers/measured_boot/rss/rss_measured_boot.mk
new file mode 100644
index 0000000..18ee836
--- /dev/null
+++ b/drivers/measured_boot/rss/rss_measured_boot.mk
@@ -0,0 +1,32 @@
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Hash algorithm for measured boot
+# SHA-256 (or stronger) is required.
+MBOOT_RSS_HASH_ALG := sha256
+
+ifeq (${MBOOT_RSS_HASH_ALG}, sha512)
+ MBOOT_ALG_ID := MBOOT_ALG_SHA512
+ MBOOT_DIGEST_SIZE := 64U
+else ifeq (${MBOOT_RSS_HASH_ALG}, sha384)
+ MBOOT_ALG_ID := MBOOT_ALG_SHA384
+ MBOOT_DIGEST_SIZE := 48U
+else
+ MBOOT_ALG_ID := MBOOT_ALG_SHA256
+ MBOOT_DIGEST_SIZE := 32U
+endif #MBOOT_RSS_HASH_ALG
+
+# Set definitions for Measured Boot driver.
+$(eval $(call add_defines,\
+ $(sort \
+ MBOOT_ALG_ID \
+ MBOOT_DIGEST_SIZE \
+ MBOOT_RSS_BACKEND \
+)))
+
+MEASURED_BOOT_SRC_DIR := drivers/measured_boot/rss/
+
+MEASURED_BOOT_SOURCES += ${MEASURED_BOOT_SRC_DIR}rss_measured_boot.c
diff --git a/drivers/mentor/i2c/mi2cv.c b/drivers/mentor/i2c/mi2cv.c
new file mode 100644
index 0000000..b0270c9
--- /dev/null
+++ b/drivers/mentor/i2c/mi2cv.c
@@ -0,0 +1,614 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * 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 <errno.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/mentor/mi2cv.h>
+#include <lib/mmio.h>
+
+#include <mentor_i2c_plat.h>
+
+#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 bool 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 != 0U);
+}
+
+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 <N> and <M> 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;
+}
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
new file mode 100644
index 0000000..8e83464
--- /dev/null
+++ b/drivers/mmc/mmc.c
@@ -0,0 +1,858 @@
+/*
+ * Copyright (c) 2018-2022, 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 <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/mmc.h>
+#include <lib/utils.h>
+#include <plat/common/common_def.h>
+
+#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 struct sd_switch_status sd_switch_func_status;
+static unsigned char mmc_ext_csd[512] __aligned(16);
+static unsigned int mmc_flags;
+static struct mmc_device_info *mmc_dev_info;
+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 bool is_sd_cmd6_enabled(void)
+{
+ return ((mmc_flags & MMC_FLAG_SD_CMD6) != 0U);
+}
+
+static int mmc_send_cmd(unsigned int idx, unsigned int arg,
+ unsigned int r_type, unsigned int *r_data)
+{
+ 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_send_part_switch_cmd(unsigned int part_config)
+{
+ int ret;
+ unsigned int part_time = 0;
+
+ ret = mmc_send_cmd(MMC_CMD(6),
+ EXTCSD_WRITE_BYTES |
+ EXTCSD_CMD(CMD_EXTCSD_PARTITION_CONFIG) |
+ EXTCSD_VALUE(part_config) |
+ EXTCSD_CMD_SET_NORMAL,
+ MMC_RESPONSE_R1B, NULL);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Partition switch timing is in 10ms units */
+ part_time = mmc_ext_csd[CMD_EXTCSD_PART_SWITCH_TIME] * 10;
+
+ mdelay(part_time);
+
+ do {
+ ret = mmc_device_state();
+ if (ret < 0) {
+ return ret;
+ }
+ } while (ret == MMC_STATE_PRG);
+
+ return 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_switch(unsigned int mode, unsigned char group,
+ unsigned char func)
+{
+ unsigned int group_shift = (group - 1U) * 4U;
+ unsigned int group_mask = GENMASK(group_shift + 3U, group_shift);
+ unsigned int arg;
+ int ret;
+
+ ret = ops->prepare(0, (uintptr_t)&sd_switch_func_status,
+ sizeof(sd_switch_func_status));
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* MMC CMD6: SWITCH_FUNC */
+ arg = mode | SD_SWITCH_ALL_GROUPS_MASK;
+ arg &= ~group_mask;
+ arg |= func << group_shift;
+ ret = mmc_send_cmd(MMC_CMD(6), arg, MMC_RESPONSE_R1, NULL);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return ops->read(0, (uintptr_t)&sd_switch_func_status,
+ sizeof(sd_switch_func_status));
+}
+
+static int sd_send_op_cond(void)
+{
+ int n;
+ 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;
+ }
+
+ ret = mmc_fill_device_info();
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (is_sd_cmd6_enabled() &&
+ (mmc_dev_info->mmc_dev_type == MMC_IS_SD_HC)) {
+ /* Try to switch to High Speed Mode */
+ ret = sd_switch(SD_SWITCH_FUNC_CHECK, 1U, 1U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((sd_switch_func_status.support_g1 & BIT(9)) == 0U) {
+ /* High speed not supported, keep default speed */
+ return 0;
+ }
+
+ ret = sd_switch(SD_SWITCH_FUNC_SWITCH, 1U, 1U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((sd_switch_func_status.sel_g2_g1 & 0x1U) == 0U) {
+ /* Cannot switch to high speed, keep default speed */
+ return 0;
+ }
+
+ mmc_dev_info->max_bus_freq = 50000000U;
+ ret = ops->set_ios(clk, bus_width);
+ }
+
+ return ret;
+}
+
+size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size)
+{
+ 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 int mmc_part_switch(unsigned int part_type)
+{
+ uint8_t part_config = mmc_ext_csd[CMD_EXTCSD_PARTITION_CONFIG];
+
+ part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
+ part_config |= part_type;
+
+ return mmc_send_part_switch_cmd(part_config);
+}
+
+static unsigned char mmc_current_boot_part(void)
+{
+ return PART_CFG_CURRENT_BOOT_PARTITION(mmc_ext_csd[CMD_EXTCSD_PARTITION_CONFIG]);
+}
+
+int mmc_part_switch_current_boot(void)
+{
+ unsigned char current_boot_part = mmc_current_boot_part();
+ int ret;
+
+ if (current_boot_part != 1U &&
+ current_boot_part != 2U) {
+ ERROR("Got unexpected value for active boot partition, %u\n", current_boot_part);
+ return -EIO;
+ }
+
+ ret = mmc_part_switch(current_boot_part);
+ if (ret < 0) {
+ ERROR("Failed to switch to boot partition, %d\n", ret);
+ }
+
+ return ret;
+}
+
+int mmc_part_switch_user(void)
+{
+ int ret;
+
+ ret = mmc_part_switch(PART_CFG_BOOT_PARTITION_NO_ACCESS);
+ if (ret < 0) {
+ ERROR("Failed to switch to user partition, %d\n", ret);
+ }
+
+ return ret;
+}
+
+size_t mmc_boot_part_size(void)
+{
+ return mmc_ext_csd[CMD_EXTCSD_BOOT_SIZE_MULT] * SZ_128K;
+}
+
+size_t mmc_boot_part_read_blocks(int lba, uintptr_t buf, size_t size)
+{
+ size_t size_read;
+ int ret;
+
+ ret = mmc_part_switch_current_boot();
+ if (ret < 0) {
+ return 0;
+ }
+
+ size_read = mmc_read_blocks(lba, buf, size);
+
+ ret = mmc_part_switch_user();
+ if (ret < 0) {
+ return 0;
+ }
+
+ return size_read;
+}
+
+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);
+}
diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
new file mode 100644
index 0000000..6ef2256
--- /dev/null
+++ b/drivers/mtd/nand/core.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/nand.h>
+#include <lib/utils.h>
+
+#include <platform_def.h>
+
+/*
+ * Define a single nand_device used by specific NAND frameworks.
+ */
+static struct nand_device nand_dev;
+
+#pragma weak plat_get_scratch_buffer
+void plat_get_scratch_buffer(void **buffer_addr, size_t *buf_size)
+{
+ static uint8_t scratch_buff[PLATFORM_MTD_MAX_PAGE_SIZE];
+
+ assert(buffer_addr != NULL);
+ assert(buf_size != NULL);
+
+ *buffer_addr = (void *)scratch_buff;
+ *buf_size = sizeof(scratch_buff);
+}
+
+int nand_read(unsigned int offset, uintptr_t buffer, size_t length,
+ size_t *length_read)
+{
+ unsigned int block = offset / nand_dev.block_size;
+ unsigned int end_block = (offset + length - 1U) / nand_dev.block_size;
+ unsigned int page_start =
+ (offset % nand_dev.block_size) / nand_dev.page_size;
+ unsigned int nb_pages = nand_dev.block_size / nand_dev.page_size;
+ unsigned int start_offset = offset % nand_dev.page_size;
+ unsigned int page;
+ unsigned int bytes_read;
+ int is_bad;
+ int ret;
+ uint8_t *scratch_buff;
+ size_t scratch_buff_size;
+
+ plat_get_scratch_buffer((void **)&scratch_buff, &scratch_buff_size);
+
+ assert(scratch_buff != NULL);
+
+ VERBOSE("Block %u - %u, page_start %u, nb %u, length %zu, offset %u\n",
+ block, end_block, page_start, nb_pages, length, offset);
+
+ *length_read = 0UL;
+
+ if (((start_offset != 0U) || (length % nand_dev.page_size) != 0U) &&
+ (scratch_buff_size < nand_dev.page_size)) {
+ return -EINVAL;
+ }
+
+ while (block <= end_block) {
+ is_bad = nand_dev.mtd_block_is_bad(block);
+ if (is_bad < 0) {
+ return is_bad;
+ }
+
+ if (is_bad == 1) {
+ /* Skip the block */
+ uint32_t max_block =
+ nand_dev.size / nand_dev.block_size;
+
+ block++;
+ end_block++;
+ if ((block < max_block) && (end_block < max_block)) {
+ continue;
+ }
+
+ return -EIO;
+ }
+
+ for (page = page_start; page < nb_pages; page++) {
+ if ((start_offset != 0U) ||
+ (length < nand_dev.page_size)) {
+ ret = nand_dev.mtd_read_page(
+ &nand_dev,
+ (block * nb_pages) + page,
+ (uintptr_t)scratch_buff);
+ if (ret != 0) {
+ return ret;
+ }
+
+ bytes_read = MIN((size_t)(nand_dev.page_size -
+ start_offset),
+ length);
+
+ memcpy((uint8_t *)buffer,
+ scratch_buff + start_offset,
+ bytes_read);
+
+ start_offset = 0U;
+ } else {
+ ret = nand_dev.mtd_read_page(&nand_dev,
+ (block * nb_pages) + page,
+ buffer);
+ if (ret != 0) {
+ return ret;
+ }
+
+ bytes_read = nand_dev.page_size;
+ }
+
+ length -= bytes_read;
+ buffer += bytes_read;
+ *length_read += bytes_read;
+
+ if (length == 0U) {
+ break;
+ }
+ }
+
+ page_start = 0U;
+ block++;
+ }
+
+ return 0;
+}
+
+int nand_seek_bb(uintptr_t base, unsigned int offset, size_t *extra_offset)
+{
+ unsigned int block;
+ unsigned int offset_block;
+ unsigned int max_block;
+ int is_bad;
+ size_t count_bb = 0U;
+
+ block = base / nand_dev.block_size;
+
+ if (offset != 0U) {
+ offset_block = (base + offset - 1U) / nand_dev.block_size;
+ } else {
+ offset_block = block;
+ }
+
+ max_block = nand_dev.size / nand_dev.block_size;
+
+ while (block <= offset_block) {
+ if (offset_block >= max_block) {
+ return -EIO;
+ }
+
+ is_bad = nand_dev.mtd_block_is_bad(block);
+ if (is_bad < 0) {
+ return is_bad;
+ }
+
+ if (is_bad == 1) {
+ count_bb++;
+ offset_block++;
+ }
+
+ block++;
+ }
+
+ *extra_offset = count_bb * nand_dev.block_size;
+
+ return 0;
+}
+
+struct nand_device *get_nand_device(void)
+{
+ return &nand_dev;
+}
diff --git a/drivers/mtd/nand/raw_nand.c b/drivers/mtd/nand/raw_nand.c
new file mode 100644
index 0000000..021e30b
--- /dev/null
+++ b/drivers/mtd/nand/raw_nand.c
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/raw_nand.h>
+#include <lib/utils.h>
+
+#include <platform_def.h>
+
+#define ONFI_SIGNATURE_ADDR 0x20U
+
+/* CRC calculation */
+#define CRC_POLYNOM 0x8005U
+#define CRC_INIT_VALUE 0x4F4EU
+
+/* Status register */
+#define NAND_STATUS_READY BIT(6)
+
+static struct rawnand_device rawnand_dev;
+
+#pragma weak plat_get_raw_nand_data
+int plat_get_raw_nand_data(struct rawnand_device *device)
+{
+ return 0;
+}
+
+static int nand_send_cmd(uint8_t cmd, unsigned int tim)
+{
+ struct nand_req req;
+
+ zeromem(&req, sizeof(struct nand_req));
+ req.nand = rawnand_dev.nand_dev;
+ req.type = NAND_REQ_CMD | cmd;
+ req.inst_delay = tim;
+
+ return rawnand_dev.ops->exec(&req);
+}
+
+static int nand_send_addr(uint8_t addr, unsigned int tim)
+{
+ struct nand_req req;
+
+ zeromem(&req, sizeof(struct nand_req));
+ req.nand = rawnand_dev.nand_dev;
+ req.type = NAND_REQ_ADDR;
+ req.addr = &addr;
+ req.inst_delay = tim;
+
+ return rawnand_dev.ops->exec(&req);
+}
+
+static int nand_send_wait(unsigned int delay, unsigned int tim)
+{
+ struct nand_req req;
+
+ zeromem(&req, sizeof(struct nand_req));
+ req.nand = rawnand_dev.nand_dev;
+ req.type = NAND_REQ_WAIT;
+ req.inst_delay = tim;
+ req.delay_ms = delay;
+
+ return rawnand_dev.ops->exec(&req);
+}
+
+
+static int nand_read_data(uint8_t *data, unsigned int length, bool use_8bit)
+{
+ struct nand_req req;
+
+ zeromem(&req, sizeof(struct nand_req));
+ req.nand = rawnand_dev.nand_dev;
+ req.type = NAND_REQ_DATAIN | (use_8bit ? NAND_REQ_BUS_WIDTH_8 : 0U);
+ req.addr = data;
+ req.length = length;
+
+ return rawnand_dev.ops->exec(&req);
+}
+
+int nand_change_read_column_cmd(unsigned int offset, uintptr_t buffer,
+ unsigned int len)
+{
+ int ret;
+ uint8_t addr[2];
+ unsigned int i;
+
+ ret = nand_send_cmd(NAND_CMD_CHANGE_1ST, 0U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (rawnand_dev.nand_dev->buswidth == NAND_BUS_WIDTH_16) {
+ offset /= 2U;
+ }
+
+ addr[0] = offset;
+ addr[1] = offset >> 8;
+
+ for (i = 0; i < 2U; i++) {
+ ret = nand_send_addr(addr[i], 0U);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ ret = nand_send_cmd(NAND_CMD_CHANGE_2ND, NAND_TCCS_MIN);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return nand_read_data((uint8_t *)buffer, len, false);
+}
+
+int nand_read_page_cmd(unsigned int page, unsigned int offset,
+ uintptr_t buffer, unsigned int len)
+{
+ uint8_t addr[5];
+ uint8_t i = 0U;
+ uint8_t j;
+ int ret;
+
+ VERBOSE(">%s page %u offset %u buffer 0x%lx\n", __func__, page, offset,
+ buffer);
+
+ if (rawnand_dev.nand_dev->buswidth == NAND_BUS_WIDTH_16) {
+ offset /= 2U;
+ }
+
+ addr[i++] = offset;
+ addr[i++] = offset >> 8;
+
+ addr[i++] = page;
+ addr[i++] = page >> 8;
+ if (rawnand_dev.nand_dev->size > SZ_128M) {
+ addr[i++] = page >> 16;
+ }
+
+ ret = nand_send_cmd(NAND_CMD_READ_1ST, 0U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ for (j = 0U; j < i; j++) {
+ ret = nand_send_addr(addr[j], 0U);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ ret = nand_send_cmd(NAND_CMD_READ_2ND, NAND_TWB_MAX);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = nand_send_wait(PSEC_TO_MSEC(NAND_TR_MAX), NAND_TRR_MIN);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (buffer != 0U) {
+ ret = nand_read_data((uint8_t *)buffer, len, false);
+ }
+
+ return ret;
+}
+
+static int nand_status(uint8_t *status)
+{
+ int ret;
+
+ ret = nand_send_cmd(NAND_CMD_STATUS, NAND_TWHR_MIN);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (status != NULL) {
+ ret = nand_read_data(status, 1U, true);
+ }
+
+ return ret;
+}
+
+int nand_wait_ready(unsigned int delay_ms)
+{
+ uint8_t status;
+ int ret;
+ uint64_t timeout;
+
+ /* Wait before reading status */
+ udelay(1);
+
+ ret = nand_status(NULL);
+ if (ret != 0) {
+ return ret;
+ }
+
+ timeout = timeout_init_us(delay_ms * 1000U);
+ while (!timeout_elapsed(timeout)) {
+ ret = nand_read_data(&status, 1U, true);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((status & NAND_STATUS_READY) != 0U) {
+ return nand_send_cmd(NAND_CMD_READ_1ST, 0U);
+ }
+
+ udelay(10);
+ }
+
+ return -ETIMEDOUT;
+}
+
+#if NAND_ONFI_DETECT
+static uint16_t nand_check_crc(uint16_t crc, uint8_t *data_in,
+ unsigned int data_len)
+{
+ uint32_t i;
+ uint32_t j;
+ uint32_t bit;
+
+ for (i = 0U; i < data_len; i++) {
+ uint8_t cur_param = *data_in++;
+
+ for (j = BIT(7); j != 0U; j >>= 1) {
+ bit = crc & BIT(15);
+ crc <<= 1;
+
+ if ((cur_param & j) != 0U) {
+ bit ^= BIT(15);
+ }
+
+ if (bit != 0U) {
+ crc ^= CRC_POLYNOM;
+ }
+ }
+
+ crc &= GENMASK(15, 0);
+ }
+
+ return crc;
+}
+
+static int nand_read_id(uint8_t addr, uint8_t *id, unsigned int size)
+{
+ int ret;
+
+ ret = nand_send_cmd(NAND_CMD_READID, 0U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = nand_send_addr(addr, NAND_TWHR_MIN);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return nand_read_data(id, size, true);
+}
+
+static int nand_reset(void)
+{
+ int ret;
+
+ ret = nand_send_cmd(NAND_CMD_RESET, NAND_TWB_MAX);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return nand_send_wait(PSEC_TO_MSEC(NAND_TRST_MAX), 0U);
+}
+
+static int nand_read_param_page(void)
+{
+ struct nand_param_page page;
+ uint8_t addr = 0U;
+ int ret;
+
+ ret = nand_send_cmd(NAND_CMD_READ_PARAM_PAGE, 0U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = nand_send_addr(addr, NAND_TWB_MAX);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = nand_send_wait(PSEC_TO_MSEC(NAND_TR_MAX), NAND_TRR_MIN);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = nand_read_data((uint8_t *)&page, sizeof(page), true);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (strncmp((char *)&page.page_sig, "ONFI", 4) != 0) {
+ WARN("Error ONFI detection\n");
+ return -EINVAL;
+ }
+
+ if (nand_check_crc(CRC_INIT_VALUE, (uint8_t *)&page, 254U) !=
+ page.crc16) {
+ WARN("Error reading param\n");
+ return -EINVAL;
+ }
+
+ if ((page.features & ONFI_FEAT_BUS_WIDTH_16) != 0U) {
+ rawnand_dev.nand_dev->buswidth = NAND_BUS_WIDTH_16;
+ } else {
+ rawnand_dev.nand_dev->buswidth = NAND_BUS_WIDTH_8;
+ }
+
+ rawnand_dev.nand_dev->block_size = page.num_pages_per_blk *
+ page.bytes_per_page;
+ rawnand_dev.nand_dev->page_size = page.bytes_per_page;
+ rawnand_dev.nand_dev->size = page.num_pages_per_blk *
+ page.bytes_per_page *
+ page.num_blk_in_lun * page.num_lun;
+
+ if (page.nb_ecc_bits != GENMASK_32(7, 0)) {
+ rawnand_dev.nand_dev->ecc.max_bit_corr = page.nb_ecc_bits;
+ rawnand_dev.nand_dev->ecc.size = SZ_512;
+ }
+
+ VERBOSE("Page size %u, block_size %u, Size %llu, ecc %u, buswidth %u\n",
+ rawnand_dev.nand_dev->page_size,
+ rawnand_dev.nand_dev->block_size, rawnand_dev.nand_dev->size,
+ rawnand_dev.nand_dev->ecc.max_bit_corr,
+ rawnand_dev.nand_dev->buswidth);
+
+ return 0;
+}
+
+static int detect_onfi(void)
+{
+ int ret;
+ char id[4];
+
+ ret = nand_reset();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = nand_read_id(ONFI_SIGNATURE_ADDR, (uint8_t *)id, sizeof(id));
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (strncmp(id, "ONFI", sizeof(id)) != 0) {
+ WARN("NAND Non ONFI detected\n");
+ return -ENODEV;
+ }
+
+ return nand_read_param_page();
+}
+#endif
+
+static int nand_mtd_block_is_bad(unsigned int block)
+{
+ unsigned int nbpages_per_block = rawnand_dev.nand_dev->block_size /
+ rawnand_dev.nand_dev->page_size;
+ uint8_t bbm_marker[2];
+ uint8_t page;
+ int ret;
+
+ for (page = 0U; page < 2U; page++) {
+ ret = nand_read_page_cmd(block * nbpages_per_block,
+ rawnand_dev.nand_dev->page_size,
+ (uintptr_t)bbm_marker,
+ sizeof(bbm_marker));
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((bbm_marker[0] != GENMASK_32(7, 0)) ||
+ (bbm_marker[1] != GENMASK_32(7, 0))) {
+ WARN("Block %u is bad\n", block);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int nand_mtd_read_page_raw(struct nand_device *nand, unsigned int page,
+ uintptr_t buffer)
+{
+ return nand_read_page_cmd(page, 0U, buffer,
+ rawnand_dev.nand_dev->page_size);
+}
+
+void nand_raw_ctrl_init(const struct nand_ctrl_ops *ops)
+{
+ rawnand_dev.ops = ops;
+}
+
+int nand_raw_init(unsigned long long *size, unsigned int *erase_size)
+{
+ rawnand_dev.nand_dev = get_nand_device();
+ if (rawnand_dev.nand_dev == NULL) {
+ return -EINVAL;
+ }
+
+ rawnand_dev.nand_dev->mtd_block_is_bad = nand_mtd_block_is_bad;
+ rawnand_dev.nand_dev->mtd_read_page = nand_mtd_read_page_raw;
+ rawnand_dev.nand_dev->ecc.mode = NAND_ECC_NONE;
+
+ if ((rawnand_dev.ops->setup == NULL) ||
+ (rawnand_dev.ops->exec == NULL)) {
+ return -ENODEV;
+ }
+
+#if NAND_ONFI_DETECT
+ if (detect_onfi() != 0) {
+ WARN("Detect ONFI failed\n");
+ }
+#endif
+
+ if (plat_get_raw_nand_data(&rawnand_dev) != 0) {
+ return -EINVAL;
+ }
+
+ assert((rawnand_dev.nand_dev->page_size != 0U) &&
+ (rawnand_dev.nand_dev->block_size != 0U) &&
+ (rawnand_dev.nand_dev->size != 0U));
+
+ *size = rawnand_dev.nand_dev->size;
+ *erase_size = rawnand_dev.nand_dev->block_size;
+
+ rawnand_dev.ops->setup(rawnand_dev.nand_dev);
+
+ return 0;
+}
diff --git a/drivers/mtd/nand/spi_nand.c b/drivers/mtd/nand/spi_nand.c
new file mode 100644
index 0000000..542b614
--- /dev/null
+++ b/drivers/mtd/nand/spi_nand.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/spi_nand.h>
+#include <lib/utils.h>
+
+#include <platform_def.h>
+
+#define SPI_NAND_MAX_ID_LEN 4U
+#define DELAY_US_400MS 400000U
+#define MACRONIX_ID 0xC2U
+
+static struct spinand_device spinand_dev;
+
+#pragma weak plat_get_spi_nand_data
+int plat_get_spi_nand_data(struct spinand_device *device)
+{
+ return 0;
+}
+
+static int spi_nand_reg(bool read_reg, uint8_t reg, uint8_t *val,
+ enum spi_mem_data_dir dir)
+{
+ struct spi_mem_op op;
+
+ zeromem(&op, sizeof(struct spi_mem_op));
+ if (read_reg) {
+ op.cmd.opcode = SPI_NAND_OP_GET_FEATURE;
+ } else {
+ op.cmd.opcode = SPI_NAND_OP_SET_FEATURE;
+ }
+
+ op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.addr.val = reg;
+ op.addr.nbytes = 1U;
+ op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.data.dir = dir;
+ op.data.nbytes = 1U;
+ op.data.buf = val;
+
+ return spi_mem_exec_op(&op);
+}
+
+static int spi_nand_read_reg(uint8_t reg, uint8_t *val)
+{
+ return spi_nand_reg(true, reg, val, SPI_MEM_DATA_IN);
+}
+
+static int spi_nand_write_reg(uint8_t reg, uint8_t val)
+{
+ return spi_nand_reg(false, reg, &val, SPI_MEM_DATA_OUT);
+}
+
+static int spi_nand_update_cfg(uint8_t mask, uint8_t val)
+{
+ int ret;
+ uint8_t cfg = spinand_dev.cfg_cache;
+
+ cfg &= ~mask;
+ cfg |= val;
+
+ if (cfg == spinand_dev.cfg_cache) {
+ return 0;
+ }
+
+ ret = spi_nand_write_reg(SPI_NAND_REG_CFG, cfg);
+ if (ret == 0) {
+ spinand_dev.cfg_cache = cfg;
+ }
+
+ return ret;
+}
+
+static int spi_nand_ecc_enable(bool enable)
+{
+ return spi_nand_update_cfg(SPI_NAND_CFG_ECC_EN,
+ enable ? SPI_NAND_CFG_ECC_EN : 0U);
+}
+
+static int spi_nand_quad_enable(uint8_t manufacturer_id)
+{
+ bool enable = false;
+
+ if (manufacturer_id != MACRONIX_ID) {
+ return 0;
+ }
+
+ if (spinand_dev.spi_read_cache_op.data.buswidth ==
+ SPI_MEM_BUSWIDTH_4_LINE) {
+ enable = true;
+ }
+
+ return spi_nand_update_cfg(SPI_NAND_CFG_QE,
+ enable ? SPI_NAND_CFG_QE : 0U);
+}
+
+static int spi_nand_wait_ready(uint8_t *status)
+{
+ int ret;
+ uint64_t timeout = timeout_init_us(DELAY_US_400MS);
+
+ while (!timeout_elapsed(timeout)) {
+ ret = spi_nand_read_reg(SPI_NAND_REG_STATUS, status);
+ if (ret != 0) {
+ return ret;
+ }
+
+ VERBOSE("%s Status %x\n", __func__, *status);
+ if ((*status & SPI_NAND_STATUS_BUSY) == 0U) {
+ return 0;
+ }
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int spi_nand_reset(void)
+{
+ struct spi_mem_op op;
+ uint8_t status;
+ int ret;
+
+ zeromem(&op, sizeof(struct spi_mem_op));
+ op.cmd.opcode = SPI_NAND_OP_RESET;
+ op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+
+ ret = spi_mem_exec_op(&op);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return spi_nand_wait_ready(&status);
+}
+
+static int spi_nand_read_id(uint8_t *id)
+{
+ struct spi_mem_op op;
+
+ zeromem(&op, sizeof(struct spi_mem_op));
+ op.cmd.opcode = SPI_NAND_OP_READ_ID;
+ op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.data.dir = SPI_MEM_DATA_IN;
+ op.data.nbytes = SPI_NAND_MAX_ID_LEN;
+ op.data.buf = id;
+ op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+
+ return spi_mem_exec_op(&op);
+}
+
+static int spi_nand_load_page(unsigned int page)
+{
+ struct spi_mem_op op;
+ uint32_t block_nb = page / spinand_dev.nand_dev->block_size;
+ uint32_t page_nb = page - (block_nb * spinand_dev.nand_dev->page_size);
+ uint32_t nbpages_per_block = spinand_dev.nand_dev->block_size /
+ spinand_dev.nand_dev->page_size;
+ uint32_t block_sh = __builtin_ctz(nbpages_per_block) + 1U;
+
+ zeromem(&op, sizeof(struct spi_mem_op));
+ op.cmd.opcode = SPI_NAND_OP_LOAD_PAGE;
+ op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.addr.val = (block_nb << block_sh) | page_nb;
+ op.addr.nbytes = 3U;
+ op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+
+ return spi_mem_exec_op(&op);
+}
+
+static int spi_nand_read_from_cache(unsigned int page, unsigned int offset,
+ uint8_t *buffer, unsigned int len)
+{
+ uint32_t nbpages_per_block = spinand_dev.nand_dev->block_size /
+ spinand_dev.nand_dev->page_size;
+ uint32_t block_nb = page / nbpages_per_block;
+ uint32_t page_sh = __builtin_ctz(spinand_dev.nand_dev->page_size) + 1U;
+
+ spinand_dev.spi_read_cache_op.addr.val = offset;
+
+ if ((spinand_dev.nand_dev->nb_planes > 1U) && ((block_nb % 2U) == 1U)) {
+ spinand_dev.spi_read_cache_op.addr.val |= 1U << page_sh;
+ }
+
+ spinand_dev.spi_read_cache_op.data.buf = buffer;
+ spinand_dev.spi_read_cache_op.data.nbytes = len;
+
+ return spi_mem_exec_op(&spinand_dev.spi_read_cache_op);
+}
+
+static int spi_nand_read_page(unsigned int page, unsigned int offset,
+ uint8_t *buffer, unsigned int len,
+ bool ecc_enabled)
+{
+ uint8_t status;
+ int ret;
+
+ ret = spi_nand_ecc_enable(ecc_enabled);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nand_load_page(page);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nand_wait_ready(&status);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nand_read_from_cache(page, offset, buffer, len);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (ecc_enabled && ((status & SPI_NAND_STATUS_ECC_UNCOR) != 0U)) {
+ return -EBADMSG;
+ }
+
+ return 0;
+}
+
+static int spi_nand_mtd_block_is_bad(unsigned int block)
+{
+ unsigned int nbpages_per_block = spinand_dev.nand_dev->block_size /
+ spinand_dev.nand_dev->page_size;
+ uint8_t bbm_marker[2];
+ int ret;
+
+ ret = spi_nand_read_page(block * nbpages_per_block,
+ spinand_dev.nand_dev->page_size,
+ bbm_marker, sizeof(bbm_marker), false);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((bbm_marker[0] != GENMASK_32(7, 0)) ||
+ (bbm_marker[1] != GENMASK_32(7, 0))) {
+ WARN("Block %u is bad\n", block);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int spi_nand_mtd_read_page(struct nand_device *nand, unsigned int page,
+ uintptr_t buffer)
+{
+ return spi_nand_read_page(page, 0, (uint8_t *)buffer,
+ spinand_dev.nand_dev->page_size, true);
+}
+
+int spi_nand_init(unsigned long long *size, unsigned int *erase_size)
+{
+ uint8_t id[SPI_NAND_MAX_ID_LEN];
+ int ret;
+
+ spinand_dev.nand_dev = get_nand_device();
+ if (spinand_dev.nand_dev == NULL) {
+ return -EINVAL;
+ }
+
+ spinand_dev.nand_dev->mtd_block_is_bad = spi_nand_mtd_block_is_bad;
+ spinand_dev.nand_dev->mtd_read_page = spi_nand_mtd_read_page;
+ spinand_dev.nand_dev->nb_planes = 1;
+
+ spinand_dev.spi_read_cache_op.cmd.opcode = SPI_NAND_OP_READ_FROM_CACHE;
+ spinand_dev.spi_read_cache_op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ spinand_dev.spi_read_cache_op.addr.nbytes = 2U;
+ spinand_dev.spi_read_cache_op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ spinand_dev.spi_read_cache_op.dummy.nbytes = 1U;
+ spinand_dev.spi_read_cache_op.dummy.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ spinand_dev.spi_read_cache_op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+
+ if (plat_get_spi_nand_data(&spinand_dev) != 0) {
+ return -EINVAL;
+ }
+
+ assert((spinand_dev.nand_dev->page_size != 0U) &&
+ (spinand_dev.nand_dev->block_size != 0U) &&
+ (spinand_dev.nand_dev->size != 0U));
+
+ ret = spi_nand_reset();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nand_read_id(id);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nand_read_reg(SPI_NAND_REG_CFG, &spinand_dev.cfg_cache);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nand_quad_enable(id[1]);
+ if (ret != 0) {
+ return ret;
+ }
+
+ VERBOSE("SPI_NAND Detected ID 0x%x\n", id[1]);
+
+ VERBOSE("Page size %u, Block size %u, size %llu\n",
+ spinand_dev.nand_dev->page_size,
+ spinand_dev.nand_dev->block_size,
+ spinand_dev.nand_dev->size);
+
+ *size = spinand_dev.nand_dev->size;
+ *erase_size = spinand_dev.nand_dev->block_size;
+
+ return 0;
+}
diff --git a/drivers/mtd/nor/spi_nor.c b/drivers/mtd/nor/spi_nor.c
new file mode 100644
index 0000000..2e34344
--- /dev/null
+++ b/drivers/mtd/nor/spi_nor.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/spi_nor.h>
+#include <lib/utils.h>
+
+#define SR_WIP BIT(0) /* Write in progress */
+#define CR_QUAD_EN_SPAN BIT(1) /* Spansion Quad I/O */
+#define SR_QUAD_EN_MX BIT(6) /* Macronix Quad I/O */
+#define FSR_READY BIT(7) /* Device status, 0 = Busy, 1 = Ready */
+
+/* Defined IDs for supported memories */
+#define SPANSION_ID 0x01U
+#define MACRONIX_ID 0xC2U
+#define MICRON_ID 0x2CU
+
+#define BANK_SIZE 0x1000000U
+
+#define SPI_READY_TIMEOUT_US 40000U
+
+static struct nor_device nor_dev;
+
+#pragma weak plat_get_nor_data
+int plat_get_nor_data(struct nor_device *device)
+{
+ return 0;
+}
+
+static int spi_nor_reg(uint8_t reg, uint8_t *buf, size_t len,
+ enum spi_mem_data_dir dir)
+{
+ struct spi_mem_op op;
+
+ zeromem(&op, sizeof(struct spi_mem_op));
+ op.cmd.opcode = reg;
+ op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.data.dir = dir;
+ op.data.nbytes = len;
+ op.data.buf = buf;
+
+ return spi_mem_exec_op(&op);
+}
+
+static inline int spi_nor_read_id(uint8_t *id)
+{
+ return spi_nor_reg(SPI_NOR_OP_READ_ID, id, 1U, SPI_MEM_DATA_IN);
+}
+
+static inline int spi_nor_read_cr(uint8_t *cr)
+{
+ return spi_nor_reg(SPI_NOR_OP_READ_CR, cr, 1U, SPI_MEM_DATA_IN);
+}
+
+static inline int spi_nor_read_sr(uint8_t *sr)
+{
+ return spi_nor_reg(SPI_NOR_OP_READ_SR, sr, 1U, SPI_MEM_DATA_IN);
+}
+
+static inline int spi_nor_read_fsr(uint8_t *fsr)
+{
+ return spi_nor_reg(SPI_NOR_OP_READ_FSR, fsr, 1U, SPI_MEM_DATA_IN);
+}
+
+static inline int spi_nor_write_en(void)
+{
+ return spi_nor_reg(SPI_NOR_OP_WREN, NULL, 0U, SPI_MEM_DATA_OUT);
+}
+
+/*
+ * Check if device is ready.
+ *
+ * Return 0 if ready, 1 if busy or a negative error code otherwise
+ */
+static int spi_nor_ready(void)
+{
+ uint8_t sr;
+ int ret;
+
+ ret = spi_nor_read_sr(&sr);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((nor_dev.flags & SPI_NOR_USE_FSR) != 0U) {
+ uint8_t fsr;
+
+ ret = spi_nor_read_fsr(&fsr);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return (((fsr & FSR_READY) != 0U) && ((sr & SR_WIP) == 0U)) ?
+ 0 : 1;
+ }
+
+ return (((sr & SR_WIP) == 0U) ? 0 : 1);
+}
+
+static int spi_nor_wait_ready(void)
+{
+ int ret;
+ uint64_t timeout = timeout_init_us(SPI_READY_TIMEOUT_US);
+
+ while (!timeout_elapsed(timeout)) {
+ ret = spi_nor_ready();
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int spi_nor_macronix_quad_enable(void)
+{
+ uint8_t sr;
+ int ret;
+
+ ret = spi_nor_read_sr(&sr);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((sr & SR_QUAD_EN_MX) != 0U) {
+ return 0;
+ }
+
+ ret = spi_nor_write_en();
+ if (ret != 0) {
+ return ret;
+ }
+
+ sr |= SR_QUAD_EN_MX;
+ ret = spi_nor_reg(SPI_NOR_OP_WRSR, &sr, 1U, SPI_MEM_DATA_OUT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nor_wait_ready();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nor_read_sr(&sr);
+ if ((ret != 0) || ((sr & SR_QUAD_EN_MX) == 0U)) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int spi_nor_write_sr_cr(uint8_t *sr_cr)
+{
+ int ret;
+
+ ret = spi_nor_write_en();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nor_reg(SPI_NOR_OP_WRSR, sr_cr, 2U, SPI_MEM_DATA_OUT);
+ if (ret != 0) {
+ return -EINVAL;
+ }
+
+ ret = spi_nor_wait_ready();
+ if (ret != 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+static int spi_nor_quad_enable(void)
+{
+ uint8_t sr_cr[2];
+ int ret;
+
+ ret = spi_nor_read_cr(&sr_cr[1]);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((sr_cr[1] & CR_QUAD_EN_SPAN) != 0U) {
+ return 0;
+ }
+
+ sr_cr[1] |= CR_QUAD_EN_SPAN;
+ ret = spi_nor_read_sr(&sr_cr[0]);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nor_write_sr_cr(sr_cr);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nor_read_cr(&sr_cr[1]);
+ if ((ret != 0) || ((sr_cr[1] & CR_QUAD_EN_SPAN) == 0U)) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int spi_nor_clean_bar(void)
+{
+ int ret;
+
+ if (nor_dev.selected_bank == 0U) {
+ return 0;
+ }
+
+ nor_dev.selected_bank = 0U;
+
+ ret = spi_nor_write_en();
+ if (ret != 0) {
+ return ret;
+ }
+
+ return spi_nor_reg(nor_dev.bank_write_cmd, &nor_dev.selected_bank,
+ 1U, SPI_MEM_DATA_OUT);
+}
+
+static int spi_nor_write_bar(uint32_t offset)
+{
+ uint8_t selected_bank = offset / BANK_SIZE;
+ int ret;
+
+ if (selected_bank == nor_dev.selected_bank) {
+ return 0;
+ }
+
+ ret = spi_nor_write_en();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nor_reg(nor_dev.bank_write_cmd, &selected_bank,
+ 1U, SPI_MEM_DATA_OUT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ nor_dev.selected_bank = selected_bank;
+
+ return 0;
+}
+
+static int spi_nor_read_bar(void)
+{
+ uint8_t selected_bank = 0U;
+ int ret;
+
+ ret = spi_nor_reg(nor_dev.bank_read_cmd, &selected_bank,
+ 1U, SPI_MEM_DATA_IN);
+ if (ret != 0) {
+ return ret;
+ }
+
+ nor_dev.selected_bank = selected_bank;
+
+ return 0;
+}
+
+int spi_nor_read(unsigned int offset, uintptr_t buffer, size_t length,
+ size_t *length_read)
+{
+ size_t remain_len;
+ int ret;
+
+ *length_read = 0U;
+ nor_dev.read_op.addr.val = offset;
+ nor_dev.read_op.data.buf = (void *)buffer;
+
+ VERBOSE("%s offset %u length %zu\n", __func__, offset, length);
+
+ while (length != 0U) {
+ if ((nor_dev.flags & SPI_NOR_USE_BANK) != 0U) {
+ ret = spi_nor_write_bar(nor_dev.read_op.addr.val);
+ if (ret != 0) {
+ return ret;
+ }
+
+ remain_len = (BANK_SIZE * (nor_dev.selected_bank + 1)) -
+ nor_dev.read_op.addr.val;
+ nor_dev.read_op.data.nbytes = MIN(length, remain_len);
+ } else {
+ nor_dev.read_op.data.nbytes = length;
+ }
+
+ ret = spi_mem_exec_op(&nor_dev.read_op);
+ if (ret != 0) {
+ spi_nor_clean_bar();
+ return ret;
+ }
+
+ length -= nor_dev.read_op.data.nbytes;
+ nor_dev.read_op.addr.val += nor_dev.read_op.data.nbytes;
+ nor_dev.read_op.data.buf += nor_dev.read_op.data.nbytes;
+ *length_read += nor_dev.read_op.data.nbytes;
+ }
+
+ if ((nor_dev.flags & SPI_NOR_USE_BANK) != 0U) {
+ ret = spi_nor_clean_bar();
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int spi_nor_init(unsigned long long *size, unsigned int *erase_size)
+{
+ int ret;
+ uint8_t id;
+
+ /* Default read command used */
+ nor_dev.read_op.cmd.opcode = SPI_NOR_OP_READ;
+ nor_dev.read_op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ nor_dev.read_op.addr.nbytes = 3U;
+ nor_dev.read_op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ nor_dev.read_op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ nor_dev.read_op.data.dir = SPI_MEM_DATA_IN;
+
+ if (plat_get_nor_data(&nor_dev) != 0) {
+ return -EINVAL;
+ }
+
+ assert(nor_dev.size != 0U);
+
+ if (nor_dev.size > BANK_SIZE) {
+ nor_dev.flags |= SPI_NOR_USE_BANK;
+ }
+
+ *size = nor_dev.size;
+
+ ret = spi_nor_read_id(&id);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((nor_dev.flags & SPI_NOR_USE_BANK) != 0U) {
+ switch (id) {
+ case SPANSION_ID:
+ nor_dev.bank_read_cmd = SPINOR_OP_BRRD;
+ nor_dev.bank_write_cmd = SPINOR_OP_BRWR;
+ break;
+ default:
+ nor_dev.bank_read_cmd = SPINOR_OP_RDEAR;
+ nor_dev.bank_write_cmd = SPINOR_OP_WREAR;
+ break;
+ }
+ }
+
+ if (nor_dev.read_op.data.buswidth == 4U) {
+ switch (id) {
+ case MACRONIX_ID:
+ INFO("Enable Macronix quad support\n");
+ ret = spi_nor_macronix_quad_enable();
+ break;
+ case MICRON_ID:
+ break;
+ default:
+ ret = spi_nor_quad_enable();
+ break;
+ }
+ }
+
+ if ((ret == 0) && ((nor_dev.flags & SPI_NOR_USE_BANK) != 0U)) {
+ ret = spi_nor_read_bar();
+ }
+
+ return ret;
+}
diff --git a/drivers/mtd/spi-mem/spi_mem.c b/drivers/mtd/spi-mem/spi_mem.c
new file mode 100644
index 0000000..c43d519
--- /dev/null
+++ b/drivers/mtd/spi-mem/spi_mem.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+#include <drivers/spi_mem.h>
+#include <lib/utils_def.h>
+#include <libfdt.h>
+
+#define SPI_MEM_DEFAULT_SPEED_HZ 100000U
+
+/*
+ * struct spi_slave - Representation of a SPI slave.
+ *
+ * @max_hz: Maximum speed for this slave in Hertz.
+ * @cs: ID of the chip select connected to the slave.
+ * @mode: SPI mode to use for this slave (see SPI mode flags).
+ * @ops: Ops defined by the bus.
+ */
+struct spi_slave {
+ unsigned int max_hz;
+ unsigned int cs;
+ unsigned int mode;
+ const struct spi_bus_ops *ops;
+};
+
+static struct spi_slave spi_slave;
+
+static bool spi_mem_check_buswidth_req(uint8_t buswidth, bool tx)
+{
+ switch (buswidth) {
+ case 1U:
+ return true;
+
+ case 2U:
+ if ((tx && (spi_slave.mode & (SPI_TX_DUAL | SPI_TX_QUAD)) !=
+ 0U) ||
+ (!tx && (spi_slave.mode & (SPI_RX_DUAL | SPI_RX_QUAD)) !=
+ 0U)) {
+ return true;
+ }
+ break;
+
+ case 4U:
+ if ((tx && (spi_slave.mode & SPI_TX_QUAD) != 0U) ||
+ (!tx && (spi_slave.mode & SPI_RX_QUAD) != 0U)) {
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static bool spi_mem_supports_op(const struct spi_mem_op *op)
+{
+ if (!spi_mem_check_buswidth_req(op->cmd.buswidth, true)) {
+ return false;
+ }
+
+ if ((op->addr.nbytes != 0U) &&
+ !spi_mem_check_buswidth_req(op->addr.buswidth, true)) {
+ return false;
+ }
+
+ if ((op->dummy.nbytes != 0U) &&
+ !spi_mem_check_buswidth_req(op->dummy.buswidth, true)) {
+ return false;
+ }
+
+ if ((op->data.nbytes != 0U) &&
+ !spi_mem_check_buswidth_req(op->data.buswidth,
+ op->data.dir == SPI_MEM_DATA_OUT)) {
+ return false;
+ }
+
+ return true;
+}
+
+static int spi_mem_set_speed_mode(void)
+{
+ const struct spi_bus_ops *ops = spi_slave.ops;
+ int ret;
+
+ ret = ops->set_speed(spi_slave.max_hz);
+ if (ret != 0) {
+ VERBOSE("Cannot set speed (err=%d)\n", ret);
+ return ret;
+ }
+
+ ret = ops->set_mode(spi_slave.mode);
+ if (ret != 0) {
+ VERBOSE("Cannot set mode (err=%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int spi_mem_check_bus_ops(const struct spi_bus_ops *ops)
+{
+ bool error = false;
+
+ if (ops->claim_bus == NULL) {
+ VERBOSE("Ops claim bus is not defined\n");
+ error = true;
+ }
+
+ if (ops->release_bus == NULL) {
+ VERBOSE("Ops release bus is not defined\n");
+ error = true;
+ }
+
+ if (ops->exec_op == NULL) {
+ VERBOSE("Ops exec op is not defined\n");
+ error = true;
+ }
+
+ if (ops->set_speed == NULL) {
+ VERBOSE("Ops set speed is not defined\n");
+ error = true;
+ }
+
+ if (ops->set_mode == NULL) {
+ VERBOSE("Ops set mode is not defined\n");
+ error = true;
+ }
+
+ return error ? -EINVAL : 0;
+}
+
+/*
+ * spi_mem_exec_op() - Execute a memory operation.
+ * @op: The memory operation to execute.
+ *
+ * This function first checks that @op is supported and then tries to execute
+ * it.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int spi_mem_exec_op(const struct spi_mem_op *op)
+{
+ const struct spi_bus_ops *ops = spi_slave.ops;
+ int ret;
+
+ VERBOSE("%s: cmd:%x mode:%d.%d.%d.%d addqr:%" PRIx64 " len:%x\n",
+ __func__, op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
+ op->dummy.buswidth, op->data.buswidth,
+ op->addr.val, op->data.nbytes);
+
+ if (!spi_mem_supports_op(op)) {
+ WARN("Error in spi_mem_support\n");
+ return -ENOTSUP;
+ }
+
+ ret = ops->claim_bus(spi_slave.cs);
+ if (ret != 0) {
+ WARN("Error claim_bus\n");
+ return ret;
+ }
+
+ ret = ops->exec_op(op);
+
+ ops->release_bus();
+
+ return ret;
+}
+
+/*
+ * spi_mem_init_slave() - SPI slave device initialization.
+ * @fdt: Pointer to the device tree blob.
+ * @bus_node: Offset of the bus node.
+ * @ops: The SPI bus ops defined.
+ *
+ * This function first checks that @ops are supported and then tries to find
+ * a SPI slave device.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int spi_mem_init_slave(void *fdt, int bus_node, const struct spi_bus_ops *ops)
+{
+ int ret;
+ int mode = 0;
+ int nchips = 0;
+ int bus_subnode = 0;
+ const fdt32_t *cuint = NULL;
+
+ ret = spi_mem_check_bus_ops(ops);
+ if (ret != 0) {
+ return ret;
+ }
+
+ fdt_for_each_subnode(bus_subnode, fdt, bus_node) {
+ nchips++;
+ }
+
+ if (nchips != 1) {
+ ERROR("Only one SPI device is currently supported\n");
+ return -EINVAL;
+ }
+
+ fdt_for_each_subnode(bus_subnode, fdt, bus_node) {
+ /* Get chip select */
+ cuint = fdt_getprop(fdt, bus_subnode, "reg", NULL);
+ if (cuint == NULL) {
+ ERROR("Chip select not well defined\n");
+ return -EINVAL;
+ }
+ spi_slave.cs = fdt32_to_cpu(*cuint);
+
+ /* Get max slave frequency */
+ spi_slave.max_hz = SPI_MEM_DEFAULT_SPEED_HZ;
+ cuint = fdt_getprop(fdt, bus_subnode,
+ "spi-max-frequency", NULL);
+ if (cuint != NULL) {
+ spi_slave.max_hz = fdt32_to_cpu(*cuint);
+ }
+
+ /* Get mode */
+ if ((fdt_getprop(fdt, bus_subnode, "spi-cpol", NULL)) != NULL) {
+ mode |= SPI_CPOL;
+ }
+ if ((fdt_getprop(fdt, bus_subnode, "spi-cpha", NULL)) != NULL) {
+ mode |= SPI_CPHA;
+ }
+ if ((fdt_getprop(fdt, bus_subnode, "spi-cs-high", NULL)) !=
+ NULL) {
+ mode |= SPI_CS_HIGH;
+ }
+ if ((fdt_getprop(fdt, bus_subnode, "spi-3wire", NULL)) !=
+ NULL) {
+ mode |= SPI_3WIRE;
+ }
+ if ((fdt_getprop(fdt, bus_subnode, "spi-half-duplex", NULL)) !=
+ NULL) {
+ mode |= SPI_PREAMBLE;
+ }
+
+ /* Get dual/quad mode */
+ cuint = fdt_getprop(fdt, bus_subnode, "spi-tx-bus-width", NULL);
+ if (cuint != NULL) {
+ switch (fdt32_to_cpu(*cuint)) {
+ case 1U:
+ break;
+ case 2U:
+ mode |= SPI_TX_DUAL;
+ break;
+ case 4U:
+ mode |= SPI_TX_QUAD;
+ break;
+ default:
+ WARN("spi-tx-bus-width %u not supported\n",
+ fdt32_to_cpu(*cuint));
+ return -EINVAL;
+ }
+ }
+
+ cuint = fdt_getprop(fdt, bus_subnode, "spi-rx-bus-width", NULL);
+ if (cuint != NULL) {
+ switch (fdt32_to_cpu(*cuint)) {
+ case 1U:
+ break;
+ case 2U:
+ mode |= SPI_RX_DUAL;
+ break;
+ case 4U:
+ mode |= SPI_RX_QUAD;
+ break;
+ default:
+ WARN("spi-rx-bus-width %u not supported\n",
+ fdt32_to_cpu(*cuint));
+ return -EINVAL;
+ }
+ }
+
+ spi_slave.mode = mode;
+ spi_slave.ops = ops;
+ }
+
+ return spi_mem_set_speed_mode();
+}
diff --git a/drivers/nxp/auth/csf_hdr_parser/cot.c b/drivers/nxp/auth/csf_hdr_parser/cot.c
new file mode 100644
index 0000000..4502ed6
--- /dev/null
+++ b/drivers/nxp/auth/csf_hdr_parser/cot.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <drivers/auth/auth_mod.h>
+
+#if USE_TBBR_DEFS
+#include <tools_share/tbbr_oid.h>
+#else
+#include <platform_oid.h>
+#endif
+
+
+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 sig_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, 0);
+
+static auth_param_type_desc_t non_trusted_world_pk = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_PUB_KEY, NON_TRUSTED_WORLD_PK_OID);
+
+/*
+ * TBBR Chain of trust definition
+ */
+static const auth_img_desc_t bl31_image = {
+ .img_id = BL31_IMAGE_ID,
+ .img_type = IMG_PLAT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &non_trusted_world_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &sig_hash
+ }
+ }
+ }
+};
+static const auth_img_desc_t scp_bl2_image = {
+ .img_id = SCP_BL2_IMAGE_ID,
+ .img_type = IMG_PLAT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &non_trusted_world_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &sig_hash
+ }
+ }
+ }
+};
+static const auth_img_desc_t bl32_image = {
+ .img_id = BL32_IMAGE_ID,
+ .img_type = IMG_PLAT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &non_trusted_world_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &sig_hash
+ }
+ }
+ }
+};
+static const auth_img_desc_t bl33_image = {
+ .img_id = BL33_IMAGE_ID,
+ .img_type = IMG_PLAT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &non_trusted_world_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &sig_hash
+ }
+ }
+ }
+};
+#ifdef POLICY_FUSE_PROVISION
+static const auth_img_desc_t fuse_prov_img = {
+ .img_id = FUSE_PROV_IMAGE_ID,
+ .img_type = IMG_PLAT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &non_trusted_world_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &sig_hash
+ }
+ }
+ }
+};
+static const auth_img_desc_t fuse_upgrade_img = {
+ .img_id = FUSE_UP_IMAGE_ID,
+ .img_type = IMG_PLAT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &non_trusted_world_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &sig_hash
+ }
+ }
+ }
+};
+#endif
+#ifdef CONFIG_DDR_FIP_IMAGE
+static const auth_img_desc_t ddr_imem_udimm_1d_img = {
+ .img_id = DDR_IMEM_UDIMM_1D_IMAGE_ID,
+ .img_type = IMG_PLAT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &non_trusted_world_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &sig_hash
+ }
+ }
+ }
+};
+static const auth_img_desc_t ddr_imem_udimm_2d_img = {
+ .img_id = DDR_IMEM_UDIMM_2D_IMAGE_ID,
+ .img_type = IMG_PLAT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &non_trusted_world_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &sig_hash
+ }
+ }
+ }
+};
+static const auth_img_desc_t ddr_dmem_udimm_1d_img = {
+ .img_id = DDR_DMEM_UDIMM_1D_IMAGE_ID,
+ .img_type = IMG_PLAT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &non_trusted_world_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &sig_hash
+ }
+ }
+ }
+};
+static const auth_img_desc_t ddr_dmem_udimm_2d_img = {
+ .img_id = DDR_DMEM_UDIMM_2D_IMAGE_ID,
+ .img_type = IMG_PLAT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &non_trusted_world_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &sig_hash
+ }
+ }
+ }
+};
+static const auth_img_desc_t ddr_imem_rdimm_1d_img = {
+ .img_id = DDR_IMEM_RDIMM_1D_IMAGE_ID,
+ .img_type = IMG_PLAT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &non_trusted_world_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &sig_hash
+ }
+ }
+ }
+};
+static const auth_img_desc_t ddr_imem_rdimm_2d_img = {
+ .img_id = DDR_IMEM_RDIMM_2D_IMAGE_ID,
+ .img_type = IMG_PLAT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &non_trusted_world_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &sig_hash
+ }
+ }
+ }
+};
+static const auth_img_desc_t ddr_dmem_rdimm_1d_img = {
+ .img_id = DDR_DMEM_RDIMM_1D_IMAGE_ID,
+ .img_type = IMG_PLAT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &non_trusted_world_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &sig_hash
+ }
+ }
+ }
+};
+static const auth_img_desc_t ddr_dmem_rdimm_2d_img = {
+ .img_id = DDR_DMEM_RDIMM_2D_IMAGE_ID,
+ .img_type = IMG_PLAT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &non_trusted_world_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &sig_hash
+ }
+ }
+ }
+};
+#endif
+
+static const auth_img_desc_t * const cot_desc[] = {
+ [BL31_IMAGE_ID] = &bl31_image,
+ [SCP_BL2_IMAGE_ID] = &scp_bl2_image,
+ [BL32_IMAGE_ID] = &bl32_image,
+ [BL33_IMAGE_ID] = &bl33_image,
+#ifdef POLICY_FUSE_PROVISION
+ [FUSE_PROV_IMAGE_ID] = &fuse_prov_img,
+ [FUSE_UP_IMAGE_ID] = &fuse_upgrade_img,
+#endif
+#ifdef CONFIG_DDR_FIP_IMAGE
+ [DDR_IMEM_UDIMM_1D_IMAGE_ID] = &ddr_imem_udimm_1d_img,
+ [DDR_IMEM_UDIMM_2D_IMAGE_ID] = &ddr_imem_udimm_2d_img,
+ [DDR_DMEM_UDIMM_1D_IMAGE_ID] = &ddr_dmem_udimm_1d_img,
+ [DDR_DMEM_UDIMM_2D_IMAGE_ID] = &ddr_dmem_udimm_2d_img,
+ [DDR_IMEM_RDIMM_1D_IMAGE_ID] = &ddr_imem_rdimm_1d_img,
+ [DDR_IMEM_RDIMM_2D_IMAGE_ID] = &ddr_imem_rdimm_2d_img,
+ [DDR_DMEM_RDIMM_1D_IMAGE_ID] = &ddr_dmem_rdimm_1d_img,
+ [DDR_DMEM_RDIMM_2D_IMAGE_ID] = &ddr_dmem_rdimm_2d_img,
+#endif
+};
+
+/* Register the CoT in the authentication module */
+REGISTER_COT(cot_desc);
diff --git a/drivers/nxp/auth/csf_hdr_parser/csf_hdr.mk b/drivers/nxp/auth/csf_hdr_parser/csf_hdr.mk
new file mode 100644
index 0000000..1af51f8
--- /dev/null
+++ b/drivers/nxp/auth/csf_hdr_parser/csf_hdr.mk
@@ -0,0 +1,64 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+
+CSF_HDR_SOURCES := $(PLAT_DRIVERS_PATH)/auth/csf_hdr_parser/csf_hdr_parser.c
+
+CSF_HDR_SOURCES += $(PLAT_DRIVERS_PATH)/auth/csf_hdr_parser/plat_img_parser.c
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/auth/csf_hdr_parser/
+
+$(eval $(call add_define, CSF_HEADER_PREPENDED))
+
+
+# Path to CST directory is required to generate the CSF header
+# and prepend it to image before fip image gets generated
+ifeq (${CST_DIR},)
+ $(error Error: CST_DIR not set)
+endif
+
+# Rules are created for generating and appending CSF header to images before
+# FIT image generation
+
+# CST_BL31
+define CST_BL31_RULE
+$(1): $(2)
+ @echo " Generating CSF Header for $$@ $$<"
+ $(Q)$(CST_DIR)/create_hdr_esbc --in $(2) --out $(1) --app_off ${CSF_HDR_SZ} \
+ --app $(2) ${BL31_INPUT_FILE}
+endef
+
+CST_BL31_SUFFIX := .cst
+
+# CST_BL32
+define CST_BL32_RULE
+$(1): $(2)
+ @echo " Generating CSF Header for $$@ $$<"
+ $(Q)$(CST_DIR)/create_hdr_esbc --in $(2) --out $(1) --app_off ${CSF_HDR_SZ} \
+ --app $(2) ${BL32_INPUT_FILE}
+endef
+
+CST_BL32_SUFFIX := .cst
+
+# CST_BL33
+define CST_BL33_RULE
+$(1): $(2)
+ @echo " Generating CSF Header for $$@ $$<"
+ $(Q)$(CST_DIR)/create_hdr_esbc --in $(2) --out $(1) --app_off ${CSF_HDR_SZ} \
+ --app $(2) ${BL33_INPUT_FILE}
+endef
+
+CST_BL33_SUFFIX := .cst
+
+# CST_SCP_BL2
+define CST_SCP_BL2_RULE
+$(1): $(2)
+ @echo " Generating CSF Header for $$@ $$<"
+ $(Q)$(CST_DIR)/create_hdr_esbc --in $(2) --out $(1) --app_off ${CSF_HDR_SZ} \
+ --app $(2) ${FUSE_INPUT_FILE}
+endef
+
+CST_SCP_BL2_SUFFIX := .cst
diff --git a/drivers/nxp/auth/csf_hdr_parser/csf_hdr_parser.c b/drivers/nxp/auth/csf_hdr_parser/csf_hdr_parser.c
new file mode 100644
index 0000000..b878082
--- /dev/null
+++ b/drivers/nxp/auth/csf_hdr_parser/csf_hdr_parser.c
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2014-2016, Freescale Semiconductor, Inc.
+ * Copyright 2017-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <cassert.h>
+#include <common/debug.h>
+#include <csf_hdr.h>
+#include <dcfg.h>
+#include <drivers/auth/crypto_mod.h>
+#include <lib/utils.h>
+#include <sfp.h>
+
+/* Maximum OID string length ("a.b.c.d.e.f ...") */
+#define MAX_OID_STR_LEN 64
+
+#define LIB_NAME "NXP CSFv2"
+
+#ifdef CSF_HDR_CH3
+/* Barker Code for LS Ch3 ESBC Header */
+static const uint8_t barker_code[CSF_BARKER_LEN] = { 0x12, 0x19, 0x20, 0x01 };
+#else
+static const uint8_t barker_code[CSF_BARKER_LEN] = { 0x68, 0x39, 0x27, 0x81 };
+#endif
+
+#define CHECK_KEY_LEN(key_len) (((key_len) == 2 * RSA_1K_KEY_SZ_BYTES) || \
+ ((key_len) == 2 * RSA_2K_KEY_SZ_BYTES) || \
+ ((key_len) == 2 * RSA_4K_KEY_SZ_BYTES))
+
+/* Flag to indicate if values are there in rotpk_hash_table */
+bool rotpk_not_dpld = true;
+uint8_t rotpk_hash_table[MAX_KEY_ENTRIES][SHA256_BYTES];
+uint32_t num_rotpk_hash_entries;
+
+/*
+ * This function deploys the hashes of the various platform keys in
+ * rotpk_hash_table. This is done in case of secure boot after comparison
+ * of table's hash with the hash in SFP fuses. This installation is done
+ * only in the first header parsing.
+ */
+static int deploy_rotpk_hash_table(void *srk_buffer, uint16_t num_srk)
+{
+ void *ctx;
+ int ret = 0;
+ int i, j = 0;
+ unsigned int digest_size = SHA256_BYTES;
+ enum hash_algo algo = SHA256;
+ uint8_t hash[SHA256_BYTES];
+ uint32_t srk_hash[SHA256_BYTES/4] __aligned(CACHE_WRITEBACK_GRANULE);
+ struct srk_table *srktbl = (void *)srk_buffer;
+ struct sfp_ccsr_regs_t *sfp_ccsr_regs = (void *)(get_sfp_addr()
+ + SFP_FUSE_REGS_OFFSET);
+
+
+ if (num_srk > MAX_KEY_ENTRIES) {
+ return -1;
+ }
+
+ ret = hash_init(algo, &ctx);
+ if (ret != 0) {
+ return -1;
+ }
+
+ /* Update hash with that of SRK table */
+ ret = hash_update(algo, ctx, (uint8_t *)((uint8_t *)srk_buffer),
+ num_srk * sizeof(struct srk_table));
+ if (ret != 0) {
+ return -1;
+ }
+
+ /* Copy hash at destination buffer */
+ ret = hash_final(algo, ctx, hash, digest_size);
+ if (ret != 0) {
+ return -1;
+ }
+
+ /* Add comparison of hash with SFP hash here */
+ for (i = 0; i < SHA256_BYTES/4; i++) {
+ srk_hash[i] =
+ mmio_read_32((uintptr_t)&sfp_ccsr_regs->srk_hash[i]);
+ }
+
+ VERBOSE("SRK table HASH\n");
+ for (i = 0; i < 8; i++) {
+ VERBOSE("%x\n", *((uint32_t *)hash + i));
+ }
+
+ if (memcmp(hash, srk_hash, SHA256_BYTES) != 0) {
+ ERROR("Error in installing ROTPK table\n");
+ ERROR("SRK hash doesn't match the fuse hash\n");
+ return -1;
+ }
+
+ /* Hash table already deployed */
+ if (rotpk_not_dpld == false) {
+ return 0;
+ }
+
+ for (i = 0; i < num_srk; i++) {
+ ret = hash_init(algo, &ctx);
+ if (ret != 0) {
+ return -1;
+ }
+
+ /* Update hash with that of SRK table */
+ ret = hash_update(algo, ctx, srktbl[i].pkey, srktbl[i].key_len);
+ if (ret != 0) {
+ return -1;
+ }
+
+ /* Copy hash at destination buffer */
+ ret = hash_final(algo, ctx, rotpk_hash_table[i], digest_size);
+ if (ret != 0) {
+ return -1;
+ }
+ VERBOSE("Table key %d HASH\n", i);
+ for (j = 0; j < 8; j++) {
+ VERBOSE("%x\n", *((uint32_t *)rotpk_hash_table[i] + j));
+ }
+ }
+ rotpk_not_dpld = false;
+ num_rotpk_hash_entries = num_srk;
+
+ return 0;
+}
+
+/*
+ * Calculate hash of ESBC hdr and ESBC. This function calculates the
+ * single hash of ESBC header and ESBC image
+ */
+int calc_img_hash(struct csf_hdr *hdr,
+ void *img_addr, uint32_t img_size,
+ uint8_t *img_hash, uint32_t *hash_len)
+{
+ void *ctx;
+ int ret = 0;
+ unsigned int digest_size = SHA256_BYTES;
+ enum hash_algo algo = SHA256;
+
+ ret = hash_init(algo, &ctx);
+ /* Copy hash at destination buffer */
+ if (ret != 0) {
+ return -1;
+ }
+
+ /* Update hash for CSF Header */
+ ret = hash_update(algo, ctx, (uint8_t *)hdr, sizeof(struct csf_hdr));
+ if (ret != 0) {
+ return -1;
+ }
+
+ /* Update hash with that of SRK table */
+ ret = hash_update(algo, ctx,
+ (uint8_t *)((uint8_t *)hdr + hdr->srk_tbl_off),
+ hdr->len_kr.num_srk * sizeof(struct srk_table));
+ if (ret != 0) {
+ return -1;
+ }
+
+ /* Update hash for actual Image */
+ ret = hash_update(algo, ctx, (uint8_t *)(img_addr), img_size);
+ if (ret != 0) {
+ return -1;
+ }
+
+ /* Copy hash at destination buffer */
+ ret = hash_final(algo, ctx, img_hash, digest_size);
+ if (ret != 0) {
+ return -1;
+ }
+
+ *hash_len = digest_size;
+
+ VERBOSE("IMG encoded HASH\n");
+ for (int i = 0; i < 8; i++) {
+ VERBOSE("%x\n", *((uint32_t *)img_hash + i));
+ }
+
+ return 0;
+}
+
+/* This function checks if selected key is revoked or not.*/
+static uint32_t is_key_revoked(uint32_t keynum, uint32_t rev_flag)
+{
+ if (keynum == UNREVOCABLE_KEY) {
+ return 0;
+ }
+
+ if (((uint32_t)(1 << (REVOC_KEY_ALIGN - keynum)) & rev_flag) != 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Parse the header to extract the type of key,
+ * Check if key is not revoked
+ * and return the key , key length and key_type
+ */
+static int32_t get_key(struct csf_hdr *hdr, uint8_t **key, uint32_t *len,
+ enum sig_alg *key_type)
+{
+ int i = 0;
+ uint32_t ret = 0U;
+ uint32_t key_num, key_revoc_flag;
+ void *esbc = hdr;
+ struct srk_table *srktbl = (void *)((uint8_t *)esbc + hdr->srk_tbl_off);
+ bool sb;
+ uint32_t mode;
+
+ /* We currently support only RSA keys and signature */
+ *key_type = RSA;
+
+ /* Check for number of SRK entries */
+ if ((hdr->len_kr.num_srk == 0) ||
+ (hdr->len_kr.num_srk > MAX_KEY_ENTRIES)) {
+ ERROR("Error in NUM entries in SRK Table\n");
+ return -1;
+ }
+
+ /*
+ * Check the key number field. It should be not greater than
+ * number of entries in SRK table.
+ */
+ key_num = hdr->len_kr.srk_sel;
+ if ((key_num == 0) || (key_num > hdr->len_kr.num_srk)) {
+ ERROR("Invalid Key number\n");
+ return -1;
+ }
+
+ /* Get revoc key from sfp */
+ key_revoc_flag = get_key_revoc();
+
+ /* Check if selected key has been revoked */
+ ret = is_key_revoked(key_num, key_revoc_flag);
+ if (ret != 0) {
+ ERROR("Selected key has been revoked\n");
+ return -1;
+ }
+
+ /* Check for valid key length - allowed key sized 1k, 2k and 4K */
+ for (i = 0; i < hdr->len_kr.num_srk; i++) {
+ if (CHECK_KEY_LEN(srktbl[i].key_len) == 0) {
+ ERROR("Invalid key length\n");
+ return -1;
+ }
+ }
+
+ /* We don't return error from here. While parsing we just try to
+ * install the srk table. Failure needs to be taken care of in
+ * case of secure boot. This failure will be handled at the time
+ * of rotpk comparison in plat_get_rotpk_info function
+ */
+ sb = check_boot_mode_secure(&mode);
+ if (sb) {
+ ret = deploy_rotpk_hash_table(srktbl, hdr->len_kr.num_srk);
+ if (ret != 0) {
+ ERROR("ROTPK FAILURE\n");
+ /* For ITS =1 , return failure */
+ if (mode != 0) {
+ return -1;
+ }
+ ERROR("SECURE BOOT DEV-ENV MODE:\n");
+ ERROR("\tCHECK ROTPK !\n");
+ ERROR("\tCONTINUING ON FAILURE...\n");
+ }
+ }
+
+ /* Return the length of the selected key */
+ *len = srktbl[key_num - 1].key_len;
+
+ /* Point key to the selected key */
+ *key = (uint8_t *)&(srktbl[key_num - 1].pkey);
+
+ return 0;
+}
+
+/*
+ * This function would parse the CSF header and do the following:
+ * 1. Basic integrity checks
+ * 2. Key checks and extract the key from SRK/IE Table
+ * 3. Key hash comparison with SRKH in fuses in case of SRK Table
+ * 4. OEM/UID checks - To be added
+ * 5. Hash calculation for various components used in signature
+ * 6. Signature integrity checks
+ * return -> 0 on success, -1 on failure
+ */
+int validate_esbc_header(void *img_hdr, void **img_key, uint32_t *key_len,
+ void **img_sign, uint32_t *sign_len,
+ enum sig_alg *algo)
+{
+ struct csf_hdr *hdr = img_hdr;
+ uint8_t *s;
+ int32_t ret = 0;
+ void *esbc = (uint8_t *)img_hdr;
+ uint8_t *key;
+ uint32_t klen;
+
+ /* check barker code */
+ if (memcmp(hdr->barker, barker_code, CSF_BARKER_LEN) != 0) {
+ ERROR("Wrong barker code in header\n");
+ return -1;
+ }
+
+ ret = get_key(hdr, &key, &klen, algo);
+ if (ret != 0) {
+ return -1;
+ }
+
+ /* check signaure */
+ if (klen == (2 * hdr->sign_len)) {
+ /* check signature length */
+ if (((hdr->sign_len == RSA_1K_KEY_SZ_BYTES) ||
+ (hdr->sign_len == RSA_2K_KEY_SZ_BYTES) ||
+ (hdr->sign_len == RSA_4K_KEY_SZ_BYTES)) == 0) {
+ ERROR("Wrong Signature length in header\n");
+ return -1;
+ }
+ } else {
+ ERROR("RSA key length not twice the signature length\n");
+ return -1;
+ }
+
+ /* modulus most significant bit should be set */
+
+ if ((key[0] & 0x80) == 0U) {
+ ERROR("RSA Public key MSB not set\n");
+ return -1;
+ }
+
+ /* modulus value should be odd */
+ if ((key[klen / 2 - 1] & 0x1) == 0U) {
+ ERROR("Public key Modulus in header not odd\n");
+ return -1;
+ }
+
+ /* Check signature value < modulus value */
+ s = (uint8_t *)(esbc + hdr->psign);
+
+ if (!(memcmp(s, key, hdr->sign_len) < 0)) {
+ ERROR("Signature not less than modulus");
+ return -1;
+ }
+
+ /* Populate the return addresses */
+ *img_sign = (void *)(s);
+
+ /* Save the length of signature */
+ *sign_len = hdr->sign_len;
+
+ *img_key = (uint8_t *)key;
+
+ *key_len = klen;
+
+ return ret;
+}
diff --git a/drivers/nxp/auth/csf_hdr_parser/input_bl2_ch2 b/drivers/nxp/auth/csf_hdr_parser/input_bl2_ch2
new file mode 100644
index 0000000..bf8934b
--- /dev/null
+++ b/drivers/nxp/auth/csf_hdr_parser/input_bl2_ch2
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2014-2016, Freescale Semiconductor, Inc.
+ * Copyright 2017-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+---------------------------------------------------
+# Specify the platform. [Mandatory]
+# Choose Platform - 1010/1040/2041/3041/4080/5020/5040/9131/9132/9164/4240/C290/LS1
+PLATFORM=LS1043
+# ESBC Flag. Specify ESBC=0 to sign u-boot and ESBC=1 to sign ESBC images.(default is 0)
+ESBC=0
+---------------------------------------------------
+# Entry Point/Image start address field in the header.[Mandatory]
+# (default=ADDRESS of first file specified in images)
+ENTRY_POINT=10000000
+---------------------------------------------------
+# Specify the file name of the keys separated by comma.
+# The number of files and key select should lie between 1 and 4 for 1040 and C290.
+# For rest of the platforms only one key is required and key select should not be provided.
+
+# USAGE (for 4080/5020/5040/3041/2041/1010/913x): PRI_KEY = <key1.pri>
+# USAGE (for 1040/C290/9164/4240/LS1): PRI_KEY = <key1.pri>, <key2.pri>, <key3.pri>, <key4.pri>
+
+# PRI_KEY (Default private key :srk.pri) - [Optional]
+PRI_KEY=srk.pri
+# PUB_KEY (Default public key :srk.pub) - [Optional]
+PUB_KEY=srk.pub
+# Please provide KEY_SELECT(between 1 to 4) (Required for 1040/C290/9164/4240/LS1 only) - [Optional]
+KEY_SELECT=
+---------------------------------------------------
+# Specify SG table address, only for (2041/3041/4080/5020/5040) with ESBC=0 - [Optional]
+SG_TABLE_ADDR=
+---------------------------------------------------
+# Specify the target where image will be loaded. (Default is NOR_16B) - [Optional]
+# Only required for Non-PBL Devices (1010/1040/9131/9132i/C290)
+# Select from - NOR_8B/NOR_16B/NAND_8B_512/NAND_8B_2K/NAND_8B_4K/NAND_16B_512/NAND_16B_2K/NAND_16B_4K/SD/MMC/SPI
+IMAGE_TARGET=
+---------------------------------------------------
+# Specify IMAGE, Max 8 images are possible. DST_ADDR is required only for Non-PBL Platform. [Mandatory]
+# USAGE : IMAGE_NO = {IMAGE_NAME, SRC_ADDR, DST_ADDR}
+IMAGE_1={bl2.bin,10000000,ffffffff}
+IMAGE_2={,,}
+IMAGE_3={,,}
+IMAGE_4={,,}
+IMAGE_5={,,}
+IMAGE_6={,,}
+IMAGE_7={,,}
+IMAGE_8={,,}
+---------------------------------------------------
+# Specify OEM AND FSL ID to be populated in header. [Optional]
+# e.g FSL_UID=11111111
+FSL_UID_0=
+FSL_UID_1=
+OEM_UID_0=
+OEM_UID_1=
+---------------------------------------------------
+# Specify the file names of csf header and sg table. (Default :hdr.out) [Optional]
+OUTPUT_HDR_FILENAME=hdr_bl2.out
+
+# Specify the file names of hash file and sign file.
+HASH_FILENAME=img_hash.out
+INPUT_SIGN_FILENAME=sign.out
+
+# Specify the signature size.It is mandatory when neither public key nor private key is specified.
+# Signature size would be [0x80 for 1k key, 0x100 for 2k key, and 0x200 for 4k key].
+SIGN_SIZE=
+---------------------------------------------------
+# Specify the output file name of sg table. (Default :sg_table.out). [Optional]
+# Please note that OUTPUT SG BIN is only required for 2041/3041/4080/5020/5040 when ESBC flag is not set.
+OUTPUT_SG_BIN=
+---------------------------------------------------
+# Following fields are Required for 4240/9164/1040/C290 only
+
+# Specify House keeping Area
+# Required for 4240/9164/1040/C290 only when ESBC flag is not set. [Mandatory]
+HK_AREA_POINTER=
+HK_AREA_SIZE=
+---------------------------------------------------
+# Following field Required for 4240/9164/1040/C290 only
+# Specify Secondary Image Flag. (0 or 1) - [Optional]
+# (Default is 0)
+SEC_IMAGE=0
+# Specify Manufacturing Protection Flag. (0 or 1) - [Optional]
+# Required only for LS1(Default is 0)
+MP_FLAG=1
+---------------------------------------------------
diff --git a/drivers/nxp/auth/csf_hdr_parser/input_bl2_ch3 b/drivers/nxp/auth/csf_hdr_parser/input_bl2_ch3
new file mode 100644
index 0000000..5fdad9c
--- /dev/null
+++ b/drivers/nxp/auth/csf_hdr_parser/input_bl2_ch3
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+---------------------------------------------------
+# Specify the platform. [Mandatory]
+# Choose Platform -
+# TRUST 3.2: LX2160
+PLATFORM=LS2088
+---------------------------------------------------
+# Entry Point/Image start address field in the header.[Mandatory]
+# (default=ADDRESS of first file specified in images)
+# Address can be 64 bit
+ENTRY_POINT=1800A000
+---------------------------------------------------
+# Specify the Key Information.
+# PUB_KEY [Mandatory] Comma Separated List
+# Usage: <srk1.pub> <srk2.pub> .....
+PUB_KEY=srk.pub
+# KEY_SELECT [Mandatory]
+# USAGE (for TRUST 3.x): (between 1 to 8)
+KEY_SELECT=1
+# PRI_KEY [Mandatory] Single Key Used for Signing
+# USAGE: <srk.pri>
+PRI_KEY=srk.pri
+---------------------------------------------------
+# Specify IMAGE, Max 8 images are possible.
+# DST_ADDR is required only for Non-PBL Platform. [Mandatory]
+# USAGE : IMAGE_NO = {IMAGE_NAME, SRC_ADDR, DST_ADDR}
+# Address can be 64 bit
+IMAGE_1={bl2.bin,1800A000,ffffffff}
+IMAGE_2={,,}
+IMAGE_3={,,}
+IMAGE_4={,,}
+IMAGE_5={,,}
+IMAGE_6={,,}
+IMAGE_7={,,}
+IMAGE_8={,,}
+---------------------------------------------------
+# Specify OEM AND FSL ID to be populated in header. [Optional]
+# e.g FSL_UID_0=11111111
+FSL_UID_0=
+FSL_UID_1=
+OEM_UID_0=
+OEM_UID_1=
+OEM_UID_2=
+OEM_UID_3=
+OEM_UID_4=
+---------------------------------------------------
+# Specify the output file names [Optional].
+# Default Values chosen in Tool
+OUTPUT_HDR_FILENAME=hdr_bl2.out
+IMAGE_HASH_FILENAME=
+RSA_SIGN_FILENAME=
+---------------------------------------------------
+# Specify The Flags. (0 or 1) - [Optional]
+MP_FLAG=0
+ISS_FLAG=1
+LW_FLAG=0
+---------------------------------------------------
+# Specify VERBOSE as 1, if you want to Display Header Information [Optional]
+VERBOSE=1
diff --git a/drivers/nxp/auth/csf_hdr_parser/input_bl2_ch3_2 b/drivers/nxp/auth/csf_hdr_parser/input_bl2_ch3_2
new file mode 100644
index 0000000..cc7c07c
--- /dev/null
+++ b/drivers/nxp/auth/csf_hdr_parser/input_bl2_ch3_2
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+---------------------------------------------------
+# Specify the platform. [Mandatory]
+# Choose Platform -
+# TRUST 3.2: LX2160
+PLATFORM=LX2160
+---------------------------------------------------
+# Entry Point/Image start address field in the header.[Mandatory]
+# (default=ADDRESS of first file specified in images)
+# Address can be 64 bit
+ENTRY_POINT=1800D000
+---------------------------------------------------
+# Specify the Key Information.
+# PUB_KEY [Mandatory] Comma Separated List
+# Usage: <srk1.pub> <srk2.pub> .....
+PUB_KEY=srk.pub
+# KEY_SELECT [Mandatory]
+# USAGE (for TRUST 3.x): (between 1 to 8)
+KEY_SELECT=1
+# PRI_KEY [Mandatory] Single Key Used for Signing
+# USAGE: <srk.pri>
+PRI_KEY=srk.pri
+---------------------------------------------------
+# Specify IMAGE, Max 8 images are possible.
+# DST_ADDR is required only for Non-PBL Platform. [Mandatory]
+# USAGE : IMAGE_NO = {IMAGE_NAME, SRC_ADDR, DST_ADDR}
+# Address can be 64 bit
+IMAGE_1={bl2.bin,1800D000,ffffffff}
+IMAGE_2={,,}
+IMAGE_3={,,}
+IMAGE_4={,,}
+IMAGE_5={,,}
+IMAGE_6={,,}
+IMAGE_7={,,}
+IMAGE_8={,,}
+---------------------------------------------------
+# Specify OEM AND FSL ID to be populated in header. [Optional]
+# e.g FSL_UID_0=11111111
+FSL_UID_0=
+FSL_UID_1=
+OEM_UID_0=
+OEM_UID_1=
+OEM_UID_2=
+OEM_UID_3=
+OEM_UID_4=
+---------------------------------------------------
+# Specify the output file names [Optional].
+# Default Values chosen in Tool
+OUTPUT_HDR_FILENAME=hdr_bl2.out
+IMAGE_HASH_FILENAME=
+RSA_SIGN_FILENAME=
+---------------------------------------------------
+# Specify The Flags. (0 or 1) - [Optional]
+MP_FLAG=0
+ISS_FLAG=1
+LW_FLAG=0
+---------------------------------------------------
+# Specify VERBOSE as 1, if you want to Display Header Information [Optional]
+VERBOSE=1
diff --git a/drivers/nxp/auth/csf_hdr_parser/input_blx_ch2 b/drivers/nxp/auth/csf_hdr_parser/input_blx_ch2
new file mode 100644
index 0000000..93b020b
--- /dev/null
+++ b/drivers/nxp/auth/csf_hdr_parser/input_blx_ch2
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+---------------------------------------------------
+# Specify the platform. [Mandatory]
+# Choose Platform - 1010/1040/2041/3041/4080/5020/5040/9131/9132/9164/4240/C290/LS1
+PLATFORM=LS1043
+# ESBC Flag. Specify ESBC=0 to sign u-boot and ESBC=1 to sign ESBC images.(default is 0)
+ESBC=1
+---------------------------------------------------
+# Specify the file name of the keys separated by comma.
+
+# PRI_KEY (Default private key :srk.pri) - [Optional]
+PRI_KEY=srk.pri
+# PUB_KEY (Default public key :srk.pub) - [Optional]
+PUB_KEY=srk.pub
+# Please provide KEY_SELECT(between 1 to 4) (Required for 1040/C290/9164/4240 only) - [Optional]
+KEY_SELECT=1
+---------------------------------------------------
+# Specify OEM AND FSL ID to be populated in header. [Optional]
+# e.g FSL_UID=11111111
+FSL_UID_0=
+FSL_UID_1=
+OEM_UID_0=
+OEM_UID_1=
+---------------------------------------------------
diff --git a/drivers/nxp/auth/csf_hdr_parser/input_blx_ch3 b/drivers/nxp/auth/csf_hdr_parser/input_blx_ch3
new file mode 100644
index 0000000..18e8e3b
--- /dev/null
+++ b/drivers/nxp/auth/csf_hdr_parser/input_blx_ch3
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2017-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+ESBC=1
+---------------------------------------------------
+# Specify the platform. [Mandatory]
+# Choose Platform -
+# TRUST 3.0: LS2085
+# TRUST 3.1: LS2088, LS1088
+PLATFORM=LS2088
+---------------------------------------------------
+# Specify the Key Information.
+# PUB_KEY [Mandatory] Comma Separated List
+# Usage: <srk1.pub> <srk2.pub> .....
+PUB_KEY=srk.pub
+# KEY_SELECT [Mandatory]
+# USAGE (for TRUST 3.x): (between 1 to 8)
+KEY_SELECT=1
+# PRI_KEY [Mandatory] Single Key Used for Signing
+# USAGE: <srk.pri>
+PRI_KEY=srk.pri
+
+---------------------------------------------------
+# Specify OEM AND FSL ID to be populated in header. [Optional]
+# e.g FSL_UID_0=11111111
+FSL_UID_0=
+FSL_UID_1=
+OEM_UID_0=
+OEM_UID_1=
+OEM_UID_2=
+OEM_UID_3=
+OEM_UID_4=
+---------------------------------------------------
diff --git a/drivers/nxp/auth/csf_hdr_parser/input_pbi_ch3 b/drivers/nxp/auth/csf_hdr_parser/input_pbi_ch3
new file mode 100644
index 0000000..9111a2a
--- /dev/null
+++ b/drivers/nxp/auth/csf_hdr_parser/input_pbi_ch3
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+---------------------------------------------------
+# Specify the platform. [Mandatory]
+# Choose Platform -
+# TRUST 3.0: LS2085
+# TRUST 3.1: LS2088, LS1088
+PLATFORM=LS2088
+---------------------------------------------------
+# Specify the Key Information.
+# PUB_KEY [Mandatory] Comma Separated List
+# Usage: <srk1.pub> <srk2.pub> .....
+PUB_KEY=srk.pub
+# KEY_SELECT [Mandatory]
+# USAGE (for TRUST 3.x): (between 1 to 8)
+KEY_SELECT=1
+# PRI_KEY [Mandatory] Single Key Used for Signing
+# USAGE: <srk.pri>
+PRI_KEY=srk.pri
+---------------------------------------------------
+# Specify OEM AND FSL ID to be populated in header. [Optional]
+# e.g FSL_UID_0=11111111
+FSL_UID_0=
+FSL_UID_1=
+OEM_UID_0=
+OEM_UID_1=
+OEM_UID_2=
+OEM_UID_3=
+OEM_UID_4=
+---------------------------------------------------
+# Specify The Flags. (0 or 1) - [Optional]
+MP_FLAG=0
+ISS_FLAG=1
+LW_FLAG=0
+---------------------------------------------------
+# Specify VERBOSE as 1, if you want to Display Header Information [Optional]
+VERBOSE=1
+---------------------------------------------------
diff --git a/drivers/nxp/auth/csf_hdr_parser/input_pbi_ch3_2 b/drivers/nxp/auth/csf_hdr_parser/input_pbi_ch3_2
new file mode 100644
index 0000000..c2d7ce4
--- /dev/null
+++ b/drivers/nxp/auth/csf_hdr_parser/input_pbi_ch3_2
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+---------------------------------------------------
+# Specify the platform. [Mandatory]
+# Choose Platform -
+# TRUST 3.0: LS2085
+# TRUST 3.1: LS2088, LS1088
+PLATFORM=LX2160
+---------------------------------------------------
+# Specify the Key Information.
+# PUB_KEY [Mandatory] Comma Separated List
+# Usage: <srk1.pub> <srk2.pub> .....
+PUB_KEY=srk.pub
+# KEY_SELECT [Mandatory]
+# USAGE (for TRUST 3.x): (between 1 to 8)
+KEY_SELECT=1
+# PRI_KEY [Mandatory] Single Key Used for Signing
+# USAGE: <srk.pri>
+PRI_KEY=srk.pri
+---------------------------------------------------
+# Specify OEM AND FSL ID to be populated in header. [Optional]
+# e.g FSL_UID_0=11111111
+FSL_UID_0=
+FSL_UID_1=
+OEM_UID_0=
+OEM_UID_1=
+OEM_UID_2=
+OEM_UID_3=
+OEM_UID_4=
+---------------------------------------------------
+# Specify The Flags. (0 or 1) - [Optional]
+MP_FLAG=0
+ISS_FLAG=1
+LW_FLAG=0
+---------------------------------------------------
+# Specify VERBOSE as 1, if you want to Display Header Information [Optional]
+VERBOSE=1
+---------------------------------------------------
diff --git a/drivers/nxp/auth/csf_hdr_parser/plat_img_parser.c b/drivers/nxp/auth/csf_hdr_parser/plat_img_parser.c
new file mode 100644
index 0000000..43b78e5
--- /dev/null
+++ b/drivers/nxp/auth/csf_hdr_parser/plat_img_parser.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2014-2016, Freescale Semiconductor, Inc.
+ * Copyright 2017-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <csf_hdr.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/auth/img_parser_mod.h>
+#include <lib/utils.h>
+#include <sfp.h>
+
+/* 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.
+ */
+
+/* Hash of Image + CSF Header + SRK table */
+uint8_t img_hash[SHA256_BYTES] __aligned(CACHE_WRITEBACK_GRANULE);
+uint32_t hash_len;
+
+/* Key being used for authentication
+ * Points to the key in CSF header copied in DDR
+ * ESBC client key
+ */
+void *img_key;
+uint32_t key_len;
+
+/* ESBC client signature */
+void *img_sign;
+uint32_t sign_len;
+enum sig_alg alg;
+
+/* Maximum OID string length ("a.b.c.d.e.f ...") */
+#define MAX_OID_STR_LEN 64
+
+#define LIB_NAME "NXP CSFv2"
+
+/*
+ * 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(img_key);
+ ZERO_AND_CLEAN(img_sign);
+ ZERO_AND_CLEAN(img_hash);
+ ZERO_AND_CLEAN(key_len);
+ ZERO_AND_CLEAN(hash_len);
+ ZERO_AND_CLEAN(sign_len);
+
+#undef ZERO_AND_CLEAN
+}
+
+/* Exported functions */
+
+static void init(void)
+{
+ clear_temp_vars();
+}
+
+/*
+ * This function would check the integrity of the CSF header
+ */
+static int check_integrity(void *img, unsigned int img_len)
+{
+ int ret;
+
+ /*
+ * The image file has been successfully loaded till here.
+ *
+ * Flush the image to main memory so that it can be authenticated
+ * by CAAM, a HW accelerator regardless of cache and MMU state.
+ */
+ flush_dcache_range((uintptr_t) img, img_len);
+
+ /*
+ * Image is appended at an offset of 16K (IMG_OFFSET) to the header.
+ * So the size in header should be equal to img_len - IMG_OFFSET
+ */
+ VERBOSE("Barker code is %x\n", *(unsigned int *)img);
+ ret = validate_esbc_header(img, &img_key, &key_len, &img_sign,
+ &sign_len, &alg);
+ if (ret < 0) {
+ ERROR("Header authentication failed\n");
+ clear_temp_vars();
+ return IMG_PARSER_ERR;
+ }
+ /* Calculate the hash of various components from the image */
+ ret = calc_img_hash(img, (uint8_t *)img + CSF_HDR_SZ,
+ img_len - CSF_HDR_SZ, img_hash, &hash_len);
+ if (ret != 0) {
+ ERROR("Issue in hash calculation %d\n", ret);
+ clear_temp_vars();
+ return IMG_PARSER_ERR;
+ }
+
+ return IMG_PARSER_OK;
+}
+
+/*
+ * Extract an authentication parameter from CSF header
+ *
+ * CSF header has already been parsed and the required information like
+ * hash of data, signature, length stored in global variables has been
+ * extracted in chek_integrity function. This data
+ * is returned back to the caller.
+ */
+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 ( pk, sig_alg, etc)
+ */
+
+ switch (type_desc->type) {
+
+ /* Hash will be returned for comparison with signature */
+ case AUTH_PARAM_HASH:
+ *param = (void *)img_hash;
+ *param_len = (unsigned int)SHA256_BYTES;
+ break;
+
+ /* Return the public key used for signature extracted from the SRK table
+ * after checks with key revocation
+ */
+ case AUTH_PARAM_PUB_KEY:
+ /* Get the subject public key */
+ /* For a 1K key - the length would be 2k/8 = 0x100 bytes
+ * 2K RSA key - 0x200 , 4K RSA - 0x400
+ */
+ *param = img_key;
+ *param_len = (unsigned int)key_len;
+ break;
+
+ /* Call a function to tell if signature is RSA or ECDSA. ECDSA to be
+ * supported in later platforms like LX2 etc
+ */
+ case AUTH_PARAM_SIG_ALG:
+ /* Algo will be signature - RSA or ECDSA on hash */
+ *param = (void *)&alg;
+ *param_len = 4U;
+ break;
+
+ /* Return the signature */
+ case AUTH_PARAM_SIG:
+ *param = img_sign;
+ *param_len = (unsigned int)sign_len;
+ break;
+
+ case AUTH_PARAM_NV_CTR:
+
+ default:
+ rc = IMG_PARSER_ERR_NOT_FOUND;
+ break;
+ }
+
+ return rc;
+}
+
+REGISTER_IMG_PARSER_LIB(IMG_PLAT, LIB_NAME, init,
+ check_integrity, get_auth_param);
diff --git a/drivers/nxp/auth/tbbr/tbbr_cot.c b/drivers/nxp/auth/tbbr/tbbr_cot.c
new file mode 100644
index 0000000..bb21fa0
--- /dev/null
+++ b/drivers/nxp/auth/tbbr/tbbr_cot.c
@@ -0,0 +1,820 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <drivers/auth/auth_mod.h>
+
+#if USE_TBBR_DEFS
+#include <tools_share/tbbr_oid.h>
+#else
+#include <platform_oid.h>
+#endif
+
+
+#if TF_MBEDTLS_HASH_ALG_ID == TF_MBEDTLS_SHA256
+#define HASH_DER_LEN 51
+#elif TF_MBEDTLS_HASH_ALG_ID == TF_MBEDTLS_SHA384
+#define HASH_DER_LEN 67
+#elif TF_MBEDTLS_HASH_ALG_ID == TF_MBEDTLS_SHA512
+#define HASH_DER_LEN 83
+#else
+#error "Invalid value for TF_MBEDTLS_HASH_ALG_ID"
+#endif
+
+/*
+ * 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 nt_world_bl_hash_buf[HASH_DER_LEN];
+
+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];
+
+#ifdef CONFIG_DDR_FIP_IMAGE
+static unsigned char ddr_fw_content_pk_buf[PK_DER_LEN];
+static unsigned char ddr_imem_udimm_1d_hash_buf[HASH_DER_LEN];
+static unsigned char ddr_imem_udimm_2d_hash_buf[HASH_DER_LEN];
+static unsigned char ddr_dmem_udimm_1d_hash_buf[HASH_DER_LEN];
+static unsigned char ddr_dmem_udimm_2d_hash_buf[HASH_DER_LEN];
+
+static unsigned char ddr_imem_rdimm_1d_hash_buf[HASH_DER_LEN];
+static unsigned char ddr_imem_rdimm_2d_hash_buf[HASH_DER_LEN];
+static unsigned char ddr_dmem_rdimm_1d_hash_buf[HASH_DER_LEN];
+static unsigned char ddr_dmem_rdimm_2d_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 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 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 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);
+
+#ifdef CONFIG_DDR_FIP_IMAGE
+static auth_param_type_desc_t ddr_fw_content_pk = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_PUB_KEY, DDR_FW_CONTENT_CERT_PK_OID);
+
+static auth_param_type_desc_t ddr_imem_udimm_1d_fw_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, DDR_IMEM_UDIMM_1D_HASH_OID);
+static auth_param_type_desc_t ddr_imem_udimm_2d_fw_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, DDR_IMEM_UDIMM_2D_HASH_OID);
+static auth_param_type_desc_t ddr_dmem_udimm_1d_fw_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, DDR_DMEM_UDIMM_1D_HASH_OID);
+static auth_param_type_desc_t ddr_dmem_udimm_2d_fw_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, DDR_DMEM_UDIMM_2D_HASH_OID);
+
+static auth_param_type_desc_t ddr_imem_rdimm_1d_fw_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, DDR_IMEM_RDIMM_1D_HASH_OID);
+static auth_param_type_desc_t ddr_imem_rdimm_2d_fw_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, DDR_IMEM_RDIMM_2D_HASH_OID);
+static auth_param_type_desc_t ddr_dmem_rdimm_1d_fw_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, DDR_DMEM_RDIMM_1D_HASH_OID);
+static auth_param_type_desc_t ddr_dmem_rdimm_2d_fw_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, DDR_DMEM_RDIMM_2D_HASH_OID);
+#endif
+
+
+/*
+ * 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
+ }
+ }
+ }
+};
+
+/*
+ * 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
+ }
+ }
+ }
+};
+#ifdef CONFIG_DDR_FIP_IMAGE
+/*
+ * DDR Firmware
+ */
+static const auth_img_desc_t ddr_fw_key_cert = {
+ .img_id = DDR_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 = &ddr_fw_content_pk,
+ .data = {
+ .ptr = (void *)ddr_fw_content_pk_buf,
+ .len = (unsigned int)PK_DER_LEN
+ }
+ }
+ }
+};
+static const auth_img_desc_t ddr_udimm_fw_content_cert = {
+ .img_id = DDR_UDIMM_FW_CONTENT_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = &ddr_fw_key_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &ddr_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 = &ddr_imem_udimm_1d_fw_hash,
+ .data = {
+ .ptr = (void *)ddr_imem_udimm_1d_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [1] = {
+ .type_desc = &ddr_imem_udimm_2d_fw_hash,
+ .data = {
+ .ptr = (void *)ddr_imem_udimm_2d_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [2] = {
+ .type_desc = &ddr_dmem_udimm_1d_fw_hash,
+ .data = {
+ .ptr = (void *)ddr_dmem_udimm_1d_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [3] = {
+ .type_desc = &ddr_dmem_udimm_2d_fw_hash,
+ .data = {
+ .ptr = (void *)ddr_dmem_udimm_2d_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ }
+};
+
+static const auth_img_desc_t ddr_imem_udimm_1d_img = {
+ .img_id = DDR_IMEM_UDIMM_1D_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &ddr_udimm_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 = &ddr_imem_udimm_1d_fw_hash
+ }
+ }
+ }
+};
+static const auth_img_desc_t ddr_imem_udimm_2d_img = {
+ .img_id = DDR_IMEM_UDIMM_2D_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &ddr_udimm_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 = &ddr_imem_udimm_2d_fw_hash
+ }
+ }
+ }
+};
+static const auth_img_desc_t ddr_dmem_udimm_1d_img = {
+ .img_id = DDR_DMEM_UDIMM_1D_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &ddr_udimm_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 = &ddr_dmem_udimm_1d_fw_hash
+ }
+ }
+ }
+};
+static const auth_img_desc_t ddr_dmem_udimm_2d_img = {
+ .img_id = DDR_DMEM_UDIMM_2D_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &ddr_udimm_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 = &ddr_dmem_udimm_2d_fw_hash
+ }
+ }
+ }
+};
+
+static const auth_img_desc_t ddr_rdimm_fw_content_cert = {
+ .img_id = DDR_RDIMM_FW_CONTENT_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = &ddr_fw_key_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &ddr_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 = &ddr_imem_rdimm_1d_fw_hash,
+ .data = {
+ .ptr = (void *)ddr_imem_rdimm_1d_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [1] = {
+ .type_desc = &ddr_imem_rdimm_2d_fw_hash,
+ .data = {
+ .ptr = (void *)ddr_imem_rdimm_2d_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [2] = {
+ .type_desc = &ddr_dmem_rdimm_1d_fw_hash,
+ .data = {
+ .ptr = (void *)ddr_dmem_rdimm_1d_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [3] = {
+ .type_desc = &ddr_dmem_rdimm_2d_fw_hash,
+ .data = {
+ .ptr = (void *)ddr_dmem_rdimm_2d_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ }
+};
+
+static const auth_img_desc_t ddr_imem_rdimm_1d_img = {
+ .img_id = DDR_IMEM_RDIMM_1D_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &ddr_rdimm_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 = &ddr_imem_rdimm_1d_fw_hash
+ }
+ }
+ }
+};
+static const auth_img_desc_t ddr_imem_rdimm_2d_img = {
+ .img_id = DDR_IMEM_RDIMM_2D_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &ddr_rdimm_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 = &ddr_imem_rdimm_2d_fw_hash
+ }
+ }
+ }
+};
+static const auth_img_desc_t ddr_dmem_rdimm_1d_img = {
+ .img_id = DDR_DMEM_RDIMM_1D_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &ddr_rdimm_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 = &ddr_dmem_rdimm_1d_fw_hash
+ }
+ }
+ }
+};
+static const auth_img_desc_t ddr_dmem_rdimm_2d_img = {
+ .img_id = DDR_DMEM_RDIMM_2D_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &ddr_rdimm_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 = &ddr_dmem_rdimm_2d_fw_hash
+ }
+ }
+ }
+};
+#endif
+
+/*
+ * TBBR Chain of trust definition
+ */
+
+static const auth_img_desc_t * const cot_desc[] = {
+ [TRUSTED_KEY_CERT_ID] = &trusted_key_cert,
+ [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,
+#ifdef CONFIG_DDR_FIP_IMAGE
+ [DDR_FW_KEY_CERT_ID] = &ddr_fw_key_cert,
+ [DDR_UDIMM_FW_CONTENT_CERT_ID] = &ddr_udimm_fw_content_cert,
+ [DDR_RDIMM_FW_CONTENT_CERT_ID] = &ddr_rdimm_fw_content_cert,
+ [DDR_IMEM_UDIMM_1D_IMAGE_ID] = &ddr_imem_udimm_1d_img,
+ [DDR_IMEM_UDIMM_2D_IMAGE_ID] = &ddr_imem_udimm_2d_img,
+ [DDR_DMEM_UDIMM_1D_IMAGE_ID] = &ddr_dmem_udimm_1d_img,
+ [DDR_DMEM_UDIMM_2D_IMAGE_ID] = &ddr_dmem_udimm_2d_img,
+ [DDR_IMEM_RDIMM_1D_IMAGE_ID] = &ddr_imem_rdimm_1d_img,
+ [DDR_IMEM_RDIMM_2D_IMAGE_ID] = &ddr_imem_rdimm_2d_img,
+ [DDR_DMEM_RDIMM_1D_IMAGE_ID] = &ddr_dmem_rdimm_1d_img,
+ [DDR_DMEM_RDIMM_2D_IMAGE_ID] = &ddr_dmem_rdimm_2d_img,
+#endif
+};
+
+/* Register the CoT in the authentication module */
+REGISTER_COT(cot_desc);
diff --git a/drivers/nxp/console/16550_console.S b/drivers/nxp/console/16550_console.S
new file mode 100644
index 0000000..044d3d0
--- /dev/null
+++ b/drivers/nxp/console/16550_console.S
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console_macros.S>
+
+/* 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_BASE
+
+ /*
+ * "core" functions are low-level implementations that don't require
+ * writable memory and are thus safe to call in BL1 crash context.
+ */
+ .globl nxp_console_16550_core_init
+ .globl nxp_console_16550_core_putc
+ .globl nxp_console_16550_core_getc
+ .globl nxp_console_16550_core_flush
+
+ .globl console_16550_putc
+ .globl console_16550_getc
+ .globl console_16550_flush
+
+ /* -----------------------------------------------
+ * int nxp_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 nxp_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 */
+ 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 nxp_console_16550_core_init
+
+ .globl nxp_console_16550_register
+
+ /* -----------------------------------------------
+ * int nxp_console_16550_register(uintptr_t baseaddr,
+ * uint32_t clock, uint32_t baud,
+ * console_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).
+ * If w1 (UART clock) is 0, initialisation will be
+ * skipped, relying on previous code to have done
+ * this already. w2 is ignored then as well.
+ * In: x0 - UART register base address
+ * w1 - UART clock in Hz
+ * w2 - Baud rate (ignored if w1 is 0)
+ * x3 - pointer to empty console_t struct
+ * Out: return 1 on success, 0 on error
+ * Clobber list : x0, x1, x2, x6, x7, x14
+ * -----------------------------------------------
+ */
+func nxp_console_16550_register
+ mov x7, x30
+ mov x6, x3
+ cbz x6, register_fail
+ str x0, [x6, #CONSOLE_T_16550_BASE]
+
+ /* A clock rate of zero means to skip the initialisation. */
+ cbz w1, register_16550
+
+ bl nxp_console_16550_core_init
+ cbz x0, register_fail
+
+register_16550:
+ mov x0, x6
+ mov x30, x7
+ finish_console_register 16550 putc=1, getc=1, flush=1
+
+register_fail:
+ ret x7
+endfunc nxp_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 nxp_console_16550_core_putc
+#if ENABLE_ASSERTIONS
+ cmp x1, #0
+ ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
+ /* Prepend '\r' to '\n' */
+ cmp w0, #'\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, #'\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 nxp_console_16550_core_putc
+
+ /* --------------------------------------------------------
+ * int console_16550_putc(int c, console_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 nxp_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 nxp_console_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 nxp_console_16550_core_getc
+
+ /* ---------------------------------------------
+ * int console_16550_getc(console_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_16550_getc
+#if ENABLE_ASSERTIONS
+ cmp x1, #0
+ ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+ ldr x0, [x0, #CONSOLE_T_16550_BASE]
+ b nxp_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 nxp_console_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_THRE)
+ cmp w1, #(UARTLSR_THRE)
+ b.ne 1b
+
+ mov w0, #0
+ ret
+endfunc nxp_console_16550_core_flush
+
+ /* ---------------------------------------------
+ * int console_16550_flush(console_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 nxp_console_16550_core_flush
+endfunc console_16550_flush
diff --git a/drivers/nxp/console/console.mk b/drivers/nxp/console/console.mk
new file mode 100644
index 0000000..6174650
--- /dev/null
+++ b/drivers/nxp/console/console.mk
@@ -0,0 +1,46 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+#------------------------------------------------------------------------------
+#
+# Select the CORE files
+#
+# -----------------------------------------------------------------------------
+
+ifeq (${ADD_CONSOLE},)
+
+ADD_CONSOLE := 1
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/console
+
+ifeq ($(CONSOLE), NS16550)
+NXP_CONSOLE := NS16550
+
+$(eval $(call add_define_val,NXP_CONSOLE,${NXP_CONSOLE}))
+
+CONSOLE_SOURCES := $(PLAT_DRIVERS_PATH)/console/16550_console.S \
+ $(PLAT_DRIVERS_PATH)/console/console_16550.c
+else
+ifeq ($(CONSOLE), PL011)
+CONSOLE_SOURCES := drivers/arm/pl011/aarch64/pl011_console.S \
+ ${PLAT_DRIVERS_PATH}/console/console_pl011.c
+else
+ $(error -> CONSOLE not set!)
+endif
+endif
+
+ifeq (${BL_COMM_CONSOLE_NEEDED},yes)
+BL_COMMON_SOURCES += ${CONSOLE_SOURCES}
+else
+ifeq (${BL2_CONSOLE_NEEDED},yes)
+BL2_SOURCES += ${CONSOLE_SOURCES}
+endif
+ifeq (${BL31_CONSOLE_NEEDED},yes)
+BL31_SOURCES += ${CONSOLE_SOURCES}
+endif
+endif
+endif
+# -----------------------------------------------------------------------------
diff --git a/drivers/nxp/console/console_16550.c b/drivers/nxp/console/console_16550.c
new file mode 100644
index 0000000..fa5c5bb
--- /dev/null
+++ b/drivers/nxp/console/console_16550.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <dcfg.h>
+#include <lib/utils.h>
+#include <plat_console.h>
+
+/*
+ * Perform Arm specific early platform setup. At this moment we only initialize
+ * the console and the memory layout.
+ */
+void plat_console_init(uintptr_t nxp_console_addr, uint32_t uart_clk_div,
+ uint32_t baud)
+{
+ struct sysinfo sys;
+ static console_t nxp_console;
+
+ zeromem(&sys, sizeof(sys));
+ if (get_clocks(&sys)) {
+ ERROR("System clocks are not set\n");
+ panic();
+ }
+ nxp_console_16550_register(nxp_console_addr,
+ (sys.freq_platform/uart_clk_div),
+ baud, &nxp_console);
+}
diff --git a/drivers/nxp/console/console_pl011.c b/drivers/nxp/console/console_pl011.c
new file mode 100644
index 0000000..93f2fc2
--- /dev/null
+++ b/drivers/nxp/console/console_pl011.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <dcfg.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <lib/utils.h>
+
+/*
+ * Perform Arm specific early platform setup. At this moment we only initialize
+ * the console and the memory layout.
+ */
+void plat_console_init(uintptr_t nxp_console_addr, uint32_t uart_clk_div,
+ uint32_t baud)
+{
+ struct sysinfo sys;
+ static console_t nxp_console;
+
+ zeromem(&sys, sizeof(sys));
+ if (get_clocks(&sys)) {
+ ERROR("System clocks are not set\n");
+ panic();
+ }
+
+ console_pl011_register(nxp_console_addr,
+ (sys.freq_platform/uart_clk_div),
+ baud, &nxp_console);
+}
diff --git a/drivers/nxp/crypto/caam/caam.mk b/drivers/nxp/crypto/caam/caam.mk
new file mode 100644
index 0000000..f929f53
--- /dev/null
+++ b/drivers/nxp/crypto/caam/caam.mk
@@ -0,0 +1,27 @@
+#
+# Copyright 2020-2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+
+ifeq (${ADD_CAAM},)
+
+ADD_CAAM := 1
+
+CAAM_DRIVER_SOURCES += $(wildcard $(PLAT_DRIVERS_PATH)/crypto/caam/src/*.c)
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/crypto/caam
+
+ifeq (${BL_COMM_CRYPTO_NEEDED},yes)
+BL_COMMON_SOURCES += ${CAAM_DRIVER_SOURCES}
+else
+ifeq (${BL2_CRYPTO_NEEDED},yes)
+BL2_SOURCES += ${CAAM_DRIVER_SOURCES}
+endif
+ifeq (${BL31_CRYPTO_NEEDED},yes)
+BL31_SOURCES += ${CAAM_DRIVER_SOURCES}
+endif
+endif
+
+endif
diff --git a/drivers/nxp/crypto/caam/src/auth/auth.mk b/drivers/nxp/crypto/caam/src/auth/auth.mk
new file mode 100644
index 0000000..d1f8c75
--- /dev/null
+++ b/drivers/nxp/crypto/caam/src/auth/auth.mk
@@ -0,0 +1,12 @@
+#
+# Copyright 2018-2020 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+
+SEC_DRIVERS_PATH := drivers/nxp/crypto/caam
+
+ifeq (${TRUSTED_BOARD_BOOT},1)
+AUTH_SOURCES += $(wildcard $(SEC_DRIVERS_PATH)/src/auth/*.c)
+endif
diff --git a/drivers/nxp/crypto/caam/src/auth/hash.c b/drivers/nxp/crypto/caam/src/auth/hash.c
new file mode 100644
index 0000000..1665df1
--- /dev/null
+++ b/drivers/nxp/crypto/caam/src/auth/hash.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include "caam.h"
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+
+#include "hash.h"
+#include "jobdesc.h"
+#include "sec_hw_specific.h"
+
+/* Since no Allocator is available . Taking a global static ctx.
+ * This would mean that only one active ctx can be there at a time.
+ */
+
+static struct hash_ctx glbl_ctx;
+
+static void hash_done(uint32_t *desc, uint32_t status, void *arg,
+ void *job_ring)
+{
+ INFO("Hash Desc SUCCESS with status %x\n", status);
+}
+
+/***************************************************************************
+ * Function : hash_init
+ * Arguments : ctx - SHA context
+ * Return : init,
+ * Description : This function initializes the context for SHA calculation
+ ***************************************************************************/
+int hash_init(enum hash_algo algo, void **ctx)
+{
+ if (glbl_ctx.active == false) {
+ memset(&glbl_ctx, 0, sizeof(struct hash_ctx));
+ glbl_ctx.active = true;
+ glbl_ctx.algo = algo;
+ *ctx = &glbl_ctx;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+/***************************************************************************
+ * Function : hash_update
+ * Arguments : ctx - SHA context
+ * buffer - Data
+ * length - Length
+ * Return : -1 on error
+ * 0 on SUCCESS
+ * Description : This function creates SG entry of the data provided
+ ***************************************************************************/
+int hash_update(enum hash_algo algo, void *context, void *data_ptr,
+ unsigned int data_len)
+{
+ struct hash_ctx *ctx = context;
+ /* MAX_SG would be MAX_SG_ENTRIES + key + hdr + sg table */
+ if (ctx->sg_num >= MAX_SG) {
+ ERROR("Reached limit for calling %s\n", __func__);
+ ctx->active = false;
+ return -EINVAL;
+
+ }
+
+ if (ctx->algo != algo) {
+ ERROR("ctx for algo not correct\n");
+ ctx->active = false;
+ return -EINVAL;
+ }
+
+#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
+ flush_dcache_range((uintptr_t)data_ptr, data_len);
+ dmbsy();
+#endif
+
+#ifdef CONFIG_PHYS_64BIT
+ sec_out32(&ctx->sg_tbl[ctx->sg_num].addr_hi,
+ (uint32_t) ((uintptr_t) data_ptr >> 32));
+#else
+ sec_out32(&ctx->sg_tbl[ctx->sg_num].addr_hi, 0x0);
+#endif
+ sec_out32(&ctx->sg_tbl[ctx->sg_num].addr_lo, (uintptr_t) data_ptr);
+
+ sec_out32(&ctx->sg_tbl[ctx->sg_num].len_flag,
+ (data_len & SG_ENTRY_LENGTH_MASK));
+
+ ctx->sg_num++;
+
+ ctx->len += data_len;
+
+ return 0;
+}
+
+/***************************************************************************
+ * Function : hash_final
+ * Arguments : ctx - SHA context
+ * Return : SUCCESS or FAILURE
+ * Description : This function sets the final bit and enqueues the decriptor
+ ***************************************************************************/
+int hash_final(enum hash_algo algo, void *context, void *hash_ptr,
+ unsigned int hash_len)
+{
+ int ret = 0;
+ struct hash_ctx *ctx = context;
+ uint32_t final = 0U;
+
+ struct job_descriptor jobdesc __aligned(CACHE_WRITEBACK_GRANULE);
+
+ jobdesc.arg = NULL;
+ jobdesc.callback = hash_done;
+
+ if (ctx->algo != algo) {
+ ERROR("ctx for algo not correct\n");
+ ctx->active = false;
+ return -EINVAL;
+ }
+
+ final = sec_in32(&ctx->sg_tbl[ctx->sg_num - 1].len_flag) |
+ SG_ENTRY_FINAL_BIT;
+ sec_out32(&ctx->sg_tbl[ctx->sg_num - 1].len_flag, final);
+
+ dsb();
+
+ /* create the hw_rng descriptor */
+ cnstr_hash_jobdesc(jobdesc.desc, (uint8_t *) ctx->sg_tbl,
+ ctx->len, hash_ptr);
+
+#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
+ flush_dcache_range((uintptr_t)ctx->sg_tbl,
+ (sizeof(struct sg_entry) * MAX_SG));
+ inv_dcache_range((uintptr_t)hash_ptr, hash_len);
+
+ dmbsy();
+#endif
+
+ /* Finally, generate the requested random data bytes */
+ ret = run_descriptor_jr(&jobdesc);
+ if (ret != 0) {
+ ERROR("Error in running descriptor\n");
+ ret = -1;
+ }
+ ctx->active = false;
+ return ret;
+}
diff --git a/drivers/nxp/crypto/caam/src/auth/nxp_crypto.c b/drivers/nxp/crypto/caam/src/auth/nxp_crypto.c
new file mode 100644
index 0000000..646e981
--- /dev/null
+++ b/drivers/nxp/crypto/caam/src/auth/nxp_crypto.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+#include "caam.h"
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+
+#include "hash.h"
+#include "rsa.h"
+
+#define LIB_NAME "NXP crypto"
+
+/*
+ * Initialize the library and export the descriptor
+ */
+static void init(void)
+{
+ /* Initialize NXP crypto library`:*/
+ NOTICE("Initializing & configuring SEC block.\n");
+
+ if (config_sec_block() < 0) {
+ ERROR("Init & config failure for caam.\n");
+ }
+}
+
+/*
+ * Verify a signature.
+ *
+ * For IMG_PLAT - data points to a PKCS#1.5 encoded HASH
+ * sig_alg will be RSA or ECC
+ * 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 *sign_alg, unsigned int sig_alg_len,
+ void *pk_ptr, unsigned int pk_len)
+{
+ int ret = CRYPTO_SUCCESS;
+
+ enum sig_alg alg = *(enum sig_alg *)sign_alg;
+
+ switch (alg) {
+ case RSA:
+ NOTICE("Verifying RSA\n");
+ ret = rsa_verify_signature(data_ptr, data_len, sig_ptr, sig_len,
+ pk_ptr, pk_len);
+ break;
+ case ECC:
+ default:
+ ret = CRYPTO_ERR_SIGNATURE;
+ break;
+ }
+
+ if (ret != 0) {
+ ERROR("RSA verification Failed\n");
+ }
+ return ret;
+
+}
+
+/*
+ * Match a hash
+ *
+ * Digest info is passed as a table of SHA-26 hashes and digest_info_len
+ * is number of entries in the table
+ * This implementation is very specific to the CSF header parser ROTPK
+ * comparison.
+ */
+static int verify_hash(void *data_ptr, unsigned int data_len,
+ void *digest_info_ptr, unsigned int digest_info_len)
+{
+ void *ctx = NULL;
+ int i = 0, ret = 0;
+ enum hash_algo algo = SHA256;
+ uint8_t hash[SHA256_BYTES] __aligned(CACHE_WRITEBACK_GRANULE) = {0};
+ uint32_t digest_size = SHA256_BYTES;
+ uint8_t *hash_tbl = digest_info_ptr;
+
+ NOTICE("Verifying hash\n");
+ ret = hash_init(algo, &ctx);
+ if (ret != 0) {
+ return CRYPTO_ERR_HASH;
+ }
+
+ /* Update hash with that of SRK table */
+ ret = hash_update(algo, ctx, data_ptr, data_len);
+ if (ret != 0) {
+ return CRYPTO_ERR_HASH;
+ }
+
+ /* Copy hash at destination buffer */
+ ret = hash_final(algo, ctx, hash, digest_size);
+ if (ret != 0) {
+ return CRYPTO_ERR_HASH;
+ }
+
+ VERBOSE("%s Calculated hash\n", __func__);
+ for (i = 0; i < SHA256_BYTES/4; i++) {
+ VERBOSE("%x\n", *((uint32_t *)hash + i));
+ }
+
+ for (i = 0; i < digest_info_len; i++) {
+ if (memcmp(hash, (hash_tbl + (i * digest_size)),
+ digest_size) == 0) {
+ return CRYPTO_SUCCESS;
+ }
+ }
+
+ return CRYPTO_ERR_HASH;
+}
+
+/*
+ * Register crypto library descriptor
+ */
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, NULL);
diff --git a/drivers/nxp/crypto/caam/src/auth/rsa.c b/drivers/nxp/crypto/caam/src/auth/rsa.c
new file mode 100644
index 0000000..0c44462
--- /dev/null
+++ b/drivers/nxp/crypto/caam/src/auth/rsa.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include "caam.h"
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+
+#include "jobdesc.h"
+#include "rsa.h"
+#include "sec_hw_specific.h"
+
+/* This array contains DER value for SHA-256 */
+static const uint8_t hash_identifier[] = {
+ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60,
+ 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00,
+ 0x04, 0x20
+};
+
+static void rsa_done(uint32_t *desc, uint32_t status, void *arg,
+ void *job_ring)
+{
+ INFO("RSA Desc SUCCESS with status %x\n", status);
+}
+
+static int rsa_public_verif_sec(uint8_t *sign, uint8_t *to,
+ uint8_t *rsa_pub_key, uint32_t klen)
+{
+ int ret = 0;
+ struct rsa_context ctx __aligned(CACHE_WRITEBACK_GRANULE);
+ struct job_descriptor jobdesc __aligned(CACHE_WRITEBACK_GRANULE);
+
+ jobdesc.arg = NULL;
+ jobdesc.callback = rsa_done;
+
+ memset(&ctx, 0, sizeof(struct rsa_context));
+
+ ctx.pkin.a = sign;
+ ctx.pkin.a_siz = klen;
+ ctx.pkin.n = rsa_pub_key;
+ ctx.pkin.n_siz = klen;
+ ctx.pkin.e = rsa_pub_key + klen;
+ ctx.pkin.e_siz = klen;
+
+ cnstr_jobdesc_pkha_rsaexp(jobdesc.desc, &ctx.pkin, to, klen);
+
+#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
+ flush_dcache_range((uintptr_t)sign, klen);
+ flush_dcache_range((uintptr_t)rsa_pub_key, 2 * klen);
+ flush_dcache_range((uintptr_t)&ctx.pkin, sizeof(ctx.pkin));
+ inv_dcache_range((uintptr_t)to, klen);
+
+ dmbsy();
+ dsbsy();
+ isb();
+#endif
+
+ /* Finally, generate the requested random data bytes */
+ ret = run_descriptor_jr(&jobdesc);
+ if (ret != 0) {
+ ERROR("Error in running descriptor\n");
+ ret = -1;
+ }
+#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
+ inv_dcache_range((uintptr_t)to, klen);
+ dmbsy();
+ dsbsy();
+ isb();
+#endif
+ return ret;
+}
+
+/*
+ * Construct encoded hash EM' wrt PKCSv1.5. This function calculates the
+ * pointers for padding, DER value and hash. And finally, constructs EM'
+ * which includes hash of complete CSF header and ESBC image. If SG flag
+ * is on, hash of SG table and entries is also included.
+ */
+static int construct_img_encoded_hash_second(uint8_t *hash, uint8_t hash_len,
+ uint8_t *encoded_hash_second,
+ unsigned int key_len)
+{
+ /*
+ * RSA PKCSv1.5 encoding format for encoded message is below
+ * EM = 0x0 || 0x1 || PS || 0x0 || DER || Hash
+ * PS is Padding String
+ * DER is DER value for SHA-256
+ * Hash is SHA-256 hash
+ * *********************************************************
+ * representative points to first byte of EM initially and is
+ * filled with 0x0
+ * representative is incremented by 1 and second byte is filled
+ * with 0x1
+ * padding points to third byte of EM
+ * digest points to full length of EM - 32 bytes
+ * hash_id (DER value) points to 19 bytes before pDigest
+ * separator is one byte which separates padding and DER
+ */
+
+ unsigned int len;
+ uint8_t *representative;
+ uint8_t *padding, *digest;
+ uint8_t *hash_id, *separator;
+ int i;
+ int ret = 0;
+
+ if (hash_len != SHA256_BYTES) {
+ return -1;
+ }
+
+ /* Key length = Modulus length */
+ len = (key_len / 2U) - 1U;
+ representative = encoded_hash_second;
+ representative[0] = 0U;
+ representative[1] = 1U; /* block type 1 */
+
+ padding = &representative[2];
+ digest = &representative[1] + len - 32;
+ hash_id = digest - sizeof(hash_identifier);
+ separator = hash_id - 1;
+
+ /* fill padding area pointed by padding with 0xff */
+ memset(padding, 0xff, separator - padding);
+
+ /* fill byte pointed by separator */
+ *separator = 0U;
+
+ /* fill SHA-256 DER value pointed by HashId */
+ memcpy(hash_id, hash_identifier, sizeof(hash_identifier));
+
+ /* fill hash pointed by Digest */
+ for (i = 0; i < SHA256_BYTES; i++) {
+ digest[i] = hash[i];
+ }
+
+ return ret;
+}
+
+int rsa_verify_signature(void *hash_ptr, unsigned int hash_len,
+ void *sig_ptr, unsigned int sig_len,
+ void *pk_ptr, unsigned int pk_len)
+{
+ uint8_t img_encoded_hash_second[RSA_4K_KEY_SZ_BYTES];
+ uint8_t encoded_hash[RSA_4K_KEY_SZ_BYTES] __aligned(CACHE_WRITEBACK_GRANULE);
+ int ret = 0;
+
+ ret = construct_img_encoded_hash_second(hash_ptr, hash_len,
+ img_encoded_hash_second,
+ pk_len);
+ if (ret != 0) {
+ ERROR("Encoded Hash Failure\n");
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ ret = rsa_public_verif_sec(sig_ptr, encoded_hash, pk_ptr, pk_len / 2);
+ if (ret != 0) {
+ ERROR("RSA signature Failure\n");
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ ret = memcmp(img_encoded_hash_second, encoded_hash, sig_len);
+ if (ret != 0) {
+ ERROR("Comparison Failure\n");
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ return CRYPTO_SUCCESS;
+}
diff --git a/drivers/nxp/crypto/caam/src/caam.c b/drivers/nxp/crypto/caam/src/caam.c
new file mode 100644
index 0000000..e594f7b
--- /dev/null
+++ b/drivers/nxp/crypto/caam/src/caam.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include "caam.h"
+#include <common/debug.h>
+#include "jobdesc.h"
+#include "sec_hw_specific.h"
+
+static uintptr_t g_nxp_caam_addr;
+static void *job_ring;
+
+uintptr_t get_caam_addr(void)
+{
+ if (g_nxp_caam_addr == 0) {
+ ERROR("Sec Init is not done.\n");
+ panic();
+ }
+ return g_nxp_caam_addr;
+}
+
+/* This function sets the TZ bit for the Job ring number passed as @num */
+static void config_tz(int num)
+{
+ uint32_t jricid;
+
+ /* Setting TZ bit of job ring */
+ switch (num) {
+ case 0:
+ jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR0ICIDR_MS_OFFSET);
+ sec_out32(g_nxp_caam_addr + SEC_REG_JR0ICIDR_MS_OFFSET,
+ jricid | JRICID_MS_TZ);
+ break;
+ case 1:
+ jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR1ICIDR_MS_OFFSET);
+ sec_out32(g_nxp_caam_addr + SEC_REG_JR1ICIDR_MS_OFFSET,
+ jricid | JRICID_MS_TZ);
+ break;
+ case 2:
+ jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR2ICIDR_MS_OFFSET);
+ sec_out32(g_nxp_caam_addr + SEC_REG_JR2ICIDR_MS_OFFSET,
+ jricid | JRICID_MS_TZ);
+ break;
+ case 3:
+ jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR3ICIDR_MS_OFFSET);
+ sec_out32(g_nxp_caam_addr + SEC_REG_JR3ICIDR_MS_OFFSET,
+ jricid | JRICID_MS_TZ);
+ break;
+ default:
+ break;
+ }
+}
+
+/* This function checks if Virtualization is enabled for JR and
+ * accordingly sets the bot for starting JR<num> in JRSTARTR register
+ */
+static inline void start_jr(int num)
+{
+ uint32_t ctpr = sec_in32((g_nxp_caam_addr + SEC_REG_CTPR_MS_OFFSET));
+ uint32_t tmp = sec_in32((g_nxp_caam_addr + SEC_REG_JRSTARTR_OFFSET));
+ uint32_t scfgr = sec_in32((g_nxp_caam_addr + SEC_REG_SCFGR_OFFSET));
+ bool start = false;
+
+ if ((ctpr & CTPR_VIRT_EN_INC) != 0U) {
+ if (((ctpr & CTPR_VIRT_EN_POR) != 0U) ||
+ ((scfgr & SCFGR_VIRT_EN) != 0U)) {
+ start = true;
+ }
+ } else {
+ if ((ctpr & CTPR_VIRT_EN_POR) != 0U) {
+ start = true;
+ }
+ }
+
+ if (start == true) {
+ switch (num) {
+ case 0:
+ tmp |= JRSTARTR_STARTJR0;
+ break;
+ case 1:
+ tmp |= JRSTARTR_STARTJR1;
+ break;
+ case 2:
+ tmp |= JRSTARTR_STARTJR2;
+ break;
+ case 3:
+ tmp |= JRSTARTR_STARTJR3;
+ break;
+ default:
+ break;
+ }
+ }
+ sec_out32((g_nxp_caam_addr + SEC_REG_JRSTARTR_OFFSET), tmp);
+}
+
+/* This functions configures the Job Ring
+ * JR3 is reserved for use by Secure world
+ */
+static int configure_jr(int num)
+{
+ int ret;
+ void *reg_base_addr;
+
+ switch (num) {
+ case 0:
+ reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR0_OFFSET);
+ break;
+ case 1:
+ reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR1_OFFSET);
+ break;
+ case 2:
+ reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR2_OFFSET);
+ break;
+ case 3:
+ reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR3_OFFSET);
+ break;
+ default:
+ break;
+ }
+
+ /* Initialize the JR library */
+ ret = sec_jr_lib_init();
+ if (ret != 0) {
+ ERROR("Error in sec_jr_lib_init");
+ return -1;
+ }
+
+ start_jr(num);
+
+ /* Do HW configuration of the JR */
+ job_ring = init_job_ring(SEC_NOTIFICATION_TYPE_POLL, 0, 0,
+ reg_base_addr, 0);
+
+ if (job_ring == NULL) {
+ ERROR("Error in init_job_ring");
+ return -1;
+ }
+
+ return ret;
+}
+
+/* TBD - Configures and locks the ICID values for various JR */
+static inline void configure_icid(void)
+{
+}
+
+/* TBD configures the TZ settings of RTIC */
+static inline void configure_rtic(void)
+{
+}
+
+int sec_init(uintptr_t nxp_caam_addr)
+{
+ g_nxp_caam_addr = nxp_caam_addr;
+ return config_sec_block();
+}
+
+/* This function configure SEC block:
+ * - It does basic parameter setting
+ * - Configures the default Job ring assigned to TZ /secure world
+ * - Instantiates the RNG
+ */
+int config_sec_block(void)
+{
+ int ret = 0;
+ uint32_t mcfgr;
+
+ if (g_nxp_caam_addr == 0) {
+ ERROR("Sec Init is not done.\n");
+ return -1;
+ } else if (job_ring != NULL) {
+ NOTICE("Sec is already initialized and configured.\n");
+ return ret;
+ }
+
+ mcfgr = sec_in32(g_nxp_caam_addr + SEC_REG_MCFGR_OFFSET);
+
+ /* Modify CAAM Read/Write attributes
+ * AXI Write - Cacheable, WB and WA
+ * AXI Read - Cacheable, RA
+ */
+#if defined(CONFIG_ARCH_LS2080A) || defined(CONFIG_ARCH_LS2088A)
+ mcfgr = (mcfgr & ~MCFGR_AWCACHE_MASK) | (0xb << MCFGR_AWCACHE_SHIFT);
+ mcfgr = (mcfgr & ~MCFGR_ARCACHE_MASK) | (0x6 << MCFGR_ARCACHE_SHIFT);
+#else
+ mcfgr = (mcfgr & ~MCFGR_AWCACHE_MASK) | (0x2 << MCFGR_AWCACHE_SHIFT);
+#endif
+
+ /* Set PS bit to 1 */
+#ifdef CONFIG_PHYS_64BIT
+ mcfgr |= (1 << MCFGR_PS_SHIFT);
+#endif
+ sec_out32(g_nxp_caam_addr + SEC_REG_MCFGR_OFFSET, mcfgr);
+
+ /* Asssign ICID to all Job rings and lock them for usage */
+ configure_icid();
+
+ /* Configure the RTIC */
+ configure_rtic();
+
+ /* Configure the default JR for usage */
+ ret = configure_jr(DEFAULT_JR);
+ if (ret != 0) {
+ ERROR("\nFSL_JR: configuration failure\n");
+ return -1;
+ }
+ /* Do TZ configuration of default JR for sec firmware */
+ config_tz(DEFAULT_JR);
+
+#ifdef CONFIG_RNG_INIT
+ /* Instantiate the RNG */
+ ret = hw_rng_instantiate();
+ if (ret != 0) {
+ ERROR("\nRNG Instantiation failure\n");
+ return -1;
+ }
+#endif
+
+ return ret;
+}
+
+/* This function is used for sumbitting job to the Job Ring
+ * [param] [in] - jobdesc to be submitted
+ * Return - -1 in case of error and 0 in case of SUCCESS
+ */
+int run_descriptor_jr(struct job_descriptor *jobdesc)
+{
+ int i = 0, ret = 0;
+ uint32_t *desc_addr = jobdesc->desc;
+ uint32_t desc_len = desc_length(jobdesc->desc);
+ uint32_t desc_word;
+
+ for (i = 0; i < desc_len; i++) {
+ desc_word = desc_addr[i];
+ VERBOSE("%x\n", desc_word);
+ sec_out32((uint32_t *)&desc_addr[i], desc_word);
+ }
+ dsb();
+
+#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
+ flush_dcache_range((uintptr_t)desc_addr, desc_len * 4);
+ dmbsy();
+ dsbsy();
+ isb();
+#endif
+
+ ret = enq_jr_desc(job_ring, jobdesc);
+ if (ret == 0) {
+ VERBOSE("JR enqueue done...\n");
+ } else {
+ ERROR("Error in Enqueue\n");
+ return ret;
+ }
+
+ VERBOSE("Dequeue in progress");
+
+ ret = dequeue_jr(job_ring, -1);
+ if (ret >= 0) {
+ VERBOSE("Dequeue of %x desc success\n", ret);
+ ret = 0;
+ } else {
+ ERROR("deq_ret %x\n", ret);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+/* this function returns a random number using HW RNG Algo
+ * In case of failure, random number returned is 0
+ * prngWidth = 0 - 32 bit random number
+ * prngWidth > 0 means 64 bit random number
+ */
+unsigned long long get_random(int rngWidth)
+{
+ unsigned long long result = 0;
+ uint8_t rand_byte[64] __aligned(CACHE_WRITEBACK_GRANULE);
+ uint8_t rand_byte_swp[8];
+ int bytes = 0;
+ int i = 0;
+ int ret = 0;
+
+#ifdef CAAM_TEST
+ rand_byte[0] = U(0x12);
+ rand_byte[1] = U(0x34);
+ rand_byte[2] = U(0x56);
+ rand_byte[3] = U(0x78);
+ rand_byte[4] = U(0x9a);
+ rand_byte[5] = U(0xbc);
+ rand_byte[6] = U(0xde);
+ rand_byte[7] = U(0xf1);
+#endif
+
+ if (rngWidth == 0U) {
+ bytes = 4;
+ } else {
+ bytes = 8;
+ }
+
+ memset(rand_byte, 0, 64);
+
+ ret = get_rand_bytes_hw(rand_byte, bytes);
+
+ for (i = 0; i < bytes; i++) {
+ if (ret != 0) {
+ /* Return 0 in case of failure */
+ rand_byte_swp[i] = 0;
+ } else {
+ rand_byte_swp[i] = rand_byte[bytes - i - 1];
+ result = (result << 8) | rand_byte_swp[i];
+ }
+ }
+
+ INFO("result %llx\n", result);
+
+ return result;
+
+} /* _get_RNG() */
+
+unsigned int _get_hw_unq_key(uint64_t hw_key_phy_addr, unsigned int size)
+{
+ int ret = 0;
+ uint8_t *hw_key = (uint8_t *) ptov((phys_addr_t *) hw_key_phy_addr);
+
+ ret = get_hw_unq_key_blob_hw(hw_key, size);
+
+ return ret;
+}
diff --git a/drivers/nxp/crypto/caam/src/hw_key_blob.c b/drivers/nxp/crypto/caam/src/hw_key_blob.c
new file mode 100644
index 0000000..0720695
--- /dev/null
+++ b/drivers/nxp/crypto/caam/src/hw_key_blob.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "caam.h"
+#include <common/debug.h>
+#include "jobdesc.h"
+#include "sec_hw_specific.h"
+
+
+/* Callback function after Instantiation decsriptor is submitted to SEC
+ */
+static void blob_done(uint32_t *desc, uint32_t status, void *arg,
+ void *job_ring)
+{
+ INFO("Blob Desc SUCCESS with status %x\n", status);
+}
+
+/* @brief Submit descriptor to create blob
+ * @retval 0 on success
+ * @retval -1 on error
+ */
+int get_hw_unq_key_blob_hw(uint8_t *hw_key, int size)
+{
+ int ret = 0;
+ int i = 0;
+
+ uint32_t key_sz = KEY_IDNFR_SZ_BYTES;
+ uint8_t key_data[KEY_IDNFR_SZ_BYTES];
+ uint8_t in_data[16];
+ uint8_t out_data[16 + KEY_BLOB_SIZE + MAC_SIZE];
+ struct job_descriptor desc __aligned(CACHE_WRITEBACK_GRANULE);
+ struct job_descriptor *jobdesc = &desc;
+ uint32_t in_sz = 16U;
+
+ /* Output blob will have 32 bytes key blob in beginning and
+ * 16 byte HMAC identifier at end of data blob
+ */
+ uint32_t out_sz = in_sz + KEY_BLOB_SIZE + MAC_SIZE;
+
+ uint32_t operation = CMD_OPERATION | OP_TYPE_ENCAP_PROTOCOL |
+ OP_PCLID_BLOB | BLOB_PROTO_INFO;
+
+ memset(key_data, 0xff, KEY_IDNFR_SZ_BYTES);
+ memset(in_data, 0x00, in_sz);
+ memset(out_data, 0x00, in_sz);
+
+ jobdesc->arg = NULL;
+ jobdesc->callback = blob_done;
+
+ INFO("\nGenerating Master Key Verification Blob.\n");
+
+ /* Create the hw_rng descriptor */
+ ret = cnstr_hw_encap_blob_jobdesc(jobdesc->desc, key_data, key_sz,
+ CLASS_2, in_data, in_sz, out_data,
+ out_sz, operation);
+
+ /* Finally, generate the blob. */
+ ret = run_descriptor_jr(jobdesc);
+ if (ret != 0) {
+ ERROR("Error in running hw unq key blob descriptor\n");
+ return -1;
+ }
+ /* Copying alternate bytes of the Master Key Verification Blob.
+ */
+ for (i = 0; i < size; i++) {
+ hw_key[i] = out_data[2 * i];
+ }
+
+ return ret;
+}
diff --git a/drivers/nxp/crypto/caam/src/jobdesc.c b/drivers/nxp/crypto/caam/src/jobdesc.c
new file mode 100644
index 0000000..f559c4b
--- /dev/null
+++ b/drivers/nxp/crypto/caam/src/jobdesc.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2017-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "caam.h"
+#include <common/debug.h>
+#include "jobdesc.h"
+#include "rsa.h"
+#include "sec_hw_specific.h"
+
+
+/* Return Length of desctiptr from first word */
+uint32_t desc_length(uint32_t *desc)
+{
+ return desc[0] & DESC_LEN_MASK;
+}
+
+/*Update start index in first word of descriptor */
+void desc_update_start_index(uint32_t *desc, uint32_t index)
+{
+ desc[0] |= (index << DESC_START_SHIFT);
+}
+
+/* Initialize the descriptor */
+void desc_init(uint32_t *desc)
+{
+ *desc = 0;
+}
+
+/* Add word in the descriptor and increment the length */
+void desc_add_word(uint32_t *desc, uint32_t word)
+{
+ uint32_t len = desc_length(desc);
+
+ /* Add Word at Last */
+ uint32_t *last = desc + len;
+ *last = word;
+
+ /* Increase the length */
+ desc[0] += 1;
+}
+
+/* Add Pointer to the descriptor */
+void desc_add_ptr(uint32_t *desc, phys_addr_t *ptr)
+{
+ uint32_t len = desc_length(desc);
+
+ /* Add Word at Last */
+ phys_addr_t *last = (phys_addr_t *) (desc + len);
+
+#ifdef CONFIG_PHYS_64BIT
+ ptr_addr_t *ptr_addr = (ptr_addr_t *) last;
+
+ ptr_addr->high = PHYS_ADDR_HI(ptr);
+ ptr_addr->low = PHYS_ADDR_LO(ptr);
+#else
+ *last = ptr;
+#endif
+
+ /* Increase the length */
+ desc[0] += (uint32_t) (sizeof(phys_addr_t) / sizeof(uint32_t));
+}
+
+/* Descriptor to generate Random words */
+int cnstr_rng_jobdesc(uint32_t *desc, uint32_t state_handle,
+ uint32_t *add_inp, uint32_t add_ip_len,
+ uint8_t *out_data, uint32_t len)
+{
+ phys_addr_t *phys_addr_out = vtop(out_data);
+
+ /* Current descriptor support only 64K length */
+ if (len > U(0xffff))
+ return -1;
+ /* Additional Input not supported by current descriptor */
+ if (add_ip_len > 0U)
+ return -1;
+
+ VERBOSE("Constructing descriptor\n");
+ desc_init(desc);
+ /* Class1 Alg Operation,RNG Optype, Generate */
+ desc_add_word(desc, U(0xb0800000));
+ desc_add_word(desc, U(0x82500000) | (state_handle << ALG_AAI_SH_SHIFT));
+ desc_add_word(desc, U(0x60340000) | len);
+ desc_add_ptr(desc, phys_addr_out);
+
+ return 0;
+
+}
+
+/* Construct descriptor to instantiate RNG */
+int cnstr_rng_instantiate_jobdesc(uint32_t *desc)
+{
+ desc_init(desc);
+ desc_add_word(desc, U(0xb0800000));
+ /* Class1 Alg Operation,RNG Optype, Instantiate */
+ desc_add_word(desc, U(0x82500004));
+ /* Wait for done */
+ desc_add_word(desc, U(0xa2000001));
+ /*Load to clear written */
+ desc_add_word(desc, U(0x10880004));
+ /*Pri Mode Reg clear */
+ desc_add_word(desc, U(0x00000001));
+ /* Generate secure keys */
+ desc_add_word(desc, U(0x82501000));
+
+ return 0;
+}
+
+/* Construct descriptor to generate hw key blob */
+int cnstr_hw_encap_blob_jobdesc(uint32_t *desc,
+ uint8_t *key_idnfr, uint32_t key_sz,
+ uint32_t key_class, uint8_t *plain_txt,
+ uint32_t in_sz, uint8_t *enc_blob,
+ uint32_t out_sz, uint32_t operation)
+{
+ phys_addr_t *phys_key_idnfr, *phys_addr_in, *phys_addr_out;
+ int i = 0;
+
+ phys_key_idnfr = vtop((void *)key_idnfr);
+ phys_addr_in = vtop((void *)plain_txt);
+ phys_addr_out = vtop((void *)enc_blob);
+
+ desc_init(desc);
+
+ desc_add_word(desc, U(0xb0800000));
+
+ /* Key Identifier */
+ desc_add_word(desc, (key_class | key_sz));
+ desc_add_ptr(desc, phys_key_idnfr);
+
+ /* Source Address */
+ desc_add_word(desc, U(0xf0400000));
+ desc_add_ptr(desc, phys_addr_in);
+
+ /* In Size = 0x10 */
+ desc_add_word(desc, in_sz);
+
+ /* Out Address */
+ desc_add_word(desc, U(0xf8400000));
+ desc_add_ptr(desc, phys_addr_out);
+
+ /* Out Size = 0x10 */
+ desc_add_word(desc, out_sz);
+
+ /* Operation */
+ desc_add_word(desc, operation);
+
+ for (i = 0; i < 15; i++)
+ VERBOSE("desc word %x\n", desc[i]);
+
+ return 0;
+}
+
+/***************************************************************************
+ * Function : inline_cnstr_jobdesc_pkha_rsaexp
+ * Arguments : desc - Pointer to Descriptor
+ * pkin - Pointer to Input Params
+ * out - Pointer to Output
+ * out_siz - Output Size
+ * Return : Void
+ * Description : Creates the descriptor for PKHA RSA
+ ***************************************************************************/
+void cnstr_jobdesc_pkha_rsaexp(uint32_t *desc,
+ struct pk_in_params *pkin, uint8_t *out,
+ uint32_t out_siz)
+{
+ phys_addr_t *ptr_addr_e, *ptr_addr_a, *ptr_addr_n, *ptr_addr_out;
+
+ ptr_addr_e = vtop((void *)(pkin->e));
+ ptr_addr_a = vtop((void *)(pkin->a));
+ ptr_addr_n = vtop((void *)(pkin->n));
+ ptr_addr_out = vtop((void *)(out));
+
+ desc_init(desc);
+ desc_add_word(desc, U(0xb0800000));
+ desc_add_word(desc, U(0x02010000) | pkin->e_siz);
+ desc_add_ptr(desc, ptr_addr_e);
+ desc_add_word(desc, U(0x220c0000) | pkin->a_siz);
+ desc_add_ptr(desc, ptr_addr_a);
+ desc_add_word(desc, U(0x22080000) | pkin->n_siz);
+ desc_add_ptr(desc, ptr_addr_n);
+ desc_add_word(desc, U(0x81800006));
+ desc_add_word(desc, U(0x620d0000) | out_siz);
+ desc_add_ptr(desc, ptr_addr_out);
+}
+
+/***************************************************************************
+ * Function : inline_cnstr_jobdesc_sha256
+ * Arguments : desc - Pointer to Descriptor
+ * msg - Pointer to SG Table
+ * msgsz - Size of SG Table
+ * digest - Pointer to Output Digest
+ * Return : Void
+ * Description : Creates the descriptor for SHA256 HASH calculation
+ ***************************************************************************/
+void cnstr_hash_jobdesc(uint32_t *desc, uint8_t *msg, uint32_t msgsz,
+ uint8_t *digest)
+{
+ /* SHA 256 , output is of length 32 words */
+ phys_addr_t *ptr_addr_in, *ptr_addr_out;
+
+ ptr_addr_in = (void *)vtop(msg);
+ ptr_addr_out = (void *)vtop(digest);
+
+ desc_init(desc);
+ desc_add_word(desc, U(0xb0800000));
+
+ /* Operation Command
+ * OP_TYPE_CLASS2_ALG | OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HASH |
+ * OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT | OP_ALG_ICV_OFF)
+ */
+ desc_add_word(desc, U(0x8443000d));
+
+ if (msgsz > U(0xffff)) {
+ desc_add_word(desc, U(0x25540000)); /* FIFO Load */
+ desc_add_ptr(desc, ptr_addr_in); /* Pointer to msg */
+ desc_add_word(desc, msgsz); /* Size */
+ desc_add_word(desc, U(0x54200020)); /* FIFO Store */
+ desc_add_ptr(desc, ptr_addr_out); /* Pointer to Result */
+ } else {
+ desc_add_word(desc, U(0x25140000) | msgsz);
+ desc_add_ptr(desc, ptr_addr_in);
+ desc_add_word(desc, U(0x54200020));
+ desc_add_ptr(desc, ptr_addr_out);
+ }
+
+}
diff --git a/drivers/nxp/crypto/caam/src/rng.c b/drivers/nxp/crypto/caam/src/rng.c
new file mode 100644
index 0000000..0b9d87d
--- /dev/null
+++ b/drivers/nxp/crypto/caam/src/rng.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <arch_helpers.h>
+#include "caam.h"
+#include <common/debug.h>
+#include "jobdesc.h"
+#include "sec_hw_specific.h"
+
+
+/* Callback function after Instantiation decsriptor is submitted to SEC */
+static void rng_done(uint32_t *desc, uint32_t status, void *arg,
+ void *job_ring)
+{
+ INFO("RNG Desc SUCCESS with status %x\n", status);
+}
+
+/* Is the HW RNG instantiated?
+ * Return code:
+ * 0 - Not in the instantiated state
+ * 1 - In the instantiated state
+ * state_handle - 0 for SH0, 1 for SH1
+ */
+static int is_hw_rng_instantiated(uint32_t *state_handle)
+{
+ int ret_code = 0;
+ uint32_t rdsta;
+
+ rdsta = sec_in32(get_caam_addr() + RNG_REG_RDSTA_OFFSET);
+
+ /*Check if either of the two state handles has been instantiated */
+ if (rdsta & RNG_STATE0_HANDLE_INSTANTIATED) {
+ *state_handle = 0;
+ ret_code = 1;
+ } else if (rdsta & RNG_STATE0_HANDLE_INSTANTIATED) {
+ *state_handle = 1;
+ ret_code = 1;
+ }
+
+ return ret_code;
+}
+
+/* @brief Kick the TRNG block of the RNG HW Engine
+ * @param [in] ent_delay Entropy delay to be used
+ * By default, the TRNG runs for 200 clocks per sample;
+ * 1200 clocks per sample generates better entropy.
+ * @retval 0 on success
+ * @retval -1 on error
+ */
+static void kick_trng(int ent_delay)
+{
+ uint32_t val;
+
+ /* put RNG4 into program mode */
+ val = sec_in32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET);
+ val = val | RTMCTL_PRGM;
+ sec_out32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET, val);
+
+ /* rtsdctl bits 0-15 contain "Entropy Delay, which defines the
+ * length (in system clocks) of each Entropy sample taken
+ */
+ val = sec_in32(get_caam_addr() + RNG_REG_RTSDCTL_OFFSET);
+ val = (val & ~RTSDCTL_ENT_DLY_MASK) |
+ (ent_delay << RTSDCTL_ENT_DLY_SHIFT);
+ sec_out32(get_caam_addr() + RNG_REG_RTSDCTL_OFFSET, val);
+ /* min. freq. count, equal to 1/4 of the entropy sample length */
+ sec_out32(get_caam_addr() + RNG_REG_RTFRQMIN_OFFSET, ent_delay >> 2);
+ /* disable maximum frequency count */
+ sec_out32(get_caam_addr() + RNG_REG_RTFRQMAX_OFFSET, RTFRQMAX_DISABLE);
+
+ /* select raw sampling in both entropy shifter
+ * and statistical checker
+ */
+ val = sec_in32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET);
+ val = val | RTMCTL_SAMP_MODE_RAW_ES_SC;
+ sec_out32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET, val);
+
+ /* put RNG4 into run mode */
+ val = sec_in32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET);
+ val = val & ~RTMCTL_PRGM;
+ sec_out32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET, val);
+}
+
+/* @brief Submit descriptor to instantiate the RNG
+ * @retval 0 on success
+ * @retval -1 on error
+ */
+static int instantiate_rng(void)
+{
+ int ret = 0;
+ struct job_descriptor desc __aligned(CACHE_WRITEBACK_GRANULE);
+ struct job_descriptor *jobdesc = &desc;
+
+ jobdesc->arg = NULL;
+ jobdesc->callback = rng_done;
+
+ /* create the hw_rng descriptor */
+ cnstr_rng_instantiate_jobdesc(jobdesc->desc);
+
+ /* Finally, generate the requested random data bytes */
+ ret = run_descriptor_jr(jobdesc);
+ if (ret != 0) {
+ ERROR("Error in running descriptor\n");
+ ret = -1;
+ }
+ return ret;
+}
+
+/* Generate Random Data using HW RNG
+ * Parameters:
+ * uint8_t* add_input - user specified optional input byte array
+ * uint32_t add_input_len - number of bytes of additional input
+ * uint8_t* out - user specified output byte array
+ * uint32_t out_len - number of bytes to store in output byte array
+ * Return code:
+ * 0 - SUCCESS
+ * -1 - ERROR
+ */
+static int
+hw_rng_generate(uint32_t *add_input, uint32_t add_input_len,
+ uint8_t *out, uint32_t out_len, uint32_t state_handle)
+{
+ int ret = 0;
+ struct job_descriptor desc __aligned(CACHE_WRITEBACK_GRANULE);
+ struct job_descriptor *jobdesc = &desc;
+
+ jobdesc->arg = NULL;
+ jobdesc->callback = rng_done;
+
+#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
+ inv_dcache_range((uintptr_t)out, out_len);
+ dmbsy();
+#endif
+
+ /* create the hw_rng descriptor */
+ ret = cnstr_rng_jobdesc(jobdesc->desc, state_handle,
+ add_input, add_input_len, out, out_len);
+ if (ret != 0) {
+ ERROR("Descriptor construction failed\n");
+ ret = -1;
+ goto out;
+ }
+ /* Finally, generate the requested random data bytes */
+ ret = run_descriptor_jr(jobdesc);
+ if (ret != 0) {
+ ERROR("Error in running descriptor\n");
+ ret = -1;
+ }
+
+out:
+ return ret;
+}
+
+/* this function instantiates the rng
+ *
+ * Return code:
+ * 0 - All is well
+ * <0 - Error occurred somewhere
+ */
+int hw_rng_instantiate(void)
+{
+ int ret = 0;
+ int ent_delay = RTSDCTL_ENT_DLY_MIN;
+ uint32_t state_handle;
+
+ ret = is_hw_rng_instantiated(&state_handle);
+ if (ret != 0) {
+ NOTICE("RNG already instantiated\n");
+ return 0;
+ }
+ do {
+ kick_trng(ent_delay);
+ ent_delay += 400;
+ /*if instantiate_rng(...) fails, the loop will rerun
+ *and the kick_trng(...) function will modify the
+ *upper and lower limits of the entropy sampling
+ *interval, leading to a sucessful initialization of
+ */
+ ret = instantiate_rng();
+ } while ((ret == -1) && (ent_delay < RTSDCTL_ENT_DLY_MAX));
+ if (ret != 0) {
+ ERROR("RNG: Failed to instantiate RNG\n");
+ return ret;
+ }
+
+ NOTICE("RNG: INSTANTIATED\n");
+
+ /* Enable RDB bit so that RNG works faster */
+ // sec_setbits32(&sec->scfgr, SEC_SCFGR_RDBENABLE);
+
+ return ret;
+}
+
+/* Generate random bytes, and stuff them into the bytes buffer
+ *
+ * If the HW RNG has not already been instantiated,
+ * it will be instantiated before data is generated.
+ *
+ * Parameters:
+ * uint8_t* bytes - byte buffer large enough to hold the requested random date
+ * int byte_len - number of random bytes to generate
+ *
+ * Return code:
+ * 0 - All is well
+ * ~0 - Error occurred somewhere
+ */
+int get_rand_bytes_hw(uint8_t *bytes, int byte_len)
+{
+ int ret_code = 0;
+ uint32_t state_handle;
+
+ /* If this is the first time this routine is called,
+ * then the hash_drbg will not already be instantiated.
+ * Therefore, before generating data, instantiate the hash_drbg
+ */
+ ret_code = is_hw_rng_instantiated(&state_handle);
+ if (ret_code == 0) {
+ INFO("Instantiating the HW RNG\n");
+
+ /* Instantiate the hw RNG */
+ ret_code = hw_rng_instantiate();
+ if (ret_code != 0) {
+ ERROR("HW RNG Instantiate failed\n");
+ return ret_code;
+ }
+ }
+ /* If HW RNG is still not instantiated, something must have gone wrong,
+ * it must be in the error state, we will not generate any random data
+ */
+ if (is_hw_rng_instantiated(&state_handle) == 0) {
+ ERROR("HW RNG is in an Error state, and cannot be used\n");
+ return -1;
+ }
+ /* Generate a random 256-bit value, as 32 bytes */
+ ret_code = hw_rng_generate(0, 0, bytes, byte_len, state_handle);
+ if (ret_code != 0) {
+ ERROR("HW RNG Generate failed\n");
+ return ret_code;
+ }
+
+ return ret_code;
+}
diff --git a/drivers/nxp/crypto/caam/src/sec_hw_specific.c b/drivers/nxp/crypto/caam/src/sec_hw_specific.c
new file mode 100644
index 0000000..92b7762
--- /dev/null
+++ b/drivers/nxp/crypto/caam/src/sec_hw_specific.c
@@ -0,0 +1,635 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <arch_helpers.h>
+#include "caam.h"
+#include <common/debug.h>
+#include "jobdesc.h"
+#include "sec_hw_specific.h"
+
+
+/* Job rings used for communication with SEC HW */
+extern struct sec_job_ring_t g_job_rings[MAX_SEC_JOB_RINGS];
+
+/* The current state of SEC user space driver */
+extern volatile sec_driver_state_t g_driver_state;
+
+/* The number of job rings used by SEC user space driver */
+extern int g_job_rings_no;
+
+/* LOCAL FUNCTIONS */
+static inline void hw_set_input_ring_start_addr(struct jobring_regs *regs,
+ phys_addr_t *start_addr)
+{
+#if defined(CONFIG_PHYS_64BIT)
+ sec_out32(&regs->irba_h, PHYS_ADDR_HI(start_addr));
+#else
+ sec_out32(&regs->irba_h, 0);
+#endif
+ sec_out32(&regs->irba_l, PHYS_ADDR_LO(start_addr));
+}
+
+static inline void hw_set_output_ring_start_addr(struct jobring_regs *regs,
+ phys_addr_t *start_addr)
+{
+#if defined(CONFIG_PHYS_64BIT)
+ sec_out32(&regs->orba_h, PHYS_ADDR_HI(start_addr));
+#else
+ sec_out32(&regs->orba_h, 0);
+#endif
+ sec_out32(&regs->orba_l, PHYS_ADDR_LO(start_addr));
+}
+
+/* ORJR - Output Ring Jobs Removed Register shows how many jobs were
+ * removed from the Output Ring for processing by software. This is done after
+ * the software has processed the entries.
+ */
+static inline void hw_remove_entries(sec_job_ring_t *jr, int num)
+{
+ struct jobring_regs *regs =
+ (struct jobring_regs *)jr->register_base_addr;
+
+ sec_out32(&regs->orjr, num);
+}
+
+/* IRSA - Input Ring Slots Available register holds the number of entries in
+ * the Job Ring's input ring. Once a job is enqueued, the value returned is
+ * decremented by the hardware by the number of jobs enqueued.
+ */
+static inline int hw_get_available_slots(sec_job_ring_t *jr)
+{
+ struct jobring_regs *regs =
+ (struct jobring_regs *)jr->register_base_addr;
+
+ return sec_in32(&regs->irsa);
+}
+
+/* ORSFR - Output Ring Slots Full register holds the number of jobs which were
+ * processed by the SEC and can be retrieved by the software. Once a job has
+ * been processed by software, the user will call hw_remove_one_entry in order
+ * to notify the SEC that the entry was processed
+ */
+static inline int hw_get_no_finished_jobs(sec_job_ring_t *jr)
+{
+ struct jobring_regs *regs =
+ (struct jobring_regs *)jr->register_base_addr;
+
+ return sec_in32(&regs->orsf);
+}
+
+/* @brief Process Jump Halt Condition related errors
+ * @param [in] error_code The error code in the descriptor status word
+ */
+static inline void hw_handle_jmp_halt_cond_err(union hw_error_code error_code)
+{
+ ERROR("JMP %x\n", error_code.error_desc.jmp_halt_cond_src.jmp);
+ ERROR("Descriptor Index: %d\n",
+ error_code.error_desc.jmp_halt_cond_src.desc_idx);
+ ERROR(" Condition %x\n", error_code.error_desc.jmp_halt_cond_src.cond);
+}
+
+/* @brief Process DECO related errors
+ * @param [in] error_code The error code in the descriptor status word
+ */
+static inline void hw_handle_deco_err(union hw_error_code error_code)
+{
+ ERROR("JMP %x\n", error_code.error_desc.deco_src.jmp);
+ ERROR("Descriptor Index: 0x%x",
+ error_code.error_desc.deco_src.desc_idx);
+
+ switch (error_code.error_desc.deco_src.desc_err) {
+ case SEC_HW_ERR_DECO_HFN_THRESHOLD:
+ WARN(" Descriptor completed but exceeds the Threshold");
+ break;
+ default:
+ ERROR("Error 0x%04x not implemented",
+ error_code.error_desc.deco_src.desc_err);
+ break;
+ }
+}
+
+/* @brief Process Jump Halt User Status related errors
+ * @param [in] error_code The error code in the descriptor status word
+ */
+static inline void hw_handle_jmp_halt_user_err(union hw_error_code error_code)
+{
+ WARN(" Not implemented");
+}
+
+/* @brief Process CCB related errors
+ * @param [in] error_code The error code in the descriptor status word
+ */
+static inline void hw_handle_ccb_err(union hw_error_code hw_error_code)
+{
+ WARN(" Not implemented");
+}
+
+/* @brief Process Job Ring related errors
+ * @param [in] error_code The error code in the descriptor status word
+ */
+static inline void hw_handle_jr_err(union hw_error_code hw_error_code)
+{
+ WARN(" Not implemented");
+}
+
+/* GLOBAL FUNCTIONS */
+
+int hw_reset_job_ring(sec_job_ring_t *job_ring)
+{
+ int ret = 0;
+ struct jobring_regs *regs =
+ (struct jobring_regs *)job_ring->register_base_addr;
+
+ /* First reset the job ring in hw */
+ ret = hw_shutdown_job_ring(job_ring);
+ if (ret != 0) {
+ ERROR("Failed resetting job ring in hardware");
+ return ret;
+ }
+ /* In order to have the HW JR in a workable state
+ *after a reset, I need to re-write the input
+ * queue size, input start address, output queue
+ * size and output start address
+ * Write the JR input queue size to the HW register
+ */
+ sec_out32(&regs->irs, SEC_JOB_RING_SIZE);
+
+ /* Write the JR output queue size to the HW register */
+ sec_out32(&regs->ors, SEC_JOB_RING_SIZE);
+
+ /* Write the JR input queue start address */
+ hw_set_input_ring_start_addr(regs, vtop(job_ring->input_ring));
+
+ /* Write the JR output queue start address */
+ hw_set_output_ring_start_addr(regs, vtop(job_ring->output_ring));
+
+ return 0;
+}
+
+int hw_shutdown_job_ring(sec_job_ring_t *job_ring)
+{
+ struct jobring_regs *regs =
+ (struct jobring_regs *)job_ring->register_base_addr;
+ unsigned int timeout = SEC_TIMEOUT;
+ uint32_t tmp = 0U;
+
+ VERBOSE("Resetting Job ring\n");
+
+ /*
+ * Mask interrupts since we are going to poll
+ * for reset completion status
+ * Also, at POR, interrupts are ENABLED on a JR, thus
+ * this is the point where I can disable them without
+ * changing the code logic too much
+ */
+
+ jr_disable_irqs(job_ring);
+
+ /* initiate flush (required prior to reset) */
+ sec_out32(&regs->jrcr, JR_REG_JRCR_VAL_RESET);
+
+ /* dummy read */
+ tmp = sec_in32(&regs->jrcr);
+
+ do {
+ tmp = sec_in32(&regs->jrint);
+ } while (((tmp & JRINT_ERR_HALT_MASK) ==
+ JRINT_ERR_HALT_INPROGRESS) && ((--timeout) != 0U));
+
+ if ((tmp & JRINT_ERR_HALT_MASK) != JRINT_ERR_HALT_COMPLETE ||
+ timeout == 0U) {
+ ERROR("Failed to flush hw job ring %x\n %u", tmp, timeout);
+ /* unmask interrupts */
+ if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL) {
+ jr_enable_irqs(job_ring);
+ }
+ return -1;
+ }
+ /* Initiate reset */
+ timeout = SEC_TIMEOUT;
+ sec_out32(&regs->jrcr, JR_REG_JRCR_VAL_RESET);
+
+ do {
+ tmp = sec_in32(&regs->jrcr);
+ } while (((tmp & JR_REG_JRCR_VAL_RESET) != 0U) &&
+ ((--timeout) != 0U));
+
+ if (timeout == 0U) {
+ ERROR("Failed to reset hw job ring\n");
+ /* unmask interrupts */
+ if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL) {
+ jr_enable_irqs(job_ring);
+ }
+ return -1;
+ }
+ /* unmask interrupts */
+ if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL) {
+ jr_enable_irqs(job_ring);
+ }
+ return 0;
+
+}
+
+void hw_handle_job_ring_error(sec_job_ring_t *job_ring, uint32_t error_code)
+{
+ union hw_error_code hw_err_code;
+
+ hw_err_code.error = error_code;
+
+ switch (hw_err_code.error_desc.value.ssrc) {
+ case SEC_HW_ERR_SSRC_NO_SRC:
+ INFO("No Status Source ");
+ break;
+ case SEC_HW_ERR_SSRC_CCB_ERR:
+ INFO("CCB Status Source");
+ hw_handle_ccb_err(hw_err_code);
+ break;
+ case SEC_HW_ERR_SSRC_JMP_HALT_U:
+ INFO("Jump Halt User Status Source");
+ hw_handle_jmp_halt_user_err(hw_err_code);
+ break;
+ case SEC_HW_ERR_SSRC_DECO:
+ INFO("DECO Status Source");
+ hw_handle_deco_err(hw_err_code);
+ break;
+ case SEC_HW_ERR_SSRC_JR:
+ INFO("Job Ring Status Source");
+ hw_handle_jr_err(hw_err_code);
+ break;
+ case SEC_HW_ERR_SSRC_JMP_HALT_COND:
+ INFO("Jump Halt Condition Codes");
+ hw_handle_jmp_halt_cond_err(hw_err_code);
+ break;
+ default:
+ INFO("Unknown SSRC");
+ break;
+ }
+}
+
+int hw_job_ring_error(sec_job_ring_t *job_ring)
+{
+ uint32_t jrint_error_code;
+ struct jobring_regs *regs =
+ (struct jobring_regs *)job_ring->register_base_addr;
+
+ if (JR_REG_JRINT_JRE_EXTRACT(sec_in32(&regs->jrint)) == 0) {
+ return 0;
+ }
+
+ jrint_error_code =
+ JR_REG_JRINT_ERR_TYPE_EXTRACT(sec_in32(&regs->jrint));
+ switch (jrint_error_code) {
+ case JRINT_ERR_WRITE_STATUS:
+ ERROR("Error writing status to Output Ring ");
+ break;
+ case JRINT_ERR_BAD_INPUT_BASE:
+ ERROR("Bad Input Ring Base (not on a 4-byte boundary)\n");
+ break;
+ case JRINT_ERR_BAD_OUTPUT_BASE:
+ ERROR("Bad Output Ring Base (not on a 4-byte boundary)\n");
+ break;
+ case JRINT_ERR_WRITE_2_IRBA:
+ ERROR("Invalid write to Input Ring Base Address Register\n");
+ break;
+ case JRINT_ERR_WRITE_2_ORBA:
+ ERROR("Invalid write to Output Ring Base Address Register\n");
+ break;
+ case JRINT_ERR_RES_B4_HALT:
+ ERROR("Job Ring released before Job Ring is halted\n");
+ break;
+ case JRINT_ERR_REM_TOO_MANY:
+ ERROR("Removed too many jobs from job ring\n");
+ break;
+ case JRINT_ERR_ADD_TOO_MANY:
+ ERROR("Added too many jobs on job ring\n");
+ break;
+ default:
+ ERROR("Unknown SEC JR Error :%d\n", jrint_error_code);
+ break;
+ }
+ return jrint_error_code;
+}
+
+int hw_job_ring_set_coalescing_param(sec_job_ring_t *job_ring,
+ uint16_t irq_coalescing_timer,
+ uint8_t irq_coalescing_count)
+{
+ uint32_t reg_val = 0U;
+ struct jobring_regs *regs =
+ (struct jobring_regs *)job_ring->register_base_addr;
+
+ /* Set descriptor count coalescing */
+ reg_val |= (irq_coalescing_count << JR_REG_JRCFG_LO_ICDCT_SHIFT);
+
+ /* Set coalescing timer value */
+ reg_val |= (irq_coalescing_timer << JR_REG_JRCFG_LO_ICTT_SHIFT);
+
+ /* Update parameters in HW */
+ sec_out32(&regs->jrcfg1, reg_val);
+
+ VERBOSE("Set coalescing params on jr\n");
+
+ return 0;
+}
+
+int hw_job_ring_enable_coalescing(sec_job_ring_t *job_ring)
+{
+ uint32_t reg_val = 0U;
+ struct jobring_regs *regs =
+ (struct jobring_regs *)job_ring->register_base_addr;
+
+ /* Get the current value of the register */
+ reg_val = sec_in32(&regs->jrcfg1);
+
+ /* Enable coalescing */
+ reg_val |= JR_REG_JRCFG_LO_ICEN_EN;
+
+ /* Write in hw */
+ sec_out32(&regs->jrcfg1, reg_val);
+
+ VERBOSE("Enabled coalescing on jr\n");
+
+ return 0;
+}
+
+int hw_job_ring_disable_coalescing(sec_job_ring_t *job_ring)
+{
+ uint32_t reg_val = 0U;
+ struct jobring_regs *regs =
+ (struct jobring_regs *)job_ring->register_base_addr;
+
+ /* Get the current value of the register */
+ reg_val = sec_in32(&regs->jrcfg1);
+
+ /* Disable coalescing */
+ reg_val &= ~JR_REG_JRCFG_LO_ICEN_EN;
+
+ /* Write in hw */
+ sec_out32(&regs->jrcfg1, reg_val);
+
+ VERBOSE("Disabled coalescing on jr");
+
+ return 0;
+
+}
+
+void hw_flush_job_ring(struct sec_job_ring_t *job_ring,
+ uint32_t do_notify,
+ uint32_t error_code, uint32_t *notified_descs)
+{
+ int32_t jobs_no_to_discard = 0;
+ int32_t discarded_descs_no = 0;
+ int32_t number_of_jobs_available = 0;
+
+ VERBOSE("JR pi[%d]i ci[%d]\n", job_ring->pidx, job_ring->cidx);
+ VERBOSE("error code %x\n", error_code);
+ VERBOSE("Notify_desc = %d\n", do_notify);
+
+ number_of_jobs_available = hw_get_no_finished_jobs(job_ring);
+
+ /* Discard all jobs */
+ jobs_no_to_discard = number_of_jobs_available;
+
+ VERBOSE("JR pi[%d]i ci[%d]\n", job_ring->pidx, job_ring->cidx);
+ VERBOSE("Discarding desc = %d\n", jobs_no_to_discard);
+
+ while (jobs_no_to_discard > discarded_descs_no) {
+ discarded_descs_no++;
+ /* Now increment the consumer index for the current job ring,
+ * AFTER saving job in temporary location!
+ * Increment the consumer index for the current job ring
+ */
+
+ job_ring->cidx = SEC_CIRCULAR_COUNTER(job_ring->cidx,
+ SEC_JOB_RING_SIZE);
+
+ hw_remove_entries(job_ring, 1);
+ }
+
+ if (do_notify == true) {
+ if (notified_descs == NULL) {
+ return;
+ }
+ *notified_descs = discarded_descs_no;
+ }
+}
+
+/* return >0 in case of success
+ * -1 in case of error from SEC block
+ * 0 in case job not yet processed by SEC
+ * or Descriptor returned is NULL after dequeue
+ */
+int hw_poll_job_ring(struct sec_job_ring_t *job_ring, int32_t limit)
+{
+ int32_t jobs_no_to_notify = 0;
+ int32_t number_of_jobs_available = 0;
+ int32_t notified_descs_no = 0;
+ uint32_t error_descs_no = 0U;
+ uint32_t sec_error_code = 0U;
+ uint32_t do_driver_shutdown = false;
+ phys_addr_t *fnptr, *arg_addr;
+ user_callback usercall = NULL;
+ uint8_t *current_desc;
+ void *arg;
+ uintptr_t current_desc_addr;
+ phys_addr_t current_desc_loc;
+
+#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
+ inv_dcache_range((uintptr_t)job_ring->register_base_addr, sizeof(struct jobring_regs));
+ dmbsy();
+#endif
+
+ /* check here if any JR error that cannot be written
+ * in the output status word has occurred
+ */
+ sec_error_code = hw_job_ring_error(job_ring);
+ if (unlikely(sec_error_code) != 0) {
+ ERROR("Error here itself %x\n", sec_error_code);
+ return -1;
+ }
+ /* Compute the number of notifications that need to be raised to UA
+ * If limit < 0 -> notify all done jobs
+ * If limit > total number of done jobs -> notify all done jobs
+ * If limit = 0 -> error
+ * If limit > 0 && limit < total number of done jobs -> notify a number
+ * of done jobs equal with limit
+ */
+
+ /*compute the number of jobs available in the job ring based on the
+ * producer and consumer index values.
+ */
+
+ number_of_jobs_available = hw_get_no_finished_jobs(job_ring);
+ jobs_no_to_notify = (limit < 0 || limit > number_of_jobs_available) ?
+ number_of_jobs_available : limit;
+ VERBOSE("JR - pi %d, ci %d, ", job_ring->pidx, job_ring->cidx);
+ VERBOSE("Jobs submitted %d", number_of_jobs_available);
+ VERBOSE("Jobs to notify %d\n", jobs_no_to_notify);
+
+ while (jobs_no_to_notify > notified_descs_no) {
+
+#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
+ inv_dcache_range(
+ (uintptr_t)(&job_ring->output_ring[job_ring->cidx]),
+ sizeof(struct sec_outring_entry));
+ dmbsy();
+#endif
+
+ /* Get job status here */
+ sec_error_code =
+ sec_in32(&(job_ring->output_ring[job_ring->cidx].status));
+
+ /* Get completed descriptor
+ */
+ current_desc_loc = (uintptr_t)
+ &job_ring->output_ring[job_ring->cidx].desc;
+ current_desc_addr = sec_read_addr(current_desc_loc);
+
+ current_desc = ptov((phys_addr_t *) current_desc_addr);
+ if (current_desc == 0) {
+ ERROR("No descriptor returned from SEC");
+ assert(current_desc);
+ return 0;
+ }
+ /* now increment the consumer index for the current job ring,
+ * AFTER saving job in temporary location!
+ */
+ job_ring->cidx = SEC_CIRCULAR_COUNTER(job_ring->cidx,
+ SEC_JOB_RING_SIZE);
+
+ if (sec_error_code != 0) {
+ ERROR("desc at cidx %d\n ", job_ring->cidx);
+ ERROR("generated error %x\n", sec_error_code);
+
+ sec_handle_desc_error(job_ring,
+ sec_error_code,
+ &error_descs_no,
+ &do_driver_shutdown);
+ hw_remove_entries(job_ring, 1);
+
+ return -1;
+ }
+ /* Signal that the job has been processed & the slot is free */
+ hw_remove_entries(job_ring, 1);
+ notified_descs_no++;
+
+ arg_addr = (phys_addr_t *) (current_desc +
+ (MAX_DESC_SIZE_WORDS * sizeof(uint32_t)));
+
+ fnptr = (phys_addr_t *) (current_desc +
+ (MAX_DESC_SIZE_WORDS * sizeof(uint32_t)
+ + sizeof(void *)));
+
+ arg = (void *)*(arg_addr);
+ if (*fnptr != 0) {
+ VERBOSE("Callback Function called\n");
+ usercall = (user_callback) *(fnptr);
+ (*usercall) ((uint32_t *) current_desc,
+ sec_error_code, arg, job_ring);
+ }
+ }
+
+ return notified_descs_no;
+}
+
+void sec_handle_desc_error(sec_job_ring_t *job_ring,
+ uint32_t sec_error_code,
+ uint32_t *notified_descs,
+ uint32_t *do_driver_shutdown)
+{
+ /* Analyze the SEC error on this job ring */
+ hw_handle_job_ring_error(job_ring, sec_error_code);
+}
+
+void flush_job_rings(void)
+{
+ struct sec_job_ring_t *job_ring = NULL;
+ int i = 0;
+
+ for (i = 0; i < g_job_rings_no; i++) {
+ job_ring = &g_job_rings[i];
+ /* Producer index is frozen. If consumer index is not equal
+ * with producer index, then we have descs to flush.
+ */
+ while (job_ring->pidx != job_ring->cidx) {
+ hw_flush_job_ring(job_ring, false, 0, /* no error */
+ NULL);
+ }
+ }
+}
+
+int shutdown_job_ring(struct sec_job_ring_t *job_ring)
+{
+ int ret = 0;
+
+ ret = hw_shutdown_job_ring(job_ring);
+ if (ret != 0) {
+ ERROR("Failed to shutdown hardware job ring\n");
+ return ret;
+ }
+
+ if (job_ring->coalescing_en != 0) {
+ hw_job_ring_disable_coalescing(job_ring);
+ }
+
+ if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL) {
+ ret = jr_disable_irqs(job_ring);
+ if (ret != 0) {
+ ERROR("Failed to disable irqs for job ring");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int jr_enable_irqs(struct sec_job_ring_t *job_ring)
+{
+ uint32_t reg_val = 0U;
+ struct jobring_regs *regs =
+ (struct jobring_regs *)job_ring->register_base_addr;
+
+ /* Get the current value of the register */
+ reg_val = sec_in32(&regs->jrcfg1);
+
+ /* Enable interrupts by disabling interrupt masking*/
+ reg_val &= ~JR_REG_JRCFG_LO_IMSK_EN;
+
+ /* Update parameters in HW */
+ sec_out32(&regs->jrcfg1, reg_val);
+
+ VERBOSE("Enable interrupts on JR\n");
+
+ return 0;
+}
+
+int jr_disable_irqs(struct sec_job_ring_t *job_ring)
+{
+ uint32_t reg_val = 0U;
+ struct jobring_regs *regs =
+ (struct jobring_regs *)job_ring->register_base_addr;
+
+ /* Get the current value of the register */
+ reg_val = sec_in32(&regs->jrcfg1);
+
+ /* Disable interrupts by enabling interrupt masking*/
+ reg_val |= JR_REG_JRCFG_LO_IMSK_EN;
+
+ /* Update parameters in HW */
+ sec_out32(&regs->jrcfg1, reg_val);
+
+ VERBOSE("Disable interrupts on JR\n");
+
+ return 0;
+}
diff --git a/drivers/nxp/crypto/caam/src/sec_jr_driver.c b/drivers/nxp/crypto/caam/src/sec_jr_driver.c
new file mode 100644
index 0000000..1fe7007
--- /dev/null
+++ b/drivers/nxp/crypto/caam/src/sec_jr_driver.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include "caam.h"
+#include <common/debug.h>
+#include "jobdesc.h"
+#include "nxp_timer.h"
+#include "sec_hw_specific.h"
+#include "sec_jr_driver.h"
+
+
+/* Job rings used for communication with SEC HW */
+struct sec_job_ring_t g_job_rings[MAX_SEC_JOB_RINGS];
+
+/* The current state of SEC user space driver */
+volatile sec_driver_state_t g_driver_state = SEC_DRIVER_STATE_IDLE;
+
+int g_job_rings_no;
+
+uint8_t ip_ring[SEC_DMA_MEM_INPUT_RING_SIZE] __aligned(CACHE_WRITEBACK_GRANULE);
+uint8_t op_ring[SEC_DMA_MEM_OUTPUT_RING_SIZE] __aligned(CACHE_WRITEBACK_GRANULE);
+
+void *init_job_ring(uint8_t jr_mode,
+ uint16_t irq_coalescing_timer,
+ uint8_t irq_coalescing_count,
+ void *reg_base_addr, uint32_t irq_id)
+{
+ struct sec_job_ring_t *job_ring = &g_job_rings[g_job_rings_no++];
+ int ret = 0;
+
+ job_ring->register_base_addr = reg_base_addr;
+ job_ring->jr_mode = jr_mode;
+ job_ring->irq_fd = irq_id;
+
+ job_ring->input_ring = vtop(ip_ring);
+ memset(job_ring->input_ring, 0, SEC_DMA_MEM_INPUT_RING_SIZE);
+
+ job_ring->output_ring = (struct sec_outring_entry *)vtop(op_ring);
+ memset(job_ring->output_ring, 0, SEC_DMA_MEM_OUTPUT_RING_SIZE);
+
+ dsb();
+
+#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
+ flush_dcache_range((uintptr_t)(job_ring->input_ring),
+ SEC_DMA_MEM_INPUT_RING_SIZE),
+ flush_dcache_range((uintptr_t)(job_ring->output_ring),
+ SEC_DMA_MEM_OUTPUT_RING_SIZE),
+
+ dmbsy();
+#endif
+ /* Reset job ring in SEC hw and configure job ring registers */
+ ret = hw_reset_job_ring(job_ring);
+ if (ret != 0) {
+ ERROR("Failed to reset hardware job ring\n");
+ return NULL;
+ }
+
+ if (jr_mode == SEC_NOTIFICATION_TYPE_IRQ) {
+ /* Enable IRQ if driver work sin interrupt mode */
+ ERROR("Enabling DONE IRQ generation on job ring\n");
+ ret = jr_enable_irqs(job_ring);
+ if (ret != 0) {
+ ERROR("Failed to enable irqs for job ring\n");
+ return NULL;
+ }
+ }
+ if ((irq_coalescing_timer != 0) || (irq_coalescing_count != 0)) {
+ hw_job_ring_set_coalescing_param(job_ring,
+ irq_coalescing_timer,
+ irq_coalescing_count);
+
+ hw_job_ring_enable_coalescing(job_ring);
+ job_ring->coalescing_en = 1;
+ }
+
+ job_ring->jr_state = SEC_JOB_RING_STATE_STARTED;
+
+ return job_ring;
+}
+
+int sec_release(void)
+{
+ int i;
+
+ /* Validate driver state */
+ if (g_driver_state == SEC_DRIVER_STATE_RELEASE) {
+ ERROR("Driver release is already in progress");
+ return SEC_DRIVER_RELEASE_IN_PROGRESS;
+ }
+ /* Update driver state */
+ g_driver_state = SEC_DRIVER_STATE_RELEASE;
+
+ /* If any descriptors in flight , poll and wait
+ * until all descriptors are received and silently discarded.
+ */
+
+ flush_job_rings();
+
+ for (i = 0; i < g_job_rings_no; i++) {
+ shutdown_job_ring(&g_job_rings[i]);
+ }
+ g_job_rings_no = 0;
+ g_driver_state = SEC_DRIVER_STATE_IDLE;
+
+ return SEC_SUCCESS;
+}
+
+int sec_jr_lib_init(void)
+{
+ /* Validate driver state */
+ if (g_driver_state != SEC_DRIVER_STATE_IDLE) {
+ ERROR("Driver already initialized\n");
+ return 0;
+ }
+
+ memset(g_job_rings, 0, sizeof(g_job_rings));
+ g_job_rings_no = 0;
+
+ /* Update driver state */
+ g_driver_state = SEC_DRIVER_STATE_STARTED;
+ return 0;
+}
+
+int dequeue_jr(void *job_ring_handle, int32_t limit)
+{
+ int ret = 0;
+ int notified_descs_no = 0;
+ struct sec_job_ring_t *job_ring = (sec_job_ring_t *) job_ring_handle;
+ uint64_t start_time;
+
+ /* Validate driver state */
+ if (g_driver_state != SEC_DRIVER_STATE_STARTED) {
+ ERROR("Driver release in progress or driver not initialized\n");
+ return -1;
+ }
+
+ /* Validate input arguments */
+ if (job_ring == NULL) {
+ ERROR("job_ring_handle is NULL\n");
+ return -1;
+ }
+ if (((limit == 0) || (limit > SEC_JOB_RING_SIZE))) {
+ ERROR("Invalid limit parameter configuration\n");
+ return -1;
+ }
+
+ VERBOSE("JR Polling limit[%d]\n", limit);
+
+ /* Poll job ring
+ * If limit < 0 -> poll JR until no more notifications are available.
+ * If limit > 0 -> poll JR until limit is reached.
+ */
+
+ start_time = get_timer_val(0);
+
+ while (notified_descs_no == 0) {
+ /* Run hw poll job ring */
+ notified_descs_no = hw_poll_job_ring(job_ring, limit);
+ if (notified_descs_no < 0) {
+ ERROR("Error polling SEC engine job ring ");
+ return notified_descs_no;
+ }
+ VERBOSE("Jobs notified[%d]. ", notified_descs_no);
+
+ if (get_timer_val(start_time) >= CAAM_TIMEOUT) {
+ break;
+ }
+ }
+
+ if (job_ring->jr_mode == SEC_NOTIFICATION_TYPE_IRQ) {
+
+ /* Always enable IRQ generation when in pure IRQ mode */
+ ret = jr_enable_irqs(job_ring);
+ if (ret != 0) {
+ ERROR("Failed to enable irqs for job ring");
+ return ret;
+ }
+ }
+ return notified_descs_no;
+}
+
+int enq_jr_desc(void *job_ring_handle, struct job_descriptor *jobdescr)
+{
+ struct sec_job_ring_t *job_ring;
+
+ job_ring = (struct sec_job_ring_t *)job_ring_handle;
+
+ /* Validate driver state */
+ if (g_driver_state != SEC_DRIVER_STATE_STARTED) {
+ ERROR("Driver release in progress or driver not initialized\n");
+ return -1;
+ }
+
+ /* Check job ring state */
+ if (job_ring->jr_state != SEC_JOB_RING_STATE_STARTED) {
+ ERROR("Job ring is currently resetting\n");
+ return -1;
+ }
+
+ if (SEC_JOB_RING_IS_FULL(job_ring->pidx, job_ring->cidx,
+ SEC_JOB_RING_SIZE, SEC_JOB_RING_SIZE)) {
+ ERROR("Job ring is full\n");
+ return -1;
+ }
+
+ /* Set ptr in input ring to current descriptor */
+ sec_write_addr(&job_ring->input_ring[job_ring->pidx],
+ (phys_addr_t) vtop(jobdescr->desc));
+
+ dsb();
+
+#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
+ flush_dcache_range((uintptr_t)(&job_ring->input_ring[job_ring->pidx]),
+ sizeof(phys_addr_t));
+
+ inv_dcache_range((uintptr_t)(&job_ring->output_ring[job_ring->cidx]),
+ sizeof(struct sec_outring_entry));
+ dmbsy();
+#endif
+ /* Notify HW that a new job is enqueued */
+ hw_enqueue_desc_on_job_ring(
+ (struct jobring_regs *)job_ring->register_base_addr, 1);
+
+ /* increment the producer index for the current job ring */
+ job_ring->pidx = SEC_CIRCULAR_COUNTER(job_ring->pidx,
+ SEC_JOB_RING_SIZE);
+
+ return 0;
+}
diff --git a/drivers/nxp/csu/csu.c b/drivers/nxp/csu/csu.c
new file mode 100644
index 0000000..9f90fe0
--- /dev/null
+++ b/drivers/nxp/csu/csu.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <endian.h>
+
+#include <common/debug.h>
+#include <csu.h>
+#include <lib/mmio.h>
+
+void enable_layerscape_ns_access(struct csu_ns_dev_st *csu_ns_dev,
+ uint32_t num, uintptr_t nxp_csu_addr)
+{
+ uint32_t *base = (uint32_t *)nxp_csu_addr;
+ uint32_t *reg;
+ uint32_t val;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ reg = base + csu_ns_dev[i].ind / 2U;
+ val = be32toh(mmio_read_32((uintptr_t)reg));
+ if (csu_ns_dev[i].ind % 2U == 0U) {
+ val &= 0x0000ffffU;
+ val |= csu_ns_dev[i].val << 16U;
+ } else {
+ val &= 0xffff0000U;
+ val |= csu_ns_dev[i].val;
+ }
+ mmio_write_32((uintptr_t)reg, htobe32(val));
+ }
+}
diff --git a/drivers/nxp/csu/csu.mk b/drivers/nxp/csu/csu.mk
new file mode 100644
index 0000000..bc16035
--- /dev/null
+++ b/drivers/nxp/csu/csu.mk
@@ -0,0 +1,26 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-----------------------------------------------------------------------------
+ifeq (${CSU_ADDED},)
+
+CSU_ADDED := 1
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/csu
+
+CSU_SOURCES += $(PLAT_DRIVERS_PATH)/csu/csu.c
+
+ifeq (${BL_COMM_CSU_NEEDED},yes)
+BL_COMMON_SOURCES += ${CSU_SOURCES}
+else
+ifeq (${BL2_CSU_NEEDED},yes)
+BL2_SOURCES += ${CSU_SOURCES}
+endif
+ifeq (${BL31_CSU_NEEDED},yes)
+BL31_SOURCES += ${CSU_SOURCES}
+endif
+endif
+
+endif
diff --git a/drivers/nxp/dcfg/dcfg.c b/drivers/nxp/dcfg/dcfg.c
new file mode 100644
index 0000000..e5c4db4
--- /dev/null
+++ b/drivers/nxp/dcfg/dcfg.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2020-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <common/debug.h>
+#include "dcfg.h"
+#include <lib/mmio.h>
+#ifdef NXP_SFP_ENABLED
+#include <sfp.h>
+#endif
+
+static soc_info_t soc_info = {0};
+static devdisr5_info_t devdisr5_info = {0};
+static dcfg_init_info_t *dcfg_init_info;
+
+/* Read the PORSR1 register */
+uint32_t read_reg_porsr1(void)
+{
+ unsigned int *porsr1_addr = NULL;
+
+ if (dcfg_init_info->porsr1 != 0U) {
+ return dcfg_init_info->porsr1;
+ }
+
+ porsr1_addr = (void *)
+ (dcfg_init_info->g_nxp_dcfg_addr + DCFG_PORSR1_OFFSET);
+ dcfg_init_info->porsr1 = gur_in32(porsr1_addr);
+
+ return dcfg_init_info->porsr1;
+}
+
+
+const soc_info_t *get_soc_info(void)
+{
+ uint32_t reg;
+
+ if (soc_info.is_populated == true) {
+ return (const soc_info_t *) &soc_info;
+ }
+
+ reg = gur_in32(dcfg_init_info->g_nxp_dcfg_addr + DCFG_SVR_OFFSET);
+
+ soc_info.svr_reg.val = reg;
+
+ /* zero means SEC enabled. */
+ soc_info.sec_enabled =
+ (((reg & SVR_SEC_MASK) >> SVR_SEC_SHIFT) == 0) ? true : false;
+
+ soc_info.is_populated = true;
+ return (const soc_info_t *) &soc_info;
+}
+
+void dcfg_init(dcfg_init_info_t *dcfg_init_data)
+{
+ dcfg_init_info = dcfg_init_data;
+ read_reg_porsr1();
+ get_soc_info();
+}
+
+bool is_sec_enabled(void)
+{
+ return soc_info.sec_enabled;
+}
+
+const devdisr5_info_t *get_devdisr5_info(void)
+{
+ uint32_t reg;
+
+ if (devdisr5_info.is_populated == true)
+ return (const devdisr5_info_t *) &devdisr5_info;
+
+ reg = gur_in32(dcfg_init_info->g_nxp_dcfg_addr + DCFG_DEVDISR5_OFFSET);
+
+ devdisr5_info.ddrc1_present = (reg & DISR5_DDRC1_MASK) ? 0 : 1;
+#if defined(CONFIG_CHASSIS_3_2)
+ devdisr5_info.ddrc2_present = (reg & DISR5_DDRC2_MASK) ? 0 : 1;
+#endif
+ devdisr5_info.ocram_present = (reg & DISR5_OCRAM_MASK) ? 0 : 1;
+ devdisr5_info.is_populated = true;
+
+ return (const devdisr5_info_t *) &devdisr5_info;
+}
+
+int get_clocks(struct sysinfo *sys)
+{
+ unsigned int *rcwsr0 = NULL;
+ const unsigned long sysclk = dcfg_init_info->nxp_sysclk_freq;
+ const unsigned long ddrclk = dcfg_init_info->nxp_ddrclk_freq;
+
+ rcwsr0 = (void *)(dcfg_init_info->g_nxp_dcfg_addr + RCWSR0_OFFSET);
+ sys->freq_platform = sysclk;
+ sys->freq_ddr_pll0 = ddrclk;
+ sys->freq_ddr_pll1 = ddrclk;
+
+ sys->freq_platform *= (gur_in32(rcwsr0) >>
+ RCWSR0_SYS_PLL_RAT_SHIFT) &
+ RCWSR0_SYS_PLL_RAT_MASK;
+
+ sys->freq_platform /= dcfg_init_info->nxp_plat_clk_divider;
+
+ sys->freq_ddr_pll0 *= (gur_in32(rcwsr0) >>
+ RCWSR0_MEM_PLL_RAT_SHIFT) &
+ RCWSR0_MEM_PLL_RAT_MASK;
+ sys->freq_ddr_pll1 *= (gur_in32(rcwsr0) >>
+ RCWSR0_MEM2_PLL_RAT_SHIFT) &
+ RCWSR0_MEM2_PLL_RAT_MASK;
+ if (sys->freq_platform == 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+#ifdef NXP_SFP_ENABLED
+/*******************************************************************************
+ * Returns true if secur eboot is enabled on board
+ * mode = 0 (development mode - sb_en = 1)
+ * mode = 1 (production mode - ITS = 1)
+ ******************************************************************************/
+bool check_boot_mode_secure(uint32_t *mode)
+{
+ uint32_t val = 0U;
+ uint32_t *rcwsr = NULL;
+ *mode = 0U;
+
+ if (sfp_check_its() == 1) {
+ /* ITS =1 , Production mode */
+ *mode = 1U;
+ return true;
+ }
+
+ rcwsr = (void *)(dcfg_init_info->g_nxp_dcfg_addr + RCWSR_SB_EN_OFFSET);
+
+ val = (gur_in32(rcwsr) >> RCWSR_SBEN_SHIFT) &
+ RCWSR_SBEN_MASK;
+
+ if (val == RCWSR_SBEN_MASK) {
+ *mode = 0U;
+ return true;
+ }
+
+ return false;
+}
+#endif
+
+void error_handler(int error_code)
+{
+ /* Dump error code in SCRATCH4 register */
+ INFO("Error in Fuse Provisioning: %x\n", error_code);
+ gur_out32((void *)
+ (dcfg_init_info->g_nxp_dcfg_addr + DCFG_SCRATCH4_OFFSET),
+ error_code);
+}
diff --git a/drivers/nxp/dcfg/dcfg.mk b/drivers/nxp/dcfg/dcfg.mk
new file mode 100644
index 0000000..206595f
--- /dev/null
+++ b/drivers/nxp/dcfg/dcfg.mk
@@ -0,0 +1,26 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${ADD_DCFG},)
+
+ADD_DCFG := 1
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/dcfg
+
+DCFG_SOURCES += $(PLAT_DRIVERS_PATH)/dcfg/dcfg.c
+
+ifeq (${BL_COMM_DCFG_NEEDED},yes)
+BL_COMMON_SOURCES += ${DCFG_SOURCES}
+else
+ifeq (${BL2_DCFG_NEEDED},yes)
+BL2_SOURCES += ${DCFG_SOURCES}
+endif
+ifeq (${BL31_DCFG_NEEDED},yes)
+BL31_SOURCES += ${DCFG_SOURCES}
+endif
+endif
+
+endif
diff --git a/drivers/nxp/ddr/fsl-mmdc/ddr.mk b/drivers/nxp/ddr/fsl-mmdc/ddr.mk
new file mode 100644
index 0000000..afccb62
--- /dev/null
+++ b/drivers/nxp/ddr/fsl-mmdc/ddr.mk
@@ -0,0 +1,19 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-----------------------------------------------------------------------------
+
+# MMDC ddr cntlr driver files
+
+DDR_DRIVERS_PATH := drivers/nxp/ddr
+
+DDR_CNTLR_SOURCES := ${PLAT_DRIVERS_PATH}/ddr/fsl-mmdc/fsl_mmdc.c \
+ ${PLAT_DRIVERS_PATH}/ddr/nxp-ddr/utility.c \
+ ${PLAT_DRIVERS_PATH}/ddr/nxp-ddr/ddr.c \
+ ${PLAT_DRIVERS_PATH}/ddr/nxp-ddr/ddrc.c
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/ddr \
+ -I$(PLAT_DRIVERS_INCLUDE_PATH)/ddr/fsl-mmdc
+#------------------------------------------------
diff --git a/drivers/nxp/ddr/fsl-mmdc/fsl_mmdc.c b/drivers/nxp/ddr/fsl-mmdc/fsl_mmdc.c
new file mode 100644
index 0000000..7e6504e
--- /dev/null
+++ b/drivers/nxp/ddr/fsl-mmdc/fsl_mmdc.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*
+ * Generic driver for Freescale MMDC(Multi Mode DDR Controller).
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include "ddr_io.h"
+#include <drivers/delay_timer.h>
+#include <fsl_mmdc.h>
+
+static void set_wait_for_bits_clear(void *ptr, unsigned int value,
+ unsigned int bits)
+{
+ int timeout = 1000;
+
+ ddr_out32(ptr, value);
+
+ while ((ddr_in32(ptr) & bits) != 0) {
+ udelay(100);
+ timeout--;
+ }
+ if (timeout <= 0) {
+ INFO("Error: %llx", (unsigned long long)ptr);
+ INFO(" wait for clear timeout.\n");
+ }
+}
+
+void mmdc_init(const struct fsl_mmdc_info *priv, uintptr_t nxp_ddr_addr)
+{
+ struct mmdc_regs *mmdc = (struct mmdc_regs *)nxp_ddr_addr;
+ unsigned int tmp;
+
+ /* 1. set configuration request */
+ ddr_out32(&mmdc->mdscr, MDSCR_ENABLE_CON_REQ);
+
+ /* 2. configure the desired timing parameters */
+ ddr_out32(&mmdc->mdotc, priv->mdotc);
+ ddr_out32(&mmdc->mdcfg0, priv->mdcfg0);
+ ddr_out32(&mmdc->mdcfg1, priv->mdcfg1);
+ ddr_out32(&mmdc->mdcfg2, priv->mdcfg2);
+
+ /* 3. configure DDR type and other miscellaneous parameters */
+ ddr_out32(&mmdc->mdmisc, priv->mdmisc);
+ ddr_out32(&mmdc->mpmur0, MMDC_MPMUR0_FRC_MSR);
+ ddr_out32(&mmdc->mdrwd, priv->mdrwd);
+ ddr_out32(&mmdc->mpodtctrl, priv->mpodtctrl);
+
+ /* 4. configure the required delay while leaving reset */
+ ddr_out32(&mmdc->mdor, priv->mdor);
+
+ /* 5. configure DDR physical parameters */
+ /* set row/column address width, burst length, data bus width */
+ tmp = priv->mdctl & ~(MDCTL_SDE0 | MDCTL_SDE1);
+ ddr_out32(&mmdc->mdctl, tmp);
+ /* configure address space partition */
+ ddr_out32(&mmdc->mdasp, priv->mdasp);
+
+ /* 6. perform a ZQ calibration - not needed here, doing in #8b */
+
+ /* 7. enable MMDC with the desired chip select */
+#if (DDRC_NUM_CS == 1)
+ ddr_out32(&mmdc->mdctl, tmp | MDCTL_SDE0);
+#elif (DDRC_NUM_CS == 2)
+ ddr_out32(&mmdc->mdctl, tmp | MDCTL_SDE0 | MDCTL_SDE1);
+#else
+#error "Unsupported DDRC_NUM_CS"
+#endif
+
+ /* 8a. dram init sequence: update MRs for ZQ, ODT, PRE, etc */
+ ddr_out32(&mmdc->mdscr, CMD_ADDR_LSB_MR_ADDR(8) |
+ MDSCR_ENABLE_CON_REQ |
+ CMD_LOAD_MODE_REG |
+ CMD_BANK_ADDR_2);
+
+ ddr_out32(&mmdc->mdscr, CMD_ADDR_LSB_MR_ADDR(0) |
+ MDSCR_ENABLE_CON_REQ |
+ CMD_LOAD_MODE_REG |
+ CMD_BANK_ADDR_3);
+
+ ddr_out32(&mmdc->mdscr, CMD_ADDR_LSB_MR_ADDR(4) |
+ MDSCR_ENABLE_CON_REQ |
+ CMD_LOAD_MODE_REG |
+ CMD_BANK_ADDR_1);
+
+ ddr_out32(&mmdc->mdscr, CMD_ADDR_MSB_MR_OP(0x19) |
+ CMD_ADDR_LSB_MR_ADDR(0x30) |
+ MDSCR_ENABLE_CON_REQ |
+ CMD_LOAD_MODE_REG | CMD_BANK_ADDR_0);
+
+ /* 8b. ZQ calibration */
+ ddr_out32(&mmdc->mdscr, CMD_ADDR_MSB_MR_OP(0x4) |
+ MDSCR_ENABLE_CON_REQ |
+ CMD_ZQ_CALIBRATION | CMD_BANK_ADDR_0);
+
+ set_wait_for_bits_clear(&mmdc->mpzqhwctrl, priv->mpzqhwctrl,
+ MPZQHWCTRL_ZQ_HW_FORCE);
+
+ /* 9a. calibrations now, wr lvl */
+ ddr_out32(&mmdc->mdscr, CMD_ADDR_LSB_MR_ADDR(0x84) | MDSCR_WL_EN |
+ MDSCR_ENABLE_CON_REQ |
+ CMD_LOAD_MODE_REG | CMD_BANK_ADDR_1);
+
+ set_wait_for_bits_clear(&mmdc->mpwlgcr, MPWLGCR_HW_WL_EN,
+ MPWLGCR_HW_WL_EN);
+
+ mdelay(1);
+
+ ddr_out32(&mmdc->mdscr, CMD_ADDR_LSB_MR_ADDR(4) |
+ MDSCR_ENABLE_CON_REQ |
+ CMD_LOAD_MODE_REG | CMD_BANK_ADDR_1);
+
+ ddr_out32(&mmdc->mdscr, MDSCR_ENABLE_CON_REQ);
+
+ mdelay(1);
+
+ /* 9b. read DQS gating calibration */
+ ddr_out32(&mmdc->mdscr, CMD_ADDR_MSB_MR_OP(4) | MDSCR_ENABLE_CON_REQ |
+ CMD_PRECHARGE_BANK_OPEN | CMD_BANK_ADDR_0);
+
+ ddr_out32(&mmdc->mdscr, CMD_ADDR_LSB_MR_ADDR(4) | MDSCR_ENABLE_CON_REQ |
+ CMD_LOAD_MODE_REG | CMD_BANK_ADDR_3);
+
+ ddr_out32(&mmdc->mppdcmpr2, MPPDCMPR2_MPR_COMPARE_EN);
+
+ /* set absolute read delay offset */
+ if (priv->mprddlctl != 0) {
+ ddr_out32(&mmdc->mprddlctl, priv->mprddlctl);
+ } else {
+ ddr_out32(&mmdc->mprddlctl, MMDC_MPRDDLCTL_DEFAULT_DELAY);
+ }
+
+ set_wait_for_bits_clear(&mmdc->mpdgctrl0,
+ AUTO_RD_DQS_GATING_CALIBRATION_EN,
+ AUTO_RD_DQS_GATING_CALIBRATION_EN);
+
+ ddr_out32(&mmdc->mdscr, MDSCR_ENABLE_CON_REQ | CMD_LOAD_MODE_REG |
+ CMD_BANK_ADDR_3);
+
+ /* 9c. read calibration */
+ ddr_out32(&mmdc->mdscr, CMD_ADDR_MSB_MR_OP(4) | MDSCR_ENABLE_CON_REQ |
+ CMD_PRECHARGE_BANK_OPEN | CMD_BANK_ADDR_0);
+ ddr_out32(&mmdc->mdscr, CMD_ADDR_LSB_MR_ADDR(4) | MDSCR_ENABLE_CON_REQ |
+ CMD_LOAD_MODE_REG | CMD_BANK_ADDR_3);
+ ddr_out32(&mmdc->mppdcmpr2, MPPDCMPR2_MPR_COMPARE_EN);
+ set_wait_for_bits_clear(&mmdc->mprddlhwctl,
+ MPRDDLHWCTL_AUTO_RD_CALIBRATION_EN,
+ MPRDDLHWCTL_AUTO_RD_CALIBRATION_EN);
+
+ ddr_out32(&mmdc->mdscr, MDSCR_ENABLE_CON_REQ | CMD_LOAD_MODE_REG |
+ CMD_BANK_ADDR_3);
+
+ /* 10. configure power-down, self-refresh entry, exit parameters */
+ ddr_out32(&mmdc->mdpdc, priv->mdpdc);
+ ddr_out32(&mmdc->mapsr, MMDC_MAPSR_PWR_SAV_CTRL_STAT);
+
+ /* 11. ZQ config again? do nothing here */
+
+ /* 12. refresh scheme */
+ set_wait_for_bits_clear(&mmdc->mdref, priv->mdref,
+ MDREF_START_REFRESH);
+
+ /* 13. disable CON_REQ */
+ ddr_out32(&mmdc->mdscr, MDSCR_DISABLE_CFG_REQ);
+}
diff --git a/drivers/nxp/ddr/nxp-ddr/README.odt b/drivers/nxp/ddr/nxp-ddr/README.odt
new file mode 100644
index 0000000..8796302
--- /dev/null
+++ b/drivers/nxp/ddr/nxp-ddr/README.odt
@@ -0,0 +1,31 @@
+Table for dynamic ODT for DDR4 with PHY generation 2
+====================================================
+Two-slot system
+Only symmetric configurations are supported for interleaving. Non-symmetric
+configurations are possible but not covered here. First slot empty is possbile
+but prohibited for simplicity.
++-----------------------+-------------+---------------+-----------------------------+-----------------------------+
+| Configuration | |DRAM controller| Slot 1 | Slot 2 |
++-----------+-----------+-------------+-------+-------+--------------+--------------+--------------+--------------+
+| | | | | | Rank 1 | Rank 2 | Rank 1 | Rank 2 |
+| Slot 1 | Slot 2 | Write/Read | Write | Read |-------+------+-------+------+-------+------+-------+------+
+| | | | | | Write | Read | Write | Read | Write | Read | Write | Read |
++-----------+-----------+------+------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+| | | |Rank 1| off | 60 | 240 | off | 60 | 240 | 60 | 60 | 60 | 60 |
+| | |Slot 1|------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+| | | |Rank 2| off | 60 | 60 | 240 | 240 | off | 60 | 60 | 60 | 60 |
+| Dual Rank | Dual Rank |------+------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+| | | |Rank 1| off | 60 | 60 | 60 | 60 | 60 | 240 | off | 60 | 240 |
+| | |Slot 2|------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+| | | |Rank 2| off | 60 | 60 | 60 | 60 | 60 | 60 | 240 | 240 | off |
++-----------+-----------+------+------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+| | | Slot 1 | off | 60 | 80 | off | | | | | | |
+|Single Rank|Single Rank|-------------+-------+-------+-------+------+-------+------+-------+------+-------+------+
+| | | Slot 2 | off | 60 | | | | | 80 | off |
++-----------+-----------+------+------+-------+-------+-------+------+-------+------+-------+------+
+| | | |Rank 1| off | 80 | 80 | off | off | off |
+| Dual Rank | |Slot 1|------+-------+-------+-------+------+-------+------+
+| | | |Rank 2| off | 80 | 80 | off | off | off |
++-----------+-----------+-------------+-------+-------+-------+------+-------+------+
+|Single Rank| | Slot 1 | off | 80 | 80 | off |
++-----------+-----------+-------------+-------+-------+-------+------+
diff --git a/drivers/nxp/ddr/nxp-ddr/ddr.c b/drivers/nxp/ddr/nxp-ddr/ddr.c
new file mode 100644
index 0000000..c051b3b
--- /dev/null
+++ b/drivers/nxp/ddr/nxp-ddr/ddr.c
@@ -0,0 +1,931 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <ddr.h>
+#ifndef CONFIG_DDR_NODIMM
+#include <i2c.h>
+#endif
+#include <nxp_timer.h>
+
+struct dynamic_odt {
+ unsigned int odt_rd_cfg;
+ unsigned int odt_wr_cfg;
+ unsigned int odt_rtt_norm;
+ unsigned int odt_rtt_wr;
+};
+
+#ifndef CONFIG_STATIC_DDR
+#if defined(PHY_GEN2_FW_IMAGE_BUFFER) && !defined(NXP_DDR_PHY_GEN2)
+#error Missing NXP_DDR_PHY_GEN2
+#endif
+#ifdef NXP_DDR_PHY_GEN2
+static const struct dynamic_odt single_D[4] = {
+ { /* cs0 */
+ DDR_ODT_NEVER,
+ DDR_ODT_ALL,
+ DDR4_RTT_80_OHM,
+ DDR4_RTT_WR_OFF
+ },
+ { /* cs1 */
+ DDR_ODT_NEVER,
+ DDR_ODT_NEVER,
+ DDR4_RTT_OFF,
+ DDR4_RTT_WR_OFF
+ },
+ {},
+ {}
+};
+
+static const struct dynamic_odt single_S[4] = {
+ { /* cs0 */
+ DDR_ODT_NEVER,
+ DDR_ODT_ALL,
+ DDR4_RTT_80_OHM,
+ DDR4_RTT_WR_OFF
+ },
+ {},
+ {},
+ {},
+};
+
+static const struct dynamic_odt dual_DD[4] = {
+ { /* cs0 */
+ DDR_ODT_OTHER_DIMM,
+ DDR_ODT_ALL,
+ DDR4_RTT_60_OHM,
+ DDR4_RTT_WR_240_OHM
+ },
+ { /* cs1 */
+ DDR_ODT_OTHER_DIMM,
+ DDR_ODT_ALL,
+ DDR4_RTT_60_OHM,
+ DDR4_RTT_WR_240_OHM
+ },
+ { /* cs2 */
+ DDR_ODT_OTHER_DIMM,
+ DDR_ODT_ALL,
+ DDR4_RTT_60_OHM,
+ DDR4_RTT_WR_240_OHM
+ },
+ { /* cs3 */
+ DDR_ODT_OTHER_DIMM,
+ DDR_ODT_ALL,
+ DDR4_RTT_60_OHM,
+ DDR4_RTT_WR_240_OHM
+ }
+};
+
+static const struct dynamic_odt dual_SS[4] = {
+ { /* cs0 */
+ DDR_ODT_NEVER,
+ DDR_ODT_ALL,
+ DDR4_RTT_80_OHM,
+ DDR4_RTT_WR_OFF
+ },
+ {},
+ { /* cs2 */
+ DDR_ODT_NEVER,
+ DDR_ODT_ALL,
+ DDR4_RTT_80_OHM,
+ DDR4_RTT_WR_OFF
+ },
+ {}
+};
+
+static const struct dynamic_odt dual_D0[4] = {
+ { /* cs0 */
+ DDR_ODT_NEVER,
+ DDR_ODT_SAME_DIMM,
+ DDR4_RTT_80_OHM,
+ DDR4_RTT_WR_OFF
+ },
+ { /* cs1 */
+ DDR_ODT_NEVER,
+ DDR_ODT_NEVER,
+ DDR4_RTT_80_OHM,
+ DDR4_RTT_WR_OFF
+ },
+ {},
+ {}
+};
+
+static const struct dynamic_odt dual_S0[4] = {
+ { /* cs0 */
+ DDR_ODT_NEVER,
+ DDR_ODT_CS,
+ DDR4_RTT_80_OHM,
+ DDR4_RTT_WR_OFF
+ },
+ {},
+ {},
+ {}
+};
+#else
+static const struct dynamic_odt single_D[4] = {
+ { /* cs0 */
+ DDR_ODT_NEVER,
+ DDR_ODT_ALL,
+ DDR4_RTT_40_OHM,
+ DDR4_RTT_WR_OFF
+ },
+ { /* cs1 */
+ DDR_ODT_NEVER,
+ DDR_ODT_NEVER,
+ DDR4_RTT_OFF,
+ DDR4_RTT_WR_OFF
+ },
+ {},
+ {}
+};
+
+static const struct dynamic_odt single_S[4] = {
+ { /* cs0 */
+ DDR_ODT_NEVER,
+ DDR_ODT_ALL,
+ DDR4_RTT_40_OHM,
+ DDR4_RTT_WR_OFF
+ },
+ {},
+ {},
+ {},
+};
+
+static const struct dynamic_odt dual_DD[4] = {
+ { /* cs0 */
+ DDR_ODT_NEVER,
+ DDR_ODT_SAME_DIMM,
+ DDR4_RTT_120_OHM,
+ DDR4_RTT_WR_OFF
+ },
+ { /* cs1 */
+ DDR_ODT_OTHER_DIMM,
+ DDR_ODT_OTHER_DIMM,
+ DDR4_RTT_34_OHM,
+ DDR4_RTT_WR_OFF
+ },
+ { /* cs2 */
+ DDR_ODT_NEVER,
+ DDR_ODT_SAME_DIMM,
+ DDR4_RTT_120_OHM,
+ DDR4_RTT_WR_OFF
+ },
+ { /* cs3 */
+ DDR_ODT_OTHER_DIMM,
+ DDR_ODT_OTHER_DIMM,
+ DDR4_RTT_34_OHM,
+ DDR4_RTT_WR_OFF
+ }
+};
+
+static const struct dynamic_odt dual_SS[4] = {
+ { /* cs0 */
+ DDR_ODT_OTHER_DIMM,
+ DDR_ODT_ALL,
+ DDR4_RTT_34_OHM,
+ DDR4_RTT_WR_120_OHM
+ },
+ {},
+ { /* cs2 */
+ DDR_ODT_OTHER_DIMM,
+ DDR_ODT_ALL,
+ DDR4_RTT_34_OHM,
+ DDR4_RTT_WR_120_OHM
+ },
+ {}
+};
+
+static const struct dynamic_odt dual_D0[4] = {
+ { /* cs0 */
+ DDR_ODT_NEVER,
+ DDR_ODT_SAME_DIMM,
+ DDR4_RTT_40_OHM,
+ DDR4_RTT_WR_OFF
+ },
+ { /* cs1 */
+ DDR_ODT_NEVER,
+ DDR_ODT_NEVER,
+ DDR4_RTT_OFF,
+ DDR4_RTT_WR_OFF
+ },
+ {},
+ {}
+};
+
+static const struct dynamic_odt dual_S0[4] = {
+ { /* cs0 */
+ DDR_ODT_NEVER,
+ DDR_ODT_CS,
+ DDR4_RTT_40_OHM,
+ DDR4_RTT_WR_OFF
+ },
+ {},
+ {},
+ {}
+};
+#endif /* NXP_DDR_PHY_GEN2 */
+
+/*
+ * Automatically select bank interleaving mode based on DIMMs
+ * in this order: cs0_cs1_cs2_cs3, cs0_cs1, null.
+ * This function only deal with one or two slots per controller.
+ */
+static inline unsigned int auto_bank_intlv(const int cs_in_use,
+ const struct dimm_params *pdimm)
+{
+ switch (cs_in_use) {
+ case 0xf:
+ return DDR_BA_INTLV_CS0123;
+ case 0x3:
+ return DDR_BA_INTLV_CS01;
+ case 0x1:
+ return DDR_BA_NONE;
+ case 0x5:
+ return DDR_BA_NONE;
+ default:
+ break;
+ }
+
+ return 0U;
+}
+
+static int cal_odt(const unsigned int clk,
+ struct memctl_opt *popts,
+ struct ddr_conf *conf,
+ struct dimm_params *pdimm,
+ const int dimm_slot_per_ctrl)
+
+{
+ unsigned int i;
+ const struct dynamic_odt *pdodt = NULL;
+
+ const static struct dynamic_odt *table[2][5] = {
+ {single_S, single_D, NULL, NULL},
+ {dual_SS, dual_DD, NULL, NULL},
+ };
+
+ if (dimm_slot_per_ctrl != 1 && dimm_slot_per_ctrl != 2) {
+ ERROR("Unsupported number of DIMMs\n");
+ return -EINVAL;
+ }
+
+ pdodt = table[dimm_slot_per_ctrl - 1][pdimm->n_ranks - 1];
+ if (pdodt == dual_SS) {
+ pdodt = (conf->cs_in_use == 0x5) ? dual_SS :
+ ((conf->cs_in_use == 0x1) ? dual_S0 : NULL);
+ } else if (pdodt == dual_DD) {
+ pdodt = (conf->cs_in_use == 0xf) ? dual_DD :
+ ((conf->cs_in_use == 0x3) ? dual_D0 : NULL);
+ }
+ if (pdodt == dual_DD && pdimm->package_3ds) {
+ ERROR("Too many 3DS DIMMs.\n");
+ return -EINVAL;
+ }
+
+ if (pdodt == NULL) {
+ ERROR("Error determing ODT.\n");
+ return -EINVAL;
+ }
+
+ /* Pick chip-select local options. */
+ for (i = 0U; i < DDRC_NUM_CS; i++) {
+ debug("cs %d\n", i);
+ popts->cs_odt[i].odt_rd_cfg = pdodt[i].odt_rd_cfg;
+ debug(" odt_rd_cfg 0x%x\n",
+ popts->cs_odt[i].odt_rd_cfg);
+ popts->cs_odt[i].odt_wr_cfg = pdodt[i].odt_wr_cfg;
+ debug(" odt_wr_cfg 0x%x\n",
+ popts->cs_odt[i].odt_wr_cfg);
+ popts->cs_odt[i].odt_rtt_norm = pdodt[i].odt_rtt_norm;
+ debug(" odt_rtt_norm 0x%x\n",
+ popts->cs_odt[i].odt_rtt_norm);
+ popts->cs_odt[i].odt_rtt_wr = pdodt[i].odt_rtt_wr;
+ debug(" odt_rtt_wr 0x%x\n",
+ popts->cs_odt[i].odt_rtt_wr);
+ popts->cs_odt[i].auto_precharge = 0;
+ debug(" auto_precharge %d\n",
+ popts->cs_odt[i].auto_precharge);
+ }
+
+ return 0;
+}
+
+static int cal_opts(const unsigned int clk,
+ struct memctl_opt *popts,
+ struct ddr_conf *conf,
+ struct dimm_params *pdimm,
+ const int dimm_slot_per_ctrl,
+ const unsigned int ip_rev)
+{
+ popts->rdimm = pdimm->rdimm;
+ popts->mirrored_dimm = pdimm->mirrored_dimm;
+#ifdef CONFIG_DDR_ECC_EN
+ popts->ecc_mode = pdimm->edc_config == 0x02 ? 1 : 0;
+#endif
+ popts->ctlr_init_ecc = popts->ecc_mode;
+ debug("ctlr_init_ecc %d\n", popts->ctlr_init_ecc);
+ popts->self_refresh_in_sleep = 1;
+ popts->dynamic_power = 0;
+
+ /*
+ * check sdram width, allow platform override
+ * 0 = 64-bit, 1 = 32-bit, 2 = 16-bit
+ */
+ if (pdimm->primary_sdram_width == 64) {
+ popts->data_bus_dimm = DDR_DBUS_64;
+ popts->otf_burst_chop_en = 1;
+ } else if (pdimm->primary_sdram_width == 32) {
+ popts->data_bus_dimm = DDR_DBUS_32;
+ popts->otf_burst_chop_en = 0;
+ } else if (pdimm->primary_sdram_width == 16) {
+ popts->data_bus_dimm = DDR_DBUS_16;
+ popts->otf_burst_chop_en = 0;
+ } else {
+ ERROR("primary sdram width invalid!\n");
+ return -EINVAL;
+ }
+ popts->data_bus_used = popts->data_bus_dimm;
+ popts->x4_en = (pdimm->device_width == 4) ? 1 : 0;
+ debug("x4_en %d\n", popts->x4_en);
+
+ /* for RDIMM and DDR4 UDIMM/discrete memory, address parity enable */
+ if (popts->rdimm != 0) {
+ popts->ap_en = 1; /* 0 = disable, 1 = enable */
+ } else {
+ popts->ap_en = 0; /* disabled for DDR4 UDIMM/discrete default */
+ }
+
+ if (ip_rev == 0x50500) {
+ popts->ap_en = 0;
+ }
+
+ debug("ap_en %d\n", popts->ap_en);
+
+ /* BSTTOPRE precharge interval uses 1/4 of refint value. */
+ popts->bstopre = picos_to_mclk(clk, pdimm->refresh_rate_ps) >> 2;
+ popts->tfaw_ps = pdimm->tfaw_ps;
+
+ return 0;
+}
+
+static void cal_intlv(const int num_ctlrs,
+ struct memctl_opt *popts,
+ struct ddr_conf *conf,
+ struct dimm_params *pdimm)
+{
+#ifdef NXP_DDR_INTLV_256B
+ if (num_ctlrs == 2) {
+ popts->ctlr_intlv = 1;
+ popts->ctlr_intlv_mode = DDR_256B_INTLV;
+ }
+#endif
+ debug("ctlr_intlv %d\n", popts->ctlr_intlv);
+ debug("ctlr_intlv_mode %d\n", popts->ctlr_intlv_mode);
+
+ popts->ba_intlv = auto_bank_intlv(conf->cs_in_use, pdimm);
+ debug("ba_intlv 0x%x\n", popts->ba_intlv);
+}
+
+static int update_burst_length(struct memctl_opt *popts)
+{
+ /* Choose burst length. */
+ if ((popts->data_bus_used == DDR_DBUS_32) ||
+ (popts->data_bus_used == DDR_DBUS_16)) {
+ /* 32-bit or 16-bit bus */
+ popts->otf_burst_chop_en = 0;
+ popts->burst_length = DDR_BL8;
+ } else if (popts->otf_burst_chop_en != 0) { /* on-the-fly burst chop */
+ popts->burst_length = DDR_OTF; /* on-the-fly BC4 and BL8 */
+ } else {
+ popts->burst_length = DDR_BL8;
+ }
+ debug("data_bus_used %d\n", popts->data_bus_used);
+ debug("otf_burst_chop_en %d\n", popts->otf_burst_chop_en);
+ debug("burst_length 0x%x\n", popts->burst_length);
+ /*
+ * If a reduced data width is requested, but the SPD
+ * specifies a physically wider device, adjust the
+ * computed dimm capacities accordingly before
+ * assigning addresses.
+ * 0 = 64-bit, 1 = 32-bit, 2 = 16-bit
+ */
+ if (popts->data_bus_dimm > popts->data_bus_used) {
+ ERROR("Data bus configuration error\n");
+ return -EINVAL;
+ }
+ popts->dbw_cap_shift = popts->data_bus_used - popts->data_bus_dimm;
+ debug("dbw_cap_shift %d\n", popts->dbw_cap_shift);
+
+ return 0;
+}
+
+int cal_board_params(struct ddr_info *priv,
+ const struct board_timing *dimm,
+ int len)
+{
+ const unsigned long speed = priv->clk / 1000000;
+ const struct dimm_params *pdimm = &priv->dimm;
+ struct memctl_opt *popts = &priv->opt;
+ struct rc_timing const *prt = NULL;
+ struct rc_timing const *chosen = NULL;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (pdimm->rc == dimm[i].rc) {
+ prt = dimm[i].p;
+ break;
+ }
+ }
+ if (prt == NULL) {
+ ERROR("Board parameters no match.\n");
+ return -EINVAL;
+ }
+ while (prt->speed_bin != 0) {
+ if (speed <= prt->speed_bin) {
+ chosen = prt;
+ break;
+ }
+ prt++;
+ }
+ if (chosen == NULL) {
+ ERROR("timing no match for speed %lu\n", speed);
+ return -EINVAL;
+ }
+ popts->clk_adj = prt->clk_adj;
+ popts->wrlvl_start = prt->wrlvl;
+ popts->wrlvl_ctl_2 = (prt->wrlvl * 0x01010101 + dimm[i].add1) &
+ 0xFFFFFFFF;
+ popts->wrlvl_ctl_3 = (prt->wrlvl * 0x01010101 + dimm[i].add2) &
+ 0xFFFFFFFF;
+
+ return 0;
+}
+
+static int synthesize_ctlr(struct ddr_info *priv)
+{
+ int ret;
+
+ ret = cal_odt(priv->clk,
+ &priv->opt,
+ &priv->conf,
+ &priv->dimm,
+ priv->dimm_on_ctlr);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = cal_opts(priv->clk,
+ &priv->opt,
+ &priv->conf,
+ &priv->dimm,
+ priv->dimm_on_ctlr,
+ priv->ip_rev);
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ cal_intlv(priv->num_ctlrs, &priv->opt, &priv->conf, &priv->dimm);
+ ret = ddr_board_options(priv);
+ if (ret != 0) {
+ ERROR("Failed matching board timing.\n");
+ }
+
+ ret = update_burst_length(&priv->opt);
+
+ return ret;
+}
+
+/* Return the bit mask of valid DIMMs found */
+static int parse_spd(struct ddr_info *priv)
+{
+ struct ddr_conf *conf = &priv->conf;
+ struct dimm_params *dimm = &priv->dimm;
+ int j, valid_mask = 0;
+
+#ifdef CONFIG_DDR_NODIMM
+ valid_mask = ddr_get_ddr_params(dimm, conf);
+ if (valid_mask < 0) {
+ ERROR("DDR params error\n");
+ return valid_mask;
+ }
+#else
+ const int *spd_addr = priv->spd_addr;
+ const int num_ctlrs = priv->num_ctlrs;
+ const int num_dimm = priv->dimm_on_ctlr;
+ struct ddr4_spd spd[2];
+ unsigned int spd_checksum[2];
+ int addr_idx = 0;
+ int spd_idx = 0;
+ int ret, addr, i;
+
+ /* Scan all DIMMs */
+ for (i = 0; i < num_ctlrs; i++) {
+ debug("Controller %d\n", i);
+ for (j = 0; j < num_dimm; j++, addr_idx++) {
+ debug("DIMM %d\n", j);
+ addr = spd_addr[addr_idx];
+ if (addr == 0) {
+ if (j == 0) {
+ ERROR("First SPD addr wrong.\n");
+ return -EINVAL;
+ }
+ continue;
+ }
+ debug("addr 0x%x\n", addr);
+ ret = read_spd(addr, &spd[spd_idx],
+ sizeof(struct ddr4_spd));
+ if (ret != 0) { /* invalid */
+ debug("Invalid SPD at address 0x%x\n", addr);
+ continue;
+ }
+
+ spd_checksum[spd_idx] =
+ (spd[spd_idx].crc[1] << 24) |
+ (spd[spd_idx].crc[0] << 16) |
+ (spd[spd_idx].mod_section.uc[127] << 8) |
+ (spd[spd_idx].mod_section.uc[126] << 0);
+ debug("checksum 0x%x\n", spd_checksum[spd_idx]);
+ if (spd_checksum[spd_idx] == 0) {
+ debug("Bad checksum, ignored.\n");
+ continue;
+ }
+ if (spd_idx == 0) {
+ /* first valid SPD */
+ ret = cal_dimm_params(&spd[0], dimm);
+ if (ret != 0) {
+ ERROR("SPD calculation error\n");
+ return -EINVAL;
+ }
+ }
+
+ if (spd_idx != 0 && spd_checksum[0] !=
+ spd_checksum[spd_idx]) {
+ ERROR("Not identical DIMMs.\n");
+ return -EINVAL;
+ }
+ conf->dimm_in_use[j] = 1;
+ valid_mask |= 1 << addr_idx;
+ spd_idx = 1;
+ }
+ debug("done with controller %d\n", i);
+ }
+ switch (num_ctlrs) {
+ case 1:
+ if ((valid_mask & 0x1) == 0) {
+ ERROR("First slot cannot be empty.\n");
+ return -EINVAL;
+ }
+ break;
+ case 2:
+ switch (num_dimm) {
+ case 1:
+ if (valid_mask == 0) {
+ ERROR("Both slot empty\n");
+ return -EINVAL;
+ }
+ break;
+ case 2:
+ if (valid_mask != 0x5 &&
+ valid_mask != 0xf &&
+ (valid_mask & 0x7) != 0x4 &&
+ (valid_mask & 0xd) != 0x1) {
+ ERROR("Invalid DIMM combination.\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ ERROR("Invalid number of DIMMs.\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ ERROR("Invalid number of controllers.\n");
+ return -EINVAL;
+ }
+ /* now we have valid and identical DIMMs on controllers */
+#endif /* CONFIG_DDR_NODIMM */
+
+ debug("cal cs\n");
+ conf->cs_in_use = 0;
+ for (j = 0; j < DDRC_NUM_DIMM; j++) {
+ if (conf->dimm_in_use[j] == 0) {
+ continue;
+ }
+ switch (dimm->n_ranks) {
+ case 4:
+ ERROR("Quad-rank DIMM not supported\n");
+ return -EINVAL;
+ case 2:
+ conf->cs_on_dimm[j] = 0x3 << (j * CONFIG_CS_PER_SLOT);
+ conf->cs_in_use |= conf->cs_on_dimm[j];
+ break;
+ case 1:
+ conf->cs_on_dimm[j] = 0x1 << (j * CONFIG_CS_PER_SLOT);
+ conf->cs_in_use |= conf->cs_on_dimm[j];
+ break;
+ default:
+ ERROR("SPD error with n_ranks\n");
+ return -EINVAL;
+ }
+ debug("cs_in_use = %x\n", conf->cs_in_use);
+ debug("cs_on_dimm[%d] = %x\n", j, conf->cs_on_dimm[j]);
+ }
+#ifndef CONFIG_DDR_NODIMM
+ if (priv->dimm.rdimm != 0) {
+ NOTICE("RDIMM %s\n", priv->dimm.mpart);
+ } else {
+ NOTICE("UDIMM %s\n", priv->dimm.mpart);
+ }
+#else
+ NOTICE("%s\n", priv->dimm.mpart);
+#endif
+
+ return valid_mask;
+}
+
+static unsigned long long assign_intlv_addr(
+ const struct dimm_params *pdimm,
+ const struct memctl_opt *opt,
+ struct ddr_conf *conf,
+ const unsigned long long current_mem_base)
+{
+ int i;
+ int ctlr_density_mul = 0;
+ const unsigned long long rank_density = pdimm->rank_density >>
+ opt->dbw_cap_shift;
+ unsigned long long total_ctlr_mem;
+
+ debug("rank density 0x%llx\n", rank_density);
+ switch (opt->ba_intlv & DDR_BA_INTLV_CS0123) {
+ case DDR_BA_INTLV_CS0123:
+ ctlr_density_mul = 4;
+ break;
+ case DDR_BA_INTLV_CS01:
+ ctlr_density_mul = 2;
+ break;
+ default:
+ ctlr_density_mul = 1;
+ break;
+ }
+ debug("ctlr density mul %d\n", ctlr_density_mul);
+ switch (opt->ctlr_intlv_mode) {
+ case DDR_256B_INTLV:
+ total_ctlr_mem = 2 * ctlr_density_mul * rank_density;
+ break;
+ default:
+ ERROR("Unknown interleaving mode");
+ return 0;
+ }
+ conf->base_addr = current_mem_base;
+ conf->total_mem = total_ctlr_mem;
+
+ /* overwrite cs_in_use bitmask with controller interleaving */
+ conf->cs_in_use = (1 << ctlr_density_mul) - 1;
+ debug("Overwrite cs_in_use as %x\n", conf->cs_in_use);
+
+ /* Fill addr with each cs in use */
+ for (i = 0; i < ctlr_density_mul; i++) {
+ conf->cs_base_addr[i] = current_mem_base;
+ conf->cs_size[i] = total_ctlr_mem;
+ debug("CS %d\n", i);
+ debug(" base_addr 0x%llx\n", conf->cs_base_addr[i]);
+ debug(" size 0x%llx\n", conf->cs_size[i]);
+ }
+
+ return total_ctlr_mem;
+}
+
+static unsigned long long assign_non_intlv_addr(
+ const struct dimm_params *pdimm,
+ const struct memctl_opt *opt,
+ struct ddr_conf *conf,
+ unsigned long long current_mem_base)
+{
+ int i;
+ const unsigned long long rank_density = pdimm->rank_density >>
+ opt->dbw_cap_shift;
+ unsigned long long total_ctlr_mem = 0ULL;
+
+ debug("rank density 0x%llx\n", rank_density);
+ conf->base_addr = current_mem_base;
+
+ /* assign each cs */
+ switch (opt->ba_intlv & DDR_BA_INTLV_CS0123) {
+ case DDR_BA_INTLV_CS0123:
+ for (i = 0; i < DDRC_NUM_CS; i++) {
+ conf->cs_base_addr[i] = current_mem_base;
+ conf->cs_size[i] = rank_density << 2;
+ total_ctlr_mem += rank_density;
+ }
+ break;
+ case DDR_BA_INTLV_CS01:
+ for (i = 0; ((conf->cs_in_use & (1 << i)) != 0) && i < 2; i++) {
+ conf->cs_base_addr[i] = current_mem_base;
+ conf->cs_size[i] = rank_density << 1;
+ total_ctlr_mem += rank_density;
+ }
+ current_mem_base += total_ctlr_mem;
+ for (; ((conf->cs_in_use & (1 << i)) != 0) && i < DDRC_NUM_CS;
+ i++) {
+ conf->cs_base_addr[i] = current_mem_base;
+ conf->cs_size[i] = rank_density;
+ total_ctlr_mem += rank_density;
+ current_mem_base += rank_density;
+ }
+ break;
+ case DDR_BA_NONE:
+ for (i = 0; ((conf->cs_in_use & (1 << i)) != 0) &&
+ (i < DDRC_NUM_CS); i++) {
+ conf->cs_base_addr[i] = current_mem_base;
+ conf->cs_size[i] = rank_density;
+ current_mem_base += rank_density;
+ total_ctlr_mem += rank_density;
+ }
+ break;
+ default:
+ ERROR("Unsupported bank interleaving\n");
+ return 0;
+ }
+ for (i = 0; ((conf->cs_in_use & (1 << i)) != 0) &&
+ (i < DDRC_NUM_CS); i++) {
+ debug("CS %d\n", i);
+ debug(" base_addr 0x%llx\n", conf->cs_base_addr[i]);
+ debug(" size 0x%llx\n", conf->cs_size[i]);
+ }
+
+ return total_ctlr_mem;
+}
+
+unsigned long long assign_addresses(struct ddr_info *priv)
+ __attribute__ ((weak));
+
+unsigned long long assign_addresses(struct ddr_info *priv)
+{
+ struct memctl_opt *opt = &priv->opt;
+ const struct dimm_params *dimm = &priv->dimm;
+ struct ddr_conf *conf = &priv->conf;
+ unsigned long long current_mem_base = priv->mem_base;
+ unsigned long long total_mem;
+
+ total_mem = 0ULL;
+ debug("ctlr_intlv %d\n", opt->ctlr_intlv);
+ if (opt->ctlr_intlv != 0) {
+ total_mem = assign_intlv_addr(dimm, opt, conf,
+ current_mem_base);
+ } else {
+ /*
+ * Simple linear assignment if memory controllers are not
+ * interleaved. This is only valid for SoCs with single DDRC.
+ */
+ total_mem = assign_non_intlv_addr(dimm, opt, conf,
+ current_mem_base);
+ }
+ conf->total_mem = total_mem;
+ debug("base 0x%llx\n", current_mem_base);
+ debug("Total mem by assignment is 0x%llx\n", total_mem);
+
+ return total_mem;
+}
+
+static int cal_ddrc_regs(struct ddr_info *priv)
+{
+ int ret;
+
+ ret = compute_ddrc(priv->clk,
+ &priv->opt,
+ &priv->conf,
+ &priv->ddr_reg,
+ &priv->dimm,
+ priv->ip_rev);
+ if (ret != 0) {
+ ERROR("Calculating DDR registers failed\n");
+ }
+
+ return ret;
+}
+
+#endif /* CONFIG_STATIC_DDR */
+
+static int write_ddrc_regs(struct ddr_info *priv)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < priv->num_ctlrs; i++) {
+ ret = ddrc_set_regs(priv->clk, &priv->ddr_reg, priv->ddr[i], 0);
+ if (ret != 0) {
+ ERROR("Writing DDR register(s) failed\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+long long dram_init(struct ddr_info *priv
+#if defined(NXP_HAS_CCN504) || defined(NXP_HAS_CCN508)
+ , uintptr_t nxp_ccn_hn_f0_addr
+#endif
+ )
+{
+ uint64_t time __unused;
+ long long dram_size;
+ int ret;
+ const uint64_t time_base = get_timer_val(0);
+ unsigned int ip_rev = get_ddrc_version(priv->ddr[0]);
+
+ int valid_spd_mask __unused;
+ int scratch = 0x0;
+
+ priv->ip_rev = ip_rev;
+
+#ifndef CONFIG_STATIC_DDR
+ INFO("time base %" PRIu64 " ms\n", time_base);
+ debug("Parse DIMM SPD(s)\n");
+ valid_spd_mask = parse_spd(priv);
+
+ if (valid_spd_mask < 0) {
+ ERROR("Parsing DIMM Error\n");
+ return valid_spd_mask;
+ }
+
+#if defined(NXP_HAS_CCN504) || defined(NXP_HAS_CCN508)
+ if (priv->num_ctlrs == 2 || priv->num_ctlrs == 1) {
+ ret = disable_unused_ddrc(priv, valid_spd_mask,
+ nxp_ccn_hn_f0_addr);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+#endif
+
+ time = get_timer_val(time_base);
+ INFO("Time after parsing SPD %" PRIu64 " ms\n", time);
+ debug("Synthesize configurations\n");
+ ret = synthesize_ctlr(priv);
+ if (ret != 0) {
+ ERROR("Synthesize config error\n");
+ return ret;
+ }
+
+ debug("Assign binding addresses\n");
+ dram_size = assign_addresses(priv);
+ if (dram_size == 0) {
+ ERROR("Assigning address error\n");
+ return -EINVAL;
+ }
+
+ debug("Calculate controller registers\n");
+ ret = cal_ddrc_regs(priv);
+ if (ret != 0) {
+ ERROR("Calculate register error\n");
+ return ret;
+ }
+
+ ret = compute_ddr_phy(priv);
+ if (ret != 0)
+ ERROR("Calculating DDR PHY registers failed.\n");
+
+#else
+ dram_size = board_static_ddr(priv);
+ if (dram_size == 0) {
+ ERROR("Error getting static DDR settings.\n");
+ return -EINVAL;
+ }
+#endif
+
+ if (priv->warm_boot_flag == DDR_WARM_BOOT) {
+ scratch = (priv->ddr_reg).sdram_cfg[1];
+ scratch = scratch & ~(SDRAM_CFG2_D_INIT);
+ priv->ddr_reg.sdram_cfg[1] = scratch;
+ }
+
+ time = get_timer_val(time_base);
+ INFO("Time before programming controller %" PRIu64 " ms\n", time);
+ debug("Program controller registers\n");
+ ret = write_ddrc_regs(priv);
+ if (ret != 0) {
+ ERROR("Programing DDRC error\n");
+ return ret;
+ }
+
+ puts("");
+ NOTICE("%lld GB ", dram_size >> 30);
+ print_ddr_info(priv->ddr[0]);
+
+ time = get_timer_val(time_base);
+ INFO("Time used by DDR driver %" PRIu64 " ms\n", time);
+
+ return dram_size;
+}
diff --git a/drivers/nxp/ddr/nxp-ddr/ddr.mk b/drivers/nxp/ddr/nxp-ddr/ddr.mk
new file mode 100644
index 0000000..f827a1b
--- /dev/null
+++ b/drivers/nxp/ddr/nxp-ddr/ddr.mk
@@ -0,0 +1,80 @@
+#
+# Copyright 2021-2022 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq ($(PLAT_DDR_PHY), PHY_GEN2)
+$(eval $(call add_define, PHY_GEN2))
+PLAT_DDR_PHY_DIR := phy-gen2
+ifeq (${APPLY_MAX_CDD},yes)
+$(eval $(call add_define,NXP_APPLY_MAX_CDD))
+endif
+
+ifeq (${ERRATA_DDR_A011396}, 1)
+$(eval $(call add_define,ERRATA_DDR_A011396))
+endif
+
+ifeq (${ERRATA_DDR_A050450}, 1)
+$(eval $(call add_define,ERRATA_DDR_A050450))
+endif
+
+ifeq (${ERRATA_DDR_A050958}, 1)
+$(eval $(call add_define,ERRATA_DDR_A050958))
+endif
+
+endif
+
+ifeq ($(PLAT_DDR_PHY), PHY_GEN1)
+PLAT_DDR_PHY_DIR := phy-gen1
+
+ifeq (${ERRATA_DDR_A008511},1)
+$(eval $(call add_define,ERRATA_DDR_A008511))
+endif
+
+ifeq (${ERRATA_DDR_A009803},1)
+$(eval $(call add_define,ERRATA_DDR_A009803))
+endif
+
+ifeq (${ERRATA_DDR_A009942},1)
+$(eval $(call add_define,ERRATA_DDR_A009942))
+endif
+
+ifeq (${ERRATA_DDR_A010165},1)
+$(eval $(call add_define,ERRATA_DDR_A010165))
+endif
+
+endif
+
+ifeq ($(DDR_BIST), yes)
+$(eval $(call add_define, BIST_EN))
+endif
+
+ifeq ($(DDR_DEBUG), yes)
+$(eval $(call add_define, DDR_DEBUG))
+endif
+
+ifeq ($(DDR_PHY_DEBUG), yes)
+$(eval $(call add_define, DDR_PHY_DEBUG))
+endif
+
+ifeq ($(DEBUG_PHY_IO), yes)
+$(eval $(call add_define, DEBUG_PHY_IO))
+endif
+
+ifeq ($(DEBUG_WARM_RESET), yes)
+$(eval $(call add_define, DEBUG_WARM_RESET))
+endif
+
+ifeq ($(DEBUG_DDR_INPUT_CONFIG), yes)
+$(eval $(call add_define, DEBUG_DDR_INPUT_CONFIG))
+endif
+
+DDR_CNTLR_SOURCES := $(PLAT_DRIVERS_PATH)/ddr/nxp-ddr/ddr.c \
+ $(PLAT_DRIVERS_PATH)/ddr/nxp-ddr/ddrc.c \
+ $(PLAT_DRIVERS_PATH)/ddr/nxp-ddr/dimm.c \
+ $(PLAT_DRIVERS_PATH)/ddr/nxp-ddr/regs.c \
+ $(PLAT_DRIVERS_PATH)/ddr/nxp-ddr/utility.c \
+ $(PLAT_DRIVERS_PATH)/ddr/$(PLAT_DDR_PHY_DIR)/phy.c
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/ddr
diff --git a/drivers/nxp/ddr/nxp-ddr/ddrc.c b/drivers/nxp/ddr/nxp-ddr/ddrc.c
new file mode 100644
index 0000000..17a2b6a
--- /dev/null
+++ b/drivers/nxp/ddr/nxp-ddr/ddrc.c
@@ -0,0 +1,594 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <common/debug.h>
+#include <ddr.h>
+#include <drivers/delay_timer.h>
+#include <immap.h>
+
+#define BIST_CR 0x80060000
+#define BIST_CR_EN 0x80000000
+#define BIST_CR_STAT 0x00000001
+#define CTLR_INTLV_MASK 0x20000000
+
+#pragma weak run_bist
+
+bool run_bist(void)
+{
+#ifdef BIST_EN
+ return true;
+#else
+ return false;
+#endif
+}
+
+/*
+ * Perform build-in test on memory
+ * timeout value in 10ms
+ */
+int bist(const struct ccsr_ddr *ddr, int timeout)
+{
+ const unsigned int test_pattern[10] = {
+ 0xffffffff,
+ 0x00000000,
+ 0xaaaaaaaa,
+ 0x55555555,
+ 0xcccccccc,
+ 0x33333333,
+ 0x12345678,
+ 0xabcdef01,
+ 0xaa55aa55,
+ 0x55aa55aa
+ };
+ unsigned int mtcr, err_detect, err_sbe;
+ unsigned int cs0_config;
+ unsigned int csn_bnds[4];
+ int ret = 0;
+ uint32_t i;
+#ifdef CONFIG_DDR_ADDR_DEC
+ uint32_t dec_9 = ddr_in32(&ddr->dec[9]);
+ uint32_t pos = 0U;
+ uint32_t map_save = 0U;
+ uint32_t temp32 = 0U;
+ uint32_t map, shift, highest;
+#endif
+
+ cs0_config = ddr_in32(&ddr->csn_cfg[0]);
+ if ((cs0_config & CTLR_INTLV_MASK) != 0U) {
+ /* set bnds to non-interleaving */
+ for (i = 0U; i < 4U; i++) {
+ csn_bnds[i] = ddr_in32(&ddr->bnds[i].a);
+ ddr_out32(&ddr->bnds[i].a,
+ (csn_bnds[i] & U(0xfffefffe)) >> 1U);
+ }
+ ddr_out32(&ddr->csn_cfg[0], cs0_config & ~CTLR_INTLV_MASK);
+#ifdef CONFIG_DDR_ADDR_DEC
+ if ((dec_9 & 0x1U) != 0U) {
+ highest = (dec_9 >> 26U) == U(0x3F) ? 0U : dec_9 >> 26U;
+ pos = 37U;
+ for (i = 0U; i < 36U; i++) { /* Go through all 37 */
+ if ((i % 4U) == 0U) {
+ temp32 = ddr_in32(&ddr->dec[i >> 2U]);
+ }
+ shift = (3U - i % 4U) * 8U + 2U;
+ map = (temp32 >> shift) & U(0x3F);
+ if (map > highest && map != U(0x3F)) {
+ highest = map;
+ pos = i;
+ }
+ }
+ debug("\nFound highest position %d, mapping to %d, ",
+ pos, highest);
+ map_save = ddr_in32(&ddr->dec[pos >> 2]);
+ shift = (3U - pos % 4U) * 8U + 2U;
+ debug("in dec[%d], bit %d (0x%x)\n",
+ pos >> 2U, shift, map_save);
+ temp32 = map_save & ~(U(0x3F) << shift);
+ temp32 |= 8U << shift;
+ ddr_out32(&ddr->dec[pos >> 2U], temp32);
+ timeout <<= 2U;
+ debug("Increase wait time to %d ms\n", timeout * 10);
+ }
+#endif
+ }
+ for (i = 0U; i < 10U; i++) {
+ ddr_out32(&ddr->mtp[i], test_pattern[i]);
+ }
+ mtcr = BIST_CR;
+ ddr_out32(&ddr->mtcr, mtcr);
+ do {
+ mdelay(10);
+ mtcr = ddr_in32(&ddr->mtcr);
+ } while (timeout-- > 0 && ((mtcr & BIST_CR_EN) != 0));
+ if (timeout <= 0) {
+ ERROR("Timeout\n");
+ } else {
+ debug("Timer remains %d\n", timeout);
+ }
+
+ err_detect = ddr_in32(&ddr->err_detect);
+ err_sbe = ddr_in32(&ddr->err_sbe);
+ if (err_detect != 0U || ((err_sbe & U(0xffff)) != 0U)) {
+ ERROR("ECC error detected\n");
+ ret = -EIO;
+ }
+
+ if ((cs0_config & CTLR_INTLV_MASK) != 0) {
+ for (i = 0U; i < 4U; i++) {
+ ddr_out32(&ddr->bnds[i].a, csn_bnds[i]);
+ }
+ ddr_out32(&ddr->csn_cfg[0], cs0_config);
+#ifdef CONFIG_DDR_ADDR_DEC
+ if ((dec_9 & U(0x1)) != 0U) {
+ ddr_out32(&ddr->dec[pos >> 2], map_save);
+ }
+#endif
+ }
+ if ((mtcr & BIST_CR_STAT) != 0) {
+ ERROR("Built-in self test failed\n");
+ ret = -EIO;
+ } else {
+ NOTICE("Build-in self test passed\n");
+ }
+
+ return ret;
+}
+
+void dump_ddrc(unsigned int *ddr)
+{
+#ifdef DDR_DEBUG
+ uint32_t i;
+ unsigned long val;
+
+ for (i = 0U; i < U(0x400); i++, ddr++) {
+ val = ddr_in32(ddr);
+ if (val != 0U) { /* skip zeros */
+ debug("*0x%lx = 0x%lx\n", (unsigned long)ddr, val);
+ }
+ }
+#endif
+}
+
+#ifdef ERRATA_DDR_A009803
+static void set_wait_for_bits_clear(const void *ptr,
+ unsigned int value,
+ unsigned int bits)
+{
+ int timeout = 1000;
+
+ ddr_out32(ptr, value);
+ do {
+ udelay(100);
+ } while (timeout-- > 0 && ((ddr_in32(ptr) & bits) != 0));
+
+ if (timeout <= 0) {
+ ERROR("wait for clear timeout.\n");
+ }
+}
+#endif
+
+#if (DDRC_NUM_CS > 4)
+#error Invalid setting for DDRC_NUM_CS
+#endif
+
+/*
+ * If supported by the platform, writing to DDR controller takes two
+ * passes to deassert DDR reset to comply with JEDEC specs for RDIMMs.
+ */
+int ddrc_set_regs(const unsigned long clk,
+ const struct ddr_cfg_regs *regs,
+ const struct ccsr_ddr *ddr,
+ int twopass)
+{
+ unsigned int i, bus_width;
+ unsigned int temp_sdram_cfg;
+ unsigned int total_mem_per_ctrl, total_mem_per_ctrl_adj;
+ const int mod_bnds = regs->cs[0].config & CTLR_INTLV_MASK;
+ int timeout;
+ int ret = 0;
+#if defined(ERRATA_DDR_A009942) || defined(ERRATA_DDR_A010165)
+ unsigned long ddr_freq;
+ unsigned int tmp;
+#ifdef ERRATA_DDR_A009942
+ unsigned int check;
+ unsigned int cpo_min = U(0xff);
+ unsigned int cpo_max = 0U;
+#endif
+#endif
+
+ if (twopass == 2U) {
+ goto after_reset;
+ }
+
+ /* Set cdr1 first in case 0.9v VDD is enabled for some SoCs*/
+ ddr_out32(&ddr->ddr_cdr1, regs->cdr[0]);
+
+ ddr_out32(&ddr->sdram_clk_cntl, regs->clk_cntl);
+
+ for (i = 0U; i < DDRC_NUM_CS; i++) {
+ if (mod_bnds != 0U) {
+ ddr_out32(&ddr->bnds[i].a,
+ (regs->cs[i].bnds & U(0xfffefffe)) >> 1U);
+ } else {
+ ddr_out32(&ddr->bnds[i].a, regs->cs[i].bnds);
+ }
+ ddr_out32(&ddr->csn_cfg_2[i], regs->cs[i].config_2);
+ }
+
+ ddr_out32(&ddr->timing_cfg_0, regs->timing_cfg[0]);
+ ddr_out32(&ddr->timing_cfg_1, regs->timing_cfg[1]);
+ ddr_out32(&ddr->timing_cfg_2, regs->timing_cfg[2]);
+ ddr_out32(&ddr->timing_cfg_3, regs->timing_cfg[3]);
+ ddr_out32(&ddr->timing_cfg_4, regs->timing_cfg[4]);
+ ddr_out32(&ddr->timing_cfg_5, regs->timing_cfg[5]);
+ ddr_out32(&ddr->timing_cfg_6, regs->timing_cfg[6]);
+ ddr_out32(&ddr->timing_cfg_7, regs->timing_cfg[7]);
+ ddr_out32(&ddr->timing_cfg_8, regs->timing_cfg[8]);
+ ddr_out32(&ddr->timing_cfg_9, regs->timing_cfg[9]);
+ ddr_out32(&ddr->zq_cntl, regs->zq_cntl);
+ for (i = 0U; i < 4U; i++) {
+ ddr_out32(&ddr->dq_map[i], regs->dq_map[i]);
+ }
+ ddr_out32(&ddr->sdram_cfg_3, regs->sdram_cfg[2]);
+ ddr_out32(&ddr->sdram_mode, regs->sdram_mode[0]);
+ ddr_out32(&ddr->sdram_mode_2, regs->sdram_mode[1]);
+ ddr_out32(&ddr->sdram_mode_3, regs->sdram_mode[2]);
+ ddr_out32(&ddr->sdram_mode_4, regs->sdram_mode[3]);
+ ddr_out32(&ddr->sdram_mode_5, regs->sdram_mode[4]);
+ ddr_out32(&ddr->sdram_mode_6, regs->sdram_mode[5]);
+ ddr_out32(&ddr->sdram_mode_7, regs->sdram_mode[6]);
+ ddr_out32(&ddr->sdram_mode_8, regs->sdram_mode[7]);
+ ddr_out32(&ddr->sdram_mode_9, regs->sdram_mode[8]);
+ ddr_out32(&ddr->sdram_mode_10, regs->sdram_mode[9]);
+ ddr_out32(&ddr->sdram_mode_11, regs->sdram_mode[10]);
+ ddr_out32(&ddr->sdram_mode_12, regs->sdram_mode[11]);
+ ddr_out32(&ddr->sdram_mode_13, regs->sdram_mode[12]);
+ ddr_out32(&ddr->sdram_mode_14, regs->sdram_mode[13]);
+ ddr_out32(&ddr->sdram_mode_15, regs->sdram_mode[14]);
+ ddr_out32(&ddr->sdram_mode_16, regs->sdram_mode[15]);
+ ddr_out32(&ddr->sdram_md_cntl, regs->md_cntl);
+#ifdef ERRATA_DDR_A009663
+ ddr_out32(&ddr->sdram_interval,
+ regs->interval & ~SDRAM_INTERVAL_BSTOPRE);
+#else
+ ddr_out32(&ddr->sdram_interval, regs->interval);
+#endif
+ ddr_out32(&ddr->sdram_data_init, regs->data_init);
+ if (regs->eor != 0) {
+ ddr_out32(&ddr->eor, regs->eor);
+ }
+
+ ddr_out32(&ddr->wrlvl_cntl, regs->wrlvl_cntl[0]);
+#ifndef NXP_DDR_EMU
+ /*
+ * Skip these two registers if running on emulator
+ * because emulator doesn't have skew between bytes.
+ */
+
+ if (regs->wrlvl_cntl[1] != 0) {
+ ddr_out32(&ddr->ddr_wrlvl_cntl_2, regs->wrlvl_cntl[1]);
+ }
+ if (regs->wrlvl_cntl[2] != 0) {
+ ddr_out32(&ddr->ddr_wrlvl_cntl_3, regs->wrlvl_cntl[2]);
+ }
+#endif
+
+ ddr_out32(&ddr->ddr_sr_cntr, regs->ddr_sr_cntr);
+ ddr_out32(&ddr->ddr_sdram_rcw_1, regs->sdram_rcw[0]);
+ ddr_out32(&ddr->ddr_sdram_rcw_2, regs->sdram_rcw[1]);
+ ddr_out32(&ddr->ddr_sdram_rcw_3, regs->sdram_rcw[2]);
+ ddr_out32(&ddr->ddr_sdram_rcw_4, regs->sdram_rcw[3]);
+ ddr_out32(&ddr->ddr_sdram_rcw_5, regs->sdram_rcw[4]);
+ ddr_out32(&ddr->ddr_sdram_rcw_6, regs->sdram_rcw[5]);
+ ddr_out32(&ddr->ddr_cdr2, regs->cdr[1]);
+ ddr_out32(&ddr->sdram_cfg_2, regs->sdram_cfg[1]);
+ ddr_out32(&ddr->init_addr, regs->init_addr);
+ ddr_out32(&ddr->init_ext_addr, regs->init_ext_addr);
+
+#ifdef ERRATA_DDR_A009803
+ /* part 1 of 2 */
+ if ((regs->sdram_cfg[1] & SDRAM_CFG2_AP_EN) != 0) {
+ if ((regs->sdram_cfg[0] & SDRAM_CFG_RD_EN) != 0) {
+ ddr_out32(&ddr->ddr_sdram_rcw_2,
+ regs->sdram_rcw[1] & ~0xf0);
+ }
+
+ ddr_out32(&ddr->err_disable,
+ regs->err_disable | DDR_ERR_DISABLE_APED);
+ }
+#else
+ ddr_out32(&ddr->err_disable, regs->err_disable);
+#endif
+ ddr_out32(&ddr->err_int_en, regs->err_int_en);
+
+ /* For DDRC 5.05 only */
+ if (get_ddrc_version(ddr) == 0x50500) {
+ ddr_out32(&ddr->tx_cfg[1], 0x1f1f1f1f);
+ ddr_out32(&ddr->debug[3], 0x124a02c0);
+ }
+
+ for (i = 0U; i < 4U; i++) {
+ if (regs->tx_cfg[i] != 0) {
+ ddr_out32(&ddr->tx_cfg[i], regs->tx_cfg[i]);
+ }
+ }
+ for (i = 0U; i < 64U; i++) {
+ if (regs->debug[i] != 0) {
+#ifdef ERRATA_DDR_A009942
+ if (i == 28U) {
+ continue;
+ }
+#endif
+ ddr_out32(&ddr->debug[i], regs->debug[i]);
+ }
+ }
+#ifdef CONFIG_DDR_ADDR_DEC
+ if ((regs->dec[9] & 1) != 0U) {
+ for (i = 0U; i < 10U; i++) {
+ ddr_out32(&ddr->dec[i], regs->dec[i]);
+ }
+ if (mod_bnds != 0) {
+ debug("Disable address decoding\n");
+ ddr_out32(&ddr->dec[9], 0);
+ }
+ }
+#endif
+
+#ifdef ERRATA_DDR_A008511
+ /* Part 1 of 2 */
+ /* This erraum only applies to verion 5.2.1 */
+ if (get_ddrc_version(ddr) == 0x50200) {
+ ERROR("Unsupported SoC.\n");
+ } else if (get_ddrc_version(ddr) == 0x50201) {
+ ddr_out32(&ddr->debug[37], (U(1) << 31));
+ ddr_out32(&ddr->ddr_cdr2,
+ regs->cdr[1] | DDR_CDR2_VREF_TRAIN_EN);
+ } else {
+ debug("Erratum A008511 doesn't apply.\n");
+ }
+#endif
+
+#ifdef ERRATA_DDR_A009942
+ ddr_freq = clk / 1000000U;
+ tmp = ddr_in32(&ddr->debug[28]);
+ tmp &= U(0xff0fff00);
+ tmp |= ddr_freq <= 1333U ? U(0x0080006a) :
+ (ddr_freq <= 1600U ? U(0x0070006f) :
+ (ddr_freq <= 1867U ? U(0x00700076) : U(0x0060007b)));
+ if (regs->debug[28] != 0) {
+ tmp &= ~0xff;
+ tmp |= regs->debug[28] & 0xff;
+ } else {
+ WARN("Warning: Optimal CPO value not set.\n");
+ }
+ ddr_out32(&ddr->debug[28], tmp);
+#endif
+
+#ifdef ERRATA_DDR_A010165
+ ddr_freq = clk / 1000000U;
+ if ((ddr_freq > 1900) && (ddr_freq < 2300)) {
+ tmp = ddr_in32(&ddr->debug[28]);
+ ddr_out32(&ddr->debug[28], tmp | 0x000a0000);
+ }
+#endif
+ /*
+ * For RDIMMs, JEDEC spec requires clocks to be stable before reset is
+ * deasserted. Clocks start when any chip select is enabled and clock
+ * control register is set. Because all DDR components are connected to
+ * one reset signal, this needs to be done in two steps. Step 1 is to
+ * get the clocks started. Step 2 resumes after reset signal is
+ * deasserted.
+ */
+ if (twopass == 1) {
+ udelay(200);
+ return 0;
+ }
+
+ /* As per new sequence flow shall be write CSn_CONFIG registers needs to
+ * be set after all the other DDR controller registers are set, then poll
+ * for PHY_INIT_CMPLT = 1 , then wait at least 100us (micro seconds),
+ * then set the MEM_EN = 1
+ */
+ for (i = 0U; i < DDRC_NUM_CS; i++) {
+ if (mod_bnds != 0U && i == 0U) {
+ ddr_out32(&ddr->csn_cfg[i],
+ (regs->cs[i].config & ~CTLR_INTLV_MASK));
+ } else {
+ ddr_out32(&ddr->csn_cfg[i], regs->cs[i].config);
+ }
+ }
+
+after_reset:
+ /* Set, but do not enable the memory */
+ temp_sdram_cfg = regs->sdram_cfg[0];
+ temp_sdram_cfg &= ~(SDRAM_CFG_MEM_EN);
+ ddr_out32(&ddr->sdram_cfg, temp_sdram_cfg);
+
+ if (get_ddrc_version(ddr) < U(0x50500)) {
+ /*
+ * 500 painful micro-seconds must elapse between
+ * the DDR clock setup and the DDR config enable.
+ * DDR2 need 200 us, and DDR3 need 500 us from spec,
+ * we choose the max, that is 500 us for all of case.
+ */
+ udelay(500);
+ /* applied memory barrier */
+ mb();
+ isb();
+ } else {
+ /* wait for PHY complete */
+ timeout = 40;
+ while (((ddr_in32(&ddr->ddr_dsr2) & 0x4) != 0) &&
+ (timeout > 0)) {
+ udelay(500);
+ timeout--;
+ }
+ if (timeout <= 0) {
+ printf("PHY handshake timeout, ddr_dsr2 = %x\n",
+ ddr_in32(&ddr->ddr_dsr2));
+ } else {
+ debug("PHY handshake completed, timer remains %d\n",
+ timeout);
+ }
+ }
+
+ temp_sdram_cfg = ddr_in32(&ddr->sdram_cfg);
+ /* Let the controller go */
+ udelay(100);
+ ddr_out32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN);
+
+ /* applied memory barrier */
+ mb();
+ isb();
+
+ total_mem_per_ctrl = 0;
+ for (i = 0; i < DDRC_NUM_CS; i++) {
+ if ((regs->cs[i].config & 0x80000000) == 0) {
+ continue;
+ }
+ total_mem_per_ctrl += 1 << (
+ ((regs->cs[i].config >> 14) & 0x3) + 2 +
+ ((regs->cs[i].config >> 8) & 0x7) + 12 +
+ ((regs->cs[i].config >> 4) & 0x3) + 0 +
+ ((regs->cs[i].config >> 0) & 0x7) + 8 +
+ ((regs->sdram_cfg[2] >> 4) & 0x3) +
+ 3 - ((regs->sdram_cfg[0] >> 19) & 0x3) -
+ 26); /* minus 26 (count of 64M) */
+ }
+ total_mem_per_ctrl_adj = total_mem_per_ctrl;
+ /*
+ * total memory / bus width = transactions needed
+ * transactions needed / data rate = seconds
+ * to add plenty of buffer, double the time
+ * For example, 2GB on 666MT/s 64-bit bus takes about 402ms
+ * Let's wait for 800ms
+ */
+ bus_width = 3 - ((ddr_in32(&ddr->sdram_cfg) & SDRAM_CFG_DBW_MASK)
+ >> SDRAM_CFG_DBW_SHIFT);
+ timeout = ((total_mem_per_ctrl_adj << (6 - bus_width)) * 100 /
+ (clk >> 20)) << 2;
+ total_mem_per_ctrl_adj >>= 4; /* shift down to gb size */
+ if ((ddr_in32(&ddr->sdram_cfg_2) & SDRAM_CFG2_D_INIT) != 0) {
+ debug("total size %d GB\n", total_mem_per_ctrl_adj);
+ debug("Need to wait up to %d ms\n", timeout * 10);
+
+ do {
+ mdelay(10);
+ } while (timeout-- > 0 &&
+ ((ddr_in32(&ddr->sdram_cfg_2) & SDRAM_CFG2_D_INIT)) != 0);
+
+ if (timeout <= 0) {
+ if (ddr_in32(&ddr->debug[1]) & 0x3d00) {
+ ERROR("Found training error(s): 0x%x\n",
+ ddr_in32(&ddr->debug[1]));
+ }
+ ERROR("Error: Waiting for D_INIT timeout.\n");
+ return -EIO;
+ }
+ }
+
+ if (mod_bnds != 0U) {
+ debug("Restore original bnds\n");
+ for (i = 0U; i < DDRC_NUM_CS; i++) {
+ ddr_out32(&ddr->bnds[i].a, regs->cs[i].bnds);
+ }
+ ddr_out32(&ddr->csn_cfg[0], regs->cs[0].config);
+#ifdef CONFIG_DDR_ADDR_DEC
+ if ((regs->dec[9] & U(0x1)) != 0U) {
+ debug("Restore address decoding\n");
+ ddr_out32(&ddr->dec[9], regs->dec[9]);
+ }
+#endif
+ }
+
+#ifdef ERRATA_DDR_A009803
+ /* Part 2 of 2 */
+ if ((regs->sdram_cfg[1] & SDRAM_CFG2_AP_EN) != 0) {
+ timeout = 400;
+ do {
+ mdelay(1);
+ } while (timeout-- > 0 && ((ddr_in32(&ddr->debug[1]) & 0x2) == 0));
+
+ if ((regs->sdram_cfg[0] & SDRAM_CFG_RD_EN) != 0) {
+ for (i = 0U; i < DDRC_NUM_CS; i++) {
+ if ((regs->cs[i].config & SDRAM_CS_CONFIG_EN) == 0) {
+ continue;
+ }
+ set_wait_for_bits_clear(&ddr->sdram_md_cntl,
+ MD_CNTL_MD_EN |
+ MD_CNTL_CS_SEL(i) |
+ 0x070000ed,
+ MD_CNTL_MD_EN);
+ udelay(1);
+ }
+ }
+
+ ddr_out32(&ddr->err_disable,
+ regs->err_disable & ~DDR_ERR_DISABLE_APED);
+ }
+#endif
+
+#ifdef ERRATA_DDR_A009663
+ ddr_out32(&ddr->sdram_interval, regs->interval);
+#endif
+
+#ifdef ERRATA_DDR_A009942
+ timeout = 400;
+ do {
+ mdelay(1);
+ } while (timeout-- > 0 && ((ddr_in32(&ddr->debug[1]) & 0x2) == 0));
+ tmp = (regs->sdram_cfg[0] >> 19) & 0x3;
+ check = (tmp == DDR_DBUS_64) ? 4 : ((tmp == DDR_DBUS_32) ? 2 : 1);
+ for (i = 0; i < check; i++) {
+ tmp = ddr_in32(&ddr->debug[9 + i]);
+ debug("Reading debug[%d] as 0x%x\n", i + 9, tmp);
+ cpo_min = min(cpo_min,
+ min((tmp >> 24) & 0xff, (tmp >> 8) & 0xff));
+ cpo_max = max(cpo_max,
+ max((tmp >> 24) & 0xff, (tmp >> 8) & 0xff));
+ }
+ if ((regs->sdram_cfg[0] & SDRAM_CFG_ECC_EN) != 0) {
+ tmp = ddr_in32(&ddr->debug[13]);
+ cpo_min = min(cpo_min, (tmp >> 24) & 0xff);
+ cpo_max = max(cpo_max, (tmp >> 24) & 0xff);
+ }
+ debug("cpo_min 0x%x\n", cpo_min);
+ debug("cpo_max 0x%x\n", cpo_max);
+ tmp = ddr_in32(&ddr->debug[28]);
+ debug("debug[28] 0x%x\n", tmp);
+ if ((cpo_min + 0x3B) < (tmp & 0xff)) {
+ WARN("Warning: A009942 requires setting cpo_sample to 0x%x\n",
+ (cpo_min + cpo_max) / 2 + 0x27);
+ } else {
+ debug("Optimal cpo_sample 0x%x\n",
+ (cpo_min + cpo_max) / 2 + 0x27);
+ }
+#endif
+ if (run_bist() != 0) {
+ if ((ddr_in32(&ddr->debug[1]) &
+ ((get_ddrc_version(ddr) == 0x50500) ? 0x3c00 : 0x3d00)) != 0) {
+ ERROR("Found training error(s): 0x%x\n",
+ ddr_in32(&ddr->debug[1]));
+ return -EIO;
+ }
+ INFO("Running built-in self test ...\n");
+ /* give it 10x time to cover whole memory */
+ timeout = ((total_mem_per_ctrl << (6 - bus_width)) *
+ 100 / (clk >> 20)) * 10;
+ INFO("\tWait up to %d ms\n", timeout * 10);
+ ret = bist(ddr, timeout);
+ }
+ dump_ddrc((void *)ddr);
+
+ return ret;
+}
diff --git a/drivers/nxp/ddr/nxp-ddr/dimm.c b/drivers/nxp/ddr/nxp-ddr/dimm.c
new file mode 100644
index 0000000..a82db6c
--- /dev/null
+++ b/drivers/nxp/ddr/nxp-ddr/dimm.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright 2021-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include <common/debug.h>
+#include <ddr.h>
+#include <dimm.h>
+#include <i2c.h>
+#include <lib/utils.h>
+
+int read_spd(unsigned char chip, void *buf, int len)
+{
+ unsigned char dummy = 0U;
+ int ret;
+
+ if (len < 256) {
+ ERROR("Invalid SPD length\n");
+ return -EINVAL;
+ }
+
+ i2c_write(SPD_SPA0_ADDRESS, 0, 1, &dummy, 1);
+ ret = i2c_read(chip, 0, 1, buf, 256);
+ if (ret == 0) {
+ i2c_write(SPD_SPA1_ADDRESS, 0, 1, &dummy, 1);
+ ret = i2c_read(chip, 0, 1, buf + 256, min(256, len - 256));
+ }
+ if (ret != 0) {
+ zeromem(buf, len);
+ }
+
+ return ret;
+}
+
+int crc16(unsigned char *ptr, int count)
+{
+ int i;
+ int crc = 0;
+
+ while (--count >= 0) {
+ crc = crc ^ (int)*ptr++ << 8;
+ for (i = 0; i < 8; ++i) {
+ if ((crc & 0x8000) != 0) {
+ crc = crc << 1 ^ 0x1021;
+ } else {
+ crc = crc << 1;
+ }
+ }
+ }
+ return crc & 0xffff;
+}
+
+static int ddr4_spd_check(const struct ddr4_spd *spd)
+{
+ void *p = (void *)spd;
+ int csum16;
+ int len;
+ char crc_lsb; /* byte 126 */
+ char crc_msb; /* byte 127 */
+
+ len = 126;
+ csum16 = crc16(p, len);
+
+ crc_lsb = (char) (csum16 & 0xff);
+ crc_msb = (char) (csum16 >> 8);
+
+ if (spd->crc[0] != crc_lsb || spd->crc[1] != crc_msb) {
+ ERROR("SPD CRC = 0x%x%x, computed CRC = 0x%x%x\n",
+ spd->crc[1], spd->crc[0], crc_msb, crc_lsb);
+ return -EINVAL;
+ }
+
+ p = (void *)spd + 128;
+ len = 126;
+ csum16 = crc16(p, len);
+
+ crc_lsb = (char) (csum16 & 0xff);
+ crc_msb = (char) (csum16 >> 8);
+
+ if (spd->mod_section.uc[126] != crc_lsb ||
+ spd->mod_section.uc[127] != crc_msb) {
+ ERROR("SPD CRC = 0x%x%x, computed CRC = 0x%x%x\n",
+ spd->mod_section.uc[127], spd->mod_section.uc[126],
+ crc_msb, crc_lsb);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static unsigned long long
+compute_ranksize(const struct ddr4_spd *spd)
+{
+ unsigned long long bsize;
+
+ int nbit_sdram_cap_bsize = 0;
+ int nbit_primary_bus_width = 0;
+ int nbit_sdram_width = 0;
+ int die_count = 0;
+ bool package_3ds;
+
+ if ((spd->density_banks & 0xf) <= 7) {
+ nbit_sdram_cap_bsize = (spd->density_banks & 0xf) + 28;
+ }
+ if ((spd->bus_width & 0x7) < 4) {
+ nbit_primary_bus_width = (spd->bus_width & 0x7) + 3;
+ }
+ if ((spd->organization & 0x7) < 4) {
+ nbit_sdram_width = (spd->organization & 0x7) + 2;
+ }
+ package_3ds = (spd->package_type & 0x3) == 0x2;
+ if (package_3ds) {
+ die_count = (spd->package_type >> 4) & 0x7;
+ }
+
+ bsize = 1ULL << (nbit_sdram_cap_bsize - 3 +
+ nbit_primary_bus_width - nbit_sdram_width +
+ die_count);
+
+ return bsize;
+}
+
+int cal_dimm_params(const struct ddr4_spd *spd, struct dimm_params *pdimm)
+{
+ int ret;
+ int i;
+ static const unsigned char udimm_rc_e_dq[18] = {
+ 0x0c, 0x2c, 0x15, 0x35, 0x15, 0x35, 0x0b, 0x2c, 0x15,
+ 0x35, 0x0b, 0x35, 0x0b, 0x2c, 0x0b, 0x35, 0x15, 0x36
+ };
+ int spd_error = 0;
+ unsigned char *ptr;
+ unsigned char val;
+
+ if (spd->mem_type != SPD_MEMTYPE_DDR4) {
+ ERROR("Not a DDR4 DIMM.\n");
+ return -EINVAL;
+ }
+
+ ret = ddr4_spd_check(spd);
+ if (ret != 0) {
+ ERROR("DIMM SPD checksum mismatch\n");
+ return -EINVAL;
+ }
+
+ /*
+ * The part name in ASCII in the SPD EEPROM is not null terminated.
+ * Guarantee null termination here by presetting all bytes to 0
+ * and copying the part name in ASCII from the SPD onto it
+ */
+ if ((spd->info_size_crc & 0xF) > 2) {
+ memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1);
+ }
+
+ /* DIMM organization parameters */
+ pdimm->n_ranks = ((spd->organization >> 3) & 0x7) + 1;
+ debug("n_ranks %d\n", pdimm->n_ranks);
+ pdimm->rank_density = compute_ranksize(spd);
+ if (pdimm->rank_density == 0) {
+ return -EINVAL;
+ }
+
+ debug("rank_density 0x%llx\n", pdimm->rank_density);
+ pdimm->capacity = pdimm->n_ranks * pdimm->rank_density;
+ debug("capacity 0x%llx\n", pdimm->capacity);
+ pdimm->die_density = spd->density_banks & 0xf;
+ debug("die density 0x%x\n", pdimm->die_density);
+ pdimm->primary_sdram_width = 1 << (3 + (spd->bus_width & 0x7));
+ debug("primary_sdram_width %d\n", pdimm->primary_sdram_width);
+ if (((spd->bus_width >> 3) & 0x3) != 0) {
+ pdimm->ec_sdram_width = 8;
+ } else {
+ pdimm->ec_sdram_width = 0;
+ }
+ debug("ec_sdram_width %d\n", pdimm->ec_sdram_width);
+ pdimm->device_width = 1 << ((spd->organization & 0x7) + 2);
+ debug("device_width %d\n", pdimm->device_width);
+ pdimm->package_3ds = (spd->package_type & 0x3) == 0x2 ?
+ (spd->package_type >> 4) & 0x7 : 0;
+ debug("package_3ds %d\n", pdimm->package_3ds);
+
+ switch (spd->module_type & DDR4_SPD_MODULETYPE_MASK) {
+ case DDR4_SPD_RDIMM:
+ case DDR4_SPD_MINI_RDIMM:
+ case DDR4_SPD_72B_SO_RDIMM:
+ pdimm->rdimm = 1;
+ pdimm->rc = spd->mod_section.registered.ref_raw_card & 0x9f;
+ if ((spd->mod_section.registered.reg_map & 0x1) != 0) {
+ pdimm->mirrored_dimm = 1;
+ }
+ val = spd->mod_section.registered.ca_stren;
+ pdimm->rcw[3] = val >> 4;
+ pdimm->rcw[4] = ((val & 0x3) << 2) | ((val & 0xc) >> 2);
+ val = spd->mod_section.registered.clk_stren;
+ pdimm->rcw[5] = ((val & 0x3) << 2) | ((val & 0xc) >> 2);
+ pdimm->rcw[6] = 0xf;
+ /* A17 used for 16Gb+, C[2:0] used for 3DS */
+ pdimm->rcw[8] = pdimm->die_density >= 0x6 ? 0x0 : 0x8 |
+ (pdimm->package_3ds > 0x3 ? 0x0 :
+ (pdimm->package_3ds > 0x1 ? 0x1 :
+ (pdimm->package_3ds > 0 ? 0x2 : 0x3)));
+ if (pdimm->package_3ds != 0 || pdimm->n_ranks != 4) {
+ pdimm->rcw[13] = 0x4;
+ } else {
+ pdimm->rcw[13] = 0x5;
+ }
+ pdimm->rcw[13] |= pdimm->mirrored_dimm ? 0x8 : 0;
+ break;
+
+ case DDR4_SPD_UDIMM:
+ case DDR4_SPD_SO_DIMM:
+ case DDR4_SPD_MINI_UDIMM:
+ case DDR4_SPD_72B_SO_UDIMM:
+ case DDR4_SPD_16B_SO_DIMM:
+ case DDR4_SPD_32B_SO_DIMM:
+ pdimm->rc = spd->mod_section.unbuffered.ref_raw_card & 0x9f;
+ if ((spd->mod_section.unbuffered.addr_mapping & 0x1) != 0) {
+ pdimm->mirrored_dimm = 1;
+ }
+ if ((spd->mod_section.unbuffered.mod_height & 0xe0) == 0 &&
+ (spd->mod_section.unbuffered.ref_raw_card == 0x04)) {
+ /* Fix SPD error found on DIMMs with raw card E0 */
+ for (i = 0; i < 18; i++) {
+ if (spd->mapping[i] == udimm_rc_e_dq[i]) {
+ continue;
+ }
+ spd_error = 1;
+ ptr = (unsigned char *)&spd->mapping[i];
+ *ptr = udimm_rc_e_dq[i];
+ }
+ if (spd_error != 0) {
+ INFO("SPD DQ mapping error fixed\n");
+ }
+ }
+ break;
+
+ default:
+ ERROR("Unknown module_type 0x%x\n", spd->module_type);
+ return -EINVAL;
+ }
+ debug("rdimm %d\n", pdimm->rdimm);
+ debug("mirrored_dimm %d\n", pdimm->mirrored_dimm);
+ debug("rc 0x%x\n", pdimm->rc);
+
+ /* SDRAM device parameters */
+ pdimm->n_row_addr = ((spd->addressing >> 3) & 0x7) + 12;
+ debug("n_row_addr %d\n", pdimm->n_row_addr);
+ pdimm->n_col_addr = (spd->addressing & 0x7) + 9;
+ debug("n_col_addr %d\n", pdimm->n_col_addr);
+ pdimm->bank_addr_bits = (spd->density_banks >> 4) & 0x3;
+ debug("bank_addr_bits %d\n", pdimm->bank_addr_bits);
+ pdimm->bank_group_bits = (spd->density_banks >> 6) & 0x3;
+ debug("bank_group_bits %d\n", pdimm->bank_group_bits);
+
+ if (pdimm->ec_sdram_width != 0) {
+ pdimm->edc_config = 0x02;
+ } else {
+ pdimm->edc_config = 0x00;
+ }
+ debug("edc_config %d\n", pdimm->edc_config);
+
+ /* DDR4 spec has BL8 -bit3, BC4 -bit2 */
+ pdimm->burst_lengths_bitmask = 0x0c;
+ debug("burst_lengths_bitmask 0x%x\n", pdimm->burst_lengths_bitmask);
+
+ /* MTB - medium timebase
+ * The MTB in the SPD spec is 125ps,
+ *
+ * FTB - fine timebase
+ * use 1/10th of ps as our unit to avoid floating point
+ * eg, 10 for 1ps, 25 for 2.5ps, 50 for 5ps
+ */
+ if ((spd->timebases & 0xf) == 0x0) {
+ pdimm->mtb_ps = 125;
+ pdimm->ftb_10th_ps = 10;
+
+ } else {
+ ERROR("Unknown Timebases\n");
+ return -EINVAL;
+ }
+
+ /* sdram minimum cycle time */
+ pdimm->tckmin_x_ps = spd_to_ps(spd->tck_min, spd->fine_tck_min);
+ debug("tckmin_x_ps %d\n", pdimm->tckmin_x_ps);
+
+ /* sdram max cycle time */
+ pdimm->tckmax_ps = spd_to_ps(spd->tck_max, spd->fine_tck_max);
+ debug("tckmax_ps %d\n", pdimm->tckmax_ps);
+
+ /*
+ * CAS latency supported
+ * bit0 - CL7
+ * bit4 - CL11
+ * bit8 - CL15
+ * bit12- CL19
+ * bit16- CL23
+ */
+ pdimm->caslat_x = (spd->caslat_b1 << 7) |
+ (spd->caslat_b2 << 15) |
+ (spd->caslat_b3 << 23);
+ debug("caslat_x 0x%x\n", pdimm->caslat_x);
+
+ if (spd->caslat_b4 != 0) {
+ WARN("Unhandled caslat_b4 value\n");
+ }
+
+ /*
+ * min CAS latency time
+ */
+ pdimm->taa_ps = spd_to_ps(spd->taa_min, spd->fine_taa_min);
+ debug("taa_ps %d\n", pdimm->taa_ps);
+
+ /*
+ * min RAS to CAS delay time
+ */
+ pdimm->trcd_ps = spd_to_ps(spd->trcd_min, spd->fine_trcd_min);
+ debug("trcd_ps %d\n", pdimm->trcd_ps);
+
+ /*
+ * Min Row Precharge Delay Time
+ */
+ pdimm->trp_ps = spd_to_ps(spd->trp_min, spd->fine_trp_min);
+ debug("trp_ps %d\n", pdimm->trp_ps);
+
+ /* min active to precharge delay time */
+ pdimm->tras_ps = (((spd->tras_trc_ext & 0xf) << 8) +
+ spd->tras_min_lsb) * pdimm->mtb_ps;
+ debug("tras_ps %d\n", pdimm->tras_ps);
+
+ /* min active to actice/refresh delay time */
+ pdimm->trc_ps = spd_to_ps((((spd->tras_trc_ext & 0xf0) << 4) +
+ spd->trc_min_lsb), spd->fine_trc_min);
+ debug("trc_ps %d\n", pdimm->trc_ps);
+ /* Min Refresh Recovery Delay Time */
+ pdimm->trfc1_ps = ((spd->trfc1_min_msb << 8) | (spd->trfc1_min_lsb)) *
+ pdimm->mtb_ps;
+ debug("trfc1_ps %d\n", pdimm->trfc1_ps);
+ pdimm->trfc2_ps = ((spd->trfc2_min_msb << 8) | (spd->trfc2_min_lsb)) *
+ pdimm->mtb_ps;
+ debug("trfc2_ps %d\n", pdimm->trfc2_ps);
+ pdimm->trfc4_ps = ((spd->trfc4_min_msb << 8) | (spd->trfc4_min_lsb)) *
+ pdimm->mtb_ps;
+ debug("trfc4_ps %d\n", pdimm->trfc4_ps);
+ /* min four active window delay time */
+ pdimm->tfaw_ps = (((spd->tfaw_msb & 0xf) << 8) | spd->tfaw_min) *
+ pdimm->mtb_ps;
+ debug("tfaw_ps %d\n", pdimm->tfaw_ps);
+
+ /* min row active to row active delay time, different bank group */
+ pdimm->trrds_ps = spd_to_ps(spd->trrds_min, spd->fine_trrds_min);
+ debug("trrds_ps %d\n", pdimm->trrds_ps);
+ /* min row active to row active delay time, same bank group */
+ pdimm->trrdl_ps = spd_to_ps(spd->trrdl_min, spd->fine_trrdl_min);
+ debug("trrdl_ps %d\n", pdimm->trrdl_ps);
+ /* min CAS to CAS Delay Time (tCCD_Lmin), same bank group */
+ pdimm->tccdl_ps = spd_to_ps(spd->tccdl_min, spd->fine_tccdl_min);
+ debug("tccdl_ps %d\n", pdimm->tccdl_ps);
+ if (pdimm->package_3ds != 0) {
+ if (pdimm->die_density > 5) {
+ debug("Unsupported logical rank density 0x%x\n",
+ pdimm->die_density);
+ return -EINVAL;
+ }
+ pdimm->trfc_slr_ps = (pdimm->die_density <= 4) ?
+ 260000 : 350000;
+ }
+ debug("trfc_slr_ps %d\n", pdimm->trfc_slr_ps);
+
+ /* 15ns for all speed bins */
+ pdimm->twr_ps = 15000;
+ debug("twr_ps %d\n", pdimm->twr_ps);
+
+ /*
+ * Average periodic refresh interval
+ * tREFI = 7.8 us at normal temperature range
+ */
+ pdimm->refresh_rate_ps = 7800000;
+ debug("refresh_rate_ps %d\n", pdimm->refresh_rate_ps);
+
+ for (i = 0; i < 18; i++) {
+ pdimm->dq_mapping[i] = spd->mapping[i];
+ debug("dq_mapping 0x%x\n", pdimm->dq_mapping[i]);
+ }
+
+ pdimm->dq_mapping_ors = ((spd->mapping[0] >> 6) & 0x3) == 0 ? 1 : 0;
+ debug("dq_mapping_ors %d\n", pdimm->dq_mapping_ors);
+
+ return 0;
+}
diff --git a/drivers/nxp/ddr/nxp-ddr/regs.c b/drivers/nxp/ddr/nxp-ddr/regs.c
new file mode 100644
index 0000000..cedd7ca
--- /dev/null
+++ b/drivers/nxp/ddr/nxp-ddr/regs.c
@@ -0,0 +1,1394 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <common/debug.h>
+#include <ddr.h>
+#include <lib/utils.h>
+
+static inline unsigned int cal_cwl(const unsigned long clk)
+{
+ const unsigned int mclk_ps = get_memory_clk_ps(clk);
+
+ return mclk_ps >= 1250U ? 9U :
+ (mclk_ps >= 1070U ? 10U :
+ (mclk_ps >= 935U ? 11U :
+ (mclk_ps >= 833U ? 12U :
+ (mclk_ps >= 750U ? 14U :
+ (mclk_ps >= 625U ? 16U : 18U)))));
+}
+
+static void cal_csn_config(int i,
+ struct ddr_cfg_regs *regs,
+ const struct memctl_opt *popts,
+ const struct dimm_params *pdimm)
+{
+ unsigned int intlv_en = 0U;
+ unsigned int intlv_ctl = 0U;
+ const unsigned int cs_n_en = 1U;
+ const unsigned int ap_n_en = popts->cs_odt[i].auto_precharge;
+ const unsigned int odt_rd_cfg = popts->cs_odt[i].odt_rd_cfg;
+ const unsigned int odt_wr_cfg = popts->cs_odt[i].odt_wr_cfg;
+ const unsigned int ba_bits_cs_n = pdimm->bank_addr_bits;
+ const unsigned int row_bits_cs_n = pdimm->n_row_addr - 12U;
+ const unsigned int col_bits_cs_n = pdimm->n_col_addr - 8U;
+ const unsigned int bg_bits_cs_n = pdimm->bank_group_bits;
+
+ if (i == 0) {
+ /* These fields only available in CS0_CONFIG */
+ if (popts->ctlr_intlv != 0) {
+ switch (popts->ctlr_intlv_mode) {
+ case DDR_256B_INTLV:
+ intlv_en = popts->ctlr_intlv;
+ intlv_ctl = popts->ctlr_intlv_mode;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ regs->cs[i].config = ((cs_n_en & 0x1) << 31) |
+ ((intlv_en & 0x3) << 29) |
+ ((intlv_ctl & 0xf) << 24) |
+ ((ap_n_en & 0x1) << 23) |
+ ((odt_rd_cfg & 0x7) << 20) |
+ ((odt_wr_cfg & 0x7) << 16) |
+ ((ba_bits_cs_n & 0x3) << 14) |
+ ((row_bits_cs_n & 0x7) << 8) |
+ ((bg_bits_cs_n & 0x3) << 4) |
+ ((col_bits_cs_n & 0x7) << 0);
+ debug("cs%d\n", i);
+ debug(" _config = 0x%x\n", regs->cs[i].config);
+}
+
+static inline int avoid_odt_overlap(const struct ddr_conf *conf,
+ const struct dimm_params *pdimm)
+{
+ if ((conf->cs_in_use == 0xf) != 0) {
+ return 2;
+ }
+
+#if DDRC_NUM_DIMM >= 2
+ if (conf->dimm_in_use[0] != 0 && conf->dimm_in_use[1] != 0) {
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+/* Requires rcw2 set first */
+static void cal_timing_cfg(const unsigned long clk,
+ struct ddr_cfg_regs *regs,
+ const struct memctl_opt *popts,
+ const struct dimm_params *pdimm,
+ const struct ddr_conf *conf,
+ unsigned int cas_latency,
+ unsigned int additive_latency)
+{
+ const unsigned int mclk_ps = get_memory_clk_ps(clk);
+ /* tXP=max(4nCK, 6ns) */
+ const int txp = max((int)mclk_ps * 4, 6000);
+ /* DDR4 supports 10, 12, 14, 16, 18, 20, 24 */
+ static const int wrrec_table[] = {
+ 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10,
+ 12, 12, 14, 14, 16,
+ 16, 18, 18, 20, 20,
+ 24, 24, 24, 24,
+ };
+ int trwt_mclk = (clk / 1000000 > 1900) ? 3 : 2;
+ int twrt_mclk;
+ int trrt_mclk;
+ int twwt_mclk;
+ const int act_pd_exit_mclk = picos_to_mclk(clk, txp);
+ const int pre_pd_exit_mclk = act_pd_exit_mclk;
+ const int taxpd_mclk = 0;
+ /*
+ * MRS_CYC = max(tMRD, tMOD)
+ * tMRD = 8nCK, tMOD = max(24nCK, 15ns)
+ */
+ const int tmrd_mclk = max(24U, picos_to_mclk(clk, 15000));
+ const int pretoact_mclk = picos_to_mclk(clk, pdimm->trp_ps);
+ const int acttopre_mclk = picos_to_mclk(clk, pdimm->tras_ps);
+ const int acttorw_mclk = picos_to_mclk(clk, pdimm->trcd_ps);
+ const int caslat_ctrl = (cas_latency - 1) << 1;
+ const int trfc1_min = pdimm->die_density >= 0x3 ? 16000 :
+ (pdimm->die_density == 0x4 ? 26000 :
+ (pdimm->die_density == 0x5 ? 35000 :
+ 55000));
+ const int refrec_ctrl = picos_to_mclk(clk,
+ pdimm->trfc1_ps) - 8;
+ int wrrec_mclk = picos_to_mclk(clk, pdimm->twr_ps);
+ const int acttoact_mclk = max(picos_to_mclk(clk,
+ pdimm->trrds_ps),
+ 4U);
+ int wrtord_mclk = max(2U, picos_to_mclk(clk, 2500));
+ const unsigned int cpo = 0U;
+ const int wr_lat = cal_cwl(clk);
+ int rd_to_pre = picos_to_mclk(clk, 7500);
+ const int wr_data_delay = popts->wr_data_delay;
+ const int cke_pls = max(3U, picos_to_mclk(clk, 5000));
+#ifdef ERRATA_DDR_A050450
+ const unsigned short four_act = ((popts->twot_en == 0) &&
+ (popts->threet_en == 0) &&
+ (popts->tfaw_ps % 2 == 0)) ?
+ (picos_to_mclk(clk, popts->tfaw_ps) + 1) :
+ picos_to_mclk(clk, popts->tfaw_ps);
+#else
+ const unsigned short four_act = picos_to_mclk(clk,
+ popts->tfaw_ps);
+#endif
+ const unsigned int cntl_adj = 0U;
+ const unsigned int ext_pretoact = picos_to_mclk(clk,
+ pdimm->trp_ps) >> 4U;
+ const unsigned int ext_acttopre = picos_to_mclk(clk,
+ pdimm->tras_ps) >> 4U;
+ const unsigned int ext_acttorw = picos_to_mclk(clk,
+ pdimm->trcd_ps) >> 4U;
+ const unsigned int ext_caslat = (2U * cas_latency - 1U) >> 4U;
+ const unsigned int ext_add_lat = additive_latency >> 4U;
+ const unsigned int ext_refrec = (picos_to_mclk(clk,
+ pdimm->trfc1_ps) - 8U) >> 4U;
+ const unsigned int ext_wrrec = (picos_to_mclk(clk, pdimm->twr_ps) +
+ (popts->otf_burst_chop_en ? 2U : 0U)) >> 4U;
+ const unsigned int rwt_same_cs = 0U;
+ const unsigned int wrt_same_cs = 0U;
+ const unsigned int rrt_same_cs = popts->burst_length == DDR_BL8 ? 0U : 2U;
+ const unsigned int wwt_same_cs = popts->burst_length == DDR_BL8 ? 0U : 2U;
+ const unsigned int dll_lock = 2U;
+ unsigned int rodt_on = 0U;
+ const unsigned int rodt_off = 4U;
+ const unsigned int wodt_on = 1U;
+ const unsigned int wodt_off = 4U;
+ const unsigned int hs_caslat = 0U;
+ const unsigned int hs_wrlat = 0U;
+ const unsigned int hs_wrrec = 0U;
+ const unsigned int hs_clkadj = 0U;
+ const unsigned int hs_wrlvl_start = 0U;
+ const unsigned int txpr = max(5U,
+ picos_to_mclk(clk,
+ pdimm->trfc1_ps + 10000U));
+ const unsigned int tcksre = max(5U, picos_to_mclk(clk, 10000U));
+ const unsigned int tcksrx = max(5U, picos_to_mclk(clk, 10000U));
+ const unsigned int cs_to_cmd = 0U;
+ const unsigned int cke_rst = txpr <= 200U ? 0U :
+ (txpr <= 256U ? 1U :
+ (txpr <= 512U ? 2U : 3U));
+ const unsigned int cksre = tcksre <= 19U ? tcksre - 5U : 15U;
+ const unsigned int cksrx = tcksrx <= 19U ? tcksrx - 5U : 15U;
+ unsigned int par_lat = 0U;
+ const int tccdl = max(5U, picos_to_mclk(clk, pdimm->tccdl_ps));
+ int rwt_bg = cas_latency + 2 + 4 - wr_lat;
+ int wrt_bg = wr_lat + 4 + 1 - cas_latency;
+ const int rrt_bg = popts->burst_length == DDR_BL8 ?
+ tccdl - 4 : tccdl - 2;
+ const int wwt_bg = popts->burst_length == DDR_BL8 ?
+ tccdl - 4 : tccdl - 2;
+ const unsigned int acttoact_bg = picos_to_mclk(clk, pdimm->trrdl_ps);
+ const unsigned int wrtord_bg = max(4U, picos_to_mclk(clk, 7500)) +
+ (popts->otf_burst_chop_en ? 2 : 0);
+ const unsigned int pre_all_rec = 0;
+ const unsigned int refrec_cid_mclk = pdimm->package_3ds ?
+ picos_to_mclk(clk, pdimm->trfc_slr_ps) : 0;
+ const unsigned int acttoact_cid_mclk = pdimm->package_3ds ? 4U : 0;
+
+
+ /* for two dual-rank DIMMs to avoid ODT overlap */
+ if (avoid_odt_overlap(conf, pdimm) == 2) {
+ twrt_mclk = 2;
+ twwt_mclk = 2;
+ trrt_mclk = 2;
+ } else {
+ twrt_mclk = 1;
+ twwt_mclk = 1;
+ trrt_mclk = 0;
+ }
+
+ if (popts->trwt_override != 0) {
+ trwt_mclk = popts->trwt;
+ if (popts->twrt != 0) {
+ twrt_mclk = popts->twrt;
+ }
+ if (popts->trrt != 0) {
+ trrt_mclk = popts->trrt;
+ }
+ if (popts->twwt != 0) {
+ twwt_mclk = popts->twwt;
+ }
+ }
+ regs->timing_cfg[0] = (((trwt_mclk & 0x3) << 30) |
+ ((twrt_mclk & 0x3) << 28) |
+ ((trrt_mclk & 0x3) << 26) |
+ ((twwt_mclk & 0x3) << 24) |
+ ((act_pd_exit_mclk & 0xf) << 20) |
+ ((pre_pd_exit_mclk & 0xF) << 16) |
+ ((taxpd_mclk & 0xf) << 8) |
+ ((tmrd_mclk & 0x1f) << 0));
+ debug("timing_cfg[0] = 0x%x\n", regs->timing_cfg[0]);
+
+ if ((wrrec_mclk < 1) || (wrrec_mclk > 24)) {
+ ERROR("WRREC doesn't support clock %d\n", wrrec_mclk);
+ } else {
+ wrrec_mclk = wrrec_table[wrrec_mclk - 1];
+ }
+
+ if (popts->otf_burst_chop_en != 0) {
+ wrrec_mclk += 2;
+ wrtord_mclk += 2;
+ }
+
+ if (pdimm->trfc1_ps < trfc1_min) {
+ ERROR("trfc1_ps (%d) < %d\n", pdimm->trfc1_ps, trfc1_min);
+ }
+
+ regs->timing_cfg[1] = (((pretoact_mclk & 0x0F) << 28) |
+ ((acttopre_mclk & 0x0F) << 24) |
+ ((acttorw_mclk & 0xF) << 20) |
+ ((caslat_ctrl & 0xF) << 16) |
+ ((refrec_ctrl & 0xF) << 12) |
+ ((wrrec_mclk & 0x0F) << 8) |
+ ((acttoact_mclk & 0x0F) << 4) |
+ ((wrtord_mclk & 0x0F) << 0));
+ debug("timing_cfg[1] = 0x%x\n", regs->timing_cfg[1]);
+
+ if (rd_to_pre < 4) {
+ rd_to_pre = 4;
+ }
+ if (popts->otf_burst_chop_en) {
+ rd_to_pre += 2;
+ }
+
+ regs->timing_cfg[2] = (((additive_latency & 0xf) << 28) |
+ ((cpo & 0x1f) << 23) |
+ ((wr_lat & 0xf) << 19) |
+ (((wr_lat & 0x10) >> 4) << 18) |
+ ((rd_to_pre & 0xf) << 13) |
+ ((wr_data_delay & 0xf) << 9) |
+ ((cke_pls & 0x7) << 6) |
+ ((four_act & 0x3f) << 0));
+ debug("timing_cfg[2] = 0x%x\n", regs->timing_cfg[2]);
+
+ regs->timing_cfg[3] = (((ext_pretoact & 0x1) << 28) |
+ ((ext_acttopre & 0x3) << 24) |
+ ((ext_acttorw & 0x1) << 22) |
+ ((ext_refrec & 0x3F) << 16) |
+ ((ext_caslat & 0x3) << 12) |
+ ((ext_add_lat & 0x1) << 10) |
+ ((ext_wrrec & 0x1) << 8) |
+ ((cntl_adj & 0x7) << 0));
+ debug("timing_cfg[3] = 0x%x\n", regs->timing_cfg[3]);
+
+ regs->timing_cfg[4] = (((rwt_same_cs & 0xf) << 28) |
+ ((wrt_same_cs & 0xf) << 24) |
+ ((rrt_same_cs & 0xf) << 20) |
+ ((wwt_same_cs & 0xf) << 16) |
+ ((trwt_mclk & 0xc) << 12) |
+ ((twrt_mclk & 0x4) << 10) |
+ ((trrt_mclk & 0x4) << 8) |
+ ((twwt_mclk & 0x4) << 6) |
+ (dll_lock & 0x3));
+ debug("timing_cfg[4] = 0x%x\n", regs->timing_cfg[4]);
+
+ /* rodt_on = timing_cfg_1[caslat] - timing_cfg_2[wrlat] + 1 */
+ if (cas_latency >= wr_lat) {
+ rodt_on = cas_latency - wr_lat + 1;
+ }
+
+ regs->timing_cfg[5] = (((rodt_on & 0x1f) << 24) |
+ ((rodt_off & 0x7) << 20) |
+ ((wodt_on & 0x1f) << 12) |
+ (wodt_off & 0x7) << 8);
+ debug("timing_cfg[5] = 0x%x\n", regs->timing_cfg[5]);
+
+ regs->timing_cfg[6] = (((hs_caslat & 0x1f) << 24) |
+ ((hs_wrlat & 0x1f) << 19) |
+ ((hs_wrrec & 0x1f) << 12) |
+ ((hs_clkadj & 0x1f) << 6) |
+ ((hs_wrlvl_start & 0x1f) << 0));
+ debug("timing_cfg[6] = 0x%x\n", regs->timing_cfg[6]);
+
+ if (popts->ap_en != 0) {
+ par_lat = (regs->sdram_rcw[1] & 0xf) + 1;
+ debug("PAR_LAT = 0x%x\n", par_lat);
+ }
+
+ regs->timing_cfg[7] = (((cke_rst & 0x3) << 28) |
+ ((cksre & 0xf) << 24) |
+ ((cksrx & 0xf) << 20) |
+ ((par_lat & 0xf) << 16) |
+ ((cs_to_cmd & 0xf) << 4));
+ debug("timing_cfg[7] = 0x%x\n", regs->timing_cfg[7]);
+
+ if (rwt_bg < tccdl) {
+ rwt_bg = tccdl - rwt_bg;
+ } else {
+ rwt_bg = 0;
+ }
+ if (wrt_bg < tccdl) {
+ wrt_bg = tccdl - wrt_bg;
+ } else {
+ wrt_bg = 0;
+ }
+ regs->timing_cfg[8] = (((rwt_bg & 0xf) << 28) |
+ ((wrt_bg & 0xf) << 24) |
+ ((rrt_bg & 0xf) << 20) |
+ ((wwt_bg & 0xf) << 16) |
+ ((acttoact_bg & 0xf) << 12) |
+ ((wrtord_bg & 0xf) << 8) |
+ ((pre_all_rec & 0x1f) << 0));
+ debug("timing_cfg[8] = 0x%x\n", regs->timing_cfg[8]);
+
+ regs->timing_cfg[9] = (refrec_cid_mclk & 0x3ff) << 16 |
+ (acttoact_cid_mclk & 0xf) << 8;
+ debug("timing_cfg[9] = 0x%x\n", regs->timing_cfg[9]);
+}
+
+static void cal_ddr_sdram_rcw(const unsigned long clk,
+ struct ddr_cfg_regs *regs,
+ const struct memctl_opt *popts,
+ const struct dimm_params *pdimm)
+{
+ const unsigned int freq = clk / 1000000U;
+ unsigned int rc0a, rc0f;
+
+ if (pdimm->rdimm == 0) {
+ return;
+ }
+
+ rc0a = freq > 3200U ? 7U :
+ (freq > 2933U ? 6U :
+ (freq > 2666U ? 5U :
+ (freq > 2400U ? 4U :
+ (freq > 2133U ? 3U :
+ (freq > 1866U ? 2U :
+ (freq > 1600U ? 1U : 0U))))));
+ rc0f = freq > 3200U ? 3U :
+ (freq > 2400U ? 2U :
+ (freq > 2133U ? 1U : 0U));
+ rc0f = (regs->sdram_cfg[1] & SDRAM_CFG2_AP_EN) ? rc0f : 4;
+ regs->sdram_rcw[0] =
+ pdimm->rcw[0] << 28 |
+ pdimm->rcw[1] << 24 |
+ pdimm->rcw[2] << 20 |
+ pdimm->rcw[3] << 16 |
+ pdimm->rcw[4] << 12 |
+ pdimm->rcw[5] << 8 |
+ pdimm->rcw[6] << 4 |
+ pdimm->rcw[7];
+ regs->sdram_rcw[1] =
+ pdimm->rcw[8] << 28 |
+ pdimm->rcw[9] << 24 |
+ rc0a << 20 |
+ pdimm->rcw[11] << 16 |
+ pdimm->rcw[12] << 12 |
+ pdimm->rcw[13] << 8 |
+ pdimm->rcw[14] << 4 |
+ rc0f;
+ regs->sdram_rcw[2] =
+ ((freq - 1260 + 19) / 20) << 8;
+
+ debug("sdram_rcw[0] = 0x%x\n", regs->sdram_rcw[0]);
+ debug("sdram_rcw[1] = 0x%x\n", regs->sdram_rcw[1]);
+ debug("sdram_rcw[2] = 0x%x\n", regs->sdram_rcw[2]);
+}
+
+static void cal_ddr_sdram_cfg(const unsigned long clk,
+ struct ddr_cfg_regs *regs,
+ const struct memctl_opt *popts,
+ const struct dimm_params *pdimm,
+ const unsigned int ip_rev)
+{
+ const unsigned int mem_en = 1U;
+ const unsigned int sren = popts->self_refresh_in_sleep;
+ const unsigned int ecc_en = popts->ecc_mode;
+ const unsigned int rd_en = (pdimm->rdimm != 0U) ? 1U : 0U;
+ const unsigned int dyn_pwr = popts->dynamic_power;
+ const unsigned int dbw = popts->data_bus_used;
+ const unsigned int eight_be = (dbw == 1U ||
+ popts->burst_length == DDR_BL8) ? 1U : 0U;
+ const unsigned int ncap = 0U;
+ const unsigned int threet_en = popts->threet_en;
+ const unsigned int twot_en = pdimm->rdimm ?
+ 0U : popts->twot_en;
+ const unsigned int ba_intlv = popts->ba_intlv;
+ const unsigned int x32_en = 0U;
+ const unsigned int pchb8 = 0U;
+ const unsigned int hse = popts->half_strength_drive_en;
+ const unsigned int acc_ecc_en = (dbw != 0U && ecc_en == 1U) ? 1U : 0U;
+ const unsigned int mem_halt = 0U;
+#ifdef PHY_GEN2
+ const unsigned int bi = 1U;
+#else
+ const unsigned int bi = 0U;
+#endif
+ const unsigned int sdram_type = SDRAM_TYPE_DDR4;
+ unsigned int odt_cfg = 0U;
+ const unsigned int frc_sr = 0U;
+ const unsigned int sr_ie = popts->self_refresh_irq_en;
+ const unsigned int num_pr = pdimm->package_3ds + 1U;
+ const unsigned int slow = (clk < 1249000000U) ? 1U : 0U;
+ const unsigned int x4_en = popts->x4_en;
+ const unsigned int obc_cfg = popts->otf_burst_chop_en;
+ const unsigned int ap_en = ip_rev == 0x50500U ? 0U : popts->ap_en;
+ const unsigned int d_init = popts->ctlr_init_ecc;
+ const unsigned int rcw_en = popts->rdimm;
+ const unsigned int md_en = popts->mirrored_dimm;
+ const unsigned int qd_en = popts->quad_rank_present;
+ const unsigned int unq_mrs_en = ip_rev < 0x50500U ? 1U : 0U;
+ const unsigned int rd_pre = popts->quad_rank_present;
+ int i;
+
+ regs->sdram_cfg[0] = ((mem_en & 0x1) << 31) |
+ ((sren & 0x1) << 30) |
+ ((ecc_en & 0x1) << 29) |
+ ((rd_en & 0x1) << 28) |
+ ((sdram_type & 0x7) << 24) |
+ ((dyn_pwr & 0x1) << 21) |
+ ((dbw & 0x3) << 19) |
+ ((eight_be & 0x1) << 18) |
+ ((ncap & 0x1) << 17) |
+ ((threet_en & 0x1) << 16) |
+ ((twot_en & 0x1) << 15) |
+ ((ba_intlv & 0x7F) << 8) |
+ ((x32_en & 0x1) << 5) |
+ ((pchb8 & 0x1) << 4) |
+ ((hse & 0x1) << 3) |
+ ((acc_ecc_en & 0x1) << 2) |
+ ((mem_halt & 0x1) << 1) |
+ ((bi & 0x1) << 0);
+ debug("sdram_cfg[0] = 0x%x\n", regs->sdram_cfg[0]);
+
+ for (i = 0; i < DDRC_NUM_CS; i++) {
+ if (popts->cs_odt[i].odt_rd_cfg != 0 ||
+ popts->cs_odt[i].odt_wr_cfg != 0) {
+ odt_cfg = SDRAM_CFG2_ODT_ONLY_READ;
+ break;
+ }
+ }
+
+ regs->sdram_cfg[1] = (0
+ | ((frc_sr & 0x1) << 31)
+ | ((sr_ie & 0x1) << 30)
+ | ((odt_cfg & 0x3) << 21)
+ | ((num_pr & 0xf) << 12)
+ | ((slow & 1) << 11)
+ | (x4_en << 10)
+ | (qd_en << 9)
+ | (unq_mrs_en << 8)
+ | ((obc_cfg & 0x1) << 6)
+ | ((ap_en & 0x1) << 5)
+ | ((d_init & 0x1) << 4)
+ | ((rcw_en & 0x1) << 2)
+ | ((md_en & 0x1) << 0)
+ );
+ debug("sdram_cfg[1] = 0x%x\n", regs->sdram_cfg[1]);
+
+ regs->sdram_cfg[2] = (rd_pre & 0x1) << 16 |
+ (popts->rdimm ? 1 : 0);
+ if (pdimm->package_3ds != 0) {
+ if (((pdimm->package_3ds + 1) & 0x1) != 0) {
+ WARN("Unsupported 3DS DIMM\n");
+ } else {
+ regs->sdram_cfg[2] |= ((pdimm->package_3ds + 1) >> 1)
+ << 4;
+ }
+ }
+ debug("sdram_cfg[2] = 0x%x\n", regs->sdram_cfg[2]);
+}
+
+
+static void cal_ddr_sdram_interval(const unsigned long clk,
+ struct ddr_cfg_regs *regs,
+ const struct memctl_opt *popts,
+ const struct dimm_params *pdimm)
+{
+ const unsigned int refint = picos_to_mclk(clk, pdimm->refresh_rate_ps);
+ const unsigned int bstopre = popts->bstopre;
+
+ regs->interval = ((refint & 0xFFFF) << 16) |
+ ((bstopre & 0x3FFF) << 0);
+ debug("interval = 0x%x\n", regs->interval);
+}
+
+/* Require cs and cfg first */
+static void cal_ddr_sdram_mode(const unsigned long clk,
+ struct ddr_cfg_regs *regs,
+ const struct memctl_opt *popts,
+ const struct ddr_conf *conf,
+ const struct dimm_params *pdimm,
+ unsigned int cas_latency,
+ unsigned int additive_latency,
+ const unsigned int ip_rev)
+{
+ int i;
+ unsigned short esdmode; /* Extended SDRAM mode */
+ unsigned short sdmode; /* SDRAM mode */
+
+ /* Mode Register - MR1 */
+ const unsigned int qoff = 0;
+ const unsigned int tdqs_en = 0;
+ unsigned int rtt;
+ const unsigned int wrlvl_en = 0;
+ unsigned int al = 0;
+ unsigned int dic = 0;
+ const unsigned int dll_en = 1;
+
+ /* Mode Register - MR0 */
+ unsigned int wr = 0;
+ const unsigned int dll_rst = 0;
+ const unsigned int mode = 0;
+ unsigned int caslat = 4;/* CAS# latency, default set as 6 cycles */
+ /* BT: Burst Type (0=Nibble Sequential, 1=Interleaved) */
+ const unsigned int bt = 0;
+ const unsigned int bl = popts->burst_length == DDR_BL8 ? 0 :
+ (popts->burst_length == DDR_BC4 ? 2 : 1);
+
+ const unsigned int wr_mclk = picos_to_mclk(clk, pdimm->twr_ps);
+ /* DDR4 support WR 10, 12, 14, 16, 18, 20, 24 */
+ static const int wr_table[] = {
+ 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 6
+ };
+ /* DDR4 support CAS 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24 */
+ static const int cas_latency_table[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 13, 8,
+ 14, 9, 15, 10, 12, 11, 16, 17,
+ 18, 19, 20, 21, 22, 23
+ };
+ const unsigned int unq_mrs_en = ip_rev < U(0x50500) ? 1U : 0U;
+ unsigned short esdmode2 = 0U;
+ unsigned short esdmode3 = 0U;
+ const unsigned int wr_crc = 0U;
+ unsigned int rtt_wr = 0U;
+ const unsigned int srt = 0U;
+ unsigned int cwl = cal_cwl(clk);
+ const unsigned int mpr = 0U;
+ const unsigned int mclk_ps = get_memory_clk_ps(clk);
+ const unsigned int wc_lat = 0U;
+ unsigned short esdmode4 = 0U;
+ unsigned short esdmode5;
+ int rtt_park_all = 0;
+ unsigned int rtt_park;
+ const bool four_cs = conf->cs_in_use == 0xf ? true : false;
+ unsigned short esdmode6 = 0U; /* Extended SDRAM mode 6 */
+ unsigned short esdmode7 = 0U; /* Extended SDRAM mode 7 */
+ const unsigned int tccdl_min = max(5U,
+ picos_to_mclk(clk, pdimm->tccdl_ps));
+
+ if (popts->rtt_override != 0U) {
+ rtt = popts->rtt_override_value;
+ } else {
+ rtt = popts->cs_odt[0].odt_rtt_norm;
+ }
+
+ if (additive_latency == (cas_latency - 1)) {
+ al = 1;
+ }
+ if (additive_latency == (cas_latency - 2)) {
+ al = 2;
+ }
+
+ if (popts->quad_rank_present != 0 || popts->output_driver_impedance != 0) {
+ dic = 1; /* output driver impedance 240/7 ohm */
+ }
+
+ esdmode = (((qoff & 0x1) << 12) |
+ ((tdqs_en & 0x1) << 11) |
+ ((rtt & 0x7) << 8) |
+ ((wrlvl_en & 0x1) << 7) |
+ ((al & 0x3) << 3) |
+ ((dic & 0x3) << 1) |
+ ((dll_en & 0x1) << 0));
+
+ if (wr_mclk >= 10 && wr_mclk <= 24) {
+ wr = wr_table[wr_mclk - 10];
+ } else {
+ ERROR("unsupported wc_mclk = %d for mode register\n", wr_mclk);
+ }
+
+ /* look up table to get the cas latency bits */
+ if (cas_latency >= 9 && cas_latency <= 32) {
+ caslat = cas_latency_table[cas_latency - 9];
+ } else {
+ WARN("Error: unsupported cas latency for mode register\n");
+ }
+
+ sdmode = (((caslat & 0x10) << 8) |
+ ((wr & 0x7) << 9) |
+ ((dll_rst & 0x1) << 8) |
+ ((mode & 0x1) << 7) |
+ (((caslat >> 1) & 0x7) << 4) |
+ ((bt & 0x1) << 3) |
+ ((caslat & 1) << 2) |
+ ((bl & 0x3) << 0));
+
+ regs->sdram_mode[0] = (((esdmode & 0xFFFF) << 16) |
+ ((sdmode & 0xFFFF) << 0));
+ debug("sdram_mode[0] = 0x%x\n", regs->sdram_mode[0]);
+
+ switch (cwl) {
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ cwl -= 9;
+ break;
+ case 14:
+ cwl -= 10;
+ break;
+ case 16:
+ cwl -= 11;
+ break;
+ case 18:
+ cwl -= 12;
+ break;
+ case 20:
+ cwl -= 13;
+ break;
+ default:
+ printf("Error CWL\n");
+ break;
+ }
+
+ if (popts->rtt_override != 0) {
+ rtt_wr = popts->rtt_wr_override_value;
+ } else {
+ rtt_wr = popts->cs_odt[0].odt_rtt_wr;
+ }
+
+ esdmode2 = ((wr_crc & 0x1) << 12) |
+ ((rtt_wr & 0x7) << 9) |
+ ((srt & 0x3) << 6) |
+ ((cwl & 0x7) << 3);
+ esdmode3 = ((mpr & 0x3) << 11) | ((wc_lat & 0x3) << 9);
+
+ regs->sdram_mode[1] = ((esdmode2 & 0xFFFF) << 16) |
+ ((esdmode3 & 0xFFFF) << 0);
+ debug("sdram_mode[1] = 0x%x\n", regs->sdram_mode[1]);
+
+ esdmode6 = ((tccdl_min - 4) & 0x7) << 10;
+ if (popts->vref_dimm != 0) {
+ esdmode6 |= popts->vref_dimm & 0x7f;
+ } else if ((popts->ddr_cdr2 & DDR_CDR2_VREF_RANGE_2) != 0) {
+ esdmode6 |= 1 << 6; /* Range 2 */
+ }
+
+ regs->sdram_mode[9] = ((esdmode6 & 0xffff) << 16) |
+ ((esdmode7 & 0xffff) << 0);
+ debug("sdram_mode[9] = 0x%x\n", regs->sdram_mode[9]);
+
+ rtt_park = (popts->rtt_park != 0) ? popts->rtt_park : 240;
+ switch (rtt_park) {
+ case 240:
+ rtt_park = 0x4;
+ break;
+ case 120:
+ rtt_park = 0x2;
+ break;
+ case 80:
+ rtt_park = 0x6;
+ break;
+ case 60:
+ rtt_park = 0x1;
+ break;
+ case 48:
+ rtt_park = 0x5;
+ break;
+ case 40:
+ rtt_park = 0x3;
+ break;
+ case 34:
+ rtt_park = 0x7;
+ break;
+ default:
+ rtt_park = 0;
+ break;
+ }
+
+ for (i = 0; i < DDRC_NUM_CS; i++) {
+ if (i != 0 && unq_mrs_en == 0) {
+ break;
+ }
+
+ if (popts->rtt_override != 0) {
+ rtt = popts->rtt_override_value;
+ rtt_wr = popts->rtt_wr_override_value;
+ } else {
+ rtt = popts->cs_odt[i].odt_rtt_norm;
+ rtt_wr = popts->cs_odt[i].odt_rtt_wr;
+ }
+
+ esdmode &= 0xF8FF; /* clear bit 10,9,8 for rtt */
+ esdmode |= (rtt & 0x7) << 8;
+ esdmode2 &= 0xF9FF; /* clear bit 10, 9 */
+ esdmode2 |= (rtt_wr & 0x3) << 9;
+ esdmode5 = (popts->x4_en) ? 0 : 0x400; /* data mask */
+
+ if (rtt_park_all == 0 &&
+ ((regs->cs[i].config & SDRAM_CS_CONFIG_EN) != 0)) {
+ esdmode5 |= rtt_park << 6;
+ rtt_park_all = four_cs ? 0 : 1;
+ }
+
+ if (((regs->sdram_cfg[1] & SDRAM_CFG2_AP_EN) != 0) &&
+ (popts->rdimm == 0)) {
+ if (mclk_ps >= 935) {
+ esdmode5 |= DDR_MR5_CA_PARITY_LAT_4_CLK;
+ } else if (mclk_ps >= 833) {
+ esdmode5 |= DDR_MR5_CA_PARITY_LAT_5_CLK;
+ } else {
+ esdmode5 |= DDR_MR5_CA_PARITY_LAT_5_CLK;
+ WARN("mclk_ps not supported %d", mclk_ps);
+
+ }
+ }
+
+ switch (i) {
+ case 0:
+ regs->sdram_mode[8] = ((esdmode4 & 0xffff) << 16) |
+ ((esdmode5 & 0xffff) << 0);
+ debug("sdram_mode[8] = 0x%x\n", regs->sdram_mode[8]);
+ break;
+ case 1:
+ regs->sdram_mode[2] = (((esdmode & 0xFFFF) << 16) |
+ ((sdmode & 0xFFFF) << 0));
+ regs->sdram_mode[3] = ((esdmode2 & 0xFFFF) << 16) |
+ ((esdmode3 & 0xFFFF) << 0);
+ regs->sdram_mode[10] = ((esdmode4 & 0xFFFF) << 16) |
+ ((esdmode5 & 0xFFFF) << 0);
+ regs->sdram_mode[11] = ((esdmode6 & 0xFFFF) << 16) |
+ ((esdmode7 & 0xFFFF) << 0);
+ debug("sdram_mode[2] = 0x%x\n", regs->sdram_mode[2]);
+ debug("sdram_mode[3] = 0x%x\n", regs->sdram_mode[3]);
+ debug("sdram_mode[10] = 0x%x\n", regs->sdram_mode[10]);
+ debug("sdram_mode[11] = 0x%x\n", regs->sdram_mode[11]);
+ break;
+ case 2:
+ regs->sdram_mode[4] = (((esdmode & 0xFFFF) << 16) |
+ ((sdmode & 0xFFFF) << 0));
+ regs->sdram_mode[5] = ((esdmode2 & 0xFFFF) << 16) |
+ ((esdmode3 & 0xFFFF) << 0);
+ regs->sdram_mode[12] = ((esdmode4 & 0xFFFF) << 16) |
+ ((esdmode5 & 0xFFFF) << 0);
+ regs->sdram_mode[13] = ((esdmode6 & 0xFFFF) << 16) |
+ ((esdmode7 & 0xFFFF) << 0);
+ debug("sdram_mode[4] = 0x%x\n", regs->sdram_mode[4]);
+ debug("sdram_mode[5] = 0x%x\n", regs->sdram_mode[5]);
+ debug("sdram_mode[12] = 0x%x\n", regs->sdram_mode[12]);
+ debug("sdram_mode[13] = 0x%x\n", regs->sdram_mode[13]);
+ break;
+ case 3:
+ regs->sdram_mode[6] = (((esdmode & 0xFFFF) << 16) |
+ ((sdmode & 0xFFFF) << 0));
+ regs->sdram_mode[7] = ((esdmode2 & 0xFFFF) << 16) |
+ ((esdmode3 & 0xFFFF) << 0);
+ regs->sdram_mode[14] = ((esdmode4 & 0xFFFF) << 16) |
+ ((esdmode5 & 0xFFFF) << 0);
+ regs->sdram_mode[15] = ((esdmode6 & 0xFFFF) << 16) |
+ ((esdmode7 & 0xFFFF) << 0);
+ debug("sdram_mode[6] = 0x%x\n", regs->sdram_mode[6]);
+ debug("sdram_mode[7] = 0x%x\n", regs->sdram_mode[7]);
+ debug("sdram_mode[14] = 0x%x\n", regs->sdram_mode[14]);
+ debug("sdram_mode[15] = 0x%x\n", regs->sdram_mode[15]);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+#ifndef CONFIG_MEM_INIT_VALUE
+#define CONFIG_MEM_INIT_VALUE 0xDEADBEEF
+#endif
+static void cal_ddr_data_init(struct ddr_cfg_regs *regs)
+{
+ regs->data_init = CONFIG_MEM_INIT_VALUE;
+}
+
+static void cal_ddr_dq_mapping(struct ddr_cfg_regs *regs,
+ const struct dimm_params *pdimm)
+{
+ const unsigned int acc_ecc_en = (regs->sdram_cfg[0] >> 2) & 0x1;
+/* FIXME: revert the dq mapping from DIMM */
+ regs->dq_map[0] = ((pdimm->dq_mapping[0] & 0x3F) << 26) |
+ ((pdimm->dq_mapping[1] & 0x3F) << 20) |
+ ((pdimm->dq_mapping[2] & 0x3F) << 14) |
+ ((pdimm->dq_mapping[3] & 0x3F) << 8) |
+ ((pdimm->dq_mapping[4] & 0x3F) << 2);
+
+ regs->dq_map[1] = ((pdimm->dq_mapping[5] & 0x3F) << 26) |
+ ((pdimm->dq_mapping[6] & 0x3F) << 20) |
+ ((pdimm->dq_mapping[7] & 0x3F) << 14) |
+ ((pdimm->dq_mapping[10] & 0x3F) << 8) |
+ ((pdimm->dq_mapping[11] & 0x3F) << 2);
+
+ regs->dq_map[2] = ((pdimm->dq_mapping[12] & 0x3F) << 26) |
+ ((pdimm->dq_mapping[13] & 0x3F) << 20) |
+ ((pdimm->dq_mapping[14] & 0x3F) << 14) |
+ ((pdimm->dq_mapping[15] & 0x3F) << 8) |
+ ((pdimm->dq_mapping[16] & 0x3F) << 2);
+
+ /* dq_map for ECC[4:7] is set to 0 if accumulated ECC is enabled */
+ regs->dq_map[3] = ((pdimm->dq_mapping[17] & 0x3F) << 26) |
+ ((pdimm->dq_mapping[8] & 0x3F) << 20) |
+ ((acc_ecc_en != 0) ? 0 :
+ (pdimm->dq_mapping[9] & 0x3F) << 14) |
+ pdimm->dq_mapping_ors;
+ debug("dq_map[0] = 0x%x\n", regs->dq_map[0]);
+ debug("dq_map[1] = 0x%x\n", regs->dq_map[1]);
+ debug("dq_map[2] = 0x%x\n", regs->dq_map[2]);
+ debug("dq_map[3] = 0x%x\n", regs->dq_map[3]);
+}
+static void cal_ddr_zq_cntl(struct ddr_cfg_regs *regs)
+{
+ const unsigned int zqinit = 10U; /* 1024 clocks */
+ const unsigned int zqoper = 9U; /* 512 clocks */
+ const unsigned int zqcs = 7U; /* 128 clocks */
+ const unsigned int zqcs_init = 5U; /* 1024 refresh seqences */
+ const unsigned int zq_en = 1U; /* enabled */
+
+ regs->zq_cntl = ((zq_en & 0x1) << 31) |
+ ((zqinit & 0xF) << 24) |
+ ((zqoper & 0xF) << 16) |
+ ((zqcs & 0xF) << 8) |
+ ((zqcs_init & 0xF) << 0);
+ debug("zq_cntl = 0x%x\n", regs->zq_cntl);
+}
+
+static void cal_ddr_sr_cntr(struct ddr_cfg_regs *regs,
+ const struct memctl_opt *popts)
+{
+ const unsigned int sr_it = (popts->auto_self_refresh_en) ?
+ popts->sr_it : 0;
+
+ regs->ddr_sr_cntr = (sr_it & 0xF) << 16;
+ debug("ddr_sr_cntr = 0x%x\n", regs->ddr_sr_cntr);
+}
+
+static void cal_ddr_eor(struct ddr_cfg_regs *regs,
+ const struct memctl_opt *popts)
+{
+ if (popts->addr_hash != 0) {
+ regs->eor = 0x40000000; /* address hash enable */
+ debug("eor = 0x%x\n", regs->eor);
+ }
+}
+
+static void cal_ddr_csn_bnds(struct ddr_cfg_regs *regs,
+ const struct memctl_opt *popts,
+ const struct ddr_conf *conf,
+ const struct dimm_params *pdimm)
+{
+ int i;
+ unsigned long long ea, sa;
+
+ /* Chip Select Memory Bounds (CSn_BNDS) */
+ for (i = 0;
+ i < DDRC_NUM_CS && conf->cs_size[i];
+ i++) {
+ debug("cs_in_use = 0x%x\n", conf->cs_in_use);
+ if (conf->cs_in_use != 0) {
+ sa = conf->cs_base_addr[i];
+ ea = sa + conf->cs_size[i] - 1;
+ sa >>= 24;
+ ea >>= 24;
+ regs->cs[i].bnds = ((sa & 0xffff) << 16) |
+ ((ea & 0xffff) << 0);
+ cal_csn_config(i, regs, popts, pdimm);
+ } else {
+ /* setting bnds to 0xffffffff for inactive CS */
+ regs->cs[i].bnds = 0xffffffff;
+ }
+
+ debug("cs[%d].bnds = 0x%x\n", i, regs->cs[i].bnds);
+ }
+}
+
+static void cal_ddr_addr_dec(struct ddr_cfg_regs *regs)
+{
+#ifdef CONFIG_DDR_ADDR_DEC
+ unsigned int ba_bits __unused;
+ char p __unused;
+ const unsigned int cs0_config = regs->cs[0].config;
+ const int cacheline = PLATFORM_CACHE_LINE_SHIFT;
+ unsigned int bg_bits;
+ unsigned int row_bits;
+ unsigned int col_bits;
+ unsigned int cs;
+ unsigned int map_row[18];
+ unsigned int map_col[11];
+ unsigned int map_ba[2];
+ unsigned int map_cid[2] = {0x3F, 0x3F};
+ unsigned int map_bg[2] = {0x3F, 0x3F};
+ unsigned int map_cs[2] = {0x3F, 0x3F};
+ unsigned int dbw;
+ unsigned int ba_intlv;
+ int placement;
+ int intlv;
+ int abort = 0;
+ int i;
+ int j;
+
+ col_bits = (cs0_config >> 0) & 0x7;
+ if (col_bits < 4) {
+ col_bits += 8;
+ } else if (col_bits < 7 || col_bits > 10) {
+ ERROR("Error %s col_bits = %d\n", __func__, col_bits);
+ }
+ row_bits = ((cs0_config >> 8) & 0x7) + 12;
+ ba_bits = ((cs0_config >> 14) & 0x3) + 2;
+ bg_bits = ((cs0_config >> 4) & 0x3) + 0;
+ intlv = (cs0_config >> 24) & 0xf;
+ ba_intlv = (regs->sdram_cfg[0] >> 8) & 0x7f;
+ switch (ba_intlv) {
+ case DDR_BA_INTLV_CS01:
+ cs = 1;
+ break;
+ case DDR_BA_INTLV_CS0123:
+ cs = 2;
+ break;
+ case DDR_BA_NONE:
+ cs = 0;
+ break;
+ default:
+ ERROR("%s ba_intlv 0x%x\n", __func__, ba_intlv);
+ return;
+ }
+ debug("col %d, row %d, ba %d, bg %d, intlv %d\n",
+ col_bits, row_bits, ba_bits, bg_bits, intlv);
+ /*
+ * Example mapping of 15x2x2x10
+ * ---- --rr rrrr rrrr rrrr rCBB Gccc cccI cGcc cbbb
+ */
+ dbw = (regs->sdram_cfg[0] >> 19) & 0x3;
+ switch (dbw) {
+ case 0: /* 64-bit */
+ placement = 3;
+ break;
+ case 1: /* 32-bit */
+ placement = 2;
+ break;
+ default:
+ ERROR("%s dbw = %d\n", __func__, dbw);
+ return;
+ }
+ debug("cacheline size %d\n", cacheline);
+ for (i = 0; placement < cacheline; i++) {
+ map_col[i] = placement++;
+ }
+ map_bg[0] = placement++;
+ for ( ; i < col_bits; i++) {
+ map_col[i] = placement++;
+ if (placement == intlv) {
+ placement++;
+ }
+ }
+ for ( ; i < 11; i++) {
+ map_col[i] = 0x3F; /* unused col bits */
+ }
+
+ if (bg_bits >= 2) {
+ map_bg[1] = placement++;
+ }
+ map_ba[0] = placement++;
+ map_ba[1] = placement++;
+ if (cs != 0U) {
+ map_cs[0] = placement++;
+ if (cs == 2U) {
+ map_cs[1] = placement++;
+ }
+ } else {
+ map_cs[0] = U(0x3F);
+ }
+
+ for (i = 0; i < row_bits; i++) {
+ map_row[i] = placement++;
+ }
+
+ for ( ; i < 18; i++) {
+ map_row[i] = 0x3F; /* unused row bits */
+ }
+
+ for (i = 39; i >= 0 ; i--) {
+ if (i == intlv) {
+ placement = 8;
+ p = 'I';
+ } else if (i < 3) {
+ p = 'b';
+ placement = 0;
+ } else {
+ placement = 0;
+ p = '-';
+ }
+ for (j = 0; j < 18; j++) {
+ if (map_row[j] != i) {
+ continue;
+ }
+ if (placement != 0) {
+ abort = 1;
+ ERROR("%s wrong address bit %d\n", __func__, i);
+ }
+ placement = i;
+ p = 'r';
+ }
+ for (j = 0; j < 11; j++) {
+ if (map_col[j] != i) {
+ continue;
+ }
+ if (placement != 0) {
+ abort = 1;
+ ERROR("%s wrong address bit %d\n", __func__, i);
+ }
+ placement = i;
+ p = 'c';
+ }
+ for (j = 0; j < 2; j++) {
+ if (map_ba[j] != i) {
+ continue;
+ }
+ if (placement != 0) {
+ abort = 1;
+ ERROR("%s wrong address bit %d\n", __func__, i);
+ }
+ placement = i;
+ p = 'B';
+ }
+ for (j = 0; j < 2; j++) {
+ if (map_bg[j] != i) {
+ continue;
+ }
+ if (placement != 0) {
+ abort = 1;
+ ERROR("%s wrong address bit %d\n", __func__, i);
+ }
+ placement = i;
+ p = 'G';
+ }
+ for (j = 0; j < 2; j++) {
+ if (map_cs[j] != i) {
+ continue;
+ }
+ if (placement != 0) {
+ abort = 1;
+ ERROR("%s wrong address bit %d\n", __func__, i);
+ }
+ placement = i;
+ p = 'C';
+ }
+#ifdef DDR_DEBUG
+ printf("%c", p);
+ if ((i % 4) == 0) {
+ printf(" ");
+ }
+#endif
+ }
+#ifdef DDR_DEBUG
+ puts("\n");
+#endif
+
+ if (abort != 0) {
+ return;
+ }
+
+ regs->dec[0] = map_row[17] << 26 |
+ map_row[16] << 18 |
+ map_row[15] << 10 |
+ map_row[14] << 2;
+ regs->dec[1] = map_row[13] << 26 |
+ map_row[12] << 18 |
+ map_row[11] << 10 |
+ map_row[10] << 2;
+ regs->dec[2] = map_row[9] << 26 |
+ map_row[8] << 18 |
+ map_row[7] << 10 |
+ map_row[6] << 2;
+ regs->dec[3] = map_row[5] << 26 |
+ map_row[4] << 18 |
+ map_row[3] << 10 |
+ map_row[2] << 2;
+ regs->dec[4] = map_row[1] << 26 |
+ map_row[0] << 18 |
+ map_col[10] << 10 |
+ map_col[9] << 2;
+ regs->dec[5] = map_col[8] << 26 |
+ map_col[7] << 18 |
+ map_col[6] << 10 |
+ map_col[5] << 2;
+ regs->dec[6] = map_col[4] << 26 |
+ map_col[3] << 18 |
+ map_col[2] << 10 |
+ map_col[1] << 2;
+ regs->dec[7] = map_col[0] << 26 |
+ map_ba[1] << 18 |
+ map_ba[0] << 10 |
+ map_cid[1] << 2;
+ regs->dec[8] = map_cid[1] << 26 |
+ map_cs[1] << 18 |
+ map_cs[0] << 10 |
+ map_bg[1] << 2;
+ regs->dec[9] = map_bg[0] << 26 |
+ 1;
+ for (i = 0; i < 10; i++) {
+ debug("dec[%d] = 0x%x\n", i, regs->dec[i]);
+ }
+#endif
+}
+static unsigned int skip_caslat(unsigned int tckmin_ps,
+ unsigned int taamin_ps,
+ unsigned int mclk_ps,
+ unsigned int package_3ds)
+{
+ int i, j, k;
+ struct cas {
+ const unsigned int tckmin_ps;
+ const unsigned int caslat[4];
+ };
+ struct speed {
+ const struct cas *cl;
+ const unsigned int taamin_ps[4];
+ };
+ const struct cas cl_3200[] = {
+ {625, {0xa00000, 0xb00000, 0xf000000,} },
+ {750, { 0x20000, 0x60000, 0xe00000,} },
+ {833, { 0x8000, 0x18000, 0x38000,} },
+ {937, { 0x4000, 0x4000, 0xc000,} },
+ {1071, { 0x1000, 0x1000, 0x3000,} },
+ {1250, { 0x400, 0x400, 0xc00,} },
+ {1500, { 0, 0x600, 0x200,} },
+ };
+ const struct cas cl_2933[] = {
+ {682, { 0, 0x80000, 0x180000, 0x380000} },
+ {750, { 0x20000, 0x60000, 0x60000, 0xe0000} },
+ {833, { 0x8000, 0x18000, 0x18000, 0x38000} },
+ {937, { 0x4000, 0x4000, 0x4000, 0xc000} },
+ {1071, { 0x1000, 0x1000, 0x1000, 0x3000} },
+ {1250, { 0x400, 0x400, 0x400, 0xc00} },
+ {1500, { 0, 0x200, 0x200, 0x200} },
+ };
+ const struct cas cl_2666[] = {
+ {750, { 0, 0x20000, 0x60000, 0xe0000} },
+ {833, { 0x8000, 0x18000, 0x18000, 0x38000} },
+ {937, { 0x4000, 0x4000, 0x4000, 0xc000} },
+ {1071, { 0x1000, 0x1000, 0x1000, 0x3000} },
+ {1250, { 0x400, 0x400, 0x400, 0xc00} },
+ {1500, { 0, 0, 0x200, 0x200} },
+ };
+ const struct cas cl_2400[] = {
+ {833, { 0, 0x8000, 0x18000, 0x38000} },
+ {937, { 0xc000, 0x4000, 0x4000, 0xc000} },
+ {1071, { 0x3000, 0x1000, 0x1000, 0x3000} },
+ {1250, { 0xc00, 0x400, 0x400, 0xc00} },
+ {1500, { 0, 0x400, 0x200, 0x200} },
+ };
+ const struct cas cl_2133[] = {
+ {937, { 0, 0x4000, 0xc000,} },
+ {1071, { 0x2000, 0, 0x2000,} },
+ {1250, { 0x800, 0, 0x800,} },
+ {1500, { 0, 0x400, 0x200,} },
+ };
+ const struct cas cl_1866[] = {
+ {1071, { 0, 0x1000, 0x3000,} },
+ {1250, { 0xc00, 0x400, 0xc00,} },
+ {1500, { 0, 0x400, 0x200,} },
+ };
+ const struct cas cl_1600[] = {
+ {1250, { 0, 0x400, 0xc00,} },
+ {1500, { 0, 0x400, 0x200,} },
+ };
+ const struct speed bin_0[] = {
+ {cl_3200, {12500, 13750, 15000,} },
+ {cl_2933, {12960, 13640, 13750, 15000,} },
+ {cl_2666, {12750, 13500, 13750, 15000,} },
+ {cl_2400, {12500, 13320, 13750, 15000,} },
+ {cl_2133, {13130, 13500, 15000,} },
+ {cl_1866, {12850, 13500, 15000,} },
+ {cl_1600, {12500, 13500, 15000,} }
+ };
+ const struct cas cl_3200_3ds[] = {
+ {625, { 0xa000000, 0xb000000, 0xf000000,} },
+ {750, { 0xaa00000, 0xab00000, 0xef00000,} },
+ {833, { 0xaac0000, 0xaac0000, 0xebc0000,} },
+ {937, { 0xaab0000, 0xaab0000, 0xeaf0000,} },
+ {1071, { 0xaaa4000, 0xaaac000, 0xeaec000,} },
+ {1250, { 0xaaa0000, 0xaaa2000, 0xeaeb000,} },
+ };
+ const struct cas cl_2666_3ds[] = {
+ {750, { 0xa00000, 0xb00000, 0xf00000,} },
+ {833, { 0xac0000, 0xac0000, 0xbc0000,} },
+ {937, { 0xab0000, 0xab0000, 0xaf0000,} },
+ {1071, { 0xaa4000, 0xaac000, 0xaac000,} },
+ {1250, { 0xaa0000, 0xaaa000, 0xaaa000,} },
+ };
+ const struct cas cl_2400_3ds[] = {
+ {833, { 0xe00000, 0xe40000, 0xec0000, 0xb00000} },
+ {937, { 0xe00000, 0xe00000, 0xea0000, 0xae0000} },
+ {1071, { 0xe00000, 0xe04000, 0xeac000, 0xaec000} },
+ {1250, { 0xe00000, 0xe00000, 0xeaa000, 0xae2000} },
+ };
+ const struct cas cl_2133_3ds[] = {
+ {937, { 0x90000, 0xb0000, 0xf0000,} },
+ {1071, { 0x84000, 0xac000, 0xec000,} },
+ {1250, { 0x80000, 0xa2000, 0xe2000,} },
+ };
+ const struct cas cl_1866_3ds[] = {
+ {1071, { 0, 0x4000, 0xc000,} },
+ {1250, { 0, 0x1000, 0x3000,} },
+ };
+ const struct cas cl_1600_3ds[] = {
+ {1250, { 0, 0x1000, 0x3000,} },
+ };
+ const struct speed bin_3ds[] = {
+ {cl_3200_3ds, {15000, 16250, 17140,} },
+ {cl_2666_3ds, {15000, 16500, 17140,} },
+ {cl_2400_3ds, {15000, 15830, 16670, 17140} },
+ {cl_2133_3ds, {15950, 16880, 17140,} },
+ {cl_1866_3ds, {15000, 16070, 17140,} },
+ {cl_1600_3ds, {15000, 16250, 17500,} },
+ };
+ const struct speed *bin;
+ int size;
+ unsigned int taamin_max, tck_max;
+
+ if (taamin_ps > ((package_3ds != 0) ? 21500 : 18000)) {
+ ERROR("taamin_ps %u invalid\n", taamin_ps);
+ return 0;
+ }
+ if (package_3ds != 0) {
+ bin = bin_3ds;
+ size = ARRAY_SIZE(bin_3ds);
+ taamin_max = 1250;
+ tck_max = 1500;
+ } else {
+ bin = bin_0;
+ size = ARRAY_SIZE(bin_0);
+ taamin_max = 1500;
+ tck_max = 1600;
+ }
+ if (mclk_ps < 625 || mclk_ps > tck_max) {
+ ERROR("mclk %u invalid\n", mclk_ps);
+ return 0;
+ }
+
+ for (i = 0; i < size; i++) {
+ if (bin[i].cl[0].tckmin_ps >= tckmin_ps) {
+ break;
+ }
+ }
+ if (i >= size) {
+ ERROR("speed bin not found\n");
+ return 0;
+ }
+ if (bin[i].cl[0].tckmin_ps > tckmin_ps && i > 0) {
+ i--;
+ }
+
+ for (j = 0; j < 4; j++) {
+ if ((bin[i].taamin_ps[j] == 0) ||
+ bin[i].taamin_ps[j] >= taamin_ps) {
+ break;
+ }
+ }
+
+ if (j >= 4) {
+ ERROR("taamin_ps out of range.\n");
+ return 0;
+ }
+
+ if ((bin[i].taamin_ps[j] == 0) ||
+ (bin[i].taamin_ps[j] > taamin_ps && j > 0)) {
+ j--;
+ }
+
+ for (k = 0; bin[i].cl[k].tckmin_ps < mclk_ps &&
+ bin[i].cl[k].tckmin_ps < taamin_max; k++)
+ ;
+ if (bin[i].cl[k].tckmin_ps > mclk_ps && k > 0) {
+ k--;
+ }
+
+ debug("Skip CL mask for this speed 0x%x\n", bin[i].cl[k].caslat[j]);
+
+ return bin[i].cl[k].caslat[j];
+}
+
+int compute_ddrc(const unsigned long clk,
+ const struct memctl_opt *popts,
+ const struct ddr_conf *conf,
+ struct ddr_cfg_regs *regs,
+ const struct dimm_params *pdimm,
+ unsigned int ip_rev)
+{
+ unsigned int cas_latency;
+ unsigned int caslat_skip;
+ unsigned int additive_latency;
+ const unsigned int mclk_ps = get_memory_clk_ps(clk);
+ int i;
+
+ zeromem(regs, sizeof(struct ddr_cfg_regs));
+
+ if (mclk_ps < pdimm->tckmin_x_ps) {
+ ERROR("DDR Clk: MCLK cycle is %u ps.\n", mclk_ps);
+ ERROR("DDR Clk is faster than DIMM can support.\n");
+ }
+
+ /* calculate cas latency, override first */
+ cas_latency = (popts->caslat_override != 0) ?
+ popts->caslat_override_value :
+ (pdimm->taa_ps + mclk_ps - 1) / mclk_ps;
+
+ /* skip unsupported caslat based on speed bin */
+ caslat_skip = skip_caslat(pdimm->tckmin_x_ps,
+ pdimm->taa_ps,
+ mclk_ps,
+ pdimm->package_3ds);
+ debug("Skip caslat 0x%x\n", caslat_skip);
+
+ /* Check if DIMM supports the cas latency */
+ i = 24;
+ while (((pdimm->caslat_x & ~caslat_skip & (1 << cas_latency)) == 0) &&
+ (i-- > 0)) {
+ cas_latency++;
+ }
+
+ if (i <= 0) {
+ ERROR("Failed to find a proper cas latency\n");
+ return -EINVAL;
+ }
+ /* Verify cas latency does not exceed 18ns for DDR4 */
+ if (cas_latency * mclk_ps > 18000) {
+ ERROR("cas latency is too large %d\n", cas_latency);
+ return -EINVAL;
+ }
+
+ additive_latency = (popts->addt_lat_override != 0) ?
+ popts->addt_lat_override_value : 0;
+
+ cal_ddr_csn_bnds(regs, popts, conf, pdimm);
+ cal_ddr_sdram_cfg(clk, regs, popts, pdimm, ip_rev);
+ cal_ddr_sdram_rcw(clk, regs, popts, pdimm);
+ cal_timing_cfg(clk, regs, popts, pdimm, conf, cas_latency,
+ additive_latency);
+ cal_ddr_dq_mapping(regs, pdimm);
+
+ if (ip_rev >= 0x50500) {
+ cal_ddr_addr_dec(regs);
+ }
+
+ cal_ddr_sdram_mode(clk, regs, popts, conf, pdimm, cas_latency,
+ additive_latency, ip_rev);
+ cal_ddr_eor(regs, popts);
+ cal_ddr_data_init(regs);
+ cal_ddr_sdram_interval(clk, regs, popts, pdimm);
+ cal_ddr_zq_cntl(regs);
+ cal_ddr_sr_cntr(regs, popts);
+
+ return 0;
+}
diff --git a/drivers/nxp/ddr/nxp-ddr/utility.c b/drivers/nxp/ddr/nxp-ddr/utility.c
new file mode 100644
index 0000000..b6dffc8
--- /dev/null
+++ b/drivers/nxp/ddr/nxp-ddr/utility.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2021-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <common/debug.h>
+#include <ddr.h>
+#include <immap.h>
+#include <lib/mmio.h>
+
+#define UL_5POW12 244140625UL
+#define ULL_2E12 2000000000000ULL
+#define UL_2POW13 (1UL << 13)
+#define ULL_8FS 0xFFFFFFFFULL
+
+#define do_div(n, base) ({ \
+ unsigned int __base = (base); \
+ unsigned int __rem; \
+ __rem = ((unsigned long long)(n)) % __base; \
+ (n) = ((unsigned long long)(n)) / __base; \
+ __rem; \
+})
+
+#define CCN_HN_F_SAM_NODEID_MASK 0x7f
+#ifdef NXP_HAS_CCN504
+#define CCN_HN_F_SAM_NODEID_DDR0 0x4
+#define CCN_HN_F_SAM_NODEID_DDR1 0xe
+#elif defined(NXP_HAS_CCN508)
+#define CCN_HN_F_SAM_NODEID_DDR0_0 0x3
+#define CCN_HN_F_SAM_NODEID_DDR0_1 0x8
+#define CCN_HN_F_SAM_NODEID_DDR1_0 0x13
+#define CCN_HN_F_SAM_NODEID_DDR1_1 0x18
+#endif
+
+unsigned long get_ddr_freq(struct sysinfo *sys, int ctrl_num)
+{
+ if (sys->freq_ddr_pll0 == 0) {
+ get_clocks(sys);
+ }
+
+ switch (ctrl_num) {
+ case 0:
+ return sys->freq_ddr_pll0;
+ case 1:
+ return sys->freq_ddr_pll0;
+ case 2:
+ return sys->freq_ddr_pll1;
+ }
+
+ return 0;
+}
+
+unsigned int get_memory_clk_ps(const unsigned long data_rate)
+{
+ unsigned int result;
+ /* Round to nearest 10ps, being careful about 64-bit multiply/divide */
+ unsigned long long rem, mclk_ps = ULL_2E12;
+
+ /* Now perform the big divide, the result fits in 32-bits */
+ rem = do_div(mclk_ps, data_rate);
+ result = (rem >= (data_rate >> 1)) ? mclk_ps + 1 : mclk_ps;
+
+ return result;
+}
+
+unsigned int picos_to_mclk(unsigned long data_rate, unsigned int picos)
+{
+ unsigned long long clks, clks_rem;
+
+ /* Short circuit for zero picos */
+ if ((picos == 0U) || (data_rate == 0UL)) {
+ return 0U;
+ }
+
+ /* First multiply the time by the data rate (32x32 => 64) */
+ clks = picos * (unsigned long long)data_rate;
+ /*
+ * Now divide by 5^12 and track the 32-bit remainder, then divide
+ * by 2*(2^12) using shifts (and updating the remainder).
+ */
+ clks_rem = do_div(clks, UL_5POW12);
+ clks_rem += (clks & (UL_2POW13-1)) * UL_5POW12;
+ clks >>= 13U;
+
+ /* If we had a remainder greater than the 1ps error, then round up */
+ if (clks_rem > data_rate) {
+ clks++;
+ }
+
+ /* Clamp to the maximum representable value */
+ if (clks > ULL_8FS) {
+ clks = ULL_8FS;
+ }
+ return (unsigned int) clks;
+}
+
+/* valid_spd_mask has been checked by parse_spd */
+int disable_unused_ddrc(struct ddr_info *priv,
+ int valid_spd_mask, uintptr_t nxp_ccn_hn_f0_addr)
+{
+#if defined(NXP_HAS_CCN504) || defined(NXP_HAS_CCN508)
+ void *hnf_sam_ctrl = (void *)(nxp_ccn_hn_f0_addr + CCN_HN_F_SAM_CTL);
+ uint32_t val, nodeid;
+#ifdef NXP_HAS_CCN504
+ uint32_t num_hnf_nodes = 4U;
+#else
+ uint32_t num_hnf_nodes = 8U;
+#endif
+ int disable_ddrc = 0;
+ int i;
+
+ if (priv->num_ctlrs < 2) {
+ debug("%s: nothing to do.\n", __func__);
+ }
+
+ switch (priv->dimm_on_ctlr) {
+ case 1:
+ disable_ddrc = ((valid_spd_mask &0x2) == 0) ? 2 : 0;
+ disable_ddrc = ((valid_spd_mask &0x1) == 0) ? 1 : disable_ddrc;
+ break;
+ case 2:
+ disable_ddrc = ((valid_spd_mask &0x4) == 0) ? 2 : 0;
+ disable_ddrc = ((valid_spd_mask &0x1) == 0) ? 1 : disable_ddrc;
+ break;
+ default:
+ ERROR("Invalid number of DIMMs %d\n", priv->dimm_on_ctlr);
+ return -EINVAL;
+ }
+
+ if (disable_ddrc != 0) {
+ debug("valid_spd_mask = 0x%x\n", valid_spd_mask);
+ }
+
+ switch (disable_ddrc) {
+ case 1:
+ priv->num_ctlrs = 1;
+ priv->spd_addr = &priv->spd_addr[priv->dimm_on_ctlr];
+ priv->ddr[0] = priv->ddr[1];
+ priv->ddr[1] = NULL;
+ priv->phy[0] = priv->phy[0];
+ priv->phy[1] = NULL;
+ debug("Disable first DDR controller\n");
+ break;
+ case 2:
+ priv->num_ctlrs = 1;
+ priv->ddr[1] = NULL;
+ priv->phy[1] = NULL;
+ debug("Disable second DDR controller\n");
+ /* fallthrough */
+ case 0:
+ break;
+ default:
+ ERROR("Program error.\n");
+ return -EINVAL;
+ }
+
+ if (disable_ddrc == 0) {
+ debug("Both controllers in use.\n");
+ return 0;
+ }
+
+ for (i = 0; i < num_hnf_nodes; i++) {
+ val = mmio_read_64((uintptr_t)hnf_sam_ctrl);
+#ifdef NXP_HAS_CCN504
+ nodeid = disable_ddrc == 1 ? CCN_HN_F_SAM_NODEID_DDR1 :
+ (disable_ddrc == 2 ? CCN_HN_F_SAM_NODEID_DDR0 :
+ 0x0); /*Failure condition. never hit */
+#elif defined(NXP_HAS_CCN508)
+ if (disable_ddrc == 1) {
+ nodeid = (i < 2 || i >= 6) ? CCN_HN_F_SAM_NODEID_DDR1_1 :
+ CCN_HN_F_SAM_NODEID_DDR1_0;
+ } else if (disable_ddrc == 2) {
+ nodeid = (i < 2 || i >= 6) ? CCN_HN_F_SAM_NODEID_DDR0_0 :
+ CCN_HN_F_SAM_NODEID_DDR0_1;
+ } else {
+ nodeid = 0; /* Failure condition. never hit */
+ }
+#endif
+ if (nodeid != (val & CCN_HN_F_SAM_NODEID_MASK)) {
+ debug("Setting HN-F node %d\n", i);
+ debug("nodeid = 0x%x\n", nodeid);
+ val &= ~CCN_HN_F_SAM_NODEID_MASK;
+ val |= nodeid;
+ mmio_write_64((uintptr_t)hnf_sam_ctrl, val);
+ }
+ hnf_sam_ctrl += CCN_HN_F_REGION_SIZE;
+ }
+#endif
+ return 0;
+}
+
+unsigned int get_ddrc_version(const struct ccsr_ddr *ddr)
+{
+ unsigned int ver;
+
+ ver = (ddr_in32(&ddr->ip_rev1) & 0xFFFF) << 8U;
+ ver |= (ddr_in32(&ddr->ip_rev2) & 0xFF00) >> 8U;
+
+ return ver;
+}
+
+void print_ddr_info(struct ccsr_ddr *ddr)
+{
+ unsigned int cs0_config = ddr_in32(&ddr->csn_cfg[0]);
+ unsigned int sdram_cfg = ddr_in32(&ddr->sdram_cfg);
+ int cas_lat;
+
+ if ((sdram_cfg & SDRAM_CFG_MEM_EN) == 0U) {
+ printf(" (DDR not enabled)\n");
+ return;
+ }
+
+ printf("DDR");
+ switch ((sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK) >>
+ SDRAM_CFG_SDRAM_TYPE_SHIFT) {
+ case SDRAM_TYPE_DDR4:
+ printf("4");
+ break;
+ default:
+ printf("?");
+ break;
+ }
+
+ switch (sdram_cfg & SDRAM_CFG_DBW_MASK) {
+ case SDRAM_CFG_32_BW:
+ printf(", 32-bit");
+ break;
+ case SDRAM_CFG_16_BW:
+ printf(", 16-bit");
+ break;
+ case SDRAM_CFG_8_BW:
+ printf(", 8-bit");
+ break;
+ default:
+ printf(", 64-bit");
+ break;
+ }
+
+ /* Calculate CAS latency based on timing cfg values */
+ cas_lat = ((ddr_in32(&ddr->timing_cfg_1) >> 16) & 0xf);
+ cas_lat += 2; /* for DDRC newer than 4.4 */
+ cas_lat += ((ddr_in32(&ddr->timing_cfg_3) >> 12) & 3) << 4;
+ printf(", CL=%d", cas_lat >> 1);
+ if ((cas_lat & 0x1) != 0) {
+ printf(".5");
+ }
+
+ if ((sdram_cfg & SDRAM_CFG_ECC_EN) != 0) {
+ printf(", ECC on");
+ } else {
+ printf(", ECC off");
+ }
+
+ if ((cs0_config & 0x20000000) != 0) {
+ printf(", ");
+ switch ((cs0_config >> 24) & 0xf) {
+ case DDR_256B_INTLV:
+ printf("256B");
+ break;
+ default:
+ printf("invalid");
+ break;
+ }
+ }
+
+ if (((sdram_cfg >> 8) & 0x7f) != 0) {
+ printf(", ");
+ switch (sdram_cfg >> 8 & 0x7f) {
+ case DDR_BA_INTLV_CS0123:
+ printf("CS0+CS1+CS2+CS3");
+ break;
+ case DDR_BA_INTLV_CS01:
+ printf("CS0+CS1");
+ break;
+ default:
+ printf("invalid");
+ break;
+ }
+ }
+ printf("\n");
+}
diff --git a/drivers/nxp/ddr/phy-gen1/phy.c b/drivers/nxp/ddr/phy-gen1/phy.c
new file mode 100644
index 0000000..4b66d38
--- /dev/null
+++ b/drivers/nxp/ddr/phy-gen1/phy.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <common/debug.h>
+#include <ddr.h>
+
+static void cal_ddr_sdram_clk_cntl(struct ddr_cfg_regs *regs,
+ const struct memctl_opt *popts)
+{
+ const unsigned int clk_adj = popts->clk_adj;
+ const unsigned int ss_en = 0U;
+
+ regs->clk_cntl = ((ss_en & U(0x1)) << 31U) |
+ ((clk_adj & U(0x1F)) << 22U);
+ debug("clk_cntl = 0x%x\n", regs->clk_cntl);
+}
+
+static void cal_ddr_cdr(struct ddr_cfg_regs *regs,
+ const struct memctl_opt *popts)
+{
+ regs->cdr[0] = popts->ddr_cdr1;
+ regs->cdr[1] = popts->ddr_cdr2;
+ debug("cdr[0] = 0x%x\n", regs->cdr[0]);
+ debug("cdr[1] = 0x%x\n", regs->cdr[1]);
+}
+
+static void cal_ddr_wrlvl_cntl(struct ddr_cfg_regs *regs,
+ const struct memctl_opt *popts)
+{
+ const unsigned int wrlvl_en = 1U; /* enabled */
+ const unsigned int wrlvl_mrd = U(0x6); /* > 40nCK */
+ const unsigned int wrlvl_odten = U(0x7); /* 128 */
+ const unsigned int wrlvl_dqsen = U(0x5); /* > 25nCK */
+ const unsigned int wrlvl_wlr = U(0x6); /* > tWLO + 6 */
+ const unsigned int wrlvl_smpl = popts->wrlvl_override ?
+ popts->wrlvl_sample : U(0xf);
+ const unsigned int wrlvl_start = popts->wrlvl_start;
+
+ regs->wrlvl_cntl[0] = ((wrlvl_en & U(0x1)) << 31U) |
+ ((wrlvl_mrd & U(0x7)) << 24U) |
+ ((wrlvl_odten & U(0x7)) << 20U) |
+ ((wrlvl_dqsen & U(0x7)) << 16U) |
+ ((wrlvl_smpl & U(0xf)) << 12U) |
+ ((wrlvl_wlr & U(0x7)) << 8U) |
+ ((wrlvl_start & U(0x1F)) << 0U);
+ regs->wrlvl_cntl[1] = popts->wrlvl_ctl_2;
+ regs->wrlvl_cntl[2] = popts->wrlvl_ctl_3;
+ debug("wrlvl_cntl[0] = 0x%x\n", regs->wrlvl_cntl[0]);
+ debug("wrlvl_cntl[1] = 0x%x\n", regs->wrlvl_cntl[1]);
+ debug("wrlvl_cntl[2] = 0x%x\n", regs->wrlvl_cntl[2]);
+
+}
+
+static void cal_ddr_dbg(struct ddr_cfg_regs *regs,
+ const struct memctl_opt *popts)
+{
+ if (popts->cswl_override != 0) {
+ regs->debug[18] = popts->cswl_override;
+ }
+
+#ifdef CONFIG_SYS_FSL_DDR_EMU
+ /* disable DDR training for emulator */
+ regs->debug[2] = U(0x00000400);
+ regs->debug[4] = U(0xff800800);
+ regs->debug[5] = U(0x08000800);
+ regs->debug[6] = U(0x08000800);
+ regs->debug[7] = U(0x08000800);
+ regs->debug[8] = U(0x08000800);
+#endif
+ if (popts->cpo_sample != 0U) {
+ regs->debug[28] = popts->cpo_sample;
+ debug("debug[28] = 0x%x\n", regs->debug[28]);
+ }
+}
+
+int compute_ddr_phy(struct ddr_info *priv)
+{
+ const struct memctl_opt *popts = &priv->opt;
+ struct ddr_cfg_regs *regs = &priv->ddr_reg;
+
+ cal_ddr_sdram_clk_cntl(regs, popts);
+ cal_ddr_cdr(regs, popts);
+ cal_ddr_wrlvl_cntl(regs, popts);
+ cal_ddr_dbg(regs, popts);
+
+ return 0;
+}
diff --git a/drivers/nxp/ddr/phy-gen2/csr.h b/drivers/nxp/ddr/phy-gen2/csr.h
new file mode 100644
index 0000000..ee7b4d8
--- /dev/null
+++ b/drivers/nxp/ddr/phy-gen2/csr.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2021 NXP
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef CSR_H
+#define CSR_H
+
+#define t_anib 0
+#define t_dbyte 0x10000
+#define t_master 0x20000
+#define t_acsm 0x40000
+#define t_initeng 0x90000
+#define t_drtub 0xc0000
+#define t_apbonly 0xd0000
+#define csr_dbyte_misc_mode_addr 0x00
+#define csr_micro_cont_mux_sel_addr 0x00
+#define csr_uct_shadow_regs 0x04
+#define csr_cal_uclk_info_addr 0x08
+#define csr_seq0bdly0_addr 0x0b
+#define csr_seq0bdly1_addr 0x0c
+#define csr_seq0bdly2_addr 0x0d
+#define csr_seq0bdly3_addr 0x0e
+#define csr_seq0bdisable_flag0_addr 0x0c
+#define csr_seq0bdisable_flag1_addr 0x0d
+#define csr_seq0bdisable_flag2_addr 0x0e
+#define csr_seq0bdisable_flag3_addr 0x0f
+#define csr_seq0bdisable_flag4_addr 0x10
+#define csr_seq0bdisable_flag5_addr 0x11
+#define csr_seq0bdisable_flag6_addr 0x12
+#define csr_seq0bdisable_flag7_addr 0x13
+#define csr_dfi_mode_addr 0x18
+#define csr_tristate_mode_ca_addr 0x19
+#define csr_dfiphyupd_addr 0x21
+#define csr_dqs_preamble_control_addr 0x24
+#define csr_master_x4config_addr 0x25
+#define csr_enable_cs_multicast_addr 0x27
+#define csr_acx4_anib_dis_addr 0x2c
+#define csr_dmipin_present_addr 0x2d
+#define csr_ard_ptr_init_val_addr 0x2e
+#define csr_dct_write_prot 0x31
+#define csr_uct_write_only_shadow 0x32
+#define csr_uct_write_prot 0x33
+#define csr_uct_dat_write_only_shadow 0x34
+#define csr_dbyte_dll_mode_cntrl_addr 0x3a
+#define csr_atx_impedance_addr 0x43
+#define csr_dq_dqs_rcv_cntrl_addr 0x43
+#define csr_cal_offsets_addr 0x45
+#define csr_tx_impedance_ctrl1_addr 0x49
+#define csr_dq_dqs_rcv_cntrl1_addr 0x4a
+#define csr_tx_odt_drv_stren_addr 0x4d
+#define csr_cal_drv_str0_addr 0x50
+#define csr_atx_slew_rate_addr 0x55
+#define csr_proc_odt_time_ctl_addr 0x56
+#define csr_mem_alert_control_addr 0x5b
+#define csr_mem_alert_control2_addr 0x5c
+#define csr_tx_slew_rate_addr 0x5f
+#define csr_mem_reset_l_addr 0x60
+#define csr_dfi_camode_addr 0x75
+#define csr_dll_gain_ctl_addr 0x7c
+#define csr_dll_lockparam_addr 0x7d
+#define csr_ucclk_hclk_enables_addr 0x80
+#define csr_acsm_playback0x0_addr 0x80
+#define csr_acsm_playback1x0_addr 0x81
+#define csr_cal_rate_addr 0x88
+#define csr_cal_zap_addr 0x89
+#define csr_cal_misc2_addr 0x98
+#define csr_micro_reset_addr 0x99
+#define csr_dfi_rd_data_cs_dest_map_addr 0xb0
+#define csr_vref_in_global_addr 0xb2
+#define csr_dfi_wr_data_cs_dest_map_addr 0xb4
+#define csr_pll_pwr_dn_addr 0xc3
+#define csr_pll_ctrl2_addr 0xc5
+#define csr_pll_ctrl1_addr 0xc7
+#define csr_pll_test_mode_addr 0xca
+#define csr_pll_ctrl4_addr 0xcc
+#define csr_dfi_freq_xlat0_addr 0xf0
+#define csr_acsm_ctrl0_addr 0xf0
+#define csr_dfi_freq_ratio_addr 0xfa
+#define csr_acsm_ctrl13_addr 0xfd
+#define csr_tx_pre_drv_mode_lsb 8
+#define csr_tx_pre_n_lsb 4
+#define csr_tx_pre_p_lsb 0
+#define csr_atx_pre_drv_mode_lsb 8
+#define csr_atx_pre_n_lsb 4
+#define csr_atx_pre_p_lsb 0
+#define csr_wdqsextension_lsb 8
+#define csr_lp4sttc_pre_bridge_rx_en_lsb 7
+#define csr_lp4postamble_ext_lsb 6
+#define csr_lp4tgl_two_tck_tx_dqs_pre_lsb 5
+#define csr_position_dfe_init_lsb 2
+#define csr_two_tck_tx_dqs_pre_lsb 1
+#define csr_two_tck_rx_dqs_pre_lsb 0
+#define csr_dll_rx_preamble_mode_lsb 1
+#define csr_odtstren_n_lsb 6
+#define csr_drv_stren_fsdq_n_lsb 6
+#define csr_drv_stren_fsdq_p_lsb 0
+#define csr_adrv_stren_n_lsb 5
+#define csr_adrv_stren_p_lsb 0
+#define csr_cal_drv_str_pu50_lsb 4
+#define csr_cal_once_lsb 5
+#define csr_cal_interval_lsb 0
+#define csr_cal_run_lsb 4
+#define csr_global_vref_in_dac_lsb 3
+#define csr_gain_curr_adj_lsb 7
+#define csr_major_mode_dbyte_lsb 4
+#define csr_dfe_ctrl_lsb 2
+#define csr_ext_vref_range_lsb 1
+#define csr_sel_analog_vref_lsb 0
+#define csr_malertsync_bypass_lsb 0
+#define csr_ck_dis_val_lsb 2
+#define csr_ddr2tmode_lsb 1
+#define csr_dis_dyn_adr_tri_lsb 0
+#define csr_dbyte_disable_lsb 2
+#define csr_power_down_rcvr_lsb 0
+#define csr_power_down_rcvr_dqs_lsb 9
+#define csr_rx_pad_standby_en_lsb 10
+#define csr_rx_pad_standby_en_mask 0x400
+#define csr_x4tg_lsb 0
+#define csr_reset_to_micro_mask 0x8
+#define csr_protect_mem_reset_mask 0x2
+#define csr_stall_to_micro_mask 0x1
+#define uct_write_prot_shadow_mask 0x1
+#define csr_acsm_par_mode_mask 0x4000
+#define csr_acsm_cke_enb_lsb 0
+#define csr_dfiphyupd_threshold_lsb 8
+#define csr_dfiphyupd_threshold_msb 11
+#define csr_dfiphyupd_threshold_mask 0xf00
+#define csr_dfi_rd_destm0_lsb 0
+#define csr_dfi_rd_destm1_lsb 2
+#define csr_dfi_rd_destm2_lsb 4
+#define csr_dfi_rd_destm3_lsb 6
+#define csr_dfi_wr_destm0_lsb 0
+#define csr_dfi_wr_destm1_lsb 2
+#define csr_dfi_wr_destm2_lsb 4
+#define csr_dfi_wr_destm3_lsb 6
+#define csr_acsm_2t_mode_mask 0x40
+#define csr_cal_misc2_err_dis 13
+#define csr_cal_offset_pdc_lsb 6
+#define csr_cal_offset_pdc_msb 9
+#define csr_cal_offset_pdc_mask 0xe0
+#define csr_cal_drv_pdth_mask 0x3c0
+
+
+struct impedance_mapping {
+ int ohm;
+ int code;
+};
+
+#endif
diff --git a/drivers/nxp/ddr/phy-gen2/ddr4fw.h b/drivers/nxp/ddr/phy-gen2/ddr4fw.h
new file mode 100644
index 0000000..f17f2e7
--- /dev/null
+++ b/drivers/nxp/ddr/phy-gen2/ddr4fw.h
@@ -0,0 +1,2897 @@
+/*
+ * Copyright 2021 NXP
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef DDR4FW
+#define DDR4FW
+
+#define PHY_GEN2_MAX_IMAGE_SIZE 32768
+#define PHY_GEN2_IMEM_ADDR 0x50000
+#define PHY_GEN2_DMEM_ADDR 0x54000
+
+struct ddr4u1d {
+ uint8_t reserved00;
+ uint8_t msg_misc;
+ uint16_t pmu_revision;
+ uint8_t pstate;
+ uint8_t pll_bypass_en;
+ uint16_t dramfreq;
+ uint8_t dfi_freq_ratio;
+ uint8_t bpznres_val;
+ uint8_t phy_odt_impedance;
+ uint8_t phy_drv_impedance;
+ uint8_t phy_vref;
+ uint8_t dram_type;
+ uint8_t disabled_dbyte;
+ uint8_t enabled_dqs;
+ uint8_t cs_present;
+ uint8_t cs_present_d0;
+ uint8_t cs_present_d1;
+ uint8_t addr_mirror;
+ uint8_t cs_test_fail;
+ uint8_t phy_cfg;
+ uint16_t sequence_ctrl;
+ uint8_t hdt_ctrl;
+ uint8_t reserved19[0x1B - 0x19];
+ uint8_t share2dvref_result;
+ uint8_t reserved1c[0x22 - 0x1c];
+ uint16_t phy_config_override;
+ uint8_t dfimrlmargin;
+ int8_t cdd_rr_3_2;
+ int8_t cdd_rr_3_1;
+ int8_t cdd_rr_3_0;
+ int8_t cdd_rr_2_3;
+ int8_t cdd_rr_2_1;
+ int8_t cdd_rr_2_0;
+ int8_t cdd_rr_1_3;
+ int8_t cdd_rr_1_2;
+ int8_t cdd_rr_1_0;
+ int8_t cdd_rr_0_3;
+ int8_t cdd_rr_0_2;
+ int8_t cdd_rr_0_1;
+ int8_t cdd_ww_3_2;
+ int8_t cdd_ww_3_1;
+ int8_t cdd_ww_3_0;
+ int8_t cdd_ww_2_3;
+ int8_t cdd_ww_2_1;
+ int8_t cdd_ww_2_0;
+ int8_t cdd_ww_1_3;
+ int8_t cdd_ww_1_2;
+ int8_t cdd_ww_1_0;
+ int8_t cdd_ww_0_3;
+ int8_t cdd_ww_0_2;
+ int8_t cdd_ww_0_1;
+ int8_t cdd_rw_3_3;
+ int8_t cdd_rw_3_2;
+ int8_t cdd_rw_3_1;
+ int8_t cdd_rw_3_0;
+ int8_t cdd_rw_2_3;
+ int8_t cdd_rw_2_2;
+ int8_t cdd_rw_2_1;
+ int8_t cdd_rw_2_0;
+ int8_t cdd_rw_1_3;
+ int8_t cdd_rw_1_2;
+ int8_t cdd_rw_1_1;
+ int8_t cdd_rw_1_0;
+ int8_t cdd_rw_0_3;
+ int8_t cdd_rw_0_2;
+ int8_t cdd_rw_0_1;
+ int8_t cdd_rw_0_0;
+ int8_t cdd_wr_3_3;
+ int8_t cdd_wr_3_2;
+ int8_t cdd_wr_3_1;
+ int8_t cdd_wr_3_0;
+ int8_t cdd_wr_2_3;
+ int8_t cdd_wr_2_2;
+ int8_t cdd_wr_2_1;
+ int8_t cdd_wr_2_0;
+ int8_t cdd_wr_1_3;
+ int8_t cdd_wr_1_2;
+ int8_t cdd_wr_1_1;
+ int8_t cdd_wr_1_0;
+ int8_t cdd_wr_0_3;
+ int8_t cdd_wr_0_2;
+ int8_t cdd_wr_0_1;
+ int8_t cdd_wr_0_0;
+ uint8_t reserved5d;
+ uint16_t mr0;
+ uint16_t mr1;
+ uint16_t mr2;
+ uint16_t mr3;
+ uint16_t mr4;
+ uint16_t mr5;
+ uint16_t mr6;
+ uint8_t x16present;
+ uint8_t cs_setup_gddec;
+ uint16_t rtt_nom_wr_park0;
+ uint16_t rtt_nom_wr_park1;
+ uint16_t rtt_nom_wr_park2;
+ uint16_t rtt_nom_wr_park3;
+ uint16_t rtt_nom_wr_park4;
+ uint16_t rtt_nom_wr_park5;
+ uint16_t rtt_nom_wr_park6;
+ uint16_t rtt_nom_wr_park7;
+ uint8_t acsm_odt_ctrl0;
+ uint8_t acsm_odt_ctrl1;
+ uint8_t acsm_odt_ctrl2;
+ uint8_t acsm_odt_ctrl3;
+ uint8_t acsm_odt_ctrl4;
+ uint8_t acsm_odt_ctrl5;
+ uint8_t acsm_odt_ctrl6;
+ uint8_t acsm_odt_ctrl7;
+ uint8_t vref_dq_r0nib0;
+ uint8_t vref_dq_r0nib1;
+ uint8_t vref_dq_r0nib2;
+ uint8_t vref_dq_r0nib3;
+ uint8_t vref_dq_r0nib4;
+ uint8_t vref_dq_r0nib5;
+ uint8_t vref_dq_r0nib6;
+ uint8_t vref_dq_r0nib7;
+ uint8_t vref_dq_r0nib8;
+ uint8_t vref_dq_r0nib9;
+ uint8_t vref_dq_r0nib10;
+ uint8_t vref_dq_r0nib11;
+ uint8_t vref_dq_r0nib12;
+ uint8_t vref_dq_r0nib13;
+ uint8_t vref_dq_r0nib14;
+ uint8_t vref_dq_r0nib15;
+ uint8_t vref_dq_r0nib16;
+ uint8_t vref_dq_r0nib17;
+ uint8_t vref_dq_r0nib18;
+ uint8_t vref_dq_r0nib19;
+ uint8_t vref_dq_r1nib0;
+ uint8_t vref_dq_r1nib1;
+ uint8_t vref_dq_r1nib2;
+ uint8_t vref_dq_r1nib3;
+ uint8_t vref_dq_r1nib4;
+ uint8_t vref_dq_r1nib5;
+ uint8_t vref_dq_r1nib6;
+ uint8_t vref_dq_r1nib7;
+ uint8_t vref_dq_r1nib8;
+ uint8_t vref_dq_r1nib9;
+ uint8_t vref_dq_r1nib10;
+ uint8_t vref_dq_r1nib11;
+ uint8_t vref_dq_r1nib12;
+ uint8_t vref_dq_r1nib13;
+ uint8_t vref_dq_r1nib14;
+ uint8_t vref_dq_r1nib15;
+ uint8_t vref_dq_r1nib16;
+ uint8_t vref_dq_r1nib17;
+ uint8_t vref_dq_r1nib18;
+ uint8_t vref_dq_r1nib19;
+ uint8_t vref_dq_r2nib0;
+ uint8_t vref_dq_r2nib1;
+ uint8_t vref_dq_r2nib2;
+ uint8_t vref_dq_r2nib3;
+ uint8_t vref_dq_r2nib4;
+ uint8_t vref_dq_r2nib5;
+ uint8_t vref_dq_r2nib6;
+ uint8_t vref_dq_r2nib7;
+ uint8_t vref_dq_r2nib8;
+ uint8_t vref_dq_r2nib9;
+ uint8_t vref_dq_r2nib10;
+ uint8_t vref_dq_r2nib11;
+ uint8_t vref_dq_r2nib12;
+ uint8_t vref_dq_r2nib13;
+ uint8_t vref_dq_r2nib14;
+ uint8_t vref_dq_r2nib15;
+ uint8_t vref_dq_r2nib16;
+ uint8_t vref_dq_r2nib17;
+ uint8_t vref_dq_r2nib18;
+ uint8_t vref_dq_r2nib19;
+ uint8_t vref_dq_r3nib0;
+ uint8_t vref_dq_r3nib1;
+ uint8_t vref_dq_r3nib2;
+ uint8_t vref_dq_r3nib3;
+ uint8_t vref_dq_r3nib4;
+ uint8_t vref_dq_r3nib5;
+ uint8_t vref_dq_r3nib6;
+ uint8_t vref_dq_r3nib7;
+ uint8_t vref_dq_r3nib8;
+ uint8_t vref_dq_r3nib9;
+ uint8_t vref_dq_r3nib10;
+ uint8_t vref_dq_r3nib11;
+ uint8_t vref_dq_r3nib12;
+ uint8_t vref_dq_r3nib13;
+ uint8_t vref_dq_r3nib14;
+ uint8_t vref_dq_r3nib15;
+ uint8_t vref_dq_r3nib16;
+ uint8_t vref_dq_r3nib17;
+ uint8_t vref_dq_r3nib18;
+ uint8_t vref_dq_r3nib19;
+ uint8_t reserved_d6[0x3f6 - 0xd6];
+ uint16_t alt_cas_l;
+ uint8_t alt_wcas_l;
+ uint8_t d4misc;
+} __packed;
+
+struct ddr4u2d {
+ uint8_t reserved00;
+ uint8_t msg_misc;
+ uint16_t pmu_revision;
+ uint8_t pstate;
+ uint8_t pll_bypass_en;
+ uint16_t dramfreq;
+ uint8_t dfi_freq_ratio;
+ uint8_t bpznres_val;
+ uint8_t phy_odt_impedance;
+ uint8_t phy_drv_impedance;
+ uint8_t phy_vref;
+ uint8_t dram_type;
+ uint8_t disabled_dbyte;
+ uint8_t enabled_dqs;
+ uint8_t cs_present;
+ uint8_t cs_present_d0;
+ uint8_t cs_present_d1;
+ uint8_t addr_mirror;
+ uint8_t cs_test_fail;
+ uint8_t phy_cfg;
+ uint16_t sequence_ctrl;
+ uint8_t hdt_ctrl;
+ uint8_t rx2d_train_opt;
+ uint8_t tx2d_train_opt;
+ uint8_t share2dvref_result;
+ uint8_t delay_weight2d;
+ uint8_t voltage_weight2d;
+ uint8_t reserved1e[0x22 - 0x1e];
+ uint16_t phy_config_override;
+ uint8_t dfimrlmargin;
+ uint8_t r0_rx_clk_dly_margin;
+ uint8_t r0_vref_dac_margin;
+ uint8_t r0_tx_dq_dly_margin;
+ uint8_t r0_device_vref_margin;
+ uint8_t reserved29[0x33 - 0x29];
+ uint8_t r1_rx_clk_dly_margin;
+ uint8_t r1_vref_dac_margin;
+ uint8_t r1_tx_dq_dly_margin;
+ uint8_t r1_device_vref_margin;
+ uint8_t reserved37[0x41 - 0x37];
+ uint8_t r2_rx_clk_dly_margin;
+ uint8_t r2_vref_dac_margin;
+ uint8_t r2_tx_dq_dly_margin;
+ uint8_t r2_device_vref_margin;
+ uint8_t reserved45[0x4f - 0x45];
+ uint8_t r3_rx_clk_dly_margin;
+ uint8_t r3_vref_dac_margin;
+ uint8_t r3_tx_dq_dly_margin;
+ uint8_t r3_device_vref_margin;
+ uint8_t reserved53[0x5e - 0x53];
+ uint16_t mr0;
+ uint16_t mr1;
+ uint16_t mr2;
+ uint16_t mr3;
+ uint16_t mr4;
+ uint16_t mr5;
+ uint16_t mr6;
+ uint8_t x16present;
+ uint8_t cs_setup_gddec;
+ uint16_t rtt_nom_wr_park0;
+ uint16_t rtt_nom_wr_park1;
+ uint16_t rtt_nom_wr_park2;
+ uint16_t rtt_nom_wr_park3;
+ uint16_t rtt_nom_wr_park4;
+ uint16_t rtt_nom_wr_park5;
+ uint16_t rtt_nom_wr_park6;
+ uint16_t rtt_nom_wr_park7;
+ uint8_t acsm_odt_ctrl0;
+ uint8_t acsm_odt_ctrl1;
+ uint8_t acsm_odt_ctrl2;
+ uint8_t acsm_odt_ctrl3;
+ uint8_t acsm_odt_ctrl4;
+ uint8_t acsm_odt_ctrl5;
+ uint8_t acsm_odt_ctrl6;
+ uint8_t acsm_odt_ctrl7;
+ uint8_t vref_dq_r0nib0;
+ uint8_t vref_dq_r0nib1;
+ uint8_t vref_dq_r0nib2;
+ uint8_t vref_dq_r0nib3;
+ uint8_t vref_dq_r0nib4;
+ uint8_t vref_dq_r0nib5;
+ uint8_t vref_dq_r0nib6;
+ uint8_t vref_dq_r0nib7;
+ uint8_t vref_dq_r0nib8;
+ uint8_t vref_dq_r0nib9;
+ uint8_t vref_dq_r0nib10;
+ uint8_t vref_dq_r0nib11;
+ uint8_t vref_dq_r0nib12;
+ uint8_t vref_dq_r0nib13;
+ uint8_t vref_dq_r0nib14;
+ uint8_t vref_dq_r0nib15;
+ uint8_t vref_dq_r0nib16;
+ uint8_t vref_dq_r0nib17;
+ uint8_t vref_dq_r0nib18;
+ uint8_t vref_dq_r0nib19;
+ uint8_t vref_dq_r1nib0;
+ uint8_t vref_dq_r1nib1;
+ uint8_t vref_dq_r1nib2;
+ uint8_t vref_dq_r1nib3;
+ uint8_t vref_dq_r1nib4;
+ uint8_t vref_dq_r1nib5;
+ uint8_t vref_dq_r1nib6;
+ uint8_t vref_dq_r1nib7;
+ uint8_t vref_dq_r1nib8;
+ uint8_t vref_dq_r1nib9;
+ uint8_t vref_dq_r1nib10;
+ uint8_t vref_dq_r1nib11;
+ uint8_t vref_dq_r1nib12;
+ uint8_t vref_dq_r1nib13;
+ uint8_t vref_dq_r1nib14;
+ uint8_t vref_dq_r1nib15;
+ uint8_t vref_dq_r1nib16;
+ uint8_t vref_dq_r1nib17;
+ uint8_t vref_dq_r1nib18;
+ uint8_t vref_dq_r1nib19;
+ uint8_t vref_dq_r2nib0;
+ uint8_t vref_dq_r2nib1;
+ uint8_t vref_dq_r2nib2;
+ uint8_t vref_dq_r2nib3;
+ uint8_t vref_dq_r2nib4;
+ uint8_t vref_dq_r2nib5;
+ uint8_t vref_dq_r2nib6;
+ uint8_t vref_dq_r2nib7;
+ uint8_t vref_dq_r2nib8;
+ uint8_t vref_dq_r2nib9;
+ uint8_t vref_dq_r2nib10;
+ uint8_t vref_dq_r2nib11;
+ uint8_t vref_dq_r2nib12;
+ uint8_t vref_dq_r2nib13;
+ uint8_t vref_dq_r2nib14;
+ uint8_t vref_dq_r2nib15;
+ uint8_t vref_dq_r2nib16;
+ uint8_t vref_dq_r2nib17;
+ uint8_t vref_dq_r2nib18;
+ uint8_t vref_dq_r2nib19;
+ uint8_t vref_dq_r3nib0;
+ uint8_t vref_dq_r3nib1;
+ uint8_t vref_dq_r3nib2;
+ uint8_t vref_dq_r3nib3;
+ uint8_t vref_dq_r3nib4;
+ uint8_t vref_dq_r3nib5;
+ uint8_t vref_dq_r3nib6;
+ uint8_t vref_dq_r3nib7;
+ uint8_t vref_dq_r3nib8;
+ uint8_t vref_dq_r3nib9;
+ uint8_t vref_dq_r3nib10;
+ uint8_t vref_dq_r3nib11;
+ uint8_t vref_dq_r3nib12;
+ uint8_t vref_dq_r3nib13;
+ uint8_t vref_dq_r3nib14;
+ uint8_t vref_dq_r3nib15;
+ uint8_t vref_dq_r3nib16;
+ uint8_t vref_dq_r3nib17;
+ uint8_t vref_dq_r3nib18;
+ uint8_t vref_dq_r3nib19;
+ uint8_t reserved_d6[0x3f6 - 0xd6];
+ uint16_t alt_cas_l;
+ uint8_t alt_wcas_l;
+ uint8_t d4misc;
+} __packed;
+
+struct ddr4r1d {
+ uint8_t reserved00;
+ uint8_t msg_misc;
+ uint16_t pmu_revision;
+ uint8_t pstate;
+ uint8_t pll_bypass_en;
+ uint16_t dramfreq;
+ uint8_t dfi_freq_ratio;
+ uint8_t bpznres_val;
+ uint8_t phy_odt_impedance;
+ uint8_t phy_drv_impedance;
+ uint8_t phy_vref;
+ uint8_t dram_type;
+ uint8_t disabled_dbyte;
+ uint8_t enabled_dqs;
+ uint8_t cs_present;
+ uint8_t cs_present_d0;
+ uint8_t cs_present_d1;
+ uint8_t addr_mirror;
+ uint8_t cs_test_fail;
+ uint8_t phy_cfg;
+ uint16_t sequence_ctrl;
+ uint8_t hdt_ctrl;
+ uint8_t reserved19[0x22 - 0x19];
+ uint16_t phy_config_override;
+ uint8_t dfimrlmargin;
+ int8_t cdd_rr_3_2;
+ int8_t cdd_rr_3_1;
+ int8_t cdd_rr_3_0;
+ int8_t cdd_rr_2_3;
+ int8_t cdd_rr_2_1;
+ int8_t cdd_rr_2_0;
+ int8_t cdd_rr_1_3;
+ int8_t cdd_rr_1_2;
+ int8_t cdd_rr_1_0;
+ int8_t cdd_rr_0_3;
+ int8_t cdd_rr_0_2;
+ int8_t cdd_rr_0_1;
+ int8_t cdd_ww_3_2;
+ int8_t cdd_ww_3_1;
+ int8_t cdd_ww_3_0;
+ int8_t cdd_ww_2_3;
+ int8_t cdd_ww_2_1;
+ int8_t cdd_ww_2_0;
+ int8_t cdd_ww_1_3;
+ int8_t cdd_ww_1_2;
+ int8_t cdd_ww_1_0;
+ int8_t cdd_ww_0_3;
+ int8_t cdd_ww_0_2;
+ int8_t cdd_ww_0_1;
+ int8_t cdd_rw_3_3;
+ int8_t cdd_rw_3_2;
+ int8_t cdd_rw_3_1;
+ int8_t cdd_rw_3_0;
+ int8_t cdd_rw_2_3;
+ int8_t cdd_rw_2_2;
+ int8_t cdd_rw_2_1;
+ int8_t cdd_rw_2_0;
+ int8_t cdd_rw_1_3;
+ int8_t cdd_rw_1_2;
+ int8_t cdd_rw_1_1;
+ int8_t cdd_rw_1_0;
+ int8_t cdd_rw_0_3;
+ int8_t cdd_rw_0_2;
+ int8_t cdd_rw_0_1;
+ int8_t cdd_rw_0_0;
+ int8_t cdd_wr_3_3;
+ int8_t cdd_wr_3_2;
+ int8_t cdd_wr_3_1;
+ int8_t cdd_wr_3_0;
+ int8_t cdd_wr_2_3;
+ int8_t cdd_wr_2_2;
+ int8_t cdd_wr_2_1;
+ int8_t cdd_wr_2_0;
+ int8_t cdd_wr_1_3;
+ int8_t cdd_wr_1_2;
+ int8_t cdd_wr_1_1;
+ int8_t cdd_wr_1_0;
+ int8_t cdd_wr_0_3;
+ int8_t cdd_wr_0_2;
+ int8_t cdd_wr_0_1;
+ int8_t cdd_wr_0_0;
+ uint8_t reserved5d;
+ uint16_t mr0;
+ uint16_t mr1;
+ uint16_t mr2;
+ uint16_t mr3;
+ uint16_t mr4;
+ uint16_t mr5;
+ uint16_t mr6;
+ uint8_t x16present;
+ uint8_t cs_setup_gddec;
+ uint16_t rtt_nom_wr_park0;
+ uint16_t rtt_nom_wr_park1;
+ uint16_t rtt_nom_wr_park2;
+ uint16_t rtt_nom_wr_park3;
+ uint16_t rtt_nom_wr_park4;
+ uint16_t rtt_nom_wr_park5;
+ uint16_t rtt_nom_wr_park6;
+ uint16_t rtt_nom_wr_park7;
+ uint8_t acsm_odt_ctrl0;
+ uint8_t acsm_odt_ctrl1;
+ uint8_t acsm_odt_ctrl2;
+ uint8_t acsm_odt_ctrl3;
+ uint8_t acsm_odt_ctrl4;
+ uint8_t acsm_odt_ctrl5;
+ uint8_t acsm_odt_ctrl6;
+ uint8_t acsm_odt_ctrl7;
+ uint8_t vref_dq_r0nib0;
+ uint8_t vref_dq_r0nib1;
+ uint8_t vref_dq_r0nib2;
+ uint8_t vref_dq_r0nib3;
+ uint8_t vref_dq_r0nib4;
+ uint8_t vref_dq_r0nib5;
+ uint8_t vref_dq_r0nib6;
+ uint8_t vref_dq_r0nib7;
+ uint8_t vref_dq_r0nib8;
+ uint8_t vref_dq_r0nib9;
+ uint8_t vref_dq_r0nib10;
+ uint8_t vref_dq_r0nib11;
+ uint8_t vref_dq_r0nib12;
+ uint8_t vref_dq_r0nib13;
+ uint8_t vref_dq_r0nib14;
+ uint8_t vref_dq_r0nib15;
+ uint8_t vref_dq_r0nib16;
+ uint8_t vref_dq_r0nib17;
+ uint8_t vref_dq_r0nib18;
+ uint8_t vref_dq_r0nib19;
+ uint8_t vref_dq_r1nib0;
+ uint8_t vref_dq_r1nib1;
+ uint8_t vref_dq_r1nib2;
+ uint8_t vref_dq_r1nib3;
+ uint8_t vref_dq_r1nib4;
+ uint8_t vref_dq_r1nib5;
+ uint8_t vref_dq_r1nib6;
+ uint8_t vref_dq_r1nib7;
+ uint8_t vref_dq_r1nib8;
+ uint8_t vref_dq_r1nib9;
+ uint8_t vref_dq_r1nib10;
+ uint8_t vref_dq_r1nib11;
+ uint8_t vref_dq_r1nib12;
+ uint8_t vref_dq_r1nib13;
+ uint8_t vref_dq_r1nib14;
+ uint8_t vref_dq_r1nib15;
+ uint8_t vref_dq_r1nib16;
+ uint8_t vref_dq_r1nib17;
+ uint8_t vref_dq_r1nib18;
+ uint8_t vref_dq_r1nib19;
+ uint8_t vref_dq_r2nib0;
+ uint8_t vref_dq_r2nib1;
+ uint8_t vref_dq_r2nib2;
+ uint8_t vref_dq_r2nib3;
+ uint8_t vref_dq_r2nib4;
+ uint8_t vref_dq_r2nib5;
+ uint8_t vref_dq_r2nib6;
+ uint8_t vref_dq_r2nib7;
+ uint8_t vref_dq_r2nib8;
+ uint8_t vref_dq_r2nib9;
+ uint8_t vref_dq_r2nib10;
+ uint8_t vref_dq_r2nib11;
+ uint8_t vref_dq_r2nib12;
+ uint8_t vref_dq_r2nib13;
+ uint8_t vref_dq_r2nib14;
+ uint8_t vref_dq_r2nib15;
+ uint8_t vref_dq_r2nib16;
+ uint8_t vref_dq_r2nib17;
+ uint8_t vref_dq_r2nib18;
+ uint8_t vref_dq_r2nib19;
+ uint8_t vref_dq_r3nib0;
+ uint8_t vref_dq_r3nib1;
+ uint8_t vref_dq_r3nib2;
+ uint8_t vref_dq_r3nib3;
+ uint8_t vref_dq_r3nib4;
+ uint8_t vref_dq_r3nib5;
+ uint8_t vref_dq_r3nib6;
+ uint8_t vref_dq_r3nib7;
+ uint8_t vref_dq_r3nib8;
+ uint8_t vref_dq_r3nib9;
+ uint8_t vref_dq_r3nib10;
+ uint8_t vref_dq_r3nib11;
+ uint8_t vref_dq_r3nib12;
+ uint8_t vref_dq_r3nib13;
+ uint8_t vref_dq_r3nib14;
+ uint8_t vref_dq_r3nib15;
+ uint8_t vref_dq_r3nib16;
+ uint8_t vref_dq_r3nib17;
+ uint8_t vref_dq_r3nib18;
+ uint8_t vref_dq_r3nib19;
+ uint8_t f0rc00_d0;
+ uint8_t f0rc01_d0;
+ uint8_t f0rc02_d0;
+ uint8_t f0rc03_d0;
+ uint8_t f0rc04_d0;
+ uint8_t f0rc05_d0;
+ uint8_t f0rc06_d0;
+ uint8_t f0rc07_d0;
+ uint8_t f0rc08_d0;
+ uint8_t f0rc09_d0;
+ uint8_t f0rc0a_d0;
+ uint8_t f0rc0b_d0;
+ uint8_t f0rc0c_d0;
+ uint8_t f0rc0d_d0;
+ uint8_t f0rc0e_d0;
+ uint8_t f0rc0f_d0;
+ uint8_t f0rc1x_d0;
+ uint8_t f0rc2x_d0;
+ uint8_t f0rc3x_d0;
+ uint8_t f0rc4x_d0;
+ uint8_t f0rc5x_d0;
+ uint8_t f0rc6x_d0;
+ uint8_t f0rc7x_d0;
+ uint8_t f0rc8x_d0;
+ uint8_t f0rc9x_d0;
+ uint8_t f0rcax_d0;
+ uint8_t f0rcbx_d0;
+ uint8_t f1rc00_d0;
+ uint8_t f1rc01_d0;
+ uint8_t f1rc02_d0;
+ uint8_t f1rc03_d0;
+ uint8_t f1rc04_d0;
+ uint8_t f1rc05_d0;
+ uint8_t f1rc06_d0;
+ uint8_t f1rc07_d0;
+ uint8_t f1rc08_d0;
+ uint8_t f1rc09_d0;
+ uint8_t f1rc0a_d0;
+ uint8_t f1rc0b_d0;
+ uint8_t f1rc0c_d0;
+ uint8_t f1rc0d_d0;
+ uint8_t f1rc0e_d0;
+ uint8_t f1rc0f_d0;
+ uint8_t f1rc1x_d0;
+ uint8_t f1rc2x_d0;
+ uint8_t f1rc3x_d0;
+ uint8_t f1rc4x_d0;
+ uint8_t f1rc5x_d0;
+ uint8_t f1rc6x_d0;
+ uint8_t f1rc7x_d0;
+ uint8_t f1rc8x_d0;
+ uint8_t f1rc9x_d0;
+ uint8_t f1rcax_d0;
+ uint8_t f1rcbx_d0;
+ uint8_t f0rc00_d1;
+ uint8_t f0rc01_d1;
+ uint8_t f0rc02_d1;
+ uint8_t f0rc03_d1;
+ uint8_t f0rc04_d1;
+ uint8_t f0rc05_d1;
+ uint8_t f0rc06_d1;
+ uint8_t f0rc07_d1;
+ uint8_t f0rc08_d1;
+ uint8_t f0rc09_d1;
+ uint8_t f0rc0a_d1;
+ uint8_t f0rc0b_d1;
+ uint8_t f0rc0c_d1;
+ uint8_t f0rc0d_d1;
+ uint8_t f0rc0e_d1;
+ uint8_t f0rc0f_d1;
+ uint8_t f0rc1x_d1;
+ uint8_t f0rc2x_d1;
+ uint8_t f0rc3x_d1;
+ uint8_t f0rc4x_d1;
+ uint8_t f0rc5x_d1;
+ uint8_t f0rc6x_d1;
+ uint8_t f0rc7x_d1;
+ uint8_t f0rc8x_d1;
+ uint8_t f0rc9x_d1;
+ uint8_t f0rcax_d1;
+ uint8_t f0rcbx_d1;
+ uint8_t f1rc00_d1;
+ uint8_t f1rc01_d1;
+ uint8_t f1rc02_d1;
+ uint8_t f1rc03_d1;
+ uint8_t f1rc04_d1;
+ uint8_t f1rc05_d1;
+ uint8_t f1rc06_d1;
+ uint8_t f1rc07_d1;
+ uint8_t f1rc08_d1;
+ uint8_t f1rc09_d1;
+ uint8_t f1rc0a_d1;
+ uint8_t f1rc0b_d1;
+ uint8_t f1rc0c_d1;
+ uint8_t f1rc0d_d1;
+ uint8_t f1rc0e_d1;
+ uint8_t f1rc0f_d1;
+ uint8_t f1rc1x_d1;
+ uint8_t f1rc2x_d1;
+ uint8_t f1rc3x_d1;
+ uint8_t f1rc4x_d1;
+ uint8_t f1rc5x_d1;
+ uint8_t f1rc6x_d1;
+ uint8_t f1rc7x_d1;
+ uint8_t f1rc8x_d1;
+ uint8_t f1rc9x_d1;
+ uint8_t f1rcax_d1;
+ uint8_t f1rcbx_d1;
+ uint8_t reserved142[0x3f6 - 0x142];
+ uint16_t alt_cas_l;
+ uint8_t alt_wcas_l;
+ uint8_t d4misc;
+} __packed;
+
+struct ddr4r2d {
+ uint8_t reserved00;
+ uint8_t msg_misc;
+ uint16_t pmu_revision;
+ uint8_t pstate;
+ uint8_t pll_bypass_en;
+ uint16_t dramfreq;
+ uint8_t dfi_freq_ratio;
+ uint8_t bpznres_val;
+ uint8_t phy_odt_impedance;
+ uint8_t phy_drv_impedance;
+ uint8_t phy_vref;
+ uint8_t dram_type;
+ uint8_t disabled_dbyte;
+ uint8_t enabled_dqs;
+ uint8_t cs_present;
+ uint8_t cs_present_d0;
+ uint8_t cs_present_d1;
+ uint8_t addr_mirror;
+ uint8_t cs_test_fail;
+ uint8_t phy_cfg;
+ uint16_t sequence_ctrl;
+ uint8_t hdt_ctrl;
+ uint8_t rx2d_train_opt;
+ uint8_t tx2d_train_opt;
+ uint8_t share2dvref_result;
+ uint8_t delay_weight2d;
+ uint8_t voltage_weight2d;
+ uint8_t reserved1e[0x22-0x1e];
+ uint16_t phy_config_override;
+ uint8_t dfimrlmargin;
+ uint8_t r0_rx_clk_dly_margin;
+ uint8_t r0_vref_dac_margin;
+ uint8_t r0_tx_dq_dly_margin;
+ uint8_t r0_device_vref_margin;
+ uint8_t reserved29[0x33-0x29];
+ uint8_t r1_rx_clk_dly_margin;
+ uint8_t r1_vref_dac_margin;
+ uint8_t r1_tx_dq_dly_margin;
+ uint8_t r1_device_vref_margin;
+ uint8_t reserved37[0x41-0x37];
+ uint8_t r2_rx_clk_dly_margin;
+ uint8_t r2_vref_dac_margin;
+ uint8_t r2_tx_dq_dly_margin;
+ uint8_t r2_device_vref_margin;
+ uint8_t reserved45[0x4f - 0x45];
+ uint8_t r3_rx_clk_dly_margin;
+ uint8_t r3_vref_dac_margin;
+ uint8_t r3_tx_dq_dly_margin;
+ uint8_t r3_device_vref_margin;
+ uint8_t reserved53[0x5e - 0x53];
+ uint16_t mr0;
+ uint16_t mr1;
+ uint16_t mr2;
+ uint16_t mr3;
+ uint16_t mr4;
+ uint16_t mr5;
+ uint16_t mr6;
+ uint8_t x16present;
+ uint8_t cs_setup_gddec;
+ uint16_t rtt_nom_wr_park0;
+ uint16_t rtt_nom_wr_park1;
+ uint16_t rtt_nom_wr_park2;
+ uint16_t rtt_nom_wr_park3;
+ uint16_t rtt_nom_wr_park4;
+ uint16_t rtt_nom_wr_park5;
+ uint16_t rtt_nom_wr_park6;
+ uint16_t rtt_nom_wr_park7;
+ uint8_t acsm_odt_ctrl0;
+ uint8_t acsm_odt_ctrl1;
+ uint8_t acsm_odt_ctrl2;
+ uint8_t acsm_odt_ctrl3;
+ uint8_t acsm_odt_ctrl4;
+ uint8_t acsm_odt_ctrl5;
+ uint8_t acsm_odt_ctrl6;
+ uint8_t acsm_odt_ctrl7;
+ uint8_t vref_dq_r0nib0;
+ uint8_t vref_dq_r0nib1;
+ uint8_t vref_dq_r0nib2;
+ uint8_t vref_dq_r0nib3;
+ uint8_t vref_dq_r0nib4;
+ uint8_t vref_dq_r0nib5;
+ uint8_t vref_dq_r0nib6;
+ uint8_t vref_dq_r0nib7;
+ uint8_t vref_dq_r0nib8;
+ uint8_t vref_dq_r0nib9;
+ uint8_t vref_dq_r0nib10;
+ uint8_t vref_dq_r0nib11;
+ uint8_t vref_dq_r0nib12;
+ uint8_t vref_dq_r0nib13;
+ uint8_t vref_dq_r0nib14;
+ uint8_t vref_dq_r0nib15;
+ uint8_t vref_dq_r0nib16;
+ uint8_t vref_dq_r0nib17;
+ uint8_t vref_dq_r0nib18;
+ uint8_t vref_dq_r0nib19;
+ uint8_t vref_dq_r1nib0;
+ uint8_t vref_dq_r1nib1;
+ uint8_t vref_dq_r1nib2;
+ uint8_t vref_dq_r1nib3;
+ uint8_t vref_dq_r1nib4;
+ uint8_t vref_dq_r1nib5;
+ uint8_t vref_dq_r1nib6;
+ uint8_t vref_dq_r1nib7;
+ uint8_t vref_dq_r1nib8;
+ uint8_t vref_dq_r1nib9;
+ uint8_t vref_dq_r1nib10;
+ uint8_t vref_dq_r1nib11;
+ uint8_t vref_dq_r1nib12;
+ uint8_t vref_dq_r1nib13;
+ uint8_t vref_dq_r1nib14;
+ uint8_t vref_dq_r1nib15;
+ uint8_t vref_dq_r1nib16;
+ uint8_t vref_dq_r1nib17;
+ uint8_t vref_dq_r1nib18;
+ uint8_t vref_dq_r1nib19;
+ uint8_t vref_dq_r2nib0;
+ uint8_t vref_dq_r2nib1;
+ uint8_t vref_dq_r2nib2;
+ uint8_t vref_dq_r2nib3;
+ uint8_t vref_dq_r2nib4;
+ uint8_t vref_dq_r2nib5;
+ uint8_t vref_dq_r2nib6;
+ uint8_t vref_dq_r2nib7;
+ uint8_t vref_dq_r2nib8;
+ uint8_t vref_dq_r2nib9;
+ uint8_t vref_dq_r2nib10;
+ uint8_t vref_dq_r2nib11;
+ uint8_t vref_dq_r2nib12;
+ uint8_t vref_dq_r2nib13;
+ uint8_t vref_dq_r2nib14;
+ uint8_t vref_dq_r2nib15;
+ uint8_t vref_dq_r2nib16;
+ uint8_t vref_dq_r2nib17;
+ uint8_t vref_dq_r2nib18;
+ uint8_t vref_dq_r2nib19;
+ uint8_t vref_dq_r3nib0;
+ uint8_t vref_dq_r3nib1;
+ uint8_t vref_dq_r3nib2;
+ uint8_t vref_dq_r3nib3;
+ uint8_t vref_dq_r3nib4;
+ uint8_t vref_dq_r3nib5;
+ uint8_t vref_dq_r3nib6;
+ uint8_t vref_dq_r3nib7;
+ uint8_t vref_dq_r3nib8;
+ uint8_t vref_dq_r3nib9;
+ uint8_t vref_dq_r3nib10;
+ uint8_t vref_dq_r3nib11;
+ uint8_t vref_dq_r3nib12;
+ uint8_t vref_dq_r3nib13;
+ uint8_t vref_dq_r3nib14;
+ uint8_t vref_dq_r3nib15;
+ uint8_t vref_dq_r3nib16;
+ uint8_t vref_dq_r3nib17;
+ uint8_t vref_dq_r3nib18;
+ uint8_t vref_dq_r3nib19;
+ uint8_t f0rc00_d0;
+ uint8_t f0rc01_d0;
+ uint8_t f0rc02_d0;
+ uint8_t f0rc03_d0;
+ uint8_t f0rc04_d0;
+ uint8_t f0rc05_d0;
+ uint8_t f0rc06_d0;
+ uint8_t f0rc07_d0;
+ uint8_t f0rc08_d0;
+ uint8_t f0rc09_d0;
+ uint8_t f0rc0a_d0;
+ uint8_t f0rc0b_d0;
+ uint8_t f0rc0c_d0;
+ uint8_t f0rc0d_d0;
+ uint8_t f0rc0e_d0;
+ uint8_t f0rc0f_d0;
+ uint8_t f0rc1x_d0;
+ uint8_t f0rc2x_d0;
+ uint8_t f0rc3x_d0;
+ uint8_t f0rc4x_d0;
+ uint8_t f0rc5x_d0;
+ uint8_t f0rc6x_d0;
+ uint8_t f0rc7x_d0;
+ uint8_t f0rc8x_d0;
+ uint8_t f0rc9x_d0;
+ uint8_t f0rcax_d0;
+ uint8_t f0rcbx_d0;
+ uint8_t f1rc00_d0;
+ uint8_t f1rc01_d0;
+ uint8_t f1rc02_d0;
+ uint8_t f1rc03_d0;
+ uint8_t f1rc04_d0;
+ uint8_t f1rc05_d0;
+ uint8_t f1rc06_d0;
+ uint8_t f1rc07_d0;
+ uint8_t f1rc08_d0;
+ uint8_t f1rc09_d0;
+ uint8_t f1rc0a_d0;
+ uint8_t f1rc0b_d0;
+ uint8_t f1rc0c_d0;
+ uint8_t f1rc0d_d0;
+ uint8_t f1rc0e_d0;
+ uint8_t f1rc0f_d0;
+ uint8_t f1rc1x_d0;
+ uint8_t f1rc2x_d0;
+ uint8_t f1rc3x_d0;
+ uint8_t f1rc4x_d0;
+ uint8_t f1rc5x_d0;
+ uint8_t f1rc6x_d0;
+ uint8_t f1rc7x_d0;
+ uint8_t f1rc8x_d0;
+ uint8_t f1rc9x_d0;
+ uint8_t f1rcax_d0;
+ uint8_t f1rcbx_d0;
+ uint8_t f0rc00_d1;
+ uint8_t f0rc01_d1;
+ uint8_t f0rc02_d1;
+ uint8_t f0rc03_d1;
+ uint8_t f0rc04_d1;
+ uint8_t f0rc05_d1;
+ uint8_t f0rc06_d1;
+ uint8_t f0rc07_d1;
+ uint8_t f0rc08_d1;
+ uint8_t f0rc09_d1;
+ uint8_t f0rc0a_d1;
+ uint8_t f0rc0b_d1;
+ uint8_t f0rc0c_d1;
+ uint8_t f0rc0d_d1;
+ uint8_t f0rc0e_d1;
+ uint8_t f0rc0f_d1;
+ uint8_t f0rc1x_d1;
+ uint8_t f0rc2x_d1;
+ uint8_t f0rc3x_d1;
+ uint8_t f0rc4x_d1;
+ uint8_t f0rc5x_d1;
+ uint8_t f0rc6x_d1;
+ uint8_t f0rc7x_d1;
+ uint8_t f0rc8x_d1;
+ uint8_t f0rc9x_d1;
+ uint8_t f0rcax_d1;
+ uint8_t f0rcbx_d1;
+ uint8_t f1rc00_d1;
+ uint8_t f1rc01_d1;
+ uint8_t f1rc02_d1;
+ uint8_t f1rc03_d1;
+ uint8_t f1rc04_d1;
+ uint8_t f1rc05_d1;
+ uint8_t f1rc06_d1;
+ uint8_t f1rc07_d1;
+ uint8_t f1rc08_d1;
+ uint8_t f1rc09_d1;
+ uint8_t f1rc0a_d1;
+ uint8_t f1rc0b_d1;
+ uint8_t f1rc0c_d1;
+ uint8_t f1rc0d_d1;
+ uint8_t f1rc0e_d1;
+ uint8_t f1rc0f_d1;
+ uint8_t f1rc1x_d1;
+ uint8_t f1rc2x_d1;
+ uint8_t f1rc3x_d1;
+ uint8_t f1rc4x_d1;
+ uint8_t f1rc5x_d1;
+ uint8_t f1rc6x_d1;
+ uint8_t f1rc7x_d1;
+ uint8_t f1rc8x_d1;
+ uint8_t f1rc9x_d1;
+ uint8_t f1rcax_d1;
+ uint8_t f1rcbx_d1;
+ uint8_t reserved142[0x3f6 - 0x142];
+ uint16_t alt_cas_l;
+ uint8_t alt_wcas_l;
+ uint8_t d4misc;
+} __packed;
+
+struct ddr4lr1d {
+ uint8_t reserved00;
+ uint8_t msg_misc;
+ uint16_t pmu_revision;
+ uint8_t pstate;
+ uint8_t pll_bypass_en;
+ uint16_t dramfreq;
+ uint8_t dfi_freq_ratio;
+ uint8_t bpznres_val;
+ uint8_t phy_odt_impedance;
+ uint8_t phy_drv_impedance;
+ uint8_t phy_vref;
+ uint8_t dram_type;
+ uint8_t disabled_dbyte;
+ uint8_t enabled_dqs;
+ uint8_t cs_present;
+ uint8_t cs_present_d0;
+ uint8_t cs_present_d1;
+ uint8_t addr_mirror;
+ uint8_t cs_test_fail;
+ uint8_t phy_cfg;
+ uint16_t sequence_ctrl;
+ uint8_t hdt_ctrl;
+ uint8_t reserved19[0x22 - 0x19];
+ uint16_t phy_config_override;
+ uint8_t dfimrlmargin;
+ int8_t cdd_rr_3_2;
+ int8_t cdd_rr_3_1;
+ int8_t cdd_rr_3_0;
+ int8_t cdd_rr_2_3;
+ int8_t cdd_rr_2_1;
+ int8_t cdd_rr_2_0;
+ int8_t cdd_rr_1_3;
+ int8_t cdd_rr_1_2;
+ int8_t cdd_rr_1_0;
+ int8_t cdd_rr_0_3;
+ int8_t cdd_rr_0_2;
+ int8_t cdd_rr_0_1;
+ int8_t cdd_ww_3_2;
+ int8_t cdd_ww_3_1;
+ int8_t cdd_ww_3_0;
+ int8_t cdd_ww_2_3;
+ int8_t cdd_ww_2_1;
+ int8_t cdd_ww_2_0;
+ int8_t cdd_ww_1_3;
+ int8_t cdd_ww_1_2;
+ int8_t cdd_ww_1_0;
+ int8_t cdd_ww_0_3;
+ int8_t cdd_ww_0_2;
+ int8_t cdd_ww_0_1;
+ int8_t cdd_rw_3_3;
+ int8_t cdd_rw_3_2;
+ int8_t cdd_rw_3_1;
+ int8_t cdd_rw_3_0;
+ int8_t cdd_rw_2_3;
+ int8_t cdd_rw_2_2;
+ int8_t cdd_rw_2_1;
+ int8_t cdd_rw_2_0;
+ int8_t cdd_rw_1_3;
+ int8_t cdd_rw_1_2;
+ int8_t cdd_rw_1_1;
+ int8_t cdd_rw_1_0;
+ int8_t cdd_rw_0_3;
+ int8_t cdd_rw_0_2;
+ int8_t cdd_rw_0_1;
+ int8_t cdd_rw_0_0;
+ int8_t cdd_wr_3_3;
+ int8_t cdd_wr_3_2;
+ int8_t cdd_wr_3_1;
+ int8_t cdd_wr_3_0;
+ int8_t cdd_wr_2_3;
+ int8_t cdd_wr_2_2;
+ int8_t cdd_wr_2_1;
+ int8_t cdd_wr_2_0;
+ int8_t cdd_wr_1_3;
+ int8_t cdd_wr_1_2;
+ int8_t cdd_wr_1_1;
+ int8_t cdd_wr_1_0;
+ int8_t cdd_wr_0_3;
+ int8_t cdd_wr_0_2;
+ int8_t cdd_wr_0_1;
+ int8_t cdd_wr_0_0;
+ uint8_t reserved5d;
+ uint16_t mr0;
+ uint16_t mr1;
+ uint16_t mr2;
+ uint16_t mr3;
+ uint16_t mr4;
+ uint16_t mr5;
+ uint16_t mr6;
+ uint8_t x16present;
+ uint8_t cs_setup_gddec;
+ uint16_t rtt_nom_wr_park0;
+ uint16_t rtt_nom_wr_park1;
+ uint16_t rtt_nom_wr_park2;
+ uint16_t rtt_nom_wr_park3;
+ uint16_t rtt_nom_wr_park4;
+ uint16_t rtt_nom_wr_park5;
+ uint16_t rtt_nom_wr_park6;
+ uint16_t rtt_nom_wr_park7;
+ uint8_t acsm_odt_ctrl0;
+ uint8_t acsm_odt_ctrl1;
+ uint8_t acsm_odt_ctrl2;
+ uint8_t acsm_odt_ctrl3;
+ uint8_t acsm_odt_ctrl4;
+ uint8_t acsm_odt_ctrl5;
+ uint8_t acsm_odt_ctrl6;
+ uint8_t acsm_odt_ctrl7;
+ uint8_t vref_dq_r0nib0;
+ uint8_t vref_dq_r0nib1;
+ uint8_t vref_dq_r0nib2;
+ uint8_t vref_dq_r0nib3;
+ uint8_t vref_dq_r0nib4;
+ uint8_t vref_dq_r0nib5;
+ uint8_t vref_dq_r0nib6;
+ uint8_t vref_dq_r0nib7;
+ uint8_t vref_dq_r0nib8;
+ uint8_t vref_dq_r0nib9;
+ uint8_t vref_dq_r0nib10;
+ uint8_t vref_dq_r0nib11;
+ uint8_t vref_dq_r0nib12;
+ uint8_t vref_dq_r0nib13;
+ uint8_t vref_dq_r0nib14;
+ uint8_t vref_dq_r0nib15;
+ uint8_t vref_dq_r0nib16;
+ uint8_t vref_dq_r0nib17;
+ uint8_t vref_dq_r0nib18;
+ uint8_t vref_dq_r0nib19;
+ uint8_t vref_dq_r1nib0;
+ uint8_t vref_dq_r1nib1;
+ uint8_t vref_dq_r1nib2;
+ uint8_t vref_dq_r1nib3;
+ uint8_t vref_dq_r1nib4;
+ uint8_t vref_dq_r1nib5;
+ uint8_t vref_dq_r1nib6;
+ uint8_t vref_dq_r1nib7;
+ uint8_t vref_dq_r1nib8;
+ uint8_t vref_dq_r1nib9;
+ uint8_t vref_dq_r1nib10;
+ uint8_t vref_dq_r1nib11;
+ uint8_t vref_dq_r1nib12;
+ uint8_t vref_dq_r1nib13;
+ uint8_t vref_dq_r1nib14;
+ uint8_t vref_dq_r1nib15;
+ uint8_t vref_dq_r1nib16;
+ uint8_t vref_dq_r1nib17;
+ uint8_t vref_dq_r1nib18;
+ uint8_t vref_dq_r1nib19;
+ uint8_t vref_dq_r2nib0;
+ uint8_t vref_dq_r2nib1;
+ uint8_t vref_dq_r2nib2;
+ uint8_t vref_dq_r2nib3;
+ uint8_t vref_dq_r2nib4;
+ uint8_t vref_dq_r2nib5;
+ uint8_t vref_dq_r2nib6;
+ uint8_t vref_dq_r2nib7;
+ uint8_t vref_dq_r2nib8;
+ uint8_t vref_dq_r2nib9;
+ uint8_t vref_dq_r2nib10;
+ uint8_t vref_dq_r2nib11;
+ uint8_t vref_dq_r2nib12;
+ uint8_t vref_dq_r2nib13;
+ uint8_t vref_dq_r2nib14;
+ uint8_t vref_dq_r2nib15;
+ uint8_t vref_dq_r2nib16;
+ uint8_t vref_dq_r2nib17;
+ uint8_t vref_dq_r2nib18;
+ uint8_t vref_dq_r2nib19;
+ uint8_t vref_dq_r3nib0;
+ uint8_t vref_dq_r3nib1;
+ uint8_t vref_dq_r3nib2;
+ uint8_t vref_dq_r3nib3;
+ uint8_t vref_dq_r3nib4;
+ uint8_t vref_dq_r3nib5;
+ uint8_t vref_dq_r3nib6;
+ uint8_t vref_dq_r3nib7;
+ uint8_t vref_dq_r3nib8;
+ uint8_t vref_dq_r3nib9;
+ uint8_t vref_dq_r3nib10;
+ uint8_t vref_dq_r3nib11;
+ uint8_t vref_dq_r3nib12;
+ uint8_t vref_dq_r3nib13;
+ uint8_t vref_dq_r3nib14;
+ uint8_t vref_dq_r3nib15;
+ uint8_t vref_dq_r3nib16;
+ uint8_t vref_dq_r3nib17;
+ uint8_t vref_dq_r3nib18;
+ uint8_t vref_dq_r3nib19;
+ uint8_t f0rc00_d0;
+ uint8_t f0rc01_d0;
+ uint8_t f0rc02_d0;
+ uint8_t f0rc03_d0;
+ uint8_t f0rc04_d0;
+ uint8_t f0rc05_d0;
+ uint8_t f0rc06_d0;
+ uint8_t f0rc07_d0;
+ uint8_t f0rc08_d0;
+ uint8_t f0rc09_d0;
+ uint8_t f0rc0a_d0;
+ uint8_t f0rc0b_d0;
+ uint8_t f0rc0c_d0;
+ uint8_t f0rc0d_d0;
+ uint8_t f0rc0e_d0;
+ uint8_t f0rc0f_d0;
+ uint8_t f0rc1x_d0;
+ uint8_t f0rc2x_d0;
+ uint8_t f0rc3x_d0;
+ uint8_t f0rc4x_d0;
+ uint8_t f0rc5x_d0;
+ uint8_t f0rc6x_d0;
+ uint8_t f0rc7x_d0;
+ uint8_t f0rc8x_d0;
+ uint8_t f0rc9x_d0;
+ uint8_t f0rcax_d0;
+ uint8_t f0rcbx_d0;
+ uint8_t f1rc00_d0;
+ uint8_t f1rc01_d0;
+ uint8_t f1rc02_d0;
+ uint8_t f1rc03_d0;
+ uint8_t f1rc04_d0;
+ uint8_t f1rc05_d0;
+ uint8_t f1rc06_d0;
+ uint8_t f1rc07_d0;
+ uint8_t f1rc08_d0;
+ uint8_t f1rc09_d0;
+ uint8_t f1rc0a_d0;
+ uint8_t f1rc0b_d0;
+ uint8_t f1rc0c_d0;
+ uint8_t f1rc0d_d0;
+ uint8_t f1rc0e_d0;
+ uint8_t f1rc0f_d0;
+ uint8_t f1rc1x_d0;
+ uint8_t f1rc2x_d0;
+ uint8_t f1rc3x_d0;
+ uint8_t f1rc4x_d0;
+ uint8_t f1rc5x_d0;
+ uint8_t f1rc6x_d0;
+ uint8_t f1rc7x_d0;
+ uint8_t f1rc8x_d0;
+ uint8_t f1rc9x_d0;
+ uint8_t f1rcax_d0;
+ uint8_t f1rcbx_d0;
+ uint8_t f0rc00_d1;
+ uint8_t f0rc01_d1;
+ uint8_t f0rc02_d1;
+ uint8_t f0rc03_d1;
+ uint8_t f0rc04_d1;
+ uint8_t f0rc05_d1;
+ uint8_t f0rc06_d1;
+ uint8_t f0rc07_d1;
+ uint8_t f0rc08_d1;
+ uint8_t f0rc09_d1;
+ uint8_t f0rc0a_d1;
+ uint8_t f0rc0b_d1;
+ uint8_t f0rc0c_d1;
+ uint8_t f0rc0d_d1;
+ uint8_t f0rc0e_d1;
+ uint8_t f0rc0f_d1;
+ uint8_t f0rc1x_d1;
+ uint8_t f0rc2x_d1;
+ uint8_t f0rc3x_d1;
+ uint8_t f0rc4x_d1;
+ uint8_t f0rc5x_d1;
+ uint8_t f0rc6x_d1;
+ uint8_t f0rc7x_d1;
+ uint8_t f0rc8x_d1;
+ uint8_t f0rc9x_d1;
+ uint8_t f0rcax_d1;
+ uint8_t f0rcbx_d1;
+ uint8_t f1rc00_d1;
+ uint8_t f1rc01_d1;
+ uint8_t f1rc02_d1;
+ uint8_t f1rc03_d1;
+ uint8_t f1rc04_d1;
+ uint8_t f1rc05_d1;
+ uint8_t f1rc06_d1;
+ uint8_t f1rc07_d1;
+ uint8_t f1rc08_d1;
+ uint8_t f1rc09_d1;
+ uint8_t f1rc0a_d1;
+ uint8_t f1rc0b_d1;
+ uint8_t f1rc0c_d1;
+ uint8_t f1rc0d_d1;
+ uint8_t f1rc0e_d1;
+ uint8_t f1rc0f_d1;
+ uint8_t f1rc1x_d1;
+ uint8_t f1rc2x_d1;
+ uint8_t f1rc3x_d1;
+ uint8_t f1rc4x_d1;
+ uint8_t f1rc5x_d1;
+ uint8_t f1rc6x_d1;
+ uint8_t f1rc7x_d1;
+ uint8_t f1rc8x_d1;
+ uint8_t f1rc9x_d1;
+ uint8_t f1rcax_d1;
+ uint8_t f1rcbx_d1;
+ uint8_t bc00_d0;
+ uint8_t bc01_d0;
+ uint8_t bc02_d0;
+ uint8_t bc03_d0;
+ uint8_t bc04_d0;
+ uint8_t bc05_d0;
+ uint8_t bc06_d0;
+ uint8_t bc07_d0;
+ uint8_t bc08_d0;
+ uint8_t bc09_d0;
+ uint8_t bc0a_d0;
+ uint8_t bc0b_d0;
+ uint8_t bc0c_d0;
+ uint8_t bc0d_d0;
+ uint8_t bc0e_d0;
+ uint8_t f0bc6x_d0;
+ uint8_t f0bccx_d0;
+ uint8_t f0bcdx_d0;
+ uint8_t f0bcex_d0;
+ uint8_t f0bcfx_d0;
+ uint8_t f1bccx_d0;
+ uint8_t f1bcdx_d0;
+ uint8_t f1bcex_d0;
+ uint8_t f1bcfx_d0;
+ uint8_t f0bc2x_b0_d0;
+ uint8_t f0bc3x_b0_d0;
+ uint8_t f0bc4x_b0_d0;
+ uint8_t f0bc5x_b0_d0;
+ uint8_t f0bc8x_b0_d0;
+ uint8_t f0bc9x_b0_d0;
+ uint8_t f0bcax_b0_d0;
+ uint8_t f0bcbx_b0_d0;
+ uint8_t f1bc2x_b0_d0;
+ uint8_t f1bc3x_b0_d0;
+ uint8_t f1bc4x_b0_d0;
+ uint8_t f1bc5x_b0_d0;
+ uint8_t f1bc8x_b0_d0;
+ uint8_t f1bc9x_b0_d0;
+ uint8_t f1bcax_b0_d0;
+ uint8_t f1bcbx_b0_d0;
+ uint8_t f2bc2x_b0_d0;
+ uint8_t f2bc3x_b0_d0;
+ uint8_t f2bc4x_b0_d0;
+ uint8_t f2bc5x_b0_d0;
+ uint8_t f2bc8x_b0_d0;
+ uint8_t f2bc9x_b0_d0;
+ uint8_t f2bcax_b0_d0;
+ uint8_t f2bcbx_b0_d0;
+ uint8_t f3bc2x_b0_d0;
+ uint8_t f3bc3x_b0_d0;
+ uint8_t f3bc4x_b0_d0;
+ uint8_t f3bc5x_b0_d0;
+ uint8_t f3bc8x_b0_d0;
+ uint8_t f3bc9x_b0_d0;
+ uint8_t f3bcax_b0_d0;
+ uint8_t f3bcbx_b0_d0;
+ uint8_t f0bc2x_b1_d0;
+ uint8_t f0bc3x_b1_d0;
+ uint8_t f0bc4x_b1_d0;
+ uint8_t f0bc5x_b1_d0;
+ uint8_t f0bc8x_b1_d0;
+ uint8_t f0bc9x_b1_d0;
+ uint8_t f0bcax_b1_d0;
+ uint8_t f0bcbx_b1_d0;
+ uint8_t f1bc2x_b1_d0;
+ uint8_t f1bc3x_b1_d0;
+ uint8_t f1bc4x_b1_d0;
+ uint8_t f1bc5x_b1_d0;
+ uint8_t f1bc8x_b1_d0;
+ uint8_t f1bc9x_b1_d0;
+ uint8_t f1bcax_b1_d0;
+ uint8_t f1bcbx_b1_d0;
+ uint8_t f2bc2x_b1_d0;
+ uint8_t f2bc3x_b1_d0;
+ uint8_t f2bc4x_b1_d0;
+ uint8_t f2bc5x_b1_d0;
+ uint8_t f2bc8x_b1_d0;
+ uint8_t f2bc9x_b1_d0;
+ uint8_t f2bcax_b1_d0;
+ uint8_t f2bcbx_b1_d0;
+ uint8_t f3bc2x_b1_d0;
+ uint8_t f3bc3x_b1_d0;
+ uint8_t f3bc4x_b1_d0;
+ uint8_t f3bc5x_b1_d0;
+ uint8_t f3bc8x_b1_d0;
+ uint8_t f3bc9x_b1_d0;
+ uint8_t f3bcax_b1_d0;
+ uint8_t f3bcbx_b1_d0;
+ uint8_t f0bc2x_b2_d0;
+ uint8_t f0bc3x_b2_d0;
+ uint8_t f0bc4x_b2_d0;
+ uint8_t f0bc5x_b2_d0;
+ uint8_t f0bc8x_b2_d0;
+ uint8_t f0bc9x_b2_d0;
+ uint8_t f0bcax_b2_d0;
+ uint8_t f0bcbx_b2_d0;
+ uint8_t f1bc2x_b2_d0;
+ uint8_t f1bc3x_b2_d0;
+ uint8_t f1bc4x_b2_d0;
+ uint8_t f1bc5x_b2_d0;
+ uint8_t f1bc8x_b2_d0;
+ uint8_t f1bc9x_b2_d0;
+ uint8_t f1bcax_b2_d0;
+ uint8_t f1bcbx_b2_d0;
+ uint8_t f2bc2x_b2_d0;
+ uint8_t f2bc3x_b2_d0;
+ uint8_t f2bc4x_b2_d0;
+ uint8_t f2bc5x_b2_d0;
+ uint8_t f2bc8x_b2_d0;
+ uint8_t f2bc9x_b2_d0;
+ uint8_t f2bcax_b2_d0;
+ uint8_t f2bcbx_b2_d0;
+ uint8_t f3bc2x_b2_d0;
+ uint8_t f3bc3x_b2_d0;
+ uint8_t f3bc4x_b2_d0;
+ uint8_t f3bc5x_b2_d0;
+ uint8_t f3bc8x_b2_d0;
+ uint8_t f3bc9x_b2_d0;
+ uint8_t f3bcax_b2_d0;
+ uint8_t f3bcbx_b2_d0;
+ uint8_t f0bc2x_b3_d0;
+ uint8_t f0bc3x_b3_d0;
+ uint8_t f0bc4x_b3_d0;
+ uint8_t f0bc5x_b3_d0;
+ uint8_t f0bc8x_b3_d0;
+ uint8_t f0bc9x_b3_d0;
+ uint8_t f0bcax_b3_d0;
+ uint8_t f0bcbx_b3_d0;
+ uint8_t f1bc2x_b3_d0;
+ uint8_t f1bc3x_b3_d0;
+ uint8_t f1bc4x_b3_d0;
+ uint8_t f1bc5x_b3_d0;
+ uint8_t f1bc8x_b3_d0;
+ uint8_t f1bc9x_b3_d0;
+ uint8_t f1bcax_b3_d0;
+ uint8_t f1bcbx_b3_d0;
+ uint8_t f2bc2x_b3_d0;
+ uint8_t f2bc3x_b3_d0;
+ uint8_t f2bc4x_b3_d0;
+ uint8_t f2bc5x_b3_d0;
+ uint8_t f2bc8x_b3_d0;
+ uint8_t f2bc9x_b3_d0;
+ uint8_t f2bcax_b3_d0;
+ uint8_t f2bcbx_b3_d0;
+ uint8_t f3bc2x_b3_d0;
+ uint8_t f3bc3x_b3_d0;
+ uint8_t f3bc4x_b3_d0;
+ uint8_t f3bc5x_b3_d0;
+ uint8_t f3bc8x_b3_d0;
+ uint8_t f3bc9x_b3_d0;
+ uint8_t f3bcax_b3_d0;
+ uint8_t f3bcbx_b3_d0;
+ uint8_t f0bc2x_b4_d0;
+ uint8_t f0bc3x_b4_d0;
+ uint8_t f0bc4x_b4_d0;
+ uint8_t f0bc5x_b4_d0;
+ uint8_t f0bc8x_b4_d0;
+ uint8_t f0bc9x_b4_d0;
+ uint8_t f0bcax_b4_d0;
+ uint8_t f0bcbx_b4_d0;
+ uint8_t f1bc2x_b4_d0;
+ uint8_t f1bc3x_b4_d0;
+ uint8_t f1bc4x_b4_d0;
+ uint8_t f1bc5x_b4_d0;
+ uint8_t f1bc8x_b4_d0;
+ uint8_t f1bc9x_b4_d0;
+ uint8_t f1bcax_b4_d0;
+ uint8_t f1bcbx_b4_d0;
+ uint8_t f2bc2x_b4_d0;
+ uint8_t f2bc3x_b4_d0;
+ uint8_t f2bc4x_b4_d0;
+ uint8_t f2bc5x_b4_d0;
+ uint8_t f2bc8x_b4_d0;
+ uint8_t f2bc9x_b4_d0;
+ uint8_t f2bcax_b4_d0;
+ uint8_t f2bcbx_b4_d0;
+ uint8_t f3bc2x_b4_d0;
+ uint8_t f3bc3x_b4_d0;
+ uint8_t f3bc4x_b4_d0;
+ uint8_t f3bc5x_b4_d0;
+ uint8_t f3bc8x_b4_d0;
+ uint8_t f3bc9x_b4_d0;
+ uint8_t f3bcax_b4_d0;
+ uint8_t f3bcbx_b4_d0;
+ uint8_t f0bc2x_b5_d0;
+ uint8_t f0bc3x_b5_d0;
+ uint8_t f0bc4x_b5_d0;
+ uint8_t f0bc5x_b5_d0;
+ uint8_t f0bc8x_b5_d0;
+ uint8_t f0bc9x_b5_d0;
+ uint8_t f0bcax_b5_d0;
+ uint8_t f0bcbx_b5_d0;
+ uint8_t f1bc2x_b5_d0;
+ uint8_t f1bc3x_b5_d0;
+ uint8_t f1bc4x_b5_d0;
+ uint8_t f1bc5x_b5_d0;
+ uint8_t f1bc8x_b5_d0;
+ uint8_t f1bc9x_b5_d0;
+ uint8_t f1bcax_b5_d0;
+ uint8_t f1bcbx_b5_d0;
+ uint8_t f2bc2x_b5_d0;
+ uint8_t f2bc3x_b5_d0;
+ uint8_t f2bc4x_b5_d0;
+ uint8_t f2bc5x_b5_d0;
+ uint8_t f2bc8x_b5_d0;
+ uint8_t f2bc9x_b5_d0;
+ uint8_t f2bcax_b5_d0;
+ uint8_t f2bcbx_b5_d0;
+ uint8_t f3bc2x_b5_d0;
+ uint8_t f3bc3x_b5_d0;
+ uint8_t f3bc4x_b5_d0;
+ uint8_t f3bc5x_b5_d0;
+ uint8_t f3bc8x_b5_d0;
+ uint8_t f3bc9x_b5_d0;
+ uint8_t f3bcax_b5_d0;
+ uint8_t f3bcbx_b5_d0;
+ uint8_t f0bc2x_b6_d0;
+ uint8_t f0bc3x_b6_d0;
+ uint8_t f0bc4x_b6_d0;
+ uint8_t f0bc5x_b6_d0;
+ uint8_t f0bc8x_b6_d0;
+ uint8_t f0bc9x_b6_d0;
+ uint8_t f0bcax_b6_d0;
+ uint8_t f0bcbx_b6_d0;
+ uint8_t f1bc2x_b6_d0;
+ uint8_t f1bc3x_b6_d0;
+ uint8_t f1bc4x_b6_d0;
+ uint8_t f1bc5x_b6_d0;
+ uint8_t f1bc8x_b6_d0;
+ uint8_t f1bc9x_b6_d0;
+ uint8_t f1bcax_b6_d0;
+ uint8_t f1bcbx_b6_d0;
+ uint8_t f2bc2x_b6_d0;
+ uint8_t f2bc3x_b6_d0;
+ uint8_t f2bc4x_b6_d0;
+ uint8_t f2bc5x_b6_d0;
+ uint8_t f2bc8x_b6_d0;
+ uint8_t f2bc9x_b6_d0;
+ uint8_t f2bcax_b6_d0;
+ uint8_t f2bcbx_b6_d0;
+ uint8_t f3bc2x_b6_d0;
+ uint8_t f3bc3x_b6_d0;
+ uint8_t f3bc4x_b6_d0;
+ uint8_t f3bc5x_b6_d0;
+ uint8_t f3bc8x_b6_d0;
+ uint8_t f3bc9x_b6_d0;
+ uint8_t f3bcax_b6_d0;
+ uint8_t f3bcbx_b6_d0;
+ uint8_t f0bc2x_b7_d0;
+ uint8_t f0bc3x_b7_d0;
+ uint8_t f0bc4x_b7_d0;
+ uint8_t f0bc5x_b7_d0;
+ uint8_t f0bc8x_b7_d0;
+ uint8_t f0bc9x_b7_d0;
+ uint8_t f0bcax_b7_d0;
+ uint8_t f0bcbx_b7_d0;
+ uint8_t f1bc2x_b7_d0;
+ uint8_t f1bc3x_b7_d0;
+ uint8_t f1bc4x_b7_d0;
+ uint8_t f1bc5x_b7_d0;
+ uint8_t f1bc8x_b7_d0;
+ uint8_t f1bc9x_b7_d0;
+ uint8_t f1bcax_b7_d0;
+ uint8_t f1bcbx_b7_d0;
+ uint8_t f2bc2x_b7_d0;
+ uint8_t f2bc3x_b7_d0;
+ uint8_t f2bc4x_b7_d0;
+ uint8_t f2bc5x_b7_d0;
+ uint8_t f2bc8x_b7_d0;
+ uint8_t f2bc9x_b7_d0;
+ uint8_t f2bcax_b7_d0;
+ uint8_t f2bcbx_b7_d0;
+ uint8_t f3bc2x_b7_d0;
+ uint8_t f3bc3x_b7_d0;
+ uint8_t f3bc4x_b7_d0;
+ uint8_t f3bc5x_b7_d0;
+ uint8_t f3bc8x_b7_d0;
+ uint8_t f3bc9x_b7_d0;
+ uint8_t f3bcax_b7_d0;
+ uint8_t f3bcbx_b7_d0;
+ uint8_t f0bc2x_b8_d0;
+ uint8_t f0bc3x_b8_d0;
+ uint8_t f0bc4x_b8_d0;
+ uint8_t f0bc5x_b8_d0;
+ uint8_t f0bc8x_b8_d0;
+ uint8_t f0bc9x_b8_d0;
+ uint8_t f0bcax_b8_d0;
+ uint8_t f0bcbx_b8_d0;
+ uint8_t f1bc2x_b8_d0;
+ uint8_t f1bc3x_b8_d0;
+ uint8_t f1bc4x_b8_d0;
+ uint8_t f1bc5x_b8_d0;
+ uint8_t f1bc8x_b8_d0;
+ uint8_t f1bc9x_b8_d0;
+ uint8_t f1bcax_b8_d0;
+ uint8_t f1bcbx_b8_d0;
+ uint8_t f2bc2x_b8_d0;
+ uint8_t f2bc3x_b8_d0;
+ uint8_t f2bc4x_b8_d0;
+ uint8_t f2bc5x_b8_d0;
+ uint8_t f2bc8x_b8_d0;
+ uint8_t f2bc9x_b8_d0;
+ uint8_t f2bcax_b8_d0;
+ uint8_t f2bcbx_b8_d0;
+ uint8_t f3bc2x_b8_d0;
+ uint8_t f3bc3x_b8_d0;
+ uint8_t f3bc4x_b8_d0;
+ uint8_t f3bc5x_b8_d0;
+ uint8_t f3bc8x_b8_d0;
+ uint8_t f3bc9x_b8_d0;
+ uint8_t f3bcax_b8_d0;
+ uint8_t f3bcbx_b8_d0;
+ uint8_t f5bc5x_d0;
+ uint8_t f5bc6x_d0;
+ uint8_t f4bc8x_d0;
+ uint8_t f4bc9x_d0;
+ uint8_t f4bcax_d0;
+ uint8_t f4bcbx_d0;
+ uint8_t f4bccx_d0;
+ uint8_t f4bcdx_d0;
+ uint8_t f4bcex_d0;
+ uint8_t f4bcfx_d0;
+ uint8_t f5bc8x_d0;
+ uint8_t f5bc9x_d0;
+ uint8_t f5bcax_d0;
+ uint8_t f5bcbx_d0;
+ uint8_t f5bccx_d0;
+ uint8_t f5bcdx_d0;
+ uint8_t f5bcex_d0;
+ uint8_t f5bcfx_d0;
+ uint8_t f6bc8x_d0;
+ uint8_t f6bc9x_d0;
+ uint8_t f6bcax_d0;
+ uint8_t f6bcbx_d0;
+ uint8_t f6bccx_d0;
+ uint8_t f6bcdx_d0;
+ uint8_t f6bcex_d0;
+ uint8_t f6bcfx_d0;
+ uint8_t f7bc8x_d0;
+ uint8_t f7bc9x_d0;
+ uint8_t f7bcax_d0;
+ uint8_t f7bcbx_d0;
+ uint8_t f7bccx_d0;
+ uint8_t f7bcdx_d0;
+ uint8_t f7bcex_d0;
+ uint8_t f7bcfx_d0;
+ uint8_t bc00_d1;
+ uint8_t bc01_d1;
+ uint8_t bc02_d1;
+ uint8_t bc03_d1;
+ uint8_t bc04_d1;
+ uint8_t bc05_d1;
+ uint8_t bc06_d1;
+ uint8_t bc07_d1;
+ uint8_t bc08_d1;
+ uint8_t bc09_d1;
+ uint8_t bc0a_d1;
+ uint8_t bc0b_d1;
+ uint8_t bc0c_d1;
+ uint8_t bc0d_d1;
+ uint8_t bc0e_d1;
+ uint8_t f0bc6x_d1;
+ uint8_t f0bccx_d1;
+ uint8_t f0bcdx_d1;
+ uint8_t f0bcex_d1;
+ uint8_t f0bcfx_d1;
+ uint8_t f1bccx_d1;
+ uint8_t f1bcdx_d1;
+ uint8_t f1bcex_d1;
+ uint8_t f1bcfx_d1;
+ uint8_t f0bc2x_b0_d1;
+ uint8_t f0bc3x_b0_d1;
+ uint8_t f0bc4x_b0_d1;
+ uint8_t f0bc5x_b0_d1;
+ uint8_t f0bc8x_b0_d1;
+ uint8_t f0bc9x_b0_d1;
+ uint8_t f0bcax_b0_d1;
+ uint8_t f0bcbx_b0_d1;
+ uint8_t f1bc2x_b0_d1;
+ uint8_t f1bc3x_b0_d1;
+ uint8_t f1bc4x_b0_d1;
+ uint8_t f1bc5x_b0_d1;
+ uint8_t f1bc8x_b0_d1;
+ uint8_t f1bc9x_b0_d1;
+ uint8_t f1bcax_b0_d1;
+ uint8_t f1bcbx_b0_d1;
+ uint8_t f2bc2x_b0_d1;
+ uint8_t f2bc3x_b0_d1;
+ uint8_t f2bc4x_b0_d1;
+ uint8_t f2bc5x_b0_d1;
+ uint8_t f2bc8x_b0_d1;
+ uint8_t f2bc9x_b0_d1;
+ uint8_t f2bcax_b0_d1;
+ uint8_t f2bcbx_b0_d1;
+ uint8_t f3bc2x_b0_d1;
+ uint8_t f3bc3x_b0_d1;
+ uint8_t f3bc4x_b0_d1;
+ uint8_t f3bc5x_b0_d1;
+ uint8_t f3bc8x_b0_d1;
+ uint8_t f3bc9x_b0_d1;
+ uint8_t f3bcax_b0_d1;
+ uint8_t f3bcbx_b0_d1;
+ uint8_t f0bc2x_b1_d1;
+ uint8_t f0bc3x_b1_d1;
+ uint8_t f0bc4x_b1_d1;
+ uint8_t f0bc5x_b1_d1;
+ uint8_t f0bc8x_b1_d1;
+ uint8_t f0bc9x_b1_d1;
+ uint8_t f0bcax_b1_d1;
+ uint8_t f0bcbx_b1_d1;
+ uint8_t f1bc2x_b1_d1;
+ uint8_t f1bc3x_b1_d1;
+ uint8_t f1bc4x_b1_d1;
+ uint8_t f1bc5x_b1_d1;
+ uint8_t f1bc8x_b1_d1;
+ uint8_t f1bc9x_b1_d1;
+ uint8_t f1bcax_b1_d1;
+ uint8_t f1bcbx_b1_d1;
+ uint8_t f2bc2x_b1_d1;
+ uint8_t f2bc3x_b1_d1;
+ uint8_t f2bc4x_b1_d1;
+ uint8_t f2bc5x_b1_d1;
+ uint8_t f2bc8x_b1_d1;
+ uint8_t f2bc9x_b1_d1;
+ uint8_t f2bcax_b1_d1;
+ uint8_t f2bcbx_b1_d1;
+ uint8_t f3bc2x_b1_d1;
+ uint8_t f3bc3x_b1_d1;
+ uint8_t f3bc4x_b1_d1;
+ uint8_t f3bc5x_b1_d1;
+ uint8_t f3bc8x_b1_d1;
+ uint8_t f3bc9x_b1_d1;
+ uint8_t f3bcax_b1_d1;
+ uint8_t f3bcbx_b1_d1;
+ uint8_t f0bc2x_b2_d1;
+ uint8_t f0bc3x_b2_d1;
+ uint8_t f0bc4x_b2_d1;
+ uint8_t f0bc5x_b2_d1;
+ uint8_t f0bc8x_b2_d1;
+ uint8_t f0bc9x_b2_d1;
+ uint8_t f0bcax_b2_d1;
+ uint8_t f0bcbx_b2_d1;
+ uint8_t f1bc2x_b2_d1;
+ uint8_t f1bc3x_b2_d1;
+ uint8_t f1bc4x_b2_d1;
+ uint8_t f1bc5x_b2_d1;
+ uint8_t f1bc8x_b2_d1;
+ uint8_t f1bc9x_b2_d1;
+ uint8_t f1bcax_b2_d1;
+ uint8_t f1bcbx_b2_d1;
+ uint8_t f2bc2x_b2_d1;
+ uint8_t f2bc3x_b2_d1;
+ uint8_t f2bc4x_b2_d1;
+ uint8_t f2bc5x_b2_d1;
+ uint8_t f2bc8x_b2_d1;
+ uint8_t f2bc9x_b2_d1;
+ uint8_t f2bcax_b2_d1;
+ uint8_t f2bcbx_b2_d1;
+ uint8_t f3bc2x_b2_d1;
+ uint8_t f3bc3x_b2_d1;
+ uint8_t f3bc4x_b2_d1;
+ uint8_t f3bc5x_b2_d1;
+ uint8_t f3bc8x_b2_d1;
+ uint8_t f3bc9x_b2_d1;
+ uint8_t f3bcax_b2_d1;
+ uint8_t f3bcbx_b2_d1;
+ uint8_t f0bc2x_b3_d1;
+ uint8_t f0bc3x_b3_d1;
+ uint8_t f0bc4x_b3_d1;
+ uint8_t f0bc5x_b3_d1;
+ uint8_t f0bc8x_b3_d1;
+ uint8_t f0bc9x_b3_d1;
+ uint8_t f0bcax_b3_d1;
+ uint8_t f0bcbx_b3_d1;
+ uint8_t f1bc2x_b3_d1;
+ uint8_t f1bc3x_b3_d1;
+ uint8_t f1bc4x_b3_d1;
+ uint8_t f1bc5x_b3_d1;
+ uint8_t f1bc8x_b3_d1;
+ uint8_t f1bc9x_b3_d1;
+ uint8_t f1bcax_b3_d1;
+ uint8_t f1bcbx_b3_d1;
+ uint8_t f2bc2x_b3_d1;
+ uint8_t f2bc3x_b3_d1;
+ uint8_t f2bc4x_b3_d1;
+ uint8_t f2bc5x_b3_d1;
+ uint8_t f2bc8x_b3_d1;
+ uint8_t f2bc9x_b3_d1;
+ uint8_t f2bcax_b3_d1;
+ uint8_t f2bcbx_b3_d1;
+ uint8_t f3bc2x_b3_d1;
+ uint8_t f3bc3x_b3_d1;
+ uint8_t f3bc4x_b3_d1;
+ uint8_t f3bc5x_b3_d1;
+ uint8_t f3bc8x_b3_d1;
+ uint8_t f3bc9x_b3_d1;
+ uint8_t f3bcax_b3_d1;
+ uint8_t f3bcbx_b3_d1;
+ uint8_t f0bc2x_b4_d1;
+ uint8_t f0bc3x_b4_d1;
+ uint8_t f0bc4x_b4_d1;
+ uint8_t f0bc5x_b4_d1;
+ uint8_t f0bc8x_b4_d1;
+ uint8_t f0bc9x_b4_d1;
+ uint8_t f0bcax_b4_d1;
+ uint8_t f0bcbx_b4_d1;
+ uint8_t f1bc2x_b4_d1;
+ uint8_t f1bc3x_b4_d1;
+ uint8_t f1bc4x_b4_d1;
+ uint8_t f1bc5x_b4_d1;
+ uint8_t f1bc8x_b4_d1;
+ uint8_t f1bc9x_b4_d1;
+ uint8_t f1bcax_b4_d1;
+ uint8_t f1bcbx_b4_d1;
+ uint8_t f2bc2x_b4_d1;
+ uint8_t f2bc3x_b4_d1;
+ uint8_t f2bc4x_b4_d1;
+ uint8_t f2bc5x_b4_d1;
+ uint8_t f2bc8x_b4_d1;
+ uint8_t f2bc9x_b4_d1;
+ uint8_t f2bcax_b4_d1;
+ uint8_t f2bcbx_b4_d1;
+ uint8_t f3bc2x_b4_d1;
+ uint8_t f3bc3x_b4_d1;
+ uint8_t f3bc4x_b4_d1;
+ uint8_t f3bc5x_b4_d1;
+ uint8_t f3bc8x_b4_d1;
+ uint8_t f3bc9x_b4_d1;
+ uint8_t f3bcax_b4_d1;
+ uint8_t f3bcbx_b4_d1;
+ uint8_t f0bc2x_b5_d1;
+ uint8_t f0bc3x_b5_d1;
+ uint8_t f0bc4x_b5_d1;
+ uint8_t f0bc5x_b5_d1;
+ uint8_t f0bc8x_b5_d1;
+ uint8_t f0bc9x_b5_d1;
+ uint8_t f0bcax_b5_d1;
+ uint8_t f0bcbx_b5_d1;
+ uint8_t f1bc2x_b5_d1;
+ uint8_t f1bc3x_b5_d1;
+ uint8_t f1bc4x_b5_d1;
+ uint8_t f1bc5x_b5_d1;
+ uint8_t f1bc8x_b5_d1;
+ uint8_t f1bc9x_b5_d1;
+ uint8_t f1bcax_b5_d1;
+ uint8_t f1bcbx_b5_d1;
+ uint8_t f2bc2x_b5_d1;
+ uint8_t f2bc3x_b5_d1;
+ uint8_t f2bc4x_b5_d1;
+ uint8_t f2bc5x_b5_d1;
+ uint8_t f2bc8x_b5_d1;
+ uint8_t f2bc9x_b5_d1;
+ uint8_t f2bcax_b5_d1;
+ uint8_t f2bcbx_b5_d1;
+ uint8_t f3bc2x_b5_d1;
+ uint8_t f3bc3x_b5_d1;
+ uint8_t f3bc4x_b5_d1;
+ uint8_t f3bc5x_b5_d1;
+ uint8_t f3bc8x_b5_d1;
+ uint8_t f3bc9x_b5_d1;
+ uint8_t f3bcax_b5_d1;
+ uint8_t f3bcbx_b5_d1;
+ uint8_t f0bc2x_b6_d1;
+ uint8_t f0bc3x_b6_d1;
+ uint8_t f0bc4x_b6_d1;
+ uint8_t f0bc5x_b6_d1;
+ uint8_t f0bc8x_b6_d1;
+ uint8_t f0bc9x_b6_d1;
+ uint8_t f0bcax_b6_d1;
+ uint8_t f0bcbx_b6_d1;
+ uint8_t f1bc2x_b6_d1;
+ uint8_t f1bc3x_b6_d1;
+ uint8_t f1bc4x_b6_d1;
+ uint8_t f1bc5x_b6_d1;
+ uint8_t f1bc8x_b6_d1;
+ uint8_t f1bc9x_b6_d1;
+ uint8_t f1bcax_b6_d1;
+ uint8_t f1bcbx_b6_d1;
+ uint8_t f2bc2x_b6_d1;
+ uint8_t f2bc3x_b6_d1;
+ uint8_t f2bc4x_b6_d1;
+ uint8_t f2bc5x_b6_d1;
+ uint8_t f2bc8x_b6_d1;
+ uint8_t f2bc9x_b6_d1;
+ uint8_t f2bcax_b6_d1;
+ uint8_t f2bcbx_b6_d1;
+ uint8_t f3bc2x_b6_d1;
+ uint8_t f3bc3x_b6_d1;
+ uint8_t f3bc4x_b6_d1;
+ uint8_t f3bc5x_b6_d1;
+ uint8_t f3bc8x_b6_d1;
+ uint8_t f3bc9x_b6_d1;
+ uint8_t f3bcax_b6_d1;
+ uint8_t f3bcbx_b6_d1;
+ uint8_t f0bc2x_b7_d1;
+ uint8_t f0bc3x_b7_d1;
+ uint8_t f0bc4x_b7_d1;
+ uint8_t f0bc5x_b7_d1;
+ uint8_t f0bc8x_b7_d1;
+ uint8_t f0bc9x_b7_d1;
+ uint8_t f0bcax_b7_d1;
+ uint8_t f0bcbx_b7_d1;
+ uint8_t f1bc2x_b7_d1;
+ uint8_t f1bc3x_b7_d1;
+ uint8_t f1bc4x_b7_d1;
+ uint8_t f1bc5x_b7_d1;
+ uint8_t f1bc8x_b7_d1;
+ uint8_t f1bc9x_b7_d1;
+ uint8_t f1bcax_b7_d1;
+ uint8_t f1bcbx_b7_d1;
+ uint8_t f2bc2x_b7_d1;
+ uint8_t f2bc3x_b7_d1;
+ uint8_t f2bc4x_b7_d1;
+ uint8_t f2bc5x_b7_d1;
+ uint8_t f2bc8x_b7_d1;
+ uint8_t f2bc9x_b7_d1;
+ uint8_t f2bcax_b7_d1;
+ uint8_t f2bcbx_b7_d1;
+ uint8_t f3bc2x_b7_d1;
+ uint8_t f3bc3x_b7_d1;
+ uint8_t f3bc4x_b7_d1;
+ uint8_t f3bc5x_b7_d1;
+ uint8_t f3bc8x_b7_d1;
+ uint8_t f3bc9x_b7_d1;
+ uint8_t f3bcax_b7_d1;
+ uint8_t f3bcbx_b7_d1;
+ uint8_t f0bc2x_b8_d1;
+ uint8_t f0bc3x_b8_d1;
+ uint8_t f0bc4x_b8_d1;
+ uint8_t f0bc5x_b8_d1;
+ uint8_t f0bc8x_b8_d1;
+ uint8_t f0bc9x_b8_d1;
+ uint8_t f0bcax_b8_d1;
+ uint8_t f0bcbx_b8_d1;
+ uint8_t f1bc2x_b8_d1;
+ uint8_t f1bc3x_b8_d1;
+ uint8_t f1bc4x_b8_d1;
+ uint8_t f1bc5x_b8_d1;
+ uint8_t f1bc8x_b8_d1;
+ uint8_t f1bc9x_b8_d1;
+ uint8_t f1bcax_b8_d1;
+ uint8_t f1bcbx_b8_d1;
+ uint8_t f2bc2x_b8_d1;
+ uint8_t f2bc3x_b8_d1;
+ uint8_t f2bc4x_b8_d1;
+ uint8_t f2bc5x_b8_d1;
+ uint8_t f2bc8x_b8_d1;
+ uint8_t f2bc9x_b8_d1;
+ uint8_t f2bcax_b8_d1;
+ uint8_t f2bcbx_b8_d1;
+ uint8_t f3bc2x_b8_d1;
+ uint8_t f3bc3x_b8_d1;
+ uint8_t f3bc4x_b8_d1;
+ uint8_t f3bc5x_b8_d1;
+ uint8_t f3bc8x_b8_d1;
+ uint8_t f3bc9x_b8_d1;
+ uint8_t f3bcax_b8_d1;
+ uint8_t f3bcbx_b8_d1;
+ uint8_t f5bc5x_d1;
+ uint8_t f5bc6x_d1;
+ uint8_t f4bc8x_d1;
+ uint8_t f4bc9x_d1;
+ uint8_t f4bcax_d1;
+ uint8_t f4bcbx_d1;
+ uint8_t f4bccx_d1;
+ uint8_t f4bcdx_d1;
+ uint8_t f4bcex_d1;
+ uint8_t f4bcfx_d1;
+ uint8_t f5bc8x_d1;
+ uint8_t f5bc9x_d1;
+ uint8_t f5bcax_d1;
+ uint8_t f5bcbx_d1;
+ uint8_t f5bccx_d1;
+ uint8_t f5bcdx_d1;
+ uint8_t f5bcex_d1;
+ uint8_t f5bcfx_d1;
+ uint8_t f6bc8x_d1;
+ uint8_t f6bc9x_d1;
+ uint8_t f6bcax_d1;
+ uint8_t f6bcbx_d1;
+ uint8_t f6bccx_d1;
+ uint8_t f6bcdx_d1;
+ uint8_t f6bcex_d1;
+ uint8_t f6bcfx_d1;
+ uint8_t f7bc8x_d1;
+ uint8_t f7bc9x_d1;
+ uint8_t f7bcax_d1;
+ uint8_t f7bcbx_d1;
+ uint8_t f7bccx_d1;
+ uint8_t f7bcdx_d1;
+ uint8_t f7bcex_d1;
+ uint8_t f7bcfx_d1;
+ uint16_t alt_cas_l;
+ uint8_t alt_wcas_l;
+ uint8_t d4misc;
+} __packed;
+
+struct ddr4lr2d {
+ uint8_t reserved00;
+ uint8_t msg_misc;
+ uint16_t pmu_revision;
+ uint8_t pstate;
+ uint8_t pll_bypass_en;
+ uint16_t dramfreq;
+ uint8_t dfi_freq_ratio;
+ uint8_t bpznres_val;
+ uint8_t phy_odt_impedance;
+ uint8_t phy_drv_impedance;
+ uint8_t phy_vref;
+ uint8_t dram_type;
+ uint8_t disabled_dbyte;
+ uint8_t enabled_dqs;
+ uint8_t cs_present;
+ uint8_t cs_present_d0;
+ uint8_t cs_present_d1;
+ uint8_t addr_mirror;
+ uint8_t cs_test_fail;
+ uint8_t phy_cfg;
+ uint16_t sequence_ctrl;
+ uint8_t hdt_ctrl;
+ uint8_t rx2d_train_opt;
+ uint8_t tx2d_train_opt;
+ uint8_t share2dvref_result;
+ uint8_t delay_weight2d;
+ uint8_t voltage_weight2d;
+ uint8_t reserved1e[0x22 - 0x1e];
+ uint16_t phy_config_override;
+ uint8_t dfimrlmargin;
+ uint8_t r0_rx_clk_dly_margin;
+ uint8_t r0_vref_dac_margin;
+ uint8_t r0_tx_dq_dly_margin;
+ uint8_t r0_device_vref_margin;
+ uint8_t reserved29[0x33 - 0x29];
+ uint8_t r1_rx_clk_dly_margin;
+ uint8_t r1_vref_dac_margin;
+ uint8_t r1_tx_dq_dly_margin;
+ uint8_t r1_device_vref_margin;
+ uint8_t reserved37[0x41 - 0x37];
+ uint8_t r2_rx_clk_dly_margin;
+ uint8_t r2_vref_dac_margin;
+ uint8_t r2_tx_dq_dly_margin;
+ uint8_t r2_device_vref_margin;
+ uint8_t reserved45[0x4f - 0x45];
+ uint8_t r3_rx_clk_dly_margin;
+ uint8_t r3_vref_dac_margin;
+ uint8_t r3_tx_dq_dly_margin;
+ uint8_t r3_device_vref_margin;
+ uint8_t reserved53[0x5e - 0x53];
+ uint16_t mr0;
+ uint16_t mr1;
+ uint16_t mr2;
+ uint16_t mr3;
+ uint16_t mr4;
+ uint16_t mr5;
+ uint16_t mr6;
+ uint8_t x16present;
+ uint8_t cs_setup_gddec;
+ uint16_t rtt_nom_wr_park0;
+ uint16_t rtt_nom_wr_park1;
+ uint16_t rtt_nom_wr_park2;
+ uint16_t rtt_nom_wr_park3;
+ uint16_t rtt_nom_wr_park4;
+ uint16_t rtt_nom_wr_park5;
+ uint16_t rtt_nom_wr_park6;
+ uint16_t rtt_nom_wr_park7;
+ uint8_t acsm_odt_ctrl0;
+ uint8_t acsm_odt_ctrl1;
+ uint8_t acsm_odt_ctrl2;
+ uint8_t acsm_odt_ctrl3;
+ uint8_t acsm_odt_ctrl4;
+ uint8_t acsm_odt_ctrl5;
+ uint8_t acsm_odt_ctrl6;
+ uint8_t acsm_odt_ctrl7;
+ uint8_t vref_dq_r0nib0;
+ uint8_t vref_dq_r0nib1;
+ uint8_t vref_dq_r0nib2;
+ uint8_t vref_dq_r0nib3;
+ uint8_t vref_dq_r0nib4;
+ uint8_t vref_dq_r0nib5;
+ uint8_t vref_dq_r0nib6;
+ uint8_t vref_dq_r0nib7;
+ uint8_t vref_dq_r0nib8;
+ uint8_t vref_dq_r0nib9;
+ uint8_t vref_dq_r0nib10;
+ uint8_t vref_dq_r0nib11;
+ uint8_t vref_dq_r0nib12;
+ uint8_t vref_dq_r0nib13;
+ uint8_t vref_dq_r0nib14;
+ uint8_t vref_dq_r0nib15;
+ uint8_t vref_dq_r0nib16;
+ uint8_t vref_dq_r0nib17;
+ uint8_t vref_dq_r0nib18;
+ uint8_t vref_dq_r0nib19;
+ uint8_t vref_dq_r1nib0;
+ uint8_t vref_dq_r1nib1;
+ uint8_t vref_dq_r1nib2;
+ uint8_t vref_dq_r1nib3;
+ uint8_t vref_dq_r1nib4;
+ uint8_t vref_dq_r1nib5;
+ uint8_t vref_dq_r1nib6;
+ uint8_t vref_dq_r1nib7;
+ uint8_t vref_dq_r1nib8;
+ uint8_t vref_dq_r1nib9;
+ uint8_t vref_dq_r1nib10;
+ uint8_t vref_dq_r1nib11;
+ uint8_t vref_dq_r1nib12;
+ uint8_t vref_dq_r1nib13;
+ uint8_t vref_dq_r1nib14;
+ uint8_t vref_dq_r1nib15;
+ uint8_t vref_dq_r1nib16;
+ uint8_t vref_dq_r1nib17;
+ uint8_t vref_dq_r1nib18;
+ uint8_t vref_dq_r1nib19;
+ uint8_t vref_dq_r2nib0;
+ uint8_t vref_dq_r2nib1;
+ uint8_t vref_dq_r2nib2;
+ uint8_t vref_dq_r2nib3;
+ uint8_t vref_dq_r2nib4;
+ uint8_t vref_dq_r2nib5;
+ uint8_t vref_dq_r2nib6;
+ uint8_t vref_dq_r2nib7;
+ uint8_t vref_dq_r2nib8;
+ uint8_t vref_dq_r2nib9;
+ uint8_t vref_dq_r2nib10;
+ uint8_t vref_dq_r2nib11;
+ uint8_t vref_dq_r2nib12;
+ uint8_t vref_dq_r2nib13;
+ uint8_t vref_dq_r2nib14;
+ uint8_t vref_dq_r2nib15;
+ uint8_t vref_dq_r2nib16;
+ uint8_t vref_dq_r2nib17;
+ uint8_t vref_dq_r2nib18;
+ uint8_t vref_dq_r2nib19;
+ uint8_t vref_dq_r3nib0;
+ uint8_t vref_dq_r3nib1;
+ uint8_t vref_dq_r3nib2;
+ uint8_t vref_dq_r3nib3;
+ uint8_t vref_dq_r3nib4;
+ uint8_t vref_dq_r3nib5;
+ uint8_t vref_dq_r3nib6;
+ uint8_t vref_dq_r3nib7;
+ uint8_t vref_dq_r3nib8;
+ uint8_t vref_dq_r3nib9;
+ uint8_t vref_dq_r3nib10;
+ uint8_t vref_dq_r3nib11;
+ uint8_t vref_dq_r3nib12;
+ uint8_t vref_dq_r3nib13;
+ uint8_t vref_dq_r3nib14;
+ uint8_t vref_dq_r3nib15;
+ uint8_t vref_dq_r3nib16;
+ uint8_t vref_dq_r3nib17;
+ uint8_t vref_dq_r3nib18;
+ uint8_t vref_dq_r3nib19;
+ uint8_t f0rc00_d0;
+ uint8_t f0rc01_d0;
+ uint8_t f0rc02_d0;
+ uint8_t f0rc03_d0;
+ uint8_t f0rc04_d0;
+ uint8_t f0rc05_d0;
+ uint8_t f0rc06_d0;
+ uint8_t f0rc07_d0;
+ uint8_t f0rc08_d0;
+ uint8_t f0rc09_d0;
+ uint8_t f0rc0a_d0;
+ uint8_t f0rc0b_d0;
+ uint8_t f0rc0c_d0;
+ uint8_t f0rc0d_d0;
+ uint8_t f0rc0e_d0;
+ uint8_t f0rc0f_d0;
+ uint8_t f0rc1x_d0;
+ uint8_t f0rc2x_d0;
+ uint8_t f0rc3x_d0;
+ uint8_t f0rc4x_d0;
+ uint8_t f0rc5x_d0;
+ uint8_t f0rc6x_d0;
+ uint8_t f0rc7x_d0;
+ uint8_t f0rc8x_d0;
+ uint8_t f0rc9x_d0;
+ uint8_t f0rcax_d0;
+ uint8_t f0rcbx_d0;
+ uint8_t f1rc00_d0;
+ uint8_t f1rc01_d0;
+ uint8_t f1rc02_d0;
+ uint8_t f1rc03_d0;
+ uint8_t f1rc04_d0;
+ uint8_t f1rc05_d0;
+ uint8_t f1rc06_d0;
+ uint8_t f1rc07_d0;
+ uint8_t f1rc08_d0;
+ uint8_t f1rc09_d0;
+ uint8_t f1rc0a_d0;
+ uint8_t f1rc0b_d0;
+ uint8_t f1rc0c_d0;
+ uint8_t f1rc0d_d0;
+ uint8_t f1rc0e_d0;
+ uint8_t f1rc0f_d0;
+ uint8_t f1rc1x_d0;
+ uint8_t f1rc2x_d0;
+ uint8_t f1rc3x_d0;
+ uint8_t f1rc4x_d0;
+ uint8_t f1rc5x_d0;
+ uint8_t f1rc6x_d0;
+ uint8_t f1rc7x_d0;
+ uint8_t f1rc8x_d0;
+ uint8_t f1rc9x_d0;
+ uint8_t f1rcax_d0;
+ uint8_t f1rcbx_d0;
+ uint8_t f0rc00_d1;
+ uint8_t f0rc01_d1;
+ uint8_t f0rc02_d1;
+ uint8_t f0rc03_d1;
+ uint8_t f0rc04_d1;
+ uint8_t f0rc05_d1;
+ uint8_t f0rc06_d1;
+ uint8_t f0rc07_d1;
+ uint8_t f0rc08_d1;
+ uint8_t f0rc09_d1;
+ uint8_t f0rc0a_d1;
+ uint8_t f0rc0b_d1;
+ uint8_t f0rc0c_d1;
+ uint8_t f0rc0d_d1;
+ uint8_t f0rc0e_d1;
+ uint8_t f0rc0f_d1;
+ uint8_t f0rc1x_d1;
+ uint8_t f0rc2x_d1;
+ uint8_t f0rc3x_d1;
+ uint8_t f0rc4x_d1;
+ uint8_t f0rc5x_d1;
+ uint8_t f0rc6x_d1;
+ uint8_t f0rc7x_d1;
+ uint8_t f0rc8x_d1;
+ uint8_t f0rc9x_d1;
+ uint8_t f0rcax_d1;
+ uint8_t f0rcbx_d1;
+ uint8_t f1rc00_d1;
+ uint8_t f1rc01_d1;
+ uint8_t f1rc02_d1;
+ uint8_t f1rc03_d1;
+ uint8_t f1rc04_d1;
+ uint8_t f1rc05_d1;
+ uint8_t f1rc06_d1;
+ uint8_t f1rc07_d1;
+ uint8_t f1rc08_d1;
+ uint8_t f1rc09_d1;
+ uint8_t f1rc0a_d1;
+ uint8_t f1rc0b_d1;
+ uint8_t f1rc0c_d1;
+ uint8_t f1rc0d_d1;
+ uint8_t f1rc0e_d1;
+ uint8_t f1rc0f_d1;
+ uint8_t f1rc1x_d1;
+ uint8_t f1rc2x_d1;
+ uint8_t f1rc3x_d1;
+ uint8_t f1rc4x_d1;
+ uint8_t f1rc5x_d1;
+ uint8_t f1rc6x_d1;
+ uint8_t f1rc7x_d1;
+ uint8_t f1rc8x_d1;
+ uint8_t f1rc9x_d1;
+ uint8_t f1rcax_d1;
+ uint8_t f1rcbx_d1;
+ uint8_t bc00_d0;
+ uint8_t bc01_d0;
+ uint8_t bc02_d0;
+ uint8_t bc03_d0;
+ uint8_t bc04_d0;
+ uint8_t bc05_d0;
+ uint8_t bc06_d0;
+ uint8_t bc07_d0;
+ uint8_t bc08_d0;
+ uint8_t bc09_d0;
+ uint8_t bc0a_d0;
+ uint8_t bc0b_d0;
+ uint8_t bc0c_d0;
+ uint8_t bc0d_d0;
+ uint8_t bc0e_d0;
+ uint8_t f0bc6x_d0;
+ uint8_t f0bccx_d0;
+ uint8_t f0bcdx_d0;
+ uint8_t f0bcex_d0;
+ uint8_t f0bcfx_d0;
+ uint8_t f1bccx_d0;
+ uint8_t f1bcdx_d0;
+ uint8_t f1bcex_d0;
+ uint8_t f1bcfx_d0;
+ uint8_t f0bc2x_b0_d0;
+ uint8_t f0bc3x_b0_d0;
+ uint8_t f0bc4x_b0_d0;
+ uint8_t f0bc5x_b0_d0;
+ uint8_t f0bc8x_b0_d0;
+ uint8_t f0bc9x_b0_d0;
+ uint8_t f0bcax_b0_d0;
+ uint8_t f0bcbx_b0_d0;
+ uint8_t f1bc2x_b0_d0;
+ uint8_t f1bc3x_b0_d0;
+ uint8_t f1bc4x_b0_d0;
+ uint8_t f1bc5x_b0_d0;
+ uint8_t f1bc8x_b0_d0;
+ uint8_t f1bc9x_b0_d0;
+ uint8_t f1bcax_b0_d0;
+ uint8_t f1bcbx_b0_d0;
+ uint8_t f2bc2x_b0_d0;
+ uint8_t f2bc3x_b0_d0;
+ uint8_t f2bc4x_b0_d0;
+ uint8_t f2bc5x_b0_d0;
+ uint8_t f2bc8x_b0_d0;
+ uint8_t f2bc9x_b0_d0;
+ uint8_t f2bcax_b0_d0;
+ uint8_t f2bcbx_b0_d0;
+ uint8_t f3bc2x_b0_d0;
+ uint8_t f3bc3x_b0_d0;
+ uint8_t f3bc4x_b0_d0;
+ uint8_t f3bc5x_b0_d0;
+ uint8_t f3bc8x_b0_d0;
+ uint8_t f3bc9x_b0_d0;
+ uint8_t f3bcax_b0_d0;
+ uint8_t f3bcbx_b0_d0;
+ uint8_t f0bc2x_b1_d0;
+ uint8_t f0bc3x_b1_d0;
+ uint8_t f0bc4x_b1_d0;
+ uint8_t f0bc5x_b1_d0;
+ uint8_t f0bc8x_b1_d0;
+ uint8_t f0bc9x_b1_d0;
+ uint8_t f0bcax_b1_d0;
+ uint8_t f0bcbx_b1_d0;
+ uint8_t f1bc2x_b1_d0;
+ uint8_t f1bc3x_b1_d0;
+ uint8_t f1bc4x_b1_d0;
+ uint8_t f1bc5x_b1_d0;
+ uint8_t f1bc8x_b1_d0;
+ uint8_t f1bc9x_b1_d0;
+ uint8_t f1bcax_b1_d0;
+ uint8_t f1bcbx_b1_d0;
+ uint8_t f2bc2x_b1_d0;
+ uint8_t f2bc3x_b1_d0;
+ uint8_t f2bc4x_b1_d0;
+ uint8_t f2bc5x_b1_d0;
+ uint8_t f2bc8x_b1_d0;
+ uint8_t f2bc9x_b1_d0;
+ uint8_t f2bcax_b1_d0;
+ uint8_t f2bcbx_b1_d0;
+ uint8_t f3bc2x_b1_d0;
+ uint8_t f3bc3x_b1_d0;
+ uint8_t f3bc4x_b1_d0;
+ uint8_t f3bc5x_b1_d0;
+ uint8_t f3bc8x_b1_d0;
+ uint8_t f3bc9x_b1_d0;
+ uint8_t f3bcax_b1_d0;
+ uint8_t f3bcbx_b1_d0;
+ uint8_t f0bc2x_b2_d0;
+ uint8_t f0bc3x_b2_d0;
+ uint8_t f0bc4x_b2_d0;
+ uint8_t f0bc5x_b2_d0;
+ uint8_t f0bc8x_b2_d0;
+ uint8_t f0bc9x_b2_d0;
+ uint8_t f0bcax_b2_d0;
+ uint8_t f0bcbx_b2_d0;
+ uint8_t f1bc2x_b2_d0;
+ uint8_t f1bc3x_b2_d0;
+ uint8_t f1bc4x_b2_d0;
+ uint8_t f1bc5x_b2_d0;
+ uint8_t f1bc8x_b2_d0;
+ uint8_t f1bc9x_b2_d0;
+ uint8_t f1bcax_b2_d0;
+ uint8_t f1bcbx_b2_d0;
+ uint8_t f2bc2x_b2_d0;
+ uint8_t f2bc3x_b2_d0;
+ uint8_t f2bc4x_b2_d0;
+ uint8_t f2bc5x_b2_d0;
+ uint8_t f2bc8x_b2_d0;
+ uint8_t f2bc9x_b2_d0;
+ uint8_t f2bcax_b2_d0;
+ uint8_t f2bcbx_b2_d0;
+ uint8_t f3bc2x_b2_d0;
+ uint8_t f3bc3x_b2_d0;
+ uint8_t f3bc4x_b2_d0;
+ uint8_t f3bc5x_b2_d0;
+ uint8_t f3bc8x_b2_d0;
+ uint8_t f3bc9x_b2_d0;
+ uint8_t f3bcax_b2_d0;
+ uint8_t f3bcbx_b2_d0;
+ uint8_t f0bc2x_b3_d0;
+ uint8_t f0bc3x_b3_d0;
+ uint8_t f0bc4x_b3_d0;
+ uint8_t f0bc5x_b3_d0;
+ uint8_t f0bc8x_b3_d0;
+ uint8_t f0bc9x_b3_d0;
+ uint8_t f0bcax_b3_d0;
+ uint8_t f0bcbx_b3_d0;
+ uint8_t f1bc2x_b3_d0;
+ uint8_t f1bc3x_b3_d0;
+ uint8_t f1bc4x_b3_d0;
+ uint8_t f1bc5x_b3_d0;
+ uint8_t f1bc8x_b3_d0;
+ uint8_t f1bc9x_b3_d0;
+ uint8_t f1bcax_b3_d0;
+ uint8_t f1bcbx_b3_d0;
+ uint8_t f2bc2x_b3_d0;
+ uint8_t f2bc3x_b3_d0;
+ uint8_t f2bc4x_b3_d0;
+ uint8_t f2bc5x_b3_d0;
+ uint8_t f2bc8x_b3_d0;
+ uint8_t f2bc9x_b3_d0;
+ uint8_t f2bcax_b3_d0;
+ uint8_t f2bcbx_b3_d0;
+ uint8_t f3bc2x_b3_d0;
+ uint8_t f3bc3x_b3_d0;
+ uint8_t f3bc4x_b3_d0;
+ uint8_t f3bc5x_b3_d0;
+ uint8_t f3bc8x_b3_d0;
+ uint8_t f3bc9x_b3_d0;
+ uint8_t f3bcax_b3_d0;
+ uint8_t f3bcbx_b3_d0;
+ uint8_t f0bc2x_b4_d0;
+ uint8_t f0bc3x_b4_d0;
+ uint8_t f0bc4x_b4_d0;
+ uint8_t f0bc5x_b4_d0;
+ uint8_t f0bc8x_b4_d0;
+ uint8_t f0bc9x_b4_d0;
+ uint8_t f0bcax_b4_d0;
+ uint8_t f0bcbx_b4_d0;
+ uint8_t f1bc2x_b4_d0;
+ uint8_t f1bc3x_b4_d0;
+ uint8_t f1bc4x_b4_d0;
+ uint8_t f1bc5x_b4_d0;
+ uint8_t f1bc8x_b4_d0;
+ uint8_t f1bc9x_b4_d0;
+ uint8_t f1bcax_b4_d0;
+ uint8_t f1bcbx_b4_d0;
+ uint8_t f2bc2x_b4_d0;
+ uint8_t f2bc3x_b4_d0;
+ uint8_t f2bc4x_b4_d0;
+ uint8_t f2bc5x_b4_d0;
+ uint8_t f2bc8x_b4_d0;
+ uint8_t f2bc9x_b4_d0;
+ uint8_t f2bcax_b4_d0;
+ uint8_t f2bcbx_b4_d0;
+ uint8_t f3bc2x_b4_d0;
+ uint8_t f3bc3x_b4_d0;
+ uint8_t f3bc4x_b4_d0;
+ uint8_t f3bc5x_b4_d0;
+ uint8_t f3bc8x_b4_d0;
+ uint8_t f3bc9x_b4_d0;
+ uint8_t f3bcax_b4_d0;
+ uint8_t f3bcbx_b4_d0;
+ uint8_t f0bc2x_b5_d0;
+ uint8_t f0bc3x_b5_d0;
+ uint8_t f0bc4x_b5_d0;
+ uint8_t f0bc5x_b5_d0;
+ uint8_t f0bc8x_b5_d0;
+ uint8_t f0bc9x_b5_d0;
+ uint8_t f0bcax_b5_d0;
+ uint8_t f0bcbx_b5_d0;
+ uint8_t f1bc2x_b5_d0;
+ uint8_t f1bc3x_b5_d0;
+ uint8_t f1bc4x_b5_d0;
+ uint8_t f1bc5x_b5_d0;
+ uint8_t f1bc8x_b5_d0;
+ uint8_t f1bc9x_b5_d0;
+ uint8_t f1bcax_b5_d0;
+ uint8_t f1bcbx_b5_d0;
+ uint8_t f2bc2x_b5_d0;
+ uint8_t f2bc3x_b5_d0;
+ uint8_t f2bc4x_b5_d0;
+ uint8_t f2bc5x_b5_d0;
+ uint8_t f2bc8x_b5_d0;
+ uint8_t f2bc9x_b5_d0;
+ uint8_t f2bcax_b5_d0;
+ uint8_t f2bcbx_b5_d0;
+ uint8_t f3bc2x_b5_d0;
+ uint8_t f3bc3x_b5_d0;
+ uint8_t f3bc4x_b5_d0;
+ uint8_t f3bc5x_b5_d0;
+ uint8_t f3bc8x_b5_d0;
+ uint8_t f3bc9x_b5_d0;
+ uint8_t f3bcax_b5_d0;
+ uint8_t f3bcbx_b5_d0;
+ uint8_t f0bc2x_b6_d0;
+ uint8_t f0bc3x_b6_d0;
+ uint8_t f0bc4x_b6_d0;
+ uint8_t f0bc5x_b6_d0;
+ uint8_t f0bc8x_b6_d0;
+ uint8_t f0bc9x_b6_d0;
+ uint8_t f0bcax_b6_d0;
+ uint8_t f0bcbx_b6_d0;
+ uint8_t f1bc2x_b6_d0;
+ uint8_t f1bc3x_b6_d0;
+ uint8_t f1bc4x_b6_d0;
+ uint8_t f1bc5x_b6_d0;
+ uint8_t f1bc8x_b6_d0;
+ uint8_t f1bc9x_b6_d0;
+ uint8_t f1bcax_b6_d0;
+ uint8_t f1bcbx_b6_d0;
+ uint8_t f2bc2x_b6_d0;
+ uint8_t f2bc3x_b6_d0;
+ uint8_t f2bc4x_b6_d0;
+ uint8_t f2bc5x_b6_d0;
+ uint8_t f2bc8x_b6_d0;
+ uint8_t f2bc9x_b6_d0;
+ uint8_t f2bcax_b6_d0;
+ uint8_t f2bcbx_b6_d0;
+ uint8_t f3bc2x_b6_d0;
+ uint8_t f3bc3x_b6_d0;
+ uint8_t f3bc4x_b6_d0;
+ uint8_t f3bc5x_b6_d0;
+ uint8_t f3bc8x_b6_d0;
+ uint8_t f3bc9x_b6_d0;
+ uint8_t f3bcax_b6_d0;
+ uint8_t f3bcbx_b6_d0;
+ uint8_t f0bc2x_b7_d0;
+ uint8_t f0bc3x_b7_d0;
+ uint8_t f0bc4x_b7_d0;
+ uint8_t f0bc5x_b7_d0;
+ uint8_t f0bc8x_b7_d0;
+ uint8_t f0bc9x_b7_d0;
+ uint8_t f0bcax_b7_d0;
+ uint8_t f0bcbx_b7_d0;
+ uint8_t f1bc2x_b7_d0;
+ uint8_t f1bc3x_b7_d0;
+ uint8_t f1bc4x_b7_d0;
+ uint8_t f1bc5x_b7_d0;
+ uint8_t f1bc8x_b7_d0;
+ uint8_t f1bc9x_b7_d0;
+ uint8_t f1bcax_b7_d0;
+ uint8_t f1bcbx_b7_d0;
+ uint8_t f2bc2x_b7_d0;
+ uint8_t f2bc3x_b7_d0;
+ uint8_t f2bc4x_b7_d0;
+ uint8_t f2bc5x_b7_d0;
+ uint8_t f2bc8x_b7_d0;
+ uint8_t f2bc9x_b7_d0;
+ uint8_t f2bcax_b7_d0;
+ uint8_t f2bcbx_b7_d0;
+ uint8_t f3bc2x_b7_d0;
+ uint8_t f3bc3x_b7_d0;
+ uint8_t f3bc4x_b7_d0;
+ uint8_t f3bc5x_b7_d0;
+ uint8_t f3bc8x_b7_d0;
+ uint8_t f3bc9x_b7_d0;
+ uint8_t f3bcax_b7_d0;
+ uint8_t f3bcbx_b7_d0;
+ uint8_t f0bc2x_b8_d0;
+ uint8_t f0bc3x_b8_d0;
+ uint8_t f0bc4x_b8_d0;
+ uint8_t f0bc5x_b8_d0;
+ uint8_t f0bc8x_b8_d0;
+ uint8_t f0bc9x_b8_d0;
+ uint8_t f0bcax_b8_d0;
+ uint8_t f0bcbx_b8_d0;
+ uint8_t f1bc2x_b8_d0;
+ uint8_t f1bc3x_b8_d0;
+ uint8_t f1bc4x_b8_d0;
+ uint8_t f1bc5x_b8_d0;
+ uint8_t f1bc8x_b8_d0;
+ uint8_t f1bc9x_b8_d0;
+ uint8_t f1bcax_b8_d0;
+ uint8_t f1bcbx_b8_d0;
+ uint8_t f2bc2x_b8_d0;
+ uint8_t f2bc3x_b8_d0;
+ uint8_t f2bc4x_b8_d0;
+ uint8_t f2bc5x_b8_d0;
+ uint8_t f2bc8x_b8_d0;
+ uint8_t f2bc9x_b8_d0;
+ uint8_t f2bcax_b8_d0;
+ uint8_t f2bcbx_b8_d0;
+ uint8_t f3bc2x_b8_d0;
+ uint8_t f3bc3x_b8_d0;
+ uint8_t f3bc4x_b8_d0;
+ uint8_t f3bc5x_b8_d0;
+ uint8_t f3bc8x_b8_d0;
+ uint8_t f3bc9x_b8_d0;
+ uint8_t f3bcax_b8_d0;
+ uint8_t f3bcbx_b8_d0;
+ uint8_t f5bc5x_d0;
+ uint8_t f5bc6x_d0;
+ uint8_t f4bc8x_d0;
+ uint8_t f4bc9x_d0;
+ uint8_t f4bcax_d0;
+ uint8_t f4bcbx_d0;
+ uint8_t f4bccx_d0;
+ uint8_t f4bcdx_d0;
+ uint8_t f4bcex_d0;
+ uint8_t f4bcfx_d0;
+ uint8_t f5bc8x_d0;
+ uint8_t f5bc9x_d0;
+ uint8_t f5bcax_d0;
+ uint8_t f5bcbx_d0;
+ uint8_t f5bccx_d0;
+ uint8_t f5bcdx_d0;
+ uint8_t f5bcex_d0;
+ uint8_t f5bcfx_d0;
+ uint8_t f6bc8x_d0;
+ uint8_t f6bc9x_d0;
+ uint8_t f6bcax_d0;
+ uint8_t f6bcbx_d0;
+ uint8_t f6bccx_d0;
+ uint8_t f6bcdx_d0;
+ uint8_t f6bcex_d0;
+ uint8_t f6bcfx_d0;
+ uint8_t f7bc8x_d0;
+ uint8_t f7bc9x_d0;
+ uint8_t f7bcax_d0;
+ uint8_t f7bcbx_d0;
+ uint8_t f7bccx_d0;
+ uint8_t f7bcdx_d0;
+ uint8_t f7bcex_d0;
+ uint8_t f7bcfx_d0;
+ uint8_t bc00_d1;
+ uint8_t bc01_d1;
+ uint8_t bc02_d1;
+ uint8_t bc03_d1;
+ uint8_t bc04_d1;
+ uint8_t bc05_d1;
+ uint8_t bc06_d1;
+ uint8_t bc07_d1;
+ uint8_t bc08_d1;
+ uint8_t bc09_d1;
+ uint8_t bc0a_d1;
+ uint8_t bc0b_d1;
+ uint8_t bc0c_d1;
+ uint8_t bc0d_d1;
+ uint8_t bc0e_d1;
+ uint8_t f0bc6x_d1;
+ uint8_t f0bccx_d1;
+ uint8_t f0bcdx_d1;
+ uint8_t f0bcex_d1;
+ uint8_t f0bcfx_d1;
+ uint8_t f1bccx_d1;
+ uint8_t f1bcdx_d1;
+ uint8_t f1bcex_d1;
+ uint8_t f1bcfx_d1;
+ uint8_t f0bc2x_b0_d1;
+ uint8_t f0bc3x_b0_d1;
+ uint8_t f0bc4x_b0_d1;
+ uint8_t f0bc5x_b0_d1;
+ uint8_t f0bc8x_b0_d1;
+ uint8_t f0bc9x_b0_d1;
+ uint8_t f0bcax_b0_d1;
+ uint8_t f0bcbx_b0_d1;
+ uint8_t f1bc2x_b0_d1;
+ uint8_t f1bc3x_b0_d1;
+ uint8_t f1bc4x_b0_d1;
+ uint8_t f1bc5x_b0_d1;
+ uint8_t f1bc8x_b0_d1;
+ uint8_t f1bc9x_b0_d1;
+ uint8_t f1bcax_b0_d1;
+ uint8_t f1bcbx_b0_d1;
+ uint8_t f2bc2x_b0_d1;
+ uint8_t f2bc3x_b0_d1;
+ uint8_t f2bc4x_b0_d1;
+ uint8_t f2bc5x_b0_d1;
+ uint8_t f2bc8x_b0_d1;
+ uint8_t f2bc9x_b0_d1;
+ uint8_t f2bcax_b0_d1;
+ uint8_t f2bcbx_b0_d1;
+ uint8_t f3bc2x_b0_d1;
+ uint8_t f3bc3x_b0_d1;
+ uint8_t f3bc4x_b0_d1;
+ uint8_t f3bc5x_b0_d1;
+ uint8_t f3bc8x_b0_d1;
+ uint8_t f3bc9x_b0_d1;
+ uint8_t f3bcax_b0_d1;
+ uint8_t f3bcbx_b0_d1;
+ uint8_t f0bc2x_b1_d1;
+ uint8_t f0bc3x_b1_d1;
+ uint8_t f0bc4x_b1_d1;
+ uint8_t f0bc5x_b1_d1;
+ uint8_t f0bc8x_b1_d1;
+ uint8_t f0bc9x_b1_d1;
+ uint8_t f0bcax_b1_d1;
+ uint8_t f0bcbx_b1_d1;
+ uint8_t f1bc2x_b1_d1;
+ uint8_t f1bc3x_b1_d1;
+ uint8_t f1bc4x_b1_d1;
+ uint8_t f1bc5x_b1_d1;
+ uint8_t f1bc8x_b1_d1;
+ uint8_t f1bc9x_b1_d1;
+ uint8_t f1bcax_b1_d1;
+ uint8_t f1bcbx_b1_d1;
+ uint8_t f2bc2x_b1_d1;
+ uint8_t f2bc3x_b1_d1;
+ uint8_t f2bc4x_b1_d1;
+ uint8_t f2bc5x_b1_d1;
+ uint8_t f2bc8x_b1_d1;
+ uint8_t f2bc9x_b1_d1;
+ uint8_t f2bcax_b1_d1;
+ uint8_t f2bcbx_b1_d1;
+ uint8_t f3bc2x_b1_d1;
+ uint8_t f3bc3x_b1_d1;
+ uint8_t f3bc4x_b1_d1;
+ uint8_t f3bc5x_b1_d1;
+ uint8_t f3bc8x_b1_d1;
+ uint8_t f3bc9x_b1_d1;
+ uint8_t f3bcax_b1_d1;
+ uint8_t f3bcbx_b1_d1;
+ uint8_t f0bc2x_b2_d1;
+ uint8_t f0bc3x_b2_d1;
+ uint8_t f0bc4x_b2_d1;
+ uint8_t f0bc5x_b2_d1;
+ uint8_t f0bc8x_b2_d1;
+ uint8_t f0bc9x_b2_d1;
+ uint8_t f0bcax_b2_d1;
+ uint8_t f0bcbx_b2_d1;
+ uint8_t f1bc2x_b2_d1;
+ uint8_t f1bc3x_b2_d1;
+ uint8_t f1bc4x_b2_d1;
+ uint8_t f1bc5x_b2_d1;
+ uint8_t f1bc8x_b2_d1;
+ uint8_t f1bc9x_b2_d1;
+ uint8_t f1bcax_b2_d1;
+ uint8_t f1bcbx_b2_d1;
+ uint8_t f2bc2x_b2_d1;
+ uint8_t f2bc3x_b2_d1;
+ uint8_t f2bc4x_b2_d1;
+ uint8_t f2bc5x_b2_d1;
+ uint8_t f2bc8x_b2_d1;
+ uint8_t f2bc9x_b2_d1;
+ uint8_t f2bcax_b2_d1;
+ uint8_t f2bcbx_b2_d1;
+ uint8_t f3bc2x_b2_d1;
+ uint8_t f3bc3x_b2_d1;
+ uint8_t f3bc4x_b2_d1;
+ uint8_t f3bc5x_b2_d1;
+ uint8_t f3bc8x_b2_d1;
+ uint8_t f3bc9x_b2_d1;
+ uint8_t f3bcax_b2_d1;
+ uint8_t f3bcbx_b2_d1;
+ uint8_t f0bc2x_b3_d1;
+ uint8_t f0bc3x_b3_d1;
+ uint8_t f0bc4x_b3_d1;
+ uint8_t f0bc5x_b3_d1;
+ uint8_t f0bc8x_b3_d1;
+ uint8_t f0bc9x_b3_d1;
+ uint8_t f0bcax_b3_d1;
+ uint8_t f0bcbx_b3_d1;
+ uint8_t f1bc2x_b3_d1;
+ uint8_t f1bc3x_b3_d1;
+ uint8_t f1bc4x_b3_d1;
+ uint8_t f1bc5x_b3_d1;
+ uint8_t f1bc8x_b3_d1;
+ uint8_t f1bc9x_b3_d1;
+ uint8_t f1bcax_b3_d1;
+ uint8_t f1bcbx_b3_d1;
+ uint8_t f2bc2x_b3_d1;
+ uint8_t f2bc3x_b3_d1;
+ uint8_t f2bc4x_b3_d1;
+ uint8_t f2bc5x_b3_d1;
+ uint8_t f2bc8x_b3_d1;
+ uint8_t f2bc9x_b3_d1;
+ uint8_t f2bcax_b3_d1;
+ uint8_t f2bcbx_b3_d1;
+ uint8_t f3bc2x_b3_d1;
+ uint8_t f3bc3x_b3_d1;
+ uint8_t f3bc4x_b3_d1;
+ uint8_t f3bc5x_b3_d1;
+ uint8_t f3bc8x_b3_d1;
+ uint8_t f3bc9x_b3_d1;
+ uint8_t f3bcax_b3_d1;
+ uint8_t f3bcbx_b3_d1;
+ uint8_t f0bc2x_b4_d1;
+ uint8_t f0bc3x_b4_d1;
+ uint8_t f0bc4x_b4_d1;
+ uint8_t f0bc5x_b4_d1;
+ uint8_t f0bc8x_b4_d1;
+ uint8_t f0bc9x_b4_d1;
+ uint8_t f0bcax_b4_d1;
+ uint8_t f0bcbx_b4_d1;
+ uint8_t f1bc2x_b4_d1;
+ uint8_t f1bc3x_b4_d1;
+ uint8_t f1bc4x_b4_d1;
+ uint8_t f1bc5x_b4_d1;
+ uint8_t f1bc8x_b4_d1;
+ uint8_t f1bc9x_b4_d1;
+ uint8_t f1bcax_b4_d1;
+ uint8_t f1bcbx_b4_d1;
+ uint8_t f2bc2x_b4_d1;
+ uint8_t f2bc3x_b4_d1;
+ uint8_t f2bc4x_b4_d1;
+ uint8_t f2bc5x_b4_d1;
+ uint8_t f2bc8x_b4_d1;
+ uint8_t f2bc9x_b4_d1;
+ uint8_t f2bcax_b4_d1;
+ uint8_t f2bcbx_b4_d1;
+ uint8_t f3bc2x_b4_d1;
+ uint8_t f3bc3x_b4_d1;
+ uint8_t f3bc4x_b4_d1;
+ uint8_t f3bc5x_b4_d1;
+ uint8_t f3bc8x_b4_d1;
+ uint8_t f3bc9x_b4_d1;
+ uint8_t f3bcax_b4_d1;
+ uint8_t f3bcbx_b4_d1;
+ uint8_t f0bc2x_b5_d1;
+ uint8_t f0bc3x_b5_d1;
+ uint8_t f0bc4x_b5_d1;
+ uint8_t f0bc5x_b5_d1;
+ uint8_t f0bc8x_b5_d1;
+ uint8_t f0bc9x_b5_d1;
+ uint8_t f0bcax_b5_d1;
+ uint8_t f0bcbx_b5_d1;
+ uint8_t f1bc2x_b5_d1;
+ uint8_t f1bc3x_b5_d1;
+ uint8_t f1bc4x_b5_d1;
+ uint8_t f1bc5x_b5_d1;
+ uint8_t f1bc8x_b5_d1;
+ uint8_t f1bc9x_b5_d1;
+ uint8_t f1bcax_b5_d1;
+ uint8_t f1bcbx_b5_d1;
+ uint8_t f2bc2x_b5_d1;
+ uint8_t f2bc3x_b5_d1;
+ uint8_t f2bc4x_b5_d1;
+ uint8_t f2bc5x_b5_d1;
+ uint8_t f2bc8x_b5_d1;
+ uint8_t f2bc9x_b5_d1;
+ uint8_t f2bcax_b5_d1;
+ uint8_t f2bcbx_b5_d1;
+ uint8_t f3bc2x_b5_d1;
+ uint8_t f3bc3x_b5_d1;
+ uint8_t f3bc4x_b5_d1;
+ uint8_t f3bc5x_b5_d1;
+ uint8_t f3bc8x_b5_d1;
+ uint8_t f3bc9x_b5_d1;
+ uint8_t f3bcax_b5_d1;
+ uint8_t f3bcbx_b5_d1;
+ uint8_t f0bc2x_b6_d1;
+ uint8_t f0bc3x_b6_d1;
+ uint8_t f0bc4x_b6_d1;
+ uint8_t f0bc5x_b6_d1;
+ uint8_t f0bc8x_b6_d1;
+ uint8_t f0bc9x_b6_d1;
+ uint8_t f0bcax_b6_d1;
+ uint8_t f0bcbx_b6_d1;
+ uint8_t f1bc2x_b6_d1;
+ uint8_t f1bc3x_b6_d1;
+ uint8_t f1bc4x_b6_d1;
+ uint8_t f1bc5x_b6_d1;
+ uint8_t f1bc8x_b6_d1;
+ uint8_t f1bc9x_b6_d1;
+ uint8_t f1bcax_b6_d1;
+ uint8_t f1bcbx_b6_d1;
+ uint8_t f2bc2x_b6_d1;
+ uint8_t f2bc3x_b6_d1;
+ uint8_t f2bc4x_b6_d1;
+ uint8_t f2bc5x_b6_d1;
+ uint8_t f2bc8x_b6_d1;
+ uint8_t f2bc9x_b6_d1;
+ uint8_t f2bcax_b6_d1;
+ uint8_t f2bcbx_b6_d1;
+ uint8_t f3bc2x_b6_d1;
+ uint8_t f3bc3x_b6_d1;
+ uint8_t f3bc4x_b6_d1;
+ uint8_t f3bc5x_b6_d1;
+ uint8_t f3bc8x_b6_d1;
+ uint8_t f3bc9x_b6_d1;
+ uint8_t f3bcax_b6_d1;
+ uint8_t f3bcbx_b6_d1;
+ uint8_t f0bc2x_b7_d1;
+ uint8_t f0bc3x_b7_d1;
+ uint8_t f0bc4x_b7_d1;
+ uint8_t f0bc5x_b7_d1;
+ uint8_t f0bc8x_b7_d1;
+ uint8_t f0bc9x_b7_d1;
+ uint8_t f0bcax_b7_d1;
+ uint8_t f0bcbx_b7_d1;
+ uint8_t f1bc2x_b7_d1;
+ uint8_t f1bc3x_b7_d1;
+ uint8_t f1bc4x_b7_d1;
+ uint8_t f1bc5x_b7_d1;
+ uint8_t f1bc8x_b7_d1;
+ uint8_t f1bc9x_b7_d1;
+ uint8_t f1bcax_b7_d1;
+ uint8_t f1bcbx_b7_d1;
+ uint8_t f2bc2x_b7_d1;
+ uint8_t f2bc3x_b7_d1;
+ uint8_t f2bc4x_b7_d1;
+ uint8_t f2bc5x_b7_d1;
+ uint8_t f2bc8x_b7_d1;
+ uint8_t f2bc9x_b7_d1;
+ uint8_t f2bcax_b7_d1;
+ uint8_t f2bcbx_b7_d1;
+ uint8_t f3bc2x_b7_d1;
+ uint8_t f3bc3x_b7_d1;
+ uint8_t f3bc4x_b7_d1;
+ uint8_t f3bc5x_b7_d1;
+ uint8_t f3bc8x_b7_d1;
+ uint8_t f3bc9x_b7_d1;
+ uint8_t f3bcax_b7_d1;
+ uint8_t f3bcbx_b7_d1;
+ uint8_t f0bc2x_b8_d1;
+ uint8_t f0bc3x_b8_d1;
+ uint8_t f0bc4x_b8_d1;
+ uint8_t f0bc5x_b8_d1;
+ uint8_t f0bc8x_b8_d1;
+ uint8_t f0bc9x_b8_d1;
+ uint8_t f0bcax_b8_d1;
+ uint8_t f0bcbx_b8_d1;
+ uint8_t f1bc2x_b8_d1;
+ uint8_t f1bc3x_b8_d1;
+ uint8_t f1bc4x_b8_d1;
+ uint8_t f1bc5x_b8_d1;
+ uint8_t f1bc8x_b8_d1;
+ uint8_t f1bc9x_b8_d1;
+ uint8_t f1bcax_b8_d1;
+ uint8_t f1bcbx_b8_d1;
+ uint8_t f2bc2x_b8_d1;
+ uint8_t f2bc3x_b8_d1;
+ uint8_t f2bc4x_b8_d1;
+ uint8_t f2bc5x_b8_d1;
+ uint8_t f2bc8x_b8_d1;
+ uint8_t f2bc9x_b8_d1;
+ uint8_t f2bcax_b8_d1;
+ uint8_t f2bcbx_b8_d1;
+ uint8_t f3bc2x_b8_d1;
+ uint8_t f3bc3x_b8_d1;
+ uint8_t f3bc4x_b8_d1;
+ uint8_t f3bc5x_b8_d1;
+ uint8_t f3bc8x_b8_d1;
+ uint8_t f3bc9x_b8_d1;
+ uint8_t f3bcax_b8_d1;
+ uint8_t f3bcbx_b8_d1;
+ uint8_t f5bc5x_d1;
+ uint8_t f5bc6x_d1;
+ uint8_t f4bc8x_d1;
+ uint8_t f4bc9x_d1;
+ uint8_t f4bcax_d1;
+ uint8_t f4bcbx_d1;
+ uint8_t f4bccx_d1;
+ uint8_t f4bcdx_d1;
+ uint8_t f4bcex_d1;
+ uint8_t f4bcfx_d1;
+ uint8_t f5bc8x_d1;
+ uint8_t f5bc9x_d1;
+ uint8_t f5bcax_d1;
+ uint8_t f5bcbx_d1;
+ uint8_t f5bccx_d1;
+ uint8_t f5bcdx_d1;
+ uint8_t f5bcex_d1;
+ uint8_t f5bcfx_d1;
+ uint8_t f6bc8x_d1;
+ uint8_t f6bc9x_d1;
+ uint8_t f6bcax_d1;
+ uint8_t f6bcbx_d1;
+ uint8_t f6bccx_d1;
+ uint8_t f6bcdx_d1;
+ uint8_t f6bcex_d1;
+ uint8_t f6bcfx_d1;
+ uint8_t f7bc8x_d1;
+ uint8_t f7bc9x_d1;
+ uint8_t f7bcax_d1;
+ uint8_t f7bcbx_d1;
+ uint8_t f7bccx_d1;
+ uint8_t f7bcdx_d1;
+ uint8_t f7bcex_d1;
+ uint8_t f7bcfx_d1;
+ uint16_t alt_cas_l;
+ uint8_t alt_wcas_l;
+ uint8_t d4misc;
+} __packed;
+#endif
diff --git a/drivers/nxp/ddr/phy-gen2/ddrphy.mk b/drivers/nxp/ddr/phy-gen2/ddrphy.mk
new file mode 100644
index 0000000..ba5c774
--- /dev/null
+++ b/drivers/nxp/ddr/phy-gen2/ddrphy.mk
@@ -0,0 +1,20 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+#-----------------------------------------------------------------------------
+
+# SNPS ddr phy driver files
+
+DDR_PHY_C =
+DDR_PHY_H =
+
+$(DDR_PHY_C): $(DDR_PHY_H) $(COMMON_HDRS) src
+ @cp -r "$(DDR_PHY_PATH)/$@" "$(SRC_DIR)/$@"
+
+$(DDR_PHY_H): src
+ @cp -r "$(DDR_PHY_PATH)/$@" "$(SRC_DIR)/$@"
+
+#------------------------------------------------
diff --git a/drivers/nxp/ddr/phy-gen2/input.h b/drivers/nxp/ddr/phy-gen2/input.h
new file mode 100644
index 0000000..dbcd1ae
--- /dev/null
+++ b/drivers/nxp/ddr/phy-gen2/input.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2021 NXP
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef _INPUT_H_
+#define _INPUT_H_
+
+enum dram_types {
+ DDR4,
+ DDR3,
+ LPDDR4,
+ LPDDR3,
+ LPDDR2,
+ DDR5,
+};
+
+enum dimm_types {
+ UDIMM,
+ SODIMM,
+ RDIMM,
+ LRDIMM,
+ NODIMM,
+};
+
+struct input_basic {
+ enum dram_types dram_type;
+ enum dimm_types dimm_type;
+ int lp4x_mode; /* 0x1 = lpddr4x mode, when dram_type is lpddr4
+ */
+ /* not used for protocols other than lpddr4 */
+ int num_dbyte; /* number of dbytes physically instantiated */
+ int num_active_dbyte_dfi0; /* number of active dbytes to be
+ * controlled by dfi0
+ */
+ int num_active_dbyte_dfi1; /* number of active dbytes to be
+ * controlled by dfi1. Not used for
+ * protocols other than lpddr3 and
+ * lpddr4
+ */
+ int num_anib; /* number of anibs physically instantiated */
+ int num_rank_dfi0; /* number of ranks in dfi0 channel */
+ int num_rank_dfi1; /* number of ranks in dfi1 channel */
+ int dram_data_width; /* 4,8,16 or 32 depending on protocol and dram
+ * type
+ */
+ int num_pstates;
+ int frequency; /* memclk frequency in mhz -- round up */
+ int pll_bypass; /* pll bypass enable */
+ int dfi_freq_ratio; /* selected dfi frequency ratio */
+ int dfi1exists; /* whether they phy config has dfi1 channel */
+ int train2d;
+ int hard_macro_ver;
+ int read_dbienable;
+ int dfi_mode; /* no longer used */
+};
+
+struct input_advanced {
+ int d4rx_preamble_length;
+ int d4tx_preamble_length;
+ int ext_cal_res_val; /* external pull-down resistor */
+ int is2ttiming;
+ int odtimpedance;
+ int tx_impedance;
+ int atx_impedance;
+ int mem_alert_en;
+ int mem_alert_puimp;
+ int mem_alert_vref_level;
+ int mem_alert_sync_bypass;
+ int dis_dyn_adr_tri;
+ int phy_mstr_train_interval;
+ int phy_mstr_max_req_to_ack;
+ int wdqsext;
+ int cal_interval;
+ int cal_once;
+ int dram_byte_swap;
+ int rx_en_back_off;
+ int train_sequence_ctrl;
+ int phy_gen2_umctl_opt;
+ int phy_gen2_umctl_f0rc5x;
+ int tx_slew_rise_dq;
+ int tx_slew_fall_dq;
+ int tx_slew_rise_ac;
+ int tx_slew_fall_ac;
+ int enable_high_clk_skew_fix;
+ int disable_unused_addr_lns;
+ int phy_init_sequence_num;
+ int cs_mode; /* rdimm */
+ int cast_cs_to_cid; /* rdimm */
+};
+
+struct input {
+ struct input_basic basic;
+ struct input_advanced adv;
+ unsigned int mr[7];
+ unsigned int cs_d0;
+ unsigned int cs_d1;
+ unsigned int mirror;
+ unsigned int odt[4];
+ unsigned int rcw[16];
+ unsigned int rcw3x;
+ unsigned int vref;
+};
+
+#endif
diff --git a/drivers/nxp/ddr/phy-gen2/messages.h b/drivers/nxp/ddr/phy-gen2/messages.h
new file mode 100644
index 0000000..7dec7df
--- /dev/null
+++ b/drivers/nxp/ddr/phy-gen2/messages.h
@@ -0,0 +1,2909 @@
+/*
+ * Copyright 2021 NXP
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef MESSAGE_H
+#define MESSAGE_H
+
+#ifdef DEBUG
+struct phy_msg {
+ uint32_t index;
+ const char *msg;
+};
+
+const static struct phy_msg messages_1d[] = {
+ {0x00000001,
+ "PMU1:prbsGenCtl:%x\n"
+ },
+ {0x00010000,
+ "PMU1: loading 2D acsm sequence\n"
+ },
+ {0x00020000,
+ "PMU1: loading 1D acsm sequence\n"
+ },
+ {0x00030002,
+ "PMU3: %d memclocks @ %d to get half of 300ns\n"
+ },
+ {0x00040000,
+ "PMU: Error: User requested MPR read pattern for read DQS training in DDR3 Mode\n"
+ },
+ {0x00050000,
+ "PMU3: Running 1D search for left eye edge\n"
+ },
+ {0x00060001,
+ "PMU1: In Phase Left Edge Search cs %d\n"
+ },
+ {0x00070001,
+ "PMU1: Out of Phase Left Edge Search cs %d\n"
+ },
+ {0x00080000,
+ "PMU3: Running 1D search for right eye edge\n"
+ },
+ {0x00090001,
+ "PMU1: In Phase Right Edge Search cs %d\n"
+ },
+ {0x000a0001,
+ "PMU1: Out of Phase Right Edge Search cs %d\n"
+ },
+ {0x000b0001,
+ "PMU1: mxRdLat training pstate %d\n"
+ },
+ {0x000c0001,
+ "PMU1: mxRdLat search for cs %d\n"
+ },
+ {0x000d0001,
+ "PMU0: MaxRdLat non consistent DtsmLoThldXingInd 0x%03x\n"
+ },
+ {0x000e0003,
+ "PMU4: CS %d Dbyte %d worked with DFIMRL = %d DFICLKs\n"
+ },
+ {0x000f0004,
+ "PMU3: MaxRdLat Read Lane err mask for csn %d, DFIMRL %2d DFIClks, dbyte %d = 0x%03x\n"
+ },
+ {0x00100003,
+ "PMU3: MaxRdLat Read Lane err mask for csn %d DFIMRL %2d, All dbytes = 0x%03x\n"
+ },
+ {0x00110001,
+ "PMU: Error: CS%d failed to find a DFIMRL setting that worked for all bytes during MaxRdLat training\n"
+ },
+ {0x00120002,
+ "PMU3: Smallest passing DFIMRL for all dbytes in CS%d = %d DFIClks\n"
+ },
+ {0x00130000,
+ "PMU: Error: No passing DFIMRL value found for any chip select during MaxRdLat training\n"
+ },
+ {0x00140003,
+ "PMU: Error: Dbyte %d lane %d txDqDly passing region is too small (width = %d)\n"
+ },
+ {0x00150006,
+ "PMU10: Adjusting rxclkdly db %d nib %d from %d+%d=%d->%d\n"
+ },
+ {0x00160000,
+ "PMU4: TxDqDly Passing Regions (EyeLeft EyeRight -> EyeCenter) Units=1/32 UI\n"
+ },
+ {0x00170005,
+ "PMU4: DB %d Lane %d: %3d %3d -> %3d\n"
+ },
+ {0x00180002,
+ "PMU2: TXDQ delayLeft[%2d] = %3d (DISCONNECTED)\n"
+ },
+ {0x00190004,
+ "PMU2: TXDQ delayLeft[%2d] = %3d oopScaled = %3d selectOop %d\n"
+ },
+ {0x001a0002,
+ "PMU2: TXDQ delayRight[%2d] = %3d (DISCONNECTED)\n"
+ },
+ {0x001b0004,
+ "PMU2: TXDQ delayRight[%2d] = %3d oopScaled = %3d selectOop %d\n"
+ },
+ {0x001c0003,
+ "PMU: Error: Dbyte %d lane %d txDqDly passing region is too small (width = %d)\n"
+ },
+ {0x001d0000,
+ "PMU4: TxDqDly Passing Regions (EyeLeft EyeRight -> EyeCenter) Units=1/32 UI\n"
+ },
+ {0x001e0002,
+ "PMU4: DB %d Lane %d: (DISCONNECTED)\n"
+ },
+ {0x001f0005,
+ "PMU4: DB %d Lane %d: %3d %3d -> %3d\n"
+ },
+ {0x00200002,
+ "PMU3: Running 1D search csn %d for DM Right/NotLeft(%d) eye edge\n"
+ },
+ {0x00210002,
+ "PMU3: WrDq DM byte%2d with Errcnt %d\n"
+ },
+ {0x00220002,
+ "PMU3: WrDq DM byte%2d avgDly 0x%04x\n"
+ },
+ {0x00230002,
+ "PMU1: WrDq DM byte%2d with Errcnt %d\n"
+ },
+ {0x00240001,
+ "PMU: Error: Dbyte %d txDqDly DM training did not start inside the eye\n"
+ },
+ {0x00250000,
+ "PMU4: DM TxDqDly Passing Regions (EyeLeft EyeRight -> EyeCenter) Units=1/32 UI\n"
+ },
+ {0x00260002,
+ "PMU4: DB %d Lane %d: (DISCONNECTED)\n"
+ },
+ {0x00270005,
+ "PMU4: DB %d Lane %d: %3d %3d -> %3d\n"
+ },
+ {0x00280003,
+ "PMU: Error: Dbyte %d lane %d txDqDly DM passing region is too small (width = %d)\n"
+ },
+ {0x00290004,
+ "PMU3: Errcnt for MRD/MWD search nib %2d delay = (%d, 0x%02x) = %d\n"
+ },
+ {0x002a0000,
+ "PMU3: Precharge all open banks\n"
+ },
+ {0x002b0002,
+ "PMU: Error: Dbyte %d nibble %d found mutliple working coarse delay setting for MRD/MWD\n"
+ },
+ {0x002c0000,
+ "PMU4: MRD Passing Regions (coarseVal, fineLeft fineRight -> fineCenter)\n"
+ },
+ {0x002d0000,
+ "PMU4: MWD Passing Regions (coarseVal, fineLeft fineRight -> fineCenter)\n"
+ },
+ {0x002e0004,
+ "PMU10: Warning: DB %d nibble %d has multiple working coarse delays, %d and %d, choosing the smaller delay\n"
+ },
+ {0x002f0003,
+ "PMU: Error: Dbyte %d nibble %d MRD/MWD passing region is too small (width = %d)\n"
+ },
+ {0x00300006,
+ "PMU4: DB %d nibble %d: %3d, %3d %3d -> %3d\n"
+ },
+ {0x00310002,
+ "PMU1: Start MRD/nMWD %d for csn %d\n"
+ },
+ {0x00320002,
+ "PMU2: RXDQS delayLeft[%2d] = %3d (DISCONNECTED)\n"
+ },
+ {0x00330006,
+ "PMU2: RXDQS delayLeft[%2d] = %3d delayOop[%2d] = %3d OopScaled %4d, selectOop %d\n"
+ },
+ {0x00340002,
+ "PMU2: RXDQS delayRight[%2d] = %3d (DISCONNECTED)\n"
+ },
+ {0x00350006,
+ "PMU2: RXDQS delayRight[%2d] = %3d delayOop[%2d] = %4d OopScaled %4d, selectOop %d\n"
+ },
+ {0x00360000,
+ "PMU4: RxClkDly Passing Regions (EyeLeft EyeRight -> EyeCenter)\n"
+ },
+ {0x00370002,
+ "PMU4: DB %d nibble %d: (DISCONNECTED)\n"
+ },
+ {0x00380005,
+ "PMU4: DB %d nibble %d: %3d %3d -> %3d\n"
+ },
+ {0x00390003,
+ "PMU: Error: Dbyte %d nibble %d rxClkDly passing region is too small (width = %d)\n"
+ },
+ {0x003a0002,
+ "PMU0: goodbar = %d for RDWR_BLEN %d\n"
+ },
+ {0x003b0001,
+ "PMU3: RxClkDly = %d\n"
+ },
+ {0x003c0005,
+ "PMU0: db %d l %d absLane %d -> bottom %d top %d\n"
+ },
+ {0x003d0009,
+ "PMU3: BYTE %d - %3d %3d %3d %3d %3d %3d %3d %3d\n"
+ },
+ {0x003e0002,
+ "PMU: Error: dbyte %d lane %d's per-lane vrefDAC's had no passing region\n"
+ },
+ {0x003f0004,
+ "PMU0: db%d l%d - %d %d\n"
+ },
+ {0x00400002,
+ "PMU0: goodbar = %d for RDWR_BLEN %d\n"
+ },
+ {0x00410004,
+ "PMU3: db%d l%d saw %d issues at rxClkDly %d\n"
+ },
+ {0x00420003,
+ "PMU3: db%d l%d first saw a pass->fail edge at rxClkDly %d\n"
+ },
+ {0x00430002,
+ "PMU3: lane %d PBD = %d\n"
+ },
+ {0x00440003,
+ "PMU3: db%d l%d first saw a DBI pass->fail edge at rxClkDly %d\n"
+ },
+ {0x00450003,
+ "PMU2: db%d l%d already passed rxPBD = %d\n"
+ },
+ {0x00460003,
+ "PMU0: db%d l%d, PBD = %d\n"
+ },
+ {0x00470002,
+ "PMU: Error: dbyte %d lane %d failed read deskew\n"
+ },
+ {0x00480003,
+ "PMU0: db%d l%d, inc PBD = %d\n"
+ },
+ {0x00490003,
+ "PMU1: Running lane deskew on pstate %d csn %d rdDBIEn %d\n"
+ },
+ {0x004a0000,
+ "PMU: Error: Read deskew training has been requested, but csrMajorModeDbyte[2] is set\n"
+ },
+ {0x004b0002,
+ "PMU1: AcsmCsMapCtrl%02d 0x%04x\n"
+ },
+ {0x004c0002,
+ "PMU1: AcsmCsMapCtrl%02d 0x%04x\n"
+ },
+ {0x004d0001,
+ "PMU: Error: Wrong PMU image loaded. message Block DramType = 0x%02x, but image built for D3U Type\n"
+ },
+ {0x004e0001,
+ "PMU: Error: Wrong PMU image loaded. message Block DramType = 0x%02x, but image built for D3R Type\n"
+ },
+ {0x004f0001,
+ "PMU: Error: Wrong PMU image loaded. message Block DramType = 0x%02x, but image built for D4U Type\n"
+ },
+ {0x00500001,
+ "PMU: Error: Wrong PMU image loaded. message Block DramType = 0x%02x, but image built for D4R Type\n"
+ },
+ {0x00510001,
+ "PMU: Error: Wrong PMU image loaded. message Block DramType = 0x%02x, but image built for D4LR Type\n"
+ },
+ {0x00520000,
+ "PMU: Error: Both 2t timing mode and ddr4 geardown mode specified in the messageblock's PhyCfg and MR3 fields. Only one can be enabled\n"
+ },
+ {0x00530003,
+ "PMU10: PHY TOTALS - NUM_DBYTES %d NUM_NIBBLES %d NUM_ANIBS %d\n"
+ },
+ {0x00540006,
+ "PMU10: CSA=0x%02x, CSB=0x%02x, TSTAGES=0x%04x, HDTOUT=%d, MMISC=%d DRAMFreq=%dMT DramType=LPDDR3\n"
+ },
+ {0x00550006,
+ "PMU10: CSA=0x%02x, CSB=0x%02x, TSTAGES=0x%04x, HDTOUT=%d, MMISC=%d DRAMFreq=%dMT DramType=LPDDR4\n"
+ },
+ {0x00560008,
+ "PMU10: CS=0x%02x, TSTAGES=0x%04x, HDTOUT=%d, 2T=%d, MMISC=%d AddrMirror=%d DRAMFreq=%dMT DramType=%d\n"
+ },
+ {0x00570004,
+ "PMU10: Pstate%d MR0=0x%04x MR1=0x%04x MR2=0x%04x\n"
+ },
+ {0x00580008,
+ "PMU10: Pstate%d MRS MR0=0x%04x MR1=0x%04x MR2=0x%04x MR3=0x%04x MR4=0x%04x MR5=0x%04x MR6=0x%04x\n"
+ },
+ {0x00590005,
+ "PMU10: Pstate%d MRS MR1_A0=0x%04x MR2_A0=0x%04x MR3_A0=0x%04x MR11_A0=0x%04x\n"
+ },
+ {0x005a0000,
+ "PMU10: UseBroadcastMR set. All ranks and channels use MRXX_A0 for MR settings.\n"
+ },
+ {0x005b0005,
+ "PMU10: Pstate%d MRS MR01_A0=0x%02x MR02_A0=0x%02x MR03_A0=0x%02x MR11_A0=0x%02x\n"
+ },
+ {0x005c0005,
+ "PMU10: Pstate%d MRS MR12_A0=0x%02x MR13_A0=0x%02x MR14_A0=0x%02x MR22_A0=0x%02x\n"
+ },
+ {0x005d0005,
+ "PMU10: Pstate%d MRS MR01_A1=0x%02x MR02_A1=0x%02x MR03_A1=0x%02x MR11_A1=0x%02x\n"
+ },
+ {0x005e0005,
+ "PMU10: Pstate%d MRS MR12_A1=0x%02x MR13_A1=0x%02x MR14_A1=0x%02x MR22_A1=0x%02x\n"
+ },
+ {0x005f0005,
+ "PMU10: Pstate%d MRS MR01_B0=0x%02x MR02_B0=0x%02x MR03_B0=0x%02x MR11_B0=0x%02x\n"
+ },
+ {0x00600005,
+ "PMU10: Pstate%d MRS MR12_B0=0x%02x MR13_B0=0x%02x MR14_B0=0x%02x MR22_B0=0x%02x\n"
+ },
+ {0x00610005,
+ "PMU10: Pstate%d MRS MR01_B1=0x%02x MR02_B1=0x%02x MR03_B1=0x%02x MR11_B1=0x%02x\n"
+ },
+ {0x00620005,
+ "PMU10: Pstate%d MRS MR12_B1=0x%02x MR13_B1=0x%02x MR14_B1=0x%02x MR22_B1=0x%02x\n"
+ },
+ {0x00630002,
+ "PMU1: AcsmOdtCtrl%02d 0x%02x\n"
+ },
+ {0x00640002,
+ "PMU1: AcsmCsMapCtrl%02d 0x%04x\n"
+ },
+ {0x00650002,
+ "PMU1: AcsmCsMapCtrl%02d 0x%04x\n"
+ },
+ {0x00660000,
+ "PMU1: HwtCAMode set\n"
+ },
+ {0x00670001,
+ "PMU3: DDR4 infinite preamble enter/exit mode %d\n"
+ },
+ {0x00680002,
+ "PMU1: In rxenb_train() csn=%d pstate=%d\n"
+ },
+ {0x00690000,
+ "PMU3: Finding DQS falling edge\n"
+ },
+ {0x006a0000,
+ "PMU3: Searching for DDR3/LPDDR3/LPDDR4 read preamble\n"
+ },
+ {0x006b0009,
+ "PMU3: dtsm fails Even Nibbles : %2x %2x %2x %2x %2x %2x %2x %2x %2x\n"
+ },
+ {0x006c0009,
+ "PMU3: dtsm fails Odd Nibbles : %2x %2x %2x %2x %2x %2x %2x %2x %2x\n"
+ },
+ {0x006d0002,
+ "PMU3: Preamble search pass=%d anyfail=%d\n"
+ },
+ {0x006e0000,
+ "PMU: Error: RxEn training preamble not found\n"
+ },
+ {0x006f0000,
+ "PMU3: Found DQS pre-amble\n"
+ },
+ {0x00700001,
+ "PMU: Error: Dbyte %d couldn't find the rising edge of DQS during RxEn Training\n"
+ },
+ {0x00710000,
+ "PMU3: RxEn aligning to first rising edge of burst\n"
+ },
+ {0x00720001,
+ "PMU3: Decreasing RxEn delay by %d fine step to allow full capture of reads\n"
+ },
+ {0x00730001,
+ "PMU3: MREP Delay = %d\n"
+ },
+ {0x00740003,
+ "PMU3: Errcnt for MREP nib %2d delay = %2d is %d\n"
+ },
+ {0x00750002,
+ "PMU3: MREP nibble %d sampled a 1 at data buffer delay %d\n"
+ },
+ {0x00760002,
+ "PMU3: MREP nibble %d saw a 0 to 1 transition at data buffer delay %d\n"
+ },
+ {0x00770000,
+ "PMU2: MREP did not find a 0 to 1 transition for all nibbles. Failing nibbles assumed to have rising edge close to fine delay 63\n"
+ },
+ {0x00780002,
+ "PMU2: Rising edge found in alias window, setting rxDly for nibble %d = %d\n"
+ },
+ {0x00790002,
+ "PMU: Error: Failed MREP for nib %d with %d one\n"
+ },
+ {0x007a0003,
+ "PMU2: Rising edge not found in alias window with %d one, leaving rxDly for nibble %d = %d\n"
+ },
+ {0x007b0002,
+ "PMU3: Training DIMM %d CSn %d\n"
+ },
+ {0x007c0001,
+ "PMU3: exitCAtrain_lp3 cs 0x%x\n"
+ },
+ {0x007d0001,
+ "PMU3: enterCAtrain_lp3 cs 0x%x\n"
+ },
+ {0x007e0001,
+ "PMU3: CAtrain_switchmsb_lp3 cs 0x%x\n"
+ },
+ {0x007f0001,
+ "PMU3: CATrain_rdwr_lp3 looking for pattern %x\n"
+ },
+ {0x00800000,
+ "PMU3: exitCAtrain_lp4\n"
+ },
+ {0x00810001,
+ "PMU3: DEBUG enterCAtrain_lp4 1: cs 0x%x\n"
+ },
+ {0x00820001,
+ "PMU3: DEBUG enterCAtrain_lp4 3: Put dbyte %d in async mode\n"
+ },
+ {0x00830000,
+ "PMU3: DEBUG enterCAtrain_lp4 5: Send MR13 to turn on CA training\n"
+ },
+ {0x00840003,
+ "PMU3: DEBUG enterCAtrain_lp4 7: idx = %d vref = %x mr12 = %x\n"
+ },
+ {0x00850001,
+ "PMU3: CATrain_rdwr_lp4 looking for pattern %x\n"
+ },
+ {0x00860004,
+ "PMU3: Phase %d CAreadbackA db:%d %x xo:%x\n"
+ },
+ {0x00870005,
+ "PMU3: DEBUG lp4SetCatrVref 1: cs=%d chan=%d mr12=%x vref=%d.%d%%\n"
+ },
+ {0x00880003,
+ "PMU3: DEBUG lp4SetCatrVref 3: mr12 = %x send vref= %x to db=%d\n"
+ },
+ {0x00890000,
+ "PMU10:Optimizing vref\n"
+ },
+ {0x008a0004,
+ "PMU4:mr12:%2x cs:%d chan %d r:%4x\n"
+ },
+ {0x008b0005,
+ "PMU3: i:%2d bstr:%2d bsto:%2d st:%d r:%d\n"
+ },
+ {0x008c0002,
+ "Failed to find sufficient CA Vref Passing Region for CS %d ch. %d\n"
+ },
+ {0x008d0005,
+ "PMU3:Found %d.%d%% MR12:%x for cs:%d chan %d\n"
+ },
+ {0x008e0002,
+ "PMU3:Calculated %d for AtxImpedence from acx %d.\n"
+ },
+ {0x008f0000,
+ "PMU3:CA Odt impedence ==0. Use default vref.\n"
+ },
+ {0x00900003,
+ "PMU3:Calculated %d.%d%% for Vref MR12=0x%x.\n"
+ },
+ {0x00910000,
+ "PMU3: CAtrain_lp\n"
+ },
+ {0x00920000,
+ "PMU3: CAtrain Begins.\n"
+ },
+ {0x00930001,
+ "PMU3: CAtrain_lp testing dly %d\n"
+ },
+ {0x00940001,
+ "PMU5: CA bitmap dump for cs %x\n"
+ },
+ {0x00950001,
+ "PMU5: CAA%d "
+ },
+ {0x00960001, "%02x"
+ },
+ {0x00970000, "\n"
+ },
+ {0x00980001,
+ "PMU5: CAB%d "
+ },
+ {0x00990001, "%02x"
+ },
+ {0x009a0000, "\n"
+ },
+ {0x009b0003,
+ "PMU3: anibi=%d, anibichan[anibi]=%d ,chan=%d\n"
+ },
+ {0x009c0001, "%02x"
+ },
+ {0x009d0001, "\nPMU3:Raw CA setting :%x"
+ },
+ {0x009e0002, "\nPMU3:ATxDly setting:%x margin:%d\n"
+ },
+ {0x009f0002, "\nPMU3:InvClk ATxDly setting:%x margin:%d\n"
+ },
+ {0x00a00000, "\nPMU3:No Range found!\n"
+ },
+ {0x00a10003,
+ "PMU3: 2 anibi=%d, anibichan[anibi]=%d ,chan=%d"
+ },
+ {0x00a20002, "\nPMU3: no neg clock => CA setting anib=%d, :%d\n"
+ },
+ {0x00a30001,
+ "PMU3:Normal margin:%d\n"
+ },
+ {0x00a40001,
+ "PMU3:Inverted margin:%d\n"
+ },
+ {0x00a50000,
+ "PMU3:Using Inverted clock\n"
+ },
+ {0x00a60000,
+ "PMU3:Using normal clk\n"
+ },
+ {0x00a70003,
+ "PMU3: 3 anibi=%d, anibichan[anibi]=%d ,chan=%d\n"
+ },
+ {0x00a80002,
+ "PMU3: Setting ATxDly for anib %x to %x\n"
+ },
+ {0x00a90000,
+ "PMU: Error: CA Training Failed.\n"
+ },
+ {0x00aa0000,
+ "PMU1: Writing MRs\n"
+ },
+ {0x00ab0000,
+ "PMU4:Using MR12 values from 1D CA VREF training.\n"
+ },
+ {0x00ac0000,
+ "PMU3:Writing all MRs to fsp 1\n"
+ },
+ {0x00ad0000,
+ "PMU10:Lp4Quickboot mode.\n"
+ },
+ {0x00ae0000,
+ "PMU3: Writing MRs\n"
+ },
+ {0x00af0001,
+ "PMU10: Setting boot clock divider to %d\n"
+ },
+ {0x00b00000,
+ "PMU3: Resetting DRAM\n"
+ },
+ {0x00b10000,
+ "PMU3: setup for RCD initalization\n"
+ },
+ {0x00b20000,
+ "PMU3: pmu_exit_SR from dev_init()\n"
+ },
+ {0x00b30000,
+ "PMU3: initializing RCD\n"
+ },
+ {0x00b40000,
+ "PMU10: **** Executing 2D Image ****\n"
+ },
+ {0x00b50001,
+ "PMU10: **** Start DDR4 Training. PMU Firmware Revision 0x%04x ****\n"
+ },
+ {0x00b60001,
+ "PMU10: **** Start DDR3 Training. PMU Firmware Revision 0x%04x ****\n"
+ },
+ {0x00b70001,
+ "PMU10: **** Start LPDDR3 Training. PMU Firmware Revision 0x%04x ****\n"
+ },
+ {0x00b80001,
+ "PMU10: **** Start LPDDR4 Training. PMU Firmware Revision 0x%04x ****\n"
+ },
+ {0x00b90000,
+ "PMU: Error: Mismatched internal revision between DCCM and ICCM images\n"
+ },
+ {0x00ba0001,
+ "PMU10: **** Testchip %d Specific Firmware ****\n"
+ },
+ {0x00bb0000,
+ "PMU1: LRDIMM with EncodedCS mode, one DIMM\n"
+ },
+ {0x00bc0000,
+ "PMU1: LRDIMM with EncodedCS mode, two DIMMs\n"
+ },
+ {0x00bd0000,
+ "PMU1: RDIMM with EncodedCS mode, one DIMM\n"
+ },
+ {0x00be0000,
+ "PMU2: Starting LRDIMM MREP training for all ranks\n"
+ },
+ {0x00bf0000,
+ "PMU199: LRDIMM MREP training for all ranks completed\n"
+ },
+ {0x00c00000,
+ "PMU2: Starting LRDIMM DWL training for all ranks\n"
+ },
+ {0x00c10000,
+ "PMU199: LRDIMM DWL training for all ranks completed\n"
+ },
+ {0x00c20000,
+ "PMU2: Starting LRDIMM MRD training for all ranks\n"
+ },
+ {0x00c30000,
+ "PMU199: LRDIMM MRD training for all ranks completed\n"
+ },
+ {0x00c40000,
+ "PMU2: Starting RXEN training for all ranks\n"
+ },
+ {0x00c50000,
+ "PMU2: Starting write leveling fine delay training for all ranks\n"
+ },
+ {0x00c60000,
+ "PMU2: Starting LRDIMM MWD training for all ranks\n"
+ },
+ {0x00c70000,
+ "PMU199: LRDIMM MWD training for all ranks completed\n"
+ },
+ {0x00c80000,
+ "PMU2: Starting write leveling fine delay training for all ranks\n"
+ },
+ {0x00c90000,
+ "PMU2: Starting read deskew training\n"
+ },
+ {0x00ca0000,
+ "PMU2: Starting SI friendly 1d RdDqs training for all ranks\n"
+ },
+ {0x00cb0000,
+ "PMU2: Starting write leveling coarse delay training for all ranks\n"
+ },
+ {0x00cc0000,
+ "PMU2: Starting 1d WrDq training for all ranks\n"
+ },
+ {0x00cd0000,
+ "PMU2: Running DQS2DQ Oscillator for all ranks\n"
+ },
+ {0x00ce0000,
+ "PMU2: Starting again read deskew training but with PRBS\n"
+ },
+ {0x00cf0000,
+ "PMU2: Starting 1d RdDqs training for all ranks\n"
+ },
+ {0x00d00000,
+ "PMU2: Starting again 1d WrDq training for all ranks\n"
+ },
+ {0x00d10000,
+ "PMU2: Starting MaxRdLat training\n"
+ },
+ {0x00d20000,
+ "PMU2: Starting 2d WrDq training for all ranks\n"
+ },
+ {0x00d30000,
+ "PMU2: Starting 2d RdDqs training for all ranks\n"
+ },
+ {0x00d40002,
+ "PMU3:read_fifo %x %x\n"
+ },
+ {0x00d50001,
+ "PMU: Error: Invalid PhyDrvImpedance of 0x%x specified in message block.\n"
+ },
+ {0x00d60001,
+ "PMU: Error: Invalid PhyOdtImpedance of 0x%x specified in message block.\n"
+ },
+ {0x00d70001,
+ "PMU: Error: Invalid BPZNResVal of 0x%x specified in message block.\n"
+ },
+ {0x00d80005,
+ "PMU3: fixRxEnBackOff csn:%d db:%d dn:%d bo:%d dly:%x\n"
+ },
+ {0x00d90001,
+ "PMU3: fixRxEnBackOff dly:%x\n"
+ },
+ {0x00da0000,
+ "PMU3: Entering setupPpt\n"
+ },
+ {0x00db0000,
+ "PMU3: Start lp4PopulateHighLowBytes\n"
+ },
+ {0x00dc0002,
+ "PMU3:Dbyte Detect: db%d received %x\n"
+ },
+ {0x00dd0002,
+ "PMU3:getDqs2Dq read %x from dbyte %d\n"
+ },
+ {0x00de0002,
+ "PMU3:getDqs2Dq(2) read %x from dbyte %d\n"
+ },
+ {0x00df0001,
+ "PMU: Error: Dbyte %d read 0 from the DQS oscillator it is connected to\n"
+ },
+ {0x00e00002,
+ "PMU4: Dbyte %d dqs2dq = %d/32 UI\n"
+ },
+ {0x00e10003,
+ "PMU3:getDqs2Dq set dqs2dq:%d/32 ui (%d ps) from dbyte %d\n"
+ },
+ {0x00e20003,
+ "PMU3: Setting coarse delay in AtxDly chiplet %d from 0x%02x to 0x%02x\n"
+ },
+ {0x00e30003,
+ "PMU3: Clearing coarse delay in AtxDly chiplet %d from 0x%02x to 0x%02x\n"
+ },
+ {0x00e40000,
+ "PMU3: Performing DDR4 geardown sync sequence\n"
+ },
+ {0x00e50000,
+ "PMU1: Enter self refresh\n"
+ },
+ {0x00e60000,
+ "PMU1: Exit self refresh\n"
+ },
+ {0x00e70000,
+ "PMU: Error: No dbiEnable with lp4\n"
+ },
+ {0x00e80000,
+ "PMU: Error: No dbiDisable with lp4\n"
+ },
+ {0x00e90001,
+ "PMU1: DDR4 update Rx DBI Setting disable %d\n"
+ },
+ {0x00ea0001,
+ "PMU1: DDR4 update 2nCk WPre Setting disable %d\n"
+ },
+ {0x00eb0005,
+ "PMU1: read_delay: db%d lane%d delays[%2d] = 0x%02x (max 0x%02x)\n"
+ },
+ {0x00ec0004,
+ "PMU1: write_delay: db%d lane%d delays[%2d] = 0x%04x\n"
+ },
+ {0x00ed0001,
+ "PMU5: ID=%d -- db0 db1 db2 db3 db4 db5 db6 db7 db8 db9 --\n"
+ },
+ {0x00ee000b,
+ "PMU5: [%d]:0x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x\n"
+ },
+ {0x00ef0003,
+ "PMU2: dump delays - pstate=%d dimm=%d csn=%d\n"
+ },
+ {0x00f00000,
+ "PMU3: Printing Mid-Training Delay Information\n"
+ },
+ {0x00f10001,
+ "PMU5: CS%d <<KEY>> 0 TrainingCntr <<KEY>> coarse(15:10) fine(9:0)\n"
+ },
+ {0x00f20001,
+ "PMU5: CS%d <<KEY>> 0 RxEnDly, 1 RxClkDly <<KEY>> coarse(10:6) fine(5:0)\n"
+ },
+ {0x00f30001,
+ "PMU5: CS%d <<KEY>> 0 TxDqsDly, 1 TxDqDly <<KEY>> coarse(9:6) fine(5:0)\n"
+ },
+ {0x00f40001,
+ "PMU5: CS%d <<KEY>> 0 RxPBDly <<KEY>> 1 Delay Unit ~= 7ps\n"
+ },
+ {0x00f50000,
+ "PMU5: all CS <<KEY>> 0 DFIMRL <<KEY>> Units = DFI clocks\n"
+ },
+ {0x00f60000,
+ "PMU5: all CS <<KEY>> VrefDACs <<KEY>> DAC(6:0)\n"
+ },
+ {0x00f70000,
+ "PMU1: Set DMD in MR13 and wrDBI in MR3 for training\n"
+ },
+ {0x00f80000,
+ "PMU: Error: getMaxRxen() failed to find largest rxen nibble delay\n"
+ },
+ {0x00f90003,
+ "PMU2: getMaxRxen(): maxDly %d maxTg %d maxNib %d\n"
+ },
+ {0x00fa0003,
+ "PMU2: getRankMaxRxen(): maxDly %d Tg %d maxNib %d\n"
+ },
+ {0x00fb0000,
+ "PMU1: skipping CDD calculation in 2D image\n"
+ },
+ {0x00fc0001,
+ "PMU3: Calculating CDDs for pstate %d\n"
+ },
+ {0x00fd0003,
+ "PMU3: rxFromDly[%d][%d] = %d\n"
+ },
+ {0x00fe0003,
+ "PMU3: rxToDly [%d][%d] = %d\n"
+ },
+ {0x00ff0003,
+ "PMU3: rxDly [%d][%d] = %d\n"
+ },
+ {0x01000003,
+ "PMU3: txDly [%d][%d] = %d\n"
+ },
+ {0x01010003,
+ "PMU3: allFine CDD_RR_%d_%d = %d\n"
+ },
+ {0x01020003,
+ "PMU3: allFine CDD_WW_%d_%d = %d\n"
+ },
+ {0x01030003,
+ "PMU3: CDD_RR_%d_%d = %d\n"
+ },
+ {0x01040003,
+ "PMU3: CDD_WW_%d_%d = %d\n"
+ },
+ {0x01050003,
+ "PMU3: allFine CDD_RW_%d_%d = %d\n"
+ },
+ {0x01060003,
+ "PMU3: allFine CDD_WR_%d_%d = %d\n"
+ },
+ {0x01070003,
+ "PMU3: CDD_RW_%d_%d = %d\n"
+ },
+ {0x01080003,
+ "PMU3: CDD_WR_%d_%d = %d\n"
+ },
+ {0x01090004,
+ "PMU3: F%dBC2x_B%d_D%d = 0x%02x\n"
+ },
+ {0x010a0004,
+ "PMU3: F%dBC3x_B%d_D%d = 0x%02x\n"
+ },
+ {0x010b0004,
+ "PMU3: F%dBC4x_B%d_D%d = 0x%02x\n"
+ },
+ {0x010c0004,
+ "PMU3: F%dBC5x_B%d_D%d = 0x%02x\n"
+ },
+ {0x010d0004,
+ "PMU3: F%dBC8x_B%d_D%d = 0x%02x\n"
+ },
+ {0x010e0004,
+ "PMU3: F%dBC9x_B%d_D%d = 0x%02x\n"
+ },
+ {0x010f0004,
+ "PMU3: F%dBCAx_B%d_D%d = 0x%02x\n"
+ },
+ {0x01100004,
+ "PMU3: F%dBCBx_B%d_D%d = 0x%02x\n"
+ },
+ {0x01110000,
+ "PMU10: Entering context_switch_postamble\n"
+ },
+ {0x01120003,
+ "PMU10: context_switch_postamble is enabled for DIMM %d, RC0A=0x%x, RC3x=0x%x\n"
+ },
+ {0x01130000,
+ "PMU10: Setting bcw fspace 0\n"
+ },
+ {0x01140001,
+ "PMU10: Sending BC0A = 0x%x\n"
+ },
+ {0x01150001,
+ "PMU10: Sending BC6x = 0x%x\n"
+ },
+ {0x01160001,
+ "PMU10: Sending RC0A = 0x%x\n"
+ },
+ {0x01170001,
+ "PMU10: Sending RC3x = 0x%x\n"
+ },
+ {0x01180001,
+ "PMU10: Sending RC0A = 0x%x\n"
+ },
+ {0x01190001,
+ "PMU1: enter_lp3: DEBUG: pstate = %d\n"
+ },
+ {0x011a0001,
+ "PMU1: enter_lp3: DEBUG: dfifreqxlat_pstate = %d\n"
+ },
+ {0x011b0001,
+ "PMU1: enter_lp3: DEBUG: pllbypass = %d\n"
+ },
+ {0x011c0001,
+ "PMU1: enter_lp3: DEBUG: forcecal = %d\n"
+ },
+ {0x011d0001,
+ "PMU1: enter_lp3: DEBUG: pllmaxrange = 0x%x\n"
+ },
+ {0x011e0001,
+ "PMU1: enter_lp3: DEBUG: dacval_out = 0x%x\n"
+ },
+ {0x011f0001,
+ "PMU1: enter_lp3: DEBUG: pllctrl3 = 0x%x\n"
+ },
+ {0x01200000,
+ "PMU3: Loading DRAM with BIOS supplied MR values and entering self refresh prior to exiting PMU code.\n"
+ },
+ {0x01210002,
+ "PMU3: Setting DataBuffer function space of dimmcs 0x%02x to %d\n"
+ },
+ {0x01220002,
+ "PMU4: Setting RCW FxRC%Xx = 0x%02x\n"
+ },
+ {0x01230002,
+ "PMU4: Setting RCW FxRC%02x = 0x%02x\n"
+ },
+ {0x01240001,
+ "PMU1: DDR4 update Rd Pre Setting disable %d\n"
+ },
+ {0x01250002,
+ "PMU2: Setting BCW FxBC%Xx = 0x%02x\n"
+ },
+ {0x01260002,
+ "PMU2: Setting BCW BC%02x = 0x%02x\n"
+ },
+ {0x01270002,
+ "PMU2: Setting BCW PBA mode FxBC%Xx = 0x%02x\n"
+ },
+ {0x01280002,
+ "PMU2: Setting BCW PBA mode BC%02x = 0x%02x\n"
+ },
+ {0x01290003,
+ "PMU4: BCW value for dimm %d, fspace %d, addr 0x%04x\n"
+ },
+ {0x012a0002,
+ "PMU4: DB %d, value 0x%02x\n"
+ },
+ {0x012b0000,
+ "PMU6: WARNING MREP underflow, set to min value -2 coarse, 0 fine\n"
+ },
+ {0x012c0004,
+ "PMU6: LRDIMM Writing final data buffer fine delay value nib %2d, trainDly %3d, fineDly code %2d, new MREP fine %2d\n"
+ },
+ {0x012d0003,
+ "PMU6: LRDIMM Writing final data buffer fine delay value nib %2d, trainDly %3d, fineDly code %2d\n"
+ },
+ {0x012e0003,
+ "PMU6: LRDIMM Writing data buffer fine delay type %d nib %2d, code %2d\n"
+ },
+ {0x012f0002,
+ "PMU6: Writing final data buffer coarse delay value dbyte %2d, coarse = 0x%02x\n"
+ },
+ {0x01300003,
+ "PMU4: data 0x%04x at MB addr 0x%08x saved at CSR addr 0x%08x\n"
+ },
+ {0x01310003,
+ "PMU4: data 0x%04x at MB addr 0x%08x restored from CSR addr 0x%08x\n"
+ },
+ {0x01320003,
+ "PMU4: data 0x%04x at MB addr 0x%08x saved at CSR addr 0x%08x\n"
+ },
+ {0x01330003,
+ "PMU4: data 0x%04x at MB addr 0x%08x restored from CSR addr 0x%08x\n"
+ },
+ {0x01340001,
+ "PMU3: Update BC00, BC01, BC02 for rank-dimm 0x%02x\n"
+ },
+ {0x01350000,
+ "PMU3: Writing D4 RDIMM RCD Control words F0RC00 -> F0RC0F\n"
+ },
+ {0x01360000,
+ "PMU3: Disable parity in F0RC0E\n"
+ },
+ {0x01370000,
+ "PMU3: Writing D4 RDIMM RCD Control words F1RC00 -> F1RC05\n"
+ },
+ {0x01380000,
+ "PMU3: Writing D4 RDIMM RCD Control words F1RC1x -> F1RC9x\n"
+ },
+ {0x01390000,
+ "PMU3: Writing D4 Data buffer Control words BC00 -> BC0E\n"
+ },
+ {0x013a0002,
+ "PMU1: setAltCL Sending MR0 0x%x cl=%d\n"
+ },
+ {0x013b0002,
+ "PMU1: restoreFromAltCL Sending MR0 0x%x cl=%d\n"
+ },
+ {0x013c0002,
+ "PMU1: restoreAcsmFromAltCL Sending MR0 0x%x cl=%d\n"
+ },
+ {0x013d0002,
+ "PMU2: Setting D3R RC%d = 0x%01x\n"
+ },
+ {0x013e0000,
+ "PMU3: Writing D3 RDIMM RCD Control words RC0 -> RC11\n"
+ },
+ {0x013f0002,
+ "PMU0: VrefDAC0/1 vddqStart %d dacToVddq %d\n"
+ },
+ {0x01400001,
+ "PMU: Error: Messageblock phyVref=0x%x is above the limit for TSMC28's attenuated LPDDR4 receivers. Please see the pub databook\n"
+ },
+ {0x01410001,
+ "PMU: Error: Messageblock phyVref=0x%x is above the limit for TSMC28's attenuated DDR4 receivers. Please see the pub databook\n"
+ },
+ {0x01420001,
+ "PMU0: PHY VREF @ (%d/1000) VDDQ\n"
+ },
+ {0x01430002,
+ "PMU0: initalizing phy vrefDacs to %d ExtVrefRange %x\n"
+ },
+ {0x01440002,
+ "PMU0: initalizing global vref to %d range %d\n"
+ },
+ {0x01450002,
+ "PMU4: Setting initial device vrefDQ for CS%d to MR6 = 0x%04x\n"
+ },
+ {0x01460003,
+ "PMU1: In write_level_fine() csn=%d dimm=%d pstate=%d\n"
+ },
+ {0x01470000,
+ "PMU3: Fine write leveling hardware search increasing TxDqsDly until full bursts are seen\n"
+ },
+ {0x01480000,
+ "PMU4: WL normalized pos : ........................|........................\n"
+ },
+ {0x01490007,
+ "PMU4: WL margin for nib %2d: %08x%08x%08x%08x%08x%08x\n"
+ },
+ {0x014a0000,
+ "PMU4: WL normalized pos : ........................|........................\n"
+ },
+ {0x014b0000,
+ "PMU3: Exiting write leveling mode\n"
+ },
+ {0x014c0001,
+ "PMU3: got %d for cl in load_wrlvl_acsm\n"
+ },
+ {0x014d0003,
+ "PMU1: In write_level_coarse() csn=%d dimm=%d pstate=%d\n"
+ },
+ {0x014e0003,
+ "PMU3: left eye edge search db:%d ln:%d dly:0x%x\n"
+ },
+ {0x014f0003,
+ "PMU3: right eye edge search db:%d ln:%d dly:0x%x\n"
+ },
+ {0x01500004,
+ "PMU3: eye center db:%d ln:%d dly:0x%x (maxdq:%x)\n"
+ },
+ {0x01510003,
+ "PMU3: Wrote to TxDqDly db:%d ln:%d dly:0x%x\n"
+ },
+ {0x01520003,
+ "PMU3: Wrote to TxDqDly db:%d ln:%d dly:0x%x\n"
+ },
+ {0x01530002,
+ "PMU3: Coarse write leveling dbyte%2d is still failing for TxDqsDly=0x%04x\n"
+ },
+ {0x01540002,
+ "PMU4: Coarse write leveling iteration %d saw %d data miscompares across the entire phy\n"
+ },
+ {0x01550000,
+ "PMU: Error: Failed write leveling coarse\n"
+ },
+ {0x01560001,
+ "PMU3: got %d for cl in load_wrlvl_acsm\n"
+ },
+ {0x01570003,
+ "PMU3: In write_level_coarse() csn=%d dimm=%d pstate=%d\n"
+ },
+ {0x01580003,
+ "PMU3: left eye edge search db:%d ln:%d dly:0x%x\n"
+ },
+ {0x01590003,
+ "PMU3: right eye edge search db: %d ln: %d dly: 0x%x\n"
+ },
+ {0x015a0004,
+ "PMU3: eye center db: %d ln: %d dly: 0x%x (maxdq: 0x%x)\n"
+ },
+ {0x015b0003,
+ "PMU3: Wrote to TxDqDly db: %d ln: %d dly: 0x%x\n"
+ },
+ {0x015c0003,
+ "PMU3: Wrote to TxDqDly db: %d ln: %d dly: 0x%x\n"
+ },
+ {0x015d0002,
+ "PMU3: Coarse write leveling nibble%2d is still failing for TxDqsDly=0x%04x\n"
+ },
+ {0x015e0002,
+ "PMU4: Coarse write leveling iteration %d saw %d data miscompares across the entire phy\n"
+ },
+ {0x015f0000,
+ "PMU: Error: Failed write leveling coarse\n"
+ },
+ {0x01600000,
+ "PMU4: WL normalized pos : ................................|................................\n"
+ },
+ {0x01610009,
+ "PMU4: WL margin for nib %2d: %08x%08x%08x%08x%08x%08x%08x%08x\n"
+ },
+ {0x01620000,
+ "PMU4: WL normalized pos : ................................|................................\n"
+ },
+ {0x01630001,
+ "PMU8: Adjust margin after WL coarse to be larger than %d\n"
+ },
+ {0x01640001,
+ "PMU: Error: All margin after write leveling coarse are smaller than minMargin %d\n"
+ },
+ {0x01650002,
+ "PMU8: Decrement nib %d TxDqsDly by %d fine step\n"
+ },
+ {0x01660003,
+ "PMU3: In write_level_coarse() csn=%d dimm=%d pstate=%d\n"
+ },
+ {0x01670005,
+ "PMU2: Write level: dbyte %d nib%d dq/dmbi %2d dqsfine 0x%04x dqDly 0x%04x\n"
+ },
+ {0x01680002,
+ "PMU3: Coarse write leveling nibble%2d is still failing for TxDqsDly=0x%04x\n"
+ },
+ {0x01690002,
+ "PMU4: Coarse write leveling iteration %d saw %d data miscompares across the entire phy\n"
+ },
+ {0x016a0000,
+ "PMU: Error: Failed write leveling coarse\n"
+ },
+ {0x016b0001,
+ "PMU3: DWL delay = %d\n"
+ },
+ {0x016c0003,
+ "PMU3: Errcnt for DWL nib %2d delay = %2d is %d\n"
+ },
+ {0x016d0002,
+ "PMU3: DWL nibble %d sampled a 1 at delay %d\n"
+ },
+ {0x016e0003,
+ "PMU3: DWL nibble %d passed at delay %d. Rising edge was at %d\n"
+ },
+ {0x016f0000,
+ "PMU2: DWL did nto find a rising edge of memclk for all nibbles. Failing nibbles assumed to have rising edge close to fine delay 63\n"
+ },
+ {0x01700002,
+ "PMU2: Rising edge found in alias window, setting wrlvlDly for nibble %d = %d\n"
+ },
+ {0x01710002,
+ "PMU: Error: Failed DWL for nib %d with %d one\n"
+ },
+ {0x01720003,
+ "PMU2: Rising edge not found in alias window with %d one, leaving wrlvlDly for nibble %d = %d\n"
+ },
+ {0x04000000,
+ "PMU: Error:Mailbox Buffer Overflowed.\n"
+ },
+ {0x04010000,
+ "PMU: Error:Mailbox Buffer Overflowed.\n"
+ },
+ {0x04020000,
+ "PMU: ***** Assertion Error - terminating *****\n"
+ },
+ {0x04030002,
+ "PMU1: swapByte db %d by %d\n"
+ },
+ {0x04040003,
+ "PMU3: get_cmd_dly max(%d ps, %d memclk) = %d\n"
+ },
+ {0x04050002,
+ "PMU0: Write CSR 0x%06x 0x%04x\n"
+ },
+ {0x04060002,
+ "PMU0: hwt_init_ppgc_prbs(): Polynomial: %x, Deg: %d\n"
+ },
+ {0x04070001,
+ "PMU: Error: acsm_set_cmd to non existent instruction address %d\n"
+ },
+ {0x04080001,
+ "PMU: Error: acsm_set_cmd with unknown ddr cmd 0x%x\n"
+ },
+ {0x0409000c,
+ "PMU1: acsm_addr %02x, acsm_flgs %04x, ddr_cmd %02x, cmd_dly %02x, ddr_addr %04x, ddr_bnk %02x, ddr_cs %02x, cmd_rcnt %02x, AcsmSeq0/1/2/3 %04x %04x %04x %04x\n"
+ },
+ {0x040a0000,
+ "PMU: Error: Polling on ACSM done failed to complete in acsm_poll_done()...\n"
+ },
+ {0x040b0000,
+ "PMU1: acsm RUN\n"
+ },
+ {0x040c0000,
+ "PMU1: acsm STOPPED\n"
+ },
+ {0x040d0002,
+ "PMU1: acsm_init: acsm_mode %04x mxrdlat %04x\n"
+ },
+ {0x040e0002,
+ "PMU: Error: setAcsmCLCWL: cl and cwl must be each >= 2 and 5, resp. CL=%d CWL=%d\n"
+ },
+ {0x040f0002,
+ "PMU: Error: setAcsmCLCWL: cl and cwl must be each >= 5. CL=%d CWL=%d\n"
+ },
+ {0x04100002,
+ "PMU1: setAcsmCLCWL: CASL %04d WCASL %04d\n"
+ },
+ {0x04110001,
+ "PMU: Error: Reserved value of register F0RC0F found in message block: 0x%04x\n"
+ },
+ {0x04120001,
+ "PMU3: Written MRS to CS=0x%02x\n"
+ },
+ {0x04130001,
+ "PMU3: Written MRS to CS=0x%02x\n"
+ },
+ {0x04140000,
+ "PMU3: Entering Boot Freq Mode.\n"
+ },
+ {0x04150001,
+ "PMU: Error: Boot clock divider setting of %d is too small\n"
+ },
+ {0x04160000,
+ "PMU3: Exiting Boot Freq Mode.\n"
+ },
+ {0x04170002,
+ "PMU3: Writing MR%d OP=%x\n"
+ },
+ {0x04180000,
+ "PMU: Error: Delay too large in slomo\n"
+ },
+ {0x04190001,
+ "PMU3: Written MRS to CS=0x%02x\n"
+ },
+ {0x041a0000,
+ "PMU3: Enable Channel A\n"
+ },
+ {0x041b0000,
+ "PMU3: Enable Channel B\n"
+ },
+ {0x041c0000,
+ "PMU3: Enable All Channels\n"
+ },
+ {0x041d0002,
+ "PMU2: Use PDA mode to set MR%d with value 0x%02x\n"
+ },
+ {0x041e0001,
+ "PMU3: Written Vref with PDA to CS=0x%02x\n"
+ },
+ {0x041f0000,
+ "PMU1: start_cal: DEBUG: setting CalRun to 1\n"
+ },
+ {0x04200000,
+ "PMU1: start_cal: DEBUG: setting CalRun to 0\n"
+ },
+ {0x04210001,
+ "PMU1: lock_pll_dll: DEBUG: pstate = %d\n"
+ },
+ {0x04220001,
+ "PMU1: lock_pll_dll: DEBUG: dfifreqxlat_pstate = %d\n"
+ },
+ {0x04230001,
+ "PMU1: lock_pll_dll: DEBUG: pllbypass = %d\n"
+ },
+ {0x04240001,
+ "PMU3: SaveLcdlSeed: Saving seed %d\n"
+ },
+ {0x04250000,
+ "PMU1: in phy_defaults()\n"
+ },
+ {0x04260003,
+ "PMU3: ACXConf:%d MaxNumDbytes:%d NumDfi:%d\n"
+ },
+ {0x04270005,
+ "PMU1: setAltAcsmCLCWL setting cl=%d cwl=%d\n"
+ },
+};
+
+const static struct phy_msg messages_2d[] = {
+ {0x00000001,
+ "PMU0: Converting %d into an MR\n"
+ },
+ {0x00010003,
+ "PMU DEBUG: vref_idx %d -= %d, range_idx = %d\n"
+ },
+ {0x00020002,
+ "PMU0: vrefIdx. Passing range %d, remaining vrefidx = %d\n"
+ },
+ {0x00030002,
+ "PMU0: VrefIdx %d -> MR[6:0] 0x%02x\n"
+ },
+ {0x00040001,
+ "PMU0: Converting MR 0x%04x to vrefIdx\n"
+ },
+ {0x00050002,
+ "PMU0: DAC %d Range %d\n"
+ },
+ {0x00060003,
+ "PMU0: Range %d, Range_idx %d, vref_idx offset %d\n"
+ },
+ {0x00070002,
+ "PMU0: MR 0x%04x -> VrefIdx %d\n"
+ },
+ {0x00080001,
+ "PMU: Error: Illegal timing group number ,%d, in getPtrVrefDq\n"
+ },
+ {0x00090003,
+ "PMU1: VrefDqR%dNib%d = %d\n"
+ },
+ {0x000a0003,
+ "PMU0: VrefDqR%dNib%d = %d\n"
+ },
+ {0x000b0000,
+ "PMU0: ----------------MARGINS-------\n"
+ },
+ {0x000c0002,
+ "PMU0: R%d_RxClkDly_Margin = %d\n"
+ },
+ {0x000d0002,
+ "PMU0: R%d_VrefDac_Margin = %d\n"
+ },
+ {0x000e0002,
+ "PMU0: R%d_TxDqDly_Margin = %d\n"
+ },
+ {0x000f0002,
+ "PMU0: R%d_DeviceVref_Margin = %d\n"
+ },
+ {0x00100000,
+ "PMU0: -----------------------\n"
+ },
+ {0x00110003,
+ "PMU0: eye %d's for all TG's is [%d ... %d]\n"
+ },
+ {0x00120000,
+ "PMU0: ------- settingWeight -----\n"
+ },
+ {0x00130002,
+ "PMU0: Weight %d @ Setting %d\n"
+ },
+ {0x0014001f,
+ "PMU4: %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d >%3d< %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d\n"
+ },
+ {0x00150002,
+ "PMU3: Voltage Range = [%d, %d]\n"
+ },
+ {0x00160004,
+ "PMU4: -- DB%d L%d -- centers: delay = %d, voltage = %d\n"
+ },
+ {0x00170001,
+ "PMU5: <<KEY>> 0 TxDqDlyTg%d <<KEY>> coarse(6:6) fine(5:0)\n"
+ },
+ {0x00180001,
+ "PMU5: <<KEY>> 0 messageBlock VrefDqR%d <<KEY>> MR6(6:0)\n"
+ },
+ {0x00190001,
+ "PMU5: <<KEY>> 0 RxClkDlyTg%d <<KEY>> fine(5:0)\n"
+ },
+ {0x001a0003,
+ "PMU0: tgToCsn: tg %d + 0x%04x -> csn %d\n"
+ },
+ {0x001b0002,
+ "PMU: Error: LP4 rank %d cannot be mapped on tg %d\n"
+ },
+ {0x001c0002,
+ "PMU3: Sending vref %d, Mr = 0X%05x, to all devices\n"
+ },
+ {0x001d0004,
+ "PMU4: -------- %dD Write Scanning TG %d (CS 0x%x) Lanes 0x%03x --------\n"
+ },
+ {0x001e0002,
+ "PMU0: training lanes 0x%03x using lanes 0x%03x\n"
+ },
+ {0x001f0003,
+ "PMU4: ------- 2D-DFE Read Scanning TG %d (CS 0x%x) Lanes 0x%03x -------\n"
+ },
+ {0x00200004,
+ "PMU4: ------- %dD Read Scanning TG %d (CS 0x%x) Lanes 0x%03x -------\n"
+ },
+ {0x00210003,
+ "PMU4: TG%d MR1[13,6,5]=0x%x MR6[13,9,8]=0x%x\n"
+ },
+ {0x00220002,
+ "PMU0: training lanes 0x%03x using lanes 0x%03x\n"
+ },
+ {0x00230003,
+ "PMU4: ------- 2D-DFE Read Scanning TG %d (CS 0x%x) Lanes 0x%03x -------\n"
+ },
+ {0x00240004,
+ "PMU4: ------- %dD Read Scanning TG %d (CS 0x%x) Lanes 0x%03x -------\n"
+ },
+ {0x00250002,
+ "PMU0: training lanes 0x%03x using lanes 0x%03x\n"
+ },
+ {0x00260002,
+ "PMU3: Sending vref %d, Mr = 0X%05x, to all devices\n"
+ },
+ {0x00270004,
+ "PMU4: -------- %dD Write Scanning TG %d (CS 0x%x) Lanes 0x%03x --------\n"
+ },
+ {0x00280001,
+ "PMU0: input %d\n"
+ },
+ {0x00290002,
+ "PMU4: Programmed Voltage Search Range [%d, %d]\n"
+ },
+ {0x002a0002,
+ "PMU3: Delay Stepsize = %d Fine, Voltage Stepsize = %d DAC\n"
+ },
+ {0x002b0002,
+ "PMU4: Delay Weight = %d, Voltage Weight = %d\n"
+ },
+ {0x002c0003,
+ "PMU0: raw 0x%x allFine %d incDec %d"
+ },
+ {0x002d0008,
+ "PMU0: db%d l%d, voltage 0x%x (u_r %d) delay 0x%x (u_r %d) - lcdl %d mask 0x%x\n"
+ },
+ {0x002e0005,
+ "PMU0: DB%d L%d, Eye %d, Seed = (0x%x, 0x%x)\n"
+ },
+ {0x002f0002,
+ "PMU3: 2D Enables : %d, 1, %d\n"
+ },
+ {0x00300006,
+ "PMU3: 2D Delay Ranges: OOPL[0x%04x,0x%04x], IP[0x%04x,0x%04x], OOPR[0x%04x,0x%04x]\n"
+ },
+ {0x00310002,
+ "PMU3: 2D Voltage Search Range : [%d, %d]\n"
+ },
+ {0x00320002,
+ "PMU4: Found Voltage Search Range [%d, %d]\n"
+ },
+ {0x00330002,
+ "PMU0: User Weight = %d, Voltage Weight = %d\n"
+ },
+ {0x00340005,
+ "PMU0: D(%d,%d) V(%d,%d | %d)\n"
+ },
+ {0x00350002,
+ "PMU0: Norm Weight = %d, Voltage Weight = %d\n"
+ },
+ {0x00360002,
+ "PMU0: seed 0 = (%d,%d) (center)\n"
+ },
+ {0x00370003,
+ "PMU0: seed 1 = (%d,%d).min edge at idx %d\n"
+ },
+ {0x00380003,
+ "PMU0: seed 2 = (%d,%d) max edge at idx %d\n"
+ },
+ {0x00390003,
+ "PMU0: Search point %d = (%d,%d)\n"
+ },
+ {0x003a0005,
+ "PMU0: YMARGIN: ^ %d, - %d, v %d. rate %d = %d\n"
+ },
+ {0x003b0003,
+ "PMU0: XMARGIN: center %d, edge %d. = %d\n"
+ },
+ {0x003c0002,
+ "PMU0: ----------- weighting (%d,%d) ----------------\n"
+ },
+ {0x003d0003,
+ "PMU0: X margin - L %d R %d - Min %d\n"
+ },
+ {0x003e0003,
+ "PMU0: Y margin - L %d R %d - Min %d\n"
+ },
+ {0x003f0003,
+ "PMU0: center (%d,%d) weight = %d\n"
+ },
+ {0x00400003,
+ "PMU4: Eye argest blob area %d from %d to %d\n"
+ },
+ {0x00410002,
+ "PMU0: Compute centroid min_x %d max_x %d\n"
+ },
+ {0x00420003,
+ "PMU0: Compute centroid sumLnDlyWidth %d sumLnVrefWidth %d sumLnWidht %d\n"
+ },
+ {0x00430000,
+ "PMU: Error: No passing region found for 1 or more lanes. Set hdtCtrl=4 to see passing regions\n"
+ },
+ {0x00440003,
+ "PMU0: Centroid ( %d, %d ) found with sumLnWidht %d\n"
+ },
+ {0x00450003,
+ "PMU0: Optimal allFine Center ( %d + %d ,%d )\n"
+ },
+ {0x00460003,
+ "PMU3: point %d starting at (%d,%d)\n"
+ },
+ {0x00470002,
+ "PMU0: picking left (%d > %d)\n"
+ },
+ {0x00480002,
+ "PMU0: picking right (%d > %d)\n"
+ },
+ {0x00490002,
+ "PMU0: picking down (%d > %d)\n"
+ },
+ {0x004a0002,
+ "PMU0: picking up (%d > %d)\n"
+ },
+ {0x004b0009,
+ "PMU3: new center @ (%3d, %3d). Moved (%2i, %2i) -- L %d, R %d, C %d, U %d, D %d\n"
+ },
+ {0x004c0003,
+ "PMU3: cordNum %d imporved %d to %d\n"
+ },
+ {0x004d0000,
+ "PMU: Error: No passing region found for 1 or more lanes. Set hdtCtrl=4 to see passing regions\n"
+ },
+ {0x004e0004,
+ "PMU0: Optimal allFine Center ( %d + %d ,%d ), found with weight %d.\n"
+ },
+ {0x004f0003,
+ "PMU0: merging lanes=%d..%d, centerMerge_t %d\n"
+ },
+ {0x00500001,
+ "PMU0: laneVal %d is disable\n"
+ },
+ {0x00510002,
+ "PMU0: checking common center %d against current center %d\n"
+ },
+ {0x00520001,
+ "PMU: Error: getCompoundEye Called on lane%d eye with non-compatible centers\n"
+ },
+ {0x00530001,
+ "PMU0: laneItr %d is disable\n"
+ },
+ {0x00540005,
+ "PMU0: lane %d, data_idx %d, offset_idx %d, = [%d..%d]\n"
+ },
+ {0x00550003,
+ "PMU0: lane %d, data_idx %d, offset_idx %d, offset_idx out of range!\n"
+ },
+ {0x00560003,
+ "PMU0: mergeData[%d] = max_v_low %d, min_v_high %d\n"
+ },
+ {0x00570005,
+ "PMU1: writing merged center (%d,%d) back to dataBlock[%d]. doDelay %d, doVoltage %d\n"
+ },
+ {0x00580005,
+ "PMU0: applying relative (%i,%i) back to dataBlock[%d]. doDelay %d, doVoltage %d\n"
+ },
+ {0x00590002,
+ "PMU0: drvstren %x is idx %d in the table\n"
+ },
+ {0x005a0000,
+ "PMU4: truncating FFE drive strength search range. Out of drive strengths to check.\n"
+ },
+ {0x005b0002,
+ "PMU5: Weak 1 changed to pull-up %5d ohms, pull-down %5d ohms\n"
+ },
+ {0x005c0002,
+ "PMU5: Weak 0 changed to pull-up %5d ohms, pull-down %5d ohms\n"
+ },
+ {0x005d0003,
+ "PMU0: dlyMargin L %02d R %02d, min %02d\n"
+ },
+ {0x005e0003,
+ "PMU0: vrefMargin T %02d B %02d, min %02d\n"
+ },
+ {0x005f0002,
+ "PMU3: new minimum VrefMargin (%d < %d) recorded\n"
+ },
+ {0x00600002,
+ "PMU3: new minimum DlyMargin (%d < %d) recorded\n"
+ },
+ {0x00610000,
+ "PMU0: RX finding the per-nibble, per-tg rxClkDly values\n"
+ },
+ {0x00620003,
+ "PMU0: Merging collected eyes [%d..%d) and analyzing for nibble %d's optimal rxClkDly\n"
+ },
+ {0x00630002,
+ "PMU0: -- centers: delay = %d, voltage = %d\n"
+ },
+ {0x00640003,
+ "PMU0: dumping optimized eye -- centers: delay = %d (%d), voltage = %d\n"
+ },
+ {0x00650000,
+ "PMU0: TX optimizing txDqDelays\n"
+ },
+ {0x00660001,
+ "PMU3: Analyzing collected eye %d for a lane's optimal TxDqDly\n"
+ },
+ {0x00670001,
+ "PMU0: eye-lane %d is disable\n"
+ },
+ {0x00680000,
+ "PMU0: TX optimizing device voltages\n"
+ },
+ {0x00690002,
+ "PMU0: Merging collected eyes [%d..%d) and analyzing for optimal device txVref\n"
+ },
+ {0x006a0002,
+ "PMU0: -- centers: delay = %d, voltage = %d\n"
+ },
+ {0x006b0003,
+ "PMU0: dumping optimized eye -- centers: delay = %d (%d), voltage = %d\n"
+ },
+ {0x006c0000,
+ "PMU4: VrefDac (compound all TG) Bottom Top -> Center\n"
+ },
+ {0x006d0005,
+ "PMU4: DB%d L%d %3d %3d -> %3d (DISCONNECTED)\n"
+ },
+ {0x006e0005,
+ "PMU4: DB%d L%d %3d %3d -> %3d\n"
+ },
+ {0x006f0005,
+ "PMU0: writing rxClkDelay for tg%d db%1d nib%1d to 0x%02x from eye[%02d] (DISCONNECTED)\n"
+ },
+ {0x00700003,
+ "PMU: Error: Dbyte %d nibble %d's optimal rxClkDly of 0x%x is out of bounds\n"
+ },
+ {0x00710005,
+ "PMU0: writing rxClkDelay for tg%d db%1d nib%1d to 0x%02x from eye[%02d]\n"
+ },
+ {0x00720005,
+ "PMU0: tx voltage for tg%2d nib%2d to %3d (%d) from eye[%02d]\n"
+ },
+ {0x00730001,
+ "PMU0: vref Sum = %d\n"
+ },
+ {0x00740004,
+ "PMU0: tx voltage total is %d/%d -> %d -> %d\n"
+ },
+ {0x00750007,
+ "PMU0: writing txDqDelay for tg%1d db%1d ln%1d to 0x%02x (%d coarse, %d fine) from eye[%02d] (DISCONNECTED)\n"
+ },
+ {0x00760003,
+ "PMU: Error: Dbyte %d lane %d's optimal txDqDly of 0x%x is out of bounds\n"
+ },
+ {0x00770007,
+ "PMU0: writing txDqDelay for tg%1d db%1d l%1d to 0x%02x (%d coarse, %d fine) from eye[%02d]\n"
+ },
+ {0x00780002,
+ "PMU0: %d (0=tx, 1=rx) TgMask for this simulation: %x\n"
+ },
+ {0x00790001,
+ "PMU0: eye-byte %d is disable\n"
+ },
+ {0x007a0001,
+ "PMU0: eye-lane %d is disable\n"
+ },
+ {0x007b0003,
+ "PMU10: Start d4_2d_lrdimm_rx_dfe dimm %d nbTap %d biasStepMode %d\n"
+ },
+ {0x007c0001,
+ "PMU10: DB DFE feature not fully supported, F2BCEx value is 0x%02x\n"
+ },
+ {0x007d0001,
+ "PMU10: DB DFE feature fully supported, F2BCEx value is 0x%02x\n"
+ },
+ {0x007e0002,
+ "PMU8: Start d4_2d_lrdimm_rx_dfe for tap %d biasStepInc %d\n"
+ },
+ {0x007f0001,
+ "PMU7: Start d4_2d_lrdimm_rx_dfe tapCoff 0x%0x\n"
+ },
+ {0x00800003,
+ "PMU6: d4_2d_lrdimm_rx_dfe db %d lane %d area %d\n"
+ },
+ {0x00810004,
+ "PMU7: d4_2d_lrdimm_rx_dfe db %d lane %d max area %d best bias 0x%0x\n"
+ },
+ {0x00820001,
+ "PMU0: eye-lane %d is disable\n"
+ },
+ {0x00830003,
+ "PMU5: Setting 0x%x improved rank weight (%4d < %4d)\n"
+ },
+ {0x00840001,
+ "PMU4: Setting 0x%x still optimal\n"
+ },
+ {0x00850002,
+ "PMU5: ---- Training CS%d MR%d DRAM Equalization ----\n"
+ },
+ {0x00860001,
+ "PMU0: eye-lane %d is disable\n"
+ },
+ {0x00870003,
+ "PMU0: eye %d weight %d allTgWeight %d\n"
+ },
+ {0x00880002,
+ "PMU5: FFE figure of merit improved from %d to %d\n"
+ },
+ {0x00890002,
+ "PMU: Error: LP4 rank %d cannot be mapped on tg %d\n"
+ },
+ {0x008a0000,
+ "PMU4: Adjusting vrefDac0 for just 1->x transitions\n"
+ },
+ {0x008b0000,
+ "PMU4: Adjusting vrefDac1 for just 0->x transitions\n"
+ },
+ {0x008c0001,
+ "PMU5: Strong 1, pull-up %d ohms\n"
+ },
+ {0x008d0001,
+ "PMU5: Strong 0, pull-down %d ohms\n"
+ },
+ {0x008e0000,
+ "PMU4: Enabling weak drive strengths (FFE)\n"
+ },
+ {0x008f0000,
+ "PMU5: Changing all weak driver strengths\n"
+ },
+ {0x00900000,
+ "PMU5: Finalizing weak drive strengths\n"
+ },
+ {0x00910000,
+ "PMU4: retraining with optimal drive strength settings\n"
+ },
+ {0x00920002,
+ "PMU0: targeting CsX = %d and CsY = %d\n"
+ },
+ {0x00930001,
+ "PMU1:prbsGenCtl:%x\n"
+ },
+ {0x00940000,
+ "PMU1: loading 2D acsm sequence\n"
+ },
+ {0x00950000,
+ "PMU1: loading 1D acsm sequence\n"
+ },
+ {0x00960002,
+ "PMU3: %d memclocks @ %d to get half of 300ns\n"
+ },
+ {0x00970000,
+ "PMU: Error: User requested MPR read pattern for read DQS training in DDR3 Mode\n"
+ },
+ {0x00980000,
+ "PMU3: Running 1D search for left eye edge\n"
+ },
+ {0x00990001,
+ "PMU1: In Phase Left Edge Search cs %d\n"
+ },
+ {0x009a0001,
+ "PMU1: Out of Phase Left Edge Search cs %d\n"
+ },
+ {0x009b0000,
+ "PMU3: Running 1D search for right eye edge\n"
+ },
+ {0x009c0001,
+ "PMU1: In Phase Right Edge Search cs %d\n"
+ },
+ {0x009d0001,
+ "PMU1: Out of Phase Right Edge Search cs %d\n"
+ },
+ {0x009e0001,
+ "PMU1: mxRdLat training pstate %d\n"
+ },
+ {0x009f0001,
+ "PMU1: mxRdLat search for cs %d\n"
+ },
+ {0x00a00001,
+ "PMU0: MaxRdLat non consistent DtsmLoThldXingInd 0x%03x\n"
+ },
+ {0x00a10003,
+ "PMU4: CS %d Dbyte %d worked with DFIMRL = %d DFICLKs\n"
+ },
+ {0x00a20004,
+ "PMU3: MaxRdLat Read Lane err mask for csn %d, DFIMRL %2d DFIClks, dbyte %d = 0x%03x\n"
+ },
+ {0x00a30003,
+ "PMU3: MaxRdLat Read Lane err mask for csn %d DFIMRL %2d, All dbytes = 0x%03x\n"
+ },
+ {0x00a40001,
+ "PMU: Error: CS%d failed to find a DFIMRL setting that worked for all bytes during MaxRdLat training\n"
+ },
+ {0x00a50002,
+ "PMU3: Smallest passing DFIMRL for all dbytes in CS%d = %d DFIClks\n"
+ },
+ {0x00a60000,
+ "PMU: Error: No passing DFIMRL value found for any chip select during MaxRdLat training\n"
+ },
+ {0x00a70003,
+ "PMU: Error: Dbyte %d lane %d txDqDly passing region is too small (width = %d)\n"
+ },
+ {0x00a80006,
+ "PMU10: Adjusting rxclkdly db %d nib %d from %d+%d=%d->%d\n"
+ },
+ {0x00a90000,
+ "PMU4: TxDqDly Passing Regions (EyeLeft EyeRight -> EyeCenter) Units=1/32 UI\n"
+ },
+ {0x00aa0005,
+ "PMU4: DB %d Lane %d: %3d %3d -> %3d\n"
+ },
+ {0x00ab0002,
+ "PMU2: TXDQ delayLeft[%2d] = %3d (DISCONNECTED)\n"
+ },
+ {0x00ac0004,
+ "PMU2: TXDQ delayLeft[%2d] = %3d oopScaled = %3d selectOop %d\n"
+ },
+ {0x00ad0002,
+ "PMU2: TXDQ delayRight[%2d] = %3d (DISCONNECTED)\n"
+ },
+ {0x00ae0004,
+ "PMU2: TXDQ delayRight[%2d] = %3d oopScaled = %3d selectOop %d\n"
+ },
+ {0x00af0003,
+ "PMU: Error: Dbyte %d lane %d txDqDly passing region is too small (width = %d)\n"
+ },
+ {0x00b00000,
+ "PMU4: TxDqDly Passing Regions (EyeLeft EyeRight -> EyeCenter) Units=1/32 UI\n"
+ },
+ {0x00b10002,
+ "PMU4: DB %d Lane %d: (DISCONNECTED)\n"
+ },
+ {0x00b20005,
+ "PMU4: DB %d Lane %d: %3d %3d -> %3d\n"
+ },
+ {0x00b30002,
+ "PMU3: Running 1D search csn %d for DM Right/NotLeft(%d) eye edge\n"
+ },
+ {0x00b40002,
+ "PMU3: WrDq DM byte%2d with Errcnt %d\n"
+ },
+ {0x00b50002,
+ "PMU3: WrDq DM byte%2d avgDly 0x%04x\n"
+ },
+ {0x00b60002,
+ "PMU1: WrDq DM byte%2d with Errcnt %d\n"
+ },
+ {0x00b70001,
+ "PMU: Error: Dbyte %d txDqDly DM training did not start inside the eye\n"
+ },
+ {0x00b80000,
+ "PMU4: DM TxDqDly Passing Regions (EyeLeft EyeRight -> EyeCenter) Units=1/32 UI\n"
+ },
+ {0x00b90002,
+ "PMU4: DB %d Lane %d: (DISCONNECTED)\n"
+ },
+ {0x00ba0005,
+ "PMU4: DB %d Lane %d: %3d %3d -> %3d\n"
+ },
+ {0x00bb0003,
+ "PMU: Error: Dbyte %d lane %d txDqDly DM passing region is too small (width = %d)\n"
+ },
+ {0x00bc0004,
+ "PMU3: Errcnt for MRD/MWD search nib %2d delay = (%d, 0x%02x) = %d\n"
+ },
+ {0x00bd0000,
+ "PMU3: Precharge all open banks\n"
+ },
+ {0x00be0002,
+ "PMU: Error: Dbyte %d nibble %d found mutliple working coarse delay setting for MRD/MWD\n"
+ },
+ {0x00bf0000,
+ "PMU4: MRD Passing Regions (coarseVal, fineLeft fineRight -> fineCenter)\n"
+ },
+ {0x00c00000,
+ "PMU4: MWD Passing Regions (coarseVal, fineLeft fineRight -> fineCenter)\n"
+ },
+ {0x00c10004,
+ "PMU10: Warning: DB %d nibble %d has multiple working coarse delays, %d and %d, choosing the smaller delay\n"
+ },
+ {0x00c20003,
+ "PMU: Error: Dbyte %d nibble %d MRD/MWD passing region is too small (width = %d)\n"
+ },
+ {0x00c30006,
+ "PMU4: DB %d nibble %d: %3d, %3d %3d -> %3d\n"
+ },
+ {0x00c40002,
+ "PMU1: Start MRD/nMWD %d for csn %d\n"
+ },
+ {0x00c50002,
+ "PMU2: RXDQS delayLeft[%2d] = %3d (DISCONNECTED)\n"
+ },
+ {0x00c60006,
+ "PMU2: RXDQS delayLeft[%2d] = %3d delayOop[%2d] = %3d OopScaled %4d, selectOop %d\n"
+ },
+ {0x00c70002,
+ "PMU2: RXDQS delayRight[%2d] = %3d (DISCONNECTED)\n"
+ },
+ {0x00c80006,
+ "PMU2: RXDQS delayRight[%2d] = %3d delayOop[%2d] = %4d OopScaled %4d, selectOop %d\n"
+ },
+ {0x00c90000,
+ "PMU4: RxClkDly Passing Regions (EyeLeft EyeRight -> EyeCenter)\n"
+ },
+ {0x00ca0002,
+ "PMU4: DB %d nibble %d: (DISCONNECTED)\n"
+ },
+ {0x00cb0005,
+ "PMU4: DB %d nibble %d: %3d %3d -> %3d\n"
+ },
+ {0x00cc0003,
+ "PMU: Error: Dbyte %d nibble %d rxClkDly passing region is too small (width = %d)\n"
+ },
+ {0x00cd0002,
+ "PMU0: goodbar = %d for RDWR_BLEN %d\n"
+ },
+ {0x00ce0001,
+ "PMU3: RxClkDly = %d\n"
+ },
+ {0x00cf0005,
+ "PMU0: db %d l %d absLane %d -> bottom %d top %d\n"
+ },
+ {0x00d00009,
+ "PMU3: BYTE %d - %3d %3d %3d %3d %3d %3d %3d %3d\n"
+ },
+ {0x00d10002,
+ "PMU: Error: dbyte %d lane %d's per-lane vrefDAC's had no passing region\n"
+ },
+ {0x00d20004,
+ "PMU0: db%d l%d - %d %d\n"
+ },
+ {0x00d30002,
+ "PMU0: goodbar = %d for RDWR_BLEN %d\n"
+ },
+ {0x00d40004,
+ "PMU3: db%d l%d saw %d issues at rxClkDly %d\n"
+ },
+ {0x00d50003,
+ "PMU3: db%d l%d first saw a pass->fail edge at rxClkDly %d\n"
+ },
+ {0x00d60002,
+ "PMU3: lane %d PBD = %d\n"
+ },
+ {0x00d70003,
+ "PMU3: db%d l%d first saw a DBI pass->fail edge at rxClkDly %d\n"
+ },
+ {0x00d80003,
+ "PMU2: db%d l%d already passed rxPBD = %d\n"
+ },
+ {0x00d90003,
+ "PMU0: db%d l%d, PBD = %d\n"
+ },
+ {0x00da0002,
+ "PMU: Error: dbyte %d lane %d failed read deskew\n"
+ },
+ {0x00db0003,
+ "PMU0: db%d l%d, inc PBD = %d\n"
+ },
+ {0x00dc0003,
+ "PMU1: Running lane deskew on pstate %d csn %d rdDBIEn %d\n"
+ },
+ {0x00dd0000,
+ "PMU: Error: Read deskew training has been requested, but csrMajorModeDbyte[2] is set\n"
+ },
+ {0x00de0002,
+ "PMU1: AcsmCsMapCtrl%02d 0x%04x\n"
+ },
+ {0x00df0002,
+ "PMU1: AcsmCsMapCtrl%02d 0x%04x\n"
+ },
+ {0x00e00001,
+ "PMU: Error: Wrong PMU image loaded. message Block DramType = 0x%02x, but image built for D3U Type\n"
+ },
+ {0x00e10001,
+ "PMU: Error: Wrong PMU image loaded. message Block DramType = 0x%02x, but image built for D3R Type\n"
+ },
+ {0x00e20001,
+ "PMU: Error: Wrong PMU image loaded. message Block DramType = 0x%02x, but image built for D4U Type\n"
+ },
+ {0x00e30001,
+ "PMU: Error: Wrong PMU image loaded. message Block DramType = 0x%02x, but image built for D4R Type\n"
+ },
+ {0x00e40001,
+ "PMU: Error: Wrong PMU image loaded. message Block DramType = 0x%02x, but image built for D4LR Type\n"
+ },
+ {0x00e50000,
+ "PMU: Error: Both 2t timing mode and ddr4 geardown mode specified in the messageblock's PhyCfg and MR3 fields. Only one can be enabled\n"
+ },
+ {0x00e60003,
+ "PMU10: PHY TOTALS - NUM_DBYTES %d NUM_NIBBLES %d NUM_ANIBS %d\n"
+ },
+ {0x00e70006,
+ "PMU10: CSA=0x%02x, CSB=0x%02x, TSTAGES=0x%04x, HDTOUT=%d, MMISC=%d DRAMFreq=%dMT DramType=LPDDR3\n"
+ },
+ {0x00e80006,
+ "PMU10: CSA=0x%02x, CSB=0x%02x, TSTAGES=0x%04x, HDTOUT=%d, MMISC=%d DRAMFreq=%dMT DramType=LPDDR4\n"
+ },
+ {0x00e90008,
+ "PMU10: CS=0x%02x, TSTAGES=0x%04x, HDTOUT=%d, 2T=%d, MMISC=%d AddrMirror=%d DRAMFreq=%dMT DramType=%d\n"
+ },
+ {0x00ea0004,
+ "PMU10: Pstate%d MR0=0x%04x MR1=0x%04x MR2=0x%04x\n"
+ },
+ {0x00eb0008,
+ "PMU10: Pstate%d MRS MR0=0x%04x MR1=0x%04x MR2=0x%04x MR3=0x%04x MR4=0x%04x MR5=0x%04x MR6=0x%04x\n"
+ },
+ {0x00ec0005,
+ "PMU10: Pstate%d MRS MR1_A0=0x%04x MR2_A0=0x%04x MR3_A0=0x%04x MR11_A0=0x%04x\n"
+ },
+ {0x00ed0000,
+ "PMU10: UseBroadcastMR set. All ranks and channels use MRXX_A0 for MR settings.\n"
+ },
+ {0x00ee0005,
+ "PMU10: Pstate%d MRS MR01_A0=0x%02x MR02_A0=0x%02x MR03_A0=0x%02x MR11_A0=0x%02x\n"
+ },
+ {0x00ef0005,
+ "PMU10: Pstate%d MRS MR12_A0=0x%02x MR13_A0=0x%02x MR14_A0=0x%02x MR22_A0=0x%02x\n"
+ },
+ {0x00f00005,
+ "PMU10: Pstate%d MRS MR01_A1=0x%02x MR02_A1=0x%02x MR03_A1=0x%02x MR11_A1=0x%02x\n"
+ },
+ {0x00f10005,
+ "PMU10: Pstate%d MRS MR12_A1=0x%02x MR13_A1=0x%02x MR14_A1=0x%02x MR22_A1=0x%02x\n"
+ },
+ {0x00f20005,
+ "PMU10: Pstate%d MRS MR01_B0=0x%02x MR02_B0=0x%02x MR03_B0=0x%02x MR11_B0=0x%02x\n"
+ },
+ {0x00f30005,
+ "PMU10: Pstate%d MRS MR12_B0=0x%02x MR13_B0=0x%02x MR14_B0=0x%02x MR22_B0=0x%02x\n"
+ },
+ {0x00f40005,
+ "PMU10: Pstate%d MRS MR01_B1=0x%02x MR02_B1=0x%02x MR03_B1=0x%02x MR11_B1=0x%02x\n"
+ },
+ {0x00f50005,
+ "PMU10: Pstate%d MRS MR12_B1=0x%02x MR13_B1=0x%02x MR14_B1=0x%02x MR22_B1=0x%02x\n"
+ },
+ {0x00f60002,
+ "PMU1: AcsmOdtCtrl%02d 0x%02x\n"
+ },
+ {0x00f70002,
+ "PMU1: AcsmCsMapCtrl%02d 0x%04x\n"
+ },
+ {0x00f80002,
+ "PMU1: AcsmCsMapCtrl%02d 0x%04x\n"
+ },
+ {0x00f90000,
+ "PMU1: HwtCAMode set\n"
+ },
+ {0x00fa0001,
+ "PMU3: DDR4 infinite preamble enter/exit mode %d\n"
+ },
+ {0x00fb0002,
+ "PMU1: In rxenb_train() csn=%d pstate=%d\n"
+ },
+ {0x00fc0000,
+ "PMU3: Finding DQS falling edge\n"
+ },
+ {0x00fd0000,
+ "PMU3: Searching for DDR3/LPDDR3/LPDDR4 read preamble\n"
+ },
+ {0x00fe0009,
+ "PMU3: dtsm fails Even Nibbles : %2x %2x %2x %2x %2x %2x %2x %2x %2x\n"
+ },
+ {0x00ff0009,
+ "PMU3: dtsm fails Odd Nibbles : %2x %2x %2x %2x %2x %2x %2x %2x %2x\n"
+ },
+ {0x01000002,
+ "PMU3: Preamble search pass=%d anyfail=%d\n"
+ },
+ {0x01010000,
+ "PMU: Error: RxEn training preamble not found\n"
+ },
+ {0x01020000,
+ "PMU3: Found DQS pre-amble\n"
+ },
+ {0x01030001,
+ "PMU: Error: Dbyte %d couldn't find the rising edge of DQS during RxEn Training\n"
+ },
+ {0x01040000,
+ "PMU3: RxEn aligning to first rising edge of burst\n"
+ },
+ {0x01050001,
+ "PMU3: Decreasing RxEn delay by %d fine step to allow full capture of reads\n"
+ },
+ {0x01060001,
+ "PMU3: MREP Delay = %d\n"
+ },
+ {0x01070003,
+ "PMU3: Errcnt for MREP nib %2d delay = %2d is %d\n"
+ },
+ {0x01080002,
+ "PMU3: MREP nibble %d sampled a 1 at data buffer delay %d\n"
+ },
+ {0x01090002,
+ "PMU3: MREP nibble %d saw a 0 to 1 transition at data buffer delay %d\n"
+ },
+ {0x010a0000,
+ "PMU2: MREP did not find a 0 to 1 transition for all nibbles. Failing nibbles assumed to have rising edge close to fine delay 63\n"
+ },
+ {0x010b0002,
+ "PMU2: Rising edge found in alias window, setting rxDly for nibble %d = %d\n"
+ },
+ {0x010c0002,
+ "PMU: Error: Failed MREP for nib %d with %d one\n"
+ },
+ {0x010d0003,
+ "PMU2: Rising edge not found in alias window with %d one, leaving rxDly for nibble %d = %d\n"
+ },
+ {0x010e0002,
+ "PMU3: Training DIMM %d CSn %d\n"
+ },
+ {0x010f0001,
+ "PMU3: exitCAtrain_lp3 cs 0x%x\n"
+ },
+ {0x01100001,
+ "PMU3: enterCAtrain_lp3 cs 0x%x\n"
+ },
+ {0x01110001,
+ "PMU3: CAtrain_switchmsb_lp3 cs 0x%x\n"
+ },
+ {0x01120001,
+ "PMU3: CATrain_rdwr_lp3 looking for pattern %x\n"
+ },
+ {0x01130000,
+ "PMU3: exitCAtrain_lp4\n"
+ },
+ {0x01140001,
+ "PMU3: DEBUG enterCAtrain_lp4 1: cs 0x%x\n"
+ },
+ {0x01150001,
+ "PMU3: DEBUG enterCAtrain_lp4 3: Put dbyte %d in async mode\n"
+ },
+ {0x01160000,
+ "PMU3: DEBUG enterCAtrain_lp4 5: Send MR13 to turn on CA training\n"
+ },
+ {0x01170003,
+ "PMU3: DEBUG enterCAtrain_lp4 7: idx = %d vref = %x mr12 = %x\n"
+ },
+ {0x01180001,
+ "PMU3: CATrain_rdwr_lp4 looking for pattern %x\n"
+ },
+ {0x01190004,
+ "PMU3: Phase %d CAreadbackA db:%d %x xo:%x\n"
+ },
+ {0x011a0005,
+ "PMU3: DEBUG lp4SetCatrVref 1: cs=%d chan=%d mr12=%x vref=%d.%d%%\n"
+ },
+ {0x011b0003,
+ "PMU3: DEBUG lp4SetCatrVref 3: mr12 = %x send vref= %x to db=%d\n"
+ },
+ {0x011c0000,
+ "PMU10:Optimizing vref\n"
+ },
+ {0x011d0004,
+ "PMU4:mr12:%2x cs:%d chan %d r:%4x\n"
+ },
+ {0x011e0005,
+ "PMU3: i:%2d bstr:%2d bsto:%2d st:%d r:%d\n"
+ },
+ {0x011f0002,
+ "Failed to find sufficient CA Vref Passing Region for CS %d ch. %d\n"
+ },
+ {0x01200005,
+ "PMU3:Found %d.%d%% MR12:%x for cs:%d chan %d\n"
+ },
+ {0x01210002,
+ "PMU3:Calculated %d for AtxImpedence from acx %d.\n"
+ },
+ {0x01220000,
+ "PMU3:CA Odt impedence ==0. Use default vref.\n"
+ },
+ {0x01230003,
+ "PMU3:Calculated %d.%d%% for Vref MR12=0x%x.\n"
+ },
+ {0x01240000,
+ "PMU3: CAtrain_lp\n"
+ },
+ {0x01250000,
+ "PMU3: CAtrain Begins.\n"
+ },
+ {0x01260001,
+ "PMU3: CAtrain_lp testing dly %d\n"
+ },
+ {0x01270001,
+ "PMU5: CA bitmap dump for cs %x\n"
+ },
+ {0x01280001,
+ "PMU5: CAA%d "
+ },
+ {0x01290001, "%02x"
+ },
+ {0x012a0000, "\n"
+ },
+ {0x012b0001,
+ "PMU5: CAB%d "
+ },
+ {0x012c0001, "%02x"
+ },
+ {0x012d0000, "\n"
+ },
+ {0x012e0003,
+ "PMU3: anibi=%d, anibichan[anibi]=%d ,chan=%d\n"
+ },
+ {0x012f0001, "%02x"
+ },
+ {0x01300001, "\nPMU3:Raw CA setting :%x"
+ },
+ {0x01310002, "\nPMU3:ATxDly setting:%x margin:%d\n"
+ },
+ {0x01320002, "\nPMU3:InvClk ATxDly setting:%x margin:%d\n"
+ },
+ {0x01330000, "\nPMU3:No Range found!\n"
+ },
+ {0x01340003,
+ "PMU3: 2 anibi=%d, anibichan[anibi]=%d ,chan=%d"
+ },
+ {0x01350002, "\nPMU3: no neg clock => CA setting anib=%d, :%d\n"
+ },
+ {0x01360001,
+ "PMU3:Normal margin:%d\n"
+ },
+ {0x01370001,
+ "PMU3:Inverted margin:%d\n"
+ },
+ {0x01380000,
+ "PMU3:Using Inverted clock\n"
+ },
+ {0x01390000,
+ "PMU3:Using normal clk\n"
+ },
+ {0x013a0003,
+ "PMU3: 3 anibi=%d, anibichan[anibi]=%d ,chan=%d\n"
+ },
+ {0x013b0002,
+ "PMU3: Setting ATxDly for anib %x to %x\n"
+ },
+ {0x013c0000,
+ "PMU: Error: CA Training Failed.\n"
+ },
+ {0x013d0000,
+ "PMU1: Writing MRs\n"
+ },
+ {0x013e0000,
+ "PMU4:Using MR12 values from 1D CA VREF training.\n"
+ },
+ {0x013f0000,
+ "PMU3:Writing all MRs to fsp 1\n"
+ },
+ {0x01400000,
+ "PMU10:Lp4Quickboot mode.\n"
+ },
+ {0x01410000,
+ "PMU3: Writing MRs\n"
+ },
+ {0x01420001,
+ "PMU10: Setting boot clock divider to %d\n"
+ },
+ {0x01430000,
+ "PMU3: Resetting DRAM\n"
+ },
+ {0x01440000,
+ "PMU3: setup for RCD initalization\n"
+ },
+ {0x01450000,
+ "PMU3: pmu_exit_SR from dev_init()\n"
+ },
+ {0x01460000,
+ "PMU3: initializing RCD\n"
+ },
+ {0x01470000,
+ "PMU10: **** Executing 2D Image ****\n"
+ },
+ {0x01480001,
+ "PMU10: **** Start DDR4 Training. PMU Firmware Revision 0x%04x ****\n"
+ },
+ {0x01490001,
+ "PMU10: **** Start DDR3 Training. PMU Firmware Revision 0x%04x ****\n"
+ },
+ {0x014a0001,
+ "PMU10: **** Start LPDDR3 Training. PMU Firmware Revision 0x%04x ****\n"
+ },
+ {0x014b0001,
+ "PMU10: **** Start LPDDR4 Training. PMU Firmware Revision 0x%04x ****\n"
+ },
+ {0x014c0000,
+ "PMU: Error: Mismatched internal revision between DCCM and ICCM images\n"
+ },
+ {0x014d0001,
+ "PMU10: **** Testchip %d Specific Firmware ****\n"
+ },
+ {0x014e0000,
+ "PMU1: LRDIMM with EncodedCS mode, one DIMM\n"
+ },
+ {0x014f0000,
+ "PMU1: LRDIMM with EncodedCS mode, two DIMMs\n"
+ },
+ {0x01500000,
+ "PMU1: RDIMM with EncodedCS mode, one DIMM\n"
+ },
+ {0x01510000,
+ "PMU2: Starting LRDIMM MREP training for all ranks\n"
+ },
+ {0x01520000,
+ "PMU199: LRDIMM MREP training for all ranks completed\n"
+ },
+ {0x01530000,
+ "PMU2: Starting LRDIMM DWL training for all ranks\n"
+ },
+ {0x01540000,
+ "PMU199: LRDIMM DWL training for all ranks completed\n"
+ },
+ {0x01550000,
+ "PMU2: Starting LRDIMM MRD training for all ranks\n"
+ },
+ {0x01560000,
+ "PMU199: LRDIMM MRD training for all ranks completed\n"
+ },
+ {0x01570000,
+ "PMU2: Starting RXEN training for all ranks\n"
+ },
+ {0x01580000,
+ "PMU2: Starting write leveling fine delay training for all ranks\n"
+ },
+ {0x01590000,
+ "PMU2: Starting LRDIMM MWD training for all ranks\n"
+ },
+ {0x015a0000,
+ "PMU199: LRDIMM MWD training for all ranks completed\n"
+ },
+ {0x015b0000,
+ "PMU2: Starting write leveling fine delay training for all ranks\n"
+ },
+ {0x015c0000,
+ "PMU2: Starting read deskew training\n"
+ },
+ {0x015d0000,
+ "PMU2: Starting SI friendly 1d RdDqs training for all ranks\n"
+ },
+ {0x015e0000,
+ "PMU2: Starting write leveling coarse delay training for all ranks\n"
+ },
+ {0x015f0000,
+ "PMU2: Starting 1d WrDq training for all ranks\n"
+ },
+ {0x01600000,
+ "PMU2: Running DQS2DQ Oscillator for all ranks\n"
+ },
+ {0x01610000,
+ "PMU2: Starting again read deskew training but with PRBS\n"
+ },
+ {0x01620000,
+ "PMU2: Starting 1d RdDqs training for all ranks\n"
+ },
+ {0x01630000,
+ "PMU2: Starting again 1d WrDq training for all ranks\n"
+ },
+ {0x01640000,
+ "PMU2: Starting MaxRdLat training\n"
+ },
+ {0x01650000,
+ "PMU2: Starting 2d WrDq training for all ranks\n"
+ },
+ {0x01660000,
+ "PMU2: Starting 2d RdDqs training for all ranks\n"
+ },
+ {0x01670002,
+ "PMU3:read_fifo %x %x\n"
+ },
+ {0x01680001,
+ "PMU: Error: Invalid PhyDrvImpedance of 0x%x specified in message block.\n"
+ },
+ {0x01690001,
+ "PMU: Error: Invalid PhyOdtImpedance of 0x%x specified in message block.\n"
+ },
+ {0x016a0001,
+ "PMU: Error: Invalid BPZNResVal of 0x%x specified in message block.\n"
+ },
+ {0x016b0005,
+ "PMU3: fixRxEnBackOff csn:%d db:%d dn:%d bo:%d dly:%x\n"
+ },
+ {0x016c0001,
+ "PMU3: fixRxEnBackOff dly:%x\n"
+ },
+ {0x016d0000,
+ "PMU3: Entering setupPpt\n"
+ },
+ {0x016e0000,
+ "PMU3: Start lp4PopulateHighLowBytes\n"
+ },
+ {0x016f0002,
+ "PMU3:Dbyte Detect: db%d received %x\n"
+ },
+ {0x01700002,
+ "PMU3:getDqs2Dq read %x from dbyte %d\n"
+ },
+ {0x01710002,
+ "PMU3:getDqs2Dq(2) read %x from dbyte %d\n"
+ },
+ {0x01720001,
+ "PMU: Error: Dbyte %d read 0 from the DQS oscillator it is connected to\n"
+ },
+ {0x01730002,
+ "PMU4: Dbyte %d dqs2dq = %d/32 UI\n"
+ },
+ {0x01740003,
+ "PMU3:getDqs2Dq set dqs2dq:%d/32 ui (%d ps) from dbyte %d\n"
+ },
+ {0x01750003,
+ "PMU3: Setting coarse delay in AtxDly chiplet %d from 0x%02x to 0x%02x\n"
+ },
+ {0x01760003,
+ "PMU3: Clearing coarse delay in AtxDly chiplet %d from 0x%02x to 0x%02x\n"
+ },
+ {0x01770000,
+ "PMU3: Performing DDR4 geardown sync sequence\n"
+ },
+ {0x01780000,
+ "PMU1: Enter self refresh\n"
+ },
+ {0x01790000,
+ "PMU1: Exit self refresh\n"
+ },
+ {0x017a0000,
+ "PMU: Error: No dbiEnable with lp4\n"
+ },
+ {0x017b0000,
+ "PMU: Error: No dbiDisable with lp4\n"
+ },
+ {0x017c0001,
+ "PMU1: DDR4 update Rx DBI Setting disable %d\n"
+ },
+ {0x017d0001,
+ "PMU1: DDR4 update 2nCk WPre Setting disable %d\n"
+ },
+ {0x017e0005,
+ "PMU1: read_delay: db%d lane%d delays[%2d] = 0x%02x (max 0x%02x)\n"
+ },
+ {0x017f0004,
+ "PMU1: write_delay: db%d lane%d delays[%2d] = 0x%04x\n"
+ },
+ {0x01800001,
+ "PMU5: ID=%d -- db0 db1 db2 db3 db4 db5 db6 db7 db8 db9 --\n"
+ },
+ {0x0181000b,
+ "PMU5: [%d]:0x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x\n"
+ },
+ {0x01820003,
+ "PMU2: dump delays - pstate=%d dimm=%d csn=%d\n"
+ },
+ {0x01830000,
+ "PMU3: Printing Mid-Training Delay Information\n"
+ },
+ {0x01840001,
+ "PMU5: CS%d <<KEY>> 0 TrainingCntr <<KEY>> coarse(15:10) fine(9:0)\n"
+ },
+ {0x01850001,
+ "PMU5: CS%d <<KEY>> 0 RxEnDly, 1 RxClkDly <<KEY>> coarse(10:6) fine(5:0)\n"
+ },
+ {0x01860001,
+ "PMU5: CS%d <<KEY>> 0 TxDqsDly, 1 TxDqDly <<KEY>> coarse(9:6) fine(5:0)\n"
+ },
+ {0x01870001,
+ "PMU5: CS%d <<KEY>> 0 RxPBDly <<KEY>> 1 Delay Unit ~= 7ps\n"
+ },
+ {0x01880000,
+ "PMU5: all CS <<KEY>> 0 DFIMRL <<KEY>> Units = DFI clocks\n"
+ },
+ {0x01890000,
+ "PMU5: all CS <<KEY>> VrefDACs <<KEY>> DAC(6:0)\n"
+ },
+ {0x018a0000,
+ "PMU1: Set DMD in MR13 and wrDBI in MR3 for training\n"
+ },
+ {0x018b0000,
+ "PMU: Error: getMaxRxen() failed to find largest rxen nibble delay\n"
+ },
+ {0x018c0003,
+ "PMU2: getMaxRxen(): maxDly %d maxTg %d maxNib %d\n"
+ },
+ {0x018d0003,
+ "PMU2: getRankMaxRxen(): maxDly %d Tg %d maxNib %d\n"
+ },
+ {0x018e0000,
+ "PMU1: skipping CDD calculation in 2D image\n"
+ },
+ {0x018f0001,
+ "PMU3: Calculating CDDs for pstate %d\n"
+ },
+ {0x01900003,
+ "PMU3: rxFromDly[%d][%d] = %d\n"
+ },
+ {0x01910003,
+ "PMU3: rxToDly [%d][%d] = %d\n"
+ },
+ {0x01920003,
+ "PMU3: rxDly [%d][%d] = %d\n"
+ },
+ {0x01930003,
+ "PMU3: txDly [%d][%d] = %d\n"
+ },
+ {0x01940003,
+ "PMU3: allFine CDD_RR_%d_%d = %d\n"
+ },
+ {0x01950003,
+ "PMU3: allFine CDD_WW_%d_%d = %d\n"
+ },
+ {0x01960003,
+ "PMU3: CDD_RR_%d_%d = %d\n"
+ },
+ {0x01970003,
+ "PMU3: CDD_WW_%d_%d = %d\n"
+ },
+ {0x01980003,
+ "PMU3: allFine CDD_RW_%d_%d = %d\n"
+ },
+ {0x01990003,
+ "PMU3: allFine CDD_WR_%d_%d = %d\n"
+ },
+ {0x019a0003,
+ "PMU3: CDD_RW_%d_%d = %d\n"
+ },
+ {0x019b0003,
+ "PMU3: CDD_WR_%d_%d = %d\n"
+ },
+ {0x019c0004,
+ "PMU3: F%dBC2x_B%d_D%d = 0x%02x\n"
+ },
+ {0x019d0004,
+ "PMU3: F%dBC3x_B%d_D%d = 0x%02x\n"
+ },
+ {0x019e0004,
+ "PMU3: F%dBC4x_B%d_D%d = 0x%02x\n"
+ },
+ {0x019f0004,
+ "PMU3: F%dBC5x_B%d_D%d = 0x%02x\n"
+ },
+ {0x01a00004,
+ "PMU3: F%dBC8x_B%d_D%d = 0x%02x\n"
+ },
+ {0x01a10004,
+ "PMU3: F%dBC9x_B%d_D%d = 0x%02x\n"
+ },
+ {0x01a20004,
+ "PMU3: F%dBCAx_B%d_D%d = 0x%02x\n"
+ },
+ {0x01a30004,
+ "PMU3: F%dBCBx_B%d_D%d = 0x%02x\n"
+ },
+ {0x01a40000,
+ "PMU10: Entering context_switch_postamble\n"
+ },
+ {0x01a50003,
+ "PMU10: context_switch_postamble is enabled for DIMM %d, RC0A=0x%x, RC3x=0x%x\n"
+ },
+ {0x01a60000,
+ "PMU10: Setting bcw fspace 0\n"
+ },
+ {0x01a70001,
+ "PMU10: Sending BC0A = 0x%x\n"
+ },
+ {0x01a80001,
+ "PMU10: Sending BC6x = 0x%x\n"
+ },
+ {0x01a90001,
+ "PMU10: Sending RC0A = 0x%x\n"
+ },
+ {0x01aa0001,
+ "PMU10: Sending RC3x = 0x%x\n"
+ },
+ {0x01ab0001,
+ "PMU10: Sending RC0A = 0x%x\n"
+ },
+ {0x01ac0001,
+ "PMU1: enter_lp3: DEBUG: pstate = %d\n"
+ },
+ {0x01ad0001,
+ "PMU1: enter_lp3: DEBUG: dfifreqxlat_pstate = %d\n"
+ },
+ {0x01ae0001,
+ "PMU1: enter_lp3: DEBUG: pllbypass = %d\n"
+ },
+ {0x01af0001,
+ "PMU1: enter_lp3: DEBUG: forcecal = %d\n"
+ },
+ {0x01b00001,
+ "PMU1: enter_lp3: DEBUG: pllmaxrange = 0x%x\n"
+ },
+ {0x01b10001,
+ "PMU1: enter_lp3: DEBUG: dacval_out = 0x%x\n"
+ },
+ {0x01b20001,
+ "PMU1: enter_lp3: DEBUG: pllctrl3 = 0x%x\n"
+ },
+ {0x01b30000,
+ "PMU3: Loading DRAM with BIOS supplied MR values and entering self refresh prior to exiting PMU code.\n"
+ },
+ {0x01b40002,
+ "PMU3: Setting DataBuffer function space of dimmcs 0x%02x to %d\n"
+ },
+ {0x01b50002,
+ "PMU4: Setting RCW FxRC%Xx = 0x%02x\n"
+ },
+ {0x01b60002,
+ "PMU4: Setting RCW FxRC%02x = 0x%02x\n"
+ },
+ {0x01b70001,
+ "PMU1: DDR4 update Rd Pre Setting disable %d\n"
+ },
+ {0x01b80002,
+ "PMU2: Setting BCW FxBC%Xx = 0x%02x\n"
+ },
+ {0x01b90002,
+ "PMU2: Setting BCW BC%02x = 0x%02x\n"
+ },
+ {0x01ba0002,
+ "PMU2: Setting BCW PBA mode FxBC%Xx = 0x%02x\n"
+ },
+ {0x01bb0002,
+ "PMU2: Setting BCW PBA mode BC%02x = 0x%02x\n"
+ },
+ {0x01bc0003,
+ "PMU4: BCW value for dimm %d, fspace %d, addr 0x%04x\n"
+ },
+ {0x01bd0002,
+ "PMU4: DB %d, value 0x%02x\n"
+ },
+ {0x01be0000,
+ "PMU6: WARNING MREP underflow, set to min value -2 coarse, 0 fine\n"
+ },
+ {0x01bf0004,
+ "PMU6: LRDIMM Writing final data buffer fine delay value nib %2d, trainDly %3d, fineDly code %2d, new MREP fine %2d\n"
+ },
+ {0x01c00003,
+ "PMU6: LRDIMM Writing final data buffer fine delay value nib %2d, trainDly %3d, fineDly code %2d\n"
+ },
+ {0x01c10003,
+ "PMU6: LRDIMM Writing data buffer fine delay type %d nib %2d, code %2d\n"
+ },
+ {0x01c20002,
+ "PMU6: Writing final data buffer coarse delay value dbyte %2d, coarse = 0x%02x\n"
+ },
+ {0x01c30003,
+ "PMU4: data 0x%04x at MB addr 0x%08x saved at CSR addr 0x%08x\n"
+ },
+ {0x01c40003,
+ "PMU4: data 0x%04x at MB addr 0x%08x restored from CSR addr 0x%08x\n"
+ },
+ {0x01c50003,
+ "PMU4: data 0x%04x at MB addr 0x%08x saved at CSR addr 0x%08x\n"
+ },
+ {0x01c60003,
+ "PMU4: data 0x%04x at MB addr 0x%08x restored from CSR addr 0x%08x\n"
+ },
+ {0x01c70001,
+ "PMU3: Update BC00, BC01, BC02 for rank-dimm 0x%02x\n"
+ },
+ {0x01c80000,
+ "PMU3: Writing D4 RDIMM RCD Control words F0RC00 -> F0RC0F\n"
+ },
+ {0x01c90000,
+ "PMU3: Disable parity in F0RC0E\n"
+ },
+ {0x01ca0000,
+ "PMU3: Writing D4 RDIMM RCD Control words F1RC00 -> F1RC05\n"
+ },
+ {0x01cb0000,
+ "PMU3: Writing D4 RDIMM RCD Control words F1RC1x -> F1RC9x\n"
+ },
+ {0x01cc0000,
+ "PMU3: Writing D4 Data buffer Control words BC00 -> BC0E\n"
+ },
+ {0x01cd0002,
+ "PMU1: setAltCL Sending MR0 0x%x cl=%d\n"
+ },
+ {0x01ce0002,
+ "PMU1: restoreFromAltCL Sending MR0 0x%x cl=%d\n"
+ },
+ {0x01cf0002,
+ "PMU1: restoreAcsmFromAltCL Sending MR0 0x%x cl=%d\n"
+ },
+ {0x01d00002,
+ "PMU2: Setting D3R RC%d = 0x%01x\n"
+ },
+ {0x01d10000,
+ "PMU3: Writing D3 RDIMM RCD Control words RC0 -> RC11\n"
+ },
+ {0x01d20002,
+ "PMU0: VrefDAC0/1 vddqStart %d dacToVddq %d\n"
+ },
+ {0x01d30001,
+ "PMU: Error: Messageblock phyVref=0x%x is above the limit for TSMC28's attenuated LPDDR4 receivers. Please see the pub databook\n"
+ },
+ {0x01d40001,
+ "PMU: Error: Messageblock phyVref=0x%x is above the limit for TSMC28's attenuated DDR4 receivers. Please see the pub databook\n"
+ },
+ {0x01d50001,
+ "PMU0: PHY VREF @ (%d/1000) VDDQ\n"
+ },
+ {0x01d60002,
+ "PMU0: initalizing phy vrefDacs to %d ExtVrefRange %x\n"
+ },
+ {0x01d70002,
+ "PMU0: initalizing global vref to %d range %d\n"
+ },
+ {0x01d80002,
+ "PMU4: Setting initial device vrefDQ for CS%d to MR6 = 0x%04x\n"
+ },
+ {0x01d90003,
+ "PMU1: In write_level_fine() csn=%d dimm=%d pstate=%d\n"
+ },
+ {0x01da0000,
+ "PMU3: Fine write leveling hardware search increasing TxDqsDly until full bursts are seen\n"
+ },
+ {0x01db0000,
+ "PMU4: WL normalized pos : ........................|........................\n"
+ },
+ {0x01dc0007,
+ "PMU4: WL margin for nib %2d: %08x%08x%08x%08x%08x%08x\n"
+ },
+ {0x01dd0000,
+ "PMU4: WL normalized pos : ........................|........................\n"
+ },
+ {0x01de0000,
+ "PMU3: Exiting write leveling mode\n"
+ },
+ {0x01df0001,
+ "PMU3: got %d for cl in load_wrlvl_acsm\n"
+ },
+ {0x01e00003,
+ "PMU1: In write_level_coarse() csn=%d dimm=%d pstate=%d\n"
+ },
+ {0x01e10003,
+ "PMU3: left eye edge search db:%d ln:%d dly:0x%x\n"
+ },
+ {0x01e20003,
+ "PMU3: right eye edge search db:%d ln:%d dly:0x%x\n"
+ },
+ {0x01e30004,
+ "PMU3: eye center db:%d ln:%d dly:0x%x (maxdq:%x)\n"
+ },
+ {0x01e40003,
+ "PMU3: Wrote to TxDqDly db:%d ln:%d dly:0x%x\n"
+ },
+ {0x01e50003,
+ "PMU3: Wrote to TxDqDly db:%d ln:%d dly:0x%x\n"
+ },
+ {0x01e60002,
+ "PMU3: Coarse write leveling dbyte%2d is still failing for TxDqsDly=0x%04x\n"
+ },
+ {0x01e70002,
+ "PMU4: Coarse write leveling iteration %d saw %d data miscompares across the entire phy\n"
+ },
+ {0x01e80000,
+ "PMU: Error: Failed write leveling coarse\n"
+ },
+ {0x01e90001,
+ "PMU3: got %d for cl in load_wrlvl_acsm\n"
+ },
+ {0x01ea0003,
+ "PMU3: In write_level_coarse() csn=%d dimm=%d pstate=%d\n"
+ },
+ {0x01eb0003,
+ "PMU3: left eye edge search db:%d ln:%d dly:0x%x\n"
+ },
+ {0x01ec0003,
+ "PMU3: right eye edge search db: %d ln: %d dly: 0x%x\n"
+ },
+ {0x01ed0004,
+ "PMU3: eye center db: %d ln: %d dly: 0x%x (maxdq: 0x%x)\n"
+ },
+ {0x01ee0003,
+ "PMU3: Wrote to TxDqDly db: %d ln: %d dly: 0x%x\n"
+ },
+ {0x01ef0003,
+ "PMU3: Wrote to TxDqDly db: %d ln: %d dly: 0x%x\n"
+ },
+ {0x01f00002,
+ "PMU3: Coarse write leveling nibble%2d is still failing for TxDqsDly=0x%04x\n"
+ },
+ {0x01f10002,
+ "PMU4: Coarse write leveling iteration %d saw %d data miscompares across the entire phy\n"
+ },
+ {0x01f20000,
+ "PMU: Error: Failed write leveling coarse\n"
+ },
+ {0x01f30000,
+ "PMU4: WL normalized pos : ................................|................................\n"
+ },
+ {0x01f40009,
+ "PMU4: WL margin for nib %2d: %08x%08x%08x%08x%08x%08x%08x%08x\n"
+ },
+ {0x01f50000,
+ "PMU4: WL normalized pos : ................................|................................\n"
+ },
+ {0x01f60001,
+ "PMU8: Adjust margin after WL coarse to be larger than %d\n"
+ },
+ {0x01f70001,
+ "PMU: Error: All margin after write leveling coarse are smaller than minMargin %d\n"
+ },
+ {0x01f80002,
+ "PMU8: Decrement nib %d TxDqsDly by %d fine step\n"
+ },
+ {0x01f90003,
+ "PMU3: In write_level_coarse() csn=%d dimm=%d pstate=%d\n"
+ },
+ {0x01fa0005,
+ "PMU2: Write level: dbyte %d nib%d dq/dmbi %2d dqsfine 0x%04x dqDly 0x%04x\n"
+ },
+ {0x01fb0002,
+ "PMU3: Coarse write leveling nibble%2d is still failing for TxDqsDly=0x%04x\n"
+ },
+ {0x01fc0002,
+ "PMU4: Coarse write leveling iteration %d saw %d data miscompares across the entire phy\n"
+ },
+ {0x01fd0000,
+ "PMU: Error: Failed write leveling coarse\n"
+ },
+ {0x01fe0001,
+ "PMU3: DWL delay = %d\n"
+ },
+ {0x01ff0003,
+ "PMU3: Errcnt for DWL nib %2d delay = %2d is %d\n"
+ },
+ {0x02000002,
+ "PMU3: DWL nibble %d sampled a 1 at delay %d\n"
+ },
+ {0x02010003,
+ "PMU3: DWL nibble %d passed at delay %d. Rising edge was at %d\n"
+ },
+ {0x02020000,
+ "PMU2: DWL did nto find a rising edge of memclk for all nibbles. Failing nibbles assumed to have rising edge close to fine delay 63\n"
+ },
+ {0x02030002,
+ "PMU2: Rising edge found in alias window, setting wrlvlDly for nibble %d = %d\n"
+ },
+ {0x02040002,
+ "PMU: Error: Failed DWL for nib %d with %d one\n"
+ },
+ {0x02050003,
+ "PMU2: Rising edge not found in alias window with %d one, leaving wrlvlDly for nibble %d = %d\n"
+ },
+ {0x04000000,
+ "PMU: Error:Mailbox Buffer Overflowed.\n"
+ },
+ {0x04010000,
+ "PMU: Error:Mailbox Buffer Overflowed.\n"
+ },
+ {0x04020000,
+ "PMU: ***** Assertion Error - terminating *****\n"
+ },
+ {0x04030002,
+ "PMU1: swapByte db %d by %d\n"
+ },
+ {0x04040003,
+ "PMU3: get_cmd_dly max(%d ps, %d memclk) = %d\n"
+ },
+ {0x04050002,
+ "PMU0: Write CSR 0x%06x 0x%04x\n"
+ },
+ {0x04060002,
+ "PMU0: hwt_init_ppgc_prbs(): Polynomial: %x, Deg: %d\n"
+ },
+ {0x04070001,
+ "PMU: Error: acsm_set_cmd to non existent instruction address %d\n"
+ },
+ {0x04080001,
+ "PMU: Error: acsm_set_cmd with unknown ddr cmd 0x%x\n"
+ },
+ {0x0409000c,
+ "PMU1: acsm_addr %02x, acsm_flgs %04x, ddr_cmd %02x, cmd_dly %02x, ddr_addr %04x, ddr_bnk %02x, ddr_cs %02x, cmd_rcnt %02x, AcsmSeq0/1/2/3 %04x %04x %04x %04x\n"
+ },
+ {0x040a0000,
+ "PMU: Error: Polling on ACSM done failed to complete in acsm_poll_done()...\n"
+ },
+ {0x040b0000,
+ "PMU1: acsm RUN\n"
+ },
+ {0x040c0000,
+ "PMU1: acsm STOPPED\n"
+ },
+ {0x040d0002,
+ "PMU1: acsm_init: acsm_mode %04x mxrdlat %04x\n"
+ },
+ {0x040e0002,
+ "PMU: Error: setAcsmCLCWL: cl and cwl must be each >= 2 and 5, resp. CL=%d CWL=%d\n"
+ },
+ {0x040f0002,
+ "PMU: Error: setAcsmCLCWL: cl and cwl must be each >= 5. CL=%d CWL=%d\n"
+ },
+ {0x04100002,
+ "PMU1: setAcsmCLCWL: CASL %04d WCASL %04d\n"
+ },
+ {0x04110001,
+ "PMU: Error: Reserved value of register F0RC0F found in message block: 0x%04x\n"
+ },
+ {0x04120001,
+ "PMU3: Written MRS to CS=0x%02x\n"
+ },
+ {0x04130001,
+ "PMU3: Written MRS to CS=0x%02x\n"
+ },
+ {0x04140000,
+ "PMU3: Entering Boot Freq Mode.\n"
+ },
+ {0x04150001,
+ "PMU: Error: Boot clock divider setting of %d is too small\n"
+ },
+ {0x04160000,
+ "PMU3: Exiting Boot Freq Mode.\n"
+ },
+ {0x04170002,
+ "PMU3: Writing MR%d OP=%x\n"
+ },
+ {0x04180000,
+ "PMU: Error: Delay too large in slomo\n"
+ },
+ {0x04190001,
+ "PMU3: Written MRS to CS=0x%02x\n"
+ },
+ {0x041a0000,
+ "PMU3: Enable Channel A\n"
+ },
+ {0x041b0000,
+ "PMU3: Enable Channel B\n"
+ },
+ {0x041c0000,
+ "PMU3: Enable All Channels\n"
+ },
+ {0x041d0002,
+ "PMU2: Use PDA mode to set MR%d with value 0x%02x\n"
+ },
+ {0x041e0001,
+ "PMU3: Written Vref with PDA to CS=0x%02x\n"
+ },
+ {0x041f0000,
+ "PMU1: start_cal: DEBUG: setting CalRun to 1\n"
+ },
+ {0x04200000,
+ "PMU1: start_cal: DEBUG: setting CalRun to 0\n"
+ },
+ {0x04210001,
+ "PMU1: lock_pll_dll: DEBUG: pstate = %d\n"
+ },
+ {0x04220001,
+ "PMU1: lock_pll_dll: DEBUG: dfifreqxlat_pstate = %d\n"
+ },
+ {0x04230001,
+ "PMU1: lock_pll_dll: DEBUG: pllbypass = %d\n"
+ },
+ {0x04240001,
+ "PMU3: SaveLcdlSeed: Saving seed %d\n"
+ },
+ {0x04250000,
+ "PMU1: in phy_defaults()\n"
+ },
+ {0x04260003,
+ "PMU3: ACXConf:%d MaxNumDbytes:%d NumDfi:%d\n"
+ },
+ {0x04270005,
+ "PMU1: setAltAcsmCLCWL setting cl=%d cwl=%d\n"
+ },
+};
+#endif /* DEBUG */
+#endif
diff --git a/drivers/nxp/ddr/phy-gen2/phy.c b/drivers/nxp/ddr/phy-gen2/phy.c
new file mode 100644
index 0000000..9e52145
--- /dev/null
+++ b/drivers/nxp/ddr/phy-gen2/phy.c
@@ -0,0 +1,2678 @@
+/*
+ * Copyright 2021-2022 NXP
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include "csr.h"
+#include <ddr.h>
+#include "ddr4fw.h"
+#include <drivers/delay_timer.h>
+#ifdef NXP_WARM_BOOT
+#include <fspi_api.h>
+#endif
+#include "input.h"
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#ifdef DDR_PHY_DEBUG
+#include "messages.h"
+#endif
+#ifdef NXP_WARM_BOOT
+#include "phy.h"
+#endif
+#include "pie.h"
+
+#define TIMEOUTDEFAULT 500
+#define MAP_PHY_ADDR(pstate, n, instance, offset, c) \
+ ((((pstate * n) + instance + c) << 12) + offset)
+
+static uint32_t map_phy_addr_space(uint32_t addr)
+{
+ /* 23 bit addressing */
+ uint32_t pstate = (addr & U(0x700000)) >> 20U; /* bit 22:20 */
+ uint32_t block_type = (addr & U(0x0f0000)) >> 16U; /* bit 19:16 */
+ uint32_t instance = (addr & U(0x00f000)) >> 12U; /* bit 15:12 */
+ uint32_t offset = (addr & U(0x000fff)); /* bit 11:0 */
+
+ switch (block_type) {
+ case 0x0: /* 0x0 : ANIB */
+ return MAP_PHY_ADDR(pstate, 12, instance, offset, 0);
+ case 0x1: /* 0x1 : DBYTE */
+ return MAP_PHY_ADDR(pstate, 10, instance, offset, 0x30);
+ case 0x2: /* 0x2 : MASTER */
+ return MAP_PHY_ADDR(pstate, 1, 0, offset, 0x58);
+ case 0x4: /* 0x4 : ACSM */
+ return MAP_PHY_ADDR(pstate, 1, 0, offset, 0x5c);
+ case 0x5: /* 0x5 : μCTL Memory */
+ return MAP_PHY_ADDR(pstate, 0, instance, offset, 0x60);
+ case 0x7: /* 0x7 : PPGC */
+ return MAP_PHY_ADDR(pstate, 0, 0, offset, 0x68);
+ case 0x9: /* 0x9 : INITENG */
+ return MAP_PHY_ADDR(pstate, 1, 0, offset, 0x69);
+ case 0xc: /* 0xC : DRTUB */
+ return MAP_PHY_ADDR(pstate, 0, 0, offset, 0x6d);
+ case 0xd: /* 0xD : APB Only */
+ return MAP_PHY_ADDR(pstate, 0, 0, offset, 0x6e);
+ default:
+ printf("ERR: Invalid block_type = 0x%x\n", block_type);
+ return 0;
+ }
+}
+
+static inline uint16_t *phy_io_addr(void *phy, uint32_t addr)
+{
+ return phy + (map_phy_addr_space(addr) << 2);
+}
+
+static inline void phy_io_write16(uint16_t *phy, uint32_t addr, uint16_t data)
+{
+ mmio_write_16((uintptr_t)phy_io_addr(phy, addr), data);
+#ifdef DEBUG_PHY_IO
+ printf("0x%06x,0x%x\n", addr, data);
+#endif
+}
+
+static inline uint16_t phy_io_read16(uint16_t *phy, uint32_t addr)
+{
+ uint16_t reg = mmio_read_16((uintptr_t) phy_io_addr(phy, addr));
+
+#ifdef DEBUG_PHY_IO
+ printf("R: 0x%06x,0x%x\n", addr, reg);
+#endif
+
+ return reg;
+}
+
+#ifdef NXP_APPLY_MAX_CDD
+
+#define CDD_VAL_READ_ADDR (0x054012)
+#define CDD_DATA_LEN (60)
+
+static void read_phy_reg(uint16_t *phy, uint32_t addr,
+ uint16_t *buf, uint32_t len)
+{
+ uint32_t i = 0U;
+
+ for (i = 0U; i < len/2; i++) {
+ buf[i] = phy_io_read16(phy, (addr + i));
+ }
+}
+
+static uint32_t findrank(uint32_t cs_in_use)
+{
+ uint32_t val = 0U;
+
+ switch (cs_in_use) {
+ case U(0xf):
+ val = 4U;
+ break;
+ case U(0x3):
+ val = 2U;
+ break;
+ case U(0x1):
+ val = 1U;
+ break;
+ default:
+ printf("Error - Invalid cs_in_use value\n");
+ }
+ return val;
+}
+
+static uint8_t findmax(uint8_t *buf, uint32_t len)
+{
+ uint8_t max = 0U;
+ uint32_t i = 0U;
+
+ for (i = 0U; i < len; i++) {
+ if (buf[i] > max) {
+ max = buf[i];
+ }
+ }
+
+ return max;
+}
+
+static void get_cdd_val(uint16_t **phy_ptr, uint32_t rank, uint32_t freq,
+ uint32_t *tcfg0, uint32_t *tcfg4)
+{
+ uint8_t cdd[CDD_DATA_LEN+4] = {0U};
+ uint32_t i, val = 0U;
+ uint16_t *phy;
+ uint8_t buf[16] = {U(0x0)};
+ uint8_t trr = 0U, tww = 0U, trw = 0U, twr = 0U;
+ uint8_t rrmax = 0U, wwmax = 0U, rwmax = 0U, wrmax = 0U;
+ uint8_t tmp = U(0x0);
+ uint8_t *c = NULL;
+
+ for (i = 0U; i < NUM_OF_DDRC; i++) {
+
+ phy = phy_ptr[i];
+ if (phy == NULL) {
+ continue;
+ }
+
+ phy_io_write16(phy, t_apbonly |
+ csr_micro_cont_mux_sel_addr, U(0x0));
+
+ read_phy_reg(phy, CDD_VAL_READ_ADDR,
+ (uint16_t *)&cdd, CDD_DATA_LEN);
+
+ phy_io_write16(phy, t_apbonly |
+ csr_micro_cont_mux_sel_addr, U(0x1));
+
+ /* CDD values and address
+ *
+ * 0x054012 0x24 cdd[0] CDD[X][X]
+ * 0x054012 0x25 cdd[1] RR[3][2]
+ * 0x054013 0x26 cdd[2] RR[3][1]
+ * 0x054013 0x27 cdd[3] RR[3][0]
+ * 0x054014 0x28 cdd[4] RR[2][3]
+ * 0x054014 0x29 cdd[5] RR[2][1]
+ * 0x054015 0x2a cdd[6] RR[2][0]
+ * 0x054015 0x2b cdd[7] RR[1][3]
+ * 0x054016 0x2c cdd[8] RR[1][2]
+ * 0x054016 0x2d cdd[9] RR[1][0]
+ * 0x054017 0x2e cdd[10] RR[0][3]
+ * 0x054017 0x2f cdd[11] RR[0][2]
+ * 0x054018 0x30 cdd[12] RR[0][1]
+
+ * 0x054018 0x31 cdd[13] WW[3][2]
+ * 0x054019 0x32 cdd[14] WW[3][1]
+ * 0x054019 0x33 cdd[15] WW[3][0]
+ * 0x05401a 0x34 cdd[16] WW[2][3]
+ * 0x05401a 0x35 cdd[17] WW[2][1]
+ * 0x05401b 0x36 cdd[18] WW[2][0]
+ * 0x05401b 0x37 cdd[19] WW[1][3]
+ * 0x05401c 0x38 cdd[20] WW[1][2]
+ * 0x05401c 0x39 cdd[21] WW[1][0]
+ * 0x05401d 0x3a cdd[22] WW[0][3]
+ * 0x05401d 0x3b cdd[23] WW[0][2]
+ * 0x05401e 0x3c cdd[24] WW[0][1]
+
+ * 0x05401e 0x3d cdd[25] RW[3][3]
+ * 0x05401f 0x3e cdd[26] RW[3][2]
+ * 0x05401f 0x3f cdd[27] RW[3][1]
+ * 0x054020 0x40 cdd[28] RW[3][0]
+ * 0x054020 0x41 cdd[29] RW[2][3]
+ * 0x054021 0x42 cdd[30] RW[2][2]
+ * 0x054021 0x43 cdd[31] RW[2][1]
+ * 0x054022 0x44 cdd[32] RW[2][0]
+ * 0x054022 0x45 cdd[33] RW[1][3]
+ * 0x054023 0x46 cdd[34] RW[1][2]
+ * 0x054023 0x47 cdd[35] RW[1][1]
+ * 0x054024 0x48 cdd[36] RW[1][0]
+ * 0x054024 0x49 cdd[37] RW[0][3]
+ * 0x054025 0x4a cdd[38] RW[0][2]
+ * 0x054025 0x4b cdd[39] RW[0][1]
+ * 0x054026 0x4c cdd[40] RW[0][0]
+
+ * 0x054026 0x4d cdd[41] WR[3][3]
+ * 0x054027 0x4e cdd[42] WR[3][2]
+ * 0x054027 0x4f cdd[43] WR[3][1]
+ * 0x054028 0x50 cdd[44] WR[3][0]
+ * 0x054028 0x51 cdd[45] WR[2][3]
+ * 0x054029 0x52 cdd[46] WR[2][2]
+ * 0x054029 0x53 cdd[47] WR[2][1]
+ * 0x05402a 0x54 cdd[48] WR[2][0]
+ * 0x05402a 0x55 cdd[49] WR[1][3]
+ * 0x05402b 0x56 cdd[50] WR[1][2]
+ * 0x05402b 0x57 cdd[51] WR[1][1]
+ * 0x05402c 0x58 cdd[52] WR[1][0]
+ * 0x05402c 0x59 cdd[53] WR[0][3]
+ * 0x05402d 0x5a cdd[54] WR[0][2]
+ * 0x05402d 0x5b cdd[55] WR[0][1]
+ * 0x05402e 0x5c cdd[56] WR[0][0]
+ * 0x05402e 0x5d cdd[57] CDD[Y][Y]
+ */
+
+ switch (rank) {
+ case 1U:
+ tmp = rwmax;
+ rwmax = cdd[40];
+ if (tmp > rwmax) {
+ rwmax = tmp;
+ }
+
+ tmp = wrmax;
+ wrmax = cdd[56];
+ if (tmp > wrmax) {
+ wrmax = tmp;
+ }
+
+ break;
+
+ case 2U:
+ buf[0] = cdd[12];
+ buf[1] = cdd[9];
+ tmp = rrmax;
+ rrmax = findmax(buf, 2U);
+ if (tmp > rrmax) {
+ rrmax = tmp;
+ }
+
+ buf[0] = cdd[24];
+ buf[1] = cdd[21];
+ tmp = wwmax;
+ wwmax = findmax(buf, 2U);
+ if (tmp > wwmax) {
+ wwmax = tmp;
+ }
+
+ buf[0] = cdd[40];
+ buf[1] = cdd[39];
+ buf[2] = cdd[36];
+ buf[3] = cdd[35];
+ tmp = rwmax;
+ rwmax = findmax(buf, 4U);
+ if (tmp > rwmax) {
+ rwmax = tmp;
+ }
+
+ buf[0] = cdd[56];
+ buf[1] = cdd[55];
+ buf[2] = cdd[52];
+ buf[3] = cdd[51];
+ tmp = wrmax;
+ wrmax = findmax(buf, 4U);
+ if (tmp > wrmax) {
+ wrmax = tmp;
+ }
+
+ break;
+
+ case 4U:
+ tmp = rrmax;
+ c = &cdd[1];
+ rrmax = findmax(c, 12U);
+ if (tmp > rrmax) {
+ rrmax = tmp;
+ }
+
+ tmp = wwmax;
+ c = &cdd[13];
+ wwmax = findmax(c, 12U);
+ if (tmp > wwmax) {
+ wwmax = tmp;
+ }
+
+ tmp = rwmax;
+ c = &cdd[25];
+ rwmax = findmax(c, 16U);
+ if (tmp > rwmax) {
+ rwmax = tmp;
+ }
+
+ tmp = wrmax;
+ c = &cdd[41];
+ wrmax = findmax(c, 16U);
+ if (tmp > wrmax) {
+ wrmax = tmp;
+ }
+
+ break;
+
+ }
+ }
+
+ rrmax += 3U;
+ wwmax += 4U;
+
+ if (wwmax > 7U) {
+ wwmax = 7U;
+ }
+
+ if (rrmax > 7U) {
+ rrmax = 7U;
+ }
+
+ if (wrmax > U(0xf)) {
+ wrmax = 0U;
+ }
+
+ if (rwmax > U(0x7)) {
+ rwmax = U(0x7);
+ }
+
+ val = *tcfg0;
+ tww = (val >> 24U) & U(0x3);
+ trr = (val >> 26U) & U(0x3);
+ twr = (val >> 28U) & U(0x3);
+ trw = (val >> 30U) & U(0x3);
+
+ val = *tcfg4;
+ tww = tww | (((val >> 8U) & U(0x1)) << 2U);
+ trr = trr | (((val >> 10U) & U(0x1)) << 2U);
+ twr = twr | (((val >> 12U) & U(0x1)) << 2U);
+ trw = trw | (((val >> 14U) & U(0x3)) << 2U);
+
+ if (trr > rrmax) {
+ rrmax = trr;
+ }
+
+ if (tww > wwmax) {
+ wwmax = tww;
+ }
+
+ if (trw > rwmax) {
+ rwmax = trw;
+ }
+
+ if (twr > wrmax) {
+ wrmax = twr;
+ }
+
+ debug("CDD rrmax %x wwmax %x rwmax %x wrmax %x\n",
+ rrmax, wwmax, rwmax, wrmax);
+
+ val = ((wwmax & U(0x3)) << 24U)
+ | ((rrmax & U(0x3)) << 26U)
+ | ((wrmax & U(0x3)) << 28U)
+ | ((rwmax & U(0x3)) << 30U);
+
+ *tcfg0 = (*tcfg0 & U(0x00FFFFFF)) | (val);
+
+ val = (((wwmax >> 2U) & U(0x1)) << 8U)
+ | (((rrmax >> 2U) & U(0x1)) << 10U)
+ | (((wrmax >> 2U) & U(0x1)) << 12U)
+ | (((rwmax >> 2U) & U(0x3)) << 14U);
+
+ *tcfg4 = (*tcfg4 & U(0xffff00ff)) | val;
+}
+#endif
+
+#ifdef NXP_WARM_BOOT
+int save_phy_training_values(uint16_t **phy_ptr, uint32_t address_to_store,
+ uint32_t num_of_phy, int train2d)
+{
+ uint16_t *phy = NULL, value = 0x0;
+ uint32_t size = 1U, num_of_regs = 1U, phy_store = 0U;
+ int i = 0, j = 0, ret = -EINVAL;
+
+ ret = xspi_sector_erase(address_to_store, PHY_ERASE_SIZE);
+ if (ret != 0) {
+ return -EINVAL;
+ }
+
+ for (j = 0; j < num_of_phy; j++) {
+ /* Save training values of all PHYs */
+ phy = phy_ptr[j];
+ size = sizeof(training_1D_values);
+ num_of_regs = ARRAY_SIZE(training_1D_values);
+
+ /* Enable access to the internal CSRs */
+ phy_io_write16(phy, t_apbonly |
+ csr_micro_cont_mux_sel_addr, 0x0);
+ /* Enable clocks in case they were disabled. */
+ phy_io_write16(phy, t_drtub |
+ csr_ucclk_hclk_enables_addr, 0x3);
+ if (train2d != 0) {
+ /* Address to store training values is
+ * to be appended for next PHY
+ */
+ phy_store = address_to_store + (j *
+ (sizeof(training_1D_values) +
+ sizeof(training_2D_values)));
+ } else {
+ phy_store = address_to_store + (j *
+ (sizeof(training_1D_values)));
+ }
+ debug("Saving 1D Training reg val at: %d\n", phy_store);
+ for (i = 0; i < num_of_regs; i++) {
+ value = phy_io_read16(phy, training_1D_values[i].addr);
+#ifdef DEBUG_WARM_RESET
+ debug("%d. Reg: %x, value: %x PHY: %p\n", i,
+ training_1D_values[i].addr, value,
+ phy_io_addr(phy,
+ training_1D_values[i].addr));
+#endif
+ training_1D_values[i].data = value;
+ }
+ /* Storing 1D training values on flash */
+ ret = xspi_write(phy_store, (void *)training_1D_values, size);
+ if (train2d != 0) {
+ phy_store = phy_store+size;
+ size = sizeof(training_2D_values);
+ num_of_regs = ARRAY_SIZE(training_2D_values);
+ debug("Saving 2D Training reg val at:%d\n", phy_store);
+ for (i = 0; i < num_of_regs; i++) {
+ value = phy_io_read16(phy,
+ training_2D_values[i].addr);
+ training_2D_values[i].data = value;
+#ifdef DEBUG_WARM_RESET
+ debug("%d.2D addr:0x%x,val:0x%x,PHY:0x%p\n",
+ i, training_2D_values[i].addr,
+ value, phy_io_addr(phy,
+ training_2D_values[i].addr));
+#endif
+ }
+ /* Storing 2D training values on flash */
+ ret = xspi_write(phy_store, training_2D_values,
+ size);
+ }
+ /* Disable clocks in case they were disabled. */
+ phy_io_write16(phy, t_drtub |
+ csr_ucclk_hclk_enables_addr, 0x0);
+ /* Disable access to the internal CSRs */
+ phy_io_write16(phy, t_apbonly |
+ csr_micro_cont_mux_sel_addr, 0x1);
+ }
+ if (ret != 0) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int restore_phy_training_values(uint16_t **phy_ptr, uint32_t address_to_restore,
+ uint32_t num_of_phy, int train2d)
+{
+ uint16_t *phy = NULL;
+ uint32_t size = 1U, num_of_regs = 1U, phy_store = 0U;
+ int i = 0, j = 0, ret = -EINVAL;
+
+ debug("Restoring Training register values\n");
+ for (j = 0; j < num_of_phy; j++) {
+ phy = phy_ptr[j];
+ size = sizeof(training_1D_values);
+ num_of_regs = ARRAY_SIZE(training_1D_values);
+ if (train2d != 0) {
+ /* The address to restore training values is
+ * to be appended for next PHY
+ */
+ phy_store = address_to_restore + (j *
+ (sizeof(training_1D_values) +
+ sizeof(training_2D_values)));
+ } else {
+ phy_store = address_to_restore + (j *
+ (sizeof(training_1D_values)));
+ }
+ /* Enable access to the internal CSRs */
+ phy_io_write16(phy, t_apbonly |
+ csr_micro_cont_mux_sel_addr, 0x0);
+ /* Enable clocks in case they were disabled. */
+ phy_io_write16(phy, t_drtub |
+ csr_ucclk_hclk_enables_addr, 0x3);
+
+ /* Reading 1D training values from flash*/
+ ret = xspi_read(phy_store, (uint32_t *)training_1D_values,
+ size);
+ debug("Restoring 1D Training reg val at:%08x\n", phy_store);
+ for (i = 0; i < num_of_regs; i++) {
+ phy_io_write16(phy, training_1D_values[i].addr,
+ training_1D_values[i].data);
+#ifdef DEBUG_WARM_RESET
+ debug("%d. Reg: %x, value: %x PHY: %p\n", i,
+ training_1D_values[i].addr,
+ training_1D_values[i].data,
+ phy_io_addr(phy,
+ training_1D_values[i].addr));
+#endif
+ }
+ if (train2d != 0) {
+ phy_store = phy_store + size;
+ size = sizeof(training_2D_values);
+ num_of_regs = ARRAY_SIZE(training_2D_values);
+ /* Reading 2D training values from flash */
+ ret = xspi_read(phy_store,
+ (uint32_t *)training_2D_values, size);
+ debug("Restoring 2D Training reg val at:%08x\n",
+ phy_store);
+ for (i = 0; i < num_of_regs; i++) {
+ phy_io_write16(phy, training_2D_values[i].addr,
+ training_2D_values[i].data);
+#ifdef DEBUG_WARM_RESET
+ debug("%d. Reg: %x, value: %x PHY: %p\n", i,
+ training_2D_values[i].addr,
+ training_2D_values[i].data,
+ phy_io_addr(phy,
+ training_1D_values[i].addr));
+#endif
+ }
+ }
+ /* Disable clocks in case they were disabled. */
+ phy_io_write16(phy, t_drtub |
+ csr_ucclk_hclk_enables_addr, 0x0);
+ /* Disable access to the internal CSRs */
+ phy_io_write16(phy, t_apbonly |
+ csr_micro_cont_mux_sel_addr, 0x1);
+ }
+ if (ret != 0) {
+ return -EINVAL;
+ }
+ return 0;
+}
+#endif
+
+static void load_pieimage(uint16_t *phy,
+ enum dimm_types dimm_type)
+{
+ int i;
+ int size;
+ const struct pie *image = NULL;
+
+ switch (dimm_type) {
+ case UDIMM:
+ case SODIMM:
+ case NODIMM:
+ image = pie_udimm;
+ size = ARRAY_SIZE(pie_udimm);
+ break;
+ case RDIMM:
+ image = pie_rdimm;
+ size = ARRAY_SIZE(pie_rdimm);
+ break;
+ case LRDIMM:
+ image = pie_lrdimm;
+ size = ARRAY_SIZE(pie_lrdimm);
+ break;
+ default:
+ printf("Unsupported DIMM type\n");
+ break;
+ }
+
+ if (image != NULL) {
+ for (i = 0; i < size; i++)
+ phy_io_write16(phy, image[i].addr, image[i].data);
+ }
+}
+
+static void prog_acsm_playback(uint16_t *phy,
+ const struct input *input, const void *msg)
+{
+ int vec;
+ const struct ddr4r1d *msg_blk;
+ uint16_t acsmplayback[2][3];
+ uint32_t f0rc0a;
+ uint32_t f0rc3x;
+ uint32_t f0rc5x;
+
+ if (input->basic.dimm_type != RDIMM) {
+ return;
+ }
+
+ msg_blk = msg;
+ f0rc0a = (msg_blk->f0rc0a_d0 & U(0xf)) | U(0xa0);
+ f0rc3x = (msg_blk->f0rc3x_d0 & U(0xff)) | U(0x300);
+ f0rc5x = (input->adv.phy_gen2_umctl_f0rc5x & U(0xff)) | U(0x500);
+
+ acsmplayback[0][0] = U(0x3ff) & f0rc0a;
+ acsmplayback[1][0] = (U(0x1c00) & f0rc0a) >> 10U;
+ acsmplayback[0][1] = U(0x3ff) & f0rc3x;
+ acsmplayback[1][1] = (U(0x1c00) & f0rc3x) >> 10U;
+ acsmplayback[0][2] = U(0x3ff) & f0rc5x;
+ acsmplayback[1][2] = (U(0x1c00) & f0rc5x) >> 10U;
+ for (vec = 0; vec < 3; vec++) {
+ phy_io_write16(phy, t_acsm | (csr_acsm_playback0x0_addr +
+ (vec << 1)), acsmplayback[0][vec]);
+ phy_io_write16(phy, t_acsm | (csr_acsm_playback1x0_addr +
+ (vec << 1)), acsmplayback[1][vec]);
+ }
+}
+
+static void prog_acsm_ctr(uint16_t *phy,
+ const struct input *input)
+{
+ if (input->basic.dimm_type != RDIMM) {
+ return;
+ }
+
+ phy_io_write16(phy, t_acsm | csr_acsm_ctrl13_addr,
+ 0xf << csr_acsm_cke_enb_lsb);
+
+ phy_io_write16(phy, t_acsm | csr_acsm_ctrl0_addr,
+ csr_acsm_par_mode_mask | csr_acsm_2t_mode_mask);
+}
+
+static void prog_cal_rate_run(uint16_t *phy,
+ const struct input *input)
+{
+ int cal_rate;
+ int cal_interval;
+ int cal_once;
+ uint32_t addr;
+
+ cal_interval = input->adv.cal_interval;
+ cal_once = input->adv.cal_once;
+ cal_rate = 0x1 << csr_cal_run_lsb |
+ cal_once << csr_cal_once_lsb |
+ cal_interval << csr_cal_interval_lsb;
+ addr = t_master | csr_cal_rate_addr;
+ phy_io_write16(phy, addr, cal_rate);
+}
+
+static void prog_seq0bdly0(uint16_t *phy,
+ const struct input *input)
+{
+ int ps_count[4];
+ int frq;
+ uint32_t addr;
+ int lower_freq_opt = 0;
+
+ __unused const soc_info_t *soc_info;
+
+ frq = input->basic.frequency >> 1;
+ ps_count[0] = frq >> 3; /* 0.5 * frq / 4*/
+ if (input->basic.frequency < 400) {
+ lower_freq_opt = (input->basic.dimm_type == RDIMM) ? 7 : 3;
+ } else if (input->basic.frequency < 533) {
+ lower_freq_opt = (input->basic.dimm_type == RDIMM) ? 14 : 11;
+ }
+
+ /* 1.0 * frq / 4 - lower_freq */
+ ps_count[1] = (frq >> 2) - lower_freq_opt;
+ ps_count[2] = (frq << 1) + (frq >> 1); /* 10.0 * frq / 4 */
+
+#ifdef DDR_PLL_FIX
+ soc_info = get_soc_info();
+ if (soc_info->svr_reg.bf.maj_ver == 1) {
+ ps_count[0] = 0x520; /* seq0bdly0 */
+ ps_count[1] = 0xa41; /* seq0bdly1 */
+ ps_count[2] = 0x668a; /* seq0bdly2 */
+ }
+#endif
+ if (frq > 266) {
+ ps_count[3] = 44;
+ } else if (frq > 200) {
+ ps_count[3] = 33;
+ } else {
+ ps_count[3] = 16;
+ }
+
+ addr = t_master | csr_seq0bdly0_addr;
+ phy_io_write16(phy, addr, ps_count[0]);
+
+ debug("seq0bdly0 = 0x%x\n", phy_io_read16(phy, addr));
+
+ addr = t_master | csr_seq0bdly1_addr;
+ phy_io_write16(phy, addr, ps_count[1]);
+
+ debug("seq0bdly1 = 0x%x\n", phy_io_read16(phy, addr));
+
+ addr = t_master | csr_seq0bdly2_addr;
+ phy_io_write16(phy, addr, ps_count[2]);
+
+ debug("seq0bdly2 = 0x%x\n", phy_io_read16(phy, addr));
+
+ addr = t_master | csr_seq0bdly3_addr;
+ phy_io_write16(phy, addr, ps_count[3]);
+
+ debug("seq0bdly3 = 0x%x\n", phy_io_read16(phy, addr));
+}
+
+/* Only RDIMM requires msg_blk */
+static void i_load_pie(uint16_t **phy_ptr,
+ const struct input *input,
+ const void *msg)
+{
+ int i;
+ uint16_t *phy;
+
+ for (i = 0; i < NUM_OF_DDRC; i++) {
+ phy = phy_ptr[i];
+ if (phy == NULL) {
+ continue;
+ }
+
+ phy_io_write16(phy,
+ t_apbonly | csr_micro_cont_mux_sel_addr,
+ 0U);
+
+ load_pieimage(phy, input->basic.dimm_type);
+
+ prog_seq0bdly0(phy, input);
+ phy_io_write16(phy, t_initeng | csr_seq0bdisable_flag0_addr,
+ U(0x0000));
+ phy_io_write16(phy, t_initeng | csr_seq0bdisable_flag1_addr,
+ U(0x0173));
+ phy_io_write16(phy, t_initeng | csr_seq0bdisable_flag2_addr,
+ U(0x0060));
+ phy_io_write16(phy, t_initeng | csr_seq0bdisable_flag3_addr,
+ U(0x6110));
+ phy_io_write16(phy, t_initeng | csr_seq0bdisable_flag4_addr,
+ U(0x2152));
+ phy_io_write16(phy, t_initeng | csr_seq0bdisable_flag5_addr,
+ U(0xdfbd));
+ phy_io_write16(phy, t_initeng | csr_seq0bdisable_flag6_addr,
+ input->basic.dimm_type == RDIMM &&
+ input->adv.phy_gen2_umctl_opt == 1U ?
+ U(0x6000) : U(0xffff));
+ phy_io_write16(phy, t_initeng | csr_seq0bdisable_flag7_addr,
+ U(0x6152));
+ prog_acsm_playback(phy, input, msg); /* rdimm */
+ prog_acsm_ctr(phy, input); /* rdimm */
+
+ phy_io_write16(phy, t_master | csr_cal_zap_addr, U(0x1));
+ prog_cal_rate_run(phy, input);
+
+ phy_io_write16(phy, t_drtub | csr_ucclk_hclk_enables_addr,
+ input->basic.dimm_type == RDIMM ? U(0x2) : 0U);
+
+ phy_io_write16(phy, t_apbonly | csr_micro_cont_mux_sel_addr, 1U);
+ }
+}
+
+static void phy_gen2_init_input(struct input *input)
+{
+ int i;
+
+ input->adv.dram_byte_swap = 0;
+ input->adv.ext_cal_res_val = 0;
+ input->adv.tx_slew_rise_dq = 0xf;
+ input->adv.tx_slew_fall_dq = 0xf;
+ input->adv.tx_slew_rise_ac = 0xf;
+ input->adv.tx_slew_fall_ac = 0xf;
+ input->adv.mem_alert_en = 0;
+ input->adv.mem_alert_puimp = 5;
+ input->adv.mem_alert_vref_level = 0x29;
+ input->adv.mem_alert_sync_bypass = 0;
+ input->adv.cal_interval = 0x9;
+ input->adv.cal_once = 0;
+ input->adv.dis_dyn_adr_tri = 0;
+ input->adv.is2ttiming = 0;
+ input->adv.d4rx_preamble_length = 0;
+ input->adv.d4tx_preamble_length = 0;
+
+ for (i = 0; i < 7; i++) {
+ debug("mr[%d] = 0x%x\n", i, input->mr[i]);
+ }
+
+ debug("input->cs_d0 = 0x%x\n", input->cs_d0);
+ debug("input->cs_d1 = 0x%x\n", input->cs_d1);
+ debug("input->mirror = 0x%x\n", input->mirror);
+ debug("PHY ODT impedance = %d ohm\n", input->adv.odtimpedance);
+ debug("PHY DQ driver impedance = %d ohm\n", input->adv.tx_impedance);
+ debug("PHY Addr driver impedance = %d ohm\n", input->adv.atx_impedance);
+
+ for (i = 0; i < 4; i++) {
+ debug("odt[%d] = 0x%x\n", i, input->odt[i]);
+ }
+
+ if (input->basic.dimm_type == RDIMM) {
+ for (i = 0; i < 16; i++) {
+ debug("input->rcw[%d] = 0x%x\n", i, input->rcw[i]);
+ }
+ debug("input->rcw3x = 0x%x\n", input->rcw3x);
+ }
+}
+
+/*
+ * All protocols share the same base structure of message block.
+ * RDIMM and LRDIMM have more entries defined than UDIMM.
+ * Create message blocks for 1D and 2D training.
+ * Update len with message block size.
+ */
+static int phy_gen2_msg_init(void *msg_1d,
+ void *msg_2d,
+ const struct input *input)
+{
+ struct ddr4u1d *msg_blk = msg_1d;
+ struct ddr4u2d *msg_blk_2d = msg_2d;
+ struct ddr4r1d *msg_blk_r;
+ struct ddr4lr1d *msg_blk_lr;
+
+ switch (input->basic.dimm_type) {
+ case UDIMM:
+ case SODIMM:
+ case NODIMM:
+ msg_blk->dram_type = U(0x2);
+ break;
+ case RDIMM:
+ msg_blk->dram_type = U(0x4);
+ break;
+ case LRDIMM:
+ msg_blk->dram_type = U(0x5);
+ break;
+ default:
+ ERROR("Unsupported DIMM type\n");
+ return -EINVAL;
+ }
+ msg_blk->pstate = 0U;
+
+ /*Enable quickRd2D, a substage of read deskew, to 1D training.*/
+ msg_blk->reserved00 = U(0x20);
+
+ /*Enable High-Effort WrDQ1D.*/
+ msg_blk->reserved00 |= U(0x40);
+
+ /* Enable 1D extra effort training.*/
+ msg_blk->reserved1c[3] = U(0x3);
+
+ if (input->basic.dimm_type == LRDIMM) {
+ msg_blk->sequence_ctrl = U(0x3f1f);
+ } else {
+ msg_blk->sequence_ctrl = U(0x031f);
+ }
+ msg_blk->phy_config_override = 0U;
+#ifdef DDR_PHY_DEBUG
+ msg_blk->hdt_ctrl = U(0x5);
+#else
+ msg_blk->hdt_ctrl = U(0xc9);
+#endif
+ msg_blk->msg_misc = U(0x0);
+ msg_blk->dfimrlmargin = U(0x1);
+ msg_blk->phy_vref = input->vref ? input->vref : U(0x61);
+ msg_blk->cs_present = input->cs_d0 | input->cs_d1;
+ msg_blk->cs_present_d0 = input->cs_d0;
+ msg_blk->cs_present_d1 = input->cs_d1;
+ if (input->mirror != 0) {
+ msg_blk->addr_mirror = U(0x0a); /* odd CS are mirrored */
+ }
+ msg_blk->share2dvref_result = 1U;
+
+ msg_blk->acsm_odt_ctrl0 = input->odt[0];
+ msg_blk->acsm_odt_ctrl1 = input->odt[1];
+ msg_blk->acsm_odt_ctrl2 = input->odt[2];
+ msg_blk->acsm_odt_ctrl3 = input->odt[3];
+ msg_blk->enabled_dqs = (input->basic.num_active_dbyte_dfi0 +
+ input->basic.num_active_dbyte_dfi1) * 8;
+ msg_blk->x16present = input->basic.dram_data_width == 0x10 ?
+ msg_blk->cs_present : 0;
+ msg_blk->d4misc = U(0x1);
+ msg_blk->cs_setup_gddec = U(0x1);
+ msg_blk->rtt_nom_wr_park0 = 0U;
+ msg_blk->rtt_nom_wr_park1 = 0U;
+ msg_blk->rtt_nom_wr_park2 = 0U;
+ msg_blk->rtt_nom_wr_park3 = 0U;
+ msg_blk->rtt_nom_wr_park4 = 0U;
+ msg_blk->rtt_nom_wr_park5 = 0U;
+ msg_blk->rtt_nom_wr_park6 = 0U;
+ msg_blk->rtt_nom_wr_park7 = 0U;
+ msg_blk->mr0 = input->mr[0];
+ msg_blk->mr1 = input->mr[1];
+ msg_blk->mr2 = input->mr[2];
+ msg_blk->mr3 = input->mr[3];
+ msg_blk->mr4 = input->mr[4];
+ msg_blk->mr5 = input->mr[5];
+ msg_blk->mr6 = input->mr[6];
+ if ((msg_blk->mr4 & U(0x1c0)) != 0U) {
+ ERROR("Setting DRAM CAL mode is not supported\n");
+ }
+
+ msg_blk->alt_cas_l = 0U;
+ msg_blk->alt_wcas_l = 0U;
+
+ msg_blk->dramfreq = input->basic.frequency * 2U;
+ msg_blk->pll_bypass_en = input->basic.pll_bypass;
+ msg_blk->dfi_freq_ratio = input->basic.dfi_freq_ratio == 0U ? 1U :
+ input->basic.dfi_freq_ratio == 1U ? 2U :
+ 4U;
+ msg_blk->bpznres_val = input->adv.ext_cal_res_val;
+ msg_blk->disabled_dbyte = 0U;
+
+ debug("msg_blk->dram_type = 0x%x\n", msg_blk->dram_type);
+ debug("msg_blk->sequence_ctrl = 0x%x\n", msg_blk->sequence_ctrl);
+ debug("msg_blk->phy_cfg = 0x%x\n", msg_blk->phy_cfg);
+ debug("msg_blk->x16present = 0x%x\n", msg_blk->x16present);
+ debug("msg_blk->dramfreq = 0x%x\n", msg_blk->dramfreq);
+ debug("msg_blk->pll_bypass_en = 0x%x\n", msg_blk->pll_bypass_en);
+ debug("msg_blk->dfi_freq_ratio = 0x%x\n", msg_blk->dfi_freq_ratio);
+ debug("msg_blk->phy_odt_impedance = 0x%x\n",
+ msg_blk->phy_odt_impedance);
+ debug("msg_blk->phy_drv_impedance = 0x%x\n",
+ msg_blk->phy_drv_impedance);
+ debug("msg_blk->bpznres_val = 0x%x\n", msg_blk->bpznres_val);
+ debug("msg_blk->enabled_dqs = 0x%x\n", msg_blk->enabled_dqs);
+ debug("msg_blk->acsm_odt_ctrl0 = 0x%x\n", msg_blk->acsm_odt_ctrl0);
+ debug("msg_blk->acsm_odt_ctrl1 = 0x%x\n", msg_blk->acsm_odt_ctrl1);
+ debug("msg_blk->acsm_odt_ctrl2 = 0x%x\n", msg_blk->acsm_odt_ctrl2);
+ debug("msg_blk->acsm_odt_ctrl3 = 0x%x\n", msg_blk->acsm_odt_ctrl3);
+
+ /* RDIMM only */
+ if (input->basic.dimm_type == RDIMM ||
+ input->basic.dimm_type == LRDIMM) {
+ msg_blk_r = (struct ddr4r1d *)msg_blk;
+ if (msg_blk_r->cs_present_d0 != 0U) {
+ msg_blk_r->f0rc00_d0 = input->rcw[0];
+ msg_blk_r->f0rc01_d0 = input->rcw[1];
+ msg_blk_r->f0rc02_d0 = input->rcw[2];
+ msg_blk_r->f0rc03_d0 = input->rcw[3];
+ msg_blk_r->f0rc04_d0 = input->rcw[4];
+ msg_blk_r->f0rc05_d0 = input->rcw[5];
+ msg_blk_r->f0rc06_d0 = input->rcw[6];
+ msg_blk_r->f0rc07_d0 = input->rcw[7];
+ msg_blk_r->f0rc08_d0 = input->rcw[8];
+ msg_blk_r->f0rc09_d0 = input->rcw[9];
+ msg_blk_r->f0rc0a_d0 = input->rcw[10];
+ msg_blk_r->f0rc0b_d0 = input->rcw[11];
+ msg_blk_r->f0rc0c_d0 = input->rcw[12];
+ msg_blk_r->f0rc0d_d0 = input->rcw[13];
+ msg_blk_r->f0rc0e_d0 = input->rcw[14];
+ msg_blk_r->f0rc0f_d0 = input->rcw[15];
+ msg_blk_r->f0rc3x_d0 = input->rcw3x;
+ }
+ if (msg_blk_r->cs_present_d1 != 0) {
+ msg_blk_r->f0rc00_d1 = input->rcw[0];
+ msg_blk_r->f0rc01_d1 = input->rcw[1];
+ msg_blk_r->f0rc02_d1 = input->rcw[2];
+ msg_blk_r->f0rc03_d1 = input->rcw[3];
+ msg_blk_r->f0rc04_d1 = input->rcw[4];
+ msg_blk_r->f0rc05_d1 = input->rcw[5];
+ msg_blk_r->f0rc06_d1 = input->rcw[6];
+ msg_blk_r->f0rc07_d1 = input->rcw[7];
+ msg_blk_r->f0rc08_d1 = input->rcw[8];
+ msg_blk_r->f0rc09_d1 = input->rcw[9];
+ msg_blk_r->f0rc0a_d1 = input->rcw[10];
+ msg_blk_r->f0rc0b_d1 = input->rcw[11];
+ msg_blk_r->f0rc0c_d1 = input->rcw[12];
+ msg_blk_r->f0rc0d_d1 = input->rcw[13];
+ msg_blk_r->f0rc0e_d1 = input->rcw[14];
+ msg_blk_r->f0rc0f_d1 = input->rcw[15];
+ msg_blk_r->f0rc3x_d1 = input->rcw3x;
+ }
+ if (input->basic.dimm_type == LRDIMM) {
+ msg_blk_lr = (struct ddr4lr1d *)msg_blk;
+ msg_blk_lr->bc0a_d0 = msg_blk_lr->f0rc0a_d0;
+ msg_blk_lr->bc0a_d1 = msg_blk_lr->f0rc0a_d1;
+ msg_blk_lr->f0bc6x_d0 = msg_blk_lr->f0rc3x_d0;
+ msg_blk_lr->f0bc6x_d1 = msg_blk_lr->f0rc3x_d1;
+ }
+ }
+
+ /* below is different for 1D and 2D message block */
+ if (input->basic.train2d != 0) {
+ memcpy(msg_blk_2d, msg_blk, sizeof(struct ddr4u1d));
+ /*High-Effort WrDQ1D is applicable to 2D traning also*/
+ msg_blk_2d->reserved00 |= U(0x40);
+ msg_blk_2d->sequence_ctrl = U(0x0061);
+ msg_blk_2d->rx2d_train_opt = 0U;
+ msg_blk_2d->tx2d_train_opt = 0U;
+ msg_blk_2d->share2dvref_result = 1U;
+ msg_blk_2d->delay_weight2d = U(0x20);
+ msg_blk_2d->voltage_weight2d = U(0x80);
+ debug("rx2d_train_opt %d, tx2d_train_opt %d\n",
+ msg_blk_2d->rx2d_train_opt,
+ msg_blk_2d->tx2d_train_opt);
+ }
+
+ msg_blk->phy_cfg = (((msg_blk->mr3 & U(0x8)) != 0U) ||
+ ((msg_blk_2d->mr3 & 0x8) != 0U)) ? 0U
+ : input->adv.is2ttiming;
+
+ return 0;
+}
+
+static void prog_tx_pre_drv_mode(uint16_t *phy,
+ const struct input *input)
+{
+ int lane, byte, b_addr, c_addr, p_addr;
+ int tx_slew_rate, tx_pre_p, tx_pre_n;
+ int tx_pre_drv_mode = 0x2;
+ uint32_t addr;
+
+ /* Program TxPreDrvMode with 0x2 */
+ /* FIXME: TxPreDrvMode depends on DramType? */
+ tx_pre_p = input->adv.tx_slew_rise_dq;
+ tx_pre_n = input->adv.tx_slew_fall_dq;
+ tx_slew_rate = tx_pre_drv_mode << csr_tx_pre_drv_mode_lsb |
+ tx_pre_p << csr_tx_pre_p_lsb |
+ tx_pre_n << csr_tx_pre_n_lsb;
+ p_addr = 0;
+ for (byte = 0; byte < input->basic.num_dbyte; byte++) {
+ c_addr = byte << 12;
+ for (lane = 0; lane <= 1; lane++) {
+ b_addr = lane << 8;
+ addr = p_addr | t_dbyte | c_addr | b_addr |
+ csr_tx_slew_rate_addr;
+ phy_io_write16(phy, addr, tx_slew_rate);
+ }
+ }
+}
+
+static void prog_atx_pre_drv_mode(uint16_t *phy,
+ const struct input *input)
+{
+ int anib, c_addr;
+ int atx_slew_rate, atx_pre_p, atx_pre_n, atx_pre_drv_mode,
+ ck_anib_inst[2];
+ uint32_t addr;
+
+ atx_pre_n = input->adv.tx_slew_fall_ac;
+ atx_pre_p = input->adv.tx_slew_rise_ac;
+
+ if (input->basic.num_anib == 8) {
+ ck_anib_inst[0] = 1;
+ ck_anib_inst[1] = 1;
+ } else if (input->basic.num_anib == 10 || input->basic.num_anib == 12 ||
+ input->basic.num_anib == 13) {
+ ck_anib_inst[0] = 4;
+ ck_anib_inst[1] = 5;
+ } else {
+ ERROR("Invalid number of aNIBs: %d\n", input->basic.num_anib);
+ return;
+ }
+
+ for (anib = 0; anib < input->basic.num_anib; anib++) {
+ c_addr = anib << 12;
+ if (anib == ck_anib_inst[0] || anib == ck_anib_inst[1]) {
+ atx_pre_drv_mode = 0;
+ } else {
+ atx_pre_drv_mode = 3;
+ }
+ atx_slew_rate = atx_pre_drv_mode << csr_atx_pre_drv_mode_lsb |
+ atx_pre_n << csr_atx_pre_n_lsb |
+ atx_pre_p << csr_atx_pre_p_lsb;
+ addr = t_anib | c_addr | csr_atx_slew_rate_addr;
+ phy_io_write16(phy, addr, atx_slew_rate);
+ }
+}
+
+static void prog_enable_cs_multicast(uint16_t *phy,
+ const struct input *input)
+{
+ uint32_t addr = t_master | csr_enable_cs_multicast_addr;
+
+ if (input->basic.dimm_type != RDIMM &&
+ input->basic.dimm_type != LRDIMM) {
+ return;
+ }
+
+ phy_io_write16(phy, addr, input->adv.cast_cs_to_cid);
+}
+
+static void prog_dfi_rd_data_cs_dest_map(uint16_t *phy,
+ unsigned int ip_rev,
+ const struct input *input,
+ const struct ddr4lr1d *msg)
+{
+ const struct ddr4lr1d *msg_blk;
+ uint16_t dfi_xxdestm0 = 0U;
+ uint16_t dfi_xxdestm1 = 0U;
+ uint16_t dfi_xxdestm2 = 0U;
+ uint16_t dfi_xxdestm3 = 0U;
+ uint16_t dfi_rd_data_cs_dest_map;
+ uint16_t dfi_wr_data_cs_dest_map;
+ __unused const soc_info_t *soc_info;
+
+#ifdef ERRATA_DDR_A011396
+ /* Only apply to DDRC 5.05.00 */
+ soc_info = get_soc_info();
+ if ((soc_info->svr_reg.bf.maj_ver == 1U) && (ip_rev == U(0x50500))) {
+ phy_io_write16(phy,
+ t_master | csr_dfi_rd_data_cs_dest_map_addr,
+ 0U);
+ return;
+ }
+#endif
+
+ msg_blk = msg;
+
+ switch (input->basic.dimm_type) {
+ case UDIMM:
+ case SODIMM:
+ case NODIMM:
+ if ((msg_blk->msg_misc & U(0x40)) != 0U) {
+ dfi_rd_data_cs_dest_map = U(0xa0);
+ dfi_wr_data_cs_dest_map = U(0xa0);
+
+ phy_io_write16(phy,
+ t_master | csr_dfi_rd_data_cs_dest_map_addr,
+ dfi_rd_data_cs_dest_map);
+ phy_io_write16(phy,
+ t_master | csr_dfi_wr_data_cs_dest_map_addr,
+ dfi_wr_data_cs_dest_map);
+ }
+ break;
+ case LRDIMM:
+ if (msg->cs_present_d1 != 0U) {
+ dfi_xxdestm2 = 1U;
+ dfi_xxdestm3 = 1U;
+ }
+
+ dfi_rd_data_cs_dest_map =
+ dfi_xxdestm0 << csr_dfi_rd_destm0_lsb |
+ dfi_xxdestm1 << csr_dfi_rd_destm1_lsb |
+ dfi_xxdestm2 << csr_dfi_rd_destm2_lsb |
+ dfi_xxdestm3 << csr_dfi_rd_destm3_lsb;
+ dfi_wr_data_cs_dest_map =
+ dfi_xxdestm0 << csr_dfi_wr_destm0_lsb |
+ dfi_xxdestm1 << csr_dfi_wr_destm1_lsb |
+ dfi_xxdestm2 << csr_dfi_wr_destm2_lsb |
+ dfi_xxdestm3 << csr_dfi_wr_destm3_lsb;
+ phy_io_write16(phy, t_master | csr_dfi_rd_data_cs_dest_map_addr,
+ dfi_rd_data_cs_dest_map);
+ phy_io_write16(phy, t_master | csr_dfi_wr_data_cs_dest_map_addr,
+ dfi_wr_data_cs_dest_map);
+
+ break;
+ default:
+ break;
+ }
+}
+
+static void prog_pll_ctrl(uint16_t *phy,
+ const struct input *input)
+{
+ uint32_t addr;
+ int pll_ctrl1 = 0x21; /* 000100001b */
+ int pll_ctrl4 = 0x17f; /* 101111111b */
+ int pll_test_mode = 0x24; /* 00100100b */
+
+ addr = t_master | csr_pll_ctrl1_addr;
+ phy_io_write16(phy, addr, pll_ctrl1);
+
+ debug("pll_ctrl1 = 0x%x\n", phy_io_read16(phy, addr));
+
+ addr = t_master | csr_pll_test_mode_addr;
+ phy_io_write16(phy, addr, pll_test_mode);
+
+ debug("pll_test_mode = 0x%x\n", phy_io_read16(phy, addr));
+
+ addr = t_master | csr_pll_ctrl4_addr;
+ phy_io_write16(phy, addr, pll_ctrl4);
+
+ debug("pll_ctrl4 = 0x%x\n", phy_io_read16(phy, addr));
+}
+
+static void prog_pll_ctrl2(uint16_t *phy,
+ const struct input *input)
+{
+ int pll_ctrl2;
+ uint32_t addr = t_master | csr_pll_ctrl2_addr;
+
+ if (input->basic.frequency / 2 < 235) {
+ pll_ctrl2 = 0x7;
+ } else if (input->basic.frequency / 2 < 313) {
+ pll_ctrl2 = 0x6;
+ } else if (input->basic.frequency / 2 < 469) {
+ pll_ctrl2 = 0xb;
+ } else if (input->basic.frequency / 2 < 625) {
+ pll_ctrl2 = 0xa;
+ } else if (input->basic.frequency / 2 < 938) {
+ pll_ctrl2 = 0x19;
+ } else if (input->basic.frequency / 2 < 1067) {
+ pll_ctrl2 = 0x18;
+ } else {
+ pll_ctrl2 = 0x19;
+ }
+
+ phy_io_write16(phy, addr, pll_ctrl2);
+
+ debug("pll_ctrl2 = 0x%x\n", phy_io_read16(phy, addr));
+}
+
+static void prog_dll_lck_param(uint16_t *phy, const struct input *input)
+{
+ uint32_t addr = t_master | csr_dll_lockparam_addr;
+
+ phy_io_write16(phy, addr, U(0x212));
+ debug("dll_lck_param = 0x%x\n", phy_io_read16(phy, addr));
+}
+
+static void prog_dll_gain_ctl(uint16_t *phy, const struct input *input)
+{
+ uint32_t addr = t_master | csr_dll_gain_ctl_addr;
+
+ phy_io_write16(phy, addr, U(0x61));
+ debug("dll_gain_ctl = 0x%x\n", phy_io_read16(phy, addr));
+}
+
+static void prog_pll_pwr_dn(uint16_t *phy,
+ const struct input *input)
+{
+ uint32_t addr;
+
+ addr = t_master | csr_pll_pwr_dn_addr;
+ phy_io_write16(phy, addr, 0U);
+
+ debug("pll_pwrdn = 0x%x\n", phy_io_read16(phy, addr));
+}
+
+static void prog_ard_ptr_init_val(uint16_t *phy,
+ const struct input *input)
+{
+ int ard_ptr_init_val;
+ uint32_t addr = t_master | csr_ard_ptr_init_val_addr;
+
+ if (input->basic.frequency >= 933) {
+ ard_ptr_init_val = 0x2;
+ } else {
+ ard_ptr_init_val = 0x1;
+ }
+
+ phy_io_write16(phy, addr, ard_ptr_init_val);
+}
+
+static void prog_dqs_preamble_control(uint16_t *phy,
+ const struct input *input)
+{
+ int data;
+ uint32_t addr = t_master | csr_dqs_preamble_control_addr;
+ const int wdqsextension = 0;
+ const int lp4sttc_pre_bridge_rx_en = 0;
+ const int lp4postamble_ext = 0;
+ const int lp4tgl_two_tck_tx_dqs_pre = 0;
+ const int position_dfe_init = 2;
+ const int dll_rx_preamble_mode = 1;
+ int two_tck_tx_dqs_pre = input->adv.d4tx_preamble_length;
+ int two_tck_rx_dqs_pre = input->adv.d4rx_preamble_length;
+
+ data = wdqsextension << csr_wdqsextension_lsb |
+ lp4sttc_pre_bridge_rx_en << csr_lp4sttc_pre_bridge_rx_en_lsb |
+ lp4postamble_ext << csr_lp4postamble_ext_lsb |
+ lp4tgl_two_tck_tx_dqs_pre << csr_lp4tgl_two_tck_tx_dqs_pre_lsb |
+ position_dfe_init << csr_position_dfe_init_lsb |
+ two_tck_tx_dqs_pre << csr_two_tck_tx_dqs_pre_lsb |
+ two_tck_rx_dqs_pre << csr_two_tck_rx_dqs_pre_lsb;
+ phy_io_write16(phy, addr, data);
+
+ data = dll_rx_preamble_mode << csr_dll_rx_preamble_mode_lsb;
+ addr = t_master | csr_dbyte_dll_mode_cntrl_addr;
+ phy_io_write16(phy, addr, data);
+}
+
+static void prog_proc_odt_time_ctl(uint16_t *phy,
+ const struct input *input)
+{
+ int proc_odt_time_ctl;
+ uint32_t addr = t_master | csr_proc_odt_time_ctl_addr;
+
+ if (input->adv.wdqsext != 0) {
+ proc_odt_time_ctl = 0x3;
+ } else if (input->basic.frequency <= 933) {
+ proc_odt_time_ctl = 0xa;
+ } else if (input->basic.frequency <= 1200) {
+ if (input->adv.d4rx_preamble_length == 1) {
+ proc_odt_time_ctl = 0x2;
+ } else {
+ proc_odt_time_ctl = 0x6;
+ }
+ } else {
+ if (input->adv.d4rx_preamble_length == 1) {
+ proc_odt_time_ctl = 0x3;
+ } else {
+ proc_odt_time_ctl = 0x7;
+ }
+ }
+ phy_io_write16(phy, addr, proc_odt_time_ctl);
+}
+
+static const struct impedance_mapping map[] = {
+ { 29, 0x3f },
+ { 31, 0x3e },
+ { 33, 0x3b },
+ { 36, 0x3a },
+ { 39, 0x39 },
+ { 42, 0x38 },
+ { 46, 0x1b },
+ { 51, 0x1a },
+ { 57, 0x19 },
+ { 64, 0x18 },
+ { 74, 0x0b },
+ { 88, 0x0a },
+ { 108, 0x09 },
+ { 140, 0x08 },
+ { 200, 0x03 },
+ { 360, 0x02 },
+ { 481, 0x01 },
+ {}
+};
+
+static int map_impedance(int strength)
+{
+ const struct impedance_mapping *tbl = map;
+ int val = 0;
+
+ if (strength == 0) {
+ return 0;
+ }
+
+ while (tbl->ohm != 0U) {
+ if (strength < tbl->ohm) {
+ val = tbl->code;
+ break;
+ }
+ tbl++;
+ }
+
+ return val;
+}
+
+static int map_odtstren_p(int strength, int hard_macro_ver)
+{
+ int val = -1;
+
+ if (hard_macro_ver == 4) {
+ if (strength == 0) {
+ val = 0;
+ } else if (strength == 120) {
+ val = 0x8;
+ } else if (strength == 60) {
+ val = 0x18;
+ } else if (strength == 40) {
+ val = 0x38;
+ } else {
+ printf("error: unsupported ODTStrenP %d\n", strength);
+ }
+ } else {
+ val = map_impedance(strength);
+ }
+
+ return val;
+}
+
+static void prog_tx_odt_drv_stren(uint16_t *phy,
+ const struct input *input)
+{
+ int lane, byte, b_addr, c_addr;
+ int tx_odt_drv_stren;
+ int odtstren_p, odtstren_n;
+ uint32_t addr;
+
+ odtstren_p = map_odtstren_p(input->adv.odtimpedance,
+ input->basic.hard_macro_ver);
+ if (odtstren_p < 0) {
+ return;
+ }
+
+ odtstren_n = 0; /* always high-z */
+ tx_odt_drv_stren = odtstren_n << csr_odtstren_n_lsb | odtstren_p;
+ for (byte = 0; byte < input->basic.num_dbyte; byte++) {
+ c_addr = byte << 12;
+ for (lane = 0; lane <= 1; lane++) {
+ b_addr = lane << 8;
+ addr = t_dbyte | c_addr | b_addr |
+ csr_tx_odt_drv_stren_addr;
+ phy_io_write16(phy, addr, tx_odt_drv_stren);
+ }
+ }
+}
+
+static int map_drvstren_fsdq_p(int strength, int hard_macro_ver)
+{
+ int val = -1;
+
+ if (hard_macro_ver == 4) {
+ if (strength == 0) {
+ val = 0x07;
+ } else if (strength == 120) {
+ val = 0x0F;
+ } else if (strength == 60) {
+ val = 0x1F;
+ } else if (strength == 40) {
+ val = 0x3F;
+ } else {
+ printf("error: unsupported drv_stren_fSDq_p %d\n",
+ strength);
+ }
+ } else {
+ val = map_impedance(strength);
+ }
+
+ return val;
+}
+
+static int map_drvstren_fsdq_n(int strength, int hard_macro_ver)
+{
+ int val = -1;
+
+ if (hard_macro_ver == 4) {
+ if (strength == 0) {
+ val = 0x00;
+ } else if (strength == 120) {
+ val = 0x08;
+ } else if (strength == 60) {
+ val = 0x18;
+ } else if (strength == 40) {
+ val = 0x38;
+ } else {
+ printf("error: unsupported drvStrenFSDqN %d\n",
+ strength);
+ }
+ } else {
+ val = map_impedance(strength);
+ }
+
+ return val;
+}
+
+static void prog_tx_impedance_ctrl1(uint16_t *phy,
+ const struct input *input)
+{
+ int lane, byte, b_addr, c_addr;
+ int tx_impedance_ctrl1;
+ int drv_stren_fsdq_p, drv_stren_fsdq_n;
+ uint32_t addr;
+
+ drv_stren_fsdq_p = map_drvstren_fsdq_p(input->adv.tx_impedance,
+ input->basic.hard_macro_ver);
+ drv_stren_fsdq_n = map_drvstren_fsdq_n(input->adv.tx_impedance,
+ input->basic.hard_macro_ver);
+ tx_impedance_ctrl1 = drv_stren_fsdq_n << csr_drv_stren_fsdq_n_lsb |
+ drv_stren_fsdq_p << csr_drv_stren_fsdq_p_lsb;
+
+ for (byte = 0; byte < input->basic.num_dbyte; byte++) {
+ c_addr = byte << 12;
+ for (lane = 0; lane <= 1; lane++) {
+ b_addr = lane << 8;
+ addr = t_dbyte | c_addr | b_addr |
+ csr_tx_impedance_ctrl1_addr;
+ phy_io_write16(phy, addr, tx_impedance_ctrl1);
+ }
+ }
+}
+
+static int map_adrv_stren_p(int strength, int hard_macro_ver)
+{
+ int val = -1;
+
+ if (hard_macro_ver == 4) {
+ if (strength == 120) {
+ val = 0x1c;
+ } else if (strength == 60) {
+ val = 0x1d;
+ } else if (strength == 40) {
+ val = 0x1f;
+ } else {
+ printf("error: unsupported aDrv_stren_p %d\n",
+ strength);
+ }
+ } else {
+ if (strength == 120) {
+ val = 0x00;
+ } else if (strength == 60) {
+ val = 0x01;
+ } else if (strength == 40) {
+ val = 0x03;
+ } else if (strength == 30) {
+ val = 0x07;
+ } else if (strength == 24) {
+ val = 0x0f;
+ } else if (strength == 20) {
+ val = 0x1f;
+ } else {
+ printf("error: unsupported aDrv_stren_p %d\n",
+ strength);
+ }
+ }
+
+ return val;
+}
+
+static int map_adrv_stren_n(int strength, int hard_macro_ver)
+{
+ int val = -1;
+
+ if (hard_macro_ver == 4) {
+ if (strength == 120) {
+ val = 0x00;
+ } else if (strength == 60) {
+ val = 0x01;
+ } else if (strength == 40) {
+ val = 0x03;
+ } else {
+ printf("Error: unsupported ADrvStrenP %d\n", strength);
+ }
+ } else {
+ if (strength == 120) {
+ val = 0x00;
+ } else if (strength == 60) {
+ val = 0x01;
+ } else if (strength == 40) {
+ val = 0x03;
+ } else if (strength == 30) {
+ val = 0x07;
+ } else if (strength == 24) {
+ val = 0x0f;
+ } else if (strength == 20) {
+ val = 0x1f;
+ } else {
+ printf("Error: unsupported ADrvStrenP %d\n", strength);
+ }
+ }
+
+ return val;
+}
+
+static void prog_atx_impedance(uint16_t *phy,
+ const struct input *input)
+{
+ int anib, c_addr;
+ int atx_impedance;
+ int adrv_stren_p;
+ int adrv_stren_n;
+ uint32_t addr;
+
+ if (input->basic.hard_macro_ver == 4 &&
+ input->adv.atx_impedance == 20) {
+ printf("Error:ATxImpedance has to be 40 for HardMacroVer 4\n");
+ return;
+ }
+
+ adrv_stren_p = map_adrv_stren_p(input->adv.atx_impedance,
+ input->basic.hard_macro_ver);
+ adrv_stren_n = map_adrv_stren_n(input->adv.atx_impedance,
+ input->basic.hard_macro_ver);
+ atx_impedance = adrv_stren_n << csr_adrv_stren_n_lsb |
+ adrv_stren_p << csr_adrv_stren_p_lsb;
+ for (anib = 0; anib < input->basic.num_anib; anib++) {
+ c_addr = anib << 12;
+ addr = t_anib | c_addr | csr_atx_impedance_addr;
+ phy_io_write16(phy, addr, atx_impedance);
+ }
+}
+
+static void prog_dfi_mode(uint16_t *phy,
+ const struct input *input)
+{
+ int dfi_mode;
+ uint32_t addr;
+
+ if (input->basic.dfi1exists == 1) {
+ dfi_mode = 0x5; /* DFI1 exists but disabled */
+ } else {
+ dfi_mode = 0x1; /* DFI1 does not physically exists */
+ }
+ addr = t_master | csr_dfi_mode_addr;
+ phy_io_write16(phy, addr, dfi_mode);
+}
+
+static void prog_acx4_anib_dis(uint16_t *phy, const struct input *input)
+{
+ uint32_t addr;
+
+ addr = t_master | csr_acx4_anib_dis_addr;
+ phy_io_write16(phy, addr, 0x0);
+ debug("%s 0x%x\n", __func__, phy_io_read16(phy, addr));
+}
+
+static void prog_dfi_camode(uint16_t *phy,
+ const struct input *input)
+{
+ int dfi_camode = 2;
+ uint32_t addr = t_master | csr_dfi_camode_addr;
+
+ phy_io_write16(phy, addr, dfi_camode);
+}
+
+static void prog_cal_drv_str0(uint16_t *phy,
+ const struct input *input)
+{
+ int cal_drv_str0;
+ int cal_drv_str_pd50;
+ int cal_drv_str_pu50;
+ uint32_t addr;
+
+ cal_drv_str_pu50 = input->adv.ext_cal_res_val;
+ cal_drv_str_pd50 = cal_drv_str_pu50;
+ cal_drv_str0 = cal_drv_str_pu50 << csr_cal_drv_str_pu50_lsb |
+ cal_drv_str_pd50;
+ addr = t_master | csr_cal_drv_str0_addr;
+ phy_io_write16(phy, addr, cal_drv_str0);
+}
+
+static void prog_cal_uclk_info(uint16_t *phy,
+ const struct input *input)
+{
+ int cal_uclk_ticks_per1u_s;
+ uint32_t addr;
+
+ cal_uclk_ticks_per1u_s = input->basic.frequency >> 1;
+ if (cal_uclk_ticks_per1u_s < 24) {
+ cal_uclk_ticks_per1u_s = 24;
+ }
+
+ addr = t_master | csr_cal_uclk_info_addr;
+ phy_io_write16(phy, addr, cal_uclk_ticks_per1u_s);
+}
+
+static void prog_cal_rate(uint16_t *phy,
+ const struct input *input)
+{
+ int cal_rate;
+ int cal_interval;
+ int cal_once;
+ uint32_t addr;
+
+ cal_interval = input->adv.cal_interval;
+ cal_once = input->adv.cal_once;
+ cal_rate = cal_once << csr_cal_once_lsb |
+ cal_interval << csr_cal_interval_lsb;
+ addr = t_master | csr_cal_rate_addr;
+ phy_io_write16(phy, addr, cal_rate);
+}
+
+static void prog_vref_in_global(uint16_t *phy,
+ const struct input *input,
+ const struct ddr4u1d *msg)
+{
+ int vref_in_global;
+ int global_vref_in_dac = 0;
+ int global_vref_in_sel = 0;
+ uint32_t addr;
+
+ /*
+ * phy_vref_prcnt = msg->phy_vref / 128.0
+ * global_vref_in_dac = (phy_vref_prcnt - 0.345) / 0.005;
+ */
+ global_vref_in_dac = (msg->phy_vref * 1000 - 345 * 128 + 320) /
+ (5 * 128);
+
+ vref_in_global = global_vref_in_dac << csr_global_vref_in_dac_lsb |
+ global_vref_in_sel;
+ addr = t_master | csr_vref_in_global_addr;
+ phy_io_write16(phy, addr, vref_in_global);
+}
+
+static void prog_dq_dqs_rcv_cntrl(uint16_t *phy,
+ const struct input *input)
+{
+ int lane, byte, b_addr, c_addr;
+ int dq_dqs_rcv_cntrl;
+ int gain_curr_adj_defval = 0xb;
+ int major_mode_dbyte = 3;
+ int dfe_ctrl_defval = 0;
+ int ext_vref_range_defval = 0;
+ int sel_analog_vref = 1;
+ uint32_t addr;
+
+#ifdef ERRATA_DDR_A050958
+ gain_curr_adj_defval = 0x1f;
+#endif
+
+ dq_dqs_rcv_cntrl = gain_curr_adj_defval << csr_gain_curr_adj_lsb |
+ major_mode_dbyte << csr_major_mode_dbyte_lsb |
+ dfe_ctrl_defval << csr_dfe_ctrl_lsb |
+ ext_vref_range_defval << csr_ext_vref_range_lsb |
+ sel_analog_vref << csr_sel_analog_vref_lsb;
+ for (byte = 0; byte < input->basic.num_dbyte; byte++) {
+ c_addr = byte << 12;
+ for (lane = 0; lane <= 1; lane++) {
+ b_addr = lane << 8;
+ addr = t_dbyte | c_addr | b_addr |
+ csr_dq_dqs_rcv_cntrl_addr;
+ phy_io_write16(phy, addr, dq_dqs_rcv_cntrl);
+ }
+ }
+}
+
+static void prog_mem_alert_control(uint16_t *phy,
+ const struct input *input)
+{
+ int mem_alert_control;
+ int mem_alert_control2;
+ int malertpu_en;
+ int malertrx_en;
+ int malertvref_level;
+ int malertpu_stren;
+ int malertsync_bypass;
+ int malertdisable_val_defval = 1;
+ uint32_t addr;
+
+ if (input->basic.dram_type == DDR4 && input->adv.mem_alert_en == 1) {
+ malertpu_en = 1;
+ malertrx_en = 1;
+ malertpu_stren = input->adv.mem_alert_puimp;
+ malertvref_level = input->adv.mem_alert_vref_level;
+ malertsync_bypass = input->adv.mem_alert_sync_bypass;
+ mem_alert_control = malertdisable_val_defval << 14 |
+ malertrx_en << 13 |
+ malertpu_en << 12 |
+ malertpu_stren << 8 |
+ malertvref_level;
+ mem_alert_control2 = malertsync_bypass <<
+ csr_malertsync_bypass_lsb;
+ addr = t_master | csr_mem_alert_control_addr;
+ phy_io_write16(phy, addr, mem_alert_control);
+ addr = t_master | csr_mem_alert_control2_addr;
+ phy_io_write16(phy, addr, mem_alert_control2);
+ }
+}
+
+static void prog_dfi_freq_ratio(uint16_t *phy,
+ const struct input *input)
+{
+ int dfi_freq_ratio;
+ uint32_t addr = t_master | csr_dfi_freq_ratio_addr;
+
+ dfi_freq_ratio = input->basic.dfi_freq_ratio;
+ phy_io_write16(phy, addr, dfi_freq_ratio);
+}
+
+static void prog_tristate_mode_ca(uint16_t *phy,
+ const struct input *input)
+{
+ int tristate_mode_ca;
+ int dis_dyn_adr_tri;
+ int ddr2tmode;
+ int ck_dis_val_def = 1;
+ uint32_t addr = t_master | csr_tristate_mode_ca_addr;
+
+ dis_dyn_adr_tri = input->adv.dis_dyn_adr_tri;
+ ddr2tmode = input->adv.is2ttiming;
+ tristate_mode_ca = ck_dis_val_def << csr_ck_dis_val_lsb |
+ ddr2tmode << csr_ddr2tmode_lsb |
+ dis_dyn_adr_tri << csr_dis_dyn_adr_tri_lsb;
+ phy_io_write16(phy, addr, tristate_mode_ca);
+}
+
+static void prog_dfi_xlat(uint16_t *phy,
+ const struct input *input)
+{
+ uint16_t loop_vector;
+ int dfifreqxlat_dat;
+ int pllbypass_dat;
+ uint32_t addr;
+
+ /* fIXME: Shall unused P1, P2, P3 be bypassed? */
+ pllbypass_dat = input->basic.pll_bypass; /* only [0] is used */
+ for (loop_vector = 0; loop_vector < 8; loop_vector++) {
+ if (loop_vector == 0) {
+ dfifreqxlat_dat = pllbypass_dat + 0x5555;
+ } else if (loop_vector == 7) {
+ dfifreqxlat_dat = 0xf000;
+ } else {
+ dfifreqxlat_dat = 0x5555;
+ }
+ addr = t_master | (csr_dfi_freq_xlat0_addr + loop_vector);
+ phy_io_write16(phy, addr, dfifreqxlat_dat);
+ }
+}
+
+static void prog_dbyte_misc_mode(uint16_t *phy,
+ const struct input *input,
+ const struct ddr4u1d *msg)
+{
+ int dbyte_misc_mode;
+ int dq_dqs_rcv_cntrl1;
+ int dq_dqs_rcv_cntrl1_1;
+ int byte, c_addr;
+ uint32_t addr;
+
+ dbyte_misc_mode = 0x1 << csr_dbyte_disable_lsb;
+ dq_dqs_rcv_cntrl1 = 0x1ff << csr_power_down_rcvr_lsb |
+ 0x1 << csr_power_down_rcvr_dqs_lsb |
+ 0x1 << csr_rx_pad_standby_en_lsb;
+ dq_dqs_rcv_cntrl1_1 = (0x100 << csr_power_down_rcvr_lsb |
+ csr_rx_pad_standby_en_mask);
+ for (byte = 0; byte < input->basic.num_dbyte; byte++) {
+ c_addr = byte << 12;
+ if (byte <= input->basic.num_active_dbyte_dfi0 - 1) {
+ /* disable RDBI lane if not used. */
+ if ((input->basic.dram_data_width != 4) &&
+ (((msg->mr5 >> 12) & 0x1) == 0)) {
+ addr = t_dbyte
+ | c_addr
+ | csr_dq_dqs_rcv_cntrl1_addr;
+ phy_io_write16(phy, addr, dq_dqs_rcv_cntrl1_1);
+ }
+ } else {
+ addr = t_dbyte | c_addr | csr_dbyte_misc_mode_addr;
+ phy_io_write16(phy, addr, dbyte_misc_mode);
+ addr = t_dbyte | c_addr | csr_dq_dqs_rcv_cntrl1_addr;
+ phy_io_write16(phy, addr, dq_dqs_rcv_cntrl1);
+ }
+ }
+}
+
+static void prog_master_x4config(uint16_t *phy,
+ const struct input *input)
+{
+ int master_x4config;
+ int x4tg;
+ uint32_t addr = t_master | csr_master_x4config_addr;
+
+ x4tg = input->basic.dram_data_width == 4 ? 0xf : 0;
+ master_x4config = x4tg << csr_x4tg_lsb;
+ phy_io_write16(phy, addr, master_x4config);
+}
+
+static void prog_dmipin_present(uint16_t *phy,
+ const struct input *input,
+ const struct ddr4u1d *msg)
+{
+ int dmipin_present;
+ uint32_t addr = t_master | csr_dmipin_present_addr;
+
+ dmipin_present = (msg->mr5 >> 12) & 0x1;
+ phy_io_write16(phy, addr, dmipin_present);
+}
+
+static void prog_dfi_phyupd(uint16_t *phy,
+ const struct input *input)
+{
+ int dfiphyupd_dat;
+ uint32_t addr;
+
+ addr = t_master | (csr_dfiphyupd_addr);
+ dfiphyupd_dat = phy_io_read16(phy, addr) &
+ ~csr_dfiphyupd_threshold_mask;
+
+ phy_io_write16(phy, addr, dfiphyupd_dat);
+}
+
+static void prog_cal_misc2(uint16_t *phy,
+ const struct input *input)
+{
+ int cal_misc2_dat, cal_drv_pdth_data, cal_offsets_dat;
+ uint32_t addr;
+
+ addr = t_master | (csr_cal_misc2_addr);
+ cal_misc2_dat = phy_io_read16(phy, addr) |
+ (1 << csr_cal_misc2_err_dis);
+
+ phy_io_write16(phy, addr, cal_misc2_dat);
+
+ addr = t_master | (csr_cal_offsets_addr);
+
+ cal_drv_pdth_data = 0x9 << 6;
+ cal_offsets_dat = (phy_io_read16(phy, addr) & ~csr_cal_drv_pdth_mask)
+ | cal_drv_pdth_data;
+
+ phy_io_write16(phy, addr, cal_offsets_dat);
+}
+
+static int c_init_phy_config(uint16_t **phy_ptr,
+ unsigned int ip_rev,
+ const struct input *input,
+ const void *msg)
+{
+ int i;
+ uint16_t *phy;
+ __unused const soc_info_t *soc_info;
+
+ for (i = 0; i < NUM_OF_DDRC; i++) {
+ phy = phy_ptr[i];
+ if (phy == NULL) {
+ continue;
+ }
+
+ debug("Initialize PHY %d config\n", i);
+ prog_dfi_phyupd(phy, input);
+ prog_cal_misc2(phy, input);
+ prog_tx_pre_drv_mode(phy, input);
+ prog_atx_pre_drv_mode(phy, input);
+ prog_enable_cs_multicast(phy, input); /* rdimm and lrdimm */
+ prog_dfi_rd_data_cs_dest_map(phy, ip_rev, input, msg);
+ prog_pll_ctrl2(phy, input);
+#ifdef DDR_PLL_FIX
+ soc_info = get_soc_info();
+ debug("SOC_SI_REV = %x\n", soc_info->svr_reg.bf.maj_ver);
+ if (soc_info->svr_reg.bf.maj_ver == 1) {
+ prog_pll_pwr_dn(phy, input);
+
+ /*Enable FFE aka TxEqualizationMode for rev1 SI*/
+ phy_io_write16(phy, 0x010048, 0x1);
+ }
+#endif
+ prog_ard_ptr_init_val(phy, input);
+ prog_dqs_preamble_control(phy, input);
+ prog_dll_lck_param(phy, input);
+ prog_dll_gain_ctl(phy, input);
+ prog_proc_odt_time_ctl(phy, input);
+ prog_tx_odt_drv_stren(phy, input);
+ prog_tx_impedance_ctrl1(phy, input);
+ prog_atx_impedance(phy, input);
+ prog_dfi_mode(phy, input);
+ prog_dfi_camode(phy, input);
+ prog_cal_drv_str0(phy, input);
+ prog_cal_uclk_info(phy, input);
+ prog_cal_rate(phy, input);
+ prog_vref_in_global(phy, input, msg);
+ prog_dq_dqs_rcv_cntrl(phy, input);
+ prog_mem_alert_control(phy, input);
+ prog_dfi_freq_ratio(phy, input);
+ prog_tristate_mode_ca(phy, input);
+ prog_dfi_xlat(phy, input);
+ prog_dbyte_misc_mode(phy, input, msg);
+ prog_master_x4config(phy, input);
+ prog_dmipin_present(phy, input, msg);
+ prog_acx4_anib_dis(phy, input);
+ }
+
+ return 0;
+}
+
+static uint32_t get_mail(uint16_t *phy, int stream)
+{
+ int timeout;
+ uint32_t mail = 0U;
+
+ timeout = TIMEOUTDEFAULT;
+ while (((--timeout) != 0) &&
+ ((phy_io_read16(phy, t_apbonly | csr_uct_shadow_regs)
+ & uct_write_prot_shadow_mask) != 0)) {
+ mdelay(10);
+ }
+ if (timeout == 0) {
+ ERROR("Timeout getting mail from PHY\n");
+ return 0xFFFF;
+ }
+
+ mail = phy_io_read16(phy, t_apbonly |
+ csr_uct_write_only_shadow);
+ if (stream != 0) {
+ mail |= phy_io_read16(phy, t_apbonly |
+ csr_uct_dat_write_only_shadow) << 16;
+ }
+
+ /* Ack */
+ phy_io_write16(phy, t_apbonly | csr_dct_write_prot, 0);
+
+ timeout = TIMEOUTDEFAULT;
+ while (((--timeout) != 0) &&
+ ((phy_io_read16(phy, t_apbonly | csr_uct_shadow_regs)
+ & uct_write_prot_shadow_mask) == 0)) {
+ mdelay(1);
+ }
+ if (timeout == 0) {
+ ERROR("Timeout ack PHY mail\n");
+ }
+
+ /* completed */
+ phy_io_write16(phy, t_apbonly | csr_dct_write_prot, 1U);
+
+ return mail;
+}
+
+#ifdef DDR_PHY_DEBUG
+static const char *lookup_msg(uint32_t index, int train2d)
+{
+ int i;
+ int size;
+ const struct phy_msg *messages;
+ const char *ptr = NULL;
+
+ if (train2d != 0) {
+ messages = messages_2d;
+ size = ARRAY_SIZE(messages_2d);
+ } else {
+ messages = messages_1d;
+ size = ARRAY_SIZE(messages_1d);
+ }
+ for (i = 0; i < size; i++) {
+ if (messages[i].index == index) {
+ ptr = messages[i].msg;
+ break;
+ }
+ }
+
+ return ptr;
+}
+#endif
+
+#define MAX_ARGS 32
+static void decode_stream_message(uint16_t *phy, int train2d)
+{
+ uint32_t index __unused;
+
+ __unused const char *format;
+ __unused uint32_t args[MAX_ARGS];
+ __unused int i;
+
+#ifdef DDR_PHY_DEBUG
+ index = get_mail(phy, 1);
+ if ((index & 0xffff) > MAX_ARGS) { /* up to MAX_ARGS args so far */
+ printf("Program error in %s\n", __func__);
+ }
+ for (i = 0; i < (index & 0xffff) && i < MAX_ARGS; i++) {
+ args[i] = get_mail(phy, 1);
+ }
+
+ format = lookup_msg(index, train2d);
+ if (format != NULL) {
+ printf("0x%08x: ", index);
+ printf(format, args[0], args[1], args[2], args[3], args[4],
+ args[5], args[6], args[7], args[8], args[9], args[10],
+ args[11], args[12], args[13], args[14], args[15],
+ args[16], args[17], args[18], args[19], args[20],
+ args[21], args[22], args[23], args[24], args[25],
+ args[26], args[27], args[28], args[29], args[30],
+ args[31]);
+ }
+#endif
+}
+
+static int wait_fw_done(uint16_t *phy, int train2d)
+{
+ uint32_t mail = 0U;
+
+ while (mail == U(0x0)) {
+ mail = get_mail(phy, 0);
+ switch (mail) {
+ case U(0x7):
+ debug("%s Training completed\n", train2d ? "2D" : "1D");
+ break;
+ case U(0xff):
+ debug("%s Training failure\n", train2d ? "2D" : "1D");
+ break;
+ case U(0x0):
+ debug("End of initialization\n");
+ mail = 0U;
+ break;
+ case U(0x1):
+ debug("End of fine write leveling\n");
+ mail = 0U;
+ break;
+ case U(0x2):
+ debug("End of read enable training\n");
+ mail = 0U;
+ break;
+ case U(0x3):
+ debug("End of read delay center optimization\n");
+ mail = 0U;
+ break;
+ case U(0x4):
+ debug("End of write delay center optimization\n");
+ mail = 0U;
+ break;
+ case U(0x5):
+ debug("End of 2D read delay/voltage center optimztn\n");
+ mail = 0U;
+ break;
+ case U(0x6):
+ debug("End of 2D write delay/voltage center optmztn\n");
+ mail = 0U;
+ break;
+ case U(0x8):
+ decode_stream_message(phy, train2d);
+ mail = 0U;
+ break;
+ case U(0x9):
+ debug("End of max read latency training\n");
+ mail = 0U;
+ break;
+ case U(0xa):
+ debug("End of read dq deskew training\n");
+ mail = 0U;
+ break;
+ case U(0xc):
+ debug("End of LRDIMM Specific training, including:\n");
+ debug("/tDWL, MREP, MRD and MWD\n");
+ mail = 0U;
+ break;
+ case U(0xd):
+ debug("End of CA training\n");
+ mail = 0U;
+ break;
+ case U(0xfd):
+ debug("End of MPR read delay center optimization\n");
+ mail = 0U;
+ break;
+ case U(0xfe):
+ debug("End of Write leveling coarse delay\n");
+ mail = 0U;
+ break;
+ case U(0xffff):
+ debug("Timed out\n");
+ break;
+ default:
+ mail = 0U;
+ break;
+ }
+ }
+
+ if (mail == U(0x7)) {
+ return 0;
+ } else if (mail == U(0xff)) {
+ return -EIO;
+ } else if (mail == U(0xffff)) {
+ return -ETIMEDOUT;
+ }
+
+ debug("PHY_GEN2 FW: Unxpected mail = 0x%x\n", mail);
+
+ return -EINVAL;
+}
+
+static int g_exec_fw(uint16_t **phy_ptr, int train2d, struct input *input)
+{
+ int ret = -EINVAL;
+ int i;
+ uint16_t *phy;
+
+ for (i = 0; i < NUM_OF_DDRC; i++) {
+ phy = phy_ptr[i];
+ if (phy == NULL) {
+ continue;
+ }
+ debug("Applying PLL optimal settings\n");
+ prog_pll_ctrl2(phy, input);
+ prog_pll_ctrl(phy, input);
+ phy_io_write16(phy,
+ t_apbonly | csr_micro_cont_mux_sel_addr,
+ 0x1);
+ phy_io_write16(phy,
+ t_apbonly | csr_micro_reset_addr,
+ csr_reset_to_micro_mask |
+ csr_stall_to_micro_mask);
+ phy_io_write16(phy,
+ t_apbonly | csr_micro_reset_addr,
+ csr_stall_to_micro_mask);
+ phy_io_write16(phy,
+ t_apbonly | csr_micro_reset_addr,
+ 0);
+
+ ret = wait_fw_done(phy, train2d);
+ if (ret == -ETIMEDOUT) {
+ ERROR("Wait timed out: Firmware execution on PHY %d\n",
+ i);
+ }
+ }
+ return ret;
+}
+
+static inline int send_fw(uint16_t *phy,
+ uint32_t dst,
+ uint16_t *img,
+ uint32_t size)
+{
+ uint32_t i;
+
+ if ((size % 2U) != 0U) {
+ ERROR("Wrong image size 0x%x\n", size);
+ return -EINVAL;
+ }
+
+ for (i = 0U; i < size / 2; i++) {
+ phy_io_write16(phy, dst + i, *(img + i));
+ }
+
+ return 0;
+}
+
+static int load_fw(uint16_t **phy_ptr,
+ struct input *input,
+ int train2d,
+ void *msg,
+ size_t len,
+ uintptr_t phy_gen2_fw_img_buf,
+ int (*img_loadr)(unsigned int, uintptr_t *, uint32_t *),
+ uint32_t warm_boot_flag)
+{
+ uint32_t imem_id, dmem_id;
+ uintptr_t image_buf;
+ uint32_t size;
+ int ret;
+ int i;
+ uint16_t *phy;
+
+ switch (input->basic.dimm_type) {
+ case UDIMM:
+ case SODIMM:
+ case NODIMM:
+ imem_id = train2d ? DDR_IMEM_UDIMM_2D_IMAGE_ID :
+ DDR_IMEM_UDIMM_1D_IMAGE_ID;
+ dmem_id = train2d ? DDR_DMEM_UDIMM_2D_IMAGE_ID :
+ DDR_DMEM_UDIMM_1D_IMAGE_ID;
+ break;
+ case RDIMM:
+ imem_id = train2d ? DDR_IMEM_RDIMM_2D_IMAGE_ID :
+ DDR_IMEM_RDIMM_1D_IMAGE_ID;
+ dmem_id = train2d ? DDR_DMEM_RDIMM_2D_IMAGE_ID :
+ DDR_DMEM_RDIMM_1D_IMAGE_ID;
+ break;
+ default:
+ ERROR("Unsupported DIMM type\n");
+ return -EINVAL;
+ }
+
+ size = PHY_GEN2_MAX_IMAGE_SIZE;
+ image_buf = (uintptr_t)phy_gen2_fw_img_buf;
+ ret = img_loadr(imem_id, &image_buf, &size);
+ if (ret != 0) {
+ ERROR("Failed to load %d firmware.\n", imem_id);
+ return ret;
+ }
+ debug("Loaded Imaged id %d of size %x at address %lx\n",
+ imem_id, size, image_buf);
+
+ for (i = 0; i < NUM_OF_DDRC; i++) {
+ phy = phy_ptr[i];
+ if (phy == NULL) {
+ continue;
+ }
+
+ if (warm_boot_flag != DDR_WARM_BOOT) {
+ if (train2d == 0) {
+ phy_io_write16(phy, t_master |
+ csr_mem_reset_l_addr,
+ csr_protect_mem_reset_mask);
+ }
+ }
+ /* Enable access to the internal CSRs */
+ phy_io_write16(phy, t_apbonly | csr_micro_cont_mux_sel_addr, 0);
+
+ ret = send_fw(phy, PHY_GEN2_IMEM_ADDR,
+ (uint16_t *)image_buf, size);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ size = PHY_GEN2_MAX_IMAGE_SIZE;
+ image_buf = (uintptr_t)phy_gen2_fw_img_buf;
+ ret = img_loadr(dmem_id, &image_buf, &size);
+ if (ret != 0) {
+ ERROR("Failed to load %d firmware.\n", dmem_id);
+ return ret;
+ }
+ debug("Loaded Imaged id %d of size %x at address %lx\n",
+ dmem_id, size, image_buf);
+ image_buf += len;
+ size -= len;
+
+ for (i = 0; i < NUM_OF_DDRC; i++) {
+ phy = phy_ptr[i];
+ if (phy == NULL) {
+ continue;
+ }
+
+ ret = send_fw(phy, PHY_GEN2_DMEM_ADDR, msg, len);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = send_fw(phy, PHY_GEN2_DMEM_ADDR + len / 2,
+ (uint16_t *)image_buf, size);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static void parse_odt(const unsigned int val,
+ const int read,
+ const int i,
+ const unsigned int cs_d0,
+ const unsigned int cs_d1,
+ unsigned int *odt)
+{
+ int shift = read ? 4 : 0;
+ int j;
+
+ if (i < 0 || i > 3) {
+ printf("Error: invalid chip-select value\n");
+ }
+ switch (val) {
+ case DDR_ODT_CS:
+ odt[i] |= (1 << i) << shift;
+ break;
+ case DDR_ODT_ALL_OTHER_CS:
+ for (j = 0; j < DDRC_NUM_CS; j++) {
+ if (i == j) {
+ continue;
+ }
+ if (((cs_d0 | cs_d1) & (1 << j)) == 0) {
+ continue;
+ }
+ odt[j] |= (1 << i) << shift;
+ }
+ break;
+ case DDR_ODT_CS_AND_OTHER_DIMM:
+ odt[i] |= (1 << i) << 4;
+ /* fallthrough */
+ case DDR_ODT_OTHER_DIMM:
+ for (j = 0; j < DDRC_NUM_CS; j++) {
+ if ((((cs_d0 & (1 << i)) != 0) &&
+ ((cs_d1 & (1 << j)) != 0)) ||
+ (((cs_d1 & (1 << i)) != 0) &&
+ ((cs_d0 & (1 << j)) != 0))) {
+ odt[j] |= (1 << i) << shift;
+ }
+ }
+ break;
+ case DDR_ODT_ALL:
+ for (j = 0; j < DDRC_NUM_CS; j++) {
+ if (((cs_d0 | cs_d1) & (1 << j)) == 0) {
+ continue;
+ }
+ odt[j] |= (1 << i) << shift;
+ }
+ break;
+ case DDR_ODT_SAME_DIMM:
+ for (j = 0; j < DDRC_NUM_CS; j++) {
+ if ((((cs_d0 & (1 << i)) != 0) &&
+ ((cs_d0 & (1 << j)) != 0)) ||
+ (((cs_d1 & (1 << i)) != 0) &&
+ ((cs_d1 & (1 << j)) != 0))) {
+ odt[j] |= (1 << i) << shift;
+ }
+ }
+ break;
+ case DDR_ODT_OTHER_CS_ONSAMEDIMM:
+ for (j = 0; j < DDRC_NUM_CS; j++) {
+ if (i == j) {
+ continue;
+ }
+ if ((((cs_d0 & (1 << i)) != 0) &&
+ ((cs_d0 & (1 << j)) != 0)) ||
+ (((cs_d1 & (1 << i)) != 0) &&
+ ((cs_d1 & (1 << j)) != 0))) {
+ odt[j] |= (1 << i) << shift;
+ }
+ }
+ break;
+ case DDR_ODT_NEVER:
+ break;
+ default:
+ break;
+ }
+}
+
+#ifdef DEBUG_DDR_INPUT_CONFIG
+char *dram_types_str[] = {
+ "DDR4",
+ "DDR3",
+ "LDDDR4",
+ "LPDDR3",
+ "LPDDR2",
+ "DDR5"
+};
+
+char *dimm_types_str[] = {
+ "UDIMM",
+ "SODIMM",
+ "RDIMM",
+ "LRDIMM",
+ "NODIMM",
+};
+
+
+static void print_jason_format(struct input *input,
+ struct ddr4u1d *msg_1d,
+ struct ddr4u2d *msg_2d)
+{
+
+ printf("\n{");
+ printf("\n \"dram_type\": \"%s\",", dram_types_str[input->basic.dram_type]);
+ printf("\n \"dimm_type\": \"%s\",", dimm_types_str[input->basic.dimm_type]);
+ printf("\n \"hard_macro_ver\": \"%d\",", input->basic.hard_macro_ver);
+ printf("\n \"num_dbyte\": \"0x%04x\",", (unsigned int)input->basic.num_dbyte);
+ printf("\n \"num_active_dbyte_dfi0\": \"0x%04x\",", (unsigned int)input->basic.num_active_dbyte_dfi0);
+ printf("\n \"num_anib\": \"0x%04x\",", (unsigned int)input->basic.num_anib);
+ printf("\n \"num_rank_dfi0\": \"0x%04x\",", (unsigned int)input->basic.num_rank_dfi0);
+ printf("\n \"num_pstates\": \"0x%04x\",", (unsigned int)input->basic.num_pstates);
+ printf("\n \"frequency\": \"%d\",", input->basic.frequency);
+ printf("\n \"pll_bypass\": \"0x%04x\",", (unsigned int)input->basic.dfi_freq_ratio);
+ printf("\n \"dfi_freq_ratio\": \"0x%04x\",", (unsigned int)input->basic.dfi_freq_ratio);
+ printf("\n \"dfi1_exists\": \"0x%04x\",", (unsigned int)input->basic.dfi1exists);
+ printf("\n \"dram_data_width\": \"0x%04x\",", (unsigned int)input->basic.dram_data_width);
+ printf("\n \"dram_byte_swap\": \"0x%04x\",", (unsigned int)input->adv.dram_byte_swap);
+ printf("\n \"ext_cal_res_val\": \"0x%04x\",", (unsigned int)input->adv.ext_cal_res_val);
+ printf("\n \"tx_slew_rise_dq\": \"0x%04x\",", (unsigned int)input->adv.tx_slew_rise_dq);
+ printf("\n \"tx_slew_fall_dq\": \"0x%04x\",", (unsigned int)input->adv.tx_slew_fall_dq);
+ printf("\n \"tx_slew_rise_ac\": \"0x%04x\",", (unsigned int)input->adv.tx_slew_rise_ac);
+ printf("\n \"tx_slew_fall_ac\": \"0x%04x\",", (unsigned int)input->adv.tx_slew_fall_ac);
+ printf("\n \"odt_impedance\": \"%d\",", input->adv.odtimpedance);
+ printf("\n \"tx_impedance\": \"%d\",", input->adv.tx_impedance);
+ printf("\n \"atx_impedance\": \"%d\",", input->adv.atx_impedance);
+ printf("\n \"mem_alert_en\": \"0x%04x\",", (unsigned int)input->adv.mem_alert_en);
+ printf("\n \"mem_alert_pu_imp\": \"0x%04x\",", (unsigned int)input->adv.mem_alert_puimp);
+ printf("\n \"mem_alert_vref_level\": \"0x%04x\",", (unsigned int)input->adv.mem_alert_vref_level);
+ printf("\n \"mem_alert_sync_bypass\": \"0x%04x\",", (unsigned int)input->adv.mem_alert_sync_bypass);
+ printf("\n \"cal_interval\": \"0x%04x\",", (unsigned int)input->adv.cal_interval);
+ printf("\n \"cal_once\": \"0x%04x\",", (unsigned int)input->adv.cal_once);
+ printf("\n \"dis_dyn_adr_tri\": \"0x%04x\",", (unsigned int)input->adv.dis_dyn_adr_tri);
+ printf("\n \"is2t_timing\": \"0x%04x\",", (unsigned int)input->adv.is2ttiming);
+ printf("\n \"d4rx_preabmle_length\": \"0x%04x\",", (unsigned int)input->adv.d4rx_preamble_length);
+ printf("\n \"d4tx_preamble_length\": \"0x%04x\",", (unsigned int)input->adv.d4tx_preamble_length);
+ printf("\n \"msg_misc\": \"0x%02x\",", (unsigned int)msg_1d->msg_misc);
+ printf("\n \"reserved00\": \"0x%01x\",", (unsigned int)msg_1d->reserved00);
+ printf("\n \"hdt_ctrl\": \"0x%02x\",", (unsigned int)msg_1d->hdt_ctrl);
+ printf("\n \"cs_present\": \"0x%02x\",", (unsigned int)msg_1d->cs_present);
+ printf("\n \"phy_vref\": \"0x%02x\",", (unsigned int)msg_1d->phy_vref);
+ printf("\n \"dfi_mrl_margin\": \"0x%02x\",", (unsigned int)msg_1d->dfimrlmargin);
+ printf("\n \"addr_mirror\": \"0x%02x\",", (unsigned int)msg_1d->addr_mirror);
+ printf("\n \"wr_odt_pat_rank0\": \"0x%02x\",", (unsigned int)(msg_1d->acsm_odt_ctrl0 & 0x0f));
+ printf("\n \"wr_odt_pat_rank1\": \"0x%02x\",", (unsigned int)(msg_1d->acsm_odt_ctrl1 & 0x0f));
+ printf("\n \"wr_odt_pat_rank2\": \"0x%02x\",", (unsigned int)(msg_1d->acsm_odt_ctrl2 & 0x0f));
+ printf("\n \"wr_odt_pat_rank3\": \"0x%02x\",", (unsigned int)(msg_1d->acsm_odt_ctrl3 & 0x0f));
+ printf("\n \"rd_odt_pat_rank0\": \"0x%02x\",", (unsigned int)(msg_1d->acsm_odt_ctrl0 & 0xf0));
+ printf("\n \"rd_odt_pat_rank1\": \"0x%02x\",", (unsigned int)(msg_1d->acsm_odt_ctrl1 & 0xf0));
+ printf("\n \"rd_odt_pat_rank2\": \"0x%02x\",", (unsigned int)(msg_1d->acsm_odt_ctrl2 & 0xf0));
+ printf("\n \"rd_odt_pat_rank3\": \"0x%02x\",", (unsigned int)(msg_1d->acsm_odt_ctrl3 & 0xf0));
+ printf("\n \"d4_misc\": \"0x%01x\",", (unsigned int)msg_1d->d4misc);
+ printf("\n \"share_2d_vref_results\": \"0x%01x\",", (unsigned int)msg_1d->share2dvref_result);
+ printf("\n \"sequence_ctrl\": \"0x%04x\",", (unsigned int)msg_1d->sequence_ctrl);
+ printf("\n \"mr0\": \"0x%04x\",", (unsigned int)msg_1d->mr0);
+ printf("\n \"mr1\": \"0x%04x\",", (unsigned int)msg_1d->mr1);
+ printf("\n \"mr2\": \"0x%04x\",", (unsigned int)msg_1d->mr2);
+ printf("\n \"mr3\": \"0x%04x\",", (unsigned int)msg_1d->mr3);
+ printf("\n \"mr4\": \"0x%04x\",", (unsigned int)msg_1d->mr4);
+ printf("\n \"mr5\": \"0x%04x\",", (unsigned int)msg_1d->mr5);
+ printf("\n \"mr6\": \"0x%04x\",", (unsigned int)msg_1d->mr6);
+ printf("\n \"alt_cal_l\": \"0x%04x\",", (unsigned int)msg_1d->alt_cas_l);
+ printf("\n \"alt_wcal_l\": \"0x%04x\",", (unsigned int)msg_1d->alt_wcas_l);
+ printf("\n \"sequence_ctrl_2d\": \"0x%04x\",", (unsigned int)msg_2d->sequence_ctrl);
+ printf("\n \"rtt_nom_wr_park0\": \"0x%01x\",", (unsigned int)msg_1d->rtt_nom_wr_park0);
+ printf("\n \"rtt_nom_wr_park1\": \"0x%01x\",", (unsigned int)msg_1d->rtt_nom_wr_park1);
+ printf("\n \"rtt_nom_wr_park2\": \"0x%01x\",", (unsigned int)msg_1d->rtt_nom_wr_park2);
+ printf("\n \"rtt_nom_wr_park3\": \"0x%01x\",", (unsigned int)msg_1d->rtt_nom_wr_park3);
+ printf("\n \"rtt_nom_wr_park4\": \"0x%01x\",", (unsigned int)msg_1d->rtt_nom_wr_park4);
+ printf("\n \"rtt_nom_wr_park5\": \"0x%01x\",", (unsigned int)msg_1d->rtt_nom_wr_park5);
+ printf("\n \"rtt_nom_wr_park6\": \"0x%01x\",", (unsigned int)msg_1d->rtt_nom_wr_park6);
+ printf("\n \"rtt_nom_wr_park7\": \"0x%01x\"", (unsigned int)msg_1d->rtt_nom_wr_park7);
+ printf("\n}");
+ printf("\n");
+}
+#endif
+
+int compute_ddr_phy(struct ddr_info *priv)
+{
+ const unsigned long clk = priv->clk;
+ const struct memctl_opt *popts = &priv->opt;
+ const struct ddr_conf *conf = &priv->conf;
+ const struct dimm_params *dimm_param = &priv->dimm;
+ struct ddr_cfg_regs *regs = &priv->ddr_reg;
+ int ret;
+ static struct input input;
+ static struct ddr4u1d msg_1d;
+ static struct ddr4u2d msg_2d;
+ unsigned int i;
+ unsigned int odt_rd, odt_wr;
+ __unused const soc_info_t *soc_info;
+#ifdef NXP_APPLY_MAX_CDD
+ unsigned int tcfg0, tcfg4, rank;
+#endif
+
+ if (dimm_param == NULL) {
+ ERROR("Empty DIMM parameters.\n");
+ return -EINVAL;
+ }
+
+ zeromem(&input, sizeof(input));
+ zeromem(&msg_1d, sizeof(msg_1d));
+ zeromem(&msg_2d, sizeof(msg_2d));
+
+ input.basic.dram_type = DDR4;
+ /* FIXME: Add condition for LRDIMM */
+ input.basic.dimm_type = (dimm_param->rdimm != 0) ? RDIMM : UDIMM;
+ input.basic.num_dbyte = dimm_param->primary_sdram_width / 8 +
+ dimm_param->ec_sdram_width / 8;
+ input.basic.num_active_dbyte_dfi0 = input.basic.num_dbyte;
+ input.basic.num_rank_dfi0 = dimm_param->n_ranks;
+ input.basic.dram_data_width = dimm_param->device_width;
+ input.basic.hard_macro_ver = 0xa;
+ input.basic.num_pstates = 1;
+ input.basic.dfi_freq_ratio = 1;
+ input.basic.num_anib = 0xc;
+ input.basic.train2d = popts->skip2d ? 0 : 1;
+ input.basic.frequency = (int) (clk / 2000000ul);
+ debug("frequency = %dMHz\n", input.basic.frequency);
+ input.cs_d0 = conf->cs_on_dimm[0];
+#if DDRC_NUM_DIMM > 1
+ input.cs_d1 = conf->cs_on_dimm[1];
+#endif
+ input.mirror = dimm_param->mirrored_dimm;
+ input.mr[0] = regs->sdram_mode[0] & U(0xffff);
+ input.mr[1] = regs->sdram_mode[0] >> 16U;
+ input.mr[2] = regs->sdram_mode[1] >> 16U;
+ input.mr[3] = regs->sdram_mode[1] & U(0xffff);
+ input.mr[4] = regs->sdram_mode[8] >> 16U;
+ input.mr[5] = regs->sdram_mode[8] & U(0xffff);
+ input.mr[6] = regs->sdram_mode[9] >> 16U;
+ input.vref = popts->vref_phy;
+ debug("Vref_phy = %d percent\n", (input.vref * 100U) >> 7U);
+ for (i = 0U; i < DDRC_NUM_CS; i++) {
+ if ((regs->cs[i].config & SDRAM_CS_CONFIG_EN) == 0U) {
+ continue;
+ }
+ odt_rd = (regs->cs[i].config >> 20U) & U(0x7);
+ odt_wr = (regs->cs[i].config >> 16U) & U(0x7);
+ parse_odt(odt_rd, true, i, input.cs_d0, input.cs_d1,
+ input.odt);
+ parse_odt(odt_wr, false, i, input.cs_d0, input.cs_d1,
+ input.odt);
+ }
+
+ /* Do not set sdram_cfg[RD_EN] or sdram_cfg2[RCW_EN] for RDIMM */
+ if (dimm_param->rdimm != 0U) {
+ regs->sdram_cfg[0] &= ~(1 << 28U);
+ regs->sdram_cfg[1] &= ~(1 << 2U);
+ input.rcw[0] = (regs->sdram_rcw[0] >> 28U) & U(0xf);
+ input.rcw[1] = (regs->sdram_rcw[0] >> 24U) & U(0xf);
+ input.rcw[2] = (regs->sdram_rcw[0] >> 20U) & U(0xf);
+ input.rcw[3] = (regs->sdram_rcw[0] >> 16U) & U(0xf);
+ input.rcw[4] = (regs->sdram_rcw[0] >> 12U) & U(0xf);
+ input.rcw[5] = (regs->sdram_rcw[0] >> 8U) & U(0xf);
+ input.rcw[6] = (regs->sdram_rcw[0] >> 4U) & U(0xf);
+ input.rcw[7] = (regs->sdram_rcw[0] >> 0U) & U(0xf);
+ input.rcw[8] = (regs->sdram_rcw[1] >> 28U) & U(0xf);
+ input.rcw[9] = (regs->sdram_rcw[1] >> 24U) & U(0xf);
+ input.rcw[10] = (regs->sdram_rcw[1] >> 20U) & U(0xf);
+ input.rcw[11] = (regs->sdram_rcw[1] >> 16U) & U(0xf);
+ input.rcw[12] = (regs->sdram_rcw[1] >> 12U) & U(0xf);
+ input.rcw[13] = (regs->sdram_rcw[1] >> 8U) & U(0xf);
+ input.rcw[14] = (regs->sdram_rcw[1] >> 4U) & U(0xf);
+ input.rcw[15] = (regs->sdram_rcw[1] >> 0U) & U(0xf);
+ input.rcw3x = (regs->sdram_rcw[2] >> 8U) & U(0xff);
+ }
+
+ input.adv.odtimpedance = popts->odt ? popts->odt : 60;
+ input.adv.tx_impedance = popts->phy_tx_impedance ?
+ popts->phy_tx_impedance : 28;
+ input.adv.atx_impedance = popts->phy_atx_impedance ?
+ popts->phy_atx_impedance : 30;
+
+ debug("Initializing input adv data structure\n");
+ phy_gen2_init_input(&input);
+
+ debug("Initializing message block\n");
+ ret = phy_gen2_msg_init(&msg_1d, &msg_2d, &input);
+ if (ret != 0) {
+ ERROR("Init msg failed (error code %d)\n", ret);
+ return ret;
+ }
+
+ ret = c_init_phy_config(priv->phy, priv->ip_rev, &input, &msg_1d);
+ if (ret != 0) {
+ ERROR("Init PHY failed (error code %d)\n", ret);
+ return ret;
+ }
+#ifdef NXP_WARM_BOOT
+ debug("Warm boot flag value %0x\n", priv->warm_boot_flag);
+ if (priv->warm_boot_flag == DDR_WARM_BOOT) {
+ debug("Restoring the Phy training data\n");
+ // Restore the training data
+ ret = restore_phy_training_values(priv->phy,
+ PHY_TRAINING_REGS_ON_FLASH,
+ priv->num_ctlrs,
+ input.basic.train2d);
+ if (ret != 0) {
+ ERROR("Restoring of training data failed %d\n", ret);
+ return ret;
+ }
+ } else {
+#endif
+ /* Mapping IMG buffer firstly */
+ ret = mmap_add_dynamic_region(priv->phy_gen2_fw_img_buf,
+ priv->phy_gen2_fw_img_buf,
+ PHY_GEN2_MAX_IMAGE_SIZE,
+ MT_MEMORY | MT_RW | MT_SECURE);
+ if (ret != 0) {
+ ERROR("Failed to add dynamic memory region.\n");
+ return ret;
+ }
+
+ debug("Load 1D firmware\n");
+ ret = load_fw(priv->phy, &input, 0, &msg_1d,
+ sizeof(struct ddr4u1d), priv->phy_gen2_fw_img_buf,
+ priv->img_loadr, priv->warm_boot_flag);
+ if (ret != 0) {
+ ERROR("Loading firmware failed (error code %d)\n", ret);
+ return ret;
+ }
+
+ debug("Execute firmware\n");
+ ret = g_exec_fw(priv->phy, 0, &input);
+ if (ret != 0) {
+ ERROR("Execution FW failed (error code %d)\n", ret);
+ }
+
+#ifdef NXP_APPLY_MAX_CDD
+ soc_info = get_soc_info();
+ if (soc_info->svr_reg.bf.maj_ver == 2) {
+ tcfg0 = regs->timing_cfg[0];
+ tcfg4 = regs->timing_cfg[4];
+ rank = findrank(conf->cs_in_use);
+ get_cdd_val(priv->phy, rank, input.basic.frequency,
+ &tcfg0, &tcfg4);
+ regs->timing_cfg[0] = tcfg0;
+ regs->timing_cfg[4] = tcfg4;
+ }
+#endif
+
+ if ((ret == 0) && (input.basic.train2d != 0)) {
+ /* 2D training starts here */
+ debug("Load 2D firmware\n");
+ ret = load_fw(priv->phy, &input, 1, &msg_2d,
+ sizeof(struct ddr4u2d),
+ priv->phy_gen2_fw_img_buf,
+ priv->img_loadr,
+ priv->warm_boot_flag);
+ if (ret != 0) {
+ ERROR("Loading fw failed (err code %d)\n", ret);
+ } else {
+ debug("Execute 2D firmware\n");
+ ret = g_exec_fw(priv->phy, 1, &input);
+ if (ret != 0) {
+ ERROR("Execution FW failed (err %d)\n",
+ ret);
+ }
+ }
+ }
+#ifdef NXP_WARM_BOOT
+ if (priv->warm_boot_flag != DDR_WRM_BOOT_NT_SUPPORTED &&
+ ret == 0) {
+ debug("save the phy training data\n");
+ //Save training data TBD
+ ret = save_phy_training_values(priv->phy,
+ PHY_TRAINING_REGS_ON_FLASH,
+ priv->num_ctlrs,
+ input.basic.train2d);
+ if (ret != 0) {
+ ERROR("Saving training data failed.");
+ ERROR("Warm boot will fail. Error=%d.\n", ret);
+ }
+ }
+ } /* else */
+#endif
+
+ if (ret == 0) {
+ debug("Load PIE\n");
+ i_load_pie(priv->phy, &input, &msg_1d);
+
+ NOTICE("DDR4 %s with %d-rank %d-bit bus (x%d)\n",
+ input.basic.dimm_type == RDIMM ? "RDIMM" :
+ input.basic.dimm_type == LRDIMM ? "LRDIMM" :
+ "UDIMM",
+ dimm_param->n_ranks,
+ dimm_param->primary_sdram_width,
+ dimm_param->device_width);
+ }
+#ifdef DEBUG_DDR_INPUT_CONFIG
+ print_jason_format(&input, &msg_1d, &msg_2d);
+#endif
+
+ return ret;
+}
diff --git a/drivers/nxp/ddr/phy-gen2/phy.h b/drivers/nxp/ddr/phy-gen2/phy.h
new file mode 100644
index 0000000..15e80d1
--- /dev/null
+++ b/drivers/nxp/ddr/phy-gen2/phy.h
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2021 NXP
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#if !defined(PHY_H) && defined(NXP_WARM_BOOT)
+#define PHY_H
+
+#include <flash_info.h>
+
+/* To store sector size to be erase on flash*/
+#define PHY_ERASE_SIZE F_SECTOR_ERASE_SZ
+
+/*Structure to implement address-data map tuples to store PHY training values*/
+struct phy_training_values {
+ uint32_t addr;
+ uint16_t data;
+};
+/* Saves PHY Training Register values after cold reset
+ *@param[in] phy_ptr array to store addresses of PHYs
+ *@param[in] address_to_store address to save PHY training register values
+ *on flash
+ *@param[in] num_of_phy the number of PHY for which training values are
+ *to be saved
+ *@param[in] train2d flag to store whether 2D training registers are to
+ *be saved or not
+ *
+ *PHY training values will be stored on flash at contigous memory in the order:
+ *1D training registers, 2D training registers
+ *for each PHY
+ *
+ *if train2d is false saving 2D training registers will be skipped
+ */
+int save_phy_training_values(uint16_t **phy_ptr, uint32_t address_to_store,
+ uint32_t num_of_phy, int train2d);
+
+/*Restores PHY Training Register values after warm reset
+ *@param[in] phy_ptr array to store addresses of PHYs
+ *@param[in] address_to_store address to retrieve PHY training register
+ *values from flash
+ *@param[in] num_of_phy the number of PHY for which training values are
+ *to be restored
+ *@param[in] train2d flag to store whether 2D training registers are
+ *to be restored or not
+ *
+ *if train2d is false saving 2D training registers will be skipped
+ */
+
+int restore_phy_training_values(uint16_t **phy_ptr, uint32_t address_to_restore,
+ uint32_t num_of_phy, int train2d);
+
+/*
+ * Address data tuples to store the PHY 1D
+ */
+
+struct phy_training_values training_1D_values[] = {
+ {0x200B2, 0}, {0x200CB, 0}, {0x10043, 0}, {0x11043, 0},
+ {0x12043, 0}, {0x13043, 0}, {0x14043, 0}, {0x15043, 0},
+ {0x16043, 0}, {0x17043, 0}, {0x18043, 0}, {0x10143, 0},
+ {0x11143, 0}, {0x12143, 0}, {0x13143, 0}, {0x14143, 0},
+ {0x15143, 0}, {0x16143, 0}, {0x17143, 0}, {0x18143, 0},
+ {0x10080, 0}, {0x11080, 0}, {0x12080, 0}, {0x13080, 0},
+ {0x14080, 0}, {0x15080, 0}, {0x16080, 0}, {0x17080, 0},
+ {0x18080, 0}, {0x10180, 0}, {0x11180, 0}, {0x12180, 0},
+ {0x13180, 0}, {0x14180, 0}, {0x15180, 0}, {0x16180, 0},
+ {0x17180, 0}, {0x18180, 0}, {0x10081, 0}, {0x11081, 0},
+ {0x12081, 0}, {0x13081, 0}, {0x14081, 0}, {0x15081, 0},
+ {0x16081, 0}, {0x17081, 0}, {0x18081, 0}, {0x10181, 0},
+ {0x11181, 0}, {0x12181, 0}, {0x13181, 0}, {0x14181, 0},
+ {0x15181, 0}, {0x16181, 0}, {0x17181, 0}, {0x18181, 0},
+ {0x10082, 0}, {0x11082, 0}, {0x12082, 0}, {0x13082, 0},
+ {0x14082, 0}, {0x15082, 0}, {0x16082, 0}, {0x17082, 0},
+ {0x18082, 0}, {0x10182, 0}, {0x11182, 0}, {0x12182, 0},
+ {0x13182, 0}, {0x14182, 0}, {0x15182, 0}, {0x16182, 0},
+ {0x17182, 0}, {0x18182, 0}, {0x10083, 0}, {0x11083, 0},
+ {0x12083, 0}, {0x13083, 0}, {0x14083, 0}, {0x15083, 0},
+ {0x16083, 0}, {0x17083, 0}, {0x18083, 0}, {0x10183, 0},
+ {0x11183, 0}, {0x12183, 0}, {0x13183, 0}, {0x14183, 0},
+ {0x15183, 0}, {0x16183, 0}, {0x17183, 0}, {0x18183, 0},
+ {0x100D0, 0}, {0x110D0, 0}, {0x120D0, 0}, {0x130D0, 0},
+ {0x140D0, 0}, {0x150D0, 0}, {0x160D0, 0}, {0x170D0, 0},
+ {0x180D0, 0}, {0x101D0, 0}, {0x111D0, 0}, {0x121D0, 0},
+ {0x131D0, 0}, {0x141D0, 0}, {0x151D0, 0}, {0x161D0, 0},
+ {0x171D0, 0}, {0x181D0, 0}, {0x100D1, 0}, {0x110D1, 0},
+ {0x120D1, 0}, {0x130D1, 0}, {0x140D1, 0}, {0x150D1, 0},
+ {0x160D1, 0}, {0x170D1, 0}, {0x180D1, 0}, {0x101D1, 0},
+ {0x111D1, 0}, {0x121D1, 0}, {0x131D1, 0}, {0x141D1, 0},
+ {0x151D1, 0}, {0x161D1, 0}, {0x171D1, 0}, {0x181D1, 0},
+ {0x100D2, 0}, {0x110D2, 0}, {0x120D2, 0}, {0x130D2, 0},
+ {0x140D2, 0}, {0x150D2, 0}, {0x160D2, 0}, {0x170D2, 0},
+ {0x180D2, 0}, {0x101D2, 0}, {0x111D2, 0}, {0x121D2, 0},
+ {0x131D2, 0}, {0x141D2, 0}, {0x151D2, 0}, {0x161D2, 0},
+ {0x171D2, 0}, {0x181D2, 0}, {0x100D3, 0}, {0x110D3, 0},
+ {0x120D3, 0}, {0x130D3, 0}, {0x140D3, 0}, {0x150D3, 0},
+ {0x160D3, 0}, {0x170D3, 0}, {0x180D3, 0}, {0x101D3, 0},
+ {0x111D3, 0}, {0x121D3, 0}, {0x131D3, 0}, {0x141D3, 0},
+ {0x151D3, 0}, {0x161D3, 0}, {0x171D3, 0}, {0x181D3, 0},
+ {0x10068, 0}, {0x11068, 0}, {0x12068, 0}, {0x13068, 0},
+ {0x14068, 0}, {0x15068, 0}, {0x16068, 0}, {0x17068, 0},
+ {0x18068, 0}, {0x10168, 0}, {0x11168, 0}, {0x12168, 0},
+ {0x13168, 0}, {0x14168, 0}, {0x15168, 0}, {0x16168, 0},
+ {0x17168, 0}, {0x18168, 0}, {0x10268, 0}, {0x11268, 0},
+ {0x12268, 0}, {0x13268, 0}, {0x14268, 0}, {0x15268, 0},
+ {0x16268, 0}, {0x17268, 0}, {0x18268, 0}, {0x10368, 0},
+ {0x11368, 0}, {0x12368, 0}, {0x13368, 0}, {0x14368, 0},
+ {0x15368, 0}, {0x16368, 0}, {0x17368, 0}, {0x18368, 0},
+ {0x10468, 0}, {0x11468, 0}, {0x12468, 0}, {0x13468, 0},
+ {0x14468, 0}, {0x15468, 0}, {0x16468, 0}, {0x17468, 0},
+ {0x18468, 0}, {0x10568, 0}, {0x11568, 0}, {0x12568, 0},
+ {0x13568, 0}, {0x14568, 0}, {0x15568, 0}, {0x16568, 0},
+ {0x17568, 0}, {0x18568, 0}, {0x10668, 0}, {0x11668, 0},
+ {0x12668, 0}, {0x13668, 0}, {0x14668, 0}, {0x15668, 0},
+ {0x16668, 0}, {0x17668, 0}, {0x18668, 0}, {0x10768, 0},
+ {0x11768, 0}, {0x12768, 0}, {0x13768, 0}, {0x14768, 0},
+ {0x15768, 0}, {0x16768, 0}, {0x17768, 0}, {0x18768, 0},
+ {0x10868, 0}, {0x11868, 0}, {0x12868, 0}, {0x13868, 0},
+ {0x14868, 0}, {0x15868, 0}, {0x16868, 0}, {0x17868, 0},
+ {0x18868, 0}, {0x10069, 0}, {0x11069, 0}, {0x12069, 0},
+ {0x13069, 0}, {0x14069, 0}, {0x15069, 0}, {0x16069, 0},
+ {0x17069, 0}, {0x18069, 0}, {0x10169, 0}, {0x11169, 0},
+ {0x12169, 0}, {0x13169, 0}, {0x14169, 0}, {0x15169, 0},
+ {0x16169, 0}, {0x17169, 0}, {0x18169, 0}, {0x10269, 0},
+ {0x11269, 0}, {0x12269, 0}, {0x13269, 0}, {0x14269, 0},
+ {0x15269, 0}, {0x16269, 0}, {0x17269, 0}, {0x18269, 0},
+ {0x10369, 0}, {0x11369, 0}, {0x12369, 0}, {0x13369, 0},
+ {0x14369, 0}, {0x15369, 0}, {0x16369, 0}, {0x17369, 0},
+ {0x18369, 0}, {0x10469, 0}, {0x11469, 0}, {0x12469, 0},
+ {0x13469, 0}, {0x14469, 0}, {0x15469, 0}, {0x16469, 0},
+ {0x17469, 0}, {0x18469, 0}, {0x10569, 0}, {0x11569, 0},
+ {0x12569, 0}, {0x13569, 0}, {0x14569, 0}, {0x15569, 0},
+ {0x16569, 0}, {0x17569, 0}, {0x18569, 0}, {0x10669, 0},
+ {0x11669, 0}, {0x12669, 0}, {0x13669, 0}, {0x14669, 0},
+ {0x15669, 0}, {0x16669, 0}, {0x17669, 0}, {0x18669, 0},
+ {0x10769, 0}, {0x11769, 0}, {0x12769, 0}, {0x13769, 0},
+ {0x14769, 0}, {0x15769, 0}, {0x16769, 0}, {0x17769, 0},
+ {0x18769, 0}, {0x10869, 0}, {0x11869, 0}, {0x12869, 0},
+ {0x13869, 0}, {0x14869, 0}, {0x15869, 0}, {0x16869, 0},
+ {0x17869, 0}, {0x18869, 0}, {0x1006A, 0}, {0x1106A, 0},
+ {0x1206A, 0}, {0x1306A, 0}, {0x1406A, 0}, {0x1506A, 0},
+ {0x1606A, 0}, {0x1706A, 0}, {0x1806A, 0}, {0x1016A, 0},
+ {0x1116A, 0}, {0x1216A, 0}, {0x1316A, 0}, {0x1416A, 0},
+ {0x1516A, 0}, {0x1616A, 0}, {0x1716A, 0}, {0x1816A, 0},
+ {0x1026A, 0}, {0x1126A, 0}, {0x1226A, 0}, {0x1326A, 0},
+ {0x1426A, 0}, {0x1526A, 0}, {0x1626A, 0}, {0x1726A, 0},
+ {0x1826A, 0}, {0x1036A, 0}, {0x1136A, 0}, {0x1236A, 0},
+ {0x1336A, 0}, {0x1436A, 0}, {0x1536A, 0}, {0x1636A, 0},
+ {0x1736A, 0}, {0x1836A, 0}, {0x1046A, 0}, {0x1146A, 0},
+ {0x1246A, 0}, {0x1346A, 0}, {0x1446A, 0}, {0x1546A, 0},
+ {0x1646A, 0}, {0x1746A, 0}, {0x1846A, 0}, {0x1056A, 0},
+ {0x1156A, 0}, {0x1256A, 0}, {0x1356A, 0}, {0x1456A, 0},
+ {0x1556A, 0}, {0x1656A, 0}, {0x1756A, 0}, {0x1856A, 0},
+ {0x1066A, 0}, {0x1166A, 0}, {0x1266A, 0}, {0x1366A, 0},
+ {0x1466A, 0}, {0x1566A, 0}, {0x1666A, 0}, {0x1766A, 0},
+ {0x1866A, 0}, {0x1076A, 0}, {0x1176A, 0}, {0x1276A, 0},
+ {0x1376A, 0}, {0x1476A, 0}, {0x1576A, 0}, {0x1676A, 0},
+ {0x1776A, 0}, {0x1876A, 0}, {0x1086A, 0}, {0x1186A, 0},
+ {0x1286A, 0}, {0x1386A, 0}, {0x1486A, 0}, {0x1586A, 0},
+ {0x1686A, 0}, {0x1786A, 0}, {0x1886A, 0}, {0x1006B, 0},
+ {0x1106B, 0}, {0x1206B, 0}, {0x1306B, 0}, {0x1406B, 0},
+ {0x1506B, 0}, {0x1606B, 0}, {0x1706B, 0}, {0x1806B, 0},
+ {0x1016B, 0}, {0x1116B, 0}, {0x1216B, 0}, {0x1316B, 0},
+ {0x1416B, 0}, {0x1516B, 0}, {0x1616B, 0}, {0x1716B, 0},
+ {0x1816B, 0}, {0x1026B, 0}, {0x1126B, 0}, {0x1226B, 0},
+ {0x1326B, 0}, {0x1426B, 0}, {0x1526B, 0}, {0x1626B, 0},
+ {0x1726B, 0}, {0x1826B, 0}, {0x1036B, 0}, {0x1136B, 0},
+ {0x1236B, 0}, {0x1336B, 0}, {0x1436B, 0}, {0x1536B, 0},
+ {0x1636B, 0}, {0x1736B, 0}, {0x1836B, 0}, {0x1046B, 0},
+ {0x1146B, 0}, {0x1246B, 0}, {0x1346B, 0}, {0x1446B, 0},
+ {0x1546B, 0}, {0x1646B, 0}, {0x1746B, 0}, {0x1846B, 0},
+ {0x1056B, 0}, {0x1156B, 0}, {0x1256B, 0}, {0x1356B, 0},
+ {0x1456B, 0}, {0x1556B, 0}, {0x1656B, 0}, {0x1756B, 0},
+ {0x1856B, 0}, {0x1066B, 0}, {0x1166B, 0}, {0x1266B, 0},
+ {0x1366B, 0}, {0x1466B, 0}, {0x1566B, 0}, {0x1666B, 0},
+ {0x1766B, 0}, {0x1866B, 0}, {0x1076B, 0}, {0x1176B, 0},
+ {0x1276B, 0}, {0x1376B, 0}, {0x1476B, 0}, {0x1576B, 0},
+ {0x1676B, 0}, {0x1776B, 0}, {0x1876B, 0}, {0x1086B, 0},
+ {0x1186B, 0}, {0x1286B, 0}, {0x1386B, 0}, {0x1486B, 0},
+ {0x1586B, 0}, {0x1686B, 0}, {0x1786B, 0}, {0x1886B, 0},
+ {0x1008C, 0}, {0x1108C, 0}, {0x1208C, 0}, {0x1308C, 0},
+ {0x1408C, 0}, {0x1508C, 0}, {0x1608C, 0}, {0x1708C, 0},
+ {0x1808C, 0}, {0x1018C, 0}, {0x1118C, 0}, {0x1218C, 0},
+ {0x1318C, 0}, {0x1418C, 0}, {0x1518C, 0}, {0x1618C, 0},
+ {0x1718C, 0}, {0x1818C, 0}, {0x1008D, 0}, {0x1108D, 0},
+ {0x1208D, 0}, {0x1308D, 0}, {0x1408D, 0}, {0x1508D, 0},
+ {0x1608D, 0}, {0x1708D, 0}, {0x1808D, 0}, {0x1018D, 0},
+ {0x1118D, 0}, {0x1218D, 0}, {0x1318D, 0}, {0x1418D, 0},
+ {0x1518D, 0}, {0x1618D, 0}, {0x1718D, 0}, {0x1818D, 0},
+ {0x1008E, 0}, {0x1108E, 0}, {0x1208E, 0}, {0x1308E, 0},
+ {0x1408E, 0}, {0x1508E, 0}, {0x1608E, 0}, {0x1708E, 0},
+ {0x1808E, 0}, {0x1018E, 0}, {0x1118E, 0}, {0x1218E, 0},
+ {0x1318E, 0}, {0x1418E, 0}, {0x1518E, 0}, {0x1618E, 0},
+ {0x1718E, 0}, {0x1818E, 0}, {0x1008F, 0}, {0x1108F, 0},
+ {0x1208F, 0}, {0x1308F, 0}, {0x1408F, 0}, {0x1508F, 0},
+ {0x1608F, 0}, {0x1708F, 0}, {0x1808F, 0}, {0x1018F, 0},
+ {0x1118F, 0}, {0x1218F, 0}, {0x1318F, 0}, {0x1418F, 0},
+ {0x1518F, 0}, {0x1618F, 0}, {0x1718F, 0}, {0x1818F, 0},
+ {0x100C0, 0}, {0x110C0, 0}, {0x120C0, 0}, {0x130C0, 0},
+ {0x140C0, 0}, {0x150C0, 0}, {0x160C0, 0}, {0x170C0, 0},
+ {0x180C0, 0}, {0x101C0, 0}, {0x111C0, 0}, {0x121C0, 0},
+ {0x131C0, 0}, {0x141C0, 0}, {0x151C0, 0}, {0x161C0, 0},
+ {0x171C0, 0}, {0x181C0, 0}, {0x102C0, 0}, {0x112C0, 0},
+ {0x122C0, 0}, {0x132C0, 0}, {0x142C0, 0}, {0x152C0, 0},
+ {0x162C0, 0}, {0x172C0, 0}, {0x182C0, 0}, {0x103C0, 0},
+ {0x113C0, 0}, {0x123C0, 0}, {0x133C0, 0}, {0x143C0, 0},
+ {0x153C0, 0}, {0x163C0, 0}, {0x173C0, 0}, {0x183C0, 0},
+ {0x104C0, 0}, {0x114C0, 0}, {0x124C0, 0}, {0x134C0, 0},
+ {0x144C0, 0}, {0x154C0, 0}, {0x164C0, 0}, {0x174C0, 0},
+ {0x184C0, 0}, {0x105C0, 0}, {0x115C0, 0}, {0x125C0, 0},
+ {0x135C0, 0}, {0x145C0, 0}, {0x155C0, 0}, {0x165C0, 0},
+ {0x175C0, 0}, {0x185C0, 0}, {0x106C0, 0}, {0x116C0, 0},
+ {0x126C0, 0}, {0x136C0, 0}, {0x146C0, 0}, {0x156C0, 0},
+ {0x166C0, 0}, {0x176C0, 0}, {0x186C0, 0}, {0x107C0, 0},
+ {0x117C0, 0}, {0x127C0, 0}, {0x137C0, 0}, {0x147C0, 0},
+ {0x157C0, 0}, {0x167C0, 0}, {0x177C0, 0}, {0x187C0, 0},
+ {0x108C0, 0}, {0x118C0, 0}, {0x128C0, 0}, {0x138C0, 0},
+ {0x148C0, 0}, {0x158C0, 0}, {0x168C0, 0}, {0x178C0, 0},
+ {0x188C0, 0}, {0x100C1, 0}, {0x110C1, 0}, {0x120C1, 0},
+ {0x130C1, 0}, {0x140C1, 0}, {0x150C1, 0}, {0x160C1, 0},
+ {0x170C1, 0}, {0x180C1, 0}, {0x101C1, 0}, {0x111C1, 0},
+ {0x121C1, 0}, {0x131C1, 0}, {0x141C1, 0}, {0x151C1, 0},
+ {0x161C1, 0}, {0x171C1, 0}, {0x181C1, 0}, {0x102C1, 0},
+ {0x112C1, 0}, {0x122C1, 0}, {0x132C1, 0}, {0x142C1, 0},
+ {0x152C1, 0}, {0x162C1, 0}, {0x172C1, 0}, {0x182C1, 0},
+ {0x103C1, 0}, {0x113C1, 0}, {0x123C1, 0}, {0x133C1, 0},
+ {0x143C1, 0}, {0x153C1, 0}, {0x163C1, 0}, {0x173C1, 0},
+ {0x183C1, 0}, {0x104C1, 0}, {0x114C1, 0}, {0x124C1, 0},
+ {0x134C1, 0}, {0x144C1, 0}, {0x154C1, 0}, {0x164C1, 0},
+ {0x174C1, 0}, {0x184C1, 0}, {0x105C1, 0}, {0x115C1, 0},
+ {0x125C1, 0}, {0x135C1, 0}, {0x145C1, 0}, {0x155C1, 0},
+ {0x165C1, 0}, {0x175C1, 0}, {0x185C1, 0}, {0x106C1, 0},
+ {0x116C1, 0}, {0x126C1, 0}, {0x136C1, 0}, {0x146C1, 0},
+ {0x156C1, 0}, {0x166C1, 0}, {0x176C1, 0}, {0x186C1, 0},
+ {0x107C1, 0}, {0x117C1, 0}, {0x127C1, 0}, {0x137C1, 0},
+ {0x147C1, 0}, {0x157C1, 0}, {0x167C1, 0}, {0x177C1, 0},
+ {0x187C1, 0}, {0x108C1, 0}, {0x118C1, 0}, {0x128C1, 0},
+ {0x138C1, 0}, {0x148C1, 0}, {0x158C1, 0}, {0x168C1, 0},
+ {0x178C1, 0}, {0x188C1, 0}, {0x100C2, 0}, {0x110C2, 0},
+ {0x120C2, 0}, {0x130C2, 0}, {0x140C2, 0}, {0x150C2, 0},
+ {0x160C2, 0}, {0x170C2, 0}, {0x180C2, 0}, {0x101C2, 0},
+ {0x111C2, 0}, {0x121C2, 0}, {0x131C2, 0}, {0x141C2, 0},
+ {0x151C2, 0}, {0x161C2, 0}, {0x171C2, 0}, {0x181C2, 0},
+ {0x102C2, 0}, {0x112C2, 0}, {0x122C2, 0}, {0x132C2, 0},
+ {0x142C2, 0}, {0x152C2, 0}, {0x162C2, 0}, {0x172C2, 0},
+ {0x182C2, 0}, {0x103C2, 0}, {0x113C2, 0}, {0x123C2, 0},
+ {0x133C2, 0}, {0x143C2, 0}, {0x153C2, 0}, {0x163C2, 0},
+ {0x173C2, 0}, {0x183C2, 0}, {0x104C2, 0}, {0x114C2, 0},
+ {0x124C2, 0}, {0x134C2, 0}, {0x144C2, 0}, {0x154C2, 0},
+ {0x164C2, 0}, {0x174C2, 0}, {0x184C2, 0}, {0x105C2, 0},
+ {0x115C2, 0}, {0x125C2, 0}, {0x135C2, 0}, {0x145C2, 0},
+ {0x155C2, 0}, {0x165C2, 0}, {0x175C2, 0}, {0x185C2, 0},
+ {0x106C2, 0}, {0x116C2, 0}, {0x126C2, 0}, {0x136C2, 0},
+ {0x146C2, 0}, {0x156C2, 0}, {0x166C2, 0}, {0x176C2, 0},
+ {0x186C2, 0}, {0x107C2, 0}, {0x117C2, 0}, {0x127C2, 0},
+ {0x137C2, 0}, {0x147C2, 0}, {0x157C2, 0}, {0x167C2, 0},
+ {0x177C2, 0}, {0x187C2, 0}, {0x108C2, 0}, {0x118C2, 0},
+ {0x128C2, 0}, {0x138C2, 0}, {0x148C2, 0}, {0x158C2, 0},
+ {0x168C2, 0}, {0x178C2, 0}, {0x188C2, 0}, {0x100C3, 0},
+ {0x110C3, 0}, {0x120C3, 0}, {0x130C3, 0}, {0x140C3, 0},
+ {0x150C3, 0}, {0x160C3, 0}, {0x170C3, 0}, {0x180C3, 0},
+ {0x101C3, 0}, {0x111C3, 0}, {0x121C3, 0}, {0x131C3, 0},
+ {0x141C3, 0}, {0x151C3, 0}, {0x161C3, 0}, {0x171C3, 0},
+ {0x181C3, 0}, {0x102C3, 0}, {0x112C3, 0}, {0x122C3, 0},
+ {0x132C3, 0}, {0x142C3, 0}, {0x152C3, 0}, {0x162C3, 0},
+ {0x172C3, 0}, {0x182C3, 0}, {0x103C3, 0}, {0x113C3, 0},
+ {0x123C3, 0}, {0x133C3, 0}, {0x143C3, 0}, {0x153C3, 0},
+ {0x163C3, 0}, {0x173C3, 0}, {0x183C3, 0}, {0x104C3, 0},
+ {0x114C3, 0}, {0x124C3, 0}, {0x134C3, 0}, {0x144C3, 0},
+ {0x154C3, 0}, {0x164C3, 0}, {0x174C3, 0}, {0x184C3, 0},
+ {0x105C3, 0}, {0x115C3, 0}, {0x125C3, 0}, {0x135C3, 0},
+ {0x145C3, 0}, {0x155C3, 0}, {0x165C3, 0}, {0x175C3, 0},
+ {0x185C3, 0}, {0x106C3, 0}, {0x116C3, 0}, {0x126C3, 0},
+ {0x136C3, 0}, {0x146C3, 0}, {0x156C3, 0}, {0x166C3, 0},
+ {0x176C3, 0}, {0x186C3, 0}, {0x107C3, 0}, {0x117C3, 0},
+ {0x127C3, 0}, {0x137C3, 0}, {0x147C3, 0}, {0x157C3, 0},
+ {0x167C3, 0}, {0x177C3, 0}, {0x187C3, 0}, {0x108C3, 0},
+ {0x118C3, 0}, {0x128C3, 0}, {0x138C3, 0}, {0x148C3, 0},
+ {0x158C3, 0}, {0x168C3, 0}, {0x178C3, 0}, {0x188C3, 0},
+ {0x10020, 0}, {0x11020, 0}, {0x12020, 0}, {0x13020, 0},
+ {0x14020, 0}, {0x15020, 0}, {0x16020, 0}, {0x17020, 0},
+ {0x18020, 0}, {0x2007D, 0}, {0x20077, 0}
+};
+
+/*
+ *Array to store the PHY 2D Training register addresses
+ */
+struct phy_training_values training_2D_values[] = {
+ {0x1008C, 0}, {0x1108C, 0}, {0x1208C, 0}, {0x1308C, 0},
+ {0x1408C, 0}, {0x1508C, 0}, {0x1608C, 0}, {0x1708C, 0},
+ {0x1808C, 0}, {0x1018C, 0}, {0x1118C, 0}, {0x1218C, 0},
+ {0x1318C, 0}, {0x1418C, 0}, {0x1518C, 0}, {0x1618C, 0},
+ {0x1718C, 0}, {0x1818C, 0}, {0x10040, 0}, {0x11040, 0},
+ {0x12040, 0}, {0x13040, 0}, {0x14040, 0}, {0x15040, 0},
+ {0x16040, 0}, {0x17040, 0}, {0x18040, 0}, {0x10140, 0},
+ {0x11140, 0}, {0x12140, 0}, {0x13140, 0}, {0x14140, 0},
+ {0x15140, 0}, {0x16140, 0}, {0x17140, 0}, {0x18140, 0},
+ {0x10240, 0}, {0x11240, 0}, {0x12240, 0}, {0x13240, 0},
+ {0x14240, 0}, {0x15240, 0}, {0x16240, 0}, {0x17240, 0},
+ {0x18240, 0}, {0x10340, 0}, {0x11340, 0}, {0x12340, 0},
+ {0x13340, 0}, {0x14340, 0}, {0x15340, 0}, {0x16340, 0},
+ {0x17340, 0}, {0x18340, 0}, {0x10440, 0}, {0x11440, 0},
+ {0x12440, 0}, {0x13440, 0}, {0x14440, 0}, {0x15440, 0},
+ {0x16440, 0}, {0x17440, 0}, {0x18440, 0}, {0x10540, 0},
+ {0x11540, 0}, {0x12540, 0}, {0x13540, 0}, {0x14540, 0},
+ {0x15540, 0}, {0x16540, 0}, {0x17540, 0}, {0x18540, 0},
+ {0x10640, 0}, {0x11640, 0}, {0x12640, 0}, {0x13640, 0},
+ {0x14640, 0}, {0x15640, 0}, {0x16640, 0}, {0x17640, 0},
+ {0x18640, 0}, {0x10740, 0}, {0x11740, 0}, {0x12740, 0},
+ {0x13740, 0}, {0x14740, 0}, {0x15740, 0}, {0x16740, 0},
+ {0x17740, 0}, {0x18740, 0}, {0x10840, 0}, {0x11840, 0},
+ {0x12840, 0}, {0x13840, 0}, {0x14840, 0}, {0x15840, 0},
+ {0x16840, 0}, {0x17840, 0}, {0x18840, 0}, {0x10030, 0},
+ {0x11030, 0}, {0x12030, 0}, {0x13030, 0}, {0x14030, 0},
+ {0x15030, 0}, {0x16030, 0}, {0x17030, 0}, {0x18030, 0},
+ {0x10130, 0}, {0x11130, 0}, {0x12130, 0}, {0x13130, 0},
+ {0x14130, 0}, {0x15130, 0}, {0x16130, 0}, {0x17130, 0},
+ {0x18130, 0}, {0x10230, 0}, {0x11230, 0}, {0x12230, 0},
+ {0x13230, 0}, {0x14230, 0}, {0x15230, 0}, {0x16230, 0},
+ {0x17230, 0}, {0x18230, 0}, {0x10330, 0}, {0x11330, 0},
+ {0x12330, 0}, {0x13330, 0}, {0x14330, 0}, {0x15330, 0},
+ {0x16330, 0}, {0x17330, 0}, {0x18330, 0}, {0x10430, 0},
+ {0x11430, 0}, {0x12430, 0}, {0x13430, 0}, {0x14430, 0},
+ {0x15430, 0}, {0x16430, 0}, {0x17430, 0}, {0x18430, 0},
+ {0x10530, 0}, {0x11530, 0}, {0x12530, 0}, {0x13530, 0},
+ {0x14530, 0}, {0x15530, 0}, {0x16530, 0}, {0x17530, 0},
+ {0x18530, 0}, {0x10630, 0}, {0x11630, 0}, {0x12630, 0},
+ {0x13630, 0}, {0x14630, 0}, {0x15630, 0}, {0x16630, 0},
+ {0x17630, 0}, {0x18630, 0}, {0x10730, 0}, {0x11730, 0},
+ {0x12730, 0}, {0x13730, 0}, {0x14730, 0}, {0x15730, 0},
+ {0x16730, 0}, {0x17730, 0}, {0x18730, 0}, {0x10830, 0},
+ {0x11830, 0}, {0x12830, 0}, {0x13830, 0}, {0x14830, 0},
+ {0x15830, 0}, {0x16830, 0}, {0x17830, 0}, {0x18830, 0}
+};
+
+#endif
diff --git a/drivers/nxp/ddr/phy-gen2/pie.h b/drivers/nxp/ddr/phy-gen2/pie.h
new file mode 100644
index 0000000..b89066a
--- /dev/null
+++ b/drivers/nxp/ddr/phy-gen2/pie.h
@@ -0,0 +1,632 @@
+/*
+ * Copyright 2021 NXP
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PIE_H
+#define PIE_H
+
+struct pie {
+ uint32_t addr;
+ uint16_t data;
+};
+
+static const struct pie pie_udimm[] = {
+ {0x90000, 0x10},
+ {0x90001, 0x400},
+ {0x90002, 0x10e},
+ {0x90003, 0x0},
+ {0x90004, 0x0},
+ {0x90005, 0x8},
+ {0x90029, 0xb},
+ {0x9002a, 0x480},
+ {0x9002b, 0x109},
+ {0x9002c, 0x8},
+ {0x9002d, 0x448},
+ {0x9002e, 0x139},
+ {0x9002f, 0x8},
+ {0x90030, 0x478},
+ {0x90031, 0x109},
+ {0x90032, 0x2},
+ {0x90033, 0x10},
+ {0x90034, 0x139},
+ {0x90035, 0xb},
+ {0x90036, 0x7c0},
+ {0x90037, 0x139},
+ {0x90038, 0x44},
+ {0x90039, 0x633},
+ {0x9003a, 0x159},
+ {0x9003b, 0x14f},
+ {0x9003c, 0x630},
+ {0x9003d, 0x159},
+ {0x9003e, 0x47},
+ {0x9003f, 0x633},
+ {0x90040, 0x149},
+ {0x90041, 0x4f},
+ {0x90042, 0x633},
+ {0x90043, 0x179},
+ {0x90044, 0x8},
+ {0x90045, 0xe0},
+ {0x90046, 0x109},
+ {0x90047, 0x0},
+ {0x90048, 0x7c8},
+ {0x90049, 0x109},
+ {0x9004a, 0x0},
+ {0x9004b, 0x1},
+ {0x9004c, 0x8},
+ {0x9004d, 0x0},
+ {0x9004e, 0x45a},
+ {0x9004f, 0x9},
+ {0x90050, 0x0},
+ {0x90051, 0x448},
+ {0x90052, 0x109},
+ {0x90053, 0x40},
+ {0x90054, 0x633},
+ {0x90055, 0x179},
+ {0x90056, 0x1},
+ {0x90057, 0x618},
+ {0x90058, 0x109},
+ {0x90059, 0x40c0},
+ {0x9005a, 0x633},
+ {0x9005b, 0x149},
+ {0x9005c, 0x8},
+ {0x9005d, 0x4},
+ {0x9005e, 0x48},
+ {0x9005f, 0x4040},
+ {0x90060, 0x633},
+ {0x90061, 0x149},
+ {0x90062, 0x0},
+ {0x90063, 0x4},
+ {0x90064, 0x48},
+ {0x90065, 0x40},
+ {0x90066, 0x633},
+ {0x90067, 0x149},
+ {0x90068, 0x10},
+ {0x90069, 0x4},
+ {0x9006a, 0x18},
+ {0x9006b, 0x0},
+ {0x9006c, 0x4},
+ {0x9006d, 0x78},
+ {0x9006e, 0x549},
+ {0x9006f, 0x633},
+ {0x90070, 0x159},
+ {0x90071, 0xd49},
+ {0x90072, 0x633},
+ {0x90073, 0x159},
+ {0x90074, 0x94a},
+ {0x90075, 0x633},
+ {0x90076, 0x159},
+ {0x90077, 0x441},
+ {0x90078, 0x633},
+ {0x90079, 0x149},
+ {0x9007a, 0x42},
+ {0x9007b, 0x633},
+ {0x9007c, 0x149},
+ {0x9007d, 0x1},
+ {0x9007e, 0x633},
+ {0x9007f, 0x149},
+ {0x90080, 0x0},
+ {0x90081, 0xe0},
+ {0x90082, 0x109},
+ {0x90083, 0xa},
+ {0x90084, 0x10},
+ {0x90085, 0x109},
+ {0x90086, 0x9},
+ {0x90087, 0x3c0},
+ {0x90088, 0x149},
+ {0x90089, 0x9},
+ {0x9008a, 0x3c0},
+ {0x9008b, 0x159},
+ {0x9008c, 0x18},
+ {0x9008d, 0x10},
+ {0x9008e, 0x109},
+ {0x9008f, 0x0},
+ {0x90090, 0x3c0},
+ {0x90091, 0x109},
+ {0x90092, 0x18},
+ {0x90093, 0x4},
+ {0x90094, 0x48},
+ {0x90095, 0x18},
+ {0x90096, 0x4},
+ {0x90097, 0x58},
+ {0x90098, 0xb},
+ {0x90099, 0x10},
+ {0x9009a, 0x109},
+ {0x9009b, 0x1},
+ {0x9009c, 0x10},
+ {0x9009d, 0x109},
+ {0x9009e, 0x5},
+ {0x9009f, 0x7c0},
+ {0x900a0, 0x109},
+ {0x900a1, 0x0},
+ {0x900a2, 0x8140},
+ {0x900a3, 0x10c},
+ {0x900a4, 0x10},
+ {0x900a5, 0x8138},
+ {0x900a6, 0x10c},
+ {0x900a7, 0x8},
+ {0x900a8, 0x7c8},
+ {0x900a9, 0x101},
+ {0x900aa, 0x8},
+ {0x900ab, 0x448},
+ {0x900ac, 0x109},
+ {0x900ad, 0xf},
+ {0x900ae, 0x7c0},
+ {0x900af, 0x109},
+ {0x900b0, 0x47},
+ {0x900b1, 0x630},
+ {0x900b2, 0x109},
+ {0x900b3, 0x8},
+ {0x900b4, 0x618},
+ {0x900b5, 0x109},
+ {0x900b6, 0x8},
+ {0x900b7, 0xe0},
+ {0x900b8, 0x109},
+ {0x900b9, 0x0},
+ {0x900ba, 0x7c8},
+ {0x900bb, 0x109},
+ {0x900bc, 0x8},
+ {0x900bd, 0x8140},
+ {0x900be, 0x10c},
+ {0x900bf, 0x0},
+ {0x900c0, 0x478},
+ {0x900c1, 0x109},
+ {0x900c2, 0x0},
+ {0x900c3, 0x1},
+ {0x900c4, 0x8},
+ {0x900c5, 0x8},
+ {0x900c6, 0x4},
+ {0x900c7, 0x8},
+ {0x900c8, 0x8},
+ {0x900c9, 0x7c8},
+ {0x900ca, 0x101},
+ {0x90006, 0x0},
+ {0x90007, 0x0},
+ {0x90008, 0x8},
+ {0x90009, 0x0},
+ {0x9000a, 0x0},
+ {0x9000b, 0x0},
+ {0xd00e7, 0x400},
+ {0x90017, 0x0},
+ {0x90026, 0x2b},
+};
+
+static const struct pie pie_rdimm[] = {
+ {0x90000, 0x10},
+ {0x90001, 0x400},
+ {0x90002, 0x10e},
+ {0x90003, 0x0},
+ {0x90004, 0x0},
+ {0x90005, 0x8},
+ {0x40000, 0x10},
+ {0x40020, 0x0},
+ {0x40040, 0x0},
+ {0x40060, 0x0},
+ {0x40001, 0x70a},
+ {0x40021, 0x7005},
+ {0x40041, 0x0},
+ {0x40061, 0x2001},
+ {0x40002, 0x4010},
+ {0x40022, 0x0},
+ {0x40042, 0x0},
+ {0x40062, 0x0},
+ {0x90029, 0x10},
+ {0x9002a, 0x400},
+ {0x9002b, 0x16e},
+ {0x9002c, 0x8},
+ {0x9002d, 0x370},
+ {0x9002e, 0x169},
+ {0x9002f, 0x8},
+ {0x90030, 0x7aa},
+ {0x90031, 0x6a},
+ {0x90032, 0x10},
+ {0x90033, 0x7b2},
+ {0x90034, 0x6a},
+ {0x90035, 0x0},
+ {0x90036, 0x48a},
+ {0x90037, 0x6a},
+ {0x90038, 0x9},
+ {0x90039, 0x480},
+ {0x9003a, 0x16a},
+ {0x9003b, 0x4},
+ {0x9003c, 0x790},
+ {0x9003d, 0x16a},
+ {0x9003e, 0xc},
+ {0x9003f, 0x408},
+ {0x90040, 0x169},
+ {0x90041, 0xa},
+ {0x90042, 0x0},
+ {0x90043, 0x68},
+ {0x90044, 0x0},
+ {0x90045, 0x408},
+ {0x90046, 0x169},
+ {0x90047, 0x1},
+ {0x90048, 0x480},
+ {0x90049, 0x16a},
+ {0x9004a, 0xb},
+ {0x9004b, 0x480},
+ {0x9004c, 0x109},
+ {0x9004d, 0x8},
+ {0x9004e, 0x448},
+ {0x9004f, 0x139},
+ {0x90050, 0x78},
+ {0x90051, 0x8},
+ {0x90052, 0x139},
+ {0x90053, 0x2},
+ {0x90054, 0x10},
+ {0x90055, 0x139},
+ {0x90056, 0xb},
+ {0x90057, 0x7c0},
+ {0x90058, 0x139},
+ {0x90059, 0x44},
+ {0x9005a, 0x633},
+ {0x9005b, 0x159},
+ {0x9005c, 0x14f},
+ {0x9005d, 0x630},
+ {0x9005e, 0x159},
+ {0x9005f, 0x47},
+ {0x90060, 0x633},
+ {0x90061, 0x149},
+ {0x90062, 0x4f},
+ {0x90063, 0x633},
+ {0x90064, 0x179},
+ {0x90065, 0x8},
+ {0x90066, 0xe0},
+ {0x90067, 0x109},
+ {0x90068, 0x0},
+ {0x90069, 0x7c8},
+ {0x9006a, 0x109},
+ {0x9006b, 0x0},
+ {0x9006c, 0x1},
+ {0x9006d, 0x8},
+ {0x9006e, 0x0},
+ {0x9006f, 0x45a},
+ {0x90070, 0x9},
+ {0x90071, 0x0},
+ {0x90072, 0x448},
+ {0x90073, 0x109},
+ {0x90074, 0x40},
+ {0x90075, 0x633},
+ {0x90076, 0x179},
+ {0x90077, 0x1},
+ {0x90078, 0x618},
+ {0x90079, 0x109},
+ {0x9007a, 0x40c0},
+ {0x9007b, 0x633},
+ {0x9007c, 0x149},
+ {0x9007d, 0x8},
+ {0x9007e, 0x4},
+ {0x9007f, 0x48},
+ {0x90080, 0x4040},
+ {0x90081, 0x633},
+ {0x90082, 0x149},
+ {0x90083, 0x0},
+ {0x90084, 0x4},
+ {0x90085, 0x48},
+ {0x90086, 0x40},
+ {0x90087, 0x633},
+ {0x90088, 0x149},
+ {0x90089, 0x10},
+ {0x9008a, 0x4},
+ {0x9008b, 0x18},
+ {0x9008c, 0x0},
+ {0x9008d, 0x4},
+ {0x9008e, 0x78},
+ {0x9008f, 0x549},
+ {0x90090, 0x633},
+ {0x90091, 0x159},
+ {0x90092, 0xd49},
+ {0x90093, 0x633},
+ {0x90094, 0x159},
+ {0x90095, 0x94a},
+ {0x90096, 0x633},
+ {0x90097, 0x159},
+ {0x90098, 0x441},
+ {0x90099, 0x633},
+ {0x9009a, 0x149},
+ {0x9009b, 0x42},
+ {0x9009c, 0x633},
+ {0x9009d, 0x149},
+ {0x9009e, 0x1},
+ {0x9009f, 0x633},
+ {0x900a0, 0x149},
+ {0x900a1, 0x0},
+ {0x900a2, 0xe0},
+ {0x900a3, 0x109},
+ {0x900a4, 0xa},
+ {0x900a5, 0x10},
+ {0x900a6, 0x109},
+ {0x900a7, 0x9},
+ {0x900a8, 0x3c0},
+ {0x900a9, 0x149},
+ {0x900aa, 0x9},
+ {0x900ab, 0x3c0},
+ {0x900ac, 0x159},
+ {0x900ad, 0x18},
+ {0x900ae, 0x10},
+ {0x900af, 0x109},
+ {0x900b0, 0x0},
+ {0x900b1, 0x3c0},
+ {0x900b2, 0x109},
+ {0x900b3, 0x18},
+ {0x900b4, 0x4},
+ {0x900b5, 0x48},
+ {0x900b6, 0x18},
+ {0x900b7, 0x4},
+ {0x900b8, 0x58},
+ {0x900b9, 0xb},
+ {0x900ba, 0x10},
+ {0x900bb, 0x109},
+ {0x900bc, 0x1},
+ {0x900bd, 0x10},
+ {0x900be, 0x109},
+ {0x900bf, 0x5},
+ {0x900c0, 0x7c0},
+ {0x900c1, 0x109},
+ {0x900c2, 0x3},
+ {0x900c3, 0x370},
+ {0x900c4, 0x169},
+ {0x900c5, 0x3},
+ {0x900c6, 0x8},
+ {0x900c7, 0x139},
+ {0x900c8, 0x0},
+ {0x900c9, 0x400},
+ {0x900ca, 0x16e},
+ {0x900cb, 0x8},
+ {0x900cc, 0x478},
+ {0x900cd, 0x109},
+ {0x900ce, 0x0},
+ {0x900cf, 0x8140},
+ {0x900d0, 0x10c},
+ {0x900d1, 0x10},
+ {0x900d2, 0x8138},
+ {0x900d3, 0x10c},
+ {0x900d4, 0x8},
+ {0x900d5, 0x7c8},
+ {0x900d6, 0x101},
+ {0x900d7, 0x7a},
+ {0x900d8, 0x8},
+ {0x900d9, 0x109},
+ {0x900da, 0x8},
+ {0x900db, 0x448},
+ {0x900dc, 0x109},
+ {0x900dd, 0xf},
+ {0x900de, 0x7c0},
+ {0x900df, 0x109},
+ {0x900e0, 0x47},
+ {0x900e1, 0x630},
+ {0x900e2, 0x109},
+ {0x900e3, 0x8},
+ {0x900e4, 0x618},
+ {0x900e5, 0x109},
+ {0x900e6, 0x8},
+ {0x900e7, 0xe0},
+ {0x900e8, 0x109},
+ {0x900e9, 0x0},
+ {0x900ea, 0x8},
+ {0x900eb, 0x109},
+ {0x900ec, 0x0},
+ {0x900ed, 0x7c8},
+ {0x900ee, 0x109},
+ {0x900ef, 0x8},
+ {0x900f0, 0x8140},
+ {0x900f1, 0x10c},
+ {0x900f2, 0x0},
+ {0x900f3, 0x478},
+ {0x900f4, 0x109},
+ {0x900f5, 0x0},
+ {0x900f6, 0x1},
+ {0x900f7, 0x8},
+ {0x900f8, 0x8},
+ {0x900f9, 0x4},
+ {0x900fa, 0x8},
+ {0x900fb, 0x8},
+ {0x900fc, 0x7c8},
+ {0x900fd, 0x101},
+ {0x90006, 0x0},
+ {0x90007, 0x0},
+ {0x90008, 0x8},
+ {0x90009, 0x0},
+ {0x9000a, 0x0},
+ {0x9000b, 0x0},
+ {0xd00e7, 0x400},
+ {0x90017, 0x0},
+ {0x90026, 0x3a},
+};
+
+static const struct pie pie_lrdimm[] = {
+ {0x90000, 0x10},
+ {0x90001, 0x400},
+ {0x90002, 0x10e},
+ {0x90003, 0x0},
+ {0x90004, 0x0},
+ {0x90005, 0x8},
+ {0x90029, 0xb},
+ {0x9002a, 0x480},
+ {0x9002b, 0x109},
+ {0x9002c, 0x8},
+ {0x9002d, 0x448},
+ {0x9002e, 0x139},
+ {0x9002f, 0x78},
+ {0x90030, 0x8},
+ {0x90031, 0x139},
+ {0x90032, 0x2},
+ {0x90033, 0x10},
+ {0x90034, 0x139},
+ {0x90035, 0xb},
+ {0x90036, 0x7c0},
+ {0x90037, 0x139},
+ {0x90038, 0x44},
+ {0x90039, 0x633},
+ {0x9003a, 0x159},
+ {0x9003b, 0x14f},
+ {0x9003c, 0x630},
+ {0x9003d, 0x159},
+ {0x9003e, 0x47},
+ {0x9003f, 0x633},
+ {0x90040, 0x149},
+ {0x90041, 0x4f},
+ {0x90042, 0x633},
+ {0x90043, 0x179},
+ {0x90044, 0x8},
+ {0x90045, 0xe0},
+ {0x90046, 0x109},
+ {0x90047, 0x0},
+ {0x90048, 0x7c8},
+ {0x90049, 0x109},
+ {0x9004a, 0x0},
+ {0x9004b, 0x1},
+ {0x9004c, 0x8},
+ {0x9004d, 0x0},
+ {0x9004e, 0x45a},
+ {0x9004f, 0x9},
+ {0x90050, 0x0},
+ {0x90051, 0x448},
+ {0x90052, 0x109},
+ {0x90053, 0x40},
+ {0x90054, 0x633},
+ {0x90055, 0x179},
+ {0x90056, 0x1},
+ {0x90057, 0x618},
+ {0x90058, 0x109},
+ {0x90059, 0x40c0},
+ {0x9005a, 0x633},
+ {0x9005b, 0x149},
+ {0x9005c, 0x8},
+ {0x9005d, 0x4},
+ {0x9005e, 0x48},
+ {0x9005f, 0x4040},
+ {0x90060, 0x633},
+ {0x90061, 0x149},
+ {0x90062, 0x0},
+ {0x90063, 0x4},
+ {0x90064, 0x48},
+ {0x90065, 0x40},
+ {0x90066, 0x633},
+ {0x90067, 0x149},
+ {0x90068, 0x10},
+ {0x90069, 0x4},
+ {0x9006a, 0x18},
+ {0x9006b, 0x0},
+ {0x9006c, 0x4},
+ {0x9006d, 0x78},
+ {0x9006e, 0x549},
+ {0x9006f, 0x633},
+ {0x90070, 0x159},
+ {0x90071, 0xd49},
+ {0x90072, 0x633},
+ {0x90073, 0x159},
+ {0x90074, 0x94a},
+ {0x90075, 0x633},
+ {0x90076, 0x159},
+ {0x90077, 0x441},
+ {0x90078, 0x633},
+ {0x90079, 0x149},
+ {0x9007a, 0x42},
+ {0x9007b, 0x633},
+ {0x9007c, 0x149},
+ {0x9007d, 0x1},
+ {0x9007e, 0x633},
+ {0x9007f, 0x149},
+ {0x90080, 0x0},
+ {0x90081, 0xe0},
+ {0x90082, 0x109},
+ {0x90083, 0xa},
+ {0x90084, 0x10},
+ {0x90085, 0x109},
+ {0x90086, 0x9},
+ {0x90087, 0x3c0},
+ {0x90088, 0x149},
+ {0x90089, 0x9},
+ {0x9008a, 0x3c0},
+ {0x9008b, 0x159},
+ {0x9008c, 0x18},
+ {0x9008d, 0x10},
+ {0x9008e, 0x109},
+ {0x9008f, 0x0},
+ {0x90090, 0x3c0},
+ {0x90091, 0x109},
+ {0x90092, 0x18},
+ {0x90093, 0x4},
+ {0x90094, 0x48},
+ {0x90095, 0x18},
+ {0x90096, 0x4},
+ {0x90097, 0x58},
+ {0x90098, 0xb},
+ {0x90099, 0x10},
+ {0x9009a, 0x109},
+ {0x9009b, 0x1},
+ {0x9009c, 0x10},
+ {0x9009d, 0x109},
+ {0x9009e, 0x5},
+ {0x9009f, 0x7c0},
+ {0x900a0, 0x109},
+ {0x900a1, 0x3},
+ {0x900a2, 0x8},
+ {0x900a3, 0x139},
+ {0x900a4, 0x0},
+ {0x900a5, 0x400},
+ {0x900a6, 0x16e},
+ {0x900a7, 0x8},
+ {0x900a8, 0x478},
+ {0x900a9, 0x109},
+ {0x900aa, 0x0},
+ {0x900ab, 0x8140},
+ {0x900ac, 0x10c},
+ {0x900ad, 0x10},
+ {0x900ae, 0x8138},
+ {0x900af, 0x10c},
+ {0x900b0, 0x8},
+ {0x900b1, 0x7c8},
+ {0x900b2, 0x101},
+ {0x900b3, 0x7a},
+ {0x900b4, 0x8},
+ {0x900b5, 0x109},
+ {0x900b6, 0x8},
+ {0x900b7, 0x448},
+ {0x900b8, 0x109},
+ {0x900b9, 0xf},
+ {0x900ba, 0x7c0},
+ {0x900bb, 0x109},
+ {0x900bc, 0x47},
+ {0x900bd, 0x630},
+ {0x900be, 0x109},
+ {0x900bf, 0x8},
+ {0x900c0, 0x618},
+ {0x900c1, 0x109},
+ {0x900c2, 0x8},
+ {0x900c3, 0xe0},
+ {0x900c4, 0x109},
+ {0x900c5, 0x0},
+ {0x900c6, 0x8},
+ {0x900c7, 0x109},
+ {0x900c8, 0x0},
+ {0x900c9, 0x7c8},
+ {0x900ca, 0x109},
+ {0x900cb, 0x8},
+ {0x900cc, 0x8140},
+ {0x900cd, 0x10c},
+ {0x900ce, 0x0},
+ {0x900cf, 0x478},
+ {0x900d0, 0x109},
+ {0x900d1, 0x0},
+ {0x900d2, 0x1},
+ {0x900d3, 0x8},
+ {0x900d4, 0x8},
+ {0x900d5, 0x4},
+ {0x900d6, 0x8},
+ {0x900d7, 0x8},
+ {0x900d8, 0x7c8},
+ {0x900d9, 0x101},
+ {0x90006, 0x0},
+ {0x90007, 0x0},
+ {0x90008, 0x8},
+ {0x90009, 0x0},
+ {0x9000a, 0x0},
+ {0x9000b, 0x0},
+ {0xd00e7, 0x400},
+ {0x90017, 0x0},
+ {0x90026, 0x2e},
+};
+#endif
diff --git a/drivers/nxp/drivers.mk b/drivers/nxp/drivers.mk
new file mode 100644
index 0000000..d77e985
--- /dev/null
+++ b/drivers/nxp/drivers.mk
@@ -0,0 +1,99 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+
+###############################################################################
+
+
+PLAT_DRIVERS_PATH := drivers/nxp
+PLAT_DRIVERS_INCLUDE_PATH := include/drivers/nxp
+
+ifeq (${SMMU_NEEDED},yes)
+PLAT_INCLUDES += -Iinclude/drivers/nxp/smmu/
+endif
+
+ifeq (${DCFG_NEEDED},yes)
+include $(PLAT_DRIVERS_PATH)/dcfg/dcfg.mk
+endif
+
+ifeq (${CSU_NEEDED},yes)
+include $(PLAT_DRIVERS_PATH)/csu/csu.mk
+endif
+
+ifeq (${TIMER_NEEDED},yes)
+include $(PLAT_DRIVERS_PATH)/timer/timer.mk
+endif
+
+ifeq (${INTERCONNECT_NEEDED},yes)
+include ${PLAT_DRIVERS_PATH}/interconnect/interconnect.mk
+endif
+
+ifeq (${GIC_NEEDED},yes)
+include ${PLAT_DRIVERS_PATH}/gic/gic.mk
+endif
+
+ifeq (${SD_MMC_NEEDED},yes)
+include $(PLAT_DRIVERS_PATH)/sd/sd_mmc.mk
+endif
+
+ifeq (${CONSOLE_NEEDED},yes)
+include $(PLAT_DRIVERS_PATH)/console/console.mk
+endif
+
+ifeq (${SFP_NEEDED},yes)
+include $(PLAT_DRIVERS_PATH)/sfp/sfp.mk
+endif
+
+ifeq (${XSPI_NEEDED},yes)
+include $(PLAT_DRIVERS_PATH)/flexspi/nor/flexspi_nor.mk
+endif
+
+ifeq (${QSPI_NEEDED},yes)
+include $(PLAT_DRIVERS_PATH)/qspi/qspi.mk
+endif
+
+ifeq (${SNVS_NEEDED},yes)
+include $(PLAT_DRIVERS_PATH)/sec_mon/sec_mon.mk
+endif
+
+ifeq ($(I2C_NEEDED),yes)
+$(eval $(call add_define, I2C_INIT))
+include $(PLAT_DRIVERS_PATH)/i2c/i2c.mk
+endif
+
+ifeq ($(DDR_DRIVER_NEEDED),yes)
+$(eval $(call add_define, DDR_INIT))
+# define DDR_CNTRL_SOURCES
+ifeq ($(DDRCNTLR),MMDC)
+include $(PLAT_DRIVERS_PATH)/ddr/fsl-mmdc/ddr.mk
+else
+include $(PLAT_DRIVERS_PATH)/ddr/nxp-ddr/ddr.mk
+endif # DDR_CNTRL_SOURCES
+endif
+
+ifeq (${PMU_NEEDED},yes)
+include $(PLAT_DRIVERS_PATH)/pmu/pmu.mk
+endif
+
+ifeq (${CRYPTO_NEEDED},yes)
+include $(PLAT_DRIVERS_PATH)/crypto/caam/caam.mk
+endif
+
+ifeq (${TZASC_NEEDED},yes)
+include $(PLAT_DRIVERS_PATH)/tzc/tzc.mk
+endif
+
+ifeq (${GPIO_NEEDED},yes)
+include ${PLAT_DRIVERS_PATH}/gpio/gpio.mk
+endif
+
+ifeq (${IFC_NOR_NEEDED},yes)
+include ${PLAT_DRIVERS_PATH}/ifc/nor/ifc_nor.mk
+endif
+
+ifeq (${IFC_NAND_NEEDED},yes)
+include ${PLAT_DRIVERS_PATH}/ifc/nand/ifc_nand.mk
+endif
diff --git a/drivers/nxp/flexspi/nor/flexspi_nor.c b/drivers/nxp/flexspi/nor/flexspi_nor.c
new file mode 100644
index 0000000..748228d
--- /dev/null
+++ b/drivers/nxp/flexspi/nor/flexspi_nor.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+
+#include <fspi_api.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+int flexspi_nor_io_setup(uintptr_t nxp_flexspi_flash_addr,
+ size_t nxp_flexspi_flash_size, uint32_t fspi_base_reg_addr)
+{
+ int ret = 0;
+
+ ret = fspi_init(fspi_base_reg_addr, nxp_flexspi_flash_addr);
+ /* Adding NOR Memory Map in XLAT Table */
+ mmap_add_region(nxp_flexspi_flash_addr, nxp_flexspi_flash_addr,
+ nxp_flexspi_flash_size, MT_MEMORY | MT_RW);
+
+ return ret;
+}
diff --git a/drivers/nxp/flexspi/nor/flexspi_nor.h b/drivers/nxp/flexspi/nor/flexspi_nor.h
new file mode 100644
index 0000000..61fc236
--- /dev/null
+++ b/drivers/nxp/flexspi/nor/flexspi_nor.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef FLEXSPI_NOR_H
+#define FLEXSPI_NOR_H
+
+int flexspi_nor_io_setup(uintptr_t nxp_flexspi_flash_addr,
+ size_t nxp_flexspi_flash_size,
+ uint32_t fspi_base_reg_addr);
+
+#endif /* FLEXSPI_NOR_H */
diff --git a/drivers/nxp/flexspi/nor/flexspi_nor.mk b/drivers/nxp/flexspi/nor/flexspi_nor.mk
new file mode 100644
index 0000000..6d9eebb
--- /dev/null
+++ b/drivers/nxp/flexspi/nor/flexspi_nor.mk
@@ -0,0 +1,35 @@
+#
+# Copyright 2020 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${XSPI_NOR},)
+XSPI_NOR := 1
+
+FLEXSPI_DRIVERS_PATH := ${PLAT_DRIVERS_PATH}/flexspi/nor
+
+PLAT_XSPI_INCLUDES += -I$(FLEXSPI_DRIVERS_PATH)
+
+XSPI_BOOT_SOURCES += $(FLEXSPI_DRIVERS_PATH)/flexspi_nor.c \
+ ${FLEXSPI_DRIVERS_PATH}/fspi.c
+ifeq ($(DEBUG),1)
+XSPI_BOOT_SOURCES += ${FLEXSPI_DRIVERS_PATH}/test_fspi.c
+endif
+
+PLAT_XSPI_INCLUDES += -Iinclude/drivers/nxp/flexspi
+
+PLAT_INCLUDES += ${PLAT_XSPI_INCLUDES}
+
+ifeq (${BL_COMM_XSPI_NEEDED},yes)
+BL_COMMON_SOURCES += ${XSPI_BOOT_SOURCES}
+else
+ifeq (${BL2_XSPI_NEEDED},yes)
+BL2_SOURCES += ${XSPI_BOOT_SOURCES}
+endif
+ifeq (${BL31_XSPI_NEEDED},yes)
+BL31_SOURCES += ${XSPI_BOOT_SOURCES}
+endif
+endif
+
+endif
diff --git a/drivers/nxp/flexspi/nor/fspi.c b/drivers/nxp/flexspi/nor/fspi.c
new file mode 100644
index 0000000..7c919b8
--- /dev/null
+++ b/drivers/nxp/flexspi/nor/fspi.c
@@ -0,0 +1,853 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * NXP FlexSpi Controller Driver.
+ * Copyright 2021 NXP
+ *
+ */
+#include <endian.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <flash_info.h>
+#include "fspi.h"
+#include <fspi_api.h>
+#include <xspi_error_codes.h>
+
+#ifdef DEBUG_FLEXSPI
+#define PR printf("In [%s][%d]\n", __func__, __LINE__)
+#define PRA(a, b) printf("In [%s][%d] %s="a"\n", __func__, __LINE__, #b, b)
+#else
+#define PR
+#define PRA(a, b)
+#endif
+
+/*
+ * This errata is valid for all NXP SoC.
+ */
+#define ERRATA_FLASH_A050272 1
+
+static uintptr_t fspi_base_reg_addr;
+static uintptr_t fspi_flash_base_addr;
+
+static void fspi_RDSR(uint32_t *, const void *, uint32_t);
+
+static void fspi_writel(uint32_t x_addr, uint32_t x_val)
+{
+ fspi_out32((uint32_t *)(fspi_base_reg_addr + x_addr),
+ (uint32_t) x_val);
+}
+
+static uint32_t fspi_readl(uint32_t x_addr)
+{
+ return fspi_in32((uint32_t *)(fspi_base_reg_addr + x_addr));
+}
+
+static void fspi_MDIS(uint8_t x_disable)
+{
+ uint32_t ui_reg;
+
+ ui_reg = fspi_readl(FSPI_MCR0);
+ if (x_disable != 0U) {
+ ui_reg |= FSPI_MCR0_MDIS;
+ } else {
+ ui_reg &= (uint32_t) (~FSPI_MCR0_MDIS);
+ }
+
+ fspi_writel(FSPI_MCR0, ui_reg);
+}
+
+static void fspi_lock_LUT(void)
+{
+ fspi_writel(FSPI_LUTKEY, FSPI_LUTKEY_VALUE);
+ VERBOSE("%s 0x%x\n", __func__, fspi_readl(FSPI_LCKCR));
+ fspi_writel(FSPI_LCKCR, FSPI_LCKER_LOCK);
+ VERBOSE("%s 0x%x\n", __func__, fspi_readl(FSPI_LCKCR));
+}
+
+static void fspi_unlock_LUT(void)
+{
+ fspi_writel(FSPI_LUTKEY, FSPI_LUTKEY_VALUE);
+ VERBOSE("%s 0x%x\n", __func__, fspi_readl(FSPI_LCKCR));
+ fspi_writel(FSPI_LCKCR, FSPI_LCKER_UNLOCK);
+ VERBOSE("%s 0x%x\n", __func__, fspi_readl(FSPI_LCKCR));
+}
+
+static void fspi_op_setup(uint32_t fspi_op_seq_id, bool ignore_flash_sz)
+{
+ uint32_t x_addr, x_instr0 = 0, x_instr1 = 0, x_instr2 = 0;
+ uint32_t cmd_id1, cmd_id2;
+
+ VERBOSE("In func %s\n", __func__);
+
+ switch (fspi_op_seq_id) {
+ case FSPI_READ_SEQ_ID:
+ cmd_id1 = FSPI_NOR_CMD_READ;
+ cmd_id2 = FSPI_NOR_CMD_READ_4B;
+ x_instr2 = FSPI_INSTR_OPRND0(0) | FSPI_INSTR_PAD0(FSPI_LUT_PAD1)
+ | FSPI_INSTR_OPCODE0(FSPI_LUT_READ);
+ break;
+ case FSPI_FASTREAD_SEQ_ID:
+ cmd_id1 = FSPI_NOR_CMD_FASTREAD;
+ cmd_id2 = FSPI_NOR_CMD_FASTREAD_4B;
+ x_instr2 = FSPI_INSTR_OPRND0(8) | FSPI_INSTR_PAD0(FSPI_LUT_PAD1)
+ | FSPI_INSTR_OPCODE0(FSPI_DUMMY_SDR)
+ | FSPI_INSTR_OPRND1(0)
+ | FSPI_INSTR_PAD1(FSPI_LUT_PAD1)
+ | FSPI_INSTR_OPCODE1(FSPI_LUT_READ);
+ break;
+ case FSPI_WRITE_SEQ_ID:
+ cmd_id1 = FSPI_NOR_CMD_PP;
+ cmd_id2 = FSPI_NOR_CMD_PP_4B;
+ x_instr2 = FSPI_INSTR_OPRND0(0) | FSPI_INSTR_PAD0(FSPI_LUT_PAD1)
+ | FSPI_INSTR_OPCODE0(FSPI_LUT_WRITE);
+ break;
+ case FSPI_WREN_SEQ_ID:
+ cmd_id1 = FSPI_NOR_CMD_WREN;
+ cmd_id2 = FSPI_NOR_CMD_WREN;
+ break;
+ case FSPI_SE_SEQ_ID:
+ cmd_id1 = FSPI_NOR_CMD_SE_64K;
+ cmd_id2 = FSPI_NOR_CMD_SE_64K_4B;
+ break;
+ case FSPI_4K_SEQ_ID:
+ cmd_id1 = FSPI_NOR_CMD_SE_4K;
+ cmd_id2 = FSPI_NOR_CMD_SE_4K_4B;
+ break;
+ case FSPI_BE_SEQ_ID:
+ cmd_id1 = FSPI_NOR_CMD_BE;
+ cmd_id2 = FSPI_NOR_CMD_BE;
+ break;
+ case FSPI_RDSR_SEQ_ID:
+ cmd_id1 = FSPI_NOR_CMD_RDSR;
+ cmd_id2 = FSPI_NOR_CMD_RDSR;
+ break;
+ }
+
+ x_addr = FSPI_LUTREG_OFFSET + (uint32_t)(0x10 * fspi_op_seq_id);
+ if ((F_FLASH_SIZE_BYTES <= SZ_16M_BYTES) || (ignore_flash_sz)) {
+ x_instr0 = FSPI_INSTR_OPRND0(cmd_id1);
+ x_instr1 = FSPI_INSTR_OPRND1(FSPI_LUT_ADDR24BIT);
+ VERBOSE("CMD_ID = %x offset = 0x%x\n", cmd_id1, x_addr);
+ } else {
+ x_instr0 = FSPI_INSTR_OPRND0(cmd_id2);
+ x_instr1 = FSPI_INSTR_OPRND1(FSPI_LUT_ADDR32BIT);
+ VERBOSE("CMD_ID = %x offset = 0x%x\n", cmd_id2, x_addr);
+ }
+ x_instr0 |= FSPI_INSTR_PAD0(FSPI_LUT_PAD1)
+ | FSPI_INSTR_OPCODE0(FSPI_LUT_CMD);
+
+ x_instr1 |= FSPI_INSTR_PAD1(FSPI_LUT_PAD1)
+ | FSPI_INSTR_OPCODE1(FSPI_LUT_ADDR);
+
+ if (fspi_op_seq_id == FSPI_RDSR_SEQ_ID) {
+ x_instr0 |= FSPI_INSTR_OPRND1(1) | FSPI_INSTR_PAD1(FSPI_LUT_PAD1)
+ | FSPI_INSTR_OPCODE1(FSPI_LUT_READ);
+ } else if ((fspi_op_seq_id != FSPI_BE_SEQ_ID)
+ && (fspi_op_seq_id != FSPI_WREN_SEQ_ID)) {
+ x_instr0 |= x_instr1;
+ }
+
+ fspi_writel((x_addr), x_instr0);
+ fspi_writel((x_addr + U(0x4)), x_instr2);
+ fspi_writel((x_addr + U(0x8)), (uint32_t) 0x0); /* STOP command */
+ fspi_writel((x_addr + U(0xc)), (uint32_t) 0x0); /* STOP command */
+}
+
+static void fspi_setup_LUT(void)
+{
+ VERBOSE("In func %s\n", __func__);
+ fspi_unlock_LUT();
+
+ /* LUT Setup for READ Command 3-Byte low Frequency */
+ fspi_op_setup(FSPI_READ_SEQ_ID, false);
+
+ /* LUT Setup for FAST READ Command 3-Byte/4-Byte high Frequency */
+ fspi_op_setup(FSPI_FASTREAD_SEQ_ID, false);
+
+ /* LUT Setup for Page Program */
+ fspi_op_setup(FSPI_WRITE_SEQ_ID, false);
+
+ /* LUT Setup for WREN */
+ fspi_op_setup(FSPI_WREN_SEQ_ID, true);
+
+ /* LUT Setup for Sector_Erase */
+ fspi_op_setup(FSPI_SE_SEQ_ID, false);
+
+ /* LUT Setup for Sub Sector 4K Erase */
+ fspi_op_setup(FSPI_4K_SEQ_ID, false);
+
+ /* LUT Setup for Bulk_Erase */
+ fspi_op_setup(FSPI_BE_SEQ_ID, true);
+
+ /* Read Status */
+ fspi_op_setup(FSPI_RDSR_SEQ_ID, true);
+
+ fspi_lock_LUT();
+}
+
+static inline void fspi_ahb_invalidate(void)
+{
+ uint32_t reg;
+
+ VERBOSE("In func %s %d\n", __func__, __LINE__);
+ reg = fspi_readl(FSPI_MCR0);
+ reg |= FSPI_MCR0_SWRST;
+ fspi_writel(FSPI_MCR0, reg);
+ while ((fspi_readl(FSPI_MCR0) & FSPI_MCR0_SWRST) != 0)
+ ; /* FSPI_MCR0_SWRESET_MASK */
+ VERBOSE("In func %s %d\n", __func__, __LINE__);
+}
+
+#if defined(CONFIG_FSPI_AHB)
+static void fspi_init_ahb(void)
+{
+ uint32_t i, x_flash_cr2, seq_id;
+
+ x_flash_cr2 = 0;
+ /* Reset AHB RX buffer CR configuration */
+ for (i = 0; i < 8; i++) {
+ fspi_writel((FSPI_AHBRX_BUF0CR0 + 4 * i), 0U);
+ }
+
+ /* Set ADATSZ with the maximum AHB buffer size */
+ fspi_writel(FSPI_AHBRX_BUF7CR0,
+ ((uint32_t) ((FSPI_RX_MAX_AHBBUF_SIZE / 8U) |
+ FSPI_AHBRXBUF0CR7_PREF)));
+
+ /* Known limitation handling: prefetch and
+ * no start address alignment.*/
+ fspi_writel(FSPI_AHBCR, FSPI_AHBCR_PREF_EN);
+ INFO("xAhbcr=0x%x\n", fspi_readl(FSPI_AHBCR));
+
+ // Setup AHB READ sequenceID for all flashes.
+ x_flash_cr2 = fspi_readl(FSPI_FLSHA1CR2);
+ INFO("x_flash_cr2=0x%x\n", x_flash_cr2);
+
+ seq_id = CONFIG_FSPI_FASTREAD ?
+ FSPI_FASTREAD_SEQ_ID : FSPI_READ_SEQ_ID;
+ x_flash_cr2 |= ((seq_id << FSPI_FLSHXCR2_ARDSEQI_SHIFT) & 0x1f);
+
+ INFO("x_flash_cr2=0x%x\n", x_flash_cr2);
+
+ fspi_writel(FSPI_FLSHA1CR2, x_flash_cr2);
+ x_flash_cr2 = fspi_readl(FSPI_FLSHA1CR2);
+ INFO("x_flash_cr2=0x%x\n", x_flash_cr2);
+}
+#endif
+
+int xspi_read(uint32_t pc_rx_addr, uint32_t *pc_rx_buf, uint32_t x_size_bytes)
+{
+ if (x_size_bytes == 0) {
+ ERROR("Zero length reads are not allowed\n");
+ return XSPI_READ_FAIL;
+ }
+
+#if defined(CONFIG_FSPI_AHB)
+ return xspi_ahb_read(pc_rx_addr, pc_rx_buf, x_size_bytes);
+#else
+ return xspi_ip_read(pc_rx_addr, pc_rx_buf, x_size_bytes);
+#endif
+}
+#if defined(CONFIG_FSPI_AHB)
+int xspi_ahb_read(uint32_t pc_rx_addr, uint32_t *pc_rx_buf, uint32_t x_size_bytes)
+{
+ VERBOSE("In func %s 0x%x\n", __func__, (pc_rx_addr));
+
+ if (F_FLASH_SIZE_BYTES <= SZ_16M_BYTES) {
+ pc_rx_addr = ((uint32_t)(pcRxAddr & MASK_24BIT_ADDRESS));
+ } else {
+ pc_rx_addr = ((uint32_t)(pcRxAddr & MASK_32BIT_ADDRESS));
+ }
+
+ pc_rx_addr = ((uint32_t)(pcRxAddr + fspi_flash_base_addr));
+
+ if (((pc_rx_addr % 4) != 0) || (((uintptr_t)pc_rx_buf % 4) != 0)) {
+ WARN("%s: unaligned Start Address src=%ld dst=0x%p\n",
+ __func__, (pc_rx_addr - fspi_flash_base_addr), pc_rx_buf);
+ }
+
+ /* Directly copy from AHB Buffer */
+ memcpy(pc_rx_buf, (void *)(uintptr_t)pc_rx_addr, x_size_bytes);
+
+ fspi_ahb_invalidate();
+ return XSPI_SUCCESS;
+}
+#endif
+
+int xspi_ip_read(uint32_t pc_rx_addr, uint32_t *pv_rx_buf, uint32_t ui_len)
+{
+
+ uint32_t i = 0U, j = 0U, x_rem = 0U;
+ uint32_t x_iteration = 0U, x_size_rx = 0U, x_size_wm, temp_size;
+ uint32_t data = 0U;
+ uint32_t x_len_bytes;
+ uint32_t x_addr, sts0, intr, seq_id;
+
+ x_addr = (uint32_t) pc_rx_addr;
+ x_len_bytes = ui_len;
+
+ /* Watermark level : 8 bytes. (BY DEFAULT) */
+ x_size_wm = 8U;
+
+ /* Clear RX Watermark interrupt in INT register, if any existing. */
+ fspi_writel(FSPI_INTR, FSPI_INTR_IPRXWA);
+ PRA("0x%x", fspi_readl(FSPI_INTR));
+ /* Invalid the RXFIFO, to run next IP Command */
+ /* Clears data entries in IP Rx FIFOs, Also reset R/W pointers */
+ fspi_writel(FSPI_IPRXFCR, FSPI_IPRXFCR_CLR);
+ fspi_writel(FSPI_INTR, FSPI_INTEN_IPCMDDONE);
+
+ while (x_len_bytes) {
+
+ /* FlexSPI can store no more than FSPI_RX_IPBUF_SIZE */
+ x_size_rx = (x_len_bytes > FSPI_RX_IPBUF_SIZE) ?
+ FSPI_RX_IPBUF_SIZE : x_len_bytes;
+
+ /* IP Control Register0 - SF Address to be read */
+ fspi_writel(FSPI_IPCR0, x_addr);
+ PRA("0x%x", fspi_readl(FSPI_IPCR0));
+ /* IP Control Register1 - SEQID_READ operation, Size */
+
+ seq_id = CONFIG_FSPI_FASTREAD ?
+ FSPI_FASTREAD_SEQ_ID : FSPI_READ_SEQ_ID;
+
+ fspi_writel(FSPI_IPCR1,
+ (uint32_t)(seq_id << FSPI_IPCR1_ISEQID_SHIFT) |
+ (uint16_t) x_size_rx);
+
+ PRA("0x%x", fspi_readl(FSPI_IPCR1));
+
+ do {
+ sts0 = fspi_readl(FSPI_STS0);
+ } while (((sts0 & FSPI_STS0_ARB_IDLE) == 0) &&
+ ((sts0 & FSPI_STS0_SEQ_IDLE) == 0));
+
+ /* Trigger IP Read Command */
+ fspi_writel(FSPI_IPCMD, FSPI_IPCMD_TRG_MASK);
+ PRA("0x%x", fspi_readl(FSPI_IPCMD));
+
+ intr = fspi_readl(FSPI_INTR);
+ if (((intr & FSPI_INTR_IPCMDGE) != 0) ||
+ ((intr & FSPI_INTR_IPCMDERR) != 0)) {
+ ERROR("Error in IP READ INTR=0x%x\n", intr);
+ return -XSPI_IP_READ_FAIL;
+ }
+ /* Will read in n iterations of each 8 FIFO's(WM level) */
+ x_iteration = x_size_rx / x_size_wm;
+ for (i = 0U; i < x_iteration; i++) {
+ if ((fspi_readl(FSPI_INTR) & FSPI_INTR_IPRXWA_MASK) == 0) {
+ PRA("0x%x", fspi_readl(FSPI_INTR));
+ }
+ /* Wait for IP Rx Watermark Fill event */
+ while (!(fspi_readl(FSPI_INTR) & FSPI_INTR_IPRXWA_MASK)) {
+ PRA("0x%x", fspi_readl(FSPI_INTR));
+ }
+
+ /* Read RX FIFO's(upto WM level) & copy to rxbuffer */
+ for (j = 0U; j < x_size_wm; j += 4U) {
+ /* Read FIFO Data Register */
+ data = fspi_readl(FSPI_RFDR + j);
+#if FSPI_IPDATA_SWAP /* Just In case you want swap */
+ data = bswap32(data);
+#endif
+ memcpy(pv_rx_buf++, &data, 4);
+ }
+
+ /* Clear IP_RX_WATERMARK Event in INTR register */
+ /* Reset FIFO Read pointer for next iteration.*/
+ fspi_writel(FSPI_INTR, FSPI_INTR_IPRXWA);
+ }
+
+ x_rem = x_size_rx % x_size_wm;
+
+ if (x_rem != 0U) {
+ /* Wait for data filled */
+ while (!(fspi_readl(FSPI_IPRXFSTS) & FSPI_IPRXFSTS_FILL_MASK)) {
+ PRA("0x%x", fspi_readl(FSPI_IPRXFSTS));
+ }
+
+ temp_size = 0;
+ j = 0U;
+ while (x_rem > 0U) {
+ data = 0U;
+ data = fspi_readl(FSPI_RFDR + j);
+#if FSPI_IPDATA_SWAP /* Just In case you want swap */
+ data = bswap32(data);
+#endif
+ temp_size = (x_rem < 4) ? x_rem : 4;
+ memcpy(pv_rx_buf++, &data, temp_size);
+ x_rem -= temp_size;
+ }
+ }
+
+
+ while (!(fspi_readl(FSPI_INTR) & FSPI_INTR_IPCMDDONE_MASK)) {
+ PRA("0x%x", fspi_readl(FSPI_INTR));
+ }
+
+ /* Invalid the RX FIFO, to run next IP Command */
+ fspi_writel(FSPI_IPRXFCR, FSPI_IPRXFCR_CLR);
+ /* Clear IP Command Done flag in interrupt register*/
+ fspi_writel(FSPI_INTR, FSPI_INTR_IPCMDDONE_MASK);
+
+ /* Update remaining len, Increment x_addr read pointer. */
+ x_len_bytes -= x_size_rx;
+ x_addr += x_size_rx;
+ }
+ PR;
+ return XSPI_SUCCESS;
+}
+
+void xspi_ip_write(uint32_t pc_wr_addr, uint32_t *pv_wr_buf, uint32_t ui_len)
+{
+
+ uint32_t x_iteration = 0U, x_rem = 0U;
+ uint32_t x_size_tx = 0U, x_size_wm, temp_size;
+ uint32_t i = 0U, j = 0U;
+ uint32_t ui_data = 0U;
+ uint32_t x_addr, x_len_bytes;
+
+
+ x_size_wm = 8U; /* Default TX WaterMark level: 8 Bytes. */
+ x_addr = (uint32_t)pc_wr_addr;
+ x_len_bytes = ui_len;
+ VERBOSE("In func %s[%d] x_addr =0x%x xLen_bytes=%d\n",
+ __func__, __LINE__, x_addr, x_len_bytes);
+
+ while (x_len_bytes != 0U) {
+
+ x_size_tx = (x_len_bytes > FSPI_TX_IPBUF_SIZE) ?
+ FSPI_TX_IPBUF_SIZE : x_len_bytes;
+
+ /* IP Control Register0 - SF Address to be read */
+ fspi_writel(FSPI_IPCR0, x_addr);
+ INFO("In func %s[%d] x_addr =0x%x xLen_bytes=%d\n",
+ __func__, __LINE__, x_addr, x_len_bytes);
+
+ /*
+ * Fill TX FIFO's..
+ *
+ */
+
+ x_iteration = x_size_tx / x_size_wm;
+ for (i = 0U; i < x_iteration; i++) {
+
+ /* Ensure TX FIFO Watermark Available */
+ while ((fspi_readl(FSPI_INTR) & FSPI_INTR_IPTXWE_MASK) == 0)
+ ;
+
+
+ /* Fill TxFIFO's ( upto watermark level) */
+ for (j = 0U; j < x_size_wm; j += 4U) {
+ memcpy(&ui_data, pv_wr_buf++, 4);
+ /* Write TX FIFO Data Register */
+ fspi_writel((FSPI_TFDR + j), ui_data);
+
+ }
+
+ /* Clear IP_TX_WATERMARK Event in INTR register */
+ /* Reset the FIFO Write pointer for next iteration */
+ fspi_writel(FSPI_INTR, FSPI_INTR_IPTXWE);
+ }
+
+ x_rem = x_size_tx % x_size_wm;
+
+ if (x_rem != 0U) {
+ /* Wait for TXFIFO empty */
+ while (!(fspi_readl(FSPI_INTR) & FSPI_INTR_IPTXWE))
+ ;
+
+ temp_size = 0U;
+ j = 0U;
+ while (x_rem > 0U) {
+ ui_data = 0U;
+ temp_size = (x_rem < 4U) ? x_rem : 4U;
+ memcpy(&ui_data, pv_wr_buf++, temp_size);
+ INFO("%d ---> pv_wr_buf=0x%p\n", __LINE__, pv_wr_buf);
+ fspi_writel((FSPI_TFDR + j), ui_data);
+ x_rem -= temp_size;
+ j += 4U ; /* TODO: May not be needed*/
+ }
+ /* Clear IP_TX_WATERMARK Event in INTR register */
+ /* Reset FIFO's Write pointer for next iteration.*/
+ fspi_writel(FSPI_INTR, FSPI_INTR_IPTXWE);
+ }
+
+ /* IP Control Register1 - SEQID_WRITE operation, Size */
+ fspi_writel(FSPI_IPCR1, (uint32_t)(FSPI_WRITE_SEQ_ID << FSPI_IPCR1_ISEQID_SHIFT) | (uint16_t) x_size_tx);
+ /* Trigger IP Write Command */
+ fspi_writel(FSPI_IPCMD, FSPI_IPCMD_TRG_MASK);
+
+ /* Wait for IP Write command done */
+ while (!(fspi_readl(FSPI_INTR) & FSPI_INTR_IPCMDDONE_MASK))
+ ;
+
+ /* Invalidate TX FIFOs & acknowledge IP_CMD_DONE event */
+ fspi_writel(FSPI_IPTXFCR, FSPI_IPTXFCR_CLR);
+ fspi_writel(FSPI_INTR, FSPI_INTR_IPCMDDONE_MASK);
+
+ /* for next iteration */
+ x_len_bytes -= x_size_tx;
+ x_addr += x_size_tx;
+ }
+
+}
+
+int xspi_write(uint32_t pc_wr_addr, void *pv_wr_buf, uint32_t ui_len)
+{
+
+ uint32_t x_addr;
+ uint32_t x_page1_len = 0U, x_page_l_len = 0U;
+ uint32_t i, j = 0U;
+ void *buf = pv_wr_buf;
+
+ VERBOSE("\nIn func %s\n", __func__);
+
+ x_addr = (uint32_t)(pc_wr_addr);
+ if ((ui_len <= F_PAGE_256) && ((x_addr % F_PAGE_256) == 0)) {
+ x_page1_len = ui_len;
+ INFO("%d ---> x_page1_len=0x%x x_page_l_len =0x%x j=0x%x\n", __LINE__, x_page1_len, x_page_l_len, j);
+ } else if ((ui_len <= F_PAGE_256) && ((x_addr % F_PAGE_256) != 0)) {
+ x_page1_len = (F_PAGE_256 - (x_addr % F_PAGE_256));
+ if (ui_len > x_page1_len) {
+ x_page_l_len = (ui_len - x_page1_len) % F_PAGE_256;
+ } else {
+ x_page1_len = ui_len;
+ x_page_l_len = 0;
+ }
+ j = 0U;
+ INFO("%d 0x%x 0x%x\n", x_addr % F_PAGE_256, x_addr % F_PAGE_256, F_PAGE_256);
+ INFO("%d ---> x_page1_len=0x%x x_page_l_len =0x%x j=0x%x\n", __LINE__, x_page1_len, x_page_l_len, j);
+ } else if ((ui_len > F_PAGE_256) && ((x_addr % F_PAGE_256) == 0)) {
+ j = ui_len / F_PAGE_256;
+ x_page_l_len = ui_len % F_PAGE_256;
+ INFO("%d ---> x_page1_len=0x%x x_page_l_len =0x%x j=0x%x\n", __LINE__, x_page1_len, x_page_l_len, j);
+ } else if ((ui_len > F_PAGE_256) && ((x_addr % F_PAGE_256) != 0)) {
+ x_page1_len = (F_PAGE_256 - (x_addr % F_PAGE_256));
+ j = (ui_len - x_page1_len) / F_PAGE_256;
+ x_page_l_len = (ui_len - x_page1_len) % F_PAGE_256;
+ INFO("%d ---> x_page1_len=0x%x x_page_l_len =0x%x j=0x%x\n", __LINE__, x_page1_len, x_page_l_len, j);
+ }
+
+ if (x_page1_len != 0U) {
+ xspi_wren(x_addr);
+ xspi_ip_write(x_addr, (uint32_t *)buf, x_page1_len);
+ while (is_flash_busy())
+ ;
+ INFO("%d Initial pc_wr_addr=0x%x, Final x_addr=0x%x, Initial ui_len=0x%x Final ui_len=0x%x\n",
+ __LINE__, pc_wr_addr, x_addr, ui_len, (x_addr-pc_wr_addr));
+ INFO("Initial Buf pv_wr_buf=%p, final Buf=%p\n", pv_wr_buf, buf);
+ x_addr += x_page1_len;
+ /* TODO What is buf start is not 4 aligned */
+ buf = buf + x_page1_len;
+ }
+
+ for (i = 0U; i < j; i++) {
+ INFO("In for loop Buf pv_wr_buf=%p, final Buf=%p x_addr=0x%x offset_buf %d.\n",
+ pv_wr_buf, buf, x_addr, x_page1_len/4);
+ xspi_wren(x_addr);
+ xspi_ip_write(x_addr, (uint32_t *)buf, F_PAGE_256);
+ while (is_flash_busy())
+ ;
+ INFO("%d Initial pc_wr_addr=0x%x, Final x_addr=0x%x, Initial ui_len=0x%x Final ui_len=0x%x\n",
+ __LINE__, pc_wr_addr, x_addr, ui_len, (x_addr-pc_wr_addr));
+ x_addr += F_PAGE_256;
+ /* TODO What is buf start is not 4 aligned */
+ buf = buf + F_PAGE_256;
+ INFO("Initial Buf pv_wr_buf=%p, final Buf=%p\n", pv_wr_buf, buf);
+ }
+
+ if (x_page_l_len != 0U) {
+ INFO("%d Initial Buf pv_wr_buf=%p, final Buf=%p x_page_l_len=0x%x\n", __LINE__, pv_wr_buf, buf, x_page_l_len);
+ xspi_wren(x_addr);
+ xspi_ip_write(x_addr, (uint32_t *)buf, x_page_l_len);
+ while (is_flash_busy())
+ ;
+ INFO("%d Initial pc_wr_addr=0x%x, Final x_addr=0x%x, Initial ui_len=0x%x Final ui_len=0x%x\n",
+ __LINE__, pc_wr_addr, x_addr, ui_len, (x_addr-pc_wr_addr));
+ }
+
+ VERBOSE("Now calling func call Invalidate%s\n", __func__);
+ fspi_ahb_invalidate();
+ return XSPI_SUCCESS;
+}
+
+int xspi_wren(uint32_t pc_wr_addr)
+{
+ VERBOSE("In func %s Addr=0x%x\n", __func__, pc_wr_addr);
+
+ fspi_writel(FSPI_IPTXFCR, FSPI_IPTXFCR_CLR);
+
+ fspi_writel(FSPI_IPCR0, (uint32_t)pc_wr_addr);
+ fspi_writel(FSPI_IPCR1, ((FSPI_WREN_SEQ_ID << FSPI_IPCR1_ISEQID_SHIFT) | 0));
+ fspi_writel(FSPI_IPCMD, FSPI_IPCMD_TRG_MASK);
+
+ while ((fspi_readl(FSPI_INTR) & FSPI_INTR_IPCMDDONE_MASK) == 0)
+ ;
+
+ fspi_writel(FSPI_INTR, FSPI_INTR_IPCMDDONE_MASK);
+ return XSPI_SUCCESS;
+}
+
+static void fspi_bbluk_er(void)
+{
+ VERBOSE("In func %s\n", __func__);
+ fspi_writel(FSPI_IPCR0, 0x0);
+ fspi_writel(FSPI_IPCR1, ((FSPI_BE_SEQ_ID << FSPI_IPCR1_ISEQID_SHIFT) | 20));
+ fspi_writel(FSPI_IPCMD, FSPI_IPCMD_TRG_MASK);
+
+ while ((fspi_readl(FSPI_INTR) & FSPI_INTR_IPCMDDONE_MASK) == 0)
+ ;
+ fspi_writel(FSPI_INTR, FSPI_INTR_IPCMDDONE_MASK);
+
+}
+
+static void fspi_RDSR(uint32_t *rxbuf, const void *p_addr, uint32_t size)
+{
+ uint32_t iprxfcr = 0U;
+ uint32_t data = 0U;
+
+ iprxfcr = fspi_readl(FSPI_IPRXFCR);
+ /* IP RX FIFO would be read by processor */
+ iprxfcr = iprxfcr & (uint32_t)~FSPI_IPRXFCR_CLR;
+ /* Invalid data entries in IP RX FIFO */
+ iprxfcr = iprxfcr | FSPI_IPRXFCR_CLR;
+ fspi_writel(FSPI_IPRXFCR, iprxfcr);
+
+ fspi_writel(FSPI_IPCR0, (uintptr_t) p_addr);
+ fspi_writel(FSPI_IPCR1,
+ (uint32_t) ((FSPI_RDSR_SEQ_ID << FSPI_IPCR1_ISEQID_SHIFT)
+ | (uint16_t) size));
+ /* Trigger the command */
+ fspi_writel(FSPI_IPCMD, FSPI_IPCMD_TRG_MASK);
+ /* Wait for command done */
+ while ((fspi_readl(FSPI_INTR) & FSPI_INTR_IPCMDDONE_MASK) == 0)
+ ;
+ fspi_writel(FSPI_INTR, FSPI_INTR_IPCMDDONE_MASK);
+
+ data = fspi_readl(FSPI_RFDR);
+ memcpy(rxbuf, &data, size);
+
+ /* Rx FIFO invalidation needs to be done prior w1c of INTR.IPRXWA bit */
+ fspi_writel(FSPI_IPRXFCR, FSPI_IPRXFCR_CLR);
+ fspi_writel(FSPI_INTR, FSPI_INTR_IPRXWA_MASK);
+ fspi_writel(FSPI_INTR, FSPI_INTR_IPCMDDONE_MASK);
+
+}
+
+bool is_flash_busy(void)
+{
+#define FSPI_ONE_BYTE 1
+ uint8_t data[4];
+
+ VERBOSE("In func %s\n\n", __func__);
+ fspi_RDSR((uint32_t *) data, 0, FSPI_ONE_BYTE);
+
+ return !!((uint32_t) data[0] & FSPI_NOR_SR_WIP_MASK);
+}
+
+int xspi_bulk_erase(void)
+{
+ VERBOSE("In func %s\n", __func__);
+ xspi_wren((uint32_t) 0x0);
+ fspi_bbluk_er();
+ while (is_flash_busy())
+ ;
+ fspi_ahb_invalidate();
+ return XSPI_SUCCESS;
+}
+
+static void fspi_sec_er(uint32_t pc_wr_addr)
+{
+ uint32_t x_addr;
+
+ VERBOSE("In func %s\n", __func__);
+ x_addr = (uint32_t)(pc_wr_addr);
+
+ fspi_writel(FSPI_IPCR0, x_addr);
+ INFO("In [%s][%d] Erase address 0x%x\n", __func__, __LINE__, (x_addr));
+#if CONFIG_FSPI_ERASE_4K
+ fspi_writel(FSPI_IPCR1, ((FSPI_4K_SEQ_ID << FSPI_IPCR1_ISEQID_SHIFT) | 0));
+#else
+ fspi_writel(FSPI_IPCR1, ((FSPI_SE_SEQ_ID << FSPI_IPCR1_ISEQID_SHIFT) | 0));
+#endif
+ fspi_writel(FSPI_IPCMD, FSPI_IPCMD_TRG_MASK);
+
+ while ((fspi_readl(FSPI_INTR) & FSPI_INTR_IPCMDDONE_MASK) == 0) {
+ PRA("0x%x", fspi_readl(FSPI_INTR));
+ }
+ fspi_writel(FSPI_INTR, FSPI_INTR_IPCMDDONE_MASK);
+}
+
+int xspi_sector_erase(uint32_t pc_wr_addr, uint32_t ui_len)
+{
+ uint32_t x_addr, x_len_bytes, i, num_sector = 0U;
+
+ VERBOSE("In func %s\n", __func__);
+ x_addr = (uint32_t)(pc_wr_addr);
+ if ((x_addr % F_SECTOR_ERASE_SZ) != 0) {
+ ERROR("!!! In func %s, unalinged start address can only be in multiples of 0x%x\n",
+ __func__, F_SECTOR_ERASE_SZ);
+ return -XSPI_ERASE_FAIL;
+ }
+
+ x_len_bytes = ui_len * 1;
+ if (x_len_bytes < F_SECTOR_ERASE_SZ) {
+ ERROR("!!! In func %s, Less than 1 sector can only be in multiples of 0x%x\n",
+ __func__, F_SECTOR_ERASE_SZ);
+ return -XSPI_ERASE_FAIL;
+ }
+
+ num_sector = x_len_bytes/F_SECTOR_ERASE_SZ;
+ num_sector += x_len_bytes % F_SECTOR_ERASE_SZ ? 1U : 0U;
+ INFO("F_SECTOR_ERASE_SZ: 0x%08x, num_sector: %d\n", F_SECTOR_ERASE_SZ, num_sector);
+
+ for (i = 0U; i < num_sector ; i++) {
+ xspi_wren(x_addr + (F_SECTOR_ERASE_SZ * i));
+ fspi_sec_er(x_addr + (F_SECTOR_ERASE_SZ * i));
+ while (is_flash_busy())
+ ;
+ }
+ fspi_ahb_invalidate();
+ return XSPI_SUCCESS;
+}
+
+
+__attribute__((unused)) static void fspi_delay_ms(uint32_t x)
+{
+ volatile unsigned long ul_count;
+
+ for (ul_count = 0U; ul_count < (30U * x); ul_count++)
+ ;
+
+}
+
+
+#if defined(DEBUG_FLEXSPI)
+static void fspi_dump_regs(void)
+{
+ uint32_t i;
+
+ VERBOSE("\nRegisters Dump:\n");
+ VERBOSE("Flexspi: Register FSPI_MCR0(0x%x) = 0x%08x\n", FSPI_MCR0, fspi_readl(FSPI_MCR0));
+ VERBOSE("Flexspi: Register FSPI_MCR2(0x%x) = 0x%08x\n", FSPI_MCR2, fspi_readl(FSPI_MCR2));
+ VERBOSE("Flexspi: Register FSPI_DLL_A_CR(0x%x) = 0x%08x\n", FSPI_DLLACR, fspi_readl(FSPI_DLLACR));
+ VERBOSE("\n");
+
+ for (i = 0U; i < 8U; i++) {
+ VERBOSE("Flexspi: Register FSPI_AHBRX_BUF0CR0(0x%x) = 0x%08x\n", FSPI_AHBRX_BUF0CR0 + i * 4, fspi_readl((FSPI_AHBRX_BUF0CR0 + i * 4)));
+ }
+ VERBOSE("\n");
+
+ VERBOSE("Flexspi: Register FSPI_AHBRX_BUF7CR0(0x%x) = 0x%08x\n", FSPI_AHBRX_BUF7CR0, fspi_readl(FSPI_AHBRX_BUF7CR0));
+ VERBOSE("Flexspi: Register FSPI_AHB_CR(0x%x) \t = 0x%08x\n", FSPI_AHBCR, fspi_readl(FSPI_AHBCR));
+ VERBOSE("\n");
+
+ for (i = 0U; i < 4U; i++) {
+ VERBOSE("Flexspi: Register FSPI_FLSH_A1_CR2,(0x%x) = 0x%08x\n", FSPI_FLSHA1CR2 + i * 4, fspi_readl(FSPI_FLSHA1CR2 + i * 4));
+ }
+}
+#endif
+
+int fspi_init(uint32_t base_reg_addr, uint32_t flash_start_addr)
+{
+ uint32_t mcrx;
+ uint32_t flash_size;
+
+ if (fspi_base_reg_addr != 0U) {
+ INFO("FSPI is already initialized.\n");
+ return XSPI_SUCCESS;
+ }
+
+ fspi_base_reg_addr = base_reg_addr;
+ fspi_flash_base_addr = flash_start_addr;
+
+ INFO("Flexspi driver: Version v1.0\n");
+ INFO("Flexspi: Default MCR0 = 0x%08x, before reset\n", fspi_readl(FSPI_MCR0));
+ VERBOSE("Flexspi: Resetting controller...\n");
+
+ /* Reset FlexSpi Controller */
+ fspi_writel(FSPI_MCR0, FSPI_MCR0_SWRST);
+ while ((fspi_readl(FSPI_MCR0) & FSPI_MCR0_SWRST))
+ ; /* FSPI_MCR0_SWRESET_MASK */
+
+
+ /* Disable Controller Module before programming its registersi, especially MCR0 (Master Control Register0) */
+ fspi_MDIS(1);
+ /*
+ * Program MCR0 with default values, AHB Timeout(0xff), IP Timeout(0xff). {FSPI_MCR0- 0xFFFF0000}
+ */
+
+ /* Timeout wait cycle for AHB command grant */
+ mcrx = fspi_readl(FSPI_MCR0);
+ mcrx |= (uint32_t)((FSPI_MAX_TIMEOUT_AHBCMD << FSPI_MCR0_AHBGRANTWAIT_SHIFT) & (FSPI_MCR0_AHBGRANTWAIT_MASK));
+
+ /* Time out wait cycle for IP command grant*/
+ mcrx |= (uint32_t) (FSPI_MAX_TIMEOUT_IPCMD << FSPI_MCR0_IPGRANTWAIT_SHIFT) & (FSPI_MCR0_IPGRANTWAIT_MASK);
+
+ /* TODO why BE64 set BE32*/
+ mcrx |= (uint32_t) (FSPI_ENDCFG_LE64 << FSPI_MCR0_ENDCFG_SHIFT) & FSPI_MCR0_ENDCFG_MASK;
+
+ fspi_writel(FSPI_MCR0, mcrx);
+
+ /* Reset the DLL register to default value */
+ fspi_writel(FSPI_DLLACR, FSPI_DLLACR_OVRDEN);
+ fspi_writel(FSPI_DLLBCR, FSPI_DLLBCR_OVRDEN);
+
+#if ERRATA_FLASH_A050272 /* ERRATA DLL */
+ for (uint8_t delay = 100U; delay > 0U; delay--) {
+ __asm__ volatile ("nop");
+ }
+#endif
+
+ /* Configure flash control registers for different chip select */
+ flash_size = (F_FLASH_SIZE_BYTES * FLASH_NUM) / FSPI_BYTES_PER_KBYTES;
+ fspi_writel(FSPI_FLSHA1CR0, flash_size);
+ fspi_writel(FSPI_FLSHA2CR0, 0U);
+ fspi_writel(FSPI_FLSHB1CR0, 0U);
+ fspi_writel(FSPI_FLSHB2CR0, 0U);
+
+#if defined(CONFIG_FSPI_AHB)
+ fspi_init_ahb();
+#endif
+ /* RE-Enable Controller Module */
+ fspi_MDIS(0);
+ INFO("Flexspi: After MCR0 = 0x%08x,\n", fspi_readl(FSPI_MCR0));
+ fspi_setup_LUT();
+
+ /* Dump of all registers, ensure controller not disabled anymore*/
+#if defined(DEBUG_FLEXSPI)
+ fspi_dump_regs();
+#endif
+
+ INFO("Flexspi: Init done!!\n");
+
+#if DEBUG_FLEXSPI
+
+ uint32_t xspi_addr = SZ_57M;
+
+ /*
+ * Second argument of fspi_test is the size of buffer(s) passed
+ * to the function.
+ * SIZE_BUFFER defined in test_fspi.c is kept large enough to
+ * accommodate variety of sizes for regressive tests.
+ */
+ fspi_test(xspi_addr, 0x40, 0);
+ fspi_test(xspi_addr, 0x15, 2);
+ fspi_test(xspi_addr, 0x80, 0);
+ fspi_test(xspi_addr, 0x81, 0);
+ fspi_test(xspi_addr, 0x79, 3);
+
+ fspi_test(xspi_addr + 0x11, 0x15, 0);
+ fspi_test(xspi_addr + 0x11, 0x40, 0);
+ fspi_test(xspi_addr + 0xff, 0x40, 1);
+ fspi_test(xspi_addr + 0x25, 0x81, 2);
+ fspi_test(xspi_addr + 0xef, 0x6f, 3);
+
+ fspi_test((xspi_addr - F_SECTOR_ERASE_SZ), 0x229, 0);
+#endif
+
+ return XSPI_SUCCESS;
+}
diff --git a/drivers/nxp/flexspi/nor/fspi.h b/drivers/nxp/flexspi/nor/fspi.h
new file mode 100644
index 0000000..da2e269
--- /dev/null
+++ b/drivers/nxp/flexspi/nor/fspi.h
@@ -0,0 +1,385 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * FlexSpi Registers & Bits definition.
+ *
+ */
+
+#ifndef FSPI_H
+#define FSPI_H
+
+#ifndef __ASSEMBLER__
+#include <lib/mmio.h>
+
+#ifdef NXP_FSPI_BE
+#define fspi_in32(a) bswap32(mmio_read_32((uintptr_t)(a)))
+#define fspi_out32(a, v) mmio_write_32((uintptr_t)(a), bswap32(v))
+#elif defined(NXP_FSPI_LE)
+#define fspi_in32(a) mmio_read_32((uintptr_t)(a))
+#define fspi_out32(a, v) mmio_write_32((uintptr_t)(a), v)
+#else
+#error Please define FSPI register endianness
+#endif
+
+#endif
+
+/* All LE so not swap needed */
+#define FSPI_IPDATA_SWAP 0U
+#define FSPI_AHBDATA_SWAP 0U
+
+#define CONFIG_FSPI_FASTREAD 1U
+
+#define FSPI_BYTES_PER_KBYTES 0x400U
+#define FLASH_NUM 1U
+
+#define FSPI_READ_SEQ_ID 0U
+#define FSPI_WREN_SEQ_ID 1U
+#define FSPI_WRITE_SEQ_ID 2U
+#define FSPI_SE_SEQ_ID 3U
+#define FSPI_RDSR_SEQ_ID 4U
+#define FSPI_BE_SEQ_ID 5U
+#define FSPI_FASTREAD_SEQ_ID 6U
+#define FSPI_4K_SEQ_ID 7U
+
+/*
+ * LUT register layout:
+ *
+ * ---------------------------------------------------
+ * | INSTR1 | PAD1 | OPRND1 | INSTR0 | PAD0 | OPRND0 |
+ * ---------------------------------------------------
+ *
+ * INSTR_SHIFT- 10, PAD_SHIFT - 8, OPRND_SHIFT -0
+ */
+#define FSPI_INSTR_OPRND0_SHIFT 0
+#define FSPI_INSTR_OPRND0(x) (x << FSPI_INSTR_OPRND0_SHIFT)
+#define FSPI_INSTR_PAD0_SHIFT 8
+#define FSPI_INSTR_PAD0(x) ((x) << FSPI_INSTR_PAD0_SHIFT)
+#define FSPI_INSTR_OPCODE0_SHIFT 10
+#define FSPI_INSTR_OPCODE0(x) ((x) << FSPI_INSTR_OPCODE0_SHIFT)
+#define FSPI_INSTR_OPRND1_SHIFT 16
+#define FSPI_INSTR_OPRND1(x) ((x) << FSPI_INSTR_OPRND1_SHIFT)
+#define FSPI_INSTR_PAD1_SHIFT 24
+#define FSPI_INSTR_PAD1(x) ((x) << FSPI_INSTR_PAD1_SHIFT)
+#define FSPI_INSTR_OPCODE1_SHIFT 26
+#define FSPI_INSTR_OPCODE1(x) ((x) << FSPI_INSTR_OPCODE1_SHIFT)
+
+/* Instruction set for the LUT register. */
+#define LUT_STOP 0x00
+#define LUT_CMD 0x01
+#define LUT_ADDR 0x02
+#define LUT_CADDR_SDR 0x03
+#define LUT_MODE 0x04
+#define LUT_MODE2 0x05
+#define LUT_MODE4 0x06
+#define LUT_MODE8 0x07
+#define LUT_NXP_WRITE 0x08
+#define LUT_NXP_READ 0x09
+
+#define LUT_LEARN_SDR 0x0A
+#define LUT_DATSZ_SDR 0x0B
+#define LUT_DUMMY 0x0C
+#define LUT_DUMMY_RWDS_SDR 0x0D
+#define LUT_JMP_ON_CS 0x1F
+#define LUT_CMD_DDR 0x21
+#define LUT_ADDR_DDR 0x22
+#define LUT_CADDR_DDR 0x23
+#define LUT_MODE_DDR 0x24
+#define LUT_MODE2_DDR 0x25
+#define LUT_MODE4_DDR 0x26
+#define LUT_MODE8_DDR 0x27
+#define LUT_WRITE_DDR 0x28
+#define LUT_READ_DDR 0x29
+#define LUT_LEARN_DDR 0x2A
+#define LUT_DATSZ_DDR 0x2B
+#define LUT_DUMMY_DDR 0x2C
+#define LUT_DUMMY_RWDS_DDR 0x2D
+
+#define FSPI_NOR_CMD_READ 0x03
+#define FSPI_NOR_CMD_READ_4B 0x13
+#define FSPI_NOR_CMD_FASTREAD 0x0b
+#define FSPI_NOR_CMD_FASTREAD_4B 0x0c
+#define FSPI_NOR_CMD_PP 0x02
+#define FSPI_NOR_CMD_PP_4B 0x12
+#define FSPI_NOR_CMD_WREN 0x06
+#define FSPI_NOR_CMD_SE_64K 0xd8
+#define FSPI_NOR_CMD_SE_64K_4B 0xdc
+#define FSPI_NOR_CMD_SE_4K 0x20
+#define FSPI_NOR_CMD_SE_4K_4B 0x21
+#define FSPI_NOR_CMD_BE 0x60
+#define FSPI_NOR_CMD_RDSR 0x05
+#define FSPI_NOR_CMD_WREN_STOP 0x04
+
+#define FSPI_LUT_STOP 0x00
+#define FSPI_LUT_CMD 0x01
+#define FSPI_LUT_ADDR 0x02
+
+#define FSPI_LUT_PAD1 0
+#define FSPI_LUT_PAD2 1
+#define FSPI_LUT_PAD4 2
+#define FSPI_LUT_PAD8 3
+
+#define FSPI_LUT_ADDR24BIT 0x18
+#define FSPI_LUT_ADDR32BIT 0x20
+
+#define FSPI_LUT_WRITE 0x08
+#define FSPI_LUT_READ 0x09
+#define FSPI_DUMMY_SDR 0x0c
+
+/* TODO Check size if functional*/
+#define FSPI_RX_IPBUF_SIZE 0x200 /* 64*64 bits */
+#define FSPI_TX_IPBUF_SIZE 0x400 /* 128*64 bits */
+
+#define FSPI_RX_MAX_AHBBUF_SIZE 0x800 /* 256 * 64bits */
+#define FSPI_TX_MAX_AHBBUF_SIZE 0x40 /* 8 * 64bits */
+
+#define FSPI_LUTREG_OFFSET 0x200ul
+
+#define FSPI_MAX_TIMEOUT_AHBCMD 0xFFU
+#define FSPI_MAX_TIMEOUT_IPCMD 0xFF
+#define FSPI_SER_CLK_DIV 0x04
+#define FSPI_HSEN 0
+#define FSPI_ENDCFG_BE64 0x01
+#define FSPI_ENDCFG_BE32 0x03
+#define FSPI_ENDCFG_LE32 0x02
+#define FSPI_ENDCFG_LE64 0x0
+
+#define MASK_24BIT_ADDRESS 0x00ffffff
+#define MASK_32BIT_ADDRESS 0xffffffff
+
+/* Registers used by the driver */
+#define FSPI_MCR0 0x0ul
+#define FSPI_MCR0_AHB_TIMEOUT(x) ((x) << 24)
+#define FSPI_MCR0_IP_TIMEOUT(x) ((x) << 16)
+#define FSPI_MCR0_LEARN_EN BIT(15)
+#define FSPI_MCR0_SCRFRUN_EN BIT(14)
+#define FSPI_MCR0_OCTCOMB_EN BIT(13)
+#define FSPI_MCR0_DOZE_EN BIT(12)
+#define FSPI_MCR0_HSEN BIT(11)
+#define FSPI_MCR0_SERCLKDIV BIT(8)
+#define FSPI_MCR0_ATDF_EN BIT(7)
+#define FSPI_MCR0_ARDF_EN BIT(6)
+#define FSPI_MCR0_RXCLKSRC(x) ((x) << 4)
+#define FSPI_MCR0_END_CFG(x) ((x) << 2)
+#define FSPI_MCR0_MDIS BIT(1)
+#define FSPI_MCR0_SWRST BIT(0)
+
+#define FSPI_MCR0_AHBGRANTWAIT_SHIFT 24
+#define FSPI_MCR0_AHBGRANTWAIT_MASK (0xFFU << FSPI_MCR0_AHBGRANTWAIT_SHIFT)
+#define FSPI_MCR0_IPGRANTWAIT_SHIFT 16
+#define FSPI_MCR0_IPGRANTWAIT_MASK (0xFF << FSPI_MCR0_IPGRANTWAIT_SHIFT)
+#define FSPI_MCR0_HSEN_SHIFT 11
+#define FSPI_MCR0_HSEN_MASK (1 << FSPI_MCR0_HSEN_SHIFT)
+#define FSPI_MCR0_SERCLKDIV_SHIFT 8
+#define FSPI_MCR0_SERCLKDIV_MASK (7 << FSPI_MCR0_SERCLKDIV_SHIFT)
+#define FSPI_MCR0_ENDCFG_SHIFT 2
+#define FSPI_MCR0_ENDCFG_MASK (3 << FSPI_MCR0_ENDCFG_SHIFT)
+#define FSPI_MCR0_RXCLKSRC_SHIFT 4
+#define FSPI_MCR0_RXCLKSRC_MASK (3 << FSPI_MCR0_RXCLKSRC_SHIFT)
+
+#define FSPI_MCR1 0x04
+#define FSPI_MCR1_SEQ_TIMEOUT(x) ((x) << 16)
+#define FSPI_MCR1_AHB_TIMEOUT(x) (x)
+
+#define FSPI_MCR2 0x08
+#define FSPI_MCR2_IDLE_WAIT(x) ((x) << 24)
+#define FSPI_MCR2_SAMEDEVICEEN BIT(15)
+#define FSPI_MCR2_CLRLRPHS BIT(14)
+#define FSPI_MCR2_ABRDATSZ BIT(8)
+#define FSPI_MCR2_ABRLEARN BIT(7)
+#define FSPI_MCR2_ABR_READ BIT(6)
+#define FSPI_MCR2_ABRWRITE BIT(5)
+#define FSPI_MCR2_ABRDUMMY BIT(4)
+#define FSPI_MCR2_ABR_MODE BIT(3)
+#define FSPI_MCR2_ABRCADDR BIT(2)
+#define FSPI_MCR2_ABRRADDR BIT(1)
+#define FSPI_MCR2_ABR_CMD BIT(0)
+
+#define FSPI_AHBCR 0x0c
+#define FSPI_AHBCR_RDADDROPT BIT(6)
+#define FSPI_AHBCR_PREF_EN BIT(5)
+#define FSPI_AHBCR_BUFF_EN BIT(4)
+#define FSPI_AHBCR_CACH_EN BIT(3)
+#define FSPI_AHBCR_CLRTXBUF BIT(2)
+#define FSPI_AHBCR_CLRRXBUF BIT(1)
+#define FSPI_AHBCR_PAR_EN BIT(0)
+
+#define FSPI_INTEN 0x10
+#define FSPI_INTEN_SCLKSBWR BIT(9)
+#define FSPI_INTEN_SCLKSBRD BIT(8)
+#define FSPI_INTEN_DATALRNFL BIT(7)
+#define FSPI_INTEN_IPTXWE BIT(6)
+#define FSPI_INTEN_IPRXWA BIT(5)
+#define FSPI_INTEN_AHBCMDERR BIT(4)
+#define FSPI_INTEN_IPCMDERR BIT(3)
+#define FSPI_INTEN_AHBCMDGE BIT(2)
+#define FSPI_INTEN_IPCMDGE BIT(1)
+#define FSPI_INTEN_IPCMDDONE BIT(0)
+
+#define FSPI_INTR 0x14
+#define FSPI_INTR_SCLKSBWR BIT(9)
+#define FSPI_INTR_SCLKSBRD BIT(8)
+#define FSPI_INTR_DATALRNFL BIT(7)
+#define FSPI_INTR_IPTXWE BIT(6)
+#define FSPI_INTR_IPRXWA BIT(5)
+#define FSPI_INTR_AHBCMDERR BIT(4)
+#define FSPI_INTR_IPCMDERR BIT(3)
+#define FSPI_INTR_AHBCMDGE BIT(2)
+#define FSPI_INTR_IPCMDGE BIT(1)
+#define FSPI_INTR_IPCMDDONE BIT(0)
+
+#define FSPI_LUTKEY 0x18
+#define FSPI_LUTKEY_VALUE 0x5AF05AF0
+
+#define FSPI_LCKCR 0x1C
+
+#define FSPI_LCKER_LOCK 0x1
+#define FSPI_LCKER_UNLOCK 0x2
+
+#define FSPI_BUFXCR_INVALID_MSTRID 0xE
+#define FSPI_AHBRX_BUF0CR0 0x20
+#define FSPI_AHBRX_BUF1CR0 0x24
+#define FSPI_AHBRX_BUF2CR0 0x28
+#define FSPI_AHBRX_BUF3CR0 0x2C
+#define FSPI_AHBRX_BUF4CR0 0x30
+#define FSPI_AHBRX_BUF5CR0 0x34
+#define FSPI_AHBRX_BUF6CR0 0x38
+#define FSPI_AHBRX_BUF7CR0 0x3C
+
+#define FSPI_AHBRXBUF0CR7_PREF BIT(31)
+
+#define FSPI_AHBRX_BUF0CR1 0x40
+#define FSPI_AHBRX_BUF1CR1 0x44
+#define FSPI_AHBRX_BUF2CR1 0x48
+#define FSPI_AHBRX_BUF3CR1 0x4C
+#define FSPI_AHBRX_BUF4CR1 0x50
+#define FSPI_AHBRX_BUF5CR1 0x54
+#define FSPI_AHBRX_BUF6CR1 0x58
+#define FSPI_AHBRX_BUF7CR1 0x5C
+
+#define FSPI_FLSHA1CR0 0x60
+#define FSPI_FLSHA2CR0 0x64
+#define FSPI_FLSHB1CR0 0x68
+#define FSPI_FLSHB2CR0 0x6C
+#define FSPI_FLSHXCR0_SZ_KB 10
+#define FSPI_FLSHXCR0_SZ(x) ((x) >> FSPI_FLSHXCR0_SZ_KB)
+
+#define FSPI_FLSHA1CR1 0x70
+#define FSPI_FLSHA2CR1 0x74
+#define FSPI_FLSHB1CR1 0x78
+#define FSPI_FLSHB2CR1 0x7C
+#define FSPI_FLSHXCR1_CSINTR(x) ((x) << 16)
+#define FSPI_FLSHXCR1_CAS(x) ((x) << 11)
+#define FSPI_FLSHXCR1_WA BIT(10)
+#define FSPI_FLSHXCR1_TCSH(x) ((x) << 5)
+#define FSPI_FLSHXCR1_TCSS(x) (x)
+
+#define FSPI_FLSHXCR1_TCSH_SHIFT 5
+#define FSPI_FLSHXCR1_TCSH_MASK (0x1F << FSPI_FLSHXCR1_TCSH_SHIFT)
+#define FSPI_FLSHXCR1_TCSS_SHIFT 0
+#define FSPI_FLSHXCR1_TCSS_MASK (0x1F << FSPI_FLSHXCR1_TCSS_SHIFT)
+
+#define FSPI_FLSHA1CR2 0x80
+#define FSPI_FLSHA2CR2 0x84
+#define FSPI_FLSHB1CR2 0x88
+#define FSPI_FLSHB2CR2 0x8C
+#define FSPI_FLSHXCR2_CLRINSP BIT(24)
+#define FSPI_FLSHXCR2_AWRWAIT BIT(16)
+#define FSPI_FLSHXCR2_AWRSEQN_SHIFT 13
+#define FSPI_FLSHXCR2_AWRSEQI_SHIFT 8
+#define FSPI_FLSHXCR2_ARDSEQN_SHIFT 5
+#define FSPI_FLSHXCR2_ARDSEQI_SHIFT 0
+
+#define FSPI_IPCR0 0xA0
+
+#define FSPI_IPCR1 0xA4
+#define FSPI_IPCR1_IPAREN BIT(31)
+#define FSPI_IPCR1_SEQNUM_SHIFT 24
+#define FSPI_IPCR1_SEQID_SHIFT 16
+#define FSPI_IPCR1_IDATSZ(x) (x)
+
+#define FSPI_IPCMD 0xB0
+#define FSPI_IPCMD_TRG BIT(0)
+
+
+/* IP Command Register */
+#define FSPI_IPCMD_TRG_SHIFT 0
+#define FSPI_IPCMD_TRG_MASK (1 << FSPI_IPCMD_TRG_SHIFT)
+
+#define FSPI_INTR_IPRXWA_SHIFT 5
+#define FSPI_INTR_IPRXWA_MASK (1 << FSPI_INTR_IPRXWA_SHIFT)
+
+#define FSPI_INTR_IPCMDDONE_SHIFT 0
+#define FSPI_INTR_IPCMDDONE_MASK (1 << FSPI_INTR_IPCMDDONE_SHIFT)
+
+#define FSPI_INTR_IPTXWE_SHIFT 6
+#define FSPI_INTR_IPTXWE_MASK (1 << FSPI_INTR_IPTXWE_SHIFT)
+
+#define FSPI_IPTXFSTS_FILL_SHIFT 0
+#define FSPI_IPTXFSTS_FILL_MASK (0xFF << FSPI_IPTXFSTS_FILL_SHIFT)
+
+#define FSPI_IPCR1_ISEQID_SHIFT 16
+#define FSPI_IPCR1_ISEQID_MASK (0x1F << FSPI_IPCR1_ISEQID_SHIFT)
+
+#define FSPI_IPRXFSTS_FILL_SHIFT 0
+#define FSPI_IPRXFSTS_FILL_MASK (0xFF << FSPI_IPRXFSTS_FILL_SHIFT)
+
+#define FSPI_DLPR 0xB4
+
+#define FSPI_IPRXFCR 0xB8
+#define FSPI_IPRXFCR_CLR BIT(0)
+#define FSPI_IPRXFCR_DMA_EN BIT(1)
+#define FSPI_IPRXFCR_WMRK(x) ((x) << 2)
+
+#define FSPI_IPTXFCR 0xBC
+#define FSPI_IPTXFCR_CLR BIT(0)
+#define FSPI_IPTXFCR_DMA_EN BIT(1)
+#define FSPI_IPTXFCR_WMRK(x) ((x) << 2)
+
+#define FSPI_DLLACR 0xC0
+#define FSPI_DLLACR_OVRDEN BIT(8)
+
+#define FSPI_DLLBCR 0xC4
+#define FSPI_DLLBCR_OVRDEN BIT(8)
+
+#define FSPI_STS0 0xE0
+#define FSPI_STS0_DLPHB(x) ((x) << 8)
+#define FSPI_STS0_DLPHA(x) ((x) << 4)
+#define FSPI_STS0_CMD_SRC(x) ((x) << 2)
+#define FSPI_STS0_ARB_IDLE BIT(1)
+#define FSPI_STS0_SEQ_IDLE BIT(0)
+
+#define FSPI_STS1 0xE4
+#define FSPI_STS1_IP_ERRCD(x) ((x) << 24)
+#define FSPI_STS1_IP_ERRID(x) ((x) << 16)
+#define FSPI_STS1_AHB_ERRCD(x) ((x) << 8)
+#define FSPI_STS1_AHB_ERRID(x) (x)
+
+#define FSPI_AHBSPNST 0xEC
+#define FSPI_AHBSPNST_DATLFT(x) ((x) << 16)
+#define FSPI_AHBSPNST_BUFID(x) ((x) << 1)
+#define FSPI_AHBSPNST_ACTIVE BIT(0)
+
+#define FSPI_IPRXFSTS 0xF0
+#define FSPI_IPRXFSTS_RDCNTR(x) ((x) << 16)
+#define FSPI_IPRXFSTS_FILL(x) (x)
+
+#define FSPI_IPTXFSTS 0xF4
+#define FSPI_IPTXFSTS_WRCNTR(x) ((x) << 16)
+#define FSPI_IPTXFSTS_FILL(x) (x)
+
+#define FSPI_NOR_SR_WIP_SHIFT (0)
+#define FSPI_NOR_SR_WIP_MASK (1 << FSPI_NOR_SR_WIP_SHIFT)
+
+#define FSPI_RFDR 0x100
+#define FSPI_TFDR 0x180
+
+#define FSPI_LUT_BASE 0x200
+#define FSPI_LUT_OFFSET (SEQID_LUT * 4 * 4)
+#define FSPI_LUT_REG(idx) \
+ (FSPI_LUT_BASE + FSPI_LUT_OFFSET + (idx) * 4)
+
+/* register map end */
+
+#endif
diff --git a/drivers/nxp/flexspi/nor/test_fspi.c b/drivers/nxp/flexspi/nor/test_fspi.c
new file mode 100644
index 0000000..c36c5b8
--- /dev/null
+++ b/drivers/nxp/flexspi/nor/test_fspi.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <common/debug.h>
+#include <flash_info.h>
+#include "fspi.h"
+#include <fspi_api.h>
+
+/*
+ * The macros are defined to be used as test vector for testing fspi.
+ */
+#define SIZE_BUFFER 0x250
+
+/*
+ * You may choose fspi_swap based on core endianness and flexspi IP/AHB
+ * buffer endianness set in MCR.
+ */
+#define fspi_swap32(A) (A)
+
+void fspi_test(uint32_t fspi_test_addr, uint32_t size, int extra)
+{
+ uint32_t buffer[SIZE_BUFFER];
+ uint32_t count = 1;
+ uint32_t failed, i;
+
+ NOTICE("-------------------------- %d----------------------------------\n", count++);
+ INFO("Sector Erase size: 0x%08x, size: %d\n", F_SECTOR_ERASE_SZ, size);
+ /* Test Sector Erase */
+ xspi_sector_erase(fspi_test_addr - fspi_test_addr % F_SECTOR_ERASE_SZ,
+ F_SECTOR_ERASE_SZ);
+
+ /* Test Erased data using IP read */
+ xspi_ip_read((fspi_test_addr), buffer, size * 4);
+
+ failed = 0;
+ for (i = 0; i < size; i++)
+ if (fspi_swap32(0xffffffff) != buffer[i]) {
+ failed = 1;
+ break;
+ }
+
+ if (failed == 0) {
+ NOTICE("[%d]: Success Erase: data in buffer[%d] 0x%08x\n", __LINE__, i-3, buffer[i-3]);
+ } else {
+ ERROR("Erase: Failed -->xxx with buffer[%d]=0x%08x\n", i, buffer[i]);
+ }
+
+ for (i = 0; i < SIZE_BUFFER; i++)
+ buffer[i] = 0x12345678;
+
+ /* Write data from buffer to flash */
+ xspi_write(fspi_test_addr, (void *)buffer, (size * 4 + extra));
+ /* Check written data using IP read */
+ xspi_ip_read(fspi_test_addr, buffer, (size * 4 + extra));
+ failed = 0;
+ for (i = 0; i < size; i++)
+ if (fspi_swap32(0x12345678) != buffer[i]) {
+ failed = 1;
+ break;
+ }
+
+ if (failed == 0) {
+ NOTICE("[%d]: Success IpWrite with IP READ in buffer[%d] 0x%08x\n", __LINE__, i-3, buffer[i-3]);
+ } else {
+ ERROR("Write: Failed -->xxxx with IP READ in buffer[%d]=0x%08x\n", i, buffer[i]);
+ return;
+ }
+
+ /* xspi_read may use AHB read */
+ xspi_read((fspi_test_addr), buffer, (size * 4 + extra));
+ failed = 0;
+ for (i = 0; i < size; i++)
+ if (fspi_swap32(0x12345678) != buffer[i]) {
+ failed = 1;
+ break;
+ }
+
+ if (failed == 0) {
+ NOTICE("[%d]: Success IpWrite with AHB OR IP READ on buffer[%d] 0x%08x\n", __LINE__, i-3, buffer[i-3]);
+ } else {
+ ERROR("Write: Failed -->xxxx with AHB READ on buffer[%d]=0x%08x\n", i, buffer[i]);
+ return;
+ }
+}
diff --git a/drivers/nxp/gic/gic.mk b/drivers/nxp/gic/gic.mk
new file mode 100644
index 0000000..d75e071
--- /dev/null
+++ b/drivers/nxp/gic/gic.mk
@@ -0,0 +1,46 @@
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+#------------------------------------------------------------------------------
+#
+# Select the GIC files
+#
+# -----------------------------------------------------------------------------
+
+ifeq (${ADD_GIC},)
+ADD_GIC := 1
+ifeq ($(GIC), GIC400)
+include drivers/arm/gic/v2/gicv2.mk
+GIC_SOURCES += ${GICV2_SOURCES}
+GIC_SOURCES += ${PLAT_DRIVERS_PATH}/gic/ls_gicv2.c \
+ plat/common/plat_gicv2.c
+
+PLAT_INCLUDES += -I${PLAT_DRIVERS_INCLUDE_PATH}/gic/gicv2
+else
+ifeq ($(GIC), GIC500)
+include drivers/arm/gic/v3/gicv3.mk
+GIC_SOURCES += ${GICV3_SOURCES}
+GIC_SOURCES += ${PLAT_DRIVERS_PATH}/gic/ls_gicv3.c \
+ plat/common/plat_gicv3.c
+
+PLAT_INCLUDES += -I${PLAT_DRIVERS_INCLUDE_PATH}/gic/gicv3
+else
+ $(error -> GIC type not set!)
+endif
+endif
+
+ifeq (${BL_COMM_GIC_NEEDED},yes)
+BL_COMMON_SOURCES += ${GIC_SOURCES}
+else
+ifeq (${BL2_GIC_NEEDED},yes)
+BL2_SOURCES += ${GIC_SOURCES}
+endif
+ifeq (${BL31_GIC_NEEDED},yes)
+BL31_SOURCES += ${GIC_SOURCES}
+endif
+endif
+endif
+
+# -----------------------------------------------------------------------------
diff --git a/drivers/nxp/gic/ls_gicv2.c b/drivers/nxp/gic/ls_gicv2.c
new file mode 100644
index 0000000..62bc8db
--- /dev/null
+++ b/drivers/nxp/gic/ls_gicv2.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <gicv2.h>
+#include <plat_gic.h>
+
+
+/*
+ * NXP common helper to initialize the GICv3 only driver.
+ */
+void plat_ls_gic_driver_init(uintptr_t nxp_gicd_addr,
+ uintptr_t nxp_gicc_addr,
+ uint8_t plat_core_count,
+ interrupt_prop_t *ls_interrupt_props,
+ uint8_t ls_interrupt_prop_count,
+ uint32_t *target_mask_array)
+{
+ static struct gicv2_driver_data ls_gic_data;
+
+ ls_gic_data.gicd_base = nxp_gicd_addr;
+ ls_gic_data.gicc_base = nxp_gicc_addr;
+ ls_gic_data.target_masks = target_mask_array;
+ ls_gic_data.target_masks_num = plat_core_count;
+ ls_gic_data.interrupt_props = ls_interrupt_props;
+ ls_gic_data.interrupt_props_num = ls_interrupt_prop_count;
+
+ gicv2_driver_init(&ls_gic_data);
+}
+
+void plat_ls_gic_init(void)
+{
+ gicv2_distif_init();
+ gicv2_pcpu_distif_init();
+ gicv2_cpuif_enable();
+}
+
+/******************************************************************************
+ * ARM common helper to enable the GICv2 CPU interface
+ *****************************************************************************/
+void plat_ls_gic_cpuif_enable(void)
+{
+ gicv2_cpuif_enable();
+}
+
+/******************************************************************************
+ * ARM common helper to disable the GICv2 CPU interface
+ *****************************************************************************/
+void plat_ls_gic_cpuif_disable(void)
+{
+ gicv2_cpuif_disable();
+}
+
+/******************************************************************************
+ * NXP common helper to initialize GICv2 per cpu
+ *****************************************************************************/
+void plat_gic_pcpu_init(void)
+{
+ gicv2_pcpu_distif_init();
+ gicv2_cpuif_enable();
+}
+
+/******************************************************************************
+ * Stubs for Redistributor power management. Although GICv2 doesn't have
+ * Redistributor interface, these are provided for the sake of uniform GIC API
+ *****************************************************************************/
+void plat_ls_gic_redistif_on(void)
+{
+}
+
+void plat_ls_gic_redistif_off(void)
+{
+}
diff --git a/drivers/nxp/gic/ls_gicv3.c b/drivers/nxp/gic/ls_gicv3.c
new file mode 100644
index 0000000..9c02bd6
--- /dev/null
+++ b/drivers/nxp/gic/ls_gicv3.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <drivers/arm/gicv3.h>
+#include <plat_gic.h>
+#include <plat/common/platform.h>
+
+/*
+ * NXP common helper to initialize the GICv3 only driver.
+ */
+void plat_ls_gic_driver_init(uintptr_t nxp_gicd_addr,
+ uintptr_t nxp_gicr_addr,
+ uint8_t plat_core_count,
+ interrupt_prop_t *ls_interrupt_props,
+ uint8_t ls_interrupt_prop_count,
+ uintptr_t *target_mask_array,
+ mpidr_hash_fn mpidr_to_core_pos)
+{
+ static struct gicv3_driver_data ls_gic_data;
+
+ ls_gic_data.gicd_base = nxp_gicd_addr;
+ ls_gic_data.gicr_base = nxp_gicr_addr;
+ ls_gic_data.interrupt_props = ls_interrupt_props;
+ ls_gic_data.interrupt_props_num = ls_interrupt_prop_count;
+ ls_gic_data.rdistif_num = plat_core_count;
+ ls_gic_data.rdistif_base_addrs = target_mask_array;
+ ls_gic_data.mpidr_to_core_pos = mpidr_to_core_pos;
+
+ gicv3_driver_init(&ls_gic_data);
+}
+
+void plat_ls_gic_init(void)
+{
+ gicv3_distif_init();
+ gicv3_rdistif_init(plat_my_core_pos());
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/*
+ * NXP common helper to enable the GICv3 CPU interface
+ */
+void plat_ls_gic_cpuif_enable(void)
+{
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/*
+ * NXP common helper to disable the GICv3 CPU interface
+ */
+void plat_ls_gic_cpuif_disable(void)
+{
+ gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+/*
+ * NXP common helper to initialize the per cpu distributor interface in GICv3
+ */
+void plat_gic_pcpu_init(void)
+{
+ gicv3_rdistif_init(plat_my_core_pos());
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/*
+ * Stubs for Redistributor power management. Although GICv3 doesn't have
+ * Redistributor interface, these are provided for the sake of uniform GIC API
+ */
+void plat_ls_gic_redistif_on(void)
+{
+}
+
+void plat_ls_gic_redistif_off(void)
+{
+}
diff --git a/drivers/nxp/gpio/gpio.mk b/drivers/nxp/gpio/gpio.mk
new file mode 100644
index 0000000..74f0dc4
--- /dev/null
+++ b/drivers/nxp/gpio/gpio.mk
@@ -0,0 +1,28 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-----------------------------------------------------------------------------
+
+ifeq (${GPIO_ADDED},)
+
+GPIO_ADDED := 1
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/gpio
+
+GPIO_SOURCES := $(PLAT_DRIVERS_PATH)/gpio/nxp_gpio.c
+
+ifeq (${BL_COMM_GPIO_NEEDED},yes)
+BL_COMMON_SOURCES += ${GPIO_SOURCES}
+else
+ifeq (${BL2_GPIO_NEEDED},yes)
+BL2_SOURCES += ${GPIO_SOURCES}
+endif
+ifeq (${BL31_GPIO_NEEDED},yes)
+BL31_SOURCES += ${GPIO_SOURCES}
+endif
+endif
+
+endif
+#------------------------------------------------
diff --git a/drivers/nxp/gpio/nxp_gpio.c b/drivers/nxp/gpio/nxp_gpio.c
new file mode 100644
index 0000000..28c9db9
--- /dev/null
+++ b/drivers/nxp/gpio/nxp_gpio.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <nxp_gpio.h>
+
+static gpio_init_info_t *gpio_init_info;
+
+void gpio_init(gpio_init_info_t *gpio_init_data)
+{
+ gpio_init_info = gpio_init_data;
+}
+
+/* This function set GPIO pin for raising POVDD. */
+int set_gpio_bit(uint32_t *gpio_base_addr,
+ uint32_t bit_num)
+{
+ uint32_t val = 0U;
+ uint32_t *gpdir = NULL;
+ uint32_t *gpdat = NULL;
+
+ if (gpio_init_info == NULL) {
+ ERROR("GPIO is not initialized.\n");
+ return GPIO_FAILURE;
+ }
+
+ gpdir = gpio_base_addr + GPDIR_REG_OFFSET;
+ gpdat = gpio_base_addr + (GPDAT_REG_OFFSET >> 2);
+
+ /*
+ * Set the corresponding bit in direction register
+ * to configure the GPIO as output.
+ */
+ val = gpio_read32(gpdir);
+ val = val | bit_num;
+ gpio_write32(gpdir, val);
+
+ /* Set the corresponding bit in GPIO data register */
+ val = gpio_read32(gpdat);
+ val = val | bit_num;
+ gpio_write32(gpdat, val);
+
+ val = gpio_read32(gpdat);
+
+ if ((val & bit_num) == 0U) {
+ return GPIO_FAILURE;
+ }
+
+ return GPIO_SUCCESS;
+}
+
+/* This function reset GPIO pin set for raising POVDD. */
+int clr_gpio_bit(uint32_t *gpio_base_addr, uint32_t bit_num)
+{
+ uint32_t val = 0U;
+ uint32_t *gpdir = NULL;
+ uint32_t *gpdat = NULL;
+
+
+ if (gpio_init_info == NULL) {
+ ERROR("GPIO is not initialized.\n");
+ return GPIO_FAILURE;
+ }
+
+ gpdir = gpio_base_addr + GPDIR_REG_OFFSET;
+ gpdat = gpio_base_addr + GPDAT_REG_OFFSET;
+
+ /*
+ * Reset the corresponding bit in direction and data register
+ * to configure the GPIO as input.
+ */
+ val = gpio_read32(gpdat);
+ val = val & ~(bit_num);
+ gpio_write32(gpdat, val);
+
+ val = gpio_read32(gpdat);
+
+ val = gpio_read32(gpdir);
+ val = val & ~(bit_num);
+ gpio_write32(gpdir, val);
+
+ val = gpio_read32(gpdat);
+
+ if ((val & bit_num) != 0U) {
+ return GPIO_FAILURE;
+ }
+
+ return GPIO_SUCCESS;
+}
+
+uint32_t *select_gpio_n_bitnum(uint32_t povdd_gpio, uint32_t *bit_num)
+{
+ uint32_t *ret_gpio;
+ uint32_t povdd_gpio_val = 0U;
+ uint32_t gpio_num = 0U;
+
+ if (gpio_init_info == NULL) {
+ ERROR("GPIO is not initialized.\n");
+ }
+ /*
+ * Subtract 1 from fuse_hdr povdd_gpio value as
+ * for 0x1 value, bit 0 is to be set
+ * for 0x20 value i.e 32, bit 31 i.e. 0x1f is to be set.
+ * 0x1f - 0x00 : GPIO_1
+ * 0x3f - 0x20 : GPIO_2
+ * 0x5f - 0x40 : GPIO_3
+ * 0x7f - 0x60 : GPIO_4
+ */
+ povdd_gpio_val = (povdd_gpio - 1U) & GPIO_SEL_MASK;
+
+ /* Right shift by 5 to divide by 32 */
+ gpio_num = povdd_gpio_val >> GPIO_ID_BASE_ADDR_SHIFT;
+ *bit_num = 1U << (GPIO_BITS_PER_BASE_REG
+ - (povdd_gpio_val & GPIO_BIT_MASK)
+ - 1U);
+
+ switch (gpio_num) {
+ case GPIO_0:
+ ret_gpio = (uint32_t *) gpio_init_info->gpio1_base_addr;
+ break;
+ case GPIO_1:
+ ret_gpio = (uint32_t *) gpio_init_info->gpio2_base_addr;
+ break;
+ case GPIO_2:
+ ret_gpio = (uint32_t *) gpio_init_info->gpio3_base_addr;
+ break;
+ case GPIO_3:
+ ret_gpio = (uint32_t *) gpio_init_info->gpio4_base_addr;
+ break;
+ default:
+ ret_gpio = NULL;
+ }
+
+ if (ret_gpio == NULL) {
+ INFO("GPIO_NUM = %d doesn't exist.\n", gpio_num);
+ }
+
+ return ret_gpio;
+}
diff --git a/drivers/nxp/i2c/i2c.c b/drivers/nxp/i2c/i2c.c
new file mode 100644
index 0000000..9281409
--- /dev/null
+++ b/drivers/nxp/i2c/i2c.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2016-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include "i2c.h"
+#include <nxp_timer.h>
+
+static uintptr_t g_nxp_i2c_addr;
+
+void i2c_init(uintptr_t nxp_i2c_addr)
+{
+ struct ls_i2c *ccsr_i2c = (void *)nxp_i2c_addr;
+
+ g_nxp_i2c_addr = nxp_i2c_addr;
+ /* Presume workaround for erratum a009203 applied */
+ i2c_out(&ccsr_i2c->cr, I2C_CR_DIS);
+ i2c_out(&ccsr_i2c->fd, I2C_FD_CONSERV);
+ i2c_out(&ccsr_i2c->sr, I2C_SR_RST);
+ i2c_out(&ccsr_i2c->cr, I2C_CR_EN);
+}
+
+static int wait_for_state(struct ls_i2c *ccsr_i2c,
+ unsigned char state, unsigned char mask)
+{
+ unsigned char sr;
+ uint64_t start_time = get_timer_val(0);
+ uint64_t timer;
+
+ do {
+ sr = i2c_in(&ccsr_i2c->sr);
+ if (sr & I2C_SR_AL) {
+ i2c_out(&ccsr_i2c->sr, sr);
+ WARN("I2C arbitration lost\n");
+ return -EIO;
+ }
+ if ((sr & mask) == state) {
+ return (int)sr;
+ }
+
+ timer = get_timer_val(start_time);
+ if (timer > I2C_TIMEOUT)
+ break;
+ mdelay(1);
+ } while (1);
+ WARN("I2C: Timeout waiting for state 0x%x, sr = 0x%x\n", state, sr);
+
+ return -ETIMEDOUT;
+}
+
+static int tx_byte(struct ls_i2c *ccsr_i2c, unsigned char c)
+{
+ int ret;
+
+ i2c_out(&ccsr_i2c->sr, I2C_SR_IF);
+ i2c_out(&ccsr_i2c->dr, c);
+ ret = wait_for_state(ccsr_i2c, I2C_SR_IF, I2C_SR_IF);
+ if (ret < 0) {
+ WARN("%s: state error\n", __func__);
+ return ret;
+ }
+ if (ret & I2C_SR_RX_NAK) {
+ WARN("%s: nodev\n", __func__);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int gen_stop(struct ls_i2c *ccsr_i2c)
+{
+ unsigned char cr;
+ int ret;
+
+ cr = i2c_in(&ccsr_i2c->cr);
+ cr &= ~(I2C_CR_MA | I2C_CR_TX);
+ i2c_out(&ccsr_i2c->cr, cr);
+ ret = wait_for_state(ccsr_i2c, I2C_SR_IDLE, I2C_SR_BB);
+ if (ret < 0) {
+ WARN("I2C: Generating stop failed.\n");
+ }
+ return ret;
+}
+
+static int i2c_write_addr(struct ls_i2c *ccsr_i2c, unsigned char chip,
+ int addr, int alen)
+{
+ int ret;
+ unsigned char cr;
+
+ if (alen != 1) {
+ WARN("I2C: Unsupported address len [%d]\n", alen);
+ return -EIO;
+ }
+
+ if (i2c_in(&ccsr_i2c->ad) == (chip << 1)) {
+ WARN("I2C: slave address same as self\n");
+ return -ENODEV;
+ }
+ i2c_out(&ccsr_i2c->sr, I2C_SR_IF);
+ ret = wait_for_state(ccsr_i2c, I2C_SR_IDLE, I2C_SR_BB);
+ if (ret < 0) {
+ return ret;
+ }
+
+ cr = i2c_in(&ccsr_i2c->cr);
+ cr |= I2C_CR_MA;
+ i2c_out(&ccsr_i2c->cr, cr);
+ ret = wait_for_state(ccsr_i2c, I2C_SR_BB, I2C_SR_BB);
+ if (ret < 0) {
+ return ret;
+ }
+
+ VERBOSE("Before writing chip %d\n", chip);
+ cr |= I2C_CR_TX | I2C_CR_TX_NAK;
+ i2c_out(&ccsr_i2c->cr, cr);
+ ret = tx_byte(ccsr_i2c, chip << 1);
+ if (ret < 0) {
+ gen_stop(ccsr_i2c);
+ return ret;
+ }
+
+ VERBOSE("Before writing addr\n");
+ while (alen--) {
+ ret = tx_byte(ccsr_i2c, (addr >> (alen << 3)) & 0xff);
+ if (ret < 0) {
+ gen_stop(ccsr_i2c);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int read_data(struct ls_i2c *ccsr_i2c, unsigned char chip,
+ unsigned char *buf, int len)
+{
+ int i;
+ int ret;
+ unsigned char cr;
+
+ cr = i2c_in(&ccsr_i2c->cr);
+ cr &= ~(I2C_CR_TX | I2C_CR_TX_NAK);
+ if (len == 1) {
+ cr |= I2C_CR_TX_NAK;
+ }
+ i2c_out(&ccsr_i2c->cr, cr);
+ i2c_out(&ccsr_i2c->sr, I2C_SR_IF);
+ i2c_in(&ccsr_i2c->dr); /* dummy read */
+ for (i = 0; i < len; i++) {
+ ret = wait_for_state(ccsr_i2c, I2C_SR_IF, I2C_SR_IF);
+ if (ret < 0) {
+ gen_stop(ccsr_i2c);
+ return ret;
+ }
+ if (i == (len - 1)) {
+ gen_stop(ccsr_i2c);
+ } else if (i == (len - 2)) {
+ /* Updating the command to send
+ * No ACK.
+ */
+ cr = i2c_in(&ccsr_i2c->cr);
+ cr |= I2C_CR_TX_NAK;
+ i2c_out(&ccsr_i2c->cr, cr);
+ }
+ i2c_out(&ccsr_i2c->sr, I2C_SR_IF);
+ buf[i] = i2c_in(&ccsr_i2c->dr);
+ }
+
+ return 0;
+}
+
+static int write_data(struct ls_i2c *ccsr_i2c, unsigned char chip,
+ const unsigned char *buf, int len)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < len; i++) {
+ ret = tx_byte(ccsr_i2c, buf[i]);
+ if (ret < 0) {
+ break;
+ }
+ }
+ ret = gen_stop(ccsr_i2c);
+
+ return ret;
+}
+
+
+int i2c_read(unsigned char chip, int addr, int alen,
+ unsigned char *buf, int len)
+{
+ int ret;
+ unsigned char cr;
+ struct ls_i2c *ccsr_i2c = (void *)g_nxp_i2c_addr;
+
+ ret = i2c_write_addr(ccsr_i2c, chip, addr, alen);
+ if (ret < 0) {
+ gen_stop(ccsr_i2c);
+ return ret;
+ }
+
+ cr = i2c_in(&ccsr_i2c->cr);
+ cr |= I2C_CR_RSTA;
+ i2c_out(&ccsr_i2c->cr, cr);
+
+ ret = tx_byte(ccsr_i2c, (chip << 1) | 1);
+ if (ret < 0) {
+ gen_stop(ccsr_i2c);
+ return ret;
+ }
+
+ return read_data(ccsr_i2c, chip, buf, len);
+}
+
+int i2c_write(unsigned char chip, int addr, int alen,
+ const unsigned char *buf, int len)
+{
+ int ret;
+ struct ls_i2c *ccsr_i2c = (void *)g_nxp_i2c_addr;
+
+ ret = i2c_write_addr(ccsr_i2c, chip, addr, alen);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return write_data(ccsr_i2c, chip, buf, len);
+}
+
+int i2c_probe_chip(unsigned char chip)
+{
+ int ret;
+ struct ls_i2c *ccsr_i2c = (void *)g_nxp_i2c_addr;
+
+ ret = i2c_write_addr(ccsr_i2c, chip, 0, 0);
+ if (ret < 0) {
+ WARN("write addr failed\n");
+ return ret;
+ }
+
+ ret = gen_stop(ccsr_i2c);
+ if (ret < 0) {
+ WARN("I2C: Probe not complete.\n");
+ }
+
+ return ret;
+}
diff --git a/drivers/nxp/i2c/i2c.mk b/drivers/nxp/i2c/i2c.mk
new file mode 100644
index 0000000..716e14a
--- /dev/null
+++ b/drivers/nxp/i2c/i2c.mk
@@ -0,0 +1,25 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${ADD_I2C},)
+
+ADD_I2C := 1
+
+I2C_SOURCES += $(PLAT_DRIVERS_PATH)/i2c/i2c.c
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/i2c
+
+ifeq (${BL_COMM_I2C_NEEDED},yes)
+BL_COMMON_SOURCES += ${I2C_SOURCES}
+else
+ifeq (${BL2_I2C_NEEDED},yes)
+BL2_SOURCES += ${I2C_SOURCES}
+endif
+ifeq (${BL31_I2C_NEEDED},yes)
+BL31_SOURCES += ${I2C_SOURCES}
+endif
+endif
+endif
diff --git a/drivers/nxp/ifc/nand/ifc.h b/drivers/nxp/ifc/nand/ifc.h
new file mode 100644
index 0000000..56c5f92
--- /dev/null
+++ b/drivers/nxp/ifc/nand/ifc.h
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IFC_H
+#define IFC_H
+
+#include <endian.h>
+
+#include <mmio.h>
+
+#define NXP_IFC_RUN_TIME_ADDR U(0x1000)
+
+/* CPSR - Chip Select Property Register Offset */
+#define EXT_CSPR(n) (U(0x000C) + (n * 0xC))
+#define CSPR(n) (U(0x0010) + (n * 0xC))
+#define CSOR(n) (U(0x0130) + (n * 0xC))
+#define EXT_CSOR(n) (U(0x0134) + (n * 0xC))
+#define IFC_AMASK_CS0 U(0x00A0)
+
+/* NAND specific Registers Offset */
+#define NCFGR (NXP_IFC_RUN_TIME_ADDR + U(0x0000))
+#define NAND_FCR0 (NXP_IFC_RUN_TIME_ADDR + U(0x0014))
+
+#define ROW0 (NXP_IFC_RUN_TIME_ADDR + U(0x003C))
+#define ROW1 (NXP_IFC_RUN_TIME_ADDR + U(0x004C))
+#define COL0 (NXP_IFC_RUN_TIME_ADDR + U(0x0044))
+#define COL1 (NXP_IFC_RUN_TIME_ADDR + U(0x0054))
+
+#define NAND_BC (NXP_IFC_RUN_TIME_ADDR + U(0x0108))
+#define NAND_FIR0 (NXP_IFC_RUN_TIME_ADDR + U(0x0110))
+#define NAND_FIR1 (NXP_IFC_RUN_TIME_ADDR + U(0x0114))
+#define NAND_FIR2 (NXP_IFC_RUN_TIME_ADDR + U(0x0118))
+#define NAND_CSEL (NXP_IFC_RUN_TIME_ADDR + U(0x015C))
+#define NANDSEQ_STRT (NXP_IFC_RUN_TIME_ADDR + U(0x0164))
+#define NAND_EVTER_STAT (NXP_IFC_RUN_TIME_ADDR + U(0x016C))
+#define NAND_AUTOBOOT_TRGR (NXP_IFC_RUN_TIME_ADDR + U(0x0284))
+
+/* Size of SRAM Buffer */
+#define CSPR_PS U(0x00000180)
+#define CSPR_PS_SHIFT 7
+#define CSPR_PS_8 0x1 // Port Size 8 bit
+#define CSPR_PS_16 0x2 // Port Size 16 bit
+#define CSPR_PS_32 0x3 // Port Size 32 bit
+
+/* Chip Select Option Register NAND Machine */
+#define CSOR_NAND_PGS U(0x00380000)
+#define CSOR_NAND_PGS_SHIFT 19
+#define CSOR_NAND_PGS_512 U(0x00000000)
+#define CSOR_NAND_PGS_2K U(0x00080000)
+#define CSOR_NAND_PGS_4K U(0x00100000)
+#define CSOR_NAND_PGS_8K U(0x00180000)
+#define CSOR_NAND_PGS_16K U(0x00200000)
+
+
+#define CSOR_NAND_PB U(0x00000700)
+#define CSOR_NAND_PB_32 U(0x00000000)
+#define CSOR_NAND_PB_64 U(0x00000100)
+#define CSOR_NAND_PB_128 U(0x00000200)
+#define CSOR_NAND_PB_256 U(0x00000300)
+#define CSOR_NAND_PB_512 U(0x00000400)
+#define CSOR_NAND_PB_1024 U(0x00000500)
+#define CSOR_NAND_PB_2048 U(0x00000600)
+#define CSOR_NAND_PPB_32 32
+#define CSOR_NAND_PPB_64 64
+#define CSOR_NAND_PPB_128 128
+#define CSOR_NAND_PPB_256 256
+#define CSOR_NAND_PPB_512 512
+#define CSOR_NAND_PPB_1024 1024
+#define CSOR_NAND_PPB_2048 2048
+
+/* NAND Chip select register */
+#define NAND_CSEL_SHIFT 26
+#define NAND_COL_MS_SHIFT 31
+
+/* FCR - Flash Command Register */
+#define FCR_CMD0 U(0xFF000000)
+#define FCR_CMD0_SHIFT 24
+#define FCR_CMD1 U(0x00FF0000)
+#define FCR_CMD1_SHIFT 16
+#define FCR_CMD2 U(0x0000FF00)
+#define FCR_CMD2_SHIFT 8
+#define FCR_CMD3 U(0x000000FF)
+#define FCR_CMD3_SHIFT 0
+
+/* FIR - Flash Instruction Register Opcode */
+#define FIR_OP0 U(0xFC000000)
+#define FIR_OP0_SHIFT 26
+#define FIR_OP1 U(0x03F00000)
+#define FIR_OP1_SHIFT 20
+#define FIR_OP2 U(0x000FC000)
+#define FIR_OP2_SHIFT 14
+#define FIR_OP3 U(0x00003F00)
+#define FIR_OP3_SHIFT 8
+#define FIR_OP4 U(0x000000FC)
+#define FIR_OP4_SHIFT 2
+#define FIR_OP5 U(0xFC000000)
+#define FIR_OP5_SHIFT 26
+#define FIR_OP6 U(0x03F00000)
+#define FIR_OP6_SHIFT 20
+
+/* Instruction Opcode - 6 bits */
+#define FIR_OP_NOP 0x00
+#define FIR_OP_CA0 0x01 /* Issue current column address */
+#define FIR_OP_CA1 0x02 /* Issue current column address */
+#define FIR_OP_RA0 0x05 /* Issue current column address */
+#define FIR_OP_RA1 0x06 /* Issue current column address */
+#define FIR_OP_CMD0 0x09 /* Issue command from FCR[CMD0] */
+#define FIR_OP_CMD1 0x0a /* Issue command from FCR[CMD1] */
+#define FIR_OP_CMD2 0x0b /* Issue command from FCR[CMD2] */
+#define FIR_OP_CMD3 0x0c /* Issue command from FCR[CMD3] */
+#define FIR_OP_CW0 0x11 /* Wait then issue FCR[CMD0] */
+#define FIR_OP_CW1 0x12 /* Wait then issue FCR[CMD1] */
+#define FIR_OP_CW2 0x13 /* Wait then issue FCR[CMD1] */
+#define FIR_OP_CW3 0x14 /* Wait then issue FCR[CMD1] */
+#define FIR_OP_WBCD 0x19 /* Wait then read FBCR bytes */
+#define FIR_OP_RBCD 0x1a /* Wait then read 1 or 2 bytes */
+#define FIR_OP_BTRD 0x1b /* Wait then read 1 or 2 bytes */
+#define FIR_OP_RDSTAT 0x1c /* Wait then read 1 or 2 bytes */
+#define FIR_OP_NWAIT 0x1d /* Wait then read 1 or 2 bytes */
+#define FIR_OP_WFR 0x1e /* Wait then read 1 or 2 bytes */
+
+#define NAND_SEQ_STRT_FIR_STRT U(0x80000000)
+#define NAND_SEQ_STRT_FIR_STRT_SHIFT 31
+
+#define NAND_EVTER_STAT_FTOER U(0x08000000)
+#define NAND_EVTER_STAT_WPER U(0x04000000)
+#define NAND_EVTER_STAT_ECCER U(0x02000000)
+#define NAND_EVTER_STAT_DQSER U(0x01000000)
+#define NAND_EVTER_STAT_RCW_DN U(0x00008000)
+#define NAND_EVTER_STAT_BOOT_DN U(0x00004000)
+#define NAND_EVTER_STAT_RCW_DN U(0x00008000)
+#define NAND_EVTER_STAT_OPC_DN U(0x80000000)
+#define NAND_EVTER_STAT_BBI_SRCH_SEL U(0x00000800)
+#define NCFGR_BOOT U(0x80000000)
+#define NAND_AUTOBOOT_TRGR_RCW_LD U(0x80000000)
+#define NAND_AUTOBOOT_TRGR_BOOT_LD U(0x20000000)
+
+/* ECC ERROR STATUS Registers */
+#define NAND_RCW_LD U(0x80000000)
+#define NAND_BOOT_LD U(0x20000000)
+
+/*Other Temp Defines */
+/*256 bad Blocks supported */
+#define BBT_SIZE 256
+
+/*Standard NAND flash commands */
+#define NAND_CMD_READ0 0
+#define NAND_CMD_READ1 1
+#define NAND_CMD_READOOB 0x50
+
+/*Extended commands for large page devices */
+#define NAND_CMD_READSTART 0x30
+
+#define NAND_TIMEOUT_MS 40
+
+#define EMPTY_VAL_CHECK U(0xFFFFFFFF)
+#define EMPTY_VAL 0xFF
+
+
+#define MAIN 0
+#define SPARE 1
+
+#define GOOD_BLK 1
+#define BAD_BLK 0
+#define DIV_2 2
+
+#define ATTRIBUTE_PGSZ 0xa
+#define ATTRIBUTE_PPB 0xb
+
+#define CSPR_PORT_SIZE_8 (0x1 << 7)
+#define CSPR_PORT_SIZE_16 (0x2 << 7)
+#define CSPR_PORT_SIZE_32 (0x3 << 7)
+
+/* NAND specific */
+#define RCW_SRC_NAND_PORT_MASK U(0x00000080)
+
+#define NAND_DEFAULT_CSPR U(0x00000053)
+#define NAND_DEFAULT_CSOR U(0x0180C00C)
+#define NAND_DEFAULT_EXT_CSPR U(0x00000000)
+#define NAND_DEFAULT_EXT_CSOR U(0x00000000)
+#define NAND_DEFAULT_FTIM0 U(0x181c0c10)
+#define NAND_DEFAULT_FTIM1 U(0x5454141e)
+#define NAND_DEFAULT_FTIM2 U(0x03808034)
+#define NAND_DEFAULT_FTIM3 U(0x2c000000)
+
+#define NAND_CSOR_ECC_MODE_DISABLE U(0x00000000)
+#define NAND_CSOR_ECC_MODE0 U(0x84000000)
+#define NAND_CSOR_ECC_MODE1 U(0x94000000)
+#define NAND_CSOR_ECC_MODE2 U(0xa4000000)
+#define NAND_CSOR_ECC_MODE3 U(0xb4000000)
+#define NAND_CSOR_PAGE_SIZE_2K (0x1 << 19)
+#define NAND_CSOR_PAGE_SIZE_4K (0x2 << 19)
+#define NAND_CSOR_PAGE_SIZE_8K (0x3 << 19)
+#define NAND_CSOR_PAGE_SIZE_16K (0x4 << 19)
+#define NAND_CSOR_PPB_64 (0x1 << 8)
+#define NAND_CSOR_PPB_128 (0x2 << 8)
+#define NAND_CSOR_PPB_256 (0x3 << 8)
+#define NAND_CSOR_PPB_512 (0x4 << 8)
+
+/* BBI INDICATOR for NAND_2K(CFG_RCW_SRC[1]) for
+ * devices greater than 2K page size(CFG_RCW_SRC[3])
+ */
+#define RCW_SRC_NAND_BBI_MASK U(0x00000008)
+#define RCW_SRC_NAND_BBI_MASK_NAND_2K U(0x00000002)
+#define NAND_BBI_ONFI_2K (0x1 << 1)
+#define NAND_BBI_ONFI (0x1 << 3)
+
+#define RCW_SRC_NAND_PAGE_MASK U(0x00000070)
+#define RCW_SRC_NAND_PAGE_MASK_NAND_2K U(0x0000000C)
+#define NAND_2K_XXX 0x00
+#define NAND_2K_64 0x04
+#define NAND_2K_128 0x08
+#define NAND_4K_128 0x10
+#define NAND_4K_256 0x20
+#define NAND_4K_512 0x30
+#define NAND_8K_128 0x40
+#define NAND_8K_256 0x50
+#define NAND_8K_512 0x60
+#define NAND_16K_512 0x70
+#define BLOCK_LEN_2K 2048
+
+#define RCW_SRC_NAND_ECC_MASK U(0x00000007)
+#define RCW_SRC_NAND_ECC_MASK_NAND_2K U(0x00000001)
+#define NAND_ECC_DISABLE 0x0
+#define NAND_ECC_4_520 0x1
+#define NAND_ECC_8_528 0x5
+#define NAND_ECC_24_1K 0x6
+#define NAND_ECC_40_1K 0x7
+
+#define NAND_SPARE_2K U(0x00000040)
+#define NAND_SPARE_4K_ECC_M0 U(0x00000080)
+#define NAND_SPARE_4K_ECC_M1 U(0x000000D2)
+#define NAND_SPARE_4K_ECC_M2 U(0x000000B0)
+#define NAND_SPARE_4K_ECC_M3 U(0x00000120)
+#define NAND_SPARE_8K_ECC_M0 U(0x00000088)
+#define NAND_SPARE_8K_ECC_M1 U(0x00000108)
+#define NAND_SPARE_8K_ECC_M2 U(0x00000158)
+#define NAND_SPARE_8K_ECC_M3 U(0x00000238)
+#define NAND_SPARE_16K_ECC_M0 U(0x00000108)
+#define NAND_SPARE_16K_ECC_M1 U(0x00000208)
+#define NAND_SPARE_16K_ECC_M2 U(0x000002A8)
+#define NAND_SPARE_16K_ECC_M3 U(0x00000468)
+
+struct nand_info {
+ uintptr_t ifc_register_addr;
+ uintptr_t ifc_region_addr;
+ uint32_t page_size;
+ uint32_t port_size;
+ uint32_t blk_size;
+ uint32_t ppb;
+ uint32_t pi_width; /* Bits Required to index a page in block */
+ uint32_t ral;
+ uint32_t ibr_flow;
+ uint32_t bbt[BBT_SIZE];
+ uint32_t lgb; /* Last Good Block */
+ uint32_t bbt_max; /* Total entries in bbt */
+ uint32_t bzero_good;
+ uint8_t bbs;
+ uint8_t bad_marker_loc;
+ uint8_t onfi_dev_flag;
+ uint8_t init_time_boot_flag;
+ uint8_t *buf;
+};
+
+struct ifc_regs {
+ uint32_t ext_cspr;
+ uint32_t cspr;
+ uint32_t csor;
+ uint32_t ext_csor;
+};
+
+struct sec_nand_info {
+ uint32_t cspr_port_size;
+ uint32_t csor_ecc_mode;
+ uint32_t csor_page_size;
+ uint32_t csor_ppb;
+ uint32_t ext_csor_spare_size;
+ uint32_t onfi_flag;
+};
+
+struct sec_nor_info {
+ uint32_t cspr_port_size;
+ uint32_t csor_nor_mode;
+ uint32_t csor_adm_shift;
+ uint32_t port_size;
+ uint32_t addr_bits;
+};
+
+enum ifc_chip_sel {
+ IFC_CS0,
+ IFC_CS1,
+ IFC_CS2,
+ IFC_CS3,
+ IFC_CS4,
+ IFC_CS5,
+ IFC_CS6,
+ IFC_CS7,
+};
+
+enum ifc_ftims {
+ IFC_FTIM0,
+ IFC_FTIM1,
+ IFC_FTIM2,
+ IFC_FTIM3,
+};
+
+#ifdef NXP_IFC_BE
+#define nand_in32(a) bswap32(mmio_read_32((uintptr_t)a))
+#define nand_out32(a, v) mmio_write_32((uintptr_t)a, bswap32(v))
+#else
+#define nand_in32(a) mmio_read_32((uintptr_t)a)
+#define nand_out32(a, v) mmio_write_32((uintptr_t)a, v)
+#endif
+
+/* Read Write on IFC registers */
+static inline void write_reg(struct nand_info *nand, uint32_t reg, uint32_t val)
+{
+ nand_out32(nand->ifc_register_addr + reg, val);
+}
+
+static inline uint32_t read_reg(struct nand_info *nand, uint32_t reg)
+{
+ return nand_in32(nand->ifc_register_addr + reg);
+}
+
+#endif /* IFC_H */
diff --git a/drivers/nxp/ifc/nand/ifc_nand.c b/drivers/nxp/ifc/nand/ifc_nand.c
new file mode 100644
index 0000000..1f7092a
--- /dev/null
+++ b/drivers/nxp/ifc/nand/ifc_nand.c
@@ -0,0 +1,658 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_block.h>
+#include "ifc.h"
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <nxp_timer.h>
+
+/* Private structure for NAND driver data */
+static struct nand_info nand_drv_data;
+
+static int update_bbt(uint32_t idx, uint32_t blk, uint32_t *updated,
+ struct nand_info *nand);
+
+static int nand_wait(struct nand_info *nand)
+{
+ int timeout = 1;
+ uint32_t neesr;
+ unsigned long start_time;
+
+ start_time = get_timer_val(0);
+
+ while (get_timer_val(start_time) < NAND_TIMEOUT_MS) {
+ /* clear the OPC event */
+ neesr = read_reg(nand, NAND_EVTER_STAT);
+ if (neesr & NAND_EVTER_STAT_OPC_DN) {
+ write_reg(nand, NAND_EVTER_STAT, neesr);
+ timeout = 0;
+
+ /* check for other errors */
+ if (neesr & NAND_EVTER_STAT_FTOER) {
+ ERROR("%s NAND_EVTER_STAT_FTOER occurs\n",
+ __func__);
+ return -1;
+ } else if (neesr & NAND_EVTER_STAT_ECCER) {
+ ERROR("%s NAND_EVTER_STAT_ECCER occurs\n",
+ __func__);
+ return -1;
+ } else if (neesr & NAND_EVTER_STAT_DQSER) {
+ ERROR("%s NAND_EVTER_STAT_DQSER occurs\n",
+ __func__);
+ return -1;
+ }
+
+ break;
+ }
+ }
+
+ if (timeout) {
+ ERROR("%s ERROR_NAND_TIMEOUT occurs\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static uint32_t nand_get_port_size(struct nand_info *nand)
+{
+ uint32_t port_size = U(0);
+ uint32_t cs_reg;
+ uint32_t cur_cs;
+
+ cur_cs = U(0);
+ cs_reg = CSPR(cur_cs);
+ port_size = (read_reg(nand, cs_reg) & CSPR_PS) >> CSPR_PS_SHIFT;
+ switch (port_size) {
+ case CSPR_PS_8:
+ port_size = U(8);
+ break;
+ case CSPR_PS_16:
+ port_size = U(16);
+ break;
+ case CSPR_PS_32:
+ port_size = U(32);
+ break;
+ default:
+ port_size = U(8);
+ }
+
+ return port_size;
+}
+
+static uint32_t nand_get_page_size(struct nand_info *nand)
+{
+ uint32_t pg_size;
+ uint32_t cs_reg;
+ uint32_t cur_cs;
+
+ cur_cs = 0;
+ cs_reg = CSOR(cur_cs);
+ pg_size = read_reg(nand, cs_reg) & CSOR_NAND_PGS;
+ switch (pg_size) {
+ case CSOR_NAND_PGS_2K:
+ pg_size = U(2048);
+ break;
+ case CSOR_NAND_PGS_4K:
+ pg_size = U(4096);
+ break;
+ case CSOR_NAND_PGS_8K:
+ pg_size = U(8192);
+ break;
+ case CSOR_NAND_PGS_16K:
+ pg_size = U(16384);
+ break;
+ default:
+ pg_size = U(512);
+ }
+
+ return pg_size;
+}
+
+static uint32_t nand_get_pages_per_blk(struct nand_info *nand)
+{
+ uint32_t pages_per_blk;
+ uint32_t cs_reg;
+ uint32_t cur_cs;
+
+ cur_cs = 0;
+ cs_reg = CSOR(cur_cs);
+ pages_per_blk = (read_reg(nand, cs_reg) & CSOR_NAND_PB);
+ switch (pages_per_blk) {
+ case CSOR_NAND_PB_32:
+ pages_per_blk = U(32);
+ break;
+ case CSOR_NAND_PB_64:
+ pages_per_blk = U(64);
+ break;
+ case CSOR_NAND_PB_128:
+ pages_per_blk = U(128);
+ break;
+ case CSOR_NAND_PB_256:
+ pages_per_blk = U(256);
+ break;
+ case CSOR_NAND_PB_512:
+ pages_per_blk = U(512);
+ break;
+ case CSOR_NAND_PB_1024:
+ pages_per_blk = U(1024);
+ break;
+ case CSOR_NAND_PB_2048:
+ pages_per_blk = U(2048);
+ break;
+ default:
+ pages_per_blk = U(0);
+ }
+
+ return pages_per_blk;
+}
+
+static uint32_t get_page_index_width(uint32_t ppb)
+{
+ switch (ppb) {
+ case CSOR_NAND_PPB_32:
+ return U(5);
+ case CSOR_NAND_PPB_64:
+ return U(6);
+ case CSOR_NAND_PPB_128:
+ return U(7);
+ case CSOR_NAND_PPB_256:
+ return U(8);
+ case CSOR_NAND_PPB_512:
+ return U(9);
+ case CSOR_NAND_PPB_1024:
+ return U(10);
+ case CSOR_NAND_PPB_2048:
+ return U(11);
+ default:
+ return U(5);
+ }
+}
+
+static void nand_get_params(struct nand_info *nand)
+{
+ nand->port_size = nand_get_port_size(nand);
+
+ nand->page_size = nand_get_page_size(nand);
+
+ /*
+ * Set Bad marker Location for LP / SP
+ * Small Page : 8 Bit : 0x5
+ * Small Page : 16 Bit : 0xa
+ * Large Page : 8 /16 Bit : 0x0
+ */
+ nand->bad_marker_loc = (nand->page_size == 512) ?
+ ((nand->port_size == 8) ? 0x5 : 0xa) : 0;
+
+ /* check for the device is ONFI compliant or not */
+ nand->onfi_dev_flag =
+ (read_reg(nand, NAND_EVTER_STAT) & NAND_EVTER_STAT_BBI_SRCH_SEL)
+ ? 1 : 0;
+
+ /* NAND Blk serached count for incremental Bad block search cnt */
+ nand->bbs = 0;
+
+ /* pages per Block */
+ nand->ppb = nand_get_pages_per_blk(nand);
+
+ /* Blk size */
+ nand->blk_size = nand->page_size * nand->ppb;
+
+ /* get_page_index_width */
+ nand->pi_width = get_page_index_width(nand->ppb);
+
+ /* bad block table init */
+ nand->lgb = 0;
+ nand->bbt_max = 0;
+ nand->bzero_good = 0;
+ memset(nand->bbt, EMPTY_VAL, BBT_SIZE * sizeof(nand->bbt[0]));
+}
+
+static int nand_init(struct nand_info *nand)
+{
+ uint32_t ncfgr = 0;
+
+ /* Get nand Parameters from IFC */
+ nand_get_params(nand);
+
+ /* Clear all errors */
+ write_reg(nand, NAND_EVTER_STAT, U(0xffffffff));
+
+ /*
+ * Disable autoboot in NCFGR. Mapping will change from
+ * physical to logical for SRAM buffer
+ */
+ ncfgr = read_reg(nand, NCFGR);
+ write_reg(nand, NCFGR, (ncfgr & ~NCFGR_BOOT));
+
+ return 0;
+}
+
+static int nand_read_data(
+ uintptr_t ifc_region_addr,
+ uint32_t row_add,
+ uint32_t col_add,
+ uint32_t byte_cnt,
+ uint8_t *data,
+ uint32_t main_spare,
+ struct nand_info *nand)
+{
+ uint32_t page_size_add_bits = U(0);
+ uint32_t page_add_in_actual, page_add;
+ uintptr_t sram_addr_calc;
+ int ret;
+ uint32_t col_val;
+
+ /* Programming MS bit to read from spare area.*/
+ col_val = (main_spare << NAND_COL_MS_SHIFT) | col_add;
+
+ write_reg(nand, NAND_BC, byte_cnt);
+
+ write_reg(nand, ROW0, row_add);
+ write_reg(nand, COL0, col_val);
+
+ /* Program FCR for small Page */
+ if (nand->page_size == U(512)) {
+ if (byte_cnt == 0 ||
+ (byte_cnt != 0 && main_spare == 0 && col_add <= 255)) {
+ write_reg(nand, NAND_FCR0,
+ (NAND_CMD_READ0 << FCR_CMD0_SHIFT));
+ } else if (main_spare == 0) {
+ write_reg(nand, NAND_FCR0,
+ (NAND_CMD_READ1 << FCR_CMD0_SHIFT));
+ } else {
+ write_reg(nand, NAND_FCR0,
+ (NAND_CMD_READOOB << FCR_CMD0_SHIFT));
+ }
+
+ } else {
+ /* Program FCR for Large Page */
+ write_reg(nand, NAND_FCR0, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
+ (NAND_CMD_READSTART << FCR_CMD1_SHIFT));
+ }
+ if (nand->page_size == U(512)) {
+ write_reg(nand, NAND_FIR0, ((FIR_OP_CW0 << FIR_OP0_SHIFT) |
+ (FIR_OP_CA0 << FIR_OP1_SHIFT) |
+ (FIR_OP_RA0 << FIR_OP2_SHIFT) |
+ (FIR_OP_BTRD << FIR_OP3_SHIFT) |
+ (FIR_OP_NOP << FIR_OP4_SHIFT)));
+ write_reg(nand, NAND_FIR1, U(0x00000000));
+ } else {
+ write_reg(nand, NAND_FIR0, ((FIR_OP_CW0 << FIR_OP0_SHIFT) |
+ (FIR_OP_CA0 << FIR_OP1_SHIFT) |
+ (FIR_OP_RA0 << FIR_OP2_SHIFT) |
+ (FIR_OP_CMD1 << FIR_OP3_SHIFT) |
+ (FIR_OP_BTRD << FIR_OP4_SHIFT)));
+
+ write_reg(nand, NAND_FIR1, (FIR_OP_NOP << FIR_OP5_SHIFT));
+ }
+ write_reg(nand, NANDSEQ_STRT, NAND_SEQ_STRT_FIR_STRT);
+
+ ret = nand_wait(nand);
+ if (ret != 0)
+ return ret;
+
+ /* calculate page_size_add_bits i.e bits
+ * in sram address corresponding to area
+ * within a page for sram
+ */
+ if (nand->page_size == U(512))
+ page_size_add_bits = U(10);
+ else if (nand->page_size == U(2048))
+ page_size_add_bits = U(12);
+ else if (nand->page_size == U(4096))
+ page_size_add_bits = U(13);
+ else if (nand->page_size == U(8192))
+ page_size_add_bits = U(14);
+ else if (nand->page_size == U(16384))
+ page_size_add_bits = U(15);
+
+ page_add = row_add;
+
+ page_add_in_actual = (page_add << page_size_add_bits) & U(0x0000FFFF);
+
+ if (byte_cnt == 0)
+ col_add = U(0);
+
+ /* Calculate SRAM address for main and spare area */
+ if (main_spare == 0)
+ sram_addr_calc = ifc_region_addr | page_add_in_actual | col_add;
+ else
+ sram_addr_calc = ifc_region_addr | page_add_in_actual |
+ (col_add + nand->page_size);
+
+ /* Depending Byte_count copy full page or partial page from SRAM */
+ if (byte_cnt == 0)
+ memcpy(data, (void *)sram_addr_calc,
+ nand->page_size);
+ else
+ memcpy(data, (void *)sram_addr_calc, byte_cnt);
+
+ return 0;
+}
+
+static int nand_read(struct nand_info *nand, int32_t src_addr,
+ uintptr_t dst, uint32_t size)
+{
+ uint32_t log_blk = U(0);
+ uint32_t pg_no = U(0);
+ uint32_t col_off = U(0);
+ uint32_t row_off = U(0);
+ uint32_t byte_cnt = U(0);
+ uint32_t read_cnt = U(0);
+ uint32_t i = U(0);
+ uint32_t updated = U(0);
+
+ int ret = 0;
+ uint8_t *out = (uint8_t *)dst;
+
+ uint32_t pblk;
+
+ /* loop till size */
+ while (size) {
+ log_blk = (src_addr / nand->blk_size);
+ pg_no = ((src_addr - (log_blk * nand->blk_size)) /
+ nand->page_size);
+ pblk = log_blk;
+
+ // iterate the bbt to find the block
+ for (i = 0; i <= nand->bbt_max; i++) {
+ if (nand->bbt[i] == EMPTY_VAL_CHECK) {
+ ret = update_bbt(i, pblk, &updated, nand);
+
+ if (ret != 0)
+ return ret;
+ /*
+ * if table not updated and we reached
+ * end of table
+ */
+ if (!updated)
+ break;
+ }
+
+ if (pblk < nand->bbt[i])
+ break;
+ else if (pblk >= nand->bbt[i])
+ pblk++;
+ }
+
+ col_off = (src_addr % nand->page_size);
+ if (col_off) {
+ if ((col_off + size) < nand->page_size)
+ byte_cnt = size;
+ else
+ byte_cnt = nand->page_size - col_off;
+
+ row_off = (pblk << nand->pi_width) | pg_no;
+
+ ret = nand_read_data(
+ nand->ifc_region_addr,
+ row_off,
+ col_off,
+ byte_cnt, out, MAIN, nand);
+
+ if (ret != 0)
+ return ret;
+ } else {
+ /*
+ * fullpage/Partial Page
+ * if byte_cnt = 0 full page
+ * else partial page
+ */
+ if (size < nand->page_size) {
+ byte_cnt = size;
+ read_cnt = size;
+ } else {
+ byte_cnt = nand->page_size;
+ read_cnt = 0;
+ }
+ row_off = (pblk << nand->pi_width) | pg_no;
+
+ ret = nand_read_data(
+ nand->ifc_region_addr,
+ row_off,
+ 0,
+ read_cnt, out, MAIN, nand);
+
+ if (ret != 0) {
+ ERROR("Error from nand-read_data %d\n", ret);
+ return ret;
+ }
+ }
+ src_addr += byte_cnt;
+ out += byte_cnt;
+ size -= byte_cnt;
+ }
+ return 0;
+}
+
+static int isgoodblock(uint32_t blk, uint32_t *gb, struct nand_info *nand)
+{
+ uint8_t buf[2];
+ int ret;
+ uint32_t row_add;
+
+ *gb = 0;
+
+ /* read Page 0 of blk */
+ ret = nand_read_data(
+ nand->ifc_region_addr,
+ blk << nand->pi_width,
+ nand->bad_marker_loc,
+ 0x2, buf, 1, nand);
+
+ if (ret != 0)
+ return ret;
+
+ /* For ONFI devices check Page 0 and Last page of block for
+ * Bad Marker and for NON-ONFI Page 0 and 1 for Bad Marker
+ */
+ row_add = (blk << nand->pi_width);
+ if (nand->port_size == 8) {
+ /* port size is 8 Bit */
+ /* check if page 0 has 0xff */
+ if (buf[0] == 0xff) {
+ /* check page 1 */
+ if (nand->onfi_dev_flag)
+ ret = nand_read_data(
+ nand->ifc_region_addr,
+ row_add | (nand->ppb - 1),
+ nand->bad_marker_loc,
+ 0x2, buf, SPARE, nand);
+ else
+ ret = nand_read_data(
+ nand->ifc_region_addr,
+ row_add | 1,
+ nand->bad_marker_loc,
+ 0x2, buf, SPARE, nand);
+
+ if (ret != 0)
+ return ret;
+
+ if (buf[0] == 0xff)
+ *gb = GOOD_BLK;
+ else
+ *gb = BAD_BLK;
+ } else {
+ /* no, so it is bad blk */
+ *gb = BAD_BLK;
+ }
+ } else {
+ /* Port size 16-Bit */
+ /* check if page 0 has 0xffff */
+ if ((buf[0] == 0xff) &&
+ (buf[1] == 0xff)) {
+ /* check page 1 for 0xffff */
+ if (nand->onfi_dev_flag) {
+ ret = nand_read_data(
+ nand->ifc_region_addr,
+ row_add | (nand->ppb - 1),
+ nand->bad_marker_loc,
+ 0x2, buf, SPARE, nand);
+ } else {
+ ret = nand_read_data(
+ nand->ifc_region_addr,
+ row_add | 1,
+ nand->bad_marker_loc,
+ 0x2, buf, SPARE, nand);
+ }
+
+ if (ret != 0)
+ return ret;
+
+ if ((buf[0] == 0xff) &&
+ (buf[1] == 0xff)) {
+ *gb = GOOD_BLK;
+ } else {
+ *gb = BAD_BLK;
+ }
+ } else {
+ /* no, so it is bad blk */
+ *gb = BAD_BLK;
+ }
+ }
+ return 0;
+}
+
+static int update_bbt(uint32_t idx, uint32_t blk,
+ uint32_t *updated, struct nand_info *nand)
+{
+ uint32_t sblk;
+ uint32_t lgb;
+ int ret;
+
+ if (nand->bzero_good && blk == 0)
+ return 0;
+
+ /* special case for lgb == 0 */
+ /* if blk <= lgb retrun */
+ if (nand->lgb != 0 && blk <= nand->lgb)
+ return 0;
+
+ *updated = 0;
+
+ /* if blk is more than lgb, iterate from lgb till a good block
+ * is found for blk
+ */
+
+ if (nand->lgb < blk)
+ sblk = nand->lgb;
+ else
+ /* this is when lgb = 0 */
+ sblk = blk;
+
+
+ lgb = nand->lgb;
+
+ /* loop from blk to find a good block */
+ while (1) {
+ while (lgb <= sblk) {
+ uint32_t gb = 0;
+
+ ret = isgoodblock(lgb, &gb, nand);
+ if (ret != 0)
+ return ret;
+
+ /* special case block 0 is good then set this flag */
+ if (lgb == 0 && gb == GOOD_BLK)
+ nand->bzero_good = 1;
+
+ if (gb == BAD_BLK) {
+ if (idx >= BBT_SIZE) {
+ ERROR("NAND BBT Table full\n");
+ return -1;
+ }
+ *updated = 1;
+ nand->bbt[idx] = lgb;
+ idx++;
+ blk++;
+ sblk++;
+ if (idx > nand->bbt_max)
+ nand->bbt_max = idx;
+ }
+ lgb++;
+ }
+ /* the access block found */
+ if (sblk == blk) {
+ /* when good block found update lgb */
+ nand->lgb = blk;
+ break;
+ }
+ sblk++;
+ }
+
+ return 0;
+}
+
+static size_t ifc_nand_read(int lba, uintptr_t buf, size_t size)
+{
+ int ret;
+ uint32_t page_size;
+ uint32_t src_addr;
+ struct nand_info *nand = &nand_drv_data;
+
+ page_size = nand_get_page_size(nand);
+ src_addr = lba * page_size;
+ ret = nand_read(nand, src_addr, buf, size);
+ return ret ? 0 : size;
+}
+
+static struct io_block_dev_spec ifc_nand_spec = {
+ .buffer = {
+ .offset = 0,
+ .length = 0,
+ },
+ .ops = {
+ .read = ifc_nand_read,
+ },
+ /*
+ * Default block size assumed as 2K
+ * Would be updated based on actual size
+ */
+ .block_size = UL(2048),
+};
+
+int ifc_nand_init(uintptr_t *block_dev_spec,
+ uintptr_t ifc_region_addr,
+ uintptr_t ifc_register_addr,
+ size_t ifc_sram_size,
+ uintptr_t ifc_nand_blk_offset,
+ size_t ifc_nand_blk_size)
+{
+ struct nand_info *nand = NULL;
+ int ret;
+
+ nand = &nand_drv_data;
+ memset(nand, 0, sizeof(struct nand_info));
+
+ nand->ifc_region_addr = ifc_region_addr;
+ nand->ifc_register_addr = ifc_register_addr;
+
+ VERBOSE("nand_init\n");
+ ret = nand_init(nand);
+ if (ret) {
+ ERROR("nand init failed\n");
+ return ret;
+ }
+
+ ifc_nand_spec.buffer.offset = ifc_nand_blk_offset;
+ ifc_nand_spec.buffer.length = ifc_nand_blk_size;
+
+ ifc_nand_spec.block_size = nand_get_page_size(nand);
+
+ VERBOSE("Page size is %ld\n", ifc_nand_spec.block_size);
+
+ *block_dev_spec = (uintptr_t)&ifc_nand_spec;
+
+ /* Adding NAND SRAM< Buffer in XLAT Table */
+ mmap_add_region(ifc_region_addr, ifc_region_addr,
+ ifc_sram_size, MT_DEVICE | MT_RW);
+
+ return 0;
+}
diff --git a/drivers/nxp/ifc/nand/ifc_nand.mk b/drivers/nxp/ifc/nand/ifc_nand.mk
new file mode 100644
index 0000000..890fd23
--- /dev/null
+++ b/drivers/nxp/ifc/nand/ifc_nand.mk
@@ -0,0 +1,29 @@
+#
+# Copyright 2022 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${NAND_ADDED},)
+
+NAND_ADDED := 1
+
+NAND_DRIVERS_PATH := ${PLAT_DRIVERS_PATH}/ifc/nand
+
+NAND_SOURCES := $(NAND_DRIVERS_PATH)/ifc_nand.c \
+ drivers/io/io_block.c
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/ifc
+
+ifeq (${BL_COMM_IFC_NAND_NEEDED},yes)
+BL_COMMON_SOURCES += ${NAND_SOURCES}
+else
+ifeq (${BL2_IFC_NAND_NEEDED},yes)
+BL2_SOURCES += ${NAND_SOURCES}
+endif
+ifeq (${BL31_IFC_NAND_NEEDED},yes)
+BL31_SOURCES += ${NAND_SOURCES}
+endif
+endif
+
+endif
diff --git a/drivers/nxp/ifc/nor/ifc_nor.c b/drivers/nxp/ifc/nor/ifc_nor.c
new file mode 100644
index 0000000..24fc308
--- /dev/null
+++ b/drivers/nxp/ifc/nor/ifc_nor.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2020-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+int ifc_nor_init(uintptr_t flash_addr, size_t flash_size)
+{
+ /* Adding NOR Memory Map in XLAT Table */
+ mmap_add_region(flash_addr, flash_addr, flash_size, MT_MEMORY | MT_RW);
+
+ return 0;
+}
diff --git a/drivers/nxp/ifc/nor/ifc_nor.mk b/drivers/nxp/ifc/nor/ifc_nor.mk
new file mode 100644
index 0000000..0022a81
--- /dev/null
+++ b/drivers/nxp/ifc/nor/ifc_nor.mk
@@ -0,0 +1,28 @@
+#
+# Copyright 2020-2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${NOR_ADDED},)
+
+NOR_ADDED := 1
+
+NOR_DRIVERS_PATH := ${PLAT_DRIVERS_PATH}/ifc/nor
+
+NOR_SOURCES := $(NOR_DRIVERS_PATH)/ifc_nor.c
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/ifc
+
+ifeq (${BL_COMM_IFC_NOR_NEEDED},yes)
+BL_COMMON_SOURCES += ${NOR_SOURCES}
+else
+ifeq (${BL2_IFC_NOR_NEEDED},yes)
+BL2_SOURCES += ${NOR_SOURCES}
+endif
+ifeq (${BL31_IFC_NOR_NEEDED},yes)
+BL31_SOURCES += ${NOR_SOURCES}
+endif
+endif
+
+endif
diff --git a/drivers/nxp/interconnect/interconnect.mk b/drivers/nxp/interconnect/interconnect.mk
new file mode 100644
index 0000000..aa51be4
--- /dev/null
+++ b/drivers/nxp/interconnect/interconnect.mk
@@ -0,0 +1,44 @@
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+#------------------------------------------------------------------------------
+#
+# Select the Interconnect files
+#
+# -----------------------------------------------------------------------------
+
+ifeq (${ADD_INTERCONNECT},)
+
+ADD_INTERCONNECT := 1
+PLAT_INCLUDES += -I${PLAT_DRIVERS_INCLUDE_PATH}/interconnect
+
+ifeq (, $(filter $(INTERCONNECT), CCI400 CCN502 CCN504 CCN508))
+ $(error -> Interconnect type not set!)
+else
+$(eval $(call add_define_val,INTERCONNECT,${INTERCONNECT}))
+ifeq ($(INTERCONNECT), $(filter $(INTERCONNECT), CCN502 CCN504 CCN508))
+INTERCONNECT_SOURCES := drivers/arm/ccn/ccn.c \
+ ${PLAT_DRIVERS_PATH}/interconnect/ls_ccn.c
+else
+ifeq ($(INTERCONNECT), CCI400)
+INTERCONNECT_SOURCES := drivers/arm/cci/cci.c \
+ ${PLAT_DRIVERS_PATH}/interconnect/ls_cci.c
+endif
+endif
+endif
+
+ifeq (${BL_COMM_INTERCONNECT_NEEDED},yes)
+BL_COMMON_SOURCES += ${INTERCONNECT_SOURCES}
+else
+ifeq (${BL2_INTERCONNECT_NEEDED},yes)
+BL2_SOURCES += ${INTERCONNECT_SOURCES}
+endif
+ifeq (${BL31_INTERCONNECT_NEEDED},yes)
+BL31_SOURCES += ${INTERCONNECT_SOURCES}
+endif
+endif
+endif
+
+# -----------------------------------------------------------------------------
diff --git a/drivers/nxp/interconnect/ls_cci.c b/drivers/nxp/interconnect/ls_cci.c
new file mode 100644
index 0000000..72a898a
--- /dev/null
+++ b/drivers/nxp/interconnect/ls_cci.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <arch.h>
+#include <cci.h>
+
+#include <plat_arm.h>
+
+/******************************************************************************
+ * 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_enter_coherency
+#pragma weak plat_arm_interconnect_exit_coherency
+
+/******************************************************************************
+ * Helper function to place current master into coherency
+ *****************************************************************************/
+void plat_ls_interconnect_enter_coherency(unsigned int num_clusters)
+{
+ cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+
+ for (uint32_t index = 1U; index < num_clusters; index++) {
+ cci_enable_snoop_dvm_reqs(index);
+ }
+}
+
+/******************************************************************************
+ * Helper function to remove current master from coherency
+ *****************************************************************************/
+void plat_ls_interconnect_exit_coherency(void)
+{
+ cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
diff --git a/drivers/nxp/interconnect/ls_ccn.c b/drivers/nxp/interconnect/ls_ccn.c
new file mode 100644
index 0000000..8f90325
--- /dev/null
+++ b/drivers/nxp/interconnect/ls_ccn.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <arch.h>
+#include <ccn.h>
+
+#include <plat_arm.h>
+
+/******************************************************************************
+ * Helper function to place current master into coherency
+ *****************************************************************************/
+void plat_ls_interconnect_enter_coherency(unsigned int num_clusters)
+{
+ ccn_enter_snoop_dvm_domain(1ULL << MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+
+ for (uint32_t index = 1U; index < num_clusters; index++) {
+ ccn_enter_snoop_dvm_domain(1ULL << index);
+ }
+}
+
+/******************************************************************************
+ * Helper function to remove current master from coherency
+ *****************************************************************************/
+void plat_ls_interconnect_exit_coherency(void)
+{
+ ccn_exit_snoop_dvm_domain(1ULL << MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
diff --git a/drivers/nxp/pmu/pmu.c b/drivers/nxp/pmu/pmu.c
new file mode 100644
index 0000000..2a907c8
--- /dev/null
+++ b/drivers/nxp/pmu/pmu.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <dcfg.h>
+#include <lib/mmio.h>
+#include <pmu.h>
+
+void enable_timer_base_to_cluster(uintptr_t nxp_pmu_addr)
+{
+ uint32_t *cltbenr = NULL;
+ uint32_t cltbenr_val = 0U;
+
+ cltbenr = (uint32_t *)(nxp_pmu_addr
+ + CLUST_TIMER_BASE_ENBL_OFFSET);
+
+ cltbenr_val = mmio_read_32((uintptr_t)cltbenr);
+
+ cltbenr_val = cltbenr_val
+ | (1 << MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+
+ mmio_write_32((uintptr_t)cltbenr, cltbenr_val);
+
+ VERBOSE("Enable cluster time base\n");
+}
+
+/*
+ * Enable core timebase. In certain Layerscape SoCs, the clock for each core's
+ * has an enable bit in the PMU Physical Core Time Base Enable
+ * Register (PCTBENR), which allows the watchdog to operate.
+ */
+
+void enable_core_tb(uintptr_t nxp_pmu_addr)
+{
+ uint32_t *pctbenr = (uint32_t *) (nxp_pmu_addr +
+ CORE_TIMEBASE_ENBL_OFFSET);
+
+ mmio_write_32((uintptr_t)pctbenr, 0xff);
+}
diff --git a/drivers/nxp/pmu/pmu.mk b/drivers/nxp/pmu/pmu.mk
new file mode 100644
index 0000000..8d2ef07
--- /dev/null
+++ b/drivers/nxp/pmu/pmu.mk
@@ -0,0 +1,26 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-----------------------------------------------------------------------------
+ifeq (${PMU_ADDED},)
+
+PMU_ADDED := 1
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/pmu
+
+PMU_SOURCES += $(PLAT_DRIVERS_PATH)/pmu/pmu.c
+
+ifeq (${BL_COMM_PMU_NEEDED},yes)
+BL_COMMON_SOURCES += ${PMU_SOURCES}
+else
+ifeq (${BL2_PMU_NEEDED},yes)
+BL2_SOURCES += ${PMU_SOURCES}
+endif
+ifeq (${BL31_PMU_NEEDED},yes)
+BL31_SOURCES += ${PMU_SOURCES}
+endif
+endif
+endif
+#------------------------------------------------
diff --git a/drivers/nxp/qspi/qspi.c b/drivers/nxp/qspi/qspi.c
new file mode 100644
index 0000000..97b2a19
--- /dev/null
+++ b/drivers/nxp/qspi/qspi.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <qspi.h>
+
+int qspi_io_setup(uintptr_t nxp_qspi_flash_addr,
+ size_t nxp_qspi_flash_size,
+ uintptr_t fip_offset)
+{
+ uint32_t qspi_mcr_val = qspi_in32(CHS_QSPI_MCR);
+
+ /* Enable and change endianness of QSPI IP */
+ qspi_out32(CHS_QSPI_MCR, (qspi_mcr_val | CHS_QSPI_64LE));
+
+ /* Adding QSPI Memory Map in XLAT Table */
+ mmap_add_region(nxp_qspi_flash_addr, nxp_qspi_flash_addr,
+ nxp_qspi_flash_size, MT_MEMORY | MT_RW);
+
+ return 0;
+}
diff --git a/drivers/nxp/qspi/qspi.mk b/drivers/nxp/qspi/qspi.mk
new file mode 100644
index 0000000..450aeca
--- /dev/null
+++ b/drivers/nxp/qspi/qspi.mk
@@ -0,0 +1,26 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${QSPI_ADDED},)
+
+QSPI_ADDED := 1
+
+QSPI_SOURCES := $(PLAT_DRIVERS_PATH)/qspi/qspi.c
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/qspi
+
+ifeq (${BL_COMM_QSPI_NEEDED},yes)
+BL_COMMON_SOURCES += ${QSPI_SOURCES}
+else
+ifeq (${BL2_QSPI_NEEDED},yes)
+BL2_SOURCES += ${QSPI_SOURCES}
+endif
+ifeq (${BL31_QSPI_NEEDED},yes)
+BL31_SOURCES += ${QSPI_SOURCES}
+endif
+endif
+
+endif
diff --git a/drivers/nxp/sd/sd_mmc.c b/drivers/nxp/sd/sd_mmc.c
new file mode 100644
index 0000000..f7f48e7
--- /dev/null
+++ b/drivers/nxp/sd/sd_mmc.c
@@ -0,0 +1,1496 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ *
+ */
+
+#include <endian.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/io/io_block.h>
+#include "nxp_timer.h"
+#include "sd_mmc.h"
+#include <utils.h>
+#include <utils_def.h>
+
+
+/* Private structure for MMC driver data */
+static struct mmc mmc_drv_data;
+
+#ifndef NXP_POLICY_OTA
+/*
+ * For NXP_POLICY_OTA, SD needs to do R/W on OCRAM. OCRAM is secure memory at
+ * default. SD can only do non-secure DMA. Configuring SD to work in PIO mode
+ * instead of DMA mode will make SD R/W on OCRAM available.
+ */
+/* To debug without dma comment this MACRO */
+#define NXP_SD_DMA_CAPABILITY
+#endif
+#define SD_TIMEOUT 1000 /* ms */
+#define SD_TIMEOUT_HIGH 20000 /* ms */
+#define SD_BLOCK_TIMEOUT 8 /* ms */
+
+#define ERROR_ESDHC_CARD_DETECT_FAIL -1
+#define ERROR_ESDHC_UNUSABLE_CARD -2
+#define ERROR_ESDHC_COMMUNICATION_ERROR -3
+#define ERROR_ESDHC_BLOCK_LENGTH -4
+#define ERROR_ESDHC_DMA_ERROR -5
+#define ERROR_ESDHC_BUSY -6
+
+/***************************************************************
+ * Function : set_speed
+ * Arguments : mmc - Pointer to mmc struct
+ * clock - Clock Value to be set
+ * Return : void
+ * Description : Calculates the value of SDCLKFS and DVS to be set
+ * for getting the required clock assuming the base_clk
+ * as a fixed value (MAX_PLATFORM_CLOCK)
+ *****************************************************************/
+static void set_speed(struct mmc *mmc, uint32_t clock)
+{
+ /* sdhc_clk = (base clock) / [(SDCLKFS × 2) × (DVS +1)] */
+
+ uint32_t dvs = 1U;
+ uint32_t sdclkfs = 2U;
+ /* TBD - Change this to actual platform clock by reading via RCW */
+ uint32_t base_clk = MAX_PLATFORM_CLOCK;
+
+ if (base_clk / 16 > clock) {
+ for (sdclkfs = 2U; sdclkfs < 256U; sdclkfs *= 2U) {
+ if ((base_clk / sdclkfs) <= (clock * 16)) {
+ break;
+ }
+ }
+ }
+
+ for (dvs = 1U; dvs <= 16U; dvs++) {
+ if ((base_clk / (dvs * sdclkfs)) <= clock) {
+ break;
+ }
+ }
+
+ sdclkfs >>= 1U;
+ dvs -= 1U;
+
+ esdhc_out32(&mmc->esdhc_regs->sysctl,
+ (ESDHC_SYSCTL_DTOCV(TIMEOUT_COUNTER_SDCLK_2_27) |
+ ESDHC_SYSCTL_SDCLKFS(sdclkfs) | ESDHC_SYSCTL_DVS(dvs) |
+ ESDHC_SYSCTL_SDCLKEN));
+}
+
+/***************************************************************************
+ * Function : esdhc_init
+ * Arguments : mmc - Pointer to mmc struct
+ * card_detect - flag to indicate if card insert needs
+ * to be detected or not. For SDHC2 controller, Card detect
+ * is not present, so this field will be false
+ * Return : SUCCESS or Error Code
+ * Description : 1. Set Initial Clock Speed
+ * 2. Card Detect if not eMMC
+ * 3. Enable Controller Clock
+ * 4. Send 80 ticks for card to power up
+ * 5. Set LE mode and Bus Width as 1 bit.
+ ***************************************************************************/
+static int esdhc_init(struct mmc *mmc, bool card_detect)
+{
+ uint32_t val;
+ uint64_t start_time;
+
+ /* Reset the entire host controller */
+ val = esdhc_in32(&mmc->esdhc_regs->sysctl) | ESDHC_SYSCTL_RSTA;
+ esdhc_out32(&mmc->esdhc_regs->sysctl, val);
+
+ /* Wait until the controller is available */
+ start_time = get_timer_val(0);
+ while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
+ val = esdhc_in32(&mmc->esdhc_regs->sysctl) & ESDHC_SYSCTL_RSTA;
+ if (val == 0U) {
+ break;
+ }
+ }
+
+ val = esdhc_in32(&mmc->esdhc_regs->sysctl) &
+ (ESDHC_SYSCTL_RSTA);
+ if (val != 0U) {
+ ERROR("SD Reset failed\n");
+ return ERROR_ESDHC_BUSY;
+ }
+
+ /* Set initial clock speed */
+ set_speed(mmc, CARD_IDENTIFICATION_FREQ);
+
+ if (card_detect) {
+ /* Check CINS in prsstat register */
+ val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
+ ESDHC_PRSSTAT_CINS;
+ if (val == 0) {
+ ERROR("CINS not set in prsstat\n");
+ return ERROR_ESDHC_CARD_DETECT_FAIL;
+ }
+ }
+
+ /* Enable controller clock */
+ val = esdhc_in32(&mmc->esdhc_regs->sysctl) | ESDHC_SYSCTL_SDCLKEN;
+ esdhc_out32(&mmc->esdhc_regs->sysctl, val);
+
+ /* Send 80 clock ticks for the card to power up */
+ val = esdhc_in32(&mmc->esdhc_regs->sysctl) | ESDHC_SYSCTL_INITA;
+ esdhc_out32(&mmc->esdhc_regs->sysctl, val);
+
+ start_time = get_timer_val(0);
+ while (get_timer_val(start_time) < SD_TIMEOUT) {
+ val = esdhc_in32(&mmc->esdhc_regs->sysctl) & ESDHC_SYSCTL_INITA;
+ if (val != 0U) {
+ break;
+ }
+ }
+
+ val = esdhc_in32(&mmc->esdhc_regs->sysctl) & ESDHC_SYSCTL_INITA;
+ if (val == 0U) {
+ ERROR("Failed to power up the card\n");
+ return ERROR_ESDHC_CARD_DETECT_FAIL;
+ }
+
+ INFO("Card detected successfully\n");
+
+ val = esdhc_in32(&mmc->esdhc_regs->proctl);
+ val = val | (ESDHC_PROCTL_EMODE_LE | ESDHC_PROCTL_DTW_1BIT);
+
+ /* Set little endian mode, set bus width as 1-bit */
+ esdhc_out32(&mmc->esdhc_regs->proctl, val);
+
+ /* Enable cache snooping for DMA transactions */
+ val = esdhc_in32(&mmc->esdhc_regs->ctl) | ESDHC_DCR_SNOOP;
+ esdhc_out32(&mmc->esdhc_regs->ctl, val);
+
+ return 0;
+}
+
+/***************************************************************************
+ * Function : esdhc_send_cmd
+ * Arguments : mmc - Pointer to mmc struct
+ * cmd - Command Number
+ * args - Command Args
+ * Return : SUCCESS is 0, or Error Code ( < 0)
+ * Description : Updates the eSDHC registers cmdargs and xfertype
+ ***************************************************************************/
+static int esdhc_send_cmd(struct mmc *mmc, uint32_t cmd, uint32_t args)
+{
+ uint32_t val;
+ uint64_t start_time;
+ uint32_t xfertyp = 0;
+
+ esdhc_out32(&mmc->esdhc_regs->irqstat, ESDHC_IRQSTAT_CLEAR_ALL);
+
+ /* Wait for the command line & data line to be free */
+ /* (poll the CIHB,CDIHB bit of the present state register) */
+ start_time = get_timer_val(0);
+ while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
+ val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
+ (ESDHC_PRSSTAT_CIHB | ESDHC_PRSSTAT_CDIHB);
+ if (val == 0U) {
+ break;
+ }
+ }
+
+ val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
+ (ESDHC_PRSSTAT_CIHB | ESDHC_PRSSTAT_CDIHB);
+ if (val != 0U) {
+ ERROR("SD send cmd: Command Line or Data Line Busy cmd = %x\n",
+ cmd);
+ return ERROR_ESDHC_BUSY;
+ }
+
+ if (cmd == CMD2 || cmd == CMD9) {
+ xfertyp |= ESDHC_XFERTYP_RSPTYP_136;
+ } else if (cmd == CMD7 || (cmd == CMD6 && mmc->card.type == MMC_CARD)) {
+ xfertyp |= ESDHC_XFERTYP_RSPTYP_48_BUSY;
+ } else if (cmd != CMD0) {
+ xfertyp |= ESDHC_XFERTYP_RSPTYP_48;
+ }
+
+ if (cmd == CMD2 || cmd == CMD9) {
+ xfertyp |= ESDHC_XFERTYP_CCCEN; /* Command index check enable */
+ } else if ((cmd != CMD0) && (cmd != ACMD41) && (cmd != CMD1)) {
+ xfertyp = xfertyp | ESDHC_XFERTYP_CCCEN | ESDHC_XFERTYP_CICEN;
+ }
+
+ if ((cmd == CMD8 || cmd == CMD14 || cmd == CMD19) &&
+ mmc->card.type == MMC_CARD) {
+ xfertyp |= ESDHC_XFERTYP_DPSEL;
+ if (cmd != CMD19) {
+ xfertyp |= ESDHC_XFERTYP_DTDSEL;
+ }
+ }
+
+ if (cmd == CMD6 || cmd == CMD17 || cmd == CMD18 || cmd == CMD24 ||
+ cmd == ACMD51) {
+ if (!(mmc->card.type == MMC_CARD && cmd == CMD6)) {
+ if (cmd == CMD24) {
+ xfertyp |= ESDHC_XFERTYP_DPSEL;
+ } else {
+ xfertyp |= (ESDHC_XFERTYP_DPSEL |
+ ESDHC_XFERTYP_DTDSEL);
+ }
+ }
+
+ if (cmd == CMD18) {
+ xfertyp |= ESDHC_XFERTYP_BCEN;
+ if (mmc->dma_support != 0) {
+ /* Set BCEN of XFERTYP */
+ xfertyp |= ESDHC_XFERTYP_DMAEN;
+ }
+ }
+
+ if ((cmd == CMD17 || cmd == CMD24) && (mmc->dma_support != 0)) {
+ xfertyp |= ESDHC_XFERTYP_DMAEN;
+ }
+ }
+
+ xfertyp |= ((cmd & 0x3F) << 24);
+ esdhc_out32(&mmc->esdhc_regs->cmdarg, args);
+ esdhc_out32(&mmc->esdhc_regs->xfertyp, xfertyp);
+
+#ifdef NXP_SD_DEBUG
+ INFO("cmd = %d\n", cmd);
+ INFO("args = %x\n", args);
+ INFO("xfertyp: = %x\n", xfertyp);
+#endif
+ return 0;
+}
+
+/***************************************************************************
+ * Function : esdhc_wait_response
+ * Arguments : mmc - Pointer to mmc struct
+ * response - Value updated
+ * Return : SUCCESS - Response Received
+ * COMMUNICATION_ERROR - Command not Complete
+ * COMMAND_ERROR - CIE, CCE or CEBE error
+ * RESP_TIMEOUT - CTOE error
+ * Description : Checks for successful command completion.
+ * Clears the CC bit at the end.
+ ***************************************************************************/
+static int esdhc_wait_response(struct mmc *mmc, uint32_t *response)
+{
+ uint32_t val;
+ uint64_t start_time;
+ uint32_t status = 0U;
+
+ /* Wait for the command to complete */
+ start_time = get_timer_val(0);
+ while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
+ val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_CC;
+ if (val != 0U) {
+ break;
+ }
+ }
+
+ val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_CC;
+ if (val == 0U) {
+ ERROR("%s:IRQSTAT Cmd not complete(CC not set)\n", __func__);
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+
+ status = esdhc_in32(&mmc->esdhc_regs->irqstat);
+
+ /* Check whether the interrupt is a CRC, CTOE or CIE error */
+ if ((status & (ESDHC_IRQSTAT_CIE | ESDHC_IRQSTAT_CEBE |
+ ESDHC_IRQSTAT_CCE)) != 0) {
+ ERROR("%s: IRQSTAT CRC, CEBE or CIE error = %x\n",
+ __func__, status);
+ return COMMAND_ERROR;
+ }
+
+ if ((status & ESDHC_IRQSTAT_CTOE) != 0) {
+ INFO("%s: IRQSTAT CTOE set = %x\n", __func__, status);
+ return RESP_TIMEOUT;
+ }
+
+ if ((status & ESDHC_IRQSTAT_DMAE) != 0) {
+ ERROR("%s: IRQSTAT DMAE set = %x\n", __func__, status);
+ return ERROR_ESDHC_DMA_ERROR;
+ }
+
+ if (response != NULL) {
+ /* Get response values from eSDHC CMDRSPx registers. */
+ response[0] = esdhc_in32(&mmc->esdhc_regs->cmdrsp[0]);
+ response[1] = esdhc_in32(&mmc->esdhc_regs->cmdrsp[1]);
+ response[2] = esdhc_in32(&mmc->esdhc_regs->cmdrsp[2]);
+ response[3] = esdhc_in32(&mmc->esdhc_regs->cmdrsp[3]);
+#ifdef NXP_SD_DEBUG
+ INFO("Resp R1 R2 R3 R4\n");
+ INFO("Resp R1 = %x\n", response[0]);
+ INFO("R2 = %x\n", response[1]);
+ INFO("R3 = %x\n", response[2]);
+ INFO("R4 = %x\n", response[3]);
+ INFO("\n");
+#endif
+ }
+
+ /* Clear the CC bit - w1c */
+ val = esdhc_in32(&mmc->esdhc_regs->irqstat) | ESDHC_IRQSTAT_CC;
+ esdhc_out32(&mmc->esdhc_regs->irqstat, val);
+
+ return 0;
+}
+
+/***************************************************************************
+ * Function : mmc_switch_to_high_frquency
+ * Arguments : mmc - Pointer to mmc struct
+ * Return : SUCCESS or Error Code
+ * Description : mmc card bellow ver 4.0 does not support high speed
+ * freq = 20 MHz
+ * Send CMD6 (CMD_SWITCH_FUNC) With args 0x03B90100
+ * Send CMD13 (CMD_SEND_STATUS)
+ * if SWITCH Error, freq = 26 MHz
+ * if no error, freq = 52 MHz
+ ***************************************************************************/
+static int mmc_switch_to_high_frquency(struct mmc *mmc)
+{
+ int error;
+ uint32_t response[4];
+ uint64_t start_time;
+
+ mmc->card.bus_freq = MMC_SS_20MHZ;
+ /* mmc card bellow ver 4.0 does not support high speed */
+ if (mmc->card.version < MMC_CARD_VERSION_4_X) {
+ return 0;
+ }
+
+ /* send switch cmd to change the card to High speed */
+ error = esdhc_send_cmd(mmc, CMD_SWITCH_FUNC, SET_EXT_CSD_HS_TIMING);
+ if (error != 0) {
+ return error;
+ }
+ error = esdhc_wait_response(mmc, response);
+ if (error != 0) {
+ return error;
+ }
+
+ start_time = get_timer_val(0);
+ do {
+ /* check the status for which error */
+ error = esdhc_send_cmd(mmc,
+ CMD_SEND_STATUS, mmc->card.rca << 16);
+ if (error != 0) {
+ return error;
+ }
+
+ error = esdhc_wait_response(mmc, response);
+ if (error != 0) {
+ return error;
+ }
+ } while (((response[0] & SWITCH_ERROR) != 0) &&
+ (get_timer_val(start_time) < SD_TIMEOUT));
+
+ /* Check for the present state of card */
+ if ((response[0] & SWITCH_ERROR) != 0) {
+ mmc->card.bus_freq = MMC_HS_26MHZ;
+ } else {
+ mmc->card.bus_freq = MMC_HS_52MHZ;
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+ * Function : esdhc_set_data_attributes
+ * Arguments : mmc - Pointer to mmc struct
+ * blkcnt
+ * blklen
+ * Return : SUCCESS or Error Code
+ * Description : Set block attributes and watermark level register
+ ***************************************************************************/
+static int esdhc_set_data_attributes(struct mmc *mmc, uint32_t *dest_ptr,
+ uint32_t blkcnt, uint32_t blklen)
+{
+ uint32_t val;
+ uint64_t start_time;
+ uint32_t wml;
+ uint32_t wl;
+ uint32_t dst = (uint32_t)((uint64_t)(dest_ptr));
+
+ /* set blkattr when no transactions are executing */
+ start_time = get_timer_val(0);
+ while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
+ val = esdhc_in32(&mmc->esdhc_regs->prsstat) & ESDHC_PRSSTAT_DLA;
+ if (val == 0U) {
+ break;
+ }
+ }
+
+ val = esdhc_in32(&mmc->esdhc_regs->prsstat) & ESDHC_PRSSTAT_DLA;
+ if (val != 0U) {
+ ERROR("%s: Data line active.Can't set attribute\n", __func__);
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+
+ wml = esdhc_in32(&mmc->esdhc_regs->wml);
+ wml &= ~(ESDHC_WML_WR_BRST_MASK | ESDHC_WML_RD_BRST_MASK |
+ ESDHC_WML_RD_WML_MASK | ESDHC_WML_WR_WML_MASK);
+
+ if ((mmc->dma_support != 0) && (dest_ptr != NULL)) {
+ /* Set burst length to 128 bytes */
+ esdhc_out32(&mmc->esdhc_regs->wml,
+ wml | ESDHC_WML_WR_BRST(BURST_128_BYTES));
+ esdhc_out32(&mmc->esdhc_regs->wml,
+ wml | ESDHC_WML_RD_BRST(BURST_128_BYTES));
+
+ /* Set DMA System Destination Address */
+ esdhc_out32(&mmc->esdhc_regs->dsaddr, dst);
+ } else {
+ wl = (blklen >= BLOCK_LEN_512) ?
+ WML_512_BYTES : ((blklen + 3) / 4);
+ /* Set 'Read Water Mark Level' register */
+ esdhc_out32(&mmc->esdhc_regs->wml, wml | ESDHC_WML_RD_WML(wl));
+ }
+
+ /* Configure block Attributes register */
+ esdhc_out32(&mmc->esdhc_regs->blkattr,
+ ESDHC_BLKATTR_BLKCNT(blkcnt) | ESDHC_BLKATTR_BLKSZE(blklen));
+
+ mmc->block_len = blklen;
+
+ return 0;
+}
+
+/***************************************************************************
+ * Function : esdhc_read_data_nodma
+ * Arguments : mmc - Pointer to mmc struct
+ * dest_ptr - Bufffer where read data is to be copied
+ * len - Length of Data to be read
+ * Return : SUCCESS or Error Code
+ * Description : Read data from the sdhc buffer without using DMA
+ * and using polling mode
+ ***************************************************************************/
+static int esdhc_read_data_nodma(struct mmc *mmc, void *dest_ptr, uint32_t len)
+{
+ uint32_t i = 0U;
+ uint32_t status;
+ uint32_t num_blocks;
+ uint32_t *dst = (uint32_t *)dest_ptr;
+ uint32_t val;
+ uint64_t start_time;
+
+ num_blocks = len / mmc->block_len;
+
+ while ((num_blocks--) != 0U) {
+
+ start_time = get_timer_val(0);
+ while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
+ val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
+ ESDHC_PRSSTAT_BREN;
+ if (val != 0U) {
+ break;
+ }
+ }
+
+ val = esdhc_in32(&mmc->esdhc_regs->prsstat)
+ & ESDHC_PRSSTAT_BREN;
+ if (val == 0U) {
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+
+ for (i = 0U, status = esdhc_in32(&mmc->esdhc_regs->irqstat);
+ i < mmc->block_len / 4; i++, dst++) {
+ /* get data from data port */
+ val = mmio_read_32(
+ (uintptr_t)&mmc->esdhc_regs->datport);
+ esdhc_out32(dst, val);
+ /* Increment destination pointer */
+ status = esdhc_in32(&mmc->esdhc_regs->irqstat);
+ }
+ /* Check whether the interrupt is an DTOE/DCE/DEBE */
+ if ((status & (ESDHC_IRQSTAT_DTOE | ESDHC_IRQSTAT_DCE |
+ ESDHC_IRQSTAT_DEBE)) != 0) {
+ ERROR("SD read error - DTOE, DCE, DEBE bit set = %x\n",
+ status);
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+ }
+
+ /* Wait for TC */
+
+ start_time = get_timer_val(0);
+ while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
+ val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_TC;
+ if (val != 0U) {
+ break;
+ }
+ }
+
+ val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_TC;
+ if (val == 0U) {
+ ERROR("SD read timeout: Transfer bit not set in IRQSTAT\n");
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+ * Function : esdhc_write_data_nodma
+ * Arguments : mmc - Pointer to mmc struct
+ * src_ptr - Buffer where data is copied from
+ * len - Length of Data to be written
+ * Return : SUCCESS or Error Code
+ * Description : Write data to the sdhc buffer without using DMA
+ * and using polling mode
+ ***************************************************************************/
+static int esdhc_write_data_nodma(struct mmc *mmc, void *src_ptr, uint32_t len)
+{
+ uint32_t i = 0U;
+ uint32_t status;
+ uint32_t num_blocks;
+ uint32_t *src = (uint32_t *)src_ptr;
+ uint32_t val;
+ uint64_t start_time;
+
+ num_blocks = len / mmc->block_len;
+
+ while ((num_blocks--) != 0U) {
+ start_time = get_timer_val(0);
+ while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
+ val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
+ ESDHC_PRSSTAT_BWEN;
+ if (val != 0U) {
+ break;
+ }
+ }
+
+ val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
+ ESDHC_PRSSTAT_BWEN;
+ if (val == 0U) {
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+
+ for (i = 0U, status = esdhc_in32(&mmc->esdhc_regs->irqstat);
+ i < mmc->block_len / 4; i++, src++) {
+ val = esdhc_in32(src);
+ /* put data to data port */
+ mmio_write_32((uintptr_t)&mmc->esdhc_regs->datport,
+ val);
+ /* Increment source pointer */
+ status = esdhc_in32(&mmc->esdhc_regs->irqstat);
+ }
+ /* Check whether the interrupt is an DTOE/DCE/DEBE */
+ if ((status & (ESDHC_IRQSTAT_DTOE | ESDHC_IRQSTAT_DCE |
+ ESDHC_IRQSTAT_DEBE)) != 0) {
+ ERROR("SD write error - DTOE, DCE, DEBE bit set = %x\n",
+ status);
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+ }
+
+ /* Wait for TC */
+ start_time = get_timer_val(0);
+ while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
+ val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_TC;
+ if (val != 0U) {
+ break;
+ }
+ }
+
+ val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_TC;
+ if (val == 0U) {
+ ERROR("SD write timeout: Transfer bit not set in IRQSTAT\n");
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+ * Function : esdhc_read_data_dma
+ * Arguments : mmc - Pointer to mmc struct
+ * len - Length of Data to be read
+ * Return : SUCCESS or Error Code
+ * Description : Read data from the sd card using DMA.
+ ***************************************************************************/
+static int esdhc_read_data_dma(struct mmc *mmc, uint32_t len)
+{
+ uint32_t status;
+ uint32_t tblk;
+ uint64_t start_time;
+
+ tblk = SD_BLOCK_TIMEOUT * (len / mmc->block_len);
+
+ start_time = get_timer_val(0);
+
+ /* poll till TC is set */
+ do {
+ status = esdhc_in32(&mmc->esdhc_regs->irqstat);
+
+ if ((status & (ESDHC_IRQSTAT_DEBE | ESDHC_IRQSTAT_DCE
+ | ESDHC_IRQSTAT_DTOE)) != 0) {
+ ERROR("SD read error - DTOE, DCE, DEBE bit set = %x\n",
+ status);
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+
+ if ((status & ESDHC_IRQSTAT_DMAE) != 0) {
+ ERROR("SD read error - DMA error = %x\n", status);
+ return ERROR_ESDHC_DMA_ERROR;
+ }
+
+ } while (((status & ESDHC_IRQSTAT_TC) == 0) &&
+ ((esdhc_in32(&mmc->esdhc_regs->prsstat) & ESDHC_PRSSTAT_DLA) != 0) &&
+ (get_timer_val(start_time) < SD_TIMEOUT_HIGH + tblk));
+
+ if (get_timer_val(start_time) > SD_TIMEOUT_HIGH + tblk) {
+ ERROR("SD read DMA timeout\n");
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+ * Function : esdhc_write_data_dma
+ * Arguments : mmc - Pointer to mmc struct
+ * len - Length of Data to be written
+ * Return : SUCCESS or Error Code
+ * Description : Write data to the sd card using DMA.
+ ***************************************************************************/
+static int esdhc_write_data_dma(struct mmc *mmc, uint32_t len)
+{
+ uint32_t status;
+ uint32_t tblk;
+ uint64_t start_time;
+
+ tblk = SD_BLOCK_TIMEOUT * (len / mmc->block_len);
+
+ start_time = get_timer_val(0);
+
+ /* poll till TC is set */
+ do {
+ status = esdhc_in32(&mmc->esdhc_regs->irqstat);
+
+ if ((status & (ESDHC_IRQSTAT_DEBE | ESDHC_IRQSTAT_DCE
+ | ESDHC_IRQSTAT_DTOE)) != 0) {
+ ERROR("SD write error - DTOE, DCE, DEBE bit set = %x\n",
+ status);
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+
+ if ((status & ESDHC_IRQSTAT_DMAE) != 0) {
+ ERROR("SD write error - DMA error = %x\n", status);
+ return ERROR_ESDHC_DMA_ERROR;
+ }
+ } while (((status & ESDHC_IRQSTAT_TC) == 0) &&
+ ((esdhc_in32(&mmc->esdhc_regs->prsstat) & ESDHC_PRSSTAT_DLA) != 0) &&
+ (get_timer_val(start_time) < SD_TIMEOUT_HIGH + tblk));
+
+ if (get_timer_val(start_time) > SD_TIMEOUT_HIGH + tblk) {
+ ERROR("SD write DMA timeout\n");
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+ * Function : esdhc_read_data
+ * Arguments : mmc - Pointer to mmc struct
+ * dest_ptr - Bufffer where read data is to be copied
+ * len - Length of Data to be read
+ * Return : SUCCESS or Error Code
+ * Description : Calls esdhc_read_data_nodma and clear interrupt status
+ ***************************************************************************/
+int esdhc_read_data(struct mmc *mmc, void *dest_ptr, uint32_t len)
+{
+ int ret;
+
+ if (mmc->dma_support && len > 64) {
+ ret = esdhc_read_data_dma(mmc, len);
+ } else {
+ ret = esdhc_read_data_nodma(mmc, dest_ptr, len);
+ }
+
+ /* clear interrupt status */
+ esdhc_out32(&mmc->esdhc_regs->irqstat, ESDHC_IRQSTAT_CLEAR_ALL);
+
+ return ret;
+}
+
+/***************************************************************************
+ * Function : esdhc_write_data
+ * Arguments : mmc - Pointer to mmc struct
+ * src_ptr - Buffer where data is copied from
+ * len - Length of Data to be written
+ * Return : SUCCESS or Error Code
+ * Description : Calls esdhc_write_data_nodma and clear interrupt status
+ ***************************************************************************/
+int esdhc_write_data(struct mmc *mmc, void *src_ptr, uint32_t len)
+{
+ int ret;
+
+ if (mmc->dma_support && len > 64) {
+ ret = esdhc_write_data_dma(mmc, len);
+ } else {
+ ret = esdhc_write_data_nodma(mmc, src_ptr, len);
+ }
+
+ /* clear interrupt status */
+ esdhc_out32(&mmc->esdhc_regs->irqstat, ESDHC_IRQSTAT_CLEAR_ALL);
+
+ return ret;
+}
+
+/***************************************************************************
+ * Function : sd_switch_to_high_freq
+ * Arguments : mmc - Pointer to mmc struct
+ * Return : SUCCESS or Error Code
+ * Description : 1. Send ACMD51 (CMD_SEND_SCR)
+ * 2. Read the SCR to check if card supports higher freq
+ * 3. check version from SCR
+ * 4. If SD 1.0, return (no Switch) freq = 25 MHz.
+ * 5. Send CMD6 (CMD_SWITCH_FUNC) with args 0x00FFFFF1 to
+ * check the status of switch func
+ * 6. Send CMD6 (CMD_SWITCH_FUNC) With args 0x80FFFFF1 to
+ * switch to high frequency = 50 Mhz
+ ***************************************************************************/
+static int sd_switch_to_high_freq(struct mmc *mmc)
+{
+ int err;
+ uint8_t scr[8];
+ uint8_t status[64];
+ uint32_t response[4];
+ uint32_t version;
+ uint32_t count;
+ uint32_t sd_versions[] = {SD_CARD_VERSION_1_0, SD_CARD_VERSION_1_10,
+ SD_CARD_VERSION_2_0};
+
+ mmc->card.bus_freq = SD_SS_25MHZ;
+ /* Send Application command */
+ err = esdhc_send_cmd(mmc, CMD_APP_CMD, mmc->card.rca << 16);
+ if (err != 0) {
+ return err;
+ }
+
+ err = esdhc_wait_response(mmc, response);
+ if (err != 0) {
+ return err;
+ }
+
+ esdhc_set_data_attributes(mmc, NULL, 1, 8);
+ /* Read the SCR to find out if this card supports higher speeds */
+ err = esdhc_send_cmd(mmc, CMD_SEND_SCR, mmc->card.rca << 16);
+ if (err != 0) {
+ return err;
+ }
+ err = esdhc_wait_response(mmc, response);
+ if (err != 0) {
+ return err;
+ }
+
+ /* read 8 bytes of scr data */
+ err = esdhc_read_data(mmc, scr, 8U);
+ if (err != 0) {
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+
+ /* check version from SCR */
+ version = scr[0] & U(0xF);
+ if (version <= 2U) {
+ mmc->card.version = sd_versions[version];
+ } else {
+ mmc->card.version = SD_CARD_VERSION_2_0;
+ }
+
+ /* does not support switch func */
+ if (mmc->card.version == SD_CARD_VERSION_1_0) {
+ return 0;
+ }
+
+ /* read 64 bytes of status */
+ esdhc_set_data_attributes(mmc, NULL, 1U, 64U);
+
+ /* check the status of switch func */
+ for (count = 0U; count < 4U; count++) {
+ err = esdhc_send_cmd(mmc, CMD_SWITCH_FUNC,
+ SD_SWITCH_FUNC_CHECK_MODE);
+ if (err != 0) {
+ return err;
+ }
+ err = esdhc_wait_response(mmc, response);
+ if (err != 0) {
+ return err;
+ }
+ /* read 64 bytes of scr data */
+ err = esdhc_read_data(mmc, status, 64U);
+ if (err != 0) {
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+
+ if ((status[29] & SD_SWITCH_FUNC_HIGH_SPEED) == 0) {
+ break;
+ }
+ }
+
+ if ((status[13] & SD_SWITCH_FUNC_HIGH_SPEED) == 0) {
+ return 0;
+ }
+
+ /* SWITCH */
+ esdhc_set_data_attributes(mmc, NULL, 1, 64);
+ err = esdhc_send_cmd(mmc, CMD_SWITCH_FUNC, SD_SWITCH_FUNC_SWITCH_MODE);
+ if (err != 0) {
+ return err;
+ }
+ err = esdhc_wait_response(mmc, response);
+ if (err != 0) {
+ return err;
+ }
+
+ err = esdhc_read_data(mmc, status, 64U);
+ if (err != 0) {
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+
+ if ((status[16]) == U(0x01)) {
+ mmc->card.bus_freq = SD_HS_50MHZ;
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+ * Function : change_state_to_transfer_state
+ * Arguments : mmc - Pointer to mmc struct
+ * Return : SUCCESS or Error Code
+ * Description : 1. Send CMD7 (CMD_SELECT_CARD) to toggles the card
+ * between stand-by and transfer state
+ * 2. Send CMD13 (CMD_SEND_STATUS) to check state as
+ * Transfer State
+ ***************************************************************************/
+static int change_state_to_transfer_state(struct mmc *mmc)
+{
+ int error = 0;
+ uint32_t response[4];
+ uint64_t start_time;
+
+ /* Command CMD_SELECT_CARD/CMD7 toggles the card between stand-by
+ * and transfer states
+ */
+ error = esdhc_send_cmd(mmc, CMD_SELECT_CARD, mmc->card.rca << 16);
+ if (error != 0) {
+ return error;
+ }
+ error = esdhc_wait_response(mmc, response);
+ if (error != 0) {
+ return error;
+ }
+
+ start_time = get_timer_val(0);
+ while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
+ /* send CMD13 to check card status */
+ error = esdhc_send_cmd(mmc,
+ CMD_SEND_STATUS, mmc->card.rca << 16);
+ if (error != 0) {
+ return error;
+ }
+ error = esdhc_wait_response(mmc, response);
+ if ((error != 0) || ((response[0] & R1_ERROR) != 0)) {
+ return error;
+ }
+
+ /* Check for the present state of card */
+ if (((response[0] >> 9U) & U(0xF)) == STATE_TRAN) {
+ break;
+ }
+ }
+ if (((response[0] >> 9U) & U(0xF)) == STATE_TRAN) {
+ return 0;
+ } else {
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+}
+
+/***************************************************************************
+ * Function : get_cid_rca_csd
+ * Arguments : mmc - Pointer to mmc struct
+ * Return : SUCCESS or Error Code
+ * Description : 1. Send CMD2 (CMD_ALL_SEND_CID)
+ * 2. get RCA for SD cards, set rca for mmc cards
+ * Send CMD3 (CMD_SEND_RELATIVE_ADDR)
+ * 3. Send CMD9 (CMD_SEND_CSD)
+ * 4. Get MMC Version from CSD
+ ***************************************************************************/
+static int get_cid_rca_csd(struct mmc *mmc)
+{
+ int err;
+ uint32_t version;
+ uint32_t response[4];
+ uint32_t mmc_version[] = {MMC_CARD_VERSION_1_2, MMC_CARD_VERSION_1_4,
+ MMC_CARD_VERSION_2_X, MMC_CARD_VERSION_3_X,
+ MMC_CARD_VERSION_4_X};
+
+ err = esdhc_send_cmd(mmc, CMD_ALL_SEND_CID, 0);
+ if (err != 0) {
+ return err;
+ }
+ err = esdhc_wait_response(mmc, response);
+ if (err != 0) {
+ return err;
+ }
+
+ /* get RCA for SD cards, set rca for mmc cards */
+ mmc->card.rca = SD_MMC_CARD_RCA;
+
+ /* send RCA cmd */
+ err = esdhc_send_cmd(mmc, CMD_SEND_RELATIVE_ADDR, mmc->card.rca << 16);
+ if (err != 0) {
+ return err;
+ }
+ err = esdhc_wait_response(mmc, response);
+ if (err != 0) {
+ return err;
+ }
+
+ /* for SD, get the the RCA */
+ if (mmc->card.type == SD_CARD) {
+ mmc->card.rca = (response[0] >> 16) & 0xFFFF;
+ }
+
+ /* Get the CSD (card specific data) from card. */
+ err = esdhc_send_cmd(mmc, CMD_SEND_CSD, mmc->card.rca << 16);
+ if (err != 0) {
+ return err;
+ }
+ err = esdhc_wait_response(mmc, response);
+ if (err != 0) {
+ return err;
+ }
+
+ version = (response[3] >> 18U) & U(0xF);
+ if (mmc->card.type == MMC_CARD) {
+ if (version <= MMC_CARD_VERSION_4_X) {
+ mmc->card.version = mmc_version[version];
+ } else {
+ mmc->card.version = MMC_CARD_VERSION_4_X;
+ }
+ }
+
+ mmc->card.block_len = 1 << ((response[2] >> 8) & 0xF);
+
+ if (mmc->card.block_len > BLOCK_LEN_512) {
+ mmc->card.block_len = BLOCK_LEN_512;
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+ * Function : identify_mmc_card
+ * Arguments : mmc - Pointer to mmc struct
+ * Return : SUCCESS or Error Code
+ * Description : 1. Send Reset Command
+ * 2. Send CMD1 with args to set voltage range and Sector
+ * Mode. (Voltage Args = 0xFF8)
+ * 3. Check the OCR Response
+ ***************************************************************************/
+static int identify_mmc_card(struct mmc *mmc)
+{
+ uint64_t start_time;
+ uint32_t resp[4];
+ int ret;
+ uint32_t args;
+
+ /* card reset */
+ ret = esdhc_send_cmd(mmc, CMD_GO_IDLE_STATE, 0U);
+ if (ret != 0) {
+ return ret;
+ }
+ ret = esdhc_wait_response(mmc, resp);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Send CMD1 to get the ocr value repeatedly till the card */
+ /* busy is clear. timeout = 20sec */
+
+ start_time = get_timer_val(0);
+ do {
+ /* set the bits for the voltage ranges supported by host */
+ args = mmc->voltages_caps | MMC_OCR_SECTOR_MODE;
+ ret = esdhc_send_cmd(mmc, CMD_MMC_SEND_OP_COND, args);
+ if (ret != 0) {
+ return ret;
+ }
+ ret = esdhc_wait_response(mmc, resp);
+ if (ret != 0) {
+ return ERROR_ESDHC_UNUSABLE_CARD;
+ }
+ } while (((resp[0] & MMC_OCR_BUSY) == 0U) &&
+ (get_timer_val(start_time) < SD_TIMEOUT_HIGH));
+
+ if (get_timer_val(start_time) > SD_TIMEOUT_HIGH) {
+ return ERROR_ESDHC_UNUSABLE_CARD;
+ }
+
+ if ((resp[0] & MMC_OCR_CCS) == MMC_OCR_CCS) {
+ mmc->card.is_high_capacity = 1;
+ }
+
+ return MMC_CARD;
+}
+
+/***************************************************************************
+ * Function : check_for_sd_card
+ * Arguments : mmc - Pointer to mmc struct
+ * Return : SUCCESS or Error Code
+ * Description : 1. Send Reset Command
+ * 2. Send CMD8 with pattern 0xAA (to check for SD 2.0)
+ * 3. Send ACMD41 with args to set voltage range and HCS
+ * HCS is set only for SD Card > 2.0
+ * Voltage Caps = 0xFF8
+ * 4. Check the OCR Response
+ ***************************************************************************/
+static int check_for_sd_card(struct mmc *mmc)
+{
+ uint64_t start_time;
+ uint32_t args;
+ int ret;
+ uint32_t resp[4];
+
+ /* Send reset command */
+ ret = esdhc_send_cmd(mmc, CMD_GO_IDLE_STATE, 0U);
+ if (ret != 0) {
+ return ret;
+ }
+ ret = esdhc_wait_response(mmc, resp);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* send CMD8 with pattern 0xAA */
+ args = MMC_VDD_HIGH_VOLTAGE | 0xAA;
+ ret = esdhc_send_cmd(mmc, CMD_SEND_IF_COND, args);
+ if (ret != 0) {
+ return ret;
+ }
+ ret = esdhc_wait_response(mmc, resp);
+ if (ret == RESP_TIMEOUT) { /* sd ver 1.x or not sd */
+ mmc->card.is_high_capacity = 0;
+ } else if ((resp[0] & U(0xFF)) == U(0xAA)) { /* ver 2.0 or later */
+ mmc->card.version = SD_CARD_VERSION_2_0;
+ } else {
+ return NOT_SD_CARD;
+ }
+ /* Send Application command-55 to get the ocr value repeatedly till
+ * the card busy is clear. timeout = 20sec
+ */
+
+ start_time = get_timer_val(0);
+ do {
+ ret = esdhc_send_cmd(mmc, CMD_APP_CMD, 0U);
+ if (ret != 0) {
+ return ret;
+ }
+ ret = esdhc_wait_response(mmc, resp);
+ if (ret == COMMAND_ERROR) {
+ return ERROR_ESDHC_UNUSABLE_CARD;
+ }
+
+ /* set the bits for the voltage ranges supported by host */
+ args = mmc->voltages_caps;
+ if (mmc->card.version == SD_CARD_VERSION_2_0) {
+ args |= SD_OCR_HCS;
+ }
+
+ /* Send ACMD41 to set voltage range */
+ ret = esdhc_send_cmd(mmc, CMD_SD_SEND_OP_COND, args);
+ if (ret != 0) {
+ return ret;
+ }
+ ret = esdhc_wait_response(mmc, resp);
+ if (ret == COMMAND_ERROR) {
+ return ERROR_ESDHC_UNUSABLE_CARD;
+ } else if (ret == RESP_TIMEOUT) {
+ return NOT_SD_CARD;
+ }
+ } while (((resp[0] & MMC_OCR_BUSY) == 0U) &&
+ (get_timer_val(start_time) < SD_TIMEOUT_HIGH));
+
+ if (get_timer_val(start_time) > SD_TIMEOUT_HIGH) {
+ INFO("SD_TIMEOUT_HIGH\n");
+ return ERROR_ESDHC_UNUSABLE_CARD;
+ }
+
+ /* bit set in card capacity status */
+ if ((resp[0] & MMC_OCR_CCS) == MMC_OCR_CCS) {
+ mmc->card.is_high_capacity = 1;
+ }
+
+ return SD_CARD;
+}
+
+/***************************************************************************
+ * Function : esdhc_emmc_init
+ * Arguments : mmc - Pointer to mmc struct
+ * src_emmc - Flag to Indicate SRC as emmc
+ * Return : SUCCESS or Error Code (< 0)
+ * Description : Base Function called from sd_mmc_init or emmc_init
+ ***************************************************************************/
+int esdhc_emmc_init(struct mmc *mmc, bool card_detect)
+{
+ int error = 0;
+ int ret = 0;
+
+ error = esdhc_init(mmc, card_detect);
+ if (error != 0) {
+ return error;
+ }
+
+ mmc->card.bus_freq = CARD_IDENTIFICATION_FREQ;
+ mmc->card.rca = 0;
+ mmc->card.is_high_capacity = 0;
+ mmc->card.type = ERROR_ESDHC_UNUSABLE_CARD;
+
+ /* Set Voltage caps as FF8 i.e all supported */
+ /* high voltage bits 2.7 - 3.6 */
+ mmc->voltages_caps = MMC_OCR_VDD_FF8;
+
+#ifdef NXP_SD_DMA_CAPABILITY
+ /* Getting host DMA capabilities. */
+ mmc->dma_support = esdhc_in32(&mmc->esdhc_regs->hostcapblt) &
+ ESDHC_HOSTCAPBLT_DMAS;
+#else
+ mmc->dma_support = 0;
+#endif
+
+ ret = NOT_SD_CARD;
+ /* If SRC is not EMMC, check for SD or MMC */
+ ret = check_for_sd_card(mmc);
+ switch (ret) {
+ case SD_CARD:
+ mmc->card.type = SD_CARD;
+ break;
+
+ case NOT_SD_CARD:
+ /* try for MMC card */
+ if (identify_mmc_card(mmc) == MMC_CARD) {
+ mmc->card.type = MMC_CARD;
+ } else {
+ return ERROR_ESDHC_UNUSABLE_CARD;
+ }
+ break;
+
+ default:
+ return ERROR_ESDHC_UNUSABLE_CARD;
+ }
+
+ /* get CID, RCA and CSD. For MMC, set the rca */
+ error = get_cid_rca_csd(mmc);
+ if (error != 0) {
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+
+ /* change state to Transfer mode */
+ error = change_state_to_transfer_state(mmc);
+ if (error != 0) {
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+
+ /* change to high frequency if supported */
+ if (mmc->card.type == SD_CARD) {
+ error = sd_switch_to_high_freq(mmc);
+ } else {
+ error = mmc_switch_to_high_frquency(mmc);
+ }
+ if (error != 0) {
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+
+ /* mmc: 20000000, 26000000, 52000000 */
+ /* sd: 25000000, 50000000 */
+ set_speed(mmc, mmc->card.bus_freq);
+
+ INFO("init done:\n");
+ return 0;
+}
+
+/***************************************************************************
+ * Function : sd_mmc_init
+ * Arguments : mmc - Pointer to mmc struct
+ * Return : SUCCESS or Error Code
+ * Description : Base Function called via hal_init for SD/MMC
+ * initialization
+ ***************************************************************************/
+int sd_mmc_init(uintptr_t nxp_esdhc_addr, bool card_detect)
+{
+ struct mmc *mmc = NULL;
+ int ret;
+
+ mmc = &mmc_drv_data;
+ memset(mmc, 0, sizeof(struct mmc));
+ mmc->esdhc_regs = (struct esdhc_regs *)nxp_esdhc_addr;
+
+ INFO("esdhc_emmc_init\n");
+ ret = esdhc_emmc_init(mmc, card_detect);
+ return ret;
+}
+
+/***************************************************************************
+ * Function : esdhc_read_block
+ * Arguments : mmc - Pointer to mmc struct
+ * dst - Destination Pointer
+ * block - Block Number
+ * Return : SUCCESS or Error Code
+ * Description : Read a Single block to Destination Pointer
+ * 1. Send CMD16 (CMD_SET_BLOCKLEN) with args as blocklen
+ * 2. Send CMD17 (CMD_READ_SINGLE_BLOCK) with args offset
+ ***************************************************************************/
+static int esdhc_read_block(struct mmc *mmc, void *dst, uint32_t block)
+{
+ uint32_t offset;
+ int err;
+
+ /* send cmd16 to set the block size. */
+ err = esdhc_send_cmd(mmc, CMD_SET_BLOCKLEN, mmc->card.block_len);
+ if (err != 0) {
+ return err;
+ }
+ err = esdhc_wait_response(mmc, NULL);
+ if (err != 0) {
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+
+ if (mmc->card.is_high_capacity != 0) {
+ offset = block;
+ } else {
+ offset = block * mmc->card.block_len;
+ }
+
+ esdhc_set_data_attributes(mmc, dst, 1, mmc->card.block_len);
+ err = esdhc_send_cmd(mmc, CMD_READ_SINGLE_BLOCK, offset);
+ if (err != 0) {
+ return err;
+ }
+ err = esdhc_wait_response(mmc, NULL);
+ if (err != 0) {
+ return err;
+ }
+
+ err = esdhc_read_data(mmc, dst, mmc->card.block_len);
+
+ return err;
+}
+
+/***************************************************************************
+ * Function : esdhc_write_block
+ * Arguments : mmc - Pointer to mmc struct
+ * src - Source Pointer
+ * block - Block Number
+ * Return : SUCCESS or Error Code
+ * Description : Write a Single block from Source Pointer
+ * 1. Send CMD16 (CMD_SET_BLOCKLEN) with args as blocklen
+ * 2. Send CMD24 (CMD_WRITE_SINGLE_BLOCK) with args offset
+ ***************************************************************************/
+static int esdhc_write_block(struct mmc *mmc, void *src, uint32_t block)
+{
+ uint32_t offset;
+ int err;
+
+ /* send cmd16 to set the block size. */
+ err = esdhc_send_cmd(mmc, CMD_SET_BLOCKLEN, mmc->card.block_len);
+ if (err != 0) {
+ return err;
+ }
+ err = esdhc_wait_response(mmc, NULL);
+ if (err != 0) {
+ return ERROR_ESDHC_COMMUNICATION_ERROR;
+ }
+
+ if (mmc->card.is_high_capacity != 0) {
+ offset = block;
+ } else {
+ offset = block * mmc->card.block_len;
+ }
+
+ esdhc_set_data_attributes(mmc, src, 1, mmc->card.block_len);
+ err = esdhc_send_cmd(mmc, CMD_WRITE_SINGLE_BLOCK, offset);
+ if (err != 0) {
+ return err;
+ }
+ err = esdhc_wait_response(mmc, NULL);
+ if (err != 0) {
+ return err;
+ }
+
+ err = esdhc_write_data(mmc, src, mmc->card.block_len);
+
+ return err;
+}
+
+/***************************************************************************
+ * Function : esdhc_read
+ * Arguments : src_offset - offset on sd/mmc to read from. Should be block
+ * size aligned
+ * dst - Destination Pointer
+ * size - Length of Data ( Multiple of block size)
+ * Return : SUCCESS or Error Code
+ * Description : Calls esdhc_read_block repeatedly for reading the
+ * data.
+ ***************************************************************************/
+int esdhc_read(struct mmc *mmc, uint32_t src_offset, uintptr_t dst, size_t size)
+{
+ int error = 0;
+ uint32_t blk, num_blocks;
+ uint8_t *buff = (uint8_t *)dst;
+
+#ifdef NXP_SD_DEBUG
+ INFO("sd mmc read\n");
+ INFO("src = %x, dst = %lxsize = %lu\n", src_offset, dst, size);
+#endif
+
+ /* check for size */
+ if (size == 0) {
+ return 0;
+ }
+
+ if ((size % mmc->card.block_len) != 0) {
+ ERROR("Size is not block aligned\n");
+ return -1;
+ }
+
+ if ((src_offset % mmc->card.block_len) != 0) {
+ ERROR("Size is not block aligned\n");
+ return -1;
+ }
+
+ /* start block */
+ blk = src_offset / mmc->card.block_len;
+#ifdef NXP_SD_DEBUG
+ INFO("blk = %x\n", blk);
+#endif
+
+ /* Number of blocks to be read */
+ num_blocks = size / mmc->card.block_len;
+
+ while (num_blocks) {
+ error = esdhc_read_block(mmc, buff, blk);
+ if (error != 0) {
+ ERROR("Read error = %x\n", error);
+ return error;
+ }
+
+ buff = buff + mmc->card.block_len;
+ blk++;
+ num_blocks--;
+ }
+
+ INFO("sd-mmc read done.\n");
+ return error;
+}
+
+/***************************************************************************
+ * Function : esdhc_write
+ * Arguments : src - Source Pointer
+ * dst_offset - offset on sd/mmc to write to. Should be block
+ * size aligned
+ * size - Length of Data (Multiple of block size)
+ * Return : SUCCESS or Error Code
+ * Description : Calls esdhc_write_block repeatedly for writing the
+ * data.
+ ***************************************************************************/
+int esdhc_write(struct mmc *mmc, uintptr_t src, uint32_t dst_offset,
+ size_t size)
+{
+ int error = 0;
+ uint32_t blk, num_blocks;
+ uint8_t *buff = (uint8_t *)src;
+
+#ifdef NXP_SD_DEBUG
+ INFO("sd mmc write\n");
+ INFO("src = %x, dst = %lxsize = %lu\n", src, dst_offset, size);
+#endif
+
+ /* check for size */
+ if (size == 0) {
+ return 0;
+ }
+
+ if ((size % mmc->card.block_len) != 0) {
+ ERROR("Size is not block aligned\n");
+ return -1;
+ }
+
+ if ((dst_offset % mmc->card.block_len) != 0) {
+ ERROR("Size is not block aligned\n");
+ return -1;
+ }
+
+ /* start block */
+ blk = dst_offset / mmc->card.block_len;
+#ifdef NXP_SD_DEBUG
+ INFO("blk = %x\n", blk);
+#endif
+
+ /* Number of blocks to be written */
+ num_blocks = size / mmc->card.block_len;
+
+ while (num_blocks != 0U) {
+ error = esdhc_write_block(mmc, buff, blk);
+ if (error != 0U) {
+ ERROR("Write error = %x\n", error);
+ return error;
+ }
+
+ buff = buff + mmc->card.block_len;
+ blk++;
+ num_blocks--;
+ }
+
+ INFO("sd-mmc write done.\n");
+ return error;
+}
+
+static size_t ls_sd_emmc_read(int lba, uintptr_t buf, size_t size)
+{
+ struct mmc *mmc = NULL;
+ int ret;
+
+ mmc = &mmc_drv_data;
+ lba *= BLOCK_LEN_512;
+ ret = esdhc_read(mmc, lba, buf, size);
+ return ret ? 0 : size;
+}
+
+static struct io_block_dev_spec ls_emmc_dev_spec = {
+ .buffer = {
+ .offset = 0,
+ .length = 0,
+ },
+ .ops = {
+ .read = ls_sd_emmc_read,
+ },
+ .block_size = BLOCK_LEN_512,
+};
+
+int sd_emmc_init(uintptr_t *block_dev_spec,
+ uintptr_t nxp_esdhc_addr,
+ size_t nxp_sd_block_offset,
+ size_t nxp_sd_block_size,
+ bool card_detect)
+{
+ int ret;
+
+ ret = sd_mmc_init(nxp_esdhc_addr, card_detect);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ls_emmc_dev_spec.buffer.offset = nxp_sd_block_offset;
+ ls_emmc_dev_spec.buffer.length = nxp_sd_block_size;
+ *block_dev_spec = (uintptr_t)&ls_emmc_dev_spec;
+
+ return 0;
+}
diff --git a/drivers/nxp/sd/sd_mmc.mk b/drivers/nxp/sd/sd_mmc.mk
new file mode 100644
index 0000000..c83b1bd
--- /dev/null
+++ b/drivers/nxp/sd/sd_mmc.mk
@@ -0,0 +1,26 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${ADD_SD_MMC},)
+
+ADD_SD_MMC := 1
+
+SD_MMC_BOOT_SOURCES += ${PLAT_DRIVERS_PATH}/sd/sd_mmc.c \
+ drivers/io/io_block.c
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/sd
+
+ifeq (${BL_COMM_SD_MMC_NEEDED},yes)
+BL_COMMON_SOURCES += ${SD_MMC_BOOT_SOURCES}
+else
+ifeq (${BL2_SD_MMC_NEEDED},yes)
+BL2_SOURCES += ${SD_MMC_BOOT_SOURCES}
+endif
+ifeq (${BL3_SD_MMC_NEEDED},yes)
+BL31_SOURCES += ${SD_MMC_BOOT_SOURCES}
+endif
+endif
+endif
diff --git a/drivers/nxp/sec_mon/sec_mon.mk b/drivers/nxp/sec_mon/sec_mon.mk
new file mode 100644
index 0000000..aaac53f
--- /dev/null
+++ b/drivers/nxp/sec_mon/sec_mon.mk
@@ -0,0 +1,25 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${ADD_SNVS},)
+
+ADD_SNVS := 1
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/sec_mon
+
+SNVS_SOURCES += $(PLAT_DRIVERS_PATH)/sec_mon/snvs.c
+
+ifeq (${BL_COMM_SNVS_NEEDED},yes)
+BL_COMMON_SOURCES += ${SNVS_SOURCES}
+else
+ifeq (${BL2_SNVS_NEEDED},yes)
+BL2_SOURCES += ${SNVS_SOURCES}
+endif
+ifeq (${BL31_SNVS_NEEDED},yes)
+BL31_SOURCES += ${SNVS_SOURCES}
+endif
+endif
+endif
diff --git a/drivers/nxp/sec_mon/snvs.c b/drivers/nxp/sec_mon/snvs.c
new file mode 100644
index 0000000..6208b67
--- /dev/null
+++ b/drivers/nxp/sec_mon/snvs.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <snvs.h>
+
+static uintptr_t g_nxp_snvs_addr;
+
+void snvs_init(uintptr_t nxp_snvs_addr)
+{
+ g_nxp_snvs_addr = nxp_snvs_addr;
+}
+
+uint32_t get_snvs_state(void)
+{
+ struct snvs_regs *snvs = (struct snvs_regs *) (g_nxp_snvs_addr);
+
+ return (snvs_read32(&snvs->hp_stat) & HPSTS_MASK_SSM_ST);
+}
+
+static uint32_t do_snvs_state_transition(uint32_t state_transtion_bit,
+ uint32_t target_state)
+{
+ struct snvs_regs *snvs = (struct snvs_regs *) (g_nxp_snvs_addr);
+ uint32_t sts = get_snvs_state();
+ uint32_t fetch_cnt = 16U;
+ uint32_t val = snvs_read32(&snvs->hp_com) | state_transtion_bit;
+
+ snvs_write32(&snvs->hp_com, val);
+
+ /* polling loop till SNVS is in target state */
+ do {
+ sts = get_snvs_state();
+ } while ((sts != target_state) && ((--fetch_cnt) != 0));
+
+ return sts;
+}
+void transition_snvs_non_secure(void)
+{
+ struct snvs_regs *snvs = (struct snvs_regs *) (g_nxp_snvs_addr);
+ uint32_t sts = get_snvs_state();
+
+ switch (sts) {
+ /* If initial state is check or Non-Secure, then
+ * set the Software Security Violation Bit and
+ * transition to Non-Secure State.
+ */
+ case HPSTS_CHECK_SSM_ST:
+ sts = do_snvs_state_transition(HPCOM_SW_SV, HPSTS_NON_SECURE_SSM_ST);
+ break;
+
+ /* If initial state is Trusted, Secure or Soft-Fail, then
+ * first set the Software Security Violation Bit and
+ * transition to Soft-Fail State.
+ */
+ case HPSTS_TRUST_SSM_ST:
+ case HPSTS_SECURE_SSM_ST:
+ case HPSTS_SOFT_FAIL_SSM_ST:
+ sts = do_snvs_state_transition(HPCOM_SW_SV, HPSTS_NON_SECURE_SSM_ST);
+
+ /* If SSM Soft Fail to Non-Secure State Transition
+ * Disable is not set, then set SSM_ST bit and
+ * transition to Non-Secure State.
+ */
+ if ((snvs_read32(&snvs->hp_com) & HPCOM_SSM_SFNS_DIS) == 0) {
+ sts = do_snvs_state_transition(HPCOM_SSM_ST, HPSTS_NON_SECURE_SSM_ST);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void transition_snvs_soft_fail(void)
+{
+ do_snvs_state_transition(HPCOM_SW_FSV, HPSTS_SOFT_FAIL_SSM_ST);
+}
+
+uint32_t transition_snvs_trusted(void)
+{
+ struct snvs_regs *snvs = (struct snvs_regs *) (g_nxp_snvs_addr);
+ uint32_t sts = get_snvs_state();
+
+ switch (sts) {
+ /* If initial state is check, set the SSM_ST bit to
+ * change the state to trusted.
+ */
+ case HPSTS_CHECK_SSM_ST:
+ sts = do_snvs_state_transition(HPCOM_SSM_ST, HPSTS_TRUST_SSM_ST);
+ break;
+ /* If SSM Secure to Trusted State Transition Disable
+ * is not set, then set SSM_ST bit and
+ * transition to Trusted State.
+ */
+ case HPSTS_SECURE_SSM_ST:
+ if ((snvs_read32(&snvs->hp_com) & HPCOM_SSM_ST_DIS) == 0) {
+ sts = do_snvs_state_transition(HPCOM_SSM_ST, HPSTS_TRUST_SSM_ST);
+ }
+ break;
+ /* If initial state is Soft-Fail or Non-Secure, then
+ * transition to Trusted is not Possible.
+ */
+ default:
+ break;
+ }
+
+ return sts;
+}
+
+uint32_t transition_snvs_secure(void)
+{
+ uint32_t sts = get_snvs_state();
+
+ if (sts == HPSTS_SECURE_SSM_ST) {
+ return sts;
+ }
+
+ if (sts != HPSTS_TRUST_SSM_ST) {
+ sts = transition_snvs_trusted();
+ if (sts != HPSTS_TRUST_SSM_ST) {
+ return sts;
+ }
+ }
+
+ sts = do_snvs_state_transition(HPCOM_SSM_ST, HPSTS_TRUST_SSM_ST);
+
+ return sts;
+}
+
+void snvs_write_lp_gpr_bit(uint32_t offset, uint32_t bit_pos, bool flag_val)
+{
+ if (flag_val) {
+ snvs_write32(g_nxp_snvs_addr + offset,
+ (snvs_read32(g_nxp_snvs_addr + offset))
+ | (1 << bit_pos));
+ } else {
+ snvs_write32(g_nxp_snvs_addr + offset,
+ (snvs_read32(g_nxp_snvs_addr + offset))
+ & ~(1 << bit_pos));
+ }
+}
+
+uint32_t snvs_read_lp_gpr_bit(uint32_t offset, uint32_t bit_pos)
+{
+ return (snvs_read32(g_nxp_snvs_addr + offset) & (1 << bit_pos));
+}
+
+void snvs_disable_zeroize_lp_gpr(void)
+{
+ snvs_write_lp_gpr_bit(NXP_LPCR_OFFSET,
+ NXP_GPR_Z_DIS_BIT,
+ true);
+}
+
+#if defined(NXP_NV_SW_MAINT_LAST_EXEC_DATA) && defined(NXP_COINED_BB)
+void snvs_write_app_data_bit(uint32_t bit_pos)
+{
+ snvs_write_lp_gpr_bit(NXP_APP_DATA_LP_GPR_OFFSET,
+ bit_pos,
+ true);
+}
+
+uint32_t snvs_read_app_data(void)
+{
+ return snvs_read32(g_nxp_snvs_addr + NXP_APP_DATA_LP_GPR_OFFSET);
+}
+
+uint32_t snvs_read_app_data_bit(uint32_t bit_pos)
+{
+ uint8_t ret = snvs_read_lp_gpr_bit(NXP_APP_DATA_LP_GPR_OFFSET, bit_pos);
+
+ return ((ret != 0U) ? 1U : 0U);
+}
+
+void snvs_clear_app_data(void)
+{
+ snvs_write32(g_nxp_snvs_addr + NXP_APP_DATA_LP_GPR_OFFSET, 0x0);
+}
+#endif
diff --git a/drivers/nxp/sfp/fuse_prov.c b/drivers/nxp/sfp/fuse_prov.c
new file mode 100644
index 0000000..165474f
--- /dev/null
+++ b/drivers/nxp/sfp/fuse_prov.c
@@ -0,0 +1,462 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <caam.h>
+#include <common/debug.h>
+#include <dcfg.h>
+#include <drivers/delay_timer.h>
+#include <fuse_prov.h>
+#include <sfp.h>
+#include <sfp_error_codes.h>
+
+
+static int write_a_fuse(uint32_t *fuse_addr, uint32_t *fuse_hdr_val,
+ uint32_t mask)
+{
+ uint32_t last_stored_val = sfp_read32(fuse_addr);
+
+ /* Check if fuse already blown or not */
+ if ((last_stored_val & mask) == mask) {
+ return ERROR_ALREADY_BLOWN;
+ }
+
+ /* Write fuse in mirror registers */
+ sfp_write32(fuse_addr, last_stored_val | (*fuse_hdr_val & mask));
+
+ /* Read back to check if write success */
+ if (sfp_read32(fuse_addr) != (last_stored_val | (*fuse_hdr_val & mask))) {
+ return ERROR_WRITE;
+ }
+
+ return 0;
+}
+
+static int write_fuses(uint32_t *fuse_addr, uint32_t *fuse_hdr_val, uint8_t len)
+{
+ int i;
+
+ /* Check if fuse already blown or not */
+ for (i = 0; i < len; i++) {
+ if (sfp_read32(&fuse_addr[i]) != 0) {
+ return ERROR_ALREADY_BLOWN;
+ }
+ }
+
+ /* Write fuse in mirror registers */
+ for (i = 0; i < len; i++) {
+ sfp_write32(&fuse_addr[i], fuse_hdr_val[i]);
+ }
+
+ /* Read back to check if write success */
+ for (i = 0; i < len; i++) {
+ if (sfp_read32(&fuse_addr[i]) != fuse_hdr_val[i]) {
+ return ERROR_WRITE;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * This function program Super Root Key Hash (SRKH) in fuse
+ * registers.
+ */
+static int prog_srkh(struct fuse_hdr_t *fuse_hdr,
+ struct sfp_ccsr_regs_t *sfp_ccsr_regs)
+{
+ int ret = 0;
+
+ ret = write_fuses(sfp_ccsr_regs->srk_hash, fuse_hdr->srkh, 8);
+
+ if (ret != 0) {
+ ret = (ret == ERROR_ALREADY_BLOWN) ?
+ ERROR_SRKH_ALREADY_BLOWN : ERROR_SRKH_WRITE;
+ }
+
+ return ret;
+}
+
+/* This function program OEMUID[0-4] in fuse registers. */
+static int prog_oemuid(struct fuse_hdr_t *fuse_hdr,
+ struct sfp_ccsr_regs_t *sfp_ccsr_regs)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < 5; i++) {
+ /* Check OEMUIDx to be blown or not */
+ if (((fuse_hdr->flags >> (FLAG_OUID0_SHIFT + i)) & 0x1) != 0) {
+ /* Check if OEMUID[i] already blown or not */
+ ret = write_fuses(&sfp_ccsr_regs->oem_uid[i],
+ &fuse_hdr->oem_uid[i], 1);
+
+ if (ret != 0) {
+ ret = (ret == ERROR_ALREADY_BLOWN) ?
+ ERROR_OEMUID_ALREADY_BLOWN
+ : ERROR_OEMUID_WRITE;
+ }
+ }
+ }
+ return ret;
+}
+
+/* This function program DCV[0-1], DRV[0-1] in fuse registers. */
+static int prog_debug(struct fuse_hdr_t *fuse_hdr,
+ struct sfp_ccsr_regs_t *sfp_ccsr_regs)
+{
+ int ret;
+
+ /* Check DCV to be blown or not */
+ if (((fuse_hdr->flags >> (FLAG_DCV0_SHIFT)) & 0x3) != 0) {
+ /* Check if DCV[i] already blown or not */
+ ret = write_fuses(sfp_ccsr_regs->dcv, fuse_hdr->dcv, 2);
+
+ if (ret != 0) {
+ ret = (ret == ERROR_ALREADY_BLOWN) ?
+ ERROR_DCV_ALREADY_BLOWN
+ : ERROR_DCV_WRITE;
+ }
+ }
+
+ /* Check DRV to be blown or not */
+ if ((((fuse_hdr->flags >> (FLAG_DRV0_SHIFT)) & 0x3)) != 0) {
+ /* Check if DRV[i] already blown or not */
+ ret = write_fuses(sfp_ccsr_regs->drv, fuse_hdr->drv, 2);
+
+ if (ret != 0) {
+ ret = (ret == ERROR_ALREADY_BLOWN) ?
+ ERROR_DRV_ALREADY_BLOWN
+ : ERROR_DRV_WRITE;
+ } else {
+ /* Check for DRV hamming error */
+ if (sfp_read32((void *)(get_sfp_addr()
+ + SFP_SVHESR_OFFSET))
+ & SFP_SVHESR_DRV_MASK) {
+ return ERROR_DRV_HAMMING_ERROR;
+ }
+ }
+ }
+
+ return 0;
+}
+
+ /*
+ * Turn a 256-bit random value (32 bytes) into an OTPMK code word
+ * modifying the input data array in place
+ */
+static void otpmk_make_code_word_256(uint8_t *otpmk, bool minimal_flag)
+{
+ int i;
+ uint8_t parity_bit;
+ uint8_t code_bit;
+
+ if (minimal_flag == true) {
+ /*
+ * Force bits 252, 253, 254 and 255 to 1
+ * This is because these fuses may have already been blown
+ * and the OTPMK cannot force them back to 0
+ */
+ otpmk[252/8] |= (1 << (252%8));
+ otpmk[253/8] |= (1 << (253%8));
+ otpmk[254/8] |= (1 << (254%8));
+ otpmk[255/8] |= (1 << (255%8));
+ }
+
+ /* Generate the hamming code for the code word */
+ parity_bit = 0;
+ code_bit = 0;
+ for (i = 0; i < 256; i += 1) {
+ if ((otpmk[i/8] & (1 << (i%8))) != 0) {
+ parity_bit ^= 1;
+ code_bit ^= i;
+ }
+ }
+
+ /* Inverting otpmk[code_bit] will cause the otpmk
+ * to become a valid code word (except for overall parity)
+ */
+ if (code_bit < 252) {
+ otpmk[code_bit/8] ^= (1 << (code_bit % 8));
+ parity_bit ^= 1; // account for flipping a bit changing parity
+ } else {
+ /* Invert two bits: (code_bit - 4) and 4
+ * Because we invert two bits, no need to touch the parity bit
+ */
+ otpmk[(code_bit - 4)/8] ^= (1 << ((code_bit - 4) % 8));
+ otpmk[4/8] ^= (1 << (4 % 8));
+ }
+
+ /* Finally, adjust the overall parity of the otpmk
+ * otpmk bit 0
+ */
+ otpmk[0] ^= parity_bit;
+}
+
+/* This function program One Time Programmable Master Key (OTPMK)
+ * in fuse registers.
+ */
+static int prog_otpmk(struct fuse_hdr_t *fuse_hdr,
+ struct sfp_ccsr_regs_t *sfp_ccsr_regs)
+{
+ int ret = 0;
+ uint32_t otpmk_flags;
+ uint32_t otpmk_random[8] __aligned(CACHE_WRITEBACK_GRANULE);
+
+ otpmk_flags = (fuse_hdr->flags >> (FLAG_OTPMK_SHIFT)) & FLAG_OTPMK_MASK;
+
+ switch (otpmk_flags) {
+ case PROG_OTPMK_MIN:
+ memset(fuse_hdr->otpmk, 0, sizeof(fuse_hdr->otpmk));
+
+ /* Minimal OTPMK value (252-255 bits set to 1) */
+ fuse_hdr->otpmk[0] |= OTPMK_MIM_BITS_MASK;
+ break;
+
+ case PROG_OTPMK_RANDOM:
+ if (is_sec_enabled() == false) {
+ ret = ERROR_OTPMK_SEC_DISABLED;
+ goto out;
+ }
+
+ /* Generate Random number using CAAM for OTPMK */
+ memset(otpmk_random, 0, sizeof(otpmk_random));
+ if (get_rand_bytes_hw((uint8_t *)otpmk_random,
+ sizeof(otpmk_random)) != 0) {
+ ret = ERROR_OTPMK_SEC_ERROR;
+ goto out;
+ }
+
+ /* Run hamming over random no. to make OTPMK */
+ otpmk_make_code_word_256((uint8_t *)otpmk_random, false);
+
+ /* Swap OTPMK */
+ fuse_hdr->otpmk[0] = otpmk_random[7];
+ fuse_hdr->otpmk[1] = otpmk_random[6];
+ fuse_hdr->otpmk[2] = otpmk_random[5];
+ fuse_hdr->otpmk[3] = otpmk_random[4];
+ fuse_hdr->otpmk[4] = otpmk_random[3];
+ fuse_hdr->otpmk[5] = otpmk_random[2];
+ fuse_hdr->otpmk[6] = otpmk_random[1];
+ fuse_hdr->otpmk[7] = otpmk_random[0];
+ break;
+
+ case PROG_OTPMK_USER:
+ break;
+
+ case PROG_OTPMK_RANDOM_MIN:
+ /* Here assumption is that user is aware of minimal OTPMK
+ * already blown.
+ */
+
+ /* Generate Random number using CAAM for OTPMK */
+ if (is_sec_enabled() == false) {
+ ret = ERROR_OTPMK_SEC_DISABLED;
+ goto out;
+ }
+
+ memset(otpmk_random, 0, sizeof(otpmk_random));
+ if (get_rand_bytes_hw((uint8_t *)otpmk_random,
+ sizeof(otpmk_random)) != 0) {
+ ret = ERROR_OTPMK_SEC_ERROR;
+ goto out;
+ }
+
+ /* Run hamming over random no. to make OTPMK */
+ otpmk_make_code_word_256((uint8_t *)otpmk_random, true);
+
+ /* Swap OTPMK */
+ fuse_hdr->otpmk[0] = otpmk_random[7];
+ fuse_hdr->otpmk[1] = otpmk_random[6];
+ fuse_hdr->otpmk[2] = otpmk_random[5];
+ fuse_hdr->otpmk[3] = otpmk_random[4];
+ fuse_hdr->otpmk[4] = otpmk_random[3];
+ fuse_hdr->otpmk[5] = otpmk_random[2];
+ fuse_hdr->otpmk[6] = otpmk_random[1];
+ fuse_hdr->otpmk[7] = otpmk_random[0];
+ break;
+
+ case PROG_OTPMK_USER_MIN:
+ /*
+ * Here assumption is that user is aware of minimal OTPMK
+ * already blown. Check if minimal bits are set in user
+ * supplied OTPMK.
+ */
+ if ((fuse_hdr->otpmk[0] & OTPMK_MIM_BITS_MASK) !=
+ OTPMK_MIM_BITS_MASK) {
+ ret = ERROR_OTPMK_USER_MIN;
+ goto out;
+ }
+ break;
+
+ default:
+ ret = 0;
+ goto out;
+ }
+
+ ret = write_fuses(sfp_ccsr_regs->otpmk, fuse_hdr->otpmk, 8);
+
+ if (ret != 0) {
+ ret = (ret == ERROR_ALREADY_BLOWN) ?
+ ERROR_OTPMK_ALREADY_BLOWN
+ : ERROR_OTPMK_WRITE;
+ } else {
+ /* Check for DRV hamming error */
+ if ((sfp_read32((void *)(get_sfp_addr() + SFP_SVHESR_OFFSET))
+ & SFP_SVHESR_OTPMK_MASK) != 0) {
+ ret = ERROR_OTPMK_HAMMING_ERROR;
+ }
+ }
+
+out:
+ return ret;
+}
+
+/* This function program OSPR1 in fuse registers.
+ */
+static int prog_ospr1(struct fuse_hdr_t *fuse_hdr,
+ struct sfp_ccsr_regs_t *sfp_ccsr_regs)
+{
+ int ret;
+ uint32_t mask = 0;
+
+#ifdef NXP_SFP_VER_3_4
+ if (((fuse_hdr->flags >> FLAG_MC_SHIFT) & 0x1) != 0) {
+ mask = OSPR1_MC_MASK;
+ }
+#endif
+ if (((fuse_hdr->flags >> FLAG_DBG_LVL_SHIFT) & 0x1) != 0) {
+ mask = mask | OSPR1_DBG_LVL_MASK;
+ }
+
+ ret = write_a_fuse(&sfp_ccsr_regs->ospr1, &fuse_hdr->ospr1, mask);
+
+ if (ret != 0) {
+ ret = (ret == ERROR_ALREADY_BLOWN) ?
+ ERROR_OSPR1_ALREADY_BLOWN
+ : ERROR_OSPR1_WRITE;
+ }
+
+ return ret;
+}
+
+/* This function program SYSCFG in fuse registers.
+ */
+static int prog_syscfg(struct fuse_hdr_t *fuse_hdr,
+ struct sfp_ccsr_regs_t *sfp_ccsr_regs)
+{
+ int ret;
+
+ /* Check if SYSCFG already blown or not */
+ ret = write_a_fuse(&sfp_ccsr_regs->ospr, &fuse_hdr->sc, OSPR0_SC_MASK);
+
+ if (ret != 0) {
+ ret = (ret == ERROR_ALREADY_BLOWN) ?
+ ERROR_SC_ALREADY_BLOWN
+ : ERROR_SC_WRITE;
+ }
+
+ return ret;
+}
+
+/* This function does fuse provisioning.
+ */
+int provision_fuses(unsigned long long fuse_scr_addr,
+ bool en_povdd_status)
+{
+ struct fuse_hdr_t *fuse_hdr = NULL;
+ struct sfp_ccsr_regs_t *sfp_ccsr_regs = (void *)(get_sfp_addr()
+ + SFP_FUSE_REGS_OFFSET);
+ int ret = 0;
+
+ fuse_hdr = (struct fuse_hdr_t *)fuse_scr_addr;
+
+ /*
+ * Check for Write Protect (WP) fuse. If blown then do
+ * no fuse provisioning.
+ */
+ if ((sfp_read32(&sfp_ccsr_regs->ospr) & 0x1) != 0) {
+ goto out;
+ }
+
+ /* Check if SRKH to be blown or not */
+ if (((fuse_hdr->flags >> FLAG_SRKH_SHIFT) & 0x1) != 0) {
+ INFO("Fuse: Program SRKH\n");
+ ret = prog_srkh(fuse_hdr, sfp_ccsr_regs);
+ if (ret != 0) {
+ error_handler(ret);
+ goto out;
+ }
+ }
+
+ /* Check if OEMUID to be blown or not */
+ if (((fuse_hdr->flags >> FLAG_OUID0_SHIFT) & FLAG_OUID_MASK) != 0) {
+ INFO("Fuse: Program OEMUIDs\n");
+ ret = prog_oemuid(fuse_hdr, sfp_ccsr_regs);
+ if (ret != 0) {
+ error_handler(ret);
+ goto out;
+ }
+ }
+
+ /* Check if Debug values to be blown or not */
+ if (((fuse_hdr->flags >> FLAG_DCV0_SHIFT) & FLAG_DEBUG_MASK) != 0) {
+ INFO("Fuse: Program Debug values\n");
+ ret = prog_debug(fuse_hdr, sfp_ccsr_regs);
+ if (ret != 0) {
+ error_handler(ret);
+ goto out;
+ }
+ }
+
+ /* Check if OTPMK values to be blown or not */
+ if (((fuse_hdr->flags >> FLAG_OTPMK_SHIFT) & PROG_NO_OTPMK) !=
+ PROG_NO_OTPMK) {
+ INFO("Fuse: Program OTPMK\n");
+ ret = prog_otpmk(fuse_hdr, sfp_ccsr_regs);
+ if (ret != 0) {
+ error_handler(ret);
+ goto out;
+ }
+ }
+
+
+ /* Check if MC or DBG LVL to be blown or not */
+ if ((((fuse_hdr->flags >> FLAG_MC_SHIFT) & 0x1) != 0) ||
+ (((fuse_hdr->flags >> FLAG_DBG_LVL_SHIFT) & 0x1) != 0)) {
+ INFO("Fuse: Program OSPR1\n");
+ ret = prog_ospr1(fuse_hdr, sfp_ccsr_regs);
+ if (ret != 0) {
+ error_handler(ret);
+ goto out;
+ }
+ }
+
+ /* Check if SYSCFG to be blown or not */
+ if (((fuse_hdr->flags >> FLAG_SYSCFG_SHIFT) & 0x1) != 0) {
+ INFO("Fuse: Program SYSCFG\n");
+ ret = prog_syscfg(fuse_hdr, sfp_ccsr_regs);
+ if (ret != 0) {
+ error_handler(ret);
+ goto out;
+ }
+ }
+
+ if (en_povdd_status) {
+ ret = sfp_program_fuses();
+ if (ret != 0) {
+ error_handler(ret);
+ goto out;
+ }
+ }
+out:
+ return ret;
+}
diff --git a/drivers/nxp/sfp/sfp.c b/drivers/nxp/sfp/sfp.c
new file mode 100644
index 0000000..e06c6b9
--- /dev/null
+++ b/drivers/nxp/sfp/sfp.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <caam.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <sfp.h>
+#include <sfp_error_codes.h>
+
+static uintptr_t g_nxp_sfp_addr;
+static uint32_t srk_hash[SRK_HASH_SIZE/sizeof(uint32_t)]
+ __aligned(CACHE_WRITEBACK_GRANULE);
+
+void sfp_init(uintptr_t nxp_sfp_addr)
+{
+ g_nxp_sfp_addr = nxp_sfp_addr;
+}
+
+uintptr_t get_sfp_addr(void)
+{
+ return g_nxp_sfp_addr;
+}
+
+uint32_t *get_sfp_srk_hash(void)
+{
+ struct sfp_ccsr_regs_t *sfp_ccsr_regs =
+ (void *) (g_nxp_sfp_addr + SFP_FUSE_REGS_OFFSET);
+ int i = 0;
+
+ /* Add comparison of hash with SFP hash here */
+ for (i = 0; i < SRK_HASH_SIZE/sizeof(uint32_t); i++)
+ srk_hash[i] =
+ mmio_read_32((uintptr_t)&sfp_ccsr_regs->srk_hash[i]);
+
+ return srk_hash;
+}
+
+void set_sfp_wr_disable(void)
+{
+ /*
+ * Mark SFP Write Disable and Write Disable Lock
+ * Bit to prevent write to SFP fuses like
+ * OUID's, Key Revocation fuse etc
+ */
+ void *sfpcr = (void *)(g_nxp_sfp_addr + SFP_SFPCR_OFFSET);
+ uint32_t sfpcr_val;
+
+ sfpcr_val = sfp_read32(sfpcr);
+ sfpcr_val |= (SFP_SFPCR_WD | SFP_SFPCR_WDL);
+ sfp_write32(sfpcr, sfpcr_val);
+}
+
+int sfp_program_fuses(void)
+{
+ uint32_t ingr;
+ uint32_t sfp_cmd_status = 0U;
+ int ret = 0;
+
+ /* Program SFP fuses from mirror registers */
+ sfp_write32((void *)(g_nxp_sfp_addr + SFP_INGR_OFFSET),
+ SFP_INGR_PROGFB_CMD);
+
+ /* Wait until fuse programming is successful */
+ do {
+ ingr = sfp_read32(g_nxp_sfp_addr + SFP_INGR_OFFSET);
+ } while (ingr & SFP_INGR_PROGFB_CMD);
+
+ /* Check for SFP fuse programming error */
+ sfp_cmd_status = sfp_read32(g_nxp_sfp_addr + SFP_INGR_OFFSET)
+ & SFP_INGR_ERROR_MASK;
+
+ if (sfp_cmd_status != 0U) {
+ return ERROR_PROGFB_CMD;
+ }
+
+ return ret;
+}
+
+uint32_t sfp_read_oem_uid(uint8_t oem_uid)
+{
+ uint32_t val = 0U;
+ struct sfp_ccsr_regs_t *sfp_ccsr_regs = (void *)(g_nxp_sfp_addr
+ + SFP_FUSE_REGS_OFFSET);
+
+ if (oem_uid > MAX_OEM_UID) {
+ ERROR("Invalid OEM UID received.\n");
+ return ERROR_OEMUID_WRITE;
+ }
+
+ val = sfp_read32(&sfp_ccsr_regs->oem_uid[oem_uid]);
+
+ return val;
+}
+
+/*
+ * return val: 0 - No update required.
+ * 1 - successful update done.
+ * ERROR_OEMUID_WRITE - Invalid OEM UID
+ */
+uint32_t sfp_write_oem_uid(uint8_t oem_uid, uint32_t sfp_val)
+{
+ uint32_t val = 0U;
+ struct sfp_ccsr_regs_t *sfp_ccsr_regs = (void *)(g_nxp_sfp_addr
+ + SFP_FUSE_REGS_OFFSET);
+
+ val = sfp_read_oem_uid(oem_uid);
+
+ if (val == ERROR_OEMUID_WRITE) {
+ return ERROR_OEMUID_WRITE;
+ }
+
+ /* Counter already set. No need to do anything */
+ if ((val & sfp_val) != 0U) {
+ return 0U;
+ }
+
+ val |= sfp_val;
+
+ INFO("SFP Value is %x for setting sfp_val = %d\n", val, sfp_val);
+
+ sfp_write32(&sfp_ccsr_regs->oem_uid[oem_uid], val);
+
+ return 1U;
+}
+
+int sfp_check_its(void)
+{
+ struct sfp_ccsr_regs_t *sfp_ccsr_regs = (void *)(g_nxp_sfp_addr
+ + SFP_FUSE_REGS_OFFSET);
+
+ if ((sfp_read32(&sfp_ccsr_regs->ospr) & OSPR_ITS_MASK) != 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int sfp_check_oem_wp(void)
+{
+ struct sfp_ccsr_regs_t *sfp_ccsr_regs = (void *)(g_nxp_sfp_addr
+ + SFP_FUSE_REGS_OFFSET);
+
+ if ((sfp_read32(&sfp_ccsr_regs->ospr) & OSPR_WP_MASK) != 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/* This function returns ospr's key_revoc values.*/
+uint32_t get_key_revoc(void)
+{
+ struct sfp_ccsr_regs_t *sfp_ccsr_regs = (void *)(g_nxp_sfp_addr
+ + SFP_FUSE_REGS_OFFSET);
+
+ return (sfp_read32(&sfp_ccsr_regs->ospr) & OSPR_KEY_REVOC_MASK) >>
+ OSPR_KEY_REVOC_SHIFT;
+}
diff --git a/drivers/nxp/sfp/sfp.mk b/drivers/nxp/sfp/sfp.mk
new file mode 100644
index 0000000..de708c5
--- /dev/null
+++ b/drivers/nxp/sfp/sfp.mk
@@ -0,0 +1,33 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-----------------------------------------------------------------------------
+ifeq (${SFP_ADDED},)
+
+SFP_ADDED := 1
+$(eval $(call add_define, NXP_SFP_ENABLED))
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/sfp
+
+SFP_SOURCES += $(PLAT_DRIVERS_PATH)/sfp/sfp.c
+
+ifeq (${FUSE_PROG}, 1)
+SFP_BL2_SOURCES += $(PLAT_DRIVERS_PATH)/sfp/fuse_prov.c
+endif
+
+ifeq (${BL_COMM_SFP_NEEDED},yes)
+BL_COMMON_SOURCES += ${SFP_SOURCES}
+BL2_SOURCES += ${SFP_BL2_SOURCES}
+else
+ifeq (${BL2_SFP_NEEDED},yes)
+BL2_SOURCES += ${SFP_SOURCES}\
+ ${SFP_BL2_SOURCES}
+endif
+ifeq (${BL31_SFP_NEEDED},yes)
+BL31_SOURCES += ${SFP_SOURCES}
+endif
+endif
+endif
+#------------------------------------------------
diff --git a/drivers/nxp/timer/nxp_timer.c b/drivers/nxp/timer/nxp_timer.c
new file mode 100644
index 0000000..8eecd2e
--- /dev/null
+++ b/drivers/nxp/timer/nxp_timer.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <nxp_timer.h>
+#include <plat/common/platform.h>
+
+static uintptr_t g_nxp_timer_addr;
+static timer_ops_t ops;
+
+uint64_t get_timer_val(uint64_t start)
+{
+ uint64_t cntpct;
+
+ isb();
+ cntpct = read_cntpct_el0();
+ return (cntpct * 1000ULL / read_cntfrq_el0() - start);
+}
+
+static uint32_t timer_get_value(void)
+{
+ uint64_t cntpct;
+
+ isb();
+ cntpct = read_cntpct_el0();
+#ifdef ERRATA_SOC_A008585
+ uint8_t max_fetch_count = 10U;
+ /* This erratum number needs to be confirmed to match ARM document */
+ uint64_t temp;
+
+ isb();
+ temp = read_cntpct_el0();
+
+ while (temp != cntpct && max_fetch_count) {
+ isb();
+ cntpct = read_cntpct_el0();
+ isb();
+ temp = read_cntpct_el0();
+ max_fetch_count--;
+ }
+#endif
+
+ /*
+ * 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)(~cntpct);
+}
+
+static void delay_timer_init_args(uint32_t mult, uint32_t div)
+{
+ ops.get_timer_value = timer_get_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);
+}
+
+/*
+ * Initialise the nxp on-chip free rolling usec counter as the delay
+ * timer.
+ */
+void delay_timer_init(uintptr_t nxp_timer_addr)
+{
+ /* Value in ticks */
+ unsigned int mult = MHZ_TICKS_PER_SEC;
+
+ unsigned int div;
+
+ unsigned int counter_base_frequency = plat_get_syscnt_freq2();
+
+ g_nxp_timer_addr = nxp_timer_addr;
+ /* Rounding off the Counter Frequency to MHZ_TICKS_PER_SEC */
+ if (counter_base_frequency > MHZ_TICKS_PER_SEC) {
+ counter_base_frequency = (counter_base_frequency
+ / MHZ_TICKS_PER_SEC)
+ * MHZ_TICKS_PER_SEC;
+ } else {
+ counter_base_frequency = (counter_base_frequency
+ / KHZ_TICKS_PER_SEC)
+ * KHZ_TICKS_PER_SEC;
+ }
+
+ /* Value in ticks per second (Hz) */
+ div = counter_base_frequency;
+
+ /* Reduce multiplier and divider by dividing them repeatedly by 10 */
+ while ((mult % 10U == 0U) && (div % 10U == 0U)) {
+ mult /= 10U;
+ div /= 10U;
+ }
+
+ /* Enable and initialize the System level generic timer */
+ mmio_write_32(g_nxp_timer_addr + CNTCR_OFF,
+ CNTCR_FCREQ(0) | CNTCR_EN);
+
+ delay_timer_init_args(mult, div);
+}
+
+
+#ifdef IMAGE_BL31
+/*******************************************************************************
+ * TBD: Configures access to the system counter timer module.
+ ******************************************************************************/
+void ls_configure_sys_timer(uintptr_t ls_sys_timctl_base,
+ uint8_t ls_config_cntacr,
+ uint8_t plat_ls_ns_timer_frame_id)
+{
+ unsigned int reg_val;
+
+ if (ls_config_cntacr == 1U) {
+ 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(ls_sys_timctl_base +
+ CNTACR_BASE(plat_ls_ns_timer_frame_id), reg_val);
+ mmio_write_32(ls_sys_timctl_base, plat_get_syscnt_freq2());
+ }
+
+ reg_val = (1U << CNTNSAR_NS_SHIFT(plat_ls_ns_timer_frame_id));
+ mmio_write_32(ls_sys_timctl_base + CNTNSAR, reg_val);
+}
+
+void enable_init_timer(void)
+{
+ /* Enable and initialize the System level generic timer */
+ mmio_write_32(g_nxp_timer_addr + CNTCR_OFF,
+ CNTCR_FCREQ(0) | CNTCR_EN);
+}
+#endif
diff --git a/drivers/nxp/timer/timer.mk b/drivers/nxp/timer/timer.mk
new file mode 100644
index 0000000..d658d19
--- /dev/null
+++ b/drivers/nxp/timer/timer.mk
@@ -0,0 +1,25 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${ADD_TIMER},)
+
+ADD_TIMER := 1
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/timer
+TIMER_SOURCES += drivers/delay_timer/delay_timer.c \
+ $(PLAT_DRIVERS_PATH)/timer/nxp_timer.c
+
+ifeq (${BL_COMM_TIMER_NEEDED},yes)
+BL_COMMON_SOURCES += ${TIMER_SOURCES}
+else
+ifeq (${BL2_TIMER_NEEDED},yes)
+BL2_SOURCES += ${TIMER_SOURCES}
+endif
+ifeq (${BL31_TIMER_NEEDED},yes)
+BL31_SOURCES += ${TIMER_SOURCES}
+endif
+endif
+endif
diff --git a/drivers/nxp/tzc/plat_tzc380.c b/drivers/nxp/tzc/plat_tzc380.c
new file mode 100644
index 0000000..13cf3b9
--- /dev/null
+++ b/drivers/nxp/tzc/plat_tzc380.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <plat_tzc380.h>
+
+#pragma weak populate_tzc380_reg_list
+
+#ifdef DEFAULT_TZASC_CONFIG
+/*
+ * Typical Memory map of DRAM0
+ * |-----------NXP_NS_DRAM_ADDR ( = NXP_DRAM0_ADDR)----------|
+ * | |
+ * | |
+ * | Non-SECURE REGION |
+ * | |
+ * | |
+ * | |
+ * |------- (NXP_NS_DRAM_ADDR + NXP_NS_DRAM_SIZE - 1) -------|
+ * |-----------------NXP_SECURE_DRAM_ADDR--------------------|
+ * | |
+ * | |
+ * | |
+ * | SECURE REGION (= 64MB) |
+ * | |
+ * | |
+ * | |
+ * |--- (NXP_SECURE_DRAM_ADDR + NXP_SECURE_DRAM_SIZE - 1)----|
+ * |-----------------NXP_SP_SHRD_DRAM_ADDR-------------------|
+ * | |
+ * | Secure EL1 Payload SHARED REGION (= 2MB) |
+ * | |
+ * |-----------(NXP_DRAM0_ADDR + NXP_DRAM0_SIZE - 1)---------|
+ *
+ *
+ *
+ * Typical Memory map of DRAM1
+ * |---------------------NXP_DRAM1_ADDR----------------------|
+ * | |
+ * | |
+ * | Non-SECURE REGION |
+ * | |
+ * | |
+ * |---(NXP_DRAM1_ADDR + Dynamically calculated Size - 1) ---|
+ *
+ *
+ * Typical Memory map of DRAM2
+ * |---------------------NXP_DRAM2_ADDR----------------------|
+ * | |
+ * | |
+ * | Non-SECURE REGION |
+ * | |
+ * | |
+ * |---(NXP_DRAM2_ADDR + Dynamically calculated Size - 1) ---|
+ */
+
+/*****************************************************************************
+ * This function sets up access permissions on memory regions
+ *
+ * Input:
+ * tzc380_reg_list : TZC380 Region List
+ * dram_idx : DRAM index
+ * list_idx : TZC380 Region List Index
+ * dram_start_addr : Start address of DRAM at dram_idx.
+ * dram_size : Size of DRAM at dram_idx.
+ * secure_dram_sz : Secure DRAM Size
+ * shrd_dram_sz : Shared DRAM Size
+ *
+ * Out:
+ * list_idx : last populated index + 1
+ *
+ ****************************************************************************/
+int populate_tzc380_reg_list(struct tzc380_reg *tzc380_reg_list,
+ int dram_idx, int list_idx,
+ uint64_t dram_start_addr,
+ uint64_t dram_size,
+ uint32_t secure_dram_sz,
+ uint32_t shrd_dram_sz)
+{
+ /* Region 0: Default region marked as Non-Secure */
+ if (list_idx == 0) {
+ tzc380_reg_list[list_idx].secure = TZC_ATTR_SP_NS_RW;
+ tzc380_reg_list[list_idx].enabled = TZC_ATTR_REGION_DISABLE;
+ tzc380_reg_list[list_idx].addr = UL(0x0);
+ tzc380_reg_list[list_idx].size = 0x0;
+ tzc380_reg_list[list_idx].sub_mask = 0x0; /* all enabled */
+ list_idx++;
+ }
+ /* Continue with list entries for index > 0 */
+ if (dram_idx == 0) {
+ /* TZC Region 1 on DRAM0 for Secure Memory*/
+ tzc380_reg_list[list_idx].secure = TZC_ATTR_SP_S_RW;
+ tzc380_reg_list[list_idx].enabled = TZC_ATTR_REGION_ENABLE;
+ tzc380_reg_list[list_idx].addr = dram_start_addr + dram_size;
+ tzc380_reg_list[list_idx].size = secure_dram_sz;
+ tzc380_reg_list[list_idx].sub_mask = 0x0; /* all enabled */
+ list_idx++;
+
+ /* TZC Region 2 on DRAM0 for Shared Memory*/
+ tzc380_reg_list[list_idx].secure = TZC_ATTR_SP_S_RW;
+ tzc380_reg_list[list_idx].enabled = TZC_ATTR_REGION_ENABLE;
+ tzc380_reg_list[list_idx].addr = dram_start_addr + dram_size + secure_dram_sz;
+ tzc380_reg_list[list_idx].size = shrd_dram_sz;
+ tzc380_reg_list[list_idx].sub_mask = 0x0; /* all enabled */
+ list_idx++;
+
+ }
+
+ return list_idx;
+}
+#else
+int populate_tzc380_reg_list(struct tzc380_reg *tzc380_reg_list,
+ int dram_idx, int list_idx,
+ uint64_t dram_start_addr,
+ uint64_t dram_size,
+ uint32_t secure_dram_sz,
+ uint32_t shrd_dram_sz)
+{
+ ERROR("tzc380_reg_list used is not a default list\n");
+ ERROR("%s needs to be over-written.\n", __func__);
+ return 0;
+}
+#endif /* DEFAULT_TZASC_CONFIG */
+
+
+void mem_access_setup(uintptr_t base, uint32_t total_regions,
+ struct tzc380_reg *tzc380_reg_list)
+{
+ uint32_t indx = 0;
+ unsigned int attr_value;
+
+ VERBOSE("Configuring TrustZone Controller tzc380\n");
+
+ tzc380_init(base);
+
+ tzc380_set_action(TZC_ACTION_NONE);
+
+ for (indx = 0; indx < total_regions; indx++) {
+ attr_value = tzc380_reg_list[indx].secure |
+ TZC_ATTR_SUBREG_DIS(tzc380_reg_list[indx].sub_mask) |
+ TZC_ATTR_REGION_SIZE(tzc380_reg_list[indx].size) |
+ tzc380_reg_list[indx].enabled;
+
+ tzc380_configure_region(indx, tzc380_reg_list[indx].addr,
+ attr_value);
+ }
+
+ tzc380_set_action(TZC_ACTION_ERR);
+}
diff --git a/drivers/nxp/tzc/plat_tzc400.c b/drivers/nxp/tzc/plat_tzc400.c
new file mode 100644
index 0000000..4fe5221
--- /dev/null
+++ b/drivers/nxp/tzc/plat_tzc400.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <common/debug.h>
+
+#include <plat_tzc400.h>
+
+#pragma weak populate_tzc400_reg_list
+
+#ifdef DEFAULT_TZASC_CONFIG
+/*
+ * Typical Memory map of DRAM0
+ * |-----------NXP_NS_DRAM_ADDR ( = NXP_DRAM0_ADDR)----------|
+ * | |
+ * | |
+ * | Non-SECURE REGION |
+ * | |
+ * | |
+ * | |
+ * |------- (NXP_NS_DRAM_ADDR + NXP_NS_DRAM_SIZE - 1) -------|
+ * |-----------------NXP_SECURE_DRAM_ADDR--------------------|
+ * | |
+ * | |
+ * | |
+ * | SECURE REGION (= 64MB) |
+ * | |
+ * | |
+ * | |
+ * |--- (NXP_SECURE_DRAM_ADDR + NXP_SECURE_DRAM_SIZE - 1)----|
+ * |-----------------NXP_SP_SHRD_DRAM_ADDR-------------------|
+ * | |
+ * | Secure EL1 Payload SHARED REGION (= 2MB) |
+ * | |
+ * |-----------(NXP_DRAM0_ADDR + NXP_DRAM0_SIZE - 1)---------|
+ *
+ *
+ *
+ * Typical Memory map of DRAM1
+ * |---------------------NXP_DRAM1_ADDR----------------------|
+ * | |
+ * | |
+ * | Non-SECURE REGION |
+ * | |
+ * | |
+ * |---(NXP_DRAM1_ADDR + Dynamically calculated Size - 1) ---|
+ *
+ *
+ * Typical Memory map of DRAM2
+ * |---------------------NXP_DRAM2_ADDR----------------------|
+ * | |
+ * | |
+ * | Non-SECURE REGION |
+ * | |
+ * | |
+ * |---(NXP_DRAM2_ADDR + Dynamically calculated Size - 1) ---|
+ */
+
+/*****************************************************************************
+ * This function sets up access permissions on memory regions
+ *
+ * Input:
+ * tzc400_reg_list : TZC400 Region List
+ * dram_idx : DRAM index
+ * list_idx : TZC400 Region List Index
+ * dram_start_addr : Start address of DRAM at dram_idx.
+ * dram_size : Size of DRAM at dram_idx.
+ * secure_dram_sz : Secure DRAM Size
+ * shrd_dram_sz : Shared DRAM Size
+ *
+ * Out:
+ * list_idx : last populated index + 1
+ *
+ ****************************************************************************/
+int populate_tzc400_reg_list(struct tzc400_reg *tzc400_reg_list,
+ int dram_idx, int list_idx,
+ uint64_t dram_start_addr,
+ uint64_t dram_size,
+ uint32_t secure_dram_sz,
+ uint32_t shrd_dram_sz)
+{
+ if (list_idx == 0) {
+ /* No need to configure TZC Region 0 in this list.
+ */
+ list_idx++;
+ }
+ /* Continue with list entries for index > 0 */
+ if (dram_idx == 0) {
+ /* TZC Region 1 on DRAM0 for Secure Memory*/
+ tzc400_reg_list[list_idx].reg_filter_en = 1;
+ tzc400_reg_list[list_idx].start_addr = dram_start_addr + dram_size;
+ tzc400_reg_list[list_idx].end_addr = dram_start_addr + dram_size
+ + secure_dram_sz - 1;
+ tzc400_reg_list[list_idx].sec_attr = TZC_REGION_S_RDWR;
+ tzc400_reg_list[list_idx].nsaid_permissions = TZC_REGION_NS_NONE;
+ list_idx++;
+
+ /* TZC Region 2 on DRAM0 for Shared Memory*/
+ tzc400_reg_list[list_idx].reg_filter_en = 1;
+ tzc400_reg_list[list_idx].start_addr = dram_start_addr + dram_size
+ + secure_dram_sz;
+ tzc400_reg_list[list_idx].end_addr = dram_start_addr + dram_size
+ + secure_dram_sz
+ + shrd_dram_sz
+ - 1;
+ tzc400_reg_list[list_idx].sec_attr = TZC_REGION_S_RDWR;
+ tzc400_reg_list[list_idx].nsaid_permissions = TZC_NS_ACCESS_ID;
+ list_idx++;
+
+ /* TZC Region 3 on DRAM0 for Non-Secure Memory*/
+ tzc400_reg_list[list_idx].reg_filter_en = 1;
+ tzc400_reg_list[list_idx].start_addr = dram_start_addr;
+ tzc400_reg_list[list_idx].end_addr = dram_start_addr + dram_size
+ - 1;
+ tzc400_reg_list[list_idx].sec_attr = TZC_REGION_S_RDWR;
+ tzc400_reg_list[list_idx].nsaid_permissions = TZC_NS_ACCESS_ID;
+ list_idx++;
+ } else {
+ /* TZC Region 3+i on DRAM(> 0) for Non-Secure Memory*/
+ tzc400_reg_list[list_idx].reg_filter_en = 1;
+ tzc400_reg_list[list_idx].start_addr = dram_start_addr;
+ tzc400_reg_list[list_idx].end_addr = dram_start_addr + dram_size
+ - 1;
+ tzc400_reg_list[list_idx].sec_attr = TZC_REGION_S_RDWR;
+ tzc400_reg_list[list_idx].nsaid_permissions = TZC_NS_ACCESS_ID;
+ list_idx++;
+ }
+
+ return list_idx;
+}
+#else
+int populate_tzc400_reg_list(struct tzc400_reg *tzc400_reg_list,
+ int dram_idx, int list_idx,
+ uint64_t dram_start_addr,
+ uint64_t dram_size,
+ uint32_t secure_dram_sz,
+ uint32_t shrd_dram_sz)
+{
+ ERROR("tzc400_reg_list used is not a default list\n");
+ ERROR("%s needs to be over-written.\n", __func__);
+ return 0;
+}
+#endif /* DEFAULT_TZASC_CONFIG */
+
+/*******************************************************************************
+ * Configure memory access permissions
+ * - Region 0 with no access;
+ * - Region 1 to 4 as per the tzc400_reg_list populated by
+ * function populate_tzc400_reg_list() with default for all the SoC.
+ ******************************************************************************/
+void mem_access_setup(uintptr_t base, uint32_t total_regions,
+ struct tzc400_reg *tzc400_reg_list)
+{
+ uint32_t list_indx = 0U;
+
+ INFO("Configuring TrustZone Controller\n");
+
+ tzc400_init(base);
+
+ /* Disable filters. */
+ tzc400_disable_filters();
+
+ /* Region 0 set to no access by default */
+ tzc400_configure_region0(TZC_REGION_S_NONE, 0U);
+
+ for (list_indx = 1U; list_indx < total_regions; list_indx++) {
+ tzc400_configure_region(
+ tzc400_reg_list[list_indx].reg_filter_en,
+ list_indx,
+ tzc400_reg_list[list_indx].start_addr,
+ tzc400_reg_list[list_indx].end_addr,
+ tzc400_reg_list[list_indx].sec_attr,
+ tzc400_reg_list[list_indx].nsaid_permissions);
+ }
+
+ /*
+ * 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();
+}
diff --git a/drivers/nxp/tzc/tzc.mk b/drivers/nxp/tzc/tzc.mk
new file mode 100644
index 0000000..4418bfc
--- /dev/null
+++ b/drivers/nxp/tzc/tzc.mk
@@ -0,0 +1,40 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${ADD_TZASC},)
+
+ADD_TZASC := 1
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/tzc
+
+ifeq ($(TZC_ID), TZC400)
+TZASC_SOURCES += drivers/arm/tzc/tzc400.c\
+ $(PLAT_DRIVERS_PATH)/tzc/plat_tzc400.c
+else
+ifeq ($(TZC_ID), TZC380)
+TZASC_SOURCES += drivers/arm/tzc/tzc380.c\
+ $(PLAT_DRIVERS_PATH)/tzc/plat_tzc380.c
+else
+ifeq ($(TZC_ID), NONE)
+ $(info -> No TZC present on platform)
+else
+ $(error -> TZC type not set!)
+endif
+endif
+endif
+
+ifeq (${BL_COMM_TZASC_NEEDED},yes)
+BL_COMMON_SOURCES += ${TZASC_SOURCES}
+else
+ifeq (${BL2_TZASC_NEEDED},yes)
+BL2_SOURCES += ${TZASC_SOURCES}
+endif
+ifeq (${BL31_TZASC_NEEDED},yes)
+BL31_SOURCES += ${TZASC_SOURCES}
+endif
+endif
+
+endif
diff --git a/drivers/partition/gpt.c b/drivers/partition/gpt.c
new file mode 100644
index 0000000..4fe8322
--- /dev/null
+++ b/drivers/partition/gpt.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/partition/efi.h>
+#include <drivers/partition/gpt.h>
+#include <lib/utils.h>
+
+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;
+ guidcpy(&entry->part_guid, &gpt_entry->unique_uuid);
+ guidcpy(&entry->type_guid, &gpt_entry->type_uuid);
+
+ return 0;
+}
diff --git a/drivers/partition/partition.c b/drivers/partition/partition.c
new file mode 100644
index 0000000..1881c91
--- /dev/null
+++ b/drivers/partition/partition.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/tf_crc32.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/partition/efi.h>
+#include <drivers/partition/partition.h>
+#include <drivers/partition/gpt.h>
+#include <drivers/partition/mbr.h>
+#include <plat/common/platform.h>
+
+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 %" PRIx64 "-%" PRIx64 "\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 and header CRC.
+ * 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;
+ uint32_t header_crc, calc_crc;
+
+ 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;
+ }
+
+ /*
+ * UEFI Spec 2.8 March 2019 Page 119: HeaderCRC32 value is
+ * computed by setting this field to 0, and computing the
+ * 32-bit CRC for HeaderSize bytes.
+ */
+ header_crc = header.header_crc;
+ header.header_crc = 0U;
+
+ calc_crc = tf_crc32(0U, (uint8_t *)&header, DEFAULT_GPT_HEADER_SIZE);
+ if (header_crc != calc_crc) {
+ ERROR("Invalid GPT Header CRC: Expected 0x%x but got 0x%x.\n",
+ header_crc, calc_crc);
+ return -EINVAL;
+ }
+
+ header.header_crc = header_crc;
+
+ /* 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_t *get_partition_entry_by_type(const uuid_t *type_uuid)
+{
+ int i;
+
+ for (i = 0; i < list.entry_count; i++) {
+ if (guidcmp(type_uuid, &list.list[i].type_guid) == 0) {
+ return &list.list[i];
+ }
+ }
+
+ return NULL;
+}
+
+const partition_entry_t *get_partition_entry_by_uuid(const uuid_t *part_uuid)
+{
+ int i;
+
+ for (i = 0; i < list.entry_count; i++) {
+ if (guidcmp(part_uuid, &list.list[i].part_guid) == 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);
+}
diff --git a/drivers/rambus/trng_ip_76.c b/drivers/rambus/trng_ip_76.c
new file mode 100644
index 0000000..8de12e9
--- /dev/null
+++ b/drivers/rambus/trng_ip_76.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2020, Marvell Technology Group Ltd. All rights reserved.
+ *
+ * Based on Linux kernel omap-rng.c - RNG driver for TI OMAP CPU family
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * Mostly based on original driver:
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/rambus/trng_ip_76.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <lib/utils.h>
+
+#define RNG_REG_STATUS_RDY (1 << 0)
+
+#define RNG_REG_INTACK_RDY_MASK (1 << 0)
+
+#define RNG_CONTROL_ENABLE_TRNG_MASK (1 << 10)
+
+#define RNG_CONFIG_NOISE_BLOCKS(val) ((0xff & (val)) << 0)
+#define RNG_CONFIG_NOISE_BLK_VAL 0x5
+
+#define RNG_CONFIG_SAMPLE_CYCLES(val) ((0xff & (val)) << 16)
+#define RNG_CONFIG_SAMPLE_CYCLES_VAL 0x22
+
+#define RNG_REG_FRO_ENABLE_MASK 0xffffff
+#define RNG_REG_FRO_DETUNE_MASK 0x0
+
+#define EIP76_RNG_OUTPUT_SIZE 0x10
+#define EIP76_RNG_WAIT_ROUNDS 10
+
+#define RNG_HW_IS_EIP76(ver) ((ver) & (0xff == 0x4C))
+#define RNG_HW_VER_MAJOR(ver) (((ver) & (0xf << 24)) >> 24)
+#define RNG_HW_VER_MINOR(ver) (((ver) & (0xf << 20)) >> 20)
+#define RNG_HW_VER_PATCH(ver) (((ver) & (0xf << 16)) >> 16)
+
+
+enum {
+ RNG_OUTPUT_0_REG = 0,
+ RNG_OUTPUT_1_REG,
+ RNG_OUTPUT_2_REG,
+ RNG_OUTPUT_3_REG,
+ RNG_STATUS_REG,
+ RNG_INTMASK_REG,
+ RNG_INTACK_REG,
+ RNG_CONTROL_REG,
+ RNG_CONFIG_REG,
+ RNG_ALARMCNT_REG,
+ RNG_FROENABLE_REG,
+ RNG_FRODETUNE_REG,
+ RNG_ALARMMASK_REG,
+ RNG_ALARMSTOP_REG,
+ RNG_REV_REG
+};
+
+static uint16_t reg_map_eip76[] = {
+ [RNG_OUTPUT_0_REG] = 0x0,
+ [RNG_OUTPUT_1_REG] = 0x4,
+ [RNG_OUTPUT_2_REG] = 0x8,
+ [RNG_OUTPUT_3_REG] = 0xc,
+ [RNG_STATUS_REG] = 0x10,
+ [RNG_INTACK_REG] = 0x10,
+ [RNG_CONTROL_REG] = 0x14,
+ [RNG_CONFIG_REG] = 0x18,
+ [RNG_ALARMCNT_REG] = 0x1c,
+ [RNG_FROENABLE_REG] = 0x20,
+ [RNG_FRODETUNE_REG] = 0x24,
+ [RNG_ALARMMASK_REG] = 0x28,
+ [RNG_ALARMSTOP_REG] = 0x2c,
+ [RNG_REV_REG] = 0x7c,
+};
+
+struct eip76_rng_dev {
+ uintptr_t base;
+ uint16_t *regs;
+};
+
+/* Locals */
+static struct eip76_rng_dev eip76_dev;
+static spinlock_t rng_lock;
+
+static inline uint32_t eip76_rng_read(struct eip76_rng_dev *dev, uint16_t reg)
+{
+ return mmio_read_32(dev->base + dev->regs[reg]);
+}
+
+static inline void eip76_rng_write(struct eip76_rng_dev *dev,
+ uint16_t reg, uint32_t val)
+{
+ mmio_write_32(dev->base + dev->regs[reg], val);
+}
+
+static void eip76_rng_init(struct eip76_rng_dev *dev)
+{
+ uint32_t val;
+
+ /* Return if RNG is already running. */
+ if (eip76_rng_read(dev, RNG_CONTROL_REG) &
+ RNG_CONTROL_ENABLE_TRNG_MASK) {
+ return;
+ }
+
+ /* This field sets the number of 512-bit blocks of raw Noise Source
+ * output data that must be processed by either the Conditioning
+ * Function or the SP 800-90 DRBG ‘BC_DF’ functionality to yield
+ * a ‘full entropy’ output value. As according to [SP 800-90B draft]
+ * the amount of entropy input to this functionality must be twice
+ * the amount that is output and the 8-bit samples output by the Noise
+ * Source are supposed to have one bit of entropy each, the settings
+ * for this field are as follows:
+ * - SHA-1 Conditioning Function:
+ * generates 160 bits output, requiring 2560 sample bits,
+ * equivalent to 5 blocks of raw Noise Source input.
+ * - SHA-256 Conditioning Function:
+ * generates 256 bits output, requiring 4096 sample bits, equivalent
+ * to 8 blocks of raw Noise Source input. Note that two blocks of 256
+ * bits are needed to start or re-seed the SP 800-90 DRBG
+ * (in the EIP-76d-*-SHA2 configurations)
+ * - SP 800-90 DRBG ‘BC_DF’ functionality:
+ * generates 384 bits output, requiring 6144 sample bits, equivalent
+ * to 12 blocks of raw Noise Source input.
+ * This field can only be modified when ‘enable_trng’ in TRNG_CONTROL
+ * is ‘0’ or when either of the ‘test_known_noise’ or ‘test_cond_func’
+ * bits in TRNG_TEST is ‘1’. Value 0 in this field selects 256 blocks
+ * of 512 bits to be processed.
+ */
+ val = RNG_CONFIG_NOISE_BLOCKS(RNG_CONFIG_NOISE_BLK_VAL);
+
+ /* This field sets the number of FRO samples that are XOR-ed together
+ * into one bit to be shifted into the main shift register.
+ * This value must be such that there is at least one bit of entropy
+ * (in total) in each 8 bits that are shifted.
+ * This field can only be modified when ‘enable_trng’ in TRNG_CONTROL
+ * is ‘0’ or when either of the ‘test_known_noise’ or ‘test_cond_func’
+ * bits in TRNG_TEST is ‘1’. Value 0 in this field selects 65536 FRO
+ * samples to be XOR-ed together
+ */
+ val |= RNG_CONFIG_SAMPLE_CYCLES(RNG_CONFIG_SAMPLE_CYCLES_VAL);
+ eip76_rng_write(dev, RNG_CONFIG_REG, val);
+
+ /* Enable all available FROs */
+ eip76_rng_write(dev, RNG_FRODETUNE_REG, RNG_REG_FRO_DETUNE_MASK);
+ eip76_rng_write(dev, RNG_FROENABLE_REG, RNG_REG_FRO_ENABLE_MASK);
+
+ /* Enable TRNG */
+ eip76_rng_write(dev, RNG_CONTROL_REG, RNG_CONTROL_ENABLE_TRNG_MASK);
+}
+
+int32_t eip76_rng_read_rand_buf(void *data, bool wait)
+{
+ uint32_t i, present;
+
+ if (!eip76_dev.base) /* not initialized */
+ return -1;
+
+ for (i = 0; i < EIP76_RNG_WAIT_ROUNDS; i++) {
+ present = eip76_rng_read(&eip76_dev, RNG_STATUS_REG) &
+ RNG_REG_STATUS_RDY;
+ if (present || !wait) {
+ break;
+ }
+
+ udelay(10);
+ }
+
+ if (present != 0U) {
+ return 0;
+ }
+
+ memcpy(data,
+ (void *)(eip76_dev.base + eip76_dev.regs[RNG_OUTPUT_0_REG]),
+ EIP76_RNG_OUTPUT_SIZE);
+
+ eip76_rng_write(&eip76_dev, RNG_INTACK_REG, RNG_REG_INTACK_RDY_MASK);
+
+ return EIP76_RNG_OUTPUT_SIZE;
+}
+
+int32_t eip76_rng_probe(uintptr_t base_addr)
+{
+ uint32_t ver;
+
+ eip76_dev.base = base_addr;
+ eip76_dev.regs = reg_map_eip76;
+
+ eip76_rng_init(&eip76_dev);
+
+ ver = eip76_rng_read(&eip76_dev, RNG_REV_REG);
+
+ INFO("%s Random Number Generator HW ver. %01x.%01x.%01x\n",
+ RNG_HW_IS_EIP76(ver) ? "TRNG-IP-76" : "Unknown",
+ RNG_HW_VER_MAJOR(ver), RNG_HW_VER_MINOR(ver),
+ RNG_HW_VER_PATCH(ver));
+
+ return 0;
+}
+
+int32_t eip76_rng_get_random(uint8_t *data, uint32_t len)
+{
+ static uint8_t rand[EIP76_RNG_OUTPUT_SIZE];
+ static uint8_t pos;
+ uint32_t i;
+ int32_t ret = 0;
+
+ if (!data)
+ return -1;
+
+ spin_lock(&rng_lock);
+
+ for (i = 0; i < len; i++) {
+ if (pos >= EIP76_RNG_OUTPUT_SIZE) {
+ pos = 0;
+ }
+
+ if (pos != 0U) {
+ ret = eip76_rng_read_rand_buf(rand, true);
+ }
+
+ /* Only advance FIFO index if it is non zero or
+ * the update from TRNG HW was successful
+ */
+ if (pos || ret > 0) {
+ data[i] = rand[pos++];
+ ret = 0;
+ } else {
+ ret = -1;
+ break;
+ }
+ }
+
+ spin_unlock(&rng_lock);
+
+ return ret;
+}
diff --git a/drivers/renesas/common/auth/auth_mod.c b/drivers/renesas/common/auth/auth_mod.c
new file mode 100644
index 0000000..4aa86e2
--- /dev/null
+++ b/drivers/renesas/common/auth/auth_mod.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights
+ * reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+#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 /* RCAR_BL2_DCACHE */
+
+#endif /* IMAGE_BL2 */
+ 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
+}
diff --git a/drivers/renesas/common/avs/avs_driver.c b/drivers/renesas/common/avs/avs_driver.c
new file mode 100644
index 0000000..2c939cd
--- /dev/null
+++ b/drivers/renesas/common/avs/avs_driver.c
@@ -0,0 +1,630 @@
+/*
+ * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include "avs_driver.h"
+#include "cpg_registers.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 */
+/* ROHM BD9571 slave address + (W) */
+#define PMIC_W_SLAVE_ADDRESS (0x60U)
+/* ROHM BD9571 slave address + (R) */
+#define PMIC_R_SLAVE_ADDRESS (0x61U)
+/* ROHM BD9571 DVFS SetVID register */
+#define PMIC_DVFS_SETVID (0x54U)
+#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, ROHM 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("%s%s=%u\n", "AVS number of ",
+ "eFuse is out of range. number",
+ 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("%s AVS status=%d Retry=%u\n",
+ "Loss of arbitration is detected.", 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("%s AVS status=%d Retry=%u\n",
+ "Non-acknowledge is detected.", 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) */
diff --git a/drivers/renesas/common/avs/avs_driver.h b/drivers/renesas/common/avs/avs_driver.h
new file mode 100644
index 0000000..aa773b6
--- /dev/null
+++ b/drivers/renesas/common/avs/avs_driver.h
@@ -0,0 +1,20 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/common/common.c b/drivers/renesas/common/common.c
new file mode 100644
index 0000000..a0aa480
--- /dev/null
+++ b/drivers/renesas/common/common.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include "cpg_registers.h"
+#include "rcar_private.h"
+
+#if IMAGE_BL31
+void __attribute__ ((section(".system_ram"))) cpg_write(uintptr_t regadr, uint32_t regval)
+#else
+void cpg_write(uintptr_t regadr, uint32_t regval)
+#endif
+{
+ uint32_t value = regval;
+
+ mmio_write_32(CPG_CPGWPR, ~value);
+ mmio_write_32(regadr, value);
+}
+
+#if IMAGE_BL31
+void __attribute__ ((section(".system_ram"))) mstpcr_write(uint32_t mstpcr, uint32_t mstpsr,
+ uint32_t target_bit)
+#else
+void mstpcr_write(uint32_t mstpcr, uint32_t mstpsr, uint32_t target_bit)
+#endif
+{
+ uint32_t reg;
+
+ reg = mmio_read_32(mstpcr);
+ reg &= ~target_bit;
+ cpg_write(mstpcr, reg);
+ while ((mmio_read_32(mstpsr) & target_bit) != 0U) {
+ }
+}
diff --git a/drivers/renesas/common/console/rcar_console.S b/drivers/renesas/common/console/rcar_console.S
new file mode 100644
index 0000000..b683d7b
--- /dev/null
+++ b/drivers/renesas/common/console/rcar_console.S
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2018-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <console_macros.S>
+#include <drivers/renesas/rcar/console/console.h>
+
+ .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_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_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_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, #1
+ ret
+endfunc console_rcar_init
+
+ /* --------------------------------------------------------
+ * int console_rcar_putc(int c, console_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_rcar_putc
+ b rcar_set_log_data
+endfunc console_rcar_putc
+
+ /* ---------------------------------------------
+ * void console_rcar_flush(void)
+ * Function to force a write of all buffered
+ * data that hasn't been output. It returns void
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func console_rcar_flush
+ ret
+endfunc console_rcar_flush
diff --git a/drivers/renesas/common/console/rcar_printf.c b/drivers/renesas/common/console/rcar_printf.c
new file mode 100644
index 0000000..ad074fe
--- /dev/null
+++ b/drivers/renesas/common/console/rcar_printf.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdarg.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/bakery_lock.h>
+
+#include "rcar_def.h"
+#include "rcar_private.h"
+#include "rcar_printf.h"
+
+#define INDEX_TIMER_COUNT (4U)
+
+#define RCAR_LOG_HEAD (('T' << 0) | ('L' << 8) | ('O' << 16) | ('G' << 24))
+
+/*
+ * The log is initialized and used before BL31 xlat tables are initialized,
+ * therefore the log memory is a device memory at that point. Make sure the
+ * memory is correclty aligned and accessed only with up-to 32bit, aligned,
+ * writes.
+ */
+CASSERT((RCAR_BL31_LOG_BASE & 0x7) == 0, assert_bl31_log_base_unaligned);
+CASSERT((RCAR_BL31_LOG_MAX & 0x7) == 0, assert_bl31_log_max_unaligned);
+
+extern RCAR_INSTANTIATE_LOCK typedef struct log_head {
+ uint32_t head;
+ uint32_t index;
+ uint32_t size;
+ uint32_t res;
+} 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)
+{
+ logmap_t *t_log = (logmap_t *)RCAR_BL31_LOG_BASE;
+ uint32_t *log_data = (uint32_t *)t_log->log_data;
+ int16_t init_flag = 0;
+ int i;
+
+ if (t_log->header.head != RCAR_LOG_HEAD) {
+ /*
+ * 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) {
+ for (i = 0; i < RCAR_BL31_LOG_MAX; i += 4)
+ *log_data++ = 0;
+
+ t_log->header.head = RCAR_LOG_HEAD;
+ t_log->header.index = 0U;
+ t_log->header.size = 0U;
+ }
+ rcar_lock_init();
+
+ return 1;
+}
diff --git a/drivers/renesas/common/console/rcar_printf.h b/drivers/renesas/common/console/rcar_printf.h
new file mode 100644
index 0000000..5da70e6
--- /dev/null
+++ b/drivers/renesas/common/console/rcar_printf.h
@@ -0,0 +1,15 @@
+/*
+ * 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 <string.h>
+
+int32_t rcar_set_log_data(int32_t c);
+int32_t rcar_log_init(void);
+
+#endif /* RCAR_PRINTF_H */
diff --git a/drivers/renesas/common/ddr/boot_init_dram.h b/drivers/renesas/common/ddr/boot_init_dram.h
new file mode 100644
index 0000000..ac237b2
--- /dev/null
+++ b/drivers/renesas/common/ddr/boot_init_dram.h
@@ -0,0 +1,18 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/common/ddr/ddr.mk b/drivers/renesas/common/ddr/ddr.mk
new file mode 100644
index 0000000..9483686
--- /dev/null
+++ b/drivers/renesas/common/ddr/ddr.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq ($(RCAR_LSI),$(filter $(RCAR_LSI),${RCAR_E3} ${RZ_G2E}))
+ include drivers/renesas/common/ddr/ddr_a/ddr_a.mk
+ BL2_SOURCES += drivers/renesas/common/ddr/dram_sub_func.c
+else ifeq (${RCAR_LSI},${RCAR_D3})
+ include drivers/renesas/common/ddr/ddr_a/ddr_a.mk
+else ifeq (${RCAR_LSI},${RCAR_V3M})
+ include drivers/renesas/common/ddr/ddr_a/ddr_a.mk
+else
+ include drivers/renesas/common/ddr/ddr_b/ddr_b.mk
+ BL2_SOURCES += drivers/renesas/common/ddr/dram_sub_func.c
+endif
diff --git a/drivers/renesas/common/ddr/ddr_a/boot_init_dram_regdef.h b/drivers/renesas/common/ddr/ddr_a/boot_init_dram_regdef.h
new file mode 100644
index 0000000..0f89b43
--- /dev/null
+++ b/drivers/renesas/common/ddr/ddr_a/boot_init_dram_regdef.h
@@ -0,0 +1,8 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "../ddr_regs.h"
diff --git a/drivers/renesas/common/ddr/ddr_a/ddr_a.mk b/drivers/renesas/common/ddr/ddr_a/ddr_a.mk
new file mode 100644
index 0000000..cd6433d
--- /dev/null
+++ b/drivers/renesas/common/ddr/ddr_a/ddr_a.mk
@@ -0,0 +1,13 @@
+#
+# Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq ($(RCAR_LSI),$(filter $(RCAR_LSI),${RCAR_E3} ${RZ_G2E}))
+BL2_SOURCES += drivers/renesas/common/ddr/ddr_a/ddr_init_e3.c
+else ifeq (${RCAR_LSI},${RCAR_D3})
+BL2_SOURCES += drivers/renesas/common/ddr/ddr_a/ddr_init_d3.c
+else
+BL2_SOURCES += drivers/renesas/common/ddr/ddr_a/ddr_init_v3m.c
+endif
diff --git a/drivers/renesas/common/ddr/ddr_a/ddr_init_d3.c b/drivers/renesas/common/ddr/ddr_a/ddr_init_d3.c
new file mode 100644
index 0000000..f0113f1
--- /dev/null
+++ b/drivers/renesas/common/ddr/ddr_a/ddr_init_d3.c
@@ -0,0 +1,735 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <lib/mmio.h>
+#include <common/debug.h>
+#include "rcar_def.h"
+#include "../ddr_regs.h"
+
+#define RCAR_DDR_VERSION "rev.0.02"
+
+/* Average periodic refresh interval[ns]. Support 3900,7800 */
+#define REFRESH_RATE 3900
+
+
+#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, 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);
+ mmio_write_32(DBSC_SCFCTST0, 0x0C050B03);
+ mmio_write_32(DBSC_SCFCTST1, 0x0305030C);
+
+ 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,
+ (uint32_t) (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);
+ 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);
+ if (REFRESH_RATE > 3900) {
+ mmio_write_32(DBSC_DBPDRGD_0, 0x00000020);
+ } else {
+ 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_DBPDRGA_0, 0x000000AF);
+ mmio_write_32(DBSC_DBPDRGD_0, ((r2 + 0x1) & 0xFF) | (r2 & 0xFFFFFF00));
+ mmio_write_32(DBSC_DBPDRGA_0, 0x000000CF);
+ 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,
+ (uint32_t) (64000000 / REFRESH_RATE) + 0x01000000);
+ mmio_write_32(DBSC_DBRFCNF1,
+ (uint32_t) (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);
+ 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(CPG_CPGWPR, 0x5A5AFFFF);
+ mmio_write_32(CPG_CPGWPCR, 0xA5A50000);
+
+ mmio_write_32(CPG_SRCR4, 0x20000000);
+
+ mmio_write_32(0xE61500DC, 0xe2200000);
+ 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);
+ 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, 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);
+ mmio_write_32(DBSC_DBTR18, 0x00000200);
+ mmio_write_32(DBSC_DBTR19, 0x01000040);
+ mmio_write_32(DBSC_DBTR20, 0x020000D6);
+ 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, 0x0D050B03);
+ mmio_write_32(DBSC_SCFCTST1, 0x0306030C);
+
+ 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,
+ (uint32_t) (REFRESH_RATE * 792 / 125) - 400 + 0x08B00000);
+ 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, 0x2A88B400);
+ 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);
+ if (REFRESH_RATE > 3900) {
+ mmio_write_32(DBSC_DBPDRGD_0, 0x00000018);
+ } else {
+ 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_DBPDRGA_0, 0x000000AF);
+ 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_DBPDRGA_0, 0x000000CF);
+ 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,
+ (uint32_t) (64000000 / REFRESH_RATE) + 0x01000000);
+ mmio_write_32(DBSC_DBRFCNF1,
+ (uint32_t) (REFRESH_RATE * 99 / 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);
+ 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(%s)\n", ddr_mbps, RCAR_DDR_VERSION);
+
+ return 0;
+}
diff --git a/drivers/renesas/common/ddr/ddr_a/ddr_init_e3.c b/drivers/renesas/common/ddr/ddr_a/ddr_init_e3.c
new file mode 100644
index 0000000..fc278ef
--- /dev/null
+++ b/drivers/renesas/common/ddr/ddr_a/ddr_init_e3.c
@@ -0,0 +1,1712 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#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;
+
+}
diff --git a/drivers/renesas/common/ddr/ddr_a/ddr_init_v3m.c b/drivers/renesas/common/ddr/ddr_a/ddr_init_v3m.c
new file mode 100644
index 0000000..5410771
--- /dev/null
+++ b/drivers/renesas/common/ddr/ddr_a/ddr_init_v3m.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <stdint.h>
+#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();
+}
diff --git a/drivers/renesas/common/ddr/ddr_b/boot_init_dram.c b/drivers/renesas/common/ddr/ddr_b/boot_init_dram.c
new file mode 100644
index 0000000..8d002de
--- /dev/null
+++ b/drivers/renesas/common/ddr/ddr_b/boot_init_dram.c
@@ -0,0 +1,4484 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#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 RZ_G2M 100U
+#define RZ_G2H 101U
+#define RZ_G2N 102U
+
+#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 || RCAR_LSI == RZ_G2M)
+static const uint32_t prr_product = PRR_PRODUCT_M3;
+#elif(RCAR_LSI == RCAR_M3N || RCAR_LSI == RZ_G2N)
+static const uint32_t prr_product = PRR_PRODUCT_M3N;
+#elif(RCAR_LSI == RCAR_H3N || RCAR_LSI == RZ_G2H)
+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();
+}
+
+static void dbwait_loop(uint32_t wait_loop)
+{
+ uint32_t i;
+
+ for (i = 0; i < wait_loop; i++)
+ wait_dbcmd();
+}
+
+/* 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 odtlon;
+ 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, 0, JS1_MR1(0), JS1_MR2(0) | 0x40 },
+ /* 1066.666Mbps */
+ { 1600, 10, 12, 8, 10, 8, 0, JS1_MR1(1), JS1_MR2(1) | 0x40 },
+ /* 1600.000Mbps */
+ { 2400, 14, 16, 12, 16, 8, 6, JS1_MR1(2), JS1_MR2(2) | 0x40 },
+ /* 2133.333Mbps */
+ { 3200, 20, 22, 10, 20, 8, 4, JS1_MR1(3), JS1_MR2(3) },
+ /* 2666.666Mbps */
+ { 4000, 24, 28, 12, 24, 10, 4, JS1_MR1(4), JS1_MR2(4) },
+ /* 3200.000Mbps */
+ { 4800, 28, 32, 14, 30, 12, 6, JS1_MR1(5), JS1_MR2(5) },
+ /* 3733.333Mbps */
+ { 5600, 32, 36, 16, 34, 14, 6, JS1_MR1(6), JS1_MR2(6) },
+ /* 4266.666Mbps */
+ { 6400, 36, 40, 18, 40, 16, 8, 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_tODTon_min 22
+#define JS2_TBLCNT 23
+
+#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},
+/*tODTon_min*/ {1500, 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},
+/*tODTon_min*/ {1500, 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 - 2);
+ }
+ 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();
+ dbwait_loop(5);
+ }
+
+ /* 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 + BL / 2 + Rounddown(tRPST) + PHY_ODTLoff -
+ * odtlon + tDQSCK - tODTon,min +
+ * PCB delay (out+in) + tPHY_ODToff
+ */
+ mmio_write_32(DBSC_DBTR(11),
+ RL + (16 / 2) + 1 + 2 - js1[js1_ind].odtlon +
+ js2[js2_tdqsck] - js2[js2_tODTon_min] +
+ _f_scale(ddr_mbps, ddr_mbpsdiv, 1300, 0));
+
+ /* 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)) {
+#if RCAR_DRAM_SPLIT == 2
+ if (board_cnf->phyvalid == 0x05) {
+ mmio_write_32(DBSC_DBTR(24),
+ (rdlat_max << 24) + (rdlat_min << 16) +
+ mmio_read_32(DBSC_DBTR(24)));
+ } else {
+ mmio_write_32(DBSC_DBTR(24),
+ ((rdlat_max * 2 - rdlat_min + 4) << 24) +
+ ((rdlat_min + 2) << 16) +
+ mmio_read_32(DBSC_DBTR(24)));
+ }
+#else /*RCAR_DRAM_SPLIT == 2 */
+ mmio_write_32(DBSC_DBTR(24),
+ ((rdlat_max * 2 - rdlat_min + 4) << 24) +
+ ((rdlat_min + 2) << 16) +
+ mmio_read_32(DBSC_DBTR(24)));
+#endif /*RCAR_DRAM_SPLIT == 2 */
+ } 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);
+
+#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 */
+ 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_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 enable */
+ mmio_write_32(DBSC_DBCALCNF, 0x01000010);
+
+ /* periodic phy ctrl update enable */
+ 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 */
+ }
+
+#ifdef DDR_BACKUPMODE
+ /* SRX */
+ if (ddr_backup == DRAM_BOOT_STATUS_WARM) {
+#ifdef DDR_BACKUPMODE_HALF /* for Half channel(ch0, 1 only) */
+ NOTICE("BL2: [DEBUG_MESS] DDR_BACKUPMODE_HALF\n");
+ send_dbcmd(0x0A040001);
+ if (Prr_Product == PRR_PRODUCT_H3)
+ send_dbcmd(0x0A140001);
+#else /* DDR_BACKUPMODE_HALF */ /* for All channels */
+ send_dbcmd(0x0A840001);
+#endif /* DDR_BACKUPMODE_HALF */
+ }
+#endif /* DDR_BACKUPMODE */
+
+ /* set Auto Refresh */
+ mmio_write_32(DBSC_DBRFEN, 0x00000001);
+
+#if RCAR_REWT_TRAINING != 0
+ /* Periodic WriteDQ Traning */
+ 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 */
+ ddr_setval_ach(_reg_PI_WDQLVL_INTERVAL, 0x0100);
+ }
+#endif /* RCAR_REWT_TRAINING */
+
+ /* 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");
+
+ /* Dummy PDE */
+ send_dbcmd(0x08840000);
+
+ /* 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 datal, ch, ddr_csn, mr14_bkup[4][4];
+
+ datal = RL + js2[js2_tdqsck] + (16 / 2) + 1 - WL + 2 + 2 + 19;
+ if ((mmio_read_32(DBSC_DBTR(11)) & 0xFF) > datal)
+ datal = mmio_read_32(DBSC_DBTR(11)) & 0xFF;
+ ddr_setval_ach(_reg_PI_TDFI_WDQLVL_RW, datal);
+
+ 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);
+ if (data_l & 0x00000040U) {
+ data_l = data_l & 0xFFFFFFBEU;
+ } else {
+ data_l = data_l | BIT(1);
+ }
+
+ 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 */
diff --git a/drivers/renesas/common/ddr/ddr_b/boot_init_dram_config.c b/drivers/renesas/common/ddr/ddr_b/boot_init_dram_config.c
new file mode 100644
index 0000000..bbb0200
--- /dev/null
+++ b/drivers/renesas/common/ddr/ddr_b/boot_init_dram_config.c
@@ -0,0 +1,2108 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RZG_SOC
+#define RZG_SOC 0
+#endif
+
+#if (RZG_SOC == 1)
+#define BOARDNUM 4
+#else
+
+#include <board.h>
+
+#define BOARDNUM 22
+#endif /* RZG_SOC == 1 */
+#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}
+
+#if (RZG_SOC == 1)
+static const struct _boardcnf boardcnfs[BOARDNUM] = {
+ {
+/* boardcnf[0] HopeRun HiHope RZ/G2M 16Gbit/1rank/2ch board with G2M SoC */
+ .phyvalid = 0x03U,
+ .dbi_en = 0x01U,
+ .cacs_dly = 0x02c0U,
+ .cacs_dly_adj = 0x0U,
+ .dqdm_dly_w = 0x0300U,
+ .dqdm_dly_r = 0x00a0U,
+ .ch = {
+ {
+ { 0x04U, 0xffU },
+ 0x00345201UL,
+ 0x3201U,
+ { 0x01672543U, 0x45361207U, 0x45632107U, 0x60715234U },
+ { 0x08U, 0x08U, 0x08U, 0x08U },
+ 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 }
+ },
+ {
+ { 0x04U, 0xffU },
+ 0x00302154UL,
+ 0x2310U,
+ { 0x01672543U, 0x45361207U, 0x45632107U, 0x60715234U },
+ { 0x08U, 0x08U, 0x08U, 0x08U },
+ 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] HopeRun HiHope RZ/G2M 8Gbit/2rank/2ch board with G2M SoC */
+ {
+ 0x03U,
+ 0x01U,
+ 0x02c0U,
+ 0x0U,
+ 0x0300U,
+ 0x00a0U,
+ {
+ {
+ { 0x02U, 0x02U },
+ 0x00345201UL,
+ 0x3201U,
+ { 0x01672543U, 0x45361207U, 0x45632107U, 0x60715234U },
+ { 0x08U, 0x08U, 0x08U, 0x08U },
+ 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 }
+ },
+ {
+ { 0x02U, 0x02U },
+ 0x00302154UL,
+ 0x2310,
+ { 0x01672543U, 0x45361207U, 0x45632107U, 0x60715234U },
+ { 0x08U, 0x08U, 0x08U, 0x08U },
+ 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] HopeRun HiHope RZ/G2H board 16Gbit/1rank/2ch */
+ {
+ 0x05U,
+ 0x01U,
+ 0x0300U,
+ 0,
+ 0x0300U,
+ 0x00a0U,
+ {
+ {
+ { 0x04U, 0xffU },
+ 0x00345201UL,
+ 0x3201U,
+ { 0x01672543U, 0x45367012U, 0x45632107U, 0x60715234U },
+ { 0x08U, 0x08U, 0x08U, 0x08U },
+ 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 }
+ },
+ {
+ { 0x04U, 0xffU },
+ 0x00302154UL,
+ 0x2310U,
+ { 0x01672543U, 0x45361207U, 0x45632107U, 0x60715234U },
+ { 0x08U, 0x08U, 0x08U, 0x08U },
+ 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 }
+ },
+ {
+ { 0x04U, 0xffU },
+ 0x00302154UL,
+ 0x2310U,
+ { 0x01672543U, 0x45361207U, 0x45632107U, 0x60715234U },
+ { 0x08U, 0x08U, 0x08U, 0x08U },
+ 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 }
+ },
+ {
+ { 0xffU, 0xffU },
+ 0UL,
+ 0U,
+ { 0U, 0U, 0U, 0U },
+ { 0U, 0U, 0U, 0U },
+ 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] HopeRun HiHope RZ/G2N board 16Gbit/2rank/1ch */
+ {
+ 0x01U,
+ 0x01U,
+ 0x0300U,
+ 0,
+ 0x0300U,
+ 0x00a0U,
+ {
+ {
+ { 0x04U, 0x04U },
+ 0x00345201UL,
+ 0x3201U,
+ { 0x01672543U, 0x45361207U, 0x45632107U, 0x60715234U },
+ { 0x08U, 0x08U, 0x08U, 0x08U },
+ 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
+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}
+ }
+ }
+ }
+};
+#endif /* RZG_SOC == 1 */
+
+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;
+
+ if (prr_product == PRR_PRODUCT_V3H) {
+ md = (mmio_read_32(RST_MODEMR) >> 19) & 0x1;
+ md = (md | (md << 1)) & 0x3; /* 0 or 3 */
+ } else {
+ 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) && (RZG_SOC == 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) && (RZG_SOC == 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
+
+#if (RZG_SOC == 1)
+#define LPDDR4_2RANK (0x01U << 25U)
+
+static uint32_t rzg2_board_judge(void)
+{
+ uint32_t brd;
+
+ switch (prr_product) {
+ case PRR_PRODUCT_M3:
+ brd = 1U;
+ if ((mmio_read_32(PRR) & PRR_CUT_MASK) != RCAR_M3_CUT_VER11) {
+ if ((mmio_read_32(GPIO_INDT5) & LPDDR4_2RANK) == 0U) {
+ brd = 0U;
+ }
+ }
+ break;
+ case PRR_PRODUCT_H3:
+ brd = 2U;
+ break;
+ case PRR_PRODUCT_M3N:
+ brd = 3U;
+ break;
+ default:
+ brd = 99U;
+ }
+
+ return brd;
+}
+#endif /* RZG_SOC == 1 */
+
+#if (RZG_SOC == 0) && (RCAR_DRAM_LPDDR4_MEMCONF != 0)
+static uint32_t ddr_rank_judge(void)
+{
+ uint32_t brd;
+
+#if (RCAR_DRAM_MEMRANK == 0)
+ int32_t ret;
+ uint32_t type = 0U;
+ uint32_t rev = 0U;
+
+ brd = 99U;
+ ret = rcar_get_board_type(&type, &rev);
+ if ((ret == 0) && (rev != 0xFFU)) {
+ if (type == (uint32_t)BOARD_SALVATOR_XS) {
+ if (rev == 0x11U) {
+ brd = 14U;
+ } else {
+ brd = 8U;
+ }
+ } else if (type == (uint32_t)BOARD_STARTER_KIT_PRE) {
+ if (rev == 0x21U) {
+ brd = 14U;
+ } else {
+ brd = 8U;
+ }
+ }
+ }
+#elif (RCAR_DRAM_MEMRANK == 1)
+ brd = 14U;
+#elif (RCAR_DRAM_MEMRANK == 2)
+ brd = 8U;
+#else
+#error Invalid value was set to RCAR_DRAM_MEMRANK
+#endif /* (RCAR_DRAM_MEMRANK == 0) */
+ return brd;
+}
+#endif /* (RCAR_DRAM_LPDDR4_MEMCONF != 0) */
+
+static uint32_t _board_judge(void)
+{
+ uint32_t brd;
+
+#if (RZG_SOC == 1)
+ brd = rzg2_board_judge();
+#else
+#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 = ddr_rank_judge();
+#endif
+ }
+ } else if (prr_product == PRR_PRODUCT_M3) {
+ if (prr_cut >= PRR_PRODUCT_30) {
+ /* RENESAS Starter Kit (M3-W Ver.3.0/SIP) */
+ brd = 18;
+ } else {
+ /* 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 = ddr_rank_judge();
+#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
+#endif /* RZG_SOC == 1 */
+
+ return brd;
+}
+#endif
diff --git a/drivers/renesas/common/ddr/ddr_b/boot_init_dram_regdef.h b/drivers/renesas/common/ddr/ddr_b/boot_init_dram_regdef.h
new file mode 100644
index 0000000..3cb1975
--- /dev/null
+++ b/drivers/renesas/common/ddr/ddr_b/boot_init_dram_regdef.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define RCAR_DDR_VERSION "rev.0.41"
+#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
diff --git a/drivers/renesas/common/ddr/ddr_b/ddr_b.mk b/drivers/renesas/common/ddr/ddr_b/ddr_b.mk
new file mode 100644
index 0000000..0334780
--- /dev/null
+++ b/drivers/renesas/common/ddr/ddr_b/ddr_b.mk
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BL2_SOURCES += drivers/renesas/common/ddr/ddr_b/boot_init_dram.c
diff --git a/drivers/renesas/common/ddr/ddr_b/ddr_regdef.h b/drivers/renesas/common/ddr/ddr_b/ddr_regdef.h
new file mode 100644
index 0000000..adf8dab
--- /dev/null
+++ b/drivers/renesas/common/ddr/ddr_b/ddr_regdef.h
@@ -0,0 +1,5887 @@
+/*
+ * 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,
+ }
+};
diff --git a/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_h3.h b/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_h3.h
new file mode 100644
index 0000000..357f8ba
--- /dev/null
+++ b/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_h3.h
@@ -0,0 +1,441 @@
+/*
+ * 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
+};
diff --git a/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_h3ver2.h b/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_h3ver2.h
new file mode 100644
index 0000000..e5258af
--- /dev/null
+++ b/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_h3ver2.h
@@ -0,0 +1,538 @@
+/*
+ * 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
+};
diff --git a/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_m3.h b/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_m3.h
new file mode 100644
index 0000000..b491f0e
--- /dev/null
+++ b/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_m3.h
@@ -0,0 +1,468 @@
+/*
+ * 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
+};
diff --git a/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_m3n.h b/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_m3n.h
new file mode 100644
index 0000000..fb3032d
--- /dev/null
+++ b/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_m3n.h
@@ -0,0 +1,587 @@
+/*
+ * Copyright (c) 2015-2020, 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*/ 0x0141a0a0,
+ /*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
+};
diff --git a/drivers/renesas/common/ddr/dram_sub_func.c b/drivers/renesas/common/ddr/dram_sub_func.c
new file mode 100644
index 0000000..ab8eabb
--- /dev/null
+++ b/drivers/renesas/common/ddr/dram_sub_func.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#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;
+}
diff --git a/drivers/renesas/common/ddr/dram_sub_func.h b/drivers/renesas/common/ddr/dram_sub_func.h
new file mode 100644
index 0000000..69c4d86
--- /dev/null
+++ b/drivers/renesas/common/ddr/dram_sub_func.h
@@ -0,0 +1,17 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/common/ddr_regs.h b/drivers/renesas/common/ddr_regs.h
new file mode 100644
index 0000000..ba26c69
--- /dev/null
+++ b/drivers/renesas/common/ddr_regs.h
@@ -0,0 +1,257 @@
+/*
+ * 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_*/
diff --git a/drivers/renesas/common/delay/micro_delay.c b/drivers/renesas/common/delay/micro_delay.c
new file mode 100644
index 0000000..a5e2a69
--- /dev/null
+++ b/drivers/renesas/common/delay/micro_delay.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018-2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+
+#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;
+ }
+}
diff --git a/drivers/renesas/common/delay/micro_delay.h b/drivers/renesas/common/delay/micro_delay.h
new file mode 100644
index 0000000..37b71f8
--- /dev/null
+++ b/drivers/renesas/common/delay/micro_delay.h
@@ -0,0 +1,15 @@
+/*
+ * 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 <stdint.h>
+void rcar_micro_delay(uint64_t micro_sec);
+#endif
+
+#endif /* MICRO_DELAY_H */
diff --git a/drivers/renesas/common/dma/dma_driver.c b/drivers/renesas/common/dma/dma_driver.c
new file mode 100644
index 0000000..44ee985
--- /dev/null
+++ b/drivers/renesas/common/dma/dma_driver.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "cpg_registers.h"
+#include "rcar_def.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 - src address invalid (0x%x), len=(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 - dest address invalid (0x%lx), len=(0x%x)\n",
+ dst, dma_len);
+ panic();
+ }
+
+ dma_start(dst, src, dma_len);
+ dma_end();
+}
+
+void rcar_dma_init(void)
+{
+ dma_enable();
+ dma_setup();
+}
diff --git a/drivers/renesas/common/emmc/emmc_cmd.c b/drivers/renesas/common/emmc/emmc_cmd.c
new file mode 100644
index 0000000..d255bff
--- /dev/null
+++ b/drivers/renesas/common/emmc/emmc_cmd.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+
+#include "emmc_config.h"
+#include "emmc_def.h"
+#include "emmc_hal.h"
+#include "emmc_registers.h"
+#include "emmc_std.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 (mmc_drv_obj.transfer_mode == HAL_MEMCARD_DMA) {
+ /* W (CC_EXT_MODE, H'0000_1010) SD_BUF DMA transfer disabled */
+ SETR_32(CC_EXT_MODE, CC_EXT_MODE_CLEAR);
+ 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 (mmc_drv_obj.transfer_mode == HAL_MEMCARD_DMA) {
+ /* W (CC_EXT_MODE, H'0000_1010) SD_BUF DMA transfer disabled */
+ SETR_32(CC_EXT_MODE, CC_EXT_MODE_CLEAR);
+ 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;
+}
diff --git a/drivers/renesas/common/emmc/emmc_config.h b/drivers/renesas/common/emmc/emmc_config.h
new file mode 100644
index 0000000..16b6b8a
--- /dev/null
+++ b/drivers/renesas/common/emmc/emmc_config.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EMMC_CONFIG_H
+#define EMMC_CONFIG_H
+
+/* RCA */
+#define EMMC_RCA 1UL
+/* 314ms (freq = 400KHz, timeout Counter = 0x04(SDCLK * 2^17) */
+#define EMMC_RW_DATA_TIMEOUT 0x40UL
+/* how many times to try after fail. Don't change. */
+#define EMMC_RETRY_COUNT 0
+#define EMMC_CMD_MAX 60UL /* Don't change. */
+
+#define LOADIMAGE_FLAGS_DMA_ENABLE 0x00000001UL
+
+#endif /* EMMC_CONFIG_H */
diff --git a/drivers/renesas/common/emmc/emmc_def.h b/drivers/renesas/common/emmc/emmc_def.h
new file mode 100644
index 0000000..178c795
--- /dev/null
+++ b/drivers/renesas/common/emmc/emmc_def.h
@@ -0,0 +1,78 @@
+/*
+ * 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 ************************************ */
diff --git a/drivers/renesas/common/emmc/emmc_hal.h b/drivers/renesas/common/emmc/emmc_hal.h
new file mode 100644
index 0000000..0a85517
--- /dev/null
+++ b/drivers/renesas/common/emmc/emmc_hal.h
@@ -0,0 +1,535 @@
+/*
+ * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EMMC_HAL_H
+#define EMMC_HAL_H
+
+/* 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
+
+/* Memory card response types */
+#define HAL_MEMCARD_COMMAND_INDEX_MASK 0x0003f
+
+/* 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, /* card status non-masked error */
+ 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;
+
+/* memory access operation */
+typedef enum {
+ HAL_MEMCARD_READ = 0U, /* read */
+ HAL_MEMCARD_WRITE = 1U /* write */
+} HAL_MEMCARD_OPERATION;
+
+/* 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 */
+
+/* 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 */
+
+/* mode of data transfer */
+typedef enum {
+ HAL_MEMCARD_DMA = 0U,
+ HAL_MEMCARD_NOT_DMA = 1U
+} HAL_MEMCARD_DATA_TRANSFER_MODE;
+
+/* 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;
+
+/* 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;
+
+/* 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;
+
+/* 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;
+
+/* Memory card command codes. */
+typedef enum {
+/* class 0 and class 1 */
+ /* CMD0 */
+ CMD0_GO_IDLE_STATE =
+ 0U | (uint32_t)HAL_MEMCARD_RESPONSE_NONE |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_BC |
+ (uint32_t) HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD1 */
+ CMD1_SEND_OP_COND =
+ 1U | (uint32_t)HAL_MEMCARD_RESPONSE_R3 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_BCR |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_MMC |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD2 */
+ CMD2_ALL_SEND_CID_MMC =
+ 2U | (uint32_t)HAL_MEMCARD_RESPONSE_R2 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_BCR |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_MMC |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ CMD2_ALL_SEND_CID_SD =
+ 2U | (uint32_t)HAL_MEMCARD_RESPONSE_R2 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_BCR |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_SD |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD3 */
+ CMD3_SET_RELATIVE_ADDR =
+ 3U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_MMC |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ CMD3_SEND_RELATIVE_ADDR =
+ 3U | (uint32_t)HAL_MEMCARD_RESPONSE_R6 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_SD |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD4 */
+ CMD4_SET_DSR =
+ 4U | (uint32_t)HAL_MEMCARD_RESPONSE_NONE |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_BC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD5 */
+ CMD5_SLEEP_AWAKE =
+ 5U | (uint32_t)HAL_MEMCARD_RESPONSE_R1b |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_MMC |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD6 */
+ CMD6_SWITCH =
+ 6U | (uint32_t)HAL_MEMCARD_RESPONSE_R1b |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_MMC |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ CMD6_SWITCH_FUNC =
+ 6U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_SD |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ ACMD6_SET_BUS_WIDTH =
+ 6U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_SD |
+ (uint32_t)HAL_MEMCARD_COMMAND_APP,
+ /* CMD7 */
+ CMD7_SELECT_CARD =
+ 7U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD7(from Disconnected State to Programming State) */
+ CMD7_SELECT_CARD_PROG =
+ 7U | (uint32_t)HAL_MEMCARD_RESPONSE_R1b |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ CMD7_DESELECT_CARD =
+ 7U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD8 */
+ CMD8_SEND_EXT_CSD =
+ 8U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_ADTC_READ |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_MMC |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ CMD8_SEND_IF_COND =
+ 8U | (uint32_t)HAL_MEMCARD_RESPONSE_R7 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_BCR |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_SD |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD9 */
+ CMD9_SEND_CSD =
+ 9U | (uint32_t)HAL_MEMCARD_RESPONSE_R2 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD10 */
+ CMD10_SEND_CID =
+ 10U | (uint32_t)HAL_MEMCARD_RESPONSE_R2 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD11 */
+ CMD11_READ_DAT_UNTIL_STOP =
+ 11U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_ADTC_READ |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_SD |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD12 */
+ CMD12_STOP_TRANSMISSION =
+ 12U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD12(R1b : write case) */
+ CMD12_STOP_TRANSMISSION_WRITE =
+ 12U | (uint32_t)HAL_MEMCARD_RESPONSE_R1b |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD13 */
+ CMD13_SEND_STATUS =
+ 13U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ ACMD13_SD_STATUS =
+ 13U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_ADTC_READ |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_SD |
+ (uint32_t)HAL_MEMCARD_COMMAND_APP,
+ /* CMD14 */
+ CMD14_BUSTEST_R =
+ 14U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_ADTC_READ |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_MMC |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD15 */
+ CMD15_GO_INACTIVE_STATE =
+ 15U | (uint32_t)HAL_MEMCARD_RESPONSE_NONE |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+
+/* class 2 */
+ /* CMD16 */
+ CMD16_SET_BLOCKLEN =
+ 16U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD17 */
+ CMD17_READ_SINGLE_BLOCK =
+ 17U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_ADTC_READ |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD18 */
+ CMD18_READ_MULTIPLE_BLOCK =
+ 18U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_ADTC_READ |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD19 */
+ CMD19_BUS_TEST_W =
+ 19U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_MMC |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+
+/* class 3 */
+ /* CMD20 */
+ CMD20_WRITE_DAT_UNTIL_STOP =
+ 20U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_MMC |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD21 */
+ CMD21 = 21U,
+ /* CMD22 */
+ CMD22 = 22U,
+ ACMD22_SEND_NUM_WR_BLOCKS =
+ 22U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_SD |
+ (uint32_t)HAL_MEMCARD_COMMAND_APP,
+
+/* class 4 */
+ /* CMD23 */
+ CMD23_SET_BLOCK_COUNT =
+ 23U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_MMC |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ ACMD23_SET_WR_BLK_ERASE_COUNT =
+ 23U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_SD |
+ (uint32_t)HAL_MEMCARD_COMMAND_APP,
+ /* CMD24 */
+ CMD24_WRITE_BLOCK =
+ 24U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD25 */
+ CMD25_WRITE_MULTIPLE_BLOCK =
+ 25U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD26 */
+ CMD26_PROGRAM_CID =
+ 26U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_MMC |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD27 */
+ CMD27_PROGRAM_CSD =
+ 27U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+
+/* class 6 */
+ /* CMD28 */
+ CMD28_SET_WRITE_PROT =
+ 28U | (uint32_t)HAL_MEMCARD_RESPONSE_R1b |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD29 */
+ CMD29_CLR_WRITE_PROT =
+ 29U | (uint32_t)HAL_MEMCARD_RESPONSE_R1b |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD30 */
+ CMD30_SEND_WRITE_PROT =
+ 30U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_ADTC_READ |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD31 */
+ CMD30_SEND_WRITE_PROT_TYPE =
+ 31U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_ADTC_READ |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+
+/* class 5 */
+ /* CMD32 */
+ CMD32_ERASE_WR_BLK_START =
+ 32U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_SD |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD33 */
+ CMD33_ERASE_WR_BLK_END =
+ 33U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_SD |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD34 */
+ CMD34 = 34U,
+ /* CMD35 */
+ CMD35_ERASE_GROUP_START =
+ 35U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_MMC |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD36 */
+ CMD36_ERASE_GROUP_END =
+ 36U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_MMC |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD37 */
+ CMD37 = 37U,
+ /* CMD38 */
+ CMD38_ERASE =
+ 38U | (uint32_t)HAL_MEMCARD_RESPONSE_R1b |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+
+/* class 9 */
+ /* CMD39 */
+ CMD39_FASTIO =
+ 39U | (uint32_t)HAL_MEMCARD_RESPONSE_R4 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_MMC |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD40 */
+ CMD40_GO_IRQSTATE =
+ 40U | (uint32_t)HAL_MEMCARD_RESPONSE_R5 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_BCR |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_MMC |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD41 */
+ CMD41 = 41,
+ ACMD41_SD_SEND_OP_COND =
+ 41U | (uint32_t)HAL_MEMCARD_RESPONSE_R3 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_BCR |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_SD |
+ (uint32_t)HAL_MEMCARD_COMMAND_APP,
+
+/* class 7 */
+ /* CMD42 */
+ CMD42_LOCK_UNLOCK =
+ 42U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ ACMD42_SET_CLR_CARD_DETECT =
+ 42U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_SD |
+ (uint32_t)HAL_MEMCARD_COMMAND_APP,
+ CMD43 = 43U, /* CMD43 */
+ CMD44 = 44U, /* CMD44 */
+ CMD45 = 45U, /* CMD45 */
+ CMD46 = 46U, /* CMD46 */
+ CMD47 = 47U, /* CMD47 */
+ CMD48 = 48U, /* CMD48 */
+ CMD49 = 49U, /* CMD49 */
+ CMD50 = 50U, /* CMD50 */
+ CMD51 = 51U, /* CMD51 */
+ ACMD51_SEND_SCR =
+ 51U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_ADTC_READ |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_SD |
+ (uint32_t)HAL_MEMCARD_COMMAND_APP,
+ CMD52 = 52U, /* CMD52 */
+ CMD53 = 53U, /* CMD53 */
+ CMD54 = 54U, /* CMD54 */
+
+/* class 8 */
+ /* CMD55 */
+ CMD55_APP_CMD =
+ 55U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_AC |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ /* CMD56 */
+ CMD56_GEN_CMD =
+ 56U | (uint32_t)HAL_MEMCARD_RESPONSE_R1 |
+ (uint32_t)HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE |
+ (uint32_t)HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON |
+ (uint32_t)HAL_MEMCARD_COMMAND_NORMAL,
+ CMD57 = 57U, /* CMD57 */
+ CMD58 = 58U, /* CMD58 */
+ CMD59 = 59U, /* CMD59 */
+ CMD60 = 60U, /* CMD60 */
+ CMD61 = 61U, /* CMD61 */
+ CMD62 = 62U, /* CMD62 */
+ CMD63 = 63U /* CMD63 */
+} HAL_MEMCARD_COMMAND;
+
+/*
+ * 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
+ *
+ * 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.<br>
+ * bits [23:16] API specification minor version number.<br>
+ * bits [15:8] API implementation year. (2000 = 0, 2001 = 1, ...)
+ * bits [7:0] API implementation week.
+ * Example: API spec 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;
+
+/* 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;
+
+#endif /* EMMC_HAL_H */
diff --git a/drivers/renesas/common/emmc/emmc_init.c b/drivers/renesas/common/emmc/emmc_init.c
new file mode 100644
index 0000000..c0ec600
--- /dev/null
+++ b/drivers/renesas/common/emmc/emmc_init.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <lib/mmio.h>
+
+#include "emmc_config.h"
+#include "emmc_hal.h"
+#include "emmc_std.h"
+#include "emmc_registers.h"
+#include "emmc_def.h"
+#include "rcar_private.h"
+#include "cpg_registers.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(SMSTPCR3);
+ if ((dataL & CPG_MSTP_MMC) == 0U) {
+ dataL |= (CPG_MSTP_MMC);
+ mmio_write_32(CPG_CPGWPR, (~dataL));
+ mmio_write_32(SMSTPCR3, dataL);
+ }
+
+ return result;
+}
+
+static EMMC_ERROR_CODE emmc_dev_init(void)
+{
+ /* Enable clock supply to eMMC. */
+ mstpcr_write(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); /* Disable Automatic Control & Clock Output */
+
+ return EMMC_SUCCESS;
+}
+
+static EMMC_ERROR_CODE emmc_reset_controller(void)
+{
+ EMMC_ERROR_CODE result;
+
+ /* initialize mmc driver */
+ emmc_drv_init();
+
+ /* initialize H/W */
+ result = emmc_dev_init();
+ if (result == EMMC_SUCCESS) {
+ mmc_drv_obj.initialize = TRUE;
+ }
+
+ return result;
+
+}
+
+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 result;
+
+ result = emmc_reset_controller();
+ if (result == EMMC_SUCCESS) {
+ emmc_driver_config();
+ }
+
+ return result;
+}
diff --git a/drivers/renesas/common/emmc/emmc_interrupt.c b/drivers/renesas/common/emmc/emmc_interrupt.c
new file mode 100644
index 0000000..092fdfb
--- /dev/null
+++ b/drivers/renesas/common/emmc/emmc_interrupt.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights
+ * reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <lib/mmio.h>
+
+#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 occurred */
+ 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 occurred */
+ 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 occurred */
+ 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;
+}
diff --git a/drivers/renesas/common/emmc/emmc_mount.c b/drivers/renesas/common/emmc/emmc_mount.c
new file mode 100644
index 0000000..e04afd4
--- /dev/null
+++ b/drivers/renesas/common/emmc/emmc_mount.c
@@ -0,0 +1,686 @@
+/*
+ * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "emmc_config.h"
+#include "emmc_def.h"
+#include "emmc_hal.h"
+#include "emmc_registers.h"
+#include "emmc_std.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 result_calc;
+
+ /* 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
+ * Card spec is calculated from TRAN_SPEED(CSD)
+ */
+ result_calc = emmc_calc_tran_speed(&freq);
+ if (result_calc == 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 selection */
+ if ((freq == MMC_52MHZ) || (freq == MMC_26MHZ)) {
+ /* 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;
+ }
+
+ /* 2 = 8bit, 1 = 4bit, 0 =1bit */
+ mmc_drv_obj.bus_width = (HAL_MEMCARD_DATA_WIDTH) (width >> 2);
+
+ /* 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] = { 10000U, 100000U, 1000000U, 10000000U,
+ 0U, 0U, 0U, 0U }; /* frequency unit (1/10) */
+ const uint32_t mult[16] = { 0U, 10U, 12U, 13U, 15U, 20U, 26U, 30U, 35U,
+ 40U, 45U, 52U, 55U, 60U, 70U, 80U };
+ uint32_t tran_speed = EMMC_CSD_TRAN_SPEED();
+ uint32_t max_freq;
+ uint32_t result;
+
+ /*
+ * 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;
+ max_freq =
+ unit[tran_speed & EMMC_TRANSPEED_FREQ_UNIT_MASK] *
+ mult[(tran_speed & EMMC_TRANSPEED_MULT_MASK) >>
+ EMMC_TRANSPEED_MULT_SHIFT];
+
+ if (max_freq == 0) {
+ result = 0;
+ } else if (max_freq >= MMC_FREQ_52MHZ) {
+ *freq = MMC_52MHZ;
+ } else if (max_freq >= MMC_FREQ_26MHZ) {
+ *freq = MMC_26MHZ;
+ } else if (max_freq >= MMC_FREQ_20MHZ) {
+ *freq = MMC_20MHZ;
+ } else {
+ *freq = MMC_400KHZ;
+ }
+
+ return result;
+}
+
+static uint32_t emmc_set_timeout_register_value(uint32_t freq)
+{
+ uint32_t timeout_cnt; /* SD_OPTION - Timeout Counter */
+
+ switch (freq) {
+ case 1U:
+ timeout_cnt = 0xE0U;
+ break; /* SDCLK * 2^27 */
+ case 2U:
+ timeout_cnt = 0xE0U;
+ break; /* SDCLK * 2^27 */
+ case 4U:
+ timeout_cnt = 0xD0U;
+ break; /* SDCLK * 2^26 */
+ case 8U:
+ timeout_cnt = 0xC0U;
+ break; /* SDCLK * 2^25 */
+ case 16U:
+ timeout_cnt = 0xB0U;
+ break; /* SDCLK * 2^24 */
+ case 32U:
+ timeout_cnt = 0xA0U;
+ break; /* SDCLK * 2^23 */
+ case 64U:
+ timeout_cnt = 0x90U;
+ break; /* SDCLK * 2^22 */
+ case 128U:
+ timeout_cnt = 0x80U;
+ break; /* SDCLK * 2^21 */
+ case 256U:
+ timeout_cnt = 0x70U;
+ break; /* SDCLK * 2^20 */
+ case 512U:
+ timeout_cnt = 0x70U;
+ break; /* SDCLK * 2^20 */
+ default:
+ timeout_cnt = 0xE0U;
+ break; /* SDCLK * 2^27 */
+ }
+
+ return timeout_cnt;
+}
+
+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;
+}
diff --git a/drivers/renesas/common/emmc/emmc_read.c b/drivers/renesas/common/emmc/emmc_read.c
new file mode 100644
index 0000000..96e73ca
--- /dev/null
+++ b/drivers/renesas/common/emmc/emmc_read.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+
+#include "emmc_config.h"
+#include "emmc_def.h"
+#include "emmc_hal.h"
+#include "emmc_registers.h"
+#include "emmc_std.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);
+ /* SD_BUF Read/Write DMA Transfer enable */
+ SETR_32(CC_EXT_MODE, (CC_EXT_MODE_CLEAR | CC_EXT_MODE_DMASDRW_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;
+}
diff --git a/drivers/renesas/common/emmc/emmc_registers.h b/drivers/renesas/common/emmc/emmc_registers.h
new file mode 100644
index 0000000..67d285d
--- /dev/null
+++ b/drivers/renesas/common/emmc/emmc_registers.h
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EMMC_REGISTERS_H
+#define EMMC_REGISTERS_H
+
+/* MMC channel select */
+#define MMC_CH0 (0U) /* SDHI2/MMC0 */
+#define MMC_CH1 (1U) /* SDHI3/MMC1 */
+
+#if (RCAR_LSI == RCAR_E3) || (RCAR_LSI == RZ_G2M) || (RCAR_LSI == RZ_G2H) || (RCAR_LSI == RZ_G2N)
+#define USE_MMC_CH (MMC_CH1) /* R-Car E3 or RZ/G2{H,M,N} */
+#else /* RCAR_LSI == RCAR_E3 || RCAR_LSI == RZ_G2{H,M,N} */
+#define USE_MMC_CH (MMC_CH0) /* R-Car H3/M3/M3N */
+#endif /* RCAR_LSI == RCAR_E3 || RCAR_LSI == RZ_G2{H,M,N} */
+
+#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)
+
+#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)
+
+/* 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)
+
+/* 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 */
+
+/* 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 write value should always be 1. HWM_0003 */
+
+/* SOFT_RST */
+#define SOFT_RST_SDRST 0x00000001UL
+
+/* 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
+
+/* SD_OPTION */
+#define SD_OPTION_TIMEOUT_CNT_MASK 0x000000F0UL
+
+/*
+ * 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 HS mode 26Mhz */
+#define MMC_52MHZ 4UL /* 200MHz * 1/4 = 50 MHz HS 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
+
+/* 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 */
+
+/* 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
+
+/* 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. */
+
+/* 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
+
+/* DM_DTRAN_ADDR */
+#define DM_DTRAN_ADDR_WRITE_MASK 0xFFFFFFF8UL
+
+/* DM_CM_DTRAN_CTRL */
+#define DM_CM_DTRAN_CTRL_START 0x00000001UL
+
+/* 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 */
+
+#endif /* EMMC_REGISTERS_H */
diff --git a/drivers/renesas/common/emmc/emmc_std.h b/drivers/renesas/common/emmc/emmc_std.h
new file mode 100644
index 0000000..087c6e9
--- /dev/null
+++ b/drivers/renesas/common/emmc/emmc_std.h
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EMMC_STD_H
+#define EMMC_STD_H
+
+#include "emmc_hal.h"
+
+#ifndef FALSE
+#define FALSE 0U
+#endif
+#ifndef TRUE
+#define TRUE 1U
+#endif
+
+/* 64bit registers */
+#define SETR_64(r, v) (*(volatile uint64_t *)(r) = (v))
+#define GETR_64(r) (*(volatile uint64_t *)(r))
+
+/* 32bit registers */
+#define SETR_32(r, v) (*(volatile uint32_t *)(r) = (v))
+#define GETR_32(r) (*(volatile uint32_t *)(r))
+
+/* 16bit registers */
+#define SETR_16(r, v) (*(volatile uint16_t *)(r) = (v))
+#define GETR_16(r) (*(volatile uint16_t *)(r))
+
+/* 8bit registers */
+#define SETR_8(r, v) (*(volatile uint8_t *)(r) = (v))
+#define GETR_8(r) (*(volatile uint8_t *)(r))
+
+/* 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))
+
+/* 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))
+
+/* 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 */
+
+/* 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 */
+
+/* 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 */
+ 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;
+
+/* 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
+/*
+ * Response
+ * R1
+ * Type 'E' bit and bit14(must be 0). ignore bit22
+ */
+#define EMMC_R1_ERROR_MASK 0xFDBFE080U
+/* Ignore bit23 (Not check CRC error) */
+#define EMMC_R1_ERROR_MASK_WITHOUT_CRC (0xFD3FE080U)
+#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 */
+/* Partition config = 0x00 */
+#define EMMC_SWITCH_PARTITION_CONFIG 0x03B30000UL
+
+#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
+
+/* TAAC mask */
+#define TAAC_TIME_UNIT_MASK (0x07)
+#define TAAC_MULTIPLIER_FACTOR_MASK (0x0F)
+
+/* 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;
+
+/* 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;
+
+/* eMMC boot driver error information */
+typedef struct {
+ uint16_t num; /* error no */
+ uint16_t code; /* error code */
+
+ volatile uint32_t info1; /* SD_INFO1. (hw dependent) */
+ volatile uint32_t info2; /* SD_INFO2. (hw dependent) */
+ volatile uint32_t status1; /* SD_ERR_STS1. (hw dependent) */
+ volatile uint32_t status2; /* SD_ERR_STS2. (hw dependent) */
+ volatile uint32_t dm_info1; /* DM_CM_INFO1. (hw dependent) */
+ volatile uint32_t dm_info2; /* DM_CM_INFO2. (hw dependent) */
+} st_error_info;
+
+/* Command information */
+typedef struct {
+ HAL_MEMCARD_COMMAND cmd; /* Command information */
+ uint32_t arg; /* argument */
+ HAL_MEMCARD_OPERATION dir; /* direction */
+ uint32_t hw; /* SD_CMD register value. */
+} st_command_info;
+
+/* 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 */
+ /*
+ * Max freq (Card Spec)[Hz]. It changes dynamically by CSD and
+ * EXT_CSD.
+ */
+ uint32_t max_freq;
+ /* request freq [Hz] (400K, 26MHz, 52MHz, etc) */
+ uint32_t request_freq;
+ /* current MMC clock[Hz] (the closest frequency supported by HW) */
+ uint32_t current_freq;
+
+ /* state flag */
+ /* presence status of the memory card */
+ HAL_MEMCARD_PRESENCE_STATUS card_present;
+
+ uint32_t card_power_enable;
+ uint32_t clock_enable;
+ /* True : initialize complete. */
+ uint32_t initialize;
+ /* True : sector access, FALSE : byte access */
+ uint32_t access_mode;
+ /* True : mount complete. */
+ uint32_t mount;
+ /* True : selected card. */
+ uint32_t selected;
+ /* 0: DMA, 1:PIO */
+ HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode;
+
+ /* loaded ISSW image No. ISSW have copy image. */
+ uint32_t image_num;
+ /* card state */
+ EMMC_R1_STATE current_state;
+ /* True : during command processing */
+ volatile uint32_t during_cmd_processing;
+ /* True : during transfer */
+ volatile uint32_t during_transfer;
+ /* True : during transfer (DMA) */
+ volatile uint32_t during_dma_transfer;
+ /* True : occurred DMAC error */
+ volatile uint32_t dma_error_flag;
+ /* force terminate flag */
+ volatile uint32_t force_terminate;
+ /* state machine blocking flag : True or False */
+ volatile uint32_t state_machine_blocking;
+ /* True : get partition access processing */
+ volatile uint32_t get_partition_access_flag;
+
+ EMMC_PARTITION_ID boot_partition_en; /* Boot partition */
+ EMMC_PARTITION_ID partition_access; /* Current access partition */
+
+ /* timeout */
+ uint32_t hs_timing;
+
+ /* read and write data timeout */
+ uint32_t data_timeout;
+
+ /* retry */
+ uint32_t retries_after_fail;
+
+ /* 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; /* buffer ptr 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 */
+
+ /* True : clock mode is low. (MMC clock = Max26MHz) */
+ uint32_t low_clock_mode_enable;
+
+ 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);
+
+uint32_t emmc_get_csd_time(void);
+
+#define MMC_DEBUG
+#endif /* EMMC_STD_H */
diff --git a/drivers/renesas/common/emmc/emmc_utility.c b/drivers/renesas/common/emmc/emmc_utility.c
new file mode 100644
index 0000000..2e88abc
--- /dev/null
+++ b/drivers/renesas/common/emmc/emmc_utility.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+
+#include "emmc_config.h"
+#include "emmc_def.h"
+#include "emmc_hal.h"
+#include "emmc_registers.h"
+#include "emmc_std.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;
+}
diff --git a/drivers/renesas/common/iic_dvfs/iic_dvfs.c b/drivers/renesas/common/iic_dvfs/iic_dvfs.c
new file mode 100644
index 0000000..bf80697
--- /dev/null
+++ b/drivers/renesas/common/iic_dvfs/iic_dvfs.c
@@ -0,0 +1,600 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "cpg_registers.h"
+#include "iic_dvfs.h"
+#include "rcar_def.h"
+#include "rcar_private.h"
+
+#define DVFS_RETRY_MAX (2U)
+
+#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_0 (0x07U)
+#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_1 (0x09U)
+#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_2 (0x0BU)
+#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_3 (0x0EU)
+#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_E (0x15U)
+
+#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_0 (0x01U)
+#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_1 (0x02U)
+#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_2 (0x03U)
+#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_3 (0x05U)
+#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_E (0x07U)
+
+#define CPG_BIT_SMSTPCR9_DVFS (0x04000000U)
+
+#define IIC_DVFS_REG_BASE (0xE60B0000U)
+#define IIC_DVFS_REG_ICDR (IIC_DVFS_REG_BASE + 0x0000U)
+#define IIC_DVFS_REG_ICCR (IIC_DVFS_REG_BASE + 0x0004U)
+#define IIC_DVFS_REG_ICSR (IIC_DVFS_REG_BASE + 0x0008U)
+#define IIC_DVFS_REG_ICIC (IIC_DVFS_REG_BASE + 0x000CU)
+#define IIC_DVFS_REG_ICCL (IIC_DVFS_REG_BASE + 0x0010U)
+#define IIC_DVFS_REG_ICCH (IIC_DVFS_REG_BASE + 0x0014U)
+
+#define IIC_DVFS_BIT_ICSR_BUSY (0x10U)
+#define IIC_DVFS_BIT_ICSR_AL (0x08U)
+#define IIC_DVFS_BIT_ICSR_TACK (0x04U)
+#define IIC_DVFS_BIT_ICSR_WAIT (0x02U)
+#define IIC_DVFS_BIT_ICSR_DTE (0x01U)
+
+#define IIC_DVFS_BIT_ICCR_ENABLE (0x80U)
+#define IIC_DVFS_SET_ICCR_START (0x94U)
+#define IIC_DVFS_SET_ICCR_STOP (0x90U)
+#define IIC_DVFS_SET_ICCR_RETRANSMISSION (0x94U)
+#define IIC_DVFS_SET_ICCR_CHANGE (0x81U)
+#define IIC_DVFS_SET_ICCR_STOP_READ (0xC0U)
+
+#define IIC_DVFS_BIT_ICIC_TACKE (0x04U)
+#define IIC_DVFS_BIT_ICIC_WAITE (0x02U)
+#define IIC_DVFS_BIT_ICIC_DTEE (0x01U)
+
+#define DVFS_READ_MODE (0x01U)
+#define DVFS_WRITE_MODE (0x00U)
+
+#define IIC_DVFS_SET_DUMMY (0x52U)
+#define IIC_DVFS_SET_BUSY_LOOP (500000000U)
+
+enum dvfs_state_t {
+ 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_RECEIVE,
+ DVFS_DONE,
+};
+
+#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, enum dvfs_state_t *state, uint32_t *err, uint8_t mode)
+{
+ uint8_t icsr_al = 0U, icsr_tack = 0U;
+ uint8_t reg, stop;
+ uint32_t i = 0U;
+
+ 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 == 0U && icsr_tack == 0U) {
+ 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 == 0U);
+
+ 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 = 0U;
+ do {
+ reg = mmio_read_8(IIC_DVFS_REG_ICSR) &
+ IIC_DVFS_BIT_ICSR_BUSY;
+ if (reg == 0U) {
+ break;
+ }
+
+ if (i++ > IIC_DVFS_SET_BUSY_LOOP) {
+ panic();
+ }
+
+ } while (true);
+
+ 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 = 0U;
+ while ((mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_BUSY) != 0U) {
+ if (i++ > IIC_DVFS_SET_BUSY_LOOP) {
+ panic();
+ }
+ }
+
+ mmio_write_8(IIC_DVFS_REG_ICCR, 0U);
+ (*err)++;
+
+ if (*err > DVFS_RETRY_MAX) {
+ return DVFS_ERROR;
+ }
+
+ *state = DVFS_START;
+
+ return DVFS_PROCESS;
+}
+
+IIC_DVFS_FUNC(start, enum 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, enum 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, enum 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, enum 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, enum 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 = 0U; i < IIC_DVFS_SET_BUSY_LOOP; i++) {
+ if ((mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_BUSY) != 0U) {
+ continue;
+ }
+ goto done;
+ }
+
+ panic();
+done:
+ mmio_write_8(IIC_DVFS_REG_ICCR, 0U);
+
+ return DVFS_COMPLETE;
+}
+
+IIC_DVFS_FUNC(write_reg_addr_read, enum 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, enum 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, enum 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_RECEIVE;
+
+ return result;
+}
+
+IIC_DVFS_FUNC(change_send_to_receive, enum 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, enum 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, enum 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)
+{
+ enum dvfs_state_t state = DVFS_START;
+ int32_t result = DVFS_PROCESS;
+ uint32_t err = 0U;
+
+ mstpcr_write(SCMSTPCR9, CPG_MSTPSR9, CPG_BIT_SMSTPCR9_DVFS);
+ mmio_write_8(IIC_DVFS_REG_ICCR, 1U);
+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)
+{
+ enum dvfs_state_t state = DVFS_START;
+ int32_t result = DVFS_PROCESS;
+ uint32_t err = 0U;
+
+ mstpcr_write(SCMSTPCR9, CPG_MSTPSR9, CPG_BIT_SMSTPCR9_DVFS);
+ mmio_write_8(IIC_DVFS_REG_ICCR, 1U);
+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_RECEIVE:
+ result = dvfs_change_send_to_receive(&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;
+}
diff --git a/drivers/renesas/common/iic_dvfs/iic_dvfs.h b/drivers/renesas/common/iic_dvfs/iic_dvfs.h
new file mode 100644
index 0000000..244c06c
--- /dev/null
+++ b/drivers/renesas/common/iic_dvfs/iic_dvfs.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IIC_DVFS_H
+#define IIC_DVFS_H
+
+/* PMIC slave */
+#define PMIC (0x30U)
+#define BKUP_MODE_CNT (0x20U)
+#define DVFS_SET_VID (0x54U)
+#define REG_KEEP10 (0x79U)
+
+/* EEPROM slave */
+#define EEPROM (0x50U)
+#define BOARD_ID (0x70U)
+
+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 */
diff --git a/drivers/renesas/common/io/io_common.h b/drivers/renesas/common/io/io_common.h
new file mode 100644
index 0000000..6eb7777
--- /dev/null
+++ b/drivers/renesas/common/io/io_common.h
@@ -0,0 +1,16 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/common/io/io_emmcdrv.c b/drivers/renesas/common/io/io_emmcdrv.c
new file mode 100644
index 0000000..c2b5f7c
--- /dev/null
+++ b/drivers/renesas/common/io/io_emmcdrv.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+
+#include "emmc_config.h"
+#include "emmc_def.h"
+#include "emmc_hal.h"
+#include "emmc_std.h"
+#include "io_common.h"
+#include "io_emmcdrv.h"
+#include "io_private.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;
+ signed long long 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,
+ signed long long 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%llx(%d) len=0x%lx(%d)\n",
+ buffer,
+ current_file.partition, current_file.file_pos,
+ sector_add, length, sector_num);
+
+ if ((buffer + length - 1U) <= (uintptr_t)UINT32_MAX) {
+ emmc_dma = LOADIMAGE_FLAGS_DMA_ENABLE;
+ }
+
+ if (emmc_read_sector((uint32_t *) buffer, sector_add, sector_num,
+ emmc_dma) != EMMC_SUCCESS) {
+ result = IO_FAIL;
+ }
+
+ *length_read = length;
+ fp->file_pos += (signed long long)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 != 0U) {
+ 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 ((emmcdrv_bootpartition == PARTITION_ID_BOOT_1) ||
+ (emmcdrv_bootpartition == PARTITION_ID_BOOT_2)) {
+ current_file.partition = emmcdrv_bootpartition;
+
+ NOTICE("BL2: eMMC boot from partition %d\n",
+ emmcdrv_bootpartition);
+ goto done;
+ }
+ return IO_FAIL;
+ }
+
+ if ((block_spec->partition == PARTITION_ID_USER) ||
+ (block_spec->partition == PARTITION_ID_BOOT_1) ||
+ (block_spec->partition == PARTITION_ID_BOOT_2)) {
+ 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) &current_file;
+
+ return IO_SUCCESS;
+}
+
+static int32_t emmcdrv_block_close(io_entity_t *entity)
+{
+ memset((void *)&current_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;
+}
diff --git a/drivers/renesas/common/io/io_emmcdrv.h b/drivers/renesas/common/io/io_emmcdrv.h
new file mode 100644
index 0000000..95070f2
--- /dev/null
+++ b/drivers/renesas/common/io/io_emmcdrv.h
@@ -0,0 +1,13 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/common/io/io_memdrv.c b/drivers/renesas/common/io/io_memdrv.c
new file mode 100644
index 0000000..1f31c0f
--- /dev/null
+++ b/drivers/renesas/common/io/io_memdrv.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+
+#include "io_common.h"
+#include "io_memdrv.h"
+#include "io_private.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;
+ signed long long 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 != 0U) {
+ 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) &current_file;
+
+ return IO_SUCCESS;
+}
+
+static int32_t memdrv_block_seek(io_entity_t *entity, int32_t mode,
+ signed long long 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%llx len=%ld(0x%lx)\n",
+ buffer, (unsigned long long)fp->base +
+ (unsigned long long)fp->file_pos, length, length);
+
+ if (FLASH_MEMORY_SIZE < (fp->file_pos + (signed long long)length)) {
+ ERROR("BL2: check load image (source address)\n");
+ return IO_FAIL;
+ }
+
+ rcar_dma_exec(buffer, fp->base + (uintptr_t)fp->file_pos, length);
+ fp->file_pos += (signed long long)length;
+ *cnt = length;
+
+ return IO_SUCCESS;
+}
+
+static int32_t memdrv_block_close(io_entity_t *entity)
+{
+ entity->info = 0U;
+
+ memset((void *)&current_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;
+}
diff --git a/drivers/renesas/common/io/io_memdrv.h b/drivers/renesas/common/io/io_memdrv.h
new file mode 100644
index 0000000..90e6812
--- /dev/null
+++ b/drivers/renesas/common/io/io_memdrv.h
@@ -0,0 +1,13 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/common/io/io_private.h b/drivers/renesas/common/io/io_private.h
new file mode 100644
index 0000000..207523a
--- /dev/null
+++ b/drivers/renesas/common/io/io_private.h
@@ -0,0 +1,20 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/common/io/io_rcar.c b/drivers/renesas/common/io/io_rcar.c
new file mode 100644
index 0000000..45ef386
--- /dev/null
+++ b/drivers/renesas/common/io/io_rcar.c
@@ -0,0 +1,665 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/auth/auth_mod.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <tools_share/firmware_image_package.h>
+#include <tools_share/uuid.h>
+
+#include "io_rcar.h"
+#include "io_common.h"
+#include "io_private.h"
+#include <platform_def.h>
+
+extern int32_t plat_get_drv_source(uint32_t id, uintptr_t *dev,
+ uintptr_t *image_spec);
+
+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;
+}
+
+#define MFISBTSTSR (0xE6260604U)
+#define MFISBTSTSR_BOOT_PARTITION (0x00000010U)
+
+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 + 2U < addr) {
+ continue;
+ }
+
+ *offset = rcar_image_header[addr];
+
+ if (mmio_read_32(MFISBTSTSR) & MFISBTSTSR_BOOT_PARTITION)
+ *offset += 0x800000;
+ *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("%s: failed to get offset\n", __func__);
+ 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("%s: Failed to open FIP (%i)\n", __func__, rc);
+ loaded = IO_FAIL;
+ return loaded;
+ }
+
+ rc = io_seek(handle, IO_SEEK_SET, offset);
+ if (rc != IO_SUCCESS) {
+ WARN("%s: failed to seek\n", __func__);
+ loaded = IO_FAIL;
+ return loaded;
+ }
+
+ rc = check_load_area(dst, len);
+ if (rc != IO_SUCCESS) {
+ WARN("%s: check load area\n", __func__);
+ loaded = IO_FAIL;
+ return loaded;
+ }
+
+ rc = io_read(handle, dst, len, &cnt);
+ if (rc != IO_SUCCESS) {
+ WARN("%s: failed to read\n", __func__);
+ loaded = IO_FAIL;
+ return loaded;
+ }
+#if TRUSTED_BOARD_BOOT
+ rc = auth_mod_verify_img(img[i], (void *)dst, len);
+ if (rc != 0) {
+ 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)
+{
+ static uint64_t header[64] __aligned(FLASH_TRANS_SIZE_UNIT) = {0UL};
+ 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;
+ }
+
+ 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;
+ }
+
+#if RCAR_BL2_DCACHE == 1
+ inv_dcache_range((uint64_t) header, sizeof(header));
+#endif
+
+ 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");
+ rc = IO_FAIL;
+ 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;
+ }
+
+ 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;
+ }
+
+#if RCAR_BL2_DCACHE == 1
+ inv_dcache_range(RCAR_SDRAM_certESS,
+ RCAR_CERT_SIZE * (2 + rcar_image_number));
+#endif
+
+ 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("%s: Only one open file at a time.\n", __func__);
+ 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 != 0U) {
+ 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) &current_file;
+
+ return IO_SUCCESS;
+ }
+
+ rcar_read_certificate((uint64_t) cert, &len, &dst);
+
+ /* Baylibre: HACK */
+ if (spec->offset == BL31_IMAGE_ID && len < RCAR_TRUSTED_SRAM_SIZE) {
+ WARN("%s,%s\n", "r-car ignoring the BL31 size from certificate",
+ "using RCAR_TRUSTED_SRAM_SIZE instead");
+ 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) &current_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 != 0U) {
+ *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("%s: failed to seek\n", __func__);
+ goto error;
+ }
+
+ if (load_bl33x_counter == RCAR_COUNT_LOAD_BL33) {
+ rc = check_load_area(buffer, length);
+ if (rc != IO_SUCCESS) {
+ WARN("%s: load area err\n", __func__);
+ 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 != 0U) {
+ memset(&current_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;
+}
diff --git a/drivers/renesas/common/io/io_rcar.h b/drivers/renesas/common/io/io_rcar.h
new file mode 100644
index 0000000..c26a617
--- /dev/null
+++ b/drivers/renesas/common/io/io_rcar.h
@@ -0,0 +1,14 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/common/pfc_regs.h b/drivers/renesas/common/pfc_regs.h
new file mode 100644
index 0000000..4187733
--- /dev/null
+++ b/drivers/renesas/common/pfc_regs.h
@@ -0,0 +1,230 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/common/pwrc/call_sram.S b/drivers/renesas/common/pwrc/call_sram.S
new file mode 100644
index 0000000..aa8644c
--- /dev/null
+++ b/drivers/renesas/common/pwrc/call_sram.S
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+.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
diff --git a/drivers/renesas/common/pwrc/pwrc.c b/drivers/renesas/common/pwrc/pwrc.c
new file mode 100644
index 0000000..b60ccab
--- /dev/null
+++ b/drivers/renesas/common/pwrc/pwrc.c
@@ -0,0 +1,917 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include "iic_dvfs.h"
+#include "micro_delay.h"
+#include "pwrc.h"
+#include "rcar_def.h"
+#include "rcar_private.h"
+#include "cpg_registers.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)
+#define SYSCEXTMASK_EXTMSK0 (0x00000001U)
+/* 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 /* PMIC_ROHM_BD9571 */
+#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(u_register_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(u_register_t mpidr)
+{
+ uintptr_t reg_pwrsr, reg_cpumcr, reg_pwron, reg_pwrer;
+ uint32_t c, sysc_reg_bit;
+ uint32_t lsi_product;
+ uint32_t lsi_cut;
+
+ 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);
+
+ lsi_product = mmio_read_32((uintptr_t)RCAR_PRR);
+ lsi_cut = lsi_product & PRR_CUT_MASK;
+ lsi_product &= PRR_PRODUCT_MASK;
+
+ if ((lsi_product == PRR_PRODUCT_M3 && lsi_cut >= PRR_PRODUCT_30) ||
+ lsi_product == PRR_PRODUCT_H3 ||
+ lsi_product == PRR_PRODUCT_M3N ||
+ lsi_product == PRR_PRODUCT_E3) {
+ mmio_setbits_32(RCAR_SYSCEXTMASK, SYSCEXTMASK_EXTMSK0);
+ }
+
+ 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_SYSCISCR, sysc_reg_bit);
+
+ if ((lsi_product == PRR_PRODUCT_M3 && lsi_cut >= PRR_PRODUCT_30) ||
+ lsi_product == PRR_PRODUCT_H3 ||
+ lsi_product == PRR_PRODUCT_M3N ||
+ lsi_product == PRR_PRODUCT_E3) {
+ mmio_clrbits_32(RCAR_SYSCEXTMASK, SYSCEXTMASK_EXTMSK0);
+ }
+
+ while ((mmio_read_32(reg_pwrsr) & STATUS_PWRUP) == 0)
+ ;
+}
+
+void rcar_pwrc_cpuon(u_register_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(CPG_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(u_register_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(CPG_CPGWPR, ~CPU_PWR_OFF);
+ mmio_write_32(reg + cpu * 0x0010, CPU_PWR_OFF);
+
+ rcar_lock_release();
+}
+
+void rcar_pwrc_enable_interrupt_wakeup(u_register_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_clrbits_32(reg, ((uint32_t) 1 << shift_irq) |
+ ((uint32_t) 1 << shift_fiq));
+ rcar_lock_release();
+}
+
+void rcar_pwrc_disable_interrupt_wakeup(u_register_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_setbits_32(reg, ((uint32_t) 1 << shift_irq) |
+ ((uint32_t) 1 << shift_fiq));
+ rcar_lock_release();
+}
+
+void rcar_pwrc_all_disable_interrupt_wakeup(void)
+{
+ uint32_t cpu_num;
+ u_register_t cl, cpu, mpidr;
+
+ const uint32_t cluster[PLATFORM_CLUSTER_COUNT] = {
+ RCAR_CLUSTER_CA57,
+ RCAR_CLUSTER_CA53
+ };
+
+ for (cl = 0; cl < PLATFORM_CLUSTER_COUNT; cl++) {
+ cpu_num = rcar_pwrc_get_cpu_num(cluster[cl]);
+ for (cpu = 0; cpu < cpu_num; cpu++) {
+ mpidr = ((cl << MPIDR_AFFINITY_BITS) | cpu);
+ if (mpidr == rcar_boot_mpidr) {
+ rcar_pwrc_enable_interrupt_wakeup(mpidr);
+ } else {
+ rcar_pwrc_disable_interrupt_wakeup(mpidr);
+ }
+ }
+ }
+}
+
+void rcar_pwrc_clusteroff(u_register_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 (product == PRR_PRODUCT_M3 && cut < PRR_PRODUCT_30) {
+ goto done;
+ }
+
+ if (product == PRR_PRODUCT_H3 && 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 /* RCAR_SYSTEM_SUSPEND */
+
+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);
+
+ attr = MT_MEMORY | MT_RO | MT_SECURE | MT_EXECUTE;
+ ret = xlat_change_mem_attributes(sram.base, sram.len, attr);
+ assert(ret == 0);
+
+ /* Invalidate instruction cache */
+ plat_invalidate_icache();
+ dsb();
+ isb();
+}
+
+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(u_register_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(u_register_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;
+}
diff --git a/drivers/renesas/common/pwrc/pwrc.h b/drivers/renesas/common/pwrc/pwrc.h
new file mode 100644
index 0000000..eefa62f
--- /dev/null
+++ b/drivers/renesas/common/pwrc/pwrc.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015-2020, 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)
+
+extern u_register_t rcar_boot_mpidr;
+
+#ifndef __ASSEMBLER__
+void rcar_pwrc_disable_interrupt_wakeup(u_register_t mpidr);
+void rcar_pwrc_enable_interrupt_wakeup(u_register_t mpidr);
+void rcar_pwrc_all_disable_interrupt_wakeup(void);
+void rcar_pwrc_clusteroff(u_register_t mpidr);
+void rcar_pwrc_cpuoff(u_register_t mpidr);
+void rcar_pwrc_cpuon(u_register_t mpidr);
+int32_t rcar_pwrc_cpu_on_check(u_register_t mpidr);
+void rcar_pwrc_setup(void);
+
+uint32_t rcar_pwrc_get_cpu_wkr(u_register_t mpidr);
+uint32_t rcar_pwrc_status(u_register_t mpidr);
+uint32_t rcar_pwrc_get_cluster(void);
+uint32_t rcar_pwrc_get_mpidr_cluster(u_register_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 */
diff --git a/drivers/renesas/common/qos_reg.h b/drivers/renesas/common/qos_reg.h
new file mode 100644
index 0000000..f2012fa
--- /dev/null
+++ b/drivers/renesas/common/qos_reg.h
@@ -0,0 +1,133 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/common/rom/rom_api.c b/drivers/renesas/common/rom/rom_api.c
new file mode 100644
index 0000000..fda2815
--- /dev/null
+++ b/drivers/renesas/common/rom/rom_api.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <lib/mmio.h>
+
+#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);
+}
diff --git a/drivers/renesas/common/rom/rom_api.h b/drivers/renesas/common/rom/rom_api.h
new file mode 100644
index 0000000..1d5b03d
--- /dev/null
+++ b/drivers/renesas/common/rom/rom_api.h
@@ -0,0 +1,31 @@
+/*
+ * 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 <stdint.h>
+
+#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 */
diff --git a/drivers/renesas/common/rpc/rpc_driver.c b/drivers/renesas/common/rpc/rpc_driver.c
new file mode 100644
index 0000000..63de5b8
--- /dev/null
+++ b/drivers/renesas/common/rpc/rpc_driver.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#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();
+}
diff --git a/drivers/renesas/common/rpc/rpc_registers.h b/drivers/renesas/common/rpc/rpc_registers.h
new file mode 100644
index 0000000..79aea85
--- /dev/null
+++ b/drivers/renesas/common/rpc/rpc_registers.h
@@ -0,0 +1,25 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/common/scif/scif.S b/drivers/renesas/common/scif/scif.S
new file mode 100644
index 0000000..72b5b4b
--- /dev/null
+++ b/drivers/renesas/common/scif/scif.S
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <console_macros.S>
+#include <drivers/renesas/rcar/console/console.h>
+
+#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_115200BPS_D3_SSCG (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_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_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_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 5f
+ and w1, w1, #PRR_PRODUCT_MASK
+ mov w2, #PRR_PRODUCT_E3
+ cmp w1, w2
+ bne 4f
+
+ /* When SSCG(MD12) on (E3) */
+ ldr x1, =RST_MODEMR
+ ldr w1, [x1]
+ and w1, w1, #MODEMR_MD12
+ mov w2, #MODEMR_MD12
+ cmp w1, w2
+ bne 4f
+
+ /* When SSCG(MD12) on (E3) */
+ mov w1, #SCBRR_115200BPS_E3_SSCG
+ b 2f
+5:
+ /* In case of D3 */
+ ldr x1, =RST_MODEMR
+ ldr w1, [x1]
+ and w1, w1, #MODEMR_MD12
+ mov w2, #MODEMR_MD12
+ cmp w1, w2
+ bne 4f
+
+ /* When SSCG(MD12) on (D3) */
+ mov w1, #SCBRR_115200BPS_D3_SSCG
+ b 2f
+4:
+ /* In case of H3/M3/M3N or when SSCG(MD12) is off in E3/D3 */
+ mov w1, #SCBRR_115200BPS
+ 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
+
+ /*
+ * void console_rcar_flush(void)
+ * Function to force a write of all buffered
+ * data that hasn't been output. It returns void
+ * 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]
+
+ ret
+endfunc console_rcar_flush
diff --git a/drivers/renesas/common/watchdog/swdt.c b/drivers/renesas/common/watchdog/swdt.c
new file mode 100644
index 0000000..29ef6f4
--- /dev/null
+++ b/drivers/renesas/common/watchdog/swdt.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+
+#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) && (RCAR_LSI != RCAR_D3) && (RCAR_LSI != RZ_G2E)
+ 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) || (RCAR_LSI == RZ_G2E)
+ mmio_write_32(SWDT_WTCNT, WTCNT_UPPER_BYTE | WTCNT_COUNT_7p81k);
+#elif (RCAR_LSI == RCAR_D3)
+ mmio_write_32(SWDT_WTCNT, WTCNT_UPPER_BYTE | WTCNT_COUNT_8p13k);
+#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, occurred address is %p\n", (void *)p);
+ panic();
+}
diff --git a/drivers/renesas/rcar/board/board.c b/drivers/renesas/rcar/board/board.c
new file mode 100644
index 0000000..dbbaed6
--- /dev/null
+++ b/drivers/renesas/rcar/board/board.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights
+ * reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#include <iic_dvfs.h>
+
+#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, 0x11U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
+#define SX_ID { 0x10U, 0x11U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
+#define SKP_ID { 0x10U, 0x10U, 0x20U, 0x21U, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
+#define SK_ID { 0x10U, 0x30U, 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;
+}
diff --git a/drivers/renesas/rcar/board/board.h b/drivers/renesas/rcar/board/board.h
new file mode 100644
index 0000000..51a8e30
--- /dev/null
+++ b/drivers/renesas/rcar/board/board.h
@@ -0,0 +1,37 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rcar/cpld/ulcb_cpld.c b/drivers/renesas/rcar/cpld/ulcb_cpld.c
new file mode 100644
index 0000000..5ffb2e1
--- /dev/null
+++ b/drivers/renesas/rcar/cpld/ulcb_cpld.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#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);
+}
diff --git a/drivers/renesas/rcar/cpld/ulcb_cpld.h b/drivers/renesas/rcar/cpld/ulcb_cpld.h
new file mode 100644
index 0000000..1616d71
--- /dev/null
+++ b/drivers/renesas/rcar/cpld/ulcb_cpld.h
@@ -0,0 +1,12 @@
+/*
+ * 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__ */
diff --git a/drivers/renesas/rcar/pfc/D3/pfc_init_d3.c b/drivers/renesas/rcar/pfc/D3/pfc_init_d3.c
new file mode 100644
index 0000000..aaa3b43
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/D3/pfc_init_d3.c
@@ -0,0 +1,667 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <lib/mmio.h>
+#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);
+}
diff --git a/drivers/renesas/rcar/pfc/D3/pfc_init_d3.h b/drivers/renesas/rcar/pfc/D3/pfc_init_d3.h
new file mode 100644
index 0000000..b7b1754
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/D3/pfc_init_d3.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rcar/pfc/E3/pfc_init_e3.c b/drivers/renesas/rcar/pfc/E3/pfc_init_e3.c
new file mode 100644
index 0000000..bd0048e
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/E3/pfc_init_e3.c
@@ -0,0 +1,651 @@
+/*
+ * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h> /* for uint32_t */
+#include <lib/mmio.h>
+#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);
+}
diff --git a/drivers/renesas/rcar/pfc/E3/pfc_init_e3.h b/drivers/renesas/rcar/pfc/E3/pfc_init_e3.h
new file mode 100644
index 0000000..647a937
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/E3/pfc_init_e3.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.c b/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.c
new file mode 100644
index 0000000..effdc76
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.c
@@ -0,0 +1,1183 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <lib/mmio.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_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);
+}
diff --git a/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.h b/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.h
new file mode 100644
index 0000000..2478e1c
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.c b/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.c
new file mode 100644
index 0000000..a54b14b
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.c
@@ -0,0 +1,1216 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h> /* for uint32_t */
+#include <lib/mmio.h>
+#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);
+}
diff --git a/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.h b/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.h
new file mode 100644
index 0000000..b02f93e
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rcar/pfc/M3/pfc_init_m3.c b/drivers/renesas/rcar/pfc/M3/pfc_init_m3.c
new file mode 100644
index 0000000..7684c62
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/M3/pfc_init_m3.c
@@ -0,0 +1,1311 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h> /* for uint32_t */
+
+#include <lib/mmio.h>
+
+#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);
+}
diff --git a/drivers/renesas/rcar/pfc/M3/pfc_init_m3.h b/drivers/renesas/rcar/pfc/M3/pfc_init_m3.h
new file mode 100644
index 0000000..70885de
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/M3/pfc_init_m3.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.c b/drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.c
new file mode 100644
index 0000000..5014556
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.c
@@ -0,0 +1,1218 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h> /* for uint32_t */
+
+#include <lib/mmio.h>
+
+#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);
+}
diff --git a/drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.h b/drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.h
new file mode 100644
index 0000000..3e6f879
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c b/drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c
new file mode 100644
index 0000000..6063758
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c
@@ -0,0 +1,906 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h> /* for uint32_t */
+#include <lib/mmio.h>
+#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);
+}
diff --git a/drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.h b/drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.h
new file mode 100644
index 0000000..7bab92f
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.h
@@ -0,0 +1,13 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rcar/pfc/pfc.mk b/drivers/renesas/rcar/pfc/pfc.mk
new file mode 100644
index 0000000..f1dd92c
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/pfc.mk
@@ -0,0 +1,69 @@
+#
+# 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
diff --git a/drivers/renesas/rcar/pfc/pfc_init.c b/drivers/renesas/rcar/pfc/pfc_init.c
new file mode 100644
index 0000000..8810667
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/pfc_init.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#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
+}
diff --git a/drivers/renesas/rcar/qos/D3/qos_init_d3.c b/drivers/renesas/rcar/qos/D3/qos_init_d3.c
new file mode 100644
index 0000000..b96e822
--- /dev/null
+++ b/drivers/renesas/rcar/qos/D3/qos_init_d3.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#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) */
+}
diff --git a/drivers/renesas/rcar/qos/D3/qos_init_d3.h b/drivers/renesas/rcar/qos/D3/qos_init_d3.h
new file mode 100644
index 0000000..968ee7a
--- /dev/null
+++ b/drivers/renesas/rcar/qos/D3/qos_init_d3.h
@@ -0,0 +1,13 @@
+/*
+ * 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__ */
diff --git a/drivers/renesas/rcar/qos/D3/qos_init_d3_mstat.h b/drivers/renesas/rcar/qos/D3/qos_init_d3_mstat.h
new file mode 100644
index 0000000..cbf1f65
--- /dev/null
+++ b/drivers/renesas/rcar/qos/D3/qos_init_d3_mstat.h
@@ -0,0 +1,244 @@
+/*
+ * 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
+
diff --git a/drivers/renesas/rcar/qos/E3/qos_init_e3_v10.c b/drivers/renesas/rcar/qos/E3/qos_init_e3_v10.c
new file mode 100644
index 0000000..6f4c66c
--- /dev/null
+++ b/drivers/renesas/rcar/qos/E3/qos_init_e3_v10.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#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
+}
diff --git a/drivers/renesas/rcar/qos/E3/qos_init_e3_v10.h b/drivers/renesas/rcar/qos/E3/qos_init_e3_v10.h
new file mode 100644
index 0000000..2c1d8c5
--- /dev/null
+++ b/drivers/renesas/rcar/qos/E3/qos_init_e3_v10.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rcar/qos/E3/qos_init_e3_v10_mstat390.h b/drivers/renesas/rcar/qos/E3/qos_init_e3_v10_mstat390.h
new file mode 100644
index 0000000..d7f9d14
--- /dev/null
+++ b/drivers/renesas/rcar/qos/E3/qos_init_e3_v10_mstat390.h
@@ -0,0 +1,241 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/E3/qos_init_e3_v10_mstat780.h b/drivers/renesas/rcar/qos/E3/qos_init_e3_v10_mstat780.h
new file mode 100644
index 0000000..439cafe
--- /dev/null
+++ b/drivers/renesas/rcar/qos/E3/qos_init_e3_v10_mstat780.h
@@ -0,0 +1,241 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v10.c b/drivers/renesas/rcar/qos/H3/qos_init_h3_v10.c
new file mode 100644
index 0000000..1fb43a7
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v10.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#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) */
+}
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v10.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v10.h
new file mode 100644
index 0000000..f96182a
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v10.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v10_mstat.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v10_mstat.h
new file mode 100644
index 0000000..fe63236
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v10_mstat.h
@@ -0,0 +1,221 @@
+/*
+ * 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
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v11.c b/drivers/renesas/rcar/qos/H3/qos_init_h3_v11.c
new file mode 100644
index 0000000..329bcb8
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v11.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include <rcar_def.h>
+
+#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) */
+}
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v11.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v11.h
new file mode 100644
index 0000000..3faeb4f
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v11.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v11_mstat.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v11_mstat.h
new file mode 100644
index 0000000..46c68c8
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v11_mstat.h
@@ -0,0 +1,221 @@
+/*
+ * 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
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v20.c b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20.c
new file mode 100644
index 0000000..c20ab08
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#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) */
+}
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v20.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20.h
new file mode 100644
index 0000000..9b7619e
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_mstat195.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_mstat195.h
new file mode 100644
index 0000000..3995df3
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_mstat195.h
@@ -0,0 +1,231 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_mstat390.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_mstat390.h
new file mode 100644
index 0000000..770c022
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_mstat390.h
@@ -0,0 +1,231 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_qoswt195.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_qoswt195.h
new file mode 100644
index 0000000..82e4b01
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_qoswt195.h
@@ -0,0 +1,231 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_qoswt390.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_qoswt390.h
new file mode 100644
index 0000000..f3e7360
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_qoswt390.h
@@ -0,0 +1,231 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v30.c b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30.c
new file mode 100644
index 0000000..1fe6182
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#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) */
+}
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v30.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30.h
new file mode 100644
index 0000000..d33b43c
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_mstat195.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_mstat195.h
new file mode 100644
index 0000000..28a240f
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_mstat195.h
@@ -0,0 +1,231 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_mstat390.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_mstat390.h
new file mode 100644
index 0000000..def6585
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_mstat390.h
@@ -0,0 +1,231 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_qoswt195.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_qoswt195.h
new file mode 100644
index 0000000..b0c11cc
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_qoswt195.h
@@ -0,0 +1,231 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_qoswt390.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_qoswt390.h
new file mode 100644
index 0000000..a1e4c72
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_qoswt390.h
@@ -0,0 +1,231 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.c b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.c
new file mode 100644
index 0000000..f1ee41b
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#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) */
+}
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.h b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.h
new file mode 100644
index 0000000..46f3440
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_mstat195.h b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_mstat195.h
new file mode 100644
index 0000000..6dbc88a
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_mstat195.h
@@ -0,0 +1,231 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_mstat390.h b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_mstat390.h
new file mode 100644
index 0000000..880211c
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_mstat390.h
@@ -0,0 +1,231 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_qoswt195.h b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_qoswt195.h
new file mode 100644
index 0000000..affd013
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_qoswt195.h
@@ -0,0 +1,231 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_qoswt390.h b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_qoswt390.h
new file mode 100644
index 0000000..1c48d28
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_qoswt390.h
@@ -0,0 +1,231 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v10.c b/drivers/renesas/rcar/qos/M3/qos_init_m3_v10.c
new file mode 100644
index 0000000..a8264cb
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v10.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#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) */
+}
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v10.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v10.h
new file mode 100644
index 0000000..01ef46c
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v10.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v10_mstat.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v10_mstat.h
new file mode 100644
index 0000000..b78b5f1
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v10_mstat.h
@@ -0,0 +1,227 @@
+/*
+ * 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
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v11.c b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11.c
new file mode 100644
index 0000000..22fd83a
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2017-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#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) */
+}
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v11.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11.h
new file mode 100644
index 0000000..1552fb6
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_mstat195.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_mstat195.h
new file mode 100644
index 0000000..d7e7777
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_mstat195.h
@@ -0,0 +1,225 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_mstat390.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_mstat390.h
new file mode 100644
index 0000000..a9520c3
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_mstat390.h
@@ -0,0 +1,225 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_qoswt195.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_qoswt195.h
new file mode 100644
index 0000000..04c7efd
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_qoswt195.h
@@ -0,0 +1,225 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_qoswt390.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_qoswt390.h
new file mode 100644
index 0000000..73f81f5
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_qoswt390.h
@@ -0,0 +1,225 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v30.c b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30.c
new file mode 100644
index 0000000..43d21d7
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#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) */
+}
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v30.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30.h
new file mode 100644
index 0000000..a89d512
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30.h
@@ -0,0 +1,12 @@
+/*
+ * 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__ */
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_mstat195.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_mstat195.h
new file mode 100644
index 0000000..2ab14da
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_mstat195.h
@@ -0,0 +1,225 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_mstat390.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_mstat390.h
new file mode 100644
index 0000000..faac3d9
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_mstat390.h
@@ -0,0 +1,225 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_qoswt195.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_qoswt195.h
new file mode 100644
index 0000000..6761f5d
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_qoswt195.h
@@ -0,0 +1,225 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_qoswt390.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_qoswt390.h
new file mode 100644
index 0000000..1deed59
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_qoswt390.h
@@ -0,0 +1,225 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.c b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.c
new file mode 100644
index 0000000..446340b
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2017-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#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) */
+}
diff --git a/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.h b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.h
new file mode 100644
index 0000000..0cd0c85
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_mstat195.h b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_mstat195.h
new file mode 100644
index 0000000..9b8b9e9
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_mstat195.h
@@ -0,0 +1,241 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_mstat390.h b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_mstat390.h
new file mode 100644
index 0000000..19143ed
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_mstat390.h
@@ -0,0 +1,241 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_qoswt195.h b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_qoswt195.h
new file mode 100644
index 0000000..d2e8040
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_qoswt195.h
@@ -0,0 +1,241 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_qoswt390.h b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_qoswt390.h
new file mode 100644
index 0000000..84f657a
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_qoswt390.h
@@ -0,0 +1,241 @@
+/*
+ * 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,
+};
diff --git a/drivers/renesas/rcar/qos/V3M/qos_init_v3m.c b/drivers/renesas/rcar/qos/V3M/qos_init_v3m.c
new file mode 100644
index 0000000..076876c
--- /dev/null
+++ b/drivers/renesas/rcar/qos/V3M/qos_init_v3m.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#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) */
+}
diff --git a/drivers/renesas/rcar/qos/V3M/qos_init_v3m.h b/drivers/renesas/rcar/qos/V3M/qos_init_v3m.h
new file mode 100644
index 0000000..2c4278b
--- /dev/null
+++ b/drivers/renesas/rcar/qos/V3M/qos_init_v3m.h
@@ -0,0 +1,13 @@
+/*
+ * 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__ */
diff --git a/drivers/renesas/rcar/qos/V3M/qos_init_v3m_mstat.h b/drivers/renesas/rcar/qos/V3M/qos_init_v3m_mstat.h
new file mode 100644
index 0000000..d0b7fc3
--- /dev/null
+++ b/drivers/renesas/rcar/qos/V3M/qos_init_v3m_mstat.h
@@ -0,0 +1,98 @@
+/*
+ * 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
diff --git a/drivers/renesas/rcar/qos/qos.mk b/drivers/renesas/rcar/qos/qos.mk
new file mode 100644
index 0000000..da10da2
--- /dev/null
+++ b/drivers/renesas/rcar/qos/qos.mk
@@ -0,0 +1,106 @@
+#
+# 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
diff --git a/drivers/renesas/rcar/qos/qos_common.h b/drivers/renesas/rcar/qos/qos_common.h
new file mode 100644
index 0000000..2c130ae
--- /dev/null
+++ b/drivers/renesas/rcar/qos/qos_common.h
@@ -0,0 +1,142 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rcar/qos/qos_init.c b/drivers/renesas/rcar/qos/qos_init.c
new file mode 100644
index 0000000..d0f1730
--- /dev/null
+++ b/drivers/renesas/rcar/qos/qos_init.c
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#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);
+}
diff --git a/drivers/renesas/rcar/qos/qos_init.h b/drivers/renesas/rcar/qos/qos_init.h
new file mode 100644
index 0000000..1b64992
--- /dev/null
+++ b/drivers/renesas/rcar/qos/qos_init.h
@@ -0,0 +1,13 @@
+/*
+ * 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 */
diff --git a/drivers/renesas/rzg/board/board.c b/drivers/renesas/rzg/board/board.c
new file mode 100644
index 0000000..7636372
--- /dev/null
+++ b/drivers/renesas/rzg/board/board.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2020-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include "board.h"
+#include "rcar_def.h"
+
+#ifndef BOARD_DEFAULT
+#if (RCAR_LSI == RZ_G2H)
+#define BOARD_DEFAULT (BOARD_HIHOPE_RZ_G2H << BOARD_CODE_SHIFT)
+#elif (RCAR_LSI == RZ_G2N)
+#define BOARD_DEFAULT (BOARD_HIHOPE_RZ_G2N << BOARD_CODE_SHIFT)
+#elif (RCAR_LSI == RZ_G2E)
+#define BOARD_DEFAULT (BOARD_EK874_RZ_G2E << BOARD_CODE_SHIFT)
+#else
+#define BOARD_DEFAULT (BOARD_HIHOPE_RZ_G2M << BOARD_CODE_SHIFT)
+#endif /* RCAR_LSI == RZ_G2H */
+#endif /* BOARD_DEFAULT */
+
+#define BOARD_CODE_MASK (0xF8U)
+#define BOARD_REV_MASK (0x07U)
+#define BOARD_CODE_SHIFT (0x03)
+#define BOARD_ID_UNKNOWN (0xFFU)
+
+#define GPIO_INDT5 0xE605500C
+#define GP5_19_BIT (0x01U << 19)
+#define GP5_21_BIT (0x01U << 21)
+#define GP5_25_BIT (0x01U << 25)
+
+#define HM_ID { 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
+#define HH_ID HM_ID
+#define HN_ID { 0x20U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
+#define EK_ID HM_ID
+
+const char *g_board_tbl[] = {
+ [BOARD_HIHOPE_RZ_G2M] = "HiHope RZ/G2M",
+ [BOARD_HIHOPE_RZ_G2H] = "HiHope RZ/G2H",
+ [BOARD_HIHOPE_RZ_G2N] = "HiHope RZ/G2N",
+ [BOARD_EK874_RZ_G2E] = "EK874 RZ/G2E",
+ [BOARD_UNKNOWN] = "unknown"
+};
+
+void rzg_get_board_type(uint32_t *type, uint32_t *rev)
+{
+ static uint8_t board_id = BOARD_ID_UNKNOWN;
+ const uint8_t board_tbl[][8] = {
+ [BOARD_HIHOPE_RZ_G2M] = HM_ID,
+ [BOARD_HIHOPE_RZ_G2H] = HH_ID,
+ [BOARD_HIHOPE_RZ_G2N] = HN_ID,
+ [BOARD_EK874_RZ_G2E] = EK_ID,
+ };
+ uint32_t reg;
+#if (RCAR_LSI != RZ_G2E)
+ uint32_t boardInfo;
+#endif /* RCAR_LSI == RZ_G2E */
+
+ if (board_id == BOARD_ID_UNKNOWN) {
+ board_id = BOARD_DEFAULT;
+ }
+
+ *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;
+ }
+
+ reg = mmio_read_32(RCAR_PRR);
+#if (RCAR_LSI == RZ_G2E)
+ if (reg & RCAR_MINOR_MASK) {
+ *rev = 0x30U;
+ } else {
+ *rev = board_tbl[*type][(uint8_t)(board_id & BOARD_REV_MASK)];
+ }
+#else
+ if ((reg & PRR_CUT_MASK) == RCAR_M3_CUT_VER11) {
+ *rev = board_tbl[*type][(uint8_t)(board_id & BOARD_REV_MASK)];
+ } else {
+ reg = mmio_read_32(GPIO_INDT5);
+ if (reg & GP5_25_BIT) {
+ *rev = board_tbl[*type][(uint8_t)(board_id & BOARD_REV_MASK)];
+ } else {
+ boardInfo = reg & (GP5_19_BIT | GP5_21_BIT);
+ *rev = (((boardInfo & GP5_19_BIT) >> 14) |
+ ((boardInfo & GP5_21_BIT) >> 17)) + 0x30U;
+ }
+ }
+#endif /* RCAR_LSI == RZ_G2E */
+}
diff --git a/drivers/renesas/rzg/board/board.h b/drivers/renesas/rzg/board/board.h
new file mode 100644
index 0000000..1a76849
--- /dev/null
+++ b/drivers/renesas/rzg/board/board.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RZ_G2_BOARD_H
+#define RZ_G2_BOARD_H
+
+enum rzg2_board_id {
+ BOARD_HIHOPE_RZ_G2M = 0,
+ BOARD_HIHOPE_RZ_G2H,
+ BOARD_HIHOPE_RZ_G2N,
+ BOARD_EK874_RZ_G2E,
+ BOARD_UNKNOWN
+};
+
+#define BOARD_REV_UNKNOWN (0xFFU)
+
+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)])
+
+void rzg_get_board_type(uint32_t *type, uint32_t *rev);
+
+#endif /* RZ_G2_BOARD_H */
diff --git a/drivers/renesas/rzg/pfc/G2E/pfc_init_g2e.c b/drivers/renesas/rzg/pfc/G2E/pfc_init_g2e.c
new file mode 100644
index 0000000..663df50
--- /dev/null
+++ b/drivers/renesas/rzg/pfc/G2E/pfc_init_g2e.c
@@ -0,0 +1,700 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <lib/mmio.h>
+
+#include "pfc_init_g2e.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_g2e(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_C |
+ MOD_SEL1_HSCIF4_B |
+ 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(2) | /* HRX4_B */
+ IPSR_24_FUNC(2) | /* HTX4_B */
+ 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(2) | /* HRX3_C */
+ IPSR_0_FUNC(2)); /* HTX3_C */
+
+ 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(1) | /* CANFD1_RX */
+ IPSR_12_FUNC(5) | /* DU_DR6 */
+ IPSR_8_FUNC(5) | /* DU_DR5 */
+ IPSR_4_FUNC(1) | /* CANFD1_TX */
+ 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(1) | /* CAN_CLK */
+ IPSR_8_FUNC(1) | /* CANFD0_RX */
+ IPSR_4_FUNC(1) | /* CANFD0_TX */
+ 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_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(8) | /* USB0_ID */
+ IPSR_20_FUNC(2) | /* AUDIO_CLKOUT1_A */
+ IPSR_16_FUNC(0) | /* CTS0#_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(0) | /* SCK2_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(4) | /* SDA1_B */
+ IPSR_12_FUNC(4) | /* SCL1_B */
+ IPSR_8_FUNC(0) | /* SSI_SDATA9 */
+ IPSR_4_FUNC(1) | /* HTX2_A */
+ IPSR_0_FUNC(1)); /* HRX2_A */
+
+ pfc_reg_write(PFC_IPSR14,
+ IPSR_28_FUNC(0) | /* SSI_SCK5 */
+ 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(3) | /* TPU0TO1 */
+ IPSR_4_FUNC(3) | /* TPU0TO0 */
+ IPSR_0_FUNC(0)); /* SSI_WS5 */
+
+ /* initialize GPIO/peripheral function select */
+ pfc_reg_write(PFC_GPSR0,
+ GPSR0_SCL4 |
+ GPSR0_D15 |
+ GPSR0_D14 |
+ GPSR0_D13 |
+ GPSR0_D12 |
+ GPSR0_D11 |
+ GPSR0_D10 |
+ GPSR0_D9 |
+ GPSR0_D8 |
+ GPSR0_D7 |
+ GPSR0_D6 |
+ GPSR0_D5 |
+ GPSR0_D4 |
+ 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_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_IO3 |
+ GPSR2_QSPI1_IO2 |
+ GPSR2_QSPI1_MISO_IO1 |
+ GPSR2_QSPI1_MOSI_IO0 |
+ 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_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_DAT3 |
+ GPSR4_SD3_DAT2 |
+ GPSR4_SD3_DAT1 |
+ GPSR4_SD3_DAT0 |
+ GPSR4_SD3_CMD |
+ GPSR4_SD3_CLK);
+
+ pfc_reg_write(PFC_GPSR5,
+ GPSR5_MLB_SIG |
+ GPSR5_MLB_CLK |
+ GPSR5_SSI_SDATA9 |
+ GPSR5_MSIOF0_SS2 |
+ GPSR5_MSIOF0_SS1 |
+ GPSR5_MSIOF0_SYNC |
+ GPSR5_MSIOF0_TXD |
+ GPSR5_MSIOF0_RXD |
+ GPSR5_MSIOF0_SCK |
+ GPSR5_RX2_A |
+ GPSR5_TX2_A |
+ GPSR5_RTS0_A |
+ GPSR5_SCK0_A);
+
+ pfc_reg_write(PFC_GPSR6,
+ GPSR6_USB30_PWEN |
+ GPSR6_SSI_SDATA6 |
+ GPSR6_SSI_WS6 |
+ GPSR6_SSI_SCK6 |
+ GPSR6_SSI_SDATA5 |
+ GPSR6_SSI_SCK5 |
+ GPSR6_SSI_SDATA4 |
+ GPSR6_USB30_OVC |
+ GPSR6_AUDIO_CLKA |
+ GPSR6_SSI_SDATA3 |
+ GPSR6_SSI_WS349 |
+ GPSR6_SSI_SCK349 |
+ 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) & ~POC2_VREF_33V);
+ pfc_reg_write(PFC_POCCTRL2, reg);
+
+ /* initialize LSI pin pull-up/down control */
+ pfc_reg_write(PFC_PUD0, 0x00080000U);
+ pfc_reg_write(PFC_PUD1, 0xCE398464U);
+ 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, 0x00000000U);
+ pfc_reg_write(PFC_PUEN1, 0x00300000U);
+ pfc_reg_write(PFC_PUEN2, 0x00400074U);
+ pfc_reg_write(PFC_PUEN3, 0x00000000U);
+ pfc_reg_write(PFC_PUEN4, 0x07900600U);
+ 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, 0x00000000U);
+ mmio_write_32(GPIO_OUTDT3, 0x00006000U);
+ mmio_write_32(GPIO_OUTDT5, 0x00000000U);
+ mmio_write_32(GPIO_OUTDT6, 0x00000000U);
+
+ /* initialize general input/output switching */
+ mmio_write_32(GPIO_INOUTSEL0, 0x00020000U);
+ mmio_write_32(GPIO_INOUTSEL1, 0x00100000U);
+ mmio_write_32(GPIO_INOUTSEL2, 0x03000000U);
+ mmio_write_32(GPIO_INOUTSEL3, 0x0000E000U);
+ mmio_write_32(GPIO_INOUTSEL4, 0x00000440U);
+ mmio_write_32(GPIO_INOUTSEL5, 0x00080000U);
+ mmio_write_32(GPIO_INOUTSEL6, 0x00000010U);
+}
diff --git a/drivers/renesas/rzg/pfc/G2E/pfc_init_g2e.h b/drivers/renesas/rzg/pfc/G2E/pfc_init_g2e.h
new file mode 100644
index 0000000..677591a
--- /dev/null
+++ b/drivers/renesas/rzg/pfc/G2E/pfc_init_g2e.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PFC_INIT_G2E_H
+#define PFC_INIT_G2E_H
+
+void pfc_init_g2e(void);
+
+#endif /* PFC_INIT_G2E_H */
diff --git a/drivers/renesas/rzg/pfc/G2H/pfc_init_g2h.c b/drivers/renesas/rzg/pfc/G2H/pfc_init_g2h.c
new file mode 100644
index 0000000..90a1c99
--- /dev/null
+++ b/drivers/renesas/rzg/pfc/G2H/pfc_init_g2h.c
@@ -0,0 +1,1310 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <lib/mmio.h>
+
+#include "pfc_init_g2h.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_g2h(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_B |
+ MOD_SEL2_I2C_3_B |
+ MOD_SEL2_I2C_0_B |
+ 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_12_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(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(0));
+
+ 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/peripheral function select */
+ pfc_reg_write(PFC_GPSR0,
+ GPSR0_D15 |
+ GPSR0_D14 |
+ GPSR0_D13 |
+ GPSR0_D12 |
+ GPSR0_D11 |
+ GPSR0_D10 |
+ GPSR0_D9 |
+ GPSR0_D8 |
+ GPSR0_D7 |
+ GPSR0_D6 |
+ GPSR0_D5 |
+ GPSR0_D4 |
+ GPSR0_D3 |
+ GPSR0_D2 |
+ GPSR0_D0);
+
+ pfc_reg_write(PFC_GPSR1,
+ GPSR1_CLKOUT |
+ GPSR1_EX_WAIT0_A |
+ GPSR1_WE1 |
+ GPSR1_RD |
+ GPSR1_RD_WR |
+ GPSR1_CS0 |
+ 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_IRQ4 |
+ GPSR2_IRQ3 |
+ GPSR2_IRQ2 |
+ GPSR2_IRQ1 |
+ GPSR2_IRQ0);
+
+ pfc_reg_write(PFC_GPSR3,
+ 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_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 |
+ 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_RXD |
+ GPSR5_MSIOF0_TXD |
+ GPSR5_MSIOF0_SYNC |
+ GPSR5_MSIOF0_SCK |
+ GPSR5_RX2_A |
+ GPSR5_TX2_A |
+ GPSR5_RTS1 |
+ GPSR5_CTS1 |
+ GPSR5_TX1_A |
+ GPSR5_RX1_A |
+ GPSR5_RTS0 |
+ GPSR5_SCK0);
+
+ pfc_reg_write(PFC_GPSR6,
+ GPSR6_AUDIO_CLKB_B |
+ GPSR6_AUDIO_CLKA_A |
+ 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_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, 0x00300EFEU);
+ 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_OUTDT0, 0x00000001U);
+ 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, 0x00000000U);
+ mmio_write_32(GPIO_OUTDT6, 0x00003800U);
+ mmio_write_32(GPIO_OUTDT7, 0x00000003U);
+
+ /* initialize general input/output switching */
+ mmio_write_32(GPIO_INOUTSEL0, 0x00000001U);
+ mmio_write_32(GPIO_INOUTSEL1, 0x00100B00U);
+ mmio_write_32(GPIO_INOUTSEL2, 0x00000418U);
+ mmio_write_32(GPIO_INOUTSEL3, 0x00002000U);
+ mmio_write_32(GPIO_INOUTSEL4, 0x00000040U);
+ mmio_write_32(GPIO_INOUTSEL5, 0x00000208U);
+ mmio_write_32(GPIO_INOUTSEL6, 0x00013F00U);
+ mmio_write_32(GPIO_INOUTSEL7, 0x00000003U);
+}
diff --git a/drivers/renesas/rzg/pfc/G2H/pfc_init_g2h.h b/drivers/renesas/rzg/pfc/G2H/pfc_init_g2h.h
new file mode 100644
index 0000000..5efce45
--- /dev/null
+++ b/drivers/renesas/rzg/pfc/G2H/pfc_init_g2h.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PFC_INIT_G2H_H
+#define PFC_INIT_G2H_H
+
+void pfc_init_g2h(void);
+
+#endif /* PFC_INIT_G2H_H */
diff --git a/drivers/renesas/rzg/pfc/G2M/pfc_init_g2m.c b/drivers/renesas/rzg/pfc/G2M/pfc_init_g2m.c
new file mode 100644
index 0000000..f76b83f
--- /dev/null
+++ b/drivers/renesas/rzg/pfc/G2M/pfc_init_g2m.c
@@ -0,0 +1,1300 @@
+/*
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h> /* for uint32_t */
+
+#include <lib/mmio.h>
+
+#include "pfc_init_g2m.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_g2m(void)
+{
+ uint32_t reg;
+
+ /*
+ * PFC write access problem seen on older SoC's. Added a workaround
+ * in RT-DMAC for fixing the same.
+ */
+ 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_B
+ | MOD_SEL2_I2C_3_B
+ | MOD_SEL2_I2C_0_B
+ | 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_12_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(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(0));
+ 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
+ | GPSR0_D7
+ | GPSR0_D6
+ | GPSR0_D5
+ | GPSR0_D4
+ | GPSR0_D3
+ | GPSR0_D2
+ | GPSR0_D0);
+ pfc_reg_write(PFC_GPSR1, GPSR1_CLKOUT
+ | GPSR1_EX_WAIT0_A
+ | GPSR1_WE1
+ | GPSR1_RD
+ | GPSR1_RD_WR
+ | GPSR1_CS0
+ | 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_IRQ4
+ | GPSR2_IRQ3
+ | GPSR2_IRQ2
+ | GPSR2_IRQ1
+ | GPSR2_IRQ0);
+ pfc_reg_write(PFC_GPSR3, 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_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
+ | 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_RXD
+ | GPSR5_MSIOF0_TXD
+ | GPSR5_MSIOF0_SYNC
+ | GPSR5_MSIOF0_SCK
+ | GPSR5_RX2_A
+ | GPSR5_TX2_A
+ | GPSR5_RTS1
+ | GPSR5_CTS1
+ | GPSR5_TX1_A
+ | GPSR5_RX1_A
+ | GPSR5_RTS0
+ | GPSR5_SCK0);
+ pfc_reg_write(PFC_GPSR6, GPSR6_AUDIO_CLKB_B
+ | GPSR6_AUDIO_CLKA_A
+ | 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_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, 0x00300EFEU);
+ 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_OUTDT0, 0x00000001U);
+ 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, 0x00000000U);
+ mmio_write_32(GPIO_OUTDT6, 0x00003800U);
+ mmio_write_32(GPIO_OUTDT7, 0x00000003U);
+
+ /* initialize general input/output switching */
+ mmio_write_32(GPIO_INOUTSEL0, 0x00000001U);
+ mmio_write_32(GPIO_INOUTSEL1, 0x00100B00U);
+ mmio_write_32(GPIO_INOUTSEL2, 0x00000418U);
+ mmio_write_32(GPIO_INOUTSEL3, 0x00002000U);
+ mmio_write_32(GPIO_INOUTSEL4, 0x00000040U);
+ mmio_write_32(GPIO_INOUTSEL5, 0x00000208U);
+ mmio_write_32(GPIO_INOUTSEL6, 0x00013F00U);
+ mmio_write_32(GPIO_INOUTSEL7, 0x00000003U);
+
+}
diff --git a/drivers/renesas/rzg/pfc/G2M/pfc_init_g2m.h b/drivers/renesas/rzg/pfc/G2M/pfc_init_g2m.h
new file mode 100644
index 0000000..3315cd6
--- /dev/null
+++ b/drivers/renesas/rzg/pfc/G2M/pfc_init_g2m.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PFC_INIT_G2M_H
+#define PFC_INIT_G2M_H
+
+void pfc_init_g2m(void);
+
+#endif /* PFC_INIT_G2M_H */
diff --git a/drivers/renesas/rzg/pfc/G2N/pfc_init_g2n.c b/drivers/renesas/rzg/pfc/G2N/pfc_init_g2n.c
new file mode 100644
index 0000000..c951e0a
--- /dev/null
+++ b/drivers/renesas/rzg/pfc/G2N/pfc_init_g2n.c
@@ -0,0 +1,1306 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <lib/mmio.h>
+
+#include "pfc_init_g2n.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_g2n(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_B |
+ MOD_SEL2_I2C_3_B |
+ MOD_SEL2_I2C_0_B |
+ 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_12_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(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(0));
+
+ 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/peripheral function select */
+ pfc_reg_write(PFC_GPSR0,
+ GPSR0_D15 |
+ GPSR0_D14 |
+ GPSR0_D13 |
+ GPSR0_D12 |
+ GPSR0_D11 |
+ GPSR0_D10 |
+ GPSR0_D9 |
+ GPSR0_D8 |
+ GPSR0_D7 |
+ GPSR0_D6 |
+ GPSR0_D5 |
+ GPSR0_D4 |
+ GPSR0_D3 |
+ GPSR0_D2 |
+ GPSR0_D0);
+
+ pfc_reg_write(PFC_GPSR1,
+ GPSR1_CLKOUT |
+ GPSR1_EX_WAIT0_A |
+ GPSR1_WE1 |
+ GPSR1_RD |
+ GPSR1_RD_WR |
+ GPSR1_CS0 |
+ 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_IRQ4 |
+ GPSR2_IRQ3 |
+ GPSR2_IRQ2 |
+ GPSR2_IRQ1 |
+ GPSR2_IRQ0);
+
+ pfc_reg_write(PFC_GPSR3,
+ 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_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 |
+ 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_RXD |
+ GPSR5_MSIOF0_TXD |
+ GPSR5_MSIOF0_SYNC |
+ GPSR5_MSIOF0_SCK |
+ GPSR5_RX2_A |
+ GPSR5_TX2_A |
+ GPSR5_RTS1 |
+ GPSR5_CTS1 |
+ GPSR5_TX1_A |
+ GPSR5_RX1_A |
+ GPSR5_RTS0 |
+ GPSR5_SCK0);
+
+ pfc_reg_write(PFC_GPSR6,
+ GPSR6_AUDIO_CLKB_B |
+ GPSR6_AUDIO_CLKA_A |
+ 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_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, 0x00300EFEU);
+ 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_OUTDT0, 0x00000001U);
+ 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, 0x00000000U);
+ mmio_write_32(GPIO_OUTDT6, 0x00003800U);
+ mmio_write_32(GPIO_OUTDT7, 0x00000003U);
+
+ /* initialize general input/output switching */
+ mmio_write_32(GPIO_INOUTSEL0, 0x00000001U);
+ mmio_write_32(GPIO_INOUTSEL1, 0x00100B00U);
+ mmio_write_32(GPIO_INOUTSEL2, 0x00000418U);
+ mmio_write_32(GPIO_INOUTSEL3, 0x00002000U);
+ mmio_write_32(GPIO_INOUTSEL4, 0x00000040U);
+ mmio_write_32(GPIO_INOUTSEL5, 0x00000208U);
+ mmio_write_32(GPIO_INOUTSEL6, 0x00013F00U);
+ mmio_write_32(GPIO_INOUTSEL7, 0x00000003U);
+}
diff --git a/drivers/renesas/rzg/pfc/G2N/pfc_init_g2n.h b/drivers/renesas/rzg/pfc/G2N/pfc_init_g2n.h
new file mode 100644
index 0000000..f0616b6
--- /dev/null
+++ b/drivers/renesas/rzg/pfc/G2N/pfc_init_g2n.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PFC_INIT_G2N_H
+#define PFC_INIT_G2N_H
+
+void pfc_init_g2n(void);
+
+#endif /* PFC_INIT_G2N_H */
diff --git a/drivers/renesas/rzg/pfc/pfc.mk b/drivers/renesas/rzg/pfc/pfc.mk
new file mode 100644
index 0000000..15d0e8d
--- /dev/null
+++ b/drivers/renesas/rzg/pfc/pfc.mk
@@ -0,0 +1,41 @@
+#
+# Copyright (c) 2020-2021, Renesas Electronics Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${RCAR_LSI},${RCAR_AUTO})
+ BL2_SOURCES += drivers/renesas/rzg/pfc/G2M/pfc_init_g2m.c
+ BL2_SOURCES += drivers/renesas/rzg/pfc/G2H/pfc_init_g2h.c
+ BL2_SOURCES += drivers/renesas/rzg/pfc/G2N/pfc_init_g2n.c
+ BL2_SOURCES += drivers/renesas/rzg/pfc/G2E/pfc_init_g2e.c
+
+else ifdef RCAR_LSI_CUT_COMPAT
+ ifeq (${RCAR_LSI},${RZ_G2M})
+ BL2_SOURCES += drivers/renesas/rzg/pfc/G2M/pfc_init_g2m.c
+ endif
+ ifeq (${RCAR_LSI},${RZ_G2H})
+ BL2_SOURCES += drivers/renesas/rzg/pfc/G2H/pfc_init_g2h.c
+ endif
+ ifeq (${RCAR_LSI},${RZ_G2N})
+ BL2_SOURCES += drivers/renesas/rzg/pfc/G2N/pfc_init_g2n.c
+ endif
+ ifeq (${RCAR_LSI},${RZ_G2E})
+ BL2_SOURCES += drivers/renesas/rzg/pfc/G2E/pfc_init_g2e.c
+ endif
+else
+ ifeq (${RCAR_LSI},${RZ_G2M})
+ BL2_SOURCES += drivers/renesas/rzg/pfc/G2M/pfc_init_g2m.c
+ endif
+ ifeq (${RCAR_LSI},${RZ_G2H})
+ BL2_SOURCES += drivers/renesas/rzg/pfc/G2H/pfc_init_g2h.c
+ endif
+ ifeq (${RCAR_LSI},${RZ_G2N})
+ BL2_SOURCES += drivers/renesas/rzg/pfc/G2N/pfc_init_g2n.c
+ endif
+ ifeq (${RCAR_LSI},${RZ_G2E})
+ BL2_SOURCES += drivers/renesas/rzg/pfc/G2E/pfc_init_g2e.c
+ endif
+endif
+
+BL2_SOURCES += drivers/renesas/rzg/pfc/pfc_init.c
diff --git a/drivers/renesas/rzg/pfc/pfc_init.c b/drivers/renesas/rzg/pfc/pfc_init.c
new file mode 100644
index 0000000..762450c
--- /dev/null
+++ b/drivers/renesas/rzg/pfc/pfc_init.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2020-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#if RCAR_LSI == RCAR_AUTO
+#include "G2E/pfc_init_g2e.h"
+#include "G2H/pfc_init_g2h.h"
+#include "G2M/pfc_init_g2m.h"
+#include "G2N/pfc_init_g2n.h"
+#endif /* RCAR_LSI == RCAR_AUTO */
+#if (RCAR_LSI == RZ_G2E)
+#include "G2E/pfc_init_g2e.h"
+#endif /* RCAR_LSI == RZ_G2N */
+#if (RCAR_LSI == RZ_G2H)
+#include "G2H/pfc_init_g2h.h"
+#endif /* RCAR_LSI == RZ_G2H */
+#if (RCAR_LSI == RZ_G2M)
+#include "G2M/pfc_init_g2m.h"
+#endif /* RCAR_LSI == RZ_G2M */
+#if (RCAR_LSI == RZ_G2N)
+#include "G2N/pfc_init_g2n.h"
+#endif /* RCAR_LSI == RZ_G2N */
+#include "rcar_def.h"
+
+#define PRR_PRODUCT_ERR(reg) \
+ do { \
+ ERROR("LSI Product ID(PRR=0x%x) PFC init not supported.\n", \
+ reg); \
+ panic(); \
+ } while (0)
+
+#define PRR_CUT_ERR(reg) \
+ do { \
+ ERROR("LSI Cut ID(PRR=0x%x) PFC init not supported.\n", \
+ reg); \
+ panic();\
+ } while (0)
+
+void rzg_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_M3:
+ pfc_init_g2m();
+ break;
+ case PRR_PRODUCT_H3:
+ pfc_init_g2h();
+ break;
+ case PRR_PRODUCT_M3N:
+ pfc_init_g2n();
+ break;
+ case PRR_PRODUCT_E3:
+ pfc_init_g2e();
+ break;
+ default:
+ PRR_PRODUCT_ERR(reg);
+ break;
+ }
+
+#elif RCAR_LSI_CUT_COMPAT /* RCAR_LSI == RCAR_AUTO */
+ switch (reg & PRR_PRODUCT_MASK) {
+ case PRR_PRODUCT_M3:
+#if RCAR_LSI != RZ_G2M
+ PRR_PRODUCT_ERR(reg);
+#else /* RCAR_LSI != RZ_G2M */
+ pfc_init_g2m();
+#endif /* RCAR_LSI != RZ_G2M */
+ break;
+ case PRR_PRODUCT_H3:
+#if (RCAR_LSI != RZ_G2H)
+ PRR_PRODUCT_ERR(reg);
+#else /* RCAR_LSI != RZ_G2H */
+ pfc_init_g2h();
+#endif /* RCAR_LSI != RZ_G2H */
+ break;
+ case PRR_PRODUCT_M3N:
+#if RCAR_LSI != RZ_G2N
+ PRR_PRODUCT_ERR(reg);
+#else
+ pfc_init_g2n();
+#endif /* RCAR_LSI != RZ_G2N */
+ break;
+ case PRR_PRODUCT_E3:
+#if RCAR_LSI != RZ_G2E
+ PRR_PRODUCT_ERR(reg);
+#else
+ pfc_init_g2e();
+#endif
+ break;
+ default:
+ PRR_PRODUCT_ERR(reg);
+ break;
+ }
+
+#else /* RCAR_LSI == RCAR_AUTO */
+#if (RCAR_LSI == RZ_G2M)
+ if ((reg & PRR_PRODUCT_MASK) != PRR_PRODUCT_M3) {
+ PRR_PRODUCT_ERR(reg);
+ }
+ pfc_init_m3();
+#elif (RCAR_LSI == RZ_G2H)
+ if ((reg & PRR_PRODUCT_MASK) != PRR_PRODUCT_H3) {
+ PRR_PRODUCT_ERR(reg);
+ }
+ pfc_init_g2h();
+#elif (RCAR_LSI == RZ_G2N) /* G2N */
+ if ((reg & PRR_PRODUCT_MASK) != PRR_PRODUCT_M3N) {
+ PRR_PRODUCT_ERR(reg);
+ }
+ pfc_init_g2n();
+#elif (RCAR_LSI == RZ_G2E)
+ if ((reg & PRR_PRODUCT_MASK) != PRR_PRODUCT_E3) {
+ PRR_PRODUCT_ERR(reg);
+ }
+ pfc_init_g2e();
+#else /* RCAR_LSI == RZ_G2M */
+#error "Don't have PFC initialize routine(unknown)."
+#endif /* RCAR_LSI == RZ_G2M */
+#endif /* RCAR_LSI == RCAR_AUTO */
+}
diff --git a/drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10.c b/drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10.c
new file mode 100644
index 0000000..14ccc21
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "qos_init_g2e_v10.h"
+#include "../qos_common.h"
+#include "../qos_reg.h"
+
+#define RCAR_QOS_VERSION "rev.0.05"
+
+#define REF_ARS_ARBSTOPCYCLE_G2E (((SL_INIT_SSLOTCLK_G2E) - 5U) << 16U)
+
+#if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_g2e_v10_mstat390.h"
+#else
+#include "qos_init_g2e_v10_mstat780.h"
+#endif /* RCAR_REF_INT == RCAR_REF_DEFAULT */
+#endif /* RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT */
+
+static const struct rcar_gen3_dbsc_qos_settings g2e_qos[] = {
+ /* BUFCAM settings */
+ { DBSC_DBCAM0CNF1, 0x00043218U },
+ { DBSC_DBCAM0CNF2, 0x000000F4U },
+ { 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_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_g2e_v10(void)
+{
+ rzg_qos_dbsc_setting(g2e_qos, ARRAY_SIZE(g2e_qos), true);
+
+ /* DRAM Split Address mapping */
+#if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH
+#if RCAR_LSI == RCAR_RZ_G2E
+#error "Don't set DRAM Split 4ch(G2E)"
+#else
+ ERROR("DRAM Split 4ch not supported.(G2E)");
+ panic();
+#endif
+#elif (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH)
+#if RCAR_LSI == RCAR_RZ_G2E
+#error "Don't set DRAM Split 2ch(G2E)"
+#else
+ ERROR("DRAM Split 2ch not supported.(G2E)");
+ 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
+
+ mmio_write_32(QOSCTRL_RAS, 0x00000020U);
+ mmio_write_64(QOSCTRL_DANN, 0x0404020002020201UL);
+ mmio_write_32(QOSCTRL_DANT, 0x00100804U);
+ mmio_write_32(QOSCTRL_FSS, 0x0000000AU);
+ mmio_write_32(QOSCTRL_INSFC, 0x06330001U);
+ mmio_write_32(QOSCTRL_EARLYR, 0x00000000U);
+ mmio_write_32(QOSCTRL_RACNT0, 0x00010003U);
+
+ mmio_write_32(QOSCTRL_SL_INIT, SL_INIT_REFFSSLOT |
+ SL_INIT_SLOTSSLOT | SL_INIT_SSLOTCLK_G2E);
+ mmio_write_32(QOSCTRL_REF_ARS, REF_ARS_ARBSTOPCYCLE_G2E);
+
+ /* QOSBW SRAM setting */
+ uint32_t i;
+
+ for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) {
+ mmio_write_64(QOSBW_FIX_QOS_BANK0 + i * 8U, mstat_fix[i]);
+ mmio_write_64(QOSBW_FIX_QOS_BANK1 + i * 8U, mstat_fix[i]);
+ }
+ for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) {
+ mmio_write_64(QOSBW_BE_QOS_BANK0 + i * 8U, mstat_be[i]);
+ mmio_write_64(QOSBW_BE_QOS_BANK1 + i * 8U, mstat_be[i]);
+ }
+
+ /* RT bus Leaf setting */
+ mmio_write_32(RT_ACT0, 0x00000000U);
+ mmio_write_32(RT_ACT1, 0x00000000U);
+
+ /* CCI bus Leaf setting */
+ mmio_write_32(CPU_ACT0, 0x00000003U);
+ mmio_write_32(CPU_ACT1, 0x00000003U);
+
+ mmio_write_32(QOSCTRL_RAEN, 0x00000001U);
+
+ mmio_write_32(QOSCTRL_STATQC, 0x00000001U);
+#else
+ NOTICE("BL2: QoS is None\n");
+
+ mmio_write_32(QOSCTRL_RAEN, 0x00000001U);
+#endif
+}
diff --git a/drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10.h b/drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10.h
new file mode 100644
index 0000000..d27de1b
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2E_V10_H
+#define QOS_INIT_G2E_V10_H
+
+void qos_init_g2e_v10(void);
+
+#endif /* QOS_INIT_G2E_V10_H */
diff --git a/drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10_mstat390.h b/drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10_mstat390.h
new file mode 100644
index 0000000..63b08c4
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10_mstat390.h
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2E_V10_MSTAT390_H
+#define QOS_INIT_G2E_V10_MSTAT390_H
+
+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, */ 0x0000000000000000UL,
+ /* 0x00f8, */ 0x000C084F0000FFFFUL,
+ /* 0x0100, */ 0x0000000000000000UL,
+ /* 0x0108, */ 0x0000000000000000UL,
+ /* 0x0110, */ 0x0000000000000000UL,
+ /* 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, */ 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, */ 0x001410040000FFFFUL,
+ /* 0x0270, */ 0x001404020000FFFFUL,
+ /* 0x0278, */ 0x0000000000000000UL,
+ /* 0x0280, */ 0x0000000000000000UL,
+ /* 0x0288, */ 0x0000000000000000UL,
+ /* 0x0290, */ 0x001410040000FFFFUL,
+ /* 0x0298, */ 0x001404020000FFFFUL,
+ /* 0x02a0, */ 0x000C04090000FFFFUL,
+ /* 0x02a8, */ 0x000C04090000FFFFUL,
+ /* 0x02b0, */ 0x0000000000000000UL,
+ /* 0x02b8, */ 0x0000000000000000UL,
+ /* 0x02c0, */ 0x0000000000000000UL,
+ /* 0x02c8, */ 0x0000000000000000UL,
+ /* 0x02d0, */ 0x000C04090000FFFFUL,
+ /* 0x02d8, */ 0x000C04090000FFFFUL,
+ /* 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 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, */ 0x0000000000000000UL,
+ /* 0x01f8, */ 0x0000000000000000UL,
+ /* 0x0200, */ 0x0000000000000000UL,
+ /* 0x0208, */ 0x0000000000000000UL,
+ /* 0x0210, */ 0x0000000000000000UL,
+ /* 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,
+};
+#endif /* QOS_INIT_G2E_V10_MSTAT390_H */
diff --git a/drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10_mstat780.h b/drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10_mstat780.h
new file mode 100644
index 0000000..3b888ea
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10_mstat780.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2E_V10_MSTAT780_H
+#define QOS_INIT_G2E_V10_MSTAT780_H
+
+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,
+};
+
+#endif /* QOS_INIT_G2E_V10_MSTAT780_H */
diff --git a/drivers/renesas/rzg/qos/G2H/qos_init_g2h_mstat195.h b/drivers/renesas/rzg/qos/G2H/qos_init_g2h_mstat195.h
new file mode 100644
index 0000000..7bb34aa
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2H/qos_init_g2h_mstat195.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2H_MSTAT195_H
+#define QOS_INIT_G2H_MSTAT195_H
+
+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,
+};
+
+#endif /* QOS_INIT_G2H_MSTAT195_H */
diff --git a/drivers/renesas/rzg/qos/G2H/qos_init_g2h_mstat390.h b/drivers/renesas/rzg/qos/G2H/qos_init_g2h_mstat390.h
new file mode 100644
index 0000000..9696a40
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2H/qos_init_g2h_mstat390.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2H_MSTAT390_H
+#define QOS_INIT_G2H_MSTAT390_H
+
+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,
+};
+
+#endif /* QOS_INIT_G2H_MSTAT390_H */
diff --git a/drivers/renesas/rzg/qos/G2H/qos_init_g2h_qoswt195.h b/drivers/renesas/rzg/qos/G2H/qos_init_g2h_qoswt195.h
new file mode 100644
index 0000000..044f246
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2H/qos_init_g2h_qoswt195.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2H_QOSWT195_H
+#define QOS_INIT_G2H_QOSWT195_H
+
+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,
+};
+
+#endif /* QOS_INIT_G2H_QOSWT195_H */
diff --git a/drivers/renesas/rzg/qos/G2H/qos_init_g2h_qoswt390.h b/drivers/renesas/rzg/qos/G2H/qos_init_g2h_qoswt390.h
new file mode 100644
index 0000000..2ae07ab
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2H/qos_init_g2h_qoswt390.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2H_QOSWT390_H
+#define QOS_INIT_G2H_QOSWT390_H
+
+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,
+};
+
+#endif /* QOS_INIT_G2H_QOSWT390_H */
diff --git a/drivers/renesas/rzg/qos/G2H/qos_init_g2h_v30.c b/drivers/renesas/rzg/qos/G2H/qos_init_g2h_v30.c
new file mode 100644
index 0000000..7f466c8
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2H/qos_init_g2h_v30.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "qos_init_g2h_v30.h"
+#include "../qos_common.h"
+#include "../qos_reg.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_G2H (SL_INIT_SSLOTCLK_G2H - 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_G2H ((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_G2H) - 1U)
+#define QOSWT_WTSET0_SSLOT0 (QOSWT_WTSET0_REQ_SSLOT0 - 1U)
+#define QOSWT_WTSET0_SLOTSLOT0 (WT_BASE_SUB_SLOT_NUM0 - 1U)
+
+#define QOSWT_WTSET1_PERIOD1_G2H (QOSWT_WTSET0_PERIOD0_G2H)
+#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_g2h_mstat195.h"
+#else
+#include "qos_init_g2h_mstat390.h"
+#endif /* RCAR_REF_INT == RCAR_REF_DEFAULT */
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_g2h_qoswt195.h"
+#else
+#include "qos_init_g2h_qoswt390.h"
+#endif /* RCAR_REF_INT == RCAR_REF_DEFAULT */
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+#endif /* RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT */
+
+static const struct rcar_gen3_dbsc_qos_settings g2h_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_g2h_v30(void)
+{
+ unsigned int split_area;
+
+ rzg_qos_dbsc_setting(g2h_v30_qos, ARRAY_SIZE(g2h_v30_qos), true);
+
+ /* use 1(2GB) for RCAR_DRAM_LPDDR4_MEMCONF for G2H */
+ split_area = 0x1CU;
+
+ /* DRAM split address mapping */
+#if (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH)
+#if RCAR_LSI == RZ_G2H
+#error "Don't set DRAM Split 4ch(G2H)"
+#else /* RCAR_LSI == RZ_G2H */
+ ERROR("DRAM split 4ch not supported.(G2H)");
+ panic();
+#endif /* RCAR_LSI == RZ_G2H */
+#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);
+
+ mmio_write_32(AXI_ADSPLCR0, ADSPLCR0_AREA(split_area));
+ mmio_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT |
+ ADSPLCR0_SPLITSEL(0xFFU) | ADSPLCR0_AREA(split_area) |
+ ADSPLCR0_SWP);
+ mmio_write_32(AXI_ADSPLCR2, 0x00001004U);
+ mmio_write_32(AXI_ADSPLCR3, 0x00000000U);
+#else /* RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH */
+ mmio_write_32(AXI_ADSPLCR0, ADSPLCR0_AREA(split_area));
+ NOTICE("BL2: DRAM Split is OFF(DDR %x)\n", (int)qos_init_ddr_phyvalid);
+#endif /* RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH */
+
+#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 */
+
+ mmio_write_32(QOSCTRL_RAS, 0x00000044U);
+ mmio_write_64(QOSCTRL_DANN, 0x0404020002020201UL);
+ mmio_write_32(QOSCTRL_DANT, 0x0020100AU);
+ mmio_write_32(QOSCTRL_FSS, 0x0000000AU);
+ mmio_write_32(QOSCTRL_INSFC, 0x06330001U);
+ mmio_write_32(QOSCTRL_RACNT0, 0x00010003U);
+
+ /* GPU Boost Mode */
+ mmio_write_32(QOSCTRL_STATGEN0, 0x00000001U);
+
+ mmio_write_32(QOSCTRL_SL_INIT, SL_INIT_REFFSSLOT |
+ SL_INIT_SLOTSSLOT | SL_INIT_SSLOTCLK_G2H);
+ mmio_write_32(QOSCTRL_REF_ARS, ((QOSCTRL_REF_ARS_ARBSTOPCYCLE_G2H << 16)));
+
+ uint32_t i;
+
+ for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) {
+ mmio_write_64(QOSBW_FIX_QOS_BANK0 + i * 8U, mstat_fix[i]);
+ mmio_write_64(QOSBW_FIX_QOS_BANK1 + i * 8U, mstat_fix[i]);
+ }
+ for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) {
+ mmio_write_64(QOSBW_BE_QOS_BANK0 + i * 8U, mstat_be[i]);
+ mmio_write_64(QOSBW_BE_QOS_BANK1 + i * 8U, mstat_be[i]);
+ }
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+ for (i = 0U; i < ARRAY_SIZE(qoswt_fix); i++) {
+ mmio_write_64(QOSWT_FIX_WTQOS_BANK0 + i * 8U, qoswt_fix[i]);
+ mmio_write_64(QOSWT_FIX_WTQOS_BANK1 + i * 8U, qoswt_fix[i]);
+ }
+ for (i = 0U; i < ARRAY_SIZE(qoswt_be); i++) {
+ mmio_write_64(QOSWT_BE_WTQOS_BANK0 + i * 8U, qoswt_be[i]);
+ mmio_write_64(QOSWT_BE_WTQOS_BANK1 + i * 8U, qoswt_be[i]);
+ }
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+ /* AXI setting */
+ mmio_write_32(AXI_MMCR, 0x00010008U);
+ mmio_write_32(AXI_TR3CR, 0x00010000U);
+ mmio_write_32(AXI_TR4CR, 0x00010000U);
+
+ /* RT bus Leaf setting */
+ mmio_write_32(RT_ACT0, 0x00000000U);
+ mmio_write_32(RT_ACT1, 0x00000000U);
+
+ /* CCI bus Leaf setting */
+ mmio_write_32(CPU_ACT0, 0x00000003U);
+ mmio_write_32(CPU_ACT1, 0x00000003U);
+ mmio_write_32(CPU_ACT2, 0x00000003U);
+ mmio_write_32(CPU_ACT3, 0x00000003U);
+
+ mmio_write_32(QOSCTRL_RAEN, 0x00000001U);
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+ /* re-write training setting */
+ mmio_write_32(QOSWT_WTREF,
+ ((QOSWT_WTREF_SLOT1_EN << 16) | QOSWT_WTREF_SLOT0_EN));
+ mmio_write_32(QOSWT_WTSET0,
+ ((QOSWT_WTSET0_PERIOD0_G2H << 16) |
+ (QOSWT_WTSET0_SSLOT0 << 8) | QOSWT_WTSET0_SLOTSLOT0));
+ mmio_write_32(QOSWT_WTSET1,
+ ((QOSWT_WTSET1_PERIOD1_G2H << 16) |
+ (QOSWT_WTSET1_SSLOT1 << 8) | QOSWT_WTSET1_SLOTSLOT1));
+
+ mmio_write_32(QOSWT_WTEN, QOSWT_WTEN_ENABLE);
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+ mmio_write_32(QOSCTRL_STATQC, 0x00000001U);
+#else
+ NOTICE("BL2: QoS is None\n");
+
+ mmio_write_32(QOSCTRL_RAEN, 0x00000001U);
+#endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+}
diff --git a/drivers/renesas/rzg/qos/G2H/qos_init_g2h_v30.h b/drivers/renesas/rzg/qos/G2H/qos_init_g2h_v30.h
new file mode 100644
index 0000000..acd9627
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2H/qos_init_g2h_v30.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2H_V30_H
+#define QOS_INIT_G2H_V30_H
+
+void qos_init_g2h_v30(void);
+
+#endif /* QOS_INIT_G2H_V30_H */
diff --git a/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v10.c b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v10.c
new file mode 100644
index 0000000..ceaad25
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v10.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "../qos_common.h"
+#include "qos_init_g2m_v10.h"
+#include "qos_init_g2m_v10_mstat.h"
+#include "qos_reg.h"
+
+#define RCAR_QOS_VERSION "rev.0.19"
+
+static const struct rcar_gen3_dbsc_qos_settings g2m_v10_qos[] = {
+ /* BUFCAM settings */
+ /* DBSC_DBCAM0CNF0 not set */
+ { DBSC_DBCAM0CNF1, 0x00043218U },
+ { DBSC_DBCAM0CNF2, 0x000000F4U },
+ { DBSC_DBCAM0CNF3, 0x00000000U },
+ { DBSC_DBSCHCNT0, 0x080F0037U },
+ /* DBSC_DBSCHCNT1 not set */
+ { 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, 0x00000300U },
+ { DBSC_DBSCHQOS91, 0x000002F0U },
+ { DBSC_DBSCHQOS92, 0x00000200U },
+ { DBSC_DBSCHQOS93, 0x00000100U },
+ { 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_g2m_v10(void)
+{
+ rzg_qos_dbsc_setting(g2m_v10_qos, ARRAY_SIZE(g2m_v10_qos), false);
+
+ /* DRAM split address mapping */
+#if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH
+#if RCAR_LSI == RZ_G2M
+#error "Don't set DRAM Split 4ch(G2M)"
+#else /* RCAR_LSI == RZ_G2M */
+ ERROR("DRAM Split 4ch not supported.(G2M)");
+ panic();
+#endif /* RCAR_LSI == RZ_G2M */
+#elif (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH) || \
+ (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO)
+ NOTICE("BL2: DRAM Split is 2ch\n");
+ mmio_write_32(AXI_ADSPLCR0, 0x00000000U);
+ mmio_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT |
+ ADSPLCR0_SPLITSEL(0xFFU) | ADSPLCR0_AREA(0x1CU) |
+ ADSPLCR0_SWP);
+ mmio_write_32(AXI_ADSPLCR2, 0x089A0000U);
+ mmio_write_32(AXI_ADSPLCR3, 0x00000000U);
+#else /* RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH */
+ NOTICE("BL2: DRAM Split is OFF\n");
+#endif /* RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH */
+
+#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 */
+ mmio_write_32(QOSCTRL_RAS, 0x00000028U);
+ mmio_write_32(QOSCTRL_FIXTH, 0x000F0005U);
+ mmio_write_32(QOSCTRL_REGGD, 0x00000000U);
+ mmio_write_64(QOSCTRL_DANN, 0x0101010102020201UL);
+ mmio_write_32(QOSCTRL_DANT, 0x00100804U);
+ mmio_write_32(QOSCTRL_EC, 0x00000000U);
+ mmio_write_64(QOSCTRL_EMS, 0x0000000000000000UL);
+ mmio_write_32(QOSCTRL_FSS, 0x000003e8U);
+ mmio_write_32(QOSCTRL_INSFC, 0xC7840001U);
+ mmio_write_32(QOSCTRL_BERR, 0x00000000U);
+ mmio_write_32(QOSCTRL_RACNT0, 0x00000000U);
+
+ /* QOSBW setting */
+ mmio_write_32(QOSCTRL_SL_INIT, SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT |
+ SL_INIT_SSLOTCLK);
+ mmio_write_32(QOSCTRL_REF_ARS, 0x00330000U);
+
+ /* QOSBW SRAM setting */
+ uint32_t i;
+
+ for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) {
+ mmio_write_64(QOSBW_FIX_QOS_BANK0 + i * 8U, mstat_fix[i]);
+ mmio_write_64(QOSBW_FIX_QOS_BANK1 + i * 8U, mstat_fix[i]);
+ }
+ for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) {
+ mmio_write_64(QOSBW_BE_QOS_BANK0 + i * 8U, mstat_be[i]);
+ mmio_write_64(QOSBW_BE_QOS_BANK1 + i * 8U, mstat_be[i]);
+ }
+
+ /* 3DG bus Leaf setting */
+ mmio_write_32(0xFD820808U, 0x00001234U);
+ mmio_write_32(0xFD820800U, 0x00000006U);
+ mmio_write_32(0xFD821800U, 0x00000006U);
+ mmio_write_32(0xFD822800U, 0x00000006U);
+ mmio_write_32(0xFD823800U, 0x00000006U);
+ mmio_write_32(0xFD824800U, 0x00000006U);
+ mmio_write_32(0xFD825800U, 0x00000006U);
+ mmio_write_32(0xFD826800U, 0x00000006U);
+ mmio_write_32(0xFD827800U, 0x00000006U);
+
+ /* RT bus Leaf setting */
+ mmio_write_32(0xFFC50800U, 0x00000000U);
+ mmio_write_32(0xFFC51800U, 0x00000000U);
+
+ /* Resource Alloc start */
+ mmio_write_32(QOSCTRL_RAEN, 0x00000001U);
+
+ /* QOSBW start */
+ mmio_write_32(QOSCTRL_STATQC, 0x00000001U);
+#else /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+ NOTICE("BL2: QoS is None\n");
+
+ /* Resource Alloc setting */
+ mmio_write_32(QOSCTRL_EC, 0x00000000U);
+ /* Resource Alloc start */
+ mmio_write_32(QOSCTRL_RAEN, 0x00000001U);
+#endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+}
diff --git a/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v10.h b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v10.h
new file mode 100644
index 0000000..627974a
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v10.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2M_V10_H
+#define QOS_INIT_G2M_V10_H
+
+void qos_init_g2m_v10(void);
+
+#endif /* QOS_INIT_G2M_V10_H */
diff --git a/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v10_mstat.h b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v10_mstat.h
new file mode 100644
index 0000000..c37915c
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v10_mstat.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2M_V10_MSTAT_H
+#define QOS_INIT_G2M_V10_MSTAT_H
+
+#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 /* RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT */
+
+#endif /* QOS_INIT_G2M_V10_MSTAT_H */
diff --git a/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11.c b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11.c
new file mode 100644
index 0000000..db61858
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "../qos_common.h"
+#include "qos_init_g2m_v11.h"
+#if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_g2m_v11_mstat195.h"
+#else /* RCAR_REF_INT == RCAR_REF_DEFAULT */
+#include "qos_init_g2m_v11_mstat390.h"
+#endif /* RCAR_REF_INT == RCAR_REF_DEFAULT */
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_g2m_v11_qoswt195.h"
+#else /* RCAR_REF_INT == RCAR_REF_DEFAULT */
+#include "qos_init_g2m_v11_qoswt390.h"
+#endif /* RCAR_REF_INT == RCAR_REF_DEFAULT */
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+#endif /* RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT */
+#include "qos_reg.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_G2M_11 (SL_INIT_SSLOTCLK_G2M_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_G2M_11 \
+ ((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_G2M_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_G2M_11 \
+ ((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_G2M_11) - 1U)
+#define QOSWT_WTSET1_SSLOT1 (QOSWT_WTSET0_REQ_SSLOT0 - 1U)
+#define QOSWT_WTSET1_SLOTSLOT1 (WT_BASE_SUB_SLOT_NUM0 - 1U)
+
+static const struct rcar_gen3_dbsc_qos_settings g2m_v11_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_g2m_v11(void)
+{
+ uint32_t i;
+
+ rzg_qos_dbsc_setting(g2m_v11_qos, ARRAY_SIZE(g2m_v11_qos), false);
+
+ /* DRAM Split Address mapping */
+#if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH
+#if RCAR_LSI == RZ_G2M
+#error "Don't set DRAM Split 4ch(G2M)"
+#else /* RCAR_LSI == RZ_G2M */
+ ERROR("DRAM Split 4ch not supported.(G2M)");
+ panic();
+#endif /* RCAR_LSI == RZ_G2M */
+#elif (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH) || \
+ (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO)
+ NOTICE("BL2: DRAM Split is 2ch\n");
+ mmio_write_32(AXI_ADSPLCR0, 0x00000000U);
+ mmio_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT |
+ ADSPLCR0_SPLITSEL(0xFFU) | ADSPLCR0_AREA(0x1CU) |
+ ADSPLCR0_SWP);
+ mmio_write_32(AXI_ADSPLCR2, 0x00001004U);
+ mmio_write_32(AXI_ADSPLCR3, 0x00000000U);
+#else /* RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH */
+ NOTICE("BL2: DRAM Split is OFF\n");
+#endif /* RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH */
+
+#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 /* RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT */
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+ NOTICE("BL2: DRAM refresh interval 1.95 usec\n");
+#else /* RCAR_REF_INT == RCAR_REF_DEFAULT */
+ NOTICE("BL2: DRAM refresh interval 3.9 usec\n");
+#endif /* RCAR_REF_INT == RCAR_REF_DEFAULT */
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+ NOTICE("BL2: Periodic Write DQ Training\n");
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+ mmio_write_32(QOSCTRL_RAS, 0x00000044U);
+ mmio_write_64(QOSCTRL_DANN, 0x0404020002020201UL);
+ mmio_write_32(QOSCTRL_DANT, 0x0020100AU);
+ mmio_write_32(QOSCTRL_INSFC, 0x06330001U);
+ mmio_write_32(QOSCTRL_RACNT0, 0x02010003U); /* GPU Boost Mode ON */
+
+ mmio_write_32(QOSCTRL_SL_INIT,
+ SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT |
+ SL_INIT_SSLOTCLK_G2M_11);
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+ mmio_write_32(QOSCTRL_REF_ARS,
+ QOSCTRL_REF_ARS_ARBSTOPCYCLE_G2M_11 << 16);
+#else /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+ mmio_write_32(QOSCTRL_REF_ARS, 0x00330000U);
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+ for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) {
+ mmio_write_64(QOSBW_FIX_QOS_BANK0 + i * 8U, mstat_fix[i]);
+ mmio_write_64(QOSBW_FIX_QOS_BANK1 + i * 8U, mstat_fix[i]);
+ }
+ for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) {
+ mmio_write_64(QOSBW_BE_QOS_BANK0 + i * 8U, mstat_be[i]);
+ mmio_write_64(QOSBW_BE_QOS_BANK1 + i * 8U, mstat_be[i]);
+ }
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+ for (i = 0U; i < ARRAY_SIZE(qoswt_fix); i++) {
+ mmio_write_64(QOSWT_FIX_WTQOS_BANK0 + i * 8U, qoswt_fix[i]);
+ mmio_write_64(QOSWT_FIX_WTQOS_BANK1 + i * 8U, qoswt_fix[i]);
+ }
+ for (i = 0U; i < ARRAY_SIZE(qoswt_be); i++) {
+ mmio_write_64(QOSWT_BE_WTQOS_BANK0 + i * 8U, qoswt_be[i]);
+ mmio_write_64(QOSWT_BE_WTQOS_BANK1 + i * 8U, qoswt_be[i]);
+ }
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+ /* 3DG bus Leaf setting */
+ mmio_write_32(GPU_ACT_GRD, 0x00001234U);
+ mmio_write_32(GPU_ACT0, 0x00000000U);
+ mmio_write_32(GPU_ACT1, 0x00000000U);
+ mmio_write_32(GPU_ACT2, 0x00000000U);
+ mmio_write_32(GPU_ACT3, 0x00000000U);
+
+ /* RT bus Leaf setting */
+ mmio_write_32(RT_ACT0, 0x00000000U);
+ mmio_write_32(RT_ACT1, 0x00000000U);
+
+ /* CCI bus Leaf setting */
+ mmio_write_32(CPU_ACT0, 0x00000003U);
+ mmio_write_32(CPU_ACT1, 0x00000003U);
+ mmio_write_32(CPU_ACT2, 0x00000003U);
+ mmio_write_32(CPU_ACT3, 0x00000003U);
+
+ mmio_write_32(QOSCTRL_RAEN, 0x00000001U);
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+ /* re-write training setting */
+ mmio_write_32(QOSWT_WTREF,
+ (QOSWT_WTREF_SLOT1_EN << 16) | QOSWT_WTREF_SLOT0_EN);
+ mmio_write_32(QOSWT_WTSET0,
+ (QOSWT_WTSET0_PERIOD0_G2M_11 << 16) |
+ (QOSWT_WTSET0_SSLOT0 << 8) | QOSWT_WTSET0_SLOTSLOT0);
+ mmio_write_32(QOSWT_WTSET1,
+ (QOSWT_WTSET1_PERIOD1_G2M_11 << 16) |
+ (QOSWT_WTSET1_SSLOT1 << 8) | QOSWT_WTSET1_SLOTSLOT1);
+
+ mmio_write_32(QOSWT_WTEN, QOSWT_WTEN_ENABLE);
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+ mmio_write_32(QOSCTRL_STATQC, 0x00000001U);
+#else /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+ NOTICE("BL2: QoS is None\n");
+
+ mmio_write_32(QOSCTRL_RAEN, 0x00000001U);
+#endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+}
diff --git a/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11.h b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11.h
new file mode 100644
index 0000000..d042493
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2M_V11_H
+#define QOS_INIT_G2M_V11_H
+
+void qos_init_g2m_v11(void);
+
+#endif /* QOS_INIT_G2M_V11_H */
diff --git a/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11_mstat195.h b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11_mstat195.h
new file mode 100644
index 0000000..950abd6
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11_mstat195.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2M_V11_MSTAT195_H
+#define QOS_INIT_G2M_V11_MSTAT195_H
+
+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, */ 0x0000000000000000UL,
+ /* 0x00f8, */ 0x0000000000000000UL,
+ /* 0x0100, */ 0x0000000000000000UL,
+ /* 0x0108, */ 0x0000000000000000UL,
+ /* 0x0110, */ 0x0000000000000000UL,
+ /* 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, */ 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, */ 0x0000000000000000UL,
+ /* 0x02b8, */ 0x0000000000000000UL,
+ /* 0x02c0, */ 0x0000000000000000UL,
+ /* 0x02c8, */ 0x0000000000000000UL,
+ /* 0x02d0, */ 0x000C04010000FFFFUL,
+ /* 0x02d8, */ 0x000C04010000FFFFUL,
+ /* 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 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, */ 0x002100600BDFFC01UL,
+ /* 0x01c8, */ 0x002100600BDFFC01UL,
+ /* 0x01d0, */ 0x002100600BDFFC01UL,
+ /* 0x01d8, */ 0x002100600BDFFC01UL,
+ /* 0x01e0, */ 0x0000000000000000UL,
+ /* 0x01e8, */ 0x0000000000000000UL,
+ /* 0x01f0, */ 0x0000000000000000UL,
+ /* 0x01f8, */ 0x0000000000000000UL,
+ /* 0x0200, */ 0x0000000000000000UL,
+ /* 0x0208, */ 0x0000000000000000UL,
+ /* 0x0210, */ 0x0000000000000000UL,
+ /* 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,
+};
+
+#endif /* QOS_INIT_G2M_V11_MSTAT195_H */
diff --git a/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11_mstat390.h b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11_mstat390.h
new file mode 100644
index 0000000..5c6fd24
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11_mstat390.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2M_V11_MSTAT390_H
+#define QOS_INIT_G2M_V11_MSTAT390_H
+
+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,
+};
+
+#endif /* QOS_INIT_G2M_V11_MSTAT390_H */
diff --git a/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11_qoswt195.h b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11_qoswt195.h
new file mode 100644
index 0000000..f526a82
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11_qoswt195.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2M_V11_QOSWT195_H
+#define QOS_INIT_G2M_V11_QOSWT195_H
+
+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,
+};
+
+#endif /* QOS_INIT_G2M_V11_QOSWT195_H */
diff --git a/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11_qoswt390.h b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11_qoswt390.h
new file mode 100644
index 0000000..bfb80e3
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11_qoswt390.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2M_V11_QOSWT390_H
+#define QOS_INIT_G2M_V11_QOSWT390_H
+
+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,
+};
+
+#endif /* QOS_INIT_G2M_V11_QOSWT390_H */
diff --git a/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30.c b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30.c
new file mode 100644
index 0000000..321cd2b
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "../qos_common.h"
+#include "qos_init_g2m_v30.h"
+#if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_g2m_v30_mstat195.h"
+#else /* RCAR_REF_INT == RCAR_REF_DEFAULT */
+#include "qos_init_g2m_v30_mstat390.h"
+#endif /* RCAR_REF_INT == RCAR_REF_DEFAULT */
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_g2m_v30_qoswt195.h"
+#else /* RCAR_REF_INT == RCAR_REF_DEFAULT */
+#include "qos_init_g2m_v30_qoswt390.h"
+#endif /* RCAR_REF_INT == RCAR_REF_DEFAULT */
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+#endif /* RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT */
+#include "qos_reg.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_G2M_30 (SL_INIT_SSLOTCLK_G2M_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_G2M_30 \
+ ((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_G2M_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_G2M_30 \
+ ((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_G2M_30) - 1U)
+#define QOSWT_WTSET1_SSLOT1 (QOSWT_WTSET0_REQ_SSLOT0 - 1U)
+#define QOSWT_WTSET1_SLOTSLOT1 (WT_BASE_SUB_SLOT_NUM0 - 1U)
+
+static const struct rcar_gen3_dbsc_qos_settings g2m_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_g2m_v30(void)
+{
+ uint32_t i;
+
+ rzg_qos_dbsc_setting(g2m_v30_qos, ARRAY_SIZE(g2m_v30_qos), true);
+
+ /* DRAM Split Address mapping */
+#if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH
+#if RCAR_LSI == RZ_G2M
+ #error "Don't set DRAM Split 4ch(G2M)"
+#else /* RCAR_LSI == RZ_G2M */
+ ERROR("DRAM Split 4ch not supported.(G2M)");
+ panic();
+#endif /* RCAR_LSI == RZ_G2M */
+#elif (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH) || \
+ (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO)
+ NOTICE("BL2: DRAM Split is 2ch\n");
+ mmio_write_32(AXI_ADSPLCR0, 0x00000000U);
+ mmio_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT |
+ ADSPLCR0_SPLITSEL(0xFFU) | ADSPLCR0_AREA(0x1DU) |
+ ADSPLCR0_SWP);
+ mmio_write_32(AXI_ADSPLCR2, 0x00001004U);
+ mmio_write_32(AXI_ADSPLCR3, 0x00000000U);
+#else /* RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH */
+ NOTICE("BL2: DRAM Split is OFF\n");
+#endif /* RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH */
+
+#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 /* RCAR_REF_INT == RCAR_REF_DEFAULT */
+ NOTICE("BL2: DRAM refresh interval 3.9 usec\n");
+#endif /* RCAR_REF_INT == RCAR_REF_DEFAULT */
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+ NOTICE("BL2: Periodic Write DQ Training\n");
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+ mmio_write_32(QOSCTRL_RAS, 0x00000044U);
+ mmio_write_64(QOSCTRL_DANN, 0x0404020002020201UL);
+ mmio_write_32(QOSCTRL_DANT, 0x0020100AU);
+ mmio_write_32(QOSCTRL_FSS, 0x0000000AU);
+ mmio_write_32(QOSCTRL_INSFC, 0x06330001U);
+ mmio_write_32(QOSCTRL_EARLYR, 0x00000001U);
+ mmio_write_32(QOSCTRL_RACNT0, 0x02010003U); /* GPU Boost Mode ON */
+
+ /* GPU Boost Mode */
+ mmio_write_32(QOSCTRL_STATGEN0, 0x00000001U);
+
+ mmio_write_32(QOSCTRL_SL_INIT,
+ SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT |
+ SL_INIT_SSLOTCLK_G2M_30);
+ mmio_write_32(QOSCTRL_REF_ARS,
+ QOSCTRL_REF_ARS_ARBSTOPCYCLE_G2M_30 << 16);
+
+ for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) {
+ mmio_write_64(QOSBW_FIX_QOS_BANK0 + i * 8U, mstat_fix[i]);
+ mmio_write_64(QOSBW_FIX_QOS_BANK1 + i * 8U, mstat_fix[i]);
+ }
+ for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) {
+ mmio_write_64(QOSBW_BE_QOS_BANK0 + i * 8U, mstat_be[i]);
+ mmio_write_64(QOSBW_BE_QOS_BANK1 + i * 8U, mstat_be[i]);
+ }
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+ for (i = 0U; i < ARRAY_SIZE(qoswt_fix); i++) {
+ mmio_write_64(QOSWT_FIX_WTQOS_BANK0 + i * 8U, qoswt_fix[i]);
+ mmio_write_64(QOSWT_FIX_WTQOS_BANK1 + i * 8U, qoswt_fix[i]);
+ }
+ for (i = 0U; i < ARRAY_SIZE(qoswt_be); i++) {
+ mmio_write_64(QOSWT_BE_WTQOS_BANK0 + i * 8U, qoswt_be[i]);
+ mmio_write_64(QOSWT_BE_WTQOS_BANK1 + i * 8U, qoswt_be[i]);
+ }
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+ /* RT bus Leaf setting */
+ mmio_write_32(RT_ACT0, 0x00000000U);
+ mmio_write_32(RT_ACT1, 0x00000000U);
+
+ /* CCI bus Leaf setting */
+ mmio_write_32(CPU_ACT0, 0x00000003U);
+ mmio_write_32(CPU_ACT1, 0x00000003U);
+ mmio_write_32(CPU_ACT2, 0x00000003U);
+ mmio_write_32(CPU_ACT3, 0x00000003U);
+
+ mmio_write_32(QOSCTRL_RAEN, 0x00000001U);
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+ /* re-write training setting */
+ mmio_write_32(QOSWT_WTREF,
+ (QOSWT_WTREF_SLOT1_EN << 16) | QOSWT_WTREF_SLOT0_EN);
+ mmio_write_32(QOSWT_WTSET0, (QOSWT_WTSET0_PERIOD0_G2M_30 << 16) |
+ (QOSWT_WTSET0_SSLOT0 << 8) | QOSWT_WTSET0_SLOTSLOT0);
+ mmio_write_32(QOSWT_WTSET1, (QOSWT_WTSET1_PERIOD1_G2M_30 << 16) |
+ (QOSWT_WTSET1_SSLOT1 << 8) | QOSWT_WTSET1_SLOTSLOT1);
+
+ mmio_write_32(QOSWT_WTEN, QOSWT_WTEN_ENABLE);
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+ mmio_write_32(QOSCTRL_STATQC, 0x00000001U);
+#else /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+ NOTICE("BL2: QoS is None\n");
+
+ mmio_write_32(QOSCTRL_RAEN, 0x00000001U);
+#endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+}
diff --git a/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30.h b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30.h
new file mode 100644
index 0000000..f89eabf
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2M_V30_H
+#define QOS_INIT_G2M_V30_H
+
+void qos_init_g2m_v30(void);
+
+#endif /* QOS_INIT_G2M_V30_H */
diff --git a/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30_mstat195.h b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30_mstat195.h
new file mode 100644
index 0000000..fd15788
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30_mstat195.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2M_V30_MSTAT195_H
+#define QOS_INIT_G2M_V30_MSTAT195_H
+
+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,
+};
+
+#endif /* QOS_INIT_G2M_V30_MSTAT195_H */
diff --git a/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30_mstat390.h b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30_mstat390.h
new file mode 100644
index 0000000..aa2036d
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30_mstat390.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2M_V30_MSTAT390_H
+#define QOS_INIT_G2M_V30_MSTAT390_H
+
+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,
+};
+
+#endif /* QOS_INIT_G2M_V30_MSTAT390_H */
diff --git a/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30_qoswt195.h b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30_qoswt195.h
new file mode 100644
index 0000000..27c9c51
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30_qoswt195.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2M_V30_QOSWT195_H
+#define QOS_INIT_G2M_V30_QOSWT195_H
+
+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,
+};
+
+#endif /* QOS_INIT_G2M_V30_QOSWT195_H */
diff --git a/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30_qoswt390.h b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30_qoswt390.h
new file mode 100644
index 0000000..5d18212
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30_qoswt390.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2M_V30_QOSWT390_H
+#define QOS_INIT_G2M_V30_QOSWT390_H
+
+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,
+};
+
+#endif /* QOS_INIT_G2M_V30_QOSWT390_H */
diff --git a/drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10.c b/drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10.c
new file mode 100644
index 0000000..00b0948
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "qos_init_g2n_v10.h"
+
+#include "../qos_common.h"
+#include "../qos_reg.h"
+
+#define RCAR_QOS_VERSION "rev.0.09"
+
+#define REF_ARS_ARBSTOPCYCLE_G2N (((SL_INIT_SSLOTCLK_G2N) - 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_G2N ((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_G2N) - 1U)
+#define QOSWT_WTSET0_SSLOT0 (QOSWT_WTSET0_REQ_SSLOT0 - 1U)
+#define QOSWT_WTSET0_SLOTSLOT0 (WT_BASE_SUB_SLOT_NUM0 - 1U)
+
+#define QOSWT_WTSET1_PERIOD1_G2N QOSWT_WTSET0_PERIOD0_G2N
+#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_g2n_v10_mstat195.h"
+#else
+#include "qos_init_g2n_v10_mstat390.h"
+#endif
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_g2n_v10_qoswt195.h"
+#else
+#include "qos_init_g2n_v10_qoswt390.h"
+#endif
+
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+#endif
+
+static const struct rcar_gen3_dbsc_qos_settings g2n_v10_qos[] = {
+ /* BUFCAM settings */
+ { DBSC_DBCAM0CNF1, 0x00043218U },
+ { DBSC_DBCAM0CNF2, 0x000000F4U },
+ { 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_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_g2n_v10(void)
+{
+ rzg_qos_dbsc_setting(g2n_v10_qos, ARRAY_SIZE(g2n_v10_qos), true);
+
+ /* DRAM Split Address mapping */
+#if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH
+#if RCAR_LSI == RZ_G2N
+#error "Don't set DRAM Split 4ch(G2N)"
+#else
+ ERROR("DRAM Split 4ch not supported.(G2N)");
+ panic();
+#endif
+#elif (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH)
+#if RCAR_LSI == RZ_G2N
+#error "Don't set DRAM Split 2ch(G2N)"
+#else
+ ERROR("DRAM Split 2ch not supported.(G2N)");
+ 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 */
+
+ mmio_write_32(QOSCTRL_RAS, 0x00000028U);
+ mmio_write_64(QOSCTRL_DANN, 0x0402000002020201UL);
+ mmio_write_32(QOSCTRL_DANT, 0x00100804U);
+ mmio_write_32(QOSCTRL_FSS, 0x0000000AU);
+ mmio_write_32(QOSCTRL_INSFC, 0x06330001U);
+ mmio_write_32(QOSCTRL_EARLYR, 0x00000001U);
+ mmio_write_32(QOSCTRL_RACNT0, 0x00010003U);
+
+ mmio_write_32(QOSCTRL_SL_INIT, SL_INIT_REFFSSLOT |
+ SL_INIT_SLOTSSLOT | SL_INIT_SSLOTCLK_G2N);
+ mmio_write_32(QOSCTRL_REF_ARS, REF_ARS_ARBSTOPCYCLE_G2N);
+
+ uint32_t i;
+
+ for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) {
+ mmio_write_64(QOSBW_FIX_QOS_BANK0 + i * 8U, mstat_fix[i]);
+ mmio_write_64(QOSBW_FIX_QOS_BANK1 + i * 8U, mstat_fix[i]);
+ }
+ for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) {
+ mmio_write_64(QOSBW_BE_QOS_BANK0 + i * 8U, mstat_be[i]);
+ mmio_write_64(QOSBW_BE_QOS_BANK1 + i * 8U, mstat_be[i]);
+ }
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+ for (i = 0U; i < ARRAY_SIZE(qoswt_fix); i++) {
+ mmio_write_64(QOSWT_FIX_WTQOS_BANK0 + i * 8U, qoswt_fix[i]);
+ mmio_write_64(QOSWT_FIX_WTQOS_BANK1 + i * 8U, qoswt_fix[i]);
+ }
+ for (i = 0U; i < ARRAY_SIZE(qoswt_be); i++) {
+ mmio_write_64(QOSWT_BE_WTQOS_BANK0 + i * 8U, qoswt_be[i]);
+ mmio_write_64(QOSWT_BE_WTQOS_BANK1 + i * 8U, qoswt_be[i]);
+ }
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+ /* RT bus Leaf setting */
+ mmio_write_32(RT_ACT0, 0x00000000U);
+ mmio_write_32(RT_ACT1, 0x00000000U);
+
+ /* CCI bus Leaf setting */
+ mmio_write_32(CPU_ACT0, 0x00000003U);
+ mmio_write_32(CPU_ACT1, 0x00000003U);
+
+ mmio_write_32(QOSCTRL_RAEN, 0x00000001U);
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+ /* re-write training setting */
+ mmio_write_32(QOSWT_WTREF, ((QOSWT_WTREF_SLOT1_EN << 16) | QOSWT_WTREF_SLOT0_EN));
+ mmio_write_32(QOSWT_WTSET0, ((QOSWT_WTSET0_PERIOD0_G2N << 16) |
+ (QOSWT_WTSET0_SSLOT0 << 8) | QOSWT_WTSET0_SLOTSLOT0));
+ mmio_write_32(QOSWT_WTSET1, ((QOSWT_WTSET1_PERIOD1_G2N << 16) |
+ (QOSWT_WTSET1_SSLOT1 << 8) | QOSWT_WTSET1_SLOTSLOT1));
+
+ mmio_write_32(QOSWT_WTEN, QOSWT_WTEN_ENABLE);
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+ mmio_write_32(QOSCTRL_STATQC, 0x00000001U);
+#else
+ NOTICE("BL2: QoS is None\n");
+
+ mmio_write_32(QOSCTRL_RAEN, 0x00000001U);
+#endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+}
diff --git a/drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10.h b/drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10.h
new file mode 100644
index 0000000..c7f02d9
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2N_V10_H
+#define QOS_INIT_G2N_V10_H
+
+void qos_init_g2n_v10(void);
+
+#endif /* QOS_INIT_G2N_V10_H */
diff --git a/drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10_mstat195.h b/drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10_mstat195.h
new file mode 100644
index 0000000..6e304b0
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10_mstat195.h
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2N_MSTAT195_H
+#define QOS_INIT_G2N_MSTAT195_H
+
+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, */ 0x0000000000000000UL,
+ /* 0x00f8, */ 0x000C084F0000FFFFUL,
+ /* 0x0100, */ 0x0000000000000000UL,
+ /* 0x0108, */ 0x0000000000000000UL,
+ /* 0x0110, */ 0x0000000000000000UL,
+ /* 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, */ 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, */ 0x001408020000FFFFUL,
+ /* 0x0270, */ 0x001404010000FFFFUL,
+ /* 0x0278, */ 0x0000000000000000UL,
+ /* 0x0280, */ 0x0000000000000000UL,
+ /* 0x0288, */ 0x0000000000000000UL,
+ /* 0x0290, */ 0x001408020000FFFFUL,
+ /* 0x0298, */ 0x001404010000FFFFUL,
+ /* 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, */ 0x0000000000000000UL,
+ /* 0x0378, */ 0x0000000000000000UL,
+ /* 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, */ 0x0000000000000000UL,
+ /* 0x01f8, */ 0x0000000000000000UL,
+ /* 0x0200, */ 0x0000000000000000UL,
+ /* 0x0208, */ 0x0000000000000000UL,
+ /* 0x0210, */ 0x0000000000000000UL,
+ /* 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,
+};
+#endif /* QOS_INIT_G2N_MSTAT195_H */
diff --git a/drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10_mstat390.h b/drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10_mstat390.h
new file mode 100644
index 0000000..4632413
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10_mstat390.h
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2N_MSTAT390_H
+#define QOS_INIT_G2N_MSTAT390_H
+
+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,
+};
+#endif /* QOS_INIT_G2N_MSTAT390_H */
diff --git a/drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10_qoswt195.h b/drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10_qoswt195.h
new file mode 100644
index 0000000..eea1fce
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10_qoswt195.h
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2N_QOSWT195_H
+#define QOS_INIT_G2N_QOSWT195_H
+
+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,
+};
+#endif /* QOS_INIT_G2N_QOSWT195_H */
diff --git a/drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10_qoswt390.h b/drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10_qoswt390.h
new file mode 100644
index 0000000..7043303
--- /dev/null
+++ b/drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10_qoswt390.h
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_G2N_QOSWT390_H
+#define QOS_INIT_G2N_QOSWT390_H
+
+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,
+};
+#endif /* QOS_INIT_G2N_QOSWT390_H */
diff --git a/drivers/renesas/rzg/qos/qos.mk b/drivers/renesas/rzg/qos/qos.mk
new file mode 100644
index 0000000..f05d126
--- /dev/null
+++ b/drivers/renesas/rzg/qos/qos.mk
@@ -0,0 +1,60 @@
+#
+# Copyright (c) 2020-2021, Renesas Electronics Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${RCAR_LSI},${RCAR_AUTO})
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10.c
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2H/qos_init_g2h_v30.c
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2M/qos_init_g2m_v10.c
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11.c
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30.c
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10.c
+else ifeq (${RCAR_LSI_CUT_COMPAT},1)
+ ifeq (${RCAR_LSI},${RZ_G2M})
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2M/qos_init_g2m_v10.c
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11.c
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30.c
+ endif
+ ifeq (${RCAR_LSI},${RZ_G2H})
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2H/qos_init_g2h_v30.c
+ endif
+ ifeq (${RCAR_LSI},${RZ_G2N})
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10.c
+ endif
+ ifeq (${RCAR_LSI},${RZ_G2E})
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10.c
+ endif
+else
+ ifeq (${RCAR_LSI},${RZ_G2M})
+ ifeq (${LSI_CUT},10)
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2M/qos_init_g2m_v10.c
+ else ifeq (${LSI_CUT},11)
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11.c
+ else ifeq (${LSI_CUT},13)
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2M/qos_init_g2m_v11.c
+ else ifeq (${LSI_CUT},30)
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30.c
+ else
+# LSI_CUT 30 or later
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2M/qos_init_g2m_v30.c
+ endif
+ endif
+ ifeq (${RCAR_LSI},${RZ_G2H})
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2H/qos_init_g2h_v30.c
+ endif
+ ifeq (${RCAR_LSI},${RZ_G2N})
+ ifeq (${LSI_CUT},10)
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10.c
+ else
+# LSI_CUT 10 or later
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2N/qos_init_g2n_v10.c
+ endif
+ endif
+ ifeq (${RCAR_LSI},${RZ_G2E})
+ BL2_SOURCES += drivers/renesas/rzg/qos/G2E/qos_init_g2e_v10.c
+ endif
+endif
+
+BL2_SOURCES += drivers/renesas/rzg/qos/qos_init.c
diff --git a/drivers/renesas/rzg/qos/qos_common.h b/drivers/renesas/rzg/qos/qos_common.h
new file mode 100644
index 0000000..535bf4c
--- /dev/null
+++ b/drivers/renesas/rzg/qos/qos_common.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2021, 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 */
+#if (RCAR_REF_INT == RCAR_REF_DEFAULT) /* REF default */
+#define REFPERIOD_CYCLE /* unit:ns */ \
+ ((126U * BASE_SUB_SLOT_NUM * 1000U) / 400U)
+#else /* REF option */
+#define REFPERIOD_CYCLE /* unit:ns */ \
+ ((252U * BASE_SUB_SLOT_NUM * 1000U) / 400U)
+#endif
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RZ_G2M)
+/* define used for G2M */
+#if (RCAR_REF_INT == RCAR_REF_DEFAULT) /* REF 1.95usec */
+#define SUB_SLOT_CYCLE_G2M_11 0x7EU /* 126 */
+#define SUB_SLOT_CYCLE_G2M_30 0x7EU /* 126 */
+#else /* REF 3.9usec */
+#define SUB_SLOT_CYCLE_G2M_11 0xFCU /* 252 */
+#define SUB_SLOT_CYCLE_G2M_30 0xFCU /* 252 */
+#endif /* (RCAR_REF_INT == RCAR_REF_DEFAULT) */
+
+#define SL_INIT_SSLOTCLK_G2M_11 (SUB_SLOT_CYCLE_G2M_11 - 1U)
+#define SL_INIT_SSLOTCLK_G2M_30 (SUB_SLOT_CYCLE_G2M_30 - 1U)
+#define QOSWT_WTSET0_CYCLE_G2M_11 /* unit:ns */ \
+ ((SUB_SLOT_CYCLE_G2M_11 * BASE_SUB_SLOT_NUM * 1000U) / OPERATING_FREQ)
+#define QOSWT_WTSET0_CYCLE_G2M_30 /* unit:ns */ \
+ ((SUB_SLOT_CYCLE_G2M_30 * BASE_SUB_SLOT_NUM * 1000U) / OPERATING_FREQ)
+#endif
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RZ_G2N)
+/* define used for G2N */
+#if (RCAR_REF_INT == RCAR_REF_DEFAULT) /* REF 1.95usec */
+#define SUB_SLOT_CYCLE_G2N 0x7EU /* 126 */
+#else /* REF 3.9usec */
+#define SUB_SLOT_CYCLE_G2N 0xFCU /* 252 */
+#endif /* (RCAR_REF_INT == RCAR_REF_DEFAULT) */
+
+#define SL_INIT_SSLOTCLK_G2N (SUB_SLOT_CYCLE_G2N - 1U)
+#define QOSWT_WTSET0_CYCLE_G2N /* unit:ns */ \
+ ((SUB_SLOT_CYCLE_G2N * BASE_SUB_SLOT_NUM * 1000U) / OPERATING_FREQ)
+#endif /* (RCAR_LSI == RZ_G2N) */
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RZ_G2H)
+/* define used for G2H */
+#if (RCAR_REF_INT == RCAR_REF_DEFAULT) /* REF 1.95usec */
+#define SUB_SLOT_CYCLE_G2H 0x7EU /* 126 */
+#else /* REF 3.9usec */
+#define SUB_SLOT_CYCLE_G2H 0xFCU /* 252 */
+#endif /* (RCAR_REF_INT == RCAR_REF_DEFAULT) */
+
+#define SL_INIT_SSLOTCLK_G2H (SUB_SLOT_CYCLE_G2H - 1U)
+#define QOSWT_WTSET0_CYCLE_G2H /* unit:ns */ \
+ ((SUB_SLOT_CYCLE_G2H * BASE_SUB_SLOT_NUM * 1000U) / OPERATING_FREQ)
+#endif
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RZ_G2E)
+/* define used for G2E */
+#if (RCAR_REF_INT == RCAR_REF_DEFAULT) /* REF 3.9usec */
+#define SUB_SLOT_CYCLE_G2E 0xAFU /* 175 */
+#else /* REF 7.8usec */
+#define SUB_SLOT_CYCLE_G2E 0x15EU /* 350 */
+#endif /* (RCAR_REF_INT == RCAR_REF_DEFAULT) */
+
+#define OPERATING_FREQ_G2E 266U /* MHz */
+#define SL_INIT_SSLOTCLK_G2E (SUB_SLOT_CYCLE_G2E - 1U)
+#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)
+
+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 rzg_qos_dbsc_setting(const struct rcar_gen3_dbsc_qos_settings *qos,
+ unsigned int qos_size, bool dbsc_wren);
+
+#endif /* QOS_COMMON_H */
diff --git a/drivers/renesas/rzg/qos/qos_init.c b/drivers/renesas/rzg/qos/qos_init.c
new file mode 100644
index 0000000..e527a61
--- /dev/null
+++ b/drivers/renesas/rzg/qos/qos_init.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#if RCAR_LSI == RCAR_AUTO
+#include "G2E/qos_init_g2e_v10.h"
+#include "G2H/qos_init_g2h_v30.h"
+#include "G2M/qos_init_g2m_v10.h"
+#include "G2M/qos_init_g2m_v11.h"
+#include "G2M/qos_init_g2m_v30.h"
+#include "G2N/qos_init_g2n_v10.h"
+#endif /* RCAR_LSI == RCAR_AUTO */
+#if (RCAR_LSI == RZ_G2M)
+#include "G2M/qos_init_g2m_v10.h"
+#include "G2M/qos_init_g2m_v11.h"
+#include "G2M/qos_init_g2m_v30.h"
+#endif /* RCAR_LSI == RZ_G2M */
+#if RCAR_LSI == RZ_G2H
+#include "G2H/qos_init_g2h_v30.h"
+#endif /* RCAR_LSI == RZ_G2H */
+#if RCAR_LSI == RZ_G2N
+#include "G2N/qos_init_g2n_v10.h"
+#endif /* RCAR_LSI == RZ_G2N */
+#if RCAR_LSI == RZ_G2E
+#include "G2E/qos_init_g2e_v10.h"
+#endif /* RCAR_LSI == RZ_G2E */
+#include "qos_common.h"
+#include "qos_init.h"
+#include "qos_reg.h"
+#include "rcar_def.h"
+
+#if (RCAR_LSI != RZ_G2E)
+#define DRAM_CH_CNT 0x04U
+uint32_t qos_init_ddr_ch;
+uint8_t qos_init_ddr_phyvalid;
+#endif /* RCAR_LSI != RZ_G2E */
+
+#define PRR_PRODUCT_ERR(reg) \
+ { \
+ ERROR("LSI Product ID(PRR=0x%x) QoS " \
+ "initialize not supported.\n", reg); \
+ panic(); \
+ }
+
+#define PRR_CUT_ERR(reg) \
+ { \
+ ERROR("LSI Cut ID(PRR=0x%x) QoS " \
+ "initialize not supported.\n", reg); \
+ panic(); \
+ }
+
+void rzg_qos_init(void)
+{
+ uint32_t reg;
+#if (RCAR_LSI != RZ_G2E)
+ uint32_t i;
+
+ qos_init_ddr_ch = 0U;
+ qos_init_ddr_phyvalid = get_boardcnf_phyvalid();
+ for (i = 0U; i < DRAM_CH_CNT; i++) {
+ if ((qos_init_ddr_phyvalid & (1U << i))) {
+ qos_init_ddr_ch++;
+ }
+ }
+#endif /* RCAR_LSI != RZ_G2E */
+
+ reg = mmio_read_32(PRR);
+#if (RCAR_LSI == RCAR_AUTO) || RCAR_LSI_CUT_COMPAT
+ switch (reg & PRR_PRODUCT_MASK) {
+ case PRR_PRODUCT_M3:
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RZ_G2M)
+ switch (reg & PRR_CUT_MASK) {
+ case PRR_PRODUCT_10:
+ qos_init_g2m_v10();
+ break;
+ case PRR_PRODUCT_21: /* G2M Cut 13 */
+ qos_init_g2m_v11();
+ break;
+ case PRR_PRODUCT_30: /* G2M Cut 30 */
+ default:
+ qos_init_g2m_v30();
+ break;
+ }
+#else /* (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RZ_G2M) */
+ PRR_PRODUCT_ERR(reg);
+#endif /* (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RZ_G2M) */
+ break;
+ case PRR_PRODUCT_H3:
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RZ_G2H)
+ switch (reg & PRR_CUT_MASK) {
+ case PRR_PRODUCT_30:
+ default:
+ qos_init_g2h_v30();
+ break;
+ }
+#else
+ PRR_PRODUCT_ERR(reg);
+#endif /* (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RZ_G2H) */
+ break;
+ case PRR_PRODUCT_M3N:
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RZ_G2N)
+ switch (reg & PRR_CUT_MASK) {
+ case PRR_PRODUCT_10:
+ default:
+ qos_init_g2n_v10();
+ break;
+ }
+#else
+ PRR_PRODUCT_ERR(reg);
+#endif /* (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RZ_G2N) */
+ break;
+ case PRR_PRODUCT_E3:
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RZ_G2E)
+ switch (reg & PRR_CUT_MASK) {
+ case PRR_PRODUCT_10:
+ default:
+ qos_init_g2e_v10();
+ break;
+ }
+#else
+ PRR_PRODUCT_ERR(reg);
+#endif /* (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RZ_G2E) */
+ break;
+ default:
+ PRR_PRODUCT_ERR(reg);
+ break;
+ }
+#else /* RCAR_LSI == RCAR_AUTO || RCAR_LSI_CUT_COMPAT */
+#if (RCAR_LSI == RZ_G2M)
+#if RCAR_LSI_CUT == RCAR_CUT_10
+ /* G2M Cut 10 */
+ if ((PRR_PRODUCT_M3 | PRR_PRODUCT_10)
+ != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) {
+ PRR_PRODUCT_ERR(reg);
+ }
+ qos_init_g2m_v10();
+#elif RCAR_LSI_CUT == RCAR_CUT_11
+ /* G2M Cut 11 */
+ if ((PRR_PRODUCT_M3 | PRR_PRODUCT_20)
+ != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) {
+ PRR_PRODUCT_ERR(reg);
+ }
+ qos_init_g2m_v11();
+#elif RCAR_LSI_CUT == RCAR_CUT_13
+ /* G2M Cut 13 */
+ if ((PRR_PRODUCT_M3 | PRR_PRODUCT_21)
+ != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) {
+ PRR_PRODUCT_ERR(reg);
+ }
+ qos_init_g2m_v11();
+#else
+ /* G2M Cut 30 or later */
+ if ((PRR_PRODUCT_M3)
+ != (reg & (PRR_PRODUCT_MASK))) {
+ PRR_PRODUCT_ERR(reg);
+ }
+ qos_init_g2m_v30();
+#endif /* RCAR_LSI_CUT == RCAR_CUT_10 */
+#elif (RCAR_LSI == RZ_G2H)
+ /* G2H Cut 30 or later */
+ if ((reg & PRR_PRODUCT_MASK) != PRR_PRODUCT_H3) {
+ PRR_PRODUCT_ERR(reg);
+ }
+ qos_init_g2h_v30();
+#elif (RCAR_LSI == RZ_G2N)
+ /* G2N Cut 10 or later */
+ if ((reg & (PRR_PRODUCT_MASK)) != PRR_PRODUCT_M3N) {
+ PRR_PRODUCT_ERR(reg);
+ }
+ qos_init_g2n_v10();
+#elif RCAR_LSI == RZ_G2E
+ /* G2E Cut 10 or later */
+ if ((reg & (PRR_PRODUCT_MASK)) != PRR_PRODUCT_E3) {
+ PRR_PRODUCT_ERR(reg);
+ }
+ qos_init_g2e_v10();
+#else /* (RCAR_LSI == RZ_G2M) */
+#error "Don't have QoS initialize routine(Unknown chip)."
+#endif /* (RCAR_LSI == RZ_G2M) */
+#endif /* RCAR_LSI == RCAR_AUTO || RCAR_LSI_CUT_COMPAT */
+}
+
+#if (RCAR_LSI != RZ_G2E)
+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 == RZ_G2M)
+ case PRR_PRODUCT_M3:
+ switch (reg & PRR_CUT_MASK) {
+ case PRR_PRODUCT_10:
+ break;
+ case PRR_PRODUCT_20: /* G2M Cut 11 */
+ case PRR_PRODUCT_21: /* G2M Cut 13 */
+ case PRR_PRODUCT_30: /* G2M Cut 30 */
+ default:
+ refperiod = REFPERIOD_CYCLE;
+ break;
+ }
+ break;
+#endif /* (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RZ_G2M) */
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RZ_G2H)
+ case PRR_PRODUCT_H3:
+ switch (reg & PRR_CUT_MASK) {
+ case PRR_PRODUCT_30:
+ default:
+ refperiod = REFPERIOD_CYCLE;
+ break;
+ }
+ break;
+#endif /* (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RZ_G2H) */
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RZ_G2N)
+ case PRR_PRODUCT_M3N:
+ refperiod = REFPERIOD_CYCLE;
+ break;
+#endif /* (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RZ_G2N) */
+ default:
+ break;
+ }
+#elif RCAR_LSI == RZ_G2M
+#if RCAR_LSI_CUT == RCAR_CUT_10
+ /* G2M Cut 10 */
+#else /* RCAR_LSI_CUT == RCAR_CUT_10 */
+ /* G2M Cut 11|13|30 or later */
+ refperiod = REFPERIOD_CYCLE;
+#endif /* RCAR_LSI_CUT == RCAR_CUT_10 */
+#elif RCAR_LSI == RZ_G2N
+ refperiod = REFPERIOD_CYCLE;
+#elif RCAR_LSI == RZ_G2H
+ /* G2H Cut 30 or later */
+ refperiod = REFPERIOD_CYCLE;
+#endif /* RCAR_LSI == RCAR_AUTO || RCAR_LSI_CUT_COMPAT */
+ return refperiod;
+}
+#endif /* RCAR_LSI != RZ_G2E */
+
+void rzg_qos_dbsc_setting(const struct rcar_gen3_dbsc_qos_settings *qos,
+ unsigned int qos_size, bool dbsc_wren)
+{
+ unsigned int i;
+
+ /* Register write enable */
+ if (dbsc_wren) {
+ mmio_write_32(DBSC_DBSYSCNT0, 0x00001234U);
+ }
+
+ for (i = 0; i < qos_size; i++) {
+ mmio_write_32(qos[i].reg, qos[i].val);
+ }
+
+ /* Register write protect */
+ if (dbsc_wren) {
+ mmio_write_32(DBSC_DBSYSCNT0, 0x00000000U);
+ }
+}
diff --git a/drivers/renesas/rzg/qos/qos_init.h b/drivers/renesas/rzg/qos/qos_init.h
new file mode 100644
index 0000000..3d62744
--- /dev/null
+++ b/drivers/renesas/rzg/qos/qos_init.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2020-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RZG_QOS_INIT_H
+#define RZG_QOS_INIT_H
+
+void rzg_qos_init(void);
+uint8_t get_boardcnf_phyvalid(void);
+
+#endif /* RZG_QOS_INIT_H */
diff --git a/drivers/rpi3/gpio/rpi3_gpio.c b/drivers/rpi3/gpio/rpi3_gpio.c
new file mode 100644
index 0000000..55a8832
--- /dev/null
+++ b/drivers/rpi3/gpio/rpi3_gpio.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2019, Linaro Limited
+ * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+#include <assert.h>
+#include <lib/mmio.h>
+#include <drivers/delay_timer.h>
+#include <drivers/rpi3/gpio/rpi3_gpio.h>
+#include <platform_def.h>
+
+static uintptr_t reg_base;
+
+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;
+ 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)
+{
+ 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)
+{
+ 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)
+{
+ 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)
+{
+ 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(void)
+{
+ reg_base = RPI3_GPIO_BASE;
+ gpio_init(&rpi3_gpio_ops);
+}
diff --git a/drivers/rpi3/mailbox/rpi3_mbox.c b/drivers/rpi3/mailbox/rpi3_mbox.c
new file mode 100644
index 0000000..aef1f39
--- /dev/null
+++ b/drivers/rpi3/mailbox/rpi3_mbox.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <rpi_hw.h>
+
+#include <drivers/rpi3/mailbox/rpi3_mbox.h>
+
+#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);
+}
diff --git a/drivers/rpi3/rng/rpi3_rng.c b/drivers/rpi3/rng/rpi3_rng.c
new file mode 100644
index 0000000..b6bf005
--- /dev/null
+++ b/drivers/rpi3/rng/rpi3_rng.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <lib/mmio.h>
+
+#include <rpi_hw.h>
+
+/* 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);
+ }
+}
diff --git a/drivers/rpi3/sdhost/rpi3_sdhost.c b/drivers/rpi3/sdhost/rpi3_sdhost.c
new file mode 100644
index 0000000..c4b6fca
--- /dev/null
+++ b/drivers/rpi3/sdhost/rpi3_sdhost.c
@@ -0,0 +1,679 @@
+/*
+ * Copyright (c) 2019, Linaro Limited
+ * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <drivers/delay_timer.h>
+#include <drivers/rpi3/sdhost/rpi3_sdhost.h>
+#include <drivers/mmc.h>
+#include <drivers/rpi3/gpio/rpi3_gpio.h>
+#include <errno.h>
+#include <string.h>
+
+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);
+}
diff --git a/drivers/scmi-msg/base.c b/drivers/scmi-msg/base.c
new file mode 100644
index 0000000..2db4d7e
--- /dev/null
+++ b/drivers/scmi-msg/base.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2022, Linaro Limited
+ */
+#include <assert.h>
+#include <string.h>
+
+#include <drivers/scmi-msg.h>
+#include <drivers/scmi.h>
+#include <lib/utils.h>
+#include <lib/utils_def.h>
+
+#include "common.h"
+
+static bool message_id_is_supported(unsigned int message_id);
+
+static void report_version(struct scmi_msg *msg)
+{
+ struct scmi_protocol_version_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .version = SCMI_PROTOCOL_VERSION_BASE,
+ };
+
+ if (msg->in_size != 0U) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_attributes(struct scmi_msg *msg)
+{
+ size_t protocol_count = plat_scmi_protocol_count();
+ struct scmi_protocol_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ /* Null agent count since agent discovery is not supported */
+ .attributes = SCMI_BASE_PROTOCOL_ATTRIBUTES(protocol_count, 0U),
+ };
+
+ if (msg->in_size != 0U) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_message_attributes(struct scmi_msg *msg)
+{
+ struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
+ struct scmi_protocol_message_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ /* For this protocol, attributes shall be zero */
+ .attributes = 0U,
+ };
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (!message_id_is_supported(in_args->message_id)) {
+ scmi_status_response(msg, SCMI_NOT_FOUND);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void discover_vendor(struct scmi_msg *msg)
+{
+ const char *name = plat_scmi_vendor_name();
+ struct scmi_base_discover_vendor_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ };
+
+ if (msg->in_size != 0U) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ COPY_NAME_IDENTIFIER(return_values.vendor_identifier, name);
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void discover_sub_vendor(struct scmi_msg *msg)
+{
+ const char *name = plat_scmi_sub_vendor_name();
+ struct scmi_base_discover_sub_vendor_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ };
+
+ if (msg->in_size != 0U) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ COPY_NAME_IDENTIFIER(return_values.sub_vendor_identifier, name);
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void discover_implementation_version(struct scmi_msg *msg)
+{
+ struct scmi_protocol_version_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .version = SCMI_IMPL_VERSION,
+ };
+
+ if (msg->in_size != 0U) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static unsigned int count_protocols_in_list(const uint8_t *protocol_list)
+{
+ unsigned int count = 0U;
+
+ if (protocol_list != NULL) {
+ while (protocol_list[count] != 0U) {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+static void discover_list_protocols(struct scmi_msg *msg)
+{
+ const struct scmi_base_discover_list_protocols_a2p *a2p = NULL;
+ struct scmi_base_discover_list_protocols_p2a p2a = {
+ .status = SCMI_SUCCESS,
+ };
+ const uint8_t *list = NULL;
+ unsigned int count = 0U;
+
+ if (msg->in_size != sizeof(*a2p)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ a2p = (void *)msg->in;
+
+ list = plat_scmi_protocol_list(msg->agent_id);
+ count = count_protocols_in_list(list);
+
+ if (count > a2p->skip) {
+ count = MIN(count - a2p->skip, msg->out_size - sizeof(p2a));
+ } else {
+ count = 0U;
+ }
+
+ p2a.num_protocols = count;
+
+ memcpy(msg->out, &p2a, sizeof(p2a));
+ memcpy(msg->out + sizeof(p2a), list + a2p->skip, count);
+ msg->out_size_out = sizeof(p2a) + round_up(count, sizeof(uint32_t));
+}
+
+static const scmi_msg_handler_t scmi_base_handler_table[] = {
+ [SCMI_PROTOCOL_VERSION] = report_version,
+ [SCMI_PROTOCOL_ATTRIBUTES] = report_attributes,
+ [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes,
+ [SCMI_BASE_DISCOVER_VENDOR] = discover_vendor,
+ [SCMI_BASE_DISCOVER_SUB_VENDOR] = discover_sub_vendor,
+ [SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION] =
+ discover_implementation_version,
+ [SCMI_BASE_DISCOVER_LIST_PROTOCOLS] = discover_list_protocols,
+};
+
+static bool message_id_is_supported(unsigned int message_id)
+{
+ return (message_id < ARRAY_SIZE(scmi_base_handler_table)) &&
+ (scmi_base_handler_table[message_id] != NULL);
+}
+
+scmi_msg_handler_t scmi_msg_get_base_handler(struct scmi_msg *msg)
+{
+ unsigned int message_id = SPECULATION_SAFE_VALUE(msg->message_id);
+
+ if (message_id >= ARRAY_SIZE(scmi_base_handler_table)) {
+ VERBOSE("Base handle not found %u\n", msg->message_id);
+ return NULL;
+ }
+
+ return scmi_base_handler_table[message_id];
+}
diff --git a/drivers/scmi-msg/base.h b/drivers/scmi-msg/base.h
new file mode 100644
index 0000000..c4a9c64
--- /dev/null
+++ b/drivers/scmi-msg/base.h
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2020, Linaro Limited
+ */
+
+#ifndef SCMI_MSG_BASE_H
+#define SCMI_MSG_BASE_H
+
+#include <stdint.h>
+
+#define SCMI_PROTOCOL_VERSION_BASE 0x20000U
+
+#define SCMI_DEFAULT_STRING_LENGTH 16U
+
+enum scmi_base_message_id {
+ SCMI_BASE_DISCOVER_VENDOR = 0x003,
+ SCMI_BASE_DISCOVER_SUB_VENDOR = 0x004,
+ SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION = 0x005,
+ SCMI_BASE_DISCOVER_LIST_PROTOCOLS = 0x006,
+ SCMI_BASE_DISCOVER_AGENT = 0x007,
+ SCMI_BASE_NOTIFY_ERRORS = 0x008,
+};
+
+/*
+ * PROTOCOL_ATTRIBUTES
+ */
+
+#define SCMI_BASE_PROTOCOL_ATTRS_NUM_PROTOCOLS_POS 0
+#define SCMI_BASE_PROTOCOL_ATTRS_NUM_AGENTS_POS 8
+
+#define SCMI_BASE_PROTOCOL_ATTRS_NUM_PROTOCOLS_MASK 0xFFU
+#define SCMI_BASE_PROTOCOL_ATTRS_NUM_AGENTS_MASK 0xFF00U
+
+#define SCMI_BASE_PROTOCOL_ATTRIBUTES(NUM_PROTOCOLS, NUM_AGENTS) \
+ ((((NUM_PROTOCOLS) << SCMI_BASE_PROTOCOL_ATTRS_NUM_PROTOCOLS_POS) & \
+ SCMI_BASE_PROTOCOL_ATTRS_NUM_PROTOCOLS_MASK) | \
+ (((NUM_AGENTS) << SCMI_BASE_PROTOCOL_ATTRS_NUM_AGENTS_POS) & \
+ SCMI_BASE_PROTOCOL_ATTRS_NUM_AGENTS_MASK))
+
+/*
+ * BASE_DISCOVER_VENDOR
+ */
+struct scmi_base_discover_vendor_p2a {
+ int32_t status;
+ char vendor_identifier[SCMI_DEFAULT_STRING_LENGTH];
+};
+
+/*
+ * BASE_DISCOVER_SUB_VENDOR
+ */
+struct scmi_base_discover_sub_vendor_p2a {
+ int32_t status;
+ char sub_vendor_identifier[SCMI_DEFAULT_STRING_LENGTH];
+};
+
+/*
+ * BASE_DISCOVER_IMPLEMENTATION_VERSION
+ * No special structure right now, see protocol_version.
+ */
+
+/*
+ * BASE_DISCOVER_LIST_PROTOCOLS
+ */
+struct scmi_base_discover_list_protocols_a2p {
+ uint32_t skip;
+};
+
+struct scmi_base_discover_list_protocols_p2a {
+ int32_t status;
+ uint32_t num_protocols;
+ uint32_t protocols[];
+};
+
+#endif /* SCMI_MSG_BASE_H */
diff --git a/drivers/scmi-msg/clock.c b/drivers/scmi-msg/clock.c
new file mode 100644
index 0000000..85bf7d2
--- /dev/null
+++ b/drivers/scmi-msg/clock.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2020, Linaro Limited
+ */
+#include <cdefs.h>
+#include <string.h>
+
+#include <drivers/scmi-msg.h>
+#include <drivers/scmi.h>
+#include <lib/utils_def.h>
+
+#include "common.h"
+
+#pragma weak plat_scmi_clock_count
+#pragma weak plat_scmi_clock_get_name
+#pragma weak plat_scmi_clock_rates_array
+#pragma weak plat_scmi_clock_rates_by_step
+#pragma weak plat_scmi_clock_get_rate
+#pragma weak plat_scmi_clock_set_rate
+#pragma weak plat_scmi_clock_get_state
+#pragma weak plat_scmi_clock_set_state
+
+static bool message_id_is_supported(unsigned int message_id);
+
+size_t plat_scmi_clock_count(unsigned int agent_id __unused)
+{
+ return 0U;
+}
+
+const char *plat_scmi_clock_get_name(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused)
+{
+ return NULL;
+}
+
+int32_t plat_scmi_clock_rates_array(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused,
+ unsigned long *rates __unused,
+ size_t *nb_elts __unused)
+{
+ return SCMI_NOT_SUPPORTED;
+}
+
+int32_t plat_scmi_clock_rates_by_step(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused,
+ unsigned long *steps __unused)
+{
+ return SCMI_NOT_SUPPORTED;
+}
+
+unsigned long plat_scmi_clock_get_rate(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused)
+{
+ return 0U;
+}
+
+int32_t plat_scmi_clock_set_rate(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused,
+ unsigned long rate __unused)
+{
+ return SCMI_NOT_SUPPORTED;
+}
+
+int32_t plat_scmi_clock_get_state(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused)
+{
+ return SCMI_NOT_SUPPORTED;
+}
+
+int32_t plat_scmi_clock_set_state(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused,
+ bool enable_not_disable __unused)
+{
+ return SCMI_NOT_SUPPORTED;
+}
+
+static void report_version(struct scmi_msg *msg)
+{
+ struct scmi_protocol_version_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .version = SCMI_PROTOCOL_VERSION_CLOCK,
+ };
+
+ if (msg->in_size != 0) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_attributes(struct scmi_msg *msg)
+{
+ size_t agent_count = plat_scmi_clock_count(msg->agent_id);
+ struct scmi_protocol_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .attributes = SCMI_CLOCK_PROTOCOL_ATTRIBUTES(1U, agent_count),
+ };
+
+ if (msg->in_size != 0) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_message_attributes(struct scmi_msg *msg)
+{
+ struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
+ struct scmi_protocol_message_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ /* For this protocol, attributes shall be zero */
+ .attributes = 0U,
+ };
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (!message_id_is_supported(in_args->message_id)) {
+ scmi_status_response(msg, SCMI_NOT_FOUND);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void scmi_clock_attributes(struct scmi_msg *msg)
+{
+ const struct scmi_clock_attributes_a2p *in_args = (void *)msg->in;
+ struct scmi_clock_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ };
+ const char *name = NULL;
+ unsigned int clock_id = 0U;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ clock_id = SPECULATION_SAFE_VALUE(in_args->clock_id);
+
+ if (clock_id >= plat_scmi_clock_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+
+ name = plat_scmi_clock_get_name(msg->agent_id, clock_id);
+ if (name == NULL) {
+ scmi_status_response(msg, SCMI_NOT_FOUND);
+ return;
+ }
+
+ COPY_NAME_IDENTIFIER(return_values.clock_name, name);
+
+ return_values.attributes = plat_scmi_clock_get_state(msg->agent_id,
+ clock_id);
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void scmi_clock_rate_get(struct scmi_msg *msg)
+{
+ const struct scmi_clock_rate_get_a2p *in_args = (void *)msg->in;
+ unsigned long rate = 0U;
+ struct scmi_clock_rate_get_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ };
+ unsigned int clock_id = 0U;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ clock_id = SPECULATION_SAFE_VALUE(in_args->clock_id);
+
+ if (clock_id >= plat_scmi_clock_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ rate = plat_scmi_clock_get_rate(msg->agent_id, clock_id);
+
+ return_values.rate[0] = (uint32_t)rate;
+ return_values.rate[1] = (uint32_t)((uint64_t)rate >> 32);
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void scmi_clock_rate_set(struct scmi_msg *msg)
+{
+ const struct scmi_clock_rate_set_a2p *in_args = (void *)msg->in;
+ unsigned long rate = 0U;
+ int32_t status = 0;
+ unsigned int clock_id = 0U;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ clock_id = SPECULATION_SAFE_VALUE(in_args->clock_id);
+
+ if (clock_id >= plat_scmi_clock_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ rate = (unsigned long)(((uint64_t)in_args->rate[1] << 32) |
+ in_args->rate[0]);
+
+ status = plat_scmi_clock_set_rate(msg->agent_id, clock_id, rate);
+
+ scmi_status_response(msg, status);
+}
+
+static void scmi_clock_config_set(struct scmi_msg *msg)
+{
+ const struct scmi_clock_config_set_a2p *in_args = (void *)msg->in;
+ int32_t status = SCMI_GENERIC_ERROR;
+ bool enable = false;
+ unsigned int clock_id = 0U;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ clock_id = SPECULATION_SAFE_VALUE(in_args->clock_id);
+
+ if (clock_id >= plat_scmi_clock_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ enable = in_args->attributes & SCMI_CLOCK_CONFIG_SET_ENABLE_MASK;
+
+ status = plat_scmi_clock_set_state(msg->agent_id, clock_id, enable);
+
+ scmi_status_response(msg, status);
+}
+
+#define RATES_ARRAY_SIZE_MAX (SCMI_PLAYLOAD_MAX - \
+ sizeof(struct scmi_clock_describe_rates_p2a))
+
+#define SCMI_RATES_BY_ARRAY(_nb_rates, _rem_rates) \
+ SCMI_CLOCK_DESCRIBE_RATES_NUM_RATES_FLAGS((_nb_rates), \
+ SCMI_CLOCK_RATE_FORMAT_LIST, \
+ (_rem_rates))
+#define SCMI_RATES_BY_STEP \
+ SCMI_CLOCK_DESCRIBE_RATES_NUM_RATES_FLAGS(3U, \
+ SCMI_CLOCK_RATE_FORMAT_RANGE, \
+ 0U)
+
+#define RATE_DESC_SIZE sizeof(struct scmi_clock_rate)
+
+static void write_rate_desc_array_in_buffer(char *dest, unsigned long *rates,
+ size_t nb_elt)
+{
+ uint32_t *out = (uint32_t *)(uintptr_t)dest;
+ size_t n;
+
+ ASSERT_SYM_PTR_ALIGN(out);
+
+ for (n = 0U; n < nb_elt; n++) {
+ out[2 * n] = (uint32_t)rates[n];
+ out[2 * n + 1] = (uint32_t)((uint64_t)rates[n] >> 32);
+ }
+}
+
+static void scmi_clock_describe_rates(struct scmi_msg *msg)
+{
+ const struct scmi_clock_describe_rates_a2p *in_args = (void *)msg->in;
+ struct scmi_clock_describe_rates_p2a p2a = {
+ .status = SCMI_SUCCESS,
+ };
+ size_t nb_rates;
+ int32_t status;
+ unsigned int clock_id;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ clock_id = SPECULATION_SAFE_VALUE(in_args->clock_id);
+
+ if (clock_id >= plat_scmi_clock_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ /* Platform may support array rate description */
+ status = plat_scmi_clock_rates_array(msg->agent_id, clock_id, NULL,
+ &nb_rates);
+ if (status == SCMI_SUCCESS) {
+ /* Currently 12 cells mex, so it's affordable for the stack */
+ unsigned long plat_rates[RATES_ARRAY_SIZE_MAX / RATE_DESC_SIZE];
+ size_t max_nb = RATES_ARRAY_SIZE_MAX / RATE_DESC_SIZE;
+ size_t ret_nb = MIN(nb_rates - in_args->rate_index, max_nb);
+ size_t rem_nb = nb_rates - in_args->rate_index - ret_nb;
+
+ status = plat_scmi_clock_rates_array(msg->agent_id, clock_id,
+ plat_rates, &ret_nb);
+ if (status == SCMI_SUCCESS) {
+ write_rate_desc_array_in_buffer(msg->out + sizeof(p2a),
+ plat_rates, ret_nb);
+
+ p2a.num_rates_flags = SCMI_RATES_BY_ARRAY(ret_nb,
+ rem_nb);
+ p2a.status = SCMI_SUCCESS;
+
+ memcpy(msg->out, &p2a, sizeof(p2a));
+ msg->out_size_out = sizeof(p2a) +
+ ret_nb * RATE_DESC_SIZE;
+ }
+ } else if (status == SCMI_NOT_SUPPORTED) {
+ unsigned long triplet[3] = { 0U, 0U, 0U };
+
+ /* Platform may support min§max/step triplet description */
+ status = plat_scmi_clock_rates_by_step(msg->agent_id, clock_id,
+ triplet);
+ if (status == SCMI_SUCCESS) {
+ write_rate_desc_array_in_buffer(msg->out + sizeof(p2a),
+ triplet, 3U);
+
+ p2a.num_rates_flags = SCMI_RATES_BY_STEP;
+ p2a.status = SCMI_SUCCESS;
+
+ memcpy(msg->out, &p2a, sizeof(p2a));
+ msg->out_size_out = sizeof(p2a) + (3U * RATE_DESC_SIZE);
+ }
+ } else {
+ /* Fallthrough generic exit sequence below with error status */
+ }
+
+ if (status != SCMI_SUCCESS) {
+ scmi_status_response(msg, status);
+ } else {
+ /*
+ * Message payload is already writen to msg->out, and
+ * msg->out_size_out updated.
+ */
+ }
+}
+
+static const scmi_msg_handler_t scmi_clock_handler_table[] = {
+ [SCMI_PROTOCOL_VERSION] = report_version,
+ [SCMI_PROTOCOL_ATTRIBUTES] = report_attributes,
+ [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes,
+ [SCMI_CLOCK_ATTRIBUTES] = scmi_clock_attributes,
+ [SCMI_CLOCK_DESCRIBE_RATES] = scmi_clock_describe_rates,
+ [SCMI_CLOCK_RATE_SET] = scmi_clock_rate_set,
+ [SCMI_CLOCK_RATE_GET] = scmi_clock_rate_get,
+ [SCMI_CLOCK_CONFIG_SET] = scmi_clock_config_set,
+};
+
+static bool message_id_is_supported(unsigned int message_id)
+{
+ return (message_id < ARRAY_SIZE(scmi_clock_handler_table)) &&
+ (scmi_clock_handler_table[message_id] != NULL);
+}
+
+scmi_msg_handler_t scmi_msg_get_clock_handler(struct scmi_msg *msg)
+{
+ const size_t array_size = ARRAY_SIZE(scmi_clock_handler_table);
+ unsigned int message_id = SPECULATION_SAFE_VALUE(msg->message_id);
+
+ if (message_id >= array_size) {
+ VERBOSE("Clock handle not found %u", msg->message_id);
+ return NULL;
+ }
+
+ return scmi_clock_handler_table[message_id];
+}
diff --git a/drivers/scmi-msg/clock.h b/drivers/scmi-msg/clock.h
new file mode 100644
index 0000000..a637934
--- /dev/null
+++ b/drivers/scmi-msg/clock.h
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Linaro Limited
+ */
+
+#ifndef SCMI_MSG_CLOCK_H
+#define SCMI_MSG_CLOCK_H
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#define SCMI_PROTOCOL_VERSION_CLOCK 0x20000U
+
+/*
+ * Identifiers of the SCMI Clock Management Protocol commands
+ */
+enum scmi_clock_command_id {
+ SCMI_CLOCK_ATTRIBUTES = 0x003,
+ SCMI_CLOCK_DESCRIBE_RATES = 0x004,
+ SCMI_CLOCK_RATE_SET = 0x005,
+ SCMI_CLOCK_RATE_GET = 0x006,
+ SCMI_CLOCK_CONFIG_SET = 0x007,
+};
+
+/* Protocol attributes */
+#define SCMI_CLOCK_CLOCK_COUNT_MASK GENMASK(15, 0)
+#define SCMI_CLOCK_MAX_PENDING_TRANSITIONS_MASK GENMASK(23, 16)
+
+#define SCMI_CLOCK_PROTOCOL_ATTRIBUTES(_max_pending, _clk_count) \
+ ((((_max_pending) << 16) & SCMI_CLOCK_MAX_PENDING_TRANSITIONS_MASK) | \
+ (((_clk_count) & SCMI_CLOCK_CLOCK_COUNT_MASK)))
+
+struct scmi_clock_attributes_a2p {
+ uint32_t clock_id;
+};
+
+#define SCMI_CLOCK_NAME_LENGTH_MAX 16U
+
+struct scmi_clock_attributes_p2a {
+ int32_t status;
+ uint32_t attributes;
+ char clock_name[SCMI_CLOCK_NAME_LENGTH_MAX];
+};
+
+/*
+ * Clock Rate Get
+ */
+
+struct scmi_clock_rate_get_a2p {
+ uint32_t clock_id;
+};
+
+struct scmi_clock_rate_get_p2a {
+ int32_t status;
+ uint32_t rate[2];
+};
+
+/*
+ * Clock Rate Set
+ */
+
+/* If set, set the new clock rate asynchronously */
+#define SCMI_CLOCK_RATE_SET_ASYNC_POS 0
+/* If set, do not send a delayed asynchronous response */
+#define SCMI_CLOCK_RATE_SET_NO_DELAYED_RESPONSE_POS 1
+/* Round up, if set, otherwise round down */
+#define SCMI_CLOCK_RATE_SET_ROUND_UP_POS 2
+/* If set, the platform chooses the appropriate rounding mode */
+#define SCMI_CLOCK_RATE_SET_ROUND_AUTO_POS 3
+
+#define SCMI_CLOCK_RATE_SET_ASYNC_MASK \
+ BIT(SCMI_CLOCK_RATE_SET_ASYNC_POS)
+#define SCMI_CLOCK_RATE_SET_NO_DELAYED_RESPONSE_MASK \
+ BIT(SCMI_CLOCK_RATE_SET_NO_DELAYED_RESPONSE_POS)
+#define SCMI_CLOCK_RATE_SET_ROUND_UP_MASK \
+ BIT(SCMI_CLOCK_RATE_SET_ROUND_UP_POS)
+#define SCMI_CLOCK_RATE_SET_ROUND_AUTO_MASK \
+ BIT(SCMI_CLOCK_RATE_SET_ROUND_AUTO_POS)
+
+struct scmi_clock_rate_set_a2p {
+ uint32_t flags;
+ uint32_t clock_id;
+ uint32_t rate[2];
+};
+
+struct scmi_clock_rate_set_p2a {
+ int32_t status;
+};
+
+/*
+ * Clock Config Set
+ */
+
+#define SCMI_CLOCK_CONFIG_SET_ENABLE_POS 0
+
+#define SCMI_CLOCK_CONFIG_SET_ENABLE_MASK \
+ BIT(SCMI_CLOCK_CONFIG_SET_ENABLE_POS)
+
+struct scmi_clock_config_set_a2p {
+ uint32_t clock_id;
+ uint32_t attributes;
+};
+
+struct scmi_clock_config_set_p2a {
+ int32_t status;
+};
+
+/*
+ * Clock Describe Rates
+ */
+
+#define SCMI_CLOCK_RATE_FORMAT_RANGE 1U
+#define SCMI_CLOCK_RATE_FORMAT_LIST 0U
+
+#define SCMI_CLOCK_DESCRIBE_RATES_REMAINING_MASK GENMASK_32(31, 16)
+#define SCMI_CLOCK_DESCRIBE_RATES_REMAINING_POS 16
+
+#define SCMI_CLOCK_DESCRIBE_RATES_FORMAT_MASK BIT(12)
+#define SCMI_CLOCK_DESCRIBE_RATES_FORMAT_POS 12
+
+#define SCMI_CLOCK_DESCRIBE_RATES_COUNT_MASK GENMASK_32(11, 0)
+
+#define SCMI_CLOCK_DESCRIBE_RATES_NUM_RATES_FLAGS(_count, _fmt, _rem_rates) \
+ ( \
+ ((_count) & SCMI_CLOCK_DESCRIBE_RATES_COUNT_MASK) | \
+ (((_rem_rates) << SCMI_CLOCK_DESCRIBE_RATES_REMAINING_POS) & \
+ SCMI_CLOCK_DESCRIBE_RATES_REMAINING_MASK) | \
+ (((_fmt) << SCMI_CLOCK_DESCRIBE_RATES_FORMAT_POS) & \
+ SCMI_CLOCK_DESCRIBE_RATES_FORMAT_MASK) \
+ )
+
+struct scmi_clock_rate {
+ uint32_t low;
+ uint32_t high;
+};
+
+struct scmi_clock_describe_rates_a2p {
+ uint32_t clock_id;
+ uint32_t rate_index;
+};
+
+struct scmi_clock_describe_rates_p2a {
+ int32_t status;
+ uint32_t num_rates_flags;
+ struct scmi_clock_rate rates[];
+};
+
+#endif /* SCMI_MSG_CLOCK_H */
diff --git a/drivers/scmi-msg/common.h b/drivers/scmi-msg/common.h
new file mode 100644
index 0000000..62f3087
--- /dev/null
+++ b/drivers/scmi-msg/common.h
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2020, Linaro Limited
+ */
+#ifndef SCMI_MSG_COMMON_H
+#define SCMI_MSG_COMMON_H
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "base.h"
+#include "clock.h"
+#include "power_domain.h"
+#include "reset_domain.h"
+
+#define SCMI_VERSION 0x20000U
+#define SCMI_IMPL_VERSION 0U
+
+#define SCMI_PLAYLOAD_MAX 92U
+
+/*
+ * Copy name identifier in target buffer following the SCMI specification
+ * that state name identifier shall be a null terminated string.
+ */
+#define COPY_NAME_IDENTIFIER(_dst_array, _name) \
+ do { \
+ assert(strlen(_name) < sizeof(_dst_array)); \
+ strlcpy((_dst_array), (_name), sizeof(_dst_array)); \
+ } while (0)
+
+/* Common command identifiers shared by all procotols */
+enum scmi_common_message_id {
+ SCMI_PROTOCOL_VERSION = 0x000,
+ SCMI_PROTOCOL_ATTRIBUTES = 0x001,
+ SCMI_PROTOCOL_MESSAGE_ATTRIBUTES = 0x002
+};
+
+/* Common platform-to-agent (p2a) PROTOCOL_VERSION structure */
+struct scmi_protocol_version_p2a {
+ int32_t status;
+ uint32_t version;
+};
+
+/* Generic platform-to-agent (p2a) PROTOCOL_ATTRIBUTES structure */
+struct scmi_protocol_attributes_p2a {
+ int32_t status;
+ uint32_t attributes;
+};
+
+/* Generic agent-to-platform (a2p) PROTOCOL_MESSAGE_ATTRIBUTES structure */
+struct scmi_protocol_message_attributes_a2p {
+ uint32_t message_id;
+};
+
+/* Generic platform-to-agent (p2a) PROTOCOL_MESSAGE_ATTRIBUTES structure */
+struct scmi_protocol_message_attributes_p2a {
+ int32_t status;
+ uint32_t attributes;
+};
+
+/*
+ * struct scmi_msg - SCMI message context
+ *
+ * @agent_id: SCMI agent ID, safely set from secure world
+ * @protocol_id: SCMI protocol ID for the related message, set by caller agent
+ * @message_id: SCMI message ID for the related message, set by caller agent
+ * @in: Address of the incoming message payload copied in secure memory
+ * @in_size: Byte length of the incoming message payload, set by caller agent
+ * @out: Address of of the output message payload message in non-secure memory
+ * @out_size: Byte length of the provisionned output buffer
+ * @out_size_out: Byte length of the output message payload
+ */
+struct scmi_msg {
+ unsigned int agent_id;
+ unsigned int protocol_id;
+ unsigned int message_id;
+ char *in;
+ size_t in_size;
+ char *out;
+ size_t out_size;
+ size_t out_size_out;
+};
+
+/*
+ * Type scmi_msg_handler_t is used by procotol drivers to safely find
+ * the handler function for the incoming message ID.
+ */
+typedef void (*scmi_msg_handler_t)(struct scmi_msg *msg);
+
+/*
+ * scmi_msg_get_base_handler - Return a handler for a base message
+ * @msg - message to process
+ * Return a function handler for the message or NULL
+ */
+scmi_msg_handler_t scmi_msg_get_base_handler(struct scmi_msg *msg);
+
+/*
+ * scmi_msg_get_clock_handler - Return a handler for a clock message
+ * @msg - message to process
+ * Return a function handler for the message or NULL
+ */
+scmi_msg_handler_t scmi_msg_get_clock_handler(struct scmi_msg *msg);
+
+/*
+ * scmi_msg_get_rstd_handler - Return a handler for a reset domain message
+ * @msg - message to process
+ * Return a function handler for the message or NULL
+ */
+scmi_msg_handler_t scmi_msg_get_rstd_handler(struct scmi_msg *msg);
+
+/*
+ * scmi_msg_get_pd_handler - Return a handler for a power domain message
+ * @msg - message to process
+ * Return a function handler for the message or NULL
+ */
+scmi_msg_handler_t scmi_msg_get_pd_handler(struct scmi_msg *msg);
+
+/*
+ * Process Read, process and write response for input SCMI message
+ *
+ * @msg: SCMI message context
+ */
+void scmi_process_message(struct scmi_msg *msg);
+
+/*
+ * Write SCMI response payload to output message shared memory
+ *
+ * @msg: SCMI message context
+ * @payload: Output message payload
+ * @size: Byte size of output message payload
+ */
+void scmi_write_response(struct scmi_msg *msg, void *payload, size_t size);
+
+/*
+ * Write status only SCMI response payload to output message shared memory
+ *
+ * @msg: SCMI message context
+ * @status: SCMI status value returned to caller
+ */
+void scmi_status_response(struct scmi_msg *msg, int32_t status);
+#endif /* SCMI_MSG_COMMON_H */
diff --git a/drivers/scmi-msg/entry.c b/drivers/scmi-msg/entry.c
new file mode 100644
index 0000000..399115c
--- /dev/null
+++ b/drivers/scmi-msg/entry.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2020, Linaro Limited
+ */
+
+#include <assert.h>
+
+#include <drivers/scmi-msg.h>
+#include <drivers/scmi.h>
+
+#include "common.h"
+
+#pragma weak scmi_msg_get_clock_handler
+#pragma weak scmi_msg_get_rstd_handler
+#pragma weak scmi_msg_get_pd_handler
+#pragma weak scmi_msg_get_voltage_handler
+
+scmi_msg_handler_t scmi_msg_get_clock_handler(struct scmi_msg *msg __unused)
+{
+ return NULL;
+}
+
+scmi_msg_handler_t scmi_msg_get_rstd_handler(struct scmi_msg *msg __unused)
+{
+ return NULL;
+}
+
+scmi_msg_handler_t scmi_msg_get_pd_handler(struct scmi_msg *msg __unused)
+{
+ return NULL;
+}
+
+scmi_msg_handler_t scmi_msg_get_voltage_handler(struct scmi_msg *msg __unused)
+{
+ return NULL;
+}
+
+void scmi_status_response(struct scmi_msg *msg, int32_t status)
+{
+ assert(msg->out && msg->out_size >= sizeof(int32_t));
+
+ memcpy(msg->out, &status, sizeof(int32_t));
+ msg->out_size_out = sizeof(int32_t);
+}
+
+void scmi_write_response(struct scmi_msg *msg, void *payload, size_t size)
+{
+ /*
+ * Output payload shall be at least the size of the status
+ * Output buffer shall be at least be the size of the status
+ * Output paylaod shall fit in output buffer
+ */
+ assert(payload && size >= sizeof(int32_t) && size <= msg->out_size &&
+ msg->out && msg->out_size >= sizeof(int32_t));
+
+ memcpy(msg->out, payload, size);
+ msg->out_size_out = size;
+}
+
+void scmi_process_message(struct scmi_msg *msg)
+{
+ scmi_msg_handler_t handler = NULL;
+
+ switch (msg->protocol_id) {
+ case SCMI_PROTOCOL_ID_BASE:
+ handler = scmi_msg_get_base_handler(msg);
+ break;
+ case SCMI_PROTOCOL_ID_CLOCK:
+ handler = scmi_msg_get_clock_handler(msg);
+ break;
+ case SCMI_PROTOCOL_ID_RESET_DOMAIN:
+ handler = scmi_msg_get_rstd_handler(msg);
+ break;
+ case SCMI_PROTOCOL_ID_POWER_DOMAIN:
+ handler = scmi_msg_get_pd_handler(msg);
+ break;
+ default:
+ break;
+ }
+
+ if (handler) {
+ handler(msg);
+ return;
+ }
+
+ ERROR("Agent %u Protocol 0x%x Message 0x%x: not supported\n",
+ msg->agent_id, msg->protocol_id, msg->message_id);
+
+ scmi_status_response(msg, SCMI_NOT_SUPPORTED);
+}
diff --git a/drivers/scmi-msg/power_domain.c b/drivers/scmi-msg/power_domain.c
new file mode 100644
index 0000000..87c41dd
--- /dev/null
+++ b/drivers/scmi-msg/power_domain.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2020, Linaro Limited
+ */
+#include <cdefs.h>
+#include <string.h>
+
+#include <drivers/scmi-msg.h>
+#include <drivers/scmi.h>
+#include <lib/utils_def.h>
+
+#include "common.h"
+
+#pragma weak plat_scmi_pd_count
+#pragma weak plat_scmi_pd_get_name
+#pragma weak plat_scmi_pd_get_state
+#pragma weak plat_scmi_pd_set_state
+#pragma weak plat_scmi_pd_statistics
+#pragma weak plat_scmi_pd_get_attributes
+
+static bool message_id_is_supported(unsigned int message_id);
+
+size_t plat_scmi_pd_count(unsigned int agent_id __unused)
+{
+ return 0U;
+}
+
+const char *plat_scmi_pd_get_name(unsigned int agent_id __unused,
+ unsigned int pd_id __unused)
+{
+ return NULL;
+}
+
+unsigned int plat_scmi_pd_statistics(unsigned int agent_id __unused,
+ unsigned long *pd_id __unused)
+{
+ return 0U;
+}
+
+unsigned int plat_scmi_pd_get_attributes(unsigned int agent_id __unused,
+ unsigned int pd_id __unused)
+{
+ return 0U;
+}
+
+unsigned int plat_scmi_pd_get_state(unsigned int agent_id __unused,
+ unsigned int pd_id __unused)
+{
+ return 0U;
+}
+
+int32_t plat_scmi_pd_set_state(unsigned int agent_id __unused,
+ unsigned int flags __unused,
+ unsigned int pd_id __unused,
+ unsigned int state __unused)
+{
+ return SCMI_NOT_SUPPORTED;
+}
+
+static void report_version(struct scmi_msg *msg)
+{
+ struct scmi_protocol_version_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .version = SCMI_PROTOCOL_VERSION_PD,
+ };
+
+ if (msg->in_size != 0) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_attributes(struct scmi_msg *msg)
+{
+ unsigned long addr = 0UL;
+ unsigned int len;
+
+ struct scmi_protocol_attributes_p2a_pd return_values = {
+ .status = SCMI_SUCCESS,
+ };
+
+ if (msg->in_size != 0) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ return_values.attributes = plat_scmi_pd_count(msg->agent_id);
+ len = plat_scmi_pd_statistics(msg->agent_id, &addr);
+ if (len != 0U) {
+ return_values.statistics_addr_low = (unsigned int)addr;
+ return_values.statistics_addr_high = (uint32_t)(addr >> 32);
+ return_values.statistics_len = len;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_message_attributes(struct scmi_msg *msg)
+{
+ struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
+ struct scmi_protocol_message_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ /* For this protocol, attributes shall be zero */
+ .attributes = 0U,
+ };
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (!message_id_is_supported(in_args->message_id)) {
+ scmi_status_response(msg, SCMI_NOT_FOUND);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void scmi_pd_attributes(struct scmi_msg *msg)
+{
+ const struct scmi_pd_attributes_a2p *in_args = (void *)msg->in;
+ struct scmi_pd_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ };
+ const char *name = NULL;
+ unsigned int pd_id = 0U;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ pd_id = SPECULATION_SAFE_VALUE(in_args->pd_id);
+
+ if (pd_id >= plat_scmi_pd_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ name = plat_scmi_pd_get_name(msg->agent_id, pd_id);
+ if (name == NULL) {
+ scmi_status_response(msg, SCMI_NOT_FOUND);
+ return;
+ }
+
+ COPY_NAME_IDENTIFIER(return_values.pd_name, name);
+
+ return_values.attributes = plat_scmi_pd_get_attributes(msg->agent_id, pd_id);
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void scmi_pd_state_get(struct scmi_msg *msg)
+{
+ const struct scmi_pd_state_get_a2p *in_args = (void *)msg->in;
+ unsigned int state = 0U;
+ struct scmi_pd_state_get_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ };
+ unsigned int pd_id = 0U;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ pd_id = SPECULATION_SAFE_VALUE(in_args->pd_id);
+
+ if (pd_id >= plat_scmi_pd_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ state = plat_scmi_pd_get_state(msg->agent_id, pd_id);
+
+ return_values.power_state = state;
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void scmi_pd_state_set(struct scmi_msg *msg)
+{
+ const struct scmi_pd_state_set_a2p *in_args = (void *)msg->in;
+ unsigned int flags = 0U;
+ int32_t status = 0;
+ unsigned int pd_id = 0U;
+ unsigned int state = 0U;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ pd_id = SPECULATION_SAFE_VALUE(in_args->pd_id);
+
+ if (pd_id >= plat_scmi_pd_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ flags = SPECULATION_SAFE_VALUE(in_args->flags);
+ state = SPECULATION_SAFE_VALUE(in_args->power_state);
+
+ status = plat_scmi_pd_set_state(msg->agent_id, flags, pd_id, state);
+
+ scmi_status_response(msg, status);
+}
+
+static const scmi_msg_handler_t scmi_pd_handler_table[] = {
+ [SCMI_PROTOCOL_VERSION] = report_version,
+ [SCMI_PROTOCOL_ATTRIBUTES] = report_attributes,
+ [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes,
+ [SCMI_PD_ATTRIBUTES] = scmi_pd_attributes,
+ [SCMI_PD_STATE_SET] = scmi_pd_state_set,
+ [SCMI_PD_STATE_GET] = scmi_pd_state_get,
+};
+
+static bool message_id_is_supported(unsigned int message_id)
+{
+ return (message_id < ARRAY_SIZE(scmi_pd_handler_table)) &&
+ (scmi_pd_handler_table[message_id] != NULL);
+}
+
+scmi_msg_handler_t scmi_msg_get_pd_handler(struct scmi_msg *msg)
+{
+ const size_t array_size = ARRAY_SIZE(scmi_pd_handler_table);
+ unsigned int message_id = SPECULATION_SAFE_VALUE(msg->message_id);
+
+ if (message_id >= array_size) {
+ VERBOSE("pd handle not found %u", msg->message_id);
+ return NULL;
+ }
+
+ return scmi_pd_handler_table[message_id];
+}
diff --git a/drivers/scmi-msg/power_domain.h b/drivers/scmi-msg/power_domain.h
new file mode 100644
index 0000000..48551fd
--- /dev/null
+++ b/drivers/scmi-msg/power_domain.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright 2021 NXP
+ */
+
+#ifndef SCMI_MSG_PD_H
+#define SCMI_MSG_PD_H
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#define SCMI_PROTOCOL_VERSION_PD 0x21000U
+
+/*
+ * Identifiers of the SCMI POWER DOMAIN Protocol commands
+ */
+enum scmi_pd_command_id {
+ SCMI_PD_ATTRIBUTES = 0x003,
+ SCMI_PD_STATE_SET = 0x004,
+ SCMI_PD_STATE_GET = 0x005,
+};
+
+/* Protocol attributes */
+struct scmi_pd_attributes_a2p {
+ uint32_t pd_id;
+};
+
+struct scmi_protocol_attributes_p2a_pd {
+ int32_t status;
+ uint32_t attributes;
+ uint32_t statistics_addr_low;
+ uint32_t statistics_addr_high;
+ uint32_t statistics_len;
+};
+
+#define SCMI_PD_NAME_LENGTH_MAX 16U
+
+struct scmi_pd_attributes_p2a {
+ int32_t status;
+ uint32_t attributes;
+ char pd_name[SCMI_PD_NAME_LENGTH_MAX];
+};
+
+/*
+ * Power Domain State Get
+ */
+
+struct scmi_pd_state_get_a2p {
+ uint32_t pd_id;
+};
+
+struct scmi_pd_state_get_p2a {
+ int32_t status;
+ uint32_t power_state;
+};
+
+/*
+ * Power domain State Set
+ */
+
+struct scmi_pd_state_set_a2p {
+ uint32_t flags;
+ uint32_t pd_id;
+ uint32_t power_state;
+};
+
+struct scmi_pd_state_set_p2a {
+ int32_t status;
+};
+
+#endif /* SCMI_MSG_PD_H */
diff --git a/drivers/scmi-msg/reset_domain.c b/drivers/scmi-msg/reset_domain.c
new file mode 100644
index 0000000..76ac47e
--- /dev/null
+++ b/drivers/scmi-msg/reset_domain.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2020, Linaro Limited
+ */
+#include <cdefs.h>
+#include <string.h>
+
+#include <drivers/scmi-msg.h>
+#include <drivers/scmi.h>
+#include <lib/utils.h>
+#include <lib/utils_def.h>
+
+#include "common.h"
+
+static bool message_id_is_supported(unsigned int message_id);
+
+#pragma weak plat_scmi_rstd_count
+#pragma weak plat_scmi_rstd_get_name
+#pragma weak plat_scmi_rstd_autonomous
+#pragma weak plat_scmi_rstd_set_state
+
+size_t plat_scmi_rstd_count(unsigned int agent_id __unused)
+{
+ return 0U;
+}
+
+const char *plat_scmi_rstd_get_name(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused)
+{
+ return NULL;
+}
+
+int32_t plat_scmi_rstd_autonomous(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused,
+ unsigned int state __unused)
+{
+ return SCMI_NOT_SUPPORTED;
+}
+
+int32_t plat_scmi_rstd_set_state(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused,
+ bool assert_not_deassert __unused)
+{
+ return SCMI_NOT_SUPPORTED;
+}
+
+static void report_version(struct scmi_msg *msg)
+{
+ struct scmi_protocol_version_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .version = SCMI_PROTOCOL_VERSION_RESET_DOMAIN,
+ };
+
+ if (msg->in_size != 0U) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_attributes(struct scmi_msg *msg)
+{
+ struct scmi_protocol_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .attributes = plat_scmi_rstd_count(msg->agent_id),
+ };
+
+ if (msg->in_size != 0U) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_message_attributes(struct scmi_msg *msg)
+{
+ struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
+ struct scmi_protocol_message_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ /* For this protocol, attributes shall be zero */
+ .attributes = 0U,
+ };
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (!message_id_is_supported(in_args->message_id)) {
+ scmi_status_response(msg, SCMI_NOT_FOUND);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void reset_domain_attributes(struct scmi_msg *msg)
+{
+ struct scmi_reset_domain_attributes_a2p *in_args = (void *)msg->in;
+ struct scmi_reset_domain_attributes_p2a return_values;
+ const char *name = NULL;
+ unsigned int domain_id = 0U;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ domain_id = SPECULATION_SAFE_VALUE(in_args->domain_id);
+
+ if (domain_id >= plat_scmi_rstd_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ name = plat_scmi_rstd_get_name(msg->agent_id, domain_id);
+ if (name == NULL) {
+ scmi_status_response(msg, SCMI_NOT_FOUND);
+ return;
+ }
+
+ zeromem(&return_values, sizeof(return_values));
+ COPY_NAME_IDENTIFIER(return_values.name, name);
+ return_values.status = SCMI_SUCCESS;
+ return_values.flags = 0U; /* Async and Notif are not supported */
+ return_values.latency = SCMI_RESET_DOMAIN_ATTR_UNK_LAT;
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void reset_request(struct scmi_msg *msg)
+{
+ struct scmi_reset_domain_request_a2p *in_args = (void *)msg->in;
+ struct scmi_reset_domain_request_p2a out_args = {
+ .status = SCMI_SUCCESS,
+ };
+ unsigned int domain_id = 0U;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ domain_id = SPECULATION_SAFE_VALUE(in_args->domain_id);
+
+ if (domain_id >= plat_scmi_rstd_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_NOT_FOUND);
+ return;
+ }
+
+ if ((in_args->flags & SCMI_RESET_DOMAIN_AUTO) != 0U) {
+ out_args.status = plat_scmi_rstd_autonomous(msg->agent_id,
+ domain_id,
+ in_args->reset_state);
+ } else if ((in_args->flags & SCMI_RESET_DOMAIN_EXPLICIT) != 0U) {
+ out_args.status = plat_scmi_rstd_set_state(msg->agent_id,
+ domain_id, true);
+ } else {
+ out_args.status = plat_scmi_rstd_set_state(msg->agent_id,
+ domain_id, false);
+ }
+
+ if (out_args.status != SCMI_SUCCESS) {
+ scmi_status_response(msg, out_args.status);
+ } else {
+ scmi_write_response(msg, &out_args, sizeof(out_args));
+ }
+}
+
+static const scmi_msg_handler_t scmi_rstd_handler_table[] = {
+ [SCMI_PROTOCOL_VERSION] = report_version,
+ [SCMI_PROTOCOL_ATTRIBUTES] = report_attributes,
+ [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes,
+ [SCMI_RESET_DOMAIN_ATTRIBUTES] = reset_domain_attributes,
+ [SCMI_RESET_DOMAIN_REQUEST] = reset_request,
+};
+
+static bool message_id_is_supported(unsigned int message_id)
+{
+ return (message_id < ARRAY_SIZE(scmi_rstd_handler_table)) &&
+ (scmi_rstd_handler_table[message_id] != NULL);
+}
+
+scmi_msg_handler_t scmi_msg_get_rstd_handler(struct scmi_msg *msg)
+{
+ unsigned int message_id = SPECULATION_SAFE_VALUE(msg->message_id);
+
+ if (message_id >= ARRAY_SIZE(scmi_rstd_handler_table)) {
+ VERBOSE("Reset domain handle not found %u\n", msg->message_id);
+ return NULL;
+ }
+
+ return scmi_rstd_handler_table[message_id];
+}
diff --git a/drivers/scmi-msg/reset_domain.h b/drivers/scmi-msg/reset_domain.h
new file mode 100644
index 0000000..47bee5e
--- /dev/null
+++ b/drivers/scmi-msg/reset_domain.h
@@ -0,0 +1,122 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Linaro Limited
+ */
+#ifndef SCMI_MSG_RESET_DOMAIN_H
+#define SCMI_MSG_RESET_DOMAIN_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#define SCMI_PROTOCOL_VERSION_RESET_DOMAIN 0x10000U
+
+#define SCMI_RESET_STATE_ARCH BIT(31)
+#define SCMI_RESET_STATE_IMPL 0U
+
+/*
+ * Identifiers of the SCMI Reset Domain Management Protocol commands
+ */
+enum scmi_reset_domain_command_id {
+ SCMI_RESET_DOMAIN_ATTRIBUTES = 0x03,
+ SCMI_RESET_DOMAIN_REQUEST = 0x04,
+ SCMI_RESET_DOMAIN_NOTIFY = 0x05,
+};
+
+/*
+ * Identifiers of the SCMI Reset Domain Management Protocol responses
+ */
+enum scmi_reset_domain_response_id {
+ SCMI_RESET_ISSUED = 0x00,
+ SCMI_RESET_COMPLETE = 0x04,
+};
+
+/*
+ * PROTOCOL_ATTRIBUTES
+ */
+
+#define SCMI_RESET_DOMAIN_COUNT_MASK GENMASK_32(15, 0)
+
+struct scmi_reset_domain_protocol_attributes_p2a {
+ int32_t status;
+ uint32_t attributes;
+};
+
+/* Value for scmi_reset_domain_attributes_p2a:flags */
+#define SCMI_RESET_DOMAIN_ATTR_ASYNC BIT(31)
+#define SCMI_RESET_DOMAIN_ATTR_NOTIF BIT(30)
+
+/* Value for scmi_reset_domain_attributes_p2a:latency */
+#define SCMI_RESET_DOMAIN_ATTR_UNK_LAT 0x7fffffffU
+#define SCMI_RESET_DOMAIN_ATTR_MAX_LAT 0x7ffffffeU
+
+/* Macro for scmi_reset_domain_attributes_p2a:name */
+#define SCMI_RESET_DOMAIN_ATTR_NAME_SZ 16U
+
+struct scmi_reset_domain_attributes_a2p {
+ uint32_t domain_id;
+};
+
+struct scmi_reset_domain_attributes_p2a {
+ int32_t status;
+ uint32_t flags;
+ uint32_t latency;
+ char name[SCMI_RESET_DOMAIN_ATTR_NAME_SZ];
+};
+
+/*
+ * RESET
+ */
+
+/* Values for scmi_reset_domain_request_a2p:flags */
+#define SCMI_RESET_DOMAIN_ASYNC BIT(2)
+#define SCMI_RESET_DOMAIN_EXPLICIT BIT(1)
+#define SCMI_RESET_DOMAIN_AUTO BIT(0)
+
+struct scmi_reset_domain_request_a2p {
+ uint32_t domain_id;
+ uint32_t flags;
+ uint32_t reset_state;
+};
+
+struct scmi_reset_domain_request_p2a {
+ int32_t status;
+};
+
+/*
+ * RESET_NOTIFY
+ */
+
+/* Values for scmi_reset_notify_p2a:flags */
+#define SCMI_RESET_DOMAIN_DO_NOTIFY BIT(0)
+
+struct scmi_reset_domain_notify_a2p {
+ uint32_t domain_id;
+ uint32_t notify_enable;
+};
+
+struct scmi_reset_domain_notify_p2a {
+ int32_t status;
+};
+
+/*
+ * RESET_COMPLETE
+ */
+
+struct scmi_reset_domain_complete_p2a {
+ int32_t status;
+ uint32_t domain_id;
+};
+
+/*
+ * RESET_ISSUED
+ */
+
+struct scmi_reset_domain_issued_p2a {
+ uint32_t domain_id;
+ uint32_t reset_state;
+};
+
+#endif /* SCMI_MSG_RESET_DOMAIN_H */
diff --git a/drivers/scmi-msg/smt.c b/drivers/scmi-msg/smt.c
new file mode 100644
index 0000000..9b079c7
--- /dev/null
+++ b/drivers/scmi-msg/smt.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2020, Linaro Limited
+ */
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <drivers/scmi-msg.h>
+#include <drivers/scmi.h>
+#include <lib/cassert.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#include "common.h"
+
+/* Legacy SMT/SCMI messages are 128 bytes at most including SMT header */
+#define SCMI_PLAYLOAD_MAX 92U
+#define SCMI_PLAYLOAD_U32_MAX (SCMI_PLAYLOAD_MAX / sizeof(uint32_t))
+
+/**
+ * struct smt_header - SMT formatted header for SMT base shared memory transfer
+ *
+ * @status: Bit flags, see SMT_STATUS_*
+ * @flags: Bit flags, see SMT_FLAG_*
+ * @length: Byte size of message payload (variable) + ::message_header (32bit)
+ * payload: SCMI message payload data
+ */
+struct smt_header {
+ uint32_t reserved0;
+ uint32_t status;
+ uint64_t reserved1;
+ uint32_t flags;
+ uint32_t length; /* message_header + payload */
+ uint32_t message_header;
+ uint32_t payload[];
+};
+
+CASSERT(SCMI_PLAYLOAD_MAX + sizeof(struct smt_header) <= SMT_BUF_SLOT_SIZE,
+ assert_scmi_message_max_length_fits_in_smt_buffer_slot);
+
+/* Flag set in smt_header::status when SMT does not contain pending message */
+#define SMT_STATUS_FREE BIT_32(0)
+/* Flag set in smt_header::status when SMT reports an error */
+#define SMT_STATUS_ERROR BIT_32(1)
+
+/* Flag set in smt_header::flags when SMT uses interrupts */
+#define SMT_FLAG_INTR_ENABLED BIT_32(1)
+
+/* Bit fields packed in smt_header::message_header */
+#define SMT_MSG_ID_MASK GENMASK_32(7, 0)
+#define SMT_HDR_MSG_ID(_hdr) ((_hdr) & SMT_MSG_ID_MASK)
+
+#define SMT_MSG_TYPE_MASK GENMASK_32(9, 8)
+#define SMT_HDR_TYPE_ID(_hdr) (((_hdr) & SMT_MSG_TYPE_MASK) >> 8)
+
+#define SMT_MSG_PROT_ID_MASK GENMASK_32(17, 10)
+#define SMT_HDR_PROT_ID(_hdr) (((_hdr) & SMT_MSG_PROT_ID_MASK) >> 10)
+
+/*
+ * Provision input message payload buffers for fastcall SMC context entries
+ * and for interrupt context execution entries.
+ */
+static uint32_t fast_smc_payload[PLATFORM_CORE_COUNT][SCMI_PLAYLOAD_U32_MAX];
+static uint32_t interrupt_payload[PLATFORM_CORE_COUNT][SCMI_PLAYLOAD_U32_MAX];
+
+/* SMP protection on channel access */
+static struct spinlock smt_channels_lock;
+
+/* If channel is not busy, set busy and return true, otherwise return false */
+static bool channel_set_busy(struct scmi_msg_channel *chan)
+{
+ bool channel_is_busy;
+
+ spin_lock(&smt_channels_lock);
+
+ channel_is_busy = chan->busy;
+
+ if (!channel_is_busy) {
+ chan->busy = true;
+ }
+
+ spin_unlock(&smt_channels_lock);
+
+ return !channel_is_busy;
+}
+
+static void channel_release_busy(struct scmi_msg_channel *chan)
+{
+ chan->busy = false;
+}
+
+static struct smt_header *channel_to_smt_hdr(struct scmi_msg_channel *chan)
+{
+ return (struct smt_header *)chan->shm_addr;
+}
+
+/*
+ * Creates a SCMI message instance in secure memory and pushes it in the SCMI
+ * message drivers. Message structure contains SCMI protocol meta-data and
+ * references to input payload in secure memory and output message buffer
+ * in shared memory.
+ */
+static void scmi_proccess_smt(unsigned int agent_id, uint32_t *payload_buf)
+{
+ struct scmi_msg_channel *chan;
+ struct smt_header *smt_hdr;
+ size_t in_payload_size;
+ uint32_t smt_status;
+ struct scmi_msg msg;
+ bool error = true;
+
+ chan = plat_scmi_get_channel(agent_id);
+ if (chan == NULL) {
+ return;
+ }
+
+ smt_hdr = channel_to_smt_hdr(chan);
+ assert(smt_hdr);
+
+ smt_status = __atomic_load_n(&smt_hdr->status, __ATOMIC_RELAXED);
+
+ if (!channel_set_busy(chan)) {
+ VERBOSE("SCMI channel %u busy", agent_id);
+ goto out;
+ }
+
+ in_payload_size = __atomic_load_n(&smt_hdr->length, __ATOMIC_RELAXED) -
+ sizeof(smt_hdr->message_header);
+
+ if (in_payload_size > SCMI_PLAYLOAD_MAX) {
+ VERBOSE("SCMI payload too big %zu", in_payload_size);
+ goto out;
+ }
+
+ if ((smt_status & (SMT_STATUS_ERROR | SMT_STATUS_FREE)) != 0U) {
+ VERBOSE("SCMI channel bad status 0x%x",
+ smt_hdr->status & (SMT_STATUS_ERROR | SMT_STATUS_FREE));
+ goto out;
+ }
+
+ /* Fill message */
+ zeromem(&msg, sizeof(msg));
+ msg.in = (char *)payload_buf;
+ msg.in_size = in_payload_size;
+ msg.out = (char *)smt_hdr->payload;
+ msg.out_size = chan->shm_size - sizeof(*smt_hdr);
+
+ assert((msg.out != NULL) && (msg.out_size >= sizeof(int32_t)));
+
+ /* Here the payload is copied in secure memory */
+ memcpy(msg.in, smt_hdr->payload, in_payload_size);
+
+ msg.protocol_id = SMT_HDR_PROT_ID(smt_hdr->message_header);
+ msg.message_id = SMT_HDR_MSG_ID(smt_hdr->message_header);
+ msg.agent_id = agent_id;
+
+ scmi_process_message(&msg);
+
+ /* Update message length with the length of the response message */
+ smt_hdr->length = msg.out_size_out + sizeof(smt_hdr->message_header);
+
+ channel_release_busy(chan);
+ error = false;
+
+out:
+ if (error) {
+ VERBOSE("SCMI error");
+ smt_hdr->status |= SMT_STATUS_ERROR | SMT_STATUS_FREE;
+ } else {
+ smt_hdr->status |= SMT_STATUS_FREE;
+ }
+}
+
+void scmi_smt_fastcall_smc_entry(unsigned int agent_id)
+{
+ scmi_proccess_smt(agent_id,
+ fast_smc_payload[plat_my_core_pos()]);
+}
+
+void scmi_smt_interrupt_entry(unsigned int agent_id)
+{
+ scmi_proccess_smt(agent_id,
+ interrupt_payload[plat_my_core_pos()]);
+}
+
+/* Init a SMT header for a shared memory buffer: state it a free/no-error */
+void scmi_smt_init_agent_channel(struct scmi_msg_channel *chan)
+{
+ if (chan != NULL) {
+ struct smt_header *smt_header = channel_to_smt_hdr(chan);
+
+ if (smt_header != NULL) {
+ memset(smt_header, 0, sizeof(*smt_header));
+ smt_header->status = SMT_STATUS_FREE;
+
+ return;
+ }
+ }
+
+ panic();
+}
diff --git a/drivers/st/bsec/bsec2.c b/drivers/st/bsec/bsec2.c
new file mode 100644
index 0000000..68d3a5b
--- /dev/null
+++ b/drivers/st/bsec/bsec2.c
@@ -0,0 +1,961 @@
+/*
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <limits.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/st/bsec.h>
+#include <drivers/st/bsec2_reg.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#define BSEC_IP_VERSION_1_1 U(0x11)
+#define BSEC_IP_VERSION_2_0 U(0x20)
+#define BSEC_IP_ID_2 U(0x100032)
+
+#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 bool is_otp_invalid_mode(void)
+{
+ bool ret = ((bsec_get_status() & BSEC_MODE_INVALID) == BSEC_MODE_INVALID);
+
+ if (ret) {
+ ERROR("OTP mode is OTP-INVALID\n");
+ }
+
+ return ret;
+}
+
+#if defined(IMAGE_BL32)
+static int bsec_get_dt_node(struct dt_node_info *info)
+{
+ int node;
+
+ node = dt_get_node(info, -1, DT_BSEC_COMPAT);
+ if (node < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ return node;
+}
+
+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)) != 0U;
+}
+
+static void 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 otp;
+ uint32_t i;
+ uint32_t size;
+ uint32_t offset;
+ uint32_t length;
+
+ cuint = fdt_getprop(fdt, bsec_subnode, "reg", NULL);
+ if (cuint == NULL) {
+ panic();
+ }
+
+ offset = fdt32_to_cpu(*cuint);
+ cuint++;
+ length = fdt32_to_cpu(*cuint);
+
+ otp = offset / sizeof(uint32_t);
+
+ if (otp < STM32MP1_UPPER_OTP_START) {
+ unsigned int otp_end = round_up(offset + length,
+ sizeof(uint32_t)) /
+ sizeof(uint32_t);
+
+ if (otp_end > STM32MP1_UPPER_OTP_START) {
+ /*
+ * OTP crosses Lower/Upper boundary, consider
+ * only the upper part.
+ */
+ otp = STM32MP1_UPPER_OTP_START;
+ length -= (STM32MP1_UPPER_OTP_START *
+ sizeof(uint32_t)) - offset;
+ offset = STM32MP1_UPPER_OTP_START *
+ sizeof(uint32_t);
+
+ WARN("OTP crosses Lower/Upper boundary\n");
+ } else {
+ continue;
+ }
+ }
+
+ if ((fdt_getprop(fdt, bsec_subnode,
+ "st,non-secure-otp", NULL)) == NULL) {
+ continue;
+ }
+
+ if (((offset % sizeof(uint32_t)) != 0U) ||
+ ((length % sizeof(uint32_t)) != 0U)) {
+ ERROR("Unaligned non-secure OTP\n");
+ panic();
+ }
+
+ size = length / sizeof(uint32_t);
+
+ for (i = otp; i < (otp + size); i++) {
+ enable_non_secure_access(i);
+ }
+ }
+}
+
+static void bsec_late_init(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();
+ }
+
+ assert(bsec_base == bsec_info.base);
+
+ bsec_dt_otp_nsec_access(fdt, node);
+}
+#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);
+}
+
+/*
+ * bsec_check_error: check BSEC error status.
+ * otp: OTP number.
+ * check_disturbed: check only error (false),
+ * or error and disturbed status (true).
+ * return value: BSEC_OK if no error.
+ */
+static uint32_t bsec_check_error(uint32_t otp, bool check_disturbed)
+{
+ uint32_t bit = BIT(otp & BSEC_OTP_MASK);
+ uint32_t bank = otp_bank_offset(otp);
+
+ if ((mmio_read_32(bsec_base + BSEC_ERROR_OFF + bank) & bit) != 0U) {
+ return BSEC_ERROR;
+ }
+
+ if (!check_disturbed) {
+ return BSEC_OK;
+ }
+
+ if ((mmio_read_32(bsec_base + BSEC_DISTURBED_OFF + bank) & bit) != 0U) {
+ return BSEC_DISTURBED;
+ }
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_probe: initialize BSEC driver.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_probe(void)
+{
+ bsec_base = BSEC_BASE;
+
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ if ((((bsec_get_version() & BSEC_IPVR_MSK) != BSEC_IP_VERSION_1_1) &&
+ ((bsec_get_version() & BSEC_IPVR_MSK) != BSEC_IP_VERSION_2_0)) ||
+ (bsec_get_id() != BSEC_IP_ID_2)) {
+ panic();
+ }
+
+#if defined(IMAGE_BL32)
+ bsec_late_init();
+#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;
+ uint32_t result;
+
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ 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 value;
+ bool power_up = false;
+
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ result = bsec_read_sr_lock(otp, &value);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: %u Sticky-read bit read Error %u\n", otp, result);
+ return result;
+ }
+
+ if (value) {
+ VERBOSE("BSEC: OTP %u 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();
+
+ 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, true);
+
+ 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)
+{
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ *val = mmio_read_32(bsec_base + BSEC_OTP_DATA_OFF +
+ (otp * sizeof(uint32_t)));
+
+ return BSEC_OK;
+}
+
+/*
+ * 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;
+ bool value;
+
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ result = bsec_read_sw_lock(otp, &value);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: %u Sticky-write bit read Error %u\n", otp, result);
+ return result;
+ }
+
+ if (value) {
+ VERBOSE("BSEC: OTP %u is locked and write will be ignored\n",
+ otp);
+ }
+
+ /* Ensure integrity of each register access sequence */
+ bsec_lock();
+
+ mmio_write_32(bsec_base + BSEC_OTP_DATA_OFF +
+ (otp * sizeof(uint32_t)), val);
+
+ 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;
+ bool sp_lock;
+ bool perm_lock;
+
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ result = bsec_read_sp_lock(otp, &sp_lock);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: %u Sticky-prog bit read Error %u\n", otp, result);
+ return result;
+ }
+
+ result = bsec_read_permanent_lock(otp, &perm_lock);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: %u permanent bit read Error %u\n", otp, result);
+ return result;
+ }
+
+ if (sp_lock || perm_lock) {
+ WARN("BSEC: OTP locked, prog will be ignored\n");
+ return BSEC_PROG_FAIL;
+ }
+
+ if ((mmio_read_32(bsec_base + BSEC_OTP_LOCK_OFF) &
+ 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();
+
+ mmio_write_32(bsec_base + BSEC_OTP_WRDATA_OFF, val);
+
+ 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, true);
+ }
+
+ 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 (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ 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();
+
+ mmio_write_32(bsec_base + BSEC_OTP_WRDATA_OFF, data);
+
+ 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, false);
+ }
+
+ 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: none.
+ */
+void bsec_write_debug_conf(uint32_t val)
+{
+ if (is_otp_invalid_mode()) {
+ return;
+ }
+
+ bsec_lock();
+ mmio_write_32(bsec_base + BSEC_DEN_OFF, val & BSEC_DEN_ALL_MSK);
+ bsec_unlock();
+}
+
+/*
+ * bsec_read_debug_conf: return debug configuration register value.
+ */
+uint32_t bsec_read_debug_conf(void)
+{
+ return mmio_read_32(bsec_base + BSEC_DEN_OFF);
+}
+
+/*
+ * bsec_write_scratch: write value in scratch register.
+ * val: value to write.
+ * return value: none.
+ */
+void bsec_write_scratch(uint32_t val)
+{
+#if defined(IMAGE_BL32)
+ if (is_otp_invalid_mode()) {
+ return;
+ }
+
+ bsec_lock();
+ mmio_write_32(bsec_base + BSEC_SCRATCH_OFF, val);
+ bsec_unlock();
+#else
+ mmio_write_32(BSEC_BASE + BSEC_SCRATCH_OFF, val);
+#endif
+}
+
+/*
+ * bsec_read_scratch: return scratch register value.
+ */
+uint32_t bsec_read_scratch(void)
+{
+ return mmio_read_32(bsec_base + BSEC_SCRATCH_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 register value.
+ */
+uint32_t bsec_get_hw_conf(void)
+{
+ return mmio_read_32(bsec_base + BSEC_IPHW_CFG_OFF);
+}
+
+/*
+ * bsec_get_version: return BSEC version register value.
+ */
+uint32_t bsec_get_version(void)
+{
+ return mmio_read_32(bsec_base + BSEC_IPVR_OFF);
+}
+
+/*
+ * bsec_get_id: return BSEC ID register value.
+ */
+uint32_t bsec_get_id(void)
+{
+ return mmio_read_32(bsec_base + BSEC_IP_ID_OFF);
+}
+
+/*
+ * bsec_get_magic_id: return BSEC magic number register value.
+ */
+uint32_t bsec_get_magic_id(void)
+{
+ return mmio_read_32(bsec_base + BSEC_IP_MAGIC_ID_OFF);
+}
+
+/*
+ * bsec_set_sr_lock: set shadow-read lock.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_set_sr_lock(uint32_t otp)
+{
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ bsec_lock();
+ mmio_write_32(bsec_base + BSEC_SRLOCK_OFF + bank, otp_mask);
+ bsec_unlock();
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_read_sr_lock: read shadow-read lock.
+ * otp: OTP number.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_read_sr_lock(uint32_t otp, bool *value)
+{
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+ uint32_t bank_value;
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ bank_value = mmio_read_32(bsec_base + BSEC_SRLOCK_OFF + bank);
+
+ *value = ((bank_value & otp_mask) != 0U);
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_set_sw_lock: set shadow-write lock.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_set_sw_lock(uint32_t otp)
+{
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ bsec_lock();
+ mmio_write_32(bsec_base + BSEC_SWLOCK_OFF + bank, otp_mask);
+ bsec_unlock();
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_read_sw_lock: read shadow-write lock.
+ * otp: OTP number.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_read_sw_lock(uint32_t otp, bool *value)
+{
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+ uint32_t bank_value;
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ bank_value = mmio_read_32(bsec_base + BSEC_SWLOCK_OFF + bank);
+
+ *value = ((bank_value & otp_mask) != 0U);
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_set_sp_lock: set shadow-program lock.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_set_sp_lock(uint32_t otp)
+{
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ bsec_lock();
+ mmio_write_32(bsec_base + BSEC_SPLOCK_OFF + bank, otp_mask);
+ bsec_unlock();
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_read_sp_lock: read shadow-program lock.
+ * otp: OTP number.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_read_sp_lock(uint32_t otp, bool *value)
+{
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+ uint32_t bank_value;
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ bank_value = mmio_read_32(bsec_base + BSEC_SPLOCK_OFF + bank);
+
+ *value = ((bank_value & otp_mask) != 0U);
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_read_permanent_lock: Read permanent lock status.
+ * otp: OTP number.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_read_permanent_lock(uint32_t otp, bool *value)
+{
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+ uint32_t bank_value;
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ bank_value = mmio_read_32(bsec_base + BSEC_WRLOCK_OFF + bank);
+
+ *value = ((bank_value & otp_mask) != 0U);
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_otp_lock: Lock Upper OTP or Global Programming or Debug Enable.
+ * service: Service to lock, see header file.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_otp_lock(uint32_t service)
+{
+ uintptr_t reg = bsec_base + BSEC_OTP_LOCK_OFF;
+
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ switch (service) {
+ case BSEC_LOCK_UPPER_OTP:
+ mmio_write_32(reg, BIT(BSEC_LOCK_UPPER_OTP));
+ break;
+ case BSEC_LOCK_DEBUG:
+ mmio_write_32(reg, BIT(BSEC_LOCK_DEBUG));
+ break;
+ case BSEC_LOCK_PROGRAM:
+ mmio_write_32(reg, BIT(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 value: BSEC_OK if no error.
+ */
+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);
+
+ 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 %u\n", word, result);
+ return result;
+ }
+
+ result = bsec_read_otp(otp_value, word);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: %u Read Error %u\n", word, result);
+ }
+
+ return result;
+}
+
+/*
+ * bsec_check_nsec_access_rights: check non-secure access rights to target OTP.
+ * otp: OTP number.
+ * return value: 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) {
+ if (!non_secure_can_access(otp)) {
+ return BSEC_ERROR;
+ }
+ }
+#endif
+
+ return BSEC_OK;
+}
+
diff --git a/drivers/st/clk/clk-stm32-core.c b/drivers/st/clk/clk-stm32-core.c
new file mode 100644
index 0000000..bb03125
--- /dev/null
+++ b/drivers/st/clk/clk-stm32-core.c
@@ -0,0 +1,1096 @@
+/*
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include "clk-stm32-core.h"
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+
+static struct spinlock reg_lock;
+static struct spinlock refcount_lock;
+
+static struct stm32_clk_priv *stm32_clock_data;
+
+const struct stm32_clk_ops clk_mux_ops;
+
+struct stm32_clk_priv *clk_stm32_get_priv(void)
+{
+ return stm32_clock_data;
+}
+
+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);
+ }
+}
+
+void stm32mp1_clk_rcc_regs_lock(void)
+{
+ stm32mp1_clk_lock(&reg_lock);
+}
+
+void stm32mp1_clk_rcc_regs_unlock(void)
+{
+ stm32mp1_clk_unlock(&reg_lock);
+}
+
+#define TIMEOUT_US_1S U(1000000)
+#define OSCRDY_TIMEOUT TIMEOUT_US_1S
+
+struct clk_oscillator_data *clk_oscillator_get_data(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct stm32_osc_cfg *osc_cfg = clk->clock_cfg;
+ int osc_id = osc_cfg->osc_id;
+
+ return &priv->osci_data[osc_id];
+}
+
+void clk_oscillator_set_bypass(struct stm32_clk_priv *priv, int id, bool digbyp, bool bypass)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id);
+
+ struct stm32_clk_bypass *bypass_data = osc_data->bypass;
+ uintptr_t address;
+
+ if (bypass_data == NULL) {
+ return;
+ }
+
+ address = priv->base + bypass_data->offset;
+
+ if (digbyp) {
+ mmio_setbits_32(address, BIT(bypass_data->bit_digbyp));
+ }
+
+ if (bypass || digbyp) {
+ mmio_setbits_32(address, BIT(bypass_data->bit_byp));
+ }
+}
+
+void clk_oscillator_set_css(struct stm32_clk_priv *priv, int id, bool css)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id);
+
+ struct stm32_clk_css *css_data = osc_data->css;
+ uintptr_t address;
+
+ if (css_data == NULL) {
+ return;
+ }
+
+ address = priv->base + css_data->offset;
+
+ if (css) {
+ mmio_setbits_32(address, BIT(css_data->bit_css));
+ }
+}
+
+void clk_oscillator_set_drive(struct stm32_clk_priv *priv, int id, uint8_t lsedrv)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id);
+
+ struct stm32_clk_drive *drive_data = osc_data->drive;
+ uintptr_t address;
+ uint32_t mask;
+ uint32_t value;
+
+ if (drive_data == NULL) {
+ return;
+ }
+
+ address = priv->base + drive_data->offset;
+
+ mask = (BIT(drive_data->drv_width) - 1U) << drive_data->drv_shift;
+
+ /*
+ * Warning: not recommended to switch directly from "high drive"
+ * to "medium low drive", and vice-versa.
+ */
+ value = (mmio_read_32(address) & mask) >> drive_data->drv_shift;
+
+ while (value != lsedrv) {
+ if (value > lsedrv) {
+ value--;
+ } else {
+ value++;
+ }
+
+ mmio_clrsetbits_32(address, mask, value << drive_data->drv_shift);
+ }
+}
+
+int clk_oscillator_wait_ready(struct stm32_clk_priv *priv, int id, bool ready_on)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id);
+
+ return _clk_stm32_gate_wait_ready(priv, osc_data->gate_rdy_id, ready_on);
+}
+
+int clk_oscillator_wait_ready_on(struct stm32_clk_priv *priv, int id)
+{
+ return clk_oscillator_wait_ready(priv, id, true);
+}
+
+int clk_oscillator_wait_ready_off(struct stm32_clk_priv *priv, int id)
+{
+ return clk_oscillator_wait_ready(priv, id, false);
+}
+
+static int clk_gate_enable(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct clk_gate_cfg *cfg = clk->clock_cfg;
+
+ mmio_setbits_32(priv->base + cfg->offset, BIT(cfg->bit_idx));
+
+ return 0;
+}
+
+static void clk_gate_disable(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct clk_gate_cfg *cfg = clk->clock_cfg;
+
+ mmio_clrbits_32(priv->base + cfg->offset, BIT(cfg->bit_idx));
+}
+
+static bool clk_gate_is_enabled(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct clk_gate_cfg *cfg = clk->clock_cfg;
+
+ return ((mmio_read_32(priv->base + cfg->offset) & BIT(cfg->bit_idx)) != 0U);
+}
+
+const struct stm32_clk_ops clk_gate_ops = {
+ .enable = clk_gate_enable,
+ .disable = clk_gate_disable,
+ .is_enabled = clk_gate_is_enabled,
+};
+
+void _clk_stm32_gate_disable(struct stm32_clk_priv *priv, uint16_t gate_id)
+{
+ const struct gate_cfg *gate = &priv->gates[gate_id];
+ uintptr_t addr = priv->base + gate->offset;
+
+ if (gate->set_clr != 0U) {
+ mmio_write_32(addr + RCC_MP_ENCLRR_OFFSET, BIT(gate->bit_idx));
+ } else {
+ mmio_clrbits_32(addr, BIT(gate->bit_idx));
+ }
+}
+
+int _clk_stm32_gate_enable(struct stm32_clk_priv *priv, uint16_t gate_id)
+{
+ const struct gate_cfg *gate = &priv->gates[gate_id];
+ uintptr_t addr = priv->base + gate->offset;
+
+ if (gate->set_clr != 0U) {
+ mmio_write_32(addr, BIT(gate->bit_idx));
+
+ } else {
+ mmio_setbits_32(addr, BIT(gate->bit_idx));
+ }
+
+ return 0;
+}
+
+const struct clk_stm32 *_clk_get(struct stm32_clk_priv *priv, int id)
+{
+ if ((unsigned int)id < priv->num) {
+ return &priv->clks[id];
+ }
+
+ return NULL;
+}
+
+#define clk_div_mask(_width) GENMASK(((_width) - 1U), 0U)
+
+static unsigned int _get_table_div(const struct clk_div_table *table,
+ unsigned int val)
+{
+ const struct clk_div_table *clkt;
+
+ for (clkt = table; clkt->div; clkt++) {
+ if (clkt->val == val) {
+ return clkt->div;
+ }
+ }
+
+ return 0;
+}
+
+static unsigned int _get_div(const struct clk_div_table *table,
+ unsigned int val, unsigned long flags,
+ uint8_t width)
+{
+ if ((flags & CLK_DIVIDER_ONE_BASED) != 0UL) {
+ return val;
+ }
+
+ if ((flags & CLK_DIVIDER_POWER_OF_TWO) != 0UL) {
+ return BIT(val);
+ }
+
+ if ((flags & CLK_DIVIDER_MAX_AT_ZERO) != 0UL) {
+ return (val != 0U) ? val : BIT(width);
+ }
+
+ if (table != NULL) {
+ return _get_table_div(table, val);
+ }
+
+ return val + 1U;
+}
+
+#define TIMEOUT_US_200MS U(200000)
+#define CLKSRC_TIMEOUT TIMEOUT_US_200MS
+
+int clk_mux_set_parent(struct stm32_clk_priv *priv, uint16_t pid, uint8_t sel)
+{
+ const struct parent_cfg *parents = &priv->parents[pid & MUX_PARENT_MASK];
+ const struct mux_cfg *mux = parents->mux;
+ uintptr_t address = priv->base + mux->offset;
+ uint32_t mask;
+ uint64_t timeout;
+
+ mask = MASK_WIDTH_SHIFT(mux->width, mux->shift);
+
+ mmio_clrsetbits_32(address, mask, (sel << mux->shift) & mask);
+
+ if (mux->bitrdy == MUX_NO_BIT_RDY) {
+ return 0;
+ }
+
+ timeout = timeout_init_us(CLKSRC_TIMEOUT);
+
+ mask = BIT(mux->bitrdy);
+
+ while ((mmio_read_32(address) & mask) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+int _clk_stm32_set_parent(struct stm32_clk_priv *priv, int clk, int clkp)
+{
+ const struct parent_cfg *parents;
+ uint16_t pid;
+ uint8_t sel;
+ int old_parent;
+
+ pid = priv->clks[clk].parent;
+
+ if ((pid == CLK_IS_ROOT) || (pid < MUX_MAX_PARENTS)) {
+ return -EINVAL;
+ }
+
+ old_parent = _clk_stm32_get_parent(priv, clk);
+ if (old_parent < 0) {
+ return old_parent;
+ }
+ if (old_parent == clkp) {
+ return 0;
+ }
+
+ parents = &priv->parents[pid & MUX_PARENT_MASK];
+
+ for (sel = 0; sel < parents->num_parents; sel++) {
+ if (parents->id_parents[sel] == (uint16_t)clkp) {
+ bool clk_was_enabled = _clk_stm32_is_enabled(priv, clk);
+ int err = 0;
+
+ /* Enable the parents (for glitch free mux) */
+ _clk_stm32_enable(priv, clkp);
+ _clk_stm32_enable(priv, old_parent);
+
+ err = clk_mux_set_parent(priv, pid, sel);
+
+ _clk_stm32_disable(priv, old_parent);
+
+ if (clk_was_enabled) {
+ _clk_stm32_disable(priv, old_parent);
+ } else {
+ _clk_stm32_disable(priv, clkp);
+ }
+
+ return err;
+ }
+ }
+
+ return -EINVAL;
+}
+
+int clk_mux_get_parent(struct stm32_clk_priv *priv, uint32_t mux_id)
+{
+ const struct parent_cfg *parent;
+ const struct mux_cfg *mux;
+ uint32_t mask;
+
+ if (mux_id >= priv->nb_parents) {
+ panic();
+ }
+
+ parent = &priv->parents[mux_id];
+ mux = parent->mux;
+
+ mask = MASK_WIDTH_SHIFT(mux->width, mux->shift);
+
+ return (mmio_read_32(priv->base + mux->offset) & mask) >> mux->shift;
+}
+
+int _clk_stm32_set_parent_by_index(struct stm32_clk_priv *priv, int clk, int sel)
+{
+ uint16_t pid;
+
+ pid = priv->clks[clk].parent;
+
+ if ((pid == CLK_IS_ROOT) || (pid < MUX_MAX_PARENTS)) {
+ return -EINVAL;
+ }
+
+ return clk_mux_set_parent(priv, pid, sel);
+}
+
+int _clk_stm32_get_parent(struct stm32_clk_priv *priv, int clk_id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, clk_id);
+ const struct parent_cfg *parent;
+ uint16_t mux_id;
+ int sel;
+
+ mux_id = priv->clks[clk_id].parent;
+ if (mux_id == CLK_IS_ROOT) {
+ return CLK_IS_ROOT;
+ }
+
+ if (mux_id < MUX_MAX_PARENTS) {
+ return mux_id & MUX_PARENT_MASK;
+ }
+
+ mux_id &= MUX_PARENT_MASK;
+ parent = &priv->parents[mux_id];
+
+ if (clk->ops->get_parent != NULL) {
+ sel = clk->ops->get_parent(priv, clk_id);
+ } else {
+ sel = clk_mux_get_parent(priv, mux_id);
+ }
+
+ if ((sel >= 0) && (sel < parent->num_parents)) {
+ return parent->id_parents[sel];
+ }
+
+ return -EINVAL;
+}
+
+int _clk_stm32_get_parent_index(struct stm32_clk_priv *priv, int clk_id)
+{
+ uint16_t mux_id;
+
+ mux_id = priv->clks[clk_id].parent;
+ if (mux_id == CLK_IS_ROOT) {
+ return CLK_IS_ROOT;
+ }
+
+ if (mux_id < MUX_MAX_PARENTS) {
+ return mux_id & MUX_PARENT_MASK;
+ }
+
+ mux_id &= MUX_PARENT_MASK;
+
+ return clk_mux_get_parent(priv, mux_id);
+}
+
+int _clk_stm32_get_parent_by_index(struct stm32_clk_priv *priv, int clk_id, int idx)
+{
+ const struct parent_cfg *parent;
+ uint16_t mux_id;
+
+ mux_id = priv->clks[clk_id].parent;
+ if (mux_id == CLK_IS_ROOT) {
+ return CLK_IS_ROOT;
+ }
+
+ if (mux_id < MUX_MAX_PARENTS) {
+ return mux_id & MUX_PARENT_MASK;
+ }
+
+ mux_id &= MUX_PARENT_MASK;
+ parent = &priv->parents[mux_id];
+
+ if (idx < parent->num_parents) {
+ return parent->id_parents[idx];
+ }
+
+ return -EINVAL;
+}
+
+int clk_get_index(struct stm32_clk_priv *priv, unsigned long binding_id)
+{
+ unsigned int i;
+
+ for (i = 0U; i < priv->num; i++) {
+ if (binding_id == priv->clks[i].binding) {
+ return (int)i;
+ }
+ }
+
+ return -EINVAL;
+}
+
+unsigned long _clk_stm32_get_rate(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ int parent;
+ unsigned long rate = 0UL;
+
+ if ((unsigned int)id >= priv->num) {
+ return rate;
+ }
+
+ parent = _clk_stm32_get_parent(priv, id);
+ if (parent < 0) {
+ return 0UL;
+ }
+
+ if (clk->ops->recalc_rate != NULL) {
+ unsigned long prate = 0UL;
+
+ if (parent != CLK_IS_ROOT) {
+ prate = _clk_stm32_get_rate(priv, parent);
+ }
+
+ rate = clk->ops->recalc_rate(priv, id, prate);
+
+ return rate;
+ }
+
+ switch (parent) {
+ case CLK_IS_ROOT:
+ panic();
+
+ default:
+ rate = _clk_stm32_get_rate(priv, parent);
+ break;
+ }
+ return rate;
+
+}
+
+unsigned long _clk_stm32_get_parent_rate(struct stm32_clk_priv *priv, int id)
+{
+ int parent_id = _clk_stm32_get_parent(priv, id);
+
+ if (parent_id < 0) {
+ return 0UL;
+ }
+
+ return _clk_stm32_get_rate(priv, parent_id);
+}
+
+static uint8_t _stm32_clk_get_flags(struct stm32_clk_priv *priv, int id)
+{
+ return priv->clks[id].flags;
+}
+
+bool _stm32_clk_is_flags(struct stm32_clk_priv *priv, int id, uint8_t flag)
+{
+ if (_stm32_clk_get_flags(priv, id) & flag) {
+ return true;
+ }
+
+ return false;
+}
+
+int clk_stm32_enable_call_ops(struct stm32_clk_priv *priv, uint16_t id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+
+ if (clk->ops->enable != NULL) {
+ clk->ops->enable(priv, id);
+ }
+
+ return 0;
+}
+
+static int _clk_stm32_enable_core(struct stm32_clk_priv *priv, int id)
+{
+ int parent;
+ int ret = 0;
+
+ if (priv->gate_refcounts[id] == 0U) {
+ parent = _clk_stm32_get_parent(priv, id);
+ if (parent < 0) {
+ return parent;
+ }
+ if (parent != CLK_IS_ROOT) {
+ ret = _clk_stm32_enable_core(priv, parent);
+ if (ret) {
+ return ret;
+ }
+ }
+ clk_stm32_enable_call_ops(priv, id);
+ }
+
+ priv->gate_refcounts[id]++;
+
+ if (priv->gate_refcounts[id] == UINT_MAX) {
+ ERROR("%s: %d max enable count !", __func__, id);
+ panic();
+ }
+
+ return 0;
+}
+
+int _clk_stm32_enable(struct stm32_clk_priv *priv, int id)
+{
+ int ret;
+
+ stm32mp1_clk_lock(&refcount_lock);
+ ret = _clk_stm32_enable_core(priv, id);
+ stm32mp1_clk_unlock(&refcount_lock);
+
+ return ret;
+}
+
+void clk_stm32_disable_call_ops(struct stm32_clk_priv *priv, uint16_t id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+
+ if (clk->ops->disable != NULL) {
+ clk->ops->disable(priv, id);
+ }
+}
+
+static void _clk_stm32_disable_core(struct stm32_clk_priv *priv, int id)
+{
+ int parent;
+
+ if ((priv->gate_refcounts[id] == 1U) && _stm32_clk_is_flags(priv, id, CLK_IS_CRITICAL)) {
+ return;
+ }
+
+ if (priv->gate_refcounts[id] == 0U) {
+ /* case of clock ignore unused */
+ if (_clk_stm32_is_enabled(priv, id)) {
+ clk_stm32_disable_call_ops(priv, id);
+ return;
+ }
+ VERBOSE("%s: %d already disabled !\n\n", __func__, id);
+ return;
+ }
+
+ if (--priv->gate_refcounts[id] > 0U) {
+ return;
+ }
+
+ clk_stm32_disable_call_ops(priv, id);
+
+ parent = _clk_stm32_get_parent(priv, id);
+ if ((parent >= 0) && (parent != CLK_IS_ROOT)) {
+ _clk_stm32_disable_core(priv, parent);
+ }
+}
+
+void _clk_stm32_disable(struct stm32_clk_priv *priv, int id)
+{
+ stm32mp1_clk_lock(&refcount_lock);
+
+ _clk_stm32_disable_core(priv, id);
+
+ stm32mp1_clk_unlock(&refcount_lock);
+}
+
+bool _clk_stm32_is_enabled(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+
+ if (clk->ops->is_enabled != NULL) {
+ return clk->ops->is_enabled(priv, id);
+ }
+
+ return priv->gate_refcounts[id];
+}
+
+static int clk_stm32_enable(unsigned long binding_id)
+{
+ struct stm32_clk_priv *priv = clk_stm32_get_priv();
+ int id;
+
+ id = clk_get_index(priv, binding_id);
+ if (id == -EINVAL) {
+ return id;
+ }
+
+ return _clk_stm32_enable(priv, id);
+}
+
+static void clk_stm32_disable(unsigned long binding_id)
+{
+ struct stm32_clk_priv *priv = clk_stm32_get_priv();
+ int id;
+
+ id = clk_get_index(priv, binding_id);
+ if (id != -EINVAL) {
+ _clk_stm32_disable(priv, id);
+ }
+}
+
+static bool clk_stm32_is_enabled(unsigned long binding_id)
+{
+ struct stm32_clk_priv *priv = clk_stm32_get_priv();
+ int id;
+
+ id = clk_get_index(priv, binding_id);
+ if (id == -EINVAL) {
+ return false;
+ }
+
+ return _clk_stm32_is_enabled(priv, id);
+}
+
+static unsigned long clk_stm32_get_rate(unsigned long binding_id)
+{
+ struct stm32_clk_priv *priv = clk_stm32_get_priv();
+ int id;
+
+ id = clk_get_index(priv, binding_id);
+ if (id == -EINVAL) {
+ return 0UL;
+ }
+
+ return _clk_stm32_get_rate(priv, id);
+}
+
+static int clk_stm32_get_parent(unsigned long binding_id)
+{
+ struct stm32_clk_priv *priv = clk_stm32_get_priv();
+ int id;
+
+ id = clk_get_index(priv, binding_id);
+ if (id == -EINVAL) {
+ return id;
+ }
+
+ return _clk_stm32_get_parent(priv, id);
+}
+
+static const struct clk_ops stm32mp_clk_ops = {
+ .enable = clk_stm32_enable,
+ .disable = clk_stm32_disable,
+ .is_enabled = clk_stm32_is_enabled,
+ .get_rate = clk_stm32_get_rate,
+ .get_parent = clk_stm32_get_parent,
+};
+
+void clk_stm32_enable_critical_clocks(void)
+{
+ struct stm32_clk_priv *priv = clk_stm32_get_priv();
+ unsigned int i;
+
+ for (i = 0U; i < priv->num; i++) {
+ if (_stm32_clk_is_flags(priv, i, CLK_IS_CRITICAL)) {
+ _clk_stm32_enable(priv, i);
+ }
+ }
+}
+
+static void stm32_clk_register(void)
+{
+ clk_register(&stm32mp_clk_ops);
+}
+
+uint32_t clk_stm32_div_get_value(struct stm32_clk_priv *priv, int div_id)
+{
+ const struct div_cfg *divider = &priv->div[div_id];
+ uint32_t val = 0;
+
+ val = mmio_read_32(priv->base + divider->offset) >> divider->shift;
+ val &= clk_div_mask(divider->width);
+
+ return val;
+}
+
+unsigned long _clk_stm32_divider_recalc(struct stm32_clk_priv *priv,
+ int div_id,
+ unsigned long prate)
+{
+ const struct div_cfg *divider = &priv->div[div_id];
+ uint32_t val = clk_stm32_div_get_value(priv, div_id);
+ unsigned int div = 0U;
+
+ div = _get_div(divider->table, val, divider->flags, divider->width);
+ if (div == 0U) {
+ return prate;
+ }
+
+ return div_round_up((uint64_t)prate, div);
+}
+
+unsigned long clk_stm32_divider_recalc(struct stm32_clk_priv *priv, int id,
+ unsigned long prate)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct clk_stm32_div_cfg *div_cfg = clk->clock_cfg;
+
+ return _clk_stm32_divider_recalc(priv, div_cfg->id, prate);
+}
+
+const struct stm32_clk_ops clk_stm32_divider_ops = {
+ .recalc_rate = clk_stm32_divider_recalc,
+};
+
+int clk_stm32_set_div(struct stm32_clk_priv *priv, uint32_t div_id, uint32_t value)
+{
+ const struct div_cfg *divider;
+ uintptr_t address;
+ uint64_t timeout;
+ uint32_t mask;
+
+ if (div_id >= priv->nb_div) {
+ panic();
+ }
+
+ divider = &priv->div[div_id];
+ address = priv->base + divider->offset;
+
+ mask = MASK_WIDTH_SHIFT(divider->width, divider->shift);
+ mmio_clrsetbits_32(address, mask, (value << divider->shift) & mask);
+
+ if (divider->bitrdy == DIV_NO_BIT_RDY) {
+ return 0;
+ }
+
+ timeout = timeout_init_us(CLKSRC_TIMEOUT);
+ mask = BIT(divider->bitrdy);
+
+ while ((mmio_read_32(address) & mask) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+int _clk_stm32_gate_wait_ready(struct stm32_clk_priv *priv, uint16_t gate_id,
+ bool ready_on)
+{
+ const struct gate_cfg *gate = &priv->gates[gate_id];
+ uintptr_t address = priv->base + gate->offset;
+ uint32_t mask_rdy = BIT(gate->bit_idx);
+ uint64_t timeout;
+ uint32_t mask_test;
+
+ if (ready_on) {
+ mask_test = BIT(gate->bit_idx);
+ } else {
+ mask_test = 0U;
+ }
+
+ timeout = timeout_init_us(OSCRDY_TIMEOUT);
+
+ while ((mmio_read_32(address) & mask_rdy) != mask_test) {
+ if (timeout_elapsed(timeout)) {
+ break;
+ }
+ }
+
+ if ((mmio_read_32(address) & mask_rdy) != mask_test) {
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+int clk_stm32_gate_enable(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct clk_stm32_gate_cfg *cfg = clk->clock_cfg;
+ const struct gate_cfg *gate = &priv->gates[cfg->id];
+ uintptr_t addr = priv->base + gate->offset;
+
+ if (gate->set_clr != 0U) {
+ mmio_write_32(addr, BIT(gate->bit_idx));
+
+ } else {
+ mmio_setbits_32(addr, BIT(gate->bit_idx));
+ }
+
+ return 0;
+}
+
+void clk_stm32_gate_disable(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct clk_stm32_gate_cfg *cfg = clk->clock_cfg;
+ const struct gate_cfg *gate = &priv->gates[cfg->id];
+ uintptr_t addr = priv->base + gate->offset;
+
+ if (gate->set_clr != 0U) {
+ mmio_write_32(addr + RCC_MP_ENCLRR_OFFSET, BIT(gate->bit_idx));
+ } else {
+ mmio_clrbits_32(addr, BIT(gate->bit_idx));
+ }
+}
+
+bool _clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int gate_id)
+{
+ const struct gate_cfg *gate;
+ uint32_t addr;
+
+ gate = &priv->gates[gate_id];
+ addr = priv->base + gate->offset;
+
+ return ((mmio_read_32(addr) & BIT(gate->bit_idx)) != 0U);
+}
+
+bool clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct clk_stm32_gate_cfg *cfg = clk->clock_cfg;
+
+ return _clk_stm32_gate_is_enabled(priv, cfg->id);
+}
+
+const struct stm32_clk_ops clk_stm32_gate_ops = {
+ .enable = clk_stm32_gate_enable,
+ .disable = clk_stm32_gate_disable,
+ .is_enabled = clk_stm32_gate_is_enabled,
+};
+
+const struct stm32_clk_ops clk_fixed_factor_ops = {
+ .recalc_rate = fixed_factor_recalc_rate,
+};
+
+unsigned long fixed_factor_recalc_rate(struct stm32_clk_priv *priv,
+ int id, unsigned long prate)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ const struct fixed_factor_cfg *cfg = clk->clock_cfg;
+ unsigned long long rate;
+
+ rate = (unsigned long long)prate * cfg->mult;
+
+ if (cfg->div == 0U) {
+ ERROR("division by zero\n");
+ panic();
+ }
+
+ return (unsigned long)(rate / cfg->div);
+};
+
+#define APB_DIV_MASK GENMASK(2, 0)
+#define TIM_PRE_MASK BIT(0)
+
+static unsigned long timer_recalc_rate(struct stm32_clk_priv *priv,
+ int id, unsigned long prate)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ const struct clk_timer_cfg *cfg = clk->clock_cfg;
+ uint32_t prescaler, timpre;
+ uintptr_t rcc_base = priv->base;
+
+ prescaler = mmio_read_32(rcc_base + cfg->apbdiv) &
+ APB_DIV_MASK;
+
+ timpre = mmio_read_32(rcc_base + cfg->timpre) &
+ TIM_PRE_MASK;
+
+ if (prescaler == 0U) {
+ return prate;
+ }
+
+ return prate * (timpre + 1U) * 2U;
+};
+
+const struct stm32_clk_ops clk_timer_ops = {
+ .recalc_rate = timer_recalc_rate,
+};
+
+static unsigned long clk_fixed_rate_recalc(struct stm32_clk_priv *priv, int id,
+ unsigned long prate)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct clk_stm32_fixed_rate_cfg *cfg = clk->clock_cfg;
+
+ return cfg->rate;
+}
+
+const struct stm32_clk_ops clk_stm32_fixed_rate_ops = {
+ .recalc_rate = clk_fixed_rate_recalc,
+};
+
+static unsigned long clk_stm32_osc_recalc_rate(struct stm32_clk_priv *priv,
+ int id, unsigned long prate)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id);
+
+ return osc_data->frequency;
+};
+
+bool clk_stm32_osc_gate_is_enabled(struct stm32_clk_priv *priv, int id)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id);
+
+ return _clk_stm32_gate_is_enabled(priv, osc_data->gate_id);
+
+}
+
+int clk_stm32_osc_gate_enable(struct stm32_clk_priv *priv, int id)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id);
+
+ _clk_stm32_gate_enable(priv, osc_data->gate_id);
+
+ if (_clk_stm32_gate_wait_ready(priv, osc_data->gate_rdy_id, true) != 0U) {
+ ERROR("%s: %s (%d)\n", __func__, osc_data->name, __LINE__);
+ panic();
+ }
+
+ return 0;
+}
+
+void clk_stm32_osc_gate_disable(struct stm32_clk_priv *priv, int id)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id);
+
+ _clk_stm32_gate_disable(priv, osc_data->gate_id);
+
+ if (_clk_stm32_gate_wait_ready(priv, osc_data->gate_rdy_id, false) != 0U) {
+ ERROR("%s: %s (%d)\n", __func__, osc_data->name, __LINE__);
+ panic();
+ }
+}
+
+static unsigned long clk_stm32_get_dt_oscillator_frequency(const char *name)
+{
+ void *fdt = NULL;
+ int node = 0;
+ int subnode = 0;
+
+ if (fdt_get_address(&fdt) == 0) {
+ panic();
+ }
+
+ node = fdt_path_offset(fdt, "/clocks");
+ if (node < 0) {
+ return 0UL;
+ }
+
+ fdt_for_each_subnode(subnode, fdt, node) {
+ const char *cchar = NULL;
+ const fdt32_t *cuint = NULL;
+ int ret = 0;
+
+ cchar = fdt_get_name(fdt, subnode, &ret);
+ if (cchar == NULL) {
+ continue;
+ }
+
+ if (strncmp(cchar, name, (size_t)ret) ||
+ fdt_get_status(subnode) == DT_DISABLED) {
+ continue;
+ }
+
+ cuint = fdt_getprop(fdt, subnode, "clock-frequency", &ret);
+ if (cuint == NULL) {
+ return 0UL;
+ }
+
+ return fdt32_to_cpu(*cuint);
+ }
+
+ return 0UL;
+}
+
+void clk_stm32_osc_init(struct stm32_clk_priv *priv, int id)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id);
+ const char *name = osc_data->name;
+
+ osc_data->frequency = clk_stm32_get_dt_oscillator_frequency(name);
+}
+
+const struct stm32_clk_ops clk_stm32_osc_ops = {
+ .recalc_rate = clk_stm32_osc_recalc_rate,
+ .is_enabled = clk_stm32_osc_gate_is_enabled,
+ .enable = clk_stm32_osc_gate_enable,
+ .disable = clk_stm32_osc_gate_disable,
+ .init = clk_stm32_osc_init,
+};
+
+const struct stm32_clk_ops clk_stm32_osc_nogate_ops = {
+ .recalc_rate = clk_stm32_osc_recalc_rate,
+ .init = clk_stm32_osc_init,
+};
+
+int stm32_clk_parse_fdt_by_name(void *fdt, int node, const char *name, uint32_t *tab, uint32_t *nb)
+{
+ const fdt32_t *cell;
+ int len = 0;
+ uint32_t i;
+
+ cell = fdt_getprop(fdt, node, name, &len);
+ if (cell == NULL) {
+ *nb = 0U;
+ return 0;
+ }
+
+ for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
+ uint32_t val = fdt32_to_cpu(cell[i]);
+
+ tab[i] = val;
+ }
+
+ *nb = (uint32_t)len / sizeof(uint32_t);
+
+ return 0;
+}
+
+int clk_stm32_init(struct stm32_clk_priv *priv, uintptr_t base)
+{
+ unsigned int i;
+
+ stm32_clock_data = priv;
+
+ priv->base = base;
+
+ for (i = 0U; i < priv->num; i++) {
+ const struct clk_stm32 *clk = _clk_get(priv, i);
+
+ assert(clk->ops != NULL);
+
+ if (clk->ops->init != NULL) {
+ clk->ops->init(priv, i);
+ }
+ }
+
+ stm32_clk_register();
+
+ return 0;
+}
diff --git a/drivers/st/clk/clk-stm32-core.h b/drivers/st/clk/clk-stm32-core.h
new file mode 100644
index 0000000..8bfb513
--- /dev/null
+++ b/drivers/st/clk/clk-stm32-core.h
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#ifndef CLK_STM32_CORE_H
+#define CLK_STM32_CORE_H
+
+struct mux_cfg {
+ uint16_t offset;
+ uint8_t shift;
+ uint8_t width;
+ uint8_t bitrdy;
+};
+
+struct gate_cfg {
+ uint16_t offset;
+ uint8_t bit_idx;
+ uint8_t set_clr;
+};
+
+struct clk_div_table {
+ unsigned int val;
+ unsigned int div;
+};
+
+struct div_cfg {
+ uint16_t offset;
+ uint8_t shift;
+ uint8_t width;
+ uint8_t flags;
+ uint8_t bitrdy;
+ const struct clk_div_table *table;
+};
+
+struct parent_cfg {
+ uint8_t num_parents;
+ const uint16_t *id_parents;
+ struct mux_cfg *mux;
+};
+
+struct stm32_clk_priv;
+
+struct stm32_clk_ops {
+ unsigned long (*recalc_rate)(struct stm32_clk_priv *priv, int id, unsigned long rate);
+ int (*get_parent)(struct stm32_clk_priv *priv, int id);
+ int (*set_rate)(struct stm32_clk_priv *priv, int id, unsigned long rate,
+ unsigned long prate);
+ int (*enable)(struct stm32_clk_priv *priv, int id);
+ void (*disable)(struct stm32_clk_priv *priv, int id);
+ bool (*is_enabled)(struct stm32_clk_priv *priv, int id);
+ void (*init)(struct stm32_clk_priv *priv, int id);
+};
+
+struct clk_stm32 {
+ uint16_t binding;
+ uint16_t parent;
+ uint8_t flags;
+ void *clock_cfg;
+ const struct stm32_clk_ops *ops;
+};
+
+struct stm32_clk_priv {
+ uintptr_t base;
+ const uint32_t num;
+ const struct clk_stm32 *clks;
+ const struct parent_cfg *parents;
+ const uint32_t nb_parents;
+ const struct gate_cfg *gates;
+ const uint32_t nb_gates;
+ const struct div_cfg *div;
+ const uint32_t nb_div;
+ struct clk_oscillator_data *osci_data;
+ const uint32_t nb_osci_data;
+ uint32_t *gate_refcounts;
+ void *pdata;
+};
+
+struct stm32_clk_bypass {
+ uint16_t offset;
+ uint8_t bit_byp;
+ uint8_t bit_digbyp;
+};
+
+struct stm32_clk_css {
+ uint16_t offset;
+ uint8_t bit_css;
+};
+
+struct stm32_clk_drive {
+ uint16_t offset;
+ uint8_t drv_shift;
+ uint8_t drv_width;
+ uint8_t drv_default;
+};
+
+struct clk_oscillator_data {
+ const char *name;
+ uint16_t id_clk;
+ unsigned long frequency;
+ uint16_t gate_id;
+ uint16_t gate_rdy_id;
+ struct stm32_clk_bypass *bypass;
+ struct stm32_clk_css *css;
+ struct stm32_clk_drive *drive;
+};
+
+struct clk_fixed_rate {
+ const char *name;
+ unsigned long fixed_rate;
+};
+
+struct clk_gate_cfg {
+ uint32_t offset;
+ uint8_t bit_idx;
+};
+
+/* CLOCK FLAGS */
+#define CLK_IS_CRITICAL BIT(0)
+#define CLK_IGNORE_UNUSED BIT(1)
+#define CLK_SET_RATE_PARENT BIT(2)
+
+#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 CLK_DIVIDER_BIG_ENDIAN BIT(7)
+
+#define MUX_MAX_PARENTS U(0x8000)
+#define MUX_PARENT_MASK GENMASK(14, 0)
+#define MUX_FLAG U(0x8000)
+#define MUX(mux) ((mux) | MUX_FLAG)
+
+#define NO_GATE 0
+#define _NO_ID UINT16_MAX
+#define CLK_IS_ROOT UINT16_MAX
+#define MUX_NO_BIT_RDY UINT8_MAX
+#define DIV_NO_BIT_RDY UINT8_MAX
+
+#define MASK_WIDTH_SHIFT(_width, _shift) \
+ GENMASK(((_width) + (_shift) - 1U), (_shift))
+
+int clk_stm32_init(struct stm32_clk_priv *priv, uintptr_t base);
+void clk_stm32_enable_critical_clocks(void);
+
+struct stm32_clk_priv *clk_stm32_get_priv(void);
+
+int clk_get_index(struct stm32_clk_priv *priv, unsigned long binding_id);
+const struct clk_stm32 *_clk_get(struct stm32_clk_priv *priv, int id);
+
+void clk_oscillator_set_bypass(struct stm32_clk_priv *priv, int id, bool digbyp, bool bypass);
+void clk_oscillator_set_drive(struct stm32_clk_priv *priv, int id, uint8_t lsedrv);
+void clk_oscillator_set_css(struct stm32_clk_priv *priv, int id, bool css);
+
+int _clk_stm32_gate_wait_ready(struct stm32_clk_priv *priv, uint16_t gate_id, bool ready_on);
+
+int clk_oscillator_wait_ready(struct stm32_clk_priv *priv, int id, bool ready_on);
+int clk_oscillator_wait_ready_on(struct stm32_clk_priv *priv, int id);
+int clk_oscillator_wait_ready_off(struct stm32_clk_priv *priv, int id);
+
+int clk_stm32_get_counter(unsigned long binding_id);
+
+void _clk_stm32_gate_disable(struct stm32_clk_priv *priv, uint16_t gate_id);
+int _clk_stm32_gate_enable(struct stm32_clk_priv *priv, uint16_t gate_id);
+
+int _clk_stm32_set_parent(struct stm32_clk_priv *priv, int id, int src_id);
+int _clk_stm32_set_parent_by_index(struct stm32_clk_priv *priv, int clk, int sel);
+
+int _clk_stm32_get_parent(struct stm32_clk_priv *priv, int id);
+int _clk_stm32_get_parent_by_index(struct stm32_clk_priv *priv, int clk_id, int idx);
+int _clk_stm32_get_parent_index(struct stm32_clk_priv *priv, int clk_id);
+
+unsigned long _clk_stm32_get_rate(struct stm32_clk_priv *priv, int id);
+unsigned long _clk_stm32_get_parent_rate(struct stm32_clk_priv *priv, int id);
+
+bool _stm32_clk_is_flags(struct stm32_clk_priv *priv, int id, uint8_t flag);
+
+int _clk_stm32_enable(struct stm32_clk_priv *priv, int id);
+void _clk_stm32_disable(struct stm32_clk_priv *priv, int id);
+
+int clk_stm32_enable_call_ops(struct stm32_clk_priv *priv, uint16_t id);
+void clk_stm32_disable_call_ops(struct stm32_clk_priv *priv, uint16_t id);
+
+bool _clk_stm32_is_enabled(struct stm32_clk_priv *priv, int id);
+
+int _clk_stm32_divider_set_rate(struct stm32_clk_priv *priv, int div_id,
+ unsigned long rate, unsigned long parent_rate);
+
+int clk_stm32_divider_set_rate(struct stm32_clk_priv *priv, int id, unsigned long rate,
+ unsigned long prate);
+
+unsigned long _clk_stm32_divider_recalc(struct stm32_clk_priv *priv,
+ int div_id,
+ unsigned long prate);
+
+unsigned long clk_stm32_divider_recalc(struct stm32_clk_priv *priv, int idx,
+ unsigned long prate);
+
+int clk_stm32_gate_enable(struct stm32_clk_priv *priv, int idx);
+void clk_stm32_gate_disable(struct stm32_clk_priv *priv, int idx);
+
+bool _clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int gate_id);
+bool clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int idx);
+
+uint32_t clk_stm32_div_get_value(struct stm32_clk_priv *priv, int div_id);
+int clk_stm32_set_div(struct stm32_clk_priv *priv, uint32_t div_id, uint32_t value);
+int clk_mux_set_parent(struct stm32_clk_priv *priv, uint16_t pid, uint8_t sel);
+int clk_mux_get_parent(struct stm32_clk_priv *priv, uint32_t mux_id);
+
+int stm32_clk_parse_fdt_by_name(void *fdt, int node, const char *name, uint32_t *tab, uint32_t *nb);
+
+#ifdef CFG_STM32_CLK_DEBUG
+void clk_stm32_display_clock_info(void);
+#endif
+
+struct clk_stm32_div_cfg {
+ int id;
+};
+
+#define STM32_DIV(idx, _binding, _parent, _flags, _div_id) \
+ [(idx)] = (struct clk_stm32){ \
+ .binding = (_binding),\
+ .parent = (_parent),\
+ .flags = (_flags),\
+ .clock_cfg = &(struct clk_stm32_div_cfg){\
+ .id = (_div_id),\
+ },\
+ .ops = &clk_stm32_divider_ops,\
+ }
+
+struct clk_stm32_gate_cfg {
+ int id;
+};
+
+#define STM32_GATE(idx, _binding, _parent, _flags, _gate_id) \
+ [(idx)] = (struct clk_stm32){ \
+ .binding = (_binding),\
+ .parent = (_parent),\
+ .flags = (_flags),\
+ .clock_cfg = &(struct clk_stm32_gate_cfg){\
+ .id = (_gate_id),\
+ },\
+ .ops = &clk_stm32_gate_ops,\
+ }
+
+struct fixed_factor_cfg {
+ unsigned int mult;
+ unsigned int div;
+};
+
+unsigned long fixed_factor_recalc_rate(struct stm32_clk_priv *priv,
+ int _idx, unsigned long prate);
+
+#define FIXED_FACTOR(idx, _idx, _parent, _mult, _div) \
+ [(idx)] = (struct clk_stm32){ \
+ .binding = (_idx),\
+ .parent = (_parent),\
+ .clock_cfg = &(struct fixed_factor_cfg){\
+ .mult = (_mult),\
+ .div = (_div),\
+ },\
+ .ops = &clk_fixed_factor_ops,\
+ }
+
+#define GATE(idx, _binding, _parent, _flags, _offset, _bit_idx) \
+ [(idx)] = (struct clk_stm32){ \
+ .binding = (_binding),\
+ .parent = (_parent),\
+ .flags = (_flags),\
+ .clock_cfg = &(struct clk_gate_cfg){\
+ .offset = (_offset),\
+ .bit_idx = (_bit_idx),\
+ },\
+ .ops = &clk_gate_ops,\
+ }
+
+#define STM32_MUX(idx, _binding, _mux_id, _flags) \
+ [(idx)] = (struct clk_stm32){ \
+ .binding = (_binding),\
+ .parent = (MUX(_mux_id)),\
+ .flags = (_flags),\
+ .clock_cfg = NULL,\
+ .ops = (&clk_mux_ops),\
+ }
+
+struct clk_timer_cfg {
+ uint32_t apbdiv;
+ uint32_t timpre;
+};
+
+#define CK_TIMER(idx, _idx, _parent, _flags, _apbdiv, _timpre) \
+ [(idx)] = (struct clk_stm32){ \
+ .binding = (_idx),\
+ .parent = (_parent),\
+ .flags = (CLK_SET_RATE_PARENT | (_flags)),\
+ .clock_cfg = &(struct clk_timer_cfg){\
+ .apbdiv = (_apbdiv),\
+ .timpre = (_timpre),\
+ },\
+ .ops = &clk_timer_ops,\
+ }
+
+struct clk_stm32_fixed_rate_cfg {
+ unsigned long rate;
+};
+
+#define CLK_FIXED_RATE(idx, _binding, _rate) \
+ [(idx)] = (struct clk_stm32){ \
+ .binding = (_binding),\
+ .parent = (CLK_IS_ROOT),\
+ .clock_cfg = &(struct clk_stm32_fixed_rate_cfg){\
+ .rate = (_rate),\
+ },\
+ .ops = &clk_stm32_fixed_rate_ops,\
+ }
+
+#define BYPASS(_offset, _bit_byp, _bit_digbyp) &(struct stm32_clk_bypass){\
+ .offset = (_offset),\
+ .bit_byp = (_bit_byp),\
+ .bit_digbyp = (_bit_digbyp),\
+}
+
+#define CSS(_offset, _bit_css) &(struct stm32_clk_css){\
+ .offset = (_offset),\
+ .bit_css = (_bit_css),\
+}
+
+#define DRIVE(_offset, _shift, _width, _default) &(struct stm32_clk_drive){\
+ .offset = (_offset),\
+ .drv_shift = (_shift),\
+ .drv_width = (_width),\
+ .drv_default = (_default),\
+}
+
+#define OSCILLATOR(idx_osc, _id, _name, _gate_id, _gate_rdy_id, _bypass, _css, _drive) \
+ [(idx_osc)] = (struct clk_oscillator_data){\
+ .name = (_name),\
+ .id_clk = (_id),\
+ .gate_id = (_gate_id),\
+ .gate_rdy_id = (_gate_rdy_id),\
+ .bypass = (_bypass),\
+ .css = (_css),\
+ .drive = (_drive),\
+ }
+
+struct clk_oscillator_data *clk_oscillator_get_data(struct stm32_clk_priv *priv, int id);
+
+void clk_stm32_osc_init(struct stm32_clk_priv *priv, int id);
+bool clk_stm32_osc_gate_is_enabled(struct stm32_clk_priv *priv, int id);
+int clk_stm32_osc_gate_enable(struct stm32_clk_priv *priv, int id);
+void clk_stm32_osc_gate_disable(struct stm32_clk_priv *priv, int id);
+
+struct stm32_osc_cfg {
+ int osc_id;
+};
+
+#define CLK_OSC(idx, _idx, _parent, _osc_id) \
+ [(idx)] = (struct clk_stm32){ \
+ .binding = (_idx),\
+ .parent = (_parent),\
+ .flags = CLK_IS_CRITICAL,\
+ .clock_cfg = &(struct stm32_osc_cfg){\
+ .osc_id = (_osc_id),\
+ },\
+ .ops = &clk_stm32_osc_ops,\
+ }
+
+#define CLK_OSC_FIXED(idx, _idx, _parent, _osc_id) \
+ [(idx)] = (struct clk_stm32){ \
+ .binding = (_idx),\
+ .parent = (_parent),\
+ .flags = CLK_IS_CRITICAL,\
+ .clock_cfg = &(struct stm32_osc_cfg){\
+ .osc_id = (_osc_id),\
+ },\
+ .ops = &clk_stm32_osc_nogate_ops,\
+ }
+
+extern const struct stm32_clk_ops clk_mux_ops;
+extern const struct stm32_clk_ops clk_stm32_divider_ops;
+extern const struct stm32_clk_ops clk_stm32_gate_ops;
+extern const struct stm32_clk_ops clk_fixed_factor_ops;
+extern const struct stm32_clk_ops clk_gate_ops;
+extern const struct stm32_clk_ops clk_timer_ops;
+extern const struct stm32_clk_ops clk_stm32_fixed_rate_ops;
+extern const struct stm32_clk_ops clk_stm32_osc_ops;
+extern const struct stm32_clk_ops clk_stm32_osc_nogate_ops;
+
+#endif /* CLK_STM32_CORE_H */
diff --git a/drivers/st/clk/clk-stm32mp13.c b/drivers/st/clk/clk-stm32mp13.c
new file mode 100644
index 0000000..c960928
--- /dev/null
+++ b/drivers/st/clk/clk-stm32mp13.c
@@ -0,0 +1,2332 @@
+/*
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include "clk-stm32-core.h"
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32mp13_rcc.h>
+#include <drivers/st/stm32mp1_clk.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <dt-bindings/clock/stm32mp13-clksrc.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <lib/utils_def.h>
+#include <libfdt.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+struct stm32_osci_dt_cfg {
+ unsigned long freq;
+ bool bypass;
+ bool digbyp;
+ bool css;
+ uint32_t drive;
+};
+
+enum pll_mn {
+ PLL_CFG_M,
+ PLL_CFG_N,
+ PLL_DIV_MN_NB
+};
+
+enum pll_pqr {
+ PLL_CFG_P,
+ PLL_CFG_Q,
+ PLL_CFG_R,
+ PLL_DIV_PQR_NB
+};
+
+enum pll_csg {
+ PLL_CSG_MOD_PER,
+ PLL_CSG_INC_STEP,
+ PLL_CSG_SSCG_MODE,
+ PLL_CSG_NB
+};
+
+struct stm32_pll_vco {
+ uint32_t status;
+ uint32_t src;
+ uint32_t div_mn[PLL_DIV_MN_NB];
+ uint32_t frac;
+ bool csg_enabled;
+ uint32_t csg[PLL_CSG_NB];
+};
+
+struct stm32_pll_output {
+ uint32_t output[PLL_DIV_PQR_NB];
+};
+
+struct stm32_pll_dt_cfg {
+ struct stm32_pll_vco vco;
+ struct stm32_pll_output output;
+};
+
+struct stm32_clk_platdata {
+ uint32_t nosci;
+ struct stm32_osci_dt_cfg *osci;
+ uint32_t npll;
+ struct stm32_pll_dt_cfg *pll;
+ uint32_t nclksrc;
+ uint32_t *clksrc;
+ uint32_t nclkdiv;
+ uint32_t *clkdiv;
+};
+
+enum stm32_clock {
+ /* ROOT CLOCKS */
+ _CK_OFF,
+ _CK_HSI,
+ _CK_HSE,
+ _CK_CSI,
+ _CK_LSI,
+ _CK_LSE,
+ _I2SCKIN,
+ _CSI_DIV122,
+ _HSE_DIV,
+ _HSE_DIV2,
+ _CK_PLL1,
+ _CK_PLL2,
+ _CK_PLL3,
+ _CK_PLL4,
+ _PLL1P,
+ _PLL1P_DIV,
+ _PLL2P,
+ _PLL2Q,
+ _PLL2R,
+ _PLL3P,
+ _PLL3Q,
+ _PLL3R,
+ _PLL4P,
+ _PLL4Q,
+ _PLL4R,
+ _PCLK1,
+ _PCLK2,
+ _PCLK3,
+ _PCLK4,
+ _PCLK5,
+ _PCLK6,
+ _CKMPU,
+ _CKAXI,
+ _CKMLAHB,
+ _CKPER,
+ _CKTIMG1,
+ _CKTIMG2,
+ _CKTIMG3,
+ _USB_PHY_48,
+ _MCO1_K,
+ _MCO2_K,
+ _TRACECK,
+ /* BUS and KERNEL CLOCKS */
+ _DDRC1,
+ _DDRC1LP,
+ _DDRPHYC,
+ _DDRPHYCLP,
+ _DDRCAPB,
+ _DDRCAPBLP,
+ _AXIDCG,
+ _DDRPHYCAPB,
+ _DDRPHYCAPBLP,
+ _SYSCFG,
+ _DDRPERFM,
+ _IWDG2APB,
+ _USBPHY_K,
+ _USBO_K,
+ _RTCAPB,
+ _TZC,
+ _ETZPC,
+ _IWDG1APB,
+ _BSEC,
+ _STGENC,
+ _USART1_K,
+ _USART2_K,
+ _I2C3_K,
+ _I2C4_K,
+ _I2C5_K,
+ _TIM12,
+ _TIM15,
+ _RTCCK,
+ _GPIOA,
+ _GPIOB,
+ _GPIOC,
+ _GPIOD,
+ _GPIOE,
+ _GPIOF,
+ _GPIOG,
+ _GPIOH,
+ _GPIOI,
+ _PKA,
+ _SAES_K,
+ _CRYP1,
+ _HASH1,
+ _RNG1_K,
+ _BKPSRAM,
+ _SDMMC1_K,
+ _SDMMC2_K,
+ _DBGCK,
+ _USART3_K,
+ _UART4_K,
+ _UART5_K,
+ _UART7_K,
+ _UART8_K,
+ _USART6_K,
+ _MCE,
+ _FMC_K,
+ _QSPI_K,
+#if defined(IMAGE_BL32)
+ _LTDC,
+ _DMA1,
+ _DMA2,
+ _MDMA,
+ _ETH1MAC,
+ _USBH,
+ _TIM2,
+ _TIM3,
+ _TIM4,
+ _TIM5,
+ _TIM6,
+ _TIM7,
+ _LPTIM1_K,
+ _SPI2_K,
+ _SPI3_K,
+ _SPDIF_K,
+ _TIM1,
+ _TIM8,
+ _SPI1_K,
+ _SAI1_K,
+ _SAI2_K,
+ _DFSDM,
+ _FDCAN_K,
+ _TIM13,
+ _TIM14,
+ _TIM16,
+ _TIM17,
+ _SPI4_K,
+ _SPI5_K,
+ _I2C1_K,
+ _I2C2_K,
+ _ADFSDM,
+ _LPTIM2_K,
+ _LPTIM3_K,
+ _LPTIM4_K,
+ _LPTIM5_K,
+ _VREF,
+ _DTS,
+ _PMBCTRL,
+ _HDP,
+ _STGENRO,
+ _DCMIPP_K,
+ _DMAMUX1,
+ _DMAMUX2,
+ _DMA3,
+ _ADC1_K,
+ _ADC2_K,
+ _TSC,
+ _AXIMC,
+ _ETH1CK,
+ _ETH1TX,
+ _ETH1RX,
+ _CRC1,
+ _ETH2CK,
+ _ETH2TX,
+ _ETH2RX,
+ _ETH2MAC,
+#endif
+ CK_LAST
+};
+
+/* PARENT CONFIG */
+static const uint16_t RTC_src[] = {
+ _CK_OFF, _CK_LSE, _CK_LSI, _CK_HSE
+};
+
+static const uint16_t MCO1_src[] = {
+ _CK_HSI, _CK_HSE, _CK_CSI, _CK_LSI, _CK_LSE
+};
+
+static const uint16_t MCO2_src[] = {
+ _CKMPU, _CKAXI, _CKMLAHB, _PLL4P, _CK_HSE, _CK_HSI
+};
+
+static const uint16_t PLL12_src[] = {
+ _CK_HSI, _CK_HSE
+};
+
+static const uint16_t PLL3_src[] = {
+ _CK_HSI, _CK_HSE, _CK_CSI
+};
+
+static const uint16_t PLL4_src[] = {
+ _CK_HSI, _CK_HSE, _CK_CSI, _I2SCKIN
+};
+
+static const uint16_t MPU_src[] = {
+ _CK_HSI, _CK_HSE, _PLL1P, _PLL1P_DIV
+};
+
+static const uint16_t AXI_src[] = {
+ _CK_HSI, _CK_HSE, _PLL2P
+};
+
+static const uint16_t MLAHBS_src[] = {
+ _CK_HSI, _CK_HSE, _CK_CSI, _PLL3P
+};
+
+static const uint16_t CKPER_src[] = {
+ _CK_HSI, _CK_CSI, _CK_HSE, _CK_OFF
+};
+
+static const uint16_t I2C12_src[] = {
+ _PCLK1, _PLL4R, _CK_HSI, _CK_CSI
+};
+
+static const uint16_t I2C3_src[] = {
+ _PCLK6, _PLL4R, _CK_HSI, _CK_CSI
+};
+
+static const uint16_t I2C4_src[] = {
+ _PCLK6, _PLL4R, _CK_HSI, _CK_CSI
+};
+
+static const uint16_t I2C5_src[] = {
+ _PCLK6, _PLL4R, _CK_HSI, _CK_CSI
+};
+
+static const uint16_t SPI1_src[] = {
+ _PLL4P, _PLL3Q, _I2SCKIN, _CKPER, _PLL3R
+};
+
+static const uint16_t SPI23_src[] = {
+ _PLL4P, _PLL3Q, _I2SCKIN, _CKPER, _PLL3R
+};
+
+static const uint16_t SPI4_src[] = {
+ _PCLK6, _PLL4Q, _CK_HSI, _CK_CSI, _CK_HSE, _I2SCKIN
+};
+
+static const uint16_t SPI5_src[] = {
+ _PCLK6, _PLL4Q, _CK_HSI, _CK_CSI, _CK_HSE
+};
+
+static const uint16_t UART1_src[] = {
+ _PCLK6, _PLL3Q, _CK_HSI, _CK_CSI, _PLL4Q, _CK_HSE
+};
+
+static const uint16_t UART2_src[] = {
+ _PCLK6, _PLL3Q, _CK_HSI, _CK_CSI, _PLL4Q, _CK_HSE
+};
+
+static const uint16_t UART35_src[] = {
+ _PCLK1, _PLL4Q, _CK_HSI, _CK_CSI, _CK_HSE
+};
+
+static const uint16_t UART4_src[] = {
+ _PCLK1, _PLL4Q, _CK_HSI, _CK_CSI, _CK_HSE
+};
+
+static const uint16_t UART6_src[] = {
+ _PCLK2, _PLL4Q, _CK_HSI, _CK_CSI, _CK_HSE
+};
+
+static const uint16_t UART78_src[] = {
+ _PCLK1, _PLL4Q, _CK_HSI, _CK_CSI, _CK_HSE
+};
+
+static const uint16_t LPTIM1_src[] = {
+ _PCLK1, _PLL4P, _PLL3Q, _CK_LSE, _CK_LSI, _CKPER
+};
+
+static const uint16_t LPTIM2_src[] = {
+ _PCLK3, _PLL4Q, _CKPER, _CK_LSE, _CK_LSI
+};
+
+static const uint16_t LPTIM3_src[] = {
+ _PCLK3, _PLL4Q, _CKPER, _CK_LSE, _CK_LSI
+};
+
+static const uint16_t LPTIM45_src[] = {
+ _PCLK3, _PLL4P, _PLL3Q, _CK_LSE, _CK_LSI, _CKPER
+};
+
+static const uint16_t SAI1_src[] = {
+ _PLL4Q, _PLL3Q, _I2SCKIN, _CKPER, _PLL3R
+};
+
+static const uint16_t SAI2_src[] = {
+ _PLL4Q, _PLL3Q, _I2SCKIN, _CKPER, _NO_ID, _PLL3R
+};
+
+static const uint16_t FDCAN_src[] = {
+ _CK_HSE, _PLL3Q, _PLL4Q, _PLL4R
+};
+
+static const uint16_t SPDIF_src[] = {
+ _PLL4P, _PLL3Q, _CK_HSI
+};
+
+static const uint16_t ADC1_src[] = {
+ _PLL4R, _CKPER, _PLL3Q
+};
+
+static const uint16_t ADC2_src[] = {
+ _PLL4R, _CKPER, _PLL3Q
+};
+
+static const uint16_t SDMMC1_src[] = {
+ _CKAXI, _PLL3R, _PLL4P, _CK_HSI
+};
+
+static const uint16_t SDMMC2_src[] = {
+ _CKAXI, _PLL3R, _PLL4P, _CK_HSI
+};
+
+static const uint16_t ETH1_src[] = {
+ _PLL4P, _PLL3Q
+};
+
+static const uint16_t ETH2_src[] = {
+ _PLL4P, _PLL3Q
+};
+
+static const uint16_t USBPHY_src[] = {
+ _CK_HSE, _PLL4R, _HSE_DIV2
+};
+
+static const uint16_t USBO_src[] = {
+ _PLL4R, _USB_PHY_48
+};
+
+static const uint16_t QSPI_src[] = {
+ _CKAXI, _PLL3R, _PLL4P, _CKPER
+};
+
+static const uint16_t FMC_src[] = {
+ _CKAXI, _PLL3R, _PLL4P, _CKPER
+};
+
+/* Position 2 of RNG1 mux is reserved */
+static const uint16_t RNG1_src[] = {
+ _CK_CSI, _PLL4R, _CK_OFF, _CK_LSI
+};
+
+static const uint16_t STGEN_src[] = {
+ _CK_HSI, _CK_HSE
+};
+
+static const uint16_t DCMIPP_src[] = {
+ _CKAXI, _PLL2Q, _PLL4P, _CKPER
+};
+
+static const uint16_t SAES_src[] = {
+ _CKAXI, _CKPER, _PLL4R, _CK_LSI
+};
+
+#define MUX_CFG(id, src, _offset, _shift, _witdh)[id] = {\
+ .id_parents = src,\
+ .num_parents = ARRAY_SIZE(src),\
+ .mux = &(struct mux_cfg) {\
+ .offset = (_offset),\
+ .shift = (_shift),\
+ .width = (_witdh),\
+ .bitrdy = MUX_NO_BIT_RDY,\
+ },\
+}
+
+#define MUX_RDY_CFG(id, src, _offset, _shift, _witdh)[id] = {\
+ .id_parents = src,\
+ .num_parents = ARRAY_SIZE(src),\
+ .mux = &(struct mux_cfg) {\
+ .offset = (_offset),\
+ .shift = (_shift),\
+ .width = (_witdh),\
+ .bitrdy = 31,\
+ },\
+}
+
+static const struct parent_cfg parent_mp13[] = {
+ MUX_CFG(MUX_ADC1, ADC1_src, RCC_ADC12CKSELR, 0, 2),
+ MUX_CFG(MUX_ADC2, ADC2_src, RCC_ADC12CKSELR, 2, 2),
+ MUX_RDY_CFG(MUX_AXI, AXI_src, RCC_ASSCKSELR, 0, 3),
+ MUX_CFG(MUX_CKPER, CKPER_src, RCC_CPERCKSELR, 0, 2),
+ MUX_CFG(MUX_DCMIPP, DCMIPP_src, RCC_DCMIPPCKSELR, 0, 2),
+ MUX_CFG(MUX_ETH1, ETH1_src, RCC_ETH12CKSELR, 0, 2),
+ MUX_CFG(MUX_ETH2, ETH2_src, RCC_ETH12CKSELR, 8, 2),
+ MUX_CFG(MUX_FDCAN, FDCAN_src, RCC_FDCANCKSELR, 0, 2),
+ MUX_CFG(MUX_FMC, FMC_src, RCC_FMCCKSELR, 0, 2),
+ MUX_CFG(MUX_I2C12, I2C12_src, RCC_I2C12CKSELR, 0, 3),
+ MUX_CFG(MUX_I2C3, I2C3_src, RCC_I2C345CKSELR, 0, 3),
+ MUX_CFG(MUX_I2C4, I2C4_src, RCC_I2C345CKSELR, 3, 3),
+ MUX_CFG(MUX_I2C5, I2C5_src, RCC_I2C345CKSELR, 6, 3),
+ MUX_CFG(MUX_LPTIM1, LPTIM1_src, RCC_LPTIM1CKSELR, 0, 3),
+ MUX_CFG(MUX_LPTIM2, LPTIM2_src, RCC_LPTIM23CKSELR, 0, 3),
+ MUX_CFG(MUX_LPTIM3, LPTIM3_src, RCC_LPTIM23CKSELR, 3, 3),
+ MUX_CFG(MUX_LPTIM45, LPTIM45_src, RCC_LPTIM45CKSELR, 0, 3),
+ MUX_CFG(MUX_MCO1, MCO1_src, RCC_MCO1CFGR, 0, 3),
+ MUX_CFG(MUX_MCO2, MCO2_src, RCC_MCO2CFGR, 0, 3),
+ MUX_RDY_CFG(MUX_MLAHB, MLAHBS_src, RCC_MSSCKSELR, 0, 2),
+ MUX_RDY_CFG(MUX_MPU, MPU_src, RCC_MPCKSELR, 0, 2),
+ MUX_RDY_CFG(MUX_PLL12, PLL12_src, RCC_RCK12SELR, 0, 2),
+ MUX_RDY_CFG(MUX_PLL3, PLL3_src, RCC_RCK3SELR, 0, 2),
+ MUX_RDY_CFG(MUX_PLL4, PLL4_src, RCC_RCK4SELR, 0, 2),
+ MUX_CFG(MUX_QSPI, QSPI_src, RCC_QSPICKSELR, 0, 2),
+ MUX_CFG(MUX_RNG1, RNG1_src, RCC_RNG1CKSELR, 0, 2),
+ MUX_CFG(MUX_RTC, RTC_src, RCC_BDCR, 16, 2),
+ MUX_CFG(MUX_SAES, SAES_src, RCC_SAESCKSELR, 0, 2),
+ MUX_CFG(MUX_SAI1, SAI1_src, RCC_SAI1CKSELR, 0, 3),
+ MUX_CFG(MUX_SAI2, SAI2_src, RCC_SAI2CKSELR, 0, 3),
+ MUX_CFG(MUX_SDMMC1, SDMMC1_src, RCC_SDMMC12CKSELR, 0, 3),
+ MUX_CFG(MUX_SDMMC2, SDMMC2_src, RCC_SDMMC12CKSELR, 3, 3),
+ MUX_CFG(MUX_SPDIF, SPDIF_src, RCC_SPDIFCKSELR, 0, 2),
+ MUX_CFG(MUX_SPI1, SPI1_src, RCC_SPI2S1CKSELR, 0, 3),
+ MUX_CFG(MUX_SPI23, SPI23_src, RCC_SPI2S23CKSELR, 0, 3),
+ MUX_CFG(MUX_SPI4, SPI4_src, RCC_SPI45CKSELR, 0, 3),
+ MUX_CFG(MUX_SPI5, SPI5_src, RCC_SPI45CKSELR, 3, 3),
+ MUX_CFG(MUX_STGEN, STGEN_src, RCC_STGENCKSELR, 0, 2),
+ MUX_CFG(MUX_UART1, UART1_src, RCC_UART12CKSELR, 0, 3),
+ MUX_CFG(MUX_UART2, UART2_src, RCC_UART12CKSELR, 3, 3),
+ MUX_CFG(MUX_UART35, UART35_src, RCC_UART35CKSELR, 0, 3),
+ MUX_CFG(MUX_UART4, UART4_src, RCC_UART4CKSELR, 0, 3),
+ MUX_CFG(MUX_UART6, UART6_src, RCC_UART6CKSELR, 0, 3),
+ MUX_CFG(MUX_UART78, UART78_src, RCC_UART78CKSELR, 0, 3),
+ MUX_CFG(MUX_USBO, USBO_src, RCC_USBCKSELR, 4, 1),
+ MUX_CFG(MUX_USBPHY, USBPHY_src, RCC_USBCKSELR, 0, 2),
+};
+
+/*
+ * GATE CONFIG
+ */
+
+enum enum_gate_cfg {
+ GATE_ZERO, /* reserved for no gate */
+ GATE_LSE,
+ GATE_RTCCK,
+ GATE_LSI,
+ GATE_HSI,
+ GATE_CSI,
+ GATE_HSE,
+ GATE_LSI_RDY,
+ GATE_CSI_RDY,
+ GATE_LSE_RDY,
+ GATE_HSE_RDY,
+ GATE_HSI_RDY,
+ GATE_MCO1,
+ GATE_MCO2,
+ GATE_DBGCK,
+ GATE_TRACECK,
+ GATE_PLL1,
+ GATE_PLL1_DIVP,
+ GATE_PLL1_DIVQ,
+ GATE_PLL1_DIVR,
+ GATE_PLL2,
+ GATE_PLL2_DIVP,
+ GATE_PLL2_DIVQ,
+ GATE_PLL2_DIVR,
+ GATE_PLL3,
+ GATE_PLL3_DIVP,
+ GATE_PLL3_DIVQ,
+ GATE_PLL3_DIVR,
+ GATE_PLL4,
+ GATE_PLL4_DIVP,
+ GATE_PLL4_DIVQ,
+ GATE_PLL4_DIVR,
+ GATE_DDRC1,
+ GATE_DDRC1LP,
+ GATE_DDRPHYC,
+ GATE_DDRPHYCLP,
+ GATE_DDRCAPB,
+ GATE_DDRCAPBLP,
+ GATE_AXIDCG,
+ GATE_DDRPHYCAPB,
+ GATE_DDRPHYCAPBLP,
+ GATE_TIM2,
+ GATE_TIM3,
+ GATE_TIM4,
+ GATE_TIM5,
+ GATE_TIM6,
+ GATE_TIM7,
+ GATE_LPTIM1,
+ GATE_SPI2,
+ GATE_SPI3,
+ GATE_USART3,
+ GATE_UART4,
+ GATE_UART5,
+ GATE_UART7,
+ GATE_UART8,
+ GATE_I2C1,
+ GATE_I2C2,
+ GATE_SPDIF,
+ GATE_TIM1,
+ GATE_TIM8,
+ GATE_SPI1,
+ GATE_USART6,
+ GATE_SAI1,
+ GATE_SAI2,
+ GATE_DFSDM,
+ GATE_ADFSDM,
+ GATE_FDCAN,
+ GATE_LPTIM2,
+ GATE_LPTIM3,
+ GATE_LPTIM4,
+ GATE_LPTIM5,
+ GATE_VREF,
+ GATE_DTS,
+ GATE_PMBCTRL,
+ GATE_HDP,
+ GATE_SYSCFG,
+ GATE_DCMIPP,
+ GATE_DDRPERFM,
+ GATE_IWDG2APB,
+ GATE_USBPHY,
+ GATE_STGENRO,
+ GATE_LTDC,
+ GATE_RTCAPB,
+ GATE_TZC,
+ GATE_ETZPC,
+ GATE_IWDG1APB,
+ GATE_BSEC,
+ GATE_STGENC,
+ GATE_USART1,
+ GATE_USART2,
+ GATE_SPI4,
+ GATE_SPI5,
+ GATE_I2C3,
+ GATE_I2C4,
+ GATE_I2C5,
+ GATE_TIM12,
+ GATE_TIM13,
+ GATE_TIM14,
+ GATE_TIM15,
+ GATE_TIM16,
+ GATE_TIM17,
+ GATE_DMA1,
+ GATE_DMA2,
+ GATE_DMAMUX1,
+ GATE_DMA3,
+ GATE_DMAMUX2,
+ GATE_ADC1,
+ GATE_ADC2,
+ GATE_USBO,
+ GATE_TSC,
+ GATE_GPIOA,
+ GATE_GPIOB,
+ GATE_GPIOC,
+ GATE_GPIOD,
+ GATE_GPIOE,
+ GATE_GPIOF,
+ GATE_GPIOG,
+ GATE_GPIOH,
+ GATE_GPIOI,
+ GATE_PKA,
+ GATE_SAES,
+ GATE_CRYP1,
+ GATE_HASH1,
+ GATE_RNG1,
+ GATE_BKPSRAM,
+ GATE_AXIMC,
+ GATE_MCE,
+ GATE_ETH1CK,
+ GATE_ETH1TX,
+ GATE_ETH1RX,
+ GATE_ETH1MAC,
+ GATE_FMC,
+ GATE_QSPI,
+ GATE_SDMMC1,
+ GATE_SDMMC2,
+ GATE_CRC1,
+ GATE_USBH,
+ GATE_ETH2CK,
+ GATE_ETH2TX,
+ GATE_ETH2RX,
+ GATE_ETH2MAC,
+ GATE_MDMA,
+
+ LAST_GATE
+};
+
+#define GATE_CFG(id, _offset, _bit_idx, _offset_clr)[id] = {\
+ .offset = (_offset),\
+ .bit_idx = (_bit_idx),\
+ .set_clr = (_offset_clr),\
+}
+
+static const struct gate_cfg gates_mp13[LAST_GATE] = {
+ GATE_CFG(GATE_LSE, RCC_BDCR, 0, 0),
+ GATE_CFG(GATE_RTCCK, RCC_BDCR, 20, 0),
+ GATE_CFG(GATE_LSI, RCC_RDLSICR, 0, 0),
+ GATE_CFG(GATE_HSI, RCC_OCENSETR, 0, 1),
+ GATE_CFG(GATE_CSI, RCC_OCENSETR, 4, 1),
+ GATE_CFG(GATE_HSE, RCC_OCENSETR, 8, 1),
+ GATE_CFG(GATE_LSI_RDY, RCC_RDLSICR, 1, 0),
+ GATE_CFG(GATE_CSI_RDY, RCC_OCRDYR, 4, 0),
+ GATE_CFG(GATE_LSE_RDY, RCC_BDCR, 2, 0),
+ GATE_CFG(GATE_HSE_RDY, RCC_OCRDYR, 8, 0),
+ GATE_CFG(GATE_HSI_RDY, RCC_OCRDYR, 0, 0),
+ GATE_CFG(GATE_MCO1, RCC_MCO1CFGR, 12, 0),
+ GATE_CFG(GATE_MCO2, RCC_MCO2CFGR, 12, 0),
+ GATE_CFG(GATE_DBGCK, RCC_DBGCFGR, 8, 0),
+ GATE_CFG(GATE_TRACECK, RCC_DBGCFGR, 9, 0),
+ GATE_CFG(GATE_PLL1, RCC_PLL1CR, 0, 0),
+ GATE_CFG(GATE_PLL1_DIVP, RCC_PLL1CR, 4, 0),
+ GATE_CFG(GATE_PLL1_DIVQ, RCC_PLL1CR, 5, 0),
+ GATE_CFG(GATE_PLL1_DIVR, RCC_PLL1CR, 6, 0),
+ GATE_CFG(GATE_PLL2, RCC_PLL2CR, 0, 0),
+ GATE_CFG(GATE_PLL2_DIVP, RCC_PLL2CR, 4, 0),
+ GATE_CFG(GATE_PLL2_DIVQ, RCC_PLL2CR, 5, 0),
+ GATE_CFG(GATE_PLL2_DIVR, RCC_PLL2CR, 6, 0),
+ GATE_CFG(GATE_PLL3, RCC_PLL3CR, 0, 0),
+ GATE_CFG(GATE_PLL3_DIVP, RCC_PLL3CR, 4, 0),
+ GATE_CFG(GATE_PLL3_DIVQ, RCC_PLL3CR, 5, 0),
+ GATE_CFG(GATE_PLL3_DIVR, RCC_PLL3CR, 6, 0),
+ GATE_CFG(GATE_PLL4, RCC_PLL4CR, 0, 0),
+ GATE_CFG(GATE_PLL4_DIVP, RCC_PLL4CR, 4, 0),
+ GATE_CFG(GATE_PLL4_DIVQ, RCC_PLL4CR, 5, 0),
+ GATE_CFG(GATE_PLL4_DIVR, RCC_PLL4CR, 6, 0),
+ GATE_CFG(GATE_DDRC1, RCC_DDRITFCR, 0, 0),
+ GATE_CFG(GATE_DDRC1LP, RCC_DDRITFCR, 1, 0),
+ GATE_CFG(GATE_DDRPHYC, RCC_DDRITFCR, 4, 0),
+ GATE_CFG(GATE_DDRPHYCLP, RCC_DDRITFCR, 5, 0),
+ GATE_CFG(GATE_DDRCAPB, RCC_DDRITFCR, 6, 0),
+ GATE_CFG(GATE_DDRCAPBLP, RCC_DDRITFCR, 7, 0),
+ GATE_CFG(GATE_AXIDCG, RCC_DDRITFCR, 8, 0),
+ GATE_CFG(GATE_DDRPHYCAPB, RCC_DDRITFCR, 9, 0),
+ GATE_CFG(GATE_DDRPHYCAPBLP, RCC_DDRITFCR, 10, 0),
+ GATE_CFG(GATE_TIM2, RCC_MP_APB1ENSETR, 0, 1),
+ GATE_CFG(GATE_TIM3, RCC_MP_APB1ENSETR, 1, 1),
+ GATE_CFG(GATE_TIM4, RCC_MP_APB1ENSETR, 2, 1),
+ GATE_CFG(GATE_TIM5, RCC_MP_APB1ENSETR, 3, 1),
+ GATE_CFG(GATE_TIM6, RCC_MP_APB1ENSETR, 4, 1),
+ GATE_CFG(GATE_TIM7, RCC_MP_APB1ENSETR, 5, 1),
+ GATE_CFG(GATE_LPTIM1, RCC_MP_APB1ENSETR, 9, 1),
+ GATE_CFG(GATE_SPI2, RCC_MP_APB1ENSETR, 11, 1),
+ GATE_CFG(GATE_SPI3, RCC_MP_APB1ENSETR, 12, 1),
+ GATE_CFG(GATE_USART3, RCC_MP_APB1ENSETR, 15, 1),
+ GATE_CFG(GATE_UART4, RCC_MP_APB1ENSETR, 16, 1),
+ GATE_CFG(GATE_UART5, RCC_MP_APB1ENSETR, 17, 1),
+ GATE_CFG(GATE_UART7, RCC_MP_APB1ENSETR, 18, 1),
+ GATE_CFG(GATE_UART8, RCC_MP_APB1ENSETR, 19, 1),
+ GATE_CFG(GATE_I2C1, RCC_MP_APB1ENSETR, 21, 1),
+ GATE_CFG(GATE_I2C2, RCC_MP_APB1ENSETR, 22, 1),
+ GATE_CFG(GATE_SPDIF, RCC_MP_APB1ENSETR, 26, 1),
+ GATE_CFG(GATE_TIM1, RCC_MP_APB2ENSETR, 0, 1),
+ GATE_CFG(GATE_TIM8, RCC_MP_APB2ENSETR, 1, 1),
+ GATE_CFG(GATE_SPI1, RCC_MP_APB2ENSETR, 8, 1),
+ GATE_CFG(GATE_USART6, RCC_MP_APB2ENSETR, 13, 1),
+ GATE_CFG(GATE_SAI1, RCC_MP_APB2ENSETR, 16, 1),
+ GATE_CFG(GATE_SAI2, RCC_MP_APB2ENSETR, 17, 1),
+ GATE_CFG(GATE_DFSDM, RCC_MP_APB2ENSETR, 20, 1),
+ GATE_CFG(GATE_ADFSDM, RCC_MP_APB2ENSETR, 21, 1),
+ GATE_CFG(GATE_FDCAN, RCC_MP_APB2ENSETR, 24, 1),
+ GATE_CFG(GATE_LPTIM2, RCC_MP_APB3ENSETR, 0, 1),
+ GATE_CFG(GATE_LPTIM3, RCC_MP_APB3ENSETR, 1, 1),
+ GATE_CFG(GATE_LPTIM4, RCC_MP_APB3ENSETR, 2, 1),
+ GATE_CFG(GATE_LPTIM5, RCC_MP_APB3ENSETR, 3, 1),
+ GATE_CFG(GATE_VREF, RCC_MP_APB3ENSETR, 13, 1),
+ GATE_CFG(GATE_DTS, RCC_MP_APB3ENSETR, 16, 1),
+ GATE_CFG(GATE_PMBCTRL, RCC_MP_APB3ENSETR, 17, 1),
+ GATE_CFG(GATE_HDP, RCC_MP_APB3ENSETR, 20, 1),
+ GATE_CFG(GATE_SYSCFG, RCC_MP_S_APB3ENSETR, 0, 1),
+ GATE_CFG(GATE_DCMIPP, RCC_MP_APB4ENSETR, 1, 1),
+ GATE_CFG(GATE_DDRPERFM, RCC_MP_APB4ENSETR, 8, 1),
+ GATE_CFG(GATE_IWDG2APB, RCC_MP_APB4ENSETR, 15, 1),
+ GATE_CFG(GATE_USBPHY, RCC_MP_APB4ENSETR, 16, 1),
+ GATE_CFG(GATE_STGENRO, RCC_MP_APB4ENSETR, 20, 1),
+ GATE_CFG(GATE_LTDC, RCC_MP_S_APB4ENSETR, 0, 1),
+ GATE_CFG(GATE_RTCAPB, RCC_MP_APB5ENSETR, 8, 1),
+ GATE_CFG(GATE_TZC, RCC_MP_APB5ENSETR, 11, 1),
+ GATE_CFG(GATE_ETZPC, RCC_MP_APB5ENSETR, 13, 1),
+ GATE_CFG(GATE_IWDG1APB, RCC_MP_APB5ENSETR, 15, 1),
+ GATE_CFG(GATE_BSEC, RCC_MP_APB5ENSETR, 16, 1),
+ GATE_CFG(GATE_STGENC, RCC_MP_APB5ENSETR, 20, 1),
+ GATE_CFG(GATE_USART1, RCC_MP_APB6ENSETR, 0, 1),
+ GATE_CFG(GATE_USART2, RCC_MP_APB6ENSETR, 1, 1),
+ GATE_CFG(GATE_SPI4, RCC_MP_APB6ENSETR, 2, 1),
+ GATE_CFG(GATE_SPI5, RCC_MP_APB6ENSETR, 3, 1),
+ GATE_CFG(GATE_I2C3, RCC_MP_APB6ENSETR, 4, 1),
+ GATE_CFG(GATE_I2C4, RCC_MP_APB6ENSETR, 5, 1),
+ GATE_CFG(GATE_I2C5, RCC_MP_APB6ENSETR, 6, 1),
+ GATE_CFG(GATE_TIM12, RCC_MP_APB6ENSETR, 7, 1),
+ GATE_CFG(GATE_TIM13, RCC_MP_APB6ENSETR, 8, 1),
+ GATE_CFG(GATE_TIM14, RCC_MP_APB6ENSETR, 9, 1),
+ GATE_CFG(GATE_TIM15, RCC_MP_APB6ENSETR, 10, 1),
+ GATE_CFG(GATE_TIM16, RCC_MP_APB6ENSETR, 11, 1),
+ GATE_CFG(GATE_TIM17, RCC_MP_APB6ENSETR, 12, 1),
+ GATE_CFG(GATE_DMA1, RCC_MP_AHB2ENSETR, 0, 1),
+ GATE_CFG(GATE_DMA2, RCC_MP_AHB2ENSETR, 1, 1),
+ GATE_CFG(GATE_DMAMUX1, RCC_MP_AHB2ENSETR, 2, 1),
+ GATE_CFG(GATE_DMA3, RCC_MP_AHB2ENSETR, 3, 1),
+ GATE_CFG(GATE_DMAMUX2, RCC_MP_AHB2ENSETR, 4, 1),
+ GATE_CFG(GATE_ADC1, RCC_MP_AHB2ENSETR, 5, 1),
+ GATE_CFG(GATE_ADC2, RCC_MP_AHB2ENSETR, 6, 1),
+ GATE_CFG(GATE_USBO, RCC_MP_AHB2ENSETR, 8, 1),
+ GATE_CFG(GATE_TSC, RCC_MP_AHB4ENSETR, 15, 1),
+
+ GATE_CFG(GATE_GPIOA, RCC_MP_S_AHB4ENSETR, 0, 1),
+ GATE_CFG(GATE_GPIOB, RCC_MP_S_AHB4ENSETR, 1, 1),
+ GATE_CFG(GATE_GPIOC, RCC_MP_S_AHB4ENSETR, 2, 1),
+ GATE_CFG(GATE_GPIOD, RCC_MP_S_AHB4ENSETR, 3, 1),
+ GATE_CFG(GATE_GPIOE, RCC_MP_S_AHB4ENSETR, 4, 1),
+ GATE_CFG(GATE_GPIOF, RCC_MP_S_AHB4ENSETR, 5, 1),
+ GATE_CFG(GATE_GPIOG, RCC_MP_S_AHB4ENSETR, 6, 1),
+ GATE_CFG(GATE_GPIOH, RCC_MP_S_AHB4ENSETR, 7, 1),
+ GATE_CFG(GATE_GPIOI, RCC_MP_S_AHB4ENSETR, 8, 1),
+
+ GATE_CFG(GATE_PKA, RCC_MP_AHB5ENSETR, 2, 1),
+ GATE_CFG(GATE_SAES, RCC_MP_AHB5ENSETR, 3, 1),
+ GATE_CFG(GATE_CRYP1, RCC_MP_AHB5ENSETR, 4, 1),
+ GATE_CFG(GATE_HASH1, RCC_MP_AHB5ENSETR, 5, 1),
+ GATE_CFG(GATE_RNG1, RCC_MP_AHB5ENSETR, 6, 1),
+ GATE_CFG(GATE_BKPSRAM, RCC_MP_AHB5ENSETR, 8, 1),
+ GATE_CFG(GATE_AXIMC, RCC_MP_AHB5ENSETR, 16, 1),
+ GATE_CFG(GATE_MCE, RCC_MP_AHB6ENSETR, 1, 1),
+ GATE_CFG(GATE_ETH1CK, RCC_MP_AHB6ENSETR, 7, 1),
+ GATE_CFG(GATE_ETH1TX, RCC_MP_AHB6ENSETR, 8, 1),
+ GATE_CFG(GATE_ETH1RX, RCC_MP_AHB6ENSETR, 9, 1),
+ GATE_CFG(GATE_ETH1MAC, RCC_MP_AHB6ENSETR, 10, 1),
+ GATE_CFG(GATE_FMC, RCC_MP_AHB6ENSETR, 12, 1),
+ GATE_CFG(GATE_QSPI, RCC_MP_AHB6ENSETR, 14, 1),
+ GATE_CFG(GATE_SDMMC1, RCC_MP_AHB6ENSETR, 16, 1),
+ GATE_CFG(GATE_SDMMC2, RCC_MP_AHB6ENSETR, 17, 1),
+ GATE_CFG(GATE_CRC1, RCC_MP_AHB6ENSETR, 20, 1),
+ GATE_CFG(GATE_USBH, RCC_MP_AHB6ENSETR, 24, 1),
+ GATE_CFG(GATE_ETH2CK, RCC_MP_AHB6ENSETR, 27, 1),
+ GATE_CFG(GATE_ETH2TX, RCC_MP_AHB6ENSETR, 28, 1),
+ GATE_CFG(GATE_ETH2RX, RCC_MP_AHB6ENSETR, 29, 1),
+ GATE_CFG(GATE_ETH2MAC, RCC_MP_AHB6ENSETR, 30, 1),
+ GATE_CFG(GATE_MDMA, RCC_MP_S_AHB6ENSETR, 0, 1),
+};
+
+/*
+ * DIV CONFIG
+ */
+
+static const struct clk_div_table axi_div_table[] = {
+ { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
+ { 4, 4 }, { 5, 4 }, { 6, 4 }, { 7, 4 },
+ { 0 },
+};
+
+static const struct clk_div_table mlahb_div_table[] = {
+ { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 },
+ { 4, 16 }, { 5, 32 }, { 6, 64 }, { 7, 128 },
+ { 8, 256 }, { 9, 512 }, { 10, 512}, { 11, 512 },
+ { 12, 512 }, { 13, 512 }, { 14, 512}, { 15, 512 },
+ { 0 },
+};
+
+static const struct clk_div_table apb_div_table[] = {
+ { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 },
+ { 4, 16 }, { 5, 16 }, { 6, 16 }, { 7, 16 },
+ { 0 },
+};
+
+#define DIV_CFG(id, _offset, _shift, _width, _flags, _table, _bitrdy)[id] = {\
+ .offset = _offset,\
+ .shift = _shift,\
+ .width = _width,\
+ .flags = _flags,\
+ .table = _table,\
+ .bitrdy = _bitrdy,\
+}
+
+static const struct div_cfg dividers_mp13[] = {
+ DIV_CFG(DIV_PLL1DIVP, RCC_PLL1CFGR2, 0, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_PLL2DIVP, RCC_PLL2CFGR2, 0, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_PLL2DIVQ, RCC_PLL2CFGR2, 8, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_PLL2DIVR, RCC_PLL2CFGR2, 16, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_PLL3DIVP, RCC_PLL3CFGR2, 0, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_PLL3DIVQ, RCC_PLL3CFGR2, 8, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_PLL3DIVR, RCC_PLL3CFGR2, 16, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_PLL4DIVP, RCC_PLL4CFGR2, 0, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_PLL4DIVQ, RCC_PLL4CFGR2, 8, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_PLL4DIVR, RCC_PLL4CFGR2, 16, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_MPU, RCC_MPCKDIVR, 0, 4, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_AXI, RCC_AXIDIVR, 0, 3, 0, axi_div_table, 31),
+ DIV_CFG(DIV_MLAHB, RCC_MLAHBDIVR, 0, 4, 0, mlahb_div_table, 31),
+ DIV_CFG(DIV_APB1, RCC_APB1DIVR, 0, 3, 0, apb_div_table, 31),
+ DIV_CFG(DIV_APB2, RCC_APB2DIVR, 0, 3, 0, apb_div_table, 31),
+ DIV_CFG(DIV_APB3, RCC_APB3DIVR, 0, 3, 0, apb_div_table, 31),
+ DIV_CFG(DIV_APB4, RCC_APB4DIVR, 0, 3, 0, apb_div_table, 31),
+ DIV_CFG(DIV_APB5, RCC_APB5DIVR, 0, 3, 0, apb_div_table, 31),
+ DIV_CFG(DIV_APB6, RCC_APB6DIVR, 0, 3, 0, apb_div_table, 31),
+ DIV_CFG(DIV_RTC, RCC_RTCDIVR, 0, 6, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_MCO1, RCC_MCO1CFGR, 4, 4, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_MCO2, RCC_MCO2CFGR, 4, 4, 0, NULL, DIV_NO_BIT_RDY),
+
+ DIV_CFG(DIV_HSI, RCC_HSICFGR, 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_TRACE, RCC_DBGCFGR, 0, 3, CLK_DIVIDER_POWER_OF_TWO, NULL, DIV_NO_BIT_RDY),
+
+ DIV_CFG(DIV_ETH1PTP, RCC_ETH12CKSELR, 4, 4, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_ETH2PTP, RCC_ETH12CKSELR, 12, 4, 0, NULL, DIV_NO_BIT_RDY),
+};
+
+#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
+
+enum stm32_osc {
+ OSC_HSI,
+ OSC_HSE,
+ OSC_CSI,
+ OSC_LSI,
+ OSC_LSE,
+ OSC_I2SCKIN,
+ NB_OSCILLATOR
+};
+
+enum stm32mp1_pll_id {
+ _PLL1,
+ _PLL2,
+ _PLL3,
+ _PLL4,
+ _PLL_NB
+};
+
+enum stm32mp1_plltype {
+ PLL_800,
+ PLL_1600,
+ PLL_2000,
+ PLL_TYPE_NB
+};
+
+#define RCC_OFFSET_PLLXCR 0
+#define RCC_OFFSET_PLLXCFGR1 4
+#define RCC_OFFSET_PLLXCFGR2 8
+#define RCC_OFFSET_PLLXFRACR 12
+#define RCC_OFFSET_PLLXCSGR 16
+
+struct stm32_clk_pll {
+ enum stm32mp1_plltype plltype;
+ uint16_t clk_id;
+ uint16_t reg_pllxcr;
+};
+
+struct stm32mp1_pll {
+ uint8_t refclk_min;
+ uint8_t refclk_max;
+};
+
+/* Define characteristic of PLL according type */
+static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = {
+ [PLL_800] = {
+ .refclk_min = 4,
+ .refclk_max = 16,
+ },
+ [PLL_1600] = {
+ .refclk_min = 8,
+ .refclk_max = 16,
+ },
+ [PLL_2000] = {
+ .refclk_min = 8,
+ .refclk_max = 16,
+ },
+};
+
+#if STM32MP_USB_PROGRAMMER
+static bool pll4_bootrom;
+#endif
+
+/* RCC clock device driver private */
+static unsigned int refcounts_mp13[CK_LAST];
+
+static const struct stm32_clk_pll *clk_st32_pll_data(unsigned int idx);
+
+#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
+static void clk_oscillator_check_bypass(struct stm32_clk_priv *priv, int idx,
+ bool digbyp, bool bypass)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, idx);
+ struct stm32_clk_bypass *bypass_data = osc_data->bypass;
+ uintptr_t address;
+
+ if (bypass_data == NULL) {
+ return;
+ }
+
+ address = priv->base + bypass_data->offset;
+ if ((mmio_read_32(address) & RCC_OCENR_HSEBYP) &&
+ (!(digbyp || bypass))) {
+ panic();
+ }
+}
+#endif
+
+static void stm32_enable_oscillator_hse(struct stm32_clk_priv *priv)
+{
+ struct stm32_clk_platdata *pdata = priv->pdata;
+ struct stm32_osci_dt_cfg *osci = &pdata->osci[OSC_HSE];
+ bool digbyp = osci->digbyp;
+ bool bypass = osci->bypass;
+ bool css = osci->css;
+
+ if (_clk_stm32_get_rate(priv, _CK_HSE) == 0U) {
+ return;
+ }
+
+ clk_oscillator_set_bypass(priv, _CK_HSE, digbyp, bypass);
+
+ _clk_stm32_enable(priv, _CK_HSE);
+
+#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
+ clk_oscillator_check_bypass(priv, _CK_HSE, digbyp, bypass);
+#endif
+
+ clk_oscillator_set_css(priv, _CK_HSE, css);
+}
+
+static void stm32_enable_oscillator_lse(struct stm32_clk_priv *priv)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, _CK_LSE);
+ struct stm32_clk_platdata *pdata = priv->pdata;
+ struct stm32_osci_dt_cfg *osci = &pdata->osci[OSC_LSE];
+ bool digbyp = osci->digbyp;
+ bool bypass = osci->bypass;
+ uint8_t drive = osci->drive;
+
+ if (_clk_stm32_get_rate(priv, _CK_LSE) == 0U) {
+ return;
+ }
+
+ clk_oscillator_set_bypass(priv, _CK_LSE, digbyp, bypass);
+
+ clk_oscillator_set_drive(priv, _CK_LSE, drive);
+
+ _clk_stm32_gate_enable(priv, osc_data->gate_id);
+}
+
+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 -EINVAL;
+ }
+
+ if (hsidiv != 0U) {
+ return stm32mp1_set_hsidiv(hsidiv);
+ }
+
+ return 0;
+}
+
+static int stm32_clk_oscillators_lse_set_css(struct stm32_clk_priv *priv)
+{
+ struct stm32_clk_platdata *pdata = priv->pdata;
+ struct stm32_osci_dt_cfg *osci = &pdata->osci[OSC_LSE];
+
+ clk_oscillator_set_css(priv, _CK_LSE, osci->css);
+
+ return 0;
+}
+
+static int stm32mp1_come_back_to_hsi(void)
+{
+ int ret;
+ struct stm32_clk_priv *priv = clk_stm32_get_priv();
+
+ /* Come back to HSI */
+ ret = _clk_stm32_set_parent(priv, _CKMPU, _CK_HSI);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = _clk_stm32_set_parent(priv, _CKAXI, _CK_HSI);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = _clk_stm32_set_parent(priv, _CKMLAHB, _CK_HSI);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+static int stm32_clk_configure_clk_get_binding_id(struct stm32_clk_priv *priv, uint32_t data)
+{
+ unsigned long binding_id = ((unsigned long)data & CLK_ID_MASK) >> CLK_ID_SHIFT;
+
+ return clk_get_index(priv, binding_id);
+}
+
+static int stm32_clk_configure_clk(struct stm32_clk_priv *priv, uint32_t data)
+{
+ int sel = (data & CLK_SEL_MASK) >> CLK_SEL_SHIFT;
+ int enable = (data & CLK_ON_MASK) >> CLK_ON_SHIFT;
+ int clk_id;
+ int ret;
+
+ clk_id = stm32_clk_configure_clk_get_binding_id(priv, data);
+ if (clk_id < 0) {
+ return clk_id;
+ }
+
+ ret = _clk_stm32_set_parent_by_index(priv, clk_id, sel);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (enable) {
+ clk_stm32_enable_call_ops(priv, clk_id);
+ } else {
+ clk_stm32_disable_call_ops(priv, clk_id);
+ }
+
+ return 0;
+}
+
+static int stm32_clk_configure_mux(struct stm32_clk_priv *priv, uint32_t data)
+{
+ int mux = (data & MUX_ID_MASK) >> MUX_ID_SHIFT;
+ int sel = (data & MUX_SEL_MASK) >> MUX_SEL_SHIFT;
+
+ return clk_mux_set_parent(priv, mux, sel);
+}
+
+static int stm32_clk_dividers_configure(struct stm32_clk_priv *priv)
+{
+ struct stm32_clk_platdata *pdata = priv->pdata;
+ uint32_t i;
+
+ for (i = 0; i < pdata->nclkdiv; i++) {
+ int div_id, div_n;
+ int val;
+ int ret;
+
+ val = pdata->clkdiv[i] & CMD_DATA_MASK;
+ div_id = (val & DIV_ID_MASK) >> DIV_ID_SHIFT;
+ div_n = (val & DIV_DIVN_MASK) >> DIV_DIVN_SHIFT;
+
+ ret = clk_stm32_set_div(priv, div_id, div_n);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int stm32_clk_source_configure(struct stm32_clk_priv *priv)
+{
+ struct stm32_clk_platdata *pdata = priv->pdata;
+ bool ckper_disabled = false;
+ int clk_id;
+ int ret;
+ uint32_t i;
+
+ for (i = 0; i < pdata->nclksrc; i++) {
+ uint32_t val = pdata->clksrc[i];
+ uint32_t cmd, cmd_data;
+
+ if (val == (uint32_t)CLK_CKPER_DISABLED) {
+ ckper_disabled = true;
+ continue;
+ }
+
+ if (val == (uint32_t)CLK_RTC_DISABLED) {
+ continue;
+ }
+
+ cmd = (val & CMD_MASK) >> CMD_SHIFT;
+ cmd_data = val & ~CMD_MASK;
+
+ switch (cmd) {
+ case CMD_MUX:
+ ret = stm32_clk_configure_mux(priv, cmd_data);
+ break;
+
+ case CMD_CLK:
+ clk_id = stm32_clk_configure_clk_get_binding_id(priv, cmd_data);
+
+ if (clk_id == _RTCCK) {
+ if ((_clk_stm32_is_enabled(priv, _RTCCK) == true)) {
+ continue;
+ }
+ }
+
+ ret = stm32_clk_configure_clk(priv, cmd_data);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ /*
+ * CKPER is source for some peripheral clocks
+ * (FMC-NAND / QPSI-NOR) and switching source is allowed
+ * only if previous clock is still ON
+ * => deactivate CKPER only after switching clock
+ */
+ if (ckper_disabled) {
+ ret = stm32_clk_configure_mux(priv, CLK_CKPER_DISABLED & CMD_MASK);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int stm32_clk_stgen_configure(struct stm32_clk_priv *priv, int id)
+{
+ unsigned long stgen_freq;
+
+ stgen_freq = _clk_stm32_get_rate(priv, id);
+
+ stm32mp_stgen_config(stgen_freq);
+
+ return 0;
+}
+
+#define CLK_PLL_CFG(_idx, _clk_id, _type, _reg)\
+ [(_idx)] = {\
+ .clk_id = (_clk_id),\
+ .plltype = (_type),\
+ .reg_pllxcr = (_reg),\
+ }
+
+static int clk_stm32_pll_compute_cfgr1(struct stm32_clk_priv *priv,
+ const struct stm32_clk_pll *pll,
+ struct stm32_pll_vco *vco,
+ uint32_t *value)
+{
+ uint32_t divm = vco->div_mn[PLL_CFG_M];
+ uint32_t divn = vco->div_mn[PLL_CFG_N];
+ unsigned long prate = 0UL;
+ unsigned long refclk = 0UL;
+
+ prate = _clk_stm32_get_parent_rate(priv, pll->clk_id);
+ refclk = prate / (divm + 1U);
+
+ if ((refclk < (stm32mp1_pll[pll->plltype].refclk_min * 1000000U)) ||
+ (refclk > (stm32mp1_pll[pll->plltype].refclk_max * 1000000U))) {
+ return -EINVAL;
+ }
+
+ *value = 0;
+
+ if ((pll->plltype == PLL_800) && (refclk >= 8000000U)) {
+ *value = 1U << RCC_PLLNCFGR1_IFRGE_SHIFT;
+ }
+
+ *value |= (divn << RCC_PLLNCFGR1_DIVN_SHIFT) & RCC_PLLNCFGR1_DIVN_MASK;
+ *value |= (divm << RCC_PLLNCFGR1_DIVM_SHIFT) & RCC_PLLNCFGR1_DIVM_MASK;
+
+ return 0;
+}
+
+static uint32_t clk_stm32_pll_compute_cfgr2(struct stm32_pll_output *out)
+{
+ uint32_t value = 0;
+
+ value |= (out->output[PLL_CFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & RCC_PLLNCFGR2_DIVP_MASK;
+ value |= (out->output[PLL_CFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) & RCC_PLLNCFGR2_DIVQ_MASK;
+ value |= (out->output[PLL_CFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & RCC_PLLNCFGR2_DIVR_MASK;
+
+ return value;
+}
+
+static void clk_stm32_pll_config_vco(struct stm32_clk_priv *priv,
+ const struct stm32_clk_pll *pll,
+ struct stm32_pll_vco *vco)
+{
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+ uint32_t value = 0;
+
+ if (clk_stm32_pll_compute_cfgr1(priv, pll, vco, &value) != 0) {
+ ERROR("Invalid Vref clock !\n");
+ panic();
+ }
+
+ /* Write N / M / IFREGE fields */
+ mmio_write_32(pll_base + RCC_OFFSET_PLLXCFGR1, value);
+
+ /* Fractional configuration */
+ mmio_write_32(pll_base + RCC_OFFSET_PLLXFRACR, 0);
+
+ /* Frac must be enabled only once its configuration is loaded */
+ mmio_write_32(pll_base + RCC_OFFSET_PLLXFRACR, vco->frac << RCC_PLLNFRACR_FRACV_SHIFT);
+ mmio_setbits_32(pll_base + RCC_OFFSET_PLLXFRACR, RCC_PLLNFRACR_FRACLE);
+}
+
+static void clk_stm32_pll_config_csg(struct stm32_clk_priv *priv,
+ const struct stm32_clk_pll *pll,
+ struct stm32_pll_vco *vco)
+{
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+ uint32_t mod_per = 0;
+ uint32_t inc_step = 0;
+ uint32_t sscg_mode = 0;
+ uint32_t value = 0;
+
+ if (!vco->csg_enabled) {
+ return;
+ }
+
+ mod_per = vco->csg[PLL_CSG_MOD_PER];
+ inc_step = vco->csg[PLL_CSG_INC_STEP];
+ sscg_mode = vco->csg[PLL_CSG_SSCG_MODE];
+
+ value |= (mod_per << RCC_PLLNCSGR_MOD_PER_SHIFT) & RCC_PLLNCSGR_MOD_PER_MASK;
+ value |= (inc_step << RCC_PLLNCSGR_INC_STEP_SHIFT) & RCC_PLLNCSGR_INC_STEP_MASK;
+ value |= (sscg_mode << RCC_PLLNCSGR_SSCG_MODE_SHIFT) & RCC_PLLNCSGR_SSCG_MODE_MASK;
+
+ mmio_write_32(pll_base + RCC_OFFSET_PLLXCSGR, value);
+ mmio_setbits_32(pll_base + RCC_OFFSET_PLLXCR, RCC_PLLNCR_SSCG_CTRL);
+}
+
+static void clk_stm32_pll_config_out(struct stm32_clk_priv *priv, const struct stm32_clk_pll *pll,
+ struct stm32_pll_output *out)
+{
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+ uint32_t value = 0;
+
+ value = clk_stm32_pll_compute_cfgr2(out);
+
+ mmio_write_32(pll_base + RCC_OFFSET_PLLXCFGR2, value);
+}
+
+static inline struct stm32_pll_dt_cfg *clk_stm32_pll_get_pdata(int pll_idx)
+{
+ struct stm32_clk_priv *priv = clk_stm32_get_priv();
+ struct stm32_clk_platdata *pdata = priv->pdata;
+
+ return &pdata->pll[pll_idx];
+}
+
+static bool _clk_stm32_pll_is_enabled(struct stm32_clk_priv *priv, const struct stm32_clk_pll *pll)
+{
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+
+ return ((mmio_read_32(pll_base) & RCC_PLLNCR_PLLON) != 0U);
+}
+
+static void _clk_stm32_pll_set_on(struct stm32_clk_priv *priv, const struct stm32_clk_pll *pll)
+{
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+
+ /* Preserve RCC_PLLNCR_SSCG_CTRL value */
+ mmio_clrsetbits_32(pll_base, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | RCC_PLLNCR_DIVREN,
+ RCC_PLLNCR_PLLON);
+}
+
+static void _clk_stm32_pll_set_off(struct stm32_clk_priv *priv, const struct stm32_clk_pll *pll)
+{
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+
+ /* Stop all output */
+ mmio_clrbits_32(pll_base, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | RCC_PLLNCR_DIVREN);
+
+ /* Stop PLL */
+ mmio_clrbits_32(pll_base, RCC_PLLNCR_PLLON);
+}
+
+static int _clk_stm32_pll_wait_ready_on(struct stm32_clk_priv *priv,
+ const struct stm32_clk_pll *pll)
+{
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+ uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT);
+
+ /* Wait PLL lock */
+ while ((mmio_read_32(pll_base) & RCC_PLLNCR_PLLRDY) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ ERROR("%d clock start failed @ 0x%x: 0x%x\n",
+ pll->clk_id, pll->reg_pllxcr, mmio_read_32(pll_base));
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int _clk_stm32_pll_wait_ready_off(struct stm32_clk_priv *priv,
+ const struct stm32_clk_pll *pll)
+{
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+ uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT);
+
+ /* Wait PLL lock */
+ while ((mmio_read_32(pll_base) & RCC_PLLNCR_PLLRDY) != 0U) {
+ if (timeout_elapsed(timeout)) {
+ ERROR("%d clock stop failed @ 0x%x: 0x%x\n",
+ pll->clk_id, pll->reg_pllxcr, mmio_read_32(pll_base));
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int _clk_stm32_pll_enable(struct stm32_clk_priv *priv, const struct stm32_clk_pll *pll)
+{
+ if (_clk_stm32_pll_is_enabled(priv, pll)) {
+ return 0;
+ }
+
+ /* Preserve RCC_PLLNCR_SSCG_CTRL value */
+ _clk_stm32_pll_set_on(priv, pll);
+
+ /* Wait PLL lock */
+ return _clk_stm32_pll_wait_ready_on(priv, pll);
+}
+
+static void _clk_stm32_pll_disable(struct stm32_clk_priv *priv, const struct stm32_clk_pll *pll)
+{
+ if (!_clk_stm32_pll_is_enabled(priv, pll)) {
+ return;
+ }
+
+ /* Stop all outputs and the PLL */
+ _clk_stm32_pll_set_off(priv, pll);
+
+ /* Wait PLL stopped */
+ _clk_stm32_pll_wait_ready_off(priv, pll);
+}
+
+static int _clk_stm32_pll_init(struct stm32_clk_priv *priv, int pll_idx,
+ struct stm32_pll_dt_cfg *pll_conf)
+{
+ const struct stm32_clk_pll *pll = clk_st32_pll_data(pll_idx);
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+ int ret = 0;
+
+ /* Configure PLLs source */
+ ret = stm32_clk_configure_mux(priv, pll_conf->vco.src);
+ if (ret) {
+ return ret;
+ }
+
+#if STM32MP_USB_PROGRAMMER
+ if ((pll_idx == _PLL4) && pll4_bootrom) {
+ clk_stm32_pll_config_out(priv, pll, &pll_conf->output);
+
+ mmio_setbits_32(pll_base,
+ RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | RCC_PLLNCR_DIVREN);
+
+ return 0;
+ }
+#endif
+ /* Stop the PLL before */
+ _clk_stm32_pll_disable(priv, pll);
+
+ clk_stm32_pll_config_vco(priv, pll, &pll_conf->vco);
+ clk_stm32_pll_config_out(priv, pll, &pll_conf->output);
+ clk_stm32_pll_config_csg(priv, pll, &pll_conf->vco);
+
+ ret = _clk_stm32_pll_enable(priv, pll);
+ if (ret != 0) {
+ return ret;
+ }
+
+ mmio_setbits_32(pll_base, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | RCC_PLLNCR_DIVREN);
+
+ return 0;
+}
+
+static int clk_stm32_pll_init(struct stm32_clk_priv *priv, int pll_idx)
+{
+ struct stm32_pll_dt_cfg *pll_conf = clk_stm32_pll_get_pdata(pll_idx);
+
+ if (pll_conf->vco.status) {
+ return _clk_stm32_pll_init(priv, pll_idx, pll_conf);
+ }
+
+ return 0;
+}
+
+static int stm32_clk_pll_configure(struct stm32_clk_priv *priv)
+{
+ int err = 0;
+
+ err = clk_stm32_pll_init(priv, _PLL1);
+ if (err) {
+ return err;
+ }
+
+ err = clk_stm32_pll_init(priv, _PLL2);
+ if (err) {
+ return err;
+ }
+
+ err = clk_stm32_pll_init(priv, _PLL3);
+ if (err) {
+ return err;
+ }
+
+ err = clk_stm32_pll_init(priv, _PLL4);
+ if (err) {
+ return err;
+ }
+
+ return 0;
+}
+
+static int stm32_clk_oscillators_wait_lse_ready(struct stm32_clk_priv *priv)
+{
+ int ret = 0;
+
+ if (_clk_stm32_get_rate(priv, _CK_LSE) != 0U) {
+ ret = clk_oscillator_wait_ready_on(priv, _CK_LSE);
+ }
+
+ return ret;
+}
+
+static void stm32_clk_oscillators_enable(struct stm32_clk_priv *priv)
+{
+ stm32_enable_oscillator_hse(priv);
+ stm32_enable_oscillator_lse(priv);
+ _clk_stm32_enable(priv, _CK_LSI);
+ _clk_stm32_enable(priv, _CK_CSI);
+}
+
+static int stm32_clk_hsidiv_configure(struct stm32_clk_priv *priv)
+{
+ return stm32mp1_hsidiv(_clk_stm32_get_rate(priv, _CK_HSI));
+}
+
+#if STM32MP_USB_PROGRAMMER
+static bool stm32mp1_clk_is_pll4_used_by_bootrom(struct stm32_clk_priv *priv, int usbphy_p)
+{
+ /* Don't initialize PLL4, when used by BOOTROM */
+ if ((stm32mp_get_boot_itf_selected() ==
+ BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB) &&
+ (usbphy_p == _PLL4R)) {
+ return true;
+ }
+
+ return false;
+}
+
+static int stm32mp1_clk_check_usb_conflict(struct stm32_clk_priv *priv, int usbphy_p, int usbo_p)
+{
+ int _usbo_p;
+ int _usbphy_p;
+
+ if (!pll4_bootrom) {
+ return 0;
+ }
+
+ _usbo_p = _clk_stm32_get_parent(priv, _USBO_K);
+ _usbphy_p = _clk_stm32_get_parent(priv, _USBPHY_K);
+
+ if ((_usbo_p != usbo_p) || (_usbphy_p != usbphy_p)) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ return 0;
+}
+#endif
+
+static struct clk_oscillator_data stm32mp13_osc_data[NB_OSCILLATOR] = {
+ OSCILLATOR(OSC_HSI, _CK_HSI, "clk-hsi", GATE_HSI, GATE_HSI_RDY,
+ NULL, NULL, NULL),
+
+ OSCILLATOR(OSC_LSI, _CK_LSI, "clk-lsi", GATE_LSI, GATE_LSI_RDY,
+ NULL, NULL, NULL),
+
+ OSCILLATOR(OSC_CSI, _CK_CSI, "clk-csi", GATE_CSI, GATE_CSI_RDY,
+ NULL, NULL, NULL),
+
+ OSCILLATOR(OSC_LSE, _CK_LSE, "clk-lse", GATE_LSE, GATE_LSE_RDY,
+ BYPASS(RCC_BDCR, 1, 3),
+ CSS(RCC_BDCR, 8),
+ DRIVE(RCC_BDCR, 4, 2, 2)),
+
+ OSCILLATOR(OSC_HSE, _CK_HSE, "clk-hse", GATE_HSE, GATE_HSE_RDY,
+ BYPASS(RCC_OCENSETR, 10, 7),
+ CSS(RCC_OCENSETR, 11),
+ NULL),
+
+ OSCILLATOR(OSC_I2SCKIN, _I2SCKIN, "i2s_ckin", NO_GATE, NO_GATE,
+ NULL, NULL, NULL),
+};
+
+static const char *clk_stm32_get_oscillator_name(enum stm32_osc id)
+{
+ if (id < NB_OSCILLATOR) {
+ return stm32mp13_osc_data[id].name;
+ }
+
+ return NULL;
+}
+
+#define CLK_PLL_CFG(_idx, _clk_id, _type, _reg)\
+ [(_idx)] = {\
+ .clk_id = (_clk_id),\
+ .plltype = (_type),\
+ .reg_pllxcr = (_reg),\
+ }
+
+static const struct stm32_clk_pll stm32_mp13_clk_pll[_PLL_NB] = {
+ CLK_PLL_CFG(_PLL1, _CK_PLL1, PLL_2000, RCC_PLL1CR),
+ CLK_PLL_CFG(_PLL2, _CK_PLL2, PLL_1600, RCC_PLL2CR),
+ CLK_PLL_CFG(_PLL3, _CK_PLL3, PLL_800, RCC_PLL3CR),
+ CLK_PLL_CFG(_PLL4, _CK_PLL4, PLL_800, RCC_PLL4CR),
+};
+
+static const struct stm32_clk_pll *clk_st32_pll_data(unsigned int idx)
+{
+ return &stm32_mp13_clk_pll[idx];
+}
+
+struct stm32_pll_cfg {
+ int pll_id;
+};
+
+static unsigned long clk_stm32_pll_recalc_rate(struct stm32_clk_priv *priv, int id,
+ unsigned long prate)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct stm32_pll_cfg *pll_cfg = clk->clock_cfg;
+ const struct stm32_clk_pll *pll = clk_st32_pll_data(pll_cfg->pll_id);
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+ uint32_t cfgr1, fracr, divm, divn;
+ unsigned long fvco;
+
+ cfgr1 = mmio_read_32(pll_base + RCC_OFFSET_PLLXCFGR1);
+ fracr = mmio_read_32(pll_base + RCC_OFFSET_PLLXFRACR);
+
+ divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT;
+ divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK;
+
+ /*
+ * 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 = prate * numerator;
+ denominator = ((unsigned long long)divm + 1U) << 13;
+ fvco = (unsigned long)(numerator / denominator);
+ } else {
+ fvco = (unsigned long)(prate * (divn + 1U) / (divm + 1U));
+ }
+
+ return fvco;
+};
+
+static bool clk_stm32_pll_is_enabled(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct stm32_pll_cfg *pll_cfg = clk->clock_cfg;
+ const struct stm32_clk_pll *pll = clk_st32_pll_data(pll_cfg->pll_id);
+
+ return _clk_stm32_pll_is_enabled(priv, pll);
+}
+
+static int clk_stm32_pll_enable(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct stm32_pll_cfg *pll_cfg = clk->clock_cfg;
+ const struct stm32_clk_pll *pll = clk_st32_pll_data(pll_cfg->pll_id);
+
+ return _clk_stm32_pll_enable(priv, pll);
+}
+
+static void clk_stm32_pll_disable(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct stm32_pll_cfg *pll_cfg = clk->clock_cfg;
+ const struct stm32_clk_pll *pll = clk_st32_pll_data(pll_cfg->pll_id);
+
+ _clk_stm32_pll_disable(priv, pll);
+}
+
+static const struct stm32_clk_ops clk_stm32_pll_ops = {
+ .recalc_rate = clk_stm32_pll_recalc_rate,
+ .enable = clk_stm32_pll_enable,
+ .disable = clk_stm32_pll_disable,
+ .is_enabled = clk_stm32_pll_is_enabled,
+};
+
+#define CLK_PLL(idx, _idx, _parent, _gate, _pll_id, _flags)[idx] = {\
+ .binding = _idx,\
+ .parent = _parent,\
+ .flags = (_flags),\
+ .clock_cfg = &(struct stm32_pll_cfg) {\
+ .pll_id = _pll_id,\
+ },\
+ .ops = &clk_stm32_pll_ops,\
+}
+
+struct clk_stm32_composite_cfg {
+ int gate_id;
+ int div_id;
+};
+
+static unsigned long clk_stm32_composite_recalc_rate(struct stm32_clk_priv *priv,
+ int idx, unsigned long prate)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, idx);
+ struct clk_stm32_composite_cfg *composite_cfg = clk->clock_cfg;
+
+ return _clk_stm32_divider_recalc(priv, composite_cfg->div_id, prate);
+};
+
+static bool clk_stm32_composite_gate_is_enabled(struct stm32_clk_priv *priv, int idx)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, idx);
+ struct clk_stm32_composite_cfg *composite_cfg = clk->clock_cfg;
+
+ return _clk_stm32_gate_is_enabled(priv, composite_cfg->gate_id);
+}
+
+static int clk_stm32_composite_gate_enable(struct stm32_clk_priv *priv, int idx)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, idx);
+ struct clk_stm32_composite_cfg *composite_cfg = clk->clock_cfg;
+
+ return _clk_stm32_gate_enable(priv, composite_cfg->gate_id);
+}
+
+static void clk_stm32_composite_gate_disable(struct stm32_clk_priv *priv, int idx)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, idx);
+ struct clk_stm32_composite_cfg *composite_cfg = clk->clock_cfg;
+
+ _clk_stm32_gate_disable(priv, composite_cfg->gate_id);
+}
+
+static const struct stm32_clk_ops clk_stm32_composite_ops = {
+ .recalc_rate = clk_stm32_composite_recalc_rate,
+ .is_enabled = clk_stm32_composite_gate_is_enabled,
+ .enable = clk_stm32_composite_gate_enable,
+ .disable = clk_stm32_composite_gate_disable,
+};
+
+#define STM32_COMPOSITE(idx, _binding, _parent, _flags, _gate_id,\
+ _div_id)[idx] = {\
+ .binding = (_binding),\
+ .parent = (_parent),\
+ .flags = (_flags),\
+ .clock_cfg = &(struct clk_stm32_composite_cfg) {\
+ .gate_id = (_gate_id),\
+ .div_id = (_div_id),\
+ },\
+ .ops = &clk_stm32_composite_ops,\
+}
+
+static const struct clk_stm32 stm32mp13_clk[CK_LAST] = {
+ /* ROOT CLOCKS */
+ CLK_FIXED_RATE(_CK_OFF, _NO_ID, 0),
+ CLK_OSC(_CK_HSE, CK_HSE, CLK_IS_ROOT, OSC_HSE),
+ CLK_OSC(_CK_HSI, CK_HSI, CLK_IS_ROOT, OSC_HSI),
+ CLK_OSC(_CK_CSI, CK_CSI, CLK_IS_ROOT, OSC_CSI),
+ CLK_OSC(_CK_LSI, CK_LSI, CLK_IS_ROOT, OSC_LSI),
+ CLK_OSC(_CK_LSE, CK_LSE, CLK_IS_ROOT, OSC_LSE),
+
+ CLK_OSC_FIXED(_I2SCKIN, _NO_ID, CLK_IS_ROOT, OSC_I2SCKIN),
+
+ CLK_FIXED_RATE(_USB_PHY_48, _NO_ID, USB_PHY_48_MHZ),
+
+ STM32_DIV(_HSE_DIV, _NO_ID, _CK_HSE, 0, DIV_RTC),
+
+ FIXED_FACTOR(_HSE_DIV2, CK_HSE_DIV2, _CK_HSE, 1, 2),
+ FIXED_FACTOR(_CSI_DIV122, _NO_ID, _CK_CSI, 1, 122),
+
+ CLK_PLL(_CK_PLL1, PLL1, MUX(MUX_PLL12), GATE_PLL1, _PLL1, 0),
+ CLK_PLL(_CK_PLL2, PLL2, MUX(MUX_PLL12), GATE_PLL2, _PLL2, 0),
+ CLK_PLL(_CK_PLL3, PLL3, MUX(MUX_PLL3), GATE_PLL3, _PLL3, 0),
+ CLK_PLL(_CK_PLL4, PLL4, MUX(MUX_PLL4), GATE_PLL4, _PLL4, 0),
+
+ STM32_COMPOSITE(_PLL1P, PLL1_P, _CK_PLL1, CLK_IS_CRITICAL, GATE_PLL1_DIVP, DIV_PLL1DIVP),
+ STM32_DIV(_PLL1P_DIV, _NO_ID, _CK_PLL1, 0, DIV_MPU),
+
+ STM32_COMPOSITE(_PLL2P, PLL2_P, _CK_PLL2, CLK_IS_CRITICAL, GATE_PLL2_DIVP, DIV_PLL2DIVP),
+ STM32_COMPOSITE(_PLL2Q, PLL2_Q, _CK_PLL2, 0, GATE_PLL2_DIVQ, DIV_PLL2DIVQ),
+ STM32_COMPOSITE(_PLL2R, PLL2_R, _CK_PLL2, CLK_IS_CRITICAL, GATE_PLL2_DIVR, DIV_PLL2DIVR),
+
+ STM32_COMPOSITE(_PLL3P, PLL3_P, _CK_PLL3, 0, GATE_PLL3_DIVP, DIV_PLL3DIVP),
+ STM32_COMPOSITE(_PLL3Q, PLL3_Q, _CK_PLL3, 0, GATE_PLL3_DIVQ, DIV_PLL3DIVQ),
+ STM32_COMPOSITE(_PLL3R, PLL3_R, _CK_PLL3, 0, GATE_PLL3_DIVR, DIV_PLL3DIVR),
+
+ STM32_COMPOSITE(_PLL4P, PLL4_P, _CK_PLL4, 0, GATE_PLL4_DIVP, DIV_PLL4DIVP),
+ STM32_COMPOSITE(_PLL4Q, PLL4_Q, _CK_PLL4, 0, GATE_PLL4_DIVQ, DIV_PLL4DIVQ),
+ STM32_COMPOSITE(_PLL4R, PLL4_R, _CK_PLL4, 0, GATE_PLL4_DIVR, DIV_PLL4DIVR),
+
+ STM32_MUX(_CKMPU, CK_MPU, MUX_MPU, 0),
+ STM32_DIV(_CKAXI, CK_AXI, MUX(MUX_AXI), 0, DIV_AXI),
+ STM32_DIV(_CKMLAHB, CK_MLAHB, MUX(MUX_MLAHB), CLK_IS_CRITICAL, DIV_MLAHB),
+ STM32_MUX(_CKPER, CK_PER, MUX(MUX_CKPER), 0),
+
+ STM32_DIV(_PCLK1, PCLK1, _CKMLAHB, 0, DIV_APB1),
+ STM32_DIV(_PCLK2, PCLK2, _CKMLAHB, 0, DIV_APB2),
+ STM32_DIV(_PCLK3, PCLK3, _CKMLAHB, 0, DIV_APB3),
+ STM32_DIV(_PCLK4, PCLK4, _CKAXI, 0, DIV_APB4),
+ STM32_DIV(_PCLK5, PCLK5, _CKAXI, 0, DIV_APB5),
+ STM32_DIV(_PCLK6, PCLK6, _CKMLAHB, 0, DIV_APB6),
+
+ CK_TIMER(_CKTIMG1, CK_TIMG1, _PCLK1, 0, RCC_APB1DIVR, RCC_TIMG1PRER),
+ CK_TIMER(_CKTIMG2, CK_TIMG2, _PCLK2, 0, RCC_APB2DIVR, RCC_TIMG2PRER),
+ CK_TIMER(_CKTIMG3, CK_TIMG3, _PCLK6, 0, RCC_APB6DIVR, RCC_TIMG3PRER),
+
+ /* END ROOT CLOCKS */
+
+ STM32_GATE(_DDRC1, DDRC1, _CKAXI, CLK_IS_CRITICAL, GATE_DDRC1),
+ STM32_GATE(_DDRC1LP, DDRC1LP, _CKAXI, CLK_IS_CRITICAL, GATE_DDRC1LP),
+ STM32_GATE(_DDRPHYC, DDRPHYC, _PLL2R, CLK_IS_CRITICAL, GATE_DDRPHYC),
+ STM32_GATE(_DDRPHYCLP, DDRPHYCLP, _PLL2R, CLK_IS_CRITICAL, GATE_DDRPHYCLP),
+ STM32_GATE(_DDRCAPB, DDRCAPB, _PCLK4, CLK_IS_CRITICAL, GATE_DDRCAPB),
+ STM32_GATE(_DDRCAPBLP, DDRCAPBLP, _PCLK4, CLK_IS_CRITICAL, GATE_DDRCAPBLP),
+ STM32_GATE(_AXIDCG, AXIDCG, _CKAXI, CLK_IS_CRITICAL, GATE_AXIDCG),
+ STM32_GATE(_DDRPHYCAPB, DDRPHYCAPB, _PCLK4, CLK_IS_CRITICAL, GATE_DDRPHYCAPB),
+ STM32_GATE(_DDRPHYCAPBLP, DDRPHYCAPBLP, _PCLK4, CLK_IS_CRITICAL, GATE_DDRPHYCAPBLP),
+
+ STM32_GATE(_SYSCFG, SYSCFG, _PCLK3, 0, GATE_SYSCFG),
+ STM32_GATE(_DDRPERFM, DDRPERFM, _PCLK4, 0, GATE_DDRPERFM),
+ STM32_GATE(_IWDG2APB, IWDG2, _PCLK4, 0, GATE_IWDG2APB),
+ STM32_GATE(_USBPHY_K, USBPHY_K, MUX(MUX_USBPHY), 0, GATE_USBPHY),
+ STM32_GATE(_USBO_K, USBO_K, MUX(MUX_USBO), 0, GATE_USBO),
+
+ STM32_GATE(_RTCAPB, RTCAPB, _PCLK5, CLK_IS_CRITICAL, GATE_RTCAPB),
+ STM32_GATE(_TZC, TZC, _PCLK5, CLK_IS_CRITICAL, GATE_TZC),
+ STM32_GATE(_ETZPC, TZPC, _PCLK5, CLK_IS_CRITICAL, GATE_ETZPC),
+ STM32_GATE(_IWDG1APB, IWDG1, _PCLK5, 0, GATE_IWDG1APB),
+ STM32_GATE(_BSEC, BSEC, _PCLK5, CLK_IS_CRITICAL, GATE_BSEC),
+ STM32_GATE(_STGENC, STGEN_K, MUX(MUX_STGEN), CLK_IS_CRITICAL, GATE_STGENC),
+
+ STM32_GATE(_USART1_K, USART1_K, MUX(MUX_UART1), 0, GATE_USART1),
+ STM32_GATE(_USART2_K, USART2_K, MUX(MUX_UART2), 0, GATE_USART2),
+ STM32_GATE(_I2C3_K, I2C3_K, MUX(MUX_I2C3), 0, GATE_I2C3),
+ STM32_GATE(_I2C4_K, I2C4_K, MUX(MUX_I2C4), 0, GATE_I2C4),
+ STM32_GATE(_I2C5_K, I2C5_K, MUX(MUX_I2C5), 0, GATE_I2C5),
+ STM32_GATE(_TIM12, TIM12_K, _CKTIMG3, 0, GATE_TIM12),
+ STM32_GATE(_TIM15, TIM15_K, _CKTIMG3, 0, GATE_TIM15),
+
+ STM32_GATE(_RTCCK, RTC, MUX(MUX_RTC), 0, GATE_RTCCK),
+
+ STM32_GATE(_GPIOA, GPIOA, _CKMLAHB, 0, GATE_GPIOA),
+ STM32_GATE(_GPIOB, GPIOB, _CKMLAHB, 0, GATE_GPIOB),
+ STM32_GATE(_GPIOC, GPIOC, _CKMLAHB, 0, GATE_GPIOC),
+ STM32_GATE(_GPIOD, GPIOD, _CKMLAHB, 0, GATE_GPIOD),
+ STM32_GATE(_GPIOE, GPIOE, _CKMLAHB, 0, GATE_GPIOE),
+ STM32_GATE(_GPIOF, GPIOF, _CKMLAHB, 0, GATE_GPIOF),
+ STM32_GATE(_GPIOG, GPIOG, _CKMLAHB, 0, GATE_GPIOG),
+ STM32_GATE(_GPIOH, GPIOH, _CKMLAHB, 0, GATE_GPIOH),
+ STM32_GATE(_GPIOI, GPIOI, _CKMLAHB, 0, GATE_GPIOI),
+
+ STM32_GATE(_PKA, PKA, _CKAXI, 0, GATE_PKA),
+ STM32_GATE(_SAES_K, SAES_K, MUX(MUX_SAES), 0, GATE_SAES),
+ STM32_GATE(_CRYP1, CRYP1, _PCLK5, 0, GATE_CRYP1),
+ STM32_GATE(_HASH1, HASH1, _PCLK5, 0, GATE_HASH1),
+
+ STM32_GATE(_RNG1_K, RNG1_K, MUX(MUX_RNG1), 0, GATE_RNG1),
+ STM32_GATE(_BKPSRAM, BKPSRAM, _PCLK5, CLK_IS_CRITICAL, GATE_BKPSRAM),
+
+ STM32_GATE(_SDMMC1_K, SDMMC1_K, MUX(MUX_SDMMC1), 0, GATE_SDMMC1),
+ STM32_GATE(_SDMMC2_K, SDMMC2_K, MUX(MUX_SDMMC2), 0, GATE_SDMMC2),
+ STM32_GATE(_DBGCK, CK_DBG, _CKAXI, 0, GATE_DBGCK),
+
+/* TODO: CHECK CLOCK FOR BL2/BL32 AND IF ONLY FOR TEST OR NOT */
+ STM32_GATE(_USART3_K, USART3_K, MUX(MUX_UART35), 0, GATE_USART3),
+ STM32_GATE(_UART4_K, UART4_K, MUX(MUX_UART4), 0, GATE_UART4),
+ STM32_GATE(_UART5_K, UART5_K, MUX(MUX_UART35), 0, GATE_UART5),
+ STM32_GATE(_UART7_K, UART7_K, MUX(MUX_UART78), 0, GATE_UART7),
+ STM32_GATE(_UART8_K, UART8_K, MUX(MUX_UART78), 0, GATE_UART8),
+ STM32_GATE(_USART6_K, USART6_K, MUX(MUX_UART6), 0, GATE_USART6),
+ STM32_GATE(_MCE, MCE, _CKAXI, CLK_IS_CRITICAL, GATE_MCE),
+ STM32_GATE(_FMC_K, FMC_K, MUX(MUX_FMC), 0, GATE_FMC),
+ STM32_GATE(_QSPI_K, QSPI_K, MUX(MUX_QSPI), 0, GATE_QSPI),
+
+ STM32_COMPOSITE(_MCO1_K, CK_MCO1, MUX(MUX_MCO1), 0, GATE_MCO1, DIV_MCO1),
+ STM32_COMPOSITE(_MCO2_K, CK_MCO2, MUX(MUX_MCO2), 0, GATE_MCO2, DIV_MCO2),
+ STM32_COMPOSITE(_TRACECK, CK_TRACE, _CKAXI, 0, GATE_TRACECK, DIV_TRACE),
+
+#if defined(IMAGE_BL32)
+ STM32_GATE(_TIM2, TIM2_K, _CKTIMG1, 0, GATE_TIM2),
+ STM32_GATE(_TIM3, TIM3_K, _CKTIMG1, 0, GATE_TIM3),
+ STM32_GATE(_TIM4, TIM4_K, _CKTIMG1, 0, GATE_TIM4),
+ STM32_GATE(_TIM5, TIM5_K, _CKTIMG1, 0, GATE_TIM5),
+ STM32_GATE(_TIM6, TIM6_K, _CKTIMG1, 0, GATE_TIM6),
+ STM32_GATE(_TIM7, TIM7_K, _CKTIMG1, 0, GATE_TIM7),
+ STM32_GATE(_TIM13, TIM13_K, _CKTIMG3, 0, GATE_TIM13),
+ STM32_GATE(_TIM14, TIM14_K, _CKTIMG3, 0, GATE_TIM14),
+ STM32_GATE(_LPTIM1_K, LPTIM1_K, MUX(MUX_LPTIM1), 0, GATE_LPTIM1),
+ STM32_GATE(_SPI2_K, SPI2_K, MUX(MUX_SPI23), 0, GATE_SPI2),
+ STM32_GATE(_SPI3_K, SPI3_K, MUX(MUX_SPI23), 0, GATE_SPI3),
+ STM32_GATE(_SPDIF_K, SPDIF_K, MUX(MUX_SPDIF), 0, GATE_SPDIF),
+ STM32_GATE(_TIM1, TIM1_K, _CKTIMG2, 0, GATE_TIM1),
+ STM32_GATE(_TIM8, TIM8_K, _CKTIMG2, 0, GATE_TIM8),
+ STM32_GATE(_TIM16, TIM16_K, _CKTIMG3, 0, GATE_TIM16),
+ STM32_GATE(_TIM17, TIM17_K, _CKTIMG3, 0, GATE_TIM17),
+ STM32_GATE(_SPI1_K, SPI1_K, MUX(MUX_SPI1), 0, GATE_SPI1),
+ STM32_GATE(_SPI4_K, SPI4_K, MUX(MUX_SPI4), 0, GATE_SPI4),
+ STM32_GATE(_SPI5_K, SPI5_K, MUX(MUX_SPI5), 0, GATE_SPI5),
+ STM32_GATE(_SAI1_K, SAI1_K, MUX(MUX_SAI1), 0, GATE_SAI1),
+ STM32_GATE(_SAI2_K, SAI2_K, MUX(MUX_SAI2), 0, GATE_SAI2),
+ STM32_GATE(_DFSDM, DFSDM_K, MUX(MUX_SAI1), 0, GATE_DFSDM),
+ STM32_GATE(_FDCAN_K, FDCAN_K, MUX(MUX_FDCAN), 0, GATE_FDCAN),
+ STM32_GATE(_USBH, USBH, _CKAXI, 0, GATE_USBH),
+ STM32_GATE(_I2C1_K, I2C1_K, MUX(MUX_I2C12), 0, GATE_I2C1),
+ STM32_GATE(_I2C2_K, I2C2_K, MUX(MUX_I2C12), 0, GATE_I2C2),
+ STM32_GATE(_ADFSDM, ADFSDM_K, MUX(MUX_SAI1), 0, GATE_ADFSDM),
+ STM32_GATE(_LPTIM2_K, LPTIM2_K, MUX(MUX_LPTIM2), 0, GATE_LPTIM2),
+ STM32_GATE(_LPTIM3_K, LPTIM3_K, MUX(MUX_LPTIM3), 0, GATE_LPTIM3),
+ STM32_GATE(_LPTIM4_K, LPTIM4_K, MUX(MUX_LPTIM45), 0, GATE_LPTIM4),
+ STM32_GATE(_LPTIM5_K, LPTIM5_K, MUX(MUX_LPTIM45), 0, GATE_LPTIM5),
+ STM32_GATE(_VREF, VREF, _PCLK3, 0, GATE_VREF),
+ STM32_GATE(_DTS, TMPSENS, _PCLK3, 0, GATE_DTS),
+ STM32_GATE(_PMBCTRL, PMBCTRL, _PCLK3, 0, GATE_HDP),
+ STM32_GATE(_HDP, HDP, _PCLK3, 0, GATE_PMBCTRL),
+ STM32_GATE(_STGENRO, STGENRO, _PCLK4, 0, GATE_DCMIPP),
+ STM32_GATE(_DCMIPP_K, DCMIPP_K, MUX(MUX_DCMIPP), 0, GATE_DCMIPP),
+ STM32_GATE(_DMAMUX1, DMAMUX1, _CKAXI, 0, GATE_DMAMUX1),
+ STM32_GATE(_DMAMUX2, DMAMUX2, _CKAXI, 0, GATE_DMAMUX2),
+ STM32_GATE(_DMA3, DMA3, _CKAXI, 0, GATE_DMAMUX2),
+ STM32_GATE(_ADC1_K, ADC1_K, MUX(MUX_ADC1), 0, GATE_ADC1),
+ STM32_GATE(_ADC2_K, ADC2_K, MUX(MUX_ADC2), 0, GATE_ADC2),
+ STM32_GATE(_TSC, TSC, _CKAXI, 0, GATE_TSC),
+ STM32_GATE(_AXIMC, AXIMC, _CKAXI, 0, GATE_AXIMC),
+ STM32_GATE(_CRC1, CRC1, _CKAXI, 0, GATE_ETH1TX),
+ STM32_GATE(_ETH1CK, ETH1CK_K, MUX(MUX_ETH1), 0, GATE_ETH1CK),
+ STM32_GATE(_ETH1TX, ETH1TX, _CKAXI, 0, GATE_ETH1TX),
+ STM32_GATE(_ETH1RX, ETH1RX, _CKAXI, 0, GATE_ETH1RX),
+ STM32_GATE(_ETH2CK, ETH2CK_K, MUX(MUX_ETH2), 0, GATE_ETH2CK),
+ STM32_GATE(_ETH2TX, ETH2TX, _CKAXI, 0, GATE_ETH2TX),
+ STM32_GATE(_ETH2RX, ETH2RX, _CKAXI, 0, GATE_ETH2RX),
+ STM32_GATE(_ETH2MAC, ETH2MAC, _CKAXI, 0, GATE_ETH2MAC),
+#endif
+};
+
+static struct stm32_pll_dt_cfg mp13_pll[_PLL_NB];
+
+static struct stm32_osci_dt_cfg mp13_osci[NB_OSCILLATOR];
+
+static uint32_t mp13_clksrc[MUX_MAX];
+
+static uint32_t mp13_clkdiv[DIV_MAX];
+
+static struct stm32_clk_platdata stm32mp13_clock_pdata = {
+ .osci = mp13_osci,
+ .nosci = NB_OSCILLATOR,
+ .pll = mp13_pll,
+ .npll = _PLL_NB,
+ .clksrc = mp13_clksrc,
+ .nclksrc = MUX_MAX,
+ .clkdiv = mp13_clkdiv,
+ .nclkdiv = DIV_MAX,
+};
+
+static struct stm32_clk_priv stm32mp13_clock_data = {
+ .base = RCC_BASE,
+ .num = ARRAY_SIZE(stm32mp13_clk),
+ .clks = stm32mp13_clk,
+ .parents = parent_mp13,
+ .nb_parents = ARRAY_SIZE(parent_mp13),
+ .gates = gates_mp13,
+ .nb_gates = ARRAY_SIZE(gates_mp13),
+ .div = dividers_mp13,
+ .nb_div = ARRAY_SIZE(dividers_mp13),
+ .osci_data = stm32mp13_osc_data,
+ .nb_osci_data = ARRAY_SIZE(stm32mp13_osc_data),
+ .gate_refcounts = refcounts_mp13,
+ .pdata = &stm32mp13_clock_pdata,
+};
+
+static int stm32mp1_init_clock_tree(void)
+{
+ struct stm32_clk_priv *priv = clk_stm32_get_priv();
+ int ret;
+
+#if STM32MP_USB_PROGRAMMER
+ int usbphy_p = _clk_stm32_get_parent(priv, _USBPHY_K);
+ int usbo_p = _clk_stm32_get_parent(priv, _USBO_K);
+
+ /* Don't initialize PLL4, when used by BOOTROM */
+ pll4_bootrom = stm32mp1_clk_is_pll4_used_by_bootrom(priv, usbphy_p);
+#endif
+
+ /*
+ * Switch ON oscillators found in device-tree.
+ * Note: HSI already ON after BootROM stage.
+ */
+ stm32_clk_oscillators_enable(priv);
+
+ /* Come back to HSI */
+ ret = stm32mp1_come_back_to_hsi();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = stm32_clk_hsidiv_configure(priv);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = stm32_clk_stgen_configure(priv, _STGENC);
+ if (ret != 0) {
+ panic();
+ }
+
+ ret = stm32_clk_dividers_configure(priv);
+ if (ret != 0) {
+ panic();
+ }
+
+ ret = stm32_clk_pll_configure(priv);
+ if (ret != 0) {
+ panic();
+ }
+
+ /* Wait LSE ready before to use it */
+ ret = stm32_clk_oscillators_wait_lse_ready(priv);
+ if (ret != 0) {
+ panic();
+ }
+
+ /* Configure with expected clock source */
+ ret = stm32_clk_source_configure(priv);
+ if (ret != 0) {
+ panic();
+ }
+
+ /* Configure LSE css after RTC source configuration */
+ ret = stm32_clk_oscillators_lse_set_css(priv);
+ if (ret != 0) {
+ panic();
+ }
+
+#if STM32MP_USB_PROGRAMMER
+ ret = stm32mp1_clk_check_usb_conflict(priv, usbphy_p, usbo_p);
+ if (ret != 0) {
+ return ret;
+ }
+#endif
+ /* reconfigure STGEN with DT config */
+ ret = stm32_clk_stgen_configure(priv, _STGENC);
+ if (ret != 0) {
+ panic();
+ }
+
+ /* Software Self-Refresh mode (SSR) during DDR initilialization */
+ mmio_clrsetbits_32(priv->base + RCC_DDRITFCR,
+ RCC_DDRITFCR_DDRCKMOD_MASK,
+ RCC_DDRITFCR_DDRCKMOD_SSR <<
+ RCC_DDRITFCR_DDRCKMOD_SHIFT);
+
+ return 0;
+}
+
+#define LSEDRV_MEDIUM_HIGH 2
+
+static int clk_stm32_parse_oscillator_fdt(void *fdt, int node, const char *name,
+ struct stm32_osci_dt_cfg *osci)
+{
+ int subnode = 0;
+
+ /* default value oscillator not found, freq=0 */
+ osci->freq = 0;
+
+ fdt_for_each_subnode(subnode, fdt, node) {
+ const char *cchar = NULL;
+ const fdt32_t *cuint = NULL;
+ int ret = 0;
+
+ cchar = fdt_get_name(fdt, subnode, &ret);
+ if (cchar == NULL) {
+ return ret;
+ }
+
+ if (strncmp(cchar, name, (size_t)ret) ||
+ fdt_get_status(subnode) == DT_DISABLED) {
+ continue;
+ }
+
+ cuint = fdt_getprop(fdt, subnode, "clock-frequency", &ret);
+ if (cuint == NULL) {
+ return ret;
+ }
+
+ osci->freq = fdt32_to_cpu(*cuint);
+
+ if (fdt_getprop(fdt, subnode, "st,bypass", NULL) != NULL) {
+ osci->bypass = true;
+ }
+
+ if (fdt_getprop(fdt, subnode, "st,digbypass", NULL) != NULL) {
+ osci->digbyp = true;
+ }
+
+ if (fdt_getprop(fdt, subnode, "st,css", NULL) != NULL) {
+ osci->css = true;
+ }
+
+ osci->drive = fdt_read_uint32_default(fdt, subnode, "st,drive", LSEDRV_MEDIUM_HIGH);
+
+ return 0;
+ }
+
+ return 0;
+}
+
+static int stm32_clk_parse_fdt_all_oscillator(void *fdt, struct stm32_clk_platdata *pdata)
+{
+ int fdt_err = 0;
+ uint32_t i = 0;
+ int node = 0;
+
+ node = fdt_path_offset(fdt, "/clocks");
+ if (node < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ for (i = 0; i < pdata->nosci; i++) {
+ const char *name = NULL;
+
+ name = clk_stm32_get_oscillator_name((enum stm32_osc)i);
+ if (name == NULL) {
+ continue;
+ }
+
+ fdt_err = clk_stm32_parse_oscillator_fdt(fdt, node, name, &pdata->osci[i]);
+ if (fdt_err < 0) {
+ panic();
+ }
+ }
+
+ return 0;
+}
+
+#define RCC_PLL_NAME_SIZE 12
+
+static int clk_stm32_load_vco_config(void *fdt, int subnode, struct stm32_pll_vco *vco)
+{
+ int err = 0;
+
+ err = fdt_read_uint32_array(fdt, subnode, "divmn", (int)PLL_DIV_MN_NB, vco->div_mn);
+ if (err != 0) {
+ return err;
+ }
+
+ err = fdt_read_uint32_array(fdt, subnode, "csg", (int)PLL_CSG_NB, vco->csg);
+
+ vco->csg_enabled = (err == 0);
+
+ if (err == -FDT_ERR_NOTFOUND) {
+ err = 0;
+ }
+
+ if (err != 0) {
+ return err;
+ }
+
+ vco->status = RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | RCC_PLLNCR_DIVREN | RCC_PLLNCR_PLLON;
+
+ vco->frac = fdt_read_uint32_default(fdt, subnode, "frac", 0);
+
+ vco->src = fdt_read_uint32_default(fdt, subnode, "src", UINT32_MAX);
+
+ return 0;
+}
+
+static int clk_stm32_load_output_config(void *fdt, int subnode, struct stm32_pll_output *output)
+{
+ int err = 0;
+
+ err = fdt_read_uint32_array(fdt, subnode, "st,pll_div_pqr", (int)PLL_DIV_PQR_NB,
+ output->output);
+ if (err != 0) {
+ return err;
+ }
+
+ return 0;
+}
+
+static int clk_stm32_parse_pll_fdt(void *fdt, int subnode, struct stm32_pll_dt_cfg *pll)
+{
+ const fdt32_t *cuint = NULL;
+ int subnode_pll = 0;
+ int subnode_vco = 0;
+ int err = 0;
+
+ cuint = fdt_getprop(fdt, subnode, "st,pll", NULL);
+ if (!cuint) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ subnode_pll = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
+ if (subnode_pll < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ cuint = fdt_getprop(fdt, subnode_pll, "st,pll_vco", NULL);
+ if (!cuint) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ subnode_vco = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
+ if (subnode_vco < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ err = clk_stm32_load_vco_config(fdt, subnode_vco, &pll->vco);
+ if (err != 0) {
+ return err;
+ }
+
+ err = clk_stm32_load_output_config(fdt, subnode_pll, &pll->output);
+ if (err != 0) {
+ return err;
+ }
+
+ return 0;
+}
+
+static int stm32_clk_parse_fdt_all_pll(void *fdt, int node, struct stm32_clk_platdata *pdata)
+{
+ size_t i = 0U;
+
+ for (i = _PLL1; i < pdata->npll; i++) {
+ struct stm32_pll_dt_cfg *pll = pdata->pll + i;
+ char name[RCC_PLL_NAME_SIZE];
+ int subnode = 0;
+ int err = 0;
+
+ snprintf(name, sizeof(name), "st,pll@%u", i);
+
+ subnode = fdt_subnode_offset(fdt, node, name);
+ if (!fdt_check_node(subnode)) {
+ continue;
+ }
+
+ err = clk_stm32_parse_pll_fdt(fdt, subnode, pll);
+ if (err != 0) {
+ panic();
+ }
+ }
+
+ return 0;
+}
+
+static int stm32_clk_parse_fdt(struct stm32_clk_platdata *pdata)
+{
+ void *fdt = NULL;
+ int node;
+ uint32_t err;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -ENOENT;
+ }
+
+ node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
+ if (node < 0) {
+ panic();
+ }
+
+ err = stm32_clk_parse_fdt_all_oscillator(fdt, pdata);
+ if (err != 0) {
+ return err;
+ }
+
+ err = stm32_clk_parse_fdt_all_pll(fdt, node, pdata);
+ if (err != 0) {
+ return err;
+ }
+
+ err = stm32_clk_parse_fdt_by_name(fdt, node, "st,clkdiv", pdata->clkdiv, &pdata->nclkdiv);
+ if (err != 0) {
+ return err;
+ }
+
+ err = stm32_clk_parse_fdt_by_name(fdt, node, "st,clksrc", pdata->clksrc, &pdata->nclksrc);
+ if (err != 0) {
+ return err;
+ }
+
+ return 0;
+}
+
+int stm32mp1_clk_init(void)
+{
+ return 0;
+}
+
+int stm32mp1_clk_probe(void)
+{
+ uintptr_t base = RCC_BASE;
+ int ret;
+
+ ret = stm32_clk_parse_fdt(&stm32mp13_clock_pdata);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = clk_stm32_init(&stm32mp13_clock_data, base);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = stm32mp1_init_clock_tree();
+ if (ret != 0) {
+ return ret;
+ }
+
+ clk_stm32_enable_critical_clocks();
+
+ return 0;
+}
diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c
new file mode 100644
index 0000000..aa5db6f
--- /dev/null
+++ b/drivers/st/clk/stm32mp1_clk.c
@@ -0,0 +1,2373 @@
+/*
+ * Copyright (C) 2018-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <drivers/st/stm32mp1_clk.h>
+#include <drivers/st/stm32mp1_rcc.h>
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <lib/utils_def.h>
+#include <libfdt.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+#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,
+ _HSE_RTC,
+ _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,
+ _MPU_SEL,
+ _CKPER_SEL,
+ _RTC_SEL,
+ _PARENT_SEL_NB,
+ _UNKNOWN_SEL = 0xff,
+};
+
+/* State the parent clock ID straight related to a clock */
+static const uint8_t parent_id_clock_id[_PARENT_NB] = {
+ [_HSE] = CK_HSE,
+ [_HSI] = CK_HSI,
+ [_CSI] = CK_CSI,
+ [_LSE] = CK_LSE,
+ [_LSI] = CK_LSI,
+ [_I2S_CKIN] = _UNKNOWN_ID,
+ [_USB_PHY_48] = _UNKNOWN_ID,
+ [_HSI_KER] = CK_HSI,
+ [_HSE_KER] = CK_HSE,
+ [_HSE_KER_DIV2] = CK_HSE_DIV2,
+ [_HSE_RTC] = _UNKNOWN_ID,
+ [_CSI_KER] = CK_CSI,
+ [_PLL1_P] = PLL1_P,
+ [_PLL1_Q] = PLL1_Q,
+ [_PLL1_R] = PLL1_R,
+ [_PLL2_P] = PLL2_P,
+ [_PLL2_Q] = PLL2_Q,
+ [_PLL2_R] = PLL2_R,
+ [_PLL3_P] = PLL3_P,
+ [_PLL3_Q] = PLL3_Q,
+ [_PLL3_R] = PLL3_R,
+ [_PLL4_P] = PLL4_P,
+ [_PLL4_Q] = PLL4_Q,
+ [_PLL4_R] = PLL4_R,
+ [_ACLK] = CK_AXI,
+ [_PCLK1] = CK_AXI,
+ [_PCLK2] = CK_AXI,
+ [_PCLK3] = CK_AXI,
+ [_PCLK4] = CK_AXI,
+ [_PCLK5] = CK_AXI,
+ [_CK_PER] = CK_PER,
+ [_CK_MPU] = CK_MPU,
+ [_CK_MCU] = CK_MCU,
+};
+
+static unsigned int clock_id2parent_id(unsigned long id)
+{
+ unsigned int n;
+
+ for (n = 0U; n < ARRAY_SIZE(parent_id_clock_id); n++) {
+ if (parent_id_clock_id[n] == id) {
+ return n;
+ }
+ }
+
+ return _UNKNOWN_ID;
+}
+
+enum stm32mp1_pll_id {
+ _PLL1,
+ _PLL2,
+ _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;
+};
+
+struct stm32mp1_clk_gate {
+ uint16_t offset;
+ uint8_t bit;
+ uint8_t index;
+ uint8_t set_clr;
+ uint8_t secure;
+ uint8_t sel; /* Relates to enum stm32mp1_parent_sel */
+ uint8_t fixed; /* Relates to enum stm32mp1_parent_id */
+};
+
+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(sec, off, b, idx, s) \
+ { \
+ .offset = (off), \
+ .bit = (b), \
+ .index = (idx), \
+ .set_clr = 0, \
+ .secure = (sec), \
+ .sel = (s), \
+ .fixed = _UNKNOWN_ID, \
+ }
+
+/* Clocks with fixed source and non set/clr register access */
+#define _CLK_FIXED(sec, off, b, idx, f) \
+ { \
+ .offset = (off), \
+ .bit = (b), \
+ .index = (idx), \
+ .set_clr = 0, \
+ .secure = (sec), \
+ .sel = _UNKNOWN_SEL, \
+ .fixed = (f), \
+ }
+
+/* Clocks with selectable source and set/clr register access */
+#define _CLK_SC_SELEC(sec, off, b, idx, s) \
+ { \
+ .offset = (off), \
+ .bit = (b), \
+ .index = (idx), \
+ .set_clr = 1, \
+ .secure = (sec), \
+ .sel = (s), \
+ .fixed = _UNKNOWN_ID, \
+ }
+
+/* Clocks with fixed source and set/clr register access */
+#define _CLK_SC_FIXED(sec, off, b, idx, f) \
+ { \
+ .offset = (off), \
+ .bit = (b), \
+ .index = (idx), \
+ .set_clr = 1, \
+ .secure = (sec), \
+ .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) >> \
+ (_rcc_selr ## _ ## _label ## SRC_SHIFT), \
+ .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), \
+ }
+
+#define NB_GATES ARRAY_SIZE(stm32mp1_clk_gate)
+
+#define SEC 1
+#define N_S 0
+
+static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 0, DDRC1, _ACLK),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 1, DDRC1LP, _ACLK),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 2, DDRC2, _ACLK),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 3, DDRC2LP, _ACLK),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 6, DDRCAPB, _PCLK4),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 8, AXIDCG, _ACLK),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4),
+
+#if defined(IMAGE_BL32)
+ _CLK_SC_FIXED(N_S, RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1),
+#endif
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 21, I2C1_K, _I2C12_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL),
+
+#if defined(IMAGE_BL32)
+ _CLK_SC_FIXED(N_S, RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2),
+#endif
+ _CLK_SC_SELEC(N_S, RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
+
+ _CLK_SC_FIXED(N_S, RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID),
+
+ _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
+
+ _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL),
+ _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
+ _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL),
+ _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 4, USART1_K, _UART1_SEL),
+ _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5),
+ _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
+
+#if defined(IMAGE_BL32)
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL),
+#endif
+
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL),
+
+ _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5),
+ _CLK_SC_SELEC(SEC, RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL),
+ _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5),
+
+#if defined(IMAGE_BL2)
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL),
+#endif
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL),
+#if defined(IMAGE_BL32)
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL),
+#endif
+
+ _CLK_SELEC(SEC, RCC_BDCR, 20, RTC, _RTC_SEL),
+ _CLK_SELEC(N_S, 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 axiss_parents[] = {
+ _HSI, _HSE, _PLL2_P
+};
+
+static const uint8_t mcuss_parents[] = {
+ _HSI, _HSE, _CSI, _PLL3_P
+};
+
+static const uint8_t usbphy_parents[] = {
+ _HSE_KER, _PLL4_R, _HSE_KER_DIV2
+};
+
+static const uint8_t usbo_parents[] = {
+ _PLL4_R, _USB_PHY_48
+};
+
+static const uint8_t mpu_parents[] = {
+ _HSI, _HSE, _PLL1_P, _PLL1_P /* specific div */
+};
+
+static const uint8_t per_parents[] = {
+ _HSI, _HSE, _CSI,
+};
+
+static const uint8_t rtc_parents[] = {
+ _UNKNOWN_ID, _LSE, _LSI, _HSE_RTC
+};
+
+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(MPU, RCC_MPCKSELR, mpu_parents),
+ _CLK_PARENT_SEL(CKPER, RCC_CPERCKSELR, per_parents),
+ _CLK_PARENT_SEL(RTC, RCC_BDCR, rtc_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, axiss_parents),
+ _CLK_PARENT_SEL(MCUS, RCC_MSSCKSELR, mcuss_parents),
+ _CLK_PARENT_SEL(USBPHY, RCC_USBCKSELR, usbphy_parents),
+ _CLK_PARENT_SEL(USBO, RCC_USBCKSELR, usbo_parents),
+};
+
+/* Define characteristic of PLL according type */
+#define DIVN_MIN 24
+static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = {
+ [PLL_800] = {
+ .refclk_min = 4,
+ .refclk_max = 16,
+ },
+ [PLL_1600] = {
+ .refclk_min = 8,
+ .refclk_max = 16,
+ },
+};
+
+/* 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
+};
+
+static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = {
+ [_HSI] = "HSI",
+ [_HSE] = "HSE",
+ [_CSI] = "CSI",
+ [_LSI] = "LSI",
+ [_LSE] = "LSE",
+ [_I2S_CKIN] = "I2S_CKIN",
+ [_HSI_KER] = "HSI_KER",
+ [_HSE_KER] = "HSE_KER",
+ [_HSE_KER_DIV2] = "HSE_KER_DIV2",
+ [_HSE_RTC] = "HSE_RTC",
+ [_CSI_KER] = "CSI_KER",
+ [_PLL1_P] = "PLL1_P",
+ [_PLL1_Q] = "PLL1_Q",
+ [_PLL1_R] = "PLL1_R",
+ [_PLL2_P] = "PLL2_P",
+ [_PLL2_Q] = "PLL2_Q",
+ [_PLL2_R] = "PLL2_R",
+ [_PLL3_P] = "PLL3_P",
+ [_PLL3_Q] = "PLL3_Q",
+ [_PLL3_R] = "PLL3_R",
+ [_PLL4_P] = "PLL4_P",
+ [_PLL4_Q] = "PLL4_Q",
+ [_PLL4_R] = "PLL4_R",
+ [_ACLK] = "ACLK",
+ [_PCLK1] = "PCLK1",
+ [_PCLK2] = "PCLK2",
+ [_PCLK3] = "PCLK3",
+ [_PCLK4] = "PCLK4",
+ [_PCLK5] = "PCLK5",
+ [_HCLK6] = "KCLK6",
+ [_HCLK2] = "HCLK2",
+ [_CK_PER] = "CK_PER",
+ [_CK_MPU] = "CK_MPU",
+ [_CK_MCU] = "CK_MCU",
+ [_USB_PHY_48] = "USB_PHY_48",
+};
+
+/* 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];
+}
+
+#if defined(IMAGE_BL32)
+static bool gate_is_non_secure(const struct stm32mp1_clk_gate *gate)
+{
+ return gate->secure == N_S;
+}
+#endif
+
+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();
+ uint32_t mask = RCC_TZCR_TZEN;
+
+ return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask;
+}
+
+bool stm32mp1_rcc_is_mckprot(void)
+{
+ uintptr_t rcc_base = stm32mp_rcc_base();
+ uint32_t mask = RCC_TZCR_TZEN | RCC_TZCR_MCKPROT;
+
+ return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask;
+}
+
+void stm32mp1_clk_rcc_regs_lock(void)
+{
+ stm32mp1_clk_lock(&reg_lock);
+}
+
+void stm32mp1_clk_rcc_regs_unlock(void)
+{
+ stm32mp1_clk_unlock(&reg_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 %lu not found\n", __func__, 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 p_sel;
+ int i;
+ enum stm32mp1_parent_id p;
+ enum stm32mp1_parent_sel s;
+ uintptr_t rcc_base = stm32mp_rcc_base();
+
+ /* Few non gateable clock have a static parent ID, find them */
+ i = (int)clock_id2parent_id(id);
+ if (i != _UNKNOWN_ID) {
+ return i;
+ }
+
+ i = stm32mp1_clk_get_gated_id(id);
+ if (i < 0) {
+ 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)) >> 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;
+ 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 _HSE_RTC:
+ clock = stm32mp1_clk_get_fixed(_HSE);
+ clock /= (mmio_read_32(rcc_base + RCC_RTCDIVR) & RCC_DIVR_DIV_MASK) + 1U;
+ 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();
+
+ VERBOSE("Enable clock %u\n", gate->index);
+
+ if (gate->set_clr != 0U) {
+ mmio_write_32(rcc_base + gate->offset, BIT(gate->bit));
+ } else {
+ mmio_setbits_32(rcc_base + gate->offset, BIT(gate->bit));
+ }
+}
+
+static void __clk_disable(struct stm32mp1_clk_gate const *gate)
+{
+ uintptr_t rcc_base = stm32mp_rcc_base();
+
+ VERBOSE("Disable clock %u\n", gate->index);
+
+ if (gate->set_clr != 0U) {
+ mmio_write_32(rcc_base + gate->offset + RCC_MP_ENCLRR_OFFSET,
+ BIT(gate->bit));
+ } else {
+ mmio_clrbits_32(rcc_base + gate->offset, BIT(gate->bit));
+ }
+}
+
+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);
+}
+
+/* Oscillators and PLLs are not gated at runtime */
+static bool clock_is_always_on(unsigned long id)
+{
+ switch (id) {
+ case CK_HSE:
+ case CK_CSI:
+ case CK_LSI:
+ case CK_LSE:
+ case CK_HSI:
+ case CK_HSE_DIV2:
+ case PLL1_Q:
+ case PLL1_R:
+ case PLL2_P:
+ case PLL2_Q:
+ case PLL2_R:
+ case PLL3_P:
+ case PLL3_Q:
+ case PLL3_R:
+ case CK_AXI:
+ case CK_MPU:
+ case CK_MCU:
+ case RTC:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void __stm32mp1_clk_enable(unsigned long id, bool with_refcnt)
+{
+ const struct stm32mp1_clk_gate *gate;
+ int i;
+
+ if (clock_is_always_on(id)) {
+ return;
+ }
+
+ i = stm32mp1_clk_get_gated_id(id);
+ if (i < 0) {
+ ERROR("Clock %lu can't be enabled\n", id);
+ panic();
+ }
+
+ gate = gate_ref(i);
+
+ if (!with_refcnt) {
+ __clk_enable(gate);
+ return;
+ }
+
+#if defined(IMAGE_BL32)
+ if (gate_is_non_secure(gate)) {
+ /* Enable non-secure clock w/o any refcounting */
+ __clk_enable(gate);
+ return;
+ }
+#endif
+
+ stm32mp1_clk_lock(&refcount_lock);
+
+ if (gate_refcounts[i] == 0U) {
+ __clk_enable(gate);
+ }
+
+ gate_refcounts[i]++;
+ if (gate_refcounts[i] == UINT_MAX) {
+ ERROR("Clock %lu refcount reached max value\n", id);
+ panic();
+ }
+
+ stm32mp1_clk_unlock(&refcount_lock);
+}
+
+static void __stm32mp1_clk_disable(unsigned long id, bool with_refcnt)
+{
+ const struct stm32mp1_clk_gate *gate;
+ int i;
+
+ if (clock_is_always_on(id)) {
+ return;
+ }
+
+ i = stm32mp1_clk_get_gated_id(id);
+ if (i < 0) {
+ ERROR("Clock %lu can't be disabled\n", id);
+ panic();
+ }
+
+ gate = gate_ref(i);
+
+ if (!with_refcnt) {
+ __clk_disable(gate);
+ return;
+ }
+
+#if defined(IMAGE_BL32)
+ if (gate_is_non_secure(gate)) {
+ /* Don't disable non-secure clocks */
+ return;
+ }
+#endif
+
+ stm32mp1_clk_lock(&refcount_lock);
+
+ if (gate_refcounts[i] == 0U) {
+ ERROR("Clock %lu refcount reached 0\n", id);
+ panic();
+ }
+ gate_refcounts[i]--;
+
+ if (gate_refcounts[i] == 0U) {
+ __clk_disable(gate);
+ }
+
+ stm32mp1_clk_unlock(&refcount_lock);
+}
+
+static int stm32mp_clk_enable(unsigned long id)
+{
+ __stm32mp1_clk_enable(id, true);
+
+ return 0;
+}
+
+static void stm32mp_clk_disable(unsigned long id)
+{
+ __stm32mp1_clk_disable(id, true);
+}
+
+static bool stm32mp_clk_is_enabled(unsigned long id)
+{
+ int i;
+
+ if (clock_is_always_on(id)) {
+ return true;
+ }
+
+ i = stm32mp1_clk_get_gated_id(id);
+ if (i < 0) {
+ panic();
+ }
+
+ return __clk_is_enabled(gate_ref(i));
+}
+
+static unsigned long stm32mp_clk_get_rate(unsigned long id)
+{
+ uintptr_t rcc_base = stm32mp_rcc_base();
+ int p = stm32mp1_clk_get_parent(id);
+ uint32_t prescaler, timpre;
+ unsigned long parent_rate;
+
+ if (p < 0) {
+ return 0;
+ }
+
+ parent_rate = get_clock_rate(p);
+
+ switch (id) {
+ case TIM2_K:
+ case TIM3_K:
+ case TIM4_K:
+ case TIM5_K:
+ case TIM6_K:
+ case TIM7_K:
+ case TIM12_K:
+ case TIM13_K:
+ case TIM14_K:
+ prescaler = mmio_read_32(rcc_base + RCC_APB1DIVR) &
+ RCC_APBXDIV_MASK;
+ timpre = mmio_read_32(rcc_base + RCC_TIMG1PRER) &
+ RCC_TIMGXPRER_TIMGXPRE;
+ break;
+
+ case TIM1_K:
+ case TIM8_K:
+ case TIM15_K:
+ case TIM16_K:
+ case TIM17_K:
+ prescaler = mmio_read_32(rcc_base + RCC_APB2DIVR) &
+ RCC_APBXDIV_MASK;
+ timpre = mmio_read_32(rcc_base + RCC_TIMG2PRER) &
+ RCC_TIMGXPRER_TIMGXPRE;
+ break;
+
+ default:
+ return parent_rate;
+ }
+
+ if (prescaler == 0U) {
+ return parent_rate;
+ }
+
+ return parent_rate * (timpre + 1U) * 2U;
+}
+
+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);
+ }
+
+#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
+ if ((mmio_read_32(rcc_base + RCC_OCENSETR) & RCC_OCENR_HSEBYP) &&
+ (!(digbyp || bypass))) {
+ panic();
+ }
+#endif
+}
+
+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 = 0;
+ void *fdt;
+
+ /* 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 */
+ if (fdt_get_address(&fdt) == 1) {
+ fracv = fdt_read_uint32_default(fdt, 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%u 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%u 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_SELR_SRC_MASK) << RCC_BDCR_RTCSRC_SHIFT);
+
+ mmio_setbits_32(address, RCC_BDCR_RTCCKEN);
+ }
+
+ if (lse_css) {
+ mmio_setbits_32(address, RCC_BDCR_LSECSSON);
+ }
+}
+
+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);
+}
+
+static int clk_get_pll_settings_from_dt(int plloff, unsigned int *pllcfg,
+ uint32_t *fracv, uint32_t *csg,
+ bool *csg_set)
+{
+ void *fdt;
+ int ret;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ ret = fdt_read_uint32_array(fdt, plloff, "cfg", (uint32_t)PLLCFG_NB,
+ pllcfg);
+ if (ret < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ *fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0);
+
+ ret = fdt_read_uint32_array(fdt, plloff, "csg", (uint32_t)PLLCSG_NB,
+ csg);
+
+ *csg_set = (ret == 0);
+
+ if (ret == -FDT_ERR_NOTFOUND) {
+ ret = 0;
+ }
+
+ return ret;
+}
+
+int stm32mp1_clk_init(void)
+{
+ uintptr_t rcc_base = stm32mp_rcc_base();
+ uint32_t pllfracv[_PLL_NB];
+ uint32_t pllcsg[_PLL_NB][PLLCSG_NB];
+ unsigned int clksrc[CLKSRC_NB];
+ unsigned int clkdiv[CLKDIV_NB];
+ unsigned int pllcfg[_PLL_NB][PLLCFG_NB];
+ int plloff[_PLL_NB];
+ int ret, len;
+ enum stm32mp1_pll_id i;
+ bool pllcsg_set[_PLL_NB];
+ bool pllcfg_valid[_PLL_NB];
+ bool lse_css = false;
+ bool pll3_preserve = false;
+ bool pll4_preserve = false;
+ bool pll4_bootrom = false;
+ const fdt32_t *pkcs_cell;
+ void *fdt;
+ int stgen_p = stm32mp1_clk_get_parent(STGEN_K);
+ int usbphy_p = stm32mp1_clk_get_parent(USBPHY_K);
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ ret = fdt_rcc_read_uint32_array("st,clksrc", (uint32_t)CLKSRC_NB,
+ clksrc);
+ if (ret < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ ret = fdt_rcc_read_uint32_array("st,clkdiv", (uint32_t)CLKDIV_NB,
+ clkdiv);
+ 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@%u", i);
+ plloff[i] = fdt_rcc_subnode_offset(name);
+
+ pllcfg_valid[i] = fdt_check_node(plloff[i]);
+ if (!pllcfg_valid[i]) {
+ continue;
+ }
+
+ ret = clk_get_pll_settings_from_dt(plloff[i], pllcfg[i],
+ &pllfracv[i], pllcsg[i],
+ &pllcsg_set[i]);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ 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) {
+ const char *name = stm32mp_osc_node_label[_LSE];
+ bool bypass, digbyp;
+ uint32_t lsedrv;
+
+ bypass = fdt_clk_read_bool(name, "st,bypass");
+ digbyp = fdt_clk_read_bool(name, "st,digbypass");
+ lse_css = fdt_clk_read_bool(name, "st,css");
+ lsedrv = fdt_clk_read_uint32_default(name, "st,drive",
+ LSEDRV_MEDIUM_HIGH);
+ stm32mp1_lse_enable(bypass, digbyp, lsedrv);
+ }
+ if (stm32mp1_osc[_HSE] != 0U) {
+ const char *name = stm32mp_osc_node_label[_HSE];
+ bool bypass, digbyp, css;
+
+ bypass = fdt_clk_read_bool(name, "st,bypass");
+ digbyp = fdt_clk_read_bool(name, "st,digbypass");
+ css = fdt_clk_read_bool(name, "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) {
+ if (pllcfg_valid[_PLL3]) {
+ pll3_preserve =
+ stm32mp1_check_pll_conf(_PLL3,
+ clksrc[CLKSRC_PLL3],
+ pllcfg[_PLL3],
+ plloff[_PLL3]);
+ }
+
+ if (pllcfg_valid[_PLL4]) {
+ pll4_preserve =
+ stm32mp1_check_pll_conf(_PLL4,
+ clksrc[CLKSRC_PLL4],
+ pllcfg[_PLL4],
+ plloff[_PLL4]);
+ }
+ }
+ /* Don't initialize PLL4, when used by BOOTROM */
+ if ((stm32mp_get_boot_itf_selected() ==
+ BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB) &&
+ ((stgen_p == (int)_PLL4_R) || (usbphy_p == (int)_PLL4_R))) {
+ pll4_bootrom = true;
+ pll4_preserve = true;
+ }
+
+ for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
+ if (((i == _PLL3) && pll3_preserve) ||
+ ((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;
+ }
+
+ stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K));
+ }
+
+ /* 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++) {
+ if (((i == _PLL3) && pll3_preserve) ||
+ ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) {
+ continue;
+ }
+
+ if (!pllcfg_valid[i]) {
+ continue;
+ }
+
+ if ((i == _PLL4) && pll4_bootrom) {
+ /* Set output divider if not done by the Bootrom */
+ stm32mp1_pll_config_output(i, pllcfg[i]);
+ continue;
+ }
+
+ ret = stm32mp1_pll_config(i, pllcfg[i], pllfracv[i]);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (pllcsg_set[i]) {
+ stm32mp1_pll_csg(i, pllcsg[i]);
+ }
+
+ stm32mp1_pll_start(i);
+ }
+ /* Wait and start PLLs ouptut when ready */
+ for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
+ if (!pllcfg_valid[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;
+ uint32_t usbreg_bootrom = 0U;
+
+ if (pll4_bootrom) {
+ usbreg_bootrom = mmio_read_32(rcc_base + RCC_USBCKSELR);
+ }
+
+ for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) {
+ uint32_t pkcs = fdt32_to_cpu(pkcs_cell[j]);
+
+ 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);
+ }
+
+ if (pll4_bootrom) {
+ uint32_t usbreg_value, usbreg_mask;
+ const struct stm32mp1_clk_sel *sel;
+
+ sel = clk_sel_ref(_USBPHY_SEL);
+ usbreg_mask = (uint32_t)sel->msk << sel->src;
+ sel = clk_sel_ref(_USBO_SEL);
+ usbreg_mask |= (uint32_t)sel->msk << sel->src;
+
+ usbreg_value = mmio_read_32(rcc_base + RCC_USBCKSELR) &
+ usbreg_mask;
+ usbreg_bootrom &= usbreg_mask;
+ if (usbreg_bootrom != usbreg_value) {
+ VERBOSE("forbidden new USB clk path\n");
+ VERBOSE("vs bootrom on USB boot\n");
+ return -FDT_ERR_BADVALUE;
+ }
+ }
+ }
+
+ /* Switch OFF HSI if not found in device-tree */
+ if (stm32mp1_osc[_HSI] == 0U) {
+ stm32mp1_hsi_set(false);
+ }
+
+ stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K));
+
+ /* 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);
+ }
+}
+
+#ifdef STM32MP_SHARED_RESOURCES
+/*
+ * Get the parent ID of the target parent clock, for tagging as secure
+ * shared clock dependencies.
+ */
+static int get_parent_id_parent(unsigned int parent_id)
+{
+ enum stm32mp1_parent_sel s = _UNKNOWN_SEL;
+ enum stm32mp1_pll_id pll_id;
+ uint32_t p_sel;
+ uintptr_t rcc_base = stm32mp_rcc_base();
+
+ switch (parent_id) {
+ case _ACLK:
+ case _PCLK4:
+ case _PCLK5:
+ s = _AXIS_SEL;
+ break;
+ case _PLL1_P:
+ case _PLL1_Q:
+ case _PLL1_R:
+ pll_id = _PLL1;
+ break;
+ case _PLL2_P:
+ case _PLL2_Q:
+ case _PLL2_R:
+ pll_id = _PLL2;
+ break;
+ case _PLL3_P:
+ case _PLL3_Q:
+ case _PLL3_R:
+ pll_id = _PLL3;
+ break;
+ case _PLL4_P:
+ case _PLL4_Q:
+ case _PLL4_R:
+ pll_id = _PLL4;
+ break;
+ case _PCLK1:
+ case _PCLK2:
+ case _HCLK2:
+ case _HCLK6:
+ case _CK_PER:
+ case _CK_MPU:
+ case _CK_MCU:
+ case _USB_PHY_48:
+ /* We do not expect to access these */
+ panic();
+ break;
+ default:
+ /* Other parents have no parent */
+ return -1;
+ }
+
+ if (s != _UNKNOWN_SEL) {
+ const struct stm32mp1_clk_sel *sel = clk_sel_ref(s);
+
+ p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) &
+ sel->msk;
+
+ if (p_sel < sel->nb_parent) {
+ return (int)sel->parent[p_sel];
+ }
+ } else {
+ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
+
+ p_sel = mmio_read_32(rcc_base + pll->rckxselr) &
+ RCC_SELR_REFCLK_SRC_MASK;
+
+ if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) {
+ return (int)pll->refclk[p_sel];
+ }
+ }
+
+ VERBOSE("No parent selected for %s\n",
+ stm32mp1_clk_parent_name[parent_id]);
+
+ return -1;
+}
+
+static void secure_parent_clocks(unsigned long parent_id)
+{
+ int grandparent_id;
+
+ switch (parent_id) {
+ case _PLL3_P:
+ case _PLL3_Q:
+ case _PLL3_R:
+ stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
+ break;
+
+ /* These clocks are always secure when RCC is secure */
+ case _ACLK:
+ case _HCLK2:
+ case _HCLK6:
+ case _PCLK4:
+ case _PCLK5:
+ case _PLL1_P:
+ case _PLL1_Q:
+ case _PLL1_R:
+ case _PLL2_P:
+ case _PLL2_Q:
+ case _PLL2_R:
+ case _HSI:
+ case _HSI_KER:
+ case _LSI:
+ case _CSI:
+ case _CSI_KER:
+ case _HSE:
+ case _HSE_KER:
+ case _HSE_KER_DIV2:
+ case _HSE_RTC:
+ case _LSE:
+ break;
+
+ default:
+ VERBOSE("Cannot secure parent clock %s\n",
+ stm32mp1_clk_parent_name[parent_id]);
+ panic();
+ }
+
+ grandparent_id = get_parent_id_parent(parent_id);
+ if (grandparent_id >= 0) {
+ secure_parent_clocks(grandparent_id);
+ }
+}
+
+void stm32mp1_register_clock_parents_secure(unsigned long clock_id)
+{
+ int parent_id;
+
+ if (!stm32mp1_rcc_is_secure()) {
+ return;
+ }
+
+ switch (clock_id) {
+ case PLL1:
+ case PLL2:
+ /* PLL1/PLL2 are always secure: nothing to do */
+ break;
+ case PLL3:
+ stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
+ break;
+ case PLL4:
+ ERROR("PLL4 cannot be secured\n");
+ panic();
+ break;
+ default:
+ /* Others are expected gateable clock */
+ parent_id = stm32mp1_clk_get_parent(clock_id);
+ if (parent_id < 0) {
+ INFO("No parent found for clock %lu\n", clock_id);
+ } else {
+ secure_parent_clocks(parent_id);
+ }
+ break;
+ }
+}
+#endif /* STM32MP_SHARED_RESOURCES */
+
+static void sync_earlyboot_clocks_state(void)
+{
+ unsigned int idx;
+ const unsigned long secure_enable[] = {
+ AXIDCG,
+ BSEC,
+ DDRC1, DDRC1LP,
+ DDRC2, DDRC2LP,
+ DDRCAPB, DDRPHYCAPB, DDRPHYCAPBLP,
+ DDRPHYC, DDRPHYCLP,
+ RTCAPB,
+ TZC1, TZC2,
+ TZPC,
+ STGEN_K,
+ };
+
+ for (idx = 0U; idx < ARRAY_SIZE(secure_enable); idx++) {
+ stm32mp_clk_enable(secure_enable[idx]);
+ }
+}
+
+static const struct clk_ops stm32mp_clk_ops = {
+ .enable = stm32mp_clk_enable,
+ .disable = stm32mp_clk_disable,
+ .is_enabled = stm32mp_clk_is_enabled,
+ .get_rate = stm32mp_clk_get_rate,
+ .get_parent = stm32mp1_clk_get_parent,
+};
+
+int stm32mp1_clk_probe(void)
+{
+#if defined(IMAGE_BL32)
+ if (!fdt_get_rcc_secure_state()) {
+ mmio_write_32(stm32mp_rcc_base() + RCC_TZCR, 0U);
+ }
+#endif
+
+ stm32mp1_osc_init();
+
+ sync_earlyboot_clocks_state();
+
+ clk_register(&stm32mp_clk_ops);
+
+ return 0;
+}
diff --git a/drivers/st/clk/stm32mp_clkfunc.c b/drivers/st/clk/stm32mp_clkfunc.c
new file mode 100644
index 0000000..01d1420
--- /dev/null
+++ b/drivers/st/clk/stm32mp_clkfunc.c
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/clk.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <lib/mmio.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+/*
+ * 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) &&
+ (fdt_get_status(subnode) != DT_DISABLED)) {
+ 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 node_label: clock node name
+ * @param prop_name: property name
+ * @return: true/false regarding search result.
+ */
+bool fdt_clk_read_bool(const char *node_label, const char *prop_name)
+{
+ int node, subnode;
+ void *fdt;
+
+ if (fdt_get_address(&fdt) == 0) {
+ 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, node_label, (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 name.
+ * @param node_label: oscillator name
+ * @param prop_name: property name
+ * @param dflt_value: default value
+ * @return oscillator value on success, default value if property not found.
+ */
+uint32_t fdt_clk_read_uint32_default(const char *node_label,
+ const char *prop_name, uint32_t dflt_value)
+{
+ int node, subnode;
+ void *fdt;
+
+ if (fdt_get_address(&fdt) == 0) {
+ 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, node_label, (size_t)ret) != 0) {
+ continue;
+ }
+
+ return fdt_read_uint32_default(fdt, 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
+ */
+static int fdt_get_rcc_node(void *fdt)
+{
+ static int node;
+
+ if (node <= 0) {
+ node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
+ }
+
+ return node;
+}
+
+/*
+ * 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 count,
+ uint32_t *array)
+{
+ 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(fdt, node, prop_name, count, array);
+}
+
+/*
+ * 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 state for rcc node in device tree.
+ * @return: true if rcc is configured for secure world access, false if not.
+ */
+bool fdt_get_rcc_secure_state(void)
+{
+ void *fdt;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return false;
+ }
+
+ if (fdt_node_offset_by_compatible(fdt, -1, DT_RCC_SEC_CLK_COMPAT) < 0) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * 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);
+}
+
+/*
+ * Get the frequency of the specified UART instance.
+ * @param instance: UART interface registers base address.
+ * @return: clock frequency on success, 0 value on failure.
+ */
+unsigned long fdt_get_uart_clock_freq(uintptr_t instance)
+{
+ void *fdt;
+ int node;
+ int clk_id;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return 0UL;
+ }
+
+ /* Check for UART nodes */
+ node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance);
+ if (node < 0) {
+ return 0UL;
+ }
+
+ clk_id = fdt_get_clock_id(node);
+ if (clk_id < 0) {
+ return 0UL;
+ }
+
+ return clk_get_rate((unsigned long)clk_id);
+}
+
+/*******************************************************************************
+ * This function configures and restores the STGEN counter depending on the
+ * connected clock.
+ ******************************************************************************/
+void stm32mp_stgen_config(unsigned long rate)
+{
+ uint32_t cntfid0;
+ unsigned long long counter;
+
+ cntfid0 = mmio_read_32(STGEN_BASE + CNTFID_OFF);
+
+ if (cntfid0 == rate) {
+ return;
+ }
+
+ mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
+ counter = stm32mp_stgen_get_counter() * rate / cntfid0;
+
+ mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)counter);
+ mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(counter >> 32));
+ mmio_write_32(STGEN_BASE + CNTFID_OFF, rate);
+ mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
+
+ write_cntfrq_el0(rate);
+
+ /* Need to update timer with new frequency */
+ generic_delay_timer_init();
+}
+
+/*******************************************************************************
+ * This function returns the STGEN counter value.
+ ******************************************************************************/
+unsigned long long stm32mp_stgen_get_counter(void)
+{
+ return (((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF) << 32) |
+ mmio_read_32(STGEN_BASE + CNTCVL_OFF));
+}
+
+/*******************************************************************************
+ * This function restores the STGEN counter value.
+ * It takes a first input value as a counter backup value to be restored and a
+ * offset in ms to be added.
+ ******************************************************************************/
+void stm32mp_stgen_restore_counter(unsigned long long value,
+ unsigned long long offset_in_ms)
+{
+ unsigned long long cnt;
+
+ cnt = value + ((offset_in_ms *
+ mmio_read_32(STGEN_BASE + CNTFID_OFF)) / 1000U);
+
+ mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
+ mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)cnt);
+ mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(cnt >> 32));
+ mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
+}
diff --git a/drivers/st/crypto/stm32_hash.c b/drivers/st/crypto/stm32_hash.c
new file mode 100644
index 0000000..e92f980
--- /dev/null
+++ b/drivers/st/crypto/stm32_hash.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_hash.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <libfdt.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+#if STM32_HASH_VER == 2
+#define DT_HASH_COMPAT "st,stm32f756-hash"
+#endif
+#if STM32_HASH_VER == 4
+#define DT_HASH_COMPAT "st,stm32mp13-hash"
+#endif
+
+#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)
+#if STM32_HASH_VER == 2
+#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))
+#endif
+#if STM32_HASH_VER == 4
+#define HASH_CR_ALGO_SHIFT U(17)
+#define HASH_CR_ALGO_SHA1 (0x0U << HASH_CR_ALGO_SHIFT)
+#define HASH_CR_ALGO_SHA224 (0x2U << HASH_CR_ALGO_SHIFT)
+#define HASH_CR_ALGO_SHA256 (0x3U << HASH_CR_ALGO_SHIFT)
+#define HASH_CR_ALGO_SHA384 (0xCU << HASH_CR_ALGO_SHIFT)
+#define HASH_CR_ALGO_SHA512_224 (0xDU << HASH_CR_ALGO_SHIFT)
+#define HASH_CR_ALGO_SHA512_256 (0xEU << HASH_CR_ALGO_SHIFT)
+#define HASH_CR_ALGO_SHA512 (0xFU << HASH_CR_ALGO_SHIFT)
+#endif
+
+/* 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 SHA384_DIGEST_SIZE 48U
+#define SHA512_224_DIGEST_SIZE 28U
+#define SHA512_256_DIGEST_SIZE 32U
+#define SHA512_DIGEST_SIZE 64U
+
+#define RESET_TIMEOUT_US_1MS 1000U
+#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) {
+#if STM32_HASH_VER == 2
+ case HASH_MD5SUM:
+ reg |= HASH_CR_ALGO_MD5;
+ stm32_hash.digest_size = MD5_DIGEST_SIZE;
+ break;
+#endif
+ 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;
+#if STM32_HASH_VER == 4
+ case HASH_SHA384:
+ reg |= HASH_CR_ALGO_SHA384;
+ stm32_hash.digest_size = SHA384_DIGEST_SIZE;
+ break;
+ case HASH_SHA512:
+ reg |= HASH_CR_ALGO_SHA512;
+ stm32_hash.digest_size = SHA512_DIGEST_SIZE;
+ break;
+#endif
+ /* 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));
+ }
+
+ /*
+ * Clean hardware context as HASH could be used later
+ * by non-secure software
+ */
+ hash_hw_init(HASH_SHA256);
+
+ 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;
+ }
+
+ 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:
+ clk_disable(stm32_hash.clock);
+
+ return ret;
+}
+
+int stm32_hash_final(uint8_t *digest)
+{
+ int ret;
+
+ clk_enable(stm32_hash.clock);
+
+ if (stm32_remain.length != 0U) {
+ ret = hash_write_data(stm32_remain.buffer);
+ if (ret != 0) {
+ 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));
+ } else {
+ mmio_clrbits_32(hash_base() + HASH_STR, HASH_STR_NBLW_MASK);
+ }
+
+ mmio_setbits_32(hash_base() + HASH_STR, HASH_STR_DCAL);
+
+ ret = hash_get_digest(digest);
+
+ 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)
+{
+ clk_enable(stm32_hash.clock);
+
+ hash_hw_init(mode);
+
+ 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 (hash_info.status != DT_DISABLED) {
+ break;
+ }
+ }
+
+ 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;
+
+ clk_enable(stm32_hash.clock);
+
+ if (hash_info.reset >= 0) {
+ uint32_t id = (uint32_t)hash_info.reset;
+
+ if (stm32mp_reset_assert(id, RESET_TIMEOUT_US_1MS) != 0) {
+ panic();
+ }
+ udelay(20);
+ if (stm32mp_reset_deassert(id, RESET_TIMEOUT_US_1MS) != 0) {
+ panic();
+ }
+ }
+
+ clk_disable(stm32_hash.clock);
+
+ return 0;
+}
diff --git a/drivers/st/crypto/stm32_pka.c b/drivers/st/crypto/stm32_pka.c
new file mode 100644
index 0000000..e03cf0f
--- /dev/null
+++ b/drivers/st/crypto/stm32_pka.c
@@ -0,0 +1,707 @@
+/*
+ * Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_pka.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <libfdt.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+/*
+ * For our comprehension in this file
+ * _len are in BITs
+ * _size are in BYTEs
+ * _nbw are in number of PKA_word (PKA_word = u64)
+ */
+
+#define UINT8_LEN 8U
+#define UINT64_LEN (UINT8_LEN * sizeof(uint64_t))
+#define WORD_SIZE (sizeof(uint64_t))
+#define OP_NBW_FROM_LEN(len) (DIV_ROUND_UP_2EVAL((len), UINT64_LEN) + 1)
+#define OP_NBW_FROM_SIZE(s) OP_NBW_FROM_LEN((s) * UINT8_LEN)
+#define OP_SIZE_FROM_SIZE(s) (OP_NBW_FROM_SIZE(s) * WORD_SIZE)
+
+#define DT_PKA_COMPAT "st,stm32-pka64"
+
+#define MAX_ECC_SIZE_LEN 640U
+#define MAX_EO_NBW OP_NBW_FROM_LEN(MAX_ECC_SIZE_LEN)
+
+/* PKA registers */
+/* PKA control register */
+#define _PKA_CR 0x0U
+/* PKA status register */
+#define _PKA_SR 0x4U
+/* PKA clear flag register */
+#define _PKA_CLRFR 0x8U
+/* PKA version register */
+#define _PKA_VERR 0x1FF4U
+/* PKA identification register */
+#define _PKA_IPIDR 0x1FF8U
+
+/* PKA control register fields */
+#define _PKA_CR_MODE_MASK GENMASK(13, 8)
+#define _PKA_CR_MODE_SHIFT 8U
+#define _PKA_CR_MODE_ADD 0x9U
+#define _PKA_CR_MODE_ECDSA_VERIF 0x26U
+#define _PKA_CR_START BIT(1)
+#define _PKA_CR_EN BIT(0)
+
+/* PKA status register fields */
+#define _PKA_SR_BUSY BIT(16)
+#define _PKA_SR_LMF BIT(1)
+#define _PKA_SR_INITOK BIT(0)
+
+/* PKA it flag fields (used in CR, SR and CLRFR) */
+#define _PKA_IT_MASK (GENMASK(21, 19) | BIT(17))
+#define _PKA_IT_SHIFT 17U
+#define _PKA_IT_OPERR BIT(21)
+#define _PKA_IT_ADDRERR BIT(20)
+#define _PKA_IT_RAMERR BIT(19)
+#define _PKA_IT_PROCEND BIT(17)
+
+/* PKA version register fields */
+#define _PKA_VERR_MAJREV_MASK GENMASK(7, 4)
+#define _PKA_VERR_MAJREV_SHIFT 4U
+#define _PKA_VERR_MINREV_MASK GENMASK(3, 0)
+#define _PKA_VERR_MINREV_SHIFT 0U
+
+/* RAM magic offset */
+#define _PKA_RAM_START 0x400U
+#define _PKA_RAM_SIZE 5336U
+
+/* ECDSA verification */
+#define _PKA_RAM_N_LEN 0x408U /* 64 */
+#define _PKA_RAM_P_LEN 0x4C8U /* 64 */
+#define _PKA_RAM_A_SIGN 0x468U /* 64 */
+#define _PKA_RAM_A 0x470U /* EOS */
+#define _PKA_RAM_P 0x4D0U /* EOS */
+#define _PKA_RAM_XG 0x678U /* EOS */
+#define _PKA_RAM_YG 0x6D0U /* EOS */
+#define _PKA_RAM_XQ 0x12F8U /* EOS */
+#define _PKA_RAM_YQ 0x1350U /* EOS */
+#define _PKA_RAM_SIGN_R 0x10E0U /* EOS */
+#define _PKA_RAM_SIGN_S 0xC68U /* EOS */
+#define _PKA_RAM_HASH_Z 0x13A8U /* EOS */
+#define _PKA_RAM_PRIME_N 0x1088U /* EOS */
+#define _PKA_RAM_ECDSA_VERIFY 0x5D0U /* 64 */
+#define _PKA_RAM_ECDSA_VERIFY_VALID 0xD60DULL
+#define _PKA_RAM_ECDSA_VERIFY_INVALID 0xA3B7ULL
+
+#define PKA_TIMEOUT_US 1000000U
+#define TIMEOUT_US_1MS 1000U
+#define PKA_RESET_DELAY 20U
+
+struct curve_parameters {
+ uint32_t a_sign; /* 0 positive, 1 negative */
+ uint8_t *a; /* Curve coefficient |a| */
+ size_t a_size;
+ uint8_t *p; /* Curve modulus value */
+ uint32_t p_len;
+ uint8_t *xg; /* Curve base point G coordinate x */
+ size_t xg_size;
+ uint8_t *yg; /* Curve base point G coordinate y */
+ size_t yg_size;
+ uint8_t *n; /* Curve prime order n */
+ uint32_t n_len;
+};
+
+static const struct curve_parameters curve_def[] = {
+#if PKA_USE_NIST_P256
+ [PKA_NIST_P256] = {
+ .p_len = 256U,
+ .n_len = 256U,
+ .p = (uint8_t[]){0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ .n = (uint8_t[]){0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84,
+ 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51},
+ .a_sign = 1U,
+ .a = (uint8_t[]){0x03},
+ .a_size = 1U,
+ .xg = (uint8_t[]){0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47,
+ 0xF8, 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, 0xF2,
+ 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0,
+ 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96},
+ .xg_size = 32U,
+ .yg = (uint8_t[]){0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B,
+ 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16,
+ 0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE,
+ 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5},
+ .yg_size = 32U,
+ },
+#endif
+#if PKA_USE_BRAINPOOL_P256R1
+ [PKA_BRAINPOOL_P256R1] = {
+ .p_len = 256,
+ .n_len = 256,
+ .p = (uint8_t[]){0xA9, 0xFB, 0x57, 0xDB, 0xA1, 0xEE, 0xA9, 0xBC,
+ 0x3E, 0x66, 0x0A, 0x90, 0x9D, 0x83, 0x8D, 0x72,
+ 0x6E, 0x3B, 0xF6, 0x23, 0xD5, 0x26, 0x20, 0x28,
+ 0x20, 0x13, 0x48, 0x1D, 0x1F, 0x6E, 0x53, 0x77},
+ .n = (uint8_t[]){0xA9, 0xFB, 0x57, 0xDB, 0xA1, 0xEE, 0xA9, 0xBC,
+ 0x3E, 0x66, 0x0A, 0x90, 0x9D, 0x83, 0x8D, 0x71,
+ 0x8C, 0x39, 0x7A, 0xA3, 0xB5, 0x61, 0xA6, 0xF7,
+ 0x90, 0x1E, 0x0E, 0x82, 0x97, 0x48, 0x56, 0xA7},
+ .a = (uint8_t[]){0x7D, 0x5A, 0x09, 0x75, 0xFC, 0x2C, 0x30, 0x57,
+ 0xEE, 0xF6, 0x75, 0x30, 0x41, 0x7A, 0xFF, 0xE7,
+ 0xFB, 0x80, 0x55, 0xC1, 0x26, 0xDC, 0x5C, 0x6C,
+ 0xE9, 0x4A, 0x4B, 0x44, 0xF3, 0x30, 0xB5, 0xD9},
+ .a_size = 32U,
+ .xg = (uint8_t[]){0x8B, 0xD2, 0xAE, 0xB9, 0xCB, 0x7E, 0x57, 0xCB,
+ 0x2C, 0x4B, 0x48, 0x2F, 0xFC, 0x81, 0xB7, 0xAF,
+ 0xB9, 0xDE, 0x27, 0xE1, 0xE3, 0xBD, 0x23, 0xC2,
+ 0x3A, 0x44, 0x53, 0xBD, 0x9A, 0xCE, 0x32, 0x62},
+ .xg_size = 32U,
+ .yg = (uint8_t[]){0x54, 0x7E, 0xF8, 0x35, 0xC3, 0xDA, 0xC4, 0xFD,
+ 0x97, 0xF8, 0x46, 0x1A, 0x14, 0x61, 0x1D, 0xC9,
+ 0xC2, 0x77, 0x45, 0x13, 0x2D, 0xED, 0x8E, 0x54,
+ 0x5C, 0x1D, 0x54, 0xC7, 0x2F, 0x04, 0x69, 0x97},
+ .yg_size = 32U,
+ },
+#endif
+#if PKA_USE_BRAINPOOL_P256T1
+ [PKA_BRAINPOOL_P256T1] = {
+ .p_len = 256,
+ .n_len = 256,
+ .p = (uint8_t[]){0xA9, 0xFB, 0x57, 0xDB, 0xA1, 0xEE, 0xA9, 0xBC,
+ 0x3E, 0x66, 0x0A, 0x90, 0x9D, 0x83, 0x8D, 0x72,
+ 0x6E, 0x3B, 0xF6, 0x23, 0xD5, 0x26, 0x20, 0x28,
+ 0x20, 0x13, 0x48, 0x1D, 0x1F, 0x6E, 0x53, 0x77},
+ .n = (uint8_t[]){0xA9, 0xFB, 0x57, 0xDB, 0xA1, 0xEE, 0xA9, 0xBC,
+ 0x3E, 0x66, 0x0A, 0x90, 0x9D, 0x83, 0x8D, 0x71,
+ 0x8C, 0x39, 0x7A, 0xA3, 0xB5, 0x61, 0xA6, 0xF7,
+ 0x90, 0x1E, 0x0E, 0x82, 0x97, 0x48, 0x56, 0xA7},
+ .a = (uint8_t[]){0xA9, 0xFB, 0x57, 0xDB, 0xA1, 0xEE, 0xA9, 0xBC,
+ 0x3E, 0x66, 0x0A, 0x90, 0x9D, 0x83, 0x8D, 0x72,
+ 0x6E, 0x3B, 0xF6, 0x23, 0xD5, 0x26, 0x20, 0x28,
+ 0x20, 0x13, 0x48, 0x1D, 0x1F, 0x6E, 0x53, 0x74},
+ .a_size = 32U,
+ .xg = (uint8_t[]){0xA3, 0xE8, 0xEB, 0x3C, 0xC1, 0xCF, 0xE7, 0xB7,
+ 0x73, 0x22, 0x13, 0xB2, 0x3A, 0x65, 0x61, 0x49,
+ 0xAF, 0xA1, 0x42, 0xC4, 0x7A, 0xAF, 0xBC, 0x2B,
+ 0x79, 0xA1, 0x91, 0x56, 0x2E, 0x13, 0x05, 0xF4},
+ .xg_size = 32U,
+ .yg = (uint8_t[]){0x2D, 0x99, 0x6C, 0x82, 0x34, 0x39, 0xC5, 0x6D,
+ 0x7F, 0x7B, 0x22, 0xE1, 0x46, 0x44, 0x41, 0x7E,
+ 0x69, 0xBC, 0xB6, 0xDE, 0x39, 0xD0, 0x27, 0x00,
+ 0x1D, 0xAB, 0xE8, 0xF3, 0x5B, 0x25, 0xC9, 0xBE},
+ .yg_size = 32U,
+ },
+#endif
+#if PKA_USE_NIST_P521
+ [PKA_NIST_P521] = {
+ .p_len = 521,
+ .n_len = 521,
+ .p = (uint8_t[]){ 0x01, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ .n = (uint8_t[]){ 0x01, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa,
+ 0x51, 0x86, 0x87, 0x83, 0xbf, 0x2f, 0x96, 0x6b,
+ 0x7f, 0xcc, 0x01, 0x48, 0xf7, 0x09, 0xa5, 0xd0,
+ 0x3b, 0xb5, 0xc9, 0xb8, 0x89, 0x9c, 0x47, 0xae,
+ 0xbb, 0x6f, 0xb7, 0x1e, 0x91, 0x38, 0x64, 0x09},
+ .a_sign = 1,
+ .a = (uint8_t[]){0x03},
+ .a_size = 1U,
+ .xg = (uint8_t[]){ 0xc6,
+ 0x85, 0x8e, 0x06, 0xb7, 0x04, 0x04, 0xe9, 0xcd,
+ 0x9e, 0x3e, 0xcb, 0x66, 0x23, 0x95, 0xb4, 0x42,
+ 0x9c, 0x64, 0x81, 0x39, 0x05, 0x3f, 0xb5, 0x21,
+ 0xf8, 0x28, 0xaf, 0x60, 0x6b, 0x4d, 0x3d, 0xba,
+ 0xa1, 0x4b, 0x5e, 0x77, 0xef, 0xe7, 0x59, 0x28,
+ 0xfe, 0x1d, 0xc1, 0x27, 0xa2, 0xff, 0xa8, 0xde,
+ 0x33, 0x48, 0xb3, 0xc1, 0x85, 0x6a, 0x42, 0x9b,
+ 0xf9, 0x7e, 0x7e, 0x31, 0xc2, 0xe5, 0xbd, 0x66},
+ .xg_size = 65U,
+ .yg = (uint8_t[]){ 0x01, 0x18,
+ 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b, 0xc0, 0x04,
+ 0x5c, 0x8a, 0x5f, 0xb4, 0x2c, 0x7d, 0x1b, 0xd9,
+ 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b, 0x44, 0x68,
+ 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e, 0x66, 0x2c,
+ 0x97, 0xee, 0x72, 0x99, 0x5e, 0xf4, 0x26, 0x40,
+ 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad, 0x07, 0x61,
+ 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72, 0xc2, 0x40,
+ 0x88, 0xbe, 0x94, 0x76, 0x9f, 0xd1, 0x66, 0x50},
+ .yg_size = 66U,
+ },
+#endif
+};
+
+static struct stm32_pka_platdata pka_pdata;
+
+#pragma weak stm32_pka_get_platdata
+
+int stm32_pka_get_platdata(struct stm32_pka_platdata *pdata)
+{
+ return -ENODEV;
+}
+
+static int stm32_pka_parse_fdt(void)
+{
+ int node;
+ struct dt_node_info info;
+ void *fdt;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ node = dt_get_node(&info, -1, DT_PKA_COMPAT);
+ if (node < 0) {
+ ERROR("No PKA entry in DT\n");
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ if (info.status == DT_DISABLED) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ if ((info.base == 0) || (info.clock < 0) || (info.reset < 0)) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ pka_pdata.base = (uintptr_t)info.base;
+ pka_pdata.clock_id = (unsigned long)info.clock;
+ pka_pdata.reset_id = (unsigned int)info.reset;
+
+ return 0;
+}
+
+static int pka_wait_bit(uintptr_t base, uint32_t bit)
+{
+ uint64_t timeout = timeout_init_us(PKA_TIMEOUT_US);
+
+ while ((mmio_read_32(base + _PKA_SR) & bit) != bit) {
+ if (timeout_elapsed(timeout)) {
+ WARN("timeout waiting %x\n", bit);
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+
+}
+
+static void pka_disable(uintptr_t base)
+{
+ mmio_clrbits_32(base + _PKA_CR, _PKA_CR_EN);
+}
+
+static int pka_enable(uintptr_t base, uint32_t mode)
+{
+ /* Set mode and disable interrupts */
+ mmio_clrsetbits_32(base + _PKA_CR, _PKA_IT_MASK | _PKA_CR_MODE_MASK,
+ _PKA_CR_MODE_MASK & (mode << _PKA_CR_MODE_SHIFT));
+
+ mmio_setbits_32(base + _PKA_CR, _PKA_CR_EN);
+
+ return pka_wait_bit(base, _PKA_SR_INITOK);
+}
+
+/*
+ * Data are already loaded in PKA internal RAM
+ * MODE is set
+ * We start process, and wait for its end.
+ */
+static int stm32_pka_process(uintptr_t base)
+{
+ mmio_setbits_32(base + _PKA_CR, _PKA_CR_START);
+
+ return pka_wait_bit(base, _PKA_IT_PROCEND);
+}
+
+/**
+ * @brief Write ECC operand to PKA RAM.
+ * @note PKA expect to write u64 word, each u64 are: the least significant bit is
+ * bit 0; the most significant bit is bit 63.
+ * We write eo_nbw (ECC operand Size) u64, value that depends of the chosen
+ * prime modulus length in bits.
+ * First less signicant u64 is written to low address
+ * Most significant u64 to higher address.
+ * And at last address we write a u64(0x0)
+ * @note This function doesn't only manage endianness (as bswap64 do), but also
+ * complete most significant incomplete u64 with 0 (if data is not a u64
+ * multiple), and fill u64 last address with 0.
+ * @param addr: PKA_RAM address to write the buffer 'data'
+ * @param data: is a BYTE list with most significant bytes first
+ * @param data_size: nb of byte in data
+ * @param eo_nbw: is ECC Operand size in 64bits word (including the extra 0)
+ * (note it depends of the prime modulus length, not the data size)
+ * @retval 0 if OK.
+ * -EINVAL if data_size and eo_nbw are inconsistent, ie data doesn't
+ * fit in defined eo_nbw, or eo_nbw bigger than hardware limit.
+ */
+static int write_eo_data(uintptr_t addr, uint8_t *data, unsigned int data_size,
+ unsigned int eo_nbw)
+{
+ uint32_t word_index;
+ int data_index;
+
+ if ((eo_nbw < OP_NBW_FROM_SIZE(data_size)) || (eo_nbw > MAX_EO_NBW)) {
+ return -EINVAL;
+ }
+
+ /* Fill value */
+ data_index = (int)data_size - 1;
+ for (word_index = 0U; word_index < eo_nbw; word_index++) {
+ uint64_t tmp = 0ULL;
+ unsigned int i = 0U; /* index in the tmp U64 word */
+
+ /* Stop if end of tmp or end of data */
+ while ((i < sizeof(tmp)) && (data_index >= 0)) {
+ tmp |= (uint64_t)(data[data_index]) << (UINT8_LEN * i);
+ i++; /* Move byte index in current (u64)tmp */
+ data_index--; /* Move to just next most significat byte */
+ }
+
+ mmio_write_64(addr + word_index * sizeof(tmp), tmp);
+ }
+
+ return 0;
+}
+
+static unsigned int get_ecc_op_nbword(enum stm32_pka_ecdsa_curve_id cid)
+{
+ if (cid >= ARRAY_SIZE(curve_def)) {
+ ERROR("CID %u is out of boundaries\n", cid);
+ panic();
+ }
+
+ return OP_NBW_FROM_LEN(curve_def[cid].n_len);
+}
+
+static int stm32_pka_ecdsa_verif_configure_curve(uintptr_t base, enum stm32_pka_ecdsa_curve_id cid)
+{
+ int ret;
+ unsigned int eo_nbw = get_ecc_op_nbword(cid);
+
+ mmio_write_64(base + _PKA_RAM_N_LEN, curve_def[cid].n_len);
+ mmio_write_64(base + _PKA_RAM_P_LEN, curve_def[cid].p_len);
+ mmio_write_64(base + _PKA_RAM_A_SIGN, curve_def[cid].a_sign);
+
+ ret = write_eo_data(base + _PKA_RAM_A, curve_def[cid].a, curve_def[cid].a_size, eo_nbw);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = write_eo_data(base + _PKA_RAM_PRIME_N,
+ curve_def[cid].n, div_round_up(curve_def[cid].n_len, UINT8_LEN),
+ eo_nbw);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = write_eo_data(base + _PKA_RAM_P, curve_def[cid].p,
+ div_round_up(curve_def[cid].p_len, UINT8_LEN), eo_nbw);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = write_eo_data(base + _PKA_RAM_XG, curve_def[cid].xg, curve_def[cid].xg_size, eo_nbw);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = write_eo_data(base + _PKA_RAM_YG, curve_def[cid].yg, curve_def[cid].yg_size, eo_nbw);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+static int stm32_pka_ecdsa_verif_check_return(uintptr_t base)
+{
+ uint64_t value;
+ uint32_t sr;
+
+ sr = mmio_read_32(base + _PKA_SR);
+ if ((sr & (_PKA_IT_OPERR | _PKA_IT_ADDRERR | _PKA_IT_RAMERR)) != 0) {
+ WARN("Detected error(s): %s%s%s\n",
+ (sr & _PKA_IT_OPERR) ? "Operation " : "",
+ (sr & _PKA_IT_ADDRERR) ? "Address " : "",
+ (sr & _PKA_IT_RAMERR) ? "RAM" : "");
+ return -EINVAL;
+ }
+
+ value = mmio_read_64(base + _PKA_RAM_ECDSA_VERIFY);
+ if (value == _PKA_RAM_ECDSA_VERIFY_VALID) {
+ return 0;
+ }
+
+ if (value == _PKA_RAM_ECDSA_VERIFY_INVALID) {
+ return -EAUTH;
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * @brief Check if BigInt stored in data is 0
+ *
+ * @param data: a BYTE array with most significant bytes first
+ * @param size: data size
+ *
+ * @retval: true: if data represents a 0 value (ie all bytes == 0)
+ * false: if data represents a non-zero value.
+ */
+static bool is_zero(uint8_t *data, unsigned int size)
+{
+ unsigned int i;
+
+ for (i = 0U; i < size; i++) {
+ if (data[i] != 0U) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * @brief Compare two BigInt:
+ * @param xdata_a: a BYTE array with most significant bytes first
+ * @param size_a: nb of Byte of 'a'
+ * @param data_b: a BYTE array with most significant bytes first
+ * @param size_b: nb of Byte of 'b'
+ *
+ * @retval: true if data_a < data_b
+ * false if data_a >= data_b
+ */
+static bool is_smaller(uint8_t *data_a, unsigned int size_a,
+ uint8_t *data_b, unsigned int size_b)
+{
+ unsigned int i;
+
+ i = MAX(size_a, size_b) + 1U;
+ do {
+ uint8_t a, b;
+
+ i--;
+ if (size_a < i) {
+ a = 0U;
+ } else {
+ a = data_a[size_a - i];
+ }
+
+ if (size_b < i) {
+ b = 0U;
+ } else {
+ b = data_b[size_b - i];
+ }
+
+ if (a < b) {
+ return true;
+ }
+
+ if (a > b) {
+ return false;
+ }
+ } while (i != 0U);
+
+ return false;
+}
+
+static int stm32_pka_ecdsa_check_param(void *sig_r_ptr, unsigned int sig_r_size,
+ void *sig_s_ptr, unsigned int sig_s_size,
+ void *pk_x_ptr, unsigned int pk_x_size,
+ void *pk_y_ptr, unsigned int pk_y_size,
+ enum stm32_pka_ecdsa_curve_id cid)
+{
+ /* Public Key check */
+ /* Check Xq < p */
+ if (!is_smaller(pk_x_ptr, pk_x_size,
+ curve_def[cid].p, div_round_up(curve_def[cid].p_len, UINT8_LEN))) {
+ WARN("%s Xq < p inval\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Check Yq < p */
+ if (!is_smaller(pk_y_ptr, pk_y_size,
+ curve_def[cid].p, div_round_up(curve_def[cid].p_len, UINT8_LEN))) {
+ WARN("%s Yq < p inval\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Signature check */
+ /* Check 0 < r < n */
+ if (!is_smaller(sig_r_ptr, sig_r_size,
+ curve_def[cid].n, div_round_up(curve_def[cid].n_len, UINT8_LEN)) &&
+ !is_zero(sig_r_ptr, sig_r_size)) {
+ WARN("%s 0< r < n inval\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Check 0 < s < n */
+ if (!is_smaller(sig_s_ptr, sig_s_size,
+ curve_def[cid].n, div_round_up(curve_def[cid].n_len, UINT8_LEN)) &&
+ !is_zero(sig_s_ptr, sig_s_size)) {
+ WARN("%s 0< s < n inval\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * @brief Initialize the PKA driver.
+ * @param None.
+ * @retval 0 if OK, negative value else.
+ */
+int stm32_pka_init(void)
+{
+ int err;
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ uint32_t ver;
+ uint32_t id;
+#endif
+
+ err = stm32_pka_parse_fdt();
+ if (err != 0) {
+ err = stm32_pka_get_platdata(&pka_pdata);
+ if (err != 0) {
+ return err;
+ }
+ }
+
+ clk_enable(pka_pdata.clock_id);
+
+ if (stm32mp_reset_assert((unsigned long)pka_pdata.reset_id, TIMEOUT_US_1MS) != 0) {
+ panic();
+ }
+
+ udelay(PKA_RESET_DELAY);
+ if (stm32mp_reset_deassert((unsigned long)pka_pdata.reset_id, TIMEOUT_US_1MS) != 0) {
+ panic();
+ }
+
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ id = mmio_read_32(pka_pdata.base + _PKA_IPIDR);
+ ver = mmio_read_32(pka_pdata.base + _PKA_VERR);
+
+ VERBOSE("STM32 PKA[%x] V%u.%u\n", id,
+ (ver & _PKA_VERR_MAJREV_MASK) >> _PKA_VERR_MAJREV_SHIFT,
+ (ver & _PKA_VERR_MINREV_MASK) >> _PKA_VERR_MINREV_SHIFT);
+#endif
+ return 0;
+}
+
+int stm32_pka_ecdsa_verif(void *hash, unsigned int hash_size,
+ void *sig_r_ptr, unsigned int sig_r_size,
+ void *sig_s_ptr, unsigned int sig_s_size,
+ void *pk_x_ptr, unsigned int pk_x_size,
+ void *pk_y_ptr, unsigned int pk_y_size,
+ enum stm32_pka_ecdsa_curve_id cid)
+{
+ int ret;
+ uintptr_t base = pka_pdata.base;
+ unsigned int eo_nbw = get_ecc_op_nbword(cid);
+
+ if ((hash == NULL) || (sig_r_ptr == NULL) || (sig_s_ptr == NULL) ||
+ (pk_x_ptr == NULL) || (pk_y_ptr == NULL)) {
+ INFO("%s invalid input param\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = stm32_pka_ecdsa_check_param(sig_r_ptr, sig_r_size,
+ sig_s_ptr, sig_s_size,
+ pk_x_ptr, pk_x_size,
+ pk_y_ptr, pk_y_size,
+ cid);
+ if (ret < 0) {
+ INFO("%s check param error %d\n", __func__, ret);
+ goto out;
+ }
+
+ if ((mmio_read_32(base + _PKA_SR) & _PKA_SR_BUSY) == _PKA_SR_BUSY) {
+ INFO("%s busy\n", __func__);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* Fill PKA RAM */
+ /* With curve id values */
+ ret = stm32_pka_ecdsa_verif_configure_curve(base, cid);
+ if (ret < 0) {
+ goto out;
+ }
+
+ /* With pubkey */
+ ret = write_eo_data(base + _PKA_RAM_XQ, pk_x_ptr, pk_x_size, eo_nbw);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = write_eo_data(base + _PKA_RAM_YQ, pk_y_ptr, pk_y_size, eo_nbw);
+ if (ret < 0) {
+ goto out;
+ }
+
+ /* With hash */
+ ret = write_eo_data(base + _PKA_RAM_HASH_Z, hash, hash_size, eo_nbw);
+ if (ret < 0) {
+ goto out;
+ }
+
+ /* With signature */
+ ret = write_eo_data(base + _PKA_RAM_SIGN_R, sig_r_ptr, sig_r_size, eo_nbw);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = write_eo_data(base + _PKA_RAM_SIGN_S, sig_s_ptr, sig_s_size, eo_nbw);
+ if (ret < 0) {
+ goto out;
+ }
+
+ /* Set mode to ecdsa signature verification */
+ ret = pka_enable(base, _PKA_CR_MODE_ECDSA_VERIF);
+ if (ret < 0) {
+ WARN("%s set mode pka error %d\n", __func__, ret);
+ goto out;
+ }
+
+ /* Start processing and wait end */
+ ret = stm32_pka_process(base);
+ if (ret < 0) {
+ WARN("%s process error %d\n", __func__, ret);
+ goto out;
+ }
+
+ /* Check return status */
+ ret = stm32_pka_ecdsa_verif_check_return(base);
+
+ /* Unset end proc */
+ mmio_setbits_32(base + _PKA_CLRFR, _PKA_IT_PROCEND);
+
+out:
+ /* Disable PKA (will stop all pending proccess and reset RAM) */
+ pka_disable(base);
+
+ return ret;
+}
diff --git a/drivers/st/crypto/stm32_rng.c b/drivers/st/crypto/stm32_rng.c
new file mode 100644
index 0000000..a9dc43f
--- /dev/null
+++ b/drivers/st/crypto/stm32_rng.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_rng.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#if STM32_RNG_VER == 2
+#define DT_RNG_COMPAT "st,stm32-rng"
+#endif
+#if STM32_RNG_VER == 4
+#define DT_RNG_COMPAT "st,stm32mp13-rng"
+#endif
+#define RNG_CR 0x00U
+#define RNG_SR 0x04U
+#define RNG_DR 0x08U
+
+#define RNG_CR_RNGEN BIT(2)
+#define RNG_CR_IE BIT(3)
+#define RNG_CR_CED BIT(5)
+#define RNG_CR_CLKDIV GENMASK(19, 16)
+#define RNG_CR_CLKDIV_SHIFT 16U
+#define RNG_CR_CONDRST BIT(30)
+
+#define RNG_SR_DRDY BIT(0)
+#define RNG_SR_CECS BIT(1)
+#define RNG_SR_SECS BIT(2)
+#define RNG_SR_CEIS BIT(5)
+#define RNG_SR_SEIS BIT(6)
+
+#define RNG_TIMEOUT_US 100000U
+#define RNG_TIMEOUT_STEP_US 10U
+
+#define TIMEOUT_US_1MS 1000U
+
+#define RNG_NIST_CONFIG_A 0x00F40F00U
+#define RNG_NIST_CONFIG_B 0x01801000U
+#define RNG_NIST_CONFIG_C 0x00F00D00U
+#define RNG_NIST_CONFIG_MASK GENMASK(25, 8)
+
+#define RNG_MAX_NOISE_CLK_FREQ 48000000U
+
+struct stm32_rng_instance {
+ uintptr_t base;
+ unsigned long clock;
+};
+
+static struct stm32_rng_instance stm32_rng;
+
+static void seed_error_recovery(void)
+{
+ uint8_t i __maybe_unused;
+
+ /* Recommended by the SoC reference manual */
+ mmio_clrbits_32(stm32_rng.base + RNG_SR, RNG_SR_SEIS);
+ dmbsy();
+
+#if STM32_RNG_VER == 2
+ /* No Auto-reset on version 2, need to clean FIFO */
+ for (i = 12U; i != 0U; i--) {
+ (void)mmio_read_32(stm32_rng.base + RNG_DR);
+ }
+
+ dmbsy();
+#endif
+
+ if ((mmio_read_32(stm32_rng.base + RNG_SR) & RNG_SR_SEIS) != 0U) {
+ ERROR("RNG noise\n");
+ panic();
+ }
+}
+
+static uint32_t stm32_rng_clock_freq_restrain(void)
+{
+ unsigned long clock_rate;
+ uint32_t clock_div = 0U;
+
+ clock_rate = clk_get_rate(stm32_rng.clock);
+
+ /*
+ * Get the exponent to apply on the CLKDIV field in RNG_CR register
+ * No need to handle the case when clock-div > 0xF as it is physically
+ * impossible
+ */
+ while ((clock_rate >> clock_div) > RNG_MAX_NOISE_CLK_FREQ) {
+ clock_div++;
+ }
+
+ VERBOSE("RNG clk rate : %lu\n", clk_get_rate(stm32_rng.clock) >> clock_div);
+
+ return clock_div;
+}
+
+static int stm32_rng_enable(void)
+{
+ uint32_t sr;
+ uint64_t timeout;
+ uint32_t clock_div __maybe_unused;
+
+#if STM32_RNG_VER == 2
+ mmio_write_32(stm32_rng.base + RNG_CR, RNG_CR_RNGEN | RNG_CR_CED);
+#endif
+#if STM32_RNG_VER == 4
+ /* Reset internal block and disable CED bit */
+ clock_div = stm32_rng_clock_freq_restrain();
+
+ /* Update configuration fields */
+ mmio_clrsetbits_32(stm32_rng.base + RNG_CR, RNG_NIST_CONFIG_MASK,
+ RNG_NIST_CONFIG_A | RNG_CR_CONDRST | RNG_CR_CED);
+
+ mmio_clrsetbits_32(stm32_rng.base + RNG_CR, RNG_CR_CLKDIV,
+ (clock_div << RNG_CR_CLKDIV_SHIFT));
+
+ mmio_clrsetbits_32(stm32_rng.base + RNG_CR, RNG_CR_CONDRST, RNG_CR_RNGEN);
+#endif
+ timeout = timeout_init_us(RNG_TIMEOUT_US);
+ sr = mmio_read_32(stm32_rng.base + RNG_SR);
+ while ((sr & RNG_SR_DRDY) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ WARN("Timeout waiting\n");
+ return -ETIMEDOUT;
+ }
+
+ if ((sr & (RNG_SR_SECS | RNG_SR_SEIS)) != 0U) {
+ seed_error_recovery();
+ timeout = timeout_init_us(RNG_TIMEOUT_US);
+ }
+
+ udelay(RNG_TIMEOUT_STEP_US);
+ sr = mmio_read_32(stm32_rng.base + RNG_SR);
+ }
+
+ VERBOSE("Init RNG done\n");
+
+ return 0;
+}
+
+/*
+ * stm32_rng_read - Read a number of random bytes from RNG
+ * out: pointer to the output buffer
+ * size: number of bytes to be read
+ * Return 0 on success, non-0 on failure
+ */
+int stm32_rng_read(uint8_t *out, uint32_t size)
+{
+ uint8_t *buf = out;
+ size_t len = size;
+ int nb_tries;
+ uint32_t data32;
+ int rc = 0;
+ unsigned int count;
+
+ if (stm32_rng.base == 0U) {
+ return -EPERM;
+ }
+
+ while (len != 0U) {
+ nb_tries = RNG_TIMEOUT_US / RNG_TIMEOUT_STEP_US;
+ do {
+ uint32_t status = mmio_read_32(stm32_rng.base + RNG_SR);
+
+ if ((status & (RNG_SR_SECS | RNG_SR_SEIS)) != 0U) {
+ seed_error_recovery();
+ }
+
+ udelay(RNG_TIMEOUT_STEP_US);
+ nb_tries--;
+ if (nb_tries == 0) {
+ rc = -ETIMEDOUT;
+ goto bail;
+ }
+ } while ((mmio_read_32(stm32_rng.base + RNG_SR) &
+ RNG_SR_DRDY) == 0U);
+
+ count = 4U;
+ while (len != 0U) {
+ data32 = mmio_read_32(stm32_rng.base + RNG_DR);
+ count--;
+
+ memcpy(buf, &data32, MIN(len, sizeof(uint32_t)));
+ buf += MIN(len, sizeof(uint32_t));
+ len -= MIN(len, sizeof(uint32_t));
+
+ if (count == 0U) {
+ break;
+ }
+ }
+ }
+
+bail:
+ if (rc != 0) {
+ memset(out, 0, buf - out);
+ }
+
+ return rc;
+}
+
+/*
+ * stm32_rng_init: Initialize rng from DT
+ * return 0 on success, negative value on failure
+ */
+int stm32_rng_init(void)
+{
+ void *fdt;
+ struct dt_node_info dt_rng;
+ int node;
+
+ if (stm32_rng.base != 0U) {
+ /* Driver is already initialized */
+ return 0;
+ }
+
+ if (fdt_get_address(&fdt) == 0) {
+ panic();
+ }
+
+ node = dt_get_node(&dt_rng, -1, DT_RNG_COMPAT);
+ if (node < 0) {
+ return 0;
+ }
+
+ if (dt_rng.status == DT_DISABLED) {
+ return 0;
+ }
+
+ assert(dt_rng.base != 0U);
+
+ stm32_rng.base = dt_rng.base;
+
+ if (dt_rng.clock < 0) {
+ panic();
+ }
+
+ stm32_rng.clock = (unsigned long)dt_rng.clock;
+ clk_enable(stm32_rng.clock);
+
+ if (dt_rng.reset >= 0) {
+ int ret;
+
+ ret = stm32mp_reset_assert((unsigned long)dt_rng.reset,
+ TIMEOUT_US_1MS);
+ if (ret != 0) {
+ panic();
+ }
+
+ udelay(20);
+
+ ret = stm32mp_reset_deassert((unsigned long)dt_rng.reset,
+ TIMEOUT_US_1MS);
+ if (ret != 0) {
+ panic();
+ }
+ }
+
+ return stm32_rng_enable();
+}
diff --git a/drivers/st/crypto/stm32_saes.c b/drivers/st/crypto/stm32_saes.c
new file mode 100644
index 0000000..02baf21
--- /dev/null
+++ b/drivers/st/crypto/stm32_saes.c
@@ -0,0 +1,913 @@
+/*
+ * Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+#include <endian.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_saes.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#define UINT8_BIT 8U
+#define AES_BLOCK_SIZE_BIT 128U
+#define AES_BLOCK_SIZE (AES_BLOCK_SIZE_BIT / UINT8_BIT)
+
+#define AES_KEYSIZE_128 16U
+#define AES_KEYSIZE_256 32U
+#define AES_IVSIZE 16U
+
+/* SAES control register */
+#define _SAES_CR 0x0U
+/* SAES status register */
+#define _SAES_SR 0x04U
+/* SAES data input register */
+#define _SAES_DINR 0x08U
+/* SAES data output register */
+#define _SAES_DOUTR 0x0CU
+/* SAES key registers [0-3] */
+#define _SAES_KEYR0 0x10U
+#define _SAES_KEYR1 0x14U
+#define _SAES_KEYR2 0x18U
+#define _SAES_KEYR3 0x1CU
+/* SAES initialization vector registers [0-3] */
+#define _SAES_IVR0 0x20U
+#define _SAES_IVR1 0x24U
+#define _SAES_IVR2 0x28U
+#define _SAES_IVR3 0x2CU
+/* SAES key registers [4-7] */
+#define _SAES_KEYR4 0x30U
+#define _SAES_KEYR5 0x34U
+#define _SAES_KEYR6 0x38U
+#define _SAES_KEYR7 0x3CU
+/* SAES suspend registers [0-7] */
+#define _SAES_SUSPR0 0x40U
+#define _SAES_SUSPR1 0x44U
+#define _SAES_SUSPR2 0x48U
+#define _SAES_SUSPR3 0x4CU
+#define _SAES_SUSPR4 0x50U
+#define _SAES_SUSPR5 0x54U
+#define _SAES_SUSPR6 0x58U
+#define _SAES_SUSPR7 0x5CU
+/* SAES Interrupt Enable Register */
+#define _SAES_IER 0x300U
+/* SAES Interrupt Status Register */
+#define _SAES_ISR 0x304U
+/* SAES Interrupt Clear Register */
+#define _SAES_ICR 0x308U
+
+/* SAES control register fields */
+#define _SAES_CR_RESET_VALUE 0x0U
+#define _SAES_CR_IPRST BIT(31)
+#define _SAES_CR_KEYSEL_MASK GENMASK(30, 28)
+#define _SAES_CR_KEYSEL_SHIFT 28U
+#define _SAES_CR_KEYSEL_SOFT 0x0U
+#define _SAES_CR_KEYSEL_DHUK 0x1U
+#define _SAES_CR_KEYSEL_BHK 0x2U
+#define _SAES_CR_KEYSEL_BHU_XOR_BH_K 0x4U
+#define _SAES_CR_KEYSEL_TEST 0x7U
+#define _SAES_CR_KSHAREID_MASK GENMASK(27, 26)
+#define _SAES_CR_KSHAREID_SHIFT 26U
+#define _SAES_CR_KSHAREID_CRYP 0x0U
+#define _SAES_CR_KEYMOD_MASK GENMASK(25, 24)
+#define _SAES_CR_KEYMOD_SHIFT 24U
+#define _SAES_CR_KEYMOD_NORMAL 0x0U
+#define _SAES_CR_KEYMOD_WRAPPED 0x1U
+#define _SAES_CR_KEYMOD_SHARED 0x2U
+#define _SAES_CR_NPBLB_MASK GENMASK(23, 20)
+#define _SAES_CR_NPBLB_SHIFT 20U
+#define _SAES_CR_KEYPROT BIT(19)
+#define _SAES_CR_KEYSIZE BIT(18)
+#define _SAES_CR_GCMPH_MASK GENMASK(14, 13)
+#define _SAES_CR_GCMPH_SHIFT 13U
+#define _SAES_CR_GCMPH_INIT 0U
+#define _SAES_CR_GCMPH_HEADER 1U
+#define _SAES_CR_GCMPH_PAYLOAD 2U
+#define _SAES_CR_GCMPH_FINAL 3U
+#define _SAES_CR_DMAOUTEN BIT(12)
+#define _SAES_CR_DMAINEN BIT(11)
+#define _SAES_CR_CHMOD_MASK (BIT(16) | GENMASK(6, 5))
+#define _SAES_CR_CHMOD_SHIFT 5U
+#define _SAES_CR_CHMOD_ECB 0x0U
+#define _SAES_CR_CHMOD_CBC 0x1U
+#define _SAES_CR_CHMOD_CTR 0x2U
+#define _SAES_CR_CHMOD_GCM 0x3U
+#define _SAES_CR_CHMOD_GMAC 0x3U
+#define _SAES_CR_CHMOD_CCM 0x800U
+#define _SAES_CR_MODE_MASK GENMASK(4, 3)
+#define _SAES_CR_MODE_SHIFT 3U
+#define _SAES_CR_MODE_ENC 0U
+#define _SAES_CR_MODE_KEYPREP 1U
+#define _SAES_CR_MODE_DEC 2U
+#define _SAES_CR_DATATYPE_MASK GENMASK(2, 1)
+#define _SAES_CR_DATATYPE_SHIFT 1U
+#define _SAES_CR_DATATYPE_NONE 0U
+#define _SAES_CR_DATATYPE_HALF_WORD 1U
+#define _SAES_CR_DATATYPE_BYTE 2U
+#define _SAES_CR_DATATYPE_BIT 3U
+#define _SAES_CR_EN BIT(0)
+
+/* SAES status register fields */
+#define _SAES_SR_KEYVALID BIT(7)
+#define _SAES_SR_BUSY BIT(3)
+#define _SAES_SR_WRERR BIT(2)
+#define _SAES_SR_RDERR BIT(1)
+#define _SAES_SR_CCF BIT(0)
+
+/* SAES interrupt registers fields */
+#define _SAES_I_RNG_ERR BIT(3)
+#define _SAES_I_KEY_ERR BIT(2)
+#define _SAES_I_RW_ERR BIT(1)
+#define _SAES_I_CC BIT(0)
+
+#define SAES_TIMEOUT_US 100000U
+#define TIMEOUT_US_1MS 1000U
+#define SAES_RESET_DELAY 20U
+
+#define IS_CHAINING_MODE(mod, cr) \
+ (((cr) & _SAES_CR_CHMOD_MASK) == (_SAES_CR_CHMOD_##mod << _SAES_CR_CHMOD_SHIFT))
+
+#define SET_CHAINING_MODE(mod, cr) \
+ mmio_clrsetbits_32((cr), _SAES_CR_CHMOD_MASK, _SAES_CR_CHMOD_##mod << _SAES_CR_CHMOD_SHIFT)
+
+#define pragma weak stm32_saes_get_platdata
+
+static struct stm32_saes_platdata saes_pdata;
+
+int stm32_saes_get_platdata(struct stm32_saes_platdata *pdata)
+{
+ return -ENODEV;
+}
+
+static int stm32_saes_parse_fdt(struct stm32_saes_platdata *pdata)
+{
+ int node;
+ struct dt_node_info info;
+ void *fdt;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ node = dt_get_node(&info, -1, DT_SAES_COMPAT);
+ if (node < 0) {
+ ERROR("No SAES entry in DT\n");
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ if (info.status == DT_DISABLED) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ if ((info.base == 0U) || (info.clock < 0) || (info.reset < 0)) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ pdata->base = (uintptr_t)info.base;
+ pdata->clock_id = (unsigned long)info.clock;
+ pdata->reset_id = (unsigned int)info.reset;
+
+ return 0;
+}
+
+static bool does_chaining_mode_need_iv(uint32_t cr)
+{
+ return !(IS_CHAINING_MODE(ECB, cr));
+}
+
+static bool is_encrypt(uint32_t cr)
+{
+ return (cr & _SAES_CR_MODE_MASK) == (_SAES_CR_MODE_ENC << _SAES_CR_MODE_SHIFT);
+}
+
+static bool is_decrypt(uint32_t cr)
+{
+ return (cr & _SAES_CR_MODE_MASK) == (_SAES_CR_MODE_DEC << _SAES_CR_MODE_SHIFT);
+}
+
+static int wait_computation_completed(uintptr_t base)
+{
+ uint64_t timeout = timeout_init_us(SAES_TIMEOUT_US);
+
+ while ((mmio_read_32(base + _SAES_SR) & _SAES_SR_CCF) != _SAES_SR_CCF) {
+ if (timeout_elapsed(timeout)) {
+ WARN("%s: timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static void clear_computation_completed(uintptr_t base)
+{
+ mmio_setbits_32(base + _SAES_ICR, _SAES_I_CC);
+}
+
+static int saes_start(struct stm32_saes_context *ctx)
+{
+ uint64_t timeout;
+
+ /* Reset IP */
+ mmio_setbits_32(ctx->base + _SAES_CR, _SAES_CR_IPRST);
+ udelay(SAES_RESET_DELAY);
+ mmio_clrbits_32(ctx->base + _SAES_CR, _SAES_CR_IPRST);
+
+ timeout = timeout_init_us(SAES_TIMEOUT_US);
+ while ((mmio_read_32(ctx->base + _SAES_SR) & _SAES_SR_BUSY) == _SAES_SR_BUSY) {
+ if (timeout_elapsed(timeout)) {
+ WARN("%s: timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static void saes_end(struct stm32_saes_context *ctx, int prev_error)
+{
+ if (prev_error != 0) {
+ /* Reset IP */
+ mmio_setbits_32(ctx->base + _SAES_CR, _SAES_CR_IPRST);
+ udelay(SAES_RESET_DELAY);
+ mmio_clrbits_32(ctx->base + _SAES_CR, _SAES_CR_IPRST);
+ }
+
+ /* Disable the SAES peripheral */
+ mmio_clrbits_32(ctx->base + _SAES_CR, _SAES_CR_EN);
+}
+
+static void saes_write_iv(struct stm32_saes_context *ctx)
+{
+ /* If chaining mode need to restore IV */
+ if (does_chaining_mode_need_iv(ctx->cr)) {
+ uint8_t i;
+
+ /* Restore the _SAES_IVRx */
+ for (i = 0U; i < AES_IVSIZE / sizeof(uint32_t); i++) {
+ mmio_write_32(ctx->base + _SAES_IVR0 + i * sizeof(uint32_t), ctx->iv[i]);
+ }
+ }
+
+}
+
+static void saes_write_key(struct stm32_saes_context *ctx)
+{
+ /* Restore the _SAES_KEYRx if SOFTWARE key */
+ if ((ctx->cr & _SAES_CR_KEYSEL_MASK) == (_SAES_CR_KEYSEL_SOFT << _SAES_CR_KEYSEL_SHIFT)) {
+ uint8_t i;
+
+ for (i = 0U; i < AES_KEYSIZE_128 / sizeof(uint32_t); i++) {
+ mmio_write_32(ctx->base + _SAES_KEYR0 + i * sizeof(uint32_t), ctx->key[i]);
+ }
+
+ if ((ctx->cr & _SAES_CR_KEYSIZE) == _SAES_CR_KEYSIZE) {
+ for (i = 0U; i < (AES_KEYSIZE_256 / 2U) / sizeof(uint32_t); i++) {
+ mmio_write_32(ctx->base + _SAES_KEYR4 + i * sizeof(uint32_t),
+ ctx->key[i + 4U]);
+ }
+ }
+ }
+}
+
+static int saes_prepare_key(struct stm32_saes_context *ctx)
+{
+ /* Disable the SAES peripheral */
+ mmio_clrbits_32(ctx->base + _SAES_CR, _SAES_CR_EN);
+
+ /* Set key size */
+ if ((ctx->cr & _SAES_CR_KEYSIZE) != 0U) {
+ mmio_setbits_32(ctx->base + _SAES_CR, _SAES_CR_KEYSIZE);
+ } else {
+ mmio_clrbits_32(ctx->base + _SAES_CR, _SAES_CR_KEYSIZE);
+ }
+
+ saes_write_key(ctx);
+
+ /* For ECB/CBC decryption, key preparation mode must be selected to populate the key */
+ if ((IS_CHAINING_MODE(ECB, ctx->cr) || IS_CHAINING_MODE(CBC, ctx->cr)) &&
+ is_decrypt(ctx->cr)) {
+ int ret;
+
+ /* Select Mode 2 */
+ mmio_clrsetbits_32(ctx->base + _SAES_CR, _SAES_CR_MODE_MASK,
+ _SAES_CR_MODE_KEYPREP << _SAES_CR_MODE_SHIFT);
+
+ /* Enable SAES */
+ mmio_setbits_32(ctx->base + _SAES_CR, _SAES_CR_EN);
+
+ /* Wait Computation completed */
+ ret = wait_computation_completed(ctx->base);
+ if (ret != 0) {
+ return ret;
+ }
+
+ clear_computation_completed(ctx->base);
+
+ /* Set Mode 3 */
+ mmio_clrsetbits_32(ctx->base + _SAES_CR, _SAES_CR_MODE_MASK,
+ _SAES_CR_MODE_DEC << _SAES_CR_MODE_SHIFT);
+ }
+
+ return 0;
+}
+
+static int save_context(struct stm32_saes_context *ctx)
+{
+ if ((mmio_read_32(ctx->base + _SAES_SR) & _SAES_SR_CCF) != 0U) {
+ /* Device should not be in a processing phase */
+ return -EINVAL;
+ }
+
+ /* Save CR */
+ ctx->cr = mmio_read_32(ctx->base + _SAES_CR);
+
+ /* If chaining mode need to save current IV */
+ if (does_chaining_mode_need_iv(ctx->cr)) {
+ uint8_t i;
+
+ /* Save IV */
+ for (i = 0U; i < AES_IVSIZE / sizeof(uint32_t); i++) {
+ ctx->iv[i] = mmio_read_32(ctx->base + _SAES_IVR0 + i * sizeof(uint32_t));
+ }
+ }
+
+ /* Disable the SAES peripheral */
+ mmio_clrbits_32(ctx->base + _SAES_CR, _SAES_CR_EN);
+
+ return 0;
+}
+
+/* To resume the processing of a message */
+static int restore_context(struct stm32_saes_context *ctx)
+{
+ int ret;
+
+ /* IP should be disabled */
+ if ((mmio_read_32(ctx->base + _SAES_CR) & _SAES_CR_EN) != 0U) {
+ VERBOSE("%s: Device is still enabled\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Reset internal state */
+ mmio_setbits_32(ctx->base + _SAES_CR, _SAES_CR_IPRST);
+
+ /* Restore the _SAES_CR */
+ mmio_write_32(ctx->base + _SAES_CR, ctx->cr);
+
+ /* Preparation decrypt key */
+ ret = saes_prepare_key(ctx);
+ if (ret != 0) {
+ return ret;
+ }
+
+ saes_write_iv(ctx);
+
+ /* Enable the SAES peripheral */
+ mmio_setbits_32(ctx->base + _SAES_CR, _SAES_CR_EN);
+
+ return 0;
+}
+
+/**
+ * @brief Initialize SAES driver.
+ * @param None.
+ * @retval 0 if OK; negative value else.
+ */
+int stm32_saes_driver_init(void)
+{
+ int err;
+
+ err = stm32_saes_parse_fdt(&saes_pdata);
+ if (err != 0) {
+ err = stm32_saes_get_platdata(&saes_pdata);
+ if (err != 0) {
+ return err;
+ }
+ }
+
+ clk_enable(saes_pdata.clock_id);
+ if (stm32mp_reset_assert(saes_pdata.reset_id, TIMEOUT_US_1MS) != 0) {
+ panic();
+ }
+
+ udelay(SAES_RESET_DELAY);
+ if (stm32mp_reset_deassert(saes_pdata.reset_id, TIMEOUT_US_1MS) != 0) {
+ panic();
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Start a AES computation.
+ * @param ctx: SAES process context
+ * @param is_dec: true if decryption, false if encryption
+ * @param ch_mode: define the chaining mode
+ * @param key_select: define where the key comes from.
+ * @param key: pointer to key (if key_select is KEY_SOFT, else unused)
+ * @param key_size: key size
+ * @param iv: pointer to initialization vectore (unsed if ch_mode is ECB)
+ * @param iv_size: iv size
+ * @note this function doesn't access to hardware but store in ctx the values
+ *
+ * @retval 0 if OK; negative value else.
+ */
+int stm32_saes_init(struct stm32_saes_context *ctx, bool is_dec,
+ enum stm32_saes_chaining_mode ch_mode, enum stm32_saes_key_selection key_select,
+ const void *key, size_t key_size, const void *iv, size_t iv_size)
+{
+ unsigned int i;
+ const uint32_t *iv_u32;
+ const uint32_t *key_u32;
+
+ ctx->assoc_len = 0U;
+ ctx->load_len = 0U;
+
+ ctx->base = saes_pdata.base;
+ ctx->cr = _SAES_CR_RESET_VALUE;
+
+ /* We want buffer to be u32 aligned */
+ assert((uintptr_t)key % __alignof__(uint32_t) == 0);
+ assert((uintptr_t)iv % __alignof__(uint32_t) == 0);
+
+ iv_u32 = iv;
+ key_u32 = key;
+
+ if (is_dec) {
+ /* Save Mode 3 = decrypt */
+ mmio_clrsetbits_32((uintptr_t)&(ctx->cr), _SAES_CR_MODE_MASK,
+ _SAES_CR_MODE_DEC << _SAES_CR_MODE_SHIFT);
+ } else {
+ /* Save Mode 1 = crypt */
+ mmio_clrsetbits_32((uintptr_t)&(ctx->cr), _SAES_CR_MODE_MASK,
+ _SAES_CR_MODE_ENC << _SAES_CR_MODE_SHIFT);
+ }
+
+ /* Save chaining mode */
+ switch (ch_mode) {
+ case STM32_SAES_MODE_ECB:
+ SET_CHAINING_MODE(ECB, (uintptr_t)&(ctx->cr));
+ break;
+ case STM32_SAES_MODE_CBC:
+ SET_CHAINING_MODE(CBC, (uintptr_t)&(ctx->cr));
+ break;
+ case STM32_SAES_MODE_CTR:
+ SET_CHAINING_MODE(CTR, (uintptr_t)&(ctx->cr));
+ break;
+ case STM32_SAES_MODE_GCM:
+ SET_CHAINING_MODE(GCM, (uintptr_t)&(ctx->cr));
+ break;
+ case STM32_SAES_MODE_CCM:
+ SET_CHAINING_MODE(CCM, (uintptr_t)&(ctx->cr));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* We will use HW Byte swap (_SAES_CR_DATATYPE_BYTE) for data.
+ * so we won't need to
+ * htobe32(data) before write to DINR
+ * nor
+ * be32toh after reading from DOUTR
+ *
+ * But note that wrap key only accept _SAES_CR_DATATYPE_NONE
+ */
+ mmio_clrsetbits_32((uintptr_t)&(ctx->cr), _SAES_CR_DATATYPE_MASK,
+ _SAES_CR_DATATYPE_BYTE << _SAES_CR_DATATYPE_SHIFT);
+
+ /* Configure keysize */
+ switch (key_size) {
+ case AES_KEYSIZE_128:
+ mmio_clrbits_32((uintptr_t)&(ctx->cr), _SAES_CR_KEYSIZE);
+ break;
+ case AES_KEYSIZE_256:
+ mmio_setbits_32((uintptr_t)&(ctx->cr), _SAES_CR_KEYSIZE);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Configure key */
+ switch (key_select) {
+ case STM32_SAES_KEY_SOFT:
+ mmio_clrsetbits_32((uintptr_t)&(ctx->cr), _SAES_CR_KEYSEL_MASK,
+ _SAES_CR_KEYSEL_SOFT << _SAES_CR_KEYSEL_SHIFT);
+ /* Save key */
+ switch (key_size) {
+ case AES_KEYSIZE_128:
+ /* First 16 bytes == 4 u32 */
+ for (i = 0U; i < AES_KEYSIZE_128 / sizeof(uint32_t); i++) {
+ mmio_write_32((uintptr_t)(ctx->key + i), htobe32(key_u32[3 - i]));
+ /* /!\ we save the key in HW byte order
+ * and word order : key[i] is for _SAES_KEYRi
+ */
+ }
+ break;
+ case AES_KEYSIZE_256:
+ for (i = 0U; i < AES_KEYSIZE_256 / sizeof(uint32_t); i++) {
+ mmio_write_32((uintptr_t)(ctx->key + i), htobe32(key_u32[7 - i]));
+ /* /!\ we save the key in HW byte order
+ * and word order : key[i] is for _SAES_KEYRi
+ */
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ break;
+ case STM32_SAES_KEY_DHU:
+ mmio_clrsetbits_32((uintptr_t)&(ctx->cr), _SAES_CR_KEYSEL_MASK,
+ _SAES_CR_KEYSEL_DHUK << _SAES_CR_KEYSEL_SHIFT);
+ break;
+ case STM32_SAES_KEY_BH:
+ mmio_clrsetbits_32((uintptr_t)&(ctx->cr), _SAES_CR_KEYSEL_MASK,
+ _SAES_CR_KEYSEL_BHK << _SAES_CR_KEYSEL_SHIFT);
+ break;
+ case STM32_SAES_KEY_BHU_XOR_BH:
+ mmio_clrsetbits_32((uintptr_t)&(ctx->cr), _SAES_CR_KEYSEL_MASK,
+ _SAES_CR_KEYSEL_BHU_XOR_BH_K << _SAES_CR_KEYSEL_SHIFT);
+ break;
+ case STM32_SAES_KEY_WRAPPED:
+ mmio_clrsetbits_32((uintptr_t)&(ctx->cr), _SAES_CR_KEYSEL_MASK,
+ _SAES_CR_KEYSEL_SOFT << _SAES_CR_KEYSEL_SHIFT);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* Save IV */
+ if (ch_mode != STM32_SAES_MODE_ECB) {
+ if ((iv == NULL) || (iv_size != AES_IVSIZE)) {
+ return -EINVAL;
+ }
+
+ for (i = 0U; i < AES_IVSIZE / sizeof(uint32_t); i++) {
+ mmio_write_32((uintptr_t)(ctx->iv + i), htobe32(iv_u32[3 - i]));
+ /* /!\ We save the iv in HW byte order */
+ }
+ }
+
+ return saes_start(ctx);
+}
+
+/**
+ * @brief Update (or start) a AES authentificate process of associated data (CCM or GCM).
+ * @param ctx: SAES process context
+ * @param last_block: true if last assoc data block
+ * @param data: pointer to associated data
+ * @param data_size: data size
+ *
+ * @retval 0 if OK; negative value else.
+ */
+int stm32_saes_update_assodata(struct stm32_saes_context *ctx, bool last_block,
+ uint8_t *data, size_t data_size)
+{
+ int ret;
+ uint32_t *data_u32;
+ unsigned int i = 0U;
+
+ /* We want buffers to be u32 aligned */
+ assert((uintptr_t)data % __alignof__(uint32_t) == 0);
+ data_u32 = (uint32_t *)data;
+
+ /* Init phase */
+ ret = restore_context(ctx);
+ if (ret != 0) {
+ goto out;
+ }
+
+ ret = wait_computation_completed(ctx->base);
+ if (ret != 0) {
+ return ret;
+ }
+
+ clear_computation_completed(ctx->base);
+
+ if ((data == NULL) || (data_size == 0U)) {
+ /* No associated data */
+ /* ret already = 0 */
+ goto out;
+ }
+
+ /* There is an header/associated data phase */
+ mmio_clrsetbits_32(ctx->base + _SAES_CR, _SAES_CR_GCMPH_MASK,
+ _SAES_CR_GCMPH_HEADER << _SAES_CR_GCMPH_SHIFT);
+
+ /* Enable the SAES peripheral */
+ mmio_setbits_32(ctx->base + _SAES_CR, _SAES_CR_EN);
+
+ while (i < round_down(data_size, AES_BLOCK_SIZE)) {
+ unsigned int w; /* Word index */
+
+ w = i / sizeof(uint32_t);
+ /* No need to htobe() as we configure the HW to swap bytes */
+ mmio_write_32(ctx->base + _SAES_DINR, data_u32[w + 0U]);
+ mmio_write_32(ctx->base + _SAES_DINR, data_u32[w + 1U]);
+ mmio_write_32(ctx->base + _SAES_DINR, data_u32[w + 2U]);
+ mmio_write_32(ctx->base + _SAES_DINR, data_u32[w + 3U]);
+
+ ret = wait_computation_completed(ctx->base);
+ if (ret != 0) {
+ goto out;
+ }
+
+ clear_computation_completed(ctx->base);
+
+ /* Process next block */
+ i += AES_BLOCK_SIZE;
+ ctx->assoc_len += AES_BLOCK_SIZE_BIT;
+ }
+
+ /* Manage last block if not a block size multiple */
+ if ((last_block) && (i < data_size)) {
+ /* We don't manage unaligned last block yet */
+ ret = -ENODEV;
+ goto out;
+ }
+
+out:
+ if (ret != 0) {
+ saes_end(ctx, ret);
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Update (or start) a AES authenticate and de/encrypt with payload data (CCM or GCM).
+ * @param ctx: SAES process context
+ * @param last_block: true if last payload data block
+ * @param data_in: pointer to payload
+ * @param data_out: pointer where to save de/encrypted payload
+ * @param data_size: payload size
+ *
+ * @retval 0 if OK; negative value else.
+ */
+int stm32_saes_update_load(struct stm32_saes_context *ctx, bool last_block,
+ uint8_t *data_in, uint8_t *data_out, size_t data_size)
+{
+ int ret = 0;
+ uint32_t *data_in_u32;
+ uint32_t *data_out_u32;
+ unsigned int i = 0U;
+ uint32_t prev_cr;
+
+ /* We want buffers to be u32 aligned */
+ assert((uintptr_t)data_in % __alignof__(uint32_t) == 0);
+ assert((uintptr_t)data_out % __alignof__(uint32_t) == 0);
+ data_in_u32 = (uint32_t *)data_in;
+ data_out_u32 = (uint32_t *)data_out;
+
+ prev_cr = mmio_read_32(ctx->base + _SAES_CR);
+
+ if ((data_in == NULL) || (data_size == 0U)) {
+ /* there is no data */
+ goto out;
+ }
+
+ /* There is a load phase */
+ mmio_clrsetbits_32(ctx->base + _SAES_CR, _SAES_CR_GCMPH_MASK,
+ _SAES_CR_GCMPH_PAYLOAD << _SAES_CR_GCMPH_SHIFT);
+
+ if ((prev_cr & _SAES_CR_GCMPH_MASK) ==
+ (_SAES_CR_GCMPH_INIT << _SAES_CR_GCMPH_SHIFT)) {
+ /* Still in initialization phase, no header
+ * We need to enable the SAES peripheral
+ */
+ mmio_setbits_32(ctx->base + _SAES_CR, _SAES_CR_EN);
+ }
+
+ while (i < round_down(data_size, AES_BLOCK_SIZE)) {
+ unsigned int w; /* Word index */
+
+ w = i / sizeof(uint32_t);
+ /* No need to htobe() as we configure the HW to swap bytes */
+ mmio_write_32(ctx->base + _SAES_DINR, data_in_u32[w + 0U]);
+ mmio_write_32(ctx->base + _SAES_DINR, data_in_u32[w + 1U]);
+ mmio_write_32(ctx->base + _SAES_DINR, data_in_u32[w + 2U]);
+ mmio_write_32(ctx->base + _SAES_DINR, data_in_u32[w + 3U]);
+
+ ret = wait_computation_completed(ctx->base);
+ if (ret != 0) {
+ goto out;
+ }
+
+ /* No need to htobe() as we configure the HW to swap bytes */
+ data_out_u32[w + 0U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ data_out_u32[w + 1U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ data_out_u32[w + 2U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ data_out_u32[w + 3U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+
+ clear_computation_completed(ctx->base);
+
+ /* Process next block */
+ i += AES_BLOCK_SIZE;
+ ctx->load_len += AES_BLOCK_SIZE_BIT;
+ }
+ /* Manage last block if not a block size multiple */
+ if ((last_block) && (i < data_size)) {
+ uint32_t block_in[AES_BLOCK_SIZE / sizeof(uint32_t)] = {0};
+ uint32_t block_out[AES_BLOCK_SIZE / sizeof(uint32_t)] = {0};
+
+ memcpy(block_in, data_in + i, data_size - i);
+
+ /* No need to htobe() as we configure the HW to swap bytes */
+ mmio_write_32(ctx->base + _SAES_DINR, block_in[0U]);
+ mmio_write_32(ctx->base + _SAES_DINR, block_in[1U]);
+ mmio_write_32(ctx->base + _SAES_DINR, block_in[2U]);
+ mmio_write_32(ctx->base + _SAES_DINR, block_in[3U]);
+
+ ret = wait_computation_completed(ctx->base);
+ if (ret != 0) {
+ VERBOSE("%s %d\n", __func__, __LINE__);
+ goto out;
+ }
+
+ /* No need to htobe() as we configure the HW to swap bytes */
+ block_out[0U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ block_out[1U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ block_out[2U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ block_out[3U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+
+ clear_computation_completed(ctx->base);
+
+ memcpy(data_out + i, block_out, data_size - i);
+
+ ctx->load_len += (data_size - i) * UINT8_BIT;
+ }
+
+out:
+ if (ret != 0) {
+ saes_end(ctx, ret);
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Get authentication tag for AES authenticated algorithms (CCM or GCM).
+ * @param ctx: SAES process context
+ * @param tag: pointer where to save the tag
+ * @param data_size: tag size
+ *
+ * @retval 0 if OK; negative value else.
+ */
+int stm32_saes_final(struct stm32_saes_context *ctx, uint8_t *tag,
+ size_t tag_size)
+{
+ int ret;
+ uint32_t tag_u32[4];
+ uint32_t prev_cr;
+
+ prev_cr = mmio_read_32(ctx->base + _SAES_CR);
+
+ mmio_clrsetbits_32(ctx->base + _SAES_CR, _SAES_CR_GCMPH_MASK,
+ _SAES_CR_GCMPH_FINAL << _SAES_CR_GCMPH_SHIFT);
+
+ if ((prev_cr & _SAES_CR_GCMPH_MASK) == (_SAES_CR_GCMPH_INIT << _SAES_CR_GCMPH_SHIFT)) {
+ /* Still in initialization phase, no header
+ * We need to enable the SAES peripheral
+ */
+ mmio_setbits_32(ctx->base + _SAES_CR, _SAES_CR_EN);
+ }
+
+ /* No need to htobe() as we configure the HW to swap bytes */
+ mmio_write_32(ctx->base + _SAES_DINR, 0);
+ mmio_write_32(ctx->base + _SAES_DINR, ctx->assoc_len);
+ mmio_write_32(ctx->base + _SAES_DINR, 0);
+ mmio_write_32(ctx->base + _SAES_DINR, ctx->load_len);
+
+ ret = wait_computation_completed(ctx->base);
+ if (ret != 0) {
+ goto out;
+ }
+
+ /* No need to htobe() as we configure the HW to swap bytes */
+ tag_u32[0] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ tag_u32[1] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ tag_u32[2] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ tag_u32[3] = mmio_read_32(ctx->base + _SAES_DOUTR);
+
+ clear_computation_completed(ctx->base);
+
+ memcpy(tag, tag_u32, MIN(sizeof(tag_u32), tag_size));
+
+out:
+ saes_end(ctx, ret);
+
+ return ret;
+}
+
+/**
+ * @brief Update (or start) a AES de/encrypt process (ECB, CBC or CTR).
+ * @param ctx: SAES process context
+ * @param last_block: true if last payload data block
+ * @param data_in: pointer to payload
+ * @param data_out: pointer where to save de/encrypted payload
+ * @param data_size: payload size
+ *
+ * @retval 0 if OK; negative value else.
+ */
+int stm32_saes_update(struct stm32_saes_context *ctx, bool last_block,
+ uint8_t *data_in, uint8_t *data_out, size_t data_size)
+{
+ int ret;
+ uint32_t *data_in_u32;
+ uint32_t *data_out_u32;
+ unsigned int i = 0U;
+
+ /* We want buffers to be u32 aligned */
+ assert((uintptr_t)data_in % __alignof__(uint32_t) == 0);
+ assert((uintptr_t)data_out % __alignof__(uint32_t) == 0);
+ data_in_u32 = (uint32_t *)data_in;
+ data_out_u32 = (uint32_t *)data_out;
+
+ if ((!last_block) &&
+ (round_down(data_size, AES_BLOCK_SIZE) != data_size)) {
+ ERROR("%s: non last block must be multiple of 128 bits\n",
+ __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* In CBC encryption we need to manage specifically last 2 128bits
+ * blocks if total size in not a block size aligned
+ * work TODO. Currently return ENODEV.
+ * Morevoer as we need to know last 2 block, if unaligned and
+ * call with less than two block, return -EINVAL.
+ */
+ if (last_block && IS_CHAINING_MODE(CBC, ctx->cr) && is_encrypt(ctx->cr) &&
+ (round_down(data_size, AES_BLOCK_SIZE) != data_size)) {
+ if (data_size < AES_BLOCK_SIZE * 2U) {
+ ERROR("if CBC, last part size should be at least 2 * AES_BLOCK_SIZE\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ /* Moreover the CBC specific padding for encrypt is not yet implemented */
+ ret = -ENODEV;
+ goto out;
+ }
+
+ ret = restore_context(ctx);
+ if (ret != 0) {
+ goto out;
+ }
+
+ while (i < round_down(data_size, AES_BLOCK_SIZE)) {
+ unsigned int w; /* Word index */
+
+ w = i / sizeof(uint32_t);
+ /* No need to htobe() as we configure the HW to swap bytes */
+ mmio_write_32(ctx->base + _SAES_DINR, data_in_u32[w + 0U]);
+ mmio_write_32(ctx->base + _SAES_DINR, data_in_u32[w + 1U]);
+ mmio_write_32(ctx->base + _SAES_DINR, data_in_u32[w + 2U]);
+ mmio_write_32(ctx->base + _SAES_DINR, data_in_u32[w + 3U]);
+
+ ret = wait_computation_completed(ctx->base);
+ if (ret != 0) {
+ goto out;
+ }
+
+ /* No need to htobe() as we configure the HW to swap bytes */
+ data_out_u32[w + 0U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ data_out_u32[w + 1U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ data_out_u32[w + 2U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ data_out_u32[w + 3U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+
+ clear_computation_completed(ctx->base);
+
+ /* Process next block */
+ i += AES_BLOCK_SIZE;
+ }
+ /* Manage last block if not a block size multiple */
+
+ if ((last_block) && (i < data_size)) {
+ /* In and out buffer have same size so should be AES_BLOCK_SIZE multiple */
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (!last_block) {
+ ret = save_context(ctx);
+ }
+
+out:
+ /* If last block or error, end of SAES process */
+ if (last_block || (ret != 0)) {
+ saes_end(ctx, ret);
+ }
+
+ return ret;
+}
diff --git a/drivers/st/ddr/stm32mp1_ddr.c b/drivers/st/ddr/stm32mp1_ddr.c
new file mode 100644
index 0000000..4719e1e
--- /dev/null
+++ b/drivers/st/ddr/stm32mp1_ddr.c
@@ -0,0 +1,764 @@
+/*
+ * Copyright (C) 2018-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stddef.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32mp1_ddr.h>
+#include <drivers/st/stm32mp1_ddr_regs.h>
+#include <drivers/st/stm32mp1_pwr.h>
+#include <drivers/st/stm32mp1_ram.h>
+#include <drivers/st/stm32mp_ddr.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+#define DDRCTL_REG(x, y) \
+ { \
+ .name = #x, \
+ .offset = offsetof(struct stm32mp_ddrctl, x), \
+ .par_offset = offsetof(struct y, x) \
+ }
+
+#define DDRPHY_REG(x, y) \
+ { \
+ .name = #x, \
+ .offset = offsetof(struct stm32mp_ddrphy, x), \
+ .par_offset = offsetof(struct y, x) \
+ }
+
+/*
+ * PARAMETERS: value get from device tree :
+ * size / order need to be aligned with binding
+ * modification NOT ALLOWED !!!
+ */
+#define DDRCTL_REG_REG_SIZE 25 /* st,ctl-reg */
+#define DDRCTL_REG_TIMING_SIZE 12 /* st,ctl-timing */
+#define DDRCTL_REG_MAP_SIZE 9 /* st,ctl-map */
+#if STM32MP_DDR_DUAL_AXI_PORT
+#define DDRCTL_REG_PERF_SIZE 17 /* st,ctl-perf */
+#else
+#define DDRCTL_REG_PERF_SIZE 11 /* st,ctl-perf */
+#endif
+
+#if STM32MP_DDR_32BIT_INTERFACE
+#define DDRPHY_REG_REG_SIZE 11 /* st,phy-reg */
+#else
+#define DDRPHY_REG_REG_SIZE 9 /* st,phy-reg */
+#endif
+#define DDRPHY_REG_TIMING_SIZE 10 /* st,phy-timing */
+
+#define DDRCTL_REG_REG(x) DDRCTL_REG(x, stm32mp1_ddrctrl_reg)
+static const struct stm32mp_ddr_reg_desc ddr_reg[DDRCTL_REG_REG_SIZE] = {
+ 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 stm32mp_ddr_reg_desc ddr_timing[DDRCTL_REG_TIMING_SIZE] = {
+ 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 stm32mp_ddr_reg_desc ddr_map[DDRCTL_REG_MAP_SIZE] = {
+ 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 stm32mp_ddr_reg_desc ddr_perf[DDRCTL_REG_PERF_SIZE] = {
+ 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),
+#if STM32MP_DDR_DUAL_AXI_PORT
+ 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),
+#endif
+};
+
+#define DDRPHY_REG_REG(x) DDRPHY_REG(x, stm32mp1_ddrphy_reg)
+static const struct stm32mp_ddr_reg_desc ddrphy_reg[DDRPHY_REG_REG_SIZE] = {
+ 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),
+#if STM32MP_DDR_32BIT_INTERFACE
+ DDRPHY_REG_REG(dx2gcr),
+ DDRPHY_REG_REG(dx3gcr),
+#endif
+};
+
+#define DDRPHY_REG_TIMING(x) DDRPHY_REG(x, stm32mp1_ddrphy_timing)
+static const struct stm32mp_ddr_reg_desc ddrphy_timing[DDRPHY_REG_TIMING_SIZE] = {
+ 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),
+};
+
+/*
+ * REGISTERS ARRAY: used to parse device tree and interactive mode
+ */
+static const struct stm32mp_ddr_reg_info ddr_registers[REG_TYPE_NB] = {
+ [REG_REG] = {
+ .name = "static",
+ .desc = ddr_reg,
+ .size = DDRCTL_REG_REG_SIZE,
+ .base = DDR_BASE
+ },
+ [REG_TIMING] = {
+ .name = "timing",
+ .desc = ddr_timing,
+ .size = DDRCTL_REG_TIMING_SIZE,
+ .base = DDR_BASE
+ },
+ [REG_PERF] = {
+ .name = "perf",
+ .desc = ddr_perf,
+ .size = DDRCTL_REG_PERF_SIZE,
+ .base = DDR_BASE
+ },
+ [REG_MAP] = {
+ .name = "map",
+ .desc = ddr_map,
+ .size = DDRCTL_REG_MAP_SIZE,
+ .base = DDR_BASE
+ },
+ [REGPHY_REG] = {
+ .name = "static",
+ .desc = ddrphy_reg,
+ .size = DDRPHY_REG_REG_SIZE,
+ .base = DDRPHY_BASE
+ },
+ [REGPHY_TIMING] = {
+ .name = "timing",
+ .desc = ddrphy_timing,
+ .size = DDRPHY_REG_TIMING_SIZE,
+ .base = DDRPHY_BASE
+ },
+};
+
+static void stm32mp1_ddrphy_idone_wait(struct stm32mp_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 stm32mp_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);
+}
+
+/* Wait quasi dynamic register update */
+static void stm32mp1_wait_operating_mode(struct stm32mp_ddr_priv *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 stm32mp_ddr_priv *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 stm32mp_ddr_priv *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
+ */
+ stm32mp_ddr_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));
+
+ stm32mp_ddr_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 (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);
+#if STM32MP_DDR_32BIT_INTERFACE
+ mmio_setbits_32((uintptr_t)&priv->phy->dx2dllcr,
+ DDRPHYC_DXNDLLCR_DLLDIS);
+ mmio_setbits_32((uintptr_t)&priv->phy->dx3dllcr,
+ DDRPHYC_DXNDLLCR_DLLDIS);
+#endif
+
+ /* 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 stm32mp_ddrctl *ctl)
+{
+ stm32mp_ddr_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);
+ stm32mp_ddr_wait_sw_done_ack(ctl);
+}
+
+static void stm32mp1_refresh_restore(struct stm32mp_ddrctl *ctl,
+ uint32_t rfshctl3, uint32_t pwrctl)
+{
+ stm32mp_ddr_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);
+ stm32mp_ddr_wait_sw_done_ack(ctl);
+}
+
+void stm32mp1_ddr_init(struct stm32mp_ddr_priv *priv,
+ struct stm32mp_ddr_config *config)
+{
+ uint32_t pir;
+ int ret = -EINVAL;
+
+ if ((config->c_reg.mstr & DDRCTRL_MSTR_DDR3) != 0U) {
+ ret = stm32mp_board_ddr_power_init(STM32MP_DDR3);
+ } else if ((config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2) != 0U) {
+ ret = stm32mp_board_ddr_power_init(STM32MP_LPDDR2);
+ } else if ((config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3) != 0U) {
+ ret = stm32mp_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 = %u 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));
+
+ stm32mp_ddr_set_reg(priv, REG_REG, &config->c_reg, ddr_registers);
+
+ /* 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));
+ }
+
+ stm32mp_ddr_set_reg(priv, REG_TIMING, &config->c_timing, ddr_registers);
+ stm32mp_ddr_set_reg(priv, REG_MAP, &config->c_map, ddr_registers);
+
+ /* 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));
+
+ stm32mp_ddr_set_reg(priv, REG_PERF, &config->c_perf, ddr_registers);
+
+ /* 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*)
+ */
+ stm32mp_ddr_set_reg(priv, REGPHY_REG, &config->p_reg, ddr_registers);
+ stm32mp_ddr_set_reg(priv, REGPHY_TIMING, &config->p_timing, ddr_registers);
+
+ /* 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.
+ */
+ stm32mp_ddr_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));
+
+ stm32mp_ddr_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
+ * RVTRN is executed only on LPDDR2/LPDDR3
+ */
+ pir = DDRPHYC_PIR_QSTRN;
+ if ((config->c_reg.mstr & DDRCTRL_MSTR_DDR3) == 0U) {
+ pir |= DDRPHYC_PIR_RVTRN;
+ }
+
+ stm32mp1_ddrphy_init(priv->phy, pir);
+
+ /* 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);
+
+ stm32mp_ddr_enable_axi_port(priv->ctl);
+}
diff --git a/drivers/st/ddr/stm32mp1_ddr_helpers.c b/drivers/st/ddr/stm32mp1_ddr_helpers.c
new file mode 100644
index 0000000..e0621b5
--- /dev/null
+++ b/drivers/st/ddr/stm32mp1_ddr_helpers.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/st/stm32mp1_ddr_helpers.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+void ddr_enable_clock(void)
+{
+ stm32mp1_clk_rcc_regs_lock();
+
+ mmio_setbits_32(stm32mp_rcc_base() + RCC_DDRITFCR,
+ RCC_DDRITFCR_DDRC1EN |
+#if STM32MP_DDR_DUAL_AXI_PORT
+ RCC_DDRITFCR_DDRC2EN |
+#endif
+ RCC_DDRITFCR_DDRPHYCEN |
+ RCC_DDRITFCR_DDRPHYCAPBEN |
+ RCC_DDRITFCR_DDRCAPBEN);
+
+ stm32mp1_clk_rcc_regs_unlock();
+}
diff --git a/drivers/st/ddr/stm32mp1_ram.c b/drivers/st/ddr/stm32mp1_ram.c
new file mode 100644
index 0000000..b510c8f
--- /dev/null
+++ b/drivers/st/ddr/stm32mp1_ram.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2018-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/clk.h>
+#include <drivers/st/stm32mp1_ddr.h>
+#include <drivers/st/stm32mp1_ddr_helpers.h>
+#include <drivers/st/stm32mp1_ram.h>
+#include <drivers/st/stm32mp_ddr.h>
+#include <drivers/st/stm32mp_ddr_test.h>
+#include <drivers/st/stm32mp_ram.h>
+#include <lib/mmio.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+static struct stm32mp_ddr_priv ddr_priv_data;
+
+int stm32mp1_ddr_clk_enable(struct stm32mp_ddr_priv *priv, uint32_t mem_speed)
+{
+ unsigned long ddrphy_clk, ddr_clk, mem_speed_hz;
+
+ ddr_enable_clock();
+
+ ddrphy_clk = clk_get_rate(DDRPHYC);
+
+ VERBOSE("DDR: mem_speed (%u kHz), RCC %lu 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 %u kHz, current is %lu kHz\n",
+ mem_speed, ddrphy_clk / 1000U);
+ return -1;
+ }
+ return 0;
+}
+
+static int stm32mp1_ddr_setup(void)
+{
+ struct stm32mp_ddr_priv *priv = &ddr_priv_data;
+ int ret;
+ struct stm32mp_ddr_config config;
+ int node;
+ uint32_t uret;
+ void *fdt;
+
+ const struct stm32mp_ddr_param param[] = {
+ CTL_PARAM(reg),
+ CTL_PARAM(timing),
+ CTL_PARAM(map),
+ CTL_PARAM(perf),
+ PHY_PARAM(reg),
+ PHY_PARAM(timing),
+ };
+
+ 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;
+ }
+
+ ret = stm32mp_ddr_dt_get_info(fdt, node, &config.info);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = stm32mp_ddr_dt_get_param(fdt, node, param, ARRAY_SIZE(param), (uintptr_t)&config);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* 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);
+
+ if (stm32mp_map_ddr_non_cacheable() != 0) {
+ panic();
+ }
+
+ uret = stm32mp_ddr_test_data_bus();
+ if (uret != 0U) {
+ ERROR("DDR data bus test: can't access memory @ 0x%x\n",
+ uret);
+ panic();
+ }
+
+ uret = stm32mp_ddr_test_addr_bus(config.info.size);
+ if (uret != 0U) {
+ ERROR("DDR addr bus test: can't access memory @ 0x%x\n",
+ uret);
+ panic();
+ }
+
+ uret = stm32mp_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();
+ }
+
+ if (stm32mp_unmap_ddr() != 0) {
+ panic();
+ }
+
+ return 0;
+}
+
+int stm32mp1_ddr_probe(void)
+{
+ struct stm32mp_ddr_priv *priv = &ddr_priv_data;
+
+ VERBOSE("STM32MP DDR probe\n");
+
+ priv->ctl = (struct stm32mp_ddrctl *)stm32mp_ddrctrl_base();
+ priv->phy = (struct stm32mp_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();
+}
diff --git a/drivers/st/ddr/stm32mp_ddr.c b/drivers/st/ddr/stm32mp_ddr.c
new file mode 100644
index 0000000..6776e3b
--- /dev/null
+++ b/drivers/st/ddr/stm32mp_ddr.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32mp_ddr.h>
+#include <drivers/st/stm32mp_ddrctrl_regs.h>
+#include <drivers/st/stm32mp_pmic.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+#define INVALID_OFFSET 0xFFU
+
+static uintptr_t get_base_addr(const struct stm32mp_ddr_priv *priv, enum stm32mp_ddr_base_type base)
+{
+ if (base == DDRPHY_BASE) {
+ return (uintptr_t)priv->phy;
+ } else {
+ return (uintptr_t)priv->ctl;
+ }
+}
+
+void stm32mp_ddr_set_reg(const struct stm32mp_ddr_priv *priv, enum stm32mp_ddr_reg_type type,
+ const void *param, const struct stm32mp_ddr_reg_info *ddr_registers)
+{
+ unsigned int i;
+ unsigned int value;
+ enum stm32mp_ddr_base_type base = ddr_registers[type].base;
+ uintptr_t base_addr = get_base_addr(priv, base);
+ const struct stm32mp_ddr_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);
+ }
+ }
+}
+
+/* Start quasi dynamic register update */
+void stm32mp_ddr_start_sw_done(struct stm32mp_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 */
+void stm32mp_ddr_wait_sw_done_ack(struct stm32mp_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);
+}
+
+void stm32mp_ddr_enable_axi_port(struct stm32mp_ddrctl *ctl)
+{
+ /* Enable uMCTL2 AXI port 0 */
+ mmio_setbits_32((uintptr_t)&ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN);
+ VERBOSE("[0x%lx] pctrl_0 = 0x%x\n", (uintptr_t)&ctl->pctrl_0,
+ mmio_read_32((uintptr_t)&ctl->pctrl_0));
+
+#if STM32MP_DDR_DUAL_AXI_PORT
+ /* Enable uMCTL2 AXI port 1 */
+ mmio_setbits_32((uintptr_t)&ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN);
+ VERBOSE("[0x%lx] pctrl_1 = 0x%x\n", (uintptr_t)&ctl->pctrl_1,
+ mmio_read_32((uintptr_t)&ctl->pctrl_1));
+#endif
+
+}
+
+int stm32mp_board_ddr_power_init(enum ddr_type ddr_type)
+{
+ if (dt_pmic_status() > 0) {
+ return pmic_ddr_power_init(ddr_type);
+ }
+
+ return 0;
+}
diff --git a/drivers/st/ddr/stm32mp_ddr_test.c b/drivers/st/ddr/stm32mp_ddr_test.c
new file mode 100644
index 0000000..6733cc6
--- /dev/null
+++ b/drivers/st/ddr/stm32mp_ddr_test.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/st/stm32mp_ddr_test.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+#define DDR_PATTERN 0xAAAAAAAAU
+#define DDR_ANTIPATTERN 0x55555555U
+
+/*******************************************************************************
+ * This function tests a simple read/write access to the DDR.
+ * Note that the previous content is restored after test.
+ * Returns 0 if success, and address value else.
+ ******************************************************************************/
+uint32_t stm32mp_ddr_test_rw_access(void)
+{
+ uint32_t saved_value = mmio_read_32(STM32MP_DDR_BASE);
+
+ mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN);
+
+ if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) {
+ return (uint32_t)STM32MP_DDR_BASE;
+ }
+
+ mmio_write_32(STM32MP_DDR_BASE, saved_value);
+
+ return 0U;
+}
+
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+uint32_t stm32mp_ddr_test_data_bus(void)
+{
+ uint32_t pattern;
+
+ for (pattern = 1U; pattern != 0U; pattern <<= 1U) {
+ 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.
+ * size: size in bytes of the DDR memory device.
+ * Returns 0 if success, and address value else.
+ ******************************************************************************/
+uint32_t stm32mp_ddr_test_addr_bus(uint64_t size)
+{
+ uint64_t addressmask = size - 1U;
+ uint64_t offset;
+ uint64_t testoffset = 0U;
+
+ /* Write the default pattern at each of the power-of-two offsets. */
+ for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
+ offset <<= 1U) {
+ 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 <<= 1U) {
+ 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 <<= 1U) {
+ 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 0U;
+}
+
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+uint32_t stm32mp_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 <<= 1U;
+ }
+
+ INFO("Memory size = 0x%x (%u MB)\n", offset, offset / (1024U * 1024U));
+
+ return offset;
+}
diff --git a/drivers/st/ddr/stm32mp_ram.c b/drivers/st/ddr/stm32mp_ram.c
new file mode 100644
index 0000000..0804568
--- /dev/null
+++ b/drivers/st/ddr/stm32mp_ram.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/st/stm32mp_ram.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+int stm32mp_ddr_dt_get_info(void *fdt, int node, struct stm32mp_ddr_info *info)
+{
+ int ret;
+
+ ret = fdt_read_uint32(fdt, node, "st,mem-speed", &info->speed);
+ if (ret < 0) {
+ VERBOSE("%s: no st,mem-speed\n", __func__);
+ return -EINVAL;
+ }
+ ret = fdt_read_uint32(fdt, node, "st,mem-size", &info->size);
+ if (ret < 0) {
+ VERBOSE("%s: no st,mem-size\n", __func__);
+ return -EINVAL;
+ }
+ info->name = fdt_getprop(fdt, node, "st,mem-name", NULL);
+ if (info->name == NULL) {
+ VERBOSE("%s: no st,mem-name\n", __func__);
+ return -EINVAL;
+ }
+
+ INFO("RAM: %s\n", info->name);
+
+ return 0;
+}
+
+int stm32mp_ddr_dt_get_param(void *fdt, int node, const struct stm32mp_ddr_param *param,
+ uint32_t param_size, uintptr_t config)
+{
+ int ret;
+ uint32_t idx;
+
+ for (idx = 0U; idx < param_size; idx++) {
+ ret = fdt_read_uint32_array(fdt, node, param[idx].name, param[idx].size,
+ (void *)(config + param[idx].offset));
+
+ VERBOSE("%s: %s[0x%x] = %d\n", __func__, param[idx].name, param[idx].size, ret);
+ if (ret != 0) {
+ ERROR("%s: Cannot read %s, error=%d\n", __func__, param[idx].name, ret);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/st/etzpc/etzpc.c b/drivers/st/etzpc/etzpc.c
new file mode 100644
index 0000000..4c3c26d
--- /dev/null
+++ b/drivers/st/etzpc/etzpc.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/st/etzpc.h>
+#include <dt-bindings/soc/st,stm32-etzpc.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+/* Device Tree related definitions */
+#define ETZPC_COMPAT "st,stm32-etzpc"
+#define ETZPC_LOCK_MASK 0x1U
+#define ETZPC_MODE_SHIFT 8
+#define ETZPC_MODE_MASK GENMASK(1, 0)
+#define ETZPC_ID_SHIFT 16
+#define ETZPC_ID_MASK GENMASK(7, 0)
+
+/* ID Registers */
+#define ETZPC_TZMA0_SIZE 0x000U
+#define ETZPC_DECPROT0 0x010U
+#define ETZPC_DECPROT_LOCK0 0x030U
+#define ETZPC_HWCFGR 0x3F0U
+#define ETZPC_VERR 0x3F4U
+
+/* ID Registers fields */
+#define ETZPC_TZMA0_SIZE_LOCK BIT(31)
+#define ETZPC_DECPROT0_MASK GENMASK(1, 0)
+#define ETZPC_HWCFGR_NUM_TZMA_SHIFT 0
+#define ETZPC_HWCFGR_NUM_PER_SEC_SHIFT 8
+#define ETZPC_HWCFGR_NUM_AHB_SEC_SHIFT 16
+#define ETZPC_HWCFGR_CHUNCKS1N4_SHIFT 24
+
+#define DECPROT_SHIFT 1
+#define IDS_PER_DECPROT_REGS 16U
+#define IDS_PER_DECPROT_LOCK_REGS 32U
+
+/*
+ * etzpc_instance.
+ * base : register base address set during init given by user
+ * chunk_size : supported TZMA size steps
+ * num_tzma: number of TZMA zone read from register at init
+ * num_ahb_sec : number of securable AHB master zone read from register
+ * num_per_sec : number of securable AHB & APB Peripherals read from register
+ * revision : IP revision read from register at init
+ */
+struct etzpc_instance {
+ uintptr_t base;
+ uint8_t chunck_size;
+ uint8_t num_tzma;
+ uint8_t num_per_sec;
+ uint8_t num_ahb_sec;
+ uint8_t revision;
+};
+
+/* Only 1 instance of the ETZPC is expected per platform */
+static struct etzpc_instance etzpc_dev;
+
+/*
+ * Implementation uses uint8_t to store each securable DECPROT configuration.
+ * When resuming from deep suspend, the DECPROT configurations are restored.
+ */
+#define PERIPH_LOCK_BIT BIT(7)
+#define PERIPH_ATTR_MASK GENMASK(2, 0)
+
+#if ENABLE_ASSERTIONS
+static bool valid_decprot_id(unsigned int id)
+{
+ return id < (unsigned int)etzpc_dev.num_per_sec;
+}
+
+static bool valid_tzma_id(unsigned int id)
+{
+ return id < (unsigned int)etzpc_dev.num_tzma;
+}
+#endif
+
+/*
+ * etzpc_configure_decprot : Load a DECPROT configuration
+ * decprot_id : ID of the IP
+ * decprot_attr : Restriction access attribute
+ */
+void etzpc_configure_decprot(uint32_t decprot_id,
+ enum etzpc_decprot_attributes decprot_attr)
+{
+ uintptr_t offset = 4U * (decprot_id / IDS_PER_DECPROT_REGS);
+ uint32_t shift = (decprot_id % IDS_PER_DECPROT_REGS) << DECPROT_SHIFT;
+ uint32_t masked_decprot = (uint32_t)decprot_attr & ETZPC_DECPROT0_MASK;
+
+ assert(valid_decprot_id(decprot_id));
+
+ mmio_clrsetbits_32(etzpc_dev.base + ETZPC_DECPROT0 + offset,
+ (uint32_t)ETZPC_DECPROT0_MASK << shift,
+ masked_decprot << shift);
+}
+
+/*
+ * etzpc_get_decprot : Get the DECPROT attribute
+ * decprot_id : ID of the IP
+ * return : Attribute of this DECPROT
+ */
+enum etzpc_decprot_attributes etzpc_get_decprot(uint32_t decprot_id)
+{
+ uintptr_t offset = 4U * (decprot_id / IDS_PER_DECPROT_REGS);
+ uint32_t shift = (decprot_id % IDS_PER_DECPROT_REGS) << DECPROT_SHIFT;
+ uintptr_t base_decprot = etzpc_dev.base + offset;
+ uint32_t value;
+
+ assert(valid_decprot_id(decprot_id));
+
+ value = (mmio_read_32(base_decprot + ETZPC_DECPROT0) >> shift) &
+ ETZPC_DECPROT0_MASK;
+
+ return (enum etzpc_decprot_attributes)value;
+}
+
+/*
+ * etzpc_lock_decprot : Lock access to the DECPROT attribute
+ * decprot_id : ID of the IP
+ */
+void etzpc_lock_decprot(uint32_t decprot_id)
+{
+ uintptr_t offset = 4U * (decprot_id / IDS_PER_DECPROT_LOCK_REGS);
+ uint32_t shift = BIT(decprot_id % IDS_PER_DECPROT_LOCK_REGS);
+ uintptr_t base_decprot = etzpc_dev.base + offset;
+
+ assert(valid_decprot_id(decprot_id));
+
+ mmio_write_32(base_decprot + ETZPC_DECPROT_LOCK0, shift);
+}
+
+/*
+ * etzpc_configure_tzma : Configure the target TZMA read only size
+ * tzma_id : ID of the memory
+ * tzma_value : read-only size
+ */
+void etzpc_configure_tzma(uint32_t tzma_id, uint16_t tzma_value)
+{
+ assert(valid_tzma_id(tzma_id));
+
+ mmio_write_32(etzpc_dev.base + ETZPC_TZMA0_SIZE +
+ (sizeof(uint32_t) * tzma_id), tzma_value);
+}
+
+/*
+ * etzpc_get_tzma : Get the target TZMA read only size
+ * tzma_id : TZMA ID
+ * return : Size of read only size
+ */
+uint16_t etzpc_get_tzma(uint32_t tzma_id)
+{
+ assert(valid_tzma_id(tzma_id));
+
+ return (uint16_t)mmio_read_32(etzpc_dev.base + ETZPC_TZMA0_SIZE +
+ (sizeof(uint32_t) * tzma_id));
+}
+
+/*
+ * etzpc_lock_tzma : Lock the target TZMA
+ * tzma_id : TZMA ID
+ */
+void etzpc_lock_tzma(uint32_t tzma_id)
+{
+ assert(valid_tzma_id(tzma_id));
+
+ mmio_setbits_32(etzpc_dev.base + ETZPC_TZMA0_SIZE +
+ (sizeof(uint32_t) * tzma_id), ETZPC_TZMA0_SIZE_LOCK);
+}
+
+/*
+ * etzpc_get_lock_tzma : Return the lock status of the target TZMA
+ * tzma_id : TZMA ID
+ * return : True if TZMA is locked, false otherwise
+ */
+bool etzpc_get_lock_tzma(uint32_t tzma_id)
+{
+ uint32_t tzma_size;
+
+ assert(valid_tzma_id(tzma_id));
+
+ tzma_size = mmio_read_32(etzpc_dev.base + ETZPC_TZMA0_SIZE +
+ (sizeof(uint32_t) * tzma_id));
+
+ return (tzma_size & ETZPC_TZMA0_SIZE_LOCK) != 0;
+}
+
+/*
+ * etzpc_get_num_per_sec : Return the DECPROT ID limit value
+ */
+uint8_t etzpc_get_num_per_sec(void)
+{
+ return etzpc_dev.num_per_sec;
+}
+
+/*
+ * etzpc_get_revision : Return the ETZPC IP revision
+ */
+uint8_t etzpc_get_revision(void)
+{
+ return etzpc_dev.revision;
+}
+
+/*
+ * etzpc_get_base_address : Return the ETZPC IP base address
+ */
+uintptr_t etzpc_get_base_address(void)
+{
+ return etzpc_dev.base;
+}
+
+/*
+ * etzpc_init : Initialize the ETZPC driver
+ * Return 0 on success and a negative errno on failure
+ */
+int etzpc_init(void)
+{
+ uint32_t hwcfg;
+
+ etzpc_dev.base = STM32MP1_ETZPC_BASE;
+
+ hwcfg = mmio_read_32(etzpc_dev.base + ETZPC_HWCFGR);
+
+ etzpc_dev.num_tzma = (uint8_t)(hwcfg >> ETZPC_HWCFGR_NUM_TZMA_SHIFT);
+ etzpc_dev.num_per_sec = (uint8_t)(hwcfg >>
+ ETZPC_HWCFGR_NUM_PER_SEC_SHIFT);
+ etzpc_dev.num_ahb_sec = (uint8_t)(hwcfg >>
+ ETZPC_HWCFGR_NUM_AHB_SEC_SHIFT);
+ etzpc_dev.chunck_size = (uint8_t)(hwcfg >>
+ ETZPC_HWCFGR_CHUNCKS1N4_SHIFT);
+
+ etzpc_dev.revision = mmio_read_8(etzpc_dev.base + ETZPC_VERR);
+
+ VERBOSE("ETZPC version 0x%x", etzpc_dev.revision);
+
+ return 0;
+}
diff --git a/drivers/st/fmc/stm32_fmc2_nand.c b/drivers/st/fmc/stm32_fmc2_nand.c
new file mode 100644
index 0000000..9bdc854
--- /dev/null
+++ b/drivers/st/fmc/stm32_fmc2_nand.c
@@ -0,0 +1,934 @@
+/*
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/raw_nand.h>
+#include <drivers/st/stm32_fmc2_nand.h>
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+/* Timeout for device interface reset */
+#define TIMEOUT_US_1_MS 1000U
+
+/* FMC2 Compatibility */
+#define DT_FMC2_EBI_COMPAT "st,stm32mp1-fmc2-ebi"
+#define DT_FMC2_NFC_COMPAT "st,stm32mp1-fmc2-nfc"
+#define MAX_CS 2U
+#define MAX_BANK 5U
+
+/* FMC2 Controller Registers */
+#define FMC2_BCR1 0x00U
+#define FMC2_PCR 0x80U
+#define FMC2_SR 0x84U
+#define FMC2_PMEM 0x88U
+#define FMC2_PATT 0x8CU
+#define FMC2_HECCR 0x94U
+#define FMC2_BCHISR 0x254U
+#define FMC2_BCHICR 0x258U
+#define FMC2_BCHDSR0 0x27CU
+#define FMC2_BCHDSR1 0x280U
+#define FMC2_BCHDSR2 0x284U
+#define FMC2_BCHDSR3 0x288U
+#define FMC2_BCHDSR4 0x28CU
+
+/* FMC2_BCR1 register */
+#define FMC2_BCR1_FMC2EN BIT(31)
+/* FMC2_PCR register */
+#define FMC2_PCR_PWAITEN BIT(1)
+#define FMC2_PCR_PBKEN BIT(2)
+#define FMC2_PCR_PWID_MASK GENMASK_32(5, 4)
+#define FMC2_PCR_PWID(x) (((x) << 4) & FMC2_PCR_PWID_MASK)
+#define FMC2_PCR_PWID_8 0x0U
+#define FMC2_PCR_PWID_16 0x1U
+#define FMC2_PCR_ECCEN BIT(6)
+#define FMC2_PCR_ECCALG BIT(8)
+#define FMC2_PCR_TCLR_MASK GENMASK_32(12, 9)
+#define FMC2_PCR_TCLR(x) (((x) << 9) & FMC2_PCR_TCLR_MASK)
+#define FMC2_PCR_TCLR_DEFAULT 0xFU
+#define FMC2_PCR_TAR_MASK GENMASK_32(16, 13)
+#define FMC2_PCR_TAR(x) (((x) << 13) & FMC2_PCR_TAR_MASK)
+#define FMC2_PCR_TAR_DEFAULT 0xFU
+#define FMC2_PCR_ECCSS_MASK GENMASK_32(19, 17)
+#define FMC2_PCR_ECCSS(x) (((x) << 17) & FMC2_PCR_ECCSS_MASK)
+#define FMC2_PCR_ECCSS_512 0x1U
+#define FMC2_PCR_ECCSS_2048 0x3U
+#define FMC2_PCR_BCHECC BIT(24)
+#define FMC2_PCR_WEN BIT(25)
+/* FMC2_SR register */
+#define FMC2_SR_NWRF BIT(6)
+/* FMC2_PMEM register*/
+#define FMC2_PMEM_MEMSET(x) (((x) & GENMASK_32(7, 0)) << 0)
+#define FMC2_PMEM_MEMWAIT(x) (((x) & GENMASK_32(7, 0)) << 8)
+#define FMC2_PMEM_MEMHOLD(x) (((x) & GENMASK_32(7, 0)) << 16)
+#define FMC2_PMEM_MEMHIZ(x) (((x) & GENMASK_32(7, 0)) << 24)
+#define FMC2_PMEM_DEFAULT 0x0A0A0A0AU
+/* FMC2_PATT register */
+#define FMC2_PATT_ATTSET(x) (((x) & GENMASK_32(7, 0)) << 0)
+#define FMC2_PATT_ATTWAIT(x) (((x) & GENMASK_32(7, 0)) << 8)
+#define FMC2_PATT_ATTHOLD(x) (((x) & GENMASK_32(7, 0)) << 16)
+#define FMC2_PATT_ATTHIZ(x) (((x) & GENMASK_32(7, 0)) << 24)
+#define FMC2_PATT_DEFAULT 0x0A0A0A0AU
+/* FMC2_BCHISR register */
+#define FMC2_BCHISR_DERF BIT(1)
+/* FMC2_BCHICR register */
+#define FMC2_BCHICR_CLEAR_IRQ GENMASK_32(4, 0)
+/* FMC2_BCHDSR0 register */
+#define FMC2_BCHDSR0_DUE BIT(0)
+#define FMC2_BCHDSR0_DEF BIT(1)
+#define FMC2_BCHDSR0_DEN_MASK GENMASK_32(7, 4)
+#define FMC2_BCHDSR0_DEN_SHIFT 4U
+/* FMC2_BCHDSR1 register */
+#define FMC2_BCHDSR1_EBP1_MASK GENMASK_32(12, 0)
+#define FMC2_BCHDSR1_EBP2_MASK GENMASK_32(28, 16)
+#define FMC2_BCHDSR1_EBP2_SHIFT 16U
+/* FMC2_BCHDSR2 register */
+#define FMC2_BCHDSR2_EBP3_MASK GENMASK_32(12, 0)
+#define FMC2_BCHDSR2_EBP4_MASK GENMASK_32(28, 16)
+#define FMC2_BCHDSR2_EBP4_SHIFT 16U
+/* FMC2_BCHDSR3 register */
+#define FMC2_BCHDSR3_EBP5_MASK GENMASK_32(12, 0)
+#define FMC2_BCHDSR3_EBP6_MASK GENMASK_32(28, 16)
+#define FMC2_BCHDSR3_EBP6_SHIFT 16U
+/* FMC2_BCHDSR4 register */
+#define FMC2_BCHDSR4_EBP7_MASK GENMASK_32(12, 0)
+#define FMC2_BCHDSR4_EBP8_MASK GENMASK_32(28, 16)
+#define FMC2_BCHDSR4_EBP8_SHIFT 16U
+
+/* Timings */
+#define FMC2_THIZ 0x01U
+#define FMC2_TIO 8000U
+#define FMC2_TSYNC 3000U
+#define FMC2_PCR_TIMING_MASK GENMASK_32(3, 0)
+#define FMC2_PMEM_PATT_TIMING_MASK GENMASK_32(7, 0)
+
+#define FMC2_BBM_LEN 2U
+#define FMC2_MAX_ECC_BYTES 14U
+#define TIMEOUT_US_10_MS 10000U
+#define FMC2_PSEC_PER_MSEC (1000UL * 1000UL * 1000UL)
+
+enum stm32_fmc2_ecc {
+ FMC2_ECC_HAM = 1U,
+ FMC2_ECC_BCH4 = 4U,
+ FMC2_ECC_BCH8 = 8U
+};
+
+struct stm32_fmc2_cs_reg {
+ uintptr_t data_base;
+ uintptr_t cmd_base;
+ uintptr_t addr_base;
+};
+
+struct stm32_fmc2_nand_timings {
+ uint8_t tclr;
+ uint8_t tar;
+ uint8_t thiz;
+ uint8_t twait;
+ uint8_t thold_mem;
+ uint8_t tset_mem;
+ uint8_t thold_att;
+ uint8_t tset_att;
+};
+
+struct stm32_fmc2_nfc {
+ uintptr_t reg_base;
+ struct stm32_fmc2_cs_reg cs[MAX_CS];
+ unsigned long clock_id;
+ unsigned int reset_id;
+ uint8_t cs_sel;
+};
+
+static struct stm32_fmc2_nfc stm32_fmc2;
+
+static uintptr_t fmc2_base(void)
+{
+ return stm32_fmc2.reg_base;
+}
+
+static void stm32_fmc2_nand_setup_timing(void)
+{
+ struct stm32_fmc2_nand_timings tims;
+ unsigned long hclk = clk_get_rate(stm32_fmc2.clock_id);
+ unsigned long hclkp = FMC2_PSEC_PER_MSEC / (hclk / 1000U);
+ unsigned long timing, tar, tclr, thiz, twait;
+ unsigned long tset_mem, tset_att, thold_mem, thold_att;
+ uint32_t pcr, pmem, patt;
+
+ tar = MAX(hclkp, NAND_TAR_MIN);
+ timing = div_round_up(tar, hclkp) - 1U;
+ tims.tar = MIN(timing, (unsigned long)FMC2_PCR_TIMING_MASK);
+
+ tclr = MAX(hclkp, NAND_TCLR_MIN);
+ timing = div_round_up(tclr, hclkp) - 1U;
+ tims.tclr = MIN(timing, (unsigned long)FMC2_PCR_TIMING_MASK);
+
+ tims.thiz = FMC2_THIZ;
+ thiz = (tims.thiz + 1U) * hclkp;
+
+ /*
+ * tWAIT > tRP
+ * tWAIT > tWP
+ * tWAIT > tREA + tIO
+ */
+ twait = MAX(hclkp, NAND_TRP_MIN);
+ twait = MAX(twait, NAND_TWP_MIN);
+ twait = MAX(twait, NAND_TREA_MAX + FMC2_TIO);
+ timing = div_round_up(twait, hclkp);
+ tims.twait = CLAMP(timing, 1UL,
+ (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
+
+ /*
+ * tSETUP_MEM > tCS - tWAIT
+ * tSETUP_MEM > tALS - tWAIT
+ * tSETUP_MEM > tDS - (tWAIT - tHIZ)
+ */
+ tset_mem = hclkp;
+ if ((twait < NAND_TCS_MIN) && (tset_mem < (NAND_TCS_MIN - twait))) {
+ tset_mem = NAND_TCS_MIN - twait;
+ }
+ if ((twait > thiz) && ((twait - thiz) < NAND_TDS_MIN) &&
+ (tset_mem < (NAND_TDS_MIN - (twait - thiz)))) {
+ tset_mem = NAND_TDS_MIN - (twait - thiz);
+ }
+ timing = div_round_up(tset_mem, hclkp);
+ tims.tset_mem = CLAMP(timing, 1UL,
+ (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
+
+ /*
+ * tHOLD_MEM > tCH
+ * tHOLD_MEM > tREH - tSETUP_MEM
+ * tHOLD_MEM > max(tRC, tWC) - (tSETUP_MEM + tWAIT)
+ */
+ thold_mem = MAX(hclkp, NAND_TCH_MIN);
+ if ((tset_mem < NAND_TREH_MIN) &&
+ (thold_mem < (NAND_TREH_MIN - tset_mem))) {
+ thold_mem = NAND_TREH_MIN - tset_mem;
+ }
+ if (((tset_mem + twait) < NAND_TRC_MIN) &&
+ (thold_mem < (NAND_TRC_MIN - (tset_mem + twait)))) {
+ thold_mem = NAND_TRC_MIN - (tset_mem + twait);
+ }
+ if (((tset_mem + twait) < NAND_TWC_MIN) &&
+ (thold_mem < (NAND_TWC_MIN - (tset_mem + twait)))) {
+ thold_mem = NAND_TWC_MIN - (tset_mem + twait);
+ }
+ timing = div_round_up(thold_mem, hclkp);
+ tims.thold_mem = CLAMP(timing, 1UL,
+ (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
+
+ /*
+ * tSETUP_ATT > tCS - tWAIT
+ * tSETUP_ATT > tCLS - tWAIT
+ * tSETUP_ATT > tALS - tWAIT
+ * tSETUP_ATT > tRHW - tHOLD_MEM
+ * tSETUP_ATT > tDS - (tWAIT - tHIZ)
+ */
+ tset_att = hclkp;
+ if ((twait < NAND_TCS_MIN) && (tset_att < (NAND_TCS_MIN - twait))) {
+ tset_att = NAND_TCS_MIN - twait;
+ }
+ if ((thold_mem < NAND_TRHW_MIN) &&
+ (tset_att < (NAND_TRHW_MIN - thold_mem))) {
+ tset_att = NAND_TRHW_MIN - thold_mem;
+ }
+ if ((twait > thiz) && ((twait - thiz) < NAND_TDS_MIN) &&
+ (tset_att < (NAND_TDS_MIN - (twait - thiz)))) {
+ tset_att = NAND_TDS_MIN - (twait - thiz);
+ }
+ timing = div_round_up(tset_att, hclkp);
+ tims.tset_att = CLAMP(timing, 1UL,
+ (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
+
+ /*
+ * tHOLD_ATT > tALH
+ * tHOLD_ATT > tCH
+ * tHOLD_ATT > tCLH
+ * tHOLD_ATT > tCOH
+ * tHOLD_ATT > tDH
+ * tHOLD_ATT > tWB + tIO + tSYNC - tSETUP_MEM
+ * tHOLD_ATT > tADL - tSETUP_MEM
+ * tHOLD_ATT > tWH - tSETUP_MEM
+ * tHOLD_ATT > tWHR - tSETUP_MEM
+ * tHOLD_ATT > tRC - (tSETUP_ATT + tWAIT)
+ * tHOLD_ATT > tWC - (tSETUP_ATT + tWAIT)
+ */
+ thold_att = MAX(hclkp, NAND_TALH_MIN);
+ thold_att = MAX(thold_att, NAND_TCH_MIN);
+ thold_att = MAX(thold_att, NAND_TCLH_MIN);
+ thold_att = MAX(thold_att, NAND_TCOH_MIN);
+ thold_att = MAX(thold_att, NAND_TDH_MIN);
+ if (((NAND_TWB_MAX + FMC2_TIO + FMC2_TSYNC) > tset_mem) &&
+ (thold_att < (NAND_TWB_MAX + FMC2_TIO + FMC2_TSYNC - tset_mem))) {
+ thold_att = NAND_TWB_MAX + FMC2_TIO + FMC2_TSYNC - tset_mem;
+ }
+ if ((tset_mem < NAND_TADL_MIN) &&
+ (thold_att < (NAND_TADL_MIN - tset_mem))) {
+ thold_att = NAND_TADL_MIN - tset_mem;
+ }
+ if ((tset_mem < NAND_TWH_MIN) &&
+ (thold_att < (NAND_TWH_MIN - tset_mem))) {
+ thold_att = NAND_TWH_MIN - tset_mem;
+ }
+ if ((tset_mem < NAND_TWHR_MIN) &&
+ (thold_att < (NAND_TWHR_MIN - tset_mem))) {
+ thold_att = NAND_TWHR_MIN - tset_mem;
+ }
+ if (((tset_att + twait) < NAND_TRC_MIN) &&
+ (thold_att < (NAND_TRC_MIN - (tset_att + twait)))) {
+ thold_att = NAND_TRC_MIN - (tset_att + twait);
+ }
+ if (((tset_att + twait) < NAND_TWC_MIN) &&
+ (thold_att < (NAND_TWC_MIN - (tset_att + twait)))) {
+ thold_att = NAND_TWC_MIN - (tset_att + twait);
+ }
+ timing = div_round_up(thold_att, hclkp);
+ tims.thold_att = CLAMP(timing, 1UL,
+ (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
+
+ VERBOSE("NAND timings: %u - %u - %u - %u - %u - %u - %u - %u\n",
+ tims.tclr, tims.tar, tims.thiz, tims.twait,
+ tims.thold_mem, tims.tset_mem,
+ tims.thold_att, tims.tset_att);
+
+ /* Set tclr/tar timings */
+ pcr = mmio_read_32(fmc2_base() + FMC2_PCR);
+ pcr &= ~FMC2_PCR_TCLR_MASK;
+ pcr |= FMC2_PCR_TCLR(tims.tclr);
+ pcr &= ~FMC2_PCR_TAR_MASK;
+ pcr |= FMC2_PCR_TAR(tims.tar);
+
+ /* Set tset/twait/thold/thiz timings in common bank */
+ pmem = FMC2_PMEM_MEMSET(tims.tset_mem);
+ pmem |= FMC2_PMEM_MEMWAIT(tims.twait);
+ pmem |= FMC2_PMEM_MEMHOLD(tims.thold_mem);
+ pmem |= FMC2_PMEM_MEMHIZ(tims.thiz);
+
+ /* Set tset/twait/thold/thiz timings in attribute bank */
+ patt = FMC2_PATT_ATTSET(tims.tset_att);
+ patt |= FMC2_PATT_ATTWAIT(tims.twait);
+ patt |= FMC2_PATT_ATTHOLD(tims.thold_att);
+ patt |= FMC2_PATT_ATTHIZ(tims.thiz);
+
+ mmio_write_32(fmc2_base() + FMC2_PCR, pcr);
+ mmio_write_32(fmc2_base() + FMC2_PMEM, pmem);
+ mmio_write_32(fmc2_base() + FMC2_PATT, patt);
+}
+
+static void stm32_fmc2_set_buswidth_16(bool set)
+{
+ mmio_clrsetbits_32(fmc2_base() + FMC2_PCR, FMC2_PCR_PWID_MASK,
+ (set ? FMC2_PCR_PWID(FMC2_PCR_PWID_16) : 0U));
+}
+
+static void stm32_fmc2_set_ecc(bool enable)
+{
+ mmio_clrsetbits_32(fmc2_base() + FMC2_PCR, FMC2_PCR_ECCEN,
+ (enable ? FMC2_PCR_ECCEN : 0U));
+}
+
+static int stm32_fmc2_ham_correct(uint8_t *buffer, uint8_t *eccbuffer,
+ uint8_t *ecc)
+{
+ uint8_t xor_ecc_ones;
+ uint16_t xor_ecc_1b, xor_ecc_2b, xor_ecc_3b;
+ union {
+ uint32_t val;
+ uint8_t bytes[4];
+ } xor_ecc;
+
+ /* Page size--------ECC_Code Size
+ * 256---------------22 bits LSB (ECC_CODE & 0x003FFFFF)
+ * 512---------------24 bits (ECC_CODE & 0x00FFFFFF)
+ * 1024--------------26 bits (ECC_CODE & 0x03FFFFFF)
+ * 2048--------------28 bits (ECC_CODE & 0x0FFFFFFF)
+ * 4096--------------30 bits (ECC_CODE & 0x3FFFFFFF)
+ * 8192--------------32 bits (ECC_CODE & 0xFFFFFFFF)
+ */
+
+ /* For Page size 512, ECC_Code size 24 bits */
+ xor_ecc_1b = ecc[0] ^ eccbuffer[0];
+ xor_ecc_2b = ecc[1] ^ eccbuffer[1];
+ xor_ecc_3b = ecc[2] ^ eccbuffer[2];
+
+ xor_ecc.val = 0U;
+ xor_ecc.bytes[2] = xor_ecc_3b;
+ xor_ecc.bytes[1] = xor_ecc_2b;
+ xor_ecc.bytes[0] = xor_ecc_1b;
+
+ if (xor_ecc.val == 0U) {
+ return 0; /* No Error */
+ }
+
+ xor_ecc_ones = __builtin_popcount(xor_ecc.val);
+ if (xor_ecc_ones < 23U) {
+ if (xor_ecc_ones == 12U) {
+ uint16_t bit_address, byte_address;
+
+ /* Correctable ERROR */
+ bit_address = ((xor_ecc_1b >> 1) & BIT(0)) |
+ ((xor_ecc_1b >> 2) & BIT(1)) |
+ ((xor_ecc_1b >> 3) & BIT(2));
+
+ byte_address = ((xor_ecc_1b >> 7) & BIT(0)) |
+ ((xor_ecc_2b) & BIT(1)) |
+ ((xor_ecc_2b >> 1) & BIT(2)) |
+ ((xor_ecc_2b >> 2) & BIT(3)) |
+ ((xor_ecc_2b >> 3) & BIT(4)) |
+ ((xor_ecc_3b << 4) & BIT(5)) |
+ ((xor_ecc_3b << 3) & BIT(6)) |
+ ((xor_ecc_3b << 2) & BIT(7)) |
+ ((xor_ecc_3b << 1) & BIT(8));
+
+ /* Correct bit error in the data */
+ buffer[byte_address] =
+ buffer[byte_address] ^ BIT(bit_address);
+ VERBOSE("Hamming: 1 ECC error corrected\n");
+
+ return 0;
+ }
+
+ /* Non Correctable ERROR */
+ ERROR("%s: Uncorrectable ECC Errors\n", __func__);
+ return -1;
+ }
+
+ /* ECC ERROR */
+ ERROR("%s: Hamming correction error\n", __func__);
+ return -1;
+}
+
+
+static int stm32_fmc2_ham_calculate(uint8_t *buffer, uint8_t *ecc)
+{
+ uint32_t heccr;
+ uint64_t timeout = timeout_init_us(TIMEOUT_US_10_MS);
+
+ while ((mmio_read_32(fmc2_base() + FMC2_SR) & FMC2_SR_NWRF) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ return -ETIMEDOUT;
+ }
+ }
+
+ heccr = mmio_read_32(fmc2_base() + FMC2_HECCR);
+
+ ecc[0] = heccr;
+ ecc[1] = heccr >> 8;
+ ecc[2] = heccr >> 16;
+
+ /* Disable ECC */
+ stm32_fmc2_set_ecc(false);
+
+ return 0;
+}
+
+static int stm32_fmc2_bch_correct(uint8_t *buffer, unsigned int eccsize)
+{
+ uint32_t bchdsr0, bchdsr1, bchdsr2, bchdsr3, bchdsr4;
+ uint16_t pos[8];
+ int i, den;
+ uint64_t timeout = timeout_init_us(TIMEOUT_US_10_MS);
+
+ while ((mmio_read_32(fmc2_base() + FMC2_BCHISR) &
+ FMC2_BCHISR_DERF) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ return -ETIMEDOUT;
+ }
+ }
+
+ bchdsr0 = mmio_read_32(fmc2_base() + FMC2_BCHDSR0);
+ bchdsr1 = mmio_read_32(fmc2_base() + FMC2_BCHDSR1);
+ bchdsr2 = mmio_read_32(fmc2_base() + FMC2_BCHDSR2);
+ bchdsr3 = mmio_read_32(fmc2_base() + FMC2_BCHDSR3);
+ bchdsr4 = mmio_read_32(fmc2_base() + FMC2_BCHDSR4);
+
+ /* Disable ECC */
+ stm32_fmc2_set_ecc(false);
+
+ /* No error found */
+ if ((bchdsr0 & FMC2_BCHDSR0_DEF) == 0U) {
+ return 0;
+ }
+
+ /* Too many errors detected */
+ if ((bchdsr0 & FMC2_BCHDSR0_DUE) != 0U) {
+ return -EBADMSG;
+ }
+
+ pos[0] = bchdsr1 & FMC2_BCHDSR1_EBP1_MASK;
+ pos[1] = (bchdsr1 & FMC2_BCHDSR1_EBP2_MASK) >> FMC2_BCHDSR1_EBP2_SHIFT;
+ pos[2] = bchdsr2 & FMC2_BCHDSR2_EBP3_MASK;
+ pos[3] = (bchdsr2 & FMC2_BCHDSR2_EBP4_MASK) >> FMC2_BCHDSR2_EBP4_SHIFT;
+ pos[4] = bchdsr3 & FMC2_BCHDSR3_EBP5_MASK;
+ pos[5] = (bchdsr3 & FMC2_BCHDSR3_EBP6_MASK) >> FMC2_BCHDSR3_EBP6_SHIFT;
+ pos[6] = bchdsr4 & FMC2_BCHDSR4_EBP7_MASK;
+ pos[7] = (bchdsr4 & FMC2_BCHDSR4_EBP8_MASK) >> FMC2_BCHDSR4_EBP8_SHIFT;
+
+ den = (bchdsr0 & FMC2_BCHDSR0_DEN_MASK) >> FMC2_BCHDSR0_DEN_SHIFT;
+ for (i = 0; i < den; i++) {
+ if (pos[i] < (eccsize * 8U)) {
+ uint8_t bitmask = BIT(pos[i] % 8U);
+ uint32_t offset = pos[i] / 8U;
+
+ *(buffer + offset) ^= bitmask;
+ }
+ }
+
+ return 0;
+}
+
+static void stm32_fmc2_hwctl(struct nand_device *nand)
+{
+ stm32_fmc2_set_ecc(false);
+
+ if (nand->ecc.max_bit_corr != FMC2_ECC_HAM) {
+ mmio_clrbits_32(fmc2_base() + FMC2_PCR, FMC2_PCR_WEN);
+ mmio_write_32(fmc2_base() + FMC2_BCHICR, FMC2_BCHICR_CLEAR_IRQ);
+ }
+
+ stm32_fmc2_set_ecc(true);
+}
+
+static int stm32_fmc2_read_page(struct nand_device *nand,
+ unsigned int page, uintptr_t buffer)
+{
+ unsigned int eccsize = nand->ecc.size;
+ unsigned int eccbytes = nand->ecc.bytes;
+ unsigned int eccsteps = nand->page_size / eccsize;
+ uint8_t ecc_corr[FMC2_MAX_ECC_BYTES];
+ uint8_t ecc_cal[FMC2_MAX_ECC_BYTES] = {0U};
+ uint8_t *p;
+ unsigned int i;
+ unsigned int s;
+ int ret;
+
+ VERBOSE(">%s page %u buffer %lx\n", __func__, page, buffer);
+
+ ret = nand_read_page_cmd(page, 0U, 0U, 0U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ for (s = 0U, i = nand->page_size + FMC2_BBM_LEN, p = (uint8_t *)buffer;
+ s < eccsteps;
+ s++, i += eccbytes, p += eccsize) {
+ stm32_fmc2_hwctl(nand);
+
+ /* Read the NAND page sector (512 bytes) */
+ ret = nand_change_read_column_cmd(s * eccsize, (uintptr_t)p,
+ eccsize);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (nand->ecc.max_bit_corr == FMC2_ECC_HAM) {
+ ret = stm32_fmc2_ham_calculate(p, ecc_cal);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ /* Read the corresponding ECC bytes */
+ ret = nand_change_read_column_cmd(i, (uintptr_t)ecc_corr,
+ eccbytes);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Correct the data */
+ if (nand->ecc.max_bit_corr == FMC2_ECC_HAM) {
+ ret = stm32_fmc2_ham_correct(p, ecc_corr, ecc_cal);
+ } else {
+ ret = stm32_fmc2_bch_correct(p, eccsize);
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void stm32_fmc2_read_data(struct nand_device *nand,
+ uint8_t *buff, unsigned int length,
+ bool use_bus8)
+{
+ uintptr_t data_base = stm32_fmc2.cs[stm32_fmc2.cs_sel].data_base;
+
+ if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
+ stm32_fmc2_set_buswidth_16(false);
+ }
+
+ if ((((uintptr_t)buff & BIT(0)) != 0U) && (length != 0U)) {
+ *buff = mmio_read_8(data_base);
+ buff += sizeof(uint8_t);
+ length -= sizeof(uint8_t);
+ }
+
+ if ((((uintptr_t)buff & GENMASK_32(1, 0)) != 0U) &&
+ (length >= sizeof(uint16_t))) {
+ *(uint16_t *)buff = mmio_read_16(data_base);
+ buff += sizeof(uint16_t);
+ length -= sizeof(uint16_t);
+ }
+
+ /* 32bit aligned */
+ while (length >= sizeof(uint32_t)) {
+ *(uint32_t *)buff = mmio_read_32(data_base);
+ buff += sizeof(uint32_t);
+ length -= sizeof(uint32_t);
+ }
+
+ /* Read remaining bytes */
+ if (length >= sizeof(uint16_t)) {
+ *(uint16_t *)buff = mmio_read_16(data_base);
+ buff += sizeof(uint16_t);
+ length -= sizeof(uint16_t);
+ }
+
+ if (length != 0U) {
+ *buff = mmio_read_8(data_base);
+ }
+
+ if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
+ /* Reconfigure bus width to 16-bit */
+ stm32_fmc2_set_buswidth_16(true);
+ }
+}
+
+static void stm32_fmc2_write_data(struct nand_device *nand,
+ uint8_t *buff, unsigned int length,
+ bool use_bus8)
+{
+ uintptr_t data_base = stm32_fmc2.cs[stm32_fmc2.cs_sel].data_base;
+
+ if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
+ /* Reconfigure bus width to 8-bit */
+ stm32_fmc2_set_buswidth_16(false);
+ }
+
+ if ((((uintptr_t)buff & BIT(0)) != 0U) && (length != 0U)) {
+ mmio_write_8(data_base, *buff);
+ buff += sizeof(uint8_t);
+ length -= sizeof(uint8_t);
+ }
+
+ if ((((uintptr_t)buff & GENMASK_32(1, 0)) != 0U) &&
+ (length >= sizeof(uint16_t))) {
+ mmio_write_16(data_base, *(uint16_t *)buff);
+ buff += sizeof(uint16_t);
+ length -= sizeof(uint16_t);
+ }
+
+ /* 32bits aligned */
+ while (length >= sizeof(uint32_t)) {
+ mmio_write_32(data_base, *(uint32_t *)buff);
+ buff += sizeof(uint32_t);
+ length -= sizeof(uint32_t);
+ }
+
+ /* Read remaining bytes */
+ if (length >= sizeof(uint16_t)) {
+ mmio_write_16(data_base, *(uint16_t *)buff);
+ buff += sizeof(uint16_t);
+ length -= sizeof(uint16_t);
+ }
+
+ if (length != 0U) {
+ mmio_write_8(data_base, *buff);
+ }
+
+ if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
+ /* Reconfigure bus width to 16-bit */
+ stm32_fmc2_set_buswidth_16(true);
+ }
+}
+
+static void stm32_fmc2_ctrl_init(void)
+{
+ uint32_t pcr = mmio_read_32(fmc2_base() + FMC2_PCR);
+ uint32_t bcr1 = mmio_read_32(fmc2_base() + FMC2_BCR1);
+
+ /* Enable wait feature and NAND flash memory bank */
+ pcr |= FMC2_PCR_PWAITEN;
+ pcr |= FMC2_PCR_PBKEN;
+
+ /* Set buswidth to 8 bits mode for identification */
+ pcr &= ~FMC2_PCR_PWID_MASK;
+
+ /* ECC logic is disabled */
+ pcr &= ~FMC2_PCR_ECCEN;
+
+ /* Default mode */
+ pcr &= ~FMC2_PCR_ECCALG;
+ pcr &= ~FMC2_PCR_BCHECC;
+ pcr &= ~FMC2_PCR_WEN;
+
+ /* Set default ECC sector size */
+ pcr &= ~FMC2_PCR_ECCSS_MASK;
+ pcr |= FMC2_PCR_ECCSS(FMC2_PCR_ECCSS_2048);
+
+ /* Set default TCLR/TAR timings */
+ pcr &= ~FMC2_PCR_TCLR_MASK;
+ pcr |= FMC2_PCR_TCLR(FMC2_PCR_TCLR_DEFAULT);
+ pcr &= ~FMC2_PCR_TAR_MASK;
+ pcr |= FMC2_PCR_TAR(FMC2_PCR_TAR_DEFAULT);
+
+ /* Enable FMC2 controller */
+ bcr1 |= FMC2_BCR1_FMC2EN;
+
+ mmio_write_32(fmc2_base() + FMC2_BCR1, bcr1);
+ mmio_write_32(fmc2_base() + FMC2_PCR, pcr);
+ mmio_write_32(fmc2_base() + FMC2_PMEM, FMC2_PMEM_DEFAULT);
+ mmio_write_32(fmc2_base() + FMC2_PATT, FMC2_PATT_DEFAULT);
+}
+
+static int stm32_fmc2_exec(struct nand_req *req)
+{
+ int ret = 0;
+
+ switch (req->type & NAND_REQ_MASK) {
+ case NAND_REQ_CMD:
+ VERBOSE("Write CMD %x\n", (uint8_t)req->type);
+ mmio_write_8(stm32_fmc2.cs[stm32_fmc2.cs_sel].cmd_base,
+ (uint8_t)req->type);
+ break;
+ case NAND_REQ_ADDR:
+ VERBOSE("Write ADDR %x\n", *(req->addr));
+ mmio_write_8(stm32_fmc2.cs[stm32_fmc2.cs_sel].addr_base,
+ *(req->addr));
+ break;
+ case NAND_REQ_DATAIN:
+ VERBOSE("Read data\n");
+ stm32_fmc2_read_data(req->nand, req->addr, req->length,
+ ((req->type & NAND_REQ_BUS_WIDTH_8) !=
+ 0U));
+ break;
+ case NAND_REQ_DATAOUT:
+ VERBOSE("Write data\n");
+ stm32_fmc2_write_data(req->nand, req->addr, req->length,
+ ((req->type & NAND_REQ_BUS_WIDTH_8) !=
+ 0U));
+ break;
+ case NAND_REQ_WAIT:
+ VERBOSE("WAIT Ready\n");
+ ret = nand_wait_ready(req->delay_ms);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ };
+
+ return ret;
+}
+
+static void stm32_fmc2_setup(struct nand_device *nand)
+{
+ uint32_t pcr = mmio_read_32(fmc2_base() + FMC2_PCR);
+
+ /* Set buswidth */
+ pcr &= ~FMC2_PCR_PWID_MASK;
+ if (nand->buswidth == NAND_BUS_WIDTH_16) {
+ pcr |= FMC2_PCR_PWID(FMC2_PCR_PWID_16);
+ }
+
+ if (nand->ecc.mode == NAND_ECC_HW) {
+ nand->mtd_read_page = stm32_fmc2_read_page;
+
+ pcr &= ~FMC2_PCR_ECCALG;
+ pcr &= ~FMC2_PCR_BCHECC;
+
+ pcr &= ~FMC2_PCR_ECCSS_MASK;
+ pcr |= FMC2_PCR_ECCSS(FMC2_PCR_ECCSS_512);
+
+ switch (nand->ecc.max_bit_corr) {
+ case FMC2_ECC_HAM:
+ nand->ecc.bytes = 3;
+ break;
+ case FMC2_ECC_BCH8:
+ pcr |= FMC2_PCR_ECCALG;
+ pcr |= FMC2_PCR_BCHECC;
+ nand->ecc.bytes = 13;
+ break;
+ default:
+ /* Use FMC2 ECC BCH4 */
+ pcr |= FMC2_PCR_ECCALG;
+ nand->ecc.bytes = 7;
+ break;
+ }
+
+ if ((nand->buswidth & NAND_BUS_WIDTH_16) != 0) {
+ nand->ecc.bytes++;
+ }
+ }
+
+ mmio_write_32(stm32_fmc2.reg_base + FMC2_PCR, pcr);
+}
+
+static const struct nand_ctrl_ops ctrl_ops = {
+ .setup = stm32_fmc2_setup,
+ .exec = stm32_fmc2_exec
+};
+
+int stm32_fmc2_init(void)
+{
+ int fmc_ebi_node;
+ int fmc_nfc_node;
+ int fmc_flash_node = 0;
+ int nchips = 0;
+ unsigned int i;
+ void *fdt = NULL;
+ const fdt32_t *cuint;
+ struct dt_node_info info;
+ uintptr_t bank_address[MAX_BANK] = { 0, 0, 0, 0, 0 };
+ uint8_t bank_assigned = 0;
+ uint8_t bank;
+ int ret;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ fmc_ebi_node = dt_get_node(&info, -1, DT_FMC2_EBI_COMPAT);
+ if (fmc_ebi_node < 0) {
+ return fmc_ebi_node;
+ }
+
+ if (info.status == DT_DISABLED) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ stm32_fmc2.reg_base = info.base;
+
+ if ((info.clock < 0) || (info.reset < 0)) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ stm32_fmc2.clock_id = (unsigned long)info.clock;
+ stm32_fmc2.reset_id = (unsigned int)info.reset;
+
+ cuint = fdt_getprop(fdt, fmc_ebi_node, "ranges", NULL);
+ if (cuint == NULL) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ for (i = 0U; i < MAX_BANK; i++) {
+ bank = fdt32_to_cpu(*cuint);
+ if ((bank >= MAX_BANK) || ((bank_assigned & BIT(bank)) != 0U)) {
+ return -FDT_ERR_BADVALUE;
+ }
+ bank_assigned |= BIT(bank);
+ bank_address[bank] = fdt32_to_cpu(*(cuint + 2));
+ cuint += 4;
+ }
+
+ /* Pinctrl initialization */
+ if (dt_set_pinctrl_config(fmc_ebi_node) != 0) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ /* Parse NFC controller node */
+ fmc_nfc_node = fdt_node_offset_by_compatible(fdt, fmc_ebi_node,
+ DT_FMC2_NFC_COMPAT);
+ if (fmc_nfc_node < 0) {
+ return fmc_nfc_node;
+ }
+
+ if (fdt_get_status(fmc_nfc_node) == DT_DISABLED) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ cuint = fdt_getprop(fdt, fmc_nfc_node, "reg", NULL);
+ if (cuint == NULL) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ for (i = 0U; i < MAX_CS; i++) {
+ bank = fdt32_to_cpu(*cuint);
+ if (bank >= MAX_BANK) {
+ return -FDT_ERR_BADVALUE;
+ }
+ stm32_fmc2.cs[i].data_base = fdt32_to_cpu(*(cuint + 1)) +
+ bank_address[bank];
+
+ bank = fdt32_to_cpu(*(cuint + 3));
+ if (bank >= MAX_BANK) {
+ return -FDT_ERR_BADVALUE;
+ }
+ stm32_fmc2.cs[i].cmd_base = fdt32_to_cpu(*(cuint + 4)) +
+ bank_address[bank];
+
+ bank = fdt32_to_cpu(*(cuint + 6));
+ if (bank >= MAX_BANK) {
+ return -FDT_ERR_BADVALUE;
+ }
+ stm32_fmc2.cs[i].addr_base = fdt32_to_cpu(*(cuint + 7)) +
+ bank_address[bank];
+
+ cuint += 9;
+ }
+
+ /* Parse flash nodes */
+ fdt_for_each_subnode(fmc_flash_node, fdt, fmc_nfc_node) {
+ nchips++;
+ }
+
+ if (nchips != 1) {
+ WARN("Only one SLC NAND device supported\n");
+ return -FDT_ERR_BADVALUE;
+ }
+
+ fdt_for_each_subnode(fmc_flash_node, fdt, fmc_nfc_node) {
+ /* Get chip select */
+ cuint = fdt_getprop(fdt, fmc_flash_node, "reg", NULL);
+ if (cuint == NULL) {
+ WARN("Chip select not well defined\n");
+ return -FDT_ERR_BADVALUE;
+ }
+
+ stm32_fmc2.cs_sel = fdt32_to_cpu(*cuint);
+ if (stm32_fmc2.cs_sel >= MAX_CS) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ VERBOSE("NAND CS %i\n", stm32_fmc2.cs_sel);
+ }
+
+ /* Enable Clock */
+ clk_enable(stm32_fmc2.clock_id);
+
+ /* Reset IP */
+ ret = stm32mp_reset_assert(stm32_fmc2.reset_id, TIMEOUT_US_1_MS);
+ if (ret != 0) {
+ panic();
+ }
+ ret = stm32mp_reset_deassert(stm32_fmc2.reset_id, TIMEOUT_US_1_MS);
+ if (ret != 0) {
+ panic();
+ }
+
+ /* Setup default IP registers */
+ stm32_fmc2_ctrl_init();
+
+ /* Setup default timings */
+ stm32_fmc2_nand_setup_timing();
+
+ /* Init NAND RAW framework */
+ nand_raw_ctrl_init(&ctrl_ops);
+
+ return 0;
+}
diff --git a/drivers/st/gpio/stm32_gpio.c b/drivers/st/gpio/stm32_gpio.c
new file mode 100644
index 0000000..708989f
--- /dev/null
+++ b/drivers/st/gpio/stm32_gpio.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2016-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/clk.h>
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#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)
+
+static void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t type,
+ uint32_t speed, uint32_t pull, uint32_t od,
+ uint32_t alternate, uint8_t status);
+
+/*******************************************************************************
+ * 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);
+ uint32_t type;
+ uint32_t od = GPIO_OD_OUTPUT_LOW;
+ 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) {
+ type = GPIO_TYPE_OPEN_DRAIN;
+ } else {
+ type = GPIO_TYPE_PUSH_PULL;
+ }
+
+ if (fdt_getprop(fdt, node, "output-high", NULL) != NULL) {
+ if (mode == GPIO_MODE_INPUT) {
+ mode = GPIO_MODE_OUTPUT;
+ od = GPIO_OD_OUTPUT_HIGH;
+ }
+ }
+
+ if (fdt_getprop(fdt, node, "output-low", NULL) != NULL) {
+ if (mode == GPIO_MODE_INPUT) {
+ mode = GPIO_MODE_OUTPUT;
+ od = GPIO_OD_OUTPUT_LOW;
+ }
+ }
+
+ 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, type, speed, pull, od, 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;
+ uint32_t i;
+ uint8_t status;
+ void *fdt;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ status = fdt_get_status(node);
+ 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;
+}
+
+static void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t type,
+ uint32_t speed, uint32_t pull, uint32_t od,
+ 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);
+
+ clk_enable(clock);
+
+ mmio_clrsetbits_32(base + GPIO_MODE_OFFSET,
+ (uint32_t)GPIO_MODE_MASK << (pin << 1),
+ mode << (pin << 1));
+
+ mmio_clrsetbits_32(base + GPIO_TYPE_OFFSET,
+ (uint32_t)GPIO_TYPE_MASK << pin,
+ type << pin);
+
+ mmio_clrsetbits_32(base + GPIO_SPEED_OFFSET,
+ (uint32_t)GPIO_SPEED_MASK << (pin << 1),
+ speed << (pin << 1));
+
+ mmio_clrsetbits_32(base + GPIO_PUPD_OFFSET,
+ (uint32_t)GPIO_PULL_MASK << (pin << 1),
+ pull << (pin << 1));
+
+ if (pin < GPIO_ALT_LOWER_LIMIT) {
+ mmio_clrsetbits_32(base + GPIO_AFRL_OFFSET,
+ (uint32_t)GPIO_ALTERNATE_MASK << (pin << 2),
+ alternate << (pin << 2));
+ } else {
+ size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2;
+
+ mmio_clrsetbits_32(base + GPIO_AFRH_OFFSET,
+ (uint32_t)GPIO_ALTERNATE_MASK << shift,
+ alternate << shift);
+ }
+
+ mmio_clrsetbits_32(base + GPIO_OD_OFFSET,
+ (uint32_t)GPIO_OD_MASK << pin,
+ od << pin);
+
+ VERBOSE("GPIO %u mode set to 0x%x\n", bank,
+ mmio_read_32(base + GPIO_MODE_OFFSET));
+ VERBOSE("GPIO %u type set to 0x%x\n", bank,
+ mmio_read_32(base + GPIO_TYPE_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));
+ VERBOSE("GPIO %u output data set to 0x%x\n", bank,
+ mmio_read_32(base + GPIO_OD_OFFSET));
+
+ clk_disable(clock);
+
+ if (status == DT_SECURE) {
+ stm32mp_register_secure_gpio(bank, pin);
+#if !IMAGE_BL2
+ set_gpio_secure_cfg(bank, pin, true);
+#endif
+
+ } else {
+ stm32mp_register_non_secure_gpio(bank, pin);
+#if !IMAGE_BL2
+ set_gpio_secure_cfg(bank, pin, false);
+#endif
+ }
+}
+
+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);
+
+ clk_enable(clock);
+
+ if (secure) {
+ mmio_setbits_32(base + GPIO_SECR_OFFSET, BIT(pin));
+ } else {
+ mmio_clrbits_32(base + GPIO_SECR_OFFSET, BIT(pin));
+ }
+
+ clk_disable(clock);
+}
+
+void set_gpio_reset_cfg(uint32_t bank, uint32_t pin)
+{
+ set_gpio(bank, pin, GPIO_MODE_ANALOG, GPIO_TYPE_PUSH_PULL,
+ GPIO_SPEED_LOW, GPIO_NO_PULL, GPIO_OD_OUTPUT_LOW,
+ GPIO_ALTERNATE_(0), DT_DISABLED);
+ set_gpio_secure_cfg(bank, pin, stm32_gpio_is_secure_at_reset(bank));
+}
diff --git a/drivers/st/i2c/stm32_i2c.c b/drivers/st/i2c/stm32_i2c.c
new file mode 100644
index 0000000..bf6c3ee
--- /dev/null
+++ b/drivers/st/i2c/stm32_i2c.c
@@ -0,0 +1,982 @@
+/*
+ * Copyright (c) 2016-2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32_i2c.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+
+/* STM32 I2C registers offsets */
+#define I2C_CR1 0x00U
+#define I2C_CR2 0x04U
+#define I2C_OAR1 0x08U
+#define I2C_OAR2 0x0CU
+#define I2C_TIMINGR 0x10U
+#define I2C_TIMEOUTR 0x14U
+#define I2C_ISR 0x18U
+#define I2C_ICR 0x1CU
+#define I2C_PECR 0x20U
+#define I2C_RXDR 0x24U
+#define I2C_TXDR 0x28U
+
+#define TIMINGR_CLEAR_MASK 0xF0FFFFFFU
+
+#define MAX_NBYTE_SIZE 255U
+
+#define I2C_NSEC_PER_SEC 1000000000L
+
+/* 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;
+
+ 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);
+ clk_disable(hi2c->clock);
+ return rc;
+ }
+
+ 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;
+ }
+
+ 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;
+ 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;
+ }
+
+ 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;
+ 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;
+ }
+
+ 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;
+ clk_disable(hi2c->clock);
+
+ return rc;
+}
+
diff --git a/drivers/st/io/io_mmc.c b/drivers/st/io/io_mmc.c
new file mode 100644
index 0000000..2bf88e6
--- /dev/null
+++ b/drivers/st/io/io_mmc.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/mmc.h>
+#include <drivers/st/io_mmc.h>
+#include <drivers/st/stm32_sdmmc2.h>
+
+/* SDMMC device functions */
+static int mmc_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info);
+static int mmc_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
+ io_entity_t *entity);
+static int mmc_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params);
+static int mmc_block_seek(io_entity_t *entity, int mode,
+ signed long long offset);
+static int mmc_block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+ size_t *length_read);
+static int mmc_block_close(io_entity_t *entity);
+static int mmc_dev_close(io_dev_info_t *dev_info);
+static io_type_t device_type_mmc(void);
+
+static signed long long seek_offset;
+static size_t (*_read_blocks)(int lba, uintptr_t buf, size_t size);
+
+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)
+{
+ struct io_mmc_dev_spec *device_spec =
+ (struct io_mmc_dev_spec *)init_params;
+
+ assert(dev_info != NULL);
+ *dev_info = (io_dev_info_t *)&mmc_dev_info;
+
+ _read_blocks = !device_spec->use_boot_part ?
+ mmc_read_blocks : mmc_boot_part_read_blocks;
+
+ return 0;
+}
+
+static int mmc_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params)
+{
+ return 0;
+}
+
+/* Close a connection to the mmc device */
+static int mmc_dev_close(io_dev_info_t *dev_info)
+{
+ return 0;
+}
+
+/* Open a file on the mmc device */
+static int mmc_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
+ io_entity_t *entity)
+{
+ seek_offset = 0;
+ return 0;
+}
+
+/* Seek to a particular file offset on the mmc device */
+static int mmc_block_seek(io_entity_t *entity, int mode,
+ signed long long offset)
+{
+ seek_offset = offset;
+ return 0;
+}
+
+/* Read data from a file on the mmc device */
+static int mmc_block_read(io_entity_t *entity, uintptr_t buffer,
+ size_t length, size_t *length_read)
+{
+ uint8_t retries;
+
+ for (retries = 0U; retries < 3U; retries++) {
+ *length_read = _read_blocks(seek_offset / MMC_BLOCK_SIZE,
+ buffer, length);
+
+ if (*length_read == length) {
+ return 0;
+ }
+ WARN("%s: length_read = %lu (!= %lu), retry %u\n", __func__,
+ (unsigned long)*length_read, (unsigned long)length,
+ retries + 1U);
+ }
+
+ return -EIO;
+}
+
+/* Close a file on the mmc device */
+static int mmc_block_close(io_entity_t *entity)
+{
+ return 0;
+}
+
+/* Register the mmc driver with the IO abstraction */
+int register_io_dev_mmc(const io_dev_connector_t **dev_con)
+{
+ int result;
+
+ assert(dev_con != NULL);
+
+ result = io_register_device(&mmc_dev_info);
+ if (result == 0) {
+ *dev_con = &mmc_dev_connector;
+ }
+
+ return result;
+}
diff --git a/drivers/st/iwdg/stm32_iwdg.c b/drivers/st/iwdg/stm32_iwdg.c
new file mode 100644
index 0000000..74451d7
--- /dev/null
+++ b/drivers/st/iwdg/stm32_iwdg.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_iwdg.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+/* 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) {
+ clk_enable(iwdg->clock);
+
+ mmio_write_32(iwdg->base + IWDG_KR_OFFSET,
+ IWDG_KR_RELOAD_KEY);
+
+ 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 ((dt_info.status & DT_NON_SECURE) != 0) {
+ stm32mp_register_non_secure_periph_iomem(iwdg->base);
+ } else {
+ stm32mp_register_secure_periph_iomem(iwdg->base);
+ }
+
+#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;
+}
diff --git a/drivers/st/mmc/stm32_sdmmc2.c b/drivers/st/mmc/stm32_sdmmc2.c
new file mode 100644
index 0000000..6bdd782
--- /dev/null
+++ b/drivers/st/mmc/stm32_sdmmc2.c
@@ -0,0 +1,798 @@
+/*
+ * Copyright (c) 2018-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/mmc.h>
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32_sdmmc2.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <libfdt.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+/* Registers offsets */
+#define SDMMC_POWER 0x00U
+#define SDMMC_CLKCR 0x04U
+#define SDMMC_ARGR 0x08U
+#define SDMMC_CMDR 0x0CU
+#define SDMMC_RESPCMDR 0x10U
+#define SDMMC_RESP1R 0x14U
+#define SDMMC_RESP2R 0x18U
+#define SDMMC_RESP3R 0x1CU
+#define SDMMC_RESP4R 0x20U
+#define SDMMC_DTIMER 0x24U
+#define SDMMC_DLENR 0x28U
+#define SDMMC_DCTRLR 0x2CU
+#define SDMMC_DCNTR 0x30U
+#define SDMMC_STAR 0x34U
+#define SDMMC_ICR 0x38U
+#define SDMMC_MASKR 0x3CU
+#define SDMMC_ACKTIMER 0x40U
+#define SDMMC_IDMACTRLR 0x50U
+#define SDMMC_IDMABSIZER 0x54U
+#define SDMMC_IDMABASE0R 0x58U
+#define SDMMC_IDMABASE1R 0x5CU
+#define SDMMC_FIFOR 0x80U
+
+/* SDMMC power control register */
+#define SDMMC_POWER_PWRCTRL GENMASK(1, 0)
+#define SDMMC_POWER_PWRCTRL_PWR_CYCLE BIT(1)
+#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_1_MS 1000U
+#define TIMEOUT_US_10_MS 10000U
+#define TIMEOUT_US_1_S 1000000U
+
+/* Power cycle delays in ms */
+#define VCC_POWER_OFF_DELAY 2
+#define VCC_POWER_ON_DELAY 2
+#define POWER_CYCLE_DELAY 2
+#define POWER_OFF_DELAY 2
+#define POWER_ON_DELAY 1
+
+#ifndef DT_SDMMC2_COMPAT
+#define DT_SDMMC2_COMPAT "st,stm32-sdmmc2"
+#endif
+
+#define SDMMC_FIFO_SIZE 64U
+
+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;
+
+static bool next_cmd_is_acmd;
+
+#pragma weak plat_sdmmc2_use_dma
+bool plat_sdmmc2_use_dma(unsigned int instance, unsigned int memory)
+{
+ return false;
+}
+
+static void stm32_sdmmc2_init(void)
+{
+ uint32_t clock_div;
+ uint32_t freq = STM32MP_MMC_INIT_FREQ;
+ uintptr_t base = sdmmc2_params.reg_base;
+ int ret;
+
+ if (sdmmc2_params.max_freq != 0U) {
+ freq = MIN(sdmmc2_params.max_freq, freq);
+ }
+
+ if (sdmmc2_params.vmmc_regu != NULL) {
+ ret = regulator_disable(sdmmc2_params.vmmc_regu);
+ if (ret < 0) {
+ panic();
+ }
+ }
+
+ mdelay(VCC_POWER_OFF_DELAY);
+
+ mmio_write_32(base + SDMMC_POWER,
+ SDMMC_POWER_PWRCTRL_PWR_CYCLE | sdmmc2_params.dirpol);
+ mdelay(POWER_CYCLE_DELAY);
+
+ if (sdmmc2_params.vmmc_regu != NULL) {
+ ret = regulator_enable(sdmmc2_params.vmmc_regu);
+ if (ret < 0) {
+ panic();
+ }
+ }
+
+ mdelay(VCC_POWER_ON_DELAY);
+
+ mmio_write_32(base + SDMMC_POWER, sdmmc2_params.dirpol);
+ mdelay(POWER_OFF_DELAY);
+
+ clock_div = div_round_up(sdmmc2_params.clk_rate, freq * 2U);
+
+ mmio_write_32(base + SDMMC_CLKCR, SDMMC_CLKCR_HWFC_EN | clock_div |
+ sdmmc2_params.negedge |
+ sdmmc2_params.pin_ckin);
+
+ mmio_write_32(base + SDMMC_POWER,
+ SDMMC_POWER_PWRCTRL | sdmmc2_params.dirpol);
+
+ mdelay(POWER_ON_DELAY);
+}
+
+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(6):
+ if ((sdmmc2_params.device_info->mmc_dev_type == MMC_IS_SD_HC) &&
+ (!next_cmd_is_acmd)) {
+ cmd_reg |= SDMMC_CMDR_CMDTRANS;
+ if (sdmmc2_params.use_dma) {
+ flags_data |= SDMMC_STAR_DCRCFAIL |
+ SDMMC_STAR_DTIMEOUT |
+ SDMMC_STAR_DATAEND |
+ SDMMC_STAR_RXOVERR |
+ SDMMC_STAR_IDMATE |
+ SDMMC_STAR_DBCKEND;
+ }
+ }
+ break;
+ case MMC_CMD(8):
+ if (sdmmc2_params.device_info->mmc_dev_type == MMC_IS_EMMC) {
+ cmd_reg |= SDMMC_CMDR_CMDTRANS;
+ }
+ 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;
+ }
+
+ next_cmd_is_acmd = (cmd->cmd_idx == MMC_CMD(55));
+
+ mmio_write_32(base + SDMMC_ICR, SDMMC_STATIC_FLAGS);
+
+ /*
+ * Clear the SDMMC_DCTRLR if the command does not await data.
+ * Skip CMD55 as the next command could be data related, and
+ * the register could have been set in prepare function.
+ */
+ if (((cmd_reg & SDMMC_CMDR_CMDTRANS) == 0U) && !next_cmd_is_acmd) {
+ mmio_write_32(base + SDMMC_DCTRLR, 0U);
+ }
+
+ 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 = %u,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 = %u,status = %x)\n",
+ __func__, cmd->cmd_idx, status);
+ }
+ } else {
+ err = -EIO;
+ ERROR("%s: CRCFAIL (cmd = %u,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 = %u,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 = %u,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)
+{
+ uint8_t retry;
+ int err;
+
+ assert(cmd != NULL);
+
+ for (retry = 0U; retry < 3U; retry++) {
+ err = stm32_sdmmc2_send_cmd_req(cmd);
+ if (err == 0) {
+ return 0;
+ }
+
+ 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%u, Retry: %u, Error: %d\n",
+ cmd->cmd_idx, retry + 1U, err);
+ }
+
+ udelay(10U);
+ }
+
+ 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 < (SDMMC_FIFO_SIZE / 2U)) {
+ 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 < (SDMMC_FIFO_SIZE / 2U);
+ count += sizeof(uint32_t)) {
+ *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;
+ struct dt_node_info dt_info;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ if (fdt == NULL) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ sdmmc_node = dt_match_instance_by_compatible(DT_SDMMC2_COMPAT,
+ sdmmc2_params.reg_base);
+ if (sdmmc_node == -FDT_ERR_NOTFOUND) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ dt_fill_device_info(&dt_info, sdmmc_node);
+ if (dt_info.status == DT_DISABLED) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ if (dt_set_pinctrl_config(sdmmc_node) != 0) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ sdmmc2_params.clock_id = dt_info.clock;
+ sdmmc2_params.reset_id = dt_info.reset;
+
+ if ((fdt_getprop(fdt, sdmmc_node, "st,use-ckin", NULL)) != NULL) {
+ sdmmc2_params.pin_ckin = SDMMC_CLKCR_SELCLKRX_0;
+ }
+
+ 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);
+ }
+
+ sdmmc2_params.vmmc_regu = regulator_get_by_supply_name(fdt, sdmmc_node, "vmmc");
+
+ 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));
+
+ sdmmc2_params.vmmc_regu = NULL;
+
+ if (stm32_sdmmc2_dt_get_config() != 0) {
+ ERROR("%s: DT error\n", __func__);
+ return -ENOMEM;
+ }
+
+ clk_enable(sdmmc2_params.clock_id);
+
+ if ((int)sdmmc2_params.reset_id >= 0) {
+ int rc;
+
+ rc = stm32mp_reset_assert(sdmmc2_params.reset_id, TIMEOUT_US_1_MS);
+ if (rc != 0) {
+ panic();
+ }
+ udelay(2);
+ rc = stm32mp_reset_deassert(sdmmc2_params.reset_id, TIMEOUT_US_1_MS);
+ if (rc != 0) {
+ panic();
+ }
+ mdelay(1);
+ }
+
+ sdmmc2_params.clk_rate = 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);
+}
diff --git a/drivers/st/pmic/stm32mp_pmic.c b/drivers/st/pmic/stm32mp_pmic.c
new file mode 100644
index 0000000..5b43760
--- /dev/null
+++ b/drivers/st/pmic/stm32mp_pmic.c
@@ -0,0 +1,526 @@
+/*
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/regulator.h>
+#include <drivers/st/stm32_i2c.h>
+#include <drivers/st/stm32mp_pmic.h>
+#include <drivers/st/stpmic1.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#define PMIC_NODE_NOT_FOUND 1
+
+static struct i2c_handle_s i2c_handle;
+static uint32_t pmic_i2c_addr;
+
+static int register_pmic(void);
+
+static int dt_get_pmic_node(void *fdt)
+{
+ static int node = -FDT_ERR_BADOFFSET;
+
+ if (node == -FDT_ERR_BADOFFSET) {
+ node = fdt_node_offset_by_compatible(fdt, -1, "st,stpmic1");
+ }
+
+ return node;
+}
+
+int dt_pmic_status(void)
+{
+ static int status = -FDT_ERR_BADVALUE;
+ int node;
+ void *fdt;
+
+ if (status != -FDT_ERR_BADVALUE) {
+ return status;
+ }
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -ENOENT;
+ }
+
+ node = dt_get_pmic_node(fdt);
+ if (node <= 0) {
+ status = -FDT_ERR_NOTFOUND;
+
+ return status;
+ }
+
+ status = (int)fdt_get_status(node);
+
+ return status;
+}
+
+static bool dt_pmic_is_secure(void)
+{
+ int status = dt_pmic_status();
+
+ return (status >= 0) &&
+ (status == DT_SECURE) &&
+ (i2c_handle.dt_status == DT_SECURE);
+}
+
+/*
+ * Get PMIC and its I2C bus configuration from the device tree.
+ * Return 0 on success, negative on error, 1 if no PMIC node is defined.
+ */
+static int dt_pmic_i2c_config(struct dt_node_info *i2c_info,
+ struct stm32_i2c_init_s *init)
+{
+ static int i2c_node = -FDT_ERR_NOTFOUND;
+ void *fdt;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ if (i2c_node == -FDT_ERR_NOTFOUND) {
+ int pmic_node;
+ const fdt32_t *cuint;
+
+ pmic_node = dt_get_pmic_node(fdt);
+ if (pmic_node < 0) {
+ return PMIC_NODE_NOT_FOUND;
+ }
+
+ 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 -FDT_ERR_BADVALUE;
+ }
+
+ 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);
+}
+
+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->i2c_state = I2C_STATE_RESET;
+ i2c_init.own_address1 = pmic_i2c_addr;
+ i2c_init.addressing_mode = I2C_ADDRESSINGMODE_7BIT;
+ i2c_init.dual_address_mode = I2C_DUALADDRESS_DISABLE;
+ 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;
+}
+
+static void register_pmic_shared_peripherals(void)
+{
+ uintptr_t i2c_base = i2c_handle.i2c_base_addr;
+
+ if (dt_pmic_is_secure()) {
+ stm32mp_register_secure_periph_iomem(i2c_base);
+ } else {
+ if (i2c_base != 0U) {
+ stm32mp_register_non_secure_periph_iomem(i2c_base);
+ }
+ }
+}
+
+void initialize_pmic(void)
+{
+ if (!initialize_pmic_i2c()) {
+ VERBOSE("No PMIC\n");
+ return;
+ }
+
+ register_pmic_shared_peripherals();
+
+ if (register_pmic() < 0) {
+ panic();
+ }
+
+ if (stpmic1_powerctrl_on() < 0) {
+ panic();
+ }
+
+}
+
+#if DEBUG
+void print_pmic_info_and_debug(void)
+{
+ unsigned long pmic_version;
+
+ if (stpmic1_get_version(&pmic_version) != 0) {
+ ERROR("Failed to access PMIC\n");
+ panic();
+ }
+
+ INFO("PMIC version = 0x%02lx\n", pmic_version);
+}
+#endif
+
+int pmic_ddr_power_init(enum ddr_type ddr_type)
+{
+ int status;
+ uint16_t buck3_min_mv;
+ struct rdev *buck2, *buck3, *vref;
+ struct rdev *ldo3 __unused;
+
+ buck2 = regulator_get_by_name("buck2");
+ if (buck2 == NULL) {
+ return -ENOENT;
+ }
+
+#if STM32MP15
+ ldo3 = regulator_get_by_name("ldo3");
+ if (ldo3 == NULL) {
+ return -ENOENT;
+ }
+#endif
+
+ vref = regulator_get_by_name("vref_ddr");
+ if (vref == NULL) {
+ return -ENOENT;
+ }
+
+ switch (ddr_type) {
+ case STM32MP_DDR3:
+#if STM32MP15
+ status = regulator_set_flag(ldo3, REGUL_SINK_SOURCE);
+ if (status != 0) {
+ return status;
+ }
+#endif
+
+ status = regulator_set_min_voltage(buck2);
+ if (status != 0) {
+ return status;
+ }
+
+ status = regulator_enable(buck2);
+ if (status != 0) {
+ return status;
+ }
+
+ status = regulator_enable(vref);
+ if (status != 0) {
+ return status;
+ }
+
+#if STM32MP15
+ status = regulator_enable(ldo3);
+ if (status != 0) {
+ return status;
+ }
+#endif
+ 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
+ */
+ buck3 = regulator_get_by_name("buck3");
+ if (buck3 == NULL) {
+ return -ENOENT;
+ }
+
+ regulator_get_range(buck3, &buck3_min_mv, NULL);
+
+#if STM32MP15
+ if (buck3_min_mv != 1800) {
+ status = regulator_set_min_voltage(ldo3);
+ if (status != 0) {
+ return status;
+ }
+ } else {
+ status = regulator_set_flag(ldo3, REGUL_ENABLE_BYPASS);
+ if (status != 0) {
+ return status;
+ }
+ }
+#endif
+
+ status = regulator_set_min_voltage(buck2);
+ if (status != 0) {
+ return status;
+ }
+
+#if STM32MP15
+ status = regulator_enable(ldo3);
+ if (status != 0) {
+ return status;
+ }
+#endif
+
+ status = regulator_enable(buck2);
+ if (status != 0) {
+ return status;
+ }
+
+ status = regulator_enable(vref);
+ if (status != 0) {
+ return status;
+ }
+ break;
+
+ default:
+ break;
+ };
+
+ return 0;
+}
+
+int pmic_voltages_init(void)
+{
+#if STM32MP13
+ struct rdev *buck1, *buck4;
+ int status;
+
+ buck1 = regulator_get_by_name("buck1");
+ if (buck1 == NULL) {
+ return -ENOENT;
+ }
+
+ buck4 = regulator_get_by_name("buck4");
+ if (buck4 == NULL) {
+ return -ENOENT;
+ }
+
+ status = regulator_set_min_voltage(buck1);
+ if (status != 0) {
+ return status;
+ }
+
+ status = regulator_set_min_voltage(buck4);
+ if (status != 0) {
+ return status;
+ }
+#endif
+
+ return 0;
+}
+
+enum {
+ STPMIC1_BUCK1 = 0,
+ STPMIC1_BUCK2,
+ STPMIC1_BUCK3,
+ STPMIC1_BUCK4,
+ STPMIC1_LDO1,
+ STPMIC1_LDO2,
+ STPMIC1_LDO3,
+ STPMIC1_LDO4,
+ STPMIC1_LDO5,
+ STPMIC1_LDO6,
+ STPMIC1_VREF_DDR,
+ STPMIC1_BOOST,
+ STPMIC1_VBUS_OTG,
+ STPMIC1_SW_OUT,
+};
+
+static int pmic_set_state(const struct regul_description *desc, bool enable)
+{
+ VERBOSE("%s: set state to %d\n", desc->node_name, enable);
+
+ if (enable == STATE_ENABLE) {
+ return stpmic1_regulator_enable(desc->node_name);
+ } else {
+ return stpmic1_regulator_disable(desc->node_name);
+ }
+}
+
+static int pmic_get_state(const struct regul_description *desc)
+{
+ VERBOSE("%s: get state\n", desc->node_name);
+
+ return stpmic1_is_regulator_enabled(desc->node_name);
+}
+
+static int pmic_get_voltage(const struct regul_description *desc)
+{
+ VERBOSE("%s: get volt\n", desc->node_name);
+
+ return stpmic1_regulator_voltage_get(desc->node_name);
+}
+
+static int pmic_set_voltage(const struct regul_description *desc, uint16_t mv)
+{
+ VERBOSE("%s: get volt\n", desc->node_name);
+
+ return stpmic1_regulator_voltage_set(desc->node_name, mv);
+}
+
+static int pmic_list_voltages(const struct regul_description *desc,
+ const uint16_t **levels, size_t *count)
+{
+ VERBOSE("%s: list volt\n", desc->node_name);
+
+ return stpmic1_regulator_levels_mv(desc->node_name, levels, count);
+}
+
+static int pmic_set_flag(const struct regul_description *desc, uint16_t flag)
+{
+ VERBOSE("%s: set_flag 0x%x\n", desc->node_name, flag);
+
+ switch (flag) {
+ case REGUL_OCP:
+ return stpmic1_regulator_icc_set(desc->node_name);
+
+ case REGUL_ACTIVE_DISCHARGE:
+ return stpmic1_active_discharge_mode_set(desc->node_name);
+
+ case REGUL_PULL_DOWN:
+ return stpmic1_regulator_pull_down_set(desc->node_name);
+
+ case REGUL_MASK_RESET:
+ return stpmic1_regulator_mask_reset_set(desc->node_name);
+
+ case REGUL_SINK_SOURCE:
+ return stpmic1_regulator_sink_mode_set(desc->node_name);
+
+ case REGUL_ENABLE_BYPASS:
+ return stpmic1_regulator_bypass_mode_set(desc->node_name);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct regul_ops pmic_ops = {
+ .set_state = pmic_set_state,
+ .get_state = pmic_get_state,
+ .set_voltage = pmic_set_voltage,
+ .get_voltage = pmic_get_voltage,
+ .list_voltages = pmic_list_voltages,
+ .set_flag = pmic_set_flag,
+};
+
+#define DEFINE_REGU(name) { \
+ .node_name = name, \
+ .ops = &pmic_ops, \
+ .driver_data = NULL, \
+ .enable_ramp_delay = 1000, \
+}
+
+static const struct regul_description pmic_regs[] = {
+ [STPMIC1_BUCK1] = DEFINE_REGU("buck1"),
+ [STPMIC1_BUCK2] = DEFINE_REGU("buck2"),
+ [STPMIC1_BUCK3] = DEFINE_REGU("buck3"),
+ [STPMIC1_BUCK4] = DEFINE_REGU("buck4"),
+ [STPMIC1_LDO1] = DEFINE_REGU("ldo1"),
+ [STPMIC1_LDO2] = DEFINE_REGU("ldo2"),
+ [STPMIC1_LDO3] = DEFINE_REGU("ldo3"),
+ [STPMIC1_LDO4] = DEFINE_REGU("ldo4"),
+ [STPMIC1_LDO5] = DEFINE_REGU("ldo5"),
+ [STPMIC1_LDO6] = DEFINE_REGU("ldo6"),
+ [STPMIC1_VREF_DDR] = DEFINE_REGU("vref_ddr"),
+ [STPMIC1_BOOST] = DEFINE_REGU("boost"),
+ [STPMIC1_VBUS_OTG] = DEFINE_REGU("pwr_sw1"),
+ [STPMIC1_SW_OUT] = DEFINE_REGU("pwr_sw2"),
+};
+
+#define NB_REG ARRAY_SIZE(pmic_regs)
+
+static int register_pmic(void)
+{
+ void *fdt;
+ int pmic_node, regulators_node, subnode;
+
+ VERBOSE("Register pmic\n");
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ pmic_node = dt_get_pmic_node(fdt);
+ if (pmic_node < 0) {
+ return pmic_node;
+ }
+
+ regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators");
+ if (regulators_node < 0) {
+ return -ENOENT;
+ }
+
+ fdt_for_each_subnode(subnode, fdt, regulators_node) {
+ const char *reg_name = fdt_get_name(fdt, subnode, NULL);
+ const struct regul_description *desc;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < NB_REG; i++) {
+ desc = &pmic_regs[i];
+ if (strcmp(desc->node_name, reg_name) == 0) {
+ break;
+ }
+ }
+ assert(i < NB_REG);
+
+ ret = regulator_register(desc, subnode);
+ if (ret != 0) {
+ WARN("%s:%d failed to register %s\n", __func__,
+ __LINE__, reg_name);
+ return ret;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/st/pmic/stpmic1.c b/drivers/st/pmic/stpmic1.c
new file mode 100644
index 0000000..37eb50b
--- /dev/null
+++ b/drivers/st/pmic/stpmic1.c
@@ -0,0 +1,937 @@
+/*
+ * Copyright (c) 2016-2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/st/stpmic1.h>
+
+#define I2C_TIMEOUT_MS 25
+
+struct regul_struct {
+ const char *dt_node_name;
+ const uint16_t *voltage_table;
+ uint8_t voltage_table_size;
+ uint8_t control_reg;
+ uint8_t enable_mask;
+ uint8_t low_power_reg;
+ uint8_t pull_down_reg;
+ uint8_t pull_down;
+ uint8_t mask_reset_reg;
+ uint8_t mask_reset;
+ uint8_t icc_reg;
+ uint8_t icc_mask;
+};
+
+static struct i2c_handle_s *pmic_i2c_handle;
+static uint16_t pmic_i2c_addr;
+/*
+ * Special mode corresponds to LDO3 in sink source mode or in bypass mode.
+ * LDO3 doesn't switch back from special to normal mode.
+ */
+static bool ldo3_special_mode;
+
+/* 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,
+};
+
+/* Special mode table is used for sink source OR bypass mode */
+static const uint16_t ldo3_special_mode_table[] = {
+ 0,
+};
+
+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,
+};
+
+static const uint16_t fixed_5v_voltage_table[] = {
+ 5000,
+};
+
+/* 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,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
+ .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,
+ .icc_reg = BUCK_ICC_TURNOFF_REG,
+ .icc_mask = BUCK1_ICC_SHIFT,
+ },
+ {
+ .dt_node_name = "buck2",
+ .voltage_table = buck2_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(buck2_voltage_table),
+ .control_reg = BUCK2_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
+ .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,
+ .icc_reg = BUCK_ICC_TURNOFF_REG,
+ .icc_mask = BUCK2_ICC_SHIFT,
+ },
+ {
+ .dt_node_name = "buck3",
+ .voltage_table = buck3_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(buck3_voltage_table),
+ .control_reg = BUCK3_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
+ .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,
+ .icc_reg = BUCK_ICC_TURNOFF_REG,
+ .icc_mask = BUCK3_ICC_SHIFT,
+ },
+ {
+ .dt_node_name = "buck4",
+ .voltage_table = buck4_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(buck4_voltage_table),
+ .control_reg = BUCK4_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
+ .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,
+ .icc_reg = BUCK_ICC_TURNOFF_REG,
+ .icc_mask = BUCK4_ICC_SHIFT,
+ },
+ {
+ .dt_node_name = "ldo1",
+ .voltage_table = ldo1_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(ldo1_voltage_table),
+ .control_reg = LDO1_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
+ .low_power_reg = LDO1_PWRCTRL_REG,
+ .mask_reset_reg = MASK_RESET_LDO_REG,
+ .mask_reset = LDO1_MASK_RESET,
+ .icc_reg = LDO_ICC_TURNOFF_REG,
+ .icc_mask = LDO1_ICC_SHIFT,
+ },
+ {
+ .dt_node_name = "ldo2",
+ .voltage_table = ldo2_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(ldo2_voltage_table),
+ .control_reg = LDO2_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
+ .low_power_reg = LDO2_PWRCTRL_REG,
+ .mask_reset_reg = MASK_RESET_LDO_REG,
+ .mask_reset = LDO2_MASK_RESET,
+ .icc_reg = LDO_ICC_TURNOFF_REG,
+ .icc_mask = LDO2_ICC_SHIFT,
+ },
+ {
+ .dt_node_name = "ldo3",
+ .voltage_table = ldo3_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(ldo3_voltage_table),
+ .control_reg = LDO3_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
+ .low_power_reg = LDO3_PWRCTRL_REG,
+ .mask_reset_reg = MASK_RESET_LDO_REG,
+ .mask_reset = LDO3_MASK_RESET,
+ .icc_reg = LDO_ICC_TURNOFF_REG,
+ .icc_mask = LDO3_ICC_SHIFT,
+ },
+ {
+ .dt_node_name = "ldo4",
+ .voltage_table = ldo4_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(ldo4_voltage_table),
+ .control_reg = LDO4_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
+ .low_power_reg = LDO4_PWRCTRL_REG,
+ .mask_reset_reg = MASK_RESET_LDO_REG,
+ .mask_reset = LDO4_MASK_RESET,
+ .icc_reg = LDO_ICC_TURNOFF_REG,
+ .icc_mask = LDO4_ICC_SHIFT,
+ },
+ {
+ .dt_node_name = "ldo5",
+ .voltage_table = ldo5_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(ldo5_voltage_table),
+ .control_reg = LDO5_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
+ .low_power_reg = LDO5_PWRCTRL_REG,
+ .mask_reset_reg = MASK_RESET_LDO_REG,
+ .mask_reset = LDO5_MASK_RESET,
+ .icc_reg = LDO_ICC_TURNOFF_REG,
+ .icc_mask = LDO5_ICC_SHIFT,
+ },
+ {
+ .dt_node_name = "ldo6",
+ .voltage_table = ldo6_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(ldo6_voltage_table),
+ .control_reg = LDO6_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
+ .low_power_reg = LDO6_PWRCTRL_REG,
+ .mask_reset_reg = MASK_RESET_LDO_REG,
+ .mask_reset = LDO6_MASK_RESET,
+ .icc_reg = LDO_ICC_TURNOFF_REG,
+ .icc_mask = LDO6_ICC_SHIFT,
+ },
+ {
+ .dt_node_name = "vref_ddr",
+ .voltage_table = vref_ddr_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(vref_ddr_voltage_table),
+ .control_reg = VREF_DDR_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
+ .low_power_reg = VREF_DDR_PWRCTRL_REG,
+ .mask_reset_reg = MASK_RESET_LDO_REG,
+ .mask_reset = VREF_DDR_MASK_RESET,
+ },
+ {
+ .dt_node_name = "boost",
+ .voltage_table = fixed_5v_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table),
+ .control_reg = USB_CONTROL_REG,
+ .enable_mask = BOOST_ENABLED,
+ .icc_reg = BUCK_ICC_TURNOFF_REG,
+ .icc_mask = BOOST_ICC_SHIFT,
+ },
+ {
+ .dt_node_name = "pwr_sw1",
+ .voltage_table = fixed_5v_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table),
+ .control_reg = USB_CONTROL_REG,
+ .enable_mask = USBSW_OTG_SWITCH_ENABLED,
+ .icc_reg = BUCK_ICC_TURNOFF_REG,
+ .icc_mask = PWR_SW1_ICC_SHIFT,
+ },
+ {
+ .dt_node_name = "pwr_sw2",
+ .voltage_table = fixed_5v_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table),
+ .control_reg = USB_CONTROL_REG,
+ .enable_mask = SWIN_SWOUT_ENABLED,
+ .icc_reg = BUCK_ICC_TURNOFF_REG,
+ .icc_mask = PWR_SW2_ICC_SHIFT,
+ },
+};
+
+#define MAX_REGUL ARRAY_SIZE(regulators_table)
+
+static const struct regul_struct *get_regulator_data(const char *name)
+{
+ uint8_t i;
+
+ for (i = 0 ; i < MAX_REGUL ; i++) {
+ if (strncmp(name, regulators_table[i].dt_node_name,
+ strlen(regulators_table[i].dt_node_name)) == 0) {
+ return &regulators_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, regul->enable_mask,
+ regul->enable_mask);
+}
+
+int stpmic1_regulator_disable(const char *name)
+{
+ const struct regul_struct *regul = get_regulator_data(name);
+
+ return stpmic1_register_update(regul->control_reg, 0,
+ regul->enable_mask);
+}
+
+bool 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 & regul->enable_mask) == regul->enable_mask;
+}
+
+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;
+
+ if ((strncmp(name, "ldo3", 5) == 0) && ldo3_special_mode) {
+ /*
+ * when the LDO3 is in special mode, we do not change voltage,
+ * because by setting voltage, the LDO would leaves sink-source
+ * mode. There is obviously no reason to leave sink-source mode
+ * at runtime.
+ */
+ return 0;
+ }
+
+ /* Voltage can be set for buck<N> or ldo<N> (except ldo4) regulators */
+ if (strncmp(name, "buck", 4) == 0) {
+ mask = BUCK_VOLTAGE_MASK;
+ } else if ((strncmp(name, "ldo", 3) == 0) &&
+ (strncmp(name, "ldo4", 5) != 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);
+
+ if (regul->mask_reset_reg == 0U) {
+ return -EPERM;
+ }
+
+ return stpmic1_register_update(regul->mask_reset_reg,
+ BIT(regul->mask_reset),
+ LDO_BUCK_RESET_MASK <<
+ regul->mask_reset);
+}
+
+int stpmic1_regulator_icc_set(const char *name)
+{
+ const struct regul_struct *regul = get_regulator_data(name);
+
+ if (regul->mask_reset_reg == 0U) {
+ return -EPERM;
+ }
+
+ return stpmic1_register_update(regul->icc_reg,
+ BIT(regul->icc_mask),
+ BIT(regul->icc_mask));
+}
+
+int stpmic1_regulator_sink_mode_set(const char *name)
+{
+ if (strncmp(name, "ldo3", 5) != 0) {
+ return -EPERM;
+ }
+
+ ldo3_special_mode = true;
+
+ /* disable bypass mode, enable sink mode */
+ return stpmic1_register_update(LDO3_CONTROL_REG,
+ LDO3_DDR_SEL << LDO_BUCK_VOLTAGE_SHIFT,
+ LDO3_BYPASS | LDO_VOLTAGE_MASK);
+}
+
+int stpmic1_regulator_bypass_mode_set(const char *name)
+{
+ if (strncmp(name, "ldo3", 5) != 0) {
+ return -EPERM;
+ }
+
+ ldo3_special_mode = true;
+
+ /* enable bypass mode, disable sink mode */
+ return stpmic1_register_update(LDO3_CONTROL_REG,
+ LDO3_BYPASS,
+ LDO3_BYPASS | LDO_VOLTAGE_MASK);
+}
+
+int stpmic1_active_discharge_mode_set(const char *name)
+{
+ if (strncmp(name, "pwr_sw1", 8) == 0) {
+ return stpmic1_register_update(USB_CONTROL_REG,
+ VBUS_OTG_DISCHARGE,
+ VBUS_OTG_DISCHARGE);
+ }
+
+ if (strncmp(name, "pwr_sw2", 8) == 0) {
+ return stpmic1_register_update(USB_CONTROL_REG,
+ SW_OUT_DISCHARGE,
+ SW_OUT_DISCHARGE);
+ }
+
+ return -EPERM;
+}
+
+int stpmic1_regulator_levels_mv(const char *name, const uint16_t **levels,
+ size_t *levels_count)
+{
+ const struct regul_struct *regul = get_regulator_data(name);
+
+ if ((strncmp(name, "ldo3", 5) == 0) && ldo3_special_mode) {
+ *levels_count = ARRAY_SIZE(ldo3_special_mode_table);
+ *levels = ldo3_special_mode_table;
+ } else {
+ *levels_count = regul->voltage_table_size;
+ *levels = regul->voltage_table;
+ }
+
+ return 0;
+}
+
+int stpmic1_regulator_voltage_get(const char *name)
+{
+ const struct regul_struct *regul = get_regulator_data(name);
+ uint8_t value;
+ uint8_t mask;
+ int status;
+
+ if ((strncmp(name, "ldo3", 5) == 0) && ldo3_special_mode) {
+ return 0;
+ }
+
+ /* Voltage can be set for buck<N> or ldo<N> (except ldo4) regulators */
+ if (strncmp(name, "buck", 4) == 0) {
+ mask = BUCK_VOLTAGE_MASK;
+ } else if ((strncmp(name, "ldo", 3) == 0) &&
+ (strncmp(name, "ldo4", 5) != 0)) {
+ mask = LDO_VOLTAGE_MASK;
+ } else {
+ return 0;
+ }
+
+ status = stpmic1_register_read(regul->control_reg, &value);
+ if (status < 0) {
+ return status;
+ }
+
+ value = (value & mask) >> LDO_BUCK_VOLTAGE_SHIFT;
+
+ if (value > regul->voltage_table_size) {
+ return -ERANGE;
+ }
+
+ 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 -EIO;
+ }
+ }
+#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)
+{
+ uint8_t read_val;
+ int status;
+
+ status = stpmic1_register_read(VERSION_STATUS_REG, &read_val);
+ if (status < 0) {
+ return status;
+ }
+
+ *version = (unsigned long)read_val;
+
+ return 0;
+}
diff --git a/drivers/st/regulator/regulator_core.c b/drivers/st/regulator/regulator_core.c
new file mode 100644
index 0000000..5cc8329
--- /dev/null
+++ b/drivers/st/regulator/regulator_core.c
@@ -0,0 +1,560 @@
+/*
+ * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/regulator.h>
+#include <libfdt.h>
+
+#define MAX_PROPERTY_LEN 64
+
+static struct rdev rdev_array[PLAT_NB_RDEVS];
+
+#define for_each_rdev(rdev) \
+ for (rdev = rdev_array; rdev < (rdev_array + PLAT_NB_RDEVS); rdev++)
+
+#define for_each_registered_rdev(rdev) \
+ for (rdev = rdev_array; \
+ (rdev < (rdev_array + PLAT_NB_RDEVS)) && (rdev->desc != NULL); rdev++)
+
+static void lock_driver(const struct rdev *rdev)
+{
+ if (rdev->desc->ops->lock != NULL) {
+ rdev->desc->ops->lock(rdev->desc);
+ }
+}
+
+static void unlock_driver(const struct rdev *rdev)
+{
+ if (rdev->desc->ops->unlock != NULL) {
+ rdev->desc->ops->unlock(rdev->desc);
+ }
+}
+
+static struct rdev *regulator_get_by_phandle(int32_t phandle)
+{
+ struct rdev *rdev;
+
+ for_each_registered_rdev(rdev) {
+ if (rdev->phandle == phandle) {
+ return rdev;
+ }
+ }
+
+ WARN("%s: phandle %d not found\n", __func__, phandle);
+ return NULL;
+}
+
+/*
+ * Get a regulator from its node name
+ *
+ * @fdt - pointer to device tree memory
+ * @node_name - name of the node "ldo1"
+ * Return pointer to rdev if succeed, NULL else.
+ */
+struct rdev *regulator_get_by_name(const char *node_name)
+{
+ struct rdev *rdev;
+
+ assert(node_name != NULL);
+ VERBOSE("get %s\n", node_name);
+
+ for_each_registered_rdev(rdev) {
+ if (strcmp(rdev->desc->node_name, node_name) == 0) {
+ return rdev;
+ }
+ }
+
+ WARN("%s: %s not found\n", __func__, node_name);
+ return NULL;
+}
+
+static int32_t get_supply_phandle(const void *fdt, int node, const char *name)
+{
+ const fdt32_t *cuint;
+ int len __unused;
+ int supply_phandle = -FDT_ERR_NOTFOUND;
+ char prop_name[MAX_PROPERTY_LEN];
+
+ len = snprintf(prop_name, MAX_PROPERTY_LEN - 1, "%s-supply", name);
+ assert((len >= 0) && (len < MAX_PROPERTY_LEN - 1));
+
+ cuint = fdt_getprop(fdt, node, prop_name, NULL);
+ if (cuint != NULL) {
+ supply_phandle = fdt32_to_cpu(*cuint);
+ VERBOSE("%s: supplied by %d\n", name, supply_phandle);
+ }
+
+ return supply_phandle;
+}
+
+/*
+ * Get a regulator from a supply name
+ *
+ * @fdt - pointer to device tree memory
+ * @node - offset of the node that contains the supply description
+ * @name - name of the supply "vdd" for "vdd-supply'
+ * Return pointer to rdev if succeed, NULL else.
+ */
+struct rdev *regulator_get_by_supply_name(const void *fdt, int node, const char *name)
+{
+ const int p = get_supply_phandle(fdt, node, name);
+
+ if (p < 0) {
+ return NULL;
+ }
+
+ return regulator_get_by_phandle(p);
+}
+
+static int __regulator_set_state(struct rdev *rdev, bool state)
+{
+ if (rdev->desc->ops->set_state == NULL) {
+ return -ENODEV;
+ }
+
+ return rdev->desc->ops->set_state(rdev->desc, state);
+}
+
+/*
+ * Enable regulator
+ *
+ * @rdev - pointer to rdev struct
+ * Return 0 if succeed, non 0 else.
+ */
+int regulator_enable(struct rdev *rdev)
+{
+ int ret;
+
+ assert(rdev != NULL);
+
+ ret = __regulator_set_state(rdev, STATE_ENABLE);
+
+ udelay(rdev->enable_ramp_delay);
+
+ return ret;
+}
+
+/*
+ * Disable regulator
+ *
+ * @rdev - pointer to rdev struct
+ * Return 0 if succeed, non 0 else.
+ */
+int regulator_disable(struct rdev *rdev)
+{
+ int ret;
+
+ assert(rdev != NULL);
+
+ if (rdev->flags & REGUL_ALWAYS_ON) {
+ return 0;
+ }
+
+ ret = __regulator_set_state(rdev, STATE_DISABLE);
+
+ udelay(rdev->enable_ramp_delay);
+
+ return ret;
+}
+
+/*
+ * Regulator enabled query
+ *
+ * @rdev - pointer to rdev struct
+ * Return 0 if disabled, 1 if enabled, <0 else.
+ */
+int regulator_is_enabled(const struct rdev *rdev)
+{
+ int ret;
+
+ assert(rdev != NULL);
+
+ VERBOSE("%s: is en\n", rdev->desc->node_name);
+
+ if (rdev->desc->ops->get_state == NULL) {
+ return -ENODEV;
+ }
+
+ lock_driver(rdev);
+
+ ret = rdev->desc->ops->get_state(rdev->desc);
+ if (ret < 0) {
+ ERROR("regul %s get state failed: err:%d\n",
+ rdev->desc->node_name, ret);
+ }
+
+ unlock_driver(rdev);
+
+ return ret;
+}
+
+/*
+ * Set regulator voltage
+ *
+ * @rdev - pointer to rdev struct
+ * @mvolt - Target voltage level in millivolt
+ * Return 0 if succeed, non 0 else.
+ */
+int regulator_set_voltage(struct rdev *rdev, uint16_t mvolt)
+{
+ int ret;
+
+ assert(rdev != NULL);
+
+ VERBOSE("%s: set mvolt\n", rdev->desc->node_name);
+
+ if (rdev->desc->ops->set_voltage == NULL) {
+ return -ENODEV;
+ }
+
+ if ((mvolt < rdev->min_mv) || (mvolt > rdev->max_mv)) {
+ return -EPERM;
+ }
+
+ lock_driver(rdev);
+
+ ret = rdev->desc->ops->set_voltage(rdev->desc, mvolt);
+ if (ret < 0) {
+ ERROR("regul %s set volt failed: err:%d\n",
+ rdev->desc->node_name, ret);
+ }
+
+ unlock_driver(rdev);
+
+ return ret;
+}
+
+/*
+ * Set regulator min voltage
+ *
+ * @rdev - pointer to rdev struct
+ * Return 0 if succeed, non 0 else.
+ */
+int regulator_set_min_voltage(struct rdev *rdev)
+{
+ return regulator_set_voltage(rdev, rdev->min_mv);
+}
+
+/*
+ * Get regulator voltage
+ *
+ * @rdev - pointer to rdev struct
+ * Return milli volts if succeed, <0 else.
+ */
+int regulator_get_voltage(const struct rdev *rdev)
+{
+ int ret;
+
+ assert(rdev != NULL);
+
+ VERBOSE("%s: get volt\n", rdev->desc->node_name);
+
+ if (rdev->desc->ops->get_voltage == NULL) {
+ return rdev->min_mv;
+ }
+
+ lock_driver(rdev);
+
+ ret = rdev->desc->ops->get_voltage(rdev->desc);
+ if (ret < 0) {
+ ERROR("regul %s get voltage failed: err:%d\n",
+ rdev->desc->node_name, ret);
+ }
+
+ unlock_driver(rdev);
+
+ return ret;
+}
+
+/*
+ * List regulator voltages
+ *
+ * @rdev - pointer to rdev struct
+ * @levels - out: array of supported millitvolt levels from min to max value
+ * @count - out: number of possible millivolt values
+ * Return 0 if succeed, non 0 else.
+ */
+int regulator_list_voltages(const struct rdev *rdev, const uint16_t **levels, size_t *count)
+{
+ int ret;
+ size_t n;
+
+ assert(rdev != NULL);
+ assert(levels != NULL);
+ assert(count != NULL);
+
+ VERBOSE("%s: list volt\n", rdev->desc->node_name);
+
+ if (rdev->desc->ops->list_voltages == NULL) {
+ return -ENODEV;
+ }
+
+ lock_driver(rdev);
+
+ ret = rdev->desc->ops->list_voltages(rdev->desc, levels, count);
+
+ unlock_driver(rdev);
+
+ if (ret < 0) {
+ ERROR("regul %s list_voltages failed: err: %d\n",
+ rdev->desc->node_name, ret);
+ return ret;
+ }
+
+ /*
+ * Reduce the possible values depending on min and max from device-tree
+ */
+ n = *count;
+ while ((n > 1U) && ((*levels)[n - 1U] > rdev->max_mv)) {
+ n--;
+ }
+
+ /* Verify that max val is a valid value */
+ if (rdev->max_mv != (*levels)[n - 1]) {
+ ERROR("regul %s: max value %u is invalid\n",
+ rdev->desc->node_name, rdev->max_mv);
+ return -EINVAL;
+ }
+
+ while ((n > 1U) && ((*levels[0U]) < rdev->min_mv)) {
+ (*levels)++;
+ n--;
+ }
+
+ /* Verify that min is not too high */
+ if (n == 0U) {
+ ERROR("regul %s set min voltage is too high\n",
+ rdev->desc->node_name);
+ return -EINVAL;
+ }
+
+ /* Verify that min val is a valid vlue */
+ if (rdev->min_mv != (*levels)[0U]) {
+ ERROR("regul %s: min value %u is invalid\n",
+ rdev->desc->node_name, rdev->min_mv);
+ return -EINVAL;
+ }
+
+ *count = n;
+
+ VERBOSE("rdev->min_mv=%u rdev->max_mv=%u\n", rdev->min_mv, rdev->max_mv);
+
+ return 0;
+}
+
+/*
+ * Get regulator voltages range
+ *
+ * @rdev - pointer to rdev struct
+ * @min_mv - out: min possible millivolt value
+ * @max_mv - out: max possible millivolt value
+ * Return 0 if succeed, non 0 else.
+ */
+void regulator_get_range(const struct rdev *rdev, uint16_t *min_mv, uint16_t *max_mv)
+{
+ assert(rdev != NULL);
+
+ if (min_mv != NULL) {
+ *min_mv = rdev->min_mv;
+ }
+ if (max_mv != NULL) {
+ *max_mv = rdev->max_mv;
+ }
+}
+
+/*
+ * Set regulator flag
+ *
+ * @rdev - pointer to rdev struct
+ * @flag - flag value to set (eg: REGUL_OCP)
+ * Return 0 if succeed, non 0 else.
+ */
+int regulator_set_flag(struct rdev *rdev, uint16_t flag)
+{
+ int ret;
+
+ /* check that only one bit is set on flag */
+ if (__builtin_popcount(flag) != 1) {
+ return -EINVAL;
+ }
+
+ /* REGUL_ALWAYS_ON and REGUL_BOOT_ON are internal properties of the core */
+ if ((flag == REGUL_ALWAYS_ON) || (flag == REGUL_BOOT_ON)) {
+ rdev->flags |= flag;
+ return 0;
+ }
+
+ if (rdev->desc->ops->set_flag == NULL) {
+ ERROR("%s can not set any flag\n", rdev->desc->node_name);
+ return -ENODEV;
+ }
+
+ lock_driver(rdev);
+
+ ret = rdev->desc->ops->set_flag(rdev->desc, flag);
+
+ unlock_driver(rdev);
+
+ if (ret != 0) {
+ ERROR("%s: could not set flag %d ret=%d\n",
+ rdev->desc->node_name, flag, ret);
+ return ret;
+ }
+
+ rdev->flags |= flag;
+
+ return 0;
+}
+
+static int parse_properties(const void *fdt, struct rdev *rdev, int node)
+{
+ int ret;
+
+ if (fdt_getprop(fdt, node, "regulator-always-on", NULL) != NULL) {
+ VERBOSE("%s: set regulator-always-on\n", rdev->desc->node_name);
+ ret = regulator_set_flag(rdev, REGUL_ALWAYS_ON);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Parse the device-tree for a regulator
+ *
+ * Read min/max voltage from dt and check its validity
+ * Read the properties, and call the driver to set flags
+ * Read power supply phandle
+ * Read and store low power mode states
+ *
+ * @rdev - pointer to rdev struct
+ * @node - device-tree node offset of the regulator
+ * Return 0 if disabled, 1 if enabled, <0 else.
+ */
+static int parse_dt(struct rdev *rdev, int node)
+{
+ void *fdt;
+ const fdt32_t *cuint;
+ const uint16_t *levels;
+ size_t size;
+ int ret;
+
+ VERBOSE("%s: parse dt\n", rdev->desc->node_name);
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -ENOENT;
+ }
+
+ rdev->phandle = fdt_get_phandle(fdt, node);
+
+ cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
+ if (cuint != NULL) {
+ uint16_t min_mv;
+
+ min_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U);
+ VERBOSE("%s: min_mv=%d\n", rdev->desc->node_name, (int)min_mv);
+ if (min_mv <= rdev->max_mv) {
+ rdev->min_mv = min_mv;
+ } else {
+ ERROR("%s: min_mv=%d is too high\n",
+ rdev->desc->node_name, (int)min_mv);
+ return -EINVAL;
+ }
+ }
+
+ cuint = fdt_getprop(fdt, node, "regulator-max-microvolt", NULL);
+ if (cuint != NULL) {
+ uint16_t max_mv;
+
+ max_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U);
+ VERBOSE("%s: max_mv=%d\n", rdev->desc->node_name, (int)max_mv);
+ if (max_mv >= rdev->min_mv) {
+ rdev->max_mv = max_mv;
+ } else {
+ ERROR("%s: max_mv=%d is too low\n",
+ rdev->desc->node_name, (int)max_mv);
+ return -EINVAL;
+ }
+ }
+
+ /* validate that min and max values can be used */
+ ret = regulator_list_voltages(rdev, &levels, &size);
+ if ((ret != 0) && (ret != -ENODEV)) {
+ return ret;
+ }
+
+ ret = parse_properties(fdt, rdev, node);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * Register a regulator driver in regulator framework.
+ * Initialize voltage range from driver description
+ *
+ * @desc - pointer to the regulator description
+ * @node - device-tree node offset of the regulator
+ * Return 0 if succeed, non 0 else.
+ */
+int regulator_register(const struct regul_description *desc, int node)
+{
+ struct rdev *rdev;
+
+ assert(desc != NULL);
+
+ VERBOSE("register %s\n", desc->node_name);
+
+ for_each_rdev(rdev) {
+ if (rdev->desc == NULL) {
+ break;
+ }
+ }
+
+ if (rdev == rdev_array + PLAT_NB_RDEVS) {
+ WARN("Not enough place for regulators, PLAT_NB_RDEVS should be increased.\n");
+ return -ENOMEM;
+ }
+
+ rdev->desc = desc;
+ rdev->enable_ramp_delay = rdev->desc->enable_ramp_delay;
+
+ if (rdev->desc->ops->list_voltages != NULL) {
+ int ret;
+ const uint16_t *levels;
+ size_t count;
+
+ lock_driver(rdev);
+
+ ret = rdev->desc->ops->list_voltages(rdev->desc, &levels, &count);
+
+ unlock_driver(rdev);
+
+ if (ret < 0) {
+ ERROR("regul %s set state failed: err:%d\n",
+ rdev->desc->node_name, ret);
+ return ret;
+ }
+
+ rdev->min_mv = levels[0];
+ rdev->max_mv = levels[count - 1U];
+ } else {
+ rdev->max_mv = UINT16_MAX;
+ }
+
+ return parse_dt(rdev, node);
+}
diff --git a/drivers/st/regulator/regulator_fixed.c b/drivers/st/regulator/regulator_fixed.c
new file mode 100644
index 0000000..f1c224e
--- /dev/null
+++ b/drivers/st/regulator/regulator_fixed.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/st/regulator.h>
+#include <drivers/st/regulator_fixed.h>
+#include <libfdt.h>
+
+#ifndef PLAT_NB_FIXED_REGS
+#error "Missing PLAT_NB_FIXED_REGS"
+#endif
+
+#define FIXED_NAME_LEN 32
+
+struct fixed_data {
+ char name[FIXED_NAME_LEN];
+ uint16_t volt;
+ struct regul_description desc;
+};
+
+static struct fixed_data data[PLAT_NB_FIXED_REGS];
+
+static int fixed_set_state(const struct regul_description *desc, bool state)
+{
+ return 0;
+}
+
+static int fixed_get_state(const struct regul_description *desc)
+{
+ return 1;
+}
+
+static struct regul_ops fixed_ops = {
+ .set_state = fixed_set_state,
+ .get_state = fixed_get_state,
+};
+
+int fixed_regulator_register(void)
+{
+ uint32_t count = 0;
+ void *fdt;
+ int node;
+
+ VERBOSE("fixed reg init!\n");
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ fdt_for_each_compatible_node(fdt, node, "regulator-fixed") {
+ int len __unused;
+ int ret;
+ struct fixed_data *d = &data[count];
+ const char *reg_name;
+
+ reg_name = fdt_get_name(fdt, node, NULL);
+
+ VERBOSE("register fixed reg %s!\n", reg_name);
+
+ len = snprintf(d->name, FIXED_NAME_LEN - 1, "%s", reg_name);
+ assert((len > 0) && (len < (FIXED_NAME_LEN - 1)));
+
+ d->desc.node_name = d->name;
+ d->desc.driver_data = d;
+ d->desc.ops = &fixed_ops;
+
+ ret = regulator_register(&d->desc, node);
+ if (ret != 0) {
+ WARN("%s:%d failed to register %s\n", __func__,
+ __LINE__, reg_name);
+ return ret;
+ }
+
+ count++;
+ assert(count <= PLAT_NB_FIXED_REGS);
+
+ }
+
+ return 0;
+}
diff --git a/drivers/st/reset/stm32mp1_reset.c b/drivers/st/reset/stm32mp1_reset.c
new file mode 100644
index 0000000..98c8dcf
--- /dev/null
+++ b/drivers/st/reset/stm32mp1_reset.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <limits.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+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));
+}
+
+int stm32mp_reset_assert(uint32_t id, unsigned int to_us)
+{
+ uint32_t offset = id2reg_offset(id);
+ uint32_t bitmsk = BIT(id2reg_bit_pos(id));
+ uintptr_t rcc_base = stm32mp_rcc_base();
+
+ mmio_write_32(rcc_base + offset, bitmsk);
+
+ if (to_us != 0U) {
+ uint64_t timeout_ref = timeout_init_us(to_us);
+
+ while ((mmio_read_32(rcc_base + offset) & bitmsk) == 0U) {
+ if (timeout_elapsed(timeout_ref)) {
+ return -ETIMEDOUT;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int stm32mp_reset_deassert(uint32_t id, unsigned int to_us)
+{
+ uint32_t offset = id2reg_offset(id) + RCC_RSTCLRR_OFFSET;
+ uint32_t bitmsk = BIT(id2reg_bit_pos(id));
+ uintptr_t rcc_base = stm32mp_rcc_base();
+
+ mmio_write_32(rcc_base + offset, bitmsk);
+
+ if (to_us != 0U) {
+ uint64_t timeout_ref = timeout_init_us(to_us);
+
+ while ((mmio_read_32(rcc_base + offset) & bitmsk) != 0U) {
+ if (timeout_elapsed(timeout_ref)) {
+ return -ETIMEDOUT;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/st/spi/stm32_qspi.c b/drivers/st/spi/stm32_qspi.c
new file mode 100644
index 0000000..73aa9ac
--- /dev/null
+++ b/drivers/st/spi/stm32_qspi.c
@@ -0,0 +1,508 @@
+/*
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#include <inttypes.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/spi_mem.h>
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32_qspi.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+/* Timeout for device interface reset */
+#define TIMEOUT_US_1_MS 1000U
+
+/* QUADSPI registers */
+#define QSPI_CR 0x00U
+#define QSPI_DCR 0x04U
+#define QSPI_SR 0x08U
+#define QSPI_FCR 0x0CU
+#define QSPI_DLR 0x10U
+#define QSPI_CCR 0x14U
+#define QSPI_AR 0x18U
+#define QSPI_ABR 0x1CU
+#define QSPI_DR 0x20U
+#define QSPI_PSMKR 0x24U
+#define QSPI_PSMAR 0x28U
+#define QSPI_PIR 0x2CU
+#define QSPI_LPTR 0x30U
+
+/* QUADSPI control register */
+#define QSPI_CR_EN BIT(0)
+#define QSPI_CR_ABORT BIT(1)
+#define QSPI_CR_DMAEN BIT(2)
+#define QSPI_CR_TCEN BIT(3)
+#define QSPI_CR_SSHIFT BIT(4)
+#define QSPI_CR_DFM BIT(6)
+#define QSPI_CR_FSEL BIT(7)
+#define QSPI_CR_FTHRES_SHIFT 8U
+#define QSPI_CR_TEIE BIT(16)
+#define QSPI_CR_TCIE BIT(17)
+#define QSPI_CR_FTIE BIT(18)
+#define QSPI_CR_SMIE BIT(19)
+#define QSPI_CR_TOIE BIT(20)
+#define QSPI_CR_APMS BIT(22)
+#define QSPI_CR_PMM BIT(23)
+#define QSPI_CR_PRESCALER_MASK GENMASK_32(31, 24)
+#define QSPI_CR_PRESCALER_SHIFT 24U
+
+/* QUADSPI device configuration register */
+#define QSPI_DCR_CKMODE BIT(0)
+#define QSPI_DCR_CSHT_MASK GENMASK_32(10, 8)
+#define QSPI_DCR_CSHT_SHIFT 8U
+#define QSPI_DCR_FSIZE_MASK GENMASK_32(20, 16)
+#define QSPI_DCR_FSIZE_SHIFT 16U
+
+/* QUADSPI status register */
+#define QSPI_SR_TEF BIT(0)
+#define QSPI_SR_TCF BIT(1)
+#define QSPI_SR_FTF BIT(2)
+#define QSPI_SR_SMF BIT(3)
+#define QSPI_SR_TOF BIT(4)
+#define QSPI_SR_BUSY BIT(5)
+
+/* QUADSPI flag clear register */
+#define QSPI_FCR_CTEF BIT(0)
+#define QSPI_FCR_CTCF BIT(1)
+#define QSPI_FCR_CSMF BIT(3)
+#define QSPI_FCR_CTOF BIT(4)
+
+/* QUADSPI communication configuration register */
+#define QSPI_CCR_DDRM BIT(31)
+#define QSPI_CCR_DHHC BIT(30)
+#define QSPI_CCR_SIOO BIT(28)
+#define QSPI_CCR_FMODE_SHIFT 26U
+#define QSPI_CCR_DMODE_SHIFT 24U
+#define QSPI_CCR_DCYC_SHIFT 18U
+#define QSPI_CCR_ABSIZE_SHIFT 16U
+#define QSPI_CCR_ABMODE_SHIFT 14U
+#define QSPI_CCR_ADSIZE_SHIFT 12U
+#define QSPI_CCR_ADMODE_SHIFT 10U
+#define QSPI_CCR_IMODE_SHIFT 8U
+#define QSPI_CCR_IND_WRITE 0U
+#define QSPI_CCR_IND_READ 1U
+#define QSPI_CCR_MEM_MAP 3U
+
+#define QSPI_MAX_CHIP 2U
+
+#define QSPI_FIFO_TIMEOUT_US 30U
+#define QSPI_CMD_TIMEOUT_US 1000U
+#define QSPI_BUSY_TIMEOUT_US 100U
+#define QSPI_ABT_TIMEOUT_US 100U
+
+#define DT_QSPI_COMPAT "st,stm32f469-qspi"
+
+#define FREQ_100MHZ 100000000U
+
+struct stm32_qspi_ctrl {
+ uintptr_t reg_base;
+ uintptr_t mm_base;
+ size_t mm_size;
+ unsigned long clock_id;
+ unsigned int reset_id;
+};
+
+static struct stm32_qspi_ctrl stm32_qspi;
+
+static uintptr_t qspi_base(void)
+{
+ return stm32_qspi.reg_base;
+}
+
+static int stm32_qspi_wait_for_not_busy(void)
+{
+ uint64_t timeout = timeout_init_us(QSPI_BUSY_TIMEOUT_US);
+
+ while ((mmio_read_32(qspi_base() + QSPI_SR) & QSPI_SR_BUSY) != 0U) {
+ if (timeout_elapsed(timeout)) {
+ ERROR("%s: busy timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static int stm32_qspi_wait_cmd(const struct spi_mem_op *op)
+{
+ int ret = 0;
+ uint64_t timeout;
+
+ timeout = timeout_init_us(QSPI_CMD_TIMEOUT_US);
+ while ((mmio_read_32(qspi_base() + QSPI_SR) & QSPI_SR_TCF) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+ }
+
+ if (ret == 0) {
+ if ((mmio_read_32(qspi_base() + QSPI_SR) & QSPI_SR_TEF) != 0U) {
+ ERROR("%s: transfer error\n", __func__);
+ ret = -EIO;
+ }
+ } else {
+ ERROR("%s: cmd timeout\n", __func__);
+ }
+
+ /* Clear flags */
+ mmio_write_32(qspi_base() + QSPI_FCR, QSPI_FCR_CTCF | QSPI_FCR_CTEF);
+
+ if (ret == 0) {
+ ret = stm32_qspi_wait_for_not_busy();
+ }
+
+ return ret;
+}
+
+static void stm32_qspi_read_fifo(uint8_t *val, uintptr_t addr)
+{
+ *val = mmio_read_8(addr);
+}
+
+static void stm32_qspi_write_fifo(uint8_t *val, uintptr_t addr)
+{
+ mmio_write_8(addr, *val);
+}
+
+static int stm32_qspi_poll(const struct spi_mem_op *op)
+{
+ void (*fifo)(uint8_t *val, uintptr_t addr);
+ uint32_t len;
+ uint8_t *buf;
+
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ fifo = stm32_qspi_read_fifo;
+ } else {
+ fifo = stm32_qspi_write_fifo;
+ }
+
+ buf = (uint8_t *)op->data.buf;
+
+ for (len = op->data.nbytes; len != 0U; len--) {
+ uint64_t timeout = timeout_init_us(QSPI_FIFO_TIMEOUT_US);
+
+ while ((mmio_read_32(qspi_base() + QSPI_SR) &
+ QSPI_SR_FTF) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ ERROR("%s: fifo timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+ }
+
+ fifo(buf++, qspi_base() + QSPI_DR);
+ }
+
+ return 0;
+}
+
+static int stm32_qspi_mm(const struct spi_mem_op *op)
+{
+ memcpy(op->data.buf,
+ (void *)(stm32_qspi.mm_base + (size_t)op->addr.val),
+ op->data.nbytes);
+
+ return 0;
+}
+
+static int stm32_qspi_tx(const struct spi_mem_op *op, uint8_t mode)
+{
+ if (op->data.nbytes == 0U) {
+ return 0;
+ }
+
+ if (mode == QSPI_CCR_MEM_MAP) {
+ return stm32_qspi_mm(op);
+ }
+
+ return stm32_qspi_poll(op);
+}
+
+static unsigned int stm32_qspi_get_mode(uint8_t buswidth)
+{
+ if (buswidth == 4U) {
+ return 3U;
+ }
+
+ return buswidth;
+}
+
+static int stm32_qspi_exec_op(const struct spi_mem_op *op)
+{
+ uint64_t timeout;
+ uint32_t ccr;
+ size_t addr_max;
+ uint8_t mode = QSPI_CCR_IND_WRITE;
+ int ret;
+
+ VERBOSE("%s: cmd:%x mode:%d.%d.%d.%d addr:%" PRIx64 " len:%x\n",
+ __func__, op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
+ op->dummy.buswidth, op->data.buswidth,
+ op->addr.val, op->data.nbytes);
+
+ addr_max = op->addr.val + op->data.nbytes + 1U;
+
+ if ((op->data.dir == SPI_MEM_DATA_IN) && (op->data.nbytes != 0U)) {
+ if ((addr_max < stm32_qspi.mm_size) &&
+ (op->addr.buswidth != 0U)) {
+ mode = QSPI_CCR_MEM_MAP;
+ } else {
+ mode = QSPI_CCR_IND_READ;
+ }
+ }
+
+ if (op->data.nbytes != 0U) {
+ mmio_write_32(qspi_base() + QSPI_DLR, op->data.nbytes - 1U);
+ }
+
+ ccr = mode << QSPI_CCR_FMODE_SHIFT;
+ ccr |= op->cmd.opcode;
+ ccr |= stm32_qspi_get_mode(op->cmd.buswidth) << QSPI_CCR_IMODE_SHIFT;
+
+ if (op->addr.nbytes != 0U) {
+ ccr |= (op->addr.nbytes - 1U) << QSPI_CCR_ADSIZE_SHIFT;
+ ccr |= stm32_qspi_get_mode(op->addr.buswidth) <<
+ QSPI_CCR_ADMODE_SHIFT;
+ }
+
+ if ((op->dummy.buswidth != 0U) && (op->dummy.nbytes != 0U)) {
+ ccr |= (op->dummy.nbytes * 8U / op->dummy.buswidth) <<
+ QSPI_CCR_DCYC_SHIFT;
+ }
+
+ if (op->data.nbytes != 0U) {
+ ccr |= stm32_qspi_get_mode(op->data.buswidth) <<
+ QSPI_CCR_DMODE_SHIFT;
+ }
+
+ mmio_write_32(qspi_base() + QSPI_CCR, ccr);
+
+ if ((op->addr.nbytes != 0U) && (mode != QSPI_CCR_MEM_MAP)) {
+ mmio_write_32(qspi_base() + QSPI_AR, op->addr.val);
+ }
+
+ ret = stm32_qspi_tx(op, mode);
+
+ /*
+ * Abort in:
+ * - Error case.
+ * - Memory mapped read: prefetching must be stopped if we read the last
+ * byte of device (device size - fifo size). If device size is not
+ * known then prefetching is always stopped.
+ */
+ if ((ret != 0) || (mode == QSPI_CCR_MEM_MAP)) {
+ goto abort;
+ }
+
+ /* Wait end of TX in indirect mode */
+ ret = stm32_qspi_wait_cmd(op);
+ if (ret != 0) {
+ goto abort;
+ }
+
+ return 0;
+
+abort:
+ mmio_setbits_32(qspi_base() + QSPI_CR, QSPI_CR_ABORT);
+
+ /* Wait clear of abort bit by hardware */
+ timeout = timeout_init_us(QSPI_ABT_TIMEOUT_US);
+ while ((mmio_read_32(qspi_base() + QSPI_CR) & QSPI_CR_ABORT) != 0U) {
+ if (timeout_elapsed(timeout)) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+ }
+
+ mmio_write_32(qspi_base() + QSPI_FCR, QSPI_FCR_CTCF);
+
+ if (ret != 0) {
+ ERROR("%s: exec op error\n", __func__);
+ }
+
+ return ret;
+}
+
+static int stm32_qspi_claim_bus(unsigned int cs)
+{
+ uint32_t cr;
+
+ if (cs >= QSPI_MAX_CHIP) {
+ return -ENODEV;
+ }
+
+ /* Set chip select and enable the controller */
+ cr = QSPI_CR_EN;
+ if (cs == 1U) {
+ cr |= QSPI_CR_FSEL;
+ }
+
+ mmio_clrsetbits_32(qspi_base() + QSPI_CR, QSPI_CR_FSEL, cr);
+
+ return 0;
+}
+
+static void stm32_qspi_release_bus(void)
+{
+ mmio_clrbits_32(qspi_base() + QSPI_CR, QSPI_CR_EN);
+}
+
+static int stm32_qspi_set_speed(unsigned int hz)
+{
+ unsigned long qspi_clk = clk_get_rate(stm32_qspi.clock_id);
+ uint32_t prescaler = UINT8_MAX;
+ uint32_t csht;
+ int ret;
+
+ if (qspi_clk == 0U) {
+ return -EINVAL;
+ }
+
+ if (hz > 0U) {
+ prescaler = div_round_up(qspi_clk, hz) - 1U;
+ if (prescaler > UINT8_MAX) {
+ prescaler = UINT8_MAX;
+ }
+ }
+
+ csht = div_round_up((5U * qspi_clk) / (prescaler + 1U), FREQ_100MHZ);
+ csht = ((csht - 1U) << QSPI_DCR_CSHT_SHIFT) & QSPI_DCR_CSHT_MASK;
+
+ ret = stm32_qspi_wait_for_not_busy();
+ if (ret != 0) {
+ return ret;
+ }
+
+ mmio_clrsetbits_32(qspi_base() + QSPI_CR, QSPI_CR_PRESCALER_MASK,
+ prescaler << QSPI_CR_PRESCALER_SHIFT);
+
+ mmio_clrsetbits_32(qspi_base() + QSPI_DCR, QSPI_DCR_CSHT_MASK, csht);
+
+ VERBOSE("%s: speed=%lu\n", __func__, qspi_clk / (prescaler + 1U));
+
+ return 0;
+}
+
+static int stm32_qspi_set_mode(unsigned int mode)
+{
+ int ret;
+
+ ret = stm32_qspi_wait_for_not_busy();
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((mode & SPI_CS_HIGH) != 0U) {
+ return -ENODEV;
+ }
+
+ if (((mode & SPI_CPHA) != 0U) && ((mode & SPI_CPOL) != 0U)) {
+ mmio_setbits_32(qspi_base() + QSPI_DCR, QSPI_DCR_CKMODE);
+ } else if (((mode & SPI_CPHA) == 0U) && ((mode & SPI_CPOL) == 0U)) {
+ mmio_clrbits_32(qspi_base() + QSPI_DCR, QSPI_DCR_CKMODE);
+ } else {
+ return -ENODEV;
+ }
+
+ VERBOSE("%s: mode=0x%x\n", __func__, mode);
+
+ if ((mode & SPI_RX_QUAD) != 0U) {
+ VERBOSE("rx: quad\n");
+ } else if ((mode & SPI_RX_DUAL) != 0U) {
+ VERBOSE("rx: dual\n");
+ } else {
+ VERBOSE("rx: single\n");
+ }
+
+ if ((mode & SPI_TX_QUAD) != 0U) {
+ VERBOSE("tx: quad\n");
+ } else if ((mode & SPI_TX_DUAL) != 0U) {
+ VERBOSE("tx: dual\n");
+ } else {
+ VERBOSE("tx: single\n");
+ }
+
+ return 0;
+}
+
+static const struct spi_bus_ops stm32_qspi_bus_ops = {
+ .claim_bus = stm32_qspi_claim_bus,
+ .release_bus = stm32_qspi_release_bus,
+ .set_speed = stm32_qspi_set_speed,
+ .set_mode = stm32_qspi_set_mode,
+ .exec_op = stm32_qspi_exec_op,
+};
+
+int stm32_qspi_init(void)
+{
+ size_t size;
+ int qspi_node;
+ struct dt_node_info info;
+ void *fdt = NULL;
+ int ret;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ qspi_node = dt_get_node(&info, -1, DT_QSPI_COMPAT);
+ if (qspi_node < 0) {
+ ERROR("No QSPI ctrl found\n");
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ if (info.status == DT_DISABLED) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ ret = fdt_get_reg_props_by_name(fdt, qspi_node, "qspi",
+ &stm32_qspi.reg_base, &size);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = fdt_get_reg_props_by_name(fdt, qspi_node, "qspi_mm",
+ &stm32_qspi.mm_base,
+ &stm32_qspi.mm_size);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (dt_set_pinctrl_config(qspi_node) != 0) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ if ((info.clock < 0) || (info.reset < 0)) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ stm32_qspi.clock_id = (unsigned long)info.clock;
+ stm32_qspi.reset_id = (unsigned int)info.reset;
+
+ clk_enable(stm32_qspi.clock_id);
+
+ ret = stm32mp_reset_assert(stm32_qspi.reset_id, TIMEOUT_US_1_MS);
+ if (ret != 0) {
+ panic();
+ }
+ ret = stm32mp_reset_deassert(stm32_qspi.reset_id, TIMEOUT_US_1_MS);
+ if (ret != 0) {
+ panic();
+ }
+
+ mmio_write_32(qspi_base() + QSPI_CR, QSPI_CR_SSHIFT);
+ mmio_write_32(qspi_base() + QSPI_DCR, QSPI_DCR_FSIZE_MASK);
+
+ return spi_mem_init_slave(fdt, qspi_node, &stm32_qspi_bus_ops);
+};
diff --git a/drivers/st/uart/aarch32/stm32_console.S b/drivers/st/uart/aarch32/stm32_console.S
new file mode 100644
index 0000000..e3e0e67
--- /dev/null
+++ b/drivers/st/uart/aarch32/stm32_console.S
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console_macros.S>
+#include <drivers/st/stm32_console.h>
+#include <drivers/st/stm32_uart_regs.h>
+
+#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)
+#if STM32MP_RECONFIGURE_CONSOLE
+ /* UART clock rate is set to 0 in BL32, skip init in that case */
+ cmp r1, #0
+ beq 1f
+#else /* STM32MP_RECONFIGURE_CONSOLE */
+ /* Skip UART initialization if it is already enabled */
+ ldr r3, [r0, #USART_CR1]
+ ands r3, r3, #USART_CR1_UE
+ bne 1f
+#endif /* STM32MP_RECONFIGURE_CONSOLE */
+#endif /* 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 */
+ lsr r3, r2, #1
+ add r3, r1, r3
+ udiv r3, r3, r2
+ cmp r3, #16
+ bhi 2f
+ /* Oversampling 8 */
+ /* Divisor = (2 * Uart clock + (baudrate / 2)) / baudrate */
+ lsr r3, r2, #1
+ add r3, r3, r1, lsl #1
+ udiv r3, r3, r2
+ and r1, r3, #USART_BRR_DIV_FRACTION
+ lsr r1, r1, #1
+ bic r3, r3, #USART_BRR_DIV_FRACTION
+ orr r3, r3, r1
+ ldr r1, [r0, #USART_CR1]
+ orr r1, r1, #USART_CR1_OVER8
+ str r1, [r0, #USART_CR1]
+2:
+ 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
+1:
+ 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,
+ * console_t *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_t 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_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, console_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_stm32_putc
+#if ENABLE_ASSERTIONS
+ cmp r1, #0
+ ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+ ldr r1, [r1, #CONSOLE_T_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
+
+ /* ---------------------------------------------------------------
+ * void 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 : void.
+ * Clobber list : r0, r1
+ * ---------------------------------------------------------------
+ */
+func console_stm32_core_flush
+#if ENABLE_ASSERTIONS
+ cmp r0, #0
+ ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+ /* Check Transmit Data Register Empty */
+txe_loop_3:
+ ldr r1, [r0, #USART_ISR]
+ tst r1, #USART_ISR_TXE
+ beq txe_loop_3
+ bx lr
+endfunc console_stm32_core_flush
+
+ /* ------------------------------------------------------
+ * void console_stm32_flush(console_t *console)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * In : r0 - pointer to console_t structure
+ * Out : void.
+ * 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_BASE]
+ b console_stm32_core_flush
+endfunc console_stm32_flush
diff --git a/drivers/st/uart/stm32_uart.c b/drivers/st/uart/stm32_uart.c
new file mode 100644
index 0000000..63970c7
--- /dev/null
+++ b/drivers/st/uart/stm32_uart.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/bl_common.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32_uart.h>
+#include <drivers/st/stm32_uart_regs.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+/* UART time-out value */
+#define STM32_UART_TIMEOUT_US 20000U
+
+/* Mask to clear ALL the configuration registers */
+
+#define STM32_UART_CR1_FIELDS \
+ (USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | USART_CR1_TE | \
+ USART_CR1_RE | USART_CR1_OVER8 | USART_CR1_FIFOEN)
+
+#define STM32_UART_CR2_FIELDS \
+ (USART_CR2_SLVEN | USART_CR2_DIS_NSS | USART_CR2_ADDM7 | \
+ USART_CR2_LBDL | USART_CR2_LBDIE | USART_CR2_LBCL | \
+ USART_CR2_CPHA | USART_CR2_CPOL | USART_CR2_CLKEN | \
+ USART_CR2_STOP | USART_CR2_LINEN | USART_CR2_SWAP | \
+ USART_CR2_RXINV | USART_CR2_TXINV | USART_CR2_DATAINV | \
+ USART_CR2_MSBFIRST | USART_CR2_ABREN | USART_CR2_ABRMODE | \
+ USART_CR2_RTOEN | USART_CR2_ADD)
+
+#define STM32_UART_CR3_FIELDS \
+ (USART_CR3_EIE | USART_CR3_IREN | USART_CR3_IRLP | \
+ USART_CR3_HDSEL | USART_CR3_NACK | USART_CR3_SCEN | \
+ USART_CR3_DMAR | USART_CR3_DMAT | USART_CR3_RTSE | \
+ USART_CR3_CTSE | USART_CR3_CTSIE | USART_CR3_ONEBIT | \
+ USART_CR3_OVRDIS | USART_CR3_DDRE | USART_CR3_DEM | \
+ USART_CR3_DEP | USART_CR3_SCARCNT | USART_CR3_WUS | \
+ USART_CR3_WUFIE | USART_CR3_TXFTIE | USART_CR3_TCBGTIE | \
+ USART_CR3_RXFTCFG | USART_CR3_RXFTIE | USART_CR3_TXFTCFG)
+
+#define STM32_UART_ISR_ERRORS \
+ (USART_ISR_ORE | USART_ISR_NE | USART_ISR_FE | USART_ISR_PE)
+
+static const uint16_t presc_table[STM32_UART_PRESCALER_NB] = {
+ 1U, 2U, 4U, 6U, 8U, 10U, 12U, 16U, 32U, 64U, 128U, 256U
+};
+
+/* @brief BRR division operation to set BRR register in 8-bit oversampling
+ * mode.
+ * @param clockfreq: UART clock.
+ * @param baud_rate: Baud rate set by the user.
+ * @param prescaler: UART prescaler value.
+ * @retval Division result.
+ */
+static uint32_t uart_div_sampling8(unsigned long clockfreq,
+ uint32_t baud_rate,
+ uint32_t prescaler)
+{
+ uint32_t scaled_freq = clockfreq / presc_table[prescaler];
+
+ return ((scaled_freq * 2) + (baud_rate / 2)) / baud_rate;
+
+}
+
+/* @brief BRR division operation to set BRR register in 16-bit oversampling
+ * mode.
+ * @param clockfreq: UART clock.
+ * @param baud_rate: Baud rate set by the user.
+ * @param prescaler: UART prescaler value.
+ * @retval Division result.
+ */
+static uint32_t uart_div_sampling16(unsigned long clockfreq,
+ uint32_t baud_rate,
+ uint32_t prescaler)
+{
+ uint32_t scaled_freq = clockfreq / presc_table[prescaler];
+
+ return (scaled_freq + (baud_rate / 2)) / baud_rate;
+
+}
+
+/*
+ * @brief Return the UART clock frequency.
+ * @param huart: UART handle.
+ * @retval Frequency value in Hz.
+ */
+static unsigned long uart_get_clock_freq(struct stm32_uart_handle_s *huart)
+{
+ return fdt_get_uart_clock_freq((uintptr_t)huart->base);
+}
+
+/*
+ * @brief Configure the UART peripheral.
+ * @param huart: UART handle.
+ * @retval UART status.
+ */
+static int uart_set_config(struct stm32_uart_handle_s *huart,
+ const struct stm32_uart_init_s *init)
+{
+ uint32_t tmpreg;
+ unsigned long clockfreq;
+ unsigned long int_div;
+ uint32_t brrtemp;
+ uint32_t over_sampling;
+
+ /*---------------------- USART BRR configuration --------------------*/
+ clockfreq = uart_get_clock_freq(huart);
+ if (clockfreq == 0UL) {
+ return -ENODEV;
+ }
+
+ int_div = clockfreq / init->baud_rate;
+ if (int_div < 16U) {
+ uint32_t usartdiv = uart_div_sampling8(clockfreq,
+ init->baud_rate,
+ init->prescaler);
+
+ brrtemp = (usartdiv & USART_BRR_DIV_MANTISSA) |
+ ((usartdiv & USART_BRR_DIV_FRACTION) >> 1);
+ over_sampling = USART_CR1_OVER8;
+ } else {
+ brrtemp = uart_div_sampling16(clockfreq,
+ init->baud_rate,
+ init->prescaler) &
+ (USART_BRR_DIV_FRACTION | USART_BRR_DIV_MANTISSA);
+ over_sampling = 0x0U;
+ }
+ mmio_write_32(huart->base + USART_BRR, brrtemp);
+
+ /*
+ * ---------------------- USART CR1 Configuration --------------------
+ * Clear M, PCE, PS, TE, RE and OVER8 bits and configure
+ * the UART word length, parity, mode and oversampling:
+ * - set the M bits according to init->word_length value,
+ * - set PCE and PS bits according to init->parity value,
+ * - set TE and RE bits according to init->mode value,
+ * - set OVER8 bit according baudrate and clock.
+ */
+ tmpreg = init->word_length |
+ init->parity |
+ init->mode |
+ over_sampling |
+ init->fifo_mode;
+ mmio_clrsetbits_32(huart->base + USART_CR1, STM32_UART_CR1_FIELDS, tmpreg);
+
+ /*
+ * --------------------- USART CR2 Configuration ---------------------
+ * Configure the UART Stop Bits: Set STOP[13:12] bits according
+ * to init->stop_bits value.
+ */
+ mmio_clrsetbits_32(huart->base + USART_CR2, STM32_UART_CR2_FIELDS,
+ init->stop_bits);
+
+ /*
+ * --------------------- USART CR3 Configuration ---------------------
+ * Configure:
+ * - UART HardWare Flow Control: set CTSE and RTSE bits according
+ * to init->hw_flow_control value,
+ * - one-bit sampling method versus three samples' majority rule
+ * according to init->one_bit_sampling (not applicable to
+ * LPUART),
+ * - set TXFTCFG bit according to init->tx_fifo_threshold value,
+ * - set RXFTCFG bit according to init->rx_fifo_threshold value.
+ */
+ tmpreg = init->hw_flow_control | init->one_bit_sampling;
+
+ if (init->fifo_mode == USART_CR1_FIFOEN) {
+ tmpreg |= init->tx_fifo_threshold |
+ init->rx_fifo_threshold;
+ }
+
+ mmio_clrsetbits_32(huart->base + USART_CR3, STM32_UART_CR3_FIELDS, tmpreg);
+
+ /*
+ * --------------------- USART PRESC Configuration -------------------
+ * Configure UART Clock Prescaler : set PRESCALER according to
+ * init->prescaler value.
+ */
+ assert(init->prescaler < STM32_UART_PRESCALER_NB);
+ mmio_clrsetbits_32(huart->base + USART_PRESC, USART_PRESC_PRESCALER,
+ init->prescaler);
+
+ return 0;
+}
+
+/*
+ * @brief Handle UART communication timeout.
+ * @param huart: UART handle.
+ * @param flag: Specifies the UART flag to check.
+ * @retval UART status.
+ */
+static int stm32_uart_wait_flag(struct stm32_uart_handle_s *huart, uint32_t flag)
+{
+ uint64_t timeout_ref = timeout_init_us(STM32_UART_TIMEOUT_US);
+
+ while ((mmio_read_32(huart->base + USART_ISR) & flag) == 0U) {
+ if (timeout_elapsed(timeout_ref)) {
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * @brief Check the UART idle State.
+ * @param huart: UART handle.
+ * @retval UART status.
+ */
+static int stm32_uart_check_idle(struct stm32_uart_handle_s *huart)
+{
+ int ret;
+
+ /* Check if the transmitter is enabled */
+ if ((mmio_read_32(huart->base + USART_CR1) & USART_CR1_TE) == USART_CR1_TE) {
+ ret = stm32_uart_wait_flag(huart, USART_ISR_TEACK);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ /* Check if the receiver is enabled */
+ if ((mmio_read_32(huart->base + USART_CR1) & USART_CR1_RE) == USART_CR1_RE) {
+ ret = stm32_uart_wait_flag(huart, USART_ISR_REACK);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * @brief Compute RDR register mask depending on word length.
+ * @param huart: UART handle.
+ * @retval Mask value.
+ */
+static unsigned int stm32_uart_rdr_mask(const struct stm32_uart_init_s *init)
+{
+ unsigned int mask = 0U;
+
+ switch (init->word_length) {
+ case STM32_UART_WORDLENGTH_9B:
+ mask = GENMASK(8, 0);
+ break;
+ case STM32_UART_WORDLENGTH_8B:
+ mask = GENMASK(7, 0);
+ break;
+ case STM32_UART_WORDLENGTH_7B:
+ mask = GENMASK(6, 0);
+ break;
+ default:
+ break; /* not reached */
+ }
+
+ if (init->parity != STM32_UART_PARITY_NONE) {
+ mask >>= 1;
+ }
+
+ return mask;
+}
+
+/*
+ * @brief Check interrupt and status errors.
+ * @retval True if error detected, false otherwise.
+ */
+static bool stm32_uart_error_detected(struct stm32_uart_handle_s *huart)
+{
+ return (mmio_read_32(huart->base + USART_ISR) & STM32_UART_ISR_ERRORS) != 0U;
+}
+
+/*
+ * @brief Clear status errors.
+ */
+static void stm32_uart_error_clear(struct stm32_uart_handle_s *huart)
+{
+ mmio_write_32(huart->base + USART_ICR, STM32_UART_ISR_ERRORS);
+}
+
+/*
+ * @brief Stop the UART.
+ * @param base: UART base address.
+ */
+void stm32_uart_stop(uintptr_t base)
+{
+ mmio_clrbits_32(base + USART_CR1, USART_CR1_UE);
+}
+
+/*
+ * @brief Initialize UART.
+ * @param huart: UART handle.
+ * @param base_addr: base address of UART.
+ * @param init: UART initialization parameter.
+ * @retval UART status.
+ */
+int stm32_uart_init(struct stm32_uart_handle_s *huart,
+ uintptr_t base_addr,
+ const struct stm32_uart_init_s *init)
+{
+ int ret;
+ int uart_node;
+ int clk;
+ void *fdt = NULL;
+
+ if (huart == NULL || init == NULL || base_addr == 0U) {
+ return -EINVAL;
+ }
+
+ huart->base = base_addr;
+
+ /* Search UART instance in DT */
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ if (fdt == NULL) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ uart_node = dt_match_instance_by_compatible(DT_UART_COMPAT, base_addr);
+ if (uart_node == -FDT_ERR_NOTFOUND) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ /* Pinctrl initialization */
+ if (dt_set_pinctrl_config(uart_node) != 0) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ /* Clock initialization */
+ clk = fdt_get_clock_id(uart_node);
+ if (clk < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+ clk_enable(clk);
+
+ /* Disable the peripheral */
+ stm32_uart_stop(huart->base);
+
+ /* Computation of UART mask to apply to RDR register */
+ huart->rdr_mask = stm32_uart_rdr_mask(init);
+
+ /* Init the peripheral */
+ ret = uart_set_config(huart, init);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Enable the peripheral */
+ mmio_setbits_32(huart->base + USART_CR1, USART_CR1_UE);
+
+ /* TEACK and/or REACK to check */
+ return stm32_uart_check_idle(huart);
+}
+
+/*
+ * @brief Transmit one data in no blocking mode.
+ * @param huart: UART handle.
+ * @param c: data to sent.
+ * @retval UART status.
+ */
+int stm32_uart_putc(struct stm32_uart_handle_s *huart, int c)
+{
+ int ret;
+
+ if (huart == NULL) {
+ return -EINVAL;
+ }
+
+ ret = stm32_uart_wait_flag(huart, USART_ISR_TXE);
+ if (ret != 0) {
+ return ret;
+ }
+
+ mmio_write_32(huart->base + USART_TDR, c);
+ if (stm32_uart_error_detected(huart)) {
+ stm32_uart_error_clear(huart);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/*
+ * @brief Flush TX Transmit fifo
+ * @param huart: UART handle.
+ * @retval UART status.
+ */
+int stm32_uart_flush(struct stm32_uart_handle_s *huart)
+{
+ int ret;
+
+ if (huart == NULL) {
+ return -EINVAL;
+ }
+
+ ret = stm32_uart_wait_flag(huart, USART_ISR_TXE);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return stm32_uart_wait_flag(huart, USART_ISR_TC);
+}
+
+/*
+ * @brief Receive a data in no blocking mode.
+ * @retval value if >0 or UART status.
+ */
+int stm32_uart_getc(struct stm32_uart_handle_s *huart)
+{
+ uint32_t data;
+
+ if (huart == NULL) {
+ return -EINVAL;
+ }
+
+ /* Check if data is available */
+ if ((mmio_read_32(huart->base + USART_ISR) & USART_ISR_RXNE) == 0U) {
+ return -EAGAIN;
+ }
+
+ data = mmio_read_32(huart->base + USART_RDR) & huart->rdr_mask;
+
+ if (stm32_uart_error_detected(huart)) {
+ stm32_uart_error_clear(huart);
+ return -EFAULT;
+ }
+
+ return (int)data;
+}
diff --git a/drivers/st/usb/stm32mp1_usb.c b/drivers/st/usb/stm32mp1_usb.c
new file mode 100644
index 0000000..9a49690
--- /dev/null
+++ b/drivers/st/usb/stm32mp1_usb.c
@@ -0,0 +1,1091 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32mp1_usb.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+#define USB_OTG_MODE_DEVICE 0U
+#define USB_OTG_MODE_HOST 1U
+#define USB_OTG_MODE_DRD 2U
+
+#define EP_TYPE_CTRL 0U
+#define EP_TYPE_ISOC 1U
+#define EP_TYPE_BULK 2U
+#define EP_TYPE_INTR 3U
+
+#define USBD_FIFO_FLUSH_TIMEOUT_US 1000U
+#define EP0_FIFO_SIZE 64U
+
+/* OTG registers offsets */
+#define OTG_GOTGINT 0x004U
+#define OTG_GAHBCFG 0x008U
+#define OTG_GUSBCFG 0x00CU
+#define OTG_GRSTCTL 0x010U
+#define OTG_GINTSTS 0x014U
+#define OTG_GINTMSK 0x018U
+#define OTG_GRXSTSP 0x020U
+#define OTG_GLPMCFG 0x054U
+#define OTG_DCFG 0x800U
+#define OTG_DCTL 0x804U
+#define OTG_DSTS 0x808U
+#define OTG_DIEPMSK 0x810U
+#define OTG_DOEPMSK 0x814U
+#define OTG_DAINT 0x818U
+#define OTG_DAINTMSK 0x81CU
+#define OTG_DIEPEMPMSK 0x834U
+
+/* Definitions for OTG_DIEPx registers */
+#define OTG_DIEP_BASE 0x900U
+#define OTG_DIEP_SIZE 0x20U
+#define OTG_DIEPCTL 0x00U
+#define OTG_DIEPINT 0x08U
+#define OTG_DIEPTSIZ 0x10U
+#define OTG_DIEPDMA 0x14U
+#define OTG_DTXFSTS 0x18U
+#define OTG_DIEP_MAX_NB 9U
+
+/* Definitions for OTG_DOEPx registers */
+#define OTG_DOEP_BASE 0xB00U
+#define OTG_DOEP_SIZE 0x20U
+#define OTG_DOEPCTL 0x00U
+#define OTG_DOEPINT 0x08U
+#define OTG_DOEPTSIZ 0x10U
+#define OTG_DOEPDMA 0x14U
+#define OTG_D0EP_MAX_NB 9U
+
+/* Definitions for OTG_DAINT registers */
+#define OTG_DAINT_OUT_MASK GENMASK(31, 16)
+#define OTG_DAINT_OUT_SHIFT 16U
+#define OTG_DAINT_IN_MASK GENMASK(15, 0)
+#define OTG_DAINT_IN_SHIFT 0U
+
+#define OTG_DAINT_EP0_IN BIT(16)
+#define OTG_DAINT_EP0_OUT BIT(0)
+
+/* Definitions for FIFOs */
+#define OTG_FIFO_BASE 0x1000U
+#define OTG_FIFO_SIZE 0x1000U
+
+/* Bit definitions for OTG_GOTGINT register */
+#define OTG_GOTGINT_SEDET BIT(2)
+
+/* Bit definitions for OTG_GAHBCFG register */
+#define OTG_GAHBCFG_GINT BIT(0)
+
+/* Bit definitions for OTG_GUSBCFG register */
+#define OTG_GUSBCFG_TRDT GENMASK(13, 10)
+#define OTG_GUSBCFG_TRDT_SHIFT 10U
+
+#define USBD_HS_TRDT_VALUE 9U
+
+/* Bit definitions for OTG_GRSTCTL register */
+#define OTG_GRSTCTL_RXFFLSH BIT(4)
+#define OTG_GRSTCTL_TXFFLSH BIT(5)
+#define OTG_GRSTCTL_TXFNUM_SHIFT 6U
+
+/* Bit definitions for OTG_GINTSTS register */
+#define OTG_GINTSTS_CMOD BIT(0)
+#define OTG_GINTSTS_MMIS BIT(1)
+#define OTG_GINTSTS_OTGINT BIT(2)
+#define OTG_GINTSTS_SOF BIT(3)
+#define OTG_GINTSTS_RXFLVL BIT(4)
+#define OTG_GINTSTS_USBSUSP BIT(11)
+#define OTG_GINTSTS_USBRST BIT(12)
+#define OTG_GINTSTS_ENUMDNE BIT(13)
+#define OTG_GINTSTS_IEPINT BIT(18)
+#define OTG_GINTSTS_OEPINT BIT(19)
+#define OTG_GINTSTS_IISOIXFR BIT(20)
+#define OTG_GINTSTS_IPXFR_INCOMPISOOUT BIT(21)
+#define OTG_GINTSTS_LPMINT BIT(27)
+#define OTG_GINTSTS_SRQINT BIT(30)
+#define OTG_GINTSTS_WKUPINT BIT(31)
+
+/* Bit definitions for OTG_GRXSTSP register */
+#define OTG_GRXSTSP_EPNUM GENMASK(3, 0)
+#define OTG_GRXSTSP_BCNT GENMASK(14, 4)
+#define OTG_GRXSTSP_BCNT_SHIFT 4U
+#define OTG_GRXSTSP_PKTSTS GENMASK(20, 17)
+#define OTG_GRXSTSP_PKTSTS_SHIFT 17U
+
+#define STS_GOUT_NAK 1U
+#define STS_DATA_UPDT 2U
+#define STS_XFER_COMP 3U
+#define STS_SETUP_COMP 4U
+#define STS_SETUP_UPDT 6U
+
+/* Bit definitions for OTG_GLPMCFG register */
+#define OTG_GLPMCFG_BESL GENMASK(5, 2)
+
+/* Bit definitions for OTG_DCFG register */
+#define OTG_DCFG_DAD GENMASK(10, 4)
+#define OTG_DCFG_DAD_SHIFT 4U
+
+/* Bit definitions for OTG_DCTL register */
+#define OTG_DCTL_RWUSIG BIT(0)
+#define OTG_DCTL_SDIS BIT(1)
+#define OTG_DCTL_CGINAK BIT(8)
+
+/* Bit definitions for OTG_DSTS register */
+#define OTG_DSTS_SUSPSTS BIT(0)
+#define OTG_DSTS_ENUMSPD_MASK GENMASK(2, 1)
+#define OTG_DSTS_FNSOF0 BIT(8)
+
+#define OTG_DSTS_ENUMSPD(val) ((val) << 1)
+#define OTG_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ OTG_DSTS_ENUMSPD(0U)
+#define OTG_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ OTG_DSTS_ENUMSPD(1U)
+#define OTG_DSTS_ENUMSPD_LS_PHY_6MHZ OTG_DSTS_ENUMSPD(2U)
+#define OTG_DSTS_ENUMSPD_FS_PHY_48MHZ OTG_DSTS_ENUMSPD(3U)
+
+/* Bit definitions for OTG_DIEPMSK register */
+#define OTG_DIEPMSK_XFRCM BIT(0)
+#define OTG_DIEPMSK_EPDM BIT(1)
+#define OTG_DIEPMSK_TOM BIT(3)
+
+/* Bit definitions for OTG_DOEPMSK register */
+#define OTG_DOEPMSK_XFRCM BIT(0)
+#define OTG_DOEPMSK_EPDM BIT(1)
+#define OTG_DOEPMSK_STUPM BIT(3)
+
+/* Bit definitions for OTG_DIEPCTLx registers */
+#define OTG_DIEPCTL_MPSIZ GENMASK(10, 0)
+#define OTG_DIEPCTL_STALL BIT(21)
+#define OTG_DIEPCTL_CNAK BIT(26)
+#define OTG_DIEPCTL_SD0PID_SEVNFRM BIT(28)
+#define OTG_DIEPCTL_SODDFRM BIT(29)
+#define OTG_DIEPCTL_EPDIS BIT(30)
+#define OTG_DIEPCTL_EPENA BIT(31)
+
+/* Bit definitions for OTG_DIEPINTx registers */
+#define OTG_DIEPINT_XFRC BIT(0)
+#define OTG_DIEPINT_EPDISD BIT(1)
+#define OTG_DIEPINT_TOC BIT(3)
+#define OTG_DIEPINT_ITTXFE BIT(4)
+#define OTG_DIEPINT_INEPNE BIT(6)
+#define OTG_DIEPINT_TXFE BIT(7)
+#define OTG_DIEPINT_TXFE_SHIFT 7U
+
+#define OTG_DIEPINT_MASK (BIT(13) | BIT(11) | GENMASK(9, 0))
+
+/* Bit definitions for OTG_DIEPTSIZx registers */
+#define OTG_DIEPTSIZ_XFRSIZ GENMASK(18, 0)
+#define OTG_DIEPTSIZ_PKTCNT GENMASK(28, 19)
+#define OTG_DIEPTSIZ_PKTCNT_SHIFT 19U
+#define OTG_DIEPTSIZ_MCNT_MASK GENMASK(30, 29)
+#define OTG_DIEPTSIZ_MCNT_DATA0 BIT(29)
+
+#define OTG_DIEPTSIZ_PKTCNT_1 BIT(19)
+
+/* Bit definitions for OTG_DTXFSTSx registers */
+#define OTG_DTXFSTS_INEPTFSAV GENMASK(15, 0)
+
+/* Bit definitions for OTG_DOEPCTLx registers */
+#define OTG_DOEPCTL_STALL BIT(21)
+#define OTG_DOEPCTL_CNAK BIT(26)
+#define OTG_DOEPCTL_SD0PID_SEVNFRM BIT(28) /* other than endpoint 0 */
+#define OTG_DOEPCTL_SD1PID_SODDFRM BIT(29) /* other than endpoint 0 */
+#define OTG_DOEPCTL_EPDIS BIT(30)
+#define OTG_DOEPCTL_EPENA BIT(31)
+
+/* Bit definitions for OTG_DOEPTSIZx registers */
+#define OTG_DOEPTSIZ_XFRSIZ GENMASK(18, 0)
+#define OTG_DOEPTSIZ_PKTCNT GENMASK(28, 19)
+#define OTG_DOEPTSIZ_RXDPID_STUPCNT GENMASK(30, 29)
+
+/* Bit definitions for OTG_DOEPINTx registers */
+#define OTG_DOEPINT_XFRC BIT(0)
+#define OTG_DOEPINT_STUP BIT(3)
+#define OTG_DOEPINT_OTEPDIS BIT(4)
+
+#define OTG_DOEPINT_MASK (GENMASK(15, 12) | GENMASK(9, 8) | GENMASK(6, 0))
+
+#define EP_NB 15U
+#define EP_ALL 0x10U
+
+/*
+ * Flush TX FIFO.
+ * handle: PCD handle.
+ * num: FIFO number.
+ * This parameter can be a value from 1 to 15 or EP_ALL.
+ * EP_ALL= 0x10 means Flush all TX FIFOs
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_flush_tx_fifo(void *handle, uint32_t num)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uint64_t timeout = timeout_init_us(USBD_FIFO_FLUSH_TIMEOUT_US);
+
+ mmio_write_32(usb_base_addr + OTG_GRSTCTL,
+ OTG_GRSTCTL_TXFFLSH | (uint32_t)(num << OTG_GRSTCTL_TXFNUM_SHIFT));
+
+ while ((mmio_read_32(usb_base_addr + OTG_GRSTCTL) &
+ OTG_GRSTCTL_TXFFLSH) == OTG_GRSTCTL_TXFFLSH) {
+ if (timeout_elapsed(timeout)) {
+ return USBD_TIMEOUT;
+ }
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * Flush RX FIFO.
+ * handle: PCD handle.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_flush_rx_fifo(void *handle)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uint64_t timeout = timeout_init_us(USBD_FIFO_FLUSH_TIMEOUT_US);
+
+ mmio_write_32(usb_base_addr + OTG_GRSTCTL, OTG_GRSTCTL_RXFFLSH);
+
+ while ((mmio_read_32(usb_base_addr + OTG_GRSTCTL) &
+ OTG_GRSTCTL_RXFFLSH) == OTG_GRSTCTL_RXFFLSH) {
+ if (timeout_elapsed(timeout)) {
+ return USBD_TIMEOUT;
+ }
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * Return the global USB interrupt status.
+ * handle: PCD handle.
+ * return: Interrupt register value.
+ */
+static uint32_t usb_dwc2_read_int(void *handle)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+
+ return mmio_read_32(usb_base_addr + OTG_GINTSTS) &
+ mmio_read_32(usb_base_addr + OTG_GINTMSK);
+}
+
+/*
+ * Return the USB device OUT endpoints interrupt.
+ * handle: PCD handle.
+ * return: Device OUT endpoint interrupts.
+ */
+static uint32_t usb_dwc2_all_out_ep_int(void *handle)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+
+ return ((mmio_read_32(usb_base_addr + OTG_DAINT) &
+ mmio_read_32(usb_base_addr + OTG_DAINTMSK)) &
+ OTG_DAINT_OUT_MASK) >> OTG_DAINT_OUT_SHIFT;
+}
+
+/*
+ * Return the USB device IN endpoints interrupt.
+ * handle: PCD handle.
+ * return: Device IN endpoint interrupts.
+ */
+static uint32_t usb_dwc2_all_in_ep_int(void *handle)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+
+ return ((mmio_read_32(usb_base_addr + OTG_DAINT) &
+ mmio_read_32(usb_base_addr + OTG_DAINTMSK)) &
+ OTG_DAINT_IN_MASK) >> OTG_DAINT_IN_SHIFT;
+}
+
+/*
+ * Return Device OUT EP interrupt register.
+ * handle: PCD handle.
+ * epnum: Endpoint number.
+ * This parameter can be a value from 0 to 15.
+ * return: Device OUT EP Interrupt register.
+ */
+static uint32_t usb_dwc2_out_ep_int(void *handle, uint8_t epnum)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+
+ return mmio_read_32(usb_base_addr + OTG_DOEP_BASE +
+ (epnum * OTG_DOEP_SIZE) + OTG_DOEPINT) &
+ mmio_read_32(usb_base_addr + OTG_DOEPMSK);
+}
+
+/*
+ * Return Device IN EP interrupt register.
+ * handle: PCD handle.
+ * epnum: Endpoint number.
+ * This parameter can be a value from 0 to 15.
+ * return: Device IN EP Interrupt register.
+ */
+static uint32_t usb_dwc2_in_ep_int(void *handle, uint8_t epnum)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uint32_t msk;
+ uint32_t emp;
+
+ msk = mmio_read_32(usb_base_addr + OTG_DIEPMSK);
+ emp = mmio_read_32(usb_base_addr + OTG_DIEPEMPMSK);
+ msk |= ((emp >> epnum) << OTG_DIEPINT_TXFE_SHIFT) & OTG_DIEPINT_TXFE;
+
+ return mmio_read_32(usb_base_addr + OTG_DIEP_BASE +
+ (epnum * OTG_DIEP_SIZE) + OTG_DIEPINT) & msk;
+}
+
+/*
+ * Return USB core mode.
+ * handle: PCD handle.
+ * return: Core mode.
+ * This parameter can be 0 (host) or 1 (device).
+ */
+static uint32_t usb_dwc2_get_mode(void *handle)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+
+ return mmio_read_32(usb_base_addr + OTG_GINTSTS) & OTG_GINTSTS_CMOD;
+}
+
+/*
+ * Activate EP0 for detup transactions.
+ * handle: PCD handle.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_activate_setup(void *handle)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uintptr_t reg_offset = usb_base_addr + OTG_DIEP_BASE;
+
+ /* Set the MPS of the IN EP based on the enumeration speed */
+ mmio_clrbits_32(reg_offset + OTG_DIEPCTL, OTG_DIEPCTL_MPSIZ);
+
+ if ((mmio_read_32(usb_base_addr + OTG_DSTS) & OTG_DSTS_ENUMSPD_MASK) ==
+ OTG_DSTS_ENUMSPD_LS_PHY_6MHZ) {
+ mmio_setbits_32(reg_offset + OTG_DIEPCTL, 3U);
+ }
+
+ mmio_setbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_CGINAK);
+
+ return USBD_OK;
+}
+
+/*
+ * Prepare the EP0 to start the first control setup.
+ * handle: Selected device.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_ep0_out_start(void *handle)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uintptr_t reg_offset = usb_base_addr + OTG_DIEP_BASE + OTG_DIEPTSIZ;
+ uint32_t reg_value = 0U;
+
+ /* PKTCNT = 1 and XFRSIZ = 24 bytes for endpoint 0 */
+ reg_value |= OTG_DIEPTSIZ_PKTCNT_1;
+ reg_value |= (EP0_FIFO_SIZE & OTG_DIEPTSIZ_XFRSIZ);
+ reg_value |= OTG_DOEPTSIZ_RXDPID_STUPCNT;
+
+ mmio_write_32(reg_offset, reg_value);
+
+ return USBD_OK;
+}
+
+/*
+ * Write a packet into the TX FIFO associated with the EP/channel.
+ * handle: Selected device.
+ * src: Pointer to source buffer.
+ * ch_ep_num: Endpoint or host channel number.
+ * len: Number of bytes to write.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_write_packet(void *handle, uint8_t *src,
+ uint8_t ch_ep_num, uint16_t len)
+{
+ uint32_t reg_offset;
+ uint32_t count32b = (len + 3U) / 4U;
+ uint32_t i;
+
+ reg_offset = (uintptr_t)handle + OTG_FIFO_BASE +
+ (ch_ep_num * OTG_FIFO_SIZE);
+
+ for (i = 0U; i < count32b; i++) {
+ uint32_t src_copy = 0U;
+ uint32_t j;
+
+ /* Data written to FIFO need to be 4 bytes aligned */
+ for (j = 0U; j < 4U; j++) {
+ src_copy += (*(src + j)) << (8U * j);
+ }
+
+ mmio_write_32(reg_offset, src_copy);
+ src += 4U;
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * Read a packet from the RX FIFO associated with the EP/channel.
+ * handle: Selected device.
+ * dst: Destination pointer.
+ * len: Number of bytes to read.
+ * return: Pointer to destination buffer.
+ */
+static void *usb_dwc2_read_packet(void *handle, uint8_t *dest, uint16_t len)
+{
+ uint32_t reg_offset;
+ uint32_t count32b = (len + 3U) / 4U;
+ uint32_t i;
+
+ VERBOSE("read packet length %i to 0x%lx\n", len, (uintptr_t)dest);
+
+ reg_offset = (uintptr_t)handle + OTG_FIFO_BASE;
+
+ for (i = 0U; i < count32b; i++) {
+ *(uint32_t *)dest = mmio_read_32(reg_offset);
+ dest += 4U;
+ dsb();
+ }
+
+ return (void *)dest;
+}
+
+/*
+ * Setup and start a transfer over an EP.
+ * handle: Selected device
+ * ep: Pointer to endpoint structure.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_ep_start_xfer(void *handle, struct usbd_ep *ep)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uint32_t reg_offset;
+ uint32_t reg_value;
+ uint32_t clear_value;
+
+ if (ep->is_in) {
+ reg_offset = usb_base_addr + OTG_DIEP_BASE + (ep->num * OTG_DIEP_SIZE);
+ clear_value = OTG_DIEPTSIZ_PKTCNT | OTG_DIEPTSIZ_XFRSIZ;
+ if (ep->xfer_len == 0U) {
+ reg_value = OTG_DIEPTSIZ_PKTCNT_1;
+ } else {
+ /*
+ * Program the transfer size and packet count
+ * as follows:
+ * xfersize = N * maxpacket + short_packet
+ * pktcnt = N + (short_packet exist ? 1 : 0)
+ */
+ reg_value = (OTG_DIEPTSIZ_PKTCNT &
+ (((ep->xfer_len + ep->maxpacket - 1U) /
+ ep->maxpacket) << OTG_DIEPTSIZ_PKTCNT_SHIFT))
+ | ep->xfer_len;
+
+ if (ep->type == EP_TYPE_ISOC) {
+ clear_value |= OTG_DIEPTSIZ_MCNT_MASK;
+ reg_value |= OTG_DIEPTSIZ_MCNT_DATA0;
+ }
+ }
+
+ mmio_clrsetbits_32(reg_offset + OTG_DIEPTSIZ, clear_value, reg_value);
+
+ if ((ep->type != EP_TYPE_ISOC) && (ep->xfer_len > 0U)) {
+ /* Enable the TX FIFO empty interrupt for this EP */
+ mmio_setbits_32(usb_base_addr + OTG_DIEPEMPMSK, BIT(ep->num));
+ }
+
+ /* EP enable, IN data in FIFO */
+ reg_value = OTG_DIEPCTL_CNAK | OTG_DIEPCTL_EPENA;
+
+ if (ep->type == EP_TYPE_ISOC) {
+ if ((mmio_read_32(usb_base_addr + OTG_DSTS) & OTG_DSTS_FNSOF0) == 0U) {
+ reg_value |= OTG_DIEPCTL_SODDFRM;
+ } else {
+ reg_value |= OTG_DIEPCTL_SD0PID_SEVNFRM;
+ }
+ }
+
+ mmio_setbits_32(reg_offset + OTG_DIEPCTL, reg_value);
+
+ if (ep->type == EP_TYPE_ISOC) {
+ usb_dwc2_write_packet(handle, ep->xfer_buff, ep->num, ep->xfer_len);
+ }
+ } else {
+ reg_offset = usb_base_addr + OTG_DOEP_BASE + (ep->num * OTG_DOEP_SIZE);
+ /*
+ * Program the transfer size and packet count as follows:
+ * pktcnt = N
+ * xfersize = N * maxpacket
+ */
+ if (ep->xfer_len == 0U) {
+ reg_value = ep->maxpacket | OTG_DIEPTSIZ_PKTCNT_1;
+ } else {
+ uint16_t pktcnt = (ep->xfer_len + ep->maxpacket - 1U) / ep->maxpacket;
+
+ reg_value = (pktcnt << OTG_DIEPTSIZ_PKTCNT_SHIFT) |
+ (ep->maxpacket * pktcnt);
+ }
+
+ mmio_clrsetbits_32(reg_offset + OTG_DOEPTSIZ,
+ OTG_DOEPTSIZ_XFRSIZ & OTG_DOEPTSIZ_PKTCNT,
+ reg_value);
+
+ /* EP enable */
+ reg_value = OTG_DOEPCTL_CNAK | OTG_DOEPCTL_EPENA;
+
+ if (ep->type == EP_TYPE_ISOC) {
+ if ((mmio_read_32(usb_base_addr + OTG_DSTS) & OTG_DSTS_FNSOF0) == 0U) {
+ reg_value |= OTG_DOEPCTL_SD1PID_SODDFRM;
+ } else {
+ reg_value |= OTG_DOEPCTL_SD0PID_SEVNFRM;
+ }
+ }
+
+ mmio_setbits_32(reg_offset + OTG_DOEPCTL, reg_value);
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * Setup and start a transfer over the EP0.
+ * handle: Selected device.
+ * ep: Pointer to endpoint structure.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_ep0_start_xfer(void *handle, struct usbd_ep *ep)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uint32_t reg_offset;
+ uint32_t reg_value;
+
+ if (ep->is_in) {
+ reg_offset = usb_base_addr + OTG_DIEP_BASE +
+ (ep->num * OTG_DIEP_SIZE);
+
+ if (ep->xfer_len == 0U) {
+ reg_value = OTG_DIEPTSIZ_PKTCNT_1;
+ } else {
+ /*
+ * Program the transfer size and packet count
+ * as follows:
+ * xfersize = N * maxpacket + short_packet
+ * pktcnt = N + (short_packet exist ? 1 : 0)
+ */
+
+ if (ep->xfer_len > ep->maxpacket) {
+ ep->xfer_len = ep->maxpacket;
+ }
+
+ reg_value = OTG_DIEPTSIZ_PKTCNT_1 | ep->xfer_len;
+ }
+
+ mmio_clrsetbits_32(reg_offset + OTG_DIEPTSIZ,
+ OTG_DIEPTSIZ_XFRSIZ | OTG_DIEPTSIZ_PKTCNT,
+ reg_value);
+
+ /* Enable the TX FIFO empty interrupt for this EP */
+ if (ep->xfer_len > 0U) {
+ mmio_setbits_32(usb_base_addr + OTG_DIEPEMPMSK,
+ BIT(ep->num));
+ }
+
+ /* EP enable, IN data in FIFO */
+ mmio_setbits_32(reg_offset + OTG_DIEPCTL,
+ OTG_DIEPCTL_CNAK | OTG_DIEPCTL_EPENA);
+ } else {
+ reg_offset = usb_base_addr + OTG_DOEP_BASE +
+ (ep->num * OTG_DOEP_SIZE);
+
+ /*
+ * Program the transfer size and packet count as follows:
+ * pktcnt = N
+ * xfersize = N * maxpacket
+ */
+ if (ep->xfer_len > 0U) {
+ ep->xfer_len = ep->maxpacket;
+ }
+
+ reg_value = OTG_DIEPTSIZ_PKTCNT_1 | ep->maxpacket;
+
+ mmio_clrsetbits_32(reg_offset + OTG_DIEPTSIZ,
+ OTG_DIEPTSIZ_XFRSIZ | OTG_DIEPTSIZ_PKTCNT,
+ reg_value);
+
+ /* EP enable */
+ mmio_setbits_32(reg_offset + OTG_DOEPCTL,
+ OTG_DOEPCTL_CNAK | OTG_DOEPCTL_EPENA);
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * Set a stall condition over an EP.
+ * handle: Selected device.
+ * ep: Pointer to endpoint structure.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_ep_set_stall(void *handle, struct usbd_ep *ep)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uint32_t reg_offset;
+ uint32_t reg_value;
+
+ if (ep->is_in) {
+ reg_offset = usb_base_addr + OTG_DIEP_BASE +
+ (ep->num * OTG_DIEP_SIZE);
+ reg_value = mmio_read_32(reg_offset + OTG_DIEPCTL);
+
+ if ((reg_value & OTG_DIEPCTL_EPENA) == 0U) {
+ reg_value &= ~OTG_DIEPCTL_EPDIS;
+ }
+
+ reg_value |= OTG_DIEPCTL_STALL;
+
+ mmio_write_32(reg_offset + OTG_DIEPCTL, reg_value);
+ } else {
+ reg_offset = usb_base_addr + OTG_DOEP_BASE +
+ (ep->num * OTG_DOEP_SIZE);
+ reg_value = mmio_read_32(reg_offset + OTG_DOEPCTL);
+
+ if ((reg_value & OTG_DOEPCTL_EPENA) == 0U) {
+ reg_value &= ~OTG_DOEPCTL_EPDIS;
+ }
+
+ reg_value |= OTG_DOEPCTL_STALL;
+
+ mmio_write_32(reg_offset + OTG_DOEPCTL, reg_value);
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * Stop the USB device mode.
+ * handle: Selected device.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_stop_device(void *handle)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uint32_t i;
+
+ /* Disable Int */
+ mmio_clrbits_32(usb_base_addr + OTG_GAHBCFG, OTG_GAHBCFG_GINT);
+
+ /* Clear pending interrupts */
+ for (i = 0U; i < EP_NB; i++) {
+ mmio_write_32(usb_base_addr + OTG_DIEP_BASE + (i * OTG_DIEP_SIZE) + OTG_DIEPINT,
+ OTG_DIEPINT_MASK);
+ mmio_write_32(usb_base_addr + OTG_DOEP_BASE + (i * OTG_DOEP_SIZE) + OTG_DOEPINT,
+ OTG_DOEPINT_MASK);
+ }
+
+ mmio_write_32(usb_base_addr + OTG_DAINT, OTG_DAINT_IN_MASK | OTG_DAINT_OUT_MASK);
+
+ /* Clear interrupt masks */
+ mmio_write_32(usb_base_addr + OTG_DIEPMSK, 0U);
+ mmio_write_32(usb_base_addr + OTG_DOEPMSK, 0U);
+ mmio_write_32(usb_base_addr + OTG_DAINTMSK, 0U);
+
+ /* Flush the FIFO */
+ usb_dwc2_flush_rx_fifo(handle);
+ usb_dwc2_flush_tx_fifo(handle, EP_ALL);
+
+ /* Disconnect the USB device by disabling the pull-up/pull-down */
+ mmio_setbits_32((uintptr_t)handle + OTG_DCTL, OTG_DCTL_SDIS);
+
+ return USBD_OK;
+}
+
+/*
+ * Stop the USB device mode.
+ * handle: Selected device.
+ * address: New device address to be assigned.
+ * This parameter can be a value from 0 to 255.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_set_address(void *handle, uint8_t address)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+
+ mmio_clrsetbits_32(usb_base_addr + OTG_DCFG,
+ OTG_DCFG_DAD,
+ address << OTG_DCFG_DAD_SHIFT);
+
+ return USBD_OK;
+}
+
+/*
+ * Check FIFO for the next packet to be loaded.
+ * handle: Selected device.
+ * epnum : Endpoint number.
+ * xfer_len: Block length.
+ * xfer_count: Number of blocks.
+ * maxpacket: Max packet length.
+ * xfer_buff: Buffer pointer.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_write_empty_tx_fifo(void *handle,
+ uint32_t epnum,
+ uint32_t xfer_len,
+ uint32_t *xfer_count,
+ uint32_t maxpacket,
+ uint8_t **xfer_buff)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uint32_t reg_offset;
+ int32_t len;
+ uint32_t len32b;
+ enum usb_status ret;
+
+ len = xfer_len - *xfer_count;
+
+ if ((len > 0) && ((uint32_t)len > maxpacket)) {
+ len = maxpacket;
+ }
+
+ len32b = (len + 3U) / 4U;
+
+ reg_offset = usb_base_addr + OTG_DIEP_BASE + (epnum * OTG_DIEP_SIZE);
+
+ while (((mmio_read_32(reg_offset + OTG_DTXFSTS) &
+ OTG_DTXFSTS_INEPTFSAV) > len32b) &&
+ (*xfer_count < xfer_len) && (xfer_len != 0U)) {
+ /* Write the FIFO */
+ len = xfer_len - *xfer_count;
+
+ if ((len > 0) && ((uint32_t)len > maxpacket)) {
+ len = maxpacket;
+ }
+
+ len32b = (len + 3U) / 4U;
+
+ ret = usb_dwc2_write_packet(handle, *xfer_buff, epnum, len);
+ if (ret != USBD_OK) {
+ return ret;
+ }
+
+ *xfer_buff += len;
+ *xfer_count += len;
+ }
+
+ if (len <= 0) {
+ mmio_clrbits_32(usb_base_addr + OTG_DIEPEMPMSK, BIT(epnum));
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * Handle PCD interrupt request.
+ * handle: PCD handle.
+ * param: Pointer to information updated by the IT handling.
+ * return: Action to do after IT handling.
+ */
+static enum usb_action usb_dwc2_it_handler(void *handle, uint32_t *param)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uint32_t ep_intr;
+ uint32_t epint;
+ uint32_t epnum;
+ uint32_t temp;
+ enum usb_status ret;
+
+ if (usb_dwc2_get_mode(handle) != USB_OTG_MODE_DEVICE) {
+ return USB_NOTHING;
+ }
+
+ /* Avoid spurious interrupt */
+ if (usb_dwc2_read_int(handle) == 0U) {
+ return USB_NOTHING;
+ }
+
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_MMIS) != 0U) {
+ /* Incorrect mode, acknowledge the interrupt */
+ mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_MMIS);
+ }
+
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_OEPINT) != 0U) {
+ uint32_t reg_offset;
+
+ /* Read in the device interrupt bits */
+ ep_intr = usb_dwc2_all_out_ep_int(handle);
+ epnum = 0U;
+ while ((ep_intr & BIT(0)) != BIT(0)) {
+ epnum++;
+ ep_intr >>= 1;
+ }
+
+ reg_offset = usb_base_addr + OTG_DOEP_BASE + (epnum * OTG_DOEP_SIZE) + OTG_DOEPINT;
+
+ epint = usb_dwc2_out_ep_int(handle, epnum);
+
+ if ((epint & OTG_DOEPINT_XFRC) == OTG_DOEPINT_XFRC) {
+ mmio_write_32(reg_offset, OTG_DOEPINT_XFRC);
+ *param = epnum;
+
+ return USB_DATA_OUT;
+ }
+
+ if ((epint & OTG_DOEPINT_STUP) == OTG_DOEPINT_STUP) {
+ /* Inform that a setup packet is available */
+ mmio_write_32(reg_offset, OTG_DOEPINT_STUP);
+
+ return USB_SETUP;
+ }
+
+ if ((epint & OTG_DOEPINT_OTEPDIS) == OTG_DOEPINT_OTEPDIS) {
+ mmio_write_32(reg_offset, OTG_DOEPINT_OTEPDIS);
+ }
+ }
+
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_IEPINT) != 0U) {
+ uint32_t reg_offset;
+
+ /* Read in the device interrupt bits */
+ ep_intr = usb_dwc2_all_in_ep_int(handle);
+ epnum = 0U;
+ while ((ep_intr & BIT(0)) != BIT(0)) {
+ epnum++;
+ ep_intr >>= 1;
+ }
+
+ reg_offset = usb_base_addr + OTG_DIEP_BASE + (epnum * OTG_DIEP_SIZE) + OTG_DIEPINT;
+
+ epint = usb_dwc2_in_ep_int(handle, epnum);
+
+ if ((epint & OTG_DIEPINT_XFRC) == OTG_DIEPINT_XFRC) {
+ mmio_clrbits_32(usb_base_addr + OTG_DIEPEMPMSK, BIT(epnum));
+ mmio_write_32(reg_offset, OTG_DIEPINT_XFRC);
+ *param = epnum;
+
+ return USB_DATA_IN;
+ }
+
+ if ((epint & OTG_DIEPINT_TOC) == OTG_DIEPINT_TOC) {
+ mmio_write_32(reg_offset, OTG_DIEPINT_TOC);
+ }
+
+ if ((epint & OTG_DIEPINT_ITTXFE) == OTG_DIEPINT_ITTXFE) {
+ mmio_write_32(reg_offset, OTG_DIEPINT_ITTXFE);
+ }
+
+ if ((epint & OTG_DIEPINT_INEPNE) == OTG_DIEPINT_INEPNE) {
+ mmio_write_32(reg_offset, OTG_DIEPINT_INEPNE);
+ }
+
+ if ((epint & OTG_DIEPINT_EPDISD) == OTG_DIEPINT_EPDISD) {
+ mmio_write_32(reg_offset, OTG_DIEPINT_EPDISD);
+ }
+
+ if ((epint & OTG_DIEPINT_TXFE) == OTG_DIEPINT_TXFE) {
+ *param = epnum;
+
+ return USB_WRITE_EMPTY;
+ }
+ }
+
+ /* Handle resume interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_WKUPINT) != 0U) {
+ INFO("handle USB : Resume\n");
+
+ /* Clear the remote wake-up signaling */
+ mmio_clrbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_RWUSIG);
+ mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_WKUPINT);
+
+ return USB_RESUME;
+ }
+
+ /* Handle suspend interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_USBSUSP) != 0U) {
+ INFO("handle USB : Suspend int\n");
+
+ mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_USBSUSP);
+
+ if ((mmio_read_32(usb_base_addr + OTG_DSTS) &
+ OTG_DSTS_SUSPSTS) == OTG_DSTS_SUSPSTS) {
+ return USB_SUSPEND;
+ }
+ }
+
+ /* Handle LPM interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_LPMINT) != 0U) {
+ INFO("handle USB : LPM int enter in suspend\n");
+
+ mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_LPMINT);
+ *param = (mmio_read_32(usb_base_addr + OTG_GLPMCFG) &
+ OTG_GLPMCFG_BESL) >> 2;
+
+ return USB_LPM;
+ }
+
+ /* Handle reset interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_USBRST) != 0U) {
+ INFO("handle USB : Reset\n");
+
+ mmio_clrbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_RWUSIG);
+
+ usb_dwc2_flush_tx_fifo(handle, 0U);
+
+ mmio_write_32(usb_base_addr + OTG_DAINT, OTG_DAINT_IN_MASK | OTG_DAINT_OUT_MASK);
+ mmio_setbits_32(usb_base_addr + OTG_DAINTMSK, OTG_DAINT_EP0_IN | OTG_DAINT_EP0_OUT);
+
+ mmio_setbits_32(usb_base_addr + OTG_DOEPMSK, OTG_DOEPMSK_STUPM |
+ OTG_DOEPMSK_XFRCM |
+ OTG_DOEPMSK_EPDM);
+ mmio_setbits_32(usb_base_addr + OTG_DIEPMSK, OTG_DIEPMSK_TOM |
+ OTG_DIEPMSK_XFRCM |
+ OTG_DIEPMSK_EPDM);
+
+ /* Set default address to 0 */
+ mmio_clrbits_32(usb_base_addr + OTG_DCFG, OTG_DCFG_DAD);
+
+ /* Setup EP0 to receive SETUP packets */
+ ret = usb_dwc2_ep0_out_start(handle);
+ if (ret != USBD_OK) {
+ return ret;
+ }
+
+ mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_USBRST);
+
+ return USB_RESET;
+ }
+
+ /* Handle enumeration done interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_ENUMDNE) != 0U) {
+ ret = usb_dwc2_activate_setup(handle);
+ if (ret != USBD_OK) {
+ return ret;
+ }
+
+ mmio_clrbits_32(usb_base_addr + OTG_GUSBCFG, OTG_GUSBCFG_TRDT);
+
+ mmio_setbits_32(usb_base_addr + OTG_GUSBCFG,
+ (USBD_HS_TRDT_VALUE << OTG_GUSBCFG_TRDT_SHIFT) & OTG_GUSBCFG_TRDT);
+
+ mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_ENUMDNE);
+
+ return USB_ENUM_DONE;
+ }
+
+ /* Handle RXQLevel interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_RXFLVL) != 0U) {
+ mmio_clrbits_32(usb_base_addr + OTG_GINTMSK,
+ OTG_GINTSTS_RXFLVL);
+
+ temp = mmio_read_32(usb_base_addr + OTG_GRXSTSP);
+
+ *param = temp & OTG_GRXSTSP_EPNUM;
+ *param |= (temp & OTG_GRXSTSP_BCNT) << (USBD_OUT_COUNT_SHIFT -
+ OTG_GRXSTSP_BCNT_SHIFT);
+
+ if (((temp & OTG_GRXSTSP_PKTSTS) >> OTG_GRXSTSP_PKTSTS_SHIFT) == STS_DATA_UPDT) {
+ if ((temp & OTG_GRXSTSP_BCNT) != 0U) {
+ mmio_setbits_32(usb_base_addr + OTG_GINTMSK, OTG_GINTSTS_RXFLVL);
+
+ return USB_READ_DATA_PACKET;
+ }
+ } else if (((temp & OTG_GRXSTSP_PKTSTS) >> OTG_GRXSTSP_PKTSTS_SHIFT) ==
+ STS_SETUP_UPDT) {
+ mmio_setbits_32(usb_base_addr + OTG_GINTMSK, OTG_GINTSTS_RXFLVL);
+
+ return USB_READ_SETUP_PACKET;
+ }
+
+ mmio_setbits_32(usb_base_addr + OTG_GINTMSK, OTG_GINTSTS_RXFLVL);
+ }
+
+ /* Handle SOF interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_SOF) != 0U) {
+ INFO("handle USB : SOF\n");
+
+ mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_SOF);
+
+ return USB_SOF;
+ }
+
+ /* Handle incomplete ISO IN interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_IISOIXFR) != 0U) {
+ INFO("handle USB : ISO IN\n");
+
+ mmio_write_32(usb_base_addr + OTG_GINTSTS,
+ OTG_GINTSTS_IISOIXFR);
+ }
+
+ /* Handle incomplete ISO OUT interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_IPXFR_INCOMPISOOUT) !=
+ 0U) {
+ INFO("handle USB : ISO OUT\n");
+
+ mmio_write_32(usb_base_addr + OTG_GINTSTS,
+ OTG_GINTSTS_IPXFR_INCOMPISOOUT);
+ }
+
+ /* Handle connection event interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_SRQINT) != 0U) {
+ INFO("handle USB : Connect\n");
+
+ mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_SRQINT);
+ }
+
+ /* Handle disconnection event interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_OTGINT) != 0U) {
+ INFO("handle USB : Disconnect\n");
+
+ temp = mmio_read_32(usb_base_addr + OTG_GOTGINT);
+
+ if ((temp & OTG_GOTGINT_SEDET) == OTG_GOTGINT_SEDET) {
+ return USB_DISCONNECT;
+ }
+ }
+
+ return USB_NOTHING;
+}
+
+/*
+ * Start the usb device mode
+ * usb_core_handle: USB core driver handle.
+ * return USB status.
+ */
+static enum usb_status usb_dwc2_start_device(void *handle)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+
+ mmio_clrbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_SDIS);
+ mmio_setbits_32(usb_base_addr + OTG_GAHBCFG, OTG_GAHBCFG_GINT);
+
+ return USBD_OK;
+}
+
+static const struct usb_driver usb_dwc2driver = {
+ .ep0_out_start = usb_dwc2_ep0_out_start,
+ .ep_start_xfer = usb_dwc2_ep_start_xfer,
+ .ep0_start_xfer = usb_dwc2_ep0_start_xfer,
+ .write_packet = usb_dwc2_write_packet,
+ .read_packet = usb_dwc2_read_packet,
+ .ep_set_stall = usb_dwc2_ep_set_stall,
+ .start_device = usb_dwc2_start_device,
+ .stop_device = usb_dwc2_stop_device,
+ .set_address = usb_dwc2_set_address,
+ .write_empty_tx_fifo = usb_dwc2_write_empty_tx_fifo,
+ .it_handler = usb_dwc2_it_handler
+};
+
+/*
+ * Initialize USB DWC2 driver.
+ * usb_core_handle: USB core driver handle.
+ * pcd_handle: PCD handle.
+ * base_register: USB global register base address.
+ */
+void stm32mp1_usb_init_driver(struct usb_handle *usb_core_handle,
+ struct pcd_handle *pcd_handle,
+ void *base_register)
+{
+ register_usb_driver(usb_core_handle, pcd_handle, &usb_dwc2driver,
+ base_register);
+}
diff --git a/drivers/synopsys/emmc/dw_mmc.c b/drivers/synopsys/emmc/dw_mmc.c
new file mode 100644
index 0000000..04f4673
--- /dev/null
+++ b/drivers/synopsys/emmc/dw_mmc.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/mmc.h>
+#include <drivers/synopsys/dw_mmc.h>
+#include <lib/utils_def.h>
+#include <lib/mmio.h>
+
+#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);
+}
diff --git a/drivers/synopsys/ufs/dw_ufs.c b/drivers/synopsys/ufs/dw_ufs.c
new file mode 100644
index 0000000..6bed981
--- /dev/null
+++ b/drivers/synopsys/ufs/dw_ufs.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/dw_ufs.h>
+#include <drivers/ufs.h>
+#include <lib/mmio.h>
+
+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;
+}
diff --git a/drivers/ti/uart/aarch32/16550_console.S b/drivers/ti/uart/aarch32/16550_console.S
new file mode 100644
index 0000000..0429f87
--- /dev/null
+++ b/drivers/ti/uart/aarch32/16550_console.S
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console_macros.S>
+#include <drivers/ti/uart/uart_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_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_16550_register(uintptr_t baseaddr,
+ * uint32_t clock, uint32_t baud,
+ * console_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).
+ * If r1 (UART clock) is 0, initialisation will be
+ * skipped, relying on previous code to have done
+ * this already. r2 is ignored then as well.
+ * In: r0 - UART register base address
+ * r1 - UART clock in Hz
+ * r2 - Baud rate (ignored if r1 is 0)
+ * r3 - pointer to empty console_t 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_BASE]
+
+ /* A clock rate of zero means to skip the initialisation. */
+ cmp r1, #0
+ beq register_16550
+
+ bl console_16550_core_init
+ cmp r0, #0
+ beq register_fail
+
+register_16550:
+ 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_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_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_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_BASE]
+ b console_16550_core_getc
+endfunc console_16550_getc
+
+ /* ---------------------------------------------
+ * void 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 : void.
+ * 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
+
+ bx lr
+endfunc console_16550_core_flush
+
+ /* ---------------------------------------------
+ * void console_16550_flush(console_t *console)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * In : r0 - pointer to console_t structure
+ * Out : void
+ * 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_BASE]
+ b console_16550_core_flush
+endfunc console_16550_flush
diff --git a/drivers/ti/uart/aarch64/16550_console.S b/drivers/ti/uart/aarch64/16550_console.S
new file mode 100644
index 0000000..cb21512
--- /dev/null
+++ b/drivers/ti/uart/aarch64/16550_console.S
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console_macros.S>
+#include <drivers/ti/uart/uart_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_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_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).
+ * If w1 (UART clock) is 0, initialisation will be
+ * skipped, relying on previous code to have done
+ * this already. w2 is ignored then as well.
+ * In: x0 - UART register base address
+ * w1 - UART clock in Hz
+ * w2 - Baud rate (ignored if w1 is 0)
+ * x3 - pointer to empty console_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_BASE]
+
+ /* A clock rate of zero means to skip the initialisation. */
+ cbz w1, register_16550
+
+ bl console_16550_core_init
+ cbz x0, register_fail
+
+register_16550:
+ 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_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_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_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_BASE]
+ b console_16550_core_getc
+endfunc console_16550_getc
+
+ /* ---------------------------------------------
+ * void 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 : void.
+ * 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
+
+ ret
+endfunc console_16550_core_flush
+
+ /* ---------------------------------------------
+ * void console_16550_flush(console_t *console)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * In : x0 - pointer to console_t structure
+ * Out : void.
+ * 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_BASE]
+ b console_16550_core_flush
+endfunc console_16550_flush
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
new file mode 100644
index 0000000..d8c0a14
--- /dev/null
+++ b/drivers/ufs/ufs.c
@@ -0,0 +1,911 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <endian.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/ufs.h>
+#include <lib/mmio.h>
+
+#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;
+
+ if (base == 0 || cmd == NULL)
+ return -EINVAL;
+
+ 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 result, retries;
+ uic_cmd_t cmd;
+
+ assert(ufs_params.reg_base != 0);
+
+ if (val == NULL)
+ return -EINVAL;
+
+ 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;
+
+ cmd.arg1 = (attr << 16) | GEN_SELECTOR_IDX(idx);
+ cmd.arg2 = 0;
+ cmd.arg3 = 0;
+ cmd.op = DME_GET;
+ for (retries = 0; retries < UFS_UIC_COMMAND_RETRIES; ++retries) {
+ result = ufshc_send_uic_cmd(base, &cmd);
+ if (result == 0)
+ break;
+ data = mmio_read_32(base + IS);
+ if (data & UFS_INT_UE)
+ return -EINVAL;
+ }
+ if (retries >= UFS_UIC_COMMAND_RETRIES)
+ return -EIO;
+
+ *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;
+ int result, retries;
+ uic_cmd_t cmd;
+
+ assert((ufs_params.reg_base != 0));
+
+ base = ufs_params.reg_base;
+ cmd.arg1 = (attr << 16) | GEN_SELECTOR_IDX(idx);
+ cmd.arg2 = 0;
+ cmd.arg3 = val;
+ cmd.op = DME_SET;
+
+ for (retries = 0; retries < UFS_UIC_COMMAND_RETRIES; ++retries) {
+ result = ufshc_send_uic_cmd(base, &cmd);
+ if (result == 0)
+ break;
+ data = mmio_read_32(base + IS);
+ if (data & UFS_INT_UE)
+ return -EINVAL;
+ }
+ if (retries >= UFS_UIC_COMMAND_RETRIES)
+ return -EIO;
+
+ return 0;
+}
+
+static int ufshc_hce_enable(uintptr_t base)
+{
+ unsigned int data;
+ int retries;
+
+ /* Enable Host Controller */
+ mmio_write_32(base + HCE, HCE_ENABLE);
+
+ /* Wait until basic initialization sequence completed */
+ for (retries = 0; retries < HCE_ENABLE_INNER_RETRIES; ++retries) {
+ data = mmio_read_32(base + HCE);
+ if (data & HCE_ENABLE) {
+ break;
+ }
+ udelay(HCE_ENABLE_TIMEOUT_US);
+ }
+ if (retries >= HCE_ENABLE_INNER_RETRIES) {
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int ufshc_hce_disable(uintptr_t base)
+{
+ unsigned int data;
+ int timeout;
+
+ /* Disable Host Controller */
+ mmio_write_32(base + HCE, HCE_DISABLE);
+ timeout = HCE_DISABLE_TIMEOUT_US;
+ do {
+ data = mmio_read_32(base + HCE);
+ if ((data & HCE_ENABLE) == HCE_DISABLE) {
+ break;
+ }
+ udelay(1);
+ } while (--timeout > 0);
+
+ if (timeout <= 0) {
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+
+static int ufshc_reset(uintptr_t base)
+{
+ unsigned int data;
+ int retries, result;
+
+ /* disable controller if enabled */
+ if (mmio_read_32(base + HCE) & HCE_ENABLE) {
+ result = ufshc_hce_disable(base);
+ if (result != 0) {
+ return -EIO;
+ }
+ }
+
+ for (retries = 0; retries < HCE_ENABLE_OUTER_RETRIES; ++retries) {
+ result = ufshc_hce_enable(base);
+ if (result == 0) {
+ break;
+ }
+ }
+ if (retries >= HCE_ENABLE_OUTER_RETRIES) {
+ return -EIO;
+ }
+
+ /* 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);
+
+ return 0;
+}
+
+static int ufshc_dme_link_startup(uintptr_t base)
+{
+ uic_cmd_t cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op = DME_LINKSTARTUP;
+ return ufshc_send_uic_cmd(base, &cmd);
+}
+
+static int ufshc_link_startup(uintptr_t base)
+{
+ int data, result;
+ int retries;
+
+ for (retries = DME_LINKSTARTUP_RETRIES; retries > 0; retries--) {
+ result = ufshc_dme_link_startup(base);
+ if (result != 0) {
+ /* Reset controller before trying again */
+ result = ufshc_reset(base);
+ if (result != 0) {
+ return result;
+ }
+ continue;
+ }
+ assert((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 * sizeof(utrd_header_t));
+ /* 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;
+
+ 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->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;
+
+ 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;
+ query_upiu->ts.attr.value = htobe32(*((uint32_t *)buf));
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ 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;
+
+ 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->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);
+ assert(mmio_read_32(ufs_params.reg_base + UTRLRSR) == 1);
+
+ 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;
+ sense_data_t *sense;
+ unsigned int data;
+ int slot;
+
+ hd = (utrd_header_t *)utrd->header;
+ resp = (resp_upiu_t *)utrd->resp_upiu;
+ 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);
+ /*
+ * Invalidate the header after DMA read operation has
+ * completed to avoid cpu referring to the prefetched
+ * data brought in before DMA completion.
+ */
+ inv_dcache_range((uintptr_t)hd, UFS_DESC_SIZE);
+ assert(hd->ocs == OCS_SUCCESS);
+ assert((resp->trans_type & TRANS_TYPE_CODE_MASK) == trans_type);
+
+ sense = &resp->sd.sense;
+ if (sense->resp_code == SENSE_DATA_VALID &&
+ sense->sense_key == SENSE_KEY_UNIT_ATTENTION && sense->asc == 0x29 &&
+ sense->ascq == 0) {
+ WARN("Unit Attention Condition\n");
+ return -EAGAIN;
+ }
+
+ (void)resp;
+ (void)slot;
+ return 0;
+}
+
+static void ufs_send_cmd(utp_utrd_t *utrd, uint8_t cmd_op, uint8_t lun, int lba, uintptr_t buf,
+ size_t length)
+{
+ int result, i;
+
+ for (i = 0; i < UFS_CMD_RETRIES; ++i) {
+ get_utrd(utrd);
+ result = ufs_prepare_cmd(utrd, cmd_op, lun, lba, buf, length);
+ assert(result == 0);
+ ufs_send_request(utrd->task_tag);
+ result = ufs_check_resp(utrd, RESPONSE_UPIU);
+ if (result == 0 || result == -EIO) {
+ break;
+ }
+ }
+ assert(result == 0);
+ (void)result;
+}
+
+#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;
+ ufs_send_cmd(&utrd, CDBCMD_TEST_UNIT_READY, 0, 0, 0, 0);
+}
+
+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_DESC:
+ memcpy((void *)buf,
+ (void *)(utrd.resp_upiu + sizeof(query_resp_upiu_t)),
+ size);
+ break;
+ case QUERY_READ_ATTR:
+ *(uint32_t *)buf = htobe32(resp->ts.attr.value);
+ 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 int 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 retries = UFS_READ_CAPACITY_RETRIES;
+
+ 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);
+ do {
+ ufs_send_cmd(&utrd, CDBCMD_READ_CAPACITY_10, lun, 0,
+ buf, READ_CAPACITY_LENGTH);
+#ifdef UFS_RESP_DEBUG
+ dump_upiu(&utrd);
+#endif
+ resp = (resp_upiu_t *)utrd.resp_upiu;
+ sense = &resp->sd.sense;
+ if (!((sense->resp_code == SENSE_DATA_VALID) &&
+ (sense->sense_key == SENSE_KEY_UNIT_ATTENTION) &&
+ (sense->asc == 0x29) && (sense->ascq == 0))) {
+ 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));
+
+ return 0;
+ }
+
+ } while (retries-- > 0);
+
+ return -ETIMEDOUT;
+}
+
+size_t ufs_read_blocks(int lun, int lba, uintptr_t buf, size_t size)
+{
+ utp_utrd_t utrd;
+ resp_upiu_t *resp;
+
+ assert((ufs_params.reg_base != 0) &&
+ (ufs_params.desc_base != 0) &&
+ (ufs_params.desc_size >= UFS_DESC_SIZE));
+
+ ufs_send_cmd(&utrd, CDBCMD_READ_10, lun, lba, buf, size);
+#ifdef UFS_RESP_DEBUG
+ dump_upiu(&utrd);
+#endif
+ /*
+ * Invalidate prefetched cache contents before cpu
+ * accesses the buf.
+ */
+ inv_dcache_range(buf, size);
+ resp = (resp_upiu_t *)utrd.resp_upiu;
+ 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;
+
+ assert((ufs_params.reg_base != 0) &&
+ (ufs_params.desc_base != 0) &&
+ (ufs_params.desc_size >= UFS_DESC_SIZE));
+
+ ufs_send_cmd(&utrd, CDBCMD_WRITE_10, lun, lba, buf, size);
+#ifdef UFS_RESP_DEBUG
+ dump_upiu(&utrd);
+#endif
+ resp = (resp_upiu_t *)utrd.resp_upiu;
+ return size - resp->res_trans_cnt;
+}
+
+static int ufs_set_fdevice_init(void)
+{
+ unsigned int result;
+ int timeout;
+
+ ufs_set_flag(FLAG_DEVICE_INIT);
+
+ timeout = FDEVICEINIT_TIMEOUT_MS;
+ do {
+ result = ufs_read_flag(FLAG_DEVICE_INIT);
+ if (!result) {
+ break;
+ }
+ mdelay(5);
+ timeout -= 5;
+ } while (timeout > 0);
+
+ if (result != 0U) {
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static void ufs_enum(void)
+{
+ unsigned int blk_num, blk_size;
+ int i, result;
+
+ mmio_write_32(ufs_params.reg_base + UTRLBA,
+ ufs_params.desc_base & UINT32_MAX);
+ mmio_write_32(ufs_params.reg_base + UTRLBAU,
+ (ufs_params.desc_base >> 32) & UINT32_MAX);
+
+ ufs_verify_init();
+ ufs_verify_ready();
+
+ result = ufs_set_fdevice_init();
+ assert(result == 0);
+
+ blk_num = 0;
+ blk_size = 0;
+
+ /* dump available LUNs */
+ for (i = 0; i < UFS_MAX_LUNS; i++) {
+ result = ufs_read_capacity(i, &blk_num, &blk_size);
+ if (result != 0) {
+ WARN("UFS LUN%d dump failed\n", i);
+ }
+ if (blk_num && blk_size) {
+ INFO("UFS LUN%d contains %d blocks with %d-byte size\n",
+ i, blk_num, blk_size);
+ }
+ }
+
+ (void)result;
+}
+
+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));
+
+ /* 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;
+ }
+
+
+ if (ufs_params.flags & UFS_FLAGS_SKIPINIT) {
+ mmio_write_32(ufs_params.reg_base + UTRLBA,
+ ufs_params.desc_base & UINT32_MAX);
+ mmio_write_32(ufs_params.reg_base + UTRLBAU,
+ (ufs_params.desc_base >> 32) & UINT32_MAX);
+
+ 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));
+
+ result = ufshc_reset(ufs_params.reg_base);
+ assert(result == 0);
+ 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;
+}
diff --git a/drivers/usb/usb_device.c b/drivers/usb/usb_device.c
new file mode 100644
index 0000000..701f301
--- /dev/null
+++ b/drivers/usb/usb_device.c
@@ -0,0 +1,845 @@
+/*
+ * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <drivers/usb_device.h>
+
+/* Define for EP address */
+#define EP_DIR_MASK BIT(7)
+#define EP_DIR_IN BIT(7)
+#define EP_NUM_MASK GENMASK(3, 0)
+
+#define EP0_IN (0U | EP_DIR_IN)
+#define EP0_OUT 0U
+
+/* USB address between 1 through 127 = 0x7F mask */
+#define ADDRESS_MASK GENMASK(6, 0)
+
+/*
+ * Set a STALL condition over an endpoint
+ * pdev: USB handle
+ * ep_addr: endpoint address
+ * return : status
+ */
+static enum usb_status usb_core_set_stall(struct usb_handle *pdev, uint8_t ep_addr)
+{
+ struct usbd_ep *ep;
+ struct pcd_handle *hpcd = (struct pcd_handle *)pdev->data;
+ uint8_t num;
+
+ num = ep_addr & EP_NUM_MASK;
+ if (num >= USBD_EP_NB) {
+ return USBD_FAIL;
+ }
+ if ((EP_DIR_MASK & ep_addr) == EP_DIR_IN) {
+ ep = &hpcd->in_ep[num];
+ ep->is_in = true;
+ } else {
+ ep = &hpcd->out_ep[num];
+ ep->is_in = false;
+ }
+ ep->num = num;
+
+ pdev->driver->ep_set_stall(hpcd->instance, ep);
+ if (num == 0U) {
+ pdev->driver->ep0_out_start(hpcd->instance);
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_get_desc
+ * Handle Get Descriptor requests
+ * pdev : device instance
+ * req : usb request
+ */
+static void usb_core_get_desc(struct usb_handle *pdev, struct usb_setup_req *req)
+{
+ uint16_t len;
+ uint8_t *pbuf;
+ uint8_t desc_type = HIBYTE(req->value);
+ uint8_t desc_idx = LOBYTE(req->value);
+
+ switch (desc_type) {
+ case USB_DESC_TYPE_DEVICE:
+ pbuf = pdev->desc->get_device_desc(&len);
+ break;
+
+ case USB_DESC_TYPE_CONFIGURATION:
+ pbuf = pdev->desc->get_config_desc(&len);
+ break;
+
+ case USB_DESC_TYPE_STRING:
+ switch (desc_idx) {
+ case USBD_IDX_LANGID_STR:
+ pbuf = pdev->desc->get_lang_id_desc(&len);
+ break;
+
+ case USBD_IDX_MFC_STR:
+ pbuf = pdev->desc->get_manufacturer_desc(&len);
+ break;
+
+ case USBD_IDX_PRODUCT_STR:
+ pbuf = pdev->desc->get_product_desc(&len);
+ break;
+
+ case USBD_IDX_SERIAL_STR:
+ pbuf = pdev->desc->get_serial_desc(&len);
+ break;
+
+ case USBD_IDX_CONFIG_STR:
+ pbuf = pdev->desc->get_configuration_desc(&len);
+ break;
+
+ case USBD_IDX_INTERFACE_STR:
+ pbuf = pdev->desc->get_interface_desc(&len);
+ break;
+
+ /* For all USER string */
+ case USBD_IDX_USER0_STR:
+ default:
+ pbuf = pdev->desc->get_usr_desc(desc_idx - USBD_IDX_USER0_STR, &len);
+ break;
+ }
+ break;
+
+ case USB_DESC_TYPE_DEVICE_QUALIFIER:
+ pbuf = pdev->desc->get_device_qualifier_desc(&len);
+ break;
+
+ case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION:
+ if (pdev->desc->get_other_speed_config_desc == NULL) {
+ usb_core_ctl_error(pdev);
+ return;
+ }
+ pbuf = pdev->desc->get_other_speed_config_desc(&len);
+ break;
+
+ default:
+ ERROR("Unknown request %i\n", desc_type);
+ usb_core_ctl_error(pdev);
+ return;
+ }
+
+ if ((len != 0U) && (req->length != 0U)) {
+ len = MIN(len, req->length);
+
+ /* Start the transfer */
+ usb_core_transmit_ep0(pdev, pbuf, len);
+ }
+}
+
+/*
+ * usb_core_set_config
+ * Handle Set device configuration request
+ * pdev : device instance
+ * req : usb request
+ */
+static void usb_core_set_config(struct usb_handle *pdev, struct usb_setup_req *req)
+{
+ static uint8_t cfgidx;
+
+ cfgidx = LOBYTE(req->value);
+
+ if (cfgidx > USBD_MAX_NUM_CONFIGURATION) {
+ usb_core_ctl_error(pdev);
+ return;
+ }
+
+ switch (pdev->dev_state) {
+ case USBD_STATE_ADDRESSED:
+ if (cfgidx != 0U) {
+ pdev->dev_config = cfgidx;
+ pdev->dev_state = USBD_STATE_CONFIGURED;
+ if (!pdev->class) {
+ usb_core_ctl_error(pdev);
+ return;
+ }
+ /* Set configuration and Start the Class */
+ if (pdev->class->init(pdev, cfgidx) != 0U) {
+ usb_core_ctl_error(pdev);
+ return;
+ }
+ }
+ break;
+
+ case USBD_STATE_CONFIGURED:
+ if (cfgidx == 0U) {
+ pdev->dev_state = USBD_STATE_ADDRESSED;
+ pdev->dev_config = cfgidx;
+ pdev->class->de_init(pdev, cfgidx);
+ } else if (cfgidx != pdev->dev_config) {
+ if (pdev->class == NULL) {
+ usb_core_ctl_error(pdev);
+ return;
+ }
+ /* Clear old configuration */
+ pdev->class->de_init(pdev, pdev->dev_config);
+ /* Set new configuration */
+ pdev->dev_config = cfgidx;
+ /* Set configuration and start the USB class */
+ if (pdev->class->init(pdev, cfgidx) != 0U) {
+ usb_core_ctl_error(pdev);
+ return;
+ }
+ }
+ break;
+
+ default:
+ usb_core_ctl_error(pdev);
+ return;
+ }
+
+ /* Send status */
+ usb_core_transmit_ep0(pdev, NULL, 0U);
+}
+
+/*
+ * usb_core_get_status
+ * Handle Get Status request
+ * pdev : device instance
+ * req : usb request
+ */
+static void usb_core_get_status(struct usb_handle *pdev,
+ struct usb_setup_req *req)
+{
+ if ((pdev->dev_state != USBD_STATE_ADDRESSED) &&
+ (pdev->dev_state != USBD_STATE_CONFIGURED)) {
+ usb_core_ctl_error(pdev);
+ return;
+ }
+
+ pdev->dev_config_status = USB_CONFIG_SELF_POWERED;
+
+ if (pdev->dev_remote_wakeup != 0U) {
+ pdev->dev_config_status |= USB_CONFIG_REMOTE_WAKEUP;
+ }
+
+ /* Start the transfer */
+ usb_core_transmit_ep0(pdev, (uint8_t *)&pdev->dev_config_status, 2U);
+}
+
+/*
+ * usb_core_set_address
+ * Set device address
+ * pdev : device instance
+ * req : usb request
+ */
+static void usb_core_set_address(struct usb_handle *pdev,
+ struct usb_setup_req *req)
+{
+ uint8_t dev_addr;
+
+ if ((req->index != 0U) || (req->length != 0U)) {
+ usb_core_ctl_error(pdev);
+ return;
+ }
+
+ dev_addr = req->value & ADDRESS_MASK;
+ if (pdev->dev_state != USBD_STATE_DEFAULT) {
+ usb_core_ctl_error(pdev);
+ return;
+ }
+
+ pdev->dev_address = dev_addr;
+ pdev->driver->set_address(((struct pcd_handle *)(pdev->data))->instance, dev_addr);
+
+ /* Send status */
+ usb_core_transmit_ep0(pdev, NULL, 0U);
+
+ if (dev_addr != 0U) {
+ pdev->dev_state = USBD_STATE_ADDRESSED;
+ } else {
+ pdev->dev_state = USBD_STATE_DEFAULT;
+ }
+}
+
+/*
+ * usb_core_dev_req
+ * Handle standard usb device requests
+ * pdev : device instance
+ * req : usb request
+ * return : status
+ */
+static enum usb_status usb_core_dev_req(struct usb_handle *pdev,
+ struct usb_setup_req *req)
+{
+ VERBOSE("receive request %i\n", req->b_request);
+ switch (req->b_request) {
+ case USB_REQ_GET_DESCRIPTOR:
+ usb_core_get_desc(pdev, req);
+ break;
+
+ case USB_REQ_SET_CONFIGURATION:
+ usb_core_set_config(pdev, req);
+ break;
+
+ case USB_REQ_GET_STATUS:
+ usb_core_get_status(pdev, req);
+ break;
+
+ case USB_REQ_SET_ADDRESS:
+ usb_core_set_address(pdev, req);
+ break;
+
+ case USB_REQ_GET_CONFIGURATION:
+ case USB_REQ_SET_FEATURE:
+ case USB_REQ_CLEAR_FEATURE:
+ default:
+ ERROR("NOT SUPPORTED %i\n", req->b_request);
+ usb_core_ctl_error(pdev);
+ break;
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_itf_req
+ * Handle standard usb interface requests
+ * pdev : device instance
+ * req : usb request
+ * return : status
+ */
+static enum usb_status usb_core_itf_req(struct usb_handle *pdev,
+ struct usb_setup_req *req)
+{
+ if (pdev->dev_state != USBD_STATE_CONFIGURED) {
+ usb_core_ctl_error(pdev);
+ return USBD_OK;
+ }
+
+ if (LOBYTE(req->index) <= USBD_MAX_NUM_INTERFACES) {
+ pdev->class->setup(pdev, req);
+
+ if (req->length == 0U) {
+ usb_core_transmit_ep0(pdev, NULL, 0U);
+ }
+ } else {
+ usb_core_ctl_error(pdev);
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_setup_stage
+ * Handle the setup stage
+ * pdev: device instance
+ * psetup : setup buffer
+ * return : status
+ */
+static enum usb_status usb_core_setup_stage(struct usb_handle *pdev,
+ uint8_t *psetup)
+{
+ struct usb_setup_req *req = &pdev->request;
+
+ /* Copy setup buffer into req structure */
+ req->bm_request = psetup[0];
+ req->b_request = psetup[1];
+ req->value = psetup[2] + (psetup[3] << 8);
+ req->index = psetup[4] + (psetup[5] << 8);
+ req->length = psetup[6] + (psetup[7] << 8);
+
+ pdev->ep0_state = USBD_EP0_SETUP;
+ pdev->ep0_data_len = pdev->request.length;
+
+ switch (pdev->request.bm_request & USB_REQ_RECIPIENT_MASK) {
+ case USB_REQ_RECIPIENT_DEVICE:
+ usb_core_dev_req(pdev, &pdev->request);
+ break;
+
+ case USB_REQ_RECIPIENT_INTERFACE:
+ usb_core_itf_req(pdev, &pdev->request);
+ break;
+
+ case USB_REQ_RECIPIENT_ENDPOINT:
+ default:
+ ERROR("receive unsupported request %u",
+ pdev->request.bm_request & USB_REQ_RECIPIENT_MASK);
+ usb_core_set_stall(pdev, pdev->request.bm_request & USB_REQ_DIRECTION);
+ return USBD_FAIL;
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_data_out
+ * Handle data OUT stage
+ * pdev: device instance
+ * epnum: endpoint index
+ * pdata: buffer to sent
+ * return : status
+ */
+static enum usb_status usb_core_data_out(struct usb_handle *pdev, uint8_t epnum,
+ uint8_t *pdata)
+{
+ struct usb_endpoint *pep;
+
+ if (epnum == 0U) {
+ pep = &pdev->ep_out[0];
+ if (pdev->ep0_state == USBD_EP0_DATA_OUT) {
+ if (pep->rem_length > pep->maxpacket) {
+ pep->rem_length -= pep->maxpacket;
+
+ usb_core_receive(pdev, 0U, pdata,
+ MIN(pep->rem_length,
+ pep->maxpacket));
+ } else {
+ if (pdev->class->ep0_rx_ready &&
+ (pdev->dev_state == USBD_STATE_CONFIGURED)) {
+ pdev->class->ep0_rx_ready(pdev);
+ }
+
+ usb_core_transmit_ep0(pdev, NULL, 0U);
+ }
+ }
+ } else if (pdev->class->data_out != NULL &&
+ (pdev->dev_state == USBD_STATE_CONFIGURED)) {
+ pdev->class->data_out(pdev, epnum);
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_data_in
+ * Handle data in stage
+ * pdev: device instance
+ * epnum: endpoint index
+ * pdata: buffer to fill
+ * return : status
+ */
+static enum usb_status usb_core_data_in(struct usb_handle *pdev, uint8_t epnum,
+ uint8_t *pdata)
+{
+ if (epnum == 0U) {
+ struct usb_endpoint *pep = &pdev->ep_in[0];
+
+ if (pdev->ep0_state == USBD_EP0_DATA_IN) {
+ if (pep->rem_length > pep->maxpacket) {
+ pep->rem_length -= pep->maxpacket;
+
+ usb_core_transmit(pdev, 0U, pdata,
+ pep->rem_length);
+
+ /* Prepare EP for premature end of transfer */
+ usb_core_receive(pdev, 0U, NULL, 0U);
+ } else {
+ /* Last packet is MPS multiple, send ZLP packet */
+ if ((pep->total_length % pep->maxpacket == 0U) &&
+ (pep->total_length >= pep->maxpacket) &&
+ (pep->total_length < pdev->ep0_data_len)) {
+ usb_core_transmit(pdev, 0U, NULL, 0U);
+
+ pdev->ep0_data_len = 0U;
+
+ /* Prepare endpoint for premature end of transfer */
+ usb_core_receive(pdev, 0U, NULL, 0U);
+ } else {
+ if (pdev->class->ep0_tx_sent != NULL &&
+ (pdev->dev_state ==
+ USBD_STATE_CONFIGURED)) {
+ pdev->class->ep0_tx_sent(pdev);
+ }
+ /* Start the transfer */
+ usb_core_receive_ep0(pdev, NULL, 0U);
+ }
+ }
+ }
+ } else if ((pdev->class->data_in != NULL) &&
+ (pdev->dev_state == USBD_STATE_CONFIGURED)) {
+ pdev->class->data_in(pdev, epnum);
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_suspend
+ * Handle suspend event
+ * pdev : device instance
+ * return : status
+ */
+static enum usb_status usb_core_suspend(struct usb_handle *pdev)
+{
+ INFO("USB Suspend mode\n");
+ pdev->dev_old_state = pdev->dev_state;
+ pdev->dev_state = USBD_STATE_SUSPENDED;
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_resume
+ * Handle resume event
+ * pdev : device instance
+ * return : status
+ */
+static enum usb_status usb_core_resume(struct usb_handle *pdev)
+{
+ INFO("USB Resume\n");
+ pdev->dev_state = pdev->dev_old_state;
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_sof
+ * Handle SOF event
+ * pdev : device instance
+ * return : status
+ */
+static enum usb_status usb_core_sof(struct usb_handle *pdev)
+{
+ if (pdev->dev_state == USBD_STATE_CONFIGURED) {
+ if (pdev->class->sof != NULL) {
+ pdev->class->sof(pdev);
+ }
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_disconnect
+ * Handle device disconnection event
+ * pdev : device instance
+ * return : status
+ */
+static enum usb_status usb_core_disconnect(struct usb_handle *pdev)
+{
+ /* Free class resources */
+ pdev->dev_state = USBD_STATE_DEFAULT;
+ pdev->class->de_init(pdev, pdev->dev_config);
+
+ return USBD_OK;
+}
+
+enum usb_status usb_core_handle_it(struct usb_handle *pdev)
+{
+ uint32_t param = 0U;
+ uint32_t len = 0U;
+ struct usbd_ep *ep;
+
+ switch (pdev->driver->it_handler(pdev->data->instance, &param)) {
+ case USB_DATA_OUT:
+ usb_core_data_out(pdev, param,
+ pdev->data->out_ep[param].xfer_buff);
+ break;
+
+ case USB_DATA_IN:
+ usb_core_data_in(pdev, param,
+ pdev->data->in_ep[param].xfer_buff);
+ break;
+
+ case USB_SETUP:
+ usb_core_setup_stage(pdev, (uint8_t *)pdev->data->setup);
+ break;
+
+ case USB_ENUM_DONE:
+ break;
+
+ case USB_READ_DATA_PACKET:
+ ep = &pdev->data->out_ep[param & USBD_OUT_EPNUM_MASK];
+ len = (param & USBD_OUT_COUNT_MASK) >> USBD_OUT_COUNT_SHIFT;
+ pdev->driver->read_packet(pdev->data->instance,
+ ep->xfer_buff, len);
+ ep->xfer_buff += len;
+ ep->xfer_count += len;
+ break;
+
+ case USB_READ_SETUP_PACKET:
+ ep = &pdev->data->out_ep[param & USBD_OUT_EPNUM_MASK];
+ len = (param & USBD_OUT_COUNT_MASK) >> 0x10;
+ pdev->driver->read_packet(pdev->data->instance,
+ (uint8_t *)pdev->data->setup, 8);
+ ep->xfer_count += len;
+ break;
+
+ case USB_RESET:
+ pdev->dev_state = USBD_STATE_DEFAULT;
+ break;
+
+ case USB_RESUME:
+ if (pdev->data->lpm_state == LPM_L1) {
+ pdev->data->lpm_state = LPM_L0;
+ } else {
+ usb_core_resume(pdev);
+ }
+ break;
+
+ case USB_SUSPEND:
+ usb_core_suspend(pdev);
+ break;
+
+ case USB_LPM:
+ if (pdev->data->lpm_state == LPM_L0) {
+ pdev->data->lpm_state = LPM_L1;
+ } else {
+ usb_core_suspend(pdev);
+ }
+ break;
+
+ case USB_SOF:
+ usb_core_sof(pdev);
+ break;
+
+ case USB_DISCONNECT:
+ usb_core_disconnect(pdev);
+ break;
+
+ case USB_WRITE_EMPTY:
+ pdev->driver->write_empty_tx_fifo(pdev->data->instance, param,
+ pdev->data->in_ep[param].xfer_len,
+ (uint32_t *)&pdev->data->in_ep[param].xfer_count,
+ pdev->data->in_ep[param].maxpacket,
+ &pdev->data->in_ep[param].xfer_buff);
+ break;
+
+ case USB_NOTHING:
+ default:
+ break;
+ }
+
+ return USBD_OK;
+}
+
+static void usb_core_start_xfer(struct usb_handle *pdev,
+ void *handle,
+ struct usbd_ep *ep)
+{
+ if (ep->num == 0U) {
+ pdev->driver->ep0_start_xfer(handle, ep);
+ } else {
+ pdev->driver->ep_start_xfer(handle, ep);
+ }
+}
+
+/*
+ * usb_core_receive
+ * Receive an amount of data
+ * pdev: USB handle
+ * ep_addr: endpoint address
+ * buf: pointer to the reception buffer
+ * len: amount of data to be received
+ * return : status
+ */
+enum usb_status usb_core_receive(struct usb_handle *pdev, uint8_t ep_addr,
+ uint8_t *buf, uint32_t len)
+{
+ struct usbd_ep *ep;
+ struct pcd_handle *hpcd = (struct pcd_handle *)pdev->data;
+ uint8_t num;
+
+ num = ep_addr & EP_NUM_MASK;
+ if (num >= USBD_EP_NB) {
+ return USBD_FAIL;
+ }
+ ep = &hpcd->out_ep[num];
+
+ /* Setup and start the Xfer */
+ ep->xfer_buff = buf;
+ ep->xfer_len = len;
+ ep->xfer_count = 0U;
+ ep->is_in = false;
+ ep->num = num;
+
+ usb_core_start_xfer(pdev, hpcd->instance, ep);
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_transmit
+ * Send an amount of data
+ * pdev: USB handle
+ * ep_addr: endpoint address
+ * buf: pointer to the transmission buffer
+ * len: amount of data to be sent
+ * return : status
+ */
+enum usb_status usb_core_transmit(struct usb_handle *pdev, uint8_t ep_addr,
+ uint8_t *buf, uint32_t len)
+{
+ struct usbd_ep *ep;
+ struct pcd_handle *hpcd = (struct pcd_handle *)pdev->data;
+ uint8_t num;
+
+ num = ep_addr & EP_NUM_MASK;
+ if (num >= USBD_EP_NB) {
+ return USBD_FAIL;
+ }
+ ep = &hpcd->in_ep[num];
+
+ /* Setup and start the Xfer */
+ ep->xfer_buff = buf;
+ ep->xfer_len = len;
+ ep->xfer_count = 0U;
+ ep->is_in = true;
+ ep->num = num;
+
+ usb_core_start_xfer(pdev, hpcd->instance, ep);
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_receive_ep0
+ * Receive an amount of data on ep0
+ * pdev: USB handle
+ * buf: pointer to the reception buffer
+ * len: amount of data to be received
+ * return : status
+ */
+enum usb_status usb_core_receive_ep0(struct usb_handle *pdev, uint8_t *buf,
+ uint32_t len)
+{
+ /* Prepare the reception of the buffer over EP0 */
+ if (len != 0U) {
+ pdev->ep0_state = USBD_EP0_DATA_OUT;
+ } else {
+ pdev->ep0_state = USBD_EP0_STATUS_OUT;
+ }
+
+ pdev->ep_out[0].total_length = len;
+ pdev->ep_out[0].rem_length = len;
+
+ /* Start the transfer */
+ return usb_core_receive(pdev, 0U, buf, len);
+}
+
+/*
+ * usb_core_transmit_ep0
+ * Send an amount of data on ep0
+ * pdev: USB handle
+ * buf: pointer to the transmission buffer
+ * len: amount of data to be sent
+ * return : status
+ */
+enum usb_status usb_core_transmit_ep0(struct usb_handle *pdev, uint8_t *buf,
+ uint32_t len)
+{
+ /* Set EP0 State */
+ if (len != 0U) {
+ pdev->ep0_state = USBD_EP0_DATA_IN;
+ } else {
+ pdev->ep0_state = USBD_EP0_STATUS_IN;
+ }
+
+ pdev->ep_in[0].total_length = len;
+ pdev->ep_in[0].rem_length = len;
+
+ /* Start the transfer */
+ return usb_core_transmit(pdev, 0U, buf, len);
+}
+
+/*
+ * usb_core_ctl_error
+ * Handle USB low level error
+ * pdev: device instance
+ * req: usb request
+ * return : None
+ */
+
+void usb_core_ctl_error(struct usb_handle *pdev)
+{
+ ERROR("%s : Send an ERROR\n", __func__);
+ usb_core_set_stall(pdev, EP0_IN);
+ usb_core_set_stall(pdev, EP0_OUT);
+}
+
+/*
+ * usb_core_start
+ * Start the USB device core.
+ * pdev: Device Handle
+ * return : USBD Status
+ */
+enum usb_status usb_core_start(struct usb_handle *pdev)
+{
+ /* Start the low level driver */
+ pdev->driver->start_device(pdev->data->instance);
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_stop
+ * Stop the USB device core.
+ * pdev: Device Handle
+ * return : USBD Status
+ */
+enum usb_status usb_core_stop(struct usb_handle *pdev)
+{
+ /* Free class resources */
+ pdev->class->de_init(pdev, pdev->dev_config);
+
+ /* Stop the low level driver */
+ pdev->driver->stop_device(pdev->data->instance);
+
+ return USBD_OK;
+}
+
+/*
+ * register_usb_driver
+ * Stop the USB device core.
+ * pdev: Device Handle
+ * pcd_handle: PCD handle
+ * driver: USB driver
+ * driver_handle: USB driver handle
+ * return : USBD Status
+ */
+enum usb_status register_usb_driver(struct usb_handle *pdev,
+ struct pcd_handle *pcd_handle,
+ const struct usb_driver *driver,
+ void *driver_handle)
+{
+ uint8_t i;
+
+ assert(pdev != NULL);
+ assert(pcd_handle != NULL);
+ assert(driver != NULL);
+ assert(driver_handle != NULL);
+
+ /* Free class resources */
+ pdev->driver = driver;
+ pdev->data = pcd_handle;
+ pdev->data->instance = driver_handle;
+ pdev->dev_state = USBD_STATE_DEFAULT;
+ pdev->ep0_state = USBD_EP0_IDLE;
+
+ /* Copy endpoint information */
+ for (i = 0U; i < USBD_EP_NB; i++) {
+ pdev->ep_in[i].maxpacket = pdev->data->in_ep[i].maxpacket;
+ pdev->ep_out[i].maxpacket = pdev->data->out_ep[i].maxpacket;
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * register_platform
+ * Register the USB device core.
+ * pdev: Device Handle
+ * plat_call_back: callback
+ * return : USBD Status
+ */
+enum usb_status register_platform(struct usb_handle *pdev,
+ const struct usb_desc *plat_call_back)
+{
+ assert(pdev != NULL);
+ assert(plat_call_back != NULL);
+
+ /* Save platform info in class resources */
+ pdev->desc = plat_call_back;
+
+ return USBD_OK;
+}
diff --git a/fdts/a5ds.dts b/fdts/a5ds.dts
new file mode 100644
index 0000000..c6f5be6
--- /dev/null
+++ b/fdts/a5ds.dts
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2019-2020, 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>;
+ enable-method = "psci";
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ reg = <0>;
+ next-level-cache = <&L2>;
+ };
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ reg = <1>;
+ next-level-cache = <&L2>;
+ };
+ cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ reg = <2>;
+ next-level-cache = <&L2>;
+ };
+ cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ reg = <3>;
+ next-level-cache = <&L2>;
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x80000000 0x7F000000>;
+ };
+
+ L2: cache-controller@1C010000 {
+ compatible = "arm,pl310-cache";
+ reg = <0x1C010000 0x1000>;
+ interrupts = <0 84 4>;
+ cache-level = <2>;
+ cache-unified;
+ arm,data-latency = <1 1 1>;
+ arm,tag-latency = <1 1 1>;
+ };
+
+ refclk7500khz: refclk7500khz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <7500000>;
+ clock-output-names = "apb_pclk";
+ };
+
+ refclk24mhz: refclk24mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24000000>;
+ 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 = <&refclk24mhz>;
+ 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 = <&refclk7500khz>;
+ clock-names = "apb_pclk";
+ };
+
+ serial1: uart@1a210000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x1a210000 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 9 0xf04>;
+ clocks = <&refclk7500khz>;
+ clock-names = "apb_pclk";
+ };
+
+ timer0: timer@1a040000 {
+ compatible = "arm,armv7-timer-mem";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ reg = <0x1a040000 0x1000>;
+ clock-frequency = <7500000>;
+
+ frame@1a050000 {
+ frame-number = <0>;
+ interrupts = <0 2 0xf04>;
+ reg = <0x1a050000 0x1000>;
+ };
+ };
+ v2m_fixed_3v3: fixed-regulator-0 {
+ compatible = "regulator-fixed";
+ regulator-name = "3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ ethernet@4020000 {
+ compatible = "smsc,lan9220", "smsc,lan9115";
+ reg = <0x40200000 0x10000>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 43 0xf04>;
+ reg-io-width = <4>;
+ phy-mode = "mii";
+ smsc,irq-active-high;
+ vdd33a-supply = <&v2m_fixed_3v3>;
+ vddvario-supply = <&v2m_fixed_3v3>;
+ };
+};
diff --git a/fdts/arm_fpga.dts b/fdts/arm_fpga.dts
new file mode 100644
index 0000000..c0efd09
--- /dev/null
+++ b/fdts/arm_fpga.dts
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: (GPL-2.0 or BSD-3-Clause)
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * Devicetree for the Arm Ltd. FPGA platform
+ * Number and kind of CPU cores differs from image to image, so the
+ * topology is auto-detected by BL31, and the /cpus node is created and
+ * populated accordingly at runtime.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/dts-v1/;
+
+/ {
+ model = "ARM FPGA";
+ compatible = "arm,fpga", "arm,vexpress";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ aliases {
+ serial0 = &dbg_uart;
+ };
+
+ chosen {
+ stdout-path = "serial0:38400n8";
+ bootargs = "console=ttyAMA0,38400n8 earlycon";
+ /* Allow to upload a generous 100MB initrd payload. */
+ linux,initrd-start = <0x0 0x84000000>;
+ linux,initrd-end = <0x0 0x8a400000>;
+ };
+
+ /* /cpus node will be added by BL31 at runtime. */
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+ };
+
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ /* This node will be removed at runtime on cores without SPE. */
+ spe-pmu {
+ compatible = "arm,statistical-profiling-extension-v1";
+ interrupts = <GIC_PPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x0 0x80000000 0x0 0x80000000>,
+ <0x8 0x80000000 0x1 0x80000000>;
+ };
+
+
+ bus_refclk: refclk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <100000000>;
+ clock-output-names = "apb_pclk";
+ };
+
+ uartclk: baudclock {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <10000000>;
+ clock-output-names = "uartclk";
+ };
+
+ dbg_uart: serial@7ff80000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0 0x7ff80000 0x0 0x00001000>;
+ interrupts = <GIC_SPI 415 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uartclk>, <&bus_refclk>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ gic: interrupt-controller@30000000 {
+ compatible = "arm,gic-v3";
+ #address-cells = <2>;
+ #interrupt-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+ interrupt-controller;
+ reg = <0x0 0x30000000 0x0 0x00010000>, /* GICD */
+ /* The GICR size will be adjusted at runtime to match the cores. */
+ <0x0 0x30040000 0x0 0x00020000>; /* GICR for one core */
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+
+ its: msi-controller@30040000 {
+ compatible = "arm,gic-v3-its";
+ reg = <0x0 0x30040000 0x0 0x40000>;
+ #msi-cells = <1>;
+ msi-controller;
+ };
+ };
+};
diff --git a/fdts/corstone700.dtsi b/fdts/corstone700.dtsi
new file mode 100644
index 0000000..2372207
--- /dev/null
+++ b/fdts/corstone700.dtsi
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ compatible = "arm,Corstone-700";
+ interrupt-parent = <&gic>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ chosen { };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0>;
+ next-level-cache = <&L2_0>;
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x80000000 0x80000000>;
+ };
+
+ 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";
+ };
+
+ uartclk: uartclk {
+ /* UART clock - 32MHz */
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32000000>;
+ clock-output-names = "uartclk";
+ };
+
+ serial0: uart@1a510000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x1a510000 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 19 4>;
+ clocks = <&uartclk>, <&refclk100mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ serial1: uart@1a520000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x1a520000 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 20 4>;
+ clocks = <&uartclk>, <&refclk100mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <1 13 0xf08>,
+ <1 14 0xf08>,
+ <1 11 0xf08>,
+ <1 10 0xf08>;
+ };
+
+ refclk: refclk@1a220000 {
+ compatible = "arm,armv7-timer-mem";
+ reg = <0x1a220000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ frame@1a230000 {
+ frame-number = <0>;
+ interrupts = <0 2 0xf04>;
+ reg = <0x1a230000 0x1000>;
+ };
+ };
+
+ 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";
+ };
+};
diff --git a/fdts/corstone700_fpga.dts b/fdts/corstone700_fpga.dts
new file mode 100644
index 0000000..1ac0d4b
--- /dev/null
+++ b/fdts/corstone700_fpga.dts
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+#include "corstone700.dtsi"
+
+/ {
+ model = "corstone700-fpga";
+
+ ethernet: eth@40100000 {
+ compatible = "smsc,lan9115";
+ reg = <0x40100000 0x10000>;
+ phy-mode = "mii";
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+ reg-io-width = <2>;
+ smsc,irq-push-pull;
+ };
+
+ usb: usb@4020000 {
+ compatible = "nxp,usb-isp1763";
+ reg = <0x40200000 0x100000>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+ };
+};
+
+&refclk {
+ clock-frequency = <32000000>;
+};
diff --git a/fdts/corstone700_fvp.dts b/fdts/corstone700_fvp.dts
new file mode 100644
index 0000000..3b1202d
--- /dev/null
+++ b/fdts/corstone700_fvp.dts
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+#include "corstone700.dtsi"
+
+/ {
+ model = "corstone700-fvp";
+
+ /*
+ * Intel StrataFlash J3 NOR flash: 2 x 16-bit interleaved components
+ * Flash total size: 32 MB
+ * Allocated flash space: 8 MB
+ */
+
+ flash@8500000 {
+ compatible = "cfi-flash";
+ reg = <0x8500000 0x800000>;
+ bank-width = <4>;
+ device-width= <2>;
+ };
+
+ ethernet: eth@4010000 {
+ compatible = "smsc,lan91c111";
+ reg = <0x40100000 0x10000>;
+ phy-mode = "mii";
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 116 0xf04>;
+ reg-io-width = <2>;
+ smsc,irq-push-pull;
+ };
+};
+
+&refclk {
+ clock-frequency = <50000000>;
+};
diff --git a/fdts/cot_descriptors.dtsi b/fdts/cot_descriptors.dtsi
new file mode 100644
index 0000000..411bae6
--- /dev/null
+++ b/fdts/cot_descriptors.dtsi
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2020, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <tools_share/tbbr_oid.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <common/nv_cntr_ids.h>
+
+cot {
+ manifests {
+ compatible = "arm, cert-descs";
+
+ trusted_boot_fw_cert: trusted_boot_fw_cert {
+ root-certificate;
+ image-id =<TRUSTED_BOOT_FW_CERT_ID>;
+ antirollback-counter = <&trusted_nv_counter>;
+
+ tb_fw_hash: tb_fw_hash {
+ oid = TRUSTED_BOOT_FW_HASH_OID;
+ };
+ tb_fw_config_hash: tb_fw_config_hash {
+ oid = TRUSTED_BOOT_FW_CONFIG_HASH_OID;
+ };
+ hw_config_hash: hw_config_hash {
+ oid = HW_CONFIG_HASH_OID;
+ };
+ fw_config_hash: fw_config_hash {
+ oid = FW_CONFIG_HASH_OID;
+ };
+ };
+
+ trusted_key_cert: trusted_key_cert {
+ root-certificate;
+ image-id = <TRUSTED_KEY_CERT_ID>;
+ antirollback-counter = <&trusted_nv_counter>;
+
+ trusted_world_pk: trusted_world_pk {
+ oid = TRUSTED_WORLD_PK_OID;
+ };
+ non_trusted_world_pk: non_trusted_world_pk {
+ oid = NON_TRUSTED_WORLD_PK_OID;
+ };
+ };
+
+ scp_fw_key_cert: scp_fw_key_cert {
+ image-id = <SCP_FW_KEY_CERT_ID>;
+ parent = <&trusted_key_cert>;
+ signing-key = <&trusted_world_pk>;
+ antirollback-counter = <&trusted_nv_counter>;
+
+ scp_fw_content_pk: scp_fw_content_pk {
+ oid = SCP_FW_CONTENT_CERT_PK_OID;
+ };
+ };
+
+ scp_fw_content_cert: scp_fw_content_cert {
+ image-id = <SCP_FW_CONTENT_CERT_ID>;
+ parent = <&scp_fw_key_cert>;
+ signing-key = <&scp_fw_content_pk>;
+ antirollback-counter = <&trusted_nv_counter>;
+
+ scp_fw_hash: scp_fw_hash {
+ oid = SCP_FW_HASH_OID;
+ };
+ };
+
+ soc_fw_key_cert: soc_fw_key_cert {
+ image-id = <SOC_FW_KEY_CERT_ID>;
+ parent = <&trusted_key_cert>;
+ signing-key = <&trusted_world_pk>;
+ antirollback-counter = <&trusted_nv_counter>;
+ soc_fw_content_pk: soc_fw_content_pk {
+ oid = SOC_FW_CONTENT_CERT_PK_OID;
+ };
+ };
+
+ soc_fw_content_cert: soc_fw_content_cert {
+ image-id = <SOC_FW_CONTENT_CERT_ID>;
+ parent = <&soc_fw_key_cert>;
+ signing-key = <&soc_fw_content_pk>;
+ antirollback-counter = <&trusted_nv_counter>;
+
+ soc_fw_hash: soc_fw_hash {
+ oid = SOC_AP_FW_HASH_OID;
+ };
+ soc_fw_config_hash: soc_fw_config_hash {
+ oid = SOC_FW_CONFIG_HASH_OID;
+ };
+ };
+
+ trusted_os_fw_key_cert: trusted_os_fw_key_cert {
+ image-id = <TRUSTED_OS_FW_KEY_CERT_ID>;
+ parent = <&trusted_key_cert>;
+ signing-key = <&trusted_world_pk>;
+ antirollback-counter = <&trusted_nv_counter>;
+
+ tos_fw_content_pk: tos_fw_content_pk {
+ oid = TRUSTED_OS_FW_CONTENT_CERT_PK_OID;
+ };
+ };
+
+ trusted_os_fw_content_cert: trusted_os_fw_content_cert {
+ image-id = <TRUSTED_OS_FW_CONTENT_CERT_ID>;
+ parent = <&trusted_os_fw_key_cert>;
+ signing-key = <&tos_fw_content_pk>;
+ antirollback-counter = <&trusted_nv_counter>;
+
+ tos_fw_hash: tos_fw_hash {
+ oid = TRUSTED_OS_FW_HASH_OID;
+ };
+ tos_fw_extra1_hash: tos_fw_extra1_hash {
+ oid = TRUSTED_OS_FW_EXTRA1_HASH_OID;
+ };
+ tos_fw_extra2_hash: tos_fw_extra2_hash {
+ oid = TRUSTED_OS_FW_EXTRA2_HASH_OID;
+ };
+ tos_fw_config_hash: tos_fw_config_hash {
+ oid = TRUSTED_OS_FW_CONFIG_HASH_OID;
+ };
+ };
+
+ non_trusted_fw_key_cert: non_trusted_fw_key_cert {
+ image-id = <NON_TRUSTED_FW_KEY_CERT_ID>;
+ parent = <&trusted_key_cert>;
+ signing-key = <&non_trusted_world_pk>;
+ antirollback-counter = <&non_trusted_nv_counter>;
+
+ nt_fw_content_pk: nt_fw_content_pk {
+ oid = NON_TRUSTED_FW_CONTENT_CERT_PK_OID;
+ };
+ };
+
+ non_trusted_fw_content_cert: non_trusted_fw_content_cert {
+ image-id = <NON_TRUSTED_FW_CONTENT_CERT_ID>;
+ parent = <&non_trusted_fw_key_cert>;
+ signing-key = <&nt_fw_content_pk>;
+ antirollback-counter = <&non_trusted_nv_counter>;
+
+ nt_world_bl_hash: nt_world_bl_hash {
+ oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID;
+ };
+ nt_fw_config_hash: nt_fw_config_hash {
+ oid = NON_TRUSTED_FW_CONFIG_HASH_OID;
+ };
+ };
+
+#if defined(SPD_spmd)
+ sip_sp_content_cert: sip_sp_content_cert {
+ image-id = <SIP_SP_CONTENT_CERT_ID>;
+ parent = <&trusted_key_cert>;
+ signing-key = <&trusted_world_pk>;
+ antirollback-counter = <&trusted_nv_counter>;
+
+ sp_pkg1_hash: sp_pkg1_hash {
+ oid = SP_PKG1_HASH_OID;
+ };
+ sp_pkg2_hash: sp_pkg2_hash {
+ oid = SP_PKG2_HASH_OID;
+ };
+ sp_pkg3_hash: sp_pkg3_hash {
+ oid = SP_PKG3_HASH_OID;
+ };
+ sp_pkg4_hash: sp_pkg4_hash {
+ oid = SP_PKG4_HASH_OID;
+ };
+ sp_pkg5_hash: sp_pkg5_hash {
+ oid = SP_PKG5_HASH_OID;
+ };
+ sp_pkg6_hash: sp_pkg6_hash {
+ oid = SP_PKG6_HASH_OID;
+ };
+ sp_pkg7_hash: sp_pkg7_hash {
+ oid = SP_PKG7_HASH_OID;
+ };
+ sp_pkg8_hash: sp_pkg8_hash {
+ oid = SP_PKG8_HASH_OID;
+ };
+ };
+#endif
+ };
+
+ images {
+ compatible = "arm, img-descs";
+
+ hw_config {
+ image-id = <HW_CONFIG_ID>;
+ parent = <&trusted_boot_fw_cert>;
+ hash = <&hw_config_hash>;
+ };
+
+ tb_fw_config {
+ image-id = <TB_FW_CONFIG_ID>;
+ parent = <&trusted_boot_fw_cert>;
+ hash = <&tb_fw_config_hash>;
+ };
+
+ scp_bl2_image {
+ image-id = <SCP_BL2_IMAGE_ID>;
+ parent = <&scp_fw_content_cert>;
+ hash = <&scp_fw_hash>;
+ };
+
+ bl31_image {
+ image-id = <BL31_IMAGE_ID>;
+ parent = <&soc_fw_content_cert>;
+ hash = <&soc_fw_hash>;
+ };
+
+ soc_fw_config {
+ image-id = <SOC_FW_CONFIG_ID>;
+ parent = <&soc_fw_content_cert>;
+ hash = <&soc_fw_config_hash>;
+ };
+
+ bl32_image {
+ image-id = <BL32_IMAGE_ID>;
+ parent = <&trusted_os_fw_content_cert>;
+ hash = <&tos_fw_hash>;
+ };
+
+ bl32_extra1_image {
+ image-id = <BL32_EXTRA1_IMAGE_ID>;
+ parent = <&trusted_os_fw_content_cert>;
+ hash = <&tos_fw_extra1_hash>;
+ };
+
+ bl32_extra2_image {
+ image-id = <BL32_EXTRA2_IMAGE_ID>;
+ parent = <&trusted_os_fw_content_cert>;
+ hash = <&tos_fw_extra2_hash>;
+ };
+
+ tos_fw_config {
+ image-id = <TOS_FW_CONFIG_ID>;
+ parent = <&trusted_os_fw_content_cert>;
+ hash = <&tos_fw_config_hash>;
+ };
+
+ bl33_image {
+ image-id = <BL33_IMAGE_ID>;
+ parent = <&non_trusted_fw_content_cert>;
+ hash = <&nt_world_bl_hash>;
+ };
+
+ nt_fw_config {
+ image-id = <NT_FW_CONFIG_ID>;
+ parent = <&non_trusted_fw_content_cert>;
+ hash = <&nt_fw_config_hash>;
+ };
+
+#if defined(SPD_spmd)
+ sp_pkg1 {
+ image-id = <SP_PKG1_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg1_hash>;
+ };
+
+ sp_pkg2 {
+ image-id = <SP_PKG2_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg2_hash>;
+ };
+
+ sp_pkg3 {
+ image-id = <SP_PKG3_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg3_hash>;
+ };
+
+ sp_pkg4 {
+ image-id = <SP_PKG4_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg4_hash>;
+ };
+
+ sp_pkg5 {
+ image-id = <SP_PKG5_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg5_hash>;
+ };
+
+ sp_pkg6 {
+ image-id = <SP_PKG6_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg6_hash>;
+ };
+
+ sp_pkg7 {
+ image-id = <SP_PKG7_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg7_hash>;
+ };
+
+ sp_pkg8 {
+ image-id = <SP_PKG8_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg8_hash>;
+ };
+#endif
+ };
+};
+
+non_volatile_counters: non_volatile_counters {
+ compatible = "arm, non-volatile-counter";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ trusted_nv_counter: trusted_nv_counter {
+ id = <TRUSTED_NV_CTR_ID>;
+ oid = TRUSTED_FW_NVCOUNTER_OID;
+ };
+
+ non_trusted_nv_counter: non_trusted_nv_counter {
+ id = <NON_TRUSTED_NV_CTR_ID>;
+ oid = NON_TRUSTED_FW_NVCOUNTER_OID;
+ };
+};
diff --git a/fdts/fvp-base-gicv2-psci.dts b/fdts/fvp-base-gicv2-psci.dts
new file mode 100644
index 0000000..0361bdc
--- /dev/null
+++ b/fdts/fvp-base-gicv2-psci.dts
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Configuration: max 4 clusters with up to 4 CPUs */
+
+#define AFF
+
+#include "fvp-defs.dtsi"
+
+/dts-v1/;
+
+/memreserve/ 0x80000000 0x00010000;
+
+#include "fvp-base-gicv2.dtsi"
+#include "fvp-base-psci-common.dtsi"
diff --git a/fdts/fvp-base-gicv2.dtsi b/fdts/fvp-base-gicv2.dtsi
new file mode 100644
index 0000000..8d84208
--- /dev/null
+++ b/fdts/fvp-base-gicv2.dtsi
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* GICv2 configuration, without V2M */
+
+/ {
+ gic: interrupt-controller@2f000000 {
+ compatible = "arm,cortex-a15-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <1>;
+ interrupt-controller;
+ reg = <0x0 0x2f000000 0 0x10000>,
+ <0x0 0x2c000000 0 0x2000>,
+ <0x0 0x2c010000 0 0x2000>,
+ <0x0 0x2c02F000 0 0x2000>;
+ interrupts = <1 9 0xf04>;
+ };
+};
diff --git a/fdts/fvp-base-gicv3-psci-1t.dts b/fdts/fvp-base-gicv3-psci-1t.dts
new file mode 100644
index 0000000..829555b
--- /dev/null
+++ b/fdts/fvp-base-gicv3-psci-1t.dts
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Configuration: max 4 clusters with up to 4 CPUs with 1 thread per each */
+
+#define AFF 00
+
+#include "fvp-defs.dtsi"
+
+/dts-v1/;
+
+/memreserve/ 0x80000000 0x00010000;
+
+#include "fvp-base-gicv3.dtsi"
+#include "fvp-base-psci-common.dtsi"
diff --git a/fdts/fvp-base-gicv3-psci-dynamiq-2t.dts b/fdts/fvp-base-gicv3-psci-dynamiq-2t.dts
new file mode 100644
index 0000000..9d5b979
--- /dev/null
+++ b/fdts/fvp-base-gicv3-psci-dynamiq-2t.dts
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* DynamIQ configuration: 1 cluster with up to 8 CPUs with 2 threads per each */
+
+/* Set default value if not passed from platform's makefile */
+#ifdef FVP_MAX_PE_PER_CPU
+#define PE_PER_CPU FVP_MAX_PE_PER_CPU
+#else
+#define PE_PER_CPU 2
+#endif
+
+#include "fvp-defs-dynamiq.dtsi"
+
+/dts-v1/;
+
+/memreserve/ 0x80000000 0x00010000;
+
+#include "fvp-base-gicv3.dtsi"
+#include "fvp-base-psci-common.dtsi"
diff --git a/fdts/fvp-base-gicv3-psci-dynamiq-common.dtsi b/fdts/fvp-base-gicv3-psci-dynamiq-common.dtsi
new file mode 100644
index 0000000..42a439f
--- /dev/null
+++ b/fdts/fvp-base-gicv3-psci-dynamiq-common.dtsi
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+#include "fvp-defs-dynamiq.dtsi"
+#include "fvp-base-gicv3-psci-common.dtsi"
diff --git a/fdts/fvp-base-gicv3-psci-dynamiq.dts b/fdts/fvp-base-gicv3-psci-dynamiq.dts
new file mode 100644
index 0000000..1bf803e
--- /dev/null
+++ b/fdts/fvp-base-gicv3-psci-dynamiq.dts
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* DynamIQ configuration: 1 cluster with up to 8 CPUs */
+
+/* Set default value if not passed from platform's makefile */
+#ifdef FVP_MAX_PE_PER_CPU
+#define PE_PER_CPU FVP_MAX_PE_PER_CPU
+#else
+#define PE_PER_CPU 1
+#endif
+
+#include "fvp-defs-dynamiq.dtsi"
+
+/dts-v1/;
+
+/memreserve/ 0x80000000 0x00010000;
+
+#include "fvp-base-gicv3.dtsi"
+#include "fvp-base-psci-common.dtsi"
diff --git a/fdts/fvp-base-gicv3-psci.dts b/fdts/fvp-base-gicv3-psci.dts
new file mode 100644
index 0000000..69db267
--- /dev/null
+++ b/fdts/fvp-base-gicv3-psci.dts
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Configuration: max 4 clusters with up to 4 CPUs */
+
+#define AFF
+
+#include "fvp-defs.dtsi"
+
+/dts-v1/;
+
+/memreserve/ 0x80000000 0x00010000;
+
+#include "fvp-base-gicv3.dtsi"
+#include "fvp-base-psci-common.dtsi"
diff --git a/fdts/fvp-base-gicv3.dtsi b/fdts/fvp-base-gicv3.dtsi
new file mode 100644
index 0000000..fdcfa92
--- /dev/null
+++ b/fdts/fvp-base-gicv3.dtsi
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* GICv3 with ITS configuration */
+
+/ {
+ gic: interrupt-controller@2f000000 {
+ compatible = "arm,gic-v3";
+ #interrupt-cells = <3>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x0 0x2f000000 0x100000>;
+ 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: msi-controller@2f020000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x20000 0x20000>; // GITS
+ };
+ };
+};
diff --git a/fdts/fvp-base-psci-common.dtsi b/fdts/fvp-base-psci-common.dtsi
new file mode 100644
index 0000000..6018f0c
--- /dev/null
+++ b/fdts/fvp-base-psci-common.dtsi
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
+/*
+ * ARM Ltd. Fast Models
+ *
+ * Architecture Envelope Model (AEM) ARMv8-A
+ * ARMAEMv8AMPCT
+ *
+ * RTSM_VE_AEMv8A.lisa
+ *
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <services/sdei_flags.h>
+
+#define LEVEL 0
+#define EDGE 2
+#define SDEI_NORMAL 0x70
+#define HIGHEST_SEC 0
+
+#include "rtsm_ve-motherboard.dtsi"
+
+/ {
+ model = "FVP Base";
+ compatible = "arm,fvp-base", "arm,vexpress";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+#if (ENABLE_RME == 1)
+ chosen { bootargs = "mem=1G console=ttyAMA0 earlycon=pl011,0x1c090000 root=/dev/vda ip=on";};
+#else
+ chosen {};
+#endif
+
+ aliases {
+ serial0 = &v2m_serial0;
+ serial1 = &v2m_serial1;
+ serial2 = &v2m_serial2;
+ serial3 = &v2m_serial3;
+ };
+
+ psci {
+ compatible = "arm,psci-1.0", "arm,psci-0.2";
+ method = "smc";
+ max-pwr-lvl = <2>;
+ };
+
+#if SDEI_IN_FCONF || SEC_INT_DESC_IN_FCONF
+ firmware {
+#if SDEI_IN_FCONF
+ sdei {
+ compatible = "arm,sdei-1.0";
+ method = "smc";
+ private_event_count = <3>;
+ shared_event_count = <3>;
+ /*
+ * Each event descriptor has typically 3 fields:
+ * 1. Event number
+ * 2. Interrupt number the event is bound to or
+ * if event is dynamic, specified as SDEI_DYN_IRQ
+ * 3. Bit map of event flags
+ */
+ private_events = <1000 SDEI_DYN_IRQ SDEI_MAPF_DYNAMIC>,
+ <1001 SDEI_DYN_IRQ SDEI_MAPF_DYNAMIC>,
+ <1002 SDEI_DYN_IRQ SDEI_MAPF_DYNAMIC>;
+ shared_events = <2000 SDEI_DYN_IRQ SDEI_MAPF_DYNAMIC>,
+ <2001 SDEI_DYN_IRQ SDEI_MAPF_DYNAMIC>,
+ <2002 SDEI_DYN_IRQ SDEI_MAPF_DYNAMIC>;
+ };
+#endif /* SDEI_IN_FCONF */
+
+#if SEC_INT_DESC_IN_FCONF
+ sec_interrupts {
+ compatible = "arm,secure_interrupt_desc";
+ /* Number of G0 and G1 secure interrupts defined by the platform */
+ g0_intr_cnt = <2>;
+ g1s_intr_cnt = <9>;
+ /*
+ * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. Each interrupt property descriptor has 3 fields:
+ * 1. Interrupt number
+ * 2. Interrupt priority
+ * 3. Type of interrupt (Edge or Level configured)
+ */
+ g0_intr_desc = < 8 SDEI_NORMAL EDGE>,
+ <14 HIGHEST_SEC EDGE>;
+
+ g1s_intr_desc = < 9 HIGHEST_SEC EDGE>,
+ <10 HIGHEST_SEC EDGE>,
+ <11 HIGHEST_SEC EDGE>,
+ <12 HIGHEST_SEC EDGE>,
+ <13 HIGHEST_SEC EDGE>,
+ <15 HIGHEST_SEC EDGE>,
+ <29 HIGHEST_SEC LEVEL>,
+ <56 HIGHEST_SEC LEVEL>,
+ <57 HIGHEST_SEC LEVEL>;
+ };
+#endif /* SEC_INT_DESC_IN_FCONF */
+ };
+#endif /* SDEI_IN_FCONF || SEC_INT_DESC_IN_FCONF */
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ CPU_MAP
+
+ idle-states {
+ entry-method = "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>;
+ };
+ };
+
+ CPUS
+
+ L2_0: l2-cache0 {
+ compatible = "cache";
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+#if (ENABLE_RME == 1)
+ reg = <0x00000000 0x80000000 0 0x7C000000>,
+ <0x00000008 0x80000000 0 0x80000000>;
+#else
+ reg = <0x00000000 0x80000000 0 0x7F000000>,
+ <0x00000008 0x80000000 0 0x80000000>;
+#endif
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ /* Chipselect 2,00000000 is physically at 0x18000000 */
+ vram: vram@18000000 {
+ /* 8 MB of designated video RAM */
+ compatible = "shared-dma-pool";
+ reg = <0x00000000 0x18000000 0 0x00800000>;
+ no-map;
+ };
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>;
+ clock-frequency = <100000000>;
+ };
+
+ timer@2a810000 {
+ compatible = "arm,armv7-timer-mem";
+ reg = <0x0 0x2a810000 0x0 0x10000>;
+ clock-frequency = <100000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x0 0x2a810000 0x100000>;
+
+ frame@2a830000 {
+ frame-number = <1>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ reg = <0x20000 0x10000>;
+ };
+ };
+
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ panel {
+ compatible = "arm,rtsm-display";
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&clcd_pads>;
+ };
+ };
+ };
+
+ bus@8000000 {
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 63>;
+ interrupt-map = <0 0 0 &gic 0 GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 1 &gic 0 GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 2 &gic 0 GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 3 &gic 0 GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 4 &gic 0 GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 5 &gic 0 GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 6 &gic 0 GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 7 &gic 0 GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 8 &gic 0 GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 9 &gic 0 GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 10 &gic 0 GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 11 &gic 0 GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 12 &gic 0 GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 13 &gic 0 GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 14 &gic 0 GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 15 &gic 0 GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 16 &gic 0 GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 17 &gic 0 GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 18 &gic 0 GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 19 &gic 0 GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 20 &gic 0 GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 21 &gic 0 GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 22 &gic 0 GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 23 &gic 0 GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 24 &gic 0 GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 25 &gic 0 GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 26 &gic 0 GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 27 &gic 0 GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 28 &gic 0 GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 29 &gic 0 GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 30 &gic 0 GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 31 &gic 0 GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 32 &gic 0 GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 33 &gic 0 GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 34 &gic 0 GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 35 &gic 0 GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 36 &gic 0 GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 37 &gic 0 GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 38 &gic 0 GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 39 &gic 0 GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 40 &gic 0 GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 41 &gic 0 GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 42 &gic 0 GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+ };
+};
diff --git a/fdts/fvp-defs-dynamiq.dtsi b/fdts/fvp-defs-dynamiq.dtsi
new file mode 100644
index 0000000..3659cd3
--- /dev/null
+++ b/fdts/fvp-defs-dynamiq.dtsi
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FVP_DEFS_DYNAMIQ_DTSI
+#define FVP_DEFS_DYNAMIQ_DTSI
+
+/* Set default topology values if not passed from platform's makefile */
+#ifdef FVP_CLUSTER_COUNT
+#define CLUSTER_COUNT FVP_CLUSTER_COUNT
+#else
+#define CLUSTER_COUNT 1
+#endif
+
+#ifdef FVP_MAX_CPUS_PER_CLUSTER
+#define CPUS_PER_CLUSTER FVP_MAX_CPUS_PER_CLUSTER
+#else
+#define CPUS_PER_CLUSTER 8
+#endif
+
+#define CONCAT(x, y) x##y
+#define CONC(x, y) CONCAT(x, y)
+
+/*
+ * n - CPU number
+ * r - MPID
+ */
+#define CPU(n, r) \
+ CPU##n:cpu@r## { \
+ device_type = "cpu"; \
+ compatible = "arm,armv8"; \
+ reg = <0x0 0x##r>; \
+ enable-method = "psci"; \
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; \
+ next-level-cache = <&L2_0>; \
+ };
+
+#if (PE_PER_CPU == 2)
+#define THREAD(n) \
+ thread##n { \
+ cpu = <&CONC(CPU, __COUNTER__)>; \
+ };
+
+#define CORE(n) \
+ core##n { \
+ THREAD(0) \
+ THREAD(1) \
+ };
+
+#else /* PE_PER_CPU == 1 */
+#define CORE(n) \
+ core##n { \
+ cpu = <&CPU##n>;\
+ };
+#endif /* PE_PER_CORE */
+
+#if (CPUS_PER_CLUSTER == 1)
+#if (PE_PER_CPU == 1)
+#define CPUS \
+ CPU(0, 0)
+#else
+#define CPUS \
+ CPU(0, 0) \
+ CPU(1, 1)
+#endif
+#define CLUSTER(n) \
+ cluster##n { \
+ CORE(0) \
+ };
+
+#elif (CPUS_PER_CLUSTER == 2)
+#if (PE_PER_CPU == 1)
+#define CPUS \
+ CPU(0, 0) \
+ CPU(1, 100)
+#else
+#define CPUS \
+ CPU(0, 0) \
+ CPU(1, 1) \
+ CPU(2, 100) \
+ CPU(3, 101)
+#endif
+#define CLUSTER(n) \
+ cluster##n { \
+ CORE(0) \
+ CORE(1) \
+ };
+
+#elif (CPUS_PER_CLUSTER == 3)
+#if (PE_PER_CPU == 1)
+#define CPUS \
+ CPU(0, 0) \
+ CPU(1, 100) \
+ CPU(2, 200)
+#else
+#define CPUS \
+ CPU(0, 0) \
+ CPU(1, 1) \
+ CPU(2, 100) \
+ CPU(3, 101) \
+ CPU(4, 200) \
+ CPU(5, 201)
+#endif
+#define CLUSTER(n) \
+ cluster##n { \
+ CORE(0) \
+ CORE(1) \
+ CORE(2) \
+ };
+
+#elif (CPUS_PER_CLUSTER == 4)
+#if (PE_PER_CPU == 1)
+#define CPUS \
+ CPU(0, 0) \
+ CPU(1, 100) \
+ CPU(2, 200) \
+ CPU(3, 300)
+#else
+#define CPUS \
+ CPU(0, 0) \
+ CPU(1, 1) \
+ CPU(2, 100) \
+ CPU(3, 101) \
+ CPU(4, 200) \
+ CPU(5, 201) \
+ CPU(6, 300) \
+ CPU(7, 301)
+#endif
+#define CLUSTER(n) \
+ cluster##n { \
+ CORE(0) \
+ CORE(1) \
+ CORE(2) \
+ CORE(3) \
+ };
+
+#elif (CPUS_PER_CLUSTER == 5)
+#if (PE_PER_CPU == 1)
+#define CPUS \
+ CPU(0, 0) \
+ CPU(1, 100) \
+ CPU(2, 200) \
+ CPU(3, 300) \
+ CPU(4, 400)
+#else
+#define CPUS \
+ CPU(0, 0) \
+ CPU(1, 1) \
+ CPU(2, 100) \
+ CPU(3, 101) \
+ CPU(4, 200) \
+ CPU(5, 201) \
+ CPU(6, 300) \
+ CPU(7, 301) \
+ CPU(8, 400) \
+ CPU(9, 401)
+#endif
+#define CLUSTER(n) \
+ cluster##n { \
+ CORE(0) \
+ CORE(1) \
+ CORE(2) \
+ CORE(3) \
+ CORE(4) \
+ };
+
+#elif (CPUS_PER_CLUSTER == 6)
+#if (PE_PER_CPU == 1)
+#define CPUS \
+ CPU(0, 0) \
+ CPU(1, 100) \
+ CPU(2, 200) \
+ CPU(3, 300) \
+ CPU(4, 400) \
+ CPU(5, 500)
+#else
+#define CPUS \
+ CPU(0, 0) \
+ CPU(1, 1) \
+ CPU(2, 100) \
+ CPU(3, 101) \
+ CPU(4, 200) \
+ CPU(5, 201) \
+ CPU(6, 300) \
+ CPU(7, 301) \
+ CPU(8, 400) \
+ CPU(9, 401) \
+ CPU(10, 500) \
+ CPU(11, 501)
+#endif
+#define CLUSTER(n) \
+ cluster##n { \
+ CORE(0) \
+ CORE(1) \
+ CORE(2) \
+ CORE(3) \
+ CORE(4) \
+ CORE(5) \
+ };
+
+#elif (CPUS_PER_CLUSTER == 7)
+#if (PE_PER_CPU == 1)
+#define CPUS \
+ CPU(0, 0) \
+ CPU(1, 100) \
+ CPU(2, 200) \
+ CPU(3, 300) \
+ CPU(4, 400) \
+ CPU(5, 500) \
+ CPU(6, 600)
+#else
+#define CPUS \
+ CPU(0, 0) \
+ CPU(1, 1) \
+ CPU(2, 100) \
+ CPU(3, 101) \
+ CPU(4, 200) \
+ CPU(5, 201) \
+ CPU(6, 300) \
+ CPU(7, 301) \
+ CPU(8, 400) \
+ CPU(9, 401) \
+ CPU(10, 500) \
+ CPU(11, 501) \
+ CPU(12, 600) \
+ CPU(13, 601)
+#endif
+#define CLUSTER(n) \
+ cluster##n { \
+ CORE(0) \
+ CORE(1) \
+ CORE(2) \
+ CORE(3) \
+ CORE(4) \
+ CORE(5) \
+ CORE(6) \
+ };
+
+#else
+#if (PE_PER_CPU == 1)
+#define CPUS \
+ CPU(0, 0) \
+ CPU(1, 100) \
+ CPU(2, 200) \
+ CPU(3, 300) \
+ CPU(4, 400) \
+ CPU(5, 500) \
+ CPU(6, 600) \
+ CPU(7, 700)
+#else
+#define CPUS \
+ CPU(0, 0) \
+ CPU(1, 1) \
+ CPU(2, 100) \
+ CPU(3, 101) \
+ CPU(4, 200) \
+ CPU(5, 201) \
+ CPU(6, 300) \
+ CPU(7, 301) \
+ CPU(8, 400) \
+ CPU(9, 401) \
+ CPU(10, 500) \
+ CPU(11, 501) \
+ CPU(12, 600) \
+ CPU(13, 601) \
+ CPU(14, 700) \
+ CPU(15, 701)
+#endif
+#define CLUSTER(n) \
+ cluster##n { \
+ CORE(0) \
+ CORE(1) \
+ CORE(2) \
+ CORE(3) \
+ CORE(4) \
+ CORE(5) \
+ CORE(6) \
+ CORE(7) \
+ };
+#endif /* CPUS_PER_CLUSTER */
+
+#define CPU_MAP \
+ cpu-map { \
+ CLUSTER(0) \
+ };
+
+#endif /* FVP_DEFS_DYNAMIQ_DTSI */
diff --git a/fdts/fvp-defs.dtsi b/fdts/fvp-defs.dtsi
new file mode 100644
index 0000000..9fd33ca
--- /dev/null
+++ b/fdts/fvp-defs.dtsi
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FVP_DEFS_DTSI
+#define FVP_DEFS_DTSI
+
+/* Set default topology values if not passed from platform's makefile */
+#ifndef CLUSTER_COUNT
+#ifdef FVP_CLUSTER_COUNT
+#define CLUSTER_COUNT FVP_CLUSTER_COUNT
+#else
+#define CLUSTER_COUNT 2
+#endif
+#endif /* CLUSTER_COUNT */
+
+#ifndef CPUS_PER_CLUSTER
+#ifdef FVP_MAX_CPUS_PER_CLUSTER
+#define CPUS_PER_CLUSTER FVP_MAX_CPUS_PER_CLUSTER
+#else
+#define CPUS_PER_CLUSTER 4
+#endif
+#endif /* CPUS_PER_CLUSTER */
+
+/* Get platform's topology */
+#define CPUS_COUNT (CLUSTER_COUNT * CPUS_PER_CLUSTER)
+
+#define CONCAT(x, y) x##y
+#define CONC(x, y) CONCAT(x, y)
+
+/* CPU's cluster */
+#define CLS(n) (n / CPUS_PER_CLUSTER)
+
+/* CPU's position in cluster */
+#define POS(n) (n % CPUS_PER_CLUSTER)
+
+#define ADR(n, c, p) \
+ CPU##n:cpu@CONC(c, CONC(p, AFF)) {
+
+#define PRE \
+ device_type = "cpu"; \
+ compatible = "arm,armv8";
+
+#define POST \
+ enable-method = "psci"; \
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; \
+ next-level-cache = <&L2_0>; \
+ };
+
+#define CPU_0 \
+ CPU0:cpu@0 { \
+ PRE \
+ reg = <0x0 0x0>;\
+ POST
+
+/*
+ * n - CPU number
+ */
+#define CPU(n, c, p) \
+ ADR(n, c, p) \
+ PRE \
+ reg = <0x0 CONC(0x, CONC(c, CONC(p, AFF)))>; \
+ POST
+
+/* 2 CPUs */
+#if (CPUS_COUNT > 1)
+#if (CLS(1) == 0)
+#define c1
+#define p1 1
+#else
+#define c1 10
+#define p1 0
+#endif
+
+#define CPU_1 CPU(1, c1, p1) /* CPU1: 0.1; 1.0 */
+
+/* 3 CPUs */
+#if (CPUS_COUNT > 2)
+#if (CLS(2) == 0)
+#define c2
+#define p2 2
+#elif (CLS(2) == 1)
+#define c2 10
+#define p2 0
+#else
+#define c2 20
+#define p2 0
+#endif
+
+#define CPU_2 CPU(2, c2, p2) /* CPU2: 0.2; 1.0; 2.0 */
+
+/* 4 CPUs */
+#if (CPUS_COUNT > 3)
+#if (CLS(3) == 0)
+#define c3
+#elif (CLS(3) == 1)
+#define c3 10
+#else
+#define c3 30
+#endif
+
+#if (POS(3) == 0)
+#define p3 0
+#elif (POS(3) == 1)
+#define p3 1
+#else
+#define p3 3
+#endif
+
+#define CPU_3 CPU(3, c3, p3) /* CPU3: 0.3; 1.0; 1.1; 3.0 */
+
+/* 6 CPUs */
+#if (CPUS_COUNT > 4)
+#if (CLS(4) == 1)
+#define c4 10
+#else
+#define c4 20
+#endif
+
+#if (POS(4) == 0)
+#define p4 0
+#else
+#define p4 1
+#endif
+
+#if (CLS(5) == 1)
+#define c5 10
+#else
+#define c5 20
+#endif
+
+#if (POS(5) == 1)
+#define p5 1
+#else
+#define p5 2
+#endif
+
+#define CPU_4 CPU(4, c4, p4) /* CPU4: 1.0; 1.1; 2.0 */
+#define CPU_5 CPU(5, c5, p5) /* CPU5: 1.1; 1.2; 2.1 */
+
+/* 8 CPUs */
+#if (CPUS_COUNT > 6)
+#if (CLS(6) == 1)
+#define c6 10
+#define p6 2
+#elif (CLS(6) == 2)
+#define c6 20
+#define p6 0
+#else
+#define c6 30
+#define p6 0
+#endif
+
+#if (CLS(7) == 1)
+#define c7 10
+#define p7 3
+#elif (CLS(7) == 2)
+#define c7 20
+#define p7 1
+#else
+#define c7 30
+#define p7 1
+#endif
+
+#define CPU_6 CPU(6, c6, p6) /* CPU6: 1.2; 2.0; 3.0 */
+#define CPU_7 CPU(7, c7, p7) /* CPU7: 1.3; 2.1; 3.1 */
+
+/* 9 CPUs */
+#if (CPUS_COUNT > 8)
+#if (POS(8) == 0)
+#define p8 0
+#else
+#define p8 2
+#endif
+
+#define CPU_8 CPU(8, 20, p8) /* CPU8: 2.0; 2.2 */
+
+/* 12 CPUs */
+#if (CPUS_COUNT > 9)
+#if (CLS(9) == 2)
+#define c9 20
+#define p9 1
+#else
+#define c9 30
+#define p9 0
+#endif
+
+#if (CLS(10) == 2)
+#define c10 20
+#define p10 2
+#else
+#define c10 30
+#define p10 1
+#endif
+
+#if (CLS(11) == 2)
+#define c11 20
+#define p11 3
+#else
+#define c11 30
+#define p11 2
+#endif
+
+#define CPU_9 CPU(9, c9, p9) /* CPU9: 2.1; 3.0 */
+#define CPU_10 CPU(10, c10, p10) /* CPU10: 2.2; 3.1 */
+#define CPU_11 CPU(11, c11, p11) /* CPU11: 2.3; 3.2 */
+
+/* 16 CPUs */
+#if (CPUS_COUNT > 12)
+#define CPU_12 CPU(12, 30, 0) /* CPU12: 3.0 */
+#define CPU_13 CPU(13, 30, 1) /* CPU13: 3.1 */
+#define CPU_14 CPU(14, 30, 2) /* CPU14: 3.2 */
+#define CPU_15 CPU(15, 30, 3) /* CPU15: 3.3 */
+#endif /* > 12 */
+#endif /* > 9 */
+#endif /* > 8 */
+#endif /* > 6 */
+#endif /* > 4 */
+#endif /* > 3 */
+#endif /* > 2 */
+#endif /* > 1 */
+
+#if (CPUS_COUNT == 1)
+#define CPUS \
+ CPU_0
+
+#elif (CPUS_COUNT == 2)
+#define CPUS \
+ CPU_0 \
+ CPU_1
+
+#elif (CPUS_COUNT == 3)
+#define CPUS \
+ CPU_0 \
+ CPU_1 \
+ CPU_2
+
+#elif (CPUS_COUNT == 4)
+#define CPUS \
+ CPU_0 \
+ CPU_1 \
+ CPU_2 \
+ CPU_3
+
+#elif (CPUS_COUNT == 6)
+#define CPUS \
+ CPU_0 \
+ CPU_1 \
+ CPU_2 \
+ CPU_3 \
+ CPU_4 \
+ CPU_5
+
+#elif (CPUS_COUNT == 8)
+#define CPUS \
+ CPU_0 \
+ CPU_1 \
+ CPU_2 \
+ CPU_3 \
+ CPU_4 \
+ CPU_5 \
+ CPU_6 \
+ CPU_7
+
+#elif (CPUS_COUNT == 9)
+#define CPUS \
+ CPU_0 \
+ CPU_1 \
+ CPU_2 \
+ CPU_3 \
+ CPU_4 \
+ CPU_5 \
+ CPU_6 \
+ CPU_7 \
+ CPU_8
+
+#elif (CPUS_COUNT == 12)
+#define CPUS \
+ CPU_0 \
+ CPU_1 \
+ CPU_2 \
+ CPU_3 \
+ CPU_4 \
+ CPU_5 \
+ CPU_6 \
+ CPU_7 \
+ CPU_8 \
+ CPU_9 \
+ CPU_10 \
+ CPU_11
+
+#else
+#define CPUS \
+ CPU_0 \
+ CPU_1 \
+ CPU_2 \
+ CPU_3 \
+ CPU_4 \
+ CPU_5 \
+ CPU_6 \
+ CPU_7 \
+ CPU_8 \
+ CPU_9 \
+ CPU_10 \
+ CPU_11 \
+ CPU_12 \
+ CPU_13 \
+ CPU_14 \
+ CPU_15
+#endif /* CPUS_COUNT */
+
+#define CORE(n) \
+ core##n { \
+ cpu = <&CONC(CPU, __COUNTER__)>; \
+ };
+
+/* Max 4 CPUs per cluster */
+#if (CPUS_PER_CLUSTER == 1)
+#define CLUSTER(n) \
+ cluster##n { \
+ CORE(0) \
+ };
+#elif (CPUS_PER_CLUSTER == 2)
+#define CLUSTER(n) \
+ cluster##n { \
+ CORE(0) \
+ CORE(1) \
+ };
+
+#elif (CPUS_PER_CLUSTER == 3)
+#define CLUSTER(n) \
+ cluster##n { \
+ CORE(0) \
+ CORE(1) \
+ CORE(2) \
+ };
+
+#else
+#define CLUSTER(n) \
+ cluster##n { \
+ CORE(0) \
+ CORE(1) \
+ CORE(2) \
+ CORE(3) \
+ };
+#endif /* CPUS_PER_CLUSTER */
+
+/* Max 4 clusters */
+#if (CLUSTER_COUNT == 1)
+#define CPU_MAP \
+ cpu-map { \
+ CLUSTER(0) \
+ };
+
+#elif (CLUSTER_COUNT == 2)
+#define CPU_MAP \
+ cpu-map { \
+ CLUSTER(0) \
+ CLUSTER(1) \
+ };
+
+#elif (CLUSTER_COUNT == 3)
+#define CPU_MAP \
+ cpu-map { \
+ CLUSTER(0) \
+ CLUSTER(1) \
+ CLUSTER(2) \
+ };
+
+#else
+#define CPU_MAP \
+ cpu-map { \
+ CLUSTER(0) \
+ CLUSTER(1) \
+ CLUSTER(2) \
+ CLUSTER(3) \
+ };
+#endif /* CLUSTER_COUNT */
+
+#endif /* FVP_DEFS_DTSI */
diff --git a/fdts/fvp-foundation-gicv2-psci.dts b/fdts/fvp-foundation-gicv2-psci.dts
new file mode 100644
index 0000000..5a82c46
--- /dev/null
+++ b/fdts/fvp-foundation-gicv2-psci.dts
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Configuration: 1 cluster with up to 4 CPUs */
+
+/dts-v1/;
+
+#define AFF
+#define CLUSTER_COUNT 1
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "fvp-defs.dtsi"
+
+/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>;
+ max-pwr-lvl = <2>;
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ CPU_MAP
+
+ 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>;
+ };
+ };
+
+ CPUS
+
+ 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 = <GIC_PPI 13
+ (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14
+ (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11
+ (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10
+ (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>;
+ 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"
+ };
+};
diff --git a/fdts/fvp-foundation-gicv3-psci.dts b/fdts/fvp-foundation-gicv3-psci.dts
new file mode 100644
index 0000000..e1249d4
--- /dev/null
+++ b/fdts/fvp-foundation-gicv3-psci.dts
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Configuration: 1 cluster with up to 4 CPUs */
+
+/dts-v1/;
+
+#define AFF
+#define CLUSTER_COUNT 1
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "fvp-defs.dtsi"
+
+/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>;
+ max-pwr-lvl = <2>;
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ CPU_MAP
+
+ 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>;
+ };
+ };
+
+ CPUS
+
+ 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 = <GIC_PPI 13
+ (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14
+ (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11
+ (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10
+ (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>;
+ 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"
+ };
+};
diff --git a/fdts/fvp-foundation-motherboard.dtsi b/fdts/fvp-foundation-motherboard.dtsi
new file mode 100644
index 0000000..9ee5b64
--- /dev/null
+++ b/fdts/fvp-foundation-motherboard.dtsi
@@ -0,0 +1,184 @@
+/*
+ * 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>;
+ };
+ };
+ };
diff --git a/fdts/fvp-ve-Cortex-A5x1.dts b/fdts/fvp-ve-Cortex-A5x1.dts
new file mode 100644
index 0000000..612b3b2
--- /dev/null
+++ b/fdts/fvp-ve-Cortex-A5x1.dts
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/dts-v1/;
+
+#include "rtsm_ve-motherboard.dtsi"
+
+/ {
+ model = "V2P-CA5s";
+ compatible = "arm,vexpress,v2p-ca5s", "arm,vexpress";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #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 = <0 0x80000000 0x1000000>;
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges;
+
+ /* Chipselect 2,00000000 is physically at 0x18000000 */
+ vram: vram@18000000 {
+ /* 8 MB of designated video RAM */
+ compatible = "shared-dma-pool";
+ reg = <0 0x18000000 0x00800000>;
+ no-map;
+ };
+ };
+
+ hdlcd@2a110000 {
+ compatible = "arm,hdlcd";
+ reg = <0 0x2a110000 0x1000>;
+ interrupts = <0 85 4>;
+ clocks = <&oscclk3>;
+ clock-names = "pxlclk";
+ };
+
+ scu@2c000000 {
+ compatible = "arm,cortex-a5-scu";
+ reg = <0 0x2c000000 0x58>;
+ };
+
+ watchdog@2c000620 {
+ compatible = "arm,cortex-a5-twd-wdt";
+ reg = <0 0x2c000620 0x20>;
+ interrupts = <1 14 0x304>;
+ };
+
+ gic: interrupt-controller@2c001000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ reg = <0 0x2c001000 0x1000>,
+ <0 0x2c000100 0x100>;
+ };
+
+ mcc {
+ oscclk0: oscclk0 {
+ /* 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: oscclk1 {
+ /* 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";
+ };
+
+ oscclk2 {
+ /* DDR2 */
+ compatible = "arm,vexpress-osc";
+ arm,vexpress-sysreg,func = <1 2>;
+ freq-range = <80000000 120000000>;
+ #clock-cells = <0>;
+ clock-output-names = "oscclk2";
+ };
+
+ oscclk3: oscclk3 {
+ /* HDLCD */
+ compatible = "arm,vexpress-osc";
+ arm,vexpress-sysreg,func = <1 3>;
+ freq-range = <23750000 165000000>;
+ #clock-cells = <0>;
+ clock-output-names = "oscclk3";
+ };
+
+ oscclk4 {
+ /* 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: oscclk5 {
+ /* SMB clock */
+ compatible = "arm,vexpress-osc";
+ arm,vexpress-sysreg,func = <1 5>;
+ freq-range = <25000000 60000000>;
+ #clock-cells = <0>;
+ clock-output-names = "oscclk5";
+ };
+ };
+
+ panel {
+ compatible = "arm,rtsm-display";
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&clcd_pads>;
+ };
+ };
+ };
+
+ bus@8000000 {
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 63>;
+ interrupt-map = <0 0 0 &gic GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 1 &gic GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 2 &gic GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 3 &gic GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 4 &gic GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 5 &gic GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 6 &gic GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 7 &gic GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 8 &gic GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 9 &gic GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 10 &gic GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 11 &gic GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 12 &gic GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 13 &gic GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 15 &gic GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 42 &gic GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 43 &gic GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 44 &gic GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 46 &gic GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+ };
+};
diff --git a/fdts/fvp-ve-Cortex-A7x1.dts b/fdts/fvp-ve-Cortex-A7x1.dts
new file mode 100644
index 0000000..6ec6adb
--- /dev/null
+++ b/fdts/fvp-ve-Cortex-A7x1.dts
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/dts-v1/;
+
+#include "rtsm_ve-motherboard.dtsi"
+
+/ {
+ model = "V2F-1XV7 Cortex-A7x1 SMM";
+ compatible = "arm,vexpress,v2f-1xv7", "arm,vexpress";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0>;
+ };
+ };
+
+ memory@0,80000000 {
+ device_type = "memory";
+ reg = <0 0x80000000 0x80000000>; /* 2GB @ 2GB */
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges;
+
+ /* Chipselect 2,00000000 is physically at 0x18000000 */
+ vram: vram@18000000 {
+ /* 8 MB of designated video RAM */
+ compatible = "shared-dma-pool";
+ reg = <0 0x18000000 0x00800000>;
+ no-map;
+ };
+ };
+
+ gic: interrupt-controller@2c001000 {
+ compatible = "arm,cortex-a15-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ reg = <0 0x2c001000 0x1000>,
+ <0 0x2c002000 0x1000>,
+ <0 0x2c004000 0x2000>,
+ <0 0x2c006000 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";
+ };
+
+ panel {
+ compatible = "arm,rtsm-display";
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&clcd_pads>;
+ };
+ };
+ };
+
+ bus@8000000 {
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 63>;
+ interrupt-map = <0 0 0 &gic GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 1 &gic GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 2 &gic GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 3 &gic GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 4 &gic GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 5 &gic GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 6 &gic GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 7 &gic GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 8 &gic GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 9 &gic GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 10 &gic GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 11 &gic GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 12 &gic GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 13 &gic GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 15 &gic GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 42 &gic GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 43 &gic GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 44 &gic GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 46 &gic GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+ };
+};
diff --git a/fdts/juno-ethosn.dtsi b/fdts/juno-ethosn.dtsi
new file mode 100644
index 0000000..4609524
--- /dev/null
+++ b/fdts/juno-ethosn.dtsi
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * This device tree is only an example and some properties have been omitted.
+ *
+ * Refer to the Arm(R) Ethos(TM)-N driver stack for complete device tree examples.
+ * https://github.com/ARM-software/ethos-n-driver-stack
+ */
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ smmu_ethosn0: iommu@6f400000 {
+ compatible = "arm,smmu-v3";
+ reg = <0 0x6f400000 0 0x80000>;
+ status = "okay";
+ /* msi-parent omitted */
+ #iommu-cells = <0x1>;
+ };
+
+ ethosn0: ethosn@6f300000 {
+ compatible = "ethosn";
+ reg = <0 0x6f300000 0 0x00100000>;
+ status = "okay";
+
+ core0 {
+ compatible = "ethosn-core";
+ status = "okay";
+
+ main_allocator {
+ compatible = "ethosn-main_allocator";
+ status = "okay";
+
+ firmware {
+ compatible = "ethosn-memory";
+ iommus = <&smmu_ethosn0 0>;
+ };
+
+ working_data {
+ compatible = "ethosn-memory";
+ iommus = <&smmu_ethosn0 1>;
+ };
+ };
+ };
+
+ asset_allocator {
+ compatible = "ethosn-asset_allocator";
+ status = "okay";
+
+ command_stream {
+ compatible = "ethosn-memory";
+ iommus = <&smmu_ethosn0 2>;
+ };
+
+ weight_data {
+ compatible = "ethosn-memory";
+ iommus = <&smmu_ethosn0 3>;
+ };
+
+ buffer_data {
+ compatible = "ethosn-memory";
+ iommus = <&smmu_ethosn0 4>;
+ };
+
+ intermediate_data {
+ compatible = "ethosn-memory";
+ iommus = <&smmu_ethosn0 5>;
+ };
+ };
+ };
+};
diff --git a/fdts/juno.dts b/fdts/juno.dts
new file mode 100644
index 0000000..56fe167
--- /dev/null
+++ b/fdts/juno.dts
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+
+};
+
+#if ARM_ETHOSN_NPU_DRIVER
+ #include "juno-ethosn.dtsi"
+#endif
diff --git a/fdts/morello-fvp.dts b/fdts/morello-fvp.dts
new file mode 100644
index 0000000..dc3df41
--- /dev/null
+++ b/fdts/morello-fvp.dts
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+#include "morello.dtsi"
+
+/ {
+ model = "Arm Morello Fixed Virtual Platform";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ secure-firmware@ff000000 {
+ reg = <0 0xff000000 0 0x01000000>;
+ no-map;
+ };
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&CPU0>;
+ };
+ core1 {
+ cpu = <&CPU1>;
+ };
+ };
+ cluster1 {
+ core0 {
+ cpu = <&CPU2>;
+ };
+ core1 {
+ cpu = <&CPU3>;
+ };
+ };
+ };
+ CPU0: cpu0@0 {
+ compatible = "arm,armv8";
+ reg = <0x0 0x0>;
+ device_type = "cpu";
+ enable-method = "psci";
+ clocks = <&scmi_dvfs 0>;
+ };
+ CPU1: cpu1@100 {
+ compatible = "arm,armv8";
+ reg = <0x0 0x100>;
+ device_type = "cpu";
+ enable-method = "psci";
+ clocks = <&scmi_dvfs 0>;
+ };
+ CPU2: cpu2@10000 {
+ compatible = "arm,armv8";
+ reg = <0x0 0x10000>;
+ device_type = "cpu";
+ enable-method = "psci";
+ clocks = <&scmi_dvfs 1>;
+ };
+ CPU3: cpu3@10100 {
+ compatible = "arm,armv8";
+ reg = <0x0 0x10100>;
+ device_type = "cpu";
+ enable-method = "psci";
+ clocks = <&scmi_dvfs 1>;
+ };
+ };
+
+ /* The first bank of memory, memory map is actually provided by UEFI. */
+ memory@80000000 {
+ device_type = "memory";
+ /* [0x80000000-0xffffffff] */
+ reg = <0x00000000 0x80000000 0x0 0x80000000>;
+ };
+
+ memory@8080000000 {
+ device_type = "memory";
+ /* [0x8080000000-0x83ffffffff] */
+ reg = <0x00000080 0x80000000 0x1 0x80000000>;
+ };
+
+ virtio_block@1c170000 {
+ compatible = "virtio,mmio";
+ reg = <0x0 0x1c170000 0x0 0x200>;
+ interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ virtio_net@1c180000 {
+ compatible = "virtio,mmio";
+ reg = <0x0 0x1c180000 0x0 0x200>;
+ interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ virtio_rng@1c190000 {
+ compatible = "virtio,mmio";
+ reg = <0x0 0x1c190000 0x0 0x200>;
+ interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ virtio_p9@1c1a0000 {
+ compatible = "virtio,mmio";
+ reg = <0x0 0x1c1a0000 0x0 0x200>;
+ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ ethernet@1d100000 {
+ compatible = "smsc,lan91c111";
+ reg = <0x0 0x1d100000 0x0 0x10000>;
+ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ kmi@1c150000 {
+ compatible = "arm,pl050", "arm,primecell";
+ reg = <0x0 0x1c150000 0x0 0x1000>;
+ interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&bp_clock24mhz>, <&bp_clock24mhz>;
+ clock-names = "KMIREFCLK", "apb_pclk";
+ };
+
+ kmi@1c160000 {
+ compatible = "arm,pl050", "arm,primecell";
+ reg = <0x0 0x1c160000 0x0 0x1000>;
+ interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&bp_clock24mhz>, <&bp_clock24mhz>;
+ clock-names = "KMIREFCLK", "apb_pclk";
+ };
+
+ firmware {
+ scmi {
+ compatible = "arm,scmi";
+ mbox-names = "tx", "rx";
+ mboxes = <&mailbox 1 0>, <&mailbox 1 1>;
+ shmem = <&cpu_scp_hpri0>, <&cpu_scp_hpri1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ scmi_dvfs: protocol@13 {
+ reg = <0x13>;
+ #clock-cells = <1>;
+ };
+ };
+ };
+
+ bp_clock24mhz: clock24mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24000000>;
+ clock-output-names = "bp:clock24mhz";
+ };
+};
+
+&gic {
+ reg = <0x0 0x30000000 0 0x10000>, /* GICD */
+ <0x0 0x300c0000 0 0x80000>; /* GICR */
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+};
diff --git a/fdts/morello-soc.dts b/fdts/morello-soc.dts
new file mode 100644
index 0000000..5f147b7
--- /dev/null
+++ b/fdts/morello-soc.dts
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+#include "morello.dtsi"
+
+/ {
+ model = "Arm Morello System Development Platform";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ secure-firmware@ff000000 {
+ reg = <0 0xff000000 0 0x01000000>;
+ no-map;
+ };
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+ cpu0@0 {
+ compatible = "arm,armv8";
+ reg = <0x0 0x0>;
+ device_type = "cpu";
+ enable-method = "psci";
+ clocks = <&scmi_dvfs 0>;
+ };
+ cpu1@100 {
+ compatible = "arm,armv8";
+ reg = <0x0 0x100>;
+ device_type = "cpu";
+ enable-method = "psci";
+ clocks = <&scmi_dvfs 0>;
+ };
+ cpu2@10000 {
+ compatible = "arm,armv8";
+ reg = <0x0 0x10000>;
+ device_type = "cpu";
+ enable-method = "psci";
+ clocks = <&scmi_dvfs 1>;
+ };
+ cpu3@10100 {
+ compatible = "arm,armv8";
+ reg = <0x0 0x10100>;
+ device_type = "cpu";
+ enable-method = "psci";
+ clocks = <&scmi_dvfs 1>;
+ };
+ };
+
+ /* The first bank of memory, memory map is actually provided by UEFI. */
+ memory@80000000 {
+ device_type = "memory";
+ /* [0x80000000-0xffffffff] */
+ reg = <0x00000000 0x80000000 0x0 0x7F000000>;
+ };
+
+ memory@8080000000 {
+ device_type = "memory";
+ /* [0x8080000000-0x83f7ffffff] */
+ reg = <0x00000080 0x80000000 0x3 0x78000000>;
+ };
+
+ smmu_pcie: iommu@4f400000 {
+ compatible = "arm,smmu-v3";
+ reg = <0 0x4f400000 0 0x40000>;
+ interrupts = <GIC_SPI 235 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 237 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 40 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 236 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "eventq", "gerror", "priq", "cmdq-sync";
+ msi-parent = <&its2 0>;
+ #iommu-cells = <1>;
+ dma-coherent;
+ };
+
+ pcie_ctlr: pcie@28c0000000 {
+ compatible = "pci-host-ecam-generic";
+ device_type = "pci";
+ reg = <0x28 0xC0000000 0 0x10000000>;
+ bus-range = <0 255>;
+ linux,pci-domain = <0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ dma-coherent;
+ ranges = <0x01000000 0x00 0x00000000 0x00 0x6F000000 0x00 0x00800000>,
+ <0x02000000 0x00 0x60000000 0x00 0x60000000 0x00 0x0F000000>,
+ <0x42000000 0x09 0x00000000 0x09 0x00000000 0x1F 0xC0000000>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &gic 0 0 0 169 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &gic 0 0 0 170 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &gic 0 0 0 171 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &gic 0 0 0 172 IRQ_TYPE_LEVEL_HIGH>;
+ msi-map = <0 &its_pcie 0 0x10000>;
+ iommu-map = <0 &smmu_pcie 0 0x10000>;
+ status = "okay";
+ };
+
+ smmu_ccix: iommu@4f000000 {
+ compatible = "arm,smmu-v3";
+ reg = <0 0x4f000000 0 0x40000>;
+ interrupts = <GIC_SPI 228 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 230 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 41 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 229 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "eventq", "gerror", "priq", "cmdq-sync";
+ msi-parent = <&its1 0>;
+ #iommu-cells = <1>;
+ dma-coherent;
+ };
+
+ ccix_pcie_ctlr: pcie@4fc0000000 {
+ compatible = "pci-host-ecam-generic";
+ device_type = "pci";
+ reg = <0x4F 0xC0000000 0 0x10000000>;
+ bus-range = <0 255>;
+ linux,pci-domain = <1>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ dma-coherent;
+ ranges = <0x01000000 0x00 0x00000000 0x00 0x7F000000 0x00 0x00800000>,
+ <0x02000000 0x00 0x70000000 0x00 0x70000000 0x00 0x0F000000>,
+ <0x42000000 0x30 0x00000000 0x30 0x00000000 0x1F 0xC0000000>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &gic 0 0 0 201 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &gic 0 0 0 202 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &gic 0 0 0 203 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &gic 0 0 0 204 IRQ_TYPE_LEVEL_HIGH>;
+ msi-map = <0 &its_ccix 0 0x10000>;
+ iommu-map = <0 &smmu_ccix 0 0x10000>;
+ status = "okay";
+ };
+
+ smmu_dp: iommu@2ce00000 {
+ compatible = "arm,smmu-v3";
+ reg = <0 0x2ce00000 0 0x40000>;
+ interrupts = <GIC_SPI 76 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 80 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 78 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "eventq", "gerror", "cmdq-sync";
+ #iommu-cells = <1>;
+ };
+
+ dp0: display@2cc00000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "arm,mali-d32", "arm,mali-d71";
+ reg = <0 0x2cc00000 0 0x20000>;
+ interrupts = <0 69 4>;
+ interrupt-names = "DPU";
+ clocks = <&dpu_aclk>;
+ clock-names = "aclk";
+ iommus = <&smmu_dp 0>, <&smmu_dp 1>, <&smmu_dp 2>, <&smmu_dp 3>,
+ <&smmu_dp 8>;
+
+ pl0: pipeline@0 {
+ reg = <0>;
+ clocks = <&scmi_clk 1>;
+ clock-names = "pxclk";
+ pl_id = <0>;
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 {
+ reg = <0>;
+ dp_pl0_out0: endpoint {
+ remote-endpoint = <&tda998x_0_input>;
+ };
+ };
+ };
+ };
+ };
+
+ i2c@1c0f0000 {
+ compatible = "cdns,i2c-r1p14";
+ reg = <0x0 0x1c0f0000 0x0 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-frequency = <100000>;
+ i2c-sda-hold-time-ns = <500>;
+ interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&dpu_aclk>;
+
+ hdmi-transmitter@70 {
+ compatible = "nxp,tda998x";
+ reg = <0x70>;
+ video-ports = <0x234501>;
+ port {
+ tda998x_0_input: endpoint {
+ remote-endpoint = <&dp_pl0_out0>;
+ };
+ };
+ };
+ };
+
+ dpu_aclk: dpu_aclk {
+ /* 77.1 MHz derived from 24 MHz reference clock */
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <350000000>;
+ clock-output-names = "aclk";
+ };
+
+ firmware {
+ scmi {
+ compatible = "arm,scmi";
+ mbox-names = "tx", "rx";
+ mboxes = <&mailbox 1 0>, <&mailbox 1 1>;
+ shmem = <&cpu_scp_hpri0>, <&cpu_scp_hpri1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ scmi_dvfs: protocol@13 {
+ reg = <0x13>;
+ #clock-cells = <1>;
+ };
+ scmi_clk: protocol@14 {
+ reg = <0x14>;
+ #clock-cells = <1>;
+ };
+ };
+ };
+};
+
+&gic {
+ reg = <0x0 0x30000000 0 0x10000>, /* GICD */
+ <0x0 0x300c0000 0 0x80000>; /* GICR */
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+
+ its1: msi-controller@30040000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x0 0x30040000 0x0 0x20000>;
+ };
+
+ its2: msi-controller@30060000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x0 0x30060000 0x0 0x20000>;
+ };
+
+ its_ccix: msi-controller@30080000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x0 0x30080000 0x0 0x20000>;
+ };
+
+ its_pcie: msi-controller@300a0000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x0 0x300a0000 0x0 0x20000>;
+ };
+};
diff --git a/fdts/morello.dtsi b/fdts/morello.dtsi
new file mode 100644
index 0000000..20640c5
--- /dev/null
+++ b/fdts/morello.dtsi
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ compatible = "arm,morello";
+
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ aliases {
+ serial0 = &soc_uart0;
+ };
+
+ gic: interrupt-controller@2c010000 {
+ compatible = "arm,gic-v3";
+ #address-cells = <2>;
+ #interrupt-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+ interrupt-controller;
+ };
+
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ spe-pmu {
+ compatible = "arm,statistical-profiling-extension-v1";
+ interrupts = <GIC_PPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+ };
+
+ mailbox: mhu@45000000 {
+ compatible = "arm,mhu-doorbell", "arm,primecell";
+ reg = <0x0 0x45000000 0x0 0x1000>;
+ interrupts = <GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "mhu_lpri_rx",
+ "mhu_hpri_rx";
+ #mbox-cells = <2>;
+ mbox-name = "ARM-MHU";
+ clocks = <&soc_refclk50mhz>;
+ clock-names = "apb_pclk";
+ };
+
+ sram: sram@45200000 {
+ compatible = "mmio-sram";
+ reg = <0x0 0x06000000 0x0 0x8000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x0 0x06000000 0x8000>;
+
+ cpu_scp_hpri0: scp-sram@0 {
+ compatible = "arm,scmi-shmem";
+ reg = <0x0 0x80>;
+ };
+
+ cpu_scp_hpri1: scp-sram@80 {
+ compatible = "arm,scmi-shmem";
+ reg = <0x80 0x80>;
+ };
+ };
+
+ soc_refclk50mhz: refclk50mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ clock-output-names = "apb_pclk";
+ };
+
+ soc_uartclk: uartclk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ clock-output-names = "uartclk";
+ };
+
+ soc_uart0: serial@2a400000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0 0x2a400000 0x0 0x1000>;
+ interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&soc_uartclk>, <&soc_refclk50mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ status = "okay";
+ };
+};
diff --git a/fdts/n1sdp-multi-chip.dts b/fdts/n1sdp-multi-chip.dts
new file mode 100644
index 0000000..852b899
--- /dev/null
+++ b/fdts/n1sdp-multi-chip.dts
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: (GPL-2.0 or BSD-3-Clause)
+/*
+ * Copyright (c) 2019-2022, Arm Limited.
+ */
+
+#include "n1sdp-single-chip.dts"
+
+/ {
+ cpus {
+ cpu4@100000000 {
+ compatible = "arm,neoverse-n1";
+ reg = <0x1 0x0>;
+ device_type = "cpu";
+ enable-method = "psci";
+ numa-node-id = <1>;
+ };
+ cpu5@100000100 {
+ compatible = "arm,neoverse-n1";
+ reg = <0x1 0x00000100>;
+ device_type = "cpu";
+ enable-method = "psci";
+ numa-node-id = <1>;
+ };
+ cpu6@100010000 {
+ compatible = "arm,neoverse-n1";
+ reg = <0x1 0x00010000>;
+ device_type = "cpu";
+ enable-method = "psci";
+ numa-node-id = <1>;
+ };
+ cpu7@100010100 {
+ compatible = "arm,neoverse-n1";
+ reg = <0x1 0x00010100>;
+ device_type = "cpu";
+ enable-method = "psci";
+ numa-node-id = <1>;
+ };
+ };
+
+ /* Remote N1SDP board address is mapped at offset 4TB.
+ * First DRAM Bank of remote N1SDP board is mapped at 4TB + 2GB.
+ */
+ memory@40080000000 {
+ device_type = "memory";
+ reg = <0x00000400 0x80000000 0x0 0x80000000>,
+ <0x00000480 0x80000000 0x3 0x80000000>;
+ numa-node-id = <1>;
+ };
+
+ distance-map {
+ compatible = "numa-distance-map-v1";
+ distance-matrix = <0 0 10>,
+ <0 1 20>,
+ <1 1 10>;
+ };
+
+ smmu_secondary_pcie: iommu@4004f400000 {
+ compatible = "arm,smmu-v3";
+ reg = <0x400 0x4f400000 0 0x40000>;
+ interrupts = <GIC_SPI 715 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 716 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 717 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "eventq", "cmdq-sync", "gerror";
+ msi-parent = <&its2_secondary 0>;
+ #iommu-cells = <1>;
+ dma-coherent;
+ };
+
+ pcie_secondary_ctlr: pcie@40070000000 {
+ compatible = "arm,n1sdp-pcie";
+ device_type = "pci";
+ reg = <0x400 0x70000000 0 0x1200000>;
+ bus-range = <0 0xff>;
+ linux,pci-domain = <2>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ dma-coherent;
+ ranges = <0x01000000 0x00 0x00000000 0x400 0x75200000 0x00 0x00010000>,
+ <0x02000000 0x00 0x71200000 0x400 0x71200000 0x00 0x04000000>,
+ <0x42000000 0x09 0x00000000 0x409 0x00000000 0x20 0x00000000>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &gic 0 0 0 649 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &gic 0 0 0 650 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &gic 0 0 0 651 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &gic 0 0 0 652 IRQ_TYPE_LEVEL_HIGH>;
+ msi-map = <0 &its_secondary_pcie 0 0x10000>;
+ iommu-map = <0 &smmu_secondary_pcie 0 0x10000>;
+ numa-node-id = <1>;
+ status = "okay";
+ };
+
+};
+
+&gic {
+ #redistributor-regions = <2>;
+ reg = <0x0 0x30000000 0 0x10000>, /* GICD */
+ <0x0 0x300c0000 0 0x80000>, /* GICR */
+ <0x400 0x300c0000 0 0x80000>; /* GICR */
+
+ its2_secondary: its@40030060000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x400 0x30060000 0x0 0x20000>;
+ };
+
+ its_secondary_pcie: its@400300a0000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x400 0x300a0000 0x0 0x20000>;
+ };
+};
+
+&pcie_ctlr {
+ numa-node-id = <0>;
+};
+
+&ccix_pcie_ctlr {
+ numa-node-id = <0>;
+};
diff --git a/fdts/n1sdp-single-chip.dts b/fdts/n1sdp-single-chip.dts
new file mode 100644
index 0000000..3c091ac
--- /dev/null
+++ b/fdts/n1sdp-single-chip.dts
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: (GPL-2.0 or BSD-3-Clause)
+/*
+ * Copyright (c) 2019-2020, Arm Limited.
+ */
+
+/dts-v1/;
+
+#include "n1sdp.dtsi"
+
+/ {
+ model = "Arm Neoverse N1 System Development Platform";
+ compatible = "arm,neoverse-n1-sdp", "arm,neoverse-n1-soc";
+
+ aliases {
+ serial0 = &soc_uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ /* This configuration assumes that standard setup with two DIMM modules.
+ * In the first 2GB of DRAM bank the top 16MB are reserved by firmware as secure memory.
+ * This configuration assumes 16GB of total DRAM being populated.
+ */
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x00000000 0x80000000 0x0 0x7f000000>,
+ <0x00000080 0x80000000 0x3 0x80000000>;
+ numa-node-id = <0>;
+ };
+
+ soc_refclk60mhz: refclk60mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <60000000>;
+ clock-output-names = "iofpga_clk";
+ };
+
+ soc_hdlcdclk: hdlcdclk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <23750000>;
+ clock-output-names = "hdlcdclk";
+ };
+
+ hdlcd: hdlcd@1c050000 {
+ compatible = "arm,hdlcd";
+ reg = <0 0x1c050000 0 0x1000>;
+ interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&soc_hdlcdclk>;
+ clock-names = "pxlclk";
+
+ port {
+ hdlcd0_output: endpoint {
+ remote-endpoint = <&tda998x_0_input>;
+ };
+ };
+ };
+
+ i2c@1c0f0000 {
+ compatible = "arm,versatile-i2c";
+ reg = <0x0 0x1c0f0000 0x0 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-frequency = <400000>;
+ i2c-sda-hold-time-ns = <500>;
+ clocks = <&soc_refclk60mhz>;
+
+ hdmi-transmitter@70 {
+ compatible = "nxp,tda998x";
+ reg = <0x70>;
+ port {
+ tda998x_0_input: endpoint {
+ remote-endpoint = <&hdlcd0_output>;
+ };
+ };
+ };
+ };
+};
+
+&pcie_ctlr {
+ status = "okay";
+};
+
+&ccix_pcie_ctlr {
+ status = "okay";
+};
+
+&soc_uart0 {
+ status = "okay";
+};
diff --git a/fdts/n1sdp.dtsi b/fdts/n1sdp.dtsi
new file mode 100644
index 0000000..88f8734
--- /dev/null
+++ b/fdts/n1sdp.dtsi
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: (GPL-2.0 or BSD-3-Clause)
+/*
+ * Copyright (c) 2019-2020, Arm Limited.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu0@0 {
+ compatible = "arm,neoverse-n1";
+ reg = <0x0 0x0>;
+ device_type = "cpu";
+ enable-method = "psci";
+ numa-node-id = <0>;
+ };
+ cpu1@100 {
+ compatible = "arm,neoverse-n1";
+ reg = <0x0 0x100>;
+ device_type = "cpu";
+ enable-method = "psci";
+ numa-node-id = <0>;
+ };
+ cpu2@10000 {
+ compatible = "arm,neoverse-n1";
+ reg = <0x0 0x10000>;
+ device_type = "cpu";
+ enable-method = "psci";
+ numa-node-id = <0>;
+ };
+ cpu3@10100 {
+ compatible = "arm,neoverse-n1";
+ reg = <0x0 0x10100>;
+ device_type = "cpu";
+ enable-method = "psci";
+ numa-node-id = <0>;
+ };
+ };
+
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ spe-pmu {
+ compatible = "arm,statistical-profiling-extension-v1";
+ interrupts = <GIC_PPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+ };
+
+ soc_refclk100mhz: refclk100mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <100000000>;
+ clock-output-names = "apb_pclk";
+ };
+
+ soc_uartclk: uartclk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ clock-output-names = "uartclk";
+ };
+
+ soc {
+ compatible = "arm,neoverse-n1-soc", "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ gic: interrupt-controller@30000000 {
+ compatible = "arm,gic-v3";
+ #address-cells = <2>;
+ #interrupt-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+ interrupt-controller;
+ reg = <0x0 0x30000000 0 0x10000>, /* GICD */
+ <0x0 0x300c0000 0 0x80000>; /* GICR */
+
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+
+ its1: its@30040000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x0 0x30040000 0x0 0x20000>;
+ };
+
+ its2: its@30060000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x0 0x30060000 0x0 0x20000>;
+ };
+
+ its_ccix: its@30080000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x0 0x30080000 0x0 0x20000>;
+ };
+
+ its_pcie: its@300a0000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x0 0x300a0000 0x0 0x20000>;
+ };
+ };
+
+ smmu_ccix: iommu@4f000000 {
+ compatible = "arm,smmu-v3";
+ reg = <0 0x4f000000 0 0x40000>;
+ interrupts = <GIC_SPI 228 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 229 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 230 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "eventq", "cmdq-sync", "gerror";
+ msi-parent = <&its1 0>;
+ #iommu-cells = <1>;
+ dma-coherent;
+ };
+
+ smmu_pcie: iommu@4f400000 {
+ compatible = "arm,smmu-v3";
+ reg = <0 0x4f400000 0 0x40000>;
+ interrupts = <GIC_SPI 235 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 236 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 237 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "eventq", "cmdq-sync", "gerror";
+ msi-parent = <&its2 0>;
+ #iommu-cells = <1>;
+ dma-coherent;
+ };
+
+ pcie_ctlr: pcie@70000000 {
+ compatible = "arm,n1sdp-pcie";
+ device_type = "pci";
+ reg = <0 0x70000000 0 0x1200000>;
+ bus-range = <0 17>;
+ linux,pci-domain = <0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ dma-coherent;
+ ranges = <0x01000000 0x00 0x00000000 0x00 0x75200000 0x00 0x00010000>,
+ <0x02000000 0x00 0x71200000 0x00 0x71200000 0x00 0x04000000>,
+ <0x42000000 0x09 0x00000000 0x09 0x00000000 0x20 0x00000000>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &gic 0 0 0 169 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &gic 0 0 0 170 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &gic 0 0 0 171 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &gic 0 0 0 172 IRQ_TYPE_LEVEL_HIGH>;
+ msi-map = <0 &its_pcie 0 0x10000>;
+ iommu-map = <0 &smmu_pcie 0 0x10000>;
+ status = "disabled";
+ };
+
+ ccix_pcie_ctlr: pcie@68000000 {
+ compatible = "arm,n1sdp-pcie";
+ device_type = "pci";
+ reg = <0 0x68000000 0 0x1200000>;
+ bus-range = <0 17>;
+ linux,pci-domain = <1>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ dma-coherent;
+ ranges = <0x01000000 0x00 0x00000000 0x00 0x6d200000 0x00 0x00010000>,
+ <0x02000000 0x00 0x69200000 0x00 0x69200000 0x00 0x04000000>,
+ <0x42000000 0x29 0x00000000 0x29 0x00000000 0x20 0x00000000>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &gic 0 0 0 201 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &gic 0 0 0 202 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &gic 0 0 0 203 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &gic 0 0 0 204 IRQ_TYPE_LEVEL_HIGH>;
+ msi-map = <0 &its_ccix 0 0x10000>;
+ iommu-map = <0 &smmu_ccix 0 0x10000>;
+ status = "disabled";
+ };
+
+ soc_uart0: serial@2a400000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0 0x2a400000 0x0 0x1000>;
+ interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&soc_uartclk>, <&soc_refclk100mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ status = "disabled";
+ };
+ };
+};
diff --git a/fdts/rtsm_ve-motherboard.dtsi b/fdts/rtsm_ve-motherboard.dtsi
new file mode 100644
index 0000000..0a824b3
--- /dev/null
+++ b/fdts/rtsm_ve-motherboard.dtsi
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * ARM Ltd. Fast Models
+ *
+ * Copyright (c) 2012-2022 ARM Ltd.
+ *
+ * Versatile Express (VE) system model
+ * Motherboard component
+ *
+ * VEMotherBoard.lisa
+ */
+/ {
+ 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";
+ };
+
+ v2m_fixed_3v3: v2m-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ mcc {
+ compatible = "arm,vexpress,config-bus";
+ arm,vexpress,config-bridge = <&v2m_sysreg>;
+
+ v2m_oscclk1: oscclk1 {
+ /* CLCD clock */
+ compatible = "arm,vexpress-osc";
+ arm,vexpress-sysreg,func = <1 1>;
+ freq-range = <23750000 63500000>;
+ #clock-cells = <0>;
+ clock-output-names = "v2m:oscclk1";
+ };
+
+ reset {
+ compatible = "arm,vexpress-reset";
+ arm,vexpress-sysreg,func = <5 0>;
+ };
+
+ muxfpga {
+ compatible = "arm,vexpress-muxfpga";
+ arm,vexpress-sysreg,func = <7 0>;
+ };
+
+ shutdown {
+ compatible = "arm,vexpress-shutdown";
+ arm,vexpress-sysreg,func = <8 0>;
+ };
+
+ reboot {
+ compatible = "arm,vexpress-reboot";
+ arm,vexpress-sysreg,func = <9 0>;
+ };
+
+ dvimode {
+ compatible = "arm,vexpress-dvimode";
+ arm,vexpress-sysreg,func = <11 0>;
+ };
+ };
+
+ bus@8000000 {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges = <0 0x8000000 0 0x8000000 0x18000000>;
+
+ motherboard-bus@8000000 {
+ compatible = "arm,vexpress,v2m-p1", "simple-bus";
+ #address-cells = <2>; /* SMB chipselect number and offset */
+ #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>;
+
+ flash@0 {
+ compatible = "arm,vexpress-flash", "cfi-flash";
+ reg = <0 0x00000000 0x04000000>,
+ <4 0x00000000 0x04000000>;
+ bank-width = <4>;
+ };
+
+ ethernet@202000000 {
+ compatible = "smsc,lan91c111";
+ reg = <2 0x02000000 0x10000>;
+ interrupts = <15>;
+ };
+
+ iofpga-bus@300000000 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 3 0 0x210000>;
+
+ 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";
+ assigned-clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&v2m_sysctl 3>, <&v2m_sysctl 3>;
+ assigned-clock-parents = <&v2m_refclk1mhz>, <&v2m_refclk1mhz>, <&v2m_refclk1mhz>, <&v2m_refclk1mhz>;
+ };
+
+ aaci@40000 {
+ compatible = "arm,pl041", "arm,primecell";
+ reg = <0x040000 0x1000>;
+ interrupts = <11>;
+ clocks = <&v2m_clk24mhz>;
+ clock-names = "apb_pclk";
+ };
+
+ mmc@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: serial@90000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x090000 0x1000>;
+ interrupts = <5>;
+ clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ v2m_serial1: serial@a0000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0a0000 0x1000>;
+ interrupts = <6>;
+ clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ v2m_serial2: serial@b0000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0b0000 0x1000>;
+ interrupts = <7>;
+ clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ v2m_serial3: serial@c0000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0c0000 0x1000>;
+ interrupts = <8>;
+ clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ watchdog@f0000 {
+ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0f0000 0x1000>;
+ interrupts = <0>;
+ clocks = <&v2m_refclk32khz>, <&v2m_clk24mhz>;
+ clock-names = "wdog_clk", "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";
+ };
+
+ virtio@130000 {
+ compatible = "virtio,mmio";
+ reg = <0x130000 0x200>;
+ interrupts = <42>;
+ };
+
+ 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>;
+ interrupt-names = "combined";
+ interrupts = <14>;
+ clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>;
+ clock-names = "clcdclk", "apb_pclk";
+ memory-region = <&vram>;
+
+ port {
+ clcd_pads: endpoint {
+ remote-endpoint = <&panel_in>;
+ arm,pl11x,tft-r0g0b0-pads = <0 8 16>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
diff --git a/fdts/stm32mp1-cot-descriptors.dtsi b/fdts/stm32mp1-cot-descriptors.dtsi
new file mode 100644
index 0000000..eb632ff
--- /dev/null
+++ b/fdts/stm32mp1-cot-descriptors.dtsi
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2020-2022, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/nv_cntr_ids.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <tools_share/tbbr_oid.h>
+
+cot {
+ manifests {
+ compatible = "arm, cert-descs";
+
+ stm32mp_cfg_cert: stm32mp_cfg_cert {
+ root-certificate;
+ image-id = <STM32MP_CONFIG_CERT_ID>;
+ antirollback-counter = <&trusted_nv_counter>;
+
+ hw_config_hash: hw_config_hash {
+ oid = HW_CONFIG_HASH_OID;
+ };
+
+ fw_config_hash: fw_config_hash {
+ oid = FW_CONFIG_HASH_OID;
+ };
+ };
+
+ trusted_key_cert: trusted_key_cert {
+ root-certificate;
+ image-id = <TRUSTED_KEY_CERT_ID>;
+ antirollback-counter = <&trusted_nv_counter>;
+
+ trusted_world_pk: trusted_world_pk {
+ oid = TRUSTED_WORLD_PK_OID;
+ };
+ non_trusted_world_pk: non_trusted_world_pk {
+ oid = NON_TRUSTED_WORLD_PK_OID;
+ };
+ };
+
+ trusted_os_fw_key_cert: trusted_os_fw_key_cert {
+ image-id = <TRUSTED_OS_FW_KEY_CERT_ID>;
+ parent = <&trusted_key_cert>;
+ signing-key = <&trusted_world_pk>;
+ antirollback-counter = <&trusted_nv_counter>;
+
+ tos_fw_content_pk: tos_fw_content_pk {
+ oid = TRUSTED_OS_FW_CONTENT_CERT_PK_OID;
+ };
+ };
+
+ trusted_os_fw_content_cert: trusted_os_fw_content_cert {
+ image-id = <TRUSTED_OS_FW_CONTENT_CERT_ID>;
+ parent = <&trusted_os_fw_key_cert>;
+ signing-key = <&tos_fw_content_pk>;
+ antirollback-counter = <&trusted_nv_counter>;
+
+ tos_fw_hash: tos_fw_hash {
+ oid = TRUSTED_OS_FW_HASH_OID;
+ };
+ tos_fw_extra1_hash: tos_fw_extra1_hash {
+ oid = TRUSTED_OS_FW_EXTRA1_HASH_OID;
+ };
+ tos_fw_extra2_hash: tos_fw_extra2_hash {
+ oid = TRUSTED_OS_FW_EXTRA2_HASH_OID;
+ };
+ tos_fw_config_hash: tos_fw_config_hash {
+ oid = TRUSTED_OS_FW_CONFIG_HASH_OID;
+ };
+ };
+
+ non_trusted_fw_key_cert: non_trusted_fw_key_cert {
+ image-id = <NON_TRUSTED_FW_KEY_CERT_ID>;
+ parent = <&trusted_key_cert>;
+ signing-key = <&non_trusted_world_pk>;
+ antirollback-counter = <&non_trusted_nv_counter>;
+
+ nt_fw_content_pk: nt_fw_content_pk {
+ oid = NON_TRUSTED_FW_CONTENT_CERT_PK_OID;
+ };
+ };
+
+ non_trusted_fw_content_cert: non_trusted_fw_content_cert {
+ image-id = <NON_TRUSTED_FW_CONTENT_CERT_ID>;
+ parent = <&non_trusted_fw_key_cert>;
+ signing-key = <&nt_fw_content_pk>;
+ antirollback-counter = <&non_trusted_nv_counter>;
+
+ nt_world_bl_hash: nt_world_bl_hash {
+ oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID;
+ };
+ };
+ };
+
+ images {
+ compatible = "arm, img-descs";
+
+ hw_config {
+ image-id = <HW_CONFIG_ID>;
+ parent = <&stm32mp_cfg_cert>;
+ hash = <&hw_config_hash>;
+ };
+
+ fw_config {
+ image-id = <FW_CONFIG_ID>;
+ parent = <&stm32mp_cfg_cert>;
+ hash = <&fw_config_hash>;
+ };
+
+ bl32_image {
+ image-id = <BL32_IMAGE_ID>;
+ parent = <&trusted_os_fw_content_cert>;
+ hash = <&tos_fw_hash>;
+ };
+
+ bl32_extra1_image {
+ image-id = <BL32_EXTRA1_IMAGE_ID>;
+ parent = <&trusted_os_fw_content_cert>;
+ hash = <&tos_fw_extra1_hash>;
+ };
+
+ bl32_extra2_image {
+ image-id = <BL32_EXTRA2_IMAGE_ID>;
+ parent = <&trusted_os_fw_content_cert>;
+ hash = <&tos_fw_extra2_hash>;
+ };
+
+ tos_fw_config {
+ image-id = <TOS_FW_CONFIG_ID>;
+ parent = <&trusted_os_fw_content_cert>;
+ hash = <&tos_fw_config_hash>;
+ };
+
+ bl33_image {
+ image-id = <BL33_IMAGE_ID>;
+ parent = <&non_trusted_fw_content_cert>;
+ hash = <&nt_world_bl_hash>;
+ };
+ };
+};
+
+non_volatile_counters: non_volatile_counters {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ trusted_nv_counter: trusted_nv_counter {
+ id = <TRUSTED_NV_CTR_ID>;
+ oid = TRUSTED_FW_NVCOUNTER_OID;
+ };
+
+ non_trusted_nv_counter: non_trusted_nv_counter {
+ id = <NON_TRUSTED_NV_CTR_ID>;
+ oid = NON_TRUSTED_FW_NVCOUNTER_OID;
+ };
+};
diff --git a/fdts/stm32mp13-bl2.dtsi b/fdts/stm32mp13-bl2.dtsi
new file mode 100644
index 0000000..836e9ae
--- /dev/null
+++ b/fdts/stm32mp13-bl2.dtsi
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
+ */
+
+/ {
+ aliases {
+#if !STM32MP_EMMC && !STM32MP_SDMMC
+ /delete-property/ mmc0;
+ /delete-property/ mmc1;
+#endif
+ };
+
+ soc {
+#if !STM32MP_USB_PROGRAMMER
+ /delete-node/ usb-otg@49000000;
+#endif
+#if !STM32MP_RAW_NAND
+ /delete-node/ memory-controller@58002000;
+#endif
+#if !STM32MP_SPI_NAND && !STM32MP_SPI_NOR
+ /delete-node/ spi@58003000;
+#endif
+#if !STM32MP_EMMC && !STM32MP_SDMMC
+ /delete-node/ mmc@58005000;
+ /delete-node/ mmc@58007000;
+#endif
+#if !STM32MP_USB_PROGRAMMER
+ /delete-node/ usbh-ohci@5800c000;
+ /delete-node/ usbh-ehci@5800d000;
+#endif
+#if !STM32MP_USB_PROGRAMMER
+ /delete-node/ usbphyc@5a006000;
+#endif
+
+ pinctrl@50002000 {
+#if !STM32MP_EMMC && !STM32MP_SDMMC
+ /delete-node/ sdmmc1-b4-0;
+ /delete-node/ sdmmc2-b4-0;
+#endif
+ };
+ };
+
+ /*
+ * UUID's here are UUID RFC 4122 compliant meaning fieds are stored in
+ * network order (big endian)
+ */
+
+ st-io_policies {
+ fip-handles {
+ compatible = "st,io-fip-handle";
+ fw_cfg_uuid = "5807e16a-8459-47be-8ed5-648e8dddab0e";
+ bl32_uuid = "05d0e189-53dc-1347-8d2b-500a4b7a3e38";
+ bl32_extra1_uuid = "0b70c29b-2a5a-7840-9f65-0a5682738288";
+ bl32_extra2_uuid = "8ea87bb1-cfa2-3f4d-85fd-e7bba50220d9";
+ bl33_uuid = "d6d0eea7-fcea-d54b-9782-9934f234b6e4";
+ hw_cfg_uuid = "08b8f1d9-c9cf-9349-a962-6fbc6b7265cc";
+ tos_fw_cfg_uuid = "26257c1a-dbc6-7f47-8d96-c4c4b0248021";
+#if TRUSTED_BOARD_BOOT
+ stm32mp_cfg_cert_uuid = "501d8dd2-8bce-49a5-84eb-559a9f2eaeaf";
+ t_key_cert_uuid = "827ee890-f860-e411-a1b4-777a21b4f94c";
+ tos_fw_key_cert_uuid = "9477d603-fb60-e411-85dd-b7105b8cee04";
+ nt_fw_key_cert_uuid = "8ad5832a-fb60-e411-8aaf-df30bbc49859";
+ tos_fw_content_cert_uuid = "a49f4411-5e63-e411-8728-3f05722af33d";
+ nt_fw_content_cert_uuid = "8ec4c1f3-5d63-e411-a7a9-87ee40b23fa7";
+#endif
+ };
+ };
+
+#if TRUSTED_BOARD_BOOT
+ tb_fw-config {
+ compatible = "arm,tb_fw";
+
+ /* Disable authentication for development */
+ disable_auth = <0x0>;
+
+ /* Use SRAM2 to manage the mbedTLS heap */
+ mbedtls_heap_addr = <0x0 0x30004000>; /* SRAM2_BASE */
+ mbedtls_heap_size = <0x2000>; /* SRAM2_SIZE */
+ };
+
+#include "stm32mp1-cot-descriptors.dtsi"
+#endif
+
+};
diff --git a/fdts/stm32mp13-ddr.dtsi b/fdts/stm32mp13-ddr.dtsi
new file mode 100644
index 0000000..56eb36e
--- /dev/null
+++ b/fdts/stm32mp13-ddr.dtsi
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ */
+
+&ddr {
+ st,mem-name = DDR_MEM_NAME;
+ st,mem-speed = <DDR_MEM_SPEED>;
+ st,mem-size = <DDR_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
+ >;
+
+ st,phy-reg = <
+ DDR_PGCR
+ DDR_ACIOCR
+ DDR_DXCCR
+ DDR_DSGCR
+ DDR_DCR
+ DDR_ODTCR
+ DDR_ZQ0CR1
+ DDR_DX0GCR
+ DDR_DX1GCR
+ >;
+
+ st,phy-timing = <
+ DDR_PTR0
+ DDR_PTR1
+ DDR_PTR2
+ DDR_DTPR0
+ DDR_DTPR1
+ DDR_DTPR2
+ DDR_MR0
+ DDR_MR1
+ DDR_MR2
+ DDR_MR3
+ >;
+};
+
+#undef DDR_MEM_NAME
+#undef DDR_MEM_SPEED
+#undef DDR_MEM_SIZE
+#undef DDR_MSTR
+#undef DDR_MRCTRL0
+#undef DDR_MRCTRL1
+#undef DDR_DERATEEN
+#undef DDR_DERATEINT
+#undef DDR_PWRCTL
+#undef DDR_PWRTMG
+#undef DDR_HWLPCTL
+#undef DDR_RFSHCTL0
+#undef DDR_RFSHCTL3
+#undef DDR_RFSHTMG
+#undef DDR_CRCPARCTL0
+#undef DDR_DRAMTMG0
+#undef DDR_DRAMTMG1
+#undef DDR_DRAMTMG2
+#undef DDR_DRAMTMG3
+#undef DDR_DRAMTMG4
+#undef DDR_DRAMTMG5
+#undef DDR_DRAMTMG6
+#undef DDR_DRAMTMG7
+#undef DDR_DRAMTMG8
+#undef DDR_DRAMTMG14
+#undef DDR_ZQCTL0
+#undef DDR_DFITMG0
+#undef DDR_DFITMG1
+#undef DDR_DFILPCFG0
+#undef DDR_DFIUPD0
+#undef DDR_DFIUPD1
+#undef DDR_DFIUPD2
+#undef DDR_DFIPHYMSTR
+#undef DDR_ADDRMAP1
+#undef DDR_ADDRMAP2
+#undef DDR_ADDRMAP3
+#undef DDR_ADDRMAP4
+#undef DDR_ADDRMAP5
+#undef DDR_ADDRMAP6
+#undef DDR_ADDRMAP9
+#undef DDR_ADDRMAP10
+#undef DDR_ADDRMAP11
+#undef DDR_ODTCFG
+#undef DDR_ODTMAP
+#undef DDR_SCHED
+#undef DDR_SCHED1
+#undef DDR_PERFHPR1
+#undef DDR_PERFLPR1
+#undef DDR_PERFWR1
+#undef DDR_DBG0
+#undef DDR_DBG1
+#undef DDR_DBGCMD
+#undef DDR_POISONCFG
+#undef DDR_PCCFG
+#undef DDR_PCFGR_0
+#undef DDR_PCFGW_0
+#undef DDR_PCFGQOS0_0
+#undef DDR_PCFGQOS1_0
+#undef DDR_PCFGWQOS0_0
+#undef DDR_PCFGWQOS1_0
+#undef DDR_PGCR
+#undef DDR_PTR0
+#undef DDR_PTR1
+#undef DDR_PTR2
+#undef DDR_ACIOCR
+#undef DDR_DXCCR
+#undef DDR_DSGCR
+#undef DDR_DCR
+#undef DDR_DTPR0
+#undef DDR_DTPR1
+#undef DDR_DTPR2
+#undef DDR_MR0
+#undef DDR_MR1
+#undef DDR_MR2
+#undef DDR_MR3
+#undef DDR_ODTCR
+#undef DDR_ZQ0CR1
+#undef DDR_DX0GCR
+#undef DDR_DX1GCR
diff --git a/fdts/stm32mp13-ddr3-1x4Gb-1066-binF.dtsi b/fdts/stm32mp13-ddr3-1x4Gb-1066-binF.dtsi
new file mode 100644
index 0000000..a5f7989
--- /dev/null
+++ b/fdts/stm32mp13-ddr3-1x4Gb-1066-binF.dtsi
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * STM32MP135C DISCO BOARD configuration
+ * 1x DDR3L 4Gb, 16-bit, 533MHz.
+ * Reference used MT41K256M16TW-107 P from Micron
+ *
+ * DDR type / Platform DDR3/3L
+ * freq 533MHz
+ * width 16
+ * datasheet 1
+ * DDR density 4
+ * timing mode optimized
+ * Scheduling/QoS options : type = 6
+ * address mapping : RBC
+ * Tc > + 85C : N
+ */
+#define DDR_MEM_NAME "DDR3-1066 bin F 1x4Gb 533MHz v1.53"
+#define DDR_MEM_SPEED 533000
+#define DDR_MEM_SIZE 0x20000000
+
+#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 0x000A041B
+#define DDR_DRAMTMG2 0x0607080F
+#define DDR_DRAMTMG3 0x0050400C
+#define DDR_DRAMTMG4 0x07040607
+#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 0x02050105
+#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 0x00000F01
+#define DDR_SCHED1 0x00000000
+#define DDR_PERFHPR1 0x00000001
+#define DDR_PERFLPR1 0x04000200
+#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 0x00000000
+#define DDR_PCFGW_0 0x00000000
+#define DDR_PCFGQOS0_0 0x00100009
+#define DDR_PCFGQOS1_0 0x00000020
+#define DDR_PCFGWQOS0_0 0x01100B03
+#define DDR_PCFGWQOS1_0 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 0x36D477D0
+#define DDR_DTPR1 0x098B00D8
+#define DDR_DTPR2 0x10023600
+#define DDR_MR0 0x00000830
+#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_DX1GCR 0x0000CE81
+
+#include "stm32mp13-ddr.dtsi"
diff --git a/fdts/stm32mp13-fw-config.dtsi b/fdts/stm32mp13-fw-config.dtsi
new file mode 100644
index 0000000..4f3bb72
--- /dev/null
+++ b/fdts/stm32mp13-fw-config.dtsi
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+ */
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <dt-bindings/soc/stm32mp13-tzc400.h>
+
+#include <platform_def.h>
+
+#ifndef DDR_SIZE
+#error "DDR_SIZE is not defined"
+#endif
+
+#define DDR_NS_BASE STM32MP_DDR_BASE
+#define DDR_SEC_SIZE STM32MP_DDR_S_SIZE
+#define DDR_SEC_BASE (STM32MP_DDR_BASE + (DDR_SIZE - DDR_SEC_SIZE))
+#define DDR_NS_SIZE (DDR_SEC_BASE - DDR_NS_BASE)
+
+/dts-v1/;
+
+/ {
+ dtb-registry {
+ compatible = "fconf,dyn_cfg-dtb_registry";
+
+ hw-config {
+ load-address = <0x0 STM32MP_HW_CONFIG_BASE>;
+ max-size = <STM32MP_HW_CONFIG_MAX_SIZE>;
+ id = <HW_CONFIG_ID>;
+ };
+
+ nt_fw {
+ load-address = <0x0 STM32MP_BL33_BASE>;
+ max-size = <STM32MP_BL33_MAX_SIZE>;
+ id = <BL33_IMAGE_ID>;
+ };
+
+ tos_fw {
+ load-address = <0x0 DDR_SEC_BASE>;
+ max-size = <DDR_SEC_SIZE>;
+ id = <BL32_IMAGE_ID>;
+ };
+ };
+
+ st-mem-firewall {
+ compatible = "st,mem-firewall";
+ memory-ranges = <
+ DDR_NS_BASE DDR_NS_SIZE TZC_REGION_S_NONE TZC_REGION_NSEC_ALL_ACCESS_RDWR
+ DDR_SEC_BASE DDR_SEC_SIZE TZC_REGION_S_RDWR 0>;
+ };
+};
diff --git a/fdts/stm32mp13-pinctrl.dtsi b/fdts/stm32mp13-pinctrl.dtsi
new file mode 100644
index 0000000..879da9c
--- /dev/null
+++ b/fdts/stm32mp13-pinctrl.dtsi
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@foss.st.com>
+ */
+#include <dt-bindings/pinctrl/stm32-pinfunc.h>
+
+&pinctrl {
+ i2c4_pins_a: i2c4-0 {
+ pins {
+ pinmux = <STM32_PINMUX('E', 15, AF6)>, /* I2C4_SCL */
+ <STM32_PINMUX('B', 9, AF6)>; /* I2C4_SDA */
+ bias-disable;
+ drive-open-drain;
+ slew-rate = <0>;
+ };
+ };
+
+ sdmmc1_b4_pins_a: sdmmc1-b4-0 {
+ pins {
+ pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
+ <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
+ <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
+ <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+ <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-disable;
+ };
+ };
+
+ sdmmc1_clk_pins_a: sdmmc1-clk-0 {
+ pins {
+ pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-disable;
+ };
+ };
+
+ sdmmc2_b4_pins_a: sdmmc2-b4-0 {
+ pins {
+ pinmux = <STM32_PINMUX('B', 14, AF10)>, /* SDMMC2_D0 */
+ <STM32_PINMUX('B', 15, AF10)>, /* SDMMC2_D1 */
+ <STM32_PINMUX('B', 3, AF10)>, /* SDMMC2_D2 */
+ <STM32_PINMUX('B', 4, AF10)>, /* SDMMC2_D3 */
+ <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-pull-up;
+ };
+ };
+
+ sdmmc2_clk_pins_a: sdmmc2-clk-0 {
+ pins {
+ pinmux = <STM32_PINMUX('E', 3, AF10)>; /* SDMMC2_CK */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-pull-up;
+ };
+ };
+
+ uart4_pins_a: uart4-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('D', 6, AF8)>; /* UART4_TX */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('D', 8, AF8)>; /* UART4_RX */
+ bias-disable;
+ };
+ };
+
+ usart1_pins_a: usart1-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('C', 0, AF7)>, /* USART1_TX */
+ <STM32_PINMUX('C', 2, AF7)>; /* USART1_RTS */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('B', 0, AF4)>, /* USART1_RX */
+ <STM32_PINMUX('A', 7, AF7)>; /* USART1_CTS_NSS */
+ bias-pull-up;
+ };
+ };
+
+ uart8_pins_a: uart8-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('E', 1, AF8)>; /* UART8_TX */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('F', 9, AF8)>; /* UART8_RX */
+ bias-pull-up;
+ };
+ };
+};
diff --git a/fdts/stm32mp131.dtsi b/fdts/stm32mp131.dtsi
new file mode 100644
index 0000000..543afa5
--- /dev/null
+++ b/fdts/stm32mp131.dtsi
@@ -0,0 +1,584 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@foss.st.com> for STMicroelectronics.
+ */
+#include <dt-bindings/clock/stm32mp13-clks.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/reset/stm32mp13-resets.h>
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <0>;
+ clocks = <&rcc CK_MPU>;
+ clock-names = "cpu";
+ nvmem-cells = <&part_number_otp>;
+ nvmem-cell-names = "part_number";
+ };
+ };
+
+ clocks {
+ clk_csi: clk-csi {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <4000000>;
+ };
+
+ 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>;
+ };
+ };
+
+ intc: interrupt-controller@a0021000 {
+ compatible = "arm,cortex-a7-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0xa0021000 0x1000>,
+ <0xa0022000 0x2000>;
+ };
+
+ psci {
+ compatible = "arm,psci-1.0";
+ method = "smc";
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&intc>;
+ ranges;
+
+ usart3: serial@4000f000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x4000f000 0x400>;
+ interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc USART3_K>;
+ resets = <&rcc USART3_R>;
+ status = "disabled";
+ };
+
+ uart4: serial@40010000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x40010000 0x400>;
+ interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc UART4_K>;
+ resets = <&rcc UART4_R>;
+ status = "disabled";
+ };
+
+ uart5: serial@40011000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x40011000 0x400>;
+ interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc UART5_K>;
+ resets = <&rcc UART5_R>;
+ status = "disabled";
+ };
+
+ uart7: serial@40018000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x40018000 0x400>;
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc UART7_K>;
+ resets = <&rcc UART7_R>;
+ status = "disabled";
+ };
+
+ uart8: serial@40019000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x40019000 0x400>;
+ interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc UART8_K>;
+ resets = <&rcc UART8_R>;
+ status = "disabled";
+ };
+
+ usart6: serial@44003000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x44003000 0x400>;
+ interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc USART6_K>;
+ resets = <&rcc USART6_R>;
+ status = "disabled";
+ };
+
+ usbotg_hs: usb-otg@49000000 {
+ compatible = "st,stm32mp15-hsotg", "snps,dwc2";
+ reg = <0x49000000 0x40000>;
+ clocks = <&rcc USBO_K>;
+ clock-names = "otg";
+ resets = <&rcc USBO_R>;
+ reset-names = "dwc2";
+ interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+ g-rx-fifo-size = <512>;
+ g-np-tx-fifo-size = <32>;
+ g-tx-fifo-size = <256 16 16 16 16 16 16 16>;
+ dr_mode = "otg";
+ usb33d-supply = <&usb33>;
+ status = "disabled";
+ };
+
+ usart1: serial@4c000000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x4c000000 0x400>;
+ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc USART1_K>;
+ resets = <&rcc USART1_R>;
+ status = "disabled";
+ };
+
+ usart2: serial@4c001000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x4c001000 0x400>;
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc USART2_K>;
+ resets = <&rcc USART2_R>;
+ status = "disabled";
+ };
+
+ i2c3: i2c@4c004000 {
+ compatible = "st,stm32mp13-i2c";
+ reg = <0x4c004000 0x400>;
+ interrupt-names = "event", "error";
+ interrupts-extended = <&exti 23 IRQ_TYPE_LEVEL_HIGH>,
+ <&intc GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc I2C3_K>;
+ resets = <&rcc I2C3_R>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ st,syscfg-fmp = <&syscfg 0x4 0x4>;
+ i2c-analog-filter;
+ status = "disabled";
+ };
+
+ i2c4: i2c@4c005000 {
+ compatible = "st,stm32mp13-i2c";
+ reg = <0x4c005000 0x400>;
+ interrupt-names = "event", "error";
+ interrupts-extended = <&exti 24 IRQ_TYPE_LEVEL_HIGH>,
+ <&intc GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc I2C4_K>;
+ resets = <&rcc I2C4_R>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ st,syscfg-fmp = <&syscfg 0x4 0x8>;
+ i2c-analog-filter;
+ status = "disabled";
+ };
+
+ i2c5: i2c@4c006000 {
+ compatible = "st,stm32mp13-i2c";
+ reg = <0x4c006000 0x400>;
+ interrupt-names = "event", "error";
+ interrupts-extended = <&exti 25 IRQ_TYPE_LEVEL_HIGH>,
+ <&intc GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc I2C5_K>;
+ resets = <&rcc I2C5_R>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ st,syscfg-fmp = <&syscfg 0x4 0x10>;
+ i2c-analog-filter;
+ status = "disabled";
+ };
+
+ rcc: rcc@50000000 {
+ compatible = "st,stm32mp13-rcc", "syscon";
+ reg = <0x50000000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ secure-interrupts = <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
+ secure-interrupt-names = "wakeup";
+ };
+
+ pwr_regulators: pwr@50001000 {
+ compatible = "st,stm32mp1,pwr-reg";
+ reg = <0x50001000 0x10>;
+
+ reg11: reg11 {
+ regulator-name = "reg11";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ reg18: reg18 {
+ regulator-name = "reg18";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ usb33: usb33 {
+ regulator-name = "usb33";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+ };
+
+ exti: interrupt-controller@5000d000 {
+ compatible = "st,stm32mp13-exti", "syscon";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x5000d000 0x400>;
+ };
+
+ syscfg: syscon@50020000 {
+ compatible = "st,stm32mp157-syscfg", "syscon";
+ reg = <0x50020000 0x400>;
+ clocks = <&rcc SYSCFG>;
+ };
+
+ hash: hash@54003000 {
+ compatible = "st,stm32mp13-hash";
+ reg = <0x54003000 0x400>;
+ clocks = <&rcc HASH1>;
+ resets = <&rcc HASH1_R>;
+ status = "disabled";
+ };
+
+ rng: rng@54004000 {
+ compatible = "st,stm32mp13-rng";
+ reg = <0x54004000 0x400>;
+ clocks = <&rcc RNG1_K>;
+ resets = <&rcc RNG1_R>;
+ status = "disabled";
+ };
+
+ fmc: memory-controller@58002000 {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ compatible = "st,stm32mp1-fmc2-ebi";
+ reg = <0x58002000 0x1000>;
+ clocks = <&rcc FMC_K>;
+ resets = <&rcc FMC_R>;
+ status = "disabled";
+
+ ranges = <0 0 0x60000000 0x04000000>, /* EBI CS 1 */
+ <1 0 0x64000000 0x04000000>, /* EBI CS 2 */
+ <2 0 0x68000000 0x04000000>, /* EBI CS 3 */
+ <3 0 0x6c000000 0x04000000>, /* EBI CS 4 */
+ <4 0 0x80000000 0x10000000>; /* NAND */
+
+ nand-controller@4,0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "st,stm32mp1-fmc2-nfc";
+ reg = <4 0x00000000 0x1000>,
+ <4 0x08010000 0x1000>,
+ <4 0x08020000 0x1000>,
+ <4 0x01000000 0x1000>,
+ <4 0x09010000 0x1000>,
+ <4 0x09020000 0x1000>;
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+ };
+
+ qspi: spi@58003000 {
+ compatible = "st,stm32f469-qspi";
+ reg = <0x58003000 0x1000>, <0x70000000 0x10000000>;
+ reg-names = "qspi", "qspi_mm";
+ interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc QSPI_K>;
+ resets = <&rcc QSPI_R>;
+ status = "disabled";
+ };
+
+ sdmmc1: mmc@58005000 {
+ compatible = "st,stm32-sdmmc2", "arm,pl18x", "arm,primecell";
+ arm,primecell-periphid = <0x20253180>;
+ 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 = <130000000>;
+ status = "disabled";
+ };
+
+ sdmmc2: mmc@58007000 {
+ compatible = "st,stm32-sdmmc2", "arm,pl18x", "arm,primecell";
+ arm,primecell-periphid = <0x20253180>;
+ 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 = <130000000>;
+ status = "disabled";
+ };
+
+ usbh_ohci: usbh-ohci@5800c000 {
+ compatible = "generic-ohci";
+ reg = <0x5800c000 0x1000>;
+ clocks = <&rcc USBH>;
+ resets = <&rcc USBH_R>;
+ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ usbh_ehci: usbh-ehci@5800d000 {
+ compatible = "generic-ehci";
+ reg = <0x5800d000 0x1000>;
+ clocks = <&rcc USBH>;
+ resets = <&rcc USBH_R>;
+ interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+ companion = <&usbh_ohci>;
+ status = "disabled";
+ };
+
+ iwdg2: watchdog@5a002000 {
+ compatible = "st,stm32mp1-iwdg";
+ reg = <0x5a002000 0x400>;
+ clocks = <&rcc IWDG2>, <&rcc CK_LSI>;
+ clock-names = "pclk", "lsi";
+ status = "disabled";
+ };
+
+ ddr: ddr@5a003000 {
+ compatible = "st,stm32mp13-ddr";
+ reg = <0x5a003000 0x550>, <0x5a004000 0x234>;
+ clocks = <&rcc AXIDCG>,
+ <&rcc DDRC1>,
+ <&rcc DDRPHYC>,
+ <&rcc DDRCAPB>,
+ <&rcc DDRPHYCAPB>;
+ clock-names = "axidcg",
+ "ddrc1",
+ "ddrphyc",
+ "ddrcapb",
+ "ddrphycapb";
+ };
+
+ usbphyc: usbphyc@5a006000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #clock-cells = <0>;
+ compatible = "st,stm32mp1-usbphyc";
+ reg = <0x5a006000 0x1000>;
+ clocks = <&rcc USBPHY_K>;
+ resets = <&rcc USBPHY_R>;
+ vdda1v1-supply = <&reg11>;
+ vdda1v8-supply = <&reg18>;
+ status = "disabled";
+
+ usbphyc_port0: usb-phy@0 {
+ #phy-cells = <0>;
+ reg = <0>;
+ };
+
+ usbphyc_port1: usb-phy@1 {
+ #phy-cells = <1>;
+ reg = <1>;
+ };
+ };
+
+ iwdg1: watchdog@5c003000 {
+ compatible = "st,stm32mp1-iwdg";
+ reg = <0x5c003000 0x400>;
+ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc IWDG1>, <&rcc CK_LSI>;
+ clock-names = "pclk", "lsi";
+ status = "disabled";
+ };
+
+ bsec: efuse@5c005000 {
+ compatible = "st,stm32mp15-bsec";
+ reg = <0x5c005000 0x400>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cfg0_otp: cfg0_otp@0 {
+ reg = <0x0 0x2>;
+ };
+ part_number_otp: part_number_otp@4 {
+ reg = <0x4 0x2>;
+ };
+ monotonic_otp: monotonic_otp@10 {
+ reg = <0x10 0x4>;
+ };
+ nand_otp: cfg9_otp@24 {
+ reg = <0x24 0x4>;
+ };
+ nand2_otp: cfg10_otp@28 {
+ reg = <0x28 0x4>;
+ };
+ uid_otp: uid_otp@34 {
+ reg = <0x34 0xc>;
+ };
+ hw2_otp: hw2_otp@48 {
+ reg = <0x48 0x4>;
+ };
+ ts_cal1: calib@5c {
+ reg = <0x5c 0x2>;
+ };
+ ts_cal2: calib@5e {
+ reg = <0x5e 0x2>;
+ };
+ pkh_otp: pkh_otp@60 {
+ reg = <0x60 0x20>;
+ };
+ mac_addr: mac_addr@e4 {
+ reg = <0xe4 0xc>;
+ st,non-secure-otp;
+ };
+ enckey_otp: enckey_otp@170 {
+ reg = <0x170 0x10>;
+ };
+ };
+ /*
+ * Break node order to solve dependency probe issue between
+ * pinctrl and exti.
+ */
+ pinctrl: pinctrl@50002000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stm32mp135-pinctrl";
+ ranges = <0 0x50002000 0x8400>;
+ interrupt-parent = <&exti>;
+ st,syscfg = <&exti 0x60 0xff>;
+ pins-are-numbered;
+
+ gpioa: gpio@50002000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x0 0x400>;
+ clocks = <&rcc GPIOA>;
+ st,bank-name = "GPIOA";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 0 16>;
+ };
+
+ gpiob: gpio@50003000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x1000 0x400>;
+ clocks = <&rcc GPIOB>;
+ st,bank-name = "GPIOB";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 16 16>;
+ };
+
+ gpioc: gpio@50004000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x2000 0x400>;
+ clocks = <&rcc GPIOC>;
+ st,bank-name = "GPIOC";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 32 16>;
+ };
+
+ gpiod: gpio@50005000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x3000 0x400>;
+ clocks = <&rcc GPIOD>;
+ st,bank-name = "GPIOD";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 48 16>;
+ };
+
+ gpioe: gpio@50006000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x4000 0x400>;
+ clocks = <&rcc GPIOE>;
+ st,bank-name = "GPIOE";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 64 16>;
+ };
+
+ gpiof: gpio@50007000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x5000 0x400>;
+ clocks = <&rcc GPIOF>;
+ st,bank-name = "GPIOF";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 80 16>;
+ };
+
+ gpiog: gpio@50008000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x6000 0x400>;
+ clocks = <&rcc GPIOG>;
+ st,bank-name = "GPIOG";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 96 16>;
+ };
+
+ gpioh: gpio@50009000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x7000 0x400>;
+ clocks = <&rcc GPIOH>;
+ st,bank-name = "GPIOH";
+ ngpios = <15>;
+ gpio-ranges = <&pinctrl 0 112 15>;
+ };
+
+ gpioi: gpio@5000a000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x8000 0x400>;
+ clocks = <&rcc GPIOI>;
+ st,bank-name = "GPIOI";
+ ngpios = <8>;
+ gpio-ranges = <&pinctrl 0 128 8>;
+ };
+ };
+ };
+};
diff --git a/fdts/stm32mp133.dtsi b/fdts/stm32mp133.dtsi
new file mode 100644
index 0000000..bb468c0
--- /dev/null
+++ b/fdts/stm32mp133.dtsi
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@foss.st.com> for STMicroelectronics.
+ */
+
+#include "stm32mp131.dtsi"
diff --git a/fdts/stm32mp135.dtsi b/fdts/stm32mp135.dtsi
new file mode 100644
index 0000000..b5ebdd9
--- /dev/null
+++ b/fdts/stm32mp135.dtsi
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@foss.st.com> for STMicroelectronics.
+ */
+
+#include "stm32mp133.dtsi"
diff --git a/fdts/stm32mp135f-dk-fw-config.dts b/fdts/stm32mp135f-dk-fw-config.dts
new file mode 100644
index 0000000..21f8242
--- /dev/null
+++ b/fdts/stm32mp135f-dk-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE 0x20000000 /* 512MB */
+#include "stm32mp13-fw-config.dtsi"
diff --git a/fdts/stm32mp135f-dk.dts b/fdts/stm32mp135f-dk.dts
new file mode 100644
index 0000000..0f06b67
--- /dev/null
+++ b/fdts/stm32mp135f-dk.dts
@@ -0,0 +1,331 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@foss.st.com> for STMicroelectronics.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/clock/stm32mp13-clksrc.h>
+#include "stm32mp135.dtsi"
+#include "stm32mp13xf.dtsi"
+#include "stm32mp13-ddr3-1x4Gb-1066-binF.dtsi"
+#include "stm32mp13-pinctrl.dtsi"
+
+/ {
+ model = "STMicroelectronics STM32MP135F-DK Discovery Board";
+ compatible = "st,stm32mp135f-dk", "st,stm32mp135";
+
+ aliases {
+ serial0 = &uart4;
+ serial1 = &usart1;
+ serial2 = &uart8;
+ serial3 = &usart2;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory@c0000000 {
+ device_type = "memory";
+ reg = <0xc0000000 0x20000000>;
+ };
+
+ vin: vin {
+ compatible = "regulator-fixed";
+ regulator-name = "vin";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
+
+ v3v3_ao: v3v3_ao {
+ compatible = "regulator-fixed";
+ regulator-name = "v3v3_ao";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+};
+
+&bsec {
+ board_id: board_id@f0 {
+ reg = <0xf0 0x4>;
+ st,non-secure-otp;
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&vddcpu>;
+};
+
+&hash {
+ status = "okay";
+};
+
+&i2c4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c4_pins_a>;
+ i2c-scl-rising-time-ns = <185>;
+ i2c-scl-falling-time-ns = <20>;
+ clock-frequency = <400000>;
+ status = "disabled";
+ secure-status = "okay";
+
+ pmic: stpmic@33 {
+ compatible = "st,stpmic1";
+ reg = <0x33>;
+
+ status = "disabled";
+ secure-status = "okay";
+
+ regulators {
+ compatible = "st,stpmic1-regulators";
+ buck1-supply = <&vin>;
+ buck2-supply = <&vin>;
+ buck3-supply = <&vin>;
+ buck4-supply = <&vin>;
+ ldo1-supply = <&vin>;
+ ldo4-supply = <&vin>;
+ ldo5-supply = <&vin>;
+ ldo6-supply = <&vin>;
+ vref_ddr-supply = <&vin>;
+ pwr_sw1-supply = <&bst_out>;
+ pwr_sw2-supply = <&v3v3_ao>;
+
+ vddcpu: buck1 {
+ regulator-name = "vddcpu";
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-always-on;
+ regulator-over-current-protection;
+ };
+
+ vdd_ddr: buck2 {
+ regulator-name = "vdd_ddr";
+ regulator-min-microvolt = <1350000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-over-current-protection;
+ };
+
+ vdd: buck3 {
+ regulator-name = "vdd";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ st,mask-reset;
+ regulator-over-current-protection;
+ };
+
+ vddcore: buck4 {
+ regulator-name = "vddcore";
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-always-on;
+ regulator-over-current-protection;
+ };
+
+ vdd_adc: ldo1 {
+ regulator-name = "vdd_adc";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ 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 = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+
+ v1v8_periph: ldo6 {
+ regulator-name = "v1v8_periph";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vref_ddr: vref_ddr {
+ regulator-name = "vref_ddr";
+ regulator-always-on;
+ };
+
+ bst_out: boost {
+ regulator-name = "bst_out";
+ };
+
+ v3v3_sw: pwr_sw2 {
+ regulator-name = "v3v3_sw";
+ regulator-active-discharge = <1>;
+ regulator-always-on;
+ };
+ };
+ };
+};
+
+&iwdg2 {
+ timeout-sec = <32>;
+ status = "okay";
+};
+
+&pka {
+ status = "okay";
+};
+
+&pwr_regulators {
+ vdd-supply = <&vdd>;
+ vdd_3v3_usbfs-supply = <&vdd_usb>;
+};
+
+&rcc {
+ st,clksrc = <
+ CLK_MPU_PLL1P
+ CLK_AXI_PLL2P
+ CLK_MLAHBS_PLL3
+ CLK_CKPER_HSE
+ CLK_RTC_LSE
+ CLK_SDMMC1_PLL4P
+ CLK_SDMMC2_PLL4P
+ CLK_STGEN_HSE
+ CLK_USBPHY_HSE
+ CLK_I2C4_HSI
+ CLK_USBO_USBPHY
+ CLK_I2C12_HSI
+ CLK_UART2_HSI
+ CLK_UART4_HSI
+ CLK_SAES_AXI
+ >;
+
+ st,clkdiv = <
+ DIV(DIV_AXI, 0)
+ DIV(DIV_MLAHB, 0)
+ DIV(DIV_APB1, 1)
+ DIV(DIV_APB2, 1)
+ DIV(DIV_APB3, 1)
+ DIV(DIV_APB4, 1)
+ DIV(DIV_APB5, 2)
+ DIV(DIV_APB6, 1)
+ DIV(DIV_RTC, 0)
+ >;
+
+ st,pll_vco {
+ pll1_vco_1300Mhz: pll1-vco-1300Mhz {
+ src = < CLK_PLL12_HSE >;
+ divmn = < 2 80 >;
+ frac = < 0x800 >;
+ };
+
+ pll2_vco_1066Mhz: pll2-vco-1066Mhz {
+ src = < CLK_PLL12_HSE >;
+ divmn = < 2 65 >;
+ frac = < 0x1400 >;
+ };
+
+ pll3_vco_417_8Mhz: pll3-vco-417_8Mhz {
+ src = < CLK_PLL3_HSE >;
+ divmn = < 1 33 >;
+ frac = < 0x1a04 >;
+ };
+
+ pll4_vco_600Mhz: pll4-vco-600Mhz {
+ src = < CLK_PLL4_HSE >;
+ divmn = < 1 49 >;
+ };
+ };
+
+ /* VCO = 1300.0 MHz => P = 650 (CPU) */
+ pll1:st,pll@0 {
+ compatible = "st,stm32mp1-pll";
+ reg = <0>;
+
+ st,pll = < &pll1_cfg1 >;
+
+ pll1_cfg1: pll1_cfg1 {
+ st,pll_vco = < &pll1_vco_1300Mhz >;
+ st,pll_div_pqr = < 0 1 1 >;
+ };
+ };
+
+ /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 266, R = 533 (DDR) */
+ pll2:st,pll@1 {
+ compatible = "st,stm32mp1-pll";
+ reg = <1>;
+
+ st,pll = < &pll2_cfg1 >;
+
+ pll2_cfg1: pll2_cfg1 {
+ st,pll_vco = < &pll2_vco_1066Mhz >;
+ st,pll_div_pqr = < 1 1 0 >;
+ };
+ };
+
+ /* VCO = 417.8 MHz => P = 209, Q = 24, R = 209 */
+ pll3:st,pll@2 {
+ compatible = "st,stm32mp1-pll";
+ reg = <2>;
+
+ st,pll = < &pll3_cfg1 >;
+
+ pll3_cfg1: pll3_cfg1 {
+ st,pll_vco = < &pll3_vco_417_8Mhz >;
+ st,pll_div_pqr = < 1 16 1 >;
+ };
+ };
+
+ /* VCO = 600.0 MHz => P = 50, Q = 10, R = 100 */
+ pll4:st,pll@3 {
+ compatible = "st,stm32mp1-pll";
+ reg = <3>;
+
+ st,pll = < &pll4_cfg1 >;
+
+ pll4_cfg1: pll4_cfg1 {
+ st,pll_vco = < &pll4_vco_600Mhz >;
+ st,pll_div_pqr = < 11 59 5 >;
+ };
+ };
+};
+
+&rng {
+ status = "okay";
+};
+
+&saes {
+ status = "okay";
+};
+
+&sdmmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_clk_pins_a>;
+ disable-wp;
+ st,neg-edge;
+ bus-width = <4>;
+ vmmc-supply = <&vdd_sd>;
+ status = "okay";
+};
+
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4_pins_a>;
+ status = "okay";
+};
+
+&uart8 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart8_pins_a>;
+ status = "disabled";
+};
+
+&usart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usart1_pins_a>;
+ uart-has-rtscts;
+ status = "disabled";
+};
diff --git a/fdts/stm32mp13xa.dtsi b/fdts/stm32mp13xa.dtsi
new file mode 100644
index 0000000..0ef2fce
--- /dev/null
+++ b/fdts/stm32mp13xa.dtsi
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@foss.st.com> for STMicroelectronics.
+ */
diff --git a/fdts/stm32mp13xc.dtsi b/fdts/stm32mp13xc.dtsi
new file mode 100644
index 0000000..4b30c5c
--- /dev/null
+++ b/fdts/stm32mp13xc.dtsi
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@foss.st.com> for STMicroelectronics.
+ */
+
+#include "stm32mp13xa.dtsi"
+
+/ {
+ soc {
+ saes: saes@54005000 {
+ compatible = "st,stm32-saes";
+ reg = <0x54005000 0x400>;
+ clocks = <&rcc SAES_K>;
+ resets = <&rcc SAES_R>;
+ status = "disabled";
+ };
+
+ pka: pka@54006000 {
+ compatible = "st,stm32-pka64";
+ reg = <0x54006000 0x2000>;
+ clocks = <&rcc PKA>;
+ resets = <&rcc PKA_R>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/fdts/stm32mp13xd.dtsi b/fdts/stm32mp13xd.dtsi
new file mode 100644
index 0000000..0ef2fce
--- /dev/null
+++ b/fdts/stm32mp13xd.dtsi
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@foss.st.com> for STMicroelectronics.
+ */
diff --git a/fdts/stm32mp13xf.dtsi b/fdts/stm32mp13xf.dtsi
new file mode 100644
index 0000000..887c4e0
--- /dev/null
+++ b/fdts/stm32mp13xf.dtsi
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@foss.st.com> for STMicroelectronics.
+ */
+#include "stm32mp13xd.dtsi"
+
+/ {
+ soc {
+ saes: saes@54005000 {
+ compatible = "st,stm32-saes";
+ reg = <0x54005000 0x400>;
+ clocks = <&rcc SAES_K>;
+ resets = <&rcc SAES_R>;
+ status = "disabled";
+ };
+
+ pka: pka@54006000 {
+ compatible = "st,stm32-pka64";
+ reg = <0x54006000 0x2000>;
+ clocks = <&rcc PKA>;
+ resets = <&rcc PKA_R>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/fdts/stm32mp15-bl2.dtsi b/fdts/stm32mp15-bl2.dtsi
new file mode 100644
index 0000000..5489a62
--- /dev/null
+++ b/fdts/stm32mp15-bl2.dtsi
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2020-2022 - All Rights Reserved
+ */
+
+/ {
+#if !STM32MP_EMMC && !STM32MP_SDMMC
+ aliases {
+ /delete-property/ mmc0;
+ /delete-property/ mmc1;
+ };
+#endif
+
+ cpus {
+ /delete-node/ cpu@1;
+ };
+
+ /delete-node/ psci;
+
+ soc {
+ /delete-node/ timer@40006000;
+ /delete-node/ timer@44006000;
+#if !STM32MP_USB_PROGRAMMER
+ /delete-node/ usb-otg@49000000;
+#endif
+ /delete-node/ pwr_mcu@50001014;
+ /delete-node/ cryp@54001000;
+ /delete-node/ rng@54003000;
+#if !STM32MP_RAW_NAND
+ /delete-node/ memory-controller@58002000;
+#endif
+#if !STM32MP_SPI_NAND && !STM32MP_SPI_NOR
+ /delete-node/ spi@58003000;
+#endif
+#if !STM32MP_EMMC && !STM32MP_SDMMC
+ /delete-node/ mmc@58005000;
+ /delete-node/ mmc@58007000;
+#endif
+#if !STM32MP_USB_PROGRAMMER
+ /delete-node/ usbphyc@5a006000;
+#endif
+ /delete-node/ spi@5c001000;
+ /delete-node/ rtc@5c004000;
+ /delete-node/ etzpc@5c007000;
+ /delete-node/ stgen@5c008000;
+ /delete-node/ i2c@5c009000;
+ /delete-node/ tamp@5c00a000;
+
+ pinctrl@50002000 {
+#if !STM32MP_RAW_NAND
+ /delete-node/ fmc-0;
+#endif
+#if !STM32MP_SPI_NAND && !STM32MP_SPI_NOR
+ /delete-node/ qspi-clk-0;
+ /delete-node/ qspi-bk1-0;
+ /delete-node/ qspi-bk2-0;
+#endif
+#if !STM32MP_EMMC && !STM32MP_SDMMC
+ /delete-node/ sdmmc1-b4-0;
+ /delete-node/ sdmmc1-dir-0;
+ /delete-node/ sdmmc2-b4-0;
+ /delete-node/ sdmmc2-b4-1;
+ /delete-node/ sdmmc2-d47-0;
+#endif
+#if !STM32MP_USB_PROGRAMMER
+ /delete-node/ usbotg_hs-0;
+ /delete-node/ usbotg-fs-dp-dm-0;
+#endif
+ };
+ };
+
+ /*
+ * UUID's here are UUID RFC 4122 compliant meaning fieds are stored in
+ * network order (big endian)
+ */
+
+ st-io_policies {
+ fip-handles {
+ compatible = "st,io-fip-handle";
+ fw_cfg_uuid = "5807e16a-8459-47be-8ed5-648e8dddab0e";
+ bl32_uuid = "05d0e189-53dc-1347-8d2b-500a4b7a3e38";
+ bl32_extra1_uuid = "0b70c29b-2a5a-7840-9f65-0a5682738288";
+ bl32_extra2_uuid = "8ea87bb1-cfa2-3f4d-85fd-e7bba50220d9";
+ bl33_uuid = "d6d0eea7-fcea-d54b-9782-9934f234b6e4";
+ hw_cfg_uuid = "08b8f1d9-c9cf-9349-a962-6fbc6b7265cc";
+ tos_fw_cfg_uuid = "26257c1a-dbc6-7f47-8d96-c4c4b0248021";
+#if TRUSTED_BOARD_BOOT
+ stm32mp_cfg_cert_uuid = "501d8dd2-8bce-49a5-84eb-559a9f2eaeaf";
+ t_key_cert_uuid = "827ee890-f860-e411-a1b4-777a21b4f94c";
+ tos_fw_key_cert_uuid = "9477d603-fb60-e411-85dd-b7105b8cee04";
+ nt_fw_key_cert_uuid = "8ad5832a-fb60-e411-8aaf-df30bbc49859";
+ tos_fw_content_cert_uuid = "a49f4411-5e63-e411-8728-3f05722af33d";
+ nt_fw_content_cert_uuid = "8ec4c1f3-5d63-e411-a7a9-87ee40b23fa7";
+#endif
+ };
+ };
+
+#if TRUSTED_BOARD_BOOT
+ tb_fw-config {
+ compatible = "arm,tb_fw";
+
+ /* Disable authentication for development */
+ disable_auth = <0x0>;
+
+ /*
+ * The following two entries are placeholders for Mbed TLS
+ * heap information.
+ */
+ mbedtls_heap_addr = <0x0 0x0>;
+ mbedtls_heap_size = <0x0>;
+ };
+
+#include "stm32mp1-cot-descriptors.dtsi"
+#endif
+};
diff --git a/fdts/stm32mp15-bl32.dtsi b/fdts/stm32mp15-bl32.dtsi
new file mode 100644
index 0000000..31b24f6
--- /dev/null
+++ b/fdts/stm32mp15-bl32.dtsi
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2020-2021 - All Rights Reserved
+ */
+
+/ {
+ aliases {
+ /delete-property/ mmc0;
+ /delete-property/ mmc1;
+ };
+
+ cpus {
+ /delete-node/ cpu@1;
+ };
+
+ /delete-node/ psci;
+
+ soc {
+ /delete-node/ usb-otg@49000000;
+ /delete-node/ hash@54002000;
+ /delete-node/ memory-controller@58002000;
+ /delete-node/ spi@58003000;
+ /delete-node/ mmc@58005000;
+ /delete-node/ mmc@58007000;
+ /delete-node/ usbphyc@5a006000;
+ /delete-node/ spi@5c001000;
+ /delete-node/ stgen@5c008000;
+ /delete-node/ i2c@5c009000;
+
+ pinctrl@50002000 {
+ /delete-node/ fmc-0;
+ /delete-node/ qspi-clk-0;
+ /delete-node/ qspi-bk1-0;
+ /delete-node/ qspi-bk2-0;
+ /delete-node/ sdmmc1-b4-0;
+ /delete-node/ sdmmc1-dir-0;
+ /delete-node/ sdmmc2-b4-0;
+ /delete-node/ sdmmc2-b4-1;
+ /delete-node/ sdmmc2-d47-0;
+ /delete-node/ sdmmc2-d47-1;
+ /delete-node/ sdmmc2-d47-3;
+ /delete-node/ usbotg_hs-0;
+ /delete-node/ usbotg-fs-dp-dm-0;
+ };
+ };
+};
diff --git a/fdts/stm32mp15-ddr.dtsi b/fdts/stm32mp15-ddr.dtsi
new file mode 100644
index 0000000..d0b3a17
--- /dev/null
+++ b/fdts/stm32mp15-ddr.dtsi
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2018-2022, STMicroelectronics - All Rights Reserved
+ */
+
+&ddr {
+ st,mem-name = DDR_MEM_NAME;
+ st,mem-speed = <DDR_MEM_SPEED>;
+ st,mem-size = <DDR_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
+ >;
+};
diff --git a/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi
new file mode 100644
index 0000000..5d1001d
--- /dev/null
+++ b/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (c) 2018-2022, STMicroelectronics - All Rights Reserved
+ */
+
+/*
+ * File generated by STMicroelectronics STM32CubeMX DDR Tool for MPUs
+ * DDR type: DDR3 / DDR3L
+ * DDR width: 16bits
+ * DDR density: 4Gb
+ * System frequency: 533000Khz
+ * Relaxed Timing Mode: false
+ * Address mapping type: RBC
+ *
+ * Save Date: 2020.02.20, save Time: 18:45:20
+ */
+
+#define DDR_MEM_NAME "DDR3-DDR3L 16bits 533000kHz"
+#define DDR_MEM_SPEED 533000
+#define DDR_MEM_SIZE 0x20000000
+
+#define DDR_MSTR 0x00041401
+#define DDR_MRCTRL0 0x00000010
+#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_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_ADDRMAP1 0x00070707
+#define DDR_ADDRMAP2 0x00000000
+#define DDR_ADDRMAP3 0x1F000000
+#define DDR_ADDRMAP4 0x00001F1F
+#define DDR_ADDRMAP5 0x06060606
+#define DDR_ADDRMAP6 0x0F060606
+#define DDR_ADDRMAP9 0x00000000
+#define DDR_ADDRMAP10 0x00000000
+#define DDR_ADDRMAP11 0x00000000
+#define DDR_PGCR 0x01442E02
+#define DDR_PTR0 0x0022AA5B
+#define DDR_PTR1 0x04841104
+#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_DX1GCR 0x0000CE81
+#define DDR_DX2GCR 0x0000CE80
+#define DDR_DX3GCR 0x0000CE80
+
+#include "stm32mp15-ddr.dtsi"
diff --git a/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi
new file mode 100644
index 0000000..6494ceb
--- /dev/null
+++ b/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (c) 2018-2022, STMicroelectronics - All Rights Reserved
+ */
+
+/*
+ * File generated by STMicroelectronics STM32CubeMX DDR Tool for MPUs
+ * DDR type: DDR3 / DDR3L
+ * DDR width: 32bits
+ * DDR density: 8Gb
+ * System frequency: 533000Khz
+ * Relaxed Timing Mode: false
+ * Address mapping type: RBC
+ *
+ * Save Date: 2020.02.20, save Time: 18:49:33
+ */
+
+#define DDR_MEM_NAME "DDR3-DDR3L 32bits 533000kHz"
+#define DDR_MEM_SPEED 533000
+#define DDR_MEM_SIZE 0x40000000
+
+#define DDR_MSTR 0x00040401
+#define DDR_MRCTRL0 0x00000010
+#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_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_ADDRMAP1 0x00080808
+#define DDR_ADDRMAP2 0x00000000
+#define DDR_ADDRMAP3 0x00000000
+#define DDR_ADDRMAP4 0x00001F1F
+#define DDR_ADDRMAP5 0x07070707
+#define DDR_ADDRMAP6 0x0F070707
+#define DDR_ADDRMAP9 0x00000000
+#define DDR_ADDRMAP10 0x00000000
+#define DDR_ADDRMAP11 0x00000000
+#define DDR_PGCR 0x01442E02
+#define DDR_PTR0 0x0022AA5B
+#define DDR_PTR1 0x04841104
+#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_DX1GCR 0x0000CE81
+#define DDR_DX2GCR 0x0000CE81
+#define DDR_DX3GCR 0x0000CE81
+
+#include "stm32mp15-ddr.dtsi"
diff --git a/fdts/stm32mp15-ddr3-dhsom-2x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-dhsom-2x4Gb-1066-binG.dtsi
new file mode 100644
index 0000000..ff184c2
--- /dev/null
+++ b/fdts/stm32mp15-ddr3-dhsom-2x4Gb-1066-binG.dtsi
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause
+/*
+ * Copyright (C) 2020, DH electronics - All Rights Reserved
+ *
+ * STM32MP15xx DHSOM configuration
+ * 2x DDR3L 4Gb each, 16-bit, 533MHz, Single Die Package in flyby topology.
+ * Reference used W634GU6NB15I from Winbond
+ *
+ * DDR type / Platform DDR3/3L
+ * freq 533MHz
+ * width 32
+ * datasheet 0 = W634GU6NB15I / DDR3-1333
+ * DDR density 8
+ * timing mode optimized
+ * address mapping : RBC
+ * Tc > + 85C : J
+ */
+
+#define DDR_MEM_NAME "DDR3L 32bits 2x4Gb 533MHz"
+#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 0x0040008B
+#define DDR_CRCPARCTL0 0x00000000
+#define DDR_DRAMTMG0 0x121B1214
+#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_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_ADDRMAP1 0x00080808
+#define DDR_ADDRMAP2 0x00000000
+#define DDR_ADDRMAP3 0x00000000
+#define DDR_ADDRMAP4 0x00001F1F
+#define DDR_ADDRMAP5 0x07070707
+#define DDR_ADDRMAP6 0x0F070707
+#define DDR_ADDRMAP9 0x00000000
+#define DDR_ADDRMAP10 0x00000000
+#define DDR_ADDRMAP11 0x00000000
+#define DDR_PGCR 0x01442E02
+#define DDR_PTR0 0x0022AA5B
+#define DDR_PTR1 0x04841104
+#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 0x00000248
+#define DDR_MR3 0x00000000
+#define DDR_ODTCR 0x00010000
+#define DDR_ZQ0CR1 0x00000038
+#define DDR_DX0GCR 0x0000CE81
+#define DDR_DX1GCR 0x0000CE81
+#define DDR_DX2GCR 0x0000CE81
+#define DDR_DX3GCR 0x0000CE81
+
+#include "stm32mp15-ddr.dtsi"
diff --git a/fdts/stm32mp15-fw-config.dtsi b/fdts/stm32mp15-fw-config.dtsi
new file mode 100644
index 0000000..d583672
--- /dev/null
+++ b/fdts/stm32mp15-fw-config.dtsi
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
+ */
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <dt-bindings/soc/stm32mp15-tzc400.h>
+
+#include <platform_def.h>
+
+#ifndef DDR_SIZE
+#error "DDR_SIZE is not defined"
+#endif
+
+#define DDR_NS_BASE STM32MP_DDR_BASE
+#ifdef AARCH32_SP_OPTEE
+/* OP-TEE reserved shared memory: located at DDR top or null size */
+#define DDR_SHARE_SIZE STM32MP_DDR_SHMEM_SIZE
+#define DDR_SHARE_BASE (STM32MP_DDR_BASE + (DDR_SIZE - DDR_SHARE_SIZE))
+/* OP-TEE secure memory: located right below OP-TEE reserved shared memory */
+#define DDR_SEC_SIZE STM32MP_DDR_S_SIZE
+#define DDR_SEC_BASE (DDR_SHARE_BASE - DDR_SEC_SIZE)
+#define DDR_NS_SIZE (DDR_SEC_BASE - DDR_NS_BASE)
+#else /* !AARCH32_SP_OPTEE */
+#define DDR_NS_SIZE DDR_SIZE
+#endif /* AARCH32_SP_OPTEE */
+
+/dts-v1/;
+
+/ {
+ dtb-registry {
+ compatible = "fconf,dyn_cfg-dtb_registry";
+
+ hw-config {
+ load-address = <0x0 STM32MP_HW_CONFIG_BASE>;
+ max-size = <STM32MP_HW_CONFIG_MAX_SIZE>;
+ id = <HW_CONFIG_ID>;
+ };
+
+ nt_fw {
+ load-address = <0x0 STM32MP_BL33_BASE>;
+ max-size = <STM32MP_BL33_MAX_SIZE>;
+ id = <BL33_IMAGE_ID>;
+ };
+
+#ifdef AARCH32_SP_OPTEE
+ tos_fw {
+ load-address = <0x0 STM32MP_OPTEE_BASE>;
+ max-size = <STM32MP_OPTEE_SIZE>;
+ id = <BL32_IMAGE_ID>;
+ };
+#else
+ tos_fw {
+ load-address = <0x0 STM32MP_BL32_BASE>;
+ max-size = <STM32MP_BL32_SIZE>;
+ id = <BL32_IMAGE_ID>;
+ };
+
+ tos_fw-config {
+ load-address = <0x0 STM32MP_BL32_DTB_BASE>;
+ max-size = <STM32MP_BL32_DTB_SIZE>;
+ id = <TOS_FW_CONFIG_ID>;
+ };
+#endif
+ };
+
+ st-mem-firewall {
+ compatible = "st,mem-firewall";
+#ifdef AARCH32_SP_OPTEE
+ memory-ranges = <
+ DDR_NS_BASE DDR_NS_SIZE TZC_REGION_S_NONE TZC_REGION_NSEC_ALL_ACCESS_RDWR
+ DDR_SEC_BASE DDR_SEC_SIZE TZC_REGION_S_RDWR 0
+#if STM32MP15_OPTEE_RSV_SHM
+ DDR_SHARE_BASE DDR_SHARE_SIZE TZC_REGION_S_NONE
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_A7_ID)
+#endif
+ >;
+#else
+ memory-ranges = <
+ DDR_NS_BASE DDR_NS_SIZE TZC_REGION_S_NONE TZC_REGION_NSEC_ALL_ACCESS_RDWR>;
+#endif
+ };
+};
diff --git a/fdts/stm32mp15-pinctrl.dtsi b/fdts/stm32mp15-pinctrl.dtsi
new file mode 100644
index 0000000..7d2be0b
--- /dev/null
+++ b/fdts/stm32mp15-pinctrl.dtsi
@@ -0,0 +1,413 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved
+ * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
+ */
+#include <dt-bindings/pinctrl/stm32-pinfunc.h>
+
+&pinctrl {
+ fmc_pins_a: fmc-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('D', 4, AF12)>, /* FMC_NOE */
+ <STM32_PINMUX('D', 5, AF12)>, /* FMC_NWE */
+ <STM32_PINMUX('D', 11, AF12)>, /* FMC_A16_FMC_CLE */
+ <STM32_PINMUX('D', 12, AF12)>, /* FMC_A17_FMC_ALE */
+ <STM32_PINMUX('D', 14, AF12)>, /* FMC_D0 */
+ <STM32_PINMUX('D', 15, AF12)>, /* FMC_D1 */
+ <STM32_PINMUX('D', 0, AF12)>, /* FMC_D2 */
+ <STM32_PINMUX('D', 1, AF12)>, /* FMC_D3 */
+ <STM32_PINMUX('E', 7, AF12)>, /* FMC_D4 */
+ <STM32_PINMUX('E', 8, AF12)>, /* FMC_D5 */
+ <STM32_PINMUX('E', 9, AF12)>, /* FMC_D6 */
+ <STM32_PINMUX('E', 10, AF12)>, /* FMC_D7 */
+ <STM32_PINMUX('G', 9, AF12)>; /* FMC_NE2_FMC_NCE */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <1>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('D', 6, AF12)>; /* FMC_NWAIT */
+ bias-pull-up;
+ };
+ };
+
+ i2c2_pins_a: i2c2-0 {
+ pins {
+ pinmux = <STM32_PINMUX('H', 4, AF4)>, /* I2C2_SCL */
+ <STM32_PINMUX('H', 5, AF4)>; /* I2C2_SDA */
+ bias-disable;
+ drive-open-drain;
+ slew-rate = <0>;
+ };
+ };
+
+ qspi_clk_pins_a: qspi-clk-0 {
+ pins {
+ pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QSPI_CLK */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <3>;
+ };
+ };
+
+ qspi_bk1_pins_a: qspi-bk1-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('F', 8, AF10)>, /* QSPI_BK1_IO0 */
+ <STM32_PINMUX('F', 9, AF10)>, /* QSPI_BK1_IO1 */
+ <STM32_PINMUX('F', 7, AF9)>, /* QSPI_BK1_IO2 */
+ <STM32_PINMUX('F', 6, AF9)>; /* QSPI_BK1_IO3 */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <1>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('B', 6, AF10)>; /* QSPI_BK1_NCS */
+ bias-pull-up;
+ drive-push-pull;
+ slew-rate = <1>;
+ };
+ };
+
+ qspi_bk2_pins_a: qspi-bk2-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('H', 2, AF9)>, /* QSPI_BK2_IO0 */
+ <STM32_PINMUX('H', 3, AF9)>, /* QSPI_BK2_IO1 */
+ <STM32_PINMUX('G', 10, AF11)>, /* QSPI_BK2_IO2 */
+ <STM32_PINMUX('G', 7, AF11)>; /* QSPI_BK2_IO3 */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <1>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('C', 0, AF10)>; /* QSPI_BK2_NCS */
+ bias-pull-up;
+ drive-push-pull;
+ slew-rate = <1>;
+ };
+ };
+
+ sdmmc1_b4_pins_a: sdmmc1-b4-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
+ <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
+ <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
+ <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+ <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-disable;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
+ slew-rate = <2>;
+ drive-push-pull;
+ bias-disable;
+ };
+ };
+
+ sdmmc1_dir_pins_a: sdmmc1-dir-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('F', 2, AF11)>, /* SDMMC1_D0DIR */
+ <STM32_PINMUX('C', 7, AF8)>, /* SDMMC1_D123DIR */
+ <STM32_PINMUX('B', 9, AF11)>; /* SDMMC1_CDIR */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-pull-up;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('E', 4, AF8)>; /* SDMMC1_CKIN */
+ bias-pull-up;
+ };
+ };
+
+ sdmmc1_dir_pins_b: sdmmc1-dir-1 {
+ pins1 {
+ pinmux = <STM32_PINMUX('F', 2, AF11)>, /* SDMMC1_D0DIR */
+ <STM32_PINMUX('E', 14, AF11)>, /* SDMMC1_D123DIR */
+ <STM32_PINMUX('B', 9, AF11)>; /* SDMMC1_CDIR */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-pull-up;
+ };
+ pins2{
+ pinmux = <STM32_PINMUX('E', 4, AF8)>; /* SDMMC1_CKIN */
+ bias-pull-up;
+ };
+ };
+
+ sdmmc2_b4_pins_a: sdmmc2-b4-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
+ <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
+ <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
+ <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
+ <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-pull-up;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
+ slew-rate = <2>;
+ drive-push-pull;
+ bias-pull-up;
+ };
+ };
+
+ sdmmc2_b4_pins_b: sdmmc2-b4-1 {
+ pins1 {
+ pinmux = <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
+ <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
+ <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
+ <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
+ <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-disable;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
+ slew-rate = <2>;
+ drive-push-pull;
+ bias-disable;
+ };
+ };
+
+ sdmmc2_d47_pins_a: sdmmc2-d47-0 {
+ pins {
+ pinmux = <STM32_PINMUX('A', 8, AF9)>, /* SDMMC2_D4 */
+ <STM32_PINMUX('A', 9, AF10)>, /* SDMMC2_D5 */
+ <STM32_PINMUX('E', 5, AF9)>, /* SDMMC2_D6 */
+ <STM32_PINMUX('D', 3, AF9)>; /* SDMMC2_D7 */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-pull-up;
+ };
+ };
+
+ sdmmc2_d47_pins_b: sdmmc2-d47-1 {
+ pins {
+ pinmux = <STM32_PINMUX('A', 8, AF9)>, /* SDMMC2_D4 */
+ <STM32_PINMUX('A', 9, AF10)>, /* SDMMC2_D5 */
+ <STM32_PINMUX('C', 6, AF10)>, /* SDMMC2_D6 */
+ <STM32_PINMUX('C', 7, AF10)>; /* SDMMC2_D7 */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-disable;
+ };
+ };
+
+ sdmmc2_d47_pins_c: sdmmc2-d47-2 {
+ pins {
+ pinmux = <STM32_PINMUX('A', 8, AF9)>, /* SDMMC2_D4 */
+ <STM32_PINMUX('A', 15, AF9)>, /* SDMMC2_D5 */
+ <STM32_PINMUX('C', 6, AF10)>, /* SDMMC2_D6 */
+ <STM32_PINMUX('C', 7, AF10)>; /* SDMMC2_D7 */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-pull-up;
+ };
+ };
+
+ sdmmc2_d47_pins_d: sdmmc2-d47-3 {
+ pins {
+ pinmux = <STM32_PINMUX('A', 8, AF9)>, /* SDMMC2_D4 */
+ <STM32_PINMUX('A', 9, AF10)>, /* SDMMC2_D5 */
+ <STM32_PINMUX('E', 5, AF9)>, /* SDMMC2_D6 */
+ <STM32_PINMUX('C', 7, AF10)>; /* SDMMC2_D7 */
+ };
+ };
+
+ uart4_pins_a: uart4-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+ bias-disable;
+ };
+ };
+
+ uart4_pins_b: uart4-1 {
+ pins1 {
+ pinmux = <STM32_PINMUX('D', 1, AF8)>; /* UART4_TX */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+ bias-disable;
+ };
+ };
+
+ uart7_pins_a: uart7-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('E', 8, AF7)>; /* UART7_TX */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('E', 7, AF7)>, /* UART7_RX */
+ <STM32_PINMUX('E', 10, AF7)>, /* UART7_CTS */
+ <STM32_PINMUX('E', 9, AF7)>; /* UART7_RTS */
+ bias-disable;
+ };
+ };
+
+ uart7_pins_b: uart7-1 {
+ pins1 {
+ pinmux = <STM32_PINMUX('F', 7, AF7)>; /* UART7_TX */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('F', 6, AF7)>; /* UART7_RX */
+ bias-disable;
+ };
+ };
+
+ uart7_pins_c: uart7-2 {
+ pins1 {
+ pinmux = <STM32_PINMUX('E', 8, AF7)>; /* UART7_TX */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('E', 7, AF7)>; /* UART7_RX */
+ bias-disable;
+ };
+ };
+
+ uart8_pins_a: uart8-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('E', 1, AF8)>; /* UART8_TX */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('E', 0, AF8)>; /* UART8_RX */
+ bias-disable;
+ };
+ };
+
+ usart2_pins_a: usart2-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('F', 5, AF7)>, /* USART2_TX */
+ <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('D', 6, AF7)>, /* USART2_RX */
+ <STM32_PINMUX('D', 3, AF7)>; /* USART2_CTS_NSS */
+ bias-disable;
+ };
+ };
+
+ usart2_pins_b: usart2-1 {
+ pins1 {
+ pinmux = <STM32_PINMUX('F', 5, AF7)>, /* USART2_TX */
+ <STM32_PINMUX('A', 1, AF7)>; /* USART2_RTS */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('F', 4, AF7)>, /* USART2_RX */
+ <STM32_PINMUX('E', 15, AF7)>; /* USART2_CTS_NSS */
+ bias-disable;
+ };
+ };
+
+ usart2_pins_c: usart2-2 {
+ pins1 {
+ pinmux = <STM32_PINMUX('D', 5, AF7)>, /* USART2_TX */
+ <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <3>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('D', 6, AF7)>, /* USART2_RX */
+ <STM32_PINMUX('D', 3, AF7)>; /* USART2_CTS_NSS */
+ bias-disable;
+ };
+ };
+
+ usart3_pins_a: usart3-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('B', 10, AF7)>; /* USART3_TX */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('B', 12, AF8)>; /* USART3_RX */
+ bias-disable;
+ };
+ };
+
+ usart3_pins_b: usart3-1 {
+ pins1 {
+ pinmux = <STM32_PINMUX('B', 10, AF7)>, /* USART3_TX */
+ <STM32_PINMUX('G', 8, AF8)>; /* USART3_RTS */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('B', 12, AF8)>, /* USART3_RX */
+ <STM32_PINMUX('I', 10, AF8)>; /* USART3_CTS_NSS */
+ bias-disable;
+ };
+ };
+
+ usart3_pins_c: usart3-2 {
+ pins1 {
+ pinmux = <STM32_PINMUX('B', 10, AF7)>, /* USART3_TX */
+ <STM32_PINMUX('G', 8, AF8)>; /* USART3_RTS */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('B', 12, AF8)>, /* USART3_RX */
+ <STM32_PINMUX('B', 13, AF7)>; /* USART3_CTS_NSS */
+ bias-disable;
+ };
+ };
+
+ usbotg_hs_pins_a: usbotg-hs-0 {
+ pins {
+ pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* OTG_ID */
+ };
+ };
+
+ usbotg_fs_dp_dm_pins_a: usbotg-fs-dp-dm-0 {
+ pins {
+ pinmux = <STM32_PINMUX('A', 11, ANALOG)>, /* OTG_FS_DM */
+ <STM32_PINMUX('A', 12, ANALOG)>; /* OTG_FS_DP */
+ };
+ };
+};
+
+&pinctrl_z {
+ i2c4_pins_a: i2c4-0 {
+ pins {
+ pinmux = <STM32_PINMUX('Z', 4, AF6)>, /* I2C4_SCL */
+ <STM32_PINMUX('Z', 5, AF6)>; /* I2C4_SDA */
+ bias-disable;
+ drive-open-drain;
+ slew-rate = <0>;
+ };
+ };
+};
diff --git a/fdts/stm32mp151.dtsi b/fdts/stm32mp151.dtsi
new file mode 100644
index 0000000..a938edc
--- /dev/null
+++ b/fdts/stm32mp151.dtsi
@@ -0,0 +1,689 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
+ * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
+ */
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/stm32mp1-clks.h>
+#include <dt-bindings/reset/stm32mp1-resets.h>
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <0>;
+ nvmem-cells = <&part_number_otp>;
+ nvmem-cell-names = "part_number";
+ };
+ };
+
+ psci {
+ compatible = "arm,psci-1.0";
+ method = "smc";
+ };
+
+ intc: interrupt-controller@a0021000 {
+ compatible = "arm,cortex-a7-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0xa0021000 0x1000>,
+ <0xa0022000 0x2000>;
+ };
+
+ clocks {
+ clk_hse: clk-hse {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <24000000>;
+ };
+
+ clk_hsi: clk-hsi {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <64000000>;
+ };
+
+ clk_lse: clk-lse {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ };
+
+ clk_lsi: clk-lsi {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32000>;
+ };
+
+ clk_csi: clk-csi {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <4000000>;
+ };
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&intc>;
+ ranges;
+
+ timers12: timer@40006000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "st,stm32-timers";
+ reg = <0x40006000 0x400>;
+ clocks = <&rcc TIM12_K>;
+ clock-names = "int";
+ status = "disabled";
+ };
+
+ usart2: serial@4000e000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x4000e000 0x400>;
+ interrupts-extended = <&exti 27 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc USART2_K>;
+ resets = <&rcc USART2_R>;
+ status = "disabled";
+ };
+
+ usart3: serial@4000f000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x4000f000 0x400>;
+ interrupts-extended = <&exti 28 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc USART3_K>;
+ resets = <&rcc USART3_R>;
+ status = "disabled";
+ };
+
+ uart4: serial@40010000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x40010000 0x400>;
+ interrupts-extended = <&exti 30 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc UART4_K>;
+ resets = <&rcc UART4_R>;
+ wakeup-source;
+ status = "disabled";
+ };
+
+ uart5: serial@40011000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x40011000 0x400>;
+ interrupts-extended = <&exti 31 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc UART5_K>;
+ resets = <&rcc UART5_R>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@40013000 {
+ compatible = "st,stm32mp15-i2c";
+ reg = <0x40013000 0x400>;
+ interrupt-names = "event", "error";
+ interrupts = <&exti 22 IRQ_TYPE_LEVEL_HIGH>,
+ <&intc GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc I2C2_K>;
+ resets = <&rcc I2C2_R>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ st,syscfg-fmp = <&syscfg 0x4 0x2>;
+ wakeup-source;
+ status = "disabled";
+ };
+
+ uart7: serial@40018000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x40018000 0x400>;
+ interrupts-extended = <&exti 32 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc UART7_K>;
+ resets = <&rcc UART7_R>;
+ status = "disabled";
+ };
+
+ uart8: serial@40019000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x40019000 0x400>;
+ interrupts-extended = <&exti 33 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc UART8_K>;
+ resets = <&rcc UART8_R>;
+ status = "disabled";
+ };
+
+ usart6: serial@44003000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x44003000 0x400>;
+ interrupts-extended = <&exti 29 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc USART6_K>;
+ resets = <&rcc USART6_R>;
+ status = "disabled";
+ };
+
+ timers15: timer@44006000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "st,stm32-timers";
+ reg = <0x44006000 0x400>;
+ clocks = <&rcc TIM15_K>;
+ clock-names = "int";
+ status = "disabled";
+ };
+
+ usbotg_hs: usb-otg@49000000 {
+ compatible = "st,stm32mp15-hsotg", "snps,dwc2";
+ reg = <0x49000000 0x10000>;
+ clocks = <&rcc USBO_K>;
+ clock-names = "otg";
+ resets = <&rcc USBO_R>;
+ reset-names = "dwc2";
+ interrupts-extended = <&exti 44 IRQ_TYPE_LEVEL_HIGH>;
+ g-rx-fifo-size = <512>;
+ g-np-tx-fifo-size = <32>;
+ g-tx-fifo-size = <256 16 16 16 16 16 16 16>;
+ dr_mode = "otg";
+ usb33d-supply = <&usb33>;
+ status = "disabled";
+ };
+
+ rcc: rcc@50000000 {
+ compatible = "st,stm32mp1-rcc", "syscon";
+ reg = <0x50000000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ secure-interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+ secure-interrupt-names = "wakeup";
+ };
+
+ pwr_regulators: pwr@50001000 {
+ compatible = "st,stm32mp1,pwr-reg";
+ reg = <0x50001000 0x10>;
+ st,tzcr = <&rcc 0x0 0x1>;
+
+ reg11: reg11 {
+ regulator-name = "reg11";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ reg18: reg18 {
+ regulator-name = "reg18";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ usb33: usb33 {
+ regulator-name = "usb33";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+ };
+
+ pwr_mcu: pwr_mcu@50001014 {
+ compatible = "st,stm32mp151-pwr-mcu", "syscon";
+ reg = <0x50001014 0x4>;
+ };
+
+ pwr_irq: pwr@50001020 {
+ compatible = "st,stm32mp1-pwr";
+ reg = <0x50001020 0x100>;
+ interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ };
+
+ exti: interrupt-controller@5000d000 {
+ compatible = "st,stm32mp1-exti", "syscon";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x5000d000 0x400>;
+
+ /* exti_pwr is an extra interrupt controller used for
+ * EXTI 55 to 60. It's mapped on pwr interrupt
+ * controller.
+ */
+ exti_pwr: exti-pwr {
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&pwr_irq>;
+ st,irq-number = <6>;
+ };
+ };
+
+ syscfg: syscon@50020000 {
+ compatible = "st,stm32mp157-syscfg", "syscon";
+ reg = <0x50020000 0x400>;
+ clocks = <&rcc SYSCFG>;
+ };
+
+ hash1: hash@54002000 {
+ compatible = "st,stm32f756-hash";
+ reg = <0x54002000 0x400>;
+ interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc HASH1>;
+ resets = <&rcc HASH1_R>;
+ status = "disabled";
+ };
+
+ rng1: rng@54003000 {
+ compatible = "st,stm32-rng";
+ reg = <0x54003000 0x400>;
+ clocks = <&rcc RNG1_K>;
+ resets = <&rcc RNG1_R>;
+ status = "disabled";
+ };
+
+ fmc: memory-controller@58002000 {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ compatible = "st,stm32mp1-fmc2-ebi";
+ reg = <0x58002000 0x1000>;
+ clocks = <&rcc FMC_K>;
+ resets = <&rcc FMC_R>;
+ status = "disabled";
+
+ ranges = <0 0 0x60000000 0x04000000>, /* EBI CS 1 */
+ <1 0 0x64000000 0x04000000>, /* EBI CS 2 */
+ <2 0 0x68000000 0x04000000>, /* EBI CS 3 */
+ <3 0 0x6c000000 0x04000000>, /* EBI CS 4 */
+ <4 0 0x80000000 0x10000000>; /* NAND */
+
+ nand-controller@4,0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "st,stm32mp1-fmc2-nfc";
+ reg = <4 0x00000000 0x1000>,
+ <4 0x08010000 0x1000>,
+ <4 0x08020000 0x1000>,
+ <4 0x01000000 0x1000>,
+ <4 0x09010000 0x1000>,
+ <4 0x09020000 0x1000>;
+ interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+ };
+
+ qspi: spi@58003000 {
+ compatible = "st,stm32f469-qspi";
+ reg = <0x58003000 0x1000>, <0x70000000 0x10000000>;
+ reg-names = "qspi", "qspi_mm";
+ interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc QSPI_K>;
+ resets = <&rcc QSPI_R>;
+ status = "disabled";
+ };
+
+ sdmmc1: mmc@58005000 {
+ compatible = "st,stm32-sdmmc2", "arm,pl18x", "arm,primecell";
+ arm,primecell-periphid = <0x00253180>;
+ reg = <0x58005000 0x1000>, <0x58006000 0x1000>;
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "cmd_irq";
+ clocks = <&rcc SDMMC1_K>;
+ clock-names = "apb_pclk";
+ resets = <&rcc SDMMC1_R>;
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+ max-frequency = <120000000>;
+ status = "disabled";
+ };
+
+ sdmmc2: mmc@58007000 {
+ compatible = "st,stm32-sdmmc2", "arm,pl18x", "arm,primecell";
+ arm,primecell-periphid = <0x00253180>;
+ reg = <0x58007000 0x1000>, <0x58008000 0x1000>;
+ interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "cmd_irq";
+ clocks = <&rcc SDMMC2_K>;
+ clock-names = "apb_pclk";
+ resets = <&rcc SDMMC2_R>;
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+ max-frequency = <120000000>;
+ status = "disabled";
+ };
+
+ iwdg2: watchdog@5a002000 {
+ compatible = "st,stm32mp1-iwdg";
+ reg = <0x5a002000 0x400>;
+ secure-interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc IWDG2>, <&rcc CK_LSI>;
+ clock-names = "pclk", "lsi";
+ status = "disabled";
+ };
+
+ 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";
+ status = "okay";
+ };
+
+ usbphyc: usbphyc@5a006000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #clock-cells = <0>;
+ compatible = "st,stm32mp1-usbphyc";
+ reg = <0x5a006000 0x1000>;
+ clocks = <&rcc USBPHY_K>;
+ resets = <&rcc USBPHY_R>;
+ vdda1v1-supply = <&reg11>;
+ vdda1v8-supply = <&reg18>;
+ status = "disabled";
+
+ usbphyc_port0: usb-phy@0 {
+ #phy-cells = <0>;
+ reg = <0>;
+ };
+
+ usbphyc_port1: usb-phy@1 {
+ #phy-cells = <1>;
+ reg = <1>;
+ };
+ };
+
+ usart1: serial@5c000000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x5c000000 0x400>;
+ interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc USART1_K>;
+ resets = <&rcc USART1_R>;
+ status = "disabled";
+ };
+
+ spi6: spi@5c001000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "st,stm32h7-spi";
+ reg = <0x5c001000 0x400>;
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc SPI6_K>;
+ resets = <&rcc SPI6_R>;
+ status = "disabled";
+ };
+
+ i2c4: i2c@5c002000 {
+ compatible = "st,stm32mp15-i2c";
+ reg = <0x5c002000 0x400>;
+ interrupt-names = "event", "error";
+ interrupts-extended = <&exti 24 IRQ_TYPE_LEVEL_HIGH>,
+ <&intc GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc I2C4_K>;
+ resets = <&rcc I2C4_R>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ st,syscfg-fmp = <&syscfg 0x4 0x8>;
+ wakeup-source;
+ status = "disabled";
+ };
+
+ iwdg1: watchdog@5c003000 {
+ compatible = "st,stm32mp1-iwdg";
+ reg = <0x5C003000 0x400>;
+ interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc IWDG1>, <&rcc CK_LSI>;
+ clock-names = "pclk", "lsi";
+ status = "disabled";
+ };
+
+ rtc: rtc@5c004000 {
+ compatible = "st,stm32mp1-rtc";
+ reg = <0x5c004000 0x400>;
+ clocks = <&rcc RTCAPB>, <&rcc RTC>;
+ clock-names = "pclk", "rtc_ck";
+ interrupts-extended = <&exti 19 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ bsec: efuse@5c005000 {
+ compatible = "st,stm32mp15-bsec";
+ reg = <0x5c005000 0x400>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cfg0_otp: cfg0_otp@0 {
+ reg = <0x0 0x1>;
+ };
+ part_number_otp: part_number_otp@4 {
+ reg = <0x4 0x1>;
+ };
+ monotonic_otp: monotonic_otp@10 {
+ reg = <0x10 0x4>;
+ };
+ nand_otp: nand_otp@24 {
+ reg = <0x24 0x4>;
+ };
+ uid_otp: uid_otp@34 {
+ reg = <0x34 0xc>;
+ };
+ package_otp: package_otp@40 {
+ reg = <0x40 0x4>;
+ };
+ hw2_otp: hw2_otp@48 {
+ reg = <0x48 0x4>;
+ };
+ ts_cal1: calib@5c {
+ reg = <0x5c 0x2>;
+ };
+ ts_cal2: calib@5e {
+ reg = <0x5e 0x2>;
+ };
+ pkh_otp: pkh_otp@60 {
+ reg = <0x60 0x20>;
+ };
+ mac_addr: mac_addr@e4 {
+ reg = <0xe4 0x8>;
+ st,non-secure-otp;
+ };
+ };
+
+ etzpc: etzpc@5c007000 {
+ compatible = "st,stm32-etzpc";
+ reg = <0x5C007000 0x400>;
+ clocks = <&rcc TZPC>;
+ };
+
+ stgen: stgen@5c008000 {
+ compatible = "st,stm32-stgen";
+ reg = <0x5C008000 0x1000>;
+ };
+
+ i2c6: i2c@5c009000 {
+ compatible = "st,stm32mp15-i2c";
+ reg = <0x5c009000 0x400>;
+ interrupt-names = "event", "error";
+ interrupts-extended = <&exti 54 IRQ_TYPE_LEVEL_HIGH>,
+ <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc I2C6_K>;
+ resets = <&rcc I2C6_R>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ st,syscfg-fmp = <&syscfg 0x4 0x20>;
+ wakeup-source;
+ status = "disabled";
+ };
+
+ tamp: tamp@5c00a000 {
+ compatible = "st,stm32-tamp", "simple-bus", "syscon", "simple-mfd";
+ reg = <0x5c00a000 0x400>;
+ secure-interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc RTCAPB>;
+ };
+
+ /*
+ * Break node order to solve dependency probe issue between
+ * pinctrl and exti.
+ */
+ pinctrl: pinctrl@50002000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stm32mp157-pinctrl";
+ ranges = <0 0x50002000 0xa400>;
+ interrupt-parent = <&exti>;
+ st,syscfg = <&exti 0x60 0xff>;
+ pins-are-numbered;
+
+ gpioa: gpio@50002000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x0 0x400>;
+ clocks = <&rcc GPIOA>;
+ st,bank-name = "GPIOA";
+ status = "disabled";
+ };
+
+ gpiob: gpio@50003000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x1000 0x400>;
+ clocks = <&rcc GPIOB>;
+ st,bank-name = "GPIOB";
+ status = "disabled";
+ };
+
+ gpioc: gpio@50004000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x2000 0x400>;
+ clocks = <&rcc GPIOC>;
+ st,bank-name = "GPIOC";
+ status = "disabled";
+ };
+
+ gpiod: gpio@50005000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x3000 0x400>;
+ clocks = <&rcc GPIOD>;
+ st,bank-name = "GPIOD";
+ status = "disabled";
+ };
+
+ gpioe: gpio@50006000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x4000 0x400>;
+ clocks = <&rcc GPIOE>;
+ st,bank-name = "GPIOE";
+ status = "disabled";
+ };
+
+ gpiof: gpio@50007000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x5000 0x400>;
+ clocks = <&rcc GPIOF>;
+ st,bank-name = "GPIOF";
+ status = "disabled";
+ };
+
+ gpiog: gpio@50008000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x6000 0x400>;
+ clocks = <&rcc GPIOG>;
+ st,bank-name = "GPIOG";
+ status = "disabled";
+ };
+
+ gpioh: gpio@50009000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x7000 0x400>;
+ clocks = <&rcc GPIOH>;
+ st,bank-name = "GPIOH";
+ status = "disabled";
+ };
+
+ gpioi: gpio@5000a000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x8000 0x400>;
+ clocks = <&rcc GPIOI>;
+ st,bank-name = "GPIOI";
+ status = "disabled";
+ };
+
+ gpioj: gpio@5000b000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x9000 0x400>;
+ clocks = <&rcc GPIOJ>;
+ st,bank-name = "GPIOJ";
+ status = "disabled";
+ };
+
+ gpiok: gpio@5000c000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0xa000 0x400>;
+ clocks = <&rcc GPIOK>;
+ st,bank-name = "GPIOK";
+ status = "disabled";
+ };
+ };
+
+ pinctrl_z: pinctrl@54004000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stm32mp157-z-pinctrl";
+ ranges = <0 0x54004000 0x400>;
+ pins-are-numbered;
+ interrupt-parent = <&exti>;
+ st,syscfg = <&exti 0x60 0xff>;
+
+ gpioz: gpio@54004000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0 0x400>;
+ clocks = <&rcc GPIOZ>;
+ st,bank-name = "GPIOZ";
+ st,bank-ioport = <11>;
+ status = "disabled";
+ };
+ };
+ };
+};
diff --git a/fdts/stm32mp153.dtsi b/fdts/stm32mp153.dtsi
new file mode 100644
index 0000000..0a0bb8d
--- /dev/null
+++ b/fdts/stm32mp153.dtsi
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+#include "stm32mp151.dtsi"
+
+/ {
+ cpus {
+ cpu1: cpu@1 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <1>;
+ clocks = <&rcc CK_MPU>;
+ clock-names = "cpu";
+ };
+ };
+};
diff --git a/fdts/stm32mp157.dtsi b/fdts/stm32mp157.dtsi
new file mode 100644
index 0000000..c834029
--- /dev/null
+++ b/fdts/stm32mp157.dtsi
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+#include "stm32mp153.dtsi"
diff --git a/fdts/stm32mp157a-avenger96-fw-config.dts b/fdts/stm32mp157a-avenger96-fw-config.dts
new file mode 100644
index 0000000..2abbe50
--- /dev/null
+++ b/fdts/stm32mp157a-avenger96-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE 0x40000000 /* 1GB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157a-avenger96.dts b/fdts/stm32mp157a-avenger96.dts
new file mode 100644
index 0000000..f0da350
--- /dev/null
+++ b/fdts/stm32mp157a-avenger96.dts
@@ -0,0 +1,303 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) Arrow Electronics 2019 - All Rights Reserved
+ * Author: Botond Kardos <botond.kardos@arroweurope.com>
+ *
+ * Copyright (C) Linaro Ltd 2019 - All Rights Reserved
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ */
+
+/dts-v1/;
+
+#include "stm32mp157.dtsi"
+#include "stm32mp15-pinctrl.dtsi"
+#include "stm32mp15xxac-pinctrl.dtsi"
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include "stm32mp15-ddr3-2x4Gb-1066-binG.dtsi"
+
+/ {
+ model = "Arrow Electronics STM32MP157A Avenger96 board";
+ compatible = "arrow,stm32mp157a-avenger96", "st,stm32mp157";
+
+ aliases {
+ mmc0 = &sdmmc1;
+ serial0 = &uart4;
+ serial1 = &uart7;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory@c0000000 {
+ device_type = "memory";
+ reg = <0xc0000000 0x40000000>;
+ };
+};
+
+&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 = <0x30>;
+
+ regulators {
+ compatible = "st,stpmic1-regulators";
+ ldo1-supply = <&v3v3>;
+ ldo2-supply = <&v3v3>;
+ ldo3-supply = <&vdd_ddr>;
+ ldo5-supply = <&v3v3>;
+ ldo6-supply = <&v3v3>;
+ pwr_sw1-supply = <&bst_out>;
+ pwr_sw2-supply = <&bst_out>;
+
+ vddcore: buck1 {
+ regulator-name = "vddcore";
+ 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-always-on;
+ regulator-over-current-protection;
+ st,regulator-sink-source;
+ };
+
+ 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;
+ };
+
+ bst_out: boost {
+ regulator-name = "bst_out";
+ };
+
+ vbus_otg: pwr_sw1 {
+ regulator-name = "vbus_otg";
+ };
+
+ vbus_sw: pwr_sw2 {
+ regulator-name = "vbus_sw";
+ regulator-active-discharge = <1>;
+ };
+ };
+ };
+};
+
+&iwdg2 {
+ timeout-sec = <32>;
+ status = "okay";
+};
+
+&pwr_regulators {
+ vdd-supply = <&vdd>;
+ vdd_3v3_usbfs-supply = <&vdd_usb>;
+};
+
+&rcc {
+ 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 {
+ compatible = "st,stm32mp1-pll";
+ reg = <0>;
+ cfg = <2 80 0 0 0 PQR(1,0,0)>;
+ frac = <0x800>;
+ };
+
+ /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */
+ pll2: st,pll@1 {
+ compatible = "st,stm32mp1-pll";
+ reg = <1>;
+ cfg = <2 65 1 0 0 PQR(1,1,1)>;
+ frac = <0x1400>;
+ };
+
+ /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */
+ pll3: st,pll@2 {
+ compatible = "st,stm32mp1-pll";
+ reg = <2>;
+ cfg = <1 33 1 16 36 PQR(1,1,1)>;
+ frac = <0x1a04>;
+ };
+
+ /* VCO = 480.0 MHz => P = 120, Q = 40, R = 96 */
+ pll4: st,pll@3 {
+ compatible = "st,stm32mp1-pll";
+ reg = <3>;
+ cfg = <1 39 3 11 4 PQR(1,1,1)>;
+ };
+};
+
+&rng1 {
+ status = "okay";
+};
+
+&rtc {
+ status = "okay";
+};
+
+&sdmmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>;
+ st,sig-dir;
+ st,neg-edge;
+ st,use-ckin;
+ bus-width = <4>;
+ vmmc-supply = <&vdd_sd>;
+ status = "okay";
+};
+
+&uart4 {
+ /* On Low speed expansion header */
+ label = "LS-UART1";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4_pins_b>;
+ status = "okay";
+};
+
+&uart7 {
+ /* On Low speed expansion header */
+ label = "LS-UART0";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart7_pins_a>;
+ status = "okay";
+};
diff --git a/fdts/stm32mp157a-dhcor-avenger96-fw-config.dts b/fdts/stm32mp157a-dhcor-avenger96-fw-config.dts
new file mode 100644
index 0000000..2abbe50
--- /dev/null
+++ b/fdts/stm32mp157a-dhcor-avenger96-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE 0x40000000 /* 1GB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157a-dhcor-avenger96.dts b/fdts/stm32mp157a-dhcor-avenger96.dts
new file mode 100644
index 0000000..82d48aa
--- /dev/null
+++ b/fdts/stm32mp157a-dhcor-avenger96.dts
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Copyright (C) Linaro Ltd 2019 - All Rights Reserved
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ * Copyright (C) 2020 Marek Vasut <marex@denx.de>
+ * Copyright (C) 2022 DH electronics GmbH
+ *
+ * DHCOR STM32MP1 variant:
+ * DHCR-STM32MP157A-C065-R102-V18-SPI-C-01LG
+ * DHCOR PCB number: 586-100 or newer
+ * Avenger96 PCB number: 588-200 or newer
+ */
+
+/dts-v1/;
+
+#include "stm32mp157.dtsi"
+#include "stm32mp15xx-dhcor-som.dtsi"
+#include "stm32mp15xx-dhcor-avenger96.dtsi"
+
+/ {
+ model = "Arrow Electronics STM32MP157A Avenger96 board";
+ compatible = "arrow,stm32mp157a-avenger96", "dh,stm32mp157a-dhcor-som",
+ "st,stm32mp157";
+};
diff --git a/fdts/stm32mp157a-dk1-fw-config.dts b/fdts/stm32mp157a-dk1-fw-config.dts
new file mode 100644
index 0000000..83116d1
--- /dev/null
+++ b/fdts/stm32mp157a-dk1-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE 0x20000000 /* 512MB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157a-dk1.dts b/fdts/stm32mp157a-dk1.dts
new file mode 100644
index 0000000..a73bef8
--- /dev/null
+++ b/fdts/stm32mp157a-dk1.dts
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+/dts-v1/;
+
+#include "stm32mp157.dtsi"
+#include "stm32mp15-pinctrl.dtsi"
+#include "stm32mp15xxac-pinctrl.dtsi"
+#include "stm32mp15xx-dkx.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";
+ };
+};
diff --git a/fdts/stm32mp157a-ed1-fw-config.dts b/fdts/stm32mp157a-ed1-fw-config.dts
new file mode 100644
index 0000000..2abbe50
--- /dev/null
+++ b/fdts/stm32mp157a-ed1-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE 0x40000000 /* 1GB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157a-ev1-fw-config.dts b/fdts/stm32mp157a-ev1-fw-config.dts
new file mode 100644
index 0000000..2abbe50
--- /dev/null
+++ b/fdts/stm32mp157a-ev1-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE 0x40000000 /* 1GB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157c-dhcom-pdk2-fw-config.dts b/fdts/stm32mp157c-dhcom-pdk2-fw-config.dts
new file mode 100644
index 0000000..6a5a192
--- /dev/null
+++ b/fdts/stm32mp157c-dhcom-pdk2-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause
+/*
+ * Copyright (c) 2022 DH electronics GmbH
+ */
+
+#define DDR_SIZE 0x40000000 /* 1GB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157c-dhcom-pdk2.dts b/fdts/stm32mp157c-dhcom-pdk2.dts
new file mode 100644
index 0000000..370a69a
--- /dev/null
+++ b/fdts/stm32mp157c-dhcom-pdk2.dts
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause
+/*
+ * Copyright (C) 2019-2020 Marek Vasut <marex@denx.de>
+ * Copyright (C) 2022 DH electronics GmbH
+ *
+ * DHCOM STM32MP1 variant:
+ * DHCM-STM32MP157C-C065-R102-F0819-SPI-E2-CAN2-SDR104-RTC-WBT-T-DSI-I-01D2
+ * DHCOM PCB number: 587-200 or newer
+ * PDK2 PCB number: 516-400 or newer
+ */
+/dts-v1/;
+
+#include "stm32mp157.dtsi"
+#include "stm32mp15xc.dtsi"
+#include "stm32mp15xx-dhcom-som.dtsi"
+#include "stm32mp15xx-dhcom-pdk2.dtsi"
+
+/ {
+ model = "DH electronics STM32MP157C DHCOM Premium Developer Kit (2)";
+ compatible = "dh,stm32mp157c-dhcom-pdk2", "dh,stm32mp157c-dhcom-som",
+ "st,stm32mp157";
+};
+
+&cryp1 {
+ status = "okay";
+};
diff --git a/fdts/stm32mp157c-dk2-fw-config.dts b/fdts/stm32mp157c-dk2-fw-config.dts
new file mode 100644
index 0000000..83116d1
--- /dev/null
+++ b/fdts/stm32mp157c-dk2-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE 0x20000000 /* 512MB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157c-dk2.dts b/fdts/stm32mp157c-dk2.dts
new file mode 100644
index 0000000..be8300e
--- /dev/null
+++ b/fdts/stm32mp157c-dk2.dts
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+/dts-v1/;
+
+#include "stm32mp157.dtsi"
+#include "stm32mp15xc.dtsi"
+#include "stm32mp15-pinctrl.dtsi"
+#include "stm32mp15xxac-pinctrl.dtsi"
+#include "stm32mp15xx-dkx.dtsi"
+
+/ {
+ model = "STMicroelectronics STM32MP157C-DK2 Discovery Board";
+ compatible = "st,stm32mp157c-dk2", "st,stm32mp157";
+
+ aliases {
+ serial0 = &uart4;
+ serial1 = &usart3;
+ serial2 = &uart7;
+ serial3 = &usart2;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&cryp1 {
+ status = "okay";
+};
diff --git a/fdts/stm32mp157c-ed1-fw-config.dts b/fdts/stm32mp157c-ed1-fw-config.dts
new file mode 100644
index 0000000..2abbe50
--- /dev/null
+++ b/fdts/stm32mp157c-ed1-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE 0x40000000 /* 1GB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157c-ed1.dts b/fdts/stm32mp157c-ed1.dts
new file mode 100644
index 0000000..d928563
--- /dev/null
+++ b/fdts/stm32mp157c-ed1.dts
@@ -0,0 +1,342 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
+ * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
+ */
+/dts-v1/;
+
+#include "stm32mp157.dtsi"
+#include "stm32mp15xc.dtsi"
+#include "stm32mp15-pinctrl.dtsi"
+#include "stm32mp15xxaa-pinctrl.dtsi"
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include "stm32mp15-ddr3-2x4Gb-1066-binG.dtsi"
+
+/ {
+ model = "STMicroelectronics STM32MP157C eval daughter";
+ compatible = "st,stm32mp157c-ed1", "st,stm32mp157";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory@c0000000 {
+ device_type = "memory";
+ reg = <0xC0000000 0x40000000>;
+ };
+
+ aliases {
+ serial0 = &uart4;
+ };
+};
+
+&bsec {
+ board_id: board_id@ec {
+ reg = <0xec 0x4>;
+ st,non-secure-otp;
+ };
+};
+
+&clk_hse {
+ st,digbypass;
+};
+
+&cpu0 {
+ cpu-supply = <&vddcore>;
+};
+
+&cpu1 {
+ cpu-supply = <&vddcore>;
+};
+
+&cryp1 {
+ status = "okay";
+};
+
+&hash1 {
+ status = "okay";
+};
+
+&i2c4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c4_pins_a>;
+ i2c-scl-rising-time-ns = <185>;
+ i2c-scl-falling-time-ns = <20>;
+ clock-frequency = <400000>;
+ status = "okay";
+
+ pmic: stpmic@33 {
+ compatible = "st,stpmic1";
+ reg = <0x33>;
+ interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "okay";
+
+ regulators {
+ compatible = "st,stpmic1-regulators";
+ ldo1-supply = <&v3v3>;
+ ldo2-supply = <&v3v3>;
+ ldo3-supply = <&vdd_ddr>;
+ ldo5-supply = <&v3v3>;
+ ldo6-supply = <&v3v3>;
+ pwr_sw1-supply = <&bst_out>;
+ pwr_sw2-supply = <&bst_out>;
+
+ vddcore: buck1 {
+ regulator-name = "vddcore";
+ 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-always-on;
+ regulator-over-current-protection;
+ st,regulator-sink-source;
+ };
+
+ 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;
+ };
+
+ bst_out: boost {
+ regulator-name = "bst_out";
+ };
+
+ vbus_otg: pwr_sw1 {
+ regulator-name = "vbus_otg";
+ };
+
+ vbus_sw: pwr_sw2 {
+ regulator-name = "vbus_sw";
+ regulator-active-discharge = <1>;
+ };
+ };
+
+ onkey {
+ compatible = "st,stpmic1-onkey";
+ power-off-time-sec = <10>;
+ status = "okay";
+ };
+
+ watchdog {
+ compatible = "st,stpmic1-wdt";
+ status = "disabled";
+ };
+ };
+};
+
+&iwdg2 {
+ timeout-sec = <32>;
+ status = "okay";
+};
+
+&pwr_regulators {
+ vdd-supply = <&vdd>;
+ vdd_3v3_usbfs-supply = <&vdd_usb>;
+};
+
+&rcc {
+ 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_PLL4P
+ 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 {
+ compatible = "st,stm32mp1-pll";
+ reg = <0>;
+ cfg = <2 80 0 0 0 PQR(1,0,0)>;
+ frac = <0x800>;
+ };
+
+ /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */
+ pll2: st,pll@1 {
+ compatible = "st,stm32mp1-pll";
+ reg = <1>;
+ cfg = <2 65 1 0 0 PQR(1,1,1)>;
+ frac = <0x1400>;
+ };
+
+ /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */
+ pll3: st,pll@2 {
+ compatible = "st,stm32mp1-pll";
+ reg = <2>;
+ cfg = <1 33 1 16 36 PQR(1,1,1)>;
+ frac = <0x1a04>;
+ };
+
+ /* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */
+ pll4: st,pll@3 {
+ compatible = "st,stm32mp1-pll";
+ reg = <3>;
+ cfg = <3 98 5 7 7 PQR(1,1,1)>;
+ };
+};
+
+&rng1 {
+ status = "okay";
+};
+
+&rtc {
+ status = "okay";
+};
+
+&sdmmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>;
+ disable-wp;
+ st,sig-dir;
+ st,neg-edge;
+ st,use-ckin;
+ bus-width = <4>;
+ vmmc-supply = <&vdd_sd>;
+ sd-uhs-sdr12;
+ sd-uhs-sdr25;
+ sd-uhs-sdr50;
+ sd-uhs-ddr50;
+ status = "okay";
+};
+
+&sdmmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_a>;
+ non-removable;
+ no-sd;
+ no-sdio;
+ st,neg-edge;
+ bus-width = <8>;
+ vmmc-supply = <&v3v3>;
+ vqmmc-supply = <&vdd>;
+ mmc-ddr-3_3v;
+ status = "okay";
+};
+
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4_pins_a>;
+ status = "okay";
+};
diff --git a/fdts/stm32mp157c-ev1-fw-config.dts b/fdts/stm32mp157c-ev1-fw-config.dts
new file mode 100644
index 0000000..2abbe50
--- /dev/null
+++ b/fdts/stm32mp157c-ev1-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE 0x40000000 /* 1GB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157c-ev1.dts b/fdts/stm32mp157c-ev1.dts
new file mode 100644
index 0000000..02840a2
--- /dev/null
+++ b/fdts/stm32mp157c-ev1.dts
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved
+ * Author: Ludovic Barre <ludovic.barre@st.com> 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 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&fmc_pins_a>;
+ status = "okay";
+
+ nand-controller@4,0 {
+ status = "okay";
+
+ 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>;
+ 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>;
+ };
+};
+
+&usart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usart3_pins_b>;
+ uart-has-rtscts;
+ status = "disabled";
+};
diff --git a/fdts/stm32mp157c-lxa-mc1-fw-config.dts b/fdts/stm32mp157c-lxa-mc1-fw-config.dts
new file mode 100644
index 0000000..9ee09e9
--- /dev/null
+++ b/fdts/stm32mp157c-lxa-mc1-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE 0x20000000 /* 512MB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157c-lxa-mc1.dts b/fdts/stm32mp157c-lxa-mc1.dts
new file mode 100644
index 0000000..6f67712
--- /dev/null
+++ b/fdts/stm32mp157c-lxa-mc1.dts
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause) */
+/*
+ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2020 Ahmad Fatoum, Pengutronix
+ */
+
+/dts-v1/;
+
+#include "stm32mp157.dtsi"
+#include "stm32mp15xc.dtsi"
+#include "stm32mp15-ddr3-1x4Gb-1066-binG.dtsi"
+#include "stm32mp15xx-osd32.dtsi"
+#include "stm32mp15xxac-pinctrl.dtsi"
+
+/ {
+ model = "Linux Automation MC-1 board";
+ compatible = "lxa,stm32mp157c-mc1", "oct,stm32mp15xx-osd32", "st,stm32mp157";
+
+ aliases {
+ mmc0 = &sdmmc1;
+ mmc1 = &sdmmc2;
+ serial0 = &uart4;
+ };
+
+ chosen {
+ stdout-path = &uart4;
+ };
+
+ led-act {
+ compatible = "gpio-leds";
+
+ led-green {
+ label = "mc1:green:act";
+ gpios = <&gpioa 13 1>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ reg_3v3: regulator_3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ vin-supply = <&v3v3>;
+ };
+};
+
+&sdmmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc1_b4_pins_a>;
+ bus-width = <4>;
+ cd-gpios = <&gpioh 3 1>;
+ disable-wp;
+ no-1-8-v;
+ st,neg-edge;
+ vmmc-supply = <&reg_3v3>;
+ status = "okay";
+};
+
+&sdmmc1_b4_pins_a {
+ /*
+ * board lacks external pull-ups on SDMMC lines. Class 10 SD refuses to
+ * work, thus enable internal pull-ups.
+ */
+ pins1 {
+ /delete-property/ bias-disable;
+ bias-pull-up;
+ };
+ pins2 {
+ /delete-property/ bias-disable;
+ bias-pull-up;
+ };
+};
+
+&sdmmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_b>;
+ bus-width = <8>;
+ no-1-8-v;
+ no-sd;
+ no-sdio;
+ non-removable;
+ st,neg-edge;
+ vmmc-supply = <&reg_3v3>;
+ status = "okay";
+};
+
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4_pins_a>;
+ status = "okay";
+};
diff --git a/fdts/stm32mp157c-odyssey-fw-config.dts b/fdts/stm32mp157c-odyssey-fw-config.dts
new file mode 100644
index 0000000..9ee09e9
--- /dev/null
+++ b/fdts/stm32mp157c-odyssey-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE 0x20000000 /* 512MB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157c-odyssey-som.dtsi b/fdts/stm32mp157c-odyssey-som.dtsi
new file mode 100644
index 0000000..091e327
--- /dev/null
+++ b/fdts/stm32mp157c-odyssey-som.dtsi
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2019, STMicroelectronics. All Rights Reserved.
+ * Copyright (C) 2021, Grzegorz Szymaszek.
+ *
+ * SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause)
+ */
+
+#include "stm32mp157.dtsi"
+#include "stm32mp15xc.dtsi"
+#include "stm32mp15-pinctrl.dtsi"
+#include "stm32mp15xxac-pinctrl.dtsi"
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include "stm32mp15-ddr3-1x4Gb-1066-binG.dtsi"
+
+/ {
+ memory@c0000000 {
+ device_type = "memory";
+ reg = <0xc0000000 0x20000000>;
+ };
+
+ vin: vin {
+ compatible = "regulator-fixed";
+ regulator-name = "vin";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
+};
+
+&bsec {
+ board_id: board_id@ec {
+ reg = <0xec 0x4>;
+ st,non-secure-otp;
+ };
+};
+
+&clk_hse {
+ st,digbypass;
+};
+
+&cpu0 {
+ cpu-supply = <&vddcore>;
+};
+
+&cpu1 {
+ cpu-supply = <&vddcore>;
+};
+
+&cryp1 {
+ status = "okay";
+};
+
+&hash1 {
+ status = "okay";
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ clock-frequency = <400000>;
+ 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";
+
+ regulators {
+ compatible = "st,stpmic1-regulators";
+ buck1-supply = <&vin>;
+ buck2-supply = <&vin>;
+ buck3-supply = <&vin>;
+ buck4-supply = <&vin>;
+ ldo1-supply = <&v3v3>;
+ ldo2-supply = <&vin>;
+ ldo3-supply = <&vdd_ddr>;
+ ldo4-supply = <&vin>;
+ ldo5-supply = <&vin>;
+ ldo6-supply = <&v3v3>;
+ vref_ddr-supply = <&vin>;
+ boost-supply = <&vin>;
+ pwr_sw1-supply = <&bst_out>;
+ pwr_sw2-supply = <&bst_out>;
+
+ vddcore: buck1 {
+ regulator-name = "vddcore";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-initial-mode = <0>;
+ regulator-over-current-protection;
+ };
+
+ 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-always-on;
+ regulator-over-current-protection;
+ st,regulator-sink-source;
+ };
+
+ vdd_usb: ldo4 {
+ regulator-name = "vdd_usb";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ 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;
+ };
+
+ bst_out: boost {
+ regulator-name = "bst_out";
+ };
+
+ vbus_otg: pwr_sw1 {
+ regulator-name = "vbus_otg";
+ };
+
+ vbus_sw: pwr_sw2 {
+ regulator-name = "vbus_sw";
+ regulator-active-discharge = <1>;
+ };
+ };
+
+ pmic_watchdog: watchdog {
+ compatible = "st,stpmic1-wdt";
+ status = "disabled";
+ };
+ };
+};
+
+&iwdg2 {
+ timeout-sec = <32>;
+ status = "okay";
+};
+
+&pwr_regulators {
+ vdd-supply = <&vdd>;
+ vdd_3v3_usbfs-supply = <&vdd_usb>;
+};
+
+&rcc {
+ 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_PLL4P
+ 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 {
+ compatible = "st,stm32mp1-pll";
+ reg = <0>;
+ cfg = <2 80 0 0 0 PQR(1,0,0)>;
+ frac = <0x800>;
+ };
+
+ /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */
+ pll2: st,pll@1 {
+ compatible = "st,stm32mp1-pll";
+ reg = <1>;
+ cfg = <2 65 1 0 0 PQR(1,1,1)>;
+ frac = <0x1400>;
+ };
+
+ /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */
+ pll3: st,pll@2 {
+ compatible = "st,stm32mp1-pll";
+ reg = <2>;
+ cfg = <1 33 1 16 36 PQR(1,1,1)>;
+ frac = <0x1a04>;
+ };
+
+ /* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */
+ pll4: st,pll@3 {
+ compatible = "st,stm32mp1-pll";
+ reg = <3>;
+ cfg = <3 98 5 7 7 PQR(1,1,1)>;
+ };
+};
+
+&rng1 {
+ status = "okay";
+};
+
+&rtc {
+ status = "okay";
+};
+
+&sdmmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_d>;
+ non-removable;
+ no-sd;
+ no-sdio;
+ st,neg-edge;
+ bus-width = <8>;
+ vmmc-supply = <&v3v3>;
+ vqmmc-supply = <&vdd>;
+ mmc-ddr-3_3v;
+ status = "okay";
+};
diff --git a/fdts/stm32mp157c-odyssey.dts b/fdts/stm32mp157c-odyssey.dts
new file mode 100644
index 0000000..03800f9
--- /dev/null
+++ b/fdts/stm32mp157c-odyssey.dts
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019, STMicroelectronics. All Rights Reserved.
+ * Copyright (C) 2021, Grzegorz Szymaszek.
+ *
+ * SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause)
+ */
+
+/dts-v1/;
+
+#include "stm32mp157c-odyssey-som.dtsi"
+
+/ {
+ model = "Seeed Studio Odyssey-STM32MP157C Board";
+ compatible = "seeed,stm32mp157c-odyssey",
+ "seeed,stm32mp157c-odyssey-som", "st,stm32mp157";
+
+ aliases {
+ serial0 = &uart4;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&sdmmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc1_b4_pins_a>;
+ disable-wp;
+ st,neg-edge;
+ bus-width = <4>;
+ vmmc-supply = <&v3v3>;
+ status = "okay";
+};
+
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4_pins_a>;
+ status = "okay";
+};
diff --git a/fdts/stm32mp157d-dk1-fw-config.dts b/fdts/stm32mp157d-dk1-fw-config.dts
new file mode 100644
index 0000000..83116d1
--- /dev/null
+++ b/fdts/stm32mp157d-dk1-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE 0x20000000 /* 512MB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157d-ed1-fw-config.dts b/fdts/stm32mp157d-ed1-fw-config.dts
new file mode 100644
index 0000000..2abbe50
--- /dev/null
+++ b/fdts/stm32mp157d-ed1-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE 0x40000000 /* 1GB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157d-ev1-fw-config.dts b/fdts/stm32mp157d-ev1-fw-config.dts
new file mode 100644
index 0000000..2abbe50
--- /dev/null
+++ b/fdts/stm32mp157d-ev1-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE 0x40000000 /* 1GB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157f-dk2-fw-config.dts b/fdts/stm32mp157f-dk2-fw-config.dts
new file mode 100644
index 0000000..83116d1
--- /dev/null
+++ b/fdts/stm32mp157f-dk2-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE 0x20000000 /* 512MB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157f-ed1-fw-config.dts b/fdts/stm32mp157f-ed1-fw-config.dts
new file mode 100644
index 0000000..2abbe50
--- /dev/null
+++ b/fdts/stm32mp157f-ed1-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE 0x40000000 /* 1GB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157f-ev1-fw-config.dts b/fdts/stm32mp157f-ev1-fw-config.dts
new file mode 100644
index 0000000..2abbe50
--- /dev/null
+++ b/fdts/stm32mp157f-ev1-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE 0x40000000 /* 1GB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp15xc.dtsi b/fdts/stm32mp15xc.dtsi
new file mode 100644
index 0000000..b06a55a
--- /dev/null
+++ b/fdts/stm32mp15xc.dtsi
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+/ {
+ soc {
+ cryp1: cryp@54001000 {
+ compatible = "st,stm32mp1-cryp";
+ reg = <0x54001000 0x400>;
+ interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc CRYP1>;
+ resets = <&rcc CRYP1_R>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/fdts/stm32mp15xx-dhcom-pdk2.dtsi b/fdts/stm32mp15xx-dhcom-pdk2.dtsi
new file mode 100644
index 0000000..1ffc60d
--- /dev/null
+++ b/fdts/stm32mp15xx-dhcom-pdk2.dtsi
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause
+/*
+ * Copyright (C) 2019-2020 Marek Vasut <marex@denx.de>
+ * Copyright (C) 2022 DH electronics GmbH
+ */
+
+/ {
+ aliases {
+ serial0 = &uart4;
+ serial1 = &usart3;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&usart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usart3_pins_a>;
+ status = "okay";
+};
+
+&usbotg_hs {
+ dr_mode = "otg";
+ pinctrl-0 = <&usbotg_hs_pins_a>;
+ pinctrl-names = "default";
+ phy-names = "usb2-phy";
+ phys = <&usbphyc_port1 0>;
+ vbus-supply = <&vbus_otg>;
+ status = "okay";
+};
+
+&usbphyc {
+ status = "okay";
+};
+
+&usbphyc_port0 {
+ phy-supply = <&vdd_usb>;
+};
+
+&usbphyc_port1 {
+ phy-supply = <&vdd_usb>;
+};
diff --git a/fdts/stm32mp15xx-dhcom-som.dtsi b/fdts/stm32mp15xx-dhcom-som.dtsi
new file mode 100644
index 0000000..c9f21b0
--- /dev/null
+++ b/fdts/stm32mp15xx-dhcom-som.dtsi
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause
+/*
+ * Copyright (C) 2019-2020 Marek Vasut <marex@denx.de>
+ * Copyright (C) 2022 DH electronics GmbH
+ */
+
+#include "stm32mp15-pinctrl.dtsi"
+#include "stm32mp15xxaa-pinctrl.dtsi"
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include "stm32mp15-ddr3-dhsom-2x4Gb-1066-binG.dtsi"
+
+/ {
+ memory@c0000000 {
+ device_type = "memory";
+ reg = <0xC0000000 0x40000000>;
+ };
+};
+
+&bsec {
+ board_id: board_id@ec {
+ reg = <0xec 0x4>;
+ st,non-secure-otp;
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&vddcore>;
+};
+
+&cpu1 {
+ cpu-supply = <&vddcore>;
+};
+
+&hash1 {
+ status = "okay";
+};
+
+&i2c4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c4_pins_a>;
+ i2c-scl-rising-time-ns = <185>;
+ i2c-scl-falling-time-ns = <20>;
+ status = "okay";
+
+ pmic: stpmic@33 {
+ compatible = "st,stpmic1";
+ reg = <0x33>;
+ interrupts-extended = <&gpioa 0 IRQ_TYPE_EDGE_FALLING>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "okay";
+
+ regulators {
+ compatible = "st,stpmic1-regulators";
+ ldo1-supply = <&v3v3>;
+ ldo2-supply = <&v3v3>;
+ ldo3-supply = <&vdd_ddr>;
+ ldo5-supply = <&v3v3>;
+ ldo6-supply = <&v3v3>;
+ pwr_sw1-supply = <&bst_out>;
+ pwr_sw2-supply = <&bst_out>;
+
+ vddcore: buck1 {
+ regulator-name = "vddcore";
+ 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>;
+ regulator-always-on;
+ };
+
+ v2v8: ldo2 {
+ regulator-name = "v2v8";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+
+ vtt_ddr: ldo3 {
+ regulator-name = "vtt_ddr";
+ regulator-always-on;
+ regulator-over-current-protection;
+ st,regulator-sink-source;
+ };
+
+ 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;
+ };
+
+ bst_out: boost {
+ regulator-name = "bst_out";
+ };
+
+ vbus_otg: pwr_sw1 {
+ regulator-name = "vbus_otg";
+ };
+
+ vbus_sw: pwr_sw2 {
+ regulator-name = "vbus_sw";
+ regulator-active-discharge = <1>;
+ };
+ };
+ };
+};
+
+&iwdg2 {
+ timeout-sec = <32>;
+ status = "okay";
+};
+
+&pwr_regulators {
+ vdd-supply = <&vdd>;
+ vdd_3v3_usbfs-supply = <&vdd_usb>;
+};
+
+&qspi {
+ pinctrl-names = "default";
+ pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a>;
+ reg = <0x58003000 0x1000>, <0x70000000 0x4000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ flash0: flash@0 {
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-rx-bus-width = <4>;
+ spi-max-frequency = <108000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+};
+
+&rcc {
+ 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_PLL4P
+ >;
+
+ st,clkdiv = <
+ 1 /*MPU*/
+ 0 /*AXI*/
+ 0 /*MCU*/
+ 1 /*APB1*/
+ 1 /*APB2*/
+ 1 /*APB3*/
+ 1 /*APB4*/
+ 2 /*APB5*/
+ 23 /*RTC*/
+ 0 /*MCO1*/
+ 1 /*MCO2*/
+ >;
+
+ st,pkcs = <
+ CLK_CKPER_HSE
+ CLK_FMC_ACLK
+ CLK_QSPI_ACLK
+ CLK_ETH_PLL4P
+ 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 {
+ compatible = "st,stm32mp1-pll";
+ reg = <0>;
+ cfg = <2 80 0 0 0 PQR(1,0,0)>;
+ frac = <0x800>;
+ };
+
+ /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */
+ pll2: st,pll@1 {
+ compatible = "st,stm32mp1-pll";
+ reg = <1>;
+ cfg = <2 65 1 0 0 PQR(1,1,1)>;
+ frac = <0x1400>;
+ };
+
+ /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */
+ pll3: st,pll@2 {
+ compatible = "st,stm32mp1-pll";
+ reg = <2>;
+ cfg = <1 33 1 16 36 PQR(1,1,1)>;
+ frac = <0x1a04>;
+ };
+
+ /* VCO = 600.0 MHz => P = 50, Q = 50, R = 50 */
+ pll4: st,pll@3 {
+ compatible = "st,stm32mp1-pll";
+ reg = <3>;
+ cfg = <1 49 5 11 11 PQR(1,1,1)>;
+ };
+};
+
+&rng1 {
+ status = "okay";
+};
+
+&rtc {
+ status = "okay";
+};
+
+&sdmmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>;
+ disable-wp;
+ st,sig-dir;
+ st,neg-edge;
+ bus-width = <4>;
+ vmmc-supply = <&vdd_sd>;
+ status = "okay";
+};
+
+&sdmmc1_b4_pins_a {
+ /*
+ * SD bus pull-up resistors:
+ * - optional on SoMs with SD voltage translator
+ * - mandatory on SoMs without SD voltage translator
+ */
+ pins1 {
+ bias-pull-up;
+ };
+ pins2 {
+ bias-pull-up;
+ };
+};
+
+&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";
+};
diff --git a/fdts/stm32mp15xx-dhcor-avenger96.dtsi b/fdts/stm32mp15xx-dhcor-avenger96.dtsi
new file mode 100644
index 0000000..576e0f1
--- /dev/null
+++ b/fdts/stm32mp15xx-dhcor-avenger96.dtsi
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Copyright (C) Linaro Ltd 2019 - All Rights Reserved
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ * Copyright (C) 2020 Marek Vasut <marex@denx.de>
+ * Copyright (C) 2022 DH electronics GmbH
+ */
+
+/* Avenger96 uses DHCOR SoM configured for 1V8 IO operation */
+#include "stm32mp15xx-dhcor-io1v8.dtsi"
+
+/ {
+ aliases {
+ serial0 = &uart4;
+ serial1 = &uart7;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ sd_switch: regulator-sd_switch {
+ compatible = "regulator-gpio";
+ regulator-name = "sd_switch";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2900000>;
+ regulator-type = "voltage";
+ regulator-always-on;
+
+ gpios = <&gpioi 5 0>;
+ gpios-states = <0>;
+ states = <1800000 0x1>,
+ <2900000 0x0>;
+ };
+};
+
+&sdmmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_b>;
+ disable-wp;
+ st,sig-dir;
+ st,neg-edge;
+ st,use-ckin;
+ bus-width = <4>;
+ vmmc-supply = <&vdd_sd>;
+ vqmmc-supply = <&sd_switch>;
+ status = "okay";
+};
+
+&sdmmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_c>;
+ bus-width = <8>;
+ mmc-ddr-1_8v;
+ no-sd;
+ no-sdio;
+ non-removable;
+ st,neg-edge;
+ vmmc-supply = <&v3v3>;
+ vqmmc-supply = <&vdd_io>;
+ status = "okay";
+};
+
+&uart4 {
+ /* On Low speed expansion header */
+ label = "LS-UART1";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4_pins_b>;
+ status = "okay";
+};
+
+&uart7 {
+ /* On Low speed expansion header */
+ label = "LS-UART0";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart7_pins_a>;
+ uart-has-rtscts;
+ status = "okay";
+};
+
+&usbotg_hs {
+ pinctrl-0 = <&usbotg_hs_pins_a>;
+ pinctrl-names = "default";
+ phy-names = "usb2-phy";
+ phys = <&usbphyc_port1 0>;
+ status = "okay";
+ vbus-supply = <&vbus_otg>;
+};
+
+&usbphyc {
+ status = "okay";
+};
+
+&usbphyc_port0 {
+ phy-supply = <&vdd_usb>;
+};
+
+&usbphyc_port1 {
+ phy-supply = <&vdd_usb>;
+};
diff --git a/fdts/stm32mp15xx-dhcor-io1v8.dtsi b/fdts/stm32mp15xx-dhcor-io1v8.dtsi
new file mode 100644
index 0000000..9937b28
--- /dev/null
+++ b/fdts/stm32mp15xx-dhcor-io1v8.dtsi
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Copyright (C) Linaro Ltd 2019 - All Rights Reserved
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ * Copyright (C) 2020 Marek Vasut <marex@denx.de>
+ */
+
+/ {
+ /* Enpirion EP3A8LQI U2 on the DHCOR */
+ vdd_io: regulator-buck-io {
+ compatible = "regulator-fixed";
+ regulator-name = "buck-io";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vdd>;
+ };
+};
+
+&vdd {
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <2900000>;
+};
+
+&pwr_regulators {
+ vdd-supply = <&vdd_io>;
+};
diff --git a/fdts/stm32mp15xx-dhcor-som.dtsi b/fdts/stm32mp15xx-dhcor-som.dtsi
new file mode 100644
index 0000000..c241efc
--- /dev/null
+++ b/fdts/stm32mp15xx-dhcor-som.dtsi
@@ -0,0 +1,286 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Copyright (C) Linaro Ltd 2019 - All Rights Reserved
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ * Copyright (C) 2020 Marek Vasut <marex@denx.de>
+ * Copyright (C) 2022 DH electronics GmbH
+ */
+
+#include "stm32mp15-pinctrl.dtsi"
+#include "stm32mp15xxaa-pinctrl.dtsi"
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include "stm32mp15-ddr3-dhsom-2x4Gb-1066-binG.dtsi"
+
+/ {
+ memory@c0000000 {
+ device_type = "memory";
+ reg = <0xc0000000 0x40000000>;
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&vddcore>;
+};
+
+&cpu1 {
+ cpu-supply = <&vddcore>;
+};
+
+&hash1 {
+ status = "okay";
+};
+
+&i2c4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c4_pins_a>;
+ i2c-scl-rising-time-ns = <185>;
+ i2c-scl-falling-time-ns = <20>;
+ status = "okay";
+
+ pmic: stpmic@33 {
+ compatible = "st,stpmic1";
+ reg = <0x33>;
+ interrupts-extended = <&gpioa 0 IRQ_TYPE_EDGE_FALLING>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "okay";
+
+ regulators {
+ compatible = "st,stpmic1-regulators";
+ ldo1-supply = <&v3v3>;
+ ldo2-supply = <&v3v3>;
+ ldo3-supply = <&vdd_ddr>;
+ ldo5-supply = <&v3v3>;
+ ldo6-supply = <&v3v3>;
+ pwr_sw1-supply = <&bst_out>;
+ pwr_sw2-supply = <&bst_out>;
+
+ vddcore: buck1 {
+ regulator-name = "vddcore";
+ 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;
+ 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-always-on;
+ regulator-over-current-protection;
+ st,regulator-sink-source;
+ };
+
+ 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>;
+ regulator-enable-ramp-delay = <300000>;
+ };
+
+ vref_ddr: vref_ddr {
+ regulator-name = "vref_ddr";
+ regulator-always-on;
+ };
+
+ bst_out: boost {
+ regulator-name = "bst_out";
+ };
+
+ vbus_otg: pwr_sw1 {
+ regulator-name = "vbus_otg";
+ regulator-active-discharge = <1>;
+ };
+
+ vbus_sw: pwr_sw2 {
+ regulator-name = "vbus_sw";
+ regulator-active-discharge = <1>;
+ };
+ };
+ };
+};
+
+&iwdg2 {
+ timeout-sec = <32>;
+ status = "okay";
+};
+
+&pwr_regulators {
+ vdd-supply = <&vdd>;
+ vdd_3v3_usbfs-supply = <&vdd_usb>;
+};
+
+&qspi {
+ pinctrl-names = "default";
+ pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a>;
+ reg = <0x58003000 0x1000>, <0x70000000 0x200000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ flash0: flash@0 {
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-rx-bus-width = <4>;
+ spi-max-frequency = <50000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+};
+
+&rcc {
+ 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 {
+ compatible = "st,stm32mp1-pll";
+ reg = <0>;
+ cfg = <2 80 0 0 0 PQR(1,0,0)>;
+ frac = <0x800>;
+ };
+
+ /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */
+ pll2: st,pll@1 {
+ compatible = "st,stm32mp1-pll";
+ reg = <1>;
+ cfg = <2 65 1 0 0 PQR(1,1,1)>;
+ frac = <0x1400>;
+ };
+
+ /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */
+ pll3: st,pll@2 {
+ compatible = "st,stm32mp1-pll";
+ reg = <2>;
+ cfg = <1 33 1 16 36 PQR(1,1,1)>;
+ frac = <0x1a04>;
+ };
+
+ /* VCO = 600.0 MHz => P = 99, Q = 74, R = 99 */
+ pll4: st,pll@3 {
+ compatible = "st,stm32mp1-pll";
+ reg = <3>;
+ cfg = <3 98 5 7 5 PQR(1,1,1)>;
+ };
+};
+
+&rng1 {
+ status = "okay";
+};
+
+&rtc {
+ status = "okay";
+};
diff --git a/fdts/stm32mp15xx-dkx.dtsi b/fdts/stm32mp15xx-dkx.dtsi
new file mode 100644
index 0000000..52d4170
--- /dev/null
+++ b/fdts/stm32mp15xx-dkx.dtsi
@@ -0,0 +1,341 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include "stm32mp15-ddr3-1x4Gb-1066-binG.dtsi"
+
+/ {
+ memory@c0000000 {
+ device_type = "memory";
+ reg = <0xc0000000 0x20000000>;
+ };
+
+ vin: vin {
+ compatible = "regulator-fixed";
+ regulator-name = "vin";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
+};
+
+&bsec {
+ board_id: board_id@ec {
+ reg = <0xec 0x4>;
+ st,non-secure-otp;
+ };
+};
+
+&clk_hse {
+ st,digbypass;
+};
+
+&cpu0 {
+ cpu-supply = <&vddcore>;
+};
+
+&cpu1 {
+ cpu-supply = <&vddcore>;
+};
+
+&hash1 {
+ status = "okay";
+};
+
+&i2c4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c4_pins_a>;
+ i2c-scl-rising-time-ns = <185>;
+ i2c-scl-falling-time-ns = <20>;
+ clock-frequency = <400000>;
+ status = "okay";
+
+ pmic: stpmic@33 {
+ compatible = "st,stpmic1";
+ reg = <0x33>;
+ interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "okay";
+
+ regulators {
+ compatible = "st,stpmic1-regulators";
+ buck1-supply = <&vin>;
+ buck2-supply = <&vin>;
+ buck3-supply = <&vin>;
+ buck4-supply = <&vin>;
+ ldo1-supply = <&v3v3>;
+ ldo2-supply = <&vin>;
+ ldo3-supply = <&vdd_ddr>;
+ ldo4-supply = <&vin>;
+ ldo5-supply = <&vin>;
+ ldo6-supply = <&v3v3>;
+ vref_ddr-supply = <&vin>;
+ boost-supply = <&vin>;
+ pwr_sw1-supply = <&bst_out>;
+ pwr_sw2-supply = <&bst_out>;
+
+ vddcore: buck1 {
+ regulator-name = "vddcore";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-initial-mode = <0>;
+ regulator-over-current-protection;
+ };
+
+ 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-always-on;
+ regulator-over-current-protection;
+ st,regulator-sink-source;
+ };
+
+ 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;
+ };
+
+ bst_out: boost {
+ regulator-name = "bst_out";
+ };
+
+ vbus_otg: pwr_sw1 {
+ regulator-name = "vbus_otg";
+ };
+
+ vbus_sw: pwr_sw2 {
+ regulator-name = "vbus_sw";
+ regulator-active-discharge = <1>;
+ };
+ };
+ };
+};
+
+&iwdg2 {
+ timeout-sec = <32>;
+ status = "okay";
+};
+
+&pwr_regulators {
+ vdd-supply = <&vdd>;
+ vdd_3v3_usbfs-supply = <&vdd_usb>;
+};
+
+&rcc {
+ 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_PLL4P
+ 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 {
+ compatible = "st,stm32mp1-pll";
+ reg = <0>;
+ cfg = < 2 80 0 0 0 PQR(1,0,0) >;
+ frac = < 0x800 >;
+ };
+
+ /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */
+ pll2: st,pll@1 {
+ compatible = "st,stm32mp1-pll";
+ reg = <1>;
+ cfg = <2 65 1 0 0 PQR(1,1,1)>;
+ frac = <0x1400>;
+ };
+
+ /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */
+ pll3: st,pll@2 {
+ compatible = "st,stm32mp1-pll";
+ reg = <2>;
+ cfg = <1 33 1 16 36 PQR(1,1,1)>;
+ frac = <0x1a04>;
+ };
+
+ /* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */
+ pll4: st,pll@3 {
+ compatible = "st,stm32mp1-pll";
+ reg = <3>;
+ cfg = <3 98 5 7 7 PQR(1,1,1)>;
+ };
+};
+
+&rng1 {
+ status = "okay";
+};
+
+&rtc {
+ status = "okay";
+};
+
+&sdmmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc1_b4_pins_a>;
+ disable-wp;
+ st,neg-edge;
+ bus-width = <4>;
+ vmmc-supply = <&v3v3>;
+ status = "okay";
+};
+
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4_pins_a>;
+ status = "okay";
+};
+
+&uart7 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart7_pins_c>;
+ status = "disabled";
+};
+
+&usart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usart3_pins_c>;
+ uart-has-rtscts;
+ status = "disabled";
+};
+
+&usbotg_hs {
+ phys = <&usbphyc_port1 0>;
+ phy-names = "usb2-phy";
+ usb-role-switch;
+ status = "okay";
+};
+
+&usbphyc {
+ status = "okay";
+};
+
+&usbphyc_port0 {
+ phy-supply = <&vdd_usb>;
+};
+
+&usbphyc_port1 {
+ phy-supply = <&vdd_usb>;
+};
diff --git a/fdts/stm32mp15xx-osd32.dtsi b/fdts/stm32mp15xx-osd32.dtsi
new file mode 100644
index 0000000..52a5d38
--- /dev/null
+++ b/fdts/stm32mp15xx-osd32.dtsi
@@ -0,0 +1,278 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause) */
+/*
+ * Copyright (C) 2020 STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2020 Ahmad Fatoum, Pengutronix
+ */
+
+#include "stm32mp15-pinctrl.dtsi"
+
+&i2c4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c4_pins_a>;
+ clock-frequency = <400000>;
+ i2c-scl-rising-time-ns = <185>;
+ i2c-scl-falling-time-ns = <20>;
+ status = "okay";
+
+ pmic: stpmic@33 {
+ compatible = "st,stpmic1";
+ reg = <0x33>;
+ interrupts-extended = <&gpioa 0 IRQ_TYPE_EDGE_FALLING>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ regulators {
+ compatible = "st,stpmic1-regulators";
+
+ ldo1-supply = <&v3v3>;
+ ldo6-supply = <&v3v3>;
+ pwr_sw1-supply = <&bst_out>;
+
+ vddcore: buck1 {
+ regulator-name = "vddcore";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-initial-mode = <0>;
+ regulator-over-current-protection;
+ };
+
+ 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-always-on;
+ regulator-over-current-protection;
+ st,regulator-sink-source;
+ };
+
+ 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;
+ };
+
+ bst_out: boost {
+ regulator-name = "bst_out";
+ };
+
+ vbus_otg: pwr_sw1 {
+ regulator-name = "vbus_otg";
+ regulator-active-discharge;
+ };
+
+ vbus_sw: pwr_sw2 {
+ regulator-name = "vbus_sw";
+ regulator-active-discharge;
+ };
+ };
+
+ pmic_watchdog: watchdog {
+ compatible = "st,stpmic1-wdt";
+ status = "disabled";
+ };
+ };
+};
+
+&rng1 {
+ status = "okay";
+};
+
+/* ATF Specific */
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+
+/ {
+ aliases {
+ gpio0 = &gpioa;
+ gpio1 = &gpiob;
+ gpio2 = &gpioc;
+ gpio3 = &gpiod;
+ gpio4 = &gpioe;
+ gpio5 = &gpiof;
+ gpio6 = &gpiog;
+ gpio7 = &gpioh;
+ gpio8 = &gpioi;
+ gpio25 = &gpioz;
+ i2c3 = &i2c4;
+ };
+};
+
+&bsec {
+ board_id: board_id@ec {
+ reg = <0xec 0x4>;
+ st,non-secure-otp;
+ };
+};
+
+&clk_hse {
+ st,digbypass;
+};
+
+&cpu0 {
+ cpu-supply = <&vddcore>;
+};
+
+&cpu1 {
+ cpu-supply = <&vddcore>;
+};
+
+&hash1 {
+ status = "okay";
+};
+
+/* CLOCK init */
+&rcc {
+ 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_PLL4P
+ 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 {
+ compatible = "st,stm32mp1-pll";
+ reg = <0>;
+ cfg = < 2 80 0 0 0 PQR(1,0,0) >;
+ frac = < 0x800 >;
+ };
+
+ /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */
+ pll2: st,pll@1 {
+ compatible = "st,stm32mp1-pll";
+ reg = <1>;
+ cfg = <2 65 1 0 0 PQR(1,1,1)>;
+ frac = <0x1400>;
+ };
+
+ /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */
+ pll3: st,pll@2 {
+ compatible = "st,stm32mp1-pll";
+ reg = <2>;
+ cfg = <1 33 1 16 36 PQR(1,1,1)>;
+ frac = <0x1a04>;
+ };
+
+ /* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */
+ pll4: st,pll@3 {
+ compatible = "st,stm32mp1-pll";
+ reg = <3>;
+ cfg = <3 98 5 7 7 PQR(1,1,1)>;
+ };
+};
diff --git a/fdts/stm32mp15xxaa-pinctrl.dtsi b/fdts/stm32mp15xxaa-pinctrl.dtsi
new file mode 100644
index 0000000..f1d540a
--- /dev/null
+++ b/fdts/stm32mp15xxaa-pinctrl.dtsi
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+&pinctrl {
+ st,package = <STM32MP_PKG_AA>;
+
+ gpioa: gpio@50002000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 0 16>;
+ };
+
+ gpiob: gpio@50003000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 16 16>;
+ };
+
+ gpioc: gpio@50004000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 32 16>;
+ };
+
+ gpiod: gpio@50005000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 48 16>;
+ };
+
+ gpioe: gpio@50006000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 64 16>;
+ };
+
+ gpiof: gpio@50007000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 80 16>;
+ };
+
+ gpiog: gpio@50008000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 96 16>;
+ };
+
+ gpioh: gpio@50009000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 112 16>;
+ };
+
+ gpioi: gpio@5000a000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 128 16>;
+ };
+
+ gpioj: gpio@5000b000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 144 16>;
+ };
+
+ gpiok: gpio@5000c000 {
+ status = "okay";
+ ngpios = <8>;
+ gpio-ranges = <&pinctrl 0 160 8>;
+ };
+};
+
+&pinctrl_z {
+ st,package = <STM32MP_PKG_AA>;
+
+ gpioz: gpio@54004000 {
+ status = "okay";
+ ngpios = <8>;
+ gpio-ranges = <&pinctrl_z 0 400 8>;
+ };
+};
diff --git a/fdts/stm32mp15xxab-pinctrl.dtsi b/fdts/stm32mp15xxab-pinctrl.dtsi
new file mode 100644
index 0000000..b58c7e2
--- /dev/null
+++ b/fdts/stm32mp15xxab-pinctrl.dtsi
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+&pinctrl {
+ st,package = <STM32MP_PKG_AB>;
+
+ gpioa: gpio@50002000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 0 16>;
+ };
+
+ gpiob: gpio@50003000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 16 16>;
+ };
+
+ gpioc: gpio@50004000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 32 16>;
+ };
+
+ gpiod: gpio@50005000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 48 16>;
+ };
+
+ gpioe: gpio@50006000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 64 16>;
+ };
+
+ gpiof: gpio@50007000 {
+ status = "okay";
+ ngpios = <6>;
+ gpio-ranges = <&pinctrl 6 86 6>;
+ };
+
+ gpiog: gpio@50008000 {
+ status = "okay";
+ ngpios = <10>;
+ gpio-ranges = <&pinctrl 6 102 10>;
+ };
+
+ gpioh: gpio@50009000 {
+ status = "okay";
+ ngpios = <2>;
+ gpio-ranges = <&pinctrl 0 112 2>;
+ };
+};
diff --git a/fdts/stm32mp15xxac-pinctrl.dtsi b/fdts/stm32mp15xxac-pinctrl.dtsi
new file mode 100644
index 0000000..11e7e03
--- /dev/null
+++ b/fdts/stm32mp15xxac-pinctrl.dtsi
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+&pinctrl {
+ st,package = <STM32MP_PKG_AC>;
+
+ gpioa: gpio@50002000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 0 16>;
+ };
+
+ gpiob: gpio@50003000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 16 16>;
+ };
+
+ gpioc: gpio@50004000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 32 16>;
+ };
+
+ gpiod: gpio@50005000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 48 16>;
+ };
+
+ gpioe: gpio@50006000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 64 16>;
+ };
+
+ gpiof: gpio@50007000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 80 16>;
+ };
+
+ gpiog: gpio@50008000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 96 16>;
+ };
+
+ gpioh: gpio@50009000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 112 16>;
+ };
+
+ gpioi: gpio@5000a000 {
+ status = "okay";
+ ngpios = <12>;
+ gpio-ranges = <&pinctrl 0 128 12>;
+ };
+};
+
+&pinctrl_z {
+ st,package = <STM32MP_PKG_AC>;
+
+ gpioz: gpio@54004000 {
+ status = "okay";
+ ngpios = <8>;
+ gpio-ranges = <&pinctrl_z 0 400 8>;
+ };
+};
diff --git a/fdts/stm32mp15xxad-pinctrl.dtsi b/fdts/stm32mp15xxad-pinctrl.dtsi
new file mode 100644
index 0000000..52806d6
--- /dev/null
+++ b/fdts/stm32mp15xxad-pinctrl.dtsi
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+&pinctrl {
+ st,package = <STM32MP_PKG_AD>;
+
+ gpioa: gpio@50002000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 0 16>;
+ };
+
+ gpiob: gpio@50003000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 16 16>;
+ };
+
+ gpioc: gpio@50004000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 32 16>;
+ };
+
+ gpiod: gpio@50005000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 48 16>;
+ };
+
+ gpioe: gpio@50006000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 64 16>;
+ };
+
+ gpiof: gpio@50007000 {
+ status = "okay";
+ ngpios = <6>;
+ gpio-ranges = <&pinctrl 6 86 6>;
+ };
+
+ gpiog: gpio@50008000 {
+ status = "okay";
+ ngpios = <10>;
+ gpio-ranges = <&pinctrl 6 102 10>;
+ };
+
+ gpioh: gpio@50009000 {
+ status = "okay";
+ ngpios = <2>;
+ gpio-ranges = <&pinctrl 0 112 2>;
+ };
+};
diff --git a/fdts/tc.dts b/fdts/tc.dts
new file mode 100644
index 0000000..5a8792e
--- /dev/null
+++ b/fdts/tc.dts
@@ -0,0 +1,567 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+ compatible = "arm,tc";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ aliases {
+ serial0 = &soc_uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&CPU0>;
+ };
+ core1 {
+ cpu = <&CPU1>;
+ };
+ core2 {
+ cpu = <&CPU2>;
+ };
+ core3 {
+ cpu = <&CPU3>;
+ };
+ core4 {
+ cpu = <&CPU4>;
+ };
+ core5 {
+ cpu = <&CPU5>;
+ };
+ core6 {
+ cpu = <&CPU6>;
+ };
+ core7 {
+ cpu = <&CPU7>;
+ };
+ };
+ };
+
+ /*
+ * The timings below are just to demonstrate working cpuidle.
+ * These values may be inaccurate.
+ */
+ idle-states {
+ entry-method = "arm,psci";
+
+ CPU_SLEEP_0: cpu-sleep-0 {
+ compatible = "arm,idle-state";
+ arm,psci-suspend-param = <0x0010000>;
+ local-timer-stop;
+ entry-latency-us = <300>;
+ exit-latency-us = <1200>;
+ min-residency-us = <2000>;
+ };
+ CLUSTER_SLEEP_0: cluster-sleep-0 {
+ compatible = "arm,idle-state";
+ arm,psci-suspend-param = <0x1010000>;
+ local-timer-stop;
+ entry-latency-us = <400>;
+ exit-latency-us = <1200>;
+ min-residency-us = <2500>;
+ };
+ };
+
+ amus {
+ amu: amu-0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mpmm_gear0: counter@0 {
+ reg = <0>;
+
+ enable-at-el3;
+ };
+
+ mpmm_gear1: counter@1 {
+ reg = <1>;
+
+ enable-at-el3;
+ };
+
+ mpmm_gear2: counter@2 {
+ reg = <2>;
+
+ enable-at-el3;
+ };
+ };
+ };
+
+ CPU0:cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0>;
+ enable-method = "psci";
+ clocks = <&scmi_dvfs 0>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ capacity-dmips-mhz = <406>;
+ amu = <&amu>;
+ supports-mpmm;
+ };
+
+ CPU1:cpu@100 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x100>;
+ enable-method = "psci";
+ clocks = <&scmi_dvfs 0>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ capacity-dmips-mhz = <406>;
+ amu = <&amu>;
+ supports-mpmm;
+ };
+
+ CPU2:cpu@200 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x200>;
+ enable-method = "psci";
+ clocks = <&scmi_dvfs 0>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ capacity-dmips-mhz = <406>;
+ amu = <&amu>;
+ supports-mpmm;
+ };
+
+ CPU3:cpu@300 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x300>;
+ enable-method = "psci";
+ clocks = <&scmi_dvfs 0>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ capacity-dmips-mhz = <406>;
+ amu = <&amu>;
+ supports-mpmm;
+ };
+
+ CPU4:cpu@400 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x400>;
+ enable-method = "psci";
+ clocks = <&scmi_dvfs 1>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ capacity-dmips-mhz = <912>;
+ amu = <&amu>;
+ supports-mpmm;
+ };
+
+ CPU5:cpu@500 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x500>;
+ enable-method = "psci";
+ clocks = <&scmi_dvfs 1>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ capacity-dmips-mhz = <912>;
+ amu = <&amu>;
+ supports-mpmm;
+ };
+
+ CPU6:cpu@600 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x600>;
+ enable-method = "psci";
+ clocks = <&scmi_dvfs 1>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ capacity-dmips-mhz = <912>;
+ amu = <&amu>;
+ supports-mpmm;
+ };
+
+ CPU7:cpu@700 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x700>;
+ enable-method = "psci";
+ clocks = <&scmi_dvfs 2>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ capacity-dmips-mhz = <1024>;
+ amu = <&amu>;
+ supports-mpmm;
+ };
+
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ linux,cma {
+ compatible = "shared-dma-pool";
+ reusable;
+ size = <0x0 0x8000000>;
+ linux,cma-default;
+ };
+
+ optee@0xfce00000 {
+ reg = <0x00000000 0xfce00000 0 0x00200000>;
+ no-map;
+ };
+ };
+
+ psci {
+ compatible = "arm,psci-1.0", "arm,psci-0.2";
+ method = "smc";
+ };
+
+ sram: sram@6000000 {
+ compatible = "mmio-sram";
+ reg = <0x0 0x06000000 0x0 0x8000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x0 0x06000000 0x8000>;
+
+ cpu_scp_scmi_mem: scp-shmem@0 {
+ compatible = "arm,scmi-shmem";
+ reg = <0x0 0x80>;
+ };
+ };
+
+ mbox_db_rx: mhu@45010000 {
+ compatible = "arm,mhuv2-rx","arm,primecell";
+ reg = <0x0 0x45010000 0x0 0x1000>;
+ clocks = <&soc_refclk100mhz>;
+ clock-names = "apb_pclk";
+ #mbox-cells = <2>;
+ interrupts = <0 317 4>;
+ interrupt-names = "mhu_rx";
+ mhu-protocol = "doorbell";
+ arm,mhuv2-protocols = <0 1>;
+ };
+
+ mbox_db_tx: mhu@45000000 {
+ compatible = "arm,mhuv2-tx","arm,primecell";
+ reg = <0x0 0x45000000 0x0 0x1000>;
+ clocks = <&soc_refclk100mhz>;
+ clock-names = "apb_pclk";
+ #mbox-cells = <2>;
+ interrupt-names = "mhu_tx";
+ mhu-protocol = "doorbell";
+ arm,mhuv2-protocols = <0 1>;
+ };
+
+ cmn-pmu {
+ compatible = "arm,ci-700";
+ reg = <0x0 0x50000000 0x0 0x10000000>;
+ interrupts = <0x0 460 0x4>;
+ };
+
+ scmi {
+ compatible = "arm,scmi";
+ mbox-names = "tx", "rx";
+ mboxes = <&mbox_db_tx 0 0 &mbox_db_rx 0 0 >;
+ shmem = <&cpu_scp_scmi_mem &cpu_scp_scmi_mem>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ scmi_dvfs: protocol@13 {
+ reg = <0x13>;
+ #clock-cells = <1>;
+ };
+
+ scmi_clk: protocol@14 {
+ reg = <0x14>;
+ #clock-cells = <1>;
+ };
+ };
+
+ gic: interrupt-controller@2c010000 {
+ compatible = "arm,gic-600", "arm,gic-v3";
+ #address-cells = <2>;
+ #interrupt-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+ interrupt-controller;
+ reg = <0x0 0x30000000 0 0x10000>, /* GICD */
+ <0x0 0x30080000 0 0x200000>; /* GICR */
+ interrupts = <0x1 0x9 0x4>;
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <0x1 13 0x8>,
+ <0x1 14 0x8>,
+ <0x1 11 0x8>,
+ <0x1 10 0x8>;
+ };
+
+ soc_refclk100mhz: refclk100mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <100000000>;
+ clock-output-names = "apb_pclk";
+ };
+
+ soc_refclk60mhz: refclk60mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <60000000>;
+ clock-output-names = "iofpga_clk";
+ };
+
+ soc_uartclk: uartclk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ clock-output-names = "uartclk";
+ };
+
+ soc_uart0: uart@7ff80000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0 0x7ff80000 0x0 0x1000>;
+ interrupts = <0x0 116 0x4>;
+ clocks = <&soc_uartclk>, <&soc_refclk100mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ status = "okay";
+ };
+
+ rtc0: rtc@1C170000 {
+ compatible = "arm,pl031", "arm,primecell";
+ reg = <0x0 0x1C170000 0x0 0x1000>;
+ interrupts = <0x0 100 0x4>;
+ clocks = <&soc_refclk100mhz>;
+ clock-names = "apb_pclk";
+ wakeup-source;
+ };
+
+ vencoder {
+ compatible = "drm,virtual-encoder";
+
+ port {
+ vencoder_in: endpoint {
+ remote-endpoint = <&dp_pl0_out0>;
+ };
+ };
+
+ display-timings {
+ panel-timing {
+ clock-frequency = <25175000>;
+ hactive = <640>;
+ vactive = <480>;
+ hfront-porch = <16>;
+ hback-porch = <48>;
+ hsync-len = <96>;
+ vfront-porch = <10>;
+ vback-porch = <33>;
+ vsync-len = <2>;
+ };
+ };
+
+ };
+
+ hdlcd: hdlcd@7ff60000 {
+ compatible = "arm,hdlcd";
+ reg = <0x0 0x7ff60000 0x0 0x1000>;
+ interrupts = <0x0 117 0x4>;
+ clocks = <&fake_hdlcd_clk>;
+ clock-names = "pxlclk";
+ status = "disabled";
+
+ port {
+ hdlcd_out: endpoint {
+ remote-endpoint = <&vencoder_in>;
+ };
+ };
+ };
+
+ fake_hdlcd_clk: fake-hdlcd-clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <25175000>;
+ clock-output-names = "pxlclk";
+ };
+
+ ethernet@18000000 {
+ compatible = "smsc,lan91c111";
+ reg = <0x0 0x18000000 0x0 0x10000>;
+ interrupts = <0 109 4>;
+ };
+
+ kmi@1c060000 {
+ compatible = "arm,pl050", "arm,primecell";
+ reg = <0x0 0x001c060000 0x0 0x1000>;
+ interrupts = <0 197 4>;
+ clocks = <&bp_clock24mhz>, <&bp_clock24mhz>;
+ clock-names = "KMIREFCLK", "apb_pclk";
+ };
+
+ kmi@1c070000 {
+ compatible = "arm,pl050", "arm,primecell";
+ reg = <0x0 0x001c070000 0x0 0x1000>;
+ interrupts = <0 103 4>;
+ clocks = <&bp_clock24mhz>, <&bp_clock24mhz>;
+ clock-names = "KMIREFCLK", "apb_pclk";
+ };
+
+ bp_clock24mhz: clock24mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24000000>;
+ clock-output-names = "bp:clock24mhz";
+ };
+
+ virtio_block@1c130000 {
+ compatible = "virtio,mmio";
+ reg = <0x0 0x1c130000 0x0 0x200>;
+ interrupts = <0 204 4>;
+ };
+
+ sysreg: sysreg@1c010000 {
+ compatible = "arm,vexpress-sysreg";
+ reg = <0x0 0x001c010000 0x0 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ fixed_3v3: v2m-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ mmci@1c050000 {
+ compatible = "arm,pl180", "arm,primecell";
+ reg = <0x0 0x001c050000 0x0 0x1000>;
+ interrupts = <0 107 0x4>,
+ <0 108 0x4>;
+ cd-gpios = <&sysreg 0 0>;
+ wp-gpios = <&sysreg 1 0>;
+ bus-width = <8>;
+ max-frequency = <12000000>;
+ vmmc-supply = <&fixed_3v3>;
+ clocks = <&bp_clock24mhz>, <&bp_clock24mhz>;
+ clock-names = "mclk", "apb_pclk";
+ };
+
+ gpu: gpu@2d000000 {
+ compatible = "arm,mali-midgard";
+ reg = <0x0 0x2d000000 0x0 0x200000>;
+ interrupts = <0 66 4>, <0 67 4>, <0 65 4>;
+ interrupt-names = "JOB", "MMU", "GPU";
+ clocks = <&soc_refclk100mhz>;
+ clock-names = "clk_mali";
+ operating-points = <
+ /* KHz uV */
+ 50000 820000
+ >;
+ };
+
+ smmu: smmu@2ce00000 {
+ #iommu-cells = <1>;
+ compatible = "arm,smmu-v3";
+ reg = <0x0 0x2ce00000 0x0 0x20000>;
+ status = "okay";
+ };
+
+ dp0: display@2cc00000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "arm,mali-d71";
+ reg = <0 0x2cc00000 0 0x20000>;
+ interrupts = <0 69 4>;
+ interrupt-names = "DPU";
+ clocks = <&scmi_clk 0>;
+ clock-names = "aclk";
+ iommus = <&smmu 0>, <&smmu 1>, <&smmu 2>, <&smmu 3>,
+ <&smmu 4>, <&smmu 5>, <&smmu 6>, <&smmu 7>,
+ <&smmu 8>, <&smmu 9>;
+ pl0: pipeline@0 {
+ reg = <0>;
+ clocks = <&scmi_clk 1>;
+ clock-names = "pxclk";
+ pl_id = <0>;
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 {
+ reg = <0>;
+ dp_pl0_out0: endpoint {
+ remote-endpoint = <&vencoder_in>;
+ };
+ };
+ };
+ };
+
+ pl1: pipeline@1 {
+ reg = <1>;
+ clocks = <&scmi_clk 2>;
+ clock-names = "pxclk";
+ pl_id = <1>;
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 {
+ reg = <0>;
+ };
+ };
+ };
+ };
+
+ ete0 {
+ compatible = "arm,embedded-trace-extension";
+ cpu = <&CPU0>;
+ };
+
+ ete1 {
+ compatible = "arm,embedded-trace-extension";
+ cpu = <&CPU1>;
+ };
+
+ ete2 {
+ compatible = "arm,embedded-trace-extension";
+ cpu = <&CPU2>;
+ };
+
+ ete3 {
+ compatible = "arm,embedded-trace-extension";
+ cpu = <&CPU3>;
+ };
+
+ ete4 {
+ compatible = "arm,embedded-trace-extension";
+ cpu = <&CPU4>;
+ };
+
+ ete5 {
+ compatible = "arm,embedded-trace-extension";
+ cpu = <&CPU5>;
+ };
+
+ ete6 {
+ compatible = "arm,embedded-trace-extension";
+ cpu = <&CPU6>;
+ };
+
+ ete7 {
+ compatible = "arm,embedded-trace-extension";
+ cpu = <&CPU7>;
+ };
+
+ trbe0 {
+ compatible = "arm,trace-buffer-extension";
+ interrupts = <1 2 4>;
+ };
+};
diff --git a/include/arch/aarch32/arch.h b/include/arch/aarch32/arch.h
new file mode 100644
index 0000000..8678bf3
--- /dev/null
+++ b/include/arch/aarch32/arch.h
@@ -0,0 +1,784 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARCH_H
+#define ARCH_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * 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_DFR0_EL1 definitions */
+#define ID_DFR0_COPTRC_SHIFT U(12)
+#define ID_DFR0_COPTRC_MASK U(0xf)
+#define ID_DFR0_COPTRC_SUPPORTED U(1)
+#define ID_DFR0_COPTRC_LENGTH U(4)
+#define ID_DFR0_TRACEFILT_SHIFT U(28)
+#define ID_DFR0_TRACEFILT_MASK U(0xf)
+#define ID_DFR0_TRACEFILT_SUPPORTED U(1)
+#define ID_DFR0_TRACEFILT_LENGTH U(4)
+
+/* ID_DFR1_EL1 definitions */
+#define ID_DFR1_MTPMU_SHIFT U(0)
+#define ID_DFR1_MTPMU_MASK U(0xf)
+#define ID_DFR1_MTPMU_SUPPORTED 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)
+
+#define ID_MMFR4_CCIDX_SHIFT U(24)
+#define ID_MMFR4_CCIDX_LENGTH U(4)
+#define ID_MMFR4_CCIDX_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_AMU_NOT_SUPPORTED U(0x0)
+#define ID_PFR0_AMU_V1 U(0x1)
+#define ID_PFR0_AMU_V1P1 U(0x2)
+
+#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)
+#define ID_PFR1_SEC_SHIFT U(4)
+#define ID_PFR1_SEC_MASK U(0xf)
+#define ID_PFR1_ELx_ENABLED U(1)
+
+/* 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_TTRF_BIT (U(1) << 19)
+#define SDCR_SPME_BIT (U(1) << 17)
+#define SDCR_RESET_VAL U(0x0)
+#define SDCR_MTPME_BIT (U(1) << 28)
+
+/* 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 UL(0x1)
+#define CPACR_FP_TRAP_ALL UL(0x2)
+#define CPACR_FP_TRAP_NONE UL(0x3)
+
+/* SCR definitions */
+#define SCR_TWE_BIT (UL(1) << 13)
+#define SCR_TWI_BIT (UL(1) << 12)
+#define SCR_SIF_BIT (UL(1) << 9)
+#define SCR_HCE_BIT (UL(1) << 8)
+#define SCR_SCD_BIT (UL(1) << 7)
+#define SCR_NET_BIT (UL(1) << 6)
+#define SCR_AW_BIT (UL(1) << 5)
+#define SCR_FW_BIT (UL(1) << 4)
+#define SCR_EA_BIT (UL(1) << 3)
+#define SCR_FIQ_BIT (UL(1) << 2)
+#define SCR_IRQ_BIT (UL(1) << 1)
+#define SCR_NS_BIT (UL(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_SHIFT U(30)
+#define TAM_BIT (U(1) << TAM_SHIFT)
+#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_MTPME_BIT (U(1) << 28)
+#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_DFR0 p15, 0, c0, c1, 2
+#define ID_DFR1 p15, 0, c0, c3, 5
+#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 CCSIDR2 p15, 1, c0, c0, 2
+#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
+
+/* Fault registers. The format is: coproc, opt1, CRn, CRm, opt2 */
+#define DFSR p15, 0, c5, c0, 0
+#define IFSR p15, 0, c5, c0, 1
+#define DFAR p15, 0, c6, c0, 0
+#define IFAR p15, 0, c6, c0, 2
+
+/*******************************************************************************
+ * Definitions of MAIR encodings for device and normal memory
+ ******************************************************************************/
+/*
+ * 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 FEAT_AMUv1
+ ******************************************************************************/
+#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
+
+/* AMCNTENSET0 definitions */
+#define AMCNTENSET0_Pn_SHIFT U(0)
+#define AMCNTENSET0_Pn_MASK U(0xffff)
+
+/* AMCNTENSET1 definitions */
+#define AMCNTENSET1_Pn_SHIFT U(0)
+#define AMCNTENSET1_Pn_MASK U(0xffff)
+
+/* AMCNTENCLR0 definitions */
+#define AMCNTENCLR0_Pn_SHIFT U(0)
+#define AMCNTENCLR0_Pn_MASK U(0xffff)
+
+/* AMCNTENCLR1 definitions */
+#define AMCNTENCLR1_Pn_SHIFT U(0)
+#define AMCNTENCLR1_Pn_MASK U(0xffff)
+
+/* AMCR definitions */
+#define AMCR_CG1RZ_SHIFT U(17)
+#define AMCR_CG1RZ_BIT (ULL(1) << AMCR_CG1RZ_SHIFT)
+
+/* AMCFGR definitions */
+#define AMCFGR_NCG_SHIFT U(28)
+#define AMCFGR_NCG_MASK U(0xf)
+#define AMCFGR_N_SHIFT U(0)
+#define AMCFGR_N_MASK U(0xff)
+
+/* AMCGCR definitions */
+#define AMCGCR_CG0NC_SHIFT U(0)
+#define AMCGCR_CG0NC_MASK U(0xff)
+#define AMCGCR_CG1NC_SHIFT U(8)
+#define AMCGCR_CG1NC_MASK U(0xff)
+
+/*******************************************************************************
+ * Definitions for DynamicIQ Shared Unit registers
+ ******************************************************************************/
+#define CLUSTERPWRDN p15, 0, c15, c3, 6
+
+/* CLUSTERPWRDN register definitions */
+#define DSU_CLUSTER_PWR_OFF 0
+#define DSU_CLUSTER_PWR_ON 1
+#define DSU_CLUSTER_PWR_MASK U(1)
+
+#endif /* ARCH_H */
diff --git a/include/arch/aarch32/arch_features.h b/include/arch/aarch32/arch_features.h
new file mode 100644
index 0000000..ddf0968
--- /dev/null
+++ b/include/arch/aarch32/arch_features.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARCH_FEATURES_H
+#define ARCH_FEATURES_H
+
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+
+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 */
diff --git a/include/arch/aarch32/arch_helpers.h b/include/arch/aarch32/arch_helpers.h
new file mode 100644
index 0000000..95d056f
--- /dev/null
+++ b/include/arch/aarch32/arch_helpers.h
@@ -0,0 +1,474 @@
+/*
+ * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
+ * Portions copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARCH_HELPERS_H
+#define ARCH_HELPERS_H
+
+#include <cdefs.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch.h>
+
+/**********************************************************************
+ * 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 : : : "memory"); \
+}
+
+/* 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);
+bool is_dcache_enabled(void);
+
+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_dfr0, ID_DFR0)
+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_WRITE_FUNC_64(icc_asgi1r, ICC_ASGI1R_EL1_64)
+
+DEFINE_COPROCR_RW_FUNCS(sdcr, SDCR)
+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)
+
+/* Coproc registers for 32bit AMU support */
+DEFINE_COPROCR_READ_FUNC(amcfgr, AMCFGR)
+DEFINE_COPROCR_READ_FUNC(amcgcr, AMCGCR)
+DEFINE_COPROCR_RW_FUNCS(amcr, AMCR)
+
+DEFINE_COPROCR_RW_FUNCS(amcntenset0, AMCNTENSET0)
+DEFINE_COPROCR_RW_FUNCS(amcntenset1, AMCNTENSET1)
+DEFINE_COPROCR_RW_FUNCS(amcntenclr0, AMCNTENCLR0)
+DEFINE_COPROCR_RW_FUNCS(amcntenclr1, AMCNTENCLR1)
+
+/* Coproc registers for 64bit AMU support */
+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
+
+/*
+ * DynamIQ Shared Unit power management
+ */
+DEFINE_COPROCR_RW_FUNCS(clusterpwrdn, CLUSTERPWRDN)
+
+/* 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 write_icc_sgi1r(_v) write64_icc_sgi1r(_v)
+#define write_icc_asgi1r(_v) write64_icc_asgi1r(_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 */
diff --git a/include/arch/aarch32/asm_macros.S b/include/arch/aarch32/asm_macros.S
new file mode 100644
index 0000000..483f9fe
--- /dev/null
+++ b/include/arch/aarch32/asm_macros.S
@@ -0,0 +1,237 @@
+/*
+ * 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 <arch.h>
+#include <common/asm_macros_common.S>
+#include <lib/spinlock.h>
+
+/*
+ * 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)
+ /*
+ * Macro for mitigating against speculative execution.
+ * ARMv7 cores without Virtualization extension do not support the
+ * eret instruction.
+ */
+ .macro exception_return
+ movs pc, lr
+ dsb nsh
+ isb
+ .endm
+
+#else
+ /*
+ * Macro for mitigating against speculative execution beyond ERET. Uses the
+ * speculation barrier instruction introduced by FEAT_SB, if it's enabled.
+ */
+ .macro exception_return
+ eret
+#if ENABLE_FEAT_SB
+ sb
+#else
+ dsb nsh
+ isb
+#endif
+ .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 */
diff --git a/include/arch/aarch32/assert_macros.S b/include/arch/aarch32/assert_macros.S
new file mode 100644
index 0000000..ab3a2eb
--- /dev/null
+++ b/include/arch/aarch32/assert_macros.S
@@ -0,0 +1,26 @@
+/*
+ * 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 */
diff --git a/include/arch/aarch32/console_macros.S b/include/arch/aarch32/console_macros.S
new file mode 100644
index 0000000..996cb32
--- /dev/null
+++ b/include/arch/aarch32/console_macros.S
@@ -0,0 +1,51 @@
+/*
+ * 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 <drivers/console.h>
+
+/*
+ * This macro encapsulates the common setup that has to be done at the end of
+ * a console driver's register function. It will register all of the driver's
+ * callbacks in the console_t structure and initialize the flags field (by
+ * default consoles are enabled for the "boot" and "crash" states, this can be
+ * changed after registration with the console_set_scope() function). It ends
+ * with a tail call that will include return to the caller.
+ * REQUIRES console_t pointer in 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 */
diff --git a/include/arch/aarch32/el3_common_macros.S b/include/arch/aarch32/el3_common_macros.S
new file mode 100644
index 0000000..8b6765a
--- /dev/null
+++ b/include/arch/aarch32/el3_common_macros.S
@@ -0,0 +1,458 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EL3_COMMON_MACROS_S
+#define EL3_COMMON_MACROS_S
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#define PAGE_START_MASK ~(PAGE_SIZE_MASK)
+
+ /*
+ * 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.
+ *
+ * NSACR.NSTRCDIS: When system register trace implemented, Set to one
+ * so that NS System register accesses to all implemented trace
+ * registers are disabled.
+ * When system register trace is not implemented, this bit is RES0 and
+ * hence set to zero.
+ * ---------------------------------------------------------------------
+ */
+ ldcopr r0, NSACR
+ and r0, r0, #NSACR_IMP_DEF_MASK
+ orr r0, r0, #(NSACR_RESET_VAL | NSACR_ENABLE_FP_ACCESS)
+ ldcopr r1, ID_DFR0
+ ubfx r1, r1, #ID_DFR0_COPTRC_SHIFT, #ID_DFR0_COPTRC_LENGTH
+ cmp r1, #ID_DFR0_COPTRC_SUPPORTED
+ bne 1f
+ orr r0, r0, #NSTRCDIS_BIT
+1:
+ 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.
+ *
+ * SDCR.TTRF: Set to one so that access to trace filter control
+ * registers in non-monitor mode generate Monitor trap exception,
+ * unless the access generates a higher priority exception when
+ * trace filter control(FEAT_TRF) is implemented.
+ * When FEAT_TRF is not implemented, this bit is RES0.
+ * ---------------------------------------------------------------------
+ */
+ ldr r0, =((SDCR_RESET_VAL | SDCR_SPD(SDCR_SPD_DISABLE) | \
+ SDCR_SCCD_BIT) & ~SDCR_TTRF_BIT)
+ ldcopr r1, ID_DFR0
+ ubfx r1, r1, #ID_DFR0_TRACEFILT_SHIFT, #ID_DFR0_TRACEFILT_LENGTH
+ cmp r1, #ID_DFR0_TRACEFILT_SUPPORTED
+ bne 1f
+ orr r0, r0, #SDCR_TTRF_BIT
+1:
+ 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<n>[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.
+ *
+ * _pie_fixup_size:
+ * Size of memory region to fixup Global Descriptor Table (GDT).
+ *
+ * A non-zero value is expected when firmware needs GDT to be fixed-up.
+ *
+ * -----------------------------------------------------------------------------
+ */
+ .macro el3_entrypoint_common \
+ _init_sctlr, _warm_boot_mailbox, _secondary_cold_boot, \
+ _init_memory, _init_c_runtime, _exception_vectors, \
+ _pie_fixup_size
+
+ /* 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 DISABLE_MTPMU
+ bl mtpmu_disable
+#endif
+
+ .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 */
+
+ .if \_pie_fixup_size
+#if ENABLE_PIE
+ /*
+ * ------------------------------------------------------------
+ * If PIE is enabled fixup the Global descriptor Table only
+ * once during primary core cold boot path.
+ *
+ * Compile time base address, required for fixup, is calculated
+ * using "pie_fixup" label present within first page.
+ * ------------------------------------------------------------
+ */
+ pie_fixup:
+ ldr r0, =pie_fixup
+ ldr r1, =PAGE_START_MASK
+ and r0, r0, r1
+ mov_imm r1, \_pie_fixup_size
+ add r1, r1, r0
+ bl fixup_gdt_reloc
+#endif /* ENABLE_PIE */
+ .endif /* _pie_fixup_size */
+
+ /* ---------------------------------------------------------------------
+ * 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. If PIE is enabled however,
+ * RO sections including the GOT may be modified during
+ * pie fixup. Therefore, to be on the safe side, invalidate
+ * the entire image region if PIE is enabled.
+ * -----------------------------------------------------------------
+ */
+#if ENABLE_PIE
+#if SEPARATE_CODE_AND_RODATA
+ ldr r0, =__TEXT_START__
+#else
+ ldr r0, =__RO_START__
+#endif /* SEPARATE_CODE_AND_RODATA */
+#else
+ ldr r0, =__RW_START__
+#endif /* ENABLE_PIE */
+ ldr r1, =__RW_END__
+ sub r1, r1, r0
+ bl inv_dcache_range
+#if defined(IMAGE_BL2) && SEPARATE_BL2_NOLOAD_REGION
+ ldr r0, =__BL2_NOLOAD_START__
+ ldr r1, =__BL2_NOLOAD_END__
+ sub r1, r1, r0
+ bl inv_dcache_range
+#endif
+#endif
+
+ /*
+ * zeromem uses r12 whereas it is used to save previous BL arg3,
+ * save it in r7
+ */
+ mov r7, r12
+ ldr r0, =__BSS_START__
+ ldr r1, =__BSS_END__
+ sub r1, r1, r0
+ bl zeromem
+
+#if USE_COHERENT_MEM
+ ldr r0, =__COHERENT_RAM_START__
+ ldr r1, =__COHERENT_RAM_END_UNALIGNED__
+ sub r1, r1, r0
+ bl zeromem
+#endif
+
+ /* Restore r12 */
+ mov r12, r7
+
+#if defined(IMAGE_BL1) || (defined(IMAGE_BL2) && BL2_AT_EL3 && BL2_IN_XIP_MEM)
+ /* -----------------------------------------------------
+ * Copy data from ROM to RAM.
+ * -----------------------------------------------------
+ */
+ ldr r0, =__DATA_RAM_START__
+ ldr r1, =__DATA_ROM_START__
+ ldr r2, =__DATA_RAM_END__
+ sub r2, r2, r0
+ 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 */
diff --git a/include/arch/aarch32/smccc_helpers.h b/include/arch/aarch32/smccc_helpers.h
new file mode 100644
index 0000000..2ce7874
--- /dev/null
+++ b/include/arch/aarch32/smccc_helpers.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SMCCC_HELPERS_H
+#define SMCCC_HELPERS_H
+
+#include <lib/smccc.h>
+
+/* 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 <stdint.h>
+
+#include <lib/cassert.h>
+
+/*
+ * 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)); \
+}
+#define SMC_RET5(_h, _r0, _r1, _r2, _r3, _r4) { \
+ ((smc_ctx_t *)(_h))->r4 = (_r4); \
+ SMC_RET4(_h, (_r0), (_r1), (_r2), (_r3)); \
+}
+#define SMC_RET6(_h, _r0, _r1, _r2, _r3, _r4, _r5) { \
+ ((smc_ctx_t *)(_h))->r5 = (_r5); \
+ SMC_RET5(_h, (_r0), (_r1), (_r2), (_r3), (_r4)); \
+}
+#define SMC_RET7(_h, _r0, _r1, _r2, _r3, _r4, _r5, _r6) { \
+ ((smc_ctx_t *)(_h))->r6 = (_r6); \
+ SMC_RET6(_h, (_r0), (_r1), (_r2), (_r3), (_r4), (_r5)); \
+}
+#define SMC_RET8(_h, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7) { \
+ ((smc_ctx_t *)(_h))->r7 = (_r7); \
+ SMC_RET7(_h, (_r0), (_r1), (_r2), (_r3), (_r4), (_r5), (_r6)); \
+}
+
+/*
+ * 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 */
diff --git a/include/arch/aarch32/smccc_macros.S b/include/arch/aarch32/smccc_macros.S
new file mode 100644
index 0000000..ea7835a
--- /dev/null
+++ b/include/arch/aarch32/smccc_macros.S
@@ -0,0 +1,241 @@
+/*
+ * 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 <arch.h>
+
+/*
+ * 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}
+ exception_return
+ .endm
+
+#endif /* SMCCC_MACROS_S */
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
new file mode 100644
index 0000000..f63e923
--- /dev/null
+++ b/include/arch/aarch64/arch.h
@@ -0,0 +1,1316 @@
+/*
+ * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARCH_H
+#define ARCH_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * 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_ASGI1R S3_0_C12_C11_6
+#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
+
+/*******************************************************************************
+ * Definitions for EL2 system registers for save/restore routine
+ ******************************************************************************/
+#define CNTPOFF_EL2 S3_4_C14_C0_6
+#define HAFGRTR_EL2 S3_4_C3_C1_6
+#define HDFGRTR_EL2 S3_4_C3_C1_4
+#define HDFGWTR_EL2 S3_4_C3_C1_5
+#define HFGITR_EL2 S3_4_C1_C1_6
+#define HFGRTR_EL2 S3_4_C1_C1_4
+#define HFGWTR_EL2 S3_4_C1_C1_5
+#define ICH_HCR_EL2 S3_4_C12_C11_0
+#define ICH_VMCR_EL2 S3_4_C12_C11_7
+#define MPAMVPM0_EL2 S3_4_C10_C6_0
+#define MPAMVPM1_EL2 S3_4_C10_C6_1
+#define MPAMVPM2_EL2 S3_4_C10_C6_2
+#define MPAMVPM3_EL2 S3_4_C10_C6_3
+#define MPAMVPM4_EL2 S3_4_C10_C6_4
+#define MPAMVPM5_EL2 S3_4_C10_C6_5
+#define MPAMVPM6_EL2 S3_4_C10_C6_6
+#define MPAMVPM7_EL2 S3_4_C10_C6_7
+#define MPAMVPMV_EL2 S3_4_C10_C4_1
+#define TRFCR_EL2 S3_4_C1_C2_1
+#define PMSCR_EL2 S3_4_C9_C9_0
+#define TFSR_EL2 S3_4_C5_C6_0
+
+/*******************************************************************************
+ * 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_AMU_NOT_SUPPORTED U(0x0)
+#define ID_AA64PFR0_AMU_V1 ULL(0x1)
+#define ID_AA64PFR0_AMU_V1P1 U(0x2)
+
+#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_SVE_SUPPORTED ULL(0x1)
+#define ID_AA64PFR0_SVE_LENGTH U(4)
+
+#define ID_AA64PFR0_SEL2_SHIFT U(36)
+#define ID_AA64PFR0_SEL2_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)
+#define ID_AA64PFR0_CSV2_2_SUPPORTED ULL(0x2)
+
+#define ID_AA64PFR0_FEAT_RME_SHIFT U(52)
+#define ID_AA64PFR0_FEAT_RME_MASK ULL(0xf)
+#define ID_AA64PFR0_FEAT_RME_LENGTH U(4)
+#define ID_AA64PFR0_FEAT_RME_NOT_SUPPORTED U(0)
+#define ID_AA64PFR0_FEAT_RME_V1 U(1)
+
+#define ID_AA64PFR0_RAS_SHIFT U(28)
+#define ID_AA64PFR0_RAS_MASK ULL(0xf)
+#define ID_AA64PFR0_RAS_NOT_SUPPORTED ULL(0x0)
+#define ID_AA64PFR0_RAS_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.TraceVer definitions */
+#define ID_AA64DFR0_TRACEVER_SHIFT U(4)
+#define ID_AA64DFR0_TRACEVER_MASK ULL(0xf)
+#define ID_AA64DFR0_TRACEVER_SUPPORTED ULL(1)
+#define ID_AA64DFR0_TRACEVER_LENGTH U(4)
+#define ID_AA64DFR0_TRACEFILT_SHIFT U(40)
+#define ID_AA64DFR0_TRACEFILT_MASK U(0xf)
+#define ID_AA64DFR0_TRACEFILT_SUPPORTED U(1)
+#define ID_AA64DFR0_TRACEFILT_LENGTH U(4)
+
+/* ID_AA64DFR0_EL1.PMS definitions (for ARMv8.2+) */
+#define ID_AA64DFR0_PMS_SHIFT U(32)
+#define ID_AA64DFR0_PMS_MASK ULL(0xf)
+#define ID_AA64DFR0_SPE_SUPPORTED ULL(0x1)
+#define ID_AA64DFR0_SPE_NOT_SUPPORTED ULL(0x0)
+
+/* ID_AA64DFR0_EL1.TraceBuffer definitions */
+#define ID_AA64DFR0_TRACEBUFFER_SHIFT U(44)
+#define ID_AA64DFR0_TRACEBUFFER_MASK ULL(0xf)
+#define ID_AA64DFR0_TRACEBUFFER_SUPPORTED ULL(1)
+
+/* ID_AA64DFR0_EL1.MTPMU definitions (for ARMv8.6+) */
+#define ID_AA64DFR0_MTPMU_SHIFT U(48)
+#define ID_AA64DFR0_MTPMU_MASK ULL(0xf)
+#define ID_AA64DFR0_MTPMU_SUPPORTED ULL(1)
+
+/* ID_AA64DFR0_EL1.BRBE definitions */
+#define ID_AA64DFR0_BRBE_SHIFT U(52)
+#define ID_AA64DFR0_BRBE_MASK ULL(0xf)
+#define ID_AA64DFR0_BRBE_SUPPORTED ULL(1)
+
+/* ID_AA64ISAR0_EL1 definitions */
+#define ID_AA64ISAR0_RNDR_SHIFT U(60)
+#define ID_AA64ISAR0_RNDR_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)
+
+#define ID_AA64ISAR1_SB_SHIFT U(36)
+#define ID_AA64ISAR1_SB_MASK ULL(0xf)
+#define ID_AA64ISAR1_SB_SUPPORTED ULL(0x1)
+#define ID_AA64ISAR1_SB_NOT_SUPPORTED ULL(0x0)
+
+/* ID_AA64ISAR2_EL1 definitions */
+#define ID_AA64ISAR2_EL1 S3_0_C0_C6_2
+
+#define ID_AA64ISAR2_GPA3_SHIFT U(8)
+#define ID_AA64ISAR2_GPA3_MASK ULL(0xf)
+
+#define ID_AA64ISAR2_APA3_SHIFT U(12)
+#define ID_AA64ISAR2_APA3_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_ECV_SHIFT U(60)
+#define ID_AA64MMFR0_EL1_ECV_MASK ULL(0xf)
+#define ID_AA64MMFR0_EL1_ECV_NOT_SUPPORTED ULL(0x0)
+#define ID_AA64MMFR0_EL1_ECV_SUPPORTED ULL(0x1)
+#define ID_AA64MMFR0_EL1_ECV_SELF_SYNCH ULL(0x2)
+
+#define ID_AA64MMFR0_EL1_FGT_SHIFT U(56)
+#define ID_AA64MMFR0_EL1_FGT_MASK ULL(0xf)
+#define ID_AA64MMFR0_EL1_FGT_SUPPORTED ULL(0x1)
+#define ID_AA64MMFR0_EL1_FGT_NOT_SUPPORTED ULL(0x0)
+
+#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_AA64MMFR1_EL1 definitions */
+#define ID_AA64MMFR1_EL1_TWED_SHIFT U(32)
+#define ID_AA64MMFR1_EL1_TWED_MASK ULL(0xf)
+#define ID_AA64MMFR1_EL1_TWED_SUPPORTED ULL(0x1)
+#define ID_AA64MMFR1_EL1_TWED_NOT_SUPPORTED ULL(0x0)
+
+#define ID_AA64MMFR1_EL1_PAN_SHIFT U(20)
+#define ID_AA64MMFR1_EL1_PAN_MASK ULL(0xf)
+#define ID_AA64MMFR1_EL1_PAN_NOT_SUPPORTED ULL(0x0)
+#define ID_AA64MMFR1_EL1_PAN_SUPPORTED ULL(0x1)
+#define ID_AA64MMFR1_EL1_PAN2_SUPPORTED ULL(0x2)
+#define ID_AA64MMFR1_EL1_PAN3_SUPPORTED ULL(0x3)
+
+#define ID_AA64MMFR1_EL1_VHE_SHIFT U(8)
+#define ID_AA64MMFR1_EL1_VHE_MASK ULL(0xf)
+
+#define ID_AA64MMFR1_EL1_HCX_SHIFT U(40)
+#define ID_AA64MMFR1_EL1_HCX_MASK ULL(0xf)
+#define ID_AA64MMFR1_EL1_HCX_SUPPORTED ULL(0x1)
+#define ID_AA64MMFR1_EL1_HCX_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_CCIDX_SHIFT U(20)
+#define ID_AA64MMFR2_EL1_CCIDX_MASK ULL(0xf)
+#define ID_AA64MMFR2_EL1_CCIDX_LENGTH U(4)
+
+#define ID_AA64MMFR2_EL1_CNP_SHIFT U(0)
+#define ID_AA64MMFR2_EL1_CNP_MASK ULL(0xf)
+
+#define ID_AA64MMFR2_EL1_NV_SHIFT U(24)
+#define ID_AA64MMFR2_EL1_NV_MASK ULL(0xf)
+#define ID_AA64MMFR2_EL1_NV_NOT_SUPPORTED ULL(0x0)
+#define ID_AA64MMFR2_EL1_NV_SUPPORTED ULL(0x1)
+#define ID_AA64MMFR2_EL1_NV2_SUPPORTED ULL(0x2)
+
+/* 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 ID_AA64PFR1_EL1_RNDR_TRAP_SHIFT U(28)
+#define ID_AA64PFR1_EL1_RNDR_TRAP_MASK U(0xf)
+
+#define ID_AA64PFR1_EL1_RNG_TRAP_SUPPORTED ULL(0x1)
+#define ID_AA64PFR1_EL1_RNG_TRAP_NOT_SUPPORTED ULL(0x0)
+
+/* Memory Tagging Extension is not implemented */
+#define MTE_UNIMPLEMENTED U(0)
+/* FEAT_MTE: MTE instructions accessible at EL0 are implemented */
+#define MTE_IMPLEMENTED_EL0 U(1)
+/* FEAT_MTE2: Full MTE is implemented */
+#define MTE_IMPLEMENTED_ELX U(2)
+/*
+ * FEAT_MTE3: MTE is implemented with support for
+ * asymmetric Tag Check Fault handling
+ */
+#define MTE_IMPLEMENTED_ASY U(3)
+
+#define ID_AA64PFR1_MPAM_FRAC_SHIFT ULL(16)
+#define ID_AA64PFR1_MPAM_FRAC_MASK ULL(0xf)
+
+#define ID_AA64PFR1_EL1_SME_SHIFT U(24)
+#define ID_AA64PFR1_EL1_SME_MASK ULL(0xf)
+
+/* 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 ((UL(1) << 29) | (UL(1) << 28) | (UL(1) << 23) | \
+ (UL(1) << 22) | (UL(1) << 20) | (UL(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_nAA_BIT (ULL(1) << 6)
+#define SCTLR_ITD_BIT (ULL(1) << 7)
+#define SCTLR_SED_BIT (ULL(1) << 8)
+#define SCTLR_UMA_BIT (ULL(1) << 9)
+#define SCTLR_EnRCTX_BIT (ULL(1) << 10)
+#define SCTLR_EOS_BIT (ULL(1) << 11)
+#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_TSCXT_BIT (ULL(1) << 20)
+#define SCTLR_IESB_BIT (ULL(1) << 21)
+#define SCTLR_EIS_BIT (ULL(1) << 22)
+#define SCTLR_SPAN_BIT (ULL(1) << 23)
+#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_nTLSMD_BIT (ULL(1) << 28)
+#define SCTLR_LSMAOE_BIT (ULL(1) << 29)
+#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_ITFSB_BIT (ULL(1) << 37)
+#define SCTLR_TCF0_SHIFT U(38)
+#define SCTLR_TCF0_MASK ULL(3)
+#define SCTLR_ENTP2_BIT (ULL(1) << 60)
+
+/* Tag Check Faults in EL0 have no effect on the PE */
+#define SCTLR_TCF0_NO_EFFECT U(0)
+/* Tag Check Faults in EL0 cause a synchronous exception */
+#define SCTLR_TCF0_SYNC U(1)
+/* Tag Check Faults in EL0 are asynchronously accumulated */
+#define SCTLR_TCF0_ASYNC U(2)
+/*
+ * Tag Check Faults in EL0 cause a synchronous exception on reads,
+ * and are asynchronously accumulated on writes
+ */
+#define SCTLR_TCF0_SYNCR_ASYNCW U(3)
+
+#define SCTLR_TCF_SHIFT U(40)
+#define SCTLR_TCF_MASK ULL(3)
+
+/* Tag Check Faults in EL1 have no effect on the PE */
+#define SCTLR_TCF_NO_EFFECT U(0)
+/* Tag Check Faults in EL1 cause a synchronous exception */
+#define SCTLR_TCF_SYNC U(1)
+/* Tag Check Faults in EL1 are asynchronously accumulated */
+#define SCTLR_TCF_ASYNC U(2)
+/*
+ * Tag Check Faults in EL1 cause a synchronous exception on reads,
+ * and are asynchronously accumulated on writes
+ */
+#define SCTLR_TCF_SYNCR_ASYNCW U(3)
+
+#define SCTLR_ATA0_BIT (ULL(1) << 42)
+#define SCTLR_ATA_BIT (ULL(1) << 43)
+#define SCTLR_DSSBS_SHIFT U(44)
+#define SCTLR_DSSBS_BIT (ULL(1) << SCTLR_DSSBS_SHIFT)
+#define SCTLR_TWEDEn_BIT (ULL(1) << 45)
+#define SCTLR_TWEDEL_SHIFT U(46)
+#define SCTLR_TWEDEL_MASK ULL(0xf)
+#define SCTLR_EnASR_BIT (ULL(1) << 54)
+#define SCTLR_EnAS0_BIT (ULL(1) << 55)
+#define SCTLR_EnALS_BIT (ULL(1) << 56)
+#define SCTLR_EPAN_BIT (ULL(1) << 57)
+#define SCTLR_RESET_VAL SCTLR_EL3_RES1
+
+/* CPACR_EL1 definitions */
+#define CPACR_EL1_FPEN(x) ((x) << 20)
+#define CPACR_EL1_FP_TRAP_EL0 UL(0x1)
+#define CPACR_EL1_FP_TRAP_ALL UL(0x2)
+#define CPACR_EL1_FP_TRAP_NONE UL(0x3)
+
+/* SCR definitions */
+#define SCR_RES1_BITS ((U(1) << 4) | (U(1) << 5))
+#define SCR_NSE_SHIFT U(62)
+#define SCR_NSE_BIT (ULL(1) << SCR_NSE_SHIFT)
+#define SCR_GPF_BIT (UL(1) << 48)
+#define SCR_TWEDEL_SHIFT U(30)
+#define SCR_TWEDEL_MASK ULL(0xf)
+#define SCR_TRNDR_BIT (UL(1) << 40)
+#define SCR_HXEn_BIT (UL(1) << 38)
+#define SCR_ENTP2_SHIFT U(41)
+#define SCR_ENTP2_BIT (UL(1) << SCR_ENTP2_SHIFT)
+#define SCR_AMVOFFEN_SHIFT U(35)
+#define SCR_AMVOFFEN_BIT (UL(1) << SCR_AMVOFFEN_SHIFT)
+#define SCR_TWEDEn_BIT (UL(1) << 29)
+#define SCR_ECVEN_BIT (UL(1) << 28)
+#define SCR_FGTEN_BIT (UL(1) << 27)
+#define SCR_ATA_BIT (UL(1) << 26)
+#define SCR_EnSCXT_BIT (UL(1) << 25)
+#define SCR_FIEN_BIT (UL(1) << 21)
+#define SCR_EEL2_BIT (UL(1) << 18)
+#define SCR_API_BIT (UL(1) << 17)
+#define SCR_APK_BIT (UL(1) << 16)
+#define SCR_TERR_BIT (UL(1) << 15)
+#define SCR_TWE_BIT (UL(1) << 13)
+#define SCR_TWI_BIT (UL(1) << 12)
+#define SCR_ST_BIT (UL(1) << 11)
+#define SCR_RW_BIT (UL(1) << 10)
+#define SCR_SIF_BIT (UL(1) << 9)
+#define SCR_HCE_BIT (UL(1) << 8)
+#define SCR_SMD_BIT (UL(1) << 7)
+#define SCR_EA_BIT (UL(1) << 3)
+#define SCR_FIQ_BIT (UL(1) << 2)
+#define SCR_IRQ_BIT (UL(1) << 1)
+#define SCR_NS_BIT (UL(1) << 0)
+#define SCR_VALID_BIT_MASK U(0x24000002F8F)
+#define SCR_RESET_VAL SCR_RES1_BITS
+
+/* MDCR_EL3 definitions */
+#define MDCR_EnPMSN_BIT (ULL(1) << 36)
+#define MDCR_MPMX_BIT (ULL(1) << 35)
+#define MDCR_MCCD_BIT (ULL(1) << 34)
+#define MDCR_SBRBE_SHIFT U(32)
+#define MDCR_SBRBE_MASK ULL(0x3)
+#define MDCR_NSTB(x) ((x) << 24)
+#define MDCR_NSTB_EL1 ULL(0x3)
+#define MDCR_NSTBE (ULL(1) << 26)
+#define MDCR_MTPME_BIT (ULL(1) << 28)
+#define MDCR_TDCC_BIT (ULL(1) << 27)
+#define MDCR_SCCD_BIT (ULL(1) << 23)
+#define MDCR_EPMAD_BIT (ULL(1) << 21)
+#define MDCR_EDAD_BIT (ULL(1) << 20)
+#define MDCR_TTRF_BIT (ULL(1) << 19)
+#define MDCR_STE_BIT (ULL(1) << 18)
+#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_MTPME (U(1) << 28)
+#define MDCR_EL2_HLP (U(1) << 26)
+#define MDCR_EL2_E2TB(x) ((x) << 24)
+#define MDCR_EL2_E2TB_EL1 U(0x3)
+#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_RESET_VAL ULL(0x0)
+#define HCR_AMVOFFEN_SHIFT U(51)
+#define HCR_AMVOFFEN_BIT (ULL(1) << HCR_AMVOFFEN_SHIFT)
+#define HCR_TEA_BIT (ULL(1) << 47)
+#define HCR_API_BIT (ULL(1) << 41)
+#define HCR_APK_BIT (ULL(1) << 40)
+#define HCR_E2H_BIT (ULL(1) << 34)
+#define HCR_HCD_BIT (ULL(1) << 29)
+#define HCR_TGE_BIT (ULL(1) << 27)
+#define HCR_RW_SHIFT U(31)
+#define HCR_RW_BIT (ULL(1) << HCR_RW_SHIFT)
+#define HCR_TWE_BIT (ULL(1) << 14)
+#define HCR_TWI_BIT (ULL(1) << 13)
+#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_SHIFT U(30)
+#define TAM_BIT (U(1) << TAM_SHIFT)
+#define TTA_BIT (U(1) << 20)
+#define ESM_BIT (U(1) << 12)
+#define TFP_BIT (U(1) << 10)
+#define CPTR_EZ_BIT (U(1) << 8)
+#define CPTR_EL3_RESET_VAL ((TCPAC_BIT | TAM_BIT | TTA_BIT | TFP_BIT) & \
+ ~(CPTR_EZ_BIT | ESM_BIT))
+
+/* 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_SHIFT U(30)
+#define CPTR_EL2_TAM_BIT (U(1) << CPTR_EL2_TAM_SHIFT)
+#define CPTR_EL2_SMEN_MASK ULL(0x3)
+#define CPTR_EL2_SMEN_SHIFT U(24)
+#define CPTR_EL2_TTA_BIT (U(1) << 20)
+#define CPTR_EL2_TSM_BIT (U(1) << 12)
+#define CPTR_EL2_TFP_BIT (U(1) << 10)
+#define CPTR_EL2_TZ_BIT (U(1) << 8)
+#define CPTR_EL2_RESET_VAL CPTR_EL2_RES1
+
+/* VTCR_EL2 definitions */
+#define VTCR_RESET_VAL U(0x0)
+#define VTCR_EL2_MSA (U(1) << 31)
+
+/* 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_M_EL2H U(0x9)
+
+#define SPSR_EL_SHIFT U(2)
+#define SPSR_EL_WIDTH U(2)
+
+#define SPSR_SSBS_SHIFT_AARCH64 U(12)
+#define SPSR_SSBS_BIT_AARCH64 (ULL(1) << SPSR_SSBS_SHIFT_AARCH64)
+#define SPSR_SSBS_SHIFT_AARCH32 U(23)
+#define SPSR_SSBS_BIT_AARCH32 (ULL(1) << SPSR_SSBS_SHIFT_AARCH32)
+
+#define SPSR_PAN_BIT BIT_64(22)
+
+#define SPSR_DIT_BIT BIT(24)
+
+#define SPSR_TCO_BIT_AARCH64 BIT_64(25)
+
+#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_EL_WIDTH U(0x2)
+#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)
+
+/* Physical timer control macros */
+#define CNTP_CTL_ENABLE_BIT (U(1) << CNTP_CTL_ENABLE_SHIFT)
+#define CNTP_CTL_IMASK_BIT (U(1) << CNTP_CTL_IMASK_SHIFT)
+
+/* 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 for system register interface to SME as needed in EL3
+ ******************************************************************************/
+#define ID_AA64SMFR0_EL1 S3_0_C0_C4_5
+#define SMCR_EL3 S3_6_C1_C2_6
+
+/* ID_AA64SMFR0_EL1 definitions */
+#define ID_AA64SMFR0_EL1_FA64_BIT (UL(1) << 63)
+
+/* SMCR_ELx definitions */
+#define SMCR_ELX_LEN_SHIFT U(0)
+#define SMCR_ELX_LEN_MASK U(0x1ff)
+#define SMCR_ELX_FA64_BIT (U(1) << 31)
+
+/*******************************************************************************
+ * 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 FEAT_AMUv1
+ ******************************************************************************/
+#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
+
+/* AMCNTENSET0_EL0 definitions */
+#define AMCNTENSET0_EL0_Pn_SHIFT U(0)
+#define AMCNTENSET0_EL0_Pn_MASK ULL(0xffff)
+
+/* AMCNTENSET1_EL0 definitions */
+#define AMCNTENSET1_EL0_Pn_SHIFT U(0)
+#define AMCNTENSET1_EL0_Pn_MASK ULL(0xffff)
+
+/* AMCNTENCLR0_EL0 definitions */
+#define AMCNTENCLR0_EL0_Pn_SHIFT U(0)
+#define AMCNTENCLR0_EL0_Pn_MASK ULL(0xffff)
+
+/* AMCNTENCLR1_EL0 definitions */
+#define AMCNTENCLR1_EL0_Pn_SHIFT U(0)
+#define AMCNTENCLR1_EL0_Pn_MASK ULL(0xffff)
+
+/* AMCFGR_EL0 definitions */
+#define AMCFGR_EL0_NCG_SHIFT U(28)
+#define AMCFGR_EL0_NCG_MASK U(0xf)
+#define AMCFGR_EL0_N_SHIFT U(0)
+#define AMCFGR_EL0_N_MASK U(0xff)
+
+/* AMCGCR_EL0 definitions */
+#define AMCGCR_EL0_CG0NC_SHIFT U(0)
+#define AMCGCR_EL0_CG0NC_MASK U(0xff)
+#define AMCGCR_EL0_CG1NC_SHIFT 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)
+
+/*******************************************************************************
+ * Definitions for system register interface to AMU for FEAT_AMUv1p1
+ ******************************************************************************/
+
+/* Definition for register defining which virtual offsets are implemented. */
+#define AMCG1IDR_EL0 S3_3_C13_C2_6
+#define AMCG1IDR_CTR_MASK ULL(0xffff)
+#define AMCG1IDR_CTR_SHIFT U(0)
+#define AMCG1IDR_VOFF_MASK ULL(0xffff)
+#define AMCG1IDR_VOFF_SHIFT U(16)
+
+/* New bit added to AMCR_EL0 */
+#define AMCR_CG1RZ_SHIFT U(17)
+#define AMCR_CG1RZ_BIT (ULL(0x1) << AMCR_CG1RZ_SHIFT)
+
+/*
+ * Definitions for virtual offset registers for architected activity monitor
+ * event counters.
+ * AMEVCNTVOFF01_EL2 intentionally left undefined, as it does not exist.
+ */
+#define AMEVCNTVOFF00_EL2 S3_4_C13_C8_0
+#define AMEVCNTVOFF02_EL2 S3_4_C13_C8_2
+#define AMEVCNTVOFF03_EL2 S3_4_C13_C8_3
+
+/*
+ * Definitions for virtual offset registers for auxiliary activity monitor event
+ * counters.
+ */
+#define AMEVCNTVOFF10_EL2 S3_4_C13_C10_0
+#define AMEVCNTVOFF11_EL2 S3_4_C13_C10_1
+#define AMEVCNTVOFF12_EL2 S3_4_C13_C10_2
+#define AMEVCNTVOFF13_EL2 S3_4_C13_C10_3
+#define AMEVCNTVOFF14_EL2 S3_4_C13_C10_4
+#define AMEVCNTVOFF15_EL2 S3_4_C13_C10_5
+#define AMEVCNTVOFF16_EL2 S3_4_C13_C10_6
+#define AMEVCNTVOFF17_EL2 S3_4_C13_C10_7
+#define AMEVCNTVOFF18_EL2 S3_4_C13_C11_0
+#define AMEVCNTVOFF19_EL2 S3_4_C13_C11_1
+#define AMEVCNTVOFF1A_EL2 S3_4_C13_C11_2
+#define AMEVCNTVOFF1B_EL2 S3_4_C13_C11_3
+#define AMEVCNTVOFF1C_EL2 S3_4_C13_C11_4
+#define AMEVCNTVOFF1D_EL2 S3_4_C13_C11_5
+#define AMEVCNTVOFF1E_EL2 S3_4_C13_C11_6
+#define AMEVCNTVOFF1F_EL2 S3_4_C13_C11_7
+
+/*******************************************************************************
+ * Realm management extension register definitions
+ ******************************************************************************/
+#define GPCCR_EL3 S3_6_C2_C1_6
+#define GPTBR_EL3 S3_6_C2_C1_4
+
+/*******************************************************************************
+ * 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_SHIFT U(0)
+#define ERXCTLR_ED_BIT (U(1) << ERXCTLR_ED_SHIFT)
+#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
+
+/*******************************************************************************
+ * FEAT_HCX - Extended Hypervisor Configuration Register
+ ******************************************************************************/
+#define HCRX_EL2 S3_4_C1_C2_2
+#define HCRX_EL2_FGTnXS_BIT (UL(1) << 4)
+#define HCRX_EL2_FnXS_BIT (UL(1) << 3)
+#define HCRX_EL2_EnASR_BIT (UL(1) << 2)
+#define HCRX_EL2_EnALS_BIT (UL(1) << 1)
+#define HCRX_EL2_EnAS0_BIT (UL(1) << 0)
+
+/*******************************************************************************
+ * Definitions for DynamicIQ Shared Unit registers
+ ******************************************************************************/
+#define CLUSTERPWRDN_EL1 S3_0_c15_c3_6
+
+/* CLUSTERPWRDN_EL1 register definitions */
+#define DSU_CLUSTER_PWR_OFF 0
+#define DSU_CLUSTER_PWR_ON 1
+#define DSU_CLUSTER_PWR_MASK U(1)
+
+/*******************************************************************************
+ * Definitions for CPU Power/Performance Management registers
+ ******************************************************************************/
+
+#define CPUPPMCR_EL3 S3_6_C15_C2_0
+#define CPUPPMCR_EL3_MPMMPINCTL_SHIFT UINT64_C(0)
+#define CPUPPMCR_EL3_MPMMPINCTL_MASK UINT64_C(0x1)
+
+#define CPUMPMMCR_EL3 S3_6_C15_C2_1
+#define CPUMPMMCR_EL3_MPMM_EN_SHIFT UINT64_C(0)
+#define CPUMPMMCR_EL3_MPMM_EN_MASK UINT64_C(0x1)
+
+#endif /* ARCH_H */
diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h
new file mode 100644
index 0000000..932e885
--- /dev/null
+++ b/include/arch/aarch64/arch_features.h
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARCH_FEATURES_H
+#define ARCH_FEATURES_H
+
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+
+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_1_pan_present(void)
+{
+ return ((read_id_aa64mmfr1_el1() >> ID_AA64MMFR1_EL1_PAN_SHIFT) &
+ ID_AA64MMFR1_EL1_PAN_MASK) != 0U;
+}
+
+static inline bool is_armv8_1_vhe_present(void)
+{
+ return ((read_id_aa64mmfr1_el1() >> ID_AA64MMFR1_EL1_VHE_SHIFT) &
+ ID_AA64MMFR1_EL1_VHE_MASK) != 0U;
+}
+
+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_feat_pacqarma3_present(void)
+{
+ uint64_t mask_id_aa64isar2 =
+ (ID_AA64ISAR2_GPA3_MASK << ID_AA64ISAR2_GPA3_SHIFT) |
+ (ID_AA64ISAR2_APA3_MASK << ID_AA64ISAR2_APA3_SHIFT);
+
+ /* If any of the fields is not zero, QARMA3 algorithm is present */
+ return (read_id_aa64isar2_el1() & mask_id_aa64isar2) != 0U;
+}
+
+static inline bool is_armv8_3_pauth_present(void)
+{
+ uint64_t mask_id_aa64isar1 =
+ (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 or QARMA3 is present,
+ * PAuth is present
+ */
+ return ((read_id_aa64isar1_el1() & mask_id_aa64isar1) != 0U ||
+ is_feat_pacqarma3_present());
+}
+
+static inline bool is_armv8_4_dit_present(void)
+{
+ return ((read_id_aa64pfr0_el1() >> ID_AA64PFR0_DIT_SHIFT) &
+ ID_AA64PFR0_DIT_MASK) == 1U;
+}
+
+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);
+}
+
+static inline bool is_armv8_4_sel2_present(void)
+{
+ return ((read_id_aa64pfr0_el1() >> ID_AA64PFR0_SEL2_SHIFT) &
+ ID_AA64PFR0_SEL2_MASK) == 1ULL;
+}
+
+static inline bool is_armv8_6_twed_present(void)
+{
+ return (((read_id_aa64mmfr1_el1() >> ID_AA64MMFR1_EL1_TWED_SHIFT) &
+ ID_AA64MMFR1_EL1_TWED_MASK) == ID_AA64MMFR1_EL1_TWED_SUPPORTED);
+}
+
+static inline bool is_armv8_6_fgt_present(void)
+{
+ return ((read_id_aa64mmfr0_el1() >> ID_AA64MMFR0_EL1_FGT_SHIFT) &
+ ID_AA64MMFR0_EL1_FGT_MASK) != 0U;
+}
+
+static inline unsigned long int get_armv8_6_ecv_support(void)
+{
+ return ((read_id_aa64mmfr0_el1() >> ID_AA64MMFR0_EL1_ECV_SHIFT) &
+ ID_AA64MMFR0_EL1_ECV_MASK);
+}
+
+static inline bool is_armv8_5_rng_present(void)
+{
+ return ((read_id_aa64isar0_el1() >> ID_AA64ISAR0_RNDR_SHIFT) &
+ ID_AA64ISAR0_RNDR_MASK);
+}
+
+static inline bool is_armv8_6_feat_amuv1p1_present(void)
+{
+ return (((read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT) &
+ ID_AA64PFR0_AMU_MASK) >= ID_AA64PFR0_AMU_V1P1);
+}
+
+/*
+ * Return MPAM version:
+ *
+ * 0x00: None Armv8.0 or later
+ * 0x01: v0.1 Armv8.4 or later
+ * 0x10: v1.0 Armv8.2 or later
+ * 0x11: v1.1 Armv8.4 or later
+ *
+ */
+static inline unsigned int get_mpam_version(void)
+{
+ return (unsigned int)((((read_id_aa64pfr0_el1() >>
+ ID_AA64PFR0_MPAM_SHIFT) & ID_AA64PFR0_MPAM_MASK) << 4) |
+ ((read_id_aa64pfr1_el1() >>
+ ID_AA64PFR1_MPAM_FRAC_SHIFT) & ID_AA64PFR1_MPAM_FRAC_MASK));
+}
+
+static inline bool is_feat_hcx_present(void)
+{
+ return (((read_id_aa64mmfr1_el1() >> ID_AA64MMFR1_EL1_HCX_SHIFT) &
+ ID_AA64MMFR1_EL1_HCX_MASK) == ID_AA64MMFR1_EL1_HCX_SUPPORTED);
+}
+
+static inline bool is_feat_rng_trap_present(void)
+{
+ return (((read_id_aa64pfr1_el1() >> ID_AA64PFR1_EL1_RNDR_TRAP_SHIFT) &
+ ID_AA64PFR1_EL1_RNDR_TRAP_MASK)
+ == ID_AA64PFR1_EL1_RNG_TRAP_SUPPORTED);
+}
+
+static inline unsigned int get_armv9_2_feat_rme_support(void)
+{
+ /*
+ * Return the RME version, zero if not supported. This function can be
+ * used as both an integer value for the RME version or compared to zero
+ * to detect RME presence.
+ */
+ return (unsigned int)(read_id_aa64pfr0_el1() >>
+ ID_AA64PFR0_FEAT_RME_SHIFT) & ID_AA64PFR0_FEAT_RME_MASK;
+}
+
+/*********************************************************************************
+ * Function to identify the presence of FEAT_SB (Speculation Barrier Instruction)
+ ********************************************************************************/
+static inline bool is_armv8_0_feat_sb_present(void)
+{
+ return (((read_id_aa64isar1_el1() >> ID_AA64ISAR1_SB_SHIFT) &
+ ID_AA64ISAR1_SB_MASK) == ID_AA64ISAR1_SB_SUPPORTED);
+}
+
+/*********************************************************************************
+ * Function to identify the presence of FEAT_CSV2_2 (Cache Speculation Variant 2)
+ ********************************************************************************/
+static inline bool is_armv8_0_feat_csv2_2_present(void)
+{
+ return (((read_id_aa64pfr0_el1() >> ID_AA64PFR0_CSV2_SHIFT) &
+ ID_AA64PFR0_CSV2_MASK) == ID_AA64PFR0_CSV2_2_SUPPORTED);
+}
+
+/**********************************************************************************
+ * Function to identify the presence of FEAT_SPE (Statistical Profiling Extension)
+ *********************************************************************************/
+static inline bool is_armv8_2_feat_spe_present(void)
+{
+ return (((read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT) &
+ ID_AA64DFR0_PMS_MASK) != ID_AA64DFR0_SPE_NOT_SUPPORTED);
+}
+
+/*******************************************************************************
+ * Function to identify the presence of FEAT_SVE (Scalable Vector Extension)
+ ******************************************************************************/
+static inline bool is_armv8_2_feat_sve_present(void)
+{
+ return (((read_id_aa64pfr0_el1() >> ID_AA64PFR0_SVE_SHIFT) &
+ ID_AA64PFR0_SVE_MASK) == ID_AA64PFR0_SVE_SUPPORTED);
+}
+
+/*******************************************************************************
+ * Function to identify the presence of FEAT_RAS (Reliability,Availability,
+ * and Serviceability Extension)
+ ******************************************************************************/
+static inline bool is_armv8_2_feat_ras_present(void)
+{
+ return (((read_id_aa64pfr0_el1() >> ID_AA64PFR0_RAS_SHIFT) &
+ ID_AA64PFR0_RAS_MASK) != ID_AA64PFR0_RAS_NOT_SUPPORTED);
+}
+
+/**************************************************************************
+ * Function to identify the presence of FEAT_DIT (Data Independent Timing)
+ *************************************************************************/
+static inline bool is_armv8_4_feat_dit_present(void)
+{
+ return (((read_id_aa64pfr0_el1() >> ID_AA64PFR0_DIT_SHIFT) &
+ ID_AA64PFR0_DIT_MASK) == ID_AA64PFR0_DIT_SUPPORTED);
+}
+
+/*************************************************************************
+ * Function to identify the presence of FEAT_TRF (TraceLift)
+ ************************************************************************/
+static inline bool is_arm8_4_feat_trf_present(void)
+{
+ return (((read_id_aa64dfr0_el1() >> ID_AA64DFR0_TRACEFILT_SHIFT) &
+ ID_AA64DFR0_TRACEFILT_MASK) == ID_AA64DFR0_TRACEFILT_SUPPORTED);
+}
+
+/*******************************************************************************
+ * Function to identify the presence of FEAT_AMUv1 (Activity Monitors-
+ * Extension v1)
+ ******************************************************************************/
+static inline bool is_armv8_4_feat_amuv1_present(void)
+{
+ return (((read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT) &
+ ID_AA64PFR0_AMU_MASK) >= ID_AA64PFR0_AMU_V1);
+}
+
+/********************************************************************************
+ * Function to identify the presence of FEAT_NV2 (Enhanced Nested Virtualization
+ * Support)
+ *******************************************************************************/
+static inline unsigned int get_armv8_4_feat_nv_support(void)
+{
+ return (((read_id_aa64mmfr2_el1() >> ID_AA64MMFR2_EL1_NV_SHIFT) &
+ ID_AA64MMFR2_EL1_NV_MASK));
+}
+
+/*******************************************************************************
+ * Function to identify the presence of FEAT_BRBE (Branch Record Buffer
+ * Extension)
+ ******************************************************************************/
+static inline bool is_feat_brbe_present(void)
+{
+ return (((read_id_aa64dfr0_el1() >> ID_AA64DFR0_BRBE_SHIFT) &
+ ID_AA64DFR0_BRBE_MASK) == ID_AA64DFR0_BRBE_SUPPORTED);
+}
+
+/*******************************************************************************
+ * Function to identify the presence of FEAT_TRBE (Trace Buffer Extension)
+ ******************************************************************************/
+static inline bool is_feat_trbe_present(void)
+{
+ return (((read_id_aa64dfr0_el1() >> ID_AA64DFR0_TRACEBUFFER_SHIFT) &
+ ID_AA64DFR0_TRACEBUFFER_MASK) == ID_AA64DFR0_TRACEBUFFER_SUPPORTED);
+}
+
+#endif /* ARCH_FEATURES_H */
diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h
new file mode 100644
index 0000000..50a5ad4
--- /dev/null
+++ b/include/arch/aarch64/arch_helpers.h
@@ -0,0 +1,671 @@
+/*
+ * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARCH_HELPERS_H
+#define ARCH_HELPERS_H
+
+#include <cdefs.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch.h>
+
+/**********************************************************************
+ * 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 register parameter */
+#define DEFINE_SYSOP_PARAM_FUNC(_op) \
+static inline void _op(uint64_t v) \
+{ \
+ __asm__ (#_op " %0" : : "r" (v)); \
+}
+
+/* Define function for system instruction with type specifier */
+#define DEFINE_SYSOP_TYPE_FUNC(_op, _type) \
+static inline void _op ## _type(void) \
+{ \
+ __asm__ (#_op " " #_type : : : "memory"); \
+}
+
+/* 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)
+
+/*******************************************************************************
+ * Strip Pointer Authentication Code
+ ******************************************************************************/
+DEFINE_SYSOP_PARAM_FUNC(xpaci)
+
+void flush_dcache_range(uintptr_t addr, size_t size);
+void flush_dcache_to_popa_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);
+bool is_dcache_enabled(void);
+
+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_mpu_el2(void);
+void disable_mmu_icache_el1(void);
+void disable_mmu_icache_el3(void);
+void disable_mpu_icache_el2(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_aa64isar0_el1)
+DEFINE_SYSREG_READ_FUNC(id_aa64isar1_el1)
+DEFINE_RENAME_SYSREG_READ_FUNC(id_aa64isar2_el1, ID_AA64ISAR2_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_SYSREG_RW_FUNCS(mdccsr_el0)
+DEFINE_SYSREG_RW_FUNCS(dbgdtrrx_el0)
+DEFINE_SYSREG_RW_FUNCS(dbgdtrtx_el0)
+DEFINE_SYSREG_RW_FUNCS(sp_el1)
+DEFINE_SYSREG_RW_FUNCS(sp_el2)
+
+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, osh)
+DEFINE_SYSOP_TYPE_FUNC(dsb, nsh)
+DEFINE_SYSOP_TYPE_FUNC(dsb, ishst)
+DEFINE_SYSOP_TYPE_FUNC(dsb, oshst)
+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_READ_FUNC(id_aa64mmfr1_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_SYSREG_RW_FUNCS(vtcr_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(icc_asgi1r, ICC_ASGI1R)
+
+DEFINE_RENAME_SYSREG_READ_FUNC(amcfgr_el0, AMCFGR_EL0)
+DEFINE_RENAME_SYSREG_READ_FUNC(amcgcr_el0, AMCGCR_EL0)
+DEFINE_RENAME_SYSREG_READ_FUNC(amcg1idr_el0, AMCG1IDR_EL0)
+DEFINE_RENAME_SYSREG_RW_FUNCS(amcr_el0, AMCR_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(id_aa64smfr0_el1, ID_AA64SMFR0_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(smcr_el3, SMCR_EL3)
+
+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.4 Data Independent Timing Register */
+DEFINE_RENAME_SYSREG_RW_FUNCS(dit, DIT)
+
+/* 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)
+
+/* Armv8.5 FEAT_RNG Registers */
+DEFINE_SYSREG_READ_FUNC(rndr)
+DEFINE_SYSREG_READ_FUNC(rndrrs)
+
+/* FEAT_HCX Register */
+DEFINE_RENAME_SYSREG_RW_FUNCS(hcrx_el2, HCRX_EL2)
+
+/* DynamIQ Shared Unit power management */
+DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpwrdn_el1, CLUSTERPWRDN_EL1)
+
+/* CPU Power/Performance Management registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(cpuppmcr_el3, CPUPPMCR_EL3)
+DEFINE_RENAME_SYSREG_RW_FUNCS(cpumpmmcr_el3, CPUMPMMCR_EL3)
+
+/* Armv9.2 RME Registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(gptbr_el3, GPTBR_EL3)
+DEFINE_RENAME_SYSREG_RW_FUNCS(gpccr_el3, GPCCR_EL3)
+
+#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());
+}
+
+static inline unsigned int get_current_el_maybe_constant(void)
+{
+#if defined(IMAGE_AT_EL1)
+ return 1;
+#elif defined(IMAGE_AT_EL2)
+ return 2; /* no use-case in TF-A */
+#elif defined(IMAGE_AT_EL3)
+ return 3;
+#else
+ /*
+ * If we do not know which exception level this is being built for
+ * (e.g. built for library), fall back to run-time detection.
+ */
+ return get_current_el();
+#endif
+}
+
+/*
+ * 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;
+ }
+}
+
+/*
+ * TLBIPAALLOS instruction
+ * (TLB Inivalidate GPT Information by PA,
+ * All Entries, Outer Shareable)
+ */
+static inline void tlbipaallos(void)
+{
+ __asm__("SYS #6,c8,c1,#4");
+}
+
+/*
+ * Invalidate TLBs of GPT entries by Physical address, last level.
+ *
+ * @pa: the starting address for the range
+ * of invalidation
+ * @size: size of the range of invalidation
+ */
+void gpt_tlbi_by_pa_ll(uint64_t pa, size_t size);
+
+
+/* Previously defined accessor 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)
+
+#define read_clusterpwrdn() read_clusterpwrdn_el1()
+#define write_clusterpwrdn(_v) write_clusterpwrdn_el1(_v)
+
+#if ERRATA_SPECULATIVE_AT
+/*
+ * Assuming SCTLR.M bit is already enabled
+ * 1. Enable page table walk by clearing TCR_EL1.EPDx bits
+ * 2. Execute AT instruction for lower EL1/0
+ * 3. Disable page table walk by setting TCR_EL1.EPDx bits
+ */
+#define AT(_at_inst, _va) \
+{ \
+ assert((read_sctlr_el1() & SCTLR_M_BIT) != 0ULL); \
+ write_tcr_el1(read_tcr_el1() & ~(TCR_EPD0_BIT | TCR_EPD1_BIT)); \
+ isb(); \
+ _at_inst(_va); \
+ write_tcr_el1(read_tcr_el1() | (TCR_EPD0_BIT | TCR_EPD1_BIT)); \
+ isb(); \
+}
+#else
+#define AT(_at_inst, _va) _at_inst(_va);
+#endif
+
+#endif /* ARCH_HELPERS_H */
diff --git a/include/arch/aarch64/asm_macros.S b/include/arch/aarch64/asm_macros.S
new file mode 100644
index 0000000..66c39e5
--- /dev/null
+++ b/include/arch/aarch64/asm_macros.S
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ASM_MACROS_S
+#define ASM_MACROS_S
+
+#include <arch.h>
+#include <common/asm_macros_common.S>
+#include <lib/spinlock.h>
+
+/*
+ * 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
+
+ /*
+ * Macro for using speculation barrier instruction introduced by
+ * FEAT_SB, if it's enabled.
+ */
+ .macro speculation_barrier
+#if ENABLE_FEAT_SB
+ sb
+#else
+ dsb sy
+ isb
+#endif
+ .endm
+
+ /*
+ * Macro for mitigating against speculative execution beyond ERET. Uses the
+ * speculation barrier instruction introduced by FEAT_SB, if it's enabled.
+ */
+ .macro exception_return
+ eret
+#if ENABLE_FEAT_SB
+ sb
+#else
+ dsb nsh
+ isb
+#endif
+ .endm
+
+#endif /* ASM_MACROS_S */
diff --git a/include/arch/aarch64/assert_macros.S b/include/arch/aarch64/assert_macros.S
new file mode 100644
index 0000000..06371c4
--- /dev/null
+++ b/include/arch/aarch64/assert_macros.S
@@ -0,0 +1,29 @@
+/*
+ * 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 */
diff --git a/include/arch/aarch64/console_macros.S b/include/arch/aarch64/console_macros.S
new file mode 100644
index 0000000..3285d85
--- /dev/null
+++ b/include/arch/aarch64/console_macros.S
@@ -0,0 +1,54 @@
+/*
+ * 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 <drivers/console.h>
+
+/*
+ * This macro encapsulates the common setup that has to be done at the end of
+ * a console driver's register function. It will register all of the driver's
+ * callbacks in the console_t structure and initialize the flags field (by
+ * default consoles are enabled for the "boot" and "crash" states, this can be
+ * changed after registration with the console_set_scope() function). It ends
+ * with a tail call that will include return to the caller.
+ * REQUIRES console_t pointer in x0 and a valid return address in x30.
+ */
+ .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 */
diff --git a/include/arch/aarch64/el2_common_macros.S b/include/arch/aarch64/el2_common_macros.S
new file mode 100644
index 0000000..7bf4806
--- /dev/null
+++ b/include/arch/aarch64/el2_common_macros.S
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EL2_COMMON_MACROS_S
+#define EL2_COMMON_MACROS_S
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <context.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#include <platform_def.h>
+
+ /*
+ * Helper macro to initialise system registers at EL2.
+ */
+ .macro el2_arch_init_common
+
+ /* ---------------------------------------------------------------------
+ * SCTLR_EL2 has already been initialised - read current value before
+ * modifying.
+ *
+ * SCTLR_EL2.I: Enable the instruction cache.
+ *
+ * SCTLR_EL2.SA: Enable Stack Alignment check. A SP alignment fault
+ * exception is generated if a load or store instruction executed at
+ * EL2 uses the SP as the base address and the SP is not aligned to a
+ * 16-byte boundary.
+ *
+ * SCTLR_EL2.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_el2
+ orr x0, x0, x1
+ msr sctlr_el2, x0
+ isb
+
+ /* ---------------------------------------------------------------------
+ * Initialise HCR_EL2, 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().
+ *
+ * HCR_EL2.TWE: Set to zero so that execution of WFE instructions at
+ * EL2, EL1 and EL0 are not trapped to EL2.
+ *
+ * HCR_EL2.TWI: Set to zero so that execution of WFI instructions at
+ * EL2, EL1 and EL0 are not trapped to EL2.
+ *
+ * HCR_EL2.HCD: Set to zero to enable HVC calls at EL1 and above,
+ * from both Security states and both Execution states.
+ *
+ * HCR_EL2.TEA: Set to one to route External Aborts and SError
+ * Interrupts to EL2 when executing at any EL.
+ *
+ * HCR_EL2.{API,APK}: For Armv8.3 pointer authentication feature,
+ * disable traps to EL2 when accessing key registers or using
+ * pointer authentication instructions from lower ELs.
+ * ---------------------------------------------------------------------
+ */
+ mov_imm x0, ((HCR_RESET_VAL | HCR_TEA_BIT) \
+ & ~(HCR_TWE_BIT | HCR_TWI_BIT | HCR_HCD_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, #(HCR_API_BIT | HCR_APK_BIT)
+#endif /* CTX_INCLUDE_PAUTH_REGS */
+ msr hcr_el2, x0
+
+ /* ---------------------------------------------------------------------
+ * Initialise MDCR_EL2, setting all fields rather than relying on
+ * hw. Some fields are architecturally UNKNOWN on reset.
+ *
+ * MDCR_EL2.TDOSA: Set to zero so that EL2 and EL2 System register
+ * access to the powerdown debug registers do not trap to EL2.
+ *
+ * MDCR_EL2.TDA: Set to zero to allow EL0, EL1 and EL2 access to the
+ * debug registers, other than those registers that are controlled by
+ * MDCR_EL2.TDOSA.
+ *
+ * MDCR_EL2.TPM: Set to zero so that EL0, EL1, and EL2 System
+ * register accesses to all Performance Monitors registers do not trap
+ * to EL2.
+ *
+ * MDCR_EL2.HPMD: Set to zero so that event counting by the program-
+ * mable counters PMEVCNTR<n>_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_EL2_RESET_VAL | \
+ MDCR_SPD32(MDCR_SPD32_DISABLE)) \
+ & ~(MDCR_EL2_HPMD | MDCR_TDOSA_BIT | \
+ MDCR_TDA_BIT | MDCR_TPM_BIT))
+
+ msr mdcr_el2, x0
+
+ /* ---------------------------------------------------------------------
+ * Initialise PMCR_EL0 setting all fields rather than relying
+ * on hw. Some fields are architecturally UNKNOWN on reset.
+ *
+ * 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_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_EL2, setting all fields rather than relying on hw.
+ * All fields are architecturally UNKNOWN on reset.
+ *
+ * CPTR_EL2.TCPAC: Set to zero so that any accesses to CPACR_EL1 do
+ * not trap to EL2.
+ *
+ * CPTR_EL2.TTA: Set to zero so that System register accesses to the
+ * trace registers do not trap to EL2.
+ *
+ * CPTR_EL2.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 EL2.
+ */
+
+ mov_imm x0, (CPTR_EL2_RESET_VAL & ~(TCPAC_BIT | TTA_BIT | TFP_BIT))
+ msr cptr_el2, x0
+
+ /*
+ * If Data Independent Timing (DIT) functionality is implemented,
+ * always enable DIT in EL2
+ */
+ 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 EL2. 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_EL2, 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_EL2 register.
+ *
+ * _pie_fixup_size:
+ * Size of memory region to fixup Global Descriptor Table (GDT).
+ *
+ * A non-zero value is expected when firmware needs GDT to be fixed-up.
+ *
+ * -----------------------------------------------------------------------------
+ */
+ .macro el2_entrypoint_common \
+ _init_sctlr, _warm_boot_mailbox, _secondary_cold_boot, \
+ _init_memory, _init_c_runtime, _exception_vectors, \
+ _pie_fixup_size
+
+ .if \_init_sctlr
+ /* -------------------------------------------------------------
+ * This is the initialisation of SCTLR_EL2 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_EL2.WXN: For the EL2 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_EL2.SA: Set to zero to disable Stack Alignment check.
+ *
+ * SCTLR_EL2.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 EL2.
+ * -------------------------------------------------------------
+ */
+ mov_imm x0, (SCTLR_RESET_VAL & ~(SCTLR_EE_BIT | SCTLR_WXN_BIT \
+ | SCTLR_SA_BIT | SCTLR_A_BIT | SCTLR_DSSBS_BIT))
+ msr sctlr_el2, x0
+ isb
+ .endif /* _init_sctlr */
+
+#if DISABLE_MTPMU
+ bl mtpmu_disable
+#endif
+
+ .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 */
+
+ .if \_pie_fixup_size
+#if ENABLE_PIE
+ /*
+ * ------------------------------------------------------------
+ * If PIE is enabled fixup the Global descriptor Table only
+ * once during primary core cold boot path.
+ *
+ * Compile time base address, required for fixup, is calculated
+ * using "pie_fixup" label present within first page.
+ * ------------------------------------------------------------
+ */
+ pie_fixup:
+ ldr x0, =pie_fixup
+ and x0, x0, #~(PAGE_SIZE_MASK)
+ mov_imm x1, \_pie_fixup_size
+ add x1, x1, x0
+ bl fixup_gdt_reloc
+#endif /* ENABLE_PIE */
+ .endif /* _pie_fixup_size */
+
+ /* ---------------------------------------------------------------------
+ * Set the exception vectors.
+ * ---------------------------------------------------------------------
+ */
+ adr x0, \_exception_vectors
+ msr vbar_el2, x0
+ isb
+
+ /* ---------------------------------------------------------------------
+ * It is a cold boot.
+ * Perform any processor specific actions upon reset e.g. cache, TLB
+ * invalidations etc.
+ * ---------------------------------------------------------------------
+ */
+ bl reset_handler
+
+ el2_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 el2_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
+ 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 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
+
+ .macro apply_at_speculative_wa
+#if ERRATA_SPECULATIVE_AT
+ /*
+ * Explicitly save x30 so as to free up a register and to enable
+ * branching and also, save x29 which will be used in the called
+ * function
+ */
+ stp x29, x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
+ bl save_and_update_ptw_el1_sys_regs
+ ldp x29, x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
+#endif
+ .endm
+
+ .macro restore_ptw_el1_sys_regs
+#if ERRATA_SPECULATIVE_AT
+ /* -----------------------------------------------------------
+ * In case of ERRATA_SPECULATIVE_AT, must follow below order
+ * to ensure that page table walk is not enabled until
+ * restoration of all EL1 system registers. TCR_EL1 register
+ * should be updated at the end which restores previous page
+ * table walk setting of stage1 i.e.(TCR_EL1.EPDx) bits. ISB
+ * ensures that CPU does below steps in order.
+ *
+ * 1. Ensure all other system registers are written before
+ * updating SCTLR_EL1 using ISB.
+ * 2. Restore SCTLR_EL1 register.
+ * 3. Ensure SCTLR_EL1 written successfully using ISB.
+ * 4. Restore TCR_EL1 register.
+ * -----------------------------------------------------------
+ */
+ isb
+ ldp x28, x29, [sp, #CTX_EL1_SYSREGS_OFFSET + CTX_SCTLR_EL1]
+ msr sctlr_el1, x28
+ isb
+ msr tcr_el1, x29
+#endif
+ .endm
+
+#endif /* EL2_COMMON_MACROS_S */
diff --git a/include/arch/aarch64/el3_common_macros.S b/include/arch/aarch64/el3_common_macros.S
new file mode 100644
index 0000000..de2b931
--- /dev/null
+++ b/include/arch/aarch64/el3_common_macros.S
@@ -0,0 +1,570 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EL3_COMMON_MACROS_S
+#define EL3_COMMON_MACROS_S
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <context.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+ /*
+ * 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
+#if ENABLE_RME
+ /*
+ * TODO: Settting the EEL2 bit to allow EL3 access to secure only registers
+ * in context management. This will need to be refactored.
+ */
+ orr x0, x0, #SCR_EEL2_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 with FEAT_PMUv3p5 not implemented, setting it to 1
+ * doesn't have any effect on them.
+ *
+ * MDCR_EL3.MCCD: Set to one so that cycle counting by PMCCNTR_EL0 is
+ * prohibited in EL3. This bit is RES0 in versions of the
+ * architecture with FEAT_PMUv3p7 not implemented, 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<n>_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().
+ *
+ * MDCR_EL3.NSTB, MDCR_EL3.NSTBE: Set to zero so that Trace Buffer
+ * owning security state is Secure state. If FEAT_TRBE is implemented,
+ * accesses to Trace Buffer control registers at EL2 and EL1 in any
+ * security state generates trap exceptions to EL3.
+ * If FEAT_TRBE is not implemented, these bits are RES0.
+ *
+ * MDCR_EL3.TTRF: Set to one so that access to trace filter control
+ * registers in non-monitor mode generate EL3 trap exception,
+ * unless the access generates a higher priority exception when trace
+ * filter control(FEAT_TRF) is implemented.
+ * When FEAT_TRF is not implemented, this bit is RES0.
+ * ---------------------------------------------------------------------
+ */
+ mov_imm x0, ((MDCR_EL3_RESET_VAL | MDCR_SDD_BIT | \
+ MDCR_SPD32(MDCR_SPD32_DISABLE) | MDCR_SCCD_BIT | \
+ MDCR_MCCD_BIT) & ~(MDCR_SPME_BIT | MDCR_TDOSA_BIT | \
+ MDCR_TDA_BIT | MDCR_TPM_BIT | MDCR_NSTB(MDCR_NSTB_EL1) | \
+ MDCR_NSTBE | MDCR_TTRF_BIT))
+
+ mrs x1, id_aa64dfr0_el1
+ ubfx x1, x1, #ID_AA64DFR0_TRACEFILT_SHIFT, #ID_AA64DFR0_TRACEFILT_LENGTH
+ cbz x1, 1f
+ orr x0, x0, #MDCR_TTRF_BIT
+1:
+ 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<n>_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 one so that accesses to the trace system
+ * registers trap to EL3 from all exception levels and security
+ * states when system register trace is implemented.
+ * When system register trace is not implemented, this bit is RES0 and
+ * hence set to zero.
+ *
+ * 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.
+ *
+ * CPTR_EL3.TAM: Set to one so that Activity Monitor access is
+ * trapped to EL3 by default.
+ *
+ * CPTR_EL3.EZ: Set to zero so that all SVE functionality is trapped
+ * to EL3 by default.
+ *
+ * CPTR_EL3.ESM: Set to zero so that all SME functionality is trapped
+ * to EL3 by default.
+ */
+
+ mov_imm x0, (CPTR_EL3_RESET_VAL & ~(TCPAC_BIT | TTA_BIT | TFP_BIT))
+ mrs x1, id_aa64dfr0_el1
+ ubfx x1, x1, #ID_AA64DFR0_TRACEVER_SHIFT, #ID_AA64DFR0_TRACEVER_LENGTH
+ cbz x1, 1f
+ orr x0, x0, #TTA_BIT
+1:
+ msr cptr_el3, x0
+
+ /*
+ * If Data Independent Timing (DIT) functionality is implemented,
+ * always enable DIT in EL3.
+ * First assert that the FEAT_DIT build flag matches the feature id
+ * register value for DIT.
+ */
+#if ENABLE_FEAT_DIT
+#if ENABLE_ASSERTIONS
+ mrs x0, id_aa64pfr0_el1
+ ubfx x0, x0, #ID_AA64PFR0_DIT_SHIFT, #ID_AA64PFR0_DIT_LENGTH
+ cmp x0, #ID_AA64PFR0_DIT_SUPPORTED
+ ASM_ASSERT(eq)
+#endif /* ENABLE_ASSERTIONS */
+ mov x0, #DIT_BIT
+ msr DIT, x0
+#endif
+ .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.
+ *
+ * _pie_fixup_size:
+ * Size of memory region to fixup Global Descriptor Table (GDT).
+ *
+ * A non-zero value is expected when firmware needs GDT to be fixed-up.
+ *
+ * -----------------------------------------------------------------------------
+ */
+ .macro el3_entrypoint_common \
+ _init_sctlr, _warm_boot_mailbox, _secondary_cold_boot, \
+ _init_memory, _init_c_runtime, _exception_vectors, \
+ _pie_fixup_size
+
+ .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 DISABLE_MTPMU
+ bl mtpmu_disable
+#endif
+
+ .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 */
+
+ .if \_pie_fixup_size
+#if ENABLE_PIE
+ /*
+ * ------------------------------------------------------------
+ * If PIE is enabled fixup the Global descriptor Table only
+ * once during primary core cold boot path.
+ *
+ * Compile time base address, required for fixup, is calculated
+ * using "pie_fixup" label present within first page.
+ * ------------------------------------------------------------
+ */
+ pie_fixup:
+ ldr x0, =pie_fixup
+ and x0, x0, #~(PAGE_SIZE_MASK)
+ mov_imm x1, \_pie_fixup_size
+ add x1, x1, x0
+ bl fixup_gdt_reloc
+#endif /* ENABLE_PIE */
+ .endif /* _pie_fixup_size */
+
+ /* ---------------------------------------------------------------------
+ * Set the exception vectors.
+ * ---------------------------------------------------------------------
+ */
+ adr x0, \_exception_vectors
+ msr vbar_el3, x0
+ isb
+
+#if !(defined(IMAGE_BL2) && ENABLE_RME)
+ /* ---------------------------------------------------------------------
+ * It is a cold boot.
+ * Perform any processor specific actions upon reset e.g. cache, TLB
+ * invalidations etc.
+ * ---------------------------------------------------------------------
+ */
+ bl reset_handler
+#endif
+
+ 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) || ENABLE_RME))
+ /* -------------------------------------------------------------
+ * 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. If PIE is enabled however,
+ * RO sections including the GOT may be modified during
+ * pie fixup. Therefore, to be on the safe side, invalidate
+ * the entire image region if PIE is enabled.
+ * -------------------------------------------------------------
+ */
+#if ENABLE_PIE
+#if SEPARATE_CODE_AND_RODATA
+ adrp x0, __TEXT_START__
+ add x0, x0, :lo12:__TEXT_START__
+#else
+ adrp x0, __RO_START__
+ add x0, x0, :lo12:__RO_START__
+#endif /* SEPARATE_CODE_AND_RODATA */
+#else
+ adrp x0, __RW_START__
+ add x0, x0, :lo12:__RW_START__
+#endif /* ENABLE_PIE */
+ adrp x1, __RW_END__
+ add x1, x1, :lo12:__RW_END__
+ sub x1, x1, x0
+ bl inv_dcache_range
+#if defined(IMAGE_BL31) && SEPARATE_NOBITS_REGION
+ adrp x0, __NOBITS_START__
+ add x0, x0, :lo12:__NOBITS_START__
+ adrp x1, __NOBITS_END__
+ add x1, x1, :lo12:__NOBITS_END__
+ sub x1, x1, x0
+ bl inv_dcache_range
+#endif
+#if defined(IMAGE_BL2) && SEPARATE_BL2_NOLOAD_REGION
+ adrp x0, __BL2_NOLOAD_START__
+ add x0, x0, :lo12:__BL2_NOLOAD_START__
+ adrp x1, __BL2_NOLOAD_END__
+ add x1, x1, :lo12:__BL2_NOLOAD_END__
+ sub x1, x1, x0
+ bl inv_dcache_range
+#endif
+#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
+
+ .macro apply_at_speculative_wa
+#if ERRATA_SPECULATIVE_AT
+ /*
+ * Explicitly save x30 so as to free up a register and to enable
+ * branching and also, save x29 which will be used in the called
+ * function
+ */
+ stp x29, x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
+ bl save_and_update_ptw_el1_sys_regs
+ ldp x29, x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
+#endif
+ .endm
+
+ .macro restore_ptw_el1_sys_regs
+#if ERRATA_SPECULATIVE_AT
+ /* -----------------------------------------------------------
+ * In case of ERRATA_SPECULATIVE_AT, must follow below order
+ * to ensure that page table walk is not enabled until
+ * restoration of all EL1 system registers. TCR_EL1 register
+ * should be updated at the end which restores previous page
+ * table walk setting of stage1 i.e.(TCR_EL1.EPDx) bits. ISB
+ * ensures that CPU does below steps in order.
+ *
+ * 1. Ensure all other system registers are written before
+ * updating SCTLR_EL1 using ISB.
+ * 2. Restore SCTLR_EL1 register.
+ * 3. Ensure SCTLR_EL1 written successfully using ISB.
+ * 4. Restore TCR_EL1 register.
+ * -----------------------------------------------------------
+ */
+ isb
+ ldp x28, x29, [sp, #CTX_EL1_SYSREGS_OFFSET + CTX_SCTLR_EL1]
+ msr sctlr_el1, x28
+ isb
+ msr tcr_el1, x29
+#endif
+ .endm
+
+#endif /* EL3_COMMON_MACROS_S */
diff --git a/include/arch/aarch64/smccc_helpers.h b/include/arch/aarch64/smccc_helpers.h
new file mode 100644
index 0000000..920f294
--- /dev/null
+++ b/include/arch/aarch64/smccc_helpers.h
@@ -0,0 +1,144 @@
+/*
+ * 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 <lib/smccc.h>
+
+/* Definitions to help the assembler access the SMC/ERET args structure */
+#define SMC_ARGS_SIZE 0x40
+#define SMC_ARG0 0x0
+#define SMC_ARG1 0x8
+#define SMC_ARG2 0x10
+#define SMC_ARG3 0x18
+#define SMC_ARG4 0x20
+#define SMC_ARG5 0x28
+#define SMC_ARG6 0x30
+#define SMC_ARG7 0x38
+#define SMC_ARGS_END 0x40
+
+#ifndef __ASSEMBLER__
+
+#include <stdbool.h>
+
+#include <context.h>
+
+#include <platform_def.h> /* For CACHE_WRITEBACK_GRANULE */
+
+/* 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)
+
+typedef struct {
+ uint64_t _regs[SMC_ARGS_END >> 3];
+} __aligned(CACHE_WRITEBACK_GRANULE) smc_args_t;
+
+/*
+ * Ensure that the assembler's view of the size of the tsp_args is the
+ * same as the compilers.
+ */
+CASSERT(sizeof(smc_args_t) == SMC_ARGS_SIZE, assert_sp_args_size_mismatch);
+
+static inline smc_args_t smc_helper(uint32_t func, uint64_t arg0,
+ uint64_t arg1, uint64_t arg2,
+ uint64_t arg3, uint64_t arg4,
+ uint64_t arg5, uint64_t arg6)
+{
+ smc_args_t ret_args = {0};
+
+ register uint64_t r0 __asm__("x0") = func;
+ register uint64_t r1 __asm__("x1") = arg0;
+ register uint64_t r2 __asm__("x2") = arg1;
+ register uint64_t r3 __asm__("x3") = arg2;
+ register uint64_t r4 __asm__("x4") = arg3;
+ register uint64_t r5 __asm__("x5") = arg4;
+ register uint64_t r6 __asm__("x6") = arg5;
+ register uint64_t r7 __asm__("x7") = arg6;
+
+ /* Output registers, also used as inputs ('+' constraint). */
+ __asm__ volatile("smc #0"
+ : "+r"(r0), "+r"(r1), "+r"(r2), "+r"(r3), "+r"(r4),
+ "+r"(r5), "+r"(r6), "+r"(r7));
+
+ ret_args._regs[0] = r0;
+ ret_args._regs[1] = r1;
+ ret_args._regs[2] = r2;
+ ret_args._regs[3] = r3;
+ ret_args._regs[4] = r4;
+ ret_args._regs[5] = r5;
+ ret_args._regs[6] = r6;
+ ret_args._regs[7] = r7;
+
+ return ret_args;
+}
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* SMCCC_HELPERS_H */
diff --git a/include/bl1/bl1.h b/include/bl1/bl1.h
new file mode 100644
index 0000000..21d3ae7
--- /dev/null
+++ b/include/bl1/bl1.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BL1_H
+#define BL1_H
+
+#include <common/bl_common.h>
+
+/*
+ * 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 UL(0x0)
+#define BL1_SMC_MINOR_VER UL(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 <lib/cassert.h>
+
+struct entry_point_info;
+
+u_register_t bl1_smc_wrapper(uint32_t smc_fid,
+ void *cookie,
+ void *handle,
+ unsigned int flags);
+
+u_register_t bl1_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,
+ 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 */
diff --git a/include/bl1/tbbr/tbbr_img_desc.h b/include/bl1/tbbr/tbbr_img_desc.h
new file mode 100644
index 0000000..db15cdb
--- /dev/null
+++ b/include/bl1/tbbr/tbbr_img_desc.h
@@ -0,0 +1,14 @@
+/*
+ * 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 <common/bl_common.h>
+
+extern image_desc_t bl1_tbbr_image_descs[];
+
+#endif /* TBBR_IMG_DESC_H */
diff --git a/include/bl2/bl2.h b/include/bl2/bl2.h
new file mode 100644
index 0000000..73f5ac7
--- /dev/null
+++ b/include/bl2/bl2.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BL2_H
+#define BL2_H
+
+#include <stdint.h>
+
+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 */
diff --git a/include/bl2u/bl2u.h b/include/bl2u/bl2u.h
new file mode 100644
index 0000000..387eaf8
--- /dev/null
+++ b/include/bl2u/bl2u.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/include/bl31/bl31.h b/include/bl31/bl31.h
new file mode 100644
index 0000000..1d58ef9
--- /dev/null
+++ b/include/bl31/bl31.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BL31_H
+#define BL31_H
+
+#include <stdint.h>
+
+/*******************************************************************************
+ * 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_register_rmm_init(int32_t (*func)(void));
+void bl31_warm_entrypoint(void);
+void bl31_main(void);
+void bl31_lib_init(void);
+
+#endif /* BL31_H */
diff --git a/include/bl31/ea_handle.h b/include/bl31/ea_handle.h
new file mode 100644
index 0000000..68f012c
--- /dev/null
+++ b/include/bl31/ea_handle.h
@@ -0,0 +1,24 @@
+/*
+ * 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 */
diff --git a/include/bl31/ehf.h b/include/bl31/ehf.h
new file mode 100644
index 0000000..c13d28c
--- /dev/null
+++ b/include/bl31/ehf.h
@@ -0,0 +1,92 @@
+/*
+ * 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 <cdefs.h>
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+/* 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 */
diff --git a/include/bl31/interrupt_mgmt.h b/include/bl31/interrupt_mgmt.h
new file mode 100644
index 0000000..21af112
--- /dev/null
+++ b/include/bl31/interrupt_mgmt.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2014-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef INTERRUPT_MGMT_H
+#define INTERRUPT_MGMT_H
+
+#include <arch.h>
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * 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 <errno.h>
+#include <stdint.h>
+
+/*******************************************************************************
+ * 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 && !(defined(SPD_spmd) && (SPMD_SPM_AT_SEL2 == 1))
+ /*
+ * With EL3 exception handling, EL3 interrupts are always routed to EL3
+ * from both Secure and Non-secure, when the SPMC does not live in S-EL2.
+ * Therefore INTR_EL3_VALID_RM1 is the only valid routing model.
+ */
+ if (x == INTR_EL3_VALID_RM1)
+ return 0;
+#else
+ /*
+ * When EL3_EXCEPTION_HANDLING is not defined both routing modes are
+ * valid. This is the most common case. The exception to this rule is
+ * when EL3_EXCEPTION_HANDLING is defined but also when the SPMC lives
+ * at S-EL2. In this case, Group0 Interrupts are trapped to the SPMC
+ * when running in S-EL0 and S-EL1. The SPMC may handle the interrupt
+ * itself, delegate it to an SP or forward to EL3 for handling.
+ */
+ 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
+ ******************************************************************************/
+u_register_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 */
diff --git a/include/bl32/payloads/tlk.h b/include/bl32/payloads/tlk.h
new file mode 100644
index 0000000..290f329
--- /dev/null
+++ b/include/bl32/payloads/tlk.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TLK_H
+#define TLK_H
+
+#include <lib/utils_def.h>
+
+/*
+ * 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_SET_BL_VERSION TLK_TOS_YIELD_FID(0x6)
+#define TLK_LOCK_BL_INTERFACE TLK_TOS_YIELD_FID(0x7)
+#define TLK_BL_RPMB_SERVICE TLK_TOS_YIELD_FID(0x8)
+#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_IRQ_FIRED TLK_TOS_YIELD_FID(0xE004)
+
+/*
+ * 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_IRQ_DONE (0x32000008 | (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 */
diff --git a/include/bl32/pnc/pnc.h b/include/bl32/pnc/pnc.h
new file mode 100644
index 0000000..03a3214
--- /dev/null
+++ b/include/bl32/pnc/pnc.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PNC_H__
+#define __PNC_H__
+
+#define SMC_YIELD 0xbf000000
+#define SMC_ACTION_FROM_S 0xbf000001
+#define SMC_GET_SHAREDMEM 0xbf000002
+#define SMC_CONFIG_SHAREDMEM 0xbf000003
+#define SMC_ACTION_FROM_NS 0xbf000004
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+void *pncd_context_switch_to(unsigned long security_state);
+int plat_pncd_setup(void);
+uintptr_t plat_pncd_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);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* __PNC_H__ */
diff --git a/include/bl32/sp_min/platform_sp_min.h b/include/bl32/sp_min/platform_sp_min.h
new file mode 100644
index 0000000..a7dffff
--- /dev/null
+++ b/include/bl32/sp_min/platform_sp_min.h
@@ -0,0 +1,28 @@
+/*
+ * 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 <stdint.h>
+
+#include <common/bl_common.h>
+
+/*******************************************************************************
+ * 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 */
diff --git a/include/bl32/tsp/platform_tsp.h b/include/bl32/tsp/platform_tsp.h
new file mode 100644
index 0000000..fe8a2c9
--- /dev/null
+++ b/include/bl32/tsp/platform_tsp.h
@@ -0,0 +1,17 @@
+/*
+ * 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 */
diff --git a/include/bl32/tsp/tsp.h b/include/bl32/tsp/tsp.h
new file mode 100644
index 0000000..285bfbe
--- /dev/null
+++ b/include/bl32/tsp/tsp.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2013-2022, 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
+#define TSP_CHECK_DIT 0x2005
+
+/*
+ * 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 <stdint.h>
+
+
+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 */
diff --git a/include/common/asm_macros_common.S b/include/common/asm_macros_common.S
new file mode 100644
index 0000000..fd0ea81
--- /dev/null
+++ b/include/common/asm_macros_common.S
@@ -0,0 +1,113 @@
+/*
+ * 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 */
diff --git a/include/common/bl_common.h b/include/common/bl_common.h
new file mode 100644
index 0000000..539280e
--- /dev/null
+++ b/include/common/bl_common.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BL_COMMON_H
+#define BL_COMMON_H
+
+#include <common/ep_info.h>
+#include <common/param_header.h>
+#include <lib/utils_def.h>
+
+#ifndef __ASSEMBLER__
+#include <stddef.h>
+#include <stdint.h>
+#include <lib/cassert.h>
+#endif /* __ASSEMBLER__ */
+
+#include <export/common/bl_common_exp.h>
+
+#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
+#if SPMC_AT_EL3
+#define __EL3_LP_DESCS_START__ Load$$__EL3_LP_DESCS__$$Base
+#define __EL3_LP_DESCS_END__ Load$$__EL3_LP_DESCS__$$Limit
+#endif
+#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 SEPARATE_NOBITS_REGION
+IMPORT_SYM(uintptr_t, __NOBITS_START__, BL_NOBITS_BASE);
+IMPORT_SYM(uintptr_t, __NOBITS_END__, BL_NOBITS_END);
+#endif
+IMPORT_SYM(uintptr_t, __RW_END__, BL_END);
+
+#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);
+#elif defined(IMAGE_RMM)
+IMPORT_SYM(uintptr_t, __RMM_END__, RMM_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[];
+const char *get_version(void);
+
+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 */
diff --git a/include/common/bl_common.ld.h b/include/common/bl_common.ld.h
new file mode 100644
index 0000000..080e331
--- /dev/null
+++ b/include/common/bl_common.ld.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BL_COMMON_LD_H
+#define BL_COMMON_LD_H
+
+#include <platform_def.h>
+
+#ifdef __aarch64__
+#define STRUCT_ALIGN 8
+#define BSS_ALIGN 16
+#else
+#define STRUCT_ALIGN 4
+#define BSS_ALIGN 8
+#endif
+
+#ifndef DATA_ALIGN
+#define DATA_ALIGN 1
+#endif
+
+#define CPU_OPS \
+ . = ALIGN(STRUCT_ALIGN); \
+ __CPU_OPS_START__ = .; \
+ KEEP(*(cpu_ops)) \
+ __CPU_OPS_END__ = .;
+
+#define PARSER_LIB_DESCS \
+ . = ALIGN(STRUCT_ALIGN); \
+ __PARSER_LIB_DESCS_START__ = .; \
+ KEEP(*(.img_parser_lib_descs)) \
+ __PARSER_LIB_DESCS_END__ = .;
+
+#define RT_SVC_DESCS \
+ . = ALIGN(STRUCT_ALIGN); \
+ __RT_SVC_DESCS_START__ = .; \
+ KEEP(*(rt_svc_descs)) \
+ __RT_SVC_DESCS_END__ = .;
+
+#if SPMC_AT_EL3
+#define EL3_LP_DESCS \
+ . = ALIGN(STRUCT_ALIGN); \
+ __EL3_LP_DESCS_START__ = .; \
+ KEEP(*(el3_lp_descs)) \
+ __EL3_LP_DESCS_END__ = .;
+#else
+#define EL3_LP_DESCS
+#endif
+
+#define PMF_SVC_DESCS \
+ . = ALIGN(STRUCT_ALIGN); \
+ __PMF_SVC_DESCS_START__ = .; \
+ KEEP(*(pmf_svc_descs)) \
+ __PMF_SVC_DESCS_END__ = .;
+
+#define FCONF_POPULATOR \
+ . = ALIGN(STRUCT_ALIGN); \
+ __FCONF_POPULATOR_START__ = .; \
+ KEEP(*(.fconf_populator)) \
+ __FCONF_POPULATOR_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 pointer size alignment.
+ */
+#define GOT \
+ . = ALIGN(STRUCT_ALIGN); \
+ __GOT_START__ = .; \
+ *(.got) \
+ __GOT_END__ = .;
+
+/*
+ * The base xlat table
+ *
+ * It is put into the rodata section if PLAT_RO_XLAT_TABLES=1,
+ * or into the bss section otherwise.
+ */
+#define BASE_XLAT_TABLE \
+ . = ALIGN(16); \
+ __BASE_XLAT_TABLE_START__ = .; \
+ *(base_xlat_table) \
+ __BASE_XLAT_TABLE_END__ = .;
+
+#if PLAT_RO_XLAT_TABLES
+#define BASE_XLAT_TABLE_RO BASE_XLAT_TABLE
+#define BASE_XLAT_TABLE_BSS
+#else
+#define BASE_XLAT_TABLE_RO
+#define BASE_XLAT_TABLE_BSS BASE_XLAT_TABLE
+#endif
+
+#define RODATA_COMMON \
+ RT_SVC_DESCS \
+ FCONF_POPULATOR \
+ PMF_SVC_DESCS \
+ PARSER_LIB_DESCS \
+ CPU_OPS \
+ GOT \
+ BASE_XLAT_TABLE_RO \
+ EL3_LP_DESCS
+
+/*
+ * .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.
+ */
+#define DATA_SECTION \
+ .data . : ALIGN(DATA_ALIGN) { \
+ __DATA_START__ = .; \
+ *(SORT_BY_ALIGNMENT(.data*)) \
+ __DATA_END__ = .; \
+ }
+
+/*
+ * .rela.dyn needs to come after .data for the read-elf utility to parse
+ * this section correctly.
+ */
+#if __aarch64__
+#define RELA_DYN_NAME .rela.dyn
+#define RELOC_SECTIONS_PATTERN *(.rela*)
+#else
+#define RELA_DYN_NAME .rel.dyn
+#define RELOC_SECTIONS_PATTERN *(.rel*)
+#endif
+
+#define RELA_SECTION \
+ RELA_DYN_NAME : ALIGN(STRUCT_ALIGN) { \
+ __RELA_START__ = .; \
+ RELOC_SECTIONS_PATTERN \
+ __RELA_END__ = .; \
+ }
+
+#if !(defined(IMAGE_BL31) && RECLAIM_INIT_CODE)
+#define STACK_SECTION \
+ stacks (NOLOAD) : { \
+ __STACKS_START__ = .; \
+ *(tzfw_normal_stacks) \
+ __STACKS_END__ = .; \
+ }
+#endif
+
+/*
+ * If BL 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
+#define BAKERY_LOCK_SIZE_CHECK \
+ 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");
+#else
+#define BAKERY_LOCK_SIZE_CHECK
+#endif
+
+/*
+ * 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
+ */
+#if !USE_COHERENT_MEM
+#define BAKERY_LOCK_NORMAL \
+ . = 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__ = .; \
+ BAKERY_LOCK_SIZE_CHECK
+#else
+#define BAKERY_LOCK_NORMAL
+#endif
+
+/*
+ * 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
+ */
+#define PMF_TIMESTAMP \
+ . = 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__ = .;
+
+
+/*
+ * The .bss section gets initialised to 0 at runtime.
+ * Its base address has bigger alignment for better performance of the
+ * zero-initialization code.
+ */
+#define BSS_SECTION \
+ .bss (NOLOAD) : ALIGN(BSS_ALIGN) { \
+ __BSS_START__ = .; \
+ *(SORT_BY_ALIGNMENT(.bss*)) \
+ *(COMMON) \
+ BAKERY_LOCK_NORMAL \
+ PMF_TIMESTAMP \
+ BASE_XLAT_TABLE_BSS \
+ __BSS_END__ = .; \
+ }
+
+/*
+ * 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.
+ */
+#define XLAT_TABLE_SECTION \
+ xlat_table (NOLOAD) : { \
+ __XLAT_TABLE_START__ = .; \
+ *(xlat_table) \
+ __XLAT_TABLE_END__ = .; \
+ }
+
+#endif /* BL_COMMON_LD_H */
diff --git a/include/common/debug.h b/include/common/debug.h
new file mode 100644
index 0000000..af47999
--- /dev/null
+++ b/include/common/debug.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <lib/utils_def.h>
+
+/*
+ * 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 <cdefs.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <drivers/console.h>
+
+/*
+ * 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__)
+# define ERROR_NL() tf_log_newline(LOG_MARKER_ERROR)
+#else
+# define ERROR(...) no_tf_log(LOG_MARKER_ERROR __VA_ARGS__)
+# define ERROR_NL()
+#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
+
+const char *get_el_str(unsigned int el);
+
+#if ENABLE_BACKTRACE
+void backtrace(const char *cookie);
+#else
+#define backtrace(x)
+#endif
+
+void __dead2 do_panic(void);
+
+#define panic() \
+ do { \
+ backtrace(__func__); \
+ 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_newline(const char log_fmt[2]);
+void tf_log_set_max_level(unsigned int log_level);
+
+#endif /* __ASSEMBLER__ */
+#endif /* DEBUG_H */
diff --git a/include/common/desc_image_load.h b/include/common/desc_image_load.h
new file mode 100644
index 0000000..b044f3e
--- /dev/null
+++ b/include/common/desc_image_load.h
@@ -0,0 +1,48 @@
+/*
+ * 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 <common/bl_common.h>
+
+/* 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 */
diff --git a/include/common/ep_info.h b/include/common/ep_info.h
new file mode 100644
index 0000000..771572c
--- /dev/null
+++ b/include/common/ep_info.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EP_INFO_H
+#define EP_INFO_H
+
+#include <common/param_header.h>
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+#include <lib/cassert.h>
+#endif /* __ASSEMBLER__ */
+
+#include <export/common/ep_info_exp.h>
+
+#define SECURE EP_SECURE
+#define NON_SECURE EP_NON_SECURE
+#define REALM EP_REALM
+#if ENABLE_RME
+#define sec_state_is_valid(s) (((s) == SECURE) || \
+ ((s) == NON_SECURE) || \
+ ((s) == REALM))
+#else
+#define sec_state_is_valid(s) (((s) == SECURE) || ((s) == NON_SECURE))
+#endif
+
+#define PARAM_EP_SECURITY_MASK EP_SECURITY_MASK
+
+#define NON_EXECUTABLE EP_NON_EXECUTABLE
+#define EXECUTABLE EP_EXECUTABLE
+
+/* Get/set security state of an 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 */
diff --git a/include/common/fdt_fixup.h b/include/common/fdt_fixup.h
new file mode 100644
index 0000000..9531bdb
--- /dev/null
+++ b/include/common/fdt_fixup.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FDT_FIXUP_H
+#define FDT_FIXUP_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#define INVALID_BASE_ADDR ((uintptr_t)~0UL)
+
+struct psci_cpu_idle_state {
+ const char *name;
+ uint32_t power_state;
+ bool local_timer_stop;
+ uint32_t entry_latency_us;
+ uint32_t exit_latency_us;
+ uint32_t min_residency_us;
+ uint32_t wakeup_latency_us;
+};
+
+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);
+int fdt_add_cpus_node(void *dtb, unsigned int afflv0,
+ unsigned int afflv1, unsigned int afflv2);
+int fdt_add_cpu_idle_states(void *dtb, const struct psci_cpu_idle_state *state);
+int fdt_adjust_gic_redist(void *dtb, unsigned int nr_cores, uintptr_t gicr_base,
+ unsigned int gicr_frame_size);
+int fdt_set_mac_address(void *dtb, unsigned int ethernet_idx,
+ const uint8_t *mac_addr);
+
+#endif /* FDT_FIXUP_H */
diff --git a/include/common/fdt_wrappers.h b/include/common/fdt_wrappers.h
new file mode 100644
index 0000000..2929fc2
--- /dev/null
+++ b/include/common/fdt_wrappers.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018-2022, 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
+
+#include <libfdt_env.h>
+
+/* Number of cells, given total length in bytes. Each cell is 4 bytes long */
+#define NCELLS(len) ((len) / 4U)
+
+int fdt_read_uint32(const void *dtb, int node, const char *prop_name,
+ uint32_t *value);
+uint32_t fdt_read_uint32_default(const void *dtb, int node,
+ const char *prop_name, uint32_t dflt_value);
+int fdt_read_uint64(const void *dtb, int node, const char *prop_name,
+ uint64_t *value);
+int fdt_read_uint32_array(const void *dtb, int node, const char *prop_name,
+ unsigned int cells, uint32_t *value);
+int fdtw_read_string(const void *dtb, int node, const char *prop,
+ char *str, size_t size);
+int fdtw_read_uuid(const void *dtb, int node, const char *prop,
+ unsigned int length, uint8_t *uuid);
+int fdtw_write_inplace_cells(void *dtb, int node, const char *prop,
+ unsigned int cells, void *value);
+int fdtw_read_bytes(const void *dtb, int node, const char *prop,
+ unsigned int length, void *value);
+int fdtw_write_inplace_bytes(void *dtb, int node, const char *prop,
+ unsigned int length, const void *data);
+int fdt_get_reg_props_by_index(const void *dtb, int node, int index,
+ uintptr_t *base, size_t *size);
+int fdt_get_reg_props_by_name(const void *dtb, int node, const char *name,
+ uintptr_t *base, size_t *size);
+int fdt_get_stdout_node_offset(const void *dtb);
+
+uint64_t fdtw_translate_address(const void *dtb, int bus_node,
+ uint64_t base_address);
+
+int fdtw_for_each_cpu(const void *fdt,
+ int (*callback)(const void *dtb, int node, uintptr_t mpidr));
+
+int fdtw_find_or_add_subnode(void *fdt, int parentoffset, const char *name);
+
+static inline uint32_t fdt_blob_size(const void *dtb)
+{
+ const uint32_t *dtb_header = dtb;
+
+ return fdt32_to_cpu(dtb_header[1]);
+}
+
+#define fdt_for_each_compatible_node(dtb, node, compatible_str) \
+for (node = fdt_node_offset_by_compatible(dtb, -1, compatible_str); \
+ node >= 0; \
+ node = fdt_node_offset_by_compatible(dtb, node, compatible_str))
+
+#endif /* FDT_WRAPPERS_H */
diff --git a/include/common/feat_detect.h b/include/common/feat_detect.h
new file mode 100644
index 0000000..0f0f105
--- /dev/null
+++ b/include/common/feat_detect.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FEAT_DETECT_H
+#define FEAT_DETECT_H
+
+#include <arch_features.h>
+#include <common/debug.h>
+
+/* Function Prototypes */
+void detect_arch_features(void);
+
+/* Macro Definitions */
+#define FEAT_STATE_1 1
+#define FEAT_STATE_2 2
+#define feat_detect_panic(a, b) ((a) ? (void)0 : feature_panic(b))
+
+/*******************************************************************************
+ * Function : feature_panic
+ * Customised panic module with error logging mechanism to list the feature
+ * not supported by the PE.
+ ******************************************************************************/
+static inline void feature_panic(char *feat_name)
+{
+ ERROR("FEAT_%s not supported by the PE\n", feat_name);
+ panic();
+}
+
+#endif /* FEAT_DETECT_H */
diff --git a/include/common/image_decompress.h b/include/common/image_decompress.h
new file mode 100644
index 0000000..bb35c3b
--- /dev/null
+++ b/include/common/image_decompress.h
@@ -0,0 +1,24 @@
+/*
+ * 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 <stddef.h>
+#include <stdint.h>
+
+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 */
diff --git a/include/common/interrupt_props.h b/include/common/interrupt_props.h
new file mode 100644
index 0000000..07bafaa
--- /dev/null
+++ b/include/common/interrupt_props.h
@@ -0,0 +1,29 @@
+/*
+ * 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 */
diff --git a/include/common/nv_cntr_ids.h b/include/common/nv_cntr_ids.h
new file mode 100644
index 0000000..a15c431
--- /dev/null
+++ b/include/common/nv_cntr_ids.h
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define TRUSTED_NV_CTR_ID U(0)
+#define NON_TRUSTED_NV_CTR_ID U(1)
+#define MAX_NV_CTR_IDS U(2)
diff --git a/include/common/param_header.h b/include/common/param_header.h
new file mode 100644
index 0000000..4dab4e3
--- /dev/null
+++ b/include/common/param_header.h
@@ -0,0 +1,35 @@
+/*
+ * 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 <stdbool.h>
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+#endif /*__ASSEMBLER__*/
+
+#include <export/common/param_header_exp.h>
+
+#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 */
diff --git a/include/common/romlib.h b/include/common/romlib.h
new file mode 100644
index 0000000..7f53c47
--- /dev/null
+++ b/include/common/romlib.h
@@ -0,0 +1,16 @@
+/*
+ * 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 */
diff --git a/include/common/runtime_svc.h b/include/common/runtime_svc.h
new file mode 100644
index 0000000..472a32a
--- /dev/null
+++ b/include/common/runtime_svc.h
@@ -0,0 +1,138 @@
+/*
+ * 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 <common/bl_common.h> /* to include exception types */
+#include <lib/cassert.h>
+#include <lib/utils_def.h>
+#include <smccc_helpers.h> /* 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 */
diff --git a/include/common/tbbr/cot_def.h b/include/common/tbbr/cot_def.h
new file mode 100644
index 0000000..60dfb8a
--- /dev/null
+++ b/include/common/tbbr/cot_def.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef COT_DEF_H
+#define COT_DEF_H
+
+#ifdef MBEDTLS_CONFIG_FILE
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+/* TBBR CoT definitions */
+#if defined(SPD_spmd)
+#define COT_MAX_VERIFIED_PARAMS 8
+#elif defined(ARM_COT_cca)
+#define COT_MAX_VERIFIED_PARAMS 8
+#else
+#define COT_MAX_VERIFIED_PARAMS 4
+#endif
+
+/*
+ * Maximum key and hash sizes (in DER format).
+ *
+ * Both RSA and ECDSA keys may be used at the same time. In this case, the key
+ * buffers must be big enough to hold either. As RSA keys are bigger than ECDSA
+ * ones for all key sizes we support, they impose the minimum size of these
+ * buffers.
+ */
+#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 /* Only using ECDSA keys. */
+#define PK_DER_LEN 92
+#endif
+
+#if TF_MBEDTLS_HASH_ALG_ID == TF_MBEDTLS_SHA256
+#define HASH_DER_LEN 51
+#elif TF_MBEDTLS_HASH_ALG_ID == TF_MBEDTLS_SHA384
+#define HASH_DER_LEN 67
+#elif TF_MBEDTLS_HASH_ALG_ID == TF_MBEDTLS_SHA512
+#define HASH_DER_LEN 83
+#else
+#error "Invalid value for TF_MBEDTLS_HASH_ALG_ID"
+#endif
+
+#endif /* COT_DEF_H */
diff --git a/include/common/tbbr/tbbr_img_def.h b/include/common/tbbr/tbbr_img_def.h
new file mode 100644
index 0000000..e1c8c29
--- /dev/null
+++ b/include/common/tbbr/tbbr_img_def.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TBBR_IMG_DEF_H
+#define TBBR_IMG_DEF_H
+
+#include <export/common/tbbr/tbbr_img_def_exp.h>
+
+#if defined(SPD_spmd)
+#define SIP_SP_CONTENT_CERT_ID MAX_IMAGE_IDS
+#define PLAT_SP_CONTENT_CERT_ID (MAX_IMAGE_IDS + 1)
+#define SP_PKG1_ID (MAX_IMAGE_IDS + 2)
+#define SP_PKG2_ID (MAX_IMAGE_IDS + 3)
+#define SP_PKG3_ID (MAX_IMAGE_IDS + 4)
+#define SP_PKG4_ID (MAX_IMAGE_IDS + 5)
+#define SP_PKG5_ID (MAX_IMAGE_IDS + 6)
+#define SP_PKG6_ID (MAX_IMAGE_IDS + 7)
+#define SP_PKG7_ID (MAX_IMAGE_IDS + 8)
+#define SP_PKG8_ID (MAX_IMAGE_IDS + 9)
+#define MAX_SP_IDS U(8)
+#define MAX_IMG_IDS_WITH_SPMDS (MAX_IMAGE_IDS + MAX_SP_IDS + U(2))
+#else
+#define MAX_IMG_IDS_WITH_SPMDS MAX_IMAGE_IDS
+#endif
+
+#ifdef PLAT_TBBR_IMG_DEF
+#include <plat_tbbr_img_def.h>
+#endif
+
+#ifndef MAX_NUMBER_IDS
+#define MAX_NUMBER_IDS MAX_IMG_IDS_WITH_SPMDS
+#endif
+
+#endif /* TBBR_IMG_DEF_H */
diff --git a/include/common/tf_crc32.h b/include/common/tf_crc32.h
new file mode 100644
index 0000000..38c56a5
--- /dev/null
+++ b/include/common/tf_crc32.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TF_CRC32_H
+#define TF_CRC32_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* compute CRC using Arm intrinsic function */
+uint32_t tf_crc32(uint32_t crc, const unsigned char *buf, size_t size);
+
+#endif /* TF_CRC32_H */
diff --git a/include/common/uuid.h b/include/common/uuid.h
new file mode 100644
index 0000000..c8dd681
--- /dev/null
+++ b/include/common/uuid.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef UUID_COMMON_H
+#define UUID_COMMON_H
+
+#define UUID_BYTES_LENGTH 16
+#define UUID_STRING_LENGTH 36
+
+int read_uuid(uint8_t *dest, char *uuid);
+bool uuid_match(uint32_t *uuid1, uint32_t *uuid2);
+void copy_uuid(uint32_t *to_uuid, uint32_t *from_uuid);
+bool is_null_uuid(uint32_t *uuid);
+
+#endif /* UUID_COMMON_H */
diff --git a/include/drivers/allwinner/axp.h b/include/drivers/allwinner/axp.h
new file mode 100644
index 0000000..8b90c7f
--- /dev/null
+++ b/include/drivers/allwinner/axp.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AXP_H
+#define AXP_H
+
+#include <stdint.h>
+
+#define AXP20X_MODE_REG 0x3e
+#define AXP20X_MODE_I2C 0x00
+#define AXP20X_MODE_RSB 0x7c
+
+#define NA 0xff
+
+enum {
+ AXP803_CHIP_ID = 0x41,
+ AXP805_CHIP_ID = 0x40,
+};
+
+struct axp_regulator {
+ const 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;
+};
+
+extern const uint8_t axp_chip_id;
+extern const char *const axp_compatible;
+extern const struct axp_regulator axp_regulators[];
+
+/*
+ * Since the PMIC can be connected to multiple bus types,
+ * low-level read/write functions must be provided by the platform
+ */
+int axp_read(uint8_t reg);
+int axp_write(uint8_t reg, uint8_t val);
+int axp_clrsetbits(uint8_t reg, uint8_t clr_mask, uint8_t set_mask);
+#define axp_clrbits(reg, clr_mask) axp_clrsetbits(reg, clr_mask, 0)
+#define axp_setbits(reg, set_mask) axp_clrsetbits(reg, 0, set_mask)
+
+int axp_check_id(void);
+void axp_power_off(void);
+
+#if SUNXI_SETUP_REGULATORS == 1
+void axp_setup_regulators(const void *fdt);
+#else
+static inline void axp_setup_regulators(const void *fdt)
+{
+}
+#endif
+
+#endif /* AXP_H */
diff --git a/include/drivers/allwinner/sunxi_rsb.h b/include/drivers/allwinner/sunxi_rsb.h
new file mode 100644
index 0000000..3d003ce
--- /dev/null
+++ b/include/drivers/allwinner/sunxi_rsb.h
@@ -0,0 +1,20 @@
+/*
+ * 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 <stdint.h>
+
+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 */
diff --git a/include/drivers/amlogic/crypto/sha_dma.h b/include/drivers/amlogic/crypto/sha_dma.h
new file mode 100644
index 0000000..52129a6
--- /dev/null
+++ b/include/drivers/amlogic/crypto/sha_dma.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019, Remi Pommarel <repk@triplefau.lt>
+ *
+ * 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
diff --git a/include/drivers/amlogic/meson_console.h b/include/drivers/amlogic/meson_console.h
new file mode 100644
index 0000000..8d52d79
--- /dev/null
+++ b/include/drivers/amlogic/meson_console.h
@@ -0,0 +1,30 @@
+/*
+ * 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 <drivers/console.h>
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+/*
+ * 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_t *console);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* MESON_CONSOLE_H */
diff --git a/include/drivers/arm/arm_gicv3_common.h b/include/drivers/arm/arm_gicv3_common.h
new file mode 100644
index 0000000..d1e93be
--- /dev/null
+++ b/include/drivers/arm/arm_gicv3_common.h
@@ -0,0 +1,28 @@
+/*
+ * 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)
+
+#define IIDR_MODEL_ARM_GIC_600 U(0x0200043b)
+#define IIDR_MODEL_ARM_GIC_600AE U(0x0300043b)
+#define IIDR_MODEL_ARM_GIC_700 U(0x0400043b)
+
+#define PIDR_COMPONENT_ARM_DIST U(0x492)
+#define PIDR_COMPONENT_ARM_REDIST U(0x493)
+#define PIDR_COMPONENT_ARM_ITS U(0x494)
+
+#endif /* ARM_GICV3_COMMON_H */
diff --git a/include/drivers/arm/cci.h b/include/drivers/arm/cci.h
new file mode 100644
index 0000000..5aea95a
--- /dev/null
+++ b/include/drivers/arm/cci.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CCI_H
+#define CCI_H
+
+#include <lib/utils_def.h>
+
+/* 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 <stdint.h>
+
+/* 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 */
diff --git a/include/drivers/arm/ccn.h b/include/drivers/arm/ccn.h
new file mode 100644
index 0000000..7f73768
--- /dev/null
+++ b/include/drivers/arm/ccn.h
@@ -0,0 +1,113 @@
+/*
+ * 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 <stdint.h>
+
+/*
+ * 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 */
diff --git a/include/drivers/arm/cryptocell/712/cc_crypto_boot_defs.h b/include/drivers/arm/cryptocell/712/cc_crypto_boot_defs.h
new file mode 100644
index 0000000..2cb8938
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/cc_crypto_boot_defs.h
@@ -0,0 +1,34 @@
+/*
+ * 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
diff --git a/include/drivers/arm/cryptocell/712/cc_pal_sb_plat.h b/include/drivers/arm/cryptocell/712/cc_pal_sb_plat.h
new file mode 100644
index 0000000..212a710
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/cc_pal_sb_plat.h
@@ -0,0 +1,33 @@
+/*
+ * 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
diff --git a/include/drivers/arm/cryptocell/712/cc_pal_types.h b/include/drivers/arm/cryptocell/712/cc_pal_types.h
new file mode 100644
index 0000000..8c09b23
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/cc_pal_types.h
@@ -0,0 +1,40 @@
+/*
+ * 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
diff --git a/include/drivers/arm/cryptocell/712/cc_pal_types_plat.h b/include/drivers/arm/cryptocell/712/cc_pal_types_plat.h
new file mode 100644
index 0000000..8410024
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/cc_pal_types_plat.h
@@ -0,0 +1,25 @@
+/*
+ * 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 <stddef.h>
+#include <stdint.h>
+
+typedef uint32_t CCStatus;
+
+#define CCError_t CCStatus
+#define CC_INFINITE 0xFFFFFFFF
+
+#define CEXPORT_C
+#define CIMPORT_C
+
+#endif /*_CC_PAL_TYPES_PLAT_H*/
diff --git a/include/drivers/arm/cryptocell/712/cc_sec_defs.h b/include/drivers/arm/cryptocell/712/cc_sec_defs.h
new file mode 100644
index 0000000..d419218
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/cc_sec_defs.h
@@ -0,0 +1,34 @@
+/*
+ * 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
diff --git a/include/drivers/arm/cryptocell/712/crypto_driver.h b/include/drivers/arm/cryptocell/712/crypto_driver.h
new file mode 100644
index 0000000..18104dd
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/crypto_driver.h
@@ -0,0 +1,35 @@
+/*
+ * 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
diff --git a/include/drivers/arm/cryptocell/712/nvm.h b/include/drivers/arm/cryptocell/712/nvm.h
new file mode 100644
index 0000000..a70289f
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/nvm.h
@@ -0,0 +1,55 @@
+/*
+ * 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
diff --git a/include/drivers/arm/cryptocell/712/nvm_otp.h b/include/drivers/arm/cryptocell/712/nvm_otp.h
new file mode 100644
index 0000000..390d62b
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/nvm_otp.h
@@ -0,0 +1,59 @@
+/*
+ * 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
diff --git a/include/drivers/arm/cryptocell/712/rsa.h b/include/drivers/arm/cryptocell/712/rsa.h
new file mode 100644
index 0000000..825214d
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/rsa.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017-2019, 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 in bits */
+#if (KEY_SIZE == 2048)
+#define RSA_MOD_SIZE_IN_BITS 2048UL
+#elif (KEY_SIZE == 3072)
+#define RSA_MOD_SIZE_IN_BITS 3072UL
+#else
+#error Unsupported CryptoCell key size requested
+#endif
+
+#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))
+
+/*
+ * @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
diff --git a/include/drivers/arm/cryptocell/712/sbrom_bsv_api.h b/include/drivers/arm/cryptocell/712/sbrom_bsv_api.h
new file mode 100644
index 0000000..de83546
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/sbrom_bsv_api.h
@@ -0,0 +1,72 @@
+/*
+ * 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
diff --git a/include/drivers/arm/cryptocell/712/secureboot_base_func.h b/include/drivers/arm/cryptocell/712/secureboot_base_func.h
new file mode 100644
index 0000000..6db596e
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/secureboot_base_func.h
@@ -0,0 +1,49 @@
+/*
+ * 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
diff --git a/include/drivers/arm/cryptocell/712/secureboot_gen_defs.h b/include/drivers/arm/cryptocell/712/secureboot_gen_defs.h
new file mode 100644
index 0000000..ed1f283
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/secureboot_gen_defs.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017-2019, 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*/
+#if (KEY_SIZE == 2048)
+#define SB_RSA_MOD_SIZE_IN_WORDS 64
+#elif (KEY_SIZE == 3072)
+#define SB_RSA_MOD_SIZE_IN_WORDS 96
+#else
+#error Unsupported CryptoCell key size requested
+#endif
+
+#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 */
+/* Note: this applies to either 2k or 3k based on CryptoCell SBROM library
+ * version - it means 2k in version 1 and 3k in version 2 (yes, really).
+ */
+typedef enum {
+ RSA_PSS = 0x01, /*!< RSA PSS after hash SHA 256 */
+ RSA_PKCS15 = 0x02, /*!< RSA PKX15 */
+ RSA_Last = 0x7FFFFFFF
+} CCSbRsaAlg_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/drivers/arm/cryptocell/712/util.h b/include/drivers/arm/cryptocell/712/util.h
new file mode 100644
index 0000000..18fb599
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/util.h
@@ -0,0 +1,72 @@
+/*
+ * 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
diff --git a/include/drivers/arm/cryptocell/713/bsv_api.h b/include/drivers/arm/cryptocell/713/bsv_api.h
new file mode 100644
index 0000000..dc49473
--- /dev/null
+++ b/include/drivers/arm/cryptocell/713/bsv_api.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2017-2020 ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _BSV_API_H
+#define _BSV_API_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*!
+@file
+@brief This file contains the Boot Services APIs and definitions.
+
+@defgroup cc_bsv_api CryptoCell Boot Services APIs and definitions
+@{
+@ingroup cc_bsv
+*/
+
+#include "cc_pal_types.h"
+#include "cc_sec_defs.h"
+#include "cc_boot_defs.h"
+
+/* Life cycle state definitions. */
+#define CC_BSV_CHIP_MANUFACTURE_LCS 0x0 /*!< The CM life-cycle state (LCS) value. */
+#define CC_BSV_DEVICE_MANUFACTURE_LCS 0x1 /*!< The DM life-cycle state (LCS) value. */
+#define CC_BSV_SECURE_LCS 0x5 /*!< The Secure life-cycle state (LCS) value. */
+#define CC_BSV_RMA_LCS 0x7 /*!< The RMA life-cycle state (LCS) value. */
+#define CC_BSV_INVALID_LCS 0xff /*!< The invalid life-cycle state (LCS) value. */
+
+/*----------------------------
+ TYPES
+-----------------------------------*/
+
+/*----------------------------
+ PUBLIC FUNCTIONS
+-----------------------------------*/
+
+
+/*!
+@brief This function verifies the product and version numbers of the HW, and initializes it.
+
+\warning This function must be the first CryptoCell-7xx SBROM library API called.
+
+@return \c CC_OK on success.
+@return A non-zero value from bsv_error.h on failure.
+*/
+CCError_t CC_BsvInit(
+ unsigned long hwBaseAddress /*!< [in] The base address of the CryptoCell HW registers. */
+ );
+
+/*!
+@brief This function retrieves the HW LCS and performs validity checks.
+
+If the LCS is RMA, it also sets the OTP secret keys to a fixed value.
+
+@note An error is returned if there is an invalid LCS. If this happens, your code must
+completely disable the device.
+
+@return \c CC_OK on success.
+@return A non-zero value from bsv_error.h on failure.
+*/
+CCError_t CC_BsvGetAndInitLcs(
+ unsigned long hwBaseAddress, /*!< [in] The base address of the CryptoCell HW registers. */
+ uint32_t *pLcs /*!< [out] The value of the current LCS. */
+ );
+
+/*!
+@brief This function retrieves the LCS from the NVM manager.
+
+@return \c CC_OK on success.
+@return A non-zero value from bsv_error.h on failure.
+*/
+CCError_t CC_BsvLcsGet(
+ unsigned long hwBaseAddress, /*!< [in] The base address of the CryptoCell HW registers. */
+ uint32_t *pLcs /*!< [out] The value of the current LCS. */
+ );
+
+/*!
+@brief This function reads software revocation counter from OTP memory, according to the provided sw version index.
+SW version is stored in NVM counter and represented by ones. Meaning seVersion=5 would be stored as binary 0b11111;
+hence:
+ the maximal of trusted is 32
+ the maximal of non-trusted is 224
+
+@return \c CC_OK on success.
+@return A non-zero value from bsv_error.h on failure.
+*/
+CCError_t CC_BsvSwVersionGet(
+ unsigned long hwBaseAddress, /*!< [in] HW registers base address. */
+ CCSbSwVersionId_t id, /*!< [in] Enumeration defining the trusted/non-trusted counter to read. */
+ uint32_t *swVersion /*!< [out] The value of the requested counter as read from OTP memory. */
+ );
+
+/*!
+@brief This function sets the NVM counter according to swVersionID (trusted/non-trusted).
+
+@return \c CC_OK on success.
+@return A non-zero value from bsv_error.h on failure.
+*/
+CCError_t CC_BsvSwVersionSet(
+ unsigned long hwBaseAddress, /*!< [in] HW registers base address. */
+ CCSbSwVersionId_t id, /*!< [in] Enumeration defining the trusted/non-trusted counter to read. */
+ uint32_t swVersion /*!< [in] New value of the counter to be programmed in OTP memory. */
+ );
+
+/*!
+@brief This function sets the "fatal error" flag in the NVM manager, to disable the use of
+any HW keys or security services.
+
+@return \c CC_OK on success.
+@return A non-zero value from bsv_error.h on failure.
+*/
+CCError_t CC_BsvFatalErrorSet(
+ unsigned long hwBaseAddress /*!< [in] The base address of the CryptoCell HW registers. */
+ );
+
+/*!
+@brief This function retrieves the public key hash from OTP memory, according to the provided index.
+
+@return \c CC_OK on success.
+@return A non-zero value from bsv_error.h on failure.
+*/
+CCError_t CC_BsvPubKeyHashGet(
+ unsigned long hwBaseAddress, /*!< [in] HW registers base address. */
+ CCSbPubKeyIndexType_t keyIndex, /*!< [in] Enumeration defining the key hash to retrieve: 128-bit HBK0, 128-bit HBK1, or 256-bit HBK. */
+ uint32_t *hashedPubKey, /*!< [out] A buffer to contain the public key HASH. */
+ uint32_t hashResultSizeWords /*!< [in] The size of the hash in 32-bit words:
+ - Must be 4 for 128-bit hash.
+ - Must be 8 for 256bit hash. */
+ );
+
+/*!
+@brief This function permanently sets the RMA LCS for the ICV and the OEM.
+
+@return \c CC_OK on success.
+@return A non-zero value from bsv_error.h on failure.
+*/
+CCError_t CC_BsvRMAModeEnable(
+ unsigned long hwBaseAddress /*!< [in] The base address of the CryptoCell HW registers. */
+ );
+
+/*!
+@brief This function is called by the ICV code, to disable the OEM code from changing the ICV RMA bit flag.
+
+@return \c CC_OK on success.
+@return A non-zero value from bsv_error.h on failure.
+*/
+CCError_t CC_BsvICVRMAFlagBitLock(
+ unsigned long hwBaseAddress /*!< [in] The base address of the CryptoCell HW registers. */
+ );
+
+/*!
+@brief This function locks the defined ICV class keys from further usage.
+
+@return \c CC_OK on success.
+@return A non-zero value from bsv_error.h on failure.
+*/
+CCError_t CC_BsvICVKeyLock(
+ unsigned long hwBaseAddress, /*!< [in] HW registers base address. */
+ CCBool_t isICVProvisioningKeyLock, /*!< [in] Should the provisioning key be locked. */
+ CCBool_t isICVCodeEncKeyLock /*!< [in] Should the encryption key be locked. */
+ );
+
+
+/*!
+@brief This function retrieves the value of "secure disable" bit.
+
+@return \c CC_OK on success.
+@return A non-zero value from bsv_error.h on failure.
+*/
+CCError_t CC_BsvSecureDisableGet(
+ unsigned long hwBaseAddress, /*!< [in] HW registers base address. */
+ CCBool_t *isSDEnabled /*!< [out] The value of the SD Enable bit. */
+ );
+
+
+/*!
+@brief This function derives the platform key (Kplt) from the Kpicv, and then decrypts the customer key (Kcst)
+from the EKcst (burned in the OTP). The decryption is done only in Secure and RMA LCS mode using AES-ECB.
+The customer ROM should invoke this function during early boot, prior to running any non-ROM code, only if Kcst exists.
+The resulting Kcst is saved in a HW register.
+
+@return \c CC_OK on success.
+@return A non-zero value from bsv_error.h on failure.
+*/
+CCError_t CC_BsvCustomerKeyDecrypt(
+ unsigned long hwBaseAddress /*!< [in] The base address of the CryptoCell HW registers. */
+ );
+#ifdef __cplusplus
+}
+#endif
+
+/*!
+@brief This function derives the unique SoC_ID for the device, as hashed (Hbk || AES_CMAC (HUK)).
+
+@note SoC_ID is required to create debug certificates.
+
+The OEM or ICV must provide a method for a developer to discover the SoC_ID of a target
+device without having to first enable debugging.
+One suggested implementation is to have the device ROM code compute the SoC_ID and place
+it in a specific location in the flash memory, from where it can be accessed by the developer.
+
+@return \c CC_OK on success.
+@return A non-zero value from bsv_error.h on failure.
+*/
+CCError_t CC_BsvSocIDCompute(
+ unsigned long hwBaseAddress, /*!< [in] The base address of the CryptoCell HW registers. */
+ CCHashResult_t hashResult /*!< [out] The derived SoC_ID. */
+ );
+
+#endif /* _BSV_API_H */
+
+/**
+@}
+ */
+
diff --git a/include/drivers/arm/cryptocell/713/bsv_crypto_api.h b/include/drivers/arm/cryptocell/713/bsv_crypto_api.h
new file mode 100644
index 0000000..1e60579
--- /dev/null
+++ b/include/drivers/arm/cryptocell/713/bsv_crypto_api.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017-2020 ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _BSV_CRYPTO_API_H
+#define _BSV_CRYPTO_API_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*!
+@file
+@brief This file contains the cryptographic ROM APIs of the Boot Services.
+
+@defgroup cc_bsv_crypto_api CryptoCell Boot Services cryptographic ROM APIs
+@{
+@ingroup cc_bsv
+*/
+
+#include "cc_pal_types.h"
+#include "cc_sec_defs.h"
+#include "cc_address_defs.h"
+#include "bsv_crypto_defs.h"
+
+/*----------------------------
+ PUBLIC FUNCTIONS
+-----------------------------------*/
+
+/*!
+@brief This function calculates the SHA-256 digest over contiguous memory
+in an integrated operation.
+
+@return \c CC_OK on success.
+@return A non-zero value from bsv_error.h on failure.
+*/
+CCError_t CC_BsvSha256(
+ unsigned long hwBaseAddress, /*!< [in] The base address of the CryptoCell HW registers. */
+ uint8_t *pDataIn, /*!< [in] A pointer to the input buffer to be hashed. The buffer must be contiguous. */
+ size_t dataSize, /*!< [in] The size of the data to be hashed, in bytes. */
+ CCHashResult_t hashBuff /*!< [out] A pointer to a word-aligned 32-byte buffer. */
+ );
+
+
+/*!
+@brief This function allows you to calculate SHA256 digest of an image with decryption base on AES-CTR,
+with HW or user key.
+
+@return \c CC_OK on success.
+@return A non-zero value from bsv_error.h on failure. (in this case, hashBuff will be returned clean, while the output data should be cleaned by the user).
+*/
+CCError_t CC_BsvCryptoImageDecrypt( unsigned long hwBaseAddress, /*!< [in] The base address of the CryptoCell HW registers. */
+ CCBsvflowMode_t flow, /*!< [in] The supported operations are: HASH, AES to HASH, AES and HASH. */
+ CCBsvKeyType_t keyType, /*!< [in] The key type to use: Kce, Kceicv, or user key. */
+ uint8_t *pUserKey, /*!< [in] A pointer to the user key buffer in case keyType is CC_BSV_USER_KEY. */
+ size_t userKeySize, /*!< [in] The user key size in bytes (128bits) in case keyType is CC_BSV_USER_KEY. */
+ uint8_t *pIvBuf, /*!< [in] A pointer to the IV / counter buffer. */
+ uint8_t *pInputData, /*!< [in] A pointer to the input data. */
+ uint8_t *pOutputData, /*!< [out] A pointer to the output buffer. (optional – should be null in case of hash only). */
+ size_t dataSize, /*!< [in] The size of the input data in bytes. MUST be multiple of AES block size. */
+ CCHashResult_t hashBuff /*!< [out] A pointer to a word-aligned 32-byte digest output buffer. */
+ );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/**
+@}
+ */
+
diff --git a/include/drivers/arm/cryptocell/713/bsv_crypto_asym_api.h b/include/drivers/arm/cryptocell/713/bsv_crypto_asym_api.h
new file mode 100644
index 0000000..406e1ef
--- /dev/null
+++ b/include/drivers/arm/cryptocell/713/bsv_crypto_asym_api.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017-2020 ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _BSV_CRYPTO_ASYM_API_H
+#define _BSV_CRYPTO_ASYM_API_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*!
+@file
+@brief This file contains the cryptographic Asymmetric ROM APIs of the Boot Services.
+
+@defgroup cc_bsv_crypto_asym_api CryptoCell Boot Services cryptographic Asymmetric ROM APIs
+@{
+@ingroup cc_bsv
+*/
+
+#include "cc_pal_types.h"
+#include "cc_pka_hw_plat_defs.h"
+#include "cc_sec_defs.h"
+#include "bsv_crypto_api.h"
+
+/*! Defines the workspace size in bytes needed for internal Asymmetric operations. */
+#define BSV_RSA_WORKSPACE_MIN_SIZE (4*BSV_CERT_RSA_KEY_SIZE_IN_BYTES +\
+ 2*RSA_PKA_BARRETT_MOD_TAG_BUFF_SIZE_IN_BYTES)
+
+/*! Definition for the RSA public modulus array. */
+typedef uint32_t CCBsvNBuff_t[BSV_CERT_RSA_KEY_SIZE_IN_WORDS];
+
+/*! Definition for the RSA Barrett mod tag array. */
+typedef uint32_t CCBsvNpBuff_t[RSA_PKA_BARRETT_MOD_TAG_BUFF_SIZE_IN_BYTES];
+
+/*! Definition for the RSA signature array. */
+typedef uint32_t CCBsvSignature_t[BSV_CERT_RSA_KEY_SIZE_IN_WORDS];
+
+
+/*----------------------------
+ PUBLIC FUNCTIONS
+-----------------------------------*/
+
+/*!
+@brief This function performs the primitive operation of RSA, meaning exponent and modulus.
+ outBuff = (pInBuff ^ Exp) mod NBuff. ( Exp = 0x10001 )
+
+ The function supports 2k and 3K bit size of modulus, based on compile time define.
+ There are no restriction on pInBuff location, however its size must be equal to BSV_RSA_KEY_SIZE_IN_BYTES and its
+ value must be smaller than the modulus.
+
+
+@return \c CC_OK on success.
+@return A non-zero value from bsv_error.h on failure.
+*/
+CCError_t CC_BsvRsaPrimVerify (unsigned long hwBaseAddress, /*!< [in] The base address of the CryptoCell HW registers. */
+ CCBsvNBuff_t NBuff, /*!< [in] The modulus buffer big endian format. */
+ CCBsvNpBuff_t NpBuff, /*!< [in] The barret tag buffer big endian format - optional. */
+ uint32_t *pInBuff, /*!< [in] The DataIn buffer to be encrypted. */
+ size_t inBuffSize, /*!< [in] The DataIn buffer size in bytes, must be BSV_RSA_KEY_SIZE_IN_BYTES. */
+ CCBsvSignature_t pOutBuff, /*!< [out] The encrypted buffer in big endian format. */
+ uint32_t *pWorkSpace, /*!< [in] The pointer to user allocated buffer for internal use. */
+ size_t workBufferSize /*!< [in] The size in bytes of pWorkSpace, must be at-least BSV_RSA_WORKSPACE_MIN_SIZE. */
+);
+
+
+/*!
+@brief This function performs RSA PSS verify.
+
+ The function should support 2k and 3K bit size of modulus, based on compile time define.
+
+@return \c CC_OK on success.
+@return A non-zero value from bsv_error.h on failure.
+*/
+CCError_t CC_BsvRsaPssVerify (unsigned long hwBaseAddress, /*!< [in] The base address of the CryptoCell HW registers. */
+ CCBsvNBuff_t NBuff, /*!< [in] The modulus buffer big endian format. */
+ CCBsvNpBuff_t NpBuff, /*!< [in] The barret tag buffer big endian format - optional. */
+ CCBsvSignature_t signature, /*!< [in] The signature buffer to verify - big endian format. */
+ CCHashResult_t hashedData, /*!< [in] The data-in buffer to be verified as sha256 digest. */
+ uint32_t *pWorkSpace, /*!< [in] The pointer to user allocated buffer for internal use. */
+ size_t workBufferSize, /*!< [in] The size in bytes of pWorkSpace, must be at-least BSV_RSA_WORKSPACE_MIN_SIZE. */
+ CCBool_t *pIsVerified /*!< [out] The flag indicates whether the signature is verified or not.
+ If verified value will be CC_TRUE, otherwise CC_FALSE */
+);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/**
+@}
+ */
+
diff --git a/include/drivers/arm/cryptocell/713/bsv_crypto_defs.h b/include/drivers/arm/cryptocell/713/bsv_crypto_defs.h
new file mode 100644
index 0000000..9ea354d
--- /dev/null
+++ b/include/drivers/arm/cryptocell/713/bsv_crypto_defs.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017-2020 ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _BSV_CRYPTO_DEFS_H
+#define _BSV_CRYPTO_DEFS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*!
+@file
+@brief This file contains the definitions of the cryptographic ROM APIs.
+
+@defgroup cc_bsv_crypto_defs CryptoCell Boot Services cryptographic ROM API definitions
+@{
+@ingroup cc_bsv
+*/
+
+/*! AES supported HW key code table. */
+typedef enum {
+
+ CC_BSV_USER_KEY = 0, /*!< Definition for a user key. */
+ CC_BSV_HUK_KEY = 1, /*!< Definition for the HW unique key. */
+ CC_BSV_RTL_KEY = 2, /*!< Definition for the RTL key. */
+ CC_BSV_SESSION_KEY = 3, /*!< Definition for the Session key. */
+ CC_BSV_CE_KEY = 4, /*!< Definition for the Kce. */
+ CC_BSV_PLT_KEY = 5, /*!< Definition for the Platform key. */
+ CC_BSV_KCST_KEY = 6, /*!< Definition for Kcst. */
+ CC_BSV_ICV_PROV_KEY = 0xd, /*!< Definition for the Kpicv. */
+ CC_BSV_ICV_CE_KEY = 0xe, /*!< Definition for the Kceicv. */
+ CC_BSV_PROV_KEY = 0xf, /*!< Definition for the Kcp. */
+ CC_BSV_END_OF_KEY_TYPE = INT32_MAX, /*!< Reserved. */
+}CCBsvKeyType_t;
+
+/*! AES directions. */
+typedef enum bsvAesDirection {
+ BSV_AES_DIRECTION_ENCRYPT = 0, /*!< Encrypt.*/
+ BSV_AES_DIRECTION_DECRYPT = 1, /*!< Decrypt.*/
+ BSV_AES_NUM_OF_ENCRYPT_MODES, /*!< The maximal number of operations. */
+ BSV_AES_DIRECTION_RESERVE32B = INT32_MAX /*!< Reserved.*/
+}bsvAesDirection_t;
+
+/*! Definitions of the cryptographic flow supported as part of the Secure Boot. */
+typedef enum {
+ CC_BSV_CRYPTO_HASH_MODE = 0, /*!< Hash mode only. */
+ CC_BSV_CRYPTO_AES_CTR_AND_HASH_MODE = 1, /*!< Data goes into the AES and Hash engines. */
+ CC_BSV_CRYPTO_AES_CTR_TO_HASH_MODE = 2 /*!< Data goes into the AES and from the AES to the Hash engine. */
+}CCBsvflowMode_t;
+
+/*! CryptoImage HW completion sequence mode */
+typedef enum
+{
+ BSV_CRYPTO_COMPLETION_NO_WAIT = 0, /*!< The driver waits only before reading the output. */
+ BSV_CRYPTO_COMPLETION_WAIT_UPON_END = 1 /*!< The driver waits after each chunk of data. */
+}bsvCryptoCompletionMode_t;
+
+
+/*! AES-CMAC result size, in words. */
+#define CC_BSV_CMAC_RESULT_SIZE_IN_WORDS 4 /* 128b */
+/*! AES-CMAC result size, in bytes. */
+#define CC_BSV_CMAC_RESULT_SIZE_IN_BYTES 16 /* 128b */
+/*! AES-CCM 128bit key size, in bytes. */
+#define CC_BSV_CCM_KEY_SIZE_BYTES 16
+/*! AES-CCM 128bit key size, in words. */
+#define CC_BSV_CCM_KEY_SIZE_WORDS 4
+/*! AES-CCM NONCE size, in bytes. */
+#define CC_BSV_CCM_NONCE_SIZE_BYTES 12
+
+
+/*! AES-CMAC result buffer. */
+typedef uint32_t CCBsvCmacResult_t[CC_BSV_CMAC_RESULT_SIZE_IN_WORDS];
+/*! AES-CCM key buffer.*/
+typedef uint32_t CCBsvCcmKey_t[CC_BSV_CCM_KEY_SIZE_WORDS];
+/*! AES-CCM nonce buffer.*/
+typedef uint8_t CCBsvCcmNonce_t[CC_BSV_CCM_NONCE_SIZE_BYTES];
+/*! AES-CCM MAC buffer.*/
+typedef uint8_t CCBsvCcmMacRes_t[CC_BSV_CMAC_RESULT_SIZE_IN_BYTES];
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/**
+@}
+ */
+
diff --git a/include/drivers/arm/cryptocell/713/bsv_error.h b/include/drivers/arm/cryptocell/713/bsv_error.h
new file mode 100644
index 0000000..4d72e60
--- /dev/null
+++ b/include/drivers/arm/cryptocell/713/bsv_error.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2017-2020 ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _BSV_ERROR_H
+#define _BSV_ERROR_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*!
+@file
+@brief This file defines the error code types that are returned from the Boot Services APIs.
+
+@defgroup cc_bsv_error CryptoCell Boot Services error codes
+@{
+@ingroup cc_bsv
+*/
+
+/*! Defines the base address for Boot Services errors. */
+#define CC_BSV_BASE_ERROR 0x0B000000
+/*! Defines the base address for Boot Services cryptographic errors. */
+#define CC_BSV_CRYPTO_ERROR 0x0C000000
+
+/*! Illegal input parameter. */
+#define CC_BSV_ILLEGAL_INPUT_PARAM_ERR (CC_BSV_BASE_ERROR + 0x00000001)
+/*! Illegal HUK value. */
+#define CC_BSV_ILLEGAL_HUK_VALUE_ERR (CC_BSV_BASE_ERROR + 0x00000002)
+/*! Illegal Kcp value. */
+#define CC_BSV_ILLEGAL_KCP_VALUE_ERR (CC_BSV_BASE_ERROR + 0x00000003)
+/*! Illegal Kce value. */
+#define CC_BSV_ILLEGAL_KCE_VALUE_ERR (CC_BSV_BASE_ERROR + 0x00000004)
+/*! Illegal Kpicv value. */
+#define CC_BSV_ILLEGAL_KPICV_VALUE_ERR (CC_BSV_BASE_ERROR + 0x00000005)
+/*! Illegal Kceicv value. */
+#define CC_BSV_ILLEGAL_KCEICV_VALUE_ERR (CC_BSV_BASE_ERROR + 0x00000006)
+/*! Illegal EKcst value. */
+#define CC_BSV_ILLEGAL_EKCST_VALUE_ERR (CC_BSV_BASE_ERROR + 0x00000007)
+/*! Hash boot key not programmed in the OTP. */
+#define CC_BSV_HASH_NOT_PROGRAMMED_ERR (CC_BSV_BASE_ERROR + 0x00000008)
+/*! Illegal Hash boot key zero count in the OTP. */
+#define CC_BSV_HBK_ZERO_COUNT_ERR (CC_BSV_BASE_ERROR + 0x00000009)
+/*! Illegal LCS. */
+#define CC_BSV_ILLEGAL_LCS_ERR (CC_BSV_BASE_ERROR + 0x0000000A)
+/*! OTP write compare failure. */
+#define CC_BSV_OTP_WRITE_CMP_FAIL_ERR (CC_BSV_BASE_ERROR + 0x0000000B)
+/*! OTP access error */
+#define CC_BSV_OTP_ACCESS_ERR (CC_BSV_BASE_ERROR + 0x0000000C)
+/*! Erase key in OTP failed. */
+#define CC_BSV_ERASE_KEY_FAILED_ERR (CC_BSV_BASE_ERROR + 0x0000000D)
+/*! Illegal PIDR. */
+#define CC_BSV_ILLEGAL_PIDR_ERR (CC_BSV_BASE_ERROR + 0x0000000E)
+/*! Illegal CIDR. */
+#define CC_BSV_ILLEGAL_CIDR_ERR (CC_BSV_BASE_ERROR + 0x0000000F)
+/*! Device failed to move to fatal error state. */
+#define CC_BSV_FAILED_TO_SET_FATAL_ERR (CC_BSV_BASE_ERROR + 0x00000010)
+/*! Failed to set RMA LCS. */
+#define CC_BSV_FAILED_TO_SET_RMA_ERR (CC_BSV_BASE_ERROR + 0x00000011)
+/*! Illegal RMA indication. */
+#define CC_BSV_ILLEGAL_RMA_INDICATION_ERR (CC_BSV_BASE_ERROR + 0x00000012)
+/*! Boot Services version is not initialized. */
+#define CC_BSV_VER_IS_NOT_INITIALIZED_ERR (CC_BSV_BASE_ERROR + 0x00000013)
+/*! APB secure mode is locked. */
+#define CC_BSV_APB_SECURE_IS_LOCKED_ERR (CC_BSV_BASE_ERROR + 0x00000014)
+/*! APB privilege mode is locked. */
+#define CC_BSV_APB_PRIVILEG_IS_LOCKED_ERR (CC_BSV_BASE_ERROR + 0x00000015)
+/*! Illegal operation. */
+#define CC_BSV_ILLEGAL_OPERATION_ERR (CC_BSV_BASE_ERROR + 0x00000016)
+/*! Illegal asset size. */
+#define CC_BSV_ILLEGAL_ASSET_SIZE_ERR (CC_BSV_BASE_ERROR + 0x00000017)
+/*! Illegal asset value. */
+#define CC_BSV_ILLEGAL_ASSET_VAL_ERR (CC_BSV_BASE_ERROR + 0x00000018)
+/*! Kpicv is locked. */
+#define CC_BSV_KPICV_IS_LOCKED_ERR (CC_BSV_BASE_ERROR + 0x00000019)
+/*! Illegal SW version. */
+#define CC_BSV_ILLEGAL_SW_VERSION_ERR (CC_BSV_BASE_ERROR + 0x0000001A)
+/*! AO write operation. */
+#define CC_BSV_AO_WRITE_FAILED_ERR (CC_BSV_BASE_ERROR + 0x0000001B)
+/*! Chip state is already initialized. */
+#define CC_BSV_CHIP_INITIALIZED_ERR (CC_BSV_BASE_ERROR + 0x0000001C)
+/*! SP is not enabled. */
+#define CC_BSV_SP_NOT_ENABLED_ERR (CC_BSV_BASE_ERROR + 0x0000001D)
+/*! Production secure provisioning - header fields. */
+#define CC_BSV_PROD_PKG_HEADER_ERR (CC_BSV_BASE_ERROR + 0x0000001E)
+/*! Production secure provisioning - header MAC. */
+#define CC_BSV_PROD_PKG_HEADER_MAC_ERR (CC_BSV_BASE_ERROR + 0x0000001F)
+/*! Overrun buffer or size. */
+#define CC_BSV_OVERRUN_ERR (CC_BSV_BASE_ERROR + 0x00000020)
+/*! Kceicv is locked. */
+#define CC_BSV_KCEICV_IS_LOCKED_ERR (CC_BSV_BASE_ERROR + 0x00000021)
+/*! Chip indication is CHIP_STATE_ERROR. */
+#define CC_BSV_CHIP_INDICATION_ERR (CC_BSV_BASE_ERROR + 0x00000022)
+/*! Device is locked in fatal error state. */
+#define CC_BSV_FATAL_ERR_IS_LOCKED_ERR (CC_BSV_BASE_ERROR + 0x00000023)
+/*! Device has security disable feature enabled. */
+#define CC_BSV_SECURE_DISABLE_ERROR (CC_BSV_BASE_ERROR + 0x00000024)
+/*! Device has Kcst in disabled state */
+#define CC_BSV_KCST_DISABLE_ERROR (CC_BSV_BASE_ERROR + 0x00000025)
+
+
+/*! Illegal data-in pointer. */
+#define CC_BSV_CRYPTO_INVALID_DATA_IN_POINTER_ERROR (CC_BSV_CRYPTO_ERROR + 0x00000001)
+/*! Illegal data-out pointer. */
+#define CC_BSV_CRYPTO_INVALID_DATA_OUT_POINTER_ERROR (CC_BSV_CRYPTO_ERROR + 0x00000002)
+/*! Illegal data size. */
+#define CC_BSV_CRYPTO_INVALID_DATA_SIZE_ERROR (CC_BSV_CRYPTO_ERROR + 0x00000003)
+/*! Illegal key type. */
+#define CC_BSV_CRYPTO_INVALID_KEY_TYPE_ERROR (CC_BSV_CRYPTO_ERROR + 0x00000004)
+/*! Illegal key size. */
+#define CC_BSV_CRYPTO_INVALID_KEY_SIZE_ERROR (CC_BSV_CRYPTO_ERROR + 0x00000005)
+/*! Invalid key pointer. */
+#define CC_BSV_CRYPTO_INVALID_KEY_POINTER_ERROR (CC_BSV_CRYPTO_ERROR + 0x00000006)
+/*! Illegal key DMA type. */
+#define CC_BSV_CRYPTO_INVALID_KEY_DMA_TYPE_ERROR (CC_BSV_CRYPTO_ERROR + 0x00000007)
+/*! Illegal IV pointer. */
+#define CC_BSV_CRYPTO_INVALID_IV_POINTER_ERROR (CC_BSV_CRYPTO_ERROR + 0x00000008)
+/*! Illegal cipher mode. */
+#define CC_BSV_CRYPTO_INVALID_CIPHER_MODE_ERROR (CC_BSV_CRYPTO_ERROR + 0x00000009)
+/*! Illegal result buffer pointer. */
+#define CC_BSV_CRYPTO_INVALID_RESULT_BUFFER_POINTER_ERROR (CC_BSV_CRYPTO_ERROR + 0x0000000A)
+/*! Invalid DMA type. */
+#define CC_BSV_CRYPTO_INVALID_DMA_TYPE_ERROR (CC_BSV_CRYPTO_ERROR + 0x0000000B)
+/*! Invalid in/out buffers overlapping. */
+#define CC_BSV_CRYPTO_DATA_OUT_DATA_IN_OVERLAP_ERROR (CC_BSV_CRYPTO_ERROR + 0x0000000C)
+/*! Invalid KDF label size. */
+#define CC_BSV_CRYPTO_ILLEGAL_KDF_LABEL_ERROR (CC_BSV_CRYPTO_ERROR + 0x0000000D)
+/*! Invalid KDF Context size. */
+#define CC_BSV_CRYPTO_ILLEGAL_KDF_CONTEXT_ERROR (CC_BSV_CRYPTO_ERROR + 0x0000000E)
+/*! Invalid CCM key. */
+#define CC_BSV_CCM_INVALID_KEY_ERROR (CC_BSV_CRYPTO_ERROR + 0x0000000f)
+/*! Invalid CCM Nonce. */
+#define CC_BSV_CCM_INVALID_NONCE_ERROR (CC_BSV_CRYPTO_ERROR + 0x00000010)
+/*! Invalid CCM associated data. */
+#define CC_BSV_CCM_INVALID_ASSOC_DATA_ERROR (CC_BSV_CRYPTO_ERROR + 0x00000011)
+/*! Invalid CCM text data. */
+#define CC_BSV_CCM_INVALID_TEXT_DATA_ERROR (CC_BSV_CRYPTO_ERROR + 0x00000012)
+/*! Invalid CCM-MAC buffer. */
+#define CC_BSV_CCM_INVALID_MAC_BUF_ERROR (CC_BSV_CRYPTO_ERROR + 0x00000013)
+/*! CCM-MAC comparison failed. */
+#define CC_BSV_CCM_TAG_LENGTH_ERROR (CC_BSV_CRYPTO_ERROR + 0x00000014)
+/*! CCM-MAC comparison failed. */
+#define CC_BSV_CCM_MAC_INVALID_ERROR (CC_BSV_CRYPTO_ERROR + 0x00000015)
+/*! Illegal flow mode. */
+#define CC_BSV_CRYPTO_INVALID_FLOW_MODE_ERROR (CC_BSV_CRYPTO_ERROR + 0x00000016)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/**
+@}
+ */
+
+
+
diff --git a/include/drivers/arm/cryptocell/713/cc_address_defs.h b/include/drivers/arm/cryptocell/713/cc_address_defs.h
new file mode 100644
index 0000000..0abc15c
--- /dev/null
+++ b/include/drivers/arm/cryptocell/713/cc_address_defs.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017-2020 ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _CC_ADDRESS_DEFS_H
+#define _CC_ADDRESS_DEFS_H
+
+/*!
+@file
+@brief This file contains general definitions.
+*/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "cc_pal_types.h"
+
+/************************ Defines ******************************/
+
+/**
+ * Address types within CC
+ */
+/*! 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 uint64_t CCAddr_t;
+/*! Definition of CC SRAM address type, can be 32 bits according to CryptoCell's HW. */
+typedef uint32_t CCSramAddr_t;
+
+/*
+ * CCSramAddr_t is being cast into pointer type which can be 64 bit.
+ */
+/*! Definition of MACRO that casts SRAM addresses to pointer types. */
+#define CCSramAddr2Ptr(sramAddr) ((uintptr_t)sramAddr)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/**
+ @}
+ */
+
+
diff --git a/include/drivers/arm/cryptocell/713/cc_boot_defs.h b/include/drivers/arm/cryptocell/713/cc_boot_defs.h
new file mode 100644
index 0000000..4d29a6d
--- /dev/null
+++ b/include/drivers/arm/cryptocell/713/cc_boot_defs.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017-2020 ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _CC_BOOT_DEFS_H
+#define _CC_BOOT_DEFS_H
+
+/*!
+ @file
+ @brief This file contains general definitions of types and enums of Boot APIs.
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*! Version counters value. */
+typedef enum {
+
+ CC_SW_VERSION_TRUSTED = 0, /*!< Trusted counter. */
+ CC_SW_VERSION_NON_TRUSTED, /*!< Non trusted counter. */
+ CC_SW_VERSION_MAX = 0x7FFFFFFF /*!< Reserved */
+} CCSbSwVersionId_t;
+
+/*! The hash boot key definition. */
+typedef enum {
+ CC_SB_HASH_BOOT_KEY_0_128B = 0, /*!< Hbk0: 128-bit truncated SHA-256 digest of PubKB0. Used by ICV */
+ CC_SB_HASH_BOOT_KEY_1_128B = 1, /*!< Hbk1: 128-bit truncated SHA-256 digest of PubKB1. Used by OEM */
+ CC_SB_HASH_BOOT_KEY_256B = 2, /*!< Hbk: 256-bit SHA-256 digest of public key. */
+ CC_SB_HASH_BOOT_NOT_USED = 0xF, /*!< Hbk is not used. */
+ CC_SB_HASH_MAX_NUM = 0x7FFFFFFF, /*!< Reserved. */
+} CCSbPubKeyIndexType_t;
+
+/*! Chip state. */
+typedef enum {
+ CHIP_STATE_NOT_INITIALIZED = 0, /*! Chip is not initialized. */
+ CHIP_STATE_TEST = 1, /*! Chip is in Production state. */
+ CHIP_STATE_PRODUCTION = 2, /*! Chip is in Production state. */
+ CHIP_STATE_ERROR = 3, /*! Chip is in Error state. */
+} CCBsvChipState_t;
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*_CC_BOOT_DEFS_H */
+
+/**
+@}
+ */
diff --git a/include/drivers/arm/cryptocell/713/cc_pal_types.h b/include/drivers/arm/cryptocell/713/cc_pal_types.h
new file mode 100644
index 0000000..4ab3960
--- /dev/null
+++ b/include/drivers/arm/cryptocell/713/cc_pal_types.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017-2020 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 of the PAL layer.
+
+@defgroup cc_pal_types CryptoCell platform-dependent PAL layer definitions and types
+@{
+@ingroup cc_pal
+
+ @{
+ @ingroup cc_pal
+ @}
+*/
+
+#include "cc_pal_types_plat.h"
+
+/*! Definition of Boolean type.*/
+typedef enum {
+ /*! Boolean false.*/
+ CC_FALSE = 0,
+ /*! Boolean true.*/
+ CC_TRUE = 1
+} CCBool_t;
+
+/*! Success. */
+#define CC_SUCCESS 0UL
+/*! Failure. */
+#define CC_FAIL 1UL
+
+/*! Success (OK). */
+#define CC_OK 0
+
+/*! This macro handles unused parameters in the code, to avoid compilation warnings. */
+#define CC_UNUSED_PARAM(prm) ((void)prm)
+
+/*! The maximal uint32 value.*/
+#define CC_MAX_UINT32_VAL (0xFFFFFFFF)
+
+
+/* Minimal and Maximal macros */
+#ifdef min
+/*! Definition for minimal calculation. */
+#define CC_MIN(a,b) min( a , b )
+#else
+/*! Definition for minimal calculation. */
+#define CC_MIN( a , b ) ( ( (a) < (b) ) ? (a) : (b) )
+#endif
+
+#ifdef max
+/*! Definition for maximal calculation. */
+#define CC_MAX(a,b) max( a , b )
+#else
+/*! Definition for maximal calculation.. */
+#define CC_MAX( a , b ) ( ( (a) > (b) ) ? (a) : (b) )
+#endif
+
+/*! This macro calculates the number of full Bytes from bits, where seven bits are one Byte. */
+#define CALC_FULL_BYTES(numBits) ((numBits)/CC_BITS_IN_BYTE + (((numBits) & (CC_BITS_IN_BYTE-1)) > 0))
+/*! This macro calculates the number of full 32-bit words from bits where 31 bits are one word. */
+#define CALC_FULL_32BIT_WORDS(numBits) ((numBits)/CC_BITS_IN_32BIT_WORD + (((numBits) & (CC_BITS_IN_32BIT_WORD-1)) > 0))
+/*! This macro calculates the number of full 32-bit words from Bytes where three Bytes are one word. */
+#define CALC_32BIT_WORDS_FROM_BYTES(sizeBytes) ((sizeBytes)/CC_32BIT_WORD_SIZE + (((sizeBytes) & (CC_32BIT_WORD_SIZE-1)) > 0))
+/*! This macro calculates the number of full 32-bit words from 64-bits dwords. */
+#define CALC_32BIT_WORDS_FROM_64BIT_DWORD(sizeWords) (sizeWords * CC_32BIT_WORD_IN_64BIT_DWORD)
+/*! This macro rounds up bits to 32-bit words. */
+#define ROUNDUP_BITS_TO_32BIT_WORD(numBits) (CALC_FULL_32BIT_WORDS(numBits) * CC_BITS_IN_32BIT_WORD)
+/*! This macro rounds up bits to Bytes. */
+#define ROUNDUP_BITS_TO_BYTES(numBits) (CALC_FULL_BYTES(numBits) * CC_BITS_IN_BYTE)
+/*! This macro rounds up bytes to 32-bit words. */
+#define ROUNDUP_BYTES_TO_32BIT_WORD(sizeBytes) (CALC_32BIT_WORDS_FROM_BYTES(sizeBytes) * CC_32BIT_WORD_SIZE)
+/*! This macro calculates the number Bytes from words. */
+#define CALC_WORDS_TO_BYTES(numwords) ((numwords)*CC_32BIT_WORD_SIZE)
+/*! Definition of 1 KB in Bytes. */
+#define CC_1K_SIZE_IN_BYTES 1024
+/*! Definition of number of bits in a Byte. */
+#define CC_BITS_IN_BYTE 8
+/*! Definition of number of bits in a 32-bits word. */
+#define CC_BITS_IN_32BIT_WORD 32
+/*! Definition of number of Bytes in a 32-bits word. */
+#define CC_32BIT_WORD_SIZE 4
+/*! Definition of number of 32-bits words in a 64-bits dword. */
+#define CC_32BIT_WORD_IN_64BIT_DWORD 2
+
+
+#endif
+
+/**
+@}
+ */
+
+
+
diff --git a/include/drivers/arm/cryptocell/713/cc_pal_types_plat.h b/include/drivers/arm/cryptocell/713/cc_pal_types_plat.h
new file mode 100644
index 0000000..9848472
--- /dev/null
+++ b/include/drivers/arm/cryptocell/713/cc_pal_types_plat.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017-2020, 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 <stddef.h>
+#include <stdint.h>
+
+typedef uint32_t CCStatus;
+
+#define CCError_t CCStatus
+#define CC_INFINITE 0xFFFFFFFF
+
+#define CEXPORT_C
+#define CIMPORT_C
+
+#endif /*_CC_PAL_TYPES_PLAT_H*/
diff --git a/include/drivers/arm/cryptocell/713/cc_pka_hw_plat_defs.h b/include/drivers/arm/cryptocell/713/cc_pka_hw_plat_defs.h
new file mode 100644
index 0000000..1a1bce0
--- /dev/null
+++ b/include/drivers/arm/cryptocell/713/cc_pka_hw_plat_defs.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017-2020 ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _CC_PKA_HW_PLAT_DEFS_H
+#define _CC_PKA_HW_PLAT_DEFS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+#include "cc_pal_types.h"
+/*!
+@file
+@brief Contains the enums and definitions that are used in the PKA code (definitions that are platform dependent).
+*/
+
+/*! The size of the PKA engine word. */
+#define CC_PKA_WORD_SIZE_IN_BITS 128
+
+/*! The maximal supported size of modulus in RSA in bits. */
+#define CC_RSA_MAX_VALID_KEY_SIZE_VALUE_IN_BITS 4096
+/*! The maximal supported size of key-generation in RSA in bits. */
+#define CC_RSA_MAX_KEY_GENERATION_HW_SIZE_BITS 4096
+
+/*! Secure boot/debug certificate RSA public modulus key size in bits. */
+#if (KEY_SIZE == 3072)
+ #define BSV_CERT_RSA_KEY_SIZE_IN_BITS 3072
+#else
+ #define BSV_CERT_RSA_KEY_SIZE_IN_BITS 2048
+#endif
+/*! Secure boot/debug certificate RSA public modulus key size in bytes. */
+#define BSV_CERT_RSA_KEY_SIZE_IN_BYTES (BSV_CERT_RSA_KEY_SIZE_IN_BITS/CC_BITS_IN_BYTE)
+/*! Secure boot/debug certificate RSA public modulus key size in words. */
+#define BSV_CERT_RSA_KEY_SIZE_IN_WORDS (BSV_CERT_RSA_KEY_SIZE_IN_BITS/CC_BITS_IN_32BIT_WORD)
+
+/*! The maximal count of extra bits in PKA operations. */
+#define PKA_EXTRA_BITS 8
+/*! The number of memory registers in PKA operations. */
+#define PKA_MAX_COUNT_OF_PHYS_MEM_REGS 32
+
+/*! Size of buffer for Barrett modulus tag in words. */
+#define RSA_PKA_BARRETT_MOD_TAG_BUFF_SIZE_IN_WORDS 5
+/*! Size of buffer for Barrett modulus tag in bytes. */
+#define RSA_PKA_BARRETT_MOD_TAG_BUFF_SIZE_IN_BYTES (RSA_PKA_BARRETT_MOD_TAG_BUFF_SIZE_IN_WORDS*CC_32BIT_WORD_SIZE)
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_CC_PKA_HW_PLAT_DEFS_H
+
+/**
+ @}
+ */
+
diff --git a/include/drivers/arm/cryptocell/713/cc_sec_defs.h b/include/drivers/arm/cryptocell/713/cc_sec_defs.h
new file mode 100644
index 0000000..8fb698f
--- /dev/null
+++ b/include/drivers/arm/cryptocell/713/cc_sec_defs.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017-2020 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 definitions and types.
+*/
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "cc_pal_types.h"
+
+/*! Hashblock size in words. */
+#define HASH_BLOCK_SIZE_IN_WORDS 16
+/*! Hash - SHA2 results in words. */
+#define HASH_RESULT_SIZE_IN_WORDS 8
+/*! Hash - SHA2 results in bytes. */
+#define HASH_RESULT_SIZE_IN_BYTES 32
+
+/*! Definition for hash result array. */
+typedef uint32_t CCHashResult_t[HASH_RESULT_SIZE_IN_WORDS];
+
+/*! Definition for converting pointer to Host address. */
+#define CONVERT_TO_ADDR(ptr) (unsigned long)ptr
+
+/*! Definition for converting pointer to SRAM address. */
+#define CONVERT_TO_SRAM_ADDR(ptr) (0xFFFFFFFF & ptr)
+
+/*! The data size of the signed SW image, in bytes. */
+/*!\internal ContentCertImageRecord_t includes: HS(8W) + 64-b dstAddr(2W) + imgSize(1W) + isCodeEncUsed(1W) */
+#define SW_REC_SIGNED_DATA_SIZE_IN_BYTES 48
+
+/*! The data size of the unsigned SW image, in bytes. */
+/*!\internal CCSbSwImgAddData_t includes: 64-b srcAddr(2W)*/
+#define SW_REC_NONE_SIGNED_DATA_SIZE_IN_BYTES 8
+
+/*! The additional data size - storage address and length of the unsigned SW image, in words. */
+#define SW_REC_NONE_SIGNED_DATA_SIZE_IN_WORDS SW_REC_NONE_SIGNED_DATA_SIZE_IN_BYTES/CC_32BIT_WORD_SIZE
+
+/*! The additional data section size, in bytes. */
+#define CC_SB_MAX_SIZE_ADDITIONAL_DATA_BYTES 128
+
+/*! Indication of whether or not to load the SW image to memory. */
+#define CC_SW_COMP_NO_MEM_LOAD_INDICATION 0xFFFFFFFFFFFFFFFFUL
+
+/*! Indication of product version, stored in certificate version field. */
+#define CC_SB_CERT_VERSION_PROJ_PRD 0x713
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/**
+@}
+ */
+
+
+
diff --git a/include/drivers/arm/cryptocell/cc_rotpk.h b/include/drivers/arm/cryptocell/cc_rotpk.h
new file mode 100644
index 0000000..9398496
--- /dev/null
+++ b/include/drivers/arm/cryptocell/cc_rotpk.h
@@ -0,0 +1,13 @@
+/*
+ * 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
diff --git a/include/drivers/arm/css/css_mhu.h b/include/drivers/arm/css/css_mhu.h
new file mode 100644
index 0000000..ff04ae4
--- /dev/null
+++ b/include/drivers/arm/css/css_mhu.h
@@ -0,0 +1,19 @@
+/*
+ * 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 <stdint.h>
+
+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 */
diff --git a/include/drivers/arm/css/css_mhu_doorbell.h b/include/drivers/arm/css/css_mhu_doorbell.h
new file mode 100644
index 0000000..88302fd
--- /dev/null
+++ b/include/drivers/arm/css/css_mhu_doorbell.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CSS_MHU_DOORBELL_H
+#define CSS_MHU_DOORBELL_H
+
+#include <stdint.h>
+
+#include <lib/mmio.h>
+
+/* MHUv2 Frame Base Mask */
+#define MHU_V2_FRAME_BASE_MASK UL(~0xFFF)
+
+/* MHUv2 Control Registers Offsets */
+#define MHU_V2_MSG_NO_CAP_OFFSET UL(0xF80)
+#define MHU_V2_ACCESS_REQ_OFFSET UL(0xF88)
+#define MHU_V2_ACCESS_READY_OFFSET UL(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 */
diff --git a/include/drivers/arm/css/css_scp.h b/include/drivers/arm/css/css_scp.h
new file mode 100644
index 0000000..2b506ea
--- /dev/null
+++ b/include/drivers/arm/css/css_scp.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CSS_SCP_H
+#define CSS_SCP_H
+
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <lib/cassert.h>
+
+/* 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 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_FW_CONFIG_LIMIT, assert_scp_bl2_overflow);
+CASSERT(SCP_BL2U_BASE >= ARM_FW_CONFIG_LIMIT, assert_scp_bl2u_overflow);
+#endif
+
+#endif /* CSS_SCP_H */
diff --git a/include/drivers/arm/css/css_scpi.h b/include/drivers/arm/css/css_scpi.h
new file mode 100644
index 0000000..68fc60a
--- /dev/null
+++ b/include/drivers/arm/css/css_scpi.h
@@ -0,0 +1,109 @@
+/*
+ * 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 <stddef.h>
+#include <stdint.h>
+
+/*
+ * 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 */
diff --git a/include/drivers/arm/css/scmi.h b/include/drivers/arm/css/scmi.h
new file mode 100644
index 0000000..9dd08e5
--- /dev/null
+++ b/include/drivers/arm/css/scmi.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SCMI_H
+#define SCMI_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <lib/bakery_lock.h>
+#include <lib/psci/psci.h>
+#include <lib/spinlock.h>
+
+/* Supported SCMI Protocol Versions */
+#define SCMI_AP_CORE_PROTO_VER MAKE_SCMI_VERSION(1, 0)
+#define SCMI_PWR_DMN_PROTO_VER MAKE_SCMI_VERSION(2, 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))
+
+/*
+ * Check that the driver's version is same or higher than the reported SCMI
+ * version. We accept lower major version numbers, as all affected protocols
+ * so far stay backwards compatible. This might need to be revisited in the
+ * future.
+ */
+#define is_scmi_version_compatible(drv, scmi) \
+ ((GET_SCMI_MAJOR_VER(drv) > GET_SCMI_MAJOR_VER(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(int channel_id);
+
+/* 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 */
diff --git a/include/drivers/arm/css/sds.h b/include/drivers/arm/css/sds.h
new file mode 100644
index 0000000..db4cbaa
--- /dev/null
+++ b/include/drivers/arm/css/sds.h
@@ -0,0 +1,90 @@
+/*
+ * 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 <stddef.h>
+#include <stdint.h>
+
+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 */
diff --git a/include/drivers/arm/dcc.h b/include/drivers/arm/dcc.h
new file mode 100644
index 0000000..1f1fd03
--- /dev/null
+++ b/include/drivers/arm/dcc.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2021, Xilinx Inc.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DCC_H
+#define DCC_H
+
+#include <stdint.h>
+#include <drivers/console.h>
+
+/*
+ * Initialize a new dcc console instance and register it with the console
+ * framework.
+ */
+int console_dcc_register(void);
+
+#endif /* DCC */
diff --git a/include/drivers/arm/ethosn.h b/include/drivers/arm/ethosn.h
new file mode 100644
index 0000000..dbaf16c
--- /dev/null
+++ b/include/drivers/arm/ethosn.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ETHOSN_H
+#define ETHOSN_H
+
+#include <lib/smccc.h>
+
+/* Function numbers */
+#define ETHOSN_FNUM_VERSION U(0x50)
+#define ETHOSN_FNUM_IS_SEC U(0x51)
+#define ETHOSN_FNUM_HARD_RESET U(0x52)
+#define ETHOSN_FNUM_SOFT_RESET U(0x53)
+/* 0x54-0x5F reserved for future use */
+
+/* SMC64 function IDs */
+#define ETHOSN_FID_64(func_num) U(0xC2000000 | func_num)
+#define ETHOSN_FID_VERSION_64 ETHOSN_FID_64(ETHOSN_FNUM_VERSION)
+#define ETHOSN_FID_IS_SEC_64 ETHOSN_FID_64(ETHOSN_FNUM_IS_SEC)
+#define ETHOSN_FID_HARD_RESET_64 ETHOSN_FID_64(ETHOSN_FNUM_HARD_RESET)
+#define ETHOSN_FID_SOFT_RESET_64 ETHOSN_FID_64(ETHOSN_FNUM_SOFT_RESET)
+
+/* SMC32 function IDs */
+#define ETHOSN_FID_32(func_num) U(0x82000000 | func_num)
+#define ETHOSN_FID_VERSION_32 ETHOSN_FID_32(ETHOSN_FNUM_VERSION)
+#define ETHOSN_FID_IS_SEC_32 ETHOSN_FID_32(ETHOSN_FNUM_IS_SEC)
+#define ETHOSN_FID_HARD_RESET_32 ETHOSN_FID_32(ETHOSN_FNUM_HARD_RESET)
+#define ETHOSN_FID_SOFT_RESET_32 ETHOSN_FID_32(ETHOSN_FNUM_SOFT_RESET)
+
+#define ETHOSN_NUM_SMC_CALLS 8
+
+/* Macro to identify function calls */
+#define ETHOSN_FID_MASK U(0xFFF0)
+#define ETHOSN_FID_VALUE U(0x50)
+#define is_ethosn_fid(_fid) (((_fid) & ETHOSN_FID_MASK) == ETHOSN_FID_VALUE)
+
+/* Service version */
+#define ETHOSN_VERSION_MAJOR U(2)
+#define ETHOSN_VERSION_MINOR U(0)
+
+/* Return codes for function calls */
+#define ETHOSN_SUCCESS 0
+#define ETHOSN_NOT_SUPPORTED -1
+/* -2 Reserved for NOT_REQUIRED */
+/* -3 Reserved for INVALID_PARAMETER */
+#define ETHOSN_FAILURE -4
+#define ETHOSN_UNKNOWN_CORE_ADDRESS -5
+#define ETHOSN_UNKNOWN_ALLOCATOR_IDX -6
+
+uintptr_t ethosn_smc_handler(uint32_t smc_fid,
+ u_register_t core_addr,
+ u_register_t asset_alloc_idx,
+ u_register_t x3,
+ u_register_t x4,
+ void *cookie,
+ void *handle,
+ u_register_t flags);
+
+#endif /* ETHOSN_H */
diff --git a/include/drivers/arm/fvp/fvp_pwrc.h b/include/drivers/arm/fvp/fvp_pwrc.h
new file mode 100644
index 0000000..39e2516
--- /dev/null
+++ b/include/drivers/arm/fvp/fvp_pwrc.h
@@ -0,0 +1,55 @@
+/*
+ * 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 <stdint.h>
+
+/*******************************************************************************
+ * 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 */
diff --git a/include/drivers/arm/gic600_multichip.h b/include/drivers/arm/gic600_multichip.h
new file mode 100644
index 0000000..bda406b
--- /dev/null
+++ b/include/drivers/arm/gic600_multichip.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GIC600_MULTICHIP_H
+#define GIC600_MULTICHIP_H
+
+#include <stdint.h>
+
+/*
+ * GIC-600 microarchitecture supports coherent multichip environments containing
+ * up to 16 chips.
+ */
+#define GIC600_MAX_MULTICHIP 16
+
+/* SPI IDs array consist of min and max ids */
+#define GIC600_SPI_IDS_SIZE 2
+
+/*******************************************************************************
+ * GIC-600 multichip data structure describes platform specific attributes
+ * related to GIC-600 multichip. Platform port is expected to define these
+ * attributes to initialize the multichip related registers and create
+ * successful connections between the GIC-600s in a multichip system.
+ *
+ * The 'rt_owner_base' field contains the base address of the GIC Distributor
+ * which owns the routing table.
+ *
+ * The 'rt_owner' field contains the chip number which owns the routing table.
+ * Chip number or chip_id starts from 0.
+ *
+ * The 'chip_count' field contains the total number of chips in a multichip
+ * system. This should match the number of entries in 'chip_addrs' and 'spi_ids'
+ * fields.
+ *
+ * The 'chip_addrs' field contains array of chip addresses. These addresses are
+ * implementation specific values.
+ *
+ * The 'spi_ids' field contains array of minimum and maximum SPI interrupt ids
+ * that each chip owns. Note that SPI interrupt ids can range from 32 to 960 and
+ * it should be group of 32 (i.e., SPI minimum and (SPI maximum + 1) should be
+ * a multiple of 32). If a chip doesn't own any SPI interrupts a value of {0, 0}
+ * should be passed.
+ ******************************************************************************/
+struct gic600_multichip_data {
+ uintptr_t rt_owner_base;
+ unsigned int rt_owner;
+ unsigned int chip_count;
+ uint64_t chip_addrs[GIC600_MAX_MULTICHIP];
+ unsigned int spi_ids[GIC600_MAX_MULTICHIP][GIC600_SPI_IDS_SIZE];
+};
+
+void gic600_multichip_init(struct gic600_multichip_data *multichip_data);
+#endif /* GIC600_MULTICHIP_H */
diff --git a/include/drivers/arm/gic600ae_fmu.h b/include/drivers/arm/gic600ae_fmu.h
new file mode 100644
index 0000000..88b87b9
--- /dev/null
+++ b/include/drivers/arm/gic600ae_fmu.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2021-2022, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GIC600AE_FMU_H
+#define GIC600AE_FMU_H
+
+/*******************************************************************************
+ * GIC600-AE FMU register offsets and constants
+ ******************************************************************************/
+#define GICFMU_ERRFR_LO U(0x000)
+#define GICFMU_ERRFR_HI U(0x004)
+#define GICFMU_ERRCTLR_LO U(0x008)
+#define GICFMU_ERRCTLR_HI U(0x00C)
+#define GICFMU_ERRSTATUS_LO U(0x010)
+#define GICFMU_ERRSTATUS_HI U(0x014)
+#define GICFMU_ERRGSR_LO U(0xE00)
+#define GICFMU_ERRGSR_HI U(0xE04)
+#define GICFMU_KEY U(0xEA0)
+#define GICFMU_PINGCTLR U(0xEA4)
+#define GICFMU_PINGNOW U(0xEA8)
+#define GICFMU_SMEN U(0xEB0)
+#define GICFMU_SMINJERR U(0xEB4)
+#define GICFMU_PINGMASK_LO U(0xEC0)
+#define GICFMU_PINGMASK_HI U(0xEC4)
+#define GICFMU_STATUS U(0xF00)
+#define GICFMU_ERRIDR U(0xFC8)
+
+/* ERRCTLR bits */
+#define FMU_ERRCTLR_ED_BIT BIT(0)
+#define FMU_ERRCTLR_CE_EN_BIT BIT(1)
+#define FMU_ERRCTLR_UI_BIT BIT(2)
+#define FMU_ERRCTLR_CI_BIT BIT(3)
+
+/* SMEN constants */
+#define FMU_SMEN_BLK_SHIFT U(8)
+#define FMU_SMEN_SMID_SHIFT U(24)
+#define FMU_SMEN_EN_BIT BIT(0)
+
+/* Error record IDs */
+#define FMU_BLK_GICD U(0)
+#define FMU_BLK_SPICOL U(1)
+#define FMU_BLK_WAKERQ U(2)
+#define FMU_BLK_ITS0 U(4)
+#define FMU_BLK_ITS1 U(5)
+#define FMU_BLK_ITS2 U(6)
+#define FMU_BLK_ITS3 U(7)
+#define FMU_BLK_ITS4 U(8)
+#define FMU_BLK_ITS5 U(9)
+#define FMU_BLK_ITS6 U(10)
+#define FMU_BLK_ITS7 U(11)
+#define FMU_BLK_PPI0 U(12)
+#define FMU_BLK_PPI1 U(13)
+#define FMU_BLK_PPI2 U(14)
+#define FMU_BLK_PPI3 U(15)
+#define FMU_BLK_PPI4 U(16)
+#define FMU_BLK_PPI5 U(17)
+#define FMU_BLK_PPI6 U(18)
+#define FMU_BLK_PPI7 U(19)
+#define FMU_BLK_PPI8 U(20)
+#define FMU_BLK_PPI9 U(21)
+#define FMU_BLK_PPI10 U(22)
+#define FMU_BLK_PPI11 U(23)
+#define FMU_BLK_PPI12 U(24)
+#define FMU_BLK_PPI13 U(25)
+#define FMU_BLK_PPI14 U(26)
+#define FMU_BLK_PPI15 U(27)
+#define FMU_BLK_PPI16 U(28)
+#define FMU_BLK_PPI17 U(29)
+#define FMU_BLK_PPI18 U(30)
+#define FMU_BLK_PPI19 U(31)
+#define FMU_BLK_PPI20 U(32)
+#define FMU_BLK_PPI21 U(33)
+#define FMU_BLK_PPI22 U(34)
+#define FMU_BLK_PPI23 U(35)
+#define FMU_BLK_PPI24 U(36)
+#define FMU_BLK_PPI25 U(37)
+#define FMU_BLK_PPI26 U(38)
+#define FMU_BLK_PPI27 U(39)
+#define FMU_BLK_PPI28 U(40)
+#define FMU_BLK_PPI29 U(41)
+#define FMU_BLK_PPI30 U(42)
+#define FMU_BLK_PPI31 U(43)
+#define FMU_BLK_PRESENT_MASK U(0xFFFFFFFFFFF)
+
+/* Safety Mechamism limit */
+#define FMU_SMID_GICD_MAX U(33)
+#define FMU_SMID_PPI_MAX U(12)
+#define FMU_SMID_ITS_MAX U(14)
+#define FMU_SMID_SPICOL_MAX U(5)
+#define FMU_SMID_WAKERQ_MAX U(2)
+
+/* MBIST Safety Mechanism ID */
+#define GICD_MBIST_REQ_ERROR U(23)
+#define GICD_FMU_CLKGATE_ERROR U(33)
+#define PPI_MBIST_REQ_ERROR U(10)
+#define PPI_FMU_CLKGATE_ERROR U(12)
+#define ITS_MBIST_REQ_ERROR U(13)
+#define ITS_FMU_CLKGATE_ERROR U(14)
+
+/* ERRSTATUS bits */
+#define FMU_ERRSTATUS_BLKID_SHIFT U(32)
+#define FMU_ERRSTATUS_BLKID_MASK U(0xFF)
+#define FMU_ERRSTATUS_V_BIT BIT(30)
+#define FMU_ERRSTATUS_UE_BIT BIT(29)
+#define FMU_ERRSTATUS_OV_BIT BIT(27)
+#define FMU_ERRSTATUS_CE_BITS (BIT(25) | BIT(24))
+#define FMU_ERRSTATUS_CLEAR (FMU_ERRSTATUS_V_BIT | FMU_ERRSTATUS_UE_BIT | \
+ FMU_ERRSTATUS_OV_BIT | FMU_ERRSTATUS_CE_BITS)
+#define FMU_ERRSTATUS_IERR_MASK U(0xFF)
+#define FMU_ERRSTATUS_IERR_SHIFT U(8)
+#define FMU_ERRSTATUS_SERR_MASK U(0xFF)
+
+/* PINGCTLR constants */
+#define FMU_PINGCTLR_INTDIFF_SHIFT U(16)
+#define FMU_PINGCTLR_TIMEOUTVAL_SHIFT U(4)
+#define FMU_PINGCTLR_EN_BIT BIT(0)
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+
+/*******************************************************************************
+ * GIC600 FMU EL3 driver API
+ ******************************************************************************/
+uint64_t gic_fmu_read_errfr(uintptr_t base, unsigned int n);
+uint64_t gic_fmu_read_errctlr(uintptr_t base, unsigned int n);
+uint64_t gic_fmu_read_errstatus(uintptr_t base, unsigned int n);
+uint64_t gic_fmu_read_errgsr(uintptr_t base);
+uint32_t gic_fmu_read_pingctlr(uintptr_t base);
+uint32_t gic_fmu_read_pingnow(uintptr_t base);
+uint64_t gic_fmu_read_pingmask(uintptr_t base);
+uint32_t gic_fmu_read_status(uintptr_t base);
+uint32_t gic_fmu_read_erridr(uintptr_t base);
+void gic_fmu_write_errctlr(uintptr_t base, unsigned int n, uint64_t val);
+void gic_fmu_write_errstatus(uintptr_t base, unsigned int n, uint64_t val);
+void gic_fmu_write_pingctlr(uintptr_t base, uint32_t val);
+void gic_fmu_write_pingnow(uintptr_t base, uint32_t val);
+void gic_fmu_write_smen(uintptr_t base, uint32_t val);
+void gic_fmu_write_sminjerr(uintptr_t base, uint32_t val);
+void gic_fmu_write_pingmask(uintptr_t base, uint64_t val);
+void gic_fmu_disable_all_sm_blkid(uintptr_t base, unsigned int blkid);
+
+void gic600_fmu_init(uint64_t base, uint64_t blk_present_mask, bool errctlr_ce_en, bool errctlr_ue_en);
+void gic600_fmu_enable_ping(uint64_t base, uint64_t blk_present_mask,
+ unsigned int timeout_val, unsigned int interval_diff);
+void gic600_fmu_print_sm_info(uint64_t base, unsigned int blk, unsigned int smid);
+int gic600_fmu_probe(uint64_t base, int *probe_data);
+int gic600_fmu_ras_handler(uint64_t base, int probe_data);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* GIC600AE_FMU_H */
diff --git a/include/drivers/arm/gic_common.h b/include/drivers/arm/gic_common.h
new file mode 100644
index 0000000..dc23721
--- /dev/null
+++ b/include/drivers/arm/gic_common.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GIC_COMMON_H
+#define GIC_COMMON_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * 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)
+
+/*******************************************************************************
+ * Common GIC Distributor interface register offsets
+ ******************************************************************************/
+#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)
+
+/*******************************************************************************
+ * Common GIC Distributor interface register constants
+ ******************************************************************************/
+#define PIDR2_ARCH_REV_SHIFT 4
+#define PIDR2_ARCH_REV_MASK U(0xf)
+
+/* GIC revision as reported by PIDR2.ArchRev register field */
+#define ARCH_REV_GICV1 U(0x1)
+#define ARCH_REV_GICV2 U(0x2)
+#define ARCH_REV_GICV3 U(0x3)
+#define ARCH_REV_GICV4 U(0x4)
+
+#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 */
diff --git a/include/drivers/arm/gicv2.h b/include/drivers/arm/gicv2.h
new file mode 100644
index 0000000..cfc168d
--- /dev/null
+++ b/include/drivers/arm/gicv2.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Portions copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GICV2_H
+#define GICV2_H
+
+#include <drivers/arm/gic_common.h>
+#include <platform_def.h>
+
+/*******************************************************************************
+ * 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)
+
+/*
+ * Some GICv2 implementations violate the specification and have this register
+ * at a different address. Allow overriding it in platform_def.h as workaround.
+ */
+#ifndef GICD_PIDR2_GICV2
+#define GICD_PIDR2_GICV2 U(0xFE8)
+#endif
+
+#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_NSATT (U(0x1) << 16)
+#define SGIR_INTID_MASK ULL(0xf)
+
+#define SGIR_TGT_SPECIFIC U(0)
+
+#define GICV2_SGIR_VALUE(tgt_lst_flt, tgt, nsatt, intid) \
+ ((((tgt_lst_flt) & SGIR_TGTLSTFLT_MASK) << SGIR_TGTLSTFLT_SHIFT) | \
+ (((tgt) & SGIR_TGTLST_MASK) << SGIR_TGTLST_SHIFT) | \
+ ((nsatt) ? SGIR_NSATT : U(0)) | \
+ ((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 <cdefs.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <common/interrupt_props.h>
+
+/*******************************************************************************
+ * 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, bool ns, 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 */
diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h
new file mode 100644
index 0000000..5bb22fd
--- /dev/null
+++ b/include/drivers/arm/gicv3.h
@@ -0,0 +1,605 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GICV3_H
+#define GICV3_H
+
+/*******************************************************************************
+ * GICv3 and 3.1 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)
+
+/* PPIs INTIDs 16-31 */
+#define MAX_PPI_ID U(31)
+
+#if GIC_EXT_INTID
+
+/* GICv3.1 extended PPIs INTIDs 1056-1119 */
+#define MIN_EPPI_ID U(1056)
+#define MAX_EPPI_ID U(1119)
+
+/* Total number of GICv3.1 EPPIs */
+#define TOTAL_EPPI_INTR_NUM (MAX_EPPI_ID - MIN_EPPI_ID + U(1))
+
+/* Total number of GICv3.1 PPIs and EPPIs */
+#define TOTAL_PRIVATE_INTR_NUM (TOTAL_PCPU_INTR_NUM + TOTAL_EPPI_INTR_NUM)
+
+/* GICv3.1 extended SPIs INTIDs 4096 - 5119 */
+#define MIN_ESPI_ID U(4096)
+#define MAX_ESPI_ID U(5119)
+
+/* Total number of GICv3.1 ESPIs */
+#define TOTAL_ESPI_INTR_NUM (MAX_ESPI_ID - MIN_ESPI_ID + U(1))
+
+/* Total number of GICv3.1 SPIs and ESPIs */
+#define TOTAL_SHARED_INTR_NUM (TOTAL_SPI_INTR_NUM + TOTAL_ESPI_INTR_NUM)
+
+/* SGIs: 0-15, PPIs: 16-31, EPPIs: 1056-1119 */
+#define IS_SGI_PPI(id) (((id) <= MAX_PPI_ID) || \
+ (((id) >= MIN_EPPI_ID) && \
+ ((id) <= MAX_EPPI_ID)))
+
+/* SPIs: 32-1019, ESPIs: 4096-5119 */
+#define IS_SPI(id) ((((id) >= MIN_SPI_ID) && \
+ ((id) <= MAX_SPI_ID)) || \
+ (((id) >= MIN_ESPI_ID) && \
+ ((id) <= MAX_ESPI_ID)))
+#else /* GICv3 */
+
+/* Total number of GICv3 PPIs */
+#define TOTAL_PRIVATE_INTR_NUM TOTAL_PCPU_INTR_NUM
+
+/* Total number of GICv3 SPIs */
+#define TOTAL_SHARED_INTR_NUM TOTAL_SPI_INTR_NUM
+
+/* SGIs: 0-15, PPIs: 16-31 */
+#define IS_SGI_PPI(id) ((id) <= MAX_PPI_ID)
+
+/* SPIs: 32-1019 */
+#define IS_SPI(id) (((id) >= MIN_SPI_ID) && ((id) <= MAX_SPI_ID))
+
+#endif /* GIC_EXT_INTID */
+
+#define GIC_REV(r, p) ((r << 4) | p)
+
+/*******************************************************************************
+ * GICv3 and 3.1 specific Distributor interface register offsets and constants
+ ******************************************************************************/
+#define GICD_TYPER2 U(0x0c)
+#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(0x58)
+#define GICD_IGRPMODR U(0xd00)
+#define GICD_IGROUPRE U(0x1000)
+#define GICD_ISENABLERE U(0x1200)
+#define GICD_ICENABLERE U(0x1400)
+#define GICD_ISPENDRE U(0x1600)
+#define GICD_ICPENDRE U(0x1800)
+#define GICD_ISACTIVERE U(0x1a00)
+#define GICD_ICACTIVERE U(0x1c00)
+#define GICD_IPRIORITYRE U(0x2000)
+#define GICD_ICFGRE U(0x3000)
+#define GICD_IGRPMODRE U(0x3400)
+#define GICD_NSACRE U(0x3600)
+/*
+ * GICD_IROUTER<n> 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_IROUTERE U(0x8000)
+
+#define GICD_PIDR0_GICV3 U(0xffe0)
+#define GICD_PIDR1_GICV3 U(0xffe4)
+#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
+
+/* GICD_TYPER shifts and masks */
+#define TYPER_ESPI U(1 << 8)
+#define TYPER_DVIS U(1 << 18)
+#define TYPER_ESPI_RANGE_MASK U(0x1f)
+#define TYPER_ESPI_RANGE_SHIFT U(27)
+#define TYPER_ESPI_RANGE U(TYPER_ESPI_MASK << TYPER_ESPI_SHIFT)
+
+/*******************************************************************************
+ * Common GIC Redistributor interface registers & constants
+ ******************************************************************************/
+#define GICR_V4_PCPUBASE_SHIFT 0x12
+#define GICR_V3_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_STATUSR U(0x10)
+#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))
+
+#define GICR_IGROUPR GICR_IGROUPR0
+#define GICR_ISENABLER GICR_ISENABLER0
+#define GICR_ICENABLER GICR_ICENABLER0
+#define GICR_ISPENDR GICR_ISPENDR0
+#define GICR_ICPENDR GICR_ICPENDR0
+#define GICR_ISACTIVER GICR_ISACTIVER0
+#define GICR_ICACTIVER GICR_ICACTIVER0
+#define GICR_ICFGR GICR_ICFGR0
+#define GICR_IGRPMODR GICR_IGRPMODR0
+
+/* 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_DPG1S_SHIFT 26
+#define GICR_CTLR_DPG1S_MASK U(0x1)
+#define GICR_CTLR_DPG1S_BIT BIT_32(GICR_CTLR_DPG1S_SHIFT)
+#define GICR_CTLR_DPG1NS_SHIFT 25
+#define GICR_CTLR_DPG1NS_MASK U(0x1)
+#define GICR_CTLR_DPG1NS_BIT BIT_32(GICR_CTLR_DPG1NS_SHIFT)
+#define GICR_CTLR_DPG0_SHIFT 24
+#define GICR_CTLR_DPG0_MASK U(0x1)
+#define GICR_CTLR_DPG0_BIT BIT_32(GICR_CTLR_DPG0_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_VLPI_SHIFT 1
+
+#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 TYPER_VLPI_BIT BIT_32(TYPER_VLPI_SHIFT)
+
+#define TYPER_PPI_NUM_SHIFT U(27)
+#define TYPER_PPI_NUM_MASK U(0x1f)
+
+/* GICR_IIDR bit definitions */
+#define IIDR_PRODUCT_ID_MASK U(0xff)
+#define IIDR_VARIANT_MASK U(0xf)
+#define IIDR_REV_MASK U(0xf)
+#define IIDR_IMPLEMENTER_MASK U(0xfff)
+#define IIDR_PRODUCT_ID_SHIFT 24
+#define IIDR_VARIANT_SHIFT 16
+#define IIDR_REV_SHIFT 12
+#define IIDR_IMPLEMENTER_SHIFT 0
+#define IIDR_PRODUCT_ID_BIT BIT_32(IIDR_PRODUCT_ID_SHIFT)
+#define IIDR_VARIANT_BIT BIT_32(IIDR_VARIANT_SHIFT)
+#define IIDR_REV_BIT BIT_32(IIDR_REVISION_SHIFT)
+#define IIDR_IMPLEMENTER_BIT BIT_32(IIDR_IMPLEMENTER_SHIFT)
+
+#define IIDR_MODEL_MASK (IIDR_PRODUCT_ID_MASK << IIDR_PRODUCT_ID_SHIFT | \
+ IIDR_IMPLEMENTER_MASK << IIDR_IMPLEMENTER_SHIFT)
+
+#define GIC_PRODUCT_ID_GIC600 U(0x2)
+#define GIC_PRODUCT_ID_GIC600AE U(0x3)
+#define GIC_PRODUCT_ID_GIC700 U(0x4)
+
+/*
+ * Note that below revisions and variants definations are as per GIC600/GIC600AE
+ * specification.
+ */
+#define GIC_REV_P0 U(0x1)
+#define GIC_REV_P1 U(0x3)
+#define GIC_REV_P2 U(0x4)
+#define GIC_REV_P3 U(0x5)
+#define GIC_REV_P4 U(0x6)
+#define GIC_REV_P6 U(0x7)
+
+#define GIC_VARIANT_R0 U(0x0)
+#define GIC_VARIANT_R1 U(0x1)
+#define GIC_VARIANT_R2 U(0x2)
+
+/*******************************************************************************
+ * GICv3 and 3.1 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(0xff)
+
+#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 and 3.1 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_BIT BIT_32(1)
+
+#define GITS_TYPER_VSGI BIT_64(39)
+
+#ifndef __ASSEMBLER__
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/utils_def.h>
+
+typedef enum {
+ GICV3_G1S,
+ GICV3_G1NS,
+ GICV3_G0
+} gicv3_irq_group_t;
+
+static inline uintptr_t gicv3_redist_size(uint64_t typer_val)
+{
+#if GIC_ENABLE_V4_EXTN
+ if ((typer_val & TYPER_VLPI_BIT) != 0U) {
+ return 1U << GICR_V4_PCPUBASE_SHIFT;
+ } else {
+ return 1U << GICR_V3_PCPUBASE_SHIFT;
+ }
+#else
+ return 1U << GICR_V3_PCPUBASE_SHIFT;
+#endif
+}
+
+unsigned int gicv3_get_component_partnum(const uintptr_t gic_frame);
+
+static inline bool gicv3_is_intr_id_special_identifier(unsigned int id)
+{
+ return (id >= PENDING_G1S_INTID) && (id <= GIC_SPURIOUS_INTERRUPT);
+}
+
+/*******************************************************************************
+ * Helper GICv3 and 3.1 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)
+{
+ /*
+ * Interrupt request deassertion from peripheral to GIC happens
+ * by clearing interrupt condition by a write to the peripheral
+ * register. It is desired that the write transfer is complete
+ * before the core tries to change GIC state from 'AP/Active' to
+ * a new state on seeing 'EOI write'.
+ * Since ICC interface writes are not ordered against Device
+ * memory writes, a barrier is required to ensure the ordering.
+ * The dsb will also ensure *completion* of previous writes with
+ * DEVICE nGnRnE attribute.
+ */
+ dsbishst();
+ 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)
+{
+ /*
+ * Interrupt request deassertion from peripheral to GIC happens
+ * by clearing interrupt condition by a write to the peripheral
+ * register. It is desired that the write transfer is complete
+ * before the core tries to change GIC state from 'AP/Active' to
+ * a new state on seeing 'EOI write'.
+ * Since ICC interface writes are not ordered against Device
+ * memory writes, a barrier is required to ensure the ordering.
+ * The dsb will also ensure *completion* of previous writes with
+ * DEVICE nGnRnE attribute.
+ */
+ dsbishst();
+ return write_icc_eoir0_el1(id);
+}
+
+/*
+ * This macro returns the total number of GICD/GICR registers corresponding to
+ * the register name
+ */
+#define GICD_NUM_REGS(reg_name) \
+ DIV_ROUND_UP_2EVAL(TOTAL_SHARED_INTR_NUM, (1 << reg_name##_SHIFT))
+
+#define GICR_NUM_REGS(reg_name) \
+ DIV_ROUND_UP_2EVAL(TOTAL_PRIVATE_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_igroupr[GICR_NUM_REGS(IGROUPR)];
+ uint32_t gicr_isenabler[GICR_NUM_REGS(ISENABLER)];
+ uint32_t gicr_ispendr[GICR_NUM_REGS(ISPENDR)];
+ uint32_t gicr_isactiver[GICR_NUM_REGS(ISACTIVER)];
+ uint32_t gicr_ipriorityr[GICR_NUM_REGS(IPRIORITYR)];
+ uint32_t gicr_icfgr[GICR_NUM_REGS(ICFGR)];
+ uint32_t gicr_igrpmodr[GICR_NUM_REGS(IGRPMODR)];
+ uint32_t gicr_nsacr;
+} gicv3_redist_ctx_t;
+
+typedef struct gicv3_dist_ctx {
+ /* 64 bits registers */
+ uint64_t gicd_irouter[TOTAL_SHARED_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);
+unsigned int gicv3_rdistif_get_number_frames(const uintptr_t gicr_frame);
+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_sgi(unsigned int sgi_num, gicv3_irq_group_t group,
+ 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);
+
+void gicv3_get_component_prodid_rev(const uintptr_t gicd_base,
+ unsigned int *gic_prod_id,
+ uint8_t *gic_rev);
+void gicv3_check_erratas_applies(const uintptr_t gicd_base);
+#if GIC600_ERRATA_WA_2384374
+void gicv3_apply_errata_wa_2384374(const uintptr_t gicr_base);
+#else
+static inline void gicv3_apply_errata_wa_2384374(const uintptr_t gicr_base)
+{
+}
+#endif /* GIC600_ERRATA_WA_2384374 */
+
+#endif /* __ASSEMBLER__ */
+#endif /* GICV3_H */
diff --git a/include/drivers/arm/mhu.h b/include/drivers/arm/mhu.h
new file mode 100644
index 0000000..31c6a81
--- /dev/null
+++ b/include/drivers/arm/mhu.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MHU_H
+#define MHU_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * Generic MHU error enumeration types.
+ */
+enum mhu_error_t {
+ MHU_ERR_NONE = 0,
+ MHU_ERR_NOT_INIT = -1,
+ MHU_ERR_ALREADY_INIT = -2,
+ MHU_ERR_UNSUPPORTED_VERSION = -3,
+ MHU_ERR_UNSUPPORTED = -4,
+ MHU_ERR_INVALID_ARG = -5,
+ MHU_ERR_BUFFER_TOO_SMALL = -6,
+ MHU_ERR_GENERAL = -7,
+};
+
+/**
+ * Initializes sender MHU.
+ *
+ * mhu_sender_base Base address of sender MHU.
+ *
+ * Returns mhu_error_t error code.
+ *
+ * This function must be called before mhu_send_data().
+ */
+enum mhu_error_t mhu_init_sender(uintptr_t mhu_sender_base);
+
+
+/**
+ * Initializes receiver MHU.
+ *
+ * mhu_receiver_base Base address of receiver MHU.
+ *
+ * Returns mhu_error_t error code.
+ *
+ * This function must be called before mhu_receive_data().
+ */
+enum mhu_error_t mhu_init_receiver(uintptr_t mhu_receiver_base);
+
+/**
+ * Sends data over MHU.
+ *
+ * send_buffer Pointer to buffer containing the data to be transmitted.
+ * size Size of the data to be transmitted in bytes.
+ *
+ * Returns mhu_error_t error code.
+ *
+ * The send_buffer must be 4-byte aligned and its length must be at least
+ * (4 - (size % 4)) bytes bigger than the data size to prevent buffer
+ * over-reading.
+ */
+enum mhu_error_t mhu_send_data(const uint8_t *send_buffer, size_t size);
+
+/**
+ * Receives data from MHU.
+ *
+ * receive_buffer Pointer the buffer where to store the received data.
+ * size As input the size of the receive_buffer, as output the
+ * number of bytes received. As a limitation,
+ * the size of the buffer must be a multiple of 4.
+ *
+ * Returns mhu_error_t error code.
+ *
+ * The receive_buffer must be 4-byte aligned and its length must be a
+ * multiple of 4.
+ */
+enum mhu_error_t mhu_receive_data(uint8_t *receive_buffer, size_t *size);
+
+/**
+ * Gets the maximum amount of bytes that can be transmitted in a single send by MHU.
+ *
+ * Returns The amount of bytes that can be sent or received in a single message.
+ */
+size_t mhu_get_max_message_size(void);
+
+#endif /* MHU_H */
diff --git a/include/drivers/arm/nic_400.h b/include/drivers/arm/nic_400.h
new file mode 100644
index 0000000..bb74982
--- /dev/null
+++ b/include/drivers/arm/nic_400.h
@@ -0,0 +1,16 @@
+/*
+ * 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 */
diff --git a/include/drivers/arm/pl011.h b/include/drivers/arm/pl011.h
new file mode 100644
index 0000000..ebc6643
--- /dev/null
+++ b/include/drivers/arm/pl011.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PL011_H
+#define PL011_H
+
+#include <drivers/console.h>
+
+/* 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 */
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+/*
+ * 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_t *console);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* PL011_H */
diff --git a/include/drivers/arm/pl061_gpio.h b/include/drivers/arm/pl061_gpio.h
new file mode 100644
index 0000000..68238c9
--- /dev/null
+++ b/include/drivers/arm/pl061_gpio.h
@@ -0,0 +1,15 @@
+/*
+ * 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 <drivers/gpio.h>
+
+void pl061_gpio_register(uintptr_t base_addr, int gpio_dev);
+void pl061_gpio_init(void);
+
+#endif /* PL061_GPIO_H */
diff --git a/include/drivers/arm/rss_comms.h b/include/drivers/arm/rss_comms.h
new file mode 100644
index 0000000..b96c79f
--- /dev/null
+++ b/include/drivers/arm/rss_comms.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef RSS_COMMS_H
+#define RSS_COMMS_H
+
+#include <stdint.h>
+
+int rss_comms_init(uintptr_t mhu_sender_base, uintptr_t mhu_receiver_base);
+
+#endif /* RSS_COMMS_H */
diff --git a/include/drivers/arm/sbsa.h b/include/drivers/arm/sbsa.h
new file mode 100644
index 0000000..9403634
--- /dev/null
+++ b/include/drivers/arm/sbsa.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SBSA_H
+#define SBSA_H
+
+#include <stdint.h>
+
+/* 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 */
diff --git a/include/drivers/arm/scu.h b/include/drivers/arm/scu.h
new file mode 100644
index 0000000..992539f
--- /dev/null
+++ b/include/drivers/arm/scu.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SCU_H
+#define SCU_H
+
+#include <stdint.h>
+
+#define SCU_CTRL_REG 0x00
+#define SCU_CFG_REG 0x04
+
+#define SCU_ENABLE_BIT (1 << 0)
+
+void enable_snoop_ctrl_unit(uintptr_t base);
+uint32_t read_snoop_ctrl_unit_cfg(uintptr_t base);
+
+#endif /* SCU_H */
diff --git a/include/drivers/arm/smmu_v3.h b/include/drivers/arm/smmu_v3.h
new file mode 100644
index 0000000..37da56f
--- /dev/null
+++ b/include/drivers/arm/smmu_v3.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SMMU_V3_H
+#define SMMU_V3_H
+
+#include <stdint.h>
+#include <lib/utils_def.h>
+#include <platform_def.h>
+
+/* SMMUv3 register offsets from device base */
+#define SMMU_CR0 U(0x0020)
+#define SMMU_CR0ACK U(0x0024)
+#define SMMU_GBPA U(0x0044)
+#define SMMU_S_IDR1 U(0x8004)
+#define SMMU_S_INIT U(0x803c)
+#define SMMU_S_GBPA U(0x8044)
+
+/*
+ * TODO: SMMU_ROOT_PAGE_OFFSET is platform specific.
+ * Currently defined as a command line model parameter.
+ */
+#if ENABLE_RME
+
+#define SMMU_ROOT_PAGE_OFFSET (PLAT_ARM_SMMUV3_ROOT_REG_OFFSET)
+#define SMMU_ROOT_IDR0 U(SMMU_ROOT_PAGE_OFFSET + 0x0000)
+#define SMMU_ROOT_IIDR U(SMMU_ROOT_PAGE_OFFSET + 0x0008)
+#define SMMU_ROOT_CR0 U(SMMU_ROOT_PAGE_OFFSET + 0x0020)
+#define SMMU_ROOT_CR0ACK U(SMMU_ROOT_PAGE_OFFSET + 0x0024)
+#define SMMU_ROOT_GPT_BASE U(SMMU_ROOT_PAGE_OFFSET + 0x0028)
+#define SMMU_ROOT_GPT_BASE_CFG U(SMMU_ROOT_PAGE_OFFSET + 0x0030)
+#define SMMU_ROOT_GPF_FAR U(SMMU_ROOT_PAGE_OFFSET + 0x0038)
+#define SMMU_ROOT_GPT_CFG_FAR U(SMMU_ROOT_PAGE_OFFSET + 0x0040)
+#define SMMU_ROOT_TLBI U(SMMU_ROOT_PAGE_OFFSET + 0x0050)
+#define SMMU_ROOT_TLBI_CTRL U(SMMU_ROOT_PAGE_OFFSET + 0x0058)
+
+#endif /* ENABLE_RME */
+
+/* SMMU_CR0 and SMMU_CR0ACK register fields */
+#define SMMU_CR0_SMMUEN (1UL << 0)
+
+/* 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)
+
+/* SMMU_ROOT_IDR0 register fields */
+#define SMMU_ROOT_IDR0_ROOT_IMPL (1UL << 0)
+
+/* SMMU_ROOT_CR0 register fields */
+#define SMMU_ROOT_CR0_GPCEN (1UL << 1)
+#define SMMU_ROOT_CR0_ACCESSEN (1UL << 0)
+
+int smmuv3_init(uintptr_t smmu_base);
+int smmuv3_security_init(uintptr_t smmu_base);
+
+int smmuv3_ns_set_abort_all(uintptr_t smmu_base);
+
+#endif /* SMMU_V3_H */
diff --git a/include/drivers/arm/sp804_delay_timer.h b/include/drivers/arm/sp804_delay_timer.h
new file mode 100644
index 0000000..f8769e8
--- /dev/null
+++ b/include/drivers/arm/sp804_delay_timer.h
@@ -0,0 +1,28 @@
+/*
+ * 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 <stdint.h>
+
+#include <drivers/delay_timer.h>
+
+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 */
diff --git a/include/drivers/arm/sp805.h b/include/drivers/arm/sp805.h
new file mode 100644
index 0000000..b00ede1
--- /dev/null
+++ b/include/drivers/arm/sp805.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SP805_H
+#define SP805_H
+
+#include <lib/utils_def.h>
+
+/* 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 <stdint.h>
+
+/* 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 */
diff --git a/include/drivers/arm/tzc380.h b/include/drivers/arm/tzc380.h
new file mode 100644
index 0000000..9bd5f21
--- /dev/null
+++ b/include/drivers/arm/tzc380.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TZC380_H
+#define TZC380_H
+
+#include <drivers/arm/tzc_common.h>
+#include <lib/utils_def.h>
+
+#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_SUBREGION_DIS_SHIFT 0x8
+#define TZC_SUBREGION_DIS_MASK U(0xff)
+#define TZC_ATTR_SUBREG_DIS(s) (((s) & TZC_SUBREGION_DIS_MASK) \
+ << TZC_SUBREGION_DIS_SHIFT)
+
+#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 */
diff --git a/include/drivers/arm/tzc400.h b/include/drivers/arm/tzc400.h
new file mode 100644
index 0000000..765c130
--- /dev/null
+++ b/include/drivers/arm/tzc400.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TZC400_H
+#define TZC400_H
+
+#include <drivers/arm/tzc_common.h>
+#include <lib/utils_def.h>
+
+#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_UNPRIV U(0)
+#define FAIL_CONTROL_PRIV_PRIV 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))
+#define TZC_400_REGION_ATTR_FILTER_BIT_ALL TZC_400_REGION_ATTR_F_EN_MASK
+
+/*
+ * 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)
+
+#define FILTER_OFFSET U(0x10)
+
+#ifndef __ASSEMBLER__
+
+#include <cdefs.h>
+#include <stdint.h>
+
+/*******************************************************************************
+ * 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_update_filters(unsigned int region, unsigned int filters);
+void tzc400_set_action(unsigned int action);
+void tzc400_enable_filters(void);
+void tzc400_disable_filters(void);
+int tzc400_it_handler(void);
+
+static inline void tzc_init(uintptr_t base)
+{
+ tzc400_init(base);
+}
+
+static inline void tzc_configure_region0(
+ unsigned int sec_attr,
+ unsigned int ns_device_access)
+{
+ 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 */
diff --git a/include/drivers/arm/tzc_common.h b/include/drivers/arm/tzc_common.h
new file mode 100644
index 0000000..e58201c
--- /dev/null
+++ b/include/drivers/arm/tzc_common.h
@@ -0,0 +1,89 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/*
+ * 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 */
diff --git a/include/drivers/arm/tzc_dmc500.h b/include/drivers/arm/tzc_dmc500.h
new file mode 100644
index 0000000..cce074c
--- /dev/null
+++ b/include/drivers/arm/tzc_dmc500.h
@@ -0,0 +1,151 @@
+/*
+ * 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 <drivers/arm/tzc_common.h>
+#include <lib/utils_def.h>
+
+#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 <stdint.h>
+
+/*
+ * 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 */
diff --git a/include/drivers/arm/tzc_dmc620.h b/include/drivers/arm/tzc_dmc620.h
new file mode 100644
index 0000000..26c444d
--- /dev/null
+++ b/include/drivers/arm/tzc_dmc620.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TZC_DMC620_H
+#define TZC_DMC620_H
+
+#include <lib/utils_def.h>
+
+/* 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 */
+
diff --git a/include/drivers/auth/auth_common.h b/include/drivers/auth/auth_common.h
new file mode 100644
index 0000000..e6859fd
--- /dev/null
+++ b/include/drivers/auth/auth_common.h
@@ -0,0 +1,120 @@
+/*
+ * 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 */
diff --git a/include/drivers/auth/auth_mod.h b/include/drivers/auth/auth_mod.h
new file mode 100644
index 0000000..94537f6
--- /dev/null
+++ b/include/drivers/auth/auth_mod.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AUTH_MOD_H
+#define AUTH_MOD_H
+
+#include <common/tbbr/cot_def.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/auth/auth_common.h>
+#include <drivers/auth/img_parser_mod.h>
+
+#include <lib/utils_def.h>
+
+/*
+ * Image flags
+ */
+#define IMG_FLAG_AUTHENTICATED (1 << 0)
+
+#if COT_DESC_IN_DTB && !IMAGE_BL1
+/*
+ * 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;
+ auth_method_desc_t *img_auth_methods;
+ auth_param_desc_t *authenticated_data;
+} auth_img_desc_t;
+#else
+/*
+ * 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;
+#endif /* COT_DESC_IN_DTB && !IMAGE_BL1 */
+
+/* Public functions */
+#if TRUSTED_BOARD_BOOT
+void auth_mod_init(void);
+#else
+static inline void auth_mod_init(void)
+{
+}
+#endif /* TRUSTED_BOARD_BOOT */
+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); \
+ const size_t cot_desc_size = ARRAY_SIZE(_cot); \
+ unsigned int auth_img_flags[MAX_NUMBER_IDS]
+
+extern const auth_img_desc_t *const *const cot_desc_ptr;
+extern const size_t cot_desc_size;
+extern unsigned int auth_img_flags[MAX_NUMBER_IDS];
+
+#if defined(SPD_spmd)
+
+#define DEFINE_SIP_SP_PKG(n) DEFINE_SP_PKG(n, sip_sp_content_cert)
+#define DEFINE_PLAT_SP_PKG(n) DEFINE_SP_PKG(n, plat_sp_content_cert)
+
+#define DEFINE_SP_PKG(n, cert) \
+ static const auth_img_desc_t sp_pkg##n = { \
+ .img_id = SP_PKG##n##_ID, \
+ .img_type = IMG_RAW, \
+ .parent = &cert, \
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { \
+ [0] = { \
+ .type = AUTH_METHOD_HASH, \
+ .param.hash = { \
+ .data = &raw_data, \
+ .hash = &sp_pkg##n##_hash \
+ } \
+ } \
+ } \
+ }
+
+#endif
+
+#endif /* AUTH_MOD_H */
diff --git a/include/drivers/auth/crypto_mod.h b/include/drivers/auth/crypto_mod.h
new file mode 100644
index 0000000..3a23df4
--- /dev/null
+++ b/include/drivers/auth/crypto_mod.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CRYPTO_MOD_H
+#define CRYPTO_MOD_H
+
+#define CRYPTO_AUTH_VERIFY_ONLY 1
+#define CRYPTO_HASH_CALC_ONLY 2
+#define CRYPTO_AUTH_VERIFY_AND_HASH_CALC 3
+
+/* Return values */
+enum crypto_ret_value {
+ CRYPTO_SUCCESS = 0,
+ CRYPTO_ERR_INIT,
+ CRYPTO_ERR_HASH,
+ CRYPTO_ERR_SIGNATURE,
+ CRYPTO_ERR_DECRYPTION,
+ CRYPTO_ERR_UNKNOWN
+};
+
+#define CRYPTO_MAX_IV_SIZE 16U
+#define CRYPTO_MAX_TAG_SIZE 16U
+
+/* Decryption algorithm */
+enum crypto_dec_algo {
+ CRYPTO_GCM_DECRYPT = 0
+};
+
+/* Message digest algorithm */
+enum crypto_md_algo {
+ CRYPTO_MD_SHA256,
+ CRYPTO_MD_SHA384,
+ CRYPTO_MD_SHA512,
+};
+
+/* Maximum size as per the known stronger hash algorithm i.e.SHA512 */
+#define CRYPTO_MD_MAX_SIZE 64U
+
+/*
+ * 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 */
+#if CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+ 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);
+#endif /* CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
+ CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
+
+#if CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+ /* Calculate a hash. Return hash value */
+ int (*calc_hash)(enum crypto_md_algo md_alg, void *data_ptr,
+ unsigned int data_len,
+ unsigned char output[CRYPTO_MD_MAX_SIZE]);
+#endif /* CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+ CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
+
+ /*
+ * Authenticated decryption. Return one of the
+ * 'enum crypto_ret_value' options.
+ */
+ int (*auth_decrypt)(enum crypto_dec_algo dec_algo, void *data_ptr,
+ size_t len, const void *key, unsigned int key_len,
+ unsigned int key_flags, const void *iv,
+ unsigned int iv_len, const void *tag,
+ unsigned int tag_len);
+} crypto_lib_desc_t;
+
+/* Public functions */
+#if CRYPTO_SUPPORT
+void crypto_mod_init(void);
+#else
+static inline void crypto_mod_init(void)
+{
+}
+#endif /* CRYPTO_SUPPORT */
+
+#if CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+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);
+#endif /* CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
+ CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
+
+int crypto_mod_auth_decrypt(enum crypto_dec_algo dec_algo, void *data_ptr,
+ size_t len, const void *key, unsigned int key_len,
+ unsigned int key_flags, const void *iv,
+ unsigned int iv_len, const void *tag,
+ unsigned int tag_len);
+
+#if CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+int crypto_mod_calc_hash(enum crypto_md_algo alg, void *data_ptr,
+ unsigned int data_len,
+ unsigned char output[CRYPTO_MD_MAX_SIZE]);
+#endif /* CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+ CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
+
+#if CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+/* Macro to register a cryptographic library */
+#define REGISTER_CRYPTO_LIB(_name, _init, _verify_signature, _verify_hash, \
+ _calc_hash, _auth_decrypt) \
+ const crypto_lib_desc_t crypto_lib_desc = { \
+ .name = _name, \
+ .init = _init, \
+ .verify_signature = _verify_signature, \
+ .verify_hash = _verify_hash, \
+ .calc_hash = _calc_hash, \
+ .auth_decrypt = _auth_decrypt \
+ }
+#elif CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY
+#define REGISTER_CRYPTO_LIB(_name, _init, _verify_signature, _verify_hash, \
+ _auth_decrypt) \
+ const crypto_lib_desc_t crypto_lib_desc = { \
+ .name = _name, \
+ .init = _init, \
+ .verify_signature = _verify_signature, \
+ .verify_hash = _verify_hash, \
+ .auth_decrypt = _auth_decrypt \
+ }
+#elif CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY
+#define REGISTER_CRYPTO_LIB(_name, _init, _calc_hash) \
+ const crypto_lib_desc_t crypto_lib_desc = { \
+ .name = _name, \
+ .init = _init, \
+ .calc_hash = _calc_hash, \
+ }
+#endif /* CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
+
+extern const crypto_lib_desc_t crypto_lib_desc;
+
+#endif /* CRYPTO_MOD_H */
diff --git a/include/drivers/auth/img_parser_mod.h b/include/drivers/auth/img_parser_mod.h
new file mode 100644
index 0000000..b2fb60e
--- /dev/null
+++ b/include/drivers/auth/img_parser_mod.h
@@ -0,0 +1,64 @@
+/*
+ * 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 <drivers/auth/auth_common.h>
+
+/*
+ * 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 */
diff --git a/include/drivers/auth/mbedtls/mbedtls_common.h b/include/drivers/auth/mbedtls/mbedtls_common.h
new file mode 100644
index 0000000..a9c2352
--- /dev/null
+++ b/include/drivers/auth/mbedtls/mbedtls_common.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/include/drivers/auth/mbedtls/mbedtls_config.h b/include/drivers/auth/mbedtls/mbedtls_config.h
new file mode 100644
index 0000000..01e261a
--- /dev/null
+++ b/include/drivers/auth/mbedtls/mbedtls_config.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited. 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
+#define MBEDTLS_ECP_NO_INTERNAL_RNG
+#endif
+#if TF_MBEDTLS_USE_RSA
+#define MBEDTLS_RSA_C
+#define MBEDTLS_X509_RSASSA_PSS_SUPPORT
+#endif
+
+#define MBEDTLS_SHA256_C
+
+/*
+ * If either Trusted Boot or Measured Boot require a stronger algorithm than
+ * SHA-256, pull in SHA-512 support.
+ */
+#if (TF_MBEDTLS_HASH_ALG_ID != TF_MBEDTLS_SHA256) /* TBB hash algo */
+#define MBEDTLS_SHA512_C
+#else
+ /* TBB uses SHA-256, what about measured boot? */
+#if defined(TF_MBEDTLS_MBOOT_USE_SHA512)
+#define MBEDTLS_SHA512_C
+#endif
+#endif
+
+#define MBEDTLS_VERSION_C
+
+#define MBEDTLS_X509_USE_C
+#define MBEDTLS_X509_CRT_PARSE_C
+
+#if TF_MBEDTLS_USE_AES_GCM
+#define MBEDTLS_AES_C
+#define MBEDTLS_CIPHER_C
+#define MBEDTLS_GCM_C
+#endif
+
+/* 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
+
+/*
+ * Prevent the use of 128-bit division which
+ * creates dependency on external libraries.
+ */
+#define MBEDTLS_NO_UDBL_DIVISION
+
+#ifndef __ASSEMBLER__
+/* System headers required to build mbed TLS with the current configuration */
+#include <stdlib.h>
+#include <mbedtls/check_config.h>
+#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
+
+/*
+ * Warn if errors from certain functions are ignored.
+ *
+ * The warnings are always enabled (where supported) for critical functions
+ * where ignoring the return value is almost always a bug. This macro extends
+ * the warnings to more functions.
+ */
+#define MBEDTLS_CHECK_RETURN_WARNING
+
+#endif /* MBEDTLS_CONFIG_H */
diff --git a/include/drivers/auth/tbbr_cot_common.h b/include/drivers/auth/tbbr_cot_common.h
new file mode 100644
index 0000000..a51faee
--- /dev/null
+++ b/include/drivers/auth/tbbr_cot_common.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TBBR_COT_COMMON_H
+#define TBBR_COT_COMMON_H
+
+#include <drivers/auth/auth_mod.h>
+
+extern unsigned char tb_fw_hash_buf[HASH_DER_LEN];
+extern unsigned char scp_fw_hash_buf[HASH_DER_LEN];
+extern unsigned char nt_world_bl_hash_buf[HASH_DER_LEN];
+
+extern auth_param_type_desc_t trusted_nv_ctr;
+extern auth_param_type_desc_t subject_pk;
+extern auth_param_type_desc_t sig;
+extern auth_param_type_desc_t sig_alg;
+extern auth_param_type_desc_t raw_data;
+
+extern auth_param_type_desc_t tb_fw_hash;
+extern auth_param_type_desc_t tb_fw_config_hash;
+extern auth_param_type_desc_t fw_config_hash;
+
+extern const auth_img_desc_t trusted_boot_fw_cert;
+extern const auth_img_desc_t hw_config;
+
+#endif /* TBBR_COT_COMMON_H */
diff --git a/include/drivers/brcm/chimp.h b/include/drivers/brcm/chimp.h
new file mode 100644
index 0000000..02d528b
--- /dev/null
+++ b/include/drivers/brcm/chimp.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SR_CHIMP_H
+#define SR_CHIMP_H
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+#define CHIMP_WINDOW_SIZE 0x400000
+#define CHIMP_ERROR_OFFSET 28
+#define CHIMP_ERROR_MASK 0xf0000000
+
+#ifndef EMULATION_SETUP
+#define CHIMP_HANDSHAKE_TIMEOUT_MS 10000
+#else
+/*
+ * 1hr timeout for test in emulator
+ * By doing this ChiMP is given a chance to boot
+ * fully from the QSPI
+ * (on Palladium this takes upto 50 min depending on QSPI clk)
+ */
+
+#define CHIMP_HANDSHAKE_TIMEOUT_MS 3600000
+#endif
+
+#define CHIMP_BPE_MODE_ID_PATTERN (0x25000000)
+#define CHIMP_BPE_MODE_ID_MASK (0x7f000000)
+#define NIC_RESET_RELEASE_TIMEOUT_US (10)
+
+/* written by M0, used by ChiMP ROM */
+#define SR_IN_SMARTNIC_MODE_BIT 0
+/* written by M0, used by ChiMP ROM */
+#define SR_CHIMP_SECURE_BOOT_BIT 1
+/* cleared by AP, set by ChiMP BC2 code */
+#define SR_FLASH_ACCESS_DONE_BIT 2
+
+#ifdef USE_CHIMP
+void bcm_chimp_write(uintptr_t addr, uint32_t value);
+uint32_t bcm_chimp_read(uintptr_t addr);
+uint32_t bcm_chimp_read_ctrl(uint32_t offset);
+void bcm_chimp_clrbits(uintptr_t addr, uint32_t bits);
+void bcm_chimp_setbits(uintptr_t addr, uint32_t bits);
+int bcm_chimp_is_nic_mode(void);
+void bcm_chimp_fru_prog_done(bool status);
+int bcm_chimp_handshake_done(void);
+int bcm_chimp_wait_handshake(void);
+/* Fastboot-related*/
+int bcm_chimp_initiate_fastboot(int fastboot_type);
+#else
+static inline void bcm_chimp_write(uintptr_t addr, uint32_t value)
+{
+}
+static inline uint32_t bcm_chimp_read(uintptr_t addr)
+{
+ return 0;
+}
+static inline uint32_t bcm_chimp_read_ctrl(uint32_t offset)
+{
+ return 0;
+}
+static inline void bcm_chimp_clrbits(uintptr_t addr, uint32_t bits)
+{
+}
+static inline void bcm_chimp_setbits(uintptr_t addr, uint32_t bits)
+{
+}
+static inline int bcm_chimp_is_nic_mode(void)
+{
+ return 0;
+}
+static inline void bcm_chimp_fru_prog_done(bool status)
+{
+}
+static inline int bcm_chimp_handshake_done(void)
+{
+ return 0;
+}
+static inline int bcm_chimp_wait_handshake(void)
+{
+ return 0;
+}
+static inline int bcm_chimp_initiate_fastboot(int fastboot_type)
+{
+ return 0;
+}
+#endif /* USE_CHIMP */
+#endif
diff --git a/include/drivers/brcm/chimp_nv_defs.h b/include/drivers/brcm/chimp_nv_defs.h
new file mode 100644
index 0000000..9be361f
--- /dev/null
+++ b/include/drivers/brcm/chimp_nv_defs.h
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BNXNVM_DEFS_H
+#define BNXNVM_DEFS_H
+
+#if defined(__GNUC__)
+ #define PACKED_STRUCT __packed
+#else /* non-GCC compiler */
+
+#ifndef DOS_DRIVERS
+ #pragma pack(push)
+ #pragma pack(1)
+#endif
+ #define PACKED_STRUCT
+#endif
+
+typedef uint32_t u32_t;
+typedef uint8_t u8_t;
+typedef uint16_t u16_t;
+
+#define BNXNVM_DEFAULT_BLOCK_SIZE 4096
+#define BNXNVM_UNUSED_BYTE_VALUE 0xff
+
+#define NV_MAX_BLOCK_SIZE 16384
+
+#define BITS_PER_BYTE (8)
+#define SIZEOF_IN_BITS(x) (sizeof(x)*BITS_PER_BYTE)
+
+/************************/
+/* byte-swapping macros */
+/************************/
+#define BYTE_SWAP_16(x) \
+ ((((u16_t)(x) & 0xff00) >> 8) | \
+ (((u16_t)(x) & 0x00ff) << 8))
+#define BYTE_SWAP_32(x) \
+ ((((u32_t)(x) & 0xff000000) >> 24) | \
+ (((u32_t)(x) & 0x00ff0000) >> 8) | \
+ (((u32_t)(x) & 0x0000ff00) << 8) | \
+ (((u32_t)(x) & 0x000000ff) << 24))
+
+/* auto-detect integer size */
+#define BYTE_SWAP_INT(x) \
+ (SIZEOF_IN_BITS(x) == 16 ? BYTE_SWAP_16(x) : \
+ SIZEOF_IN_BITS(x) == 32 ? BYTE_SWAP_32(x) : (x))
+
+/********************************/
+/* Architecture-specific macros */
+/********************************/
+#ifdef __BIG_ENDIAN__ /* e.g. Motorola */
+
+ #define BE_INT16(x) (x)
+ #define BE_INT32(x) (x)
+ #define BE_INT(x) (x)
+ #define LE_INT16(x) BYTE_SWAP_16(x)
+ #define LE_INT32(x) BYTE_SWAP_32(x)
+ #define LE_INT(x) BYTE_SWAP_INT(x)
+
+#else /* Little Endian (e.g. Intel) */
+
+ #define LE_INT16(x) (x)
+ #define LE_INT32(x) (x)
+ #define LE_INT(x) (x)
+ #define BE_INT16(x) BYTE_SWAP_16(x)
+ #define BE_INT32(x) BYTE_SWAP_32(x)
+ #define BE_INT(x) BYTE_SWAP_INT(x)
+
+#endif
+
+
+enum {
+ NV_OK = 0,
+ NV_NOT_NVRAM,
+ NV_BAD_MB,
+ NV_BAD_DIR_HEADER,
+ NV_BAD_DIR_ENTRY,
+ NV_FW_NOT_FOUND,
+};
+
+typedef struct {
+#define BNXNVM_MASTER_BLOCK_SIG BE_INT32(0x424E5834) /*"BNX4"*/
+ /* Signature*/
+ u32_t sig;
+ /* Length of Master Block Header, in bytes [32] */
+ u32_t length;
+ /* Block size, in bytes [4096] */
+ u32_t block_size;
+ /* Byte-offset to Directory Block (translated) */
+ u32_t directory_offset;
+ /* Byte-offset to Block Redirection Table (non-translated) */
+ u32_t redirect_offset;
+ /* Size, in bytes of Reserved Blocks region (at end of NVRAM) */
+ u32_t reserved_size;
+ /*
+ * Size of NVRAM (in bytes) - may be used to
+ * override auto-detected size
+ */
+ u32_t nvram_size;
+ /* CRC-32 (IEEE 802.3 compatible) of the above */
+ u32_t chksum;
+} PACKED_STRUCT bnxnvm_master_block_header_t;
+
+typedef struct {
+#define BNXNVM_DIRECTORY_BLOCK_SIG BE_INT32(0x44697230) /* "Dir0" */
+ /* Signature */
+ u32_t sig;
+ /* Length of Directory Header, in bytes [16] */
+ u32_t length;
+ /* Number of Directory Entries */
+ u32_t entries;
+ /* Length of each Directory Entry, in bytes [24] */
+ u32_t entry_length;
+} PACKED_STRUCT bnxnvm_directory_block_header_t;
+
+typedef struct {
+ /* Directory Entry Type (see enum bnxnvm_directory_type) */
+ u16_t type;
+ /* Instance of this Directory Entry type (0-based) */
+ u16_t ordinal;
+ /*
+ * Directory Entry Extension flags used to identify
+ * secondary instances of a type:ordinal combinations
+ */
+ u16_t ext;
+ /* Directory Entry Attribute flags used to describe the item contents */
+ u16_t attr;
+ /* Item location in NVRAM specified as offset (in bytes) */
+ u32_t item_location;
+ /*
+ * Length of NVRAM item in bytes
+ * (including padding - multiple of block size)
+ */
+ u32_t item_length;
+ /* Length of item data in bytes (excluding padding) */
+ u32_t data_length;
+ /*
+ * CRC-32 (IEEE 802.3 compatible) of item data
+ * (excluding padding) (optional)
+ */
+ u32_t data_chksum;
+} PACKED_STRUCT bnxnvm_directory_entry_t;
+
+enum bnxnvm_version_format {
+ /* US-ASCII string (not necessarily null-terminated) */
+ BNX_VERSION_FMT_ASCII = 0,
+ /* Each field 16-bits, displayed as unpadded decimal (e.g. "1.2.3.4") */
+ BNX_VERSION_FMT_DEC = 1,
+ /* A single hexadecimal value, up to 64-bits (no dots) */
+ BNX_VERSION_FMT_HEX = 2,
+ /* Multiple version values (three 8-bit version fields) */
+ BNX_VERSION_FMT_MULTI = 3
+};
+
+/* This structure definition must not change: */
+typedef struct {
+ u16_t flags; /* bit-flags (defaults to 0x0000) */
+ u8_t version_format; /* enum bnxnvm_version_format */
+ u8_t version_length; /* in bytes */
+ u8_t version[16]; /* version value */
+ u16_t dir_type; /* enum bnxnvm_directory_type */
+ /* size of the entire trailer (to locate end of component data) */
+ u16_t trailer_length;
+#define BNXNVM_COMPONENT_TRAILER_SIG BE_INT32(0x54726c72) /* "Trlr" */
+ u32_t sig;
+ u32_t chksum; /* CRC-32 of all bytes to this point */
+} PACKED_STRUCT bnxnvm_component_trailer_base_t;
+
+typedef struct {
+ /*
+ * new trailer members (e.g. digital signature)
+ * go here (insert at top):
+ */
+ u8_t rsa_sig[256]; /* 2048-bit RSA-encrypted SHA-256 hash */
+ bnxnvm_component_trailer_base_t base;
+} PACKED_STRUCT bnxnvm_component_trailer_t;
+
+#define BNX_MAX_LEN_DIR_NAME 12
+#define BNX_MAX_LEN_DIR_DESC 50
+/*********************************************************
+ * NVRAM Directory Entry/Item Types, Names, and Descriptions
+ *
+ * If you see a name or description that needs improvement,
+ * please correct it or raise for discussion.
+ * When adding a new directory type, it would be appreciated
+ * if you also updated ../../libs/nvm/bnxt_nvm_str.c.
+ * DIR_NAME macros may contain up to 12 alpha-numeric
+ * US-ASCII characters only, camelCase is preferred for clarity.
+ * DIR_DESC macros may contain up to 50 US-ASCII characters
+ * providing a verbose description of the directory type.
+ */
+enum bnxnvm_directory_type {
+ /* 0x00 Unused directory entry, available for use */
+ BNX_DIR_TYPE_UNUSED = 0,
+#define BNX_DIR_NAME_UNUSED "unused"
+#define BNX_DIR_DESC_UNUSED "Deleted directory entry, available for reuse"
+ /* 0x01 Package installation log */
+ BNX_DIR_TYPE_PKG_LOG = 1,
+#define BNX_DIR_NAME_PKG_LOG "pkgLog"
+#define BNX_DIR_DESC_PKG_LOG "Package Installation Log"
+ BNX_DIR_TYPE_CHIMP_PATCH = 3,
+#define BNX_DIR_NAME_CHIMP_PATCH "chimpPatch"
+#define BNX_DIR_DESC_CHIMP_PATCH "ChiMP Patch Firmware"
+ /* 0x04 ChiMP firmware: Boot Code phase 1 */
+ BNX_DIR_TYPE_BOOTCODE = 4,
+#define BNX_DIR_NAME_BOOTCODE "chimpBoot"
+#define BNX_DIR_DESC_BOOTCODE "Chip Management Processor Boot Firmware"
+ /* 0x05 VPD data block */
+ BNX_DIR_TYPE_VPD = 5,
+#define BNX_DIR_NAME_VPD "VPD"
+#define BNX_DIR_DESC_VPD "Vital Product Data"
+ /* 0x06 Exp ROM MBA */
+ BNX_DIR_TYPE_EXP_ROM_MBA = 6,
+#define BNX_DIR_NAME_EXP_ROM_MBA "MBA"
+#define BNX_DIR_DESC_EXP_ROM_MBA "Multiple Boot Agent Expansion ROM"
+ BNX_DIR_TYPE_AVS = 7, /* 0x07 AVS FW */
+#define BNX_DIR_NAME_AVS "AVS"
+#define BNX_DIR_DESC_AVS "Adaptive Voltage Scaling Firmware"
+ BNX_DIR_TYPE_PCIE = 8, /* 0x08 PCIE FW */
+#define BNX_DIR_NAME_PCIE "PCIEucode"
+#define BNX_DIR_DESC_PCIE "PCIe Microcode"
+ BNX_DIR_TYPE_PORT_MACRO = 9, /* 0x09 PORT MACRO FW */
+#define BNX_DIR_NAME_PORT_MACRO "portMacro"
+#define BNX_DIR_DESC_PORT_MACRO "Port Macro Firmware"
+ BNX_DIR_TYPE_APE_FW = 10, /* 0x0A APE Firmware */
+#define BNX_DIR_NAME_APE_FW "apeFW"
+#define BNX_DIR_DESC_APE_FW "Application Processing Engine Firmware"
+ /* 0x0B Patch firmware executed by APE ROM */
+ BNX_DIR_TYPE_APE_PATCH = 11,
+#define BNX_DIR_NAME_APE_PATCH "apePatch"
+#define BNX_DIR_DESC_APE_PATCH "APE Patch Firmware"
+ BNX_DIR_TYPE_KONG_FW = 12, /* 0x0C Kong Firmware */
+#define BNX_DIR_NAME_KONG_FW "kongFW"
+#define BNX_DIR_DESC_KONG_FW "Kong Firmware"
+ /* 0x0D Patch firmware executed by Kong ROM */
+ BNX_DIR_TYPE_KONG_PATCH = 13,
+#define BNX_DIR_NAME_KONG_PATCH "kongPatch"
+#define BNX_DIR_DESC_KONG_PATCH "Kong Patch Firmware"
+ BNX_DIR_TYPE_BONO_FW = 14, /* 0x0E Bono Firmware */
+#define BNX_DIR_NAME_BONO_FW "bonoFW"
+#define BNX_DIR_DESC_BONO_FW "Bono Firmware"
+ /* 0x0F Patch firmware executed by Bono ROM */
+ BNX_DIR_TYPE_BONO_PATCH = 15,
+#define BNX_DIR_NAME_BONO_PATCH "bonoPatch"
+#define BNX_DIR_DESC_BONO_PATCH "Bono Patch Firmware"
+ BNX_DIR_TYPE_TANG_FW = 16, /* 0x10 Tang firmware */
+#define BNX_DIR_NAME_TANG_FW "tangFW"
+#define BNX_DIR_DESC_TANG_FW "Tang Firmware"
+ /* 0x11 Patch firmware executed by Tang ROM */
+ BNX_DIR_TYPE_TANG_PATCH = 17,
+#define BNX_DIR_NAME_TANG_PATCH "tangPatch"
+#define BNX_DIR_DESC_TANG_PATCH "Tang Patch Firmware"
+ /* 0x12 ChiMP firmware: Boot Code phase 2 (loaded by phase 1) */
+ BNX_DIR_TYPE_BOOTCODE_2 = 18,
+#define BNX_DIR_NAME_BOOTCODE_2 "chimpHWRM"
+#define BNX_DIR_DESC_BOOTCODE_2 "ChiMP Hardware Resource Manager Firmware"
+ BNX_DIR_TYPE_CCM = 19, /* 0x13 CCM ROM binary */
+#define BNX_DIR_NAME_CCM "CCM"
+#define BNX_DIR_DESC_CCM "Comprehensive Configuration Management"
+ /* 0x14 PCI-IDs, PCI-related configuration properties */
+ BNX_DIR_TYPE_PCI_CFG = 20,
+#define BNX_DIR_NAME_PCI_CFG "pciCFG"
+#define BNX_DIR_DESC_PCI_CFG "PCIe Configuration Data"
+
+ BNX_DIR_TYPE_TSCF_UCODE = 21, /* 0x15 TSCF micro-code */
+#define BNX_DIR_NAME_TSCF_UCODE "PHYucode"
+#define BNX_DIR_DESC_TSCF_UCODE "Falcon PHY Microcode"
+ BNX_DIR_TYPE_ISCSI_BOOT = 22, /* 0x16 iSCSI Boot */
+#define BNX_DIR_NAME_ISCSI_BOOT "iSCSIboot"
+#define BNX_DIR_DESC_ISCSI_BOOT "iSCSI Boot Software Initiator"
+ /* 0x18 iSCSI Boot IPV6 - ***DEPRECATED*** */
+ BNX_DIR_TYPE_ISCSI_BOOT_IPV6 = 24,
+ /* 0x19 iSCSI Boot IPV4N6 - ***DEPRECATED*** */
+ BNX_DIR_TYPE_ISCSI_BOOT_IPV4N6 = 25,
+ BNX_DIR_TYPE_ISCSI_BOOT_CFG = 26, /* 0x1a iSCSI Boot CFG v6 */
+#define BNX_DIR_NAME_ISCSI_BOOT_CFG "iSCSIcfg"
+#define BNX_DIR_DESC_ISCSI_BOOT_CFG "iSCSI Boot Configuration Data"
+ BNX_DIR_TYPE_EXT_PHY = 27, /* 0x1b External PHY FW */
+#define BNX_DIR_NAME_EXT_PHY "extPHYfw"
+#define BNX_DIR_DESC_EXT_PHY "External PHY Firmware"
+ BNX_DIR_TYPE_MODULES_PN = 28, /* 0x1c Modules PartNum list */
+#define BNX_DIR_NAME_MODULES_PN "modPartNums"
+#define BNX_DIR_DESC_MODULES_PN "Optical Modules Part Number List"
+ BNX_DIR_TYPE_SHARED_CFG = 40, /* 0x28 shared configuration block */
+#define BNX_DIR_NAME_SHARED_CFG "sharedCFG"
+#define BNX_DIR_DESC_SHARED_CFG "Shared Configuration Data"
+ BNX_DIR_TYPE_PORT_CFG = 41, /* 0x29 port configuration block */
+#define BNX_DIR_NAME_PORT_CFG "portCFG"
+#define BNX_DIR_DESC_PORT_CFG "Port Configuration Data"
+ BNX_DIR_TYPE_FUNC_CFG = 42, /* 0x2A func configuration block */
+#define BNX_DIR_NAME_FUNC_CFG "funcCFG"
+#define BNX_DIR_DESC_FUNC_CFG "Function Configuration Data"
+
+ /* Management Firmware (TruManage) related dir entries*/
+ /* 0x30 Management firmware configuration (see BMCFG library)*/
+ BNX_DIR_TYPE_MGMT_CFG = 48,
+#define BNX_DIR_NAME_MGMT_CFG "mgmtCFG"
+#define BNX_DIR_DESC_MGMT_CFG "Out-of-band Management Configuration Data"
+ BNX_DIR_TYPE_MGMT_DATA = 49, /* 0x31 "Opaque Management Data" */
+#define BNX_DIR_NAME_MGMT_DATA "mgmtData"
+#define BNX_DIR_DESC_MGMT_DATA "Out-of-band Management Data"
+ BNX_DIR_TYPE_MGMT_WEB_DATA = 50, /* 0x32 "Web GUI" file data */
+#define BNX_DIR_NAME_MGMT_WEB_DATA "webData"
+#define BNX_DIR_DESC_MGMT_WEB_DATA "Out-of-band Management Web Data"
+ /* 0x33 "Web GUI" file metadata */
+ BNX_DIR_TYPE_MGMT_WEB_META = 51,
+#define BNX_DIR_NAME_MGMT_WEB_META "webMeta"
+#define BNX_DIR_DESC_MGMT_WEB_META "Out-of-band Management Web Metadata"
+ /* 0x34 Management firmware Event Log (a.k.a. "SEL") */
+ BNX_DIR_TYPE_MGMT_EVENT_LOG = 52,
+#define BNX_DIR_NAME_MGMT_EVENT_LOG "eventLog"
+#define BNX_DIR_DESC_MGMT_EVENT_LOG "Out-of-band Management Event Log"
+ /* 0x35 Management firmware Audit Log */
+ BNX_DIR_TYPE_MGMT_AUDIT_LOG = 53
+#define BNX_DIR_NAME_MGMT_AUDIT_LOG "auditLog"
+#define BNX_DIR_DESC_MGMT_AUDIT_LOG "Out-of-band Management Audit Log"
+
+};
+
+/* For backwards compatibility only, may be removed later */
+#define BNX_DIR_TYPE_ISCSI_BOOT_CFG6 BNX_DIR_TYPE_ISCSI_BOOT_CFG
+
+/* Firmware NVM items of "APE BIN" format are identified with
+ * the following macro:
+ */
+#define BNX_DIR_TYPE_IS_APE_BIN_FMT(type)\
+ ((type) == BNX_DIR_TYPE_CHIMP_PATCH \
+ || (type) == BNX_DIR_TYPE_BOOTCODE \
+ || (type) == BNX_DIR_TYPE_BOOTCODE_2 \
+ || (type) == BNX_DIR_TYPE_APE_FW \
+ || (type) == BNX_DIR_TYPE_APE_PATCH \
+ || (type) == BNX_DIR_TYPE_TANG_FW \
+ || (type) == BNX_DIR_TYPE_TANG_PATCH \
+ || (type) == BNX_DIR_TYPE_KONG_FW \
+ || (type) == BNX_DIR_TYPE_KONG_PATCH \
+ || (type) == BNX_DIR_TYPE_BONO_FW \
+ || (type) == BNX_DIR_TYPE_BONO_PATCH \
+ )
+
+/* Other (non APE BIN) executable NVM items are identified with
+ * the following macro:
+ */
+#define BNX_DIR_TYPE_IS_OTHER_EXEC(type)\
+ ((type) == BNX_DIR_TYPE_AVS \
+ || (type) == BNX_DIR_TYPE_EXP_ROM_MBA \
+ || (type) == BNX_DIR_TYPE_PCIE \
+ || (type) == BNX_DIR_TYPE_TSCF_UCODE \
+ || (type) == BNX_DIR_TYPE_EXT_PHY \
+ || (type) == BNX_DIR_TYPE_CCM \
+ || (type) == BNX_DIR_TYPE_ISCSI_BOOT \
+ )
+
+/* Executable NVM items (e.g. microcode, firmware, software) identified
+ * with the following macro
+ */
+#define BNX_DIR_TYPE_IS_EXECUTABLE(type) \
+ (BNX_DIR_TYPE_IS_APE_BIN_FMT(type) \
+ || BNX_DIR_TYPE_IS_OTHER_EXEC(type))
+
+#define BNX_DIR_ORDINAL_FIRST 0 /* Ordinals are 0-based */
+
+/* No extension flags for this directory entry */
+#define BNX_DIR_EXT_NONE 0
+/* Directory entry is inactive (not used, not hidden,
+ * not available for reuse)
+ */
+#define BNX_DIR_EXT_INACTIVE (1 << 0)
+/* Directory content is a temporary staging location for
+ * updating the primary (non-update) directory entry contents
+ * (e.g. performing a secure firmware update)
+ */
+#define BNX_DIR_EXT_UPDATE (1 << 1)
+
+/* No attribute flags set for this directory entry */
+#define BNX_DIR_ATTR_NONE 0
+/* Directory entry checksum of contents is purposely incorrect */
+#define BNX_DIR_ATTR_NO_CHKSUM (1 << 0)
+/* Directory contents are in the form of a property-stream
+ * (e.g. configuration properties)
+ */
+#define BNX_DIR_ATTR_PROP_STREAM (1 << 1)
+/* Directory content (e.g. iSCSI boot) supports IPv4 */
+#define BNX_DIR_ATTR_IPv4 (1 << 2)
+/* Directory content (e.g. iSCSI boot) supports IPv6 */
+#define BNX_DIR_ATTR_IPv6 (1 << 3)
+/* Directory content includes standard NVM component trailer
+ * (bnxnvm_component_trailer_t)
+ */
+#define BNX_DIR_ATTR_TRAILER (1 << 4)
+
+/* Index of tab-delimited fields in each package log
+ * (BNX_DIR_TYPE_PKG_LOG) record (\n-terminated line):
+ */
+enum bnxnvm_pkglog_field_index {
+ /* Package installation date/time in ISO-8601 format */
+ BNX_PKG_LOG_FIELD_IDX_INSTALLED_TIMESTAMP = 0,
+ /* Installed package description (from package header) or "N/A" */
+ BNX_PKG_LOG_FIELD_IDX_PKG_DESCRIPTION = 1,
+ /* Installed package version string (from package header) or "N/A" */
+ BNX_PKG_LOG_FIELD_IDX_PKG_VERSION = 2,
+ /* Installed package creation/modification timestamp (ISO-8601) */
+ BNX_PKG_LOG_FIELD_IDX_PKG_TIMESTAMP = 3,
+ /* Installed package checksum in hexadecimal (CRC-32) or "N/A" */
+ BNX_PKG_LOG_FIELD_IDX_PKG_CHECKSUM = 4,
+ /* Total number of packaged items applied in this installation */
+ BNX_PKG_LOG_FIELD_IDX_INSTALLED_ITEMS = 5,
+ /* Hexadecimal bit-mask identifying which items were installed */
+ BNX_PKG_LOG_FIELD_IDX_INSTALLED_MASK = 6
+};
+
+#if !defined(__GNUC__)
+#ifndef DOS_DRIVERS
+ #pragma pack(pop) /* original packing */
+#endif
+#endif
+
+#endif /* Don't add anything after this line */
diff --git a/include/drivers/brcm/dmu.h b/include/drivers/brcm/dmu.h
new file mode 100644
index 0000000..3a57bbd
--- /dev/null
+++ b/include/drivers/brcm/dmu.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DMU_H
+#define DMU_H
+
+/* Clock field should be 2 bits only */
+#define CLKCONFIG_MASK 0x3
+
+/* argument */
+struct DmuBlockEnable {
+ uint32_t sotp:1;
+ uint32_t pka_rng:1;
+ uint32_t crypto:1;
+ uint32_t spl:1;
+ uint32_t cdru_vgm:1;
+ uint32_t apbs_s0_idm:1;
+ uint32_t smau_s0_idm:1;
+};
+
+/* prototype */
+uint32_t bcm_dmu_block_enable(struct DmuBlockEnable dbe);
+uint32_t bcm_dmu_block_disable(struct DmuBlockEnable dbe);
+uint32_t bcm_set_ihost_pll_freq(uint32_t cluster_num, int ihost_pll_freq_sel);
+uint32_t bcm_get_ihost_pll_freq(uint32_t cluster_num);
+
+#define PLL_FREQ_BYPASS 0x0
+#define PLL_FREQ_FULL 0x1
+#define PLL_FREQ_HALF 0x2
+#define PLL_FREQ_QRTR 0x3
+
+#endif
diff --git a/include/drivers/brcm/emmc/bcm_emmc.h b/include/drivers/brcm/emmc/bcm_emmc.h
new file mode 100644
index 0000000..67f0602
--- /dev/null
+++ b/include/drivers/brcm/emmc/bcm_emmc.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EMMC_H
+#define EMMC_H
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include <platform_def.h>
+
+#include "emmc_chal_types.h"
+#include "emmc_chal_sd.h"
+#include "emmc_csl_sdprot.h"
+#include "emmc_csl_sdcmd.h"
+#include "emmc_pboot_hal_memory_drv.h"
+
+/* ------------------------------------------------------------------- */
+#define EXT_CSD_SIZE 512
+
+#ifdef PLAT_SD_MAX_READ_LENGTH
+#define SD_MAX_READ_LENGTH PLAT_SD_MAX_READ_LENGTH
+#ifdef USE_EMMC_LARGE_BLK_TRANSFER_LENGTH
+#define SD_MAX_BLK_TRANSFER_LENGTH 0x10000000
+#else
+#define SD_MAX_BLK_TRANSFER_LENGTH 0x1000
+#endif
+#else
+#define SD_MAX_READ_LENGTH EMMC_BLOCK_SIZE
+#define SD_MAX_BLK_TRANSFER_LENGTH EMMC_BLOCK_SIZE
+#endif
+
+struct emmc_global_buffer {
+ union {
+ uint8_t Ext_CSD_storage[EXT_CSD_SIZE];
+ uint8_t tempbuf[SD_MAX_READ_LENGTH];
+ } u;
+};
+
+struct emmc_global_vars {
+ struct sd_card_data cardData;
+ struct sd_handle sdHandle;
+ struct sd_dev sdDevice;
+ struct sd_card_info sdCard;
+ unsigned int init_done;
+};
+
+#define ICFG_SDIO0_CAP0__SLOT_TYPE_R 27
+#define ICFG_SDIO0_CAP0__INT_MODE_R 26
+#define ICFG_SDIO0_CAP0__SYS_BUS_64BIT_R 25
+#define ICFG_SDIO0_CAP0__VOLTAGE_1P8V_R 24
+#define ICFG_SDIO0_CAP0__VOLTAGE_3P0V_R 23
+#define ICFG_SDIO0_CAP0__VOLTAGE_3P3V_R 22
+#define ICFG_SDIO0_CAP0__SUSPEND_RESUME_R 21
+#define ICFG_SDIO0_CAP0__SDMA_R 20
+#define ICFG_SDIO0_CAP0__HIGH_SPEED_R 19
+#define ICFG_SDIO0_CAP0__ADMA2_R 18
+#define ICFG_SDIO0_CAP0__EXTENDED_MEDIA_R 17
+#define ICFG_SDIO0_CAP0__MAX_BLOCK_LEN_R 15
+#define ICFG_SDIO0_CAP0__BASE_CLK_FREQ_R 7
+#define ICFG_SDIO0_CAP0__TIMEOUT_UNIT_R 6
+#define ICFG_SDIO0_CAP0__TIMEOUT_CLK_FREQ_R 0
+#define ICFG_SDIO0_CAP1__SPI_BLOCK_MODE_R 22
+#define ICFG_SDIO0_CAP1__SPI_MODE_R 21
+#define ICFG_SDIO0_CAP1__CLK_MULT_R 13
+#define ICFG_SDIO0_CAP1__RETUNING_MODE_R 11
+#define ICFG_SDIO0_CAP1__TUNE_SDR50_R 10
+#define ICFG_SDIO0_CAP1__TIME_RETUNE_R 6
+#define ICFG_SDIO0_CAP1__DRIVER_D_R 5
+#define ICFG_SDIO0_CAP1__DRIVER_C_R 4
+#define ICFG_SDIO0_CAP1__DRIVER_A_R 3
+#define ICFG_SDIO0_CAP1__DDR50_R 2
+#define ICFG_SDIO0_CAP1__SDR104_R 1
+#define ICFG_SDIO0_CAP1__SDR50_R 0
+
+#define SDIO0_CTRL_REGS_BASE_ADDR (SDIO0_EMMCSDXC_SYSADDR)
+#define SDIO0_IDM_RESET_CTRL_ADDR (SDIO_IDM0_IDM_RESET_CONTROL)
+
+#define EMMC_CTRL_REGS_BASE_ADDR SDIO0_CTRL_REGS_BASE_ADDR
+#define EMMC_IDM_RESET_CTRL_ADDR SDIO0_IDM_RESET_CTRL_ADDR
+#define EMMC_IDM_IO_CTRL_DIRECT_ADDR SDIO_IDM0_IO_CONTROL_DIRECT
+
+extern struct emmc_global_buffer *emmc_global_buf_ptr;
+
+extern struct emmc_global_vars *emmc_global_vars_ptr;
+
+#define EMMC_CARD_DETECT_TIMEOUT_MS 1200
+#define EMMC_CMD_TIMEOUT_MS 200
+#define EMMC_BUSY_CMD_TIMEOUT_MS 200
+#define EMMC_CLOCK_SETTING_TIMEOUT_MS 100
+#define EMMC_WFE_RETRY 40000
+#define EMMC_WFE_RETRY_DELAY_US 10
+
+#ifdef EMMC_DEBUG
+#define EMMC_TRACE INFO
+#else
+#define EMMC_TRACE(...)
+#endif
+
+#endif /* EMMC_H */
diff --git a/include/drivers/brcm/emmc/emmc_api.h b/include/drivers/brcm/emmc/emmc_api.h
new file mode 100644
index 0000000..c4c2a58
--- /dev/null
+++ b/include/drivers/brcm/emmc/emmc_api.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EMMC_API_H
+#define EMMC_API_H
+
+#include "bcm_emmc.h"
+#include "emmc_pboot_hal_memory_drv.h"
+
+#ifdef INCLUDE_EMMC_DRIVER_ERASE_CODE
+/*
+ * The erasable unit of the eMMC is the Erase Group
+ * Erase group is measured in write blocks which
+ * are the basic writable units of the Device
+ * EMMC_ERASE_GROUP_SIZE is the number of writeable
+ * units (each unit is 512 bytes)
+ */
+
+/* Start address (sector) */
+#define EMMC_ERASE_START_BLOCK 0x0
+/* Number of blocks to be erased */
+#define EMMC_ERASE_BLOCK_COUNT 0x1
+
+#define EMMC_ERASE_USER_AREA 0
+#define EMMC_ERASE_BOOT_PARTITION1 1
+#define EMMC_ERASE_BOOT_PARTITION2 2
+
+/* eMMC partition to be erased */
+#define EMMC_ERASE_PARTITION EMMC_ERASE_USER_AREA
+#endif
+
+uint32_t bcm_emmc_init(bool card_rdy_only);
+void emmc_deinit(void);
+
+#ifdef INCLUDE_EMMC_DRIVER_ERASE_CODE
+int emmc_erase(uintptr_t mem_addr, size_t num_of_blocks, uint32_t partition);
+#endif
+
+uint32_t emmc_partition_select(uint32_t partition);
+uint32_t emmc_read(uintptr_t mem_addr, uintptr_t storage_addr,
+ size_t storage_size, size_t bytes_to_read);
+uint32_t emmc_write(uintptr_t mem_addr, uintptr_t data_addr,
+ size_t bytes_to_write);
+#endif /* EMMC_API_H */
diff --git a/include/drivers/brcm/emmc/emmc_brcm_rdb_sd4_top.h b/include/drivers/brcm/emmc/emmc_brcm_rdb_sd4_top.h
new file mode 100644
index 0000000..96c333d
--- /dev/null
+++ b/include/drivers/brcm/emmc/emmc_brcm_rdb_sd4_top.h
@@ -0,0 +1,1116 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BRCM_RDB_SD4_EMMC_TOP_H
+#define BRCM_RDB_SD4_EMMC_TOP_H
+
+#define SD4_EMMC_TOP_SYSADDR_OFFSET 0x00000000
+#define SD4_EMMC_TOP_SYSADDR_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_SYSADDR_TYPE uint32_t
+#define SD4_EMMC_TOP_SYSADDR_RESERVED_MASK 0x00000000
+#define SD4_EMMC_TOP_SYSADDR_SYSADDR_SHIFT 0
+#define SD4_EMMC_TOP_SYSADDR_SYSADDR_MASK 0xFFFFFFFF
+
+#define SD4_EMMC_TOP_BLOCK_OFFSET 0x00000004
+#define SD4_EMMC_TOP_BLOCK_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_BLOCK_TYPE uint32_t
+#define SD4_EMMC_TOP_BLOCK_RESERVED_MASK 0x00008000
+#define SD4_EMMC_TOP_BLOCK_BCNT_SHIFT 16
+#define SD4_EMMC_TOP_BLOCK_BCNT_MASK 0xFFFF0000
+#define SD4_EMMC_TOP_BLOCK_HSBS_SHIFT 12
+#define SD4_EMMC_TOP_BLOCK_HSBS_MASK 0x00007000
+#define SD4_EMMC_TOP_BLOCK_TBS_SHIFT 0
+#define SD4_EMMC_TOP_BLOCK_TBS_MASK 0x00000FFF
+
+#define SD4_EMMC_TOP_ARG_OFFSET 0x00000008
+#define SD4_EMMC_TOP_ARG_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_ARG_TYPE uint32_t
+#define SD4_EMMC_TOP_ARG_RESERVED_MASK 0x00000000
+#define SD4_EMMC_TOP_ARG_ARG_SHIFT 0
+#define SD4_EMMC_TOP_ARG_ARG_MASK 0xFFFFFFFF
+
+#define SD4_EMMC_TOP_CMD_OFFSET 0x0000000C
+#define SD4_EMMC_TOP_CMD_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_CMD_TYPE uint32_t
+#define SD4_EMMC_TOP_CMD_RESERVED_MASK 0xC004FFC0
+#define SD4_EMMC_TOP_CMD_CIDX_SHIFT 24
+#define SD4_EMMC_TOP_CMD_CIDX_MASK 0x3F000000
+#define SD4_EMMC_TOP_CMD_CTYP_SHIFT 22
+#define SD4_EMMC_TOP_CMD_CTYP_MASK 0x00C00000
+#define SD4_EMMC_TOP_CMD_DPS_SHIFT 21
+#define SD4_EMMC_TOP_CMD_DPS_MASK 0x00200000
+#define SD4_EMMC_TOP_CMD_CCHK_EN_SHIFT 20
+#define SD4_EMMC_TOP_CMD_CCHK_EN_MASK 0x00100000
+#define SD4_EMMC_TOP_CMD_CRC_EN_SHIFT 19
+#define SD4_EMMC_TOP_CMD_CRC_EN_MASK 0x00080000
+#define SD4_EMMC_TOP_CMD_RTSEL_SHIFT 16
+#define SD4_EMMC_TOP_CMD_RTSEL_MASK 0x00030000
+#define SD4_EMMC_TOP_CMD_MSBS_SHIFT 5
+#define SD4_EMMC_TOP_CMD_MSBS_MASK 0x00000020
+#define SD4_EMMC_TOP_CMD_DTDS_SHIFT 4
+#define SD4_EMMC_TOP_CMD_DTDS_MASK 0x00000010
+#define SD4_EMMC_TOP_CMD_ACMDEN_SHIFT 2
+#define SD4_EMMC_TOP_CMD_ACMDEN_MASK 0x0000000C
+#define SD4_EMMC_TOP_CMD_BCEN_SHIFT 1
+#define SD4_EMMC_TOP_CMD_BCEN_MASK 0x00000002
+#define SD4_EMMC_TOP_CMD_DMA_SHIFT 0
+#define SD4_EMMC_TOP_CMD_DMA_MASK 0x00000001
+
+#define SD4_EMMC_TOP_CMD_SD4_OFFSET 0x0000000C
+#define SD4_EMMC_TOP_CMD_SD4_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_CMD_SD4_TYPE uint32_t
+#define SD4_EMMC_TOP_CMD_SD4_RESERVED_MASK 0xC004FE00
+#define SD4_EMMC_TOP_CMD_SD4_CIDX_SHIFT 24
+#define SD4_EMMC_TOP_CMD_SD4_CIDX_MASK 0x3F000000
+#define SD4_EMMC_TOP_CMD_SD4_CTYP_SHIFT 22
+#define SD4_EMMC_TOP_CMD_SD4_CTYP_MASK 0x00C00000
+#define SD4_EMMC_TOP_CMD_SD4_DPS_SHIFT 21
+#define SD4_EMMC_TOP_CMD_SD4_DPS_MASK 0x00200000
+#define SD4_EMMC_TOP_CMD_SD4_CCHK_EN_SHIFT 20
+#define SD4_EMMC_TOP_CMD_SD4_CCHK_EN_MASK 0x00100000
+#define SD4_EMMC_TOP_CMD_SD4_CRC_EN_SHIFT 19
+#define SD4_EMMC_TOP_CMD_SD4_CRC_EN_MASK 0x00080000
+#define SD4_EMMC_TOP_CMD_SD4_RTSEL_SHIFT 16
+#define SD4_EMMC_TOP_CMD_SD4_RTSEL_MASK 0x00030000
+#define SD4_EMMC_TOP_CMD_SD4_RESPIRQDIS_SHIFT 8
+#define SD4_EMMC_TOP_CMD_SD4_RESPIRQDIS_MASK 0x00000100
+#define SD4_EMMC_TOP_CMD_SD4_RESPERRCHKEN_SHIFT 7
+#define SD4_EMMC_TOP_CMD_SD4_RESPERRCHKEN_MASK 0x00000080
+#define SD4_EMMC_TOP_CMD_SD4_RESPR1R5_SHIFT 6
+#define SD4_EMMC_TOP_CMD_SD4_RESPR1R5_MASK 0x00000040
+#define SD4_EMMC_TOP_CMD_SD4_MSBS_SHIFT 5
+#define SD4_EMMC_TOP_CMD_SD4_MSBS_MASK 0x00000020
+#define SD4_EMMC_TOP_CMD_SD4_DTDS_SHIFT 4
+#define SD4_EMMC_TOP_CMD_SD4_DTDS_MASK 0x00000010
+#define SD4_EMMC_TOP_CMD_SD4_ACMDEN_SHIFT 2
+#define SD4_EMMC_TOP_CMD_SD4_ACMDEN_MASK 0x0000000C
+#define SD4_EMMC_TOP_CMD_SD4_BCEN_SHIFT 1
+#define SD4_EMMC_TOP_CMD_SD4_BCEN_MASK 0x00000002
+#define SD4_EMMC_TOP_CMD_SD4_DMA_SHIFT 0
+#define SD4_EMMC_TOP_CMD_SD4_DMA_MASK 0x00000001
+
+#define SD4_EMMC_TOP_RESP0_OFFSET 0x00000010
+#define SD4_EMMC_TOP_RESP0_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_RESP0_TYPE uint32_t
+#define SD4_EMMC_TOP_RESP0_RESERVED_MASK 0x00000000
+#define SD4_EMMC_TOP_RESP0_RESP0_SHIFT 0
+#define SD4_EMMC_TOP_RESP0_RESP0_MASK 0xFFFFFFFF
+
+#define SD4_EMMC_TOP_RESP2_OFFSET 0x00000014
+#define SD4_EMMC_TOP_RESP2_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_RESP2_TYPE uint32_t
+#define SD4_EMMC_TOP_RESP2_RESERVED_MASK 0x00000000
+#define SD4_EMMC_TOP_RESP2_RESP2_SHIFT 0
+#define SD4_EMMC_TOP_RESP2_RESP2_MASK 0xFFFFFFFF
+
+#define SD4_EMMC_TOP_RESP4_OFFSET 0x00000018
+#define SD4_EMMC_TOP_RESP4_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_RESP4_TYPE uint32_t
+#define SD4_EMMC_TOP_RESP4_RESERVED_MASK 0x00000000
+#define SD4_EMMC_TOP_RESP4_RESP4_SHIFT 0
+#define SD4_EMMC_TOP_RESP4_RESP4_MASK 0xFFFFFFFF
+
+#define SD4_EMMC_TOP_RESP6_OFFSET 0x0000001C
+#define SD4_EMMC_TOP_RESP6_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_RESP6_TYPE uint32_t
+#define SD4_EMMC_TOP_RESP6_RESERVED_MASK 0x00000000
+#define SD4_EMMC_TOP_RESP6_RESP6_SHIFT 0
+#define SD4_EMMC_TOP_RESP6_RESP6_MASK 0xFFFFFFFF
+
+#define SD4_EMMC_TOP_BUFDAT_OFFSET 0x00000020
+#define SD4_EMMC_TOP_BUFDAT_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_BUFDAT_TYPE uint32_t
+#define SD4_EMMC_TOP_BUFDAT_RESERVED_MASK 0x00000000
+#define SD4_EMMC_TOP_BUFDAT_BUFDAT_SHIFT 0
+#define SD4_EMMC_TOP_BUFDAT_BUFDAT_MASK 0xFFFFFFFF
+
+#define SD4_EMMC_TOP_PSTATE_OFFSET 0x00000024
+#define SD4_EMMC_TOP_PSTATE_DEFAULT 0x1FFC0000
+#define SD4_EMMC_TOP_PSTATE_TYPE uint32_t
+#define SD4_EMMC_TOP_PSTATE_RESERVED_MASK 0xE000F0F0
+#define SD4_EMMC_TOP_PSTATE_DLS7_4_SHIFT 25
+#define SD4_EMMC_TOP_PSTATE_DLS7_4_MASK 0x1E000000
+#define SD4_EMMC_TOP_PSTATE_CLSL_SHIFT 24
+#define SD4_EMMC_TOP_PSTATE_CLSL_MASK 0x01000000
+#define SD4_EMMC_TOP_PSTATE_DLS3_0_SHIFT 20
+#define SD4_EMMC_TOP_PSTATE_DLS3_0_MASK 0x00F00000
+#define SD4_EMMC_TOP_PSTATE_WPSL_SHIFT 19
+#define SD4_EMMC_TOP_PSTATE_WPSL_MASK 0x00080000
+#define SD4_EMMC_TOP_PSTATE_CDPL_SHIFT 18
+#define SD4_EMMC_TOP_PSTATE_CDPL_MASK 0x00040000
+#define SD4_EMMC_TOP_PSTATE_CSS_SHIFT 17
+#define SD4_EMMC_TOP_PSTATE_CSS_MASK 0x00020000
+#define SD4_EMMC_TOP_PSTATE_CINS_SHIFT 16
+#define SD4_EMMC_TOP_PSTATE_CINS_MASK 0x00010000
+#define SD4_EMMC_TOP_PSTATE_BREN_SHIFT 11
+#define SD4_EMMC_TOP_PSTATE_BREN_MASK 0x00000800
+#define SD4_EMMC_TOP_PSTATE_BWEN_SHIFT 10
+#define SD4_EMMC_TOP_PSTATE_BWEN_MASK 0x00000400
+#define SD4_EMMC_TOP_PSTATE_RXACT_SHIFT 9
+#define SD4_EMMC_TOP_PSTATE_RXACT_MASK 0x00000200
+#define SD4_EMMC_TOP_PSTATE_WXACT_SHIFT 8
+#define SD4_EMMC_TOP_PSTATE_WXACT_MASK 0x00000100
+#define SD4_EMMC_TOP_PSTATE_RETUNE_REQ_SHIFT 3
+#define SD4_EMMC_TOP_PSTATE_RETUNE_REQ_MASK 0x00000008
+#define SD4_EMMC_TOP_PSTATE_DATACT_SHIFT 2
+#define SD4_EMMC_TOP_PSTATE_DATACT_MASK 0x00000004
+#define SD4_EMMC_TOP_PSTATE_DATINH_SHIFT 1
+#define SD4_EMMC_TOP_PSTATE_DATINH_MASK 0x00000002
+#define SD4_EMMC_TOP_PSTATE_CMDINH_SHIFT 0
+#define SD4_EMMC_TOP_PSTATE_CMDINH_MASK 0x00000001
+
+#define SD4_EMMC_TOP_PSTATE_SD4_OFFSET 0x00000024
+#define SD4_EMMC_TOP_PSTATE_SD4_DEFAULT 0x01FC00F0
+#define SD4_EMMC_TOP_PSTATE_SD4_TYPE uint32_t
+#define SD4_EMMC_TOP_PSTATE_SD4_RESERVED_MASK 0x1E00F000
+#define SD4_EMMC_TOP_PSTATE_SD4_STBLDET_SHIFT 31
+#define SD4_EMMC_TOP_PSTATE_SD4_STBLDET_MASK 0x80000000
+#define SD4_EMMC_TOP_PSTATE_SD4_LANESYNC_SHIFT 30
+#define SD4_EMMC_TOP_PSTATE_SD4_LANESYNC_MASK 0x40000000
+#define SD4_EMMC_TOP_PSTATE_SD4_INDORMNTSTATE_SHIFT 29
+#define SD4_EMMC_TOP_PSTATE_SD4_INDORMNTSTATE_MASK 0x20000000
+#define SD4_EMMC_TOP_PSTATE_SD4_CLSL_SHIFT 24
+#define SD4_EMMC_TOP_PSTATE_SD4_CLSL_MASK 0x01000000
+#define SD4_EMMC_TOP_PSTATE_SD4_DLS3_0_SHIFT 20
+#define SD4_EMMC_TOP_PSTATE_SD4_DLS3_0_MASK 0x00F00000
+#define SD4_EMMC_TOP_PSTATE_SD4_WPSL_SHIFT 19
+#define SD4_EMMC_TOP_PSTATE_SD4_WPSL_MASK 0x00080000
+#define SD4_EMMC_TOP_PSTATE_SD4_CDPL_SHIFT 18
+#define SD4_EMMC_TOP_PSTATE_SD4_CDPL_MASK 0x00040000
+#define SD4_EMMC_TOP_PSTATE_SD4_CSS_SHIFT 17
+#define SD4_EMMC_TOP_PSTATE_SD4_CSS_MASK 0x00020000
+#define SD4_EMMC_TOP_PSTATE_SD4_CINS_SHIFT 16
+#define SD4_EMMC_TOP_PSTATE_SD4_CINS_MASK 0x00010000
+#define SD4_EMMC_TOP_PSTATE_SD4_BREN_SHIFT 11
+#define SD4_EMMC_TOP_PSTATE_SD4_BREN_MASK 0x00000800
+#define SD4_EMMC_TOP_PSTATE_SD4_BWEN_SHIFT 10
+#define SD4_EMMC_TOP_PSTATE_SD4_BWEN_MASK 0x00000400
+#define SD4_EMMC_TOP_PSTATE_SD4_RXACT_SHIFT 9
+#define SD4_EMMC_TOP_PSTATE_SD4_RXACT_MASK 0x00000200
+#define SD4_EMMC_TOP_PSTATE_SD4_WXACT_SHIFT 8
+#define SD4_EMMC_TOP_PSTATE_SD4_WXACT_MASK 0x00000100
+#define SD4_EMMC_TOP_PSTATE_SD4_DLS7_4_SHIFT 4
+#define SD4_EMMC_TOP_PSTATE_SD4_DLS7_4_MASK 0x000000F0
+#define SD4_EMMC_TOP_PSTATE_SD4_RETUNE_REQ_SHIFT 3
+#define SD4_EMMC_TOP_PSTATE_SD4_RETUNE_REQ_MASK 0x00000008
+#define SD4_EMMC_TOP_PSTATE_SD4_DATACT_SHIFT 2
+#define SD4_EMMC_TOP_PSTATE_SD4_DATACT_MASK 0x00000004
+#define SD4_EMMC_TOP_PSTATE_SD4_DATINH_SHIFT 1
+#define SD4_EMMC_TOP_PSTATE_SD4_DATINH_MASK 0x00000002
+#define SD4_EMMC_TOP_PSTATE_SD4_CMDINH_SHIFT 0
+#define SD4_EMMC_TOP_PSTATE_SD4_CMDINH_MASK 0x00000001
+
+#define SD4_EMMC_TOP_CTRL_OFFSET 0x00000028
+#define SD4_EMMC_TOP_CTRL_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_CTRL_TYPE uint32_t
+#define SD4_EMMC_TOP_CTRL_RESERVED_MASK 0xF800E000
+#define SD4_EMMC_TOP_CTRL_WAKENRMV_SHIFT 26
+#define SD4_EMMC_TOP_CTRL_WAKENRMV_MASK 0x04000000
+#define SD4_EMMC_TOP_CTRL_WAKENINS_SHIFT 25
+#define SD4_EMMC_TOP_CTRL_WAKENINS_MASK 0x02000000
+#define SD4_EMMC_TOP_CTRL_WAKENIRQ_SHIFT 24
+#define SD4_EMMC_TOP_CTRL_WAKENIRQ_MASK 0x01000000
+#define SD4_EMMC_TOP_CTRL_BOOTACK_SHIFT 23
+#define SD4_EMMC_TOP_CTRL_BOOTACK_MASK 0x00800000
+#define SD4_EMMC_TOP_CTRL_ATLBOOTEN_SHIFT 22
+#define SD4_EMMC_TOP_CTRL_ATLBOOTEN_MASK 0x00400000
+#define SD4_EMMC_TOP_CTRL_BOOTEN_SHIFT 21
+#define SD4_EMMC_TOP_CTRL_BOOTEN_MASK 0x00200000
+#define SD4_EMMC_TOP_CTRL_SPIMODE_SHIFT 20
+#define SD4_EMMC_TOP_CTRL_SPIMODE_MASK 0x00100000
+#define SD4_EMMC_TOP_CTRL_BLKIRQ_SHIFT 19
+#define SD4_EMMC_TOP_CTRL_BLKIRQ_MASK 0x00080000
+#define SD4_EMMC_TOP_CTRL_RDWTCRTL_SHIFT 18
+#define SD4_EMMC_TOP_CTRL_RDWTCRTL_MASK 0x00040000
+#define SD4_EMMC_TOP_CTRL_CONTREQ_SHIFT 17
+#define SD4_EMMC_TOP_CTRL_CONTREQ_MASK 0x00020000
+#define SD4_EMMC_TOP_CTRL_BLKSTPREQ_SHIFT 16
+#define SD4_EMMC_TOP_CTRL_BLKSTPREQ_MASK 0x00010000
+#define SD4_EMMC_TOP_CTRL_HRESET_SHIFT 12
+#define SD4_EMMC_TOP_CTRL_HRESET_MASK 0x00001000
+#define SD4_EMMC_TOP_CTRL_SDVSELVDD1_SHIFT 9
+#define SD4_EMMC_TOP_CTRL_SDVSELVDD1_MASK 0x00000E00
+#define SD4_EMMC_TOP_CTRL_SDPWR_SHIFT 8
+#define SD4_EMMC_TOP_CTRL_SDPWR_MASK 0x00000100
+#define SD4_EMMC_TOP_CTRL_CDSD_SHIFT 7
+#define SD4_EMMC_TOP_CTRL_CDSD_MASK 0x00000080
+#define SD4_EMMC_TOP_CTRL_CDTL_SHIFT 6
+#define SD4_EMMC_TOP_CTRL_CDTL_MASK 0x00000040
+#define SD4_EMMC_TOP_CTRL_SDB_SHIFT 5
+#define SD4_EMMC_TOP_CTRL_SDB_MASK 0x00000020
+#define SD4_EMMC_TOP_CTRL_DMASEL_SHIFT 3
+#define SD4_EMMC_TOP_CTRL_DMASEL_MASK 0x00000018
+#define SD4_EMMC_TOP_CTRL_HSEN_SHIFT 2
+#define SD4_EMMC_TOP_CTRL_HSEN_MASK 0x00000004
+#define SD4_EMMC_TOP_CTRL_DXTW_SHIFT 1
+#define SD4_EMMC_TOP_CTRL_DXTW_MASK 0x00000002
+#define SD4_EMMC_TOP_CTRL_LEDCTL_SHIFT 0
+#define SD4_EMMC_TOP_CTRL_LEDCTL_MASK 0x00000001
+
+#define SD4_EMMC_TOP_CTRL_SD4_OFFSET 0x00000028
+#define SD4_EMMC_TOP_CTRL_SD4_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_CTRL_SD4_TYPE uint32_t
+#define SD4_EMMC_TOP_CTRL_SD4_RESERVED_MASK 0xF8F00000
+#define SD4_EMMC_TOP_CTRL_SD4_WAKENRMV_SHIFT 26
+#define SD4_EMMC_TOP_CTRL_SD4_WAKENRMV_MASK 0x04000000
+#define SD4_EMMC_TOP_CTRL_SD4_WAKENINS_SHIFT 25
+#define SD4_EMMC_TOP_CTRL_SD4_WAKENINS_MASK 0x02000000
+#define SD4_EMMC_TOP_CTRL_SD4_WAKENIRQ_SHIFT 24
+#define SD4_EMMC_TOP_CTRL_SD4_WAKENIRQ_MASK 0x01000000
+#define SD4_EMMC_TOP_CTRL_SD4_BLKIRQ_SHIFT 19
+#define SD4_EMMC_TOP_CTRL_SD4_BLKIRQ_MASK 0x00080000
+#define SD4_EMMC_TOP_CTRL_SD4_RDWTCRTL_SHIFT 18
+#define SD4_EMMC_TOP_CTRL_SD4_RDWTCRTL_MASK 0x00040000
+#define SD4_EMMC_TOP_CTRL_SD4_CONTREQ_SHIFT 17
+#define SD4_EMMC_TOP_CTRL_SD4_CONTREQ_MASK 0x00020000
+#define SD4_EMMC_TOP_CTRL_SD4_BLKSTPREQ_SHIFT 16
+#define SD4_EMMC_TOP_CTRL_SD4_BLKSTPREQ_MASK 0x00010000
+#define SD4_EMMC_TOP_CTRL_SD4_SDVSELVDD2_SHIFT 13
+#define SD4_EMMC_TOP_CTRL_SD4_SDVSELVDD2_MASK 0x0000E000
+#define SD4_EMMC_TOP_CTRL_SD4_SDPWRVDD2_SHIFT 12
+#define SD4_EMMC_TOP_CTRL_SD4_SDPWRVDD2_MASK 0x00001000
+#define SD4_EMMC_TOP_CTRL_SD4_SDVSELVDD1_SHIFT 9
+#define SD4_EMMC_TOP_CTRL_SD4_SDVSELVDD1_MASK 0x00000E00
+#define SD4_EMMC_TOP_CTRL_SD4_SDPWR_SHIFT 8
+#define SD4_EMMC_TOP_CTRL_SD4_SDPWR_MASK 0x00000100
+#define SD4_EMMC_TOP_CTRL_SD4_CDSD_SHIFT 7
+#define SD4_EMMC_TOP_CTRL_SD4_CDSD_MASK 0x00000080
+#define SD4_EMMC_TOP_CTRL_SD4_CDTL_SHIFT 6
+#define SD4_EMMC_TOP_CTRL_SD4_CDTL_MASK 0x00000040
+#define SD4_EMMC_TOP_CTRL_SD4_SDB_SHIFT 5
+#define SD4_EMMC_TOP_CTRL_SD4_SDB_MASK 0x00000020
+#define SD4_EMMC_TOP_CTRL_SD4_DMASEL_SHIFT 3
+#define SD4_EMMC_TOP_CTRL_SD4_DMASEL_MASK 0x00000018
+#define SD4_EMMC_TOP_CTRL_SD4_HSEN_SHIFT 2
+#define SD4_EMMC_TOP_CTRL_SD4_HSEN_MASK 0x00000004
+#define SD4_EMMC_TOP_CTRL_SD4_DXTW_SHIFT 1
+#define SD4_EMMC_TOP_CTRL_SD4_DXTW_MASK 0x00000002
+#define SD4_EMMC_TOP_CTRL_SD4_LEDCTL_SHIFT 0
+#define SD4_EMMC_TOP_CTRL_SD4_LEDCTL_MASK 0x00000001
+
+#define SD4_EMMC_TOP_CTRL1_OFFSET 0x0000002C
+#define SD4_EMMC_TOP_CTRL1_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_CTRL1_TYPE uint32_t
+#define SD4_EMMC_TOP_CTRL1_RESERVED_MASK 0xF8F00018
+#define SD4_EMMC_TOP_CTRL1_DATRST_SHIFT 26
+#define SD4_EMMC_TOP_CTRL1_DATRST_MASK 0x04000000
+#define SD4_EMMC_TOP_CTRL1_CMDRST_SHIFT 25
+#define SD4_EMMC_TOP_CTRL1_CMDRST_MASK 0x02000000
+#define SD4_EMMC_TOP_CTRL1_RST_SHIFT 24
+#define SD4_EMMC_TOP_CTRL1_RST_MASK 0x01000000
+#define SD4_EMMC_TOP_CTRL1_DTCNT_SHIFT 16
+#define SD4_EMMC_TOP_CTRL1_DTCNT_MASK 0x000F0000
+#define SD4_EMMC_TOP_CTRL1_SDCLKSEL_SHIFT 8
+#define SD4_EMMC_TOP_CTRL1_SDCLKSEL_MASK 0x0000FF00
+#define SD4_EMMC_TOP_CTRL1_SDCLKSEL_UP_SHIFT 6
+#define SD4_EMMC_TOP_CTRL1_SDCLKSEL_UP_MASK 0x000000C0
+#define SD4_EMMC_TOP_CTRL1_CLKGENSEL_SHIFT 5
+#define SD4_EMMC_TOP_CTRL1_CLKGENSEL_MASK 0x00000020
+#define SD4_EMMC_TOP_CTRL1_SDCLKEN_SHIFT 2
+#define SD4_EMMC_TOP_CTRL1_SDCLKEN_MASK 0x00000004
+#define SD4_EMMC_TOP_CTRL1_ICLKSTB_SHIFT 1
+#define SD4_EMMC_TOP_CTRL1_ICLKSTB_MASK 0x00000002
+#define SD4_EMMC_TOP_CTRL1_ICLKEN_SHIFT 0
+#define SD4_EMMC_TOP_CTRL1_ICLKEN_MASK 0x00000001
+
+#define SD4_EMMC_TOP_INTR_OFFSET 0x00000030
+#define SD4_EMMC_TOP_INTR_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_INTR_TYPE uint32_t
+#define SD4_EMMC_TOP_INTR_RESERVED_MASK 0xEC000000
+#define SD4_EMMC_TOP_INTR_TRESPERR_SHIFT 28
+#define SD4_EMMC_TOP_INTR_TRESPERR_MASK 0x10000000
+#define SD4_EMMC_TOP_INTR_ADMAERR_SHIFT 25
+#define SD4_EMMC_TOP_INTR_ADMAERR_MASK 0x02000000
+#define SD4_EMMC_TOP_INTR_CMDERROR_SHIFT 24
+#define SD4_EMMC_TOP_INTR_CMDERROR_MASK 0x01000000
+#define SD4_EMMC_TOP_INTR_IERR_SHIFT 23
+#define SD4_EMMC_TOP_INTR_IERR_MASK 0x00800000
+#define SD4_EMMC_TOP_INTR_DEBERR_SHIFT 22
+#define SD4_EMMC_TOP_INTR_DEBERR_MASK 0x00400000
+#define SD4_EMMC_TOP_INTR_DCRCERR_SHIFT 21
+#define SD4_EMMC_TOP_INTR_DCRCERR_MASK 0x00200000
+#define SD4_EMMC_TOP_INTR_DTOERR_SHIFT 20
+#define SD4_EMMC_TOP_INTR_DTOERR_MASK 0x00100000
+#define SD4_EMMC_TOP_INTR_CMDIDXERR_SHIFT 19
+#define SD4_EMMC_TOP_INTR_CMDIDXERR_MASK 0x00080000
+#define SD4_EMMC_TOP_INTR_CEBERR_SHIFT 18
+#define SD4_EMMC_TOP_INTR_CEBERR_MASK 0x00040000
+#define SD4_EMMC_TOP_INTR_CCRCERR_SHIFT 17
+#define SD4_EMMC_TOP_INTR_CCRCERR_MASK 0x00020000
+#define SD4_EMMC_TOP_INTR_CTOERR_SHIFT 16
+#define SD4_EMMC_TOP_INTR_CTOERR_MASK 0x00010000
+#define SD4_EMMC_TOP_INTR_ERRIRQ_SHIFT 15
+#define SD4_EMMC_TOP_INTR_ERRIRQ_MASK 0x00008000
+#define SD4_EMMC_TOP_INTR_BTIRQ_SHIFT 14
+#define SD4_EMMC_TOP_INTR_BTIRQ_MASK 0x00004000
+#define SD4_EMMC_TOP_INTR_BTACKRX_SHIFT 13
+#define SD4_EMMC_TOP_INTR_BTACKRX_MASK 0x00002000
+#define SD4_EMMC_TOP_INTR_RETUNE_EVENT_SHIFT 12
+#define SD4_EMMC_TOP_INTR_RETUNE_EVENT_MASK 0x00001000
+#define SD4_EMMC_TOP_INTR_INT_C_SHIFT 11
+#define SD4_EMMC_TOP_INTR_INT_C_MASK 0x00000800
+#define SD4_EMMC_TOP_INTR_INT_B_SHIFT 10
+#define SD4_EMMC_TOP_INTR_INT_B_MASK 0x00000400
+#define SD4_EMMC_TOP_INTR_INT_A_SHIFT 9
+#define SD4_EMMC_TOP_INTR_INT_A_MASK 0x00000200
+#define SD4_EMMC_TOP_INTR_CRDIRQ_SHIFT 8
+#define SD4_EMMC_TOP_INTR_CRDIRQ_MASK 0x00000100
+#define SD4_EMMC_TOP_INTR_CRDRMV_SHIFT 7
+#define SD4_EMMC_TOP_INTR_CRDRMV_MASK 0x00000080
+#define SD4_EMMC_TOP_INTR_CRDINS_SHIFT 6
+#define SD4_EMMC_TOP_INTR_CRDINS_MASK 0x00000040
+#define SD4_EMMC_TOP_INTR_BRRDY_SHIFT 5
+#define SD4_EMMC_TOP_INTR_BRRDY_MASK 0x00000020
+#define SD4_EMMC_TOP_INTR_BWRDY_SHIFT 4
+#define SD4_EMMC_TOP_INTR_BWRDY_MASK 0x00000010
+#define SD4_EMMC_TOP_INTR_DMAIRQ_SHIFT 3
+#define SD4_EMMC_TOP_INTR_DMAIRQ_MASK 0x00000008
+#define SD4_EMMC_TOP_INTR_BLKENT_SHIFT 2
+#define SD4_EMMC_TOP_INTR_BLKENT_MASK 0x00000004
+#define SD4_EMMC_TOP_INTR_TXDONE_SHIFT 1
+#define SD4_EMMC_TOP_INTR_TXDONE_MASK 0x00000002
+#define SD4_EMMC_TOP_INTR_CMDDONE_SHIFT 0
+#define SD4_EMMC_TOP_INTR_CMDDONE_MASK 0x00000001
+
+#define SD4_EMMC_TOP_INTR_SD4_OFFSET 0x00000030
+#define SD4_EMMC_TOP_INTR_SD4_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_INTR_SD4_TYPE uint32_t
+#define SD4_EMMC_TOP_INTR_SD4_RESERVED_MASK 0xF0006000
+#define SD4_EMMC_TOP_INTR_SD4_TRESPERR_SHIFT 27
+#define SD4_EMMC_TOP_INTR_SD4_TRESPERR_MASK 0x08000000
+#define SD4_EMMC_TOP_INTR_SD4_TUNEERR_SHIFT 26
+#define SD4_EMMC_TOP_INTR_SD4_TUNEERR_MASK 0x04000000
+#define SD4_EMMC_TOP_INTR_SD4_ADMAERR_SHIFT 25
+#define SD4_EMMC_TOP_INTR_SD4_ADMAERR_MASK 0x02000000
+#define SD4_EMMC_TOP_INTR_SD4_CMDERROR_SHIFT 24
+#define SD4_EMMC_TOP_INTR_SD4_CMDERROR_MASK 0x01000000
+#define SD4_EMMC_TOP_INTR_SD4_IERR_SHIFT 23
+#define SD4_EMMC_TOP_INTR_SD4_IERR_MASK 0x00800000
+#define SD4_EMMC_TOP_INTR_SD4_DEBERR_SHIFT 22
+#define SD4_EMMC_TOP_INTR_SD4_DEBERR_MASK 0x00400000
+#define SD4_EMMC_TOP_INTR_SD4_DCRCERR_SHIFT 21
+#define SD4_EMMC_TOP_INTR_SD4_DCRCERR_MASK 0x00200000
+#define SD4_EMMC_TOP_INTR_SD4_DTOERR_SHIFT 20
+#define SD4_EMMC_TOP_INTR_SD4_DTOERR_MASK 0x00100000
+#define SD4_EMMC_TOP_INTR_SD4_CMDIDXERR_SHIFT 19
+#define SD4_EMMC_TOP_INTR_SD4_CMDIDXERR_MASK 0x00080000
+#define SD4_EMMC_TOP_INTR_SD4_CEBERR_SHIFT 18
+#define SD4_EMMC_TOP_INTR_SD4_CEBERR_MASK 0x00040000
+#define SD4_EMMC_TOP_INTR_SD4_CCRCERR_SHIFT 17
+#define SD4_EMMC_TOP_INTR_SD4_CCRCERR_MASK 0x00020000
+#define SD4_EMMC_TOP_INTR_SD4_CTOERR_SHIFT 16
+#define SD4_EMMC_TOP_INTR_SD4_CTOERR_MASK 0x00010000
+#define SD4_EMMC_TOP_INTR_SD4_ERRIRQ_SHIFT 15
+#define SD4_EMMC_TOP_INTR_SD4_ERRIRQ_MASK 0x00008000
+#define SD4_EMMC_TOP_INTR_SD4_RETUNE_EVENT_SHIFT 12
+#define SD4_EMMC_TOP_INTR_SD4_RETUNE_EVENT_MASK 0x00001000
+#define SD4_EMMC_TOP_INTR_SD4_INT_C_SHIFT 11
+#define SD4_EMMC_TOP_INTR_SD4_INT_C_MASK 0x00000800
+#define SD4_EMMC_TOP_INTR_SD4_INT_B_SHIFT 10
+#define SD4_EMMC_TOP_INTR_SD4_INT_B_MASK 0x00000400
+#define SD4_EMMC_TOP_INTR_SD4_INT_A_SHIFT 9
+#define SD4_EMMC_TOP_INTR_SD4_INT_A_MASK 0x00000200
+#define SD4_EMMC_TOP_INTR_SD4_CRDIRQ_SHIFT 8
+#define SD4_EMMC_TOP_INTR_SD4_CRDIRQ_MASK 0x00000100
+#define SD4_EMMC_TOP_INTR_SD4_CRDRMV_SHIFT 7
+#define SD4_EMMC_TOP_INTR_SD4_CRDRMV_MASK 0x00000080
+#define SD4_EMMC_TOP_INTR_SD4_CRDINS_SHIFT 6
+#define SD4_EMMC_TOP_INTR_SD4_CRDINS_MASK 0x00000040
+#define SD4_EMMC_TOP_INTR_SD4_BRRDY_SHIFT 5
+#define SD4_EMMC_TOP_INTR_SD4_BRRDY_MASK 0x00000020
+#define SD4_EMMC_TOP_INTR_SD4_BWRDY_SHIFT 4
+#define SD4_EMMC_TOP_INTR_SD4_BWRDY_MASK 0x00000010
+#define SD4_EMMC_TOP_INTR_SD4_DMAIRQ_SHIFT 3
+#define SD4_EMMC_TOP_INTR_SD4_DMAIRQ_MASK 0x00000008
+#define SD4_EMMC_TOP_INTR_SD4_BLKENT_SHIFT 2
+#define SD4_EMMC_TOP_INTR_SD4_BLKENT_MASK 0x00000004
+#define SD4_EMMC_TOP_INTR_SD4_TXDONE_SHIFT 1
+#define SD4_EMMC_TOP_INTR_SD4_TXDONE_MASK 0x00000002
+#define SD4_EMMC_TOP_INTR_SD4_CMDDONE_SHIFT 0
+#define SD4_EMMC_TOP_INTR_SD4_CMDDONE_MASK 0x00000001
+
+#define SD4_EMMC_TOP_INTREN1_OFFSET 0x00000034
+#define SD4_EMMC_TOP_INTREN1_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_INTREN1_TYPE uint32_t
+#define SD4_EMMC_TOP_INTREN1_RESERVED_MASK 0xEC000000
+#define SD4_EMMC_TOP_INTREN1_TRESPERREN_SHIFT 28
+#define SD4_EMMC_TOP_INTREN1_TRESPERREN_MASK 0x10000000
+#define SD4_EMMC_TOP_INTREN1_ADMAEREN_SHIFT 25
+#define SD4_EMMC_TOP_INTREN1_ADMAEREN_MASK 0x02000000
+#define SD4_EMMC_TOP_INTREN1_CMDERREN_SHIFT 24
+#define SD4_EMMC_TOP_INTREN1_CMDERREN_MASK 0x01000000
+#define SD4_EMMC_TOP_INTREN1_ILIMERREN_SHIFT 23
+#define SD4_EMMC_TOP_INTREN1_ILIMERREN_MASK 0x00800000
+#define SD4_EMMC_TOP_INTREN1_DEBERREN_SHIFT 22
+#define SD4_EMMC_TOP_INTREN1_DEBERREN_MASK 0x00400000
+#define SD4_EMMC_TOP_INTREN1_DCRCERREN_SHIFT 21
+#define SD4_EMMC_TOP_INTREN1_DCRCERREN_MASK 0x00200000
+#define SD4_EMMC_TOP_INTREN1_DTOERREN_SHIFT 20
+#define SD4_EMMC_TOP_INTREN1_DTOERREN_MASK 0x00100000
+#define SD4_EMMC_TOP_INTREN1_CIDXERREN_SHIFT 19
+#define SD4_EMMC_TOP_INTREN1_CIDXERREN_MASK 0x00080000
+#define SD4_EMMC_TOP_INTREN1_CEBERREN_SHIFT 18
+#define SD4_EMMC_TOP_INTREN1_CEBERREN_MASK 0x00040000
+#define SD4_EMMC_TOP_INTREN1_CMDCRCEN_SHIFT 17
+#define SD4_EMMC_TOP_INTREN1_CMDCRCEN_MASK 0x00020000
+#define SD4_EMMC_TOP_INTREN1_CMDTOEN_SHIFT 16
+#define SD4_EMMC_TOP_INTREN1_CMDTOEN_MASK 0x00010000
+#define SD4_EMMC_TOP_INTREN1_FIXZ_SHIFT 15
+#define SD4_EMMC_TOP_INTREN1_FIXZ_MASK 0x00008000
+#define SD4_EMMC_TOP_INTREN1_BTIRQEN_SHIFT 14
+#define SD4_EMMC_TOP_INTREN1_BTIRQEN_MASK 0x00004000
+#define SD4_EMMC_TOP_INTREN1_BTACKRXEN_SHIFT 13
+#define SD4_EMMC_TOP_INTREN1_BTACKRXEN_MASK 0x00002000
+#define SD4_EMMC_TOP_INTREN1_RETUNE_EVENTEN_SHIFT 12
+#define SD4_EMMC_TOP_INTREN1_RETUNE_EVENTEN_MASK 0x00001000
+#define SD4_EMMC_TOP_INTREN1_INT_C_EN_SHIFT 11
+#define SD4_EMMC_TOP_INTREN1_INT_C_EN_MASK 0x00000800
+#define SD4_EMMC_TOP_INTREN1_INT_B_EN_SHIFT 10
+#define SD4_EMMC_TOP_INTREN1_INT_B_EN_MASK 0x00000400
+#define SD4_EMMC_TOP_INTREN1_INT_A_EN_SHIFT 9
+#define SD4_EMMC_TOP_INTREN1_INT_A_EN_MASK 0x00000200
+#define SD4_EMMC_TOP_INTREN1_CIRQEN_SHIFT 8
+#define SD4_EMMC_TOP_INTREN1_CIRQEN_MASK 0x00000100
+#define SD4_EMMC_TOP_INTREN1_CRDRMVEN_SHIFT 7
+#define SD4_EMMC_TOP_INTREN1_CRDRMVEN_MASK 0x00000080
+#define SD4_EMMC_TOP_INTREN1_CRDINSEN_SHIFT 6
+#define SD4_EMMC_TOP_INTREN1_CRDINSEN_MASK 0x00000040
+#define SD4_EMMC_TOP_INTREN1_BUFRREN_SHIFT 5
+#define SD4_EMMC_TOP_INTREN1_BUFRREN_MASK 0x00000020
+#define SD4_EMMC_TOP_INTREN1_BUFWREN_SHIFT 4
+#define SD4_EMMC_TOP_INTREN1_BUFWREN_MASK 0x00000010
+#define SD4_EMMC_TOP_INTREN1_DMAIRQEN_SHIFT 3
+#define SD4_EMMC_TOP_INTREN1_DMAIRQEN_MASK 0x00000008
+#define SD4_EMMC_TOP_INTREN1_BLKEN_SHIFT 2
+#define SD4_EMMC_TOP_INTREN1_BLKEN_MASK 0x00000004
+#define SD4_EMMC_TOP_INTREN1_TXDONEEN_SHIFT 1
+#define SD4_EMMC_TOP_INTREN1_TXDONEEN_MASK 0x00000002
+#define SD4_EMMC_TOP_INTREN1_CMDDONEEN_SHIFT 0
+#define SD4_EMMC_TOP_INTREN1_CMDDONEEN_MASK 0x00000001
+
+#define SD4_EMMC_TOP_INTREN1_SD4_OFFSET 0x00000034
+#define SD4_EMMC_TOP_INTREN1_SD4_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_INTREN1_SD4_TYPE uint32_t
+#define SD4_EMMC_TOP_INTREN1_SD4_RESERVED_MASK 0x00006000
+#define SD4_EMMC_TOP_INTREN1_SD4_VNDRERREN_SHIFT 28
+#define SD4_EMMC_TOP_INTREN1_SD4_VNDRERREN_MASK 0xF0000000
+#define SD4_EMMC_TOP_INTREN1_SD4_TRESPERREN_SHIFT 27
+#define SD4_EMMC_TOP_INTREN1_SD4_TRESPERREN_MASK 0x08000000
+#define SD4_EMMC_TOP_INTREN1_SD4_TUNEERREN_SHIFT 26
+#define SD4_EMMC_TOP_INTREN1_SD4_TUNEERREN_MASK 0x04000000
+#define SD4_EMMC_TOP_INTREN1_SD4_ADMAEREN_SHIFT 25
+#define SD4_EMMC_TOP_INTREN1_SD4_ADMAEREN_MASK 0x02000000
+#define SD4_EMMC_TOP_INTREN1_SD4_CMDERREN_SHIFT 24
+#define SD4_EMMC_TOP_INTREN1_SD4_CMDERREN_MASK 0x01000000
+#define SD4_EMMC_TOP_INTREN1_SD4_ILIMERREN_SHIFT 23
+#define SD4_EMMC_TOP_INTREN1_SD4_ILIMERREN_MASK 0x00800000
+#define SD4_EMMC_TOP_INTREN1_SD4_DEBERREN_SHIFT 22
+#define SD4_EMMC_TOP_INTREN1_SD4_DEBERREN_MASK 0x00400000
+#define SD4_EMMC_TOP_INTREN1_SD4_DCRCERREN_SHIFT 21
+#define SD4_EMMC_TOP_INTREN1_SD4_DCRCERREN_MASK 0x00200000
+#define SD4_EMMC_TOP_INTREN1_SD4_DTOERREN_SHIFT 20
+#define SD4_EMMC_TOP_INTREN1_SD4_DTOERREN_MASK 0x00100000
+#define SD4_EMMC_TOP_INTREN1_SD4_CIDXERREN_SHIFT 19
+#define SD4_EMMC_TOP_INTREN1_SD4_CIDXERREN_MASK 0x00080000
+#define SD4_EMMC_TOP_INTREN1_SD4_CEBERREN_SHIFT 18
+#define SD4_EMMC_TOP_INTREN1_SD4_CEBERREN_MASK 0x00040000
+#define SD4_EMMC_TOP_INTREN1_SD4_CMDCRCEN_SHIFT 17
+#define SD4_EMMC_TOP_INTREN1_SD4_CMDCRCEN_MASK 0x00020000
+#define SD4_EMMC_TOP_INTREN1_SD4_CMDTOEN_SHIFT 16
+#define SD4_EMMC_TOP_INTREN1_SD4_CMDTOEN_MASK 0x00010000
+#define SD4_EMMC_TOP_INTREN1_SD4_FIXZ_SHIFT 15
+#define SD4_EMMC_TOP_INTREN1_SD4_FIXZ_MASK 0x00008000
+#define SD4_EMMC_TOP_INTREN1_SD4_RETUNE_EVENTEN_SHIFT 12
+#define SD4_EMMC_TOP_INTREN1_SD4_RETUNE_EVENTEN_MASK 0x00001000
+#define SD4_EMMC_TOP_INTREN1_SD4_INT_C_EN_SHIFT 11
+#define SD4_EMMC_TOP_INTREN1_SD4_INT_C_EN_MASK 0x00000800
+#define SD4_EMMC_TOP_INTREN1_SD4_INT_B_EN_SHIFT 10
+#define SD4_EMMC_TOP_INTREN1_SD4_INT_B_EN_MASK 0x00000400
+#define SD4_EMMC_TOP_INTREN1_SD4_INT_A_EN_SHIFT 9
+#define SD4_EMMC_TOP_INTREN1_SD4_INT_A_EN_MASK 0x00000200
+#define SD4_EMMC_TOP_INTREN1_SD4_CIRQEN_SHIFT 8
+#define SD4_EMMC_TOP_INTREN1_SD4_CIRQEN_MASK 0x00000100
+#define SD4_EMMC_TOP_INTREN1_SD4_CRDRMVEN_SHIFT 7
+#define SD4_EMMC_TOP_INTREN1_SD4_CRDRMVEN_MASK 0x00000080
+#define SD4_EMMC_TOP_INTREN1_SD4_CRDINSEN_SHIFT 6
+#define SD4_EMMC_TOP_INTREN1_SD4_CRDINSEN_MASK 0x00000040
+#define SD4_EMMC_TOP_INTREN1_SD4_BUFRREN_SHIFT 5
+#define SD4_EMMC_TOP_INTREN1_SD4_BUFRREN_MASK 0x00000020
+#define SD4_EMMC_TOP_INTREN1_SD4_BUFWREN_SHIFT 4
+#define SD4_EMMC_TOP_INTREN1_SD4_BUFWREN_MASK 0x00000010
+#define SD4_EMMC_TOP_INTREN1_SD4_DMAIRQEN_SHIFT 3
+#define SD4_EMMC_TOP_INTREN1_SD4_DMAIRQEN_MASK 0x00000008
+#define SD4_EMMC_TOP_INTREN1_SD4_BLKEN_SHIFT 2
+#define SD4_EMMC_TOP_INTREN1_SD4_BLKEN_MASK 0x00000004
+#define SD4_EMMC_TOP_INTREN1_SD4_TXDONEEN_SHIFT 1
+#define SD4_EMMC_TOP_INTREN1_SD4_TXDONEEN_MASK 0x00000002
+#define SD4_EMMC_TOP_INTREN1_SD4_CMDDONEEN_SHIFT 0
+#define SD4_EMMC_TOP_INTREN1_SD4_CMDDONEEN_MASK 0x00000001
+
+#define SD4_EMMC_TOP_INTREN2_OFFSET 0x00000038
+#define SD4_EMMC_TOP_INTREN2_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_INTREN2_TYPE uint32_t
+#define SD4_EMMC_TOP_INTREN2_RESERVED_MASK 0xEC000000
+#define SD4_EMMC_TOP_INTREN2_TRESPERRSEN_SHIFT 28
+#define SD4_EMMC_TOP_INTREN2_TRESPERRSEN_MASK 0x10000000
+#define SD4_EMMC_TOP_INTREN2_ADMASIGEN_SHIFT 25
+#define SD4_EMMC_TOP_INTREN2_ADMASIGEN_MASK 0x02000000
+#define SD4_EMMC_TOP_INTREN2_CMDSIGEN_SHIFT 24
+#define SD4_EMMC_TOP_INTREN2_CMDSIGEN_MASK 0x01000000
+#define SD4_EMMC_TOP_INTREN2_ILIMSIGEN_SHIFT 23
+#define SD4_EMMC_TOP_INTREN2_ILIMSIGEN_MASK 0x00800000
+#define SD4_EMMC_TOP_INTREN2_DEBSIGEN_SHIFT 22
+#define SD4_EMMC_TOP_INTREN2_DEBSIGEN_MASK 0x00400000
+#define SD4_EMMC_TOP_INTREN2_DCRCSIGEN_SHIFT 21
+#define SD4_EMMC_TOP_INTREN2_DCRCSIGEN_MASK 0x00200000
+#define SD4_EMMC_TOP_INTREN2_DTOSIGEN_SHIFT 20
+#define SD4_EMMC_TOP_INTREN2_DTOSIGEN_MASK 0x00100000
+#define SD4_EMMC_TOP_INTREN2_CIDXSIGEN_SHIFT 19
+#define SD4_EMMC_TOP_INTREN2_CIDXSIGEN_MASK 0x00080000
+#define SD4_EMMC_TOP_INTREN2_CEBSIGEN_SHIFT 18
+#define SD4_EMMC_TOP_INTREN2_CEBSIGEN_MASK 0x00040000
+#define SD4_EMMC_TOP_INTREN2_CMDCRCSIGEN_SHIFT 17
+#define SD4_EMMC_TOP_INTREN2_CMDCRCSIGEN_MASK 0x00020000
+#define SD4_EMMC_TOP_INTREN2_CMDTOSIGEN_SHIFT 16
+#define SD4_EMMC_TOP_INTREN2_CMDTOSIGEN_MASK 0x00010000
+#define SD4_EMMC_TOP_INTREN2_FIXZERO_SHIFT 15
+#define SD4_EMMC_TOP_INTREN2_FIXZERO_MASK 0x00008000
+#define SD4_EMMC_TOP_INTREN2_BTIRQSEN_SHIFT 14
+#define SD4_EMMC_TOP_INTREN2_BTIRQSEN_MASK 0x00004000
+#define SD4_EMMC_TOP_INTREN2_BTACKRXSEN_SHIFT 13
+#define SD4_EMMC_TOP_INTREN2_BTACKRXSEN_MASK 0x00002000
+#define SD4_EMMC_TOP_INTREN2_RETUNE_EVENTSIGEN_SHIFT 12
+#define SD4_EMMC_TOP_INTREN2_RETUNE_EVENTSIGEN_MASK 0x00001000
+#define SD4_EMMC_TOP_INTREN2_INT_C_SIGEN_SHIFT 11
+#define SD4_EMMC_TOP_INTREN2_INT_C_SIGEN_MASK 0x00000800
+#define SD4_EMMC_TOP_INTREN2_INT_B_SIGEN_SHIFT 10
+#define SD4_EMMC_TOP_INTREN2_INT_B_SIGEN_MASK 0x00000400
+#define SD4_EMMC_TOP_INTREN2_INT_A_SIGEN_SHIFT 9
+#define SD4_EMMC_TOP_INTREN2_INT_A_SIGEN_MASK 0x00000200
+#define SD4_EMMC_TOP_INTREN2_CRDIRQEN_SHIFT 8
+#define SD4_EMMC_TOP_INTREN2_CRDIRQEN_MASK 0x00000100
+#define SD4_EMMC_TOP_INTREN2_CRDRVMEN_SHIFT 7
+#define SD4_EMMC_TOP_INTREN2_CRDRVMEN_MASK 0x00000080
+#define SD4_EMMC_TOP_INTREN2_CRDINSEN_SHIFT 6
+#define SD4_EMMC_TOP_INTREN2_CRDINSEN_MASK 0x00000040
+#define SD4_EMMC_TOP_INTREN2_BUFRRDYEN_SHIFT 5
+#define SD4_EMMC_TOP_INTREN2_BUFRRDYEN_MASK 0x00000020
+#define SD4_EMMC_TOP_INTREN2_BUFWRDYEN_SHIFT 4
+#define SD4_EMMC_TOP_INTREN2_BUFWRDYEN_MASK 0x00000010
+#define SD4_EMMC_TOP_INTREN2_DMAIRQEN_SHIFT 3
+#define SD4_EMMC_TOP_INTREN2_DMAIRQEN_MASK 0x00000008
+#define SD4_EMMC_TOP_INTREN2_BLKGAPEN_SHIFT 2
+#define SD4_EMMC_TOP_INTREN2_BLKGAPEN_MASK 0x00000004
+#define SD4_EMMC_TOP_INTREN2_TXDONE_SHIFT 1
+#define SD4_EMMC_TOP_INTREN2_TXDONE_MASK 0x00000002
+#define SD4_EMMC_TOP_INTREN2_CMDDONE_SHIFT 0
+#define SD4_EMMC_TOP_INTREN2_CMDDONE_MASK 0x00000001
+
+#define SD4_EMMC_TOP_INTREN2_SD4_OFFSET 0x00000038
+#define SD4_EMMC_TOP_INTREN2_SD4_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_INTREN2_SD4_TYPE uint32_t
+#define SD4_EMMC_TOP_INTREN2_SD4_RESERVED_MASK 0xF0006000
+#define SD4_EMMC_TOP_INTREN2_SD4_TRESPERRSEN_SHIFT 27
+#define SD4_EMMC_TOP_INTREN2_SD4_TRESPERRSEN_MASK 0x08000000
+#define SD4_EMMC_TOP_INTREN2_SD4_TUNERRSIGEN_SHIFT 26
+#define SD4_EMMC_TOP_INTREN2_SD4_TUNERRSIGEN_MASK 0x04000000
+#define SD4_EMMC_TOP_INTREN2_SD4_ADMASIGEN_SHIFT 25
+#define SD4_EMMC_TOP_INTREN2_SD4_ADMASIGEN_MASK 0x02000000
+#define SD4_EMMC_TOP_INTREN2_SD4_CMDSIGEN_SHIFT 24
+#define SD4_EMMC_TOP_INTREN2_SD4_CMDSIGEN_MASK 0x01000000
+#define SD4_EMMC_TOP_INTREN2_SD4_ILIMSIGEN_SHIFT 23
+#define SD4_EMMC_TOP_INTREN2_SD4_ILIMSIGEN_MASK 0x00800000
+#define SD4_EMMC_TOP_INTREN2_SD4_DEBSIGEN_SHIFT 22
+#define SD4_EMMC_TOP_INTREN2_SD4_DEBSIGEN_MASK 0x00400000
+#define SD4_EMMC_TOP_INTREN2_SD4_DCRCSIGEN_SHIFT 21
+#define SD4_EMMC_TOP_INTREN2_SD4_DCRCSIGEN_MASK 0x00200000
+#define SD4_EMMC_TOP_INTREN2_SD4_DTOSIGEN_SHIFT 20
+#define SD4_EMMC_TOP_INTREN2_SD4_DTOSIGEN_MASK 0x00100000
+#define SD4_EMMC_TOP_INTREN2_SD4_CIDXSIGEN_SHIFT 19
+#define SD4_EMMC_TOP_INTREN2_SD4_CIDXSIGEN_MASK 0x00080000
+#define SD4_EMMC_TOP_INTREN2_SD4_CEBSIGEN_SHIFT 18
+#define SD4_EMMC_TOP_INTREN2_SD4_CEBSIGEN_MASK 0x00040000
+#define SD4_EMMC_TOP_INTREN2_SD4_CMDCRCSIGEN_SHIFT 17
+#define SD4_EMMC_TOP_INTREN2_SD4_CMDCRCSIGEN_MASK 0x00020000
+#define SD4_EMMC_TOP_INTREN2_SD4_CMDTOSIGEN_SHIFT 16
+#define SD4_EMMC_TOP_INTREN2_SD4_CMDTOSIGEN_MASK 0x00010000
+#define SD4_EMMC_TOP_INTREN2_SD4_FIXZERO_SHIFT 15
+#define SD4_EMMC_TOP_INTREN2_SD4_FIXZERO_MASK 0x00008000
+#define SD4_EMMC_TOP_INTREN2_SD4_RETUNE_EVENTSIGEN_SHIFT 12
+#define SD4_EMMC_TOP_INTREN2_SD4_RETUNE_EVENTSIGEN_MASK 0x00001000
+#define SD4_EMMC_TOP_INTREN2_SD4_INT_C_SIGEN_SHIFT 11
+#define SD4_EMMC_TOP_INTREN2_SD4_INT_C_SIGEN_MASK 0x00000800
+#define SD4_EMMC_TOP_INTREN2_SD4_INT_B_SIGEN_SHIFT 10
+#define SD4_EMMC_TOP_INTREN2_SD4_INT_B_SIGEN_MASK 0x00000400
+#define SD4_EMMC_TOP_INTREN2_SD4_INT_A_SIGEN_SHIFT 9
+#define SD4_EMMC_TOP_INTREN2_SD4_INT_A_SIGEN_MASK 0x00000200
+#define SD4_EMMC_TOP_INTREN2_SD4_CRDIRQEN_SHIFT 8
+#define SD4_EMMC_TOP_INTREN2_SD4_CRDIRQEN_MASK 0x00000100
+#define SD4_EMMC_TOP_INTREN2_SD4_CRDRVMEN_SHIFT 7
+#define SD4_EMMC_TOP_INTREN2_SD4_CRDRVMEN_MASK 0x00000080
+#define SD4_EMMC_TOP_INTREN2_SD4_CRDINSEN_SHIFT 6
+#define SD4_EMMC_TOP_INTREN2_SD4_CRDINSEN_MASK 0x00000040
+#define SD4_EMMC_TOP_INTREN2_SD4_BUFRRDYEN_SHIFT 5
+#define SD4_EMMC_TOP_INTREN2_SD4_BUFRRDYEN_MASK 0x00000020
+#define SD4_EMMC_TOP_INTREN2_SD4_BUFWRDYEN_SHIFT 4
+#define SD4_EMMC_TOP_INTREN2_SD4_BUFWRDYEN_MASK 0x00000010
+#define SD4_EMMC_TOP_INTREN2_SD4_DMAIRQEN_SHIFT 3
+#define SD4_EMMC_TOP_INTREN2_SD4_DMAIRQEN_MASK 0x00000008
+#define SD4_EMMC_TOP_INTREN2_SD4_BLKGAPEN_SHIFT 2
+#define SD4_EMMC_TOP_INTREN2_SD4_BLKGAPEN_MASK 0x00000004
+#define SD4_EMMC_TOP_INTREN2_SD4_TXDONE_SHIFT 1
+#define SD4_EMMC_TOP_INTREN2_SD4_TXDONE_MASK 0x00000002
+#define SD4_EMMC_TOP_INTREN2_SD4_CMDDONE_SHIFT 0
+#define SD4_EMMC_TOP_INTREN2_SD4_CMDDONE_MASK 0x00000001
+
+#define SD4_EMMC_TOP_ERRSTAT_OFFSET 0x0000003C
+#define SD4_EMMC_TOP_ERRSTAT_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_ERRSTAT_TYPE uint32_t
+#define SD4_EMMC_TOP_ERRSTAT_RESERVED_MASK 0x3F00FF60
+#define SD4_EMMC_TOP_ERRSTAT_PRESETEN_SHIFT 31
+#define SD4_EMMC_TOP_ERRSTAT_PRESETEN_MASK 0x80000000
+#define SD4_EMMC_TOP_ERRSTAT_ASYNC_INTREN_SHIFT 30
+#define SD4_EMMC_TOP_ERRSTAT_ASYNC_INTREN_MASK 0x40000000
+#define SD4_EMMC_TOP_ERRSTAT_SAMPLECLOCKSEL_SHIFT 23
+#define SD4_EMMC_TOP_ERRSTAT_SAMPLECLOCKSEL_MASK 0x00800000
+#define SD4_EMMC_TOP_ERRSTAT_EXECTUNE_SHIFT 22
+#define SD4_EMMC_TOP_ERRSTAT_EXECTUNE_MASK 0x00400000
+#define SD4_EMMC_TOP_ERRSTAT_DRVSTRESEL_SHIFT 20
+#define SD4_EMMC_TOP_ERRSTAT_DRVSTRESEL_MASK 0x00300000
+#define SD4_EMMC_TOP_ERRSTAT_EN1P8V_SHIFT 19
+#define SD4_EMMC_TOP_ERRSTAT_EN1P8V_MASK 0x00080000
+#define SD4_EMMC_TOP_ERRSTAT_UHSMODESEL_SHIFT 16
+#define SD4_EMMC_TOP_ERRSTAT_UHSMODESEL_MASK 0x00070000
+#define SD4_EMMC_TOP_ERRSTAT_NOCMD_SHIFT 7
+#define SD4_EMMC_TOP_ERRSTAT_NOCMD_MASK 0x00000080
+#define SD4_EMMC_TOP_ERRSTAT_CMDIDXERR_SHIFT 4
+#define SD4_EMMC_TOP_ERRSTAT_CMDIDXERR_MASK 0x00000010
+#define SD4_EMMC_TOP_ERRSTAT_CMDENDERR_SHIFT 3
+#define SD4_EMMC_TOP_ERRSTAT_CMDENDERR_MASK 0x00000008
+#define SD4_EMMC_TOP_ERRSTAT_CMDCRCERR_SHIFT 2
+#define SD4_EMMC_TOP_ERRSTAT_CMDCRCERR_MASK 0x00000004
+#define SD4_EMMC_TOP_ERRSTAT_CMDTOERR_SHIFT 1
+#define SD4_EMMC_TOP_ERRSTAT_CMDTOERR_MASK 0x00000002
+#define SD4_EMMC_TOP_ERRSTAT_CMDNOEXEC_SHIFT 0
+#define SD4_EMMC_TOP_ERRSTAT_CMDNOEXEC_MASK 0x00000001
+
+#define SD4_EMMC_TOP_ERRSTAT_SD4_OFFSET 0x0000003C
+#define SD4_EMMC_TOP_ERRSTAT_SD4_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_ERRSTAT_SD4_TYPE uint32_t
+#define SD4_EMMC_TOP_ERRSTAT_SD4_RESERVED_MASK 0x0E00FF40
+#define SD4_EMMC_TOP_ERRSTAT_SD4_PRESETEN_SHIFT 31
+#define SD4_EMMC_TOP_ERRSTAT_SD4_PRESETEN_MASK 0x80000000
+#define SD4_EMMC_TOP_ERRSTAT_SD4_ASYNC_INTREN_SHIFT 30
+#define SD4_EMMC_TOP_ERRSTAT_SD4_ASYNC_INTREN_MASK 0x40000000
+#define SD4_EMMC_TOP_ERRSTAT_SD4_ADDR64_SHIFT 29
+#define SD4_EMMC_TOP_ERRSTAT_SD4_ADDR64_MASK 0x20000000
+#define SD4_EMMC_TOP_ERRSTAT_SD4_HOSTVER4_00_SHIFT 28
+#define SD4_EMMC_TOP_ERRSTAT_SD4_HOSTVER4_00_MASK 0x10000000
+#define SD4_EMMC_TOP_ERRSTAT_SD4_UHS2INTFEN_SHIFT 24
+#define SD4_EMMC_TOP_ERRSTAT_SD4_UHS2INTFEN_MASK 0x01000000
+#define SD4_EMMC_TOP_ERRSTAT_SD4_SAMPLECLOCKSEL_SHIFT 23
+#define SD4_EMMC_TOP_ERRSTAT_SD4_SAMPLECLOCKSEL_MASK 0x00800000
+#define SD4_EMMC_TOP_ERRSTAT_SD4_EXECTUNE_SHIFT 22
+#define SD4_EMMC_TOP_ERRSTAT_SD4_EXECTUNE_MASK 0x00400000
+#define SD4_EMMC_TOP_ERRSTAT_SD4_DRVSTRESEL_SHIFT 20
+#define SD4_EMMC_TOP_ERRSTAT_SD4_DRVSTRESEL_MASK 0x00300000
+#define SD4_EMMC_TOP_ERRSTAT_SD4_EN1P8V_SHIFT 19
+#define SD4_EMMC_TOP_ERRSTAT_SD4_EN1P8V_MASK 0x00080000
+#define SD4_EMMC_TOP_ERRSTAT_SD4_UHSMODESEL_SHIFT 16
+#define SD4_EMMC_TOP_ERRSTAT_SD4_UHSMODESEL_MASK 0x00070000
+#define SD4_EMMC_TOP_ERRSTAT_SD4_NOCMD_SHIFT 7
+#define SD4_EMMC_TOP_ERRSTAT_SD4_NOCMD_MASK 0x00000080
+#define SD4_EMMC_TOP_ERRSTAT_SD4_CMDRESPERR_SHIFT 5
+#define SD4_EMMC_TOP_ERRSTAT_SD4_CMDRESPERR_MASK 0x00000020
+#define SD4_EMMC_TOP_ERRSTAT_SD4_CMDIDXERR_SHIFT 4
+#define SD4_EMMC_TOP_ERRSTAT_SD4_CMDIDXERR_MASK 0x00000010
+#define SD4_EMMC_TOP_ERRSTAT_SD4_CMDENDERR_SHIFT 3
+#define SD4_EMMC_TOP_ERRSTAT_SD4_CMDENDERR_MASK 0x00000008
+#define SD4_EMMC_TOP_ERRSTAT_SD4_CMDCRCERR_SHIFT 2
+#define SD4_EMMC_TOP_ERRSTAT_SD4_CMDCRCERR_MASK 0x00000004
+#define SD4_EMMC_TOP_ERRSTAT_SD4_CMDTOERR_SHIFT 1
+#define SD4_EMMC_TOP_ERRSTAT_SD4_CMDTOERR_MASK 0x00000002
+#define SD4_EMMC_TOP_ERRSTAT_SD4_CMDNOEXEC_SHIFT 0
+#define SD4_EMMC_TOP_ERRSTAT_SD4_CMDNOEXEC_MASK 0x00000001
+
+#define SD4_EMMC_TOP_CAPABILITIES1_OFFSET 0x00000040
+#define SD4_EMMC_TOP_CAPABILITIES1_DEFAULT 0x17EFD0B0
+#define SD4_EMMC_TOP_CAPABILITIES1_TYPE uint32_t
+#define SD4_EMMC_TOP_CAPABILITIES1_RESERVED_MASK 0x08100040
+#define SD4_EMMC_TOP_CAPABILITIES1_SLOTTYPE_SHIFT 30
+#define SD4_EMMC_TOP_CAPABILITIES1_SLOTTYPE_MASK 0xC0000000
+#define SD4_EMMC_TOP_CAPABILITIES1_ASYNCHIRQ_SHIFT 29
+#define SD4_EMMC_TOP_CAPABILITIES1_ASYNCHIRQ_MASK 0x20000000
+#define SD4_EMMC_TOP_CAPABILITIES1_SYSBUS64_SHIFT 28
+#define SD4_EMMC_TOP_CAPABILITIES1_SYSBUS64_MASK 0x10000000
+#define SD4_EMMC_TOP_CAPABILITIES1_V18_SHIFT 26
+#define SD4_EMMC_TOP_CAPABILITIES1_V18_MASK 0x04000000
+#define SD4_EMMC_TOP_CAPABILITIES1_V3_SHIFT 25
+#define SD4_EMMC_TOP_CAPABILITIES1_V3_MASK 0x02000000
+#define SD4_EMMC_TOP_CAPABILITIES1_V33_SHIFT 24
+#define SD4_EMMC_TOP_CAPABILITIES1_V33_MASK 0x01000000
+#define SD4_EMMC_TOP_CAPABILITIES1_SUPRSM_SHIFT 23
+#define SD4_EMMC_TOP_CAPABILITIES1_SUPRSM_MASK 0x00800000
+#define SD4_EMMC_TOP_CAPABILITIES1_SDMA_SHIFT 22
+#define SD4_EMMC_TOP_CAPABILITIES1_SDMA_MASK 0x00400000
+#define SD4_EMMC_TOP_CAPABILITIES1_HSPEED_SHIFT 21
+#define SD4_EMMC_TOP_CAPABILITIES1_HSPEED_MASK 0x00200000
+#define SD4_EMMC_TOP_CAPABILITIES1_ADMA2_SHIFT 19
+#define SD4_EMMC_TOP_CAPABILITIES1_ADMA2_MASK 0x00080000
+#define SD4_EMMC_TOP_CAPABILITIES1_EXTBUSMED_SHIFT 18
+#define SD4_EMMC_TOP_CAPABILITIES1_EXTBUSMED_MASK 0x00040000
+#define SD4_EMMC_TOP_CAPABILITIES1_MAXBLK_SHIFT 16
+#define SD4_EMMC_TOP_CAPABILITIES1_MAXBLK_MASK 0x00030000
+#define SD4_EMMC_TOP_CAPABILITIES1_BCLK_SHIFT 8
+#define SD4_EMMC_TOP_CAPABILITIES1_BCLK_MASK 0x0000FF00
+#define SD4_EMMC_TOP_CAPABILITIES1_TOUT_SHIFT 7
+#define SD4_EMMC_TOP_CAPABILITIES1_TOUT_MASK 0x00000080
+#define SD4_EMMC_TOP_CAPABILITIES1_TOUTFREQ_SHIFT 0
+#define SD4_EMMC_TOP_CAPABILITIES1_TOUTFREQ_MASK 0x0000003F
+
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_OFFSET 0x00000040
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_DEFAULT 0x10E934B4
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_TYPE uint32_t
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_RESERVED_MASK 0x08100040
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_SLOTTYPE_SHIFT 30
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_SLOTTYPE_MASK 0xC0000000
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_ASYNCHIRQ_SHIFT 29
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_ASYNCHIRQ_MASK 0x20000000
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_SYSBUS64_SHIFT 28
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_SYSBUS64_MASK 0x10000000
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_V18_SHIFT 26
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_V18_MASK 0x04000000
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_V3_SHIFT 25
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_V3_MASK 0x02000000
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_V33_SHIFT 24
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_V33_MASK 0x01000000
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_SUPRSM_SHIFT 23
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_SUPRSM_MASK 0x00800000
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_SDMA_SHIFT 22
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_SDMA_MASK 0x00400000
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_HSPEED_SHIFT 21
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_HSPEED_MASK 0x00200000
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_ADMA2_SHIFT 19
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_ADMA2_MASK 0x00080000
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_EXTBUSMED_SHIFT 18
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_EXTBUSMED_MASK 0x00040000
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_MAXBLK_SHIFT 16
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_MAXBLK_MASK 0x00030000
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_BCLK_SHIFT 8
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_BCLK_MASK 0x0000FF00
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_TOUT_SHIFT 7
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_TOUT_MASK 0x00000080
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_TOUTFREQ_SHIFT 0
+#define SD4_EMMC_TOP_CAPABILITIES1_SD4_TOUTFREQ_MASK 0x0000003F
+
+#define SD4_EMMC_TOP_CAPABILITIES2_OFFSET 0x00000044
+#define SD4_EMMC_TOP_CAPABILITIES2_DEFAULT 0x03002177
+#define SD4_EMMC_TOP_CAPABILITIES2_TYPE uint32_t
+#define SD4_EMMC_TOP_CAPABILITIES2_RESERVED_MASK 0xFC001088
+#define SD4_EMMC_TOP_CAPABILITIES2_SPIBLOCKMODE_SHIFT 25
+#define SD4_EMMC_TOP_CAPABILITIES2_SPIBLOCKMODE_MASK 0x02000000
+#define SD4_EMMC_TOP_CAPABILITIES2_SPIMODE_CAP_SHIFT 24
+#define SD4_EMMC_TOP_CAPABILITIES2_SPIMODE_CAP_MASK 0x01000000
+#define SD4_EMMC_TOP_CAPABILITIES2_CLOCKMULT_SHIFT 16
+#define SD4_EMMC_TOP_CAPABILITIES2_CLOCKMULT_MASK 0x00FF0000
+#define SD4_EMMC_TOP_CAPABILITIES2_RETUNE_MODE_SHIFT 14
+#define SD4_EMMC_TOP_CAPABILITIES2_RETUNE_MODE_MASK 0x0000C000
+#define SD4_EMMC_TOP_CAPABILITIES2_USETUNE_SDR50_SHIFT 13
+#define SD4_EMMC_TOP_CAPABILITIES2_USETUNE_SDR50_MASK 0x00002000
+#define SD4_EMMC_TOP_CAPABILITIES2_TMRCNT_RETUNE_SHIFT 8
+#define SD4_EMMC_TOP_CAPABILITIES2_TMRCNT_RETUNE_MASK 0x00000F00
+#define SD4_EMMC_TOP_CAPABILITIES2_DRVR_TYPED_SHIFT 6
+#define SD4_EMMC_TOP_CAPABILITIES2_DRVR_TYPED_MASK 0x00000040
+#define SD4_EMMC_TOP_CAPABILITIES2_DRVR_TYPEC_SHIFT 5
+#define SD4_EMMC_TOP_CAPABILITIES2_DRVR_TYPEC_MASK 0x00000020
+#define SD4_EMMC_TOP_CAPABILITIES2_DRVR_TYPEA_SHIFT 4
+#define SD4_EMMC_TOP_CAPABILITIES2_DRVR_TYPEA_MASK 0x00000010
+#define SD4_EMMC_TOP_CAPABILITIES2_DDR50_SHIFT 2
+#define SD4_EMMC_TOP_CAPABILITIES2_DDR50_MASK 0x00000004
+#define SD4_EMMC_TOP_CAPABILITIES2_SDR104_SHIFT 1
+#define SD4_EMMC_TOP_CAPABILITIES2_SDR104_MASK 0x00000002
+#define SD4_EMMC_TOP_CAPABILITIES2_SDR50_SHIFT 0
+#define SD4_EMMC_TOP_CAPABILITIES2_SDR50_MASK 0x00000001
+
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_OFFSET 0x00000044
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_DEFAULT 0x10000064
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_TYPE uint32_t
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_RESERVED_MASK 0xE7001080
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_VDD2_18_SHIFT 28
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_VDD2_18_MASK 0x10000000
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_ADMA3_SHIFT 27
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_ADMA3_MASK 0x08000000
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_CLOCKMULT_SHIFT 16
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_CLOCKMULT_MASK 0x00FF0000
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_RETUNE_MODE_SHIFT 14
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_RETUNE_MODE_MASK 0x0000C000
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_USETUNE_SDR50_SHIFT 13
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_USETUNE_SDR50_MASK 0x00002000
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_TMRCNT_RETUNE_SHIFT 8
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_TMRCNT_RETUNE_MASK 0x00000F00
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_DRVR_TYPED_SHIFT 6
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_DRVR_TYPED_MASK 0x00000040
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_DRVR_TYPEC_SHIFT 5
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_DRVR_TYPEC_MASK 0x00000020
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_DRVR_TYPEA_SHIFT 4
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_DRVR_TYPEA_MASK 0x00000010
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_UHS_II_SHIFT 3
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_UHS_II_MASK 0x00000008
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_DDR50_SHIFT 2
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_DDR50_MASK 0x00000004
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_SDR104_SHIFT 1
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_SDR104_MASK 0x00000002
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_SDR50_SHIFT 0
+#define SD4_EMMC_TOP_CAPABILITIES2_SD4_SDR50_MASK 0x00000001
+
+#define SD4_EMMC_TOP_MAX_A1_OFFSET 0x00000048
+#define SD4_EMMC_TOP_MAX_A1_DEFAULT 0x00000001
+#define SD4_EMMC_TOP_MAX_A1_TYPE uint32_t
+#define SD4_EMMC_TOP_MAX_A1_RESERVED_MASK 0xFF000000
+#define SD4_EMMC_TOP_MAX_A1_MAXA18_SHIFT 16
+#define SD4_EMMC_TOP_MAX_A1_MAXA18_MASK 0x00FF0000
+#define SD4_EMMC_TOP_MAX_A1_MAXA30_SHIFT 8
+#define SD4_EMMC_TOP_MAX_A1_MAXA30_MASK 0x0000FF00
+#define SD4_EMMC_TOP_MAX_A1_MAXA33_SHIFT 0
+#define SD4_EMMC_TOP_MAX_A1_MAXA33_MASK 0x000000FF
+
+#define SD4_EMMC_TOP_MAX_A2_OFFSET 0x0000004C
+#define SD4_EMMC_TOP_MAX_A2_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_MAX_A2_TYPE uint32_t
+#define SD4_EMMC_TOP_MAX_A2_RESERVED_MASK 0xFFFFFFFF
+
+#define SD4_EMMC_TOP_MAX_A2_SD4_OFFSET 0x0000004C
+#define SD4_EMMC_TOP_MAX_A2_SD4_DEFAULT 0x00000001
+#define SD4_EMMC_TOP_MAX_A2_SD4_TYPE uint32_t
+#define SD4_EMMC_TOP_MAX_A2_SD4_RESERVED_MASK 0xFFFFFF00
+#define SD4_EMMC_TOP_MAX_A2_SD4_MAXAVDD2_SHIFT 0
+#define SD4_EMMC_TOP_MAX_A2_SD4_MAXAVDD2_MASK 0x000000FF
+
+#define SD4_EMMC_TOP_CMDENTSTAT_OFFSET 0x00000050
+#define SD4_EMMC_TOP_CMDENTSTAT_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_CMDENTSTAT_TYPE uint32_t
+#define SD4_EMMC_TOP_CMDENTSTAT_RESERVED_MASK 0x2C00FF60
+#define SD4_EMMC_TOP_CMDENTSTAT_VSES_SHIFT 30
+#define SD4_EMMC_TOP_CMDENTSTAT_VSES_MASK 0xC0000000
+#define SD4_EMMC_TOP_CMDENTSTAT_TRERR_SHIFT 28
+#define SD4_EMMC_TOP_CMDENTSTAT_TRERR_MASK 0x10000000
+#define SD4_EMMC_TOP_CMDENTSTAT_ADMAERR_SHIFT 25
+#define SD4_EMMC_TOP_CMDENTSTAT_ADMAERR_MASK 0x02000000
+#define SD4_EMMC_TOP_CMDENTSTAT_ACMDERR_SHIFT 24
+#define SD4_EMMC_TOP_CMDENTSTAT_ACMDERR_MASK 0x01000000
+#define SD4_EMMC_TOP_CMDENTSTAT_ILERR_SHIFT 23
+#define SD4_EMMC_TOP_CMDENTSTAT_ILERR_MASK 0x00800000
+#define SD4_EMMC_TOP_CMDENTSTAT_DENDERR_SHIFT 22
+#define SD4_EMMC_TOP_CMDENTSTAT_DENDERR_MASK 0x00400000
+#define SD4_EMMC_TOP_CMDENTSTAT_DCRCERR_SHIFT 21
+#define SD4_EMMC_TOP_CMDENTSTAT_DCRCERR_MASK 0x00200000
+#define SD4_EMMC_TOP_CMDENTSTAT_DTOUTERR_SHIFT 20
+#define SD4_EMMC_TOP_CMDENTSTAT_DTOUTERR_MASK 0x00100000
+#define SD4_EMMC_TOP_CMDENTSTAT_CIDXERR_SHIFT 19
+#define SD4_EMMC_TOP_CMDENTSTAT_CIDXERR_MASK 0x00080000
+#define SD4_EMMC_TOP_CMDENTSTAT_CENDERR_SHIFT 18
+#define SD4_EMMC_TOP_CMDENTSTAT_CENDERR_MASK 0x00040000
+#define SD4_EMMC_TOP_CMDENTSTAT_CCRCERR_SHIFT 17
+#define SD4_EMMC_TOP_CMDENTSTAT_CCRCERR_MASK 0x00020000
+#define SD4_EMMC_TOP_CMDENTSTAT_CTOUTERR_SHIFT 16
+#define SD4_EMMC_TOP_CMDENTSTAT_CTOUTERR_MASK 0x00010000
+#define SD4_EMMC_TOP_CMDENTSTAT_NOFRCENT_SHIFT 7
+#define SD4_EMMC_TOP_CMDENTSTAT_NOFRCENT_MASK 0x00000080
+#define SD4_EMMC_TOP_CMDENTSTAT_IDXERR_SHIFT 4
+#define SD4_EMMC_TOP_CMDENTSTAT_IDXERR_MASK 0x00000010
+#define SD4_EMMC_TOP_CMDENTSTAT_EBITERR_SHIFT 3
+#define SD4_EMMC_TOP_CMDENTSTAT_EBITERR_MASK 0x00000008
+#define SD4_EMMC_TOP_CMDENTSTAT_CRCERR_SHIFT 2
+#define SD4_EMMC_TOP_CMDENTSTAT_CRCERR_MASK 0x00000004
+#define SD4_EMMC_TOP_CMDENTSTAT_TOUTERR_SHIFT 1
+#define SD4_EMMC_TOP_CMDENTSTAT_TOUTERR_MASK 0x00000002
+#define SD4_EMMC_TOP_CMDENTSTAT_AUTONOEX_SHIFT 0
+#define SD4_EMMC_TOP_CMDENTSTAT_AUTONOEX_MASK 0x00000001
+
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_OFFSET 0x00000050
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_TYPE uint32_t
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_RESERVED_MASK 0x0000FF40
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_VSES_SHIFT 28
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_VSES_MASK 0xF0000000
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_TRESPERR_SHIFT 27
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_TRESPERR_MASK 0x08000000
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_TUNERR_SHIFT 26
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_TUNERR_MASK 0x04000000
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_ADMAERR_SHIFT 25
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_ADMAERR_MASK 0x02000000
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_ACMDERR_SHIFT 24
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_ACMDERR_MASK 0x01000000
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_ILERR_SHIFT 23
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_ILERR_MASK 0x00800000
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_DENDERR_SHIFT 22
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_DENDERR_MASK 0x00400000
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_DCRCERR_SHIFT 21
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_DCRCERR_MASK 0x00200000
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_DTOUTERR_SHIFT 20
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_DTOUTERR_MASK 0x00100000
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_CIDXERR_SHIFT 19
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_CIDXERR_MASK 0x00080000
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_CENDERR_SHIFT 18
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_CENDERR_MASK 0x00040000
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_CCRCERR_SHIFT 17
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_CCRCERR_MASK 0x00020000
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_CTOUTERR_SHIFT 16
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_CTOUTERR_MASK 0x00010000
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_NOFRCENT_SHIFT 7
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_NOFRCENT_MASK 0x00000080
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_RESPERR_SHIFT 5
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_RESPERR_MASK 0x00000020
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_IDXERR_SHIFT 4
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_IDXERR_MASK 0x00000010
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_EBITERR_SHIFT 3
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_EBITERR_MASK 0x00000008
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_CRCERR_SHIFT 2
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_CRCERR_MASK 0x00000004
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_TOUTERR_SHIFT 1
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_TOUTERR_MASK 0x00000002
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_AUTONOEX_SHIFT 0
+#define SD4_EMMC_TOP_CMDENTSTAT_SD4_AUTONOEX_MASK 0x00000001
+
+#define SD4_EMMC_TOP_ADMAERR_OFFSET 0x00000054
+#define SD4_EMMC_TOP_ADMAERR_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_ADMAERR_TYPE uint32_t
+#define SD4_EMMC_TOP_ADMAERR_RESERVED_MASK 0xFFFFFFF8
+#define SD4_EMMC_TOP_ADMAERR_ADMALERR_SHIFT 2
+#define SD4_EMMC_TOP_ADMAERR_ADMALERR_MASK 0x00000004
+#define SD4_EMMC_TOP_ADMAERR_ADMAERR_SHIFT 0
+#define SD4_EMMC_TOP_ADMAERR_ADMAERR_MASK 0x00000003
+
+#define SD4_EMMC_TOP_ADMAADDR0_OFFSET 0x00000058
+#define SD4_EMMC_TOP_ADMAADDR0_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_ADMAADDR0_TYPE uint32_t
+#define SD4_EMMC_TOP_ADMAADDR0_RESERVED_MASK 0x00000000
+#define SD4_EMMC_TOP_ADMAADDR0_ADMAADDR0_SHIFT 0
+#define SD4_EMMC_TOP_ADMAADDR0_ADMAADDR0_MASK 0xFFFFFFFF
+
+#define SD4_EMMC_TOP_ADMAADDR1_OFFSET 0x0000005C
+#define SD4_EMMC_TOP_ADMAADDR1_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_ADMAADDR1_TYPE uint32_t
+#define SD4_EMMC_TOP_ADMAADDR1_RESERVED_MASK 0x00000000
+#define SD4_EMMC_TOP_ADMAADDR1_ADMAADDR1_SHIFT 0
+#define SD4_EMMC_TOP_ADMAADDR1_ADMAADDR1_MASK 0xFFFFFFFF
+
+#define SD4_EMMC_TOP_PRESETVAL1_OFFSET 0x00000060
+#define SD4_EMMC_TOP_PRESETVAL1_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_PRESETVAL1_TYPE uint32_t
+#define SD4_EMMC_TOP_PRESETVAL1_RESERVED_MASK 0x38003800
+#define SD4_EMMC_TOP_PRESETVAL1_DRVS_SEL_DFS_SHIFT 30
+#define SD4_EMMC_TOP_PRESETVAL1_DRVS_SEL_DFS_MASK 0xC0000000
+#define SD4_EMMC_TOP_PRESETVAL1_CLKGENSEL_DFS_SHIFT 26
+#define SD4_EMMC_TOP_PRESETVAL1_CLKGENSEL_DFS_MASK 0x04000000
+#define SD4_EMMC_TOP_PRESETVAL1_FREQ_SEL_DFS_SHIFT 16
+#define SD4_EMMC_TOP_PRESETVAL1_FREQ_SEL_DFS_MASK 0x03FF0000
+#define SD4_EMMC_TOP_PRESETVAL1_DRVS_SEL_INIT_SHIFT 14
+#define SD4_EMMC_TOP_PRESETVAL1_DRVS_SEL_INIT_MASK 0x0000C000
+#define SD4_EMMC_TOP_PRESETVAL1_CLKGENSEL_INIT_SHIFT 10
+#define SD4_EMMC_TOP_PRESETVAL1_CLKGENSEL_INIT_MASK 0x00000400
+#define SD4_EMMC_TOP_PRESETVAL1_FREQ_SEL_INIT_SHIFT 0
+#define SD4_EMMC_TOP_PRESETVAL1_FREQ_SEL_INIT_MASK 0x000003FF
+
+#define SD4_EMMC_TOP_PRESETVAL2_OFFSET 0x00000064
+#define SD4_EMMC_TOP_PRESETVAL2_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_PRESETVAL2_TYPE uint32_t
+#define SD4_EMMC_TOP_PRESETVAL2_RESERVED_MASK 0x38003800
+#define SD4_EMMC_TOP_PRESETVAL2_DRVS_SEL_SDR12_SHIFT 30
+#define SD4_EMMC_TOP_PRESETVAL2_DRVS_SEL_SDR12_MASK 0xC0000000
+#define SD4_EMMC_TOP_PRESETVAL2_CLKGENSEL_SDR12_SHIFT 26
+#define SD4_EMMC_TOP_PRESETVAL2_CLKGENSEL_SDR12_MASK 0x04000000
+#define SD4_EMMC_TOP_PRESETVAL2_FREQ_SEL_SDR12_SHIFT 16
+#define SD4_EMMC_TOP_PRESETVAL2_FREQ_SEL_SDR12_MASK 0x03FF0000
+#define SD4_EMMC_TOP_PRESETVAL2_DRVS_SEL_HS_SHIFT 14
+#define SD4_EMMC_TOP_PRESETVAL2_DRVS_SEL_HS_MASK 0x0000C000
+#define SD4_EMMC_TOP_PRESETVAL2_CLKGENSEL_HS_SHIFT 10
+#define SD4_EMMC_TOP_PRESETVAL2_CLKGENSEL_HS_MASK 0x00000400
+#define SD4_EMMC_TOP_PRESETVAL2_FREQ_SEL_HS_SHIFT 0
+#define SD4_EMMC_TOP_PRESETVAL2_FREQ_SEL_HS_MASK 0x000003FF
+
+#define SD4_EMMC_TOP_PRESETVAL3_OFFSET 0x00000068
+#define SD4_EMMC_TOP_PRESETVAL3_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_PRESETVAL3_TYPE uint32_t
+#define SD4_EMMC_TOP_PRESETVAL3_RESERVED_MASK 0x38003800
+#define SD4_EMMC_TOP_PRESETVAL3_DRVS_SEL_SDR50_SHIFT 30
+#define SD4_EMMC_TOP_PRESETVAL3_DRVS_SEL_SDR50_MASK 0xC0000000
+#define SD4_EMMC_TOP_PRESETVAL3_CLKGENSEL_SDR50_SHIFT 26
+#define SD4_EMMC_TOP_PRESETVAL3_CLKGENSEL_SDR50_MASK 0x04000000
+#define SD4_EMMC_TOP_PRESETVAL3_FREQ_SEL_SDR50_SHIFT 16
+#define SD4_EMMC_TOP_PRESETVAL3_FREQ_SEL_SDR50_MASK 0x03FF0000
+#define SD4_EMMC_TOP_PRESETVAL3_DRVS_SEL_SDR25_SHIFT 14
+#define SD4_EMMC_TOP_PRESETVAL3_DRVS_SEL_SDR25_MASK 0x0000C000
+#define SD4_EMMC_TOP_PRESETVAL3_CLKGENSEL_SDR25_SHIFT 10
+#define SD4_EMMC_TOP_PRESETVAL3_CLKGENSEL_SDR25_MASK 0x00000400
+#define SD4_EMMC_TOP_PRESETVAL3_FREQ_SEL_SDR25_SHIFT 0
+#define SD4_EMMC_TOP_PRESETVAL3_FREQ_SEL_SDR25_MASK 0x000003FF
+
+#define SD4_EMMC_TOP_PRESETVAL4_OFFSET 0x0000006C
+#define SD4_EMMC_TOP_PRESETVAL4_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_PRESETVAL4_TYPE uint32_t
+#define SD4_EMMC_TOP_PRESETVAL4_RESERVED_MASK 0x38003800
+#define SD4_EMMC_TOP_PRESETVAL4_DRVS_SEL_DDR50_SHIFT 30
+#define SD4_EMMC_TOP_PRESETVAL4_DRVS_SEL_DDR50_MASK 0xC0000000
+#define SD4_EMMC_TOP_PRESETVAL4_CLKGENSEL_DDR50_SHIFT 26
+#define SD4_EMMC_TOP_PRESETVAL4_CLKGENSEL_DDR50_MASK 0x04000000
+#define SD4_EMMC_TOP_PRESETVAL4_FREQ_SEL_DDR50_SHIFT 16
+#define SD4_EMMC_TOP_PRESETVAL4_FREQ_SEL_DDR50_MASK 0x03FF0000
+#define SD4_EMMC_TOP_PRESETVAL4_DRVS_SEL_SDR104_SHIFT 14
+#define SD4_EMMC_TOP_PRESETVAL4_DRVS_SEL_SDR104_MASK 0x0000C000
+#define SD4_EMMC_TOP_PRESETVAL4_CLKGENSEL_SDR104_SHIFT 10
+#define SD4_EMMC_TOP_PRESETVAL4_CLKGENSEL_SDR104_MASK 0x00000400
+#define SD4_EMMC_TOP_PRESETVAL4_FREQ_SEL_SDR104_SHIFT 0
+#define SD4_EMMC_TOP_PRESETVAL4_FREQ_SEL_SDR104_MASK 0x000003FF
+
+#define SD4_EMMC_TOP_BOOTTIMEOUT_OFFSET 0x00000070
+#define SD4_EMMC_TOP_BOOTTIMEOUT_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_BOOTTIMEOUT_TYPE uint32_t
+#define SD4_EMMC_TOP_BOOTTIMEOUT_RESERVED_MASK 0x00000000
+#define SD4_EMMC_TOP_BOOTTIMEOUT_BOOTDATATIMEOUTCTRVALUE_SHIFT 0
+#define SD4_EMMC_TOP_BOOTTIMEOUT_BOOTDATATIMEOUTCTRVALUE_MASK 0xFFFFFFFF
+
+#define SD4_EMMC_TOP_DBGSEL_OFFSET 0x00000074
+#define SD4_EMMC_TOP_DBGSEL_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_DBGSEL_TYPE uint32_t
+#define SD4_EMMC_TOP_DBGSEL_RESERVED_MASK 0xFFFFFFFE
+#define SD4_EMMC_TOP_DBGSEL_DBGSEL_SHIFT 0
+#define SD4_EMMC_TOP_DBGSEL_DBGSEL_MASK 0x00000001
+
+#define SD4_EMMC_TOP_UHS2_PRESETVAL_OFFSET 0x00000074
+#define SD4_EMMC_TOP_UHS2_PRESETVAL_DEFAULT 0x00000000
+#define SD4_EMMC_TOP_UHS2_PRESETVAL_TYPE uint32_t
+#define SD4_EMMC_TOP_UHS2_PRESETVAL_RESERVED_MASK 0xFFFF3800
+#define SD4_EMMC_TOP_UHS2_PRESETVAL_DRVSTRVAL_SHIFT 14
+#define SD4_EMMC_TOP_UHS2_PRESETVAL_DRVSTRVAL_MASK 0x0000C000
+#define SD4_EMMC_TOP_UHS2_PRESETVAL_CLKGENSELVAL_SHIFT 10
+#define SD4_EMMC_TOP_UHS2_PRESETVAL_CLKGENSELVAL_MASK 0x00000400
+#define SD4_EMMC_TOP_UHS2_PRESETVAL_SDCLKFREQSELVAL_SHIFT 0
+#define SD4_EMMC_TOP_UHS2_PRESETVAL_SDCLKFREQSELVAL_MASK 0x000003FF
+
+#define SD4_EMMC_TOP_HCVERSIRQ_OFFSET 0x000000FC
+#define SD4_EMMC_TOP_HCVERSIRQ_DEFAULT 0x10020000
+#define SD4_EMMC_TOP_HCVERSIRQ_TYPE uint32_t
+#define SD4_EMMC_TOP_HCVERSIRQ_RESERVED_MASK 0x0000FF00
+#define SD4_EMMC_TOP_HCVERSIRQ_VENDVER_SHIFT 24
+#define SD4_EMMC_TOP_HCVERSIRQ_VENDVER_MASK 0xFF000000
+#define SD4_EMMC_TOP_HCVERSIRQ_SPECVER_SHIFT 16
+#define SD4_EMMC_TOP_HCVERSIRQ_SPECVER_MASK 0x00FF0000
+#define SD4_EMMC_TOP_HCVERSIRQ_SIRQ_SHIFT 0
+#define SD4_EMMC_TOP_HCVERSIRQ_SIRQ_MASK 0x000000FF
+
+#define SD4_EMMC_TOP_HCVERSIRQ_SD4_OFFSET 0x000000FC
+#define SD4_EMMC_TOP_HCVERSIRQ_SD4_DEFAULT 0x01030000
+#define SD4_EMMC_TOP_HCVERSIRQ_SD4_TYPE uint32_t
+#define SD4_EMMC_TOP_HCVERSIRQ_SD4_RESERVED_MASK 0x0000FF00
+#define SD4_EMMC_TOP_HCVERSIRQ_SD4_VENDVER_SHIFT 24
+#define SD4_EMMC_TOP_HCVERSIRQ_SD4_VENDVER_MASK 0xFF000000
+#define SD4_EMMC_TOP_HCVERSIRQ_SD4_SPECVER_SHIFT 16
+#define SD4_EMMC_TOP_HCVERSIRQ_SD4_SPECVER_MASK 0x00FF0000
+#define SD4_EMMC_TOP_HCVERSIRQ_SD4_SIRQ_SHIFT 0
+#define SD4_EMMC_TOP_HCVERSIRQ_SD4_SIRQ_MASK 0x000000FF
+
+#endif /* BRCM_RDB_SD4_EMMC_TOP_H */
diff --git a/include/drivers/brcm/emmc/emmc_chal_sd.h b/include/drivers/brcm/emmc/emmc_chal_sd.h
new file mode 100644
index 0000000..8d223f9
--- /dev/null
+++ b/include/drivers/brcm/emmc/emmc_chal_sd.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CHAL_SD_H
+#define CHAL_SD_H
+
+#include <stddef.h>
+
+#define BASE_CLK_FREQ (200 * 1000 * 1000)
+#define INIT_CLK_FREQ (400 * 1000)
+
+#define SD_ERROR_RECOVERABLE 0
+#define SD_ERROR_NON_RECOVERABLE 1
+
+#define SD_OK 0
+#define SD_FAIL (-1)
+#define SD_INVALID_HANDLE (-2)
+#define SD_CEATA_INIT_ERROR (-3)
+#define SD_RESET_ERROR (-4)
+#define SD_CARD_INIT_ERROR (-5)
+#define SD_INV_DATA_WIDTH (-6)
+#define SD_SET_BUS_WIDTH_ERROR (-7)
+#define SD_DMA_NOT_SUPPORT (-8)
+#define SD_SDIO_READ_ERROR (-9)
+#define SD_SDIO_WRITE_ERROR (-10)
+#define SD_WRITE_ERROR (-11)
+#define SD_READ_ERROR (-12)
+#define SD_READ_SIZE_ERROR (-13)
+#define SD_RW_ADDRESS_ERROR (-14)
+#define SD_XFER_ADDRESS_ERROR (-15)
+#define SD_DATA_XFER_ADDR_ERROR (-16)
+#define SD_DATA_XFER_ERROR (-17)
+#define SD_WRITE_SIZE_ERROR (-18)
+#define SD_CMD_STATUS_UPDATE_ERR (-19)
+#define SD_CMD12_ERROR (-20)
+#define SD_CMD_DATA_ERROR (-21)
+#define SD_CMD_TIMEOUT (-22)
+#define SD_CMD_NO_RESPONSE (-22)
+#define SD_CMD_ABORT_ERROR (-23)
+#define SD_CMD_INVALID (-24)
+#define SD_CMD_RESUME_ERROR (-25)
+#define SD_CMD_ERR_INVALID_RESPONSE (-26)
+#define SD_WAIT_TIMEOUT (-27)
+#define SD_READ_TIMEOUT (-28)
+#define SD_CEATA_REST_ERROR (-29)
+#define SD_INIT_CAED_FAILED (-30)
+#define SD_ERROR_CLOCK_OFFLIMIT (-31)
+#define SD_INV_SLOT (-32)
+
+#define SD_NOR_INTERRUPTS 0x000000FF
+#define SD_ERR_INTERRUPTS 0x03FF0000
+#define SD_CMD_ERROR_INT 0x010F0000
+#define SD_DAT_ERROR_INT 0x02F00000
+#define SD_DAT_TIMEOUT 0x00100000
+
+/* Operation modes */
+#define SD_PIO_MODE 0
+#define SD_INT_MODE 1
+
+/* Support both ADMA and SDMA (for version 2.0 and above) */
+#define SD_DMA_OFF 0
+#define SD_DMA_SDMA 1
+#define SD_DMA_ADMA 2
+
+#define SD_NORMAL_SPEED 0
+#define SD_HIGH_SPEED 1
+
+#define SD_XFER_CARD_TO_HOST 3
+#define SD_XFER_HOST_TO_CARD 4
+
+#define SD_CARD_DETECT_AUTO 0
+#define SD_CARD_DETECT_SD 1
+#define SD_CARD_DETECT_SDIO 2
+#define SD_CARD_DETECT_MMC 3
+#define SD_CARD_DETECT_CEATA 4
+
+#define SD_ABORT_SYNC_MODE 0
+#define SD_ABORT_ASYNC_MODE 1
+
+#define SD_CMD_ERROR_FLAGS (0x18F << 16)
+#define SD_DATA_ERROR_FLAGS (0x70 << 16)
+#define SD_AUTO_CMD12_ERROR_FLAGS (0x9F)
+
+#define SD_CARD_STATUS_ERROR 0x10000000
+#define SD_CMD_MISSING 0x80000000
+#define SD_ERROR_INT 0x8000
+
+#define SD_TRAN_HIGH_SPEED 0x32
+#define SD_CARD_HIGH_CAPACITY 0x40000000
+#define SD_CARD_POWER_UP_STATUS 0x80000000
+
+#define SD_HOST_CORE_TIMEOUT 0x0E
+
+/* SD CARD and Host Controllers bus width */
+#define SD_BUS_DATA_WIDTH_1BIT 0x00
+#define SD_BUS_DATA_WIDTH_4BIT 0x02
+#define SD_BUS_DATA_WIDTH_8BIT 0x20
+
+/* dma boundary settings */
+#define SD_DMA_BOUNDARY_4K 0
+#define SD_DMA_BOUNDARY_8K (1 << 12)
+#define SD_DMA_BOUNDARY_16K (2 << 12)
+#define SD_DMA_BOUNDARY_32K (3 << 12)
+#define SD_DMA_BOUNDARY_64K (4 << 12)
+#define SD_DMA_BOUNDARY_128K (5 << 12)
+#define SD_DMA_BOUNDARY_256K (6 << 12)
+#define SD_DMA_BOUNDARY_512K (7 << 12)
+
+#define SD_CMDR_CMD_NORMAL 0x00000000
+#define SD_CMDR_CMD_SUSPEND 0x00400000
+#define SD_CMDR_CMD_RESUME 0x00800000
+#define SD_CMDR_CMD_ABORT 0x00c00000
+
+#define SD_CMDR_RSP_TYPE_NONE 0x0
+#define SD_CMDR_RSP_TYPE_R2 0x1
+#define SD_CMDR_RSP_TYPE_R3_4 0x2
+#define SD_CMDR_RSP_TYPE_R1_5_6 0x2
+#define SD_CMDR_RSP_TYPE_R1b_5b 0x3
+#define SD_CMDR_RSP_TYPE_S 16
+
+struct sd_ctrl_info {
+ uint32_t blkReg; /* current block register cache value */
+ uint32_t cmdReg; /* current command register cache value */
+ uint32_t argReg; /* current argument register cache value */
+ uint32_t cmdIndex; /* current command index */
+ uint32_t cmdStatus; /* current command status, cmd/data compelete */
+ uint16_t rca; /* relative card address */
+ uint32_t ocr; /* operation codition */
+ uint32_t eventList; /* events list */
+ uint32_t blkGapEnable;
+
+ uint32_t capability; /* controller's capbilities */
+ uint32_t maxCurrent; /* maximum current supported */
+ uint32_t present; /* if card is inserted or removed */
+ uint32_t version; /* SD spec version 1.0 or 2.0 */
+ uint32_t vendor; /* vendor number */
+
+ uintptr_t sdRegBaseAddr; /* sdio control registers */
+ uintptr_t hostRegBaseAddr; /* SD Host control registers */
+};
+
+struct sd_cfg {
+ uint32_t mode; /* interrupt or polling */
+ uint32_t dma; /* dma enabled or disabled */
+ uint32_t retryLimit; /* command retry limit */
+ uint32_t speedMode; /* speed mode, 0 standard, 1 high speed */
+ uint32_t voltage; /* voltage level */
+ uint32_t blockSize; /* access block size (512 for HC card) */
+ uint32_t dmaBoundary; /* dma address boundary */
+ uint32_t detSignal; /* card det signal src, for test purpose only */
+ uint32_t rdWaiting;
+ uint32_t wakeupOut;
+ uint32_t wakeupIn;
+ uint32_t wakeupInt;
+ uint32_t wfe_retry;
+ uint32_t gapInt;
+ uint32_t readWait;
+ uint32_t led;
+};
+
+struct sd_dev {
+ struct sd_cfg cfg; /* SD configuration */
+ struct sd_ctrl_info ctrl; /* SD info */
+};
+
+int32_t chal_sd_start(CHAL_HANDLE *sdHandle, uint32_t mode,
+ uint32_t sdBase, uint32_t hostBase);
+int32_t chal_sd_config(CHAL_HANDLE *sdHandle, uint32_t speed,
+ uint32_t retry, uint32_t boundary,
+ uint32_t blkSize, uint32_t dma);
+int32_t chal_sd_stop(void);
+int32_t chal_sd_set_dma(CHAL_HANDLE *sdHandle, uint32_t mode);
+uintptr_t chal_sd_get_dma_addr(CHAL_HANDLE *handle);
+int32_t chal_sd_config_bus_width(CHAL_HANDLE *sdHandle, int32_t width);
+int32_t chal_sd_send_cmd(CHAL_HANDLE *sdHandle, uint32_t cmdIndex,
+ uint32_t arg, uint32_t options);
+int32_t chal_sd_set_dma_addr(CHAL_HANDLE *sdHandle, uintptr_t address);
+int32_t chal_sd_set_clock(CHAL_HANDLE *sdHandle,
+ uint32_t div_ctrl_setting, uint32_t on);
+uint32_t chal_sd_freq_2_div_ctrl_setting(uint32_t desired_freq);
+int32_t chal_sd_setup_xfer(CHAL_HANDLE *sdHandle, uint8_t *data,
+ uint32_t length, int32_t dir);
+int32_t chal_sd_write_buffer(CHAL_HANDLE *sdHandle, uint32_t length,
+ uint8_t *data);
+int32_t chal_sd_read_buffer(CHAL_HANDLE *sdHandle, uint32_t length,
+ uint8_t *data);
+int32_t chal_sd_reset_line(CHAL_HANDLE *sdHandle, uint32_t line);
+int32_t chal_sd_get_response(CHAL_HANDLE *sdHandle, uint32_t *resp);
+int32_t chal_sd_clear_pending_irq(CHAL_HANDLE *sdHandle);
+int32_t chal_sd_get_irq_status(CHAL_HANDLE *sdHandle);
+int32_t chal_sd_clear_irq(CHAL_HANDLE *sdHandle, uint32_t mask);
+uint32_t chal_sd_get_present_status(CHAL_HANDLE *sdHandle);
+int32_t chal_sd_get_atuo12_error(CHAL_HANDLE *sdHandle);
+void chal_sd_set_speed(CHAL_HANDLE *sdHandle, uint32_t speed);
+int32_t chal_sd_check_cap(CHAL_HANDLE *sdHandle, uint32_t cap);
+void chal_sd_set_irq_signal(CHAL_HANDLE *sdHandle, uint32_t mask,
+ uint32_t state);
+void chal_sd_dump_fifo(CHAL_HANDLE *sdHandle);
+#endif /* CHAL_SD_H */
diff --git a/include/drivers/brcm/emmc/emmc_chal_types.h b/include/drivers/brcm/emmc/emmc_chal_types.h
new file mode 100644
index 0000000..9563273
--- /dev/null
+++ b/include/drivers/brcm/emmc/emmc_chal_types.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#ifndef CHAL_TYPES_H
+#define CHAL_TYPES_H
+
+#include <stdint.h>
+
+//
+// Generic cHAL handler
+//
+#ifndef CHAL_HANDLE
+ typedef void *CHAL_HANDLE; ///< void pointer (32 bits wide)
+#endif
+
+#endif /* _CHAL_TYPES_H_ */
diff --git a/include/drivers/brcm/emmc/emmc_csl_sd.h b/include/drivers/brcm/emmc/emmc_csl_sd.h
new file mode 100644
index 0000000..52b8bc8
--- /dev/null
+++ b/include/drivers/brcm/emmc/emmc_csl_sd.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CSL_SD_H
+#define CSL_SD_H
+
+#define SD_CLOCK_BASE 104000000
+#define SD_CLOCK_52MHZ 52000000
+#define SD_CLOCK_26MHZ 26000000
+#define SD_CLOCK_17MHZ 17330000
+#define SD_CLOCK_13MHZ 13000000
+#define SD_CLOCK_10MHZ 10000000
+#define SD_CLOCK_9MHZ 9000000
+#define SD_CLOCK_7MHZ 7000000
+#define SD_CLOCK_5MHZ 5000000
+#define SD_CLOCK_1MHZ 1000000
+#define SD_CLOCK_400KHZ 400000
+
+#define SD_DRIVE_STRENGTH_MASK 0x38000000
+#if defined(_BCM213x1_) || defined(_BCM21551_) || defined(_ATHENA_)
+#define SD_DRIVE_STRENGTH 0x28000000
+#elif defined(_BCM2153_)
+#define SD_DRIVE_STRENGTH 0x38000000
+#else
+#define SD_DRIVE_STRENGTH 0x00000000
+#endif
+
+#define SD_NUM_HOST 2
+
+#define SD_CARD_UNLOCK 0
+#define SD_CARD_LOCK 0x4
+#define SD_CARD_CLEAR_PWD 0x2
+#define SD_CARD_SET_PWD 0x1
+#define SD_CARD_ERASE_PWD 0x8
+
+#define SD_CARD_LOCK_STATUS 0x02000000
+#define SD_CARD_UNLOCK_STATUS 0x01000000
+
+#define SD_CMD_ERROR_FLAGS (0x18F << 16)
+#define SD_DATA_ERROR_FLAGS (0x70 << 16)
+#define SD_AUTO_CMD12_ERROR_FLAGS (0x9F)
+#define SD_CARD_STATUS_ERROR 0x10000000
+#define SD_CMD_MISSING 0x80000000
+
+#define SD_TRAN_HIGH_SPEED 0x32
+#define SD_CARD_HIGH_CAPACITY 0x40000000
+#define SD_CARD_POWER_UP_STATUS 0x80000000
+
+struct sd_dev_info {
+ uint32_t mode; /* interrupt or polling */
+ uint32_t dma; /* dma enabled or disabled */
+ uint32_t voltage; /* voltage level */
+ uint32_t slot; /* if the HC is locatd at slot 0 or slot 1 */
+ uint32_t version; /* 1.0 or 2.0 */
+ uint32_t curSystemAddr; /* system address */
+ uint32_t dataWidth; /* data width for the controller */
+ uint32_t clock; /* clock rate */
+ uint32_t status; /* if device is active on transfer or not */
+};
+
+void data_xfer_setup(struct sd_handle *handle, uint8_t *data,
+ uint32_t length, int dir);
+int reset_card(struct sd_handle *handle);
+int reset_host_ctrl(struct sd_handle *handle);
+int init_card(struct sd_handle *handle, int detection);
+int init_mmc_card(struct sd_handle *handle);
+int write_buffer(struct sd_handle *handle, uint32_t len, uint8_t *buffer);
+int read_buffer(struct sd_handle *handle, uint32_t len, uint8_t *buffer);
+int select_blk_sz(struct sd_handle *handle, uint16_t size);
+int check_error(struct sd_handle *handle, uint32_t ints);
+
+int process_data_xfer(struct sd_handle *handle, uint8_t *buffer,
+ uint32_t addr, uint32_t length, int dir);
+int read_block(struct sd_handle *handle, uint8_t *dst, uint32_t addr,
+ uint32_t len);
+#ifdef INCLUDE_EMMC_DRIVER_ERASE_CODE
+int erase_card(struct sd_handle *handle, uint32_t addr, uint32_t blocks);
+#endif
+int write_block(struct sd_handle *handle, uint8_t *src, uint32_t addr,
+ uint32_t len);
+int process_cmd_response(struct sd_handle *handle, uint32_t cmdIndex,
+ uint32_t rsp0, uint32_t rsp1, uint32_t rsp2,
+ uint32_t rsp3, struct sd_resp *resp);
+int32_t set_config(struct sd_handle *handle, uint32_t speed,
+ uint32_t retry, uint32_t dma, uint32_t dmaBound,
+ uint32_t blkSize, uint32_t wfe_retry);
+
+uint32_t wait_for_event(struct sd_handle *handle, uint32_t mask,
+ uint32_t retry);
+int set_boot_config(struct sd_handle *handle, uint32_t config);
+
+int mmc_cmd1(struct sd_handle *handle);
+#endif /* CSL_SD_H */
diff --git a/include/drivers/brcm/emmc/emmc_csl_sdcmd.h b/include/drivers/brcm/emmc/emmc_csl_sdcmd.h
new file mode 100644
index 0000000..425603f
--- /dev/null
+++ b/include/drivers/brcm/emmc/emmc_csl_sdcmd.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CSL_SD_CMD_H
+#define CSL_SD_CMD_H
+
+#define SD_CMD_OK 0
+#define SD_CMD_ERROR -1
+
+#define SD_CMD_ERR_NO_IO_FUNC 5
+#define SD_CMD_ERR_INVALID_PARAMETER 6
+#define SD_CMD_ERR_R1_ILLEGAL_COMMAND 7
+#define SD_CMD_ERR_R1_COM_CRC_ERROR 8
+#define SD_CMD_ERR_R1_FUNC_NUM_ERROR 9
+#define SD_CMD_ERR_R1_ADDRESS_ERROR 10
+#define SD_CMD_ERR_R1_PARAMETER_ERROR 11
+#define SD_CMD_ERR_DATA_ERROR_TOKEN 12
+#define SD_CMD_ERR_DATA_NOT_ACCEPTED 13
+#define SD_CMD7_ARG_RCA_SHIFT 16
+
+#define SD_CARD_STATUS_PENDING 0x01
+#define SD_CARD_STATUS_BUFFER_OVERFLOW 0x01
+#define SD_CARD_STATUS_DEVICE_BUSY 0x02
+#define SD_CARD_STATUS_UNSUCCESSFUL 0x03
+#define SD_CARD_STATUS_NOT_IMPLEMENTED 0x04
+#define SD_CARD_STATUS_ACCESS_VIOLATION 0x05
+#define SD_CARD_STATUS_INVALID_HANDLE 0x06
+#define SD_CARD_STATUS_INVALID_PARAMETER 0x07
+#define SD_CARD_STATUS_NO_SUCH_DEVICE 0x08
+#define SD_CARD_STATUS_INVALID_DEVICE_REQUEST 0x09
+#define SD_CARD_STATUS_NO_MEMORY 0x0A
+#define SD_CARD_STATUS_BUS_DRIVER_NOT_READY 0x0B
+#define SD_CARD_STATUS_DATA_ERROR 0x0C
+#define SD_CARD_STATUS_CRC_ERROR 0x0D
+#define SD_CARD_STATUS_INSUFFICIENT_RESOURCES 0x0E
+#define SD_CARD_STATUS_DEVICE_NOT_CONNECTED 0x10
+#define SD_CARD_STATUS_DEVICE_REMOVED 0x11
+#define SD_CARD_STATUS_DEVICE_NOT_RESPONDING 0x12
+#define SD_CARD_STATUS_CANCELED 0x13
+#define SD_CARD_STATUS_RESPONSE_TIMEOUT 0x14
+#define SD_CARD_STATUS_DATA_TIMEOUT 0x15
+#define SD_CARD_STATUS_DEVICE_RESPONSE_ERROR 0x16
+#define SD_CARD_STATUS_DEVICE_UNSUPPORTED 0x17
+
+/* Response structure */
+struct sd_r2_resp {
+ uint32_t rsp4; /* 127:96 */
+ uint32_t rsp3; /* 95:64 */
+ uint32_t rsp2; /* 63:32 */
+ uint32_t rsp1; /* 31:0 */
+};
+
+struct sd_r3_resp {
+ uint32_t ocr;
+};
+
+struct sd_r4_resp {
+ uint8_t cardReady;
+ uint8_t funcs;
+ uint8_t memPresent;
+ uint32_t ocr;
+};
+
+struct sd_r5_resp {
+ uint8_t data;
+};
+
+struct sd_r6_resp {
+ uint16_t rca;
+ uint16_t cardStatus;
+};
+
+struct sd_r7_resp {
+ uint16_t rca;
+};
+
+struct sd_resp {
+ uint8_t r1;
+ uint32_t cardStatus;
+ uint32_t rawData[4];
+ union {
+ struct sd_r2_resp r2;
+ struct sd_r3_resp r3;
+ struct sd_r4_resp r4;
+ struct sd_r5_resp r5;
+ struct sd_r6_resp r6;
+ struct sd_r7_resp r7;
+ } data;
+};
+
+struct sd_card_info {
+ uint32_t type; /* card type SD, MMC or SDIO */
+ uint64_t size; /* card size */
+ uint32_t speed; /* card speed */
+ uint32_t voltage; /* voltage supported */
+ uint32_t mId; /* manufacturer ID */
+ uint32_t oId; /* OEM ID */
+ uint32_t classes; /* card class */
+ uint32_t name1; /* product name part 1 */
+ uint32_t name2; /* product name part 2 */
+ uint32_t revision; /* revison */
+ uint32_t sn; /* serial number */
+ uint32_t numIoFuns; /* total I/O function number */
+ uint32_t maxRdBlkLen; /* max read block length */
+ uint32_t maxWtBlkLen; /* max write block length */
+ uint32_t blkMode; /* sdio card block mode support */
+ uint32_t f0Cis; /* sdio card block mode support */
+ uint32_t f1Cis; /* sdio card block mode support */
+
+ uint8_t partRead; /* partial block read allowed */
+ uint8_t partWrite; /* partial block write allowed */
+ uint8_t dsr; /* card DSR */
+ uint8_t rdCurMin; /* min current for read */
+ uint8_t rdCurMax; /* max current for read */
+ uint8_t wtCurMin; /* min current for write */
+ uint8_t wtCurMax; /* max current for write */
+ uint8_t erase; /* erase enable */
+ uint8_t eraseSecSize; /* erase sector size */
+ uint8_t proGrpSize; /* write protection group size */
+ uint8_t protect; /* permanent write protection or not */
+ uint8_t tmpProt; /* temp write protection or not */
+ uint8_t wtSpeed; /* write speed relatively to read */
+ uint8_t version; /* card version 0:1.0 - 1.01, 1:1.10, 2:2.0 */
+ uint8_t eraseState; /* if the data will be 0 or 1 after erase */
+ uint8_t bus; /* data with supported */
+ uint8_t security; /* security support 0, 2:1.01 3:2.0 */
+ uint8_t format; /* file format */
+ uint8_t fileGrp; /* file group */
+ char pwd[20]; /* password */
+};
+
+struct sd_handle {
+ struct sd_dev *device;
+ struct sd_card_info *card;
+};
+
+int sd_cmd0(struct sd_handle *handle);
+int sd_cmd1(struct sd_handle *handle, uint32_t initOcr, uint32_t *ocr);
+int sd_cmd2(struct sd_handle *handle);
+int sd_cmd3(struct sd_handle *handle);
+int sd_cmd7(struct sd_handle *handle, uint32_t rca);
+int sd_cmd9(struct sd_handle *handle, struct sd_card_data *card);
+int sd_cmd13(struct sd_handle *handle, uint32_t *status);
+int sd_cmd16(struct sd_handle *handle, uint32_t blockLen);
+int sd_cmd17(struct sd_handle *handle,
+ uint32_t addr, uint32_t len, uint8_t *buffer);
+int sd_cmd18(struct sd_handle *handle,
+ uint32_t addr, uint32_t len, uint8_t *buffer);
+#ifdef INCLUDE_EMMC_DRIVER_WRITE_CODE
+int sd_cmd24(struct sd_handle *handle,
+ uint32_t addr, uint32_t len, uint8_t *buffer);
+int sd_cmd25(struct sd_handle *handle,
+ uint32_t addr, uint32_t len, uint8_t *buffer);
+#endif
+#ifdef INCLUDE_EMMC_DRIVER_ERASE_CODE
+int sd_cmd35(struct sd_handle *handle, uint32_t start);
+int sd_cmd36(struct sd_handle *handle, uint32_t end);
+int sd_cmd38(struct sd_handle *handle);
+#endif
+int mmc_cmd6(struct sd_handle *handle, uint32_t argument);
+int mmc_cmd8(struct sd_handle *handle, uint8_t *extCsdReg);
+
+int send_cmd(struct sd_handle *handle, uint32_t cmdIndex,
+ uint32_t argument, uint32_t options, struct sd_resp *resp);
+#endif /* CSL_SD_CMD_H */
diff --git a/include/drivers/brcm/emmc/emmc_csl_sdprot.h b/include/drivers/brcm/emmc/emmc_csl_sdprot.h
new file mode 100644
index 0000000..597e1e0
--- /dev/null
+++ b/include/drivers/brcm/emmc/emmc_csl_sdprot.h
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CSL_SD_PROT_H
+#define CSL_SD_PROT_H
+
+#define SD_CARD_UNKNOWN 0 /* bad type or unrecognized */
+#define SD_CARD_SD 1 /* IO only card */
+#define SD_CARD_SDIO 2 /* memory only card */
+#define SD_CARD_COMBO 3 /* IO and memory combo card */
+#define SD_CARD_MMC 4 /* memory only card */
+#define SD_CARD_CEATA 5 /* IO and memory combo card */
+
+#define SD_IO_FIXED_ADDRESS 0 /* fix Address */
+#define SD_IO_INCREMENT_ADDRESS 1
+
+#define SD_HIGH_CAPACITY_CARD 0x40000000
+
+#define MMC_CMD_IDLE_RESET_ARG 0xF0F0F0F0
+
+/* Supported operating voltages are 3.2-3.3 and 3.3-3.4 */
+#define MMC_OCR_OP_VOLT 0x00300000
+/* Enable sector access mode */
+#define MMC_OCR_SECTOR_ACCESS_MODE 0x40000000
+
+/* command index */
+#define SD_CMD_GO_IDLE_STATE 0 /* mandatory for SDIO */
+#define SD_CMD_SEND_OPCOND 1
+#define SD_CMD_ALL_SEND_CID 2
+#define SD_CMD_MMC_SET_RCA 3
+#define SD_CMD_MMC_SET_DSR 4
+#define SD_CMD_IO_SEND_OP_COND 5 /* mandatory for SDIO */
+#define SD_ACMD_SET_BUS_WIDTH 6
+#define SD_CMD_SWITCH_FUNC 6
+#define SD_CMD_SELECT_DESELECT_CARD 7
+#define SD_CMD_READ_EXT_CSD 8
+#define SD_CMD_SEND_CSD 9
+#define SD_CMD_SEND_CID 10
+#define SD_CMD_STOP_TRANSMISSION 12
+#define SD_CMD_SEND_STATUS 13
+#define SD_ACMD_SD_STATUS 13
+#define SD_CMD_GO_INACTIVE_STATE 15
+#define SD_CMD_SET_BLOCKLEN 16
+#define SD_CMD_READ_SINGLE_BLOCK 17
+#define SD_CMD_READ_MULTIPLE_BLOCK 18
+#define SD_CMD_WRITE_BLOCK 24
+#define SD_CMD_WRITE_MULTIPLE_BLOCK 25
+#define SD_CMD_PROGRAM_CSD 27
+#define SD_CMD_SET_WRITE_PROT 28
+#define SD_CMD_CLR_WRITE_PROT 29
+#define SD_CMD_SEND_WRITE_PROT 30
+#define SD_CMD_ERASE_WR_BLK_START 32
+#define SD_CMD_ERASE_WR_BLK_END 33
+#define SD_CMD_ERASE_GROUP_START 35
+#define SD_CMD_ERASE_GROUP_END 36
+#define SD_CMD_ERASE 38
+#define SD_CMD_LOCK_UNLOCK 42
+#define SD_CMD_IO_RW_DIRECT 52 /* mandatory for SDIO */
+#define SD_CMD_IO_RW_EXTENDED 53 /* mandatory for SDIO */
+#define SD_CMD_APP_CMD 55
+#define SD_CMD_GEN_CMD 56
+#define SD_CMD_READ_OCR 58
+#define SD_CMD_CRC_ON_OFF 59 /* mandatory for SDIO */
+#define SD_ACMD_SEND_NUM_WR_BLOCKS 22
+#define SD_ACMD_SET_WR_BLOCK_ERASE_CNT 23
+#define SD_ACMD_SD_SEND_OP_COND 41
+#define SD_ACMD_SET_CLR_CARD_DETECT 42
+#define SD_ACMD_SEND_SCR 51
+
+/* response parameters */
+#define SD_RSP_NO_NONE 0
+#define SD_RSP_NO_1 1
+#define SD_RSP_NO_2 2
+#define SD_RSP_NO_3 3
+#define SD_RSP_NO_4 4
+#define SD_RSP_NO_5 5
+#define SD_RSP_NO_6 6
+
+/* Modified R6 response (to CMD3) */
+#define SD_RSP_MR6_COM_CRC_ERROR 0x8000
+#define SD_RSP_MR6_ILLEGAL_COMMAND 0x4000
+#define SD_RSP_MR6_ERROR 0x2000
+
+/* Modified R1 in R4 Response (to CMD5) */
+#define SD_RSP_MR1_SBIT 0x80
+#define SD_RSP_MR1_PARAMETER_ERROR 0x40
+#define SD_RSP_MR1_RFU5 0x20
+#define SD_RSP_MR1_FUNC_NUM_ERROR 0x10
+#define SD_RSP_MR1_COM_CRC_ERROR 0x80
+#define SD_RSP_MR1_ILLEGAL_COMMAND 0x40
+#define SD_RSP_MR1_RFU1 0x20
+#define SD_RSP_MR1_IDLE_STATE 0x01
+
+/* R5 response (to CMD52 and CMD53) */
+#define SD_RSP_R5_COM_CRC_ERROR 0x80
+#define SD_RSP_R5_ILLEGAL_COMMAND 0x40
+#define SD_RSP_R5_IO_CURRENTSTATE1 0x20
+#define SD_RSP_R5_IO_CURRENTSTATE0 0x10
+#define SD_RSP_R5_ERROR 0x80
+#define SD_RSP_R5_RFU 0x40
+#define SD_RSP_R5_FUNC_NUM_ERROR 0x20
+#define SD_RSP_R5_OUT_OF_RANGE 0x01
+
+/* argument for SD_CMD_IO_RW_DIRECT and SD_CMD_IO_RW_EXTENDED */
+#define SD_OP_READ 0 /* Read_Write */
+#define SD_OP_WRITE 1 /* Read_Write */
+
+#define SD_RW_NORMAL 0 /* no RAW */
+#define SD_RW_RAW 1 /* RAW */
+
+#define SD_BYTE_MODE 0 /* Byte Mode */
+#define SD_BLOCK_MODE 1 /* BlockMode */
+
+#define SD_FIXED_ADDRESS 0 /* fix Address */
+#define SD_INCREMENT_ADDRESS 1 /* IncrementAddress */
+
+#define SD_CMD5_ARG_IO_OCR_MASK 0x00FFFFFF
+#define SD_CMD5_ARG_IO_OCR_SHIFT 0
+#define SD_CMD55_ARG_RCA_SHIFT 16
+#define SD_CMD59_ARG_CRC_OPTION_MASK 0x01
+#define SD_CMD59_ARG_CRC_OPTION_SHIFT 0
+
+/* SD_CMD_IO_RW_DIRECT Argument */
+#define SdioIoRWDirectArg(rw, raw, func, addr, data) \
+ (((rw & 1) << 31) | ((func & 0x7) << 28) | \
+ ((raw & 1) << 27) | ((addr & 0x1FFFF) << 9) | \
+ (data & 0xFF))
+
+/* build SD_CMD_IO_RW_EXTENDED Argument */
+#define SdioIoRWExtArg(rw, blk, func, addr, inc_addr, count) \
+ (((rw & 1) << 31) | ((func & 0x7) << 28) | \
+ ((blk & 1) << 27) | ((inc_addr & 1) << 26) | \
+ ((addr & 0x1FFFF) << 9) | (count & 0x1FF))
+
+/*
+ * The Common I/O area shall be implemented on all SDIO cards and
+ * is accessed the the host via I/O reads and writes to function 0,
+ * the registers within the CIA are provided to enable/disable
+ * the operationo fthe i/o funciton.
+ */
+
+/* cccr_sdio_rev */
+#define SDIO_REV_SDIOID_MASK 0xf0 /* SDIO spec revision number */
+#define SDIO_REV_CCCRID_MASK 0x0f /* CCCR format version number */
+
+/* sd_rev */
+#define SDIO_REV_PHY_MASK 0x0f /* SD format version number */
+#define SDIO_FUNC_ENABLE_1 0x02 /* function 1 I/O enable */
+#define SDIO_FUNC_READY_1 0x02 /* function 1 I/O ready */
+#define SDIO_INTR_CTL_FUNC1_EN 0x2 /* interrupt enable for function 1 */
+#define SDIO_INTR_CTL_MASTER_EN 0x1 /* interrupt enable master */
+#define SDIO_INTR_STATUS_FUNC1 0x2 /* interrupt pending for function 1 */
+#define SDIO_IO_ABORT_RESET_ALL 0x08 /* I/O card reset */
+#define SDIO_IO_ABORT_FUNC_MASK 0x07 /* abort selection: function x */
+#define SDIO_BUS_CARD_DETECT_DIS 0x80 /* Card Detect disable */
+#define SDIO_BUS_SPI_CONT_INTR_CAP 0x40 /* support continuous SPI interrupt */
+#define SDIO_BUS_SPI_CONT_INTR_EN 0x20 /* continuous SPI interrupt enable */
+#define SDIO_BUS_DATA_WIDTH_MASK 0x03 /* bus width mask */
+#define SDIO_BUS_DATA_WIDTH_4BIT 0x02 /* bus width 4-bit mode */
+#define SDIO_BUS_DATA_WIDTH_1BIT 0x00 /* bus width 1-bit mode */
+
+/* capability */
+#define SDIO_CAP_4BLS 0x80 /* 4-bit support for low speed card */
+#define SDIO_CAP_LSC 0x40 /* low speed card */
+#define SDIO_CAP_E4MI 0x20 /* enable int between block in 4-bit mode */
+#define SDIO_CAP_S4MI 0x10 /* support int between block in 4-bit mode */
+#define SDIO_CAP_SBS 0x08 /* support suspend/resume */
+#define SDIO_CAP_SRW 0x04 /* support read wait */
+#define SDIO_CAP_SMB 0x02 /* support multi-block transfer */
+#define SDIO_CAP_SDC 0x01 /* Support Direct cmd during multi-uint8 transfer */
+
+/* CIA FBR1 registers */
+#define SDIO_FUNC1_INFO 0x100 /* basic info for function 1 */
+#define SDIO_FUNC1_EXT 0x101 /* extension of standard I/O device */
+#define SDIO_CIS_FUNC1_BASE_LOW 0x109 /* function 1 cis address bit 0-7 */
+#define SDIO_CIS_FUNC1_BASE_MID 0x10A /* function 1 cis address bit 8-15 */
+#define SDIO_CIS_FUNC1_BASE_HIGH 0x10B /* function 1 cis address bit 16 */
+#define SDIO_CSA_BASE_LOW 0x10C /* CSA base address uint8_t 0 */
+#define SDIO_CSA_BASE_MID 0x10D /* CSA base address uint8_t 1 */
+#define SDIO_CSA_BASE_HIGH 0x10E /* CSA base address uint8_t 2 */
+#define SDIO_CSA_DATA_OFFSET 0x10F /* CSA data register */
+#define SDIO_IO_BLK_SIZE_LOW 0x110 /* I/O block size uint8_t 0 */
+#define SDIO_IO_BLK_SIZE_HIGH 0x111 /* I/O block size uint8_t 1 */
+
+/* SD_SDIO_FUNC1_INFO bits */
+#define SDIO_FUNC1_INFO_DIC 0x0f /* device interface code */
+#define SDIO_FUNC1_INFO_CSA 0x40 /* CSA support flag */
+#define SDIO_FUNC1_INFO_CSA_EN 0x80 /* CSA enabled */
+
+/* SD_SDIO_FUNC1_EXT bits */
+#define SDIO_FUNC1_EXT_SHP 0x03 /* support high power */
+#define SDIO_FUNC1_EXT_EHP 0x04 /* enable high power */
+
+/* devctr */
+/* I/O device interface code */
+#define SDIO_DEVCTR_DEVINTER 0x0f
+/* support CSA */
+#define SDIO_DEVCTR_CSA_SUP 0x40
+/* enable CSA */
+#define SDIO_DEVCTR_CSA_EN 0x80
+
+/* ext_dev */
+/* supports high-power mask */
+#define SDIO_HIGHPWR_SUPPORT_M 0x3
+/* enable high power */
+#define SDIO_HIGHPWR_EN 0x4
+/* standard power function(up to 200mA */
+#define SDIO_HP_STD 0
+/* need high power to operate */
+#define SDIO_HP_REQUIRED 0x2
+/* can work with standard power, but prefer high power */
+#define SDIO_HP_DESIRED 0x3
+
+/* misc define */
+/* macro to calculate fbr register base */
+#define FBR_REG_BASE(n) (n*0x100)
+#define SDIO_FUNC_0 0
+#define SDIO_FUNC_1 1
+#define SDIO_FUNC_2 2
+#define SDIO_FUNC_3 3
+#define SDIO_FUNC_4 4
+#define SDIO_FUNC_5 5
+#define SDIO_FUNC_6 6
+#define SDIO_FUNC_7 7
+
+/* maximum block size for block mode operation */
+#define SDIO_MAX_BLOCK_SIZE 2048
+/* minimum block size for block mode operation */
+#define SDIO_MIN_BLOCK_SIZE 1
+
+/* Card registers: status bit position */
+#define SDIO_STATUS_OUTOFRANGE 31
+#define SDIO_STATUS_COMCRCERROR 23
+#define SDIO_STATUS_ILLEGALCOMMAND 22
+#define SDIO_STATUS_ERROR 19
+#define SDIO_STATUS_IOCURRENTSTATE3 12
+#define SDIO_STATUS_IOCURRENTSTATE2 11
+#define SDIO_STATUS_IOCURRENTSTATE1 10
+#define SDIO_STATUS_IOCURRENTSTATE0 9
+#define SDIO_STATUS_FUN_NUM_ERROR 4
+
+#define GET_SDIOCARD_STATUS(x) ((x >> 9) & 0x0f)
+#define SDIO_STATUS_STATE_IDLE 0
+#define SDIO_STATUS_STATE_READY 1
+#define SDIO_STATUS_STATE_IDENT 2
+#define SDIO_STATUS_STATE_STBY 3
+#define SDIO_STATUS_STATE_TRAN 4
+#define SDIO_STATUS_STATE_DATA 5
+#define SDIO_STATUS_STATE_RCV 6
+#define SDIO_STATUS_STATE_PRG 7
+#define SDIO_STATUS_STATE_DIS 8
+
+/* sprom */
+#define SBSDIO_SPROM_CS 0x10000 /* command and status */
+#define SBSDIO_SPROM_INFO 0x10001 /* info register */
+#define SBSDIO_SPROM_DATA_LOW 0x10002 /* indirect access data uint8_t 0 */
+#define SBSDIO_SPROM_DATA_HIGH 0x10003 /* indirect access data uint8_t 1 */
+#define SBSDIO_SPROM_ADDR_LOW 0x10004 /* indirect access addr uint8_t 0 */
+#define SBSDIO_SPROM_ADDR_HIGH 0x10005 /* indirect access addr uint8_t 0 */
+#define SBSDIO_CHIP_CTRL_DATA 0x10006 /* xtal_pu data output */
+#define SBSDIO_CHIP_CTRL_EN 0x10007 /* xtal_pu enable */
+#define SBSDIO_WATERMARK 0x10008 /* retired in rev 7 */
+#define SBSDIO_DEVICE_CTL 0x10009 /* control busy signal generation */
+
+#define SBSDIO_SPROM_IDLE 0
+#define SBSDIO_SPROM_WRITE 1
+#define SBSDIO_SPROM_READ 2
+#define SBSDIO_SPROM_WEN 4
+#define SBSDIO_SPROM_WDS 7
+#define SBSDIO_SPROM_DONE 8
+
+/* SBSDIO_SPROM_INFO */
+#define SBSDIO_SROM_SZ_MASK 0x03 /* SROM size, 1: 4k, 2: 16k */
+#define SBSDIO_SROM_BLANK 0x04 /* depreciated in corerev 6 */
+#define SBSDIO_SROM_OTP 0x80 /* OTP present */
+
+/* SBSDIO_CHIP_CTRL */
+/* or'd with onchip xtal_pu, 1: power on oscillator */
+#define SBSDIO_CHIP_CTRL_XTAL 0x01
+
+/* SBSDIO_WATERMARK */
+/* number of bytes minus 1 for sd device to wait before sending data to host */
+#define SBSDIO_WATERMARK_MASK 0x3f
+
+/* SBSDIO_DEVICE_CTL */
+/* 1: device will assert busy signal when receiving CMD53 */
+#define SBSDIO_DEVCTL_SETBUSY 0x01
+/* 1: assertion of sdio interrupt is synchronous to the sdio clock */
+#define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02
+
+/* function 1 OCP space */
+/* sb offset addr is <= 15 bits, 32k */
+#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF
+#define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000
+/* sdsdio function 1 OCP space has 16/32 bit section */
+#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000
+
+/* direct(mapped) cis space */
+/* MAPPED common CIS address */
+#define SBSDIO_CIS_BASE_COMMON 0x1000
+/* function 0(common) cis size in bytes */
+#define SBSDIO_CIS_FUNC0_LIMIT 0x020
+/* funciton 1 cis size in bytes */
+#define SBSDIO_CIS_SIZE_LIMIT 0x200
+/* cis offset addr is < 17 bits */
+#define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF
+/* manfid tuple length, include tuple, link bytes */
+#define SBSDIO_CIS_MANFID_TUPLE_LEN 6
+
+/* indirect cis access (in sprom) */
+/* 8 control bytes first, CIS starts from 8th uint8_t */
+#define SBSDIO_SPROM_CIS_OFFSET 0x8
+/* sdio uint8_t mode: maximum length of one data comamnd */
+#define SBSDIO_BYTEMODE_DATALEN_MAX 64
+/* 4317 supports less */
+#define SBSDIO_BYTEMODE_DATALEN_MAX_4317 52
+/* sdio core function one address mask */
+#define SBSDIO_CORE_ADDR_MASK 0x1FFFF
+
+/* CEATA defines */
+#define CEATA_EXT_CSDBLOCK_SIZE 512
+#define CEATA_FAST_IO 39
+#define CEATA_MULTIPLE_REGISTER_RW 60
+#define CEATA_MULTIPLE_BLOCK_RW 61
+
+/* defines CE ATA task file registers */
+#define CEATA_SCT_CNT_EXP_REG 0x02
+#define CEATA_LBA_LOW_EXP_REG 0x03
+#define CEATA_LBA_MID_EXP_REG 0x04
+#define CEATA_LBA_HIGH_EXP_REG 0x05
+#define CEATA_CNTRL_REG 0x06
+#define CEATA_FEATURE_REG 0x09 /* write */
+#define CEATA_ERROR_REG 0x09 /* read */
+#define CEATA_SCT_CNT_REG 0x0A
+#define CEATA_LBA_LOW_REG 0x0B
+#define CEATA_LBA_MID_REG 0x0C
+#define CEATA_LBA_HIGH_REG 0x0D
+#define CEATA_DEV_HEAD_REG 0x0E
+#define CEATA_STA_REG 0x0F /* read */
+#define CEATA_CMD_REG 0x0F /* write */
+
+/* defines CEATA control and status registers for ce ata client driver */
+#define CEATA_SCR_TEMPC_REG 0x80
+#define CEATA_SCR_TEMPMAXP_REG 0x84
+#define CEATA_TEMPMINP_REG 0x88
+#define CEATA_SCR_STATUS_REG 0x8C
+#define CEATA_SCR_REALLOCSA_REG 0x90
+#define CEATA_SCR_ERETRACTSA_REG 0x94
+#define CEATA_SCR_CAPABILITIES_REG 0x98
+#define CEATA_SCR_CONTROL_REG 0xC0
+
+/* defines for SCR capabilities register bits for ce ata client driver */
+#define CEATA_SCR_CAP_512 0x00000001
+#define CEATA_SCR_CAP_1K 0x00000002
+#define CEATA_SCR_CAP_4K 0x00000004
+
+/* defines CE ATA Control reg bits for ce ata client driver */
+#define CEATA_CNTRL_ENABLE_INTR 0x00
+#define CEATA_CNTRL_DISABLE_INTR 0x02
+#define CEATA_CNTRL_SRST 0x04
+#define CEATA_CNTRL_RSRST 0x00
+
+/* define CE ATA Status reg bits for ce ata client driver */
+#define CEATA_STA_ERROR_BIT 0x01
+#define CEATA_STA_OVR_BIT 0x02
+#define CEATA_STA_SPT_BIT 0x04
+#define CEATA_STA_DRQ_BIT 0x08
+#define CEATA_STA_DRDY_BIT 0x40
+#define CEATA_STA_BSY_BIT 0x80
+
+/* define CE ATA Error reg bits for ce ata client driver */
+#define CEATA_ERROR_ABORTED_BIT 0x04
+#define CEATA_ERROR_IDNF_BIT 0x10
+#define CEATA_ERROR_UNCORRECTABLE_BIT 0x40
+#define CEATA_ERROR_ICRC_BIT 0x80
+
+/* define CE ATA Commands for ce ata client driver */
+#define CEATA_CMD_IDENTIFY_DEVICE 0xEC
+#define CEATA_CMD_READ_DMA_EXT 0x25
+#define CEATA_CMD_WRITE_DMA_EXT 0x35
+#define CEATA_CMD_STANDBY_IMMEDIATE 0xE0
+#define CEATA_CMD_FLUSH_CACHE_EXT 0xEA
+
+struct csd_mmc {
+ uint32_t padding:8;
+ uint32_t structure:2;
+ uint32_t csdSpecVer:4;
+ uint32_t reserved1:2;
+ uint32_t taac:8;
+ uint32_t nsac:8;
+ uint32_t speed:8;
+ uint32_t classes:12;
+ uint32_t rdBlkLen:4;
+ uint32_t rdBlkPartial:1;
+ uint32_t wrBlkMisalign:1;
+ uint32_t rdBlkMisalign:1;
+ uint32_t dsr:1;
+ uint32_t reserved2:2;
+ uint32_t size:12;
+ uint32_t vddRdCurrMin:3;
+ uint32_t vddRdCurrMax:3;
+ uint32_t vddWrCurrMin:3;
+ uint32_t vddWrCurrMax:3;
+ uint32_t devSizeMulti:3;
+ uint32_t eraseGrpSize:5;
+ uint32_t eraseGrpSizeMulti:5;
+ uint32_t wrProtGroupSize:5;
+ uint32_t wrProtGroupEnable:1;
+ uint32_t manuDefEcc:2;
+ uint32_t wrSpeedFactor:3;
+ uint32_t wrBlkLen:4;
+ uint32_t wrBlkPartial:1;
+ uint32_t reserved5:4;
+ uint32_t protAppl:1;
+ uint32_t fileFormatGrp:1;
+ uint32_t copyFlag:1;
+ uint32_t permWrProt:1;
+ uint32_t tmpWrProt:1;
+ uint32_t fileFormat:2;
+ uint32_t eccCode:2;
+};
+
+/* CSD register*/
+union sd_csd {
+ uint32_t csd[4];
+ struct csd_mmc mmc;
+};
+
+struct sd_card_data {
+ union sd_csd csd;
+};
+#endif /* CSL_SD_PROT_H */
diff --git a/include/drivers/brcm/emmc/emmc_pboot_hal_memory_drv.h b/include/drivers/brcm/emmc/emmc_pboot_hal_memory_drv.h
new file mode 100644
index 0000000..8e61b51
--- /dev/null
+++ b/include/drivers/brcm/emmc/emmc_pboot_hal_memory_drv.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PBOOT_HAL_MEMORY_EMMC_DRV_H
+#define PBOOT_HAL_MEMORY_EMMC_DRV_H
+
+#include <drivers/delay_timer.h>
+
+#include "emmc_chal_types.h"
+#include "emmc_chal_sd.h"
+#include "emmc_csl_sdprot.h"
+#include "emmc_csl_sdcmd.h"
+#include "emmc_csl_sd.h"
+#include "emmc_brcm_rdb_sd4_top.h"
+
+#define CLK_SDIO_DIV_52MHZ 0x0
+#define SYSCFG_IOCR4_PAD_10MA 0x38000000
+
+#define SDCLK_CNT_PER_MS 52000
+#define BOOT_ACK_TIMEOUT (50 * SDCLK_CNT_PER_MS)
+#define BOOT_DATA_TIMEOUT (1000 * SDCLK_CNT_PER_MS)
+
+#define EMMC_BOOT_OK 0
+#define EMMC_BOOT_ERROR 1
+#define EMMC_BOOT_TIMEOUT 2
+#define EMMC_BOOT_INVALIDIMAGE 3
+#define EMMC_BOOT_NO_CARD 4
+
+#define EMMC_USER_AREA 0
+#define EMMC_BOOT_PARTITION1 1
+#define EMMC_BOOT_PARTITION2 2
+#define EMMC_USE_CURRENT_PARTITION 3
+
+#define EMMC_BOOT_PARTITION_SIZE (128*1024)
+#define EMMC_BLOCK_SIZE 512
+#define EMMC_DMA_SIZE (4*1024)
+
+/*
+ * EMMC4.3 definitions
+ * Table 6 EXT_CSD access mode
+ * Access
+ * Bits Access Name Operation
+ * 00 Command Set The command set is changed according to the Cmd Set field of
+ * the argument
+ * 01 Set Bits The bits in the pointed uint8_t are set,
+ * according to the 1 bits in the Value field.
+ * 10 Clear Bits The bits in the pointed uint8_t are cleared,
+ * according to the 1 bits in the Value field.
+ * 11 Write Byte The Value field is written into the pointed uint8_t.
+ */
+
+#define SDIO_HW_EMMC_EXT_CSD_WRITE_BYTE 0X03000000
+
+/* Boot bus width1 BOOT_BUS_WIDTH 1 R/W [177] */
+#define SDIO_HW_EMMC_EXT_CSD_BOOT_BUS_WIDTH_OFFSET 0X00B10000
+
+/* Boot configuration BOOT_CONFIG 1 R/W [179] */
+#define SDIO_HW_EMMC_EXT_CSD_BOOT_CONFIG_OFFSET 0X00B30000
+
+/* Bus width mode BUS_WIDTH 1 WO [183] */
+#define SDIO_HW_EMMC_EXT_CSD_BUS_WIDTH_OFFSET 0X00B70000
+
+/*
+ * Bit 6: BOOT_ACK (non-volatile)
+ * 0x0 : No boot acknowledge sent (default)
+ * 0x1 : Boot acknowledge sent during boot operation
+ * Bit[5:3] : BOOT_PARTITION_ENABLE (non-volatile)
+ * User selects boot data that will be sent to master
+ * 0x0 : Device not boot enabled (default)
+ * 0x1 : Boot partition 1 enabled for boot
+ * 0x2 : Boot partition 2 enabled for boot
+ * 0x3-0x6 : Reserved
+ * 0x7 : User area enabled for boot
+ * Bit[2:0] : BOOT_PARTITION_ACCESS
+ * User selects boot partition for read and write operation
+ * 0x0 : No access to boot partition (default)
+ * 0x1 : R/W boot partition 1
+ * 0x2 : R/W boot partition 2
+ * 0x3-0x7 : Reserved
+ */
+
+#define SDIO_HW_EMMC_EXT_CSD_BOOT_ACC_BOOT1 0X00000100
+#define SDIO_HW_EMMC_EXT_CSD_BOOT_ACC_BOOT2 0X00000200
+#define SDIO_HW_EMMC_EXT_CSD_BOOT_ACC_USER 0X00000000
+#define SDIO_HW_EMMC_EXT_CSD_BOOT_EN_BOOT1 0X00004800
+#define SDIO_HW_EMMC_EXT_CSD_BOOT_EN_BOOT2 0X00005000
+#define SDIO_HW_EMMC_EXT_CSD_BOOT_EN_USER 0X00007800
+
+#define SD_US_DELAY(x) udelay(x)
+
+#endif
diff --git a/include/drivers/brcm/fru.h b/include/drivers/brcm/fru.h
new file mode 100644
index 0000000..ee863b4
--- /dev/null
+++ b/include/drivers/brcm/fru.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FRU_H
+#define FRU_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/* max string length */
+#define FRU_MAX_STR_LEN 32
+
+/* max number of DDR channels */
+#define BCM_MAX_NR_DDR 3
+
+/* max supported FRU table size */
+#define BCM_MAX_FRU_LEN 512
+
+/* FRU table starting offset */
+#define BCM_FRU_TBL_OFFSET 0x300000
+
+/* FRU time constants */
+#define MINS_PER_DAY 1440
+#define MINS_PER_HOUR 60
+#define FRU_YEAR_START 1996
+#define FRU_MONTH_START 1
+#define FRU_DAY_START 1
+#define MONTHS_PER_YEAR 12
+
+/*
+ * FRU areas based on the spec
+ */
+enum fru_area_name {
+ FRU_AREA_INTERNAL = 0,
+ FRU_AREA_CHASSIS_INFO,
+ FRU_AREA_BOARD_INFO,
+ FRU_AREA_PRODUCT_INFO,
+ FRU_AREA_MRECORD_INFO,
+ FRU_MAX_NR_AREAS
+};
+
+/*
+ * FRU area information
+ *
+ * @use: indicate this area is being used
+ * @version: format version
+ * @offset: offset of this area from the beginning of the FRU table
+ * @len: total length of the area
+ */
+struct fru_area_info {
+ bool use;
+ uint8_t version;
+ unsigned int offset;
+ unsigned int len;
+};
+
+/*
+ * DDR MCB information
+ *
+ * @idx: DDR channel index
+ * @size_mb: DDR size of this channel in MB
+ * @ref_id: DDR MCB reference ID
+ */
+struct ddr_mcb {
+ unsigned int idx;
+ unsigned int size_mb;
+ uint32_t ref_id;
+};
+
+/*
+ * DDR information
+ *
+ * @ddr_info: array that contains MCB related info for each channel
+ */
+struct ddr_info {
+ struct ddr_mcb mcb[BCM_MAX_NR_DDR];
+};
+
+/*
+ * FRU board area information
+ *
+ * @lang: Language code
+ * @mfg_date: Manufacturing date
+ * @manufacturer: Manufacturer
+ * @product_name: Product name
+ * @serial_number: Serial number
+ * @part_number: Part number
+ * @file_id: FRU file ID
+ */
+struct fru_board_info {
+ unsigned char lang;
+ unsigned int mfg_date;
+ unsigned char manufacturer[FRU_MAX_STR_LEN];
+ unsigned char product_name[FRU_MAX_STR_LEN];
+ unsigned char serial_number[FRU_MAX_STR_LEN];
+ unsigned char part_number[FRU_MAX_STR_LEN];
+ unsigned char file_id[FRU_MAX_STR_LEN];
+};
+
+/*
+ * FRU manufacture date in human readable format
+ */
+struct fru_time {
+ unsigned int min;
+ unsigned int hour;
+ unsigned int day;
+ unsigned int month;
+ unsigned int year;
+};
+
+#ifdef USE_FRU
+int fru_validate(uint8_t *data, struct fru_area_info *fru_area);
+int fru_parse_ddr(uint8_t *data, struct fru_area_info *area,
+ struct ddr_info *ddr);
+int fru_parse_board(uint8_t *data, struct fru_area_info *area,
+ struct fru_board_info *board);
+void fru_format_time(unsigned int min, struct fru_time *tm);
+#else
+static inline int fru_validate(uint8_t *data, struct fru_area_info *fru_area)
+{
+ return -1;
+}
+
+static inline int fru_parse_ddr(uint8_t *data, struct fru_area_info *area,
+ struct ddr_info *ddr)
+{
+ return -1;
+}
+
+static inline int fru_parse_board(uint8_t *data, struct fru_area_info *area,
+ struct fru_board_info *board)
+{
+ return -1;
+}
+
+static inline void fru_format_time(unsigned int min, struct fru_time *tm)
+{
+}
+#endif /* USE_FRU */
+
+#endif /* FRU_H */
diff --git a/include/drivers/brcm/i2c/i2c.h b/include/drivers/brcm/i2c/i2c.h
new file mode 100644
index 0000000..24d42e2
--- /dev/null
+++ b/include/drivers/brcm/i2c/i2c.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2016 - 2021, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef I2C_H
+#define I2C_H
+
+#include <stdint.h>
+
+#define I2C_SPEED_100KHz 100000
+#define I2C_SPEED_400KHz 400000
+#define I2C_SPEED_DEFAULT I2C_SPEED_100KHz
+
+/*
+ * Function Name: i2c_probe
+ *
+ * Description:
+ * This function probes the I2C bus for the existence of the specified
+ * device.
+ *
+ * Parameters:
+ * bus_id - I2C bus ID
+ * devaddr - Device Address
+ *
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+int i2c_probe(uint32_t bus_id, uint8_t devaddr);
+
+/*
+ * Function Name: i2c_init
+ *
+ * Description:
+ * This function initializes the SMBUS.
+ *
+ * Parameters:
+ * bus_id - I2C bus ID
+ * speed - I2C bus speed in Hz
+ *
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+int i2c_init(uint32_t bus_id, int speed);
+
+/*
+ * Function Name: i2c_set_bus_speed
+ *
+ * Description:
+ * This function configures the SMBUS speed
+ *
+ * Parameters:
+ * bus_id - I2C bus ID
+ * speed - I2C bus speed in Hz
+ *
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+int i2c_set_bus_speed(uint32_t bus_id, uint32_t speed);
+
+/*
+ * Function Name: i2c_get_bus_speed
+ *
+ * Description:
+ * This function returns the SMBUS speed.
+ *
+ * Parameters:
+ * bus_id - I2C bus ID
+ *
+ * Return:
+ * Bus speed in Hz, 0 on failure
+ */
+uint32_t i2c_get_bus_speed(uint32_t bus_id);
+
+/*
+ * Function Name: i2c_recv_byte
+ *
+ * Description:
+ * This function reads I2C data from a device without specifying
+ * a command regsiter.
+ *
+ * Parameters:
+ * bus_id - I2C bus ID
+ * devaddr - Device Address
+ * value - Data Read
+ *
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+int i2c_recv_byte(uint32_t bus_id, uint8_t devaddr, uint8_t *value);
+
+/*
+ * Function Name: i2c_send_byte
+ *
+ * Description:
+ * This function send I2C data to a device without specifying
+ * a command regsiter.
+ *
+ * Parameters:
+ * bus_id - I2C bus ID
+ * devaddr - Device Address
+ * value - Data Send
+ *
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+int i2c_send_byte(uint32_t bus_id, uint8_t devaddr, uint8_t value);
+
+/*
+ * Function Name: i2c_read
+ *
+ * Description:
+ * This function reads I2C data from a device with a designated
+ * command register
+ *
+ * Parameters:
+ * bus_id - I2C bus ID
+ * devaddr - Device Address
+ * addr - Register Offset
+ * alen - Address Length, 1 for byte, 2 for word (not supported)
+ * buffer - Data Buffer
+ * len - Data Length in bytes
+ *
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+int i2c_read(uint32_t bus_id,
+ uint8_t devaddr,
+ uint32_t addr,
+ int alen,
+ uint8_t *buffer,
+ int len);
+
+/*
+ * Function Name: i2c_write
+ *
+ * Description:
+ * This function write I2C data to a device with a designated
+ * command register
+ *
+ * Parameters:
+ * bus_id - I2C bus ID
+ * devaddr - Device Address
+ * addr - Register Offset
+ * alen - Address Length, 1 for byte, 2 for word (not supported)
+ * buffer - Data Buffer
+ * len - Data Length in bytes
+ *
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+int i2c_write(uint32_t bus_id,
+ uint8_t devaddr,
+ uint32_t addr,
+ int alen,
+ uint8_t *buffer,
+ int len);
+
+
+#endif /* I2C_H */
diff --git a/include/drivers/brcm/i2c/i2c_regs.h b/include/drivers/brcm/i2c/i2c_regs.h
new file mode 100644
index 0000000..74ea824
--- /dev/null
+++ b/include/drivers/brcm/i2c/i2c_regs.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2016 - 2021, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef I2C_REGS
+#define I2C_REGS
+
+/* SMBUS Config register */
+#define SMB_CFG_REG 0x0U
+
+#define SMB_CFG_RST_MASK 0x80000000U
+#define SMB_CFG_RST_SHIFT 31U
+
+#define SMB_CFG_SMBEN_MASK 0x40000000U
+#define SMB_CFG_SMBEN_SHIFT 30U
+
+#define SMB_CFG_BITBANGEN_MASK 0x20000000U
+#define SMB_CFG_BITBANGEN_SHIFT 29U
+
+#define SMB_CFG_EN_NIC_SMBADDR0_MASK 0x10000000U
+#define SMB_CFG_EN_NIC_SMBADDR0_SHIFT 28U
+
+#define SMB_CFG_PROMISCMODE_MASK 0x08000000U
+#define SMB_CFG_PROMISCMODE_SHIFT 27U
+
+#define SMB_CFG_TSTMPCNTEN_MASK 0x04000000U
+#define SMB_CFG_TSTMPCNTEN_SHIFT 26U
+
+#define SMB_CFG_MSTRRTRYCNT_MASK 0x000F0000U
+#define SMB_CFG_MSTRRTRYCNT_SHIFT 16U
+
+/* SMBUS Timing config register */
+#define SMB_TIMGCFG_REG 0x4U
+
+#define SMB_TIMGCFG_MODE400_MASK 0x80000000U
+#define SMB_TIMGCFG_MODE400_SHIFT 31U
+
+#define SMB_TIMGCFG_RNDSLVSTR_MASK 0x7F000000U
+#define SMB_TIMGCFG_RNDSLVSTR_SHIFT 24U
+
+#define SMB_TIMGCFG_PERSLVSTR_MASK 0x00FF0000U
+#define SMB_TIMGCFG_PERSLVSTR_SHIFT 16U
+
+#define SMB_TIMGCFG_IDLTIME_MASK 0x0000FF00U
+#define SMB_TIMGCFG_IDLTIME_SHIFT 8U
+
+/* SMBUS Slave address register */
+#define SMB_ADDR_REG 0x8U
+
+#define SMB_EN_NIC_SMBADDR3_MASK 0x80000000U
+#define SMB_EN_NIC_SMBADDR3_SHIFT 31U
+
+#define SMB_NIC_SMBADDR3_MASK 0x7F000000U
+#define SMB_NIC_SMBADDR3_SHIFT 24U
+
+#define SMB_EN_NIC_SMBADDR2_MASK 0x00800000U
+#define SMB_EN_NIC_SMBADDR2_SHIFT 23U
+
+#define SMB_NIC_SMBADDR2_MASK 0x007F0000U
+#define SMB_NIC_SMBADDR2_SHIFT 16U
+
+#define SMB_EN_NIC_SMBADDR1_MASK 0x00008000U
+#define SMB_EN_NIC_SMBADDR1_SHIFT 15U
+
+#define SMB_NIC_SMBADDR1_MASK 0x00007F00U
+#define SMB_NIC_SMBADDR1_SHIFT 8U
+
+#define SMB_EN_NIC_SMBADDR0_MASK 0x00000080U
+#define SMB_EN_NIC_SMBADDR0_SHIFT 7U
+
+#define SMB_NIC_SMBADDR0_MASK 0x0000007FU
+#define SMB_NIC_SMBADDR0_SHIFT 0U
+
+/* SMBUS Master FIFO control register */
+#define SMB_MSTRFIFOCTL_REG 0xCU
+
+#define SMB_MSTRRXFIFOFLSH_MASK 0x80000000U
+#define SMB_MSTRRXFIFOFLSH_SHIFT 31U
+
+#define SMB_MSTRTXFIFOFLSH_MASK 0x40000000U
+#define SMB_MSTRTXFIFOFLSH_SHIFT 30U
+
+#define SMB_MSTRRXPKTCNT_MASK 0x007F0000U
+#define SMB_MSTRRXPKTCNT_SHIFT 16U
+
+#define SMB_MSTRRXFIFOTHR_MASK 0x00003F00U
+#define SMB_MSTRRXFIFOTHR_SHIFT 8U
+
+/* SMBUS Slave FIFO control register */
+#define SMB_SLVFIFOCTL_REG 0x10U
+
+#define SMB_SLVRXFIFOFLSH_MASK 0x80000000U
+#define SMB_SLVRXFIFOFLSH_SHIFT 31U
+
+#define SMB_SLVTXFIFOFLSH_MASK 0x40000000U
+#define SMB_SLVTXFIFOFLSH_SHIFT 30U
+
+#define SMB_SLVRXPKTCNT_MASK 0x007F0000U
+#define SMB_SLVRXPKTCNT_SHIFT 16U
+
+#define SMB_SLVRXFIFOTHR_MASK 0x00003F00U
+#define SMB_SLVRXFIFOTHR_SHIFT 8U
+
+/* SMBUS Bit-bang mode control register */
+#define SMB_BITBANGCTL_REG 0x14U
+
+#define SMB_SMBCLKIN_MASK 0x80000000U
+#define SMB_SMBCLKIN_SHIFT 31U
+
+#define SMB_SMBCLKOUTEN_MASK 0x40000000U
+#define SMB_SMBCLKOUTEN_SHIFT 30U
+
+#define SMB_SMBDATAIN_MASK 0x20000000U
+#define SMB_SMBDATAIN_SHIFT 29U
+
+#define SMB_SMBDATAOUTEN_MASK 0x10000000U
+#define SMB_SMBDATAOUTEN_SHIFT 28U
+
+/* SMBUS Master command register */
+#define SMB_MSTRCMD_REG 0x30U
+
+#define SMB_MSTRSTARTBUSYCMD_MASK 0x80000000U
+#define SMB_MSTRSTARTBUSYCMD_SHIFT 31U
+
+#define SMB_MSTRABORT_MASK 0x40000000U
+#define SMB_MSTRABORT_SHIFT 30U
+
+#define SMB_MSTRSTS_MASK 0x0E000000U
+#define SMB_MSTRSTS_SHIFT 25U
+
+#define SMB_MSTRSMBUSPROTO_MASK 0x00001E00U
+#define SMB_MSTRSMBUSPROTO_SHIFT 9U
+
+#define SMB_MSTRPEC_MASK 0x00000100U
+#define SMB_MSTRPEC_SHIFT 8U
+
+#define SMB_MSTRRDBYTECNT_MASK 0x000000FFU
+#define SMB_MSTRRDBYTECNT_SHIFT 0U
+
+/* SMBUS Slave command register */
+#define SMB_SLVCMD_REG 0x34U
+
+#define SMB_SLVSTARTBUSYCMD_MASK 0x80000000U
+#define SMB_SLVSTARTBUSYCMD_SHIFT 31U
+
+#define SMB_SLVABORT_MASK 0x40000000U
+#define SMB_SLVABORT_SHIFT 30U
+
+#define SMB_SLVSTS_MASK 0x03800000U
+#define SMB_SLVSTS_SHIFT 23U
+
+#define SMB_SLVPEC_MASK 0x00000100U
+#define SMB_SLVPEC_SHIFT 8U
+
+/* SMBUS Event enable register */
+#define SMB_EVTEN_REG 0x38U
+
+#define SMB_MSTRRXFIFOFULLEN_MASK 0x80000000U
+#define SMB_MSTRRXFIFOFULLEN_SHIFT 31U
+
+#define SMB_MSTRRXFIFOTHRHITEN_MASK 0x40000000U
+#define SMB_MSTRRXFIFOTHRHITEN_SHIFT 30U
+
+#define SMB_MSTRRXEVTEN_MASK 0x20000000U
+#define SMB_MSTRRXEVTEN_SHIFT 29U
+
+#define SMB_MSTRSTARTBUSYEN_MASK 0x10000000U
+#define SMB_MSTRSTARTBUSYEN_SHIFT 28U
+
+#define SMB_MSTRTXUNDEN_MASK 0x08000000U
+#define SMB_MSTRTXUNDEN_SHIFT 27U
+
+#define SMB_SLVRXFIFOFULLEN_MASK 0x04000000U
+#define SMB_SLVRXFIFOFULLEN_SHIFT 26U
+
+#define SMB_SLVRXFIFOTHRHITEN_MASK 0x02000000U
+#define SMB_SLVRXFIFOTHRHITEN_SHIFT 25U
+
+#define SMB_SLVRXEVTEN_MASK 0x01000000U
+#define SMB_SLVRXEVTEN_SHIFT 24U
+
+#define SMB_SLVSTARTBUSYEN_MASK 0x00800000U
+#define SMB_SLVSTARTBUSYEN_SHIFT 23U
+
+#define SMB_SLVTXUNDEN_MASK 0x00400000U
+#define SMB_SLVTXUNDEN_SHIFT 22U
+
+#define SMB_SLVRDEVTEN_MASK 0x00200000U
+#define SMB_SLVRDEVTEN_SHIFT 21U
+
+/* SMBUS Event status register */
+#define SMB_EVTSTS_REG 0x3CU
+
+#define SMB_MSTRRXFIFOFULLSTS_MASK 0x80000000U
+#define SMB_MSTRRXFIFOFULLSTS_SHIFT 31U
+
+#define SMB_MSTRRXFIFOTHRHITSTS_MASK 0x40000000U
+#define SMB_MSTRRXFIFOTHRHITSTS_SHIFT 30U
+
+#define SMB_MSTRRXEVTSTS_MASK 0x20000000U
+#define SMB_MSTRRXEVTSTS_SHIFT 29U
+
+#define SMB_MSTRSTARTBUSYSTS_MASK 0x10000000U
+#define SMB_MSTRSTARTBUSYSTS_SHIFT 28U
+
+#define SMB_MSTRTXUNDSTS_MASK 0x08000000U
+#define SMB_MSTRTXUNDSTS_SHIFT 27U
+
+#define SMB_SLVRXFIFOFULLSTS_MASK 0x04000000U
+#define SMB_SLVRXFIFOFULLSTS_SHIFT 26U
+
+#define SMB_SLVRXFIFOTHRHITSTS_MASK 0x02000000U
+#define SMB_SLVRXFIFOTHRHITSTS_SHIFT 25U
+
+#define SMB_SLVRXEVTSTS_MASK 0x01000000U
+#define SMB_SLVRXEVTSTS_SHIFT 24U
+
+#define SMB_SLVSTARTBUSYSTS_MASK 0x00800000U
+#define SMB_SLVSTARTBUSYSTS_SHIFT 23U
+
+#define SMB_SLVTXUNDSTS_MASK 0x00400000U
+#define SMB_SLVTXUNDSTS_SHIFT 22U
+
+#define SMB_SLVRDEVTSTS_MASK 0x00200000U
+#define SMB_SLVRDEVTSTS_SHIFT 21U
+
+/* SMBUS Master data write register */
+#define SMB_MSTRDATAWR_REG 0x40U
+
+#define SMB_MSTRWRSTS_MASK 0x80000000U
+#define SMB_MSTRWRSTS_SHIFT 31U
+
+#define SMB_MSTRWRDATA_MASK 0x000000FFU
+#define SMB_MSTRWRDATA_SHIFT 0U
+
+/* SMBUS Master data read register */
+#define SMB_MSTRDATARD_REG 0x44U
+
+#define SMB_MSTRRDSTS_MASK 0xC0000000U
+#define SMB_MSTRRDSTS_SHIFT 30U
+
+#define SMB_MSTRRDPECERR_MASK 0x20000000U
+#define SMB_MSTRRDPECERR_SHIFT 29U
+
+#define SMB_MSTRRDDATA_MASK 0x000000FFU
+#define SMB_MSTRRDDATA_SHIFT 0U
+
+/* SMBUS Slave data write register */
+#define SMB_SLVDATAWR_REG 0x48U
+
+#define SMB_SLVWRSTS_MASK 0x80000000U
+#define SMB_SLVWRSTS_SHIFT 31U
+
+#define SMB_SLVWRDATA_MASK 0x000000FFU
+#define SMB_SLVWRDATA_SHIFT 0U
+
+/* SMBUS Slave data read register */
+#define SMB_SLVDATARD_REG 0x4CU
+
+#define SMB_SLVRDSTS_MASK 0xC0000000U
+#define SMB_SLVRDSTS_SHIFT 30U
+
+#define SMB_SLVRDERRSTS_MASK 0x30000000U
+#define SMB_SLVRDERRSTS_SHIFT 28U
+
+#define SMB_SLVRDDATA_MASK 0x000000FFU
+#define SMB_SLVRDDATA_SHIFT 0U
+
+#endif /* I2C_REGS */
diff --git a/include/drivers/brcm/iproc_gpio.h b/include/drivers/brcm/iproc_gpio.h
new file mode 100644
index 0000000..be971f6
--- /dev/null
+++ b/include/drivers/brcm/iproc_gpio.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IPROC_GPIO_H
+#define IPROC_GPIO_H
+
+#ifdef USE_GPIO
+void iproc_gpio_init(uintptr_t base, int nr_gpios, uintptr_t pinmux_base,
+ uintptr_t pinconf_base);
+#else
+static void iproc_gpio_init(uintptr_t base, int nr_gpios, uintptr_t pinmux_base,
+ uintptr_t pinconf_base)
+{
+}
+#endif /* IPROC_GPIO */
+
+#endif /* IPROC_GPIO_H */
diff --git a/include/drivers/brcm/mdio/mdio.h b/include/drivers/brcm/mdio/mdio.h
new file mode 100644
index 0000000..b27c7b3
--- /dev/null
+++ b/include/drivers/brcm/mdio/mdio.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016 - 2021, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MDIO_H
+#define MDIO_H
+
+#define CMIC_MIIM_PARAM (PLAT_CMIC_MIIM_BASE + 0x23cU)
+#define MDIO_PARAM_MIIM_CYCLE 29U
+#define MDIO_PARAM_INTERNAL_SEL 25U
+#define MDIO_PARAM_BUSID 22U
+#define MDIO_PARAM_BUSID_MASK 0x7U
+#define MDIO_PARAM_C45_SEL 21U
+#define MDIO_PARAM_PHYID 16U
+#define MDIO_PARAM_PHYID_MASK 0x1FU
+#define MDIO_PARAM_DATA 0U
+#define MDIO_PARAM_DATA_MASK 0xFFFFU
+#define CMIC_MIIM_READ_DATA (PLAT_CMIC_MIIM_BASE + 0x240U)
+#define MDIO_READ_DATA_MASK 0xffffU
+#define CMIC_MIIM_ADDRESS (PLAT_CMIC_MIIM_BASE + 0x244U)
+#define CMIC_MIIM_CTRL (PLAT_CMIC_MIIM_BASE + 0x248U)
+#define MDIO_CTRL_WRITE_OP 0x1U
+#define MDIO_CTRL_READ_OP 0x2U
+#define CMIC_MIIM_STAT (PLAT_CMIC_MIIM_BASE + 0x24cU)
+#define MDIO_STAT_DONE 1U
+
+int mdio_write(uint16_t busid, uint16_t phyid, uint32_t reg, uint16_t val);
+int mdio_read(uint16_t busid, uint16_t phyid, uint32_t reg);
+#endif /* MDIO_H */
diff --git a/include/drivers/brcm/ocotp.h b/include/drivers/brcm/ocotp.h
new file mode 100644
index 0000000..830b3e4
--- /dev/null
+++ b/include/drivers/brcm/ocotp.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef OCOTP_H
+#define OCOTP_H
+
+#include <stdint.h>
+
+struct otpc_map {
+ /* in words. */
+ uint32_t otpc_row_size;
+ /* 128 bit row / 4 words support. */
+ uint16_t data_r_offset[4];
+ /* 128 bit row / 4 words support. */
+ uint16_t data_w_offset[4];
+ int word_size;
+ int stride;
+};
+
+int bcm_otpc_init(struct otpc_map *map);
+int bcm_otpc_read(unsigned int offset, void *val, uint32_t bytes,
+ uint32_t ecc_flag);
+
+#endif /* OCOTP_H */
diff --git a/include/drivers/brcm/scp.h b/include/drivers/brcm/scp.h
new file mode 100644
index 0000000..7806314
--- /dev/null
+++ b/include/drivers/brcm/scp.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SCP_H
+#define SCP_H
+
+#include <stdint.h>
+
+int download_scp_patch(void *image, unsigned int image_size);
+
+#endif /* SCP_H */
diff --git a/include/drivers/brcm/sf.h b/include/drivers/brcm/sf.h
new file mode 100644
index 0000000..c32cbeb
--- /dev/null
+++ b/include/drivers/brcm/sf.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SF_H
+#define SF_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#ifdef SPI_DEBUG
+#define SPI_DEBUG(fmt, ...) INFO(fmt, ##__VA_ARGS__)
+#else
+#define SPI_DEBUG(fmt, ...)
+#endif
+
+#define SPI_FLASH_MAX_ID_LEN 6
+
+#define CMD_WRSR 0x01 /* Write status register */
+#define CMD_PAGE_PROGRAM 0x02
+#define CMD_READ_NORMAL 0x03
+#define CMD_RDSR 0x05
+#define CMD_WRITE_ENABLE 0x06
+#define CMD_RDFSR 0x70
+#define CMD_READ_ID 0x9f
+#define CMD_ERASE_4K 0x20
+#define CMD_ERASE_64K 0xd8
+#define ERASE_SIZE_64K (64 * 1024)
+
+/* Common status */
+#define STATUS_WIP BIT(0)
+
+struct spi_flash {
+ struct spi_slave *spi;
+ uint32_t size;
+ uint32_t page_size;
+ uint32_t sector_size;
+ uint32_t erase_size;
+ uint8_t erase_cmd;
+ uint8_t read_cmd;
+ uint8_t write_cmd;
+ uint8_t flags;
+};
+
+struct spi_flash_info {
+ const char *name;
+
+ /*
+ * This array stores the ID bytes.
+ * The first three bytes are the JEDIC ID.
+ * JEDEC ID zero means "no ID" (mostly older chips).
+ */
+ uint8_t id[SPI_FLASH_MAX_ID_LEN];
+ uint8_t id_len;
+
+ uint32_t sector_size;
+ uint32_t n_sectors;
+ uint16_t page_size;
+
+ uint8_t flags;
+};
+
+/* Enum list - Full read commands */
+enum spi_read_cmds {
+ ARRAY_SLOW = BIT(0),
+ ARRAY_FAST = BIT(1),
+ DUAL_OUTPUT_FAST = BIT(2),
+ DUAL_IO_FAST = BIT(3),
+ QUAD_OUTPUT_FAST = BIT(4),
+ QUAD_IO_FAST = BIT(5),
+};
+
+/* sf param flags */
+enum spi_param_flag {
+ SECT_4K = BIT(0),
+ SECT_32K = BIT(1),
+ E_FSR = BIT(2),
+ SST_BP = BIT(3),
+ SST_WP = BIT(4),
+ WR_QPP = BIT(5),
+};
+
+int spi_flash_cmd_read(const uint8_t *cmd, size_t cmd_len,
+ void *data, size_t data_len);
+int spi_flash_cmd(uint8_t cmd, void *response, size_t len);
+int spi_flash_cmd_write(const uint8_t *cmd, size_t cmd_len,
+ const void *data, size_t data_len);
+#endif
diff --git a/include/drivers/brcm/sotp.h b/include/drivers/brcm/sotp.h
new file mode 100644
index 0000000..a93d687
--- /dev/null
+++ b/include/drivers/brcm/sotp.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOTP_H
+#define SOTP_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <platform_sotp.h>
+
+#define SOTP_ROW_NO_ECC 0
+#define SOTP_ROW_ECC 1
+
+#define SOTP_STATUS_1 (SOTP_REGS_OTP_BASE + 0x001c)
+#define SOTP_FAIL_BITS 0x18000000000
+#define SOTP_ECC_ERR_DETECT 0x8000000000000000
+
+#define SOTP_REGS_SOTP_CHIP_STATES (SOTP_REGS_OTP_BASE + 0x0028)
+#define SOTP_REGS_OTP_WR_LOCK (SOTP_REGS_OTP_BASE + 0x0038)
+
+#define SOTP_CHIP_STATES_MANU_DEBUG_MASK (1 << 8)
+#define SOTP_DEVICE_SECURE_CFG0_OTP_ERASED_MASK (3 << 16)
+#define SOTP_REGS_SOTP_CHIP_STATES_OTP_ERASED_MASK (1 << 16)
+
+#define SOTP_DEVICE_SECURE_CFG0_CID_MASK (3 << 2)
+#define SOTP_DEVICE_SECURE_CFG0_AB_MASK (3 << 6)
+#define SOTP_DEVICE_SECURE_CFG0_DEV_MASK (3 << 8)
+
+#define SOTP_BOOT_SOURCE_SHIFT 8
+/* bits 14 and 15 */
+#define SOTP_BOOT_SOURCE_ENABLE_MASK (0xC0 << SOTP_BOOT_SOURCE_SHIFT)
+/* bits 8 to 13 */
+#define SOTP_BOOT_SOURCE_BITS0 (0x03 << SOTP_BOOT_SOURCE_SHIFT)
+#define SOTP_BOOT_SOURCE_BITS1 (0x0C << SOTP_BOOT_SOURCE_SHIFT)
+#define SOTP_BOOT_SOURCE_BITS2 (0x30 << SOTP_BOOT_SOURCE_SHIFT)
+#define SOTP_BOOT_SOURCE_MASK (0x3F << SOTP_BOOT_SOURCE_SHIFT)
+
+#define SOTP_ATF_CFG_ROW_ID SOTP_DEVICE_SECURE_CFG2_ROW
+/* bits 28 and 29 */
+#define SOTP_SBL_MASK (3 << 28)
+/* bits 30 and 31 */
+#define SOTP_ATF_NVCOUNTER_ENABLE_MASK ((uint64_t)3 << 30)
+/* bits 32 and 33 */
+#define SOTP_ATF_WATCHDOG_ENABLE_MASK ((uint64_t)3 << 32)
+/* bits 34 and 35 */
+#define SOTP_ATF_PLL_ON ((uint64_t)3 << 34)
+/* bits 36 and 37 */
+#define SOTP_ATF_RESET_RETRY ((uint64_t)3 << 36)
+/* bits 38 to 40 */
+#define SOTP_ATF_LOG_LEVEL_SHIFT 38
+#define SOTP_ATF_LOG_LEVEL ((uint64_t)7 << SOTP_ATF_LOG_LEVEL_SHIFT)
+
+#define SOTP_ATF2_CFG_ROW_ID SOTP_DEVICE_SECURE_CFG3_ROW
+/* bits 16 and 17 */
+#define SOTP_ROMKEY_MASK (3 << 16)
+/* bits 18 and 19 */
+#define SOTP_EC_EN_MASK (3 << 18)
+
+#define SOTP_ENC_DEV_TYPE_AB_DEV ((uint64_t)0x19999800000)
+#define SOTP_ENC_DEV_TYPE_MASK ((uint64_t)0x1ffff800000)
+
+uint64_t sotp_mem_read(uint32_t offset, uint32_t sotp_add_ecc);
+void sotp_mem_write(uint32_t addr, uint32_t sotp_add_ecc, uint64_t wdata);
+int sotp_read_key(uint8_t *key, size_t keysize, int start_row, int end_row);
+int sotp_key_erased(void);
+uint32_t sotp_redundancy_reduction(uint32_t sotp_row_data);
+#endif
diff --git a/include/drivers/brcm/spi.h b/include/drivers/brcm/spi.h
new file mode 100644
index 0000000..9d92d8c
--- /dev/null
+++ b/include/drivers/brcm/spi.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPI_H
+#define SPI_H
+
+#include <stdint.h>
+
+#define SPI_XFER_BEGIN (1 << 0) /* Assert CS before transfer */
+#define SPI_XFER_END (1 << 1) /* De-assert CS after transfer */
+#define SPI_XFER_QUAD (1 << 2)
+
+int spi_init(void);
+int spi_claim_bus(void);
+void spi_release_bus(void);
+int spi_xfer(uint32_t bitlen, const void *dout, void *din, uint32_t flags);
+
+#endif /* _SPI_H_ */
diff --git a/include/drivers/brcm/spi_flash.h b/include/drivers/brcm/spi_flash.h
new file mode 100644
index 0000000..bbaaa50
--- /dev/null
+++ b/include/drivers/brcm/spi_flash.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPI_FLASH_H
+#define SPI_FLASH_H
+
+#include <sf.h>
+
+int spi_flash_probe(struct spi_flash *flash);
+int spi_flash_erase(struct spi_flash *flash, uint32_t offset, uint32_t len);
+int spi_flash_write(struct spi_flash *flash, uint32_t offset,
+ uint32_t len, void *buf);
+int spi_flash_read(struct spi_flash *flash, uint32_t offset,
+ uint32_t len, void *data);
+#endif /* _SPI_FLASH_H_ */
diff --git a/include/drivers/brcm/usbh_xhci_regs.h b/include/drivers/brcm/usbh_xhci_regs.h
new file mode 100644
index 0000000..93dec7b
--- /dev/null
+++ b/include/drivers/brcm/usbh_xhci_regs.h
@@ -0,0 +1,4809 @@
+/*
+ * Copyright (c) 2017 - 2021, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#ifndef USBH_XHCI_REGS_H
+#define USBH_XHCI_REGS_H
+
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#define XHCI_LEN (8096U)
+
+#define XHC_CPLIVER_OFFSET 0x000U
+#define XHC_SPARAMS1_OFFSET 0x004U
+#define XHC_SPARAMS2_OFFSET 0x008U
+#define XHC_SPARAMS3_OFFSET 0x00cU
+#define XHC_CPARAMS1_OFFSET 0x010U
+#define XHC_DBOFF_OFFSET 0x014U
+#define XHC_RTOFF_OFFSET 0x018U
+#define XHC_CPARAMS2_OFFSET 0x01cU
+#define XHC_USBCMD_OFFSET 0x020U
+#define XHC_USBSTS_OFFSET 0x024U
+#define XHC_PAGESIZE_OFFSET 0x028U
+#define XHC_DNCTRL_OFFSET 0x034U
+#define XHC_CRCRL_OFFSET 0x038U
+#define XHC_CRCRH_OFFSET 0x03cU
+#define XHC_DCBAAPL_OFFSET 0x050U
+#define XHC_DCBAAPH_OFFSET 0x054U
+#define XHC_CONFIG_OFFSET 0x058U
+#define XHC_PORTSC1_OFFSET 0x420U
+#define XHC_PORTPM1_OFFSET 0x424U
+#define XHC_PORTLC1_OFFSET 0x428U
+#define XHC_PORTSC2_OFFSET 0x430U
+#define XHC_PORTPM2_OFFSET 0x434U
+#define XHC_PORTLC2_OFFSET 0x43cU
+#define XHC_PORTSC3_OFFSET 0x440U
+#define XHC_PORTPM3_OFFSET 0x444U
+#define XHC_PORTLI3_OFFSET 0x44cU
+#define XHC_MFINDEX_OFFSET 0x4a0U
+#define XHC_IMAN0_OFFSET 0x4c0U
+#define XHC_IMOD0_OFFSET 0x4c4U
+#define XHC_ERSTSZ0_OFFSET 0x4c8U
+#define XHC_ERSTBAL0_OFFSET 0x4d0U
+#define XHC_ERSTBAH0_OFFSET 0x4d4U
+#define XHC_ERDPL0_OFFSET 0x4d8U
+#define XHC_ERDPH0_OFFSET 0x4dcU
+#define XHC_IMAN1_OFFSET 0x4e0U
+#define XHC_IMOD1_OFFSET 0x4e4U
+#define XHC_ERSTSZ1_OFFSET 0x4e8U
+#define XHC_ERSTBAL1_OFFSET 0x4f0U
+#define XHC_ERSTBAH1_OFFSET 0x4f4U
+#define XHC_ERDPL1_OFFSET 0x4f8U
+#define XHC_ERDPH1_OFFSET 0x4fcU
+#define XHC_DBLCMD_OFFSET 0x8c0U
+#define XHC_DBLDVX1_OFFSET 0x8c4U
+#define XHC_DBLDVX2_OFFSET 0x8c8U
+#define XHC_DBLDVX3_OFFSET 0x8ccU
+#define XHC_DBLDVX4_OFFSET 0x8d0U
+#define XHC_DBLDVX5_OFFSET 0x8d4U
+#define XHC_DBLDVX6_OFFSET 0x8d8U
+#define XHC_DBLDVX7_OFFSET 0x8dcU
+#define XHC_DBLDVX8_OFFSET 0x8e0U
+#define XHC_DBLDVX9_OFFSET 0x8e4U
+#define XHC_DBLDVX10_OFFSET 0x8e8U
+#define XHC_DBLDVX11_OFFSET 0x8ecU
+#define XHC_DBLDVX12_OFFSET 0x8f0U
+#define XHC_DBLDVX13_OFFSET 0x8f4U
+#define XHC_DBLDVX14_OFFSET 0x8f8U
+#define XHC_DBLDVX15_OFFSET 0x8fcU
+#define XHC_DBLDVX16_OFFSET 0x900U
+#define XHC_ECHSPT3_OFFSET 0x940U
+#define XHC_PNSTR3_OFFSET 0x944U
+#define XHC_PSUM3_OFFSET 0x948U
+#define XHC_PTSLTYP3_OFFSET 0x94cU
+#define XHC_ECHSPT2_OFFSET 0x950U
+#define XHC_PNSTR2_OFFSET 0x954U
+#define XHC_PSUM2_OFFSET 0x958U
+#define XHC_PTSLTYP2_OFFSET 0x95cU
+#define XHC_ECHRSVP_OFFSET 0x960U
+#define XHC_ECHRSVI_OFFSET 0x968U
+#define XHC_ECHRSVM_OFFSET 0xae8U
+#define XHC_ECHRSVD_OFFSET 0xaf8U
+#define XHC_ECHRSVO_OFFSET 0xb38U
+#define XHC_ECHCTT_OFFSET 0xbf0U
+#define XHC_CTTMTS0_OFFSET 0xbf8U
+#define XHC_CTTMTS1_OFFSET 0xbfcU
+#define XHC_ECHBIU_OFFSET 0xc00U
+#define XHC_BIUSPC_OFFSET 0xc04U
+#define XHC_AXIWRA_OFFSET 0xc08U
+#define XHC_AXIRDA_OFFSET 0xc0cU
+#define XHC_AXILPM_OFFSET 0xc10U
+#define XHC_AXIQOS_OFFSET 0xc14U
+#define XHC_ECHCSR_OFFSET 0xc20U
+#define XHC_CSRSPC_OFFSET 0xc24U
+#define XHC_ECHAIU_OFFSET 0xc30U
+#define XHC_AIUDMA_OFFSET 0xc34U
+#define XHC_AIUFLA_OFFSET 0xc38U
+#define XHC_AIUCFG_OFFSET 0xc3cU
+#define XHC_ECHFSC_OFFSET 0xc40U
+#define XHC_FSCPOC_OFFSET 0xc54U
+#define XHC_FSCGOC_OFFSET 0xc58U
+#define XHC_FSCNOC_OFFSET 0xc5cU
+#define XHC_FSCAIC_OFFSET 0xc60U
+#define XHC_FSCPIC_OFFSET 0xc64U
+#define XHC_FSCGIC_OFFSET 0xc68U
+#define XHC_FSCNIC_OFFSET 0xc6cU
+#define XHC_ECHPRT_OFFSET 0xc70U
+#define XHC_PRTHSC_OFFSET 0xc78U
+#define XHC_PRTHSR_OFFSET 0xc7cU
+#define XHC_ECHRHS_OFFSET 0xc80U
+#define XHC_RHSDES_OFFSET 0xc84U
+#define XHC_RHSHSC0_OFFSET 0xc90U
+#define XHC_RHSHSR0_OFFSET 0xc94U
+#define XHC_RHSHSC1_OFFSET 0xc98U
+#define XHC_RHSHSR1_OFFSET 0xc9cU
+#define XHC_RHSHSC2_OFFSET 0xca0U
+#define XHC_RHSHSR2_OFFSET 0xca4U
+#define XHC_RHSHSC3_OFFSET 0xca8U
+#define XHC_RHSHSR3_OFFSET 0xcacU
+#define XHC_ECHSSP_OFFSET 0xcb0U
+#define XHC_SSPVER_OFFSET 0xcb4U
+#define XHC_SSPMGN_OFFSET 0xcb8U
+#define XHC_ECHFSC2_OFFSET 0xcc0U
+#define XHC_FSC2POC_OFFSET 0xcd4U
+#define XHC_FSC2GOC_OFFSET 0xcd8U
+#define XHC_FSC2NOC_OFFSET 0xcdcU
+#define XHC_FSC2AIC_OFFSET 0xce0U
+#define XHC_FSC2PIC_OFFSET 0xce4U
+#define XHC_FSC2GIC_OFFSET 0xce8U
+#define XHC_FSC2NIC_OFFSET 0xcecU
+#define XHC_ECHPRT2_OFFSET 0xcf0U
+#define XHC_PRT2HSC_OFFSET 0xcf8U
+#define XHC_PRT2HSR_OFFSET 0xcfcU
+#define XHC_ECHRH2_OFFSET 0xd00U
+#define XHC_RH2DES_OFFSET 0xd04U
+#define XHC_RH2HSC0_OFFSET 0xd10U
+#define XHC_RH2HSR0_OFFSET 0xd14U
+#define XHC_RH2HSC1_OFFSET 0xd18U
+#define XHC_RH2HSR1_OFFSET 0xd1cU
+#define XHC_RH2HSC2_OFFSET 0xd20U
+#define XHC_RH2HSR2_OFFSET 0xd24U
+#define XHC_RH2HSC3_OFFSET 0xd28U
+#define XHC_RH2HSR3_OFFSET 0xd2cU
+#define XHC_ECHU2P_OFFSET 0xd30U
+#define XHC_U2PVER_OFFSET 0xd34U
+#define XHC_U2PMGN_OFFSET 0xd38U
+#define XHC_ECHRSV2_OFFSET 0xd40U
+#define XHC_ECHIRA_OFFSET 0xf90U
+#define XHC_IRAADR_OFFSET 0xf98U
+#define XHC_IRADAT_OFFSET 0xf9cU
+#define XHC_ECHHST_OFFSET 0xfa0U
+#define XHC_HSTDBG_OFFSET 0xfa4U
+#define XHC_HSTNPL_OFFSET 0xfa8U
+#define XHC_HSTNPH_OFFSET 0xfacU
+#define XHC_ECHRBV_OFFSET 0xfb0U
+#define XHC_RBVPDT_OFFSET 0xfb4U
+#define XHC_RBVMGN_OFFSET 0xfbcU
+
+#define XHC_CPLIVER_BASE 0x000U
+#define XHC_CPLIVER__IVH_L 31U
+#define XHC_CPLIVER__IVH_R 24U
+#define XHC_CPLIVER__IVH_WIDTH 8U
+#define XHC_CPLIVER__IVH_RESETVALUE 0x01U
+#define XHC_CPLIVER__IVL_L 23U
+#define XHC_CPLIVER__IVL_R 16U
+#define XHC_CPLIVER__IVL_WIDTH 8U
+#define XHC_CPLIVER__IVL_RESETVALUE 0x10U
+#define XHC_CPLIVER__reserved_L 15U
+#define XHC_CPLIVER__reserved_R 8U
+#define XHC_CPLIVER__reserved_WIDTH 8U
+#define XHC_CPLIVER__reserved_RESETVALUE 0x00U
+#define XHC_CPLIVER__CPL_L 7U
+#define XHC_CPLIVER__CPL_R 0U
+#define XHC_CPLIVER__CPL_WIDTH 8U
+#define XHC_CPLIVER__CPL_RESETVALUE 0x00U
+#define XHC_CPLIVER_WIDTH 32U
+#define XHC_CPLIVER__WIDTH 32U
+#define XHC_CPLIVER_ALL_L 31U
+#define XHC_CPLIVER_ALL_R 0U
+#define XHC_CPLIVER__ALL_L 31U
+#define XHC_CPLIVER__ALL_R 0U
+#define XHC_CPLIVER_DATAMASK 0xffffffffU
+#define XHC_CPLIVER_RDWRMASK 0x00000000U
+#define XHC_CPLIVER_RESETVALUE 0x01100000U
+
+#define XHC_SPARAMS1_OFFSET 0x004U
+#define XHC_SPARAMS1_BASE 0x004U
+#define XHC_SPARAMS1__NPTS_L 31U
+#define XHC_SPARAMS1__NPTS_R 24U
+#define XHC_SPARAMS1__NPTS_WIDTH 8U
+#define XHC_SPARAMS1__NPTS_RESETVALUE 0x00U
+#define XHC_SPARAMS1__reserved_L 23U
+#define XHC_SPARAMS1__reserved_R 19U
+#define XHC_SPARAMS1__reserved_WIDTH 5U
+#define XHC_SPARAMS1__reserved_RESETVALUE 0x0U
+#define XHC_SPARAMS1__MITS_L 18U
+#define XHC_SPARAMS1__MITS_R 8U
+#define XHC_SPARAMS1__MITS_WIDTH 11U
+#define XHC_SPARAMS1__MITS_RESETVALUE 0x1U
+#define XHC_SPARAMS1__MSLS_L 7U
+#define XHC_SPARAMS1__MSLS_R 0U
+#define XHC_SPARAMS1__MSLS_WIDTH 8U
+#define XHC_SPARAMS1__MSLS_RESETVALUE 0x00U
+#define XHC_SPARAMS1_WIDTH 32U
+#define XHC_SPARAMS1__WIDTH 32U
+#define XHC_SPARAMS1_ALL_L 31U
+#define XHC_SPARAMS1_ALL_R 0U
+#define XHC_SPARAMS1__ALL_L 31U
+#define XHC_SPARAMS1__ALL_R 0U
+#define XHC_SPARAMS1_DATAMASK 0xffffffffU
+#define XHC_SPARAMS1_RDWRMASK 0x00000000U
+#define XHC_SPARAMS1_RESETVALUE 0x00000100U
+
+#define XHC_SPARAMS2_OFFSET 0x008U
+#define XHC_SPARAMS2_BASE 0x008U
+#define XHC_SPARAMS2__MSPBSL_L 31U
+#define XHC_SPARAMS2__MSPBSL_R 27U
+#define XHC_SPARAMS2__MSPBSL_WIDTH 5U
+#define XHC_SPARAMS2__MSPBSL_RESETVALUE 0x0U
+#define XHC_SPARAMS2__SPR 26U
+#define XHC_SPARAMS2__SPR_L 26U
+#define XHC_SPARAMS2__SPR_R 26U
+#define XHC_SPARAMS2__SPR_WIDTH 1U
+#define XHC_SPARAMS2__SPR_RESETVALUE 0x1U
+#define XHC_SPARAMS2__MSPBSH_L 25U
+#define XHC_SPARAMS2__MSPBSH_R 21U
+#define XHC_SPARAMS2__MSPBSH_WIDTH 5U
+#define XHC_SPARAMS2__MSPBSH_RESETVALUE 0x0U
+#define XHC_SPARAMS2__reserved_L 20U
+#define XHC_SPARAMS2__reserved_R 8U
+#define XHC_SPARAMS2__reserved_WIDTH 13U
+#define XHC_SPARAMS2__reserved_RESETVALUE 0x0U
+#define XHC_SPARAMS2__MERST_L 7U
+#define XHC_SPARAMS2__MERST_R 4U
+#define XHC_SPARAMS2__MERST_WIDTH 4U
+#define XHC_SPARAMS2__MERST_RESETVALUE 0x0U
+#define XHC_SPARAMS2__IST_L 3U
+#define XHC_SPARAMS2__IST_R 0U
+#define XHC_SPARAMS2__IST_WIDTH 4U
+#define XHC_SPARAMS2__IST_RESETVALUE 0x0U
+#define XHC_SPARAMS2_WIDTH 32U
+#define XHC_SPARAMS2__WIDTH 32U
+#define XHC_SPARAMS2_ALL_L 31U
+#define XHC_SPARAMS2_ALL_R 0U
+#define XHC_SPARAMS2__ALL_L 31U
+#define XHC_SPARAMS2__ALL_R 0U
+#define XHC_SPARAMS2_DATAMASK 0xffffffffU
+#define XHC_SPARAMS2_RDWRMASK 0x00000000U
+#define XHC_SPARAMS2_RESETVALUE 0x04000000U
+
+#define XHC_SPARAMS3_OFFSET 0x00cU
+#define XHC_SPARAMS3_BASE 0x00cU
+#define XHC_SPARAMS3__U2L_L 31U
+#define XHC_SPARAMS3__U2L_R 16U
+#define XHC_SPARAMS3__U2L_WIDTH 16U
+#define XHC_SPARAMS3__U2L_RESETVALUE 0x0000U
+#define XHC_SPARAMS3__reserved_L 15U
+#define XHC_SPARAMS3__reserved_R 8U
+#define XHC_SPARAMS3__reserved_WIDTH 8U
+#define XHC_SPARAMS3__reserved_RESETVALUE 0x00U
+#define XHC_SPARAMS3__U1L_L 7U
+#define XHC_SPARAMS3__U1L_R 0U
+#define XHC_SPARAMS3__U1L_WIDTH 8U
+#define XHC_SPARAMS3__U1L_RESETVALUE 0x00U
+#define XHC_SPARAMS3_WIDTH 32U
+#define XHC_SPARAMS3__WIDTH 32U
+#define XHC_SPARAMS3_ALL_L 31U
+#define XHC_SPARAMS3_ALL_R 0U
+#define XHC_SPARAMS3__ALL_L 31U
+#define XHC_SPARAMS3__ALL_R 0U
+#define XHC_SPARAMS3_DATAMASK 0xffffffffU
+#define XHC_SPARAMS3_RDWRMASK 0x00000000U
+#define XHC_SPARAMS3_RESETVALUE 0x00000000U
+
+#define XHC_CPARAMS1_OFFSET 0x010U
+#define XHC_CPARAMS1_BASE 0x010U
+#define XHC_CPARAMS1__XECP_L 31U
+#define XHC_CPARAMS1__XECP_R 16U
+#define XHC_CPARAMS1__XECP_WIDTH 16U
+#define XHC_CPARAMS1__XECP_RESETVALUE 0x0000U
+#define XHC_CPARAMS1__MPSA_L 15U
+#define XHC_CPARAMS1__MPSA_R 12U
+#define XHC_CPARAMS1__MPSA_WIDTH 4U
+#define XHC_CPARAMS1__MPSA_RESETVALUE 0x0U
+#define XHC_CPARAMS1__CFC 11U
+#define XHC_CPARAMS1__CFC_L 11U
+#define XHC_CPARAMS1__CFC_R 11U
+#define XHC_CPARAMS1__CFC_WIDTH 1U
+#define XHC_CPARAMS1__CFC_RESETVALUE 0x0U
+#define XHC_CPARAMS1__SEC 10U
+#define XHC_CPARAMS1__SEC_L 10U
+#define XHC_CPARAMS1__SEC_R 10U
+#define XHC_CPARAMS1__SEC_WIDTH 1U
+#define XHC_CPARAMS1__SEC_RESETVALUE 0x0U
+#define XHC_CPARAMS1__SPC 9U
+#define XHC_CPARAMS1__SPC_L 9U
+#define XHC_CPARAMS1__SPC_R 9U
+#define XHC_CPARAMS1__SPC_WIDTH 1U
+#define XHC_CPARAMS1__SPC_RESETVALUE 0x0U
+#define XHC_CPARAMS1__PAE 8U
+#define XHC_CPARAMS1__PAE_L 8U
+#define XHC_CPARAMS1__PAE_R 8U
+#define XHC_CPARAMS1__PAE_WIDTH 1U
+#define XHC_CPARAMS1__PAE_RESETVALUE 0x1U
+#define XHC_CPARAMS1__NSS 7U
+#define XHC_CPARAMS1__NSS_L 7U
+#define XHC_CPARAMS1__NSS_R 7U
+#define XHC_CPARAMS1__NSS_WIDTH 1U
+#define XHC_CPARAMS1__NSS_RESETVALUE 0x0U
+#define XHC_CPARAMS1__LTC 6U
+#define XHC_CPARAMS1__LTC_L 6U
+#define XHC_CPARAMS1__LTC_R 6U
+#define XHC_CPARAMS1__LTC_WIDTH 1U
+#define XHC_CPARAMS1__LTC_RESETVALUE 0x1U
+#define XHC_CPARAMS1__LRC 5U
+#define XHC_CPARAMS1__LRC_L 5U
+#define XHC_CPARAMS1__LRC_R 5U
+#define XHC_CPARAMS1__LRC_WIDTH 1U
+#define XHC_CPARAMS1__LRC_RESETVALUE 0x0U
+#define XHC_CPARAMS1__PIND 4U
+#define XHC_CPARAMS1__PIND_L 4U
+#define XHC_CPARAMS1__PIND_R 4U
+#define XHC_CPARAMS1__PIND_WIDTH 1U
+#define XHC_CPARAMS1__PIND_RESETVALUE 0x0U
+
+#define XHC_CPARAMS1__PPC_L 3U
+#define XHC_CPARAMS1__PPC_R 3U
+#define XHC_CPARAMS1__PPC_WIDTH 1U
+#define XHC_CPARAMS1__PPC_RESETVALUE 0x0U
+#define XHC_CPARAMS1__CSZ 2U
+#define XHC_CPARAMS1__CSZ_L 2U
+#define XHC_CPARAMS1__CSZ_R 2U
+#define XHC_CPARAMS1__CSZ_WIDTH 1U
+#define XHC_CPARAMS1__CSZ_RESETVALUE 0x1U
+#define XHC_CPARAMS1__BNC 1U
+#define XHC_CPARAMS1__BNC_L 1U
+#define XHC_CPARAMS1__BNC_R 1U
+#define XHC_CPARAMS1__BNC_WIDTH 1U
+#define XHC_CPARAMS1__BNC_RESETVALUE 0x0U
+#define XHC_CPARAMS1__AC64 0U
+#define XHC_CPARAMS1__AC64_L 0U
+#define XHC_CPARAMS1__AC64_R 0U
+#define XHC_CPARAMS1__AC64_WIDTH 1U
+#define XHC_CPARAMS1__AC64_RESETVALUE 0x0U
+#define XHC_CPARAMS1_WIDTH 32U
+#define XHC_CPARAMS1__WIDTH 32U
+#define XHC_CPARAMS1_ALL_L 31U
+#define XHC_CPARAMS1_ALL_R 0U
+#define XHC_CPARAMS1__ALL_L 31U
+#define XHC_CPARAMS1__ALL_R 0U
+#define XHC_CPARAMS1_DATAMASK 0xffffffffU
+#define XHC_CPARAMS1_RDWRMASK 0x00000000U
+#define XHC_CPARAMS1_RESETVALUE 0x00000144U
+
+#define XHC_DBOFF_OFFSET 0x014U
+#define XHC_DBOFF_BASE 0x014U
+#define XHC_DBOFF__DBO_L 15U
+#define XHC_DBOFF__DBO_R 2U
+#define XHC_DBOFF__DBO_WIDTH 14U
+#define XHC_DBOFF__DBO_RESETVALUE 0x0U
+#define XHC_DBOFF__reserved_L 1U
+#define XHC_DBOFF__reserved_R 0U
+#define XHC_DBOFF__reserved_WIDTH 2U
+#define XHC_DBOFF__reserved_RESETVALUE 0x0U
+#define XHC_DBOFF__RESERVED_L 31U
+#define XHC_DBOFF__RESERVED_R 16U
+#define XHC_DBOFF_WIDTH 16U
+#define XHC_DBOFF__WIDTH 16U
+#define XHC_DBOFF_ALL_L 15U
+#define XHC_DBOFF_ALL_R 0U
+#define XHC_DBOFF__ALL_L 15U
+#define XHC_DBOFF__ALL_R 0U
+#define XHC_DBOFF_DATAMASK 0x0000ffffU
+#define XHC_DBOFF_RDWRMASK 0xffff0000U
+#define XHC_DBOFF_RESETVALUE 0x0000U
+
+#define XHC_RTOFF_OFFSET 0x018U
+#define XHC_RTOFF_BASE 0x018U
+#define XHC_RTOFF__RTO_L 15U
+#define XHC_RTOFF__RTO_R 5U
+#define XHC_RTOFF__RTO_WIDTH 11U
+#define XHC_RTOFF__RTO_RESETVALUE 0x0U
+#define XHC_RTOFF__reserved_L 4U
+#define XHC_RTOFF__reserved_R 0U
+#define XHC_RTOFF__reserved_WIDTH 5U
+#define XHC_RTOFF__reserved_RESETVALUE 0x0U
+#define XHC_RTOFF__RESERVED_L 31U
+#define XHC_RTOFF__RESERVED_R 16U
+#define XHC_RTOFF_WIDTH 16U
+#define XHC_RTOFF__WIDTH 16U
+#define XHC_RTOFF_ALL_L 15U
+#define XHC_RTOFF_ALL_R 0U
+#define XHC_RTOFF__ALL_L 15U
+#define XHC_RTOFF__ALL_R 0U
+#define XHC_RTOFF_DATAMASK 0x0000ffffU
+#define XHC_RTOFF_RDWRMASK 0xffff0000U
+#define XHC_RTOFF_RESETVALUE 0x0000U
+
+#define XHC_CPARAMS2_OFFSET 0x01cU
+#define XHC_CPARAMS2_BASE 0x01cU
+#define XHC_CPARAMS2__reserved_L 31U
+#define XHC_CPARAMS2__reserved_R 6U
+#define XHC_CPARAMS2__reserved_WIDTH 26U
+#define XHC_CPARAMS2__reserved_RESETVALUE 0x0U
+#define XHC_CPARAMS2__CIC 5U
+#define XHC_CPARAMS2__CIC_L 5U
+#define XHC_CPARAMS2__CIC_R 5U
+#define XHC_CPARAMS2__CIC_WIDTH 1U
+#define XHC_CPARAMS2__CIC_RESETVALUE 0x0U
+#define XHC_CPARAMS2__LEC 4U
+#define XHC_CPARAMS2__LEC_L 4U
+#define XHC_CPARAMS2__LEC_R 4U
+#define XHC_CPARAMS2__LEC_WIDTH 1U
+#define XHC_CPARAMS2__LEC_RESETVALUE 0x0U
+#define XHC_CPARAMS2__CTC 3U
+#define XHC_CPARAMS2__CTC_L 3U
+#define XHC_CPARAMS2__CTC_R 3U
+#define XHC_CPARAMS2__CTC_WIDTH 1U
+#define XHC_CPARAMS2__CTC_RESETVALUE 0x0U
+#define XHC_CPARAMS2__FSC 2U
+#define XHC_CPARAMS2__FSC_L 2U
+#define XHC_CPARAMS2__FSC_R 2U
+#define XHC_CPARAMS2__FSC_WIDTH 1U
+#define XHC_CPARAMS2__FSC_RESETVALUE 0x0U
+#define XHC_CPARAMS2__CMC 1U
+#define XHC_CPARAMS2__CMC_L 1U
+#define XHC_CPARAMS2__CMC_R 1U
+#define XHC_CPARAMS2__CMC_WIDTH 1U
+#define XHC_CPARAMS2__CMC_RESETVALUE 0x0U
+#define XHC_CPARAMS2__U3C 0U
+#define XHC_CPARAMS2__U3C_L 0U
+#define XHC_CPARAMS2__U3C_R 0U
+#define XHC_CPARAMS2__U3C_WIDTH 1U
+#define XHC_CPARAMS2__U3C_RESETVALUE 0x0U
+#define XHC_CPARAMS2_WIDTH 32U
+#define XHC_CPARAMS2__WIDTH 32U
+#define XHC_CPARAMS2_ALL_L 31U
+#define XHC_CPARAMS2_ALL_R 0U
+#define XHC_CPARAMS2__ALL_L 31U
+#define XHC_CPARAMS2__ALL_R 0U
+#define XHC_CPARAMS2_DATAMASK 0xffffffffU
+#define XHC_CPARAMS2_RDWRMASK 0x00000000U
+#define XHC_CPARAMS2_RESETVALUE 0x00000000U
+
+#define XHC_USBCMD_OFFSET 0x020U
+#define XHC_USBCMD_BASE 0x020U
+#define XHC_USBCMD__CME 13U
+#define XHC_USBCMD__CME_L 13U
+#define XHC_USBCMD__CME_R 13U
+#define XHC_USBCMD__CME_WIDTH 1U
+#define XHC_USBCMD__CME_RESETVALUE 0x0U
+#define XHC_USBCMD__SPE 12U
+#define XHC_USBCMD__SPE_L 12U
+#define XHC_USBCMD__SPE_R 12U
+#define XHC_USBCMD__SPE_WIDTH 1U
+#define XHC_USBCMD__SPE_RESETVALUE 0x0U
+#define XHC_USBCMD__EU3S 11U
+#define XHC_USBCMD__EU3S_L 11U
+#define XHC_USBCMD__EU3S_R 11U
+#define XHC_USBCMD__EU3S_WIDTH 1U
+#define XHC_USBCMD__EU3S_RESETVALUE 0x0U
+#define XHC_USBCMD__EWE 10U
+#define XHC_USBCMD__EWE_L 10U
+#define XHC_USBCMD__EWE_R 10U
+#define XHC_USBCMD__EWE_WIDTH 1U
+#define XHC_USBCMD__EWE_RESETVALUE 0x0U
+#define XHC_USBCMD__CRS 9U
+#define XHC_USBCMD__CRS_L 9U
+#define XHC_USBCMD__CRS_R 9U
+#define XHC_USBCMD__CRS_WIDTH 1U
+#define XHC_USBCMD__CRS_RESETVALUE 0x0U
+#define XHC_USBCMD__CSS 8U
+#define XHC_USBCMD__CSS_L 8U
+#define XHC_USBCMD__CSS_R 8U
+#define XHC_USBCMD__CSS_WIDTH 1U
+#define XHC_USBCMD__CSS_RESETVALUE 0x0U
+#define XHC_USBCMD__LRST 7U
+#define XHC_USBCMD__LRST_L 7U
+#define XHC_USBCMD__LRST_R 7U
+#define XHC_USBCMD__LRST_WIDTH 1U
+#define XHC_USBCMD__LRST_RESETVALUE 0x0U
+#define XHC_USBCMD__reserved_L 6U
+#define XHC_USBCMD__reserved_R 4U
+#define XHC_USBCMD__reserved_WIDTH 3U
+#define XHC_USBCMD__reserved_RESETVALUE 0x0U
+#define XHC_USBCMD__HSEE 3U
+#define XHC_USBCMD__HSEE_L 3U
+#define XHC_USBCMD__HSEE_R 3U
+#define XHC_USBCMD__HSEE_WIDTH 1U
+#define XHC_USBCMD__HSEE_RESETVALUE 0x0U
+#define XHC_USBCMD__INTE 2U
+#define XHC_USBCMD__INTE_L 2U
+#define XHC_USBCMD__INTE_R 2U
+#define XHC_USBCMD__INTE_WIDTH 1U
+#define XHC_USBCMD__INTE_RESETVALUE 0x0U
+#define XHC_USBCMD__RST 1U
+#define XHC_USBCMD__RST_L 1U
+#define XHC_USBCMD__RST_R 1U
+#define XHC_USBCMD__RST_WIDTH 1U
+#define XHC_USBCMD__RST_RESETVALUE 0x0U
+#define XHC_USBCMD__RS 0U
+#define XHC_USBCMD__RS_L 0U
+#define XHC_USBCMD__RS_R 0U
+#define XHC_USBCMD__RS_WIDTH 1U
+#define XHC_USBCMD__RS_RESETVALUE 0x0U
+#define XHC_USBCMD__RESERVED_L 31U
+#define XHC_USBCMD__RESERVED_R 14U
+#define XHC_USBCMD_WIDTH 14U
+#define XHC_USBCMD__WIDTH 14U
+#define XHC_USBCMD_ALL_L 13U
+#define XHC_USBCMD_ALL_R 0U
+#define XHC_USBCMD__ALL_L 13U
+#define XHC_USBCMD__ALL_R 0U
+#define XHC_USBCMD_DATAMASK 0x00003fffU
+#define XHC_USBCMD_RDWRMASK 0xffffc000U
+#define XHC_USBCMD_RESETVALUE 0x0000U
+
+#define XHC_USBSTS_OFFSET 0x024U
+#define XHC_USBSTS_BASE 0x024U
+#define XHC_USBSTS__CE 12U
+#define XHC_USBSTS__CE_L 12U
+#define XHC_USBSTS__CE_R 12U
+#define XHC_USBSTS__CE_WIDTH 1U
+#define XHC_USBSTS__CE_RESETVALUE 0x0U
+#define XHC_USBSTS__CNR 11U
+#define XHC_USBSTS__CNR_L 11U
+#define XHC_USBSTS__CNR_R 11U
+#define XHC_USBSTS__CNR_WIDTH 1U
+#define XHC_USBSTS__CNR_RESETVALUE 0x1U
+
+#define XHC_USBSTS__SRE 10U
+#define XHC_USBSTS__SRE_L 10U
+#define XHC_USBSTS__SRE_R 10U
+#define XHC_USBSTS__SRE_WIDTH 1U
+#define XHC_USBSTS__SRE_RESETVALUE 0x0U
+#define XHC_USBSTS__RSS 9U
+#define XHC_USBSTS__RSS_L 9U
+#define XHC_USBSTS__RSS_R 9U
+#define XHC_USBSTS__RSS_WIDTH 1U
+#define XHC_USBSTS__RSS_RESETVALUE 0x0U
+#define XHC_USBSTS__SSS 8U
+#define XHC_USBSTS__SSS_L 8U
+#define XHC_USBSTS__SSS_R 8U
+#define XHC_USBSTS__SSS_WIDTH 1U
+#define XHC_USBSTS__SSS_RESETVALUE 0x0U
+#define XHC_USBSTS__PCD 4U
+#define XHC_USBSTS__PCD_L 4U
+#define XHC_USBSTS__PCD_R 4U
+#define XHC_USBSTS__PCD_WIDTH 1U
+#define XHC_USBSTS__PCD_RESETVALUE 0x0U
+#define XHC_USBSTS__EINT 3U
+#define XHC_USBSTS__EINT_L 3U
+#define XHC_USBSTS__EINT_R 3U
+#define XHC_USBSTS__EINT_WIDTH 1U
+#define XHC_USBSTS__EINT_RESETVALUE 0x0U
+#define XHC_USBSTS__HSE 2U
+#define XHC_USBSTS__HSE_L 2U
+#define XHC_USBSTS__HSE_R 2U
+#define XHC_USBSTS__HSE_WIDTH 1U
+#define XHC_USBSTS__HSE_RESETVALUE 0x0U
+#define XHC_USBSTS__reserved 1U
+#define XHC_USBSTS__reserved_L 1U
+#define XHC_USBSTS__reserved_R 1U
+#define XHC_USBSTS__reserved_WIDTH 1U
+#define XHC_USBSTS__reserved_RESETVALUE 0x0U
+
+#define XHC_USBSTS__CH_L 0U
+#define XHC_USBSTS__CH_R 0U
+#define XHC_USBSTS__CH_WIDTH 1U
+#define XHC_USBSTS__CH_RESETVALUE 0x1U
+#define XHC_USBSTS__RESERVED_L 31U
+#define XHC_USBSTS__RESERVED_R 13U
+#define XHC_USBSTS_WIDTH 13U
+#define XHC_USBSTS__WIDTH 13U
+#define XHC_USBSTS_ALL_L 12U
+#define XHC_USBSTS_ALL_R 0U
+#define XHC_USBSTS__ALL_L 12U
+#define XHC_USBSTS__ALL_R 0U
+#define XHC_USBSTS_DATAMASK 0x00001f1fU
+#define XHC_USBSTS_RDWRMASK 0xffffe0e0U
+#define XHC_USBSTS_RESETVALUE 0x0801U
+
+#define XHC_PAGESIZE_OFFSET 0x028U
+#define XHC_PAGESIZE_BASE 0x028U
+#define XHC_PAGESIZE__reserved_L 31U
+#define XHC_PAGESIZE__reserved_R 16U
+#define XHC_PAGESIZE__reserved_WIDTH 16U
+#define XHC_PAGESIZE__reserved_RESETVALUE 0x0000U
+#define XHC_PAGESIZE__PS_L 15U
+#define XHC_PAGESIZE__PS_R 0U
+#define XHC_PAGESIZE__PS_WIDTH 16U
+#define XHC_PAGESIZE__PS_RESETVALUE 0x0000U
+#define XHC_PAGESIZE_WIDTH 32U
+#define XHC_PAGESIZE__WIDTH 32U
+#define XHC_PAGESIZE_ALL_L 31U
+#define XHC_PAGESIZE_ALL_R 0U
+#define XHC_PAGESIZE__ALL_L 31U
+#define XHC_PAGESIZE__ALL_R 0U
+#define XHC_PAGESIZE_DATAMASK 0xffffffffU
+#define XHC_PAGESIZE_RDWRMASK 0x00000000U
+#define XHC_PAGESIZE_RESETVALUE 0x00000000U
+
+#define XHC_DNCTRL_OFFSET 0x034U
+#define XHC_DNCTRL_BASE 0x034U
+#define XHC_DNCTRL__reserved_L 31U
+#define XHC_DNCTRL__reserved_R 16U
+#define XHC_DNCTRL__reserved_WIDTH 16U
+#define XHC_DNCTRL__reserved_RESETVALUE 0x0000U
+#define XHC_DNCTRL__DNE_L 15U
+#define XHC_DNCTRL__DNE_R 0U
+#define XHC_DNCTRL__DNE_WIDTH 16U
+#define XHC_DNCTRL__DNE_RESETVALUE 0x0000U
+#define XHC_DNCTRL_WIDTH 32U
+#define XHC_DNCTRL__WIDTH 32U
+#define XHC_DNCTRL_ALL_L 31U
+#define XHC_DNCTRL_ALL_R 0U
+#define XHC_DNCTRL__ALL_L 31U
+#define XHC_DNCTRL__ALL_R 0U
+#define XHC_DNCTRL_DATAMASK 0xffffffffU
+#define XHC_DNCTRL_RDWRMASK 0x00000000U
+#define XHC_DNCTRL_RESETVALUE 0x00000000U
+
+#define XHC_CRCRL_OFFSET 0x038U
+#define XHC_CRCRL_BASE 0x038U
+#define XHC_CRCRL__CRPL_L 31U
+#define XHC_CRCRL__CRPL_R 6U
+#define XHC_CRCRL__CRPL_WIDTH 26U
+#define XHC_CRCRL__CRPL_RESETVALUE 0x0U
+#define XHC_CRCRL__reserved_L 5U
+#define XHC_CRCRL__reserved_R 4U
+#define XHC_CRCRL__reserved_WIDTH 2U
+#define XHC_CRCRL__reserved_RESETVALUE 0x0U
+#define XHC_CRCRL__CRR 3U
+#define XHC_CRCRL__CRR_L 3U
+#define XHC_CRCRL__CRR_R 3U
+#define XHC_CRCRL__CRR_WIDTH 1U
+#define XHC_CRCRL__CRR_RESETVALUE 0x0U
+#define XHC_CRCRL__CA 2U
+#define XHC_CRCRL__CA_L 2U
+#define XHC_CRCRL__CA_R 2U
+#define XHC_CRCRL__CA_WIDTH 1U
+#define XHC_CRCRL__CA_RESETVALUE 0x0U
+#define XHC_CRCRL__CS 1U
+#define XHC_CRCRL__CS_L 1U
+#define XHC_CRCRL__CS_R 1U
+#define XHC_CRCRL__CS_WIDTH 1U
+#define XHC_CRCRL__CS_RESETVALUE 0x0U
+#define XHC_CRCRL__RCS 0U
+#define XHC_CRCRL__RCS_L 0U
+#define XHC_CRCRL__RCS_R 0U
+#define XHC_CRCRL__RCS_WIDTH 1U
+#define XHC_CRCRL__RCS_RESETVALUE 0x0U
+#define XHC_CRCRL_WIDTH 32U
+#define XHC_CRCRL__WIDTH 32U
+#define XHC_CRCRL_ALL_L 31U
+#define XHC_CRCRL_ALL_R 0U
+#define XHC_CRCRL__ALL_L 31U
+#define XHC_CRCRL__ALL_R 0U
+#define XHC_CRCRL_DATAMASK 0xffffffffU
+#define XHC_CRCRL_RDWRMASK 0x00000000U
+#define XHC_CRCRL_RESETVALUE 0x00000000U
+
+#define XHC_CRCRH_OFFSET 0x03cU
+#define XHC_CRCRH_BASE 0x03cU
+#define XHC_CRCRH__CRPH_L 31U
+#define XHC_CRCRH__CRPH_R 0U
+#define XHC_CRCRH__CRPH_WIDTH 32U
+#define XHC_CRCRH__CRPH_RESETVALUE 0x00000000U
+#define XHC_CRCRH_WIDTH 32U
+#define XHC_CRCRH__WIDTH 32U
+#define XHC_CRCRH_ALL_L 31U
+#define XHC_CRCRH_ALL_R 0U
+#define XHC_CRCRH__ALL_L 31U
+#define XHC_CRCRH__ALL_R 0U
+#define XHC_CRCRH_DATAMASK 0xffffffffU
+#define XHC_CRCRH_RDWRMASK 0x00000000U
+#define XHC_CRCRH_RESETVALUE 0x00000000U
+
+#define XHC_DCBAAPL_OFFSET 0x050U
+#define XHC_DCBAAPL_BASE 0x050U
+#define XHC_DCBAAPL__DCAL_L 31U
+#define XHC_DCBAAPL__DCAL_R 6U
+#define XHC_DCBAAPL__DCAL_WIDTH 26U
+#define XHC_DCBAAPL__DCAL_RESETVALUE 0x0U
+
+#define XHC_DCBAAPL__reserved_L 5U
+#define XHC_DCBAAPL__reserved_R 0U
+#define XHC_DCBAAPL__reserved_WIDTH 6U
+#define XHC_DCBAAPL__reserved_RESETVALUE 0x0U
+#define XHC_DCBAAPL_WIDTH 32U
+#define XHC_DCBAAPL__WIDTH 32U
+#define XHC_DCBAAPL_ALL_L 31U
+#define XHC_DCBAAPL_ALL_R 0U
+#define XHC_DCBAAPL__ALL_L 31U
+#define XHC_DCBAAPL__ALL_R 0U
+#define XHC_DCBAAPL_DATAMASK 0xffffffffU
+#define XHC_DCBAAPL_RDWRMASK 0x00000000U
+#define XHC_DCBAAPL_RESETVALUE 0x00000000U
+
+#define XHC_DCBAAPH_OFFSET 0x054U
+#define XHC_DCBAAPH_BASE 0x054U
+#define XHC_DCBAAPH__DCAH_L 31U
+#define XHC_DCBAAPH__DCAH_R 0U
+#define XHC_DCBAAPH__DCAH_WIDTH 32U
+#define XHC_DCBAAPH__DCAH_RESETVALUE 0x00000000U
+#define XHC_DCBAAPH_WIDTH 32U
+#define XHC_DCBAAPH__WIDTH 32U
+#define XHC_DCBAAPH_ALL_L 31U
+#define XHC_DCBAAPH_ALL_R 0U
+#define XHC_DCBAAPH__ALL_L 31U
+#define XHC_DCBAAPH__ALL_R 0U
+#define XHC_DCBAAPH_DATAMASK 0xffffffffU
+#define XHC_DCBAAPH_RDWRMASK 0x00000000U
+#define XHC_DCBAAPH_RESETVALUE 0x00000000U
+
+#define XHC_CONFIG_OFFSET 0x058U
+#define XHC_CONFIG_BASE 0x058U
+#define XHC_CONFIG__reserved_L 31U
+#define XHC_CONFIG__reserved_R 10U
+#define XHC_CONFIG__reserved_WIDTH 22U
+#define XHC_CONFIG__reserved_RESETVALUE 0x0U
+#define XHC_CONFIG__CIE 9U
+#define XHC_CONFIG__CIE_L 9U
+#define XHC_CONFIG__CIE_R 9U
+#define XHC_CONFIG__CIE_WIDTH 1U
+#define XHC_CONFIG__CIE_RESETVALUE 0x0U
+#define XHC_CONFIG__U3E 8U
+#define XHC_CONFIG__U3E_L 8U
+#define XHC_CONFIG__U3E_R 8U
+#define XHC_CONFIG__U3E_WIDTH 1U
+#define XHC_CONFIG__U3E_RESETVALUE 0x0U
+#define XHC_CONFIG__MSE_L 7U
+#define XHC_CONFIG__MSE_R 0U
+#define XHC_CONFIG__MSE_WIDTH 8U
+#define XHC_CONFIG__MSE_RESETVALUE 0x00U
+#define XHC_CONFIG_WIDTH 32U
+#define XHC_CONFIG__WIDTH 32U
+#define XHC_CONFIG_ALL_L 31U
+#define XHC_CONFIG_ALL_R 0U
+#define XHC_CONFIG__ALL_L 31U
+#define XHC_CONFIG__ALL_R 0U
+#define XHC_CONFIG_DATAMASK 0xffffffffU
+#define XHC_CONFIG_RDWRMASK 0x00000000U
+#define XHC_CONFIG_RESETVALUE 0x00000000U
+
+#define XHC_PORTSC1_OFFSET 0x420U
+#define XHC_PORTSC1_BASE 0x420U
+
+#define XHC_PORTSC1__WPR_L 31U
+#define XHC_PORTSC1__WPR_R 31U
+#define XHC_PORTSC1__WPR_WIDTH 1U
+#define XHC_PORTSC1__WPR_RESETVALUE 0x0U
+
+#define XHC_PORTSC1__DNR_L 30U
+#define XHC_PORTSC1__DNR_R 30U
+#define XHC_PORTSC1__DNR_WIDTH 1U
+#define XHC_PORTSC1__DNR_RESETVALUE 0x0U
+
+#define XHC_PORTSC1__WOE_L 27U
+#define XHC_PORTSC1__WOE_R 27U
+#define XHC_PORTSC1__WOE_WIDTH 1U
+#define XHC_PORTSC1__WOE_RESETVALUE 0x0U
+
+#define XHC_PORTSC1__WDE_L 26U
+#define XHC_PORTSC1__WDE_R 26U
+#define XHC_PORTSC1__WDE_WIDTH 1U
+#define XHC_PORTSC1__WDE_RESETVALUE 0x0U
+
+#define XHC_PORTSC1__WCE_L 25U
+#define XHC_PORTSC1__WCE_R 25U
+#define XHC_PORTSC1__WCE_WIDTH 1U
+#define XHC_PORTSC1__WCE_RESETVALUE 0x0U
+
+#define XHC_PORTSC1__CAS_L 24U
+#define XHC_PORTSC1__CAS_R 24U
+#define XHC_PORTSC1__CAS_WIDTH 1U
+#define XHC_PORTSC1__CAS_RESETVALUE 0x0U
+
+#define XHC_PORTSC1__CEC_L 23U
+#define XHC_PORTSC1__CEC_R 23U
+#define XHC_PORTSC1__CEC_WIDTH 1U
+#define XHC_PORTSC1__CEC_RESETVALUE 0x0U
+
+#define XHC_PORTSC1__PLC_L 22U
+#define XHC_PORTSC1__PLC_R 22U
+#define XHC_PORTSC1__PLC_WIDTH 1U
+#define XHC_PORTSC1__PLC_RESETVALUE 0x0U
+
+#define XHC_PORTSC1__PRC_L 21U
+#define XHC_PORTSC1__PRC_R 21U
+#define XHC_PORTSC1__PRC_WIDTH 1U
+#define XHC_PORTSC1__PRC_RESETVALUE 0x0U
+
+#define XHC_PORTSC1__OCC_L 20U
+#define XHC_PORTSC1__OCC_R 20U
+#define XHC_PORTSC1__OCC_WIDTH 1U
+#define XHC_PORTSC1__OCC_RESETVALUE 0x0U
+
+#define XHC_PORTSC1__WRC_L 19U
+#define XHC_PORTSC1__WRC_R 19U
+#define XHC_PORTSC1__WRC_WIDTH 1U
+#define XHC_PORTSC1__WRC_RESETVALUE 0x0U
+
+#define XHC_PORTSC1__PEC_L 18U
+#define XHC_PORTSC1__PEC_R 18U
+#define XHC_PORTSC1__PEC_WIDTH 1U
+#define XHC_PORTSC1__PEC_RESETVALUE 0x0U
+
+#define XHC_PORTSC1__CSC_L 17U
+#define XHC_PORTSC1__CSC_R 17U
+#define XHC_PORTSC1__CSC_WIDTH 1U
+#define XHC_PORTSC1__CSC_RESETVALUE 0x0U
+
+#define XHC_PORTSC1__LWS_L 16U
+#define XHC_PORTSC1__LWS_R 16U
+#define XHC_PORTSC1__LWS_WIDTH 1U
+#define XHC_PORTSC1__LWS_RESETVALUE 0x0U
+#define XHC_PORTSC1__PIC_L 15U
+#define XHC_PORTSC1__PIC_R 14U
+#define XHC_PORTSC1__PIC_WIDTH 2U
+#define XHC_PORTSC1__PIC_RESETVALUE 0x0U
+#define XHC_PORTSC1__PS_L 13U
+#define XHC_PORTSC1__PS_R 10U
+#define XHC_PORTSC1__PS_WIDTH 4U
+#define XHC_PORTSC1__PS_RESETVALUE 0x0U
+
+#define XHC_PORTSC1__PP_L 9U
+#define XHC_PORTSC1__PP_R 9U
+#define XHC_PORTSC1__PP_WIDTH 1U
+#define XHC_PORTSC1__PP_RESETVALUE 0x0U
+#define XHC_PORTSC1__PLS_L 8U
+#define XHC_PORTSC1__PLS_R 5U
+#define XHC_PORTSC1__PLS_WIDTH 4U
+#define XHC_PORTSC1__PLS_RESETVALUE 0x5U
+
+#define XHC_PORTSC1__PRST_L 4U
+#define XHC_PORTSC1__PRST_R 4U
+#define XHC_PORTSC1__PRST_WIDTH 1U
+#define XHC_PORTSC1__PRST_RESETVALUE 0x0U
+
+#define XHC_PORTSC1__OCA_L 3U
+#define XHC_PORTSC1__OCA_R 3U
+#define XHC_PORTSC1__OCA_WIDTH 1U
+#define XHC_PORTSC1__OCA_RESETVALUE 0x0U
+#define XHC_PORTSC1__reserved 2U
+#define XHC_PORTSC1__reserved_L 2U
+#define XHC_PORTSC1__reserved_R 2U
+#define XHC_PORTSC1__reserved_WIDTH 1U
+#define XHC_PORTSC1__reserved_RESETVALUE 0x0U
+
+#define XHC_PORTSC1__PED_L 1U
+#define XHC_PORTSC1__PED_R 1U
+#define XHC_PORTSC1__PED_WIDTH 1U
+#define XHC_PORTSC1__PED_RESETVALUE 0x0U
+
+#define XHC_PORTSC1__CCS_L 0U
+#define XHC_PORTSC1__CCS_R 0U
+#define XHC_PORTSC1__CCS_WIDTH 1U
+#define XHC_PORTSC1__CCS_RESETVALUE 0x0U
+#define XHC_PORTSC1__RESERVED_L 29U
+#define XHC_PORTSC1__RESERVED_R 28U
+#define XHC_PORTSC1_WIDTH 32U
+#define XHC_PORTSC1__WIDTH 32U
+#define XHC_PORTSC1_ALL_L 31U
+#define XHC_PORTSC1_ALL_R 0U
+#define XHC_PORTSC1__ALL_L 31U
+#define XHC_PORTSC1__ALL_R 0U
+#define XHC_PORTSC1_DATAMASK 0xcfffffffU
+#define XHC_PORTSC1_RDWRMASK 0x30000000U
+#define XHC_PORTSC1_RESETVALUE 0x000000a0U
+
+#define XHC_PORTPM1_OFFSET 0x424U
+#define XHC_PORTPM1_BASE 0x424U
+#define XHC_PORTPM1__reserved_L 31U
+#define XHC_PORTPM1__reserved_R 17U
+#define XHC_PORTPM1__reserved_WIDTH 15U
+#define XHC_PORTPM1__reserved_RESETVALUE 0x0U
+#define XHC_PORTPM1__FLA 16U
+#define XHC_PORTPM1__FLA_L 16U
+#define XHC_PORTPM1__FLA_R 16U
+#define XHC_PORTPM1__FLA_WIDTH 1U
+#define XHC_PORTPM1__FLA_RESETVALUE 0x0U
+#define XHC_PORTPM1__U2T_L 15U
+#define XHC_PORTPM1__U2T_R 8U
+#define XHC_PORTPM1__U2T_WIDTH 8U
+#define XHC_PORTPM1__U2T_RESETVALUE 0x00U
+#define XHC_PORTPM1__U1T_L 7U
+#define XHC_PORTPM1__U1T_R 0U
+#define XHC_PORTPM1__U1T_WIDTH 8U
+#define XHC_PORTPM1__U1T_RESETVALUE 0x00U
+#define XHC_PORTPM1_WIDTH 32U
+#define XHC_PORTPM1__WIDTH 32U
+#define XHC_PORTPM1_ALL_L 31U
+#define XHC_PORTPM1_ALL_R 0U
+#define XHC_PORTPM1__ALL_L 31U
+#define XHC_PORTPM1__ALL_R 0U
+#define XHC_PORTPM1_DATAMASK 0xffffffffU
+#define XHC_PORTPM1_RDWRMASK 0x00000000U
+#define XHC_PORTPM1_RESETVALUE 0x00000000U
+
+#define XHC_PORTLC1_OFFSET 0x428U
+#define XHC_PORTLC1_BASE 0x428U
+#define XHC_PORTLC1__reserved_L 31U
+#define XHC_PORTLC1__reserved_R 0U
+#define XHC_PORTLC1__reserved_WIDTH 32U
+#define XHC_PORTLC1__reserved_RESETVALUE 0x00000000U
+#define XHC_PORTLC1_WIDTH 32U
+#define XHC_PORTLC1__WIDTH 32U
+#define XHC_PORTLC1_ALL_L 31U
+#define XHC_PORTLC1_ALL_R 0U
+#define XHC_PORTLC1__ALL_L 31U
+#define XHC_PORTLC1__ALL_R 0U
+#define XHC_PORTLC1_DATAMASK 0xffffffffU
+#define XHC_PORTLC1_RDWRMASK 0x00000000U
+#define XHC_PORTLC1_RESETVALUE 0x00000000U
+
+#define XHC_PORTSC2_OFFSET 0x430U
+#define XHC_PORTSC2_BASE 0x430U
+#define XHC_PORTSC2__WPR 31U
+#define XHC_PORTSC2__WPR_L 31U
+#define XHC_PORTSC2__WPR_R 31U
+#define XHC_PORTSC2__WPR_WIDTH 1U
+#define XHC_PORTSC2__WPR_RESETVALUE 0x0U
+#define XHC_PORTSC2__DNR 30U
+#define XHC_PORTSC2__DNR_L 30U
+#define XHC_PORTSC2__DNR_R 30U
+#define XHC_PORTSC2__DNR_WIDTH 1U
+#define XHC_PORTSC2__DNR_RESETVALUE 0x0U
+#define XHC_PORTSC2__WOE 27U
+#define XHC_PORTSC2__WOE_L 27U
+#define XHC_PORTSC2__WOE_R 27U
+#define XHC_PORTSC2__WOE_WIDTH 1U
+#define XHC_PORTSC2__WOE_RESETVALUE 0x0U
+#define XHC_PORTSC2__WDE 26U
+#define XHC_PORTSC2__WDE_L 26U
+#define XHC_PORTSC2__WDE_R 26U
+#define XHC_PORTSC2__WDE_WIDTH 1U
+#define XHC_PORTSC2__WDE_RESETVALUE 0x0U
+#define XHC_PORTSC2__WCE 25U
+#define XHC_PORTSC2__WCE_L 25U
+#define XHC_PORTSC2__WCE_R 25U
+#define XHC_PORTSC2__WCE_WIDTH 1U
+#define XHC_PORTSC2__WCE_RESETVALUE 0x0U
+#define XHC_PORTSC2__CAS 24U
+#define XHC_PORTSC2__CAS_L 24U
+#define XHC_PORTSC2__CAS_R 24U
+#define XHC_PORTSC2__CAS_WIDTH 1U
+#define XHC_PORTSC2__CAS_RESETVALUE 0x0U
+#define XHC_PORTSC2__CEC 23U
+#define XHC_PORTSC2__CEC_L 23U
+#define XHC_PORTSC2__CEC_R 23U
+#define XHC_PORTSC2__CEC_WIDTH 1U
+#define XHC_PORTSC2__CEC_RESETVALUE 0x0U
+#define XHC_PORTSC2__PLC 22U
+#define XHC_PORTSC2__PLC_L 22U
+#define XHC_PORTSC2__PLC_R 22U
+#define XHC_PORTSC2__PLC_WIDTH 1U
+#define XHC_PORTSC2__PLC_RESETVALUE 0x0U
+#define XHC_PORTSC2__PRC 21U
+#define XHC_PORTSC2__PRC_L 21U
+#define XHC_PORTSC2__PRC_R 21U
+#define XHC_PORTSC2__PRC_WIDTH 1U
+#define XHC_PORTSC2__PRC_RESETVALUE 0x0U
+#define XHC_PORTSC2__OCC 20U
+#define XHC_PORTSC2__OCC_L 20U
+#define XHC_PORTSC2__OCC_R 20U
+#define XHC_PORTSC2__OCC_WIDTH 1U
+#define XHC_PORTSC2__OCC_RESETVALUE 0x0U
+#define XHC_PORTSC2__WRC 19U
+#define XHC_PORTSC2__WRC_L 19U
+#define XHC_PORTSC2__WRC_R 19U
+#define XHC_PORTSC2__WRC_WIDTH 1U
+#define XHC_PORTSC2__WRC_RESETVALUE 0x0U
+#define XHC_PORTSC2__PEC 18U
+#define XHC_PORTSC2__PEC_L 18U
+#define XHC_PORTSC2__PEC_R 18U
+#define XHC_PORTSC2__PEC_WIDTH 1U
+#define XHC_PORTSC2__PEC_RESETVALUE 0x0U
+#define XHC_PORTSC2__CSC 17U
+#define XHC_PORTSC2__CSC_L 17U
+#define XHC_PORTSC2__CSC_R 17U
+#define XHC_PORTSC2__CSC_WIDTH 1U
+#define XHC_PORTSC2__CSC_RESETVALUE 0x0U
+#define XHC_PORTSC2__LWS 16U
+#define XHC_PORTSC2__LWS_L 16U
+#define XHC_PORTSC2__LWS_R 16U
+#define XHC_PORTSC2__LWS_WIDTH 1U
+#define XHC_PORTSC2__LWS_RESETVALUE 0x0U
+#define XHC_PORTSC2__PIC_L 15U
+#define XHC_PORTSC2__PIC_R 14U
+#define XHC_PORTSC2__PIC_WIDTH 2U
+#define XHC_PORTSC2__PIC_RESETVALUE 0x0U
+#define XHC_PORTSC2__PS_L 13U
+#define XHC_PORTSC2__PS_R 10U
+#define XHC_PORTSC2__PS_WIDTH 4U
+#define XHC_PORTSC2__PS_RESETVALUE 0x0U
+#define XHC_PORTSC2__PP 9U
+#define XHC_PORTSC2__PP_L 9U
+#define XHC_PORTSC2__PP_R 9U
+#define XHC_PORTSC2__PP_WIDTH 1U
+#define XHC_PORTSC2__PP_RESETVALUE 0x0U
+#define XHC_PORTSC2__PLS_L 8U
+#define XHC_PORTSC2__PLS_R 5U
+#define XHC_PORTSC2__PLS_WIDTH 4U
+#define XHC_PORTSC2__PLS_RESETVALUE 0x5U
+
+#define XHC_PORTSC2__PRST_L 4U
+#define XHC_PORTSC2__PRST_R 4U
+#define XHC_PORTSC2__PRST_WIDTH 1U
+#define XHC_PORTSC2__PRST_RESETVALUE 0x0U
+#define XHC_PORTSC2__OCA 3U
+#define XHC_PORTSC2__OCA_L 3U
+#define XHC_PORTSC2__OCA_R 3U
+#define XHC_PORTSC2__OCA_WIDTH 1U
+#define XHC_PORTSC2__OCA_RESETVALUE 0x0U
+#define XHC_PORTSC2__reserved 2U
+#define XHC_PORTSC2__reserved_L 2U
+#define XHC_PORTSC2__reserved_R 2U
+#define XHC_PORTSC2__reserved_WIDTH 1U
+#define XHC_PORTSC2__reserved_RESETVALUE 0x0U
+#define XHC_PORTSC2__PED 1U
+#define XHC_PORTSC2__PED_L 1U
+#define XHC_PORTSC2__PED_R 1U
+#define XHC_PORTSC2__PED_WIDTH 1U
+#define XHC_PORTSC2__PED_RESETVALUE 0x0U
+#define XHC_PORTSC2__CCS 0U
+#define XHC_PORTSC2__CCS_L 0U
+#define XHC_PORTSC2__CCS_R 0U
+#define XHC_PORTSC2__CCS_WIDTH 1U
+#define XHC_PORTSC2__CCS_RESETVALUE 0x0U
+#define XHC_PORTSC2__RESERVED_L 29U
+#define XHC_PORTSC2__RESERVED_R 28U
+#define XHC_PORTSC2_WIDTH 32U
+#define XHC_PORTSC2__WIDTH 32U
+#define XHC_PORTSC2_ALL_L 31U
+#define XHC_PORTSC2_ALL_R 0U
+#define XHC_PORTSC2__ALL_L 31U
+#define XHC_PORTSC2__ALL_R 0U
+#define XHC_PORTSC2_DATAMASK 0xcfffffffU
+#define XHC_PORTSC2_RDWRMASK 0x30000000U
+#define XHC_PORTSC2_RESETVALUE 0x000000a0U
+
+#define XHC_PORTPM2_OFFSET 0x434U
+#define XHC_PORTPM2_BASE 0x434U
+#define XHC_PORTPM2__PTC_L 31U
+#define XHC_PORTPM2__PTC_R 28U
+#define XHC_PORTPM2__PTC_WIDTH 4U
+#define XHC_PORTPM2__PTC_RESETVALUE 0x0U
+#define XHC_PORTPM2__reserved_L 27U
+#define XHC_PORTPM2__reserved_R 17U
+#define XHC_PORTPM2__reserved_WIDTH 11U
+#define XHC_PORTPM2__reserved_RESETVALUE 0x0U
+#define XHC_PORTPM2__HLE 16U
+#define XHC_PORTPM2__HLE_L 16U
+#define XHC_PORTPM2__HLE_R 16U
+#define XHC_PORTPM2__HLE_WIDTH 1U
+#define XHC_PORTPM2__HLE_RESETVALUE 0x0U
+#define XHC_PORTPM2__L1DS_L 15U
+#define XHC_PORTPM2__L1DS_R 8U
+#define XHC_PORTPM2__L1DS_WIDTH 8U
+#define XHC_PORTPM2__L1DS_RESETVALUE 0x00U
+#define XHC_PORTPM2__BESL_L 7U
+#define XHC_PORTPM2__BESL_R 4U
+#define XHC_PORTPM2__BESL_WIDTH 4U
+#define XHC_PORTPM2__BESL_RESETVALUE 0x0U
+#define XHC_PORTPM2__RWE 3U
+#define XHC_PORTPM2__RWE_L 3U
+#define XHC_PORTPM2__RWE_R 3U
+#define XHC_PORTPM2__RWE_WIDTH 1U
+#define XHC_PORTPM2__RWE_RESETVALUE 0x0U
+#define XHC_PORTPM2__L1S_L 2U
+#define XHC_PORTPM2__L1S_R 0U
+#define XHC_PORTPM2__L1S_WIDTH 3U
+#define XHC_PORTPM2__L1S_RESETVALUE 0x0U
+#define XHC_PORTPM2_WIDTH 32U
+#define XHC_PORTPM2__WIDTH 32U
+#define XHC_PORTPM2_ALL_L 31U
+#define XHC_PORTPM2_ALL_R 0U
+#define XHC_PORTPM2__ALL_L 31U
+#define XHC_PORTPM2__ALL_R 0U
+#define XHC_PORTPM2_DATAMASK 0xffffffffU
+#define XHC_PORTPM2_RDWRMASK 0x00000000U
+#define XHC_PORTPM2_RESETVALUE 0x00000000U
+
+#define XHC_PORTLC2_OFFSET 0x43cU
+#define XHC_PORTLC2_BASE 0x43cU
+#define XHC_PORTLC2__reserved_L 31U
+#define XHC_PORTLC2__reserved_R 14U
+#define XHC_PORTLC2__reserved_WIDTH 18U
+#define XHC_PORTLC2__reserved_RESETVALUE 0x0U
+#define XHC_PORTLC2__BESLD_L 13U
+#define XHC_PORTLC2__BESLD_R 10U
+#define XHC_PORTLC2__BESLD_WIDTH 4U
+#define XHC_PORTLC2__BESLD_RESETVALUE 0x0U
+#define XHC_PORTLC2__L1T_L 9U
+#define XHC_PORTLC2__L1T_R 2U
+#define XHC_PORTLC2__L1T_WIDTH 8U
+#define XHC_PORTLC2__L1T_RESETVALUE 0x00U
+#define XHC_PORTLC2__HIRDM_L 1U
+#define XHC_PORTLC2__HIRDM_R 0U
+#define XHC_PORTLC2__HIRDM_WIDTH 2U
+#define XHC_PORTLC2__HIRDM_RESETVALUE 0x0U
+#define XHC_PORTLC2_WIDTH 32U
+#define XHC_PORTLC2__WIDTH 32U
+#define XHC_PORTLC2_ALL_L 31U
+#define XHC_PORTLC2_ALL_R 0U
+#define XHC_PORTLC2__ALL_L 31U
+#define XHC_PORTLC2__ALL_R 0U
+#define XHC_PORTLC2_DATAMASK 0xffffffffU
+#define XHC_PORTLC2_RDWRMASK 0x00000000U
+#define XHC_PORTLC2_RESETVALUE 0x00000000U
+
+#define XHC_PORTSC3_OFFSET 0x440U
+#define XHC_PORTSC3_BASE 0x440U
+#define XHC_PORTSC3__WPR 31U
+#define XHC_PORTSC3__WPR_L 31U
+#define XHC_PORTSC3__WPR_R 31U
+#define XHC_PORTSC3__WPR_WIDTH 1U
+#define XHC_PORTSC3__WPR_RESETVALUE 0x0U
+#define XHC_PORTSC3__DNR 30U
+#define XHC_PORTSC3__DNR_L 30U
+#define XHC_PORTSC3__DNR_R 30U
+#define XHC_PORTSC3__DNR_WIDTH 1U
+#define XHC_PORTSC3__DNR_RESETVALUE 0x0U
+#define XHC_PORTSC3__WOE 27U
+#define XHC_PORTSC3__WOE_L 27U
+#define XHC_PORTSC3__WOE_R 27U
+#define XHC_PORTSC3__WOE_WIDTH 1U
+#define XHC_PORTSC3__WOE_RESETVALUE 0x0U
+#define XHC_PORTSC3__WDE 26U
+#define XHC_PORTSC3__WDE_L 26U
+#define XHC_PORTSC3__WDE_R 26U
+#define XHC_PORTSC3__WDE_WIDTH 1U
+#define XHC_PORTSC3__WDE_RESETVALUE 0x0U
+#define XHC_PORTSC3__WCE 25U
+#define XHC_PORTSC3__WCE_L 25U
+#define XHC_PORTSC3__WCE_R 25U
+#define XHC_PORTSC3__WCE_WIDTH 1U
+#define XHC_PORTSC3__WCE_RESETVALUE 0x0U
+#define XHC_PORTSC3__CAS 24U
+#define XHC_PORTSC3__CAS_L 24U
+#define XHC_PORTSC3__CAS_R 24U
+#define XHC_PORTSC3__CAS_WIDTH 1U
+#define XHC_PORTSC3__CAS_RESETVALUE 0x0U
+#define XHC_PORTSC3__CEC 23U
+#define XHC_PORTSC3__CEC_L 23U
+#define XHC_PORTSC3__CEC_R 23U
+#define XHC_PORTSC3__CEC_WIDTH 1U
+#define XHC_PORTSC3__CEC_RESETVALUE 0x0U
+#define XHC_PORTSC3__PLC 22U
+#define XHC_PORTSC3__PLC_L 22U
+#define XHC_PORTSC3__PLC_R 22U
+#define XHC_PORTSC3__PLC_WIDTH 1U
+#define XHC_PORTSC3__PLC_RESETVALUE 0x0U
+#define XHC_PORTSC3__PRC 21U
+#define XHC_PORTSC3__PRC_L 21U
+#define XHC_PORTSC3__PRC_R 21U
+#define XHC_PORTSC3__PRC_WIDTH 1U
+#define XHC_PORTSC3__PRC_RESETVALUE 0x0U
+#define XHC_PORTSC3__OCC 20U
+#define XHC_PORTSC3__OCC_L 20U
+#define XHC_PORTSC3__OCC_R 20U
+#define XHC_PORTSC3__OCC_WIDTH 1U
+#define XHC_PORTSC3__OCC_RESETVALUE 0x0U
+#define XHC_PORTSC3__WRC 19U
+#define XHC_PORTSC3__WRC_L 19U
+#define XHC_PORTSC3__WRC_R 19U
+#define XHC_PORTSC3__WRC_WIDTH 1U
+#define XHC_PORTSC3__WRC_RESETVALUE 0x0U
+#define XHC_PORTSC3__PEC 18U
+#define XHC_PORTSC3__PEC_L 18U
+#define XHC_PORTSC3__PEC_R 18U
+#define XHC_PORTSC3__PEC_WIDTH 1U
+#define XHC_PORTSC3__PEC_RESETVALUE 0x0U
+#define XHC_PORTSC3__CSC 17U
+#define XHC_PORTSC3__CSC_L 17U
+#define XHC_PORTSC3__CSC_R 17U
+#define XHC_PORTSC3__CSC_WIDTH 1U
+#define XHC_PORTSC3__CSC_RESETVALUE 0x0U
+#define XHC_PORTSC3__LWS 16U
+#define XHC_PORTSC3__LWS_L 16U
+#define XHC_PORTSC3__LWS_R 16U
+#define XHC_PORTSC3__LWS_WIDTH 1U
+#define XHC_PORTSC3__LWS_RESETVALUE 0x0U
+#define XHC_PORTSC3__PIC_L 15U
+#define XHC_PORTSC3__PIC_R 14U
+#define XHC_PORTSC3__PIC_WIDTH 2U
+#define XHC_PORTSC3__PIC_RESETVALUE 0x0U
+#define XHC_PORTSC3__PS_L 13U
+#define XHC_PORTSC3__PS_R 10U
+#define XHC_PORTSC3__PS_WIDTH 4U
+#define XHC_PORTSC3__PS_RESETVALUE 0x0U
+#define XHC_PORTSC3__PP 9U
+#define XHC_PORTSC3__PP_L 9U
+#define XHC_PORTSC3__PP_R 9U
+#define XHC_PORTSC3__PP_WIDTH 1U
+#define XHC_PORTSC3__PP_RESETVALUE 0x0U
+#define XHC_PORTSC3__PLS_L 8U
+#define XHC_PORTSC3__PLS_R 5U
+#define XHC_PORTSC3__PLS_WIDTH 4U
+#define XHC_PORTSC3__PLS_RESETVALUE 0x5U
+#define XHC_PORTSC3__PR 4U
+#define XHC_PORTSC3__PR_L 4U
+#define XHC_PORTSC3__PR_R 4U
+#define XHC_PORTSC3__PR_WIDTH 1U
+#define XHC_PORTSC3__PR_RESETVALUE 0x0U
+#define XHC_PORTSC3__OCA 3U
+#define XHC_PORTSC3__OCA_L 3U
+#define XHC_PORTSC3__OCA_R 3U
+#define XHC_PORTSC3__OCA_WIDTH 1U
+#define XHC_PORTSC3__OCA_RESETVALUE 0x0U
+#define XHC_PORTSC3__reserved 2U
+#define XHC_PORTSC3__reserved_L 2U
+#define XHC_PORTSC3__reserved_R 2U
+#define XHC_PORTSC3__reserved_WIDTH 1U
+#define XHC_PORTSC3__reserved_RESETVALUE 0x0U
+#define XHC_PORTSC3__PED 1U
+#define XHC_PORTSC3__PED_L 1U
+#define XHC_PORTSC3__PED_R 1U
+#define XHC_PORTSC3__PED_WIDTH 1U
+#define XHC_PORTSC3__PED_RESETVALUE 0x0U
+#define XHC_PORTSC3__CCS 0U
+#define XHC_PORTSC3__CCS_L 0U
+#define XHC_PORTSC3__CCS_R 0U
+#define XHC_PORTSC3__CCS_WIDTH 1U
+#define XHC_PORTSC3__CCS_RESETVALUE 0x0U
+#define XHC_PORTSC3__RESERVED_L 29U
+#define XHC_PORTSC3__RESERVED_R 28U
+#define XHC_PORTSC3_WIDTH 32U
+#define XHC_PORTSC3__WIDTH 32U
+#define XHC_PORTSC3_ALL_L 31U
+#define XHC_PORTSC3_ALL_R 0U
+#define XHC_PORTSC3__ALL_L 31U
+#define XHC_PORTSC3__ALL_R 0U
+#define XHC_PORTSC3_DATAMASK 0xcfffffffU
+#define XHC_PORTSC3_RDWRMASK 0x30000000U
+#define XHC_PORTSC3_RESETVALUE 0x000000a0U
+
+#define XHC_PORTPM3_OFFSET 0x444U
+#define XHC_PORTPM3_BASE 0x444U
+#define XHC_PORTPM3__PTC_L 31U
+#define XHC_PORTPM3__PTC_R 28U
+#define XHC_PORTPM3__PTC_WIDTH 4U
+#define XHC_PORTPM3__PTC_RESETVALUE 0x0U
+#define XHC_PORTPM3__reserved_L 27U
+#define XHC_PORTPM3__reserved_R 17U
+#define XHC_PORTPM3__reserved_WIDTH 11U
+#define XHC_PORTPM3__reserved_RESETVALUE 0x0U
+#define XHC_PORTPM3__HLE 16U
+#define XHC_PORTPM3__HLE_L 16U
+#define XHC_PORTPM3__HLE_R 16U
+#define XHC_PORTPM3__HLE_WIDTH 1U
+#define XHC_PORTPM3__HLE_RESETVALUE 0x0U
+#define XHC_PORTPM3__L1DS_L 15U
+#define XHC_PORTPM3__L1DS_R 8U
+#define XHC_PORTPM3__L1DS_WIDTH 8U
+#define XHC_PORTPM3__L1DS_RESETVALUE 0x00U
+#define XHC_PORTPM3__BESL_L 7U
+#define XHC_PORTPM3__BESL_R 4U
+#define XHC_PORTPM3__BESL_WIDTH 4U
+#define XHC_PORTPM3__BESL_RESETVALUE 0x0U
+#define XHC_PORTPM3__RWE 3U
+#define XHC_PORTPM3__RWE_L 3U
+#define XHC_PORTPM3__RWE_R 3U
+#define XHC_PORTPM3__RWE_WIDTH 1U
+#define XHC_PORTPM3__RWE_RESETVALUE 0x0U
+#define XHC_PORTPM3__L1S_L 2U
+#define XHC_PORTPM3__L1S_R 0U
+#define XHC_PORTPM3__L1S_WIDTH 3U
+#define XHC_PORTPM3__L1S_RESETVALUE 0x0U
+#define XHC_PORTPM3_WIDTH 32U
+#define XHC_PORTPM3__WIDTH 32U
+#define XHC_PORTPM3_ALL_L 31U
+#define XHC_PORTPM3_ALL_R 0U
+#define XHC_PORTPM3__ALL_L 31U
+#define XHC_PORTPM3__ALL_R 0U
+#define XHC_PORTPM3_DATAMASK 0xffffffffU
+#define XHC_PORTPM3_RDWRMASK 0x00000000U
+#define XHC_PORTPM3_RESETVALUE 0x00000000U
+
+#define XHC_PORTLI3_OFFSET 0x44cU
+#define XHC_PORTLI3_BASE 0x44cU
+#define XHC_PORTLI3__reserved_L 31U
+#define XHC_PORTLI3__reserved_R 0U
+#define XHC_PORTLI3__reserved_WIDTH 32U
+#define XHC_PORTLI3__reserved_RESETVALUE 0x00000000U
+#define XHC_PORTLI3_WIDTH 32U
+#define XHC_PORTLI3__WIDTH 32U
+#define XHC_PORTLI3_ALL_L 31U
+#define XHC_PORTLI3_ALL_R 0U
+#define XHC_PORTLI3__ALL_L 31U
+#define XHC_PORTLI3__ALL_R 0U
+#define XHC_PORTLI3_DATAMASK 0xffffffffU
+#define XHC_PORTLI3_RDWRMASK 0x00000000U
+#define XHC_PORTLI3_RESETVALUE 0x00000000U
+
+#define XHC_MFINDEX_OFFSET 0x4a0U
+#define XHC_MFINDEX_BASE 0x4a0U
+#define XHC_MFINDEX__reserved_L 31U
+#define XHC_MFINDEX__reserved_R 14U
+#define XHC_MFINDEX__reserved_WIDTH 18U
+#define XHC_MFINDEX__reserved_RESETVALUE 0x0U
+#define XHC_MFINDEX__MFI_L 13U
+#define XHC_MFINDEX__MFI_R 0U
+#define XHC_MFINDEX__MFI_WIDTH 14U
+#define XHC_MFINDEX__MFI_RESETVALUE 0x0U
+#define XHC_MFINDEX_WIDTH 32U
+#define XHC_MFINDEX__WIDTH 32U
+#define XHC_MFINDEX_ALL_L 31U
+#define XHC_MFINDEX_ALL_R 0U
+#define XHC_MFINDEX__ALL_L 31U
+#define XHC_MFINDEX__ALL_R 0U
+#define XHC_MFINDEX_DATAMASK 0xffffffffU
+#define XHC_MFINDEX_RDWRMASK 0x00000000U
+#define XHC_MFINDEX_RESETVALUE 0x00000000U
+
+#define XHC_IMAN0_OFFSET 0x4c0U
+#define XHC_IMAN0_BASE 0x4c0U
+#define XHC_IMAN0__reserved_L 31U
+#define XHC_IMAN0__reserved_R 2U
+#define XHC_IMAN0__reserved_WIDTH 30U
+#define XHC_IMAN0__reserved_RESETVALUE 0x0U
+#define XHC_IMAN0__IE 1U
+#define XHC_IMAN0__IE_L 1U
+#define XHC_IMAN0__IE_R 1U
+#define XHC_IMAN0__IE_WIDTH 1U
+#define XHC_IMAN0__IE_RESETVALUE 0x0U
+#define XHC_IMAN0__IP 0U
+#define XHC_IMAN0__IP_L 0U
+#define XHC_IMAN0__IP_R 0U
+#define XHC_IMAN0__IP_WIDTH 1U
+#define XHC_IMAN0__IP_RESETVALUE 0x0U
+#define XHC_IMAN0_WIDTH 32U
+#define XHC_IMAN0__WIDTH 32U
+#define XHC_IMAN0_ALL_L 31U
+#define XHC_IMAN0_ALL_R 0U
+#define XHC_IMAN0__ALL_L 31U
+#define XHC_IMAN0__ALL_R 0U
+#define XHC_IMAN0_DATAMASK 0xffffffffU
+#define XHC_IMAN0_RDWRMASK 0x00000000U
+#define XHC_IMAN0_RESETVALUE 0x00000000U
+
+#define XHC_IMOD0_OFFSET 0x4c4U
+#define XHC_IMOD0_BASE 0x4c4U
+#define XHC_IMOD0__IMODC_L 31U
+#define XHC_IMOD0__IMODC_R 16U
+#define XHC_IMOD0__IMODC_WIDTH 16U
+#define XHC_IMOD0__IMODC_RESETVALUE 0x0000U
+#define XHC_IMOD0__IMODI_L 15U
+#define XHC_IMOD0__IMODI_R 0U
+#define XHC_IMOD0__IMODI_WIDTH 16U
+#define XHC_IMOD0__IMODI_RESETVALUE 0x4000U
+#define XHC_IMOD0_WIDTH 32U
+#define XHC_IMOD0__WIDTH 32U
+#define XHC_IMOD0_ALL_L 31U
+#define XHC_IMOD0_ALL_R 0U
+#define XHC_IMOD0__ALL_L 31U
+#define XHC_IMOD0__ALL_R 0U
+#define XHC_IMOD0_DATAMASK 0xffffffffU
+#define XHC_IMOD0_RDWRMASK 0x00000000U
+#define XHC_IMOD0_RESETVALUE 0x00004000U
+
+#define XHC_ERSTSZ0_OFFSET 0x4c8U
+#define XHC_ERSTSZ0_BASE 0x4c8U
+#define XHC_ERSTSZ0__reserved_L 31U
+#define XHC_ERSTSZ0__reserved_R 16U
+#define XHC_ERSTSZ0__reserved_WIDTH 16U
+#define XHC_ERSTSZ0__reserved_RESETVALUE 0x0000U
+#define XHC_ERSTSZ0__TSZ_L 15U
+#define XHC_ERSTSZ0__TSZ_R 0U
+#define XHC_ERSTSZ0__TSZ_WIDTH 16U
+#define XHC_ERSTSZ0__TSZ_RESETVALUE 0x0000U
+#define XHC_ERSTSZ0_WIDTH 32U
+#define XHC_ERSTSZ0__WIDTH 32U
+#define XHC_ERSTSZ0_ALL_L 31U
+#define XHC_ERSTSZ0_ALL_R 0U
+#define XHC_ERSTSZ0__ALL_L 31U
+#define XHC_ERSTSZ0__ALL_R 0U
+#define XHC_ERSTSZ0_DATAMASK 0xffffffffU
+#define XHC_ERSTSZ0_RDWRMASK 0x00000000U
+#define XHC_ERSTSZ0_RESETVALUE 0x00000000U
+
+#define XHC_ERSTBAL0_OFFSET 0x4d0U
+#define XHC_ERSTBAL0_BASE 0x4d0U
+#define XHC_ERSTBAL0__BAL_L 31U
+#define XHC_ERSTBAL0__BAL_R 4U
+#define XHC_ERSTBAL0__BAL_WIDTH 28U
+#define XHC_ERSTBAL0__BAL_RESETVALUE 0x0000000U
+#define XHC_ERSTBAL0__reserved_L 3U
+#define XHC_ERSTBAL0__reserved_R 0U
+#define XHC_ERSTBAL0__reserved_WIDTH 4U
+#define XHC_ERSTBAL0__reserved_RESETVALUE 0x0U
+#define XHC_ERSTBAL0_WIDTH 32U
+#define XHC_ERSTBAL0__WIDTH 32U
+#define XHC_ERSTBAL0_ALL_L 31U
+#define XHC_ERSTBAL0_ALL_R 0U
+#define XHC_ERSTBAL0__ALL_L 31U
+#define XHC_ERSTBAL0__ALL_R 0U
+#define XHC_ERSTBAL0_DATAMASK 0xffffffffU
+#define XHC_ERSTBAL0_RDWRMASK 0x00000000U
+#define XHC_ERSTBAL0_RESETVALUE 0x00000000U
+
+#define XHC_ERSTBAH0_OFFSET 0x4d4U
+#define XHC_ERSTBAH0_BASE 0x4d4U
+#define XHC_ERSTBAH0__BAH_L 31U
+#define XHC_ERSTBAH0__BAH_R 0U
+#define XHC_ERSTBAH0__BAH_WIDTH 32U
+#define XHC_ERSTBAH0__BAH_RESETVALUE 0x00000000U
+#define XHC_ERSTBAH0_WIDTH 32U
+#define XHC_ERSTBAH0__WIDTH 32U
+#define XHC_ERSTBAH0_ALL_L 31U
+#define XHC_ERSTBAH0_ALL_R 0U
+#define XHC_ERSTBAH0__ALL_L 31U
+#define XHC_ERSTBAH0__ALL_R 0U
+#define XHC_ERSTBAH0_DATAMASK 0xffffffffU
+#define XHC_ERSTBAH0_RDWRMASK 0x00000000U
+#define XHC_ERSTBAH0_RESETVALUE 0x00000000U
+
+#define XHC_ERDPL0_OFFSET 0x4d8U
+#define XHC_ERDPL0_BASE 0x4d8U
+#define XHC_ERDPL0__DPL_L 31U
+#define XHC_ERDPL0__DPL_R 4U
+#define XHC_ERDPL0__DPL_WIDTH 28U
+#define XHC_ERDPL0__DPL_RESETVALUE 0x0000000U
+#define XHC_ERDPL0__EHB 3U
+#define XHC_ERDPL0__EHB_L 3U
+#define XHC_ERDPL0__EHB_R 3U
+#define XHC_ERDPL0__EHB_WIDTH 1U
+#define XHC_ERDPL0__EHB_RESETVALUE 0x0U
+#define XHC_ERDPL0__DESI_L 2U
+#define XHC_ERDPL0__DESI_R 0U
+#define XHC_ERDPL0__DESI_WIDTH 3U
+#define XHC_ERDPL0__DESI_RESETVALUE 0x0U
+#define XHC_ERDPL0_WIDTH 32U
+#define XHC_ERDPL0__WIDTH 32U
+#define XHC_ERDPL0_ALL_L 31U
+#define XHC_ERDPL0_ALL_R 0U
+#define XHC_ERDPL0__ALL_L 31U
+#define XHC_ERDPL0__ALL_R 0U
+#define XHC_ERDPL0_DATAMASK 0xffffffffU
+#define XHC_ERDPL0_RDWRMASK 0x00000000U
+#define XHC_ERDPL0_RESETVALUE 0x00000000U
+
+#define XHC_ERDPH0_OFFSET 0x4dcU
+#define XHC_ERDPH0_BASE 0x4dcU
+#define XHC_ERDPH0__DPH_L 31U
+#define XHC_ERDPH0__DPH_R 0U
+#define XHC_ERDPH0__DPH_WIDTH 32U
+#define XHC_ERDPH0__DPH_RESETVALUE 0x00000000U
+#define XHC_ERDPH0_WIDTH 32U
+#define XHC_ERDPH0__WIDTH 32U
+#define XHC_ERDPH0_ALL_L 31U
+#define XHC_ERDPH0_ALL_R 0U
+#define XHC_ERDPH0__ALL_L 31U
+#define XHC_ERDPH0__ALL_R 0U
+#define XHC_ERDPH0_DATAMASK 0xffffffffU
+#define XHC_ERDPH0_RDWRMASK 0x00000000U
+#define XHC_ERDPH0_RESETVALUE 0x00000000U
+
+#define XHC_IMAN1_OFFSET 0x4e0U
+#define XHC_IMAN1_BASE 0x4e0U
+#define XHC_IMAN1__reserved_L 31U
+#define XHC_IMAN1__reserved_R 2U
+#define XHC_IMAN1__reserved_WIDTH 30U
+#define XHC_IMAN1__reserved_RESETVALUE 0x0U
+#define XHC_IMAN1__IE 1U
+#define XHC_IMAN1__IE_L 1U
+#define XHC_IMAN1__IE_R 1U
+#define XHC_IMAN1__IE_WIDTH 1U
+#define XHC_IMAN1__IE_RESETVALUE 0x0U
+#define XHC_IMAN1__IP 0U
+#define XHC_IMAN1__IP_L 0U
+#define XHC_IMAN1__IP_R 0U
+#define XHC_IMAN1__IP_WIDTH 1U
+#define XHC_IMAN1__IP_RESETVALUE 0x0U
+#define XHC_IMAN1_WIDTH 32U
+#define XHC_IMAN1__WIDTH 32U
+#define XHC_IMAN1_ALL_L 31U
+#define XHC_IMAN1_ALL_R 0U
+#define XHC_IMAN1__ALL_L 31U
+#define XHC_IMAN1__ALL_R 0U
+#define XHC_IMAN1_DATAMASK 0xffffffffU
+#define XHC_IMAN1_RDWRMASK 0x00000000U
+#define XHC_IMAN1_RESETVALUE 0x00000000U
+
+#define XHC_IMOD1_OFFSET 0x4e4U
+#define XHC_IMOD1_BASE 0x4e4U
+#define XHC_IMOD1__IMODC_L 31U
+#define XHC_IMOD1__IMODC_R 16U
+#define XHC_IMOD1__IMODC_WIDTH 16U
+#define XHC_IMOD1__IMODC_RESETVALUE 0x0000U
+#define XHC_IMOD1__IMODI_L 15U
+#define XHC_IMOD1__IMODI_R 0U
+#define XHC_IMOD1__IMODI_WIDTH 16U
+#define XHC_IMOD1__IMODI_RESETVALUE 0x4000U
+#define XHC_IMOD1_WIDTH 32U
+#define XHC_IMOD1__WIDTH 32U
+#define XHC_IMOD1_ALL_L 31U
+#define XHC_IMOD1_ALL_R 0U
+#define XHC_IMOD1__ALL_L 31U
+#define XHC_IMOD1__ALL_R 0U
+#define XHC_IMOD1_DATAMASK 0xffffffffU
+#define XHC_IMOD1_RDWRMASK 0x00000000U
+#define XHC_IMOD1_RESETVALUE 0x00004000U
+
+#define XHC_ERSTSZ1_OFFSET 0x4e8U
+#define XHC_ERSTSZ1_BASE 0x4e8U
+#define XHC_ERSTSZ1__reserved_L 31U
+#define XHC_ERSTSZ1__reserved_R 16U
+#define XHC_ERSTSZ1__reserved_WIDTH 16U
+#define XHC_ERSTSZ1__reserved_RESETVALUE 0x0000U
+#define XHC_ERSTSZ1__TSZ_L 15U
+#define XHC_ERSTSZ1__TSZ_R 0U
+#define XHC_ERSTSZ1__TSZ_WIDTH 16U
+#define XHC_ERSTSZ1__TSZ_RESETVALUE 0x0000U
+#define XHC_ERSTSZ1_WIDTH 32U
+#define XHC_ERSTSZ1__WIDTH 32U
+#define XHC_ERSTSZ1_ALL_L 31U
+#define XHC_ERSTSZ1_ALL_R 0U
+#define XHC_ERSTSZ1__ALL_L 31U
+#define XHC_ERSTSZ1__ALL_R 0U
+#define XHC_ERSTSZ1_DATAMASK 0xffffffffU
+#define XHC_ERSTSZ1_RDWRMASK 0x00000000U
+#define XHC_ERSTSZ1_RESETVALUE 0x00000000U
+
+#define XHC_ERSTBAL1_OFFSET 0x4f0U
+#define XHC_ERSTBAL1_BASE 0x4f0U
+#define XHC_ERSTBAL1__BAL_L 31U
+#define XHC_ERSTBAL1__BAL_R 4U
+#define XHC_ERSTBAL1__BAL_WIDTH 28U
+#define XHC_ERSTBAL1__BAL_RESETVALUE 0x0000000U
+#define XHC_ERSTBAL1__reserved_L 3U
+#define XHC_ERSTBAL1__reserved_R 0U
+#define XHC_ERSTBAL1__reserved_WIDTH 4U
+#define XHC_ERSTBAL1__reserved_RESETVALUE 0x0U
+#define XHC_ERSTBAL1_WIDTH 32U
+#define XHC_ERSTBAL1__WIDTH 32U
+#define XHC_ERSTBAL1_ALL_L 31U
+#define XHC_ERSTBAL1_ALL_R 0U
+#define XHC_ERSTBAL1__ALL_L 31U
+#define XHC_ERSTBAL1__ALL_R 0U
+#define XHC_ERSTBAL1_DATAMASK 0xffffffffU
+#define XHC_ERSTBAL1_RDWRMASK 0x00000000U
+#define XHC_ERSTBAL1_RESETVALUE 0x00000000U
+
+#define XHC_ERSTBAH1_OFFSET 0x4f4U
+#define XHC_ERSTBAH1_BASE 0x4f4U
+#define XHC_ERSTBAH1__BAH_L 31U
+#define XHC_ERSTBAH1__BAH_R 0U
+#define XHC_ERSTBAH1__BAH_WIDTH 32U
+#define XHC_ERSTBAH1__BAH_RESETVALUE 0x00000000U
+#define XHC_ERSTBAH1_WIDTH 32U
+#define XHC_ERSTBAH1__WIDTH 32U
+#define XHC_ERSTBAH1_ALL_L 31U
+#define XHC_ERSTBAH1_ALL_R 0U
+#define XHC_ERSTBAH1__ALL_L 31U
+#define XHC_ERSTBAH1__ALL_R 0U
+#define XHC_ERSTBAH1_DATAMASK 0xffffffffU
+#define XHC_ERSTBAH1_RDWRMASK 0x00000000U
+#define XHC_ERSTBAH1_RESETVALUE 0x00000000U
+
+#define XHC_ERDPL1_OFFSET 0x4f8U
+#define XHC_ERDPL1_BASE 0x4f8U
+#define XHC_ERDPL1__DPL_L 31U
+#define XHC_ERDPL1__DPL_R 4U
+#define XHC_ERDPL1__DPL_WIDTH 28U
+#define XHC_ERDPL1__DPL_RESETVALUE 0x0000000U
+#define XHC_ERDPL1__EHB 3U
+#define XHC_ERDPL1__EHB_L 3U
+#define XHC_ERDPL1__EHB_R 3U
+#define XHC_ERDPL1__EHB_WIDTH 1U
+#define XHC_ERDPL1__EHB_RESETVALUE 0x0U
+#define XHC_ERDPL1__DESI_L 2U
+#define XHC_ERDPL1__DESI_R 0U
+#define XHC_ERDPL1__DESI_WIDTH 3U
+#define XHC_ERDPL1__DESI_RESETVALUE 0x0U
+#define XHC_ERDPL1_WIDTH 32U
+#define XHC_ERDPL1__WIDTH 32U
+#define XHC_ERDPL1_ALL_L 31U
+#define XHC_ERDPL1_ALL_R 0U
+#define XHC_ERDPL1__ALL_L 31U
+#define XHC_ERDPL1__ALL_R 0U
+#define XHC_ERDPL1_DATAMASK 0xffffffffU
+#define XHC_ERDPL1_RDWRMASK 0x00000000U
+#define XHC_ERDPL1_RESETVALUE 0x00000000U
+
+#define XHC_ERDPH1_OFFSET 0x4fcU
+#define XHC_ERDPH1_BASE 0x4fcU
+#define XHC_ERDPH1__DPH_L 31U
+#define XHC_ERDPH1__DPH_R 0U
+#define XHC_ERDPH1__DPH_WIDTH 32U
+#define XHC_ERDPH1__DPH_RESETVALUE 0x00000000U
+#define XHC_ERDPH1_WIDTH 32U
+#define XHC_ERDPH1__WIDTH 32U
+#define XHC_ERDPH1_ALL_L 31U
+#define XHC_ERDPH1_ALL_R 0U
+#define XHC_ERDPH1__ALL_L 31U
+#define XHC_ERDPH1__ALL_R 0U
+#define XHC_ERDPH1_DATAMASK 0xffffffffU
+#define XHC_ERDPH1_RDWRMASK 0x00000000U
+#define XHC_ERDPH1_RESETVALUE 0x00000000U
+
+#define XHC_DBLCMD_OFFSET 0x8c0U
+#define XHC_DBLCMD_BASE 0x8c0U
+#define XHC_DBLCMD__SID_L 31U
+#define XHC_DBLCMD__SID_R 16U
+#define XHC_DBLCMD__SID_WIDTH 16U
+#define XHC_DBLCMD__SID_RESETVALUE 0x0000U
+#define XHC_DBLCMD__reserved_L 15U
+#define XHC_DBLCMD__reserved_R 8U
+#define XHC_DBLCMD__reserved_WIDTH 8U
+#define XHC_DBLCMD__reserved_RESETVALUE 0x00U
+#define XHC_DBLCMD__TGT_L 7U
+#define XHC_DBLCMD__TGT_R 0U
+#define XHC_DBLCMD__TGT_WIDTH 8U
+#define XHC_DBLCMD__TGT_RESETVALUE 0x00U
+#define XHC_DBLCMD_WIDTH 32U
+#define XHC_DBLCMD__WIDTH 32U
+#define XHC_DBLCMD_ALL_L 31U
+#define XHC_DBLCMD_ALL_R 0U
+#define XHC_DBLCMD__ALL_L 31U
+#define XHC_DBLCMD__ALL_R 0U
+#define XHC_DBLCMD_DATAMASK 0xffffffffU
+#define XHC_DBLCMD_RDWRMASK 0x00000000U
+#define XHC_DBLCMD_RESETVALUE 0x00000000U
+
+#define XHC_DBLDVX1_OFFSET 0x8c4U
+#define XHC_DBLDVX1_BASE 0x8c4U
+#define XHC_DBLDVX1__SID_L 31U
+#define XHC_DBLDVX1__SID_R 16U
+#define XHC_DBLDVX1__SID_WIDTH 16U
+#define XHC_DBLDVX1__SID_RESETVALUE 0x0000U
+#define XHC_DBLDVX1__reserved_L 15U
+#define XHC_DBLDVX1__reserved_R 8U
+#define XHC_DBLDVX1__reserved_WIDTH 8U
+#define XHC_DBLDVX1__reserved_RESETVALUE 0x00U
+#define XHC_DBLDVX1__TGT_L 7U
+#define XHC_DBLDVX1__TGT_R 0U
+#define XHC_DBLDVX1__TGT_WIDTH 8U
+#define XHC_DBLDVX1__TGT_RESETVALUE 0x00U
+#define XHC_DBLDVX1_WIDTH 32U
+#define XHC_DBLDVX1__WIDTH 32U
+#define XHC_DBLDVX1_ALL_L 31U
+#define XHC_DBLDVX1_ALL_R 0U
+#define XHC_DBLDVX1__ALL_L 31U
+#define XHC_DBLDVX1__ALL_R 0U
+#define XHC_DBLDVX1_DATAMASK 0xffffffffU
+#define XHC_DBLDVX1_RDWRMASK 0x00000000U
+#define XHC_DBLDVX1_RESETVALUE 0x00000000U
+
+#define XHC_DBLDVX2_OFFSET 0x8c8U
+#define XHC_DBLDVX2_BASE 0x8c8U
+#define XHC_DBLDVX2__SID_L 31U
+#define XHC_DBLDVX2__SID_R 16U
+#define XHC_DBLDVX2__SID_WIDTH 16U
+#define XHC_DBLDVX2__SID_RESETVALUE 0x0000U
+#define XHC_DBLDVX2__reserved_L 15U
+#define XHC_DBLDVX2__reserved_R 8U
+#define XHC_DBLDVX2__reserved_WIDTH 8U
+#define XHC_DBLDVX2__reserved_RESETVALUE 0x00U
+#define XHC_DBLDVX2__TGT_L 7U
+#define XHC_DBLDVX2__TGT_R 0U
+#define XHC_DBLDVX2__TGT_WIDTH 8U
+#define XHC_DBLDVX2__TGT_RESETVALUE 0x00U
+#define XHC_DBLDVX2_WIDTH 32U
+#define XHC_DBLDVX2__WIDTH 32U
+#define XHC_DBLDVX2_ALL_L 31U
+#define XHC_DBLDVX2_ALL_R 0U
+#define XHC_DBLDVX2__ALL_L 31U
+#define XHC_DBLDVX2__ALL_R 0U
+#define XHC_DBLDVX2_DATAMASK 0xffffffffU
+#define XHC_DBLDVX2_RDWRMASK 0x00000000U
+#define XHC_DBLDVX2_RESETVALUE 0x00000000U
+
+#define XHC_DBLDVX3_OFFSET 0x8ccU
+#define XHC_DBLDVX3_BASE 0x8ccU
+#define XHC_DBLDVX3__SID_L 31U
+#define XHC_DBLDVX3__SID_R 16U
+#define XHC_DBLDVX3__SID_WIDTH 16U
+#define XHC_DBLDVX3__SID_RESETVALUE 0x0000U
+#define XHC_DBLDVX3__reserved_L 15U
+#define XHC_DBLDVX3__reserved_R 8U
+#define XHC_DBLDVX3__reserved_WIDTH 8U
+#define XHC_DBLDVX3__reserved_RESETVALUE 0x00U
+#define XHC_DBLDVX3__TGT_L 7U
+#define XHC_DBLDVX3__TGT_R 0U
+#define XHC_DBLDVX3__TGT_WIDTH 8U
+#define XHC_DBLDVX3__TGT_RESETVALUE 0x00U
+#define XHC_DBLDVX3_WIDTH 32U
+#define XHC_DBLDVX3__WIDTH 32U
+#define XHC_DBLDVX3_ALL_L 31U
+#define XHC_DBLDVX3_ALL_R 0U
+#define XHC_DBLDVX3__ALL_L 31U
+#define XHC_DBLDVX3__ALL_R 0U
+#define XHC_DBLDVX3_DATAMASK 0xffffffffU
+#define XHC_DBLDVX3_RDWRMASK 0x00000000U
+#define XHC_DBLDVX3_RESETVALUE 0x00000000U
+
+#define XHC_DBLDVX4_OFFSET 0x8d0U
+#define XHC_DBLDVX4_BASE 0x8d0U
+#define XHC_DBLDVX4__SID_L 31U
+#define XHC_DBLDVX4__SID_R 16U
+#define XHC_DBLDVX4__SID_WIDTH 16U
+#define XHC_DBLDVX4__SID_RESETVALUE 0x0000U
+#define XHC_DBLDVX4__reserved_L 15U
+#define XHC_DBLDVX4__reserved_R 8U
+#define XHC_DBLDVX4__reserved_WIDTH 8U
+#define XHC_DBLDVX4__reserved_RESETVALUE 0x00U
+#define XHC_DBLDVX4__TGT_L 7U
+#define XHC_DBLDVX4__TGT_R 0U
+#define XHC_DBLDVX4__TGT_WIDTH 8U
+#define XHC_DBLDVX4__TGT_RESETVALUE 0x00U
+#define XHC_DBLDVX4_WIDTH 32U
+#define XHC_DBLDVX4__WIDTH 32U
+#define XHC_DBLDVX4_ALL_L 31U
+#define XHC_DBLDVX4_ALL_R 0U
+#define XHC_DBLDVX4__ALL_L 31U
+#define XHC_DBLDVX4__ALL_R 0U
+#define XHC_DBLDVX4_DATAMASK 0xffffffffU
+#define XHC_DBLDVX4_RDWRMASK 0x00000000U
+#define XHC_DBLDVX4_RESETVALUE 0x00000000U
+
+#define XHC_DBLDVX5_OFFSET 0x8d4U
+#define XHC_DBLDVX5_BASE 0x8d4U
+#define XHC_DBLDVX5__SID_L 31U
+#define XHC_DBLDVX5__SID_R 16U
+#define XHC_DBLDVX5__SID_WIDTH 16U
+#define XHC_DBLDVX5__SID_RESETVALUE 0x0000U
+#define XHC_DBLDVX5__reserved_L 15U
+#define XHC_DBLDVX5__reserved_R 8U
+#define XHC_DBLDVX5__reserved_WIDTH 8U
+#define XHC_DBLDVX5__reserved_RESETVALUE 0x00U
+#define XHC_DBLDVX5__TGT_L 7U
+#define XHC_DBLDVX5__TGT_R 0U
+#define XHC_DBLDVX5__TGT_WIDTH 8U
+#define XHC_DBLDVX5__TGT_RESETVALUE 0x00U
+#define XHC_DBLDVX5_WIDTH 32U
+#define XHC_DBLDVX5__WIDTH 32U
+#define XHC_DBLDVX5_ALL_L 31U
+#define XHC_DBLDVX5_ALL_R 0U
+#define XHC_DBLDVX5__ALL_L 31U
+#define XHC_DBLDVX5__ALL_R 0U
+#define XHC_DBLDVX5_DATAMASK 0xffffffffU
+#define XHC_DBLDVX5_RDWRMASK 0x00000000U
+#define XHC_DBLDVX5_RESETVALUE 0x00000000U
+
+#define XHC_DBLDVX6_OFFSET 0x8d8U
+#define XHC_DBLDVX6_BASE 0x8d8U
+#define XHC_DBLDVX6__SID_L 31U
+#define XHC_DBLDVX6__SID_R 16U
+#define XHC_DBLDVX6__SID_WIDTH 16U
+#define XHC_DBLDVX6__SID_RESETVALUE 0x0000U
+#define XHC_DBLDVX6__reserved_L 15U
+#define XHC_DBLDVX6__reserved_R 8U
+#define XHC_DBLDVX6__reserved_WIDTH 8U
+#define XHC_DBLDVX6__reserved_RESETVALUE 0x00U
+#define XHC_DBLDVX6__TGT_L 7U
+#define XHC_DBLDVX6__TGT_R 0U
+#define XHC_DBLDVX6__TGT_WIDTH 8U
+#define XHC_DBLDVX6__TGT_RESETVALUE 0x00U
+#define XHC_DBLDVX6_WIDTH 32U
+#define XHC_DBLDVX6__WIDTH 32U
+#define XHC_DBLDVX6_ALL_L 31U
+#define XHC_DBLDVX6_ALL_R 0U
+#define XHC_DBLDVX6__ALL_L 31U
+#define XHC_DBLDVX6__ALL_R 0U
+#define XHC_DBLDVX6_DATAMASK 0xffffffffU
+#define XHC_DBLDVX6_RDWRMASK 0x00000000U
+#define XHC_DBLDVX6_RESETVALUE 0x00000000U
+
+#define XHC_DBLDVX7_OFFSET 0x8dcU
+#define XHC_DBLDVX7_BASE 0x8dcU
+#define XHC_DBLDVX7__SID_L 31U
+#define XHC_DBLDVX7__SID_R 16U
+#define XHC_DBLDVX7__SID_WIDTH 16U
+#define XHC_DBLDVX7__SID_RESETVALUE 0x0000U
+#define XHC_DBLDVX7__reserved_L 15U
+#define XHC_DBLDVX7__reserved_R 8U
+#define XHC_DBLDVX7__reserved_WIDTH 8U
+#define XHC_DBLDVX7__reserved_RESETVALUE 0x00U
+#define XHC_DBLDVX7__TGT_L 7U
+#define XHC_DBLDVX7__TGT_R 0U
+#define XHC_DBLDVX7__TGT_WIDTH 8U
+#define XHC_DBLDVX7__TGT_RESETVALUE 0x00U
+#define XHC_DBLDVX7_WIDTH 32U
+#define XHC_DBLDVX7__WIDTH 32U
+#define XHC_DBLDVX7_ALL_L 31U
+#define XHC_DBLDVX7_ALL_R 0U
+#define XHC_DBLDVX7__ALL_L 31U
+#define XHC_DBLDVX7__ALL_R 0U
+#define XHC_DBLDVX7_DATAMASK 0xffffffffU
+#define XHC_DBLDVX7_RDWRMASK 0x00000000U
+#define XHC_DBLDVX7_RESETVALUE 0x00000000U
+
+#define XHC_DBLDVX8_OFFSET 0x8e0U
+#define XHC_DBLDVX8_BASE 0x8e0U
+#define XHC_DBLDVX8__SID_L 31U
+#define XHC_DBLDVX8__SID_R 16U
+#define XHC_DBLDVX8__SID_WIDTH 16U
+#define XHC_DBLDVX8__SID_RESETVALUE 0x0000U
+#define XHC_DBLDVX8__reserved_L 15U
+#define XHC_DBLDVX8__reserved_R 8U
+#define XHC_DBLDVX8__reserved_WIDTH 8U
+#define XHC_DBLDVX8__reserved_RESETVALUE 0x00U
+#define XHC_DBLDVX8__TGT_L 7U
+#define XHC_DBLDVX8__TGT_R 0U
+#define XHC_DBLDVX8__TGT_WIDTH 8U
+#define XHC_DBLDVX8__TGT_RESETVALUE 0x00U
+#define XHC_DBLDVX8_WIDTH 32U
+#define XHC_DBLDVX8__WIDTH 32U
+#define XHC_DBLDVX8_ALL_L 31U
+#define XHC_DBLDVX8_ALL_R 0U
+#define XHC_DBLDVX8__ALL_L 31U
+#define XHC_DBLDVX8__ALL_R 0U
+#define XHC_DBLDVX8_DATAMASK 0xffffffffU
+#define XHC_DBLDVX8_RDWRMASK 0x00000000U
+#define XHC_DBLDVX8_RESETVALUE 0x00000000U
+
+#define XHC_DBLDVX9_OFFSET 0x8e4U
+#define XHC_DBLDVX9_BASE 0x8e4U
+#define XHC_DBLDVX9__SID_L 31U
+#define XHC_DBLDVX9__SID_R 16U
+#define XHC_DBLDVX9__SID_WIDTH 16U
+#define XHC_DBLDVX9__SID_RESETVALUE 0x0000U
+#define XHC_DBLDVX9__reserved_L 15U
+#define XHC_DBLDVX9__reserved_R 8U
+#define XHC_DBLDVX9__reserved_WIDTH 8U
+#define XHC_DBLDVX9__reserved_RESETVALUE 0x00U
+#define XHC_DBLDVX9__TGT_L 7U
+#define XHC_DBLDVX9__TGT_R 0U
+#define XHC_DBLDVX9__TGT_WIDTH 8U
+#define XHC_DBLDVX9__TGT_RESETVALUE 0x00U
+#define XHC_DBLDVX9_WIDTH 32U
+#define XHC_DBLDVX9__WIDTH 32U
+#define XHC_DBLDVX9_ALL_L 31U
+#define XHC_DBLDVX9_ALL_R 0U
+#define XHC_DBLDVX9__ALL_L 31U
+#define XHC_DBLDVX9__ALL_R 0U
+#define XHC_DBLDVX9_DATAMASK 0xffffffffU
+#define XHC_DBLDVX9_RDWRMASK 0x00000000U
+#define XHC_DBLDVX9_RESETVALUE 0x00000000U
+
+#define XHC_DBLDVX10_OFFSET 0x8e8U
+#define XHC_DBLDVX10_BASE 0x8e8U
+#define XHC_DBLDVX10__SID_L 31U
+#define XHC_DBLDVX10__SID_R 16U
+#define XHC_DBLDVX10__SID_WIDTH 16U
+#define XHC_DBLDVX10__SID_RESETVALUE 0x0000U
+#define XHC_DBLDVX10__reserved_L 15U
+#define XHC_DBLDVX10__reserved_R 8U
+#define XHC_DBLDVX10__reserved_WIDTH 8U
+#define XHC_DBLDVX10__reserved_RESETVALUE 0x00U
+#define XHC_DBLDVX10__TGT_L 7U
+#define XHC_DBLDVX10__TGT_R 0U
+#define XHC_DBLDVX10__TGT_WIDTH 8U
+#define XHC_DBLDVX10__TGT_RESETVALUE 0x00U
+#define XHC_DBLDVX10_WIDTH 32U
+#define XHC_DBLDVX10__WIDTH 32U
+#define XHC_DBLDVX10_ALL_L 31U
+#define XHC_DBLDVX10_ALL_R 0U
+#define XHC_DBLDVX10__ALL_L 31U
+#define XHC_DBLDVX10__ALL_R 0U
+#define XHC_DBLDVX10_DATAMASK 0xffffffffU
+#define XHC_DBLDVX10_RDWRMASK 0x00000000U
+#define XHC_DBLDVX10_RESETVALUE 0x00000000U
+
+#define XHC_DBLDVX11_OFFSET 0x8ecU
+#define XHC_DBLDVX11_BASE 0x8ecU
+#define XHC_DBLDVX11__SID_L 31U
+#define XHC_DBLDVX11__SID_R 16U
+#define XHC_DBLDVX11__SID_WIDTH 16U
+#define XHC_DBLDVX11__SID_RESETVALUE 0x0000U
+#define XHC_DBLDVX11__reserved_L 15U
+#define XHC_DBLDVX11__reserved_R 8U
+#define XHC_DBLDVX11__reserved_WIDTH 8U
+#define XHC_DBLDVX11__reserved_RESETVALUE 0x00U
+#define XHC_DBLDVX11__TGT_L 7U
+#define XHC_DBLDVX11__TGT_R 0U
+#define XHC_DBLDVX11__TGT_WIDTH 8U
+#define XHC_DBLDVX11__TGT_RESETVALUE 0x00U
+#define XHC_DBLDVX11_WIDTH 32U
+#define XHC_DBLDVX11__WIDTH 32U
+#define XHC_DBLDVX11_ALL_L 31U
+#define XHC_DBLDVX11_ALL_R 0U
+#define XHC_DBLDVX11__ALL_L 31U
+#define XHC_DBLDVX11__ALL_R 0U
+#define XHC_DBLDVX11_DATAMASK 0xffffffffU
+#define XHC_DBLDVX11_RDWRMASK 0x00000000U
+#define XHC_DBLDVX11_RESETVALUE 0x00000000U
+
+#define XHC_DBLDVX12_OFFSET 0x8f0U
+#define XHC_DBLDVX12_BASE 0x8f0U
+#define XHC_DBLDVX12__SID_L 31U
+#define XHC_DBLDVX12__SID_R 16U
+#define XHC_DBLDVX12__SID_WIDTH 16U
+#define XHC_DBLDVX12__SID_RESETVALUE 0x0000U
+#define XHC_DBLDVX12__reserved_L 15U
+#define XHC_DBLDVX12__reserved_R 8U
+#define XHC_DBLDVX12__reserved_WIDTH 8U
+#define XHC_DBLDVX12__reserved_RESETVALUE 0x00U
+#define XHC_DBLDVX12__TGT_L 7U
+#define XHC_DBLDVX12__TGT_R 0U
+#define XHC_DBLDVX12__TGT_WIDTH 8U
+#define XHC_DBLDVX12__TGT_RESETVALUE 0x00U
+#define XHC_DBLDVX12_WIDTH 32U
+#define XHC_DBLDVX12__WIDTH 32U
+#define XHC_DBLDVX12_ALL_L 31U
+#define XHC_DBLDVX12_ALL_R 0U
+#define XHC_DBLDVX12__ALL_L 31U
+#define XHC_DBLDVX12__ALL_R 0U
+#define XHC_DBLDVX12_DATAMASK 0xffffffffU
+#define XHC_DBLDVX12_RDWRMASK 0x00000000U
+#define XHC_DBLDVX12_RESETVALUE 0x00000000U
+
+#define XHC_DBLDVX13_OFFSET 0x8f4U
+#define XHC_DBLDVX13_BASE 0x8f4U
+#define XHC_DBLDVX13__SID_L 31U
+#define XHC_DBLDVX13__SID_R 16U
+#define XHC_DBLDVX13__SID_WIDTH 16U
+#define XHC_DBLDVX13__SID_RESETVALUE 0x0000U
+#define XHC_DBLDVX13__reserved_L 15U
+#define XHC_DBLDVX13__reserved_R 8U
+#define XHC_DBLDVX13__reserved_WIDTH 8U
+#define XHC_DBLDVX13__reserved_RESETVALUE 0x00U
+#define XHC_DBLDVX13__TGT_L 7U
+#define XHC_DBLDVX13__TGT_R 0U
+#define XHC_DBLDVX13__TGT_WIDTH 8U
+#define XHC_DBLDVX13__TGT_RESETVALUE 0x00U
+#define XHC_DBLDVX13_WIDTH 32U
+#define XHC_DBLDVX13__WIDTH 32U
+#define XHC_DBLDVX13_ALL_L 31U
+#define XHC_DBLDVX13_ALL_R 0U
+#define XHC_DBLDVX13__ALL_L 31U
+#define XHC_DBLDVX13__ALL_R 0U
+#define XHC_DBLDVX13_DATAMASK 0xffffffffU
+#define XHC_DBLDVX13_RDWRMASK 0x00000000U
+#define XHC_DBLDVX13_RESETVALUE 0x00000000U
+
+#define XHC_DBLDVX14_OFFSET 0x8f8U
+#define XHC_DBLDVX14_BASE 0x8f8U
+#define XHC_DBLDVX14__SID_L 31U
+#define XHC_DBLDVX14__SID_R 16U
+#define XHC_DBLDVX14__SID_WIDTH 16U
+#define XHC_DBLDVX14__SID_RESETVALUE 0x0000U
+#define XHC_DBLDVX14__reserved_L 15U
+#define XHC_DBLDVX14__reserved_R 8U
+#define XHC_DBLDVX14__reserved_WIDTH 8U
+#define XHC_DBLDVX14__reserved_RESETVALUE 0x00U
+#define XHC_DBLDVX14__TGT_L 7U
+#define XHC_DBLDVX14__TGT_R 0U
+#define XHC_DBLDVX14__TGT_WIDTH 8U
+#define XHC_DBLDVX14__TGT_RESETVALUE 0x00U
+#define XHC_DBLDVX14_WIDTH 32U
+#define XHC_DBLDVX14__WIDTH 32U
+#define XHC_DBLDVX14_ALL_L 31U
+#define XHC_DBLDVX14_ALL_R 0U
+#define XHC_DBLDVX14__ALL_L 31U
+#define XHC_DBLDVX14__ALL_R 0U
+#define XHC_DBLDVX14_DATAMASK 0xffffffffU
+#define XHC_DBLDVX14_RDWRMASK 0x00000000U
+#define XHC_DBLDVX14_RESETVALUE 0x00000000U
+
+#define XHC_DBLDVX15_OFFSET 0x8fcU
+#define XHC_DBLDVX15_BASE 0x8fcU
+#define XHC_DBLDVX15__SID_L 31U
+#define XHC_DBLDVX15__SID_R 16U
+#define XHC_DBLDVX15__SID_WIDTH 16U
+#define XHC_DBLDVX15__SID_RESETVALUE 0x0000U
+#define XHC_DBLDVX15__reserved_L 15U
+#define XHC_DBLDVX15__reserved_R 8U
+#define XHC_DBLDVX15__reserved_WIDTH 8U
+#define XHC_DBLDVX15__reserved_RESETVALUE 0x00U
+#define XHC_DBLDVX15__TGT_L 7U
+#define XHC_DBLDVX15__TGT_R 0U
+#define XHC_DBLDVX15__TGT_WIDTH 8U
+#define XHC_DBLDVX15__TGT_RESETVALUE 0x00U
+#define XHC_DBLDVX15_WIDTH 32U
+#define XHC_DBLDVX15__WIDTH 32U
+#define XHC_DBLDVX15_ALL_L 31U
+#define XHC_DBLDVX15_ALL_R 0U
+#define XHC_DBLDVX15__ALL_L 31U
+#define XHC_DBLDVX15__ALL_R 0U
+#define XHC_DBLDVX15_DATAMASK 0xffffffffU
+#define XHC_DBLDVX15_RDWRMASK 0x00000000U
+#define XHC_DBLDVX15_RESETVALUE 0x00000000U
+
+#define XHC_DBLDVX16_OFFSET 0x900U
+#define XHC_DBLDVX16_BASE 0x900U
+#define XHC_DBLDVX16__SID_L 31U
+#define XHC_DBLDVX16__SID_R 16U
+#define XHC_DBLDVX16__SID_WIDTH 16U
+#define XHC_DBLDVX16__SID_RESETVALUE 0x0000U
+#define XHC_DBLDVX16__reserved_L 15U
+#define XHC_DBLDVX16__reserved_R 8U
+#define XHC_DBLDVX16__reserved_WIDTH 8U
+#define XHC_DBLDVX16__reserved_RESETVALUE 0x00U
+#define XHC_DBLDVX16__TGT_L 7U
+#define XHC_DBLDVX16__TGT_R 0U
+#define XHC_DBLDVX16__TGT_WIDTH 8U
+#define XHC_DBLDVX16__TGT_RESETVALUE 0x00U
+#define XHC_DBLDVX16_WIDTH 32U
+#define XHC_DBLDVX16__WIDTH 32U
+#define XHC_DBLDVX16_ALL_L 31U
+#define XHC_DBLDVX16_ALL_R 0U
+#define XHC_DBLDVX16__ALL_L 31U
+#define XHC_DBLDVX16__ALL_R 0U
+#define XHC_DBLDVX16_DATAMASK 0xffffffffU
+#define XHC_DBLDVX16_RDWRMASK 0x00000000U
+#define XHC_DBLDVX16_RESETVALUE 0x00000000U
+
+#define XHC_ECHSPT3_OFFSET 0x940U
+#define XHC_ECHSPT3_BASE 0x940U
+#define XHC_ECHSPT3__RMAJ_L 31U
+#define XHC_ECHSPT3__RMAJ_R 24U
+#define XHC_ECHSPT3__RMAJ_WIDTH 8U
+#define XHC_ECHSPT3__RMAJ_RESETVALUE 0x00U
+#define XHC_ECHSPT3__RMIN_L 23U
+#define XHC_ECHSPT3__RMIN_R 16U
+#define XHC_ECHSPT3__RMIN_WIDTH 8U
+#define XHC_ECHSPT3__RMIN_RESETVALUE 0x00U
+#define XHC_ECHSPT3__NCP_L 15U
+#define XHC_ECHSPT3__NCP_R 8U
+#define XHC_ECHSPT3__NCP_WIDTH 8U
+#define XHC_ECHSPT3__NCP_RESETVALUE 0x00U
+#define XHC_ECHSPT3__CID_L 7U
+#define XHC_ECHSPT3__CID_R 0U
+#define XHC_ECHSPT3__CID_WIDTH 8U
+#define XHC_ECHSPT3__CID_RESETVALUE 0x02U
+#define XHC_ECHSPT3_WIDTH 32U
+#define XHC_ECHSPT3__WIDTH 32U
+#define XHC_ECHSPT3_ALL_L 31U
+#define XHC_ECHSPT3_ALL_R 0U
+#define XHC_ECHSPT3__ALL_L 31U
+#define XHC_ECHSPT3__ALL_R 0U
+#define XHC_ECHSPT3_DATAMASK 0xffffffffU
+#define XHC_ECHSPT3_RDWRMASK 0x00000000U
+#define XHC_ECHSPT3_RESETVALUE 0x00000002U
+
+#define XHC_PNSTR3_OFFSET 0x944U
+#define XHC_PNSTR3_BASE 0x944U
+#define XHC_PNSTR3__STR_L 31U
+#define XHC_PNSTR3__STR_R 0U
+#define XHC_PNSTR3__STR_WIDTH 32U
+#define XHC_PNSTR3__STR_RESETVALUE 0x20425355U
+#define XHC_PNSTR3_WIDTH 32U
+#define XHC_PNSTR3__WIDTH 32U
+#define XHC_PNSTR3_ALL_L 31U
+#define XHC_PNSTR3_ALL_R 0U
+#define XHC_PNSTR3__ALL_L 31U
+#define XHC_PNSTR3__ALL_R 0U
+#define XHC_PNSTR3_DATAMASK 0xffffffffU
+#define XHC_PNSTR3_RDWRMASK 0x00000000U
+#define XHC_PNSTR3_RESETVALUE 0x20425355U
+
+#define XHC_PSUM3_OFFSET 0x948U
+#define XHC_PSUM3_BASE 0x948U
+#define XHC_PSUM3__PSIC_L 31U
+#define XHC_PSUM3__PSIC_R 28U
+#define XHC_PSUM3__PSIC_WIDTH 4U
+#define XHC_PSUM3__PSIC_RESETVALUE 0x0U
+#define XHC_PSUM3__MHD_L 27U
+#define XHC_PSUM3__MHD_R 25U
+#define XHC_PSUM3__MHD_WIDTH 3U
+#define XHC_PSUM3__MHD_RESETVALUE 0x0U
+#define XHC_PSUM3__BLC 20U
+#define XHC_PSUM3__BLC_L 20U
+#define XHC_PSUM3__BLC_R 20U
+#define XHC_PSUM3__BLC_WIDTH 1U
+#define XHC_PSUM3__BLC_RESETVALUE 0x0U
+#define XHC_PSUM3__HLC 19U
+#define XHC_PSUM3__HLC_L 19U
+#define XHC_PSUM3__HLC_R 19U
+#define XHC_PSUM3__HLC_WIDTH 1U
+#define XHC_PSUM3__HLC_RESETVALUE 0x1U
+#define XHC_PSUM3__IHI 18U
+#define XHC_PSUM3__IHI_L 18U
+#define XHC_PSUM3__IHI_R 18U
+#define XHC_PSUM3__IHI_WIDTH 1U
+#define XHC_PSUM3__IHI_RESETVALUE 0x0U
+#define XHC_PSUM3__HSO 17U
+#define XHC_PSUM3__HSO_L 17U
+#define XHC_PSUM3__HSO_R 17U
+#define XHC_PSUM3__HSO_WIDTH 1U
+#define XHC_PSUM3__HSO_RESETVALUE 0x0U
+#define XHC_PSUM3__reserved 16U
+#define XHC_PSUM3__reserved_L 16U
+#define XHC_PSUM3__reserved_R 16U
+#define XHC_PSUM3__reserved_WIDTH 1U
+#define XHC_PSUM3__reserved_RESETVALUE 0x0U
+#define XHC_PSUM3__CPC_L 15U
+#define XHC_PSUM3__CPC_R 8U
+#define XHC_PSUM3__CPC_WIDTH 8U
+#define XHC_PSUM3__CPC_RESETVALUE 0x00U
+#define XHC_PSUM3__CPO_L 7U
+#define XHC_PSUM3__CPO_R 0U
+#define XHC_PSUM3__CPO_WIDTH 8U
+#define XHC_PSUM3__CPO_RESETVALUE 0x00U
+#define XHC_PSUM3__RESERVED_L 24U
+#define XHC_PSUM3__RESERVED_R 21U
+#define XHC_PSUM3_WIDTH 32U
+#define XHC_PSUM3__WIDTH 32U
+#define XHC_PSUM3_ALL_L 31U
+#define XHC_PSUM3_ALL_R 0U
+#define XHC_PSUM3__ALL_L 31U
+#define XHC_PSUM3__ALL_R 0U
+#define XHC_PSUM3_DATAMASK 0xfe1fffffU
+#define XHC_PSUM3_RDWRMASK 0x01e00000U
+#define XHC_PSUM3_RESETVALUE 0x00080000U
+
+#define XHC_PTSLTYP3_OFFSET 0x94cU
+#define XHC_PTSLTYP3_BASE 0x94cU
+#define XHC_PTSLTYP3__reserved_L 31U
+#define XHC_PTSLTYP3__reserved_R 5U
+#define XHC_PTSLTYP3__reserved_WIDTH 27U
+#define XHC_PTSLTYP3__reserved_RESETVALUE 0x0U
+#define XHC_PTSLTYP3__PST_L 4U
+#define XHC_PTSLTYP3__PST_R 0U
+#define XHC_PTSLTYP3__PST_WIDTH 5U
+#define XHC_PTSLTYP3__PST_RESETVALUE 0x0U
+#define XHC_PTSLTYP3_WIDTH 32U
+#define XHC_PTSLTYP3__WIDTH 32U
+#define XHC_PTSLTYP3_ALL_L 31U
+#define XHC_PTSLTYP3_ALL_R 0U
+#define XHC_PTSLTYP3__ALL_L 31U
+#define XHC_PTSLTYP3__ALL_R 0U
+#define XHC_PTSLTYP3_DATAMASK 0xffffffffU
+#define XHC_PTSLTYP3_RDWRMASK 0x00000000U
+#define XHC_PTSLTYP3_RESETVALUE 0x00000000U
+
+#define XHC_ECHSPT2_OFFSET 0x950U
+#define XHC_ECHSPT2_BASE 0x950U
+#define XHC_ECHSPT2__RMAJ_L 31U
+#define XHC_ECHSPT2__RMAJ_R 24U
+#define XHC_ECHSPT2__RMAJ_WIDTH 8U
+#define XHC_ECHSPT2__RMAJ_RESETVALUE 0x00U
+#define XHC_ECHSPT2__RMIN_L 23U
+#define XHC_ECHSPT2__RMIN_R 16U
+#define XHC_ECHSPT2__RMIN_WIDTH 8U
+#define XHC_ECHSPT2__RMIN_RESETVALUE 0x00U
+#define XHC_ECHSPT2__NCP_L 15U
+#define XHC_ECHSPT2__NCP_R 8U
+#define XHC_ECHSPT2__NCP_WIDTH 8U
+#define XHC_ECHSPT2__NCP_RESETVALUE 0x00U
+#define XHC_ECHSPT2__CID_L 7U
+#define XHC_ECHSPT2__CID_R 0U
+#define XHC_ECHSPT2__CID_WIDTH 8U
+#define XHC_ECHSPT2__CID_RESETVALUE 0x02U
+#define XHC_ECHSPT2_WIDTH 32U
+#define XHC_ECHSPT2__WIDTH 32U
+#define XHC_ECHSPT2_ALL_L 31U
+#define XHC_ECHSPT2_ALL_R 0U
+#define XHC_ECHSPT2__ALL_L 31U
+#define XHC_ECHSPT2__ALL_R 0U
+#define XHC_ECHSPT2_DATAMASK 0xffffffffU
+#define XHC_ECHSPT2_RDWRMASK 0x00000000U
+#define XHC_ECHSPT2_RESETVALUE 0x00000002U
+
+#define XHC_PNSTR2_OFFSET 0x954U
+#define XHC_PNSTR2_BASE 0x954U
+#define XHC_PNSTR2__STR_L 31U
+#define XHC_PNSTR2__STR_R 0U
+#define XHC_PNSTR2__STR_WIDTH 32U
+#define XHC_PNSTR2__STR_RESETVALUE 0x20425355U
+#define XHC_PNSTR2_WIDTH 32U
+#define XHC_PNSTR2__WIDTH 32U
+#define XHC_PNSTR2_ALL_L 31U
+#define XHC_PNSTR2_ALL_R 0U
+#define XHC_PNSTR2__ALL_L 31U
+#define XHC_PNSTR2__ALL_R 0U
+#define XHC_PNSTR2_DATAMASK 0xffffffffU
+#define XHC_PNSTR2_RDWRMASK 0x00000000U
+#define XHC_PNSTR2_RESETVALUE 0x20425355U
+
+#define XHC_PSUM2_OFFSET 0x958U
+#define XHC_PSUM2_BASE 0x958U
+#define XHC_PSUM2__PSIC_L 31U
+#define XHC_PSUM2__PSIC_R 28U
+#define XHC_PSUM2__PSIC_WIDTH 4U
+#define XHC_PSUM2__PSIC_RESETVALUE 0x0U
+#define XHC_PSUM2__MHD_L 27U
+#define XHC_PSUM2__MHD_R 25U
+#define XHC_PSUM2__MHD_WIDTH 3U
+#define XHC_PSUM2__MHD_RESETVALUE 0x0U
+#define XHC_PSUM2__BLC 20U
+#define XHC_PSUM2__BLC_L 20U
+#define XHC_PSUM2__BLC_R 20U
+#define XHC_PSUM2__BLC_WIDTH 1U
+#define XHC_PSUM2__BLC_RESETVALUE 0x0U
+#define XHC_PSUM2__HLC 19U
+#define XHC_PSUM2__HLC_L 19U
+#define XHC_PSUM2__HLC_R 19U
+#define XHC_PSUM2__HLC_WIDTH 1U
+#define XHC_PSUM2__HLC_RESETVALUE 0x1U
+#define XHC_PSUM2__IHI 18U
+#define XHC_PSUM2__IHI_L 18U
+#define XHC_PSUM2__IHI_R 18U
+#define XHC_PSUM2__IHI_WIDTH 1U
+#define XHC_PSUM2__IHI_RESETVALUE 0x0U
+#define XHC_PSUM2__HSO 17U
+#define XHC_PSUM2__HSO_L 17U
+#define XHC_PSUM2__HSO_R 17U
+#define XHC_PSUM2__HSO_WIDTH 1U
+#define XHC_PSUM2__HSO_RESETVALUE 0x0U
+#define XHC_PSUM2__reserved 16U
+#define XHC_PSUM2__reserved_L 16U
+#define XHC_PSUM2__reserved_R 16U
+#define XHC_PSUM2__reserved_WIDTH 1U
+#define XHC_PSUM2__reserved_RESETVALUE 0x0U
+#define XHC_PSUM2__CPC_L 15U
+#define XHC_PSUM2__CPC_R 8U
+#define XHC_PSUM2__CPC_WIDTH 8U
+#define XHC_PSUM2__CPC_RESETVALUE 0x00U
+#define XHC_PSUM2__CPO_L 7U
+#define XHC_PSUM2__CPO_R 0U
+#define XHC_PSUM2__CPO_WIDTH 8U
+#define XHC_PSUM2__CPO_RESETVALUE 0x00U
+#define XHC_PSUM2__RESERVED_L 24U
+#define XHC_PSUM2__RESERVED_R 21U
+#define XHC_PSUM2_WIDTH 32U
+#define XHC_PSUM2__WIDTH 32U
+#define XHC_PSUM2_ALL_L 31U
+#define XHC_PSUM2_ALL_R 0U
+#define XHC_PSUM2__ALL_L 31U
+#define XHC_PSUM2__ALL_R 0U
+#define XHC_PSUM2_DATAMASK 0xfe1fffffU
+#define XHC_PSUM2_RDWRMASK 0x01e00000U
+#define XHC_PSUM2_RESETVALUE 0x00080000U
+
+#define XHC_PTSLTYP2_OFFSET 0x95cU
+#define XHC_PTSLTYP2_BASE 0x95cU
+#define XHC_PTSLTYP2__reserved_L 31U
+#define XHC_PTSLTYP2__reserved_R 5U
+#define XHC_PTSLTYP2__reserved_WIDTH 27U
+#define XHC_PTSLTYP2__reserved_RESETVALUE 0x0U
+#define XHC_PTSLTYP2__PST_L 4U
+#define XHC_PTSLTYP2__PST_R 0U
+#define XHC_PTSLTYP2__PST_WIDTH 5U
+#define XHC_PTSLTYP2__PST_RESETVALUE 0x0U
+#define XHC_PTSLTYP2_WIDTH 32U
+#define XHC_PTSLTYP2__WIDTH 32U
+#define XHC_PTSLTYP2_ALL_L 31U
+#define XHC_PTSLTYP2_ALL_R 0U
+#define XHC_PTSLTYP2__ALL_L 31U
+#define XHC_PTSLTYP2__ALL_R 0U
+#define XHC_PTSLTYP2_DATAMASK 0xffffffffU
+#define XHC_PTSLTYP2_RDWRMASK 0x00000000U
+#define XHC_PTSLTYP2_RESETVALUE 0x00000000U
+
+#define XHC_ECHRSVP_OFFSET 0x960U
+#define XHC_ECHRSVP_BASE 0x960U
+#define XHC_ECHRSVP__reserved_L 31U
+#define XHC_ECHRSVP__reserved_R 16U
+#define XHC_ECHRSVP__reserved_WIDTH 16U
+#define XHC_ECHRSVP__reserved_RESETVALUE 0x0000U
+#define XHC_ECHRSVP__NCP_L 15U
+#define XHC_ECHRSVP__NCP_R 8U
+#define XHC_ECHRSVP__NCP_WIDTH 8U
+#define XHC_ECHRSVP__NCP_RESETVALUE 0x00U
+#define XHC_ECHRSVP__CID_L 7U
+#define XHC_ECHRSVP__CID_R 0U
+#define XHC_ECHRSVP__CID_WIDTH 8U
+#define XHC_ECHRSVP__CID_RESETVALUE 0xffU
+#define XHC_ECHRSVP_WIDTH 32U
+#define XHC_ECHRSVP__WIDTH 32U
+#define XHC_ECHRSVP_ALL_L 31U
+#define XHC_ECHRSVP_ALL_R 0U
+#define XHC_ECHRSVP__ALL_L 31U
+#define XHC_ECHRSVP__ALL_R 0U
+#define XHC_ECHRSVP_DATAMASK 0xffffffffU
+#define XHC_ECHRSVP_RDWRMASK 0x00000000U
+#define XHC_ECHRSVP_RESETVALUE 0x000000ffU
+
+#define XHC_ECHRSVI_OFFSET 0x968U
+#define XHC_ECHRSVI_BASE 0x968U
+#define XHC_ECHRSVI__reserved_L 31U
+#define XHC_ECHRSVI__reserved_R 16U
+#define XHC_ECHRSVI__reserved_WIDTH 16U
+#define XHC_ECHRSVI__reserved_RESETVALUE 0x0000U
+#define XHC_ECHRSVI__NCP_L 15U
+#define XHC_ECHRSVI__NCP_R 8U
+#define XHC_ECHRSVI__NCP_WIDTH 8U
+#define XHC_ECHRSVI__NCP_RESETVALUE 0x00U
+#define XHC_ECHRSVI__CID_L 7U
+#define XHC_ECHRSVI__CID_R 0U
+#define XHC_ECHRSVI__CID_WIDTH 8U
+#define XHC_ECHRSVI__CID_RESETVALUE 0xffU
+#define XHC_ECHRSVI_WIDTH 32U
+#define XHC_ECHRSVI__WIDTH 32U
+#define XHC_ECHRSVI_ALL_L 31U
+#define XHC_ECHRSVI_ALL_R 0U
+#define XHC_ECHRSVI__ALL_L 31U
+#define XHC_ECHRSVI__ALL_R 0U
+#define XHC_ECHRSVI_DATAMASK 0xffffffffU
+#define XHC_ECHRSVI_RDWRMASK 0x00000000U
+#define XHC_ECHRSVI_RESETVALUE 0x000000ffU
+
+#define XHC_ECHRSVM_OFFSET 0xae8U
+#define XHC_ECHRSVM_BASE 0xae8U
+#define XHC_ECHRSVM__reserved_L 31U
+#define XHC_ECHRSVM__reserved_R 16U
+#define XHC_ECHRSVM__reserved_WIDTH 16U
+#define XHC_ECHRSVM__reserved_RESETVALUE 0x0000U
+#define XHC_ECHRSVM__NCP_L 15U
+#define XHC_ECHRSVM__NCP_R 8U
+#define XHC_ECHRSVM__NCP_WIDTH 8U
+#define XHC_ECHRSVM__NCP_RESETVALUE 0x00U
+#define XHC_ECHRSVM__CID_L 7U
+#define XHC_ECHRSVM__CID_R 0U
+#define XHC_ECHRSVM__CID_WIDTH 8U
+#define XHC_ECHRSVM__CID_RESETVALUE 0xffU
+#define XHC_ECHRSVM_WIDTH 32U
+#define XHC_ECHRSVM__WIDTH 32U
+#define XHC_ECHRSVM_ALL_L 31U
+#define XHC_ECHRSVM_ALL_R 0U
+#define XHC_ECHRSVM__ALL_L 31U
+#define XHC_ECHRSVM__ALL_R 0U
+#define XHC_ECHRSVM_DATAMASK 0xffffffffU
+#define XHC_ECHRSVM_RDWRMASK 0x00000000U
+#define XHC_ECHRSVM_RESETVALUE 0x000000ffU
+
+#define XHC_ECHRSVD_OFFSET 0xaf8U
+#define XHC_ECHRSVD_BASE 0xaf8U
+#define XHC_ECHRSVD__reserved_L 31U
+#define XHC_ECHRSVD__reserved_R 16U
+#define XHC_ECHRSVD__reserved_WIDTH 16U
+#define XHC_ECHRSVD__reserved_RESETVALUE 0x0000U
+#define XHC_ECHRSVD__NCP_L 15U
+#define XHC_ECHRSVD__NCP_R 8U
+#define XHC_ECHRSVD__NCP_WIDTH 8U
+#define XHC_ECHRSVD__NCP_RESETVALUE 0x00U
+#define XHC_ECHRSVD__CID_L 7U
+#define XHC_ECHRSVD__CID_R 0U
+#define XHC_ECHRSVD__CID_WIDTH 8U
+#define XHC_ECHRSVD__CID_RESETVALUE 0xffU
+#define XHC_ECHRSVD_WIDTH 32U
+#define XHC_ECHRSVD__WIDTH 32U
+#define XHC_ECHRSVD_ALL_L 31U
+#define XHC_ECHRSVD_ALL_R 0U
+#define XHC_ECHRSVD__ALL_L 31U
+#define XHC_ECHRSVD__ALL_R 0U
+#define XHC_ECHRSVD_DATAMASK 0xffffffffU
+#define XHC_ECHRSVD_RDWRMASK 0x00000000U
+#define XHC_ECHRSVD_RESETVALUE 0x000000ffU
+
+#define XHC_ECHRSVO_OFFSET 0xb38U
+#define XHC_ECHRSVO_BASE 0xb38U
+#define XHC_ECHRSVO__reserved_L 31U
+#define XHC_ECHRSVO__reserved_R 16U
+#define XHC_ECHRSVO__reserved_WIDTH 16U
+#define XHC_ECHRSVO__reserved_RESETVALUE 0x0000U
+#define XHC_ECHRSVO__NCP_L 15U
+#define XHC_ECHRSVO__NCP_R 8U
+#define XHC_ECHRSVO__NCP_WIDTH 8U
+#define XHC_ECHRSVO__NCP_RESETVALUE 0x00U
+#define XHC_ECHRSVO__CID_L 7U
+#define XHC_ECHRSVO__CID_R 0U
+#define XHC_ECHRSVO__CID_WIDTH 8U
+#define XHC_ECHRSVO__CID_RESETVALUE 0xffU
+#define XHC_ECHRSVO_WIDTH 32U
+#define XHC_ECHRSVO__WIDTH 32U
+#define XHC_ECHRSVO_ALL_L 31U
+#define XHC_ECHRSVO_ALL_R 0U
+#define XHC_ECHRSVO__ALL_L 31U
+#define XHC_ECHRSVO__ALL_R 0U
+#define XHC_ECHRSVO_DATAMASK 0xffffffffU
+#define XHC_ECHRSVO_RDWRMASK 0x00000000U
+#define XHC_ECHRSVO_RESETVALUE 0x000000ffU
+
+#define XHC_ECHCTT_OFFSET 0xbf0U
+#define XHC_ECHCTT_BASE 0xbf0U
+#define XHC_ECHCTT__reserved_L 31U
+#define XHC_ECHCTT__reserved_R 16U
+#define XHC_ECHCTT__reserved_WIDTH 16U
+#define XHC_ECHCTT__reserved_RESETVALUE 0x0000U
+#define XHC_ECHCTT__NCP_L 15U
+#define XHC_ECHCTT__NCP_R 8U
+#define XHC_ECHCTT__NCP_WIDTH 8U
+#define XHC_ECHCTT__NCP_RESETVALUE 0x04U
+#define XHC_ECHCTT__CID_L 7U
+#define XHC_ECHCTT__CID_R 0U
+#define XHC_ECHCTT__CID_WIDTH 8U
+#define XHC_ECHCTT__CID_RESETVALUE 0xe0U
+#define XHC_ECHCTT_WIDTH 32U
+#define XHC_ECHCTT__WIDTH 32U
+#define XHC_ECHCTT_ALL_L 31U
+#define XHC_ECHCTT_ALL_R 0U
+#define XHC_ECHCTT__ALL_L 31U
+#define XHC_ECHCTT__ALL_R 0U
+#define XHC_ECHCTT_DATAMASK 0xffffffffU
+#define XHC_ECHCTT_RDWRMASK 0x00000000U
+#define XHC_ECHCTT_RESETVALUE 0x000004e0U
+
+#define XHC_CTTMTS0_OFFSET 0xbf8U
+#define XHC_CTTMTS0_BASE 0xbf8U
+#define XHC_CTTMTS0__DCM 31U
+#define XHC_CTTMTS0__DCM_L 31U
+#define XHC_CTTMTS0__DCM_R 31U
+#define XHC_CTTMTS0__DCM_WIDTH 1U
+#define XHC_CTTMTS0__DCM_RESETVALUE 0x0U
+#define XHC_CTTMTS0__reserved_L 30U
+#define XHC_CTTMTS0__reserved_R 10U
+#define XHC_CTTMTS0__reserved_WIDTH 21U
+#define XHC_CTTMTS0__reserved_RESETVALUE 0x0U
+#define XHC_CTTMTS0__SLA_L 9U
+#define XHC_CTTMTS0__SLA_R 0U
+#define XHC_CTTMTS0__SLA_WIDTH 10U
+#define XHC_CTTMTS0__SLA_RESETVALUE 0x0U
+#define XHC_CTTMTS0_WIDTH 32U
+#define XHC_CTTMTS0__WIDTH 32U
+#define XHC_CTTMTS0_ALL_L 31U
+#define XHC_CTTMTS0_ALL_R 0U
+#define XHC_CTTMTS0__ALL_L 31U
+#define XHC_CTTMTS0__ALL_R 0U
+#define XHC_CTTMTS0_DATAMASK 0xffffffffU
+#define XHC_CTTMTS0_RDWRMASK 0x00000000U
+#define XHC_CTTMTS0_RESETVALUE 0x00000000U
+
+#define XHC_CTTMTS1_OFFSET 0xbfcU
+#define XHC_CTTMTS1_BASE 0xbfcU
+#define XHC_CTTMTS1__TXF_L 25U
+#define XHC_CTTMTS1__TXF_R 16U
+#define XHC_CTTMTS1__TXF_WIDTH 10U
+#define XHC_CTTMTS1__TXF_RESETVALUE 0x0U
+#define XHC_CTTMTS1__reserved_L 15U
+#define XHC_CTTMTS1__reserved_R 10U
+#define XHC_CTTMTS1__reserved_WIDTH 6U
+#define XHC_CTTMTS1__reserved_RESETVALUE 0x0U
+#define XHC_CTTMTS1__RXF_L 9U
+#define XHC_CTTMTS1__RXF_R 0U
+#define XHC_CTTMTS1__RXF_WIDTH 10U
+#define XHC_CTTMTS1__RXF_RESETVALUE 0x0U
+#define XHC_CTTMTS1__RESERVED_L 31U
+#define XHC_CTTMTS1__RESERVED_R 26U
+#define XHC_CTTMTS1_WIDTH 26U
+#define XHC_CTTMTS1__WIDTH 26U
+#define XHC_CTTMTS1_ALL_L 25U
+#define XHC_CTTMTS1_ALL_R 0U
+#define XHC_CTTMTS1__ALL_L 25U
+#define XHC_CTTMTS1__ALL_R 0U
+#define XHC_CTTMTS1_DATAMASK 0x03ffffffU
+#define XHC_CTTMTS1_RDWRMASK 0xfc000000U
+#define XHC_CTTMTS1_RESETVALUE 0x0000000U
+
+#define XHC_ECHBIU_OFFSET 0xc00U
+#define XHC_ECHBIU_BASE 0xc00U
+#define XHC_ECHBIU__CLK_L 31U
+#define XHC_ECHBIU__CLK_R 21U
+#define XHC_ECHBIU__CLK_WIDTH 11U
+#define XHC_ECHBIU__CLK_RESETVALUE 0x0U
+#define XHC_ECHBIU__reserved_L 20U
+#define XHC_ECHBIU__reserved_R 19U
+#define XHC_ECHBIU__reserved_WIDTH 2U
+#define XHC_ECHBIU__reserved_RESETVALUE 0x0U
+#define XHC_ECHBIU__WID_L 18U
+#define XHC_ECHBIU__WID_R 16U
+#define XHC_ECHBIU__WID_WIDTH 3U
+#define XHC_ECHBIU__WID_RESETVALUE 0x0U
+#define XHC_ECHBIU__NCP_L 15U
+#define XHC_ECHBIU__NCP_R 8U
+#define XHC_ECHBIU__NCP_WIDTH 8U
+#define XHC_ECHBIU__NCP_RESETVALUE 0x08U
+#define XHC_ECHBIU__CID_L 7U
+#define XHC_ECHBIU__CID_R 0U
+#define XHC_ECHBIU__CID_WIDTH 8U
+#define XHC_ECHBIU__CID_RESETVALUE 0xc0U
+#define XHC_ECHBIU_WIDTH 32U
+#define XHC_ECHBIU__WIDTH 32U
+#define XHC_ECHBIU_ALL_L 31U
+#define XHC_ECHBIU_ALL_R 0U
+#define XHC_ECHBIU__ALL_L 31U
+#define XHC_ECHBIU__ALL_R 0U
+#define XHC_ECHBIU_DATAMASK 0xffffffffU
+#define XHC_ECHBIU_RDWRMASK 0x00000000U
+#define XHC_ECHBIU_RESETVALUE 0x000008c0U
+
+#define XHC_BIUSPC_OFFSET 0xc04U
+#define XHC_BIUSPC_BASE 0xc04U
+#define XHC_BIUSPC__MAJ_L 31U
+#define XHC_BIUSPC__MAJ_R 28U
+#define XHC_BIUSPC__MAJ_WIDTH 4U
+#define XHC_BIUSPC__MAJ_RESETVALUE 0x0U
+#define XHC_BIUSPC__MIN_L 27U
+#define XHC_BIUSPC__MIN_R 24U
+#define XHC_BIUSPC__MIN_WIDTH 4U
+#define XHC_BIUSPC__MIN_RESETVALUE 0x0U
+#define XHC_BIUSPC__RLS_L 23U
+#define XHC_BIUSPC__RLS_R 20U
+#define XHC_BIUSPC__RLS_WIDTH 4U
+#define XHC_BIUSPC__RLS_RESETVALUE 0x0U
+#define XHC_BIUSPC__reserved_L 19U
+#define XHC_BIUSPC__reserved_R 4U
+#define XHC_BIUSPC__reserved_WIDTH 16U
+#define XHC_BIUSPC__reserved_RESETVALUE 0x0000U
+#define XHC_BIUSPC__SPI_L 3U
+#define XHC_BIUSPC__SPI_R 2U
+#define XHC_BIUSPC__SPI_WIDTH 2U
+#define XHC_BIUSPC__SPI_RESETVALUE 0x3U
+#define XHC_BIUSPC__TYP_L 1U
+#define XHC_BIUSPC__TYP_R 0U
+#define XHC_BIUSPC__TYP_WIDTH 2U
+#define XHC_BIUSPC__TYP_RESETVALUE 0x0U
+#define XHC_BIUSPC_WIDTH 32U
+#define XHC_BIUSPC__WIDTH 32U
+#define XHC_BIUSPC_ALL_L 31U
+#define XHC_BIUSPC_ALL_R 0U
+#define XHC_BIUSPC__ALL_L 31U
+#define XHC_BIUSPC__ALL_R 0U
+#define XHC_BIUSPC_DATAMASK 0xffffffffU
+#define XHC_BIUSPC_RDWRMASK 0x00000000U
+#define XHC_BIUSPC_RESETVALUE 0x0000000cU
+
+#define XHC_AXIWRA_OFFSET 0xc08U
+#define XHC_AXIWRA_BASE 0xc08U
+#define XHC_AXIWRA__WTS_L 31U
+#define XHC_AXIWRA__WTS_R 28U
+#define XHC_AXIWRA__WTS_WIDTH 4U
+#define XHC_AXIWRA__WTS_RESETVALUE 0x2U
+#define XHC_AXIWRA__WUA_L 24U
+#define XHC_AXIWRA__WUA_R 16U
+#define XHC_AXIWRA__WUA_WIDTH 9U
+#define XHC_AXIWRA__WUA_RESETVALUE 0x0U
+#define XHC_AXIWRA__reserved_L 15U
+#define XHC_AXIWRA__reserved_R 10U
+#define XHC_AXIWRA__reserved_WIDTH 6U
+#define XHC_AXIWRA__reserved_RESETVALUE 0x0U
+#define XHC_AXIWRA__BYP 9U
+#define XHC_AXIWRA__BYP_L 9U
+#define XHC_AXIWRA__BYP_R 9U
+#define XHC_AXIWRA__BYP_WIDTH 1U
+#define XHC_AXIWRA__BYP_RESETVALUE 0x0U
+#define XHC_AXIWRA__WSA_L 8U
+#define XHC_AXIWRA__WSA_R 0U
+#define XHC_AXIWRA__WSA_WIDTH 9U
+#define XHC_AXIWRA__WSA_RESETVALUE 0x0U
+#define XHC_AXIWRA__RESERVED_L 27U
+#define XHC_AXIWRA__RESERVED_R 25U
+#define XHC_AXIWRA_WIDTH 32U
+#define XHC_AXIWRA__WIDTH 32U
+#define XHC_AXIWRA_ALL_L 31U
+#define XHC_AXIWRA_ALL_R 0U
+#define XHC_AXIWRA__ALL_L 31U
+#define XHC_AXIWRA__ALL_R 0U
+#define XHC_AXIWRA_DATAMASK 0xf1ffffffU
+#define XHC_AXIWRA_RDWRMASK 0x0e000000U
+#define XHC_AXIWRA_RESETVALUE 0x20000000U
+
+#define XHC_AXIRDA_OFFSET 0xc0cU
+#define XHC_AXIRDA_BASE 0xc0cU
+#define XHC_AXIRDA__RTS_L 31U
+#define XHC_AXIRDA__RTS_R 28U
+#define XHC_AXIRDA__RTS_WIDTH 4U
+#define XHC_AXIRDA__RTS_RESETVALUE 0x2U
+#define XHC_AXIRDA__RFPC 27U
+#define XHC_AXIRDA__RFPC_L 27U
+#define XHC_AXIRDA__RFPC_R 27U
+#define XHC_AXIRDA__RFPC_WIDTH 1U
+#define XHC_AXIRDA__RFPC_RESETVALUE 0x0U
+#define XHC_AXIRDA__RUA_L 24U
+#define XHC_AXIRDA__RUA_R 16U
+#define XHC_AXIRDA__RUA_WIDTH 9U
+#define XHC_AXIRDA__RUA_RESETVALUE 0x0U
+#define XHC_AXIRDA__reserved_L 15U
+#define XHC_AXIRDA__reserved_R 9U
+#define XHC_AXIRDA__reserved_WIDTH 7U
+#define XHC_AXIRDA__reserved_RESETVALUE 0x0U
+#define XHC_AXIRDA__RSA_L 8U
+#define XHC_AXIRDA__RSA_R 0U
+#define XHC_AXIRDA__RSA_WIDTH 9U
+#define XHC_AXIRDA__RSA_RESETVALUE 0x0U
+#define XHC_AXIRDA__RESERVED_L 26U
+#define XHC_AXIRDA__RESERVED_R 25U
+#define XHC_AXIRDA_WIDTH 32U
+#define XHC_AXIRDA__WIDTH 32U
+#define XHC_AXIRDA_ALL_L 31U
+#define XHC_AXIRDA_ALL_R 0U
+#define XHC_AXIRDA__ALL_L 31U
+#define XHC_AXIRDA__ALL_R 0U
+#define XHC_AXIRDA_DATAMASK 0xf9ffffffU
+#define XHC_AXIRDA_RDWRMASK 0x06000000U
+#define XHC_AXIRDA_RESETVALUE 0x20000000U
+
+#define XHC_AXILPM_OFFSET 0xc10U
+#define XHC_AXILPM_BASE 0xc10U
+#define XHC_AXILPM__ENB 31U
+#define XHC_AXILPM__ENB_L 31U
+#define XHC_AXILPM__ENB_R 31U
+#define XHC_AXILPM__ENB_WIDTH 1U
+#define XHC_AXILPM__ENB_RESETVALUE 0x0U
+#define XHC_AXILPM__reserved_L 30U
+#define XHC_AXILPM__reserved_R 3U
+#define XHC_AXILPM__reserved_WIDTH 28U
+#define XHC_AXILPM__reserved_RESETVALUE 0x0000000U
+#define XHC_AXILPM__ITT_L 2U
+#define XHC_AXILPM__ITT_R 0U
+#define XHC_AXILPM__ITT_WIDTH 3U
+#define XHC_AXILPM__ITT_RESETVALUE 0x0U
+#define XHC_AXILPM_WIDTH 32U
+#define XHC_AXILPM__WIDTH 32U
+#define XHC_AXILPM_ALL_L 31U
+#define XHC_AXILPM_ALL_R 0U
+#define XHC_AXILPM__ALL_L 31U
+#define XHC_AXILPM__ALL_R 0U
+#define XHC_AXILPM_DATAMASK 0xffffffffU
+#define XHC_AXILPM_RDWRMASK 0x00000000U
+#define XHC_AXILPM_RESETVALUE 0x00000000U
+
+#define XHC_AXIQOS_OFFSET 0xc14U
+#define XHC_AXIQOS_BASE 0xc14U
+#define XHC_AXIQOS__WQOS3_L 31U
+#define XHC_AXIQOS__WQOS3_R 28U
+#define XHC_AXIQOS__WQOS3_WIDTH 4U
+#define XHC_AXIQOS__WQOS3_RESETVALUE 0x0U
+#define XHC_AXIQOS__WQOS2_L 27U
+#define XHC_AXIQOS__WQOS2_R 24U
+#define XHC_AXIQOS__WQOS2_WIDTH 4U
+#define XHC_AXIQOS__WQOS2_RESETVALUE 0x0U
+#define XHC_AXIQOS__WQOS1_L 23U
+#define XHC_AXIQOS__WQOS1_R 20U
+#define XHC_AXIQOS__WQOS1_WIDTH 4U
+#define XHC_AXIQOS__WQOS1_RESETVALUE 0x0U
+#define XHC_AXIQOS__WQOS0_L 19U
+#define XHC_AXIQOS__WQOS0_R 16U
+#define XHC_AXIQOS__WQOS0_WIDTH 4U
+#define XHC_AXIQOS__WQOS0_RESETVALUE 0x0U
+#define XHC_AXIQOS__RQOS3_L 15U
+#define XHC_AXIQOS__RQOS3_R 12U
+#define XHC_AXIQOS__RQOS3_WIDTH 4U
+#define XHC_AXIQOS__RQOS3_RESETVALUE 0x0U
+#define XHC_AXIQOS__RQOS2_L 11U
+#define XHC_AXIQOS__RQOS2_R 8U
+#define XHC_AXIQOS__RQOS2_WIDTH 4U
+#define XHC_AXIQOS__RQOS2_RESETVALUE 0x0U
+#define XHC_AXIQOS__RQOS1_L 7U
+#define XHC_AXIQOS__RQOS1_R 4U
+#define XHC_AXIQOS__RQOS1_WIDTH 4U
+#define XHC_AXIQOS__RQOS1_RESETVALUE 0x0U
+#define XHC_AXIQOS__RQOS0_L 3U
+#define XHC_AXIQOS__RQOS0_R 0U
+#define XHC_AXIQOS__RQOS0_WIDTH 4U
+#define XHC_AXIQOS__RQOS0_RESETVALUE 0x0U
+#define XHC_AXIQOS_WIDTH 32U
+#define XHC_AXIQOS__WIDTH 32U
+#define XHC_AXIQOS_ALL_L 31U
+#define XHC_AXIQOS_ALL_R 0U
+#define XHC_AXIQOS__ALL_L 31U
+#define XHC_AXIQOS__ALL_R 0U
+#define XHC_AXIQOS_DATAMASK 0xffffffffU
+#define XHC_AXIQOS_RDWRMASK 0x00000000U
+#define XHC_AXIQOS_RESETVALUE 0x00000000U
+
+#define XHC_ECHCSR_OFFSET 0xc20U
+#define XHC_ECHCSR_BASE 0xc20U
+#define XHC_ECHCSR__CLK_L 31U
+#define XHC_ECHCSR__CLK_R 21U
+#define XHC_ECHCSR__CLK_WIDTH 11U
+#define XHC_ECHCSR__CLK_RESETVALUE 0x0U
+#define XHC_ECHCSR__reserved_L 20U
+#define XHC_ECHCSR__reserved_R 19U
+#define XHC_ECHCSR__reserved_WIDTH 2U
+#define XHC_ECHCSR__reserved_RESETVALUE 0x0U
+#define XHC_ECHCSR__WID_L 18U
+#define XHC_ECHCSR__WID_R 16U
+#define XHC_ECHCSR__WID_WIDTH 3U
+#define XHC_ECHCSR__WID_RESETVALUE 0x0U
+#define XHC_ECHCSR__NCP_L 15U
+#define XHC_ECHCSR__NCP_R 8U
+#define XHC_ECHCSR__NCP_WIDTH 8U
+#define XHC_ECHCSR__NCP_RESETVALUE 0x04U
+#define XHC_ECHCSR__CID_L 7U
+#define XHC_ECHCSR__CID_R 0U
+#define XHC_ECHCSR__CID_WIDTH 8U
+#define XHC_ECHCSR__CID_RESETVALUE 0xc1U
+#define XHC_ECHCSR_WIDTH 32U
+#define XHC_ECHCSR__WIDTH 32U
+#define XHC_ECHCSR_ALL_L 31U
+#define XHC_ECHCSR_ALL_R 0U
+#define XHC_ECHCSR__ALL_L 31U
+#define XHC_ECHCSR__ALL_R 0U
+#define XHC_ECHCSR_DATAMASK 0xffffffffU
+#define XHC_ECHCSR_RDWRMASK 0x00000000U
+#define XHC_ECHCSR_RESETVALUE 0x000004c1U
+
+#define XHC_CSRSPC_OFFSET 0xc24U
+#define XHC_CSRSPC_BASE 0xc24U
+#define XHC_CSRSPC__MAJ_L 31U
+#define XHC_CSRSPC__MAJ_R 28U
+#define XHC_CSRSPC__MAJ_WIDTH 4U
+#define XHC_CSRSPC__MAJ_RESETVALUE 0x0U
+#define XHC_CSRSPC__MIN_L 27U
+#define XHC_CSRSPC__MIN_R 24U
+#define XHC_CSRSPC__MIN_WIDTH 4U
+#define XHC_CSRSPC__MIN_RESETVALUE 0x0U
+#define XHC_CSRSPC__RLS_L 23U
+#define XHC_CSRSPC__RLS_R 20U
+#define XHC_CSRSPC__RLS_WIDTH 4U
+#define XHC_CSRSPC__RLS_RESETVALUE 0x0U
+#define XHC_CSRSPC__reserved_L 19U
+#define XHC_CSRSPC__reserved_R 3U
+#define XHC_CSRSPC__reserved_WIDTH 17U
+#define XHC_CSRSPC__reserved_RESETVALUE 0x0U
+#define XHC_CSRSPC__ASP 2U
+#define XHC_CSRSPC__ASP_L 2U
+#define XHC_CSRSPC__ASP_R 2U
+#define XHC_CSRSPC__ASP_WIDTH 1U
+#define XHC_CSRSPC__ASP_RESETVALUE 0x0U
+#define XHC_CSRSPC__TYP_L 1U
+#define XHC_CSRSPC__TYP_R 0U
+#define XHC_CSRSPC__TYP_WIDTH 2U
+#define XHC_CSRSPC__TYP_RESETVALUE 0x0U
+#define XHC_CSRSPC_WIDTH 32U
+#define XHC_CSRSPC__WIDTH 32U
+#define XHC_CSRSPC_ALL_L 31U
+#define XHC_CSRSPC_ALL_R 0U
+#define XHC_CSRSPC__ALL_L 31U
+#define XHC_CSRSPC__ALL_R 0U
+#define XHC_CSRSPC_DATAMASK 0xffffffffU
+#define XHC_CSRSPC_RDWRMASK 0x00000000U
+#define XHC_CSRSPC_RESETVALUE 0x00000000U
+
+#define XHC_ECHAIU_OFFSET 0xc30U
+#define XHC_ECHAIU_BASE 0xc30U
+#define XHC_ECHAIU__DMA_L 31U
+#define XHC_ECHAIU__DMA_R 30U
+#define XHC_ECHAIU__DMA_WIDTH 2U
+#define XHC_ECHAIU__DMA_RESETVALUE 0x1U
+#define XHC_ECHAIU__PBRS_L 29U
+#define XHC_ECHAIU__PBRS_R 28U
+#define XHC_ECHAIU__PBRS_WIDTH 2U
+#define XHC_ECHAIU__PBRS_RESETVALUE 0x0U
+#define XHC_ECHAIU__PBR2_L 27U
+#define XHC_ECHAIU__PBR2_R 26U
+#define XHC_ECHAIU__PBR2_WIDTH 2U
+#define XHC_ECHAIU__PBR2_RESETVALUE 0x0U
+#define XHC_ECHAIU__SCHS_L 25U
+#define XHC_ECHAIU__SCHS_R 24U
+#define XHC_ECHAIU__SCHS_WIDTH 2U
+#define XHC_ECHAIU__SCHS_RESETVALUE 0x0U
+#define XHC_ECHAIU__SCH2_L 23U
+#define XHC_ECHAIU__SCH2_R 22U
+#define XHC_ECHAIU__SCH2_WIDTH 2U
+#define XHC_ECHAIU__SCH2_RESETVALUE 0x0U
+#define XHC_ECHAIU__CHMS_L 21U
+#define XHC_ECHAIU__CHMS_R 20U
+#define XHC_ECHAIU__CHMS_WIDTH 2U
+#define XHC_ECHAIU__CHMS_RESETVALUE 0x3U
+#define XHC_ECHAIU__CHM2_L 19U
+#define XHC_ECHAIU__CHM2_R 18U
+#define XHC_ECHAIU__CHM2_WIDTH 2U
+#define XHC_ECHAIU__CHM2_RESETVALUE 0x0U
+#define XHC_ECHAIU__reserved_L 17U
+#define XHC_ECHAIU__reserved_R 16U
+#define XHC_ECHAIU__reserved_WIDTH 2U
+#define XHC_ECHAIU__reserved_RESETVALUE 0x0U
+#define XHC_ECHAIU__NCP_L 15U
+#define XHC_ECHAIU__NCP_R 8U
+#define XHC_ECHAIU__NCP_WIDTH 8U
+#define XHC_ECHAIU__NCP_RESETVALUE 0x04U
+#define XHC_ECHAIU__CID_L 7U
+#define XHC_ECHAIU__CID_R 0U
+#define XHC_ECHAIU__CID_WIDTH 8U
+#define XHC_ECHAIU__CID_RESETVALUE 0xc2U
+#define XHC_ECHAIU_WIDTH 32U
+#define XHC_ECHAIU__WIDTH 32U
+#define XHC_ECHAIU_ALL_L 31U
+#define XHC_ECHAIU_ALL_R 0U
+#define XHC_ECHAIU__ALL_L 31U
+#define XHC_ECHAIU__ALL_R 0U
+#define XHC_ECHAIU_DATAMASK 0xffffffffU
+#define XHC_ECHAIU_RDWRMASK 0x00000000U
+#define XHC_ECHAIU_RESETVALUE 0x403004c2U
+
+#define XHC_AIUDMA_OFFSET 0xc34U
+#define XHC_AIUDMA_BASE 0xc34U
+#define XHC_AIUDMA__WRMB_L 31U
+#define XHC_AIUDMA__WRMB_R 28U
+#define XHC_AIUDMA__WRMB_WIDTH 4U
+#define XHC_AIUDMA__WRMB_RESETVALUE 0x0U
+#define XHC_AIUDMA__WRD_L 27U
+#define XHC_AIUDMA__WRD_R 26U
+#define XHC_AIUDMA__WRD_WIDTH 2U
+#define XHC_AIUDMA__WRD_RESETVALUE 0x0U
+#define XHC_AIUDMA__WED_L 25U
+#define XHC_AIUDMA__WED_R 24U
+#define XHC_AIUDMA__WED_WIDTH 2U
+#define XHC_AIUDMA__WED_RESETVALUE 0x0U
+#define XHC_AIUDMA__WMS_L 23U
+#define XHC_AIUDMA__WMS_R 22U
+#define XHC_AIUDMA__WMS_WIDTH 2U
+#define XHC_AIUDMA__WMS_RESETVALUE 0x0U
+#define XHC_AIUDMA__WMI_L 21U
+#define XHC_AIUDMA__WMI_R 20U
+#define XHC_AIUDMA__WMI_WIDTH 2U
+#define XHC_AIUDMA__WMI_RESETVALUE 0x0U
+#define XHC_AIUDMA__WPF_L 19U
+#define XHC_AIUDMA__WPF_R 16U
+#define XHC_AIUDMA__WPF_WIDTH 4U
+#define XHC_AIUDMA__WPF_RESETVALUE 0x6U
+#define XHC_AIUDMA__RRMB_L 15U
+#define XHC_AIUDMA__RRMB_R 12U
+#define XHC_AIUDMA__RRMB_WIDTH 4U
+#define XHC_AIUDMA__RRMB_RESETVALUE 0x0U
+#define XHC_AIUDMA__RTD_L 11U
+#define XHC_AIUDMA__RTD_R 10U
+#define XHC_AIUDMA__RTD_WIDTH 2U
+#define XHC_AIUDMA__RTD_RESETVALUE 0x0U
+#define XHC_AIUDMA__RTF_L 9U
+#define XHC_AIUDMA__RTF_R 8U
+#define XHC_AIUDMA__RTF_WIDTH 2U
+#define XHC_AIUDMA__RTF_RESETVALUE 0x0U
+#define XHC_AIUDMA__RM_S_L 7U
+#define XHC_AIUDMA__RM_S_R 6U
+#define XHC_AIUDMA__RM_S_WIDTH 2U
+#define XHC_AIUDMA__RM_S_RESETVALUE 0x0U
+#define XHC_AIUDMA__TFBS_L 5U
+#define XHC_AIUDMA__TFBS_R 3U
+#define XHC_AIUDMA__TFBS_WIDTH 3U
+#define XHC_AIUDMA__TFBS_RESETVALUE 0x0U
+#define XHC_AIUDMA__reserved_L 2U
+#define XHC_AIUDMA__reserved_R 0U
+#define XHC_AIUDMA__reserved_WIDTH 3U
+#define XHC_AIUDMA__reserved_RESETVALUE 0x0U
+#define XHC_AIUDMA_WIDTH 32U
+#define XHC_AIUDMA__WIDTH 32U
+#define XHC_AIUDMA_ALL_L 31U
+#define XHC_AIUDMA_ALL_R 0U
+#define XHC_AIUDMA__ALL_L 31U
+#define XHC_AIUDMA__ALL_R 0U
+#define XHC_AIUDMA_DATAMASK 0xffffffffU
+#define XHC_AIUDMA_RDWRMASK 0x00000000U
+#define XHC_AIUDMA_RESETVALUE 0x00060000U
+
+#define XHC_AIUFLA_OFFSET 0xc38U
+#define XHC_AIUFLA_BASE 0xc38U
+#define XHC_AIUFLA__ACLK_L 31U
+#define XHC_AIUFLA__ACLK_R 23U
+#define XHC_AIUFLA__ACLK_WIDTH 9U
+#define XHC_AIUFLA__ACLK_RESETVALUE 0x0U
+#define XHC_AIUFLA__MFLV_L 22U
+#define XHC_AIUFLA__MFLV_R 7U
+#define XHC_AIUFLA__MFLV_WIDTH 16U
+#define XHC_AIUFLA__MFLV_RESETVALUE 0x0000U
+#define XHC_AIUFLA__NFC 6U
+#define XHC_AIUFLA__NFC_L 6U
+#define XHC_AIUFLA__NFC_R 6U
+#define XHC_AIUFLA__NFC_WIDTH 1U
+#define XHC_AIUFLA__NFC_RESETVALUE 0x1U
+#define XHC_AIUFLA__FLADJ_L 5U
+#define XHC_AIUFLA__FLADJ_R 0U
+#define XHC_AIUFLA__FLADJ_WIDTH 6U
+#define XHC_AIUFLA__FLADJ_RESETVALUE 0x20U
+#define XHC_AIUFLA_WIDTH 32U
+#define XHC_AIUFLA__WIDTH 32U
+#define XHC_AIUFLA_ALL_L 31U
+#define XHC_AIUFLA_ALL_R 0U
+#define XHC_AIUFLA__ALL_L 31U
+#define XHC_AIUFLA__ALL_R 0U
+#define XHC_AIUFLA_DATAMASK 0xffffffffU
+#define XHC_AIUFLA_RDWRMASK 0x00000000U
+#define XHC_AIUFLA_RESETVALUE 0x00000060U
+
+#define XHC_AIUCFG_OFFSET 0xc3cU
+#define XHC_AIUCFG_BASE 0xc3cU
+#define XHC_AIUCFG__ISO_L 30U
+#define XHC_AIUCFG__ISO_R 28U
+#define XHC_AIUCFG__ISO_WIDTH 3U
+#define XHC_AIUCFG__ISO_RESETVALUE 0x0U
+#define XHC_AIUCFG__EPC_L 26U
+#define XHC_AIUCFG__EPC_R 24U
+#define XHC_AIUCFG__EPC_WIDTH 3U
+#define XHC_AIUCFG__EPC_RESETVALUE 0x5U
+#define XHC_AIUCFG__PTQ_L 22U
+#define XHC_AIUCFG__PTQ_R 20U
+#define XHC_AIUCFG__PTQ_WIDTH 3U
+#define XHC_AIUCFG__PTQ_RESETVALUE 0x3U
+#define XHC_AIUCFG__NTQ_L 18U
+#define XHC_AIUCFG__NTQ_R 16U
+#define XHC_AIUCFG__NTQ_WIDTH 3U
+#define XHC_AIUCFG__NTQ_RESETVALUE 0x3U
+#define XHC_AIUCFG__HID 15U
+#define XHC_AIUCFG__HID_L 15U
+#define XHC_AIUCFG__HID_R 15U
+#define XHC_AIUCFG__HID_WIDTH 1U
+#define XHC_AIUCFG__HID_RESETVALUE 0x0U
+#define XHC_AIUCFG__EPS_L 14U
+#define XHC_AIUCFG__EPS_R 12U
+#define XHC_AIUCFG__EPS_WIDTH 3U
+#define XHC_AIUCFG__EPS_RESETVALUE 0x0U
+#define XHC_AIUCFG__reserved_L 11U
+#define XHC_AIUCFG__reserved_R 9U
+#define XHC_AIUCFG__reserved_WIDTH 3U
+#define XHC_AIUCFG__reserved_RESETVALUE 0x0U
+#define XHC_AIUCFG__PEP2_L 8U
+#define XHC_AIUCFG__PEP2_R 6U
+#define XHC_AIUCFG__PEP2_WIDTH 3U
+#define XHC_AIUCFG__PEP2_RESETVALUE 0x4U
+#define XHC_AIUCFG__MELADJ_L 5U
+#define XHC_AIUCFG__MELADJ_R 0U
+#define XHC_AIUCFG__MELADJ_WIDTH 6U
+#define XHC_AIUCFG__MELADJ_RESETVALUE 0x0U
+#define XHC_AIUCFG__RESERVED_0 31U
+#define XHC_AIUCFG__RESERVED_0_L 31U
+#define XHC_AIUCFG__RESERVED_0_R 31U
+#define XHC_AIUCFG__RESERVED_1 27U
+#define XHC_AIUCFG__RESERVED_1_L 27U
+#define XHC_AIUCFG__RESERVED_1_R 27U
+#define XHC_AIUCFG__RESERVED_2 23U
+#define XHC_AIUCFG__RESERVED_2_L 23U
+#define XHC_AIUCFG__RESERVED_2_R 23U
+#define XHC_AIUCFG__RESERVED_3 19U
+#define XHC_AIUCFG__RESERVED_3_L 19U
+#define XHC_AIUCFG__RESERVED_3_R 19U
+#define XHC_AIUCFG_WIDTH 31U
+#define XHC_AIUCFG__WIDTH 31U
+#define XHC_AIUCFG_ALL_L 30U
+#define XHC_AIUCFG_ALL_R 0U
+#define XHC_AIUCFG__ALL_L 30U
+#define XHC_AIUCFG__ALL_R 0U
+#define XHC_AIUCFG_DATAMASK 0x7777ffffU
+#define XHC_AIUCFG_RDWRMASK 0x88880000U
+#define XHC_AIUCFG_RESETVALUE 0x05330100U
+
+#define XHC_ECHFSC_OFFSET 0xc40U
+#define XHC_ECHFSC_BASE 0xc40U
+#define XHC_ECHFSC__reserved_L 31U
+#define XHC_ECHFSC__reserved_R 24U
+#define XHC_ECHFSC__reserved_WIDTH 8U
+#define XHC_ECHFSC__reserved_RESETVALUE 0x00U
+#define XHC_ECHFSC__WRMB_L 23U
+#define XHC_ECHFSC__WRMB_R 20U
+#define XHC_ECHFSC__WRMB_WIDTH 4U
+#define XHC_ECHFSC__WRMB_RESETVALUE 0x0U
+#define XHC_ECHFSC__RRMB_L 19U
+#define XHC_ECHFSC__RRMB_R 16U
+#define XHC_ECHFSC__RRMB_WIDTH 4U
+#define XHC_ECHFSC__RRMB_RESETVALUE 0x0U
+#define XHC_ECHFSC__NCP_L 15U
+#define XHC_ECHFSC__NCP_R 8U
+#define XHC_ECHFSC__NCP_WIDTH 8U
+#define XHC_ECHFSC__NCP_RESETVALUE 0x50U
+#define XHC_ECHFSC__CID_L 7U
+#define XHC_ECHFSC__CID_R 0U
+#define XHC_ECHFSC__CID_WIDTH 8U
+#define XHC_ECHFSC__CID_RESETVALUE 0xc3U
+#define XHC_ECHFSC_WIDTH 32U
+#define XHC_ECHFSC__WIDTH 32U
+#define XHC_ECHFSC_ALL_L 31U
+#define XHC_ECHFSC_ALL_R 0U
+#define XHC_ECHFSC__ALL_L 31U
+#define XHC_ECHFSC__ALL_R 0U
+#define XHC_ECHFSC_DATAMASK 0xffffffffU
+#define XHC_ECHFSC_RDWRMASK 0x00000000U
+#define XHC_ECHFSC_RESETVALUE 0x000050c3U
+
+#define XHC_FSCPOC_OFFSET 0xc54U
+#define XHC_FSCPOC_BASE 0xc54U
+#define XHC_FSCPOC__NCS_L 31U
+#define XHC_FSCPOC__NCS_R 28U
+#define XHC_FSCPOC__NCS_WIDTH 4U
+#define XHC_FSCPOC__NCS_RESETVALUE 0x0U
+#define XHC_FSCPOC__FSIZ_L 22U
+#define XHC_FSCPOC__FSIZ_R 18U
+#define XHC_FSCPOC__FSIZ_WIDTH 5U
+#define XHC_FSCPOC__FSIZ_RESETVALUE 0x0U
+#define XHC_FSCPOC__PSIZ_L 16U
+#define XHC_FSCPOC__PSIZ_R 12U
+#define XHC_FSCPOC__PSIZ_WIDTH 5U
+#define XHC_FSCPOC__PSIZ_RESETVALUE 0x0U
+#define XHC_FSCPOC__reserved_L 11U
+#define XHC_FSCPOC__reserved_R 5U
+#define XHC_FSCPOC__reserved_WIDTH 7U
+#define XHC_FSCPOC__reserved_RESETVALUE 0x0U
+#define XHC_FSCPOC__TSIZ_L 4U
+#define XHC_FSCPOC__TSIZ_R 0U
+#define XHC_FSCPOC__TSIZ_WIDTH 5U
+#define XHC_FSCPOC__TSIZ_RESETVALUE 0x0U
+#define XHC_FSCPOC__RESERVED_L 27U
+#define XHC_FSCPOC__RESERVED_R 23U
+#define XHC_FSCPOC_WIDTH 32U
+#define XHC_FSCPOC__WIDTH 32U
+#define XHC_FSCPOC_ALL_L 31U
+#define XHC_FSCPOC_ALL_R 0U
+#define XHC_FSCPOC__ALL_L 31U
+#define XHC_FSCPOC__ALL_R 0U
+#define XHC_FSCPOC_DATAMASK 0xf07dffffU
+#define XHC_FSCPOC_RDWRMASK 0x0f820000U
+#define XHC_FSCPOC_RESETVALUE 0x00000000U
+
+#define XHC_FSCGOC_OFFSET 0xc58U
+#define XHC_FSCGOC_BASE 0xc58U
+#define XHC_FSCGOC__NCS_L 31U
+#define XHC_FSCGOC__NCS_R 28U
+#define XHC_FSCGOC__NCS_WIDTH 4U
+#define XHC_FSCGOC__NCS_RESETVALUE 0x0U
+#define XHC_FSCGOC__FSIZ_L 22U
+#define XHC_FSCGOC__FSIZ_R 18U
+#define XHC_FSCGOC__FSIZ_WIDTH 5U
+#define XHC_FSCGOC__FSIZ_RESETVALUE 0x0U
+#define XHC_FSCGOC__PSIZ_L 16U
+#define XHC_FSCGOC__PSIZ_R 12U
+#define XHC_FSCGOC__PSIZ_WIDTH 5U
+#define XHC_FSCGOC__PSIZ_RESETVALUE 0x0U
+#define XHC_FSCGOC__reserved_L 11U
+#define XHC_FSCGOC__reserved_R 5U
+#define XHC_FSCGOC__reserved_WIDTH 7U
+#define XHC_FSCGOC__reserved_RESETVALUE 0x0U
+#define XHC_FSCGOC__TSIZ_L 4U
+#define XHC_FSCGOC__TSIZ_R 0U
+#define XHC_FSCGOC__TSIZ_WIDTH 5U
+#define XHC_FSCGOC__TSIZ_RESETVALUE 0x0U
+#define XHC_FSCGOC__RESERVED_L 27U
+#define XHC_FSCGOC__RESERVED_R 23U
+#define XHC_FSCGOC_WIDTH 32U
+#define XHC_FSCGOC__WIDTH 32U
+#define XHC_FSCGOC_ALL_L 31U
+#define XHC_FSCGOC_ALL_R 0U
+#define XHC_FSCGOC__ALL_L 31U
+#define XHC_FSCGOC__ALL_R 0U
+#define XHC_FSCGOC_DATAMASK 0xf07dffffU
+#define XHC_FSCGOC_RDWRMASK 0x0f820000U
+#define XHC_FSCGOC_RESETVALUE 0x00000000U
+
+#define XHC_FSCNOC_OFFSET 0xc5cU
+#define XHC_FSCNOC_BASE 0xc5cU
+#define XHC_FSCNOC__NCS_L 31U
+#define XHC_FSCNOC__NCS_R 28U
+#define XHC_FSCNOC__NCS_WIDTH 4U
+#define XHC_FSCNOC__NCS_RESETVALUE 0x0U
+#define XHC_FSCNOC__FSIZ_L 22U
+#define XHC_FSCNOC__FSIZ_R 18U
+#define XHC_FSCNOC__FSIZ_WIDTH 5U
+#define XHC_FSCNOC__FSIZ_RESETVALUE 0x0U
+#define XHC_FSCNOC__PSIZ_L 16U
+#define XHC_FSCNOC__PSIZ_R 12U
+#define XHC_FSCNOC__PSIZ_WIDTH 5U
+#define XHC_FSCNOC__PSIZ_RESETVALUE 0x0U
+#define XHC_FSCNOC__reserved_L 11U
+#define XHC_FSCNOC__reserved_R 5U
+#define XHC_FSCNOC__reserved_WIDTH 7U
+#define XHC_FSCNOC__reserved_RESETVALUE 0x0U
+#define XHC_FSCNOC__TSIZ_L 4U
+#define XHC_FSCNOC__TSIZ_R 0U
+#define XHC_FSCNOC__TSIZ_WIDTH 5U
+#define XHC_FSCNOC__TSIZ_RESETVALUE 0x0U
+#define XHC_FSCNOC__RESERVED_L 27U
+#define XHC_FSCNOC__RESERVED_R 23U
+#define XHC_FSCNOC_WIDTH 32U
+#define XHC_FSCNOC__WIDTH 32U
+#define XHC_FSCNOC_ALL_L 31U
+#define XHC_FSCNOC_ALL_R 0U
+#define XHC_FSCNOC__ALL_L 31U
+#define XHC_FSCNOC__ALL_R 0U
+#define XHC_FSCNOC_DATAMASK 0xf07dffffU
+#define XHC_FSCNOC_RDWRMASK 0x0f820000U
+#define XHC_FSCNOC_RESETVALUE 0x00000000U
+
+#define XHC_FSCAIC_OFFSET 0xc60U
+#define XHC_FSCAIC_BASE 0xc60U
+#define XHC_FSCAIC__FSIZ_L 22U
+#define XHC_FSCAIC__FSIZ_R 18U
+#define XHC_FSCAIC__FSIZ_WIDTH 5U
+#define XHC_FSCAIC__FSIZ_RESETVALUE 0x0U
+#define XHC_FSCAIC__PSIZ_L 16U
+#define XHC_FSCAIC__PSIZ_R 12U
+#define XHC_FSCAIC__PSIZ_WIDTH 5U
+#define XHC_FSCAIC__PSIZ_RESETVALUE 0x0U
+#define XHC_FSCAIC__reserved_L 11U
+#define XHC_FSCAIC__reserved_R 0U
+#define XHC_FSCAIC__reserved_WIDTH 12U
+#define XHC_FSCAIC__reserved_RESETVALUE 0x000U
+#define XHC_FSCAIC__RESERVED_L 31U
+#define XHC_FSCAIC__RESERVED_R 23U
+#define XHC_FSCAIC_WIDTH 23U
+#define XHC_FSCAIC__WIDTH 23U
+#define XHC_FSCAIC_ALL_L 22U
+#define XHC_FSCAIC_ALL_R 0U
+#define XHC_FSCAIC__ALL_L 22U
+#define XHC_FSCAIC__ALL_R 0U
+#define XHC_FSCAIC_DATAMASK 0x007dffffU
+#define XHC_FSCAIC_RDWRMASK 0xff820000U
+#define XHC_FSCAIC_RESETVALUE 0x000000U
+
+#define XHC_FSCPIC_OFFSET 0xc64U
+#define XHC_FSCPIC_BASE 0xc64U
+#define XHC_FSCPIC__NCS_L 31U
+#define XHC_FSCPIC__NCS_R 28U
+#define XHC_FSCPIC__NCS_WIDTH 4U
+#define XHC_FSCPIC__NCS_RESETVALUE 0x0U
+#define XHC_FSCPIC__reserved_L 27U
+#define XHC_FSCPIC__reserved_R 5U
+#define XHC_FSCPIC__reserved_WIDTH 23U
+#define XHC_FSCPIC__reserved_RESETVALUE 0x0U
+#define XHC_FSCPIC__TSIZ_L 4U
+#define XHC_FSCPIC__TSIZ_R 0U
+#define XHC_FSCPIC__TSIZ_WIDTH 5U
+#define XHC_FSCPIC__TSIZ_RESETVALUE 0x0U
+#define XHC_FSCPIC_WIDTH 32U
+#define XHC_FSCPIC__WIDTH 32U
+#define XHC_FSCPIC_ALL_L 31U
+#define XHC_FSCPIC_ALL_R 0U
+#define XHC_FSCPIC__ALL_L 31U
+#define XHC_FSCPIC__ALL_R 0U
+#define XHC_FSCPIC_DATAMASK 0xffffffffU
+#define XHC_FSCPIC_RDWRMASK 0x00000000U
+#define XHC_FSCPIC_RESETVALUE 0x00000000U
+
+#define XHC_FSCGIC_OFFSET 0xc68U
+#define XHC_FSCGIC_BASE 0xc68U
+#define XHC_FSCGIC__NCS_L 31U
+#define XHC_FSCGIC__NCS_R 28U
+#define XHC_FSCGIC__NCS_WIDTH 4U
+#define XHC_FSCGIC__NCS_RESETVALUE 0x0U
+#define XHC_FSCGIC__reserved_L 27U
+#define XHC_FSCGIC__reserved_R 5U
+#define XHC_FSCGIC__reserved_WIDTH 23U
+#define XHC_FSCGIC__reserved_RESETVALUE 0x0U
+#define XHC_FSCGIC__TSIZ_L 4U
+#define XHC_FSCGIC__TSIZ_R 0U
+#define XHC_FSCGIC__TSIZ_WIDTH 5U
+#define XHC_FSCGIC__TSIZ_RESETVALUE 0x0U
+#define XHC_FSCGIC_WIDTH 32U
+#define XHC_FSCGIC__WIDTH 32U
+#define XHC_FSCGIC_ALL_L 31U
+#define XHC_FSCGIC_ALL_R 0U
+#define XHC_FSCGIC__ALL_L 31U
+#define XHC_FSCGIC__ALL_R 0U
+#define XHC_FSCGIC_DATAMASK 0xffffffffU
+#define XHC_FSCGIC_RDWRMASK 0x00000000U
+#define XHC_FSCGIC_RESETVALUE 0x00000000U
+
+#define XHC_FSCNIC_OFFSET 0xc6cU
+#define XHC_FSCNIC_BASE 0xc6cU
+#define XHC_FSCNIC__NCS_L 31U
+#define XHC_FSCNIC__NCS_R 28U
+#define XHC_FSCNIC__NCS_WIDTH 4U
+#define XHC_FSCNIC__NCS_RESETVALUE 0x0U
+#define XHC_FSCNIC__reserved_L 27U
+#define XHC_FSCNIC__reserved_R 5U
+#define XHC_FSCNIC__reserved_WIDTH 23U
+#define XHC_FSCNIC__reserved_RESETVALUE 0x0U
+#define XHC_FSCNIC__TSIZ_L 4U
+#define XHC_FSCNIC__TSIZ_R 0U
+#define XHC_FSCNIC__TSIZ_WIDTH 5U
+#define XHC_FSCNIC__TSIZ_RESETVALUE 0x0U
+#define XHC_FSCNIC_WIDTH 32U
+#define XHC_FSCNIC__WIDTH 32U
+#define XHC_FSCNIC_ALL_L 31U
+#define XHC_FSCNIC_ALL_R 0U
+#define XHC_FSCNIC__ALL_L 31U
+#define XHC_FSCNIC__ALL_R 0U
+#define XHC_FSCNIC_DATAMASK 0xffffffffU
+#define XHC_FSCNIC_RDWRMASK 0x00000000U
+#define XHC_FSCNIC_RESETVALUE 0x00000000U
+
+#define XHC_ECHPRT_OFFSET 0xc70U
+#define XHC_ECHPRT_BASE 0xc70U
+#define XHC_ECHPRT__TDP 31U
+#define XHC_ECHPRT__TDP_L 31U
+#define XHC_ECHPRT__TDP_R 31U
+#define XHC_ECHPRT__TDP_WIDTH 1U
+#define XHC_ECHPRT__TDP_RESETVALUE 0x0U
+#define XHC_ECHPRT__RDP 30U
+#define XHC_ECHPRT__RDP_L 30U
+#define XHC_ECHPRT__RDP_R 30U
+#define XHC_ECHPRT__RDP_WIDTH 1U
+#define XHC_ECHPRT__RDP_RESETVALUE 0x0U
+#define XHC_ECHPRT__reserved_L 29U
+#define XHC_ECHPRT__reserved_R 25U
+#define XHC_ECHPRT__reserved_WIDTH 5U
+#define XHC_ECHPRT__reserved_RESETVALUE 0x0U
+#define XHC_ECHPRT__MFT_L 24U
+#define XHC_ECHPRT__MFT_R 17U
+#define XHC_ECHPRT__MFT_WIDTH 8U
+#define XHC_ECHPRT__MFT_RESETVALUE 0x7dU
+#define XHC_ECHPRT__HST 16U
+#define XHC_ECHPRT__HST_L 16U
+#define XHC_ECHPRT__HST_R 16U
+#define XHC_ECHPRT__HST_WIDTH 1U
+#define XHC_ECHPRT__HST_RESETVALUE 0x0U
+#define XHC_ECHPRT__NCP_L 15U
+#define XHC_ECHPRT__NCP_R 8U
+#define XHC_ECHPRT__NCP_WIDTH 8U
+#define XHC_ECHPRT__NCP_RESETVALUE 0x04U
+#define XHC_ECHPRT__CID_L 7U
+#define XHC_ECHPRT__CID_R 0U
+#define XHC_ECHPRT__CID_WIDTH 8U
+#define XHC_ECHPRT__CID_RESETVALUE 0xc4U
+#define XHC_ECHPRT_WIDTH 32U
+#define XHC_ECHPRT__WIDTH 32U
+#define XHC_ECHPRT_ALL_L 31U
+#define XHC_ECHPRT_ALL_R 0U
+#define XHC_ECHPRT__ALL_L 31U
+#define XHC_ECHPRT__ALL_R 0U
+#define XHC_ECHPRT_DATAMASK 0xffffffffU
+#define XHC_ECHPRT_RDWRMASK 0x00000000U
+#define XHC_ECHPRT_RESETVALUE 0x00fa04c4U
+
+#define XHC_PRTHSC_OFFSET 0xc78U
+#define XHC_PRTHSC_BASE 0xc78U
+#define XHC_PRTHSC__TMR_L 31U
+#define XHC_PRTHSC__TMR_R 16U
+#define XHC_PRTHSC__TMR_WIDTH 16U
+#define XHC_PRTHSC__TMR_RESETVALUE 0x0000U
+#define XHC_PRTHSC__RSL_L 7U
+#define XHC_PRTHSC__RSL_R 6U
+#define XHC_PRTHSC__RSL_WIDTH 2U
+#define XHC_PRTHSC__RSL_RESETVALUE 0x0U
+#define XHC_PRTHSC__AS_M_L 5U
+#define XHC_PRTHSC__AS_M_R 4U
+#define XHC_PRTHSC__AS_M_WIDTH 2U
+#define XHC_PRTHSC__AS_M_RESETVALUE 0x0U
+#define XHC_PRTHSC__CMD_L 3U
+#define XHC_PRTHSC__CMD_R 2U
+#define XHC_PRTHSC__CMD_WIDTH 2U
+#define XHC_PRTHSC__CMD_RESETVALUE 0x0U
+#define XHC_PRTHSC__reserved 1U
+#define XHC_PRTHSC__reserved_L 1U
+#define XHC_PRTHSC__reserved_R 1U
+#define XHC_PRTHSC__reserved_WIDTH 1U
+#define XHC_PRTHSC__reserved_RESETVALUE 0x0U
+#define XHC_PRTHSC__STB 0U
+#define XHC_PRTHSC__STB_L 0U
+#define XHC_PRTHSC__STB_R 0U
+#define XHC_PRTHSC__STB_WIDTH 1U
+#define XHC_PRTHSC__STB_RESETVALUE 0x0U
+#define XHC_PRTHSC__RESERVED_L 15U
+#define XHC_PRTHSC__RESERVED_R 8U
+#define XHC_PRTHSC_WIDTH 32U
+#define XHC_PRTHSC__WIDTH 32U
+#define XHC_PRTHSC_ALL_L 31U
+#define XHC_PRTHSC_ALL_R 0U
+#define XHC_PRTHSC__ALL_L 31U
+#define XHC_PRTHSC__ALL_R 0U
+#define XHC_PRTHSC_DATAMASK 0xffff00ffU
+#define XHC_PRTHSC_RDWRMASK 0x0000ff00U
+#define XHC_PRTHSC_RESETVALUE 0x00000000U
+
+#define XHC_PRTHSR_OFFSET 0xc7cU
+#define XHC_PRTHSR_BASE 0xc7cU
+#define XHC_PRTHSR__RDLY_L 31U
+#define XHC_PRTHSR__RDLY_R 24U
+#define XHC_PRTHSR__RDLY_WIDTH 8U
+#define XHC_PRTHSR__RDLY_RESETVALUE 0x00U
+#define XHC_PRTHSR__TDPP_L 23U
+#define XHC_PRTHSR__TDPP_R 16U
+#define XHC_PRTHSR__TDPP_WIDTH 8U
+#define XHC_PRTHSR__TDPP_RESETVALUE 0x00U
+#define XHC_PRTHSR__RDPP_L 15U
+#define XHC_PRTHSR__RDPP_R 8U
+#define XHC_PRTHSR__RDPP_WIDTH 8U
+#define XHC_PRTHSR__RDPP_RESETVALUE 0x00U
+#define XHC_PRTHSR__TRTY_L 7U
+#define XHC_PRTHSR__TRTY_R 0U
+#define XHC_PRTHSR__TRTY_WIDTH 8U
+#define XHC_PRTHSR__TRTY_RESETVALUE 0x00U
+#define XHC_PRTHSR_WIDTH 32U
+#define XHC_PRTHSR__WIDTH 32U
+#define XHC_PRTHSR_ALL_L 31U
+#define XHC_PRTHSR_ALL_R 0U
+#define XHC_PRTHSR__ALL_L 31U
+#define XHC_PRTHSR__ALL_R 0U
+#define XHC_PRTHSR_DATAMASK 0xffffffffU
+#define XHC_PRTHSR_RDWRMASK 0x00000000U
+#define XHC_PRTHSR_RESETVALUE 0x00000000U
+
+#define XHC_ECHRHS_OFFSET 0xc80U
+#define XHC_ECHRHS_BASE 0xc80U
+#define XHC_ECHRHS__RPO_L 30U
+#define XHC_ECHRHS__RPO_R 24U
+#define XHC_ECHRHS__RPO_WIDTH 7U
+#define XHC_ECHRHS__RPO_RESETVALUE 0x0U
+#define XHC_ECHRHS__reserved_L 23U
+#define XHC_ECHRHS__reserved_R 22U
+#define XHC_ECHRHS__reserved_WIDTH 2U
+#define XHC_ECHRHS__reserved_RESETVALUE 0x0U
+#define XHC_ECHRHS__RPN_L 21U
+#define XHC_ECHRHS__RPN_R 20U
+#define XHC_ECHRHS__RPN_WIDTH 2U
+#define XHC_ECHRHS__RPN_RESETVALUE 0x0U
+#define XHC_ECHRHS__DNR_L 19U
+#define XHC_ECHRHS__DNR_R 16U
+#define XHC_ECHRHS__DNR_WIDTH 4U
+#define XHC_ECHRHS__DNR_RESETVALUE 0x0U
+#define XHC_ECHRHS__NCP_L 15U
+#define XHC_ECHRHS__NCP_R 8U
+#define XHC_ECHRHS__NCP_WIDTH 8U
+#define XHC_ECHRHS__NCP_RESETVALUE 0x0cU
+#define XHC_ECHRHS__CID_L 7U
+#define XHC_ECHRHS__CID_R 0U
+#define XHC_ECHRHS__CID_WIDTH 8U
+#define XHC_ECHRHS__CID_RESETVALUE 0xc8U
+#define XHC_ECHRHS__RESERVED 31U
+#define XHC_ECHRHS__RESERVED_L 31U
+#define XHC_ECHRHS__RESERVED_R 31U
+#define XHC_ECHRHS_WIDTH 31U
+#define XHC_ECHRHS__WIDTH 31U
+#define XHC_ECHRHS_ALL_L 30U
+#define XHC_ECHRHS_ALL_R 0U
+#define XHC_ECHRHS__ALL_L 30U
+#define XHC_ECHRHS__ALL_R 0U
+#define XHC_ECHRHS_DATAMASK 0x7fffffffU
+#define XHC_ECHRHS_RDWRMASK 0x80000000U
+#define XHC_ECHRHS_RESETVALUE 0x00000cc8U
+
+#define XHC_RHSDES_OFFSET 0xc84U
+#define XHC_RHSDES_BASE 0xc84U
+#define XHC_RHSDES__PIS3_L 31U
+#define XHC_RHSDES__PIS3_R 30U
+#define XHC_RHSDES__PIS3_WIDTH 2U
+#define XHC_RHSDES__PIS3_RESETVALUE 0x0U
+#define XHC_RHSDES__HIST3 24U
+#define XHC_RHSDES__HIST3_L 24U
+#define XHC_RHSDES__HIST3_R 24U
+#define XHC_RHSDES__HIST3_WIDTH 1U
+#define XHC_RHSDES__HIST3_RESETVALUE 0x0U
+#define XHC_RHSDES__PIS2_L 23U
+#define XHC_RHSDES__PIS2_R 22U
+#define XHC_RHSDES__PIS2_WIDTH 2U
+#define XHC_RHSDES__PIS2_RESETVALUE 0x0U
+#define XHC_RHSDES__HIST2 16U
+#define XHC_RHSDES__HIST2_L 16U
+#define XHC_RHSDES__HIST2_R 16U
+#define XHC_RHSDES__HIST2_WIDTH 1U
+#define XHC_RHSDES__HIST2_RESETVALUE 0x0U
+#define XHC_RHSDES__PIS1_L 15U
+#define XHC_RHSDES__PIS1_R 14U
+#define XHC_RHSDES__PIS1_WIDTH 2U
+#define XHC_RHSDES__PIS1_RESETVALUE 0x0U
+#define XHC_RHSDES__HIST1 8U
+#define XHC_RHSDES__HIST1_L 8U
+#define XHC_RHSDES__HIST1_R 8U
+#define XHC_RHSDES__HIST1_WIDTH 1U
+#define XHC_RHSDES__HIST1_RESETVALUE 0x0U
+#define XHC_RHSDES__PIS0_L 7U
+#define XHC_RHSDES__PIS0_R 6U
+#define XHC_RHSDES__PIS0_WIDTH 2U
+#define XHC_RHSDES__PIS0_RESETVALUE 0x0U
+#define XHC_RHSDES__reserved_L 5U
+#define XHC_RHSDES__reserved_R 1U
+#define XHC_RHSDES__reserved_WIDTH 5U
+#define XHC_RHSDES__reserved_RESETVALUE 0x0U
+#define XHC_RHSDES__HIST0 0U
+#define XHC_RHSDES__HIST0_L 0U
+#define XHC_RHSDES__HIST0_R 0U
+#define XHC_RHSDES__HIST0_WIDTH 1U
+#define XHC_RHSDES__HIST0_RESETVALUE 0x0U
+#define XHC_RHSDES__RESERVED_0_L 29U
+#define XHC_RHSDES__RESERVED_0_R 25U
+#define XHC_RHSDES__RESERVED_1_L 21U
+#define XHC_RHSDES__RESERVED_1_R 17U
+#define XHC_RHSDES__RESERVED_2_L 13U
+#define XHC_RHSDES__RESERVED_2_R 9U
+#define XHC_RHSDES__RESERVED_L 29U
+#define XHC_RHSDES__RESERVED_R 25U
+#define XHC_RHSDES_WIDTH 32U
+#define XHC_RHSDES__WIDTH 32U
+#define XHC_RHSDES_ALL_L 31U
+#define XHC_RHSDES_ALL_R 0U
+#define XHC_RHSDES__ALL_L 31U
+#define XHC_RHSDES__ALL_R 0U
+#define XHC_RHSDES_DATAMASK 0xc1c1c1ffU
+#define XHC_RHSDES_RDWRMASK 0x3e3e3e00U
+#define XHC_RHSDES_RESETVALUE 0x00000000U
+
+#define XHC_RHSHSC0_OFFSET 0xc90U
+#define XHC_RHSHSC0_BASE 0xc90U
+#define XHC_RHSHSC0__TMR_L 31U
+#define XHC_RHSHSC0__TMR_R 16U
+#define XHC_RHSHSC0__TMR_WIDTH 16U
+#define XHC_RHSHSC0__TMR_RESETVALUE 0x0000U
+#define XHC_RHSHSC0__RSL_L 7U
+#define XHC_RHSHSC0__RSL_R 6U
+#define XHC_RHSHSC0__RSL_WIDTH 2U
+#define XHC_RHSHSC0__RSL_RESETVALUE 0x0U
+#define XHC_RHSHSC0__AS_M_L 5U
+#define XHC_RHSHSC0__AS_M_R 4U
+#define XHC_RHSHSC0__AS_M_WIDTH 2U
+#define XHC_RHSHSC0__AS_M_RESETVALUE 0x0U
+#define XHC_RHSHSC0__CMD_L 3U
+#define XHC_RHSHSC0__CMD_R 2U
+#define XHC_RHSHSC0__CMD_WIDTH 2U
+#define XHC_RHSHSC0__CMD_RESETVALUE 0x0U
+#define XHC_RHSHSC0__reserved 1U
+#define XHC_RHSHSC0__reserved_L 1U
+#define XHC_RHSHSC0__reserved_R 1U
+#define XHC_RHSHSC0__reserved_WIDTH 1U
+#define XHC_RHSHSC0__reserved_RESETVALUE 0x0U
+#define XHC_RHSHSC0__STB 0U
+#define XHC_RHSHSC0__STB_L 0U
+#define XHC_RHSHSC0__STB_R 0U
+#define XHC_RHSHSC0__STB_WIDTH 1U
+#define XHC_RHSHSC0__STB_RESETVALUE 0x0U
+#define XHC_RHSHSC0__RESERVED_L 15U
+#define XHC_RHSHSC0__RESERVED_R 8U
+#define XHC_RHSHSC0_WIDTH 32U
+#define XHC_RHSHSC0__WIDTH 32U
+#define XHC_RHSHSC0_ALL_L 31U
+#define XHC_RHSHSC0_ALL_R 0U
+#define XHC_RHSHSC0__ALL_L 31U
+#define XHC_RHSHSC0__ALL_R 0U
+#define XHC_RHSHSC0_DATAMASK 0xffff00ffU
+#define XHC_RHSHSC0_RDWRMASK 0x0000ff00U
+#define XHC_RHSHSC0_RESETVALUE 0x00000000U
+
+#define XHC_RHSHSR0_OFFSET 0xc94U
+#define XHC_RHSHSR0_BASE 0xc94U
+#define XHC_RHSHSR0__C2U_L 31U
+#define XHC_RHSHSR0__C2U_R 24U
+#define XHC_RHSHSR0__C2U_WIDTH 8U
+#define XHC_RHSHSR0__C2U_RESETVALUE 0x00U
+#define XHC_RHSHSR0__C1U_L 23U
+#define XHC_RHSHSR0__C1U_R 16U
+#define XHC_RHSHSR0__C1U_WIDTH 8U
+#define XHC_RHSHSR0__C1U_RESETVALUE 0x00U
+#define XHC_RHSHSR0__RCV_L 15U
+#define XHC_RHSHSR0__RCV_R 8U
+#define XHC_RHSHSR0__RCV_WIDTH 8U
+#define XHC_RHSHSR0__RCV_RESETVALUE 0x00U
+#define XHC_RHSHSR0__RTY_L 7U
+#define XHC_RHSHSR0__RTY_R 0U
+#define XHC_RHSHSR0__RTY_WIDTH 8U
+#define XHC_RHSHSR0__RTY_RESETVALUE 0x00U
+#define XHC_RHSHSR0_WIDTH 32U
+#define XHC_RHSHSR0__WIDTH 32U
+#define XHC_RHSHSR0_ALL_L 31U
+#define XHC_RHSHSR0_ALL_R 0U
+#define XHC_RHSHSR0__ALL_L 31U
+#define XHC_RHSHSR0__ALL_R 0U
+#define XHC_RHSHSR0_DATAMASK 0xffffffffU
+#define XHC_RHSHSR0_RDWRMASK 0x00000000U
+#define XHC_RHSHSR0_RESETVALUE 0x00000000U
+
+#define XHC_RHSHSC1_OFFSET 0xc98U
+#define XHC_RHSHSC1_BASE 0xc98U
+#define XHC_RHSHSC1__TMR_L 31U
+#define XHC_RHSHSC1__TMR_R 16U
+#define XHC_RHSHSC1__TMR_WIDTH 16U
+#define XHC_RHSHSC1__TMR_RESETVALUE 0x0000U
+#define XHC_RHSHSC1__RSL_L 7U
+#define XHC_RHSHSC1__RSL_R 6U
+#define XHC_RHSHSC1__RSL_WIDTH 2U
+#define XHC_RHSHSC1__RSL_RESETVALUE 0x0U
+#define XHC_RHSHSC1__AS_M_L 5U
+#define XHC_RHSHSC1__AS_M_R 4U
+#define XHC_RHSHSC1__AS_M_WIDTH 2U
+#define XHC_RHSHSC1__AS_M_RESETVALUE 0x0U
+#define XHC_RHSHSC1__CMD_L 3U
+#define XHC_RHSHSC1__CMD_R 2U
+#define XHC_RHSHSC1__CMD_WIDTH 2U
+#define XHC_RHSHSC1__CMD_RESETVALUE 0x0U
+#define XHC_RHSHSC1__reserved 1U
+#define XHC_RHSHSC1__reserved_L 1U
+#define XHC_RHSHSC1__reserved_R 1U
+#define XHC_RHSHSC1__reserved_WIDTH 1U
+#define XHC_RHSHSC1__reserved_RESETVALUE 0x0U
+#define XHC_RHSHSC1__STB 0U
+#define XHC_RHSHSC1__STB_L 0U
+#define XHC_RHSHSC1__STB_R 0U
+#define XHC_RHSHSC1__STB_WIDTH 1U
+#define XHC_RHSHSC1__STB_RESETVALUE 0x0U
+#define XHC_RHSHSC1__RESERVED_L 15U
+#define XHC_RHSHSC1__RESERVED_R 8U
+#define XHC_RHSHSC1_WIDTH 32U
+#define XHC_RHSHSC1__WIDTH 32U
+#define XHC_RHSHSC1_ALL_L 31U
+#define XHC_RHSHSC1_ALL_R 0U
+#define XHC_RHSHSC1__ALL_L 31U
+#define XHC_RHSHSC1__ALL_R 0U
+#define XHC_RHSHSC1_DATAMASK 0xffff00ffU
+#define XHC_RHSHSC1_RDWRMASK 0x0000ff00U
+#define XHC_RHSHSC1_RESETVALUE 0x00000000U
+
+#define XHC_RHSHSR1_OFFSET 0xc9cU
+#define XHC_RHSHSR1_BASE 0xc9cU
+#define XHC_RHSHSR1__C2U_L 31U
+#define XHC_RHSHSR1__C2U_R 24U
+#define XHC_RHSHSR1__C2U_WIDTH 8U
+#define XHC_RHSHSR1__C2U_RESETVALUE 0x00U
+#define XHC_RHSHSR1__C1U_L 23U
+#define XHC_RHSHSR1__C1U_R 16U
+#define XHC_RHSHSR1__C1U_WIDTH 8U
+#define XHC_RHSHSR1__C1U_RESETVALUE 0x00U
+#define XHC_RHSHSR1__RCV_L 15U
+#define XHC_RHSHSR1__RCV_R 8U
+#define XHC_RHSHSR1__RCV_WIDTH 8U
+#define XHC_RHSHSR1__RCV_RESETVALUE 0x00U
+#define XHC_RHSHSR1__RTY_L 7U
+#define XHC_RHSHSR1__RTY_R 0U
+#define XHC_RHSHSR1__RTY_WIDTH 8U
+#define XHC_RHSHSR1__RTY_RESETVALUE 0x00U
+#define XHC_RHSHSR1_WIDTH 32U
+#define XHC_RHSHSR1__WIDTH 32U
+#define XHC_RHSHSR1_ALL_L 31U
+#define XHC_RHSHSR1_ALL_R 0U
+#define XHC_RHSHSR1__ALL_L 31U
+#define XHC_RHSHSR1__ALL_R 0U
+#define XHC_RHSHSR1_DATAMASK 0xffffffffU
+#define XHC_RHSHSR1_RDWRMASK 0x00000000U
+#define XHC_RHSHSR1_RESETVALUE 0x00000000U
+
+#define XHC_RHSHSC2_OFFSET 0xca0U
+#define XHC_RHSHSC2_BASE 0xca0U
+#define XHC_RHSHSC2__TMR_L 31U
+#define XHC_RHSHSC2__TMR_R 16U
+#define XHC_RHSHSC2__TMR_WIDTH 16U
+#define XHC_RHSHSC2__TMR_RESETVALUE 0x0000U
+#define XHC_RHSHSC2__RSL_L 7U
+#define XHC_RHSHSC2__RSL_R 6U
+#define XHC_RHSHSC2__RSL_WIDTH 2U
+#define XHC_RHSHSC2__RSL_RESETVALUE 0x0U
+#define XHC_RHSHSC2__AS_M_L 5U
+#define XHC_RHSHSC2__AS_M_R 4U
+#define XHC_RHSHSC2__AS_M_WIDTH 2U
+#define XHC_RHSHSC2__AS_M_RESETVALUE 0x0U
+#define XHC_RHSHSC2__CMD_L 3U
+#define XHC_RHSHSC2__CMD_R 2U
+#define XHC_RHSHSC2__CMD_WIDTH 2U
+#define XHC_RHSHSC2__CMD_RESETVALUE 0x0U
+#define XHC_RHSHSC2__reserved 1U
+#define XHC_RHSHSC2__reserved_L 1U
+#define XHC_RHSHSC2__reserved_R 1U
+#define XHC_RHSHSC2__reserved_WIDTH 1U
+#define XHC_RHSHSC2__reserved_RESETVALUE 0x0U
+#define XHC_RHSHSC2__STB 0U
+#define XHC_RHSHSC2__STB_L 0U
+#define XHC_RHSHSC2__STB_R 0U
+#define XHC_RHSHSC2__STB_WIDTH 1U
+#define XHC_RHSHSC2__STB_RESETVALUE 0x0U
+#define XHC_RHSHSC2__RESERVED_L 15U
+#define XHC_RHSHSC2__RESERVED_R 8U
+#define XHC_RHSHSC2_WIDTH 32U
+#define XHC_RHSHSC2__WIDTH 32U
+#define XHC_RHSHSC2_ALL_L 31U
+#define XHC_RHSHSC2_ALL_R 0U
+#define XHC_RHSHSC2__ALL_L 31U
+#define XHC_RHSHSC2__ALL_R 0U
+#define XHC_RHSHSC2_DATAMASK 0xffff00ffU
+#define XHC_RHSHSC2_RDWRMASK 0x0000ff00U
+#define XHC_RHSHSC2_RESETVALUE 0x00000000U
+
+#define XHC_RHSHSR2_OFFSET 0xca4U
+#define XHC_RHSHSR2_BASE 0xca4U
+#define XHC_RHSHSR2__C2U_L 31U
+#define XHC_RHSHSR2__C2U_R 24U
+#define XHC_RHSHSR2__C2U_WIDTH 8U
+#define XHC_RHSHSR2__C2U_RESETVALUE 0x00U
+#define XHC_RHSHSR2__C1U_L 23U
+#define XHC_RHSHSR2__C1U_R 16U
+#define XHC_RHSHSR2__C1U_WIDTH 8U
+#define XHC_RHSHSR2__C1U_RESETVALUE 0x00U
+#define XHC_RHSHSR2__RCV_L 15U
+#define XHC_RHSHSR2__RCV_R 8U
+#define XHC_RHSHSR2__RCV_WIDTH 8U
+#define XHC_RHSHSR2__RCV_RESETVALUE 0x00U
+#define XHC_RHSHSR2__RTY_L 7U
+#define XHC_RHSHSR2__RTY_R 0U
+#define XHC_RHSHSR2__RTY_WIDTH 8U
+#define XHC_RHSHSR2__RTY_RESETVALUE 0x00U
+#define XHC_RHSHSR2_WIDTH 32U
+#define XHC_RHSHSR2__WIDTH 32U
+#define XHC_RHSHSR2_ALL_L 31U
+#define XHC_RHSHSR2_ALL_R 0U
+#define XHC_RHSHSR2__ALL_L 31U
+#define XHC_RHSHSR2__ALL_R 0U
+#define XHC_RHSHSR2_DATAMASK 0xffffffffU
+#define XHC_RHSHSR2_RDWRMASK 0x00000000U
+#define XHC_RHSHSR2_RESETVALUE 0x00000000U
+
+#define XHC_RHSHSC3_OFFSET 0xca8U
+#define XHC_RHSHSC3_BASE 0xca8U
+#define XHC_RHSHSC3__TMR_L 31U
+#define XHC_RHSHSC3__TMR_R 16U
+#define XHC_RHSHSC3__TMR_WIDTH 16U
+#define XHC_RHSHSC3__TMR_RESETVALUE 0x0000U
+#define XHC_RHSHSC3__RSL_L 7U
+#define XHC_RHSHSC3__RSL_R 6U
+#define XHC_RHSHSC3__RSL_WIDTH 2U
+#define XHC_RHSHSC3__RSL_RESETVALUE 0x0U
+#define XHC_RHSHSC3__AS_M_L 5U
+#define XHC_RHSHSC3__AS_M_R 4U
+#define XHC_RHSHSC3__AS_M_WIDTH 2U
+#define XHC_RHSHSC3__AS_M_RESETVALUE 0x0U
+#define XHC_RHSHSC3__CMD_L 3U
+#define XHC_RHSHSC3__CMD_R 2U
+#define XHC_RHSHSC3__CMD_WIDTH 2U
+#define XHC_RHSHSC3__CMD_RESETVALUE 0x0U
+#define XHC_RHSHSC3__reserved 1U
+#define XHC_RHSHSC3__reserved_L 1U
+#define XHC_RHSHSC3__reserved_R 1U
+#define XHC_RHSHSC3__reserved_WIDTH 1U
+#define XHC_RHSHSC3__reserved_RESETVALUE 0x0U
+#define XHC_RHSHSC3__STB 0U
+#define XHC_RHSHSC3__STB_L 0U
+#define XHC_RHSHSC3__STB_R 0U
+#define XHC_RHSHSC3__STB_WIDTH 1U
+#define XHC_RHSHSC3__STB_RESETVALUE 0x0U
+#define XHC_RHSHSC3__RESERVED_L 15U
+#define XHC_RHSHSC3__RESERVED_R 8U
+#define XHC_RHSHSC3_WIDTH 32U
+#define XHC_RHSHSC3__WIDTH 32U
+#define XHC_RHSHSC3_ALL_L 31U
+#define XHC_RHSHSC3_ALL_R 0U
+#define XHC_RHSHSC3__ALL_L 31U
+#define XHC_RHSHSC3__ALL_R 0U
+#define XHC_RHSHSC3_DATAMASK 0xffff00ffU
+#define XHC_RHSHSC3_RDWRMASK 0x0000ff00U
+#define XHC_RHSHSC3_RESETVALUE 0x00000000U
+
+#define XHC_RHSHSR3_OFFSET 0xcacU
+#define XHC_RHSHSR3_BASE 0xcacU
+#define XHC_RHSHSR3__C2U_L 31U
+#define XHC_RHSHSR3__C2U_R 24U
+#define XHC_RHSHSR3__C2U_WIDTH 8U
+#define XHC_RHSHSR3__C2U_RESETVALUE 0x00U
+#define XHC_RHSHSR3__C1U_L 23U
+#define XHC_RHSHSR3__C1U_R 16U
+#define XHC_RHSHSR3__C1U_WIDTH 8U
+#define XHC_RHSHSR3__C1U_RESETVALUE 0x00U
+#define XHC_RHSHSR3__RCV_L 15U
+#define XHC_RHSHSR3__RCV_R 8U
+#define XHC_RHSHSR3__RCV_WIDTH 8U
+#define XHC_RHSHSR3__RCV_RESETVALUE 0x00U
+#define XHC_RHSHSR3__RTY_L 7U
+#define XHC_RHSHSR3__RTY_R 0U
+#define XHC_RHSHSR3__RTY_WIDTH 8U
+#define XHC_RHSHSR3__RTY_RESETVALUE 0x00U
+#define XHC_RHSHSR3_WIDTH 32U
+#define XHC_RHSHSR3__WIDTH 32U
+#define XHC_RHSHSR3_ALL_L 31U
+#define XHC_RHSHSR3_ALL_R 0U
+#define XHC_RHSHSR3__ALL_L 31U
+#define XHC_RHSHSR3__ALL_R 0U
+#define XHC_RHSHSR3_DATAMASK 0xffffffffU
+#define XHC_RHSHSR3_RDWRMASK 0x00000000U
+#define XHC_RHSHSR3_RESETVALUE 0x00000000U
+
+#define XHC_ECHSSP_OFFSET 0xcb0U
+#define XHC_ECHSSP_BASE 0xcb0U
+#define XHC_ECHSSP__reserved_L 31U
+#define XHC_ECHSSP__reserved_R 16U
+#define XHC_ECHSSP__reserved_WIDTH 16U
+#define XHC_ECHSSP__reserved_RESETVALUE 0x0000U
+#define XHC_ECHSSP__NCP_L 15U
+#define XHC_ECHSSP__NCP_R 8U
+#define XHC_ECHSSP__NCP_WIDTH 8U
+#define XHC_ECHSSP__NCP_RESETVALUE 0x04U
+#define XHC_ECHSSP__CID_L 7U
+#define XHC_ECHSSP__CID_R 0U
+#define XHC_ECHSSP__CID_WIDTH 8U
+#define XHC_ECHSSP__CID_RESETVALUE 0xc6U
+#define XHC_ECHSSP_WIDTH 32U
+#define XHC_ECHSSP__WIDTH 32U
+#define XHC_ECHSSP_ALL_L 31U
+#define XHC_ECHSSP_ALL_R 0U
+#define XHC_ECHSSP__ALL_L 31U
+#define XHC_ECHSSP__ALL_R 0U
+#define XHC_ECHSSP_DATAMASK 0xffffffffU
+#define XHC_ECHSSP_RDWRMASK 0x00000000U
+#define XHC_ECHSSP_RESETVALUE 0x000004c6U
+
+#define XHC_SSPVER_OFFSET 0xcb4U
+#define XHC_SSPVER_BASE 0xcb4U
+#define XHC_SSPVER__MAJ_L 31U
+#define XHC_SSPVER__MAJ_R 28U
+#define XHC_SSPVER__MAJ_WIDTH 4U
+#define XHC_SSPVER__MAJ_RESETVALUE 0x0U
+#define XHC_SSPVER__MIN_L 27U
+#define XHC_SSPVER__MIN_R 24U
+#define XHC_SSPVER__MIN_WIDTH 4U
+#define XHC_SSPVER__MIN_RESETVALUE 0x0U
+#define XHC_SSPVER__RLS_L 23U
+#define XHC_SSPVER__RLS_R 20U
+#define XHC_SSPVER__RLS_WIDTH 4U
+#define XHC_SSPVER__RLS_RESETVALUE 0x0U
+#define XHC_SSPVER__reserved_L 19U
+#define XHC_SSPVER__reserved_R 0U
+#define XHC_SSPVER__reserved_WIDTH 20U
+#define XHC_SSPVER__reserved_RESETVALUE 0x00000U
+#define XHC_SSPVER_WIDTH 32U
+#define XHC_SSPVER__WIDTH 32U
+#define XHC_SSPVER_ALL_L 31U
+#define XHC_SSPVER_ALL_R 0U
+#define XHC_SSPVER__ALL_L 31U
+#define XHC_SSPVER__ALL_R 0U
+#define XHC_SSPVER_DATAMASK 0xffffffffU
+#define XHC_SSPVER_RDWRMASK 0x00000000U
+#define XHC_SSPVER_RESETVALUE 0x00000000U
+
+#define XHC_SSPMGN_OFFSET 0xcb8U
+#define XHC_SSPMGN_BASE 0xcb8U
+#define XHC_SSPMGN__MGN_L 31U
+#define XHC_SSPMGN__MGN_R 0U
+#define XHC_SSPMGN__MGN_WIDTH 32U
+#define XHC_SSPMGN__MGN_RESETVALUE 0x4b535040U
+#define XHC_SSPMGN_WIDTH 32U
+#define XHC_SSPMGN__WIDTH 32U
+#define XHC_SSPMGN_ALL_L 31U
+#define XHC_SSPMGN_ALL_R 0U
+#define XHC_SSPMGN__ALL_L 31U
+#define XHC_SSPMGN__ALL_R 0U
+#define XHC_SSPMGN_DATAMASK 0xffffffffU
+#define XHC_SSPMGN_RDWRMASK 0x00000000U
+#define XHC_SSPMGN_RESETVALUE 0x4b535040U
+
+#define XHC_ECHFSC2_OFFSET 0xcc0U
+#define XHC_ECHFSC2_BASE 0xcc0U
+#define XHC_ECHFSC2__reserved_L 31U
+#define XHC_ECHFSC2__reserved_R 16U
+#define XHC_ECHFSC2__reserved_WIDTH 16U
+#define XHC_ECHFSC2__reserved_RESETVALUE 0x0000U
+#define XHC_ECHFSC2__NCP_L 15U
+#define XHC_ECHFSC2__NCP_R 8U
+#define XHC_ECHFSC2__NCP_WIDTH 8U
+#define XHC_ECHFSC2__NCP_RESETVALUE 0x50U
+#define XHC_ECHFSC2__CID_L 7U
+#define XHC_ECHFSC2__CID_R 0U
+#define XHC_ECHFSC2__CID_WIDTH 8U
+#define XHC_ECHFSC2__CID_RESETVALUE 0xc7U
+#define XHC_ECHFSC2_WIDTH 32U
+#define XHC_ECHFSC2__WIDTH 32U
+#define XHC_ECHFSC2_ALL_L 31U
+#define XHC_ECHFSC2_ALL_R 0U
+#define XHC_ECHFSC2__ALL_L 31U
+#define XHC_ECHFSC2__ALL_R 0U
+#define XHC_ECHFSC2_DATAMASK 0xffffffffU
+#define XHC_ECHFSC2_RDWRMASK 0x00000000U
+#define XHC_ECHFSC2_RESETVALUE 0x000050c7U
+
+#define XHC_FSC2POC_OFFSET 0xcd4U
+#define XHC_FSC2POC_BASE 0xcd4U
+#define XHC_FSC2POC__NCS_L 31U
+#define XHC_FSC2POC__NCS_R 28U
+#define XHC_FSC2POC__NCS_WIDTH 4U
+#define XHC_FSC2POC__NCS_RESETVALUE 0x0U
+#define XHC_FSC2POC__FSIZ_L 22U
+#define XHC_FSC2POC__FSIZ_R 18U
+#define XHC_FSC2POC__FSIZ_WIDTH 5U
+#define XHC_FSC2POC__FSIZ_RESETVALUE 0x0U
+#define XHC_FSC2POC__PSIZ_L 16U
+#define XHC_FSC2POC__PSIZ_R 12U
+#define XHC_FSC2POC__PSIZ_WIDTH 5U
+#define XHC_FSC2POC__PSIZ_RESETVALUE 0x0U
+#define XHC_FSC2POC__reserved_L 11U
+#define XHC_FSC2POC__reserved_R 5U
+#define XHC_FSC2POC__reserved_WIDTH 7U
+#define XHC_FSC2POC__reserved_RESETVALUE 0x0U
+#define XHC_FSC2POC__TSIZ_L 4U
+#define XHC_FSC2POC__TSIZ_R 0U
+#define XHC_FSC2POC__TSIZ_WIDTH 5U
+#define XHC_FSC2POC__TSIZ_RESETVALUE 0x0U
+#define XHC_FSC2POC__RESERVED_L 27U
+#define XHC_FSC2POC__RESERVED_R 23U
+#define XHC_FSC2POC_WIDTH 32U
+#define XHC_FSC2POC__WIDTH 32U
+#define XHC_FSC2POC_ALL_L 31U
+#define XHC_FSC2POC_ALL_R 0U
+#define XHC_FSC2POC__ALL_L 31U
+#define XHC_FSC2POC__ALL_R 0U
+#define XHC_FSC2POC_DATAMASK 0xf07dffffU
+#define XHC_FSC2POC_RDWRMASK 0x0f820000U
+#define XHC_FSC2POC_RESETVALUE 0x00000000U
+
+#define XHC_FSC2GOC_OFFSET 0xcd8U
+#define XHC_FSC2GOC_BASE 0xcd8U
+#define XHC_FSC2GOC__NCS_L 31U
+#define XHC_FSC2GOC__NCS_R 28U
+#define XHC_FSC2GOC__NCS_WIDTH 4U
+#define XHC_FSC2GOC__NCS_RESETVALUE 0x0U
+#define XHC_FSC2GOC__FSIZ_L 22U
+#define XHC_FSC2GOC__FSIZ_R 18U
+#define XHC_FSC2GOC__FSIZ_WIDTH 5U
+#define XHC_FSC2GOC__FSIZ_RESETVALUE 0x0U
+#define XHC_FSC2GOC__PSIZ_L 16U
+#define XHC_FSC2GOC__PSIZ_R 12U
+#define XHC_FSC2GOC__PSIZ_WIDTH 5U
+#define XHC_FSC2GOC__PSIZ_RESETVALUE 0x0U
+#define XHC_FSC2GOC__reserved_L 11U
+#define XHC_FSC2GOC__reserved_R 5U
+#define XHC_FSC2GOC__reserved_WIDTH 7U
+#define XHC_FSC2GOC__reserved_RESETVALUE 0x0U
+#define XHC_FSC2GOC__TSIZ_L 4U
+#define XHC_FSC2GOC__TSIZ_R 0U
+#define XHC_FSC2GOC__TSIZ_WIDTH 5U
+#define XHC_FSC2GOC__TSIZ_RESETVALUE 0x0U
+#define XHC_FSC2GOC__RESERVED_L 27U
+#define XHC_FSC2GOC__RESERVED_R 23U
+#define XHC_FSC2GOC_WIDTH 32U
+#define XHC_FSC2GOC__WIDTH 32U
+#define XHC_FSC2GOC_ALL_L 31U
+#define XHC_FSC2GOC_ALL_R 0U
+#define XHC_FSC2GOC__ALL_L 31U
+#define XHC_FSC2GOC__ALL_R 0U
+#define XHC_FSC2GOC_DATAMASK 0xf07dffffU
+#define XHC_FSC2GOC_RDWRMASK 0x0f820000U
+#define XHC_FSC2GOC_RESETVALUE 0x00000000U
+
+#define XHC_FSC2NOC_OFFSET 0xcdcU
+#define XHC_FSC2NOC_BASE 0xcdcU
+#define XHC_FSC2NOC__NCS_L 31U
+#define XHC_FSC2NOC__NCS_R 28U
+#define XHC_FSC2NOC__NCS_WIDTH 4U
+#define XHC_FSC2NOC__NCS_RESETVALUE 0x0U
+#define XHC_FSC2NOC__FSIZ_L 22U
+#define XHC_FSC2NOC__FSIZ_R 18U
+#define XHC_FSC2NOC__FSIZ_WIDTH 5U
+#define XHC_FSC2NOC__FSIZ_RESETVALUE 0x0U
+#define XHC_FSC2NOC__PSIZ_L 16U
+#define XHC_FSC2NOC__PSIZ_R 12U
+#define XHC_FSC2NOC__PSIZ_WIDTH 5U
+#define XHC_FSC2NOC__PSIZ_RESETVALUE 0x0U
+#define XHC_FSC2NOC__reserved_L 11U
+#define XHC_FSC2NOC__reserved_R 5U
+#define XHC_FSC2NOC__reserved_WIDTH 7U
+#define XHC_FSC2NOC__reserved_RESETVALUE 0x0U
+#define XHC_FSC2NOC__TSIZ_L 4U
+#define XHC_FSC2NOC__TSIZ_R 0U
+#define XHC_FSC2NOC__TSIZ_WIDTH 5U
+#define XHC_FSC2NOC__TSIZ_RESETVALUE 0x0U
+#define XHC_FSC2NOC__RESERVED_L 27U
+#define XHC_FSC2NOC__RESERVED_R 23U
+#define XHC_FSC2NOC_WIDTH 32U
+#define XHC_FSC2NOC__WIDTH 32U
+#define XHC_FSC2NOC_ALL_L 31U
+#define XHC_FSC2NOC_ALL_R 0U
+#define XHC_FSC2NOC__ALL_L 31U
+#define XHC_FSC2NOC__ALL_R 0U
+#define XHC_FSC2NOC_DATAMASK 0xf07dffffU
+#define XHC_FSC2NOC_RDWRMASK 0x0f820000U
+#define XHC_FSC2NOC_RESETVALUE 0x00000000U
+
+#define XHC_FSC2AIC_OFFSET 0xce0U
+#define XHC_FSC2AIC_BASE 0xce0U
+#define XHC_FSC2AIC__FSIZ_L 22U
+#define XHC_FSC2AIC__FSIZ_R 18U
+#define XHC_FSC2AIC__FSIZ_WIDTH 5U
+#define XHC_FSC2AIC__FSIZ_RESETVALUE 0x0U
+#define XHC_FSC2AIC__PSIZ_L 16U
+#define XHC_FSC2AIC__PSIZ_R 12U
+#define XHC_FSC2AIC__PSIZ_WIDTH 5U
+#define XHC_FSC2AIC__PSIZ_RESETVALUE 0x0U
+#define XHC_FSC2AIC__reserved_L 11U
+#define XHC_FSC2AIC__reserved_R 0U
+#define XHC_FSC2AIC__reserved_WIDTH 12U
+#define XHC_FSC2AIC__reserved_RESETVALUE 0x000U
+#define XHC_FSC2AIC__RESERVED_L 31U
+#define XHC_FSC2AIC__RESERVED_R 23U
+#define XHC_FSC2AIC_WIDTH 23U
+#define XHC_FSC2AIC__WIDTH 23U
+#define XHC_FSC2AIC_ALL_L 22U
+#define XHC_FSC2AIC_ALL_R 0U
+#define XHC_FSC2AIC__ALL_L 22U
+#define XHC_FSC2AIC__ALL_R 0U
+#define XHC_FSC2AIC_DATAMASK 0x007dffffU
+#define XHC_FSC2AIC_RDWRMASK 0xff820000U
+#define XHC_FSC2AIC_RESETVALUE 0x000000U
+
+#define XHC_FSC2PIC_OFFSET 0xce4U
+#define XHC_FSC2PIC_BASE 0xce4U
+#define XHC_FSC2PIC__NCS_L 31U
+#define XHC_FSC2PIC__NCS_R 28U
+#define XHC_FSC2PIC__NCS_WIDTH 4U
+#define XHC_FSC2PIC__NCS_RESETVALUE 0x0U
+#define XHC_FSC2PIC__reserved_L 27U
+#define XHC_FSC2PIC__reserved_R 5U
+#define XHC_FSC2PIC__reserved_WIDTH 23U
+#define XHC_FSC2PIC__reserved_RESETVALUE 0x0U
+#define XHC_FSC2PIC__TSIZ_L 4U
+#define XHC_FSC2PIC__TSIZ_R 0U
+#define XHC_FSC2PIC__TSIZ_WIDTH 5U
+#define XHC_FSC2PIC__TSIZ_RESETVALUE 0x0U
+#define XHC_FSC2PIC_WIDTH 32U
+#define XHC_FSC2PIC__WIDTH 32U
+#define XHC_FSC2PIC_ALL_L 31U
+#define XHC_FSC2PIC_ALL_R 0U
+#define XHC_FSC2PIC__ALL_L 31U
+#define XHC_FSC2PIC__ALL_R 0U
+#define XHC_FSC2PIC_DATAMASK 0xffffffffU
+#define XHC_FSC2PIC_RDWRMASK 0x00000000U
+#define XHC_FSC2PIC_RESETVALUE 0x00000000U
+
+#define XHC_FSC2GIC_OFFSET 0xce8U
+#define XHC_FSC2GIC_BASE 0xce8U
+#define XHC_FSC2GIC__NCS_L 31U
+#define XHC_FSC2GIC__NCS_R 28U
+#define XHC_FSC2GIC__NCS_WIDTH 4U
+#define XHC_FSC2GIC__NCS_RESETVALUE 0x0U
+#define XHC_FSC2GIC__reserved_L 27U
+#define XHC_FSC2GIC__reserved_R 5U
+#define XHC_FSC2GIC__reserved_WIDTH 23U
+#define XHC_FSC2GIC__reserved_RESETVALUE 0x0U
+#define XHC_FSC2GIC__TSIZ_L 4U
+#define XHC_FSC2GIC__TSIZ_R 0U
+#define XHC_FSC2GIC__TSIZ_WIDTH 5U
+#define XHC_FSC2GIC__TSIZ_RESETVALUE 0x0U
+#define XHC_FSC2GIC_WIDTH 32U
+#define XHC_FSC2GIC__WIDTH 32U
+#define XHC_FSC2GIC_ALL_L 31U
+#define XHC_FSC2GIC_ALL_R 0U
+#define XHC_FSC2GIC__ALL_L 31U
+#define XHC_FSC2GIC__ALL_R 0U
+#define XHC_FSC2GIC_DATAMASK 0xffffffffU
+#define XHC_FSC2GIC_RDWRMASK 0x00000000U
+#define XHC_FSC2GIC_RESETVALUE 0x00000000U
+
+#define XHC_FSC2NIC_OFFSET 0xcecU
+#define XHC_FSC2NIC_BASE 0xcecU
+#define XHC_FSC2NIC__NCS_L 31U
+#define XHC_FSC2NIC__NCS_R 28U
+#define XHC_FSC2NIC__NCS_WIDTH 4U
+#define XHC_FSC2NIC__NCS_RESETVALUE 0x0U
+#define XHC_FSC2NIC__reserved_L 27U
+#define XHC_FSC2NIC__reserved_R 5U
+#define XHC_FSC2NIC__reserved_WIDTH 23U
+#define XHC_FSC2NIC__reserved_RESETVALUE 0x0U
+#define XHC_FSC2NIC__TSIZ_L 4U
+#define XHC_FSC2NIC__TSIZ_R 0U
+#define XHC_FSC2NIC__TSIZ_WIDTH 5U
+#define XHC_FSC2NIC__TSIZ_RESETVALUE 0x0U
+#define XHC_FSC2NIC_WIDTH 32U
+#define XHC_FSC2NIC__WIDTH 32U
+#define XHC_FSC2NIC_ALL_L 31U
+#define XHC_FSC2NIC_ALL_R 0U
+#define XHC_FSC2NIC__ALL_L 31U
+#define XHC_FSC2NIC__ALL_R 0U
+#define XHC_FSC2NIC_DATAMASK 0xffffffffU
+#define XHC_FSC2NIC_RDWRMASK 0x00000000U
+#define XHC_FSC2NIC_RESETVALUE 0x00000000U
+
+#define XHC_ECHPRT2_OFFSET 0xcf0U
+#define XHC_ECHPRT2_BASE 0xcf0U
+#define XHC_ECHPRT2__HDP 31U
+#define XHC_ECHPRT2__HDP_L 31U
+#define XHC_ECHPRT2__HDP_R 31U
+#define XHC_ECHPRT2__HDP_WIDTH 1U
+#define XHC_ECHPRT2__HDP_RESETVALUE 0x0U
+#define XHC_ECHPRT2__FDP 30U
+#define XHC_ECHPRT2__FDP_L 30U
+#define XHC_ECHPRT2__FDP_R 30U
+#define XHC_ECHPRT2__FDP_WIDTH 1U
+#define XHC_ECHPRT2__FDP_RESETVALUE 0x0U
+#define XHC_ECHPRT2__reserved_L 29U
+#define XHC_ECHPRT2__reserved_R 17U
+#define XHC_ECHPRT2__reserved_WIDTH 13U
+#define XHC_ECHPRT2__reserved_RESETVALUE 0x0U
+#define XHC_ECHPRT2__HST 16U
+#define XHC_ECHPRT2__HST_L 16U
+#define XHC_ECHPRT2__HST_R 16U
+#define XHC_ECHPRT2__HST_WIDTH 1U
+#define XHC_ECHPRT2__HST_RESETVALUE 0x0U
+#define XHC_ECHPRT2__NCP_L 15U
+#define XHC_ECHPRT2__NCP_R 8U
+#define XHC_ECHPRT2__NCP_WIDTH 8U
+#define XHC_ECHPRT2__NCP_RESETVALUE 0x04U
+#define XHC_ECHPRT2__CID_L 7U
+#define XHC_ECHPRT2__CID_R 0U
+#define XHC_ECHPRT2__CID_WIDTH 8U
+#define XHC_ECHPRT2__CID_RESETVALUE 0xc8U
+#define XHC_ECHPRT2_WIDTH 32U
+#define XHC_ECHPRT2__WIDTH 32U
+#define XHC_ECHPRT2_ALL_L 31U
+#define XHC_ECHPRT2_ALL_R 0U
+#define XHC_ECHPRT2__ALL_L 31U
+#define XHC_ECHPRT2__ALL_R 0U
+#define XHC_ECHPRT2_DATAMASK 0xffffffffU
+#define XHC_ECHPRT2_RDWRMASK 0x00000000U
+#define XHC_ECHPRT2_RESETVALUE 0x000004c8U
+
+#define XHC_PRT2HSC_OFFSET 0xcf8U
+#define XHC_PRT2HSC_BASE 0xcf8U
+#define XHC_PRT2HSC__TMR_L 31U
+#define XHC_PRT2HSC__TMR_R 16U
+#define XHC_PRT2HSC__TMR_WIDTH 16U
+#define XHC_PRT2HSC__TMR_RESETVALUE 0x0000U
+#define XHC_PRT2HSC__RSL_L 7U
+#define XHC_PRT2HSC__RSL_R 6U
+#define XHC_PRT2HSC__RSL_WIDTH 2U
+#define XHC_PRT2HSC__RSL_RESETVALUE 0x0U
+#define XHC_PRT2HSC__AS_M_L 5U
+#define XHC_PRT2HSC__AS_M_R 4U
+#define XHC_PRT2HSC__AS_M_WIDTH 2U
+#define XHC_PRT2HSC__AS_M_RESETVALUE 0x0U
+#define XHC_PRT2HSC__CMD_L 3U
+#define XHC_PRT2HSC__CMD_R 2U
+#define XHC_PRT2HSC__CMD_WIDTH 2U
+#define XHC_PRT2HSC__CMD_RESETVALUE 0x0U
+#define XHC_PRT2HSC__reserved 1U
+#define XHC_PRT2HSC__reserved_L 1U
+#define XHC_PRT2HSC__reserved_R 1U
+#define XHC_PRT2HSC__reserved_WIDTH 1U
+#define XHC_PRT2HSC__reserved_RESETVALUE 0x0U
+#define XHC_PRT2HSC__STB 0U
+#define XHC_PRT2HSC__STB_L 0U
+#define XHC_PRT2HSC__STB_R 0U
+#define XHC_PRT2HSC__STB_WIDTH 1U
+#define XHC_PRT2HSC__STB_RESETVALUE 0x0U
+#define XHC_PRT2HSC__RESERVED_L 15U
+#define XHC_PRT2HSC__RESERVED_R 8U
+#define XHC_PRT2HSC_WIDTH 32U
+#define XHC_PRT2HSC__WIDTH 32U
+#define XHC_PRT2HSC_ALL_L 31U
+#define XHC_PRT2HSC_ALL_R 0U
+#define XHC_PRT2HSC__ALL_L 31U
+#define XHC_PRT2HSC__ALL_R 0U
+#define XHC_PRT2HSC_DATAMASK 0xffff00ffU
+#define XHC_PRT2HSC_RDWRMASK 0x0000ff00U
+#define XHC_PRT2HSC_RESETVALUE 0x00000000U
+
+#define XHC_PRT2HSR_OFFSET 0xcfcU
+#define XHC_PRT2HSR_BASE 0xcfcU
+#define XHC_PRT2HSR__RNAK_L 31U
+#define XHC_PRT2HSR__RNAK_R 24U
+#define XHC_PRT2HSR__RNAK_WIDTH 8U
+#define XHC_PRT2HSR__RNAK_RESETVALUE 0x00U
+#define XHC_PRT2HSR__HSTX_L 23U
+#define XHC_PRT2HSR__HSTX_R 16U
+#define XHC_PRT2HSR__HSTX_WIDTH 8U
+#define XHC_PRT2HSR__HSTX_RESETVALUE 0x00U
+#define XHC_PRT2HSR__HSRX_L 15U
+#define XHC_PRT2HSR__HSRX_R 8U
+#define XHC_PRT2HSR__HSRX_WIDTH 8U
+#define XHC_PRT2HSR__HSRX_RESETVALUE 0x00U
+#define XHC_PRT2HSR__SPLT_L 7U
+#define XHC_PRT2HSR__SPLT_R 0U
+#define XHC_PRT2HSR__SPLT_WIDTH 8U
+#define XHC_PRT2HSR__SPLT_RESETVALUE 0x00U
+#define XHC_PRT2HSR_WIDTH 32U
+#define XHC_PRT2HSR__WIDTH 32U
+#define XHC_PRT2HSR_ALL_L 31U
+#define XHC_PRT2HSR_ALL_R 0U
+#define XHC_PRT2HSR__ALL_L 31U
+#define XHC_PRT2HSR__ALL_R 0U
+#define XHC_PRT2HSR_DATAMASK 0xffffffffU
+#define XHC_PRT2HSR_RDWRMASK 0x00000000U
+#define XHC_PRT2HSR_RESETVALUE 0x00000000U
+
+#define XHC_ECHRH2_OFFSET 0xd00U
+#define XHC_ECHRH2_BASE 0xd00U
+#define XHC_ECHRH2__MTT 31U
+#define XHC_ECHRH2__MTT_L 31U
+#define XHC_ECHRH2__MTT_R 31U
+#define XHC_ECHRH2__MTT_WIDTH 1U
+#define XHC_ECHRH2__MTT_RESETVALUE 0x0U
+#define XHC_ECHRH2__RPO_L 30U
+#define XHC_ECHRH2__RPO_R 24U
+#define XHC_ECHRH2__RPO_WIDTH 7U
+#define XHC_ECHRH2__RPO_RESETVALUE 0x0U
+#define XHC_ECHRH2__reserved_L 23U
+#define XHC_ECHRH2__reserved_R 22U
+#define XHC_ECHRH2__reserved_WIDTH 2U
+#define XHC_ECHRH2__reserved_RESETVALUE 0x0U
+#define XHC_ECHRH2__RPN_L 21U
+#define XHC_ECHRH2__RPN_R 20U
+#define XHC_ECHRH2__RPN_WIDTH 2U
+#define XHC_ECHRH2__RPN_RESETVALUE 0x0U
+#define XHC_ECHRH2__DNR_L 19U
+#define XHC_ECHRH2__DNR_R 16U
+#define XHC_ECHRH2__DNR_WIDTH 4U
+#define XHC_ECHRH2__DNR_RESETVALUE 0x0U
+#define XHC_ECHRH2__NCP_L 15U
+#define XHC_ECHRH2__NCP_R 8U
+#define XHC_ECHRH2__NCP_WIDTH 8U
+#define XHC_ECHRH2__NCP_RESETVALUE 0x0cU
+#define XHC_ECHRH2__CID_L 7U
+#define XHC_ECHRH2__CID_R 0U
+#define XHC_ECHRH2__CID_WIDTH 8U
+#define XHC_ECHRH2__CID_RESETVALUE 0xc9U
+#define XHC_ECHRH2_WIDTH 32U
+#define XHC_ECHRH2__WIDTH 32U
+#define XHC_ECHRH2_ALL_L 31U
+#define XHC_ECHRH2_ALL_R 0U
+#define XHC_ECHRH2__ALL_L 31U
+#define XHC_ECHRH2__ALL_R 0U
+#define XHC_ECHRH2_DATAMASK 0xffffffffU
+#define XHC_ECHRH2_RDWRMASK 0x00000000U
+#define XHC_ECHRH2_RESETVALUE 0x00000cc9U
+
+#define XHC_RH2DES_OFFSET 0xd04U
+#define XHC_RH2DES_BASE 0xd04U
+#define XHC_RH2DES__PIS3_L 31U
+#define XHC_RH2DES__PIS3_R 30U
+#define XHC_RH2DES__PIS3_WIDTH 2U
+#define XHC_RH2DES__PIS3_RESETVALUE 0x0U
+#define XHC_RH2DES__HIST3 24U
+#define XHC_RH2DES__HIST3_L 24U
+#define XHC_RH2DES__HIST3_R 24U
+#define XHC_RH2DES__HIST3_WIDTH 1U
+#define XHC_RH2DES__HIST3_RESETVALUE 0x0U
+#define XHC_RH2DES__PIS2_L 23U
+#define XHC_RH2DES__PIS2_R 22U
+#define XHC_RH2DES__PIS2_WIDTH 2U
+#define XHC_RH2DES__PIS2_RESETVALUE 0x0U
+#define XHC_RH2DES__HIST2 16U
+#define XHC_RH2DES__HIST2_L 16U
+#define XHC_RH2DES__HIST2_R 16U
+#define XHC_RH2DES__HIST2_WIDTH 1U
+#define XHC_RH2DES__HIST2_RESETVALUE 0x0U
+#define XHC_RH2DES__PIS1_L 15U
+#define XHC_RH2DES__PIS1_R 14U
+#define XHC_RH2DES__PIS1_WIDTH 2U
+#define XHC_RH2DES__PIS1_RESETVALUE 0x0U
+#define XHC_RH2DES__HIST1 8U
+#define XHC_RH2DES__HIST1_L 8U
+#define XHC_RH2DES__HIST1_R 8U
+#define XHC_RH2DES__HIST1_WIDTH 1U
+#define XHC_RH2DES__HIST1_RESETVALUE 0x0U
+#define XHC_RH2DES__PIS0_L 7U
+#define XHC_RH2DES__PIS0_R 6U
+#define XHC_RH2DES__PIS0_WIDTH 2U
+#define XHC_RH2DES__PIS0_RESETVALUE 0x0U
+#define XHC_RH2DES__reserved_L 5U
+#define XHC_RH2DES__reserved_R 1U
+#define XHC_RH2DES__reserved_WIDTH 5U
+#define XHC_RH2DES__reserved_RESETVALUE 0x0U
+#define XHC_RH2DES__HIST0 0U
+#define XHC_RH2DES__HIST0_L 0U
+#define XHC_RH2DES__HIST0_R 0U
+#define XHC_RH2DES__HIST0_WIDTH 1U
+#define XHC_RH2DES__HIST0_RESETVALUE 0x0U
+#define XHC_RH2DES__RESERVED_0_L 29U
+#define XHC_RH2DES__RESERVED_0_R 25U
+#define XHC_RH2DES__RESERVED_1_L 21U
+#define XHC_RH2DES__RESERVED_1_R 17U
+#define XHC_RH2DES__RESERVED_2_L 13U
+#define XHC_RH2DES__RESERVED_2_R 9U
+#define XHC_RH2DES__RESERVED_L 29U
+#define XHC_RH2DES__RESERVED_R 25U
+#define XHC_RH2DES_WIDTH 32U
+#define XHC_RH2DES__WIDTH 32U
+#define XHC_RH2DES_ALL_L 31U
+#define XHC_RH2DES_ALL_R 0U
+#define XHC_RH2DES__ALL_L 31U
+#define XHC_RH2DES__ALL_R 0U
+#define XHC_RH2DES_DATAMASK 0xc1c1c1ffU
+#define XHC_RH2DES_RDWRMASK 0x3e3e3e00U
+#define XHC_RH2DES_RESETVALUE 0x00000000U
+
+#define XHC_RH2HSC0_OFFSET 0xd10U
+#define XHC_RH2HSC0_BASE 0xd10U
+#define XHC_RH2HSC0__TMR_L 31U
+#define XHC_RH2HSC0__TMR_R 16U
+#define XHC_RH2HSC0__TMR_WIDTH 16U
+#define XHC_RH2HSC0__TMR_RESETVALUE 0x0000U
+#define XHC_RH2HSC0__RSL_L 7U
+#define XHC_RH2HSC0__RSL_R 6U
+#define XHC_RH2HSC0__RSL_WIDTH 2U
+#define XHC_RH2HSC0__RSL_RESETVALUE 0x0U
+#define XHC_RH2HSC0__AS_M_L 5U
+#define XHC_RH2HSC0__AS_M_R 4U
+#define XHC_RH2HSC0__AS_M_WIDTH 2U
+#define XHC_RH2HSC0__AS_M_RESETVALUE 0x0U
+#define XHC_RH2HSC0__CMD_L 3U
+#define XHC_RH2HSC0__CMD_R 2U
+#define XHC_RH2HSC0__CMD_WIDTH 2U
+#define XHC_RH2HSC0__CMD_RESETVALUE 0x0U
+#define XHC_RH2HSC0__reserved 1U
+#define XHC_RH2HSC0__reserved_L 1U
+#define XHC_RH2HSC0__reserved_R 1U
+#define XHC_RH2HSC0__reserved_WIDTH 1U
+#define XHC_RH2HSC0__reserved_RESETVALUE 0x0U
+#define XHC_RH2HSC0__STB 0U
+#define XHC_RH2HSC0__STB_L 0U
+#define XHC_RH2HSC0__STB_R 0U
+#define XHC_RH2HSC0__STB_WIDTH 1U
+#define XHC_RH2HSC0__STB_RESETVALUE 0x0U
+#define XHC_RH2HSC0__RESERVED_L 15U
+#define XHC_RH2HSC0__RESERVED_R 8U
+#define XHC_RH2HSC0_WIDTH 32U
+#define XHC_RH2HSC0__WIDTH 32U
+#define XHC_RH2HSC0_ALL_L 31U
+#define XHC_RH2HSC0_ALL_R 0U
+#define XHC_RH2HSC0__ALL_L 31U
+#define XHC_RH2HSC0__ALL_R 0U
+#define XHC_RH2HSC0_DATAMASK 0xffff00ffU
+#define XHC_RH2HSC0_RDWRMASK 0x0000ff00U
+#define XHC_RH2HSC0_RESETVALUE 0x00000000U
+
+#define XHC_RH2HSR0_OFFSET 0xd14U
+#define XHC_RH2HSR0_BASE 0xd14U
+#define XHC_RH2HSR0__C2U_L 31U
+#define XHC_RH2HSR0__C2U_R 24U
+#define XHC_RH2HSR0__C2U_WIDTH 8U
+#define XHC_RH2HSR0__C2U_RESETVALUE 0x00U
+#define XHC_RH2HSR0__C1U_L 23U
+#define XHC_RH2HSR0__C1U_R 16U
+#define XHC_RH2HSR0__C1U_WIDTH 8U
+#define XHC_RH2HSR0__C1U_RESETVALUE 0x00U
+#define XHC_RH2HSR0__reserved_L 15U
+#define XHC_RH2HSR0__reserved_R 8U
+#define XHC_RH2HSR0__reserved_WIDTH 8U
+#define XHC_RH2HSR0__reserved_RESETVALUE 0x00U
+#define XHC_RH2HSR0__RTY_L 7U
+#define XHC_RH2HSR0__RTY_R 0U
+#define XHC_RH2HSR0__RTY_WIDTH 8U
+#define XHC_RH2HSR0__RTY_RESETVALUE 0x00U
+#define XHC_RH2HSR0_WIDTH 32U
+#define XHC_RH2HSR0__WIDTH 32U
+#define XHC_RH2HSR0_ALL_L 31U
+#define XHC_RH2HSR0_ALL_R 0U
+#define XHC_RH2HSR0__ALL_L 31U
+#define XHC_RH2HSR0__ALL_R 0U
+#define XHC_RH2HSR0_DATAMASK 0xffffffffU
+#define XHC_RH2HSR0_RDWRMASK 0x00000000U
+#define XHC_RH2HSR0_RESETVALUE 0x00000000U
+
+#define XHC_RH2HSC1_OFFSET 0xd18U
+#define XHC_RH2HSC1_BASE 0xd18U
+#define XHC_RH2HSC1__TMR_L 31U
+#define XHC_RH2HSC1__TMR_R 16U
+#define XHC_RH2HSC1__TMR_WIDTH 16U
+#define XHC_RH2HSC1__TMR_RESETVALUE 0x0000U
+#define XHC_RH2HSC1__RSL_L 7U
+#define XHC_RH2HSC1__RSL_R 6U
+#define XHC_RH2HSC1__RSL_WIDTH 2U
+#define XHC_RH2HSC1__RSL_RESETVALUE 0x0U
+#define XHC_RH2HSC1__AS_M_L 5U
+#define XHC_RH2HSC1__AS_M_R 4U
+#define XHC_RH2HSC1__AS_M_WIDTH 2U
+#define XHC_RH2HSC1__AS_M_RESETVALUE 0x0U
+#define XHC_RH2HSC1__CMD_L 3U
+#define XHC_RH2HSC1__CMD_R 2U
+#define XHC_RH2HSC1__CMD_WIDTH 2U
+#define XHC_RH2HSC1__CMD_RESETVALUE 0x0U
+#define XHC_RH2HSC1__reserved 1U
+#define XHC_RH2HSC1__reserved_L 1U
+#define XHC_RH2HSC1__reserved_R 1U
+#define XHC_RH2HSC1__reserved_WIDTH 1U
+#define XHC_RH2HSC1__reserved_RESETVALUE 0x0U
+#define XHC_RH2HSC1__STB 0U
+#define XHC_RH2HSC1__STB_L 0U
+#define XHC_RH2HSC1__STB_R 0U
+#define XHC_RH2HSC1__STB_WIDTH 1U
+#define XHC_RH2HSC1__STB_RESETVALUE 0x0U
+#define XHC_RH2HSC1__RESERVED_L 15U
+#define XHC_RH2HSC1__RESERVED_R 8U
+#define XHC_RH2HSC1_WIDTH 32U
+#define XHC_RH2HSC1__WIDTH 32U
+#define XHC_RH2HSC1_ALL_L 31U
+#define XHC_RH2HSC1_ALL_R 0U
+#define XHC_RH2HSC1__ALL_L 31U
+#define XHC_RH2HSC1__ALL_R 0U
+#define XHC_RH2HSC1_DATAMASK 0xffff00ffU
+#define XHC_RH2HSC1_RDWRMASK 0x0000ff00U
+#define XHC_RH2HSC1_RESETVALUE 0x00000000U
+
+#define XHC_RH2HSR1_OFFSET 0xd1cU
+#define XHC_RH2HSR1_BASE 0xd1cU
+#define XHC_RH2HSR1__C2U_L 31U
+#define XHC_RH2HSR1__C2U_R 24U
+#define XHC_RH2HSR1__C2U_WIDTH 8U
+#define XHC_RH2HSR1__C2U_RESETVALUE 0x00U
+#define XHC_RH2HSR1__C1U_L 23U
+#define XHC_RH2HSR1__C1U_R 16U
+#define XHC_RH2HSR1__C1U_WIDTH 8U
+#define XHC_RH2HSR1__C1U_RESETVALUE 0x00U
+#define XHC_RH2HSR1__reserved_L 15U
+#define XHC_RH2HSR1__reserved_R 8U
+#define XHC_RH2HSR1__reserved_WIDTH 8U
+#define XHC_RH2HSR1__reserved_RESETVALUE 0x00U
+#define XHC_RH2HSR1__RTY_L 7U
+#define XHC_RH2HSR1__RTY_R 0U
+#define XHC_RH2HSR1__RTY_WIDTH 8U
+#define XHC_RH2HSR1__RTY_RESETVALUE 0x00U
+#define XHC_RH2HSR1_WIDTH 32U
+#define XHC_RH2HSR1__WIDTH 32U
+#define XHC_RH2HSR1_ALL_L 31U
+#define XHC_RH2HSR1_ALL_R 0U
+#define XHC_RH2HSR1__ALL_L 31U
+#define XHC_RH2HSR1__ALL_R 0U
+#define XHC_RH2HSR1_DATAMASK 0xffffffffU
+#define XHC_RH2HSR1_RDWRMASK 0x00000000U
+#define XHC_RH2HSR1_RESETVALUE 0x00000000U
+
+#define XHC_RH2HSC2_OFFSET 0xd20U
+#define XHC_RH2HSC2_BASE 0xd20U
+#define XHC_RH2HSC2__TMR_L 31U
+#define XHC_RH2HSC2__TMR_R 16U
+#define XHC_RH2HSC2__TMR_WIDTH 16U
+#define XHC_RH2HSC2__TMR_RESETVALUE 0x0000U
+#define XHC_RH2HSC2__RSL_L 7U
+#define XHC_RH2HSC2__RSL_R 6U
+#define XHC_RH2HSC2__RSL_WIDTH 2U
+#define XHC_RH2HSC2__RSL_RESETVALUE 0x0U
+#define XHC_RH2HSC2__AS_M_L 5U
+#define XHC_RH2HSC2__AS_M_R 4U
+#define XHC_RH2HSC2__AS_M_WIDTH 2U
+#define XHC_RH2HSC2__AS_M_RESETVALUE 0x0U
+#define XHC_RH2HSC2__CMD_L 3U
+#define XHC_RH2HSC2__CMD_R 2U
+#define XHC_RH2HSC2__CMD_WIDTH 2U
+#define XHC_RH2HSC2__CMD_RESETVALUE 0x0U
+#define XHC_RH2HSC2__reserved 1U
+#define XHC_RH2HSC2__reserved_L 1U
+#define XHC_RH2HSC2__reserved_R 1U
+#define XHC_RH2HSC2__reserved_WIDTH 1U
+#define XHC_RH2HSC2__reserved_RESETVALUE 0x0U
+#define XHC_RH2HSC2__STB 0U
+#define XHC_RH2HSC2__STB_L 0U
+#define XHC_RH2HSC2__STB_R 0U
+#define XHC_RH2HSC2__STB_WIDTH 1U
+#define XHC_RH2HSC2__STB_RESETVALUE 0x0U
+#define XHC_RH2HSC2__RESERVED_L 15U
+#define XHC_RH2HSC2__RESERVED_R 8U
+#define XHC_RH2HSC2_WIDTH 32U
+#define XHC_RH2HSC2__WIDTH 32U
+#define XHC_RH2HSC2_ALL_L 31U
+#define XHC_RH2HSC2_ALL_R 0U
+#define XHC_RH2HSC2__ALL_L 31U
+#define XHC_RH2HSC2__ALL_R 0U
+#define XHC_RH2HSC2_DATAMASK 0xffff00ffU
+#define XHC_RH2HSC2_RDWRMASK 0x0000ff00U
+#define XHC_RH2HSC2_RESETVALUE 0x00000000U
+
+#define XHC_RH2HSR2_OFFSET 0xd24U
+#define XHC_RH2HSR2_BASE 0xd24U
+#define XHC_RH2HSR2__C2U_L 31U
+#define XHC_RH2HSR2__C2U_R 24U
+#define XHC_RH2HSR2__C2U_WIDTH 8U
+#define XHC_RH2HSR2__C2U_RESETVALUE 0x00U
+#define XHC_RH2HSR2__C1U_L 23U
+#define XHC_RH2HSR2__C1U_R 16U
+#define XHC_RH2HSR2__C1U_WIDTH 8U
+#define XHC_RH2HSR2__C1U_RESETVALUE 0x00U
+#define XHC_RH2HSR2__reserved_L 15U
+#define XHC_RH2HSR2__reserved_R 8U
+#define XHC_RH2HSR2__reserved_WIDTH 8U
+#define XHC_RH2HSR2__reserved_RESETVALUE 0x00U
+#define XHC_RH2HSR2__RTY_L 7U
+#define XHC_RH2HSR2__RTY_R 0U
+#define XHC_RH2HSR2__RTY_WIDTH 8U
+#define XHC_RH2HSR2__RTY_RESETVALUE 0x00U
+#define XHC_RH2HSR2_WIDTH 32U
+#define XHC_RH2HSR2__WIDTH 32U
+#define XHC_RH2HSR2_ALL_L 31U
+#define XHC_RH2HSR2_ALL_R 0U
+#define XHC_RH2HSR2__ALL_L 31U
+#define XHC_RH2HSR2__ALL_R 0U
+#define XHC_RH2HSR2_DATAMASK 0xffffffffU
+#define XHC_RH2HSR2_RDWRMASK 0x00000000U
+#define XHC_RH2HSR2_RESETVALUE 0x00000000U
+
+#define XHC_RH2HSC3_OFFSET 0xd28U
+#define XHC_RH2HSC3_BASE 0xd28U
+#define XHC_RH2HSC3__TMR_L 31U
+#define XHC_RH2HSC3__TMR_R 16U
+#define XHC_RH2HSC3__TMR_WIDTH 16U
+#define XHC_RH2HSC3__TMR_RESETVALUE 0x0000U
+#define XHC_RH2HSC3__RSL_L 7U
+#define XHC_RH2HSC3__RSL_R 6U
+#define XHC_RH2HSC3__RSL_WIDTH 2U
+#define XHC_RH2HSC3__RSL_RESETVALUE 0x0U
+#define XHC_RH2HSC3__AS_M_L 5U
+#define XHC_RH2HSC3__AS_M_R 4U
+#define XHC_RH2HSC3__AS_M_WIDTH 2U
+#define XHC_RH2HSC3__AS_M_RESETVALUE 0x0U
+#define XHC_RH2HSC3__CMD_L 3U
+#define XHC_RH2HSC3__CMD_R 2U
+#define XHC_RH2HSC3__CMD_WIDTH 2U
+#define XHC_RH2HSC3__CMD_RESETVALUE 0x0U
+#define XHC_RH2HSC3__reserved 1U
+#define XHC_RH2HSC3__reserved_L 1U
+#define XHC_RH2HSC3__reserved_R 1U
+#define XHC_RH2HSC3__reserved_WIDTH 1U
+#define XHC_RH2HSC3__reserved_RESETVALUE 0x0U
+#define XHC_RH2HSC3__STB 0U
+#define XHC_RH2HSC3__STB_L 0U
+#define XHC_RH2HSC3__STB_R 0U
+#define XHC_RH2HSC3__STB_WIDTH 1U
+#define XHC_RH2HSC3__STB_RESETVALUE 0x0U
+#define XHC_RH2HSC3__RESERVED_L 15U
+#define XHC_RH2HSC3__RESERVED_R 8U
+#define XHC_RH2HSC3_WIDTH 32U
+#define XHC_RH2HSC3__WIDTH 32U
+#define XHC_RH2HSC3_ALL_L 31U
+#define XHC_RH2HSC3_ALL_R 0U
+#define XHC_RH2HSC3__ALL_L 31U
+#define XHC_RH2HSC3__ALL_R 0U
+#define XHC_RH2HSC3_DATAMASK 0xffff00ffU
+#define XHC_RH2HSC3_RDWRMASK 0x0000ff00U
+#define XHC_RH2HSC3_RESETVALUE 0x00000000U
+
+#define XHC_RH2HSR3_OFFSET 0xd2cU
+#define XHC_RH2HSR3_BASE 0xd2cU
+#define XHC_RH2HSR3__C2U_L 31U
+#define XHC_RH2HSR3__C2U_R 24U
+#define XHC_RH2HSR3__C2U_WIDTH 8U
+#define XHC_RH2HSR3__C2U_RESETVALUE 0x00U
+#define XHC_RH2HSR3__C1U_L 23U
+#define XHC_RH2HSR3__C1U_R 16U
+#define XHC_RH2HSR3__C1U_WIDTH 8U
+#define XHC_RH2HSR3__C1U_RESETVALUE 0x00U
+#define XHC_RH2HSR3__reserved_L 15U
+#define XHC_RH2HSR3__reserved_R 8U
+#define XHC_RH2HSR3__reserved_WIDTH 8U
+#define XHC_RH2HSR3__reserved_RESETVALUE 0x00U
+#define XHC_RH2HSR3__RTY_L 7U
+#define XHC_RH2HSR3__RTY_R 0U
+#define XHC_RH2HSR3__RTY_WIDTH 8U
+#define XHC_RH2HSR3__RTY_RESETVALUE 0x00U
+#define XHC_RH2HSR3_WIDTH 32U
+#define XHC_RH2HSR3__WIDTH 32U
+#define XHC_RH2HSR3_ALL_L 31U
+#define XHC_RH2HSR3_ALL_R 0U
+#define XHC_RH2HSR3__ALL_L 31U
+#define XHC_RH2HSR3__ALL_R 0U
+#define XHC_RH2HSR3_DATAMASK 0xffffffffU
+#define XHC_RH2HSR3_RDWRMASK 0x00000000U
+#define XHC_RH2HSR3_RESETVALUE 0x00000000U
+
+#define XHC_ECHU2P_OFFSET 0xd30U
+#define XHC_ECHU2P_BASE 0xd30U
+#define XHC_ECHU2P__reserved_L 31U
+#define XHC_ECHU2P__reserved_R 16U
+#define XHC_ECHU2P__reserved_WIDTH 16U
+#define XHC_ECHU2P__reserved_RESETVALUE 0x0000U
+#define XHC_ECHU2P__NCP_L 15U
+#define XHC_ECHU2P__NCP_R 8U
+#define XHC_ECHU2P__NCP_WIDTH 8U
+#define XHC_ECHU2P__NCP_RESETVALUE 0x04U
+#define XHC_ECHU2P__CID_L 7U
+#define XHC_ECHU2P__CID_R 0U
+#define XHC_ECHU2P__CID_WIDTH 8U
+#define XHC_ECHU2P__CID_RESETVALUE 0xcaU
+#define XHC_ECHU2P_WIDTH 32U
+#define XHC_ECHU2P__WIDTH 32U
+#define XHC_ECHU2P_ALL_L 31U
+#define XHC_ECHU2P_ALL_R 0U
+#define XHC_ECHU2P__ALL_L 31U
+#define XHC_ECHU2P__ALL_R 0U
+#define XHC_ECHU2P_DATAMASK 0xffffffffU
+#define XHC_ECHU2P_RDWRMASK 0x00000000U
+#define XHC_ECHU2P_RESETVALUE 0x000004caU
+
+#define XHC_U2PVER_OFFSET 0xd34U
+#define XHC_U2PVER_BASE 0xd34U
+#define XHC_U2PVER__MAJ_L 31U
+#define XHC_U2PVER__MAJ_R 28U
+#define XHC_U2PVER__MAJ_WIDTH 4U
+#define XHC_U2PVER__MAJ_RESETVALUE 0x0U
+#define XHC_U2PVER__MIN_L 27U
+#define XHC_U2PVER__MIN_R 24U
+#define XHC_U2PVER__MIN_WIDTH 4U
+#define XHC_U2PVER__MIN_RESETVALUE 0x0U
+#define XHC_U2PVER__RLS_L 23U
+#define XHC_U2PVER__RLS_R 20U
+#define XHC_U2PVER__RLS_WIDTH 4U
+#define XHC_U2PVER__RLS_RESETVALUE 0x0U
+#define XHC_U2PVER__reserved_L 19U
+#define XHC_U2PVER__reserved_R 0U
+#define XHC_U2PVER__reserved_WIDTH 20U
+#define XHC_U2PVER__reserved_RESETVALUE 0x00000U
+#define XHC_U2PVER_WIDTH 32U
+#define XHC_U2PVER__WIDTH 32U
+#define XHC_U2PVER_ALL_L 31U
+#define XHC_U2PVER_ALL_R 0U
+#define XHC_U2PVER__ALL_L 31U
+#define XHC_U2PVER__ALL_R 0U
+#define XHC_U2PVER_DATAMASK 0xffffffffU
+#define XHC_U2PVER_RDWRMASK 0x00000000U
+#define XHC_U2PVER_RESETVALUE 0x00000000U
+
+#define XHC_U2PMGN_OFFSET 0xd38U
+#define XHC_U2PMGN_BASE 0xd38U
+#define XHC_U2PMGN__MGN_L 31U
+#define XHC_U2PMGN__MGN_R 0U
+#define XHC_U2PMGN__MGN_WIDTH 32U
+#define XHC_U2PMGN__MGN_RESETVALUE 0x4b534b4dU
+#define XHC_U2PMGN_WIDTH 32U
+#define XHC_U2PMGN__WIDTH 32U
+#define XHC_U2PMGN_ALL_L 31U
+#define XHC_U2PMGN_ALL_R 0U
+#define XHC_U2PMGN__ALL_L 31U
+#define XHC_U2PMGN__ALL_R 0U
+#define XHC_U2PMGN_DATAMASK 0xffffffffU
+#define XHC_U2PMGN_RDWRMASK 0x00000000U
+#define XHC_U2PMGN_RESETVALUE 0x4b534b4dU
+
+#define XHC_ECHRSV2_OFFSET 0xd40U
+#define XHC_ECHRSV2_BASE 0xd40U
+#define XHC_ECHRSV2__reserved_L 31U
+#define XHC_ECHRSV2__reserved_R 16U
+#define XHC_ECHRSV2__reserved_WIDTH 16U
+#define XHC_ECHRSV2__reserved_RESETVALUE 0x0000U
+#define XHC_ECHRSV2__NCP_L 15U
+#define XHC_ECHRSV2__NCP_R 8U
+#define XHC_ECHRSV2__NCP_WIDTH 8U
+#define XHC_ECHRSV2__NCP_RESETVALUE 0x00U
+#define XHC_ECHRSV2__CID_L 7U
+#define XHC_ECHRSV2__CID_R 0U
+#define XHC_ECHRSV2__CID_WIDTH 8U
+#define XHC_ECHRSV2__CID_RESETVALUE 0xffU
+#define XHC_ECHRSV2_WIDTH 32U
+#define XHC_ECHRSV2__WIDTH 32U
+#define XHC_ECHRSV2_ALL_L 31U
+#define XHC_ECHRSV2_ALL_R 0U
+#define XHC_ECHRSV2__ALL_L 31U
+#define XHC_ECHRSV2__ALL_R 0U
+#define XHC_ECHRSV2_DATAMASK 0xffffffffU
+#define XHC_ECHRSV2_RDWRMASK 0x00000000U
+#define XHC_ECHRSV2_RESETVALUE 0x000000ffU
+
+#define XHC_ECHIRA_OFFSET 0xf90U
+#define XHC_ECHIRA_BASE 0xf90U
+#define XHC_ECHIRA__reserved_L 31U
+#define XHC_ECHIRA__reserved_R 16U
+#define XHC_ECHIRA__reserved_WIDTH 16U
+#define XHC_ECHIRA__reserved_RESETVALUE 0x0000U
+#define XHC_ECHIRA__NCP_L 15U
+#define XHC_ECHIRA__NCP_R 8U
+#define XHC_ECHIRA__NCP_WIDTH 8U
+#define XHC_ECHIRA__NCP_RESETVALUE 0x04U
+#define XHC_ECHIRA__CID_L 7U
+#define XHC_ECHIRA__CID_R 0U
+#define XHC_ECHIRA__CID_WIDTH 8U
+#define XHC_ECHIRA__CID_RESETVALUE 0xfdU
+#define XHC_ECHIRA_WIDTH 32U
+#define XHC_ECHIRA__WIDTH 32U
+#define XHC_ECHIRA_ALL_L 31U
+#define XHC_ECHIRA_ALL_R 0U
+#define XHC_ECHIRA__ALL_L 31U
+#define XHC_ECHIRA__ALL_R 0U
+#define XHC_ECHIRA_DATAMASK 0xffffffffU
+#define XHC_ECHIRA_RDWRMASK 0x00000000U
+#define XHC_ECHIRA_RESETVALUE 0x000004fdU
+
+#define XHC_IRAADR_OFFSET 0xf98U
+#define XHC_IRAADR_BASE 0xf98U
+#define XHC_IRAADR__ADR_L 23U
+#define XHC_IRAADR__ADR_R 2U
+#define XHC_IRAADR__ADR_WIDTH 22U
+#define XHC_IRAADR__ADR_RESETVALUE 0x0U
+#define XHC_IRAADR__reserved 1U
+#define XHC_IRAADR__reserved_L 1U
+#define XHC_IRAADR__reserved_R 1U
+#define XHC_IRAADR__reserved_WIDTH 1U
+#define XHC_IRAADR__reserved_RESETVALUE 0x0U
+#define XHC_IRAADR__MOD 0U
+#define XHC_IRAADR__MOD_L 0U
+#define XHC_IRAADR__MOD_R 0U
+#define XHC_IRAADR__MOD_WIDTH 1U
+#define XHC_IRAADR__MOD_RESETVALUE 0x0U
+#define XHC_IRAADR__RESERVED_L 31U
+#define XHC_IRAADR__RESERVED_R 24U
+#define XHC_IRAADR_WIDTH 24U
+#define XHC_IRAADR__WIDTH 24U
+#define XHC_IRAADR_ALL_L 23U
+#define XHC_IRAADR_ALL_R 0U
+#define XHC_IRAADR__ALL_L 23U
+#define XHC_IRAADR__ALL_R 0U
+#define XHC_IRAADR_DATAMASK 0x00ffffffU
+#define XHC_IRAADR_RDWRMASK 0xff000000U
+#define XHC_IRAADR_RESETVALUE 0x000000U
+
+#define XHC_IRADAT_OFFSET 0xf9cU
+#define XHC_IRADAT_BASE 0xf9cU
+#define XHC_IRADAT__DAT_L 31U
+#define XHC_IRADAT__DAT_R 0U
+#define XHC_IRADAT__DAT_WIDTH 32U
+#define XHC_IRADAT__DAT_RESETVALUE 0x00000000U
+#define XHC_IRADAT_WIDTH 32U
+#define XHC_IRADAT__WIDTH 32U
+#define XHC_IRADAT_ALL_L 31U
+#define XHC_IRADAT_ALL_R 0U
+#define XHC_IRADAT__ALL_L 31U
+#define XHC_IRADAT__ALL_R 0U
+#define XHC_IRADAT_DATAMASK 0xffffffffU
+#define XHC_IRADAT_RDWRMASK 0x00000000U
+#define XHC_IRADAT_RESETVALUE 0x00000000U
+
+
+#define XHC_ECHHST_OFFSET 0xfa0U
+#define XHC_ECHHST_BASE 0xfa0U
+#define XHC_ECHHST__CCC 31U
+#define XHC_ECHHST__CCC_L 31U
+#define XHC_ECHHST__CCC_R 31U
+#define XHC_ECHHST__CCC_WIDTH 1U
+#define XHC_ECHHST__CCC_RESETVALUE 0x1U
+#define XHC_ECHHST__PME 30U
+#define XHC_ECHHST__PME_L 30U
+#define XHC_ECHHST__PME_R 30U
+#define XHC_ECHHST__PME_WIDTH 1U
+#define XHC_ECHHST__PME_RESETVALUE 0x0U
+#define XHC_ECHHST__AUX_L 29U
+#define XHC_ECHHST__AUX_R 24U
+#define XHC_ECHHST__AUX_WIDTH 6U
+#define XHC_ECHHST__AUX_RESETVALUE 0x0U
+#define XHC_ECHHST__IRA 20U
+#define XHC_ECHHST__IRA_L 20U
+#define XHC_ECHHST__IRA_R 20U
+#define XHC_ECHHST__IRA_WIDTH 1U
+#define XHC_ECHHST__IRA_RESETVALUE 0x0U
+#define XHC_ECHHST__ULS 19U
+#define XHC_ECHHST__ULS_L 19U
+#define XHC_ECHHST__ULS_R 19U
+#define XHC_ECHHST__ULS_WIDTH 1U
+#define XHC_ECHHST__ULS_RESETVALUE 0x0U
+#define XHC_ECHHST__reserved 18U
+#define XHC_ECHHST__reserved_L 18U
+#define XHC_ECHHST__reserved_R 18U
+#define XHC_ECHHST__reserved_WIDTH 1U
+#define XHC_ECHHST__reserved_RESETVALUE 0x0U
+#define XHC_ECHHST__TEDA 17U
+#define XHC_ECHHST__TEDA_L 17U
+#define XHC_ECHHST__TEDA_R 17U
+#define XHC_ECHHST__TEDA_WIDTH 1U
+#define XHC_ECHHST__TEDA_RESETVALUE 0x0U
+#define XHC_ECHHST__FSW 16U
+#define XHC_ECHHST__FSW_L 16U
+#define XHC_ECHHST__FSW_R 16U
+#define XHC_ECHHST__FSW_WIDTH 1U
+#define XHC_ECHHST__FSW_RESETVALUE 0x1U
+#define XHC_ECHHST__NCP_L 15U
+#define XHC_ECHHST__NCP_R 8U
+#define XHC_ECHHST__NCP_WIDTH 8U
+#define XHC_ECHHST__NCP_RESETVALUE 0x04U
+#define XHC_ECHHST__CID_L 7U
+#define XHC_ECHHST__CID_R 0U
+#define XHC_ECHHST__CID_WIDTH 8U
+#define XHC_ECHHST__CID_RESETVALUE 0xfcU
+#define XHC_ECHHST__RESERVED_L 23U
+#define XHC_ECHHST__RESERVED_R 21U
+#define XHC_ECHHST_WIDTH 32U
+#define XHC_ECHHST__WIDTH 32U
+#define XHC_ECHHST_ALL_L 31U
+#define XHC_ECHHST_ALL_R 0U
+#define XHC_ECHHST__ALL_L 31U
+#define XHC_ECHHST__ALL_R 0U
+#define XHC_ECHHST_DATAMASK 0xff1fffffU
+#define XHC_ECHHST_RDWRMASK 0x00e00000U
+#define XHC_ECHHST_RESETVALUE 0x800104fcU
+
+#define XHC_HSTDBG_OFFSET 0xfa4U
+#define XHC_HSTDBG_BASE 0xfa4U
+#define XHC_HSTDBG__ETE 31U
+#define XHC_HSTDBG__ETE_L 31U
+#define XHC_HSTDBG__ETE_R 31U
+#define XHC_HSTDBG__ETE_WIDTH 1U
+#define XHC_HSTDBG__ETE_RESETVALUE 0x0U
+#define XHC_HSTDBG__reserved_L 30U
+#define XHC_HSTDBG__reserved_R 16U
+#define XHC_HSTDBG__reserved_WIDTH 15U
+#define XHC_HSTDBG__reserved_RESETVALUE 0x0U
+#define XHC_HSTDBG__OUTP_L 15U
+#define XHC_HSTDBG__OUTP_R 8U
+#define XHC_HSTDBG__OUTP_WIDTH 8U
+#define XHC_HSTDBG__OUTP_RESETVALUE 0x00U
+#define XHC_HSTDBG__INP_L 7U
+#define XHC_HSTDBG__INP_R 0U
+#define XHC_HSTDBG__INP_WIDTH 8U
+#define XHC_HSTDBG__INP_RESETVALUE 0x00U
+#define XHC_HSTDBG_WIDTH 32U
+#define XHC_HSTDBG__WIDTH 32U
+#define XHC_HSTDBG_ALL_L 31U
+#define XHC_HSTDBG_ALL_R 0U
+#define XHC_HSTDBG__ALL_L 31U
+#define XHC_HSTDBG__ALL_R 0U
+#define XHC_HSTDBG_DATAMASK 0xffffffffU
+#define XHC_HSTDBG_RDWRMASK 0x00000000U
+#define XHC_HSTDBG_RESETVALUE 0x00000000U
+
+#define XHC_HSTNPL_OFFSET 0xfa8U
+#define XHC_HSTNPL_BASE 0xfa8U
+#define XHC_HSTNPL__NPL_L 31U
+#define XHC_HSTNPL__NPL_R 9U
+#define XHC_HSTNPL__NPL_WIDTH 23U
+#define XHC_HSTNPL__NPL_RESETVALUE 0x0U
+#define XHC_HSTNPL__reserved_L 8U
+#define XHC_HSTNPL__reserved_R 0U
+#define XHC_HSTNPL__reserved_WIDTH 9U
+#define XHC_HSTNPL__reserved_RESETVALUE 0x0U
+#define XHC_HSTNPL_WIDTH 32U
+#define XHC_HSTNPL__WIDTH 32U
+#define XHC_HSTNPL_ALL_L 31U
+#define XHC_HSTNPL_ALL_R 0U
+#define XHC_HSTNPL__ALL_L 31U
+#define XHC_HSTNPL__ALL_R 0U
+#define XHC_HSTNPL_DATAMASK 0xffffffffU
+#define XHC_HSTNPL_RDWRMASK 0x00000000U
+#define XHC_HSTNPL_RESETVALUE 0x00000000U
+
+#define XHC_HSTNPH_OFFSET 0xfacU
+#define XHC_HSTNPH_BASE 0xfacU
+#define XHC_HSTNPH__NPH_L 31U
+#define XHC_HSTNPH__NPH_R 0U
+#define XHC_HSTNPH__NPH_WIDTH 32U
+#define XHC_HSTNPH__NPH_RESETVALUE 0x00000000U
+#define XHC_HSTNPH_WIDTH 32U
+#define XHC_HSTNPH__WIDTH 32U
+#define XHC_HSTNPH_ALL_L 31U
+#define XHC_HSTNPH_ALL_R 0U
+#define XHC_HSTNPH__ALL_L 31U
+#define XHC_HSTNPH__ALL_R 0U
+#define XHC_HSTNPH_DATAMASK 0xffffffffU
+#define XHC_HSTNPH_RDWRMASK 0x00000000U
+#define XHC_HSTNPH_RESETVALUE 0x00000000U
+
+#define XHC_ECHRBV_OFFSET 0xfb0U
+#define XHC_ECHRBV_BASE 0xfb0U
+#define XHC_ECHRBV__MAJ_L 31U
+#define XHC_ECHRBV__MAJ_R 28U
+#define XHC_ECHRBV__MAJ_WIDTH 4U
+#define XHC_ECHRBV__MAJ_RESETVALUE 0x0U
+#define XHC_ECHRBV__MIN_L 27U
+#define XHC_ECHRBV__MIN_R 24U
+#define XHC_ECHRBV__MIN_WIDTH 4U
+#define XHC_ECHRBV__MIN_RESETVALUE 0x0U
+#define XHC_ECHRBV__RLS_L 23U
+#define XHC_ECHRBV__RLS_R 16U
+#define XHC_ECHRBV__RLS_WIDTH 8U
+#define XHC_ECHRBV__RLS_RESETVALUE 0x00U
+#define XHC_ECHRBV__NCP_L 15U
+#define XHC_ECHRBV__NCP_R 8U
+#define XHC_ECHRBV__NCP_WIDTH 8U
+#define XHC_ECHRBV__NCP_RESETVALUE 0x00U
+#define XHC_ECHRBV__CID_L 7U
+#define XHC_ECHRBV__CID_R 0U
+#define XHC_ECHRBV__CID_WIDTH 8U
+#define XHC_ECHRBV__CID_RESETVALUE 0xfeU
+#define XHC_ECHRBV_WIDTH 32U
+#define XHC_ECHRBV__WIDTH 32U
+#define XHC_ECHRBV_ALL_L 31U
+#define XHC_ECHRBV_ALL_R 0U
+#define XHC_ECHRBV__ALL_L 31U
+#define XHC_ECHRBV__ALL_R 0U
+#define XHC_ECHRBV_DATAMASK 0xffffffffU
+#define XHC_ECHRBV_RDWRMASK 0x00000000U
+#define XHC_ECHRBV_RESETVALUE 0x000000feU
+
+#define XHC_RBVPDT_OFFSET 0xfb4U
+#define XHC_RBVPDT_BASE 0xfb4U
+#define XHC_RBVPDT__VDR_L 31U
+#define XHC_RBVPDT__VDR_R 16U
+#define XHC_RBVPDT__VDR_WIDTH 16U
+#define XHC_RBVPDT__VDR_RESETVALUE 0x0a5cU
+#define XHC_RBVPDT__PDT_L 15U
+#define XHC_RBVPDT__PDT_R 0U
+#define XHC_RBVPDT__PDT_WIDTH 16U
+#define XHC_RBVPDT__PDT_RESETVALUE 0x0000U
+#define XHC_RBVPDT_WIDTH 32U
+#define XHC_RBVPDT__WIDTH 32U
+#define XHC_RBVPDT_ALL_L 31U
+#define XHC_RBVPDT_ALL_R 0U
+#define XHC_RBVPDT__ALL_L 31U
+#define XHC_RBVPDT__ALL_R 0U
+#define XHC_RBVPDT_DATAMASK 0xffffffffU
+#define XHC_RBVPDT_RDWRMASK 0x00000000U
+#define XHC_RBVPDT_RESETVALUE 0x0a5c0000U
+
+#define XHC_RBVMGN_OFFSET 0xfbcU
+#define XHC_RBVMGN_BASE 0xfbcU
+#define XHC_RBVMGN__MGN_L 31U
+#define XHC_RBVMGN__MGN_R 0U
+#define XHC_RBVMGN__MGN_WIDTH 32U
+#define XHC_RBVMGN__MGN_RESETVALUE 0x52535354U
+#define XHC_RBVMGN_WIDTH 32U
+#define XHC_RBVMGN__WIDTH 32U
+#define XHC_RBVMGN_ALL_L 31U
+#define XHC_RBVMGN_ALL_R 0U
+#define XHC_RBVMGN__ALL_L 31U
+#define XHC_RBVMGN__ALL_R 0U
+#define XHC_RBVMGN_DATAMASK 0xffffffffU
+#define XHC_RBVMGN_RDWRMASK 0x00000000U
+#define XHC_RBVMGN_RESETVALUE 0x52535354U
+
+/* PORTSC field defines */
+#define XHC_PORTSC__PS_LINK_STATE_U0 0U
+#define XHC_PORTSC__PS_LINK_STATE_U1 1U
+#define XHC_PORTSC__PS_LINK_STATE_U2 2U
+#define XHC_PORTSC__PS_LINK_STATE_U3 3U
+#define XHC_PORTSC__PS_LINK_STATE_DISABLED 4U
+#define XHC_PORTSC__PS_LINK_STATE_RX_DETECT 5U
+#define XHC_PORTSC__PS_LINK_STATE_INACTIVE 6U
+#define XHC_PORTSC__PS_LINK_STATE_POLLING 7U
+#define XHC_PORTSC__PS_LINK_STATE_RECOVERY 8U
+#define XHC_PORTSC__PS_LINK_STATE_HOT_RESET 9U
+#define XHC_PORTSC__PS_LINK_STATE_COMPLIANCE 10U
+#define XHC_PORTSC__PS_LINK_STATE_TEST 11U
+#define XHC_PORTSC__PS_LINK_STATE_RESUME 15U
+
+#define XHC_PORTSC__PS_SPEED_UNDEFINED 0U
+#define XHC_PORTSC__PS_FS 1U
+#define XHC_PORTSC__PS_LS 2U
+#define XHC_PORTSC__PS_HS 3U
+#define XHC_PORTSC__PS_SS 4U
+
+/* macros and inline functions */
+
+/* write 64bit ptr 'p' to destination 'd' with offset 'v' */
+inline void WRITE64_REG_PTRL(uint32_t r, uint32_t *p)
+{
+ uint32_t *ptr = (uint32_t *) (uint64_t) (XHC_BASE + r);
+
+ *ptr = (uint32_t) ((uint64_t) p & (uint64_t) 0xffffffffU);
+}
+
+inline void WRITE64_REG_PTRH(uint32_t r, uint32_t *p)
+{
+ uint32_t *ptr = (uint32_t *) (uint64_t) (XHC_BASE + r);
+
+ *ptr = (uint32_t) ((uint64_t) p >> 32U);
+}
+
+#define XHC_REG_RD(addr) mmio_read_32(XHC_BASE + addr)
+
+#define XHC_REG_WR(addr, val) mmio_write_32(XHC_BASE+addr, val)
+
+#endif /* USBH_XHCI_REGS_H */
+
diff --git a/include/drivers/cadence/cdns_uart.h b/include/drivers/cadence/cdns_uart.h
new file mode 100644
index 0000000..30ca910
--- /dev/null
+++ b/include/drivers/cadence/cdns_uart.h
@@ -0,0 +1,44 @@
+/*
+ * 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 <drivers/console.h>
+
+/* 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 UART_SR_INTR_TEMPTY_BIT 3
+
+#define R_UART_TX 0x30
+#define R_UART_RX 0x30
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+/*
+ * 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_t *console);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* CDNS_UART_H */
diff --git a/include/drivers/cfi/v2m_flash.h b/include/drivers/cfi/v2m_flash.h
new file mode 100644
index 0000000..6beec50
--- /dev/null
+++ b/include/drivers/cfi/v2m_flash.h
@@ -0,0 +1,45 @@
+/*
+ * 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 <stdint.h>
+
+/* 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*/
diff --git a/include/drivers/clk.h b/include/drivers/clk.h
new file mode 100644
index 0000000..a18f41f
--- /dev/null
+++ b/include/drivers/clk.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CLK_H
+#define CLK_H
+
+#include <stdbool.h>
+
+struct clk_ops {
+ int (*enable)(unsigned long id);
+ void (*disable)(unsigned long id);
+ unsigned long (*get_rate)(unsigned long id);
+ int (*get_parent)(unsigned long id);
+ bool (*is_enabled)(unsigned long id);
+};
+
+int clk_enable(unsigned long id);
+void clk_disable(unsigned long id);
+unsigned long clk_get_rate(unsigned long id);
+bool clk_is_enabled(unsigned long id);
+int clk_get_parent(unsigned long id);
+
+void clk_register(const struct clk_ops *ops);
+
+#endif /* CLK_H */
diff --git a/include/drivers/console.h b/include/drivers/console.h
new file mode 100644
index 0000000..99bf960
--- /dev/null
+++ b/include/drivers/console.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CONSOLE_H
+#define CONSOLE_H
+
+#include <lib/utils_def.h>
+
+#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_BASE (U(5) * REGSZ)
+#define CONSOLE_T_DRVDATA (U(6) * 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 <stdint.h>
+
+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);
+ void (*const flush)(struct console *console);
+ uintptr_t base;
+ /* Additional private driver data may follow here. */
+} console_t;
+
+/* offset macro assertions for console_t */
+#include <drivers/console_assertions.h>
+
+/*
+ * 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. */
+void console_flush(void);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* CONSOLE_H */
diff --git a/include/drivers/console_assertions.h b/include/drivers/console_assertions.h
new file mode 100644
index 0000000..00caa31
--- /dev/null
+++ b/include/drivers/console_assertions.h
@@ -0,0 +1,29 @@
+/*
+ * 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 <lib/cassert.h>
+
+/*
+ * This file contains some separate assertions about console_t, moved here to
+ * keep them out of the way. Should only be included from <console.h>.
+ */
+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 */
diff --git a/include/drivers/coreboot/cbmem_console.h b/include/drivers/coreboot/cbmem_console.h
new file mode 100644
index 0000000..30b39f1
--- /dev/null
+++ b/include/drivers/coreboot/cbmem_console.h
@@ -0,0 +1,25 @@
+/*
+ * 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 <drivers/console.h>
+
+#define CONSOLE_T_CBMC_SIZE CONSOLE_T_DRVDATA
+
+#ifndef __ASSEMBLER__
+
+typedef struct {
+ console_t console;
+ uint32_t size;
+} console_cbmc_t;
+
+int console_cbmc_register(uintptr_t base, console_cbmc_t *console);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* CBMEM_CONSOLE_H */
diff --git a/include/drivers/delay_timer.h b/include/drivers/delay_timer.h
new file mode 100644
index 0000000..20a5543
--- /dev/null
+++ b/include/drivers/delay_timer.h
@@ -0,0 +1,53 @@
+/*
+ * 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 <stdbool.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+
+/********************************************************************
+ * 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 */
diff --git a/include/drivers/dw_ufs.h b/include/drivers/dw_ufs.h
new file mode 100644
index 0000000..13e53f1
--- /dev/null
+++ b/include/drivers/dw_ufs.h
@@ -0,0 +1,110 @@
+/*
+ * 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 <stdint.h>
+
+/* 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 */
diff --git a/include/drivers/fwu/fwu.h b/include/drivers/fwu/fwu.h
new file mode 100644
index 0000000..9f18e22
--- /dev/null
+++ b/include/drivers/fwu/fwu.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FWU_H
+#define FWU_H
+
+#include <stdbool.h>
+
+void fwu_init(void);
+bool fwu_is_trial_run_state(void);
+const struct fwu_metadata *fwu_get_metadata(void);
+
+#endif /* FWU_H */
diff --git a/include/drivers/fwu/fwu_metadata.h b/include/drivers/fwu/fwu_metadata.h
new file mode 100644
index 0000000..2e88de5
--- /dev/null
+++ b/include/drivers/fwu/fwu_metadata.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * FWU metadata information as per the specification section 4.1:
+ * https://developer.arm.com/documentation/den0118/a/
+ *
+ */
+
+#ifndef FWU_METADATA_H
+#define FWU_METADATA_H
+
+#include <stdint.h>
+#include <tools_share/uuid.h>
+
+/* Properties of image in a bank */
+struct fwu_image_properties {
+
+ /* UUID of the image in this bank */
+ uuid_t img_uuid;
+
+ /* [0]: bit describing the image acceptance status –
+ * 1 means the image is accepted
+ * [31:1]: MBZ
+ */
+ uint32_t accepted;
+
+ /* reserved (MBZ) */
+ uint32_t reserved;
+
+} __packed;
+
+/* Image entry information */
+struct fwu_image_entry {
+
+ /* UUID identifying the image type */
+ uuid_t img_type_uuid;
+
+ /* UUID of the storage volume where the image is located */
+ uuid_t location_uuid;
+
+ /* Properties of images with img_type_uuid in the different FW banks */
+ struct fwu_image_properties img_props[NR_OF_FW_BANKS];
+
+} __packed;
+
+/*
+ * FWU metadata filled by the updater and consumed by TF-A for
+ * various purposes as below:
+ * 1. Get active FW bank.
+ * 2. Rollback to previous working FW bank.
+ * 3. Get properties of all images present in all banks.
+ */
+struct fwu_metadata {
+
+ /* Metadata CRC value */
+ uint32_t crc_32;
+
+ /* Metadata version */
+ uint32_t version;
+
+ /* Bank index with which device boots */
+ uint32_t active_index;
+
+ /* Previous bank index with which device booted successfully */
+ uint32_t previous_active_index;
+
+ /* Image entry information */
+ struct fwu_image_entry img_entry[NR_OF_IMAGES_IN_FW_BANK];
+
+} __packed;
+
+#endif /* FWU_METADATA_H */
diff --git a/include/drivers/generic_delay_timer.h b/include/drivers/generic_delay_timer.h
new file mode 100644
index 0000000..adba10f
--- /dev/null
+++ b/include/drivers/generic_delay_timer.h
@@ -0,0 +1,16 @@
+/*
+ * 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 <stdint.h>
+
+void generic_delay_timer_init_args(uint32_t mult, uint32_t div);
+
+void generic_delay_timer_init(void);
+
+#endif /* GENERIC_DELAY_TIMER_H */
diff --git a/include/drivers/gpio.h b/include/drivers/gpio.h
new file mode 100644
index 0000000..9bba993
--- /dev/null
+++ b/include/drivers/gpio.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GPIO_H
+#define GPIO_H
+
+#include <export/drivers/gpio_exp.h>
+
+#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
+#define GPIO_PULL_REPEATER ARM_TF_GPIO_PULL_REPEATER
+
+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 */
diff --git a/include/drivers/io/io_block.h b/include/drivers/io/io_block.h
new file mode 100644
index 0000000..c99e8c7
--- /dev/null
+++ b/include/drivers/io/io_block.h
@@ -0,0 +1,28 @@
+/*
+ * 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 <drivers/io/io_storage.h>
+
+/* 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 */
diff --git a/include/drivers/io/io_driver.h b/include/drivers/io/io_driver.h
new file mode 100644
index 0000000..d8bb435
--- /dev/null
+++ b/include/drivers/io/io_driver.h
@@ -0,0 +1,59 @@
+/*
+ * 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 <stdint.h>
+
+#include <drivers/io/io_storage.h>
+
+/* 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, signed long long offset);
+ int (*size)(io_entity_t *entity, size_t *length);
+ int (*read)(io_entity_t *entity, uintptr_t buffer, size_t length,
+ size_t *length_read);
+ 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 */
diff --git a/include/drivers/io/io_dummy.h b/include/drivers/io/io_dummy.h
new file mode 100644
index 0000000..edfc699
--- /dev/null
+++ b/include/drivers/io/io_dummy.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/include/drivers/io/io_encrypted.h b/include/drivers/io/io_encrypted.h
new file mode 100644
index 0000000..9dcf061
--- /dev/null
+++ b/include/drivers/io/io_encrypted.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2020, Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_ENCRYPTED_H
+#define IO_ENCRYPTED_H
+
+struct io_dev_connector;
+
+int register_io_dev_enc(const struct io_dev_connector **dev_con);
+
+#endif /* IO_ENCRYPTED_H */
diff --git a/include/drivers/io/io_fip.h b/include/drivers/io/io_fip.h
new file mode 100644
index 0000000..7e65436
--- /dev/null
+++ b/include/drivers/io/io_fip.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2014-2020, 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);
+int fip_dev_get_plat_toc_flag(io_dev_info_t *dev_info, uint16_t *plat_toc_flag);
+
+#endif /* IO_FIP_H */
diff --git a/include/drivers/io/io_memmap.h b/include/drivers/io/io_memmap.h
new file mode 100644
index 0000000..87e3466
--- /dev/null
+++ b/include/drivers/io/io_memmap.h
@@ -0,0 +1,14 @@
+/*
+ * 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 */
diff --git a/include/drivers/io/io_mtd.h b/include/drivers/io/io_mtd.h
new file mode 100644
index 0000000..2b5d9b1
--- /dev/null
+++ b/include/drivers/io/io_mtd.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2019-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_MTD_H
+#define IO_MTD_H
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <drivers/io/io_storage.h>
+
+/* MTD devices ops */
+typedef struct io_mtd_ops {
+ /*
+ * Initialize MTD framework and retrieve device information.
+ *
+ * @size: [out] MTD device size in bytes.
+ * @erase_size: [out] MTD erase size in bytes.
+ * Return 0 on success, a negative error code otherwise.
+ */
+ int (*init)(unsigned long long *size, unsigned int *erase_size);
+
+ /*
+ * Execute a read memory operation.
+ *
+ * @offset: Offset in bytes to start read operation.
+ * @buffer: [out] Buffer to store read data.
+ * @length: Required length to be read in bytes.
+ * @out_length: [out] Length read in bytes.
+ * Return 0 on success, a negative error code otherwise.
+ */
+ int (*read)(unsigned int offset, uintptr_t buffer, size_t length,
+ size_t *out_length);
+
+ /*
+ * Execute a write memory operation.
+ *
+ * @offset: Offset in bytes to start write operation.
+ * @buffer: Buffer to be written in device.
+ * @length: Required length to be written in bytes.
+ * Return 0 on success, a negative error code otherwise.
+ */
+ int (*write)(unsigned int offset, uintptr_t buffer, size_t length);
+
+ /*
+ * Look for an offset to be added to the given offset.
+ *
+ * @base: Base address of the area.
+ * @offset: Offset in bytes to start read operation.
+ * @extra_offset: [out] Offset to be added to the previous offset.
+ * Return 0 on success, a negative error code otherwise.
+ */
+ int (*seek)(uintptr_t base, unsigned int offset, size_t *extra_offset);
+} io_mtd_ops_t;
+
+typedef struct io_mtd_dev_spec {
+ unsigned long long device_size;
+ unsigned int erase_size;
+ size_t offset;
+ io_mtd_ops_t ops;
+} io_mtd_dev_spec_t;
+
+struct io_dev_connector;
+
+int register_io_dev_mtd(const struct io_dev_connector **dev_con);
+
+#endif /* IO_MTD_H */
diff --git a/include/drivers/io/io_semihosting.h b/include/drivers/io/io_semihosting.h
new file mode 100644
index 0000000..e90ea5c
--- /dev/null
+++ b/include/drivers/io/io_semihosting.h
@@ -0,0 +1,14 @@
+/*
+ * 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 */
diff --git a/include/drivers/io/io_storage.h b/include/drivers/io/io_storage.h
new file mode 100644
index 0000000..8f30ed0
--- /dev/null
+++ b/include/drivers/io/io_storage.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2014-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_STORAGE_H
+#define IO_STORAGE_H
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h> /* For ssize_t */
+
+#include <tools_share/uuid.h>
+
+/* 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_MTD,
+ IO_TYPE_MMC,
+ IO_TYPE_ENCRYPTED,
+ 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 {
+ 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, signed long long 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 */
diff --git a/include/drivers/marvell/addr_map.h b/include/drivers/marvell/addr_map.h
new file mode 100644
index 0000000..0d219f2
--- /dev/null
+++ b/include/drivers/marvell/addr_map.h
@@ -0,0 +1,21 @@
+/*
+ * 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 <stdint.h>
+
+struct addr_map_win {
+ uint64_t base_addr;
+ uint64_t win_size;
+ uint32_t target_id;
+};
+
+#endif /* ADDR_MAP_H */
diff --git a/include/drivers/marvell/amb_adec.h b/include/drivers/marvell/amb_adec.h
new file mode 100644
index 0000000..a92db5b
--- /dev/null
+++ b/include/drivers/marvell/amb_adec.h
@@ -0,0 +1,36 @@
+/*
+ * 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 <stdint.h>
+
+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 */
diff --git a/include/drivers/marvell/ap807_clocks_init.h b/include/drivers/marvell/ap807_clocks_init.h
new file mode 100644
index 0000000..4353b83
--- /dev/null
+++ b/include/drivers/marvell/ap807_clocks_init.h
@@ -0,0 +1,14 @@
+/*
+ * 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 */
+
diff --git a/include/drivers/marvell/aro.h b/include/drivers/marvell/aro.h
new file mode 100644
index 0000000..4d1094a
--- /dev/null
+++ b/include/drivers/marvell/aro.h
@@ -0,0 +1,49 @@
+/*
+ * 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
+};
+
+#include <mvebu_def.h>
+
+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_2200_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 */
diff --git a/include/drivers/marvell/cache_llc.h b/include/drivers/marvell/cache_llc.h
new file mode 100644
index 0000000..72111b3
--- /dev/null
+++ b/include/drivers/marvell/cache_llc.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018-2020 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_SECURE_CTRL(ap) (MVEBU_LLC_BASE(ap) + 0x10C)
+#define LLC_SYNC(ap) (MVEBU_LLC_BASE(ap) + 0x700)
+#define LLC_BANKED_MNT_AHR(ap) (MVEBU_LLC_BASE(ap) + 0x724)
+#define LLC_INV_WAY(ap) (MVEBU_LLC_BASE(ap) + 0x77C)
+#define LLC_BLK_ALOC(ap) (MVEBU_LLC_BASE(ap) + 0x78c)
+#define LLC_CLEAN_WAY(ap) (MVEBU_LLC_BASE(ap) + 0x7BC)
+#define LLC_CLEAN_INV_WAY(ap) (MVEBU_LLC_BASE(ap) + 0x7FC)
+#define LLC_TCN_LOCK(ap, tc) (MVEBU_LLC_BASE(ap) + 0x920 + 4 * (tc))
+
+#define MASTER_LLC_CTRL LLC_CTRL(MVEBU_AP0)
+#define MASTER_LLC_INV_WAY LLC_INV_WAY(MVEBU_AP0)
+#define MASTER_LLC_TC0_LOCK LLC_TCN_LOCK(MVEBU_AP0, 0)
+
+#define LLC_CTRL_EN 1
+#define LLC_EXCLUSIVE_EN 0x100
+#define LLC_ALL_WAYS_MASK 0xFFFFFFFF
+
+/* AP806/AP807 - 1MB 8-ways LLC */
+#define LLC_WAYS 8
+#define LLC_WAY_MASK ((1 << LLC_WAYS) - 1)
+#define LLC_SIZE (1024 * 1024)
+#define LLC_WAY_SIZE (LLC_SIZE / LLC_WAYS)
+#define LLC_TC_NUM 15
+
+#define LLC_BLK_ALOC_WAY_ID(way) ((way) & 0x1f)
+#define LLC_BLK_ALOC_WAY_DATA_DSBL (0x0 << 6)
+#define LLC_BLK_ALOC_WAY_DATA_CLR (0x1 << 6)
+#define LLC_BLK_ALOC_WAY_DATA_SET (0x3 << 6)
+#define LLC_BLK_ALOC_BASE_ADDR(addr) ((addr) & ~(LLC_WAY_SIZE - 1))
+
+#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);
+#if LLC_SRAM
+int llc_sram_enable(int ap_index, int size);
+void llc_sram_disable(int ap_index);
+int llc_sram_test(int ap_index, int size, char *msg);
+#endif /* LLC_SRAM */
+#endif /* __ASSEMBLER__ */
+
+#endif /* CACHE_LLC_H */
diff --git a/include/drivers/marvell/ccu.h b/include/drivers/marvell/ccu.h
new file mode 100644
index 0000000..f8f0adf
--- /dev/null
+++ b/include/drivers/marvell/ccu.h
@@ -0,0 +1,53 @@
+/*
+ * 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 <drivers/marvell/addr_map.h>
+#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);
+int ccu_is_win_enabled(int ap_index, uint32_t win_id);
+void errata_wa_init(void);
+#endif
+
+#endif /* CCU_H */
diff --git a/include/drivers/marvell/gwin.h b/include/drivers/marvell/gwin.h
new file mode 100644
index 0000000..1b874a7
--- /dev/null
+++ b/include/drivers/marvell/gwin.h
@@ -0,0 +1,19 @@
+/*
+ * 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 <drivers/marvell/addr_map.h>
+
+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 */
diff --git a/include/drivers/marvell/i2c.h b/include/drivers/marvell/i2c.h
new file mode 100644
index 0000000..06c5114
--- /dev/null
+++ b/include/drivers/marvell/i2c.h
@@ -0,0 +1,20 @@
+/*
+ * 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 */
diff --git a/include/drivers/marvell/io_win.h b/include/drivers/marvell/io_win.h
new file mode 100644
index 0000000..7438d6b
--- /dev/null
+++ b/include/drivers/marvell/io_win.h
@@ -0,0 +1,21 @@
+/*
+ * 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 <drivers/marvell/addr_map.h>
+
+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 */
diff --git a/include/drivers/marvell/iob.h b/include/drivers/marvell/iob.h
new file mode 100644
index 0000000..9b5e515
--- /dev/null
+++ b/include/drivers/marvell/iob.h
@@ -0,0 +1,31 @@
+/*
+ * 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 <drivers/marvell/addr_map.h>
+
+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 */
diff --git a/include/drivers/marvell/mci.h b/include/drivers/marvell/mci.h
new file mode 100644
index 0000000..af5d620
--- /dev/null
+++ b/include/drivers/marvell/mci.h
@@ -0,0 +1,18 @@
+/*
+ * 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_link_tune(int mci_index);
+void mci_turn_link_down(void);
+void mci_turn_link_on(void);
+int mci_get_link_status(void);
+
+#endif /* MCI_H */
diff --git a/include/drivers/marvell/mochi/ap_setup.h b/include/drivers/marvell/mochi/ap_setup.h
new file mode 100644
index 0000000..5b0e75f
--- /dev/null
+++ b/include/drivers/marvell/mochi/ap_setup.h
@@ -0,0 +1,18 @@
+/*
+ * 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);
+void update_cp110_default_win(int cp_id);
+
+#endif /* AP_SETUP_H */
diff --git a/include/drivers/marvell/mochi/cp110_setup.h b/include/drivers/marvell/mochi/cp110_setup.h
new file mode 100644
index 0000000..4a69257
--- /dev/null
+++ b/include/drivers/marvell/mochi/cp110_setup.h
@@ -0,0 +1,66 @@
+/*
+ * 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 <lib/mmio.h>
+
+#include <mvebu_def.h>
+
+#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_CN9130_DEV_ID (0x7025)
+#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)
+
+#define MVEBU_SECUREBOOT_CTRL_REG (MVEBU_RFU_BASE + 0x4730)
+#define MVEBU_SECUREBOOT_EN_MASK BIT(0)
+
+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;
+}
+
+static inline uint32_t is_secure(void)
+{
+ return !!(mmio_read_32(MVEBU_SECUREBOOT_CTRL_REG) &
+ MVEBU_SECUREBOOT_EN_MASK);
+}
+
+void cp110_init(uintptr_t cp110_base, uint32_t stream_id);
+void cp110_ble_init(uintptr_t cp110_base);
+void cp110_amb_init(uintptr_t base);
+
+#endif /* CP110_SETUP_H */
diff --git a/include/drivers/marvell/thermal.h b/include/drivers/marvell/thermal.h
new file mode 100644
index 0000000..48376a7
--- /dev/null
+++ b/include/drivers/marvell/thermal.h
@@ -0,0 +1,31 @@
+/*
+ * 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 */
diff --git a/include/drivers/marvell/uart/a3700_console.h b/include/drivers/marvell/uart/a3700_console.h
new file mode 100644
index 0000000..ce673a1
--- /dev/null
+++ b/include/drivers/marvell/uart/a3700_console.h
@@ -0,0 +1,74 @@
+/*
+ * 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 <drivers/console.h>
+#include <platform_def.h>
+
+/* 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 */
+#define UARTLSR_TXEMPTY (1 << 6) /* Tx Empty */
+#define UARTLSR_RXRDY (1 << 4) /* Rx Ready */
+
+/* UART Control Register bits */
+#define UART_CTRL_RXFIFO_RESET (1 << 14)
+#define UART_CTRL_TXFIFO_RESET (1 << 15)
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+/*
+ * 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_t *console);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* A3700_CONSOLE_H */
diff --git a/include/drivers/measured_boot/event_log/event_log.h b/include/drivers/measured_boot/event_log/event_log.h
new file mode 100644
index 0000000..eb0e2b1
--- /dev/null
+++ b/include/drivers/measured_boot/event_log/event_log.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EVENT_LOG_H
+#define EVENT_LOG_H
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/measured_boot/event_log/tcg.h>
+
+/*
+ * Set Event Log debug level to one of:
+ *
+ * LOG_LEVEL_ERROR
+ * LOG_LEVEL_INFO
+ * LOG_LEVEL_WARNING
+ * LOG_LEVEL_VERBOSE
+ */
+#if EVENT_LOG_LEVEL == LOG_LEVEL_ERROR
+#define LOG_EVENT ERROR
+#elif EVENT_LOG_LEVEL == LOG_LEVEL_NOTICE
+#define LOG_EVENT NOTICE
+#elif EVENT_LOG_LEVEL == LOG_LEVEL_WARNING
+#define LOG_EVENT WARN
+#elif EVENT_LOG_LEVEL == LOG_LEVEL_INFO
+#define LOG_EVENT INFO
+#elif EVENT_LOG_LEVEL == LOG_LEVEL_VERBOSE
+#define LOG_EVENT VERBOSE
+#else
+#error "Not supported EVENT_LOG_LEVEL"
+#endif
+
+/* Number of hashing algorithms supported */
+#define HASH_ALG_COUNT 1U
+
+#define EVLOG_INVALID_ID UINT32_MAX
+
+#define MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
+
+/*
+ * Each event log entry has some metadata (i.e. a string) that identifies
+ * what is measured.These macros define these strings.
+ * Note that these strings follow the standardization recommendations
+ * defined in the Arm Server Base Security Guide (a.k.a. SBSG, Arm DEN 0086),
+ * where applicable. They should not be changed in the code.
+ * Where the SBSG does not make recommendations, we are free to choose any
+ * naming convention.
+ * The key thing is to choose meaningful strings so that when the TPM event
+ * log is used in attestation, the different components can be identified.
+ */
+#define EVLOG_BL2_STRING "BL_2"
+#define EVLOG_BL31_STRING "SECURE_RT_EL3"
+#if defined(SPD_opteed)
+#define EVLOG_BL32_STRING "SECURE_RT_EL1_OPTEE"
+#elif defined(SPD_tspd)
+#define EVLOG_BL32_STRING "SECURE_RT_EL1_TSPD"
+#elif defined(SPD_tlkd)
+#define EVLOG_BL32_STRING "SECURE_RT_EL1_TLKD"
+#elif defined(SPD_trusty)
+#define EVLOG_BL32_STRING "SECURE_RT_EL1_TRUSTY"
+#else
+#define EVLOG_BL32_STRING "SECURE_RT_EL1_UNKNOWN"
+#endif
+#define EVLOG_BL32_EXTRA1_STRING "SECURE_RT_EL1_OPTEE_EXTRA1"
+#define EVLOG_BL32_EXTRA2_STRING "SECURE_RT_EL1_OPTEE_EXTRA2"
+#define EVLOG_BL33_STRING "BL_33"
+#define EVLOG_FW_CONFIG_STRING "FW_CONFIG"
+#define EVLOG_HW_CONFIG_STRING "HW_CONFIG"
+#define EVLOG_NT_FW_CONFIG_STRING "NT_FW_CONFIG"
+#define EVLOG_SCP_BL2_STRING "SYS_CTRL_2"
+#define EVLOG_SOC_FW_CONFIG_STRING "SOC_FW_CONFIG"
+#define EVLOG_STM32_STRING "STM32"
+#define EVLOG_TB_FW_CONFIG_STRING "TB_FW_CONFIG"
+#define EVLOG_TOS_FW_CONFIG_STRING "TOS_FW_CONFIG"
+#define EVLOG_RMM_STRING "RMM"
+#define EVLOG_SP1_STRING "SP1"
+#define EVLOG_SP2_STRING "SP2"
+#define EVLOG_SP3_STRING "SP3"
+#define EVLOG_SP4_STRING "SP4"
+#define EVLOG_SP5_STRING "SP5"
+#define EVLOG_SP6_STRING "SP6"
+#define EVLOG_SP7_STRING "SP7"
+#define EVLOG_SP8_STRING "SP8"
+
+typedef struct {
+ unsigned int id;
+ const char *name;
+ unsigned int pcr;
+} event_log_metadata_t;
+
+#define ID_EVENT_SIZE (sizeof(id_event_headers_t) + \
+ (sizeof(id_event_algorithm_size_t) * HASH_ALG_COUNT) + \
+ sizeof(id_event_struct_data_t))
+
+#define LOC_EVENT_SIZE (sizeof(event2_header_t) + \
+ sizeof(tpmt_ha) + TCG_DIGEST_SIZE + \
+ sizeof(event2_data_t) + \
+ sizeof(startup_locality_event_t))
+
+#define LOG_MIN_SIZE (ID_EVENT_SIZE + LOC_EVENT_SIZE)
+
+#define EVENT2_HDR_SIZE (sizeof(event2_header_t) + \
+ sizeof(tpmt_ha) + TCG_DIGEST_SIZE + \
+ sizeof(event2_data_t))
+
+/* Functions' declarations */
+void event_log_buf_init(uint8_t *event_log_start, uint8_t *event_log_finish);
+void event_log_init(uint8_t *event_log_start, uint8_t *event_log_finish);
+void event_log_write_specid_event(void);
+void event_log_write_header(void);
+void dump_event_log(uint8_t *log_addr, size_t log_size);
+const event_log_metadata_t *plat_event_log_get_metadata(void);
+int event_log_measure(uintptr_t data_base, uint32_t data_size,
+ unsigned char hash_data[CRYPTO_MD_MAX_SIZE]);
+void event_log_record(const uint8_t *hash, uint32_t event_type,
+ const event_log_metadata_t *metadata_ptr);
+int event_log_measure_and_record(uintptr_t data_base, uint32_t data_size,
+ uint32_t data_id);
+size_t event_log_get_cur_size(uint8_t *event_log_start);
+
+#endif /* EVENT_LOG_H */
diff --git a/include/drivers/measured_boot/event_log/tcg.h b/include/drivers/measured_boot/event_log/tcg.h
new file mode 100644
index 0000000..4ac2c2f
--- /dev/null
+++ b/include/drivers/measured_boot/event_log/tcg.h
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TCG_H
+#define TCG_H
+
+#include <stdint.h>
+
+#define TCG_ID_EVENT_SIGNATURE_03 "Spec ID Event03"
+#define TCG_STARTUP_LOCALITY_SIGNATURE "StartupLocality"
+
+#define TCG_SPEC_VERSION_MAJOR_TPM2 2
+#define TCG_SPEC_VERSION_MINOR_TPM2 0
+#define TCG_SPEC_ERRATA_TPM2 2
+
+/*
+ * Event types
+ * Ref. Table 9 Events
+ * TCG PC Client Platform Firmware Profile Specification.
+ */
+#define EV_PREBOOT_CERT U(0x00000000)
+#define EV_POST_CODE U(0x00000001)
+#define EV_UNUSED U(0x00000002)
+#define EV_NO_ACTION U(0x00000003)
+#define EV_SEPARATOR U(0x00000004)
+#define EV_ACTION U(0x00000005)
+#define EV_EVENT_TAG U(0x00000006)
+#define EV_S_CRTM_CONTENTS U(0x00000007)
+#define EV_S_CRTM_VERSION U(0x00000008)
+#define EV_CPU_MICROCODE U(0x00000009)
+#define EV_PLATFORM_CONFIG_FLAGS U(0x0000000A)
+#define EV_TABLE_OF_DEVICES U(0x0000000B)
+#define EV_COMPACT_HASH U(0x0000000C)
+#define EV_IPL U(0x0000000D)
+#define EV_IPL_PARTITION_DATA U(0x0000000E)
+#define EV_NONHOST_CODE U(0x0000000F)
+#define EV_NONHOST_CONFIG U(0x00000010)
+#define EV_NONHOST_INFO U(0x00000011)
+#define EV_OMIT_BOOT_DEVICE_EVENTS U(0x00000012)
+#define EV_EFI_EVENT_BASE U(0x80000000)
+#define EV_EFI_VARIABLE_DRIVER_CONFIG U(0x80000001)
+#define EV_EFI_VARIABLE_BOOT U(0x80000002)
+#define EV_EFI_BOOT_SERVICES_APPLICATION U(0x80000003)
+#define EV_EFI_BOOT_SERVICES_DRIVER U(0x80000004)
+#define EV_EFI_RUNTIME_SERVICES_DRIVER U(0x80000005)
+#define EV_EFI_GPT_EVENT U(0x80000006)
+#define EV_EFI_ACTION U(0x80000007)
+#define EV_EFI_PLATFORM_FIRMWARE_BLOB U(0x80000008)
+#define EV_EFI_HANDOFF_TABLES U(0x80000009)
+#define EV_EFI_HCRTM_EVENT U(0x80000010)
+#define EV_EFI_VARIABLE_AUTHORITY U(0x800000E0)
+
+/*
+ * TPM_ALG_ID constants.
+ * Ref. Table 9 - Definition of (UINT16) TPM_ALG_ID Constants
+ * Trusted Platform Module Library. Part 2: Structures
+ */
+#define TPM_ALG_SHA256 0x000B
+#define TPM_ALG_SHA384 0x000C
+#define TPM_ALG_SHA512 0x000D
+
+/* TCG Platform Type */
+#define PLATFORM_CLASS_CLIENT 0
+#define PLATFORM_CLASS_SERVER 1
+
+/* SHA digest sizes in bytes */
+#define SHA1_DIGEST_SIZE 20
+#define SHA256_DIGEST_SIZE 32
+#define SHA384_DIGEST_SIZE 48
+#define SHA512_DIGEST_SIZE 64
+
+enum {
+ /*
+ * SRTM, BIOS, Host Platform Extensions, Embedded
+ * Option ROMs and PI Drivers
+ */
+ PCR_0 = 0,
+ /* Host Platform Configuration */
+ PCR_1,
+ /* UEFI driver and application Code */
+ PCR_2,
+ /* UEFI driver and application Configuration and Data */
+ PCR_3,
+ /* UEFI Boot Manager Code (usually the MBR) and Boot Attempts */
+ PCR_4,
+ /*
+ * Boot Manager Code Configuration and Data (for use
+ * by the Boot Manager Code) and GPT/Partition Table
+ */
+ PCR_5,
+ /* Host Platform Manufacturer Specific */
+ PCR_6,
+ /* Secure Boot Policy */
+ PCR_7,
+ /* 8-15: Defined for use by the Static OS */
+ PCR_8,
+ /* Debug */
+ PCR_16 = 16,
+
+ /* D-CRTM-measurements by DRTM implementation */
+ PCR_17 = 17,
+ /* DCE measurements by DRTM implementation */
+ PCR_18 = 18
+};
+
+#pragma pack(push, 1)
+
+/*
+ * PCR Event Header
+ * TCG EFI Protocol Specification
+ * 5.3 Event Log Header
+ */
+typedef struct {
+ /* PCRIndex:
+ * The PCR Index to which this event is extended
+ */
+ uint32_t pcr_index;
+
+ /* EventType:
+ * SHALL be an EV_NO_ACTION event
+ */
+ uint32_t event_type;
+
+ /* SHALL be 20 Bytes of 0x00 */
+ uint8_t digest[SHA1_DIGEST_SIZE];
+
+ /* The size of the event */
+ uint32_t event_size;
+
+ /* SHALL be a TCG_EfiSpecIdEvent */
+ uint8_t event[]; /* [event_data_size] */
+} tcg_pcr_event_t;
+
+/*
+ * Log Header Entry Data
+ * Ref. Table 14 TCG_EfiSpecIdEventAlgorithmSize
+ * TCG PC Client Platform Firmware Profile 9.4.5.1
+ */
+typedef struct {
+ /* Algorithm ID (hashAlg) of the Hash used by BIOS */
+ uint16_t algorithm_id;
+
+ /* The size of the digest produced by the implemented Hash algorithm */
+ uint16_t digest_size;
+} id_event_algorithm_size_t;
+
+/*
+ * TCG_EfiSpecIdEvent structure
+ * Ref. Table 15 TCG_EfiSpecIdEvent
+ * TCG PC Client Platform Firmware Profile 9.4.5.1
+ */
+typedef struct {
+ /*
+ * The NUL-terminated ASCII string "Spec ID Event03".
+ * SHALL be set to {0x53, 0x70, 0x65, 0x63, 0x20, 0x49, 0x44,
+ * 0x20, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x33, 0x00}.
+ */
+ uint8_t signature[16];
+
+ /*
+ * The value for the Platform Class.
+ * The enumeration is defined in the TCG ACPI Specification Client
+ * Common Header.
+ */
+ uint32_t platform_class;
+
+ /*
+ * The PC Client Platform Profile Specification minor version number
+ * this BIOS supports.
+ * Any BIOS supporting this version (2.0) MUST set this value to 0x00.
+ */
+ uint8_t spec_version_minor;
+
+ /*
+ * The PC Client Platform Profile Specification major version number
+ * this BIOS supports.
+ * Any BIOS supporting this version (2.0) MUST set this value to 0x02.
+ */
+ uint8_t spec_version_major;
+
+ /*
+ * The PC Client Platform Profile Specification errata version number
+ * this BIOS supports.
+ * Any BIOS supporting this version (2.0) MUST set this value to 0x02.
+ */
+ uint8_t spec_errata;
+
+ /*
+ * Specifies the size of the UINTN fields used in various data
+ * structures used in this specification.
+ * 0x01 indicates UINT32 and 0x02 indicates UINT64.
+ */
+ uint8_t uintn_size;
+
+ /*
+ * The number of Hash algorithms in the digestSizes field.
+ * This field MUST be set to a value of 0x01 or greater.
+ */
+ uint32_t number_of_algorithms;
+
+ /*
+ * Each TCG_EfiSpecIdEventAlgorithmSize SHALL contain an algorithmId
+ * and digestSize for each hash algorithm used in the TCG_PCR_EVENT2
+ * structure, the first of which is a Hash algorithmID and the second
+ * is the size of the respective digest.
+ */
+ id_event_algorithm_size_t digest_size[]; /* number_of_algorithms */
+} id_event_struct_header_t;
+
+typedef struct {
+ /*
+ * Size in bytes of the VendorInfo field.
+ * Maximum value MUST be FFh bytes.
+ */
+ uint8_t vendor_info_size;
+
+ /*
+ * Provided for use by Platform Firmware implementer. The value might
+ * be used, for example, to provide more detailed information about the
+ * specific BIOS such as BIOS revision numbers, etc. The values within
+ * this field are not standardized and are implementer-specific.
+ * Platform-specific or -unique information MUST NOT be provided in
+ * this field.
+ *
+ */
+ uint8_t vendor_info[]; /* [vendorInfoSize] */
+} id_event_struct_data_t;
+
+typedef struct {
+ id_event_struct_header_t struct_header;
+ id_event_struct_data_t struct_data;
+} id_event_struct_t;
+
+typedef struct {
+ tcg_pcr_event_t header;
+ id_event_struct_header_t struct_header;
+} id_event_headers_t;
+
+/* TPMT_HA Structure */
+typedef struct {
+ /* Selector of the hash contained in the digest that implies
+ * the size of the digest
+ */
+ uint16_t algorithm_id; /* AlgorithmId */
+
+ /* Digest, depends on AlgorithmId */
+ uint8_t digest[]; /* Digest[] */
+} tpmt_ha;
+
+/*
+ * TPML_DIGEST_VALUES Structure
+ */
+typedef struct {
+ /* The number of digests in the list */
+ uint32_t count; /* Count */
+
+ /* The list of tagged digests, as sent to the TPM as part of a
+ * TPM2_PCR_Extend or as received from a TPM2_PCR_Event command
+ */
+ tpmt_ha digests[]; /* Digests[Count] */
+} tpml_digest_values;
+
+/*
+ * TCG_PCR_EVENT2 header
+ */
+typedef struct {
+ /* The PCR Index to which this event was extended */
+ uint32_t pcr_index; /* PCRIndex */
+
+ /* Type of event */
+ uint32_t event_type; /* EventType */
+
+ /* Digests:
+ * A counted list of tagged digests, which contain the digest of
+ * the event data (or external data) for all active PCR banks
+ */
+ tpml_digest_values digests; /* Digests */
+} event2_header_t;
+
+typedef struct event2_data {
+ /* The size of the event data */
+ uint32_t event_size; /* EventSize */
+
+ /* The data of the event */
+ uint8_t event[]; /* Event[EventSize] */
+} event2_data_t;
+
+/*
+ * Startup Locality Event
+ * Ref. TCG PC Client Platform Firmware Profile 9.4.5.3
+ */
+typedef struct {
+ /*
+ * The NUL-terminated ASCII string "StartupLocality" SHALL be
+ * set to {0x53 0x74 0x61 0x72 0x74 0x75 0x70 0x4C 0x6F 0x63
+ * 0x61 0x6C 0x69 0x74 0x79 0x00}
+ */
+ uint8_t signature[16];
+
+ /* The Locality Indicator which sent the TPM2_Startup command */
+ uint8_t startup_locality;
+} startup_locality_event_t;
+
+#pragma pack(pop)
+
+#endif /* TCG_H */
diff --git a/include/drivers/measured_boot/rss/rss_measured_boot.h b/include/drivers/measured_boot/rss/rss_measured_boot.h
new file mode 100644
index 0000000..fe88576
--- /dev/null
+++ b/include/drivers/measured_boot/rss/rss_measured_boot.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RSS_MEASURED_BOOT_H
+#define RSS_MEASURED_BOOT_H
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <measured_boot.h>
+
+#define RSS_MBOOT_INVALID_ID UINT32_MAX
+
+/*
+ * Each boot measurement has some metadata (i.e. a string) that identifies
+ * what was measured and how. The sw_type field of the rss_mboot_metadata
+ * structure represents the role of the software component that was measured.
+ * The below macros define strings suitable for the sw_type.
+ * The key thing is to choose meaningful strings so that when the attestation
+ * token is verified, then the different components can be identified.
+ */
+#define RSS_MBOOT_BL2_STRING "BL_2"
+#define RSS_MBOOT_BL31_STRING "SECURE_RT_EL3"
+#define RSS_MBOOT_HW_CONFIG_STRING "HW_CONFIG"
+#define RSS_MBOOT_FW_CONFIG_STRING "FW_CONFIG"
+#define RSS_MBOOT_TB_FW_CONFIG_STRING "TB_FW_CONFIG"
+#define RSS_MBOOT_SOC_FW_CONFIG_STRING "SOC_FW_CONFIG"
+#define RSS_MBOOT_RMM_STRING "RMM"
+
+
+struct rss_mboot_metadata {
+ unsigned int id;
+ uint8_t slot;
+ uint8_t signer_id[SIGNER_ID_MAX_SIZE];
+ size_t signer_id_size;
+ uint8_t version[VERSION_MAX_SIZE];
+ size_t version_size;
+ uint8_t sw_type[SW_TYPE_MAX_SIZE];
+ size_t sw_type_size;
+ bool lock_measurement;
+};
+
+/* Functions' declarations */
+void rss_measured_boot_init(void);
+struct rss_mboot_metadata *plat_rss_mboot_get_metadata(void);
+int rss_mboot_measure_and_record(uintptr_t data_base, uint32_t data_size,
+ uint32_t data_id);
+
+/* TODO: These metadata are currently not available during TF-A boot */
+int rss_mboot_set_signer_id(unsigned int img_id, const void *pk_ptr, size_t pk_len);
+
+#endif /* RSS_MEASURED_BOOT_H */
diff --git a/include/drivers/mentor/mi2cv.h b/include/drivers/mentor/mi2cv.h
new file mode 100644
index 0000000..85b733b
--- /dev/null
+++ b/include/drivers/mentor/mi2cv.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * 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 <stdint.h>
+
+/*
+ * 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 */
diff --git a/include/drivers/mmc.h b/include/drivers/mmc.h
new file mode 100644
index 0000000..e94693d
--- /dev/null
+++ b/include/drivers/mmc.h
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MMC_H
+#define MMC_H
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#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_PART_SWITCH_TIME 199
+#define CMD_EXTCSD_SEC_CNT 212
+#define CMD_EXTCSD_BOOT_SIZE_MULT 226
+
+#define EXT_CSD_PART_CONFIG_ACC_MASK GENMASK(2, 0)
+#define PART_CFG_BOOT_PARTITION1_ENABLE (U(1) << 3)
+#define PART_CFG_BOOT_PARTITION1_ACCESS (U(1) << 0)
+#define PART_CFG_BOOT_PARTITION_NO_ACCESS U(0)
+#define PART_CFG_BOOT_PART_EN_MASK GENMASK(5, 3)
+#define PART_CFG_BOOT_PART_EN_SHIFT 3
+#define PART_CFG_CURRENT_BOOT_PARTITION(x) (((x) & PART_CFG_BOOT_PART_EN_MASK) >> \
+ PART_CFG_BOOT_PART_EN_SHIFT)
+
+/* 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 MMC_FLAG_SD_CMD6 (U(1) << 1)
+
+#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)
+
+#define SD_SWITCH_FUNC_CHECK 0U
+#define SD_SWITCH_FUNC_SWITCH BIT(31)
+#define SD_SWITCH_ALL_GROUPS_MASK GENMASK(23, 0)
+
+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;
+};
+
+struct sd_switch_status {
+ unsigned short max_current;
+ unsigned short support_g6;
+ unsigned short support_g5;
+ unsigned short support_g4;
+ unsigned short support_g3;
+ unsigned short support_g2;
+ unsigned short support_g1;
+ unsigned char sel_g6_g5;
+ unsigned char sel_g4_g3;
+ unsigned char sel_g2_g1;
+ unsigned char data_struct_ver;
+ unsigned short busy_g6;
+ unsigned short busy_g5;
+ unsigned short busy_g4;
+ unsigned short busy_g3;
+ unsigned short busy_g2;
+ unsigned short busy_g1;
+ unsigned short reserved[17];
+};
+
+enum mmc_device_type {
+ MMC_IS_EMMC,
+ MMC_IS_SD,
+ 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);
+int mmc_part_switch_current_boot(void);
+int mmc_part_switch_user(void);
+size_t mmc_boot_part_size(void);
+size_t mmc_boot_part_read_blocks(int lba, uintptr_t buf, 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 */
diff --git a/include/drivers/nand.h b/include/drivers/nand.h
new file mode 100644
index 0000000..5e5607c
--- /dev/null
+++ b/include/drivers/nand.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRIVERS_NAND_H
+#define DRIVERS_NAND_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#define PSEC_TO_MSEC(x) div_round_up((x), 1000000000ULL)
+
+struct ecc {
+ unsigned int mode; /* ECC mode NAND_ECC_MODE_{NONE|HW|ONDIE} */
+ unsigned int size; /* Data byte per ECC step */
+ unsigned int bytes; /* ECC bytes per step */
+ unsigned int max_bit_corr; /* Max correctible bits per ECC steps */
+};
+
+struct nand_device {
+ unsigned int block_size;
+ unsigned int page_size;
+ unsigned long long size;
+ unsigned int nb_planes;
+ unsigned int buswidth;
+ struct ecc ecc;
+ int (*mtd_block_is_bad)(unsigned int block);
+ int (*mtd_read_page)(struct nand_device *nand, unsigned int page,
+ uintptr_t buffer);
+};
+
+void plat_get_scratch_buffer(void **buffer_addr, size_t *buf_size);
+
+/*
+ * Read bytes from NAND device
+ *
+ * @offset: Byte offset to read from in device
+ * @buffer: [out] Bytes read from device
+ * @length: Number of bytes to read
+ * @length_read: [out] Number of bytes read from device
+ * Return: 0 on success, a negative errno on failure
+ */
+int nand_read(unsigned int offset, uintptr_t buffer, size_t length,
+ size_t *length_read);
+
+/*
+ * Look for an extra offset to be added in case of bad blocks
+ *
+ * @base: Base address of the area
+ * @offset: Byte offset to read from in device
+ * @extra_offset: [out] Extra offset to be added if bad blocks are found
+ * Return: 0 on success, a negative errno on failure
+ */
+int nand_seek_bb(uintptr_t base, unsigned int offset, size_t *extra_offset);
+
+/*
+ * Get NAND device instance
+ *
+ * Return: NAND device instance reference
+ */
+struct nand_device *get_nand_device(void);
+
+#endif /* DRIVERS_NAND_H */
diff --git a/include/drivers/nxp/auth/csf_hdr_parser/csf_hdr.h b/include/drivers/nxp/auth/csf_hdr_parser/csf_hdr.h
new file mode 100644
index 0000000..ae56d3b
--- /dev/null
+++ b/include/drivers/nxp/auth/csf_hdr_parser/csf_hdr.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2017-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef CSF_HDR_H
+#define CSF_HDR_H
+
+#include "caam.h"
+#include "hash.h"
+#include "rsa.h"
+
+/* Barker code size in bytes */
+#define CSF_BARKER_LEN 4 /* barker code length in ESBC uboot client */
+ /* header */
+
+#ifdef CSF_HDR_CH3
+struct csf_hdr {
+ uint8_t barker[CSF_BARKER_LEN]; /* 0x00 Barker code */
+ uint32_t srk_tbl_off; /* 0x04 SRK Table Offset */
+
+ struct {
+ uint8_t num_srk; /* 0x08 No. of keys */
+ uint8_t srk_sel; /* Key no. to be used */
+ uint8_t reserve; /* 0x0a rseerved */
+ } len_kr;
+ uint8_t ie_flag;
+
+ uint32_t uid_flag;
+
+ uint32_t psign; /* 0x10 signature offset */
+ uint32_t sign_len; /* 0x14 length of signature */
+
+ union {
+ struct {
+ uint32_t sg_table_offset; /* 0x18 SG Table Offset */
+ uint32_t sg_entries; /* 0x1c no of entries in SG */
+ } sg_isbc;
+ uint64_t img_addr; /* 64 bit pointer to ESBC Image */
+ };
+
+ union {
+ struct {
+ uint32_t img_size; /* ESBC client img size in bytes */
+ uint32_t ie_key_sel;
+ } img;
+ uint64_t entry_point; /* 0x20-0x24 ESBC entry point */
+ };
+
+ uint32_t fsl_uid_0; /* 0x28 Freescale unique id 0 */
+ uint32_t fsl_uid_1; /* 0x2c Freescale unique id 1 */
+ uint32_t oem_uid_0; /* 0x30 OEM unique id 0 */
+ uint32_t oem_uid_1; /* 0x34 OEM unique id 1 */
+ uint32_t oem_uid_2; /* 0x38 OEM unique id 2 */
+ uint32_t oem_uid_3; /* 0x3c OEM unique id 3 */
+ uint32_t oem_uid_4; /* 0x40 OEM unique id 4 */
+
+ uint32_t reserved[3]; /* 0x44 - 0x4f */
+};
+
+/* Srk table and key revocation check */
+#define UNREVOCABLE_KEY 8
+#define REVOC_KEY_ALIGN 7
+#define MAX_KEY_ENTRIES 8
+
+#else
+
+/* CSF header for Chassis 2 */
+struct csf_hdr {
+ uint8_t barker[CSF_BARKER_LEN]; /* barker code */
+ union {
+ uint32_t pkey; /* public key offset */
+ uint32_t srk_tbl_off;
+ };
+
+ union {
+ uint32_t key_len; /* pub key length in bytes */
+ struct {
+ uint32_t srk_table_flag:8;
+ uint32_t srk_sel:8;
+ uint32_t num_srk:16;
+ } len_kr;
+ };
+
+ uint32_t psign; /* signature offset */
+ uint32_t sign_len; /* length of the signature in bytes */
+
+ /* SG Table used by ISBC header */
+ union {
+ struct {
+ uint32_t sg_table_offset; /* 0x14 SG Table Offset */
+ uint32_t sg_entries; /* no of entries in SG table */
+ } sg_isbc;
+ struct {
+ uint32_t reserved1; /* Reserved field */
+ uint32_t img_size; /* ESBC img size in bytes */
+ } img;
+ };
+
+ uint32_t entry_point; /* ESBC client entry point */
+ uint32_t reserved2; /* Scatter gather flag */
+ uint32_t uid_flag;
+ uint32_t fsl_uid_0;
+ uint32_t oem_uid_0;
+ uint32_t reserved3[2];
+ uint32_t fsl_uid_1;
+ uint32_t oem_uid_1;
+
+ /* The entries below aren't present in ISBC header */
+ uint64_t img_addr; /* 64 bit pointer to ESBC Image */
+ uint32_t ie_flag;
+ uint32_t ie_key_sel;
+};
+
+/* Srk table and key revocation check */
+#define UNREVOCABLE_KEY 4
+#define REVOC_KEY_ALIGN 3
+#define MAX_KEY_ENTRIES 4
+
+#endif
+
+struct srk_table {
+ uint32_t key_len;
+ uint8_t pkey[2 * RSA_4K_KEY_SZ_BYTES];
+};
+
+/*
+ * This struct contains the following fields
+ * length of the segment
+ * Destination Target ID
+ * source address
+ * destination address
+ */
+struct sg_table {
+ uint32_t len; /* Length of Image */
+ uint32_t res1;
+ union {
+ uint64_t src_addr; /* SRC Address of Image */
+ struct {
+ uint32_t src_addr;
+ uint32_t dst_addr;
+ } img;
+ };
+};
+
+int validate_esbc_header(void *img_hdr, void **img_key, uint32_t *key_len,
+ void **img_sign, uint32_t *sign_len,
+ enum sig_alg *algo);
+
+int calc_img_hash(struct csf_hdr *hdr, void *img_addr, uint32_t img_size,
+ uint8_t *img_hash, uint32_t *hash_len);
+
+#endif
diff --git a/include/drivers/nxp/console/plat_console.h b/include/drivers/nxp/console/plat_console.h
new file mode 100644
index 0000000..8b1b23a
--- /dev/null
+++ b/include/drivers/nxp/console/plat_console.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PLAT_CONSOLE_H
+#define PLAT_CONSOLE_H
+
+#include <stdint.h>
+#include <drivers/console.h>
+
+#if (NXP_CONSOLE == NS16550)
+/*
+ * NXP specific UART - 16550 configuration
+ *
+ * Initialize a NXP 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.
+ * When |clock| has a value of 0, the UART will *not* be initialised. This
+ * means the UART should already be enabled and the baudrate and clock setup
+ * should have been done already, either by platform specific code or by
+ * previous firmware stages. The |baud| parameter will be ignored in this
+ * case as well.
+ */
+int nxp_console_16550_register(uintptr_t baseaddr, uint32_t clock,
+ uint32_t baud, console_t *console);
+#endif
+/*
+ * Function to initialize platform's console
+ * and register with console framework
+ */
+void plat_console_init(uintptr_t nxp_console_addr, uint32_t uart_clk_div,
+ uint32_t baud);
+
+#endif
diff --git a/include/drivers/nxp/crypto/caam/caam.h b/include/drivers/nxp/crypto/caam/caam.h
new file mode 100644
index 0000000..6cc1f3d
--- /dev/null
+++ b/include/drivers/nxp/crypto/caam/caam.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef CAAM_H
+#define CAAM_H
+
+#include "caam_io.h"
+#include "sec_jr_driver.h"
+
+
+/* Job ring 3 is reserved for usage by sec firmware */
+#define DEFAULT_JR 3
+
+#if defined(CONFIG_CHASSIS_3_2) || defined(CONFIG_CHASSIS_3) || defined(CONFIG_CHASSIS_2)
+#define CAAM_JR0_OFFSET 0x10000
+#define CAAM_JR1_OFFSET 0x20000
+#define CAAM_JR2_OFFSET 0x30000
+#define CAAM_JR3_OFFSET 0x40000
+#endif
+
+enum sig_alg {
+ RSA,
+ ECC
+};
+
+/* This function does basic SEC Initialization */
+int sec_init(uintptr_t nxp_caam_addr);
+int config_sec_block(void);
+uintptr_t get_caam_addr(void);
+
+/* This function is used to submit jobs to JR */
+int run_descriptor_jr(struct job_descriptor *desc);
+
+/* This function is used to instatiate the HW RNG is already not instantiated */
+int hw_rng_instantiate(void);
+
+/* This function is used to return random bytes of byte_len from HW RNG */
+int get_rand_bytes_hw(uint8_t *bytes, int byte_len);
+
+/* This function is used to set the hw unique key from HW CAAM */
+int get_hw_unq_key_blob_hw(uint8_t *hw_key, int size);
+
+/* This function is used to fetch random number from
+ * CAAM of length either of 4 bytes or 8 bytes depending
+ * rngWidth value.
+ */
+unsigned long long get_random(int rngWidth);
+
+#endif /* CAAM_H */
diff --git a/include/drivers/nxp/crypto/caam/caam_io.h b/include/drivers/nxp/crypto/caam/caam_io.h
new file mode 100644
index 0000000..b68f836
--- /dev/null
+++ b/include/drivers/nxp/crypto/caam/caam_io.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef CAAM_IO_H
+#define CAAM_IO_H
+
+#include <endian.h>
+#include <lib/mmio.h>
+
+typedef unsigned long long phys_addr_t;
+typedef unsigned long long phys_size_t;
+
+/* Return higher 32 bits of physical address */
+#define PHYS_ADDR_HI(phys_addr) \
+ (uint32_t)(((uint64_t)phys_addr) >> 32)
+
+/* Return lower 32 bits of physical address */
+#define PHYS_ADDR_LO(phys_addr) \
+ (uint32_t)(((uint64_t)phys_addr) & 0xFFFFFFFF)
+
+#ifdef NXP_SEC_BE
+#define sec_in32(a) bswap32(mmio_read_32((uintptr_t)(a)))
+#define sec_out32(a, v) mmio_write_32((uintptr_t)(a), bswap32(v))
+#define sec_in64(addr) ( \
+ ((uint64_t)sec_in32((uintptr_t)(addr)) << 32) | \
+ (sec_in32(((uintptr_t)(addr)) + 4)))
+#define sec_out64(addr, val) ({ \
+ sec_out32(((uintptr_t)(addr)), (uint32_t)((val) >> 32)); \
+ sec_out32(((uintptr_t)(addr)) + 4, (uint32_t)(val)); })
+#elif defined(NXP_SEC_LE)
+#define sec_in32(a) mmio_read_32((uintptr_t)(a))
+#define sec_out32(a, v) mmio_write_32((uintptr_t)(a), (v))
+#define sec_in64(addr) ( \
+ ((uint64_t)sec_in32((uintptr_t)(addr) + 4) << 32) | \
+ (sec_in32((uintptr_t)(addr))))
+#define sec_out64(addr, val) ({ \
+ sec_out32(((uintptr_t)(addr)) + 4, (uint32_t)((val) >> 32)); \
+ sec_out32(((uintptr_t)(addr)), (uint32_t)(val)); })
+#else
+#error Please define CCSR SEC register endianness
+#endif
+
+static inline void *ptov(phys_addr_t *ptr)
+{
+ return (void *)ptr;
+}
+
+static inline phys_addr_t *vtop(void *ptr)
+{
+ return (phys_addr_t *)ptr;
+}
+#endif /* CAAM_IO_H */
diff --git a/include/drivers/nxp/crypto/caam/hash.h b/include/drivers/nxp/crypto/caam/hash.h
new file mode 100644
index 0000000..9136dca
--- /dev/null
+++ b/include/drivers/nxp/crypto/caam/hash.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2017-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __HASH_H__
+#define __HASH_H__
+
+#include <stdbool.h>
+
+/* List of hash algorithms */
+enum hash_algo {
+ SHA1 = 0,
+ SHA256
+};
+
+/* number of bytes in the SHA256-256 digest */
+#define SHA256_DIGEST_SIZE 32
+
+/*
+ * number of words in the digest - Digest is kept internally
+ * as 8 32-bit words
+ */
+#define _SHA256_DIGEST_LENGTH 8
+
+/*
+ * block length - A block, treated as a sequence of
+ * 32-bit words
+ */
+#define SHA256_BLOCK_LENGTH 16
+
+/* number of bytes in the block */
+#define SHA256_DATA_SIZE 64
+
+#define MAX_SG 12
+
+struct sg_entry {
+#if defined(NXP_SEC_LE)
+ uint32_t addr_lo; /* Memory Address - lo */
+ uint32_t addr_hi; /* Memory Address of start of buffer - hi */
+#else
+ uint32_t addr_hi; /* Memory Address of start of buffer - hi */
+ uint32_t addr_lo; /* Memory Address - lo */
+#endif
+
+ uint32_t len_flag; /* Length of the data in the frame */
+#define SG_ENTRY_LENGTH_MASK 0x3FFFFFFF
+#define SG_ENTRY_EXTENSION_BIT 0x80000000
+#define SG_ENTRY_FINAL_BIT 0x40000000
+ uint32_t bpid_offset;
+#define SG_ENTRY_BPID_MASK 0x00FF0000
+#define SG_ENTRY_BPID_SHIFT 16
+#define SG_ENTRY_OFFSET_MASK 0x00001FFF
+#define SG_ENTRY_OFFSET_SHIFT 0
+};
+
+/*
+ * SHA256-256 context
+ * contain the following fields
+ * State
+ * count low
+ * count high
+ * block data buffer
+ * index to the buffer
+ */
+struct hash_ctx {
+ struct sg_entry sg_tbl[MAX_SG];
+ uint32_t hash_desc[64];
+ uint8_t hash[SHA256_DIGEST_SIZE];
+ uint32_t sg_num;
+ uint32_t len;
+ uint8_t *data;
+ enum hash_algo algo;
+ bool active;
+};
+
+int hash_init(enum hash_algo algo, void **ctx);
+int hash_update(enum hash_algo algo, void *context, void *data_ptr,
+ unsigned int data_len);
+int hash_final(enum hash_algo algo, void *context, void *hash_ptr,
+ unsigned int hash_len);
+
+#endif
diff --git a/include/drivers/nxp/crypto/caam/jobdesc.h b/include/drivers/nxp/crypto/caam/jobdesc.h
new file mode 100644
index 0000000..efef228
--- /dev/null
+++ b/include/drivers/nxp/crypto/caam/jobdesc.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2017-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __JOBDESC_H
+#define __JOBDESC_H
+
+#include <rsa.h>
+
+#define DESC_LEN_MASK 0x7f
+#define DESC_START_SHIFT 16
+
+#define KEY_BLOB_SIZE 32
+#define MAC_SIZE 16
+
+#define KEY_IDNFR_SZ_BYTES 16
+#define CLASS_SHIFT 25
+#define CLASS_2 (0x02 << CLASS_SHIFT)
+
+#define CMD_SHIFT 27
+#define CMD_OPERATION (U(0x10) << CMD_SHIFT)
+
+#define OP_TYPE_SHIFT 24
+#define OP_TYPE_ENCAP_PROTOCOL (0x07 << OP_TYPE_SHIFT)
+
+/* Assuming OP_TYPE = OP_TYPE_UNI_PROTOCOL */
+#define OP_PCLID_SHIFT 16
+#define OP_PCLID_BLOB (0x0d << OP_PCLID_SHIFT)
+
+#define BLOB_PROTO_INFO 0x00000002
+
+uint32_t desc_length(uint32_t *desc);
+
+int cnstr_rng_jobdesc(uint32_t *desc, uint32_t state_handle,
+ uint32_t *add_inp, uint32_t add_ip_len,
+ uint8_t *out_data, uint32_t len);
+
+int cnstr_rng_instantiate_jobdesc(uint32_t *desc);
+
+/* Construct descriptor to generate hw key blob */
+int cnstr_hw_encap_blob_jobdesc(uint32_t *desc,
+ uint8_t *key_idnfr, uint32_t key_sz,
+ uint32_t key_class, uint8_t *plain_txt,
+ uint32_t in_sz, uint8_t *enc_blob,
+ uint32_t out_sz, uint32_t operation);
+
+void cnstr_hash_jobdesc(uint32_t *desc, uint8_t *msg, uint32_t msgsz,
+ uint8_t *digest);
+
+void cnstr_jobdesc_pkha_rsaexp(uint32_t *desc,
+ struct pk_in_params *pkin, uint8_t *out,
+ uint32_t out_siz);
+#endif
diff --git a/include/drivers/nxp/crypto/caam/jr_driver_config.h b/include/drivers/nxp/crypto/caam/jr_driver_config.h
new file mode 100644
index 0000000..1b3c447
--- /dev/null
+++ b/include/drivers/nxp/crypto/caam/jr_driver_config.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2017-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef _JR_DRIVER_CONFIG_H_
+#define _JR_DRIVER_CONFIG_H_
+
+/* Helper defines */
+
+ /* Define used for setting a flag on */
+#define ON 1
+ /* Define used for setting a flag off */
+#define OFF 0
+
+ /* SEC is configured to start work in polling mode, */
+#define SEC_STARTUP_POLLING_MODE 0
+/*
+ * SEC is configured to start work in interrupt mode,
+ * when configured for NAPI notification style.
+ */
+#define SEC_STARTUP_INTERRUPT_MODE 1
+
+/*
+ * SEC driver will use ONLY interrupts to receive notifications
+ * for processed packets from SEC engine hardware.
+ */
+#define SEC_NOTIFICATION_TYPE_IRQ 1
+/*
+ * SEC driver will use ONLY polling to receive notifications
+ * for processed packets from SEC engine hardware.
+ */
+#define SEC_NOTIFICATION_TYPE_POLL 2
+
+/*
+ * Determines how SEC user space driver will receive notifications
+ * for processed packets from SEC engine.
+ * Valid values are: #SEC_NOTIFICATION_TYPE_POLL, #SEC_NOTIFICATION_TYPE_IRQ
+ */
+#define SEC_NOTIFICATION_TYPE SEC_NOTIFICATION_TYPE_POLL
+
+ /* Maximum number of job rings supported by SEC hardware */
+#define MAX_SEC_JOB_RINGS 1
+
+/*
+ * Size of cryptographic context that is used directly in communicating
+ * with SEC device.
+ * SEC device works only with physical addresses. This is the maximum size
+ * for a SEC descriptor ( = 64 words).
+ */
+
+#define SEC_CRYPTO_DESCRIPTOR_SIZE 256
+
+/*
+ * Size of job descriptor submitted to SEC device for each packet to be
+ * processed.
+ * Job descriptor contains 3 DMA address pointers:
+ * - to shared descriptor, to input buffer and to output buffer.
+ * The job descriptor contains other SEC specific commands as well:
+ * - HEADER command, SEQ IN PTR command SEQ OUT PTR command and opaque
+ * data, each measuring 4 bytes.
+ * Job descriptor size, depending on physical address representation:
+ * - 32 bit - size is 28 bytes - cacheline-aligned size is 64 bytes
+ * - 36 bit - size is 40 bytes - cacheline-aligned size is 64 bytes
+ * @note: Job descriptor must be cacheline-aligned to ensure efficient memory
+ * access.
+ * @note: If other format is used for job descriptor, then the size must be
+ * revised.
+ */
+
+#define SEC_JOB_DESCRIPTOR_SIZE 64
+
+/*
+ * Size of one entry in the input ring of a job ring.
+ * Input ring contains pointers to job descriptors.
+ * The memory used for an input ring and output ring must be physically
+ * contiguous.
+ */
+
+#define SEC_JOB_INPUT_RING_ENTRY_SIZE sizeof(phys_addr_t)
+
+/*
+ * Size of one entry in the output ring of a job ring.
+ * Output ring entry is a pointer to a job descriptor followed by a 4 byte
+ * status word.
+ * The memory used for an input ring and output ring must be physically
+ * contiguous.
+ * @note If desired to use also the optional SEQ OUT indication in output
+ * ring entries, then 4 more bytes must be added to the size.
+ */
+
+#define SEC_JOB_OUTPUT_RING_ENTRY_SIZE (SEC_JOB_INPUT_RING_ENTRY_SIZE + 4)
+
+ /* DMA memory required for an input ring of a job ring. */
+#define SEC_DMA_MEM_INPUT_RING_SIZE \
+ ((SEC_JOB_INPUT_RING_ENTRY_SIZE) * (SEC_JOB_RING_SIZE))
+
+/*
+ * DMA memory required for an output ring of a job ring.
+ * Required extra 4 byte for status word per each entry.
+ */
+#define SEC_DMA_MEM_OUTPUT_RING_SIZE \
+ ((SEC_JOB_OUTPUT_RING_ENTRY_SIZE) * (SEC_JOB_RING_SIZE))
+
+ /* DMA memory required for descriptors of a job ring. */
+#define SEC_DMA_MEM_DESCRIPTORS \
+ ((SEC_CRYPTO_DESCRIPTOR_SIZE)*(SEC_JOB_RING_SIZE))
+
+ /* DMA memory required for a job ring, including both input output rings. */
+#define SEC_DMA_MEM_JOB_RING_SIZE \
+ ((SEC_DMA_MEM_INPUT_RING_SIZE) + \
+ (SEC_DMA_MEM_OUTPUT_RING_SIZE))
+
+/*
+ * When calling sec_init() UA will provide an area of virtual memory
+ * of size #SEC_DMA_MEMORY_SIZE to be used internally by the driver
+ * to allocate data (like SEC descriptors) that needs to be passed to
+ * SEC device in physical addressing and later on retrieved from SEC device.
+ * At initialization the UA provides specialized ptov/vtop functions/macros to
+ * translate addresses allocated from this memory area.
+ */
+#define SEC_DMA_MEMORY_SIZE \
+ ((SEC_DMA_MEM_JOB_RING_SIZE) * (MAX_SEC_JOB_RINGS))
+
+/*
+ * SEC DEVICE related configuration.
+
+ * Enable/Disable logging support at compile time.
+ * Valid values:
+ * ON - enable logging
+ * OFF - disable logging
+ * The messages are logged at stdout.
+ */
+
+#define SEC_DRIVER_LOGGING OFF
+
+/*
+ * Configure logging level at compile time.
+ * Valid values:
+ * SEC_DRIVER_LOG_ERROR - log only errors
+ * SEC_DRIVER_LOG_INFO - log errors and info messages
+ * SEC_DRIVER_LOG_DEBUG - log errors, info and debug messages
+ */
+
+#define SEC_DRIVER_LOGGING_LEVEL SEC_DRIVER_LOG_DEBUG
+
+/*
+ * SEC JOB RING related configuration.
+
+ * Configure the size of the JOB RING.
+ * The maximum size of the ring is hardware limited to 1024.
+ * However the number of packets in flight in a time interval of
+ * 1ms can be calculated
+ * from the traffic rate (Mbps) and packet size.
+ * Here it was considered a packet size of 40 bytes.
+ * @note Round up to nearest power of 2 for optimized update
+ * of producer/consumer indexes of each job ring
+ * \todo Should set to 750, according to the calculation above, but
+ * the JR size must be power of 2, thus the next closest value must
+ * be chosen (i.e. 512 since 1024 is not available)
+ * For firmware choose this to be 16
+ */
+
+#define SEC_JOB_RING_SIZE 16
+
+/*
+ * Interrupt coalescing related configuration.
+ * NOTE: SEC hardware enabled interrupt
+ * coalescing is not supported on SEC version 3.1!
+ * SEC version 4.4 has support for interrupt
+ * coalescing.
+ */
+
+#if SEC_NOTIFICATION_TYPE != SEC_NOTIFICATION_TYPE_POLL
+
+#define SEC_INT_COALESCING_ENABLE ON
+/*
+ * Interrupt Coalescing Descriptor Count Threshold.
+ * While interrupt coalescing is enabled (ICEN=1), this value determines
+ * how many Descriptors are completed before raising an interrupt.
+ * Valid values for this field are from 0 to 255.
+ * Note that a value of 1 functionally defeats the advantages of interrupt
+ * coalescing since the threshold value is reached each time that a
+ * Job Descriptor is completed. A value of 0 is treated in the same
+ * manner as a value of 1.
+ *
+ */
+#define SEC_INTERRUPT_COALESCING_DESCRIPTOR_COUNT_THRESH 10
+
+/*
+ * Interrupt Coalescing Timer Threshold.
+ * While interrupt coalescing is enabled (ICEN=1), this value determines the
+ * maximum amount of time after processing a Descriptor before raising an
+ * interrupt.
+ * The threshold value is represented in units equal to 64 CAAM interface
+ * clocks. Valid values for this field are from 1 to 65535.
+ * A value of 0 results in behavior identical to that when interrupt
+ * coalescing is disabled.
+ */
+#define SEC_INTERRUPT_COALESCING_TIMER_THRESH 100
+#endif /* SEC_NOTIFICATION_TYPE_POLL */
+
+#endif /* _JR_DRIVER_CONFIG_H_ */
diff --git a/include/drivers/nxp/crypto/caam/rsa.h b/include/drivers/nxp/crypto/caam/rsa.h
new file mode 100644
index 0000000..dd9ecdc
--- /dev/null
+++ b/include/drivers/nxp/crypto/caam/rsa.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2017-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef _RSA_H__
+#define _RSA_H__
+
+/* RSA key size defines */
+#define RSA_4K_KEY_SZ 4096
+#define RSA_4K_KEY_SZ_BYTES (RSA_4K_KEY_SZ/8)
+#define RSA_2K_KEY_SZ 2048
+#define RSA_2K_KEY_SZ_BYTES (RSA_2K_KEY_SZ/8)
+#define RSA_1K_KEY_SZ 1024
+#define RSA_1K_KEY_SZ_BYTES (RSA_1K_KEY_SZ/8)
+
+#define SHA256_BYTES (256/8)
+
+struct pk_in_params {
+ uint8_t *e;
+ uint32_t e_siz;
+ uint8_t *n;
+ uint32_t n_siz;
+ uint8_t *a;
+ uint32_t a_siz;
+ uint8_t *b;
+ uint32_t b_siz;
+};
+
+struct rsa_context {
+ struct pk_in_params pkin;
+};
+
+int rsa_verify_signature(void *hash_ptr, unsigned int hash_len,
+ void *sig_ptr, unsigned int sig_len,
+ void *pk_ptr, unsigned int pk_len);
+
+#endif
diff --git a/include/drivers/nxp/crypto/caam/sec_hw_specific.h b/include/drivers/nxp/crypto/caam/sec_hw_specific.h
new file mode 100644
index 0000000..9800793
--- /dev/null
+++ b/include/drivers/nxp/crypto/caam/sec_hw_specific.h
@@ -0,0 +1,503 @@
+/*
+ * Copyright 2017-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef _SEC_HW_SPECIFIC_H_
+#define _SEC_HW_SPECIFIC_H_
+
+#include "caam.h"
+#include "sec_jr_driver.h"
+
+ /* DEFINES AND MACROS */
+
+/* Used to retry resetting a job ring in SEC hardware. */
+#define SEC_TIMEOUT 100000
+
+/*
+ * Offset to the registers of a job ring.
+ *Is different for each job ring.
+ */
+#define CHAN_BASE(jr) ((phys_addr_t)(jr)->register_base_addr)
+
+#define unlikely(x) __builtin_expect(!!(x), 0)
+
+#define SEC_JOB_RING_IS_FULL(pi, ci, ring_max_size, ring_threshold) \
+ ((((pi) + 1 + ((ring_max_size) - (ring_threshold))) & \
+ (ring_max_size - 1)) == ((ci)))
+
+#define SEC_CIRCULAR_COUNTER(x, max) (((x) + 1) & (max - 1))
+
+ /* Struct representing various job ring registers */
+struct jobring_regs {
+#ifdef NXP_SEC_BE
+ unsigned int irba_h;
+ unsigned int irba_l;
+#else
+ unsigned int irba_l;
+ unsigned int irba_h;
+#endif
+ unsigned int rsvd1;
+ unsigned int irs;
+ unsigned int rsvd2;
+ unsigned int irsa;
+ unsigned int rsvd3;
+ unsigned int irja;
+#ifdef NXP_SEC_BE
+ unsigned int orba_h;
+ unsigned int orba_l;
+#else
+ unsigned int orba_l;
+ unsigned int orba_h;
+#endif
+ unsigned int rsvd4;
+ unsigned int ors;
+ unsigned int rsvd5;
+ unsigned int orjr;
+ unsigned int rsvd6;
+ unsigned int orsf;
+ unsigned int rsvd7;
+ unsigned int jrsta;
+ unsigned int rsvd8;
+ unsigned int jrint;
+ unsigned int jrcfg0;
+ unsigned int jrcfg1;
+ unsigned int rsvd9;
+ unsigned int irri;
+ unsigned int rsvd10;
+ unsigned int orwi;
+ unsigned int rsvd11;
+ unsigned int jrcr;
+};
+
+ /* Offsets representing common SEC Registers */
+#define SEC_REG_MCFGR_OFFSET 0x0004
+#define SEC_REG_SCFGR_OFFSET 0x000C
+#define SEC_REG_JR0ICIDR_MS_OFFSET 0x0010
+#define SEC_REG_JR0ICIDR_LS_OFFSET 0x0014
+#define SEC_REG_JR1ICIDR_MS_OFFSET 0x0018
+#define SEC_REG_JR1ICIDR_LS_OFFSET 0x001C
+#define SEC_REG_JR2ICIDR_MS_OFFSET 0x0020
+#define SEC_REG_JR2ICIDR_LS_OFFSET 0x0024
+#define SEC_REG_JR3ICIDR_MS_OFFSET 0x0028
+#define SEC_REG_JR3ICIDR_LS_OFFSET 0x002C
+#define SEC_REG_JRSTARTR_OFFSET 0x005C
+#define SEC_REG_CTPR_MS_OFFSET 0x0FA8
+
+ /* Offsets representing various RNG registers */
+#define RNG_REG_RTMCTL_OFFSET 0x0600
+#define RNG_REG_RTSDCTL_OFFSET 0x0610
+#define RNG_REG_RTFRQMIN_OFFSET 0x0618
+#define RNG_REG_RTFRQMAX_OFFSET 0x061C
+#define RNG_REG_RDSTA_OFFSET 0x06C0
+#define ALG_AAI_SH_SHIFT 4
+
+ /* SEC Registers Bitmasks */
+#define MCFGR_PS_SHIFT 16
+#define MCFGR_AWCACHE_SHIFT 8
+#define MCFGR_AWCACHE_MASK (0xF << MCFGR_AWCACHE_SHIFT)
+#define MCFGR_ARCACHE_SHIFT 12
+#define MCFGR_ARCACHE_MASK (0xF << MCFGR_ARCACHE_SHIFT)
+
+#define SCFGR_RNGSH0 0x00000200
+#define SCFGR_VIRT_EN 0x00008000
+
+#define JRICID_MS_LICID 0x80000000
+#define JRICID_MS_LAMTD 0x00020000
+#define JRICID_MS_AMTDT 0x00010000
+#define JRICID_MS_TZ 0x00008000
+#define JRICID_LS_SDID_MASK 0x00000FFF
+#define JRICID_LS_NSEQID_MASK 0x0FFF0000
+#define JRICID_LS_NSEQID_SHIFT 16
+#define JRICID_LS_SEQID_MASK 0x00000FFF
+
+#define JRSTARTR_STARTJR0 0x00000001
+#define JRSTARTR_STARTJR1 0x00000002
+#define JRSTARTR_STARTJR2 0x00000004
+#define JRSTARTR_STARTJR3 0x00000008
+
+#define CTPR_VIRT_EN_POR 0x00000002
+#define CTPR_VIRT_EN_INC 0x00000001
+
+ /* RNG RDSTA bitmask */
+#define RNG_STATE0_HANDLE_INSTANTIATED 0x00000001
+#define RTMCTL_PRGM 0x00010000 /* 1 -> program mode, 0 -> run mode */
+ /* use von Neumann data in both entropy shifter and statistical checker */
+#define RTMCTL_SAMP_MODE_VON_NEUMANN_ES_SC 0
+ /* use raw data in both entropy shifter and statistical checker */
+#define RTMCTL_SAMP_MODE_RAW_ES_SC 1
+ /* use von Neumann data in entropy shifter, raw data in statistical checker */
+#define RTMCTL_SAMP_MODE_VON_NEUMANN_ES_RAW_SC 2
+ /* invalid combination */
+#define RTMCTL_SAMP_MODE_INVALID 3
+#define RTSDCTL_ENT_DLY_MIN 3200
+#define RTSDCTL_ENT_DLY_MAX 12800
+#define RTSDCTL_ENT_DLY_SHIFT 16
+#define RTSDCTL_ENT_DLY_MASK (U(0xffff) << RTSDCTL_ENT_DLY_SHIFT)
+#define RTFRQMAX_DISABLE (1 << 20)
+
+ /* Constants for error handling on job ring */
+#define JR_REG_JRINT_ERR_TYPE_SHIFT 8
+#define JR_REG_JRINT_ERR_ORWI_SHIFT 16
+#define JR_REG_JRINIT_JRE_SHIFT 1
+
+#define JRINT_JRE (1 << JR_REG_JRINIT_JRE_SHIFT)
+#define JRINT_ERR_WRITE_STATUS (1 << JR_REG_JRINT_ERR_TYPE_SHIFT)
+#define JRINT_ERR_BAD_INPUT_BASE (3 << JR_REG_JRINT_ERR_TYPE_SHIFT)
+#define JRINT_ERR_BAD_OUTPUT_BASE (4 << JR_REG_JRINT_ERR_TYPE_SHIFT)
+#define JRINT_ERR_WRITE_2_IRBA (5 << JR_REG_JRINT_ERR_TYPE_SHIFT)
+#define JRINT_ERR_WRITE_2_ORBA (6 << JR_REG_JRINT_ERR_TYPE_SHIFT)
+#define JRINT_ERR_RES_B4_HALT (7 << JR_REG_JRINT_ERR_TYPE_SHIFT)
+#define JRINT_ERR_REM_TOO_MANY (8 << JR_REG_JRINT_ERR_TYPE_SHIFT)
+#define JRINT_ERR_ADD_TOO_MANY (9 << JR_REG_JRINT_ERR_TYPE_SHIFT)
+#define JRINT_ERR_HALT_MASK 0x0C
+#define JRINT_ERR_HALT_INPROGRESS 0x04
+#define JRINT_ERR_HALT_COMPLETE 0x08
+
+#define JR_REG_JRCR_VAL_RESET 0x00000001
+
+#define JR_REG_JRCFG_LO_ICTT_SHIFT 0x10
+#define JR_REG_JRCFG_LO_ICDCT_SHIFT 0x08
+#define JR_REG_JRCFG_LO_ICEN_EN 0x02
+#define JR_REG_JRCFG_LO_IMSK_EN 0x01
+
+ /* Constants for Descriptor Processing errors */
+#define SEC_HW_ERR_SSRC_NO_SRC 0x00
+#define SEC_HW_ERR_SSRC_CCB_ERR 0x02
+#define SEC_HW_ERR_SSRC_JMP_HALT_U 0x03
+#define SEC_HW_ERR_SSRC_DECO 0x04
+#define SEC_HW_ERR_SSRC_JR 0x06
+#define SEC_HW_ERR_SSRC_JMP_HALT_COND 0x07
+
+#define SEC_HW_ERR_DECO_HFN_THRESHOLD 0xF1
+#define SEC_HW_ERR_CCB_ICV_CHECK_FAIL 0x0A
+
+ /* Macros for extracting error codes for the job ring */
+
+#define JR_REG_JRINT_ERR_TYPE_EXTRACT(value) \
+ ((value) & 0x00000F00)
+
+#define JR_REG_JRINT_ERR_ORWI_EXTRACT(value) \
+ (((value) & 0x3FFF0000) >> \
+ JR_REG_JRINT_ERR_ORWI_SHIFT)
+
+#define JR_REG_JRINT_JRE_EXTRACT(value) \
+ ((value) & JRINT_JRE)
+
+ /* Macros for manipulating JR registers */
+typedef struct {
+#ifdef NXP_SEC_BE
+ uint32_t high;
+ uint32_t low;
+#else
+ uint32_t low;
+ uint32_t high;
+#endif
+} ptr_addr_t;
+
+#if defined(CONFIG_PHYS_64BIT)
+#define sec_read_addr(a) sec_in64((a))
+#define sec_write_addr(a, v) sec_out64((a), (v))
+#else
+#define sec_read_addr(a) sec_in32((a))
+#define sec_write_addr(a, v) sec_out32((a), (v))
+#endif
+
+#define JR_REG(name, jr) (CHAN_BASE(jr) + JR_REG_##name##_OFFSET)
+#define JR_REG_LO(name, jr) (CHAN_BASE(jr) + JR_REG_##name##_OFFSET_LO)
+
+#define GET_JR_REG(name, jr) (sec_in32(JR_REG(name, (jr))))
+#define GET_JR_REG_LO(name, jr) (sec_in32(JR_REG_LO(name, (jr))))
+
+#define SET_JR_REG(name, jr, val) \
+ (sec_out32(JR_REG(name, (jr)), (val)))
+
+#define SET_JR_REG_LO(name, jr, val) \
+ (sec_out32(JR_REG_LO(name, (jr)), (val)))
+
+ /* STRUCTURES AND OTHER TYPEDEFS */
+ /* Lists the possible states for a job ring. */
+typedef enum sec_job_ring_state_e {
+ SEC_JOB_RING_STATE_STARTED, /* Job ring is initialized */
+ SEC_JOB_RING_STATE_RESET, /* Job ring reset is in progres */
+} sec_job_ring_state_t;
+
+struct sec_job_ring_t {
+ /*
+ * Consumer index for job ring (jobs array).
+ * @note: cidx and pidx are accessed from
+ * different threads.
+ * Place the cidx and pidx inside the structure
+ * so that they lay on different cachelines, to
+ * avoid false sharing between threads when the
+ * threads run on different cores!
+ */
+ uint32_t cidx;
+
+ /* Producer index for job ring (jobs array) */
+ uint32_t pidx;
+
+ /* Ring of input descriptors. Size of array is power of 2 to allow
+ * fast update of producer/consumer indexes with bitwise operations.
+ */
+ phys_addr_t *input_ring;
+
+ /* Ring of output descriptors. */
+ struct sec_outring_entry *output_ring;
+
+ /* The file descriptor used for polling for interrupts notifications */
+ uint32_t irq_fd;
+
+ /* Model used by SEC Driver to receive notifications from SEC.
+ * Can be either of the three:
+ * #SEC_NOTIFICATION_TYPE_IRQ or
+ * #SEC_NOTIFICATION_TYPE_POLL
+ */
+ uint32_t jr_mode;
+ /* Base address for SEC's register memory for this job ring. */
+ void *register_base_addr;
+ /* notifies if coelescing is enabled for the job ring */
+ uint8_t coalescing_en;
+ /* The state of this job ring */
+ sec_job_ring_state_t jr_state;
+};
+
+ /* Forward structure declaration */
+typedef struct sec_job_ring_t sec_job_ring_t;
+
+struct sec_outring_entry {
+ phys_addr_t desc; /* Pointer to completed descriptor */
+ uint32_t status; /* Status for completed descriptor */
+} __packed;
+
+ /* Lists the states possible for the SEC user space driver. */
+typedef enum sec_driver_state_e {
+ SEC_DRIVER_STATE_IDLE, /*< Driver not initialized */
+ SEC_DRIVER_STATE_STARTED, /*< Driver initialized and */
+ SEC_DRIVER_STATE_RELEASE, /*< Driver release is in progress */
+} sec_driver_state_t;
+
+ /* Union describing the possible error codes that */
+ /* can be set in the descriptor status word */
+
+union hw_error_code {
+ uint32_t error;
+ union {
+ struct {
+ uint32_t ssrc:4;
+ uint32_t ssed_val:28;
+ } __packed value;
+ struct {
+ uint32_t ssrc:4;
+ uint32_t res:28;
+ } __packed no_status_src;
+ struct {
+ uint32_t ssrc:4;
+ uint32_t jmp:1;
+ uint32_t res:11;
+ uint32_t desc_idx:8;
+ uint32_t cha_id:4;
+ uint32_t err_id:4;
+ } __packed ccb_status_src;
+ struct {
+ uint32_t ssrc:4;
+ uint32_t jmp:1;
+ uint32_t res:11;
+ uint32_t desc_idx:8;
+ uint32_t offset:8;
+ } __packed jmp_halt_user_src;
+ struct {
+ uint32_t ssrc:4;
+ uint32_t jmp:1;
+ uint32_t res:11;
+ uint32_t desc_idx:8;
+ uint32_t desc_err:8;
+ } __packed deco_src;
+ struct {
+ uint32_t ssrc:4;
+ uint32_t res:17;
+ uint32_t naddr:3;
+ uint32_t desc_err:8;
+ } __packed jr_src;
+ struct {
+ uint32_t ssrc:4;
+ uint32_t jmp:1;
+ uint32_t res:11;
+ uint32_t desc_idx:8;
+ uint32_t cond:8;
+ } __packed jmp_halt_cond_src;
+ } __packed error_desc;
+} __packed;
+
+ /* FUNCTION PROTOTYPES */
+
+/*
+ * @brief Initialize a job ring/channel in SEC device.
+ * Write configuration register/s to properly initialize a job ring.
+ *
+ * @param [in] job_ring The job ring
+ *
+ * @retval 0 for success
+ * @retval other for error
+ */
+int hw_reset_job_ring(sec_job_ring_t *job_ring);
+
+/*
+ * @brief Reset a job ring/channel in SEC device.
+ * Write configuration register/s to reset a job ring.
+ *
+ * @param [in] job_ring The job ring
+ *
+ * @retval 0 for success
+ * @retval -1 in case job ring reset failed
+ */
+int hw_shutdown_job_ring(sec_job_ring_t *job_ring);
+
+/*
+ * @brief Handle a job ring/channel error in SEC device.
+ * Identify the error type and clear error bits if required.
+ *
+ * @param [in] job_ring The job ring
+ * @param [in] sec_error_code error code as first read from SEC engine
+ */
+
+void hw_handle_job_ring_error(sec_job_ring_t *job_ring,
+ uint32_t sec_error_code);
+/*
+ * @brief Handle a job ring error in the device.
+ * Identify the error type and printout a explanatory
+ * messages.
+ *
+ * @param [in] job_ring The job ring
+ *
+ */
+
+int hw_job_ring_error(sec_job_ring_t *job_ring);
+
+/* @brief Set interrupt coalescing parameters on the Job Ring.
+ * @param [in] job_ring The job ring
+ * @param [in] irq_coalesing_timer
+ * Interrupt coalescing timer threshold.
+ * This value determines the maximum
+ * amount of time after processing a descriptor
+ * before raising an interrupt.
+ * @param [in] irq_coalescing_count
+ * Interrupt coalescing count threshold.
+ * This value determines how many descriptors
+ * are completed before raising an interrupt.
+ */
+
+int hw_job_ring_set_coalescing_param(sec_job_ring_t *job_ring,
+ uint16_t irq_coalescing_timer,
+ uint8_t irq_coalescing_count);
+
+/* @brief Enable interrupt coalescing on a job ring
+ * @param [in] job_ring The job ring
+ */
+
+int hw_job_ring_enable_coalescing(sec_job_ring_t *job_ring);
+
+/*
+ * @brief Disable interrupt coalescing on a job ring
+ * @param [in] job_ring The job ring
+ */
+
+int hw_job_ring_disable_coalescing(sec_job_ring_t *job_ring);
+
+/*
+ * @brief Poll the HW for already processed jobs in the JR
+ * and notify the available jobs to UA.
+ *
+ * @param [in] job_ring The job ring to poll.
+ * @param [in] limit The maximum number of jobs to notify.
+ * If set to negative value, all available
+ * jobs are notified.
+ *
+ * @retval >=0 for No of jobs notified to UA.
+ * @retval -1 for error
+ */
+
+int hw_poll_job_ring(struct sec_job_ring_t *job_ring, int32_t limit);
+
+/* @brief Poll the HW for already processed jobs in the JR
+ * and silently discard the available jobs or notify them to UA
+ * with indicated error code.
+
+ * @param [in,out] job_ring The job ring to poll.
+ * @param [in] do_notify Can be #TRUE or #FALSE.
+ * Indicates if descriptors to be discarded
+ * or notified to UA with given error_code.
+ * @param [in] error_code The detailed SEC error code.
+ * @param [out] notified_descs Number of notified descriptors.
+ * Can be NULL if do_notify is #FALSE
+ */
+void hw_flush_job_ring(struct sec_job_ring_t *job_ring,
+ uint32_t do_notify,
+ uint32_t error_code, uint32_t *notified_descs);
+
+/*
+ * @brief Flush job rings of any processed descs.
+ * The processed descs are silently dropped,
+ * WITHOUT being notified to UA.
+ */
+void flush_job_rings(void);
+
+/*
+ * @brief Handle desc that generated error in SEC engine.
+ * Identify the exact type of error and handle the error.
+ * Depending on the error type, the job ring could be reset.
+ * All descs that are submitted for processing on this job ring
+ * are notified to User Application with error status and detailed error code.
+
+ * @param [in] job_ring Job ring
+ * @param [in] sec_error_code Error code read from job ring's Channel
+ * Status Register
+ * @param [out] notified_descs Number of notified descs. Can be NULL if
+ * do_notify is #FALSE
+ * @param [out] do_driver_shutdown If set to #TRUE, then UA is returned code
+ * #SEC_PROCESSING_ERROR
+ * which is indication that UA must call
+ * sec_release() after this.
+ */
+void sec_handle_desc_error(struct sec_job_ring_t *job_ring,
+ uint32_t sec_error_code,
+ uint32_t *notified_descs,
+ uint32_t *do_driver_shutdown);
+
+/*
+ * @brief Release the software and hardware resources tied to a job ring.
+ * @param [in] job_ring The job ring
+ * @retval 0 for success
+ * @retval -1 for error
+ */
+int shutdown_job_ring(struct sec_job_ring_t *job_ring);
+
+/*
+ * @brief Enable irqs on associated job ring.
+ * @param [in] job_ring The job ring
+ * @retval 0 for success
+ * @retval -1 for error
+ */
+int jr_enable_irqs(struct sec_job_ring_t *job_ring);
+
+/*
+ * @brief Disable irqs on associated job ring.
+ * @param [in] job_ring The job ring
+ * @retval 0 for success
+ * @retval -1 for error
+ */
+int jr_disable_irqs(struct sec_job_ring_t *job_ring);
+
+ /*
+ * IRJA - Input Ring Jobs Added Register shows
+ * how many new jobs were added to the Input Ring.
+ */
+static inline void hw_enqueue_desc_on_job_ring(struct jobring_regs *regs,
+ int num)
+{
+ sec_out32(&regs->irja, num);
+}
+
+#endif /* _SEC_HW_SPECIFIC_H_ */
diff --git a/include/drivers/nxp/crypto/caam/sec_jr_driver.h b/include/drivers/nxp/crypto/caam/sec_jr_driver.h
new file mode 100644
index 0000000..57e0fa0
--- /dev/null
+++ b/include/drivers/nxp/crypto/caam/sec_jr_driver.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2017-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef _JR_DRIVER_H_
+#define _JR_DRIVER_H_
+
+#include "jr_driver_config.h"
+
+/* The maximum size of a SEC descriptor, in WORDs (32 bits). */
+#define MAX_DESC_SIZE_WORDS 64
+
+#define CAAM_TIMEOUT 200000 /* ms */
+
+/* Return codes for JR user space driver APIs */
+typedef enum sec_return_code_e {
+ SEC_SUCCESS = 0,
+ SEC_INVALID_INPUT_PARAM,
+ SEC_OUT_OF_MEMORY,
+ SEC_DESCRIPTOR_IN_FLIGHT,
+ SEC_LAST_DESCRIPTOR_IN_FLIGHT,
+ SEC_PROCESSING_ERROR,
+ SEC_DESC_PROCESSING_ERROR,
+ SEC_JR_IS_FULL,
+ SEC_DRIVER_RELEASE_IN_PROGRESS,
+ SEC_DRIVER_ALREADY_INITIALIZED,
+ SEC_DRIVER_NOT_INITIALIZED,
+ SEC_JOB_RING_RESET_IN_PROGRESS,
+ SEC_RESET_ENGINE_FAILED,
+ SEC_ENABLE_IRQS_FAILED,
+ SEC_DISABLE_IRQS_FAILED,
+ SEC_RETURN_CODE_MAX_VALUE,
+} sec_return_code_t;
+
+/* STRUCTURES AND OTHER TYPEDEFS */
+
+/*
+ * @brief Function called by JR User Space driver to notify every processed
+ * descriptor.
+ *
+ * Callback provided by the User Application.
+ * Callback is invoked by JR User Space driver for each descriptor processed by
+ * SEC
+ * @param [in] status Status word indicating processing result for
+ * this descriptor.
+ * @param [in] arg Opaque data passed by User Application
+ * It is opaque from JR driver's point of view.
+ * @param [in] job_ring The job ring handle on which the processed
+ * descriptor word was enqueued
+ */
+typedef void (*user_callback) (uint32_t *desc, uint32_t status,
+ void *arg, void *job_ring);
+
+/*
+ * Structure encompassing a job descriptor which is to be processed
+ * by SEC. User should also initialise this structure with the callback
+ * function pointer which will be called by driver after recieving proccessed
+ * descriptor from SEC. User data is also passed in this data structure which
+ * will be sent as an argument to the user callback function.
+ */
+struct job_descriptor {
+ uint32_t desc[MAX_DESC_SIZE_WORDS];
+ void *arg;
+ user_callback callback;
+};
+
+/*
+ * @brief Initialize the JR User Space driver.
+ * This function will handle initialization of sec library
+ * along with registering platform specific callbacks,
+ * as well as local data initialization.
+ * Call once during application startup.
+ * @note Global SEC initialization is done in SEC kernel driver.
+ * @note The hardware IDs of the initialized Job Rings are opaque to the UA.
+ * The exact Job Rings used by this library are decided between SEC user
+ * space driver and SEC kernel driver. A static partitioning of Job Rings is
+ * assumed, configured in DTS(device tree specification) file.
+ * @param [in] platform_cb Registering the platform specific
+ * callbacks with driver
+ * @retval ::0 for successful execution
+ * @retval ::-1 failure
+ */
+int sec_jr_lib_init(void);
+
+/*
+ * @brief Initialize the software and hardware resources tied to a job ring.
+ * @param [in] jr_mode; Model to be used by SEC Driver to receive
+ * notifications from SEC. Can be either
+ * SEC_NOTIFICATION_TYPE_IRQ or
+ * SEC_NOTIFICATION_TYPE_POLL
+ * @param [in] irq_coalescing_timer This value determines the maximum
+ * amount of time after processing a
+ * descriptor before raising an interrupt.
+ * @param [in] irq_coalescing_count This value determines how many
+ * descriptors are completed before
+ * raising an interrupt.
+ * @param [in] reg_base_addr The job ring base address register
+ * @param [in] irq_id The job ring interrupt identification number.
+ * @retval job_ring_handle for successful job ring configuration
+ * @retval NULL on error
+ */
+void *init_job_ring(uint8_t jr_mode,
+ uint16_t irq_coalescing_timer,
+ uint8_t irq_coalescing_count,
+ void *reg_base_addr, uint32_t irq_id);
+
+/*
+ * @brief Release the resources used by the JR User Space driver.
+ * Reset and release SEC's job rings indicated by the User Application at
+ * init_job_ring() and free any memory allocated internally.
+ * Call once during application tear down.
+ * @note In case there are any descriptors in-flight (descriptors received by
+ * JR driver for processing and for which no response was yet provided to UA),
+ * the descriptors are discarded without any notifications to User Application.
+ * @retval ::0 is returned for a successful execution
+ * @retval ::-1 is returned if JR driver release is in progress
+ */
+int sec_release(void);
+
+/*
+ * @brief Submit a descriptor for SEC processing.
+ * This function creates a "job" which is meant to instruct SEC HW
+ * to perform the processing on the input buffer. The "job" is enqueued
+ * in the Job Ring associated. The function will return after the "job"
+ * enqueue is finished. The function will not wait for SEC to
+ * start or/and finish the "job" processing.
+ * After the processing is finished the SEC HW writes the processing result
+ * to the provided output buffer.
+ * The Caller must poll JR driver using jr_dequeue()
+ * to receive notifications of the processing completion
+ * status. The notifications are received by caller by means of callback
+ * (see ::user_callback).
+ * @param [in] job_ring_handle The handle of the job ring on which
+ * descriptor is to be enqueued
+ * @param [in] job_descriptor The job descriptor structure of type
+ * struct job_descriptor. This structure
+ * should be filled with job descriptor along
+ * with callback function to be called after
+ * processing of descriptor and some
+ * opaque data passed to be passed to the
+ * callback function
+ *
+ * @retval ::0 is returned for successful execution
+ * @retval ::-1 is returned if there is some enqueue failure
+ */
+int enq_jr_desc(void *job_ring_handle, struct job_descriptor *jobdescr);
+
+/*
+ * @brief Polls for available descriptors processed by SEC on a specific
+ * Job Ring
+ * This function polls the SEC Job Rings and delivers processed descriptors
+ * Each processed descriptor has a user_callback registered.
+ * This user_callback is invoked for each processed descriptor.
+ * The polling is stopped when "limit" descriptors are notified or when
+ * there are no more descriptors to notify.
+ * @note The dequeue_jr() API cannot be called from within a user_callback
+ * function
+ * @param [in] job_ring_handle The Job Ring handle.
+ * @param [in] limit This value represents the maximum number
+ * of processed descriptors that can be
+ * notified API call on this Job Ring.
+ * Note that fewer descriptors may be notified
+ * if enough processed descriptors are not
+ * available.
+ * If limit has a negative value, then all
+ * ready descriptors will be notified.
+ *
+ * @retval :: >=0 is returned where retval is the total
+ * Number of descriptors notified
+ * during this function call.
+ * @retval :: -1 is returned in case of some error
+ */
+int dequeue_jr(void *job_ring_handle, int32_t limit);
+
+#endif /* _JR_DRIVER_H_ */
diff --git a/include/drivers/nxp/csu/csu.h b/include/drivers/nxp/csu/csu.h
new file mode 100644
index 0000000..83f1834
--- /dev/null
+++ b/include/drivers/nxp/csu/csu.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef CSU_H
+#define CSU_H
+
+#define CSU_SEC_ACCESS_REG_OFFSET (0x0021CU)
+/* Bit mask */
+#define TZASC_BYPASS_MUX_DISABLE (0x4U)
+
+/* Macros defining access permissions to configure
+ * the regions controlled by Central Security Unit.
+ */
+enum csu_cslx_access {
+ CSU_NS_SUP_R = (0x8U),
+ CSU_NS_SUP_W = (0x80U),
+ CSU_NS_SUP_RW = (0x88U),
+ CSU_NS_USER_R = (0x4U),
+ CSU_NS_USER_W = (0x40U),
+ CSU_NS_USER_RW = (0x44U),
+ CSU_S_SUP_R = (0x2U),
+ CSU_S_SUP_W = (0x20U),
+ CSU_S_SUP_RW = (0x22U),
+ CSU_S_USER_R = (0x1U),
+ CSU_S_USER_W = (0x10U),
+ CSU_S_USER_RW = (0x11U),
+ CSU_ALL_RW = (0xffU),
+};
+
+struct csu_ns_dev_st {
+ uintptr_t ind;
+ uint32_t val;
+};
+
+void enable_layerscape_ns_access(struct csu_ns_dev_st *csu_ns_dev,
+ uint32_t num, uintptr_t nxp_csu_addr);
+
+#endif
diff --git a/include/drivers/nxp/dcfg/dcfg.h b/include/drivers/nxp/dcfg/dcfg.h
new file mode 100644
index 0000000..cf29b12
--- /dev/null
+++ b/include/drivers/nxp/dcfg/dcfg.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef DCFG_H
+#define DCFG_H
+
+#include <endian.h>
+
+#if defined(CONFIG_CHASSIS_2)
+#include <dcfg_lsch2.h>
+#elif defined(CONFIG_CHASSIS_3_2) || defined(CONFIG_CHASSIS_3)
+#include <dcfg_lsch3.h>
+#endif
+
+#ifdef NXP_GUR_BE
+#define gur_in32(a) bswap32(mmio_read_32((uintptr_t)(a)))
+#define gur_out32(a, v) mmio_write_32((uintptr_t)(a), bswap32(v))
+#elif defined(NXP_GUR_LE)
+#define gur_in32(a) mmio_read_32((uintptr_t)(a))
+#define gur_out32(a, v) mmio_write_32((uintptr_t)(a), v)
+#else
+#error Please define CCSR GUR register endianness
+#endif
+
+typedef struct {
+ union {
+ uint32_t val;
+ struct {
+ uint32_t min_ver:4;
+ uint32_t maj_ver:4;
+#if defined(CONFIG_CHASSIS_3) || defined(CONFIG_CHASSIS_3_2)
+ uint32_t personality:6;
+ uint32_t rsv1:2;
+#elif defined(CONFIG_CHASSIS_2)
+ uint32_t personality:8;
+
+#endif
+#if defined(CONFIG_CHASSIS_3) || defined(CONFIG_CHASSIS_3_2)
+ uint32_t dev_id:6;
+ uint32_t rsv2:2;
+ uint32_t family:4;
+#elif defined(CONFIG_CHASSIS_2)
+ uint32_t dev_id:12;
+#endif
+ uint32_t mfr_id;
+ } __packed bf;
+ struct {
+ uint32_t maj_min:8;
+ uint32_t version; /* SoC version without major and minor info */
+ } __packed bf_ver;
+ } __packed svr_reg;
+ bool sec_enabled;
+ bool is_populated;
+} soc_info_t;
+
+typedef struct {
+ bool is_populated;
+ uint8_t ocram_present;
+ uint8_t ddrc1_present;
+#if defined(CONFIG_CHASSIS_3) || defined(CONFIG_CHASSIS_3_2)
+ uint8_t ddrc2_present;
+#endif
+} devdisr5_info_t;
+
+typedef struct {
+ uint32_t porsr1;
+ uintptr_t g_nxp_dcfg_addr;
+ unsigned long nxp_sysclk_freq;
+ unsigned long nxp_ddrclk_freq;
+ unsigned int nxp_plat_clk_divider;
+} dcfg_init_info_t;
+
+
+struct sysinfo {
+ unsigned long freq_platform;
+ unsigned long freq_ddr_pll0;
+ unsigned long freq_ddr_pll1;
+};
+
+int get_clocks(struct sysinfo *sys);
+
+/* Read the PORSR1 register */
+uint32_t read_reg_porsr1(void);
+
+/*******************************************************************************
+ * Returns true if secur eboot is enabled on board
+ * mode = 0 (development mode - sb_en = 1)
+ * mode = 1 (production mode - ITS = 1)
+ ******************************************************************************/
+bool check_boot_mode_secure(uint32_t *mode);
+
+const soc_info_t *get_soc_info();
+const devdisr5_info_t *get_devdisr5_info();
+
+void dcfg_init(dcfg_init_info_t *dcfg_init_data);
+bool is_sec_enabled(void);
+
+void error_handler(int error_code);
+#endif /* DCFG_H */
diff --git a/include/drivers/nxp/dcfg/dcfg_lsch2.h b/include/drivers/nxp/dcfg/dcfg_lsch2.h
new file mode 100644
index 0000000..882ba5a
--- /dev/null
+++ b/include/drivers/nxp/dcfg/dcfg_lsch2.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2020-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef DCFG_LSCH2_H
+#define DCFG_LSCH2_H
+
+/* dcfg block register offsets and bitfields */
+#define DCFG_PORSR1_OFFSET 0x00
+#define DCFG_DEVDISR1_OFFSET 0x070
+#define DCFG_DEVDISR2_OFFSET 0x074
+#define DCFG_DEVDISR3_OFFSET 0x078
+#define DCFG_DEVDISR4_OFFSET 0x07C
+#define DCFG_DEVDISR5_OFFSET 0x080
+#define DCFG_COREDISR_OFFSET 0x094
+#define RCWSR0_OFFSET 0x100
+#define RCWSR5_OFFSET 0x118
+#define DCFG_BOOTLOCPTRL_OFFSET 0x400
+#define DCFG_BOOTLOCPTRH_OFFSET 0x404
+#define DCFG_COREDISABLEDSR_OFFSET 0x990
+#define DCFG_SCRATCH4_OFFSET 0x20C
+#define DCFG_SVR_OFFSET 0x0A4
+#define DCFG_BRR_OFFSET 0x0E4
+
+#define DCFG_RSTCR_OFFSET 0x0B0
+#define RSTCR_RESET_REQ 0x2
+
+#define DCFG_RSTRQSR1_OFFSET 0x0C8
+#define DCFG_RSTRQMR1_OFFSET 0x0C0
+
+/* PORSR1 bit mask */
+#define PORSR1_RCW_MASK 0xff800000
+#define PORSR1_RCW_SHIFT 23
+
+/* DCFG DCSR Macros */
+#define DCFG_DCSR_PORCR1_OFFSET 0x0
+
+#define SVR_MFR_ID_MASK 0xF0000000
+#define SVR_MFR_ID_SHIFT 28
+#define SVR_DEV_ID_MASK 0xFFF0000
+#define SVR_DEV_ID_SHIFT 16
+#define SVR_PERSONALITY_MASK 0xFF00
+#define SVR_PERSONALITY_SHIFT 8
+#define SVR_SEC_MASK 0x100
+#define SVR_SEC_SHIFT 8
+#define SVR_MAJ_VER_MASK 0xF0
+#define SVR_MAJ_VER_SHIFT 4
+#define SVR_MIN_VER_MASK 0xF
+#define SVR_MINOR_VER_0 0x00
+#define SVR_MINOR_VER_1 0x01
+
+#define DISR5_DDRC1_MASK 0x1
+#define DISR5_OCRAM_MASK 0x40
+
+/* DCFG regsiters bit masks */
+#define RCWSR0_SYS_PLL_RAT_SHIFT 25
+#define RCWSR0_SYS_PLL_RAT_MASK 0x1f
+#define RCWSR0_MEM_PLL_RAT_SHIFT 16
+#define RCWSR0_MEM_PLL_RAT_MASK 0x3f
+#define RCWSR0_MEM2_PLL_RAT_SHIFT 18
+#define RCWSR0_MEM2_PLL_RAT_MASK 0x3f
+
+#define RCWSR_SB_EN_OFFSET RCWSR5_OFFSET
+#define RCWSR_SBEN_MASK 0x1
+#define RCWSR_SBEN_SHIFT 21
+
+/* RCW SRC NAND */
+#define RCW_SRC_NAND_MASK (0x100)
+#define RCW_SRC_NAND_VAL (0x100)
+#define NAND_RESERVED_MASK (0xFC)
+#define NAND_RESERVED_1 (0x0)
+#define NAND_RESERVED_2 (0x80)
+
+/* RCW SRC NOR */
+#define RCW_SRC_NOR_MASK (0x1F0)
+#define NOR_8B_VAL (0x10)
+#define NOR_16B_VAL (0x20)
+#define SD_VAL (0x40)
+#define QSPI_VAL1 (0x44)
+#define QSPI_VAL2 (0x45)
+
+#endif /* DCFG_LSCH2_H */
diff --git a/include/drivers/nxp/dcfg/dcfg_lsch3.h b/include/drivers/nxp/dcfg/dcfg_lsch3.h
new file mode 100644
index 0000000..cde86fe
--- /dev/null
+++ b/include/drivers/nxp/dcfg/dcfg_lsch3.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2020-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef DCFG_LSCH3_H
+#define DCFG_LSCH3_H
+
+/* dcfg block register offsets and bitfields */
+#define DCFG_PORSR1_OFFSET 0x00
+
+#define DCFG_DEVDISR1_OFFSET 0x70
+#define DCFG_DEVDISR1_SEC (1 << 22)
+
+#define DCFG_DEVDISR2_OFFSET 0x74
+
+#define DCFG_DEVDISR3_OFFSET 0x78
+#define DCFG_DEVDISR3_QBMAIN (1 << 12)
+
+#define DCFG_DEVDISR4_OFFSET 0x7C
+#define DCFG_DEVDISR4_SPI_QSPI (1 << 4 | 1 << 5)
+
+#define DCFG_DEVDISR5_OFFSET 0x80
+#define DISR5_DDRC1_MASK 0x1
+#define DISR5_DDRC2_MASK 0x2
+#define DISR5_OCRAM_MASK 0x1000
+#define DEVDISR5_MASK_ALL_MEM 0x00001003
+#define DEVDISR5_MASK_DDR 0x00000003
+#define DEVDISR5_MASK_DBG 0x00000400
+
+#define DCFG_DEVDISR6_OFFSET 0x84
+//#define DEVDISR6_MASK 0x00000001
+
+#define DCFG_COREDISR_OFFSET 0x94
+
+#define DCFG_SVR_OFFSET 0x0A4
+#define SVR_MFR_ID_MASK 0xF0000000
+#define SVR_MFR_ID_SHIFT 28
+#define SVR_FAMILY_MASK 0xF000000
+#define SVR_FAMILY_SHIFT 24
+#define SVR_DEV_ID_MASK 0x3F0000
+#define SVR_DEV_ID_SHIFT 16
+#define SVR_PERSONALITY_MASK 0x3E00
+#define SVR_PERSONALITY_SHIFT 9
+#define SVR_SEC_MASK 0x100
+#define SVR_SEC_SHIFT 8
+#define SVR_MAJ_VER_MASK 0xF0
+#define SVR_MAJ_VER_SHIFT 4
+#define SVR_MIN_VER_MASK 0xF
+
+#define RCWSR0_OFFSET 0x100
+#define RCWSR0_SYS_PLL_RAT_SHIFT 2
+#define RCWSR0_SYS_PLL_RAT_MASK 0x1f
+#define RCWSR0_MEM_PLL_RAT_SHIFT 10
+#define RCWSR0_MEM_PLL_RAT_MASK 0x3f
+#define RCWSR0_MEM2_PLL_RAT_SHIFT 18
+#define RCWSR0_MEM2_PLL_RAT_MASK 0x3f
+
+#define RCWSR5_OFFSET 0x110
+#define RCWSR9_OFFSET 0x120
+#define RCWSR_SB_EN_OFFSET RCWSR9_OFFSET
+#define RCWSR_SBEN_MASK 0x1
+#define RCWSR_SBEN_SHIFT 10
+
+#define RCW_SR27_OFFSET 0x168
+/* DCFG register to dump error code */
+#define DCFG_SCRATCH4_OFFSET 0x20C
+#define DCFG_SCRATCHRW5_OFFSET 0x210
+#define DCFG_SCRATCHRW6_OFFSET 0x214
+#define DCFG_SCRATCHRW7_OFFSET 0x218
+#define DCFG_BOOTLOCPTRL_OFFSET 0x400
+#define DCFG_BOOTLOCPTRH_OFFSET 0x404
+#define DCFG_COREDISABLEDSR_OFFSET 0x990
+
+/* Reset module bit field */
+#define RSTCR_RESET_REQ 0x2
+
+#endif /* DCFG_LSCH3_H */
diff --git a/include/drivers/nxp/dcfg/scfg.h b/include/drivers/nxp/dcfg/scfg.h
new file mode 100644
index 0000000..8067de1
--- /dev/null
+++ b/include/drivers/nxp/dcfg/scfg.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2020-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef SCFG_H
+#define SCFG_H
+
+#ifdef CONFIG_CHASSIS_2
+
+/* SCFG register offsets */
+#define SCFG_CORE0_SFT_RST_OFFSET 0x0130
+#define SCFG_SNPCNFGCR_OFFSET 0x01A4
+#define SCFG_CORESRENCR_OFFSET 0x0204
+#define SCFG_RVBAR0_0_OFFSET 0x0220
+#define SCFG_RVBAR0_1_OFFSET 0x0224
+#define SCFG_COREBCR_OFFSET 0x0680
+#define SCFG_RETREQCR_OFFSET 0x0424
+
+#define SCFG_COREPMCR_OFFSET 0x042C
+#define COREPMCR_WFIL2 0x1
+
+#define SCFG_GIC400_ADDR_ALIGN_OFFSET 0x0188
+#define SCFG_BOOTLOCPTRH_OFFSET 0x0600
+#define SCFG_BOOTLOCPTRL_OFFSET 0x0604
+#define SCFG_SCRATCHRW2_OFFSET 0x0608
+#define SCFG_SCRATCHRW3_OFFSET 0x060C
+
+/* SCFG bit fields */
+#define SCFG_SNPCNFGCR_SECRDSNP 0x80000000
+#define SCFG_SNPCNFGCR_SECWRSNP 0x40000000
+
+/* GIC Address Align Register */
+#define SCFG_GIC400_ADDR_ALIGN_4KMODE_MASK 0x80000000
+#define SCFG_GIC400_ADDR_ALIGN_4KMODE_EN 0x80000000
+#define SCFG_GIC400_ADDR_ALIGN_4KMODE_DIS 0x0
+
+#endif /* CONFIG_CHASSIS_2 */
+
+#ifndef __ASSEMBLER__
+#include <endian.h>
+#include <lib/mmio.h>
+
+#ifdef NXP_SCFG_BE
+#define scfg_in32(a) bswap32(mmio_read_32((uintptr_t)(a)))
+#define scfg_out32(a, v) mmio_write_32((uintptr_t)(a), bswap32(v))
+#define scfg_setbits32(a, v) mmio_setbits_32((uintptr_t)(a), v)
+#define scfg_clrbits32(a, v) mmio_clrbits_32((uintptr_t)(a), v)
+#define scfg_clrsetbits32(a, clear, set) \
+ mmio_clrsetbits_32((uintptr_t)(a), clear, set)
+#elif defined(NXP_SCFG_LE)
+#define scfg_in32(a) mmio_read_32((uintptr_t)(a))
+#define scfg_out32(a, v) mmio_write_32((uintptr_t)(a), v)
+#define scfg_setbits32(a, v) mmio_setbits_32((uintptr_t)(a), v)
+#define scfg_clrbits32(a, v) mmio_clrbits_32((uintptr_t)(a), v)
+#define scfg_clrsetbits32(a, clear, set) \
+ mmio_clrsetbits_32((uintptr_t)(a), clear, set)
+#else
+#error Please define CCSR SCFG register endianness
+#endif
+#endif /* __ASSEMBLER__ */
+
+#endif /* SCFG_H */
diff --git a/include/drivers/nxp/ddr/ddr.h b/include/drivers/nxp/ddr/ddr.h
new file mode 100644
index 0000000..0ef2870
--- /dev/null
+++ b/include/drivers/nxp/ddr/ddr.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef DDR_H
+#define DDR_H
+
+#include "ddr_io.h"
+#include "dimm.h"
+#include "immap.h"
+
+#ifndef DDRC_NUM_CS
+#define DDRC_NUM_CS 4
+#endif
+
+/*
+ * This is irrespective of what is the number of DDR controller,
+ * number of DIMM used. This is set to maximum
+ * Max controllers = 2
+ * Max num of DIMM per controlle = 2
+ * MAX NUM CS = 4
+ * Not to be changed.
+ */
+#define MAX_DDRC_NUM 2
+#define MAX_DIMM_NUM 2
+#define MAX_CS_NUM 4
+
+#include "opts.h"
+#include "regs.h"
+#include "utility.h"
+
+#ifdef DDR_DEBUG
+#define debug(...) INFO(__VA_ARGS__)
+#else
+#define debug(...) VERBOSE(__VA_ARGS__)
+#endif
+
+#ifndef DDRC_NUM_DIMM
+#define DDRC_NUM_DIMM 1
+#endif
+
+#define CONFIG_CS_PER_SLOT \
+ (DDRC_NUM_CS / DDRC_NUM_DIMM)
+
+/* Record of register values computed */
+struct ddr_cfg_regs {
+ struct {
+ unsigned int bnds;
+ unsigned int config;
+ unsigned int config_2;
+ } cs[MAX_CS_NUM];
+ unsigned int dec[10];
+ unsigned int timing_cfg[10];
+ unsigned int sdram_cfg[3];
+ unsigned int sdram_mode[16];
+ unsigned int md_cntl;
+ unsigned int interval;
+ unsigned int data_init;
+ unsigned int clk_cntl;
+ unsigned int init_addr;
+ unsigned int init_ext_addr;
+ unsigned int zq_cntl;
+ unsigned int wrlvl_cntl[3];
+ unsigned int ddr_sr_cntr;
+ unsigned int sdram_rcw[6];
+ unsigned int dq_map[4];
+ unsigned int eor;
+ unsigned int cdr[2];
+ unsigned int err_disable;
+ unsigned int err_int_en;
+ unsigned int tx_cfg[4];
+ unsigned int debug[64];
+};
+
+struct ddr_conf {
+ int dimm_in_use[MAX_DIMM_NUM];
+ int cs_in_use; /* bitmask, bit 0 for cs0, bit 1 for cs1, etc. */
+ int cs_on_dimm[MAX_DIMM_NUM]; /* bitmask */
+ unsigned long long cs_base_addr[MAX_CS_NUM];
+ unsigned long long cs_size[MAX_CS_NUM];
+ unsigned long long base_addr;
+ unsigned long long total_mem;
+};
+
+struct ddr_info {
+ unsigned long clk;
+ unsigned long long mem_base;
+ unsigned int num_ctlrs;
+ unsigned int dimm_on_ctlr;
+ struct dimm_params dimm;
+ struct memctl_opt opt;
+ struct ddr_conf conf;
+ struct ddr_cfg_regs ddr_reg;
+ struct ccsr_ddr *ddr[MAX_DDRC_NUM];
+ uint16_t *phy[MAX_DDRC_NUM];
+ int *spd_addr;
+ unsigned int ip_rev;
+ uintptr_t phy_gen2_fw_img_buf;
+ void *img_loadr;
+ int warm_boot_flag;
+};
+
+struct rc_timing {
+ unsigned int speed_bin;
+ unsigned int clk_adj;
+ unsigned int wrlvl;
+};
+
+struct board_timing {
+ unsigned int rc;
+ struct rc_timing const *p;
+ unsigned int add1;
+ unsigned int add2;
+};
+
+enum warm_boot {
+ DDR_COLD_BOOT = 0,
+ DDR_WARM_BOOT = 1,
+ DDR_WRM_BOOT_NT_SUPPORTED = -1,
+};
+
+int disable_unused_ddrc(struct ddr_info *priv, int mask,
+ uintptr_t nxp_ccn_hn_f0_addr);
+int ddr_board_options(struct ddr_info *priv);
+int compute_ddrc(const unsigned long clk,
+ const struct memctl_opt *popts,
+ const struct ddr_conf *conf,
+ struct ddr_cfg_regs *ddr,
+ const struct dimm_params *dimm_params,
+ const unsigned int ip_rev);
+int compute_ddr_phy(struct ddr_info *priv);
+int ddrc_set_regs(const unsigned long clk,
+ const struct ddr_cfg_regs *regs,
+ const struct ccsr_ddr *ddr,
+ int twopass);
+int cal_board_params(struct ddr_info *priv,
+ const struct board_timing *dimm,
+ int len);
+/* return bit mask of used DIMM(s) */
+int ddr_get_ddr_params(struct dimm_params *pdimm, struct ddr_conf *conf);
+long long dram_init(struct ddr_info *priv
+#if defined(NXP_HAS_CCN504) || defined(NXP_HAS_CCN508)
+ , uintptr_t nxp_ccn_hn_f0_addr
+#endif
+ );
+long long board_static_ddr(struct ddr_info *info);
+
+#endif /* DDR_H */
diff --git a/include/drivers/nxp/ddr/ddr_io.h b/include/drivers/nxp/ddr/ddr_io.h
new file mode 100644
index 0000000..fbd7e97
--- /dev/null
+++ b/include/drivers/nxp/ddr/ddr_io.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef DDR_IO_H
+#define DDR_IO_H
+
+#include <endian.h>
+
+#include <lib/mmio.h>
+
+#define min(a, b) (((a) > (b)) ? (b) : (a))
+
+#define max(a, b) (((a) > (b)) ? (a) : (b))
+
+/* macro for memory barrier */
+#define mb() asm volatile("dsb sy" : : : "memory")
+
+#ifdef NXP_DDR_BE
+#define ddr_in32(a) bswap32(mmio_read_32((uintptr_t)(a)))
+#define ddr_out32(a, v) mmio_write_32((uintptr_t)(a),\
+ bswap32(v))
+#elif defined(NXP_DDR_LE)
+#define ddr_in32(a) mmio_read_32((uintptr_t)(a))
+#define ddr_out32(a, v) mmio_write_32((uintptr_t)(a), v)
+#else
+#error Please define CCSR DDR register endianness
+#endif
+
+#define ddr_setbits32(a, v) ddr_out32((a), ddr_in32(a) | (v))
+#define ddr_clrbits32(a, v) ddr_out32((a), ddr_in32(a) & ~(v))
+#define ddr_clrsetbits32(a, c, s) ddr_out32((a), (ddr_in32(a) & ~(c)) \
+ | (s))
+
+#endif /* DDR_IO_H */
diff --git a/include/drivers/nxp/ddr/dimm.h b/include/drivers/nxp/ddr/dimm.h
new file mode 100644
index 0000000..fcae179
--- /dev/null
+++ b/include/drivers/nxp/ddr/dimm.h
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef DIMM_H
+#define DIMM_H
+
+#define SPD_MEMTYPE_DDR4 0x0C
+
+#define DDR4_SPD_MODULETYPE_MASK 0x0f
+#define DDR4_SPD_MODULETYPE_EXT 0x00
+#define DDR4_SPD_RDIMM 0x01
+#define DDR4_SPD_UDIMM 0x02
+#define DDR4_SPD_SO_DIMM 0x03
+#define DDR4_SPD_LRDIMM 0x04
+#define DDR4_SPD_MINI_RDIMM 0x05
+#define DDR4_SPD_MINI_UDIMM 0x06
+#define DDR4_SPD_72B_SO_RDIMM 0x08
+#define DDR4_SPD_72B_SO_UDIMM 0x09
+#define DDR4_SPD_16B_SO_DIMM 0x0c
+#define DDR4_SPD_32B_SO_DIMM 0x0d
+
+#define SPD_SPA0_ADDRESS 0x36
+#define SPD_SPA1_ADDRESS 0x37
+
+#define spd_to_ps(mtb, ftb) \
+ ((mtb) * pdimm->mtb_ps + ((ftb) * pdimm->ftb_10th_ps) / 10)
+
+#ifdef DDR_DEBUG
+#define dump_spd(spd, len) { \
+ register int i; \
+ register unsigned char *buf = (void *)(spd); \
+ \
+ for (i = 0; i < (len); i++) { \
+ print_uint(i); \
+ puts("\t: 0x"); \
+ print_hex(buf[i]); \
+ puts("\n"); \
+ } \
+}
+#else
+#define dump_spd(spd, len) {}
+#endif
+
+/* From JEEC Standard No. 21-C release 23A */
+struct ddr4_spd {
+ /* General Section: Bytes 0-127 */
+ unsigned char info_size_crc; /* 0 # bytes */
+ unsigned char spd_rev; /* 1 Total # bytes of SPD */
+ unsigned char mem_type; /* 2 Key Byte / mem type */
+ unsigned char module_type; /* 3 Key Byte / Module Type */
+ unsigned char density_banks; /* 4 Density and Banks */
+ unsigned char addressing; /* 5 Addressing */
+ unsigned char package_type; /* 6 Package type */
+ unsigned char opt_feature; /* 7 Optional features */
+ unsigned char thermal_ref; /* 8 Thermal and refresh */
+ unsigned char oth_opt_features; /* 9 Other optional features */
+ unsigned char res_10; /* 10 Reserved */
+ unsigned char module_vdd; /* 11 Module nominal voltage */
+ unsigned char organization; /* 12 Module Organization */
+ unsigned char bus_width; /* 13 Module Memory Bus Width */
+ unsigned char therm_sensor; /* 14 Module Thermal Sensor */
+ unsigned char ext_type; /* 15 Extended module type */
+ unsigned char res_16;
+ unsigned char timebases; /* 17 MTb and FTB */
+ unsigned char tck_min; /* 18 tCKAVGmin */
+ unsigned char tck_max; /* 19 TCKAVGmax */
+ unsigned char caslat_b1; /* 20 CAS latencies, 1st byte */
+ unsigned char caslat_b2; /* 21 CAS latencies, 2nd byte */
+ unsigned char caslat_b3; /* 22 CAS latencies, 3rd byte */
+ unsigned char caslat_b4; /* 23 CAS latencies, 4th byte */
+ unsigned char taa_min; /* 24 Min CAS Latency Time */
+ unsigned char trcd_min; /* 25 Min RAS# to CAS# Delay Time */
+ unsigned char trp_min; /* 26 Min Row Precharge Delay Time */
+ unsigned char tras_trc_ext; /* 27 Upper Nibbles for tRAS and tRC */
+ unsigned char tras_min_lsb; /* 28 tRASmin, lsb */
+ unsigned char trc_min_lsb; /* 29 tRCmin, lsb */
+ unsigned char trfc1_min_lsb; /* 30 Min Refresh Recovery Delay Time */
+ unsigned char trfc1_min_msb; /* 31 Min Refresh Recovery Delay Time */
+ unsigned char trfc2_min_lsb; /* 32 Min Refresh Recovery Delay Time */
+ unsigned char trfc2_min_msb; /* 33 Min Refresh Recovery Delay Time */
+ unsigned char trfc4_min_lsb; /* 34 Min Refresh Recovery Delay Time */
+ unsigned char trfc4_min_msb; /* 35 Min Refresh Recovery Delay Time */
+ unsigned char tfaw_msb; /* 36 Upper Nibble for tFAW */
+ unsigned char tfaw_min; /* 37 tFAW, lsb */
+ unsigned char trrds_min; /* 38 tRRD_Smin, MTB */
+ unsigned char trrdl_min; /* 39 tRRD_Lmin, MTB */
+ unsigned char tccdl_min; /* 40 tCCS_Lmin, MTB */
+ unsigned char res_41[60-41]; /* 41 Rserved */
+ unsigned char mapping[78-60]; /* 60~77 Connector to SDRAM bit map */
+ unsigned char res_78[117-78]; /* 78~116, Reserved */
+ signed char fine_tccdl_min; /* 117 Fine offset for tCCD_Lmin */
+ signed char fine_trrdl_min; /* 118 Fine offset for tRRD_Lmin */
+ signed char fine_trrds_min; /* 119 Fine offset for tRRD_Smin */
+ signed char fine_trc_min; /* 120 Fine offset for tRCmin */
+ signed char fine_trp_min; /* 121 Fine offset for tRPmin */
+ signed char fine_trcd_min; /* 122 Fine offset for tRCDmin */
+ signed char fine_taa_min; /* 123 Fine offset for tAAmin */
+ signed char fine_tck_max; /* 124 Fine offset for tCKAVGmax */
+ signed char fine_tck_min; /* 125 Fine offset for tCKAVGmin */
+ /* CRC: Bytes 126-127 */
+ unsigned char crc[2]; /* 126-127 SPD CRC */
+
+ /* Module-Specific Section: Bytes 128-255 */
+ union {
+ struct {
+ /* 128 (Unbuffered) Module Nominal Height */
+ unsigned char mod_height;
+ /* 129 (Unbuffered) Module Maximum Thickness */
+ unsigned char mod_thickness;
+ /* 130 (Unbuffered) Reference Raw Card Used */
+ unsigned char ref_raw_card;
+ /* 131 (Unbuffered) Address Mapping from
+ * Edge Connector to DRAM
+ */
+ unsigned char addr_mapping;
+ /* 132~253 (Unbuffered) Reserved */
+ unsigned char res_132[254-132];
+ /* 254~255 CRC */
+ unsigned char crc[2];
+ } unbuffered;
+ struct {
+ /* 128 (Registered) Module Nominal Height */
+ unsigned char mod_height;
+ /* 129 (Registered) Module Maximum Thickness */
+ unsigned char mod_thickness;
+ /* 130 (Registered) Reference Raw Card Used */
+ unsigned char ref_raw_card;
+ /* 131 DIMM Module Attributes */
+ unsigned char modu_attr;
+ /* 132 RDIMM Thermal Heat Spreader Solution */
+ unsigned char thermal;
+ /* 133 Register Manufacturer ID Code, LSB */
+ unsigned char reg_id_lo;
+ /* 134 Register Manufacturer ID Code, MSB */
+ unsigned char reg_id_hi;
+ /* 135 Register Revision Number */
+ unsigned char reg_rev;
+ /* 136 Address mapping from register to DRAM */
+ unsigned char reg_map;
+ unsigned char ca_stren;
+ unsigned char clk_stren;
+ /* 139~253 Reserved */
+ unsigned char res_139[254-139];
+ /* 254~255 CRC */
+ unsigned char crc[2];
+ } registered;
+ struct {
+ /* 128 (Loadreduced) Module Nominal Height */
+ unsigned char mod_height;
+ /* 129 (Loadreduced) Module Maximum Thickness */
+ unsigned char mod_thickness;
+ /* 130 (Loadreduced) Reference Raw Card Used */
+ unsigned char ref_raw_card;
+ /* 131 DIMM Module Attributes */
+ unsigned char modu_attr;
+ /* 132 RDIMM Thermal Heat Spreader Solution */
+ unsigned char thermal;
+ /* 133 Register Manufacturer ID Code, LSB */
+ unsigned char reg_id_lo;
+ /* 134 Register Manufacturer ID Code, MSB */
+ unsigned char reg_id_hi;
+ /* 135 Register Revision Number */
+ unsigned char reg_rev;
+ /* 136 Address mapping from register to DRAM */
+ unsigned char reg_map;
+ /* 137 Register Output Drive Strength for CMD/Add*/
+ unsigned char reg_drv;
+ /* 138 Register Output Drive Strength for CK */
+ unsigned char reg_drv_ck;
+ /* 139 Data Buffer Revision Number */
+ unsigned char data_buf_rev;
+ /* 140 DRAM VrefDQ for Package Rank 0 */
+ unsigned char vrefqe_r0;
+ /* 141 DRAM VrefDQ for Package Rank 1 */
+ unsigned char vrefqe_r1;
+ /* 142 DRAM VrefDQ for Package Rank 2 */
+ unsigned char vrefqe_r2;
+ /* 143 DRAM VrefDQ for Package Rank 3 */
+ unsigned char vrefqe_r3;
+ /* 144 Data Buffer VrefDQ for DRAM Interface */
+ unsigned char data_intf;
+ /*
+ * 145 Data Buffer MDQ Drive Strength and RTT
+ * for data rate <= 1866
+ */
+ unsigned char data_drv_1866;
+ /*
+ * 146 Data Buffer MDQ Drive Strength and RTT
+ * for 1866 < data rate <= 2400
+ */
+ unsigned char data_drv_2400;
+ /*
+ * 147 Data Buffer MDQ Drive Strength and RTT
+ * for 2400 < data rate <= 3200
+ */
+ unsigned char data_drv_3200;
+ /* 148 DRAM Drive Strength */
+ unsigned char dram_drv;
+ /*
+ * 149 DRAM ODT (RTT_WR, RTT_NOM)
+ * for data rate <= 1866
+ */
+ unsigned char dram_odt_1866;
+ /*
+ * 150 DRAM ODT (RTT_WR, RTT_NOM)
+ * for 1866 < data rate <= 2400
+ */
+ unsigned char dram_odt_2400;
+ /*
+ * 151 DRAM ODT (RTT_WR, RTT_NOM)
+ * for 2400 < data rate <= 3200
+ */
+ unsigned char dram_odt_3200;
+ /*
+ * 152 DRAM ODT (RTT_PARK)
+ * for data rate <= 1866
+ */
+ unsigned char dram_odt_park_1866;
+ /*
+ * 153 DRAM ODT (RTT_PARK)
+ * for 1866 < data rate <= 2400
+ */
+ unsigned char dram_odt_park_2400;
+ /*
+ * 154 DRAM ODT (RTT_PARK)
+ * for 2400 < data rate <= 3200
+ */
+ unsigned char dram_odt_park_3200;
+ unsigned char res_155[254-155]; /* Reserved */
+ /* 254~255 CRC */
+ unsigned char crc[2];
+ } loadreduced;
+ unsigned char uc[128]; /* 128-255 Module-Specific Section */
+ } mod_section;
+
+ unsigned char res_256[320-256]; /* 256~319 Reserved */
+
+ /* Module supplier's data: Byte 320~383 */
+ unsigned char mmid_lsb; /* 320 Module MfgID Code LSB */
+ unsigned char mmid_msb; /* 321 Module MfgID Code MSB */
+ unsigned char mloc; /* 322 Mfg Location */
+ unsigned char mdate[2]; /* 323~324 Mfg Date */
+ unsigned char sernum[4]; /* 325~328 Module Serial Number */
+ unsigned char mpart[20]; /* 329~348 Mfg's Module Part Number */
+ unsigned char mrev; /* 349 Module Revision Code */
+ unsigned char dmid_lsb; /* 350 DRAM MfgID Code LSB */
+ unsigned char dmid_msb; /* 351 DRAM MfgID Code MSB */
+ unsigned char stepping; /* 352 DRAM stepping */
+ unsigned char msd[29]; /* 353~381 Mfg's Specific Data */
+ unsigned char res_382[2]; /* 382~383 Reserved */
+};
+
+/* Parameters for a DDR dimm computed from the SPD */
+struct dimm_params {
+ /* DIMM organization parameters */
+ char mpart[19]; /* guaranteed null terminated */
+
+ unsigned int n_ranks;
+ unsigned int die_density;
+ unsigned long long rank_density;
+ unsigned long long capacity;
+ unsigned int primary_sdram_width;
+ unsigned int ec_sdram_width;
+ unsigned int rdimm;
+ unsigned int package_3ds; /* number of dies in 3DS */
+ unsigned int device_width; /* x4, x8, x16 components */
+ unsigned int rc;
+
+ /* SDRAM device parameters */
+ unsigned int n_row_addr;
+ unsigned int n_col_addr;
+ unsigned int edc_config; /* 0 = none, 1 = parity, 2 = ECC */
+ unsigned int bank_addr_bits;
+ unsigned int bank_group_bits;
+ unsigned int burst_lengths_bitmask; /* BL=4 bit 2, BL=8 = bit 3 */
+
+ /* mirrored DIMMs */
+ unsigned int mirrored_dimm; /* only for ddr3 */
+
+ /* DIMM timing parameters */
+
+ int mtb_ps; /* medium timebase ps */
+ int ftb_10th_ps; /* fine timebase, in 1/10 ps */
+ int taa_ps; /* minimum CAS latency time */
+ int tfaw_ps; /* four active window delay */
+
+ /*
+ * SDRAM clock periods
+ * The range for these are 1000-10000 so a short should be sufficient
+ */
+ int tckmin_x_ps;
+ int tckmax_ps;
+
+ /* SPD-defined CAS latencies */
+ unsigned int caslat_x;
+
+ /* basic timing parameters */
+ int trcd_ps;
+ int trp_ps;
+ int tras_ps;
+
+ int trfc1_ps;
+ int trfc2_ps;
+ int trfc4_ps;
+ int trrds_ps;
+ int trrdl_ps;
+ int tccdl_ps;
+ int trfc_slr_ps;
+
+ int trc_ps; /* maximum = 254 ns + .75 ns = 254750 ps */
+ int twr_ps; /* 15ns for all speed bins */
+
+ unsigned int refresh_rate_ps;
+ unsigned int extended_op_srt;
+
+ /* RDIMM */
+ unsigned char rcw[16]; /* Register Control Word 0-15 */
+ unsigned int dq_mapping[18];
+ unsigned int dq_mapping_ors;
+};
+
+int read_spd(unsigned char chip, void *buf, int len);
+int crc16(unsigned char *ptr, int count);
+int cal_dimm_params(const struct ddr4_spd *spd, struct dimm_params *pdimm);
+
+#endif /* DIMM_H */
diff --git a/include/drivers/nxp/ddr/fsl-mmdc/fsl_mmdc.h b/include/drivers/nxp/ddr/fsl-mmdc/fsl_mmdc.h
new file mode 100644
index 0000000..31db552
--- /dev/null
+++ b/include/drivers/nxp/ddr/fsl-mmdc/fsl_mmdc.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef FSL_MMDC_H
+#define FSL_MMDC_H
+
+/* PHY Write Leveling Configuration and Error Status Register (MPWLGCR) */
+#define MPWLGCR_HW_WL_EN (1 << 0)
+
+/* PHY Pre-defined Compare and CA delay-line Configuration (MPPDCMPR2) */
+#define MPPDCMPR2_MPR_COMPARE_EN (1 << 0)
+
+
+/* MMDC PHY Read DQS gating control register 0 (MPDGCTRL0) */
+#define AUTO_RD_DQS_GATING_CALIBRATION_EN (1 << 28)
+
+/* MMDC PHY Read Delay HW Calibration Control Register (MPRDDLHWCTL) */
+#define MPRDDLHWCTL_AUTO_RD_CALIBRATION_EN (1 << 4)
+
+/* MMDC Core Power Saving Control and Status Register (MMDC_MAPSR) */
+#define MMDC_MAPSR_PWR_SAV_CTRL_STAT 0x00001067
+
+/* MMDC Core Refresh Control Register (MMDC_MDREF) */
+#define MDREF_START_REFRESH (1 << 0)
+
+/* MMDC Core Special Command Register (MDSCR) */
+#define CMD_ADDR_MSB_MR_OP(x) (x << 24)
+#define CMD_ADDR_LSB_MR_ADDR(x) (x << 16)
+#define MDSCR_DISABLE_CFG_REQ (0 << 15)
+#define MDSCR_ENABLE_CON_REQ (1 << 15)
+#define MDSCR_CON_ACK (1 << 14)
+#define MDSCR_WL_EN (1 << 9)
+#define CMD_NORMAL (0 << 4)
+#define CMD_PRECHARGE (1 << 4)
+#define CMD_AUTO_REFRESH (2 << 4)
+#define CMD_LOAD_MODE_REG (3 << 4)
+#define CMD_ZQ_CALIBRATION (4 << 4)
+#define CMD_PRECHARGE_BANK_OPEN (5 << 4)
+#define CMD_MRR (6 << 4)
+#define CMD_BANK_ADDR_0 0x0
+#define CMD_BANK_ADDR_1 0x1
+#define CMD_BANK_ADDR_2 0x2
+#define CMD_BANK_ADDR_3 0x3
+#define CMD_BANK_ADDR_4 0x4
+#define CMD_BANK_ADDR_5 0x5
+#define CMD_BANK_ADDR_6 0x6
+#define CMD_BANK_ADDR_7 0x7
+
+/* MMDC Core Control Register (MDCTL) */
+#define MDCTL_SDE0 (U(1) << 31)
+#define MDCTL_SDE1 (1 << 30)
+
+/* MMDC PHY ZQ HW control register (MMDC_MPZQHWCTRL) */
+#define MPZQHWCTRL_ZQ_HW_FORCE (1 << 16)
+
+/* MMDC PHY Measure Unit Register (MMDC_MPMUR0) */
+#define MMDC_MPMUR0_FRC_MSR (1 << 11)
+
+/* MMDC PHY Read delay-lines Configuration Register (MMDC_MPRDDLCTL) */
+/* default 64 for a quarter cycle delay */
+#define MMDC_MPRDDLCTL_DEFAULT_DELAY 0x40404040
+
+/* MMDC Registers */
+struct mmdc_regs {
+ unsigned int mdctl;
+ unsigned int mdpdc;
+ unsigned int mdotc;
+ unsigned int mdcfg0;
+ unsigned int mdcfg1;
+ unsigned int mdcfg2;
+ unsigned int mdmisc;
+ unsigned int mdscr;
+ unsigned int mdref;
+ unsigned int res1[2];
+ unsigned int mdrwd;
+ unsigned int mdor;
+ unsigned int mdmrr;
+ unsigned int mdcfg3lp;
+ unsigned int mdmr4;
+ unsigned int mdasp;
+ unsigned int res2[239];
+ unsigned int maarcr;
+ unsigned int mapsr;
+ unsigned int maexidr0;
+ unsigned int maexidr1;
+ unsigned int madpcr0;
+ unsigned int madpcr1;
+ unsigned int madpsr0;
+ unsigned int madpsr1;
+ unsigned int madpsr2;
+ unsigned int madpsr3;
+ unsigned int madpsr4;
+ unsigned int madpsr5;
+ unsigned int masbs0;
+ unsigned int masbs1;
+ unsigned int res3[2];
+ unsigned int magenp;
+ unsigned int res4[239];
+ unsigned int mpzqhwctrl;
+ unsigned int mpzqswctrl;
+ unsigned int mpwlgcr;
+ unsigned int mpwldectrl0;
+ unsigned int mpwldectrl1;
+ unsigned int mpwldlst;
+ unsigned int mpodtctrl;
+ unsigned int mprddqby0dl;
+ unsigned int mprddqby1dl;
+ unsigned int mprddqby2dl;
+ unsigned int mprddqby3dl;
+ unsigned int mpwrdqby0dl;
+ unsigned int mpwrdqby1dl;
+ unsigned int mpwrdqby2dl;
+ unsigned int mpwrdqby3dl;
+ unsigned int mpdgctrl0;
+ unsigned int mpdgctrl1;
+ unsigned int mpdgdlst0;
+ unsigned int mprddlctl;
+ unsigned int mprddlst;
+ unsigned int mpwrdlctl;
+ unsigned int mpwrdlst;
+ unsigned int mpsdctrl;
+ unsigned int mpzqlp2ctl;
+ unsigned int mprddlhwctl;
+ unsigned int mpwrdlhwctl;
+ unsigned int mprddlhwst0;
+ unsigned int mprddlhwst1;
+ unsigned int mpwrdlhwst0;
+ unsigned int mpwrdlhwst1;
+ unsigned int mpwlhwerr;
+ unsigned int mpdghwst0;
+ unsigned int mpdghwst1;
+ unsigned int mpdghwst2;
+ unsigned int mpdghwst3;
+ unsigned int mppdcmpr1;
+ unsigned int mppdcmpr2;
+ unsigned int mpswdar0;
+ unsigned int mpswdrdr0;
+ unsigned int mpswdrdr1;
+ unsigned int mpswdrdr2;
+ unsigned int mpswdrdr3;
+ unsigned int mpswdrdr4;
+ unsigned int mpswdrdr5;
+ unsigned int mpswdrdr6;
+ unsigned int mpswdrdr7;
+ unsigned int mpmur0;
+ unsigned int mpwrcadl;
+ unsigned int mpdccr;
+};
+
+struct fsl_mmdc_info {
+ unsigned int mdctl;
+ unsigned int mdpdc;
+ unsigned int mdotc;
+ unsigned int mdcfg0;
+ unsigned int mdcfg1;
+ unsigned int mdcfg2;
+ unsigned int mdmisc;
+ unsigned int mdref;
+ unsigned int mdrwd;
+ unsigned int mdor;
+ unsigned int mdasp;
+ unsigned int mpodtctrl;
+ unsigned int mpzqhwctrl;
+ unsigned int mprddlctl;
+};
+
+void mmdc_init(const struct fsl_mmdc_info *priv, uintptr_t nxp_ddr_addr);
+
+#endif /* FSL_MMDC_H */
diff --git a/include/drivers/nxp/ddr/immap.h b/include/drivers/nxp/ddr/immap.h
new file mode 100644
index 0000000..83b4de6
--- /dev/null
+++ b/include/drivers/nxp/ddr/immap.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef DDR_IMMAP_H
+#define DDR_IMMAP_H
+
+#define DDR_DBUS_64 0
+#define DDR_DBUS_32 1
+#define DDR_DBUS_16 2
+
+/*
+ * DDRC register file for DDRC 5.0 and above
+ */
+struct ccsr_ddr {
+ struct {
+ unsigned int a; /* 0x0, 0x8, 0x10, 0x18 */
+ unsigned int res; /* 0x4, 0xc, 0x14, 0x1c */
+ } bnds[4];
+ unsigned char res_20[0x40 - 0x20];
+ unsigned int dec[10]; /* 0x40 */
+ unsigned char res_68[0x80 - 0x68];
+ unsigned int csn_cfg[4]; /* 0x80, 0x84, 0x88, 0x8c */
+ unsigned char res_90[48];
+ unsigned int csn_cfg_2[4]; /* 0xc0, 0xc4, 0xc8, 0xcc */
+ unsigned char res_d0[48];
+ unsigned int timing_cfg_3; /* SDRAM Timing Configuration 3 */
+ unsigned int timing_cfg_0; /* SDRAM Timing Configuration 0 */
+ unsigned int timing_cfg_1; /* SDRAM Timing Configuration 1 */
+ unsigned int timing_cfg_2; /* SDRAM Timing Configuration 2 */
+ unsigned int sdram_cfg; /* SDRAM Control Configuration */
+ unsigned int sdram_cfg_2; /* SDRAM Control Configuration 2 */
+ unsigned int sdram_mode; /* SDRAM Mode Configuration */
+ unsigned int sdram_mode_2; /* SDRAM Mode Configuration 2 */
+ unsigned int sdram_md_cntl; /* SDRAM Mode Control */
+ unsigned int sdram_interval; /* SDRAM Interval Configuration */
+ unsigned int sdram_data_init; /* SDRAM Data initialization */
+ unsigned char res_12c[4];
+ unsigned int sdram_clk_cntl; /* SDRAM Clock Control */
+ unsigned char res_134[20];
+ unsigned int init_addr; /* training init addr */
+ unsigned int init_ext_addr; /* training init extended addr */
+ unsigned char res_150[16];
+ unsigned int timing_cfg_4; /* SDRAM Timing Configuration 4 */
+ unsigned int timing_cfg_5; /* SDRAM Timing Configuration 5 */
+ unsigned int timing_cfg_6; /* SDRAM Timing Configuration 6 */
+ unsigned int timing_cfg_7; /* SDRAM Timing Configuration 7 */
+ unsigned int zq_cntl; /* ZQ calibration control*/
+ unsigned int wrlvl_cntl; /* write leveling control*/
+ unsigned char reg_178[4];
+ unsigned int ddr_sr_cntr; /* self refresh counter */
+ unsigned int ddr_sdram_rcw_1; /* Control Words 1 */
+ unsigned int ddr_sdram_rcw_2; /* Control Words 2 */
+ unsigned char reg_188[8];
+ unsigned int ddr_wrlvl_cntl_2; /* write leveling control 2 */
+ unsigned int ddr_wrlvl_cntl_3; /* write leveling control 3 */
+ unsigned char res_198[0x1a0-0x198];
+ unsigned int ddr_sdram_rcw_3;
+ unsigned int ddr_sdram_rcw_4;
+ unsigned int ddr_sdram_rcw_5;
+ unsigned int ddr_sdram_rcw_6;
+ unsigned char res_1b0[0x200-0x1b0];
+ unsigned int sdram_mode_3; /* SDRAM Mode Configuration 3 */
+ unsigned int sdram_mode_4; /* SDRAM Mode Configuration 4 */
+ unsigned int sdram_mode_5; /* SDRAM Mode Configuration 5 */
+ unsigned int sdram_mode_6; /* SDRAM Mode Configuration 6 */
+ unsigned int sdram_mode_7; /* SDRAM Mode Configuration 7 */
+ unsigned int sdram_mode_8; /* SDRAM Mode Configuration 8 */
+ unsigned char res_218[0x220-0x218];
+ unsigned int sdram_mode_9; /* SDRAM Mode Configuration 9 */
+ unsigned int sdram_mode_10; /* SDRAM Mode Configuration 10 */
+ unsigned int sdram_mode_11; /* SDRAM Mode Configuration 11 */
+ unsigned int sdram_mode_12; /* SDRAM Mode Configuration 12 */
+ unsigned int sdram_mode_13; /* SDRAM Mode Configuration 13 */
+ unsigned int sdram_mode_14; /* SDRAM Mode Configuration 14 */
+ unsigned int sdram_mode_15; /* SDRAM Mode Configuration 15 */
+ unsigned int sdram_mode_16; /* SDRAM Mode Configuration 16 */
+ unsigned char res_240[0x250-0x240];
+ unsigned int timing_cfg_8; /* SDRAM Timing Configuration 8 */
+ unsigned int timing_cfg_9; /* SDRAM Timing Configuration 9 */
+ unsigned int timing_cfg_10; /* SDRAM Timing COnfigurtion 10 */
+ unsigned char res_258[0x260-0x25c];
+ unsigned int sdram_cfg_3;
+ unsigned char res_264[0x270-0x264];
+ unsigned int sdram_md_cntl_2;
+ unsigned char res_274[0x400-0x274];
+ unsigned int dq_map[4];
+ unsigned char res_410[0x800-0x410];
+ unsigned int tx_cfg[4];
+ unsigned char res_810[0xb20-0x810];
+ unsigned int ddr_dsr1; /* Debug Status 1 */
+ unsigned int ddr_dsr2; /* Debug Status 2 */
+ unsigned int ddr_cdr1; /* Control Driver 1 */
+ unsigned int ddr_cdr2; /* Control Driver 2 */
+ unsigned char res_b30[200];
+ unsigned int ip_rev1; /* IP Block Revision 1 */
+ unsigned int ip_rev2; /* IP Block Revision 2 */
+ unsigned int eor; /* Enhanced Optimization Register */
+ unsigned char res_c04[252];
+ unsigned int mtcr; /* Memory Test Control Register */
+ unsigned char res_d04[28];
+ unsigned int mtp[10]; /* Memory Test Patterns */
+ unsigned char res_d48[184];
+ unsigned int data_err_inject_hi; /* Data Path Err Injection Mask Hi*/
+ unsigned int data_err_inject_lo;/* Data Path Err Injection Mask Lo*/
+ unsigned int ecc_err_inject; /* Data Path Err Injection Mask ECC */
+ unsigned char res_e0c[20];
+ unsigned int capture_data_hi; /* Data Path Read Capture High */
+ unsigned int capture_data_lo; /* Data Path Read Capture Low */
+ unsigned int capture_ecc; /* Data Path Read Capture ECC */
+ unsigned char res_e2c[20];
+ unsigned int err_detect; /* Error Detect */
+ unsigned int err_disable; /* Error Disable */
+ unsigned int err_int_en;
+ unsigned int capture_attributes; /* Error Attrs Capture */
+ unsigned int capture_address; /* Error Addr Capture */
+ unsigned int capture_ext_address; /* Error Extended Addr Capture */
+ unsigned int err_sbe; /* Single-Bit ECC Error Management */
+ unsigned char res_e5c[164];
+ unsigned int debug[64]; /* debug_1 to debug_64 */
+};
+#endif /* DDR_IMMAP_H */
diff --git a/include/drivers/nxp/ddr/opts.h b/include/drivers/nxp/ddr/opts.h
new file mode 100644
index 0000000..f32891b
--- /dev/null
+++ b/include/drivers/nxp/ddr/opts.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef DDR_OPTS_H
+#define DDR_OPTS_H
+
+#define SDRAM_TYPE_DDR4 5 /* sdram_cfg register */
+
+#define DDR_BC4 4 /* burst chop */
+#define DDR_OTF 6 /* on-the-fly BC4 and BL8 */
+#define DDR_BL8 8 /* burst length 8 */
+
+#define DDR4_RTT_OFF 0
+#define DDR4_RTT_60_OHM 1 /* RZQ/4 */
+#define DDR4_RTT_120_OHM 2 /* RZQ/2 */
+#define DDR4_RTT_40_OHM 3 /* RZQ/6 */
+#define DDR4_RTT_240_OHM 4 /* RZQ/1 */
+#define DDR4_RTT_48_OHM 5 /* RZQ/5 */
+#define DDR4_RTT_80_OHM 6 /* RZQ/3 */
+#define DDR4_RTT_34_OHM 7 /* RZQ/7 */
+#define DDR4_RTT_WR_OFF 0
+#define DDR4_RTT_WR_120_OHM 1
+#define DDR4_RTT_WR_240_OHM 2
+#define DDR4_RTT_WR_HZ 3
+#define DDR4_RTT_WR_80_OHM 4
+#define DDR_ODT_NEVER 0x0
+#define DDR_ODT_CS 0x1
+#define DDR_ODT_ALL_OTHER_CS 0x2
+#define DDR_ODT_OTHER_DIMM 0x3
+#define DDR_ODT_ALL 0x4
+#define DDR_ODT_SAME_DIMM 0x5
+#define DDR_ODT_CS_AND_OTHER_DIMM 0x6
+#define DDR_ODT_OTHER_CS_ONSAMEDIMM 0x7
+#define DDR_BA_INTLV_CS01 0x40
+#define DDR_BA_INTLV_CS0123 0x64
+#define DDR_BA_NONE 0
+#define DDR_256B_INTLV 0x8
+
+struct memctl_opt {
+ int rdimm;
+ unsigned int dbw_cap_shift;
+ struct local_opts_s {
+ unsigned int auto_precharge;
+ unsigned int odt_rd_cfg;
+ unsigned int odt_wr_cfg;
+ unsigned int odt_rtt_norm;
+ unsigned int odt_rtt_wr;
+ } cs_odt[DDRC_NUM_CS];
+ int ctlr_intlv;
+ unsigned int ctlr_intlv_mode;
+ unsigned int ba_intlv;
+ int addr_hash;
+ int ecc_mode;
+ int ctlr_init_ecc;
+ int self_refresh_in_sleep;
+ int self_refresh_irq_en;
+ int dynamic_power;
+ /* memory data width 0 = 64-bit, 1 = 32-bit, 2 = 16-bit */
+ unsigned int data_bus_dimm;
+ unsigned int data_bus_used; /* on individual board */
+ unsigned int burst_length; /* BC4, OTF and BL8 */
+ int otf_burst_chop_en;
+ int mirrored_dimm;
+ int quad_rank_present;
+ int output_driver_impedance;
+ int ap_en;
+ int x4_en;
+
+ int caslat_override;
+ unsigned int caslat_override_value;
+ int addt_lat_override;
+ unsigned int addt_lat_override_value;
+
+ unsigned int clk_adj;
+ unsigned int cpo_sample;
+ unsigned int wr_data_delay;
+
+ unsigned int cswl_override;
+ unsigned int wrlvl_override;
+ unsigned int wrlvl_sample;
+ unsigned int wrlvl_start;
+ unsigned int wrlvl_ctl_2;
+ unsigned int wrlvl_ctl_3;
+
+ int half_strength_drive_en;
+ int twot_en;
+ int threet_en;
+ unsigned int bstopre;
+ unsigned int tfaw_ps;
+
+ int rtt_override;
+ unsigned int rtt_override_value;
+ unsigned int rtt_wr_override_value;
+ unsigned int rtt_park;
+
+ int auto_self_refresh_en;
+ unsigned int sr_it;
+ unsigned int ddr_cdr1;
+ unsigned int ddr_cdr2;
+
+ unsigned int trwt_override;
+ unsigned int trwt;
+ unsigned int twrt;
+ unsigned int trrt;
+ unsigned int twwt;
+
+ unsigned int vref_phy;
+ unsigned int vref_dimm;
+ unsigned int odt;
+ unsigned int phy_tx_impedance;
+ unsigned int phy_atx_impedance;
+ unsigned int skip2d;
+};
+
+#endif /* DDR_OPTS_H */
diff --git a/include/drivers/nxp/ddr/regs.h b/include/drivers/nxp/ddr/regs.h
new file mode 100644
index 0000000..e85fd8f
--- /dev/null
+++ b/include/drivers/nxp/ddr/regs.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef DDR_REG_H
+#define DDR_REG_H
+
+#define SDRAM_CS_CONFIG_EN 0x80000000
+
+/* DDR_SDRAM_CFG - DDR SDRAM Control Configuration
+ */
+#define SDRAM_CFG_MEM_EN 0x80000000
+#define SDRAM_CFG_SREN 0x40000000
+#define SDRAM_CFG_ECC_EN 0x20000000
+#define SDRAM_CFG_RD_EN 0x10000000
+#define SDRAM_CFG_SDRAM_TYPE_MASK 0x07000000
+#define SDRAM_CFG_SDRAM_TYPE_SHIFT 24
+#define SDRAM_CFG_DYN_PWR 0x00200000
+#define SDRAM_CFG_DBW_MASK 0x00180000
+#define SDRAM_CFG_DBW_SHIFT 19
+#define SDRAM_CFG_32_BW 0x00080000
+#define SDRAM_CFG_16_BW 0x00100000
+#define SDRAM_CFG_8_BW 0x00180000
+#define SDRAM_CFG_8_BE 0x00040000
+#define SDRAM_CFG_2T_EN 0x00008000
+#define SDRAM_CFG_MEM_HLT 0x00000002
+#define SDRAM_CFG_BI 0x00000001
+
+#define SDRAM_CFG2_FRC_SR 0x80000000
+#define SDRAM_CFG2_FRC_SR_CLEAR ~(SDRAM_CFG2_FRC_SR)
+#define SDRAM_CFG2_D_INIT 0x00000010
+#define SDRAM_CFG2_AP_EN 0x00000020
+#define SDRAM_CFG2_ODT_ONLY_READ 2
+
+#define SDRAM_CFG3_DDRC_RST 0x80000000
+
+#define SDRAM_INTERVAL_REFINT 0xFFFF0000
+#define SDRAM_INTERVAL_REFINT_CLEAR ~(SDRAM_INTERVAL_REFINT)
+#define SDRAM_INTERVAL_BSTOPRE 0x3FFF
+
+/* DDR_MD_CNTL */
+#define MD_CNTL_MD_EN 0x80000000
+#define MD_CNTL_CS_SEL(x) (((x) & 0x7) << 28)
+#define MD_CNTL_MD_SEL(x) (((x) & 0xf) << 24)
+#define MD_CNTL_CKE(x) (((x) & 0x3) << 20)
+
+/* DDR_CDR1 */
+#define DDR_CDR1_DHC_EN 0x80000000
+#define DDR_CDR1_ODT_SHIFT 17
+#define DDR_CDR1_ODT_MASK 0x6
+#define DDR_CDR2_ODT_MASK 0x1
+#define DDR_CDR1_ODT(x) ((x & DDR_CDR1_ODT_MASK) << DDR_CDR1_ODT_SHIFT)
+#define DDR_CDR2_ODT(x) (x & DDR_CDR2_ODT_MASK)
+#define DDR_CDR2_VREF_OVRD(x) (0x00008080 | ((((x) - 37) & 0x3F) << 8))
+#define DDR_CDR2_VREF_TRAIN_EN 0x00000080
+#define DDR_CDR2_VREF_RANGE_2 0x00000040
+#define DDR_CDR_ODT_OFF 0x0
+#define DDR_CDR_ODT_100ohm 0x1
+#define DDR_CDR_ODT_120OHM 0x2
+#define DDR_CDR_ODT_80ohm 0x3
+#define DDR_CDR_ODT_60ohm 0x4
+#define DDR_CDR_ODT_40ohm 0x5
+#define DDR_CDR_ODT_50ohm 0x6
+#define DDR_CDR_ODT_30ohm 0x7
+
+
+/* DDR ERR_DISABLE */
+#define DDR_ERR_DISABLE_APED (1 << 8) /* Address parity error disable */
+#define DDR_ERR_DISABLE_SBED (1 << 2) /* Address parity error disable */
+#define DDR_ERR_DISABLE_MBED (1 << 3) /* Address parity error disable */
+
+/* Mode Registers */
+#define DDR_MR5_CA_PARITY_LAT_4_CLK 0x1 /* for DDR4-1600/1866/2133 */
+#define DDR_MR5_CA_PARITY_LAT_5_CLK 0x2 /* for DDR4-2400 */
+
+/* DDR DSR2 register */
+#define DDR_DSR_2_PHY_INIT_CMPLT 0x4
+
+/* SDRAM TIMING_CFG_10 register */
+#define DDR_TIMING_CFG_10_T_STAB 0x7FFF
+
+/* DEBUG 2 register */
+#define DDR_DBG_2_MEM_IDLE 0x00000002
+
+/* DEBUG 26 register */
+#define DDR_DEBUG_26_BIT_6 (0x1 << 6)
+#define DDR_DEBUG_26_BIT_7 (0x1 << 7)
+#define DDR_DEBUG_26_BIT_12 (0x1 << 12)
+#define DDR_DEBUG_26_BIT_13 (0x1 << 13)
+#define DDR_DEBUG_26_BIT_14 (0x1 << 14)
+#define DDR_DEBUG_26_BIT_15 (0x1 << 15)
+#define DDR_DEBUG_26_BIT_16 (0x1 << 16)
+#define DDR_DEBUG_26_BIT_17 (0x1 << 17)
+#define DDR_DEBUG_26_BIT_18 (0x1 << 18)
+#define DDR_DEBUG_26_BIT_19 (0x1 << 19)
+#define DDR_DEBUG_26_BIT_24 (0x1 << 24)
+#define DDR_DEBUG_26_BIT_25 (0x1 << 25)
+
+#define DDR_DEBUG_26_BIT_24_CLEAR ~(DDR_DEBUG_26_BIT_24)
+
+/* DEBUG_29 register */
+#define DDR_TX_BD_DIS (1 << 10) /* Transmit Bit Deskew Disable */
+
+#define DDR_INIT_ADDR_EXT_UIA (1 << 31)
+
+#endif /* DDR_REG_H */
diff --git a/include/drivers/nxp/ddr/utility.h b/include/drivers/nxp/ddr/utility.h
new file mode 100644
index 0000000..2e22ad5
--- /dev/null
+++ b/include/drivers/nxp/ddr/utility.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef UTILITY_H
+#define UTILITY_H
+
+#include <dcfg.h>
+
+#if defined(NXP_HAS_CCN504) || defined(NXP_HAS_CCN508)
+#define CCN_HN_F_SAM_CTL 0x8
+#define CCN_HN_F_REGION_SIZE 0x10000
+#endif
+
+unsigned long get_ddr_freq(struct sysinfo *sys, int ctrl_num);
+unsigned int get_memory_clk_ps(unsigned long clk);
+unsigned int picos_to_mclk(unsigned long data_rate, unsigned int picos);
+unsigned int get_ddrc_version(const struct ccsr_ddr *ddr);
+void print_ddr_info(struct ccsr_ddr *ddr);
+
+#endif
diff --git a/include/drivers/nxp/flexspi/flash_info.h b/include/drivers/nxp/flexspi/flash_info.h
new file mode 100644
index 0000000..d0ffc86
--- /dev/null
+++ b/include/drivers/nxp/flexspi/flash_info.h
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright 2020-2021 NXP
+ */
+
+/**
+ * @Flash info
+ *
+ */
+#ifndef FLASH_INFO_H
+#define FLASH_INFO_H
+
+#define SZ_16M_BYTES 0x1000000U
+
+/* Start of "if defined(CONFIG_MT25QU512A)" */
+#if defined(CONFIG_MT25QU512A)
+#define F_SECTOR_64K 0x10000U
+#define F_PAGE_256 0x100U
+#define F_SECTOR_4K 0x1000U
+#define F_FLASH_SIZE_BYTES 0x4000000U
+#define F_SECTOR_ERASE_SZ F_SECTOR_64K
+#ifdef CONFIG_FSPI_4K_ERASE
+#define F_SECTOR_ERASE_SZ F_SECTOR_4K
+#endif
+
+/* End of "if defined(CONFIG_MT25QU512A)" */
+
+/* Start of "if defined(CONFIG_MX25U25645G)" */
+#elif defined(CONFIG_MX25U25645G)
+#define F_SECTOR_64K 0x10000U
+#define F_PAGE_256 0x100U
+#define F_SECTOR_4K 0x1000U
+#define F_FLASH_SIZE_BYTES 0x2000000U
+#define F_SECTOR_ERASE_SZ F_SECTOR_64K
+#ifdef CONFIG_FSPI_4K_ERASE
+#define F_SECTOR_ERASE_SZ F_SECTOR_4K
+#endif
+
+/* End of "if defined(CONFIG_MX25U25645G)" */
+
+/* Start of "if defined(CONFIG_MX25U51245G)" */
+#elif defined(CONFIG_MX25U51245G)
+#define F_SECTOR_64K 0x10000U
+#define F_PAGE_256 0x100U
+#define F_SECTOR_4K 0x1000U
+#define F_FLASH_SIZE_BYTES 0x4000000U
+#define F_SECTOR_ERASE_SZ F_SECTOR_64K
+#ifdef CONFIG_FSPI_4K_ERASE
+#define F_SECTOR_ERASE_SZ F_SECTOR_4K
+#endif
+
+/* End of "if defined(CONFIG_MX25U51245G)" */
+
+/* Start of "if defined(CONFIG_MT35XU512A)" */
+#elif defined(CONFIG_MT35XU512A)
+#define F_SECTOR_128K 0x20000U
+#define F_SECTOR_32K 0x8000U
+#define F_PAGE_256 0x100U
+#define F_SECTOR_4K 0x1000U
+#define F_FLASH_SIZE_BYTES 0x4000000U
+#define F_SECTOR_ERASE_SZ F_SECTOR_128K
+#ifdef CONFIG_FSPI_4K_ERASE
+#define F_SECTOR_ERASE_SZ F_SECTOR_4K
+#endif
+/* If Warm boot is enabled for the platform,
+ * count of arm instruction N-OP(s) to mark
+ * the completion of write operation to flash;
+ * varies from one flash to other.
+ */
+#ifdef NXP_WARM_BOOT
+#define FLASH_WR_COMP_WAIT_BY_NOP_COUNT 0x20000
+#endif
+
+/* End of "if defined(CONFIG_MT35XU512A)" */
+
+/* Start of #elif defined(CONFIG_MT35XU02G) */
+#elif defined(CONFIG_MT35XU02G)
+#define F_SECTOR_128K 0x20000U
+#define F_PAGE_256 0x100U
+#define F_SECTOR_4K 0x1000U
+#define F_FLASH_SIZE_BYTES 0x10000000U
+#define F_SECTOR_ERASE_SZ F_SECTOR_128K
+#ifdef CONFIG_FSPI_4K_ERASE
+#define F_SECTOR_ERASE_SZ F_SECTOR_4K
+#endif
+
+#endif /* End of #elif defined(CONFIG_MT35XU02G) */
+
+#endif /* FLASH_INFO_H */
diff --git a/include/drivers/nxp/flexspi/fspi_api.h b/include/drivers/nxp/flexspi/fspi_api.h
new file mode 100644
index 0000000..d0de543
--- /dev/null
+++ b/include/drivers/nxp/flexspi/fspi_api.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+
+/*!
+ * @file fspi_api.h
+ * @brief This file contains the FlexSPI/FSPI API to communicate
+ * to attached Slave device.
+ * @addtogroup FSPI_API
+ * @{
+ */
+
+#ifndef FSPI_API_H
+#define FSPI_API_H
+
+#if DEBUG_FLEXSPI
+#define SZ_57M 0x3900000u
+#endif
+
+/*!
+ * Basic set of APIs.
+ */
+
+/*!
+ * @details AHB read/IP Read, decision to be internal to API
+ * Minimum Read size = 1Byte
+ * @param[in] src_off source offset from where data to read from flash
+ * @param[out] des Destination location where data needs to be copied
+ * @param[in] len length in Bytes,where 1-word=4-bytes/32-bits
+ *
+ * @return XSPI_SUCCESS or error code
+ */
+int xspi_read(uint32_t src_off, uint32_t *des, uint32_t len);
+/*!
+ * @details Sector erase, Minimum size
+ * 256KB(0x40000)/128KB(0x20000)/64K(0x10000)/4K(0x1000)
+ * depending upon flash, Calls xspi_wren() internally
+ * @param[out] erase_offset Destination erase location on flash which
+ * has to be erased, needs to be multiple of 0x40000/0x20000/0x10000
+ * @param[in] erase_len length in bytes in Hex like 0x100000 for 1MB, minimum
+ * erase size is 1 sector(0x40000/0x20000/0x10000)
+ *
+ * @return XSPI_SUCCESS or error code
+ */
+int xspi_sector_erase(uint32_t erase_offset, uint32_t erase_len);
+/*!
+ * @details IP write, For writing data to flash, calls xspi_wren() internally.
+ * Single/multiple page write can start @any offset, but performance will be low
+ * due to ERRATA
+ * @param[out] dst_off Destination location on flash where data needs to
+ * be written
+ * @param[in] src source offset from where data to be read
+ * @param[in] len length in bytes,where 1-word=4-bytes/32-bits
+ *
+ * @return XSPI_SUCCESS or error code
+ */
+int xspi_write(uint32_t dst_off, void *src, uint32_t len);
+/*!
+ * @details fspi_init, Init function.
+ * @param[in] uint32_t base_reg_addr
+ * @param[in] uint32_t flash_start_addr
+ *
+ * @return XSPI_SUCCESS or error code
+ */
+int fspi_init(uint32_t base_reg_addr, uint32_t flash_start_addr);
+/*!
+ * @details is_flash_busy, Check if any erase or write or lock is
+ * pending on flash/slave
+ * @param[in] void
+ *
+ * @return TRUE/FLASE
+ */
+bool is_flash_busy(void);
+
+/*!
+ * Advanced set of APIs.
+ */
+
+/*!
+ * @details Write enable, to be used by advance users only.
+ * Step 1 for sending write commands to flash.
+ * @param[in] dst_off destination offset where data will be written
+ *
+ * @return XSPI_SUCCESS or error code
+ */
+int xspi_wren(uint32_t dst_off);
+/*!
+ * @details AHB read, meaning direct memory mapped access to flash,
+ * Minimum Read size = 1Byte
+ * @param[in] src_off source offset from where data to read from flash,
+ * needs to be word aligned
+ * @param[out] des Destination location where data needs to be copied
+ * @param[in] len length in Bytes,where 1-word=4-bytes/32-bits
+ *
+ * @return XSPI_SUCCESS or error code
+ */
+int xspi_ahb_read(uint32_t src_off, uint32_t *des, uint32_t len);
+/*!
+ * @details IP read, READ via RX buffer from flash, minimum READ size = 1Byte
+ * @param[in] src_off source offset from where data to be read from flash
+ * @param[out] des Destination location where data needs to be copied
+ * @param[in] len length in Bytes,where 1-word=4-bytes/32-bits
+ *
+ * @return XSPI_SUCCESS or error code
+ */
+int xspi_ip_read(uint32_t src_off, uint32_t *des, uint32_t len);
+/*!
+ * @details CHIP erase, Erase complete chip in one go
+ *
+ * @return XSPI_SUCCESS or error code
+ */
+int xspi_bulk_erase(void);
+
+/*!
+ * Add test cases to confirm flash read/erase/write functionality.
+ */
+void fspi_test(uint32_t fspi_test_addr, uint32_t size, int extra);
+#endif /* FSPI_API_H */
diff --git a/include/drivers/nxp/flexspi/xspi_error_codes.h b/include/drivers/nxp/flexspi/xspi_error_codes.h
new file mode 100644
index 0000000..18b31eb
--- /dev/null
+++ b/include/drivers/nxp/flexspi/xspi_error_codes.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/* error codes */
+#ifndef XSPI_ERROR_CODES_H
+#define XSPI_ERROR_CODES_H
+
+#include <errno.h>
+
+typedef enum {
+ XSPI_SUCCESS = 0,
+ XSPI_READ_FAIL = ELAST + 1,
+ XSPI_ERASE_FAIL,
+ XSPI_IP_READ_FAIL,
+ XSPI_AHB_READ_FAIL,
+ XSPI_IP_WRITE_FAIL,
+ XSPI_AHB_WRITE_FAIL,
+ XSPI_BLOCK_TIMEOUT,
+ XSPI_UNALIGN_ADDR,
+ XSPI_UNALIGN_SIZE,
+} XSPI_STATUS_CODES;
+#undef ELAST
+#define ELAST XSPI_STATUS_CODES.XSPI_UNALIGN_SIZE
+#endif
diff --git a/include/drivers/nxp/gic/gicv2/plat_gic.h b/include/drivers/nxp/gic/gicv2/plat_gic.h
new file mode 100644
index 0000000..ff34744
--- /dev/null
+++ b/include/drivers/nxp/gic/gicv2/plat_gic.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PLAT_GICV2_H
+#define PLAT_GICV2_H
+
+#include <drivers/arm/gicv2.h>
+
+ /* register offsets */
+#define GICD_CTLR_OFFSET 0x0
+#define GICD_CPENDSGIR3_OFFSET 0xF1C
+#define GICD_SPENDSGIR3_OFFSET 0xF2C
+#define GICD_SGIR_OFFSET 0xF00
+#define GICD_IGROUPR0_OFFSET 0x080
+#define GICD_TYPER_OFFSET 0x0004
+#define GICD_ISENABLER0_OFFSET 0x0100
+#define GICD_ICENABLER0_OFFSET 0x0180
+#define GICD_IPRIORITYR3_OFFSET 0x040C
+#define GICD_ISENABLERn_OFFSET 0x0100
+#define GICD_ISACTIVER0_OFFSET 0x300
+
+#define GICC_CTLR_OFFSET 0x0
+#define GICC_PMR_OFFSET 0x0004
+#define GICC_IAR_OFFSET 0x000C
+#define GICC_DIR_OFFSET 0x1000
+#define GICC_EOIR_OFFSET 0x0010
+
+ /* bitfield masks */
+#define GICC_CTLR_EN_GRP0 0x1
+#define GICC_CTLR_EN_GRP1 0x2
+#define GICC_CTLR_EOImodeS_MASK 0x200
+#define GICC_CTLR_DIS_BYPASS 0x60
+#define GICC_CTLR_CBPR_MASK 0x10
+#define GICC_CTLR_FIQ_EN_MASK 0x8
+#define GICC_CTLR_ACKCTL_MASK 0x4
+#define GICC_PMR_FILTER 0xFF
+
+#define GICD_CTLR_EN_GRP0 0x1
+#define GICD_CTLR_EN_GRP1 0x2
+#define GICD_IGROUP0_SGI15 0x8000
+#define GICD_ISENABLE0_SGI15 0x8000
+#define GICD_ICENABLE0_SGI15 0x8000
+#define GICD_ISACTIVER0_SGI15 0x8000
+#define GICD_CPENDSGIR_CLR_MASK 0xFF000000
+#define GICD_IPRIORITY_SGI15_MASK 0xFF000000
+#define GICD_SPENDSGIR3_SGI15_MASK 0xFF000000
+#define GICD_SPENDSGIR3_SGI15_OFFSET 0x18
+
+#ifndef __ASSEMBLER__
+
+/* GIC common API's */
+void plat_ls_gic_driver_init(const uintptr_t nxp_gicd_addr,
+ const uintptr_t nxp_gicc_addr,
+ uint8_t plat_core_count,
+ interrupt_prop_t *ls_interrupt_props,
+ uint8_t ls_interrupt_prop_count,
+ uint32_t *target_mask_array);
+void plat_ls_gic_init(void);
+void plat_ls_gic_cpuif_enable(void);
+void plat_ls_gic_cpuif_disable(void);
+void plat_ls_gic_redistif_on(void);
+void plat_ls_gic_redistif_off(void);
+void plat_gic_pcpu_init(void);
+/* GIC utility functions */
+void get_gic_offset(uint32_t *gicc_base, uint32_t *gicd_base);
+#endif
+
+#endif /* PLAT_GICV2_H */
diff --git a/include/drivers/nxp/gic/gicv3/plat_gic.h b/include/drivers/nxp/gic/gicv3/plat_gic.h
new file mode 100644
index 0000000..794b06b
--- /dev/null
+++ b/include/drivers/nxp/gic/gicv3/plat_gic.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2021-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PLAT_GICV3_H
+#define PLAT_GICV3_H
+
+#include <drivers/arm/gicv3.h>
+
+ /* offset between redistributors */
+#define GIC_RD_OFFSET 0x00020000
+ /* offset between SGI's */
+#define GIC_SGI_OFFSET 0x00020000
+ /* offset from rd base to sgi base */
+#define GIC_RD_2_SGI_OFFSET 0x00010000
+
+ /* register offsets */
+#define GICD_CTLR_OFFSET 0x0
+#define GICD_CLR_SPI_SR 0x58
+#define GICD_IGROUPR_2 0x88
+#define GICD_ISENABLER_1 0x104
+#define GICD_ICENABLER_1 0x184
+#define GICD_ISENABLER_2 0x108
+#define GICD_ICENABLER_2 0x188
+#define GICD_ISENABLER_3 0x10c
+#define GICD_ICENABLER_3 0x18c
+#define GICD_ICPENDR_2 0x288
+#define GICD_ICACTIVER_2 0x388
+#define GICD_IPRIORITYR_22 0x458
+#define GICD_ICFGR_5 0xC14
+#define GICD_IGRPMODR_2 0xD08
+
+#define GICD_IROUTER60_OFFSET 0x61e0
+#define GICD_IROUTER76_OFFSET 0x6260
+#define GICD_IROUTER89_OFFSET 0x62C8
+#define GICD_IROUTER112_OFFSET 0x6380
+#define GICD_IROUTER113_OFFSET 0x6388
+
+#define GICR_ICENABLER0_OFFSET 0x180
+#define GICR_CTLR_OFFSET 0x0
+#define GICR_IGROUPR0_OFFSET 0x80
+#define GICR_IGRPMODR0_OFFSET 0xD00
+#define GICR_IPRIORITYR3_OFFSET 0x40C
+#define GICR_ICPENDR0_OFFSET 0x280
+#define GICR_ISENABLER0_OFFSET 0x100
+#define GICR_TYPER_OFFSET 0x8
+#define GICR_WAKER_OFFSET 0x14
+#define GICR_ICACTIVER0_OFFSET 0x380
+#define GICR_ICFGR0_OFFSET 0xC00
+
+ /* bitfield masks */
+#define GICD_CTLR_EN_GRP_MASK 0x7
+#define GICD_CTLR_EN_GRP_1NS 0x2
+#define GICD_CTLR_EN_GRP_1S 0x4
+#define GICD_CTLR_EN_GRP_0 0x1
+#define GICD_CTLR_ARE_S_MASK 0x10
+#define GICD_CTLR_RWP 0x80000000
+
+#define GICR_ICENABLER0_SGI15 0x00008000
+#define GICR_CTLR_RWP 0x8
+#define GICR_IGROUPR0_SGI15 0x00008000
+#define GICR_IGRPMODR0_SGI15 0x00008000
+#define GICR_ISENABLER0_SGI15 0x00008000
+#define GICR_IPRIORITYR3_SGI15_MASK 0xFF000000
+#define GICR_ICPENDR0_SGI15 0x8000
+
+#define GIC_SPI_89_MASK 0x02000000
+#define GIC_SPI89_PRIORITY_MASK 0xFF00
+#define GIC_IRM_SPI89 0x80000000
+
+#define GICD_IROUTER_VALUE 0x100
+#define GICD_ISENABLER_1_VALUE 0x10000000
+#define GICD_ISENABLER_2_VALUE 0x100
+#define GICD_ISENABLER_3_VALUE 0x20100
+#define GICR_WAKER_SLEEP_BIT 0x2
+#define GICR_WAKER_ASLEEP (1 << 2 | 1 << 1)
+
+#define ICC_SRE_EL3_SRE 0x1
+#define ICC_IGRPEN0_EL1_EN 0x1
+#define ICC_CTLR_EL3_CBPR_EL1S 0x1
+#define ICC_CTLR_EL3_RM 0x20
+#define ICC_CTLR_EL3_EOIMODE_EL3 0x4
+#define ICC_CTLR_EL3_PMHE 0x40
+#define ICC_PMR_EL1_P_FILTER 0xFF
+#define ICC_IAR0_EL1_SGI15 0xF
+#define ICC_SGI0R_EL1_INTID 0x0F000000
+#define ICC_IAR0_INTID_SPI_89 0x59
+
+#define ICC_IGRPEN1_EL1 S3_0_C12_C12_7
+#define ICC_PMR_EL1 S3_0_C4_C6_0
+#define ICC_SRE_EL3 S3_6_C12_C12_5
+#define ICC_CTLR_EL3 S3_6_C12_C12_4
+#define ICC_SRE_EL2 S3_4_C12_C9_5
+#define ICC_CTLR_EL1 S3_0_C12_C12_4
+
+#ifndef __ASSEMBLER__
+
+/* GIC common API's */
+typedef unsigned int (*my_core_pos_fn)(void);
+
+void plat_ls_gic_driver_init(const uintptr_t nxp_gicd_addr,
+ const uintptr_t nxp_gicr_addr,
+ uint8_t plat_core_count,
+ interrupt_prop_t *ls_interrupt_props,
+ uint8_t ls_interrupt_prop_count,
+ uintptr_t *target_mask_array,
+ mpidr_hash_fn mpidr_to_core_pos);
+//void plat_ls_gic_driver_init(void);
+void plat_ls_gic_init(void);
+void plat_ls_gic_cpuif_enable(void);
+void plat_ls_gic_cpuif_disable(void);
+void plat_ls_gic_redistif_on(void);
+void plat_ls_gic_redistif_off(void);
+void plat_gic_pcpu_init(void);
+#endif
+
+#endif /* PLAT_GICV3_H */
diff --git a/include/drivers/nxp/gpio/nxp_gpio.h b/include/drivers/nxp/gpio/nxp_gpio.h
new file mode 100644
index 0000000..df75840
--- /dev/null
+++ b/include/drivers/nxp/gpio/nxp_gpio.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PLAT_GPIO_H
+#define PLAT_GPIO_H
+
+#include <endian.h>
+#include <lib/mmio.h>
+
+/* GPIO Register offset */
+#define GPIO_SEL_MASK 0x7F
+#define GPIO_BIT_MASK 0x1F
+#define GPDIR_REG_OFFSET 0x0
+#define GPDAT_REG_OFFSET 0x8
+
+#define GPIO_ID_BASE_ADDR_SHIFT 5U
+#define GPIO_BITS_PER_BASE_REG 32U
+
+#define GPIO_0 0
+#define GPIO_1 1
+#define GPIO_2 2
+#define GPIO_3 3
+
+#define GPIO_SUCCESS 0x0
+#define GPIO_FAILURE 0x1
+
+#ifdef NXP_GPIO_BE
+#define gpio_read32(a) bswap32(mmio_read_32((uintptr_t)(a)))
+#define gpio_write32(a, v) mmio_write_32((uintptr_t)(a), bswap32(v))
+#elif defined(NXP_GPIO_LE)
+#define gpio_read32(a) mmio_read_32((uintptr_t)(a))
+#define gpio_write32(a, v) mmio_write_32((uintptr_t)(a), (v))
+#else
+#error Please define GPIO register endianness
+#endif
+
+typedef struct {
+ uintptr_t gpio1_base_addr;
+ uintptr_t gpio2_base_addr;
+ uintptr_t gpio3_base_addr;
+ uintptr_t gpio4_base_addr;
+} gpio_init_info_t;
+
+void gpio_init(gpio_init_info_t *gpio_init_data);
+uint32_t *select_gpio_n_bitnum(uint32_t povdd_gpio, uint32_t *bit_num);
+int clr_gpio_bit(uint32_t *gpio_base_addr, uint32_t bit_num);
+int set_gpio_bit(uint32_t *gpio_base_addr, uint32_t bit_num);
+
+#endif /* PLAT_GPIO_H */
diff --git a/include/drivers/nxp/i2c/i2c.h b/include/drivers/nxp/i2c/i2c.h
new file mode 100644
index 0000000..85e6eb4
--- /dev/null
+++ b/include/drivers/nxp/i2c/i2c.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+
+#ifndef I2C_H
+#define I2C_H
+
+#include <lib/mmio.h>
+
+#define I2C_TIMEOUT 1000 /* ms */
+
+#define I2C_FD_CONSERV 0x7e
+#define I2C_CR_DIS (1 << 7)
+#define I2C_CR_EN (0 << 7)
+#define I2C_CR_MA (1 << 5)
+#define I2C_CR_TX (1 << 4)
+#define I2C_CR_TX_NAK (1 << 3)
+#define I2C_CR_RSTA (1 << 2)
+#define I2C_SR_BB (1 << 5)
+#define I2C_SR_IDLE (0 << 5)
+#define I2C_SR_AL (1 << 4)
+#define I2C_SR_IF (1 << 1)
+#define I2C_SR_RX_NAK (1 << 0)
+#define I2C_SR_RST (I2C_SR_AL | I2C_SR_IF)
+
+#define I2C_GLITCH_EN 0x8
+
+#define i2c_in(a) mmio_read_8((uintptr_t)(a))
+#define i2c_out(a, v) mmio_write_8((uintptr_t)(a), (v))
+
+struct ls_i2c {
+ unsigned char ad; /* I2c Bus Address Register */
+ unsigned char fd; /* I2c Bus Frequency Dividor Register */
+ unsigned char cr; /* I2c Bus Control Register */
+ unsigned char sr; /* I2c Bus Status Register */
+ unsigned char dr; /* I2C Bus Data I/O Register */
+ unsigned char ic; /* I2C Bus Interrupt Config Register */
+ unsigned char dbg; /* I2C Bus Debug Register */
+};
+
+void i2c_init(uintptr_t nxp_i2c_addr);
+int i2c_read(unsigned char chip, int addr, int alen,
+ unsigned char *buf, int len);
+int i2c_write(unsigned char chip, int addr, int alen,
+ const unsigned char *buf, int len);
+int i2c_probe_chip(unsigned char chip);
+
+#endif /* I2C_H */
diff --git a/include/drivers/nxp/ifc/ifc_nand.h b/include/drivers/nxp/ifc/ifc_nand.h
new file mode 100644
index 0000000..dbcd762
--- /dev/null
+++ b/include/drivers/nxp/ifc/ifc_nand.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IFC_NAND_H
+#define IFC_NAND_H
+
+#define NXP_IFC_SRAM_BUFFER_SIZE UL(0x100000) /* 1M */
+
+int ifc_nand_init(uintptr_t *block_dev_spec,
+ uintptr_t ifc_region_addr,
+ uintptr_t ifc_register_addr,
+ size_t ifc_sram_size,
+ uintptr_t ifc_nand_blk_offset,
+ size_t ifc_nand_blk_size);
+
+#endif /*IFC_NAND_H*/
diff --git a/include/drivers/nxp/ifc/ifc_nor.h b/include/drivers/nxp/ifc/ifc_nor.h
new file mode 100644
index 0000000..ee14460
--- /dev/null
+++ b/include/drivers/nxp/ifc/ifc_nor.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2020-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef IFC_NOR_H
+#define IFC_NOR_H
+
+
+int ifc_nor_init(uintptr_t flash_addr, size_t flash_size);
+
+#endif /*IFC_NOR_H*/
diff --git a/include/drivers/nxp/interconnect/ls_interconnect.h b/include/drivers/nxp/interconnect/ls_interconnect.h
new file mode 100644
index 0000000..777089c
--- /dev/null
+++ b/include/drivers/nxp/interconnect/ls_interconnect.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2020-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef LS_INTERCONNECT_H
+#define LS_INTERCONNECT_H
+
+#if (INTERCONNECT == CCI400)
+#define CCI_TERMINATE_BARRIER_TX 0x8
+#endif
+
+/* Interconnect CCI/CCN functions */
+void plat_ls_interconnect_enter_coherency(unsigned int num_clusters);
+void plat_ls_interconnect_exit_coherency(void);
+
+#endif
diff --git a/include/drivers/nxp/pmu/pmu.h b/include/drivers/nxp/pmu/pmu.h
new file mode 100644
index 0000000..28199e8
--- /dev/null
+++ b/include/drivers/nxp/pmu/pmu.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PMU_H
+#define PMU_H
+
+/* PMU Registers' OFFSET */
+#define PMU_PCPW20SR_OFFSET 0x830
+#define PMU_CLL2FLUSHSETR_OFFSET 0x1110
+#define PMU_CLSL2FLUSHCLRR_OFFSET 0x1114
+#define PMU_CLL2FLUSHSR_OFFSET 0x1118
+#define PMU_POWMGTCSR_VAL (1 << 20)
+
+/* PMU Registers */
+#define CORE_TIMEBASE_ENBL_OFFSET 0x8A0
+#define CLUST_TIMER_BASE_ENBL_OFFSET 0x18A0
+
+#define PMU_IDLE_CLUSTER_MASK 0x2
+#define PMU_FLUSH_CLUSTER_MASK 0x2
+#define PMU_IDLE_CORE_MASK 0xfe
+
+/* pmu register offsets and bitmaps */
+#define PMU_POWMGTDCR0_OFFSET 0xC20
+#define PMU_POWMGTCSR_OFFSET 0x4000
+#define PMU_CLAINACTSETR_OFFSET 0x1100
+#define PMU_CLAINACTCLRR_OFFSET 0x1104
+#define PMU_CLSINACTSETR_OFFSET 0x1108
+#define PMU_CLSINACTCLRR_OFFSET 0x110C
+#define PMU_CLL2FLUSHSETR_OFFSET 0x1110
+#define PMU_CLL2FLUSHCLRR_OFFSET 0x1114
+#define PMU_IPPDEXPCR0_OFFSET 0x4040
+#define PMU_IPPDEXPCR1_OFFSET 0x4044
+#define PMU_IPPDEXPCR2_OFFSET 0x4048
+#define PMU_IPPDEXPCR3_OFFSET 0x404C
+#define PMU_IPPDEXPCR4_OFFSET 0x4050
+#define PMU_IPPDEXPCR5_OFFSET 0x4054
+#define PMU_IPPDEXPCR6_OFFSET 0x4058
+#define PMU_IPSTPCR0_OFFSET 0x4120
+#define PMU_IPSTPCR1_OFFSET 0x4124
+#define PMU_IPSTPCR2_OFFSET 0x4128
+#define PMU_IPSTPCR3_OFFSET 0x412C
+#define PMU_IPSTPCR4_OFFSET 0x4130
+#define PMU_IPSTPCR5_OFFSET 0x4134
+#define PMU_IPSTPCR6_OFFSET 0x4138
+#define PMU_IPSTPACKSR0_OFFSET 0x4140
+#define PMU_IPSTPACKSR1_OFFSET 0x4144
+#define PMU_IPSTPACKSR2_OFFSET 0x4148
+#define PMU_IPSTPACKSR3_OFFSET 0x414C
+#define PMU_IPSTPACKSR4_OFFSET 0x4150
+#define PMU_IPSTPACKSR5_OFFSET 0x4154
+#define PMU_IPSTPACKSR6_OFFSET 0x4158
+
+#define CLAINACT_DISABLE_ACP 0xFF
+#define CLSINACT_DISABLE_SKY 0xFF
+#define POWMGTDCR_STP_OV_EN 0x1
+#define POWMGTCSR_LPM20_REQ 0x00100000
+
+/* Used by PMU */
+#define DEVDISR1_MASK 0x024F3504
+#define DEVDISR2_MASK 0x0003FFFF
+#define DEVDISR3_MASK 0x0000303F
+#define DEVDISR4_MASK 0x0000FFFF
+#define DEVDISR5_MASK 0x00F07603
+#define DEVDISR6_MASK 0x00000001
+
+#ifndef __ASSEMBLER__
+void enable_timer_base_to_cluster(uintptr_t nxp_pmu_addr);
+void enable_core_tb(uintptr_t nxp_pmu_addr);
+#endif /* __ASSEMBLER__ */
+
+#endif
diff --git a/include/drivers/nxp/qspi/qspi.h b/include/drivers/nxp/qspi/qspi.h
new file mode 100644
index 0000000..db11c3b
--- /dev/null
+++ b/include/drivers/nxp/qspi/qspi.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef QSPI_H
+#define QSPI_H
+
+#include <endian.h>
+#include <lib/mmio.h>
+
+#define CHS_QSPI_MCR 0x01550000
+#define CHS_QSPI_64LE 0xC
+
+#ifdef NXP_QSPI_BE
+#define qspi_in32(a) bswap32(mmio_read_32((uintptr_t)(a)))
+#define qspi_out32(a, v) mmio_write_32((uintptr_t)(a), bswap32(v))
+#elif defined(NXP_QSPI_LE)
+#define qspi_in32(a) mmio_read_32((uintptr_t)(a))
+#define qspi_out32(a, v) mmio_write_32((uintptr_t)(a), (v))
+#else
+#error Please define CCSR QSPI register endianness
+#endif
+
+int qspi_io_setup(uintptr_t nxp_qspi_flash_addr,
+ size_t nxp_qspi_flash_size,
+ uintptr_t fip_offset);
+#endif /* __QSPI_H__ */
diff --git a/include/drivers/nxp/sd/sd_mmc.h b/include/drivers/nxp/sd/sd_mmc.h
new file mode 100644
index 0000000..32b41f1
--- /dev/null
+++ b/include/drivers/nxp/sd/sd_mmc.h
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2015, 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef SD_MMC_H
+#define SD_MMC_H
+
+#include <lib/mmio.h>
+
+/* operating freq */
+#define CARD_IDENTIFICATION_FREQ 400000
+#define SD_SS_25MHZ 20000000
+#define SD_HS_50MHZ 40000000
+#define MMC_SS_20MHZ 15000000
+#define MMC_HS_26MHZ 20000000
+#define MMC_HS_52MHZ 40000000
+
+/* Need to check this value ? */
+#define MAX_PLATFORM_CLOCK 800000000
+
+/* eSDHC system control register defines */
+#define ESDHC_SYSCTL_DTOCV(t) (((t) & 0xF) << 16)
+#define ESDHC_SYSCTL_SDCLKFS(f) (((f) & 0xFF) << 8)
+#define ESDHC_SYSCTL_DVS(d) (((d) & 0xF) << 4)
+#define ESDHC_SYSCTL_SDCLKEN (0x00000008)
+#define ESDHC_SYSCTL_RSTA (0x01000000)
+
+/* Data timeout counter value. SDHC_CLK x 227 */
+#define TIMEOUT_COUNTER_SDCLK_2_27 0xE
+#define ESDHC_SYSCTL_INITA 0x08000000
+
+/* eSDHC interrupt status enable register defines */
+#define ESDHC_IRQSTATEN_CINS 0x00000040
+#define ESDHC_IRQSTATEN_BWR 0x00000010
+
+/* eSDHC interrupt status register defines */
+#define ESDHC_IRQSTAT_DMAE (0x10000000)
+#define ESDHC_IRQSTAT_AC12E (0x01000000)
+#define ESDHC_IRQSTAT_DEBE (0x00400000)
+#define ESDHC_IRQSTAT_DCE (0x00200000)
+#define ESDHC_IRQSTAT_DTOE (0x00100000)
+#define ESDHC_IRQSTAT_CIE (0x00080000)
+#define ESDHC_IRQSTAT_CEBE (0x00040000)
+#define ESDHC_IRQSTAT_CCE (0x00020000)
+#define ESDHC_IRQSTAT_CTOE (0x00010000)
+#define ESDHC_IRQSTAT_CINT (0x00000100)
+#define ESDHC_IRQSTAT_CRM (0x00000080)
+#define ESDHC_IRQSTAT_CINS (0x00000040)
+#define ESDHC_IRQSTAT_BRR (0x00000020)
+#define ESDHC_IRQSTAT_BWR (0x00000010)
+#define ESDHC_IRQSTAT_DINT (0x00000008)
+#define ESDHC_IRQSTAT_BGE (0x00000004)
+#define ESDHC_IRQSTAT_TC (0x00000002)
+#define ESDHC_IRQSTAT_CC (0x00000001)
+#define ESDHC_IRQSTAT_CMD_ERR (ESDHC_IRQSTAT_CIE |\
+ ESDHC_IRQSTAT_CEBE |\
+ ESDHC_IRQSTAT_CCE)
+#define ESDHC_IRQSTAT_DATA_ERR (ESDHC_IRQSTAT_DEBE |\
+ ESDHC_IRQSTAT_DCE |\
+ ESDHC_IRQSTAT_DTOE)
+#define ESDHC_IRQSTAT_CLEAR_ALL (0xFFFFFFFF)
+
+/* eSDHC present state register defines */
+#define ESDHC_PRSSTAT_CLSL 0x00800000
+#define ESDHC_PRSSTAT_WPSPL 0x00080000
+#define ESDHC_PRSSTAT_CDPL 0x00040000
+#define ESDHC_PRSSTAT_CINS 0x00010000
+#define ESDHC_PRSSTAT_BREN 0x00000800
+#define ESDHC_PRSSTAT_BWEN 0x00000400
+#define ESDHC_PRSSTAT_RTA 0x00000200
+#define ESDHC_PRSSTAT_WTA 0x00000100
+#define ESDHC_PRSSTAT_SDOFF 0x00000080
+#define ESDHC_PRSSTAT_PEROFF 0x00000040
+#define ESDHC_PRSSTAT_HCKOFF 0x00000020
+#define ESDHC_PRSSTAT_IPGOFF 0x00000010
+#define ESDHC_PRSSTAT_DLA 0x00000004
+#define ESDHC_PRSSTAT_CDIHB 0x00000002
+#define ESDHC_PRSSTAT_CIHB 0x00000001
+
+/* eSDHC protocol control register defines */
+#define ESDHC_PROCTL_EMODE_LE 0x00000020
+#define ESDHC_PROCTL_DTW_1BIT 0x00000000
+#define ESDHC_PROCTL_DTW_4BIT 0x00000002
+#define ESDHC_PROCTL_DTW_8BIT 0x00000004
+
+/* Watermark Level Register (WML) */
+#define ESDHC_WML_RD_WML(w) ((w) & 0x7F)
+#define ESDHC_WML_WR_WML(w) (((w) & 0x7F) << 16)
+#define ESDHC_WML_RD_BRST(w) (((w) & 0xF) << 8)
+#define ESDHC_WML_WR_BRST(w) (((w) & 0xF) << 24)
+#define ESDHC_WML_WR_BRST_MASK (0x0F000000)
+#define ESDHC_WML_RD_BRST_MASK (0x00000F00)
+#define ESDHC_WML_RD_WML_MASK (0x0000007F)
+#define ESDHC_WML_WR_WML_MASK (0x007F0000)
+#define WML_512_BYTES (0x0)
+#define BURST_128_BYTES (0x0)
+
+/* eSDHC control register define */
+#define ESDHC_DCR_SNOOP 0x00000040
+
+/* ESDHC Block attributes register */
+#define ESDHC_BLKATTR_BLKCNT(c) (((c) & 0xffff) << 16)
+#define ESDHC_BLKATTR_BLKSZE(s) ((s) & 0xfff)
+
+/* Transfer Type Register */
+#define ESDHC_XFERTYP_CMD(c) (((c) & 0x3F) << 24)
+#define ESDHC_XFERTYP_CMDTYP_NORMAL (0x0)
+#define ESDHC_XFERTYP_CMDTYP_SUSPEND (0x00400000)
+#define ESDHC_XFERTYP_CMDTYP_RESUME (0x00800000)
+#define ESDHC_XFERTYP_CMDTYP_ABORT (0x00C00000)
+#define ESDHC_XFERTYP_DPSEL (0x00200000)
+#define ESDHC_XFERTYP_CICEN (0x00100000)
+#define ESDHC_XFERTYP_CCCEN (0x00080000)
+#define ESDHC_XFERTYP_RSPTYP_NONE (0x0)
+#define ESDHC_XFERTYP_RSPTYP_136 (0x00010000)
+#define ESDHC_XFERTYP_RSPTYP_48 (0x00020000)
+#define ESDHC_XFERTYP_RSPTYP_48_BUSY (0x00030000)
+#define ESDHC_XFERTYP_MSBSEL (0x00000020)
+#define ESDHC_XFERTYP_DTDSEL (0x00000010)
+#define ESDHC_XFERTYP_AC12EN (0x00000004)
+#define ESDHC_XFERTYP_BCEN (0x00000002)
+#define ESDHC_XFERTYP_DMAEN (0x00000001)
+
+#define MMC_VDD_HIGH_VOLTAGE 0x00000100
+
+/* command index */
+#define CMD0 0
+#define CMD1 1
+#define CMD2 2
+#define CMD3 3
+#define CMD5 5
+#define CMD6 6
+#define CMD7 7
+#define CMD8 8
+#define CMD9 9
+#define CMD12 12
+#define CMD13 13
+#define CMD14 14
+#define CMD16 16
+#define CMD17 17
+#define CMD18 18
+#define CMD19 19
+#define CMD24 24
+#define CMD41 41
+#define CMD42 42
+#define CMD51 51
+#define CMD55 55
+#define CMD56 56
+#define ACMD6 CMD6
+#define ACMD13 CMD13
+#define ACMD41 CMD41
+#define ACMD42 CMD42
+#define ACMD51 CMD51
+
+/* commands abbreviations */
+#define CMD_GO_IDLE_STATE CMD0
+#define CMD_MMC_SEND_OP_COND CMD1
+#define CMD_ALL_SEND_CID CMD2
+#define CMD_SEND_RELATIVE_ADDR CMD3
+#define CMD_SET_DSR CMD4
+#define CMD_SWITCH_FUNC CMD6
+#define CMD_SELECT_CARD CMD7
+#define CMD_DESELECT_CARD CMD7
+#define CMD_SEND_IF_COND CMD8
+#define CMD_MMC_SEND_EXT_CSD CMD8
+#define CMD_SEND_CSD CMD9
+#define CMD_SEND_CID CMD10
+#define CMD_STOP_TRANSMISSION CMD12
+#define CMD_SEND_STATUS CMD13
+#define CMD_BUS_TEST_R CMD14
+#define CMD_GO_INACTIVE_STATE CMD15
+#define CMD_SET_BLOCKLEN CMD16
+#define CMD_READ_SINGLE_BLOCK CMD17
+#define CMD_READ_MULTIPLE_BLOCK CMD18
+#define CMD_WRITE_SINGLE_BLOCK CMD24
+#define CMD_BUS_TEST_W CMD19
+#define CMD_APP_CMD CMD55
+#define CMD_GEN_CMD CMD56
+#define CMD_SET_BUS_WIDTH ACMD6
+#define CMD_SD_STATUS ACMD13
+#define CMD_SD_SEND_OP_COND ACMD41
+#define CMD_SET_CLR_CARD_DETECT ACMD42
+#define CMD_SEND_SCR ACMD51
+
+/* MMC card spec version */
+#define MMC_CARD_VERSION_1_2 0
+#define MMC_CARD_VERSION_1_4 1
+#define MMC_CARD_VERSION_2_X 2
+#define MMC_CARD_VERSION_3_X 3
+#define MMC_CARD_VERSION_4_X 4
+
+/* SD Card Spec Version */
+/* May need to add version 3 here? */
+#define SD_CARD_VERSION_1_0 0
+#define SD_CARD_VERSION_1_10 1
+#define SD_CARD_VERSION_2_0 2
+
+/* card types */
+#define MMC_CARD 0
+#define SD_CARD 1
+#define NOT_SD_CARD MMC_CARD
+
+/* Card rca */
+#define SD_MMC_CARD_RCA 0x1
+#define BLOCK_LEN_512 512
+
+/* card state */
+#define STATE_IDLE 0
+#define STATE_READY 1
+#define STATE_IDENT 2
+#define STATE_STBY 3
+#define STATE_TRAN 4
+#define STATE_DATA 5
+#define STATE_RCV 6
+#define STATE_PRG 7
+#define STATE_DIS 8
+
+/* Card OCR register */
+/* VDD voltage window 1,65 to 1.95 */
+#define MMC_OCR_VDD_165_195 0x00000080
+/* VDD voltage window 2.7-2.8 */
+#define MMC_OCR_VDD_FF8 0x00FF8000
+#define MMC_OCR_CCS 0x40000000/* Card Capacity */
+#define MMC_OCR_BUSY 0x80000000/* busy bit */
+#define SD_OCR_HCS 0x40000000/* High capacity host */
+#define MMC_OCR_SECTOR_MODE 0x40000000/* Access Mode as Sector */
+
+/* mmc Switch function */
+#define SET_EXT_CSD_HS_TIMING 0x03B90100/* set High speed */
+
+/* check supports switching or not */
+#define SD_SWITCH_FUNC_CHECK_MODE 0x00FFFFF1
+#define SD_SWITCH_FUNC_SWITCH_MODE 0x80FFFFF1/* switch */
+#define SD_SWITCH_FUNC_HIGH_SPEED 0x02/* HIGH SPEED FUNC */
+#define SWITCH_ERROR 0x00000080
+
+/* errors in sending commands */
+#define RESP_TIMEOUT 0x1
+#define COMMAND_ERROR 0x2
+/* error in response */
+#define R1_ERROR (1 << 19)
+#define R1_CURRENT_STATE(x) (((x) & 0x00001E00) >> 9)
+
+/* Host Controller Capabilities */
+#define ESDHC_HOSTCAPBLT_DMAS (0x00400000)
+
+
+/* SD/MMC memory map */
+struct esdhc_regs {
+ uint32_t dsaddr; /* dma system address */
+ uint32_t blkattr; /* Block attributes */
+ uint32_t cmdarg; /* Command argument */
+ uint32_t xfertyp; /* Command transfer type */
+ uint32_t cmdrsp[4]; /* Command response0,1,2,3 */
+ uint32_t datport; /* Data buffer access port */
+ uint32_t prsstat; /* Present state */
+ uint32_t proctl; /* Protocol control */
+ uint32_t sysctl; /* System control */
+ uint32_t irqstat; /* Interrupt status */
+ uint32_t irqstaten; /* Interrupt status enable */
+ uint32_t irqsigen; /* Interrupt signal enable */
+ uint32_t autoc12err; /* Auto CMD12 status */
+ uint32_t hostcapblt; /* Host controller capabilities */
+ uint32_t wml; /* Watermark level */
+ uint32_t res1[2];
+ uint32_t fevt; /* Force event */
+ uint32_t res2;
+ uint32_t adsaddrl;
+ uint32_t adsaddrh;
+ uint32_t res3[39];
+ uint32_t hostver; /* Host controller version */
+ uint32_t res4;
+ uint32_t dmaerr; /* DMA error address */
+ uint32_t dmaerrh; /* DMA error address high */
+ uint32_t dmaerrattr; /* DMA error atrribute */
+ uint32_t res5;
+ uint32_t hostcapblt2;/* Host controller capabilities2 */
+ uint32_t res6[2];
+ uint32_t tcr; /* Tuning control */
+ uint32_t res7[7];
+ uint32_t dirctrl; /* Direction control */
+ uint32_t ccr; /* Clock control */
+ uint32_t res8[177];
+ uint32_t ctl; /* Control register */
+};
+
+/* SD/MMC card attributes */
+struct card_attributes {
+ uint32_t type; /* sd or mmc card */
+ uint32_t version; /* version */
+ uint32_t block_len; /* block length */
+ uint32_t bus_freq; /* sdhc bus frequency */
+ uint16_t rca; /* relative card address */
+ uint8_t is_high_capacity; /* high capacity */
+};
+
+struct mmc {
+ struct esdhc_regs *esdhc_regs;
+ struct card_attributes card;
+
+ uint32_t block_len;
+ uint32_t voltages_caps; /* supported voltaes */
+ uint32_t dma_support; /* DMA support */
+};
+
+enum cntrl_num {
+ SDHC1 = 0,
+ SDHC2
+};
+
+int sd_emmc_init(uintptr_t *block_dev_spec,
+ uintptr_t nxp_esdhc_addr,
+ size_t nxp_sd_block_offset,
+ size_t nxp_sd_block_size,
+ bool card_detect);
+
+int esdhc_emmc_init(struct mmc *mmc, bool card_detect);
+int esdhc_read(struct mmc *mmc, uint32_t src_offset, uintptr_t dst,
+ size_t size);
+int esdhc_write(struct mmc *mmc, uintptr_t src, uint32_t dst_offset,
+ size_t size);
+
+#ifdef NXP_ESDHC_BE
+#define esdhc_in32(a) bswap32(mmio_read_32((uintptr_t)(a)))
+#define esdhc_out32(a, v) mmio_write_32((uintptr_t)(a), bswap32(v))
+#elif defined(NXP_ESDHC_LE)
+#define esdhc_in32(a) mmio_read_32((uintptr_t)(a))
+#define esdhc_out32(a, v) mmio_write_32((uintptr_t)(a), (v))
+#else
+#error Please define CCSR ESDHC register endianness
+#endif
+
+#endif /*SD_MMC_H*/
diff --git a/include/drivers/nxp/sec_mon/snvs.h b/include/drivers/nxp/sec_mon/snvs.h
new file mode 100644
index 0000000..4455383
--- /dev/null
+++ b/include/drivers/nxp/sec_mon/snvs.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef SNVS_H
+#define SNVS_H
+
+
+#ifndef __ASSEMBLER__
+
+#include <endian.h>
+#include <stdbool.h>
+
+#include <lib/mmio.h>
+
+struct snvs_regs {
+ uint32_t reserved1;
+ uint32_t hp_com; /* 0x04 SNVS_HP Command Register */
+ uint32_t reserved2[3];
+ uint32_t hp_stat; /* 0x14 SNVS_HP Status Register */
+};
+
+#ifdef NXP_SNVS_BE
+#define snvs_read32(a) bswap32(mmio_read_32((uintptr_t)(a)))
+#define snvs_write32(a, v) mmio_write_32((uintptr_t)(a), bswap32((v)))
+#elif defined(NXP_SNVS_LE)
+#define snvs_read32(a) mmio_read_32((uintptr_t)(a))
+#define snvs_write32(a, v) mmio_write_32((uintptr_t)(a), (v))
+#else
+#error Please define CCSR SNVS register endianness
+#endif
+
+void snvs_init(uintptr_t nxp_snvs_addr);
+uint32_t get_snvs_state(void);
+void transition_snvs_non_secure(void);
+void transition_snvs_soft_fail(void);
+uint32_t transition_snvs_trusted(void);
+uint32_t transition_snvs_secure(void);
+
+uint32_t snvs_read_lp_gpr_bit(uint32_t offset, uint32_t bit_pos);
+void snvs_write_lp_gpr_bit(uint32_t offset, uint32_t bit_pos, bool flag_val);
+
+void snvs_disable_zeroize_lp_gpr(void);
+
+#if defined(NXP_NV_SW_MAINT_LAST_EXEC_DATA) && defined(NXP_COINED_BB)
+uint32_t snvs_read_app_data(void);
+uint32_t snvs_read_app_data_bit(uint32_t bit_pos);
+void snvs_clear_app_data(void);
+void snvs_write_app_data_bit(uint32_t bit_pos);
+#endif
+
+#endif /* __ASSEMBLER__ */
+
+/* SSM_ST field in SNVS status reg */
+#define HPSTS_CHECK_SSM_ST 0x900 /* SNVS is in check state */
+#define HPSTS_NON_SECURE_SSM_ST 0xb00 /* SNVS is in non secure state */
+#define HPSTS_TRUST_SSM_ST 0xd00 /* SNVS is in trusted state */
+#define HPSTS_SECURE_SSM_ST 0xf00 /* SNVS is in secure state */
+#define HPSTS_SOFT_FAIL_SSM_ST 0x300 /* SNVS is in soft fail state */
+#define HPSTS_MASK_SSM_ST 0xf00 /* SSM_ST field mask in SNVS reg */
+
+/* SNVS register bits */
+#define HPCOM_SW_SV 0x100 /* Security Violation bit */
+#define HPCOM_SW_FSV 0x200 /* Fatal Security Violation bit */
+#define HPCOM_SSM_ST 0x1 /* SSM_ST field in SNVS command reg */
+#define HPCOM_SSM_ST_DIS 0x2 /* Disable Secure to Trusted State */
+#define HPCOM_SSM_SFNS_DIS 0x4 /* Disable Soft Fail to Non-Secure */
+
+#define NXP_LP_GPR0_OFFSET 0x90
+#define NXP_LPCR_OFFSET 0x38
+#define NXP_GPR_Z_DIS_BIT 24
+
+#ifdef NXP_COINED_BB
+
+#ifndef NXP_APP_DATA_LP_GPR_OFFSET
+#define NXP_APP_DATA_LP_GPR_OFFSET NXP_LP_GPR0_OFFSET
+#endif
+
+#define NXP_LPGPR_ZEROTH_BIT 0
+
+#endif /* NXP_COINED_BB */
+
+#endif /* SNVS_H */
diff --git a/include/drivers/nxp/sfp/fuse_prov.h b/include/drivers/nxp/sfp/fuse_prov.h
new file mode 100644
index 0000000..e015318
--- /dev/null
+++ b/include/drivers/nxp/sfp/fuse_prov.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#if !defined(FUSE_PROV_H) && defined(POLICY_FUSE_PROVISION)
+#define FUSE_PROV_H
+
+#include <endian.h>
+#include <lib/mmio.h>
+
+#define MASK_NONE U(0xFFFFFFFF)
+#define ERROR_WRITE U(0xA)
+#define ERROR_ALREADY_BLOWN U(0xB)
+
+/* Flag bit shifts */
+#define FLAG_POVDD_SHIFT U(0)
+#define FLAG_SYSCFG_SHIFT U(1)
+#define FLAG_SRKH_SHIFT U(2)
+#define FLAG_MC_SHIFT U(3)
+#define FLAG_DCV0_SHIFT U(4)
+#define FLAG_DCV1_SHIFT U(5)
+#define FLAG_DRV0_SHIFT U(6)
+#define FLAG_DRV1_SHIFT U(7)
+#define FLAG_OUID0_SHIFT U(8)
+#define FLAG_OUID1_SHIFT U(9)
+#define FLAG_OUID2_SHIFT U(10)
+#define FLAG_OUID3_SHIFT U(11)
+#define FLAG_OUID4_SHIFT U(12)
+#define FLAG_DBG_LVL_SHIFT U(13)
+#define FLAG_OTPMK_SHIFT U(16)
+#define FLAG_OUID_MASK U(0x1F)
+#define FLAG_DEBUG_MASK U(0xF)
+#define FLAG_OTPMK_MASK U(0xF)
+
+/* OTPMK flag values */
+#define PROG_OTPMK_MIN U(0x0)
+#define PROG_OTPMK_RANDOM U(0x1)
+#define PROG_OTPMK_USER U(0x2)
+#define PROG_OTPMK_RANDOM_MIN U(0x5)
+#define PROG_OTPMK_USER_MIN U(0x6)
+#define PROG_NO_OTPMK U(0x8)
+
+#define OTPMK_MIM_BITS_MASK U(0xF0000000)
+
+/* System configuration bit shifts */
+#define SCB_WP_SHIFT U(0)
+#define SCB_ITS_SHIFT U(2)
+#define SCB_NSEC_SHIFT U(4)
+#define SCB_ZD_SHIFT U(5)
+#define SCB_K0_SHIFT U(15)
+#define SCB_K1_SHIFT U(14)
+#define SCB_K2_SHIFT U(13)
+#define SCB_K3_SHIFT U(12)
+#define SCB_K4_SHIFT U(11)
+#define SCB_K5_SHIFT U(10)
+#define SCB_K6_SHIFT U(9)
+#define SCB_FR0_SHIFT U(30)
+#define SCB_FR1_SHIFT U(31)
+
+/* Fuse Header Structure */
+struct fuse_hdr_t {
+ uint8_t barker[4]; /* 0x00 Barker code */
+ uint32_t flags; /* 0x04 Script flags */
+ uint32_t povdd_gpio; /* 0x08 GPIO for POVDD */
+ uint32_t otpmk[8]; /* 0x0C-0x2B OTPMK */
+ uint32_t srkh[8]; /* 0x2C-0x4B SRKH */
+ uint32_t oem_uid[5]; /* 0x4C-0x5F OEM unique id's */
+ uint32_t dcv[2]; /* 0x60-0x67 Debug Challenge */
+ uint32_t drv[2]; /* 0x68-0x6F Debug Response */
+ uint32_t ospr1; /* 0x70 OSPR1 */
+ uint32_t sc; /* 0x74 OSPR0 (System Configuration) */
+ uint32_t reserved[2]; /* 0x78-0x7F Reserved */
+};
+
+/* Function to do fuse provisioning */
+int provision_fuses(unsigned long long fuse_scr_addr,
+ bool en_povdd_status);
+
+#define EFUSE_POWERUP_DELAY_mSec U(25)
+#endif /* FUSE_PROV_H */
diff --git a/include/drivers/nxp/sfp/sfp.h b/include/drivers/nxp/sfp/sfp.h
new file mode 100644
index 0000000..2cb4c7d
--- /dev/null
+++ b/include/drivers/nxp/sfp/sfp.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef SFP_H
+#define SFP_H
+
+#include <endian.h>
+#include <lib/mmio.h>
+
+/* SFP Configuration Register Offsets */
+#define SFP_INGR_OFFSET U(0x20)
+#define SFP_SVHESR_OFFSET U(0x24)
+#define SFP_SFPCR_OFFSET U(0x28)
+#define SFP_VER_OFFSET U(0x38)
+
+/* SFP Hamming register masks for OTPMK and DRV */
+#define SFP_SVHESR_DRV_MASK U(0x7F)
+#define SFP_SVHESR_OTPMK_MASK U(0x7FC00)
+
+/* SFP commands */
+#define SFP_INGR_READFB_CMD U(0x1)
+#define SFP_INGR_PROGFB_CMD U(0x2)
+#define SFP_INGR_ERROR_MASK U(0x100)
+
+/* SFPCR Masks */
+#define SFP_SFPCR_WD U(0x80000000)
+#define SFP_SFPCR_WDL U(0x40000000)
+
+/* SFPCR Masks */
+#define SFP_SFPCR_WD U(0x80000000)
+#define SFP_SFPCR_WDL U(0x40000000)
+
+#define SFP_FUSE_REGS_OFFSET U(0x200)
+
+#ifdef NXP_SFP_VER_3_4
+#define OSPR0_SC_MASK U(0xC000FE35)
+#elif defined(NXP_SFP_VER_3_2)
+#define OSPR0_SC_MASK U(0x0000E035)
+#endif
+
+#if defined(NXP_SFP_VER_3_4)
+#define OSPR_KEY_REVOC_SHIFT U(9)
+#define OSPR_KEY_REVOC_MASK U(0x0000fe00)
+#elif defined(NXP_SFP_VER_3_2)
+#define OSPR_KEY_REVOC_SHIFT U(13)
+#define OSPR_KEY_REVOC_MASK U(0x0000e000)
+#endif /* NXP_SFP_VER_3_4 */
+
+#define OSPR1_MC_MASK U(0xFFFF0000)
+#define OSPR1_DBG_LVL_MASK U(0x00000007)
+
+#define OSPR_ITS_MASK U(0x00000004)
+#define OSPR_WP_MASK U(0x00000001)
+
+#define MAX_OEM_UID U(5)
+#define SRK_HASH_SIZE U(32)
+
+/* SFP CCSR Register Map */
+struct sfp_ccsr_regs_t {
+ uint32_t ospr; /* 0x200 OSPR0 */
+ uint32_t ospr1; /* 0x204 OSPR1 */
+ uint32_t dcv[2]; /* 0x208 Debug Challenge Value */
+ uint32_t drv[2]; /* 0x210 Debug Response Value */
+ uint32_t fswpr; /* 0x218 FSL Section Write Protect */
+ uint32_t fsl_uid[2]; /* 0x21c FSL UID 0 */
+ uint32_t isbcr; /* 0x224 ISBC Configuration */
+ uint32_t fsspr[3]; /* 0x228 FSL Scratch Pad */
+ uint32_t otpmk[8]; /* 0x234 OTPMK */
+ uint32_t srk_hash[SRK_HASH_SIZE/sizeof(uint32_t)];
+ /* 0x254 Super Root Key Hash */
+ uint32_t oem_uid[MAX_OEM_UID]; /* 0x274 OEM UID 0 */
+};
+
+uintptr_t get_sfp_addr(void);
+void sfp_init(uintptr_t nxp_sfp_addr);
+uint32_t *get_sfp_srk_hash(void);
+int sfp_check_its(void);
+int sfp_check_oem_wp(void);
+uint32_t get_key_revoc(void);
+void set_sfp_wr_disable(void);
+int sfp_program_fuses(void);
+
+uint32_t sfp_read_oem_uid(uint8_t oem_uid);
+uint32_t sfp_write_oem_uid(uint8_t oem_uid, uint32_t sfp_val);
+
+#ifdef NXP_SFP_BE
+#define sfp_read32(a) bswap32(mmio_read_32((uintptr_t)(a)))
+#define sfp_write32(a, v) mmio_write_32((uintptr_t)(a), bswap32(v))
+#elif defined(NXP_SFP_LE)
+#define sfp_read32(a) mmio_read_32((uintptr_t)(a))
+#define sfp_write32(a, v) mmio_write_32((uintptr_t)(a), (v))
+#else
+#error Please define CCSR SFP register endianness
+#endif
+
+#endif/* SFP_H */
diff --git a/include/drivers/nxp/sfp/sfp_error_codes.h b/include/drivers/nxp/sfp/sfp_error_codes.h
new file mode 100644
index 0000000..7be7a27
--- /dev/null
+++ b/include/drivers/nxp/sfp/sfp_error_codes.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef SFP_ERROR_CODES_H
+#define SFP_ERROR_CODES_H
+
+ /* Error codes */
+#define ERROR_FUSE_BARKER 0x1
+#define ERROR_READFB_CMD 0x2
+#define ERROR_PROGFB_CMD 0x3
+#define ERROR_SRKH_ALREADY_BLOWN 0x4
+#define ERROR_SRKH_WRITE 0x5
+#define ERROR_OEMUID_ALREADY_BLOWN 0x6
+#define ERROR_OEMUID_WRITE 0x7
+#define ERROR_DCV_ALREADY_BLOWN 0x8
+#define ERROR_DCV_WRITE 0x9
+#define ERROR_DRV_ALREADY_BLOWN 0xa
+#define ERROR_DRV_HAMMING_ERROR 0xb
+#define ERROR_DRV_WRITE 0x18
+#define ERROR_OTPMK_ALREADY_BLOWN 0xc
+#define ERROR_OTPMK_HAMMING_ERROR 0xd
+#define ERROR_OTPMK_USER_MIN 0xe
+#define ERROR_OSPR1_ALREADY_BLOWN 0xf
+#define ERROR_OSPR1_WRITE 0x10
+#define ERROR_SC_ALREADY_BLOWN 0x11
+#define ERROR_SC_WRITE 0x12
+#define ERROR_POVDD_GPIO_FAIL 0x13
+#define ERROR_GPIO_SET_FAIL 0x14
+#define ERROR_GPIO_RESET_FAIL 0x15
+#define ERROR_OTPMK_SEC_DISABLED 0x16
+#define ERROR_OTPMK_SEC_ERROR 0x17
+#define ERROR_OTPMK_WRITE 0x19
+#define PLAT_ERROR_ENABLE_POVDD 0x20
+#define PLAT_ERROR_DISABLE_POVDD 0x21
+
+#endif /* SFP_ERROR_CODES_H */
diff --git a/include/drivers/nxp/smmu/nxp_smmu.h b/include/drivers/nxp/smmu/nxp_smmu.h
new file mode 100644
index 0000000..d64c33b
--- /dev/null
+++ b/include/drivers/nxp/smmu/nxp_smmu.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef NXP_SMMU_H
+#define NXP_SMMU_H
+
+#define SMMU_SCR0 (0x0)
+#define SMMU_NSCR0 (0x400)
+
+#define SCR0_CLIENTPD_MASK 0x00000001
+#define SCR0_USFCFG_MASK 0x00000400
+
+static inline void bypass_smmu(uintptr_t smmu_base_addr)
+{
+ uint32_t val;
+
+ val = (mmio_read_32(smmu_base_addr + SMMU_SCR0) | SCR0_CLIENTPD_MASK) &
+ ~(SCR0_USFCFG_MASK);
+ mmio_write_32((smmu_base_addr + SMMU_SCR0), val);
+
+ val = (mmio_read_32(smmu_base_addr + SMMU_NSCR0) | SCR0_CLIENTPD_MASK) &
+ ~(SCR0_USFCFG_MASK);
+ mmio_write_32((smmu_base_addr + SMMU_NSCR0), val);
+}
+
+#endif
diff --git a/include/drivers/nxp/timer/nxp_timer.h b/include/drivers/nxp/timer/nxp_timer.h
new file mode 100644
index 0000000..280e5b2
--- /dev/null
+++ b/include/drivers/nxp/timer/nxp_timer.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#
+#ifndef NXP_TIMER_H
+#define NXP_TIMER_H
+
+ /* System Counter Offset and Bit Mask */
+#define SYS_COUNTER_CNTCR_OFFSET 0x0
+#define SYS_COUNTER_CNTCR_EN 0x00000001
+#define CNTCR_EN_MASK 0x1
+
+#ifndef __ASSEMBLER__
+uint64_t get_timer_val(uint64_t start);
+
+#ifdef IMAGE_BL31
+void ls_configure_sys_timer(uintptr_t ls_sys_timctl_base,
+ uint8_t ls_config_cntacr,
+ uint8_t plat_ls_ns_timer_frame_id);
+void enable_init_timer(void);
+#endif
+
+/*
+ * Initialise the nxp on-chip free rolling usec counter as the delay
+ * timer.
+ */
+void delay_timer_init(uintptr_t nxp_timer_addr);
+void ls_bl31_timer_init(uintptr_t nxp_timer_addr);
+#endif /* __ASSEMBLER__ */
+
+#endif /* NXP_TIMER_H */
diff --git a/include/drivers/nxp/tzc/plat_tzc380.h b/include/drivers/nxp/tzc/plat_tzc380.h
new file mode 100644
index 0000000..08d2148
--- /dev/null
+++ b/include/drivers/nxp/tzc/plat_tzc380.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#if !defined(PLAT_TZC380_H) && defined(IMAGE_BL2)
+#define PLAT_TZC380_H
+
+#include <tzc380.h>
+
+/* Number of DRAM regions to be configured
+ * for the platform can be over-written.
+ *
+ * Array tzc400_reg_list too, needs be over-written
+ * if there is any changes to default DRAM region
+ * configuration.
+ */
+#ifndef MAX_NUM_TZC_REGION
+/* 3 regions:
+ * Region 0(default),
+ * Region 1 (DRAM0, Secure Memory),
+ * Region 2 (DRAM0, Shared memory)
+ */
+#define MAX_NUM_TZC_REGION 3
+#define DEFAULT_TZASC_CONFIG 1
+#endif
+
+struct tzc380_reg {
+ unsigned int secure;
+ unsigned int enabled;
+ uint64_t addr;
+ uint64_t size;
+ unsigned int sub_mask;
+};
+
+void mem_access_setup(uintptr_t base, uint32_t total_regions,
+ struct tzc380_reg *tzc380_reg_list);
+
+int populate_tzc380_reg_list(struct tzc380_reg *tzc380_reg_list,
+ int dram_idx, int list_idx,
+ uint64_t dram_start_addr,
+ uint64_t dram_size,
+ uint32_t secure_dram_sz,
+ uint32_t shrd_dram_sz);
+
+#endif /* PLAT_TZC380_H */
diff --git a/include/drivers/nxp/tzc/plat_tzc400.h b/include/drivers/nxp/tzc/plat_tzc400.h
new file mode 100644
index 0000000..1b8e3a4
--- /dev/null
+++ b/include/drivers/nxp/tzc/plat_tzc400.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#if !defined(PLAT_TZC400_H) && defined(IMAGE_BL2)
+#define PLAT_TZC400_H
+
+#include <tzc400.h>
+
+/* Structure to configure TZC Regions' boundaries and attributes. */
+struct tzc400_reg {
+ uint8_t reg_filter_en;
+ unsigned long long start_addr;
+ unsigned long long end_addr;
+ unsigned int sec_attr;
+ unsigned int nsaid_permissions;
+};
+
+#define TZC_REGION_NS_NONE 0x00000000U
+
+/* NXP Platforms do not support NS Access ID (NSAID) based non-secure access.
+ * Supports only non secure through generic NS ACCESS ID
+ */
+#define TZC_NS_ACCESS_ID 0xFFFFFFFFU
+
+/* Number of DRAM regions to be configured
+ * for the platform can be over-written.
+ *
+ * Array tzc400_reg_list too, needs be over-written
+ * if there is any changes to default DRAM region
+ * configuration.
+ */
+#ifndef MAX_NUM_TZC_REGION
+/* 3 regions:
+ * Region 0(default),
+ * Region 1 (DRAM0, Secure Memory),
+ * Region 2 (DRAM0, Shared memory)
+ */
+#define MAX_NUM_TZC_REGION NUM_DRAM_REGIONS + 3
+#define DEFAULT_TZASC_CONFIG 1
+#endif
+
+void mem_access_setup(uintptr_t base, uint32_t total_regions,
+ struct tzc400_reg *tzc400_reg_list);
+int populate_tzc400_reg_list(struct tzc400_reg *tzc400_reg_list,
+ int dram_idx, int list_idx,
+ uint64_t dram_start_addr,
+ uint64_t dram_size,
+ uint32_t secure_dram_sz,
+ uint32_t shrd_dram_sz);
+
+#endif /* PLAT_TZC400_H */
diff --git a/include/drivers/partition/efi.h b/include/drivers/partition/efi.h
new file mode 100644
index 0000000..e463f96
--- /dev/null
+++ b/include/drivers/partition/efi.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2021, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef DRIVERS_PARTITION_EFI_H
+#define DRIVERS_PARTITION_EFI_H
+
+#include <string.h>
+
+#include <tools_share/uuid.h>
+
+#define EFI_NAMELEN 36
+
+static inline int guidcmp(const void *g1, const void *g2)
+{
+ return memcmp(g1, g2, sizeof(struct efi_guid));
+}
+
+static inline void *guidcpy(void *dst, const void *src)
+{
+ return memcpy(dst, src, sizeof(struct efi_guid));
+}
+
+#define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \
+ { (a) & 0xffffffff, \
+ (b) & 0xffff, \
+ (c) & 0xffff, \
+ { (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) } }
+
+#define NULL_GUID \
+ EFI_GUID(0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
+
+#endif /* DRIVERS_PARTITION_EFI_H */
diff --git a/include/drivers/partition/gpt.h b/include/drivers/partition/gpt.h
new file mode 100644
index 0000000..c2a229e
--- /dev/null
+++ b/include/drivers/partition/gpt.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GPT_H
+#define GPT_H
+
+#include <drivers/partition/efi.h>
+#include <drivers/partition/partition.h>
+#include <tools_share/uuid.h>
+
+#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 GPT_SIGNATURE "EFI PART"
+
+typedef struct gpt_entry {
+ struct efi_guid type_uuid;
+ struct efi_guid unique_uuid;
+ 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;
+ struct efi_guid disk_uuid;
+ /* 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 */
diff --git a/include/drivers/partition/mbr.h b/include/drivers/partition/mbr.h
new file mode 100644
index 0000000..1452c02
--- /dev/null
+++ b/include/drivers/partition/mbr.h
@@ -0,0 +1,29 @@
+/*
+ * 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 */
diff --git a/include/drivers/partition/partition.h b/include/drivers/partition/partition.h
new file mode 100644
index 0000000..6cb59c3
--- /dev/null
+++ b/include/drivers/partition/partition.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PARTITION_H
+#define PARTITION_H
+
+#include <stdint.h>
+
+#include <lib/cassert.h>
+#include <drivers/partition/efi.h>
+#include <tools_share/uuid.h>
+
+#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 DEFAULT_GPT_HEADER_SIZE 92
+
+typedef struct partition_entry {
+ uint64_t start;
+ uint64_t length;
+ char name[EFI_NAMELEN];
+ struct efi_guid part_guid;
+ struct efi_guid type_guid;
+} 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_t *get_partition_entry_by_type(const uuid_t *type_guid);
+const partition_entry_t *get_partition_entry_by_uuid(const uuid_t *part_uuid);
+const partition_entry_list_t *get_partition_entry_list(void);
+void partition_init(unsigned int image_id);
+
+#endif /* PARTITION_H */
diff --git a/include/drivers/rambus/trng_ip_76.h b/include/drivers/rambus/trng_ip_76.h
new file mode 100644
index 0000000..6de8fc7
--- /dev/null
+++ b/include/drivers/rambus/trng_ip_76.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2020, Marvell Technology Group Ltd. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#ifndef __TRNG_IP_76_H__
+#define __TRNG_IP_76_H__
+
+#include <stdbool.h>
+#include <stdint.h>
+
+int32_t eip76_rng_read_rand_buf(void *data, bool wait);
+int32_t eip76_rng_probe(uintptr_t base_addr);
+int32_t eip76_rng_get_random(uint8_t *data, uint32_t len);
+
+#endif /* __TRNG_IP_76_H__ */
diff --git a/include/drivers/raw_nand.h b/include/drivers/raw_nand.h
new file mode 100644
index 0000000..7152300
--- /dev/null
+++ b/include/drivers/raw_nand.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRIVERS_RAW_NAND_H
+#define DRIVERS_RAW_NAND_H
+
+#include <cdefs.h>
+#include <stdint.h>
+
+#include <drivers/nand.h>
+
+/* NAND ONFI default value mode 0 in picosecond */
+#define NAND_TADL_MIN 400000UL
+#define NAND_TALH_MIN 20000UL
+#define NAND_TALS_MIN 50000UL
+#define NAND_TAR_MIN 25000UL
+#define NAND_TCCS_MIN 500000UL
+#define NAND_TCEA_MIN 100000UL
+#define NAND_TCEH_MIN 20000UL
+#define NAND_TCH_MIN 20000UL
+#define NAND_TCHZ_MAX 100000UL
+#define NAND_TCLH_MIN 20000UL
+#define NAND_TCLR_MIN 20000UL
+#define NAND_TCLS_MIN 50000UL
+#define NAND_TCOH_MIN 0UL
+#define NAND_TCS_MIN 70000UL
+#define NAND_TDH_MIN 20000UL
+#define NAND_TDS_MIN 40000UL
+#define NAND_TFEAT_MAX 1000000UL
+#define NAND_TIR_MIN 10000UL
+#define NAND_TITC_MIN 1000000UL
+#define NAND_TR_MAX 200000000UL
+#define NAND_TRC_MIN 100000UL
+#define NAND_TREA_MAX 40000UL
+#define NAND_TREH_MIN 30000UL
+#define NAND_TRHOH_MIN 0UL
+#define NAND_TRHW_MIN 200000UL
+#define NAND_TRHZ_MAX 200000UL
+#define NAND_TRLOH_MIN 0UL
+#define NAND_TRP_MIN 50000UL
+#define NAND_TRR_MIN 40000UL
+#define NAND_TRST_MAX 250000000000ULL
+#define NAND_TWB_MAX 200000UL
+#define NAND_TWC_MIN 100000UL
+#define NAND_TWH_MIN 30000UL
+#define NAND_TWHR_MIN 120000UL
+#define NAND_TWP_MIN 50000UL
+#define NAND_TWW_MIN 100000UL
+
+/* NAND request types */
+#define NAND_REQ_CMD 0x0000U
+#define NAND_REQ_ADDR 0x1000U
+#define NAND_REQ_DATAIN 0x2000U
+#define NAND_REQ_DATAOUT 0x3000U
+#define NAND_REQ_WAIT 0x4000U
+#define NAND_REQ_MASK GENMASK(14, 12)
+#define NAND_REQ_BUS_WIDTH_8 BIT(15)
+
+#define PARAM_PAGE_SIZE 256
+
+/* NAND ONFI commands */
+#define NAND_CMD_READ_1ST 0x00U
+#define NAND_CMD_CHANGE_1ST 0x05U
+#define NAND_CMD_READID_SIG_ADDR 0x20U
+#define NAND_CMD_READ_2ND 0x30U
+#define NAND_CMD_STATUS 0x70U
+#define NAND_CMD_READID 0x90U
+#define NAND_CMD_CHANGE_2ND 0xE0U
+#define NAND_CMD_READ_PARAM_PAGE 0xECU
+#define NAND_CMD_RESET 0xFFU
+
+#define ONFI_REV_21 BIT(3)
+#define ONFI_FEAT_BUS_WIDTH_16 BIT(0)
+#define ONFI_FEAT_EXTENDED_PARAM BIT(7)
+
+/* NAND ECC type */
+#define NAND_ECC_NONE U(0)
+#define NAND_ECC_HW U(1)
+#define NAND_ECC_ONDIE U(2)
+
+/* NAND bus width */
+#define NAND_BUS_WIDTH_8 U(0)
+#define NAND_BUS_WIDTH_16 U(1)
+
+struct nand_req {
+ struct nand_device *nand;
+ uint16_t type;
+ uint8_t *addr;
+ unsigned int length;
+ unsigned int delay_ms;
+ unsigned int inst_delay;
+};
+
+struct nand_param_page {
+ /* Rev information and feature block */
+ uint32_t page_sig;
+ uint16_t rev;
+ uint16_t features;
+ uint16_t opt_cmd;
+ uint8_t jtg;
+ uint8_t train_cmd;
+ uint16_t ext_param_length;
+ uint8_t nb_param_pages;
+ uint8_t reserved1[17];
+ /* Manufacturer information */
+ uint8_t manufacturer[12];
+ uint8_t model[20];
+ uint8_t manufacturer_id;
+ uint16_t data_code;
+ uint8_t reserved2[13];
+ /* Memory organization */
+ uint32_t bytes_per_page;
+ uint16_t spare_per_page;
+ uint32_t bytes_per_partial;
+ uint16_t spare_per_partial;
+ uint32_t num_pages_per_blk;
+ uint32_t num_blk_in_lun;
+ uint8_t num_lun;
+ uint8_t num_addr_cycles;
+ uint8_t bit_per_cell;
+ uint16_t max_bb_per_lun;
+ uint16_t blk_endur;
+ uint8_t valid_blk_begin;
+ uint16_t blk_enbur_valid;
+ uint8_t nb_prog_page;
+ uint8_t partial_prog_attr;
+ uint8_t nb_ecc_bits;
+ uint8_t plane_addr;
+ uint8_t mplanes_ops;
+ uint8_t ez_nand;
+ uint8_t reserved3[12];
+ /* Electrical parameters */
+ uint8_t io_pin_cap_max;
+ uint16_t sdr_timing_mode;
+ uint16_t sdr_prog_cache_timing;
+ uint16_t tprog;
+ uint16_t tbers;
+ uint16_t tr;
+ uint16_t tccs;
+ uint8_t nvddr_timing_mode;
+ uint8_t nvddr2_timing_mode;
+ uint8_t nvddr_features;
+ uint16_t clk_input_cap_typ;
+ uint16_t io_pin_cap_typ;
+ uint16_t input_pin_cap_typ;
+ uint8_t input_pin_cap_max;
+ uint8_t drv_strength_support;
+ uint16_t tr_max;
+ uint16_t tadl;
+ uint16_t tr_typ;
+ uint8_t reserved4[6];
+ /* Vendor block */
+ uint16_t vendor_revision;
+ uint8_t vendor[88];
+ uint16_t crc16;
+} __packed;
+
+struct nand_ctrl_ops {
+ int (*exec)(struct nand_req *req);
+ void (*setup)(struct nand_device *nand);
+};
+
+struct rawnand_device {
+ struct nand_device *nand_dev;
+ const struct nand_ctrl_ops *ops;
+};
+
+int nand_raw_init(unsigned long long *size, unsigned int *erase_size);
+int nand_wait_ready(unsigned int delay_ms);
+int nand_read_page_cmd(unsigned int page, unsigned int offset,
+ uintptr_t buffer, unsigned int len);
+int nand_change_read_column_cmd(unsigned int offset, uintptr_t buffer,
+ unsigned int len);
+void nand_raw_ctrl_init(const struct nand_ctrl_ops *ops);
+
+/*
+ * Platform can implement this to override default raw NAND instance
+ * configuration.
+ *
+ * @device: target raw NAND instance.
+ * Return 0 on success, negative value otherwise.
+ */
+int plat_get_raw_nand_data(struct rawnand_device *device);
+
+#endif /* DRIVERS_RAW_NAND_H */
diff --git a/include/drivers/renesas/rcar/console/console.h b/include/drivers/renesas/rcar/console/console.h
new file mode 100644
index 0000000..7d5b5d3
--- /dev/null
+++ b/include/drivers/renesas/rcar/console/console.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RCAR_PRINTF_H
+#define RCAR_PRINTF_H
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+/*
+ * 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_t *console);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* RCAR_PRINTF_H */
diff --git a/include/drivers/rpi3/gpio/rpi3_gpio.h b/include/drivers/rpi3/gpio/rpi3_gpio.h
new file mode 100644
index 0000000..7bb3ee2
--- /dev/null
+++ b/include/drivers/rpi3/gpio/rpi3_gpio.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, Linaro Limited
+ * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPI3_GPIO_H
+#define RPI3_GPIO_H
+
+#include <stdint.h>
+#include <drivers/gpio.h>
+
+void rpi3_gpio_init(void);
+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 */
diff --git a/include/drivers/rpi3/mailbox/rpi3_mbox.h b/include/drivers/rpi3/mailbox/rpi3_mbox.h
new file mode 100644
index 0000000..c107440
--- /dev/null
+++ b/include/drivers/rpi3/mailbox/rpi3_mbox.h
@@ -0,0 +1,39 @@
+/*
+ * 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 <stdint.h>
+
+/* 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
diff --git a/include/drivers/rpi3/rng/rpi3_rng.h b/include/drivers/rpi3/rng/rpi3_rng.h
new file mode 100644
index 0000000..ea5a677
--- /dev/null
+++ b/include/drivers/rpi3/rng/rpi3_rng.h
@@ -0,0 +1,12 @@
+/*
+ * 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
diff --git a/include/drivers/rpi3/sdhost/rpi3_sdhost.h b/include/drivers/rpi3/sdhost/rpi3_sdhost.h
new file mode 100644
index 0000000..1653240
--- /dev/null
+++ b/include/drivers/rpi3/sdhost/rpi3_sdhost.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2019, Linaro Limited
+ * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPI3_SDHOST_H
+#define RPI3_SDHOST_H
+
+#include <drivers/mmc.h>
+#include <stdint.h>
+#include <platform_def.h>
+
+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 */
diff --git a/include/drivers/scmi-msg.h b/include/drivers/scmi-msg.h
new file mode 100644
index 0000000..a9a99cf
--- /dev/null
+++ b/include/drivers/scmi-msg.h
@@ -0,0 +1,207 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Linaro Limited
+ */
+
+#ifndef SCMI_MSG_H
+#define SCMI_MSG_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/* Minimum size expected for SMT based shared memory message buffers */
+#define SMT_BUF_SLOT_SIZE 128U
+
+/* A channel abstract a communication path between agent and server */
+struct scmi_msg_channel;
+
+/*
+ * struct scmi_msg_channel - Shared memory buffer for a agent-to-server channel
+ *
+ * @shm_addr: Address of the shared memory for the SCMI channel
+ * @shm_size: Byte size of the shared memory for the SCMI channel
+ * @busy: True when channel is busy, flase when channel is free
+ * @agent_name: Agent name, SCMI protocol exposes 16 bytes max, or NULL
+ */
+struct scmi_msg_channel {
+ uintptr_t shm_addr;
+ size_t shm_size;
+ bool busy;
+ const char *agent_name;
+};
+
+/*
+ * Initialize SMT memory buffer, called by platform at init for each
+ * agent channel using the SMT header format.
+ *
+ * @chan: Pointer to the channel shared memory to be initialized
+ */
+void scmi_smt_init_agent_channel(struct scmi_msg_channel *chan);
+
+/*
+ * Process SMT formatted message in a fastcall SMC execution context.
+ * Called by platform on SMC entry. When returning, output message is
+ * available in shared memory for agent to read the response.
+ *
+ * @agent_id: SCMI agent ID the SMT belongs to
+ */
+void scmi_smt_fastcall_smc_entry(unsigned int agent_id);
+
+/*
+ * Process SMT formatted message in a secure interrupt execution context.
+ * Called by platform interrupt handler. When returning, output message is
+ * available in shared memory for agent to read the response.
+ *
+ * @agent_id: SCMI agent ID the SMT belongs to
+ */
+void scmi_smt_interrupt_entry(unsigned int agent_id);
+
+/* Platform callback functions */
+
+/*
+ * Return the SCMI channel related to an agent
+ * @agent_id: SCMI agent ID
+ * Return a pointer to channel on success, NULL otherwise
+ */
+struct scmi_msg_channel *plat_scmi_get_channel(unsigned int agent_id);
+
+/*
+ * Return how many SCMI protocols supported by the platform
+ * According to the SCMI specification, this function does not target
+ * a specific agent ID and shall return all platform known capabilities.
+ */
+size_t plat_scmi_protocol_count(void);
+
+/*
+ * Get the count and list of SCMI protocols (but base) supported for an agent
+ *
+ * @agent_id: SCMI agent ID
+ * Return a pointer to a null terminated array supported protocol IDs.
+ */
+const uint8_t *plat_scmi_protocol_list(unsigned int agent_id);
+
+/* Get the name of the SCMI vendor for the platform */
+const char *plat_scmi_vendor_name(void);
+
+/* Get the name of the SCMI sub-vendor for the platform */
+const char *plat_scmi_sub_vendor_name(void);
+
+/* Handlers for SCMI Clock protocol services */
+
+/*
+ * Return number of clock controllers for an agent
+ * @agent_id: SCMI agent ID
+ * Return number of clock controllers
+ */
+size_t plat_scmi_clock_count(unsigned int agent_id);
+
+/*
+ * Get clock controller string ID (aka name)
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI clock ID
+ * Return pointer to name or NULL
+ */
+const char *plat_scmi_clock_get_name(unsigned int agent_id,
+ unsigned int scmi_id);
+
+/*
+ * Get clock possible rate as an array of frequencies in Hertz.
+ *
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI clock ID
+ * @rates: If NULL, function returns, else output rates array
+ * @nb_elts: Array size of @rates.
+ * Return an SCMI compliant error code
+ */
+int32_t plat_scmi_clock_rates_array(unsigned int agent_id, unsigned int scmi_id,
+ unsigned long *rates, size_t *nb_elts);
+
+/*
+ * Get clock possible rate as range with regular steps in Hertz
+ *
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI clock ID
+ * @min_max_step: 3 cell array for min, max and step rate data
+ * Return an SCMI compliant error code
+ */
+int32_t plat_scmi_clock_rates_by_step(unsigned int agent_id,
+ unsigned int scmi_id,
+ unsigned long *min_max_step);
+
+/*
+ * Get clock rate in Hertz
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI clock ID
+ * Return clock rate or 0 if not supported
+ */
+unsigned long plat_scmi_clock_get_rate(unsigned int agent_id,
+ unsigned int scmi_id);
+
+/*
+ * Set clock rate in Hertz
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI clock ID
+ * @rate: Target clock frequency in Hertz
+ * Return a compliant SCMI error code
+ */
+int32_t plat_scmi_clock_set_rate(unsigned int agent_id, unsigned int scmi_id,
+ unsigned long rate);
+
+/*
+ * Get clock state (enabled or disabled)
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI clock ID
+ * Return 1 if clock is enabled, 0 if disables, or a negative SCMI error code
+ */
+int32_t plat_scmi_clock_get_state(unsigned int agent_id, unsigned int scmi_id);
+
+/*
+ * Get clock state (enabled or disabled)
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI clock ID
+ * @enable_not_disable: Enable clock if true, disable clock otherwise
+ * Return a compliant SCMI error code
+ */
+int32_t plat_scmi_clock_set_state(unsigned int agent_id, unsigned int scmi_id,
+ bool enable_not_disable);
+
+/* Handlers for SCMI Reset Domain protocol services */
+
+/*
+ * Return number of reset domains for the agent
+ * @agent_id: SCMI agent ID
+ * Return number of reset domains
+ */
+size_t plat_scmi_rstd_count(unsigned int agent_id);
+
+/*
+ * Get reset domain string ID (aka name)
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI reset domain ID
+ * Return pointer to name or NULL
+ */
+const char *plat_scmi_rstd_get_name(unsigned int agent_id, unsigned int scmi_id);
+
+/*
+ * Perform a reset cycle on a target reset domain
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI reset domain ID
+ * @state: Target reset state (see SCMI specification, 0 means context loss)
+ * Return a compliant SCMI error code
+ */
+int32_t plat_scmi_rstd_autonomous(unsigned int agent_id, unsigned int scmi_id,
+ unsigned int state);
+
+/*
+ * Assert or deassert target reset domain
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI reset domain ID
+ * @assert_not_deassert: Assert domain if true, otherwise deassert domain
+ * Return a compliant SCMI error code
+ */
+int32_t plat_scmi_rstd_set_state(unsigned int agent_id, unsigned int scmi_id,
+ bool assert_not_deassert);
+
+#endif /* SCMI_MSG_H */
diff --git a/include/drivers/scmi.h b/include/drivers/scmi.h
new file mode 100644
index 0000000..ac5dc38
--- /dev/null
+++ b/include/drivers/scmi.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ */
+#ifndef SCMI_MSG_SCMI_H
+#define SCMI_MSG_SCMI_H
+
+#define SCMI_PROTOCOL_ID_BASE 0x10U
+#define SCMI_PROTOCOL_ID_POWER_DOMAIN 0x11U
+#define SCMI_PROTOCOL_ID_SYS_POWER 0x12U
+#define SCMI_PROTOCOL_ID_PERF 0x13U
+#define SCMI_PROTOCOL_ID_CLOCK 0x14U
+#define SCMI_PROTOCOL_ID_SENSOR 0x15U
+#define SCMI_PROTOCOL_ID_RESET_DOMAIN 0x16U
+
+/* SCMI error codes reported to agent through server-to-agent messages */
+#define SCMI_SUCCESS 0
+#define SCMI_NOT_SUPPORTED (-1)
+#define SCMI_INVALID_PARAMETERS (-2)
+#define SCMI_DENIED (-3)
+#define SCMI_NOT_FOUND (-4)
+#define SCMI_OUT_OF_RANGE (-5)
+#define SCMI_BUSY (-6)
+#define SCMI_COMMS_ERROR (-7)
+#define SCMI_GENERIC_ERROR (-8)
+#define SCMI_HARDWARE_ERROR (-9)
+#define SCMI_PROTOCOL_ERROR (-10)
+
+#endif /* SCMI_MSG_SCMI_H */
diff --git a/include/drivers/spi_mem.h b/include/drivers/spi_mem.h
new file mode 100644
index 0000000..d1953ac
--- /dev/null
+++ b/include/drivers/spi_mem.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRIVERS_SPI_MEM_H
+#define DRIVERS_SPI_MEM_H
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#define SPI_MEM_BUSWIDTH_1_LINE 1U
+#define SPI_MEM_BUSWIDTH_2_LINE 2U
+#define SPI_MEM_BUSWIDTH_4_LINE 4U
+
+/*
+ * enum spi_mem_data_dir - Describes the direction of a SPI memory data
+ * transfer from the controller perspective.
+ * @SPI_MEM_DATA_IN: data coming from the SPI memory.
+ * @SPI_MEM_DATA_OUT: data sent to the SPI memory.
+ */
+enum spi_mem_data_dir {
+ SPI_MEM_DATA_IN,
+ SPI_MEM_DATA_OUT,
+};
+
+/*
+ * struct spi_mem_op - Describes a SPI memory operation.
+ *
+ * @cmd.buswidth: Number of IO lines used to transmit the command.
+ * @cmd.opcode: Operation opcode.
+ * @addr.nbytes: Number of address bytes to send. Can be zero if the operation
+ * does not need to send an address.
+ * @addr.buswidth: Number of IO lines used to transmit the address.
+ * @addr.val: Address value. This value is always sent MSB first on the bus.
+ * Note that only @addr.nbytes are taken into account in this
+ * address value, so users should make sure the value fits in the
+ * assigned number of bytes.
+ * @dummy.nbytes: Number of dummy bytes to send after an opcode or address. Can
+ * be zero if the operation does not require dummy bytes.
+ * @dummy.buswidth: Number of IO lines used to transmit the dummy bytes.
+ * @data.buswidth: Number of IO lines used to send/receive the data.
+ * @data.dir: Direction of the transfer.
+ * @data.nbytes: Number of data bytes to transfer.
+ * @data.buf: Input or output data buffer depending on data::dir.
+ */
+struct spi_mem_op {
+ struct {
+ uint8_t buswidth;
+ uint8_t opcode;
+ } cmd;
+
+ struct {
+ uint8_t nbytes;
+ uint8_t buswidth;
+ uint64_t val;
+ } addr;
+
+ struct {
+ uint8_t nbytes;
+ uint8_t buswidth;
+ } dummy;
+
+ struct {
+ uint8_t buswidth;
+ enum spi_mem_data_dir dir;
+ unsigned int nbytes;
+ void *buf;
+ } data;
+};
+
+/* SPI mode flags */
+#define SPI_CPHA BIT(0) /* clock phase */
+#define SPI_CPOL BIT(1) /* clock polarity */
+#define SPI_CS_HIGH BIT(2) /* CS active high */
+#define SPI_LSB_FIRST BIT(3) /* per-word bits-on-wire */
+#define SPI_3WIRE BIT(4) /* SI/SO signals shared */
+#define SPI_PREAMBLE BIT(5) /* Skip preamble bytes */
+#define SPI_TX_DUAL BIT(6) /* transmit with 2 wires */
+#define SPI_TX_QUAD BIT(7) /* transmit with 4 wires */
+#define SPI_RX_DUAL BIT(8) /* receive with 2 wires */
+#define SPI_RX_QUAD BIT(9) /* receive with 4 wires */
+
+struct spi_bus_ops {
+ /*
+ * Claim the bus and prepare it for communication.
+ *
+ * @cs: The chip select.
+ * Returns: 0 if the bus was claimed successfully, or a negative value
+ * if it wasn't.
+ */
+ int (*claim_bus)(unsigned int cs);
+
+ /*
+ * Release the SPI bus.
+ */
+ void (*release_bus)(void);
+
+ /*
+ * Set transfer speed.
+ *
+ * @hz: The transfer speed in Hertz.
+ * Returns: 0 on success, a negative error code otherwise.
+ */
+ int (*set_speed)(unsigned int hz);
+
+ /*
+ * Set the SPI mode/flags.
+ *
+ * @mode: Requested SPI mode (SPI_... flags).
+ * Returns: 0 on success, a negative error code otherwise.
+ */
+ int (*set_mode)(unsigned int mode);
+
+ /*
+ * Execute a SPI memory operation.
+ *
+ * @op: The memory operation to execute.
+ * Returns: 0 on success, a negative error code otherwise.
+ */
+ int (*exec_op)(const struct spi_mem_op *op);
+};
+
+int spi_mem_exec_op(const struct spi_mem_op *op);
+int spi_mem_init_slave(void *fdt, int bus_node,
+ const struct spi_bus_ops *ops);
+
+#endif /* DRIVERS_SPI_MEM_H */
diff --git a/include/drivers/spi_nand.h b/include/drivers/spi_nand.h
new file mode 100644
index 0000000..40e2063
--- /dev/null
+++ b/include/drivers/spi_nand.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRIVERS_SPI_NAND_H
+#define DRIVERS_SPI_NAND_H
+
+#include <drivers/nand.h>
+#include <drivers/spi_mem.h>
+
+#define SPI_NAND_OP_GET_FEATURE 0x0FU
+#define SPI_NAND_OP_SET_FEATURE 0x1FU
+#define SPI_NAND_OP_READ_ID 0x9FU
+#define SPI_NAND_OP_LOAD_PAGE 0x13U
+#define SPI_NAND_OP_RESET 0xFFU
+#define SPI_NAND_OP_READ_FROM_CACHE 0x03U
+#define SPI_NAND_OP_READ_FROM_CACHE_2X 0x3BU
+#define SPI_NAND_OP_READ_FROM_CACHE_4X 0x6BU
+
+/* Configuration register */
+#define SPI_NAND_REG_CFG 0xB0U
+#define SPI_NAND_CFG_ECC_EN BIT(4)
+#define SPI_NAND_CFG_QE BIT(0)
+
+/* Status register */
+#define SPI_NAND_REG_STATUS 0xC0U
+#define SPI_NAND_STATUS_BUSY BIT(0)
+#define SPI_NAND_STATUS_ECC_UNCOR BIT(5)
+
+struct spinand_device {
+ struct nand_device *nand_dev;
+ struct spi_mem_op spi_read_cache_op;
+ uint8_t cfg_cache; /* Cached value of SPI NAND device register CFG */
+};
+
+int spi_nand_init(unsigned long long *size, unsigned int *erase_size);
+
+/*
+ * Platform can implement this to override default SPI-NAND instance
+ * configuration.
+ *
+ * @device: target SPI-NAND instance.
+ * Return 0 on success, negative value otherwise.
+ */
+int plat_get_spi_nand_data(struct spinand_device *device);
+
+#endif /* DRIVERS_SPI_NAND_H */
diff --git a/include/drivers/spi_nor.h b/include/drivers/spi_nor.h
new file mode 100644
index 0000000..72cfe5b
--- /dev/null
+++ b/include/drivers/spi_nor.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRIVERS_SPI_NOR_H
+#define DRIVERS_SPI_NOR_H
+
+#include <drivers/spi_mem.h>
+
+/* OPCODE */
+#define SPI_NOR_OP_WREN 0x06U /* Write enable */
+#define SPI_NOR_OP_WRSR 0x01U /* Write status register 1 byte */
+#define SPI_NOR_OP_READ_ID 0x9FU /* Read JEDEC ID */
+#define SPI_NOR_OP_READ_CR 0x35U /* Read configuration register */
+#define SPI_NOR_OP_READ_SR 0x05U /* Read status register */
+#define SPI_NOR_OP_READ_FSR 0x70U /* Read flag status register */
+#define SPINOR_OP_RDEAR 0xC8U /* Read Extended Address Register */
+#define SPINOR_OP_WREAR 0xC5U /* Write Extended Address Register */
+
+/* Used for Spansion flashes only. */
+#define SPINOR_OP_BRWR 0x17U /* Bank register write */
+#define SPINOR_OP_BRRD 0x16U /* Bank register read */
+
+#define SPI_NOR_OP_READ 0x03U /* Read data bytes (low frequency) */
+#define SPI_NOR_OP_READ_FAST 0x0BU /* Read data bytes (high frequency) */
+#define SPI_NOR_OP_READ_1_1_2 0x3BU /* Read data bytes (Dual Output SPI) */
+#define SPI_NOR_OP_READ_1_2_2 0xBBU /* Read data bytes (Dual I/O SPI) */
+#define SPI_NOR_OP_READ_1_1_4 0x6BU /* Read data bytes (Quad Output SPI) */
+#define SPI_NOR_OP_READ_1_4_4 0xEBU /* Read data bytes (Quad I/O SPI) */
+
+/* Flags for NOR specific configuration */
+#define SPI_NOR_USE_FSR BIT(0)
+#define SPI_NOR_USE_BANK BIT(1)
+
+struct nor_device {
+ struct spi_mem_op read_op;
+ uint32_t size;
+ uint32_t flags;
+ uint8_t selected_bank;
+ uint8_t bank_write_cmd;
+ uint8_t bank_read_cmd;
+};
+
+int spi_nor_read(unsigned int offset, uintptr_t buffer, size_t length,
+ size_t *length_read);
+int spi_nor_init(unsigned long long *device_size, unsigned int *erase_size);
+
+/*
+ * Platform can implement this to override default NOR instance configuration.
+ *
+ * @device: target NOR instance.
+ * Return 0 on success, negative value otherwise.
+ */
+int plat_get_nor_data(struct nor_device *device);
+
+#endif /* DRIVERS_SPI_NOR_H */
diff --git a/include/drivers/st/bsec.h b/include/drivers/st/bsec.h
new file mode 100644
index 0000000..60dcf3c
--- /dev/null
+++ b/include/drivers/st/bsec.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BSEC_H
+#define BSEC_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+/*
+ * IP configuration
+ */
+#define BSEC_OTP_MASK GENMASK(4, 0)
+#define BSEC_OTP_BANK_SHIFT 5
+#define BSEC_TIMEOUT_VALUE 0xFFFF
+
+/*
+ * 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_TIMEOUT 0xFFFFFFF9U
+#define BSEC_RETRY 0xFFFFFFF8U
+#define BSEC_NOT_SUPPORTED 0xFFFFFFF7U
+#define BSEC_WRITE_LOCKED 0xFFFFFFF6U
+#define BSEC_ERROR_INVALID_FVR 0xFFFFFFF5U
+
+/*
+ * OTP MODE
+ */
+#define BSEC_MODE_OPEN1 0x00U
+#define BSEC_MODE_SECURED 0x01U
+#define BSEC_MODE_OPEN2 0x02U
+#define BSEC_MODE_INVALID 0x04U
+
+/*
+ * OTP Lock services definition.
+ * Value must corresponding to the bit number in the register.
+ * Special case: (bit number << 1) for BSEC3.
+ */
+#define BSEC_LOCK_UPPER_OTP 0x00
+#define BSEC_LOCK_GWLOCK 0x01
+#define BSEC_LOCK_DEBUG 0x02
+#define BSEC_LOCK_PROGRAM 0x03
+#define BSEC_LOCK_KVLOCK 0x04
+
+/*
+ * Values for struct bsec_config::freq
+ */
+#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 den_lock; /*
+ * Debug enable sticky lock
+ * 1 debug enable is locked until next reset
+ */
+
+ /* BSEC2 only */
+ uint8_t tread; /* SAFMEM Reading current level default 0 */
+ uint8_t pulse_width; /* SAFMEM Programming pulse width default 1 */
+ uint8_t freq; /*
+ * SAFMEM CLOCK see freq value define
+ * 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 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);
+
+void bsec_write_debug_conf(uint32_t val);
+uint32_t bsec_read_debug_conf(void);
+
+void bsec_write_scratch(uint32_t val);
+uint32_t bsec_read_scratch(void);
+
+uint32_t bsec_get_status(void);
+uint32_t bsec_get_hw_conf(void);
+uint32_t bsec_get_version(void);
+uint32_t bsec_get_id(void);
+uint32_t bsec_get_magic_id(void);
+
+uint32_t bsec_set_sr_lock(uint32_t otp);
+uint32_t bsec_read_sr_lock(uint32_t otp, bool *value);
+uint32_t bsec_set_sw_lock(uint32_t otp);
+uint32_t bsec_read_sw_lock(uint32_t otp, bool *value);
+uint32_t bsec_set_sp_lock(uint32_t otp);
+uint32_t bsec_read_sp_lock(uint32_t otp, bool *value);
+uint32_t bsec_read_permanent_lock(uint32_t otp, bool *value);
+uint32_t bsec_otp_lock(uint32_t service);
+
+uint32_t bsec_shadow_read_otp(uint32_t *otp_value, uint32_t word);
+uint32_t bsec_check_nsec_access_rights(uint32_t otp);
+
+#endif /* BSEC_H */
diff --git a/include/drivers/st/bsec2_reg.h b/include/drivers/st/bsec2_reg.h
new file mode 100644
index 0000000..f895020
--- /dev/null
+++ b/include/drivers/st/bsec2_reg.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BSEC2_REG_H
+#define BSEC2_REG_H
+
+#include <lib/utils_def.h>
+
+/* IP configuration */
+#define ADDR_LOWER_OTP_PERLOCK_SHIFT 0x03
+#define DATA_LOWER_OTP_PERLOCK_BIT 0x03U /* 2 significants bits are used */
+#define DATA_LOWER_OTP_PERLOCK_MASK GENMASK(2, 0)
+#define ADDR_UPPER_OTP_PERLOCK_SHIFT 0x04
+#define DATA_UPPER_OTP_PERLOCK_BIT 0x01U /* 1 significants bits are used */
+#define DATA_UPPER_OTP_PERLOCK_MASK GENMASK(3, 0)
+
+/* BSEC REGISTER OFFSET (base relative) */
+#define BSEC_OTP_CONF_OFF U(0x000)
+#define BSEC_OTP_CTRL_OFF U(0x004)
+#define BSEC_OTP_WRDATA_OFF U(0x008)
+#define BSEC_OTP_STATUS_OFF U(0x00C)
+#define BSEC_OTP_LOCK_OFF U(0x010)
+#define BSEC_DEN_OFF U(0x014)
+#define BSEC_DISTURBED_OFF U(0x01C)
+#define BSEC_DISTURBED1_OFF U(0x020)
+#define BSEC_DISTURBED2_OFF U(0x024)
+#define BSEC_ERROR_OFF U(0x034)
+#define BSEC_ERROR1_OFF U(0x038)
+#define BSEC_ERROR2_OFF U(0x03C)
+#define BSEC_WRLOCK_OFF U(0x04C) /* Safmem permanent lock */
+#define BSEC_WRLOCK1_OFF U(0x050)
+#define BSEC_WRLOCK2_OFF U(0x054)
+#define BSEC_SPLOCK_OFF U(0x064) /* Program safmem sticky lock */
+#define BSEC_SPLOCK1_OFF U(0x068)
+#define BSEC_SPLOCK2_OFF U(0x06C)
+#define BSEC_SWLOCK_OFF U(0x07C) /* Write in OTP sticky lock */
+#define BSEC_SWLOCK1_OFF U(0x080)
+#define BSEC_SWLOCK2_OFF U(0x084)
+#define BSEC_SRLOCK_OFF U(0x094) /* Shadowing sticky lock */
+#define BSEC_SRLOCK1_OFF U(0x098)
+#define BSEC_SRLOCK2_OFF U(0x09C)
+#define BSEC_JTAG_IN_OFF U(0x0AC)
+#define BSEC_JTAG_OUT_OFF U(0x0B0)
+#define BSEC_SCRATCH_OFF U(0x0B4)
+#define BSEC_OTP_DATA_OFF U(0x200)
+#define BSEC_IPHW_CFG_OFF U(0xFF0)
+#define BSEC_IPVR_OFF U(0xFF4)
+#define BSEC_IP_ID_OFF U(0xFF8)
+#define BSEC_IP_MAGIC_ID_OFF U(0xFFC)
+
+#define BSEC_WRLOCK(n) (BSEC_WRLOCK_OFF + U(0x04) * (n))
+#define BSEC_SPLOCK(n) (BSEC_SPLOCK_OFF + U(0x04) * (n))
+#define BSEC_SWLOCK(n) (BSEC_SWLOCK_OFF + U(0x04) * (n))
+#define BSEC_SRLOCK(n) (BSEC_SRLOCK_OFF + U(0x04) * (n))
+
+/* 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 0U
+#define BSEC_WRITE BIT(8)
+#define BSEC_LOCK BIT(9)
+
+/* BSEC_OTP_LOCK register */
+#define UPPER_OTP_LOCK_MASK BIT(0)
+#define UPPER_OTP_LOCK_SHIFT 0
+#define DENREG_LOCK_MASK BIT(2)
+#define DENREG_LOCK_SHIFT 2
+#define GPLOCK_LOCK_MASK BIT(4)
+#define GPLOCK_LOCK_SHIFT 4
+
+/* BSEC_OTP_STATUS Register */
+#define BSEC_MODE_STATUS_MASK GENMASK(2, 0)
+#define BSEC_MODE_SECURE_MASK BIT(0)
+#define BSEC_MODE_FULLDBG_MASK BIT(1)
+#define BSEC_MODE_INVALID_MASK BIT(2)
+#define BSEC_MODE_BUSY_MASK BIT(3)
+#define BSEC_MODE_PROGFAIL_MASK BIT(4)
+#define BSEC_MODE_PWR_MASK BIT(5)
+#define BSEC_MODE_BIST1_LOCK_MASK BIT(6)
+#define BSEC_MODE_BIST2_LOCK_MASK BIT(7)
+
+/* BSEC_DENABLE Register */
+#define BSEC_HDPEN BIT(4)
+#define BSEC_SPIDEN BIT(5)
+#define BSEC_SPINDEN BIT(6)
+#define BSEC_DBGSWGEN BIT(10)
+#define BSEC_DEN_ALL_MSK GENMASK(10, 0)
+
+/* BSEC_FENABLE Register */
+#define BSEC_FEN_ALL_MSK GENMASK(14, 0)
+
+/* BSEC_IPVR Register */
+#define BSEC_IPVR_MSK GENMASK(7, 0)
+
+#endif /* BSEC2_REG_H */
diff --git a/include/drivers/st/etzpc.h b/include/drivers/st/etzpc.h
new file mode 100644
index 0000000..4cd2b4e
--- /dev/null
+++ b/include/drivers/st/etzpc.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRIVERS_ST_ETZPC_H
+#define DRIVERS_ST_ETZPC_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/* Define security level for each peripheral (DECPROT) */
+enum etzpc_decprot_attributes {
+ ETZPC_DECPROT_S_RW = 0,
+ ETZPC_DECPROT_NS_R_S_W = 1,
+ ETZPC_DECPROT_MCU_ISOLATION = 2,
+ ETZPC_DECPROT_NS_RW = 3,
+ ETZPC_DECPROT_MAX = 4,
+};
+
+void etzpc_configure_decprot(uint32_t decprot_id,
+ enum etzpc_decprot_attributes decprot_attr);
+enum etzpc_decprot_attributes etzpc_get_decprot(uint32_t decprot_id);
+void etzpc_lock_decprot(uint32_t decprot_id);
+
+void etzpc_configure_tzma(uint32_t tzma_id, uint16_t tzma_value);
+uint16_t etzpc_get_tzma(uint32_t tzma_id);
+void etzpc_lock_tzma(uint32_t tzma_id);
+bool etzpc_get_lock_tzma(uint32_t tzma_id);
+
+uint8_t etzpc_get_num_per_sec(void);
+uint8_t etzpc_get_revision(void);
+uintptr_t etzpc_get_base_address(void);
+
+int etzpc_init(void);
+
+#endif /* DRIVERS_ST_ETZPC_H */
diff --git a/include/drivers/st/io_mmc.h b/include/drivers/st/io_mmc.h
new file mode 100644
index 0000000..6179e89
--- /dev/null
+++ b/include/drivers/st/io_mmc.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_MMC_H
+#define IO_MMC_H
+
+#include <drivers/io/io_driver.h>
+
+struct io_mmc_dev_spec {
+ bool use_boot_part;
+};
+
+int register_io_dev_mmc(const io_dev_connector_t **dev_con);
+
+#endif /* IO_MMC_H */
diff --git a/include/drivers/st/regulator.h b/include/drivers/st/regulator.h
new file mode 100644
index 0000000..bf583e2
--- /dev/null
+++ b/include/drivers/st/regulator.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef REGULATOR_H
+#define REGULATOR_H
+
+#include <platform_def.h>
+
+#ifndef PLAT_NB_RDEVS
+#error "Missing PLAT_NB_RDEVS"
+#endif
+
+/*
+ * Consumer interface
+ */
+
+/* regulator-always-on : regulator should never be disabled */
+#define REGUL_ALWAYS_ON BIT(0)
+/*
+ * regulator-boot-on:
+ * It's expected that this regulator was left on by the bootloader.
+ * The core shouldn't prevent it from being turned off later.
+ * The regulator is needed to exit from suspend so it is turned on during suspend entry.
+ */
+#define REGUL_BOOT_ON BIT(1)
+/* regulator-over-current-protection: Enable over current protection. */
+#define REGUL_OCP BIT(2)
+/* regulator-active-discharge: enable active discharge. */
+#define REGUL_ACTIVE_DISCHARGE BIT(3)
+/* regulator-pull-down: Enable pull down resistor when the regulator is disabled. */
+#define REGUL_PULL_DOWN BIT(4)
+/*
+ * st,mask-reset: set mask reset for the regulator, meaning that the regulator
+ * setting is maintained during pmic reset.
+ */
+#define REGUL_MASK_RESET BIT(5)
+/* st,regulator-sink-source: set the regulator in sink source mode */
+#define REGUL_SINK_SOURCE BIT(6)
+/* st,regulator-bypass: set the regulator in bypass mode */
+#define REGUL_ENABLE_BYPASS BIT(7)
+
+struct rdev *regulator_get_by_name(const char *node_name);
+
+struct rdev *regulator_get_by_supply_name(const void *fdt, int node, const char *name);
+
+int regulator_enable(struct rdev *rdev);
+int regulator_disable(struct rdev *rdev);
+int regulator_is_enabled(const struct rdev *rdev);
+
+int regulator_set_voltage(struct rdev *rdev, uint16_t volt);
+int regulator_set_min_voltage(struct rdev *rdev);
+int regulator_get_voltage(const struct rdev *rdev);
+
+int regulator_list_voltages(const struct rdev *rdev, const uint16_t **levels, size_t *count);
+void regulator_get_range(const struct rdev *rdev, uint16_t *min_mv, uint16_t *max_mv);
+int regulator_set_flag(struct rdev *rdev, uint16_t flag);
+
+/*
+ * Driver Interface
+ */
+
+/* set_state() arguments */
+#define STATE_DISABLE false
+#define STATE_ENABLE true
+
+struct regul_description {
+ const char *node_name;
+ const struct regul_ops *ops;
+ const void *driver_data;
+ const char *supply_name;
+ const uint32_t enable_ramp_delay;
+};
+
+struct regul_ops {
+ int (*set_state)(const struct regul_description *desc, bool state);
+ int (*get_state)(const struct regul_description *desc);
+ int (*set_voltage)(const struct regul_description *desc, uint16_t mv);
+ int (*get_voltage)(const struct regul_description *desc);
+ int (*list_voltages)(const struct regul_description *desc,
+ const uint16_t **levels, size_t *count);
+ int (*set_flag)(const struct regul_description *desc, uint16_t flag);
+ void (*lock)(const struct regul_description *desc);
+ void (*unlock)(const struct regul_description *desc);
+};
+
+int regulator_register(const struct regul_description *desc, int node);
+
+/*
+ * Internal regulator structure
+ * The structure is internal to the core, and the content should not be used
+ * by a consumer nor a driver.
+ */
+struct rdev {
+ const struct regul_description *desc;
+
+ int32_t phandle;
+
+ uint16_t min_mv;
+ uint16_t max_mv;
+
+ uint16_t flags;
+
+ uint32_t enable_ramp_delay;
+};
+
+#endif /* REGULATOR_H */
diff --git a/include/drivers/st/regulator_fixed.h b/include/drivers/st/regulator_fixed.h
new file mode 100644
index 0000000..b981262
--- /dev/null
+++ b/include/drivers/st/regulator_fixed.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef REGULATOR_FIXED_H
+#define REGULATOR_FIXED_H
+
+int fixed_regulator_register(void);
+
+#endif /* REGULATOR_FIXED_H */
diff --git a/include/drivers/st/stm32_console.h b/include/drivers/st/stm32_console.h
new file mode 100644
index 0000000..8d9187d
--- /dev/null
+++ b/include/drivers/st/stm32_console.h
@@ -0,0 +1,27 @@
+/*
+ * 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 <drivers/console.h>
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+/*
+ * 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,
+ console_t *console);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* STM32_CONSOLE_H */
diff --git a/include/drivers/st/stm32_fmc2_nand.h b/include/drivers/st/stm32_fmc2_nand.h
new file mode 100644
index 0000000..81d5b9d
--- /dev/null
+++ b/include/drivers/st/stm32_fmc2_nand.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#ifndef STM32_FMC2_NAND_H
+#define STM32_FMC2_NAND_H
+
+int stm32_fmc2_init(void);
+
+#endif /* STM32_FMC2_NAND_H */
diff --git a/include/drivers/st/stm32_gpio.h b/include/drivers/st/stm32_gpio.h
new file mode 100644
index 0000000..eeef9da
--- /dev/null
+++ b/include/drivers/st/stm32_gpio.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_GPIO_H
+#define STM32_GPIO_H
+
+#include <lib/utils_def.h>
+
+#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_OD_OFFSET U(0x14)
+#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 U(0x00)
+#define GPIO_MODE_OUTPUT U(0x01)
+#define GPIO_MODE_ALTERNATE U(0x02)
+#define GPIO_MODE_ANALOG U(0x03)
+#define GPIO_MODE_MASK U(0x03)
+
+#define GPIO_TYPE_PUSH_PULL U(0x00)
+#define GPIO_TYPE_OPEN_DRAIN U(0x01)
+#define GPIO_TYPE_MASK U(0x01)
+
+#define GPIO_SPEED_LOW U(0x00)
+#define GPIO_SPEED_MEDIUM U(0x01)
+#define GPIO_SPEED_HIGH U(0x02)
+#define GPIO_SPEED_VERY_HIGH U(0x03)
+#define GPIO_SPEED_MASK U(0x03)
+
+#define GPIO_NO_PULL U(0x00)
+#define GPIO_PULL_UP U(0x01)
+#define GPIO_PULL_DOWN U(0x02)
+#define GPIO_PULL_MASK U(0x03)
+
+#define GPIO_OD_OUTPUT_LOW U(0x00)
+#define GPIO_OD_OUTPUT_HIGH U(0x01)
+#define GPIO_OD_MASK U(0x01)
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+
+int dt_set_pinctrl_config(int node);
+void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure);
+void set_gpio_reset_cfg(uint32_t bank, uint32_t pin);
+#endif /*__ASSEMBLER__*/
+
+#endif /* STM32_GPIO_H */
diff --git a/include/drivers/st/stm32_hash.h b/include/drivers/st/stm32_hash.h
new file mode 100644
index 0000000..bebb4af
--- /dev/null
+++ b/include/drivers/st/stm32_hash.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_HASH_H
+#define STM32_HASH_H
+
+#include <stdint.h>
+
+enum stm32_hash_algo_mode {
+#if STM32_HASH_VER == 2
+ HASH_MD5SUM,
+#endif
+ HASH_SHA1,
+ HASH_SHA224,
+ HASH_SHA256,
+#if STM32_HASH_VER == 4
+ HASH_SHA384,
+ HASH_SHA512,
+#endif
+};
+
+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 */
diff --git a/include/drivers/st/stm32_i2c.h b/include/drivers/st/stm32_i2c.h
new file mode 100644
index 0000000..170d4cf
--- /dev/null
+++ b/include/drivers/st/stm32_i2c.h
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_I2C_H
+#define STM32_I2C_H
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+/* 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 */
diff --git a/include/drivers/st/stm32_iwdg.h b/include/drivers/st/stm32_iwdg.h
new file mode 100644
index 0000000..bad2524
--- /dev/null
+++ b/include/drivers/st/stm32_iwdg.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_IWDG_H
+#define STM32_IWDG_H
+
+#include <stdint.h>
+
+#define IWDG_HW_ENABLED BIT(0)
+#define IWDG_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 */
diff --git a/include/drivers/st/stm32_pka.h b/include/drivers/st/stm32_pka.h
new file mode 100644
index 0000000..ad4690a
--- /dev/null
+++ b/include/drivers/st/stm32_pka.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_PKA_H
+#define STM32_PKA_H
+
+#include <stdint.h>
+
+#if !PKA_USE_NIST_P256 && !PKA_USE_BRAINPOOL_P256R1 && !PKA_USE_BRAINPOOL_P256T1 && \
+ !PKA_USE_NIST_P521
+#error "At least one ECDSA curve needs to be selected"
+#endif
+
+enum stm32_pka_ecdsa_curve_id {
+#if PKA_USE_NIST_P256
+ PKA_NIST_P256,
+#endif
+#if PKA_USE_BRAINPOOL_P256R1
+ PKA_BRAINPOOL_P256R1,
+#endif
+#if PKA_USE_BRAINPOOL_P256T1
+ PKA_BRAINPOOL_P256T1,
+#endif
+#if PKA_USE_NIST_P521
+ PKA_NIST_P521,
+#endif
+};
+
+struct stm32_pka_platdata {
+ uintptr_t base;
+ unsigned long clock_id;
+ unsigned int reset_id;
+};
+
+int stm32_pka_init(void);
+int stm32_pka_ecdsa_verif(void *hash, unsigned int hash_size,
+ void *sig_r_ptr, unsigned int sig_r_size,
+ void *sig_s_ptr, unsigned int sig_s_size,
+ void *pk_x_ptr, unsigned int pk_x_size,
+ void *pk_y_ptr, unsigned int pk_y_size,
+ enum stm32_pka_ecdsa_curve_id cid);
+
+#endif /* STM32_PKA_H */
diff --git a/include/drivers/st/stm32_qspi.h b/include/drivers/st/stm32_qspi.h
new file mode 100644
index 0000000..f47fca4
--- /dev/null
+++ b/include/drivers/st/stm32_qspi.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#ifndef STM32_QSPI_H
+#define STM32_QSPI_H
+
+int stm32_qspi_init(void);
+
+#endif /* STM32_QSPI_H */
diff --git a/include/drivers/st/stm32_rng.h b/include/drivers/st/stm32_rng.h
new file mode 100644
index 0000000..6ac064d
--- /dev/null
+++ b/include/drivers/st/stm32_rng.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_RNG_H
+#define STM32_RNG_H
+
+#include <stdint.h>
+
+int stm32_rng_read(uint8_t *out, uint32_t size);
+int stm32_rng_init(void);
+
+#endif /* STM32_RNG_H */
diff --git a/include/drivers/st/stm32_saes.h b/include/drivers/st/stm32_saes.h
new file mode 100644
index 0000000..0a50438
--- /dev/null
+++ b/include/drivers/st/stm32_saes.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_SAES_H
+#define STM32_SAES_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#define DT_SAES_COMPAT "st,stm32-saes"
+
+struct stm32_saes_platdata {
+ uintptr_t base;
+ unsigned long clock_id;
+ unsigned int reset_id;
+};
+
+enum stm32_saes_chaining_mode {
+ STM32_SAES_MODE_ECB,
+ STM32_SAES_MODE_CBC,
+ STM32_SAES_MODE_CTR,
+ STM32_SAES_MODE_GCM,
+ STM32_SAES_MODE_CCM, /* Not use in TF-A */
+};
+
+enum stm32_saes_key_selection {
+ STM32_SAES_KEY_SOFT,
+ STM32_SAES_KEY_DHU, /* Derived HW unique key */
+ STM32_SAES_KEY_BH, /* Boot HW key */
+ STM32_SAES_KEY_BHU_XOR_BH, /* XOR of DHUK and BHK */
+ STM32_SAES_KEY_WRAPPED
+};
+
+struct stm32_saes_context {
+ uintptr_t base;
+ uint32_t cr;
+ uint32_t assoc_len;
+ uint32_t load_len;
+ uint32_t key[8]; /* In HW byte order */
+ uint32_t iv[4]; /* In HW byte order */
+};
+
+int stm32_saes_driver_init(void);
+
+int stm32_saes_init(struct stm32_saes_context *ctx, bool is_decrypt,
+ enum stm32_saes_chaining_mode ch_mode, enum stm32_saes_key_selection key_select,
+ const void *key, size_t key_len, const void *iv, size_t iv_len);
+int stm32_saes_update(struct stm32_saes_context *ctx, bool last_block,
+ uint8_t *data_in, uint8_t *data_out, size_t data_len);
+int stm32_saes_update_assodata(struct stm32_saes_context *ctx, bool last_block,
+ uint8_t *data, size_t data_len);
+int stm32_saes_update_load(struct stm32_saes_context *ctx, bool last_block,
+ uint8_t *data_in, uint8_t *data_out, size_t data_len);
+int stm32_saes_final(struct stm32_saes_context *ctx, uint8_t *tag, size_t tag_len);
+#endif
diff --git a/include/drivers/st/stm32_sdmmc2.h b/include/drivers/st/stm32_sdmmc2.h
new file mode 100644
index 0000000..c83f625
--- /dev/null
+++ b/include/drivers/st/stm32_sdmmc2.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_SDMMC2_H
+#define STM32_SDMMC2_H
+
+#include <stdbool.h>
+
+#include <drivers/mmc.h>
+#include <drivers/st/regulator.h>
+
+struct stm32_sdmmc2_params {
+ uintptr_t reg_base;
+ unsigned int clk_rate;
+ unsigned int bus_width;
+ unsigned int flags;
+ struct mmc_device_info *device_info;
+ unsigned int pin_ckin;
+ unsigned int negedge;
+ unsigned int dirpol;
+ unsigned int clock_id;
+ unsigned int reset_id;
+ unsigned int max_freq;
+ bool use_dma;
+ struct rdev *vmmc_regu;
+};
+
+unsigned long long stm32_sdmmc2_mmc_get_device_size(void);
+int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params);
+bool plat_sdmmc2_use_dma(unsigned int instance, unsigned int memory);
+
+#endif /* STM32_SDMMC2_H */
diff --git a/include/drivers/st/stm32_uart.h b/include/drivers/st/stm32_uart.h
new file mode 100644
index 0000000..866e158
--- /dev/null
+++ b/include/drivers/st/stm32_uart.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_UART_H
+#define STM32_UART_H
+
+/* UART word length */
+#define STM32_UART_WORDLENGTH_7B USART_CR1_M1
+#define STM32_UART_WORDLENGTH_8B 0x00000000U
+#define STM32_UART_WORDLENGTH_9B USART_CR1_M0
+
+/* UART number of stop bits */
+#define STM32_UART_STOPBITS_0_5 USART_CR2_STOP_0
+#define STM32_UART_STOPBITS_1 0x00000000U
+#define STM32_UART_STOPBITS_1_5 (USART_CR2_STOP_0 | USART_CR2_STOP_1)
+#define STM32_UART_STOPBITS_2 USART_CR2_STOP_1
+
+/* UART parity */
+#define STM32_UART_PARITY_NONE 0x00000000U
+#define STM32_UART_PARITY_EVEN USART_CR1_PCE
+#define STM32_UART_PARITY_ODD (USART_CR1_PCE | USART_CR1_PS)
+
+/* UART transfer mode */
+#define STM32_UART_MODE_RX USART_CR1_RE
+#define STM32_UART_MODE_TX USART_CR1_TE
+#define STM32_UART_MODE_TX_RX (USART_CR1_TE | USART_CR1_RE)
+
+/* UART hardware flow control */
+#define STM32_UART_HWCONTROL_NONE 0x00000000U
+#define STM32_UART_HWCONTROL_RTS USART_CR3_RTSE
+#define STM32_UART_HWCONTROL_CTS USART_CR3_CTSE
+#define STM32_UART_HWCONTROL_RTS_CTS (USART_CR3_RTSE | USART_CR3_CTSE)
+
+/* UART prescaler */
+#define STM32_UART_PRESCALER_DIV1 0x00000000U
+#define STM32_UART_PRESCALER_DIV2 0x00000001U
+#define STM32_UART_PRESCALER_DIV4 0x00000002U
+#define STM32_UART_PRESCALER_DIV6 0x00000003U
+#define STM32_UART_PRESCALER_DIV8 0x00000004U
+#define STM32_UART_PRESCALER_DIV10 0x00000005U
+#define STM32_UART_PRESCALER_DIV12 0x00000006U
+#define STM32_UART_PRESCALER_DIV16 0x00000007U
+#define STM32_UART_PRESCALER_DIV32 0x00000008U
+#define STM32_UART_PRESCALER_DIV64 0x00000009U
+#define STM32_UART_PRESCALER_DIV128 0x0000000AU
+#define STM32_UART_PRESCALER_DIV256 0x0000000BU
+#define STM32_UART_PRESCALER_NB 0x0000000CU
+
+/* UART fifo mode */
+#define STM32_UART_FIFOMODE_EN USART_CR1_FIFOEN
+#define STM32_UART_FIFOMODE_DIS 0x00000000U
+
+/* UART TXFIFO threshold level */
+#define STM32_UART_TXFIFO_THRESHOLD_1EIGHTHFULL 0x00000000U
+#define STM32_UART_TXFIFO_THRESHOLD_1QUARTERFUL USART_CR3_TXFTCFG_0
+#define STM32_UART_TXFIFO_THRESHOLD_HALFFULL USART_CR3_TXFTCFG_1
+#define STM32_UART_TXFIFO_THRESHOLD_3QUARTERSFULL (USART_CR3_TXFTCFG_0 | USART_CR3_TXFTCFG_1)
+#define STM32_UART_TXFIFO_THRESHOLD_7EIGHTHFULL USART_CR3_TXFTCFG_2
+#define STM32_UART_TXFIFO_THRESHOLD_EMPTY (USART_CR3_TXFTCFG_2 | USART_CR3_TXFTCFG_0)
+
+/* UART RXFIFO threshold level */
+#define STM32_UART_RXFIFO_THRESHOLD_1EIGHTHFULL 0x00000000U
+#define STM32_UART_RXFIFO_THRESHOLD_1QUARTERFULL USART_CR3_RXFTCFG_0
+#define STM32_UART_RXFIFO_THRESHOLD_HALFFULL USART_CR3_RXFTCFG_1
+#define STM32_UART_RXFIFO_THRESHOLD_3QUARTERSFULL (USART_CR3_RXFTCFG_0 | USART_CR3_RXFTCFG_1)
+#define STM32_UART_RXFIFO_THRESHOLD_7EIGHTHFULL USART_CR3_RXFTCFG_2
+#define STM32_UART_RXFIFO_THRESHOLD_FULL (USART_CR3_RXFTCFG_2 | USART_CR3_RXFTCFG_0)
+
+struct stm32_uart_init_s {
+ uint32_t baud_rate; /*
+ * Configures the UART communication
+ * baud rate.
+ */
+
+ uint32_t word_length; /*
+ * Specifies the number of data bits
+ * transmitted or received in a frame.
+ * This parameter can be a value of
+ * @ref STM32_UART_WORDLENGTH_*.
+ */
+
+ uint32_t stop_bits; /*
+ * Specifies the number of stop bits
+ * transmitted. This parameter can be
+ * a value of @ref STM32_UART_STOPBITS_*.
+ */
+
+ uint32_t parity; /*
+ * Specifies the parity mode.
+ * This parameter can be a value of
+ * @ref STM32_UART_PARITY_*.
+ */
+
+ uint32_t mode; /*
+ * Specifies whether the receive or
+ * transmit mode is enabled or
+ * disabled. This parameter can be a
+ * value of @ref @ref STM32_UART_MODE_*.
+ */
+
+ uint32_t hw_flow_control; /*
+ * Specifies whether the hardware flow
+ * control mode is enabled or
+ * disabled. This parameter can be a
+ * value of @ref STM32_UARTHWCONTROL_*.
+ */
+
+ uint32_t one_bit_sampling; /*
+ * Specifies whether a single sample
+ * or three samples' majority vote is
+ * selected. This parameter can be 0
+ * or USART_CR3_ONEBIT.
+ */
+
+ uint32_t prescaler; /*
+ * Specifies the prescaler value used
+ * to divide the UART clock source.
+ * This parameter can be a value of
+ * @ref STM32_UART_PRESCALER_*.
+ */
+
+ uint32_t fifo_mode; /*
+ * Specifies if the FIFO mode will be
+ * used. This parameter can be a value
+ * of @ref STM32_UART_FIFOMODE_*.
+ */
+
+ uint32_t tx_fifo_threshold; /*
+ * Specifies the TXFIFO threshold
+ * level. This parameter can be a
+ * value of @ref
+ * STM32_UART_TXFIFO_THRESHOLD_*.
+ */
+
+ uint32_t rx_fifo_threshold; /*
+ * Specifies the RXFIFO threshold
+ * level. This parameter can be a
+ * value of @ref
+ * STM32_UART_RXFIFO_THRESHOLD_*.
+ */
+};
+
+struct stm32_uart_handle_s {
+ uint32_t base;
+ uint32_t rdr_mask;
+};
+
+int stm32_uart_init(struct stm32_uart_handle_s *huart,
+ uintptr_t base_addr,
+ const struct stm32_uart_init_s *init);
+void stm32_uart_stop(uintptr_t base_addr);
+int stm32_uart_putc(struct stm32_uart_handle_s *huart, int c);
+int stm32_uart_flush(struct stm32_uart_handle_s *huart);
+int stm32_uart_getc(struct stm32_uart_handle_s *huart);
+
+#endif /* STM32_UART_H */
diff --git a/include/drivers/st/stm32_uart_regs.h b/include/drivers/st/stm32_uart_regs.h
new file mode 100644
index 0000000..14b296c
--- /dev/null
+++ b/include/drivers/st/stm32_uart_regs.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_UART_REGS_H
+#define STM32_UART_REGS_H
+
+#include <lib/utils_def.h>
+
+#define USART_CR1 U(0x00)
+#define USART_CR2 U(0x04)
+#define USART_CR3 U(0x08)
+#define USART_BRR U(0x0C)
+#define USART_GTPR U(0x10)
+#define USART_RTOR U(0x14)
+#define USART_RQR U(0x18)
+#define USART_ISR U(0x1C)
+#define USART_ICR U(0x20)
+#define USART_RDR U(0x24)
+#define USART_TDR U(0x28)
+#define USART_PRESC U(0x2C)
+
+/* USART_CR1 register fields */
+#define USART_CR1_UE BIT(0)
+#define USART_CR1_UESM BIT(1)
+#define USART_CR1_RE BIT(2)
+#define USART_CR1_TE BIT(3)
+#define USART_CR1_IDLEIE BIT(4)
+#define USART_CR1_RXNEIE BIT(5)
+#define USART_CR1_TCIE BIT(6)
+#define USART_CR1_TXEIE BIT(7)
+#define USART_CR1_PEIE BIT(8)
+#define USART_CR1_PS BIT(9)
+#define USART_CR1_PCE BIT(10)
+#define USART_CR1_WAKE BIT(11)
+#define USART_CR1_M (BIT(28) | BIT(12))
+#define USART_CR1_M0 BIT(12)
+#define USART_CR1_MME BIT(13)
+#define USART_CR1_CMIE BIT(14)
+#define USART_CR1_OVER8 BIT(15)
+#define USART_CR1_DEDT GENMASK(20, 16)
+#define USART_CR1_DEDT_0 BIT(16)
+#define USART_CR1_DEDT_1 BIT(17)
+#define USART_CR1_DEDT_2 BIT(18)
+#define USART_CR1_DEDT_3 BIT(19)
+#define USART_CR1_DEDT_4 BIT(20)
+#define USART_CR1_DEAT GENMASK(25, 21)
+#define USART_CR1_DEAT_0 BIT(21)
+#define USART_CR1_DEAT_1 BIT(22)
+#define USART_CR1_DEAT_2 BIT(23)
+#define USART_CR1_DEAT_3 BIT(24)
+#define USART_CR1_DEAT_4 BIT(25)
+#define USART_CR1_RTOIE BIT(26)
+#define USART_CR1_EOBIE BIT(27)
+#define USART_CR1_M1 BIT(28)
+#define USART_CR1_FIFOEN BIT(29)
+#define USART_CR1_TXFEIE BIT(30)
+#define USART_CR1_RXFFIE BIT(31)
+
+/* USART_CR2 register fields */
+#define USART_CR2_SLVEN BIT(0)
+#define USART_CR2_DIS_NSS BIT(3)
+#define USART_CR2_ADDM7 BIT(4)
+#define USART_CR2_LBDL BIT(5)
+#define USART_CR2_LBDIE BIT(6)
+#define USART_CR2_LBCL BIT(8)
+#define USART_CR2_CPHA BIT(9)
+#define USART_CR2_CPOL BIT(10)
+#define USART_CR2_CLKEN BIT(11)
+#define USART_CR2_STOP GENMASK(13, 12)
+#define USART_CR2_STOP_0 BIT(12)
+#define USART_CR2_STOP_1 BIT(13)
+#define USART_CR2_LINEN BIT(14)
+#define USART_CR2_SWAP BIT(15)
+#define USART_CR2_RXINV BIT(16)
+#define USART_CR2_TXINV BIT(17)
+#define USART_CR2_DATAINV BIT(18)
+#define USART_CR2_MSBFIRST BIT(19)
+#define USART_CR2_ABREN BIT(20)
+#define USART_CR2_ABRMODE GENMASK(22, 21)
+#define USART_CR2_ABRMODE_0 BIT(21)
+#define USART_CR2_ABRMODE_1 BIT(22)
+#define USART_CR2_RTOEN BIT(23)
+#define USART_CR2_ADD GENMASK(31, 24)
+
+/* USART_CR3 register fields */
+#define USART_CR3_EIE BIT(0)
+#define USART_CR3_IREN BIT(1)
+#define USART_CR3_IRLP BIT(2)
+#define USART_CR3_HDSEL BIT(3)
+#define USART_CR3_NACK BIT(4)
+#define USART_CR3_SCEN BIT(5)
+#define USART_CR3_DMAR BIT(6)
+#define USART_CR3_DMAT BIT(7)
+#define USART_CR3_RTSE BIT(8)
+#define USART_CR3_CTSE BIT(9)
+#define USART_CR3_CTSIE BIT(10)
+#define USART_CR3_ONEBIT BIT(11)
+#define USART_CR3_OVRDIS BIT(12)
+#define USART_CR3_DDRE BIT(13)
+#define USART_CR3_DEM BIT(14)
+#define USART_CR3_DEP BIT(15)
+#define USART_CR3_SCARCNT GENMASK(19, 17)
+#define USART_CR3_SCARCNT_0 BIT(17)
+#define USART_CR3_SCARCNT_1 BIT(18)
+#define USART_CR3_SCARCNT_2 BIT(19)
+#define USART_CR3_WUS GENMASK(21, 20)
+#define USART_CR3_WUS_0 BIT(20)
+#define USART_CR3_WUS_1 BIT(21)
+#define USART_CR3_WUFIE BIT(22)
+#define USART_CR3_TXFTIE BIT(23)
+#define USART_CR3_TCBGTIE BIT(24)
+#define USART_CR3_RXFTCFG GENMASK(27, 25)
+#define USART_CR3_RXFTCFG_0 BIT(25)
+#define USART_CR3_RXFTCFG_1 BIT(26)
+#define USART_CR3_RXFTCFG_2 BIT(27)
+#define USART_CR3_RXFTIE BIT(28)
+#define USART_CR3_TXFTCFG GENMASK(31, 29)
+#define USART_CR3_TXFTCFG_0 BIT(29)
+#define USART_CR3_TXFTCFG_1 BIT(30)
+#define USART_CR3_TXFTCFG_2 BIT(31)
+
+/* USART_BRR register fields */
+#define USART_BRR_DIV_FRACTION GENMASK(3, 0)
+#define USART_BRR_DIV_MANTISSA GENMASK(15, 4)
+
+/* USART_GTPR register fields */
+#define USART_GTPR_PSC GENMASK(7, 0)
+#define USART_GTPR_GT GENMASK(15, 8)
+
+/* USART_RTOR register fields */
+#define USART_RTOR_RTO GENMASK(23, 0)
+#define USART_RTOR_BLEN GENMASK(31, 24)
+
+/* USART_RQR register fields */
+#define USART_RQR_ABRRQ BIT(0)
+#define USART_RQR_SBKRQ BIT(1)
+#define USART_RQR_MMRQ BIT(2)
+#define USART_RQR_RXFRQ BIT(3)
+#define USART_RQR_TXFRQ BIT(4)
+
+/* USART_ISR register fields */
+#define USART_ISR_PE BIT(0)
+#define USART_ISR_FE BIT(1)
+#define USART_ISR_NE BIT(2)
+#define USART_ISR_ORE BIT(3)
+#define USART_ISR_IDLE BIT(4)
+#define USART_ISR_RXNE BIT(5)
+#define USART_ISR_TC BIT(6)
+#define USART_ISR_TXE BIT(7)
+#define USART_ISR_LBDF BIT(8)
+#define USART_ISR_CTSIF BIT(9)
+#define USART_ISR_CTS BIT(10)
+#define USART_ISR_RTOF BIT(11)
+#define USART_ISR_EOBF BIT(12)
+#define USART_ISR_UDR BIT(13)
+#define USART_ISR_ABRE BIT(14)
+#define USART_ISR_ABRF BIT(15)
+#define USART_ISR_BUSY BIT(16)
+#define USART_ISR_CMF BIT(17)
+#define USART_ISR_SBKF BIT(18)
+#define USART_ISR_RWU BIT(19)
+#define USART_ISR_WUF BIT(20)
+#define USART_ISR_TEACK BIT(21)
+#define USART_ISR_REACK BIT(22)
+#define USART_ISR_TXFE BIT(23)
+#define USART_ISR_RXFF BIT(24)
+#define USART_ISR_TCBGT BIT(25)
+#define USART_ISR_RXFT BIT(26)
+#define USART_ISR_TXFT BIT(27)
+
+/* USART_ICR register fields */
+#define USART_ICR_PECF BIT(0)
+#define USART_ICR_FECF BIT(1)
+#define USART_ICR_NCF BIT(2)
+#define USART_ICR_ORECF BIT(3)
+#define USART_ICR_IDLECF BIT(4)
+#define USART_ICR_TCCF BIT(6)
+#define USART_ICR_TCBGT BIT(7)
+#define USART_ICR_LBDCF BIT(8)
+#define USART_ICR_CTSCF BIT(9)
+#define USART_ICR_RTOCF BIT(11)
+#define USART_ICR_EOBCF BIT(12)
+#define USART_ICR_UDRCF BIT(13)
+#define USART_ICR_CMCF BIT(17)
+#define USART_ICR_WUCF BIT(20)
+
+/* USART_RDR register fields */
+#define USART_RDR_RDR GENMASK(8, 0)
+
+/* USART_TDR register fields */
+#define USART_TDR_TDR GENMASK(8, 0)
+
+/* USART_PRESC register fields */
+#define USART_PRESC_PRESCALER GENMASK(3, 0)
+
+#endif /* STM32_UART_REGS_H */
diff --git a/include/drivers/st/stm32mp13_rcc.h b/include/drivers/st/stm32mp13_rcc.h
new file mode 100644
index 0000000..1451c9a
--- /dev/null
+++ b/include/drivers/st/stm32mp13_rcc.h
@@ -0,0 +1,1878 @@
+/*
+ * Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP13_RCC_H
+#define STM32MP13_RCC_H
+
+#include <lib/utils_def.h>
+
+#define RCC_SECCFGR U(0X0)
+#define RCC_MP_SREQSETR U(0X100)
+#define RCC_MP_SREQCLRR U(0X104)
+#define RCC_MP_APRSTCR U(0X108)
+#define RCC_MP_APRSTSR U(0X10C)
+#define RCC_PWRLPDLYCR U(0X110)
+#define RCC_MP_GRSTCSETR U(0X114)
+#define RCC_BR_RSTSCLRR U(0X118)
+#define RCC_MP_RSTSSETR U(0X11C)
+#define RCC_MP_RSTSCLRR U(0X120)
+#define RCC_MP_IWDGFZSETR U(0X124)
+#define RCC_MP_IWDGFZCLRR U(0X128)
+#define RCC_MP_CIER U(0X200)
+#define RCC_MP_CIFR U(0X204)
+#define RCC_BDCR U(0X400)
+#define RCC_RDLSICR U(0X404)
+#define RCC_OCENSETR U(0X420)
+#define RCC_OCENCLRR U(0X424)
+#define RCC_OCRDYR U(0X428)
+#define RCC_HSICFGR U(0X440)
+#define RCC_CSICFGR U(0X444)
+#define RCC_MCO1CFGR U(0X460)
+#define RCC_MCO2CFGR U(0X464)
+#define RCC_DBGCFGR U(0X468)
+#define RCC_RCK12SELR U(0X480)
+#define RCC_RCK3SELR U(0X484)
+#define RCC_RCK4SELR U(0X488)
+#define RCC_PLL1CR U(0X4A0)
+#define RCC_PLL1CFGR1 U(0X4A4)
+#define RCC_PLL1CFGR2 U(0X4A8)
+#define RCC_PLL1FRACR U(0X4AC)
+#define RCC_PLL1CSGR U(0X4B0)
+#define RCC_PLL2CR U(0X4D0)
+#define RCC_PLL2CFGR1 U(0X4D4)
+#define RCC_PLL2CFGR2 U(0X4D8)
+#define RCC_PLL2FRACR U(0X4DC)
+#define RCC_PLL2CSGR U(0X4E0)
+#define RCC_PLL3CR U(0X500)
+#define RCC_PLL3CFGR1 U(0X504)
+#define RCC_PLL3CFGR2 U(0X508)
+#define RCC_PLL3FRACR U(0X50C)
+#define RCC_PLL3CSGR U(0X510)
+#define RCC_PLL4CR U(0X520)
+#define RCC_PLL4CFGR1 U(0X524)
+#define RCC_PLL4CFGR2 U(0X528)
+#define RCC_PLL4FRACR U(0X52C)
+#define RCC_PLL4CSGR U(0X530)
+#define RCC_MPCKSELR U(0X540)
+#define RCC_ASSCKSELR U(0X544)
+#define RCC_MSSCKSELR U(0X548)
+#define RCC_CPERCKSELR U(0X54C)
+#define RCC_RTCDIVR U(0X560)
+#define RCC_MPCKDIVR U(0X564)
+#define RCC_AXIDIVR U(0X568)
+#define RCC_MLAHBDIVR U(0X56C)
+#define RCC_APB1DIVR U(0X570)
+#define RCC_APB2DIVR U(0X574)
+#define RCC_APB3DIVR U(0X578)
+#define RCC_APB4DIVR U(0X57C)
+#define RCC_APB5DIVR U(0X580)
+#define RCC_APB6DIVR U(0X584)
+#define RCC_TIMG1PRER U(0X5A0)
+#define RCC_TIMG2PRER U(0X5A4)
+#define RCC_TIMG3PRER U(0X5A8)
+#define RCC_DDRITFCR U(0X5C0)
+#define RCC_I2C12CKSELR U(0X600)
+#define RCC_I2C345CKSELR U(0X604)
+#define RCC_SPI2S1CKSELR U(0X608)
+#define RCC_SPI2S23CKSELR U(0X60C)
+#define RCC_SPI45CKSELR U(0X610)
+#define RCC_UART12CKSELR U(0X614)
+#define RCC_UART35CKSELR U(0X618)
+#define RCC_UART4CKSELR U(0X61C)
+#define RCC_UART6CKSELR U(0X620)
+#define RCC_UART78CKSELR U(0X624)
+#define RCC_LPTIM1CKSELR U(0X628)
+#define RCC_LPTIM23CKSELR U(0X62C)
+#define RCC_LPTIM45CKSELR U(0X630)
+#define RCC_SAI1CKSELR U(0X634)
+#define RCC_SAI2CKSELR U(0X638)
+#define RCC_FDCANCKSELR U(0X63C)
+#define RCC_SPDIFCKSELR U(0X640)
+#define RCC_ADC12CKSELR U(0X644)
+#define RCC_SDMMC12CKSELR U(0X648)
+#define RCC_ETH12CKSELR U(0X64C)
+#define RCC_USBCKSELR U(0X650)
+#define RCC_QSPICKSELR U(0X654)
+#define RCC_FMCCKSELR U(0X658)
+#define RCC_RNG1CKSELR U(0X65C)
+#define RCC_STGENCKSELR U(0X660)
+#define RCC_DCMIPPCKSELR U(0X664)
+#define RCC_SAESCKSELR U(0X668)
+#define RCC_APB1RSTSETR U(0X6A0)
+#define RCC_APB1RSTCLRR U(0X6A4)
+#define RCC_APB2RSTSETR U(0X6A8)
+#define RCC_APB2RSTCLRR U(0X6AC)
+#define RCC_APB3RSTSETR U(0X6B0)
+#define RCC_APB3RSTCLRR U(0X6B4)
+#define RCC_APB4RSTSETR U(0X6B8)
+#define RCC_APB4RSTCLRR U(0X6BC)
+#define RCC_APB5RSTSETR U(0X6C0)
+#define RCC_APB5RSTCLRR U(0X6C4)
+#define RCC_APB6RSTSETR U(0X6C8)
+#define RCC_APB6RSTCLRR U(0X6CC)
+#define RCC_AHB2RSTSETR U(0X6D0)
+#define RCC_AHB2RSTCLRR U(0X6D4)
+#define RCC_AHB4RSTSETR U(0X6E0)
+#define RCC_AHB4RSTCLRR U(0X6E4)
+#define RCC_AHB5RSTSETR U(0X6E8)
+#define RCC_AHB5RSTCLRR U(0X6EC)
+#define RCC_AHB6RSTSETR U(0X6F0)
+#define RCC_AHB6RSTCLRR U(0X6F4)
+#define RCC_MP_APB1ENSETR U(0X700)
+#define RCC_MP_APB1ENCLRR U(0X704)
+#define RCC_MP_APB2ENSETR U(0X708)
+#define RCC_MP_APB2ENCLRR U(0X70C)
+#define RCC_MP_APB3ENSETR U(0X710)
+#define RCC_MP_APB3ENCLRR U(0X714)
+#define RCC_MP_S_APB3ENSETR U(0X718)
+#define RCC_MP_S_APB3ENCLRR U(0X71C)
+#define RCC_MP_NS_APB3ENSETR U(0X720)
+#define RCC_MP_NS_APB3ENCLRR U(0X724)
+#define RCC_MP_APB4ENSETR U(0X728)
+#define RCC_MP_APB4ENCLRR U(0X72C)
+#define RCC_MP_S_APB4ENSETR U(0X730)
+#define RCC_MP_S_APB4ENCLRR U(0X734)
+#define RCC_MP_NS_APB4ENSETR U(0X738)
+#define RCC_MP_NS_APB4ENCLRR U(0X73C)
+#define RCC_MP_APB5ENSETR U(0X740)
+#define RCC_MP_APB5ENCLRR U(0X744)
+#define RCC_MP_APB6ENSETR U(0X748)
+#define RCC_MP_APB6ENCLRR U(0X74C)
+#define RCC_MP_AHB2ENSETR U(0X750)
+#define RCC_MP_AHB2ENCLRR U(0X754)
+#define RCC_MP_AHB4ENSETR U(0X760)
+#define RCC_MP_AHB4ENCLRR U(0X764)
+#define RCC_MP_S_AHB4ENSETR U(0X768)
+#define RCC_MP_S_AHB4ENCLRR U(0X76C)
+#define RCC_MP_NS_AHB4ENSETR U(0X770)
+#define RCC_MP_NS_AHB4ENCLRR U(0X774)
+#define RCC_MP_AHB5ENSETR U(0X778)
+#define RCC_MP_AHB5ENCLRR U(0X77C)
+#define RCC_MP_AHB6ENSETR U(0X780)
+#define RCC_MP_AHB6ENCLRR U(0X784)
+#define RCC_MP_S_AHB6ENSETR U(0X788)
+#define RCC_MP_S_AHB6ENCLRR U(0X78C)
+#define RCC_MP_NS_AHB6ENSETR U(0X790)
+#define RCC_MP_NS_AHB6ENCLRR U(0X794)
+#define RCC_MP_APB1LPENSETR U(0X800)
+#define RCC_MP_APB1LPENCLRR U(0X804)
+#define RCC_MP_APB2LPENSETR U(0X808)
+#define RCC_MP_APB2LPENCLRR U(0X80C)
+#define RCC_MP_APB3LPENSETR U(0X810)
+#define RCC_MP_APB3LPENCLRR U(0X814)
+#define RCC_MP_S_APB3LPENSETR U(0X818)
+#define RCC_MP_S_APB3LPENCLRR U(0X81C)
+#define RCC_MP_NS_APB3LPENSETR U(0X820)
+#define RCC_MP_NS_APB3LPENCLRR U(0X824)
+#define RCC_MP_APB4LPENSETR U(0X828)
+#define RCC_MP_APB4LPENCLRR U(0X82C)
+#define RCC_MP_S_APB4LPENSETR U(0X830)
+#define RCC_MP_S_APB4LPENCLRR U(0X834)
+#define RCC_MP_NS_APB4LPENSETR U(0X838)
+#define RCC_MP_NS_APB4LPENCLRR U(0X83C)
+#define RCC_MP_APB5LPENSETR U(0X840)
+#define RCC_MP_APB5LPENCLRR U(0X844)
+#define RCC_MP_APB6LPENSETR U(0X848)
+#define RCC_MP_APB6LPENCLRR U(0X84C)
+#define RCC_MP_AHB2LPENSETR U(0X850)
+#define RCC_MP_AHB2LPENCLRR U(0X854)
+#define RCC_MP_AHB4LPENSETR U(0X858)
+#define RCC_MP_AHB4LPENCLRR U(0X85C)
+#define RCC_MP_S_AHB4LPENSETR U(0X868)
+#define RCC_MP_S_AHB4LPENCLRR U(0X86C)
+#define RCC_MP_NS_AHB4LPENSETR U(0X870)
+#define RCC_MP_NS_AHB4LPENCLRR U(0X874)
+#define RCC_MP_AHB5LPENSETR U(0X878)
+#define RCC_MP_AHB5LPENCLRR U(0X87C)
+#define RCC_MP_AHB6LPENSETR U(0X880)
+#define RCC_MP_AHB6LPENCLRR U(0X884)
+#define RCC_MP_S_AHB6LPENSETR U(0X888)
+#define RCC_MP_S_AHB6LPENCLRR U(0X88C)
+#define RCC_MP_NS_AHB6LPENSETR U(0X890)
+#define RCC_MP_NS_AHB6LPENCLRR U(0X894)
+#define RCC_MP_S_AXIMLPENSETR U(0X898)
+#define RCC_MP_S_AXIMLPENCLRR U(0X89C)
+#define RCC_MP_NS_AXIMLPENSETR U(0X8A0)
+#define RCC_MP_NS_AXIMLPENCLRR U(0X8A4)
+#define RCC_MP_MLAHBLPENSETR U(0X8A8)
+#define RCC_MP_MLAHBLPENCLRR U(0X8AC)
+#define RCC_APB3SECSR U(0X8C0)
+#define RCC_APB4SECSR U(0X8C4)
+#define RCC_APB5SECSR U(0X8C8)
+#define RCC_APB6SECSR U(0X8CC)
+#define RCC_AHB2SECSR U(0X8D0)
+#define RCC_AHB4SECSR U(0X8D4)
+#define RCC_AHB5SECSR U(0X8D8)
+#define RCC_AHB6SECSR U(0X8DC)
+#define RCC_VERR U(0XFF4)
+#define RCC_IDR U(0XFF8)
+#define RCC_SIDR U(0XFFC)
+
+/* RCC_SECCFGR register fields */
+#define RCC_SECCFGR_HSISEC BIT(0)
+#define RCC_SECCFGR_CSISEC BIT(1)
+#define RCC_SECCFGR_HSESEC BIT(2)
+#define RCC_SECCFGR_LSISEC BIT(3)
+#define RCC_SECCFGR_LSESEC BIT(4)
+#define RCC_SECCFGR_PLL12SEC BIT(8)
+#define RCC_SECCFGR_PLL3SEC BIT(9)
+#define RCC_SECCFGR_PLL4SEC BIT(10)
+#define RCC_SECCFGR_MPUSEC BIT(11)
+#define RCC_SECCFGR_AXISEC BIT(12)
+#define RCC_SECCFGR_MLAHBSEC BIT(13)
+#define RCC_SECCFGR_APB3DIVSEC BIT(16)
+#define RCC_SECCFGR_APB4DIVSEC BIT(17)
+#define RCC_SECCFGR_APB5DIVSEC BIT(18)
+#define RCC_SECCFGR_APB6DIVSEC BIT(19)
+#define RCC_SECCFGR_TIMG3SEC BIT(20)
+#define RCC_SECCFGR_CPERSEC BIT(21)
+#define RCC_SECCFGR_MCO1SEC BIT(22)
+#define RCC_SECCFGR_MCO2SEC BIT(23)
+#define RCC_SECCFGR_STPSEC BIT(24)
+#define RCC_SECCFGR_RSTSEC BIT(25)
+#define RCC_SECCFGR_PWRSEC BIT(31)
+
+/* RCC_MP_SREQSETR register fields */
+#define RCC_MP_SREQSETR_STPREQ_P0 BIT(0)
+
+/* RCC_MP_SREQCLRR register fields */
+#define RCC_MP_SREQCLRR_STPREQ_P0 BIT(0)
+
+/* RCC_MP_APRSTCR register fields */
+#define RCC_MP_APRSTCR_RDCTLEN BIT(0)
+#define RCC_MP_APRSTCR_RSTTO_MASK GENMASK(14, 8)
+#define RCC_MP_APRSTCR_RSTTO_SHIFT 8
+
+/* RCC_MP_APRSTSR register fields */
+#define RCC_MP_APRSTSR_RSTTOV_MASK GENMASK(14, 8)
+#define RCC_MP_APRSTSR_RSTTOV_SHIFT 8
+
+/* RCC_PWRLPDLYCR register fields */
+#define RCC_PWRLPDLYCR_PWRLP_DLY_MASK GENMASK(21, 0)
+#define RCC_PWRLPDLYCR_PWRLP_DLY_SHIFT 0
+
+/* RCC_MP_GRSTCSETR register fields */
+#define RCC_MP_GRSTCSETR_MPSYSRST BIT(0)
+#define RCC_MP_GRSTCSETR_MPUP0RST BIT(4)
+
+/* RCC_BR_RSTSCLRR register fields */
+#define RCC_BR_RSTSCLRR_PORRSTF BIT(0)
+#define RCC_BR_RSTSCLRR_BORRSTF BIT(1)
+#define RCC_BR_RSTSCLRR_PADRSTF BIT(2)
+#define RCC_BR_RSTSCLRR_HCSSRSTF BIT(3)
+#define RCC_BR_RSTSCLRR_VCORERSTF BIT(4)
+#define RCC_BR_RSTSCLRR_VCPURSTF BIT(5)
+#define RCC_BR_RSTSCLRR_MPSYSRSTF BIT(6)
+#define RCC_BR_RSTSCLRR_IWDG1RSTF BIT(8)
+#define RCC_BR_RSTSCLRR_IWDG2RSTF BIT(9)
+#define RCC_BR_RSTSCLRR_MPUP0RSTF BIT(13)
+
+/* RCC_MP_RSTSSETR register fields */
+#define RCC_MP_RSTSSETR_PORRSTF BIT(0)
+#define RCC_MP_RSTSSETR_BORRSTF BIT(1)
+#define RCC_MP_RSTSSETR_PADRSTF BIT(2)
+#define RCC_MP_RSTSSETR_HCSSRSTF BIT(3)
+#define RCC_MP_RSTSSETR_VCORERSTF BIT(4)
+#define RCC_MP_RSTSSETR_VCPURSTF BIT(5)
+#define RCC_MP_RSTSSETR_MPSYSRSTF BIT(6)
+#define RCC_MP_RSTSSETR_IWDG1RSTF BIT(8)
+#define RCC_MP_RSTSSETR_IWDG2RSTF BIT(9)
+#define RCC_MP_RSTSSETR_STP2RSTF BIT(10)
+#define RCC_MP_RSTSSETR_STDBYRSTF BIT(11)
+#define RCC_MP_RSTSSETR_CSTDBYRSTF BIT(12)
+#define RCC_MP_RSTSSETR_MPUP0RSTF BIT(13)
+#define RCC_MP_RSTSSETR_SPARE BIT(15)
+
+/* RCC_MP_RSTSCLRR register fields */
+#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_VCPURSTF BIT(5)
+#define RCC_MP_RSTSCLRR_MPSYSRSTF BIT(6)
+#define RCC_MP_RSTSCLRR_IWDG1RSTF BIT(8)
+#define RCC_MP_RSTSCLRR_IWDG2RSTF BIT(9)
+#define RCC_MP_RSTSCLRR_STP2RSTF BIT(10)
+#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_SPARE BIT(15)
+
+/* RCC_MP_IWDGFZSETR register fields */
+#define RCC_MP_IWDGFZSETR_FZ_IWDG1 BIT(0)
+#define RCC_MP_IWDGFZSETR_FZ_IWDG2 BIT(1)
+
+/* RCC_MP_IWDGFZCLRR register fields */
+#define RCC_MP_IWDGFZCLRR_FZ_IWDG1 BIT(0)
+#define RCC_MP_IWDGFZCLRR_FZ_IWDG2 BIT(1)
+
+/* RCC_MP_CIER register fields */
+#define RCC_MP_CIER_LSIRDYIE BIT(0)
+#define RCC_MP_CIER_LSERDYIE BIT(1)
+#define RCC_MP_CIER_HSIRDYIE BIT(2)
+#define RCC_MP_CIER_HSERDYIE BIT(3)
+#define RCC_MP_CIER_CSIRDYIE BIT(4)
+#define RCC_MP_CIER_PLL1DYIE BIT(8)
+#define RCC_MP_CIER_PLL2DYIE BIT(9)
+#define RCC_MP_CIER_PLL3DYIE BIT(10)
+#define RCC_MP_CIER_PLL4DYIE BIT(11)
+#define RCC_MP_CIER_LSECSSIE BIT(16)
+#define RCC_MP_CIER_WKUPIE BIT(20)
+
+/* RCC_MP_CIFR register fields */
+#define RCC_MP_CIFR_LSIRDYF BIT(0)
+#define RCC_MP_CIFR_LSERDYF BIT(1)
+#define RCC_MP_CIFR_HSIRDYF BIT(2)
+#define RCC_MP_CIFR_HSERDYF BIT(3)
+#define RCC_MP_CIFR_CSIRDYF BIT(4)
+#define RCC_MP_CIFR_PLL1DYF BIT(8)
+#define RCC_MP_CIFR_PLL2DYF BIT(9)
+#define RCC_MP_CIFR_PLL3DYF BIT(10)
+#define RCC_MP_CIFR_PLL4DYF BIT(11)
+#define RCC_MP_CIFR_LSECSSF BIT(16)
+#define RCC_MP_CIFR_WKUPF BIT(20)
+
+/* RCC_BDCR register fields */
+#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_LSECSSD BIT(9)
+#define RCC_BDCR_RTCSRC_MASK GENMASK(17, 16)
+#define RCC_BDCR_RTCSRC_SHIFT 16
+#define RCC_BDCR_RTCCKEN BIT(20)
+#define RCC_BDCR_VSWRST BIT(31)
+
+#define RCC_BDCR_LSEBYP_BIT 1
+#define RCC_BDCR_LSERDY_BIT 2
+#define RCC_BDCR_DIGBYP_BIT 3
+#define RCC_BDCR_LSECSSON_BIT 8
+
+#define RCC_BDCR_LSEDRV_WIDTH 2
+
+/* RCC_RDLSICR register fields */
+#define RCC_RDLSICR_LSION BIT(0)
+#define RCC_RDLSICR_LSIRDY BIT(1)
+#define RCC_RDLSICR_MRD_MASK GENMASK(20, 16)
+#define RCC_RDLSICR_MRD_SHIFT 16
+#define RCC_RDLSICR_EADLY_MASK GENMASK(26, 24)
+#define RCC_RDLSICR_EADLY_SHIFT 24
+#define RCC_RDLSICR_SPARE_MASK GENMASK(31, 27)
+#define RCC_RDLSICR_SPARE_SHIFT 27
+
+#define RCC_RDLSICR_LSIRDY_BIT 1
+
+/* RCC_OCENSETR register fields */
+#define RCC_OCENSETR_HSION BIT(0)
+#define RCC_OCENSETR_HSIKERON BIT(1)
+#define RCC_OCENSETR_CSION BIT(4)
+#define RCC_OCENSETR_CSIKERON BIT(5)
+#define RCC_OCENSETR_DIGBYP BIT(7)
+#define RCC_OCENSETR_HSEON BIT(8)
+#define RCC_OCENSETR_HSEKERON BIT(9)
+#define RCC_OCENSETR_HSEBYP BIT(10)
+#define RCC_OCENSETR_HSECSSON BIT(11)
+
+#define RCC_OCENR_DIGBYP_BIT 7
+#define RCC_OCENR_HSEBYP_BIT 10
+#define RCC_OCENR_HSECSSON_BIT 11
+
+/* RCC_OCENCLRR register fields */
+#define RCC_OCENCLRR_HSION BIT(0)
+#define RCC_OCENCLRR_HSIKERON BIT(1)
+#define RCC_OCENCLRR_CSION BIT(4)
+#define RCC_OCENCLRR_CSIKERON BIT(5)
+#define RCC_OCENCLRR_DIGBYP BIT(7)
+#define RCC_OCENCLRR_HSEON BIT(8)
+#define RCC_OCENCLRR_HSEKERON BIT(9)
+#define RCC_OCENCLRR_HSEBYP BIT(10)
+
+/* RCC_OCRDYR register fields */
+#define RCC_OCRDYR_HSIRDY BIT(0)
+#define RCC_OCRDYR_HSIDIVRDY BIT(2)
+#define RCC_OCRDYR_CSIRDY BIT(4)
+#define RCC_OCRDYR_HSERDY BIT(8)
+#define RCC_OCRDYR_MPUCKRDY BIT(23)
+#define RCC_OCRDYR_AXICKRDY BIT(24)
+
+#define RCC_OCRDYR_HSIRDY_BIT 0
+#define RCC_OCRDYR_HSIDIVRDY_BIT 2
+#define RCC_OCRDYR_CSIRDY_BIT 4
+#define RCC_OCRDYR_HSERDY_BIT 8
+
+/* RCC_HSICFGR register fields */
+#define RCC_HSICFGR_HSIDIV_MASK GENMASK(1, 0)
+#define RCC_HSICFGR_HSIDIV_SHIFT 0
+#define RCC_HSICFGR_HSITRIM_MASK GENMASK(14, 8)
+#define RCC_HSICFGR_HSITRIM_SHIFT 8
+#define RCC_HSICFGR_HSICAL_MASK GENMASK(27, 16)
+#define RCC_HSICFGR_HSICAL_SHIFT 16
+
+/* RCC_CSICFGR register fields */
+#define RCC_CSICFGR_CSITRIM_MASK GENMASK(12, 8)
+#define RCC_CSICFGR_CSITRIM_SHIFT 8
+#define RCC_CSICFGR_CSICAL_MASK GENMASK(23, 16)
+#define RCC_CSICFGR_CSICAL_SHIFT 16
+
+/* RCC_MCO1CFGR register fields */
+#define RCC_MCO1CFGR_MCO1SEL_MASK GENMASK(2, 0)
+#define RCC_MCO1CFGR_MCO1SEL_SHIFT 0
+#define RCC_MCO1CFGR_MCO1DIV_MASK GENMASK(7, 4)
+#define RCC_MCO1CFGR_MCO1DIV_SHIFT 4
+#define RCC_MCO1CFGR_MCO1ON BIT(12)
+
+/* RCC_MCO2CFGR register fields */
+#define RCC_MCO2CFGR_MCO2SEL_MASK GENMASK(2, 0)
+#define RCC_MCO2CFGR_MCO2SEL_SHIFT 0
+#define RCC_MCO2CFGR_MCO2DIV_MASK GENMASK(7, 4)
+#define RCC_MCO2CFGR_MCO2DIV_SHIFT 4
+#define RCC_MCO2CFGR_MCO2ON BIT(12)
+
+/* RCC_DBGCFGR register fields */
+#define RCC_DBGCFGR_TRACEDIV_MASK GENMASK(2, 0)
+#define RCC_DBGCFGR_TRACEDIV_SHIFT 0
+#define RCC_DBGCFGR_DBGCKEN BIT(8)
+#define RCC_DBGCFGR_TRACECKEN BIT(9)
+#define RCC_DBGCFGR_DBGRST BIT(12)
+
+/* RCC_RCK12SELR register fields */
+#define RCC_RCK12SELR_PLL12SRC_MASK GENMASK(1, 0)
+#define RCC_RCK12SELR_PLL12SRC_SHIFT 0
+#define RCC_RCK12SELR_PLL12SRCRDY BIT(31)
+
+/* RCC_RCK3SELR register fields */
+#define RCC_RCK3SELR_PLL3SRC_MASK GENMASK(1, 0)
+#define RCC_RCK3SELR_PLL3SRC_SHIFT 0
+#define RCC_RCK3SELR_PLL3SRCRDY BIT(31)
+
+/* RCC_RCK4SELR register fields */
+#define RCC_RCK4SELR_PLL4SRC_MASK GENMASK(1, 0)
+#define RCC_RCK4SELR_PLL4SRC_SHIFT 0
+#define RCC_RCK4SELR_PLL4SRCRDY BIT(31)
+
+/* RCC_PLL1CR register fields */
+#define RCC_PLL1CR_PLLON BIT(0)
+#define RCC_PLL1CR_PLL1RDY BIT(1)
+#define RCC_PLL1CR_SSCG_CTRL BIT(2)
+#define RCC_PLL1CR_DIVPEN BIT(4)
+#define RCC_PLL1CR_DIVQEN BIT(5)
+#define RCC_PLL1CR_DIVREN BIT(6)
+
+/* RCC_PLL1CFGR1 register fields */
+#define RCC_PLL1CFGR1_DIVN_MASK GENMASK(8, 0)
+#define RCC_PLL1CFGR1_DIVN_SHIFT 0
+#define RCC_PLL1CFGR1_DIVM1_MASK GENMASK(21, 16)
+#define RCC_PLL1CFGR1_DIVM1_SHIFT 16
+
+/* RCC_PLL1CFGR2 register fields */
+#define RCC_PLL1CFGR2_DIVP_MASK GENMASK(6, 0)
+#define RCC_PLL1CFGR2_DIVP_SHIFT 0
+#define RCC_PLL1CFGR2_DIVQ_MASK GENMASK(14, 8)
+#define RCC_PLL1CFGR2_DIVQ_SHIFT 8
+#define RCC_PLL1CFGR2_DIVR_MASK GENMASK(22, 16)
+#define RCC_PLL1CFGR2_DIVR_SHIFT 16
+
+/* RCC_PLL1FRACR register fields */
+#define RCC_PLL1FRACR_FRACV_MASK GENMASK(15, 3)
+#define RCC_PLL1FRACR_FRACV_SHIFT 3
+#define RCC_PLL1FRACR_FRACLE BIT(16)
+
+/* RCC_PLL1CSGR register fields */
+#define RCC_PLL1CSGR_MOD_PER_MASK GENMASK(12, 0)
+#define RCC_PLL1CSGR_MOD_PER_SHIFT 0
+#define RCC_PLL1CSGR_TPDFN_DIS BIT(13)
+#define RCC_PLL1CSGR_RPDFN_DIS BIT(14)
+#define RCC_PLL1CSGR_SSCG_MODE BIT(15)
+#define RCC_PLL1CSGR_INC_STEP_MASK GENMASK(30, 16)
+#define RCC_PLL1CSGR_INC_STEP_SHIFT 16
+
+/* RCC_PLL2CR register fields */
+#define RCC_PLL2CR_PLLON BIT(0)
+#define RCC_PLL2CR_PLL2RDY BIT(1)
+#define RCC_PLL2CR_SSCG_CTRL BIT(2)
+#define RCC_PLL2CR_DIVPEN BIT(4)
+#define RCC_PLL2CR_DIVQEN BIT(5)
+#define RCC_PLL2CR_DIVREN BIT(6)
+
+/* RCC_PLL2CFGR1 register fields */
+#define RCC_PLL2CFGR1_DIVN_MASK GENMASK(8, 0)
+#define RCC_PLL2CFGR1_DIVN_SHIFT 0
+#define RCC_PLL2CFGR1_DIVM2_MASK GENMASK(21, 16)
+#define RCC_PLL2CFGR1_DIVM2_SHIFT 16
+
+/* RCC_PLL2CFGR2 register fields */
+#define RCC_PLL2CFGR2_DIVP_MASK GENMASK(6, 0)
+#define RCC_PLL2CFGR2_DIVP_SHIFT 0
+#define RCC_PLL2CFGR2_DIVQ_MASK GENMASK(14, 8)
+#define RCC_PLL2CFGR2_DIVQ_SHIFT 8
+#define RCC_PLL2CFGR2_DIVR_MASK GENMASK(22, 16)
+#define RCC_PLL2CFGR2_DIVR_SHIFT 16
+
+/* RCC_PLL2FRACR register fields */
+#define RCC_PLL2FRACR_FRACV_MASK GENMASK(15, 3)
+#define RCC_PLL2FRACR_FRACV_SHIFT 3
+#define RCC_PLL2FRACR_FRACLE BIT(16)
+
+/* RCC_PLL2CSGR register fields */
+#define RCC_PLL2CSGR_MOD_PER_MASK GENMASK(12, 0)
+#define RCC_PLL2CSGR_MOD_PER_SHIFT 0
+#define RCC_PLL2CSGR_TPDFN_DIS BIT(13)
+#define RCC_PLL2CSGR_RPDFN_DIS BIT(14)
+#define RCC_PLL2CSGR_SSCG_MODE BIT(15)
+#define RCC_PLL2CSGR_INC_STEP_MASK GENMASK(30, 16)
+#define RCC_PLL2CSGR_INC_STEP_SHIFT 16
+
+/* RCC_PLL3CR register fields */
+#define RCC_PLL3CR_PLLON BIT(0)
+#define RCC_PLL3CR_PLL3RDY BIT(1)
+#define RCC_PLL3CR_SSCG_CTRL BIT(2)
+#define RCC_PLL3CR_DIVPEN BIT(4)
+#define RCC_PLL3CR_DIVQEN BIT(5)
+#define RCC_PLL3CR_DIVREN BIT(6)
+
+/* RCC_PLL3CFGR1 register fields */
+#define RCC_PLL3CFGR1_DIVN_MASK GENMASK(8, 0)
+#define RCC_PLL3CFGR1_DIVN_SHIFT 0
+#define RCC_PLL3CFGR1_DIVM3_MASK GENMASK(21, 16)
+#define RCC_PLL3CFGR1_DIVM3_SHIFT 16
+#define RCC_PLL3CFGR1_IFRGE_MASK GENMASK(25, 24)
+#define RCC_PLL3CFGR1_IFRGE_SHIFT 24
+
+/* RCC_PLL3CFGR2 register fields */
+#define RCC_PLL3CFGR2_DIVP_MASK GENMASK(6, 0)
+#define RCC_PLL3CFGR2_DIVP_SHIFT 0
+#define RCC_PLL3CFGR2_DIVQ_MASK GENMASK(14, 8)
+#define RCC_PLL3CFGR2_DIVQ_SHIFT 8
+#define RCC_PLL3CFGR2_DIVR_MASK GENMASK(22, 16)
+#define RCC_PLL3CFGR2_DIVR_SHIFT 16
+
+/* RCC_PLL3FRACR register fields */
+#define RCC_PLL3FRACR_FRACV_MASK GENMASK(15, 3)
+#define RCC_PLL3FRACR_FRACV_SHIFT 3
+#define RCC_PLL3FRACR_FRACLE BIT(16)
+
+/* RCC_PLL3CSGR register fields */
+#define RCC_PLL3CSGR_MOD_PER_MASK GENMASK(12, 0)
+#define RCC_PLL3CSGR_MOD_PER_SHIFT 0
+#define RCC_PLL3CSGR_TPDFN_DIS BIT(13)
+#define RCC_PLL3CSGR_RPDFN_DIS BIT(14)
+#define RCC_PLL3CSGR_SSCG_MODE BIT(15)
+#define RCC_PLL3CSGR_INC_STEP_MASK GENMASK(30, 16)
+#define RCC_PLL3CSGR_INC_STEP_SHIFT 16
+
+/* RCC_PLL4CR register fields */
+#define RCC_PLL4CR_PLLON BIT(0)
+#define RCC_PLL4CR_PLL4RDY BIT(1)
+#define RCC_PLL4CR_SSCG_CTRL BIT(2)
+#define RCC_PLL4CR_DIVPEN BIT(4)
+#define RCC_PLL4CR_DIVQEN BIT(5)
+#define RCC_PLL4CR_DIVREN BIT(6)
+
+/* RCC_PLL4CFGR1 register fields */
+#define RCC_PLL4CFGR1_DIVN_MASK GENMASK(8, 0)
+#define RCC_PLL4CFGR1_DIVN_SHIFT 0
+#define RCC_PLL4CFGR1_DIVM4_MASK GENMASK(21, 16)
+#define RCC_PLL4CFGR1_DIVM4_SHIFT 16
+#define RCC_PLL4CFGR1_IFRGE_MASK GENMASK(25, 24)
+#define RCC_PLL4CFGR1_IFRGE_SHIFT 24
+
+/* RCC_PLL4CFGR2 register fields */
+#define RCC_PLL4CFGR2_DIVP_MASK GENMASK(6, 0)
+#define RCC_PLL4CFGR2_DIVP_SHIFT 0
+#define RCC_PLL4CFGR2_DIVQ_MASK GENMASK(14, 8)
+#define RCC_PLL4CFGR2_DIVQ_SHIFT 8
+#define RCC_PLL4CFGR2_DIVR_MASK GENMASK(22, 16)
+#define RCC_PLL4CFGR2_DIVR_SHIFT 16
+
+/* RCC_PLL4FRACR register fields */
+#define RCC_PLL4FRACR_FRACV_MASK GENMASK(15, 3)
+#define RCC_PLL4FRACR_FRACV_SHIFT 3
+#define RCC_PLL4FRACR_FRACLE BIT(16)
+
+/* RCC_PLL4CSGR register fields */
+#define RCC_PLL4CSGR_MOD_PER_MASK GENMASK(12, 0)
+#define RCC_PLL4CSGR_MOD_PER_SHIFT 0
+#define RCC_PLL4CSGR_TPDFN_DIS BIT(13)
+#define RCC_PLL4CSGR_RPDFN_DIS BIT(14)
+#define RCC_PLL4CSGR_SSCG_MODE BIT(15)
+#define RCC_PLL4CSGR_INC_STEP_MASK GENMASK(30, 16)
+#define RCC_PLL4CSGR_INC_STEP_SHIFT 16
+
+/* RCC_MPCKSELR register fields */
+#define RCC_MPCKSELR_MPUSRC_MASK GENMASK(1, 0)
+#define RCC_MPCKSELR_MPUSRC_SHIFT 0
+#define RCC_MPCKSELR_MPUSRCRDY BIT(31)
+
+/* RCC_ASSCKSELR register fields */
+#define RCC_ASSCKSELR_AXISSRC_MASK GENMASK(2, 0)
+#define RCC_ASSCKSELR_AXISSRC_SHIFT 0
+#define RCC_ASSCKSELR_AXISSRCRDY BIT(31)
+
+/* RCC_MSSCKSELR register fields */
+#define RCC_MSSCKSELR_MLAHBSSRC_MASK GENMASK(1, 0)
+#define RCC_MSSCKSELR_MLAHBSSRC_SHIFT 0
+#define RCC_MSSCKSELR_MLAHBSSRCRDY BIT(31)
+
+/* RCC_CPERCKSELR register fields */
+#define RCC_CPERCKSELR_CKPERSRC_MASK GENMASK(1, 0)
+#define RCC_CPERCKSELR_CKPERSRC_SHIFT 0
+
+/* RCC_RTCDIVR register fields */
+#define RCC_RTCDIVR_RTCDIV_MASK GENMASK(5, 0)
+#define RCC_RTCDIVR_RTCDIV_SHIFT 0
+
+/* RCC_MPCKDIVR register fields */
+#define RCC_MPCKDIVR_MPUDIV_MASK GENMASK(3, 0)
+#define RCC_MPCKDIVR_MPUDIV_SHIFT 0
+#define RCC_MPCKDIVR_MPUDIVRDY BIT(31)
+
+/* RCC_AXIDIVR register fields */
+#define RCC_AXIDIVR_AXIDIV_MASK GENMASK(2, 0)
+#define RCC_AXIDIVR_AXIDIV_SHIFT 0
+#define RCC_AXIDIVR_AXIDIVRDY BIT(31)
+
+/* RCC_MLAHBDIVR register fields */
+#define RCC_MLAHBDIVR_MLAHBDIV_MASK GENMASK(3, 0)
+#define RCC_MLAHBDIVR_MLAHBDIV_SHIFT 0
+#define RCC_MLAHBDIVR_MLAHBDIVRDY BIT(31)
+
+/* RCC_APB1DIVR register fields */
+#define RCC_APB1DIVR_APB1DIV_MASK GENMASK(2, 0)
+#define RCC_APB1DIVR_APB1DIV_SHIFT 0
+#define RCC_APB1DIVR_APB1DIVRDY BIT(31)
+
+/* RCC_APB2DIVR register fields */
+#define RCC_APB2DIVR_APB2DIV_MASK GENMASK(2, 0)
+#define RCC_APB2DIVR_APB2DIV_SHIFT 0
+#define RCC_APB2DIVR_APB2DIVRDY BIT(31)
+
+/* RCC_APB3DIVR register fields */
+#define RCC_APB3DIVR_APB3DIV_MASK GENMASK(2, 0)
+#define RCC_APB3DIVR_APB3DIV_SHIFT 0
+#define RCC_APB3DIVR_APB3DIVRDY BIT(31)
+
+/* RCC_APB4DIVR register fields */
+#define RCC_APB4DIVR_APB4DIV_MASK GENMASK(2, 0)
+#define RCC_APB4DIVR_APB4DIV_SHIFT 0
+#define RCC_APB4DIVR_APB4DIVRDY BIT(31)
+
+/* RCC_APB5DIVR register fields */
+#define RCC_APB5DIVR_APB5DIV_MASK GENMASK(2, 0)
+#define RCC_APB5DIVR_APB5DIV_SHIFT 0
+#define RCC_APB5DIVR_APB5DIVRDY BIT(31)
+
+/* RCC_APB6DIVR register fields */
+#define RCC_APB6DIVR_APB6DIV_MASK GENMASK(2, 0)
+#define RCC_APB6DIVR_APB6DIV_SHIFT 0
+#define RCC_APB6DIVR_APB6DIVRDY BIT(31)
+
+/* RCC_TIMG1PRER register fields */
+#define RCC_TIMG1PRER_TIMG1PRE BIT(0)
+#define RCC_TIMG1PRER_TIMG1PRERDY BIT(31)
+
+/* RCC_TIMG2PRER register fields */
+#define RCC_TIMG2PRER_TIMG2PRE BIT(0)
+#define RCC_TIMG2PRER_TIMG2PRERDY BIT(31)
+
+/* RCC_TIMG3PRER register fields */
+#define RCC_TIMG3PRER_TIMG3PRE BIT(0)
+#define RCC_TIMG3PRER_TIMG3PRERDY BIT(31)
+
+/* RCC_DDRITFCR register fields */
+#define RCC_DDRITFCR_DDRC1EN BIT(0)
+#define RCC_DDRITFCR_DDRC1LPEN BIT(1)
+#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_KERDCG_DLY_MASK GENMASK(13, 11)
+#define RCC_DDRITFCR_KERDCG_DLY_SHIFT 11
+#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_GSKPMOD BIT(23)
+#define RCC_DDRITFCR_GSKPCTRL BIT(24)
+#define RCC_DDRITFCR_DFILP_WIDTH_MASK GENMASK(27, 25)
+#define RCC_DDRITFCR_DFILP_WIDTH_SHIFT 25
+#define RCC_DDRITFCR_GSKP_DUR_MASK GENMASK(31, 28)
+#define RCC_DDRITFCR_GSKP_DUR_SHIFT 28
+
+/* RCC_I2C12CKSELR register fields */
+#define RCC_I2C12CKSELR_I2C12SRC_MASK GENMASK(2, 0)
+#define RCC_I2C12CKSELR_I2C12SRC_SHIFT 0
+
+/* RCC_I2C345CKSELR register fields */
+#define RCC_I2C345CKSELR_I2C3SRC_MASK GENMASK(2, 0)
+#define RCC_I2C345CKSELR_I2C3SRC_SHIFT 0
+#define RCC_I2C345CKSELR_I2C4SRC_MASK GENMASK(5, 3)
+#define RCC_I2C345CKSELR_I2C4SRC_SHIFT 3
+#define RCC_I2C345CKSELR_I2C5SRC_MASK GENMASK(8, 6)
+#define RCC_I2C345CKSELR_I2C5SRC_SHIFT 6
+
+/* RCC_SPI2S1CKSELR register fields */
+#define RCC_SPI2S1CKSELR_SPI1SRC_MASK GENMASK(2, 0)
+#define RCC_SPI2S1CKSELR_SPI1SRC_SHIFT 0
+
+/* RCC_SPI2S23CKSELR register fields */
+#define RCC_SPI2S23CKSELR_SPI23SRC_MASK GENMASK(2, 0)
+#define RCC_SPI2S23CKSELR_SPI23SRC_SHIFT 0
+
+/* RCC_SPI45CKSELR register fields */
+#define RCC_SPI45CKSELR_SPI4SRC_MASK GENMASK(2, 0)
+#define RCC_SPI45CKSELR_SPI4SRC_SHIFT 0
+#define RCC_SPI45CKSELR_SPI5SRC_MASK GENMASK(5, 3)
+#define RCC_SPI45CKSELR_SPI5SRC_SHIFT 3
+
+/* RCC_UART12CKSELR register fields */
+#define RCC_UART12CKSELR_UART1SRC_MASK GENMASK(2, 0)
+#define RCC_UART12CKSELR_UART1SRC_SHIFT 0
+#define RCC_UART12CKSELR_UART2SRC_MASK GENMASK(5, 3)
+#define RCC_UART12CKSELR_UART2SRC_SHIFT 3
+
+/* RCC_UART35CKSELR register fields */
+#define RCC_UART35CKSELR_UART35SRC_MASK GENMASK(2, 0)
+#define RCC_UART35CKSELR_UART35SRC_SHIFT 0
+
+/* RCC_UART4CKSELR register fields */
+#define RCC_UART4CKSELR_UART4SRC_MASK GENMASK(2, 0)
+#define RCC_UART4CKSELR_UART4SRC_SHIFT 0
+
+/* RCC_UART6CKSELR register fields */
+#define RCC_UART6CKSELR_UART6SRC_MASK GENMASK(2, 0)
+#define RCC_UART6CKSELR_UART6SRC_SHIFT 0
+
+/* RCC_UART78CKSELR register fields */
+#define RCC_UART78CKSELR_UART78SRC_MASK GENMASK(2, 0)
+#define RCC_UART78CKSELR_UART78SRC_SHIFT 0
+
+/* RCC_LPTIM1CKSELR register fields */
+#define RCC_LPTIM1CKSELR_LPTIM1SRC_MASK GENMASK(2, 0)
+#define RCC_LPTIM1CKSELR_LPTIM1SRC_SHIFT 0
+
+/* RCC_LPTIM23CKSELR register fields */
+#define RCC_LPTIM23CKSELR_LPTIM2SRC_MASK GENMASK(2, 0)
+#define RCC_LPTIM23CKSELR_LPTIM2SRC_SHIFT 0
+#define RCC_LPTIM23CKSELR_LPTIM3SRC_MASK GENMASK(5, 3)
+#define RCC_LPTIM23CKSELR_LPTIM3SRC_SHIFT 3
+
+/* RCC_LPTIM45CKSELR register fields */
+#define RCC_LPTIM45CKSELR_LPTIM45SRC_MASK GENMASK(2, 0)
+#define RCC_LPTIM45CKSELR_LPTIM45SRC_SHIFT 0
+
+/* RCC_SAI1CKSELR register fields */
+#define RCC_SAI1CKSELR_SAI1SRC_MASK GENMASK(2, 0)
+#define RCC_SAI1CKSELR_SAI1SRC_SHIFT 0
+
+/* RCC_SAI2CKSELR register fields */
+#define RCC_SAI2CKSELR_SAI2SRC_MASK GENMASK(2, 0)
+#define RCC_SAI2CKSELR_SAI2SRC_SHIFT 0
+
+/* RCC_FDCANCKSELR register fields */
+#define RCC_FDCANCKSELR_FDCANSRC_MASK GENMASK(1, 0)
+#define RCC_FDCANCKSELR_FDCANSRC_SHIFT 0
+
+/* RCC_SPDIFCKSELR register fields */
+#define RCC_SPDIFCKSELR_SPDIFSRC_MASK GENMASK(1, 0)
+#define RCC_SPDIFCKSELR_SPDIFSRC_SHIFT 0
+
+/* RCC_ADC12CKSELR register fields */
+#define RCC_ADC12CKSELR_ADC1SRC_MASK GENMASK(1, 0)
+#define RCC_ADC12CKSELR_ADC1SRC_SHIFT 0
+#define RCC_ADC12CKSELR_ADC2SRC_MASK GENMASK(3, 2)
+#define RCC_ADC12CKSELR_ADC2SRC_SHIFT 2
+
+/* RCC_SDMMC12CKSELR register fields */
+#define RCC_SDMMC12CKSELR_SDMMC1SRC_MASK GENMASK(2, 0)
+#define RCC_SDMMC12CKSELR_SDMMC1SRC_SHIFT 0
+#define RCC_SDMMC12CKSELR_SDMMC2SRC_MASK GENMASK(5, 3)
+#define RCC_SDMMC12CKSELR_SDMMC2SRC_SHIFT 3
+
+/* RCC_ETH12CKSELR register fields */
+#define RCC_ETH12CKSELR_ETH1SRC_MASK GENMASK(1, 0)
+#define RCC_ETH12CKSELR_ETH1SRC_SHIFT 0
+#define RCC_ETH12CKSELR_ETH1PTPDIV_MASK GENMASK(7, 4)
+#define RCC_ETH12CKSELR_ETH1PTPDIV_SHIFT 4
+#define RCC_ETH12CKSELR_ETH2SRC_MASK GENMASK(9, 8)
+#define RCC_ETH12CKSELR_ETH2SRC_SHIFT 8
+#define RCC_ETH12CKSELR_ETH2PTPDIV_MASK GENMASK(15, 12)
+#define RCC_ETH12CKSELR_ETH2PTPDIV_SHIFT 12
+
+/* RCC_USBCKSELR register fields */
+#define RCC_USBCKSELR_USBPHYSRC_MASK GENMASK(1, 0)
+#define RCC_USBCKSELR_USBPHYSRC_SHIFT 0
+#define RCC_USBCKSELR_USBOSRC BIT(4)
+
+/* 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_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_DCMIPPCKSELR register fields */
+#define RCC_DCMIPPCKSELR_DCMIPPSRC_MASK GENMASK(1, 0)
+#define RCC_DCMIPPCKSELR_DCMIPPSRC_SHIFT 0
+
+/* RCC_SAESCKSELR register fields */
+#define RCC_SAESCKSELR_SAESSRC_MASK GENMASK(1, 0)
+#define RCC_SAESCKSELR_SAESSRC_SHIFT 0
+
+/* RCC_APB1RSTSETR register fields */
+#define RCC_APB1RSTSETR_TIM2RST BIT(0)
+#define RCC_APB1RSTSETR_TIM3RST BIT(1)
+#define RCC_APB1RSTSETR_TIM4RST BIT(2)
+#define RCC_APB1RSTSETR_TIM5RST BIT(3)
+#define RCC_APB1RSTSETR_TIM6RST BIT(4)
+#define RCC_APB1RSTSETR_TIM7RST BIT(5)
+#define RCC_APB1RSTSETR_LPTIM1RST BIT(9)
+#define RCC_APB1RSTSETR_SPI2RST BIT(11)
+#define RCC_APB1RSTSETR_SPI3RST BIT(12)
+#define RCC_APB1RSTSETR_USART3RST BIT(15)
+#define RCC_APB1RSTSETR_UART4RST BIT(16)
+#define RCC_APB1RSTSETR_UART5RST BIT(17)
+#define RCC_APB1RSTSETR_UART7RST BIT(18)
+#define RCC_APB1RSTSETR_UART8RST BIT(19)
+#define RCC_APB1RSTSETR_I2C1RST BIT(21)
+#define RCC_APB1RSTSETR_I2C2RST BIT(22)
+#define RCC_APB1RSTSETR_SPDIFRST BIT(26)
+
+/* RCC_APB1RSTCLRR register fields */
+#define RCC_APB1RSTCLRR_TIM2RST BIT(0)
+#define RCC_APB1RSTCLRR_TIM3RST BIT(1)
+#define RCC_APB1RSTCLRR_TIM4RST BIT(2)
+#define RCC_APB1RSTCLRR_TIM5RST BIT(3)
+#define RCC_APB1RSTCLRR_TIM6RST BIT(4)
+#define RCC_APB1RSTCLRR_TIM7RST BIT(5)
+#define RCC_APB1RSTCLRR_LPTIM1RST BIT(9)
+#define RCC_APB1RSTCLRR_SPI2RST BIT(11)
+#define RCC_APB1RSTCLRR_SPI3RST BIT(12)
+#define RCC_APB1RSTCLRR_USART3RST BIT(15)
+#define RCC_APB1RSTCLRR_UART4RST BIT(16)
+#define RCC_APB1RSTCLRR_UART5RST BIT(17)
+#define RCC_APB1RSTCLRR_UART7RST BIT(18)
+#define RCC_APB1RSTCLRR_UART8RST BIT(19)
+#define RCC_APB1RSTCLRR_I2C1RST BIT(21)
+#define RCC_APB1RSTCLRR_I2C2RST BIT(22)
+#define RCC_APB1RSTCLRR_SPDIFRST BIT(26)
+
+/* RCC_APB2RSTSETR register fields */
+#define RCC_APB2RSTSETR_TIM1RST BIT(0)
+#define RCC_APB2RSTSETR_TIM8RST BIT(1)
+#define RCC_APB2RSTSETR_SPI1RST BIT(8)
+#define RCC_APB2RSTSETR_USART6RST BIT(13)
+#define RCC_APB2RSTSETR_SAI1RST BIT(16)
+#define RCC_APB2RSTSETR_SAI2RST BIT(17)
+#define RCC_APB2RSTSETR_DFSDMRST BIT(20)
+#define RCC_APB2RSTSETR_FDCANRST BIT(24)
+
+/* RCC_APB2RSTCLRR register fields */
+#define RCC_APB2RSTCLRR_TIM1RST BIT(0)
+#define RCC_APB2RSTCLRR_TIM8RST BIT(1)
+#define RCC_APB2RSTCLRR_SPI1RST BIT(8)
+#define RCC_APB2RSTCLRR_USART6RST BIT(13)
+#define RCC_APB2RSTCLRR_SAI1RST BIT(16)
+#define RCC_APB2RSTCLRR_SAI2RST BIT(17)
+#define RCC_APB2RSTCLRR_DFSDMRST BIT(20)
+#define RCC_APB2RSTCLRR_FDCANRST BIT(24)
+
+/* RCC_APB3RSTSETR register fields */
+#define RCC_APB3RSTSETR_LPTIM2RST BIT(0)
+#define RCC_APB3RSTSETR_LPTIM3RST BIT(1)
+#define RCC_APB3RSTSETR_LPTIM4RST BIT(2)
+#define RCC_APB3RSTSETR_LPTIM5RST BIT(3)
+#define RCC_APB3RSTSETR_SYSCFGRST BIT(11)
+#define RCC_APB3RSTSETR_VREFRST BIT(13)
+#define RCC_APB3RSTSETR_DTSRST BIT(16)
+#define RCC_APB3RSTSETR_PMBCTRLRST BIT(17)
+
+/* RCC_APB3RSTCLRR register fields */
+#define RCC_APB3RSTCLRR_LPTIM2RST BIT(0)
+#define RCC_APB3RSTCLRR_LPTIM3RST BIT(1)
+#define RCC_APB3RSTCLRR_LPTIM4RST BIT(2)
+#define RCC_APB3RSTCLRR_LPTIM5RST BIT(3)
+#define RCC_APB3RSTCLRR_SYSCFGRST BIT(11)
+#define RCC_APB3RSTCLRR_VREFRST BIT(13)
+#define RCC_APB3RSTCLRR_DTSRST BIT(16)
+#define RCC_APB3RSTCLRR_PMBCTRLRST BIT(17)
+
+/* RCC_APB4RSTSETR register fields */
+#define RCC_APB4RSTSETR_LTDCRST BIT(0)
+#define RCC_APB4RSTSETR_DCMIPPRST BIT(1)
+#define RCC_APB4RSTSETR_DDRPERFMRST BIT(8)
+#define RCC_APB4RSTSETR_USBPHYRST BIT(16)
+
+/* RCC_APB4RSTCLRR register fields */
+#define RCC_APB4RSTCLRR_LTDCRST BIT(0)
+#define RCC_APB4RSTCLRR_DCMIPPRST BIT(1)
+#define RCC_APB4RSTCLRR_DDRPERFMRST BIT(8)
+#define RCC_APB4RSTCLRR_USBPHYRST BIT(16)
+
+/* RCC_APB5RSTSETR register fields */
+#define RCC_APB5RSTSETR_STGENRST BIT(20)
+
+/* RCC_APB5RSTCLRR register fields */
+#define RCC_APB5RSTCLRR_STGENRST BIT(20)
+
+/* RCC_APB6RSTSETR register fields */
+#define RCC_APB6RSTSETR_USART1RST BIT(0)
+#define RCC_APB6RSTSETR_USART2RST BIT(1)
+#define RCC_APB6RSTSETR_SPI4RST BIT(2)
+#define RCC_APB6RSTSETR_SPI5RST BIT(3)
+#define RCC_APB6RSTSETR_I2C3RST BIT(4)
+#define RCC_APB6RSTSETR_I2C4RST BIT(5)
+#define RCC_APB6RSTSETR_I2C5RST BIT(6)
+#define RCC_APB6RSTSETR_TIM12RST BIT(7)
+#define RCC_APB6RSTSETR_TIM13RST BIT(8)
+#define RCC_APB6RSTSETR_TIM14RST BIT(9)
+#define RCC_APB6RSTSETR_TIM15RST BIT(10)
+#define RCC_APB6RSTSETR_TIM16RST BIT(11)
+#define RCC_APB6RSTSETR_TIM17RST BIT(12)
+
+/* RCC_APB6RSTCLRR register fields */
+#define RCC_APB6RSTCLRR_USART1RST BIT(0)
+#define RCC_APB6RSTCLRR_USART2RST BIT(1)
+#define RCC_APB6RSTCLRR_SPI4RST BIT(2)
+#define RCC_APB6RSTCLRR_SPI5RST BIT(3)
+#define RCC_APB6RSTCLRR_I2C3RST BIT(4)
+#define RCC_APB6RSTCLRR_I2C4RST BIT(5)
+#define RCC_APB6RSTCLRR_I2C5RST BIT(6)
+#define RCC_APB6RSTCLRR_TIM12RST BIT(7)
+#define RCC_APB6RSTCLRR_TIM13RST BIT(8)
+#define RCC_APB6RSTCLRR_TIM14RST BIT(9)
+#define RCC_APB6RSTCLRR_TIM15RST BIT(10)
+#define RCC_APB6RSTCLRR_TIM16RST BIT(11)
+#define RCC_APB6RSTCLRR_TIM17RST BIT(12)
+
+/* RCC_AHB2RSTSETR register fields */
+#define RCC_AHB2RSTSETR_DMA1RST BIT(0)
+#define RCC_AHB2RSTSETR_DMA2RST BIT(1)
+#define RCC_AHB2RSTSETR_DMAMUX1RST BIT(2)
+#define RCC_AHB2RSTSETR_DMA3RST BIT(3)
+#define RCC_AHB2RSTSETR_DMAMUX2RST BIT(4)
+#define RCC_AHB2RSTSETR_ADC1RST BIT(5)
+#define RCC_AHB2RSTSETR_ADC2RST BIT(6)
+#define RCC_AHB2RSTSETR_USBORST BIT(8)
+
+/* RCC_AHB2RSTCLRR register fields */
+#define RCC_AHB2RSTCLRR_DMA1RST BIT(0)
+#define RCC_AHB2RSTCLRR_DMA2RST BIT(1)
+#define RCC_AHB2RSTCLRR_DMAMUX1RST BIT(2)
+#define RCC_AHB2RSTCLRR_DMA3RST BIT(3)
+#define RCC_AHB2RSTCLRR_DMAMUX2RST BIT(4)
+#define RCC_AHB2RSTCLRR_ADC1RST BIT(5)
+#define RCC_AHB2RSTCLRR_ADC2RST BIT(6)
+#define RCC_AHB2RSTCLRR_USBORST BIT(8)
+
+/* RCC_AHB4RSTSETR register fields */
+#define RCC_AHB4RSTSETR_GPIOARST BIT(0)
+#define RCC_AHB4RSTSETR_GPIOBRST BIT(1)
+#define RCC_AHB4RSTSETR_GPIOCRST BIT(2)
+#define RCC_AHB4RSTSETR_GPIODRST BIT(3)
+#define RCC_AHB4RSTSETR_GPIOERST BIT(4)
+#define RCC_AHB4RSTSETR_GPIOFRST BIT(5)
+#define RCC_AHB4RSTSETR_GPIOGRST BIT(6)
+#define RCC_AHB4RSTSETR_GPIOHRST BIT(7)
+#define RCC_AHB4RSTSETR_GPIOIRST BIT(8)
+#define RCC_AHB4RSTSETR_TSCRST BIT(15)
+
+/* RCC_AHB4RSTCLRR register fields */
+#define RCC_AHB4RSTCLRR_GPIOARST BIT(0)
+#define RCC_AHB4RSTCLRR_GPIOBRST BIT(1)
+#define RCC_AHB4RSTCLRR_GPIOCRST BIT(2)
+#define RCC_AHB4RSTCLRR_GPIODRST BIT(3)
+#define RCC_AHB4RSTCLRR_GPIOERST BIT(4)
+#define RCC_AHB4RSTCLRR_GPIOFRST BIT(5)
+#define RCC_AHB4RSTCLRR_GPIOGRST BIT(6)
+#define RCC_AHB4RSTCLRR_GPIOHRST BIT(7)
+#define RCC_AHB4RSTCLRR_GPIOIRST BIT(8)
+#define RCC_AHB4RSTCLRR_TSCRST BIT(15)
+
+/* RCC_AHB5RSTSETR register fields */
+#define RCC_AHB5RSTSETR_PKARST BIT(2)
+#define RCC_AHB5RSTSETR_SAESRST BIT(3)
+#define RCC_AHB5RSTSETR_CRYP1RST BIT(4)
+#define RCC_AHB5RSTSETR_HASH1RST BIT(5)
+#define RCC_AHB5RSTSETR_RNG1RST BIT(6)
+#define RCC_AHB5RSTSETR_AXIMCRST BIT(16)
+
+/* RCC_AHB5RSTCLRR register fields */
+#define RCC_AHB5RSTCLRR_PKARST BIT(2)
+#define RCC_AHB5RSTCLRR_SAESRST BIT(3)
+#define RCC_AHB5RSTCLRR_CRYP1RST BIT(4)
+#define RCC_AHB5RSTCLRR_HASH1RST BIT(5)
+#define RCC_AHB5RSTCLRR_RNG1RST BIT(6)
+#define RCC_AHB5RSTCLRR_AXIMCRST BIT(16)
+
+/* RCC_AHB6RSTSETR register fields */
+#define RCC_AHB6RSTSETR_MDMARST BIT(0)
+#define RCC_AHB6RSTSETR_MCERST BIT(1)
+#define RCC_AHB6RSTSETR_ETH1MACRST BIT(10)
+#define RCC_AHB6RSTSETR_FMCRST BIT(12)
+#define RCC_AHB6RSTSETR_QSPIRST BIT(14)
+#define RCC_AHB6RSTSETR_SDMMC1RST BIT(16)
+#define RCC_AHB6RSTSETR_SDMMC2RST BIT(17)
+#define RCC_AHB6RSTSETR_CRC1RST BIT(20)
+#define RCC_AHB6RSTSETR_USBHRST BIT(24)
+#define RCC_AHB6RSTSETR_ETH2MACRST BIT(30)
+
+/* RCC_AHB6RSTCLRR register fields */
+#define RCC_AHB6RSTCLRR_MDMARST BIT(0)
+#define RCC_AHB6RSTCLRR_MCERST BIT(1)
+#define RCC_AHB6RSTCLRR_ETH1MACRST BIT(10)
+#define RCC_AHB6RSTCLRR_FMCRST BIT(12)
+#define RCC_AHB6RSTCLRR_QSPIRST BIT(14)
+#define RCC_AHB6RSTCLRR_SDMMC1RST BIT(16)
+#define RCC_AHB6RSTCLRR_SDMMC2RST BIT(17)
+#define RCC_AHB6RSTCLRR_CRC1RST BIT(20)
+#define RCC_AHB6RSTCLRR_USBHRST BIT(24)
+#define RCC_AHB6RSTCLRR_ETH2MACRST BIT(30)
+
+/* RCC_MP_APB1ENSETR register fields */
+#define RCC_MP_APB1ENSETR_TIM2EN BIT(0)
+#define RCC_MP_APB1ENSETR_TIM3EN BIT(1)
+#define RCC_MP_APB1ENSETR_TIM4EN BIT(2)
+#define RCC_MP_APB1ENSETR_TIM5EN BIT(3)
+#define RCC_MP_APB1ENSETR_TIM6EN BIT(4)
+#define RCC_MP_APB1ENSETR_TIM7EN BIT(5)
+#define RCC_MP_APB1ENSETR_LPTIM1EN BIT(9)
+#define RCC_MP_APB1ENSETR_SPI2EN BIT(11)
+#define RCC_MP_APB1ENSETR_SPI3EN BIT(12)
+#define RCC_MP_APB1ENSETR_USART3EN BIT(15)
+#define RCC_MP_APB1ENSETR_UART4EN BIT(16)
+#define RCC_MP_APB1ENSETR_UART5EN BIT(17)
+#define RCC_MP_APB1ENSETR_UART7EN BIT(18)
+#define RCC_MP_APB1ENSETR_UART8EN BIT(19)
+#define RCC_MP_APB1ENSETR_I2C1EN BIT(21)
+#define RCC_MP_APB1ENSETR_I2C2EN BIT(22)
+#define RCC_MP_APB1ENSETR_SPDIFEN BIT(26)
+
+/* RCC_MP_APB1ENCLRR register fields */
+#define RCC_MP_APB1ENCLRR_TIM2EN BIT(0)
+#define RCC_MP_APB1ENCLRR_TIM3EN BIT(1)
+#define RCC_MP_APB1ENCLRR_TIM4EN BIT(2)
+#define RCC_MP_APB1ENCLRR_TIM5EN BIT(3)
+#define RCC_MP_APB1ENCLRR_TIM6EN BIT(4)
+#define RCC_MP_APB1ENCLRR_TIM7EN BIT(5)
+#define RCC_MP_APB1ENCLRR_LPTIM1EN BIT(9)
+#define RCC_MP_APB1ENCLRR_SPI2EN BIT(11)
+#define RCC_MP_APB1ENCLRR_SPI3EN BIT(12)
+#define RCC_MP_APB1ENCLRR_USART3EN BIT(15)
+#define RCC_MP_APB1ENCLRR_UART4EN BIT(16)
+#define RCC_MP_APB1ENCLRR_UART5EN BIT(17)
+#define RCC_MP_APB1ENCLRR_UART7EN BIT(18)
+#define RCC_MP_APB1ENCLRR_UART8EN BIT(19)
+#define RCC_MP_APB1ENCLRR_I2C1EN BIT(21)
+#define RCC_MP_APB1ENCLRR_I2C2EN BIT(22)
+#define RCC_MP_APB1ENCLRR_SPDIFEN BIT(26)
+
+/* RCC_MP_APB2ENSETR register fields */
+#define RCC_MP_APB2ENSETR_TIM1EN BIT(0)
+#define RCC_MP_APB2ENSETR_TIM8EN BIT(1)
+#define RCC_MP_APB2ENSETR_SPI1EN BIT(8)
+#define RCC_MP_APB2ENSETR_USART6EN BIT(13)
+#define RCC_MP_APB2ENSETR_SAI1EN BIT(16)
+#define RCC_MP_APB2ENSETR_SAI2EN BIT(17)
+#define RCC_MP_APB2ENSETR_DFSDMEN BIT(20)
+#define RCC_MP_APB2ENSETR_ADFSDMEN BIT(21)
+#define RCC_MP_APB2ENSETR_FDCANEN BIT(24)
+
+/* RCC_MP_APB2ENCLRR register fields */
+#define RCC_MP_APB2ENCLRR_TIM1EN BIT(0)
+#define RCC_MP_APB2ENCLRR_TIM8EN BIT(1)
+#define RCC_MP_APB2ENCLRR_SPI1EN BIT(8)
+#define RCC_MP_APB2ENCLRR_USART6EN BIT(13)
+#define RCC_MP_APB2ENCLRR_SAI1EN BIT(16)
+#define RCC_MP_APB2ENCLRR_SAI2EN BIT(17)
+#define RCC_MP_APB2ENCLRR_DFSDMEN BIT(20)
+#define RCC_MP_APB2ENCLRR_ADFSDMEN BIT(21)
+#define RCC_MP_APB2ENCLRR_FDCANEN BIT(24)
+
+/* RCC_MP_APB3ENSETR register fields */
+#define RCC_MP_APB3ENSETR_LPTIM2EN BIT(0)
+#define RCC_MP_APB3ENSETR_LPTIM3EN BIT(1)
+#define RCC_MP_APB3ENSETR_LPTIM4EN BIT(2)
+#define RCC_MP_APB3ENSETR_LPTIM5EN BIT(3)
+#define RCC_MP_APB3ENSETR_VREFEN BIT(13)
+#define RCC_MP_APB3ENSETR_DTSEN BIT(16)
+#define RCC_MP_APB3ENSETR_PMBCTRLEN BIT(17)
+#define RCC_MP_APB3ENSETR_HDPEN BIT(20)
+
+/* RCC_MP_APB3ENCLRR register fields */
+#define RCC_MP_APB3ENCLRR_LPTIM2EN BIT(0)
+#define RCC_MP_APB3ENCLRR_LPTIM3EN BIT(1)
+#define RCC_MP_APB3ENCLRR_LPTIM4EN BIT(2)
+#define RCC_MP_APB3ENCLRR_LPTIM5EN BIT(3)
+#define RCC_MP_APB3ENCLRR_VREFEN BIT(13)
+#define RCC_MP_APB3ENCLRR_DTSEN BIT(16)
+#define RCC_MP_APB3ENCLRR_PMBCTRLEN BIT(17)
+#define RCC_MP_APB3ENCLRR_HDPEN BIT(20)
+
+/* RCC_MP_S_APB3ENSETR register fields */
+#define RCC_MP_S_APB3ENSETR_SYSCFGEN BIT(0)
+
+/* RCC_MP_S_APB3ENCLRR register fields */
+#define RCC_MP_S_APB3ENCLRR_SYSCFGEN BIT(0)
+
+/* RCC_MP_NS_APB3ENSETR register fields */
+#define RCC_MP_NS_APB3ENSETR_SYSCFGEN BIT(0)
+
+/* RCC_MP_NS_APB3ENCLRR register fields */
+#define RCC_MP_NS_APB3ENCLRR_SYSCFGEN BIT(0)
+
+/* RCC_MP_APB4ENSETR register fields */
+#define RCC_MP_APB4ENSETR_DCMIPPEN BIT(1)
+#define RCC_MP_APB4ENSETR_DDRPERFMEN BIT(8)
+#define RCC_MP_APB4ENSETR_IWDG2APBEN BIT(15)
+#define RCC_MP_APB4ENSETR_USBPHYEN BIT(16)
+#define RCC_MP_APB4ENSETR_STGENROEN BIT(20)
+
+/* RCC_MP_APB4ENCLRR register fields */
+#define RCC_MP_APB4ENCLRR_DCMIPPEN BIT(1)
+#define RCC_MP_APB4ENCLRR_DDRPERFMEN BIT(8)
+#define RCC_MP_APB4ENCLRR_IWDG2APBEN BIT(15)
+#define RCC_MP_APB4ENCLRR_USBPHYEN BIT(16)
+#define RCC_MP_APB4ENCLRR_STGENROEN BIT(20)
+
+/* RCC_MP_S_APB4ENSETR register fields */
+#define RCC_MP_S_APB4ENSETR_LTDCEN BIT(0)
+
+/* RCC_MP_S_APB4ENCLRR register fields */
+#define RCC_MP_S_APB4ENCLRR_LTDCEN BIT(0)
+
+/* RCC_MP_NS_APB4ENSETR register fields */
+#define RCC_MP_NS_APB4ENSETR_LTDCEN BIT(0)
+
+/* RCC_MP_NS_APB4ENCLRR register fields */
+#define RCC_MP_NS_APB4ENCLRR_LTDCEN BIT(0)
+
+/* RCC_MP_APB5ENSETR register fields */
+#define RCC_MP_APB5ENSETR_RTCAPBEN BIT(8)
+#define RCC_MP_APB5ENSETR_TZCEN BIT(11)
+#define RCC_MP_APB5ENSETR_ETZPCEN BIT(13)
+#define RCC_MP_APB5ENSETR_IWDG1APBEN BIT(15)
+#define RCC_MP_APB5ENSETR_BSECEN BIT(16)
+#define RCC_MP_APB5ENSETR_STGENCEN BIT(20)
+
+/* RCC_MP_APB5ENCLRR register fields */
+#define RCC_MP_APB5ENCLRR_RTCAPBEN BIT(8)
+#define RCC_MP_APB5ENCLRR_TZCEN BIT(11)
+#define RCC_MP_APB5ENCLRR_ETZPCEN BIT(13)
+#define RCC_MP_APB5ENCLRR_IWDG1APBEN BIT(15)
+#define RCC_MP_APB5ENCLRR_BSECEN BIT(16)
+#define RCC_MP_APB5ENCLRR_STGENCEN BIT(20)
+
+/* RCC_MP_APB6ENSETR register fields */
+#define RCC_MP_APB6ENSETR_USART1EN BIT(0)
+#define RCC_MP_APB6ENSETR_USART2EN BIT(1)
+#define RCC_MP_APB6ENSETR_SPI4EN BIT(2)
+#define RCC_MP_APB6ENSETR_SPI5EN BIT(3)
+#define RCC_MP_APB6ENSETR_I2C3EN BIT(4)
+#define RCC_MP_APB6ENSETR_I2C4EN BIT(5)
+#define RCC_MP_APB6ENSETR_I2C5EN BIT(6)
+#define RCC_MP_APB6ENSETR_TIM12EN BIT(7)
+#define RCC_MP_APB6ENSETR_TIM13EN BIT(8)
+#define RCC_MP_APB6ENSETR_TIM14EN BIT(9)
+#define RCC_MP_APB6ENSETR_TIM15EN BIT(10)
+#define RCC_MP_APB6ENSETR_TIM16EN BIT(11)
+#define RCC_MP_APB6ENSETR_TIM17EN BIT(12)
+
+/* RCC_MP_APB6ENCLRR register fields */
+#define RCC_MP_APB6ENCLRR_USART1EN BIT(0)
+#define RCC_MP_APB6ENCLRR_USART2EN BIT(1)
+#define RCC_MP_APB6ENCLRR_SPI4EN BIT(2)
+#define RCC_MP_APB6ENCLRR_SPI5EN BIT(3)
+#define RCC_MP_APB6ENCLRR_I2C3EN BIT(4)
+#define RCC_MP_APB6ENCLRR_I2C4EN BIT(5)
+#define RCC_MP_APB6ENCLRR_I2C5EN BIT(6)
+#define RCC_MP_APB6ENCLRR_TIM12EN BIT(7)
+#define RCC_MP_APB6ENCLRR_TIM13EN BIT(8)
+#define RCC_MP_APB6ENCLRR_TIM14EN BIT(9)
+#define RCC_MP_APB6ENCLRR_TIM15EN BIT(10)
+#define RCC_MP_APB6ENCLRR_TIM16EN BIT(11)
+#define RCC_MP_APB6ENCLRR_TIM17EN BIT(12)
+
+/* RCC_MP_AHB2ENSETR register fields */
+#define RCC_MP_AHB2ENSETR_DMA1EN BIT(0)
+#define RCC_MP_AHB2ENSETR_DMA2EN BIT(1)
+#define RCC_MP_AHB2ENSETR_DMAMUX1EN BIT(2)
+#define RCC_MP_AHB2ENSETR_DMA3EN BIT(3)
+#define RCC_MP_AHB2ENSETR_DMAMUX2EN BIT(4)
+#define RCC_MP_AHB2ENSETR_ADC1EN BIT(5)
+#define RCC_MP_AHB2ENSETR_ADC2EN BIT(6)
+#define RCC_MP_AHB2ENSETR_USBOEN BIT(8)
+
+/* RCC_MP_AHB2ENCLRR register fields */
+#define RCC_MP_AHB2ENCLRR_DMA1EN BIT(0)
+#define RCC_MP_AHB2ENCLRR_DMA2EN BIT(1)
+#define RCC_MP_AHB2ENCLRR_DMAMUX1EN BIT(2)
+#define RCC_MP_AHB2ENCLRR_DMA3EN BIT(3)
+#define RCC_MP_AHB2ENCLRR_DMAMUX2EN BIT(4)
+#define RCC_MP_AHB2ENCLRR_ADC1EN BIT(5)
+#define RCC_MP_AHB2ENCLRR_ADC2EN BIT(6)
+#define RCC_MP_AHB2ENCLRR_USBOEN BIT(8)
+
+/* RCC_MP_AHB4ENSETR register fields */
+#define RCC_MP_AHB4ENSETR_TSCEN BIT(15)
+
+/* RCC_MP_AHB4ENCLRR register fields */
+#define RCC_MP_AHB4ENCLRR_TSCEN BIT(15)
+
+/* RCC_MP_S_AHB4ENSETR register fields */
+#define RCC_MP_S_AHB4ENSETR_GPIOAEN BIT(0)
+#define RCC_MP_S_AHB4ENSETR_GPIOBEN BIT(1)
+#define RCC_MP_S_AHB4ENSETR_GPIOCEN BIT(2)
+#define RCC_MP_S_AHB4ENSETR_GPIODEN BIT(3)
+#define RCC_MP_S_AHB4ENSETR_GPIOEEN BIT(4)
+#define RCC_MP_S_AHB4ENSETR_GPIOFEN BIT(5)
+#define RCC_MP_S_AHB4ENSETR_GPIOGEN BIT(6)
+#define RCC_MP_S_AHB4ENSETR_GPIOHEN BIT(7)
+#define RCC_MP_S_AHB4ENSETR_GPIOIEN BIT(8)
+
+/* RCC_MP_S_AHB4ENCLRR register fields */
+#define RCC_MP_S_AHB4ENCLRR_GPIOAEN BIT(0)
+#define RCC_MP_S_AHB4ENCLRR_GPIOBEN BIT(1)
+#define RCC_MP_S_AHB4ENCLRR_GPIOCEN BIT(2)
+#define RCC_MP_S_AHB4ENCLRR_GPIODEN BIT(3)
+#define RCC_MP_S_AHB4ENCLRR_GPIOEEN BIT(4)
+#define RCC_MP_S_AHB4ENCLRR_GPIOFEN BIT(5)
+#define RCC_MP_S_AHB4ENCLRR_GPIOGEN BIT(6)
+#define RCC_MP_S_AHB4ENCLRR_GPIOHEN BIT(7)
+#define RCC_MP_S_AHB4ENCLRR_GPIOIEN BIT(8)
+
+/* RCC_MP_NS_AHB4ENSETR register fields */
+#define RCC_MP_NS_AHB4ENSETR_GPIOAEN BIT(0)
+#define RCC_MP_NS_AHB4ENSETR_GPIOBEN BIT(1)
+#define RCC_MP_NS_AHB4ENSETR_GPIOCEN BIT(2)
+#define RCC_MP_NS_AHB4ENSETR_GPIODEN BIT(3)
+#define RCC_MP_NS_AHB4ENSETR_GPIOEEN BIT(4)
+#define RCC_MP_NS_AHB4ENSETR_GPIOFEN BIT(5)
+#define RCC_MP_NS_AHB4ENSETR_GPIOGEN BIT(6)
+#define RCC_MP_NS_AHB4ENSETR_GPIOHEN BIT(7)
+#define RCC_MP_NS_AHB4ENSETR_GPIOIEN BIT(8)
+
+/* RCC_MP_NS_AHB4ENCLRR register fields */
+#define RCC_MP_NS_AHB4ENCLRR_GPIOAEN BIT(0)
+#define RCC_MP_NS_AHB4ENCLRR_GPIOBEN BIT(1)
+#define RCC_MP_NS_AHB4ENCLRR_GPIOCEN BIT(2)
+#define RCC_MP_NS_AHB4ENCLRR_GPIODEN BIT(3)
+#define RCC_MP_NS_AHB4ENCLRR_GPIOEEN BIT(4)
+#define RCC_MP_NS_AHB4ENCLRR_GPIOFEN BIT(5)
+#define RCC_MP_NS_AHB4ENCLRR_GPIOGEN BIT(6)
+#define RCC_MP_NS_AHB4ENCLRR_GPIOHEN BIT(7)
+#define RCC_MP_NS_AHB4ENCLRR_GPIOIEN BIT(8)
+
+/* RCC_MP_AHB5ENSETR register fields */
+#define RCC_MP_AHB5ENSETR_PKAEN BIT(2)
+#define RCC_MP_AHB5ENSETR_SAESEN BIT(3)
+#define RCC_MP_AHB5ENSETR_CRYP1EN BIT(4)
+#define RCC_MP_AHB5ENSETR_HASH1EN BIT(5)
+#define RCC_MP_AHB5ENSETR_RNG1EN BIT(6)
+#define RCC_MP_AHB5ENSETR_BKPSRAMEN BIT(8)
+#define RCC_MP_AHB5ENSETR_AXIMCEN BIT(16)
+
+/* RCC_MP_AHB5ENCLRR register fields */
+#define RCC_MP_AHB5ENCLRR_PKAEN BIT(2)
+#define RCC_MP_AHB5ENCLRR_SAESEN BIT(3)
+#define RCC_MP_AHB5ENCLRR_CRYP1EN BIT(4)
+#define RCC_MP_AHB5ENCLRR_HASH1EN BIT(5)
+#define RCC_MP_AHB5ENCLRR_RNG1EN BIT(6)
+#define RCC_MP_AHB5ENCLRR_BKPSRAMEN BIT(8)
+#define RCC_MP_AHB5ENCLRR_AXIMCEN BIT(16)
+
+/* RCC_MP_AHB6ENSETR register fields */
+#define RCC_MP_AHB6ENSETR_MCEEN BIT(1)
+#define RCC_MP_AHB6ENSETR_ETH1CKEN BIT(7)
+#define RCC_MP_AHB6ENSETR_ETH1TXEN BIT(8)
+#define RCC_MP_AHB6ENSETR_ETH1RXEN BIT(9)
+#define RCC_MP_AHB6ENSETR_ETH1MACEN BIT(10)
+#define RCC_MP_AHB6ENSETR_FMCEN BIT(12)
+#define RCC_MP_AHB6ENSETR_QSPIEN BIT(14)
+#define RCC_MP_AHB6ENSETR_SDMMC1EN BIT(16)
+#define RCC_MP_AHB6ENSETR_SDMMC2EN BIT(17)
+#define RCC_MP_AHB6ENSETR_CRC1EN BIT(20)
+#define RCC_MP_AHB6ENSETR_USBHEN BIT(24)
+#define RCC_MP_AHB6ENSETR_ETH2CKEN BIT(27)
+#define RCC_MP_AHB6ENSETR_ETH2TXEN BIT(28)
+#define RCC_MP_AHB6ENSETR_ETH2RXEN BIT(29)
+#define RCC_MP_AHB6ENSETR_ETH2MACEN BIT(30)
+
+/* RCC_MP_AHB6ENCLRR register fields */
+#define RCC_MP_AHB6ENCLRR_MCEEN BIT(1)
+#define RCC_MP_AHB6ENCLRR_ETH1CKEN BIT(7)
+#define RCC_MP_AHB6ENCLRR_ETH1TXEN BIT(8)
+#define RCC_MP_AHB6ENCLRR_ETH1RXEN BIT(9)
+#define RCC_MP_AHB6ENCLRR_ETH1MACEN BIT(10)
+#define RCC_MP_AHB6ENCLRR_FMCEN BIT(12)
+#define RCC_MP_AHB6ENCLRR_QSPIEN BIT(14)
+#define RCC_MP_AHB6ENCLRR_SDMMC1EN BIT(16)
+#define RCC_MP_AHB6ENCLRR_SDMMC2EN BIT(17)
+#define RCC_MP_AHB6ENCLRR_CRC1EN BIT(20)
+#define RCC_MP_AHB6ENCLRR_USBHEN BIT(24)
+#define RCC_MP_AHB6ENCLRR_ETH2CKEN BIT(27)
+#define RCC_MP_AHB6ENCLRR_ETH2TXEN BIT(28)
+#define RCC_MP_AHB6ENCLRR_ETH2RXEN BIT(29)
+#define RCC_MP_AHB6ENCLRR_ETH2MACEN BIT(30)
+
+/* RCC_MP_S_AHB6ENSETR register fields */
+#define RCC_MP_S_AHB6ENSETR_MDMAEN BIT(0)
+
+/* RCC_MP_S_AHB6ENCLRR register fields */
+#define RCC_MP_S_AHB6ENCLRR_MDMAEN BIT(0)
+
+/* RCC_MP_NS_AHB6ENSETR register fields */
+#define RCC_MP_NS_AHB6ENSETR_MDMAEN BIT(0)
+
+/* RCC_MP_NS_AHB6ENCLRR register fields */
+#define RCC_MP_NS_AHB6ENCLRR_MDMAEN BIT(0)
+
+/* RCC_MP_APB1LPENSETR register fields */
+#define RCC_MP_APB1LPENSETR_TIM2LPEN BIT(0)
+#define RCC_MP_APB1LPENSETR_TIM3LPEN BIT(1)
+#define RCC_MP_APB1LPENSETR_TIM4LPEN BIT(2)
+#define RCC_MP_APB1LPENSETR_TIM5LPEN BIT(3)
+#define RCC_MP_APB1LPENSETR_TIM6LPEN BIT(4)
+#define RCC_MP_APB1LPENSETR_TIM7LPEN BIT(5)
+#define RCC_MP_APB1LPENSETR_LPTIM1LPEN BIT(9)
+#define RCC_MP_APB1LPENSETR_SPI2LPEN BIT(11)
+#define RCC_MP_APB1LPENSETR_SPI3LPEN BIT(12)
+#define RCC_MP_APB1LPENSETR_USART3LPEN BIT(15)
+#define RCC_MP_APB1LPENSETR_UART4LPEN BIT(16)
+#define RCC_MP_APB1LPENSETR_UART5LPEN BIT(17)
+#define RCC_MP_APB1LPENSETR_UART7LPEN BIT(18)
+#define RCC_MP_APB1LPENSETR_UART8LPEN BIT(19)
+#define RCC_MP_APB1LPENSETR_I2C1LPEN BIT(21)
+#define RCC_MP_APB1LPENSETR_I2C2LPEN BIT(22)
+#define RCC_MP_APB1LPENSETR_SPDIFLPEN BIT(26)
+
+/* RCC_MP_APB1LPENCLRR register fields */
+#define RCC_MP_APB1LPENCLRR_TIM2LPEN BIT(0)
+#define RCC_MP_APB1LPENCLRR_TIM3LPEN BIT(1)
+#define RCC_MP_APB1LPENCLRR_TIM4LPEN BIT(2)
+#define RCC_MP_APB1LPENCLRR_TIM5LPEN BIT(3)
+#define RCC_MP_APB1LPENCLRR_TIM6LPEN BIT(4)
+#define RCC_MP_APB1LPENCLRR_TIM7LPEN BIT(5)
+#define RCC_MP_APB1LPENCLRR_LPTIM1LPEN BIT(9)
+#define RCC_MP_APB1LPENCLRR_SPI2LPEN BIT(11)
+#define RCC_MP_APB1LPENCLRR_SPI3LPEN BIT(12)
+#define RCC_MP_APB1LPENCLRR_USART3LPEN BIT(15)
+#define RCC_MP_APB1LPENCLRR_UART4LPEN BIT(16)
+#define RCC_MP_APB1LPENCLRR_UART5LPEN BIT(17)
+#define RCC_MP_APB1LPENCLRR_UART7LPEN BIT(18)
+#define RCC_MP_APB1LPENCLRR_UART8LPEN BIT(19)
+#define RCC_MP_APB1LPENCLRR_I2C1LPEN BIT(21)
+#define RCC_MP_APB1LPENCLRR_I2C2LPEN BIT(22)
+#define RCC_MP_APB1LPENCLRR_SPDIFLPEN BIT(26)
+
+/* RCC_MP_APB2LPENSETR register fields */
+#define RCC_MP_APB2LPENSETR_TIM1LPEN BIT(0)
+#define RCC_MP_APB2LPENSETR_TIM8LPEN BIT(1)
+#define RCC_MP_APB2LPENSETR_SPI1LPEN BIT(8)
+#define RCC_MP_APB2LPENSETR_USART6LPEN BIT(13)
+#define RCC_MP_APB2LPENSETR_SAI1LPEN BIT(16)
+#define RCC_MP_APB2LPENSETR_SAI2LPEN BIT(17)
+#define RCC_MP_APB2LPENSETR_DFSDMLPEN BIT(20)
+#define RCC_MP_APB2LPENSETR_ADFSDMLPEN BIT(21)
+#define RCC_MP_APB2LPENSETR_FDCANLPEN BIT(24)
+
+/* RCC_MP_APB2LPENCLRR register fields */
+#define RCC_MP_APB2LPENCLRR_TIM1LPEN BIT(0)
+#define RCC_MP_APB2LPENCLRR_TIM8LPEN BIT(1)
+#define RCC_MP_APB2LPENCLRR_SPI1LPEN BIT(8)
+#define RCC_MP_APB2LPENCLRR_USART6LPEN BIT(13)
+#define RCC_MP_APB2LPENCLRR_SAI1LPEN BIT(16)
+#define RCC_MP_APB2LPENCLRR_SAI2LPEN BIT(17)
+#define RCC_MP_APB2LPENCLRR_DFSDMLPEN BIT(20)
+#define RCC_MP_APB2LPENCLRR_ADFSDMLPEN BIT(21)
+#define RCC_MP_APB2LPENCLRR_FDCANLPEN BIT(24)
+
+/* RCC_MP_APB3LPENSETR register fields */
+#define RCC_MP_APB3LPENSETR_LPTIM2LPEN BIT(0)
+#define RCC_MP_APB3LPENSETR_LPTIM3LPEN BIT(1)
+#define RCC_MP_APB3LPENSETR_LPTIM4LPEN BIT(2)
+#define RCC_MP_APB3LPENSETR_LPTIM5LPEN BIT(3)
+#define RCC_MP_APB3LPENSETR_VREFLPEN BIT(13)
+#define RCC_MP_APB3LPENSETR_DTSLPEN BIT(16)
+#define RCC_MP_APB3LPENSETR_PMBCTRLLPEN BIT(17)
+
+/* RCC_MP_APB3LPENCLRR register fields */
+#define RCC_MP_APB3LPENCLRR_LPTIM2LPEN BIT(0)
+#define RCC_MP_APB3LPENCLRR_LPTIM3LPEN BIT(1)
+#define RCC_MP_APB3LPENCLRR_LPTIM4LPEN BIT(2)
+#define RCC_MP_APB3LPENCLRR_LPTIM5LPEN BIT(3)
+#define RCC_MP_APB3LPENCLRR_VREFLPEN BIT(13)
+#define RCC_MP_APB3LPENCLRR_DTSLPEN BIT(16)
+#define RCC_MP_APB3LPENCLRR_PMBCTRLLPEN BIT(17)
+
+/* RCC_MP_S_APB3LPENSETR register fields */
+#define RCC_MP_S_APB3LPENSETR_SYSCFGLPEN BIT(0)
+
+/* RCC_MP_S_APB3LPENCLRR register fields */
+#define RCC_MP_S_APB3LPENCLRR_SYSCFGLPEN BIT(0)
+
+/* RCC_MP_NS_APB3LPENSETR register fields */
+#define RCC_MP_NS_APB3LPENSETR_SYSCFGLPEN BIT(0)
+
+/* RCC_MP_NS_APB3LPENCLRR register fields */
+#define RCC_MP_NS_APB3LPENCLRR_SYSCFGLPEN BIT(0)
+
+/* RCC_MP_APB4LPENSETR register fields */
+#define RCC_MP_APB4LPENSETR_DCMIPPLPEN BIT(1)
+#define RCC_MP_APB4LPENSETR_DDRPERFMLPEN BIT(8)
+#define RCC_MP_APB4LPENSETR_IWDG2APBLPEN BIT(15)
+#define RCC_MP_APB4LPENSETR_USBPHYLPEN BIT(16)
+#define RCC_MP_APB4LPENSETR_STGENROLPEN BIT(20)
+#define RCC_MP_APB4LPENSETR_STGENROSTPEN BIT(21)
+
+/* RCC_MP_APB4LPENCLRR register fields */
+#define RCC_MP_APB4LPENCLRR_DCMIPPLPEN BIT(1)
+#define RCC_MP_APB4LPENCLRR_DDRPERFMLPEN BIT(8)
+#define RCC_MP_APB4LPENCLRR_IWDG2APBLPEN BIT(15)
+#define RCC_MP_APB4LPENCLRR_USBPHYLPEN BIT(16)
+#define RCC_MP_APB4LPENCLRR_STGENROLPEN BIT(20)
+#define RCC_MP_APB4LPENCLRR_STGENROSTPEN BIT(21)
+
+/* RCC_MP_S_APB4LPENSETR register fields */
+#define RCC_MP_S_APB4LPENSETR_LTDCLPEN BIT(0)
+
+/* RCC_MP_S_APB4LPENCLRR register fields */
+#define RCC_MP_S_APB4LPENCLRR_LTDCLPEN BIT(0)
+
+/* RCC_MP_NS_APB4LPENSETR register fields */
+#define RCC_MP_NS_APB4LPENSETR_LTDCLPEN BIT(0)
+
+/* RCC_MP_NS_APB4LPENCLRR register fields */
+#define RCC_MP_NS_APB4LPENCLRR_LTDCLPEN BIT(0)
+
+/* RCC_MP_APB5LPENSETR register fields */
+#define RCC_MP_APB5LPENSETR_RTCAPBLPEN BIT(8)
+#define RCC_MP_APB5LPENSETR_TZCLPEN BIT(11)
+#define RCC_MP_APB5LPENSETR_ETZPCLPEN BIT(13)
+#define RCC_MP_APB5LPENSETR_IWDG1APBLPEN BIT(15)
+#define RCC_MP_APB5LPENSETR_BSECLPEN BIT(16)
+#define RCC_MP_APB5LPENSETR_STGENCLPEN BIT(20)
+#define RCC_MP_APB5LPENSETR_STGENCSTPEN BIT(21)
+
+/* RCC_MP_APB5LPENCLRR register fields */
+#define RCC_MP_APB5LPENCLRR_RTCAPBLPEN BIT(8)
+#define RCC_MP_APB5LPENCLRR_TZCLPEN BIT(11)
+#define RCC_MP_APB5LPENCLRR_ETZPCLPEN BIT(13)
+#define RCC_MP_APB5LPENCLRR_IWDG1APBLPEN BIT(15)
+#define RCC_MP_APB5LPENCLRR_BSECLPEN BIT(16)
+#define RCC_MP_APB5LPENCLRR_STGENCLPEN BIT(20)
+#define RCC_MP_APB5LPENCLRR_STGENCSTPEN BIT(21)
+
+/* RCC_MP_APB6LPENSETR register fields */
+#define RCC_MP_APB6LPENSETR_USART1LPEN BIT(0)
+#define RCC_MP_APB6LPENSETR_USART2LPEN BIT(1)
+#define RCC_MP_APB6LPENSETR_SPI4LPEN BIT(2)
+#define RCC_MP_APB6LPENSETR_SPI5LPEN BIT(3)
+#define RCC_MP_APB6LPENSETR_I2C3LPEN BIT(4)
+#define RCC_MP_APB6LPENSETR_I2C4LPEN BIT(5)
+#define RCC_MP_APB6LPENSETR_I2C5LPEN BIT(6)
+#define RCC_MP_APB6LPENSETR_TIM12LPEN BIT(7)
+#define RCC_MP_APB6LPENSETR_TIM13LPEN BIT(8)
+#define RCC_MP_APB6LPENSETR_TIM14LPEN BIT(9)
+#define RCC_MP_APB6LPENSETR_TIM15LPEN BIT(10)
+#define RCC_MP_APB6LPENSETR_TIM16LPEN BIT(11)
+#define RCC_MP_APB6LPENSETR_TIM17LPEN BIT(12)
+
+/* RCC_MP_APB6LPENCLRR register fields */
+#define RCC_MP_APB6LPENCLRR_USART1LPEN BIT(0)
+#define RCC_MP_APB6LPENCLRR_USART2LPEN BIT(1)
+#define RCC_MP_APB6LPENCLRR_SPI4LPEN BIT(2)
+#define RCC_MP_APB6LPENCLRR_SPI5LPEN BIT(3)
+#define RCC_MP_APB6LPENCLRR_I2C3LPEN BIT(4)
+#define RCC_MP_APB6LPENCLRR_I2C4LPEN BIT(5)
+#define RCC_MP_APB6LPENCLRR_I2C5LPEN BIT(6)
+#define RCC_MP_APB6LPENCLRR_TIM12LPEN BIT(7)
+#define RCC_MP_APB6LPENCLRR_TIM13LPEN BIT(8)
+#define RCC_MP_APB6LPENCLRR_TIM14LPEN BIT(9)
+#define RCC_MP_APB6LPENCLRR_TIM15LPEN BIT(10)
+#define RCC_MP_APB6LPENCLRR_TIM16LPEN BIT(11)
+#define RCC_MP_APB6LPENCLRR_TIM17LPEN BIT(12)
+
+/* RCC_MP_AHB2LPENSETR register fields */
+#define RCC_MP_AHB2LPENSETR_DMA1LPEN BIT(0)
+#define RCC_MP_AHB2LPENSETR_DMA2LPEN BIT(1)
+#define RCC_MP_AHB2LPENSETR_DMAMUX1LPEN BIT(2)
+#define RCC_MP_AHB2LPENSETR_DMA3LPEN BIT(3)
+#define RCC_MP_AHB2LPENSETR_DMAMUX2LPEN BIT(4)
+#define RCC_MP_AHB2LPENSETR_ADC1LPEN BIT(5)
+#define RCC_MP_AHB2LPENSETR_ADC2LPEN BIT(6)
+#define RCC_MP_AHB2LPENSETR_USBOLPEN BIT(8)
+
+/* RCC_MP_AHB2LPENCLRR register fields */
+#define RCC_MP_AHB2LPENCLRR_DMA1LPEN BIT(0)
+#define RCC_MP_AHB2LPENCLRR_DMA2LPEN BIT(1)
+#define RCC_MP_AHB2LPENCLRR_DMAMUX1LPEN BIT(2)
+#define RCC_MP_AHB2LPENCLRR_DMA3LPEN BIT(3)
+#define RCC_MP_AHB2LPENCLRR_DMAMUX2LPEN BIT(4)
+#define RCC_MP_AHB2LPENCLRR_ADC1LPEN BIT(5)
+#define RCC_MP_AHB2LPENCLRR_ADC2LPEN BIT(6)
+#define RCC_MP_AHB2LPENCLRR_USBOLPEN BIT(8)
+
+/* RCC_MP_AHB4LPENSETR register fields */
+#define RCC_MP_AHB4LPENSETR_TSCLPEN BIT(15)
+
+/* RCC_MP_AHB4LPENCLRR register fields */
+#define RCC_MP_AHB4LPENCLRR_TSCLPEN BIT(15)
+
+/* RCC_MP_S_AHB4LPENSETR register fields */
+#define RCC_MP_S_AHB4LPENSETR_GPIOALPEN BIT(0)
+#define RCC_MP_S_AHB4LPENSETR_GPIOBLPEN BIT(1)
+#define RCC_MP_S_AHB4LPENSETR_GPIOCLPEN BIT(2)
+#define RCC_MP_S_AHB4LPENSETR_GPIODLPEN BIT(3)
+#define RCC_MP_S_AHB4LPENSETR_GPIOELPEN BIT(4)
+#define RCC_MP_S_AHB4LPENSETR_GPIOFLPEN BIT(5)
+#define RCC_MP_S_AHB4LPENSETR_GPIOGLPEN BIT(6)
+#define RCC_MP_S_AHB4LPENSETR_GPIOHLPEN BIT(7)
+#define RCC_MP_S_AHB4LPENSETR_GPIOILPEN BIT(8)
+
+/* RCC_MP_S_AHB4LPENCLRR register fields */
+#define RCC_MP_S_AHB4LPENCLRR_GPIOALPEN BIT(0)
+#define RCC_MP_S_AHB4LPENCLRR_GPIOBLPEN BIT(1)
+#define RCC_MP_S_AHB4LPENCLRR_GPIOCLPEN BIT(2)
+#define RCC_MP_S_AHB4LPENCLRR_GPIODLPEN BIT(3)
+#define RCC_MP_S_AHB4LPENCLRR_GPIOELPEN BIT(4)
+#define RCC_MP_S_AHB4LPENCLRR_GPIOFLPEN BIT(5)
+#define RCC_MP_S_AHB4LPENCLRR_GPIOGLPEN BIT(6)
+#define RCC_MP_S_AHB4LPENCLRR_GPIOHLPEN BIT(7)
+#define RCC_MP_S_AHB4LPENCLRR_GPIOILPEN BIT(8)
+
+/* RCC_MP_NS_AHB4LPENSETR register fields */
+#define RCC_MP_NS_AHB4LPENSETR_GPIOALPEN BIT(0)
+#define RCC_MP_NS_AHB4LPENSETR_GPIOBLPEN BIT(1)
+#define RCC_MP_NS_AHB4LPENSETR_GPIOCLPEN BIT(2)
+#define RCC_MP_NS_AHB4LPENSETR_GPIODLPEN BIT(3)
+#define RCC_MP_NS_AHB4LPENSETR_GPIOELPEN BIT(4)
+#define RCC_MP_NS_AHB4LPENSETR_GPIOFLPEN BIT(5)
+#define RCC_MP_NS_AHB4LPENSETR_GPIOGLPEN BIT(6)
+#define RCC_MP_NS_AHB4LPENSETR_GPIOHLPEN BIT(7)
+#define RCC_MP_NS_AHB4LPENSETR_GPIOILPEN BIT(8)
+
+/* RCC_MP_NS_AHB4LPENCLRR register fields */
+#define RCC_MP_NS_AHB4LPENCLRR_GPIOALPEN BIT(0)
+#define RCC_MP_NS_AHB4LPENCLRR_GPIOBLPEN BIT(1)
+#define RCC_MP_NS_AHB4LPENCLRR_GPIOCLPEN BIT(2)
+#define RCC_MP_NS_AHB4LPENCLRR_GPIODLPEN BIT(3)
+#define RCC_MP_NS_AHB4LPENCLRR_GPIOELPEN BIT(4)
+#define RCC_MP_NS_AHB4LPENCLRR_GPIOFLPEN BIT(5)
+#define RCC_MP_NS_AHB4LPENCLRR_GPIOGLPEN BIT(6)
+#define RCC_MP_NS_AHB4LPENCLRR_GPIOHLPEN BIT(7)
+#define RCC_MP_NS_AHB4LPENCLRR_GPIOILPEN BIT(8)
+
+/* RCC_MP_AHB5LPENSETR register fields */
+#define RCC_MP_AHB5LPENSETR_PKALPEN BIT(2)
+#define RCC_MP_AHB5LPENSETR_SAESLPEN BIT(3)
+#define RCC_MP_AHB5LPENSETR_CRYP1LPEN BIT(4)
+#define RCC_MP_AHB5LPENSETR_HASH1LPEN BIT(5)
+#define RCC_MP_AHB5LPENSETR_RNG1LPEN BIT(6)
+#define RCC_MP_AHB5LPENSETR_BKPSRAMLPEN BIT(8)
+
+/* RCC_MP_AHB5LPENCLRR register fields */
+#define RCC_MP_AHB5LPENCLRR_PKALPEN BIT(2)
+#define RCC_MP_AHB5LPENCLRR_SAESLPEN BIT(3)
+#define RCC_MP_AHB5LPENCLRR_CRYP1LPEN BIT(4)
+#define RCC_MP_AHB5LPENCLRR_HASH1LPEN BIT(5)
+#define RCC_MP_AHB5LPENCLRR_RNG1LPEN BIT(6)
+#define RCC_MP_AHB5LPENCLRR_BKPSRAMLPEN BIT(8)
+
+/* RCC_MP_AHB6LPENSETR register fields */
+#define RCC_MP_AHB6LPENSETR_MCELPEN BIT(1)
+#define RCC_MP_AHB6LPENSETR_ETH1CKLPEN BIT(7)
+#define RCC_MP_AHB6LPENSETR_ETH1TXLPEN BIT(8)
+#define RCC_MP_AHB6LPENSETR_ETH1RXLPEN BIT(9)
+#define RCC_MP_AHB6LPENSETR_ETH1MACLPEN BIT(10)
+#define RCC_MP_AHB6LPENSETR_ETH1STPEN BIT(11)
+#define RCC_MP_AHB6LPENSETR_FMCLPEN BIT(12)
+#define RCC_MP_AHB6LPENSETR_QSPILPEN BIT(14)
+#define RCC_MP_AHB6LPENSETR_SDMMC1LPEN BIT(16)
+#define RCC_MP_AHB6LPENSETR_SDMMC2LPEN BIT(17)
+#define RCC_MP_AHB6LPENSETR_CRC1LPEN BIT(20)
+#define RCC_MP_AHB6LPENSETR_USBHLPEN BIT(24)
+#define RCC_MP_AHB6LPENSETR_ETH2CKLPEN BIT(27)
+#define RCC_MP_AHB6LPENSETR_ETH2TXLPEN BIT(28)
+#define RCC_MP_AHB6LPENSETR_ETH2RXLPEN BIT(29)
+#define RCC_MP_AHB6LPENSETR_ETH2MACLPEN BIT(30)
+#define RCC_MP_AHB6LPENSETR_ETH2STPEN BIT(31)
+
+/* RCC_MP_AHB6LPENCLRR register fields */
+#define RCC_MP_AHB6LPENCLRR_MCELPEN BIT(1)
+#define RCC_MP_AHB6LPENCLRR_ETH1CKLPEN BIT(7)
+#define RCC_MP_AHB6LPENCLRR_ETH1TXLPEN BIT(8)
+#define RCC_MP_AHB6LPENCLRR_ETH1RXLPEN BIT(9)
+#define RCC_MP_AHB6LPENCLRR_ETH1MACLPEN BIT(10)
+#define RCC_MP_AHB6LPENCLRR_ETH1STPEN BIT(11)
+#define RCC_MP_AHB6LPENCLRR_FMCLPEN BIT(12)
+#define RCC_MP_AHB6LPENCLRR_QSPILPEN BIT(14)
+#define RCC_MP_AHB6LPENCLRR_SDMMC1LPEN BIT(16)
+#define RCC_MP_AHB6LPENCLRR_SDMMC2LPEN BIT(17)
+#define RCC_MP_AHB6LPENCLRR_CRC1LPEN BIT(20)
+#define RCC_MP_AHB6LPENCLRR_USBHLPEN BIT(24)
+#define RCC_MP_AHB6LPENCLRR_ETH2CKLPEN BIT(27)
+#define RCC_MP_AHB6LPENCLRR_ETH2TXLPEN BIT(28)
+#define RCC_MP_AHB6LPENCLRR_ETH2RXLPEN BIT(29)
+#define RCC_MP_AHB6LPENCLRR_ETH2MACLPEN BIT(30)
+#define RCC_MP_AHB6LPENCLRR_ETH2STPEN BIT(31)
+
+/* RCC_MP_S_AHB6LPENSETR register fields */
+#define RCC_MP_S_AHB6LPENSETR_MDMALPEN BIT(0)
+
+/* RCC_MP_S_AHB6LPENCLRR register fields */
+#define RCC_MP_S_AHB6LPENCLRR_MDMALPEN BIT(0)
+
+/* RCC_MP_NS_AHB6LPENSETR register fields */
+#define RCC_MP_NS_AHB6LPENSETR_MDMALPEN BIT(0)
+
+/* RCC_MP_NS_AHB6LPENCLRR register fields */
+#define RCC_MP_NS_AHB6LPENCLRR_MDMALPEN BIT(0)
+
+/* RCC_MP_S_AXIMLPENSETR register fields */
+#define RCC_MP_S_AXIMLPENSETR_SYSRAMLPEN BIT(0)
+
+/* RCC_MP_S_AXIMLPENCLRR register fields */
+#define RCC_MP_S_AXIMLPENCLRR_SYSRAMLPEN BIT(0)
+
+/* RCC_MP_NS_AXIMLPENSETR register fields */
+#define RCC_MP_NS_AXIMLPENSETR_SYSRAMLPEN BIT(0)
+
+/* RCC_MP_NS_AXIMLPENCLRR register fields */
+#define RCC_MP_NS_AXIMLPENCLRR_SYSRAMLPEN BIT(0)
+
+/* RCC_MP_MLAHBLPENSETR register fields */
+#define RCC_MP_MLAHBLPENSETR_SRAM1LPEN BIT(0)
+#define RCC_MP_MLAHBLPENSETR_SRAM2LPEN BIT(1)
+#define RCC_MP_MLAHBLPENSETR_SRAM3LPEN BIT(2)
+
+/* RCC_MP_MLAHBLPENCLRR register fields */
+#define RCC_MP_MLAHBLPENCLRR_SRAM1LPEN BIT(0)
+#define RCC_MP_MLAHBLPENCLRR_SRAM2LPEN BIT(1)
+#define RCC_MP_MLAHBLPENCLRR_SRAM3LPEN BIT(2)
+
+/* RCC_APB3SECSR register fields */
+#define RCC_APB3SECSR_LPTIM2SECF BIT(0)
+#define RCC_APB3SECSR_LPTIM3SECF BIT(1)
+#define RCC_APB3SECSR_VREFSECF BIT(13)
+
+/* RCC_APB4SECSR register fields */
+#define RCC_APB4SECSR_DCMIPPSECF BIT(1)
+#define RCC_APB4SECSR_USBPHYSECF BIT(16)
+
+/* RCC_APB5SECSR register fields */
+#define RCC_APB5SECSR_RTCSECF BIT(8)
+#define RCC_APB5SECSR_TZCSECF BIT(11)
+#define RCC_APB5SECSR_ETZPCSECF BIT(13)
+#define RCC_APB5SECSR_IWDG1SECF BIT(15)
+#define RCC_APB5SECSR_BSECSECF BIT(16)
+#define RCC_APB5SECSR_STGENCSECF_MASK GENMASK(21, 20)
+#define RCC_APB5SECSR_STGENCSECF_SHIFT 20
+
+/* RCC_APB6SECSR register fields */
+#define RCC_APB6SECSR_USART1SECF BIT(0)
+#define RCC_APB6SECSR_USART2SECF BIT(1)
+#define RCC_APB6SECSR_SPI4SECF BIT(2)
+#define RCC_APB6SECSR_SPI5SECF BIT(3)
+#define RCC_APB6SECSR_I2C3SECF BIT(4)
+#define RCC_APB6SECSR_I2C4SECF BIT(5)
+#define RCC_APB6SECSR_I2C5SECF BIT(6)
+#define RCC_APB6SECSR_TIM12SECF BIT(7)
+#define RCC_APB6SECSR_TIM13SECF BIT(8)
+#define RCC_APB6SECSR_TIM14SECF BIT(9)
+#define RCC_APB6SECSR_TIM15SECF BIT(10)
+#define RCC_APB6SECSR_TIM16SECF BIT(11)
+#define RCC_APB6SECSR_TIM17SECF BIT(12)
+
+/* RCC_AHB2SECSR register fields */
+#define RCC_AHB2SECSR_DMA3SECF BIT(3)
+#define RCC_AHB2SECSR_DMAMUX2SECF BIT(4)
+#define RCC_AHB2SECSR_ADC1SECF BIT(5)
+#define RCC_AHB2SECSR_ADC2SECF BIT(6)
+#define RCC_AHB2SECSR_USBOSECF BIT(8)
+
+/* RCC_AHB4SECSR register fields */
+#define RCC_AHB4SECSR_TSCSECF BIT(15)
+
+/* RCC_AHB5SECSR register fields */
+#define RCC_AHB5SECSR_PKASECF BIT(2)
+#define RCC_AHB5SECSR_SAESSECF BIT(3)
+#define RCC_AHB5SECSR_CRYP1SECF BIT(4)
+#define RCC_AHB5SECSR_HASH1SECF BIT(5)
+#define RCC_AHB5SECSR_RNG1SECF BIT(6)
+#define RCC_AHB5SECSR_BKPSRAMSECF BIT(8)
+
+/* RCC_AHB6SECSR register fields */
+#define RCC_AHB6SECSR_MCESECF BIT(1)
+#define RCC_AHB6SECSR_ETH1SECF_MASK GENMASK(11, 7)
+#define RCC_AHB6SECSR_ETH1SECF_SHIFT 7
+#define RCC_AHB6SECSR_FMCSECF BIT(12)
+#define RCC_AHB6SECSR_QSPISECF BIT(14)
+#define RCC_AHB6SECSR_SDMMC1SECF BIT(16)
+#define RCC_AHB6SECSR_SDMMC2SECF BIT(17)
+#define RCC_AHB6SECSR_ETH2SECF_MASK GENMASK(31, 27)
+#define RCC_AHB6SECSR_ETH2SECF_SHIFT 27
+
+/* RCC_VERR register fields */
+#define RCC_VERR_MINREV_MASK GENMASK(3, 0)
+#define RCC_VERR_MINREV_SHIFT 0
+#define RCC_VERR_MAJREV_MASK GENMASK(7, 4)
+#define RCC_VERR_MAJREV_SHIFT 4
+
+/* RCC_IDR register fields */
+#define RCC_IDR_ID_MASK GENMASK(31, 0)
+#define RCC_IDR_ID_SHIFT 0
+
+/* RCC_SIDR register fields */
+#define RCC_SIDR_SID_MASK GENMASK(31, 0)
+#define RCC_SIDR_SID_SHIFT 0
+
+/* Used for all RCC_PLL<n>CR registers */
+#define RCC_PLLNCR_PLLON BIT(0)
+#define RCC_PLLNCR_PLLRDY BIT(1)
+#define RCC_PLLNCR_SSCG_CTRL BIT(2)
+#define RCC_PLLNCR_DIVPEN BIT(4)
+#define RCC_PLLNCR_DIVQEN BIT(5)
+#define RCC_PLLNCR_DIVREN BIT(6)
+#define RCC_PLLNCR_DIVEN_SHIFT 4
+
+/* Used for all RCC_PLL<n>CFGR1 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_PLL<n>CFGR2 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_PLL<n>FRACR 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_PLL<n>CSGR 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 most of RCC_<x>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_MLAHBDIV_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)
+
+/* RCC_OCENSETR register fields */
+#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)
+
+#define RCC_OCENR_DIGBYP_BIT 7
+#define RCC_OCENR_HSEBYP_BIT 10
+#define RCC_OCENR_HSECSSON_BIT 11
+
+/* 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)
+
+#define RCC_UART4CKSELR_HSI 0x00000002
+
+#define RCC_CPERCKSELR_PERSRC_MASK GENMASK(1, 0)
+#define RCC_CPERCKSELR_PERSRC_SHIFT 0
+
+#define RCC_USBCKSELR_USBOSRC_MASK BIT(4)
+#define RCC_USBCKSELR_USBOSRC_SHIFT 4
+
+#define RCC_DDRITFCR_DDRCKMOD_SSR 0
+#define RCC_DDRITFCR_DDRCKMOD_ASR1 BIT(20)
+#define RCC_DDRITFCR_DDRCKMOD_HSR1 BIT(21)
+
+#define RCC_DDRITFCR_DDRC2EN BIT(0)
+#define RCC_DDRITFCR_DDRC2LPEN BIT(1)
+
+#define RCC_MP_CIFR_MASK U(0x110F1F)
+#define RCC_OFFSET_MASK GENMASK(11, 0)
+
+#endif /* STM32MP1_RCC_H */
diff --git a/include/drivers/st/stm32mp15_rcc.h b/include/drivers/st/stm32mp15_rcc.h
new file mode 100644
index 0000000..ddc0397
--- /dev/null
+++ b/include/drivers/st/stm32mp15_rcc.h
@@ -0,0 +1,2328 @@
+/*
+ * Copyright (c) 2015-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_RCC_H
+#define STM32MP1_RCC_H
+
+#include <lib/utils_def.h>
+
+#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)
+
+/* RCC_TZCR register fields */
+#define RCC_TZCR_TZEN BIT(0)
+#define RCC_TZCR_MCKPROT BIT(1)
+
+/* RCC_OCENSETR register fields */
+#define RCC_OCENSETR_HSION BIT(0)
+#define RCC_OCENSETR_HSIKERON BIT(1)
+#define RCC_OCENSETR_CSION BIT(4)
+#define RCC_OCENSETR_CSIKERON BIT(5)
+#define RCC_OCENSETR_DIGBYP BIT(7)
+#define RCC_OCENSETR_HSEON BIT(8)
+#define RCC_OCENSETR_HSEKERON BIT(9)
+#define RCC_OCENSETR_HSEBYP BIT(10)
+#define RCC_OCENSETR_HSECSSON BIT(11)
+
+/* RCC_OCENCLRR register fields */
+#define RCC_OCENCLRR_HSION BIT(0)
+#define RCC_OCENCLRR_HSIKERON BIT(1)
+#define RCC_OCENCLRR_CSION BIT(4)
+#define RCC_OCENCLRR_CSIKERON BIT(5)
+#define RCC_OCENCLRR_DIGBYP BIT(7)
+#define RCC_OCENCLRR_HSEON BIT(8)
+#define RCC_OCENCLRR_HSEKERON BIT(9)
+#define RCC_OCENCLRR_HSEBYP BIT(10)
+
+/* RCC_HSICFGR register fields */
+#define RCC_HSICFGR_HSIDIV_MASK GENMASK(1, 0)
+#define RCC_HSICFGR_HSIDIV_SHIFT 0
+#define RCC_HSICFGR_HSITRIM_MASK GENMASK(14, 8)
+#define RCC_HSICFGR_HSITRIM_SHIFT 8
+#define RCC_HSICFGR_HSICAL_MASK GENMASK(24, 16)
+#define RCC_HSICFGR_HSICAL_SHIFT 16
+#define RCC_HSICFGR_HSICAL_TEMP_MASK GENMASK(27, 25)
+
+/* RCC_CSICFGR register fields */
+#define RCC_CSICFGR_CSITRIM_MASK GENMASK(12, 8)
+#define RCC_CSICFGR_CSITRIM_SHIFT 8
+#define RCC_CSICFGR_CSICAL_MASK GENMASK(23, 16)
+#define RCC_CSICFGR_CSICAL_SHIFT 16
+
+/* RCC_MPCKSELR register fields */
+#define RCC_MPCKSELR_HSI 0x00000000
+#define RCC_MPCKSELR_HSE 0x00000001
+#define RCC_MPCKSELR_PLL 0x00000002
+#define RCC_MPCKSELR_PLL_MPUDIV 0x00000003
+#define RCC_MPCKSELR_MPUSRC_MASK GENMASK(1, 0)
+#define RCC_MPCKSELR_MPUSRC_SHIFT 0
+#define RCC_MPCKSELR_MPUSRCRDY BIT(31)
+
+/* RCC_ASSCKSELR register fields */
+#define RCC_ASSCKSELR_HSI 0x00000000
+#define RCC_ASSCKSELR_HSE 0x00000001
+#define RCC_ASSCKSELR_PLL 0x00000002
+#define RCC_ASSCKSELR_AXISSRC_MASK GENMASK(2, 0)
+#define RCC_ASSCKSELR_AXISSRC_SHIFT 0
+#define RCC_ASSCKSELR_AXISSRCRDY BIT(31)
+
+/* RCC_RCK12SELR register fields */
+#define RCC_RCK12SELR_PLL12SRC_MASK GENMASK(1, 0)
+#define RCC_RCK12SELR_PLL12SRC_SHIFT 0
+#define RCC_RCK12SELR_PLL12SRCRDY BIT(31)
+
+/* RCC_MPCKDIVR register fields */
+#define RCC_MPCKDIVR_MPUDIV_MASK GENMASK(2, 0)
+#define RCC_MPCKDIVR_MPUDIV_SHIFT 0
+#define RCC_MPCKDIVR_MPUDIVRDY BIT(31)
+
+/* RCC_AXIDIVR register fields */
+#define RCC_AXIDIVR_AXIDIV_MASK GENMASK(2, 0)
+#define RCC_AXIDIVR_AXIDIV_SHIFT 0
+#define RCC_AXIDIVR_AXIDIVRDY BIT(31)
+
+/* RCC_APB4DIVR register fields */
+#define RCC_APB4DIVR_APB4DIV_MASK GENMASK(2, 0)
+#define RCC_APB4DIVR_APB4DIV_SHIFT 0
+#define RCC_APB4DIVR_APB4DIVRDY BIT(31)
+
+/* RCC_APB5DIVR register fields */
+#define RCC_APB5DIVR_APB5DIV_MASK GENMASK(2, 0)
+#define RCC_APB5DIVR_APB5DIV_SHIFT 0
+#define RCC_APB5DIVR_APB5DIVRDY BIT(31)
+
+/* RCC_RTCDIVR register fields */
+#define RCC_RTCDIVR_RTCDIV_MASK GENMASK(5, 0)
+#define RCC_RTCDIVR_RTCDIV_SHIFT 0
+
+/* RCC_MSSCKSELR register fields */
+#define RCC_MSSCKSELR_HSI 0x00000000
+#define RCC_MSSCKSELR_HSE 0x00000001
+#define RCC_MSSCKSELR_CSI 0x00000002
+#define RCC_MSSCKSELR_PLL 0x00000003
+#define RCC_MSSCKSELR_MCUSSRC_MASK GENMASK(1, 0)
+#define RCC_MSSCKSELR_MCUSSRC_SHIFT 0
+#define RCC_MSSCKSELR_MCUSSRCRDY BIT(31)
+
+/* RCC_PLL1CR register fields */
+#define RCC_PLL1CR_PLLON BIT(0)
+#define RCC_PLL1CR_PLL1RDY BIT(1)
+#define RCC_PLL1CR_SSCG_CTRL BIT(2)
+#define RCC_PLL1CR_DIVPEN BIT(4)
+#define RCC_PLL1CR_DIVQEN BIT(5)
+#define RCC_PLL1CR_DIVREN BIT(6)
+
+/* RCC_PLL1CFGR1 register fields */
+#define RCC_PLL1CFGR1_DIVN_MASK GENMASK(8, 0)
+#define RCC_PLL1CFGR1_DIVN_SHIFT 0
+#define RCC_PLL1CFGR1_DIVM1_MASK GENMASK(21, 16)
+#define RCC_PLL1CFGR1_DIVM1_SHIFT 16
+
+/* RCC_PLL1CFGR2 register fields */
+#define RCC_PLL1CFGR2_DIVP_MASK GENMASK(6, 0)
+#define RCC_PLL1CFGR2_DIVP_SHIFT 0
+#define RCC_PLL1CFGR2_DIVQ_MASK GENMASK(14, 8)
+#define RCC_PLL1CFGR2_DIVQ_SHIFT 8
+#define RCC_PLL1CFGR2_DIVR_MASK GENMASK(22, 16)
+#define RCC_PLL1CFGR2_DIVR_SHIFT 16
+
+/* RCC_PLL1FRACR register fields */
+#define RCC_PLL1FRACR_FRACV_MASK GENMASK(15, 3)
+#define RCC_PLL1FRACR_FRACV_SHIFT 3
+#define RCC_PLL1FRACR_FRACLE BIT(16)
+
+/* RCC_PLL1CSGR register fields */
+#define RCC_PLL1CSGR_MOD_PER_MASK GENMASK(12, 0)
+#define RCC_PLL1CSGR_MOD_PER_SHIFT 0
+#define RCC_PLL1CSGR_TPDFN_DIS BIT(13)
+#define RCC_PLL1CSGR_RPDFN_DIS BIT(14)
+#define RCC_PLL1CSGR_SSCG_MODE BIT(15)
+#define RCC_PLL1CSGR_INC_STEP_MASK GENMASK(30, 16)
+#define RCC_PLL1CSGR_INC_STEP_SHIFT 16
+
+/* RCC_PLL2CR register fields */
+#define RCC_PLL2CR_PLLON BIT(0)
+#define RCC_PLL2CR_PLL2RDY BIT(1)
+#define RCC_PLL2CR_SSCG_CTRL BIT(2)
+#define RCC_PLL2CR_DIVPEN BIT(4)
+#define RCC_PLL2CR_DIVQEN BIT(5)
+#define RCC_PLL2CR_DIVREN BIT(6)
+
+/* RCC_PLL2CFGR1 register fields */
+#define RCC_PLL2CFGR1_DIVN_MASK GENMASK(8, 0)
+#define RCC_PLL2CFGR1_DIVN_SHIFT 0
+#define RCC_PLL2CFGR1_DIVM2_MASK GENMASK(21, 16)
+#define RCC_PLL2CFGR1_DIVM2_SHIFT 16
+
+/* RCC_PLL2CFGR2 register fields */
+#define RCC_PLL2CFGR2_DIVP_MASK GENMASK(6, 0)
+#define RCC_PLL2CFGR2_DIVP_SHIFT 0
+#define RCC_PLL2CFGR2_DIVQ_MASK GENMASK(14, 8)
+#define RCC_PLL2CFGR2_DIVQ_SHIFT 8
+#define RCC_PLL2CFGR2_DIVR_MASK GENMASK(22, 16)
+#define RCC_PLL2CFGR2_DIVR_SHIFT 16
+
+/* RCC_PLL2FRACR register fields */
+#define RCC_PLL2FRACR_FRACV_MASK GENMASK(15, 3)
+#define RCC_PLL2FRACR_FRACV_SHIFT 3
+#define RCC_PLL2FRACR_FRACLE BIT(16)
+
+/* RCC_PLL2CSGR register fields */
+#define RCC_PLL2CSGR_MOD_PER_MASK GENMASK(12, 0)
+#define RCC_PLL2CSGR_MOD_PER_SHIFT 0
+#define RCC_PLL2CSGR_TPDFN_DIS BIT(13)
+#define RCC_PLL2CSGR_RPDFN_DIS BIT(14)
+#define RCC_PLL2CSGR_SSCG_MODE BIT(15)
+#define RCC_PLL2CSGR_INC_STEP_MASK GENMASK(30, 16)
+#define RCC_PLL2CSGR_INC_STEP_SHIFT 16
+
+/* 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_CPERCKSELR register fields */
+#define RCC_CPERCKSELR_HSI 0x00000000
+#define RCC_CPERCKSELR_CSI 0x00000001
+#define RCC_CPERCKSELR_HSE 0x00000002
+#define RCC_CPERCKSELR_CKPERSRC_MASK GENMASK(1, 0)
+#define RCC_CPERCKSELR_CKPERSRC_SHIFT 0
+
+/* RCC_STGENCKSELR register fields */
+#define RCC_STGENCKSELR_STGENSRC_MASK GENMASK(1, 0)
+#define RCC_STGENCKSELR_STGENSRC_SHIFT 0
+
+/* RCC_DDRITFCR register fields */
+#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_KERDCG_DLY_MASK GENMASK(13, 11)
+#define RCC_DDRITFCR_KERDCG_DLY_SHIFT 11
+#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_GSKPMOD BIT(23)
+#define RCC_DDRITFCR_GSKPCTRL BIT(24)
+#define RCC_DDRITFCR_DFILP_WIDTH_MASK GENMASK(27, 25)
+#define RCC_DDRITFCR_DFILP_WIDTH_SHIFT 25
+#define RCC_DDRITFCR_GSKP_DUR_MASK GENMASK(31, 28)
+#define RCC_DDRITFCR_GSKP_DUR_SHIFT 28
+
+/* RCC_MP_BOOTCR register fields */
+#define RCC_MP_BOOTCR_MCU_BEN BIT(0)
+#define RCC_MP_BOOTCR_MPU_BEN BIT(1)
+
+/* RCC_MP_SREQSETR register fields */
+#define RCC_MP_SREQSETR_STPREQ_P0 BIT(0)
+#define RCC_MP_SREQSETR_STPREQ_P1 BIT(1)
+
+/* RCC_MP_SREQCLRR register fields */
+#define RCC_MP_SREQCLRR_STPREQ_P0 BIT(0)
+#define RCC_MP_SREQCLRR_STPREQ_P1 BIT(1)
+
+/* RCC_MP_GCR register fields */
+#define RCC_MP_GCR_BOOT_MCU BIT(0)
+
+/* RCC_MP_APRSTCR register fields */
+#define RCC_MP_APRSTCR_RDCTLEN BIT(0)
+#define RCC_MP_APRSTCR_RSTTO_MASK GENMASK(14, 8)
+#define RCC_MP_APRSTCR_RSTTO_SHIFT 8
+
+/* RCC_MP_APRSTSR register fields */
+#define RCC_MP_APRSTSR_RSTTOV_MASK GENMASK(14, 8)
+#define RCC_MP_APRSTSR_RSTTOV_SHIFT 8
+
+/* RCC_BDCR register fields */
+#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_LSECSSD BIT(9)
+#define RCC_BDCR_RTCSRC_MASK GENMASK(17, 16)
+#define RCC_BDCR_RTCSRC_SHIFT 16
+#define RCC_BDCR_RTCCKEN BIT(20)
+#define RCC_BDCR_VSWRST BIT(31)
+
+/* RCC_RDLSICR register fields */
+#define RCC_RDLSICR_LSION BIT(0)
+#define RCC_RDLSICR_LSIRDY BIT(1)
+#define RCC_RDLSICR_MRD_MASK GENMASK(20, 16)
+#define RCC_RDLSICR_MRD_SHIFT 16
+#define RCC_RDLSICR_EADLY_MASK GENMASK(26, 24)
+#define RCC_RDLSICR_EADLY_SHIFT 24
+#define RCC_RDLSICR_SPARE_MASK GENMASK(31, 27)
+#define RCC_RDLSICR_SPARE_SHIFT 27
+
+/* RCC_APB4RSTSETR register fields */
+#define RCC_APB4RSTSETR_LTDCRST BIT(0)
+#define RCC_APB4RSTSETR_DSIRST BIT(4)
+#define RCC_APB4RSTSETR_DDRPERFMRST BIT(8)
+#define RCC_APB4RSTSETR_USBPHYRST BIT(16)
+
+/* RCC_APB4RSTCLRR register fields */
+#define RCC_APB4RSTCLRR_LTDCRST BIT(0)
+#define RCC_APB4RSTCLRR_DSIRST BIT(4)
+#define RCC_APB4RSTCLRR_DDRPERFMRST BIT(8)
+#define RCC_APB4RSTCLRR_USBPHYRST BIT(16)
+
+/* RCC_APB5RSTSETR register fields */
+#define RCC_APB5RSTSETR_SPI6RST BIT(0)
+#define RCC_APB5RSTSETR_I2C4RST BIT(2)
+#define RCC_APB5RSTSETR_I2C6RST BIT(3)
+#define RCC_APB5RSTSETR_USART1RST BIT(4)
+#define RCC_APB5RSTSETR_STGENRST BIT(20)
+
+/* RCC_APB5RSTCLRR register fields */
+#define RCC_APB5RSTCLRR_SPI6RST BIT(0)
+#define RCC_APB5RSTCLRR_I2C4RST BIT(2)
+#define RCC_APB5RSTCLRR_I2C6RST BIT(3)
+#define RCC_APB5RSTCLRR_USART1RST BIT(4)
+#define RCC_APB5RSTCLRR_STGENRST BIT(20)
+
+/* RCC_AHB5RSTSETR register fields */
+#define RCC_AHB5RSTSETR_GPIOZRST BIT(0)
+#define RCC_AHB5RSTSETR_CRYP1RST BIT(4)
+#define RCC_AHB5RSTSETR_HASH1RST BIT(5)
+#define RCC_AHB5RSTSETR_RNG1RST BIT(6)
+#define RCC_AHB5RSTSETR_AXIMCRST BIT(16)
+
+/* RCC_AHB5RSTCLRR register fields */
+#define RCC_AHB5RSTCLRR_GPIOZRST BIT(0)
+#define RCC_AHB5RSTCLRR_CRYP1RST BIT(4)
+#define RCC_AHB5RSTCLRR_HASH1RST BIT(5)
+#define RCC_AHB5RSTCLRR_RNG1RST BIT(6)
+#define RCC_AHB5RSTCLRR_AXIMCRST BIT(16)
+
+/* RCC_AHB6RSTSETR register fields */
+#define RCC_AHB6RSTSETR_GPURST BIT(5)
+#define RCC_AHB6RSTSETR_ETHMACRST BIT(10)
+#define RCC_AHB6RSTSETR_FMCRST BIT(12)
+#define RCC_AHB6RSTSETR_QSPIRST BIT(14)
+#define RCC_AHB6RSTSETR_SDMMC1RST BIT(16)
+#define RCC_AHB6RSTSETR_SDMMC2RST BIT(17)
+#define RCC_AHB6RSTSETR_CRC1RST BIT(20)
+#define RCC_AHB6RSTSETR_USBHRST BIT(24)
+
+/* RCC_AHB6RSTCLRR register fields */
+#define RCC_AHB6RSTCLRR_ETHMACRST BIT(10)
+#define RCC_AHB6RSTCLRR_FMCRST BIT(12)
+#define RCC_AHB6RSTCLRR_QSPIRST BIT(14)
+#define RCC_AHB6RSTCLRR_SDMMC1RST BIT(16)
+#define RCC_AHB6RSTCLRR_SDMMC2RST BIT(17)
+#define RCC_AHB6RSTCLRR_CRC1RST BIT(20)
+#define RCC_AHB6RSTCLRR_USBHRST BIT(24)
+
+/* RCC_TZAHB6RSTSETR register fields */
+#define RCC_TZAHB6RSTSETR_MDMARST BIT(0)
+
+/* RCC_TZAHB6RSTCLRR register fields */
+#define RCC_TZAHB6RSTCLRR_MDMARST BIT(0)
+
+/* RCC_MP_APB4ENSETR register fields */
+#define RCC_MP_APB4ENSETR_LTDCEN BIT(0)
+#define RCC_MP_APB4ENSETR_DSIEN BIT(4)
+#define RCC_MP_APB4ENSETR_DDRPERFMEN BIT(8)
+#define RCC_MP_APB4ENSETR_IWDG2APBEN BIT(15)
+#define RCC_MP_APB4ENSETR_USBPHYEN BIT(16)
+#define RCC_MP_APB4ENSETR_STGENROEN BIT(20)
+
+/* RCC_MP_APB4ENCLRR register fields */
+#define RCC_MP_APB4ENCLRR_LTDCEN BIT(0)
+#define RCC_MP_APB4ENCLRR_DSIEN BIT(4)
+#define RCC_MP_APB4ENCLRR_DDRPERFMEN BIT(8)
+#define RCC_MP_APB4ENCLRR_IWDG2APBEN BIT(15)
+#define RCC_MP_APB4ENCLRR_USBPHYEN BIT(16)
+#define RCC_MP_APB4ENCLRR_STGENROEN BIT(20)
+
+/* RCC_MP_APB5ENSETR register fields */
+#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_TZC1EN BIT(11)
+#define RCC_MP_APB5ENSETR_TZC2EN BIT(12)
+#define RCC_MP_APB5ENSETR_TZPCEN BIT(13)
+#define RCC_MP_APB5ENSETR_IWDG1APBEN BIT(15)
+#define RCC_MP_APB5ENSETR_BSECEN BIT(16)
+#define RCC_MP_APB5ENSETR_STGENEN BIT(20)
+
+/* RCC_MP_APB5ENCLRR register fields */
+#define RCC_MP_APB5ENCLRR_SPI6EN BIT(0)
+#define RCC_MP_APB5ENCLRR_I2C4EN BIT(2)
+#define RCC_MP_APB5ENCLRR_I2C6EN BIT(3)
+#define RCC_MP_APB5ENCLRR_USART1EN BIT(4)
+#define RCC_MP_APB5ENCLRR_RTCAPBEN BIT(8)
+#define RCC_MP_APB5ENCLRR_TZC1EN BIT(11)
+#define RCC_MP_APB5ENCLRR_TZC2EN BIT(12)
+#define RCC_MP_APB5ENCLRR_TZPCEN BIT(13)
+#define RCC_MP_APB5ENCLRR_IWDG1APBEN BIT(15)
+#define RCC_MP_APB5ENCLRR_BSECEN BIT(16)
+#define RCC_MP_APB5ENCLRR_STGENEN BIT(20)
+
+/* RCC_MP_AHB5ENSETR register fields */
+#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)
+#define RCC_MP_AHB5ENSETR_BKPSRAMEN BIT(8)
+#define RCC_MP_AHB5ENSETR_AXIMCEN BIT(16)
+
+/* RCC_MP_AHB5ENCLRR register fields */
+#define RCC_MP_AHB5ENCLRR_GPIOZEN BIT(0)
+#define RCC_MP_AHB5ENCLRR_CRYP1EN BIT(4)
+#define RCC_MP_AHB5ENCLRR_HASH1EN BIT(5)
+#define RCC_MP_AHB5ENCLRR_RNG1EN BIT(6)
+#define RCC_MP_AHB5ENCLRR_BKPSRAMEN BIT(8)
+#define RCC_MP_AHB5ENCLRR_AXIMCEN BIT(16)
+
+/* RCC_MP_AHB6ENSETR register fields */
+#define RCC_MP_AHB6ENSETR_MDMAEN BIT(0)
+#define RCC_MP_AHB6ENSETR_GPUEN BIT(5)
+#define RCC_MP_AHB6ENSETR_ETHCKEN BIT(7)
+#define RCC_MP_AHB6ENSETR_ETHTXEN BIT(8)
+#define RCC_MP_AHB6ENSETR_ETHRXEN BIT(9)
+#define RCC_MP_AHB6ENSETR_ETHMACEN BIT(10)
+#define RCC_MP_AHB6ENSETR_FMCEN BIT(12)
+#define RCC_MP_AHB6ENSETR_QSPIEN BIT(14)
+#define RCC_MP_AHB6ENSETR_SDMMC1EN BIT(16)
+#define RCC_MP_AHB6ENSETR_SDMMC2EN BIT(17)
+#define RCC_MP_AHB6ENSETR_CRC1EN BIT(20)
+#define RCC_MP_AHB6ENSETR_USBHEN BIT(24)
+
+/* RCC_MP_AHB6ENCLRR register fields */
+#define RCC_MP_AHB6ENCLRR_MDMAEN BIT(0)
+#define RCC_MP_AHB6ENCLRR_GPUEN BIT(5)
+#define RCC_MP_AHB6ENCLRR_ETHCKEN BIT(7)
+#define RCC_MP_AHB6ENCLRR_ETHTXEN BIT(8)
+#define RCC_MP_AHB6ENCLRR_ETHRXEN BIT(9)
+#define RCC_MP_AHB6ENCLRR_ETHMACEN BIT(10)
+#define RCC_MP_AHB6ENCLRR_FMCEN BIT(12)
+#define RCC_MP_AHB6ENCLRR_QSPIEN BIT(14)
+#define RCC_MP_AHB6ENCLRR_SDMMC1EN BIT(16)
+#define RCC_MP_AHB6ENCLRR_SDMMC2EN BIT(17)
+#define RCC_MP_AHB6ENCLRR_CRC1EN BIT(20)
+#define RCC_MP_AHB6ENCLRR_USBHEN BIT(24)
+
+/* RCC_MP_TZAHB6ENSETR register fields */
+#define RCC_MP_TZAHB6ENSETR_MDMAEN BIT(0)
+
+/* RCC_MP_TZAHB6ENCLRR register fields */
+#define RCC_MP_TZAHB6ENCLRR_MDMAEN BIT(0)
+
+/* RCC_MC_APB4ENSETR register fields */
+#define RCC_MC_APB4ENSETR_LTDCEN BIT(0)
+#define RCC_MC_APB4ENSETR_DSIEN BIT(4)
+#define RCC_MC_APB4ENSETR_DDRPERFMEN BIT(8)
+#define RCC_MC_APB4ENSETR_USBPHYEN BIT(16)
+#define RCC_MC_APB4ENSETR_STGENROEN BIT(20)
+
+/* RCC_MC_APB4ENCLRR register fields */
+#define RCC_MC_APB4ENCLRR_LTDCEN BIT(0)
+#define RCC_MC_APB4ENCLRR_DSIEN BIT(4)
+#define RCC_MC_APB4ENCLRR_DDRPERFMEN BIT(8)
+#define RCC_MC_APB4ENCLRR_USBPHYEN BIT(16)
+#define RCC_MC_APB4ENCLRR_STGENROEN BIT(20)
+
+/* RCC_MC_APB5ENSETR register fields */
+#define RCC_MC_APB5ENSETR_SPI6EN BIT(0)
+#define RCC_MC_APB5ENSETR_I2C4EN BIT(2)
+#define RCC_MC_APB5ENSETR_I2C6EN BIT(3)
+#define RCC_MC_APB5ENSETR_USART1EN BIT(4)
+#define RCC_MC_APB5ENSETR_RTCAPBEN BIT(8)
+#define RCC_MC_APB5ENSETR_TZC1EN BIT(11)
+#define RCC_MC_APB5ENSETR_TZC2EN BIT(12)
+#define RCC_MC_APB5ENSETR_TZPCEN BIT(13)
+#define RCC_MC_APB5ENSETR_BSECEN BIT(16)
+#define RCC_MC_APB5ENSETR_STGENEN BIT(20)
+
+/* RCC_MC_APB5ENCLRR register fields */
+#define RCC_MC_APB5ENCLRR_SPI6EN BIT(0)
+#define RCC_MC_APB5ENCLRR_I2C4EN BIT(2)
+#define RCC_MC_APB5ENCLRR_I2C6EN BIT(3)
+#define RCC_MC_APB5ENCLRR_USART1EN BIT(4)
+#define RCC_MC_APB5ENCLRR_RTCAPBEN BIT(8)
+#define RCC_MC_APB5ENCLRR_TZC1EN BIT(11)
+#define RCC_MC_APB5ENCLRR_TZC2EN BIT(12)
+#define RCC_MC_APB5ENCLRR_TZPCEN BIT(13)
+#define RCC_MC_APB5ENCLRR_BSECEN BIT(16)
+#define RCC_MC_APB5ENCLRR_STGENEN BIT(20)
+
+/* RCC_MC_AHB5ENSETR register fields */
+#define RCC_MC_AHB5ENSETR_GPIOZEN BIT(0)
+#define RCC_MC_AHB5ENSETR_CRYP1EN BIT(4)
+#define RCC_MC_AHB5ENSETR_HASH1EN BIT(5)
+#define RCC_MC_AHB5ENSETR_RNG1EN BIT(6)
+#define RCC_MC_AHB5ENSETR_BKPSRAMEN BIT(8)
+
+/* RCC_MC_AHB5ENCLRR register fields */
+#define RCC_MC_AHB5ENCLRR_GPIOZEN BIT(0)
+#define RCC_MC_AHB5ENCLRR_CRYP1EN BIT(4)
+#define RCC_MC_AHB5ENCLRR_HASH1EN BIT(5)
+#define RCC_MC_AHB5ENCLRR_RNG1EN BIT(6)
+#define RCC_MC_AHB5ENCLRR_BKPSRAMEN BIT(8)
+
+/* RCC_MC_AHB6ENSETR register fields */
+#define RCC_MC_AHB6ENSETR_MDMAEN BIT(0)
+#define RCC_MC_AHB6ENSETR_GPUEN BIT(5)
+#define RCC_MC_AHB6ENSETR_ETHCKEN BIT(7)
+#define RCC_MC_AHB6ENSETR_ETHTXEN BIT(8)
+#define RCC_MC_AHB6ENSETR_ETHRXEN BIT(9)
+#define RCC_MC_AHB6ENSETR_ETHMACEN BIT(10)
+#define RCC_MC_AHB6ENSETR_FMCEN BIT(12)
+#define RCC_MC_AHB6ENSETR_QSPIEN BIT(14)
+#define RCC_MC_AHB6ENSETR_SDMMC1EN BIT(16)
+#define RCC_MC_AHB6ENSETR_SDMMC2EN BIT(17)
+#define RCC_MC_AHB6ENSETR_CRC1EN BIT(20)
+#define RCC_MC_AHB6ENSETR_USBHEN BIT(24)
+
+/* RCC_MC_AHB6ENCLRR register fields */
+#define RCC_MC_AHB6ENCLRR_MDMAEN BIT(0)
+#define RCC_MC_AHB6ENCLRR_GPUEN BIT(5)
+#define RCC_MC_AHB6ENCLRR_ETHCKEN BIT(7)
+#define RCC_MC_AHB6ENCLRR_ETHTXEN BIT(8)
+#define RCC_MC_AHB6ENCLRR_ETHRXEN BIT(9)
+#define RCC_MC_AHB6ENCLRR_ETHMACEN BIT(10)
+#define RCC_MC_AHB6ENCLRR_FMCEN BIT(12)
+#define RCC_MC_AHB6ENCLRR_QSPIEN BIT(14)
+#define RCC_MC_AHB6ENCLRR_SDMMC1EN BIT(16)
+#define RCC_MC_AHB6ENCLRR_SDMMC2EN BIT(17)
+#define RCC_MC_AHB6ENCLRR_CRC1EN BIT(20)
+#define RCC_MC_AHB6ENCLRR_USBHEN BIT(24)
+
+/* RCC_MP_APB4LPENSETR register fields */
+#define RCC_MP_APB4LPENSETR_LTDCLPEN BIT(0)
+#define RCC_MP_APB4LPENSETR_DSILPEN BIT(4)
+#define RCC_MP_APB4LPENSETR_DDRPERFMLPEN BIT(8)
+#define RCC_MP_APB4LPENSETR_IWDG2APBLPEN BIT(15)
+#define RCC_MP_APB4LPENSETR_USBPHYLPEN BIT(16)
+#define RCC_MP_APB4LPENSETR_STGENROLPEN BIT(20)
+#define RCC_MP_APB4LPENSETR_STGENROSTPEN BIT(21)
+
+/* RCC_MP_APB4LPENCLRR register fields */
+#define RCC_MP_APB4LPENCLRR_LTDCLPEN BIT(0)
+#define RCC_MP_APB4LPENCLRR_DSILPEN BIT(4)
+#define RCC_MP_APB4LPENCLRR_DDRPERFMLPEN BIT(8)
+#define RCC_MP_APB4LPENCLRR_IWDG2APBLPEN BIT(15)
+#define RCC_MP_APB4LPENCLRR_USBPHYLPEN BIT(16)
+#define RCC_MP_APB4LPENCLRR_STGENROLPEN BIT(20)
+#define RCC_MP_APB4LPENCLRR_STGENROSTPEN BIT(21)
+
+/* RCC_MP_APB5LPENSETR register fields */
+#define RCC_MP_APB5LPENSETR_SPI6LPEN BIT(0)
+#define RCC_MP_APB5LPENSETR_I2C4LPEN BIT(2)
+#define RCC_MP_APB5LPENSETR_I2C6LPEN BIT(3)
+#define RCC_MP_APB5LPENSETR_USART1LPEN BIT(4)
+#define RCC_MP_APB5LPENSETR_RTCAPBLPEN BIT(8)
+#define RCC_MP_APB5LPENSETR_TZC1LPEN BIT(11)
+#define RCC_MP_APB5LPENSETR_TZC2LPEN BIT(12)
+#define RCC_MP_APB5LPENSETR_TZPCLPEN BIT(13)
+#define RCC_MP_APB5LPENSETR_IWDG1APBLPEN BIT(15)
+#define RCC_MP_APB5LPENSETR_BSECLPEN BIT(16)
+#define RCC_MP_APB5LPENSETR_STGENLPEN BIT(20)
+#define RCC_MP_APB5LPENSETR_STGENSTPEN BIT(21)
+
+/* RCC_MP_APB5LPENCLRR register fields */
+#define RCC_MP_APB5LPENCLRR_SPI6LPEN BIT(0)
+#define RCC_MP_APB5LPENCLRR_I2C4LPEN BIT(2)
+#define RCC_MP_APB5LPENCLRR_I2C6LPEN BIT(3)
+#define RCC_MP_APB5LPENCLRR_USART1LPEN BIT(4)
+#define RCC_MP_APB5LPENCLRR_RTCAPBLPEN BIT(8)
+#define RCC_MP_APB5LPENCLRR_TZC1LPEN BIT(11)
+#define RCC_MP_APB5LPENCLRR_TZC2LPEN BIT(12)
+#define RCC_MP_APB5LPENCLRR_TZPCLPEN BIT(13)
+#define RCC_MP_APB5LPENCLRR_IWDG1APBLPEN BIT(15)
+#define RCC_MP_APB5LPENCLRR_BSECLPEN BIT(16)
+#define RCC_MP_APB5LPENCLRR_STGENLPEN BIT(20)
+#define RCC_MP_APB5LPENCLRR_STGENSTPEN BIT(21)
+
+/* RCC_MP_AHB5LPENSETR register fields */
+#define RCC_MP_AHB5LPENSETR_GPIOZLPEN BIT(0)
+#define RCC_MP_AHB5LPENSETR_CRYP1LPEN BIT(4)
+#define RCC_MP_AHB5LPENSETR_HASH1LPEN BIT(5)
+#define RCC_MP_AHB5LPENSETR_RNG1LPEN BIT(6)
+#define RCC_MP_AHB5LPENSETR_BKPSRAMLPEN BIT(8)
+
+/* RCC_MP_AHB5LPENCLRR register fields */
+#define RCC_MP_AHB5LPENCLRR_GPIOZLPEN BIT(0)
+#define RCC_MP_AHB5LPENCLRR_CRYP1LPEN BIT(4)
+#define RCC_MP_AHB5LPENCLRR_HASH1LPEN BIT(5)
+#define RCC_MP_AHB5LPENCLRR_RNG1LPEN BIT(6)
+#define RCC_MP_AHB5LPENCLRR_BKPSRAMLPEN BIT(8)
+
+/* RCC_MP_AHB6LPENSETR register fields */
+#define RCC_MP_AHB6LPENSETR_MDMALPEN BIT(0)
+#define RCC_MP_AHB6LPENSETR_GPULPEN BIT(5)
+#define RCC_MP_AHB6LPENSETR_ETHCKLPEN BIT(7)
+#define RCC_MP_AHB6LPENSETR_ETHTXLPEN BIT(8)
+#define RCC_MP_AHB6LPENSETR_ETHRXLPEN BIT(9)
+#define RCC_MP_AHB6LPENSETR_ETHMACLPEN BIT(10)
+#define RCC_MP_AHB6LPENSETR_ETHSTPEN BIT(11)
+#define RCC_MP_AHB6LPENSETR_FMCLPEN BIT(12)
+#define RCC_MP_AHB6LPENSETR_QSPILPEN BIT(14)
+#define RCC_MP_AHB6LPENSETR_SDMMC1LPEN BIT(16)
+#define RCC_MP_AHB6LPENSETR_SDMMC2LPEN BIT(17)
+#define RCC_MP_AHB6LPENSETR_CRC1LPEN BIT(20)
+#define RCC_MP_AHB6LPENSETR_USBHLPEN BIT(24)
+
+/* RCC_MP_AHB6LPENCLRR register fields */
+#define RCC_MP_AHB6LPENCLRR_MDMALPEN BIT(0)
+#define RCC_MP_AHB6LPENCLRR_GPULPEN BIT(5)
+#define RCC_MP_AHB6LPENCLRR_ETHCKLPEN BIT(7)
+#define RCC_MP_AHB6LPENCLRR_ETHTXLPEN BIT(8)
+#define RCC_MP_AHB6LPENCLRR_ETHRXLPEN BIT(9)
+#define RCC_MP_AHB6LPENCLRR_ETHMACLPEN BIT(10)
+#define RCC_MP_AHB6LPENCLRR_ETHSTPEN BIT(11)
+#define RCC_MP_AHB6LPENCLRR_FMCLPEN BIT(12)
+#define RCC_MP_AHB6LPENCLRR_QSPILPEN BIT(14)
+#define RCC_MP_AHB6LPENCLRR_SDMMC1LPEN BIT(16)
+#define RCC_MP_AHB6LPENCLRR_SDMMC2LPEN BIT(17)
+#define RCC_MP_AHB6LPENCLRR_CRC1LPEN BIT(20)
+#define RCC_MP_AHB6LPENCLRR_USBHLPEN BIT(24)
+
+/* RCC_MP_TZAHB6LPENSETR register fields */
+#define RCC_MP_TZAHB6LPENSETR_MDMALPEN BIT(0)
+
+/* RCC_MP_TZAHB6LPENCLRR register fields */
+#define RCC_MP_TZAHB6LPENCLRR_MDMALPEN BIT(0)
+
+/* RCC_MC_APB4LPENSETR register fields */
+#define RCC_MC_APB4LPENSETR_LTDCLPEN BIT(0)
+#define RCC_MC_APB4LPENSETR_DSILPEN BIT(4)
+#define RCC_MC_APB4LPENSETR_DDRPERFMLPEN BIT(8)
+#define RCC_MC_APB4LPENSETR_USBPHYLPEN BIT(16)
+#define RCC_MC_APB4LPENSETR_STGENROLPEN BIT(20)
+#define RCC_MC_APB4LPENSETR_STGENROSTPEN BIT(21)
+
+/* RCC_MC_APB4LPENCLRR register fields */
+#define RCC_MC_APB4LPENCLRR_LTDCLPEN BIT(0)
+#define RCC_MC_APB4LPENCLRR_DSILPEN BIT(4)
+#define RCC_MC_APB4LPENCLRR_DDRPERFMLPEN BIT(8)
+#define RCC_MC_APB4LPENCLRR_USBPHYLPEN BIT(16)
+#define RCC_MC_APB4LPENCLRR_STGENROLPEN BIT(20)
+#define RCC_MC_APB4LPENCLRR_STGENROSTPEN BIT(21)
+
+/* RCC_MC_APB5LPENSETR register fields */
+#define RCC_MC_APB5LPENSETR_SPI6LPEN BIT(0)
+#define RCC_MC_APB5LPENSETR_I2C4LPEN BIT(2)
+#define RCC_MC_APB5LPENSETR_I2C6LPEN BIT(3)
+#define RCC_MC_APB5LPENSETR_USART1LPEN BIT(4)
+#define RCC_MC_APB5LPENSETR_RTCAPBLPEN BIT(8)
+#define RCC_MC_APB5LPENSETR_TZC1LPEN BIT(11)
+#define RCC_MC_APB5LPENSETR_TZC2LPEN BIT(12)
+#define RCC_MC_APB5LPENSETR_TZPCLPEN BIT(13)
+#define RCC_MC_APB5LPENSETR_BSECLPEN BIT(16)
+#define RCC_MC_APB5LPENSETR_STGENLPEN BIT(20)
+#define RCC_MC_APB5LPENSETR_STGENSTPEN BIT(21)
+
+/* RCC_MC_APB5LPENCLRR register fields */
+#define RCC_MC_APB5LPENCLRR_SPI6LPEN BIT(0)
+#define RCC_MC_APB5LPENCLRR_I2C4LPEN BIT(2)
+#define RCC_MC_APB5LPENCLRR_I2C6LPEN BIT(3)
+#define RCC_MC_APB5LPENCLRR_USART1LPEN BIT(4)
+#define RCC_MC_APB5LPENCLRR_RTCAPBLPEN BIT(8)
+#define RCC_MC_APB5LPENCLRR_TZC1LPEN BIT(11)
+#define RCC_MC_APB5LPENCLRR_TZC2LPEN BIT(12)
+#define RCC_MC_APB5LPENCLRR_TZPCLPEN BIT(13)
+#define RCC_MC_APB5LPENCLRR_BSECLPEN BIT(16)
+#define RCC_MC_APB5LPENCLRR_STGENLPEN BIT(20)
+#define RCC_MC_APB5LPENCLRR_STGENSTPEN BIT(21)
+
+/* RCC_MC_AHB5LPENSETR register fields */
+#define RCC_MC_AHB5LPENSETR_GPIOZLPEN BIT(0)
+#define RCC_MC_AHB5LPENSETR_CRYP1LPEN BIT(4)
+#define RCC_MC_AHB5LPENSETR_HASH1LPEN BIT(5)
+#define RCC_MC_AHB5LPENSETR_RNG1LPEN BIT(6)
+#define RCC_MC_AHB5LPENSETR_BKPSRAMLPEN BIT(8)
+
+/* RCC_MC_AHB5LPENCLRR register fields */
+#define RCC_MC_AHB5LPENCLRR_GPIOZLPEN BIT(0)
+#define RCC_MC_AHB5LPENCLRR_CRYP1LPEN BIT(4)
+#define RCC_MC_AHB5LPENCLRR_HASH1LPEN BIT(5)
+#define RCC_MC_AHB5LPENCLRR_RNG1LPEN BIT(6)
+#define RCC_MC_AHB5LPENCLRR_BKPSRAMLPEN BIT(8)
+
+/* RCC_MC_AHB6LPENSETR register fields */
+#define RCC_MC_AHB6LPENSETR_MDMALPEN BIT(0)
+#define RCC_MC_AHB6LPENSETR_GPULPEN BIT(5)
+#define RCC_MC_AHB6LPENSETR_ETHCKLPEN BIT(7)
+#define RCC_MC_AHB6LPENSETR_ETHTXLPEN BIT(8)
+#define RCC_MC_AHB6LPENSETR_ETHRXLPEN BIT(9)
+#define RCC_MC_AHB6LPENSETR_ETHMACLPEN BIT(10)
+#define RCC_MC_AHB6LPENSETR_ETHSTPEN BIT(11)
+#define RCC_MC_AHB6LPENSETR_FMCLPEN BIT(12)
+#define RCC_MC_AHB6LPENSETR_QSPILPEN BIT(14)
+#define RCC_MC_AHB6LPENSETR_SDMMC1LPEN BIT(16)
+#define RCC_MC_AHB6LPENSETR_SDMMC2LPEN BIT(17)
+#define RCC_MC_AHB6LPENSETR_CRC1LPEN BIT(20)
+#define RCC_MC_AHB6LPENSETR_USBHLPEN BIT(24)
+
+/* RCC_MC_AHB6LPENCLRR register fields */
+#define RCC_MC_AHB6LPENCLRR_MDMALPEN BIT(0)
+#define RCC_MC_AHB6LPENCLRR_GPULPEN BIT(5)
+#define RCC_MC_AHB6LPENCLRR_ETHCKLPEN BIT(7)
+#define RCC_MC_AHB6LPENCLRR_ETHTXLPEN BIT(8)
+#define RCC_MC_AHB6LPENCLRR_ETHRXLPEN BIT(9)
+#define RCC_MC_AHB6LPENCLRR_ETHMACLPEN BIT(10)
+#define RCC_MC_AHB6LPENCLRR_ETHSTPEN BIT(11)
+#define RCC_MC_AHB6LPENCLRR_FMCLPEN BIT(12)
+#define RCC_MC_AHB6LPENCLRR_QSPILPEN BIT(14)
+#define RCC_MC_AHB6LPENCLRR_SDMMC1LPEN BIT(16)
+#define RCC_MC_AHB6LPENCLRR_SDMMC2LPEN BIT(17)
+#define RCC_MC_AHB6LPENCLRR_CRC1LPEN BIT(20)
+#define RCC_MC_AHB6LPENCLRR_USBHLPEN BIT(24)
+
+/* RCC_BR_RSTSCLRR register fields */
+#define RCC_BR_RSTSCLRR_PORRSTF BIT(0)
+#define RCC_BR_RSTSCLRR_BORRSTF BIT(1)
+#define RCC_BR_RSTSCLRR_PADRSTF BIT(2)
+#define RCC_BR_RSTSCLRR_HCSSRSTF BIT(3)
+#define RCC_BR_RSTSCLRR_VCORERSTF BIT(4)
+#define RCC_BR_RSTSCLRR_MPSYSRSTF BIT(6)
+#define RCC_BR_RSTSCLRR_MCSYSRSTF BIT(7)
+#define RCC_BR_RSTSCLRR_IWDG1RSTF BIT(8)
+#define RCC_BR_RSTSCLRR_IWDG2RSTF BIT(9)
+#define RCC_BR_RSTSCLRR_MPUP0RSTF BIT(13)
+#define RCC_BR_RSTSCLRR_MPUP1RSTF BIT(14)
+
+/* RCC_MP_GRSTCSETR register fields */
+#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)
+
+/* RCC_MP_RSTSCLRR register fields */
+#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)
+#define RCC_MP_RSTSCLRR_SPARE BIT(15)
+
+/* RCC_MP_IWDGFZSETR register fields */
+#define RCC_MP_IWDGFZSETR_FZ_IWDG1 BIT(0)
+#define RCC_MP_IWDGFZSETR_FZ_IWDG2 BIT(1)
+
+/* RCC_MP_IWDGFZCLRR register fields */
+#define RCC_MP_IWDGFZCLRR_FZ_IWDG1 BIT(0)
+#define RCC_MP_IWDGFZCLRR_FZ_IWDG2 BIT(1)
+
+/* RCC_MP_CIER register fields */
+#define RCC_MP_CIER_LSIRDYIE BIT(0)
+#define RCC_MP_CIER_LSERDYIE BIT(1)
+#define RCC_MP_CIER_HSIRDYIE BIT(2)
+#define RCC_MP_CIER_HSERDYIE BIT(3)
+#define RCC_MP_CIER_CSIRDYIE BIT(4)
+#define RCC_MP_CIER_PLL1DYIE BIT(8)
+#define RCC_MP_CIER_PLL2DYIE BIT(9)
+#define RCC_MP_CIER_PLL3DYIE BIT(10)
+#define RCC_MP_CIER_PLL4DYIE BIT(11)
+#define RCC_MP_CIER_LSECSSIE BIT(16)
+#define RCC_MP_CIER_WKUPIE BIT(20)
+
+/* RCC_MP_CIFR register fields */
+#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_LSECSSF BIT(16)
+#define RCC_MP_CIFR_WKUPF BIT(20)
+
+/* RCC_PWRLPDLYCR register fields */
+#define RCC_PWRLPDLYCR_PWRLP_DLY_MASK GENMASK(21, 0)
+#define RCC_PWRLPDLYCR_PWRLP_DLY_SHIFT 0
+#define RCC_PWRLPDLYCR_MCTMPSKP BIT(24)
+
+/* RCC_MP_RSTSSETR register fields */
+#define RCC_MP_RSTSSETR_PORRSTF BIT(0)
+#define RCC_MP_RSTSSETR_BORRSTF BIT(1)
+#define RCC_MP_RSTSSETR_PADRSTF BIT(2)
+#define RCC_MP_RSTSSETR_HCSSRSTF BIT(3)
+#define RCC_MP_RSTSSETR_VCORERSTF BIT(4)
+#define RCC_MP_RSTSSETR_MPSYSRSTF BIT(6)
+#define RCC_MP_RSTSSETR_MCSYSRSTF BIT(7)
+#define RCC_MP_RSTSSETR_IWDG1RSTF BIT(8)
+#define RCC_MP_RSTSSETR_IWDG2RSTF BIT(9)
+#define RCC_MP_RSTSSETR_STDBYRSTF BIT(11)
+#define RCC_MP_RSTSSETR_CSTDBYRSTF BIT(12)
+#define RCC_MP_RSTSSETR_MPUP0RSTF BIT(13)
+#define RCC_MP_RSTSSETR_MPUP1RSTF BIT(14)
+#define RCC_MP_RSTSSETR_SPARE BIT(15)
+
+/* RCC_MCO1CFGR register fields */
+#define RCC_MCO1CFGR_MCO1SEL_MASK GENMASK(2, 0)
+#define RCC_MCO1CFGR_MCO1SEL_SHIFT 0
+#define RCC_MCO1CFGR_MCO1DIV_MASK GENMASK(7, 4)
+#define RCC_MCO1CFGR_MCO1DIV_SHIFT 4
+#define RCC_MCO1CFGR_MCO1ON BIT(12)
+
+/* RCC_MCO2CFGR register fields */
+#define RCC_MCO2CFGR_MCO2SEL_MASK GENMASK(2, 0)
+#define RCC_MCO2CFGR_MCO2SEL_SHIFT 0
+#define RCC_MCO2CFGR_MCO2DIV_MASK GENMASK(7, 4)
+#define RCC_MCO2CFGR_MCO2DIV_SHIFT 4
+#define RCC_MCO2CFGR_MCO2ON BIT(12)
+
+/* RCC_OCRDYR register fields */
+#define RCC_OCRDYR_HSIRDY BIT(0)
+#define RCC_OCRDYR_HSIDIVRDY BIT(2)
+#define RCC_OCRDYR_CSIRDY BIT(4)
+#define RCC_OCRDYR_HSERDY BIT(8)
+#define RCC_OCRDYR_MPUCKRDY BIT(23)
+#define RCC_OCRDYR_AXICKRDY BIT(24)
+#define RCC_OCRDYR_CKREST BIT(25)
+
+/* RCC_DBGCFGR register fields */
+#define RCC_DBGCFGR_TRACEDIV_MASK GENMASK(2, 0)
+#define RCC_DBGCFGR_TRACEDIV_SHIFT 0
+#define RCC_DBGCFGR_DBGCKEN BIT(8)
+#define RCC_DBGCFGR_TRACECKEN BIT(9)
+#define RCC_DBGCFGR_DBGRST BIT(12)
+
+/* RCC_RCK3SELR register fields */
+#define RCC_RCK3SELR_PLL3SRC_MASK GENMASK(1, 0)
+#define RCC_RCK3SELR_PLL3SRC_SHIFT 0
+#define RCC_RCK3SELR_PLL3SRCRDY BIT(31)
+
+/* RCC_RCK4SELR register fields */
+#define RCC_RCK4SELR_PLL4SRC_MASK GENMASK(1, 0)
+#define RCC_RCK4SELR_PLL4SRC_SHIFT 0
+#define RCC_RCK4SELR_PLL4SRCRDY BIT(31)
+
+/* RCC_TIMG1PRER register fields */
+#define RCC_TIMG1PRER_TIMG1PRE BIT(0)
+#define RCC_TIMG1PRER_TIMG1PRERDY BIT(31)
+
+/* RCC_TIMG2PRER register fields */
+#define RCC_TIMG2PRER_TIMG2PRE BIT(0)
+#define RCC_TIMG2PRER_TIMG2PRERDY BIT(31)
+
+/* RCC_MCUDIVR register fields */
+#define RCC_MCUDIVR_MCUDIV_MASK GENMASK(3, 0)
+#define RCC_MCUDIVR_MCUDIV_SHIFT 0
+#define RCC_MCUDIVR_MCUDIVRDY BIT(31)
+
+/* RCC_APB1DIVR register fields */
+#define RCC_APB1DIVR_APB1DIV_MASK GENMASK(2, 0)
+#define RCC_APB1DIVR_APB1DIV_SHIFT 0
+#define RCC_APB1DIVR_APB1DIVRDY BIT(31)
+
+/* RCC_APB2DIVR register fields */
+#define RCC_APB2DIVR_APB2DIV_MASK GENMASK(2, 0)
+#define RCC_APB2DIVR_APB2DIV_SHIFT 0
+#define RCC_APB2DIVR_APB2DIVRDY BIT(31)
+
+/* RCC_APB3DIVR register fields */
+#define RCC_APB3DIVR_APB3DIV_MASK GENMASK(2, 0)
+#define RCC_APB3DIVR_APB3DIV_SHIFT 0
+#define RCC_APB3DIVR_APB3DIVRDY BIT(31)
+
+/* RCC_PLL3CR register fields */
+#define RCC_PLL3CR_PLLON BIT(0)
+#define RCC_PLL3CR_PLL3RDY BIT(1)
+#define RCC_PLL3CR_SSCG_CTRL BIT(2)
+#define RCC_PLL3CR_DIVPEN BIT(4)
+#define RCC_PLL3CR_DIVQEN BIT(5)
+#define RCC_PLL3CR_DIVREN BIT(6)
+
+/* RCC_PLL3CFGR1 register fields */
+#define RCC_PLL3CFGR1_DIVN_MASK GENMASK(8, 0)
+#define RCC_PLL3CFGR1_DIVN_SHIFT 0
+#define RCC_PLL3CFGR1_DIVM3_MASK GENMASK(21, 16)
+#define RCC_PLL3CFGR1_DIVM3_SHIFT 16
+#define RCC_PLL3CFGR1_IFRGE_MASK GENMASK(25, 24)
+#define RCC_PLL3CFGR1_IFRGE_SHIFT 24
+
+/* RCC_PLL3CFGR2 register fields */
+#define RCC_PLL3CFGR2_DIVP_MASK GENMASK(6, 0)
+#define RCC_PLL3CFGR2_DIVP_SHIFT 0
+#define RCC_PLL3CFGR2_DIVQ_MASK GENMASK(14, 8)
+#define RCC_PLL3CFGR2_DIVQ_SHIFT 8
+#define RCC_PLL3CFGR2_DIVR_MASK GENMASK(22, 16)
+#define RCC_PLL3CFGR2_DIVR_SHIFT 16
+
+/* RCC_PLL3FRACR register fields */
+#define RCC_PLL3FRACR_FRACV_MASK GENMASK(15, 3)
+#define RCC_PLL3FRACR_FRACV_SHIFT 3
+#define RCC_PLL3FRACR_FRACLE BIT(16)
+
+/* RCC_PLL3CSGR register fields */
+#define RCC_PLL3CSGR_MOD_PER_MASK GENMASK(12, 0)
+#define RCC_PLL3CSGR_MOD_PER_SHIFT 0
+#define RCC_PLL3CSGR_TPDFN_DIS BIT(13)
+#define RCC_PLL3CSGR_RPDFN_DIS BIT(14)
+#define RCC_PLL3CSGR_SSCG_MODE BIT(15)
+#define RCC_PLL3CSGR_INC_STEP_MASK GENMASK(30, 16)
+#define RCC_PLL3CSGR_INC_STEP_SHIFT 16
+
+/* RCC_PLL4CR register fields */
+#define RCC_PLL4CR_PLLON BIT(0)
+#define RCC_PLL4CR_PLL4RDY BIT(1)
+#define RCC_PLL4CR_SSCG_CTRL BIT(2)
+#define RCC_PLL4CR_DIVPEN BIT(4)
+#define RCC_PLL4CR_DIVQEN BIT(5)
+#define RCC_PLL4CR_DIVREN BIT(6)
+
+/* RCC_PLL4CFGR1 register fields */
+#define RCC_PLL4CFGR1_DIVN_MASK GENMASK(8, 0)
+#define RCC_PLL4CFGR1_DIVN_SHIFT 0
+#define RCC_PLL4CFGR1_DIVM4_MASK GENMASK(21, 16)
+#define RCC_PLL4CFGR1_DIVM4_SHIFT 16
+#define RCC_PLL4CFGR1_IFRGE_MASK GENMASK(25, 24)
+#define RCC_PLL4CFGR1_IFRGE_SHIFT 24
+
+/* RCC_PLL4CFGR2 register fields */
+#define RCC_PLL4CFGR2_DIVP_MASK GENMASK(6, 0)
+#define RCC_PLL4CFGR2_DIVP_SHIFT 0
+#define RCC_PLL4CFGR2_DIVQ_MASK GENMASK(14, 8)
+#define RCC_PLL4CFGR2_DIVQ_SHIFT 8
+#define RCC_PLL4CFGR2_DIVR_MASK GENMASK(22, 16)
+#define RCC_PLL4CFGR2_DIVR_SHIFT 16
+
+/* RCC_PLL4FRACR register fields */
+#define RCC_PLL4FRACR_FRACV_MASK GENMASK(15, 3)
+#define RCC_PLL4FRACR_FRACV_SHIFT 3
+#define RCC_PLL4FRACR_FRACLE BIT(16)
+
+/* RCC_PLL4CSGR register fields */
+#define RCC_PLL4CSGR_MOD_PER_MASK GENMASK(12, 0)
+#define RCC_PLL4CSGR_MOD_PER_SHIFT 0
+#define RCC_PLL4CSGR_TPDFN_DIS BIT(13)
+#define RCC_PLL4CSGR_RPDFN_DIS BIT(14)
+#define RCC_PLL4CSGR_SSCG_MODE BIT(15)
+#define RCC_PLL4CSGR_INC_STEP_MASK GENMASK(30, 16)
+#define RCC_PLL4CSGR_INC_STEP_SHIFT 16
+
+/* 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_SAI1CKSELR register fields */
+#define RCC_SAI1CKSELR_SAI1SRC_MASK GENMASK(2, 0)
+#define RCC_SAI1CKSELR_SAI1SRC_SHIFT 0
+
+/* RCC_SAI2CKSELR register fields */
+#define RCC_SAI2CKSELR_SAI2SRC_MASK GENMASK(2, 0)
+#define RCC_SAI2CKSELR_SAI2SRC_SHIFT 0
+
+/* RCC_SAI3CKSELR register fields */
+#define RCC_SAI3CKSELR_SAI3SRC_MASK GENMASK(2, 0)
+#define RCC_SAI3CKSELR_SAI3SRC_SHIFT 0
+
+/* RCC_SAI4CKSELR register fields */
+#define RCC_SAI4CKSELR_SAI4SRC_MASK GENMASK(2, 0)
+#define RCC_SAI4CKSELR_SAI4SRC_SHIFT 0
+
+/* RCC_SPI2S1CKSELR register fields */
+#define RCC_SPI2S1CKSELR_SPI1SRC_MASK GENMASK(2, 0)
+#define RCC_SPI2S1CKSELR_SPI1SRC_SHIFT 0
+
+/* RCC_SPI2S23CKSELR register fields */
+#define RCC_SPI2S23CKSELR_SPI23SRC_MASK GENMASK(2, 0)
+#define RCC_SPI2S23CKSELR_SPI23SRC_SHIFT 0
+
+/* RCC_SPI45CKSELR register fields */
+#define RCC_SPI45CKSELR_SPI45SRC_MASK GENMASK(2, 0)
+#define RCC_SPI45CKSELR_SPI45SRC_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_HSI 0x00000002
+#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
+#define RCC_ETHCKSELR_ETHPTPDIV_MASK GENMASK(7, 4)
+#define RCC_ETHCKSELR_ETHPTPDIV_SHIFT 4
+
+/* 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_FDCANCKSELR register fields */
+#define RCC_FDCANCKSELR_FDCANSRC_MASK GENMASK(1, 0)
+#define RCC_FDCANCKSELR_FDCANSRC_SHIFT 0
+
+/* RCC_SPDIFCKSELR register fields */
+#define RCC_SPDIFCKSELR_SPDIFSRC_MASK GENMASK(1, 0)
+#define RCC_SPDIFCKSELR_SPDIFSRC_SHIFT 0
+
+/* RCC_CECCKSELR register fields */
+#define RCC_CECCKSELR_CECSRC_MASK GENMASK(1, 0)
+#define RCC_CECCKSELR_CECSRC_SHIFT 0
+
+/* RCC_USBCKSELR register fields */
+#define RCC_USBCKSELR_USBPHYSRC_MASK GENMASK(1, 0)
+#define RCC_USBCKSELR_USBPHYSRC_SHIFT 0
+#define RCC_USBCKSELR_USBOSRC BIT(4)
+#define RCC_USBCKSELR_USBOSRC_MASK BIT(4)
+#define RCC_USBCKSELR_USBOSRC_SHIFT 4
+
+/* RCC_RNG2CKSELR register fields */
+#define RCC_RNG2CKSELR_RNG2SRC_MASK GENMASK(1, 0)
+#define RCC_RNG2CKSELR_RNG2SRC_SHIFT 0
+
+/* RCC_DSICKSELR register fields */
+#define RCC_DSICKSELR_DSISRC BIT(0)
+
+/* RCC_ADCCKSELR register fields */
+#define RCC_ADCCKSELR_ADCSRC_MASK GENMASK(1, 0)
+#define RCC_ADCCKSELR_ADCSRC_SHIFT 0
+
+/* RCC_LPTIM45CKSELR register fields */
+#define RCC_LPTIM45CKSELR_LPTIM45SRC_MASK GENMASK(2, 0)
+#define RCC_LPTIM45CKSELR_LPTIM45SRC_SHIFT 0
+
+/* RCC_LPTIM23CKSELR register fields */
+#define RCC_LPTIM23CKSELR_LPTIM23SRC_MASK GENMASK(2, 0)
+#define RCC_LPTIM23CKSELR_LPTIM23SRC_SHIFT 0
+
+/* RCC_LPTIM1CKSELR register fields */
+#define RCC_LPTIM1CKSELR_LPTIM1SRC_MASK GENMASK(2, 0)
+#define RCC_LPTIM1CKSELR_LPTIM1SRC_SHIFT 0
+
+/* RCC_APB1RSTSETR register fields */
+#define RCC_APB1RSTSETR_TIM2RST BIT(0)
+#define RCC_APB1RSTSETR_TIM3RST BIT(1)
+#define RCC_APB1RSTSETR_TIM4RST BIT(2)
+#define RCC_APB1RSTSETR_TIM5RST BIT(3)
+#define RCC_APB1RSTSETR_TIM6RST BIT(4)
+#define RCC_APB1RSTSETR_TIM7RST BIT(5)
+#define RCC_APB1RSTSETR_TIM12RST BIT(6)
+#define RCC_APB1RSTSETR_TIM13RST BIT(7)
+#define RCC_APB1RSTSETR_TIM14RST BIT(8)
+#define RCC_APB1RSTSETR_LPTIM1RST BIT(9)
+#define RCC_APB1RSTSETR_SPI2RST BIT(11)
+#define RCC_APB1RSTSETR_SPI3RST BIT(12)
+#define RCC_APB1RSTSETR_USART2RST BIT(14)
+#define RCC_APB1RSTSETR_USART3RST BIT(15)
+#define RCC_APB1RSTSETR_UART4RST BIT(16)
+#define RCC_APB1RSTSETR_UART5RST BIT(17)
+#define RCC_APB1RSTSETR_UART7RST BIT(18)
+#define RCC_APB1RSTSETR_UART8RST BIT(19)
+#define RCC_APB1RSTSETR_I2C1RST BIT(21)
+#define RCC_APB1RSTSETR_I2C2RST BIT(22)
+#define RCC_APB1RSTSETR_I2C3RST BIT(23)
+#define RCC_APB1RSTSETR_I2C5RST BIT(24)
+#define RCC_APB1RSTSETR_SPDIFRST BIT(26)
+#define RCC_APB1RSTSETR_CECRST BIT(27)
+#define RCC_APB1RSTSETR_DAC12RST BIT(29)
+#define RCC_APB1RSTSETR_MDIOSRST BIT(31)
+
+/* RCC_APB1RSTCLRR register fields */
+#define RCC_APB1RSTCLRR_TIM2RST BIT(0)
+#define RCC_APB1RSTCLRR_TIM3RST BIT(1)
+#define RCC_APB1RSTCLRR_TIM4RST BIT(2)
+#define RCC_APB1RSTCLRR_TIM5RST BIT(3)
+#define RCC_APB1RSTCLRR_TIM6RST BIT(4)
+#define RCC_APB1RSTCLRR_TIM7RST BIT(5)
+#define RCC_APB1RSTCLRR_TIM12RST BIT(6)
+#define RCC_APB1RSTCLRR_TIM13RST BIT(7)
+#define RCC_APB1RSTCLRR_TIM14RST BIT(8)
+#define RCC_APB1RSTCLRR_LPTIM1RST BIT(9)
+#define RCC_APB1RSTCLRR_SPI2RST BIT(11)
+#define RCC_APB1RSTCLRR_SPI3RST BIT(12)
+#define RCC_APB1RSTCLRR_USART2RST BIT(14)
+#define RCC_APB1RSTCLRR_USART3RST BIT(15)
+#define RCC_APB1RSTCLRR_UART4RST BIT(16)
+#define RCC_APB1RSTCLRR_UART5RST BIT(17)
+#define RCC_APB1RSTCLRR_UART7RST BIT(18)
+#define RCC_APB1RSTCLRR_UART8RST BIT(19)
+#define RCC_APB1RSTCLRR_I2C1RST BIT(21)
+#define RCC_APB1RSTCLRR_I2C2RST BIT(22)
+#define RCC_APB1RSTCLRR_I2C3RST BIT(23)
+#define RCC_APB1RSTCLRR_I2C5RST BIT(24)
+#define RCC_APB1RSTCLRR_SPDIFRST BIT(26)
+#define RCC_APB1RSTCLRR_CECRST BIT(27)
+#define RCC_APB1RSTCLRR_DAC12RST BIT(29)
+#define RCC_APB1RSTCLRR_MDIOSRST BIT(31)
+
+/* RCC_APB2RSTSETR register fields */
+#define RCC_APB2RSTSETR_TIM1RST BIT(0)
+#define RCC_APB2RSTSETR_TIM8RST BIT(1)
+#define RCC_APB2RSTSETR_TIM15RST BIT(2)
+#define RCC_APB2RSTSETR_TIM16RST BIT(3)
+#define RCC_APB2RSTSETR_TIM17RST BIT(4)
+#define RCC_APB2RSTSETR_SPI1RST BIT(8)
+#define RCC_APB2RSTSETR_SPI4RST BIT(9)
+#define RCC_APB2RSTSETR_SPI5RST BIT(10)
+#define RCC_APB2RSTSETR_USART6RST BIT(13)
+#define RCC_APB2RSTSETR_SAI1RST BIT(16)
+#define RCC_APB2RSTSETR_SAI2RST BIT(17)
+#define RCC_APB2RSTSETR_SAI3RST BIT(18)
+#define RCC_APB2RSTSETR_DFSDMRST BIT(20)
+#define RCC_APB2RSTSETR_FDCANRST BIT(24)
+
+/* RCC_APB2RSTCLRR register fields */
+#define RCC_APB2RSTCLRR_TIM1RST BIT(0)
+#define RCC_APB2RSTCLRR_TIM8RST BIT(1)
+#define RCC_APB2RSTCLRR_TIM15RST BIT(2)
+#define RCC_APB2RSTCLRR_TIM16RST BIT(3)
+#define RCC_APB2RSTCLRR_TIM17RST BIT(4)
+#define RCC_APB2RSTCLRR_SPI1RST BIT(8)
+#define RCC_APB2RSTCLRR_SPI4RST BIT(9)
+#define RCC_APB2RSTCLRR_SPI5RST BIT(10)
+#define RCC_APB2RSTCLRR_USART6RST BIT(13)
+#define RCC_APB2RSTCLRR_SAI1RST BIT(16)
+#define RCC_APB2RSTCLRR_SAI2RST BIT(17)
+#define RCC_APB2RSTCLRR_SAI3RST BIT(18)
+#define RCC_APB2RSTCLRR_DFSDMRST BIT(20)
+#define RCC_APB2RSTCLRR_FDCANRST BIT(24)
+
+/* RCC_APB3RSTSETR register fields */
+#define RCC_APB3RSTSETR_LPTIM2RST BIT(0)
+#define RCC_APB3RSTSETR_LPTIM3RST BIT(1)
+#define RCC_APB3RSTSETR_LPTIM4RST BIT(2)
+#define RCC_APB3RSTSETR_LPTIM5RST BIT(3)
+#define RCC_APB3RSTSETR_SAI4RST BIT(8)
+#define RCC_APB3RSTSETR_SYSCFGRST BIT(11)
+#define RCC_APB3RSTSETR_VREFRST BIT(13)
+#define RCC_APB3RSTSETR_TMPSENSRST BIT(16)
+#define RCC_APB3RSTSETR_PMBCTRLRST BIT(17)
+
+/* RCC_APB3RSTCLRR register fields */
+#define RCC_APB3RSTCLRR_LPTIM2RST BIT(0)
+#define RCC_APB3RSTCLRR_LPTIM3RST BIT(1)
+#define RCC_APB3RSTCLRR_LPTIM4RST BIT(2)
+#define RCC_APB3RSTCLRR_LPTIM5RST BIT(3)
+#define RCC_APB3RSTCLRR_SAI4RST BIT(8)
+#define RCC_APB3RSTCLRR_SYSCFGRST BIT(11)
+#define RCC_APB3RSTCLRR_VREFRST BIT(13)
+#define RCC_APB3RSTCLRR_TMPSENSRST BIT(16)
+#define RCC_APB3RSTCLRR_PMBCTRLRST BIT(17)
+
+/* RCC_AHB2RSTSETR register fields */
+#define RCC_AHB2RSTSETR_DMA1RST BIT(0)
+#define RCC_AHB2RSTSETR_DMA2RST BIT(1)
+#define RCC_AHB2RSTSETR_DMAMUXRST BIT(2)
+#define RCC_AHB2RSTSETR_ADC12RST BIT(5)
+#define RCC_AHB2RSTSETR_USBORST BIT(8)
+#define RCC_AHB2RSTSETR_SDMMC3RST BIT(16)
+
+/* RCC_AHB2RSTCLRR register fields */
+#define RCC_AHB2RSTCLRR_DMA1RST BIT(0)
+#define RCC_AHB2RSTCLRR_DMA2RST BIT(1)
+#define RCC_AHB2RSTCLRR_DMAMUXRST BIT(2)
+#define RCC_AHB2RSTCLRR_ADC12RST BIT(5)
+#define RCC_AHB2RSTCLRR_USBORST BIT(8)
+#define RCC_AHB2RSTCLRR_SDMMC3RST BIT(16)
+
+/* RCC_AHB3RSTSETR register fields */
+#define RCC_AHB3RSTSETR_DCMIRST BIT(0)
+#define RCC_AHB3RSTSETR_CRYP2RST BIT(4)
+#define RCC_AHB3RSTSETR_HASH2RST BIT(5)
+#define RCC_AHB3RSTSETR_RNG2RST BIT(6)
+#define RCC_AHB3RSTSETR_CRC2RST BIT(7)
+#define RCC_AHB3RSTSETR_HSEMRST BIT(11)
+#define RCC_AHB3RSTSETR_IPCCRST BIT(12)
+
+/* RCC_AHB3RSTCLRR register fields */
+#define RCC_AHB3RSTCLRR_DCMIRST BIT(0)
+#define RCC_AHB3RSTCLRR_CRYP2RST BIT(4)
+#define RCC_AHB3RSTCLRR_HASH2RST BIT(5)
+#define RCC_AHB3RSTCLRR_RNG2RST BIT(6)
+#define RCC_AHB3RSTCLRR_CRC2RST BIT(7)
+#define RCC_AHB3RSTCLRR_HSEMRST BIT(11)
+#define RCC_AHB3RSTCLRR_IPCCRST BIT(12)
+
+/* RCC_AHB4RSTSETR register fields */
+#define RCC_AHB4RSTSETR_GPIOARST BIT(0)
+#define RCC_AHB4RSTSETR_GPIOBRST BIT(1)
+#define RCC_AHB4RSTSETR_GPIOCRST BIT(2)
+#define RCC_AHB4RSTSETR_GPIODRST BIT(3)
+#define RCC_AHB4RSTSETR_GPIOERST BIT(4)
+#define RCC_AHB4RSTSETR_GPIOFRST BIT(5)
+#define RCC_AHB4RSTSETR_GPIOGRST BIT(6)
+#define RCC_AHB4RSTSETR_GPIOHRST BIT(7)
+#define RCC_AHB4RSTSETR_GPIOIRST BIT(8)
+#define RCC_AHB4RSTSETR_GPIOJRST BIT(9)
+#define RCC_AHB4RSTSETR_GPIOKRST BIT(10)
+
+/* RCC_AHB4RSTCLRR register fields */
+#define RCC_AHB4RSTCLRR_GPIOARST BIT(0)
+#define RCC_AHB4RSTCLRR_GPIOBRST BIT(1)
+#define RCC_AHB4RSTCLRR_GPIOCRST BIT(2)
+#define RCC_AHB4RSTCLRR_GPIODRST BIT(3)
+#define RCC_AHB4RSTCLRR_GPIOERST BIT(4)
+#define RCC_AHB4RSTCLRR_GPIOFRST BIT(5)
+#define RCC_AHB4RSTCLRR_GPIOGRST BIT(6)
+#define RCC_AHB4RSTCLRR_GPIOHRST BIT(7)
+#define RCC_AHB4RSTCLRR_GPIOIRST BIT(8)
+#define RCC_AHB4RSTCLRR_GPIOJRST BIT(9)
+#define RCC_AHB4RSTCLRR_GPIOKRST BIT(10)
+
+/* RCC_MP_APB1ENSETR register fields */
+#define RCC_MP_APB1ENSETR_TIM2EN BIT(0)
+#define RCC_MP_APB1ENSETR_TIM3EN BIT(1)
+#define RCC_MP_APB1ENSETR_TIM4EN BIT(2)
+#define RCC_MP_APB1ENSETR_TIM5EN BIT(3)
+#define RCC_MP_APB1ENSETR_TIM6EN BIT(4)
+#define RCC_MP_APB1ENSETR_TIM7EN BIT(5)
+#define RCC_MP_APB1ENSETR_TIM12EN BIT(6)
+#define RCC_MP_APB1ENSETR_TIM13EN BIT(7)
+#define RCC_MP_APB1ENSETR_TIM14EN BIT(8)
+#define RCC_MP_APB1ENSETR_LPTIM1EN BIT(9)
+#define RCC_MP_APB1ENSETR_SPI2EN BIT(11)
+#define RCC_MP_APB1ENSETR_SPI3EN BIT(12)
+#define RCC_MP_APB1ENSETR_USART2EN BIT(14)
+#define RCC_MP_APB1ENSETR_USART3EN BIT(15)
+#define RCC_MP_APB1ENSETR_UART4EN BIT(16)
+#define RCC_MP_APB1ENSETR_UART5EN BIT(17)
+#define RCC_MP_APB1ENSETR_UART7EN BIT(18)
+#define RCC_MP_APB1ENSETR_UART8EN BIT(19)
+#define RCC_MP_APB1ENSETR_I2C1EN BIT(21)
+#define RCC_MP_APB1ENSETR_I2C2EN BIT(22)
+#define RCC_MP_APB1ENSETR_I2C3EN BIT(23)
+#define RCC_MP_APB1ENSETR_I2C5EN BIT(24)
+#define RCC_MP_APB1ENSETR_SPDIFEN BIT(26)
+#define RCC_MP_APB1ENSETR_CECEN BIT(27)
+#define RCC_MP_APB1ENSETR_DAC12EN BIT(29)
+#define RCC_MP_APB1ENSETR_MDIOSEN BIT(31)
+
+/* RCC_MP_APB1ENCLRR register fields */
+#define RCC_MP_APB1ENCLRR_TIM2EN BIT(0)
+#define RCC_MP_APB1ENCLRR_TIM3EN BIT(1)
+#define RCC_MP_APB1ENCLRR_TIM4EN BIT(2)
+#define RCC_MP_APB1ENCLRR_TIM5EN BIT(3)
+#define RCC_MP_APB1ENCLRR_TIM6EN BIT(4)
+#define RCC_MP_APB1ENCLRR_TIM7EN BIT(5)
+#define RCC_MP_APB1ENCLRR_TIM12EN BIT(6)
+#define RCC_MP_APB1ENCLRR_TIM13EN BIT(7)
+#define RCC_MP_APB1ENCLRR_TIM14EN BIT(8)
+#define RCC_MP_APB1ENCLRR_LPTIM1EN BIT(9)
+#define RCC_MP_APB1ENCLRR_SPI2EN BIT(11)
+#define RCC_MP_APB1ENCLRR_SPI3EN BIT(12)
+#define RCC_MP_APB1ENCLRR_USART2EN BIT(14)
+#define RCC_MP_APB1ENCLRR_USART3EN BIT(15)
+#define RCC_MP_APB1ENCLRR_UART4EN BIT(16)
+#define RCC_MP_APB1ENCLRR_UART5EN BIT(17)
+#define RCC_MP_APB1ENCLRR_UART7EN BIT(18)
+#define RCC_MP_APB1ENCLRR_UART8EN BIT(19)
+#define RCC_MP_APB1ENCLRR_I2C1EN BIT(21)
+#define RCC_MP_APB1ENCLRR_I2C2EN BIT(22)
+#define RCC_MP_APB1ENCLRR_I2C3EN BIT(23)
+#define RCC_MP_APB1ENCLRR_I2C5EN BIT(24)
+#define RCC_MP_APB1ENCLRR_SPDIFEN BIT(26)
+#define RCC_MP_APB1ENCLRR_CECEN BIT(27)
+#define RCC_MP_APB1ENCLRR_DAC12EN BIT(29)
+#define RCC_MP_APB1ENCLRR_MDIOSEN BIT(31)
+
+/* RCC_MP_APB2ENSETR register fields */
+#define RCC_MP_APB2ENSETR_TIM1EN BIT(0)
+#define RCC_MP_APB2ENSETR_TIM8EN BIT(1)
+#define RCC_MP_APB2ENSETR_TIM15EN BIT(2)
+#define RCC_MP_APB2ENSETR_TIM16EN BIT(3)
+#define RCC_MP_APB2ENSETR_TIM17EN BIT(4)
+#define RCC_MP_APB2ENSETR_SPI1EN BIT(8)
+#define RCC_MP_APB2ENSETR_SPI4EN BIT(9)
+#define RCC_MP_APB2ENSETR_SPI5EN BIT(10)
+#define RCC_MP_APB2ENSETR_USART6EN BIT(13)
+#define RCC_MP_APB2ENSETR_SAI1EN BIT(16)
+#define RCC_MP_APB2ENSETR_SAI2EN BIT(17)
+#define RCC_MP_APB2ENSETR_SAI3EN BIT(18)
+#define RCC_MP_APB2ENSETR_DFSDMEN BIT(20)
+#define RCC_MP_APB2ENSETR_ADFSDMEN BIT(21)
+#define RCC_MP_APB2ENSETR_FDCANEN BIT(24)
+
+/* RCC_MP_APB2ENCLRR register fields */
+#define RCC_MP_APB2ENCLRR_TIM1EN BIT(0)
+#define RCC_MP_APB2ENCLRR_TIM8EN BIT(1)
+#define RCC_MP_APB2ENCLRR_TIM15EN BIT(2)
+#define RCC_MP_APB2ENCLRR_TIM16EN BIT(3)
+#define RCC_MP_APB2ENCLRR_TIM17EN BIT(4)
+#define RCC_MP_APB2ENCLRR_SPI1EN BIT(8)
+#define RCC_MP_APB2ENCLRR_SPI4EN BIT(9)
+#define RCC_MP_APB2ENCLRR_SPI5EN BIT(10)
+#define RCC_MP_APB2ENCLRR_USART6EN BIT(13)
+#define RCC_MP_APB2ENCLRR_SAI1EN BIT(16)
+#define RCC_MP_APB2ENCLRR_SAI2EN BIT(17)
+#define RCC_MP_APB2ENCLRR_SAI3EN BIT(18)
+#define RCC_MP_APB2ENCLRR_DFSDMEN BIT(20)
+#define RCC_MP_APB2ENCLRR_ADFSDMEN BIT(21)
+#define RCC_MP_APB2ENCLRR_FDCANEN BIT(24)
+
+/* RCC_MP_APB3ENSETR register fields */
+#define RCC_MP_APB3ENSETR_LPTIM2EN BIT(0)
+#define RCC_MP_APB3ENSETR_LPTIM3EN BIT(1)
+#define RCC_MP_APB3ENSETR_LPTIM4EN BIT(2)
+#define RCC_MP_APB3ENSETR_LPTIM5EN BIT(3)
+#define RCC_MP_APB3ENSETR_SAI4EN BIT(8)
+#define RCC_MP_APB3ENSETR_SYSCFGEN BIT(11)
+#define RCC_MP_APB3ENSETR_VREFEN BIT(13)
+#define RCC_MP_APB3ENSETR_TMPSENSEN BIT(16)
+#define RCC_MP_APB3ENSETR_PMBCTRLEN BIT(17)
+#define RCC_MP_APB3ENSETR_HDPEN BIT(20)
+
+/* RCC_MP_APB3ENCLRR register fields */
+#define RCC_MP_APB3ENCLRR_LPTIM2EN BIT(0)
+#define RCC_MP_APB3ENCLRR_LPTIM3EN BIT(1)
+#define RCC_MP_APB3ENCLRR_LPTIM4EN BIT(2)
+#define RCC_MP_APB3ENCLRR_LPTIM5EN BIT(3)
+#define RCC_MP_APB3ENCLRR_SAI4EN BIT(8)
+#define RCC_MP_APB3ENCLRR_SYSCFGEN BIT(11)
+#define RCC_MP_APB3ENCLRR_VREFEN BIT(13)
+#define RCC_MP_APB3ENCLRR_TMPSENSEN BIT(16)
+#define RCC_MP_APB3ENCLRR_PMBCTRLEN BIT(17)
+#define RCC_MP_APB3ENCLRR_HDPEN BIT(20)
+
+/* RCC_MP_AHB2ENSETR register fields */
+#define RCC_MP_AHB2ENSETR_DMA1EN BIT(0)
+#define RCC_MP_AHB2ENSETR_DMA2EN BIT(1)
+#define RCC_MP_AHB2ENSETR_DMAMUXEN BIT(2)
+#define RCC_MP_AHB2ENSETR_ADC12EN BIT(5)
+#define RCC_MP_AHB2ENSETR_USBOEN BIT(8)
+#define RCC_MP_AHB2ENSETR_SDMMC3EN BIT(16)
+
+/* RCC_MP_AHB2ENCLRR register fields */
+#define RCC_MP_AHB2ENCLRR_DMA1EN BIT(0)
+#define RCC_MP_AHB2ENCLRR_DMA2EN BIT(1)
+#define RCC_MP_AHB2ENCLRR_DMAMUXEN BIT(2)
+#define RCC_MP_AHB2ENCLRR_ADC12EN BIT(5)
+#define RCC_MP_AHB2ENCLRR_USBOEN BIT(8)
+#define RCC_MP_AHB2ENCLRR_SDMMC3EN BIT(16)
+
+/* RCC_MP_AHB3ENSETR register fields */
+#define RCC_MP_AHB3ENSETR_DCMIEN BIT(0)
+#define RCC_MP_AHB3ENSETR_CRYP2EN BIT(4)
+#define RCC_MP_AHB3ENSETR_HASH2EN BIT(5)
+#define RCC_MP_AHB3ENSETR_RNG2EN BIT(6)
+#define RCC_MP_AHB3ENSETR_CRC2EN BIT(7)
+#define RCC_MP_AHB3ENSETR_HSEMEN BIT(11)
+#define RCC_MP_AHB3ENSETR_IPCCEN BIT(12)
+
+/* RCC_MP_AHB3ENCLRR register fields */
+#define RCC_MP_AHB3ENCLRR_DCMIEN BIT(0)
+#define RCC_MP_AHB3ENCLRR_CRYP2EN BIT(4)
+#define RCC_MP_AHB3ENCLRR_HASH2EN BIT(5)
+#define RCC_MP_AHB3ENCLRR_RNG2EN BIT(6)
+#define RCC_MP_AHB3ENCLRR_CRC2EN BIT(7)
+#define RCC_MP_AHB3ENCLRR_HSEMEN BIT(11)
+#define RCC_MP_AHB3ENCLRR_IPCCEN BIT(12)
+
+/* RCC_MP_AHB4ENSETR register fields */
+#define RCC_MP_AHB4ENSETR_GPIOAEN BIT(0)
+#define RCC_MP_AHB4ENSETR_GPIOBEN BIT(1)
+#define RCC_MP_AHB4ENSETR_GPIOCEN BIT(2)
+#define RCC_MP_AHB4ENSETR_GPIODEN BIT(3)
+#define RCC_MP_AHB4ENSETR_GPIOEEN BIT(4)
+#define RCC_MP_AHB4ENSETR_GPIOFEN BIT(5)
+#define RCC_MP_AHB4ENSETR_GPIOGEN BIT(6)
+#define RCC_MP_AHB4ENSETR_GPIOHEN BIT(7)
+#define RCC_MP_AHB4ENSETR_GPIOIEN BIT(8)
+#define RCC_MP_AHB4ENSETR_GPIOJEN BIT(9)
+#define RCC_MP_AHB4ENSETR_GPIOKEN BIT(10)
+
+/* RCC_MP_AHB4ENCLRR register fields */
+#define RCC_MP_AHB4ENCLRR_GPIOAEN BIT(0)
+#define RCC_MP_AHB4ENCLRR_GPIOBEN BIT(1)
+#define RCC_MP_AHB4ENCLRR_GPIOCEN BIT(2)
+#define RCC_MP_AHB4ENCLRR_GPIODEN BIT(3)
+#define RCC_MP_AHB4ENCLRR_GPIOEEN BIT(4)
+#define RCC_MP_AHB4ENCLRR_GPIOFEN BIT(5)
+#define RCC_MP_AHB4ENCLRR_GPIOGEN BIT(6)
+#define RCC_MP_AHB4ENCLRR_GPIOHEN BIT(7)
+#define RCC_MP_AHB4ENCLRR_GPIOIEN BIT(8)
+#define RCC_MP_AHB4ENCLRR_GPIOJEN BIT(9)
+#define RCC_MP_AHB4ENCLRR_GPIOKEN BIT(10)
+
+/* RCC_MP_MLAHBENSETR register fields */
+#define RCC_MP_MLAHBENSETR_RETRAMEN BIT(4)
+
+/* RCC_MP_MLAHBENCLRR register fields */
+#define RCC_MP_MLAHBENCLRR_RETRAMEN BIT(4)
+
+/* RCC_MC_APB1ENSETR register fields */
+#define RCC_MC_APB1ENSETR_TIM2EN BIT(0)
+#define RCC_MC_APB1ENSETR_TIM3EN BIT(1)
+#define RCC_MC_APB1ENSETR_TIM4EN BIT(2)
+#define RCC_MC_APB1ENSETR_TIM5EN BIT(3)
+#define RCC_MC_APB1ENSETR_TIM6EN BIT(4)
+#define RCC_MC_APB1ENSETR_TIM7EN BIT(5)
+#define RCC_MC_APB1ENSETR_TIM12EN BIT(6)
+#define RCC_MC_APB1ENSETR_TIM13EN BIT(7)
+#define RCC_MC_APB1ENSETR_TIM14EN BIT(8)
+#define RCC_MC_APB1ENSETR_LPTIM1EN BIT(9)
+#define RCC_MC_APB1ENSETR_SPI2EN BIT(11)
+#define RCC_MC_APB1ENSETR_SPI3EN BIT(12)
+#define RCC_MC_APB1ENSETR_USART2EN BIT(14)
+#define RCC_MC_APB1ENSETR_USART3EN BIT(15)
+#define RCC_MC_APB1ENSETR_UART4EN BIT(16)
+#define RCC_MC_APB1ENSETR_UART5EN BIT(17)
+#define RCC_MC_APB1ENSETR_UART7EN BIT(18)
+#define RCC_MC_APB1ENSETR_UART8EN BIT(19)
+#define RCC_MC_APB1ENSETR_I2C1EN BIT(21)
+#define RCC_MC_APB1ENSETR_I2C2EN BIT(22)
+#define RCC_MC_APB1ENSETR_I2C3EN BIT(23)
+#define RCC_MC_APB1ENSETR_I2C5EN BIT(24)
+#define RCC_MC_APB1ENSETR_SPDIFEN BIT(26)
+#define RCC_MC_APB1ENSETR_CECEN BIT(27)
+#define RCC_MC_APB1ENSETR_WWDG1EN BIT(28)
+#define RCC_MC_APB1ENSETR_DAC12EN BIT(29)
+#define RCC_MC_APB1ENSETR_MDIOSEN BIT(31)
+
+/* RCC_MC_APB1ENCLRR register fields */
+#define RCC_MC_APB1ENCLRR_TIM2EN BIT(0)
+#define RCC_MC_APB1ENCLRR_TIM3EN BIT(1)
+#define RCC_MC_APB1ENCLRR_TIM4EN BIT(2)
+#define RCC_MC_APB1ENCLRR_TIM5EN BIT(3)
+#define RCC_MC_APB1ENCLRR_TIM6EN BIT(4)
+#define RCC_MC_APB1ENCLRR_TIM7EN BIT(5)
+#define RCC_MC_APB1ENCLRR_TIM12EN BIT(6)
+#define RCC_MC_APB1ENCLRR_TIM13EN BIT(7)
+#define RCC_MC_APB1ENCLRR_TIM14EN BIT(8)
+#define RCC_MC_APB1ENCLRR_LPTIM1EN BIT(9)
+#define RCC_MC_APB1ENCLRR_SPI2EN BIT(11)
+#define RCC_MC_APB1ENCLRR_SPI3EN BIT(12)
+#define RCC_MC_APB1ENCLRR_USART2EN BIT(14)
+#define RCC_MC_APB1ENCLRR_USART3EN BIT(15)
+#define RCC_MC_APB1ENCLRR_UART4EN BIT(16)
+#define RCC_MC_APB1ENCLRR_UART5EN BIT(17)
+#define RCC_MC_APB1ENCLRR_UART7EN BIT(18)
+#define RCC_MC_APB1ENCLRR_UART8EN BIT(19)
+#define RCC_MC_APB1ENCLRR_I2C1EN BIT(21)
+#define RCC_MC_APB1ENCLRR_I2C2EN BIT(22)
+#define RCC_MC_APB1ENCLRR_I2C3EN BIT(23)
+#define RCC_MC_APB1ENCLRR_I2C5EN BIT(24)
+#define RCC_MC_APB1ENCLRR_SPDIFEN BIT(26)
+#define RCC_MC_APB1ENCLRR_CECEN BIT(27)
+#define RCC_MC_APB1ENCLRR_DAC12EN BIT(29)
+#define RCC_MC_APB1ENCLRR_MDIOSEN BIT(31)
+
+/* RCC_MC_APB2ENSETR register fields */
+#define RCC_MC_APB2ENSETR_TIM1EN BIT(0)
+#define RCC_MC_APB2ENSETR_TIM8EN BIT(1)
+#define RCC_MC_APB2ENSETR_TIM15EN BIT(2)
+#define RCC_MC_APB2ENSETR_TIM16EN BIT(3)
+#define RCC_MC_APB2ENSETR_TIM17EN BIT(4)
+#define RCC_MC_APB2ENSETR_SPI1EN BIT(8)
+#define RCC_MC_APB2ENSETR_SPI4EN BIT(9)
+#define RCC_MC_APB2ENSETR_SPI5EN BIT(10)
+#define RCC_MC_APB2ENSETR_USART6EN BIT(13)
+#define RCC_MC_APB2ENSETR_SAI1EN BIT(16)
+#define RCC_MC_APB2ENSETR_SAI2EN BIT(17)
+#define RCC_MC_APB2ENSETR_SAI3EN BIT(18)
+#define RCC_MC_APB2ENSETR_DFSDMEN BIT(20)
+#define RCC_MC_APB2ENSETR_ADFSDMEN BIT(21)
+#define RCC_MC_APB2ENSETR_FDCANEN BIT(24)
+
+/* RCC_MC_APB2ENCLRR register fields */
+#define RCC_MC_APB2ENCLRR_TIM1EN BIT(0)
+#define RCC_MC_APB2ENCLRR_TIM8EN BIT(1)
+#define RCC_MC_APB2ENCLRR_TIM15EN BIT(2)
+#define RCC_MC_APB2ENCLRR_TIM16EN BIT(3)
+#define RCC_MC_APB2ENCLRR_TIM17EN BIT(4)
+#define RCC_MC_APB2ENCLRR_SPI1EN BIT(8)
+#define RCC_MC_APB2ENCLRR_SPI4EN BIT(9)
+#define RCC_MC_APB2ENCLRR_SPI5EN BIT(10)
+#define RCC_MC_APB2ENCLRR_USART6EN BIT(13)
+#define RCC_MC_APB2ENCLRR_SAI1EN BIT(16)
+#define RCC_MC_APB2ENCLRR_SAI2EN BIT(17)
+#define RCC_MC_APB2ENCLRR_SAI3EN BIT(18)
+#define RCC_MC_APB2ENCLRR_DFSDMEN BIT(20)
+#define RCC_MC_APB2ENCLRR_ADFSDMEN BIT(21)
+#define RCC_MC_APB2ENCLRR_FDCANEN BIT(24)
+
+/* RCC_MC_APB3ENSETR register fields */
+#define RCC_MC_APB3ENSETR_LPTIM2EN BIT(0)
+#define RCC_MC_APB3ENSETR_LPTIM3EN BIT(1)
+#define RCC_MC_APB3ENSETR_LPTIM4EN BIT(2)
+#define RCC_MC_APB3ENSETR_LPTIM5EN BIT(3)
+#define RCC_MC_APB3ENSETR_SAI4EN BIT(8)
+#define RCC_MC_APB3ENSETR_SYSCFGEN BIT(11)
+#define RCC_MC_APB3ENSETR_VREFEN BIT(13)
+#define RCC_MC_APB3ENSETR_TMPSENSEN BIT(16)
+#define RCC_MC_APB3ENSETR_PMBCTRLEN BIT(17)
+#define RCC_MC_APB3ENSETR_HDPEN BIT(20)
+
+/* RCC_MC_APB3ENCLRR register fields */
+#define RCC_MC_APB3ENCLRR_LPTIM2EN BIT(0)
+#define RCC_MC_APB3ENCLRR_LPTIM3EN BIT(1)
+#define RCC_MC_APB3ENCLRR_LPTIM4EN BIT(2)
+#define RCC_MC_APB3ENCLRR_LPTIM5EN BIT(3)
+#define RCC_MC_APB3ENCLRR_SAI4EN BIT(8)
+#define RCC_MC_APB3ENCLRR_SYSCFGEN BIT(11)
+#define RCC_MC_APB3ENCLRR_VREFEN BIT(13)
+#define RCC_MC_APB3ENCLRR_TMPSENSEN BIT(16)
+#define RCC_MC_APB3ENCLRR_PMBCTRLEN BIT(17)
+#define RCC_MC_APB3ENCLRR_HDPEN BIT(20)
+
+/* RCC_MC_AHB2ENSETR register fields */
+#define RCC_MC_AHB2ENSETR_DMA1EN BIT(0)
+#define RCC_MC_AHB2ENSETR_DMA2EN BIT(1)
+#define RCC_MC_AHB2ENSETR_DMAMUXEN BIT(2)
+#define RCC_MC_AHB2ENSETR_ADC12EN BIT(5)
+#define RCC_MC_AHB2ENSETR_USBOEN BIT(8)
+#define RCC_MC_AHB2ENSETR_SDMMC3EN BIT(16)
+
+/* RCC_MC_AHB2ENCLRR register fields */
+#define RCC_MC_AHB2ENCLRR_DMA1EN BIT(0)
+#define RCC_MC_AHB2ENCLRR_DMA2EN BIT(1)
+#define RCC_MC_AHB2ENCLRR_DMAMUXEN BIT(2)
+#define RCC_MC_AHB2ENCLRR_ADC12EN BIT(5)
+#define RCC_MC_AHB2ENCLRR_USBOEN BIT(8)
+#define RCC_MC_AHB2ENCLRR_SDMMC3EN BIT(16)
+
+/* RCC_MC_AHB3ENSETR register fields */
+#define RCC_MC_AHB3ENSETR_DCMIEN BIT(0)
+#define RCC_MC_AHB3ENSETR_CRYP2EN BIT(4)
+#define RCC_MC_AHB3ENSETR_HASH2EN BIT(5)
+#define RCC_MC_AHB3ENSETR_RNG2EN BIT(6)
+#define RCC_MC_AHB3ENSETR_CRC2EN BIT(7)
+#define RCC_MC_AHB3ENSETR_HSEMEN BIT(11)
+#define RCC_MC_AHB3ENSETR_IPCCEN BIT(12)
+
+/* RCC_MC_AHB3ENCLRR register fields */
+#define RCC_MC_AHB3ENCLRR_DCMIEN BIT(0)
+#define RCC_MC_AHB3ENCLRR_CRYP2EN BIT(4)
+#define RCC_MC_AHB3ENCLRR_HASH2EN BIT(5)
+#define RCC_MC_AHB3ENCLRR_RNG2EN BIT(6)
+#define RCC_MC_AHB3ENCLRR_CRC2EN BIT(7)
+#define RCC_MC_AHB3ENCLRR_HSEMEN BIT(11)
+#define RCC_MC_AHB3ENCLRR_IPCCEN BIT(12)
+
+/* RCC_MC_AHB4ENSETR register fields */
+#define RCC_MC_AHB4ENSETR_GPIOAEN BIT(0)
+#define RCC_MC_AHB4ENSETR_GPIOBEN BIT(1)
+#define RCC_MC_AHB4ENSETR_GPIOCEN BIT(2)
+#define RCC_MC_AHB4ENSETR_GPIODEN BIT(3)
+#define RCC_MC_AHB4ENSETR_GPIOEEN BIT(4)
+#define RCC_MC_AHB4ENSETR_GPIOFEN BIT(5)
+#define RCC_MC_AHB4ENSETR_GPIOGEN BIT(6)
+#define RCC_MC_AHB4ENSETR_GPIOHEN BIT(7)
+#define RCC_MC_AHB4ENSETR_GPIOIEN BIT(8)
+#define RCC_MC_AHB4ENSETR_GPIOJEN BIT(9)
+#define RCC_MC_AHB4ENSETR_GPIOKEN BIT(10)
+
+/* RCC_MC_AHB4ENCLRR register fields */
+#define RCC_MC_AHB4ENCLRR_GPIOAEN BIT(0)
+#define RCC_MC_AHB4ENCLRR_GPIOBEN BIT(1)
+#define RCC_MC_AHB4ENCLRR_GPIOCEN BIT(2)
+#define RCC_MC_AHB4ENCLRR_GPIODEN BIT(3)
+#define RCC_MC_AHB4ENCLRR_GPIOEEN BIT(4)
+#define RCC_MC_AHB4ENCLRR_GPIOFEN BIT(5)
+#define RCC_MC_AHB4ENCLRR_GPIOGEN BIT(6)
+#define RCC_MC_AHB4ENCLRR_GPIOHEN BIT(7)
+#define RCC_MC_AHB4ENCLRR_GPIOIEN BIT(8)
+#define RCC_MC_AHB4ENCLRR_GPIOJEN BIT(9)
+#define RCC_MC_AHB4ENCLRR_GPIOKEN BIT(10)
+
+/* RCC_MC_AXIMENSETR register fields */
+#define RCC_MC_AXIMENSETR_SYSRAMEN BIT(0)
+
+/* RCC_MC_AXIMENCLRR register fields */
+#define RCC_MC_AXIMENCLRR_SYSRAMEN BIT(0)
+
+/* RCC_MC_MLAHBENSETR register fields */
+#define RCC_MC_MLAHBENSETR_RETRAMEN BIT(4)
+
+/* RCC_MC_MLAHBENCLRR register fields */
+#define RCC_MC_MLAHBENCLRR_RETRAMEN BIT(4)
+
+/* RCC_MP_APB1LPENSETR register fields */
+#define RCC_MP_APB1LPENSETR_TIM2LPEN BIT(0)
+#define RCC_MP_APB1LPENSETR_TIM3LPEN BIT(1)
+#define RCC_MP_APB1LPENSETR_TIM4LPEN BIT(2)
+#define RCC_MP_APB1LPENSETR_TIM5LPEN BIT(3)
+#define RCC_MP_APB1LPENSETR_TIM6LPEN BIT(4)
+#define RCC_MP_APB1LPENSETR_TIM7LPEN BIT(5)
+#define RCC_MP_APB1LPENSETR_TIM12LPEN BIT(6)
+#define RCC_MP_APB1LPENSETR_TIM13LPEN BIT(7)
+#define RCC_MP_APB1LPENSETR_TIM14LPEN BIT(8)
+#define RCC_MP_APB1LPENSETR_LPTIM1LPEN BIT(9)
+#define RCC_MP_APB1LPENSETR_SPI2LPEN BIT(11)
+#define RCC_MP_APB1LPENSETR_SPI3LPEN BIT(12)
+#define RCC_MP_APB1LPENSETR_USART2LPEN BIT(14)
+#define RCC_MP_APB1LPENSETR_USART3LPEN BIT(15)
+#define RCC_MP_APB1LPENSETR_UART4LPEN BIT(16)
+#define RCC_MP_APB1LPENSETR_UART5LPEN BIT(17)
+#define RCC_MP_APB1LPENSETR_UART7LPEN BIT(18)
+#define RCC_MP_APB1LPENSETR_UART8LPEN BIT(19)
+#define RCC_MP_APB1LPENSETR_I2C1LPEN BIT(21)
+#define RCC_MP_APB1LPENSETR_I2C2LPEN BIT(22)
+#define RCC_MP_APB1LPENSETR_I2C3LPEN BIT(23)
+#define RCC_MP_APB1LPENSETR_I2C5LPEN BIT(24)
+#define RCC_MP_APB1LPENSETR_SPDIFLPEN BIT(26)
+#define RCC_MP_APB1LPENSETR_CECLPEN BIT(27)
+#define RCC_MP_APB1LPENSETR_DAC12LPEN BIT(29)
+#define RCC_MP_APB1LPENSETR_MDIOSLPEN BIT(31)
+
+/* RCC_MP_APB1LPENCLRR register fields */
+#define RCC_MP_APB1LPENCLRR_TIM2LPEN BIT(0)
+#define RCC_MP_APB1LPENCLRR_TIM3LPEN BIT(1)
+#define RCC_MP_APB1LPENCLRR_TIM4LPEN BIT(2)
+#define RCC_MP_APB1LPENCLRR_TIM5LPEN BIT(3)
+#define RCC_MP_APB1LPENCLRR_TIM6LPEN BIT(4)
+#define RCC_MP_APB1LPENCLRR_TIM7LPEN BIT(5)
+#define RCC_MP_APB1LPENCLRR_TIM12LPEN BIT(6)
+#define RCC_MP_APB1LPENCLRR_TIM13LPEN BIT(7)
+#define RCC_MP_APB1LPENCLRR_TIM14LPEN BIT(8)
+#define RCC_MP_APB1LPENCLRR_LPTIM1LPEN BIT(9)
+#define RCC_MP_APB1LPENCLRR_SPI2LPEN BIT(11)
+#define RCC_MP_APB1LPENCLRR_SPI3LPEN BIT(12)
+#define RCC_MP_APB1LPENCLRR_USART2LPEN BIT(14)
+#define RCC_MP_APB1LPENCLRR_USART3LPEN BIT(15)
+#define RCC_MP_APB1LPENCLRR_UART4LPEN BIT(16)
+#define RCC_MP_APB1LPENCLRR_UART5LPEN BIT(17)
+#define RCC_MP_APB1LPENCLRR_UART7LPEN BIT(18)
+#define RCC_MP_APB1LPENCLRR_UART8LPEN BIT(19)
+#define RCC_MP_APB1LPENCLRR_I2C1LPEN BIT(21)
+#define RCC_MP_APB1LPENCLRR_I2C2LPEN BIT(22)
+#define RCC_MP_APB1LPENCLRR_I2C3LPEN BIT(23)
+#define RCC_MP_APB1LPENCLRR_I2C5LPEN BIT(24)
+#define RCC_MP_APB1LPENCLRR_SPDIFLPEN BIT(26)
+#define RCC_MP_APB1LPENCLRR_CECLPEN BIT(27)
+#define RCC_MP_APB1LPENCLRR_DAC12LPEN BIT(29)
+#define RCC_MP_APB1LPENCLRR_MDIOSLPEN BIT(31)
+
+/* RCC_MP_APB2LPENSETR register fields */
+#define RCC_MP_APB2LPENSETR_TIM1LPEN BIT(0)
+#define RCC_MP_APB2LPENSETR_TIM8LPEN BIT(1)
+#define RCC_MP_APB2LPENSETR_TIM15LPEN BIT(2)
+#define RCC_MP_APB2LPENSETR_TIM16LPEN BIT(3)
+#define RCC_MP_APB2LPENSETR_TIM17LPEN BIT(4)
+#define RCC_MP_APB2LPENSETR_SPI1LPEN BIT(8)
+#define RCC_MP_APB2LPENSETR_SPI4LPEN BIT(9)
+#define RCC_MP_APB2LPENSETR_SPI5LPEN BIT(10)
+#define RCC_MP_APB2LPENSETR_USART6LPEN BIT(13)
+#define RCC_MP_APB2LPENSETR_SAI1LPEN BIT(16)
+#define RCC_MP_APB2LPENSETR_SAI2LPEN BIT(17)
+#define RCC_MP_APB2LPENSETR_SAI3LPEN BIT(18)
+#define RCC_MP_APB2LPENSETR_DFSDMLPEN BIT(20)
+#define RCC_MP_APB2LPENSETR_ADFSDMLPEN BIT(21)
+#define RCC_MP_APB2LPENSETR_FDCANLPEN BIT(24)
+
+/* RCC_MP_APB2LPENCLRR register fields */
+#define RCC_MP_APB2LPENCLRR_TIM1LPEN BIT(0)
+#define RCC_MP_APB2LPENCLRR_TIM8LPEN BIT(1)
+#define RCC_MP_APB2LPENCLRR_TIM15LPEN BIT(2)
+#define RCC_MP_APB2LPENCLRR_TIM16LPEN BIT(3)
+#define RCC_MP_APB2LPENCLRR_TIM17LPEN BIT(4)
+#define RCC_MP_APB2LPENCLRR_SPI1LPEN BIT(8)
+#define RCC_MP_APB2LPENCLRR_SPI4LPEN BIT(9)
+#define RCC_MP_APB2LPENCLRR_SPI5LPEN BIT(10)
+#define RCC_MP_APB2LPENCLRR_USART6LPEN BIT(13)
+#define RCC_MP_APB2LPENCLRR_SAI1LPEN BIT(16)
+#define RCC_MP_APB2LPENCLRR_SAI2LPEN BIT(17)
+#define RCC_MP_APB2LPENCLRR_SAI3LPEN BIT(18)
+#define RCC_MP_APB2LPENCLRR_DFSDMLPEN BIT(20)
+#define RCC_MP_APB2LPENCLRR_ADFSDMLPEN BIT(21)
+#define RCC_MP_APB2LPENCLRR_FDCANLPEN BIT(24)
+
+/* RCC_MP_APB3LPENSETR register fields */
+#define RCC_MP_APB3LPENSETR_LPTIM2LPEN BIT(0)
+#define RCC_MP_APB3LPENSETR_LPTIM3LPEN BIT(1)
+#define RCC_MP_APB3LPENSETR_LPTIM4LPEN BIT(2)
+#define RCC_MP_APB3LPENSETR_LPTIM5LPEN BIT(3)
+#define RCC_MP_APB3LPENSETR_SAI4LPEN BIT(8)
+#define RCC_MP_APB3LPENSETR_SYSCFGLPEN BIT(11)
+#define RCC_MP_APB3LPENSETR_VREFLPEN BIT(13)
+#define RCC_MP_APB3LPENSETR_TMPSENSLPEN BIT(16)
+#define RCC_MP_APB3LPENSETR_PMBCTRLLPEN BIT(17)
+
+/* RCC_MP_APB3LPENCLRR register fields */
+#define RCC_MP_APB3LPENCLRR_LPTIM2LPEN BIT(0)
+#define RCC_MP_APB3LPENCLRR_LPTIM3LPEN BIT(1)
+#define RCC_MP_APB3LPENCLRR_LPTIM4LPEN BIT(2)
+#define RCC_MP_APB3LPENCLRR_LPTIM5LPEN BIT(3)
+#define RCC_MP_APB3LPENCLRR_SAI4LPEN BIT(8)
+#define RCC_MP_APB3LPENCLRR_SYSCFGLPEN BIT(11)
+#define RCC_MP_APB3LPENCLRR_VREFLPEN BIT(13)
+#define RCC_MP_APB3LPENCLRR_TMPSENSLPEN BIT(16)
+#define RCC_MP_APB3LPENCLRR_PMBCTRLLPEN BIT(17)
+
+/* RCC_MP_AHB2LPENSETR register fields */
+#define RCC_MP_AHB2LPENSETR_DMA1LPEN BIT(0)
+#define RCC_MP_AHB2LPENSETR_DMA2LPEN BIT(1)
+#define RCC_MP_AHB2LPENSETR_DMAMUXLPEN BIT(2)
+#define RCC_MP_AHB2LPENSETR_ADC12LPEN BIT(5)
+#define RCC_MP_AHB2LPENSETR_USBOLPEN BIT(8)
+#define RCC_MP_AHB2LPENSETR_SDMMC3LPEN BIT(16)
+
+/* RCC_MP_AHB2LPENCLRR register fields */
+#define RCC_MP_AHB2LPENCLRR_DMA1LPEN BIT(0)
+#define RCC_MP_AHB2LPENCLRR_DMA2LPEN BIT(1)
+#define RCC_MP_AHB2LPENCLRR_DMAMUXLPEN BIT(2)
+#define RCC_MP_AHB2LPENCLRR_ADC12LPEN BIT(5)
+#define RCC_MP_AHB2LPENCLRR_USBOLPEN BIT(8)
+#define RCC_MP_AHB2LPENCLRR_SDMMC3LPEN BIT(16)
+
+/* RCC_MP_AHB3LPENSETR register fields */
+#define RCC_MP_AHB3LPENSETR_DCMILPEN BIT(0)
+#define RCC_MP_AHB3LPENSETR_CRYP2LPEN BIT(4)
+#define RCC_MP_AHB3LPENSETR_HASH2LPEN BIT(5)
+#define RCC_MP_AHB3LPENSETR_RNG2LPEN BIT(6)
+#define RCC_MP_AHB3LPENSETR_CRC2LPEN BIT(7)
+#define RCC_MP_AHB3LPENSETR_HSEMLPEN BIT(11)
+#define RCC_MP_AHB3LPENSETR_IPCCLPEN BIT(12)
+
+/* RCC_MP_AHB3LPENCLRR register fields */
+#define RCC_MP_AHB3LPENCLRR_DCMILPEN BIT(0)
+#define RCC_MP_AHB3LPENCLRR_CRYP2LPEN BIT(4)
+#define RCC_MP_AHB3LPENCLRR_HASH2LPEN BIT(5)
+#define RCC_MP_AHB3LPENCLRR_RNG2LPEN BIT(6)
+#define RCC_MP_AHB3LPENCLRR_CRC2LPEN BIT(7)
+#define RCC_MP_AHB3LPENCLRR_HSEMLPEN BIT(11)
+#define RCC_MP_AHB3LPENCLRR_IPCCLPEN BIT(12)
+
+/* RCC_MP_AHB4LPENSETR register fields */
+#define RCC_MP_AHB4LPENSETR_GPIOALPEN BIT(0)
+#define RCC_MP_AHB4LPENSETR_GPIOBLPEN BIT(1)
+#define RCC_MP_AHB4LPENSETR_GPIOCLPEN BIT(2)
+#define RCC_MP_AHB4LPENSETR_GPIODLPEN BIT(3)
+#define RCC_MP_AHB4LPENSETR_GPIOELPEN BIT(4)
+#define RCC_MP_AHB4LPENSETR_GPIOFLPEN BIT(5)
+#define RCC_MP_AHB4LPENSETR_GPIOGLPEN BIT(6)
+#define RCC_MP_AHB4LPENSETR_GPIOHLPEN BIT(7)
+#define RCC_MP_AHB4LPENSETR_GPIOILPEN BIT(8)
+#define RCC_MP_AHB4LPENSETR_GPIOJLPEN BIT(9)
+#define RCC_MP_AHB4LPENSETR_GPIOKLPEN BIT(10)
+
+/* RCC_MP_AHB4LPENCLRR register fields */
+#define RCC_MP_AHB4LPENCLRR_GPIOALPEN BIT(0)
+#define RCC_MP_AHB4LPENCLRR_GPIOBLPEN BIT(1)
+#define RCC_MP_AHB4LPENCLRR_GPIOCLPEN BIT(2)
+#define RCC_MP_AHB4LPENCLRR_GPIODLPEN BIT(3)
+#define RCC_MP_AHB4LPENCLRR_GPIOELPEN BIT(4)
+#define RCC_MP_AHB4LPENCLRR_GPIOFLPEN BIT(5)
+#define RCC_MP_AHB4LPENCLRR_GPIOGLPEN BIT(6)
+#define RCC_MP_AHB4LPENCLRR_GPIOHLPEN BIT(7)
+#define RCC_MP_AHB4LPENCLRR_GPIOILPEN BIT(8)
+#define RCC_MP_AHB4LPENCLRR_GPIOJLPEN BIT(9)
+#define RCC_MP_AHB4LPENCLRR_GPIOKLPEN BIT(10)
+
+/* RCC_MP_AXIMLPENSETR register fields */
+#define RCC_MP_AXIMLPENSETR_SYSRAMLPEN BIT(0)
+
+/* RCC_MP_AXIMLPENCLRR register fields */
+#define RCC_MP_AXIMLPENCLRR_SYSRAMLPEN BIT(0)
+
+/* RCC_MP_MLAHBLPENSETR register fields */
+#define RCC_MP_MLAHBLPENSETR_SRAM1LPEN BIT(0)
+#define RCC_MP_MLAHBLPENSETR_SRAM2LPEN BIT(1)
+#define RCC_MP_MLAHBLPENSETR_SRAM34LPEN BIT(2)
+#define RCC_MP_MLAHBLPENSETR_RETRAMLPEN BIT(4)
+
+/* RCC_MP_MLAHBLPENCLRR register fields */
+#define RCC_MP_MLAHBLPENCLRR_SRAM1LPEN BIT(0)
+#define RCC_MP_MLAHBLPENCLRR_SRAM2LPEN BIT(1)
+#define RCC_MP_MLAHBLPENCLRR_SRAM34LPEN BIT(2)
+#define RCC_MP_MLAHBLPENCLRR_RETRAMLPEN BIT(4)
+
+/* RCC_MC_APB1LPENSETR register fields */
+#define RCC_MC_APB1LPENSETR_TIM2LPEN BIT(0)
+#define RCC_MC_APB1LPENSETR_TIM3LPEN BIT(1)
+#define RCC_MC_APB1LPENSETR_TIM4LPEN BIT(2)
+#define RCC_MC_APB1LPENSETR_TIM5LPEN BIT(3)
+#define RCC_MC_APB1LPENSETR_TIM6LPEN BIT(4)
+#define RCC_MC_APB1LPENSETR_TIM7LPEN BIT(5)
+#define RCC_MC_APB1LPENSETR_TIM12LPEN BIT(6)
+#define RCC_MC_APB1LPENSETR_TIM13LPEN BIT(7)
+#define RCC_MC_APB1LPENSETR_TIM14LPEN BIT(8)
+#define RCC_MC_APB1LPENSETR_LPTIM1LPEN BIT(9)
+#define RCC_MC_APB1LPENSETR_SPI2LPEN BIT(11)
+#define RCC_MC_APB1LPENSETR_SPI3LPEN BIT(12)
+#define RCC_MC_APB1LPENSETR_USART2LPEN BIT(14)
+#define RCC_MC_APB1LPENSETR_USART3LPEN BIT(15)
+#define RCC_MC_APB1LPENSETR_UART4LPEN BIT(16)
+#define RCC_MC_APB1LPENSETR_UART5LPEN BIT(17)
+#define RCC_MC_APB1LPENSETR_UART7LPEN BIT(18)
+#define RCC_MC_APB1LPENSETR_UART8LPEN BIT(19)
+#define RCC_MC_APB1LPENSETR_I2C1LPEN BIT(21)
+#define RCC_MC_APB1LPENSETR_I2C2LPEN BIT(22)
+#define RCC_MC_APB1LPENSETR_I2C3LPEN BIT(23)
+#define RCC_MC_APB1LPENSETR_I2C5LPEN BIT(24)
+#define RCC_MC_APB1LPENSETR_SPDIFLPEN BIT(26)
+#define RCC_MC_APB1LPENSETR_CECLPEN BIT(27)
+#define RCC_MC_APB1LPENSETR_WWDG1LPEN BIT(28)
+#define RCC_MC_APB1LPENSETR_DAC12LPEN BIT(29)
+#define RCC_MC_APB1LPENSETR_MDIOSLPEN BIT(31)
+
+/* RCC_MC_APB1LPENCLRR register fields */
+#define RCC_MC_APB1LPENCLRR_TIM2LPEN BIT(0)
+#define RCC_MC_APB1LPENCLRR_TIM3LPEN BIT(1)
+#define RCC_MC_APB1LPENCLRR_TIM4LPEN BIT(2)
+#define RCC_MC_APB1LPENCLRR_TIM5LPEN BIT(3)
+#define RCC_MC_APB1LPENCLRR_TIM6LPEN BIT(4)
+#define RCC_MC_APB1LPENCLRR_TIM7LPEN BIT(5)
+#define RCC_MC_APB1LPENCLRR_TIM12LPEN BIT(6)
+#define RCC_MC_APB1LPENCLRR_TIM13LPEN BIT(7)
+#define RCC_MC_APB1LPENCLRR_TIM14LPEN BIT(8)
+#define RCC_MC_APB1LPENCLRR_LPTIM1LPEN BIT(9)
+#define RCC_MC_APB1LPENCLRR_SPI2LPEN BIT(11)
+#define RCC_MC_APB1LPENCLRR_SPI3LPEN BIT(12)
+#define RCC_MC_APB1LPENCLRR_USART2LPEN BIT(14)
+#define RCC_MC_APB1LPENCLRR_USART3LPEN BIT(15)
+#define RCC_MC_APB1LPENCLRR_UART4LPEN BIT(16)
+#define RCC_MC_APB1LPENCLRR_UART5LPEN BIT(17)
+#define RCC_MC_APB1LPENCLRR_UART7LPEN BIT(18)
+#define RCC_MC_APB1LPENCLRR_UART8LPEN BIT(19)
+#define RCC_MC_APB1LPENCLRR_I2C1LPEN BIT(21)
+#define RCC_MC_APB1LPENCLRR_I2C2LPEN BIT(22)
+#define RCC_MC_APB1LPENCLRR_I2C3LPEN BIT(23)
+#define RCC_MC_APB1LPENCLRR_I2C5LPEN BIT(24)
+#define RCC_MC_APB1LPENCLRR_SPDIFLPEN BIT(26)
+#define RCC_MC_APB1LPENCLRR_CECLPEN BIT(27)
+#define RCC_MC_APB1LPENCLRR_WWDG1LPEN BIT(28)
+#define RCC_MC_APB1LPENCLRR_DAC12LPEN BIT(29)
+#define RCC_MC_APB1LPENCLRR_MDIOSLPEN BIT(31)
+
+/* RCC_MC_APB2LPENSETR register fields */
+#define RCC_MC_APB2LPENSETR_TIM1LPEN BIT(0)
+#define RCC_MC_APB2LPENSETR_TIM8LPEN BIT(1)
+#define RCC_MC_APB2LPENSETR_TIM15LPEN BIT(2)
+#define RCC_MC_APB2LPENSETR_TIM16LPEN BIT(3)
+#define RCC_MC_APB2LPENSETR_TIM17LPEN BIT(4)
+#define RCC_MC_APB2LPENSETR_SPI1LPEN BIT(8)
+#define RCC_MC_APB2LPENSETR_SPI4LPEN BIT(9)
+#define RCC_MC_APB2LPENSETR_SPI5LPEN BIT(10)
+#define RCC_MC_APB2LPENSETR_USART6LPEN BIT(13)
+#define RCC_MC_APB2LPENSETR_SAI1LPEN BIT(16)
+#define RCC_MC_APB2LPENSETR_SAI2LPEN BIT(17)
+#define RCC_MC_APB2LPENSETR_SAI3LPEN BIT(18)
+#define RCC_MC_APB2LPENSETR_DFSDMLPEN BIT(20)
+#define RCC_MC_APB2LPENSETR_ADFSDMLPEN BIT(21)
+#define RCC_MC_APB2LPENSETR_FDCANLPEN BIT(24)
+
+/* RCC_MC_APB2LPENCLRR register fields */
+#define RCC_MC_APB2LPENCLRR_TIM1LPEN BIT(0)
+#define RCC_MC_APB2LPENCLRR_TIM8LPEN BIT(1)
+#define RCC_MC_APB2LPENCLRR_TIM15LPEN BIT(2)
+#define RCC_MC_APB2LPENCLRR_TIM16LPEN BIT(3)
+#define RCC_MC_APB2LPENCLRR_TIM17LPEN BIT(4)
+#define RCC_MC_APB2LPENCLRR_SPI1LPEN BIT(8)
+#define RCC_MC_APB2LPENCLRR_SPI4LPEN BIT(9)
+#define RCC_MC_APB2LPENCLRR_SPI5LPEN BIT(10)
+#define RCC_MC_APB2LPENCLRR_USART6LPEN BIT(13)
+#define RCC_MC_APB2LPENCLRR_SAI1LPEN BIT(16)
+#define RCC_MC_APB2LPENCLRR_SAI2LPEN BIT(17)
+#define RCC_MC_APB2LPENCLRR_SAI3LPEN BIT(18)
+#define RCC_MC_APB2LPENCLRR_DFSDMLPEN BIT(20)
+#define RCC_MC_APB2LPENCLRR_ADFSDMLPEN BIT(21)
+#define RCC_MC_APB2LPENCLRR_FDCANLPEN BIT(24)
+
+/* RCC_MC_APB3LPENSETR register fields */
+#define RCC_MC_APB3LPENSETR_LPTIM2LPEN BIT(0)
+#define RCC_MC_APB3LPENSETR_LPTIM3LPEN BIT(1)
+#define RCC_MC_APB3LPENSETR_LPTIM4LPEN BIT(2)
+#define RCC_MC_APB3LPENSETR_LPTIM5LPEN BIT(3)
+#define RCC_MC_APB3LPENSETR_SAI4LPEN BIT(8)
+#define RCC_MC_APB3LPENSETR_SYSCFGLPEN BIT(11)
+#define RCC_MC_APB3LPENSETR_VREFLPEN BIT(13)
+#define RCC_MC_APB3LPENSETR_TMPSENSLPEN BIT(16)
+#define RCC_MC_APB3LPENSETR_PMBCTRLLPEN BIT(17)
+
+/* RCC_MC_APB3LPENCLRR register fields */
+#define RCC_MC_APB3LPENCLRR_LPTIM2LPEN BIT(0)
+#define RCC_MC_APB3LPENCLRR_LPTIM3LPEN BIT(1)
+#define RCC_MC_APB3LPENCLRR_LPTIM4LPEN BIT(2)
+#define RCC_MC_APB3LPENCLRR_LPTIM5LPEN BIT(3)
+#define RCC_MC_APB3LPENCLRR_SAI4LPEN BIT(8)
+#define RCC_MC_APB3LPENCLRR_SYSCFGLPEN BIT(11)
+#define RCC_MC_APB3LPENCLRR_VREFLPEN BIT(13)
+#define RCC_MC_APB3LPENCLRR_TMPSENSLPEN BIT(16)
+#define RCC_MC_APB3LPENCLRR_PMBCTRLLPEN BIT(17)
+
+/* RCC_MC_AHB2LPENSETR register fields */
+#define RCC_MC_AHB2LPENSETR_DMA1LPEN BIT(0)
+#define RCC_MC_AHB2LPENSETR_DMA2LPEN BIT(1)
+#define RCC_MC_AHB2LPENSETR_DMAMUXLPEN BIT(2)
+#define RCC_MC_AHB2LPENSETR_ADC12LPEN BIT(5)
+#define RCC_MC_AHB2LPENSETR_USBOLPEN BIT(8)
+#define RCC_MC_AHB2LPENSETR_SDMMC3LPEN BIT(16)
+
+/* RCC_MC_AHB2LPENCLRR register fields */
+#define RCC_MC_AHB2LPENCLRR_DMA1LPEN BIT(0)
+#define RCC_MC_AHB2LPENCLRR_DMA2LPEN BIT(1)
+#define RCC_MC_AHB2LPENCLRR_DMAMUXLPEN BIT(2)
+#define RCC_MC_AHB2LPENCLRR_ADC12LPEN BIT(5)
+#define RCC_MC_AHB2LPENCLRR_USBOLPEN BIT(8)
+#define RCC_MC_AHB2LPENCLRR_SDMMC3LPEN BIT(16)
+
+/* RCC_MC_AHB3LPENSETR register fields */
+#define RCC_MC_AHB3LPENSETR_DCMILPEN BIT(0)
+#define RCC_MC_AHB3LPENSETR_CRYP2LPEN BIT(4)
+#define RCC_MC_AHB3LPENSETR_HASH2LPEN BIT(5)
+#define RCC_MC_AHB3LPENSETR_RNG2LPEN BIT(6)
+#define RCC_MC_AHB3LPENSETR_CRC2LPEN BIT(7)
+#define RCC_MC_AHB3LPENSETR_HSEMLPEN BIT(11)
+#define RCC_MC_AHB3LPENSETR_IPCCLPEN BIT(12)
+
+/* RCC_MC_AHB3LPENCLRR register fields */
+#define RCC_MC_AHB3LPENCLRR_DCMILPEN BIT(0)
+#define RCC_MC_AHB3LPENCLRR_CRYP2LPEN BIT(4)
+#define RCC_MC_AHB3LPENCLRR_HASH2LPEN BIT(5)
+#define RCC_MC_AHB3LPENCLRR_RNG2LPEN BIT(6)
+#define RCC_MC_AHB3LPENCLRR_CRC2LPEN BIT(7)
+#define RCC_MC_AHB3LPENCLRR_HSEMLPEN BIT(11)
+#define RCC_MC_AHB3LPENCLRR_IPCCLPEN BIT(12)
+
+/* RCC_MC_AHB4LPENSETR register fields */
+#define RCC_MC_AHB4LPENSETR_GPIOALPEN BIT(0)
+#define RCC_MC_AHB4LPENSETR_GPIOBLPEN BIT(1)
+#define RCC_MC_AHB4LPENSETR_GPIOCLPEN BIT(2)
+#define RCC_MC_AHB4LPENSETR_GPIODLPEN BIT(3)
+#define RCC_MC_AHB4LPENSETR_GPIOELPEN BIT(4)
+#define RCC_MC_AHB4LPENSETR_GPIOFLPEN BIT(5)
+#define RCC_MC_AHB4LPENSETR_GPIOGLPEN BIT(6)
+#define RCC_MC_AHB4LPENSETR_GPIOHLPEN BIT(7)
+#define RCC_MC_AHB4LPENSETR_GPIOILPEN BIT(8)
+#define RCC_MC_AHB4LPENSETR_GPIOJLPEN BIT(9)
+#define RCC_MC_AHB4LPENSETR_GPIOKLPEN BIT(10)
+
+/* RCC_MC_AHB4LPENCLRR register fields */
+#define RCC_MC_AHB4LPENCLRR_GPIOALPEN BIT(0)
+#define RCC_MC_AHB4LPENCLRR_GPIOBLPEN BIT(1)
+#define RCC_MC_AHB4LPENCLRR_GPIOCLPEN BIT(2)
+#define RCC_MC_AHB4LPENCLRR_GPIODLPEN BIT(3)
+#define RCC_MC_AHB4LPENCLRR_GPIOELPEN BIT(4)
+#define RCC_MC_AHB4LPENCLRR_GPIOFLPEN BIT(5)
+#define RCC_MC_AHB4LPENCLRR_GPIOGLPEN BIT(6)
+#define RCC_MC_AHB4LPENCLRR_GPIOHLPEN BIT(7)
+#define RCC_MC_AHB4LPENCLRR_GPIOILPEN BIT(8)
+#define RCC_MC_AHB4LPENCLRR_GPIOJLPEN BIT(9)
+#define RCC_MC_AHB4LPENCLRR_GPIOKLPEN BIT(10)
+
+/* RCC_MC_AXIMLPENSETR register fields */
+#define RCC_MC_AXIMLPENSETR_SYSRAMLPEN BIT(0)
+
+/* RCC_MC_AXIMLPENCLRR register fields */
+#define RCC_MC_AXIMLPENCLRR_SYSRAMLPEN BIT(0)
+
+/* RCC_MC_MLAHBLPENSETR register fields */
+#define RCC_MC_MLAHBLPENSETR_SRAM1LPEN BIT(0)
+#define RCC_MC_MLAHBLPENSETR_SRAM2LPEN BIT(1)
+#define RCC_MC_MLAHBLPENSETR_SRAM34LPEN BIT(2)
+#define RCC_MC_MLAHBLPENSETR_RETRAMLPEN BIT(4)
+
+/* RCC_MC_MLAHBLPENCLRR register fields */
+#define RCC_MC_MLAHBLPENCLRR_SRAM1LPEN BIT(0)
+#define RCC_MC_MLAHBLPENCLRR_SRAM2LPEN BIT(1)
+#define RCC_MC_MLAHBLPENCLRR_SRAM34LPEN BIT(2)
+#define RCC_MC_MLAHBLPENCLRR_RETRAMLPEN BIT(4)
+
+/* RCC_MC_RSTSCLRR register fields */
+#define RCC_MC_RSTSCLRR_PORRSTF BIT(0)
+#define RCC_MC_RSTSCLRR_BORRSTF BIT(1)
+#define RCC_MC_RSTSCLRR_PADRSTF BIT(2)
+#define RCC_MC_RSTSCLRR_HCSSRSTF BIT(3)
+#define RCC_MC_RSTSCLRR_VCORERSTF BIT(4)
+#define RCC_MC_RSTSCLRR_MCURSTF BIT(5)
+#define RCC_MC_RSTSCLRR_MPSYSRSTF BIT(6)
+#define RCC_MC_RSTSCLRR_MCSYSRSTF BIT(7)
+#define RCC_MC_RSTSCLRR_IWDG1RSTF BIT(8)
+#define RCC_MC_RSTSCLRR_IWDG2RSTF BIT(9)
+#define RCC_MC_RSTSCLRR_WWDG1RSTF BIT(10)
+
+/* RCC_MC_CIER register fields */
+#define RCC_MC_CIER_LSIRDYIE BIT(0)
+#define RCC_MC_CIER_LSERDYIE BIT(1)
+#define RCC_MC_CIER_HSIRDYIE BIT(2)
+#define RCC_MC_CIER_HSERDYIE BIT(3)
+#define RCC_MC_CIER_CSIRDYIE BIT(4)
+#define RCC_MC_CIER_PLL1DYIE BIT(8)
+#define RCC_MC_CIER_PLL2DYIE BIT(9)
+#define RCC_MC_CIER_PLL3DYIE BIT(10)
+#define RCC_MC_CIER_PLL4DYIE BIT(11)
+#define RCC_MC_CIER_LSECSSIE BIT(16)
+#define RCC_MC_CIER_WKUPIE BIT(20)
+
+/* RCC_MC_CIFR register fields */
+#define RCC_MC_CIFR_LSIRDYF BIT(0)
+#define RCC_MC_CIFR_LSERDYF BIT(1)
+#define RCC_MC_CIFR_HSIRDYF BIT(2)
+#define RCC_MC_CIFR_HSERDYF BIT(3)
+#define RCC_MC_CIFR_CSIRDYF BIT(4)
+#define RCC_MC_CIFR_PLL1DYF BIT(8)
+#define RCC_MC_CIFR_PLL2DYF BIT(9)
+#define RCC_MC_CIFR_PLL3DYF BIT(10)
+#define RCC_MC_CIFR_PLL4DYF BIT(11)
+#define RCC_MC_CIFR_LSECSSF BIT(16)
+#define RCC_MC_CIFR_WKUPF BIT(20)
+
+/* RCC_VERR register fields */
+#define RCC_VERR_MINREV_MASK GENMASK(3, 0)
+#define RCC_VERR_MINREV_SHIFT 0
+#define RCC_VERR_MAJREV_MASK GENMASK(7, 4)
+#define RCC_VERR_MAJREV_SHIFT 4
+
+/* 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)
+
+/* 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)
+
+/* 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 most of RCC_<x>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)
+
+/* Used for all RCC_PLL<n>CR registers */
+#define RCC_PLLNCR_PLLON BIT(0)
+#define RCC_PLLNCR_PLLRDY BIT(1)
+#define RCC_PLLNCR_SSCG_CTRL BIT(2)
+#define RCC_PLLNCR_DIVPEN BIT(4)
+#define RCC_PLLNCR_DIVQEN BIT(5)
+#define RCC_PLLNCR_DIVREN BIT(6)
+#define RCC_PLLNCR_DIVEN_SHIFT 4
+
+/* Used for all RCC_PLL<n>CFGR1 registers */
+#define RCC_PLLNCFGR1_DIVM_MASK GENMASK(21, 16)
+#define RCC_PLLNCFGR1_DIVM_SHIFT 16
+#define RCC_PLLNCFGR1_DIVN_MASK GENMASK(8, 0)
+#define RCC_PLLNCFGR1_DIVN_SHIFT 0
+
+/* Only for PLL3 and PLL4 */
+#define RCC_PLLNCFGR1_IFRGE_MASK GENMASK(25, 24)
+#define RCC_PLLNCFGR1_IFRGE_SHIFT 24
+
+/* Used for all RCC_PLL<n>CFGR2 registers */
+#define RCC_PLLNCFGR2_DIVX_MASK GENMASK(6, 0)
+#define RCC_PLLNCFGR2_DIVP_MASK GENMASK(6, 0)
+#define RCC_PLLNCFGR2_DIVP_SHIFT 0
+#define RCC_PLLNCFGR2_DIVQ_MASK GENMASK(14, 8)
+#define RCC_PLLNCFGR2_DIVQ_SHIFT 8
+#define RCC_PLLNCFGR2_DIVR_MASK GENMASK(22, 16)
+#define RCC_PLLNCFGR2_DIVR_SHIFT 16
+
+/* Used for all RCC_PLL<n>FRACR 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_PLL<n>CSGR 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 TIMER Prescaler */
+#define RCC_TIMGXPRER_TIMGXPRE BIT(0)
+
+/* 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)
+
+#endif /* STM32MP1_RCC_H */
diff --git a/include/drivers/st/stm32mp1_clk.h b/include/drivers/st/stm32mp1_clk.h
new file mode 100644
index 0000000..e2395bc
--- /dev/null
+++ b/include/drivers/st/stm32mp1_clk.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_CLK_H
+#define STM32MP1_CLK_H
+
+#include <arch_helpers.h>
+
+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);
+
+/* SMP protection on RCC registers access */
+void stm32mp1_clk_rcc_regs_lock(void);
+void stm32mp1_clk_rcc_regs_unlock(void);
+
+#ifdef STM32MP_SHARED_RESOURCES
+void stm32mp1_register_clock_parents_secure(unsigned long id);
+#endif
+#endif /* STM32MP1_CLK_H */
diff --git a/include/drivers/st/stm32mp1_ddr.h b/include/drivers/st/stm32mp1_ddr.h
new file mode 100644
index 0000000..df71f35
--- /dev/null
+++ b/include/drivers/st/stm32mp1_ddr.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2018-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#ifndef STM32MP1_DDR_H
+#define STM32MP1_DDR_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <drivers/st/stm32mp_ddr.h>
+
+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;
+#if STM32MP_DDR_DUAL_AXI_PORT
+ uint32_t pcfgr_1;
+ uint32_t pcfgw_1;
+ uint32_t pcfgqos0_1;
+ uint32_t pcfgqos1_1;
+ uint32_t pcfgwqos0_1;
+ uint32_t pcfgwqos1_1;
+#endif
+};
+
+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;
+#if STM32MP_DDR_32BIT_INTERFACE
+ uint32_t dx2gcr;
+ uint32_t dx3gcr;
+#endif
+};
+
+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 stm32mp_ddr_config {
+ struct stm32mp_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;
+};
+
+int stm32mp1_ddr_clk_enable(struct stm32mp_ddr_priv *priv, uint32_t mem_speed);
+void stm32mp1_ddr_init(struct stm32mp_ddr_priv *priv, struct stm32mp_ddr_config *config);
+
+#endif /* STM32MP1_DDR_H */
diff --git a/include/drivers/st/stm32mp1_ddr_helpers.h b/include/drivers/st/stm32mp1_ddr_helpers.h
new file mode 100644
index 0000000..38f2415
--- /dev/null
+++ b/include/drivers/st/stm32mp1_ddr_helpers.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/include/drivers/st/stm32mp1_ddr_regs.h b/include/drivers/st/stm32mp1_ddr_regs.h
new file mode 100644
index 0000000..2fbe1c8
--- /dev/null
+++ b/include/drivers/st/stm32mp1_ddr_regs.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2017-2022, 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 <drivers/st/stm32mp_ddrctrl_regs.h>
+#include <lib/utils_def.h>
+
+/* DDR Physical Interface Control (DDRPHYC) registers*/
+struct stm32mp_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 */
+#if STM32MP_DDR_32BIT_INTERFACE
+ 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 */
+#endif
+} __packed;
+
+/* 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
+#if STM32MP_DDR_32BIT_INTERFACE
+#define DDRPHYC_DX2GCR 0x240
+#define DDRPHYC_DX2DLLCR 0x24C
+#define DDRPHYC_DX3GCR 0x280
+#define DDRPHYC_DX3DLLCR 0x28C
+#endif
+
+/* 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_RVTRN BIT(8)
+#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 */
diff --git a/include/drivers/st/stm32mp1_pwr.h b/include/drivers/st/stm32mp1_pwr.h
new file mode 100644
index 0000000..e17df44
--- /dev/null
+++ b/include/drivers/st/stm32mp1_pwr.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_PWR_H
+#define STM32MP1_PWR_H
+
+#include <lib/utils_def.h>
+
+#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 */
diff --git a/include/drivers/st/stm32mp1_ram.h b/include/drivers/st/stm32mp1_ram.h
new file mode 100644
index 0000000..38360e7
--- /dev/null
+++ b/include/drivers/st/stm32mp1_ram.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/include/drivers/st/stm32mp1_rcc.h b/include/drivers/st/stm32mp1_rcc.h
new file mode 100644
index 0000000..d794225
--- /dev/null
+++ b/include/drivers/st/stm32mp1_rcc.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2015-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#if STM32MP13
+#include "stm32mp13_rcc.h"
+#endif
+#if STM32MP15
+#include "stm32mp15_rcc.h"
+#endif
diff --git a/include/drivers/st/stm32mp1_usb.h b/include/drivers/st/stm32mp1_usb.h
new file mode 100644
index 0000000..06a34cb
--- /dev/null
+++ b/include/drivers/st/stm32mp1_usb.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_USB_H
+#define STM32MP1_USB_H
+
+#include <drivers/usb_device.h>
+
+void stm32mp1_usb_init_driver(struct usb_handle *usb_core_handle,
+ struct pcd_handle *pcd_handle,
+ void *base_register);
+
+#endif /* STM32MP1_USB_H */
diff --git a/include/drivers/st/stm32mp_clkfunc.h b/include/drivers/st/stm32mp_clkfunc.h
new file mode 100644
index 0000000..61286b2
--- /dev/null
+++ b/include/drivers/st/stm32mp_clkfunc.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP_CLKFUNC_H
+#define STM32MP_CLKFUNC_H
+
+#include <stdbool.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+int fdt_osc_read_freq(const char *name, uint32_t *freq);
+bool fdt_clk_read_bool(const char *node_label, const char *prop_name);
+uint32_t fdt_clk_read_uint32_default(const char *node_label,
+ const char *prop_name,
+ uint32_t dflt_value);
+
+int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count,
+ uint32_t *array);
+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_state(void);
+
+int fdt_get_clock_id(int node);
+unsigned long fdt_get_uart_clock_freq(uintptr_t instance);
+
+void stm32mp_stgen_config(unsigned long rate);
+void stm32mp_stgen_restore_counter(unsigned long long value,
+ unsigned long long offset_in_ms);
+unsigned long long stm32mp_stgen_get_counter(void);
+
+#endif /* STM32MP_CLKFUNC_H */
diff --git a/include/drivers/st/stm32mp_ddr.h b/include/drivers/st/stm32mp_ddr.h
new file mode 100644
index 0000000..1efca42
--- /dev/null
+++ b/include/drivers/st/stm32mp_ddr.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#ifndef STM32MP_DDR_H
+#define STM32MP_DDR_H
+
+#include <platform_def.h>
+
+enum stm32mp_ddr_base_type {
+ DDR_BASE,
+ DDRPHY_BASE,
+ NONE_BASE
+};
+
+enum stm32mp_ddr_reg_type {
+ REG_REG,
+ REG_TIMING,
+ REG_PERF,
+ REG_MAP,
+ REGPHY_REG,
+ REGPHY_TIMING,
+ REG_TYPE_NB
+};
+
+struct stm32mp_ddr_reg_desc {
+ const char *name;
+ uint16_t offset; /* Offset for base address */
+ uint8_t par_offset; /* Offset for parameter array */
+};
+
+struct stm32mp_ddr_reg_info {
+ const char *name;
+ const struct stm32mp_ddr_reg_desc *desc;
+ uint8_t size;
+ enum stm32mp_ddr_base_type base;
+};
+
+struct stm32mp_ddr_size {
+ uint64_t base;
+ uint64_t size;
+};
+
+struct stm32mp_ddr_priv {
+ struct stm32mp_ddr_size info;
+ struct stm32mp_ddrctl *ctl;
+ struct stm32mp_ddrphy *phy;
+ uintptr_t pwr;
+ uintptr_t rcc;
+};
+
+struct stm32mp_ddr_info {
+ const char *name;
+ uint32_t speed; /* in kHZ */
+ uint32_t size; /* Memory size in byte = col * row * width */
+};
+
+#define TIMEOUT_US_1S 1000000U
+
+void stm32mp_ddr_set_reg(const struct stm32mp_ddr_priv *priv, enum stm32mp_ddr_reg_type type,
+ const void *param, const struct stm32mp_ddr_reg_info *ddr_registers);
+void stm32mp_ddr_start_sw_done(struct stm32mp_ddrctl *ctl);
+void stm32mp_ddr_wait_sw_done_ack(struct stm32mp_ddrctl *ctl);
+void stm32mp_ddr_enable_axi_port(struct stm32mp_ddrctl *ctl);
+int stm32mp_board_ddr_power_init(enum ddr_type ddr_type);
+
+#endif /* STM32MP_DDR_H */
diff --git a/include/drivers/st/stm32mp_ddr_test.h b/include/drivers/st/stm32mp_ddr_test.h
new file mode 100644
index 0000000..34e522a
--- /dev/null
+++ b/include/drivers/st/stm32mp_ddr_test.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP_DDR_TEST_H
+#define STM32MP_DDR_TEST_H
+
+#include <stdint.h>
+
+uint32_t stm32mp_ddr_test_rw_access(void);
+uint32_t stm32mp_ddr_test_data_bus(void);
+uint32_t stm32mp_ddr_test_addr_bus(uint64_t size);
+uint32_t stm32mp_ddr_check_size(void);
+
+#endif /* STM32MP_DDR_TEST_H */
diff --git a/include/drivers/st/stm32mp_ddrctrl_regs.h b/include/drivers/st/stm32mp_ddrctrl_regs.h
new file mode 100644
index 0000000..79de86b
--- /dev/null
+++ b/include/drivers/st/stm32mp_ddrctrl_regs.h
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#ifndef STM32MP_DDRCTRL_REGS_H
+#define STM32MP_DDRCTRL_REGS_H
+
+#include <cdefs.h>
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+/* DDR Controller (DDRCTRL) registers */
+struct stm32mp_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 mrctrl2; /* 0x1c Control 2 */
+ uint32_t derateen; /* 0x20 Temperature Derate Enable */
+ uint32_t derateint; /* 0x24 Temperature Derate Interval */
+ uint32_t reserved028;
+ uint32_t deratectl; /* 0x2c Temperature Derate Control */
+ 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 rfshctl1; /* 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 */
+ uint32_t rfshtmg1; /* 0x68 Refresh Timing 1 */
+ uint8_t reserved06c[0xc0 - 0x6c];
+ uint32_t crcparctl0; /* 0xc0 CRC Parity Control0 */
+ uint32_t crcparctl1; /* 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 init6; /* 0xe8 SDRAM Initialization 6 */
+ uint32_t init7; /* 0xec SDRAM Initialization 7 */
+ uint32_t dimmctl; /* 0xf0 DIMM Control */
+ uint32_t rankctl; /* 0xf4 Rank Control */
+ uint8_t reserved0f4[0x100 - 0xf8];
+ 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 */
+ uint32_t dramtmg9; /* 0x124 SDRAM Timing 9 */
+ uint32_t dramtmg10; /* 0x128 SDRAM Timing 10 */
+ uint32_t dramtmg11; /* 0x12c SDRAM Timing 11 */
+ uint32_t dramtmg12; /* 0x130 SDRAM Timing 12 */
+ uint32_t dramtmg13; /* 0x134 SDRAM Timing 13 */
+ 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 dfilpcfg1; /* 0x19c DFI Low Power Configuration 1 */
+ 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 */
+ uint32_t dfitmg2; /* 0x1b4 DFI Timing 2 */
+ uint32_t dfitmg3; /* 0x1b8 DFI Timing 3 */
+ uint32_t dfistat; /* 0x1bc DFI Status */
+ uint32_t dbictl; /* 0x1c0 DM/DBI Control */
+ uint32_t dfiphymstr; /* 0x1c4 DFI PHY Master interface */
+ uint8_t reserved1c8[0x200 - 0x1c8];
+ uint32_t addrmap0; /* 0x200 Address Map 0 */
+ 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 */
+ uint32_t addrmap7; /* 0x21c Address Map 7 */
+ uint32_t addrmap8; /* 0x220 Address Map 8 */
+ 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[0x3f0 - 0x374];
+ uint32_t deratestat; /* 0x3f0 Temperature Derate Status */
+ uint8_t reserved3f4[0x3fc - 0x3f4];
+
+ /* 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];
+
+#if STM32MP_DDR_DUAL_AXI_PORT
+ /* 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 */
+#endif
+
+ uint8_t reserved554[0xff0 - 0x554];
+ uint32_t umctl2_ver_number; /* 0xff0 UMCTL2 Version Number */
+} __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
+#if STM32MP_DDR_DUAL_AXI_PORT
+#define DDRCTRL_PCTRL_1 0x540
+#endif
+
+/* 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_DDR4 BIT(4)
+#define DDRCTRL_MSTR_LPDDR4 BIT(5)
+#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(23, 16)
+#define DDRCTRL_PWRTMG_SELFREF_TO_X32_0 BIT(16)
+
+#define DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH BIT(0)
+#define DDRCTRL_RFSHCTL3_REFRESH_UPDATE_LEVEL BIT(1)
+
+#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_DFIMISC_DFI_INIT_START BIT(5)
+
+#define DDRCTRL_DFISTAT_DFI_INIT_COMPLETE 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)
+
+#endif /* STM32MP_DDRCTRL_REGS_H */
diff --git a/include/drivers/st/stm32mp_pmic.h b/include/drivers/st/stm32mp_pmic.h
new file mode 100644
index 0000000..303c571
--- /dev/null
+++ b/include/drivers/st/stm32mp_pmic.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP_PMIC_H
+#define STM32MP_PMIC_H
+
+#include <stdbool.h>
+
+#include <platform_def.h>
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+#if DEBUG
+void print_pmic_info_and_debug(void);
+#else
+static inline void print_pmic_info_and_debug(void)
+{
+}
+#endif
+
+/*
+ * 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);
+
+/*
+ * pmic_voltages_init - Update voltages for platform init
+ *
+ * Returns 0 on success, and negative values on errors
+ */
+int pmic_voltages_init(void);
+
+#endif /* STM32MP_PMIC_H */
diff --git a/include/drivers/st/stm32mp_ram.h b/include/drivers/st/stm32mp_ram.h
new file mode 100644
index 0000000..6e1e21d
--- /dev/null
+++ b/include/drivers/st/stm32mp_ram.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef STM32MP_RAM_H
+#define STM32MP_RAM_H
+
+#include <stdbool.h>
+
+#include <drivers/st/stm32mp_ddr.h>
+
+#define PARAM(x, y) \
+ { \
+ .name = x, \
+ .offset = offsetof(struct stm32mp_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)
+
+struct stm32mp_ddr_param {
+ const char *name; /* Name in DT */
+ const uint32_t offset; /* Offset in config struct */
+ const uint32_t size; /* Size of parameters */
+};
+
+int stm32mp_ddr_dt_get_info(void *fdt, int node, struct stm32mp_ddr_info *info);
+int stm32mp_ddr_dt_get_param(void *fdt, int node, const struct stm32mp_ddr_param *param,
+ uint32_t param_size, uintptr_t config);
+
+#endif /* STM32MP_RAM_H */
diff --git a/include/drivers/st/stm32mp_reset.h b/include/drivers/st/stm32mp_reset.h
new file mode 100644
index 0000000..8444805
--- /dev/null
+++ b/include/drivers/st/stm32mp_reset.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP_RESET_H
+#define STM32MP_RESET_H
+
+#include <stdint.h>
+
+/*
+ * Assert target reset, if @to_us non null, wait until reset is asserted
+ *
+ * @reset_id: Reset controller ID
+ * @to_us: Timeout in microsecond, or 0 if not waiting
+ * Return 0 on success and -ETIMEDOUT if waiting and timeout expired
+ */
+int stm32mp_reset_assert(uint32_t reset_id, unsigned int to_us);
+
+/*
+ * Enable reset control for target resource
+ *
+ * @reset_id: Reset controller ID
+ */
+static inline void stm32mp_reset_set(uint32_t reset_id)
+{
+ (void)stm32mp_reset_assert(reset_id, 0U);
+}
+
+/*
+ * Deassert target reset, if @to_us non null, wait until reset is deasserted
+ *
+ * @reset_id: Reset controller ID
+ * @to_us: Timeout in microsecond, or 0 if not waiting
+ * Return 0 on success and -ETIMEDOUT if waiting and timeout expired
+ */
+int stm32mp_reset_deassert(uint32_t reset_id, unsigned int to_us);
+
+/*
+ * Release reset control for target resource
+ *
+ * @reset_id: Reset controller ID
+ */
+static inline void stm32mp_reset_release(uint32_t reset_id)
+{
+ (void)stm32mp_reset_deassert(reset_id, 0U);
+}
+
+#endif /* STM32MP_RESET_H */
diff --git a/include/drivers/st/stpmic1.h b/include/drivers/st/stpmic1.h
new file mode 100644
index 0000000..2dfc7f8
--- /dev/null
+++ b/include/drivers/st/stpmic1.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2016-2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STPMIC1_H
+#define STPMIC1_H
+
+#include <drivers/st/stm32_i2c.h>
+#include <lib/utils_def.h>
+
+#define TURN_ON_REG 0x1U
+#define TURN_OFF_REG 0x2U
+#define ICC_LDO_TURN_OFF_REG 0x3U
+#define ICC_BUCK_TURN_OFF_REG 0x4U
+#define RESET_STATUS_REG 0x5U
+#define VERSION_STATUS_REG 0x6U
+#define MAIN_CONTROL_REG 0x10U
+#define PADS_PULL_REG 0x11U
+#define BUCK_PULL_DOWN_REG 0x12U
+#define LDO14_PULL_DOWN_REG 0x13U
+#define LDO56_PULL_DOWN_REG 0x14U
+#define VIN_CONTROL_REG 0x15U
+#define PONKEY_TIMER_REG 0x16U
+#define MASK_RANK_BUCK_REG 0x17U
+#define MASK_RESET_BUCK_REG 0x18U
+#define MASK_RANK_LDO_REG 0x19U
+#define MASK_RESET_LDO_REG 0x1AU
+#define WATCHDOG_CONTROL_REG 0x1BU
+#define WATCHDOG_TIMER_REG 0x1CU
+#define BUCK_ICC_TURNOFF_REG 0x1DU
+#define LDO_ICC_TURNOFF_REG 0x1EU
+#define BUCK_APM_CONTROL_REG 0x1FU
+#define BUCK1_CONTROL_REG 0x20U
+#define BUCK2_CONTROL_REG 0x21U
+#define BUCK3_CONTROL_REG 0x22U
+#define BUCK4_CONTROL_REG 0x23U
+#define VREF_DDR_CONTROL_REG 0x24U
+#define LDO1_CONTROL_REG 0x25U
+#define LDO2_CONTROL_REG 0x26U
+#define LDO3_CONTROL_REG 0x27U
+#define LDO4_CONTROL_REG 0x28U
+#define LDO5_CONTROL_REG 0x29U
+#define LDO6_CONTROL_REG 0x2AU
+#define BUCK1_PWRCTRL_REG 0x30U
+#define BUCK2_PWRCTRL_REG 0x31U
+#define BUCK3_PWRCTRL_REG 0x32U
+#define BUCK4_PWRCTRL_REG 0x33U
+#define VREF_DDR_PWRCTRL_REG 0x34U
+#define LDO1_PWRCTRL_REG 0x35U
+#define LDO2_PWRCTRL_REG 0x36U
+#define LDO3_PWRCTRL_REG 0x37U
+#define LDO4_PWRCTRL_REG 0x38U
+#define LDO5_PWRCTRL_REG 0x39U
+#define LDO6_PWRCTRL_REG 0x3AU
+#define FREQUENCY_SPREADING_REG 0x3BU
+#define USB_CONTROL_REG 0x40U
+#define ITLATCH1_REG 0x50U
+#define ITLATCH2_REG 0x51U
+#define ITLATCH3_REG 0x52U
+#define ITLATCH4_REG 0x53U
+#define ITSETLATCH1_REG 0x60U
+#define ITSETLATCH2_REG 0x61U
+#define ITSETLATCH3_REG 0x62U
+#define ITSETLATCH4_REG 0x63U
+#define ITCLEARLATCH1_REG 0x70U
+#define ITCLEARLATCH2_REG 0x71U
+#define ITCLEARLATCH3_REG 0x72U
+#define ITCLEARLATCH4_REG 0x73U
+#define ITMASK1_REG 0x80U
+#define ITMASK2_REG 0x81U
+#define ITMASK3_REG 0x82U
+#define ITMASK4_REG 0x83U
+#define ITSETMASK1_REG 0x90U
+#define ITSETMASK2_REG 0x91U
+#define ITSETMASK3_REG 0x92U
+#define ITSETMASK4_REG 0x93U
+#define ITCLEARMASK1_REG 0xA0U
+#define ITCLEARMASK2_REG 0xA1U
+#define ITCLEARMASK3_REG 0xA2U
+#define ITCLEARMASK4_REG 0xA3U
+#define ITSOURCE1_REG 0xB0U
+#define ITSOURCE2_REG 0xB1U
+#define ITSOURCE3_REG 0xB2U
+#define ITSOURCE4_REG 0xB3U
+
+/* Registers masks */
+#define LDO_VOLTAGE_MASK GENMASK(6, 2)
+#define BUCK_VOLTAGE_MASK GENMASK(7, 2)
+#define LDO_BUCK_VOLTAGE_SHIFT 2
+#define LDO_BUCK_ENABLE_MASK BIT(0)
+#define LDO_BUCK_HPLP_ENABLE_MASK BIT(1)
+#define LDO_BUCK_HPLP_SHIFT 1
+#define LDO_BUCK_RANK_MASK BIT(0)
+#define LDO_BUCK_RESET_MASK BIT(0)
+#define LDO_BUCK_PULL_DOWN_MASK GENMASK(1, 0)
+
+/* Pull down register */
+#define BUCK1_PULL_DOWN_SHIFT 0
+#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
+
+/* ICC register */
+#define BUCK1_ICC_SHIFT 0
+#define BUCK2_ICC_SHIFT 1
+#define BUCK3_ICC_SHIFT 2
+#define BUCK4_ICC_SHIFT 3
+#define PWR_SW1_ICC_SHIFT 4
+#define PWR_SW2_ICC_SHIFT 5
+#define BOOST_ICC_SHIFT 6
+
+#define LDO1_ICC_SHIFT 0
+#define LDO2_ICC_SHIFT 1
+#define LDO3_ICC_SHIFT 2
+#define LDO4_ICC_SHIFT 3
+#define LDO5_ICC_SHIFT 4
+#define LDO6_ICC_SHIFT 5
+
+/* 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
+
+/* LDO3 Special modes */
+#define LDO3_BYPASS BIT(7)
+#define LDO3_DDR_SEL 31U
+
+/* 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 GENMASK(1, 0)
+#define VINLOW_HYST_SHIFT 4
+#define VINLOW_THRESHOLD_MASK GENMASK(2, 0)
+#define VINLOW_THRESHOLD_SHIFT 1
+#define VINLOW_ENABLED BIT(0)
+#define VINLOW_CTRL_REG_MASK GENMASK(7, 0)
+
+/* USB Control Register */
+#define BOOST_OVP_DISABLED BIT(7)
+#define VBUS_OTG_DETECTION_DISABLED BIT(6)
+#define SW_OUT_DISCHARGE BIT(5)
+#define VBUS_OTG_DISCHARGE BIT(4)
+#define OCP_LIMIT_HIGH BIT(3)
+#define SWIN_SWOUT_ENABLED BIT(2)
+#define USBSW_OTG_SWITCH_ENABLED BIT(1)
+#define BOOST_ENABLED BIT(0)
+
+int stpmic1_powerctrl_on(void);
+int stpmic1_switch_off(void);
+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);
+bool stpmic1_is_regulator_enabled(const char *name);
+int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts);
+int stpmic1_regulator_levels_mv(const char *name, const uint16_t **levels,
+ size_t *levels_count);
+int stpmic1_regulator_voltage_get(const char *name);
+int stpmic1_regulator_pull_down_set(const char *name);
+int stpmic1_regulator_mask_reset_set(const char *name);
+int stpmic1_regulator_icc_set(const char *name);
+int stpmic1_regulator_sink_mode_set(const char *name);
+int stpmic1_regulator_bypass_mode_set(const char *name);
+int stpmic1_active_discharge_mode_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 */
diff --git a/include/drivers/synopsys/dw_mmc.h b/include/drivers/synopsys/dw_mmc.h
new file mode 100644
index 0000000..2004355
--- /dev/null
+++ b/include/drivers/synopsys/dw_mmc.h
@@ -0,0 +1,24 @@
+/*
+ * 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 <drivers/mmc.h>
+
+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 */
diff --git a/include/drivers/ti/uart/uart_16550.h b/include/drivers/ti/uart/uart_16550.h
new file mode 100644
index 0000000..bddd997
--- /dev/null
+++ b/include/drivers/ti/uart/uart_16550.h
@@ -0,0 +1,94 @@
+/*
+ * 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 <drivers/console.h>
+
+/* 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 */
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+/*
+ * 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.
+ * When |clock| has a value of 0, the UART will *not* be initialised. This
+ * means the UART should already be enabled and the baudrate and clock setup
+ * should have been done already, either by platform specific code or by
+ * previous firmware stages. The |baud| parameter will be ignored in this
+ * case as well.
+ */
+int console_16550_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
+ console_t *console);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* UART_16550_H */
diff --git a/include/drivers/ufs.h b/include/drivers/ufs.h
new file mode 100644
index 0000000..1cd1bee
--- /dev/null
+++ b/include/drivers/ufs.h
@@ -0,0 +1,569 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef UFS_H
+#define UFS_H
+
+#include <lib/utils_def.h>
+
+/* 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
+#define HCE_DISABLE 0
+
+/* 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
+
+/* maximum number of retries for a general UIC command */
+#define UFS_UIC_COMMAND_RETRIES 3
+
+/* maximum number of retries for a transfer command */
+#define UFS_CMD_RETRIES 3
+
+/* maximum number of retries for reading UFS capacity */
+#define UFS_READ_CAPACITY_RETRIES 10
+
+/* maximum number of link-startup retries */
+#define DME_LINKSTARTUP_RETRIES 10
+
+#define HCE_ENABLE_OUTER_RETRIES 3
+#define HCE_ENABLE_INNER_RETRIES 50
+#define HCE_ENABLE_TIMEOUT_US 100
+#define HCE_DISABLE_TIMEOUT_US 1000
+
+#define FDEVICEINIT_TIMEOUT_MS 1500
+
+/**
+ * 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 */
diff --git a/include/drivers/usb_device.h b/include/drivers/usb_device.h
new file mode 100644
index 0000000..8fdb6ae
--- /dev/null
+++ b/include/drivers/usb_device.h
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef USB_DEVICE_H
+#define USB_DEVICE_H
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#define USBD_MAX_NUM_INTERFACES 1U
+#define USBD_MAX_NUM_CONFIGURATION 1U
+
+#define USB_LEN_DEV_QUALIFIER_DESC 0x0AU
+#define USB_LEN_DEV_DESC 0x12U
+#define USB_LEN_CFG_DESC 0x09U
+#define USB_LEN_IF_DESC 0x09U
+#define USB_LEN_EP_DESC 0x07U
+#define USB_LEN_OTG_DESC 0x03U
+#define USB_LEN_LANGID_STR_DESC 0x04U
+#define USB_LEN_OTHER_SPEED_DESC_SIZ 0x09U
+
+#define USBD_IDX_LANGID_STR 0x00U
+#define USBD_IDX_MFC_STR 0x01U
+#define USBD_IDX_PRODUCT_STR 0x02U
+#define USBD_IDX_SERIAL_STR 0x03U
+#define USBD_IDX_CONFIG_STR 0x04U
+#define USBD_IDX_INTERFACE_STR 0x05U
+#define USBD_IDX_USER0_STR 0x06U
+
+#define USB_REQ_TYPE_STANDARD 0x00U
+#define USB_REQ_TYPE_CLASS 0x20U
+#define USB_REQ_TYPE_VENDOR 0x40U
+#define USB_REQ_TYPE_MASK 0x60U
+
+#define USB_REQ_RECIPIENT_DEVICE 0x00U
+#define USB_REQ_RECIPIENT_INTERFACE 0x01U
+#define USB_REQ_RECIPIENT_ENDPOINT 0x02U
+#define USB_REQ_RECIPIENT_MASK 0x1FU
+
+#define USB_REQ_DIRECTION 0x80U
+
+#define USB_REQ_GET_STATUS 0x00U
+#define USB_REQ_CLEAR_FEATURE 0x01U
+#define USB_REQ_SET_FEATURE 0x03U
+#define USB_REQ_SET_ADDRESS 0x05U
+#define USB_REQ_GET_DESCRIPTOR 0x06U
+#define USB_REQ_SET_DESCRIPTOR 0x07U
+#define USB_REQ_GET_CONFIGURATION 0x08U
+#define USB_REQ_SET_CONFIGURATION 0x09U
+#define USB_REQ_GET_INTERFACE 0x0AU
+#define USB_REQ_SET_INTERFACE 0x0BU
+#define USB_REQ_SYNCH_FRAME 0x0CU
+
+#define USB_DESC_TYPE_DEVICE 0x01U
+#define USB_DESC_TYPE_CONFIGURATION 0x02U
+#define USB_DESC_TYPE_STRING 0x03U
+#define USB_DESC_TYPE_INTERFACE 0x04U
+#define USB_DESC_TYPE_ENDPOINT 0x05U
+#define USB_DESC_TYPE_DEVICE_QUALIFIER 0x06U
+#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 0x07U
+#define USB_DESC_TYPE_BOS 0x0FU
+
+#define USB_CONFIG_REMOTE_WAKEUP 2U
+#define USB_CONFIG_SELF_POWERED 1U
+
+#define USB_MAX_EP0_SIZE 64U
+
+/* Device Status */
+#define USBD_STATE_DEFAULT 1U
+#define USBD_STATE_ADDRESSED 2U
+#define USBD_STATE_CONFIGURED 3U
+#define USBD_STATE_SUSPENDED 4U
+
+/* EP0 State */
+#define USBD_EP0_IDLE 0U
+#define USBD_EP0_SETUP 1U
+#define USBD_EP0_DATA_IN 2U
+#define USBD_EP0_DATA_OUT 3U
+#define USBD_EP0_STATUS_IN 4U
+#define USBD_EP0_STATUS_OUT 5U
+#define USBD_EP0_STALL 6U
+
+#define USBD_EP_TYPE_CTRL 0U
+#define USBD_EP_TYPE_ISOC 1U
+#define USBD_EP_TYPE_BULK 2U
+#define USBD_EP_TYPE_INTR 3U
+
+#define USBD_OUT_EPNUM_MASK GENMASK(15, 0)
+#define USBD_OUT_COUNT_MASK GENMASK(31, 16)
+#define USBD_OUT_COUNT_SHIFT 16U
+
+/* Number of EP supported, allow to reduce footprint: default max = 15 */
+#ifndef CONFIG_USBD_EP_NB
+#define USBD_EP_NB 15U
+#else
+#define USBD_EP_NB CONFIG_USBD_EP_NB
+#endif
+
+#define LOBYTE(x) ((uint8_t)((x) & 0x00FF))
+#define HIBYTE(x) ((uint8_t)(((x) & 0xFF00) >> 8))
+
+struct usb_setup_req {
+ uint8_t bm_request;
+ uint8_t b_request;
+ uint16_t value;
+ uint16_t index;
+ uint16_t length;
+};
+
+struct usb_handle;
+
+struct usb_class {
+ uint8_t (*init)(struct usb_handle *pdev, uint8_t cfgidx);
+ uint8_t (*de_init)(struct usb_handle *pdev, uint8_t cfgidx);
+ /* Control Endpoints */
+ uint8_t (*setup)(struct usb_handle *pdev, struct usb_setup_req *req);
+ uint8_t (*ep0_tx_sent)(struct usb_handle *pdev);
+ uint8_t (*ep0_rx_ready)(struct usb_handle *pdev);
+ /* Class Specific Endpoints */
+ uint8_t (*data_in)(struct usb_handle *pdev, uint8_t epnum);
+ uint8_t (*data_out)(struct usb_handle *pdev, uint8_t epnum);
+ uint8_t (*sof)(struct usb_handle *pdev);
+ uint8_t (*iso_in_incomplete)(struct usb_handle *pdev, uint8_t epnum);
+ uint8_t (*iso_out_incomplete)(struct usb_handle *pdev, uint8_t epnum);
+};
+
+/* Following USB Device status */
+enum usb_status {
+ USBD_OK = 0U,
+ USBD_BUSY,
+ USBD_FAIL,
+ USBD_TIMEOUT
+};
+
+/* Action to do after IT handling */
+enum usb_action {
+ USB_NOTHING = 0U,
+ USB_DATA_OUT,
+ USB_DATA_IN,
+ USB_SETUP,
+ USB_ENUM_DONE,
+ USB_READ_DATA_PACKET,
+ USB_READ_SETUP_PACKET,
+ USB_RESET,
+ USB_RESUME,
+ USB_SUSPEND,
+ USB_LPM,
+ USB_SOF,
+ USB_DISCONNECT,
+ USB_WRITE_EMPTY
+};
+
+/* USB Device descriptors structure */
+struct usb_desc {
+ uint8_t *(*get_device_desc)(uint16_t *length);
+ uint8_t *(*get_lang_id_desc)(uint16_t *length);
+ uint8_t *(*get_manufacturer_desc)(uint16_t *length);
+ uint8_t *(*get_product_desc)(uint16_t *length);
+ uint8_t *(*get_serial_desc)(uint16_t *length);
+ uint8_t *(*get_configuration_desc)(uint16_t *length);
+ uint8_t *(*get_interface_desc)(uint16_t *length);
+ uint8_t *(*get_usr_desc)(uint8_t index, uint16_t *length);
+ uint8_t *(*get_config_desc)(uint16_t *length);
+ uint8_t *(*get_device_qualifier_desc)(uint16_t *length);
+ /* optional: high speed capable device operating at its other speed */
+ uint8_t *(*get_other_speed_config_desc)(uint16_t *length);
+};
+
+/* USB Device handle structure */
+struct usb_endpoint {
+ uint32_t status;
+ uint32_t total_length;
+ uint32_t rem_length;
+ uint32_t maxpacket;
+};
+
+/*
+ * EndPoint descriptor
+ * num : Endpoint number, between 0 and 15 (limited by USBD_EP_NB)
+ * is_in: Endpoint direction
+ * type : Endpoint type
+ * maxpacket: Endpoint Max packet size: between 0 and 64KB
+ * xfer_buff: Pointer to transfer buffer
+ * xfer_len: Current transfer lengt
+ * hxfer_count: Partial transfer length in case of multi packet transfer
+ */
+struct usbd_ep {
+ uint8_t num;
+ bool is_in;
+ uint8_t type;
+ uint32_t maxpacket;
+ uint8_t *xfer_buff;
+ uint32_t xfer_len;
+ uint32_t xfer_count;
+};
+
+enum pcd_lpm_state {
+ LPM_L0 = 0x00U, /* on */
+ LPM_L1 = 0x01U, /* LPM L1 sleep */
+ LPM_L2 = 0x02U, /* suspend */
+ LPM_L3 = 0x03U, /* off */
+};
+
+/* USB Device descriptors structure */
+struct usb_driver {
+ enum usb_status (*ep0_out_start)(void *handle);
+ enum usb_status (*ep_start_xfer)(void *handle, struct usbd_ep *ep);
+ enum usb_status (*ep0_start_xfer)(void *handle, struct usbd_ep *ep);
+ enum usb_status (*write_packet)(void *handle, uint8_t *src,
+ uint8_t ch_ep_num, uint16_t len);
+ void *(*read_packet)(void *handle, uint8_t *dest, uint16_t len);
+ enum usb_status (*ep_set_stall)(void *handle, struct usbd_ep *ep);
+ enum usb_status (*start_device)(void *handle);
+ enum usb_status (*stop_device)(void *handle);
+ enum usb_status (*set_address)(void *handle, uint8_t address);
+ enum usb_status (*write_empty_tx_fifo)(void *handle,
+ uint32_t epnum, uint32_t xfer_len,
+ uint32_t *xfer_count,
+ uint32_t maxpacket,
+ uint8_t **xfer_buff);
+ enum usb_action (*it_handler)(void *handle, uint32_t *param);
+};
+
+/* USB Peripheral Controller Drivers */
+struct pcd_handle {
+ void *instance; /* Register base address */
+ struct usbd_ep in_ep[USBD_EP_NB]; /* IN endpoint parameters */
+ struct usbd_ep out_ep[USBD_EP_NB]; /* OUT endpoint parameters */
+ uint32_t setup[12]; /* Setup packet buffer */
+ enum pcd_lpm_state lpm_state; /* LPM State */
+};
+
+/* USB Device handle structure */
+struct usb_handle {
+ uint8_t id;
+ uint32_t dev_config;
+ uint32_t dev_config_status;
+ struct usb_endpoint ep_in[USBD_EP_NB];
+ struct usb_endpoint ep_out[USBD_EP_NB];
+ uint32_t ep0_state;
+ uint32_t ep0_data_len;
+ uint8_t dev_state;
+ uint8_t dev_old_state;
+ uint8_t dev_address;
+ uint32_t dev_remote_wakeup;
+ struct usb_setup_req request;
+ const struct usb_desc *desc;
+ struct usb_class *class;
+ void *class_data;
+ void *user_data;
+ struct pcd_handle *data;
+ const struct usb_driver *driver;
+};
+
+enum usb_status usb_core_handle_it(struct usb_handle *pdev);
+enum usb_status usb_core_receive(struct usb_handle *pdev, uint8_t ep_addr,
+ uint8_t *p_buf, uint32_t len);
+enum usb_status usb_core_transmit(struct usb_handle *pdev, uint8_t ep_addr,
+ uint8_t *p_buf, uint32_t len);
+enum usb_status usb_core_receive_ep0(struct usb_handle *pdev, uint8_t *p_buf,
+ uint32_t len);
+enum usb_status usb_core_transmit_ep0(struct usb_handle *pdev, uint8_t *p_buf,
+ uint32_t len);
+void usb_core_ctl_error(struct usb_handle *pdev);
+enum usb_status usb_core_start(struct usb_handle *pdev);
+enum usb_status usb_core_stop(struct usb_handle *pdev);
+enum usb_status register_usb_driver(struct usb_handle *pdev,
+ struct pcd_handle *pcd_handle,
+ const struct usb_driver *driver,
+ void *driver_handle);
+enum usb_status register_platform(struct usb_handle *pdev,
+ const struct usb_desc *plat_call_back);
+
+#endif /* USB_DEVICE_H */
diff --git a/include/dt-bindings/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h
new file mode 100644
index 0000000..0d25ded
--- /dev/null
+++ b/include/dt-bindings/clock/stm32mp1-clks.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
+/*
+ * Copyright (C) STMicroelectronics 2018-2022 - All Rights Reserved
+ * Author: Gabriel Fernandez <gabriel.fernandez@st.com> for STMicroelectronics.
+ */
+
+#if STM32MP13
+#include "stm32mp13-clks.h"
+#endif
+#if STM32MP15
+#include "stm32mp15-clks.h"
+#endif
diff --git a/include/dt-bindings/clock/stm32mp1-clksrc.h b/include/dt-bindings/clock/stm32mp1-clksrc.h
new file mode 100644
index 0000000..d02ddcd
--- /dev/null
+++ b/include/dt-bindings/clock/stm32mp1-clksrc.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
+/*
+ * Copyright (C) 2017-2022, STMicroelectronics - All Rights Reserved
+ */
+
+#if STM32MP13
+#include "stm32mp13-clksrc.h"
+#endif
+#if STM32MP15
+#include "stm32mp15-clksrc.h"
+#endif
diff --git a/include/dt-bindings/clock/stm32mp13-clks.h b/include/dt-bindings/clock/stm32mp13-clks.h
new file mode 100644
index 0000000..1d5bb78
--- /dev/null
+++ b/include/dt-bindings/clock/stm32mp13-clks.h
@@ -0,0 +1,230 @@
+/* SPDX-License-Identifier: GPL-2.0+ or BSD-3-Clause */
+/*
+ * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
+ * Author: Gabriel Fernandez <gabriel.fernandez@st.com> for STMicroelectronics.
+ */
+
+#ifndef _DT_BINDINGS_STM32MP13_CLKS_H_
+#define _DT_BINDINGS_STM32MP13_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
+
+/* PLL */
+#define PLL1 6
+#define PLL2 7
+#define PLL3 8
+#define PLL4 9
+
+/* ODF */
+#define PLL1_P 10
+#define PLL1_Q 11
+#define PLL1_R 12
+#define PLL2_P 13
+#define PLL2_Q 14
+#define PLL2_R 15
+#define PLL3_P 16
+#define PLL3_Q 17
+#define PLL3_R 18
+#define PLL4_P 19
+#define PLL4_Q 20
+#define PLL4_R 21
+
+#define PCLK1 22
+#define PCLK2 23
+#define PCLK3 24
+#define PCLK4 25
+#define PCLK5 26
+#define PCLK6 27
+
+/* SYSTEM CLOCK */
+#define CK_PER 28
+#define CK_MPU 29
+#define CK_AXI 30
+#define CK_MLAHB 31
+
+/* BASE TIMER */
+#define CK_TIMG1 32
+#define CK_TIMG2 33
+#define CK_TIMG3 34
+
+/* AUX */
+#define RTC 35
+
+/* TRACE & DEBUG clocks */
+#define CK_DBG 36
+#define CK_TRACE 37
+
+/* MCO clocks */
+#define CK_MCO1 38
+#define CK_MCO2 39
+
+/* IP clocks */
+#define SYSCFG 40
+#define VREF 41
+#define TMPSENS 42
+#define PMBCTRL 43
+#define HDP 44
+#define IWDG2 45
+#define STGENRO 46
+#define USART1 47
+#define RTCAPB 48
+#define TZC 49
+#define TZPC 50
+#define IWDG1 51
+#define BSEC 52
+#define DMA1 53
+#define DMA2 54
+#define DMAMUX1 55
+#define DMAMUX2 56
+#define GPIOA 57
+#define GPIOB 58
+#define GPIOC 59
+#define GPIOD 60
+#define GPIOE 61
+#define GPIOF 62
+#define GPIOG 63
+#define GPIOH 64
+#define GPIOI 65
+#define CRYP1 66
+#define HASH1 67
+#define BKPSRAM 68
+#define MDMA 69
+#define CRC1 70
+#define USBH 71
+#define DMA3 72
+#define TSC 73
+#define PKA 74
+#define AXIMC 75
+#define MCE 76
+#define ETH1TX 77
+#define ETH2TX 78
+#define ETH1RX 79
+#define ETH2RX 80
+#define ETH1MAC 81
+#define ETH2MAC 82
+#define ETH1STP 83
+#define ETH2STP 84
+
+/* IP clocks with parents */
+#define SDMMC1_K 85
+#define SDMMC2_K 86
+#define ADC1_K 87
+#define ADC2_K 88
+#define FMC_K 89
+#define QSPI_K 90
+#define RNG1_K 91
+#define USBPHY_K 92
+#define STGEN_K 93
+#define SPDIF_K 94
+#define SPI1_K 95
+#define SPI2_K 96
+#define SPI3_K 97
+#define SPI4_K 98
+#define SPI5_K 99
+#define I2C1_K 100
+#define I2C2_K 101
+#define I2C3_K 102
+#define I2C4_K 103
+#define I2C5_K 104
+#define TIM2_K 105
+#define TIM3_K 106
+#define TIM4_K 107
+#define TIM5_K 108
+#define TIM6_K 109
+#define TIM7_K 110
+#define TIM12_K 111
+#define TIM13_K 112
+#define TIM14_K 113
+#define TIM1_K 114
+#define TIM8_K 115
+#define TIM15_K 116
+#define TIM16_K 117
+#define TIM17_K 118
+#define LPTIM1_K 119
+#define LPTIM2_K 120
+#define LPTIM3_K 121
+#define LPTIM4_K 122
+#define LPTIM5_K 123
+#define USART1_K 124
+#define USART2_K 125
+#define USART3_K 126
+#define UART4_K 127
+#define UART5_K 128
+#define USART6_K 129
+#define UART7_K 130
+#define UART8_K 131
+#define DFSDM_K 132
+#define FDCAN_K 133
+#define SAI1_K 134
+#define SAI2_K 135
+#define ADFSDM_K 136
+#define USBO_K 137
+#define LTDC_PX 138
+#define ETH1CK_K 139
+#define ETH1PTP_K 140
+#define ETH2CK_K 141
+#define ETH2PTP_K 142
+#define DCMIPP_K 143
+#define SAES_K 144
+#define DTS_K 145
+
+/* DDR */
+#define DDRC1 146
+#define DDRC1LP 147
+#define DDRC2 148
+#define DDRC2LP 149
+#define DDRPHYC 150
+#define DDRPHYCLP 151
+#define DDRCAPB 152
+#define DDRCAPBLP 153
+#define AXIDCG 154
+#define DDRPHYCAPB 155
+#define DDRPHYCAPBLP 156
+#define DDRPERFM 157
+
+#define ADC1 158
+#define ADC2 159
+#define SAI1 160
+#define SAI2 161
+
+#define STM32MP1_LAST_CLK 162
+
+/* SCMI clock identifiers */
+#define CK_SCMI0_HSE 0
+#define CK_SCMI0_HSI 1
+#define CK_SCMI0_CSI 2
+#define CK_SCMI0_LSE 3
+#define CK_SCMI0_LSI 4
+#define CK_SCMI0_HSE_DIV2 5
+#define CK_SCMI0_PLL2_Q 6
+#define CK_SCMI0_PLL2_R 7
+#define CK_SCMI0_PLL3_P 8
+#define CK_SCMI0_PLL3_Q 9
+#define CK_SCMI0_PLL3_R 10
+#define CK_SCMI0_PLL4_P 11
+#define CK_SCMI0_PLL4_Q 12
+#define CK_SCMI0_PLL4_R 13
+#define CK_SCMI0_MPU 14
+#define CK_SCMI0_AXI 15
+#define CK_SCMI0_MLAHB 16
+#define CK_SCMI0_CKPER 17
+#define CK_SCMI0_PCLK1 18
+#define CK_SCMI0_PCLK2 19
+#define CK_SCMI0_PCLK3 20
+#define CK_SCMI0_PCLK4 21
+#define CK_SCMI0_PCLK5 22
+#define CK_SCMI0_PCLK6 23
+#define CK_SCMI0_CKTIMG1 24
+#define CK_SCMI0_CKTIMG2 25
+#define CK_SCMI0_CKTIMG3 26
+#define CK_SCMI0_RTC 27
+#define CK_SCMI0_RTCAPB 28
+#define CK_SCMI0_BSEC 29
+
+#endif /* _DT_BINDINGS_STM32MP13_CLKS_H_ */
diff --git a/include/dt-bindings/clock/stm32mp13-clksrc.h b/include/dt-bindings/clock/stm32mp13-clksrc.h
new file mode 100644
index 0000000..0d54ab9
--- /dev/null
+++ b/include/dt-bindings/clock/stm32mp13-clksrc.h
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_STM32MP13_CLKSRC_H_
+#define _DT_BINDINGS_CLOCK_STM32MP13_CLKSRC_H_
+
+#define CMD_DIV 0
+#define CMD_MUX 1
+#define CMD_CLK 2
+#define CMD_RESERVED1 3
+
+#define CMD_SHIFT 26
+#define CMD_MASK 0xFC000000
+#define CMD_DATA_MASK 0x03FFFFFF
+
+#define DIV_ID_SHIFT 8
+#define DIV_ID_MASK 0x0000FF00
+
+#define DIV_DIVN_SHIFT 0
+#define DIV_DIVN_MASK 0x000000FF
+
+#define MUX_ID_SHIFT 4
+#define MUX_ID_MASK 0x00000FF0
+
+#define MUX_SEL_SHIFT 0
+#define MUX_SEL_MASK 0x0000000F
+
+#define CLK_ID_MASK GENMASK_32(19, 11)
+#define CLK_ID_SHIFT 11
+#define CLK_ON_MASK 0x00000400
+#define CLK_ON_SHIFT 10
+#define CLK_DIV_MASK GENMASK_32(9, 4)
+#define CLK_DIV_SHIFT 4
+#define CLK_SEL_MASK GENMASK_32(3, 0)
+#define CLK_SEL_SHIFT 0
+
+#define DIV_PLL1DIVP 0
+#define DIV_PLL2DIVP 1
+#define DIV_PLL2DIVQ 2
+#define DIV_PLL2DIVR 3
+#define DIV_PLL3DIVP 4
+#define DIV_PLL3DIVQ 5
+#define DIV_PLL3DIVR 6
+#define DIV_PLL4DIVP 7
+#define DIV_PLL4DIVQ 8
+#define DIV_PLL4DIVR 9
+#define DIV_MPU 10
+#define DIV_AXI 11
+#define DIV_MLAHB 12
+#define DIV_APB1 13
+#define DIV_APB2 14
+#define DIV_APB3 15
+#define DIV_APB4 16
+#define DIV_APB5 17
+#define DIV_APB6 18
+#define DIV_RTC 19
+#define DIV_MCO1 20
+#define DIV_MCO2 21
+#define DIV_HSI 22
+#define DIV_TRACE 23
+#define DIV_ETH1PTP 24
+#define DIV_ETH2PTP 25
+#define DIV_MAX 26
+
+#define DIV(div_id, div) ((CMD_DIV << CMD_SHIFT) |\
+ ((div_id) << DIV_ID_SHIFT |\
+ (div)))
+
+#define CLKSRC(mux_id, sel) ((CMD_MUX << CMD_SHIFT) |\
+ ((mux_id) << MUX_ID_SHIFT |\
+ (sel)))
+
+/* MCO output is enable */
+#define MCO_SRC(mco_id, sel) ((CMD_CLK << CMD_SHIFT) |\
+ (((mco_id) << CLK_ID_SHIFT) |\
+ (sel)) | CLK_ON_MASK)
+
+#define MCO_DISABLED(mco_id) ((CMD_CLK << CMD_SHIFT) |\
+ ((mco_id) << CLK_ID_SHIFT))
+
+/* CLK output is enable */
+#define CLK_SRC(clk_id, sel) ((CMD_CLK << CMD_SHIFT) |\
+ (((clk_id) << CLK_ID_SHIFT) |\
+ (sel)) | CLK_ON_MASK)
+
+#define CLK_DISABLED(clk_id) ((CMD_CLK << CMD_SHIFT) |\
+ ((clk_id) << CLK_ID_SHIFT))
+
+#define MUX_MPU 0
+#define MUX_AXI 1
+#define MUX_MLAHB 2
+#define MUX_PLL12 3
+#define MUX_PLL3 4
+#define MUX_PLL4 5
+#define MUX_RTC 6
+#define MUX_MCO1 7
+#define MUX_MCO2 8
+#define MUX_CKPER 9
+#define MUX_KERNEL_BEGIN 10
+#define MUX_ADC1 10
+#define MUX_ADC2 11
+#define MUX_DCMIPP 12
+#define MUX_ETH1 13
+#define MUX_ETH2 14
+#define MUX_FDCAN 15
+#define MUX_FMC 16
+#define MUX_I2C12 17
+#define MUX_I2C3 18
+#define MUX_I2C4 19
+#define MUX_I2C5 20
+#define MUX_LPTIM1 21
+#define MUX_LPTIM2 22
+#define MUX_LPTIM3 23
+#define MUX_LPTIM45 24
+#define MUX_QSPI 25
+#define MUX_RNG1 26
+#define MUX_SAES 27
+#define MUX_SAI1 28
+#define MUX_SAI2 29
+#define MUX_SDMMC1 30
+#define MUX_SDMMC2 31
+#define MUX_SPDIF 32
+#define MUX_SPI1 33
+#define MUX_SPI23 34
+#define MUX_SPI4 35
+#define MUX_SPI5 36
+#define MUX_STGEN 37
+#define MUX_UART1 38
+#define MUX_UART2 39
+#define MUX_UART35 40
+#define MUX_UART4 41
+#define MUX_UART6 42
+#define MUX_UART78 43
+#define MUX_USBO 44
+#define MUX_USBPHY 45
+#define MUX_MAX 46
+
+#define CLK_MPU_HSI CLKSRC(MUX_MPU, 0)
+#define CLK_MPU_HSE CLKSRC(MUX_MPU, 1)
+#define CLK_MPU_PLL1P CLKSRC(MUX_MPU, 2)
+#define CLK_MPU_PLL1P_DIV CLKSRC(MUX_MPU, 3)
+
+#define CLK_AXI_HSI CLKSRC(MUX_AXI, 0)
+#define CLK_AXI_HSE CLKSRC(MUX_AXI, 1)
+#define CLK_AXI_PLL2P CLKSRC(MUX_AXI, 2)
+
+#define CLK_MLAHBS_HSI CLKSRC(MUX_MLAHB, 0)
+#define CLK_MLAHBS_HSE CLKSRC(MUX_MLAHB, 1)
+#define CLK_MLAHBS_CSI CLKSRC(MUX_MLAHB, 2)
+#define CLK_MLAHBS_PLL3 CLKSRC(MUX_MLAHB, 3)
+
+#define CLK_PLL12_HSI CLKSRC(MUX_PLL12, 0)
+#define CLK_PLL12_HSE CLKSRC(MUX_PLL12, 1)
+
+#define CLK_PLL3_HSI CLKSRC(MUX_PLL3, 0)
+#define CLK_PLL3_HSE CLKSRC(MUX_PLL3, 1)
+#define CLK_PLL3_CSI CLKSRC(MUX_PLL3, 2)
+
+#define CLK_PLL4_HSI CLKSRC(MUX_PLL4, 0)
+#define CLK_PLL4_HSE CLKSRC(MUX_PLL4, 1)
+#define CLK_PLL4_CSI CLKSRC(MUX_PLL4, 2)
+
+#define CLK_RTC_DISABLED CLK_DISABLED(RTC)
+#define CLK_RTC_LSE CLK_SRC(RTC, 1)
+#define CLK_RTC_LSI CLK_SRC(RTC, 2)
+#define CLK_RTC_HSE CLK_SRC(RTC, 3)
+
+#define CLK_MCO1_HSI CLK_SRC(CK_MCO1, 0)
+#define CLK_MCO1_HSE CLK_SRC(CK_MCO1, 1)
+#define CLK_MCO1_CSI CLK_SRC(CK_MCO1, 2)
+#define CLK_MCO1_LSI CLK_SRC(CK_MCO1, 3)
+#define CLK_MCO1_LSE CLK_SRC(CK_MCO1, 4)
+#define CLK_MCO1_DISABLED CLK_DISABLED(CK_MCO1)
+
+#define CLK_MCO2_MPU CLK_SRC(CK_MCO2, 0)
+#define CLK_MCO2_AXI CLK_SRC(CK_MCO2, 1)
+#define CLK_MCO2_MLAHB CLK_SRC(CK_MCO2, 2)
+#define CLK_MCO2_PLL4 CLK_SRC(CK_MCO2, 3)
+#define CLK_MCO2_HSE CLK_SRC(CK_MCO2, 4)
+#define CLK_MCO2_HSI CLK_SRC(CK_MCO2, 5)
+#define CLK_MCO2_DISABLED CLK_DISABLED(CK_MCO2)
+
+#define CLK_CKPER_HSI CLKSRC(MUX_CKPER, 0)
+#define CLK_CKPER_CSI CLKSRC(MUX_CKPER, 1)
+#define CLK_CKPER_HSE CLKSRC(MUX_CKPER, 2)
+#define CLK_CKPER_DISABLED CLKSRC(MUX_CKPER, 3)
+
+#define CLK_I2C12_PCLK1 CLKSRC(MUX_I2C12, 0)
+#define CLK_I2C12_PLL4R CLKSRC(MUX_I2C12, 1)
+#define CLK_I2C12_HSI CLKSRC(MUX_I2C12, 2)
+#define CLK_I2C12_CSI CLKSRC(MUX_I2C12, 3)
+
+#define CLK_I2C3_PCLK6 CLKSRC(MUX_I2C3, 0)
+#define CLK_I2C3_PLL4R CLKSRC(MUX_I2C3, 1)
+#define CLK_I2C3_HSI CLKSRC(MUX_I2C3, 2)
+#define CLK_I2C3_CSI CLKSRC(MUX_I2C3, 3)
+
+#define CLK_I2C4_PCLK6 CLKSRC(MUX_I2C4, 0)
+#define CLK_I2C4_PLL4R CLKSRC(MUX_I2C4, 1)
+#define CLK_I2C4_HSI CLKSRC(MUX_I2C4, 2)
+#define CLK_I2C4_CSI CLKSRC(MUX_I2C4, 3)
+
+#define CLK_I2C5_PCLK6 CLKSRC(MUX_I2C5, 0)
+#define CLK_I2C5_PLL4R CLKSRC(MUX_I2C5, 1)
+#define CLK_I2C5_HSI CLKSRC(MUX_I2C5, 2)
+#define CLK_I2C5_CSI CLKSRC(MUX_I2C5, 3)
+
+#define CLK_SPI1_PLL4P CLKSRC(MUX_SPI1, 0)
+#define CLK_SPI1_PLL3Q CLKSRC(MUX_SPI1, 1)
+#define CLK_SPI1_I2SCKIN CLKSRC(MUX_SPI1, 2)
+#define CLK_SPI1_CKPER CLKSRC(MUX_SPI1, 3)
+#define CLK_SPI1_PLL3R CLKSRC(MUX_SPI1, 4)
+
+#define CLK_SPI23_PLL4P CLKSRC(MUX_SPI23, 0)
+#define CLK_SPI23_PLL3Q CLKSRC(MUX_SPI23, 1)
+#define CLK_SPI23_I2SCKIN CLKSRC(MUX_SPI23, 2)
+#define CLK_SPI23_CKPER CLKSRC(MUX_SPI23, 3)
+#define CLK_SPI23_PLL3R CLKSRC(MUX_SPI23, 4)
+
+#define CLK_SPI4_PCLK6 CLKSRC(MUX_SPI4, 0)
+#define CLK_SPI4_PLL4Q CLKSRC(MUX_SPI4, 1)
+#define CLK_SPI4_HSI CLKSRC(MUX_SPI4, 2)
+#define CLK_SPI4_CSI CLKSRC(MUX_SPI4, 3)
+#define CLK_SPI4_HSE CLKSRC(MUX_SPI4, 4)
+#define CLK_SPI4_I2SCKIN CLKSRC(MUX_SPI4, 5)
+
+#define CLK_SPI5_PCLK6 CLKSRC(MUX_SPI5, 0)
+#define CLK_SPI5_PLL4Q CLKSRC(MUX_SPI5, 1)
+#define CLK_SPI5_HSI CLKSRC(MUX_SPI5, 2)
+#define CLK_SPI5_CSI CLKSRC(MUX_SPI5, 3)
+#define CLK_SPI5_HSE CLKSRC(MUX_SPI5, 4)
+
+#define CLK_UART1_PCLK6 CLKSRC(MUX_UART1, 0)
+#define CLK_UART1_PLL3Q CLKSRC(MUX_UART1, 1)
+#define CLK_UART1_HSI CLKSRC(MUX_UART1, 2)
+#define CLK_UART1_CSI CLKSRC(MUX_UART1, 3)
+#define CLK_UART1_PLL4Q CLKSRC(MUX_UART1, 4)
+#define CLK_UART1_HSE CLKSRC(MUX_UART1, 5)
+
+#define CLK_UART2_PCLK6 CLKSRC(MUX_UART2, 0)
+#define CLK_UART2_PLL3Q CLKSRC(MUX_UART2, 1)
+#define CLK_UART2_HSI CLKSRC(MUX_UART2, 2)
+#define CLK_UART2_CSI CLKSRC(MUX_UART2, 3)
+#define CLK_UART2_PLL4Q CLKSRC(MUX_UART2, 4)
+#define CLK_UART2_HSE CLKSRC(MUX_UART2, 5)
+
+#define CLK_UART35_PCLK1 CLKSRC(MUX_UART35, 0)
+#define CLK_UART35_PLL4Q CLKSRC(MUX_UART35, 1)
+#define CLK_UART35_HSI CLKSRC(MUX_UART35, 2)
+#define CLK_UART35_CSI CLKSRC(MUX_UART35, 3)
+#define CLK_UART35_HSE CLKSRC(MUX_UART35, 4)
+
+#define CLK_UART4_PCLK1 CLKSRC(MUX_UART4, 0)
+#define CLK_UART4_PLL4Q CLKSRC(MUX_UART4, 1)
+#define CLK_UART4_HSI CLKSRC(MUX_UART4, 2)
+#define CLK_UART4_CSI CLKSRC(MUX_UART4, 3)
+#define CLK_UART4_HSE CLKSRC(MUX_UART4, 4)
+
+#define CLK_UART6_PCLK2 CLKSRC(MUX_UART6, 0)
+#define CLK_UART6_PLL4Q CLKSRC(MUX_UART6, 1)
+#define CLK_UART6_HSI CLKSRC(MUX_UART6, 2)
+#define CLK_UART6_CSI CLKSRC(MUX_UART6, 3)
+#define CLK_UART6_HSE CLKSRC(MUX_UART6, 4)
+
+#define CLK_UART78_PCLK1 CLKSRC(MUX_UART78, 0)
+#define CLK_UART78_PLL4Q CLKSRC(MUX_UART78, 1)
+#define CLK_UART78_HSI CLKSRC(MUX_UART78, 2)
+#define CLK_UART78_CSI CLKSRC(MUX_UART78, 3)
+#define CLK_UART78_HSE CLKSRC(MUX_UART78, 4)
+
+#define CLK_LPTIM1_PCLK1 CLKSRC(MUX_LPTIM1, 0)
+#define CLK_LPTIM1_PLL4P CLKSRC(MUX_LPTIM1, 1)
+#define CLK_LPTIM1_PLL3Q CLKSRC(MUX_LPTIM1, 2)
+#define CLK_LPTIM1_LSE CLKSRC(MUX_LPTIM1, 3)
+#define CLK_LPTIM1_LSI CLKSRC(MUX_LPTIM1, 4)
+#define CLK_LPTIM1_CKPER CLKSRC(MUX_LPTIM1, 5)
+
+#define CLK_LPTIM2_PCLK3 CLKSRC(MUX_LPTIM2, 0)
+#define CLK_LPTIM2_PLL4Q CLKSRC(MUX_LPTIM2, 1)
+#define CLK_LPTIM2_CKPER CLKSRC(MUX_LPTIM2, 2)
+#define CLK_LPTIM2_LSE CLKSRC(MUX_LPTIM2, 3)
+#define CLK_LPTIM2_LSI CLKSRC(MUX_LPTIM2, 4)
+
+#define CLK_LPTIM3_PCLK3 CLKSRC(MUX_LPTIM3, 0)
+#define CLK_LPTIM3_PLL4Q CLKSRC(MUX_LPTIM3, 1)
+#define CLK_LPTIM3_CKPER CLKSRC(MUX_LPTIM3, 2)
+#define CLK_LPTIM3_LSE CLKSRC(MUX_LPTIM3, 3)
+#define CLK_LPTIM3_LSI CLKSRC(MUX_LPTIM3, 4)
+
+#define CLK_LPTIM45_PCLK3 CLKSRC(MUX_LPTIM45, 0)
+#define CLK_LPTIM45_PLL4P CLKSRC(MUX_LPTIM45, 1)
+#define CLK_LPTIM45_PLL3Q CLKSRC(MUX_LPTIM45, 2)
+#define CLK_LPTIM45_LSE CLKSRC(MUX_LPTIM45, 3)
+#define CLK_LPTIM45_LSI CLKSRC(MUX_LPTIM45, 4)
+#define CLK_LPTIM45_CKPER CLKSRC(MUX_LPTIM45, 5)
+
+#define CLK_SAI1_PLL4Q CLKSRC(MUX_SAI1, 0)
+#define CLK_SAI1_PLL3Q CLKSRC(MUX_SAI1, 1)
+#define CLK_SAI1_I2SCKIN CLKSRC(MUX_SAI1, 2)
+#define CLK_SAI1_CKPER CLKSRC(MUX_SAI1, 3)
+#define CLK_SAI1_PLL3R CLKSRC(MUX_SAI1, 4)
+
+#define CLK_SAI2_PLL4Q CLKSRC(MUX_SAI2, 0)
+#define CLK_SAI2_PLL3Q CLKSRC(MUX_SAI2, 1)
+#define CLK_SAI2_I2SCKIN CLKSRC(MUX_SAI2, 2)
+#define CLK_SAI2_CKPER CLKSRC(MUX_SAI2, 3)
+#define CLK_SAI2_SPDIF CLKSRC(MUX_SAI2, 4)
+#define CLK_SAI2_PLL3R CLKSRC(MUX_SAI2, 5)
+
+#define CLK_FDCAN_HSE CLKSRC(MUX_FDCAN, 0)
+#define CLK_FDCAN_PLL3Q CLKSRC(MUX_FDCAN, 1)
+#define CLK_FDCAN_PLL4Q CLKSRC(MUX_FDCAN, 2)
+#define CLK_FDCAN_PLL4R CLKSRC(MUX_FDCAN, 3)
+
+#define CLK_SPDIF_PLL4P CLKSRC(MUX_SPDIF, 0)
+#define CLK_SPDIF_PLL3Q CLKSRC(MUX_SPDIF, 1)
+#define CLK_SPDIF_HSI CLKSRC(MUX_SPDIF, 2)
+
+#define CLK_ADC1_PLL4R CLKSRC(MUX_ADC1, 0)
+#define CLK_ADC1_CKPER CLKSRC(MUX_ADC1, 1)
+#define CLK_ADC1_PLL3Q CLKSRC(MUX_ADC1, 2)
+
+#define CLK_ADC2_PLL4R CLKSRC(MUX_ADC2, 0)
+#define CLK_ADC2_CKPER CLKSRC(MUX_ADC2, 1)
+#define CLK_ADC2_PLL3Q CLKSRC(MUX_ADC2, 2)
+
+#define CLK_SDMMC1_HCLK6 CLKSRC(MUX_SDMMC1, 0)
+#define CLK_SDMMC1_PLL3R CLKSRC(MUX_SDMMC1, 1)
+#define CLK_SDMMC1_PLL4P CLKSRC(MUX_SDMMC1, 2)
+#define CLK_SDMMC1_HSI CLKSRC(MUX_SDMMC1, 3)
+
+#define CLK_SDMMC2_HCLK6 CLKSRC(MUX_SDMMC2, 0)
+#define CLK_SDMMC2_PLL3R CLKSRC(MUX_SDMMC2, 1)
+#define CLK_SDMMC2_PLL4P CLKSRC(MUX_SDMMC2, 2)
+#define CLK_SDMMC2_HSI CLKSRC(MUX_SDMMC2, 3)
+
+#define CLK_ETH1_PLL4P CLKSRC(MUX_ETH1, 0)
+#define CLK_ETH1_PLL3Q CLKSRC(MUX_ETH1, 1)
+
+#define CLK_ETH2_PLL4P CLKSRC(MUX_ETH2, 0)
+#define CLK_ETH2_PLL3Q CLKSRC(MUX_ETH2, 1)
+
+#define CLK_USBPHY_HSE CLKSRC(MUX_USBPHY, 0)
+#define CLK_USBPHY_PLL4R CLKSRC(MUX_USBPHY, 1)
+#define CLK_USBPHY_HSE_DIV2 CLKSRC(MUX_USBPHY, 2)
+
+#define CLK_USBO_PLL4R CLKSRC(MUX_USBO, 0)
+#define CLK_USBO_USBPHY CLKSRC(MUX_USBO, 1)
+
+#define CLK_QSPI_ACLK CLKSRC(MUX_QSPI, 0)
+#define CLK_QSPI_PLL3R CLKSRC(MUX_QSPI, 1)
+#define CLK_QSPI_PLL4P CLKSRC(MUX_QSPI, 2)
+#define CLK_QSPI_CKPER CLKSRC(MUX_QSPI, 3)
+
+#define CLK_FMC_ACLK CLKSRC(MUX_FMC, 0)
+#define CLK_FMC_PLL3R CLKSRC(MUX_FMC, 1)
+#define CLK_FMC_PLL4P CLKSRC(MUX_FMC, 2)
+#define CLK_FMC_CKPER CLKSRC(MUX_FMC, 3)
+
+#define CLK_RNG1_CSI CLKSRC(MUX_RNG1, 0)
+#define CLK_RNG1_PLL4R CLKSRC(MUX_RNG1, 1)
+/* WARNING: POSITION 2 OF RNG1 MUX IS RESERVED */
+#define CLK_RNG1_LSI CLKSRC(MUX_RNG1, 3)
+
+#define CLK_STGEN_HSI CLKSRC(MUX_STGEN, 0)
+#define CLK_STGEN_HSE CLKSRC(MUX_STGEN, 1)
+
+#define CLK_DCMIPP_ACLK CLKSRC(MUX_DCMIPP, 0)
+#define CLK_DCMIPP_PLL2Q CLKSRC(MUX_DCMIPP, 1)
+#define CLK_DCMIPP_PLL4P CLKSRC(MUX_DCMIPP, 2)
+#define CLK_DCMIPP_CKPER CLKSRC(MUX_DCMIPP, 3)
+
+#define CLK_SAES_AXI CLKSRC(MUX_SAES, 0)
+#define CLK_SAES_CKPER CLKSRC(MUX_SAES, 1)
+#define CLK_SAES_PLL4R CLKSRC(MUX_SAES, 2)
+#define CLK_SAES_LSI CLKSRC(MUX_SAES, 3)
+
+/* 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))
+
+/* 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 /* _DT_BINDINGS_CLOCK_STM32MP13_CLKSRC_H_ */
diff --git a/include/dt-bindings/clock/stm32mp15-clks.h b/include/dt-bindings/clock/stm32mp15-clks.h
new file mode 100644
index 0000000..bef1368
--- /dev/null
+++ b/include/dt-bindings/clock/stm32mp15-clks.h
@@ -0,0 +1,278 @@
+/* SPDX-License-Identifier: GPL-2.0+ or BSD-3-Clause */
+/*
+ * Copyright (C) STMicroelectronics 2018-2022 - All Rights Reserved
+ * Author: Gabriel Fernandez <gabriel.fernandez@st.com> 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
+
+/* SCMI clock identifiers */
+#define CK_SCMI0_HSE 0
+#define CK_SCMI0_HSI 1
+#define CK_SCMI0_CSI 2
+#define CK_SCMI0_LSE 3
+#define CK_SCMI0_LSI 4
+#define CK_SCMI0_PLL2_Q 5
+#define CK_SCMI0_PLL2_R 6
+#define CK_SCMI0_MPU 7
+#define CK_SCMI0_AXI 8
+#define CK_SCMI0_BSEC 9
+#define CK_SCMI0_CRYP1 10
+#define CK_SCMI0_GPIOZ 11
+#define CK_SCMI0_HASH1 12
+#define CK_SCMI0_I2C4 13
+#define CK_SCMI0_I2C6 14
+#define CK_SCMI0_IWDG1 15
+#define CK_SCMI0_RNG1 16
+#define CK_SCMI0_RTC 17
+#define CK_SCMI0_RTCAPB 18
+#define CK_SCMI0_SPI6 19
+#define CK_SCMI0_USART1 20
+
+#define CK_SCMI1_PLL3_Q 0
+#define CK_SCMI1_PLL3_R 1
+#define CK_SCMI1_MCU 2
+
+#endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */
diff --git a/include/dt-bindings/clock/stm32mp15-clksrc.h b/include/dt-bindings/clock/stm32mp15-clksrc.h
new file mode 100644
index 0000000..3a3792d
--- /dev/null
+++ b/include/dt-bindings/clock/stm32mp15-clksrc.h
@@ -0,0 +1,282 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
+/*
+ * Copyright (C) 2017-2022, STMicroelectronics - All Rights Reserved
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_STM32MP15_CLKSRC_H_
+#define _DT_BINDINGS_CLOCK_STM32MP15_CLKSRC_H_
+
+/* PLL output is enable when x=1, with x=p,q or r */
+#define PQR(p, q, r) (((p) & 1) | (((q) & 1) << 1) | (((r) & 1) << 2))
+
+/* st,clksrc: mandatory clock source */
+#define CLK_MPU_HSI 0x00000200
+#define CLK_MPU_HSE 0x00000201
+#define CLK_MPU_PLL1P 0x00000202
+#define CLK_MPU_PLL1P_DIV 0x00000203
+
+#define CLK_AXI_HSI 0x00000240
+#define CLK_AXI_HSE 0x00000241
+#define CLK_AXI_PLL2P 0x00000242
+
+#define CLK_MCU_HSI 0x00000480
+#define CLK_MCU_HSE 0x00000481
+#define CLK_MCU_CSI 0x00000482
+#define CLK_MCU_PLL3P 0x00000483
+
+#define CLK_PLL12_HSI 0x00000280
+#define CLK_PLL12_HSE 0x00000281
+
+#define CLK_PLL3_HSI 0x00008200
+#define CLK_PLL3_HSE 0x00008201
+#define CLK_PLL3_CSI 0x00008202
+
+#define CLK_PLL4_HSI 0x00008240
+#define CLK_PLL4_HSE 0x00008241
+#define CLK_PLL4_CSI 0x00008242
+#define CLK_PLL4_I2SCKIN 0x00008243
+
+#define CLK_RTC_DISABLED 0x00001400
+#define CLK_RTC_LSE 0x00001401
+#define CLK_RTC_LSI 0x00001402
+#define CLK_RTC_HSE 0x00001403
+
+#define CLK_MCO1_HSI 0x00008000
+#define CLK_MCO1_HSE 0x00008001
+#define CLK_MCO1_CSI 0x00008002
+#define CLK_MCO1_LSI 0x00008003
+#define CLK_MCO1_LSE 0x00008004
+#define CLK_MCO1_DISABLED 0x0000800F
+
+#define CLK_MCO2_MPU 0x00008040
+#define CLK_MCO2_AXI 0x00008041
+#define CLK_MCO2_MCU 0x00008042
+#define CLK_MCO2_PLL4P 0x00008043
+#define CLK_MCO2_HSE 0x00008044
+#define CLK_MCO2_HSI 0x00008045
+#define CLK_MCO2_DISABLED 0x0000804F
+
+/* st,pkcs: peripheral kernel clock source */
+
+#define CLK_I2C12_PCLK1 0x00008C00
+#define CLK_I2C12_PLL4R 0x00008C01
+#define CLK_I2C12_HSI 0x00008C02
+#define CLK_I2C12_CSI 0x00008C03
+#define CLK_I2C12_DISABLED 0x00008C07
+
+#define CLK_I2C35_PCLK1 0x00008C40
+#define CLK_I2C35_PLL4R 0x00008C41
+#define CLK_I2C35_HSI 0x00008C42
+#define CLK_I2C35_CSI 0x00008C43
+#define CLK_I2C35_DISABLED 0x00008C47
+
+#define CLK_I2C46_PCLK5 0x00000C00
+#define CLK_I2C46_PLL3Q 0x00000C01
+#define CLK_I2C46_HSI 0x00000C02
+#define CLK_I2C46_CSI 0x00000C03
+#define CLK_I2C46_DISABLED 0x00000C07
+
+#define CLK_SAI1_PLL4Q 0x00008C80
+#define CLK_SAI1_PLL3Q 0x00008C81
+#define CLK_SAI1_I2SCKIN 0x00008C82
+#define CLK_SAI1_CKPER 0x00008C83
+#define CLK_SAI1_PLL3R 0x00008C84
+#define CLK_SAI1_DISABLED 0x00008C87
+
+#define CLK_SAI2_PLL4Q 0x00008CC0
+#define CLK_SAI2_PLL3Q 0x00008CC1
+#define CLK_SAI2_I2SCKIN 0x00008CC2
+#define CLK_SAI2_CKPER 0x00008CC3
+#define CLK_SAI2_SPDIF 0x00008CC4
+#define CLK_SAI2_PLL3R 0x00008CC5
+#define CLK_SAI2_DISABLED 0x00008CC7
+
+#define CLK_SAI3_PLL4Q 0x00008D00
+#define CLK_SAI3_PLL3Q 0x00008D01
+#define CLK_SAI3_I2SCKIN 0x00008D02
+#define CLK_SAI3_CKPER 0x00008D03
+#define CLK_SAI3_PLL3R 0x00008D04
+#define CLK_SAI3_DISABLED 0x00008D07
+
+#define CLK_SAI4_PLL4Q 0x00008D40
+#define CLK_SAI4_PLL3Q 0x00008D41
+#define CLK_SAI4_I2SCKIN 0x00008D42
+#define CLK_SAI4_CKPER 0x00008D43
+#define CLK_SAI4_PLL3R 0x00008D44
+#define CLK_SAI4_DISABLED 0x00008D47
+
+#define CLK_SPI2S1_PLL4P 0x00008D80
+#define CLK_SPI2S1_PLL3Q 0x00008D81
+#define CLK_SPI2S1_I2SCKIN 0x00008D82
+#define CLK_SPI2S1_CKPER 0x00008D83
+#define CLK_SPI2S1_PLL3R 0x00008D84
+#define CLK_SPI2S1_DISABLED 0x00008D87
+
+#define CLK_SPI2S23_PLL4P 0x00008DC0
+#define CLK_SPI2S23_PLL3Q 0x00008DC1
+#define CLK_SPI2S23_I2SCKIN 0x00008DC2
+#define CLK_SPI2S23_CKPER 0x00008DC3
+#define CLK_SPI2S23_PLL3R 0x00008DC4
+#define CLK_SPI2S23_DISABLED 0x00008DC7
+
+#define CLK_SPI45_PCLK2 0x00008E00
+#define CLK_SPI45_PLL4Q 0x00008E01
+#define CLK_SPI45_HSI 0x00008E02
+#define CLK_SPI45_CSI 0x00008E03
+#define CLK_SPI45_HSE 0x00008E04
+#define CLK_SPI45_DISABLED 0x00008E07
+
+#define CLK_SPI6_PCLK5 0x00000C40
+#define CLK_SPI6_PLL4Q 0x00000C41
+#define CLK_SPI6_HSI 0x00000C42
+#define CLK_SPI6_CSI 0x00000C43
+#define CLK_SPI6_HSE 0x00000C44
+#define CLK_SPI6_PLL3Q 0x00000C45
+#define CLK_SPI6_DISABLED 0x00000C47
+
+#define CLK_UART6_PCLK2 0x00008E40
+#define CLK_UART6_PLL4Q 0x00008E41
+#define CLK_UART6_HSI 0x00008E42
+#define CLK_UART6_CSI 0x00008E43
+#define CLK_UART6_HSE 0x00008E44
+#define CLK_UART6_DISABLED 0x00008E47
+
+#define CLK_UART24_PCLK1 0x00008E80
+#define CLK_UART24_PLL4Q 0x00008E81
+#define CLK_UART24_HSI 0x00008E82
+#define CLK_UART24_CSI 0x00008E83
+#define CLK_UART24_HSE 0x00008E84
+#define CLK_UART24_DISABLED 0x00008E87
+
+#define CLK_UART35_PCLK1 0x00008EC0
+#define CLK_UART35_PLL4Q 0x00008EC1
+#define CLK_UART35_HSI 0x00008EC2
+#define CLK_UART35_CSI 0x00008EC3
+#define CLK_UART35_HSE 0x00008EC4
+#define CLK_UART35_DISABLED 0x00008EC7
+
+#define CLK_UART78_PCLK1 0x00008F00
+#define CLK_UART78_PLL4Q 0x00008F01
+#define CLK_UART78_HSI 0x00008F02
+#define CLK_UART78_CSI 0x00008F03
+#define CLK_UART78_HSE 0x00008F04
+#define CLK_UART78_DISABLED 0x00008F07
+
+#define CLK_UART1_PCLK5 0x00000C80
+#define CLK_UART1_PLL3Q 0x00000C81
+#define CLK_UART1_HSI 0x00000C82
+#define CLK_UART1_CSI 0x00000C83
+#define CLK_UART1_PLL4Q 0x00000C84
+#define CLK_UART1_HSE 0x00000C85
+#define CLK_UART1_DISABLED 0x00000C87
+
+#define CLK_SDMMC12_HCLK6 0x00008F40
+#define CLK_SDMMC12_PLL3R 0x00008F41
+#define CLK_SDMMC12_PLL4P 0x00008F42
+#define CLK_SDMMC12_HSI 0x00008F43
+#define CLK_SDMMC12_DISABLED 0x00008F47
+
+#define CLK_SDMMC3_HCLK2 0x00008F80
+#define CLK_SDMMC3_PLL3R 0x00008F81
+#define CLK_SDMMC3_PLL4P 0x00008F82
+#define CLK_SDMMC3_HSI 0x00008F83
+#define CLK_SDMMC3_DISABLED 0x00008F87
+
+#define CLK_ETH_PLL4P 0x00008FC0
+#define CLK_ETH_PLL3Q 0x00008FC1
+#define CLK_ETH_DISABLED 0x00008FC3
+
+#define CLK_QSPI_ACLK 0x00009000
+#define CLK_QSPI_PLL3R 0x00009001
+#define CLK_QSPI_PLL4P 0x00009002
+#define CLK_QSPI_CKPER 0x00009003
+
+#define CLK_FMC_ACLK 0x00009040
+#define CLK_FMC_PLL3R 0x00009041
+#define CLK_FMC_PLL4P 0x00009042
+#define CLK_FMC_CKPER 0x00009043
+
+#define CLK_FDCAN_HSE 0x000090C0
+#define CLK_FDCAN_PLL3Q 0x000090C1
+#define CLK_FDCAN_PLL4Q 0x000090C2
+#define CLK_FDCAN_PLL4R 0x000090C3
+
+#define CLK_SPDIF_PLL4P 0x00009140
+#define CLK_SPDIF_PLL3Q 0x00009141
+#define CLK_SPDIF_HSI 0x00009142
+#define CLK_SPDIF_DISABLED 0x00009143
+
+#define CLK_CEC_LSE 0x00009180
+#define CLK_CEC_LSI 0x00009181
+#define CLK_CEC_CSI_DIV122 0x00009182
+#define CLK_CEC_DISABLED 0x00009183
+
+#define CLK_USBPHY_HSE 0x000091C0
+#define CLK_USBPHY_PLL4R 0x000091C1
+#define CLK_USBPHY_HSE_DIV2 0x000091C2
+#define CLK_USBPHY_DISABLED 0x000091C3
+
+#define CLK_USBO_PLL4R 0x800091C0
+#define CLK_USBO_USBPHY 0x800091C1
+
+#define CLK_RNG1_CSI 0x00000CC0
+#define CLK_RNG1_PLL4R 0x00000CC1
+#define CLK_RNG1_LSE 0x00000CC2
+#define CLK_RNG1_LSI 0x00000CC3
+
+#define CLK_RNG2_CSI 0x00009200
+#define CLK_RNG2_PLL4R 0x00009201
+#define CLK_RNG2_LSE 0x00009202
+#define CLK_RNG2_LSI 0x00009203
+
+#define CLK_CKPER_HSI 0x00000D00
+#define CLK_CKPER_CSI 0x00000D01
+#define CLK_CKPER_HSE 0x00000D02
+#define CLK_CKPER_DISABLED 0x00000D03
+
+#define CLK_STGEN_HSI 0x00000D40
+#define CLK_STGEN_HSE 0x00000D41
+#define CLK_STGEN_DISABLED 0x00000D43
+
+#define CLK_DSI_DSIPLL 0x00009240
+#define CLK_DSI_PLL4P 0x00009241
+
+#define CLK_ADC_PLL4R 0x00009280
+#define CLK_ADC_CKPER 0x00009281
+#define CLK_ADC_PLL3Q 0x00009282
+#define CLK_ADC_DISABLED 0x00009283
+
+#define CLK_LPTIM45_PCLK3 0x000092C0
+#define CLK_LPTIM45_PLL4P 0x000092C1
+#define CLK_LPTIM45_PLL3Q 0x000092C2
+#define CLK_LPTIM45_LSE 0x000092C3
+#define CLK_LPTIM45_LSI 0x000092C4
+#define CLK_LPTIM45_CKPER 0x000092C5
+#define CLK_LPTIM45_DISABLED 0x000092C7
+
+#define CLK_LPTIM23_PCLK3 0x00009300
+#define CLK_LPTIM23_PLL4Q 0x00009301
+#define CLK_LPTIM23_CKPER 0x00009302
+#define CLK_LPTIM23_LSE 0x00009303
+#define CLK_LPTIM23_LSI 0x00009304
+#define CLK_LPTIM23_DISABLED 0x00009307
+
+#define CLK_LPTIM1_PCLK1 0x00009340
+#define CLK_LPTIM1_PLL4P 0x00009341
+#define CLK_LPTIM1_PLL3Q 0x00009342
+#define CLK_LPTIM1_LSE 0x00009343
+#define CLK_LPTIM1_LSI 0x00009344
+#define CLK_LPTIM1_CKPER 0x00009345
+#define CLK_LPTIM1_DISABLED 0x00009347
+
+/* define for st,pll /csg */
+#define SSCG_MODE_CENTER_SPREAD 0
+#define SSCG_MODE_DOWN_SPREAD 1
+
+/* define for st,drive */
+#define LSEDRV_LOWEST 0
+#define LSEDRV_MEDIUM_LOW 1
+#define LSEDRV_MEDIUM_HIGH 2
+#define LSEDRV_HIGHEST 3
+
+#endif
diff --git a/include/dt-bindings/interrupt-controller/arm-gic.h b/include/dt-bindings/interrupt-controller/arm-gic.h
new file mode 100644
index 0000000..803cd9c
--- /dev/null
+++ b/include/dt-bindings/interrupt-controller/arm-gic.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * This header provides constants for the ARM GIC.
+ */
+
+#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_ARM_GIC_H
+#define _DT_BINDINGS_INTERRUPT_CONTROLLER_ARM_GIC_H
+
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/* interrupt specifier cell 0 */
+
+#define GIC_SPI 0
+#define GIC_PPI 1
+
+/*
+ * Interrupt specifier cell 2.
+ * The flags in irq.h are valid, plus those below.
+ */
+#define GIC_CPU_MASK_RAW(x) ((x) << 8)
+#define GIC_CPU_MASK_SIMPLE(num) GIC_CPU_MASK_RAW((1 << (num)) - 1)
+
+#endif
diff --git a/include/dt-bindings/interrupt-controller/irq.h b/include/dt-bindings/interrupt-controller/irq.h
new file mode 100644
index 0000000..94e7f95
--- /dev/null
+++ b/include/dt-bindings/interrupt-controller/irq.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * This header provides constants for most IRQ bindings.
+ *
+ * Most IRQ bindings include a flags cell as part of the IRQ specifier.
+ * In most cases, the format of the flags cell uses the standard values
+ * defined in this header.
+ */
+
+#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_IRQ_H
+#define _DT_BINDINGS_INTERRUPT_CONTROLLER_IRQ_H
+
+#define IRQ_TYPE_NONE 0
+#define IRQ_TYPE_EDGE_RISING 1
+#define IRQ_TYPE_EDGE_FALLING 2
+#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
+#define IRQ_TYPE_LEVEL_HIGH 4
+#define IRQ_TYPE_LEVEL_LOW 8
+
+#endif
diff --git a/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h
new file mode 100644
index 0000000..1bc2c40
--- /dev/null
+++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved
+ * Author: Torgue Alexandre <alexandre.torgue@st.com> 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 RSVD 0x12
+
+/* 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 STM32MP_PKG_AA 0x1
+#define STM32MP_PKG_AB 0x2
+#define STM32MP_PKG_AC 0x4
+#define STM32MP_PKG_AD 0x8
+
+#endif /* _DT_BINDINGS_STM32_PINFUNC_H */
diff --git a/include/dt-bindings/reset/stm32mp1-resets.h b/include/dt-bindings/reset/stm32mp1-resets.h
new file mode 100644
index 0000000..d40b1a2
--- /dev/null
+++ b/include/dt-bindings/reset/stm32mp1-resets.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
+/*
+ * Copyright (C) 2020-2022, STMicroelectronics - All Rights Reserved
+ */
+
+#if STM32MP13
+#include "stm32mp13-resets.h"
+#endif
+#if STM32MP15
+#include "stm32mp15-resets.h"
+#endif
diff --git a/include/dt-bindings/reset/stm32mp13-resets.h b/include/dt-bindings/reset/stm32mp13-resets.h
new file mode 100644
index 0000000..8a0f80e
--- /dev/null
+++ b/include/dt-bindings/reset/stm32mp13-resets.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
+/*
+ * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
+ * Author: Gabriel Fernandez <gabriel.fernandez@st.com> for STMicroelectronics.
+ */
+
+#ifndef _DT_BINDINGS_STM32MP13_RESET_H_
+#define _DT_BINDINGS_STM32MP13_RESET_H_
+
+#define TIM2_R 13568
+#define TIM3_R 13569
+#define TIM4_R 13570
+#define TIM5_R 13571
+#define TIM6_R 13572
+#define TIM7_R 13573
+#define LPTIM1_R 13577
+#define SPI2_R 13579
+#define SPI3_R 13580
+#define USART3_R 13583
+#define UART4_R 13584
+#define UART5_R 13585
+#define UART7_R 13586
+#define UART8_R 13587
+#define I2C1_R 13589
+#define I2C2_R 13590
+#define SPDIF_R 13594
+#define TIM1_R 13632
+#define TIM8_R 13633
+#define SPI1_R 13640
+#define USART6_R 13645
+#define SAI1_R 13648
+#define SAI2_R 13649
+#define DFSDM_R 13652
+#define FDCAN_R 13656
+#define LPTIM2_R 13696
+#define LPTIM3_R 13697
+#define LPTIM4_R 13698
+#define LPTIM5_R 13699
+#define SYSCFG_R 13707
+#define VREF_R 13709
+#define DTS_R 13712
+#define PMBCTRL_R 13713
+#define LTDC_R 13760
+#define DCMIPP_R 13761
+#define DDRPERFM_R 13768
+#define USBPHY_R 13776
+#define STGEN_R 13844
+#define USART1_R 13888
+#define USART2_R 13889
+#define SPI4_R 13890
+#define SPI5_R 13891
+#define I2C3_R 13892
+#define I2C4_R 13893
+#define I2C5_R 13894
+#define TIM12_R 13895
+#define TIM13_R 13896
+#define TIM14_R 13897
+#define TIM15_R 13898
+#define TIM16_R 13899
+#define TIM17_R 13900
+#define DMA1_R 13952
+#define DMA2_R 13953
+#define DMAMUX1_R 13954
+#define DMA3_R 13955
+#define DMAMUX2_R 13956
+#define ADC1_R 13957
+#define ADC2_R 13958
+#define USBO_R 13960
+#define GPIOA_R 14080
+#define GPIOB_R 14081
+#define GPIOC_R 14082
+#define GPIOD_R 14083
+#define GPIOE_R 14084
+#define GPIOF_R 14085
+#define GPIOG_R 14086
+#define GPIOH_R 14087
+#define GPIOI_R 14088
+#define TSC_R 14095
+#define PKA_R 14146
+#define SAES_R 14147
+#define CRYP1_R 14148
+#define HASH1_R 14149
+#define RNG1_R 14150
+#define AXIMC_R 14160
+#define MDMA_R 14208
+#define MCE_R 14209
+#define ETH1MAC_R 14218
+#define FMC_R 14220
+#define QSPI_R 14222
+#define SDMMC1_R 14224
+#define SDMMC2_R 14225
+#define CRC1_R 14228
+#define USBH_R 14232
+#define ETH2MAC_R 14238
+
+#endif /* _DT_BINDINGS_STM32MP13_RESET_H_ */
diff --git a/include/dt-bindings/reset/stm32mp15-resets.h b/include/dt-bindings/reset/stm32mp15-resets.h
new file mode 100644
index 0000000..2b34864
--- /dev/null
+++ b/include/dt-bindings/reset/stm32mp15-resets.h
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
+/*
+ * Copyright (C) STMicroelectronics 2018-2022 - All Rights Reserved
+ * Author: Gabriel Fernandez <gabriel.fernandez@st.com> for STMicroelectronics.
+ */
+
+#ifndef _DT_BINDINGS_STM32MP15_RESET_H_
+#define _DT_BINDINGS_STM32MP15_RESET_H_
+
+#define MCU_HOLD_BOOT_R 2144
+#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
+
+/* SCMI reset domain identifiers */
+#define RST_SCMI0_SPI6 0
+#define RST_SCMI0_I2C4 1
+#define RST_SCMI0_I2C6 2
+#define RST_SCMI0_USART1 3
+#define RST_SCMI0_STGEN 4
+#define RST_SCMI0_GPIOZ 5
+#define RST_SCMI0_CRYP1 6
+#define RST_SCMI0_HASH1 7
+#define RST_SCMI0_RNG1 8
+#define RST_SCMI0_MDMA 9
+#define RST_SCMI0_MCU 10
+#define RST_SCMI0_MCU_HOLD_BOOT 11
+
+#endif /* _DT_BINDINGS_STM32MP15_RESET_H_ */
diff --git a/include/dt-bindings/soc/st,stm32-etzpc.h b/include/dt-bindings/soc/st,stm32-etzpc.h
new file mode 100644
index 0000000..3f9fb3b
--- /dev/null
+++ b/include/dt-bindings/soc/st,stm32-etzpc.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2017-2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#ifndef _DT_BINDINGS_STM32_ETZPC_H
+#define _DT_BINDINGS_STM32_ETZPC_H
+
+/* DECPROT modes */
+#define DECPROT_S_RW 0x0
+#define DECPROT_NS_R_S_W 0x1
+#define DECPROT_MCU_ISOLATION 0x2
+#define DECPROT_NS_RW 0x3
+
+/* DECPROT lock */
+#define DECPROT_UNLOCK 0x0
+#define DECPROT_LOCK 0x1
+
+#endif /* _DT_BINDINGS_STM32_ETZPC_H */
diff --git a/include/dt-bindings/soc/stm32mp13-tzc400.h b/include/dt-bindings/soc/stm32mp13-tzc400.h
new file mode 100644
index 0000000..1cb2326
--- /dev/null
+++ b/include/dt-bindings/soc/stm32mp13-tzc400.h
@@ -0,0 +1,35 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ *
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ */
+
+#ifndef _DT_BINDINGS_STM32MP13_TZC400_H
+#define _DT_BINDINGS_STM32MP13_TZC400_H
+
+#include <drivers/arm/tzc_common.h>
+
+#define STM32MP1_TZC_A7_ID U(0)
+#define STM32MP1_TZC_LCD_ID U(3)
+#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_DCMIPP_ID U(11)
+#define STM32MP1_TZC_DAP_ID U(15)
+
+#define TZC_REGION_NSEC_ALL_ACCESS_RDWR \
+ (TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_A7_ID) | \
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_LCD_ID) | \
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_MDMA_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_DCMIPP_ID) | \
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DAP_ID))
+
+#endif /* _DT_BINDINGS_STM32MP13_TZC400_H */
diff --git a/include/dt-bindings/soc/stm32mp15-tzc400.h b/include/dt-bindings/soc/stm32mp15-tzc400.h
new file mode 100644
index 0000000..54cd902
--- /dev/null
+++ b/include/dt-bindings/soc/stm32mp15-tzc400.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
+/*
+ * Copyright (C) 2021, STMicroelectronics - All Rights Reserved
+ */
+
+#ifndef _DT_BINDINGS_STM32MP15_TZC400_H
+#define _DT_BINDINGS_STM32MP15_TZC400_H
+
+#include <drivers/arm/tzc_common.h>
+
+#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 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))
+
+#endif /* _DT_BINDINGS_STM32MP15_TZC400_H */
diff --git a/include/export/README b/include/export/README
new file mode 100644
index 0000000..2de8d6b
--- /dev/null
+++ b/include/export/README
@@ -0,0 +1,33 @@
+All 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 <stdint.h> types defined
+ in the ISO C standard (i.e. uint64_t is fine, but not u_register_t). They
+ should still not #include <stdint.h>. Instead, wrapper headers including
+ export headers need to ensure that they #include <stdint.h> 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.)
diff --git a/include/export/common/bl_common_exp.h b/include/export/common/bl_common_exp.h
new file mode 100644
index 0000000..2cc7c54
--- /dev/null
+++ b/include/export/common/bl_common_exp.h
@@ -0,0 +1,95 @@
+/*
+ * 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 */
diff --git a/include/export/common/ep_info_exp.h b/include/export/common/ep_info_exp.h
new file mode 100644
index 0000000..a5bd10a
--- /dev/null
+++ b/include/export/common/ep_info_exp.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2021, 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. Bit 0 and
+ * bit 5 are used to determine the security
+ * state of the image as follows:
+ *
+ * ---------------------------------
+ * Bit 5 | Bit 0 | Security state
+ * ---------------------------------
+ * 0 0 EP_SECURE
+ * 0 1 EP_NON_SECURE
+ * 1 1 EP_REALM
+ */
+#define EP_SECURITY_MASK UL(0x21)
+#define EP_SECURITY_SHIFT UL(0)
+#define EP_SECURE UL(0x0)
+#define EP_NON_SECURE UL(0x1)
+#define EP_REALM UL(0x21)
+
+/* 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 */
diff --git a/include/export/common/param_header_exp.h b/include/export/common/param_header_exp.h
new file mode 100644
index 0000000..15bb6f2
--- /dev/null
+++ b/include/export/common/param_header_exp.h
@@ -0,0 +1,42 @@
+/*
+ * 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 */
diff --git a/include/export/common/tbbr/tbbr_img_def_exp.h b/include/export/common/tbbr/tbbr_img_def_exp.h
new file mode 100644
index 0000000..98a0099
--- /dev/null
+++ b/include/export/common/tbbr/tbbr_img_def_exp.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2019-2022, 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)
+
+/* Encrypted image identifier */
+#define ENC_IMAGE_ID U(30)
+
+/* FW_CONFIG */
+#define FW_CONFIG_ID U(31)
+
+/*
+ * Primary FWU metadata image ID
+ */
+#define FWU_METADATA_IMAGE_ID U(32)
+
+/*
+ * Backup FWU metadata image ID
+ */
+#define BKUP_FWU_METADATA_IMAGE_ID U(33)
+
+/* Realm Monitor Manager (RMM) */
+#define RMM_IMAGE_ID U(34)
+
+/* CCA Content Certificate ID */
+#define CCA_CONTENT_CERT_ID U(35)
+
+/* Core SWD Key Certificate ID */
+#define CORE_SWD_KEY_CERT_ID U(36)
+
+/* Platform Key Certificate ID */
+#define PLAT_KEY_CERT_ID U(37)
+
+/* Max Images */
+#define MAX_IMAGE_IDS U(38)
+
+#endif /* ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_TBBR_TBBR_IMG_DEF_EXP_H */
diff --git a/include/export/drivers/gpio_exp.h b/include/export/drivers/gpio_exp.h
new file mode 100644
index 0000000..e4112a9
--- /dev/null
+++ b/include/export/drivers/gpio_exp.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019-2021, 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
+#define ARM_TF_GPIO_PULL_REPEATER 3
+
+#endif /* ARM_TRUSTED_FIRMWARE_EXPORT_DRIVERS_GPIO_EXP_H */
diff --git a/include/export/lib/bl_aux_params/bl_aux_params_exp.h b/include/export/lib/bl_aux_params/bl_aux_params_exp.h
new file mode 100644
index 0000000..7391dec
--- /dev/null
+++ b/include/export/lib/bl_aux_params/bl_aux_params_exp.h
@@ -0,0 +1,89 @@
+/*
+ * 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 */
diff --git a/include/export/lib/utils_def_exp.h b/include/export/lib/utils_def_exp.h
new file mode 100644
index 0000000..d4a4a85
--- /dev/null
+++ b/include/export/lib/utils_def_exp.h
@@ -0,0 +1,37 @@
+/*
+ * 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 U(_x) U_(_x)
+# 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 */
diff --git a/include/export/plat/mediatek/common/plat_params_exp.h b/include/export/plat/mediatek/common/plat_params_exp.h
new file mode 100644
index 0000000..d650030
--- /dev/null
+++ b/include/export/plat/mediatek/common/plat_params_exp.h
@@ -0,0 +1,19 @@
+/*
+ * 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 */
diff --git a/include/export/plat/rockchip/common/plat_params_exp.h b/include/export/plat/rockchip/common/plat_params_exp.h
new file mode 100644
index 0000000..ccc9cd9
--- /dev/null
+++ b/include/export/plat/rockchip/common/plat_params_exp.h
@@ -0,0 +1,35 @@
+/*
+ * 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 */
diff --git a/include/lib/bakery_lock.h b/include/lib/bakery_lock.h
new file mode 100644
index 0000000..1fece01
--- /dev/null
+++ b/include/lib/bakery_lock.h
@@ -0,0 +1,105 @@
+/*
+ * 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 <platform_def.h>
+
+#define BAKERY_LOCK_MAX_CPUS PLATFORM_CORE_COUNT
+
+#ifndef __ASSEMBLER__
+#include <cdefs.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+/*****************************************************************************
+ * 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 */
diff --git a/include/lib/bl_aux_params/bl_aux_params.h b/include/lib/bl_aux_params/bl_aux_params.h
new file mode 100644
index 0000000..f6ce802
--- /dev/null
+++ b/include/lib/bl_aux_params/bl_aux_params.h
@@ -0,0 +1,30 @@
+/*
+ * 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 <stdbool.h>
+#include <stdint.h>
+
+#include <export/lib/bl_aux_params/bl_aux_params_exp.h>
+
+/*
+ * 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 */
diff --git a/include/lib/cassert.h b/include/lib/cassert.h
new file mode 100644
index 0000000..bbfdfdb
--- /dev/null
+++ b/include/lib/cassert.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CASSERT_H
+#define CASSERT_H
+
+#include <cdefs.h>
+
+/*******************************************************************************
+ * 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 */
diff --git a/include/lib/coreboot.h b/include/lib/coreboot.h
new file mode 100644
index 0000000..0aa6579
--- /dev/null
+++ b/include/lib/coreboot.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef COREBOOT_H
+#define COREBOOT_H
+
+#include <stdint.h>
+
+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;
+
+#define COREBOOT_MAX_MEMRANGES 32 /* libpayload also uses this limit */
+
+typedef struct __packed {
+ uint64_t start;
+ uint64_t size;
+ uint32_t type;
+} coreboot_memrange_t;
+extern coreboot_memrange_t coreboot_memranges[COREBOOT_MAX_MEMRANGES];
+
+typedef enum {
+ CB_MEM_NONE = 0, /* coreboot will never report this */
+ CB_MEM_RAM = 1,
+ CB_MEM_RESERVED = 2,
+ CB_MEM_ACPI = 3,
+ CB_MEM_NVS = 4,
+ CB_MEM_UNUSABLE = 5,
+ CB_MEM_VENDOR_RSVD = 6,
+ CB_MEM_TABLE = 16,
+} coreboot_memory_t;
+
+coreboot_memory_t coreboot_get_memory_type(uintptr_t start, size_t size);
+void coreboot_table_setup(void *base);
+
+#endif /* COREBOOT_H */
diff --git a/include/lib/cpus/aarch32/aem_generic.h b/include/lib/cpus/aarch32/aem_generic.h
new file mode 100644
index 0000000..1d40cec
--- /dev/null
+++ b/include/lib/cpus/aarch32/aem_generic.h
@@ -0,0 +1,15 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/* BASE AEM midr for revision 0 */
+#define BASE_AEM_MIDR U(0x410FD0F0)
+
+#endif /* AEM_GENERIC_H */
diff --git a/include/lib/cpus/aarch32/cortex_a12.h b/include/lib/cpus/aarch32/cortex_a12.h
new file mode 100644
index 0000000..abacdba
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a12.h
@@ -0,0 +1,22 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/*******************************************************************************
+ * 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 */
diff --git a/include/lib/cpus/aarch32/cortex_a15.h b/include/lib/cpus/aarch32/cortex_a15.h
new file mode 100644
index 0000000..9526a9c
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a15.h
@@ -0,0 +1,30 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/*******************************************************************************
+ * 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 */
diff --git a/include/lib/cpus/aarch32/cortex_a17.h b/include/lib/cpus/aarch32/cortex_a17.h
new file mode 100644
index 0000000..89a8eb6
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a17.h
@@ -0,0 +1,27 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/*******************************************************************************
+ * 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 */
diff --git a/include/lib/cpus/aarch32/cortex_a32.h b/include/lib/cpus/aarch32/cortex_a32.h
new file mode 100644
index 0000000..6ddd533
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a32.h
@@ -0,0 +1,22 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/* 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 */
diff --git a/include/lib/cpus/aarch32/cortex_a5.h b/include/lib/cpus/aarch32/cortex_a5.h
new file mode 100644
index 0000000..76703b7
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a5.h
@@ -0,0 +1,22 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/*******************************************************************************
+ * 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 */
diff --git a/include/lib/cpus/aarch32/cortex_a53.h b/include/lib/cpus/aarch32/cortex_a53.h
new file mode 100644
index 0000000..8dd0192
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a53.h
@@ -0,0 +1,73 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/* 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 */
diff --git a/include/lib/cpus/aarch32/cortex_a57.h b/include/lib/cpus/aarch32/cortex_a57.h
new file mode 100644
index 0000000..ffabd61
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a57.h
@@ -0,0 +1,84 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/* 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 */
diff --git a/include/lib/cpus/aarch32/cortex_a7.h b/include/lib/cpus/aarch32/cortex_a7.h
new file mode 100644
index 0000000..730fdb5
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a7.h
@@ -0,0 +1,22 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/*******************************************************************************
+ * 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 */
diff --git a/include/lib/cpus/aarch32/cortex_a72.h b/include/lib/cpus/aarch32/cortex_a72.h
new file mode 100644
index 0000000..4b1af61
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a72.h
@@ -0,0 +1,58 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/* 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 */
diff --git a/include/lib/cpus/aarch32/cortex_a9.h b/include/lib/cpus/aarch32/cortex_a9.h
new file mode 100644
index 0000000..a8c978a
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a9.h
@@ -0,0 +1,33 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/*******************************************************************************
+ * 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 <arch_helpers.h>
+DEFINE_COPROCR_RW_FUNCS(pcr, PCR)
+#endif
+
+#endif /* CORTEX_A9_H */
diff --git a/include/lib/cpus/aarch32/cpu_macros.S b/include/lib/cpus/aarch32/cpu_macros.S
new file mode 100644
index 0000000..a5ae6a4
--- /dev/null
+++ b/include/lib/cpus/aarch32/cpu_macros.S
@@ -0,0 +1,230 @@
+/*
+ * 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 <arch.h>
+#include <lib/cpus/errata_report.h>
+
+#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 */
diff --git a/include/lib/cpus/aarch64/a64fx.h b/include/lib/cpus/aarch64/a64fx.h
new file mode 100644
index 0000000..b7342b0
--- /dev/null
+++ b/include/lib/cpus/aarch64/a64fx.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2022, Fujitsu Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef A64FX_H
+#define A64FX_H
+
+#include <lib/utils_def.h>
+
+/* A64FX midr for revision 0 */
+#define A64FX_MIDR U(0x461f0010)
+
+#endif /* A64FX_H */
diff --git a/include/lib/cpus/aarch64/aem_generic.h b/include/lib/cpus/aarch64/aem_generic.h
new file mode 100644
index 0000000..6bb30a2
--- /dev/null
+++ b/include/lib/cpus/aarch64/aem_generic.h
@@ -0,0 +1,18 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/* 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 */
diff --git a/include/lib/cpus/aarch64/cortex_a35.h b/include/lib/cpus/aarch64/cortex_a35.h
new file mode 100644
index 0000000..5421478
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a35.h
@@ -0,0 +1,29 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/* 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 */
diff --git a/include/lib/cpus/aarch64/cortex_a510.h b/include/lib/cpus/aarch64/cortex_a510.h
new file mode 100644
index 0000000..6af85a8
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a510.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2022, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A510_H
+#define CORTEX_A510_H
+
+#define CORTEX_A510_MIDR U(0x410FD460)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_A510_CPUECTLR_EL1 S3_0_C15_C1_4
+#define CORTEX_A510_CPUECTLR_EL1_READPREFERUNIQUE_SHIFT U(19)
+#define CORTEX_A510_CPUECTLR_EL1_READPREFERUNIQUE_DISABLE U(1)
+#define CORTEX_A510_CPUECTLR_EL1_RSCTL_SHIFT U(23)
+#define CORTEX_A510_CPUECTLR_EL1_NTCTL_SHIFT U(46)
+#define CORTEX_A510_CPUECTLR_EL1_ATOM_EXECALLINSTRNEAR U(2)
+#define CORTEX_A510_CPUECTLR_EL1_ATOM U(38)
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_A510_CPUPWRCTLR_EL1 S3_0_C15_C2_7
+#define CORTEX_A510_CPUPWRCTLR_EL1_CORE_PWRDN_BIT U(1)
+
+/*******************************************************************************
+ * Complex auxiliary control register specific definitions
+ ******************************************************************************/
+#define CORTEX_A510_CMPXACTLR_EL1 S3_0_C15_C1_3
+
+/*******************************************************************************
+ * Auxiliary control register specific definitions
+ ******************************************************************************/
+#define CORTEX_A510_CPUACTLR_EL1 S3_0_C15_C1_0
+#define CORTEX_A510_CPUACTLR_EL1_BIT_17 (ULL(1) << 17)
+#define CORTEX_A510_CPUACTLR_EL1_BIT_38 (ULL(1) << 38)
+
+#endif /* CORTEX_A510_H */ \ No newline at end of file
diff --git a/include/lib/cpus/aarch64/cortex_a53.h b/include/lib/cpus/aarch64/cortex_a53.h
new file mode 100644
index 0000000..54e646c
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a53.h
@@ -0,0 +1,85 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/* 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)
+#define CORTEX_A53_CPUACTLR_EL1_L1PCTL_SHIFT U(13)
+#define CORTEX_A53_CPUACTLR_EL1_L1PCTL (ULL(7) << CORTEX_A53_CPUACTLR_EL1_L1PCTL_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 */
diff --git a/include/lib/cpus/aarch64/cortex_a55.h b/include/lib/cpus/aarch64/cortex_a55.h
new file mode 100644
index 0000000..60ed957
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a55.h
@@ -0,0 +1,48 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/* 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 */
diff --git a/include/lib/cpus/aarch64/cortex_a57.h b/include/lib/cpus/aarch64/cortex_a57.h
new file mode 100644
index 0000000..dc40e31
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a57.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A57_H
+#define CORTEX_A57_H
+
+#include <lib/utils_def.h>
+
+/* 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_EN_NC_LOAD_FWD (ULL(1) << 24)
+#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 */
diff --git a/include/lib/cpus/aarch64/cortex_a65.h b/include/lib/cpus/aarch64/cortex_a65.h
new file mode 100644
index 0000000..0df34c9
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a65.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A65_H
+#define CORTEX_A65_H
+
+#include <lib/utils_def.h>
+
+#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 */
diff --git a/include/lib/cpus/aarch64/cortex_a65ae.h b/include/lib/cpus/aarch64/cortex_a65ae.h
new file mode 100644
index 0000000..bd4a881
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a65ae.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A65AE_H
+#define CORTEX_A65AE_H
+
+#include <lib/utils_def.h>
+
+#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 */
diff --git a/include/lib/cpus/aarch64/cortex_a710.h b/include/lib/cpus/aarch64/cortex_a710.h
new file mode 100644
index 0000000..432e17a
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a710.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A710_H
+#define CORTEX_A710_H
+
+#define CORTEX_A710_MIDR U(0x410FD470)
+
+/* Cortex-A710 loop count for CVE-2022-23960 mitigation */
+#define CORTEX_A710_BHB_LOOP_COUNT U(32)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_A710_CPUECTLR_EL1 S3_0_C15_C1_4
+#define CORTEX_A710_CPUECTLR_EL1_PFSTIDIS_BIT (ULL(1) << 8)
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_A710_CPUPWRCTLR_EL1 S3_0_C15_C2_7
+#define CORTEX_A710_CPUPWRCTLR_EL1_CORE_PWRDN_BIT U(1)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A710_CPUACTLR_EL1 S3_0_C15_C1_0
+#define CORTEX_A710_CPUACTLR_EL1_BIT_46 (ULL(1) << 46)
+#define CORTEX_A710_CPUACTLR_EL1_BIT_22 (ULL(1) << 22)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register 2 specific definitions.
+ ******************************************************************************/
+#define CORTEX_A710_CPUACTLR2_EL1 S3_0_C15_C1_1
+#define CORTEX_A710_CPUACTLR2_EL1_BIT_40 (ULL(1) << 40)
+#define CORTEX_A710_CPUACTLR2_EL1_BIT_36 (ULL(1) << 36)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register 5 specific definitions.
+ ******************************************************************************/
+#define CORTEX_A710_CPUACTLR5_EL1 S3_0_C15_C8_0
+#define CORTEX_A710_CPUACTLR5_EL1_BIT_13 (ULL(1) << 13)
+#define CORTEX_A710_CPUACTLR5_EL1_BIT_17 (ULL(1) << 17)
+#define CORTEX_A710_CPUACTLR5_EL1_BIT_44 (ULL(1) << 44)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A710_CPUECTLR2_EL1 S3_0_C15_C1_5
+#define CORTEX_A710_CPUECTLR2_EL1_PF_MODE_CNSRV ULL(9)
+#define CPUECTLR2_EL1_PF_MODE_LSB U(11)
+#define CPUECTLR2_EL1_PF_MODE_WIDTH U(4)
+
+/*******************************************************************************
+ * CPU Selected Instruction Private register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A710_CPUPSELR_EL3 S3_6_C15_C8_0
+#define CORTEX_A710_CPUPCR_EL3 S3_6_C15_C8_1
+#define CORTEX_A710_CPUPOR_EL3 S3_6_C15_C8_2
+#define CORTEX_A710_CPUPMR_EL3 S3_6_C15_C8_3
+
+#endif /* CORTEX_A710_H */
diff --git a/include/lib/cpus/aarch64/cortex_a72.h b/include/lib/cpus/aarch64/cortex_a72.h
new file mode 100644
index 0000000..1777645
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a72.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A72_H
+#define CORTEX_A72_H
+
+#include <lib/utils_def.h>
+
+/* Cortex-A72 midr for revision 0 */
+#define CORTEX_A72_MIDR U(0x410FD080)
+
+/* Cortex-A72 loop count for CVE-2022-23960 mitigation */
+#define CORTEX_A72_BHB_LOOP_COUNT U(8)
+
+/*******************************************************************************
+ * 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_FORCE_TAG_BANK_CLK_ACTIVE (ULL(1) << 28)
+#define CORTEX_A72_L2ACTLR_FORCE_L2_LOGIC_CLK_ACTIVE (ULL(1) << 27)
+#define CORTEX_A72_L2ACTLR_FORCE_L2_GIC_TIMER_RCG_CLK_ACTIVE (ULL(1) << 26)
+#define CORTEX_A72_L2ACTLR_ENABLE_UNIQUE_CLEAN (ULL(1) << 14)
+#define CORTEX_A72_L2ACTLR_DISABLE_DSB_WITH_NO_DVM_SYNC (ULL(1) << 11)
+#define CORTEX_A72_L2ACTLR_DISABLE_DVM_CMO_BROADCAST (ULL(1) << 8)
+#define CORTEX_A72_L2ACTLR_ENABLE_HAZARD_DETECT_TIMEOUT (ULL(1) << 7)
+#define CORTEX_A72_L2ACTLR_DISABLE_ACE_SH_OR_CHI (ULL(1) << 6)
+
+/*******************************************************************************
+ * 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_DATA_RAM_SETUP_SHIFT U(5)
+#define CORTEX_A72_L2CTLR_TAG_RAM_LATENCY_SHIFT U(6)
+#define CORTEX_A72_L2CTLR_TAG_RAM_SETUP_SHIFT U(9)
+
+#define CORTEX_A72_L2_DATA_RAM_LATENCY_MASK U(0x7)
+#define CORTEX_A72_L2_TAG_RAM_LATENCY_MASK U(0x7)
+#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 */
diff --git a/include/lib/cpus/aarch64/cortex_a73.h b/include/lib/cpus/aarch64/cortex_a73.h
new file mode 100644
index 0000000..271a333
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a73.h
@@ -0,0 +1,45 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/* 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 */
diff --git a/include/lib/cpus/aarch64/cortex_a75.h b/include/lib/cpus/aarch64/cortex_a75.h
new file mode 100644
index 0000000..e5ca1ba
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a75.h
@@ -0,0 +1,55 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/* 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<n> 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 <stdint.h>
+
+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 */
diff --git a/include/lib/cpus/aarch64/cortex_a76.h b/include/lib/cpus/aarch64/cortex_a76.h
new file mode 100644
index 0000000..74fb6e9
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a76.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A76_H
+#define CORTEX_A76_H
+
+#include <lib/utils_def.h>
+
+/* Cortex-A76 MIDR for revision 0 */
+#define CORTEX_A76_MIDR U(0x410fd0b0)
+
+/* Cortex-A76 loop count for CVE-2022-23960 mitigation */
+#define CORTEX_A76_BHB_LOOP_COUNT U(24)
+
+/*******************************************************************************
+ * 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_BIT_2 (ULL(1) << 2)
+
+#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 */
diff --git a/include/lib/cpus/aarch64/cortex_a76ae.h b/include/lib/cpus/aarch64/cortex_a76ae.h
new file mode 100644
index 0000000..0d30f70
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a76ae.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A76AE_H
+#define CORTEX_A76AE_H
+
+#include <lib/utils_def.h>
+
+/* Cortex-A76AE MIDR for revision 0 */
+#define CORTEX_A76AE_MIDR U(0x410FD0E0)
+
+/* Cortex-A76 loop count for CVE-2022-23960 mitigation */
+#define CORTEX_A76AE_BHB_LOOP_COUNT U(24)
+
+/*******************************************************************************
+ * 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 */
diff --git a/include/lib/cpus/aarch64/cortex_a77.h b/include/lib/cpus/aarch64/cortex_a77.h
new file mode 100644
index 0000000..a9b4546
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a77.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A77_H
+#define CORTEX_A77_H
+
+#include <lib/utils_def.h>
+
+/* Cortex-A77 MIDR */
+#define CORTEX_A77_MIDR U(0x410FD0D0)
+
+/* Cortex-A77 loop count for CVE-2022-23960 mitigation */
+#define CORTEX_A77_BHB_LOOP_COUNT U(24)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A77_CPUECTLR_EL1 S3_0_C15_C1_4
+#define CORTEX_A77_CPUECTLR_EL1_BIT_8 (ULL(1) << 8)
+#define CORTEX_A77_CPUECTLR_EL1_BIT_53 (ULL(1) << 53)
+
+/*******************************************************************************
+ * 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)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A77_ACTLR2_EL1 S3_0_C15_C1_1
+#define CORTEX_A77_ACTLR2_EL1_BIT_2 (ULL(1) << 2)
+#define CORTEX_A77_ACTLR2_EL1_BIT_0 ULL(1)
+
+#define CORTEX_A77_CPUPSELR_EL3 S3_6_C15_C8_0
+#define CORTEX_A77_CPUPCR_EL3 S3_6_C15_C8_1
+#define CORTEX_A77_CPUPOR_EL3 S3_6_C15_C8_2
+#define CORTEX_A77_CPUPMR_EL3 S3_6_C15_C8_3
+#define CORTEX_A77_CPUPOR2_EL3 S3_6_C15_C8_4
+#define CORTEX_A77_CPUPMR2_EL3 S3_6_C15_C8_5
+
+#endif /* CORTEX_A77_H */
diff --git a/include/lib/cpus/aarch64/cortex_a78.h b/include/lib/cpus/aarch64/cortex_a78.h
new file mode 100644
index 0000000..31da99e
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a78.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A78_H
+#define CORTEX_A78_H
+
+#include <lib/utils_def.h>
+
+#define CORTEX_A78_MIDR U(0x410FD410)
+
+/* Cortex-A78 loop count for CVE-2022-23960 mitigation */
+#define CORTEX_A78_BHB_LOOP_COUNT U(32)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A78_CPUECTLR_EL1 S3_0_C15_C1_4
+#define CORTEX_A78_CPUECTLR_EL1_BIT_8 (ULL(1) << 8)
+#define CORTEX_A78_CPUECTLR_EL1_PF_MODE_CNSRV ULL(3)
+#define CPUECTLR_EL1_PF_MODE_LSB U(6)
+#define CPUECTLR_EL1_PF_MODE_WIDTH U(2)
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_A78_CPUPWRCTLR_EL1 S3_0_C15_C2_7
+#define CORTEX_A78_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT U(1)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A78_ACTLR_TAM_BIT (ULL(1) << 30)
+
+#define CORTEX_A78_ACTLR2_EL1 S3_0_C15_C1_1
+#define CORTEX_A78_ACTLR2_EL1_BIT_0 (ULL(1) << 0)
+#define CORTEX_A78_ACTLR2_EL1_BIT_1 (ULL(1) << 1)
+#define CORTEX_A78_ACTLR2_EL1_BIT_2 (ULL(1) << 2)
+#define CORTEX_A78_ACTLR2_EL1_BIT_40 (ULL(1) << 40)
+
+/*******************************************************************************
+ * 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_A78_AMU_GROUP0_MASK U(0xF)
+#define CORTEX_A78_AMU_GROUP1_MASK U(0x7)
+
+#endif /* CORTEX_A78_H */
diff --git a/include/lib/cpus/aarch64/cortex_a78_ae.h b/include/lib/cpus/aarch64/cortex_a78_ae.h
new file mode 100644
index 0000000..b68ec1e
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a78_ae.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited. All rights reserved.
+ * Copyright (c) 2021-2022, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A78_AE_H
+#define CORTEX_A78_AE_H
+
+#include <cortex_a78.h>
+
+#define CORTEX_A78_AE_MIDR U(0x410FD420)
+
+/* Cortex-A78AE loop count for CVE-2022-23960 mitigation */
+#define CORTEX_A78_AE_BHB_LOOP_COUNT U(32)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A78_AE_CPUECTLR_EL1 CORTEX_A78_CPUECTLR_EL1
+#define CORTEX_A78_AE_CPUECTLR_EL1_BIT_8 CORTEX_A78_CPUECTLR_EL1_BIT_8
+
+/*******************************************************************************
+ * CPU Auxiliary Control register 2 specific definitions.
+ ******************************************************************************/
+#define CORTEX_A78_AE_ACTLR2_EL1 CORTEX_A78_ACTLR2_EL1
+#define CORTEX_A78_AE_ACTLR2_EL1_BIT_0 CORTEX_A78_ACTLR2_EL1_BIT_0
+#define CORTEX_A78_AE_ACTLR2_EL1_BIT_40 CORTEX_A78_ACTLR2_EL1_BIT_40
+
+#endif /* CORTEX_A78_AE_H */
diff --git a/include/lib/cpus/aarch64/cortex_a78c.h b/include/lib/cpus/aarch64/cortex_a78c.h
new file mode 100644
index 0000000..35e543c
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a78c.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A78C_H
+#define CORTEX_A78C_H
+
+
+#define CORTEX_A78C_MIDR U(0x410FD4B1)
+
+/* Cortex-A76 loop count for CVE-2022-23960 mitigation */
+#define CORTEX_A78C_BHB_LOOP_COUNT U(32)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register 2 specific definitions.
+ * ****************************************************************************/
+#define CORTEX_A78C_CPUACTLR2_EL1 S3_0_C15_C1_1
+#define CORTEX_A78C_CPUACTLR2_EL1_BIT_0 (ULL(1) << 0)
+#define CORTEX_A78C_CPUACTLR2_EL1_BIT_40 (ULL(1) << 40)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A78C_CPUECTLR_EL1 S3_0_C15_C1_4
+#define CORTEX_A78C_CPUECTLR_EL1_BIT_6 (ULL(1) << 6)
+#define CORTEX_A78C_CPUECTLR_EL1_BIT_7 (ULL(1) << 7)
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_A78C_CPUPWRCTLR_EL1 S3_0_C15_C2_7
+#define CORTEX_A78C_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT U(1)
+
+/*******************************************************************************
+ * CPU Implementation Specific Selected Instruction registers
+ ******************************************************************************/
+#define CORTEX_A78C_IMP_CPUPSELR_EL3 S3_6_C15_C8_0
+#define CORTEX_A78C_IMP_CPUPCR_EL3 S3_6_C15_C8_1
+#define CORTEX_A78C_IMP_CPUPOR_EL3 S3_6_C15_C8_2
+#define CORTEX_A78C_IMP_CPUPMR_EL3 S3_6_C15_C8_3
+
+#endif /* CORTEX_A78C_H */
diff --git a/include/lib/cpus/aarch64/cortex_hayes.h b/include/lib/cpus/aarch64/cortex_hayes.h
new file mode 100644
index 0000000..82022e9
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_hayes.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_HAYES_H
+#define CORTEX_HAYES_H
+
+#define CORTEX_HAYES_MIDR U(0x410FD800)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_HAYES_CPUECTLR_EL1 S3_0_C15_C1_4
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_HAYES_CPUPWRCTLR_EL1 S3_0_C15_C2_7
+#define CORTEX_HAYES_CPUPWRCTLR_EL1_CORE_PWRDN_BIT U(1)
+
+#endif /* CORTEX_HAYES_H */
diff --git a/include/lib/cpus/aarch64/cortex_hunter.h b/include/lib/cpus/aarch64/cortex_hunter.h
new file mode 100644
index 0000000..24bd217
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_hunter.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_HUNTER_H
+#define CORTEX_HUNTER_H
+
+#define CORTEX_HUNTER_MIDR U(0x410FD810)
+
+/* Cortex Hunter loop count for CVE-2022-23960 mitigation */
+#define CORTEX_HUNTER_BHB_LOOP_COUNT U(132)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_HUNTER_CPUECTLR_EL1 S3_0_C15_C1_4
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_HUNTER_CPUPWRCTLR_EL1 S3_0_C15_C2_7
+#define CORTEX_HUNTER_CPUPWRCTLR_EL1_CORE_PWRDN_BIT U(1)
+
+#endif /* CORTEX_HUNTER_H */
diff --git a/include/lib/cpus/aarch64/cortex_hunter_elp_arm.h b/include/lib/cpus/aarch64/cortex_hunter_elp_arm.h
new file mode 100644
index 0000000..f9bb0f3
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_hunter_elp_arm.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_HUNTER_ELP_ARM_H
+#define CORTEX_HUNTER_ELP_ARM_H
+
+#define CORTEX_HUNTER_ELP_ARM_MIDR U(0x410FD821)
+
+/* Cortex Hunter ELP loop count for CVE-2022-23960 mitigation */
+#define CORTEX_HUNTER_ELP_ARM_BHB_LOOP_COUNT U(132)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_HUNTER_ELP_ARM_CPUECTLR_EL1 S3_0_C15_C1_4
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_HUNTER_ELP_ARM_CPUPWRCTLR_EL1 S3_0_C15_C2_7
+#define CORTEX_HUNTER_ELP_ARM_CPUPWRCTLR_EL1_CORE_PWRDN_BIT U(1)
+
+#endif /* CORTEX_HUNTER_ELP_ARM_H */
diff --git a/include/lib/cpus/aarch64/cortex_makalu.h b/include/lib/cpus/aarch64/cortex_makalu.h
new file mode 100644
index 0000000..ee59657
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_makalu.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_MAKALU_H
+#define CORTEX_MAKALU_H
+
+#define CORTEX_MAKALU_MIDR U(0x410FD4D0)
+
+/* Cortex Makalu loop count for CVE-2022-23960 mitigation */
+#define CORTEX_MAKALU_BHB_LOOP_COUNT U(38)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_MAKALU_CPUECTLR_EL1 S3_0_C15_C1_4
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_MAKALU_CPUPWRCTLR_EL1 S3_0_C15_C2_7
+#define CORTEX_MAKALU_CPUPWRCTLR_EL1_CORE_PWRDN_BIT U(1)
+
+#endif /* CORTEX_MAKALU_H */
diff --git a/include/lib/cpus/aarch64/cortex_x1.h b/include/lib/cpus/aarch64/cortex_x1.h
new file mode 100644
index 0000000..e3661a8
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_x1.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2022, Google LLC. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_X1_H
+#define CORTEX_X1_H
+
+/* Cortex-X1 MIDR for r1p0 */
+#define CORTEX_X1_MIDR U(0x411fd440)
+
+/* Cortex-X1 loop count for CVE-2022-23960 mitigation */
+#define CORTEX_X1_BHB_LOOP_COUNT U(32)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_X1_CPUECTLR_EL1 S3_0_C15_C1_4
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_X1_ACTLR2_EL1 S3_0_C15_C1_1
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_X1_CPUPWRCTLR_EL1 S3_0_C15_C2_7
+#define CORTEX_X1_CORE_PWRDN_EN_MASK U(0x1)
+
+#endif /* CORTEX_X1_H */
diff --git a/include/lib/cpus/aarch64/cortex_x2.h b/include/lib/cpus/aarch64/cortex_x2.h
new file mode 100644
index 0000000..863b8c8
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_x2.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_X2_H
+#define CORTEX_X2_H
+
+#define CORTEX_X2_MIDR U(0x410FD480)
+
+/* Cortex-X2 loop count for CVE-2022-23960 mitigation */
+#define CORTEX_X2_BHB_LOOP_COUNT U(32)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_X2_CPUECTLR_EL1 S3_0_C15_C1_4
+#define CORTEX_X2_CPUECTLR_EL1_PFSTIDIS_BIT (ULL(1) << 8)
+
+/*******************************************************************************
+ * CPU Extended Control register 2 specific definitions
+ ******************************************************************************/
+#define CORTEX_X2_CPUECTLR2_EL1 S3_0_C15_C1_5
+
+#define CORTEX_X2_CPUECTLR2_EL1_PF_MODE_SHIFT U(11)
+#define CORTEX_X2_CPUECTLR2_EL1_PF_MODE_WIDTH U(4)
+#define CORTEX_X2_CPUECTLR2_EL1_PF_MODE_CNSRV ULL(0x9)
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_X2_CPUPWRCTLR_EL1 S3_0_C15_C2_7
+#define CORTEX_X2_CPUPWRCTLR_EL1_CORE_PWRDN_BIT U(1)
+
+/*******************************************************************************
+ * CPU Auxiliary Control Register definitions
+ ******************************************************************************/
+#define CORTEX_X2_CPUACTLR_EL1 S3_0_C15_C1_0
+#define CORTEX_X2_CPUACTLR_EL1_BIT_22 (ULL(1) << 22)
+
+/*******************************************************************************
+ * CPU Auxiliary Control Register 2 definitions
+ ******************************************************************************/
+#define CORTEX_X2_CPUACTLR2_EL1 S3_0_C15_C1_1
+#define CORTEX_X2_CPUACTLR2_EL1_BIT_40 (ULL(1) << 40)
+
+/*******************************************************************************
+ * CPU Auxiliary Control Register 5 definitions
+ ******************************************************************************/
+#define CORTEX_X2_CPUACTLR5_EL1 S3_0_C15_C8_0
+#define CORTEX_X2_CPUACTLR5_EL1_BIT_17 (ULL(1) << 17)
+
+/*******************************************************************************
+ * CPU Implementation Specific Selected Instruction registers
+ ******************************************************************************/
+#define CORTEX_X2_IMP_CPUPSELR_EL3 S3_6_C15_C8_0
+#define CORTEX_X2_IMP_CPUPCR_EL3 S3_6_C15_C8_1
+#define CORTEX_X2_IMP_CPUPOR_EL3 S3_6_C15_C8_2
+#define CORTEX_X2_IMP_CPUPMR_EL3 S3_6_C15_C8_3
+
+#endif /* CORTEX_X2_H */
diff --git a/include/lib/cpus/aarch64/cortex_x3.h b/include/lib/cpus/aarch64/cortex_x3.h
new file mode 100644
index 0000000..076a87b
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_x3.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_X3_H
+#define CORTEX_X3_H
+
+#define CORTEX_X3_MIDR U(0x410FD4E0)
+
+/* Cortex-X3 loop count for CVE-2022-23960 mitigation */
+#define CORTEX_X3_BHB_LOOP_COUNT U(132)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_X3_CPUECTLR_EL1 S3_0_C15_C1_4
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_X3_CPUPWRCTLR_EL1 S3_0_C15_C2_7
+#define CORTEX_X3_CPUPWRCTLR_EL1_CORE_PWRDN_BIT U(1)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register 2 specific definitions.
+ ******************************************************************************/
+#define CORTEX_X3_CPUACTLR2_EL1 S3_0_C15_C1_1
+#define CORTEX_X3_CPUACTLR2_EL1_BIT_36 (ULL(1) << 36)
+
+#endif /* CORTEX_X3_H */
diff --git a/include/lib/cpus/aarch64/cpu_macros.S b/include/lib/cpus/aarch64/cpu_macros.S
new file mode 100644
index 0000000..92e65ae
--- /dev/null
+++ b/include/lib/cpus/aarch64/cpu_macros.S
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2014-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef CPU_MACROS_S
+#define CPU_MACROS_S
+
+#include <arch.h>
+#include <assert_macros.S>
+#include <lib/cpus/errata_report.h>
+
+#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
+#define CPU_NO_EXTRA3_FUNC 0
+
+/* Word size for 64-bit CPUs */
+#define CPU_WORD_SIZE 8
+
+/*
+ * 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_EXTRA3_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_EXTRA3_FUNC, CPU_EXTRA2_FUNC + CPU_EXTRA2_FUNC_SIZE
+ .equ CPU_E_HANDLER_FUNC, CPU_EXTRA3_FUNC + CPU_EXTRA3_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.
+ * _extra3:
+ * 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-2022-23960 needs to be applied or not.
+ * _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, _extra3: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 \_extra3
+ .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, 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, 0, \_e_handler, \_power_down_ops
+ .endm
+
+ .macro declare_cpu_ops_wa _name:req, _midr:req, \
+ _resetfunc:req, _extra1:req, _extra2:req, \
+ _extra3:req, _power_down_ops:vararg
+ declare_cpu_ops_base \_name, \_midr, \_resetfunc, \
+ \_extra1, \_extra2, \_extra3, 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 */
diff --git a/include/lib/cpus/aarch64/cpuamu.h b/include/lib/cpus/aarch64/cpuamu.h
new file mode 100644
index 0000000..463f890
--- /dev/null
+++ b/include/lib/cpus/aarch64/cpuamu.h
@@ -0,0 +1,48 @@
+/*
+ * 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 <stdint.h>
+
+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 */
diff --git a/include/lib/cpus/aarch64/denver.h b/include/lib/cpus/aarch64/denver.h
new file mode 100644
index 0000000..24b6a87
--- /dev/null
+++ b/include/lib/cpus/aarch64/denver.h
@@ -0,0 +1,54 @@
+/*
+ * 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)
+#define DENVER_MIDR_PN5 U(0x4E0F0050)
+#define DENVER_MIDR_PN6 U(0x4E0F0060)
+#define DENVER_MIDR_PN7 U(0x4E0F0070)
+#define DENVER_MIDR_PN8 U(0x4E0F0080)
+#define DENVER_MIDR_PN9 U(0x4E0F0090)
+
+/* 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)
+
+/* ACTRL_ELx bits to enable dual execution*/
+#define DENVER_CPU_ENABLE_DUAL_EXEC_EL2 (ULL(1) << 9)
+#define DENVER_CPU_ENABLE_DUAL_EXEC_EL3 (ULL(1) << 9)
+#define DENVER_CPU_ENABLE_DUAL_EXEC_EL1 (U(1) << 4)
+
+#ifndef __ASSEMBLER__
+
+/* Disable Dynamic Code Optimisation */
+void denver_disable_dco(void);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* DENVER_H */
diff --git a/include/lib/cpus/aarch64/dsu_def.h b/include/lib/cpus/aarch64/dsu_def.h
new file mode 100644
index 0000000..577de61
--- /dev/null
+++ b/include/lib/cpus/aarch64/dsu_def.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DSU_DEF_H
+#define DSU_DEF_H
+
+#include <lib/utils_def.h>
+
+/********************************************************************
+ * 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)
+#define CLUSTERACTLR_EL1_DISABLE_SCLK_GATING (ULL(3) << 15)
+
+/********************************************************************
+ * Masks applied for DSU errata workarounds
+ ********************************************************************/
+#define DSU_ERRATA_936184_MASK (U(0x3) << 15)
+
+#endif /* DSU_DEF_H */
diff --git a/include/lib/cpus/aarch64/generic.h b/include/lib/cpus/aarch64/generic.h
new file mode 100644
index 0000000..53df587
--- /dev/null
+++ b/include/lib/cpus/aarch64/generic.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserverd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AARCH64_GENERIC_H
+#define AARCH64_GENERIC_H
+
+#include <lib/utils_def.h>
+
+/*
+ * 0x0 value on the MIDR implementer value is reserved for software use,
+ * so use an MIDR value of 0 for a default CPU library.
+ */
+#define AARCH64_GENERIC_MIDR U(0)
+
+#endif /* AARCH64_GENERIC_H */
diff --git a/include/lib/cpus/aarch64/neoverse_e1.h b/include/lib/cpus/aarch64/neoverse_e1.h
new file mode 100644
index 0000000..96b4661
--- /dev/null
+++ b/include/lib/cpus/aarch64/neoverse_e1.h
@@ -0,0 +1,31 @@
+/*
+ * 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 <lib/utils_def.h>
+
+#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 */
diff --git a/include/lib/cpus/aarch64/neoverse_n1.h b/include/lib/cpus/aarch64/neoverse_n1.h
new file mode 100644
index 0000000..b6b8d8d
--- /dev/null
+++ b/include/lib/cpus/aarch64/neoverse_n1.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NEOVERSE_N1_H
+#define NEOVERSE_N1_H
+
+#include <lib/utils_def.h>
+
+/* Neoverse N1 MIDR for revision 0 */
+#define NEOVERSE_N1_MIDR U(0x410fd0c0)
+
+/* Neoverse N1 loop count for CVE-2022-23960 mitigation */
+#define NEOVERSE_N1_BHB_LOOP_COUNT U(24)
+
+/* 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)
+#define NEOVERSE_N1_CPUECTLR_EL1_EXTLLC_BIT (ULL(1) << 0)
+
+/*******************************************************************************
+ * 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 */
diff --git a/include/lib/cpus/aarch64/neoverse_n2.h b/include/lib/cpus/aarch64/neoverse_n2.h
new file mode 100644
index 0000000..cb1be5b
--- /dev/null
+++ b/include/lib/cpus/aarch64/neoverse_n2.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NEOVERSE_N2_H
+#define NEOVERSE_N2_H
+
+/* Neoverse N2 ID register for revision r0p0 */
+#define NEOVERSE_N2_MIDR U(0x410FD490)
+
+/* Neoverse N2 loop count for CVE-2022-23960 mitigation */
+#define NEOVERSE_N2_BHB_LOOP_COUNT U(32)
+
+/*******************************************************************************
+ * CPU Power control register
+ ******************************************************************************/
+#define NEOVERSE_N2_CPUPWRCTLR_EL1 S3_0_C15_C2_7
+#define NEOVERSE_N2_CORE_PWRDN_EN_BIT (ULL(1) << 0)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define NEOVERSE_N2_CPUECTLR_EL1 S3_0_C15_C1_4
+#define NEOVERSE_N2_CPUECTLR_EL1_EXTLLC_BIT (ULL(1) << 0)
+#define NEOVERSE_N2_CPUECTLR_EL1_PFSTIDIS_BIT (ULL(1) << 8)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define NEOVERSE_N2_CPUACTLR_EL1 S3_0_C15_C1_0
+#define NEOVERSE_N2_CPUACTLR_EL1_BIT_46 (ULL(1) << 46)
+#define NEOVERSE_N2_CPUACTLR_EL1_BIT_22 (ULL(1) << 22)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register 2 specific definitions.
+ ******************************************************************************/
+#define NEOVERSE_N2_CPUACTLR2_EL1 S3_0_C15_C1_1
+#define NEOVERSE_N2_CPUACTLR2_EL1_BIT_0 (ULL(1) << 0)
+#define NEOVERSE_N2_CPUACTLR2_EL1_BIT_2 (ULL(1) << 2)
+#define NEOVERSE_N2_CPUACTLR2_EL1_BIT_36 (ULL(1) << 36)
+#define NEOVERSE_N2_CPUACTLR2_EL1_BIT_40 (ULL(1) << 40)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register 5 specific definitions.
+ ******************************************************************************/
+#define NEOVERSE_N2_CPUACTLR5_EL1 S3_0_C15_C8_0
+#define NEOVERSE_N2_CPUACTLR5_EL1_BIT_44 (ULL(1) << 44)
+#define NEOVERSE_N2_CPUACTLR5_EL1_BIT_13 (ULL(1) << 13)
+#define NEOVERSE_N2_CPUACTLR5_EL1_BIT_17 (ULL(1) << 17)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define NEOVERSE_N2_CPUECTLR2_EL1 S3_0_C15_C1_5
+#define NEOVERSE_N2_CPUECTLR2_EL1_PF_MODE_CNSRV ULL(9)
+#define CPUECTLR2_EL1_PF_MODE_LSB U(11)
+#define CPUECTLR2_EL1_PF_MODE_WIDTH U(4)
+
+#endif /* NEOVERSE_N2_H */
diff --git a/include/lib/cpus/aarch64/neoverse_n_common.h b/include/lib/cpus/aarch64/neoverse_n_common.h
new file mode 100644
index 0000000..7cb91cd
--- /dev/null
+++ b/include/lib/cpus/aarch64/neoverse_n_common.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NEOVERSE_N_COMMON_H
+#define NEOVERSE_N_COMMON_H
+
+/******************************************************************************
+ * Neoverse Nx CPU Configuration register definitions
+ *****************************************************************************/
+#define CPUCFR_EL1 S3_0_C15_C0_0
+
+/* SCU bit of CPU Configuration Register, EL1 */
+#define SCU_SHIFT U(2)
+
+#endif /* NEOVERSE_N_COMMON_H */
diff --git a/include/lib/cpus/aarch64/neoverse_poseidon.h b/include/lib/cpus/aarch64/neoverse_poseidon.h
new file mode 100644
index 0000000..798ecd1
--- /dev/null
+++ b/include/lib/cpus/aarch64/neoverse_poseidon.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2022, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NEOVERSE_POSEIDON_H
+#define NEOVERSE_POSEIDON_H
+
+
+#define NEOVERSE_POSEIDON_MIDR U(0x410FD830)
+
+/* Neoverse Poseidon loop count for CVE-2022-23960 mitigation */
+#define NEOVERSE_POSEIDON_BHB_LOOP_COUNT U(132)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define NEOVERSE_POSEIDON_CPUECTLR_EL1 S3_0_C15_C1_4
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define NEOVERSE_POSEIDON_CPUPWRCTLR_EL1 S3_0_C15_C2_7
+#define NEOVERSE_POSEIDON_CPUPWRCTLR_EL1_CORE_PWRDN_BIT U(1)
+
+#endif /* NEOVERSE_POSEIDON_H */
diff --git a/include/lib/cpus/aarch64/neoverse_v1.h b/include/lib/cpus/aarch64/neoverse_v1.h
new file mode 100644
index 0000000..9c7e967
--- /dev/null
+++ b/include/lib/cpus/aarch64/neoverse_v1.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NEOVERSE_V1_H
+#define NEOVERSE_V1_H
+
+#define NEOVERSE_V1_MIDR U(0x410FD400)
+
+/* Neoverse V1 loop count for CVE-2022-23960 mitigation */
+#define NEOVERSE_V1_BHB_LOOP_COUNT U(32)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define NEOVERSE_V1_CPUECTLR_EL1 S3_0_C15_C1_4
+#define NEOVERSE_V1_CPUPSELR_EL3 S3_6_C15_C8_0
+#define NEOVERSE_V1_CPUPOR_EL3 S3_6_C15_C8_2
+#define NEOVERSE_V1_CPUPMR_EL3 S3_6_C15_C8_3
+#define NEOVERSE_V1_CPUPCR_EL3 S3_6_C15_C8_1
+#define NEOVERSE_V1_CPUECTLR_EL1_BIT_8 (ULL(1) << 8)
+#define NEOVERSE_V1_CPUECTLR_EL1_BIT_53 (ULL(1) << 53)
+#define NEOVERSE_V1_CPUECTLR_EL1_PF_MODE_CNSRV ULL(3)
+#define CPUECTLR_EL1_PF_MODE_LSB U(6)
+#define CPUECTLR_EL1_PF_MODE_WIDTH U(2)
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define NEOVERSE_V1_CPUPWRCTLR_EL1 S3_0_C15_C2_7
+#define NEOVERSE_V1_CPUPWRCTLR_EL1_CORE_PWRDN_BIT U(1)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define NEOVERSE_V1_ACTLR2_EL1 S3_0_C15_C1_1
+#define NEOVERSE_V1_ACTLR2_EL1_BIT_0 ULL(1)
+#define NEOVERSE_V1_ACTLR2_EL1_BIT_2 (ULL(1) << 2)
+#define NEOVERSE_V1_ACTLR2_EL1_BIT_28 (ULL(1) << 28)
+#define NEOVERSE_V1_ACTLR2_EL1_BIT_40 (ULL(1) << 40)
+
+#endif /* NEOVERSE_V1_H */
diff --git a/include/lib/cpus/aarch64/neoverse_v2.h b/include/lib/cpus/aarch64/neoverse_v2.h
new file mode 100644
index 0000000..efb960e
--- /dev/null
+++ b/include/lib/cpus/aarch64/neoverse_v2.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NEOVERSE_V2_H
+#define NEOVERSE_V2_H
+
+#define NEOVERSE_V2_MIDR U(0x410FD4F0)
+
+/* Neoverse V2 loop count for CVE-2022-23960 mitigation */
+#define NEOVERSE_V2_BHB_LOOP_COUNT U(132)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions
+ ******************************************************************************/
+#define NEOVERSE_V2_CPUECTLR_EL1 S3_0_C15_C1_4
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define NEOVERSE_V2_CPUPWRCTLR_EL1 S3_0_C15_C2_7
+#define NEOVERSE_V2_CPUPWRCTLR_EL1_CORE_PWRDN_BIT U(1)
+
+#endif /* NEOVERSE_V2_H */
diff --git a/include/lib/cpus/aarch64/qemu_max.h b/include/lib/cpus/aarch64/qemu_max.h
new file mode 100644
index 0000000..14da170
--- /dev/null
+++ b/include/lib/cpus/aarch64/qemu_max.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QEMU_MAX_H
+#define QEMU_MAX_H
+
+#include <lib/utils_def.h>
+
+/*
+ * QEMU MAX midr for revision 0
+ * 00 - Reserved for software use
+ * 0 - Variant
+ * F - Architectural features identified in ID_* registers
+ * 051 - 'Q', in a 12-bit field.
+ * 0 - Revision
+ */
+#define QEMU_MAX_MIDR U(0x000F0510)
+
+#endif /* QEMU_MAX_H */
diff --git a/include/lib/cpus/aarch64/rainier.h b/include/lib/cpus/aarch64/rainier.h
new file mode 100644
index 0000000..978661f
--- /dev/null
+++ b/include/lib/cpus/aarch64/rainier.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RAINIER_H
+#define RAINIER_H
+
+#include <lib/utils_def.h>
+
+/* RAINIER MIDR for revision 0 */
+#define RAINIER_MIDR U(0x3f0f4120)
+
+/* Exception Syndrome register EC code for IC Trap */
+#define RAINIER_EC_IC_TRAP U(0x1f)
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions.
+ ******************************************************************************/
+#define RAINIER_CPUPWRCTLR_EL1 S3_0_C15_C2_7
+
+/* Definitions of register field mask in RAINIER_CPUPWRCTLR_EL1 */
+#define RAINIER_CORE_PWRDN_EN_MASK U(0x1)
+
+#define RAINIER_ACTLR_AMEN_BIT (U(1) << 4)
+
+#define RAINIER_AMU_NR_COUNTERS U(5)
+#define RAINIER_AMU_GROUP0_MASK U(0x1f)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define RAINIER_CPUECTLR_EL1 S3_0_C15_C1_4
+
+#define RAINIER_WS_THR_L2_MASK (ULL(3) << 24)
+#define RAINIER_CPUECTLR_EL1_MM_TLBPF_DIS_BIT (ULL(1) << 51)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define RAINIER_CPUACTLR_EL1 S3_0_C15_C1_0
+
+#define RAINIER_CPUACTLR_EL1_BIT_6 (ULL(1) << 6)
+#define RAINIER_CPUACTLR_EL1_BIT_13 (ULL(1) << 13)
+
+#define RAINIER_CPUACTLR2_EL1 S3_0_C15_C1_1
+
+#define RAINIER_CPUACTLR2_EL1_BIT_0 (ULL(1) << 0)
+#define RAINIER_CPUACTLR2_EL1_BIT_2 (ULL(1) << 2)
+#define RAINIER_CPUACTLR2_EL1_BIT_11 (ULL(1) << 11)
+#define RAINIER_CPUACTLR2_EL1_BIT_15 (ULL(1) << 15)
+#define RAINIER_CPUACTLR2_EL1_BIT_16 (ULL(1) << 16)
+#define RAINIER_CPUACTLR2_EL1_BIT_59 (ULL(1) << 59)
+
+#define RAINIER_CPUACTLR3_EL1 S3_0_C15_C1_2
+
+#define RAINIER_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 /* RAINIER_H */
diff --git a/include/lib/cpus/errata_report.h b/include/lib/cpus/errata_report.h
new file mode 100644
index 0000000..efdedf0
--- /dev/null
+++ b/include/lib/cpus/errata_report.h
@@ -0,0 +1,36 @@
+/*
+ * 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 <arch.h>
+#include <arch_helpers.h>
+#include <lib/spinlock.h>
+#include <lib/utils_def.h>
+
+#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
+
+/* Macro to get CPU revision code for checking errata version compatibility. */
+#define CPU_REV(r, p) ((r << 4) | p)
+
+#endif /* ERRATA_REPORT_H */
diff --git a/include/lib/cpus/wa_cve_2017_5715.h b/include/lib/cpus/wa_cve_2017_5715.h
new file mode 100644
index 0000000..940fc65
--- /dev/null
+++ b/include/lib/cpus/wa_cve_2017_5715.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/include/lib/cpus/wa_cve_2018_3639.h b/include/lib/cpus/wa_cve_2018_3639.h
new file mode 100644
index 0000000..e37db37
--- /dev/null
+++ b/include/lib/cpus/wa_cve_2018_3639.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/include/lib/cpus/wa_cve_2022_23960.h b/include/lib/cpus/wa_cve_2022_23960.h
new file mode 100644
index 0000000..35b3fd8
--- /dev/null
+++ b/include/lib/cpus/wa_cve_2022_23960.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef WA_CVE_2022_23960_H
+#define WA_CVE_2022_23960_H
+
+int check_smccc_arch_wa3_applies(void);
+
+#endif /* WA_CVE_2022_23960_H */
diff --git a/include/lib/debugfs.h b/include/lib/debugfs.h
new file mode 100644
index 0000000..8ed237a
--- /dev/null
+++ b/include/lib/debugfs.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DEBUGFS_H
+#define DEBUGFS_H
+
+#define NAMELEN 13 /* Maximum length of a file name */
+#define PATHLEN 41 /* Maximum length of a path */
+#define STATLEN 41 /* Size of static part of dir format */
+#define ROOTLEN (2 + 4) /* Size needed to encode root string */
+#define FILNAMLEN (2 + NAMELEN) /* Size needed to encode filename */
+#define DIRLEN (STATLEN + FILNAMLEN + 3*ROOTLEN) /* Size of dir entry */
+
+#define KSEEK_SET 0
+#define KSEEK_CUR 1
+#define KSEEK_END 2
+
+#define NELEM(tab) (sizeof(tab) / sizeof((tab)[0]))
+
+typedef unsigned short qid_t; /* FIXME: short type not recommended? */
+
+/*******************************************************************************
+ * This structure contains the necessary information to represent a 9p
+ * directory.
+ ******************************************************************************/
+typedef struct {
+ char name[NAMELEN];
+ long length;
+ unsigned char mode;
+ unsigned char index;
+ unsigned char dev;
+ qid_t qid;
+} dir_t;
+
+/* Permission definitions used as flags */
+#define O_READ (1 << 0)
+#define O_WRITE (1 << 1)
+#define O_RDWR (1 << 2)
+#define O_BIND (1 << 3)
+#define O_DIR (1 << 4)
+#define O_STAT (1 << 5)
+
+/* 9p interface */
+int mount(const char *srv, const char *mnt, const char *spec);
+int create(const char *name, int flags);
+int open(const char *name, int flags);
+int close(int fd);
+int read(int fd, void *buf, int n);
+int write(int fd, void *buf, int n);
+int seek(int fd, long off, int whence);
+int bind(const char *path, const char *where);
+int stat(const char *path, dir_t *dir);
+
+/* DebugFS initialization */
+void debugfs_init(void);
+int debugfs_smc_setup(void);
+
+/* Debugfs version returned through SMC interface */
+#define DEBUGFS_VERSION (0x000000001U)
+
+/* Function ID for accessing the debugfs interface */
+#define DEBUGFS_FID_VALUE (0x30U)
+
+#define is_debugfs_fid(_fid) \
+ (((_fid) & FUNCID_NUM_MASK) == DEBUGFS_FID_VALUE)
+
+/* Error code for debugfs SMC interface failures */
+#define DEBUGFS_E_INVALID_PARAMS (-2)
+#define DEBUGFS_E_DENIED (-3)
+
+uintptr_t debugfs_smc_handler(unsigned int smc_fid,
+ u_register_t cmd,
+ u_register_t arg2,
+ u_register_t arg3,
+ u_register_t arg4,
+ void *cookie,
+ void *handle,
+ uintptr_t flags);
+
+#endif /* DEBUGFS_H */
diff --git a/include/lib/el3_runtime/aarch32/context.h b/include/lib/el3_runtime/aarch32/context.h
new file mode 100644
index 0000000..5604c8e
--- /dev/null
+++ b/include/lib/el3_runtime/aarch32/context.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CONTEXT_H
+#define CONTEXT_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * 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 <stdint.h>
+
+#include <lib/cassert.h>
+
+/*
+ * 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 ctx_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)->ctx_regs[offset >> WORD_SHIFT])
+#define write_ctx_reg(ctx, offset, val) (((ctx)->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 */
diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h
new file mode 100644
index 0000000..6c13166
--- /dev/null
+++ b/include/lib/el3_runtime/aarch64/context.h
@@ -0,0 +1,567 @@
+/*
+ * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CONTEXT_H
+#define CONTEXT_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * 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_IS_IN_EL3 U(0x30)
+#define CTX_CPTR_EL3 U(0x38)
+#define CTX_ZCR_EL3 U(0x40)
+#define CTX_EL3STATE_END U(0x50) /* Align to the next 16 byte boundary */
+
+/*******************************************************************************
+ * 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_EL1_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_TCR_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_ACTLR_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_EL1_SYSREGS_END CTX_MTE_REGS_END
+
+/*
+ * EL2 register set
+ */
+
+#if CTX_INCLUDE_EL2_REGS
+/* For later discussion
+ * ICH_AP0R<n>_EL2
+ * ICH_AP1R<n>_EL2
+ * AMEVCNTVOFF0<n>_EL2
+ * AMEVCNTVOFF1<n>_EL2
+ * ICH_LR<n>_EL2
+ */
+#define CTX_EL2_SYSREGS_OFFSET (CTX_EL1_SYSREGS_OFFSET + CTX_EL1_SYSREGS_END)
+
+#define CTX_ACTLR_EL2 U(0x0)
+#define CTX_AFSR0_EL2 U(0x8)
+#define CTX_AFSR1_EL2 U(0x10)
+#define CTX_AMAIR_EL2 U(0x18)
+#define CTX_CNTHCTL_EL2 U(0x20)
+#define CTX_CNTVOFF_EL2 U(0x28)
+#define CTX_CPTR_EL2 U(0x30)
+#define CTX_DBGVCR32_EL2 U(0x38)
+#define CTX_ELR_EL2 U(0x40)
+#define CTX_ESR_EL2 U(0x48)
+#define CTX_FAR_EL2 U(0x50)
+#define CTX_HACR_EL2 U(0x58)
+#define CTX_HCR_EL2 U(0x60)
+#define CTX_HPFAR_EL2 U(0x68)
+#define CTX_HSTR_EL2 U(0x70)
+#define CTX_ICC_SRE_EL2 U(0x78)
+#define CTX_ICH_HCR_EL2 U(0x80)
+#define CTX_ICH_VMCR_EL2 U(0x88)
+#define CTX_MAIR_EL2 U(0x90)
+#define CTX_MDCR_EL2 U(0x98)
+#define CTX_PMSCR_EL2 U(0xa0)
+#define CTX_SCTLR_EL2 U(0xa8)
+#define CTX_SPSR_EL2 U(0xb0)
+#define CTX_SP_EL2 U(0xb8)
+#define CTX_TCR_EL2 U(0xc0)
+#define CTX_TPIDR_EL2 U(0xc8)
+#define CTX_TTBR0_EL2 U(0xd0)
+#define CTX_VBAR_EL2 U(0xd8)
+#define CTX_VMPIDR_EL2 U(0xe0)
+#define CTX_VPIDR_EL2 U(0xe8)
+#define CTX_VTCR_EL2 U(0xf0)
+#define CTX_VTTBR_EL2 U(0xf8)
+
+// Only if MTE registers in use
+#define CTX_TFSR_EL2 U(0x100)
+
+// Only if ENABLE_MPAM_FOR_LOWER_ELS==1
+#define CTX_MPAM2_EL2 U(0x108)
+#define CTX_MPAMHCR_EL2 U(0x110)
+#define CTX_MPAMVPM0_EL2 U(0x118)
+#define CTX_MPAMVPM1_EL2 U(0x120)
+#define CTX_MPAMVPM2_EL2 U(0x128)
+#define CTX_MPAMVPM3_EL2 U(0x130)
+#define CTX_MPAMVPM4_EL2 U(0x138)
+#define CTX_MPAMVPM5_EL2 U(0x140)
+#define CTX_MPAMVPM6_EL2 U(0x148)
+#define CTX_MPAMVPM7_EL2 U(0x150)
+#define CTX_MPAMVPMV_EL2 U(0x158)
+
+// Starting with Armv8.6
+#define CTX_HDFGRTR_EL2 U(0x160)
+#define CTX_HAFGRTR_EL2 U(0x168)
+#define CTX_HDFGWTR_EL2 U(0x170)
+#define CTX_HFGITR_EL2 U(0x178)
+#define CTX_HFGRTR_EL2 U(0x180)
+#define CTX_HFGWTR_EL2 U(0x188)
+#define CTX_CNTPOFF_EL2 U(0x190)
+
+// Starting with Armv8.4
+#define CTX_CONTEXTIDR_EL2 U(0x198)
+#define CTX_TTBR1_EL2 U(0x1a0)
+#define CTX_VDISR_EL2 U(0x1a8)
+#define CTX_VSESR_EL2 U(0x1b0)
+#define CTX_VNCR_EL2 U(0x1b8)
+#define CTX_TRFCR_EL2 U(0x1c0)
+
+// Starting with Armv8.5
+#define CTX_SCXTNUM_EL2 U(0x1c8)
+
+// Register for FEAT_HCX
+#define CTX_HCRX_EL2 U(0x1d0)
+
+/* Align to the next 16 byte boundary */
+#define CTX_EL2_SYSREGS_END U(0x1e0)
+
+#endif /* CTX_INCLUDE_EL2_REGS */
+
+/*******************************************************************************
+ * Constants that allow assembler code to access members of and the 'fp_regs'
+ * structure at their correct offsets.
+ ******************************************************************************/
+#if CTX_INCLUDE_EL2_REGS
+# define CTX_FPREGS_OFFSET (CTX_EL2_SYSREGS_OFFSET + CTX_EL2_SYSREGS_END)
+#else
+# define CTX_FPREGS_OFFSET (CTX_EL1_SYSREGS_OFFSET + CTX_EL1_SYSREGS_END)
+#endif
+#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 <stdint.h>
+
+#include <lib/cassert.h>
+
+/*
+ * 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 ctx_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_EL1_SYSREGS_ALL (CTX_EL1_SYSREGS_END >> DWORD_SHIFT)
+#if CTX_INCLUDE_EL2_REGS
+# define CTX_EL2_SYSREGS_ALL (CTX_EL2_SYSREGS_END >> DWORD_SHIFT)
+#endif
+#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 world switches.
+ */
+DEFINE_REG_STRUCT(el1_sysregs, CTX_EL1_SYSREGS_ALL);
+
+
+/*
+ * AArch64 EL2 system register context structure for preserving the
+ * architectural state during world switches.
+ */
+#if CTX_INCLUDE_EL2_REGS
+DEFINE_REG_STRUCT(el2_sysregs, CTX_EL2_SYSREGS_ALL);
+#endif
+
+/*
+ * 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)->ctx_regs[(offset) >> DWORD_SHIFT])
+#define write_ctx_reg(ctx, offset, val) (((ctx)->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 the next lower EL in a given security state 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.
+ */
+typedef struct cpu_context {
+ gp_regs_t gpregs_ctx;
+ el3_state_t el3state_ctx;
+ el1_sysregs_t el1_sysregs_ctx;
+#if CTX_INCLUDE_EL2_REGS
+ el2_sysregs_t el2_sysregs_ctx;
+#endif
+#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_el1_sysregs_ctx(h) (&((cpu_context_t *) h)->el1_sysregs_ctx)
+#if CTX_INCLUDE_EL2_REGS
+# define get_el2_sysregs_ctx(h) (&((cpu_context_t *) h)->el2_sysregs_ctx)
+#endif
+#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_EL1_SYSREGS_OFFSET == __builtin_offsetof(cpu_context_t, el1_sysregs_ctx), \
+ assert_core_context_el1_sys_offset_mismatch);
+#if CTX_INCLUDE_EL2_REGS
+CASSERT(CTX_EL2_SYSREGS_OFFSET == __builtin_offsetof(cpu_context_t, el2_sysregs_ctx), \
+ assert_core_context_el2_sys_offset_mismatch);
+#endif
+#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_sysregs_t *regs);
+void el1_sysregs_context_restore(el1_sysregs_t *regs);
+
+#if CTX_INCLUDE_EL2_REGS
+void el2_sysregs_context_save_common(el2_sysregs_t *regs);
+void el2_sysregs_context_restore_common(el2_sysregs_t *regs);
+#if ENABLE_SPE_FOR_LOWER_ELS
+void el2_sysregs_context_save_spe(el2_sysregs_t *regs);
+void el2_sysregs_context_restore_spe(el2_sysregs_t *regs);
+#endif /* ENABLE_SPE_FOR_LOWER_ELS */
+#if CTX_INCLUDE_MTE_REGS
+void el2_sysregs_context_save_mte(el2_sysregs_t *regs);
+void el2_sysregs_context_restore_mte(el2_sysregs_t *regs);
+#endif /* CTX_INCLUDE_MTE_REGS */
+#if ENABLE_MPAM_FOR_LOWER_ELS
+void el2_sysregs_context_save_mpam(el2_sysregs_t *regs);
+void el2_sysregs_context_restore_mpam(el2_sysregs_t *regs);
+#endif /* ENABLE_MPAM_FOR_LOWER_ELS */
+#if ENABLE_FEAT_FGT
+void el2_sysregs_context_save_fgt(el2_sysregs_t *regs);
+void el2_sysregs_context_restore_fgt(el2_sysregs_t *regs);
+#endif /* ENABLE_FEAT_FGT */
+#if ENABLE_FEAT_ECV
+void el2_sysregs_context_save_ecv(el2_sysregs_t *regs);
+void el2_sysregs_context_restore_ecv(el2_sysregs_t *regs);
+#endif /* ENABLE_FEAT_ECV */
+#if ENABLE_FEAT_VHE
+void el2_sysregs_context_save_vhe(el2_sysregs_t *regs);
+void el2_sysregs_context_restore_vhe(el2_sysregs_t *regs);
+#endif /* ENABLE_FEAT_VHE */
+#if RAS_EXTENSION
+void el2_sysregs_context_save_ras(el2_sysregs_t *regs);
+void el2_sysregs_context_restore_ras(el2_sysregs_t *regs);
+#endif /* RAS_EXTENSION */
+#if CTX_INCLUDE_NEVE_REGS
+void el2_sysregs_context_save_nv2(el2_sysregs_t *regs);
+void el2_sysregs_context_restore_nv2(el2_sysregs_t *regs);
+#endif /* CTX_INCLUDE_NEVE_REGS */
+#if ENABLE_TRF_FOR_NS
+void el2_sysregs_context_save_trf(el2_sysregs_t *regs);
+void el2_sysregs_context_restore_trf(el2_sysregs_t *regs);
+#endif /* ENABLE_TRF_FOR_NS */
+#if ENABLE_FEAT_CSV2_2
+void el2_sysregs_context_save_csv2(el2_sysregs_t *regs);
+void el2_sysregs_context_restore_csv2(el2_sysregs_t *regs);
+#endif /* ENABLE_FEAT_CSV2_2 */
+#if ENABLE_FEAT_HCX
+void el2_sysregs_context_save_hcx(el2_sysregs_t *regs);
+void el2_sysregs_context_restore_hcx(el2_sysregs_t *regs);
+#endif /* ENABLE_FEAT_HCX */
+#endif /* CTX_INCLUDE_EL2_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 */
diff --git a/include/lib/el3_runtime/context_mgmt.h b/include/lib/el3_runtime/context_mgmt.h
new file mode 100644
index 0000000..1a76d8e
--- /dev/null
+++ b/include/lib/el3_runtime/context_mgmt.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CONTEXT_MGMT_H
+#define CONTEXT_MGMT_H
+
+#include <assert.h>
+#include <context.h>
+#include <stdint.h>
+
+#include <arch.h>
+
+/*******************************************************************************
+ * 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 struct entry_point_info *ep);
+void cm_prepare_el3_exit(uint32_t security_state);
+void cm_prepare_el3_exit_ns(void);
+
+#ifdef __aarch64__
+#if CTX_INCLUDE_EL2_REGS
+void cm_el2_sysregs_context_save(uint32_t security_state);
+void cm_el2_sysregs_context_restore(uint32_t security_state);
+#endif
+
+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);
+u_register_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 */
diff --git a/include/lib/el3_runtime/cpu_data.h b/include/lib/el3_runtime/cpu_data.h
new file mode 100644
index 0000000..2c7b619
--- /dev/null
+++ b/include/lib/el3_runtime/cpu_data.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2014-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CPU_DATA_H
+#define CPU_DATA_H
+
+#include <platform_def.h> /* CACHE_WRITEBACK_GRANULE required */
+
+#include <bl31/ehf.h>
+
+/* 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)
+
+#if ENABLE_RME
+/* Size of cpu_context array */
+#define CPU_DATA_CONTEXT_NUM 3
+/* Offset of cpu_ops_ptr, size 8 bytes */
+#define CPU_DATA_CPU_OPS_PTR 0x18
+#else /* ENABLE_RME */
+#define CPU_DATA_CONTEXT_NUM 2
+#define CPU_DATA_CPU_OPS_PTR 0x10
+#endif /* ENABLE_RME */
+
+#if ENABLE_PAUTH
+/* 8-bytes aligned offset of apiakey[2], size 16 bytes */
+#define CPU_DATA_APIAKEY_OFFSET (0x8 + PSCI_CPU_DATA_SIZE_ALIGNED \
+ + CPU_DATA_CPU_OPS_PTR)
+#define CPU_DATA_CRASH_BUF_OFFSET (0x10 + CPU_DATA_APIAKEY_OFFSET)
+#else /* ENABLE_PAUTH */
+#define CPU_DATA_CRASH_BUF_OFFSET (0x8 + PSCI_CPU_DATA_SIZE_ALIGNED \
+ + CPU_DATA_CPU_OPS_PTR)
+#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 <assert.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <lib/cassert.h>
+#include <lib/psci/psci.h>
+
+#include <platform_def.h>
+
+/* 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
+
+typedef enum context_pas {
+ CPU_CONTEXT_SECURE = 0,
+ CPU_CONTEXT_NS,
+#if ENABLE_RME
+ CPU_CONTEXT_REALM,
+#endif
+ CPU_CONTEXT_NUM
+} context_pas_t;
+
+/*******************************************************************************
+ * Function & variable prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Cache of frequently used per-cpu data:
+ * Pointers to non-secure, realm, 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
+ *
+ * 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[CPU_DATA_CONTEXT_NUM];
+#endif /* __aarch64__ */
+ 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];
+
+#ifdef __aarch64__
+CASSERT(CPU_DATA_CONTEXT_NUM == CPU_CONTEXT_NUM,
+ assert_cpu_data_context_num_mismatch);
+#endif
+
+#if ENABLE_PAUTH
+CASSERT(CPU_DATA_APIAKEY_OFFSET == __builtin_offsetof
+ (cpu_data_t, apiakey),
+ assert_cpu_data_pauth_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
+
+/*
+ * Returns the index of the cpu_context array for the given security state.
+ * All accesses to cpu_context should be through this helper to make sure
+ * an access is not out-of-bounds. The function assumes security_state is
+ * valid.
+ */
+static inline context_pas_t get_cpu_context_index(uint32_t security_state)
+{
+ if (security_state == SECURE) {
+ return CPU_CONTEXT_SECURE;
+ } else {
+#if ENABLE_RME
+ if (security_state == NON_SECURE) {
+ return CPU_CONTEXT_NS;
+ } else {
+ assert(security_state == REALM);
+ return CPU_CONTEXT_REALM;
+ }
+#else
+ assert(security_state == NON_SECURE);
+ return CPU_CONTEXT_NS;
+#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 */
diff --git a/include/lib/el3_runtime/pubsub.h b/include/lib/el3_runtime/pubsub.h
new file mode 100644
index 0000000..64fe5cc
--- /dev/null
+++ b/include/lib/el3_runtime/pubsub.h
@@ -0,0 +1,106 @@
+/*
+ * 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 <assert.h>
+#include <cdefs.h>
+#include <stddef.h>
+
+#include <arch_helpers.h>
+
+#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 */
diff --git a/include/lib/el3_runtime/pubsub_events.h b/include/lib/el3_runtime/pubsub_events.h
new file mode 100644
index 0000000..5012082
--- /dev/null
+++ b/include/lib/el3_runtime/pubsub_events.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/el3_runtime/pubsub.h>
+
+/*
+ * 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__ */
diff --git a/include/lib/extensions/amu.h b/include/lib/extensions/amu.h
new file mode 100644
index 0000000..6452f7e
--- /dev/null
+++ b/include/lib/extensions/amu.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AMU_H
+#define AMU_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <context.h>
+
+#include <platform_def.h>
+
+#if __aarch64__
+void amu_enable(bool el2_unused, cpu_context_t *ctx);
+#else
+void amu_enable(bool el2_unused);
+#endif
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+/*
+ * AMU data for a single core.
+ */
+struct amu_core {
+ uint16_t enable; /* Mask of auxiliary counters to enable */
+};
+
+/*
+ * Topological platform data specific to the AMU.
+ */
+struct amu_topology {
+ struct amu_core cores[PLATFORM_CORE_COUNT]; /* Per-core data */
+};
+
+#if !ENABLE_AMU_FCONF
+/*
+ * Retrieve the platform's AMU topology. A `NULL` return value is treated as a
+ * non-fatal error, in which case no auxiliary counters will be enabled.
+ */
+const struct amu_topology *plat_amu_topology(void);
+#endif /* ENABLE_AMU_FCONF */
+#endif /* ENABLE_AMU_AUXILIARY_COUNTERS */
+
+#endif /* AMU_H */
diff --git a/include/lib/extensions/brbe.h b/include/lib/extensions/brbe.h
new file mode 100644
index 0000000..aac1ace
--- /dev/null
+++ b/include/lib/extensions/brbe.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BRBE_H
+#define BRBE_H
+
+void brbe_enable(void);
+
+#endif /* BRBE_H */
diff --git a/include/lib/extensions/mpam.h b/include/lib/extensions/mpam.h
new file mode 100644
index 0000000..414adcb
--- /dev/null
+++ b/include/lib/extensions/mpam.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MPAM_H
+#define MPAM_H
+
+#include <stdbool.h>
+
+void mpam_enable(bool el2_unused);
+
+#endif /* MPAM_H */
diff --git a/include/lib/extensions/pauth.h b/include/lib/extensions/pauth.h
new file mode 100644
index 0000000..2e780de
--- /dev/null
+++ b/include/lib/extensions/pauth.h
@@ -0,0 +1,18 @@
+/*
+ * 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 */
diff --git a/include/lib/extensions/ras.h b/include/lib/extensions/ras.h
new file mode 100644
index 0000000..793ab9f
--- /dev/null
+++ b/include/lib/extensions/ras.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. 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 <assert.h>
+
+#include <lib/extensions/ras_arch.h>
+
+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);
+}
+
+const char *ras_serr_to_str(unsigned int serr);
+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 */
diff --git a/include/lib/extensions/ras_arch.h b/include/lib/extensions/ras_arch.h
new file mode 100644
index 0000000..55760b0
--- /dev/null
+++ b/include/lib/extensions/ras_arch.h
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. 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 */
+
+/* Number of architecturally-defined primary error codes */
+#define ERROR_STATUS_NUM_SERR U(22)
+
+/* 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 <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <context.h>
+#include <lib/mmio.h>
+#include <stdint.h>
+
+/*
+ * 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 */
diff --git a/include/lib/extensions/sme.h b/include/lib/extensions/sme.h
new file mode 100644
index 0000000..893f9f2
--- /dev/null
+++ b/include/lib/extensions/sme.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SME_H
+#define SME_H
+
+#include <stdbool.h>
+
+#include <context.h>
+
+/*
+ * Maximum value of LEN field in SMCR_ELx. This is different than the maximum
+ * supported value which is platform dependent. In the first version of SME the
+ * LEN field is limited to 4 bits but will be expanded in future iterations.
+ * To support different versions, the code that discovers the supported vector
+ * lengths will write the max value into SMCR_ELx then read it back to see how
+ * many bits are implemented.
+ */
+#define SME_SMCR_LEN_MAX U(0x1FF)
+
+void sme_enable(cpu_context_t *context);
+void sme_disable(cpu_context_t *context);
+
+#endif /* SME_H */
diff --git a/include/lib/extensions/spe.h b/include/lib/extensions/spe.h
new file mode 100644
index 0000000..d4b925f
--- /dev/null
+++ b/include/lib/extensions/spe.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPE_H
+#define SPE_H
+
+#include <stdbool.h>
+
+bool spe_supported(void);
+void spe_enable(bool el2_unused);
+void spe_disable(void);
+
+#endif /* SPE_H */
diff --git a/include/lib/extensions/sve.h b/include/lib/extensions/sve.h
new file mode 100644
index 0000000..4b66cdb
--- /dev/null
+++ b/include/lib/extensions/sve.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SVE_H
+#define SVE_H
+
+#include <context.h>
+
+void sve_enable(cpu_context_t *context);
+void sve_disable(cpu_context_t *context);
+
+#endif /* SVE_H */
diff --git a/include/lib/extensions/sys_reg_trace.h b/include/lib/extensions/sys_reg_trace.h
new file mode 100644
index 0000000..74470fe
--- /dev/null
+++ b/include/lib/extensions/sys_reg_trace.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SYS_REG_TRACE_H
+#define SYS_REG_TRACE_H
+
+#include <context.h>
+
+#if __aarch64__
+void sys_reg_trace_enable(cpu_context_t *context);
+#else
+void sys_reg_trace_enable(void);
+#endif /* __aarch64__ */
+
+#endif /* SYS_REG_TRACE_H */
diff --git a/include/lib/extensions/trbe.h b/include/lib/extensions/trbe.h
new file mode 100644
index 0000000..1753ab6
--- /dev/null
+++ b/include/lib/extensions/trbe.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TRBE_H
+#define TRBE_H
+
+void trbe_enable(void);
+
+#endif /* TRBE_H */
diff --git a/include/lib/extensions/trf.h b/include/lib/extensions/trf.h
new file mode 100644
index 0000000..18f17f3
--- /dev/null
+++ b/include/lib/extensions/trf.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TRF_H
+#define TRF_H
+
+void trf_enable(void);
+
+#endif /* TRF_H */
diff --git a/include/lib/fconf/fconf.h b/include/lib/fconf/fconf.h
new file mode 100644
index 0000000..131c542
--- /dev/null
+++ b/include/lib/fconf/fconf.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FCONF_H
+#define FCONF_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* Public API */
+#define FCONF_GET_PROPERTY(a, b, c) a##__##b##_getter(c)
+
+/*
+ * This macro takes three arguments:
+ * config: Configuration identifier
+ * name: property namespace
+ * callback: populate() function
+ */
+#define FCONF_REGISTER_POPULATOR(config, name, callback) \
+ __attribute__((used, section(".fconf_populator"))) \
+ const struct fconf_populator (name##__populator) = { \
+ .config_type = (#config), \
+ .info = (#name), \
+ .populate = (callback) \
+ };
+
+/*
+ * Populator callback
+ *
+ * This structure are used by the fconf_populate function and should only be
+ * defined by the FCONF_REGISTER_POPULATOR macro.
+ */
+struct fconf_populator {
+ /* Description of the data loaded by the callback */
+ const char *config_type;
+ const char *info;
+
+ /* Callback used by fconf_populate function with a provided config dtb.
+ * Return 0 on success, err_code < 0 otherwise.
+ */
+ int (*populate)(uintptr_t config);
+};
+
+/* This function supports to load tb_fw_config and fw_config dtb */
+int fconf_load_config(unsigned int image_id);
+
+/* Top level populate function
+ *
+ * This function takes a configuration dtb and calls all the registered
+ * populator callback with it.
+ *
+ * Panic on error.
+ */
+void fconf_populate(const char *config_type, uintptr_t config);
+
+/* FCONF specific getter */
+#define fconf__dtb_getter(prop) fconf_dtb_info.prop
+
+/* Structure used to locally keep a reference to the config dtb. */
+struct fconf_dtb_info_t {
+ uintptr_t base_addr;
+ size_t size;
+};
+
+extern struct fconf_dtb_info_t fconf_dtb_info;
+
+#endif /* FCONF_H */
diff --git a/include/lib/fconf/fconf_amu_getter.h b/include/lib/fconf/fconf_amu_getter.h
new file mode 100644
index 0000000..2faee73
--- /dev/null
+++ b/include/lib/fconf/fconf_amu_getter.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FCONF_AMU_GETTER_H
+#define FCONF_AMU_GETTER_H
+
+#include <lib/extensions/amu.h>
+
+#define amu__config_getter(id) fconf_amu_config.id
+
+struct fconf_amu_config {
+ const struct amu_topology *topology;
+};
+
+extern struct fconf_amu_config fconf_amu_config;
+
+#endif /* FCONF_AMU_GETTER_H */
diff --git a/include/lib/fconf/fconf_dyn_cfg_getter.h b/include/lib/fconf/fconf_dyn_cfg_getter.h
new file mode 100644
index 0000000..43f298e
--- /dev/null
+++ b/include/lib/fconf/fconf_dyn_cfg_getter.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FCONF_DYN_CFG_GETTER_H
+#define FCONF_DYN_CFG_GETTER_H
+
+#include <lib/fconf/fconf.h>
+
+#define FCONF_INVALID_IDX 0xFFFFFFFFU
+
+/* Dynamic configuration related getter */
+#define dyn_cfg__dtb_getter(id) dyn_cfg_dtb_info_getter(id)
+
+struct dyn_cfg_dtb_info_t {
+ uintptr_t config_addr;
+ uint32_t config_max_size;
+ unsigned int config_id;
+ /*
+ * Load address in non-secure memory. Only needed by those
+ * configuration files which require being loaded in secure
+ * memory (at config_addr) as well as in non-secure memory
+ * - e.g. HW_CONFIG
+ */
+ uintptr_t ns_config_addr;
+};
+
+unsigned int dyn_cfg_dtb_info_get_index(unsigned int config_id);
+struct dyn_cfg_dtb_info_t *dyn_cfg_dtb_info_getter(unsigned int config_id);
+int fconf_populate_dtb_registry(uintptr_t config);
+
+/* Set config information in global DTB array */
+void set_config_info(uintptr_t config_addr, uintptr_t ns_config_addr,
+ uint32_t config_max_size,
+ unsigned int config_id);
+
+#endif /* FCONF_DYN_CFG_GETTER_H */
diff --git a/include/lib/fconf/fconf_mpmm_getter.h b/include/lib/fconf/fconf_mpmm_getter.h
new file mode 100644
index 0000000..50d991a
--- /dev/null
+++ b/include/lib/fconf/fconf_mpmm_getter.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FCONF_MPMM_GETTER_H
+#define FCONF_MPMM_GETTER_H
+
+#include <lib/mpmm/mpmm.h>
+
+#define mpmm__config_getter(id) fconf_mpmm_config.id
+
+struct fconf_mpmm_config {
+ const struct mpmm_topology *topology;
+};
+
+extern struct fconf_mpmm_config fconf_mpmm_config;
+
+#endif /* FCONF_MPMM_GETTER_H */
diff --git a/include/lib/fconf/fconf_tbbr_getter.h b/include/lib/fconf/fconf_tbbr_getter.h
new file mode 100644
index 0000000..db98b68
--- /dev/null
+++ b/include/lib/fconf/fconf_tbbr_getter.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FCONF_TBBR_GETTER_H
+#define FCONF_TBBR_GETTER_H
+
+#include <assert.h>
+
+#include <lib/fconf/fconf.h>
+
+/* TBBR related getter */
+#define tbbr__cot_getter(id) __extension__ ({ \
+ assert((id) < cot_desc_size); \
+ cot_desc_ptr[id]; \
+})
+
+#define tbbr__dyn_config_getter(id) tbbr_dyn_config.id
+
+struct tbbr_dyn_config_t {
+ uint32_t disable_auth;
+ void *mbedtls_heap_addr;
+ size_t mbedtls_heap_size;
+};
+
+extern struct tbbr_dyn_config_t tbbr_dyn_config;
+
+int fconf_populate_tbbr_dyn_config(uintptr_t config);
+
+#endif /* FCONF_TBBR_GETTER_H */
diff --git a/include/lib/gpt_rme/gpt_rme.h b/include/lib/gpt_rme/gpt_rme.h
new file mode 100644
index 0000000..94a88b0
--- /dev/null
+++ b/include/lib/gpt_rme/gpt_rme.h
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GPT_RME_H
+#define GPT_RME_H
+
+#include <stdint.h>
+
+#include <arch.h>
+
+/******************************************************************************/
+/* GPT helper macros and definitions */
+/******************************************************************************/
+
+/*
+ * Structure for specifying a mapping range and it's properties. This should not
+ * be manually initialized, using the MAP_GPT_REGION_x macros is recommended as
+ * to avoid potential incompatibilities in the future.
+ */
+typedef struct pas_region {
+ uintptr_t base_pa; /* Base address for PAS. */
+ size_t size; /* Size of the PAS. */
+ unsigned int attrs; /* PAS GPI and entry type. */
+} pas_region_t;
+
+/* GPT GPI definitions */
+#define GPT_GPI_NO_ACCESS U(0x0)
+#define GPT_GPI_SECURE U(0x8)
+#define GPT_GPI_NS U(0x9)
+#define GPT_GPI_ROOT U(0xA)
+#define GPT_GPI_REALM U(0xB)
+#define GPT_GPI_ANY U(0xF)
+#define GPT_GPI_VAL_MASK UL(0xF)
+
+#define GPT_NSE_SECURE U(0b00)
+#define GPT_NSE_ROOT U(0b01)
+#define GPT_NSE_NS U(0b10)
+#define GPT_NSE_REALM U(0b11)
+
+#define GPT_NSE_SHIFT U(62)
+
+/* PAS attribute GPI definitions. */
+#define GPT_PAS_ATTR_GPI_SHIFT U(0)
+#define GPT_PAS_ATTR_GPI_MASK U(0xF)
+#define GPT_PAS_ATTR_GPI(_attrs) (((_attrs) \
+ >> GPT_PAS_ATTR_GPI_SHIFT) \
+ & GPT_PAS_ATTR_GPI_MASK)
+
+/* PAS attribute mapping type definitions */
+#define GPT_PAS_ATTR_MAP_TYPE_BLOCK U(0x0)
+#define GPT_PAS_ATTR_MAP_TYPE_GRANULE U(0x1)
+#define GPT_PAS_ATTR_MAP_TYPE_SHIFT U(4)
+#define GPT_PAS_ATTR_MAP_TYPE_MASK U(0x1)
+#define GPT_PAS_ATTR_MAP_TYPE(_attrs) (((_attrs) \
+ >> GPT_PAS_ATTR_MAP_TYPE_SHIFT) \
+ & GPT_PAS_ATTR_MAP_TYPE_MASK)
+
+/*
+ * Macro to initialize the attributes field in the pas_region_t structure.
+ * [31:5] Reserved
+ * [4] Mapping type (GPT_PAS_ATTR_MAP_TYPE_x definitions)
+ * [3:0] PAS GPI type (GPT_GPI_x definitions)
+ */
+#define GPT_PAS_ATTR(_type, _gpi) \
+ ((((_type) & GPT_PAS_ATTR_MAP_TYPE_MASK) \
+ << GPT_PAS_ATTR_MAP_TYPE_SHIFT) | \
+ (((_gpi) & GPT_PAS_ATTR_GPI_MASK) \
+ << GPT_PAS_ATTR_GPI_SHIFT))
+
+/*
+ * Macro to create a GPT entry for this PAS range as a block descriptor. If this
+ * region does not fit the requirements for a block descriptor then GPT
+ * initialization will fail.
+ */
+#define GPT_MAP_REGION_BLOCK(_pa, _sz, _gpi) \
+ { \
+ .base_pa = (_pa), \
+ .size = (_sz), \
+ .attrs = GPT_PAS_ATTR(GPT_PAS_ATTR_MAP_TYPE_BLOCK, (_gpi)), \
+ }
+
+/*
+ * Macro to create a GPT entry for this PAS range as a table descriptor. If this
+ * region does not fit the requirements for a table descriptor then GPT
+ * initialization will fail.
+ */
+#define GPT_MAP_REGION_GRANULE(_pa, _sz, _gpi) \
+ { \
+ .base_pa = (_pa), \
+ .size = (_sz), \
+ .attrs = GPT_PAS_ATTR(GPT_PAS_ATTR_MAP_TYPE_GRANULE, (_gpi)), \
+ }
+
+/******************************************************************************/
+/* GPT register field definitions */
+/******************************************************************************/
+
+/*
+ * Least significant address bits protected by each entry in level 0 GPT. This
+ * field is read-only.
+ */
+#define GPCCR_L0GPTSZ_SHIFT U(20)
+#define GPCCR_L0GPTSZ_MASK U(0xF)
+
+typedef enum {
+ GPCCR_L0GPTSZ_30BITS = U(0x0),
+ GPCCR_L0GPTSZ_34BITS = U(0x4),
+ GPCCR_L0GPTSZ_36BITS = U(0x6),
+ GPCCR_L0GPTSZ_39BITS = U(0x9)
+} gpccr_l0gptsz_e;
+
+/* Granule protection check priority bit definitions */
+#define GPCCR_GPCP_SHIFT U(17)
+#define GPCCR_GPCP_BIT (ULL(1) << GPCCR_EL3_GPCP_SHIFT)
+
+/* Granule protection check bit definitions */
+#define GPCCR_GPC_SHIFT U(16)
+#define GPCCR_GPC_BIT (ULL(1) << GPCCR_GPC_SHIFT)
+
+/* Physical granule size bit definitions */
+#define GPCCR_PGS_SHIFT U(14)
+#define GPCCR_PGS_MASK U(0x3)
+#define SET_GPCCR_PGS(x) (((x) & GPCCR_PGS_MASK) << GPCCR_PGS_SHIFT)
+
+typedef enum {
+ GPCCR_PGS_4K = U(0x0),
+ GPCCR_PGS_64K = U(0x1),
+ GPCCR_PGS_16K = U(0x2)
+} gpccr_pgs_e;
+
+/* GPT fetch shareability attribute bit definitions */
+#define GPCCR_SH_SHIFT U(12)
+#define GPCCR_SH_MASK U(0x3)
+#define SET_GPCCR_SH(x) (((x) & GPCCR_SH_MASK) << GPCCR_SH_SHIFT)
+
+typedef enum {
+ GPCCR_SH_NS = U(0x0),
+ GPCCR_SH_OS = U(0x2),
+ GPCCR_SH_IS = U(0x3)
+} gpccr_sh_e;
+
+/* GPT fetch outer cacheability attribute bit definitions */
+#define GPCCR_ORGN_SHIFT U(10)
+#define GPCCR_ORGN_MASK U(0x3)
+#define SET_GPCCR_ORGN(x) (((x) & GPCCR_ORGN_MASK) << GPCCR_ORGN_SHIFT)
+
+typedef enum {
+ GPCCR_ORGN_NC = U(0x0),
+ GPCCR_ORGN_WB_RA_WA = U(0x1),
+ GPCCR_ORGN_WT_RA_NWA = U(0x2),
+ GPCCR_ORGN_WB_RA_NWA = U(0x3)
+} gpccr_orgn_e;
+
+/* GPT fetch inner cacheability attribute bit definitions */
+#define GPCCR_IRGN_SHIFT U(8)
+#define GPCCR_IRGN_MASK U(0x3)
+#define SET_GPCCR_IRGN(x) (((x) & GPCCR_IRGN_MASK) << GPCCR_IRGN_SHIFT)
+
+typedef enum {
+ GPCCR_IRGN_NC = U(0x0),
+ GPCCR_IRGN_WB_RA_WA = U(0x1),
+ GPCCR_IRGN_WT_RA_NWA = U(0x2),
+ GPCCR_IRGN_WB_RA_NWA = U(0x3)
+} gpccr_irgn_e;
+
+/* Protected physical address size bit definitions */
+#define GPCCR_PPS_SHIFT U(0)
+#define GPCCR_PPS_MASK U(0x7)
+#define SET_GPCCR_PPS(x) (((x) & GPCCR_PPS_MASK) << GPCCR_PPS_SHIFT)
+
+typedef enum {
+ GPCCR_PPS_4GB = U(0x0),
+ GPCCR_PPS_64GB = U(0x1),
+ GPCCR_PPS_1TB = U(0x2),
+ GPCCR_PPS_4TB = U(0x3),
+ GPCCR_PPS_16TB = U(0x4),
+ GPCCR_PPS_256TB = U(0x5),
+ GPCCR_PPS_4PB = U(0x6)
+} gpccr_pps_e;
+
+/* Base Address for the GPT bit definitions */
+#define GPTBR_BADDR_SHIFT U(0)
+#define GPTBR_BADDR_VAL_SHIFT U(12)
+#define GPTBR_BADDR_MASK ULL(0xffffffffff)
+
+/******************************************************************************/
+/* GPT public APIs */
+/******************************************************************************/
+
+/*
+ * Public API that initializes the entire protected space to GPT_GPI_ANY using
+ * the L0 tables (block descriptors). Ideally, this function is invoked prior
+ * to DDR discovery and initialization. The MMU must be initialized before
+ * calling this function.
+ *
+ * Parameters
+ * pps PPS value to use for table generation
+ * l0_mem_base Base address of L0 tables in memory.
+ * l0_mem_size Total size of memory available for L0 tables.
+ *
+ * Return
+ * Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_init_l0_tables(gpccr_pps_e pps,
+ uintptr_t l0_mem_base,
+ size_t l0_mem_size);
+
+/*
+ * Public API that carves out PAS regions from the L0 tables and builds any L1
+ * tables that are needed. This function ideally is run after DDR discovery and
+ * initialization. The L0 tables must have already been initialized to GPI_ANY
+ * when this function is called.
+ *
+ * Parameters
+ * pgs PGS value to use for table generation.
+ * l1_mem_base Base address of memory used for L1 tables.
+ * l1_mem_size Total size of memory available for L1 tables.
+ * *pas_regions Pointer to PAS regions structure array.
+ * pas_count Total number of PAS regions.
+ *
+ * Return
+ * Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_init_pas_l1_tables(gpccr_pgs_e pgs,
+ uintptr_t l1_mem_base,
+ size_t l1_mem_size,
+ pas_region_t *pas_regions,
+ unsigned int pas_count);
+
+/*
+ * Public API to initialize the runtime gpt_config structure based on the values
+ * present in the GPTBR_EL3 and GPCCR_EL3 registers. GPT initialization
+ * typically happens in a bootloader stage prior to setting up the EL3 runtime
+ * environment for the granule transition service so this function detects the
+ * initialization from a previous stage. Granule protection checks must be
+ * enabled already or this function will return an error.
+ *
+ * Return
+ * Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_runtime_init(void);
+
+/*
+ * Public API to enable granule protection checks once the tables have all been
+ * initialized. This function is called at first initialization and then again
+ * later during warm boots of CPU cores.
+ *
+ * Return
+ * Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_enable(void);
+
+/*
+ * Public API to disable granule protection checks.
+ */
+void gpt_disable(void);
+
+/*
+ * This function is the core of the granule transition service. When a granule
+ * transition request occurs it is routed to this function where the request is
+ * validated then fulfilled if possible.
+ *
+ * TODO: implement support for transitioning multiple granules at once.
+ *
+ * Parameters
+ * base: Base address of the region to transition, must be aligned to granule
+ * size.
+ * size: Size of region to transition, must be aligned to granule size.
+ * src_sec_state: Security state of the originating SMC invoking the API.
+ *
+ * Return
+ * Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_delegate_pas(uint64_t base, size_t size, unsigned int src_sec_state);
+int gpt_undelegate_pas(uint64_t base, size_t size, unsigned int src_sec_state);
+
+#endif /* GPT_RME_H */
diff --git a/include/lib/libc/aarch32/endian_.h b/include/lib/libc/aarch32/endian_.h
new file mode 100644
index 0000000..0cf2c75
--- /dev/null
+++ b/include/lib/libc/aarch32/endian_.h
@@ -0,0 +1,146 @@
+/*-
+ * 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 <stdint.h>
+
+/*
+ * 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 */
diff --git a/include/lib/libc/aarch32/float.h b/include/lib/libc/aarch32/float.h
new file mode 100644
index 0000000..857d76e
--- /dev/null
+++ b/include/lib/libc/aarch32/float.h
@@ -0,0 +1,100 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1989 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.
+ *
+ * from: @(#)float.h 7.1 (Berkeley) 5/8/90
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_FLOAT_H_
+#define _MACHINE_FLOAT_H_ 1
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+extern int __flt_rounds(void);
+__END_DECLS
+
+#define FLT_RADIX 2 /* b */
+#ifndef _ARM_HARD_FLOAT
+#define FLT_ROUNDS __flt_rounds()
+#else
+#define FLT_ROUNDS (-1)
+#endif
+#if __ISO_C_VISIBLE >= 1999
+#define FLT_EVAL_METHOD 0
+#define DECIMAL_DIG 17 /* max precision in decimal digits */
+#endif
+
+#define FLT_MANT_DIG 24 /* p */
+#define FLT_EPSILON 1.19209290E-07F /* b**(1-p) */
+#define FLT_DIG 6 /* floor((p-1)*log10(b))+(b == 10) */
+#define FLT_MIN_EXP (-125) /* emin */
+#define FLT_MIN 1.17549435E-38F /* b**(emin-1) */
+#define FLT_MIN_10_EXP (-37) /* ceil(log10(b**(emin-1))) */
+#define FLT_MAX_EXP 128 /* emax */
+#define FLT_MAX 3.40282347E+38F /* (1-b**(-p))*b**emax */
+#define FLT_MAX_10_EXP 38 /* floor(log10((1-b**(-p))*b**emax)) */
+#if __ISO_C_VISIBLE >= 2011
+#define FLT_TRUE_MIN 1.40129846E-45F /* b**(emin-p) */
+#define FLT_DECIMAL_DIG 9 /* ceil(1+p*log10(b)) */
+#define FLT_HAS_SUBNORM 1
+#endif /* __ISO_C_VISIBLE >= 2011 */
+
+#define DBL_MANT_DIG 53
+#define DBL_EPSILON 2.2204460492503131E-16
+#define DBL_DIG 15
+#define DBL_MIN_EXP (-1021)
+#define DBL_MIN 2.2250738585072014E-308
+#define DBL_MIN_10_EXP (-307)
+#define DBL_MAX_EXP 1024
+#define DBL_MAX 1.7976931348623157E+308
+#define DBL_MAX_10_EXP 308
+#if __ISO_C_VISIBLE >= 2011
+#define DBL_TRUE_MIN 4.9406564584124654E-324
+#define DBL_DECIMAL_DIG 17
+#define DBL_HAS_SUBNORM 1
+#endif /* __ISO_C_VISIBLE >= 2011 */
+
+#define LDBL_MANT_DIG DBL_MANT_DIG
+#define LDBL_EPSILON ((long double)DBL_EPSILON)
+#define LDBL_DIG DBL_DIG
+#define LDBL_MIN_EXP DBL_MIN_EXP
+#define LDBL_MIN ((long double)DBL_MIN)
+#define LDBL_MIN_10_EXP DBL_MIN_10_EXP
+#define LDBL_MAX_EXP DBL_MAX_EXP
+#define LDBL_MAX ((long double)DBL_MAX)
+#define LDBL_MAX_10_EXP DBL_MAX_10_EXP
+#if __ISO_C_VISIBLE >= 2011
+#define LDBL_TRUE_MIN ((long double)DBL_TRUE_MIN)
+#define LDBL_DECIMAL_DIG DBL_DECIMAL_DIG
+#define LDBL_HAS_SUBNORM DBL_HAS_SUBNORM
+#endif /* __ISO_C_VISIBLE >= 2011 */
+
+#endif /* _MACHINE_FLOAT_H_ */
diff --git a/include/lib/libc/aarch32/inttypes_.h b/include/lib/libc/aarch32/inttypes_.h
new file mode 100644
index 0000000..ef3fb8f
--- /dev/null
+++ b/include/lib/libc/aarch32/inttypes_.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020 Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2020, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef INTTYPES__H
+#define INTTYPES__H
+
+#define PRId64 "lld" /* int64_t */
+#define PRIi64 "lli" /* int64_t */
+#define PRIo64 "llo" /* int64_t */
+#define PRIu64 "llu" /* uint64_t */
+#define PRIx64 "llx" /* uint64_t */
+#define PRIX64 "llX" /* uint64_t */
+
+#define PRIdPTR "d" /* intptr_t */
+#define PRIiPTR "i" /* intptr_t */
+#define PRIoPTR "o" /* intptr_t */
+#define PRIuPTR "u" /* uintptr_t */
+#define PRIxPTR "x" /* uintptr_t */
+#define PRIXPTR "X" /* uintptr_t */
+
+#endif /* INTTYPES__H */
diff --git a/include/lib/libc/aarch32/limits_.h b/include/lib/libc/aarch32/limits_.h
new file mode 100644
index 0000000..26cec17
--- /dev/null
+++ b/include/lib/libc/aarch32/limits_.h
@@ -0,0 +1,26 @@
+/*
+ * 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
diff --git a/include/lib/libc/aarch32/stddef_.h b/include/lib/libc/aarch32/stddef_.h
new file mode 100644
index 0000000..36dc20b
--- /dev/null
+++ b/include/lib/libc/aarch32/stddef_.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2018-2019, 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
+
+#endif /* STDDEF__H */
diff --git a/include/lib/libc/aarch32/stdint_.h b/include/lib/libc/aarch32/stdint_.h
new file mode 100644
index 0000000..dafe142
--- /dev/null
+++ b/include/lib/libc/aarch32/stdint_.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020 Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2020, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef STDINT__H
+#define STDINT__H
+
+#define INT64_MAX LLONG_MAX
+#define INT64_MIN LLONG_MIN
+#define UINT64_MAX ULLONG_MAX
+
+#define INT64_C(x) x ## LL
+#define UINT64_C(x) x ## ULL
+
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+typedef long long int64_least_t;
+typedef unsigned long long uint64_least_t;
+typedef long long int64_fast_t;
+typedef unsigned long long uint64_fast_t;
+
+#endif
diff --git a/include/lib/libc/aarch32/stdio_.h b/include/lib/libc/aarch32/stdio_.h
new file mode 100644
index 0000000..5e49425
--- /dev/null
+++ b/include/lib/libc/aarch32/stdio_.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STDIO__H
+#define STDIO__H
+
+#ifndef SSIZET_
+typedef int ssize_t;
+#define SSIZET_
+#endif
+
+#endif /* STDIO__H */
diff --git a/include/lib/libc/aarch64/endian_.h b/include/lib/libc/aarch64/endian_.h
new file mode 100644
index 0000000..7c79fd4
--- /dev/null
+++ b/include/lib/libc/aarch64/endian_.h
@@ -0,0 +1,128 @@
+/*-
+ * 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 <stdint.h>
+
+/*
+ * 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 */
diff --git a/include/lib/libc/aarch64/float.h b/include/lib/libc/aarch64/float.h
new file mode 100644
index 0000000..0829f6f
--- /dev/null
+++ b/include/lib/libc/aarch64/float.h
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 1989 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.
+ *
+ * from: @(#)float.h 7.1 (Berkeley) 5/8/90
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_FLOAT_H_
+#define _MACHINE_FLOAT_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+extern int __flt_rounds(void);
+__END_DECLS
+
+#define FLT_RADIX 2 /* b */
+#define FLT_ROUNDS __flt_rounds()
+#if __ISO_C_VISIBLE >= 1999
+#define FLT_EVAL_METHOD 0
+#define DECIMAL_DIG 17 /* max precision in decimal digits */
+#endif
+
+#define FLT_MANT_DIG 24 /* p */
+#define FLT_EPSILON 1.19209290E-07F /* b**(1-p) */
+#define FLT_DIG 6 /* floor((p-1)*log10(b))+(b == 10) */
+#define FLT_MIN_EXP (-125) /* emin */
+#define FLT_MIN 1.17549435E-38F /* b**(emin-1) */
+#define FLT_MIN_10_EXP (-37) /* ceil(log10(b**(emin-1))) */
+#define FLT_MAX_EXP 128 /* emax */
+#define FLT_MAX 3.40282347E+38F /* (1-b**(-p))*b**emax */
+#define FLT_MAX_10_EXP 38 /* floor(log10((1-b**(-p))*b**emax)) */
+#if __ISO_C_VISIBLE >= 2011
+#define FLT_TRUE_MIN 1.40129846E-45F /* b**(emin-p) */
+#define FLT_DECIMAL_DIG 9 /* ceil(1+p*log10(b)) */
+#define FLT_HAS_SUBNORM 1
+#endif /* __ISO_C_VISIBLE >= 2011 */
+
+#define DBL_MANT_DIG 53
+#define DBL_EPSILON 2.2204460492503131E-16
+#define DBL_DIG 15
+#define DBL_MIN_EXP (-1021)
+#define DBL_MIN 2.2250738585072014E-308
+#define DBL_MIN_10_EXP (-307)
+#define DBL_MAX_EXP 1024
+#define DBL_MAX 1.7976931348623157E+308
+#define DBL_MAX_10_EXP 308
+#if __ISO_C_VISIBLE >= 2011
+#define DBL_TRUE_MIN 4.9406564584124654E-324
+#define DBL_DECIMAL_DIG 17
+#define DBL_HAS_SUBNORM 1
+#endif /* __ISO_C_VISIBLE >= 2011 */
+
+#define LDBL_MANT_DIG 113
+#define LDBL_EPSILON 1.925929944387235853055977942584927319E-34L
+#define LDBL_DIG 33
+#define LDBL_MIN_EXP (-16381)
+#define LDBL_MIN 3.362103143112093506262677817321752603E-4932L
+#define LDBL_MIN_10_EXP (-4931)
+#define LDBL_MAX_EXP (+16384)
+#define LDBL_MAX 1.189731495357231765085759326628007016E+4932L
+#define LDBL_MAX_10_EXP (+4932)
+#if __ISO_C_VISIBLE >= 2011
+#define LDBL_TRUE_MIN 6.475175119438025110924438958227646552E-4966L
+#define LDBL_DECIMAL_DIG 36
+#define LDBL_HAS_SUBNORM 1
+#endif /* __ISO_C_VISIBLE >= 2011 */
+
+#endif /* _MACHINE_FLOAT_H_ */
diff --git a/include/lib/libc/aarch64/inttypes_.h b/include/lib/libc/aarch64/inttypes_.h
new file mode 100644
index 0000000..f25882f
--- /dev/null
+++ b/include/lib/libc/aarch64/inttypes_.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020 Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2020, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef INTTYPES__H
+#define INTTYPES__H
+
+#define PRId64 "ld" /* int64_t */
+#define PRIi64 "li" /* int64_t */
+#define PRIo64 "lo" /* int64_t */
+#define PRIu64 "lu" /* uint64_t */
+#define PRIx64 "lx" /* uint64_t */
+#define PRIX64 "lX" /* uint64_t */
+
+#define PRIdPTR "ld" /* intptr_t */
+#define PRIiPTR "li" /* intptr_t */
+#define PRIoPTR "lo" /* intptr_t */
+#define PRIuPTR "lu" /* uintptr_t */
+#define PRIxPTR "lx" /* uintptr_t */
+#define PRIXPTR "lX" /* uintptr_t */
+
+#endif /* INTTYPES__H */
diff --git a/include/lib/libc/aarch64/limits_.h b/include/lib/libc/aarch64/limits_.h
new file mode 100644
index 0000000..e36cfe7
--- /dev/null
+++ b/include/lib/libc/aarch64/limits_.h
@@ -0,0 +1,26 @@
+/*
+ * 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
diff --git a/include/lib/libc/aarch64/setjmp_.h b/include/lib/libc/aarch64/setjmp_.h
new file mode 100644
index 0000000..f880a17
--- /dev/null
+++ b/include/lib/libc/aarch64/setjmp_.h
@@ -0,0 +1,30 @@
+/*
+ * 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 <cdefs.h>
+
+/* Jump buffer hosting x18 - x30 and sp_el0 registers */
+typedef uint64_t jmp_buf[JMP_SIZE] __aligned(16);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* SETJMP__H */
diff --git a/include/lib/libc/aarch64/stddef_.h b/include/lib/libc/aarch64/stddef_.h
new file mode 100644
index 0000000..6ecc606
--- /dev/null
+++ b/include/lib/libc/aarch64/stddef_.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2018-2019, 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
+
+#endif /* STDDEF__H */
diff --git a/include/lib/libc/aarch64/stdint_.h b/include/lib/libc/aarch64/stdint_.h
new file mode 100644
index 0000000..56e9f1b
--- /dev/null
+++ b/include/lib/libc/aarch64/stdint_.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2020 Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2020, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef STDINT__H
+#define STDINT__H
+
+#define INT64_MAX LONG_MAX
+#define INT64_MIN LONG_MIN
+#define UINT64_MAX ULONG_MAX
+
+#define INT64_C(x) x ## L
+#define UINT64_C(x) x ## UL
+
+typedef long int64_t;
+typedef unsigned long uint64_t;
+typedef long int64_least_t;
+typedef unsigned long uint64_least_t;
+typedef long int64_fast_t;
+typedef unsigned long uint64_fast_t;
+
+typedef __int128 int128_t;
+typedef unsigned __int128 uint128_t;
+
+#endif
diff --git a/include/lib/libc/aarch64/stdio_.h b/include/lib/libc/aarch64/stdio_.h
new file mode 100644
index 0000000..afaeadc
--- /dev/null
+++ b/include/lib/libc/aarch64/stdio_.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STDIO__H
+#define STDIO__H
+
+#ifndef SSIZET_
+typedef long ssize_t;
+#define SSIZET_
+#endif
+
+#endif /* STDIO__H */
diff --git a/include/lib/libc/arm_acle.h b/include/lib/libc/arm_acle.h
new file mode 100644
index 0000000..eb08552
--- /dev/null
+++ b/include/lib/libc/arm_acle.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2021 ARM Limited
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * The definitions below are a subset of what we would normally get by using
+ * the compiler's version of arm_acle.h. We can't use that directly because
+ * we specify -nostdinc in the Makefiles.
+ *
+ * We just define the functions we need so far.
+ */
+
+#ifndef ARM_ACLE_H
+#define ARM_ACLE_H
+
+#if !defined(__aarch64__) || defined(__clang__)
+# define __crc32b __builtin_arm_crc32b
+# define __crc32w __builtin_arm_crc32w
+#else
+# define __crc32b __builtin_aarch64_crc32b
+# define __crc32w __builtin_aarch64_crc32w
+#endif
+
+#endif /* ARM_ACLE_H */
diff --git a/include/lib/libc/assert.h b/include/lib/libc/assert.h
new file mode 100644
index 0000000..462bb43
--- /dev/null
+++ b/include/lib/libc/assert.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ASSERT_H
+#define ASSERT_H
+
+#include <cdefs.h>
+
+#include <common/debug.h>
+
+#ifndef PLAT_LOG_LEVEL_ASSERT
+#define PLAT_LOG_LEVEL_ASSERT LOG_LEVEL
+#endif
+
+#if ENABLE_ASSERTIONS
+# if 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_INFO
+void __dead2 __assert(const char *file, unsigned int line);
+#else
+void __dead2 __assert(void);
+#endif
+
+#endif /* ASSERT_H */
diff --git a/include/lib/libc/cdefs.h b/include/lib/libc/cdefs.h
new file mode 100644
index 0000000..423f0db
--- /dev/null
+++ b/include/lib/libc/cdefs.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018-2022, 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 __maybe_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 */
diff --git a/include/lib/libc/endian.h b/include/lib/libc/endian.h
new file mode 100644
index 0000000..4100f57
--- /dev/null
+++ b/include/lib/libc/endian.h
@@ -0,0 +1,191 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2002 Thomas Moestl <tmm@FreeBSD.org>
+ * 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 <cdefs.h>
+#include <stdint.h>
+#include <endian_.h>
+
+/*
+ * 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 */
diff --git a/include/lib/libc/errno.h b/include/lib/libc/errno.h
new file mode 100644
index 0000000..029912f
--- /dev/null
+++ b/include/lib/libc/errno.h
@@ -0,0 +1,169 @@
+/*-
+ * 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 */
diff --git a/include/lib/libc/inttypes.h b/include/lib/libc/inttypes.h
new file mode 100644
index 0000000..6ad1c9e
--- /dev/null
+++ b/include/lib/libc/inttypes.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020 Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2020, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef INTTYPES_H
+#define INTTYPES_H
+
+#include <inttypes_.h>
+#include <stdint.h>
+
+#define PRId8 "d" /* int8_t */
+#define PRId16 "d" /* int16_t */
+#define PRId32 "d" /* int32_t */
+
+#define PRIi8 "i" /* int8_t */
+#define PRIi16 "i" /* int16_t */
+#define PRIi32 "i" /* int32_t */
+
+#define PRIo8 "o" /* int8_t */
+#define PRIo16 "o" /* int16_t */
+#define PRIo32 "o" /* int32_t */
+
+#define PRIu8 "u" /* uint8_t */
+#define PRIu16 "u" /* uint16_t */
+#define PRIu32 "u" /* uint32_t */
+
+#define PRIx8 "x" /* uint8_t */
+#define PRIx16 "x" /* uint16_t */
+#define PRIx32 "x" /* uint32_t */
+
+#define PRIX8 "X" /* uint8_t */
+#define PRIX16 "X" /* uint16_t */
+#define PRIX32 "X" /* uint32_t */
+
+#endif
diff --git a/include/lib/libc/limits.h b/include/lib/libc/limits.h
new file mode 100644
index 0000000..41bb658
--- /dev/null
+++ b/include/lib/libc/limits.h
@@ -0,0 +1,19 @@
+/*
+ * 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 <limits_.h>
+
+#define CHAR_BIT 8
+#define MB_LEN_MAX 1
+
+#endif /* LIMITS_H */
diff --git a/include/lib/libc/setjmp.h b/include/lib/libc/setjmp.h
new file mode 100644
index 0000000..be8e2c0
--- /dev/null
+++ b/include/lib/libc/setjmp.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SETJMP_H
+#define SETJMP_H
+
+#include <setjmp_.h>
+
+#ifndef __ASSEMBLER__
+
+#include <cdefs.h>
+
+int setjmp(jmp_buf env);
+__dead2 void longjmp(jmp_buf env, int val);
+
+#endif /* __ASSEMBLER__ */
+#endif /* SETJMP_H */
diff --git a/include/lib/libc/stdarg.h b/include/lib/libc/stdarg.h
new file mode 100644
index 0000000..e260b9b
--- /dev/null
+++ b/include/lib/libc/stdarg.h
@@ -0,0 +1,20 @@
+/*
+ * 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 */
diff --git a/include/lib/libc/stdbool.h b/include/lib/libc/stdbool.h
new file mode 100644
index 0000000..b58334c
--- /dev/null
+++ b/include/lib/libc/stdbool.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STDBOOL_H
+#define STDBOOL_H
+
+#define bool _Bool
+
+#define true (0 < 1)
+#define false (0 > 1)
+
+#define __bool_true_false_are_defined 1
+
+#endif /* STDBOOL_H */
diff --git a/include/lib/libc/stddef.h b/include/lib/libc/stddef.h
new file mode 100644
index 0000000..58a519e
--- /dev/null
+++ b/include/lib/libc/stddef.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2012-2017 Roberto E. Vargas Caballero
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2018-2019, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef STDDEF_H
+#define STDDEF_H
+
+#include <stddef_.h>
+
+#ifndef _PTRDIFF_T
+typedef long ptrdiff_t;
+#define _PTRDIFF_T
+#endif
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#define offsetof(st, m) __builtin_offsetof(st, m)
+
+#endif /* STDDEF_H */
diff --git a/include/lib/libc/stdint.h b/include/lib/libc/stdint.h
new file mode 100644
index 0000000..e96a25c
--- /dev/null
+++ b/include/lib/libc/stdint.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2012-2017 Roberto E. Vargas Caballero
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2018-2019, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef STDINT_H
+#define STDINT_H
+
+#include <limits.h>
+#include <stdint_.h>
+
+#define INT8_MAX CHAR_MAX
+#define INT8_MIN CHAR_MIN
+#define UINT8_MAX UCHAR_MAX
+
+#define INT16_MAX SHRT_MAX
+#define INT16_MIN SHRT_MIN
+#define UINT16_MAX USHRT_MAX
+
+#define INT32_MAX INT_MAX
+#define INT32_MIN INT_MIN
+#define UINT32_MAX UINT_MAX
+
+#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 LONG_MIN
+#define INTPTR_MAX LONG_MAX
+#define UINTPTR_MAX ULONG_MAX
+
+#define INTMAX_MIN LLONG_MIN
+#define INTMAX_MAX LLONG_MAX
+#define UINTMAX_MAX ULLONG_MAX
+
+#define PTRDIFF_MIN LONG_MIN
+#define PTRDIFF_MAX LONG_MAX
+
+#define SIZE_MAX ULONG_MAX
+
+#define INT8_C(x) x
+#define INT16_C(x) x
+#define INT32_C(x) x
+
+#define UINT8_C(x) x
+#define UINT16_C(x) x
+#define UINT32_C(x) x ## U
+
+#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 unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+
+typedef signed char int8_least_t;
+typedef short int16_least_t;
+typedef int int32_least_t;
+
+typedef unsigned char uint8_least_t;
+typedef unsigned short uint16_least_t;
+typedef unsigned int uint32_least_t;
+
+typedef int int8_fast_t;
+typedef int int16_fast_t;
+typedef int int32_fast_t;
+
+typedef unsigned int uint8_fast_t;
+typedef unsigned int uint16_fast_t;
+typedef unsigned int uint32_fast_t;
+
+typedef long intptr_t;
+typedef unsigned long uintptr_t;
+
+/*
+* Conceptually, these are supposed to be the largest integers representable in C,
+* but GCC and Clang define them as long long for compatibility.
+*/
+typedef long long intmax_t;
+typedef unsigned long long uintmax_t;
+
+typedef long register_t;
+typedef unsigned long u_register_t;
+
+#endif /* STDINT_H */
diff --git a/include/lib/libc/stdio.h b/include/lib/libc/stdio.h
new file mode 100644
index 0000000..ba13683
--- /dev/null
+++ b/include/lib/libc/stdio.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2012-2017 Roberto E. Vargas Caballero
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2018-2019, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef STDIO_H
+#define STDIO_H
+
+#include <cdefs.h>
+#include <stddef.h>
+#include <stdio_.h>
+
+#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);
+int vsnprintf(char *s, size_t n, const char *fmt, va_list args);
+#endif
+
+int putchar(int c);
+int puts(const char *s);
+
+#endif /* STDIO_H */
diff --git a/include/lib/libc/stdlib.h b/include/lib/libc/stdlib.h
new file mode 100644
index 0000000..4641e56
--- /dev/null
+++ b/include/lib/libc/stdlib.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2012-2021 Roberto E. Vargas Caballero
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2018-2019, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef STDLIB_H
+#define STDLIB_H
+
+#include <stddef.h>
+
+#define EXIT_FAILURE 1
+#define EXIT_SUCCESS 0
+
+#define _ATEXIT_MAX 1
+
+#define isspace(x) (((x) == ' ') || ((x) == '\r') || ((x) == '\n') || \
+ ((x) == '\t') || ((x) == '\b'))
+
+extern void abort(void);
+extern int atexit(void (*func)(void));
+extern void exit(int status);
+
+long strtol(const char *nptr, char **endptr, int base);
+unsigned long strtoul(const char *nptr, char **endptr, int base);
+long long strtoll(const char *nptr, char **endptr, int base);
+unsigned long long strtoull(const char *nptr, char **endptr, int base);
+#endif /* STDLIB_H */
diff --git a/include/lib/libc/string.h b/include/lib/libc/string.h
new file mode 100644
index 0000000..9894483
--- /dev/null
+++ b/include/lib/libc/string.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2012-2017 Roberto E. Vargas Caballero
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2018-2020, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef STRING_H
+#define STRING_H
+
+#include <stddef.h>
+
+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);
+void *memrchr(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);
+size_t strlcat(char * dst, const char * src, size_t dsize);
+char *strtok_r(char *s, const char *delim, char **last);
+
+#endif /* STRING_H */
diff --git a/include/lib/libc/sys/cdefs.h b/include/lib/libc/sys/cdefs.h
new file mode 100644
index 0000000..1ace5fb
--- /dev/null
+++ b/include/lib/libc/sys/cdefs.h
@@ -0,0 +1,922 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Berkeley Software Design, 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.
+ *
+ * @(#)cdefs.h 8.8 (Berkeley) 1/9/95
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_CDEFS_H_
+#define _SYS_CDEFS_H_
+
+#if defined(_KERNEL) && defined(_STANDALONE)
+#error "_KERNEL and _STANDALONE are mutually exclusive"
+#endif
+
+/*
+ * Testing against Clang-specific extensions.
+ */
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+#ifndef __has_extension
+#define __has_extension __has_feature
+#endif
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+#ifndef __has_include
+#define __has_include(x) 0
+#endif
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+
+#if defined(__cplusplus)
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS }
+#else
+#define __BEGIN_DECLS
+#define __END_DECLS
+#endif
+
+/*
+ * This code has been put in place to help reduce the addition of
+ * compiler specific defines in FreeBSD code. It helps to aid in
+ * having a compiler-agnostic source tree.
+ */
+
+#if defined(__GNUC__)
+
+#if __GNUC__ >= 3
+#define __GNUCLIKE_ASM 3
+#define __GNUCLIKE_MATH_BUILTIN_CONSTANTS
+#else
+#define __GNUCLIKE_ASM 2
+#endif
+#define __GNUCLIKE___TYPEOF 1
+#define __GNUCLIKE___SECTION 1
+
+#define __GNUCLIKE_CTOR_SECTION_HANDLING 1
+
+#define __GNUCLIKE_BUILTIN_CONSTANT_P 1
+
+#if (__GNUC_MINOR__ > 95 || __GNUC__ >= 3)
+#define __GNUCLIKE_BUILTIN_VARARGS 1
+#define __GNUCLIKE_BUILTIN_STDARG 1
+#define __GNUCLIKE_BUILTIN_VAALIST 1
+#endif
+
+#define __GNUC_VA_LIST_COMPATIBILITY 1
+
+/*
+ * Compiler memory barriers, specific to gcc and clang.
+ */
+#define __compiler_membar() __asm __volatile(" " : : : "memory")
+
+#define __GNUCLIKE_BUILTIN_NEXT_ARG 1
+#define __GNUCLIKE_MATH_BUILTIN_RELOPS
+
+#define __GNUCLIKE_BUILTIN_MEMCPY 1
+
+/* XXX: if __GNUC__ >= 2: not tested everywhere originally, where replaced */
+#define __CC_SUPPORTS_INLINE 1
+#define __CC_SUPPORTS___INLINE 1
+#define __CC_SUPPORTS___INLINE__ 1
+
+#define __CC_SUPPORTS___FUNC__ 1
+#define __CC_SUPPORTS_WARNING 1
+
+#define __CC_SUPPORTS_VARADIC_XXX 1 /* see varargs.h */
+
+#define __CC_SUPPORTS_DYNAMIC_ARRAY_INIT 1
+
+#endif /* __GNUC__ */
+
+/*
+ * Macro to test if we're using a specific version of gcc or later.
+ */
+#if defined(__GNUC__)
+#define __GNUC_PREREQ__(ma, mi) \
+ (__GNUC__ > (ma) || __GNUC__ == (ma) && __GNUC_MINOR__ >= (mi))
+#else
+#define __GNUC_PREREQ__(ma, mi) 0
+#endif
+
+/*
+ * The __CONCAT macro is used to concatenate parts of symbol names, e.g.
+ * with "#define OLD(foo) __CONCAT(old,foo)", OLD(foo) produces oldfoo.
+ * The __CONCAT macro is a bit tricky to use if it must work in non-ANSI
+ * mode -- there must be no spaces between its arguments, and for nested
+ * __CONCAT's, all the __CONCAT's must be at the left. __CONCAT can also
+ * concatenate double-quoted strings produced by the __STRING macro, but
+ * this only works with ANSI C.
+ *
+ * __XSTRING is like __STRING, but it expands any macros in its argument
+ * first. It is only available with ANSI C.
+ */
+#if defined(__STDC__) || defined(__cplusplus)
+#define __P(protos) protos /* full-blown ANSI C */
+#define __CONCAT1(x,y) x ## y
+#define __CONCAT(x,y) __CONCAT1(x,y)
+#define __STRING(x) #x /* stringify without expanding x */
+#define __XSTRING(x) __STRING(x) /* expand x, then stringify */
+
+#define __const const /* define reserved names to standard */
+#define __signed signed
+#define __volatile volatile
+#if defined(__cplusplus)
+#define __inline inline /* convert to C++ keyword */
+#else
+#if !(defined(__CC_SUPPORTS___INLINE))
+#define __inline /* delete GCC keyword */
+#endif /* ! __CC_SUPPORTS___INLINE */
+#endif /* !__cplusplus */
+
+#else /* !(__STDC__ || __cplusplus) */
+#define __P(protos) () /* traditional C preprocessor */
+#define __CONCAT(x,y) x/**/y
+#define __STRING(x) "x"
+
+#if !defined(__CC_SUPPORTS___INLINE)
+#define __const /* delete pseudo-ANSI C keywords */
+#define __inline
+#define __signed
+#define __volatile
+/*
+ * In non-ANSI C environments, new programs will want ANSI-only C keywords
+ * deleted from the program and old programs will want them left alone.
+ * When using a compiler other than gcc, programs using the ANSI C keywords
+ * const, inline etc. as normal identifiers should define -DNO_ANSI_KEYWORDS.
+ * When using "gcc -traditional", we assume that this is the intent; if
+ * __GNUC__ is defined but __STDC__ is not, we leave the new keywords alone.
+ */
+#ifndef NO_ANSI_KEYWORDS
+#define const /* delete ANSI C keywords */
+#define inline
+#define signed
+#define volatile
+#endif /* !NO_ANSI_KEYWORDS */
+#endif /* !__CC_SUPPORTS___INLINE */
+#endif /* !(__STDC__ || __cplusplus) */
+
+/*
+ * Compiler-dependent macros to help declare dead (non-returning) and
+ * pure (no side effects) functions, and unused variables. They are
+ * null except for versions of gcc that are known to support the features
+ * properly (old versions of gcc-2 supported the dead and pure features
+ * in a different (wrong) way). If we do not provide an implementation
+ * for a given compiler, let the compile fail if it is told to use
+ * a feature that we cannot live without.
+ */
+#define __weak_symbol __attribute__((__weak__))
+#if !__GNUC_PREREQ__(2, 5)
+#define __dead2
+#define __pure2
+#define __unused
+#endif
+#if __GNUC__ == 2 && __GNUC_MINOR__ >= 5 && __GNUC_MINOR__ < 7
+#define __dead2 __attribute__((__noreturn__))
+#define __pure2 __attribute__((__const__))
+#define __unused
+/* XXX Find out what to do for __packed, __aligned and __section */
+#endif
+#if __GNUC_PREREQ__(2, 7)
+#define __dead2 __attribute__((__noreturn__))
+#define __pure2 __attribute__((__const__))
+#define __unused __attribute__((__unused__))
+#define __used __attribute__((__used__))
+#define __packed __attribute__((__packed__))
+#define __aligned(x) __attribute__((__aligned__(x)))
+#define __section(x) __attribute__((__section__(x)))
+#endif
+#if __GNUC_PREREQ__(4, 3) || __has_attribute(__alloc_size__)
+#define __alloc_size(x) __attribute__((__alloc_size__(x)))
+#define __alloc_size2(n, x) __attribute__((__alloc_size__(n, x)))
+#else
+#define __alloc_size(x)
+#define __alloc_size2(n, x)
+#endif
+#if __GNUC_PREREQ__(4, 9) || __has_attribute(__alloc_align__)
+#define __alloc_align(x) __attribute__((__alloc_align__(x)))
+#else
+#define __alloc_align(x)
+#endif
+
+#if !__GNUC_PREREQ__(2, 95)
+#define __alignof(x) __offsetof(struct { char __a; x __b; }, __b)
+#endif
+
+/*
+ * Keywords added in C11.
+ */
+
+#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L
+
+#if !__has_extension(c_alignas)
+#if (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ __has_extension(cxx_alignas)
+#define _Alignas(x) alignas(x)
+#else
+/* XXX: Only emulates _Alignas(constant-expression); not _Alignas(type-name). */
+#define _Alignas(x) __aligned(x)
+#endif
+#endif
+
+#if defined(__cplusplus) && __cplusplus >= 201103L
+#define _Alignof(x) alignof(x)
+#else
+#define _Alignof(x) __alignof(x)
+#endif
+
+#if !defined(__cplusplus) && !__has_extension(c_atomic) && \
+ !__has_extension(cxx_atomic) && !__GNUC_PREREQ__(4, 7)
+/*
+ * No native support for _Atomic(). Place object in structure to prevent
+ * most forms of direct non-atomic access.
+ */
+#define _Atomic(T) struct { T volatile __val; }
+#endif
+
+#if defined(__cplusplus) && __cplusplus >= 201103L
+#define _Noreturn [[noreturn]]
+#else
+#define _Noreturn __dead2
+#endif
+
+#if !__has_extension(c_static_assert)
+#if (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ __has_extension(cxx_static_assert)
+#define _Static_assert(x, y) static_assert(x, y)
+#elif __GNUC_PREREQ__(4,6) && !defined(__cplusplus)
+/* Nothing, gcc 4.6 and higher has _Static_assert built-in */
+#elif defined(__COUNTER__)
+#define _Static_assert(x, y) __Static_assert(x, __COUNTER__)
+#define __Static_assert(x, y) ___Static_assert(x, y)
+#define ___Static_assert(x, y) typedef char __assert_ ## y[(x) ? 1 : -1] \
+ __unused
+#else
+#define _Static_assert(x, y) struct __hack
+#endif
+#endif
+
+#if !__has_extension(c_thread_local)
+/*
+ * XXX: Some compilers (Clang 3.3, GCC 4.7) falsely announce C++11 mode
+ * without actually supporting the thread_local keyword. Don't check for
+ * the presence of C++11 when defining _Thread_local.
+ */
+#if /* (defined(__cplusplus) && __cplusplus >= 201103L) || */ \
+ __has_extension(cxx_thread_local)
+#define _Thread_local thread_local
+#else
+#define _Thread_local __thread
+#endif
+#endif
+
+#endif /* __STDC_VERSION__ || __STDC_VERSION__ < 201112L */
+
+/*
+ * Emulation of C11 _Generic(). Unlike the previously defined C11
+ * keywords, it is not possible to implement this using exactly the same
+ * syntax. Therefore implement something similar under the name
+ * __generic(). Unlike _Generic(), this macro can only distinguish
+ * between a single type, so it requires nested invocations to
+ * distinguish multiple cases.
+ */
+
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || \
+ __has_extension(c_generic_selections)
+#define __generic(expr, t, yes, no) \
+ _Generic(expr, t: yes, default: no)
+#elif __GNUC_PREREQ__(3, 1) && !defined(__cplusplus)
+#define __generic(expr, t, yes, no) \
+ __builtin_choose_expr( \
+ __builtin_types_compatible_p(__typeof(expr), t), yes, no)
+#endif
+
+/*
+ * C99 Static array indices in function parameter declarations. Syntax such as:
+ * void bar(int myArray[static 10]);
+ * is allowed in C99 but not in C++. Define __min_size appropriately so
+ * headers using it can be compiled in either language. Use like this:
+ * void bar(int myArray[__min_size(10)]);
+ */
+#if !defined(__cplusplus) && \
+ (defined(__clang__) || __GNUC_PREREQ__(4, 6)) && \
+ (!defined(__STDC_VERSION__) || (__STDC_VERSION__ >= 199901))
+#define __min_size(x) static (x)
+#else
+#define __min_size(x) (x)
+#endif
+
+#if __GNUC_PREREQ__(2, 96)
+#define __malloc_like __attribute__((__malloc__))
+#define __pure __attribute__((__pure__))
+#else
+#define __malloc_like
+#define __pure
+#endif
+
+#if __GNUC_PREREQ__(3, 1)
+#define __always_inline __attribute__((__always_inline__))
+#else
+#define __always_inline
+#endif
+
+#if __GNUC_PREREQ__(3, 1)
+#define __noinline __attribute__ ((__noinline__))
+#else
+#define __noinline
+#endif
+
+#if __GNUC_PREREQ__(3, 4)
+#define __fastcall __attribute__((__fastcall__))
+#define __result_use_check __attribute__((__warn_unused_result__))
+#else
+#define __fastcall
+#define __result_use_check
+#endif
+
+#if __GNUC_PREREQ__(4, 1)
+#define __returns_twice __attribute__((__returns_twice__))
+#else
+#define __returns_twice
+#endif
+
+#if __GNUC_PREREQ__(4, 6) || __has_builtin(__builtin_unreachable)
+#define __unreachable() __builtin_unreachable()
+#else
+#define __unreachable() ((void)0)
+#endif
+
+/* XXX: should use `#if __STDC_VERSION__ < 199901'. */
+#if !__GNUC_PREREQ__(2, 7)
+#define __func__ NULL
+#endif
+
+#if (defined(__GNUC__) && __GNUC__ >= 2) && !defined(__STRICT_ANSI__) || __STDC_VERSION__ >= 199901
+#define __LONG_LONG_SUPPORTED
+#endif
+
+/* C++11 exposes a load of C99 stuff */
+#if defined(__cplusplus) && __cplusplus >= 201103L
+#define __LONG_LONG_SUPPORTED
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+#endif
+
+/*
+ * GCC 2.95 provides `__restrict' as an extension to C90 to support the
+ * C99-specific `restrict' type qualifier. We happen to use `__restrict' as
+ * a way to define the `restrict' type qualifier without disturbing older
+ * software that is unaware of C99 keywords.
+ */
+#if !(__GNUC__ == 2 && __GNUC_MINOR__ == 95)
+#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901
+#define __restrict
+#else
+#define __restrict restrict
+#endif
+#endif
+
+/*
+ * GNU C version 2.96 adds explicit branch prediction so that
+ * the CPU back-end can hint the processor and also so that
+ * code blocks can be reordered such that the predicted path
+ * sees a more linear flow, thus improving cache behavior, etc.
+ *
+ * The following two macros provide us with a way to utilize this
+ * compiler feature. Use __predict_true() if you expect the expression
+ * to evaluate to true, and __predict_false() if you expect the
+ * expression to evaluate to false.
+ *
+ * A few notes about usage:
+ *
+ * * Generally, __predict_false() error condition checks (unless
+ * you have some _strong_ reason to do otherwise, in which case
+ * document it), and/or __predict_true() `no-error' condition
+ * checks, assuming you want to optimize for the no-error case.
+ *
+ * * Other than that, if you don't know the likelihood of a test
+ * succeeding from empirical or other `hard' evidence, don't
+ * make predictions.
+ *
+ * * These are meant to be used in places that are run `a lot'.
+ * It is wasteful to make predictions in code that is run
+ * seldomly (e.g. at subsystem initialization time) as the
+ * basic block reordering that this affects can often generate
+ * larger code.
+ */
+#if __GNUC_PREREQ__(2, 96)
+#define __predict_true(exp) __builtin_expect((exp), 1)
+#define __predict_false(exp) __builtin_expect((exp), 0)
+#else
+#define __predict_true(exp) (exp)
+#define __predict_false(exp) (exp)
+#endif
+
+#if __GNUC_PREREQ__(4, 0)
+#define __null_sentinel __attribute__((__sentinel__))
+#define __exported __attribute__((__visibility__("default")))
+#define __hidden __attribute__((__visibility__("hidden")))
+#else
+#define __null_sentinel
+#define __exported
+#define __hidden
+#endif
+
+/*
+ * We define this here since <stddef.h>, <sys/queue.h>, and <sys/types.h>
+ * require it.
+ */
+#if __GNUC_PREREQ__(4, 1)
+#define __offsetof(type, field) __builtin_offsetof(type, field)
+#else
+#ifndef __cplusplus
+#define __offsetof(type, field) \
+ ((__size_t)(__uintptr_t)((const volatile void *)&((type *)0)->field))
+#else
+#define __offsetof(type, field) \
+ (__offsetof__ (reinterpret_cast <__size_t> \
+ (&reinterpret_cast <const volatile char &> \
+ (static_cast<type *> (0)->field))))
+#endif
+#endif
+#define __rangeof(type, start, end) \
+ (__offsetof(type, end) - __offsetof(type, start))
+
+/*
+ * Given the pointer x to the member m of the struct s, return
+ * a pointer to the containing structure. When using GCC, we first
+ * assign pointer x to a local variable, to check that its type is
+ * compatible with member m.
+ */
+#if __GNUC_PREREQ__(3, 1)
+#define __containerof(x, s, m) ({ \
+ const volatile __typeof(((s *)0)->m) *__x = (x); \
+ __DEQUALIFY(s *, (const volatile char *)__x - __offsetof(s, m));\
+})
+#else
+#define __containerof(x, s, m) \
+ __DEQUALIFY(s *, (const volatile char *)(x) - __offsetof(s, m))
+#endif
+
+/*
+ * Compiler-dependent macros to declare that functions take printf-like
+ * or scanf-like arguments. They are null except for versions of gcc
+ * that are known to support the features properly (old versions of gcc-2
+ * didn't permit keeping the keywords out of the application namespace).
+ */
+#if !__GNUC_PREREQ__(2, 7)
+#define __printflike(fmtarg, firstvararg)
+#define __scanflike(fmtarg, firstvararg)
+#define __format_arg(fmtarg)
+#define __strfmonlike(fmtarg, firstvararg)
+#define __strftimelike(fmtarg, firstvararg)
+#else
+#define __printflike(fmtarg, firstvararg) \
+ __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
+#define __scanflike(fmtarg, firstvararg) \
+ __attribute__((__format__ (__scanf__, fmtarg, firstvararg)))
+#define __format_arg(fmtarg) __attribute__((__format_arg__ (fmtarg)))
+#define __strfmonlike(fmtarg, firstvararg) \
+ __attribute__((__format__ (__strfmon__, fmtarg, firstvararg)))
+#define __strftimelike(fmtarg, firstvararg) \
+ __attribute__((__format__ (__strftime__, fmtarg, firstvararg)))
+#endif
+
+/* Compiler-dependent macros that rely on FreeBSD-specific extensions. */
+#if defined(__FreeBSD_cc_version) && __FreeBSD_cc_version >= 300001 && \
+ defined(__GNUC__)
+#define __printf0like(fmtarg, firstvararg) \
+ __attribute__((__format__ (__printf0__, fmtarg, firstvararg)))
+#else
+#define __printf0like(fmtarg, firstvararg)
+#endif
+
+#if defined(__GNUC__)
+#define __strong_reference(sym,aliassym) \
+ extern __typeof (sym) aliassym __attribute__ ((__alias__ (#sym)))
+#ifdef __STDC__
+#define __weak_reference(sym,alias) \
+ __asm__(".weak " #alias); \
+ __asm__(".equ " #alias ", " #sym)
+#define __warn_references(sym,msg) \
+ __asm__(".section .gnu.warning." #sym); \
+ __asm__(".asciz \"" msg "\""); \
+ __asm__(".previous")
+#define __sym_compat(sym,impl,verid) \
+ __asm__(".symver " #impl ", " #sym "@" #verid)
+#define __sym_default(sym,impl,verid) \
+ __asm__(".symver " #impl ", " #sym "@@@" #verid)
+#else
+#define __weak_reference(sym,alias) \
+ __asm__(".weak alias"); \
+ __asm__(".equ alias, sym")
+#define __warn_references(sym,msg) \
+ __asm__(".section .gnu.warning.sym"); \
+ __asm__(".asciz \"msg\""); \
+ __asm__(".previous")
+#define __sym_compat(sym,impl,verid) \
+ __asm__(".symver impl, sym@verid")
+#define __sym_default(impl,sym,verid) \
+ __asm__(".symver impl, sym@@@verid")
+#endif /* __STDC__ */
+#endif /* __GNUC__ */
+
+#define __GLOBL(sym) __asm__(".globl " __XSTRING(sym))
+#define __WEAK(sym) __asm__(".weak " __XSTRING(sym))
+
+#if defined(__GNUC__)
+#define __IDSTRING(name,string) __asm__(".ident\t\"" string "\"")
+#else
+/*
+ * The following definition might not work well if used in header files,
+ * but it should be better than nothing. If you want a "do nothing"
+ * version, then it should generate some harmless declaration, such as:
+ * #define __IDSTRING(name,string) struct __hack
+ */
+#define __IDSTRING(name,string) static const char name[] __unused = string
+#endif
+
+/*
+ * Embed the rcs id of a source file in the resulting library. Note that in
+ * more recent ELF binutils, we use .ident allowing the ID to be stripped.
+ * Usage:
+ * __FBSDID("$FreeBSD$");
+ */
+#ifndef __FBSDID
+#if !defined(STRIP_FBSDID)
+#define __FBSDID(s) __IDSTRING(__CONCAT(__rcsid_,__LINE__),s)
+#else
+#define __FBSDID(s) struct __hack
+#endif
+#endif
+
+#ifndef __RCSID
+#ifndef NO__RCSID
+#define __RCSID(s) __IDSTRING(__CONCAT(__rcsid_,__LINE__),s)
+#else
+#define __RCSID(s) struct __hack
+#endif
+#endif
+
+#ifndef __RCSID_SOURCE
+#ifndef NO__RCSID_SOURCE
+#define __RCSID_SOURCE(s) __IDSTRING(__CONCAT(__rcsid_source_,__LINE__),s)
+#else
+#define __RCSID_SOURCE(s) struct __hack
+#endif
+#endif
+
+#ifndef __SCCSID
+#ifndef NO__SCCSID
+#define __SCCSID(s) __IDSTRING(__CONCAT(__sccsid_,__LINE__),s)
+#else
+#define __SCCSID(s) struct __hack
+#endif
+#endif
+
+#ifndef __COPYRIGHT
+#ifndef NO__COPYRIGHT
+#define __COPYRIGHT(s) __IDSTRING(__CONCAT(__copyright_,__LINE__),s)
+#else
+#define __COPYRIGHT(s) struct __hack
+#endif
+#endif
+
+#ifndef __DECONST
+#define __DECONST(type, var) ((type)(__uintptr_t)(const void *)(var))
+#endif
+
+#ifndef __DEVOLATILE
+#define __DEVOLATILE(type, var) ((type)(__uintptr_t)(volatile void *)(var))
+#endif
+
+#ifndef __DEQUALIFY
+#define __DEQUALIFY(type, var) ((type)(__uintptr_t)(const volatile void *)(var))
+#endif
+
+/*-
+ * The following definitions are an extension of the behavior originally
+ * implemented in <sys/_posix.h>, but with a different level of granularity.
+ * POSIX.1 requires that the macros we test be defined before any standard
+ * header file is included.
+ *
+ * Here's a quick run-down of the versions (and some informal names)
+ * defined(_POSIX_SOURCE) 1003.1-1988
+ * encoded as 198808 below
+ * _POSIX_C_SOURCE == 1 1003.1-1990
+ * encoded as 199009 below
+ * _POSIX_C_SOURCE == 2 1003.2-1992 C Language Binding Option
+ * encoded as 199209 below
+ * _POSIX_C_SOURCE == 199309 1003.1b-1993
+ * (1003.1 Issue 4, Single Unix Spec v1, Unix 93)
+ * _POSIX_C_SOURCE == 199506 1003.1c-1995, 1003.1i-1995,
+ * and the omnibus ISO/IEC 9945-1: 1996
+ * (1003.1 Issue 5, Single Unix Spec v2, Unix 95)
+ * _POSIX_C_SOURCE == 200112 1003.1-2001 (1003.1 Issue 6, Unix 03)
+ * _POSIX_C_SOURCE == 200809 1003.1-2008 (1003.1 Issue 7)
+ * IEEE Std 1003.1-2017 (Rev of 1003.1-2008) is
+ * 1003.1-2008 with two TCs applied with
+ * _POSIX_C_SOURCE=200809 and _XOPEN_SOURCE=700
+ *
+ * In addition, the X/Open Portability Guide, which is now the Single UNIX
+ * Specification, defines a feature-test macro which indicates the version of
+ * that specification, and which subsumes _POSIX_C_SOURCE.
+ *
+ * Our macros begin with two underscores to avoid namespace screwage.
+ */
+
+/* Deal with IEEE Std. 1003.1-1990, in which _POSIX_C_SOURCE == 1. */
+#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE == 1
+#undef _POSIX_C_SOURCE /* Probably illegal, but beyond caring now. */
+#define _POSIX_C_SOURCE 199009
+#endif
+
+/* Deal with IEEE Std. 1003.2-1992, in which _POSIX_C_SOURCE == 2. */
+#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE == 2
+#undef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 199209
+#endif
+
+/* Deal with various X/Open Portability Guides and Single UNIX Spec. */
+#ifdef _XOPEN_SOURCE
+#if _XOPEN_SOURCE - 0 >= 700
+#define __XSI_VISIBLE 700
+#undef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 200809
+#elif _XOPEN_SOURCE - 0 >= 600
+#define __XSI_VISIBLE 600
+#undef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 200112
+#elif _XOPEN_SOURCE - 0 >= 500
+#define __XSI_VISIBLE 500
+#undef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 199506
+#endif
+#endif
+
+/*
+ * Deal with all versions of POSIX. The ordering relative to the tests above is
+ * important.
+ */
+#if defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE)
+#define _POSIX_C_SOURCE 198808
+#endif
+#ifdef _POSIX_C_SOURCE
+#if _POSIX_C_SOURCE >= 200809
+#define __POSIX_VISIBLE 200809
+#define __ISO_C_VISIBLE 1999
+#elif _POSIX_C_SOURCE >= 200112
+#define __POSIX_VISIBLE 200112
+#define __ISO_C_VISIBLE 1999
+#elif _POSIX_C_SOURCE >= 199506
+#define __POSIX_VISIBLE 199506
+#define __ISO_C_VISIBLE 1990
+#elif _POSIX_C_SOURCE >= 199309
+#define __POSIX_VISIBLE 199309
+#define __ISO_C_VISIBLE 1990
+#elif _POSIX_C_SOURCE >= 199209
+#define __POSIX_VISIBLE 199209
+#define __ISO_C_VISIBLE 1990
+#elif _POSIX_C_SOURCE >= 199009
+#define __POSIX_VISIBLE 199009
+#define __ISO_C_VISIBLE 1990
+#else
+#define __POSIX_VISIBLE 198808
+#define __ISO_C_VISIBLE 0
+#endif /* _POSIX_C_SOURCE */
+/*
+ * Both glibc and OpenBSD enable c11 features when _ISOC11_SOURCE is defined, or
+ * when compiling with -stdc=c11. A strict reading of the standard would suggest
+ * doing it only for the former. However, a strict reading also requires C99
+ * mode only, so building with C11 is already undefined. Follow glibc's and
+ * OpenBSD's lead for this non-standard configuration for maximum compatibility.
+ */
+#if _ISOC11_SOURCE || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
+#undef __ISO_C_VISIBLE
+#define __ISO_C_VISIBLE 2011
+#endif
+#else
+/*-
+ * Deal with _ANSI_SOURCE:
+ * If it is defined, and no other compilation environment is explicitly
+ * requested, then define our internal feature-test macros to zero. This
+ * makes no difference to the preprocessor (undefined symbols in preprocessing
+ * expressions are defined to have value zero), but makes it more convenient for
+ * a test program to print out the values.
+ *
+ * If a program mistakenly defines _ANSI_SOURCE and some other macro such as
+ * _POSIX_C_SOURCE, we will assume that it wants the broader compilation
+ * environment (and in fact we will never get here).
+ */
+#if defined(_ANSI_SOURCE) /* Hide almost everything. */
+#define __POSIX_VISIBLE 0
+#define __XSI_VISIBLE 0
+#define __BSD_VISIBLE 0
+#define __ISO_C_VISIBLE 1990
+#define __EXT1_VISIBLE 0
+#elif defined(_C99_SOURCE) /* Localism to specify strict C99 env. */
+#define __POSIX_VISIBLE 0
+#define __XSI_VISIBLE 0
+#define __BSD_VISIBLE 0
+#define __ISO_C_VISIBLE 1999
+#define __EXT1_VISIBLE 0
+#elif defined(_C11_SOURCE) /* Localism to specify strict C11 env. */
+#define __POSIX_VISIBLE 0
+#define __XSI_VISIBLE 0
+#define __BSD_VISIBLE 0
+#define __ISO_C_VISIBLE 2011
+#define __EXT1_VISIBLE 0
+#else /* Default environment: show everything. */
+#define __POSIX_VISIBLE 200809
+#define __XSI_VISIBLE 700
+#define __BSD_VISIBLE 1
+#define __ISO_C_VISIBLE 2011
+#define __EXT1_VISIBLE 1
+#endif
+#endif
+
+/* User override __EXT1_VISIBLE */
+#if defined(__STDC_WANT_LIB_EXT1__)
+#undef __EXT1_VISIBLE
+#if __STDC_WANT_LIB_EXT1__
+#define __EXT1_VISIBLE 1
+#else
+#define __EXT1_VISIBLE 0
+#endif
+#endif /* __STDC_WANT_LIB_EXT1__ */
+
+/*
+ * Old versions of GCC use non-standard ARM arch symbols; acle-compat.h
+ * translates them to __ARM_ARCH and the modern feature symbols defined by ARM.
+ */
+#if defined(__arm__) && !defined(__ARM_ARCH)
+#include <machine/acle-compat.h>
+#endif
+
+/*
+ * Nullability qualifiers: currently only supported by Clang.
+ */
+#if !(defined(__clang__) && __has_feature(nullability))
+#define _Nonnull
+#define _Nullable
+#define _Null_unspecified
+#define __NULLABILITY_PRAGMA_PUSH
+#define __NULLABILITY_PRAGMA_POP
+#else
+#define __NULLABILITY_PRAGMA_PUSH _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wnullability-completeness\"")
+#define __NULLABILITY_PRAGMA_POP _Pragma("clang diagnostic pop")
+#endif
+
+/*
+ * Type Safety Checking
+ *
+ * Clang provides additional attributes to enable checking type safety
+ * properties that cannot be enforced by the C type system.
+ */
+
+#if __has_attribute(__argument_with_type_tag__) && \
+ __has_attribute(__type_tag_for_datatype__)
+#define __arg_type_tag(arg_kind, arg_idx, type_tag_idx) \
+ __attribute__((__argument_with_type_tag__(arg_kind, arg_idx, type_tag_idx)))
+#define __datatype_type_tag(kind, type) \
+ __attribute__((__type_tag_for_datatype__(kind, type)))
+#else
+#define __arg_type_tag(arg_kind, arg_idx, type_tag_idx)
+#define __datatype_type_tag(kind, type)
+#endif
+
+/*
+ * Lock annotations.
+ *
+ * Clang provides support for doing basic thread-safety tests at
+ * compile-time, by marking which locks will/should be held when
+ * entering/leaving a functions.
+ *
+ * Furthermore, it is also possible to annotate variables and structure
+ * members to enforce that they are only accessed when certain locks are
+ * held.
+ */
+
+#if __has_extension(c_thread_safety_attributes)
+#define __lock_annotate(x) __attribute__((x))
+#else
+#define __lock_annotate(x)
+#endif
+
+/* Structure implements a lock. */
+#define __lockable __lock_annotate(lockable)
+
+/* Function acquires an exclusive or shared lock. */
+#define __locks_exclusive(...) \
+ __lock_annotate(exclusive_lock_function(__VA_ARGS__))
+#define __locks_shared(...) \
+ __lock_annotate(shared_lock_function(__VA_ARGS__))
+
+/* Function attempts to acquire an exclusive or shared lock. */
+#define __trylocks_exclusive(...) \
+ __lock_annotate(exclusive_trylock_function(__VA_ARGS__))
+#define __trylocks_shared(...) \
+ __lock_annotate(shared_trylock_function(__VA_ARGS__))
+
+/* Function releases a lock. */
+#define __unlocks(...) __lock_annotate(unlock_function(__VA_ARGS__))
+
+/* Function asserts that an exclusive or shared lock is held. */
+#define __asserts_exclusive(...) \
+ __lock_annotate(assert_exclusive_lock(__VA_ARGS__))
+#define __asserts_shared(...) \
+ __lock_annotate(assert_shared_lock(__VA_ARGS__))
+
+/* Function requires that an exclusive or shared lock is or is not held. */
+#define __requires_exclusive(...) \
+ __lock_annotate(exclusive_locks_required(__VA_ARGS__))
+#define __requires_shared(...) \
+ __lock_annotate(shared_locks_required(__VA_ARGS__))
+#define __requires_unlocked(...) \
+ __lock_annotate(locks_excluded(__VA_ARGS__))
+
+/* Function should not be analyzed. */
+#define __no_lock_analysis __lock_annotate(no_thread_safety_analysis)
+
+/*
+ * Function or variable should not be sanitized, e.g., by AddressSanitizer.
+ * GCC has the nosanitize attribute, but as a function attribute only, and
+ * warns on use as a variable attribute.
+ */
+#if __has_attribute(no_sanitize) && defined(__clang__)
+#ifdef _KERNEL
+#define __nosanitizeaddress __attribute__((no_sanitize("kernel-address")))
+#define __nosanitizememory __attribute__((no_sanitize("kernel-memory")))
+#else
+#define __nosanitizeaddress __attribute__((no_sanitize("address")))
+#define __nosanitizememory __attribute__((no_sanitize("memory")))
+#endif
+#define __nosanitizethread __attribute__((no_sanitize("thread")))
+#else
+#define __nosanitizeaddress
+#define __nosanitizememory
+#define __nosanitizethread
+#endif
+
+/* Guard variables and structure members by lock. */
+#define __guarded_by(x) __lock_annotate(guarded_by(x))
+#define __pt_guarded_by(x) __lock_annotate(pt_guarded_by(x))
+
+/* Alignment builtins for better type checking and improved code generation. */
+/* Provide fallback versions for other compilers (GCC/Clang < 10): */
+#if !__has_builtin(__builtin_is_aligned)
+#define __builtin_is_aligned(x, align) \
+ (((__uintptr_t)x & ((align) - 1)) == 0)
+#endif
+#if !__has_builtin(__builtin_align_up)
+#define __builtin_align_up(x, align) \
+ ((__typeof__(x))(((__uintptr_t)(x)+((align)-1))&(~((align)-1))))
+#endif
+#if !__has_builtin(__builtin_align_down)
+#define __builtin_align_down(x, align) \
+ ((__typeof__(x))((x)&(~((align)-1))))
+#endif
+
+#define __align_up(x, y) __builtin_align_up(x, y)
+#define __align_down(x, y) __builtin_align_down(x, y)
+#define __is_aligned(x, y) __builtin_is_aligned(x, y)
+
+#endif /* !_SYS_CDEFS_H_ */
diff --git a/include/lib/libc/time.h b/include/lib/libc/time.h
new file mode 100644
index 0000000..c1c95e5
--- /dev/null
+++ b/include/lib/libc/time.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2012-2017 Roberto E. Vargas Caballero
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2018-2019, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef TIME_H
+#define TIME_H
+
+#include <stddef.h>
+
+typedef long int time_t;
+
+#endif /* TIME_H */
diff --git a/include/lib/libfdt/fdt.h b/include/lib/libfdt/fdt.h
new file mode 100644
index 0000000..eb9edb7
--- /dev/null
+++ b/include/lib/libfdt/fdt.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
+#ifndef FDT_H
+#define FDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ * Copyright 2012 Kim Phillips, Freescale Semiconductor.
+ */
+
+#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 */
diff --git a/include/lib/libfdt/libfdt.h b/include/lib/libfdt/libfdt.h
new file mode 100644
index 0000000..a7f432c
--- /dev/null
+++ b/include/lib/libfdt/libfdt.h
@@ -0,0 +1,2147 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
+#ifndef LIBFDT_H
+#define LIBFDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ */
+
+#include <libfdt_env.h>
+#include <fdt.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define FDT_FIRST_SUPPORTED_VERSION 0x02
+#define FDT_LAST_COMPATIBLE_VERSION 0x10
+#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: FDT or a sub-block is improperly
+ * terminated (overflows, goes outside allowed bounds, or
+ * isn't properly terminated). */
+#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_BADFLAGS 18
+ /* FDT_ERR_BADFLAGS: The function was passed a flags field that
+ * contains invalid flags or an invalid combination of flags. */
+
+#define FDT_ERR_ALIGNMENT 19
+ /* FDT_ERR_ALIGNMENT: The device tree base address is not 8-byte
+ * aligned. */
+
+#define FDT_ERR_MAX 19
+
+/* constants */
+#define FDT_MAX_PHANDLE 0xfffffffe
+ /* Valid values for phandles range from 1 to 2^32-2. */
+
+/**********************************************************************/
+/* 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);
+
+/*
+ * External helpers to access words from a device tree blob. They're built
+ * to work even with unaligned pointers on platforms (such as ARMv5) that don't
+ * like unaligned loads and stores.
+ */
+static inline uint16_t fdt16_ld(const fdt16_t *p)
+{
+ const uint8_t *bp = (const uint8_t *)p;
+
+ return ((uint16_t)bp[0] << 8) | bp[1];
+}
+
+static inline uint32_t fdt32_ld(const fdt32_t *p)
+{
+ const uint8_t *bp = (const uint8_t *)p;
+
+ return ((uint32_t)bp[0] << 24)
+ | ((uint32_t)bp[1] << 16)
+ | ((uint32_t)bp[2] << 8)
+ | bp[3];
+}
+
+static inline void fdt32_st(void *property, uint32_t value)
+{
+ uint8_t *bp = (uint8_t *)property;
+
+ bp[0] = value >> 24;
+ bp[1] = (value >> 16) & 0xff;
+ bp[2] = (value >> 8) & 0xff;
+ bp[3] = value & 0xff;
+}
+
+static inline uint64_t fdt64_ld(const fdt64_t *p)
+{
+ const uint8_t *bp = (const uint8_t *)p;
+
+ return ((uint64_t)bp[0] << 56)
+ | ((uint64_t)bp[1] << 48)
+ | ((uint64_t)bp[2] << 40)
+ | ((uint64_t)bp[3] << 32)
+ | ((uint64_t)bp[4] << 24)
+ | ((uint64_t)bp[5] << 16)
+ | ((uint64_t)bp[6] << 8)
+ | bp[7];
+}
+
+static inline void fdt64_st(void *property, uint64_t value)
+{
+ uint8_t *bp = (uint8_t *)property;
+
+ bp[0] = value >> 56;
+ bp[1] = (value >> 48) & 0xff;
+ bp[2] = (value >> 40) & 0xff;
+ bp[3] = (value >> 32) & 0xff;
+ bp[4] = (value >> 24) & 0xff;
+ bp[5] = (value >> 16) & 0xff;
+ bp[6] = (value >> 8) & 0xff;
+ bp[7] = value & 0xff;
+}
+
+/**********************************************************************/
+/* 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
+ * @fdt: FDT blob
+ * @offset: Offset of previous subnode
+ *
+ * After first calling fdt_first_subnode(), call this function repeatedly to
+ * get direct subnodes of a parent node.
+ *
+ * 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_NOTFOUND)) {
+ * 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_ld(&((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_header_size - return the size of the tree's header
+ * @fdt: pointer to a flattened device tree
+ *
+ * Return: size of DTB header in bytes
+ */
+size_t fdt_header_size(const void *fdt);
+
+/**
+ * fdt_header_size_ - internal function to get header size from a version number
+ * @version: devicetree version number
+ *
+ * Return: size of DTB header in bytes
+ */
+size_t fdt_header_size_(uint32_t version);
+
+/**
+ * fdt_check_header - sanity check a device tree header
+ * @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, and that the header contains
+ * valid information (to the extent that can be determined from the
+ * header alone).
+ *
+ * returns:
+ * 0, if the buffer appears to contain a valid device tree
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_TRUNCATED, 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 */
+/**********************************************************************/
+
+int fdt_check_full(const void *fdt, size_t bufsize);
+
+/**
+ * fdt_get_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)
+ * @lenp: optional pointer to return the string's length
+ *
+ * fdt_get_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt, and optionally also
+ * returns the string's length in *lenp.
+ *
+ * returns:
+ * a pointer to the string, on success
+ * NULL, if stroffset is out of bounds, or doesn't point to a valid string
+ */
+const char *fdt_get_string(const void *fdt, int stroffset, int *lenp);
+
+/**
+ * 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, or doesn't point to a valid string
+ */
+const char *fdt_string(const void *fdt, int stroffset);
+
+/**
+ * fdt_find_max_phandle - find and return the highest phandle in a tree
+ * @fdt: pointer to the device tree blob
+ * @phandle: return location for the highest phandle value found in the tree
+ *
+ * fdt_find_max_phandle() finds the highest phandle value in the given device
+ * tree. The value returned in @phandle is only valid if the function returns
+ * success.
+ *
+ * returns:
+ * 0 on success or a negative error code on failure
+ */
+int fdt_find_max_phandle(const void *fdt, uint32_t *phandle);
+
+/**
+ * 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.
+ *
+ * This function is deprecated in favour of fdt_find_max_phandle().
+ *
+ * returns:
+ * the highest phandle on success
+ * 0, if no phandle was found in the device tree
+ * -1, if an error occurred
+ */
+static inline uint32_t fdt_get_max_phandle(const void *fdt)
+{
+ uint32_t phandle;
+ int err;
+
+ err = fdt_find_max_phandle(fdt, &phandle);
+ if (err < 0)
+ return (uint32_t)-1;
+
+ return phandle;
+}
+
+/**
+ * fdt_generate_phandle - return a new, unused phandle for a device tree blob
+ * @fdt: pointer to the device tree blob
+ * @phandle: return location for the new phandle
+ *
+ * Walks the device tree blob and looks for the highest phandle value. On
+ * success, the new, unused phandle value (one higher than the previously
+ * highest phandle value in the device tree blob) will be returned in the
+ * @phandle parameter.
+ *
+ * Return: 0 on success or a negative error-code on failure
+ */
+int fdt_generate_phandle(const void *fdt, uint32_t *phandle);
+
+/**
+ * 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
+ * @n: index of reserve map entry
+ * @address: pointer to 64-bit variable to hold the start address
+ * @size: pointer to 64-bit variable to hold the size of the entry
+ *
+ * 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.
+ *
+ * Return: offset of the subnode or -FDT_ERR_NOTFOUND if name not found.
+ */
+#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.
+ *
+ * Return: offset of the node or negative libfdt error value otherwise
+ */
+#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: 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_NOTFOUND)) {
+ * 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.
+ *
+ * Return: pointer to the structure representing the property, or NULL
+ * if not found
+ */
+#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
+ * @offset: 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.
+ *
+ * Return: pointer to the property's value or NULL on error
+ */
+#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.
+ *
+ * Return: a pointer to the expansion of the alias named @name, if it exists,
+ * NULL otherwise
+ */
+#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
+ * 1, if the node has no #size-cells property
+ * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ * #size-cells property
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -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.
+ *
+ * Return: 0 on success, negative libfdt error value otherwise
+ */
+#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
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node containing the property
+ * @name: name of the property to change the value of
+ * @val: new value of the 32-bit cell
+ *
+ * This is an alternative name for fdt_setprop_inplace_u32()
+ * Return: 0 on success, negative libfdt error number otherwise.
+ */
+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 */
+/**********************************************************************/
+
+/* fdt_create_with_flags flags */
+#define FDT_CREATE_FLAG_NO_NAME_DEDUP 0x1
+ /* FDT_CREATE_FLAG_NO_NAME_DEDUP: Do not try to de-duplicate property
+ * names in the fdt. This can result in faster creation times, but
+ * a larger fdt. */
+
+#define FDT_CREATE_FLAGS_ALL (FDT_CREATE_FLAG_NO_NAME_DEDUP)
+
+/**
+ * fdt_create_with_flags - begin creation of a new fdt
+ * @buf: pointer to memory allocated where fdt will be created
+ * @bufsize: size of the memory space at fdt
+ * @flags: a valid combination of FDT_CREATE_FLAG_ flags, or 0.
+ *
+ * fdt_create_with_flags() begins the process of creating a new fdt with
+ * the sequential write interface.
+ *
+ * fdt creation process must end with fdt_finished() to produce a valid fdt.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt
+ * -FDT_ERR_BADFLAGS, flags is not valid
+ */
+int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags);
+
+/**
+ * fdt_create - begin creation of a new fdt
+ * @buf: pointer to memory allocated where fdt will be created
+ * @bufsize: size of the memory space at fdt
+ *
+ * fdt_create() is equivalent to fdt_create_with_flags() with flags=0.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt
+ */
+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));
+}
+
+#ifndef SWIG /* Not available in Python */
+static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
+{
+ return fdt_property_u32(fdt, name, val);
+}
+#endif
+
+/**
+ * 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: 64-bit start address of the reserve map entry
+ * @size: 64-bit size of the reserved region
+ *
+ * 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
+ * @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)
+ *
+ * This is an alternative name for fdt_setprop_u32()
+ *
+ * Return: 0 on success, negative libfdt error value otherwise.
+ */
+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
+ * @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)
+ *
+ * This is an alternative name for fdt_appendprop_u32()
+ *
+ * Return: 0 on success, negative libfdt error value otherwise.
+ */
+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_appendprop_addrrange - append a address range property
+ * @fdt: pointer to the device tree blob
+ * @parent: offset of the parent node
+ * @nodeoffset: offset of the node to add a property at
+ * @name: name of property
+ * @addr: start address of a given range
+ * @size: size of a given range
+ *
+ * fdt_appendprop_addrrange() appends an address range value (start
+ * address and size) 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.
+ * If "name" is not specified, a default "reg" is used.
+ * Cell sizes are determined by parent's #address-cells and #size-cells.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ * #address-cells property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADVALUE, addr or size doesn't fit to respective cells size
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain a new property
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
+ const char *name, uint64_t addr, uint64_t size);
+
+/**
+ * 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 create
+ * @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.
+ *
+ * Return: structure block offset of the created subnode (>=0),
+ * negative libfdt error value otherwise
+ */
+#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);
+
+/**
+ * fdt_overlay_target_offset - retrieves the offset of a fragment's target
+ * @fdt: Base device tree blob
+ * @fdto: Device tree overlay blob
+ * @fragment_offset: node offset of the fragment in the overlay
+ * @pathp: pointer which receives the path of the target (or NULL)
+ *
+ * fdt_overlay_target_offset() retrieves the target offset in the base
+ * device tree of a fragment, no matter how the actual targeting is
+ * done (through a phandle or a path)
+ *
+ * returns:
+ * the targeted node offset in the base device tree
+ * Negative error code on error
+ */
+int fdt_overlay_target_offset(const void *fdt, const void *fdto,
+ int fragment_offset, char const **pathp);
+
+/**********************************************************************/
+/* Debugging / informational functions */
+/**********************************************************************/
+
+const char *fdt_strerror(int errval);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBFDT_H */
diff --git a/include/lib/libfdt/libfdt_env.h b/include/lib/libfdt/libfdt_env.h
new file mode 100644
index 0000000..73b6d40
--- /dev/null
+++ b/include/lib/libfdt/libfdt_env.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
+#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.
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#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 <AvailabilityMacros.h>
+
+/* 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 */
diff --git a/include/lib/mmio.h b/include/lib/mmio.h
new file mode 100644
index 0000000..3242a7c
--- /dev/null
+++ b/include/lib/mmio.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MMIO_H
+#define MMIO_H
+
+#include <stdint.h>
+
+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 */
diff --git a/include/lib/mpmm/mpmm.h b/include/lib/mpmm/mpmm.h
new file mode 100644
index 0000000..955c530
--- /dev/null
+++ b/include/lib/mpmm/mpmm.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MPMM_H
+#define MPMM_H
+
+#include <stdbool.h>
+
+#include <platform_def.h>
+
+/*
+ * Enable the Maximum Power Mitigation Mechanism.
+ *
+ * This function will enable MPMM for the current core. The AMU counters
+ * representing the MPMM gears must have been configured and enabled prior to
+ * calling this function.
+ */
+void mpmm_enable(void);
+
+/*
+ * MPMM core data.
+ *
+ * This structure represents per-core data retrieved from the hardware
+ * configuration device tree.
+ */
+struct mpmm_core {
+ /*
+ * Whether MPMM is supported.
+ *
+ * Cores with support for MPMM offer one or more auxiliary AMU counters
+ * representing MPMM gears.
+ */
+ bool supported;
+};
+
+/*
+ * MPMM topology.
+ *
+ * This topology structure describes the system-wide representation of the
+ * information retrieved from the hardware configuration device tree.
+ */
+struct mpmm_topology {
+ struct mpmm_core cores[PLATFORM_CORE_COUNT]; /* Per-core data */
+};
+
+#if !ENABLE_MPMM_FCONF
+/*
+ * Retrieve the platform's MPMM topology. A `NULL` return value is treated as a
+ * non-fatal error, in which case MPMM will not be enabled for any core.
+ */
+const struct mpmm_topology *plat_mpmm_topology(void);
+#endif /* ENABLE_MPMM_FCONF */
+
+#endif /* MPMM_H */
diff --git a/include/lib/object_pool.h b/include/lib/object_pool.h
new file mode 100644
index 0000000..66e8c47
--- /dev/null
+++ b/include/lib/object_pool.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef OBJECT_POOL_H
+#define OBJECT_POOL_H
+
+#include <stdlib.h>
+
+#include <common/debug.h>
+#include <lib/utils_def.h>
+
+/*
+ * 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 */
diff --git a/include/lib/optee_utils.h b/include/lib/optee_utils.h
new file mode 100644
index 0000000..06378eb
--- /dev/null
+++ b/include/lib/optee_utils.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef OPTEE_UTILS_H
+#define OPTEE_UTILS_H
+
+#include <stdbool.h>
+
+#include <common/bl_common.h>
+
+bool optee_header_is_valid(uintptr_t header_base);
+
+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 */
diff --git a/include/lib/pmf/aarch32/pmf_asm_macros.S b/include/lib/pmf/aarch32/pmf_asm_macros.S
new file mode 100644
index 0000000..1dbb408
--- /dev/null
+++ b/include/lib/pmf/aarch32/pmf_asm_macros.S
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2019, Arm Limited. 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: r0 - r4
+ */
+ .macro pmf_calc_timestamp_addr _name, _tid
+ mov r4, lr
+ bl plat_my_core_pos
+ mov lr, r4
+ ldr r1, =__PERCPU_TIMESTAMP_SIZE__
+ mov r2, #(\_tid * PMF_TS_SIZE)
+ mla r0, r0, r1, r2
+ ldr r1, =pmf_ts_mem_\_name
+ add r0, r0, r1
+ .endm
+
+#endif /* PMF_ASM_MACROS_S */
diff --git a/include/lib/pmf/aarch64/pmf_asm_macros.S b/include/lib/pmf/aarch64/pmf_asm_macros.S
new file mode 100644
index 0000000..5f3e6b7
--- /dev/null
+++ b/include/lib/pmf/aarch64/pmf_asm_macros.S
@@ -0,0 +1,30 @@
+/*
+ * 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 */
diff --git a/include/lib/pmf/pmf.h b/include/lib/pmf/pmf.h
new file mode 100644
index 0000000..fa990d2
--- /dev/null
+++ b/include/lib/pmf/pmf.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMF_H
+#define PMF_H
+
+#include <lib/cassert.h>
+#include <lib/pmf/pmf_helpers.h>
+#include <lib/utils_def.h>
+
+/*
+ * Constants used for/by PMF services.
+ */
+#define PMF_ARM_TIF_IMPL_ID UL(0x41)
+#define PMF_TID_SHIFT 0
+#define PMF_TID_MASK (UL(0xFF) << PMF_TID_SHIFT)
+#define PMF_SVC_ID_SHIFT 10
+#define PMF_SVC_ID_MASK (UL(0x3F) << PMF_SVC_ID_SHIFT)
+#define PMF_IMPL_ID_SHIFT 24
+#define PMF_IMPL_ID_MASK (UL(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
+
+/*******************************************************************************
+ * 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 */
diff --git a/include/lib/pmf/pmf_helpers.h b/include/lib/pmf/pmf_helpers.h
new file mode 100644
index 0000000..b49c6da
--- /dev/null
+++ b/include/lib/pmf/pmf_helpers.h
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMF_HELPERS_H
+#define PMF_HELPERS_H
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <plat/common/platform.h>
+
+/*
+ * 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;
+
+#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 */
+
+/*
+ * 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) \
+ { \
+ CASSERT(_flags != 0, select_proper_config); \
+ PMF_VALIDATE_TID(_name, (uint64_t)tid); \
+ uintptr_t base_addr = (uintptr_t) pmf_ts_mem_ ## _name; \
+ if (((_flags) & PMF_STORE_ENABLE) != 0) \
+ __pmf_store_timestamp(base_addr, \
+ (uint64_t)tid, ts); \
+ if (((_flags) & PMF_DUMP_ENABLE) != 0) \
+ __pmf_dump_timestamp((uint64_t)tid, ts); \
+ } \
+ void pmf_capture_timestamp_with_cache_maint_ ## _name( \
+ unsigned int tid, \
+ unsigned long long ts) \
+ { \
+ CASSERT(_flags != 0, select_proper_config); \
+ PMF_VALIDATE_TID(_name, (uint64_t)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, (uint64_t)tid, ts); \
+ if (((_flags) & PMF_DUMP_ENABLE) != 0) \
+ __pmf_dump_timestamp((uint64_t)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)\
+ { \
+ 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)\
+ { \
+ 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 */
diff --git a/include/lib/psa/delegated_attestation.h b/include/lib/psa/delegated_attestation.h
new file mode 100644
index 0000000..7aaceb3
--- /dev/null
+++ b/include/lib/psa/delegated_attestation.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/* This file describes the Delegated Attestation API */
+
+#ifndef DELEGATED_ATTESTATION_H
+#define DELEGATED_ATTESTATION_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "psa/error.h"
+
+/* RSS Delegated Attestation message types that distinguish its services. */
+#define RSS_DELEGATED_ATTEST_GET_DELEGATED_KEY 1001U
+#define RSS_DELEGATED_ATTEST_GET_PLATFORM_TOKEN 1002U
+
+/**
+ * The aim of these APIs to get a derived signing key (private only) for the
+ * delegated attestation model and obtain the corresponding platform attestation
+ * token. In the delegated attestation model the final token consist of more
+ * than one subtokens which are signed by different entities. There is a
+ * cryptographical binding between the tokens. The derived delegated attestation
+ * key is bind to the platform token (details below).
+ *
+ * Expected usage model:
+ * - First rss_delegated_attest_get_delegated_key() API need to be called to
+ * obtain the private part of the delegated attestation key. The public part
+ * of key is computed by the cryptographic library when the key is
+ * registered.
+ * - Secondly the rss_delegated_attest_get_token() must be called to obtain
+ * platform attestation token. The hash of the public key (computed by
+ * the hash_algo indicated in the rss_delegated_attest_get_delegated_key()
+ * call) must be the input of this call. This ensures that nothing but the
+ * previously derived delegated key is bindable to the platform token.
+ */
+
+/**
+ * Get a delegated attestation key (DAK).
+ *
+ * The aim of the delegated attestation key is to enable other SW components
+ * within the system to sign an attestation token which is different than the
+ * initial/platform token. The initial attestation token MUST contain the hash
+ * of the public delegated key to make a cryptographical binding (hash lock)
+ * between the key and the token.
+ * The initial attestation token has two roles in this scenario:
+ * - Attest the device boot status and security lifecycle.
+ * - Attest the delegated attestation key.
+ * The delegated attestation key is derived from a preprovisioned seed. The
+ * input for the key derivation is the platform boot status. The system can be
+ * attestated with the two tokens together.
+ *
+ * ecc_curve The type of the elliptic curve to which the requested
+ * attestation key belongs. Please check the note section for
+ * limitations.
+ * key_bits The size of the requested attestation key, in bits.
+ * key_buf Pointer to the buffer where the delegated attestation key will
+ * be stored.
+ * key_buf_size Size of allocated buffer for the key, in bytes.
+ * key_size Size of the key that has been returned, in bytes.
+ * hash_algo The hash algorithm that will be used later by the owner of the
+ * requested delegated key for binding it to the platform
+ * attestation token.
+ *
+ * Returns error code as specified in psa_status_t.
+ *
+ * Notes:
+ * - Currently, only the PSA_ECC_FAMILY_SECP_R1 curve type is supported.
+ * - The delegated attestation key must be derived before requesting for the
+ * platform attestation token as they are cryptographically linked together.
+ */
+psa_status_t
+rss_delegated_attest_get_delegated_key(uint8_t ecc_curve,
+ uint32_t key_bits,
+ uint8_t *key_buf,
+ size_t key_buf_size,
+ size_t *key_size,
+ uint32_t hash_algo);
+
+/**
+ * Get platform attestation token
+ *
+ * dak_pub_hash Pointer to buffer where the hash of the public DAK is
+ * stored.
+ * dak_pub_hash_size Size of the hash value, in bytes.
+ * token_buf Pointer to the buffer where the platform attestation token
+ * will be stored.
+ * token_buf_size Size of allocated buffer for token, in bytes.
+ * token_size Size of the token that has been returned, in bytes.
+ *
+ * Returns error code as specified in psa_status_t.
+ *
+ * A delegated attestation key must be derived before requesting for the
+ * platform attestation token as they are cryptographically linked together.
+ * Otherwise, the token request will fail and the PSA_ERROR_INVALID_ARGUMENT
+ * code will be returned.
+ */
+psa_status_t
+rss_delegated_attest_get_token(const uint8_t *dak_pub_hash,
+ size_t dak_pub_hash_size,
+ uint8_t *token_buf,
+ size_t token_buf_size,
+ size_t *token_size);
+
+#endif /* DELEGATED_ATTESTATION_H */
diff --git a/include/lib/psa/measured_boot.h b/include/lib/psa/measured_boot.h
new file mode 100644
index 0000000..bdb79d5
--- /dev/null
+++ b/include/lib/psa/measured_boot.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PSA_MEASURED_BOOT_H
+#define PSA_MEASURED_BOOT_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "psa/error.h"
+
+/* Minimum measurement value size that can be requested to store */
+#define MEASUREMENT_VALUE_MIN_SIZE 32U
+/* Maximum measurement value size that can be requested to store */
+#define MEASUREMENT_VALUE_MAX_SIZE 64U
+/* Minimum signer id size that can be requested to store */
+#define SIGNER_ID_MIN_SIZE MEASUREMENT_VALUE_MIN_SIZE
+/* Maximum signer id size that can be requested to store */
+#define SIGNER_ID_MAX_SIZE MEASUREMENT_VALUE_MAX_SIZE
+/* The theoretical maximum image version is: "255.255.65535\0" */
+#define VERSION_MAX_SIZE 14U
+/* Example sw_type: "BL_2, BL_33, etc." */
+#define SW_TYPE_MAX_SIZE 20U
+#define NUM_OF_MEASUREMENT_SLOTS 32U
+
+
+/**
+ * Extends and stores a measurement to the requested slot.
+ *
+ * index Slot number in which measurement is to be stored
+ * signer_id Pointer to signer_id buffer.
+ * signer_id_size Size of the signer_id buffer in bytes.
+ * version Pointer to version buffer.
+ * version_size Size of the version buffer in bytes.
+ * measurement_algo Algorithm identifier used for measurement.
+ * sw_type Pointer to sw_type buffer.
+ * sw_type_size Size of the sw_type buffer in bytes.
+ * measurement_value Pointer to measurement_value buffer.
+ * measurement_value_size Size of the measurement_value buffer in bytes.
+ * lock_measurement Boolean flag requesting whether the measurement
+ * is to be locked.
+ *
+ * PSA_SUCCESS:
+ * - Success.
+ * PSA_ERROR_INVALID_ARGUMENT:
+ * - The size of any argument is invalid OR
+ * - Input Measurement value is NULL OR
+ * - Input Signer ID is NULL OR
+ * - Requested slot index is invalid.
+ * PSA_ERROR_BAD_STATE:
+ * - Request to lock, when slot is already locked.
+ * PSA_ERROR_NOT_PERMITTED:
+ * - When the requested slot is not accessible to the caller.
+ */
+
+/* Not a standard PSA API, just an extension therefore use the 'rss_' prefix
+ * rather than the usual 'psa_'.
+ */
+psa_status_t
+rss_measured_boot_extend_measurement(uint8_t index,
+ const uint8_t *signer_id,
+ size_t signer_id_size,
+ const uint8_t *version,
+ size_t version_size,
+ uint32_t measurement_algo,
+ const uint8_t *sw_type,
+ size_t sw_type_size,
+ const uint8_t *measurement_value,
+ size_t measurement_value_size,
+ bool lock_measurement);
+
+#endif /* PSA_MEASURED_BOOT_H */
diff --git a/include/lib/psa/psa/client.h b/include/lib/psa/psa/client.h
new file mode 100644
index 0000000..56fe028
--- /dev/null
+++ b/include/lib/psa/psa/client.h
@@ -0,0 +1,102 @@
+
+/*
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PSA_CLIENT_H
+#define PSA_CLIENT_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <psa/error.h>
+
+#ifndef IOVEC_LEN
+#define IOVEC_LEN(arr) ((uint32_t)(sizeof(arr)/sizeof(arr[0])))
+#endif
+/*********************** PSA Client Macros and Types *************************/
+/**
+ * The version of the PSA Framework API that is being used to build the calling
+ * firmware. Only part of features of FF-M v1.1 have been implemented. FF-M v1.1
+ * is compatible with v1.0.
+ */
+#define PSA_FRAMEWORK_VERSION (0x0101u)
+/**
+ * Return value from psa_version() if the requested RoT Service is not present
+ * in the system.
+ */
+#define PSA_VERSION_NONE (0u)
+/**
+ * The zero-value null handle can be assigned to variables used in clients and
+ * RoT Services, indicating that there is no current connection or message.
+ */
+#define PSA_NULL_HANDLE ((psa_handle_t)0)
+/**
+ * Tests whether a handle value returned by psa_connect() is valid.
+ */
+#define PSA_HANDLE_IS_VALID(handle) ((psa_handle_t)(handle) > 0)
+/**
+ * Converts the handle value returned from a failed call psa_connect() into
+ * an error code.
+ */
+#define PSA_HANDLE_TO_ERROR(handle) ((psa_status_t)(handle))
+/**
+ * Maximum number of input and output vectors for a request to psa_call().
+ */
+#define PSA_MAX_IOVEC (4u)
+/**
+ * An IPC message type that indicates a generic client request.
+ */
+#define PSA_IPC_CALL (0)
+typedef int32_t psa_handle_t;
+/**
+ * A read-only input memory region provided to an RoT Service.
+ */
+typedef struct psa_invec {
+ const void *base; /*!< the start address of the memory buffer */
+ size_t len; /*!< the size in bytes */
+} psa_invec;
+/**
+ * A writable output memory region provided to an RoT Service.
+ */
+typedef struct psa_outvec {
+ void *base; /*!< the start address of the memory buffer */
+ size_t len; /*!< the size in bytes */
+} psa_outvec;
+
+/**
+ * Call an RoT Service on an established connection.
+ *
+ * handle A handle to an established connection.
+ * type The request type. Must be zero(PSA_IPC_CALL) or positive.
+ * in_vec Array of input psa_invec structures.
+ * in_len Number of input psa_invec structures.
+ * out_vec Array of output psa_outvec structures.
+ * out_len Number of output psa_outvec structures.
+ *
+ * Return value >=0 RoT Service-specific status value.
+ * Return value <0 RoT Service-specific error code.
+ *
+ * PSA_ERROR_PROGRAMMER_ERROR:
+ * - The connection has been terminated by the RoT Service.
+ *
+ * The call is a PROGRAMMER ERROR if one or more of the following are true:
+ * - An invalid handle was passed.
+ * - The connection is already handling a request.
+ * - type < 0.
+ * - An invalid memory reference was provided.
+ * - in_len + out_len > PSA_MAX_IOVEC.
+ * - The message is unrecognized by the RoT.
+ * - Service or incorrectly formatted.
+ */
+psa_status_t psa_call(psa_handle_t handle,
+ int32_t type,
+ const psa_invec *in_vec,
+ size_t in_len,
+ psa_outvec *out_vec,
+ size_t out_len);
+
+#endif /* PSA_CLIENT_H */
diff --git a/include/lib/psa/psa/error.h b/include/lib/psa/psa/error.h
new file mode 100644
index 0000000..8a6eb7b
--- /dev/null
+++ b/include/lib/psa/psa/error.h
@@ -0,0 +1,42 @@
+
+/*
+ * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PSA_ERROR_H
+#define PSA_ERROR_H
+
+#include <stdint.h>
+
+typedef int32_t psa_status_t;
+
+#define PSA_SUCCESS ((psa_status_t)0)
+#define PSA_SUCCESS_REBOOT ((psa_status_t)1)
+#define PSA_SUCCESS_RESTART ((psa_status_t)2)
+#define PSA_ERROR_PROGRAMMER_ERROR ((psa_status_t)-129)
+#define PSA_ERROR_CONNECTION_REFUSED ((psa_status_t)-130)
+#define PSA_ERROR_CONNECTION_BUSY ((psa_status_t)-131)
+#define PSA_ERROR_GENERIC_ERROR ((psa_status_t)-132)
+#define PSA_ERROR_NOT_PERMITTED ((psa_status_t)-133)
+#define PSA_ERROR_NOT_SUPPORTED ((psa_status_t)-134)
+#define PSA_ERROR_INVALID_ARGUMENT ((psa_status_t)-135)
+#define PSA_ERROR_INVALID_HANDLE ((psa_status_t)-136)
+#define PSA_ERROR_BAD_STATE ((psa_status_t)-137)
+#define PSA_ERROR_BUFFER_TOO_SMALL ((psa_status_t)-138)
+#define PSA_ERROR_ALREADY_EXISTS ((psa_status_t)-139)
+#define PSA_ERROR_DOES_NOT_EXIST ((psa_status_t)-140)
+#define PSA_ERROR_INSUFFICIENT_MEMORY ((psa_status_t)-141)
+#define PSA_ERROR_INSUFFICIENT_STORAGE ((psa_status_t)-142)
+#define PSA_ERROR_INSUFFICIENT_DATA ((psa_status_t)-143)
+#define PSA_ERROR_SERVICE_FAILURE ((psa_status_t)-144)
+#define PSA_ERROR_COMMUNICATION_FAILURE ((psa_status_t)-145)
+#define PSA_ERROR_STORAGE_FAILURE ((psa_status_t)-146)
+#define PSA_ERROR_HARDWARE_FAILURE ((psa_status_t)-147)
+#define PSA_ERROR_INVALID_SIGNATURE ((psa_status_t)-149)
+#define PSA_ERROR_DEPENDENCY_NEEDED ((psa_status_t)-156)
+#define PSA_ERROR_CURRENTLY_INSTALLING ((psa_status_t)-157)
+
+#endif /* PSA_ERROR_H */
diff --git a/include/lib/psa/psa_manifest/sid.h b/include/lib/psa/psa_manifest/sid.h
new file mode 100644
index 0000000..0bdeed4
--- /dev/null
+++ b/include/lib/psa/psa_manifest/sid.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PSA_MANIFEST_SID_H
+#define PSA_MANIFEST_SID_H
+
+/******** PSA_SP_MEASURED_BOOT ********/
+#define RSS_MEASURED_BOOT_HANDLE (0x40000110U)
+
+/******** PSA_SP_DELAGATED_ATTESTATION ********/
+#define RSS_DELEGATED_SERVICE_HANDLE (0x40000111U)
+
+#endif /* PSA_MANIFEST_SID_H */
diff --git a/include/lib/psci/psci.h b/include/lib/psci/psci.h
new file mode 100644
index 0000000..b56e98b
--- /dev/null
+++ b/include/lib/psci/psci.h
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSCI_H
+#define PSCI_H
+
+#include <platform_def.h> /* for PLAT_NUM_PWR_DOMAINS */
+
+#include <common/bl_common.h>
+#include <lib/bakery_lock.h>
+#include <lib/psci/psci_lib.h> /* To maintain compatibility for SPDs */
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * 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 (U(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 <stdint.h>
+
+/* 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 */
diff --git a/include/lib/psci/psci_lib.h b/include/lib/psci/psci_lib.h
new file mode 100644
index 0000000..3edc50b
--- /dev/null
+++ b/include/lib/psci/psci_lib.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSCI_LIB_H
+#define PSCI_LIB_H
+
+#include <common/ep_info.h>
+
+#ifndef __ASSEMBLER__
+
+#include <cdefs.h>
+#include <stdint.h>
+
+/*******************************************************************************
+ * 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);
+int psci_stop_other_cores(unsigned int wait_ms,
+ void (*stop_func)(u_register_t mpidr));
+bool psci_is_last_on_cpu_safe(void);
+void psci_pwrdown_cpu(unsigned int power_level);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* PSCI_LIB_H */
diff --git a/include/lib/runtime_instr.h b/include/lib/runtime_instr.h
new file mode 100644
index 0000000..303f27e
--- /dev/null
+++ b/include/lib/runtime_instr.h
@@ -0,0 +1,25 @@
+/*
+ * 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 <lib/utils_def.h>
+
+#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 */
diff --git a/include/lib/semihosting.h b/include/lib/semihosting.h
new file mode 100644
index 0000000..24b030c
--- /dev/null
+++ b/include/lib/semihosting.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SEMIHOSTING_H
+#define SEMIHOSTING_H
+
+#include <stdint.h>
+#include <stdio.h> /* 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 SEMIHOSTING_SYS_EXIT 0x18
+
+#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);
+void semihosting_exit(uint32_t reason, uint32_t subcode);
+
+#endif /* SEMIHOSTING_H */
diff --git a/include/lib/smccc.h b/include/lib/smccc.h
new file mode 100644
index 0000000..cce91af
--- /dev/null
+++ b/include/lib/smccc.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SMCCC_H
+#define SMCCC_H
+
+#include <lib/utils_def.h>
+
+#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(2)
+
+/*******************************************************************************
+ * 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_SVE_HINT_SHIFT U(16)
+#define FUNCID_SVE_HINT_MASK U(1)
+#define FUNCID_SVE_HINT_WIDTH U(1)
+
+#define FUNCID_NUM_SHIFT U(0)
+#define FUNCID_NUM_MASK U(0xffff)
+#define FUNCID_NUM_WIDTH U(16)
+
+#define FUNCID_MASK U(0xffffffff)
+
+#define GET_SMC_NUM(id) (((id) >> FUNCID_NUM_SHIFT) & \
+ FUNCID_NUM_MASK)
+#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)
+
+/*******************************************************************************
+ * SMCCC_ARCH_SOC_ID SoC version & revision bit definition
+ ******************************************************************************/
+#define SOC_ID_JEP_106_BANK_IDX_MASK GENMASK_32(30, 24)
+#define SOC_ID_JEP_106_BANK_IDX_SHIFT U(24)
+#define SOC_ID_JEP_106_ID_CODE_MASK GENMASK_32(23, 16)
+#define SOC_ID_JEP_106_ID_CODE_SHIFT U(16)
+#define SOC_ID_IMPL_DEF_MASK GENMASK_32(15, 0)
+#define SOC_ID_IMPL_DEF_SHIFT U(0)
+#define SOC_ID_SET_JEP_106(bkid, mfid) ((((bkid) << SOC_ID_JEP_106_BANK_IDX_SHIFT) & \
+ SOC_ID_JEP_106_BANK_IDX_MASK) | \
+ (((mfid) << SOC_ID_JEP_106_ID_CODE_SHIFT) & \
+ SOC_ID_JEP_106_ID_CODE_MASK))
+
+#define SOC_ID_REV_MASK GENMASK_32(30, 0)
+#define SOC_ID_REV_SHIFT U(0)
+
+/*******************************************************************************
+ * 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 UL(1)
+#define SMC_TYPE_YIELD UL(0)
+
+#define SMC_OK ULL(0)
+#define SMC_UNK -1
+#define SMC_PREEMPTED -2 /* Not defined by the SMCCC */
+
+/* Return codes for Arm Architecture Service SMC calls */
+#define SMC_ARCH_CALL_SUCCESS 0
+#define SMC_ARCH_CALL_NOT_SUPPORTED -1
+#define SMC_ARCH_CALL_NOT_REQUIRED -2
+#define SMC_ARCH_CALL_INVAL_PARAM -3
+
+/*
+ * Various flags passed to SMC handlers
+ *
+ * Bit 5 and bit 0 of the flag are used to
+ * determine the source security state as
+ * follows:
+ * ---------------------------------
+ * Bit 5 | Bit 0 | Security state
+ * ---------------------------------
+ * 0 0 SMC_FROM_SECURE
+ * 0 1 SMC_FROM_NON_SECURE
+ * 1 1 SMC_FROM_REALM
+ *
+ * Bit 16 of flags records the caller's SMC
+ * SVE hint bit according to SMCCCv1.3.
+ * It can be consumed by dispatchers using
+ * is_sve_hint_set macro.
+ *
+ */
+
+#define SMC_FROM_SECURE (U(0) << 0)
+#define SMC_FROM_NON_SECURE (U(1) << 0)
+#define SMC_FROM_REALM U(0x21)
+#define SMC_FROM_MASK U(0x21)
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+#include <lib/cassert.h>
+
+#if ENABLE_RME
+#define is_caller_non_secure(_f) (((_f) & SMC_FROM_MASK) \
+ == SMC_FROM_NON_SECURE)
+#define is_caller_secure(_f) (((_f) & SMC_FROM_MASK) \
+ == SMC_FROM_SECURE)
+#define is_caller_realm(_f) (((_f) & SMC_FROM_MASK) \
+ == SMC_FROM_REALM)
+#define caller_sec_state(_f) ((_f) & SMC_FROM_MASK)
+#else /* ENABLE_RME */
+#define is_caller_non_secure(_f) (((_f) & SMC_FROM_NON_SECURE) != U(0))
+#define is_caller_secure(_f) (!is_caller_non_secure(_f))
+#endif /* ENABLE_RME */
+
+#define is_sve_hint_set(_f) (((_f) & (FUNCID_SVE_HINT_MASK \
+ << FUNCID_SVE_HINT_SHIFT)) != U(0))
+
+/* 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) \
+ == (uint32_t)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_##_name); \
+ 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 */
diff --git a/include/lib/spinlock.h b/include/lib/spinlock.h
new file mode 100644
index 0000000..0bf3ee0
--- /dev/null
+++ b/include/lib/spinlock.h
@@ -0,0 +1,29 @@
+/*
+ * 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 <stdint.h>
+
+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 */
diff --git a/include/lib/utils.h b/include/lib/utils.h
new file mode 100644
index 0000000..17ee936
--- /dev/null
+++ b/include/lib/utils.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016-2019, 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 <stddef.h>
+#include <stdint.h>
+
+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; \
+ __asm__ volatile ("ldr %0, =" #_name : "=r" (v) : "X" (#_name));\
+ 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 */
diff --git a/include/lib/utils_def.h b/include/lib/utils_def.h
new file mode 100644
index 0000000..198b890
--- /dev/null
+++ b/include/lib/utils_def.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef UTILS_DEF_H
+#define UTILS_DEF_H
+
+#include <export/lib/utils_def_exp.h>
+
+/* 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) (U(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; \
+})
+
+#define CLAMP(x, min, max) __extension__ ({ \
+ __typeof__(x) _x = (x); \
+ __typeof__(min) _min = (min); \
+ __typeof__(max) _max = (max); \
+ (void)(&_x == &_min); \
+ (void)(&_x == &_max); \
+ (_x > _max ? _max : (_x < _min ? _min : _x)); \
+})
+
+/*
+ * The round_up() macro rounds up a value to the given boundary in a
+ * type-agnostic yet type-safe manner. The boundary must be a power of two.
+ * 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))
+
+/**
+ * Helper macro to ensure a value lies on a given boundary.
+ */
+#define is_aligned(value, boundary) \
+ (round_up((uintptr_t) value, boundary) == \
+ round_down((uintptr_t) 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
+
+/*
+ * Ticks elapsed in one second with a signal of 1 MHz
+ */
+#define MHZ_TICKS_PER_SEC U(1000000)
+
+/*
+ * Ticks elapsed in one second with a signal of 1 KHz
+ */
+#define KHZ_TICKS_PER_SEC U(1000)
+
+#endif /* UTILS_DEF_H */
diff --git a/include/lib/xlat_mpu/xlat_mpu.h b/include/lib/xlat_mpu/xlat_mpu.h
new file mode 100644
index 0000000..252b92c
--- /dev/null
+++ b/include/lib/xlat_mpu/xlat_mpu.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef XLAT_MPU_H
+#define XLAT_MPU_H
+
+#ifndef __ASSEMBLER__
+
+#include <lib/cassert.h>
+
+#define XLAT_TABLES_LIB_V2 1
+
+void enable_mpu_el2(unsigned int flags);
+void enable_mpu_direct_el2(unsigned int flags);
+
+/*
+ * Function to wipe clean and disable all MPU regions. This function expects
+ * that the MPU has already been turned off, and caching concerns addressed,
+ * but it nevertheless also explicitly turns off the MPU.
+ */
+void clear_all_mpu_regions(void);
+
+#endif /* __ASSEMBLER__ */
+#endif /* XLAT_MPU_H */
diff --git a/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h b/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h
new file mode 100644
index 0000000..30eb5e9
--- /dev/null
+++ b/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h
@@ -0,0 +1,72 @@
+/*
+ * 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 <arch.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#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 */
diff --git a/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h b/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h
new file mode 100644
index 0000000..3014c8f
--- /dev/null
+++ b/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h
@@ -0,0 +1,96 @@
+/*
+ * 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 <arch.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#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 */
diff --git a/include/lib/xlat_tables/xlat_mmu_helpers.h b/include/lib/xlat_tables/xlat_mmu_helpers.h
new file mode 100644
index 0000000..269afd2
--- /dev/null
+++ b/include/lib/xlat_tables/xlat_mmu_helpers.h
@@ -0,0 +1,94 @@
+/*
+ * 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 <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+
+/*
+ * 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(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 */
diff --git a/include/lib/xlat_tables/xlat_tables.h b/include/lib/xlat_tables/xlat_tables.h
new file mode 100644
index 0000000..a156969
--- /dev/null
+++ b/include/lib/xlat_tables/xlat_tables.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef XLAT_TABLES_H
+#define XLAT_TABLES_H
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#ifndef __ASSEMBLER__
+#include <stddef.h>
+#include <stdint.h>
+
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+
+/* 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)
+
+/* Memory type for EL3 regions */
+#if ENABLE_RME
+#error FEAT_RME requires version 2 of the Translation Tables Library
+#else
+#define EL3_PAS MT_SECURE
+#endif
+
+/*
+ * 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 */
diff --git a/include/lib/xlat_tables/xlat_tables_arch.h b/include/lib/xlat_tables/xlat_tables_arch.h
new file mode 100644
index 0000000..0ce0cac
--- /dev/null
+++ b/include/lib/xlat_tables/xlat_tables_arch.h
@@ -0,0 +1,31 @@
+/*
+ * 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 */
diff --git a/include/lib/xlat_tables/xlat_tables_compat.h b/include/lib/xlat_tables/xlat_tables_compat.h
new file mode 100644
index 0000000..5f28195
--- /dev/null
+++ b/include/lib/xlat_tables/xlat_tables_compat.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef XLAT_TABLES_COMPAT_H
+#define XLAT_TABLES_COMPAT_H
+
+#if XLAT_TABLES_LIB_V2
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#else
+#include <lib/xlat_tables/xlat_tables.h>
+#endif
+
+#endif /* XLAT_TABLES_COMPAT_H */
diff --git a/include/lib/xlat_tables/xlat_tables_defs.h b/include/lib/xlat_tables/xlat_tables_defs.h
new file mode 100644
index 0000000..2d0949b
--- /dev/null
+++ b/include/lib/xlat_tables/xlat_tables_defs.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef XLAT_TABLES_DEFS_H
+#define XLAT_TABLES_DEFS_H
+
+#include <arch.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+
+/* 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 (UL(1) << PAGE_SIZE_SHIFT)
+#define PAGE_SIZE_MASK (PAGE_SIZE - UL(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 EL3_S1_NSE (U(0x1) << 9)
+#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 */
diff --git a/include/lib/xlat_tables/xlat_tables_v2.h b/include/lib/xlat_tables/xlat_tables_v2.h
new file mode 100644
index 0000000..69ad027
--- /dev/null
+++ b/include/lib/xlat_tables/xlat_tables_v2.h
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef XLAT_TABLES_V2_H
+#define XLAT_TABLES_V2_H
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <lib/xlat_tables/xlat_tables_v2_helpers.h>
+
+#ifndef __ASSEMBLER__
+#include <stddef.h>
+#include <stdint.h>
+
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+
+/*
+ * 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)
+
+/* Physical address space (SECURE/NS/Root/Realm) */
+#define MT_PAS_SHIFT U(4)
+#define MT_PAS_MASK (U(3) << MT_PAS_SHIFT)
+#define MT_PAS(_attr) ((_attr) & MT_PAS_MASK)
+
+/* Access permissions for instruction execution (EXECUTE/EXECUTE_NEVER) */
+#define MT_EXECUTE_SHIFT U(6)
+/* In the EL1&0 translation regime, User (EL0) or Privileged (EL1). */
+#define MT_USER_SHIFT U(7)
+
+/* Shareability attribute for the memory region */
+#define MT_SHAREABILITY_SHIFT U(8)
+#define MT_SHAREABILITY_MASK (U(3) << MT_SHAREABILITY_SHIFT)
+#define MT_SHAREABILITY(_attr) ((_attr) & MT_SHAREABILITY_MASK)
+
+/* 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_PAS_SHIFT)
+#define MT_NS (U(1) << MT_PAS_SHIFT)
+#define MT_ROOT (U(2) << MT_PAS_SHIFT)
+#define MT_REALM (U(3) << MT_PAS_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)
+
+/*
+ * Shareability defines the visibility of any cache changes to
+ * all masters belonging to a shareable domain.
+ *
+ * MT_SHAREABILITY_ISH: For inner shareable domain
+ * MT_SHAREABILITY_OSH: For outer shareable domain
+ * MT_SHAREABILITY_NSH: For non shareable domain
+ */
+#define MT_SHAREABILITY_ISH (U(1) << MT_SHAREABILITY_SHIFT)
+#define MT_SHAREABILITY_OSH (U(2) << MT_SHAREABILITY_SHIFT)
+#define MT_SHAREABILITY_NSH (U(3) << MT_SHAREABILITY_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
+
+/* Memory type for EL3 regions. With RME, EL3 is in ROOT PAS */
+#if ENABLE_RME
+#define EL3_PAS MT_ROOT
+#else
+#define EL3_PAS MT_SECURE
+#endif /* ENABLE_RME */
+
+/*
+ * 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", "base_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.
+ *
+ * _base_table_section_name:
+ * Specify the name of the section where the base 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, _base_table_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), (_base_table_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);
+
+#if PLAT_RO_XLAT_TABLES
+/*
+ * Change the memory attributes of the memory region encompassing the higher
+ * level translation tables to secure read-only data.
+ *
+ * Return 0 on success, a negative error code on error.
+ */
+int xlat_make_tables_readonly(void);
+#endif
+
+/*
+ * 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 */
diff --git a/include/lib/xlat_tables/xlat_tables_v2_helpers.h b/include/lib/xlat_tables/xlat_tables_v2_helpers.h
new file mode 100644
index 0000000..62f853d
--- /dev/null
+++ b/include/lib/xlat_tables/xlat_tables_v2_helpers.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2017-2020, 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 <stdbool.h>
+#include <stddef.h>
+
+#include <platform_def.h>
+
+#include <lib/cassert.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_arch.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+/* 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;
+#if PLAT_RO_XLAT_TABLES
+ bool readonly_tables;
+#endif
+ /*
+ * 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 */
+
+#if PLAT_RO_XLAT_TABLES
+#define XLAT_CTX_INIT_TABLE_ATTR() \
+ .readonly_tables = false,
+#else
+#define XLAT_CTX_INIT_TABLE_ATTR()
+ /* do nothing */
+#endif
+
+#define REGISTER_XLAT_CONTEXT_FULL_SPEC(_ctx_name, _mmap_count, \
+ _xlat_tables_count, _virt_addr_space_size, \
+ _phy_addr_space_size, _xlat_regime, \
+ _table_section, _base_table_section) \
+ 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(_table_section); \
+ \
+ 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)) \
+ __section(_base_table_section); \
+ \
+ XLAT_ALLOC_DYNMAP_STRUCT(_ctx_name, _xlat_tables_count) \
+ \
+ static xlat_ctx_t _ctx_name##_xlat_ctx = { \
+ .pa_max_address = (_phy_addr_space_size) - 1ULL, \
+ .va_max_address = (_virt_addr_space_size) - 1UL, \
+ .mmap = _ctx_name##_mmap, \
+ .mmap_num = (_mmap_count), \
+ .tables = _ctx_name##_xlat_tables, \
+ .tables_num = ARRAY_SIZE(_ctx_name##_xlat_tables), \
+ XLAT_CTX_INIT_TABLE_ATTR() \
+ XLAT_REGISTER_DYNMAP_STRUCT(_ctx_name) \
+ .next_table = 0, \
+ .base_table = _ctx_name##_base_xlat_table, \
+ .base_table_entries = \
+ ARRAY_SIZE(_ctx_name##_base_xlat_table), \
+ .max_pa = 0U, \
+ .max_va = 0U, \
+ .base_level = GET_XLAT_TABLE_LEVEL_BASE(_virt_addr_space_size),\
+ .initialized = false, \
+ .xlat_regime = (_xlat_regime) \
+ }
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* XLAT_TABLES_V2_HELPERS_H */
diff --git a/include/lib/zlib/tf_gunzip.h b/include/lib/zlib/tf_gunzip.h
new file mode 100644
index 0000000..741ba50
--- /dev/null
+++ b/include/lib/zlib/tf_gunzip.h
@@ -0,0 +1,16 @@
+/*
+ * 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 <stddef.h>
+#include <stdint.h>
+
+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 */
diff --git a/include/plat/arm/board/common/board_css_def.h b/include/plat/arm/board/common/board_css_def.h
new file mode 100644
index 0000000..1963bf0
--- /dev/null
+++ b/include/plat/arm/board/common/board_css_def.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BOARD_CSS_DEF_H
+#define BOARD_CSS_DEF_H
+
+#include <lib/utils_def.h>
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/soc/common/soc_css_def.h>
+#include <plat/common/common_def.h>
+
+/*
+ * 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 <lib/mmio.h>
+
+#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_FLASH_IMAGE_BASE V2M_FLASH0_BASE
+#define PLAT_ARM_FLASH_IMAGE_MAX_SIZE (V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+#if ARM_GPT_SUPPORT
+/*
+ * Offset of the FIP in the GPT image. BL1 component uses this option
+ * as it does not load the partition table to get the FIP base
+ * address. At sector 34 by default (i.e. after reserved sectors 0-33)
+ * Offset = 34 * 512(sector size) = 17408 i.e. 0x4400
+ */
+#define PLAT_ARM_FIP_OFFSET_IN_GPT 0x4400
+#endif /* ARM_GPT_SUPPORT */
+
+#define PLAT_ARM_NVM_BASE V2M_FLASH0_BASE
+#define PLAT_ARM_NVM_SIZE (V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+/* 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 */
diff --git a/include/plat/arm/board/common/v2m_def.h b/include/plat/arm/board/common/v2m_def.h
new file mode 100644
index 0000000..cb11dac
--- /dev/null
+++ b/include/plat/arm/board/common/v2m_def.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef V2M_DEF_H
+#define V2M_DEF_H
+
+#include <lib/utils_def.h>
+
+/* Base address of all V2M */
+#ifdef PLAT_V2M_OFFSET
+#define V2M_OFFSET PLAT_V2M_OFFSET
+#else
+#define V2M_OFFSET UL(0)
+#endif
+
+/* 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 (V2M_OFFSET + UL(0x08000000))
+#define V2M_FLASH0_SIZE UL(0x04000000)
+#define V2M_FLASH_BLOCK_SIZE UL(0x00040000) /* 256 KB */
+
+#define V2M_IOFPGA_BASE (V2M_OFFSET + UL(0x1c000000))
+#define V2M_IOFPGA_SIZE UL(0x03000000)
+
+/* PL011 UART related constants */
+#define V2M_IOFPGA_UART0_BASE (V2M_OFFSET + UL(0x1c090000))
+#define V2M_IOFPGA_UART1_BASE (V2M_OFFSET + UL(0x1c0a0000))
+#define V2M_IOFPGA_UART2_BASE (V2M_OFFSET + UL(0x1c0b0000))
+#define V2M_IOFPGA_UART3_BASE (V2M_OFFSET + 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 (V2M_OFFSET + UL(0x1C110000))
+#define V2M_SP804_TIMER1_BASE (V2M_OFFSET + UL(0x1C120000))
+
+/* SP810 controller */
+#define V2M_SP810_BASE (V2M_OFFSET + 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 */
diff --git a/include/plat/arm/board/fvp_r/fvp_r_bl1.h b/include/plat/arm/board/fvp_r/fvp_r_bl1.h
new file mode 100644
index 0000000..0b41e67
--- /dev/null
+++ b/include/plat/arm/board/fvp_r/fvp_r_bl1.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FVP_R_BL1_H
+#define FVP_R_BL1_H
+
+void bl1_load_bl33(void);
+void bl1_transfer_bl33(void);
+
+#endif /* FVP_R_BL1_H */
diff --git a/include/plat/arm/common/aarch64/arm_macros.S b/include/plat/arm/common/aarch64/arm_macros.S
new file mode 100644
index 0000000..d47e4e0
--- /dev/null
+++ b/include/plat/arm/common/aarch64/arm_macros.S
@@ -0,0 +1,104 @@
+/*
+ * 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 <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gicv3.h>
+#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)\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 */
diff --git a/include/plat/arm/common/aarch64/cci_macros.S b/include/plat/arm/common/aarch64/cci_macros.S
new file mode 100644
index 0000000..07f7cd3
--- /dev/null
+++ b/include/plat/arm/common/aarch64/cci_macros.S
@@ -0,0 +1,37 @@
+/*
+ * 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 <drivers/arm/cci.h>
+#include <platform_def.h>
+
+.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 */
diff --git a/include/plat/arm/common/arm_config.h b/include/plat/arm/common/arm_config.h
new file mode 100644
index 0000000..c2b28df
--- /dev/null
+++ b/include/plat/arm/common/arm_config.h
@@ -0,0 +1,43 @@
+/*
+ * 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 <stdint.h>
+
+#include <lib/utils_def.h>
+
+/* 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 */
diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h
new file mode 100644
index 0000000..ab0e4ff
--- /dev/null
+++ b/include/plat/arm/common/arm_def.h
@@ -0,0 +1,780 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ARM_DEF_H
+#define ARM_DEF_H
+
+#include <arch.h>
+#include <common/interrupt_props.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/arm/common/smccc_def.h>
+#include <plat/common/common_def.h>
+
+/******************************************************************************
+ * Definitions common to all ARM standard platforms
+ *****************************************************************************/
+
+/*
+ * Root of trust key hash lengths
+ */
+#define ARM_ROTPK_HEADER_LEN 19
+#define ARM_ROTPK_HASH_LEN 32
+
+/* Special value used to verify platform parameters from BL2 to BL31 */
+#define ARM_BL31_PLAT_PARAM_VAL ULL(0x0f1e2d3c4b5a6978)
+
+#define ARM_SYSTEM_COUNT U(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
+
+#ifdef PLAT_ARM_TRUSTED_SRAM_BASE
+#define ARM_TRUSTED_SRAM_BASE PLAT_ARM_TRUSTED_SRAM_BASE
+#else
+#define ARM_TRUSTED_SRAM_BASE UL(0x04000000)
+#endif /* PLAT_ARM_TRUSTED_SRAM_BASE */
+
+#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 (or 64MB if RME is enabled) of DRAM1 is configured as
+ * follows:
+ * - SCP TZC DRAM: If present, DRAM reserved for SCP use
+ * - L1 GPT DRAM: Reserved for L1 GPT if RME is enabled
+ * - REALM DRAM: Reserved for Realm world if RME is enabled
+ * - TF-A <-> RMM SHARED: Area shared for communication between TF-A and RMM
+ * - AP TZC DRAM: The remaining TZC secured DRAM reserved for AP use
+ *
+ * RME enabled(64MB) RME not enabled(16MB)
+ * -------------------- -------------------
+ * | | | |
+ * | AP TZC (~28MB) | | AP TZC (~14MB) |
+ * -------------------- -------------------
+ * | | | |
+ * | REALM (RMM) | | EL3 TZC (2MB) |
+ * | (32MB - 4KB) | -------------------
+ * -------------------- | |
+ * | | | SCP TZC |
+ * | TF-A <-> RMM | 0xFFFF_FFFF-------------------
+ * | SHARED (4KB) |
+ * --------------------
+ * | |
+ * | EL3 TZC (3MB) |
+ * --------------------
+ * | L1 GPT + SCP TZC |
+ * | (~1MB) |
+ * 0xFFFF_FFFF --------------------
+ */
+#if ENABLE_RME
+#define ARM_TZC_DRAM1_SIZE UL(0x04000000) /* 64MB */
+/*
+ * Define a 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. 3MB region is reserved if RME is enabled, 2MB otherwise.
+ */
+#define ARM_EL3_TZC_DRAM1_SIZE UL(0x00300000) /* 3MB */
+#define ARM_L1_GPT_SIZE UL(0x00100000) /* 1MB */
+
+/* 32MB - ARM_EL3_RMM_SHARED_SIZE */
+#define ARM_REALM_SIZE (UL(0x02000000) - \
+ ARM_EL3_RMM_SHARED_SIZE)
+#define ARM_EL3_RMM_SHARED_SIZE (PAGE_SIZE) /* 4KB */
+#else
+#define ARM_TZC_DRAM1_SIZE UL(0x01000000) /* 16MB */
+#define ARM_EL3_TZC_DRAM1_SIZE UL(0x00200000) /* 2MB */
+#define ARM_L1_GPT_SIZE UL(0)
+#define ARM_REALM_SIZE UL(0)
+#define ARM_EL3_RMM_SHARED_SIZE UL(0)
+#endif /* ENABLE_RME */
+
+#define ARM_SCP_TZC_DRAM1_BASE (ARM_DRAM1_BASE + \
+ ARM_DRAM1_SIZE - \
+ (ARM_SCP_TZC_DRAM1_SIZE + \
+ ARM_L1_GPT_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 - 1U)
+#if ENABLE_RME
+#define ARM_L1_GPT_ADDR_BASE (ARM_DRAM1_BASE + \
+ ARM_DRAM1_SIZE - \
+ ARM_L1_GPT_SIZE)
+#define ARM_L1_GPT_END (ARM_L1_GPT_ADDR_BASE + \
+ ARM_L1_GPT_SIZE - 1U)
+
+#define ARM_REALM_BASE (ARM_EL3_RMM_SHARED_BASE - \
+ ARM_REALM_SIZE)
+
+#define ARM_REALM_END (ARM_REALM_BASE + ARM_REALM_SIZE - 1U)
+
+#define ARM_EL3_RMM_SHARED_BASE (ARM_DRAM1_BASE + \
+ ARM_DRAM1_SIZE - \
+ (ARM_SCP_TZC_DRAM1_SIZE + \
+ ARM_L1_GPT_SIZE + \
+ ARM_EL3_RMM_SHARED_SIZE + \
+ ARM_EL3_TZC_DRAM1_SIZE))
+
+#define ARM_EL3_RMM_SHARED_END (ARM_EL3_RMM_SHARED_BASE + \
+ ARM_EL3_RMM_SHARED_SIZE - 1U)
+#endif /* ENABLE_RME */
+
+#define ARM_EL3_TZC_DRAM1_BASE (ARM_SCP_TZC_DRAM1_BASE - \
+ ARM_EL3_TZC_DRAM1_SIZE)
+#define ARM_EL3_TZC_DRAM1_END (ARM_EL3_TZC_DRAM1_BASE + \
+ ARM_EL3_TZC_DRAM1_SIZE - 1U)
+
+#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 + \
+ ARM_EL3_RMM_SHARED_SIZE + \
+ ARM_REALM_SIZE + \
+ ARM_L1_GPT_SIZE))
+#define ARM_AP_TZC_DRAM1_END (ARM_AP_TZC_DRAM1_BASE + \
+ ARM_AP_TZC_DRAM1_SIZE - 1U)
+
+/* 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 - 1U)
+#ifdef PLAT_ARM_DRAM1_BASE
+#define ARM_DRAM1_BASE PLAT_ARM_DRAM1_BASE
+#else
+#define ARM_DRAM1_BASE ULL(0x80000000)
+#endif /* PLAT_ARM_DRAM1_BASE */
+
+#define ARM_DRAM1_SIZE ULL(0x80000000)
+#define ARM_DRAM1_END (ARM_DRAM1_BASE + \
+ ARM_DRAM1_SIZE - 1U)
+
+#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 - 1U)
+
+#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 | EL3_PAS)
+
+#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 | EL3_PAS)
+
+#define ARM_MAP_TRUSTED_DRAM MAP_REGION_FLAT( \
+ PLAT_ARM_TRUSTED_DRAM_BASE, \
+ PLAT_ARM_TRUSTED_DRAM_SIZE, \
+ MT_MEMORY | MT_RW | MT_SECURE)
+
+#if ENABLE_RME
+/*
+ * We add the EL3_RMM_SHARED size to RMM mapping to map the region as a block.
+ * Else we end up requiring more pagetables in BL2 for ROMLIB build.
+ */
+#define ARM_MAP_RMM_DRAM MAP_REGION_FLAT( \
+ PLAT_ARM_RMM_BASE, \
+ (PLAT_ARM_RMM_SIZE + \
+ ARM_EL3_RMM_SHARED_SIZE), \
+ MT_MEMORY | MT_RW | MT_REALM)
+
+
+#define ARM_MAP_GPT_L1_DRAM MAP_REGION_FLAT( \
+ ARM_L1_GPT_ADDR_BASE, \
+ ARM_L1_GPT_SIZE, \
+ MT_MEMORY | MT_RW | EL3_PAS)
+
+#define ARM_MAP_EL3_RMM_SHARED_MEM \
+ MAP_REGION_FLAT( \
+ ARM_EL3_RMM_SHARED_BASE, \
+ ARM_EL3_RMM_SHARED_SIZE, \
+ MT_MEMORY | MT_RW | MT_REALM)
+
+#endif /* ENABLE_RME */
+
+/*
+ * 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 | EL3_PAS)
+
+/*
+ * 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 | EL3_PAS), \
+ MAP_REGION_FLAT( \
+ BL_RO_DATA_BASE, \
+ BL_RO_DATA_END \
+ - BL_RO_DATA_BASE, \
+ MT_RO_DATA | EL3_PAS)
+#else
+#define ARM_MAP_BL_RO MAP_REGION_FLAT( \
+ BL_CODE_BASE, \
+ BL_CODE_END - BL_CODE_BASE, \
+ MT_CODE | EL3_PAS)
+#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 | EL3_PAS)
+#endif
+#if USE_ROMLIB
+#define ARM_MAP_ROMLIB_CODE MAP_REGION_FLAT( \
+ ROMLIB_RO_BASE, \
+ ROMLIB_RO_LIMIT - ROMLIB_RO_BASE,\
+ MT_CODE | EL3_PAS)
+
+#define ARM_MAP_ROMLIB_DATA MAP_REGION_FLAT( \
+ ROMLIB_RW_BASE, \
+ ROMLIB_RW_END - ROMLIB_RW_BASE,\
+ MT_MEMORY | MT_RW | EL3_PAS)
+#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)
+/*
+ * Map the region for device tree configuration with read and write permissions
+ */
+#define ARM_MAP_BL_CONFIG_REGION MAP_REGION_FLAT(ARM_BL_RAM_BASE, \
+ (ARM_FW_CONFIGS_LIMIT \
+ - ARM_BL_RAM_BASE), \
+ MT_MEMORY | MT_RW | EL3_PAS)
+/*
+ * Map L0_GPT with read and write permissions
+ */
+#if ENABLE_RME
+#define ARM_MAP_L0_GPT_REGION MAP_REGION_FLAT(ARM_L0_GPT_ADDR_BASE, \
+ ARM_L0_GPT_SIZE, \
+ MT_MEMORY | MT_RW | MT_ROOT)
+#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 7
+
+#define MAX_MMAP_REGIONS (PLAT_ARM_MMAP_ENTRIES + \
+ ARM_BL_REGIONS)
+
+/* Memory mapped Generic timer interfaces */
+#ifdef PLAT_ARM_SYS_CNTCTL_BASE
+#define ARM_SYS_CNTCTL_BASE PLAT_ARM_SYS_CNTCTL_BASE
+#else
+#define ARM_SYS_CNTCTL_BASE UL(0x2a430000)
+#endif
+
+#ifdef PLAT_ARM_SYS_CNTREAD_BASE
+#define ARM_SYS_CNTREAD_BASE PLAT_ARM_SYS_CNTREAD_BASE
+#else
+#define ARM_SYS_CNTREAD_BASE UL(0x2a800000)
+#endif
+
+#ifdef PLAT_ARM_SYS_TIMCTL_BASE
+#define ARM_SYS_TIMCTL_BASE PLAT_ARM_SYS_TIMCTL_BASE
+#else
+#define ARM_SYS_TIMCTL_BASE UL(0x2a810000)
+#endif
+
+#ifdef PLAT_ARM_SYS_CNT_BASE_S
+#define ARM_SYS_CNT_BASE_S PLAT_ARM_SYS_CNT_BASE_S
+#else
+#define ARM_SYS_CNT_BASE_S UL(0x2a820000)
+#endif
+
+#ifdef PLAT_ARM_SYS_CNT_BASE_NS
+#define ARM_SYS_CNT_BASE_NS PLAT_ARM_SYS_CNT_BASE_NS
+#else
+#define ARM_SYS_CNT_BASE_NS UL(0x2a830000)
+#endif
+
+#define ARM_CONSOLE_BAUDRATE 115200
+
+/* Trusted Watchdog constants */
+#ifdef PLAT_ARM_SP805_TWDG_BASE
+#define ARM_SP805_TWDG_BASE PLAT_ARM_SP805_TWDG_BASE
+#else
+#define ARM_SP805_TWDG_BASE UL(0x2a490000)
+#endif
+#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 FW_CONFIG to be loaded by BL1, define the corresponding base
+ * and limit. Leave enough space of BL2 meminfo.
+ */
+#define ARM_FW_CONFIG_BASE (ARM_BL_RAM_BASE + sizeof(meminfo_t))
+#define ARM_FW_CONFIG_LIMIT ((ARM_BL_RAM_BASE + PAGE_SIZE) \
+ + (PAGE_SIZE / 2U))
+
+/*
+ * Boot parameters passed from BL2 to BL31/BL32 are stored here
+ */
+#define ARM_BL2_MEM_DESC_BASE (ARM_FW_CONFIG_LIMIT)
+#define ARM_BL2_MEM_DESC_LIMIT (ARM_BL2_MEM_DESC_BASE \
+ + (PAGE_SIZE / 2U))
+
+/*
+ * Define limit of firmware configuration memory:
+ * ARM_FW_CONFIG + ARM_BL2_MEM_DESC memory
+ */
+#define ARM_FW_CONFIGS_LIMIT (ARM_BL_RAM_BASE + (PAGE_SIZE * 2))
+
+#if ENABLE_RME
+/*
+ * Store the L0 GPT on Trusted SRAM next to firmware
+ * configuration memory, 4KB aligned.
+ */
+#define ARM_L0_GPT_SIZE (PAGE_SIZE)
+#define ARM_L0_GPT_ADDR_BASE (ARM_FW_CONFIGS_LIMIT)
+#define ARM_L0_GPT_LIMIT (ARM_L0_GPT_ADDR_BASE + ARM_L0_GPT_SIZE)
+#else
+#define ARM_L0_GPT_SIZE U(0)
+#endif
+
+/*******************************************************************************
+ * 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
+#ifdef PLAT_BL1_RO_LIMIT
+#define BL1_RO_LIMIT PLAT_BL1_RO_LIMIT
+#else
+#define BL1_RO_LIMIT (PLAT_ARM_TRUSTED_ROM_BASE \
+ + (PLAT_ARM_TRUSTED_ROM_SIZE - \
+ PLAT_ARM_MAX_ROMLIB_RO_SIZE))
+#endif
+
+/*
+ * 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
+#if ENABLE_PIE
+/*
+ * As the BL31 image size appears to be increased when built with the ENABLE_PIE
+ * option, set BL2 base address to have enough space for BL31 in Trusted SRAM.
+ */
+#define BL2_BASE (ARM_TRUSTED_SRAM_BASE + \
+ (PLAT_ARM_TRUSTED_SRAM_SIZE >> 1) + \
+ 0x3000)
+#else
+/* Put BL2 towards the middle of the Trusted SRAM */
+#define BL2_BASE (ARM_TRUSTED_SRAM_BASE + \
+ (PLAT_ARM_TRUSTED_SRAM_SIZE >> 1) + \
+ 0x2000)
+#endif /* ENABLE_PIE */
+#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 || SEPARATE_NOBITS_REGION
+/*
+ * 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)
+/*
+ * For SEPARATE_NOBITS_REGION, BL31 PROGBITS are loaded in TZC secured DRAM.
+ * And BL31 NOBITS are loaded in Trusted SRAM such that BL2 is overwritten.
+ */
+#if SEPARATE_NOBITS_REGION
+#define BL31_NOBITS_BASE BL2_BASE
+#define BL31_NOBITS_LIMIT BL2_LIMIT
+#endif /* SEPARATE_NOBITS_REGION */
+#elif (RESET_TO_BL31)
+/* Ensure Position Independent support (PIE) is enabled for this config.*/
+# if !ENABLE_PIE
+# error "BL31 must be a PIE if RESET_TO_BL31=1."
+#endif
+/*
+ * 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 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
+
+/******************************************************************************
+ * RMM specific defines
+ *****************************************************************************/
+#if ENABLE_RME
+#define RMM_BASE (ARM_REALM_BASE)
+#define RMM_LIMIT (RMM_BASE + ARM_REALM_SIZE)
+#define RMM_SHARED_BASE (ARM_EL3_RMM_SHARED_BASE)
+#define RMM_SHARED_SIZE (ARM_EL3_RMM_SHARED_SIZE)
+#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
+/* Ensure Position Independent support (PIE) is enabled for this config.*/
+# if !ENABLE_PIE
+# error "BL32 must be a PIE if RESET_TO_SP_MIN=1."
+#endif
+/*
+ * Since this is PIE, we can define BL32_BASE to 0x0 since this macro is solely
+ * used for building BL32 and not used for loading BL32.
+ */
+# define BL32_BASE 0x0
+# define BL32_LIMIT PLAT_ARM_MAX_BL32_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 SPM_MM || SPMC_AT_EL3
+# 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 defined(SPD_spmd)
+# 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 PLAT_ARM_SPMC_BASE
+# define BL32_LIMIT (PLAT_ARM_SPMC_BASE + \
+ PLAT_ARM_SPMC_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_CONFIGS_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-MM and no SPMC-AT-EL3, as they are the only ones that can be
+ * used as BL32.
+ */
+#if defined(__aarch64__) && !JUNO_AARCH32_EL3_RUNTIME
+# if defined(SPD_none) && !SPM_MM && !SPMC_AT_EL3
+# undef BL32_BASE
+# endif /* defined(SPD_none) && !SPM_MM || !SPMC_AT_EL3 */
+#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 PLAT_PRI_BITS 3
+
+/* SGI used for SDEI signalling */
+#define ARM_SDEI_SGI ARM_IRQ_SEC_SGI_0
+
+#if SDEI_IN_FCONF
+/* ARM SDEI dynamic private event max count */
+#define ARM_SDEI_DP_EVENT_MAX_CNT 3
+
+/* ARM SDEI dynamic shared event max count */
+#define ARM_SDEI_DS_EVENT_MAX_CNT 3
+#else
+/* 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 /* SDEI_IN_FCONF */
+
+#endif /* ARM_DEF_H */
diff --git a/include/plat/arm/common/arm_dyn_cfg_helpers.h b/include/plat/arm/common/arm_dyn_cfg_helpers.h
new file mode 100644
index 0000000..ff00fe7
--- /dev/null
+++ b/include/plat/arm/common/arm_dyn_cfg_helpers.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2018-2021, 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 <stddef.h>
+#include <stdint.h>
+
+/* Function declarations */
+int arm_dyn_tb_fw_cfg_init(void *dtb, int *node);
+int arm_set_dtb_mbedtls_heap_info(void *dtb, void *heap_addr,
+ size_t heap_size);
+
+#endif /* ARM_DYN_CFG_HELPERS_H */
diff --git a/include/plat/arm/common/arm_fconf_getter.h b/include/plat/arm/common/arm_fconf_getter.h
new file mode 100644
index 0000000..8fd8c7a
--- /dev/null
+++ b/include/plat/arm/common/arm_fconf_getter.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARM_FCONF_GETTER
+#define ARM_FCONF_GETTER
+
+#include <assert.h>
+
+#include <lib/fconf/fconf.h>
+
+/* ARM io policies */
+#define arm__io_policies_getter(id) __extension__ ({ \
+ assert((id) < MAX_NUMBER_IDS); \
+ &policies[id]; \
+})
+
+struct plat_io_policy {
+ uintptr_t *dev_handle;
+ uintptr_t image_spec;
+ int (*check)(const uintptr_t spec);
+};
+
+extern struct plat_io_policy policies[];
+int fconf_populate_arm_io_policies(uintptr_t config);
+
+#endif /* ARM_FCONF_GETTER */
diff --git a/include/plat/arm/common/arm_fconf_io_storage.h b/include/plat/arm/common/arm_fconf_io_storage.h
new file mode 100644
index 0000000..02ee66c
--- /dev/null
+++ b/include/plat/arm/common/arm_fconf_io_storage.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2020, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ARM_FCONF_IO_STORAGE_H
+#define ARM_FCONF_IO_STORAGE_H
+
+#include <stdint.h>
+
+/* IO devices handle */
+extern uintptr_t memmap_dev_handle;
+extern uintptr_t fip_dev_handle;
+
+/* Function declarations */
+int open_fip(const uintptr_t spec);
+int open_memmap(const uintptr_t spec);
+
+#endif /* ARM_FCONF_IO_STORAGE_H */
diff --git a/include/plat/arm/common/arm_pas_def.h b/include/plat/arm/common/arm_pas_def.h
new file mode 100644
index 0000000..c199302
--- /dev/null
+++ b/include/plat/arm/common/arm_pas_def.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ARM_PAS_DEF_H
+#define ARM_PAS_DEF_H
+
+#include <lib/gpt_rme/gpt_rme.h>
+#include <plat/arm/common/arm_def.h>
+
+/*****************************************************************************
+ * PAS regions used to initialize the Granule Protection Table (GPT)
+ ****************************************************************************/
+
+/*
+ * The PA space is initially mapped in the GPT as follows:
+ *
+ * ============================================================================
+ * Base Addr| Size |L? GPT|PAS |Content |Comment
+ * ============================================================================
+ * 0GB | 1GB |L0 GPT|ANY |TBROM (EL3 code) |Fixed mapping
+ * | | | |TSRAM (EL3 data) |
+ * | | | |IO (incl.UARTs & GIC) |
+ * ----------------------------------------------------------------------------
+ * 1GB | 1GB |L0 GPT|ANY |IO |Fixed mapping
+ * ----------------------------------------------------------------------------
+ * 2GB | 1GB |L1 GPT|NS |DRAM (NS Kernel) |Use T.Descrip
+ * ----------------------------------------------------------------------------
+ * 3GB |1GB-64MB |L1 GPT|NS |DRAM (NS Kernel) |Use T.Descrip
+ * ----------------------------------------------------------------------------
+ * 4GB-64MB |64MB-32MB | | | |
+ * | -4MB |L1 GPT|SECURE|DRAM TZC |Use T.Descrip
+ * ----------------------------------------------------------------------------
+ * 4GB-32MB | | | | |
+ * -3MB-1MB |32MB |L1 GPT|REALM |RMM |Use T.Descrip
+ * ----------------------------------------------------------------------------
+ * 4GB-3MB | | | | |
+ * -1MB |3MB |L1 GPT|ROOT |EL3 DRAM data |Use T.Descrip
+ * ----------------------------------------------------------------------------
+ * 4GB-1MB |1MB |L1 GPT|ROOT |DRAM (L1 GPTs, SCP TZC) |Fixed mapping
+ * ============================================================================
+ *
+ * - 4KB of L0 GPT reside in TSRAM, on top of the CONFIG section.
+ * - ~1MB of L1 GPTs reside at the top of DRAM1 (TZC area).
+ * - The first 1GB region has GPT_GPI_ANY and, therefore, is not protected by
+ * the GPT.
+ * - The DRAM TZC area is split into three regions: the L1 GPT region and
+ * 3MB of region below that are defined as GPT_GPI_ROOT, 32MB Realm region
+ * below that is defined as GPT_GPI_REALM and the rest of it is defined as
+ * GPT_GPI_SECURE.
+ */
+
+/* TODO: This might not be the best way to map the PAS */
+
+/* Device memory 0 to 2GB */
+#define ARM_PAS_1_BASE (U(0))
+#define ARM_PAS_1_SIZE ((ULL(1)<<31)) /* 2GB */
+
+/* NS memory 2GB to (end - 64MB) */
+#define ARM_PAS_2_BASE (ARM_PAS_1_BASE + ARM_PAS_1_SIZE)
+#define ARM_PAS_2_SIZE (ARM_NS_DRAM1_SIZE)
+
+/* Shared area between EL3 and RMM */
+#define ARM_PAS_SHARED_BASE (ARM_EL3_RMM_SHARED_BASE)
+#define ARM_PAS_SHARED_SIZE (ARM_EL3_RMM_SHARED_SIZE)
+
+/* Secure TZC region */
+#define ARM_PAS_3_BASE (ARM_AP_TZC_DRAM1_BASE)
+#define ARM_PAS_3_SIZE (ARM_AP_TZC_DRAM1_SIZE)
+
+#define ARM_PAS_GPI_ANY MAP_GPT_REGION(ARM_PAS_1_BASE, \
+ ARM_PAS_1_SIZE, \
+ GPT_GPI_ANY)
+#define ARM_PAS_KERNEL GPT_MAP_REGION_GRANULE(ARM_PAS_2_BASE, \
+ ARM_PAS_2_SIZE, \
+ GPT_GPI_NS)
+
+#define ARM_PAS_SECURE GPT_MAP_REGION_GRANULE(ARM_PAS_3_BASE, \
+ ARM_PAS_3_SIZE, \
+ GPT_GPI_SECURE)
+
+/*
+ * REALM and Shared area share the same PAS, so consider them a single
+ * PAS region to configure in GPT.
+ */
+#define ARM_PAS_REALM GPT_MAP_REGION_GRANULE(ARM_REALM_BASE, \
+ (ARM_PAS_SHARED_SIZE + \
+ ARM_REALM_SIZE), \
+ GPT_GPI_REALM)
+
+#define ARM_PAS_EL3_DRAM GPT_MAP_REGION_GRANULE(ARM_EL3_TZC_DRAM1_BASE, \
+ ARM_EL3_TZC_DRAM1_SIZE, \
+ GPT_GPI_ROOT)
+
+#define ARM_PAS_GPTS GPT_MAP_REGION_GRANULE(ARM_L1_GPT_ADDR_BASE, \
+ ARM_L1_GPT_SIZE, \
+ GPT_GPI_ROOT)
+
+/* GPT Configuration options */
+#define PLATFORM_L0GPTSZ GPCCR_L0GPTSZ_30BITS
+
+#endif /* ARM_PAS_DEF_H */
diff --git a/include/plat/arm/common/arm_reclaim_init.ld.S b/include/plat/arm/common/arm_reclaim_init.ld.S
new file mode 100644
index 0000000..788e9ff
--- /dev/null
+++ b/include/plat/arm/common/arm_reclaim_init.ld.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017-2022, 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__ = .;
+ *(*text.init.*);
+ __INIT_CODE_END__ = .;
+ INIT_CODE_END_ALIGNED = ALIGN(PAGE_SIZE);
+ } >RAM
+
+#ifdef BL31_PROGBITS_LIMIT
+ ASSERT(__INIT_CODE_END__ <= BL31_PROGBITS_LIMIT,
+ "BL31 init has exceeded progbits limit.")
+#endif
+}
+
+#define ABS ABSOLUTE
+
+#define STACK_SECTION \
+ stacks (NOLOAD) : { \
+ __STACKS_START__ = .; \
+ *(tzfw_normal_stacks) \
+ __STACKS_END__ = .; \
+ /* Allow room for the init section where necessary. */ \
+ OFFSET = ABS(SIZEOF(.init) - (. - __STACKS_START__)); \
+ /* Offset sign */ \
+ SIGN = ABS(OFFSET) & (1 << 63); \
+ /* Offset mask */ \
+ MASK = ABS(SIGN >> 63) - 1; \
+ . += ABS(OFFSET) & ABS(MASK); \
+ . = ALIGN(PAGE_SIZE); \
+ }
+
+#endif /* ARM_RECLAIM_INIT_LD_S */
diff --git a/include/plat/arm/common/arm_sip_svc.h b/include/plat/arm/common/arm_sip_svc.h
new file mode 100644
index 0000000..025d10e
--- /dev/null
+++ b/include/plat/arm/common/arm_sip_svc.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016-2019,2021-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARM_SIP_SVC_H
+#define ARM_SIP_SVC_H
+
+#include <lib/utils_def.h>
+
+/* 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)
+
+/* PMF_SMC_GET_TIMESTAMP_32 0x82000010 */
+/* PMF_SMC_GET_TIMESTAMP_64 0xC2000010 */
+
+/* Function ID for requesting state switch of lower EL */
+#define ARM_SIP_SVC_EXE_STATE_SWITCH U(0x82000020)
+
+/* DEBUGFS_SMC_32 0x82000030U */
+/* DEBUGFS_SMC_64 0xC2000030U */
+
+/*
+ * Arm(R) Ethos(TM)-N NPU SiP SMC function IDs
+ * 0xC2000050-0xC200005F
+ * 0x82000050-0x8200005F
+ */
+
+/* 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 */
diff --git a/include/plat/arm/common/arm_spm_def.h b/include/plat/arm/common/arm_spm_def.h
new file mode 100644
index 0000000..c43583d
--- /dev/null
+++ b/include/plat/arm/common/arm_spm_def.h
@@ -0,0 +1,103 @@
+/*
+ * 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 <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+/*
+ * 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
+
+/* 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)
+
+#endif /* ARM_SPM_DEF_H */
diff --git a/include/plat/arm/common/arm_tzc_dram.ld.S b/include/plat/arm/common/arm_tzc_dram.ld.S
new file mode 100644
index 0000000..6dcea0b
--- /dev/null
+++ b/include/plat/arm/common/arm_tzc_dram.ld.S
@@ -0,0 +1,30 @@
+/*
+ * 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 <lib/xlat_tables/xlat_tables_defs.h>
+
+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 */
diff --git a/include/plat/arm/common/fconf_arm_sp_getter.h b/include/plat/arm/common/fconf_arm_sp_getter.h
new file mode 100644
index 0000000..96ed963
--- /dev/null
+++ b/include/plat/arm/common/fconf_arm_sp_getter.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FCONF_ARM_SP_GETTER_H
+#define FCONF_ARM_SP_GETTER_H
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/fconf/fconf.h>
+#include <tools_share/uuid.h>
+
+/* arm_sp getter */
+#define arm__sp_getter(prop) arm_sp.prop
+
+#define ARM_SP_MAX_SIZE U(0xb0000)
+#define ARM_SP_OWNER_NAME_LEN U(8)
+
+struct arm_sp_t {
+ unsigned int number_of_sp;
+ union uuid_helper_t uuids[MAX_SP_IDS];
+ uintptr_t load_addr[MAX_SP_IDS];
+ char owner[MAX_SP_IDS][ARM_SP_OWNER_NAME_LEN];
+};
+
+int fconf_populate_arm_sp(uintptr_t config);
+
+extern struct arm_sp_t arm_sp;
+
+extern bl_mem_params_node_t sp_mem_params_descs[MAX_SP_IDS];
+
+#endif /* FCONF_ARM_SP_GETTER_H */
diff --git a/include/plat/arm/common/fconf_ethosn_getter.h b/include/plat/arm/common/fconf_ethosn_getter.h
new file mode 100644
index 0000000..5b9a7ed
--- /dev/null
+++ b/include/plat/arm/common/fconf_ethosn_getter.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FCONF_ETHOSN_GETTER_H
+#define FCONF_ETHOSN_GETTER_H
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <lib/fconf/fconf.h>
+
+#define hw_config__ethosn_config_getter(prop) ethosn_config.prop
+#define hw_config__ethosn_device_getter(dev_idx) __extension__ ({ \
+ assert(dev_idx < ethosn_config.num_devices); \
+ &ethosn_config.devices[dev_idx]; \
+})
+
+#define ETHOSN_DEV_NUM_MAX U(2)
+#define ETHOSN_DEV_CORE_NUM_MAX U(8)
+#define ETHOSN_DEV_ASSET_ALLOCATOR_NUM_MAX U(16)
+
+struct ethosn_allocator_t {
+ uint32_t stream_id;
+};
+
+struct ethosn_main_allocator_t {
+ struct ethosn_allocator_t firmware;
+ struct ethosn_allocator_t working_data;
+};
+
+struct ethosn_asset_allocator_t {
+ struct ethosn_allocator_t command_stream;
+ struct ethosn_allocator_t weight_data;
+ struct ethosn_allocator_t buffer_data;
+ struct ethosn_allocator_t intermediate_data;
+};
+
+struct ethosn_core_t {
+ uint64_t addr;
+ struct ethosn_main_allocator_t main_allocator;
+};
+
+struct ethosn_device_t {
+ bool has_reserved_memory;
+ uint32_t num_cores;
+ struct ethosn_core_t cores[ETHOSN_DEV_CORE_NUM_MAX];
+ uint32_t num_allocators;
+ struct ethosn_asset_allocator_t asset_allocators[ETHOSN_DEV_ASSET_ALLOCATOR_NUM_MAX];
+};
+
+struct ethosn_config_t {
+ uint32_t num_devices;
+ struct ethosn_device_t devices[ETHOSN_DEV_NUM_MAX];
+};
+
+int fconf_populate_arm_ethosn(uintptr_t config);
+
+extern struct ethosn_config_t ethosn_config;
+
+#endif /* FCONF_ETHOSN_GETTER_H */
diff --git a/include/plat/arm/common/fconf_nv_cntr_getter.h b/include/plat/arm/common/fconf_nv_cntr_getter.h
new file mode 100644
index 0000000..80a6000
--- /dev/null
+++ b/include/plat/arm/common/fconf_nv_cntr_getter.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FCONF_NV_CNTR_GETTER_H
+#define FCONF_NV_CNTR_GETTER_H
+
+#include <common/nv_cntr_ids.h>
+#include <lib/fconf/fconf.h>
+
+#define cot__nv_cntr_addr_getter(id) nv_cntr_base_addr[id]
+
+extern uintptr_t nv_cntr_base_addr[MAX_NV_CTR_IDS];
+
+#endif /* FCONF_NV_CNTR_GETTER_H */
diff --git a/include/plat/arm/common/fconf_sdei_getter.h b/include/plat/arm/common/fconf_sdei_getter.h
new file mode 100644
index 0000000..e0a97a6
--- /dev/null
+++ b/include/plat/arm/common/fconf_sdei_getter.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FCONF_SDEI_GETTER_H
+#define FCONF_SDEI_GETTER_H
+
+#include <lib/fconf/fconf.h>
+
+#include <platform_def.h>
+
+#define sdei__dyn_config_getter(id) sdei_dyn_config.id
+
+struct sdei_dyn_config_t {
+ uint32_t private_ev_cnt;
+ int32_t private_ev_nums[PLAT_SDEI_DP_EVENT_MAX_CNT];
+ unsigned int private_ev_intrs[PLAT_SDEI_DP_EVENT_MAX_CNT];
+ unsigned int private_ev_flags[PLAT_SDEI_DP_EVENT_MAX_CNT];
+ uint32_t shared_ev_cnt;
+ int32_t shared_ev_nums[PLAT_SDEI_DS_EVENT_MAX_CNT];
+ unsigned int shared_ev_intrs[PLAT_SDEI_DS_EVENT_MAX_CNT];
+ unsigned int shared_ev_flags[PLAT_SDEI_DS_EVENT_MAX_CNT];
+};
+
+int fconf_populate_sdei_dyn_config(uintptr_t config);
+
+extern struct sdei_dyn_config_t sdei_dyn_config;
+
+#endif /* FCONF_SDEI_GETTER_H */
diff --git a/include/plat/arm/common/fconf_sec_intr_config.h b/include/plat/arm/common/fconf_sec_intr_config.h
new file mode 100644
index 0000000..5d6b594
--- /dev/null
+++ b/include/plat/arm/common/fconf_sec_intr_config.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FCONF_SEC_INTR_CONFIG_H
+#define FCONF_SEC_INTR_CONFIG_H
+
+#include <lib/fconf/fconf.h>
+
+#include <platform_def.h>
+
+#define hw_config__sec_intr_prop_getter(id) sec_intr_prop.id
+
+#define SEC_INT_COUNT_MAX U(15)
+
+struct sec_intr_prop_t {
+ interrupt_prop_t descriptor[SEC_INT_COUNT_MAX];
+ uint32_t count;
+};
+
+int fconf_populate_sec_intr_config(uintptr_t config);
+
+extern struct sec_intr_prop_t sec_intr_prop;
+
+#endif /* FCONF_SEC_INTR_CONFIG_H */
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
new file mode 100644
index 0000000..6c0d91d
--- /dev/null
+++ b/include/plat/arm/common/plat_arm.h
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_ARM_H
+#define PLAT_ARM_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <drivers/arm/tzc_common.h>
+#include <lib/bakery_lock.h>
+#include <lib/cassert.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/spinlock.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+
+/*******************************************************************************
+ * 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 SPM_MM
+#define ARM_TZC_REGIONS_DEF \
+ {ARM_AP_TZC_DRAM1_BASE, ARM_EL3_TZC_DRAM1_END + ARM_L1_GPT_SIZE,\
+ 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}
+
+#elif ENABLE_RME
+#define ARM_TZC_REGIONS_DEF \
+ {ARM_AP_TZC_DRAM1_BASE, ARM_AP_TZC_DRAM1_END, TZC_REGION_S_RDWR, 0},\
+ {ARM_EL3_TZC_DRAM1_BASE, ARM_L1_GPT_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}, \
+ /* Realm and Shared area share the same PAS */ \
+ {ARM_REALM_BASE, ARM_EL3_RMM_SHARED_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}
+
+#else
+#define ARM_TZC_REGIONS_DEF \
+ {ARM_AP_TZC_DRAM1_BASE, ARM_EL3_TZC_DRAM1_END + ARM_L1_GPT_SIZE,\
+ 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)
+
+/* plat_get_rotpk_info() flags */
+#define ARM_ROTPK_REGS_ID 1
+#define ARM_ROTPK_DEVEL_RSA_ID 2
+#define ARM_ROTPK_DEVEL_ECDSA_ID 3
+
+
+/* IO storage utility functions */
+int arm_io_setup(void);
+
+/* Set image specification in IO block policy */
+int arm_set_image_source(unsigned int image_id, const char *part_name,
+ uintptr_t *dev_handle, uintptr_t *image_spec);
+void arm_set_fip_addr(uint32_t active_fw_bank_idx);
+
+/* Security utility functions */
+void arm_tzc400_setup(uintptr_t tzc_base,
+ 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 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);
+void arm_sp_min_plat_arch_setup(void);
+
+/* FIP TOC validity check */
+bool arm_io_is_toc_valid(void);
+
+/* Utility functions for Dynamic Config */
+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);
+
+#if MEASURED_BOOT
+int arm_set_tos_fw_info(uintptr_t log_addr, size_t log_size);
+int arm_set_nt_fw_info(
+/*
+ * Currently OP-TEE does not support reading DTBs from Secure memory
+ * and this option should be removed when feature is supported.
+ */
+#ifdef SPD_opteed
+ uintptr_t log_addr,
+#endif
+ size_t log_size, uintptr_t *ns_log_addr);
+int arm_set_tb_fw_info(uintptr_t log_addr, size_t log_size);
+int arm_get_tb_fw_info(uint64_t *log_addr, size_t *log_size);
+#endif /* MEASURED_BOOT */
+
+/*
+ * 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);
+
+/*
+ * Make the higher level translation tables read-only
+ */
+void arm_xlat_make_tables_readonly(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);
+bool plat_arm_bl1_fwu_needed(void);
+__dead2 void plat_arm_error_handler(int err);
+__dead2 void plat_arm_system_reset(void);
+
+/*
+ * Optional functions in ARM standard platforms
+ */
+void plat_arm_override_gicr_frames(const uintptr_t *plat_gicr_frames);
+int arm_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+ unsigned int *flags);
+int arm_get_rotpk_info_regs(void **key_ptr, unsigned int *key_len,
+ unsigned int *flags);
+int arm_get_rotpk_info_cc(void **key_ptr, unsigned int *key_len,
+ unsigned int *flags);
+int arm_get_rotpk_info_dev(void **key_ptr, unsigned int *key_len,
+ unsigned int *flags);
+
+#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);
+
+/* Get SOC-ID of ARM platform */
+uint32_t plat_arm_get_soc_id(void);
+
+#endif /* PLAT_ARM_H */
diff --git a/include/plat/arm/common/smccc_def.h b/include/plat/arm/common/smccc_def.h
new file mode 100644
index 0000000..0f4e573
--- /dev/null
+++ b/include/plat/arm/common/smccc_def.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef SMCCC_DEF_H
+#define SMCCC_DEF_H
+
+/* Defines used to retrieve ARM SOC revision */
+#define ARM_SOC_CONTINUATION_CODE U(0x4)
+#define ARM_SOC_IDENTIFICATION_CODE U(0x3B)
+
+#endif /* SMCCC_DEF_H */
diff --git a/include/plat/arm/css/common/aarch64/css_macros.S b/include/plat/arm/css/common/aarch64/css_macros.S
new file mode 100644
index 0000000..85a7044
--- /dev/null
+++ b/include/plat/arm/css/common/aarch64/css_macros.S
@@ -0,0 +1,25 @@
+/*
+ * 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 <arm_macros.S>
+#include <platform_def.h>
+
+ /* ---------------------------------------------
+ * 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 */
diff --git a/include/plat/arm/css/common/css_def.h b/include/plat/arm/css/common/css_def.h
new file mode 100644
index 0000000..dde174c
--- /dev/null
+++ b/include/plat/arm/css/common/css_def.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CSS_DEF_H
+#define CSS_DEF_H
+
+#include <common/interrupt_props.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/tzc400.h>
+
+/*************************************************************************
+ * 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
+#define SID_NODE_ID_OFFSET 0x60
+#define SID_CHIP_ID_MASK 0xFF
+#define SID_MULTI_CHIP_MODE_MASK 0x100
+#define SID_MULTI_CHIP_MODE_SHIFT 8
+
+/* 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 SPNIDEN_INT_CLR_SHIFT 4
+#define SPNIDEN_SEL_SET_SHIFT 5
+#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)
+
+/*
+ * 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 */
diff --git a/include/plat/arm/css/common/css_pm.h b/include/plat/arm/css/common/css_pm.h
new file mode 100644
index 0000000..84e6b38
--- /dev/null
+++ b/include/plat/arm/css/common/css_pm.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CSS_PM_H
+#define CSS_PM_H
+
+#include <cdefs.h>
+#include <stdint.h>
+
+#include <lib/psci/psci.h>
+
+/* SGI used to trigger per-core power down request */
+#define CSS_CPU_PWR_DOWN_REQ_INTR ARM_IRQ_SEC_SGI_7
+
+/* 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);
+void css_setup_cpu_pwr_down_intr(void);
+int css_reboot_interrupt_handler(uint32_t intr_raw, uint32_t flags,
+ void *handle, void *cookie);
+
+/*
+ * 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[];
+
+#define SCMI_DOMAIN_ID_MASK U(0xFFFF)
+#define SCMI_CHANNEL_ID_MASK U(0xFFFF)
+#define SCMI_CHANNEL_ID_SHIFT U(16)
+
+#define SET_SCMI_CHANNEL_ID(n) (((n) & SCMI_CHANNEL_ID_MASK) << \
+ SCMI_CHANNEL_ID_SHIFT)
+#define SET_SCMI_DOMAIN_ID(n) ((n) & SCMI_DOMAIN_ID_MASK)
+#define GET_SCMI_CHANNEL_ID(n) (((n) >> SCMI_CHANNEL_ID_SHIFT) & \
+ SCMI_CHANNEL_ID_MASK)
+#define GET_SCMI_DOMAIN_ID(n) ((n) & SCMI_DOMAIN_ID_MASK)
+
+#endif /* CSS_PM_H */
diff --git a/include/plat/arm/soc/common/soc_css.h b/include/plat/arm/soc/common/soc_css.h
new file mode 100644
index 0000000..469928d
--- /dev/null
+++ b/include/plat/arm/soc/common/soc_css.h
@@ -0,0 +1,22 @@
+/*
+ * 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 */
diff --git a/include/plat/arm/soc/common/soc_css_def.h b/include/plat/arm/soc/common/soc_css_def.h
new file mode 100644
index 0000000..b4b6ba8
--- /dev/null
+++ b/include/plat/arm/soc/common/soc_css_def.h
@@ -0,0 +1,86 @@
+/*
+ * 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 <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+/*
+ * 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 */
diff --git a/include/plat/brcm/common/bcm_console.h b/include/plat/brcm/common/bcm_console.h
new file mode 100644
index 0000000..7b653d8
--- /dev/null
+++ b/include/plat/brcm/common/bcm_console.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2018-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BCM_CONSOLE_H
+#define BCM_CONSOLE_H
+
+void bcm_console_boot_init(void);
+void bcm_console_boot_end(void);
+void bcm_console_runtime_init(void);
+void bcm_console_runtime_end(void);
+
+#endif /* BCM_CONSOLE_H */
diff --git a/include/plat/brcm/common/bcm_elog.h b/include/plat/brcm/common/bcm_elog.h
new file mode 100644
index 0000000..ea4b169
--- /dev/null
+++ b/include/plat/brcm/common/bcm_elog.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BCM_ELOG_H
+#define BCM_ELOG_H
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+#if defined(BCM_ELOG) && (defined(IMAGE_BL2) || defined(IMAGE_BL31))
+int bcm_elog_init(void *base, uint32_t size, unsigned int level);
+void bcm_elog_exit(void);
+int bcm_elog_copy_log(void *dst, uint32_t max_size);
+void bcm_elog(const char *fmt, ...);
+#else
+static inline int bcm_elog_init(void *base, uint32_t size,
+ unsigned int level)
+{
+ return 0;
+}
+static inline void bcm_elog_exit(void)
+{
+}
+static inline int bcm_elog_copy_log(void *dst, uint32_t max_size)
+{
+ return 0;
+}
+static inline void bcm_elog(const char *fmt, ...)
+{
+}
+#endif /* BCM_ELOG */
+
+#endif /* __ASSEMBLER__ */
+#endif /* BCM_ELOG_H */
diff --git a/include/plat/brcm/common/brcm_def.h b/include/plat/brcm/common/brcm_def.h
new file mode 100644
index 0000000..c9137bc
--- /dev/null
+++ b/include/plat/brcm/common/brcm_def.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BRCM_DEF_H
+#define BRCM_DEF_H
+
+#include <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/common_def.h>
+
+#include <platform_def.h>
+
+#define PLAT_PHY_ADDR_SPACE_SIZE BIT_64(32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE BIT_64(32)
+
+#define BL11_DAUTH_ID 0x796C51ab
+#define BL11_DAUTH_BASE BL11_RW_BASE
+
+/* We keep a table at the end of ROM for function pointers */
+#define ROM_TABLE_SIZE 32
+#define BL1_ROM_TABLE (BL1_RO_LIMIT - ROM_TABLE_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 BRCM_TZC_DRAM1_SIZE ULL(0x01000000)
+
+#define BRCM_SCP_TZC_DRAM1_BASE (BRCM_DRAM1_BASE + \
+ BRCM_DRAM1_SIZE - \
+ BRCM_SCP_TZC_DRAM1_SIZE)
+#define BRCM_SCP_TZC_DRAM1_SIZE PLAT_BRCM_SCP_TZC_DRAM1_SIZE
+
+#define BRCM_AP_TZC_DRAM1_BASE (BRCM_DRAM1_BASE + \
+ BRCM_DRAM1_SIZE - \
+ BRCM_TZC_DRAM1_SIZE)
+#define BRCM_AP_TZC_DRAM1_SIZE (BRCM_TZC_DRAM1_SIZE - \
+ BRCM_SCP_TZC_DRAM1_SIZE)
+
+#define BRCM_NS_DRAM1_BASE BRCM_DRAM1_BASE
+#define BRCM_NS_DRAM1_SIZE (BRCM_DRAM1_SIZE - \
+ BRCM_TZC_DRAM1_SIZE)
+
+#ifdef BRCM_SHARED_DRAM_BASE
+#define BRCM_NS_SHARED_DRAM_BASE BRCM_SHARED_DRAM_BASE
+#define BRCM_NS_SHARED_DRAM_SIZE BRCM_SHARED_DRAM_SIZE
+#endif
+
+#define BRCM_MAP_SHARED_RAM MAP_REGION_FLAT( \
+ BRCM_SHARED_RAM_BASE, \
+ BRCM_SHARED_RAM_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+#define BRCM_MAP_NS_DRAM1 MAP_REGION_FLAT( \
+ BRCM_NS_DRAM1_BASE, \
+ BRCM_NS_DRAM1_SIZE, \
+ MT_MEMORY | MT_RW | MT_NS)
+
+#ifdef BRCM_SHARED_DRAM_BASE
+#define BRCM_MAP_NS_SHARED_DRAM MAP_REGION_FLAT( \
+ BRCM_NS_SHARED_DRAM_BASE, \
+ BRCM_NS_SHARED_DRAM_SIZE, \
+ MT_MEMORY | MT_RW | MT_NS)
+#endif
+
+#ifdef BRCM_EXT_SRAM_BASE
+#define BRCM_MAP_EXT_SRAM MAP_REGION_FLAT( \
+ BRCM_EXT_SRAM_BASE, \
+ BRCM_EXT_SRAM_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+#endif
+
+#define BRCM_MAP_NAND_RO MAP_REGION_FLAT(NAND_BASE_ADDR,\
+ NAND_SIZE, \
+ MT_MEMORY | MT_RO | MT_SECURE)
+
+#define BRCM_MAP_QSPI_RO MAP_REGION_FLAT(QSPI_BASE_ADDR,\
+ QSPI_SIZE, \
+ MT_MEMORY | MT_RO | MT_SECURE)
+
+#define HSLS_REGION MAP_REGION_FLAT(HSLS_BASE_ADDR, \
+ HSLS_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+#define CCN_REGION MAP_REGION_FLAT(PLAT_BRCM_CCN_BASE, \
+ CCN_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+#define GIC500_REGION MAP_REGION_FLAT(GIC500_BASE, \
+ GIC500_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+#ifdef PERIPH0_BASE
+#define PERIPH0_REGION MAP_REGION_FLAT(PERIPH0_BASE, \
+ PERIPH0_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+#endif
+
+#ifdef PERIPH1_BASE
+#define PERIPH1_REGION MAP_REGION_FLAT(PERIPH1_BASE, \
+ PERIPH1_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+#endif
+
+#ifdef PERIPH2_BASE
+#define PERIPH2_REGION MAP_REGION_FLAT(PERIPH2_BASE, \
+ PERIPH2_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+#endif
+
+#if BRCM_BL31_IN_DRAM
+#if IMAGE_BL2
+#define BRCM_MAP_BL31_SEC_DRAM MAP_REGION_FLAT( \
+ BL31_BASE, \
+ PLAT_BRCM_MAX_BL31_SIZE,\
+ MT_DEVICE | MT_RW | MT_SECURE)
+#else
+#define BRCM_MAP_BL31_SEC_DRAM MAP_REGION_FLAT( \
+ BL31_BASE, \
+ PLAT_BRCM_MAX_BL31_SIZE,\
+ MT_MEMORY | MT_RW | MT_SECURE)
+#endif
+#endif
+
+#if defined(USB_BASE) && defined(DRIVER_USB_ENABLE)
+#define USB_REGION MAP_REGION_FLAT( \
+ USB_BASE, \
+ USB_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+#endif
+
+#ifdef USE_CRMU_SRAM
+#define CRMU_SRAM_REGION MAP_REGION_FLAT( \
+ CRMU_SRAM_BASE, \
+ CRMU_SRAM_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+#endif
+/*
+ * 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 BRCM_BL_REGIONS 3
+#else
+#define BRCM_BL_REGIONS 2
+#endif
+
+#endif /* BRCM_DEF_H */
diff --git a/include/plat/brcm/common/plat_brcm.h b/include/plat/brcm/common/plat_brcm.h
new file mode 100644
index 0000000..66ed2cb
--- /dev/null
+++ b/include/plat/brcm/common/plat_brcm.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_BRCM_H
+#define PLAT_BRCM_H
+
+#include <stdint.h>
+
+#include <lib/cassert.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+#include <platform_def.h>
+
+struct image_info;
+
+/* Global variables */
+extern const mmap_region_t plat_brcm_mmap[];
+
+uint32_t brcm_get_spsr_for_bl32_entry(void);
+uint32_t brcm_get_spsr_for_bl33_entry(void);
+const mmap_region_t *plat_brcm_get_mmap(void);
+int bcm_bl2_handle_scp_bl2(struct image_info *image_info);
+unsigned int plat_brcm_calc_core_pos(u_register_t mpidr);
+void plat_brcm_gic_driver_init(void);
+void plat_brcm_gic_init(void);
+void plat_brcm_gic_cpuif_enable(void);
+void plat_brcm_gic_cpuif_disable(void);
+void plat_brcm_gic_pcpu_init(void);
+void plat_brcm_gic_redistif_on(void);
+void plat_brcm_gic_redistif_off(void);
+void plat_brcm_interconnect_init(void);
+void plat_brcm_interconnect_enter_coherency(void);
+void plat_brcm_interconnect_exit_coherency(void);
+void plat_brcm_io_setup(void);
+void plat_brcm_process_flags(uint16_t plat_toc_flags);
+
+#endif /* PLAT_BRCM_H */
diff --git a/include/plat/common/common_def.h b/include/plat/common/common_def.h
new file mode 100644
index 0000000..1d3ac15
--- /dev/null
+++ b/include/plat/common/common_def.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef COMMON_DEF_H
+#define COMMON_DEF_H
+
+#include <common/bl_common.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#include <platform_def.h>
+
+#define SZ_32 U(0x00000020)
+#define SZ_64 U(0x00000040)
+#define SZ_128 U(0x00000080)
+#define SZ_256 U(0x00000100)
+#define SZ_512 U(0x00000200)
+
+#define SZ_1K U(0x00000400)
+#define SZ_2K U(0x00000800)
+#define SZ_4K U(0x00001000)
+#define SZ_8K U(0x00002000)
+#define SZ_16K U(0x00004000)
+#define SZ_32K U(0x00008000)
+#define SZ_64K U(0x00010000)
+#define SZ_128K U(0x00020000)
+#define SZ_256K U(0x00040000)
+#define SZ_512K U(0x00080000)
+
+#define SZ_1M U(0x00100000)
+#define SZ_2M U(0x00200000)
+#define SZ_4M U(0x00400000)
+#define SZ_8M U(0x00800000)
+#define SZ_16M U(0x01000000)
+#define SZ_32M U(0x02000000)
+#define SZ_64M U(0x04000000)
+#define SZ_128M U(0x08000000)
+#define SZ_256M U(0x10000000)
+#define SZ_512M U(0x20000000)
+
+#define SZ_1G U(0x40000000)
+#define SZ_2G U(0x80000000)
+
+/******************************************************************************
+ * 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 */
+
+#if MEASURED_BOOT
+/*
+ * Start critical data Ids from 2^32/2 reserving Ids from 0 to (2^32/2 - 1)
+ * for Images, It is a critical data Id base for all platforms.
+ */
+#define CRITICAL_DATA_ID_BASE U(0x80000000)
+#endif /* MEASURED_BOOT */
+
+#endif /* COMMON_DEF_H */
diff --git a/include/plat/common/plat_drtm.h b/include/plat/common/plat_drtm.h
new file mode 100644
index 0000000..e96e719
--- /dev/null
+++ b/include/plat/common/plat_drtm.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_DRTM_H
+#define PLAT_DRTM_H
+
+#include <stdint.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+
+typedef struct {
+ uint8_t max_num_mem_prot_regions;
+ uint8_t dma_protection_support;
+} plat_drtm_dma_prot_features_t;
+
+typedef struct {
+ bool tpm_based_hash_support;
+ uint32_t firmware_hash_algorithm;
+} plat_drtm_tpm_features_t;
+
+typedef struct {
+ uint64_t region_address;
+ uint64_t region_size_type;
+} __attribute__((packed)) drtm_mem_region_t;
+
+/*
+ * Memory region descriptor table structure as per DRTM beta0 section 3.13
+ * Table 11 MEMORY_REGION_DESCRIPTOR_TABLE
+ */
+typedef struct {
+ uint16_t revision;
+ uint16_t reserved;
+ uint32_t num_regions;
+ drtm_mem_region_t region[];
+} __attribute__((packed)) drtm_memory_region_descriptor_table_t;
+
+/* platform specific address map functions */
+const mmap_region_t *plat_get_addr_mmap(void);
+
+/* platform-specific DMA protection functions */
+bool plat_has_non_host_platforms(void);
+bool plat_has_unmanaged_dma_peripherals(void);
+unsigned int plat_get_total_smmus(void);
+void plat_enumerate_smmus(const uintptr_t **smmus_out,
+ size_t *smmu_count_out);
+const plat_drtm_dma_prot_features_t *plat_drtm_get_dma_prot_features(void);
+uint64_t plat_drtm_dma_prot_get_max_table_bytes(void);
+
+/* platform-specific TPM functions */
+const plat_drtm_tpm_features_t *plat_drtm_get_tpm_features(void);
+
+/*
+ * TODO: Implement these functions as per the platform use case,
+ * as of now none of the platform uses these functions
+ */
+uint64_t plat_drtm_get_min_size_normal_world_dce(void);
+uint64_t plat_drtm_get_tcb_hash_table_size(void);
+uint64_t plat_drtm_get_imp_def_dlme_region_size(void);
+uint64_t plat_drtm_get_tcb_hash_features(void);
+
+/* DRTM error handling functions */
+int plat_set_drtm_error(uint64_t error_code);
+int plat_get_drtm_error(uint64_t *error_code);
+
+/*
+ * Platform-specific function to ensure passed region lies within
+ * Non-Secure region of DRAM
+ */
+int plat_drtm_validate_ns_region(uintptr_t region_start,
+ size_t region_size);
+
+#endif /* PLAT_DRTM_H */
diff --git a/include/plat/common/plat_trng.h b/include/plat/common/plat_trng.h
new file mode 100644
index 0000000..a9f73b6
--- /dev/null
+++ b/include/plat/common/plat_trng.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2021, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_TRNG_H
+#define PLAT_TRNG_H
+
+#include <tools_share/uuid.h>
+
+/* TRNG platform functions */
+
+extern uuid_t plat_trng_uuid;
+void plat_entropy_setup(void);
+bool plat_get_entropy(uint64_t *out);
+
+#endif /* PLAT_TRNG_H */
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
new file mode 100644
index 0000000..8407bbd
--- /dev/null
+++ b/include/plat/common/platform.h
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_H
+#define PLATFORM_H
+
+#include <stdint.h>
+
+#include <lib/psci/psci.h>
+#if defined(SPD_spmd)
+ #include <services/spm_core_manifest.h>
+#endif
+#if ENABLE_RME
+#include <services/rmm_core_manifest.h>
+#endif
+#include <drivers/fwu/fwu_metadata.h>
+#if TRNG_SUPPORT
+#include "plat_trng.h"
+#endif /* TRNG_SUPPORT */
+#if DRTM_SUPPORT
+#include "plat_drtm.h"
+#endif /* DRTM_SUPPORT */
+
+/*******************************************************************************
+ * 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 spm_mm_boot_info;
+struct sp_res_desc;
+enum fw_enc_status_t;
+
+/*******************************************************************************
+ * 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)
+
+/*******************************************************************************
+ * plat_get_enc_key_info() flags
+ ******************************************************************************/
+/*
+ * Flag used to notify caller that information provided in key buffer is an
+ * identifier rather than an actual key.
+ */
+#define ENC_KEY_IS_IDENTIFIER (1 << 0)
+
+/*******************************************************************************
+ * 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_raise_ns_sgi(int sgi_num, u_register_t target);
+void plat_ic_raise_s_el1_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);
+void plat_report_prefetch_abort(unsigned int fault_address);
+void plat_report_data_abort(unsigned int fault_address);
+int plat_crash_console_init(void);
+int plat_crash_console_putc(int c);
+void plat_crash_console_flush(void);
+void plat_error_handler(int err) __dead2;
+void plat_panic_handler(void) __dead2;
+void plat_system_reset(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);
+
+#if MEASURED_BOOT
+int plat_mboot_measure_image(unsigned int image_id, image_info_t *image_data);
+int plat_mboot_measure_critical_data(unsigned int critical_data_id,
+ const void *base,
+ size_t size);
+#else
+static inline int plat_mboot_measure_image(unsigned int image_id __unused,
+ image_info_t *image_data __unused)
+{
+ return 0;
+}
+static inline int plat_mboot_measure_critical_data(
+ unsigned int critical_data_id __unused,
+ const void *base __unused,
+ size_t size __unused)
+{
+ return 0;
+}
+#endif /* MEASURED_BOOT */
+
+/*******************************************************************************
+ * 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
+void plat_sdei_setup(void);
+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_default_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
+ void *handle, uint64_t flags);
+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);
+
+#if MEASURED_BOOT
+void bl1_plat_mboot_init(void);
+void bl1_plat_mboot_finish(void);
+#else
+static inline void bl1_plat_mboot_init(void)
+{
+}
+static inline void bl1_plat_mboot_finish(void)
+{
+}
+#endif /* MEASURED_BOOT */
+
+/*******************************************************************************
+ * 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)
+ ******************************************************************************/
+#if MEASURED_BOOT
+void bl2_plat_mboot_init(void);
+void bl2_plat_mboot_finish(void);
+#else
+static inline void bl2_plat_mboot_init(void)
+{
+}
+static inline void bl2_plat_mboot_finish(void)
+{
+}
+#endif /* MEASURED_BOOT */
+
+/*******************************************************************************
+ * 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,
+ unsigned 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);
+
+/*******************************************************************************
+ * Mandatory BL31 functions when ENABLE_RME=1
+ ******************************************************************************/
+#if ENABLE_RME
+int plat_rmmd_get_cca_attest_token(uintptr_t buf, size_t *len,
+ uintptr_t hash, size_t hash_size);
+int plat_rmmd_get_cca_realm_attest_key(uintptr_t buf, size_t *len,
+ unsigned int type);
+size_t plat_rmmd_get_el3_rmm_shared_mem(uintptr_t *shared);
+int plat_rmmd_load_manifest(rmm_manifest_t *manifest);
+#endif
+
+/*******************************************************************************
+ * 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 plat_convert_pk(void *full_pk_ptr, unsigned int full_pk_len,
+ void **hashed_pk_ptr, unsigned int *hash_pk_len);
+int get_mbedtls_heap_helper(void **heap_addr, size_t *heap_size);
+int plat_get_enc_key_info(enum fw_enc_status_t fw_enc_status, uint8_t *key,
+ size_t *key_len, unsigned int *flags,
+ const uint8_t *img_id, size_t img_id_len);
+
+/*******************************************************************************
+ * Secure Partitions functions
+ ******************************************************************************/
+const struct mmap_region *plat_get_secure_partition_mmap(void *cookie);
+const struct spm_mm_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);
+#if defined(SPD_spmd)
+int plat_spm_core_manifest_load(spmc_manifest_attribute_t *manifest,
+ const void *pm_addr);
+#endif
+#if defined(SPMC_AT_EL3)
+int plat_spmc_shmem_datastore_get(uint8_t **datastore, size_t *size);
+#endif
+
+/*******************************************************************************
+ * 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);
+
+/*
+ * Optional function to get SOC version
+ */
+int32_t plat_get_soc_version(void);
+
+/*
+ * Optional function to get SOC revision
+ */
+int32_t plat_get_soc_revision(void);
+
+/*
+ * Optional function to check for SMCCC function availability for platform
+ */
+int32_t plat_is_smccc_feature_available(u_register_t fid);
+
+/*******************************************************************************
+ * FWU platform specific functions
+ ******************************************************************************/
+int plat_fwu_set_metadata_image_source(unsigned int image_id,
+ uintptr_t *dev_handle,
+ uintptr_t *image_spec);
+void plat_fwu_set_images_source(const struct fwu_metadata *metadata);
+uint32_t plat_fwu_get_boot_idx(void);
+
+#endif /* PLATFORM_H */
diff --git a/include/plat/marvell/armada/a3k/common/armada_common.h b/include/plat/marvell/armada/a3k/common/armada_common.h
new file mode 100644
index 0000000..c6953fb
--- /dev/null
+++ b/include/plat/marvell/armada/a3k/common/armada_common.h
@@ -0,0 +1,17 @@
+/*
+ * 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 <stdint.h>
+
+#include <io_addr_dec.h>
+
+int marvell_get_io_dec_win_conf(struct dec_win_config **win, uint32_t *size);
+
+#endif /* ARMADA_COMMON_H */
diff --git a/include/plat/marvell/armada/a3k/common/board_marvell_def.h b/include/plat/marvell/armada/a3k/common/board_marvell_def.h
new file mode 100644
index 0000000..bc3e04f
--- /dev/null
+++ b/include/plat/marvell/armada/a3k/common/board_marvell_def.h
@@ -0,0 +1,74 @@
+/*
+ * 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
+
+#endif /* BOARD_MARVELL_DEF_H */
diff --git a/include/plat/marvell/armada/a3k/common/marvell_def.h b/include/plat/marvell/armada/a3k/common/marvell_def.h
new file mode 100644
index 0000000..1394c05
--- /dev/null
+++ b/include/plat/marvell/armada/a3k/common/marvell_def.h
@@ -0,0 +1,188 @@
+/*
+ * 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 <platform_def.h>
+
+#include <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/common_def.h>
+
+/****************************************************************************
+ * 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
+
+/* This leaves a gap between end of DRAM and start of ROM block */
+#define MARVELL_TRUSTED_DRAM_SIZE 0x80000 /* 512 KB */
+
+/* The first 4KB of Trusted SRAM are used as shared memory */
+#define MARVELL_SHARED_RAM_BASE PLAT_MARVELL_ATF_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 (MARVELL_TRUSTED_DRAM_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)
+
+/*****************************************************************************
+ * BL32 specific defines.
+ *****************************************************************************
+ */
+#define BL32_BASE PLAT_MARVELL_TRUSTED_RAM_BASE
+#define BL32_LIMIT (BL32_BASE + PLAT_MARVELL_TRUSTED_RAM_SIZE)
+
+#ifdef SPD_none
+#undef BL32_BASE
+#endif /* SPD_none */
+
+#endif /* MARVELL_DEF_H */
diff --git a/include/plat/marvell/armada/a3k/common/plat_marvell.h b/include/plat/marvell/armada/a3k/common/plat_marvell.h
new file mode 100644
index 0000000..cb31481
--- /dev/null
+++ b/include/plat/marvell/armada/a3k/common/plat_marvell.h
@@ -0,0 +1,105 @@
+/*
+ * 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 <stdint.h>
+
+#include <common/bl_common.h>
+#include <lib/cassert.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+/*
+ * 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);
+
+uint32_t get_ref_clk(void);
+
+#endif /* PLAT_MARVELL_H */
diff --git a/include/plat/marvell/armada/a8k/common/armada_common.h b/include/plat/marvell/armada/a8k/common/armada_common.h
new file mode 100644
index 0000000..709d009
--- /dev/null
+++ b/include/plat/marvell/armada/a8k/common/armada_common.h
@@ -0,0 +1,129 @@
+/*
+ * 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 <drivers/marvell/amb_adec.h>
+#include <drivers/marvell/ccu.h>
+#include <drivers/marvell/io_win.h>
+#include <drivers/marvell/iob.h>
+
+/*
+ * 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);
+int system_power_off(void);
+
+#endif /* ARMADA_COMMON_H */
diff --git a/include/plat/marvell/armada/a8k/common/board_marvell_def.h b/include/plat/marvell/armada/a8k/common/board_marvell_def.h
new file mode 100644
index 0000000..7e90f5f
--- /dev/null
+++ b/include/plat/marvell/armada/a8k/common/board_marvell_def.h
@@ -0,0 +1,74 @@
+/*
+ * 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
+
+#endif /* BOARD_MARVELL_DEF_H */
diff --git a/include/plat/marvell/armada/a8k/common/efuse_def.h b/include/plat/marvell/armada/a8k/common/efuse_def.h
new file mode 100644
index 0000000..ff1d4a3
--- /dev/null
+++ b/include/plat/marvell/armada/a8k/common/efuse_def.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef EFUSE_DEF_H
+#define EFUSE_DEF_H
+
+#include <platform_def.h>
+
+#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_SELECT_MASK (1 << EFUSE_SRV_CTRL_LD_SELECT_OFFS)
+
+#define MVEBU_AP_LD_EFUSE_BASE (MVEBU_AP_GEN_MGMT_BASE + 0xF00)
+/* Bits [31:0] - 32 data bits total */
+#define MVEBU_AP_LDX_31_0_EFUSE_OFFS (MVEBU_AP_LD_EFUSE_BASE)
+/* Bits [62:32] - 31 data bits total 32nd bit is parity for bits [62:0]*/
+#define MVEBU_AP_LDX_62_32_EFUSE_OFFS (MVEBU_AP_LD_EFUSE_BASE + 0x4)
+/* Bits [94:63] - 32 data bits total */
+#define MVEBU_AP_LDX_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_LDX_125_95_EFUSE_OFFS (MVEBU_AP_LD_EFUSE_BASE + 0xC)
+/* Bits [157:126] - 32 data bits total */
+#define MVEBU_AP_LDX_126_157_EFUSE_OFFS (MVEBU_AP_LD_EFUSE_BASE + 0x10)
+/* Bits [188:158] - 31 data bits total, 32nd bit is parity for bits [188:126] */
+#define MVEBU_AP_LDX_188_158_EFUSE_OFFS (MVEBU_AP_LD_EFUSE_BASE + 0x14)
+/* Bits [220:189] - 32 data bits total */
+#define MVEBU_AP_LDX_220_189_EFUSE_OFFS (MVEBU_AP_LD_EFUSE_BASE + 0x18)
+
+#endif /* EFUSE_DEF_H */
diff --git a/include/plat/marvell/armada/a8k/common/marvell_def.h b/include/plat/marvell/armada/a8k/common/marvell_def.h
new file mode 100644
index 0000000..1245b88
--- /dev/null
+++ b/include/plat/marvell/armada/a8k/common/marvell_def.h
@@ -0,0 +1,222 @@
+/*
+ * 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 <platform_def.h>
+
+#include <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/common_def.h>
+
+/******************************************************************************
+ * 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
+
+/* This leaves a gap between end of DRAM and start of ROM block */
+#define MARVELL_TRUSTED_DRAM_SIZE 0x80000 /* 512 KB */
+
+/* The first 4KB of Trusted SRAM are used as shared memory */
+#define MARVELL_SHARED_RAM_BASE PLAT_MARVELL_ATF_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 (MARVELL_TRUSTED_DRAM_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
+
+#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 MARVELL_OPTEE_PAGEABLE_LOAD_BASE \
+ (PLAT_MARVELL_TRUSTED_RAM_BASE + \
+ PLAT_MARVELL_TRUSTED_RAM_SIZE - \
+ MARVELL_OPTEE_PAGEABLE_LOAD_SIZE)
+#define MARVELL_OPTEE_PAGEABLE_LOAD_SIZE 0x400000
+#define MARVELL_OPTEE_PAGEABLE_LOAD_MEM \
+ MAP_REGION_FLAT( \
+ MARVELL_OPTEE_PAGEABLE_LOAD_BASE, \
+ MARVELL_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 MARVELL_MAP_OPTEE_CORE_MEM MAP_REGION_FLAT( \
+ BL32_BASE, \
+ BL32_LIMIT - BL32_BASE, \
+ MT_MEMORY | MT_RW | MT_SECURE)
+#endif /* SPD_opteed */
+
+#define MARVELL_MAP_SECURE_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)
+
+/*******************************************************************************
+ * BL32 specific defines.
+ ******************************************************************************/
+#define BL32_BASE PLAT_MARVELL_TRUSTED_RAM_BASE
+#define BL32_LIMIT (BL32_BASE + PLAT_MARVELL_TRUSTED_RAM_SIZE)
+
+#ifdef SPD_none
+#undef BL32_BASE
+#endif /* SPD_none */
+
+#endif /* MARVELL_DEF_H */
diff --git a/include/plat/marvell/armada/a8k/common/plat_marvell.h b/include/plat/marvell/armada/a8k/common/plat_marvell.h
new file mode 100644
index 0000000..bec21a0
--- /dev/null
+++ b/include/plat/marvell/armada/a8k/common/plat_marvell.h
@@ -0,0 +1,138 @@
+/*
+ * 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 <stdint.h>
+
+#include <common/bl_common.h>
+#include <lib/cassert.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+/*
+ * 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 */
diff --git a/include/plat/marvell/armada/a8k/common/plat_pm_trace.h b/include/plat/marvell/armada/a8k/common/plat_pm_trace.h
new file mode 100644
index 0000000..a954914
--- /dev/null
+++ b/include/plat/marvell/armada/a8k/common/plat_pm_trace.h
@@ -0,0 +1,99 @@
+/*
+ * 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 */
diff --git a/include/plat/marvell/armada/common/aarch64/cci_macros.S b/include/plat/marvell/armada/common/aarch64/cci_macros.S
new file mode 100644
index 0000000..b0a909b
--- /dev/null
+++ b/include/plat/marvell/armada/common/aarch64/cci_macros.S
@@ -0,0 +1,39 @@
+/*
+ * 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 <drivers/arm/cci.h>
+#include <platform_def.h>
+
+.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 */
diff --git a/include/plat/marvell/armada/common/aarch64/marvell_macros.S b/include/plat/marvell/armada/common/aarch64/marvell_macros.S
new file mode 100644
index 0000000..bfe2d41
--- /dev/null
+++ b/include/plat/marvell/armada/common/aarch64/marvell_macros.S
@@ -0,0 +1,134 @@
+/*
+ * 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 <drivers/arm/cci.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gicv3.h>
+#include <platform_def.h>
+
+/*
+ * 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 */
diff --git a/include/plat/marvell/armada/common/marvell_plat_priv.h b/include/plat/marvell/armada/common/marvell_plat_priv.h
new file mode 100644
index 0000000..78b5331
--- /dev/null
+++ b/include/plat/marvell/armada/common/marvell_plat_priv.h
@@ -0,0 +1,34 @@
+/*
+ * 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 <lib/utils.h>
+
+/*****************************************************************************
+ * 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 */
diff --git a/include/plat/marvell/armada/common/marvell_pm.h b/include/plat/marvell/armada/common/marvell_pm.h
new file mode 100644
index 0000000..8f16607
--- /dev/null
+++ b/include/plat/marvell/armada/common/marvell_pm.h
@@ -0,0 +1,26 @@
+/*
+ * 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 */
diff --git a/include/plat/marvell/armada/common/mvebu.h b/include/plat/marvell/armada/common/mvebu.h
new file mode 100644
index 0000000..35a0200
--- /dev/null
+++ b/include/plat/marvell/armada/common/mvebu.h
@@ -0,0 +1,39 @@
+/*
+ * 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 */
diff --git a/include/services/arm_arch_svc.h b/include/services/arm_arch_svc.h
new file mode 100644
index 0000000..645b388
--- /dev/null
+++ b/include/services/arm_arch_svc.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018-2022, 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_SOC_ID U(0x80000002)
+#define SMCCC_ARCH_WORKAROUND_1 U(0x80008000)
+#define SMCCC_ARCH_WORKAROUND_2 U(0x80007FFF)
+#define SMCCC_ARCH_WORKAROUND_3 U(0x80003FFF)
+
+#define SMCCC_GET_SOC_VERSION U(0)
+#define SMCCC_GET_SOC_REVISION U(1)
+
+#endif /* ARM_ARCH_SVC_H */
diff --git a/include/services/drtm_svc.h b/include/services/drtm_svc.h
new file mode 100644
index 0000000..69b314f
--- /dev/null
+++ b/include/services/drtm_svc.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2022 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * DRTM service
+ *
+ * Authors:
+ * Lucian Paul-Trifu <lucian.paultrifu@gmail.com>
+ * Brian Nezvadovitz <brinez@microsoft.com> 2021-02-01
+ *
+ */
+
+#ifndef ARM_DRTM_SVC_H
+#define ARM_DRTM_SVC_H
+
+/*
+ * SMC function IDs for DRTM Service
+ * Upper word bits set: Fast call, SMC64, Standard Secure Svc. Call (OEN = 4)
+ */
+#define DRTM_FID(func_num) \
+ ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT) | \
+ (SMC_64 << FUNCID_CC_SHIFT) | \
+ (OEN_STD_START << FUNCID_OEN_SHIFT) | \
+ ((func_num) << FUNCID_NUM_SHIFT))
+
+#define DRTM_FNUM_SVC_VERSION U(0x110)
+#define DRTM_FNUM_SVC_FEATURES U(0x111)
+#define DRTM_FNUM_SVC_UNPROTECT_MEM U(0x113)
+#define DRTM_FNUM_SVC_DYNAMIC_LAUNCH U(0x114)
+#define DRTM_FNUM_SVC_CLOSE_LOCALITY U(0x115)
+#define DRTM_FNUM_SVC_GET_ERROR U(0x116)
+#define DRTM_FNUM_SVC_SET_ERROR U(0x117)
+#define DRTM_FNUM_SVC_SET_TCB_HASH U(0x118)
+#define DRTM_FNUM_SVC_LOCK_TCB_HASH U(0x119)
+
+#define ARM_DRTM_SVC_VERSION DRTM_FID(DRTM_FNUM_SVC_VERSION)
+#define ARM_DRTM_SVC_FEATURES DRTM_FID(DRTM_FNUM_SVC_FEATURES)
+#define ARM_DRTM_SVC_UNPROTECT_MEM DRTM_FID(DRTM_FNUM_SVC_UNPROTECT_MEM)
+#define ARM_DRTM_SVC_DYNAMIC_LAUNCH DRTM_FID(DRTM_FNUM_SVC_DYNAMIC_LAUNCH)
+#define ARM_DRTM_SVC_CLOSE_LOCALITY DRTM_FID(DRTM_FNUM_SVC_CLOSE_LOCALITY)
+#define ARM_DRTM_SVC_GET_ERROR DRTM_FID(DRTM_FNUM_SVC_GET_ERROR)
+#define ARM_DRTM_SVC_SET_ERROR DRTM_FID(DRTM_FNUM_SVC_SET_ERROR)
+#define ARM_DRTM_SVC_SET_TCB_HASH DRTM_FID(DRTM_FNUM_SVC_SET_TCB_HASH)
+#define ARM_DRTM_SVC_LOCK_TCB_HASH DRTM_FID(DRTM_FNUM_SVC_LOCK_TCB_HASH)
+
+#define ARM_DRTM_FEATURES_TPM U(0x1)
+#define ARM_DRTM_FEATURES_MEM_REQ U(0x2)
+#define ARM_DRTM_FEATURES_DMA_PROT U(0x3)
+#define ARM_DRTM_FEATURES_BOOT_PE_ID U(0x4)
+#define ARM_DRTM_FEATURES_TCB_HASHES U(0x5)
+
+#define is_drtm_fid(_fid) \
+ (((_fid) >= ARM_DRTM_SVC_VERSION) && ((_fid) <= ARM_DRTM_SVC_LOCK_TCB_HASH))
+
+/* ARM DRTM Service Calls version numbers */
+#define ARM_DRTM_VERSION_MAJOR U(0)
+#define ARM_DRTM_VERSION_MAJOR_SHIFT 16
+#define ARM_DRTM_VERSION_MAJOR_MASK U(0x7FFF)
+#define ARM_DRTM_VERSION_MINOR U(1)
+#define ARM_DRTM_VERSION_MINOR_SHIFT 0
+#define ARM_DRTM_VERSION_MINOR_MASK U(0xFFFF)
+
+#define ARM_DRTM_VERSION \
+ ((((ARM_DRTM_VERSION_MAJOR) & ARM_DRTM_VERSION_MAJOR_MASK) << \
+ ARM_DRTM_VERSION_MAJOR_SHIFT) \
+ | (((ARM_DRTM_VERSION_MINOR) & ARM_DRTM_VERSION_MINOR_MASK) << \
+ ARM_DRTM_VERSION_MINOR_SHIFT))
+
+#define ARM_DRTM_FUNC_SHIFT U(63)
+#define ARM_DRTM_FUNC_MASK ULL(0x1)
+#define ARM_DRTM_FUNC_ID U(0x0)
+#define ARM_DRTM_FEAT_ID U(0x1)
+#define ARM_DRTM_FEAT_ID_MASK ULL(0xff)
+
+/*
+ * Definitions for DRTM features as per DRTM beta0 section 3.3,
+ * Table 6 DRTM_FEATURES
+ */
+#define ARM_DRTM_TPM_FEATURES_PCR_SCHEMA_SHIFT U(33)
+#define ARM_DRTM_TPM_FEATURES_PCR_SCHEMA_MASK ULL(0xF)
+#define ARM_DRTM_TPM_FEATURES_PCR_SCHEMA_DEFAULT ULL(0x1)
+
+#define ARM_DRTM_TPM_FEATURES_TPM_HASH_SHIFT U(32)
+#define ARM_DRTM_TPM_FEATURES_TPM_HASH_MASK ULL(0x1)
+#define ARM_DRTM_TPM_FEATURES_TPM_HASH_NOT_SUPPORTED ULL(0x0)
+#define ARM_DRTM_TPM_FEATURES_TPM_HASH_SUPPORTED ULL(0x1)
+
+#define ARM_DRTM_TPM_FEATURES_FW_HASH_SHIFT U(0)
+#define ARM_DRTM_TPM_FEATURES_FW_HASH_MASK ULL(0xFFFFFFFF)
+#define ARM_DRTM_TPM_FEATURES_FW_HASH_SHA256 ULL(0xB)
+#define ARM_DRTM_TPM_FEATURES_FW_HASH_SHA384 ULL(0xC)
+#define ARM_DRTM_TPM_FEATURES_FW_HASH_SHA512 ULL(0xD)
+
+#define ARM_DRTM_MIN_MEM_REQ_DCE_SIZE_SHIFT U(32)
+#define ARM_DRTM_MIN_MEM_REQ_DCE_SIZE_MASK ULL(0xFFFFFFFF)
+
+#define ARM_DRTM_MIN_MEM_REQ_MIN_DLME_DATA_SIZE_SHIFT U(0)
+#define ARM_DRTM_MIN_MEM_REQ_MIN_DLME_DATA_SIZE_MASK ULL(0xFFFFFFFF)
+
+#define ARM_DRTM_DMA_PROT_FEATURES_MAX_REGIONS_SHIFT U(8)
+#define ARM_DRTM_DMA_PROT_FEATURES_MAX_REGIONS_MASK ULL(0xF)
+
+#define ARM_DRTM_DMA_PROT_FEATURES_DMA_SUPPORT_SHIFT U(0)
+#define ARM_DRTM_DMA_PROT_FEATURES_DMA_SUPPORT_MASK ULL(0xFF)
+#define ARM_DRTM_DMA_PROT_FEATURES_DMA_SUPPORT_COMPLETE ULL(0x1)
+#define ARM_DRTM_DMA_PROT_FEATURES_DMA_SUPPORT_REGION ULL(0x2)
+
+#define ARM_DRTM_TCB_HASH_FEATURES_MAX_NUM_HASHES_SHIFT U(0)
+#define ARM_DRTM_TCB_HASH_FEATURES_MAX_NUM_HASHES_MASK ULL(0xFF)
+
+#define ARM_DRTM_TPM_FEATURES_SET_PCR_SCHEMA(reg, val) \
+ do { \
+ reg = (((reg) & ~(ARM_DRTM_TPM_FEATURES_PCR_SCHEMA_MASK \
+ << ARM_DRTM_TPM_FEATURES_PCR_SCHEMA_SHIFT)) | (((val) & \
+ ARM_DRTM_TPM_FEATURES_PCR_SCHEMA_MASK) << \
+ ARM_DRTM_TPM_FEATURES_PCR_SCHEMA_SHIFT)); \
+ } while (false)
+
+#define ARM_DRTM_TPM_FEATURES_SET_TPM_HASH(reg, val) \
+ do { \
+ reg = (((reg) & ~(ARM_DRTM_TPM_FEATURES_TPM_HASH_MASK \
+ << ARM_DRTM_TPM_FEATURES_TPM_HASH_SHIFT)) | (((val) & \
+ ARM_DRTM_TPM_FEATURES_TPM_HASH_MASK) << \
+ ARM_DRTM_TPM_FEATURES_TPM_HASH_SHIFT)); \
+ } while (false)
+
+#define ARM_DRTM_TPM_FEATURES_SET_FW_HASH(reg, val) \
+ do { \
+ reg = (((reg) & ~(ARM_DRTM_TPM_FEATURES_FW_HASH_MASK \
+ << ARM_DRTM_TPM_FEATURES_FW_HASH_SHIFT)) | (((val) & \
+ ARM_DRTM_TPM_FEATURES_FW_HASH_MASK) << \
+ ARM_DRTM_TPM_FEATURES_FW_HASH_SHIFT)); \
+ } while (false)
+
+#define ARM_DRTM_MIN_MEM_REQ_SET_DCE_SIZE(reg, val) \
+ do { \
+ reg = (((reg) & ~(ARM_DRTM_MIN_MEM_REQ_DCE_SIZE_MASK \
+ << ARM_DRTM_MIN_MEM_REQ_DCE_SIZE_SHIFT)) | (((val) & \
+ ARM_DRTM_MIN_MEM_REQ_DCE_SIZE_MASK) << \
+ ARM_DRTM_MIN_MEM_REQ_DCE_SIZE_SHIFT)); \
+ } while (false)
+
+#define ARM_DRTM_MIN_MEM_REQ_SET_MIN_DLME_DATA_SIZE(reg, val) \
+ do { \
+ reg = (((reg) & \
+ ~(ARM_DRTM_MIN_MEM_REQ_MIN_DLME_DATA_SIZE_MASK << \
+ ARM_DRTM_MIN_MEM_REQ_MIN_DLME_DATA_SIZE_SHIFT)) | \
+ (((val) & ARM_DRTM_MIN_MEM_REQ_MIN_DLME_DATA_SIZE_MASK) \
+ << ARM_DRTM_MIN_MEM_REQ_MIN_DLME_DATA_SIZE_SHIFT)); \
+ } while (false)
+
+#define ARM_DRTM_DMA_PROT_FEATURES_SET_MAX_REGIONS(reg, val) \
+ do { \
+ reg = (((reg) & \
+ ~(ARM_DRTM_DMA_PROT_FEATURES_MAX_REGIONS_MASK << \
+ ARM_DRTM_DMA_PROT_FEATURES_MAX_REGIONS_SHIFT)) | \
+ (((val) & ARM_DRTM_DMA_PROT_FEATURES_MAX_REGIONS_MASK) \
+ << ARM_DRTM_DMA_PROT_FEATURES_MAX_REGIONS_SHIFT)); \
+ } while (false)
+
+#define ARM_DRTM_DMA_PROT_FEATURES_SET_DMA_SUPPORT(reg, val) \
+ do { \
+ reg = (((reg) & \
+ ~(ARM_DRTM_DMA_PROT_FEATURES_DMA_SUPPORT_MASK << \
+ ARM_DRTM_DMA_PROT_FEATURES_DMA_SUPPORT_SHIFT)) | \
+ (((val) & ARM_DRTM_DMA_PROT_FEATURES_DMA_SUPPORT_MASK) \
+ << ARM_DRTM_DMA_PROT_FEATURES_DMA_SUPPORT_SHIFT)); \
+ } while (false)
+
+#define ARM_DRTM_TCB_HASH_FEATURES_SET_MAX_NUM_HASHES(reg, val) \
+ do { \
+ reg = (((reg) & \
+ ~(ARM_DRTM_TCB_HASH_FEATURES_MAX_NUM_HASHES_MASK << \
+ ARM_DRTM_TCB_HASH_FEATURES_MAX_NUM_HASHES_SHIFT)) | \
+ (((val) & \
+ ARM_DRTM_TCB_HASH_FEATURES_MAX_NUM_HASHES_MASK) << \
+ ARM_DRTM_TCB_HASH_FEATURES_MAX_NUM_HASHES_SHIFT)); \
+ } while (false)
+
+/* Definitions for DRTM address map */
+#define ARM_DRTM_REGION_SIZE_TYPE_CACHEABILITY_SHIFT U(55)
+#define ARM_DRTM_REGION_SIZE_TYPE_CACHEABILITY_MASK ULL(0x3)
+#define ARM_DRTM_REGION_SIZE_TYPE_CACHEABILITY_NC ULL(0)
+#define ARM_DRTM_REGION_SIZE_TYPE_CACHEABILITY_WC ULL(1)
+#define ARM_DRTM_REGION_SIZE_TYPE_CACHEABILITY_WT ULL(2)
+#define ARM_DRTM_REGION_SIZE_TYPE_CACHEABILITY_WB ULL(3)
+
+#define ARM_DRTM_REGION_SIZE_TYPE_REGION_TYPE_SHIFT U(52)
+#define ARM_DRTM_REGION_SIZE_TYPE_REGION_TYPE_MASK ULL(0x7)
+#define ARM_DRTM_REGION_SIZE_TYPE_REGION_TYPE_NORMAL ULL(0)
+#define ARM_DRTM_REGION_SIZE_TYPE_REGION_TYPE_NCAR ULL(1)
+#define ARM_DRTM_REGION_SIZE_TYPE_REGION_TYPE_DEVICE ULL(2)
+#define ARM_DRTM_REGION_SIZE_TYPE_REGION_TYPE_NV ULL(3)
+#define ARM_DRTM_REGION_SIZE_TYPE_REGION_TYPE_RSVD ULL(4)
+
+#define ARM_DRTM_REGION_SIZE_TYPE_4K_PAGE_NUM_SHIFT U(0)
+#define ARM_DRTM_REGION_SIZE_TYPE_4K_PAGE_NUM_MASK ULL(0xFFFFFFFFFFFFF)
+
+#define ARM_DRTM_REGION_SIZE_TYPE_SET_CACHEABILITY(reg, val) \
+ do { \
+ reg = (((reg) & \
+ ~(ARM_DRTM_REGION_SIZE_TYPE_CACHEABILITY_MASK << \
+ ARM_DRTM_REGION_SIZE_TYPE_CACHEABILITY_SHIFT)) | \
+ (((val) & \
+ ARM_DRTM_REGION_SIZE_TYPE_CACHEABILITY_MASK) << \
+ ARM_DRTM_REGION_SIZE_TYPE_CACHEABILITY_SHIFT)); \
+ } while (false)
+
+#define ARM_DRTM_REGION_SIZE_TYPE_SET_REGION_TYPE(reg, val) \
+ do { \
+ reg = (((reg) & \
+ ~(ARM_DRTM_REGION_SIZE_TYPE_REGION_TYPE_MASK << \
+ ARM_DRTM_REGION_SIZE_TYPE_REGION_TYPE_SHIFT)) | \
+ (((val) & ARM_DRTM_REGION_SIZE_TYPE_REGION_TYPE_MASK) \
+ << ARM_DRTM_REGION_SIZE_TYPE_REGION_TYPE_SHIFT)); \
+ } while (false)
+
+#define ARM_DRTM_REGION_SIZE_TYPE_SET_4K_PAGE_NUM(reg, val) \
+ do { \
+ reg = (((reg) & \
+ ~(ARM_DRTM_REGION_SIZE_TYPE_4K_PAGE_NUM_MASK << \
+ ARM_DRTM_REGION_SIZE_TYPE_4K_PAGE_NUM_SHIFT)) | \
+ (((val) & ARM_DRTM_REGION_SIZE_TYPE_4K_PAGE_NUM_MASK) \
+ << ARM_DRTM_REGION_SIZE_TYPE_4K_PAGE_NUM_SHIFT)); \
+ } while (false)
+
+/* Initialization routine for the DRTM service */
+int drtm_setup(void);
+
+/* Handler to be called to handle DRTM SMC calls */
+uint64_t drtm_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 /* ARM_DRTM_SVC_H */
diff --git a/include/services/el3_spmc_ffa_memory.h b/include/services/el3_spmc_ffa_memory.h
new file mode 100644
index 0000000..2037eca
--- /dev/null
+++ b/include/services/el3_spmc_ffa_memory.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EL3_SPMC_FFA_MEM_H
+#define EL3_SPMC_FFA_MEM_H
+
+#include <assert.h>
+
+/*
+ * Subset of Arm Firmware Framework for Armv8-A
+ * (https://developer.arm.com/docs/den0077/a) needed for shared memory.
+ */
+
+/**
+ * typedef ffa_endpoint_id16_t - Endpoint ID
+ *
+ * Current implementation only supports VM IDs. FF-A spec also support stream
+ * endpoint ids.
+ */
+typedef uint16_t ffa_endpoint_id16_t;
+
+/**
+ * struct ffa_cons_mrd - Constituent memory region descriptor
+ * @address:
+ * Start address of contiguous memory region. Must be 4K page aligned.
+ * @page_count:
+ * Number of 4K pages in region.
+ * @reserved_12_15:
+ * Reserve bytes 12-15 to pad struct size to 16 bytes.
+ */
+struct ffa_cons_mrd {
+ uint64_t address;
+ uint32_t page_count;
+ uint32_t reserved_12_15;
+};
+CASSERT(sizeof(struct ffa_cons_mrd) == 16, assert_ffa_cons_mrd_size_mismatch);
+
+/**
+ * struct ffa_comp_mrd - Composite memory region descriptor
+ * @total_page_count:
+ * Number of 4k pages in memory region. Must match sum of
+ * @address_range_array[].page_count.
+ * @address_range_count:
+ * Number of entries in @address_range_array.
+ * @reserved_8_15:
+ * Reserve bytes 8-15 to pad struct size to 16 byte alignment and
+ * make @address_range_array 16 byte aligned.
+ * @address_range_array:
+ * Array of &struct ffa_cons_mrd entries.
+ */
+struct ffa_comp_mrd {
+ uint32_t total_page_count;
+ uint32_t address_range_count;
+ uint64_t reserved_8_15;
+ struct ffa_cons_mrd address_range_array[];
+};
+CASSERT(sizeof(struct ffa_comp_mrd) == 16, assert_ffa_comp_mrd_size_mismatch);
+
+/**
+ * typedef ffa_mem_attr8_t - Memory region attributes v1.0.
+ * typedef ffa_mem_attr16_t - Memory region attributes v1.1.
+ *
+ * * @FFA_MEM_ATTR_NS_BIT:
+ * Memory security state.
+ * * @FFA_MEM_ATTR_DEVICE_NGNRNE:
+ * Device-nGnRnE.
+ * * @FFA_MEM_ATTR_DEVICE_NGNRE:
+ * Device-nGnRE.
+ * * @FFA_MEM_ATTR_DEVICE_NGRE:
+ * Device-nGRE.
+ * * @FFA_MEM_ATTR_DEVICE_GRE:
+ * Device-GRE.
+ * * @FFA_MEM_ATTR_NORMAL_MEMORY_UNCACHED
+ * Normal memory. Non-cacheable.
+ * * @FFA_MEM_ATTR_NORMAL_MEMORY_CACHED_WB
+ * Normal memory. Write-back cached.
+ * * @FFA_MEM_ATTR_NON_SHAREABLE
+ * Non-shareable. Combine with FFA_MEM_ATTR_NORMAL_MEMORY_*.
+ * * @FFA_MEM_ATTR_OUTER_SHAREABLE
+ * Outer Shareable. Combine with FFA_MEM_ATTR_NORMAL_MEMORY_*.
+ * * @FFA_MEM_ATTR_INNER_SHAREABLE
+ * Inner Shareable. Combine with FFA_MEM_ATTR_NORMAL_MEMORY_*.
+ */
+typedef uint8_t ffa_mem_attr8_t;
+typedef uint16_t ffa_mem_attr16_t;
+#define FFA_MEM_ATTR_NS_BIT (0x1U << 6)
+#define FFA_MEM_ATTR_DEVICE_NGNRNE ((1U << 4) | (0x0U << 2))
+#define FFA_MEM_ATTR_DEVICE_NGNRE ((1U << 4) | (0x1U << 2))
+#define FFA_MEM_ATTR_DEVICE_NGRE ((1U << 4) | (0x2U << 2))
+#define FFA_MEM_ATTR_DEVICE_GRE ((1U << 4) | (0x3U << 2))
+#define FFA_MEM_ATTR_NORMAL_MEMORY_UNCACHED ((2U << 4) | (0x1U << 2))
+#define FFA_MEM_ATTR_NORMAL_MEMORY_CACHED_WB ((2U << 4) | (0x3U << 2))
+#define FFA_MEM_ATTR_NON_SHAREABLE (0x0U << 0)
+#define FFA_MEM_ATTR_OUTER_SHAREABLE (0x2U << 0)
+#define FFA_MEM_ATTR_INNER_SHAREABLE (0x3U << 0)
+
+/**
+ * typedef ffa_mem_perm8_t - Memory access permissions
+ *
+ * * @FFA_MEM_ATTR_RO
+ * Request or specify read-only mapping.
+ * * @FFA_MEM_ATTR_RW
+ * Request or allow read-write mapping.
+ * * @FFA_MEM_PERM_NX
+ * Deny executable mapping.
+ * * @FFA_MEM_PERM_X
+ * Request executable mapping.
+ */
+typedef uint8_t ffa_mem_perm8_t;
+#define FFA_MEM_PERM_RO (1U << 0)
+#define FFA_MEM_PERM_RW (1U << 1)
+#define FFA_MEM_PERM_NX (1U << 2)
+#define FFA_MEM_PERM_X (1U << 3)
+
+/**
+ * typedef ffa_mem_flag8_t - Endpoint memory flags
+ *
+ * * @FFA_MEM_FLAG_NON_RETRIEVAL_BORROWER
+ * Non-retrieval Borrower. Memory region must not be or was not retrieved on
+ * behalf of this endpoint.
+ */
+typedef uint8_t ffa_mem_flag8_t;
+#define FFA_MEM_FLAG_NON_RETRIEVAL_BORROWER (1U << 0)
+
+/**
+ * typedef ffa_mtd_flag32_t - Memory transaction descriptor flags
+ *
+ * * @FFA_MTD_FLAG_ZERO_MEMORY
+ * Zero memory after unmapping from sender (must be 0 for share).
+ * * @FFA_MTD_FLAG_TIME_SLICING
+ * Not supported by this implementation.
+ * * @FFA_MTD_FLAG_ZERO_MEMORY_AFTER_RELINQUISH
+ * Zero memory after unmapping from borrowers (must be 0 for share).
+ * * @FFA_MTD_FLAG_TYPE_MASK
+ * Bit-mask to extract memory management transaction type from flags.
+ * * @FFA_MTD_FLAG_TYPE_SHARE_MEMORY
+ * Share memory transaction flag.
+ * Used by @SMC_FC_FFA_MEM_RETRIEVE_RESP to indicate that memory came from
+ * @SMC_FC_FFA_MEM_SHARE and by @SMC_FC_FFA_MEM_RETRIEVE_REQ to specify that
+ * it must have.
+ * * @FFA_MTD_FLAG_ADDRESS_RANGE_ALIGNMENT_HINT_MASK
+ * Not supported by this implementation.
+ */
+typedef uint32_t ffa_mtd_flag32_t;
+#define FFA_MTD_FLAG_ZERO_MEMORY (1U << 0)
+#define FFA_MTD_FLAG_TIME_SLICING (1U << 1)
+#define FFA_MTD_FLAG_ZERO_MEMORY_AFTER_RELINQUISH (1U << 2)
+#define FFA_MTD_FLAG_TYPE_MASK (3U << 3)
+#define FFA_MTD_FLAG_TYPE_SHARE_MEMORY (1U << 3)
+#define FFA_MTD_FLAG_TYPE_LEND_MEMORY (1U << 4)
+#define FFA_MTD_FLAG_ADDRESS_RANGE_ALIGNMENT_HINT_MASK (0x1FU << 5)
+
+/**
+ * struct ffa_mapd - Memory access permissions descriptor
+ * @endpoint_id:
+ * Endpoint id that @memory_access_permissions and @flags apply to.
+ * (&typedef ffa_endpoint_id16_t).
+ * @memory_access_permissions:
+ * FFA_MEM_PERM_* values or'ed together (&typedef ffa_mem_perm8_t).
+ * @flags:
+ * FFA_MEM_FLAG_* values or'ed together (&typedef ffa_mem_flag8_t).
+ */
+struct ffa_mapd {
+ ffa_endpoint_id16_t endpoint_id;
+ ffa_mem_perm8_t memory_access_permissions;
+ ffa_mem_flag8_t flags;
+};
+CASSERT(sizeof(struct ffa_mapd) == 4, assert_ffa_mapd_size_mismatch);
+
+/**
+ * struct ffa_emad_v1_0 - Endpoint memory access descriptor.
+ * @mapd: &struct ffa_mapd.
+ * @comp_mrd_offset:
+ * Offset of &struct ffa_comp_mrd from start of &struct ffa_mtd_v1_0.
+ * @reserved_8_15:
+ * Reserved bytes 8-15. Must be 0.
+ */
+struct ffa_emad_v1_0 {
+ struct ffa_mapd mapd;
+ uint32_t comp_mrd_offset;
+ uint64_t reserved_8_15;
+};
+CASSERT(sizeof(struct ffa_emad_v1_0) == 16, assert_ffa_emad_v1_0_size_mismatch);
+
+/**
+ * struct ffa_mtd_v1_0 - Memory transaction descriptor.
+ * @sender_id:
+ * Sender endpoint id.
+ * @memory_region_attributes:
+ * FFA_MEM_ATTR_* values or'ed together (&typedef ffa_mem_attr8_t).
+ * @reserved_3:
+ * Reserved bytes 3. Must be 0.
+ * @flags:
+ * FFA_MTD_FLAG_* values or'ed together (&typedef ffa_mtd_flag32_t).
+ * @handle:
+ * Id of shared memory object. Must be 0 for MEM_SHARE or MEM_LEND.
+ * @tag: Client allocated tag. Must match original value.
+ * @reserved_24_27:
+ * Reserved bytes 24-27. Must be 0.
+ * @emad_count:
+ * Number of entries in @emad.
+ * @emad:
+ * Endpoint memory access descriptor array (see @struct ffa_emad_v1_0).
+ */
+struct ffa_mtd_v1_0 {
+ ffa_endpoint_id16_t sender_id;
+ ffa_mem_attr8_t memory_region_attributes;
+ uint8_t reserved_3;
+ ffa_mtd_flag32_t flags;
+ uint64_t handle;
+ uint64_t tag;
+ uint32_t reserved_24_27;
+ uint32_t emad_count;
+ struct ffa_emad_v1_0 emad[];
+};
+CASSERT(sizeof(struct ffa_mtd_v1_0) == 32, assert_ffa_mtd_size_v1_0_mismatch);
+
+/**
+ * struct ffa_mtd - Memory transaction descriptor for FF-A v1.1.
+ * @sender_id:
+ * Sender endpoint id.
+ * @memory_region_attributes:
+ * FFA_MEM_ATTR_* values or'ed together (&typedef ffa_mem_attr16_t).
+ * @flags:
+ * FFA_MTD_FLAG_* values or'ed together (&typedef ffa_mtd_flag32_t).
+ * @handle:
+ * Id of shared memory object. Must be 0 for MEM_SHARE or MEM_LEND.
+ * @tag: Client allocated tag. Must match original value.
+ * @emad_size:
+ * Size of the emad descriptor.
+ * @emad_count:
+ * Number of entries in the emad array.
+ * @emad_offset:
+ * Offset from the beginning of the descriptor to the location of the
+ * memory access descriptor array (see @struct ffa_emad_v1_0).
+ * @reserved_36_39:
+ * Reserved bytes 36-39. Must be 0.
+ * @reserved_40_47:
+ * Reserved bytes 44-47. Must be 0.
+ */
+struct ffa_mtd {
+ ffa_endpoint_id16_t sender_id;
+ ffa_mem_attr16_t memory_region_attributes;
+ ffa_mtd_flag32_t flags;
+ uint64_t handle;
+ uint64_t tag;
+ uint32_t emad_size;
+ uint32_t emad_count;
+ uint32_t emad_offset;
+ uint32_t reserved_36_39;
+ uint64_t reserved_40_47;
+};
+CASSERT(sizeof(struct ffa_mtd) == 48, assert_ffa_mtd_size_mismatch);
+
+#endif /* EL3_SPMC_FFA_MEM_H */
diff --git a/include/services/el3_spmc_logical_sp.h b/include/services/el3_spmc_logical_sp.h
new file mode 100644
index 0000000..7ec9958
--- /dev/null
+++ b/include/services/el3_spmc_logical_sp.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef EL3_SP_H
+#define EL3_SP_H
+
+#include <common/bl_common.h>
+#include <lib/cassert.h>
+
+/*******************************************************************************
+ * Structure definition, typedefs & constants for the Logical SPs.
+ ******************************************************************************/
+
+typedef uint64_t (*direct_msg_handler)(uint32_t smc_fid, bool secure_origin,
+ uint64_t x1, uint64_t x2, uint64_t x3,
+ uint64_t x4, void *cookie, void *handle,
+ uint64_t flags);
+
+/* Prototype for logical partition initializing function. */
+typedef int32_t (*ffa_partition_init_t)(void);
+
+/* Logical Partition Descriptor. */
+struct el3_lp_desc {
+ ffa_partition_init_t init;
+ uint16_t sp_id;
+ uint32_t properties;
+ uint32_t uuid[4]; /* Little Endian. */
+ direct_msg_handler direct_req;
+ const char *debug_name;
+};
+
+/* Convenience macro to declare a logical partition descriptor. */
+#define DECLARE_LOGICAL_PARTITION(_name, _init, _sp_id, _uuid, _properties, \
+ _direct_req) \
+ static const struct el3_lp_desc __partition_desc_ ## _name \
+ __section("el3_lp_descs") __used = { \
+ .debug_name = #_name, \
+ .init = (_init), \
+ .sp_id = (_sp_id), \
+ .uuid = _uuid, \
+ .properties = (_properties), \
+ .direct_req = (_direct_req), \
+ }
+
+
+/*******************************************************************************
+ * Function & variable prototypes.
+ ******************************************************************************/
+int el3_sp_desc_validate(void);
+uintptr_t handle_el3_sp(uint32_t smc_fid, void *cookie, void *handle,
+ unsigned int flags);
+IMPORT_SYM(uintptr_t, __EL3_LP_DESCS_START__, EL3_LP_DESCS_START);
+IMPORT_SYM(uintptr_t, __EL3_LP_DESCS_END__, EL3_LP_DESCS_END);
+
+#define EL3_LP_DESCS_COUNT ((EL3_LP_DESCS_END - EL3_LP_DESCS_START) \
+ / sizeof(struct el3_lp_desc))
+
+#endif /* EL3_SP_H */
diff --git a/include/services/ffa_svc.h b/include/services/ffa_svc.h
new file mode 100644
index 0000000..da016fd
--- /dev/null
+++ b/include/services/ffa_svc.h
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FFA_SVC_H
+#define FFA_SVC_H
+
+#include <stdbool.h>
+
+#include <lib/smccc.h>
+#include <lib/utils_def.h>
+#include <tools_share/uuid.h>
+
+/* FFA error codes. */
+#define FFA_ERROR_NOT_SUPPORTED -1
+#define FFA_ERROR_INVALID_PARAMETER -2
+#define FFA_ERROR_NO_MEMORY -3
+#define FFA_ERROR_BUSY -4
+#define FFA_ERROR_INTERRUPTED -5
+#define FFA_ERROR_DENIED -6
+#define FFA_ERROR_RETRY -7
+
+/* The macros below are used to identify FFA calls from the SMC function ID */
+#define FFA_FNUM_MIN_VALUE U(0x60)
+#define FFA_FNUM_MAX_VALUE U(0x87)
+#define is_ffa_fid(fid) __extension__ ({ \
+ __typeof__(fid) _fid = (fid); \
+ ((GET_SMC_NUM(_fid) >= FFA_FNUM_MIN_VALUE) && \
+ (GET_SMC_NUM(_fid) <= FFA_FNUM_MAX_VALUE)); })
+
+/* FFA_VERSION helpers */
+#define FFA_VERSION_MAJOR U(1)
+#define FFA_VERSION_MAJOR_SHIFT 16
+#define FFA_VERSION_MAJOR_MASK U(0x7FFF)
+#define FFA_VERSION_MINOR U(1)
+#define FFA_VERSION_MINOR_SHIFT 0
+#define FFA_VERSION_MINOR_MASK U(0xFFFF)
+#define FFA_VERSION_BIT31_MASK U(0x1u << 31)
+#define FFA_VERSION_MASK U(0xFFFFFFFF)
+
+
+#define MAKE_FFA_VERSION(major, minor) \
+ ((((major) & FFA_VERSION_MAJOR_MASK) << FFA_VERSION_MAJOR_SHIFT) | \
+ (((minor) & FFA_VERSION_MINOR_MASK) << FFA_VERSION_MINOR_SHIFT))
+#define FFA_VERSION_COMPILED MAKE_FFA_VERSION(FFA_VERSION_MAJOR, \
+ FFA_VERSION_MINOR)
+
+/* FFA_MSG_SEND helpers */
+#define FFA_MSG_SEND_ATTRS_BLK_SHIFT U(0)
+#define FFA_MSG_SEND_ATTRS_BLK_MASK U(0x1)
+#define FFA_MSG_SEND_ATTRS_BLK U(0)
+#define FFA_MSG_SEND_ATTRS_BLK_NOT U(1)
+#define FFA_MSG_SEND_ATTRS(blk) \
+ (((blk) & FFA_MSG_SEND_ATTRS_BLK_MASK) \
+ << FFA_MSG_SEND_ATTRS_BLK_SHIFT)
+
+/* Defines for FF-A framework messages exchanged using direct messages. */
+#define FFA_FWK_MSG_BIT BIT(31)
+#define FFA_FWK_MSG_MASK 0xFF
+#define FFA_FWK_MSG_PSCI U(0x0)
+
+/* Defines for FF-A power management messages framework messages. */
+#define FFA_PM_MSG_WB_REQ U(0x1) /* Warm boot request. */
+#define FFA_PM_MSG_PM_RESP U(0x2) /* Response to PSCI or warmboot req. */
+
+/* FF-A warm boot types. */
+#define FFA_WB_TYPE_S2RAM 0x0
+#define FFA_WB_TYPE_NOTS2RAM 0x1
+
+/* Get FFA fastcall std FID from function number */
+#define FFA_FID(smc_cc, func_num) \
+ ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT) | \
+ ((smc_cc) << FUNCID_CC_SHIFT) | \
+ (OEN_STD_START << FUNCID_OEN_SHIFT) | \
+ ((func_num) << FUNCID_NUM_SHIFT))
+
+/* FFA function numbers */
+#define FFA_FNUM_ERROR U(0x60)
+#define FFA_FNUM_SUCCESS U(0x61)
+#define FFA_FNUM_INTERRUPT U(0x62)
+#define FFA_FNUM_VERSION U(0x63)
+#define FFA_FNUM_FEATURES U(0x64)
+#define FFA_FNUM_RX_RELEASE U(0x65)
+#define FFA_FNUM_RXTX_MAP U(0x66)
+#define FFA_FNUM_RXTX_UNMAP U(0x67)
+#define FFA_FNUM_PARTITION_INFO_GET U(0x68)
+#define FFA_FNUM_ID_GET U(0x69)
+#define FFA_FNUM_MSG_POLL U(0x6A) /* Legacy FF-A v1.0 */
+#define FFA_FNUM_MSG_WAIT U(0x6B)
+#define FFA_FNUM_MSG_YIELD U(0x6C)
+#define FFA_FNUM_MSG_RUN U(0x6D)
+#define FFA_FNUM_MSG_SEND U(0x6E) /* Legacy FF-A v1.0 */
+#define FFA_FNUM_MSG_SEND_DIRECT_REQ U(0x6F)
+#define FFA_FNUM_MSG_SEND_DIRECT_RESP U(0x70)
+#define FFA_FNUM_MEM_DONATE U(0x71)
+#define FFA_FNUM_MEM_LEND U(0x72)
+#define FFA_FNUM_MEM_SHARE U(0x73)
+#define FFA_FNUM_MEM_RETRIEVE_REQ U(0x74)
+#define FFA_FNUM_MEM_RETRIEVE_RESP U(0x75)
+#define FFA_FNUM_MEM_RELINQUISH U(0x76)
+#define FFA_FNUM_MEM_RECLAIM U(0x77)
+#define FFA_FNUM_MEM_FRAG_RX U(0x7A)
+#define FFA_FNUM_MEM_FRAG_TX U(0x7B)
+#define FFA_FNUM_NORMAL_WORLD_RESUME U(0x7C)
+
+/* FF-A v1.1 */
+#define FFA_FNUM_NOTIFICATION_BITMAP_CREATE U(0x7D)
+#define FFA_FNUM_NOTIFICATION_BITMAP_DESTROY U(0x7E)
+#define FFA_FNUM_NOTIFICATION_BIND U(0x7F)
+#define FFA_FNUM_NOTIFICATION_UNBIND U(0x80)
+#define FFA_FNUM_NOTIFICATION_SET U(0x81)
+#define FFA_FNUM_NOTIFICATION_GET U(0x82)
+#define FFA_FNUM_NOTIFICATION_INFO_GET U(0x83)
+#define FFA_FNUM_RX_ACQUIRE U(0x84)
+#define FFA_FNUM_SPM_ID_GET U(0x85)
+#define FFA_FNUM_MSG_SEND2 U(0x86)
+#define FFA_FNUM_SECONDARY_EP_REGISTER U(0x87)
+
+/* FFA SMC32 FIDs */
+#define FFA_ERROR FFA_FID(SMC_32, FFA_FNUM_ERROR)
+#define FFA_SUCCESS_SMC32 FFA_FID(SMC_32, FFA_FNUM_SUCCESS)
+#define FFA_INTERRUPT FFA_FID(SMC_32, FFA_FNUM_INTERRUPT)
+#define FFA_VERSION FFA_FID(SMC_32, FFA_FNUM_VERSION)
+#define FFA_FEATURES FFA_FID(SMC_32, FFA_FNUM_FEATURES)
+#define FFA_RX_RELEASE FFA_FID(SMC_32, FFA_FNUM_RX_RELEASE)
+#define FFA_RX_ACQUIRE FFA_FID(SMC_32, FFA_FNUM_RX_ACQUIRE)
+#define FFA_RXTX_MAP_SMC32 FFA_FID(SMC_32, FFA_FNUM_RXTX_MAP)
+#define FFA_RXTX_UNMAP FFA_FID(SMC_32, FFA_FNUM_RXTX_UNMAP)
+#define FFA_PARTITION_INFO_GET FFA_FID(SMC_32, FFA_FNUM_PARTITION_INFO_GET)
+#define FFA_ID_GET FFA_FID(SMC_32, FFA_FNUM_ID_GET)
+#define FFA_MSG_POLL FFA_FID(SMC_32, FFA_FNUM_MSG_POLL)
+#define FFA_MSG_WAIT FFA_FID(SMC_32, FFA_FNUM_MSG_WAIT)
+#define FFA_MSG_YIELD FFA_FID(SMC_32, FFA_FNUM_MSG_YIELD)
+#define FFA_MSG_RUN FFA_FID(SMC_32, FFA_FNUM_MSG_RUN)
+#define FFA_MSG_SEND FFA_FID(SMC_32, FFA_FNUM_MSG_SEND)
+#define FFA_MSG_SEND2 FFA_FID(SMC_32, FFA_FNUM_MSG_SEND2)
+#define FFA_MSG_SEND_DIRECT_REQ_SMC32 \
+ FFA_FID(SMC_32, FFA_FNUM_MSG_SEND_DIRECT_REQ)
+#define FFA_MSG_SEND_DIRECT_RESP_SMC32 \
+ FFA_FID(SMC_32, FFA_FNUM_MSG_SEND_DIRECT_RESP)
+#define FFA_MEM_DONATE_SMC32 FFA_FID(SMC_32, FFA_FNUM_MEM_DONATE)
+#define FFA_MEM_LEND_SMC32 FFA_FID(SMC_32, FFA_FNUM_MEM_LEND)
+#define FFA_MEM_SHARE_SMC32 FFA_FID(SMC_32, FFA_FNUM_MEM_SHARE)
+#define FFA_MEM_RETRIEVE_REQ_SMC32 \
+ FFA_FID(SMC_32, FFA_FNUM_MEM_RETRIEVE_REQ)
+#define FFA_MEM_RETRIEVE_RESP FFA_FID(SMC_32, FFA_FNUM_MEM_RETRIEVE_RESP)
+#define FFA_MEM_RELINQUISH FFA_FID(SMC_32, FFA_FNUM_MEM_RELINQUISH)
+#define FFA_MEM_RECLAIM FFA_FID(SMC_32, FFA_FNUM_MEM_RECLAIM)
+#define FFA_NOTIFICATION_BITMAP_CREATE \
+ FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_BITMAP_CREATE)
+#define FFA_NOTIFICATION_BITMAP_DESTROY \
+ FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_BITMAP_DESTROY)
+#define FFA_NOTIFICATION_BIND FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_BIND)
+#define FFA_NOTIFICATION_UNBIND FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_UNBIND)
+#define FFA_NOTIFICATION_SET FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_SET)
+#define FFA_NOTIFICATION_GET FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_GET)
+#define FFA_NOTIFICATION_INFO_GET \
+ FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_INFO_GET)
+#define FFA_MEM_FRAG_RX FFA_FID(SMC_32, FFA_FNUM_MEM_FRAG_RX)
+#define FFA_MEM_FRAG_TX FFA_FID(SMC_32, FFA_FNUM_MEM_FRAG_TX)
+#define FFA_SPM_ID_GET FFA_FID(SMC_32, FFA_FNUM_SPM_ID_GET)
+#define FFA_NORMAL_WORLD_RESUME FFA_FID(SMC_32, FFA_FNUM_NORMAL_WORLD_RESUME)
+
+/* FFA SMC64 FIDs */
+#define FFA_ERROR_SMC64 FFA_FID(SMC_64, FFA_FNUM_ERROR)
+#define FFA_SUCCESS_SMC64 FFA_FID(SMC_64, FFA_FNUM_SUCCESS)
+#define FFA_RXTX_MAP_SMC64 FFA_FID(SMC_64, FFA_FNUM_RXTX_MAP)
+#define FFA_MSG_SEND_DIRECT_REQ_SMC64 \
+ FFA_FID(SMC_64, FFA_FNUM_MSG_SEND_DIRECT_REQ)
+#define FFA_MSG_SEND_DIRECT_RESP_SMC64 \
+ FFA_FID(SMC_64, FFA_FNUM_MSG_SEND_DIRECT_RESP)
+#define FFA_MEM_DONATE_SMC64 FFA_FID(SMC_64, FFA_FNUM_MEM_DONATE)
+#define FFA_MEM_LEND_SMC64 FFA_FID(SMC_64, FFA_FNUM_MEM_LEND)
+#define FFA_MEM_SHARE_SMC64 FFA_FID(SMC_64, FFA_FNUM_MEM_SHARE)
+#define FFA_MEM_RETRIEVE_REQ_SMC64 \
+ FFA_FID(SMC_64, FFA_FNUM_MEM_RETRIEVE_REQ)
+#define FFA_SECONDARY_EP_REGISTER_SMC64 \
+ FFA_FID(SMC_64, FFA_FNUM_SECONDARY_EP_REGISTER)
+#define FFA_NOTIFICATION_INFO_GET_SMC64 \
+ FFA_FID(SMC_64, FFA_FNUM_NOTIFICATION_INFO_GET)
+
+/*
+ * FF-A partition properties values.
+ */
+#define FFA_PARTITION_DIRECT_REQ_RECV U(1 << 0)
+#define FFA_PARTITION_DIRECT_REQ_SEND U(1 << 1)
+#define FFA_PARTITION_INDIRECT_MSG U(1 << 2)
+
+/*
+ * Reserve a special value for traffic targeted to the Hypervisor or SPM.
+ */
+#define FFA_TARGET_INFO_MBZ U(0x0)
+
+/*
+ * Reserve a special value for MBZ parameters.
+ */
+#define FFA_PARAM_MBZ U(0x0)
+
+/*
+ * Maximum FF-A endpoint id value
+ */
+#define FFA_ENDPOINT_ID_MAX U(1 << 16)
+
+/*
+ * Reserve endpoint id for the SPMD.
+ */
+#define SPMD_DIRECT_MSG_ENDPOINT_ID U(FFA_ENDPOINT_ID_MAX - 1)
+
+/* Mask and shift to check valid secure FF-A Endpoint ID. */
+#define SPMC_SECURE_ID_MASK U(1)
+#define SPMC_SECURE_ID_SHIFT U(15)
+
+/*
+ * Partition Count Flag in FFA_PARTITION_INFO_GET.
+ */
+#define FFA_PARTITION_INFO_GET_COUNT_FLAG_MASK U(1 << 0)
+
+/*
+ * Mask for source and destination endpoint id in
+ * a direct message request/response.
+ */
+#define FFA_DIRECT_MSG_ENDPOINT_ID_MASK U(0xffff)
+
+/*
+ * Bit shift for destination endpoint id in a direct message request/response.
+ */
+#define FFA_DIRECT_MSG_DESTINATION_SHIFT U(0)
+
+/*
+ * Bit shift for source endpoint id in a direct message request/response.
+ */
+#define FFA_DIRECT_MSG_SOURCE_SHIFT U(16)
+
+/******************************************************************************
+ * ffa_endpoint_destination
+ *****************************************************************************/
+static inline uint16_t ffa_endpoint_destination(unsigned int ep)
+{
+ return (ep >> FFA_DIRECT_MSG_DESTINATION_SHIFT) &
+ FFA_DIRECT_MSG_ENDPOINT_ID_MASK;
+}
+
+/******************************************************************************
+ * ffa_endpoint_source
+ *****************************************************************************/
+static inline uint16_t ffa_endpoint_source(unsigned int ep)
+{
+ return (ep >> FFA_DIRECT_MSG_SOURCE_SHIFT) &
+ FFA_DIRECT_MSG_ENDPOINT_ID_MASK;
+}
+
+/******************************************************************************
+ * FF-A helper functions to determine partition ID world.
+ *****************************************************************************/
+
+/*
+ * Determine if provided ID is in the secure world.
+ */
+static inline bool ffa_is_secure_world_id(uint16_t id)
+{
+ return ((id >> SPMC_SECURE_ID_SHIFT) & SPMC_SECURE_ID_MASK) == 1;
+}
+
+/*
+ * Determine if provided ID is in the normal world.
+ */
+static inline bool ffa_is_normal_world_id(uint16_t id)
+{
+ return !ffa_is_secure_world_id(id);
+}
+
+
+/******************************************************************************
+ * Boot information protocol as per the FF-A v1.1 spec.
+ *****************************************************************************/
+#define FFA_INIT_DESC_SIGNATURE 0x00000FFA
+
+/* Boot information type. */
+#define FFA_BOOT_INFO_TYPE_STD U(0x0)
+#define FFA_BOOT_INFO_TYPE_IMPL U(0x1)
+
+#define FFA_BOOT_INFO_TYPE_MASK U(0x1)
+#define FFA_BOOT_INFO_TYPE_SHIFT U(0x7)
+#define FFA_BOOT_INFO_TYPE(type) \
+ (((type) & FFA_BOOT_INFO_TYPE_MASK) \
+ << FFA_BOOT_INFO_TYPE_SHIFT)
+
+/* Boot information identifier. */
+#define FFA_BOOT_INFO_TYPE_ID_FDT U(0x0)
+#define FFA_BOOT_INFO_TYPE_ID_HOB U(0x1)
+
+#define FFA_BOOT_INFO_TYPE_ID_MASK U(0x3F)
+#define FFA_BOOT_INFO_TYPE_ID_SHIFT U(0x0)
+#define FFA_BOOT_INFO_TYPE_ID(type) \
+ (((type) & FFA_BOOT_INFO_TYPE_ID_MASK) \
+ << FFA_BOOT_INFO_TYPE_ID_SHIFT)
+
+/* Format of Flags Name field. */
+#define FFA_BOOT_INFO_FLAG_NAME_STRING U(0x0)
+#define FFA_BOOT_INFO_FLAG_NAME_UUID U(0x1)
+
+#define FFA_BOOT_INFO_FLAG_NAME_MASK U(0x3)
+#define FFA_BOOT_INFO_FLAG_NAME_SHIFT U(0x0)
+#define FFA_BOOT_INFO_FLAG_NAME(type) \
+ (((type) & FFA_BOOT_INFO_FLAG_NAME_MASK)\
+ << FFA_BOOT_INFO_FLAG_NAME_SHIFT)
+
+/* Format of Flags Contents field. */
+#define FFA_BOOT_INFO_FLAG_CONTENT_ADR U(0x0)
+#define FFA_BOOT_INFO_FLAG_CONTENT_VAL U(0x1)
+
+#define FFA_BOOT_INFO_FLAG_CONTENT_MASK U(0x1)
+#define FFA_BOOT_INFO_FLAG_CONTENT_SHIFT U(0x2)
+#define FFA_BOOT_INFO_FLAG_CONTENT(content) \
+ (((content) & FFA_BOOT_INFO_FLAG_CONTENT_MASK) \
+ << FFA_BOOT_INFO_FLAG_CONTENT_SHIFT)
+
+/* Boot information descriptor. */
+struct ffa_boot_info_desc {
+ uint8_t name[16];
+ uint8_t type;
+ uint8_t reserved;
+ uint16_t flags;
+ uint32_t size_boot_info;
+ uint64_t content;
+};
+
+/* Boot information header. */
+struct ffa_boot_info_header {
+ uint32_t signature; /* 0xFFA */
+ uint32_t version;
+ uint32_t size_boot_info_blob;
+ uint32_t size_boot_info_desc;
+ uint32_t count_boot_info_desc;
+ uint32_t offset_boot_info_desc;
+ uint64_t reserved;
+};
+
+#endif /* FFA_SVC_H */
diff --git a/include/services/pci_svc.h b/include/services/pci_svc.h
new file mode 100644
index 0000000..664a742
--- /dev/null
+++ b/include/services/pci_svc.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PCI_SVC_H
+#define PCI_SVC_H
+
+#include <lib/utils_def.h>
+
+/* SMCCC PCI platform functions */
+#define SMC_PCI_VERSION U(0x84000130)
+#define SMC_PCI_FEATURES U(0x84000131)
+#define SMC_PCI_READ U(0x84000132)
+#define SMC_PCI_WRITE U(0x84000133)
+#define SMC_PCI_SEG_INFO U(0x84000134)
+
+#define is_pci_fid(_fid) (((_fid) >= SMC_PCI_VERSION) && \
+ ((_fid) <= SMC_PCI_SEG_INFO))
+
+uint64_t pci_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);
+
+#define PCI_ADDR_FUN(dev) ((dev) & U(0x7))
+#define PCI_ADDR_DEV(dev) (((dev) >> U(3)) & U(0x001F))
+#define PCI_ADDR_BUS(dev) (((dev) >> U(8)) & U(0x00FF))
+#define PCI_ADDR_SEG(dev) (((dev) >> U(16)) & U(0xFFFF))
+#define PCI_OFFSET_MASK U(0xFFF)
+typedef union {
+ struct {
+ uint16_t minor;
+ uint16_t major;
+ } __packed;
+ uint32_t val;
+} pcie_version;
+
+/*
+ * platforms are responsible for providing implementations of these
+ * three functions in a manner which conforms to the Arm PCI Configuration
+ * Space Access Firmware Interface (DEN0115) and the PCIe specification's
+ * sections on PCI configuration access. See the rpi4_pci_svc.c example.
+ */
+uint32_t pci_read_config(uint32_t addr, uint32_t off, uint32_t sz, uint32_t *val);
+uint32_t pci_write_config(uint32_t addr, uint32_t off, uint32_t sz, uint32_t val);
+uint32_t pci_get_bus_for_seg(uint32_t seg, uint32_t *bus_range, uint32_t *nseg);
+
+/* Return codes for Arm PCI Config Space Access Firmware SMC calls */
+#define SMC_PCI_CALL_SUCCESS U(0)
+#define SMC_PCI_CALL_NOT_SUPPORTED -1
+#define SMC_PCI_CALL_INVAL_PARAM -2
+#define SMC_PCI_CALL_NOT_IMPL -3
+
+#define SMC_PCI_SZ_8BIT U(1)
+#define SMC_PCI_SZ_16BIT U(2)
+#define SMC_PCI_SZ_32BIT U(4)
+
+#endif /* PCI_SVC_H */
diff --git a/include/services/rmm_core_manifest.h b/include/services/rmm_core_manifest.h
new file mode 100644
index 0000000..2f25858
--- /dev/null
+++ b/include/services/rmm_core_manifest.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RMM_CORE_MANIFEST_H
+#define RMM_CORE_MANIFEST_H
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <lib/cassert.h>
+
+#define RMMD_MANIFEST_VERSION_MAJOR U(0)
+#define RMMD_MANIFEST_VERSION_MINOR U(1)
+
+/*
+ * Manifest version encoding:
+ * - Bit[31] RES0
+ * - Bits [30:16] Major version
+ * - Bits [15:0] Minor version
+ */
+#define _RMMD_MANIFEST_VERSION(_major, _minor) \
+ ((((_major) & 0x7FFF) << 16) | ((_minor) & 0xFFFF))
+
+#define RMMD_MANIFEST_VERSION _RMMD_MANIFEST_VERSION( \
+ RMMD_MANIFEST_VERSION_MAJOR, \
+ RMMD_MANIFEST_VERSION_MINOR)
+
+#define RMMD_GET_MANIFEST_VERSION_MAJOR(_version) \
+ ((_version >> 16) & 0x7FFF)
+
+#define RMMD_GET_MANIFEST_VERSION_MINOR(_version) \
+ (_version & 0xFFFF)
+
+/* Boot manifest core structure as per v0.1 */
+typedef struct rmm_manifest {
+ uint32_t version; /* Manifest version */
+ uintptr_t plat_data; /* Manifest platform data */
+} rmm_manifest_t;
+
+CASSERT(offsetof(rmm_manifest_t, version) == 0,
+ rmm_manifest_t_version_unaligned);
+CASSERT(offsetof(rmm_manifest_t, plat_data) == 8,
+ rmm_manifest_t_plat_data_unaligned);
+
+#endif /* RMM_CORE_MANIFEST_H */
diff --git a/include/services/rmmd_svc.h b/include/services/rmmd_svc.h
new file mode 100644
index 0000000..de7181c
--- /dev/null
+++ b/include/services/rmmd_svc.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RMMD_SVC_H
+#define RMMD_SVC_H
+
+#include <lib/smccc.h>
+#include <lib/utils_def.h>
+
+/* STD calls FNUM Min/Max ranges */
+#define RMI_FNUM_MIN_VALUE U(0x150)
+#define RMI_FNUM_MAX_VALUE U(0x18F)
+
+/* Construct RMI fastcall std FID from offset */
+#define SMC64_RMI_FID(_offset) \
+ ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT) | \
+ (SMC_64 << FUNCID_CC_SHIFT) | \
+ (OEN_STD_START << FUNCID_OEN_SHIFT) | \
+ (((RMI_FNUM_MIN_VALUE + (_offset)) & FUNCID_NUM_MASK) \
+ << FUNCID_NUM_SHIFT))
+
+#define is_rmi_fid(fid) __extension__ ({ \
+ __typeof__(fid) _fid = (fid); \
+ ((GET_SMC_NUM(_fid) >= RMI_FNUM_MIN_VALUE) && \
+ (GET_SMC_NUM(_fid) <= RMI_FNUM_MAX_VALUE) && \
+ (GET_SMC_TYPE(_fid) == SMC_TYPE_FAST) && \
+ (GET_SMC_CC(_fid) == SMC_64) && \
+ (GET_SMC_OEN(_fid) == OEN_STD_START) && \
+ ((_fid & 0x00FE0000) == 0U)); })
+
+/*
+ * RMI_FNUM_REQ_COMPLETE is the only function in the RMI range that originates
+ * from the Realm world and is handled by the RMMD. The RMI functions are
+ * always invoked by the Normal world, forwarded by RMMD and handled by the
+ * RMM.
+ */
+ /* 0x18F */
+#define RMM_RMI_REQ_COMPLETE SMC64_RMI_FID(U(0x3F))
+
+/* RMM_BOOT_COMPLETE arg0 error codes */
+#define E_RMM_BOOT_SUCCESS (0)
+#define E_RMM_BOOT_UNKNOWN (-1)
+#define E_RMM_BOOT_VERSION_MISMATCH (-2)
+#define E_RMM_BOOT_CPUS_OUT_OF_RANGE (-3)
+#define E_RMM_BOOT_CPU_ID_OUT_OF_RANGE (-4)
+#define E_RMM_BOOT_INVALID_SHARED_BUFFER (-5)
+#define E_RMM_BOOT_MANIFEST_VERSION_NOT_SUPPORTED (-6)
+#define E_RMM_BOOT_MANIFEST_DATA_ERROR (-7)
+
+/* The SMC in the range 0x8400 0191 - 0x8400 01AF are reserved for RSIs.*/
+
+/*
+ * EL3 - RMM SMCs used for requesting RMMD services. These SMCs originate in Realm
+ * world and return to Realm world.
+ *
+ * These are allocated from 0x8400 01B0 - 0x8400 01CF in the RMM Service range.
+ */
+#define RMMD_EL3_FNUM_MIN_VALUE U(0x1B0)
+#define RMMD_EL3_FNUM_MAX_VALUE U(0x1CF)
+
+/* Construct RMM_EL3 fastcall std FID from offset */
+#define SMC64_RMMD_EL3_FID(_offset) \
+ ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT) | \
+ (SMC_64 << FUNCID_CC_SHIFT) | \
+ (OEN_STD_START << FUNCID_OEN_SHIFT) | \
+ (((RMMD_EL3_FNUM_MIN_VALUE + (_offset)) & FUNCID_NUM_MASK) \
+ << FUNCID_NUM_SHIFT))
+
+/* The macros below are used to identify GTSI calls from the SMC function ID */
+#define is_rmmd_el3_fid(fid) __extension__ ({ \
+ __typeof__(fid) _fid = (fid); \
+ ((GET_SMC_NUM(_fid) >= RMMD_EL3_FNUM_MIN_VALUE) &&\
+ (GET_SMC_NUM(_fid) <= RMMD_EL3_FNUM_MAX_VALUE) &&\
+ (GET_SMC_TYPE(_fid) == SMC_TYPE_FAST) && \
+ (GET_SMC_CC(_fid) == SMC_64) && \
+ (GET_SMC_OEN(_fid) == OEN_STD_START) && \
+ ((_fid & 0x00FE0000) == 0U)); })
+
+ /* 0x1B0 - 0x1B1 */
+#define RMM_GTSI_DELEGATE SMC64_RMMD_EL3_FID(U(0))
+#define RMM_GTSI_UNDELEGATE SMC64_RMMD_EL3_FID(U(1))
+
+/* Return error codes from RMM-EL3 SMCs */
+#define E_RMM_OK 0
+#define E_RMM_UNK -1
+#define E_RMM_BAD_ADDR -2
+#define E_RMM_BAD_PAS -3
+#define E_RMM_NOMEM -4
+#define E_RMM_INVAL -5
+
+/* Acceptable SHA sizes for Challenge object */
+#define SHA256_DIGEST_SIZE 32U
+#define SHA384_DIGEST_SIZE 48U
+#define SHA512_DIGEST_SIZE 64U
+
+/*
+ * Retrieve Realm attestation key from EL3. Only P-384 ECC curve key is
+ * supported. The arguments to this SMC are :
+ * arg0 - Function ID.
+ * arg1 - Realm attestation key buffer Physical address.
+ * arg2 - Realm attestation key buffer size (in bytes).
+ * arg3 - The type of the elliptic curve to which the requested
+ * attestation key belongs to. The value should be one of the
+ * defined curve types.
+ * The return arguments are :
+ * ret0 - Status / error.
+ * ret1 - Size of the realm attestation key if successful.
+ */
+ /* 0x1B2 */
+#define RMM_ATTEST_GET_REALM_KEY SMC64_RMMD_EL3_FID(U(2))
+
+/*
+ * Retrieve Platform token from EL3.
+ * The arguments to this SMC are :
+ * arg0 - Function ID.
+ * arg1 - Platform attestation token buffer Physical address. (The challenge
+ * object is passed in this buffer.)
+ * arg2 - Platform attestation token buffer size (in bytes).
+ * arg3 - Challenge object size (in bytes). It has to be one of the defined
+ * SHA hash sizes.
+ * The return arguments are :
+ * ret0 - Status / error.
+ * ret1 - Size of the platform token if successful.
+ */
+ /* 0x1B3 */
+#define RMM_ATTEST_GET_PLAT_TOKEN SMC64_RMMD_EL3_FID(U(3))
+
+/* ECC Curve types for attest key generation */
+#define ATTEST_KEY_CURVE_ECC_SECP384R1 0
+
+/*
+ * RMM_BOOT_COMPLETE originates on RMM when the boot finishes (either cold
+ * or warm boot). This is handled by the RMM-EL3 interface SMC handler.
+ *
+ * RMM_BOOT_COMPLETE FID is located at the end of the available range.
+ */
+ /* 0x1CF */
+#define RMM_BOOT_COMPLETE SMC64_RMMD_EL3_FID(U(0x1F))
+
+/*
+ * The major version number of the RMM Boot Interface implementation.
+ * Increase this whenever the semantics of the boot arguments change making it
+ * backwards incompatible.
+ */
+#define RMM_EL3_IFC_VERSION_MAJOR (U(0))
+
+/*
+ * The minor version number of the RMM Boot Interface implementation.
+ * Increase this when a bug is fixed, or a feature is added without
+ * breaking compatibility.
+ */
+#define RMM_EL3_IFC_VERSION_MINOR (U(1))
+
+#define RMM_EL3_INTERFACE_VERSION \
+ (((RMM_EL3_IFC_VERSION_MAJOR << 16) & 0x7FFFF) | \
+ RMM_EL3_IFC_VERSION_MINOR)
+
+#define RMM_EL3_IFC_VERSION_GET_MAJOR(_version) (((_version) >> 16) \
+ & 0x7FFF)
+#define RMM_EL3_IFC_VERSION_GET_MAJOR_MINOR(_version) ((_version) & 0xFFFF)
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+
+int rmmd_setup(void);
+uint64_t rmmd_rmi_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 rmmd_rmm_el3_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 /* __ASSEMBLER__ */
+#endif /* RMMD_SVC_H */
diff --git a/include/services/sdei.h b/include/services/sdei.h
new file mode 100644
index 0000000..c12a182
--- /dev/null
+++ b/include/services/sdei.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SDEI_H
+#define SDEI_H
+
+#include <lib/spinlock.h>
+#include <lib/utils_def.h>
+#include <services/sdei_flags.h>
+
+/* 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
+
+/* 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);
+
+/* Public API to check how many SDEI events are registered. */
+int sdei_get_registered_event_count(void);
+
+#endif /* SDEI_H */
diff --git a/include/services/sdei_flags.h b/include/services/sdei_flags.h
new file mode 100644
index 0000000..d1308f8
--- /dev/null
+++ b/include/services/sdei_flags.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SDEI_FLAGS_H
+#define SDEI_FLAGS_H
+
+#include <lib/utils_def.h>
+
+/* 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_)
+
+#endif /* SDEI_FLAGS_H */
diff --git a/include/services/spm_core_manifest.h b/include/services/spm_core_manifest.h
new file mode 100644
index 0000000..453b21c
--- /dev/null
+++ b/include/services/spm_core_manifest.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPM_CORE_MANIFEST_H
+#define SPM_CORE_MANIFEST_H
+
+#include <stdint.h>
+
+/*******************************************************************************
+ * Attribute Section
+ ******************************************************************************/
+
+typedef struct spm_core_manifest_sect_attribute {
+ /*
+ * FFA version (mandatory).
+ */
+ uint32_t major_version;
+ uint32_t minor_version;
+
+ /*
+ * Run-Time Execution state (optional):
+ * - 0: AArch64 (default)
+ * - 1: AArch32
+ */
+ uint32_t exec_state;
+
+ /*
+ * Address of binary image containing SPM Core (optional).
+ */
+ uint64_t load_address;
+
+ /*
+ * Offset from the base of the partition's binary image to the entry
+ * point of the partition (optional).
+ */
+ uint64_t entrypoint;
+
+ /*
+ * Size of binary image containing SPM Core in bytes (mandatory).
+ */
+ uint32_t binary_size;
+
+ /*
+ * ID of the SPMC (mandatory)
+ */
+ uint16_t spmc_id;
+
+} spmc_manifest_attribute_t;
+
+#endif /* SPM_CORE_MANIFEST_H */
diff --git a/include/services/spm_mm_partition.h b/include/services/spm_mm_partition.h
new file mode 100644
index 0000000..ad5ceef
--- /dev/null
+++ b/include/services/spm_mm_partition.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPM_MM_PARTITION_H
+#define SPM_MM_PARTITION_H
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+/*
+ * Flags used by the spm_mm_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 spm_mm_mp_info {
+ uint64_t mpidr;
+ uint32_t linear_id;
+ uint32_t flags;
+} spm_mm_mp_info_t;
+
+typedef struct spm_mm_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;
+ spm_mm_mp_info_t *mp_info;
+} spm_mm_boot_info_t;
+
+#endif /* SPM_MM_PARTITION_H */
diff --git a/include/services/spm_mm_svc.h b/include/services/spm_mm_svc.h
new file mode 100644
index 0000000..3148beb
--- /dev/null
+++ b/include/services/spm_mm_svc.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPM_MM_SVC_H
+#define SPM_MM_SVC_H
+
+#include <lib/utils_def.h>
+
+/*
+ * The MM_VERSION_XXX definitions are used when responding to the
+ * MM_VERSION_AARCH32 service request. The version returned is different between
+ * this request and the SPM_MM_VERSION_AARCH32 request - both have been retained
+ * for compatibility.
+ */
+#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)
+
+#define SPM_MM_VERSION_MAJOR U(0)
+#define SPM_MM_VERSION_MAJOR_SHIFT 16
+#define SPM_MM_VERSION_MAJOR_MASK U(0x7FFF)
+#define SPM_MM_VERSION_MINOR U(1)
+#define SPM_MM_VERSION_MINOR_SHIFT 0
+#define SPM_MM_VERSION_MINOR_MASK U(0xFFFF)
+#define SPM_MM_VERSION_FORM(major, minor) ((major << \
+ SPM_MM_VERSION_MAJOR_SHIFT) | \
+ (minor))
+#define SPM_MM_VERSION_COMPILED SPM_MM_VERSION_FORM(SPM_MM_VERSION_MAJOR, \
+ SPM_MM_VERSION_MINOR)
+
+/* These macros are used to identify SPM-MM calls using the SMC function ID */
+#define SPM_MM_FID_MASK U(0xffff)
+#define SPM_MM_FID_MIN_VALUE U(0x40)
+#define SPM_MM_FID_MAX_VALUE U(0x7f)
+#define is_spm_mm_fid(_fid) \
+ ((((_fid) & SPM_MM_FID_MASK) >= SPM_MM_FID_MIN_VALUE) && \
+ (((_fid) & SPM_MM_FID_MASK) <= SPM_MM_FID_MAX_VALUE))
+
+/*
+ * 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)
+
+/*
+ * 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_MM_VERSION_AARCH32 U(0x84000060)
+#define MM_SP_EVENT_COMPLETE_AARCH64 U(0xC4000061)
+#define MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 U(0xC4000064)
+#define MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 U(0xC4000065)
+
+/*
+ * Macros used by MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64.
+ */
+
+#define MM_SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS U(0)
+#define MM_SP_MEMORY_ATTRIBUTES_ACCESS_RW U(1)
+/* Value U(2) is reserved. */
+#define MM_SP_MEMORY_ATTRIBUTES_ACCESS_RO U(3)
+#define MM_SP_MEMORY_ATTRIBUTES_ACCESS_MASK U(3)
+#define MM_SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT 0
+
+#define MM_SP_MEMORY_ATTRIBUTES_EXEC (U(0) << 2)
+#define MM_SP_MEMORY_ATTRIBUTES_NON_EXEC (U(1) << 2)
+
+
+/* SPM error codes. */
+#define SPM_MM_SUCCESS 0
+#define SPM_MM_NOT_SUPPORTED -1
+#define SPM_MM_INVALID_PARAMETER -2
+#define SPM_MM_DENIED -3
+#define SPM_MM_NO_MEMORY -5
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+int32_t spm_mm_setup(void);
+
+uint64_t spm_mm_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_mm_sp_call(uint32_t smc_fid,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* SPM_MM_SVC_H */
diff --git a/include/services/spmc_svc.h b/include/services/spmc_svc.h
new file mode 100644
index 0000000..8ee61e9
--- /dev/null
+++ b/include/services/spmc_svc.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPMC_SVC_H
+#define SPMC_SVC_H
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+#include <services/ffa_svc.h>
+#include <services/spm_core_manifest.h>
+
+int spmc_setup(void);
+void spmc_populate_attrs(spmc_manifest_attribute_t *spmc_attrs);
+void *spmc_get_config_addr(void);
+
+void spmc_set_config_addr(uintptr_t soc_fw_config);
+
+uint64_t spmc_smc_handler(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags);
+
+static inline bool is_spmc_at_el3(void)
+{
+ return SPMC_AT_EL3 == 1;
+}
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* SPMC_SVC_H */
diff --git a/include/services/spmd_svc.h b/include/services/spmd_svc.h
new file mode 100644
index 0000000..29dfdad
--- /dev/null
+++ b/include/services/spmd_svc.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPMD_SVC_H
+#define SPMD_SVC_H
+
+#ifndef __ASSEMBLER__
+#include <services/ffa_svc.h>
+#include <stdint.h>
+
+int spmd_setup(void);
+uint64_t spmd_ffa_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 spmd_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 spmd_smc_switch_state(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *handle);
+#endif /* __ASSEMBLER__ */
+
+#endif /* SPMD_SVC_H */
diff --git a/include/services/std_svc.h b/include/services/std_svc.h
new file mode 100644
index 0000000..b0614fb
--- /dev/null
+++ b/include/services/std_svc.h
@@ -0,0 +1,30 @@
+/*
+ * 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 */
diff --git a/include/services/trng_svc.h b/include/services/trng_svc.h
new file mode 100644
index 0000000..92417c2
--- /dev/null
+++ b/include/services/trng_svc.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TRNG_SVC_H
+#define TRNG_SVC_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <lib/smccc.h>
+
+/* SMC function IDs for TRNG queries */
+#define ARM_TRNG_VERSION U(0x84000050)
+#define ARM_TRNG_FEATURES U(0x84000051)
+#define ARM_TRNG_GET_UUID U(0x84000052)
+#define ARM_TRNG_RND32 U(0x84000053)
+#define ARM_TRNG_RND64 U(0xC4000053)
+
+/* TRNG version numbers */
+#define TRNG_VERSION_MAJOR (0x1)
+#define TRNG_VERSION_MINOR (0x0)
+
+/* TRNG Error Numbers */
+#define TRNG_E_SUCCESS (0)
+#define TRNG_E_NOT_SUPPORTED (-1)
+#define TRNG_E_INVALID_PARAMS (-2)
+#define TRNG_E_NO_ENTROPY (-3)
+#define TRNG_E_NOT_IMPLEMENTED (-4)
+
+/* TRNG Entropy Bit Numbers */
+#define TRNG_RND32_ENTROPY_MAXBITS (96U)
+#define TRNG_RND64_ENTROPY_MAXBITS (192U)
+
+/* Public API to perform the initial TRNG entropy setup */
+void trng_setup(void);
+
+/* Public API to verify function id is part of TRNG */
+bool is_trng_fid(uint32_t smc_fid);
+
+/* Handler to be called to handle TRNG smc calls */
+uintptr_t trng_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
+);
+
+#endif /* TRNG_SVC_H */
diff --git a/include/services/trp/platform_trp.h b/include/services/trp/platform_trp.h
new file mode 100644
index 0000000..1c963c8
--- /dev/null
+++ b/include/services/trp/platform_trp.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_TRP_H
+#define PLATFORM_TRP_H
+
+#include <services/rmm_core_manifest.h>
+
+/*******************************************************************************
+ * Mandatory TRP functions (only if platform contains a TRP)
+ ******************************************************************************/
+void trp_early_platform_setup(rmm_manifest_t *manifest);
+
+#endif /* PLATFORM_TRP_H */
diff --git a/include/services/trp/trp_helpers.h b/include/services/trp/trp_helpers.h
new file mode 100644
index 0000000..8e786e2
--- /dev/null
+++ b/include/services/trp/trp_helpers.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TRP_HELPERS_H
+#define TRP_HELPERS_H
+
+/* Definitions to help the assembler access the SMC/ERET args structure */
+#define TRP_ARGS_SIZE TRP_ARGS_END
+#define TRP_ARG0 0x0
+#define TRP_ARG1 0x8
+#define TRP_ARG2 0x10
+#define TRP_ARG3 0x18
+#define TRP_ARG4 0x20
+#define TRP_ARG5 0x28
+#define TRP_ARG6 0x30
+#define TRP_ARG7 0x38
+#define TRP_ARGS_END 0x40
+
+#ifndef __ASSEMBLER__
+
+#include <platform_def.h>
+
+/* Data structure to hold SMC arguments */
+typedef struct trp_args {
+ uint64_t regs[TRP_ARGS_END >> 3];
+} __aligned(CACHE_WRITEBACK_GRANULE) trp_args_t;
+
+trp_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);
+
+__dead2 void trp_boot_abort(uint64_t err);
+
+#endif /* __ASSEMBLER __ */
+#endif /* TRP_HELPERS_H */
diff --git a/include/tools_share/cca_oid.h b/include/tools_share/cca_oid.h
new file mode 100644
index 0000000..e586b8c
--- /dev/null
+++ b/include/tools_share/cca_oid.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CCA_OID_H
+#define CCA_OID_H
+
+/* Reuse the Object IDs defined by TBBR for certificate extensions. */
+#include "tbbr_oid.h"
+
+/*
+ * Assign arbitrary Object ID values that do not conflict with any of the
+ * TBBR reserved OIDs.
+ */
+/* Platform root-of-trust public key */
+#define PROT_PK_OID "1.3.6.1.4.1.4128.2100.1102"
+/* Secure World root-of-trust public key */
+#define SWD_ROT_PK_OID "1.3.6.1.4.1.4128.2100.1103"
+/* Core Secure World public key */
+#define CORE_SWD_PK_OID "1.3.6.1.4.1.4128.2100.1104"
+/* Platform public key */
+#define PLAT_PK_OID "1.3.6.1.4.1.4128.2100.1105"
+/* Realm Monitor Manager (RMM) Hash */
+#define RMM_HASH_OID "1.3.6.1.4.1.4128.2100.1106"
+
+#endif /* CCA_OID_H */
diff --git a/include/tools_share/dualroot_oid.h b/include/tools_share/dualroot_oid.h
new file mode 100644
index 0000000..3e88a6d
--- /dev/null
+++ b/include/tools_share/dualroot_oid.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DUALROOT_OID_H
+#define DUALROOT_OID_H
+
+/* Reuse the Object IDs defined by TBBR for certificate extensions. */
+#include "tbbr_oid.h"
+
+/*
+ * Platform root-of-trust public key.
+ * Arbitrary value that does not conflict with any of the TBBR reserved OIDs.
+ */
+#define PROT_PK_OID "1.3.6.1.4.1.4128.2100.1102"
+
+#endif /* DUALROOT_OID_H */
diff --git a/include/tools_share/firmware_encrypted.h b/include/tools_share/firmware_encrypted.h
new file mode 100644
index 0000000..7ca634f
--- /dev/null
+++ b/include/tools_share/firmware_encrypted.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2020, Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FIRMWARE_ENCRYPTED_H
+#define FIRMWARE_ENCRYPTED_H
+
+#include <stdint.h>
+
+/* This is used as a signature to validate the encryption header */
+#define ENC_HEADER_MAGIC 0xAA640001U
+
+/* Firmware encryption status flag mask */
+#define FW_ENC_STATUS_FLAG_MASK 0x1
+
+/*
+ * SSK: Secret Symmetric Key
+ * BSSK: Binding Secret Symmetric Key
+ */
+enum fw_enc_status_t {
+ FW_ENC_WITH_SSK = 0,
+ FW_ENC_WITH_BSSK = 1,
+};
+
+#define ENC_MAX_IV_SIZE 16U
+#define ENC_MAX_TAG_SIZE 16U
+#define ENC_MAX_KEY_SIZE 32U
+
+struct fw_enc_hdr {
+ uint32_t magic;
+ uint16_t dec_algo;
+ uint16_t flags;
+ uint16_t iv_len;
+ uint16_t tag_len;
+ uint8_t iv[ENC_MAX_IV_SIZE];
+ uint8_t tag[ENC_MAX_TAG_SIZE];
+};
+
+#endif /* FIRMWARE_ENCRYPTED_H */
diff --git a/include/tools_share/firmware_image_package.h b/include/tools_share/firmware_image_package.h
new file mode 100644
index 0000000..b73eec7
--- /dev/null
+++ b/include/tools_share/firmware_image_package.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2014-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FIRMWARE_IMAGE_PACKAGE_H
+#define FIRMWARE_IMAGE_PACKAGE_H
+
+#include <stdint.h>
+
+#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_CCA_CONTENT_CERT \
+ {{0x36, 0xd8, 0x3d, 0x85}, {0x76, 0x1d}, {0x4d, 0xaf}, 0x96, 0xf1, {0xcd, 0x99, 0xd6, 0x56, 0x9b, 0x00} }
+#define UUID_CORE_SWD_KEY_CERT \
+ {{0x52, 0x22, 0x2d, 0x31}, {0x82, 0x0f}, {0x49, 0x4d}, 0x8b, 0xbc, {0xea, 0x68, 0x25, 0xd3, 0xc3, 0x5a} }
+#define UUID_PLAT_KEY_CERT \
+ {{0xd4, 0x3c, 0xd9, 0x02}, {0x5b, 0x9f}, {0x41, 0x2e}, 0x8a, 0xc6, {0x92, 0xb6, 0xd1, 0x8b, 0xe6, 0x0d} }
+#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} }
+#define UUID_REALM_MONITOR_MGMT_FIRMWARE \
+ {{0x6c, 0x07, 0x62, 0xa6}, {0x12, 0xf2}, {0x4b, 0x56}, 0x92, 0xcb, {0xba, 0x8f, 0x63, 0x36, 0x06, 0xd9} }
+/* 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} }
+#define UUID_SIP_SECURE_PARTITION_CONTENT_CERT \
+ {{0x77, 0x6d, 0xfd, 0x44}, {0x86, 0x97}, {0x4c, 0x3b}, 0x91, 0xeb, {0xc1, 0x3e, 0x02, 0x5a, 0x2a, 0x6f} }
+#define UUID_PLAT_SECURE_PARTITION_CONTENT_CERT \
+ {{0xdd, 0xcb, 0xbf, 0x4a}, {0xca, 0xd6}, {0x11, 0xea}, 0x87, 0xd0, {0x02, 0x42, 0xac, 0x13, 0x00, 0x03} }
+/* 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} }
+#define UUID_FW_CONFIG \
+ {{0x58, 0x07, 0xe1, 0x6a}, {0x84, 0x59}, {0x47, 0xbe}, 0x8e, 0xd5, {0x64, 0x8e, 0x8d, 0xdd, 0xab, 0x0e} }
+
+#ifdef PLAT_DEF_FIP_UUID
+#include <plat_def_fip_uuid.h>
+#endif
+
+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 */
diff --git a/include/tools_share/tbbr_oid.h b/include/tools_share/tbbr_oid.h
new file mode 100644
index 0000000..52b43ab
--- /dev/null
+++ b/include/tools_share/tbbr_oid.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TBBR_OID_H
+#define TBBR_OID_H
+
+#define MAX_OID_NAME_LEN 30
+
+/*
+ * 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"
+#define FW_CONFIG_HASH_OID "1.3.6.1.4.1.4128.2100.204"
+
+/*
+ * 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"
+
+/*
+ * Secure Partitions Content Certificate
+ */
+#define SP_PKG1_HASH_OID "1.3.6.1.4.1.4128.2100.1301"
+#define SP_PKG2_HASH_OID "1.3.6.1.4.1.4128.2100.1302"
+#define SP_PKG3_HASH_OID "1.3.6.1.4.1.4128.2100.1303"
+#define SP_PKG4_HASH_OID "1.3.6.1.4.1.4128.2100.1304"
+#define SP_PKG5_HASH_OID "1.3.6.1.4.1.4128.2100.1305"
+#define SP_PKG6_HASH_OID "1.3.6.1.4.1.4128.2100.1306"
+#define SP_PKG7_HASH_OID "1.3.6.1.4.1.4128.2100.1307"
+#define SP_PKG8_HASH_OID "1.3.6.1.4.1.4128.2100.1308"
+
+#ifdef PLAT_DEF_OID
+#include <platform_oid.h>
+#endif
+#endif /* TBBR_OID_H */
diff --git a/include/tools_share/uuid.h b/include/tools_share/uuid.h
new file mode 100644
index 0000000..2ced3a3
--- /dev/null
+++ b/include/tools_share/uuid.h
@@ -0,0 +1,74 @@
+/*-
+ * 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-2020, 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];
+};
+
+struct efi_guid {
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_hi_and_version;
+ uint8_t clock_seq_and_node[8];
+};
+
+union uuid_helper_t {
+ struct uuid uuid_struct;
+ struct efi_guid efi_guid;
+};
+
+/* XXX namespace pollution? */
+typedef struct uuid uuid_t;
+
+#endif /* UUID_H */
diff --git a/lib/aarch32/arm32_aeabi_divmod.c b/lib/aarch32/arm32_aeabi_divmod.c
new file mode 100644
index 0000000..ea8e2bb
--- /dev/null
+++ b/lib/aarch32/arm32_aeabi_divmod.c
@@ -0,0 +1,156 @@
+/*
+ * 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);
+}
diff --git a/lib/aarch32/arm32_aeabi_divmod_a32.S b/lib/aarch32/arm32_aeabi_divmod_a32.S
new file mode 100644
index 0000000..6915dcd
--- /dev/null
+++ b/lib/aarch32/arm32_aeabi_divmod_a32.S
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+/*
+ * 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
diff --git a/lib/aarch32/armclang_printf.S b/lib/aarch32/armclang_printf.S
new file mode 100644
index 0000000..2b87bf7
--- /dev/null
+++ b/lib/aarch32/armclang_printf.S
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+/* Symbols needed by armclang */
+
+ .globl __0printf
+ .globl __1printf
+ .globl __2printf
+
+func __0printf
+__1printf:
+__2printf:
+ b printf
+endfunc __0printf
diff --git a/lib/aarch32/cache_helpers.S b/lib/aarch32/cache_helpers.S
new file mode 100644
index 0000000..13d1872
--- /dev/null
+++ b/lib/aarch32/cache_helpers.S
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2016-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+ .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}
+ ldcopr r8, ID_MMFR4 // stash FEAT_CCIDX identifier in r8
+ ubfx r8, r8, #ID_MMFR4_CCIDX_SHIFT, #ID_MMFR4_CCIDX_LENGTH
+ 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)
+
+ cmp r8, #0 // check for FEAT_CCIDX for Associativity
+ beq 1f
+ ubfx r4, r12, #3, #21 // r4 = associativity CCSIDR[23:3]
+ b 2f
+1:
+ ubfx r4, r12, #3, #10 // r4 = associativity CCSIDR[12:3]
+2:
+ 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:
+ cmp r8, #0 // check for FEAT_CCIDX for NumSets
+ beq 3f
+ ldcopr r12, CCSIDR2 // FEAT_CCIDX numsets is in CCSIDR2
+ ubfx r7, r12, #0, #24 // r7 = numsets CCSIDR2[23:0]
+ b loop3
+3:
+ ubfx r7, r12, #13, #15 // r7 = numsets CCSIDR[27:13]
+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
diff --git a/lib/aarch32/misc_helpers.S b/lib/aarch32/misc_helpers.S
new file mode 100644
index 0000000..59e15bd
--- /dev/null
+++ b/lib/aarch32/misc_helpers.S
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <common/bl_common.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+ .globl smc
+ .globl zeromem
+ .globl zero_normalmem
+ .globl memcpy4
+ .globl disable_mmu_icache_secure
+ .globl disable_mmu_secure
+ .globl fixup_gdt_reloc
+
+#define PAGE_START_MASK ~(PAGE_SIZE_MASK)
+
+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
+ subs r2, r2, #4
+ bne m_loop4
+ bx lr
+
+/* copy byte per byte */
+m_loop1:
+ ldrb r3, [r1], #1
+ strb r3, [r0], #1
+ subs r2, r2, #1
+ bne m_loop1
+ 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
+
+/* ---------------------------------------------------------------------------
+ * Helper to fixup Global Descriptor table (GDT) and dynamic relocations
+ * (.rel.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).
+ * r0 - the start of the fixup region
+ * r1 - the limit of the fixup region
+ * These addresses have to be 4KB page aligned.
+ * ---------------------------------------------------------------------------
+ */
+
+/* Relocation codes */
+#define R_ARM_RELATIVE 23
+
+func fixup_gdt_reloc
+ mov r6, r0
+ mov r7, r1
+
+#if ENABLE_ASSERTIONS
+ /* Test if the limits are 4K aligned */
+ orr r0, r0, r1
+ mov r1, #(PAGE_SIZE_MASK)
+ tst r0, r1
+ ASM_ASSERT(eq)
+#endif
+ /*
+ * Calculate the offset based on return address in lr.
+ * Assume that this function is called within a page at the start of
+ * fixup region.
+ */
+ ldr r1, =PAGE_START_MASK
+ and r2, lr, r1
+ subs r0, r2, r6 /* Diff(S) = Current Address - Compiled Address */
+ beq 3f /* Diff(S) = 0. No relocation needed */
+
+ ldr r1, =__GOT_START__
+ add r1, r1, r0
+ ldr r2, =__GOT_END__
+ add r2, r2, r0
+
+ /*
+ * GOT is an array of 32_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 r3, [r1]
+
+ /* Skip adding offset if address is < lower limit */
+ cmp r3, r6
+ blo 2f
+
+ /* Skip adding offset if address is > upper limit */
+ cmp r3, r7
+ bhi 2f
+ add r3, r3, r0
+ str r3, [r1]
+
+2: add r1, r1, #4
+ cmp r1, r2
+ blo 1b
+
+ /* Starting dynamic relocations. Use ldr to get RELA_START and END */
+3: ldr r1, =__RELA_START__
+ add r1, r1, r0
+ ldr r2, =__RELA_END__
+ add r2, r2, r0
+
+ /*
+ * According to ELF-32 specification, the RELA data structure is as
+ * follows:
+ * typedef struct {
+ * Elf32_Addr r_offset;
+ * Elf32_Xword r_info;
+ * } Elf32_Rela;
+ *
+ * r_offset is address of reference
+ * r_info is symbol index and type of relocation (in this case
+ * code 23 which corresponds to R_ARM_RELATIVE).
+ *
+ * Size of Elf32_Rela structure is 8 bytes.
+ */
+
+ /* Skip R_ARM_NONE entry with code 0 */
+1: ldr r3, [r1, #4]
+ ands r3, r3, #0xff
+ beq 2f
+
+#if ENABLE_ASSERTIONS
+ /* Assert that the relocation type is R_ARM_RELATIVE */
+ cmp r3, #R_ARM_RELATIVE
+ ASM_ASSERT(eq)
+#endif
+ ldr r3, [r1] /* r_offset */
+ add r3, r0, r3 /* Diff(S) + r_offset */
+ ldr r4, [r3]
+
+ /* Skip adding offset if address is < lower limit */
+ cmp r4, r6
+ blo 2f
+
+ /* Skip adding offset if address is > upper limit */
+ cmp r4, r7
+ bhi 2f
+
+ add r4, r0, r4
+ str r4, [r3]
+
+2: add r1, r1, #8
+ cmp r1, r2
+ blo 1b
+ bx lr
+endfunc fixup_gdt_reloc
diff --git a/lib/aarch64/armclang_printf.S b/lib/aarch64/armclang_printf.S
new file mode 100644
index 0000000..52a6976
--- /dev/null
+++ b/lib/aarch64/armclang_printf.S
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+/* 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
diff --git a/lib/aarch64/cache_helpers.S b/lib/aarch64/cache_helpers.S
new file mode 100644
index 0000000..314ed6e
--- /dev/null
+++ b/lib/aarch64/cache_helpers.S
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+ .globl flush_dcache_range
+ .globl flush_dcache_to_popa_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
+
+.macro check_plat_can_cmo
+#if CONDITIONAL_CMO
+ mov x3, x30
+ mov x2, x0
+ bl plat_can_cmo
+ mov x30, x3
+ cbnz x0, 1f
+ ret
+1:
+ mov x0, x2
+#endif
+.endm
+ /* ------------------------------------------
+ * Clean+Invalidate from base address till
+ * size. 'x0' = addr, 'x1' = size
+ * ------------------------------------------
+ */
+func flush_dcache_range
+ check_plat_can_cmo
+ do_dcache_maintenance_by_mva civac
+endfunc flush_dcache_range
+
+ /* ------------------------------------------
+ * Clean from base address till size.
+ * 'x0' = addr, 'x1' = size
+ * ------------------------------------------
+ */
+func clean_dcache_range
+ check_plat_can_cmo
+ do_dcache_maintenance_by_mva cvac
+endfunc clean_dcache_range
+
+ /* ------------------------------------------
+ * Invalidate from base address till
+ * size. 'x0' = addr, 'x1' = size
+ * ------------------------------------------
+ */
+func inv_dcache_range
+ check_plat_can_cmo
+ do_dcache_maintenance_by_mva ivac
+endfunc inv_dcache_range
+
+
+ /*
+ * On implementations with FEAT_MTE2,
+ * Root firmware must issue DC_CIGDPAPA instead of DC_CIPAPA ,
+ * in order to additionally clean and invalidate Allocation Tags
+ * associated with the affected locations.
+ *
+ * ------------------------------------------
+ * Clean+Invalidate by PA to POPA
+ * from base address till size.
+ * 'x0' = addr, 'x1' = size
+ * ------------------------------------------
+ */
+func flush_dcache_to_popa_range
+ /* Exit early if size is zero */
+ cbz x1, exit_loop_dc_cipapa
+ check_plat_can_cmo
+ dcache_line_size x2, x3
+ sub x3, x2, #1
+ bic x0, x0, x3
+ add x1, x1, x0
+loop_dc_cipapa:
+ sys #6, c7, c14, #1, x0 /* DC CIPAPA,<Xt> */
+ add x0, x0, x2
+ cmp x0, x1
+ b.lo loop_dc_cipapa
+ dsb osh
+exit_loop_dc_cipapa:
+ ret
+endfunc flush_dcache_to_popa_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
+ mrs x12, ID_AA64MMFR2_EL1 // stash FEAT_CCIDX identifier in x12
+ ubfx x12, x12, #ID_AA64MMFR2_EL1_CCIDX_SHIFT, #ID_AA64MMFR2_EL1_CCIDX_LENGTH
+ 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)
+
+ cbz x12, 1f // check for FEAT_CCIDX for Associativity
+ ubfx x4, x1, #3, #21 // x4 = associativity CCSIDR_EL1[23:3]
+ b 2f
+1:
+ ubfx x4, x1, #3, #10 // x4 = associativity CCSIDR_EL1[12:3]
+2:
+ 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
+
+ cbz x12, 3f // check for FEAT_CCIDX for NumSets
+ ubfx x6, x1, #32, #24 // x6 (w6) = numsets CCSIDR_EL1[55:32]
+ // ISA will not allow x->w ubfx
+ b 4f
+3:
+ ubfx w6, w1, #13, #15 // w6 = numsets CCSIDR_EL1[27:13]
+4:
+ 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
+ check_plat_can_cmo
+ dcsw_op #LOUIS_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT
+endfunc dcsw_op_louis
+
+
+func dcsw_op_all
+ check_plat_can_cmo
+ 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
+ check_plat_can_cmo
+ 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
+ check_plat_can_cmo
+ 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
+ check_plat_can_cmo
+ dcsw_op_level #(3 << LEVEL_SHIFT)
+endfunc dcsw_op_level3
diff --git a/lib/aarch64/misc_helpers.S b/lib/aarch64/misc_helpers.S
new file mode 100644
index 0000000..e8110b0
--- /dev/null
+++ b/lib/aarch64/misc_helpers.S
@@ -0,0 +1,613 @@
+/*
+ * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <common/bl_common.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+ .globl smc
+
+ .globl zero_normalmem
+ .globl zeromem
+ .globl memcpy16
+ .globl gpt_tlbi_by_pa_ll
+
+ .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 || ENABLE_RME))
+ 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(<block size>) >> 2) (see encoding of
+ * dczid_el0 reg)
+ */
+ mrs block_size, dczid_el0
+
+ /*
+ * Select the 4 lowest bits and convert the extracted log2(<block size
+ * in words>) to <block size in bytes>
+ */
+ 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 4KB page aligned.
+ * ---------------------------------------------------------------------------
+ */
+
+/* Relocation codes */
+#define R_AARCH64_NONE 0
+#define R_AARCH64_RELATIVE 1027
+
+func fixup_gdt_reloc
+ mov x6, x0
+ mov x7, x1
+
+#if ENABLE_ASSERTIONS
+ /* Test if the limits are 4KB aligned */
+ orr x0, x0, x1
+ tst x0, #(PAGE_SIZE_MASK)
+ 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_MASK)
+ subs x0, x2, x6 /* Diff(S) = Current Address - Compiled Address */
+ b.eq 3f /* Diff(S) = 0. No relocation needed */
+
+ 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.hi 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 */
+3: 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
+ * code 1027 which corresponds to R_AARCH64_RELATIVE).
+ * r_addend is constant part of expression.
+ *
+ * Size of Elf64_Rela structure is 24 bytes.
+ */
+
+ /* Skip R_AARCH64_NONE entry with code 0 */
+1: ldr x3, [x1, #8]
+ cbz x3, 2f
+
+#if ENABLE_ASSERTIONS
+ /* Assert that the relocation type is R_AARCH64_RELATIVE */
+ cmp x3, #R_AARCH64_RELATIVE
+ 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.hi 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
+
+/*
+ * TODO: Currently only supports size of 4KB,
+ * support other sizes as well.
+ */
+func gpt_tlbi_by_pa_ll
+#if ENABLE_ASSERTIONS
+ cmp x1, #PAGE_SIZE_4KB
+ ASM_ASSERT(eq)
+ tst x0, #(PAGE_SIZE_MASK)
+ ASM_ASSERT(eq)
+#endif
+ lsr x0, x0, #FOUR_KB_SHIFT /* 4KB size encoding is zero */
+ sys #6, c8, c4, #7, x0 /* TLBI RPALOS, <Xt> */
+ dsb sy
+ ret
+endfunc gpt_tlbi_by_pa_ll
diff --git a/lib/bl_aux_params/bl_aux_params.c b/lib/bl_aux_params/bl_aux_params.c
new file mode 100644
index 0000000..7f357b7
--- /dev/null
+++ b/lib/bl_aux_params/bl_aux_params.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <inttypes.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/coreboot.h>
+#include <lib/bl_aux_params/bl_aux_params.h>
+
+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%" PRIx64,
+ p->type);
+ break;
+ }
+ }
+}
diff --git a/lib/compiler-rt/LICENSE.TXT b/lib/compiler-rt/LICENSE.TXT
new file mode 100644
index 0000000..a17dc12
--- /dev/null
+++ b/lib/compiler-rt/LICENSE.TXT
@@ -0,0 +1,91 @@
+==============================================================================
+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.
+
diff --git a/lib/compiler-rt/builtins/arm/aeabi_ldivmod.S b/lib/compiler-rt/builtins/arm/aeabi_ldivmod.S
new file mode 100644
index 0000000..d0d06be
--- /dev/null
+++ b/lib/compiler-rt/builtins/arm/aeabi_ldivmod.S
@@ -0,0 +1,45 @@
+//===-- aeabi_ldivmod.S - EABI ldivmod implementation ---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// struct { int64_t quot, int64_t rem}
+// __aeabi_ldivmod(int64_t numerator, int64_t denominator) {
+// int64_t rem, quot;
+// quot = __divmoddi4(numerator, denominator, &rem);
+// return {quot, rem};
+// }
+
+#if defined(__MINGW32__)
+#define __aeabi_ldivmod __rt_sdiv64
+#endif
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_ldivmod)
+ push {r6, lr}
+ sub sp, sp, #16
+ add r6, sp, #8
+ str r6, [sp]
+#if defined(__MINGW32__)
+ movs r6, r0
+ movs r0, r2
+ movs r2, r6
+ movs r6, r1
+ movs r1, r3
+ movs r3, r6
+#endif
+ bl SYMBOL_NAME(__divmoddi4)
+ ldr r2, [sp, #8]
+ ldr r3, [sp, #12]
+ add sp, sp, #16
+ pop {r6, pc}
+END_COMPILERRT_FUNCTION(__aeabi_ldivmod)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/lib/compiler-rt/builtins/arm/aeabi_memcpy.S b/lib/compiler-rt/builtins/arm/aeabi_memcpy.S
new file mode 100644
index 0000000..93e1b05
--- /dev/null
+++ b/lib/compiler-rt/builtins/arm/aeabi_memcpy.S
@@ -0,0 +1,29 @@
+//===-- aeabi_memcpy.S - EABI memcpy implementation -----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// void __aeabi_memcpy(void *dest, void *src, size_t n) { memcpy(dest, src, n); }
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_memcpy)
+#ifdef USE_THUMB_1
+ push {r7, lr}
+ bl memcpy
+ pop {r7, pc}
+#else
+ b memcpy
+#endif
+END_COMPILERRT_FUNCTION(__aeabi_memcpy)
+
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy4, __aeabi_memcpy)
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy8, __aeabi_memcpy)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/lib/compiler-rt/builtins/arm/aeabi_uldivmod.S b/lib/compiler-rt/builtins/arm/aeabi_uldivmod.S
new file mode 100644
index 0000000..4fc9770
--- /dev/null
+++ b/lib/compiler-rt/builtins/arm/aeabi_uldivmod.S
@@ -0,0 +1,45 @@
+//===-- aeabi_uldivmod.S - EABI uldivmod implementation -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#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
+
diff --git a/lib/compiler-rt/builtins/assembly.h b/lib/compiler-rt/builtins/assembly.h
new file mode 100644
index 0000000..69a3d86
--- /dev/null
+++ b/lib/compiler-rt/builtins/assembly.h
@@ -0,0 +1,292 @@
+//===-- assembly.h - compiler-rt assembler support macros -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// 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(__linux__) && defined(__CET__)
+#if __has_include(<cet.h>)
+#include <cet.h>
+#endif
+#endif
+
+#if defined(__APPLE__) && defined(__aarch64__)
+#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__) || defined(__aarch64__)
+#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(__FreeBSD__) || defined(__Fuchsia__) || \
+ defined(__linux__)
+#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__) || defined(__aarch64__)
+#define FUNC_ALIGN \
+ .text SEPARATOR \
+ .balign 16 SEPARATOR
+#else
+#define FUNC_ALIGN
+#endif
+
+// BTI and PAC gnu property note
+#define NT_GNU_PROPERTY_TYPE_0 5
+#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
+#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI 1
+#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC 2
+
+#if defined(__ARM_FEATURE_BTI_DEFAULT)
+#define BTI_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_BTI
+#else
+#define BTI_FLAG 0
+#endif
+
+#if __ARM_FEATURE_PAC_DEFAULT & 3
+#define PAC_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_PAC
+#else
+#define PAC_FLAG 0
+#endif
+
+#define GNU_PROPERTY(type, value) \
+ .pushsection .note.gnu.property, "a" SEPARATOR \
+ .p2align 3 SEPARATOR \
+ .word 4 SEPARATOR \
+ .word 16 SEPARATOR \
+ .word NT_GNU_PROPERTY_TYPE_0 SEPARATOR \
+ .asciz "GNU" SEPARATOR \
+ .word type SEPARATOR \
+ .word 4 SEPARATOR \
+ .word value SEPARATOR \
+ .word 0 SEPARATOR \
+ .popsection
+
+#if BTI_FLAG != 0
+#define BTI_C hint #34
+#define BTI_J hint #36
+#else
+#define BTI_C
+#define BTI_J
+#endif
+
+#if (BTI_FLAG | PAC_FLAG) != 0
+#define GNU_PROPERTY_BTI_PAC \
+ GNU_PROPERTY(GNU_PROPERTY_AARCH64_FEATURE_1_AND, BTI_FLAG | PAC_FLAG)
+#else
+#define GNU_PROPERTY_BTI_PAC
+#endif
+
+#if defined(__clang__) || defined(__GCC_HAVE_DWARF2_CFI_ASM)
+#define CFI_START .cfi_startproc
+#define CFI_END .cfi_endproc
+#else
+#define CFI_START
+#define CFI_END
+#endif
+
+#if defined(__arm__)
+
+// Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros:
+// - for '-mthumb -march=armv6' compiler defines '__thumb__'
+// - for '-mthumb -march=armv7' compiler defines '__thumb__' and '__thumb2__'
+#if defined(__thumb2__) || defined(__thumb__)
+#define DEFINE_CODE_STATE .thumb SEPARATOR
+#define DECLARE_FUNC_ENCODING .thumb_func SEPARATOR
+#if defined(__thumb2__)
+#define USE_THUMB_2
+#define IT(cond) it cond
+#define ITT(cond) itt cond
+#define ITE(cond) ite cond
+#else
+#define USE_THUMB_1
+#define IT(cond)
+#define ITT(cond)
+#define ITE(cond)
+#endif // defined(__thumb__2)
+#else // !defined(__thumb2__) && !defined(__thumb__)
+#define DEFINE_CODE_STATE .arm SEPARATOR
+#define DECLARE_FUNC_ENCODING
+#define IT(cond)
+#define ITT(cond)
+#define ITE(cond)
+#endif
+
+#if defined(USE_THUMB_1) && defined(USE_THUMB_2)
+#error "USE_THUMB_1 and USE_THUMB_2 can't be defined together."
+#endif
+
+#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5
+#define ARM_HAS_BX
+#endif
+#if !defined(__ARM_FEATURE_CLZ) && !defined(USE_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 defined(USE_THUMB_2)
+#define WIDE(op) op.w
+#else
+#define WIDE(op) op
+#endif
+#else // !defined(__arm)
+#define DECLARE_FUNC_ENCODING
+#define DEFINE_CODE_STATE
+#endif
+
+#define GLUE2_(a, b) a##b
+#define GLUE(a, b) GLUE2_(a, b)
+#define GLUE2(a, b) GLUE2_(a, b)
+#define GLUE3_(a, b, c) a##b##c
+#define GLUE3(a, b, c) GLUE3_(a, b, c)
+#define GLUE4_(a, b, c, d) a##b##c##d
+#define GLUE4(a, b, c, d) GLUE4_(a, b, c, d)
+
+#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
+
+#ifdef VISIBILITY_HIDDEN
+#define DECLARE_SYMBOL_VISIBILITY(name) \
+ HIDDEN(SYMBOL_NAME(name)) SEPARATOR
+#define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) \
+ HIDDEN(name) SEPARATOR
+#else
+#define DECLARE_SYMBOL_VISIBILITY(name)
+#define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name)
+#endif
+
+#define DEFINE_COMPILERRT_FUNCTION(name) \
+ DEFINE_CODE_STATE \
+ FILE_LEVEL_DIRECTIVE SEPARATOR \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_SYMBOL_VISIBILITY(name) \
+ DECLARE_FUNC_ENCODING \
+ SYMBOL_NAME(name):
+
+#define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \
+ DEFINE_CODE_STATE \
+ 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) \
+ DEFINE_CODE_STATE \
+ FILE_LEVEL_DIRECTIVE SEPARATOR \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ HIDDEN(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_FUNC_ENCODING \
+ SYMBOL_NAME(name):
+
+#define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \
+ DEFINE_CODE_STATE \
+ .globl name SEPARATOR \
+ SYMBOL_IS_FUNC(name) SEPARATOR \
+ HIDDEN(name) SEPARATOR \
+ DECLARE_FUNC_ENCODING \
+ name:
+
+#define DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(name) \
+ DEFINE_CODE_STATE \
+ FUNC_ALIGN \
+ .globl name SEPARATOR \
+ SYMBOL_IS_FUNC(name) SEPARATOR \
+ DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) SEPARATOR \
+ CFI_START SEPARATOR \
+ DECLARE_FUNC_ENCODING \
+ name: SEPARATOR BTI_C
+
+#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)
+#define END_COMPILERRT_OUTLINE_FUNCTION(name) \
+ CFI_END SEPARATOR \
+ .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
+#else
+#define END_COMPILERRT_FUNCTION(name)
+#define END_COMPILERRT_OUTLINE_FUNCTION(name) \
+ CFI_END
+#endif
+
+#endif // COMPILERRT_ASSEMBLY_H
diff --git a/lib/compiler-rt/builtins/ctzdi2.c b/lib/compiler-rt/builtins/ctzdi2.c
new file mode 100644
index 0000000..26c908d
--- /dev/null
+++ b/lib/compiler-rt/builtins/ctzdi2.c
@@ -0,0 +1,35 @@
+//===-- ctzdi2.c - Implement __ctzdi2 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __ctzdi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "int_lib.h"
+
+// Returns: the number of trailing 0-bits
+
+#if !defined(__clang__) && \
+ ((defined(__sparc__) && defined(__arch64__)) || defined(__mips64) || \
+ (defined(__riscv) && __SIZEOF_POINTER__ >= 8))
+// On 64-bit architectures with neither a native clz instruction nor a native
+// ctz instruction, gcc resolves __builtin_ctz to __ctzdi2 rather than
+// __ctzsi2, leading to infinite recursion.
+#define __builtin_ctz(a) __ctzsi2(a)
+extern int __ctzsi2(si_int);
+#endif
+
+// Precondition: a != 0
+
+COMPILER_RT_ABI int __ctzdi2(di_int a) {
+ dwords x;
+ x.all = a;
+ const si_int f = -(x.s.low == 0);
+ return ctzsi((x.s.high & f) | (x.s.low & ~f)) +
+ (f & ((si_int)(sizeof(si_int) * CHAR_BIT)));
+}
diff --git a/lib/compiler-rt/builtins/divdi3.c b/lib/compiler-rt/builtins/divdi3.c
new file mode 100644
index 0000000..d71e138
--- /dev/null
+++ b/lib/compiler-rt/builtins/divdi3.c
@@ -0,0 +1,22 @@
+//===-- divdi3.c - Implement __divdi3 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __divdi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "int_lib.h"
+
+// Returns: a / b
+
+#define fixint_t di_int
+#define fixuint_t du_int
+#define COMPUTE_UDIV(a, b) __udivmoddi4((a), (b), (du_int *)0)
+#include "int_div_impl.inc"
+
+COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b) { return __divXi3(a, b); }
diff --git a/lib/compiler-rt/builtins/divmoddi4.c b/lib/compiler-rt/builtins/divmoddi4.c
new file mode 100644
index 0000000..e7cbbb1
--- /dev/null
+++ b/lib/compiler-rt/builtins/divmoddi4.c
@@ -0,0 +1,28 @@
+//===-- divmoddi4.c - Implement __divmoddi4 -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __divmoddi4 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "int_lib.h"
+
+// Returns: a / b, *rem = a % b
+
+COMPILER_RT_ABI di_int __divmoddi4(di_int a, di_int b, di_int *rem) {
+ const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1;
+ di_int s_a = a >> bits_in_dword_m1; // s_a = a < 0 ? -1 : 0
+ di_int s_b = b >> bits_in_dword_m1; // s_b = b < 0 ? -1 : 0
+ a = (a ^ s_a) - s_a; // negate if s_a == -1
+ b = (b ^ s_b) - s_b; // negate if s_b == -1
+ s_b ^= s_a; // sign of quotient
+ du_int r;
+ di_int q = (__udivmoddi4(a, b, &r) ^ s_b) - s_b; // negate if s_b == -1
+ *rem = (r ^ s_a) - s_a; // negate if s_a == -1
+ return q;
+}
diff --git a/lib/compiler-rt/builtins/int_div_impl.inc b/lib/compiler-rt/builtins/int_div_impl.inc
new file mode 100644
index 0000000..dc1f97c
--- /dev/null
+++ b/lib/compiler-rt/builtins/int_div_impl.inc
@@ -0,0 +1,95 @@
+//===-- int_div_impl.inc - Integer division ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Helpers used by __udivsi3, __umodsi3, __udivdi3, and __umodsi3.
+//
+//===----------------------------------------------------------------------===//
+
+#define clz(a) (sizeof(a) == sizeof(unsigned long long) ? __builtin_clzll(a) : clzsi(a))
+
+// Adapted from Figure 3-40 of The PowerPC Compiler Writer's Guide
+static __inline fixuint_t __udivXi3(fixuint_t n, fixuint_t d) {
+ const unsigned N = sizeof(fixuint_t) * CHAR_BIT;
+ // d == 0 cases are unspecified.
+ unsigned sr = (d ? clz(d) : N) - (n ? clz(n) : N);
+ // 0 <= sr <= N - 1 or sr is very large.
+ if (sr > N - 1) // n < d
+ return 0;
+ if (sr == N - 1) // d == 1
+ return n;
+ ++sr;
+ // 1 <= sr <= N - 1. Shifts do not trigger UB.
+ fixuint_t r = n >> sr;
+ n <<= N - sr;
+ fixuint_t carry = 0;
+ for (; sr > 0; --sr) {
+ r = (r << 1) | (n >> (N - 1));
+ n = (n << 1) | carry;
+ // Branch-less version of:
+ // carry = 0;
+ // if (r >= d) r -= d, carry = 1;
+ const fixint_t s = (fixint_t)(d - r - 1) >> (N - 1);
+ carry = s & 1;
+ r -= d & s;
+ }
+ n = (n << 1) | carry;
+ return n;
+}
+
+// Mostly identical to __udivXi3 but the return values are different.
+static __inline fixuint_t __umodXi3(fixuint_t n, fixuint_t d) {
+ const unsigned N = sizeof(fixuint_t) * CHAR_BIT;
+ // d == 0 cases are unspecified.
+ unsigned sr = (d ? clz(d) : N) - (n ? clz(n) : N);
+ // 0 <= sr <= N - 1 or sr is very large.
+ if (sr > N - 1) // n < d
+ return n;
+ if (sr == N - 1) // d == 1
+ return 0;
+ ++sr;
+ // 1 <= sr <= N - 1. Shifts do not trigger UB.
+ fixuint_t r = n >> sr;
+ n <<= N - sr;
+ fixuint_t carry = 0;
+ for (; sr > 0; --sr) {
+ r = (r << 1) | (n >> (N - 1));
+ n = (n << 1) | carry;
+ // Branch-less version of:
+ // carry = 0;
+ // if (r >= d) r -= d, carry = 1;
+ const fixint_t s = (fixint_t)(d - r - 1) >> (N - 1);
+ carry = s & 1;
+ r -= d & s;
+ }
+ return r;
+}
+
+#ifdef COMPUTE_UDIV
+static __inline fixint_t __divXi3(fixint_t a, fixint_t b) {
+ const int N = (int)(sizeof(fixint_t) * CHAR_BIT) - 1;
+ fixint_t s_a = a >> N; // s_a = a < 0 ? -1 : 0
+ fixint_t s_b = b >> N; // s_b = b < 0 ? -1 : 0
+ fixuint_t a_u = (fixuint_t)(a ^ s_a) + (-s_a); // negate if s_a == -1
+ fixuint_t b_u = (fixuint_t)(b ^ s_b) + (-s_b); // negate if s_b == -1
+ s_a ^= s_b; // sign of quotient
+ return (COMPUTE_UDIV(a_u, b_u) ^ s_a) + (-s_a); // negate if s_a == -1
+}
+#endif // COMPUTE_UDIV
+
+#ifdef ASSIGN_UMOD
+static __inline fixint_t __modXi3(fixint_t a, fixint_t b) {
+ const int N = (int)(sizeof(fixint_t) * CHAR_BIT) - 1;
+ fixint_t s = b >> N; // s = b < 0 ? -1 : 0
+ fixuint_t b_u = (fixuint_t)(b ^ s) + (-s); // negate if s == -1
+ s = a >> N; // s = a < 0 ? -1 : 0
+ fixuint_t a_u = (fixuint_t)(a ^ s) + (-s); // negate if s == -1
+ fixuint_t res;
+ ASSIGN_UMOD(res, a_u, b_u);
+ return (res ^ s) + (-s); // negate if s == -1
+}
+#endif // ASSIGN_UMOD
diff --git a/lib/compiler-rt/builtins/int_endianness.h b/lib/compiler-rt/builtins/int_endianness.h
new file mode 100644
index 0000000..291c6b5
--- /dev/null
+++ b/lib/compiler-rt/builtins/int_endianness.h
@@ -0,0 +1,114 @@
+//===-- int_endianness.h - configuration header for compiler-rt -----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// 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 <sys/byteorder.h>
+
+#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
+
+// ..
+
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \
+ defined(__minix)
+#include <sys/endian.h>
+
+#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__)
+#include <machine/endian.h>
+
+#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
+
+// ..
+
+// 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
diff --git a/lib/compiler-rt/builtins/int_lib.h b/lib/compiler-rt/builtins/int_lib.h
new file mode 100644
index 0000000..fb791eb
--- /dev/null
+++ b/lib/compiler-rt/builtins/int_lib.h
@@ -0,0 +1,171 @@
+//===-- int_lib.h - configuration header for compiler-rt -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a configuration header for compiler-rt.
+// This file is not part of the interface of this library.
+//
+//===----------------------------------------------------------------------===//
+
+#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).
+
+// 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
+
+#define STR(a) #a
+#define XSTR(a) STR(a)
+#define SYMBOL_NAME(name) XSTR(__USER_LABEL_PREFIX__) #name
+
+#if defined(__ELF__) || defined(__MINGW32__) || defined(__wasm__) || \
+ defined(_AIX)
+#define COMPILER_RT_ALIAS(name, aliasname) \
+ COMPILER_RT_ABI __typeof(name) aliasname __attribute__((__alias__(#name)));
+#elif defined(__APPLE__)
+#if defined(VISIBILITY_HIDDEN)
+#define COMPILER_RT_ALIAS_VISIBILITY(name) \
+ __asm__(".private_extern " SYMBOL_NAME(name));
+#else
+#define COMPILER_RT_ALIAS_VISIBILITY(name)
+#endif
+#define COMPILER_RT_ALIAS(name, aliasname) \
+ __asm__(".globl " SYMBOL_NAME(aliasname)); \
+ COMPILER_RT_ALIAS_VISIBILITY(aliasname) \
+ __asm__(SYMBOL_NAME(aliasname) " = " SYMBOL_NAME(name)); \
+ COMPILER_RT_ABI __typeof(name) aliasname;
+#elif defined(_WIN32)
+#define COMPILER_RT_ALIAS(name, aliasname)
+#else
+#error Unsupported target
+#endif
+
+#if (defined(__FreeBSD__) || defined(__NetBSD__)) && \
+ (defined(_KERNEL) || defined(_STANDALONE))
+//
+// Kernel and boot environment can't use normal headers,
+// so use the equivalent system headers.
+// NB: FreeBSD (and OpenBSD) deprecate machine/limits.h in
+// favour of sys/limits.h, so prefer the former, but fall
+// back on the latter if not available since NetBSD only has
+// the latter.
+//
+#if defined(__has_include) && __has_include(<sys/limits.h>)
+#include <sys/limits.h>
+#else
+#include <machine/limits.h>
+#endif
+#include <sys/stdint.h>
+#include <sys/types.h>
+#else
+// Include the standard compiler builtin headers we use functionality from.
+#include <float.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
+#endif
+
+// Include the commonly used internal type definitions.
+#include "int_types.h"
+
+// Include internal utility function declarations.
+#include "int_util.h"
+
+COMPILER_RT_ABI int __paritysi2(si_int a);
+COMPILER_RT_ABI 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 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 <intrin.h>
+
+int __inline __builtin_ctz(uint32_t value) {
+ unsigned long trailing_zero = 0;
+ if (_BitScanForward(&trailing_zero, value))
+ return trailing_zero;
+ return 32;
+}
+
+int __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)
+int __inline __builtin_clzll(uint64_t value) {
+ unsigned long leading_zero = 0;
+ if (_BitScanReverse64(&leading_zero, value))
+ return 63 - leading_zero;
+ return 64;
+}
+#else
+int __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
+
+bool __inline __builtin_sadd_overflow(int x, int y, int *result) {
+ if ((x < 0) != (y < 0)) {
+ *result = x + y;
+ return false;
+ }
+ int tmp = (unsigned int)x + (unsigned int)y;
+ if ((tmp < 0) != (x < 0))
+ return true;
+ *result = tmp;
+ return false;
+}
+
+#endif // defined(_MSC_VER) && !defined(__clang__)
+
+#endif // INT_LIB_H
diff --git a/lib/compiler-rt/builtins/int_math.h b/lib/compiler-rt/builtins/int_math.h
new file mode 100644
index 0000000..48b9580
--- /dev/null
+++ b/lib/compiler-rt/builtins/int_math.h
@@ -0,0 +1,98 @@
+//===-- int_math.h - internal math inlines --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// 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 <math.h>
+#include <stdlib.h>
+#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_fmaxl(x, y) __max((x), (y))
+#else
+#define crt_fmaxl(x, y) __builtin_fmaxl((x), (y))
+#endif
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#define crt_logbl(x) logbl((x))
+#else
+#define crt_logbl(x) __builtin_logbl((x))
+#endif
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#define crt_scalbnl(x, y) scalbnl((x), (y))
+#else
+#define crt_scalbnl(x, y) __builtin_scalbnl((x), (y))
+#endif
+
+#endif // INT_MATH_H
diff --git a/lib/compiler-rt/builtins/int_types.h b/lib/compiler-rt/builtins/int_types.h
new file mode 100644
index 0000000..7a72de4
--- /dev/null
+++ b/lib/compiler-rt/builtins/int_types.h
@@ -0,0 +1,198 @@
+//===-- int_lib.h - configuration header for compiler-rt -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// 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 int32_t si_int;
+typedef uint32_t su_int;
+#if UINT_MAX == 0xFFFFFFFF
+#define clzsi __builtin_clz
+#define ctzsi __builtin_ctz
+#elif ULONG_MAX == 0xFFFFFFFF
+#define clzsi __builtin_clzl
+#define ctzsi __builtin_ctzl
+#else
+#error could not determine appropriate clzsi macro for this system
+#endif
+
+typedef int64_t di_int;
+typedef uint64_t 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;
+
+#if defined(__LP64__) || defined(__wasm__) || defined(__mips64) || \
+ defined(__riscv) || defined(_WIN64)
+#define CRT_HAS_128BIT
+#endif
+
+// MSVC doesn't have a working 128bit integer type. Users should really compile
+// compiler-rt with clang, but if they happen to be doing a standalone build for
+// asan or something else, disable the 128 bit parts so things sort of work.
+#if defined(_MSC_VER) && !defined(__clang__)
+#undef 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
+
+// FreeBSD's boot environment does not support using floating-point and poisons
+// the float and double keywords.
+#if defined(__FreeBSD__) && defined(_STANDALONE)
+#define CRT_HAS_FLOATING_POINT 0
+#else
+#define CRT_HAS_FLOATING_POINT 1
+#endif
+
+#if CRT_HAS_FLOATING_POINT
+typedef union {
+ su_int u;
+ float f;
+} float_bits;
+
+typedef union {
+ udwords u;
+ double f;
+} double_bits;
+#endif
+
+typedef struct {
+#if _YUGA_LITTLE_ENDIAN
+ udwords low;
+ udwords high;
+#else
+ udwords high;
+ udwords low;
+#endif // _YUGA_LITTLE_ENDIAN
+} uqwords;
+
+// Check if the target supports 80 bit extended precision long doubles.
+// Notably, on x86 Windows, MSVC only provides a 64-bit long double, but GCC
+// still makes it 80 bits. Clang will match whatever compiler it is trying to
+// be compatible with. On 32-bit x86 Android, long double is 64 bits, while on
+// x86_64 Android, long double is 128 bits.
+#if (defined(__i386__) || defined(__x86_64__)) && \
+ !(defined(_MSC_VER) || defined(__ANDROID__))
+#define HAS_80_BIT_LONG_DOUBLE 1
+#elif defined(__m68k__) || defined(__ia64__)
+#define HAS_80_BIT_LONG_DOUBLE 1
+#else
+#define HAS_80_BIT_LONG_DOUBLE 0
+#endif
+
+#if CRT_HAS_FLOATING_POINT
+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
+#endif // INT_TYPES_H
diff --git a/lib/compiler-rt/builtins/int_util.h b/lib/compiler-rt/builtins/int_util.h
new file mode 100644
index 0000000..c372c2e
--- /dev/null
+++ b/lib/compiler-rt/builtins/int_util.h
@@ -0,0 +1,47 @@
+//===-- int_util.h - internal utility functions ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is not part of the interface of this library.
+//
+// This file defines non-inline utilities which are available for use in the
+// library. The function definitions themselves are all contained in int_util.c
+// which will always be compiled into any compiler-rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef INT_UTIL_H
+#define INT_UTIL_H
+
+/// \brief Trigger a program abort (or panic for kernel code).
+#define compilerrt_abort() __compilerrt_abort_impl(__FILE__, __LINE__, __func__)
+
+NORETURN void __compilerrt_abort_impl(const char *file, int line,
+ const char *function);
+
+#define COMPILE_TIME_ASSERT(expr) COMPILE_TIME_ASSERT1(expr, __COUNTER__)
+#define COMPILE_TIME_ASSERT1(expr, cnt) COMPILE_TIME_ASSERT2(expr, cnt)
+#define COMPILE_TIME_ASSERT2(expr, cnt) \
+ typedef char ct_assert_##cnt[(expr) ? 1 : -1] UNUSED
+
+// Force unrolling the code specified to be repeated N times.
+#define REPEAT_0_TIMES(code_to_repeat) /* do nothing */
+#define REPEAT_1_TIMES(code_to_repeat) code_to_repeat
+#define REPEAT_2_TIMES(code_to_repeat) \
+ REPEAT_1_TIMES(code_to_repeat) \
+ code_to_repeat
+#define REPEAT_3_TIMES(code_to_repeat) \
+ REPEAT_2_TIMES(code_to_repeat) \
+ code_to_repeat
+#define REPEAT_4_TIMES(code_to_repeat) \
+ REPEAT_3_TIMES(code_to_repeat) \
+ code_to_repeat
+
+#define REPEAT_N_TIMES_(N, code_to_repeat) REPEAT_##N##_TIMES(code_to_repeat)
+#define REPEAT_N_TIMES(N, code_to_repeat) REPEAT_N_TIMES_(N, code_to_repeat)
+
+#endif // INT_UTIL_H
diff --git a/lib/compiler-rt/builtins/lshrdi3.c b/lib/compiler-rt/builtins/lshrdi3.c
new file mode 100644
index 0000000..6072152
--- /dev/null
+++ b/lib/compiler-rt/builtins/lshrdi3.c
@@ -0,0 +1,38 @@
+//===-- lshrdi3.c - Implement __lshrdi3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// 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, 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__)
+COMPILER_RT_ALIAS(__lshrdi3, __aeabi_llsr)
+#endif
diff --git a/lib/compiler-rt/builtins/popcountdi2.c b/lib/compiler-rt/builtins/popcountdi2.c
new file mode 100644
index 0000000..20dd0b0
--- /dev/null
+++ b/lib/compiler-rt/builtins/popcountdi2.c
@@ -0,0 +1,32 @@
+//===-- popcountdi2.c - Implement __popcountdi2 ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __popcountdi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "int_lib.h"
+
+// Returns: count of 1 bits
+
+COMPILER_RT_ABI int __popcountdi2(di_int a) {
+ du_int x2 = (du_int)a;
+ x2 = x2 - ((x2 >> 1) & 0x5555555555555555uLL);
+ // Every 2 bits holds the sum of every pair of bits (32)
+ x2 = ((x2 >> 2) & 0x3333333333333333uLL) + (x2 & 0x3333333333333333uLL);
+ // Every 4 bits holds the sum of every 4-set of bits (3 significant bits) (16)
+ x2 = (x2 + (x2 >> 4)) & 0x0F0F0F0F0F0F0F0FuLL;
+ // Every 8 bits holds the sum of every 8-set of bits (4 significant bits) (8)
+ su_int x = (su_int)(x2 + (x2 >> 32));
+ // The lower 32 bits hold four 16 bit sums (5 significant bits).
+ // Upper 32 bits are garbage
+ x = x + (x >> 16);
+ // The lower 16 bits hold two 32 bit sums (6 significant bits).
+ // Upper 16 bits are garbage
+ return (x + (x >> 8)) & 0x0000007F; // (7 significant bits)
+}
diff --git a/lib/compiler-rt/builtins/popcountsi2.c b/lib/compiler-rt/builtins/popcountsi2.c
new file mode 100644
index 0000000..4d346c4
--- /dev/null
+++ b/lib/compiler-rt/builtins/popcountsi2.c
@@ -0,0 +1,29 @@
+//===-- popcountsi2.c - Implement __popcountsi2 ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __popcountsi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "int_lib.h"
+
+// Returns: count of 1 bits
+
+COMPILER_RT_ABI int __popcountsi2(si_int a) {
+ su_int x = (su_int)a;
+ x = x - ((x >> 1) & 0x55555555);
+ // Every 2 bits holds the sum of every pair of bits
+ x = ((x >> 2) & 0x33333333) + (x & 0x33333333);
+ // Every 4 bits holds the sum of every 4-set of bits (3 significant bits)
+ x = (x + (x >> 4)) & 0x0F0F0F0F;
+ // Every 8 bits holds the sum of every 8-set of bits (4 significant bits)
+ x = (x + (x >> 16));
+ // The lower 16 bits hold two 8 bit sums (5 significant bits).
+ // Upper 16 bits are garbage
+ return (x + (x >> 8)) & 0x0000003F; // (6 significant bits)
+}
diff --git a/lib/compiler-rt/builtins/udivmoddi4.c b/lib/compiler-rt/builtins/udivmoddi4.c
new file mode 100644
index 0000000..123e5fb
--- /dev/null
+++ b/lib/compiler-rt/builtins/udivmoddi4.c
@@ -0,0 +1,200 @@
+//===-- udivmoddi4.c - Implement __udivmoddi4 -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+#if defined(_MSC_VER) && !defined(__clang__)
+// MSVC throws a warning about mod 0 here, disable it for builds that
+// warn-as-error
+#pragma warning(push)
+#pragma warning(disable : 4723 4724)
+#endif
+
+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 >> ctzsi(d.s.high);
+ }
+ // K K
+ // ---
+ // K 0
+ sr = clzsi(d.s.high) - clzsi(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 = ctzsi(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 + clzsi(d.s.low) - clzsi(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 = clzsi(d.s.high) - clzsi(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;
+}
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#pragma warning(pop)
+#endif
diff --git a/lib/compiler-rt/compiler-rt.mk b/lib/compiler-rt/compiler-rt.mk
new file mode 100644
index 0000000..2338908
--- /dev/null
+++ b/lib/compiler-rt/compiler-rt.mk
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 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.
+#
+
+COMPILER_RT_SRCS := lib/compiler-rt/builtins/popcountdi2.c \
+ lib/compiler-rt/builtins/popcountsi2.c
+
+ifeq (${ARCH},aarch32)
+COMPILER_RT_SRCS += lib/compiler-rt/builtins/arm/aeabi_ldivmod.S \
+ lib/compiler-rt/builtins/arm/aeabi_uldivmod.S \
+ lib/compiler-rt/builtins/arm/aeabi_memcpy.S \
+ lib/compiler-rt/builtins/ctzdi2.c \
+ lib/compiler-rt/builtins/divdi3.c \
+ lib/compiler-rt/builtins/divmoddi4.c \
+ lib/compiler-rt/builtins/lshrdi3.c \
+ lib/compiler-rt/builtins/udivmoddi4.c
+endif
diff --git a/lib/coreboot/coreboot.mk b/lib/coreboot/coreboot.mk
new file mode 100644
index 0000000..4201823
--- /dev/null
+++ b/lib/coreboot/coreboot.mk
@@ -0,0 +1,22 @@
+#
+# 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
diff --git a/lib/coreboot/coreboot_table.c b/lib/coreboot/coreboot_table.c
new file mode 100644
index 0000000..fb31ef1
--- /dev/null
+++ b/lib/coreboot/coreboot_table.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <drivers/coreboot/cbmem_console.h>
+#include <common/debug.h>
+#include <lib/coreboot.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+/*
+ * Structures describing coreboot's in-memory descriptor tables. See
+ * <coreboot>/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_MEMORY = 0x1,
+ CB_TAG_SERIAL = 0xf,
+ CB_TAG_CBMEM_CONSOLE = 0x17,
+} cb_tag_t;
+
+typedef struct {
+ uint32_t tag;
+ uint32_t size;
+ union {
+ coreboot_memrange_t memranges[COREBOOT_MAX_MEMRANGES];
+ coreboot_serial_t serial;
+ uint64_t uint64;
+ };
+} cb_entry_t;
+
+coreboot_memrange_t coreboot_memranges[COREBOOT_MAX_MEMRANGES];
+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.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);
+}
+
+coreboot_memory_t coreboot_get_memory_type(uintptr_t start, size_t size)
+{
+ int i;
+
+ for (i = 0; i < COREBOOT_MAX_MEMRANGES; i++) {
+ coreboot_memrange_t *range = &coreboot_memranges[i];
+
+ if (range->type == CB_MEM_NONE)
+ break; /* end of table reached */
+ if ((start >= range->start) &&
+ (start - range->start < range->size) &&
+ (size <= range->size - (start - range->start))) {
+ return range->type;
+ }
+ }
+
+ return CB_MEM_NONE;
+}
+
+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++) {
+ size_t size;
+ 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_MEMORY:
+ size = read_le32(&entry->size) -
+ offsetof(cb_entry_t, memranges);
+ if (size > sizeof(coreboot_memranges)) {
+ ERROR("Need to truncate coreboot memranges!\n");
+ size = sizeof(coreboot_memranges);
+ }
+ memcpy(&coreboot_memranges, &entry->memranges, size);
+ break;
+ 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);
+ }
+}
diff --git a/lib/cpus/aarch32/aem_generic.S b/lib/cpus/aarch32/aem_generic.S
new file mode 100644
index 0000000..7bd586a
--- /dev/null
+++ b/lib/cpus/aarch32/aem_generic.S
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <aem_generic.h>
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cpu_macros.S>
+
+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
diff --git a/lib/cpus/aarch32/cortex_a12.S b/lib/cpus/aarch32/cortex_a12.S
new file mode 100644
index 0000000..5300fe0
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a12.S
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a12.h>
+#include <cpu_macros.S>
+
+ .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
diff --git a/lib/cpus/aarch32/cortex_a15.S b/lib/cpus/aarch32/cortex_a15.S
new file mode 100644
index 0000000..1143e9b
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a15.S
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2016-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a15.h>
+#include <cpu_macros.S>
+
+/*
+ * 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
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov r0, #ERRATA_APPLIES
+#else
+ mov r0, #ERRATA_MISSING
+#endif
+ bx lr
+endfunc check_errata_cve_2022_23960
+
+#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
+ report_errata WORKAROUND_CVE_2022_23960, cortex_a15, cve_2022_23960
+
+ 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 || WORKAROUND_CVE_2022_23960)
+ ldcopr r0, ACTLR
+ orr r0, #CORTEX_A15_ACTLR_INV_BTB_BIT
+ stcopr r0, ACTLR
+ ldr r0, =wa_cve_2017_5715_icache_inv_vbar
+ 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
diff --git a/lib/cpus/aarch32/cortex_a17.S b/lib/cpus/aarch32/cortex_a17.S
new file mode 100644
index 0000000..b8abd33
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a17.S
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a17.h>
+#include <cpu_macros.S>
+
+ .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
diff --git a/lib/cpus/aarch32/cortex_a32.S b/lib/cpus/aarch32/cortex_a32.S
new file mode 100644
index 0000000..c262276
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a32.S
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a32.h>
+#include <cpu_macros.S>
+
+
+ /* ---------------------------------------------
+ * 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
diff --git a/lib/cpus/aarch32/cortex_a5.S b/lib/cpus/aarch32/cortex_a5.S
new file mode 100644
index 0000000..8abb66f
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a5.S
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a5.h>
+#include <cpu_macros.S>
+
+ .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
diff --git a/lib/cpus/aarch32/cortex_a53.S b/lib/cpus/aarch32/cortex_a53.S
new file mode 100644
index 0000000..6e3ff81
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a53.S
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <common/debug.h>
+#include <cortex_a53.h>
+#include <cpu_macros.S>
+
+#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
diff --git a/lib/cpus/aarch32/cortex_a57.S b/lib/cpus/aarch32/cortex_a57.S
new file mode 100644
index 0000000..18ee1f9
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a57.S
@@ -0,0 +1,618 @@
+/*
+ * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <common/debug.h>
+#include <cortex_a57.h>
+#include <cpu_macros.S>
+
+ /* ---------------------------------------------
+ * 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
+
+func check_errata_cve_2022_23960
+ mov r0, #ERRATA_MISSING
+ bx lr
+endfunc check_errata_cve_2022_23960
+
+ /* -------------------------------------------------
+ * 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
+ report_errata WORKAROUND_CVE_2022_23960, cortex_a57, cve_2022_23960
+
+ 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
diff --git a/lib/cpus/aarch32/cortex_a7.S b/lib/cpus/aarch32/cortex_a7.S
new file mode 100644
index 0000000..4d4bb77
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a7.S
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a7.h>
+#include <cpu_macros.S>
+
+ .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
diff --git a/lib/cpus/aarch32/cortex_a72.S b/lib/cpus/aarch32/cortex_a72.S
new file mode 100644
index 0000000..03914b2
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a72.S
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <common/debug.h>
+#include <cortex_a72.h>
+#include <cpu_macros.S>
+
+ /* ---------------------------------------------
+ * 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
+
+func check_errata_cve_2022_23960
+ mov r0, #ERRATA_MISSING
+ bx lr
+endfunc check_errata_cve_2022_23960
+
+ /* -------------------------------------------------
+ * 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
+ report_errata WORKAROUND_CVE_2022_23960, cortex_a72, cve_2022_23960
+
+ 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
diff --git a/lib/cpus/aarch32/cortex_a9.S b/lib/cpus/aarch32/cortex_a9.S
new file mode 100644
index 0000000..7200343
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a9.S
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a9.h>
+#include <cpu_macros.S>
+
+ .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
diff --git a/lib/cpus/aarch32/cpu_helpers.S b/lib/cpus/aarch32/cpu_helpers.S
new file mode 100644
index 0000000..6ed800c
--- /dev/null
+++ b/lib/cpus/aarch32/cpu_helpers.S
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cpu_macros.S>
+#include <common/bl_common.h>
+#include <lib/el3_runtime/cpu_data.h>
+
+#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]
+#if ENABLE_ASSERTIONS
+ cmp r1, #0
+ ASM_ASSERT(ne)
+#endif
+ 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)
+#if ENABLE_ASSERTIONS
+ cmp r0, #0
+ ASM_ASSERT(ne)
+#endif
+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
+#if ENABLE_ASSERTIONS
+ cmp r0, #0
+ ASM_ASSERT(ne)
+#endif
+ ldr r1, [r0, #CPU_DATA_CPU_OPS_PTR]
+#if ENABLE_ASSERTIONS
+ cmp r1, #0
+ ASM_ASSERT(ne)
+#endif
+ 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
diff --git a/lib/cpus/aarch64/a64fx.S b/lib/cpus/aarch64/a64fx.S
new file mode 100644
index 0000000..54c20c3
--- /dev/null
+++ b/lib/cpus/aarch64/a64fx.S
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2022, Fujitsu Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <a64fx.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+func a64fx_core_pwr_dwn
+endfunc a64fx_core_pwr_dwn
+
+func a64fx_cluster_pwr_dwn
+endfunc a64fx_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for A64FX. Must follow AAPCS.
+ */
+func a64fx_errata_report
+ ret
+endfunc a64fx_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.a64fx_regs, "aS"
+a64fx_regs: /* The ascii list of register names to be reported */
+ .asciz ""
+
+func a64fx_cpu_reg_dump
+ adr x6, a64fx_regs
+ ret
+endfunc a64fx_cpu_reg_dump
+
+declare_cpu_ops a64fx, A64FX_MIDR, CPU_NO_RESET_FUNC \
+ a64fx_core_pwr_dwn, \
+ a64fx_cluster_pwr_dwn
+
diff --git a/lib/cpus/aarch64/aem_generic.S b/lib/cpus/aarch64/aem_generic.S
new file mode 100644
index 0000000..6291e43
--- /dev/null
+++ b/lib/cpus/aarch64/aem_generic.S
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <aem_generic.h>
+#include <arch.h>
+#include <asm_macros.S>
+#include <cpu_macros.S>
+
+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
diff --git a/lib/cpus/aarch64/cortex_a35.S b/lib/cpus/aarch64/cortex_a35.S
new file mode 100644
index 0000000..be3c652
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a35.S
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a35.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+ /* ---------------------------------------------
+ * 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
diff --git a/lib/cpus/aarch64/cortex_a510.S b/lib/cpus/aarch64/cortex_a510.S
new file mode 100644
index 0000000..f7f8027
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a510.S
@@ -0,0 +1,500 @@
+/*
+ * Copyright (c) 2022, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a510.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Cortex-A510 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Cortex-A510 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex-A510 Errata #1922240.
+ * This applies only to revision r0p0 (fixed in r0p1)
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1, x17
+ * --------------------------------------------------
+ */
+func errata_cortex_a510_1922240_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_1922240
+ cbz x0, 1f
+
+ /* Apply the workaround by setting IMP_CMPXACTLR_EL1[11:10] = 0b11. */
+ mrs x0, CORTEX_A510_CMPXACTLR_EL1
+ mov x1, #3
+ bfi x0, x1, #10, #2
+ msr CORTEX_A510_CMPXACTLR_EL1, x0
+
+1:
+ ret x17
+endfunc errata_cortex_a510_1922240_wa
+
+func check_errata_1922240
+ /* Applies to r0p0 only */
+ mov x1, #0x00
+ b cpu_rev_var_ls
+endfunc check_errata_1922240
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex-A510 Errata #2288014.
+ * This applies only to revisions r0p0, r0p1, r0p2,
+ * r0p3 and r1p0. (fixed in r1p1)
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1, x17
+ * --------------------------------------------------
+ */
+func errata_cortex_a510_2288014_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_2288014
+ cbz x0, 1f
+
+ /* Apply the workaround by setting IMP_CPUACTLR_EL1[18] = 0b1. */
+ mrs x0, CORTEX_A510_CPUACTLR_EL1
+ mov x1, #1
+ bfi x0, x1, #18, #1
+ msr CORTEX_A510_CPUACTLR_EL1, x0
+
+1:
+ ret x17
+endfunc errata_cortex_a510_2288014_wa
+
+func check_errata_2288014
+ /* Applies to r1p0 and below */
+ mov x1, #0x10
+ b cpu_rev_var_ls
+endfunc check_errata_2288014
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex-A510 Errata #2042739.
+ * This applies only to revisions r0p0, r0p1 and r0p2.
+ * (fixed in r0p3)
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1, x17
+ * --------------------------------------------------
+ */
+func errata_cortex_a510_2042739_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_2042739
+ cbz x0, 1f
+
+ /* Apply the workaround by disabling ReadPreferUnique. */
+ mrs x0, CORTEX_A510_CPUECTLR_EL1
+ mov x1, #CORTEX_A510_CPUECTLR_EL1_READPREFERUNIQUE_DISABLE
+ bfi x0, x1, #CORTEX_A510_CPUECTLR_EL1_READPREFERUNIQUE_SHIFT, #1
+ msr CORTEX_A510_CPUECTLR_EL1, x0
+
+1:
+ ret x17
+endfunc errata_cortex_a510_2042739_wa
+
+func check_errata_2042739
+ /* Applies to revisions r0p0 - r0p2 */
+ mov x1, #0x02
+ b cpu_rev_var_ls
+endfunc check_errata_2042739
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex-A510 Errata #2041909.
+ * This applies only to revision r0p2 and it is fixed in
+ * r0p3. The issue is also present in r0p0 and r0p1 but
+ * there is no workaround in those revisions.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1, x2, x17
+ * --------------------------------------------------
+ */
+func errata_cortex_a510_2041909_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_2041909
+ cbz x0, 1f
+
+ /* Apply workaround */
+ mov x0, xzr
+ msr S3_6_C15_C4_0, x0
+ isb
+
+ mov x0, #0x8500000
+ msr S3_6_C15_C4_2, x0
+
+ mov x0, #0x1F700000
+ movk x0, #0x8, lsl #32
+ msr S3_6_C15_C4_3, x0
+
+ mov x0, #0x3F1
+ movk x0, #0x110, lsl #16
+ msr S3_6_C15_C4_1, x0
+ isb
+
+1:
+ ret x17
+endfunc errata_cortex_a510_2041909_wa
+
+func check_errata_2041909
+ /* Applies only to revision r0p2 */
+ mov x1, #0x02
+ mov x2, #0x02
+ b cpu_rev_var_range
+endfunc check_errata_2041909
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex-A510 Errata #2250311.
+ * This applies only to revisions r0p0, r0p1, r0p2,
+ * r0p3 and r1p0, and is fixed in r1p1.
+ * This workaround is not a typical errata fix. MPMM
+ * is disabled here, but this conflicts with the BL31
+ * MPMM support. So in addition to simply disabling
+ * the feature, a flag is set in the MPMM library
+ * indicating that it should not be enabled even if
+ * ENABLE_MPMM=1.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1, x17
+ * --------------------------------------------------
+ */
+func errata_cortex_a510_2250311_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_2250311
+ cbz x0, 1f
+
+ /* Disable MPMM */
+ mrs x0, CPUMPMMCR_EL3
+ bfm x0, xzr, #0, #0 /* bfc instruction does not work in GCC */
+ msr CPUMPMMCR_EL3, x0
+
+#if ENABLE_MPMM && IMAGE_BL31
+ /* If ENABLE_MPMM is set, tell the runtime lib to skip enabling it. */
+ bl mpmm_errata_disable
+#endif
+
+1:
+ ret x17
+endfunc errata_cortex_a510_2250311_wa
+
+func check_errata_2250311
+ /* Applies to r1p0 and lower */
+ mov x1, #0x10
+ b cpu_rev_var_ls
+endfunc check_errata_2250311
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex-A510 Errata #2218950.
+ * This applies only to revisions r0p0, r0p1, r0p2,
+ * r0p3 and r1p0, and is fixed in r1p1.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1, x17
+ * --------------------------------------------------
+ */
+func errata_cortex_a510_2218950_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_2218950
+ cbz x0, 1f
+
+ /* Source register for BFI */
+ mov x1, #1
+
+ /* Set bit 18 in CPUACTLR_EL1 */
+ mrs x0, CORTEX_A510_CPUACTLR_EL1
+ bfi x0, x1, #18, #1
+ msr CORTEX_A510_CPUACTLR_EL1, x0
+
+ /* Set bit 25 in CMPXACTLR_EL1 */
+ mrs x0, CORTEX_A510_CMPXACTLR_EL1
+ bfi x0, x1, #25, #1
+ msr CORTEX_A510_CMPXACTLR_EL1, x0
+
+1:
+ ret x17
+endfunc errata_cortex_a510_2218950_wa
+
+func check_errata_2218950
+ /* Applies to r1p0 and lower */
+ mov x1, #0x10
+ b cpu_rev_var_ls
+endfunc check_errata_2218950
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex-A510 Errata #2172148.
+ * This applies only to revisions r0p0, r0p1, r0p2,
+ * r0p3 and r1p0, and is fixed in r1p1.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1, x17
+ * --------------------------------------------------
+ */
+func errata_cortex_a510_2172148_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_2172148
+ cbz x0, 1f
+
+ /*
+ * Force L2 allocation of transient lines by setting
+ * CPUECTLR_EL1.RSCTL=0b01 and CPUECTLR_EL1.NTCTL=0b01.
+ */
+ mrs x0, CORTEX_A510_CPUECTLR_EL1
+ mov x1, #1
+ bfi x0, x1, #CORTEX_A510_CPUECTLR_EL1_RSCTL_SHIFT, #2
+ bfi x0, x1, #CORTEX_A510_CPUECTLR_EL1_NTCTL_SHIFT, #2
+ msr CORTEX_A510_CPUECTLR_EL1, x0
+
+1:
+ ret x17
+endfunc errata_cortex_a510_2172148_wa
+
+func check_errata_2172148
+ /* Applies to r1p0 and lower */
+ mov x1, #0x10
+ b cpu_rev_var_ls
+endfunc check_errata_2172148
+
+ /* ----------------------------------------------------
+ * Errata Workaround for Cortex-A510 Errata #2347730.
+ * This applies to revisions r0p0 - r0p3, r1p0, r1p1.
+ * It is fixed in r1p2.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x1, x17
+ * ----------------------------------------------------
+ */
+func errata_cortex_a510_2347730_wa
+ mov x17, x30
+ bl check_errata_2347730
+ cbz x0, 1f
+
+ /*
+ * Set CPUACTLR_EL1[17] to 1'b1, which disables
+ * specific microarchitectural clock gating
+ * behaviour.
+ */
+ mrs x1, CORTEX_A510_CPUACTLR_EL1
+ orr x1, x1, CORTEX_A510_CPUACTLR_EL1_BIT_17
+ msr CORTEX_A510_CPUACTLR_EL1, x1
+1:
+ ret x17
+endfunc errata_cortex_a510_2347730_wa
+
+func check_errata_2347730
+ /* Applies to revisions r1p1 and lower. */
+ mov x1, #0x11
+ b cpu_rev_var_ls
+endfunc check_errata_2347730
+
+ /*---------------------------------------------------
+ * Errata Workaround for Cortex-A510 Errata #2371937.
+ * This applies to revisions r1p1 and lower, and is
+ * fixed in r1p2.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1, x17
+ *---------------------------------------------------
+ */
+func errata_cortex_a510_2371937_wa
+ mov x17, x30
+ bl check_errata_2371937
+ cbz x0, 1f
+
+ /*
+ * Cacheable atomic operations can be forced
+ * to be executed near by setting
+ * IMP_CPUECTLR_EL1.ATOM=0b010. ATOM is found
+ * in [40:38] of CPUECTLR_EL1.
+ */
+ mrs x0, CORTEX_A510_CPUECTLR_EL1
+ mov x1, CORTEX_A510_CPUECTLR_EL1_ATOM_EXECALLINSTRNEAR
+ bfi x0, x1, CORTEX_A510_CPUECTLR_EL1_ATOM, #3
+ msr CORTEX_A510_CPUECTLR_EL1, x0
+1:
+ ret x17
+endfunc errata_cortex_a510_2371937_wa
+
+func check_errata_2371937
+ /* Applies to r1p1 and lower */
+ mov x1, #0x11
+ b cpu_rev_var_ls
+endfunc check_errata_2371937
+
+ /* ------------------------------------------------------
+ * Errata Workaround for Cortex-A510 Errata #2666669
+ * This applies to revisions r1p1 and lower, and is fixed
+ * in r1p2.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1, x17
+ * ------------------------------------------------------
+ */
+func errata_cortex_a510_2666669_wa
+ mov x17, x30
+ bl check_errata_2666669
+ cbz x0, 1f
+
+ /*
+ * Workaround will set IMP_CPUACTLR_EL1[38]
+ * to 0b1.
+ */
+ mrs x1, CORTEX_A510_CPUACTLR_EL1
+ orr x1, x1, CORTEX_A510_CPUACTLR_EL1_BIT_38
+ msr CORTEX_A510_CPUACTLR_EL1, x1
+1:
+ ret x17
+endfunc errata_cortex_a510_2666669_wa
+
+func check_errata_2666669
+ /* Applies to r1p1 and lower */
+ mov x1, #0x11
+ b cpu_rev_var_ls
+endfunc check_errata_2666669
+
+ /* ----------------------------------------------------
+ * HW will do the cache maintenance while powering down
+ * ----------------------------------------------------
+ */
+func cortex_a510_core_pwr_dwn
+ /* ---------------------------------------------------
+ * Enable CPU power down bit in power control register
+ * ---------------------------------------------------
+ */
+ mrs x0, CORTEX_A510_CPUPWRCTLR_EL1
+ orr x0, x0, #CORTEX_A510_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+ msr CORTEX_A510_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+endfunc cortex_a510_core_pwr_dwn
+
+ /*
+ * Errata printing function for Cortex-A510. Must follow AAPCS.
+ */
+#if REPORT_ERRATA
+func cortex_a510_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_A510_1922240, cortex_a510, 1922240
+ report_errata ERRATA_A510_2041909, cortex_a510, 2041909
+ report_errata ERRATA_A510_2042739, cortex_a510, 2042739
+ report_errata ERRATA_A510_2172148, cortex_a510, 2172148
+ report_errata ERRATA_A510_2218950, cortex_a510, 2218950
+ report_errata ERRATA_A510_2250311, cortex_a510, 2250311
+ report_errata ERRATA_A510_2288014, cortex_a510, 2288014
+ report_errata ERRATA_A510_2347730, cortex_a510, 2347730
+ report_errata ERRATA_A510_2371937, cortex_a510, 2371937
+ report_errata ERRATA_A510_2666669, cortex_a510, 2666669
+ report_errata ERRATA_DSU_2313941, cortex_a510, dsu_2313941
+
+ ldp x8, x30, [sp], #16
+ ret
+endfunc cortex_a510_errata_report
+#endif
+
+func cortex_a510_reset_func
+ mov x19, x30
+
+ /* Disable speculative loads */
+ msr SSBS, xzr
+
+ /* Get the CPU revision and stash it in x18. */
+ bl cpu_get_rev_var
+ mov x18, x0
+
+#if ERRATA_DSU_2313941
+ bl errata_dsu_2313941_wa
+#endif
+
+#if ERRATA_A510_1922240
+ mov x0, x18
+ bl errata_cortex_a510_1922240_wa
+#endif
+
+#if ERRATA_A510_2288014
+ mov x0, x18
+ bl errata_cortex_a510_2288014_wa
+#endif
+
+#if ERRATA_A510_2042739
+ mov x0, x18
+ bl errata_cortex_a510_2042739_wa
+#endif
+
+#if ERRATA_A510_2041909
+ mov x0, x18
+ bl errata_cortex_a510_2041909_wa
+#endif
+
+#if ERRATA_A510_2250311
+ mov x0, x18
+ bl errata_cortex_a510_2250311_wa
+#endif
+
+#if ERRATA_A510_2218950
+ mov x0, x18
+ bl errata_cortex_a510_2218950_wa
+#endif
+
+#if ERRATA_A510_2371937
+ mov x0, x18
+ bl errata_cortex_a510_2371937_wa
+#endif
+
+#if ERRATA_A510_2172148
+ mov x0, x18
+ bl errata_cortex_a510_2172148_wa
+#endif
+
+#if ERRATA_A510_2347730
+ mov x0, x18
+ bl errata_cortex_a510_2347730_wa
+#endif
+
+#if ERRATA_A510_2666669
+ mov x0, x18
+ bl errata_cortex_a510_2666669_wa
+#endif
+
+ isb
+ ret x19
+endfunc cortex_a510_reset_func
+
+ /* ---------------------------------------------
+ * This function provides Cortex-A510 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_a510_regs, "aS"
+cortex_a510_regs: /* The ascii list of register names to be reported */
+ .asciz "cpuectlr_el1", ""
+
+func cortex_a510_cpu_reg_dump
+ adr x6, cortex_a510_regs
+ mrs x8, CORTEX_A510_CPUECTLR_EL1
+ ret
+endfunc cortex_a510_cpu_reg_dump
+
+declare_cpu_ops cortex_a510, CORTEX_A510_MIDR, \
+ cortex_a510_reset_func, \
+ cortex_a510_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a53.S b/lib/cpus/aarch64/cortex_a53.S
new file mode 100644
index 0000000..df11d86
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a53.S
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <cortex_a53.h>
+#include <cpu_macros.S>
+#include <lib/cpus/errata_report.h>
+#include <plat_macros.S>
+
+#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
+
+ /* --------------------------------------------------
+ * Errata workaround for Cortex A53 Errata #1530924.
+ * This applies to all revisions of Cortex A53.
+ * --------------------------------------------------
+ */
+func check_errata_1530924
+#if ERRATA_A53_1530924
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_1530924
+
+ /* -------------------------------------------------
+ * 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
+ report_errata ERRATA_A53_1530924, cortex_a53, 1530924
+
+ 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
diff --git a/lib/cpus/aarch64/cortex_a55.S b/lib/cpus/aarch64/cortex_a55.S
new file mode 100644
index 0000000..0e0388b
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a55.S
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a55.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Cortex-A55 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+ .globl cortex_a55_reset_func
+ .globl cortex_a55_core_pwr_dwn
+ /* --------------------------------------------------
+ * 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
+
+ /* --------------------------------------------------
+ * Errata workaround for Cortex A55 Errata #1530923.
+ * This applies to all revisions of Cortex A55.
+ * --------------------------------------------------
+ */
+func check_errata_1530923
+#if ERRATA_A55_1530923
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_1530923
+
+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
+ report_errata ERRATA_A55_1530923, cortex_a55, 1530923
+
+ 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
diff --git a/lib/cpus/aarch64/cortex_a57.S b/lib/cpus/aarch64/cortex_a57.S
new file mode 100644
index 0000000..3766ec7
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a57.S
@@ -0,0 +1,686 @@
+/*
+ * Copyright (c) 2014-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <cortex_a57.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+ /* ---------------------------------------------
+ * 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
+
+ /* --------------------------------------------------
+ * Errata workaround for Cortex A57 Errata #1319537.
+ * This applies to all revisions of Cortex A57.
+ * --------------------------------------------------
+ */
+func check_errata_1319537
+#if ERRATA_A57_1319537
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_1319537
+
+ /* -------------------------------------------------
+ * 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 || WORKAROUND_CVE_2022_23960 )
+ /* ---------------------------------------------------------------
+ * Override vector table & enable existing workaround if either of
+ * the build flags are enabled
+ * ---------------------------------------------------------------
+ */
+ 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
+
+#if A57_ENABLE_NONCACHEABLE_LOAD_FWD
+ /* ---------------------------------------------
+ * Enable higher performance non-cacheable load
+ * forwarding
+ * ---------------------------------------------
+ */
+ mrs x0, CORTEX_A57_CPUACTLR_EL1
+ orr x0, x0, #CORTEX_A57_CPUACTLR_EL1_EN_NC_LOAD_FWD
+ msr CORTEX_A57_CPUACTLR_EL1, x0
+#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
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_cve_2022_23960
+
+func check_smccc_arch_workaround_3
+ mov x0, #ERRATA_APPLIES
+ ret
+endfunc check_smccc_arch_workaround_3
+
+ /* ----------------------------------------------------
+ * 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 ERRATA_A57_1319537, cortex_a57, 1319537
+ report_errata WORKAROUND_CVE_2017_5715, cortex_a57, cve_2017_5715
+ report_errata WORKAROUND_CVE_2018_3639, cortex_a57, cve_2018_3639
+ report_errata WORKAROUND_CVE_2022_23960, cortex_a57, cve_2022_23960
+
+ 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, \
+ check_smccc_arch_workaround_3, \
+ cortex_a57_core_pwr_dwn, \
+ cortex_a57_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a65.S b/lib/cpus/aarch64/cortex_a65.S
new file mode 100644
index 0000000..666324c
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a65.S
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <cortex_a65.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+/* 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
diff --git a/lib/cpus/aarch64/cortex_a65ae.S b/lib/cpus/aarch64/cortex_a65ae.S
new file mode 100644
index 0000000..ac6583e
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a65ae.S
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <cortex_a65ae.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+/* 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
diff --git a/lib/cpus/aarch64/cortex_a710.S b/lib/cpus/aarch64/cortex_a710.S
new file mode 100644
index 0000000..fed3f33
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a710.S
@@ -0,0 +1,668 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a710.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Cortex A710 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Cortex A710 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+#if WORKAROUND_CVE_2022_23960
+ wa_cve_2022_23960_bhb_vector_table CORTEX_A710_BHB_LOOP_COUNT, cortex_a710
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+/* --------------------------------------------------
+ * Errata Workaround for Cortex-A710 Erratum 1987031.
+ * This applies to revision r0p0, r1p0 and r2p0 of Cortex-A710. It is still
+ * open.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a710_1987031_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_1987031
+ cbz x0, 1f
+
+ /* Apply instruction patching sequence */
+ ldr x0,=0x6
+ msr S3_6_c15_c8_0,x0
+ ldr x0,=0xF3A08002
+ msr S3_6_c15_c8_2,x0
+ ldr x0,=0xFFF0F7FE
+ msr S3_6_c15_c8_3,x0
+ ldr x0,=0x40000001003ff
+ msr S3_6_c15_c8_1,x0
+ ldr x0,=0x7
+ msr S3_6_c15_c8_0,x0
+ ldr x0,=0xBF200000
+ msr S3_6_c15_c8_2,x0
+ ldr x0,=0xFFEF0000
+ msr S3_6_c15_c8_3,x0
+ ldr x0,=0x40000001003f3
+ msr S3_6_c15_c8_1,x0
+ isb
+1:
+ ret x17
+endfunc errata_a710_1987031_wa
+
+func check_errata_1987031
+ /* Applies to r0p0, r1p0 and r2p0 */
+ mov x1, #0x20
+ b cpu_rev_var_ls
+endfunc check_errata_1987031
+
+/* --------------------------------------------------
+ * Errata Workaround for Cortex-A710 Erratum 2081180.
+ * This applies to revision r0p0, r1p0 and r2p0 of Cortex-A710.
+ * It is still open.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a710_2081180_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_2081180
+ cbz x0, 1f
+
+ /* Apply instruction patching sequence */
+ ldr x0,=0x3
+ msr S3_6_c15_c8_0,x0
+ ldr x0,=0xF3A08002
+ msr S3_6_c15_c8_2,x0
+ ldr x0,=0xFFF0F7FE
+ msr S3_6_c15_c8_3,x0
+ ldr x0,=0x10002001003FF
+ msr S3_6_c15_c8_1,x0
+ ldr x0,=0x4
+ msr S3_6_c15_c8_0,x0
+ ldr x0,=0xBF200000
+ msr S3_6_c15_c8_2,x0
+ ldr x0,=0xFFEF0000
+ msr S3_6_c15_c8_3,x0
+ ldr x0,=0x10002001003F3
+ msr S3_6_c15_c8_1,x0
+ isb
+1:
+ ret x17
+endfunc errata_a710_2081180_wa
+
+func check_errata_2081180
+ /* Applies to r0p0, r1p0 and r2p0 */
+ mov x1, #0x20
+ b cpu_rev_var_ls
+endfunc check_errata_2081180
+
+/* ---------------------------------------------------------------------
+ * Errata Workaround for Cortex-A710 Erratum 2055002.
+ * This applies to revision r1p0, r2p0 of Cortex-A710 and is still open.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * ---------------------------------------------------------------------
+ */
+func errata_a710_2055002_wa
+ /* Compare x0 against revision r2p0 */
+ mov x17, x30
+ bl check_errata_2055002
+ cbz x0, 1f
+ mrs x1, CORTEX_A710_CPUACTLR_EL1
+ orr x1, x1, CORTEX_A710_CPUACTLR_EL1_BIT_46
+ msr CORTEX_A710_CPUACTLR_EL1, x1
+1:
+ ret x17
+endfunc errata_a710_2055002_wa
+
+func check_errata_2055002
+ /* Applies to r1p0, r2p0 */
+ mov x1, #0x20
+ b cpu_rev_var_ls
+endfunc check_errata_2055002
+
+/* -------------------------------------------------------------
+ * Errata Workaround for Cortex-A710 Erratum 2017096.
+ * This applies to revisions r0p0, r1p0 and r2p0 of Cortex-A710.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * -------------------------------------------------------------
+ */
+func errata_a710_2017096_wa
+ /* Compare x0 against revision r0p0 to r2p0 */
+ mov x17, x30
+ bl check_errata_2017096
+ cbz x0, 1f
+ mrs x1, CORTEX_A710_CPUECTLR_EL1
+ orr x1, x1, CORTEX_A710_CPUECTLR_EL1_PFSTIDIS_BIT
+ msr CORTEX_A710_CPUECTLR_EL1, x1
+
+1:
+ ret x17
+endfunc errata_a710_2017096_wa
+
+func check_errata_2017096
+ /* Applies to r0p0, r1p0, r2p0 */
+ mov x1, #0x20
+ b cpu_rev_var_ls
+endfunc check_errata_2017096
+
+
+/* ---------------------------------------------------------------------
+ * Errata Workaround for Cortex-A710 Erratum 2083908.
+ * This applies to revision r2p0 of Cortex-A710 and is still open.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * ---------------------------------------------------------------------
+ */
+func errata_a710_2083908_wa
+ /* Compare x0 against revision r2p0 */
+ mov x17, x30
+ bl check_errata_2083908
+ cbz x0, 1f
+ mrs x1, CORTEX_A710_CPUACTLR5_EL1
+ orr x1, x1, CORTEX_A710_CPUACTLR5_EL1_BIT_13
+ msr CORTEX_A710_CPUACTLR5_EL1, x1
+1:
+ ret x17
+endfunc errata_a710_2083908_wa
+
+func check_errata_2083908
+ /* Applies to r2p0 */
+ mov x1, #CPU_REV(2, 0)
+ mov x2, #CPU_REV(2, 0)
+ b cpu_rev_var_range
+endfunc check_errata_2083908
+
+/* ---------------------------------------------------------------------
+ * Errata Workaround for Cortex-A710 Erratum 2058056.
+ * This applies to revisions r0p0, r1p0 and r2p0 of Cortex-A710 and is still
+ * open.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * ---------------------------------------------------------------------
+ */
+func errata_a710_2058056_wa
+ /* Compare x0 against revision r2p0 */
+ mov x17, x30
+ bl check_errata_2058056
+ cbz x0, 1f
+ mrs x1, CORTEX_A710_CPUECTLR2_EL1
+ mov x0, #CORTEX_A710_CPUECTLR2_EL1_PF_MODE_CNSRV
+ bfi x1, x0, #CPUECTLR2_EL1_PF_MODE_LSB, #CPUECTLR2_EL1_PF_MODE_WIDTH
+ msr CORTEX_A710_CPUECTLR2_EL1, x1
+1:
+ ret x17
+endfunc errata_a710_2058056_wa
+
+func check_errata_2058056
+ /* Applies to r0p0, r1p0 and r2p0 */
+ mov x1, #0x20
+ b cpu_rev_var_ls
+endfunc check_errata_2058056
+
+/* --------------------------------------------------
+ * Errata Workaround for Cortex-A710 Erratum 2267065.
+ * This applies to revisions r0p0, r1p0 and r2p0.
+ * It is fixed in r2p1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x1, x17
+ * --------------------------------------------------
+ */
+func errata_a710_2267065_wa
+ /* Compare x0 against revision r2p0 */
+ mov x17, x30
+ bl check_errata_2267065
+ cbz x0, 1f
+
+ /* Apply instruction patching sequence */
+ mrs x1, CORTEX_A710_CPUACTLR_EL1
+ orr x1, x1, CORTEX_A710_CPUACTLR_EL1_BIT_22
+ msr CORTEX_A710_CPUACTLR_EL1, x1
+1:
+ ret x17
+endfunc errata_a710_2267065_wa
+
+func check_errata_2267065
+ /* Applies to r0p0, r1p0 and r2p0 */
+ mov x1, #0x20
+ b cpu_rev_var_ls
+endfunc check_errata_2267065
+
+/* ---------------------------------------------------------------
+ * Errata Workaround for Cortex-A710 Erratum 2136059.
+ * This applies to revision r0p0, r1p0 and r2p0.
+ * It is fixed in r2p1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * ---------------------------------------------------------------
+ */
+func errata_a710_2136059_wa
+ /* Compare x0 against revision r2p0 */
+ mov x17, x30
+ bl check_errata_2136059
+ cbz x0, 1f
+
+ /* Apply the workaround */
+ mrs x1, CORTEX_A710_CPUACTLR5_EL1
+ orr x1, x1, CORTEX_A710_CPUACTLR5_EL1_BIT_44
+ msr CORTEX_A710_CPUACTLR5_EL1, x1
+
+1:
+ ret x17
+endfunc errata_a710_2136059_wa
+
+func check_errata_2136059
+ /* Applies to r0p0, r1p0 and r2p0 */
+ mov x1, #0x20
+ b cpu_rev_var_ls
+endfunc check_errata_2136059
+
+/* ----------------------------------------------------------------
+ * Errata workaround for Cortex-A710 Erratum 2147715.
+ * This applies to revision r2p0, and is fixed in r2p1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1, x17
+ * ----------------------------------------------------------------
+ */
+func errata_a710_2147715_wa
+ mov x17, x30
+ bl check_errata_2147715
+ cbz x0, 1f
+
+ /* Apply workaround; set CPUACTLR_EL1[22]
+ * to 1, which will cause the CFP instruction
+ * to invalidate all branch predictor resources
+ * regardless of context.
+ */
+ mrs x1, CORTEX_A710_CPUACTLR_EL1
+ orr x1, x1, CORTEX_A710_CPUACTLR_EL1_BIT_22
+ msr CORTEX_A710_CPUACTLR_EL1, x1
+1:
+ ret x17
+endfunc errata_a710_2147715_wa
+
+func check_errata_2147715
+ mov x1, #0x20
+ mov x2, #0x20
+ b cpu_rev_var_range
+endfunc check_errata_2147715
+
+/* ---------------------------------------------------------------
+ * Errata Workaround for Cortex-A710 Erratum 2216384.
+ * This applies to revision r0p0, r1p0 and r2p0.
+ * It is fixed in r2p1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * ---------------------------------------------------------------
+ */
+func errata_a710_2216384_wa
+ /* Compare x0 against revision r2p0 */
+ mov x17, x30
+ bl check_errata_2216384
+ cbz x0, 1f
+
+ /* Apply workaround: set CPUACTLR5_EL1[17]
+ * to 1 and the following instruction
+ * patching sequence.
+ */
+ mrs x1, CORTEX_A710_CPUACTLR5_EL1
+ orr x1, x1, CORTEX_A710_CPUACTLR5_EL1_BIT_17
+ msr CORTEX_A710_CPUACTLR5_EL1, x1
+
+ ldr x0,=0x5
+ msr CORTEX_A710_CPUPSELR_EL3, x0
+ ldr x0,=0x10F600E000
+ msr CORTEX_A710_CPUPOR_EL3, x0
+ ldr x0,=0x10FF80E000
+ msr CORTEX_A710_CPUPMR_EL3, x0
+ ldr x0,=0x80000000003FF
+ msr CORTEX_A710_CPUPCR_EL3, x0
+ isb
+1:
+ ret x17
+endfunc errata_a710_2216384_wa
+
+func check_errata_2216384
+ /* Applies to r0p0, r1p0 and r2p0 */
+ mov x1, #0x20
+ b cpu_rev_var_ls
+endfunc check_errata_2216384
+
+/* ---------------------------------------------------------------
+ * Errata Workaround for Cortex-A710 Erratum 2282622.
+ * This applies to revision r0p0, r1p0 and r2p0.
+ * It is fixed in r2p1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1, x17
+ * ---------------------------------------------------------------
+ */
+func errata_a710_2282622_wa
+ /* Compare x0 against revision r2p0 */
+ mov x17, x30
+ bl check_errata_2282622
+ cbz x0, 1f
+
+ /* Apply the workaround */
+ mrs x1, CORTEX_A710_CPUACTLR2_EL1
+ orr x1, x1, BIT(0)
+ msr CORTEX_A710_CPUACTLR2_EL1, x1
+
+1:
+ ret x17
+endfunc errata_a710_2282622_wa
+
+func check_errata_2282622
+ /* Applies to r0p0, r1p0 and r2p0 */
+ mov x1, #0x20
+ b cpu_rev_var_ls
+endfunc check_errata_2282622
+
+/* ------------------------------------------------------------------------
+ * Errata Workaround for Cortex-A710 Erratum 2291219 on power down request.
+ * This applies to revision <= r2p0 and is fixed in r2p1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x1, x17
+ * ------------------------------------------------------------------------
+ */
+func errata_a710_2291219_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_2291219
+ cbz x0, 1f
+
+ /* Set bit 36 in ACTLR2_EL1 */
+ mrs x1, CORTEX_A710_CPUACTLR2_EL1
+ orr x1, x1, #CORTEX_A710_CPUACTLR2_EL1_BIT_36
+ msr CORTEX_A710_CPUACTLR2_EL1, x1
+1:
+ ret x17
+endfunc errata_a710_2291219_wa
+
+func check_errata_2291219
+ /* Applies to <= r2p0. */
+ mov x1, #0x20
+ b cpu_rev_var_ls
+endfunc check_errata_2291219
+
+/* ---------------------------------------------------------------
+ * Errata Workaround for Cortex-A710 Erratum 2008768.
+ * This applies to revision r0p0, r1p0 and r2p0.
+ * It is fixed in r2p1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1, x2, x17
+ * ---------------------------------------------------------------
+ */
+func errata_a710_2008768_wa
+ mov x17, x30
+ bl check_errata_2008768
+ cbz x0, 1f
+
+ /* Stash ERRSELR_EL1 in x2 */
+ mrs x2, ERRSELR_EL1
+
+ /* Select error record 0 and clear ED bit */
+ msr ERRSELR_EL1, xzr
+ mrs x1, ERXCTLR_EL1
+ bfi x1, xzr, #ERXCTLR_ED_SHIFT, #1
+ msr ERXCTLR_EL1, x1
+
+ /* Select error record 1 and clear ED bit */
+ mov x0, #1
+ msr ERRSELR_EL1, x0
+ mrs x1, ERXCTLR_EL1
+ bfi x1, xzr, #ERXCTLR_ED_SHIFT, #1
+ msr ERXCTLR_EL1, x1
+
+ /* Restore ERRSELR_EL1 from x2 */
+ msr ERRSELR_EL1, x2
+
+1:
+ ret x17
+endfunc errata_a710_2008768_wa
+
+func check_errata_2008768
+ /* Applies to r0p0, r1p0 and r2p0 */
+ mov x1, #0x20
+ b cpu_rev_var_ls
+endfunc check_errata_2008768
+
+/* -------------------------------------------------------
+ * Errata Workaround for Cortex-A710 Erratum 2371105.
+ * This applies to revisions <= r2p0 and is fixed in r2p1.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * -------------------------------------------------------
+ */
+func errata_a710_2371105_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_2371105
+ cbz x0, 1f
+
+ /* Set bit 40 in CPUACTLR2_EL1 */
+ mrs x1, CORTEX_A710_CPUACTLR2_EL1
+ orr x1, x1, #CORTEX_A710_CPUACTLR2_EL1_BIT_40
+ msr CORTEX_A710_CPUACTLR2_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_a710_2371105_wa
+
+func check_errata_2371105
+ /* Applies to <= r2p0. */
+ mov x1, #0x20
+ b cpu_rev_var_ls
+endfunc check_errata_2371105
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_cve_2022_23960
+
+ /* ----------------------------------------------------
+ * HW will do the cache maintenance while powering down
+ * ----------------------------------------------------
+ */
+func cortex_a710_core_pwr_dwn
+
+#if ERRATA_A710_2008768
+ mov x4, x30
+ bl cpu_get_rev_var
+ bl errata_a710_2008768_wa
+ mov x30, x4
+#endif
+
+#if ERRATA_A710_2291219
+ mov x15, x30
+ bl cpu_get_rev_var
+ bl errata_a710_2291219_wa
+ mov x30, x15
+#endif /* ERRATA_A710_2291219 */
+
+ /* ---------------------------------------------------
+ * Enable CPU power down bit in power control register
+ * ---------------------------------------------------
+ */
+ mrs x0, CORTEX_A710_CPUPWRCTLR_EL1
+ orr x0, x0, #CORTEX_A710_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+ msr CORTEX_A710_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+endfunc cortex_a710_core_pwr_dwn
+
+#if REPORT_ERRATA
+ /*
+ * Errata printing function for Cortex-A710. Must follow AAPCS.
+ */
+func cortex_a710_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_A710_1987031, cortex_a710, 1987031
+ report_errata ERRATA_A710_2081180, cortex_a710, 2081180
+ report_errata ERRATA_A710_2055002, cortex_a710, 2055002
+ report_errata ERRATA_A710_2017096, cortex_a710, 2017096
+ report_errata ERRATA_A710_2083908, cortex_a710, 2083908
+ report_errata ERRATA_A710_2058056, cortex_a710, 2058056
+ report_errata ERRATA_A710_2267065, cortex_a710, 2267065
+ report_errata ERRATA_A710_2136059, cortex_a710, 2136059
+ report_errata ERRATA_A710_2282622, cortex_a710, 2282622
+ report_errata ERRATA_A710_2008768, cortex_a710, 2008768
+ report_errata ERRATA_A710_2147715, cortex_a710, 2147715
+ report_errata ERRATA_A710_2216384, cortex_a710, 2216384
+ report_errata ERRATA_A710_2291219, cortex_a710, 2291219
+ report_errata ERRATA_A710_2371105, cortex_a710, 2371105
+ report_errata WORKAROUND_CVE_2022_23960, cortex_a710, cve_2022_23960
+ report_errata ERRATA_DSU_2313941, cortex_a710, dsu_2313941
+
+ ldp x8, x30, [sp], #16
+ ret
+endfunc cortex_a710_errata_report
+#endif
+
+func cortex_a710_reset_func
+ mov x19, x30
+
+ /* Disable speculative loads */
+ msr SSBS, xzr
+
+ bl cpu_get_rev_var
+ mov x18, x0
+
+#if ERRATA_DSU_2313941
+ bl errata_dsu_2313941_wa
+#endif
+
+#if ERRATA_A710_1987031
+ mov x0, x18
+ bl errata_a710_1987031_wa
+#endif
+
+#if ERRATA_A710_2081180
+ mov x0, x18
+ bl errata_a710_2081180_wa
+#endif
+
+#if ERRATA_A710_2055002
+ mov x0, x18
+ bl errata_a710_2055002_wa
+#endif
+
+#if ERRATA_A710_2017096
+ mov x0, x18
+ bl errata_a710_2017096_wa
+#endif
+
+#if ERRATA_A710_2083908
+ mov x0, x18
+ bl errata_a710_2083908_wa
+#endif
+
+#if ERRATA_A710_2058056
+ mov x0, x18
+ bl errata_a710_2058056_wa
+#endif
+
+#if ERRATA_A710_2267065
+ mov x0, x18
+ bl errata_a710_2267065_wa
+#endif
+
+#if ERRATA_A710_2136059
+ mov x0, x18
+ bl errata_a710_2136059_wa
+#endif
+
+#if ERRATA_A710_2147715
+ mov x0, x18
+ bl errata_a710_2147715_wa
+#endif
+
+#if ERRATA_A710_2216384
+ mov x0, x18
+ bl errata_a710_2216384_wa
+#endif /* ERRATA_A710_2216384 */
+
+#if ERRATA_A710_2282622
+ mov x0, x18
+ bl errata_a710_2282622_wa
+#endif
+
+#if ERRATA_A710_2371105
+ mov x0, x18
+ bl errata_a710_2371105_wa
+#endif
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2022_23960
+ /*
+ * The Cortex-A710 generic vectors are overridden to apply errata
+ * mitigation on exception entry from lower ELs.
+ */
+ adr x0, wa_cve_vbar_cortex_a710
+ msr vbar_el3, x0
+#endif /* IMAGE_BL31 && WORKAROUND_CVE_2022_23960 */
+
+ isb
+ ret x19
+endfunc cortex_a710_reset_func
+
+ /* ---------------------------------------------
+ * This function provides Cortex-A710 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_a710_regs, "aS"
+cortex_a710_regs: /* The ascii list of register names to be reported */
+ .asciz "cpuectlr_el1", ""
+
+func cortex_a710_cpu_reg_dump
+ adr x6, cortex_a710_regs
+ mrs x8, CORTEX_A710_CPUECTLR_EL1
+ ret
+endfunc cortex_a710_cpu_reg_dump
+
+declare_cpu_ops cortex_a710, CORTEX_A710_MIDR, \
+ cortex_a710_reset_func, \
+ cortex_a710_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a715.S b/lib/cpus/aarch64/cortex_a715.S
new file mode 100644
index 0000000..7603210
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a715.S
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_makalu.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Cortex Makalu must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Cortex Makalu supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+#if WORKAROUND_CVE_2022_23960
+ wa_cve_2022_23960_bhb_vector_table CORTEX_MAKALU_BHB_LOOP_COUNT, cortex_makalu
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_cve_2022_23960
+
+func cortex_makalu_reset_func
+ /* Disable speculative loads */
+ msr SSBS, xzr
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2022_23960
+ /*
+ * The Cortex Makalu generic vectors are overridden to apply errata
+ * mitigation on exception entry from lower ELs.
+ */
+ adr x0, wa_cve_vbar_cortex_makalu
+ msr vbar_el3, x0
+#endif /* IMAGE_BL31 && WORKAROUND_CVE_2022_23960 */
+
+ isb
+ ret
+endfunc cortex_makalu_reset_func
+
+ /* ----------------------------------------------------
+ * HW will do the cache maintenance while powering down
+ * ----------------------------------------------------
+ */
+func cortex_makalu_core_pwr_dwn
+ /* ---------------------------------------------------
+ * Enable CPU power down bit in power control register
+ * ---------------------------------------------------
+ */
+ mrs x0, CORTEX_MAKALU_CPUPWRCTLR_EL1
+ orr x0, x0, #CORTEX_MAKALU_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+ msr CORTEX_MAKALU_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+endfunc cortex_makalu_core_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex Makalu. Must follow AAPCS.
+ */
+func cortex_makalu_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_2022_23960, cortex_makalu, cve_2022_23960
+
+ ldp x8, x30, [sp], #16
+ ret
+endfunc cortex_makalu_errata_report
+#endif
+
+ /* ---------------------------------------------
+ * This function provides Cortex Makalu-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_makalu_regs, "aS"
+cortex_makalu_regs: /* The ascii list of register names to be reported */
+ .asciz "cpuectlr_el1", ""
+
+func cortex_makalu_cpu_reg_dump
+ adr x6, cortex_makalu_regs
+ mrs x8, CORTEX_MAKALU_CPUECTLR_EL1
+ ret
+endfunc cortex_makalu_cpu_reg_dump
+
+declare_cpu_ops cortex_makalu, CORTEX_MAKALU_MIDR, \
+ cortex_makalu_reset_func, \
+ cortex_makalu_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a72.S b/lib/cpus/aarch64/cortex_a72.S
new file mode 100644
index 0000000..de2d36e
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a72.S
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a72.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+#if WORKAROUND_CVE_2022_23960
+ wa_cve_2022_23960_bhb_vector_table CORTEX_A72_BHB_LOOP_COUNT, cortex_a72
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+ /* ---------------------------------------------
+ * 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
+
+ /* --------------------------------------------------
+ * Errata workaround for Cortex A72 Errata #1319367.
+ * This applies to all revisions of Cortex A72.
+ * --------------------------------------------------
+ */
+func check_errata_1319367
+#if ERRATA_A72_1319367
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_1319367
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_cve_2022_23960
+
+func check_smccc_arch_workaround_3
+ cpu_check_csv2 x0, 1f
+ mov x0, #ERRATA_APPLIES
+ ret
+1:
+ mov x0, #ERRATA_NOT_APPLIES
+ ret
+endfunc check_smccc_arch_workaround_3
+
+ /* -------------------------------------------------
+ * 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 || WORKAROUND_CVE_2022_23960)
+ 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 */
+
+ /* Skip CVE_2022_23960 mitigation if cve_2017_5715 mitigation applied */
+ b 2f
+1:
+#if WORKAROUND_CVE_2022_23960
+ /*
+ * The Cortex-A72 generic vectors are overridden to apply the
+ * mitigation on exception entry from lower ELs for revisions >= r1p0
+ * which has CSV2 implemented.
+ */
+ adr x0, wa_cve_vbar_cortex_a72
+ msr vbar_el3, x0
+
+ /* isb will be performed before returning from this function */
+#endif /* WORKAROUND_CVE_2022_23960 */
+2:
+#endif /* IMAGE_BL31 && (WORKAROUND_CVE_2017_5715 || WORKAROUND_CVE_2022_23960) */
+
+#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 ERRATA_A72_1319367, cortex_a72, 1319367
+ report_errata WORKAROUND_CVE_2017_5715, cortex_a72, cve_2017_5715
+ report_errata WORKAROUND_CVE_2018_3639, cortex_a72, cve_2018_3639
+ report_errata WORKAROUND_CVE_2022_23960, cortex_a72, cve_2022_23960
+
+ 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, \
+ check_smccc_arch_workaround_3, \
+ cortex_a72_core_pwr_dwn, \
+ cortex_a72_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a73.S b/lib/cpus/aarch64/cortex_a73.S
new file mode 100644
index 0000000..edcd1f5
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a73.S
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a73.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+ /* ---------------------------------------------
+ * 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 || WORKAROUND_CVE_2022_23960)
+ cpu_check_csv2 x0, 1f
+ adr x0, wa_cve_2017_5715_bpiall_vbar
+ msr vbar_el3, x0
+ isb
+ /* Skip installing vector table again for CVE_2022_23960 */
+ b 2f
+1:
+#if WORKAROUND_CVE_2022_23960
+ adr x0, wa_cve_2017_5715_bpiall_vbar
+ msr vbar_el3, x0
+ isb
+#endif
+2:
+#endif /* IMAGE_BL31 && (WORKAROUND_CVE_2017_5715 || WORKAROUND_CVE_2022_23960) */
+
+#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
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2017_5715 || WORKAROUND_CVE_2022_23960
+ cpu_check_csv2 x0, 1f
+ mov x0, #ERRATA_APPLIES
+ ret
+ 1:
+# if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+# else
+ mov x0, #ERRATA_MISSING
+# endif /* WORKAROUND_CVE_2022_23960 */
+ ret
+#endif /* WORKAROUND_CVE_2017_5715 || WORKAROUND_CVE_2022_23960 */
+ mov x0, #ERRATA_MISSING
+ ret
+endfunc check_errata_cve_2022_23960
+
+func check_smccc_arch_workaround_3
+ mov x0, #ERRATA_APPLIES
+ ret
+endfunc check_smccc_arch_workaround_3
+
+#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
+ report_errata WORKAROUND_CVE_2022_23960, cortex_a73, cve_2022_23960
+
+ 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, \
+ check_smccc_arch_workaround_3, \
+ cortex_a73_core_pwr_dwn, \
+ cortex_a73_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a75.S b/lib/cpus/aarch64/cortex_a75.S
new file mode 100644
index 0000000..d561be4
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a75.S
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cortex_a75.h>
+#include <cpuamu.h>
+#include <cpu_macros.S>
+
+/* 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 || WORKAROUND_CVE_2022_23960)
+ cpu_check_csv2 x0, 1f
+ adr x0, wa_cve_2017_5715_bpiall_vbar
+ msr vbar_el3, x0
+ isb
+ /* Skip installing vector table again for CVE_2022_23960 */
+ b 2f
+1:
+#if WORKAROUND_CVE_2022_23960
+ adr x0, wa_cve_2017_5715_bpiall_vbar
+ msr vbar_el3, x0
+ isb
+#endif
+2:
+#endif /* IMAGE_BL31 && (WORKAROUND_CVE_2017_5715 || WORKAROUND_CVE_2022_23960) */
+
+#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
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2017_5715 || WORKAROUND_CVE_2022_23960
+ cpu_check_csv2 x0, 1f
+ mov x0, #ERRATA_APPLIES
+ ret
+1:
+# if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+# else
+ mov x0, #ERRATA_MISSING
+# endif /* WORKAROUND_CVE_2022_23960 */
+ ret
+#endif /* WORKAROUND_CVE_2017_5715 || WORKAROUND_CVE_2022_23960 */
+ mov x0, #ERRATA_MISSING
+ ret
+endfunc check_errata_cve_2022_23960
+
+func check_smccc_arch_workaround_3
+ mov x0, #ERRATA_APPLIES
+ ret
+endfunc check_smccc_arch_workaround_3
+
+ /* ---------------------------------------------
+ * 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
+ report_errata WORKAROUND_CVE_2022_23960, cortex_a75, cve_2022_23960
+
+ 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, \
+ check_smccc_arch_workaround_3, \
+ cortex_a75_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a75_pubsub.c b/lib/cpus/aarch64/cortex_a75_pubsub.c
new file mode 100644
index 0000000..bd2c697
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a75_pubsub.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cortex_a75.h>
+#include <cpuamu.h>
+#include <lib/el3_runtime/pubsub_events.h>
+
+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);
diff --git a/lib/cpus/aarch64/cortex_a76.S b/lib/cpus/aarch64/cortex_a76.S
new file mode 100644
index 0000000..36507de
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a76.S
@@ -0,0 +1,846 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a76.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+#include <services/arm_arch_svc.h>
+#include "wa_cve_2022_23960_bhb.S"
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Cortex-A76 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+ .globl cortex_a76_reset_func
+ .globl cortex_a76_core_pwr_dwn
+ .globl cortex_a76_disable_wa_cve_2018_3639
+
+/* 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. The macro also saves
+ * x29-x30 to the context in the sync_exception path.
+ */
+ .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
+ stp x29, x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
+ mov_imm w2, \_esr_el3_val
+ bl apply_cve_2018_3639_sync_wa
+ ldp x29, x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
+ .endif
+ /*
+ * 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
+#endif /* DYNAMIC_WORKAROUND_CVE_2018_3639 */
+
+#if DYNAMIC_WORKAROUND_CVE_2018_3639 || WORKAROUND_CVE_2022_23960
+vector_base cortex_a76_wa_cve_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
+
+#if WORKAROUND_CVE_2022_23960
+ apply_cve_2022_23960_bhb_wa CORTEX_A76_BHB_LOOP_COUNT
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+#if DYNAMIC_WORKAROUND_CVE_2018_3639
+ apply_cve_2018_3639_wa _is_sync_exception=1 _esr_el3_val=ESR_EL3_A64_SMC0
+#endif /* DYNAMIC_WORKAROUND_CVE_2018_3639*/
+
+ b sync_exception_aarch64
+end_vector_entry cortex_a76_sync_exception_aarch64
+
+vector_entry cortex_a76_irq_aarch64
+
+#if WORKAROUND_CVE_2022_23960
+ apply_cve_2022_23960_bhb_wa CORTEX_A76_BHB_LOOP_COUNT
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+#if DYNAMIC_WORKAROUND_CVE_2018_3639
+ apply_cve_2018_3639_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A64_SMC0
+#endif /* DYNAMIC_WORKAROUND_CVE_2018_3639*/
+
+ b irq_aarch64
+end_vector_entry cortex_a76_irq_aarch64
+
+vector_entry cortex_a76_fiq_aarch64
+
+#if WORKAROUND_CVE_2022_23960
+ apply_cve_2022_23960_bhb_wa CORTEX_A76_BHB_LOOP_COUNT
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+#if DYNAMIC_WORKAROUND_CVE_2018_3639
+ apply_cve_2018_3639_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A64_SMC0
+#endif /* DYNAMIC_WORKAROUND_CVE_2018_3639*/
+
+ b fiq_aarch64
+end_vector_entry cortex_a76_fiq_aarch64
+
+vector_entry cortex_a76_serror_aarch64
+
+#if WORKAROUND_CVE_2022_23960
+ apply_cve_2022_23960_bhb_wa CORTEX_A76_BHB_LOOP_COUNT
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+#if DYNAMIC_WORKAROUND_CVE_2018_3639
+ apply_cve_2018_3639_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A64_SMC0
+#endif /* DYNAMIC_WORKAROUND_CVE_2018_3639*/
+
+ b serror_aarch64
+end_vector_entry cortex_a76_serror_aarch64
+
+ /* ---------------------------------------------------------------------
+ * Lower EL using AArch32 : 0x600 - 0x800
+ * ---------------------------------------------------------------------
+ */
+vector_entry cortex_a76_sync_exception_aarch32
+
+#if WORKAROUND_CVE_2022_23960
+ apply_cve_2022_23960_bhb_wa CORTEX_A76_BHB_LOOP_COUNT
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+#if DYNAMIC_WORKAROUND_CVE_2018_3639
+ apply_cve_2018_3639_wa _is_sync_exception=1 _esr_el3_val=ESR_EL3_A32_SMC0
+#endif /* DYNAMIC_WORKAROUND_CVE_2018_3639*/
+
+ b sync_exception_aarch32
+end_vector_entry cortex_a76_sync_exception_aarch32
+
+vector_entry cortex_a76_irq_aarch32
+
+#if WORKAROUND_CVE_2022_23960
+ apply_cve_2022_23960_bhb_wa CORTEX_A76_BHB_LOOP_COUNT
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+#if DYNAMIC_WORKAROUND_CVE_2018_3639
+ apply_cve_2018_3639_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A32_SMC0
+#endif /* DYNAMIC_WORKAROUND_CVE_2018_3639*/
+
+ b irq_aarch32
+end_vector_entry cortex_a76_irq_aarch32
+
+vector_entry cortex_a76_fiq_aarch32
+
+#if WORKAROUND_CVE_2022_23960
+ apply_cve_2022_23960_bhb_wa CORTEX_A76_BHB_LOOP_COUNT
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+#if DYNAMIC_WORKAROUND_CVE_2018_3639
+ apply_cve_2018_3639_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A32_SMC0
+#endif /* DYNAMIC_WORKAROUND_CVE_2018_3639*/
+
+ b fiq_aarch32
+end_vector_entry cortex_a76_fiq_aarch32
+
+vector_entry cortex_a76_serror_aarch32
+
+#if WORKAROUND_CVE_2022_23960
+ apply_cve_2022_23960_bhb_wa CORTEX_A76_BHB_LOOP_COUNT
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+#if DYNAMIC_WORKAROUND_CVE_2018_3639
+ apply_cve_2018_3639_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A32_SMC0
+#endif /* DYNAMIC_WORKAROUND_CVE_2018_3639*/
+
+ b serror_aarch32
+end_vector_entry cortex_a76_serror_aarch32
+#endif /* DYNAMIC_WORKAROUND_CVE_2018_3639 || WORKAROUND_CVE_2022_23960 */
+
+#if DYNAMIC_WORKAROUND_CVE_2018_3639
+ /*
+ * -----------------------------------------------------------------
+ * This function applies the mitigation for CVE-2018-3639
+ * specifically for sync exceptions. It implements a fast path
+ * where `SMCCC_ARCH_WORKAROUND_2` SMC calls from a lower EL
+ * running in AArch64 will go through the fast and return early.
+ *
+ * In the fast path x0-x3 registers do not need to be restored as the
+ * calling context will have saved them.
+ *
+ * Caller must pass value of esr_el3 to compare via x2.
+ * Save and restore these registers outside of this function from the
+ * context before jumping to the main runtime vector table entry.
+ *
+ * Shall clobber: x0-x3, x30
+ * -----------------------------------------------------------------
+ */
+func apply_cve_2018_3639_sync_wa
+ /*
+ * 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
+ * X2 populated outside this function with the SMC FID.
+ */
+ orr w3, wzr, #SMCCC_ARCH_WORKAROUND_2
+ cmp x0, x3
+ mrs x3, esr_el3
+
+ 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
+ ldp x29, x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
+ /*
+ * `SMCCC_ARCH_WORKAROUND_2`fast path return to lower EL.
+ */
+ exception_return /* exception_return contains ISB */
+1:
+ ret
+endfunc apply_cve_2018_3639_sync_wa
+#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 #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
+
+ /* --------------------------------------------------
+ * Errata workaround for Cortex A76 Errata #1791580.
+ * This applies to revisions <= r4p0 of Cortex A76.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a76_1791580_wa
+ /* Compare x0 against revision r4p0 */
+ mov x17, x30
+ bl check_errata_1791580
+ cbz x0, 1f
+ mrs x1, CORTEX_A76_CPUACTLR2_EL1
+ orr x1, x1, CORTEX_A76_CPUACTLR2_EL1_BIT_2
+ msr CORTEX_A76_CPUACTLR2_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_a76_1791580_wa
+
+func check_errata_1791580
+ /* Applies to everything <=r4p0. */
+ mov x1, #0x40
+ b cpu_rev_var_ls
+endfunc check_errata_1791580
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex A76 Errata #1262606,
+ * #1275112, and #1868343. #1262606 and #1275112
+ * apply to revisions <= r3p0 and #1868343 applies to
+ * revisions <= r4p0.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+
+func errata_a76_1262606_1275112_1868343_wa
+ mov x17, x30
+
+/* Check for <= r3p0 cases and branch if check passes. */
+#if ERRATA_A76_1262606 || ERRATA_A76_1275112
+ bl check_errata_1262606
+ cbnz x0, 1f
+#endif
+
+/* Check for <= r4p0 cases and branch if check fails. */
+#if ERRATA_A76_1868343
+ bl check_errata_1868343
+ cbz x0, 2f
+#endif
+1:
+ mrs x1, CORTEX_A76_CPUACTLR_EL1
+ orr x1, x1, #CORTEX_A76_CPUACTLR_EL1_BIT_13
+ msr CORTEX_A76_CPUACTLR_EL1, x1
+ isb
+2:
+ ret x17
+endfunc errata_a76_1262606_1275112_1868343_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
+
+func check_errata_1868343
+ mov x1, #0x40
+ b cpu_rev_var_ls
+endfunc check_errata_1868343
+
+/* --------------------------------------------------
+ * Errata Workaround for A76 Erratum 1946160.
+ * This applies to revisions r3p0 - r4p1 of A76.
+ * It also exists in r0p0 - r2p0 but there is no fix
+ * in those revisions.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a76_1946160_wa
+ /* Compare x0 against revisions r3p0 - r4p1 */
+ mov x17, x30
+ bl check_errata_1946160
+ cbz x0, 1f
+
+ mov x0, #3
+ msr S3_6_C15_C8_0, x0
+ ldr x0, =0x10E3900002
+ msr S3_6_C15_C8_2, x0
+ ldr x0, =0x10FFF00083
+ msr S3_6_C15_C8_3, x0
+ ldr x0, =0x2001003FF
+ msr S3_6_C15_C8_1, x0
+
+ mov x0, #4
+ msr S3_6_C15_C8_0, x0
+ ldr x0, =0x10E3800082
+ msr S3_6_C15_C8_2, x0
+ ldr x0, =0x10FFF00083
+ msr S3_6_C15_C8_3, x0
+ ldr x0, =0x2001003FF
+ msr S3_6_C15_C8_1, x0
+
+ mov x0, #5
+ msr S3_6_C15_C8_0, x0
+ ldr x0, =0x10E3800200
+ msr S3_6_C15_C8_2, x0
+ ldr x0, =0x10FFF003E0
+ msr S3_6_C15_C8_3, x0
+ ldr x0, =0x2001003FF
+ msr S3_6_C15_C8_1, x0
+
+ isb
+1:
+ ret x17
+endfunc errata_a76_1946160_wa
+
+func check_errata_1946160
+ /* Applies to revisions r3p0 - r4p1. */
+ mov x1, #0x30
+ mov x2, #0x41
+ b cpu_rev_var_range
+endfunc check_errata_1946160
+
+ /* ----------------------------------------------------
+ * Errata Workaround for Cortex-A76 Errata #2743102
+ * This applies to revisions <= r4p1 and is still open.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * ----------------------------------------------------
+ */
+func errata_a76_2743102_wa
+ mov x17, x30
+ bl check_errata_2743102
+ cbz x0, 1f
+
+ /* dsb before isb of power down sequence */
+ dsb sy
+1:
+ ret x17
+endfunc errata_a76_2743102_wa
+
+func check_errata_2743102
+ /* Applies to all revisions <= r4p1 */
+ mov x1, #0x41
+ b cpu_rev_var_ls
+endfunc check_errata_2743102
+
+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
+
+ /* --------------------------------------------------------------
+ * Errata Workaround for Cortex A76 Errata #1165522.
+ * This applies only to revisions <= 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_1165522
+#if ERRATA_A76_1165522
+ mov x0, #ERRATA_APPLIES
+ ret
+#else
+ mov x1, #0x30
+ b cpu_rev_var_ls
+#endif
+endfunc check_errata_1165522
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif /* WORKAROUND_CVE_2022_23960 */
+ ret
+endfunc check_errata_cve_2022_23960
+
+ /* -------------------------------------------------
+ * 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 || ERRATA_A76_1868343
+ mov x0, x18
+ bl errata_a76_1262606_1275112_1868343_wa
+#endif
+
+#if ERRATA_A76_1262888
+ mov x0, x18
+ bl errata_a76_1262888_wa
+#endif
+
+#if ERRATA_A76_1791580
+ mov x0, x18
+ bl errata_a76_1791580_wa
+#endif
+
+#if ERRATA_A76_1946160
+ mov x0, x18
+ bl errata_a76_1946160_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.
+ * If the below vector table is used, skip overriding it again for
+ * CVE_2022_23960 as both use the same vbar.
+ */
+ adr x0, cortex_a76_wa_cve_vbar
+ msr vbar_el3, x0
+ isb
+ b 2f
+#endif /* IMAGE_BL31 */
+
+1:
+#endif /* DYNAMIC_WORKAROUND_CVE_2018_3639 */
+#endif /* WORKAROUND_CVE_2018_3639 */
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2022_23960
+ /*
+ * The Cortex-A76 generic vectors are overridden to apply errata
+ * mitigation on exception entry from lower ELs. This will be bypassed
+ * if DYNAMIC_WORKAROUND_CVE_2018_3639 has overridden the vectors.
+ */
+ adr x0, cortex_a76_wa_cve_vbar
+ msr vbar_el3, x0
+ isb
+#endif /* IMAGE_BL31 && WORKAROUND_CVE_2022_23960 */
+2:
+
+#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
+#if ERRATA_A76_2743102
+ mov x15, x30
+ bl cpu_get_rev_var
+ bl errata_a76_2743102_wa
+ mov x30, x15
+#endif /* ERRATA_A76_2743102 */
+ 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_1165522, cortex_a76, 1165522
+ 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 ERRATA_A76_1791580, cortex_a76, 1791580
+ report_errata ERRATA_A76_1868343, cortex_a76, 1868343
+ report_errata ERRATA_A76_1946160, cortex_a76, 1946160
+ report_errata ERRATA_A76_2743102, cortex_a76, 2743102
+ 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
+ report_errata WORKAROUND_CVE_2022_23960, cortex_a76, cve_2022_23960
+
+ 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, \
+ CPU_NO_EXTRA3_FUNC, \
+ cortex_a76_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a76ae.S b/lib/cpus/aarch64/cortex_a76ae.S
new file mode 100644
index 0000000..5c19548
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a76ae.S
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a76ae.h>
+#include <cpu_macros.S>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+/* 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
+
+#if WORKAROUND_CVE_2022_23960
+ wa_cve_2022_23960_bhb_vector_table CORTEX_A76AE_BHB_LOOP_COUNT, cortex_a76ae
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif /* WORKAROUND_CVE_2022_23960 */
+ ret
+endfunc check_errata_cve_2022_23960
+
+ /* --------------------------------------------
+ * The CPU Ops reset function for Cortex-A76AE.
+ * Shall clobber: x0-x19
+ * --------------------------------------------
+ */
+func cortex_a76ae_reset_func
+#if IMAGE_BL31 && WORKAROUND_CVE_2022_23960
+ /*
+ * The Cortex-A76ae generic vectors are overridden to apply errata
+ * mitigation on exception entry from lower ELs.
+ */
+ adr x0, wa_cve_vbar_cortex_a76ae
+ msr vbar_el3, x0
+ isb
+#endif /* IMAGE_BL31 && WORKAROUND_CVE_2022_23960 */
+
+ ret
+endfunc cortex_a76ae_reset_func
+
+ /* ----------------------------------------------------
+ * 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
+ 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_2022_23960, cortex_a76ae, cve_2022_23960
+
+ ldp x8, x30, [sp], #16
+ 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, cortex_a76ae_reset_func, \
+ cortex_a76ae_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a77.S b/lib/cpus/aarch64/cortex_a77.S
new file mode 100644
index 0000000..2882df7
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a77.S
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a77.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+/* 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
+
+#if WORKAROUND_CVE_2022_23960
+ wa_cve_2022_23960_bhb_vector_table CORTEX_A77_BHB_LOOP_COUNT, cortex_a77
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex A77 Errata #1508412.
+ * This applies only to revision <= r1p0 of Cortex A77.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a77_1508412_wa
+ /*
+ * Compare x0 against revision r1p0
+ */
+ mov x17, x30
+ bl check_errata_1508412
+ cbz x0, 3f
+ /*
+ * Compare x0 against revision r0p0
+ */
+ bl check_errata_1508412_0
+ cbz x0, 1f
+ ldr x0, =0x0
+ msr CORTEX_A77_CPUPSELR_EL3, x0
+ ldr x0, =0x00E8400000
+ msr CORTEX_A77_CPUPOR_EL3, x0
+ ldr x0, =0x00FFE00000
+ msr CORTEX_A77_CPUPMR_EL3, x0
+ ldr x0, =0x4004003FF
+ msr CORTEX_A77_CPUPCR_EL3, x0
+ ldr x0, =0x1
+ msr CORTEX_A77_CPUPSELR_EL3, x0
+ ldr x0, =0x00E8C00040
+ msr CORTEX_A77_CPUPOR_EL3, x0
+ ldr x0, =0x00FFE00040
+ msr CORTEX_A77_CPUPMR_EL3, x0
+ b 2f
+1:
+ ldr x0, =0x0
+ msr CORTEX_A77_CPUPSELR_EL3, x0
+ ldr x0, =0x00E8400000
+ msr CORTEX_A77_CPUPOR_EL3, x0
+ ldr x0, =0x00FF600000
+ msr CORTEX_A77_CPUPMR_EL3, x0
+ ldr x0, =0x00E8E00080
+ msr CORTEX_A77_CPUPOR2_EL3, x0
+ ldr x0, =0x00FFE000C0
+ msr CORTEX_A77_CPUPMR2_EL3, x0
+2:
+ ldr x0, =0x04004003FF
+ msr CORTEX_A77_CPUPCR_EL3, x0
+ isb
+3:
+ ret x17
+endfunc errata_a77_1508412_wa
+
+func check_errata_1508412
+ mov x1, #0x10
+ b cpu_rev_var_ls
+endfunc check_errata_1508412
+
+func check_errata_1508412_0
+ mov x1, #0x0
+ b cpu_rev_var_ls
+endfunc check_errata_1508412_0
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex A77 Errata #1925769.
+ * This applies to revision <= r1p1 of Cortex A77.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a77_1925769_wa
+ /* Compare x0 against revision <= r1p1 */
+ mov x17, x30
+ bl check_errata_1925769
+ cbz x0, 1f
+
+ /* Set bit 8 in ECTLR_EL1 */
+ mrs x1, CORTEX_A77_CPUECTLR_EL1
+ orr x1, x1, #CORTEX_A77_CPUECTLR_EL1_BIT_8
+ msr CORTEX_A77_CPUECTLR_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_a77_1925769_wa
+
+func check_errata_1925769
+ /* Applies to everything <= r1p1 */
+ mov x1, #0x11
+ b cpu_rev_var_ls
+endfunc check_errata_1925769
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex A77 Errata #1946167.
+ * This applies to revision <= r1p1 of Cortex A77.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a77_1946167_wa
+ /* Compare x0 against revision <= r1p1 */
+ mov x17, x30
+ bl check_errata_1946167
+ cbz x0, 1f
+
+ ldr x0,=0x4
+ msr CORTEX_A77_CPUPSELR_EL3,x0
+ ldr x0,=0x10E3900002
+ msr CORTEX_A77_CPUPOR_EL3,x0
+ ldr x0,=0x10FFF00083
+ msr CORTEX_A77_CPUPMR_EL3,x0
+ ldr x0,=0x2001003FF
+ msr CORTEX_A77_CPUPCR_EL3,x0
+
+ ldr x0,=0x5
+ msr CORTEX_A77_CPUPSELR_EL3,x0
+ ldr x0,=0x10E3800082
+ msr CORTEX_A77_CPUPOR_EL3,x0
+ ldr x0,=0x10FFF00083
+ msr CORTEX_A77_CPUPMR_EL3,x0
+ ldr x0,=0x2001003FF
+ msr CORTEX_A77_CPUPCR_EL3,x0
+
+ ldr x0,=0x6
+ msr CORTEX_A77_CPUPSELR_EL3,x0
+ ldr x0,=0x10E3800200
+ msr CORTEX_A77_CPUPOR_EL3,x0
+ ldr x0,=0x10FFF003E0
+ msr CORTEX_A77_CPUPMR_EL3,x0
+ ldr x0,=0x2001003FF
+ msr CORTEX_A77_CPUPCR_EL3,x0
+
+ isb
+1:
+ ret x17
+endfunc errata_a77_1946167_wa
+
+func check_errata_1946167
+ /* Applies to everything <= r1p1 */
+ mov x1, #0x11
+ b cpu_rev_var_ls
+endfunc check_errata_1946167
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex A77 Errata #1791578.
+ * This applies to revisions r0p0, r1p0, and r1p1 and is still open.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a77_1791578_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_1791578
+ cbz x0, 1f
+
+ /* Set bit 2 in ACTLR2_EL1 */
+ mrs x1, CORTEX_A77_ACTLR2_EL1
+ orr x1, x1, #CORTEX_A77_ACTLR2_EL1_BIT_2
+ msr CORTEX_A77_ACTLR2_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_a77_1791578_wa
+
+func check_errata_1791578
+ /* Applies to r0p0, r1p0, and r1p1 right now */
+ mov x1, #0x11
+ b cpu_rev_var_ls
+endfunc check_errata_1791578
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex A77 Errata #2356587.
+ * This applies to revisions r0p0, r1p0, and r1p1 and is still open.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a77_2356587_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_2356587
+ cbz x0, 1f
+
+ /* Set bit 0 in ACTLR2_EL1 */
+ mrs x1, CORTEX_A77_ACTLR2_EL1
+ orr x1, x1, #CORTEX_A77_ACTLR2_EL1_BIT_0
+ msr CORTEX_A77_ACTLR2_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_a77_2356587_wa
+
+func check_errata_2356587
+ /* Applies to r0p0, r1p0, and r1p1 right now */
+ mov x1, #0x11
+ b cpu_rev_var_ls
+endfunc check_errata_2356587
+
+ /* -----------------------------------------------------------------
+ * Errata Workaround for Cortex A77 Errata #2743100
+ * This applies to revisions r0p0, r1p0, and r1p1 and is still open.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * -----------------------------------------------------------------
+ */
+func errata_a77_2743100_wa
+ mov x17, x30
+ bl check_errata_2743100
+ cbz x0, 1f
+
+ /* dsb before isb of power down sequence */
+ dsb sy
+1:
+ ret x17
+endfunc errata_a77_2743100_wa
+
+func check_errata_2743100
+ /* Applies to r0p0, r1p0, and r1p1 right now */
+ mov x1, #0x11
+ b cpu_rev_var_ls
+endfunc check_errata_2743100
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_cve_2022_23960
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex A77 Errata #1800714.
+ * This applies to revision <= r1p1 of Cortex A77.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a77_1800714_wa
+ /* Compare x0 against revision <= r1p1 */
+ mov x17, x30
+ bl check_errata_1800714
+ cbz x0, 1f
+
+ /* Disable allocation of splintered pages in the L2 TLB */
+ mrs x1, CORTEX_A77_CPUECTLR_EL1
+ orr x1, x1, CORTEX_A77_CPUECTLR_EL1_BIT_53
+ msr CORTEX_A77_CPUECTLR_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_a77_1800714_wa
+
+func check_errata_1800714
+ /* Applies to everything <= r1p1 */
+ mov x1, #0x11
+ b cpu_rev_var_ls
+endfunc check_errata_1800714
+
+ /* -------------------------------------------------
+ * The CPU Ops reset function for Cortex-A77.
+ * Shall clobber: x0-x19
+ * -------------------------------------------------
+ */
+func cortex_a77_reset_func
+ mov x19, x30
+ bl cpu_get_rev_var
+ mov x18, x0
+
+#if ERRATA_A77_1508412
+ mov x0, x18
+ bl errata_a77_1508412_wa
+#endif
+
+#if ERRATA_A77_1925769
+ mov x0, x18
+ bl errata_a77_1925769_wa
+#endif
+
+#if ERRATA_A77_1946167
+ mov x0, x18
+ bl errata_a77_1946167_wa
+#endif
+
+#if ERRATA_A77_1791578
+ mov x0, x18
+ bl errata_a77_1791578_wa
+#endif
+
+#if ERRATA_A77_2356587
+ mov x0, x18
+ bl errata_a77_2356587_wa
+#endif
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2022_23960
+ /*
+ * The Cortex-A77 generic vectors are overridden to apply errata
+ * mitigation on exception entry from lower ELs.
+ */
+ adr x0, wa_cve_vbar_cortex_a77
+ msr vbar_el3, x0
+#endif /* IMAGE_BL31 && WORKAROUND_CVE_2022_23960 */
+
+#if ERRATA_A77_1800714
+ mov x0, x18
+ bl errata_a77_1800714_wa
+#endif
+
+ isb
+ ret x19
+endfunc cortex_a77_reset_func
+
+ /* ---------------------------------------------
+ * 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
+#if ERRATA_A77_2743100
+ mov x15, x30
+ bl cpu_get_rev_var
+ bl errata_a77_2743100_wa
+ mov x30, x15
+#endif /* ERRATA_A77_2743100 */
+ 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
+ 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_A77_1508412, cortex_a77, 1508412
+ report_errata ERRATA_A77_1791578, cortex_a77, 1791578
+ report_errata ERRATA_A77_1800714, cortex_a77, 1800714
+ report_errata ERRATA_A77_1925769, cortex_a77, 1925769
+ report_errata ERRATA_A77_1946167, cortex_a77, 1946167
+ report_errata ERRATA_A77_2356587, cortex_a77, 2356587
+ report_errata ERRATA_A77_2743100, cortex_a77, 2743100
+ report_errata WORKAROUND_CVE_2022_23960, cortex_a77, cve_2022_23960
+
+ ldp x8, x30, [sp], #16
+ 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, \
+ cortex_a77_reset_func, \
+ cortex_a77_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a78.S b/lib/cpus/aarch64/cortex_a78.S
new file mode 100644
index 0000000..dd3487a
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a78.S
@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a78.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "cortex_a78 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+.globl cortex_a78_reset_func
+.globl cortex_a78_core_pwr_dwn
+
+#if WORKAROUND_CVE_2022_23960
+ wa_cve_2022_23960_bhb_vector_table CORTEX_A78_BHB_LOOP_COUNT, cortex_a78
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+/* --------------------------------------------------
+ * Errata Workaround for A78 Erratum 1688305.
+ * This applies to revision r0p0 and r1p0 of A78.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a78_1688305_wa
+ /* Compare x0 against revision r1p0 */
+ mov x17, x30
+ bl check_errata_1688305
+ cbz x0, 1f
+ mrs x1, CORTEX_A78_ACTLR2_EL1
+ orr x1, x1, #CORTEX_A78_ACTLR2_EL1_BIT_1
+ msr CORTEX_A78_ACTLR2_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_a78_1688305_wa
+
+func check_errata_1688305
+ /* Applies to r0p0 and r1p0 */
+ mov x1, #0x10
+ b cpu_rev_var_ls
+endfunc check_errata_1688305
+
+/* --------------------------------------------------
+ * Errata Workaround for Cortex A78 Errata #1941498.
+ * This applies to revisions r0p0, r1p0, and r1p1.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a78_1941498_wa
+ /* Compare x0 against revision <= r1p1 */
+ mov x17, x30
+ bl check_errata_1941498
+ cbz x0, 1f
+
+ /* Set bit 8 in ECTLR_EL1 */
+ mrs x1, CORTEX_A78_CPUECTLR_EL1
+ orr x1, x1, #CORTEX_A78_CPUECTLR_EL1_BIT_8
+ msr CORTEX_A78_CPUECTLR_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_a78_1941498_wa
+
+func check_errata_1941498
+ /* Check for revision <= r1p1, might need to be updated later. */
+ mov x1, #0x11
+ b cpu_rev_var_ls
+endfunc check_errata_1941498
+
+/* --------------------------------------------------
+ * Errata Workaround for A78 Erratum 1951500.
+ * This applies to revisions r1p0 and r1p1 of A78.
+ * The issue also exists in r0p0 but there is no fix
+ * in that revision.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a78_1951500_wa
+ /* Compare x0 against revisions r1p0 - r1p1 */
+ mov x17, x30
+ bl check_errata_1951500
+ cbz x0, 1f
+
+ msr S3_6_c15_c8_0, xzr
+ ldr x0, =0x10E3900002
+ msr S3_6_c15_c8_2, x0
+ ldr x0, =0x10FFF00083
+ msr S3_6_c15_c8_3, x0
+ ldr x0, =0x2001003FF
+ msr S3_6_c15_c8_1, x0
+
+ mov x0, #1
+ msr S3_6_c15_c8_0, x0
+ ldr x0, =0x10E3800082
+ msr S3_6_c15_c8_2, x0
+ ldr x0, =0x10FFF00083
+ msr S3_6_c15_c8_3, x0
+ ldr x0, =0x2001003FF
+ msr S3_6_c15_c8_1, x0
+
+ mov x0, #2
+ msr S3_6_c15_c8_0, x0
+ ldr x0, =0x10E3800200
+ msr S3_6_c15_c8_2, x0
+ ldr x0, =0x10FFF003E0
+ msr S3_6_c15_c8_3, x0
+ ldr x0, =0x2001003FF
+ msr S3_6_c15_c8_1, x0
+
+ isb
+1:
+ ret x17
+endfunc errata_a78_1951500_wa
+
+func check_errata_1951500
+ /* Applies to revisions r1p0 and r1p1. */
+ mov x1, #CPU_REV(1, 0)
+ mov x2, #CPU_REV(1, 1)
+ b cpu_rev_var_range
+endfunc check_errata_1951500
+
+/* --------------------------------------------------
+ * Errata Workaround for Cortex A78 Errata #1821534.
+ * This applies to revisions r0p0 and r1p0.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a78_1821534_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_1821534
+ cbz x0, 1f
+
+ /* Set bit 2 in ACTLR2_EL1 */
+ mrs x1, CORTEX_A78_ACTLR2_EL1
+ orr x1, x1, #CORTEX_A78_ACTLR2_EL1_BIT_2
+ msr CORTEX_A78_ACTLR2_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_a78_1821534_wa
+
+func check_errata_1821534
+ /* Applies to r0p0 and r1p0 */
+ mov x1, #0x10
+ b cpu_rev_var_ls
+endfunc check_errata_1821534
+
+/* --------------------------------------------------
+ * Errata Workaround for Cortex A78 Errata 1952683.
+ * This applies to revision r0p0.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a78_1952683_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_1952683
+ cbz x0, 1f
+
+ ldr x0,=0x5
+ msr S3_6_c15_c8_0,x0
+ ldr x0,=0xEEE10A10
+ msr S3_6_c15_c8_2,x0
+ ldr x0,=0xFFEF0FFF
+ msr S3_6_c15_c8_3,x0
+ ldr x0,=0x0010F000
+ msr S3_6_c15_c8_4,x0
+ ldr x0,=0x0010F000
+ msr S3_6_c15_c8_5,x0
+ ldr x0,=0x40000080023ff
+ msr S3_6_c15_c8_1,x0
+ ldr x0,=0x6
+ msr S3_6_c15_c8_0,x0
+ ldr x0,=0xEE640F34
+ msr S3_6_c15_c8_2,x0
+ ldr x0,=0xFFEF0FFF
+ msr S3_6_c15_c8_3,x0
+ ldr x0,=0x40000080023ff
+ msr S3_6_c15_c8_1,x0
+ isb
+1:
+ ret x17
+endfunc errata_a78_1952683_wa
+
+func check_errata_1952683
+ /* Applies to r0p0 only */
+ mov x1, #0x00
+ b cpu_rev_var_ls
+endfunc check_errata_1952683
+
+/* --------------------------------------------------
+ * Errata Workaround for Cortex A78 Errata 2132060.
+ * This applies to revisions r0p0, r1p0, r1p1, and r1p2.
+ * It is still open.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x1, x17
+ * --------------------------------------------------
+ */
+func errata_a78_2132060_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_2132060
+ cbz x0, 1f
+
+ /* Apply the workaround. */
+ mrs x1, CORTEX_A78_CPUECTLR_EL1
+ mov x0, #CORTEX_A78_CPUECTLR_EL1_PF_MODE_CNSRV
+ bfi x1, x0, #CPUECTLR_EL1_PF_MODE_LSB, #CPUECTLR_EL1_PF_MODE_WIDTH
+ msr CORTEX_A78_CPUECTLR_EL1, x1
+1:
+ ret x17
+endfunc errata_a78_2132060_wa
+
+func check_errata_2132060
+ /* Applies to r0p0, r0p1, r1p1, and r1p2 */
+ mov x1, #0x12
+ b cpu_rev_var_ls
+endfunc check_errata_2132060
+
+/* --------------------------------------------------------------------
+ * Errata Workaround for A78 Erratum 2242635.
+ * This applies to revisions r1p0, r1p1, and r1p2 of the Cortex A78
+ * processor and is still open.
+ * The issue also exists in r0p0 but there is no fix in that revision.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------------------------
+ */
+func errata_a78_2242635_wa
+ /* Compare x0 against revisions r1p0 - r1p2 */
+ mov x17, x30
+ bl check_errata_2242635
+ cbz x0, 1f
+
+ ldr x0, =0x5
+ msr S3_6_c15_c8_0, x0 /* CPUPSELR_EL3 */
+ ldr x0, =0x10F600E000
+ msr S3_6_c15_c8_2, x0 /* CPUPOR_EL3 */
+ ldr x0, =0x10FF80E000
+ msr S3_6_c15_c8_3, x0 /* CPUPMR_EL3 */
+ ldr x0, =0x80000000003FF
+ msr S3_6_c15_c8_1, x0 /* CPUPCR_EL3 */
+
+ isb
+1:
+ ret x17
+endfunc errata_a78_2242635_wa
+
+func check_errata_2242635
+ /* Applies to revisions r1p0 through r1p2. */
+ mov x1, #CPU_REV(1, 0)
+ mov x2, #CPU_REV(1, 2)
+ b cpu_rev_var_range
+endfunc check_errata_2242635
+
+/* --------------------------------------------------
+ * Errata Workaround for Cortex A78 Errata 2376745.
+ * This applies to revisions r0p0, r1p0, r1p1, and r1p2.
+ * It is still open.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x1, x17
+ * --------------------------------------------------
+ */
+func errata_a78_2376745_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_2376745
+ cbz x0, 1f
+
+ /* Apply the workaround. */
+ mrs x1, CORTEX_A78_ACTLR2_EL1
+ orr x1, x1, #BIT(0)
+ msr CORTEX_A78_ACTLR2_EL1, x1
+1:
+ ret x17
+endfunc errata_a78_2376745_wa
+
+func check_errata_2376745
+ /* Applies to r0p0, r0p1, r1p1, and r1p2 */
+ mov x1, #CPU_REV(1, 2)
+ b cpu_rev_var_ls
+endfunc check_errata_2376745
+
+/* --------------------------------------------------
+ * Errata Workaround for Cortex A78 Errata 2395406.
+ * This applies to revisions r0p0, r1p0, r1p1, and r1p2.
+ * It is still open.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x1, x17
+ * --------------------------------------------------
+ */
+func errata_a78_2395406_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_2395406
+ cbz x0, 1f
+
+ /* Apply the workaround. */
+ mrs x1, CORTEX_A78_ACTLR2_EL1
+ orr x1, x1, #BIT(40)
+ msr CORTEX_A78_ACTLR2_EL1, x1
+1:
+ ret x17
+endfunc errata_a78_2395406_wa
+
+func check_errata_2395406
+ /* Applies to r0p0, r0p1, r1p1, and r1p2 */
+ mov x1, #CPU_REV(1, 2)
+ b cpu_rev_var_ls
+endfunc check_errata_2395406
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_cve_2022_23960
+
+ /* -------------------------------------------------
+ * The CPU Ops reset function for Cortex-A78
+ * -------------------------------------------------
+ */
+func cortex_a78_reset_func
+ mov x19, x30
+ bl cpu_get_rev_var
+ mov x18, x0
+
+#if ERRATA_A78_1688305
+ mov x0, x18
+ bl errata_a78_1688305_wa
+#endif
+
+#if ERRATA_A78_1941498
+ mov x0, x18
+ bl errata_a78_1941498_wa
+#endif
+
+#if ERRATA_A78_1951500
+ mov x0, x18
+ bl errata_a78_1951500_wa
+#endif
+
+#if ERRATA_A78_1821534
+ mov x0, x18
+ bl errata_a78_1821534_wa
+#endif
+
+#if ERRATA_A78_1952683
+ mov x0, x18
+ bl errata_a78_1952683_wa
+#endif
+
+#if ERRATA_A78_2132060
+ mov x0, x18
+ bl errata_a78_2132060_wa
+#endif
+
+#if ERRATA_A78_2242635
+ mov x0, x18
+ bl errata_a78_2242635_wa
+#endif
+
+#if ERRATA_A78_2376745
+ mov x0, x18
+ bl errata_a78_2376745_wa
+#endif
+
+#if ERRATA_A78_2395406
+ mov x0, x18
+ bl errata_a78_2395406_wa
+#endif
+
+#if ENABLE_AMU
+ /* Make sure accesses from EL0/EL1 and EL2 are not trapped to EL3 */
+ mrs x0, actlr_el3
+ bic x0, x0, #CORTEX_A78_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_A78_ACTLR_TAM_BIT
+ msr actlr_el2, x0
+
+ /* Enable group0 counters */
+ mov x0, #CORTEX_A78_AMU_GROUP0_MASK
+ msr CPUAMCNTENSET0_EL0, x0
+
+ /* Enable group1 counters */
+ mov x0, #CORTEX_A78_AMU_GROUP1_MASK
+ msr CPUAMCNTENSET1_EL0, x0
+#endif
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2022_23960
+ /*
+ * The Cortex-A78 generic vectors are overridden to apply errata
+ * mitigation on exception entry from lower ELs.
+ */
+ adr x0, wa_cve_vbar_cortex_a78
+ msr vbar_el3, x0
+#endif /* IMAGE_BL31 && WORKAROUND_CVE_2022_23960 */
+
+ isb
+ ret x19
+endfunc cortex_a78_reset_func
+
+ /* ---------------------------------------------
+ * HW will do the cache maintenance while powering down
+ * ---------------------------------------------
+ */
+func cortex_a78_core_pwr_dwn
+ /* ---------------------------------------------
+ * Enable CPU power down bit in power control register
+ * ---------------------------------------------
+ */
+ mrs x0, CORTEX_A78_CPUPWRCTLR_EL1
+ orr x0, x0, #CORTEX_A78_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT
+ msr CORTEX_A78_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+endfunc cortex_a78_core_pwr_dwn
+
+ /*
+ * Errata printing function for cortex_a78. Must follow AAPCS.
+ */
+#if REPORT_ERRATA
+func cortex_a78_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_A78_1688305, cortex_a78, 1688305
+ report_errata ERRATA_A78_1941498, cortex_a78, 1941498
+ report_errata ERRATA_A78_1951500, cortex_a78, 1951500
+ report_errata ERRATA_A78_1821534, cortex_a78, 1821534
+ report_errata ERRATA_A78_1952683, cortex_a78, 1952683
+ report_errata ERRATA_A78_2132060, cortex_a78, 2132060
+ report_errata ERRATA_A78_2242635, cortex_a78, 2242635
+ report_errata ERRATA_A78_2376745, cortex_a78, 2376745
+ report_errata ERRATA_A78_2395406, cortex_a78, 2395406
+ report_errata WORKAROUND_CVE_2022_23960, cortex_a78, cve_2022_23960
+
+ ldp x8, x30, [sp], #16
+ ret
+endfunc cortex_a78_errata_report
+#endif
+
+ /* ---------------------------------------------
+ * This function provides cortex_a78 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_a78_regs, "aS"
+cortex_a78_regs: /* The ascii list of register names to be reported */
+ .asciz "cpuectlr_el1", ""
+
+func cortex_a78_cpu_reg_dump
+ adr x6, cortex_a78_regs
+ mrs x8, CORTEX_A78_CPUECTLR_EL1
+ ret
+endfunc cortex_a78_cpu_reg_dump
+
+declare_cpu_ops cortex_a78, CORTEX_A78_MIDR, \
+ cortex_a78_reset_func, \
+ cortex_a78_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a78_ae.S b/lib/cpus/aarch64/cortex_a78_ae.S
new file mode 100644
index 0000000..27adc38
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a78_ae.S
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited. All rights reserved.
+ * Copyright (c) 2021-2022, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a78_ae.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "cortex_a78_ae must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+#if WORKAROUND_CVE_2022_23960
+ wa_cve_2022_23960_bhb_vector_table CORTEX_A78_AE_BHB_LOOP_COUNT, cortex_a78_ae
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+/* --------------------------------------------------
+ * Errata Workaround for A78 AE Erratum 1941500.
+ * This applies to revisions r0p0 and r0p1 of A78 AE.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a78_ae_1941500_wa
+ /* Compare x0 against revisions r0p0 - r0p1 */
+ mov x17, x30
+ bl check_errata_1941500
+ cbz x0, 1f
+
+ /* Set bit 8 in ECTLR_EL1 */
+ mrs x0, CORTEX_A78_AE_CPUECTLR_EL1
+ bic x0, x0, #CORTEX_A78_AE_CPUECTLR_EL1_BIT_8
+ msr CORTEX_A78_AE_CPUECTLR_EL1, x0
+ isb
+1:
+ ret x17
+endfunc errata_a78_ae_1941500_wa
+
+func check_errata_1941500
+ /* Applies to revisions r0p0 and r0p1. */
+ mov x1, #CPU_REV(0, 0)
+ mov x2, #CPU_REV(0, 1)
+ b cpu_rev_var_range
+endfunc check_errata_1941500
+
+/* --------------------------------------------------
+ * Errata Workaround for A78 AE Erratum 1951502.
+ * This applies to revisions r0p0 and r0p1 of A78 AE.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a78_ae_1951502_wa
+ /* Compare x0 against revisions r0p0 - r0p1 */
+ mov x17, x30
+ bl check_errata_1951502
+ cbz x0, 1f
+
+ msr S3_6_c15_c8_0, xzr
+ ldr x0, =0x10E3900002
+ msr S3_6_c15_c8_2, x0
+ ldr x0, =0x10FFF00083
+ msr S3_6_c15_c8_3, x0
+ ldr x0, =0x2001003FF
+ msr S3_6_c15_c8_1, x0
+
+ mov x0, #1
+ msr S3_6_c15_c8_0, x0
+ ldr x0, =0x10E3800082
+ msr S3_6_c15_c8_2, x0
+ ldr x0, =0x10FFF00083
+ msr S3_6_c15_c8_3, x0
+ ldr x0, =0x2001003FF
+ msr S3_6_c15_c8_1, x0
+
+ mov x0, #2
+ msr S3_6_c15_c8_0, x0
+ ldr x0, =0x10E3800200
+ msr S3_6_c15_c8_2, x0
+ ldr x0, =0x10FFF003E0
+ msr S3_6_c15_c8_3, x0
+ ldr x0, =0x2001003FF
+ msr S3_6_c15_c8_1, x0
+
+ isb
+1:
+ ret x17
+endfunc errata_a78_ae_1951502_wa
+
+func check_errata_1951502
+ /* Applies to revisions r0p0 and r0p1. */
+ mov x1, #CPU_REV(0, 0)
+ mov x2, #CPU_REV(0, 1)
+ b cpu_rev_var_range
+endfunc check_errata_1951502
+
+/* --------------------------------------------------
+ * Errata Workaround for A78 AE Erratum 2376748.
+ * This applies to revisions r0p0 and r0p1 of A78 AE.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a78_ae_2376748_wa
+ /* Compare x0 against revisions r0p0 - r0p1 */
+ mov x17, x30
+ bl check_errata_2376748
+ cbz x0, 1f
+
+ /* -------------------------------------------------------
+ * Set CPUACTLR2_EL1[0] to 1 to force PLDW/PFRM ST to
+ * behave like PLD/PRFM LD and not cause invalidations to
+ * other PE caches. There might be a small performance
+ * degradation to this workaround for certain workloads
+ * that share data.
+ * -------------------------------------------------------
+ */
+ mrs x0, CORTEX_A78_AE_ACTLR2_EL1
+ orr x0, x0, #CORTEX_A78_AE_ACTLR2_EL1_BIT_0
+ msr CORTEX_A78_AE_ACTLR2_EL1, x0
+ isb
+1:
+ ret x17
+endfunc errata_a78_ae_2376748_wa
+
+func check_errata_2376748
+ /* Applies to revisions r0p0 and r0p1. */
+ mov x1, #CPU_REV(0, 0)
+ mov x2, #CPU_REV(0, 1)
+ b cpu_rev_var_range
+endfunc check_errata_2376748
+
+/* --------------------------------------------------
+ * Errata Workaround for A78 AE Erratum 2395408.
+ * This applies to revisions r0p0 and r0p1 of A78 AE.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a78_ae_2395408_wa
+ /* Compare x0 against revisions r0p0 - r0p1 */
+ mov x17, x30
+ bl check_errata_2395408
+ cbz x0, 1f
+
+ /* --------------------------------------------------------
+ * Disable folding of demand requests into older prefetches
+ * with L2 miss requests outstanding by setting the
+ * CPUACTLR2_EL1[40] to 1.
+ * --------------------------------------------------------
+ */
+ mrs x0, CORTEX_A78_AE_ACTLR2_EL1
+ orr x0, x0, #CORTEX_A78_AE_ACTLR2_EL1_BIT_40
+ msr CORTEX_A78_AE_ACTLR2_EL1, x0
+ isb
+1:
+ ret x17
+endfunc errata_a78_ae_2395408_wa
+
+func check_errata_2395408
+ /* Applies to revisions r0p0 and r0p1. */
+ mov x1, #CPU_REV(0, 0)
+ mov x2, #CPU_REV(0, 1)
+ b cpu_rev_var_range
+endfunc check_errata_2395408
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_cve_2022_23960
+
+ /* -------------------------------------------------
+ * The CPU Ops reset function for Cortex-A78-AE
+ * -------------------------------------------------
+ */
+func cortex_a78_ae_reset_func
+ mov x19, x30
+ bl cpu_get_rev_var
+ mov x18, x0
+
+#if ERRATA_A78_AE_1941500
+ mov x0, x18
+ bl errata_a78_ae_1941500_wa
+#endif
+
+#if ERRATA_A78_AE_1951502
+ mov x0, x18
+ bl errata_a78_ae_1951502_wa
+#endif
+
+#if ERRATA_A78_AE_2376748
+ mov x0, x18
+ bl errata_a78_ae_2376748_wa
+#endif
+
+#if ERRATA_A78_AE_2395408
+ mov x0, x18
+ bl errata_a78_ae_2395408_wa
+#endif
+
+#if ENABLE_AMU
+ /* Make sure accesses from EL0/EL1 and EL2 are not trapped to EL3 */
+ mrs x0, actlr_el3
+ bic x0, x0, #CORTEX_A78_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_A78_ACTLR_TAM_BIT
+ msr actlr_el2, x0
+
+ /* Enable group0 counters */
+ mov x0, #CORTEX_A78_AMU_GROUP0_MASK
+ msr CPUAMCNTENSET0_EL0, x0
+
+ /* Enable group1 counters */
+ mov x0, #CORTEX_A78_AMU_GROUP1_MASK
+ msr CPUAMCNTENSET1_EL0, x0
+#endif
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2022_23960
+ /*
+ * The Cortex-A78AE generic vectors are overridden to apply errata
+ * mitigation on exception entry from lower ELs.
+ */
+ adr x0, wa_cve_vbar_cortex_a78_ae
+ msr vbar_el3, x0
+#endif /* IMAGE_BL31 && WORKAROUND_CVE_2022_23960 */
+
+ isb
+ ret x19
+endfunc cortex_a78_ae_reset_func
+
+ /* -------------------------------------------------------
+ * HW will do the cache maintenance while powering down
+ * -------------------------------------------------------
+ */
+func cortex_a78_ae_core_pwr_dwn
+ /* -------------------------------------------------------
+ * Enable CPU power down bit in power control register
+ * -------------------------------------------------------
+ */
+ mrs x0, CORTEX_A78_CPUPWRCTLR_EL1
+ orr x0, x0, #CORTEX_A78_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT
+ msr CORTEX_A78_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+endfunc cortex_a78_ae_core_pwr_dwn
+
+ /*
+ * Errata printing function for cortex_a78_ae. Must follow AAPCS.
+ */
+#if REPORT_ERRATA
+func cortex_a78_ae_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_A78_AE_1941500, cortex_a78_ae, 1941500
+ report_errata ERRATA_A78_AE_1951502, cortex_a78_ae, 1951502
+ report_errata ERRATA_A78_AE_2376748, cortex_a78_ae, 2376748
+ report_errata ERRATA_A78_AE_2395408, cortex_a78_ae, 2395408
+ report_errata WORKAROUND_CVE_2022_23960, cortex_a78_ae, cve_2022_23960
+
+ ldp x8, x30, [sp], #16
+ ret
+endfunc cortex_a78_ae_errata_report
+#endif
+
+ /* -------------------------------------------------------
+ * This function provides cortex_a78_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_a78_ae_regs, "aS"
+cortex_a78_ae_regs: /* The ascii list of register names to be reported */
+ .asciz "cpuectlr_el1", ""
+
+func cortex_a78_ae_cpu_reg_dump
+ adr x6, cortex_a78_ae_regs
+ mrs x8, CORTEX_A78_CPUECTLR_EL1
+ ret
+endfunc cortex_a78_ae_cpu_reg_dump
+
+declare_cpu_ops cortex_a78_ae, CORTEX_A78_AE_MIDR, \
+ cortex_a78_ae_reset_func, \
+ cortex_a78_ae_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a78c.S b/lib/cpus/aarch64/cortex_a78c.S
new file mode 100644
index 0000000..49cebfe
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a78c.S
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a78c.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "cortex_a78c must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* --------------------------------------------------
+ * Errata Workaround for Cortex A78C Erratum 2376749.
+ * This applies to revision r0p1 and r0p2 of the A78C
+ * and is currently open. It is a Cat B erratum.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x4, x17
+ * --------------------------------------------------
+ */
+func errata_a78c_2376749_wa
+ /* Check revision */
+ mov x17, x30
+ bl check_errata_2376749
+ cbz x0, 1f
+ /* Set CPUACTLR2_EL1[0] to 1. */
+ mrs x1, CORTEX_A78C_CPUACTLR2_EL1
+ orr x1, x1, #CORTEX_A78C_CPUACTLR2_EL1_BIT_0
+ msr CORTEX_A78C_CPUACTLR2_EL1, x1
+1:
+ ret x17
+endfunc errata_a78c_2376749_wa
+
+func check_errata_2376749
+ /* Applies to r0p1 and r0p2*/
+ mov x1, #0x01
+ mov x2, #0x02
+ b cpu_rev_var_range
+endfunc check_errata_2376749
+
+/* --------------------------------------------------
+ * Errata Workaround for Cortex A78C Erratum 2395411.
+ * This applies to revision r0p1 and r0p2 of the A78C
+ * and is currently open. It is a Cat B erratum.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x4, x17
+ * --------------------------------------------------
+ */
+func errata_a78c_2395411_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_2395411
+ cbz x0, 1f
+
+ /* Set CPUACTRL2_EL1[40] to 1. */
+ mrs x1, CORTEX_A78C_CPUACTLR2_EL1
+ orr x1, x1, #CORTEX_A78C_CPUACTLR2_EL1_BIT_40
+ msr CORTEX_A78C_CPUACTLR2_EL1, x1
+1:
+ ret x17
+endfunc errata_a78c_2395411_wa
+
+func check_errata_2395411
+ /* Applies to r0p1 and r0p2 */
+ mov x1, #0x01
+ mov x2, #0x02
+ b cpu_rev_var_range
+endfunc check_errata_2395411
+
+#if WORKAROUND_CVE_2022_23960
+ wa_cve_2022_23960_bhb_vector_table CORTEX_A78C_BHB_LOOP_COUNT, cortex_a78c
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+/* --------------------------------------------------
+ * Errata Workaround for A78C Erratum 2132064.
+ * This applies to revisions r0p1 and r0p2 of A78C
+ * and is still open.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a78c_2132064_wa
+ /* Compare x0 against revisions r0p0 - r0p1 */
+ mov x17, x30
+ bl check_errata_2132064
+ cbz x0, 1f
+
+ /* --------------------------------------------------------
+ * Place the data prefetcher in the most conservative mode
+ * to reduce prefetches by writing the following bits to
+ * the value indicated: ecltr[7:6], PF_MODE = 2'b11
+ * --------------------------------------------------------
+ */
+ mrs x0, CORTEX_A78C_CPUECTLR_EL1
+ orr x0, x0, #CORTEX_A78C_CPUECTLR_EL1_BIT_6
+ orr x0, x0, #CORTEX_A78C_CPUECTLR_EL1_BIT_7
+ msr CORTEX_A78C_CPUECTLR_EL1, x0
+ isb
+1:
+ ret x17
+endfunc errata_a78c_2132064_wa
+
+func check_errata_2132064
+ /* Applies to revisions r0p1 and r0p2. */
+ mov x1, #CPU_REV(0, 1)
+ mov x2, #CPU_REV(0, 2)
+ b cpu_rev_var_range
+endfunc check_errata_2132064
+
+/* --------------------------------------------------------------------
+ * Errata Workaround for A78C Erratum 2242638.
+ * This applies to revisions r0p1 and r0p2 of the Cortex A78C
+ * processor and is still open.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------------------------
+ */
+func errata_a78c_2242638_wa
+ /* Compare x0 against revisions r0p1 - r0p2 */
+ mov x17, x30
+ bl check_errata_2242638
+ cbz x0, 1f
+
+ ldr x0, =0x5
+ msr CORTEX_A78C_IMP_CPUPSELR_EL3, x0
+ ldr x0, =0x10F600E000
+ msr CORTEX_A78C_IMP_CPUPOR_EL3, x0
+ ldr x0, =0x10FF80E000
+ msr CORTEX_A78C_IMP_CPUPMR_EL3, x0
+ ldr x0, =0x80000000003FF
+ msr CORTEX_A78C_IMP_CPUPCR_EL3, x0
+
+ isb
+1:
+ ret x17
+endfunc errata_a78c_2242638_wa
+
+func check_errata_2242638
+ /* Applies to revisions r0p1-r0p2. */
+ mov x1, #CPU_REV(0, 1)
+ mov x2, #CPU_REV(0, 2)
+ b cpu_rev_var_range
+endfunc check_errata_2242638
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_cve_2022_23960
+
+ /* -------------------------------------------------
+ * The CPU Ops reset function for Cortex-A78C
+ * -------------------------------------------------
+ */
+func cortex_a78c_reset_func
+ mov x19, x30
+ bl cpu_get_rev_var
+ mov x18, x0
+
+#if ERRATA_A78C_2132064
+ mov x0, x18
+ bl errata_a78c_2132064_wa
+#endif
+
+#if ERRATA_A78C_2242638
+ mov x0, x18
+ bl errata_a78c_2242638_wa
+#endif
+
+#if ERRATA_A78C_2376749
+ mov x0, x18
+ bl errata_a78c_2376749_wa
+#endif
+
+#if ERRATA_A78C_2395411
+ mov x0, x18
+ bl errata_a78c_2395411_wa
+#endif
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2022_23960
+ /*
+ * The Cortex-A78c generic vectors are overridden to apply errata
+ * mitigation on exception entry from lower ELs.
+ */
+ adr x0, wa_cve_vbar_cortex_a78c
+ msr vbar_el3, x0
+#endif /* IMAGE_BL31 && WORKAROUND_CVE_2022_23960 */
+
+ isb
+ ret x19
+endfunc cortex_a78c_reset_func
+
+ /* ----------------------------------------------------
+ * HW will do the cache maintenance while powering down
+ * ----------------------------------------------------
+ */
+func cortex_a78c_core_pwr_dwn
+ /* ---------------------------------------------------
+ * Enable CPU power down bit in power control register
+ * ---------------------------------------------------
+ */
+ mrs x0, CORTEX_A78C_CPUPWRCTLR_EL1
+ orr x0, x0, #CORTEX_A78C_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT
+ msr CORTEX_A78C_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+endfunc cortex_a78c_core_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A78C. Must follow AAPCS.
+ */
+func cortex_a78c_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_A78C_2132064, cortex_a78c, 2132064
+ report_errata ERRATA_A78C_2242638, cortex_a78c, 2242638
+ report_errata ERRATA_A78C_2376749, cortex_a78c, 2376749
+ report_errata ERRATA_A78C_2395411, cortex_a78c, 2395411
+ report_errata WORKAROUND_CVE_2022_23960, cortex_a78c, cve_2022_23960
+
+ ldp x8, x30, [sp], #16
+ ret
+endfunc cortex_a78c_errata_report
+#endif
+
+ /* ---------------------------------------------
+ * This function provides cortex_a78c 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_a78c_regs, "aS"
+cortex_a78c_regs: /* The ascii list of register names to be reported */
+ .asciz "cpuectlr_el1", ""
+
+func cortex_a78c_cpu_reg_dump
+ adr x6, cortex_a78c_regs
+ mrs x8, CORTEX_A78C_CPUECTLR_EL1
+ ret
+endfunc cortex_a78c_cpu_reg_dump
+
+declare_cpu_ops cortex_a78c, CORTEX_A78C_MIDR, \
+ cortex_a78c_reset_func, \
+ cortex_a78c_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_hayes.S b/lib/cpus/aarch64/cortex_hayes.S
new file mode 100644
index 0000000..445a691
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_hayes.S
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_hayes.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Cortex Hayes must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Cortex Hayes supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+ /* ----------------------------------------------------
+ * HW will do the cache maintenance while powering down
+ * ----------------------------------------------------
+ */
+func cortex_hayes_core_pwr_dwn
+ /* ---------------------------------------------------
+ * Enable CPU power down bit in power control register
+ * ---------------------------------------------------
+ */
+ mrs x0, CORTEX_HAYES_CPUPWRCTLR_EL1
+ orr x0, x0, #CORTEX_HAYES_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+ msr CORTEX_HAYES_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+endfunc cortex_hayes_core_pwr_dwn
+
+ /*
+ * Errata printing function for Cortex Hayes. Must follow AAPCS.
+ */
+#if REPORT_ERRATA
+func cortex_hayes_errata_report
+ ret
+endfunc cortex_hayes_errata_report
+#endif
+
+func cortex_hayes_reset_func
+ /* Disable speculative loads */
+ msr SSBS, xzr
+ isb
+ ret
+endfunc cortex_hayes_reset_func
+
+ /* ---------------------------------------------
+ * This function provides Cortex Hayes 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_hayes_regs, "aS"
+cortex_hayes_regs: /* The ascii list of register names to be reported */
+ .asciz "cpuectlr_el1", ""
+
+func cortex_hayes_cpu_reg_dump
+ adr x6, cortex_hayes_regs
+ mrs x8, CORTEX_HAYES_CPUECTLR_EL1
+ ret
+endfunc cortex_hayes_cpu_reg_dump
+
+declare_cpu_ops cortex_hayes, CORTEX_HAYES_MIDR, \
+ cortex_hayes_reset_func, \
+ cortex_hayes_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_hunter.S b/lib/cpus/aarch64/cortex_hunter.S
new file mode 100644
index 0000000..973637e
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_hunter.S
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_hunter.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Cortex Hunter must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Cortex Hunter supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+#if WORKAROUND_CVE_2022_23960
+ wa_cve_2022_23960_bhb_vector_table CORTEX_HUNTER_BHB_LOOP_COUNT, cortex_hunter
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_cve_2022_23960
+
+func cortex_hunter_reset_func
+ /* Disable speculative loads */
+ msr SSBS, xzr
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2022_23960
+ /*
+ * The Cortex Hunter generic vectors are overridden to apply errata
+ * mitigation on exception entry from lower ELs.
+ */
+ adr x0, wa_cve_vbar_cortex_hunter
+ msr vbar_el3, x0
+#endif /* IMAGE_BL31 && WORKAROUND_CVE_2022_23960 */
+
+ isb
+ ret
+endfunc cortex_hunter_reset_func
+
+ /* ----------------------------------------------------
+ * HW will do the cache maintenance while powering down
+ * ----------------------------------------------------
+ */
+func cortex_hunter_core_pwr_dwn
+ /* ---------------------------------------------------
+ * Enable CPU power down bit in power control register
+ * ---------------------------------------------------
+ */
+ mrs x0, CORTEX_HUNTER_CPUPWRCTLR_EL1
+ orr x0, x0, #CORTEX_HUNTER_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+ msr CORTEX_HUNTER_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+endfunc cortex_hunter_core_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex Hunter. Must follow AAPCS.
+ */
+func cortex_hunter_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_2022_23960, cortex_hunter, cve_2022_23960
+
+ ldp x8, x30, [sp], #16
+ ret
+endfunc cortex_hunter_errata_report
+#endif
+
+ /* ---------------------------------------------
+ * This function provides Cortex Hunter-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_hunter_regs, "aS"
+cortex_hunter_regs: /* The ascii list of register names to be reported */
+ .asciz "cpuectlr_el1", ""
+
+func cortex_hunter_cpu_reg_dump
+ adr x6, cortex_hunter_regs
+ mrs x8, CORTEX_HUNTER_CPUECTLR_EL1
+ ret
+endfunc cortex_hunter_cpu_reg_dump
+
+declare_cpu_ops cortex_hunter, CORTEX_HUNTER_MIDR, \
+ cortex_hunter_reset_func, \
+ cortex_hunter_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_hunter_elp_arm.S b/lib/cpus/aarch64/cortex_hunter_elp_arm.S
new file mode 100644
index 0000000..5f86d4e
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_hunter_elp_arm.S
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_hunter_elp_arm.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Cortex Hunter ELP must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Cortex Hunter ELP supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+#if WORKAROUND_CVE_2022_23960
+ wa_cve_2022_23960_bhb_vector_table CORTEX_HUNTER_ELP_ARM_BHB_LOOP_COUNT, cortex_hunter_elp_arm
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_cve_2022_23960
+
+func cortex_hunter_elp_arm_reset_func
+ /* Disable speculative loads */
+ msr SSBS, xzr
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2022_23960
+ /*
+ * The Cortex Hunter ELP generic vectors are overridden to apply errata
+ * mitigation on exception entry from lower ELs.
+ */
+ adr x0, wa_cve_vbar_cortex_hunter_elp_arm
+ msr vbar_el3, x0
+#endif /* IMAGE_BL31 && WORKAROUND_CVE_2022_23960 */
+
+ isb
+ ret
+endfunc cortex_hunter_elp_arm_reset_func
+
+ /* ----------------------------------------------------
+ * HW will do the cache maintenance while powering down
+ * ----------------------------------------------------
+ */
+func cortex_hunter_elp_arm_core_pwr_dwn
+ /* ---------------------------------------------------
+ * Enable CPU power down bit in power control register
+ * ---------------------------------------------------
+ */
+ mrs x0, CORTEX_HUNTER_ELP_ARM_CPUPWRCTLR_EL1
+ orr x0, x0, #CORTEX_HUNTER_ELP_ARM_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+ msr CORTEX_HUNTER_ELP_ARM_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+endfunc cortex_hunter_elp_arm_core_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex Hunter ELP. Must follow AAPCS.
+ */
+func cortex_hunter_elp_arm_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_2022_23960, cortex_hunter_elp_arm, cve_2022_23960
+
+ ldp x8, x30, [sp], #16
+ ret
+endfunc cortex_hunter_elp_arm_errata_report
+#endif
+
+ /* ---------------------------------------------
+ * This function provides Cortex Hunter ELP-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_hunter_elp_arm_regs, "aS"
+cortex_hunter_elp_arm_regs: /* The ascii list of register names to be reported */
+ .asciz "cpuectlr_el1", ""
+
+func cortex_hunter_elp_arm_cpu_reg_dump
+ adr x6, cortex_hunter_elp_arm_regs
+ mrs x8, CORTEX_HUNTER_ELP_ARM_CPUECTLR_EL1
+ ret
+endfunc cortex_hunter_elp_arm_cpu_reg_dump
+
+declare_cpu_ops cortex_hunter_elp_arm, CORTEX_HUNTER_ELP_ARM_MIDR, \
+ cortex_hunter_elp_arm_reset_func, \
+ cortex_hunter_elp_arm_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_x1.S b/lib/cpus/aarch64/cortex_x1.S
new file mode 100644
index 0000000..9a7f666
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_x1.S
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2022, Google LLC. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <cortex_x1.h>
+#include <cpu_macros.S>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Cortex-X1 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Cortex-X1 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+#if WORKAROUND_CVE_2022_23960
+ wa_cve_2022_23960_bhb_vector_table CORTEX_X1_BHB_LOOP_COUNT, cortex_x1
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+/* --------------------------------------------------
+ * Errata Workaround for X1 Erratum 1821534.
+ * This applies to revision r0p0 and r1p0 of X1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_x1_1821534_wa
+ /* Compare x0 against revision r1p0 */
+ mov x17, x30
+ bl check_errata_1821534
+ cbz x0, 1f
+ mrs x1, CORTEX_X1_ACTLR2_EL1
+ orr x1, x1, BIT(2)
+ msr CORTEX_X1_ACTLR2_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_x1_1821534_wa
+
+func check_errata_1821534
+ /* Applies to r0p0 and r1p0 */
+ mov x1, #0x10
+ b cpu_rev_var_ls
+endfunc check_errata_1821534
+
+/* --------------------------------------------------
+ * Errata Workaround for X1 Erratum 1688305.
+ * This applies to revision r0p0 and r1p0 of X1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_x1_1688305_wa
+ /* Compare x0 against revision r1p0 */
+ mov x17, x30
+ bl check_errata_1688305
+ cbz x0, 1f
+ mrs x0, CORTEX_X1_ACTLR2_EL1
+ orr x0, x0, BIT(1)
+ msr CORTEX_X1_ACTLR2_EL1, x0
+ isb
+
+1:
+ ret x17
+endfunc errata_x1_1688305_wa
+
+func check_errata_1688305
+ /* Applies to r0p0 and r1p0 */
+ mov x1, #0x10
+ b cpu_rev_var_ls
+endfunc check_errata_1688305
+
+/* --------------------------------------------------
+ * Errata Workaround for X1 Erratum 1827429.
+ * This applies to revision r0p0 and r1p0 of X1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_x1_1827429_wa
+ /* Compare x0 against revision r1p0 */
+ mov x17, x30
+ bl check_errata_1827429
+ cbz x0, 1f
+ mrs x0, CORTEX_X1_CPUECTLR_EL1
+ orr x0, x0, BIT(53)
+ msr CORTEX_X1_CPUECTLR_EL1, x0
+ isb
+
+1:
+ ret x17
+endfunc errata_x1_1827429_wa
+
+func check_errata_1827429
+ /* Applies to r0p0 and r1p0 */
+ mov x1, #0x10
+ b cpu_rev_var_ls
+endfunc check_errata_1827429
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_cve_2022_23960
+
+ /* -------------------------------------------------
+ * The CPU Ops reset function for Cortex-X1.
+ * Shall clobber: x0-x19
+ * -------------------------------------------------
+ */
+func cortex_x1_reset_func
+ mov x19, x30
+ bl cpu_get_rev_var
+ mov x18, x0
+
+#if ERRATA_X1_1821534
+ mov x0, x18
+ bl errata_x1_1821534_wa
+#endif
+
+#if ERRATA_X1_1688305
+ mov x0, x18
+ bl errata_x1_1688305_wa
+#endif
+
+#if ERRATA_X1_1827429
+ mov x0, x18
+ bl errata_x1_1827429_wa
+#endif
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2022_23960
+ /*
+ * The Cortex-X1 generic vectors are overridden to apply errata
+ * mitigation on exception entry from lower ELs.
+ */
+ adr x0, wa_cve_vbar_cortex_x1
+ msr vbar_el3, x0
+#endif /* IMAGE_BL31 && WORKAROUND_CVE_2022_23960 */
+
+ isb
+ ret x19
+endfunc cortex_x1_reset_func
+
+ /* ---------------------------------------------
+ * HW will do the cache maintenance while powering down
+ * ---------------------------------------------
+ */
+func cortex_x1_core_pwr_dwn
+ /* ---------------------------------------------
+ * Enable CPU power down bit in power control register
+ * ---------------------------------------------
+ */
+ mrs x0, CORTEX_X1_CPUPWRCTLR_EL1
+ orr x0, x0, #CORTEX_X1_CORE_PWRDN_EN_MASK
+ msr CORTEX_X1_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+endfunc cortex_x1_core_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex X1. Must follow AAPCS.
+ */
+func cortex_x1_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_X1_1821534, cortex_x1, 1821534
+ report_errata ERRATA_X1_1688305, cortex_x1, 1688305
+ report_errata ERRATA_X1_1827429, cortex_x1, 1827429
+ report_errata WORKAROUND_CVE_2022_23960, cortex_x1, cve_2022_23960
+
+ ldp x8, x30, [sp], #16
+ ret
+endfunc cortex_x1_errata_report
+#endif
+
+ /* ---------------------------------------------
+ * This function provides Cortex X1 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_x1_regs, "aS"
+cortex_x1_regs: /* The ascii list of register names to be reported */
+ .asciz "cpuectlr_el1", ""
+
+func cortex_x1_cpu_reg_dump
+ adr x6, cortex_x1_regs
+ mrs x8, CORTEX_X1_CPUECTLR_EL1
+ ret
+endfunc cortex_x1_cpu_reg_dump
+
+declare_cpu_ops cortex_x1, CORTEX_X1_MIDR, \
+ cortex_x1_reset_func, \
+ cortex_x1_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_x2.S b/lib/cpus/aarch64/cortex_x2.S
new file mode 100644
index 0000000..c810be6
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_x2.S
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_x2.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Cortex X2 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Cortex X2 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+#if WORKAROUND_CVE_2022_23960
+ wa_cve_2022_23960_bhb_vector_table CORTEX_X2_BHB_LOOP_COUNT, cortex_x2
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex X2 Errata #2002765.
+ * This applies to revisions r0p0, r1p0, and r2p0 and
+ * is open.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1, x17
+ * --------------------------------------------------
+ */
+func errata_cortex_x2_2002765_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_2002765
+ cbz x0, 1f
+
+ ldr x0, =0x6
+ msr S3_6_C15_C8_0, x0 /* CPUPSELR_EL3 */
+ ldr x0, =0xF3A08002
+ msr S3_6_C15_C8_2, x0 /* CPUPOR_EL3 */
+ ldr x0, =0xFFF0F7FE
+ msr S3_6_C15_C8_3, x0 /* CPUPMR_EL3 */
+ ldr x0, =0x40000001003ff
+ msr S3_6_C15_C8_1, x0 /* CPUPCR_EL3 */
+ isb
+
+1:
+ ret x17
+endfunc errata_cortex_x2_2002765_wa
+
+func check_errata_2002765
+ /* Applies to r0p0 - r2p0 */
+ mov x1, #0x20
+ b cpu_rev_var_ls
+endfunc check_errata_2002765
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex X2 Errata #2058056.
+ * This applies to revisions r0p0, r1p0, and r2p0 and
+ * is open.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1, x17
+ * --------------------------------------------------
+ */
+func errata_cortex_x2_2058056_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_2058056
+ cbz x0, 1f
+
+ mrs x1, CORTEX_X2_CPUECTLR2_EL1
+ mov x0, #CORTEX_X2_CPUECTLR2_EL1_PF_MODE_CNSRV
+ bfi x1, x0, #CORTEX_X2_CPUECTLR2_EL1_PF_MODE_SHIFT, #CORTEX_X2_CPUECTLR2_EL1_PF_MODE_WIDTH
+ msr CORTEX_X2_CPUECTLR2_EL1, x1
+
+1:
+ ret x17
+endfunc errata_cortex_x2_2058056_wa
+
+func check_errata_2058056
+ /* Applies to r0p0 - r2p0 */
+ mov x1, #0x20
+ b cpu_rev_var_ls
+endfunc check_errata_2058056
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex X2 Errata #2083908.
+ * This applies to revision r2p0 and is open.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x2, x17
+ * --------------------------------------------------
+ */
+func errata_cortex_x2_2083908_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_2083908
+ cbz x0, 1f
+
+ /* Apply the workaround by setting bit 13 in CPUACTLR5_EL1. */
+ mrs x1, CORTEX_X2_CPUACTLR5_EL1
+ orr x1, x1, #BIT(13)
+ msr CORTEX_X2_CPUACTLR5_EL1, x1
+
+1:
+ ret x17
+endfunc errata_cortex_x2_2083908_wa
+
+func check_errata_2083908
+ /* Applies to r2p0 */
+ mov x1, #0x20
+ mov x2, #0x20
+ b cpu_rev_var_range
+endfunc check_errata_2083908
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex-X2 Errata 2017096.
+ * This applies only to revisions r0p0, r1p0 and r2p0
+ * and is fixed in r2p1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1, x17
+ * --------------------------------------------------
+ */
+func errata_x2_2017096_wa
+ /* Compare x0 against revision r0p0 to r2p0 */
+ mov x17, x30
+ bl check_errata_2017096
+ cbz x0, 1f
+ mrs x1, CORTEX_X2_CPUECTLR_EL1
+ orr x1, x1, CORTEX_X2_CPUECTLR_EL1_PFSTIDIS_BIT
+ msr CORTEX_X2_CPUECTLR_EL1, x1
+
+1:
+ ret x17
+endfunc errata_x2_2017096_wa
+
+func check_errata_2017096
+ /* Applies to r0p0, r1p0, r2p0 */
+ mov x1, #0x20
+ b cpu_rev_var_ls
+endfunc check_errata_2017096
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex-X2 Errata 2081180.
+ * This applies to revision r0p0, r1p0 and r2p0
+ * and is fixed in r2p1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1, x17
+ * --------------------------------------------------
+ */
+func errata_x2_2081180_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_2081180
+ cbz x0, 1f
+
+ /* Apply instruction patching sequence */
+ ldr x0, =0x3
+ msr CORTEX_X2_IMP_CPUPSELR_EL3, x0
+ ldr x0, =0xF3A08002
+ msr CORTEX_X2_IMP_CPUPOR_EL3, x0
+ ldr x0, =0xFFF0F7FE
+ msr CORTEX_X2_IMP_CPUPMR_EL3, x0
+ ldr x0, =0x10002001003FF
+ msr CORTEX_X2_IMP_CPUPCR_EL3, x0
+ ldr x0, =0x4
+ msr CORTEX_X2_IMP_CPUPSELR_EL3, x0
+ ldr x0, =0xBF200000
+ msr CORTEX_X2_IMP_CPUPOR_EL3, x0
+ ldr x0, =0xFFEF0000
+ msr CORTEX_X2_IMP_CPUPMR_EL3, x0
+ ldr x0, =0x10002001003F3
+ msr CORTEX_X2_IMP_CPUPCR_EL3, x0
+ isb
+1:
+ ret x17
+endfunc errata_x2_2081180_wa
+
+func check_errata_2081180
+ /* Applies to r0p0, r1p0 and r2p0 */
+ mov x1, #0x20
+ b cpu_rev_var_ls
+endfunc check_errata_2081180
+
+ /* --------------------------------------------------
+ * Errata Workaround for Cortex X2 Errata 2216384.
+ * This applies to revisions r0p0, r1p0, and r2p0
+ * and is fixed in r2p1.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1, x17
+ * --------------------------------------------------
+ */
+func errata_x2_2216384_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_2216384
+ cbz x0, 1f
+
+ mrs x1, CORTEX_X2_CPUACTLR5_EL1
+ orr x1, x1, CORTEX_X2_CPUACTLR5_EL1_BIT_17
+ msr CORTEX_X2_CPUACTLR5_EL1, x1
+
+ /* Apply instruction patching sequence */
+ ldr x0, =0x5
+ msr CORTEX_X2_IMP_CPUPSELR_EL3, x0
+ ldr x0, =0x10F600E000
+ msr CORTEX_X2_IMP_CPUPOR_EL3, x0
+ ldr x0, =0x10FF80E000
+ msr CORTEX_X2_IMP_CPUPMR_EL3, x0
+ ldr x0, =0x80000000003FF
+ msr CORTEX_X2_IMP_CPUPCR_EL3, x0
+ isb
+
+1:
+ ret x17
+endfunc errata_x2_2216384_wa
+
+func check_errata_2216384
+ /* Applies to r0p0 - r2p0 */
+ mov x1, #0x20
+ b cpu_rev_var_ls
+endfunc check_errata_2216384
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_cve_2022_23960
+
+ /* ---------------------------------------------------------
+ * Errata Workaround for Cortex-X2 Errata 2147715.
+ * This applies only to revisions r2p0 and is fixed in r2p1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1, x17
+ * ---------------------------------------------------------
+ */
+func errata_x2_2147715_wa
+ /* Compare x0 against revision r2p0 */
+ mov x17, x30
+ bl check_errata_2147715
+ cbz x0, 1f
+
+ /* Apply the workaround by setting bit 22 in CPUACTLR_EL1. */
+ mrs x1, CORTEX_X2_CPUACTLR_EL1
+ orr x1, x1, CORTEX_X2_CPUACTLR_EL1_BIT_22
+ msr CORTEX_X2_CPUACTLR_EL1, x1
+
+1:
+ ret x17
+endfunc errata_x2_2147715_wa
+
+func check_errata_2147715
+ /* Applies to r2p0 */
+ mov x1, #0x20
+ mov x2, #0x20
+ b cpu_rev_var_range
+endfunc check_errata_2147715
+
+/* -------------------------------------------------------
+ * Errata Workaround for Cortex-X2 Erratum 2371105.
+ * This applies to revisions <= r2p0 and is fixed in r2p1.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * -------------------------------------------------------
+ */
+func errata_x2_2371105_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_2371105
+ cbz x0, 1f
+
+ /* Set bit 40 in CPUACTLR2_EL1 */
+ mrs x1, CORTEX_X2_CPUACTLR2_EL1
+ orr x1, x1, #CORTEX_X2_CPUACTLR2_EL1_BIT_40
+ msr CORTEX_X2_CPUACTLR2_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_x2_2371105_wa
+
+func check_errata_2371105
+ /* Applies to <= r2p0. */
+ mov x1, #0x20
+ b cpu_rev_var_ls
+endfunc check_errata_2371105
+
+ /* ----------------------------------------------------
+ * HW will do the cache maintenance while powering down
+ * ----------------------------------------------------
+ */
+func cortex_x2_core_pwr_dwn
+ /* ---------------------------------------------------
+ * Enable CPU power down bit in power control register
+ * ---------------------------------------------------
+ */
+ mrs x0, CORTEX_X2_CPUPWRCTLR_EL1
+ orr x0, x0, #CORTEX_X2_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+ msr CORTEX_X2_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+endfunc cortex_x2_core_pwr_dwn
+
+ /*
+ * Errata printing function for Cortex X2. Must follow AAPCS.
+ */
+#if REPORT_ERRATA
+func cortex_x2_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_X2_2002765, cortex_x2, 2002765
+ report_errata ERRATA_X2_2017096, cortex_x2, 2017096
+ report_errata ERRATA_X2_2058056, cortex_x2, 2058056
+ report_errata ERRATA_X2_2081180, cortex_x2, 2081180
+ report_errata ERRATA_X2_2083908, cortex_x2, 2083908
+ report_errata ERRATA_X2_2147715, cortex_x2, 2147715
+ report_errata ERRATA_X2_2216384, cortex_x2, 2216384
+ report_errata ERRATA_X2_2371105, cortex_x2, 2371105
+ report_errata WORKAROUND_CVE_2022_23960, cortex_x2, cve_2022_23960
+ report_errata ERRATA_DSU_2313941, cortex_x2, dsu_2313941
+
+ ldp x8, x30, [sp], #16
+ ret
+endfunc cortex_x2_errata_report
+#endif
+
+func cortex_x2_reset_func
+ mov x19, x30
+
+ /* Disable speculative loads */
+ msr SSBS, xzr
+
+ /* Get the CPU revision and stash it in x18. */
+ bl cpu_get_rev_var
+ mov x18, x0
+
+#if ERRATA_DSU_2313941
+ bl errata_dsu_2313941_wa
+#endif
+
+#if ERRATA_X2_2002765
+ mov x0, x18
+ bl errata_cortex_x2_2002765_wa
+#endif
+
+#if ERRATA_X2_2058056
+ mov x0, x18
+ bl errata_cortex_x2_2058056_wa
+#endif
+
+#if ERRATA_X2_2083908
+ mov x0, x18
+ bl errata_cortex_x2_2083908_wa
+#endif
+
+#if ERRATA_X2_2017096
+ mov x0, x18
+ bl errata_x2_2017096_wa
+#endif
+
+#if ERRATA_X2_2081180
+ mov x0, x18
+ bl errata_x2_2081180_wa
+#endif
+
+#if ERRATA_X2_2216384
+ mov x0, x18
+ bl errata_x2_2216384_wa
+#endif
+
+#if ERRATA_X2_2147715
+ mov x0, x18
+ bl errata_x2_2147715_wa
+#endif
+
+#if ERRATA_X2_2371105
+ mov x0, x18
+ bl errata_x2_2371105_wa
+#endif
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2022_23960
+ /*
+ * The Cortex-X2 generic vectors are overridden to apply errata
+ * mitigation on exception entry from lower ELs.
+ */
+ adr x0, wa_cve_vbar_cortex_x2
+ msr vbar_el3, x0
+#endif /* IMAGE_BL31 && WORKAROUND_CVE_2022_23960 */
+
+ isb
+ ret x19
+endfunc cortex_x2_reset_func
+
+ /* ---------------------------------------------
+ * This function provides Cortex X2 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_x2_regs, "aS"
+cortex_x2_regs: /* The ascii list of register names to be reported */
+ .asciz "cpuectlr_el1", ""
+
+func cortex_x2_cpu_reg_dump
+ adr x6, cortex_x2_regs
+ mrs x8, CORTEX_X2_CPUECTLR_EL1
+ ret
+endfunc cortex_x2_cpu_reg_dump
+
+declare_cpu_ops cortex_x2, CORTEX_X2_MIDR, \
+ cortex_x2_reset_func, \
+ cortex_x2_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_x3.S b/lib/cpus/aarch64/cortex_x3.S
new file mode 100644
index 0000000..bf1b6ec
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_x3.S
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_x3.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Cortex-X3 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Cortex-X3 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+#if WORKAROUND_CVE_2022_23960
+ wa_cve_2022_23960_bhb_vector_table CORTEX_X3_BHB_LOOP_COUNT, cortex_x3
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+ /* ----------------------------------------------------
+ * HW will do the cache maintenance while powering down
+ * ----------------------------------------------------
+ */
+func cortex_x3_core_pwr_dwn
+#if ERRATA_X3_2313909
+ mov x15, x30
+ bl cpu_get_rev_var
+ bl errata_cortex_x3_2313909_wa
+ mov x30, x15
+#endif /* ERRATA_X3_2313909 */
+
+ /* ---------------------------------------------------
+ * Enable CPU power down bit in power control register
+ * ---------------------------------------------------
+ */
+ mrs x0, CORTEX_X3_CPUPWRCTLR_EL1
+ orr x0, x0, #CORTEX_X3_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+ msr CORTEX_X3_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+endfunc cortex_x3_core_pwr_dwn
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_cve_2022_23960
+
+func cortex_x3_reset_func
+ /* Disable speculative loads */
+ msr SSBS, xzr
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2022_23960
+ /*
+ * The Cortex-X3 generic vectors are overridden to apply
+ * errata mitigation on exception entry from lower ELs.
+ */
+ adr x0, wa_cve_vbar_cortex_x3
+ msr vbar_el3, x0
+#endif /* IMAGE_BL31 && WORKAROUND_CVE_2022_23960 */
+
+ isb
+ ret
+endfunc cortex_x3_reset_func
+
+/* ----------------------------------------------------------------------
+ * Errata Workaround for Cortex-X3 Erratum 2313909 on power down request.
+ * This applies to revision r0p0 and r1p0 of Cortex-X3. Fixed in r1p1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x1, x17
+ * ----------------------------------------------------------------------
+ */
+func errata_cortex_x3_2313909_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_2313909
+ cbz x0, 1f
+
+ /* Set bit 36 in ACTLR2_EL1 */
+ mrs x1, CORTEX_X3_CPUACTLR2_EL1
+ orr x1, x1, #CORTEX_X3_CPUACTLR2_EL1_BIT_36
+ msr CORTEX_X3_CPUACTLR2_EL1, x1
+1:
+ ret x17
+endfunc errata_cortex_x3_2313909_wa
+
+func check_errata_2313909
+ /* Applies to r0p0 and r1p0 */
+ mov x1, #0x10
+ b cpu_rev_var_ls
+endfunc check_errata_2313909
+
+#if REPORT_ERRATA
+ /*
+ * Errata printing function for Cortex-X3. Must follow AAPCS.
+ */
+func cortex_x3_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_X3_2313909, cortex_x3, 2313909
+ report_errata WORKAROUND_CVE_2022_23960, cortex_x3, cve_2022_23960
+
+ ldp x8, x30, [sp], #16
+ ret
+endfunc cortex_x3_errata_report
+#endif
+
+ /* ---------------------------------------------
+ * This function provides Cortex-X3-
+ * 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_x3_regs, "aS"
+cortex_x3_regs: /* The ascii list of register names to be reported */
+ .asciz "cpuectlr_el1", ""
+
+func cortex_x3_cpu_reg_dump
+ adr x6, cortex_x3_regs
+ mrs x8, CORTEX_X3_CPUECTLR_EL1
+ ret
+endfunc cortex_x3_cpu_reg_dump
+
+declare_cpu_ops cortex_x3, CORTEX_X3_MIDR, \
+ cortex_x3_reset_func, \
+ cortex_x3_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cpu_helpers.S b/lib/cpus/aarch64/cpu_helpers.S
new file mode 100644
index 0000000..2385627
--- /dev/null
+++ b/lib/cpus/aarch64/cpu_helpers.S
@@ -0,0 +1,456 @@
+/*
+ * Copyright (c) 2014-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <cpu_macros.S>
+#include <lib/cpus/errata_report.h>
+#include <lib/el3_runtime/cpu_data.h>
+
+ /* 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]
+#if ENABLE_ASSERTIONS
+ cmp x1, #0
+ ASM_ASSERT(ne)
+#endif
+ 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.
+ *
+ * If cpu_ops for the MIDR_EL1 cannot be found and
+ * SUPPORT_UNKNOWN_MPID is enabled, it will try to look for a
+ * default cpu_ops with an MIDR value of 0.
+ * (Implementation number 0x0 should be reserved for software use
+ * and therefore no clashes should happen with that default value).
+ *
+ * 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
+ /* 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
+
+ /* Get the cpu_ops end location */
+ adr x5, (__CPU_OPS_END__ + CPU_MIDR)
+
+ /* Initialize the return parameter */
+ mov x0, #0
+1:
+ /* Get the cpu_ops start location */
+ adr x4, (__CPU_OPS_START__ + CPU_MIDR)
+
+2:
+ /* Check if we have reached end of list */
+ cmp x4, x5
+ b.eq search_def_ptr
+
+ /* 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 2b
+
+ /* Subtract the increment and offset to get the cpu-ops pointer */
+ sub x0, x4, #(CPU_OPS_SIZE + CPU_MIDR)
+#if ENABLE_ASSERTIONS
+ cmp x0, #0
+ ASM_ASSERT(ne)
+#endif
+#ifdef SUPPORT_UNKNOWN_MPID
+ cbnz x2, exit_mpid_found
+ /* Mark the unsupported MPID flag */
+ adrp x1, unsupported_mpid_flag
+ add x1, x1, :lo12:unsupported_mpid_flag
+ str w2, [x1]
+exit_mpid_found:
+#endif
+ ret
+
+ /*
+ * Search again for a default pointer (MIDR = 0x0)
+ * or return error if already searched.
+ */
+search_def_ptr:
+#ifdef SUPPORT_UNKNOWN_MPID
+ cbz x2, error_exit
+ mov x2, #0
+ b 1b
+error_exit:
+#endif
+ 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
+#if ENABLE_ASSERTIONS
+ cmp x0, #0
+ ASM_ASSERT(ne)
+#endif
+ ldr x1, [x0, #CPU_DATA_CPU_OPS_PTR]
+#if ENABLE_ASSERTIONS
+ cmp x1, #0
+ ASM_ASSERT(ne)
+#endif
+ 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]
+#if ENABLE_ASSERTIONS
+ cmp x0, #0
+ ASM_ASSERT(ne)
+#endif
+ 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, #CPU_NO_EXTRA1_FUNC
+ 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]
+#if ENABLE_ASSERTIONS
+ cmp x0, #0
+ ASM_ASSERT(ne)
+#endif
+ ldr x0, [x0, #CPU_EXTRA2_FUNC]
+ ret
+endfunc wa_cve_2018_3639_get_disable_ptr
+
+/*
+ * int check_smccc_arch_wa3_applies(void);
+ *
+ * This function checks whether SMCCC_ARCH_WORKAROUND_3 is enabled to mitigate
+ * CVE-2022-23960 for this CPU. It returns:
+ * - ERRATA_APPLIES when SMCCC_ARCH_WORKAROUND_3 can be invoked to mitigate
+ * the CVE.
+ * - ERRATA_NOT_APPLIES when SMCCC_ARCH_WORKAROUND_3 should not be invoked to
+ * mitigate the CVE.
+ *
+ * NOTE: Must be called only after cpu_ops have been initialized
+ * in per-CPU data.
+ */
+ .globl check_smccc_arch_wa3_applies
+func check_smccc_arch_wa3_applies
+ mrs x0, tpidr_el3
+#if ENABLE_ASSERTIONS
+ cmp x0, #0
+ ASM_ASSERT(ne)
+#endif
+ ldr x0, [x0, #CPU_DATA_CPU_OPS_PTR]
+#if ENABLE_ASSERTIONS
+ cmp x0, #0
+ ASM_ASSERT(ne)
+#endif
+ ldr x0, [x0, #CPU_EXTRA3_FUNC]
+ /*
+ * If the reserved function pointer is NULL, this CPU
+ * is unaffected by CVE-2022-23960 so bail out.
+ */
+ cmp x0, #CPU_NO_EXTRA3_FUNC
+ beq 1f
+ br x0
+1:
+ mov x0, #ERRATA_NOT_APPLIES
+ ret
+endfunc check_smccc_arch_wa3_applies
diff --git a/lib/cpus/aarch64/cpuamu.c b/lib/cpus/aarch64/cpuamu.c
new file mode 100644
index 0000000..3a2fa81
--- /dev/null
+++ b/lib/cpus/aarch64/cpuamu.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cpuamu.h>
+#include <lib/el3_runtime/pubsub_events.h>
+#include <plat/common/platform.h>
+
+#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);
+}
diff --git a/lib/cpus/aarch64/cpuamu_helpers.S b/lib/cpus/aarch64/cpuamu_helpers.S
new file mode 100644
index 0000000..5a77fc7
--- /dev/null
+++ b/lib/cpus/aarch64/cpuamu_helpers.S
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cpuamu.h>
+
+ .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
diff --git a/lib/cpus/aarch64/denver.S b/lib/cpus/aarch64/denver.S
new file mode 100644
index 0000000..3c54a6f
--- /dev/null
+++ b/lib/cpus/aarch64/denver.S
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <context.h>
+#include <denver.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+ /* -------------------------------------------------
+ * 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.
+ * -------------------------------------------------
+ */
+vector_base workaround_bpflush_runtime_exceptions
+
+ .macro apply_workaround
+ stp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
+
+ /* Disable cycle counter when event counting is prohibited */
+ mrs x1, pmcr_el0
+ orr x0, x1, #PMCR_EL0_DP_BIT
+ msr pmcr_el0, x0
+ isb
+
+ /* -------------------------------------------------
+ * 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
+ /* DCO is not supported on PN5 and later */
+ mrs x1, midr_el1
+ mov_imm x2, DENVER_MIDR_PN4
+ cmp x1, x2
+ b.hi 1f
+
+ mov x18, x30
+ bl plat_my_core_pos
+ mov x1, #1
+ lsl x1, x1, x0
+ msr s3_0_c15_c0_2, x1
+ mov x30, x18
+1: ret
+endfunc denver_enable_dco
+
+ /* ----------------------------------------------------
+ * Disable dynamic code optimizer (DCO)
+ * ----------------------------------------------------
+ */
+func denver_disable_dco
+ /* DCO is not supported on PN5 and later */
+ mrs x1, midr_el1
+ mov_imm x2, DENVER_MIDR_PN4
+ cmp x1, x2
+ b.hi 2f
+
+ /* turn off background work */
+ mov x18, x30
+ 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, x18
+2: 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
+
+/* macro to declare cpu_ops for Denver SKUs */
+.macro denver_cpu_ops_wa midr
+ declare_cpu_ops_wa denver, \midr, \
+ denver_reset_func, \
+ check_errata_cve_2017_5715, \
+ CPU_NO_EXTRA2_FUNC, \
+ CPU_NO_EXTRA3_FUNC, \
+ denver_core_pwr_dwn, \
+ denver_cluster_pwr_dwn
+.endm
+
+denver_cpu_ops_wa DENVER_MIDR_PN0
+denver_cpu_ops_wa DENVER_MIDR_PN1
+denver_cpu_ops_wa DENVER_MIDR_PN2
+denver_cpu_ops_wa DENVER_MIDR_PN3
+denver_cpu_ops_wa DENVER_MIDR_PN4
+denver_cpu_ops_wa DENVER_MIDR_PN5
+denver_cpu_ops_wa DENVER_MIDR_PN6
+denver_cpu_ops_wa DENVER_MIDR_PN7
+denver_cpu_ops_wa DENVER_MIDR_PN8
+denver_cpu_ops_wa DENVER_MIDR_PN9
diff --git a/lib/cpus/aarch64/dsu_helpers.S b/lib/cpus/aarch64/dsu_helpers.S
new file mode 100644
index 0000000..419b6ea
--- /dev/null
+++ b/lib/cpus/aarch64/dsu_helpers.S
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2019-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <dsu_def.h>
+#include <lib/cpus/errata_report.h>
+
+ /* -----------------------------------------------------------------------
+ * 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-x15
+ * -----------------------------------------------------------------------
+ */
+ .globl check_errata_dsu_936184
+ .globl errata_dsu_936184_wa
+ .weak is_scu_present_in_dsu
+
+ /* --------------------------------------------------------------------
+ * Default behaviour respresents SCU is always present with DSU.
+ * CPUs can override this definition if required.
+ *
+ * Can clobber only: x0-x14
+ * --------------------------------------------------------------------
+ */
+func is_scu_present_in_dsu
+ mov x0, #1
+ ret
+endfunc is_scu_present_in_dsu
+
+func check_errata_dsu_936184
+ mov x15, x30
+ bl is_scu_present_in_dsu
+ cmp x0, xzr
+ /* Default error status */
+ mov x0, #ERRATA_NOT_APPLIES
+
+ /* If SCU is not present, return without applying patch */
+ b.eq 1f
+
+ /* Erratum applies only if DSU has the ACP interface */
+ 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 x2, x1, #CLUSTERIDR_REV_SHIFT,\
+ #(CLUSTERIDR_REV_BITS + CLUSTERIDR_VAR_BITS)
+ cmp x2, #(0x2 << CLUSTERIDR_VAR_SHIFT)
+ b.hs 1f
+ mov x0, #ERRATA_APPLIES
+1:
+ ret x15
+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
+
+ /* -----------------------------------------------------------------------
+ * DSU erratum 2313941 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, r1p0, r2p0, r2p1, r3p0, r3p1.
+ *
+ * The erratum is still open.
+ *
+ * This function is called from both assembly and C environment. So it
+ * follows AAPCS.
+ *
+ * Clobbers: x0-x3
+ * -----------------------------------------------------------------------
+ */
+ .globl check_errata_dsu_2313941
+ .globl errata_dsu_2313941_wa
+
+func check_errata_dsu_2313941
+ mov x2, #ERRATA_APPLIES
+ mov x3, #ERRATA_NOT_APPLIES
+
+ /* Check if DSU version is less than or equal to r3p1 */
+ 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, #(0x31 << CLUSTERIDR_REV_SHIFT)
+ cmp x0, x1
+ csel x0, x2, x3, LS
+ ret
+endfunc check_errata_dsu_2313941
+
+ /* --------------------------------------------------
+ * Errata Workaround for DSU erratum #2313941.
+ *
+ * Can clobber only: x0-x17
+ * --------------------------------------------------
+ */
+func errata_dsu_2313941_wa
+ mov x17, x30
+ bl check_errata_dsu_2313941
+ cbz x0, 1f
+
+ /* If erratum applies, disable high-level clock gating */
+ mrs x0, CLUSTERACTLR_EL1
+ orr x0, x0, #CLUSTERACTLR_EL1_DISABLE_SCLK_GATING
+ msr CLUSTERACTLR_EL1, x0
+ isb
+1:
+ ret x17
+endfunc errata_dsu_2313941_wa
+
diff --git a/lib/cpus/aarch64/generic.S b/lib/cpus/aarch64/generic.S
new file mode 100644
index 0000000..ef1f048
--- /dev/null
+++ b/lib/cpus/aarch64/generic.S
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <generic.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+ /* ---------------------------------------------
+ * Disable L1 data cache and unified L2 cache
+ * ---------------------------------------------
+ */
+func generic_disable_dcache
+ mrs x1, sctlr_el3
+ bic x1, x1, #SCTLR_C_BIT
+ msr sctlr_el3, x1
+ isb
+ ret
+endfunc generic_disable_dcache
+
+func generic_core_pwr_dwn
+ mov x18, x30
+
+ /* ---------------------------------------------
+ * Turn off caches.
+ * ---------------------------------------------
+ */
+ bl generic_disable_dcache
+
+ /* ---------------------------------------------
+ * Flush L1 caches.
+ * ---------------------------------------------
+ */
+ mov x0, #DCCISW
+ bl dcsw_op_level1
+
+ ret x18
+endfunc generic_core_pwr_dwn
+
+func generic_cluster_pwr_dwn
+ mov x18, x30
+
+ /* ---------------------------------------------
+ * Turn off caches.
+ * ---------------------------------------------
+ */
+ bl generic_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
+
+ ret x18
+
+endfunc generic_cluster_pwr_dwn
+
+/* ---------------------------------------------
+ * Unimplemented functions.
+ * ---------------------------------------------
+ */
+.equ generic_errata_report, 0
+.equ generic_cpu_reg_dump, 0
+.equ generic_reset_func, 0
+
+declare_cpu_ops generic, AARCH64_GENERIC_MIDR, \
+ generic_reset_func, \
+ generic_core_pwr_dwn, \
+ generic_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/neoverse_e1.S b/lib/cpus/aarch64/neoverse_e1.S
new file mode 100644
index 0000000..96b63cf
--- /dev/null
+++ b/lib/cpus/aarch64/neoverse_e1.S
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <neoverse_e1.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+/* 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
diff --git a/lib/cpus/aarch64/neoverse_n1.S b/lib/cpus/aarch64/neoverse_n1.S
new file mode 100644
index 0000000..ec62519
--- /dev/null
+++ b/lib/cpus/aarch64/neoverse_n1.S
@@ -0,0 +1,745 @@
+/*
+ * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cpuamu.h>
+#include <cpu_macros.S>
+#include <neoverse_n1.h>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+/* 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
+
+ .global neoverse_n1_errata_ic_trap_handler
+
+#if WORKAROUND_CVE_2022_23960
+ wa_cve_2022_23960_bhb_vector_table NEOVERSE_N1_BHB_LOOP_COUNT, neoverse_n1
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+/* --------------------------------------------------
+ * 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
+
+ /* --------------------------------------------------
+ * Errata Workaround for Neoverse N1 Errata #1868343.
+ * This applies to revision <= r4p0 of Neoverse N1.
+ * This workaround is the same as the workaround for
+ * errata 1262606 and 1275112 but applies to a wider
+ * revision range.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_n1_1868343_wa
+ /*
+ * Compare x0 against revision r4p0
+ */
+ mov x17, x30
+ bl check_errata_1868343
+ cbz x0, 1f
+ mrs x1, NEOVERSE_N1_CPUACTLR_EL1
+ orr x1, x1, NEOVERSE_N1_CPUACTLR_EL1_BIT_13
+ msr NEOVERSE_N1_CPUACTLR_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_n1_1868343_wa
+
+func check_errata_1868343
+ /* Applies to everything <= r4p0 */
+ mov x1, #0x40
+ b cpu_rev_var_ls
+endfunc check_errata_1868343
+
+ /* --------------------------------------------------
+ * Errata Workaround for Neoverse N1 Errata #1946160.
+ * This applies to revisions r3p0, r3p1, r4p0, and
+ * r4p1 of Neoverse N1. It also exists in r0p0, r1p0,
+ * and r2p0 but there is no fix in these revisions.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_n1_1946160_wa
+ /*
+ * Compare x0 against r3p0 - r4p1
+ */
+ mov x17, x30
+ bl check_errata_1946160
+ cbz x0, 1f
+
+ mov x0, #3
+ msr S3_6_C15_C8_0, x0
+ ldr x0, =0x10E3900002
+ msr S3_6_C15_C8_2, x0
+ ldr x0, =0x10FFF00083
+ msr S3_6_C15_C8_3, x0
+ ldr x0, =0x2001003FF
+ msr S3_6_C15_C8_1, x0
+
+ mov x0, #4
+ msr S3_6_C15_C8_0, x0
+ ldr x0, =0x10E3800082
+ msr S3_6_C15_C8_2, x0
+ ldr x0, =0x10FFF00083
+ msr S3_6_C15_C8_3, x0
+ ldr x0, =0x2001003FF
+ msr S3_6_C15_C8_1, x0
+
+ mov x0, #5
+ msr S3_6_C15_C8_0, x0
+ ldr x0, =0x10E3800200
+ msr S3_6_C15_C8_2, x0
+ ldr x0, =0x10FFF003E0
+ msr S3_6_C15_C8_3, x0
+ ldr x0, =0x2001003FF
+ msr S3_6_C15_C8_1, x0
+
+ isb
+1:
+ ret x17
+endfunc errata_n1_1946160_wa
+
+func check_errata_1946160
+ /* Applies to r3p0 - r4p1. */
+ mov x1, #0x30
+ mov x2, #0x41
+ b cpu_rev_var_range
+endfunc check_errata_1946160
+
+ /* ----------------------------------------------------
+ * Errata Workaround for Neoverse N1 Errata #2743102
+ * This applies to revisions <= r4p1 and is still open.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * ----------------------------------------------------
+ */
+func errata_n1_2743102_wa
+ mov x17, x30
+ bl check_errata_2743102
+ cbz x0, 1f
+
+ /* dsb before isb of power down sequence */
+ dsb sy
+1:
+ ret x17
+endfunc errata_n1_2743102_wa
+
+func check_errata_2743102
+ /* Applies to all revisions <= r4p1 */
+ mov x1, #0x41
+ b cpu_rev_var_ls
+endfunc check_errata_2743102
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_cve_2022_23960
+
+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 ERRATA_N1_1868343
+ mov x0, x18
+ bl errata_n1_1868343_wa
+#endif
+
+#if ERRATA_N1_1946160
+ mov x0, x18
+ bl errata_n1_1946160_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 NEOVERSE_Nx_EXTERNAL_LLC
+ /* Some system may have External LLC, core needs to be made aware */
+ mrs x0, NEOVERSE_N1_CPUECTLR_EL1
+ orr x0, x0, NEOVERSE_N1_CPUECTLR_EL1_EXTLLC_BIT
+ msr NEOVERSE_N1_CPUECTLR_EL1, x0
+#endif
+
+#if ERRATA_DSU_936184
+ bl errata_dsu_936184_wa
+#endif
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2022_23960
+ /*
+ * The Neoverse-N1 generic vectors are overridden to apply errata
+ * mitigation on exception entry from lower ELs.
+ */
+ adr x0, wa_cve_vbar_neoverse_n1
+ msr vbar_el3, x0
+#endif /* IMAGE_BL31 && WORKAROUND_CVE_2022_23960 */
+
+ 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
+#if ERRATA_N1_2743102
+ mov x15, x30
+ bl cpu_get_rev_var
+ bl errata_n1_2743102_wa
+ mov x30, x15
+#endif /* ERRATA_N1_2743102 */
+ 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_N1_1868343, neoverse_n1, 1868343
+ report_errata ERRATA_N1_1946160, neoverse_n1, 1946160
+ report_errata ERRATA_N1_2743102, neoverse_n1, 2743102
+ report_errata ERRATA_DSU_936184, neoverse_n1, dsu_936184
+ report_errata WORKAROUND_CVE_2022_23960, neoverse_n1, cve_2022_23960
+
+ 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
+ exception_return
+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
diff --git a/lib/cpus/aarch64/neoverse_n1_pubsub.c b/lib/cpus/aarch64/neoverse_n1_pubsub.c
new file mode 100644
index 0000000..b1b7bb8
--- /dev/null
+++ b/lib/cpus/aarch64/neoverse_n1_pubsub.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <neoverse_n1.h>
+#include <cpuamu.h>
+#include <lib/el3_runtime/pubsub_events.h>
+
+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);
diff --git a/lib/cpus/aarch64/neoverse_n2.S b/lib/cpus/aarch64/neoverse_n2.S
new file mode 100644
index 0000000..5861dec
--- /dev/null
+++ b/lib/cpus/aarch64/neoverse_n2.S
@@ -0,0 +1,639 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cpu_macros.S>
+#include <neoverse_n2.h>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Neoverse N2 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Neoverse-N2 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+#if WORKAROUND_CVE_2022_23960
+ wa_cve_2022_23960_bhb_vector_table NEOVERSE_N2_BHB_LOOP_COUNT, neoverse_n2
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N2 Erratum 2002655.
+ * This applies to revision r0p0 of Neoverse N2. it is still open.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_n2_2002655_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_2002655
+ cbz x0, 1f
+
+ /* Apply instruction patching sequence */
+ ldr x0,=0x6
+ msr S3_6_c15_c8_0,x0
+ ldr x0,=0xF3A08002
+ msr S3_6_c15_c8_2,x0
+ ldr x0,=0xFFF0F7FE
+ msr S3_6_c15_c8_3,x0
+ ldr x0,=0x40000001003ff
+ msr S3_6_c15_c8_1,x0
+ ldr x0,=0x7
+ msr S3_6_c15_c8_0,x0
+ ldr x0,=0xBF200000
+ msr S3_6_c15_c8_2,x0
+ ldr x0,=0xFFEF0000
+ msr S3_6_c15_c8_3,x0
+ ldr x0,=0x40000001003f3
+ msr S3_6_c15_c8_1,x0
+ isb
+1:
+ ret x17
+endfunc errata_n2_2002655_wa
+
+func check_errata_2002655
+ /* Applies to r0p0 */
+ mov x1, #0x00
+ b cpu_rev_var_ls
+endfunc check_errata_2002655
+
+/* ---------------------------------------------------------------
+ * Errata Workaround for Neoverse N2 Erratum 2067956.
+ * This applies to revision r0p0 of Neoverse N2 and is still open.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * ---------------------------------------------------------------
+ */
+func errata_n2_2067956_wa
+ /* Compare x0 against revision r0p0 */
+ mov x17, x30
+ bl check_errata_2067956
+ cbz x0, 1f
+ mrs x1, NEOVERSE_N2_CPUACTLR_EL1
+ orr x1, x1, NEOVERSE_N2_CPUACTLR_EL1_BIT_46
+ msr NEOVERSE_N2_CPUACTLR_EL1, x1
+1:
+ ret x17
+endfunc errata_n2_2067956_wa
+
+func check_errata_2067956
+ /* Applies to r0p0 */
+ mov x1, #0x00
+ b cpu_rev_var_ls
+endfunc check_errata_2067956
+
+/* ---------------------------------------------------------------
+ * Errata Workaround for Neoverse N2 Erratum 2025414.
+ * This applies to revision r0p0 of Neoverse N2 and is still open.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * ---------------------------------------------------------------
+ */
+func errata_n2_2025414_wa
+ /* Compare x0 against revision r0p0 */
+ mov x17, x30
+ bl check_errata_2025414
+ cbz x0, 1f
+ mrs x1, NEOVERSE_N2_CPUECTLR_EL1
+ orr x1, x1, NEOVERSE_N2_CPUECTLR_EL1_PFSTIDIS_BIT
+ msr NEOVERSE_N2_CPUECTLR_EL1, x1
+
+1:
+ ret x17
+endfunc errata_n2_2025414_wa
+
+func check_errata_2025414
+ /* Applies to r0p0 */
+ mov x1, #0x00
+ b cpu_rev_var_ls
+endfunc check_errata_2025414
+
+/* ---------------------------------------------------------------
+ * Errata Workaround for Neoverse N2 Erratum 2189731.
+ * This applies to revision r0p0 of Neoverse N2 and is still open.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * ---------------------------------------------------------------
+ */
+func errata_n2_2189731_wa
+ /* Compare x0 against revision r0p0 */
+ mov x17, x30
+ bl check_errata_2189731
+ cbz x0, 1f
+ mrs x1, NEOVERSE_N2_CPUACTLR5_EL1
+ orr x1, x1, NEOVERSE_N2_CPUACTLR5_EL1_BIT_44
+ msr NEOVERSE_N2_CPUACTLR5_EL1, x1
+
+1:
+ ret x17
+endfunc errata_n2_2189731_wa
+
+func check_errata_2189731
+ /* Applies to r0p0 */
+ mov x1, #0x00
+ b cpu_rev_var_ls
+endfunc check_errata_2189731
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N2 Erratum 2138956.
+ * This applies to revision r0p0 of Neoverse N2. it is still open.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_n2_2138956_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_2138956
+ cbz x0, 1f
+
+ /* Apply instruction patching sequence */
+ ldr x0,=0x3
+ msr S3_6_c15_c8_0,x0
+ ldr x0,=0xF3A08002
+ msr S3_6_c15_c8_2,x0
+ ldr x0,=0xFFF0F7FE
+ msr S3_6_c15_c8_3,x0
+ ldr x0,=0x10002001003FF
+ msr S3_6_c15_c8_1,x0
+ ldr x0,=0x4
+ msr S3_6_c15_c8_0,x0
+ ldr x0,=0xBF200000
+ msr S3_6_c15_c8_2,x0
+ ldr x0,=0xFFEF0000
+ msr S3_6_c15_c8_3,x0
+ ldr x0,=0x10002001003F3
+ msr S3_6_c15_c8_1,x0
+ isb
+1:
+ ret x17
+endfunc errata_n2_2138956_wa
+
+func check_errata_2138956
+ /* Applies to r0p0 */
+ mov x1, #0x00
+ b cpu_rev_var_ls
+endfunc check_errata_2138956
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N2 Erratum 2242415.
+ * This applies to revision r0p0 of Neoverse N2. it is still open.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x1, x17
+ * --------------------------------------------------
+ */
+func errata_n2_2242415_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_2242415
+ cbz x0, 1f
+
+ /* Apply instruction patching sequence */
+ mrs x1, NEOVERSE_N2_CPUACTLR_EL1
+ orr x1, x1, NEOVERSE_N2_CPUACTLR_EL1_BIT_22
+ msr NEOVERSE_N2_CPUACTLR_EL1, x1
+1:
+ ret x17
+endfunc errata_n2_2242415_wa
+
+func check_errata_2242415
+ /* Applies to r0p0 */
+ mov x1, #0x00
+ b cpu_rev_var_ls
+endfunc check_errata_2242415
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N2 Erratum 2138953.
+ * This applies to revision r0p0 of Neoverse N2. it is still open.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x1, x17
+ * --------------------------------------------------
+ */
+func errata_n2_2138953_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_2138953
+ cbz x0, 1f
+
+ /* Apply instruction patching sequence */
+ mrs x1, NEOVERSE_N2_CPUECTLR2_EL1
+ mov x0, #NEOVERSE_N2_CPUECTLR2_EL1_PF_MODE_CNSRV
+ bfi x1, x0, #CPUECTLR2_EL1_PF_MODE_LSB, #CPUECTLR2_EL1_PF_MODE_WIDTH
+ msr NEOVERSE_N2_CPUECTLR2_EL1, x1
+1:
+ ret x17
+endfunc errata_n2_2138953_wa
+
+func check_errata_2138953
+ /* Applies to r0p0 */
+ mov x1, #0x00
+ b cpu_rev_var_ls
+endfunc check_errata_2138953
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N2 Erratum 2138958.
+ * This applies to revision r0p0 of Neoverse N2. it is still open.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x1, x17
+ * --------------------------------------------------
+ */
+func errata_n2_2138958_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_2138958
+ cbz x0, 1f
+
+ /* Apply instruction patching sequence */
+ mrs x1, NEOVERSE_N2_CPUACTLR5_EL1
+ orr x1, x1, NEOVERSE_N2_CPUACTLR5_EL1_BIT_13
+ msr NEOVERSE_N2_CPUACTLR5_EL1, x1
+1:
+ ret x17
+endfunc errata_n2_2138958_wa
+
+func check_errata_2138958
+ /* Applies to r0p0 */
+ mov x1, #0x00
+ b cpu_rev_var_ls
+endfunc check_errata_2138958
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N2 Erratum 2242400.
+ * This applies to revision r0p0 of Neoverse N2. it is still open.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x1, x17
+ * --------------------------------------------------
+ */
+func errata_n2_2242400_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_2242400
+ cbz x0, 1f
+
+ /* Apply instruction patching sequence */
+ mrs x1, NEOVERSE_N2_CPUACTLR5_EL1
+ orr x1, x1, NEOVERSE_N2_CPUACTLR5_EL1_BIT_17
+ msr NEOVERSE_N2_CPUACTLR5_EL1, x1
+ ldr x0, =0x2
+ msr S3_6_c15_c8_0, x0
+ ldr x0, =0x10F600E000
+ msr S3_6_c15_c8_2, x0
+ ldr x0, =0x10FF80E000
+ msr S3_6_c15_c8_3, x0
+ ldr x0, =0x80000000003FF
+ msr S3_6_c15_c8_1, x0
+ isb
+1:
+ ret x17
+endfunc errata_n2_2242400_wa
+
+func check_errata_2242400
+ /* Applies to r0p0 */
+ mov x1, #0x00
+ b cpu_rev_var_ls
+endfunc check_errata_2242400
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N2 Erratum 2280757.
+ * This applies to revision r0p0 of Neoverse N2. it is still open.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x1, x17
+ * --------------------------------------------------
+ */
+func errata_n2_2280757_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_2280757
+ cbz x0, 1f
+
+ /* Apply instruction patching sequence */
+ mrs x1, NEOVERSE_N2_CPUACTLR_EL1
+ orr x1, x1, NEOVERSE_N2_CPUACTLR_EL1_BIT_22
+ msr NEOVERSE_N2_CPUACTLR_EL1, x1
+1:
+ ret x17
+endfunc errata_n2_2280757_wa
+
+func check_errata_2280757
+ /* Applies to r0p0 */
+ mov x1, #0x00
+ b cpu_rev_var_ls
+endfunc check_errata_2280757
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N2 Erratum 2326639.
+ * This applies to revision r0p0 of Neoverse N2,
+ * fixed in r0p1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x1, x17
+ * --------------------------------------------------
+ */
+func errata_n2_2326639_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_2326639
+ cbz x0, 1f
+
+ /* Set bit 36 in ACTLR2_EL1 */
+ mrs x1, NEOVERSE_N2_CPUACTLR2_EL1
+ orr x1, x1, #NEOVERSE_N2_CPUACTLR2_EL1_BIT_36
+ msr NEOVERSE_N2_CPUACTLR2_EL1, x1
+1:
+ ret x17
+endfunc errata_n2_2326639_wa
+
+func check_errata_2326639
+ /* Applies to r0p0, fixed in r0p1 */
+ mov x1, #0x00
+ b cpu_rev_var_ls
+endfunc check_errata_2326639
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N2 Erratum 2376738.
+ * This applies to revision r0p0 of Neoverse N2,
+ * fixed in r0p1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current CPU.
+ * Shall clobber: x0-x1, x17
+ * --------------------------------------------------
+ */
+func errata_n2_2376738_wa
+ mov x17, x30
+ bl check_errata_2376738
+ cbz x0, 1f
+
+ /* Set CPUACTLR2_EL1[0] to 1 to force PLDW/PFRM
+ * ST to behave like PLD/PFRM LD and not cause
+ * invalidations to other PE caches.
+ */
+ mrs x1, NEOVERSE_N2_CPUACTLR2_EL1
+ orr x1, x1, NEOVERSE_N2_CPUACTLR2_EL1_BIT_0
+ msr NEOVERSE_N2_CPUACTLR2_EL1, x1
+1:
+ ret x17
+endfunc errata_n2_2376738_wa
+
+func check_errata_2376738
+ /* Applies to r0p0, fixed in r0p1 */
+ mov x1, 0x00
+ b cpu_rev_var_ls
+endfunc check_errata_2376738
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N2 Erratum 2388450.
+ * This applies to revision r0p0 of Neoverse N2,
+ * fixed in r0p1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x1, x17
+ * --------------------------------------------------
+ */
+func errata_n2_2388450_wa
+ /* Check revision. */
+ mov x17, x30
+ bl check_errata_2388450
+ cbz x0, 1f
+
+ /*Set bit 40 in ACTLR2_EL1 */
+ mrs x1, NEOVERSE_N2_CPUACTLR2_EL1
+ orr x1, x1, #NEOVERSE_N2_CPUACTLR2_EL1_BIT_40
+ msr NEOVERSE_N2_CPUACTLR2_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_n2_2388450_wa
+
+func check_errata_2388450
+ /* Applies to r0p0, fixed in r0p1 */
+ mov x1, #0x00
+ b cpu_rev_var_ls
+endfunc check_errata_2388450
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_cve_2022_23960
+
+ /* -------------------------------------------
+ * The CPU Ops reset function for Neoverse N2.
+ * -------------------------------------------
+ */
+func neoverse_n2_reset_func
+ mov x19, x30
+
+ /* 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:
+ /* Force all cacheable atomic instructions to be near */
+ mrs x0, NEOVERSE_N2_CPUACTLR2_EL1
+ orr x0, x0, #NEOVERSE_N2_CPUACTLR2_EL1_BIT_2
+ msr NEOVERSE_N2_CPUACTLR2_EL1, x0
+
+ /* Get the CPU revision and stash it in x18. */
+ bl cpu_get_rev_var
+ mov x18, x0
+
+#if ERRATA_DSU_2313941
+ bl errata_dsu_2313941_wa
+#endif
+
+#if ERRATA_N2_2067956
+ mov x0, x18
+ bl errata_n2_2067956_wa
+#endif
+
+#if ERRATA_N2_2025414
+ mov x0, x18
+ bl errata_n2_2025414_wa
+#endif
+
+#if ERRATA_N2_2189731
+ mov x0, x18
+ bl errata_n2_2189731_wa
+#endif
+
+
+#if ERRATA_N2_2138956
+ mov x0, x18
+ bl errata_n2_2138956_wa
+#endif
+
+#if ERRATA_N2_2138953
+ mov x0, x18
+ bl errata_n2_2138953_wa
+#endif
+
+#if ERRATA_N2_2242415
+ mov x0, x18
+ bl errata_n2_2242415_wa
+#endif
+
+#if ERRATA_N2_2138958
+ mov x0, x18
+ bl errata_n2_2138958_wa
+#endif
+
+#if ERRATA_N2_2242400
+ mov x0, x18
+ bl errata_n2_2242400_wa
+#endif
+
+#if ERRATA_N2_2280757
+ mov x0, x18
+ bl errata_n2_2280757_wa
+#endif
+
+#if ERRATA_N2_2376738
+ mov x0, x18
+ bl errata_n2_2376738_wa
+#endif
+
+#if ERRATA_N2_2388450
+ mov x0, x18
+ bl errata_n2_2388450_wa
+#endif
+
+#if ENABLE_AMU
+ /* Make sure accesses from EL0/EL1 and EL2 are not trapped to EL3 */
+ mrs x0, cptr_el3
+ orr x0, x0, #TAM_BIT
+ msr cptr_el3, x0
+
+ /* Make sure accesses from EL0/EL1 are not trapped to EL2 */
+ mrs x0, cptr_el2
+ orr x0, x0, #TAM_BIT
+ msr cptr_el2, x0
+
+ /* No need to enable the counters as this would be done at el3 exit */
+#endif
+
+#if NEOVERSE_Nx_EXTERNAL_LLC
+ /* Some systems may have External LLC, core needs to be made aware */
+ mrs x0, NEOVERSE_N2_CPUECTLR_EL1
+ orr x0, x0, NEOVERSE_N2_CPUECTLR_EL1_EXTLLC_BIT
+ msr NEOVERSE_N2_CPUECTLR_EL1, x0
+#endif
+
+#if ERRATA_N2_2002655
+ mov x0, x18
+ bl errata_n2_2002655_wa
+#endif
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2022_23960
+ /*
+ * The Neoverse-N2 generic vectors are overridden to apply errata
+ * mitigation on exception entry from lower ELs.
+ */
+ adr x0, wa_cve_vbar_neoverse_n2
+ msr vbar_el3, x0
+#endif /* IMAGE_BL31 && WORKAROUND_CVE_2022_23960 */
+
+ isb
+ ret x19
+endfunc neoverse_n2_reset_func
+
+func neoverse_n2_core_pwr_dwn
+#if ERRATA_N2_2326639
+ mov x15, x30
+ bl cpu_get_rev_var
+ bl errata_n2_2326639_wa
+ mov x30, x15
+#endif /* ERRATA_N2_2326639 */
+
+ /* ---------------------------------------------------
+ * Enable CPU power down bit in power control register
+ * No need to do cache maintenance here.
+ * ---------------------------------------------------
+ */
+ mrs x0, NEOVERSE_N2_CPUPWRCTLR_EL1
+ orr x0, x0, #NEOVERSE_N2_CORE_PWRDN_EN_BIT
+ msr NEOVERSE_N2_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+endfunc neoverse_n2_core_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Neoverse N2 cores. Must follow AAPCS.
+ */
+func neoverse_n2_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_N2_2002655, neoverse_n2, 2002655
+ report_errata ERRATA_N2_2067956, neoverse_n2, 2067956
+ report_errata ERRATA_N2_2025414, neoverse_n2, 2025414
+ report_errata ERRATA_N2_2189731, neoverse_n2, 2189731
+ report_errata ERRATA_N2_2138956, neoverse_n2, 2138956
+ report_errata ERRATA_N2_2138953, neoverse_n2, 2138953
+ report_errata ERRATA_N2_2242415, neoverse_n2, 2242415
+ report_errata ERRATA_N2_2138958, neoverse_n2, 2138958
+ report_errata ERRATA_N2_2242400, neoverse_n2, 2242400
+ report_errata ERRATA_N2_2280757, neoverse_n2, 2280757
+ report_errata ERRATA_N2_2326639, neoverse_n2, 2326639
+ report_errata ERRATA_N2_2376738, neoverse_n2, 2376738
+ report_errata ERRATA_N2_2388450, neoverse_n2, 2388450
+ report_errata WORKAROUND_CVE_2022_23960, neoverse_n2, cve_2022_23960
+ report_errata ERRATA_DSU_2313941, neoverse_n2, dsu_2313941
+
+ ldp x8, x30, [sp], #16
+ ret
+endfunc neoverse_n2_errata_report
+#endif
+
+ /* ---------------------------------------------
+ * This function provides Neoverse N2 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_n2_regs, "aS"
+neoverse_n2_regs: /* The ASCII list of register names to be reported */
+ .asciz "cpupwrctlr_el1", ""
+
+func neoverse_n2_cpu_reg_dump
+ adr x6, neoverse_n2_regs
+ mrs x8, NEOVERSE_N2_CPUPWRCTLR_EL1
+ ret
+endfunc neoverse_n2_cpu_reg_dump
+
+declare_cpu_ops neoverse_n2, NEOVERSE_N2_MIDR, \
+ neoverse_n2_reset_func, \
+ neoverse_n2_core_pwr_dwn
diff --git a/lib/cpus/aarch64/neoverse_n_common.S b/lib/cpus/aarch64/neoverse_n_common.S
new file mode 100644
index 0000000..b816342
--- /dev/null
+++ b/lib/cpus/aarch64/neoverse_n_common.S
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <neoverse_n_common.h>
+
+ .global is_scu_present_in_dsu
+
+/*
+ * Check if the SCU L3 Unit is present on the DSU
+ * 1-> SCU present
+ * 0-> SCU not present
+ *
+ * This function is implemented as weak on dsu_helpers.S and must be
+ * overwritten for Neoverse Nx cores.
+ */
+
+func is_scu_present_in_dsu
+ mrs x0, CPUCFR_EL1
+ ubfx x0, x0, #SCU_SHIFT, #1
+ eor x0, x0, #1
+ ret
+endfunc is_scu_present_in_dsu
diff --git a/lib/cpus/aarch64/neoverse_poseidon.S b/lib/cpus/aarch64/neoverse_poseidon.S
new file mode 100644
index 0000000..030293d
--- /dev/null
+++ b/lib/cpus/aarch64/neoverse_poseidon.S
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <neoverse_poseidon.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Neoverse Poseidon must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Neoverse Poseidon supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+#if WORKAROUND_CVE_2022_23960
+ wa_cve_2022_23960_bhb_vector_table NEOVERSE_POSEIDON_BHB_LOOP_COUNT, neoverse_poseidon
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+ /* ---------------------------------------------
+ * HW will do the cache maintenance while powering down
+ * ---------------------------------------------
+ */
+func neoverse_poseidon_core_pwr_dwn
+ /* ---------------------------------------------
+ * Enable CPU power down bit in power control register
+ * ---------------------------------------------
+ */
+ mrs x0, NEOVERSE_POSEIDON_CPUPWRCTLR_EL1
+ orr x0, x0, #NEOVERSE_POSEIDON_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+ msr NEOVERSE_POSEIDON_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+endfunc neoverse_poseidon_core_pwr_dwn
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_cve_2022_23960
+
+func neoverse_poseidon_reset_func
+ /* Disable speculative loads */
+ msr SSBS, xzr
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2022_23960
+ /*
+ * The Neoverse Poseidon generic vectors are overridden to apply
+ * errata mitigation on exception entry from lower ELs.
+ */
+ adr x0, wa_cve_vbar_neoverse_poseidon
+ msr vbar_el3, x0
+#endif /* IMAGE_BL31 && WORKAROUND_CVE_2022_23960 */
+
+ isb
+ ret
+endfunc neoverse_poseidon_reset_func
+
+#if REPORT_ERRATA
+ /*
+ * Errata printing function for Neoverse Poseidon. Must follow AAPCS.
+ */
+func neoverse_poseidon_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_2022_23960, neoverse_poseidon, cve_2022_23960
+
+ ldp x8, x30, [sp], #16
+ ret
+endfunc neoverse_poseidon_errata_report
+#endif
+
+ /* ---------------------------------------------
+ * This function provides Neoverse-Poseidon 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_poseidon_regs, "aS"
+neoverse_poseidon_regs: /* The ascii list of register names to be reported */
+ .asciz "cpuectlr_el1", ""
+
+func neoverse_poseidon_cpu_reg_dump
+ adr x6, neoverse_poseidon_regs
+ mrs x8, NEOVERSE_POSEIDON_CPUECTLR_EL1
+ ret
+endfunc neoverse_poseidon_cpu_reg_dump
+
+declare_cpu_ops neoverse_poseidon, NEOVERSE_POSEIDON_MIDR, \
+ neoverse_poseidon_reset_func, \
+ neoverse_poseidon_core_pwr_dwn
diff --git a/lib/cpus/aarch64/neoverse_v1.S b/lib/cpus/aarch64/neoverse_v1.S
new file mode 100644
index 0000000..3282fbc
--- /dev/null
+++ b/lib/cpus/aarch64/neoverse_v1.S
@@ -0,0 +1,628 @@
+/*
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <neoverse_v1.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Neoverse V1 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Neoverse-V1 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+#if WORKAROUND_CVE_2022_23960
+ wa_cve_2022_23960_bhb_vector_table NEOVERSE_V1_BHB_LOOP_COUNT, neoverse_v1
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+ /* --------------------------------------------------
+ * Errata Workaround for Neoverse V1 Errata #1618635.
+ * This applies to revision r0p0 and is fixed in
+ * r1p0.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x17
+ * --------------------------------------------------
+ */
+func errata_neoverse_v1_1618635_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_1618635
+ cbz x0, 1f
+
+ /* Inserts a DMB SY before and after MRS PAR_EL1 */
+ ldr x0, =0x0
+ msr NEOVERSE_V1_CPUPSELR_EL3, x0
+ ldr x0, = 0xEE070F14
+ msr NEOVERSE_V1_CPUPOR_EL3, x0
+ ldr x0, = 0xFFFF0FFF
+ msr NEOVERSE_V1_CPUPMR_EL3, x0
+ ldr x0, =0x4005027FF
+ msr NEOVERSE_V1_CPUPCR_EL3, x0
+
+ /* Inserts a DMB SY before STREX imm offset */
+ ldr x0, =0x1
+ msr NEOVERSE_V1_CPUPSELR_EL3, x0
+ ldr x0, =0x00e8400000
+ msr NEOVERSE_V1_CPUPOR_EL3, x0
+ ldr x0, =0x00fff00000
+ msr NEOVERSE_V1_CPUPMR_EL3, x0
+ ldr x0, = 0x4001027FF
+ msr NEOVERSE_V1_CPUPCR_EL3, x0
+
+ /* Inserts a DMB SY before STREX[BHD}/STLEX* */
+ ldr x0, =0x2
+ msr NEOVERSE_V1_CPUPSELR_EL3, x0
+ ldr x0, =0x00e8c00040
+ msr NEOVERSE_V1_CPUPOR_EL3, x0
+ ldr x0, =0x00fff00040
+ msr NEOVERSE_V1_CPUPMR_EL3, x0
+ ldr x0, = 0x4001027FF
+ msr NEOVERSE_V1_CPUPCR_EL3, x0
+
+ /* Inserts a DMB SY after STREX imm offset */
+ ldr x0, =0x3
+ msr NEOVERSE_V1_CPUPSELR_EL3, x0
+ ldr x0, =0x00e8400000
+ msr NEOVERSE_V1_CPUPOR_EL3, x0
+ ldr x0, =0x00fff00000
+ msr NEOVERSE_V1_CPUPMR_EL3, x0
+ ldr x0, = 0x4004027FF
+ msr NEOVERSE_V1_CPUPCR_EL3, x0
+
+ /* Inserts a DMB SY after STREX[BHD}/STLEX* */
+ ldr x0, =0x4
+ msr NEOVERSE_V1_CPUPSELR_EL3, x0
+ ldr x0, =0x00e8c00040
+ msr NEOVERSE_V1_CPUPOR_EL3, x0
+ ldr x0, =0x00fff00040
+ msr NEOVERSE_V1_CPUPMR_EL3, x0
+ ldr x0, = 0x4004027FF
+ msr NEOVERSE_V1_CPUPCR_EL3, x0
+
+ /* Synchronize to enable patches */
+ isb
+1:
+ ret x17
+endfunc errata_neoverse_v1_1618635_wa
+
+func check_errata_1618635
+ /* Applies to revision r0p0. */
+ mov x1, #0x00
+ b cpu_rev_var_ls
+endfunc check_errata_1618635
+
+ /* --------------------------------------------------
+ * Errata Workaround for Neoverse V1 Errata #1774420.
+ * This applies to revisions r0p0 and r1p0, fixed in r1p1.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_neoverse_v1_1774420_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_1774420
+ cbz x0, 1f
+
+ /* Set bit 53 in CPUECTLR_EL1 */
+ mrs x1, NEOVERSE_V1_CPUECTLR_EL1
+ orr x1, x1, #NEOVERSE_V1_CPUECTLR_EL1_BIT_53
+ msr NEOVERSE_V1_CPUECTLR_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_neoverse_v1_1774420_wa
+
+func check_errata_1774420
+ /* Applies to r0p0 and r1p0. */
+ mov x1, #0x10
+ b cpu_rev_var_ls
+endfunc check_errata_1774420
+
+ /* --------------------------------------------------
+ * Errata Workaround for Neoverse V1 Errata #1791573.
+ * This applies to revisions r0p0 and r1p0, fixed in r1p1.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_neoverse_v1_1791573_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_1791573
+ cbz x0, 1f
+
+ /* Set bit 2 in ACTLR2_EL1 */
+ mrs x1, NEOVERSE_V1_ACTLR2_EL1
+ orr x1, x1, #NEOVERSE_V1_ACTLR2_EL1_BIT_2
+ msr NEOVERSE_V1_ACTLR2_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_neoverse_v1_1791573_wa
+
+func check_errata_1791573
+ /* Applies to r0p0 and r1p0. */
+ mov x1, #0x10
+ b cpu_rev_var_ls
+endfunc check_errata_1791573
+
+ /* --------------------------------------------------
+ * Errata Workaround for Neoverse V1 Errata #1852267.
+ * This applies to revisions r0p0 and r1p0, fixed in r1p1.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_neoverse_v1_1852267_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_1852267
+ cbz x0, 1f
+
+ /* Set bit 28 in ACTLR2_EL1 */
+ mrs x1, NEOVERSE_V1_ACTLR2_EL1
+ orr x1, x1, #NEOVERSE_V1_ACTLR2_EL1_BIT_28
+ msr NEOVERSE_V1_ACTLR2_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_neoverse_v1_1852267_wa
+
+func check_errata_1852267
+ /* Applies to r0p0 and r1p0. */
+ mov x1, #0x10
+ b cpu_rev_var_ls
+endfunc check_errata_1852267
+
+ /* --------------------------------------------------
+ * Errata Workaround for Neoverse V1 Errata #1925756.
+ * This applies to revisions <= r1p1.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_neoverse_v1_1925756_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_1925756
+ cbz x0, 1f
+
+ /* Set bit 8 in CPUECTLR_EL1 */
+ mrs x1, NEOVERSE_V1_CPUECTLR_EL1
+ orr x1, x1, #NEOVERSE_V1_CPUECTLR_EL1_BIT_8
+ msr NEOVERSE_V1_CPUECTLR_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_neoverse_v1_1925756_wa
+
+func check_errata_1925756
+ /* Applies to <= r1p1. */
+ mov x1, #0x11
+ b cpu_rev_var_ls
+endfunc check_errata_1925756
+
+ /* --------------------------------------------------
+ * Errata Workaround for Neoverse V1 Erratum #1940577
+ * This applies to revisions r1p0 - r1p1 and is open.
+ * It also exists in r0p0 but there is no fix in that
+ * revision.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_neoverse_v1_1940577_wa
+ /* Compare x0 against revisions r1p0 - r1p1 */
+ mov x17, x30
+ bl check_errata_1940577
+ cbz x0, 1f
+
+ mov x0, #0
+ msr S3_6_C15_C8_0, x0
+ ldr x0, =0x10E3900002
+ msr S3_6_C15_C8_2, x0
+ ldr x0, =0x10FFF00083
+ msr S3_6_C15_C8_3, x0
+ ldr x0, =0x2001003FF
+ msr S3_6_C15_C8_1, x0
+
+ mov x0, #1
+ msr S3_6_C15_C8_0, x0
+ ldr x0, =0x10E3800082
+ msr S3_6_C15_C8_2, x0
+ ldr x0, =0x10FFF00083
+ msr S3_6_C15_C8_3, x0
+ ldr x0, =0x2001003FF
+ msr S3_6_C15_C8_1, x0
+
+ mov x0, #2
+ msr S3_6_C15_C8_0, x0
+ ldr x0, =0x10E3800200
+ msr S3_6_C15_C8_2, x0
+ ldr x0, =0x10FFF003E0
+ msr S3_6_C15_C8_3, x0
+ ldr x0, =0x2001003FF
+ msr S3_6_C15_C8_1, x0
+
+ isb
+1:
+ ret x17
+endfunc errata_neoverse_v1_1940577_wa
+
+func check_errata_1940577
+ /* Applies to revisions r1p0 - r1p1. */
+ mov x1, #0x10
+ mov x2, #0x11
+ b cpu_rev_var_range
+endfunc check_errata_1940577
+
+ /* --------------------------------------------------
+ * Errata Workaround for Neoverse V1 Errata #1966096
+ * This applies to revisions r1p0 - r1p1 and is open.
+ * It also exists in r0p0 but there is no workaround
+ * for that revision.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_neoverse_v1_1966096_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_1966096
+ cbz x0, 1f
+
+ /* Apply the workaround. */
+ mov x0, #0x3
+ msr S3_6_C15_C8_0, x0
+ ldr x0, =0xEE010F12
+ msr S3_6_C15_C8_2, x0
+ ldr x0, =0xFFFF0FFF
+ msr S3_6_C15_C8_3, x0
+ ldr x0, =0x80000000003FF
+ msr S3_6_C15_C8_1, x0
+ isb
+
+1:
+ ret x17
+endfunc errata_neoverse_v1_1966096_wa
+
+func check_errata_1966096
+ mov x1, #0x10
+ mov x2, #0x11
+ b cpu_rev_var_range
+endfunc check_errata_1966096
+
+ /* --------------------------------------------------
+ * Errata Workaround for Neoverse V1 Errata #2139242.
+ * This applies to revisions r0p0, r1p0, and r1p1, it
+ * is still open.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_neoverse_v1_2139242_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_2139242
+ cbz x0, 1f
+
+ /* Apply the workaround. */
+ mov x0, #0x3
+ msr S3_6_C15_C8_0, x0
+ ldr x0, =0xEE720F14
+ msr S3_6_C15_C8_2, x0
+ ldr x0, =0xFFFF0FDF
+ msr S3_6_C15_C8_3, x0
+ ldr x0, =0x40000005003FF
+ msr S3_6_C15_C8_1, x0
+ isb
+
+1:
+ ret x17
+endfunc errata_neoverse_v1_2139242_wa
+
+func check_errata_2139242
+ /* Applies to r0p0, r1p0, r1p1 */
+ mov x1, #0x11
+ b cpu_rev_var_ls
+endfunc check_errata_2139242
+
+ /* --------------------------------------------------
+ * Errata Workaround for Neoverse V1 Errata #2108267.
+ * This applies to revisions r0p0, r1p0, and r1p1, it
+ * is still open.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x1, x17
+ * --------------------------------------------------
+ */
+func errata_neoverse_v1_2108267_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_2108267
+ cbz x0, 1f
+
+ /* Apply the workaround. */
+ mrs x1, NEOVERSE_V1_CPUECTLR_EL1
+ mov x0, #NEOVERSE_V1_CPUECTLR_EL1_PF_MODE_CNSRV
+ bfi x1, x0, #CPUECTLR_EL1_PF_MODE_LSB, #CPUECTLR_EL1_PF_MODE_WIDTH
+ msr NEOVERSE_V1_CPUECTLR_EL1, x1
+1:
+ ret x17
+endfunc errata_neoverse_v1_2108267_wa
+
+func check_errata_2108267
+ /* Applies to r0p0, r1p0, r1p1 */
+ mov x1, #0x11
+ b cpu_rev_var_ls
+endfunc check_errata_2108267
+
+ /* --------------------------------------------------
+ * Errata Workaround for Neoverse V1 Errata #2216392.
+ * This applies to revisions r1p0 and r1p1 and is
+ * still open.
+ * This issue is also present in r0p0 but there is no
+ * workaround in that revision.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_neoverse_v1_2216392_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_2216392
+ cbz x0, 1f
+
+ ldr x0, =0x5
+ msr S3_6_c15_c8_0, x0 /* CPUPSELR_EL3 */
+ ldr x0, =0x10F600E000
+ msr S3_6_c15_c8_2, x0 /* CPUPOR_EL3 */
+ ldr x0, =0x10FF80E000
+ msr S3_6_c15_c8_3, x0 /* CPUPMR_EL3 */
+ ldr x0, =0x80000000003FF
+ msr S3_6_c15_c8_1, x0 /* CPUPCR_EL3 */
+
+ isb
+1:
+ ret x17
+endfunc errata_neoverse_v1_2216392_wa
+
+func check_errata_2216392
+ /* Applies to revisions r1p0 and r1p1. */
+ mov x1, #CPU_REV(1, 0)
+ mov x2, #CPU_REV(1, 1)
+ b cpu_rev_var_range
+endfunc check_errata_2216392
+
+ /* -----------------------------------------------------------------
+ * Errata Workaround for Neoverse V1 Errata #2294912.
+ * This applies to revisions r0p0, r1p0, and r1p1 and is still open.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * -----------------------------------------------------------------
+ */
+func errata_neoverse_v1_2294912_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_2294912
+ cbz x0, 1f
+
+ /* Set bit 0 in ACTLR2_EL1 */
+ mrs x1, NEOVERSE_V1_ACTLR2_EL1
+ orr x1, x1, #NEOVERSE_V1_ACTLR2_EL1_BIT_0
+ msr NEOVERSE_V1_ACTLR2_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_neoverse_v1_2294912_wa
+
+func check_errata_2294912
+ /* Applies to r0p0, r1p0, and r1p1 right now */
+ mov x1, #0x11
+ b cpu_rev_var_ls
+endfunc check_errata_2294912
+
+ /* ---------------------------------------------------
+ * Errata Workaround for Neoverse V1 Errata #2372203.
+ * This applies to revisions <= r1p1 and is still open.
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * ----------------------------------------------------
+ */
+func errata_neoverse_v1_2372203_wa
+ /* Check workaround compatibility. */
+ mov x17, x30
+ bl check_errata_2372203
+ cbz x0, 1f
+
+ /* Set bit 40 in ACTLR2_EL1 */
+ mrs x1, NEOVERSE_V1_ACTLR2_EL1
+ orr x1, x1, #NEOVERSE_V1_ACTLR2_EL1_BIT_40
+ msr NEOVERSE_V1_ACTLR2_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_neoverse_v1_2372203_wa
+
+func check_errata_2372203
+ /* Applies to <= r1p1. */
+ mov x1, #0x11
+ b cpu_rev_var_ls
+endfunc check_errata_2372203
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_cve_2022_23960
+
+ /* ---------------------------------------------
+ * HW will do the cache maintenance while powering down
+ * ---------------------------------------------
+ */
+func neoverse_v1_core_pwr_dwn
+ /* ---------------------------------------------
+ * Enable CPU power down bit in power control register
+ * ---------------------------------------------
+ */
+ mrs x0, NEOVERSE_V1_CPUPWRCTLR_EL1
+ orr x0, x0, #NEOVERSE_V1_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+ msr NEOVERSE_V1_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+endfunc neoverse_v1_core_pwr_dwn
+
+ /*
+ * Errata printing function for Neoverse V1. Must follow AAPCS.
+ */
+#if REPORT_ERRATA
+func neoverse_v1_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_V1_1618635, neoverse_v1, 1618635
+ report_errata ERRATA_V1_1774420, neoverse_v1, 1774420
+ report_errata ERRATA_V1_1791573, neoverse_v1, 1791573
+ report_errata ERRATA_V1_1852267, neoverse_v1, 1852267
+ report_errata ERRATA_V1_1925756, neoverse_v1, 1925756
+ report_errata ERRATA_V1_1940577, neoverse_v1, 1940577
+ report_errata ERRATA_V1_1966096, neoverse_v1, 1966096
+ report_errata ERRATA_V1_2108267, neoverse_v1, 2108267
+ report_errata ERRATA_V1_2139242, neoverse_v1, 2139242
+ report_errata ERRATA_V1_2216392, neoverse_v1, 2216392
+ report_errata ERRATA_V1_2294912, neoverse_v1, 2294912
+ report_errata ERRATA_V1_2372203, neoverse_v1, 2372203
+ report_errata WORKAROUND_CVE_2022_23960, neoverse_v1, cve_2022_23960
+
+ ldp x8, x30, [sp], #16
+ ret
+endfunc neoverse_v1_errata_report
+#endif
+
+func neoverse_v1_reset_func
+ mov x19, x30
+
+ /* Disable speculative loads */
+ msr SSBS, xzr
+ isb
+
+ /* Get the CPU revision and stash it in x18. */
+ bl cpu_get_rev_var
+ mov x18, x0
+
+#if ERRATA_V1_1618635
+ mov x0, x18
+ bl errata_neoverse_v1_1618635_wa
+#endif
+
+#if ERRATA_V1_1774420
+ mov x0, x18
+ bl errata_neoverse_v1_1774420_wa
+#endif
+
+#if ERRATA_V1_1791573
+ mov x0, x18
+ bl errata_neoverse_v1_1791573_wa
+#endif
+
+#if ERRATA_V1_1852267
+ mov x0, x18
+ bl errata_neoverse_v1_1852267_wa
+#endif
+
+#if ERRATA_V1_1925756
+ mov x0, x18
+ bl errata_neoverse_v1_1925756_wa
+#endif
+
+#if ERRATA_V1_1940577
+ mov x0, x18
+ bl errata_neoverse_v1_1940577_wa
+#endif
+
+#if ERRATA_V1_1966096
+ mov x0, x18
+ bl errata_neoverse_v1_1966096_wa
+#endif
+
+#if ERRATA_V1_2139242
+ mov x0, x18
+ bl errata_neoverse_v1_2139242_wa
+#endif
+
+#if ERRATA_V1_2108267
+ mov x0, x18
+ bl errata_neoverse_v1_2108267_wa
+#endif
+
+#if ERRATA_V1_2216392
+ mov x0, x18
+ bl errata_neoverse_v1_2216392_wa
+#endif
+
+#if ERRATA_V1_2294912
+ mov x0, x18
+ bl errata_neoverse_v1_2294912_wa
+#endif
+
+#if ERRATA_V1_2372203
+ mov x0, x18
+ bl errata_neoverse_v1_2372203_wa
+#endif
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2022_23960
+ /*
+ * The Neoverse-V1 generic vectors are overridden to apply errata
+ * mitigation on exception entry from lower ELs.
+ */
+ adr x0, wa_cve_vbar_neoverse_v1
+ msr vbar_el3, x0
+#endif /* IMAGE_BL31 && WORKAROUND_CVE_2022_23960 */
+
+ isb
+ ret x19
+endfunc neoverse_v1_reset_func
+
+ /* ---------------------------------------------
+ * This function provides Neoverse-V1 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_v1_regs, "aS"
+neoverse_v1_regs: /* The ascii list of register names to be reported */
+ .asciz "cpuectlr_el1", ""
+
+func neoverse_v1_cpu_reg_dump
+ adr x6, neoverse_v1_regs
+ mrs x8, NEOVERSE_V1_CPUECTLR_EL1
+ ret
+endfunc neoverse_v1_cpu_reg_dump
+
+declare_cpu_ops neoverse_v1, NEOVERSE_V1_MIDR, \
+ neoverse_v1_reset_func, \
+ neoverse_v1_core_pwr_dwn
diff --git a/lib/cpus/aarch64/neoverse_v2.S b/lib/cpus/aarch64/neoverse_v2.S
new file mode 100644
index 0000000..4ea887f
--- /dev/null
+++ b/lib/cpus/aarch64/neoverse_v2.S
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <neoverse_v2.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+#include "wa_cve_2022_23960_bhb_vector.S"
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Neoverse V2 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Neoverse V2 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+#if WORKAROUND_CVE_2022_23960
+ wa_cve_2022_23960_bhb_vector_table NEOVERSE_V2_BHB_LOOP_COUNT, neoverse_v2
+#endif /* WORKAROUND_CVE_2022_23960 */
+
+ /* ----------------------------------------------------
+ * HW will do the cache maintenance while powering down
+ * ----------------------------------------------------
+ */
+func neoverse_v2_core_pwr_dwn
+ /* ---------------------------------------------------
+ * Enable CPU power down bit in power control register
+ * ---------------------------------------------------
+ */
+ mrs x0, NEOVERSE_V2_CPUPWRCTLR_EL1
+ orr x0, x0, #NEOVERSE_V2_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+ msr NEOVERSE_V2_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+endfunc neoverse_v2_core_pwr_dwn
+
+func check_errata_cve_2022_23960
+#if WORKAROUND_CVE_2022_23960
+ mov x0, #ERRATA_APPLIES
+#else
+ mov x0, #ERRATA_MISSING
+#endif
+ ret
+endfunc check_errata_cve_2022_23960
+
+func neoverse_v2_reset_func
+ /* Disable speculative loads */
+ msr SSBS, xzr
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2022_23960
+ /*
+ * The Neoverse V2 vectors are overridden to apply
+ * errata mitigation on exception entry from lower ELs.
+ */
+ adr x0, wa_cve_vbar_neoverse_v2
+ msr vbar_el3, x0
+#endif /* IMAGE_BL31 && WORKAROUND_CVE_2022_23960 */
+ isb
+ ret
+endfunc neoverse_v2_reset_func
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Neoverse V2. Must follow AAPCS.
+ */
+func neoverse_v2_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_2022_23960, neoverse_v2, cve_2022_23960
+
+ ldp x8, x30, [sp], #16
+ ret
+endfunc neoverse_v2_errata_report
+#endif
+
+ /* ---------------------------------------------
+ * This function provides Neoverse V2-
+ * 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_v2_regs, "aS"
+neoverse_v2_regs: /* The ascii list of register names to be reported */
+ .asciz "cpuectlr_el1", ""
+
+func neoverse_v2_cpu_reg_dump
+ adr x6, neoverse_v2_regs
+ mrs x8, NEOVERSE_V2_CPUECTLR_EL1
+ ret
+endfunc neoverse_v2_cpu_reg_dump
+
+declare_cpu_ops neoverse_v2, NEOVERSE_V2_MIDR, \
+ neoverse_v2_reset_func, \
+ neoverse_v2_core_pwr_dwn
diff --git a/lib/cpus/aarch64/qemu_max.S b/lib/cpus/aarch64/qemu_max.S
new file mode 100644
index 0000000..8948fda
--- /dev/null
+++ b/lib/cpus/aarch64/qemu_max.S
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <cpu_macros.S>
+#include <qemu_max.h>
+
+func qemu_max_core_pwr_dwn
+ /* ---------------------------------------------
+ * Disable the Data Cache.
+ * ---------------------------------------------
+ */
+ mrs x1, sctlr_el3
+ bic x1, x1, #SCTLR_C_BIT
+ msr sctlr_el3, x1
+ isb
+
+ /* ---------------------------------------------
+ * Flush L1 cache to L2.
+ * ---------------------------------------------
+ */
+ mov x18, lr
+ mov x0, #DCCISW
+ bl dcsw_op_level1
+ mov lr, x18
+ ret
+endfunc qemu_max_core_pwr_dwn
+
+func qemu_max_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 qemu_max_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for QEMU "max". Must follow AAPCS.
+ */
+func qemu_max_errata_report
+ ret
+endfunc qemu_max_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.qemu_max_regs, "aS"
+qemu_max_regs: /* The ascii list of register names to be reported */
+ .asciz "" /* no registers to report */
+
+func qemu_max_cpu_reg_dump
+ adr x6, qemu_max_regs
+ ret
+endfunc qemu_max_cpu_reg_dump
+
+
+/* cpu_ops for QEMU MAX */
+declare_cpu_ops qemu_max, QEMU_MAX_MIDR, CPU_NO_RESET_FUNC, \
+ qemu_max_core_pwr_dwn, \
+ qemu_max_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/rainier.S b/lib/cpus/aarch64/rainier.S
new file mode 100644
index 0000000..584ab97
--- /dev/null
+++ b/lib/cpus/aarch64/rainier.S
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <context.h>
+#include <cpu_macros.S>
+#include <cpuamu.h>
+#include <rainier.h>
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Rainier CPU must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Rainier CPU supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+/* --------------------------------------------------
+ * Disable speculative loads if Rainier supports
+ * SSBS.
+ *
+ * Shall clobber: x0.
+ * --------------------------------------------------
+ */
+func rainier_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 rainier_disable_speculative_loads
+
+ /* --------------------------------------------------
+ * Errata Workaround for Neoverse N1 Errata #1868343.
+ * This applies to revision <= r4p0 of Neoverse N1.
+ * This workaround is the same as the workaround for
+ * errata 1262606 and 1275112 but applies to a wider
+ * revision range.
+ * Rainier R0P0 is based on Neoverse N1 R4P0 so the
+ * workaround checks for r0p0 version of Rainier CPU.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0, x1 & x17
+ * --------------------------------------------------
+ */
+func errata_n1_1868343_wa
+ /*
+ * Compare x0 against revision r4p0
+ */
+ mov x17, x30
+ bl check_errata_1868343
+ cbz x0, 1f
+ mrs x1, RAINIER_CPUACTLR_EL1
+ orr x1, x1, RAINIER_CPUACTLR_EL1_BIT_13
+ msr RAINIER_CPUACTLR_EL1, x1
+ isb
+1:
+ ret x17
+endfunc errata_n1_1868343_wa
+
+func check_errata_1868343
+ /* Applies to r0p0 of Rainier CPU */
+ mov x1, #0x00
+ b cpu_rev_var_ls
+endfunc check_errata_1868343
+
+func rainier_reset_func
+ mov x19, x30
+
+ bl rainier_disable_speculative_loads
+
+ /* Forces all cacheable atomic instructions to be near */
+ mrs x0, RAINIER_CPUACTLR2_EL1
+ orr x0, x0, #RAINIER_CPUACTLR2_EL1_BIT_2
+ msr RAINIER_CPUACTLR2_EL1, x0
+ isb
+
+ bl cpu_get_rev_var
+ mov x18, x0
+
+#if ERRATA_N1_1868343
+ mov x0, x18
+ bl errata_n1_1868343_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, #RAINIER_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, #RAINIER_ACTLR_AMEN_BIT
+ msr actlr_el2, x0
+
+ /* Enable group0 counters */
+ mov x0, #RAINIER_AMU_GROUP0_MASK
+ msr CPUAMCNTENSET_EL0, x0
+#endif
+
+ isb
+ ret x19
+endfunc rainier_reset_func
+
+ /* ---------------------------------------------
+ * HW will do the cache maintenance while powering down
+ * ---------------------------------------------
+ */
+func rainier_core_pwr_dwn
+ /* ---------------------------------------------
+ * Enable CPU power down bit in power control register
+ * ---------------------------------------------
+ */
+ mrs x0, RAINIER_CPUPWRCTLR_EL1
+ orr x0, x0, #RAINIER_CORE_PWRDN_EN_MASK
+ msr RAINIER_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+endfunc rainier_core_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Rainier. Must follow AAPCS.
+ */
+func rainier_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_1868343, rainier, 1868343
+
+ ldp x8, x30, [sp], #16
+ ret
+endfunc rainier_errata_report
+#endif
+
+ /* ---------------------------------------------
+ * This function provides Rainier 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.rainier_regs, "aS"
+rainier_regs: /* The ascii list of register names to be reported */
+ .asciz "cpuectlr_el1", ""
+
+func rainier_cpu_reg_dump
+ adr x6, rainier_regs
+ mrs x8, RAINIER_CPUECTLR_EL1
+ ret
+endfunc rainier_cpu_reg_dump
+
+declare_cpu_ops rainier, RAINIER_MIDR, \
+ rainier_reset_func, \
+ rainier_core_pwr_dwn
diff --git a/lib/cpus/aarch64/wa_cve_2017_5715_bpiall.S b/lib/cpus/aarch64/wa_cve_2017_5715_bpiall.S
new file mode 100644
index 0000000..0222818
--- /dev/null
+++ b/lib/cpus/aarch64/wa_cve_2017_5715_bpiall.S
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <context.h>
+#include <services/arm_arch_svc.h>
+
+ .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 or W0 = SMCCC_ARCH_WORKAROUND_3
+ *
+ * This sequence evaluates as:
+ * (W0==SMCCC_ARCH_WORKAROUND_1) || (W0==SMCCC_ARCH_WORKAROUND_3) ?
+ * (ESR_EL3==SMC#0) : (NE)
+ * allowing use of a single branch operation
+ */
+ orr w2, wzr, #SMCCC_ARCH_WORKAROUND_1
+ cmp w0, w2
+ orr w2, wzr, #SMCCC_ARCH_WORKAROUND_3
+ ccmp w0, w2, #4, ne
+ mov_imm w2, ESR_EL3_A64_SMC0
+ ccmp w3, w2, #0, eq
+ /* Static predictor will predict a fall through */
+ bne 1f
+ eret
+1:
+ /* restore x2 and x3 and continue sync exception handling */
+ b bpiall_ret_sync_exception_aarch32_tail
+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
+
+ /*
+ * Part of bpiall_ret_sync_exception_aarch32 to save vector space
+ */
+func bpiall_ret_sync_exception_aarch32_tail
+ ldp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
+ b sync_exception_aarch64
+endfunc bpiall_ret_sync_exception_aarch32_tail
diff --git a/lib/cpus/aarch64/wa_cve_2017_5715_mmu.S b/lib/cpus/aarch64/wa_cve_2017_5715_mmu.S
new file mode 100644
index 0000000..ed0a549
--- /dev/null
+++ b/lib/cpus/aarch64/wa_cve_2017_5715_mmu.S
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <context.h>
+#include <services/arm_arch_svc.h>
+
+ .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 or W0 = SMCCC_ARCH_WORKAROUND_3
+ *
+ * This sequence evaluates as:
+ * (W0==SMCCC_ARCH_WORKAROUND_1) || (W0==SMCCC_ARCH_WORKAROUND_3) ?
+ * (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
+ orr w1, wzr, #SMCCC_ARCH_WORKAROUND_3
+ ccmp w0, w1, #4, ne
+ mrs x0, esr_el3
+ mov_imm w1, \_esr_el3_val
+ ccmp w0, w1, #0, eq
+ /* Static predictor will predict a fall through */
+ bne 1f
+ exception_return
+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
diff --git a/lib/cpus/aarch64/wa_cve_2022_23960_bhb.S b/lib/cpus/aarch64/wa_cve_2022_23960_bhb.S
new file mode 100644
index 0000000..ceb93f1
--- /dev/null
+++ b/lib/cpus/aarch64/wa_cve_2022_23960_bhb.S
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <context.h>
+
+#if WORKAROUND_CVE_2022_23960
+ /*
+ * This macro applies the mitigation for CVE-2022-23960.
+ * The macro saves x2 to the CPU context.
+ * SP should point to the CPU context.
+ */
+ .macro apply_cve_2022_23960_bhb_wa _bhb_loop_count
+ str x2, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
+
+ /* CVE-BHB-NUM loop count */
+ mov x2, \_bhb_loop_count
+
+1:
+ /* b pc+4 part of the workaround */
+ b 2f
+2:
+ subs x2, x2, #1
+ bne 1b
+ speculation_barrier
+ ldr x2, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
+ .endm
+#endif /* WORKAROUND_CVE_2022_23960 */
diff --git a/lib/cpus/aarch64/wa_cve_2022_23960_bhb_vector.S b/lib/cpus/aarch64/wa_cve_2022_23960_bhb_vector.S
new file mode 100644
index 0000000..220fa11
--- /dev/null
+++ b/lib/cpus/aarch64/wa_cve_2022_23960_bhb_vector.S
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <services/arm_arch_svc.h>
+#include "wa_cve_2022_23960_bhb.S"
+
+ /*
+ * This macro is used to isolate the vector table for relevant CPUs
+ * used in the mitigation for CVE_2022_23960.
+ */
+ .macro wa_cve_2022_23960_bhb_vector_table _bhb_loop_count, _cpu
+
+ .globl wa_cve_vbar_\_cpu
+
+vector_base wa_cve_vbar_\_cpu
+ /* ---------------------------------------------------------------------
+ * Current EL with SP_EL0 : 0x0 - 0x200
+ * ---------------------------------------------------------------------
+ */
+vector_entry bhb_sync_exception_sp_el0_\_cpu
+ b sync_exception_sp_el0
+end_vector_entry bhb_sync_exception_sp_el0_\_cpu
+
+vector_entry bhb_irq_sp_el0_\_cpu
+ b irq_sp_el0
+end_vector_entry bhb_irq_sp_el0_\_cpu
+
+vector_entry bhb_fiq_sp_el0_\_cpu
+ b fiq_sp_el0
+end_vector_entry bhb_fiq_sp_el0_\_cpu
+
+vector_entry bhb_serror_sp_el0_\_cpu
+ b serror_sp_el0
+end_vector_entry bhb_serror_sp_el0_\_cpu
+
+ /* ---------------------------------------------------------------------
+ * Current EL with SP_ELx: 0x200 - 0x400
+ * ---------------------------------------------------------------------
+ */
+vector_entry bhb_sync_exception_sp_elx_\_cpu
+ b sync_exception_sp_elx
+end_vector_entry bhb_sync_exception_sp_elx_\_cpu
+
+vector_entry bhb_irq_sp_elx_\_cpu
+ b irq_sp_elx
+end_vector_entry bhb_irq_sp_elx_\_cpu
+
+vector_entry bhb_fiq_sp_elx_\_cpu
+ b fiq_sp_elx
+end_vector_entry bhb_fiq_sp_elx_\_cpu
+
+vector_entry bhb_serror_sp_elx_\_cpu
+ b serror_sp_elx
+end_vector_entry bhb_serror_sp_elx_\_cpu
+
+ /* ---------------------------------------------------------------------
+ * Lower EL using AArch64 : 0x400 - 0x600
+ * ---------------------------------------------------------------------
+ */
+vector_entry bhb_sync_exception_aarch64_\_cpu
+ apply_cve_2022_23960_bhb_wa \_bhb_loop_count
+ b sync_exception_aarch64
+end_vector_entry bhb_sync_exception_aarch64_\_cpu
+
+vector_entry bhb_irq_aarch64_\_cpu
+ apply_cve_2022_23960_bhb_wa \_bhb_loop_count
+ b irq_aarch64
+end_vector_entry bhb_irq_aarch64_\_cpu
+
+vector_entry bhb_fiq_aarch64_\_cpu
+ apply_cve_2022_23960_bhb_wa \_bhb_loop_count
+ b fiq_aarch64
+end_vector_entry bhb_fiq_aarch64_\_cpu
+
+vector_entry bhb_serror_aarch64_\_cpu
+ apply_cve_2022_23960_bhb_wa \_bhb_loop_count
+ b serror_aarch64
+end_vector_entry bhb_serror_aarch64_\_cpu
+
+ /* ---------------------------------------------------------------------
+ * Lower EL using AArch32 : 0x600 - 0x800
+ * ---------------------------------------------------------------------
+ */
+vector_entry bhb_sync_exception_aarch32_\_cpu
+ apply_cve_2022_23960_bhb_wa \_bhb_loop_count
+ b sync_exception_aarch32
+end_vector_entry bhb_sync_exception_aarch32_\_cpu
+
+vector_entry bhb_irq_aarch32_\_cpu
+ apply_cve_2022_23960_bhb_wa \_bhb_loop_count
+ b irq_aarch32
+end_vector_entry bhb_irq_aarch32_\_cpu
+
+vector_entry bhb_fiq_aarch32_\_cpu
+ apply_cve_2022_23960_bhb_wa \_bhb_loop_count
+ b fiq_aarch32
+end_vector_entry bhb_fiq_aarch32_\_cpu
+
+vector_entry bhb_serror_aarch32_\_cpu
+ apply_cve_2022_23960_bhb_wa \_bhb_loop_count
+ b serror_aarch32
+end_vector_entry bhb_serror_aarch32_\_cpu
+ .endm
diff --git a/lib/cpus/cpu-ops.mk b/lib/cpus/cpu-ops.mk
new file mode 100644
index 0000000..f19c16e
--- /dev/null
+++ b/lib/cpus/cpu-ops.mk
@@ -0,0 +1,1358 @@
+#
+# Copyright (c) 2014-2022, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, NVIDIA Corporation. 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
+
+# Flag to enable higher performance non-cacheable load forwarding.
+# It is disabled by default.
+A57_ENABLE_NONCACHEABLE_LOAD_FWD ?= 0
+
+WORKAROUND_CVE_2017_5715 ?=1
+WORKAROUND_CVE_2018_3639 ?=1
+DYNAMIC_WORKAROUND_CVE_2018_3639 ?=0
+WORKAROUND_CVE_2022_23960 ?=1
+
+# Flags to indicate internal or external Last level cache
+# By default internal
+NEOVERSE_Nx_EXTERNAL_LLC ?=0
+
+# Process A57_ENABLE_NONCACHEABLE_LOAD_FWD flag
+$(eval $(call assert_boolean,A57_ENABLE_NONCACHEABLE_LOAD_FWD))
+$(eval $(call add_define,A57_ENABLE_NONCACHEABLE_LOAD_FWD))
+
+# 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))
+
+# Process WORKAROUND_CVE_2022_23960 flag
+$(eval $(call assert_boolean,WORKAROUND_CVE_2022_23960))
+$(eval $(call add_define,WORKAROUND_CVE_2022_23960))
+
+$(eval $(call assert_boolean,NEOVERSE_Nx_EXTERNAL_LLC))
+$(eval $(call add_define,NEOVERSE_Nx_EXTERNAL_LLC))
+
+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 1530924 workaround during reset. This erratum applies
+# to all revisions of Cortex A53 cpu.
+ERRATA_A53_1530924 ?=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 1530923 workaround during reset. This erratum applies
+# to all revisions of Cortex A55 cpu.
+ERRATA_A55_1530923 ?=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 1319537 workaround during reset. This erratum applies
+# to all revisions of Cortex A57 cpu.
+ERRATA_A57_1319537 ?=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 1319367 workaround during reset. This erratum applies
+# to all revisions of Cortex A72 cpu.
+ERRATA_A72_1319367 ?=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 erratum 1791580 workaround during reset. This erratum applies
+# only to revision <= r4p0 of the Cortex A76 cpu.
+ERRATA_A76_1791580 ?=0
+
+# Flag to apply erratum 1165522 workaround during reset. This erratum applies
+# to all revisions of Cortex A76 cpu.
+ERRATA_A76_1165522 ?=0
+
+# Flag to apply erratum 1868343 workaround during reset. This erratum applies
+# only to revision <= r4p0 of the Cortex A76 cpu.
+ERRATA_A76_1868343 ?=0
+
+# Flag to apply erratum 1946160 workaround during reset. This erratum applies
+# only to revisions r3p0 - r4p1 of the Cortex A76 cpu.
+ERRATA_A76_1946160 ?=0
+
+# Flag to apply erratum 2743102 workaround during powerdown. This erratum
+# applies to all revisions <= r4p1 of the Cortex A76 cpu and is still open.
+ERRATA_A76_2743102 ?=0
+
+# Flag to apply erratum 1508412 workaround during reset. This erratum applies
+# only to revision <= r1p0 of the Cortex A77 cpu.
+ERRATA_A77_1508412 ?=0
+
+# Flag to apply erratum 1925769 workaround during reset. This erratum applies
+# only to revision <= r1p1 of the Cortex A77 cpu.
+ERRATA_A77_1925769 ?=0
+
+# Flag to apply erratum 1946167 workaround during reset. This erratum applies
+# only to revision <= r1p1 of the Cortex A77 cpu.
+ERRATA_A77_1946167 ?=0
+
+# Flag to apply erratum 1791578 workaround during reset. This erratum applies
+# to revisions r0p0, r1p0, and r1p1, it is still open.
+ERRATA_A77_1791578 ?=0
+
+# Flag to apply erratum 2356587 workaround during reset. This erratum applies
+# to revisions r0p0, r1p0, and r1p1, it is still open.
+ERRATA_A77_2356587 ?=0
+
+# Flag to apply erratum 1800714 workaround during reset. This erratum applies
+# to revisions <= r1p1 of the Cortex A77 cpu.
+ERRATA_A77_1800714 ?=0
+
+# Flag to apply erratum 2743100 workaround during power down. This erratum
+# applies to revisions r0p0, r1p0, and r1p1, it is still open.
+ERRATA_A77_2743100 ?=0
+
+# Flag to apply erratum 1688305 workaround during reset. This erratum applies
+# to revisions r0p0 - r1p0 of the A78 cpu.
+ERRATA_A78_1688305 ?=0
+
+# Flag to apply erratum 1941498 workaround during reset. This erratum applies
+# to revisions r0p0, r1p0, and r1p1 of the A78 cpu.
+ERRATA_A78_1941498 ?=0
+
+# Flag to apply erratum 1951500 workaround during reset. This erratum applies
+# to revisions r1p0 and r1p1 of the A78 cpu. The issue is present in r0p0 as
+# well but there is no workaround for that revision.
+ERRATA_A78_1951500 ?=0
+
+# Flag to apply erratum 1821534 workaround during reset. This erratum applies
+# to revisions r0p0 and r1p0 of the A78 cpu.
+ERRATA_A78_1821534 ?=0
+
+# Flag to apply erratum 1952683 workaround during reset. This erratum applies
+# to revision r0p0 of the A78 cpu and was fixed in the revision r1p0.
+ERRATA_A78_1952683 ?=0
+
+# Flag to apply erratum 2132060 workaround during reset. This erratum applies
+# to revisions r0p0, r1p0, r1p1, and r1p2 of the A78 cpu. It is still open.
+ERRATA_A78_2132060 ?=0
+
+# Flag to apply erratum 2242635 workaround during reset. This erratum applies
+# to revisions r1p0, r1p1, and r1p2 of the A78 cpu and is open. The issue is
+# present in r0p0 as well but there is no workaround for that revision.
+ERRATA_A78_2242635 ?=0
+
+# Flag to apply erratum 2376745 workaround during reset. This erratum applies
+# to revisions r0p0, r1p0, r1p1, and r1p2 of the A78 cpu. It is still open.
+ERRATA_A78_2376745 ?=0
+
+# Flag to apply erratum 2395406 workaround during reset. This erratum applies
+# to revisions r0p0, r1p0, r1p1, and r1p2 of the A78 cpu. It is still open.
+ERRATA_A78_2395406 ?=0
+
+# Flag to apply erratum 1941500 workaround during reset. This erratum applies
+# to revisions r0p0 and r0p1 of the A78 AE cpu. It is still open.
+ERRATA_A78_AE_1941500 ?=0
+
+# Flag to apply erratum 1951502 workaround during reset. This erratum applies
+# to revisions r0p0 and r0p1 of the A78 AE cpu. It is still open.
+ERRATA_A78_AE_1951502 ?=0
+
+# Flag to apply erratum 2376748 workaround during reset. This erratum applies
+# to revisions r0p0 and r0p1 of the A78 AE cpu. It is still open.
+ERRATA_A78_AE_2376748 ?=0
+
+# Flag to apply erratum 2395408 workaround during reset. This erratum applies
+# to revisions r0p0 and r0p1 of the A78 AE cpu. It is still open.
+ERRATA_A78_AE_2395408 ?=0
+
+# Flag to apply erratum 2132064 workaround during reset. This erratum applies
+# to revisions r0p1 and r0p2 of the A78C cpu. It is still open.
+ERRATA_A78C_2132064 ?=0
+
+# Flag to apply erratum 2242638 workaround during reset. This erratum applies
+# to revisions r0p1 and r0p2 of the A78C cpu. It is still open.
+ERRATA_A78C_2242638 ?=0
+
+# Flag to apply erratum 2376749 workaround during reset. This erratum applies
+# to revisions r0p1 and r0p2 of the A78C cpu. It is still open.
+ERRATA_A78C_2376749 ?=0
+
+# Flag to apply erratum 2395411 workaround during reset. This erratum applies
+# to revisions r0p1 and r0p2 of the A78C cpu. It is still open.
+ERRATA_A78C_2395411 ?=0
+
+# Flag to apply erratum 1821534 workaround during reset. This erratum applies
+# to revisions r0p0 - r1p0 of the X1 cpu and fixed in r1p1.
+ERRATA_X1_1821534 ?=0
+
+# Flag to apply erratum 1688305 workaround during reset. This erratum applies
+# to revisions r0p0 - r1p0 of the X1 cpu and fixed in r1p1.
+ERRATA_X1_1688305 ?=0
+
+# Flag to apply erratum 1827429 workaround during reset. This erratum applies
+# to revisions r0p0 - r1p0 of the X1 cpu and fixed in r1p1.
+ERRATA_X1_1827429 ?=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 ?=0
+
+# 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 ?=0
+
+# 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 erratum 1868343 workaround during reset. This erratum applies
+# to revision <= r4p0 of the Neoverse N1 cpu.
+ERRATA_N1_1868343 ?=0
+
+# Flag to apply erratum 1946160 workaround during reset. This erratum applies
+# to revisions r3p0, r3p1, r4p0, and r4p1 of the Neoverse N1 cpu. The issue
+# exists in revisions r0p0, r1p0, and r2p0 as well but there is no workaround.
+ERRATA_N1_1946160 ?=0
+
+# Flag to apply erratum 2743102 workaround during powerdown. This erratum
+# applies to all revisions <= r4p1 of the Neoverse N1 cpu and is still open.
+ERRATA_N1_2743102 ?=0
+
+# Flag to apply erratum 2002655 workaround during reset. This erratum applies
+# to revisions r0p0 of the Neoverse-N2 cpu, it is still open.
+ERRATA_N2_2002655 ?=0
+
+# Flag to apply erratum 1618635 workaround during reset. This erratum applies
+# to revision r0p0 of the Neoverse V1 cpu and was fixed in the revision r1p0.
+ERRATA_V1_1618635 ?=0
+
+# Flag to apply erratum 1774420 workaround during reset. This erratum applies
+# to revisions r0p0 and r1p0 of the Neoverse V1 core, and was fixed in r1p1.
+ERRATA_V1_1774420 ?=0
+
+# Flag to apply erratum 1791573 workaround during reset. This erratum applies
+# to revisions r0p0 and r1p0 of the Neoverse V1 core, and was fixed in r1p1.
+ERRATA_V1_1791573 ?=0
+
+# Flag to apply erratum 1852267 workaround during reset. This erratum applies
+# to revisions r0p0 and r1p0 of the Neoverse V1 core, and was fixed in r1p1.
+ERRATA_V1_1852267 ?=0
+
+# Flag to apply erratum 1925756 workaround during reset. This needs to be
+# enabled for r0p0, r1p0, and r1p1 of the Neoverse V1 core, it is still open.
+ERRATA_V1_1925756 ?=0
+
+# Flag to apply erratum 1940577 workaround during reset. This erratum applies
+# to revisions r1p0 and r1p1 of the Neoverse V1 cpu.
+ERRATA_V1_1940577 ?=0
+
+# Flag to apply erratum 1966096 workaround during reset. This erratum applies
+# to revisions r1p0 and r1p1 of the Neoverse V1 CPU and is open. This issue
+# exists in r0p0 as well but there is no workaround for that revision.
+ERRATA_V1_1966096 ?=0
+
+# Flag to apply erratum 2139242 workaround during reset. This erratum applies
+# to revisions r0p0, r1p0, and r1p1 of the Neoverse V1 cpu and is still open.
+ERRATA_V1_2139242 ?=0
+
+# Flag to apply erratum 2108267 workaround during reset. This erratum applies
+# to revisions r0p0, r1p0, and r1p1 of the Neoverse V1 cpu and is still open.
+ERRATA_V1_2108267 ?=0
+
+# Flag to apply erratum 2216392 workaround during reset. This erratum applies
+# to revisions r1p0 and r1p1 of the Neoverse V1 cpu and is still open. This
+# issue exists in r0p0 as well but there is no workaround for that revision.
+ERRATA_V1_2216392 ?=0
+
+# Flag to apply erratum 2294912 workaround during reset. This erratum applies
+# to revisions r0p0, r1p0, and r1p1 of the Neoverse V1 cpu and is still open.
+ERRATA_V1_2294912 ?=0
+
+# Flag to apply erratum 2372203 workaround during reset. This erratum applies
+# to revisions r0p0, r1p0 and r1p1 of the Neoverse V1 cpu and is still open.
+ERRATA_V1_2372203 ?=0
+
+# Flag to apply erratum 1987031 workaround during reset. This erratum applies
+# to revisions r0p0, r1p0 and r2p0 of the Cortex-A710 cpu and is still open.
+ERRATA_A710_1987031 ?=0
+
+# Flag to apply erratum 2081180 workaround during reset. This erratum applies
+# to revisions r0p0, r1p0 and r2p0 of the Cortex-A710 cpu and is still open.
+ERRATA_A710_2081180 ?=0
+
+# Flag to apply erratum 2083908 workaround during reset. This erratum applies
+# to revision r2p0 of the Cortex-A710 cpu and is still open.
+ERRATA_A710_2083908 ?=0
+
+# Flag to apply erratum 2058056 workaround during reset. This erratum applies
+# to revisions r0p0, r1p0 and r2p0 of the Cortex-A710 cpu and is still open.
+ERRATA_A710_2058056 ?=0
+
+# Flag to apply erratum 2055002 workaround during reset. This erratum applies
+# to revision r1p0, r2p0 of the Cortex-A710 cpu and is still open.
+ERRATA_A710_2055002 ?=0
+
+# Flag to apply erratum 2017096 workaround during reset. This erratum applies
+# to revision r0p0, r1p0 and r2p0 of the Cortex-A710 cpu and is still open.
+ERRATA_A710_2017096 ?=0
+
+# Flag to apply erratum 2267065 workaround during reset. This erratum applies
+# to revision r0p0, r1p0 and r2p0 of the Cortex-A710 cpu and is fixed in r2p1.
+ERRATA_A710_2267065 ?=0
+
+# Flag to apply erratum 2136059 workaround during reset. This erratum applies
+# to revision r0p0, r1p0 and r2p0 of the Cortex-A710 cpu and is fixed in r2p1.
+ERRATA_A710_2136059 ?=0
+
+# Flag to apply erratum 2147715 workaround during reset. This erratum applies
+# to revision r2p0 of the Cortex-A710 CPU and is fixed in revision r2p1.
+ERRATA_A710_2147715 ?=0
+
+# Flag to apply erratum 2216384 workaround during reset. This erratum applies
+# to revision r0p0, r1p0 and r2p0 of the Cortex-A710 cpu and is fixed in r2p1.
+ERRATA_A710_2216384 ?=0
+
+# Flag to apply erratum 2282622 workaround during reset. This erratum applies
+# to revision r0p0, r1p0 and r2p0 of the Cortex-A710 cpu and is fixed in r2p1.
+ERRATA_A710_2282622 ?=0
+
+# Flag to apply erratum 2291219 workaround during reset. This erratum applies
+# to revision r0p0, r1p0 and r2p0 of the Cortex-A710 cpu and is fixed in r2p1.
+ERRATA_A710_2291219 ?=0
+
+# Flag to apply erratum 2008768 workaround during reset. This erratum applies
+# to revision r0p0, r1p0 and r2p0 of the Cortex-A710 cpu and is fixed in r2p1.
+ERRATA_A710_2008768 ?=0
+
+# Flag to apply erratum 2371105 workaround during reset. This erratum applies
+# to revision r0p0, r1p0 and r2p0 of the Cortex-A710 cpu and is fixed in r2p1.
+ERRATA_A710_2371105 ?=0
+
+# Flag to apply erratum 2067956 workaround during reset. This erratum applies
+# to revision r0p0 of the Neoverse N2 cpu and is still open.
+ERRATA_N2_2067956 ?=0
+
+# Flag to apply erratum 2025414 workaround during reset. This erratum applies
+# to revision r0p0 of the Neoverse N2 cpu and is still open.
+ERRATA_N2_2025414 ?=0
+
+# Flag to apply erratum 2189731 workaround during reset. This erratum applies
+# to revision r0p0 of the Neoverse N2 cpu and is still open.
+ERRATA_N2_2189731 ?=0
+
+# Flag to apply erratum 2138956 workaround during reset. This erratum applies
+# to revision r0p0 of the Neoverse N2 cpu and is still open.
+ERRATA_N2_2138956 ?=0
+
+# Flag to apply erratum 2138953 workaround during reset. This erratum applies
+# to revision r0p0 of the Neoverse N2 cpu and is still open.
+ERRATA_N2_2138953 ?=0
+
+# Flag to apply erratum 2242415 workaround during reset. This erratum applies
+# to revision r0p0 of the Neoverse N2 cpu and is still open.
+ERRATA_N2_2242415 ?=0
+
+# Flag to apply erratum 2138958 workaround during reset. This erratum applies
+# to revision r0p0 of the Neoverse N2 cpu and is still open.
+ERRATA_N2_2138958 ?=0
+
+# Flag to apply erratum 2242400 workaround during reset. This erratum applies
+# to revision r0p0 of the Neoverse N2 cpu and is still open.
+ERRATA_N2_2242400 ?=0
+
+# Flag to apply erratum 2280757 workaround during reset. This erratum applies
+# to revision r0p0 of the Neoverse N2 cpu and is still open.
+ERRATA_N2_2280757 ?=0
+
+# Flag to apply erraturm 2326639 workaroud during powerdown. This erratum
+# applies to revision r0p0 of the Neoverse N2 cpu and is fixed in r0p1.
+ERRATA_N2_2326639 ?=0
+
+# Flag to apply erratum 2376738 workaround during reset. This erratum applies
+# to revision r0p0 of the Neoverse N2 cpu, it is fixed in r0p1.
+ERRATA_N2_2376738 ?=0
+
+# Flag to apply erratum 2388450 workaround during reset. This erratum applies
+# to revision r0p0 of the Neoverse N2 cpu, it is fixed in r0p1.
+ERRATA_N2_2388450 ?=0
+
+# Flag to apply erratum 2002765 workaround during reset. This erratum applies
+# to revisions r0p0, r1p0, and r2p0 of the Cortex-X2 cpu and is still open.
+ERRATA_X2_2002765 ?=0
+
+# Flag to apply erratum 2058056 workaround during reset. This erratum applies
+# to revisions r0p0, r1p0, and r2p0 of the Cortex-X2 cpu and is still open.
+ERRATA_X2_2058056 ?=0
+
+# Flag to apply erratum 2083908 workaround during reset. This erratum applies
+# to revision r2p0 of the Cortex-X2 cpu and is still open.
+ERRATA_X2_2083908 ?=0
+
+# Flag to apply erratum 2017096 workaround during reset. This erratum applies
+# only to revisions r0p0, r1p0 and r2p0 of the Cortex-X2 cpu, it is fixed in
+# r2p1.
+ERRATA_X2_2017096 ?=0
+
+# Flag to apply erratum 2081180 workaround during reset. This erratum applies
+# only to revisions r0p0, r1p0 and r2p0 of the Cortex-X2 cpu, it is fixed in
+# r2p1.
+ERRATA_X2_2081180 ?=0
+
+# Flag to apply erratum 2216384 workaround during reset. This erratum applies
+# only to revisions r0p0, r1p0 and r2p0 of the Cortex-X2 cpu, it is fixed in
+# r2p1.
+ERRATA_X2_2216384 ?=0
+
+# Flag to apply erratum 2147715 workaround during reset. This erratum applies
+# only to revision r2p0 of the Cortex-X2 cpu, it is fixed in r2p1.
+ERRATA_X2_2147715 ?=0
+
+# Flag to apply erratum 2371105 workaround during reset. This erratum applies
+# to revision r0p0, r1p0 and r2p0 of the Cortex-X2 cpu and is fixed in r2p1.
+ERRATA_X2_2371105 ?=0
+
+# Flag to apply erratum 2313909 workaround on powerdown. This erratum applies
+# to revisions r0p0 and r1p0 of the Cortex-X3 cpu, it is fixed in r1p1.
+ERRATA_X3_2313909 ?=0
+
+# Flag to apply erratum 1922240 workaround during reset. This erratum applies
+# to revision r0p0 of the Cortex-A510 cpu and is fixed in r0p1.
+ERRATA_A510_1922240 ?=0
+
+# Flag to apply erratum 2288014 workaround during reset. This erratum applies
+# to revisions r0p0, r0p1, r0p2, r0p3 and r1p0 of the Cortex-A510 cpu and is
+# fixed in r1p1.
+ERRATA_A510_2288014 ?=0
+
+# Flag to apply erratum 2042739 workaround during reset. This erratum applies
+# to revisions r0p0, r0p1 and r0p2 of the Cortex-A510 cpu and is fixed in r0p3.
+ERRATA_A510_2042739 ?=0
+
+# Flag to apply erratum 2041909 workaround during reset. This erratum applies
+# to revision r0p2 of the Cortex-A510 cpu and is fixed in r0p3. The issue is
+# present in r0p0 and r0p1 but there is no workaround for those revisions.
+ERRATA_A510_2041909 ?=0
+
+# Flag to apply erratum 2250311 workaround during reset. This erratum applies
+# to revisions r0p0, r0p1, r0p2, r0p3 and r1p0, and is fixed in r1p1.
+ERRATA_A510_2250311 ?=0
+
+# Flag to apply erratum 2218950 workaround during reset. This erratum applies
+# to revisions r0p0, r0p1, r0p2, r0p3 and r1p0, and is fixed in r1p1.
+ERRATA_A510_2218950 ?=0
+
+# Flag to apply erratum 2172148 workaround during reset. This erratum applies
+# to revisions r0p0, r0p1, r0p2, r0p3 and r1p0, and is fixed in r1p1.
+ERRATA_A510_2172148 ?=0
+
+# Flag to apply erratum 2347730 workaround during reset. This erratum applies
+# to revisions r0p0, r0p1, r0p2, r0p3, r1p0 and r1p1 of the Cortex-A510 CPU,
+# and is fixed in r1p2.
+ERRATA_A510_2347730 ?=0
+
+# Flag to apply erratum 2371937 workaround during reset. This erratum applies
+# to revisions r0p0, r0p1, r0p2, r0p3, r1p0, and r1p1. It is fixed in r1p2.
+ERRATA_A510_2371937 ?=0
+
+# Flag to apply erratum 2666669 workaround during reset. This erratum applies
+# to revisions r0p0, r0p1, r0p2, r0p3, r1p0, and r1p1. It is fixed in r1p2.
+ERRATA_A510_2666669 ?=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
+
+# Flag to apply DSU erratum 2313941. This erratum applies to DSUs revisions
+# r0p0, r1p0, r2p0, r2p1, r3p0, r3p1 and is still open. Applying the workaround
+# results in higher DSU power consumption on idle.
+ERRATA_DSU_2313941 ?=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_A53_1530924 flag
+$(eval $(call assert_boolean,ERRATA_A53_1530924))
+$(eval $(call add_define,ERRATA_A53_1530924))
+
+# 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_A55_1530923 flag
+$(eval $(call assert_boolean,ERRATA_A55_1530923))
+$(eval $(call add_define,ERRATA_A55_1530923))
+
+# 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_A57_1319537 flag
+$(eval $(call assert_boolean,ERRATA_A57_1319537))
+$(eval $(call add_define,ERRATA_A57_1319537))
+
+# Process ERRATA_A72_859971 flag
+$(eval $(call assert_boolean,ERRATA_A72_859971))
+$(eval $(call add_define,ERRATA_A72_859971))
+
+# Process ERRATA_A72_1319367 flag
+$(eval $(call assert_boolean,ERRATA_A72_1319367))
+$(eval $(call add_define,ERRATA_A72_1319367))
+
+# 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_A76_1791580 flag
+$(eval $(call assert_boolean,ERRATA_A76_1791580))
+$(eval $(call add_define,ERRATA_A76_1791580))
+
+# Process ERRATA_A76_1165522 flag
+$(eval $(call assert_boolean,ERRATA_A76_1165522))
+$(eval $(call add_define,ERRATA_A76_1165522))
+
+# Process ERRATA_A76_1868343 flag
+$(eval $(call assert_boolean,ERRATA_A76_1868343))
+$(eval $(call add_define,ERRATA_A76_1868343))
+
+# Process ERRATA_A76_1946160 flag
+$(eval $(call assert_boolean,ERRATA_A76_1946160))
+$(eval $(call add_define,ERRATA_A76_1946160))
+
+# Process ERRATA_A76_2743102 flag
+$(eval $(call assert_boolean,ERRATA_A76_2743102))
+$(eval $(call add_define,ERRATA_A76_2743102))
+
+# Process ERRATA_A77_1508412 flag
+$(eval $(call assert_boolean,ERRATA_A77_1508412))
+$(eval $(call add_define,ERRATA_A77_1508412))
+
+# Process ERRATA_A77_1925769 flag
+$(eval $(call assert_boolean,ERRATA_A77_1925769))
+$(eval $(call add_define,ERRATA_A77_1925769))
+
+# Process ERRATA_A77_1946167 flag
+$(eval $(call assert_boolean,ERRATA_A77_1946167))
+$(eval $(call add_define,ERRATA_A77_1946167))
+
+# Process ERRATA_A77_1791578 flag
+$(eval $(call assert_boolean,ERRATA_A77_1791578))
+$(eval $(call add_define,ERRATA_A77_1791578))
+
+# Process ERRATA_A77_2356587 flag
+$(eval $(call assert_boolean,ERRATA_A77_2356587))
+$(eval $(call add_define,ERRATA_A77_2356587))
+
+# Process ERRATA_A77_1800714 flag
+$(eval $(call assert_boolean,ERRATA_A77_1800714))
+$(eval $(call add_define,ERRATA_A77_1800714))
+
+# Process ERRATA_A77_2743100 flag
+$(eval $(call assert_boolean,ERRATA_A77_2743100))
+$(eval $(call add_define,ERRATA_A77_2743100))
+
+# Process ERRATA_A78_1688305 flag
+$(eval $(call assert_boolean,ERRATA_A78_1688305))
+$(eval $(call add_define,ERRATA_A78_1688305))
+
+# Process ERRATA_A78_1941498 flag
+$(eval $(call assert_boolean,ERRATA_A78_1941498))
+$(eval $(call add_define,ERRATA_A78_1941498))
+
+# Process ERRATA_A78_1951500 flag
+$(eval $(call assert_boolean,ERRATA_A78_1951500))
+$(eval $(call add_define,ERRATA_A78_1951500))
+
+# Process ERRATA_A78_1821534 flag
+$(eval $(call assert_boolean,ERRATA_A78_1821534))
+$(eval $(call add_define,ERRATA_A78_1821534))
+
+# Process ERRATA_A78_1952683 flag
+$(eval $(call assert_boolean,ERRATA_A78_1952683))
+$(eval $(call add_define,ERRATA_A78_1952683))
+
+# Process ERRATA_A78_2132060 flag
+$(eval $(call assert_boolean,ERRATA_A78_2132060))
+$(eval $(call add_define,ERRATA_A78_2132060))
+
+# Process ERRATA_A78_2242635 flag
+$(eval $(call assert_boolean,ERRATA_A78_2242635))
+$(eval $(call add_define,ERRATA_A78_2242635))
+
+# Process ERRATA_A78_2376745 flag
+$(eval $(call assert_boolean,ERRATA_A78_2376745))
+$(eval $(call add_define,ERRATA_A78_2376745))
+
+# Process ERRATA_A78_2395406 flag
+$(eval $(call assert_boolean,ERRATA_A78_2395406))
+$(eval $(call add_define,ERRATA_A78_2395406))
+
+# Process ERRATA_A78_AE_1941500 flag
+$(eval $(call assert_boolean,ERRATA_A78_AE_1941500))
+$(eval $(call add_define,ERRATA_A78_AE_1941500))
+
+# Process ERRATA_A78_AE_1951502 flag
+$(eval $(call assert_boolean,ERRATA_A78_AE_1951502))
+$(eval $(call add_define,ERRATA_A78_AE_1951502))
+
+# Process ERRATA_A78_AE_2376748 flag
+$(eval $(call assert_boolean,ERRATA_A78_AE_2376748))
+$(eval $(call add_define,ERRATA_A78_AE_2376748))
+
+# Process ERRATA_A78_AE_2395408 flag
+$(eval $(call assert_boolean,ERRATA_A78_AE_2395408))
+$(eval $(call add_define,ERRATA_A78_AE_2395408))
+
+# Process ERRATA_A78C_2132064 flag
+$(eval $(call assert_boolean,ERRATA_A78C_2132064))
+$(eval $(call add_define,ERRATA_A78C_2132064))
+
+# Process ERRATA_A78C_2242638 flag
+$(eval $(call assert_boolean,ERRATA_A78C_2242638))
+$(eval $(call add_define,ERRATA_A78C_2242638))
+
+# Process ERRATA_A78C_2376749 flag
+$(eval $(call assert_boolean,ERRATA_A78C_2376749))
+$(eval $(call add_define,ERRATA_A78C_2376749))
+
+# Process ERRATA_A78C_2395411 flag
+$(eval $(call assert_boolean,ERRATA_A78C_2395411))
+$(eval $(call add_define,ERRATA_A78C_2395411))
+
+# Process ERRATA_X1_1821534 flag
+$(eval $(call assert_boolean,ERRATA_X1_1821534))
+$(eval $(call add_define,ERRATA_X1_1821534))
+
+# Process ERRATA_X1_1688305 flag
+$(eval $(call assert_boolean,ERRATA_X1_1688305))
+$(eval $(call add_define,ERRATA_X1_1688305))
+
+# Process ERRATA_X1_1827429 flag
+$(eval $(call assert_boolean,ERRATA_X1_1827429))
+$(eval $(call add_define,ERRATA_X1_1827429))
+
+# 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_N1_1868343 flag
+$(eval $(call assert_boolean,ERRATA_N1_1868343))
+$(eval $(call add_define,ERRATA_N1_1868343))
+
+# Process ERRATA_N1_1946160 flag
+$(eval $(call assert_boolean,ERRATA_N1_1946160))
+$(eval $(call add_define,ERRATA_N1_1946160))
+
+# Process ERRATA_N1_2743102 flag
+$(eval $(call assert_boolean,ERRATA_N1_2743102))
+$(eval $(call add_define,ERRATA_N1_2743102))
+#
+# Process ERRATA_N2_2002655 flag
+$(eval $(call assert_boolean,ERRATA_N2_2002655))
+$(eval $(call add_define,ERRATA_N2_2002655))
+
+# Process ERRATA_V1_1618635 flag
+$(eval $(call assert_boolean,ERRATA_V1_1618635))
+$(eval $(call add_define,ERRATA_V1_1618635))
+
+# Process ERRATA_V1_1774420 flag
+$(eval $(call assert_boolean,ERRATA_V1_1774420))
+$(eval $(call add_define,ERRATA_V1_1774420))
+
+# Process ERRATA_V1_1791573 flag
+$(eval $(call assert_boolean,ERRATA_V1_1791573))
+$(eval $(call add_define,ERRATA_V1_1791573))
+
+# Process ERRATA_V1_1852267 flag
+$(eval $(call assert_boolean,ERRATA_V1_1852267))
+$(eval $(call add_define,ERRATA_V1_1852267))
+
+# Process ERRATA_V1_1925756 flag
+$(eval $(call assert_boolean,ERRATA_V1_1925756))
+$(eval $(call add_define,ERRATA_V1_1925756))
+
+# Process ERRATA_V1_1940577 flag
+$(eval $(call assert_boolean,ERRATA_V1_1940577))
+$(eval $(call add_define,ERRATA_V1_1940577))
+
+# Process ERRATA_V1_1966096 flag
+$(eval $(call assert_boolean,ERRATA_V1_1966096))
+$(eval $(call add_define,ERRATA_V1_1966096))
+
+# Process ERRATA_V1_2139242 flag
+$(eval $(call assert_boolean,ERRATA_V1_2139242))
+$(eval $(call add_define,ERRATA_V1_2139242))
+
+# Process ERRATA_V1_2108267 flag
+$(eval $(call assert_boolean,ERRATA_V1_2108267))
+$(eval $(call add_define,ERRATA_V1_2108267))
+
+# Process ERRATA_V1_2216392 flag
+$(eval $(call assert_boolean,ERRATA_V1_2216392))
+$(eval $(call add_define,ERRATA_V1_2216392))
+
+# Process ERRATA_V1_2294912 flag
+$(eval $(call assert_boolean,ERRATA_V1_2294912))
+$(eval $(call add_define,ERRATA_V1_2294912))
+
+# Process ERRATA_V1_2372203 flag
+$(eval $(call assert_boolean,ERRATA_V1_2372203))
+$(eval $(call add_define,ERRATA_V1_2372203))
+
+# Process ERRATA_A710_1987031 flag
+$(eval $(call assert_boolean,ERRATA_A710_1987031))
+$(eval $(call add_define,ERRATA_A710_1987031))
+
+# Process ERRATA_A710_2081180 flag
+$(eval $(call assert_boolean,ERRATA_A710_2081180))
+$(eval $(call add_define,ERRATA_A710_2081180))
+
+# Process ERRATA_A710_2083908 flag
+$(eval $(call assert_boolean,ERRATA_A710_2083908))
+$(eval $(call add_define,ERRATA_A710_2083908))
+
+# Process ERRATA_A710_2058056 flag
+$(eval $(call assert_boolean,ERRATA_A710_2058056))
+$(eval $(call add_define,ERRATA_A710_2058056))
+
+# Process ERRATA_A710_2055002 flag
+$(eval $(call assert_boolean,ERRATA_A710_2055002))
+$(eval $(call add_define,ERRATA_A710_2055002))
+
+# Process ERRATA_A710_2017096 flag
+$(eval $(call assert_boolean,ERRATA_A710_2017096))
+$(eval $(call add_define,ERRATA_A710_2017096))
+
+# Process ERRATA_A710_2267065 flag
+$(eval $(call assert_boolean,ERRATA_A710_2267065))
+$(eval $(call add_define,ERRATA_A710_2267065))
+
+# Process ERRATA_A710_2136059 flag
+$(eval $(call assert_boolean,ERRATA_A710_2136059))
+$(eval $(call add_define,ERRATA_A710_2136059))
+
+# Process ERRATA_A710_2147715 flag
+$(eval $(call assert_boolean,ERRATA_A710_2147715))
+$(eval $(call add_define,ERRATA_A710_2147715))
+
+# Process ERRATA_A710_2216384 flag
+$(eval $(call assert_boolean,ERRATA_A710_2216384))
+$(eval $(call add_define,ERRATA_A710_2216384))
+
+# Process ERRATA_A710_2282622 flag
+$(eval $(call assert_boolean,ERRATA_A710_2282622))
+$(eval $(call add_define,ERRATA_A710_2282622))
+
+# Process ERRATA_A710_2291219 flag
+$(eval $(call assert_boolean,ERRATA_A710_2291219))
+$(eval $(call add_define,ERRATA_A710_2291219))
+
+# Process ERRATA_A710_2008768 flag
+$(eval $(call assert_boolean,ERRATA_A710_2008768))
+$(eval $(call add_define,ERRATA_A710_2008768))
+
+# Process ERRATA_A710_2371105 flag
+$(eval $(call assert_boolean,ERRATA_A710_2371105))
+$(eval $(call add_define,ERRATA_A710_2371105))
+
+# Process ERRATA_N2_2067956 flag
+$(eval $(call assert_boolean,ERRATA_N2_2067956))
+$(eval $(call add_define,ERRATA_N2_2067956))
+
+# Process ERRATA_N2_2025414 flag
+$(eval $(call assert_boolean,ERRATA_N2_2025414))
+$(eval $(call add_define,ERRATA_N2_2025414))
+
+# Process ERRATA_N2_2189731 flag
+$(eval $(call assert_boolean,ERRATA_N2_2189731))
+$(eval $(call add_define,ERRATA_N2_2189731))
+
+# Process ERRATA_N2_2138956 flag
+$(eval $(call assert_boolean,ERRATA_N2_2138956))
+$(eval $(call add_define,ERRATA_N2_2138956))
+
+# Process ERRATA_N2_2138953 flag
+$(eval $(call assert_boolean,ERRATA_N2_2138953))
+$(eval $(call add_define,ERRATA_N2_2138953))
+
+# Process ERRATA_N2_2242415 flag
+$(eval $(call assert_boolean,ERRATA_N2_2242415))
+$(eval $(call add_define,ERRATA_N2_2242415))
+
+# Process ERRATA_N2_2138958 flag
+$(eval $(call assert_boolean,ERRATA_N2_2138958))
+$(eval $(call add_define,ERRATA_N2_2138958))
+
+# Process ERRATA_N2_2242400 flag
+$(eval $(call assert_boolean,ERRATA_N2_2242400))
+$(eval $(call add_define,ERRATA_N2_2242400))
+
+# Process ERRATA_N2_2280757 flag
+$(eval $(call assert_boolean,ERRATA_N2_2280757))
+$(eval $(call add_define,ERRATA_N2_2280757))
+
+# Process ERRATA_N2_2326639 flag
+$(eval $(call assert_boolean,ERRATA_N2_2326639))
+$(eval $(call add_define,ERRATA_N2_2326639))
+
+# Process ERRATA_N2_2376738 flag
+$(eval $(call assert_boolean,ERRATA_N2_2376738))
+$(eval $(call add_define,ERRATA_N2_2376738))
+
+# Process ERRATA_N2_2388450 flag
+$(eval $(call assert_boolean,ERRATA_N2_2388450))
+$(eval $(call add_define,ERRATA_N2_2388450))
+
+# Process ERRATA_X2_2002765 flag
+$(eval $(call assert_boolean,ERRATA_X2_2002765))
+$(eval $(call add_define,ERRATA_X2_2002765))
+
+# Process ERRATA_X2_2058056 flag
+$(eval $(call assert_boolean,ERRATA_X2_2058056))
+$(eval $(call add_define,ERRATA_X2_2058056))
+
+# Process ERRATA_X2_2083908 flag
+$(eval $(call assert_boolean,ERRATA_X2_2083908))
+$(eval $(call add_define,ERRATA_X2_2083908))
+
+# Process ERRATA_X2_2017096 flag
+$(eval $(call assert_boolean,ERRATA_X2_2017096))
+$(eval $(call add_define,ERRATA_X2_2017096))
+
+# Process ERRATA_X2_2081180 flag
+$(eval $(call assert_boolean,ERRATA_X2_2081180))
+$(eval $(call add_define,ERRATA_X2_2081180))
+
+# Process ERRATA_X2_2216384 flag
+$(eval $(call assert_boolean,ERRATA_X2_2216384))
+$(eval $(call add_define,ERRATA_X2_2216384))
+
+# Process ERRATA_X2_2147715 flag
+$(eval $(call assert_boolean,ERRATA_X2_2147715))
+$(eval $(call add_define,ERRATA_X2_2147715))
+
+# Process ERRATA_X2_2371105 flag
+$(eval $(call assert_boolean,ERRATA_X2_2371105))
+$(eval $(call add_define,ERRATA_X2_2371105))
+
+# Process ERRATA_X3_2313909 flag
+$(eval $(call assert_boolean,ERRATA_X3_2313909))
+$(eval $(call add_define,ERRATA_X3_2313909))
+
+# Process ERRATA_A510_1922240 flag
+$(eval $(call assert_boolean,ERRATA_A510_1922240))
+$(eval $(call add_define,ERRATA_A510_1922240))
+
+# Process ERRATA_A510_2288014 flag
+$(eval $(call assert_boolean,ERRATA_A510_2288014))
+$(eval $(call add_define,ERRATA_A510_2288014))
+
+# Process ERRATA_A510_2042739 flag
+$(eval $(call assert_boolean,ERRATA_A510_2042739))
+$(eval $(call add_define,ERRATA_A510_2042739))
+
+# Process ERRATA_A510_2041909 flag
+$(eval $(call assert_boolean,ERRATA_A510_2041909))
+$(eval $(call add_define,ERRATA_A510_2041909))
+
+# Process ERRATA_A510_2250311 flag
+$(eval $(call assert_boolean,ERRATA_A510_2250311))
+$(eval $(call add_define,ERRATA_A510_2250311))
+
+# Process ERRATA_A510_2218950 flag
+$(eval $(call assert_boolean,ERRATA_A510_2218950))
+$(eval $(call add_define,ERRATA_A510_2218950))
+
+# Process ERRATA_A510_2172148 flag
+$(eval $(call assert_boolean,ERRATA_A510_2172148))
+$(eval $(call add_define,ERRATA_A510_2172148))
+
+# Process ERRATA_A510_2347730 flag
+$(eval $(call assert_boolean,ERRATA_A510_2347730))
+$(eval $(call add_define,ERRATA_A510_2347730))
+
+# Process ERRATA_A510_2371937 flag
+$(eval $(call assert_boolean,ERRATA_A510_2371937))
+$(eval $(call add_define,ERRATA_A510_2371937))
+
+# Process ERRATA_A510_2666669 flag
+$(eval $(call assert_boolean,ERRATA_A510_2666669))
+$(eval $(call add_define,ERRATA_A510_2666669))
+
+#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))
+
+# Process ERRATA_DSU_2313941 flag
+$(eval $(call assert_boolean,ERRATA_DSU_2313941))
+$(eval $(call add_define,ERRATA_DSU_2313941))
+
+# 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
+
+ifneq ($(filter 1,${ERRATA_A53_1530924} ${ERRATA_A55_1530923} \
+ ${ERRATA_A57_1319537} ${ERRATA_A72_1319367} ${ERRATA_A76_1165522}),)
+ERRATA_SPECULATIVE_AT := 1
+else
+ERRATA_SPECULATIVE_AT := 0
+endif
diff --git a/lib/cpus/errata_report.c b/lib/cpus/errata_report.c
new file mode 100644
index 0000000..93b2744
--- /dev/null
+++ b/lib/cpus/errata_report.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017-2021, 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 <assert.h>
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/cpus/errata_report.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/spinlock.h>
+
+#ifdef IMAGE_BL1
+# define BL_STRING "BL1"
+#elif defined(__aarch64__) && defined(IMAGE_BL31)
+# define BL_STRING "BL31"
+#elif !defined(__aarch64__) && 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;
+ }
+}
diff --git a/lib/debugfs/blobs.h b/lib/debugfs/blobs.h
new file mode 100644
index 0000000..54ca9f7
--- /dev/null
+++ b/lib/debugfs/blobs.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "dev.h"
+
+static const dirtab_t blobtab[] = {
+ {"ctl", DEV_ROOT_QBLOBCTL, 0, O_READ},
+ {"fip.bin", DEV_ROOT_QBLOBCTL + 1, 0x100000, O_READ, (void *)0x8000000}
+};
diff --git a/lib/debugfs/debugfs.mk b/lib/debugfs/debugfs.mk
new file mode 100644
index 0000000..138fc72
--- /dev/null
+++ b/lib/debugfs/debugfs.mk
@@ -0,0 +1,13 @@
+#
+# Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+DEBUGFS_SRCS := $(addprefix lib/debugfs/, \
+ dev.c \
+ devc.c \
+ devroot.c \
+ devfip.c)
+
+DEBUGFS_SRCS += lib/debugfs/debugfs_smc.c
diff --git a/lib/debugfs/debugfs_smc.c b/lib/debugfs/debugfs_smc.c
new file mode 100644
index 0000000..400c166
--- /dev/null
+++ b/lib/debugfs/debugfs_smc.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <lib/debugfs.h>
+#include <lib/smccc.h>
+#include <lib/spinlock.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <smccc_helpers.h>
+
+#define MAX_PATH_LEN 256
+
+#define MOUNT 0
+#define CREATE 1
+#define OPEN 2
+#define CLOSE 3
+#define READ 4
+#define WRITE 5
+#define SEEK 6
+#define BIND 7
+#define STAT 8
+#define INIT 10
+#define VERSION 11
+
+/* This is the virtual address to which we map the NS shared buffer */
+#define DEBUGFS_SHARED_BUF_VIRT ((void *)0x81000000U)
+
+static union debugfs_parms {
+ struct {
+ char fname[MAX_PATH_LEN];
+ } open;
+
+ struct {
+ char srv[MAX_PATH_LEN];
+ char where[MAX_PATH_LEN];
+ char spec[MAX_PATH_LEN];
+ } mount;
+
+ struct {
+ char path[MAX_PATH_LEN];
+ dir_t dir;
+ } stat;
+
+ struct {
+ char oldpath[MAX_PATH_LEN];
+ char newpath[MAX_PATH_LEN];
+ } bind;
+} parms;
+
+/* debugfs_access_lock protects shared buffer and internal */
+/* FS functions from concurrent acccesses. */
+static spinlock_t debugfs_access_lock;
+
+static bool debugfs_initialized;
+
+uintptr_t debugfs_smc_handler(unsigned int smc_fid,
+ u_register_t cmd,
+ u_register_t arg2,
+ u_register_t arg3,
+ u_register_t arg4,
+ void *cookie,
+ void *handle,
+ u_register_t flags)
+{
+ int64_t smc_ret = DEBUGFS_E_INVALID_PARAMS, smc_resp = 0;
+ int ret;
+
+ /* Allow calls from non-secure only */
+ if (is_caller_secure(flags)) {
+ SMC_RET1(handle, DEBUGFS_E_DENIED);
+ }
+
+ /* Expect a SiP service fast call */
+ if ((GET_SMC_TYPE(smc_fid) != SMC_TYPE_FAST) ||
+ (GET_SMC_OEN(smc_fid) != OEN_SIP_START)) {
+ SMC_RET1(handle, SMC_UNK);
+ }
+
+ /* Truncate parameters if 32b SMC convention call */
+ if (GET_SMC_CC(smc_fid) == SMC_32) {
+ arg2 &= 0xffffffff;
+ arg3 &= 0xffffffff;
+ arg4 &= 0xffffffff;
+ }
+
+ spin_lock(&debugfs_access_lock);
+
+ if (debugfs_initialized == true) {
+ /* Copy NS shared buffer to internal secure location */
+ memcpy(&parms, (void *)DEBUGFS_SHARED_BUF_VIRT,
+ sizeof(union debugfs_parms));
+ }
+
+ switch (cmd) {
+ case INIT:
+ if (debugfs_initialized == false) {
+ /* TODO: check PA validity e.g. whether */
+ /* it is an NS region. */
+ ret = mmap_add_dynamic_region(arg2,
+ (uintptr_t)DEBUGFS_SHARED_BUF_VIRT,
+ PAGE_SIZE_4KB,
+ MT_MEMORY | MT_RW | MT_NS);
+ if (ret == 0) {
+ debugfs_initialized = true;
+ smc_ret = SMC_OK;
+ smc_resp = 0;
+ }
+ }
+ break;
+
+ case VERSION:
+ smc_ret = SMC_OK;
+ smc_resp = DEBUGFS_VERSION;
+ break;
+
+ case MOUNT:
+ ret = mount(parms.mount.srv,
+ parms.mount.where,
+ parms.mount.spec);
+ if (ret == 0) {
+ smc_ret = SMC_OK;
+ smc_resp = 0;
+ }
+ break;
+
+ case OPEN:
+ ret = open(parms.open.fname, arg2);
+ if (ret >= 0) {
+ smc_ret = SMC_OK;
+ smc_resp = ret;
+ }
+ break;
+
+ case CLOSE:
+ ret = close(arg2);
+ if (ret == 0) {
+ smc_ret = SMC_OK;
+ smc_resp = 0;
+ }
+ break;
+
+ case READ:
+ ret = read(arg2, DEBUGFS_SHARED_BUF_VIRT, arg3);
+ if (ret >= 0) {
+ smc_ret = SMC_OK;
+ smc_resp = ret;
+ }
+ break;
+
+ case SEEK:
+ ret = seek(arg2, arg3, arg4);
+ if (ret == 0) {
+ smc_ret = SMC_OK;
+ smc_resp = 0;
+ }
+ break;
+
+ case BIND:
+ ret = bind(parms.bind.oldpath, parms.bind.newpath);
+ if (ret == 0) {
+ smc_ret = SMC_OK;
+ smc_resp = 0;
+ }
+ break;
+
+ case STAT:
+ ret = stat(parms.stat.path, &parms.stat.dir);
+ if (ret == 0) {
+ memcpy((void *)DEBUGFS_SHARED_BUF_VIRT, &parms,
+ sizeof(union debugfs_parms));
+ smc_ret = SMC_OK;
+ smc_resp = 0;
+ }
+ break;
+
+ /* Not implemented */
+ case CREATE:
+ /* Intentional fall-through */
+
+ /* Not implemented */
+ case WRITE:
+ /* Intentional fall-through */
+
+ default:
+ smc_ret = SMC_UNK;
+ smc_resp = 0;
+ }
+
+ spin_unlock(&debugfs_access_lock);
+
+ SMC_RET2(handle, smc_ret, smc_resp);
+
+ /* Not reached */
+ return smc_ret;
+}
+
+int debugfs_smc_setup(void)
+{
+ debugfs_initialized = false;
+ debugfs_access_lock.lock = 0;
+
+ return 0;
+}
diff --git a/lib/debugfs/dev.c b/lib/debugfs/dev.c
new file mode 100644
index 0000000..2fc1d40
--- /dev/null
+++ b/lib/debugfs/dev.c
@@ -0,0 +1,853 @@
+/*
+ * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cdefs.h>
+#include <common/debug.h>
+#include <lib/debugfs.h>
+#include <string.h>
+
+#include "dev.h"
+
+#define NR_MOUNT_POINTS 4
+
+struct mount_point {
+ chan_t *new;
+ chan_t *old;
+};
+
+/* This array contains all the available channels of the filesystem.
+ * A file descriptor is the index of a specific channel in this array.
+ */
+static chan_t fdset[NR_CHANS];
+
+/* This array contains all the available mount points of the filesystem. */
+static struct mount_point mount_points[NR_MOUNT_POINTS];
+
+/* This variable stores the channel associated to the root directory. */
+static chan_t slash_channel;
+
+/* This function creates a channel from a device index and registers
+ * it to fdset.
+ */
+static chan_t *create_new_channel(unsigned char index)
+{
+ chan_t *channel = NULL;
+ int i;
+
+ for (i = 0; i < NR_CHANS; i++) {
+ if (fdset[i].index == NODEV) {
+ channel = &fdset[i];
+ channel->index = index;
+ break;
+ }
+ }
+
+ return channel;
+}
+
+/*******************************************************************************
+ * This function returns a pointer to an existing channel in fdset from a file
+ * descriptor.
+ ******************************************************************************/
+static chan_t *fd_to_channel(int fd)
+{
+ if ((fd < 0) || (fd >= NR_CHANS) || (fdset[fd].index == NODEV)) {
+ return NULL;
+ }
+
+ return &fdset[fd];
+}
+
+/*******************************************************************************
+ * This function returns a file descriptor from a channel.
+ * The caller must be sure that the channel is registered in fdset.
+ ******************************************************************************/
+static int channel_to_fd(chan_t *channel)
+{
+ return (channel == NULL) ? -1 : (channel - fdset);
+}
+
+/*******************************************************************************
+ * This function checks the validity of a mode.
+ ******************************************************************************/
+static bool is_valid_mode(int mode)
+{
+ if ((mode & O_READ) && (mode & (O_WRITE | O_RDWR))) {
+ return false;
+ }
+ if ((mode & O_WRITE) && (mode & (O_READ | O_RDWR))) {
+ return false;
+ }
+ if ((mode & O_RDWR) && (mode & (O_READ | O_WRITE))) {
+ return false;
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ * This function extracts the next part of the given path contained and puts it
+ * in token. It returns a pointer to the remainder of the path.
+ ******************************************************************************/
+static const char *next(const char *path, char *token)
+{
+ int index;
+ const char *cursor;
+
+ while (*path == '/') {
+ ++path;
+ }
+
+ index = 0;
+ cursor = path;
+ if (*path != '\0') {
+ while (*cursor != '/' && *cursor != '\0') {
+ if (index == NAMELEN) {
+ return NULL;
+ }
+ token[index++] = *cursor++;
+ }
+ }
+ token[index] = '\0';
+
+ return cursor;
+}
+
+/*******************************************************************************
+ * This function returns the driver index in devtab of the driver
+ * identified by id.
+ ******************************************************************************/
+static int get_device_index(int id)
+{
+ int index;
+ dev_t * const *dp;
+
+ for (index = 0, dp = devtab; *dp && (*dp)->id != id; ++dp) {
+ index++;
+ }
+
+ if (*dp == NULL) {
+ return -1;
+ }
+
+ return index;
+}
+
+/*******************************************************************************
+ * This function clears a given channel fields
+ ******************************************************************************/
+static void channel_clear(chan_t *channel)
+{
+ channel->offset = 0;
+ channel->qid = 0;
+ channel->index = NODEV;
+ channel->dev = 0;
+ channel->mode = 0;
+}
+
+/*******************************************************************************
+ * This function closes the channel pointed to by c.
+ ******************************************************************************/
+void channel_close(chan_t *channel)
+{
+ if (channel != NULL) {
+ channel_clear(channel);
+ }
+}
+
+/*******************************************************************************
+ * This function copies data from src to dst after applying the offset of the
+ * channel c. nbytes bytes are expected to be copied unless the data goes over
+ * dst + len.
+ * It returns the actual number of bytes that were copied.
+ ******************************************************************************/
+int buf_to_channel(chan_t *channel, void *dst, void *src, int nbytes, long len)
+{
+ const char *addr = src;
+
+ if ((channel == NULL) || (dst == NULL) || (src == NULL)) {
+ return 0;
+ }
+
+ if (channel->offset >= len) {
+ return 0;
+ }
+
+ if ((channel->offset + nbytes) > len) {
+ nbytes = len - channel->offset;
+ }
+
+ memcpy(dst, addr + channel->offset, nbytes);
+
+ channel->offset += nbytes;
+
+ return nbytes;
+}
+
+/*******************************************************************************
+ * This function checks whether a channel (identified by its device index and
+ * qid) is registered as a mount point.
+ * Returns a pointer to the channel it is mounted to when found, NULL otherwise.
+ ******************************************************************************/
+static chan_t *mount_point_to_channel(int index, qid_t qid)
+{
+ chan_t *channel;
+ struct mount_point *mp;
+
+ for (mp = mount_points; mp < &mount_points[NR_MOUNT_POINTS]; mp++) {
+ channel = mp->new;
+ if (channel == NULL) {
+ continue;
+ }
+
+ if ((channel->index == index) && (channel->qid == qid)) {
+ return mp->old;
+ }
+ }
+
+ return NULL;
+}
+
+/*******************************************************************************
+ * This function calls the attach function of the driver identified by id.
+ ******************************************************************************/
+chan_t *attach(int id, int dev)
+{
+ /* Get the devtab index for the driver identified by id */
+ int index = get_device_index(id);
+
+ if (index < 0) {
+ return NULL;
+ }
+
+ return devtab[index]->attach(id, dev);
+}
+
+/*******************************************************************************
+ * This function is the default implementation of the driver attach function.
+ * It creates a new channel and returns a pointer to it.
+ ******************************************************************************/
+chan_t *devattach(int id, int dev)
+{
+ chan_t *channel;
+ int index;
+
+ index = get_device_index(id);
+ if (index < 0) {
+ return NULL;
+ }
+
+ channel = create_new_channel(index);
+ if (channel == NULL) {
+ return NULL;
+ }
+
+ channel->dev = dev;
+ channel->qid = CHDIR;
+
+ return channel;
+}
+
+/*******************************************************************************
+ * This function returns a channel given a path.
+ * It goes through the filesystem, from the root namespace ('/') or from a
+ * device namespace ('#'), switching channel on mount points.
+ ******************************************************************************/
+chan_t *path_to_channel(const char *path, int mode)
+{
+ int i, n;
+ const char *path_next;
+ chan_t *mnt, *channel;
+ char elem[NAMELEN];
+
+ if (path == NULL) {
+ return NULL;
+ }
+
+ switch (path[0]) {
+ case '/':
+ channel = clone(&slash_channel, NULL);
+ path_next = path;
+ break;
+ case '#':
+ path_next = next(path + 1, elem);
+ if (path_next == NULL) {
+ goto noent;
+ }
+
+ n = 0;
+ for (i = 1; (elem[i] >= '0') && (elem[i] <= '9'); i++) {
+ n += elem[i] - '0';
+ }
+
+ if (elem[i] != '\0') {
+ goto noent;
+ }
+
+ channel = attach(elem[0], n);
+ break;
+ default:
+ return NULL;
+ }
+
+ if (channel == NULL) {
+ return NULL;
+ }
+
+ for (path_next = next(path_next, elem); *elem;
+ path_next = next(path_next, elem)) {
+ if ((channel->qid & CHDIR) == 0) {
+ goto notfound;
+ }
+
+ if (devtab[channel->index]->walk(channel, elem) < 0) {
+ channel_close(channel);
+ goto notfound;
+ }
+
+ mnt = mount_point_to_channel(channel->index, channel->qid);
+ if (mnt != NULL) {
+ clone(mnt, channel);
+ }
+ }
+
+ if (path_next == NULL) {
+ goto notfound;
+ }
+
+ /* TODO: check mode */
+ return channel;
+
+notfound:
+ channel_close(channel);
+noent:
+ return NULL;
+}
+
+/*******************************************************************************
+ * This function calls the clone function of the driver associated to the
+ * channel c.
+ ******************************************************************************/
+chan_t *clone(chan_t *c, chan_t *nc)
+{
+ if (c->index == NODEV) {
+ return NULL;
+ }
+
+ return devtab[c->index]->clone(c, nc);
+}
+
+/*******************************************************************************
+ * This function is the default implementation of the driver clone function.
+ * It creates a new channel and returns a pointer to it.
+ * It clones channel into new_channel.
+ ******************************************************************************/
+chan_t *devclone(chan_t *channel, chan_t *new_channel)
+{
+ if (channel == NULL) {
+ return NULL;
+ }
+
+ if (new_channel == NULL) {
+ new_channel = create_new_channel(channel->index);
+ if (new_channel == NULL) {
+ return NULL;
+ }
+ }
+
+ new_channel->qid = channel->qid;
+ new_channel->dev = channel->dev;
+ new_channel->mode = channel->mode;
+ new_channel->offset = channel->offset;
+ new_channel->index = channel->index;
+
+ return new_channel;
+}
+
+/*******************************************************************************
+ * This function is the default implementation of the driver walk function.
+ * It goes through all the elements of tab using the gen function until a match
+ * is found with name.
+ * If a match is found, it copies the qid of the new directory.
+ ******************************************************************************/
+int devwalk(chan_t *channel, const char *name, const dirtab_t *tab,
+ int ntab, devgen_t *gen)
+{
+ int i;
+ dir_t dir;
+
+ if ((channel == NULL) || (name == NULL) || (gen == NULL)) {
+ return -1;
+ }
+
+ if ((name[0] == '.') && (name[1] == '\0')) {
+ return 1;
+ }
+
+ for (i = 0; ; i++) {
+ switch ((*gen)(channel, tab, ntab, i, &dir)) {
+ case 0:
+ /* Intentional fall-through */
+ case -1:
+ return -1;
+ case 1:
+ if (strncmp(name, dir.name, NAMELEN) != 0) {
+ continue;
+ }
+ channel->qid = dir.qid;
+ return 1;
+ }
+ }
+}
+
+/*******************************************************************************
+ * This is a helper function which exposes the content of a directory, element
+ * by element. It is meant to be called until the end of the directory is
+ * reached or an error occurs.
+ * It returns -1 on error, 0 on end of directory and 1 when a new file is found.
+ ******************************************************************************/
+int dirread(chan_t *channel, dir_t *dir, const dirtab_t *tab,
+ int ntab, devgen_t *gen)
+{
+ int i, ret;
+
+ if ((channel == NULL) || (dir == NULL) || (gen == NULL)) {
+ return -1;
+ }
+
+ i = channel->offset/sizeof(dir_t);
+ ret = (*gen)(channel, tab, ntab, i, dir);
+ if (ret == 1) {
+ channel->offset += sizeof(dir_t);
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ * This function sets the elements of dir.
+ ******************************************************************************/
+void make_dir_entry(chan_t *channel, dir_t *dir,
+ const char *name, long length, qid_t qid, unsigned int mode)
+{
+ if ((channel == NULL) || (dir == NULL) || (name == NULL)) {
+ return;
+ }
+
+ strlcpy(dir->name, name, sizeof(dir->name));
+ dir->length = length;
+ dir->qid = qid;
+ dir->mode = mode;
+
+ if ((qid & CHDIR) != 0) {
+ dir->mode |= O_DIR;
+ }
+
+ dir->index = channel->index;
+ dir->dev = channel->dev;
+}
+
+/*******************************************************************************
+ * This function is the default implementation of the internal driver gen
+ * function.
+ * It copies and formats the information of the nth element of tab into dir.
+ ******************************************************************************/
+int devgen(chan_t *channel, const dirtab_t *tab, int ntab, int n, dir_t *dir)
+{
+ const dirtab_t *dp;
+
+ if ((channel == NULL) || (dir == NULL) || (tab == NULL) ||
+ (n >= ntab)) {
+ return 0;
+ }
+
+ dp = &tab[n];
+ make_dir_entry(channel, dir, dp->name, dp->length, dp->qid, dp->perm);
+ return 1;
+}
+
+/*******************************************************************************
+ * This function returns a file descriptor identifying the channel associated to
+ * the given path.
+ ******************************************************************************/
+int open(const char *path, int mode)
+{
+ chan_t *channel;
+
+ if (path == NULL) {
+ return -1;
+ }
+
+ if (is_valid_mode(mode) == false) {
+ return -1;
+ }
+
+ channel = path_to_channel(path, mode);
+
+ return channel_to_fd(channel);
+}
+
+/*******************************************************************************
+ * This function closes the channel identified by the file descriptor fd.
+ ******************************************************************************/
+int close(int fd)
+{
+ chan_t *channel;
+
+ channel = fd_to_channel(fd);
+ if (channel == NULL) {
+ return -1;
+ }
+
+ channel_close(channel);
+ return 0;
+}
+
+/*******************************************************************************
+ * This function is the default implementation of the driver stat function.
+ * It goes through all the elements of tab using the gen function until a match
+ * is found with file.
+ * If a match is found, dir contains the information file.
+ ******************************************************************************/
+int devstat(chan_t *dirc, const char *file, dir_t *dir,
+ const dirtab_t *tab, int ntab, devgen_t *gen)
+{
+ int i, r = 0;
+ chan_t *c, *mnt;
+
+ if ((dirc == NULL) || (dir == NULL) || (gen == NULL)) {
+ return -1;
+ }
+
+ c = path_to_channel(file, O_STAT);
+ if (c == NULL) {
+ return -1;
+ }
+
+ for (i = 0; ; i++) {
+ switch ((*gen)(dirc, tab, ntab, i, dir)) {
+ case 0:
+ /* Intentional fall-through */
+ case -1:
+ r = -1;
+ goto leave;
+ case 1:
+ mnt = mount_point_to_channel(dir->index, dir->qid);
+ if (mnt != NULL) {
+ dir->qid = mnt->qid;
+ dir->index = mnt->index;
+ }
+
+ if ((dir->qid != c->qid) || (dir->index != c->index)) {
+ continue;
+ }
+
+ goto leave;
+ }
+ }
+
+leave:
+ channel_close(c);
+ return r;
+}
+
+/*******************************************************************************
+ * This function calls the stat function of the driver associated to the parent
+ * directory of the file in path.
+ * The result is stored in dir.
+ ******************************************************************************/
+int stat(const char *path, dir_t *dir)
+{
+ int r;
+ size_t len;
+ chan_t *channel;
+ char *p, dirname[PATHLEN];
+
+ if ((path == NULL) || (dir == NULL)) {
+ return -1;
+ }
+
+ len = strlen(path);
+ if ((len + 1) > sizeof(dirname)) {
+ return -1;
+ }
+
+ memcpy(dirname, path, len);
+ for (p = dirname + len; p > dirname; --p) {
+ if (*p != '/') {
+ break;
+ }
+ }
+
+ p = memrchr(dirname, '/', p - dirname);
+ if (p == NULL) {
+ return -1;
+ }
+
+ dirname[p - dirname + 1] = '\0';
+
+ channel = path_to_channel(dirname, O_STAT);
+ if (channel == NULL) {
+ return -1;
+ }
+
+ r = devtab[channel->index]->stat(channel, path, dir);
+ channel_close(channel);
+
+ return r;
+}
+
+/*******************************************************************************
+ * This function calls the read function of the driver associated to fd.
+ * It fills buf with at most n bytes.
+ * It returns the number of bytes that were actually read.
+ ******************************************************************************/
+int read(int fd, void *buf, int n)
+{
+ chan_t *channel;
+
+ if (buf == NULL) {
+ return -1;
+ }
+
+ channel = fd_to_channel(fd);
+ if (channel == NULL) {
+ return -1;
+ }
+
+ if (((channel->qid & CHDIR) != 0) && (n < sizeof(dir_t))) {
+ return -1;
+ }
+
+ return devtab[channel->index]->read(channel, buf, n);
+}
+
+/*******************************************************************************
+ * This function calls the write function of the driver associated to fd.
+ * It writes at most n bytes of buf.
+ * It returns the number of bytes that were actually written.
+ ******************************************************************************/
+int write(int fd, void *buf, int n)
+{
+ chan_t *channel;
+
+ if (buf == NULL) {
+ return -1;
+ }
+
+ channel = fd_to_channel(fd);
+ if (channel == NULL) {
+ return -1;
+ }
+
+ if ((channel->qid & CHDIR) != 0) {
+ return -1;
+ }
+
+ return devtab[channel->index]->write(channel, buf, n);
+}
+
+/*******************************************************************************
+ * This function calls the seek function of the driver associated to fd.
+ * It applies the offset off according to the strategy whence.
+ ******************************************************************************/
+int seek(int fd, long off, int whence)
+{
+ chan_t *channel;
+
+ channel = fd_to_channel(fd);
+ if (channel == NULL) {
+ return -1;
+ }
+
+ if ((channel->qid & CHDIR) != 0) {
+ return -1;
+ }
+
+ return devtab[channel->index]->seek(channel, off, whence);
+}
+
+/*******************************************************************************
+ * This function is the default error implementation of the driver mount
+ * function.
+ ******************************************************************************/
+chan_t *deverrmount(chan_t *channel, const char *spec)
+{
+ return NULL;
+}
+
+/*******************************************************************************
+ * This function is the default error implementation of the driver write
+ * function.
+ ******************************************************************************/
+int deverrwrite(chan_t *channel, void *buf, int n)
+{
+ return -1;
+}
+
+/*******************************************************************************
+ * This function is the default error implementation of the driver seek
+ * function.
+ ******************************************************************************/
+int deverrseek(chan_t *channel, long off, int whence)
+{
+ return -1;
+}
+
+/*******************************************************************************
+ * This function is the default implementation of the driver seek function.
+ * It applies the offset off according to the strategy whence to the channel c.
+ ******************************************************************************/
+int devseek(chan_t *channel, long off, int whence)
+{
+ switch (whence) {
+ case KSEEK_SET:
+ channel->offset = off;
+ break;
+ case KSEEK_CUR:
+ channel->offset += off;
+ break;
+ case KSEEK_END:
+ /* Not implemented */
+ return -1;
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ * This function registers the channel associated to the path new as a mount
+ * point for the channel c.
+ ******************************************************************************/
+static int add_mount_point(chan_t *channel, const char *new)
+{
+ int i;
+ chan_t *cn;
+ struct mount_point *mp;
+
+ if (new == NULL) {
+ goto err0;
+ }
+
+ cn = path_to_channel(new, O_READ);
+ if (cn == NULL) {
+ goto err0;
+ }
+
+ if ((cn->qid & CHDIR) == 0) {
+ goto err1;
+ }
+
+ for (i = NR_MOUNT_POINTS - 1; i >= 0; i--) {
+ mp = &mount_points[i];
+ if (mp->new == NULL) {
+ break;
+ }
+ }
+
+ if (i < 0) {
+ goto err1;
+ }
+
+ mp->new = cn;
+ mp->old = channel;
+
+ return 0;
+
+err1:
+ channel_close(cn);
+err0:
+ return -1;
+}
+
+/*******************************************************************************
+ * This function registers the path new as a mount point for the path old.
+ ******************************************************************************/
+int bind(const char *old, const char *new)
+{
+ chan_t *channel;
+
+ channel = path_to_channel(old, O_BIND);
+ if (channel == NULL) {
+ return -1;
+ }
+
+ if (add_mount_point(channel, new) < 0) {
+ channel_close(channel);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ * This function calls the mount function of the driver associated to the path
+ * srv.
+ * It mounts the path srv on the path where.
+ ******************************************************************************/
+int mount(const char *srv, const char *where, const char *spec)
+{
+ chan_t *channel, *mount_point_chan;
+ int ret;
+
+ channel = path_to_channel(srv, O_RDWR);
+ if (channel == NULL) {
+ goto err0;
+ }
+
+ mount_point_chan = devtab[channel->index]->mount(channel, spec);
+ if (mount_point_chan == NULL) {
+ goto err1;
+ }
+
+ ret = add_mount_point(mount_point_chan, where);
+ if (ret < 0) {
+ goto err2;
+ }
+
+ channel_close(channel);
+
+ return 0;
+
+err2:
+ channel_close(mount_point_chan);
+err1:
+ channel_close(channel);
+err0:
+ return -1;
+}
+
+/*******************************************************************************
+ * This function initializes the device environment.
+ * It creates the '/' channel.
+ * It links the device drivers to the physical drivers.
+ ******************************************************************************/
+void debugfs_init(void)
+{
+ chan_t *channel, *cloned_channel;
+
+ for (channel = fdset; channel < &fdset[NR_CHANS]; channel++) {
+ channel_clear(channel);
+ }
+
+ channel = devattach('/', 0);
+ if (channel == NULL) {
+ panic();
+ }
+
+ cloned_channel = clone(channel, &slash_channel);
+ if (cloned_channel == NULL) {
+ panic();
+ }
+
+ channel_close(channel);
+ devlink();
+}
+
+__dead2 void devpanic(const char *cause)
+{
+ panic();
+}
diff --git a/lib/debugfs/dev.h b/lib/debugfs/dev.h
new file mode 100644
index 0000000..c142651
--- /dev/null
+++ b/lib/debugfs/dev.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DEV_H
+#define DEV_H
+
+#include <cdefs.h>
+#include <lib/debugfs.h>
+#include <stddef.h>
+
+/* FIXME: need configurability */
+#define NR_CHANS 10
+#define NR_CONSS 1
+#define NR_BINDS 4
+#define NR_FILES 18
+
+#define NODEV 255
+#define CHDIR (1 << 15)
+
+#define SYNCDEV 0
+#define SYNCALL 1
+
+typedef struct dev dev_t;
+typedef struct chan chan_t;
+typedef struct dirtab dirtab_t;
+typedef int devgen_t(chan_t *, const dirtab_t *, int, int, dir_t *);
+typedef struct attr attr_t;
+
+enum {
+ DEV_ROOT_QROOT,
+ DEV_ROOT_QDEV,
+ DEV_ROOT_QFIP,
+ DEV_ROOT_QBLOBS,
+ DEV_ROOT_QBLOBCTL,
+ DEV_ROOT_QPSCI
+};
+
+/*******************************************************************************
+ * This structure contains the necessary information to represent a directory
+ * of the filesystem.
+ ******************************************************************************/
+struct dirtab {
+ char name[NAMELEN];
+ qid_t qid;
+ long length;
+ unsigned char perm;
+ void *data;
+};
+
+/*******************************************************************************
+ * This structure defines the interface of device drivers.
+ * Each driver must implement a subset of those functions.
+ * It is possible to redirect to default implementations defined in dev.c.
+ ******************************************************************************/
+/* FIXME: comments for the callbacks */
+struct dev {
+ char id;
+ int (*stat)(chan_t *c, const char *file, dir_t *dir);
+ int (*walk)(chan_t *c, const char *name);
+ int (*read)(chan_t *c, void *buf, int n);
+ int (*write)(chan_t *c, void *buf, int n);
+ int (*seek)(chan_t *c, long off, int whence);
+ chan_t *(*clone)(chan_t *c, chan_t *nc);
+ chan_t *(*attach)(int id, int dev);
+ chan_t *(*mount)(chan_t *c, const char *spec);
+};
+
+/*******************************************************************************
+ * This structure defines the channel structure.
+ * A channel is a handle on an element of the filesystem.
+ ******************************************************************************/
+struct chan {
+ long offset;
+ qid_t qid;
+ unsigned char index; /* device index in devtab */
+ unsigned char dev;
+ unsigned char mode;
+};
+
+/*******************************************************************************
+ * This structure defines an abstract argument passed to physical drivers from
+ * the configuration file.
+ ******************************************************************************/
+struct attr {
+ char *key;
+ char *value;
+};
+
+chan_t *path_to_channel(const char *path, int mode);
+chan_t *clone(chan_t *c, chan_t *nc);
+chan_t *attach(int id, int dev);
+void channel_close(chan_t *c);
+int buf_to_channel(chan_t *c, void *dst, void *src, int nbytes, long len);
+int dirread(chan_t *c, dir_t *dir, const dirtab_t *tab,
+ int ntab, devgen_t *gen);
+void make_dir_entry(chan_t *c, dir_t *dir, const char *name, long length,
+ qid_t qid, unsigned int mode);
+void devlink(void);
+
+chan_t *devattach(int id, int dev);
+int devseek(chan_t *c, long off, int whence);
+chan_t *devclone(chan_t *c, chan_t *nc);
+int devgen(chan_t *c, const dirtab_t *tab, int ntab, int n, dir_t *dir);
+int devwalk(chan_t *c, const char *name, const dirtab_t *tab, int ntab,
+ devgen_t *gen);
+int devstat(chan_t *dirc, const char *file, dir_t *dir,
+ const dirtab_t *tab, int ntab, devgen_t *gen);
+
+chan_t *deverrmount(chan_t *c, const char *spec);
+int deverrwrite(chan_t *c, void *buf, int n);
+int deverrseek(chan_t *c, long off, int whence);
+
+extern dev_t *const devtab[];
+
+void __dead2 devpanic(const char *cause);
+
+#endif /* DEV_H */
diff --git a/lib/debugfs/devc.c b/lib/debugfs/devc.c
new file mode 100644
index 0000000..1099a85
--- /dev/null
+++ b/lib/debugfs/devc.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+typedef struct dev dev_t;
+
+extern dev_t rootdevtab;
+extern dev_t fipdevtab;
+
+dev_t *const devtab[] = {
+ &rootdevtab,
+ &fipdevtab,
+ 0
+};
+
+void devlink(void)
+{
+}
diff --git a/lib/debugfs/devfip.c b/lib/debugfs/devfip.c
new file mode 100644
index 0000000..85e6403
--- /dev/null
+++ b/lib/debugfs/devfip.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <lib/debugfs.h>
+#include <limits.h>
+#include <plat/arm/common/plat_arm.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tools_share/firmware_image_package.h>
+
+#include "dev.h"
+
+#define NR_FIPS 1
+#define STOC_HEADER (sizeof(fip_toc_header_t))
+#define STOC_ENTRY (sizeof(fip_toc_entry_t))
+
+struct fipfile {
+ chan_t *c;
+ long offset[NR_FILES];
+ long size[NR_FILES];
+};
+
+struct fip_entry {
+ uuid_t uuid;
+ long long offset_address;
+ long long size;
+ long long flags;
+};
+
+struct uuidnames {
+ const char name[NAMELEN];
+ const uuid_t uuid;
+};
+
+/*******************************************************************************
+ * This array links the FIP file names to their UUID.
+ * The elements are ordered according to the image number stored in
+ * tbbr_img_def.h, starting at index 1.
+ *
+ * TODO: this name to uuid binding will preferably be done using
+ * the coming Property Access Layer / Firmware CONFiguration feature.
+ ******************************************************************************/
+static const struct uuidnames uuidnames[] = {
+ {"", { {0}, {0}, {0}, 0, 0, {0} } },
+ {"bl2.bin", UUID_TRUSTED_BOOT_FIRMWARE_BL2},
+ {"scp-bl2.bin", UUID_SCP_FIRMWARE_SCP_BL2},
+ {"bl31.bin", UUID_EL3_RUNTIME_FIRMWARE_BL31},
+ {"bl32.bin", UUID_SECURE_PAYLOAD_BL32},
+ {"bl33.bin", UUID_NON_TRUSTED_FIRMWARE_BL33},
+ {"tb-fw.crt", UUID_TRUSTED_BOOT_FW_CERT},
+ {"trstd-k.crt", UUID_TRUSTED_KEY_CERT},
+ {"scp-fw-k.crt", UUID_SCP_FW_KEY_CERT},
+ {"soc-fw-k.crt", UUID_SOC_FW_KEY_CERT},
+ {"tos-fw-k.crt", UUID_TRUSTED_OS_FW_KEY_CERT},
+ {"nt-fw-k.crt", UUID_NON_TRUSTED_FW_KEY_CERT},
+ {"scp-fw-c.crt", UUID_SCP_FW_CONTENT_CERT},
+ {"soc-fw-c.crt", UUID_SOC_FW_CONTENT_CERT},
+ {"tos-fw-c.crt", UUID_TRUSTED_OS_FW_CONTENT_CERT},
+ {"nt-fw-c.crt", UUID_NON_TRUSTED_FW_CONTENT_CERT},
+ { },
+ {"fwu.crt", UUID_TRUSTED_FWU_CERT},
+ {"scp-bl2u.bin", UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U},
+ {"bl2u.bin", UUID_TRUSTED_UPDATE_FIRMWARE_BL2U},
+ {"ns-bl2u.bin", UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U},
+ {"bl32-xtr1.bin", UUID_SECURE_PAYLOAD_BL32_EXTRA1},
+ {"bl32-xtr2.bin", UUID_SECURE_PAYLOAD_BL32_EXTRA2},
+ {"hw.cfg", UUID_HW_CONFIG},
+ {"tb-fw.cfg", UUID_TB_FW_CONFIG},
+ {"soc-fw.cfg", UUID_SOC_FW_CONFIG},
+ {"tos-fw.cfg", UUID_TOS_FW_CONFIG},
+ {"nt-fw.cfg", UUID_NT_FW_CONFIG},
+ {"fw.cfg", UUID_FW_CONFIG},
+ {"rot-k.crt", UUID_ROT_KEY_CERT},
+ {"nt-k.crt", UUID_NON_TRUSTED_WORLD_KEY_CERT},
+ {"sip-sp.crt", UUID_SIP_SECURE_PARTITION_CONTENT_CERT},
+ {"plat-sp.crt", UUID_PLAT_SECURE_PARTITION_CONTENT_CERT}
+};
+
+/*******************************************************************************
+ * This array contains all the available FIP files.
+ ******************************************************************************/
+static struct fipfile archives[NR_FIPS];
+
+/*******************************************************************************
+ * This variable stores the current number of registered FIP files.
+ ******************************************************************************/
+static int nfips;
+
+/*******************************************************************************
+ * This function parses the ToC of the FIP.
+ ******************************************************************************/
+static int get_entry(chan_t *c, struct fip_entry *entry)
+{
+ int n;
+
+ n = devtab[c->index]->read(c, entry, sizeof(struct fip_entry));
+ if (n <= 0) {
+ return n;
+ }
+
+ if (n != sizeof(struct fip_entry)) {
+ return -1;
+ }
+
+ if (entry->size == 0) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/*******************************************************************************
+ * This function exposes the FIP images as files.
+ ******************************************************************************/
+static int fipgen(chan_t *c, const dirtab_t *tab, int ntab, int n, dir_t *dir)
+{
+ int i, r;
+ long off;
+ chan_t nc;
+ struct fip_entry entry;
+ struct fipfile *fip;
+ static const char unk[] = "unknown";
+
+ if (c->dev >= nfips) {
+ panic();
+ }
+
+ if (clone(archives[c->dev].c, &nc) == NULL) {
+ panic();
+ }
+
+ fip = &archives[nc.dev];
+
+ off = STOC_HEADER;
+ for (i = 0; i <= n; i++) {
+ if (fip->offset[i] == -1) {
+ return 0;
+ }
+
+ if (devtab[nc.index]->seek(&nc, off, KSEEK_SET) < 0) {
+ return -1;
+ }
+
+ r = get_entry(&nc, &entry);
+ if (r <= 0) {
+ return r;
+ }
+
+ off += sizeof(entry);
+ }
+
+ for (i = 1; i < NELEM(uuidnames); i++) {
+ if (memcmp(&uuidnames[i].uuid,
+ &entry.uuid, sizeof(uuid_t)) == 0) {
+ break;
+ }
+ }
+
+ if (i < NELEM(uuidnames)) {
+ make_dir_entry(c, dir, uuidnames[i].name,
+ entry.size, n, O_READ);
+ } else {
+ // TODO: set name depending on uuid node value
+ make_dir_entry(c, dir, unk, entry.size, n, O_READ);
+ }
+
+ return 1;
+}
+
+static int fipwalk(chan_t *c, const char *name)
+{
+ return devwalk(c, name, NULL, 0, fipgen);
+}
+
+static int fipstat(chan_t *c, const char *file, dir_t *dir)
+{
+ return devstat(c, file, dir, NULL, 0, fipgen);
+}
+
+/*******************************************************************************
+ * This function copies at most n bytes of the FIP image referred by c into
+ * buf.
+ ******************************************************************************/
+static int fipread(chan_t *c, void *buf, int n)
+{
+ long off;
+ chan_t cs;
+ struct fipfile *fip;
+ long size;
+
+ /* Only makes sense when using debug language */
+ assert(c->qid != CHDIR);
+
+ if ((c->dev >= nfips) || ((c->qid & CHDIR) != 0)) {
+ panic();
+ }
+
+ fip = &archives[c->dev];
+
+ if ((c->qid >= NR_FILES) || (fip->offset[c->qid] < 0)) {
+ panic();
+ }
+
+ if (clone(fip->c, &cs) == NULL) {
+ panic();
+ }
+
+ size = fip->size[c->qid];
+ if (c->offset >= size) {
+ return 0;
+ }
+
+ if (n < 0) {
+ return -1;
+ }
+
+ if (n > (size - c->offset)) {
+ n = size - c->offset;
+ }
+
+ off = fip->offset[c->qid] + c->offset;
+ if (devtab[cs.index]->seek(&cs, off, KSEEK_SET) < 0) {
+ return -1;
+ }
+
+ n = devtab[cs.index]->read(&cs, buf, n);
+ if (n > 0) {
+ c->offset += n;
+ }
+
+ return n;
+}
+
+/*******************************************************************************
+ * This function parses the FIP spec and registers its images in order to
+ * expose them as files in the driver namespace.
+ * It acts as an initialization function for the FIP driver.
+ * It returns a pointer to the newly created channel.
+ ******************************************************************************/
+static chan_t *fipmount(chan_t *c, const char *spec)
+{
+ int r, n, t;
+ chan_t *cspec;
+ uint32_t hname;
+ struct fip_entry entry;
+ struct fipfile *fip;
+ dir_t dir;
+
+ if (nfips == NR_FIPS) {
+ return NULL;
+ }
+
+ fip = &archives[nfips];
+
+ for (n = 0; n < NR_FILES; n++) {
+ fip->offset[n] = -1;
+ }
+
+ cspec = path_to_channel(spec, O_READ);
+ if (cspec == NULL) {
+ return NULL;
+ }
+
+ fip->c = cspec;
+
+ r = devtab[cspec->index]->read(cspec, &hname, sizeof(hname));
+ if (r < 0) {
+ goto err;
+ }
+
+ if ((r != sizeof(hname)) || (hname != TOC_HEADER_NAME)) {
+ goto err;
+ }
+
+ if (stat(spec, &dir) < 0) {
+ goto err;
+ }
+
+ t = cspec->index;
+ if (devtab[t]->seek(cspec, STOC_HEADER, KSEEK_SET) < 0) {
+ goto err;
+ }
+
+ for (n = 0; n < NR_FILES; n++) {
+ switch (get_entry(cspec, &entry)) {
+ case 0:
+ return attach('F', nfips++);
+ case -1:
+ goto err;
+ default:
+ if ((entry.offset_address + entry.size) > dir.length) {
+ goto err;
+ }
+
+ fip->offset[n] = entry.offset_address;
+ fip->size[n] = entry.size;
+ break;
+ }
+ }
+
+err:
+ channel_close(cspec);
+ return NULL;
+}
+
+const dev_t fipdevtab = {
+ .id = 'F',
+ .stat = fipstat,
+ .clone = devclone,
+ .attach = devattach,
+ .walk = fipwalk,
+ .read = fipread,
+ .write = deverrwrite,
+ .mount = fipmount,
+ .seek = devseek
+};
+
diff --git a/lib/debugfs/devroot.c b/lib/debugfs/devroot.c
new file mode 100644
index 0000000..9dd6c92
--- /dev/null
+++ b/lib/debugfs/devroot.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/debug.h>
+#include <lib/debugfs.h>
+
+#include "blobs.h"
+#include "dev.h"
+
+/*******************************************************************************
+ * This array contains the directories available from the root directory.
+ ******************************************************************************/
+static const dirtab_t dirtab[] = {
+ {"dev", CHDIR | DEV_ROOT_QDEV, 0, O_READ},
+ {"blobs", CHDIR | DEV_ROOT_QBLOBS, 0, O_READ},
+ {"fip", CHDIR | DEV_ROOT_QFIP, 0, O_READ}
+};
+
+static const dirtab_t devfstab[] = {
+};
+
+/*******************************************************************************
+ * This function exposes the elements of the root directory.
+ * It also exposes the content of the dev and blobs directories.
+ ******************************************************************************/
+static int rootgen(chan_t *channel, const dirtab_t *tab, int ntab,
+ int n, dir_t *dir)
+{
+ switch (channel->qid & ~CHDIR) {
+ case DEV_ROOT_QROOT:
+ tab = dirtab;
+ ntab = NELEM(dirtab);
+ break;
+ case DEV_ROOT_QDEV:
+ tab = devfstab;
+ ntab = NELEM(devfstab);
+ break;
+ case DEV_ROOT_QBLOBS:
+ tab = blobtab;
+ ntab = NELEM(blobtab);
+ break;
+ default:
+ return 0;
+ }
+
+ return devgen(channel, tab, ntab, n, dir);
+}
+
+static int rootwalk(chan_t *channel, const char *name)
+{
+ return devwalk(channel, name, NULL, 0, rootgen);
+}
+
+/*******************************************************************************
+ * This function copies at most n bytes from the element referred by c into buf.
+ ******************************************************************************/
+static int rootread(chan_t *channel, void *buf, int size)
+{
+ const dirtab_t *dp;
+ dir_t *dir;
+
+ if ((channel->qid & CHDIR) != 0) {
+ if (size < sizeof(dir_t)) {
+ return -1;
+ }
+
+ dir = buf;
+ return dirread(channel, dir, NULL, 0, rootgen);
+ }
+
+ /* Only makes sense when using debug language */
+ assert(channel->qid != DEV_ROOT_QBLOBCTL);
+
+ dp = &blobtab[channel->qid - DEV_ROOT_QBLOBCTL];
+ return buf_to_channel(channel, buf, dp->data, size, dp->length);
+}
+
+static int rootstat(chan_t *channel, const char *file, dir_t *dir)
+{
+ return devstat(channel, file, dir, NULL, 0, rootgen);
+}
+
+const dev_t rootdevtab = {
+ .id = '/',
+ .stat = rootstat,
+ .clone = devclone,
+ .attach = devattach,
+ .walk = rootwalk,
+ .read = rootread,
+ .write = deverrwrite,
+ .mount = deverrmount,
+ .seek = devseek
+};
diff --git a/lib/el3_runtime/aarch32/context_mgmt.c b/lib/el3_runtime/aarch32/context_mgmt.c
new file mode 100644
index 0000000..af8edf5
--- /dev/null
+++ b/lib/el3_runtime/aarch32/context_mgmt.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/extensions/amu.h>
+#include <lib/extensions/sys_reg_trace.h>
+#include <lib/extensions/trf.h>
+#include <lib/utils.h>
+
+/*******************************************************************************
+ * 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_el1_sysregs_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
+
+#if ENABLE_SYS_REG_TRACE_FOR_NS
+ sys_reg_trace_enable();
+#endif /* ENABLE_SYS_REG_TRACE_FOR_NS */
+
+#if ENABLE_TRF_FOR_NS
+ trf_enable();
+#endif /* ENABLE_TRF_FOR_NS */
+#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<n>[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);
+ }
+}
+
+/*******************************************************************************
+ * This function is used to exit to Non-secure world. It simply calls the
+ * cm_prepare_el3_exit function for AArch32.
+ ******************************************************************************/
+void cm_prepare_el3_exit_ns(void)
+{
+ cm_prepare_el3_exit(NON_SECURE);
+}
diff --git a/lib/el3_runtime/aarch32/cpu_data.S b/lib/el3_runtime/aarch32/cpu_data.S
new file mode 100644
index 0000000..bdad2c1
--- /dev/null
+++ b/lib/el3_runtime/aarch32/cpu_data.S
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <lib/el3_runtime/cpu_data.h>
+
+ .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
diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S
new file mode 100644
index 0000000..6b88a90
--- /dev/null
+++ b/lib/el3_runtime/aarch64/context.S
@@ -0,0 +1,1136 @@
+/*
+ * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <context.h>
+#include <el3_common_macros.S>
+
+#if CTX_INCLUDE_EL2_REGS
+ .global el2_sysregs_context_save_common
+ .global el2_sysregs_context_restore_common
+#if ENABLE_SPE_FOR_LOWER_ELS
+ .global el2_sysregs_context_save_spe
+ .global el2_sysregs_context_restore_spe
+#endif /* ENABLE_SPE_FOR_LOWER_ELS */
+#if CTX_INCLUDE_MTE_REGS
+ .global el2_sysregs_context_save_mte
+ .global el2_sysregs_context_restore_mte
+#endif /* CTX_INCLUDE_MTE_REGS */
+#if ENABLE_MPAM_FOR_LOWER_ELS
+ .global el2_sysregs_context_save_mpam
+ .global el2_sysregs_context_restore_mpam
+#endif /* ENABLE_MPAM_FOR_LOWER_ELS */
+#if ENABLE_FEAT_FGT
+ .global el2_sysregs_context_save_fgt
+ .global el2_sysregs_context_restore_fgt
+#endif /* ENABLE_FEAT_FGT */
+#if ENABLE_FEAT_ECV
+ .global el2_sysregs_context_save_ecv
+ .global el2_sysregs_context_restore_ecv
+#endif /* ENABLE_FEAT_ECV */
+#if ENABLE_FEAT_VHE
+ .global el2_sysregs_context_save_vhe
+ .global el2_sysregs_context_restore_vhe
+#endif /* ENABLE_FEAT_VHE */
+#if RAS_EXTENSION
+ .global el2_sysregs_context_save_ras
+ .global el2_sysregs_context_restore_ras
+#endif /* RAS_EXTENSION */
+#if CTX_INCLUDE_NEVE_REGS
+ .global el2_sysregs_context_save_nv2
+ .global el2_sysregs_context_restore_nv2
+#endif /* CTX_INCLUDE_NEVE_REGS */
+#if ENABLE_TRF_FOR_NS
+ .global el2_sysregs_context_save_trf
+ .global el2_sysregs_context_restore_trf
+#endif /* ENABLE_TRF_FOR_NS */
+#if ENABLE_FEAT_CSV2_2
+ .global el2_sysregs_context_save_csv2
+ .global el2_sysregs_context_restore_csv2
+#endif /* ENABLE_FEAT_CSV2_2 */
+#if ENABLE_FEAT_HCX
+ .global el2_sysregs_context_save_hcx
+ .global el2_sysregs_context_restore_hcx
+#endif /* ENABLE_FEAT_HCX */
+#endif /* CTX_INCLUDE_EL2_REGS */
+
+ .global el1_sysregs_context_save
+ .global el1_sysregs_context_restore
+#if CTX_INCLUDE_FPREGS
+ .global fpregs_context_save
+ .global fpregs_context_restore
+#endif /* CTX_INCLUDE_FPREGS */
+ .global prepare_el3_entry
+ .global restore_gp_pmcr_pauth_regs
+ .global save_and_update_ptw_el1_sys_regs
+ .global el3_exit
+
+#if CTX_INCLUDE_EL2_REGS
+
+/* -----------------------------------------------------
+ * The following functions strictly follow the AArch64
+ * PCS to use x9-x16 (temporary caller-saved registers)
+ * to save/restore EL2 system register context.
+ * el2_sysregs_context_save/restore_common functions
+ * save and restore registers that are common to all
+ * configurations. The rest of the functions save and
+ * restore EL2 system registers that are present when a
+ * particular feature is enabled. All functions assume
+ * that 'x0' is pointing to a 'el2_sys_regs' structure
+ * where the register context will be saved/restored.
+ *
+ * The following registers are not added.
+ * AMEVCNTVOFF0<n>_EL2
+ * AMEVCNTVOFF1<n>_EL2
+ * ICH_AP0R<n>_EL2
+ * ICH_AP1R<n>_EL2
+ * ICH_LR<n>_EL2
+ * -----------------------------------------------------
+ */
+func el2_sysregs_context_save_common
+ mrs x9, actlr_el2
+ mrs x10, afsr0_el2
+ stp x9, x10, [x0, #CTX_ACTLR_EL2]
+
+ mrs x11, afsr1_el2
+ mrs x12, amair_el2
+ stp x11, x12, [x0, #CTX_AFSR1_EL2]
+
+ mrs x13, cnthctl_el2
+ mrs x14, cntvoff_el2
+ stp x13, x14, [x0, #CTX_CNTHCTL_EL2]
+
+ mrs x15, cptr_el2
+ str x15, [x0, #CTX_CPTR_EL2]
+
+#if CTX_INCLUDE_AARCH32_REGS
+ mrs x16, dbgvcr32_el2
+ str x16, [x0, #CTX_DBGVCR32_EL2]
+#endif /* CTX_INCLUDE_AARCH32_REGS */
+
+ mrs x9, elr_el2
+ mrs x10, esr_el2
+ stp x9, x10, [x0, #CTX_ELR_EL2]
+
+ mrs x11, far_el2
+ mrs x12, hacr_el2
+ stp x11, x12, [x0, #CTX_FAR_EL2]
+
+ mrs x13, hcr_el2
+ mrs x14, hpfar_el2
+ stp x13, x14, [x0, #CTX_HCR_EL2]
+
+ mrs x15, hstr_el2
+ mrs x16, ICC_SRE_EL2
+ stp x15, x16, [x0, #CTX_HSTR_EL2]
+
+ mrs x9, ICH_HCR_EL2
+ mrs x10, ICH_VMCR_EL2
+ stp x9, x10, [x0, #CTX_ICH_HCR_EL2]
+
+ mrs x11, mair_el2
+ mrs x12, mdcr_el2
+ stp x11, x12, [x0, #CTX_MAIR_EL2]
+
+ mrs x14, sctlr_el2
+ str x14, [x0, #CTX_SCTLR_EL2]
+
+ mrs x15, spsr_el2
+ mrs x16, sp_el2
+ stp x15, x16, [x0, #CTX_SPSR_EL2]
+
+ mrs x9, tcr_el2
+ mrs x10, tpidr_el2
+ stp x9, x10, [x0, #CTX_TCR_EL2]
+
+ mrs x11, ttbr0_el2
+ mrs x12, vbar_el2
+ stp x11, x12, [x0, #CTX_TTBR0_EL2]
+
+ mrs x13, vmpidr_el2
+ mrs x14, vpidr_el2
+ stp x13, x14, [x0, #CTX_VMPIDR_EL2]
+
+ mrs x15, vtcr_el2
+ mrs x16, vttbr_el2
+ stp x15, x16, [x0, #CTX_VTCR_EL2]
+ ret
+endfunc el2_sysregs_context_save_common
+
+func el2_sysregs_context_restore_common
+ ldp x9, x10, [x0, #CTX_ACTLR_EL2]
+ msr actlr_el2, x9
+ msr afsr0_el2, x10
+
+ ldp x11, x12, [x0, #CTX_AFSR1_EL2]
+ msr afsr1_el2, x11
+ msr amair_el2, x12
+
+ ldp x13, x14, [x0, #CTX_CNTHCTL_EL2]
+ msr cnthctl_el2, x13
+ msr cntvoff_el2, x14
+
+ ldr x15, [x0, #CTX_CPTR_EL2]
+ msr cptr_el2, x15
+
+#if CTX_INCLUDE_AARCH32_REGS
+ ldr x16, [x0, #CTX_DBGVCR32_EL2]
+ msr dbgvcr32_el2, x16
+#endif /* CTX_INCLUDE_AARCH32_REGS */
+
+ ldp x9, x10, [x0, #CTX_ELR_EL2]
+ msr elr_el2, x9
+ msr esr_el2, x10
+
+ ldp x11, x12, [x0, #CTX_FAR_EL2]
+ msr far_el2, x11
+ msr hacr_el2, x12
+
+ ldp x13, x14, [x0, #CTX_HCR_EL2]
+ msr hcr_el2, x13
+ msr hpfar_el2, x14
+
+ ldp x15, x16, [x0, #CTX_HSTR_EL2]
+ msr hstr_el2, x15
+ msr ICC_SRE_EL2, x16
+
+ ldp x9, x10, [x0, #CTX_ICH_HCR_EL2]
+ msr ICH_HCR_EL2, x9
+ msr ICH_VMCR_EL2, x10
+
+ ldp x11, x12, [x0, #CTX_MAIR_EL2]
+ msr mair_el2, x11
+ msr mdcr_el2, x12
+
+ ldr x14, [x0, #CTX_SCTLR_EL2]
+ msr sctlr_el2, x14
+
+ ldp x15, x16, [x0, #CTX_SPSR_EL2]
+ msr spsr_el2, x15
+ msr sp_el2, x16
+
+ ldp x9, x10, [x0, #CTX_TCR_EL2]
+ msr tcr_el2, x9
+ msr tpidr_el2, x10
+
+ ldp x11, x12, [x0, #CTX_TTBR0_EL2]
+ msr ttbr0_el2, x11
+ msr vbar_el2, x12
+
+ ldp x13, x14, [x0, #CTX_VMPIDR_EL2]
+ msr vmpidr_el2, x13
+ msr vpidr_el2, x14
+
+ ldp x15, x16, [x0, #CTX_VTCR_EL2]
+ msr vtcr_el2, x15
+ msr vttbr_el2, x16
+ ret
+endfunc el2_sysregs_context_restore_common
+
+#if ENABLE_SPE_FOR_LOWER_ELS
+func el2_sysregs_context_save_spe
+ mrs x13, PMSCR_EL2
+ str x13, [x0, #CTX_PMSCR_EL2]
+ ret
+endfunc el2_sysregs_context_save_spe
+
+func el2_sysregs_context_restore_spe
+ ldr x13, [x0, #CTX_PMSCR_EL2]
+ msr PMSCR_EL2, x13
+ ret
+endfunc el2_sysregs_context_restore_spe
+#endif /* ENABLE_SPE_FOR_LOWER_ELS */
+
+#if CTX_INCLUDE_MTE_REGS
+func el2_sysregs_context_save_mte
+ mrs x9, TFSR_EL2
+ str x9, [x0, #CTX_TFSR_EL2]
+ ret
+endfunc el2_sysregs_context_save_mte
+
+func el2_sysregs_context_restore_mte
+ ldr x9, [x0, #CTX_TFSR_EL2]
+ msr TFSR_EL2, x9
+ ret
+endfunc el2_sysregs_context_restore_mte
+#endif /* CTX_INCLUDE_MTE_REGS */
+
+#if ENABLE_MPAM_FOR_LOWER_ELS
+func el2_sysregs_context_save_mpam
+ mrs x10, MPAM2_EL2
+ str x10, [x0, #CTX_MPAM2_EL2]
+
+ mrs x11, MPAMHCR_EL2
+ mrs x12, MPAMVPM0_EL2
+ stp x11, x12, [x0, #CTX_MPAMHCR_EL2]
+
+ mrs x13, MPAMVPM1_EL2
+ mrs x14, MPAMVPM2_EL2
+ stp x13, x14, [x0, #CTX_MPAMVPM1_EL2]
+
+ mrs x15, MPAMVPM3_EL2
+ mrs x16, MPAMVPM4_EL2
+ stp x15, x16, [x0, #CTX_MPAMVPM3_EL2]
+
+ mrs x9, MPAMVPM5_EL2
+ mrs x10, MPAMVPM6_EL2
+ stp x9, x10, [x0, #CTX_MPAMVPM5_EL2]
+
+ mrs x11, MPAMVPM7_EL2
+ mrs x12, MPAMVPMV_EL2
+ stp x11, x12, [x0, #CTX_MPAMVPM7_EL2]
+ ret
+endfunc func el2_sysregs_context_save_mpam
+
+func el2_sysregs_context_restore_mpam
+ ldr x10, [x0, #CTX_MPAM2_EL2]
+ msr MPAM2_EL2, x10
+
+ ldp x11, x12, [x0, #CTX_MPAMHCR_EL2]
+ msr MPAMHCR_EL2, x11
+ msr MPAMVPM0_EL2, x12
+
+ ldp x13, x14, [x0, #CTX_MPAMVPM1_EL2]
+ msr MPAMVPM1_EL2, x13
+ msr MPAMVPM2_EL2, x14
+
+ ldp x15, x16, [x0, #CTX_MPAMVPM3_EL2]
+ msr MPAMVPM3_EL2, x15
+ msr MPAMVPM4_EL2, x16
+
+ ldp x9, x10, [x0, #CTX_MPAMVPM5_EL2]
+ msr MPAMVPM5_EL2, x9
+ msr MPAMVPM6_EL2, x10
+
+ ldp x11, x12, [x0, #CTX_MPAMVPM7_EL2]
+ msr MPAMVPM7_EL2, x11
+ msr MPAMVPMV_EL2, x12
+ ret
+endfunc el2_sysregs_context_restore_mpam
+#endif /* ENABLE_MPAM_FOR_LOWER_ELS */
+
+#if ENABLE_FEAT_FGT
+func el2_sysregs_context_save_fgt
+ mrs x13, HDFGRTR_EL2
+#if ENABLE_FEAT_AMUv1
+ mrs x14, HAFGRTR_EL2
+ stp x13, x14, [x0, #CTX_HDFGRTR_EL2]
+#else
+ str x13, [x0, #CTX_HDFGRTR_EL2]
+#endif /* ENABLE_FEAT_AMUv1 */
+ mrs x15, HDFGWTR_EL2
+ mrs x16, HFGITR_EL2
+ stp x15, x16, [x0, #CTX_HDFGWTR_EL2]
+
+ mrs x9, HFGRTR_EL2
+ mrs x10, HFGWTR_EL2
+ stp x9, x10, [x0, #CTX_HFGRTR_EL2]
+ ret
+endfunc el2_sysregs_context_save_fgt
+
+func el2_sysregs_context_restore_fgt
+ #if ENABLE_FEAT_AMUv1
+ ldp x13, x14, [x0, #CTX_HDFGRTR_EL2]
+ msr HAFGRTR_EL2, x14
+#else
+ ldr x13, [x0, #CTX_HDFGRTR_EL2]
+#endif /* ENABLE_FEAT_AMUv1 */
+ msr HDFGRTR_EL2, x13
+
+ ldp x15, x16, [x0, #CTX_HDFGWTR_EL2]
+ msr HDFGWTR_EL2, x15
+ msr HFGITR_EL2, x16
+
+ ldp x9, x10, [x0, #CTX_HFGRTR_EL2]
+ msr HFGRTR_EL2, x9
+ msr HFGWTR_EL2, x10
+ ret
+endfunc el2_sysregs_context_restore_fgt
+#endif /* ENABLE_FEAT_FGT */
+
+#if ENABLE_FEAT_ECV
+func el2_sysregs_context_save_ecv
+ mrs x11, CNTPOFF_EL2
+ str x11, [x0, #CTX_CNTPOFF_EL2]
+ ret
+endfunc el2_sysregs_context_save_ecv
+
+func el2_sysregs_context_restore_ecv
+ ldr x11, [x0, #CTX_CNTPOFF_EL2]
+ msr CNTPOFF_EL2, x11
+ ret
+endfunc el2_sysregs_context_restore_ecv
+#endif /* ENABLE_FEAT_ECV */
+
+#if ENABLE_FEAT_VHE
+func el2_sysregs_context_save_vhe
+ /*
+ * CONTEXTIDR_EL2 register is saved only when FEAT_VHE or
+ * FEAT_Debugv8p2 (currently not in TF-A) is supported.
+ */
+ mrs x9, contextidr_el2
+ mrs x10, ttbr1_el2
+ stp x9, x10, [x0, #CTX_CONTEXTIDR_EL2]
+ ret
+endfunc el2_sysregs_context_save_vhe
+
+func el2_sysregs_context_restore_vhe
+ /*
+ * CONTEXTIDR_EL2 register is restored only when FEAT_VHE or
+ * FEAT_Debugv8p2 (currently not in TF-A) is supported.
+ */
+ ldp x9, x10, [x0, #CTX_CONTEXTIDR_EL2]
+ msr contextidr_el2, x9
+ msr ttbr1_el2, x10
+ ret
+endfunc el2_sysregs_context_restore_vhe
+#endif /* ENABLE_FEAT_VHE */
+
+#if RAS_EXTENSION
+func el2_sysregs_context_save_ras
+ /*
+ * VDISR_EL2 and VSESR_EL2 registers are saved only when
+ * FEAT_RAS is supported.
+ */
+ mrs x11, vdisr_el2
+ mrs x12, vsesr_el2
+ stp x11, x12, [x0, #CTX_VDISR_EL2]
+ ret
+endfunc el2_sysregs_context_save_ras
+
+func el2_sysregs_context_restore_ras
+ /*
+ * VDISR_EL2 and VSESR_EL2 registers are restored only when FEAT_RAS
+ * is supported.
+ */
+ ldp x11, x12, [x0, #CTX_VDISR_EL2]
+ msr vdisr_el2, x11
+ msr vsesr_el2, x12
+ ret
+endfunc el2_sysregs_context_restore_ras
+#endif /* RAS_EXTENSION */
+
+#if CTX_INCLUDE_NEVE_REGS
+func el2_sysregs_context_save_nv2
+ /*
+ * VNCR_EL2 register is saved only when FEAT_NV2 is supported.
+ */
+ mrs x16, vncr_el2
+ str x16, [x0, #CTX_VNCR_EL2]
+ ret
+endfunc el2_sysregs_context_save_nv2
+
+func el2_sysregs_context_restore_nv2
+ /*
+ * VNCR_EL2 register is restored only when FEAT_NV2 is supported.
+ */
+ ldr x16, [x0, #CTX_VNCR_EL2]
+ msr vncr_el2, x16
+ ret
+endfunc el2_sysregs_context_restore_nv2
+#endif /* CTX_INCLUDE_NEVE_REGS */
+
+#if ENABLE_TRF_FOR_NS
+func el2_sysregs_context_save_trf
+ /*
+ * TRFCR_EL2 register is saved only when FEAT_TRF is supported.
+ */
+ mrs x12, TRFCR_EL2
+ str x12, [x0, #CTX_TRFCR_EL2]
+ ret
+endfunc el2_sysregs_context_save_trf
+
+func el2_sysregs_context_restore_trf
+ /*
+ * TRFCR_EL2 register is restored only when FEAT_TRF is supported.
+ */
+ ldr x12, [x0, #CTX_TRFCR_EL2]
+ msr TRFCR_EL2, x12
+ ret
+endfunc el2_sysregs_context_restore_trf
+#endif /* ENABLE_TRF_FOR_NS */
+
+#if ENABLE_FEAT_CSV2_2
+func el2_sysregs_context_save_csv2
+ /*
+ * SCXTNUM_EL2 register is saved only when FEAT_CSV2_2 is supported.
+ */
+ mrs x13, scxtnum_el2
+ str x13, [x0, #CTX_SCXTNUM_EL2]
+ ret
+endfunc el2_sysregs_context_save_csv2
+
+func el2_sysregs_context_restore_csv2
+ /*
+ * SCXTNUM_EL2 register is restored only when FEAT_CSV2_2 is supported.
+ */
+ ldr x13, [x0, #CTX_SCXTNUM_EL2]
+ msr scxtnum_el2, x13
+ ret
+endfunc el2_sysregs_context_restore_csv2
+#endif /* ENABLE_FEAT_CSV2_2 */
+
+#if ENABLE_FEAT_HCX
+func el2_sysregs_context_save_hcx
+ mrs x14, hcrx_el2
+ str x14, [x0, #CTX_HCRX_EL2]
+ ret
+endfunc el2_sysregs_context_save_hcx
+
+func el2_sysregs_context_restore_hcx
+ ldr x14, [x0, #CTX_HCRX_EL2]
+ msr hcrx_el2, x14
+ ret
+endfunc el2_sysregs_context_restore_hcx
+#endif /* ENABLE_FEAT_HCX */
+#endif /* CTX_INCLUDE_EL2_REGS */
+
+/* ------------------------------------------------------------------
+ * 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]
+
+#if !ERRATA_SPECULATIVE_AT
+ mrs x15, sctlr_el1
+ mrs x16, tcr_el1
+ stp x15, x16, [x0, #CTX_SCTLR_EL1]
+#endif /* ERRATA_SPECULATIVE_AT */
+
+ 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, actlr_el1
+ mrs x17, tpidr_el1
+ stp x16, x17, [x0, #CTX_ACTLR_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 /* CTX_INCLUDE_AARCH32_REGS */
+
+ /* 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 /* NS_TIMER_SWITCH */
+
+ /* 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 /* CTX_INCLUDE_MTE_REGS */
+
+ 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
+
+#if !ERRATA_SPECULATIVE_AT
+ ldp x15, x16, [x0, #CTX_SCTLR_EL1]
+ msr sctlr_el1, x15
+ msr tcr_el1, x16
+#endif /* ERRATA_SPECULATIVE_AT */
+
+ 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_ACTLR_EL1]
+ msr actlr_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 /* CTX_INCLUDE_AARCH32_REGS */
+
+ /* 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 /* NS_TIMER_SWITCH */
+
+ /* 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 /* CTX_INCLUDE_MTE_REGS */
+
+ /* 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 /* CTX_INCLUDE_AARCH32_REGS */
+ 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 /* CTX_INCLUDE_AARCH32_REGS */
+
+ /*
+ * 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 */
+
+ /*
+ * Set the PSTATE bits not set when the exception was taken as
+ * described in the AArch64.TakeException() pseudocode function
+ * in ARM DDI 0487F.c page J1-7635 to a default value.
+ */
+ .macro set_unset_pstate_bits
+ /*
+ * If Data Independent Timing (DIT) functionality is implemented,
+ * always enable DIT in EL3
+ */
+#if ENABLE_FEAT_DIT
+ mov x8, #DIT_BIT
+ msr DIT, x8
+#endif /* ENABLE_FEAT_DIT */
+ .endm /* set_unset_pstate_bits */
+
+/* ------------------------------------------------------------------
+ * The following macro is used to save and restore all the general
+ * purpose and ARMv8.3-PAuth (if enabled) registers.
+ * It also checks if the Secure Cycle Counter (PMCCNTR_EL0)
+ * is disabled in EL3/Secure (ARMv8.5-PMU), wherein PMCCNTR_EL0
+ * needs not to be saved/restored during world switch.
+ *
+ * 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.
+ * clobbers: x18
+ * ------------------------------------------------------------------
+ */
+ .macro 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 of MDCR_EL3.SCCD/MCCD to 1
+ * has failed.
+ *
+ * MDCR_EL3:
+ * MCCD bit set, Prohibits the Cycle Counter PMCCNTR_EL0 from
+ * counting at EL3.
+ * SCCD bit set, Secure Cycle Counter Disable. Prohibits PMCCNTR_EL0
+ * from counting in Secure state.
+ * If these bits are not set, meaning that FEAT_PMUv3p5/7 is
+ * not implemented and PMCR_EL0 should be saved in non-secure
+ * context.
+ * ----------------------------------------------------------
+ */
+ mov_imm x10, (MDCR_SCCD_BIT | MDCR_MCCD_BIT)
+ mrs x9, mdcr_el3
+ tst x9, x10
+ bne 1f
+
+ /* ----------------------------------------------------------
+ * If control reaches here, it ensures the Secure Cycle
+ * Counter (PMCCNTR_EL0) is not prohibited from counting at
+ * EL3 and in secure states.
+ * Henceforth, PMCR_EL0 to be saved before world switch.
+ * ----------------------------------------------------------
+ */
+ 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 */
+ .endm /* save_gp_pmcr_pauth_regs */
+
+/* -----------------------------------------------------------------
+ * This function saves the context and sets the PSTATE to a known
+ * state, preparing entry to el3.
+ * Save all the general purpose and ARMv8.3-PAuth (if enabled)
+ * registers.
+ * Then set any of the PSTATE bits that are not set by hardware
+ * according to the Aarch64.TakeException pseudocode in the Arm
+ * Architecture Reference Manual to a default value for EL3.
+ * clobbers: x17
+ * -----------------------------------------------------------------
+ */
+func prepare_el3_entry
+ save_gp_pmcr_pauth_regs
+ /*
+ * Set the PSTATE bits not described in the Aarch64.TakeException
+ * pseudocode to their default values.
+ */
+ set_unset_pstate_bits
+ ret
+endfunc prepare_el3_entry
+
+/* ------------------------------------------------------------------
+ * 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/MCCD to 1
+ * failed, meaning that FEAT_PMUv3p5/7 is not implemented and
+ * PMCR_EL0 should be restored from non-secure context.
+ * ----------------------------------------------------------
+ */
+ mov_imm x1, (MDCR_SCCD_BIT | MDCR_MCCD_BIT)
+ mrs x0, mdcr_el3
+ tst x0, x1
+ 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
+
+/*
+ * In case of ERRATA_SPECULATIVE_AT, save SCTLR_EL1 and TCR_EL1
+ * registers and update EL1 registers to disable stage1 and stage2
+ * page table walk
+ */
+func save_and_update_ptw_el1_sys_regs
+ /* ----------------------------------------------------------
+ * Save only sctlr_el1 and tcr_el1 registers
+ * ----------------------------------------------------------
+ */
+ mrs x29, sctlr_el1
+ str x29, [sp, #(CTX_EL1_SYSREGS_OFFSET + CTX_SCTLR_EL1)]
+ mrs x29, tcr_el1
+ str x29, [sp, #(CTX_EL1_SYSREGS_OFFSET + CTX_TCR_EL1)]
+
+ /* ------------------------------------------------------------
+ * Must follow below order in order to disable page table
+ * walk for lower ELs (EL1 and EL0). First step ensures that
+ * page table walk is disabled for stage1 and second step
+ * ensures that page table walker should use TCR_EL1.EPDx
+ * bits to perform address translation. ISB ensures that CPU
+ * does these 2 steps in order.
+ *
+ * 1. Update TCR_EL1.EPDx bits to disable page table walk by
+ * stage1.
+ * 2. Enable MMU bit to avoid identity mapping via stage2
+ * and force TCR_EL1.EPDx to be used by the page table
+ * walker.
+ * ------------------------------------------------------------
+ */
+ orr x29, x29, #(TCR_EPD0_BIT)
+ orr x29, x29, #(TCR_EPD1_BIT)
+ msr tcr_el1, x29
+ isb
+ mrs x29, sctlr_el1
+ orr x29, x29, #SCTLR_M_BIT
+ msr sctlr_el1, x29
+ isb
+
+ ret
+endfunc save_and_update_ptw_el1_sys_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
+#if ENABLE_ASSERTIONS
+ /* el3_exit assumes SP_EL0 on entry */
+ mrs x17, spsel
+ cmp x17, #MODE_SP_EL0
+ ASM_ASSERT(eq)
+#endif /* ENABLE_ASSERTIONS */
+
+ /* ----------------------------------------------------------
+ * 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
+ /* ----------------------------------------------------------
+ * Restore CPTR_EL3.
+ * ZCR is only restored if SVE is supported and enabled.
+ * Synchronization is required before zcr_el3 is addressed.
+ * ----------------------------------------------------------
+ */
+ ldp x19, x20, [sp, #CTX_EL3STATE_OFFSET + CTX_CPTR_EL3]
+ msr cptr_el3, x19
+
+ ands x19, x19, #CPTR_EZ_BIT
+ beq sve_not_enabled
+
+ isb
+ msr S3_6_C1_C2_0, x20 /* zcr_el3 */
+sve_not_enabled:
+#endif /* IMAGE_BL31 */
+
+#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 /* IMAGE_BL31 && DYNAMIC_WORKAROUND_CVE_2018_3639 */
+
+ restore_ptw_el1_sys_regs
+
+ /* ----------------------------------------------------------
+ * 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
+#else
+ dsb sy
+#endif /* IMAGE_BL31 && RAS_EXTENSION */
+
+#ifdef IMAGE_BL31
+ str xzr, [sp, #CTX_EL3STATE_OFFSET + CTX_IS_IN_EL3]
+#endif /* IMAGE_BL31 */
+
+ exception_return
+
+endfunc el3_exit
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
new file mode 100644
index 0000000..866ac41
--- /dev/null
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -0,0 +1,1098 @@
+/*
+ * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <arch_features.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/el3_runtime/pubsub_events.h>
+#include <lib/extensions/amu.h>
+#include <lib/extensions/brbe.h>
+#include <lib/extensions/mpam.h>
+#include <lib/extensions/sme.h>
+#include <lib/extensions/spe.h>
+#include <lib/extensions/sve.h>
+#include <lib/extensions/sys_reg_trace.h>
+#include <lib/extensions/trbe.h>
+#include <lib/extensions/trf.h>
+#include <lib/utils.h>
+
+#if ENABLE_FEAT_TWED
+/* Make sure delay value fits within the range(0-15) */
+CASSERT(((TWED_DELAY & ~SCR_TWEDEL_MASK) == 0U), assert_twed_delay_value_check);
+#endif /* ENABLE_FEAT_TWED */
+
+static void manage_extensions_secure(cpu_context_t *ctx);
+
+static void setup_el1_context(cpu_context_t *ctx, const struct entry_point_info *ep)
+{
+ u_register_t sctlr_elx, actlr_elx;
+
+ /*
+ * Initialise SCTLR_EL1 to the reset value corresponding to the target
+ * execution state setting all fields rather than relying on 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 : 0UL;
+ 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 */
+ write_ctx_reg(get_el1_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_el1_sysregs_ctx(ctx)), (CTX_ACTLR_EL1), (actlr_elx));
+}
+
+/******************************************************************************
+ * This function performs initializations that are specific to SECURE state
+ * and updates the cpu context specified by 'ctx'.
+ *****************************************************************************/
+static void setup_secure_context(cpu_context_t *ctx, const struct entry_point_info *ep)
+{
+ u_register_t scr_el3;
+ el3_state_t *state;
+
+ state = get_el3state_ctx(ctx);
+ scr_el3 = read_ctx_reg(state, CTX_SCR_EL3);
+
+#if defined(IMAGE_BL31) && !defined(SPD_spmd)
+ /*
+ * 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(SECURE);
+#endif
+
+#if !CTX_INCLUDE_MTE_REGS || ENABLE_ASSERTIONS
+ /* Get Memory Tagging Extension support level */
+ unsigned int mte = get_armv8_5_mte_support();
+#endif
+ /*
+ * Allow access to Allocation Tags when CTX_INCLUDE_MTE_REGS
+ * is set, or when MTE is only implemented at EL0.
+ */
+#if CTX_INCLUDE_MTE_REGS
+ assert((mte == MTE_IMPLEMENTED_ELX) || (mte == MTE_IMPLEMENTED_ASY));
+ scr_el3 |= SCR_ATA_BIT;
+#else
+ if (mte == MTE_IMPLEMENTED_EL0) {
+ scr_el3 |= SCR_ATA_BIT;
+ }
+#endif /* CTX_INCLUDE_MTE_REGS */
+
+ /* Enable S-EL2 if the next EL is EL2 and S-EL2 is present */
+ if ((GET_EL(ep->spsr) == MODE_EL2) && is_armv8_4_sel2_present()) {
+ if (GET_RW(ep->spsr) != MODE_RW_64) {
+ ERROR("S-EL2 can not be used in AArch32\n.");
+ panic();
+ }
+
+ scr_el3 |= SCR_EEL2_BIT;
+ }
+
+ write_ctx_reg(state, CTX_SCR_EL3, scr_el3);
+
+ /*
+ * Initialize EL1 context registers unless SPMC is running
+ * at S-EL2.
+ */
+#if !SPMD_SPM_AT_SEL2
+ setup_el1_context(ctx, ep);
+#endif
+
+ manage_extensions_secure(ctx);
+}
+
+#if ENABLE_RME
+/******************************************************************************
+ * This function performs initializations that are specific to REALM state
+ * and updates the cpu context specified by 'ctx'.
+ *****************************************************************************/
+static void setup_realm_context(cpu_context_t *ctx, const struct entry_point_info *ep)
+{
+ u_register_t scr_el3;
+ el3_state_t *state;
+
+ state = get_el3state_ctx(ctx);
+ scr_el3 = read_ctx_reg(state, CTX_SCR_EL3);
+
+ scr_el3 |= SCR_NS_BIT | SCR_NSE_BIT | SCR_EnSCXT_BIT;
+
+ write_ctx_reg(state, CTX_SCR_EL3, scr_el3);
+}
+#endif /* ENABLE_RME */
+
+/******************************************************************************
+ * This function performs initializations that are specific to NON-SECURE state
+ * and updates the cpu context specified by 'ctx'.
+ *****************************************************************************/
+static void setup_ns_context(cpu_context_t *ctx, const struct entry_point_info *ep)
+{
+ u_register_t scr_el3;
+ el3_state_t *state;
+
+ state = get_el3state_ctx(ctx);
+ scr_el3 = read_ctx_reg(state, CTX_SCR_EL3);
+
+ /* SCR_NS: Set the NS bit */
+ scr_el3 |= SCR_NS_BIT;
+
+#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.
+ */
+ scr_el3 |= SCR_API_BIT | SCR_APK_BIT;
+#endif /* !CTX_INCLUDE_PAUTH_REGS */
+
+ /* Allow access to Allocation Tags when MTE is implemented. */
+ scr_el3 |= SCR_ATA_BIT;
+
+#if HANDLE_EA_EL3_FIRST_NS
+ /* SCR_EL3.EA: Route External Abort and SError Interrupt to EL3. */
+ scr_el3 |= SCR_EA_BIT;
+#endif
+
+#if RAS_TRAP_NS_ERR_REC_ACCESS
+ /*
+ * SCR_EL3.TERR: Trap Error record accesses. Accesses to the RAS ERR
+ * and RAS ERX registers from EL1 and EL2(from any security state)
+ * are trapped to EL3.
+ * Set here to trap only for NS EL1/EL2
+ *
+ */
+ scr_el3 |= SCR_TERR_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(NON_SECURE);
+#endif
+ write_ctx_reg(state, CTX_SCR_EL3, scr_el3);
+
+ /* Initialize EL1 context registers */
+ setup_el1_context(ctx, ep);
+
+ /* Initialize EL2 context registers */
+#if CTX_INCLUDE_EL2_REGS
+
+ /*
+ * Initialize SCTLR_EL2 context register using Endianness value
+ * taken from the entrypoint attribute.
+ */
+ u_register_t sctlr_el2 = (EP_GET_EE(ep->h.attr) != 0U) ? SCTLR_EE_BIT : 0UL;
+ sctlr_el2 |= SCTLR_EL2_RES1;
+ write_ctx_reg(get_el2_sysregs_ctx(ctx), CTX_SCTLR_EL2,
+ sctlr_el2);
+
+ /*
+ * Program the ICC_SRE_EL2 to make sure the correct bits are set
+ * when restoring NS context.
+ */
+ u_register_t icc_sre_el2 = ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT |
+ ICC_SRE_EN_BIT | ICC_SRE_SRE_BIT;
+ write_ctx_reg(get_el2_sysregs_ctx(ctx), CTX_ICC_SRE_EL2,
+ icc_sre_el2);
+
+ /*
+ * Initialize MDCR_EL2.HPMN to its hardware reset value so we don't
+ * throw anyone off who expects this to be sensible.
+ * TODO: A similar thing happens in cm_prepare_el3_exit. They should be
+ * unified with the proper PMU implementation
+ */
+ u_register_t mdcr_el2 = ((read_pmcr_el0() >> PMCR_EL0_N_SHIFT) &
+ PMCR_EL0_N_MASK);
+ write_ctx_reg(get_el2_sysregs_ctx(ctx), CTX_MDCR_EL2, mdcr_el2);
+#endif /* CTX_INCLUDE_EL2_REGS */
+}
+
+/*******************************************************************************
+ * The following function performs initialization of the cpu_context 'ctx'
+ * for first use that is common to all security states, and sets the
+ * initial entrypoint state as specified by the entry_point_info structure.
+ *
+ * The EE and ST attributes are used to configure the endianness and secure
+ * timer availability for the new execution context.
+ ******************************************************************************/
+static void setup_context_common(cpu_context_t *ctx, const entry_point_info_t *ep)
+{
+ u_register_t scr_el3;
+ el3_state_t *state;
+ gp_regs_t *gp_regs;
+
+ /* 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 = read_scr();
+ scr_el3 &= ~(SCR_NS_BIT | SCR_RW_BIT | SCR_EA_BIT | SCR_FIQ_BIT | SCR_IRQ_BIT |
+ SCR_ST_BIT | SCR_HCE_BIT | SCR_NSE_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 SEL2 is present and enabled, the ST
+ * bit always behaves as 1 (i.e. secure physical timer register access
+ * is not trapped)
+ */
+ if (EP_GET_ST(ep->h.attr) != 0U) {
+ scr_el3 |= SCR_ST_BIT;
+ }
+
+ /*
+ * If FEAT_HCX is enabled, enable access to HCRX_EL2 by setting
+ * SCR_EL3.HXEn.
+ */
+#if ENABLE_FEAT_HCX
+ scr_el3 |= SCR_HXEn_BIT;
+#endif
+
+ /*
+ * If FEAT_RNG_TRAP is enabled, all reads of the RNDR and RNDRRS
+ * registers are trapped to EL3.
+ */
+#if ENABLE_FEAT_RNG_TRAP
+ scr_el3 |= SCR_TRNDR_BIT;
+#endif
+
+#if FAULT_INJECTION_SUPPORT
+ /* Enable fault injection from lower ELs */
+ scr_el3 |= SCR_FIEN_BIT;
+#endif
+
+ /*
+ * CPTR_EL3 was initialized out of reset, copy that value to the
+ * context register.
+ */
+ write_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3, read_cptr_el3());
+
+ /*
+ * 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.
+ * SCR_EL3.FGTEn: Enable Fine Grained Virtualization Traps under the
+ * same conditions as HVC instructions and when the processor supports
+ * ARMv8.6-FGT.
+ * SCR_EL3.ECVEn: Enable Enhanced Counter Virtualization (ECV)
+ * CNTPOFF_EL2 register under the same conditions as HVC instructions
+ * and when the processor supports ECV.
+ */
+ 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;
+
+ if (is_armv8_6_fgt_present()) {
+ scr_el3 |= SCR_FGTEN_BIT;
+ }
+
+ if (get_armv8_6_ecv_support()
+ == ID_AA64MMFR0_EL1_ECV_SELF_SYNCH) {
+ scr_el3 |= SCR_ECVEN_BIT;
+ }
+ }
+
+#if ENABLE_FEAT_TWED
+ /* Enable WFE trap delay in SCR_EL3 if supported and configured */
+ /* Set delay in SCR_EL3 */
+ scr_el3 &= ~(SCR_TWEDEL_MASK << SCR_TWEDEL_SHIFT);
+ scr_el3 |= ((TWED_DELAY & SCR_TWEDEL_MASK)
+ << SCR_TWEDEL_SHIFT);
+
+ /* Enable WFE delay */
+ scr_el3 |= SCR_TWEDEn_BIT;
+#endif /* ENABLE_FEAT_TWED */
+
+ /*
+ * 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));
+}
+
+/*******************************************************************************
+ * Context management library initialization routine. This library is used by
+ * runtime services to share pointers to 'cpu_context' structures for secure
+ * non-secure and realm 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 be used for programming an entry into a lower EL. The same context
+ * will be 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.
+ */
+}
+
+/*******************************************************************************
+ * This is the high-level function used to initialize the cpu_context 'ctx' for
+ * first use. It performs initializations that are common to all security states
+ * and initializations specific to the security state specified in 'ep'
+ ******************************************************************************/
+void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep)
+{
+ unsigned int security_state;
+
+ assert(ctx != NULL);
+
+ /*
+ * Perform initializations that are common
+ * to all security states
+ */
+ setup_context_common(ctx, ep);
+
+ security_state = GET_SECURITY_STATE(ep->h.attr);
+
+ /* Perform security state specific initializations */
+ switch (security_state) {
+ case SECURE:
+ setup_secure_context(ctx, ep);
+ break;
+#if ENABLE_RME
+ case REALM:
+ setup_realm_context(ctx, ep);
+ break;
+#endif
+ case NON_SECURE:
+ setup_ns_context(ctx, ep);
+ break;
+ default:
+ ERROR("Invalid security state\n");
+ panic();
+ break;
+ }
+}
+
+/*******************************************************************************
+ * 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 manage_extensions_nonsecure(bool el2_unused, cpu_context_t *ctx)
+{
+#if IMAGE_BL31
+#if ENABLE_SPE_FOR_LOWER_ELS
+ spe_enable(el2_unused);
+#endif
+
+#if ENABLE_AMU
+ amu_enable(el2_unused, ctx);
+#endif
+
+#if ENABLE_SME_FOR_NS
+ /* Enable SME, SVE, and FPU/SIMD for non-secure world. */
+ sme_enable(ctx);
+#elif ENABLE_SVE_FOR_NS
+ /* Enable SVE and FPU/SIMD for non-secure world. */
+ sve_enable(ctx);
+#endif
+
+#if ENABLE_MPAM_FOR_LOWER_ELS
+ mpam_enable(el2_unused);
+#endif
+
+#if ENABLE_TRBE_FOR_NS
+ trbe_enable();
+#endif /* ENABLE_TRBE_FOR_NS */
+
+#if ENABLE_BRBE_FOR_NS
+ brbe_enable();
+#endif /* ENABLE_BRBE_FOR_NS */
+
+#if ENABLE_SYS_REG_TRACE_FOR_NS
+ sys_reg_trace_enable(ctx);
+#endif /* ENABLE_SYS_REG_TRACE_FOR_NS */
+
+#if ENABLE_TRF_FOR_NS
+ trf_enable();
+#endif /* ENABLE_TRF_FOR_NS */
+#endif
+}
+
+/*******************************************************************************
+ * Enable architecture extensions on first entry to Secure world.
+ ******************************************************************************/
+static void manage_extensions_secure(cpu_context_t *ctx)
+{
+#if IMAGE_BL31
+ #if ENABLE_SME_FOR_NS
+ #if ENABLE_SME_FOR_SWD
+ /*
+ * Enable SME, SVE, FPU/SIMD in secure context, secure manager must
+ * ensure SME, SVE, and FPU/SIMD context properly managed.
+ */
+ sme_enable(ctx);
+ #else /* ENABLE_SME_FOR_SWD */
+ /*
+ * Disable SME, SVE, FPU/SIMD in secure context so non-secure world can
+ * safely use the associated registers.
+ */
+ sme_disable(ctx);
+ #endif /* ENABLE_SME_FOR_SWD */
+ #elif ENABLE_SVE_FOR_NS
+ #if ENABLE_SVE_FOR_SWD
+ /*
+ * Enable SVE and FPU in secure context, secure manager must ensure that
+ * the SVE and FPU register contexts are properly managed.
+ */
+ sve_enable(ctx);
+ #else /* ENABLE_SVE_FOR_SWD */
+ /*
+ * Disable SVE and FPU in secure context so non-secure world can safely
+ * use them.
+ */
+ sve_disable(ctx);
+ #endif /* ENABLE_SVE_FOR_SWD */
+ #endif /* ENABLE_SVE_FOR_NS */
+#endif /* IMAGE_BL31 */
+}
+
+/*******************************************************************************
+ * 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 realm, 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)
+{
+ u_register_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 = 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 = read_ctx_reg(get_el1_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.
+ * If PE trace unit System registers are not implemented
+ * then this bit is reserved, and must be set to zero.
+ *
+ * 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.EL1PTEN: 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<n>_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.E2TB: Set to zero so that the trace Buffer
+ * owning exception level is NS-EL1 and, tracing is
+ * prohibited at NS-EL2. These bits are RES0 when
+ * FEAT_TRBE is not implemented.
+ */
+ 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 |
+ MDCR_EL2_E2TB(MDCR_EL2_E2TB_EL1));
+
+ write_mdcr_el2(mdcr_el2);
+
+ /*
+ * Initialise HSTR_EL2. All fields are architecturally
+ * UNKNOWN on reset.
+ *
+ * HSTR_EL2.T<n>: 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));
+ }
+ manage_extensions_nonsecure(el2_unused, ctx);
+ }
+
+ cm_el1_sysregs_context_restore(security_state);
+ cm_set_next_eret_context(security_state);
+}
+
+#if CTX_INCLUDE_EL2_REGS
+/*******************************************************************************
+ * Save EL2 sysreg context
+ ******************************************************************************/
+void cm_el2_sysregs_context_save(uint32_t security_state)
+{
+ u_register_t scr_el3 = read_scr();
+
+ /*
+ * Always save the non-secure and realm EL2 context, only save the
+ * S-EL2 context if S-EL2 is enabled.
+ */
+ if ((security_state != SECURE) ||
+ ((security_state == SECURE) && ((scr_el3 & SCR_EEL2_BIT) != 0U))) {
+ cpu_context_t *ctx;
+ el2_sysregs_t *el2_sysregs_ctx;
+
+ ctx = cm_get_context(security_state);
+ assert(ctx != NULL);
+
+ el2_sysregs_ctx = get_el2_sysregs_ctx(ctx);
+
+ el2_sysregs_context_save_common(el2_sysregs_ctx);
+#if ENABLE_SPE_FOR_LOWER_ELS
+ el2_sysregs_context_save_spe(el2_sysregs_ctx);
+#endif
+#if CTX_INCLUDE_MTE_REGS
+ el2_sysregs_context_save_mte(el2_sysregs_ctx);
+#endif
+#if ENABLE_MPAM_FOR_LOWER_ELS
+ el2_sysregs_context_save_mpam(el2_sysregs_ctx);
+#endif
+#if ENABLE_FEAT_FGT
+ el2_sysregs_context_save_fgt(el2_sysregs_ctx);
+#endif
+#if ENABLE_FEAT_ECV
+ el2_sysregs_context_save_ecv(el2_sysregs_ctx);
+#endif
+#if ENABLE_FEAT_VHE
+ el2_sysregs_context_save_vhe(el2_sysregs_ctx);
+#endif
+#if RAS_EXTENSION
+ el2_sysregs_context_save_ras(el2_sysregs_ctx);
+#endif
+#if CTX_INCLUDE_NEVE_REGS
+ el2_sysregs_context_save_nv2(el2_sysregs_ctx);
+#endif
+#if ENABLE_TRF_FOR_NS
+ el2_sysregs_context_save_trf(el2_sysregs_ctx);
+#endif
+#if ENABLE_FEAT_CSV2_2
+ el2_sysregs_context_save_csv2(el2_sysregs_ctx);
+#endif
+#if ENABLE_FEAT_HCX
+ el2_sysregs_context_save_hcx(el2_sysregs_ctx);
+#endif
+ }
+}
+
+/*******************************************************************************
+ * Restore EL2 sysreg context
+ ******************************************************************************/
+void cm_el2_sysregs_context_restore(uint32_t security_state)
+{
+ u_register_t scr_el3 = read_scr();
+
+ /*
+ * Always restore the non-secure and realm EL2 context, only restore the
+ * S-EL2 context if S-EL2 is enabled.
+ */
+ if ((security_state != SECURE) ||
+ ((security_state == SECURE) && ((scr_el3 & SCR_EEL2_BIT) != 0U))) {
+ cpu_context_t *ctx;
+ el2_sysregs_t *el2_sysregs_ctx;
+
+ ctx = cm_get_context(security_state);
+ assert(ctx != NULL);
+
+ el2_sysregs_ctx = get_el2_sysregs_ctx(ctx);
+
+ el2_sysregs_context_restore_common(el2_sysregs_ctx);
+#if ENABLE_SPE_FOR_LOWER_ELS
+ el2_sysregs_context_restore_spe(el2_sysregs_ctx);
+#endif
+#if CTX_INCLUDE_MTE_REGS
+ el2_sysregs_context_restore_mte(el2_sysregs_ctx);
+#endif
+#if ENABLE_MPAM_FOR_LOWER_ELS
+ el2_sysregs_context_restore_mpam(el2_sysregs_ctx);
+#endif
+#if ENABLE_FEAT_FGT
+ el2_sysregs_context_restore_fgt(el2_sysregs_ctx);
+#endif
+#if ENABLE_FEAT_ECV
+ el2_sysregs_context_restore_ecv(el2_sysregs_ctx);
+#endif
+#if ENABLE_FEAT_VHE
+ el2_sysregs_context_restore_vhe(el2_sysregs_ctx);
+#endif
+#if RAS_EXTENSION
+ el2_sysregs_context_restore_ras(el2_sysregs_ctx);
+#endif
+#if CTX_INCLUDE_NEVE_REGS
+ el2_sysregs_context_restore_nv2(el2_sysregs_ctx);
+#endif
+#if ENABLE_TRF_FOR_NS
+ el2_sysregs_context_restore_trf(el2_sysregs_ctx);
+#endif
+#if ENABLE_FEAT_CSV2_2
+ el2_sysregs_context_restore_csv2(el2_sysregs_ctx);
+#endif
+#if ENABLE_FEAT_HCX
+ el2_sysregs_context_restore_hcx(el2_sysregs_ctx);
+#endif
+ }
+}
+#endif /* CTX_INCLUDE_EL2_REGS */
+
+/*******************************************************************************
+ * This function is used to exit to Non-secure world. If CTX_INCLUDE_EL2_REGS
+ * is enabled, it restores EL1 and EL2 sysreg contexts instead of directly
+ * updating EL1 and EL2 registers. Otherwise, it calls the generic
+ * cm_prepare_el3_exit function.
+ ******************************************************************************/
+void cm_prepare_el3_exit_ns(void)
+{
+#if CTX_INCLUDE_EL2_REGS
+ cpu_context_t *ctx = cm_get_context(NON_SECURE);
+ assert(ctx != NULL);
+
+ /* Assert that EL2 is used. */
+#if ENABLE_ASSERTIONS
+ el3_state_t *state = get_el3state_ctx(ctx);
+ u_register_t scr_el3 = read_ctx_reg(state, CTX_SCR_EL3);
+#endif
+ assert(((scr_el3 & SCR_HCE_BIT) != 0UL) &&
+ (el_implemented(2U) != EL_IMPL_NONE));
+
+ /*
+ * Currently some extensions are configured using
+ * direct register updates. Therefore, do this here
+ * instead of when setting up context.
+ */
+ manage_extensions_nonsecure(0, ctx);
+
+ /*
+ * Set the NS bit to be able to access the ICC_SRE_EL2
+ * register when restoring context.
+ */
+ write_scr_el3(read_scr_el3() | SCR_NS_BIT);
+
+ /*
+ * Ensure the NS bit change is committed before the EL2/EL1
+ * state restoration.
+ */
+ isb();
+
+ /* Restore EL2 and EL1 sysreg contexts */
+ cm_el2_sysregs_context_restore(NON_SECURE);
+ cm_el1_sysregs_context_restore(NON_SECURE);
+ cm_set_next_eret_context(NON_SECURE);
+#else
+ cm_prepare_el3_exit(NON_SECURE);
+#endif /* CTX_INCLUDE_EL2_REGS */
+}
+
+/*******************************************************************************
+ * 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_el1_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_el1_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;
+ u_register_t scr_el3;
+
+ ctx = cm_get_context(security_state);
+ assert(ctx != NULL);
+
+ /* Ensure that the bit position is a valid one */
+ assert(((1UL << 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 = read_ctx_reg(state, CTX_SCR_EL3);
+ scr_el3 &= ~(1UL << bit_pos);
+ scr_el3 |= (u_register_t)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.
+ ******************************************************************************/
+u_register_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 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);
+}
diff --git a/lib/el3_runtime/aarch64/cpu_data.S b/lib/el3_runtime/aarch64/cpu_data.S
new file mode 100644
index 0000000..2392d6b
--- /dev/null
+++ b/lib/el3_runtime/aarch64/cpu_data.S
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <lib/el3_runtime/cpu_data.h>
+
+.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
+ adrp x1, percpu_data
+ add x1, x1, :lo12:percpu_data
+ add x0, x0, x1
+ ret
+endfunc _cpu_data_by_index
diff --git a/lib/el3_runtime/cpu_data_array.c b/lib/el3_runtime/cpu_data_array.c
new file mode 100644
index 0000000..13d464c
--- /dev/null
+++ b/lib/el3_runtime/cpu_data_array.c
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <lib/cassert.h>
+#include <lib/el3_runtime/cpu_data.h>
+
+/* The per_cpu_ptr_cache_t space allocation */
+cpu_data_t percpu_data[PLATFORM_CORE_COUNT];
diff --git a/lib/extensions/amu/aarch32/amu.c b/lib/extensions/amu/aarch32/amu.c
new file mode 100644
index 0000000..57b1158
--- /dev/null
+++ b/lib/extensions/amu/aarch32/amu.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <cdefs.h>
+#include <stdbool.h>
+
+#include "../amu_private.h"
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/pubsub_events.h>
+#include <lib/extensions/amu.h>
+
+#include <plat/common/platform.h>
+
+struct amu_ctx {
+ uint64_t group0_cnts[AMU_GROUP0_MAX_COUNTERS];
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ uint64_t group1_cnts[AMU_GROUP1_MAX_COUNTERS];
+#endif
+
+ uint16_t group0_enable;
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ uint16_t group1_enable;
+#endif
+};
+
+static struct amu_ctx amu_ctxs_[PLATFORM_CORE_COUNT];
+
+CASSERT((sizeof(amu_ctxs_[0].group0_enable) * CHAR_BIT) <= AMU_GROUP0_MAX_COUNTERS,
+ amu_ctx_group0_enable_cannot_represent_all_group0_counters);
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+CASSERT((sizeof(amu_ctxs_[0].group1_enable) * CHAR_BIT) <= AMU_GROUP1_MAX_COUNTERS,
+ amu_ctx_group1_enable_cannot_represent_all_group1_counters);
+#endif
+
+static inline __unused uint32_t read_id_pfr0_amu(void)
+{
+ return (read_id_pfr0() >> ID_PFR0_AMU_SHIFT) &
+ ID_PFR0_AMU_MASK;
+}
+
+static inline __unused void write_hcptr_tam(uint32_t value)
+{
+ write_hcptr((read_hcptr() & ~TAM_BIT) |
+ ((value << TAM_SHIFT) & TAM_BIT));
+}
+
+static inline __unused void write_amcr_cg1rz(uint32_t value)
+{
+ write_amcr((read_amcr() & ~AMCR_CG1RZ_BIT) |
+ ((value << AMCR_CG1RZ_SHIFT) & AMCR_CG1RZ_BIT));
+}
+
+static inline __unused uint32_t read_amcfgr_ncg(void)
+{
+ return (read_amcfgr() >> AMCFGR_NCG_SHIFT) &
+ AMCFGR_NCG_MASK;
+}
+
+static inline __unused uint32_t read_amcgcr_cg0nc(void)
+{
+ return (read_amcgcr() >> AMCGCR_CG0NC_SHIFT) &
+ AMCGCR_CG0NC_MASK;
+}
+
+static inline __unused uint32_t read_amcgcr_cg1nc(void)
+{
+ return (read_amcgcr() >> AMCGCR_CG1NC_SHIFT) &
+ AMCGCR_CG1NC_MASK;
+}
+
+static inline __unused uint32_t read_amcntenset0_px(void)
+{
+ return (read_amcntenset0() >> AMCNTENSET0_Pn_SHIFT) &
+ AMCNTENSET0_Pn_MASK;
+}
+
+static inline __unused uint32_t read_amcntenset1_px(void)
+{
+ return (read_amcntenset1() >> AMCNTENSET1_Pn_SHIFT) &
+ AMCNTENSET1_Pn_MASK;
+}
+
+static inline __unused void write_amcntenset0_px(uint32_t px)
+{
+ uint32_t value = read_amcntenset0();
+
+ value &= ~AMCNTENSET0_Pn_MASK;
+ value |= (px << AMCNTENSET0_Pn_SHIFT) &
+ AMCNTENSET0_Pn_MASK;
+
+ write_amcntenset0(value);
+}
+
+static inline __unused void write_amcntenset1_px(uint32_t px)
+{
+ uint32_t value = read_amcntenset1();
+
+ value &= ~AMCNTENSET1_Pn_MASK;
+ value |= (px << AMCNTENSET1_Pn_SHIFT) &
+ AMCNTENSET1_Pn_MASK;
+
+ write_amcntenset1(value);
+}
+
+static inline __unused void write_amcntenclr0_px(uint32_t px)
+{
+ uint32_t value = read_amcntenclr0();
+
+ value &= ~AMCNTENCLR0_Pn_MASK;
+ value |= (px << AMCNTENCLR0_Pn_SHIFT) & AMCNTENCLR0_Pn_MASK;
+
+ write_amcntenclr0(value);
+}
+
+static inline __unused void write_amcntenclr1_px(uint32_t px)
+{
+ uint32_t value = read_amcntenclr1();
+
+ value &= ~AMCNTENCLR1_Pn_MASK;
+ value |= (px << AMCNTENCLR1_Pn_SHIFT) & AMCNTENCLR1_Pn_MASK;
+
+ write_amcntenclr1(value);
+}
+
+static __unused bool amu_supported(void)
+{
+ return read_id_pfr0_amu() >= ID_PFR0_AMU_V1;
+}
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+static __unused bool amu_group1_supported(void)
+{
+ return read_amcfgr_ncg() > 0U;
+}
+#endif
+
+/*
+ * Enable counters. This function is meant to be invoked by the context
+ * management library before exiting from EL3.
+ */
+void amu_enable(bool el2_unused)
+{
+ uint32_t id_pfr0_amu; /* AMU version */
+
+ uint32_t amcfgr_ncg; /* Number of counter groups */
+ uint32_t amcgcr_cg0nc; /* Number of group 0 counters */
+
+ uint32_t amcntenset0_px = 0x0; /* Group 0 enable mask */
+ uint32_t amcntenset1_px = 0x0; /* Group 1 enable mask */
+
+ id_pfr0_amu = read_id_pfr0_amu();
+ if (id_pfr0_amu == ID_PFR0_AMU_NOT_SUPPORTED) {
+ /*
+ * If the AMU is unsupported, nothing needs to be done.
+ */
+
+ return;
+ }
+
+ if (el2_unused) {
+ /*
+ * HCPTR.TAM: Set to zero so any accesses to the Activity
+ * Monitor registers do not trap to EL2.
+ */
+ write_hcptr_tam(0U);
+ }
+
+ /*
+ * Retrieve the number of architected counters. All of these counters
+ * are enabled by default.
+ */
+
+ amcgcr_cg0nc = read_amcgcr_cg0nc();
+ amcntenset0_px = (UINT32_C(1) << (amcgcr_cg0nc)) - 1U;
+
+ assert(amcgcr_cg0nc <= AMU_AMCGCR_CG0NC_MAX);
+
+ /*
+ * The platform may opt to enable specific auxiliary counters. This can
+ * be done via the common FCONF getter, or via the platform-implemented
+ * function.
+ */
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ const struct amu_topology *topology;
+
+#if ENABLE_AMU_FCONF
+ topology = FCONF_GET_PROPERTY(amu, config, topology);
+#else
+ topology = plat_amu_topology();
+#endif /* ENABLE_AMU_FCONF */
+
+ if (topology != NULL) {
+ unsigned int core_pos = plat_my_core_pos();
+
+ amcntenset1_el0_px = topology->cores[core_pos].enable;
+ } else {
+ ERROR("AMU: failed to generate AMU topology\n");
+ }
+#endif /* ENABLE_AMU_AUXILIARY_COUNTERS */
+
+ /*
+ * Enable the requested counters.
+ */
+
+ write_amcntenset0_px(amcntenset0_px);
+
+ amcfgr_ncg = read_amcfgr_ncg();
+ if (amcfgr_ncg > 0U) {
+ write_amcntenset1_px(amcntenset1_px);
+
+#if !ENABLE_AMU_AUXILIARY_COUNTERS
+ VERBOSE("AMU: auxiliary counters detected but support is disabled\n");
+#endif
+ }
+
+ /* Initialize FEAT_AMUv1p1 features if present. */
+ if (id_pfr0_amu < ID_PFR0_AMU_V1P1) {
+ return;
+ }
+
+#if AMU_RESTRICT_COUNTERS
+ /*
+ * FEAT_AMUv1p1 adds a register field to restrict access to group 1
+ * counters at all but the highest implemented EL. This is controlled
+ * with the AMU_RESTRICT_COUNTERS compile time flag, when set, system
+ * register reads at lower ELs return zero. Reads from the memory
+ * mapped view are unaffected.
+ */
+ VERBOSE("AMU group 1 counter access restricted.\n");
+ write_amcr_cg1rz(1U);
+#else
+ write_amcr_cg1rz(0U);
+#endif
+}
+
+/* Read the group 0 counter identified by the given `idx`. */
+static uint64_t amu_group0_cnt_read(unsigned int idx)
+{
+ assert(amu_supported());
+ assert(idx < read_amcgcr_cg0nc());
+
+ return amu_group0_cnt_read_internal(idx);
+}
+
+/* Write the group 0 counter identified by the given `idx` with `val` */
+static void amu_group0_cnt_write(unsigned int idx, uint64_t val)
+{
+ assert(amu_supported());
+ assert(idx < read_amcgcr_cg0nc());
+
+ amu_group0_cnt_write_internal(idx, val);
+ isb();
+}
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+/* Read the group 1 counter identified by the given `idx` */
+static uint64_t amu_group1_cnt_read(unsigned int idx)
+{
+ assert(amu_supported());
+ assert(amu_group1_supported());
+ assert(idx < read_amcgcr_cg1nc());
+
+ return amu_group1_cnt_read_internal(idx);
+}
+
+/* Write the group 1 counter identified by the given `idx` with `val` */
+static void amu_group1_cnt_write(unsigned int idx, uint64_t val)
+{
+ assert(amu_supported());
+ assert(amu_group1_supported());
+ assert(idx < read_amcgcr_cg1nc());
+
+ amu_group1_cnt_write_internal(idx, val);
+ isb();
+}
+#endif
+
+static void *amu_context_save(const void *arg)
+{
+ uint32_t i;
+
+ unsigned int core_pos;
+ struct amu_ctx *ctx;
+
+ uint32_t id_pfr0_amu; /* AMU version */
+ uint32_t amcgcr_cg0nc; /* Number of group 0 counters */
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ uint32_t amcfgr_ncg; /* Number of counter groups */
+ uint32_t amcgcr_cg1nc; /* Number of group 1 counters */
+#endif
+
+ id_pfr0_amu = read_id_pfr0_amu();
+ if (id_pfr0_amu == ID_PFR0_AMU_NOT_SUPPORTED) {
+ return (void *)0;
+ }
+
+ core_pos = plat_my_core_pos();
+ ctx = &amu_ctxs_[core_pos];
+
+ amcgcr_cg0nc = read_amcgcr_cg0nc();
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ amcfgr_ncg = read_amcfgr_ncg();
+ amcgcr_cg1nc = (amcfgr_ncg > 0U) ? read_amcgcr_cg1nc() : 0U;
+#endif
+
+ /*
+ * Disable all AMU counters.
+ */
+
+ ctx->group0_enable = read_amcntenset0_px();
+ write_amcntenclr0_px(ctx->group0_enable);
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ if (amcfgr_ncg > 0U) {
+ ctx->group1_enable = read_amcntenset1_px();
+ write_amcntenclr1_px(ctx->group1_enable);
+ }
+#endif
+
+ /*
+ * Save the counters to the local context.
+ */
+
+ isb(); /* Ensure counters have been stopped */
+
+ for (i = 0U; i < amcgcr_cg0nc; i++) {
+ ctx->group0_cnts[i] = amu_group0_cnt_read(i);
+ }
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ for (i = 0U; i < amcgcr_cg1nc; i++) {
+ ctx->group1_cnts[i] = amu_group1_cnt_read(i);
+ }
+#endif
+
+ return (void *)0;
+}
+
+static void *amu_context_restore(const void *arg)
+{
+ uint32_t i;
+
+ unsigned int core_pos;
+ struct amu_ctx *ctx;
+
+ uint32_t id_pfr0_amu; /* AMU version */
+
+ uint32_t amcfgr_ncg; /* Number of counter groups */
+ uint32_t amcgcr_cg0nc; /* Number of group 0 counters */
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ uint32_t amcgcr_cg1nc; /* Number of group 1 counters */
+#endif
+
+ id_pfr0_amu = read_id_pfr0_amu();
+ if (id_pfr0_amu == ID_PFR0_AMU_NOT_SUPPORTED) {
+ return (void *)0;
+ }
+
+ core_pos = plat_my_core_pos();
+ ctx = &amu_ctxs_[core_pos];
+
+ amcfgr_ncg = read_amcfgr_ncg();
+ amcgcr_cg0nc = read_amcgcr_cg0nc();
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ amcgcr_cg1nc = (amcfgr_ncg > 0U) ? read_amcgcr_cg1nc() : 0U;
+#endif
+
+ /*
+ * Sanity check that all counters were disabled when the context was
+ * previously saved.
+ */
+
+ assert(read_amcntenset0_px() == 0U);
+
+ if (amcfgr_ncg > 0U) {
+ assert(read_amcntenset1_px() == 0U);
+ }
+
+ /*
+ * Restore the counter values from the local context.
+ */
+
+ for (i = 0U; i < amcgcr_cg0nc; i++) {
+ amu_group0_cnt_write(i, ctx->group0_cnts[i]);
+ }
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ for (i = 0U; i < amcgcr_cg1nc; i++) {
+ amu_group1_cnt_write(i, ctx->group1_cnts[i]);
+ }
+#endif
+
+ /*
+ * Re-enable counters that were disabled during context save.
+ */
+
+ write_amcntenset0_px(ctx->group0_enable);
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ if (amcfgr_ncg > 0U) {
+ write_amcntenset1_px(ctx->group1_enable);
+ }
+#endif
+
+ return (void *)0;
+}
+
+SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save);
+SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore);
diff --git a/lib/extensions/amu/aarch32/amu_helpers.S b/lib/extensions/amu/aarch32/amu_helpers.S
new file mode 100644
index 0000000..8ac7678
--- /dev/null
+++ b/lib/extensions/amu/aarch32/amu_helpers.S
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <assert_macros.S>
+#include <asm_macros.S>
+
+ .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
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+/*
+ * 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
+#endif
diff --git a/lib/extensions/amu/aarch64/amu.c b/lib/extensions/amu/aarch64/amu.c
new file mode 100644
index 0000000..72566fd
--- /dev/null
+++ b/lib/extensions/amu/aarch64/amu.c
@@ -0,0 +1,655 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <cdefs.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "../amu_private.h"
+#include <arch.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/pubsub_events.h>
+#include <lib/extensions/amu.h>
+
+#include <plat/common/platform.h>
+
+#if ENABLE_AMU_FCONF
+# include <lib/fconf/fconf.h>
+# include <lib/fconf/fconf_amu_getter.h>
+#endif
+
+#if ENABLE_MPMM
+# include <lib/mpmm/mpmm.h>
+#endif
+
+struct amu_ctx {
+ uint64_t group0_cnts[AMU_GROUP0_MAX_COUNTERS];
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ uint64_t group1_cnts[AMU_GROUP1_MAX_COUNTERS];
+#endif
+
+ /* Architected event counter 1 does not have an offset register */
+ uint64_t group0_voffsets[AMU_GROUP0_MAX_COUNTERS - 1U];
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ uint64_t group1_voffsets[AMU_GROUP1_MAX_COUNTERS];
+#endif
+
+ uint16_t group0_enable;
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ uint16_t group1_enable;
+#endif
+};
+
+static struct amu_ctx amu_ctxs_[PLATFORM_CORE_COUNT];
+
+CASSERT((sizeof(amu_ctxs_[0].group0_enable) * CHAR_BIT) <= AMU_GROUP0_MAX_COUNTERS,
+ amu_ctx_group0_enable_cannot_represent_all_group0_counters);
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+CASSERT((sizeof(amu_ctxs_[0].group1_enable) * CHAR_BIT) <= AMU_GROUP1_MAX_COUNTERS,
+ amu_ctx_group1_enable_cannot_represent_all_group1_counters);
+#endif
+
+static inline __unused uint64_t read_id_aa64pfr0_el1_amu(void)
+{
+ return (read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT) &
+ ID_AA64PFR0_AMU_MASK;
+}
+
+static inline __unused uint64_t read_hcr_el2_amvoffen(void)
+{
+ return (read_hcr_el2() & HCR_AMVOFFEN_BIT) >>
+ HCR_AMVOFFEN_SHIFT;
+}
+
+static inline __unused void write_cptr_el2_tam(uint64_t value)
+{
+ write_cptr_el2((read_cptr_el2() & ~CPTR_EL2_TAM_BIT) |
+ ((value << CPTR_EL2_TAM_SHIFT) & CPTR_EL2_TAM_BIT));
+}
+
+static inline __unused void ctx_write_cptr_el3_tam(cpu_context_t *ctx, uint64_t tam)
+{
+ uint64_t value = read_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3);
+
+ value &= ~TAM_BIT;
+ value |= (tam << TAM_SHIFT) & TAM_BIT;
+
+ write_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3, value);
+}
+
+static inline __unused void ctx_write_scr_el3_amvoffen(cpu_context_t *ctx, uint64_t amvoffen)
+{
+ uint64_t value = read_ctx_reg(get_el3state_ctx(ctx), CTX_SCR_EL3);
+
+ value &= ~SCR_AMVOFFEN_BIT;
+ value |= (amvoffen << SCR_AMVOFFEN_SHIFT) & SCR_AMVOFFEN_BIT;
+
+ write_ctx_reg(get_el3state_ctx(ctx), CTX_SCR_EL3, value);
+}
+
+static inline __unused void write_hcr_el2_amvoffen(uint64_t value)
+{
+ write_hcr_el2((read_hcr_el2() & ~HCR_AMVOFFEN_BIT) |
+ ((value << HCR_AMVOFFEN_SHIFT) & HCR_AMVOFFEN_BIT));
+}
+
+static inline __unused void write_amcr_el0_cg1rz(uint64_t value)
+{
+ write_amcr_el0((read_amcr_el0() & ~AMCR_CG1RZ_BIT) |
+ ((value << AMCR_CG1RZ_SHIFT) & AMCR_CG1RZ_BIT));
+}
+
+static inline __unused uint64_t read_amcfgr_el0_ncg(void)
+{
+ return (read_amcfgr_el0() >> AMCFGR_EL0_NCG_SHIFT) &
+ AMCFGR_EL0_NCG_MASK;
+}
+
+static inline __unused uint64_t read_amcgcr_el0_cg0nc(void)
+{
+ return (read_amcgcr_el0() >> AMCGCR_EL0_CG0NC_SHIFT) &
+ AMCGCR_EL0_CG0NC_MASK;
+}
+
+static inline __unused uint64_t read_amcg1idr_el0_voff(void)
+{
+ return (read_amcg1idr_el0() >> AMCG1IDR_VOFF_SHIFT) &
+ AMCG1IDR_VOFF_MASK;
+}
+
+static inline __unused uint64_t read_amcgcr_el0_cg1nc(void)
+{
+ return (read_amcgcr_el0() >> AMCGCR_EL0_CG1NC_SHIFT) &
+ AMCGCR_EL0_CG1NC_MASK;
+}
+
+static inline __unused uint64_t read_amcntenset0_el0_px(void)
+{
+ return (read_amcntenset0_el0() >> AMCNTENSET0_EL0_Pn_SHIFT) &
+ AMCNTENSET0_EL0_Pn_MASK;
+}
+
+static inline __unused uint64_t read_amcntenset1_el0_px(void)
+{
+ return (read_amcntenset1_el0() >> AMCNTENSET1_EL0_Pn_SHIFT) &
+ AMCNTENSET1_EL0_Pn_MASK;
+}
+
+static inline __unused void write_amcntenset0_el0_px(uint64_t px)
+{
+ uint64_t value = read_amcntenset0_el0();
+
+ value &= ~AMCNTENSET0_EL0_Pn_MASK;
+ value |= (px << AMCNTENSET0_EL0_Pn_SHIFT) & AMCNTENSET0_EL0_Pn_MASK;
+
+ write_amcntenset0_el0(value);
+}
+
+static inline __unused void write_amcntenset1_el0_px(uint64_t px)
+{
+ uint64_t value = read_amcntenset1_el0();
+
+ value &= ~AMCNTENSET1_EL0_Pn_MASK;
+ value |= (px << AMCNTENSET1_EL0_Pn_SHIFT) & AMCNTENSET1_EL0_Pn_MASK;
+
+ write_amcntenset1_el0(value);
+}
+
+static inline __unused void write_amcntenclr0_el0_px(uint64_t px)
+{
+ uint64_t value = read_amcntenclr0_el0();
+
+ value &= ~AMCNTENCLR0_EL0_Pn_MASK;
+ value |= (px << AMCNTENCLR0_EL0_Pn_SHIFT) & AMCNTENCLR0_EL0_Pn_MASK;
+
+ write_amcntenclr0_el0(value);
+}
+
+static inline __unused void write_amcntenclr1_el0_px(uint64_t px)
+{
+ uint64_t value = read_amcntenclr1_el0();
+
+ value &= ~AMCNTENCLR1_EL0_Pn_MASK;
+ value |= (px << AMCNTENCLR1_EL0_Pn_SHIFT) & AMCNTENCLR1_EL0_Pn_MASK;
+
+ write_amcntenclr1_el0(value);
+}
+
+static __unused bool amu_supported(void)
+{
+ return read_id_aa64pfr0_el1_amu() >= ID_AA64PFR0_AMU_V1;
+}
+
+static __unused bool amu_v1p1_supported(void)
+{
+ return read_id_aa64pfr0_el1_amu() >= ID_AA64PFR0_AMU_V1P1;
+}
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+static __unused bool amu_group1_supported(void)
+{
+ return read_amcfgr_el0_ncg() > 0U;
+}
+#endif
+
+/*
+ * Enable counters. This function is meant to be invoked by the context
+ * management library before exiting from EL3.
+ */
+void amu_enable(bool el2_unused, cpu_context_t *ctx)
+{
+ uint64_t id_aa64pfr0_el1_amu; /* AMU version */
+
+ uint64_t amcfgr_el0_ncg; /* Number of counter groups */
+ uint64_t amcgcr_el0_cg0nc; /* Number of group 0 counters */
+
+ uint64_t amcntenset0_el0_px = 0x0; /* Group 0 enable mask */
+ uint64_t amcntenset1_el0_px = 0x0; /* Group 1 enable mask */
+
+ id_aa64pfr0_el1_amu = read_id_aa64pfr0_el1_amu();
+ if (id_aa64pfr0_el1_amu == ID_AA64PFR0_AMU_NOT_SUPPORTED) {
+ /*
+ * If the AMU is unsupported, nothing needs to be done.
+ */
+
+ return;
+ }
+
+ if (el2_unused) {
+ /*
+ * CPTR_EL2.TAM: Set to zero so any accesses to the Activity
+ * Monitor registers do not trap to EL2.
+ */
+ write_cptr_el2_tam(0U);
+ }
+
+ /*
+ * Retrieve and update the CPTR_EL3 value from the context mentioned
+ * in 'ctx'. Set CPTR_EL3.TAM to zero so that any accesses to
+ * the Activity Monitor registers do not trap to EL3.
+ */
+ ctx_write_cptr_el3_tam(ctx, 0U);
+
+ /*
+ * Retrieve the number of architected counters. All of these counters
+ * are enabled by default.
+ */
+
+ amcgcr_el0_cg0nc = read_amcgcr_el0_cg0nc();
+ amcntenset0_el0_px = (UINT64_C(1) << (amcgcr_el0_cg0nc)) - 1U;
+
+ assert(amcgcr_el0_cg0nc <= AMU_AMCGCR_CG0NC_MAX);
+
+ /*
+ * The platform may opt to enable specific auxiliary counters. This can
+ * be done via the common FCONF getter, or via the platform-implemented
+ * function.
+ */
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ const struct amu_topology *topology;
+
+#if ENABLE_AMU_FCONF
+ topology = FCONF_GET_PROPERTY(amu, config, topology);
+#else
+ topology = plat_amu_topology();
+#endif /* ENABLE_AMU_FCONF */
+
+ if (topology != NULL) {
+ unsigned int core_pos = plat_my_core_pos();
+
+ amcntenset1_el0_px = topology->cores[core_pos].enable;
+ } else {
+ ERROR("AMU: failed to generate AMU topology\n");
+ }
+#endif /* ENABLE_AMU_AUXILIARY_COUNTERS */
+
+ /*
+ * Enable the requested counters.
+ */
+
+ write_amcntenset0_el0_px(amcntenset0_el0_px);
+
+ amcfgr_el0_ncg = read_amcfgr_el0_ncg();
+ if (amcfgr_el0_ncg > 0U) {
+ write_amcntenset1_el0_px(amcntenset1_el0_px);
+
+#if !ENABLE_AMU_AUXILIARY_COUNTERS
+ VERBOSE("AMU: auxiliary counters detected but support is disabled\n");
+#endif
+ }
+
+ /* Initialize FEAT_AMUv1p1 features if present. */
+ if (id_aa64pfr0_el1_amu >= ID_AA64PFR0_AMU_V1P1) {
+ if (el2_unused) {
+ /*
+ * Make sure virtual offsets are disabled if EL2 not
+ * used.
+ */
+ write_hcr_el2_amvoffen(0U);
+ } else {
+ /*
+ * Virtual offset registers are only accessible from EL3
+ * and EL2, when clear, this bit traps accesses from EL2
+ * so we set it to 1 when EL2 is present.
+ */
+ ctx_write_scr_el3_amvoffen(ctx, 1U);
+ }
+
+#if AMU_RESTRICT_COUNTERS
+ /*
+ * FEAT_AMUv1p1 adds a register field to restrict access to
+ * group 1 counters at all but the highest implemented EL. This
+ * is controlled with the `AMU_RESTRICT_COUNTERS` compile time
+ * flag, when set, system register reads at lower ELs return
+ * zero. Reads from the memory mapped view are unaffected.
+ */
+ VERBOSE("AMU group 1 counter access restricted.\n");
+ write_amcr_el0_cg1rz(1U);
+#else
+ write_amcr_el0_cg1rz(0U);
+#endif
+ }
+
+#if ENABLE_MPMM
+ mpmm_enable();
+#endif
+}
+
+/* Read the group 0 counter identified by the given `idx`. */
+static uint64_t amu_group0_cnt_read(unsigned int idx)
+{
+ assert(amu_supported());
+ assert(idx < read_amcgcr_el0_cg0nc());
+
+ return amu_group0_cnt_read_internal(idx);
+}
+
+/* Write the group 0 counter identified by the given `idx` with `val` */
+static void amu_group0_cnt_write(unsigned int idx, uint64_t val)
+{
+ assert(amu_supported());
+ assert(idx < read_amcgcr_el0_cg0nc());
+
+ amu_group0_cnt_write_internal(idx, val);
+ isb();
+}
+
+/*
+ * Unlike with auxiliary counters, we cannot detect at runtime whether an
+ * architected counter supports a virtual offset. These are instead fixed
+ * according to FEAT_AMUv1p1, but this switch will need to be updated if later
+ * revisions of FEAT_AMU add additional architected counters.
+ */
+static bool amu_group0_voffset_supported(uint64_t idx)
+{
+ switch (idx) {
+ case 0U:
+ case 2U:
+ case 3U:
+ return true;
+
+ case 1U:
+ return false;
+
+ default:
+ ERROR("AMU: can't set up virtual offset for unknown "
+ "architected counter %" PRIu64 "!\n", idx);
+
+ panic();
+ }
+}
+
+/*
+ * Read the group 0 offset register for a given index. Index must be 0, 2,
+ * or 3, the register for 1 does not exist.
+ *
+ * Using this function requires FEAT_AMUv1p1 support.
+ */
+static uint64_t amu_group0_voffset_read(unsigned int idx)
+{
+ assert(amu_v1p1_supported());
+ assert(idx < read_amcgcr_el0_cg0nc());
+ assert(idx != 1U);
+
+ return amu_group0_voffset_read_internal(idx);
+}
+
+/*
+ * Write the group 0 offset register for a given index. Index must be 0, 2, or
+ * 3, the register for 1 does not exist.
+ *
+ * Using this function requires FEAT_AMUv1p1 support.
+ */
+static void amu_group0_voffset_write(unsigned int idx, uint64_t val)
+{
+ assert(amu_v1p1_supported());
+ assert(idx < read_amcgcr_el0_cg0nc());
+ assert(idx != 1U);
+
+ amu_group0_voffset_write_internal(idx, val);
+ isb();
+}
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+/* Read the group 1 counter identified by the given `idx` */
+static uint64_t amu_group1_cnt_read(unsigned int idx)
+{
+ assert(amu_supported());
+ assert(amu_group1_supported());
+ assert(idx < read_amcgcr_el0_cg1nc());
+
+ return amu_group1_cnt_read_internal(idx);
+}
+
+/* Write the group 1 counter identified by the given `idx` with `val` */
+static void amu_group1_cnt_write(unsigned int idx, uint64_t val)
+{
+ assert(amu_supported());
+ assert(amu_group1_supported());
+ assert(idx < read_amcgcr_el0_cg1nc());
+
+ amu_group1_cnt_write_internal(idx, val);
+ isb();
+}
+
+/*
+ * Read the group 1 offset register for a given index.
+ *
+ * Using this function requires FEAT_AMUv1p1 support.
+ */
+static uint64_t amu_group1_voffset_read(unsigned int idx)
+{
+ assert(amu_v1p1_supported());
+ assert(amu_group1_supported());
+ assert(idx < read_amcgcr_el0_cg1nc());
+ assert((read_amcg1idr_el0_voff() & (UINT64_C(1) << idx)) != 0U);
+
+ return amu_group1_voffset_read_internal(idx);
+}
+
+/*
+ * Write the group 1 offset register for a given index.
+ *
+ * Using this function requires FEAT_AMUv1p1 support.
+ */
+static void amu_group1_voffset_write(unsigned int idx, uint64_t val)
+{
+ assert(amu_v1p1_supported());
+ assert(amu_group1_supported());
+ assert(idx < read_amcgcr_el0_cg1nc());
+ assert((read_amcg1idr_el0_voff() & (UINT64_C(1) << idx)) != 0U);
+
+ amu_group1_voffset_write_internal(idx, val);
+ isb();
+}
+#endif
+
+static void *amu_context_save(const void *arg)
+{
+ uint64_t i, j;
+
+ unsigned int core_pos;
+ struct amu_ctx *ctx;
+
+ uint64_t id_aa64pfr0_el1_amu; /* AMU version */
+ uint64_t hcr_el2_amvoffen; /* AMU virtual offsets enabled */
+ uint64_t amcgcr_el0_cg0nc; /* Number of group 0 counters */
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ uint64_t amcg1idr_el0_voff; /* Auxiliary counters with virtual offsets */
+ uint64_t amcfgr_el0_ncg; /* Number of counter groups */
+ uint64_t amcgcr_el0_cg1nc; /* Number of group 1 counters */
+#endif
+
+ id_aa64pfr0_el1_amu = read_id_aa64pfr0_el1_amu();
+ if (id_aa64pfr0_el1_amu == ID_AA64PFR0_AMU_NOT_SUPPORTED) {
+ return (void *)0;
+ }
+
+ core_pos = plat_my_core_pos();
+ ctx = &amu_ctxs_[core_pos];
+
+ amcgcr_el0_cg0nc = read_amcgcr_el0_cg0nc();
+ hcr_el2_amvoffen = (id_aa64pfr0_el1_amu >= ID_AA64PFR0_AMU_V1P1) ?
+ read_hcr_el2_amvoffen() : 0U;
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ amcfgr_el0_ncg = read_amcfgr_el0_ncg();
+ amcgcr_el0_cg1nc = (amcfgr_el0_ncg > 0U) ? read_amcgcr_el0_cg1nc() : 0U;
+ amcg1idr_el0_voff = (hcr_el2_amvoffen != 0U) ? read_amcg1idr_el0_voff() : 0U;
+#endif
+
+ /*
+ * Disable all AMU counters.
+ */
+
+ ctx->group0_enable = read_amcntenset0_el0_px();
+ write_amcntenclr0_el0_px(ctx->group0_enable);
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ if (amcfgr_el0_ncg > 0U) {
+ ctx->group1_enable = read_amcntenset1_el0_px();
+ write_amcntenclr1_el0_px(ctx->group1_enable);
+ }
+#endif
+
+ /*
+ * Save the counters to the local context.
+ */
+
+ isb(); /* Ensure counters have been stopped */
+
+ for (i = 0U; i < amcgcr_el0_cg0nc; i++) {
+ ctx->group0_cnts[i] = amu_group0_cnt_read(i);
+ }
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ for (i = 0U; i < amcgcr_el0_cg1nc; i++) {
+ ctx->group1_cnts[i] = amu_group1_cnt_read(i);
+ }
+#endif
+
+ /*
+ * Save virtual offsets for counters that offer them.
+ */
+
+ if (hcr_el2_amvoffen != 0U) {
+ for (i = 0U, j = 0U; i < amcgcr_el0_cg0nc; i++) {
+ if (!amu_group0_voffset_supported(i)) {
+ continue; /* No virtual offset */
+ }
+
+ ctx->group0_voffsets[j++] = amu_group0_voffset_read(i);
+ }
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ for (i = 0U, j = 0U; i < amcgcr_el0_cg1nc; i++) {
+ if ((amcg1idr_el0_voff >> i) & 1U) {
+ continue; /* No virtual offset */
+ }
+
+ ctx->group1_voffsets[j++] = amu_group1_voffset_read(i);
+ }
+#endif
+ }
+
+ return (void *)0;
+}
+
+static void *amu_context_restore(const void *arg)
+{
+ uint64_t i, j;
+
+ unsigned int core_pos;
+ struct amu_ctx *ctx;
+
+ uint64_t id_aa64pfr0_el1_amu; /* AMU version */
+
+ uint64_t hcr_el2_amvoffen; /* AMU virtual offsets enabled */
+
+ uint64_t amcfgr_el0_ncg; /* Number of counter groups */
+ uint64_t amcgcr_el0_cg0nc; /* Number of group 0 counters */
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ uint64_t amcgcr_el0_cg1nc; /* Number of group 1 counters */
+ uint64_t amcg1idr_el0_voff; /* Auxiliary counters with virtual offsets */
+#endif
+
+ id_aa64pfr0_el1_amu = read_id_aa64pfr0_el1_amu();
+ if (id_aa64pfr0_el1_amu == ID_AA64PFR0_AMU_NOT_SUPPORTED) {
+ return (void *)0;
+ }
+
+ core_pos = plat_my_core_pos();
+ ctx = &amu_ctxs_[core_pos];
+
+ amcfgr_el0_ncg = read_amcfgr_el0_ncg();
+ amcgcr_el0_cg0nc = read_amcgcr_el0_cg0nc();
+
+ hcr_el2_amvoffen = (id_aa64pfr0_el1_amu >= ID_AA64PFR0_AMU_V1P1) ?
+ read_hcr_el2_amvoffen() : 0U;
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ amcgcr_el0_cg1nc = (amcfgr_el0_ncg > 0U) ? read_amcgcr_el0_cg1nc() : 0U;
+ amcg1idr_el0_voff = (hcr_el2_amvoffen != 0U) ? read_amcg1idr_el0_voff() : 0U;
+#endif
+
+ /*
+ * Sanity check that all counters were disabled when the context was
+ * previously saved.
+ */
+
+ assert(read_amcntenset0_el0_px() == 0U);
+
+ if (amcfgr_el0_ncg > 0U) {
+ assert(read_amcntenset1_el0_px() == 0U);
+ }
+
+ /*
+ * Restore the counter values from the local context.
+ */
+
+ for (i = 0U; i < amcgcr_el0_cg0nc; i++) {
+ amu_group0_cnt_write(i, ctx->group0_cnts[i]);
+ }
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ for (i = 0U; i < amcgcr_el0_cg1nc; i++) {
+ amu_group1_cnt_write(i, ctx->group1_cnts[i]);
+ }
+#endif
+
+ /*
+ * Restore virtual offsets for counters that offer them.
+ */
+
+ if (hcr_el2_amvoffen != 0U) {
+ for (i = 0U, j = 0U; i < amcgcr_el0_cg0nc; i++) {
+ if (!amu_group0_voffset_supported(i)) {
+ continue; /* No virtual offset */
+ }
+
+ amu_group0_voffset_write(i, ctx->group0_voffsets[j++]);
+ }
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ for (i = 0U, j = 0U; i < amcgcr_el0_cg1nc; i++) {
+ if ((amcg1idr_el0_voff >> i) & 1U) {
+ continue; /* No virtual offset */
+ }
+
+ amu_group1_voffset_write(i, ctx->group1_voffsets[j++]);
+ }
+#endif
+ }
+
+ /*
+ * Re-enable counters that were disabled during context save.
+ */
+
+ write_amcntenset0_el0_px(ctx->group0_enable);
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+ if (amcfgr_el0_ncg > 0) {
+ write_amcntenset1_el0_px(ctx->group1_enable);
+ }
+#endif
+
+#if ENABLE_MPMM
+ mpmm_enable();
+#endif
+
+ return (void *)0;
+}
+
+SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save);
+SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore);
diff --git a/lib/extensions/amu/aarch64/amu_helpers.S b/lib/extensions/amu/aarch64/amu_helpers.S
new file mode 100644
index 0000000..0f6d799
--- /dev/null
+++ b/lib/extensions/amu/aarch64/amu_helpers.S
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <assert_macros.S>
+#include <asm_macros.S>
+
+ .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
+
+ /* FEAT_AMUv1p1 virtualisation offset register functions */
+ .globl amu_group0_voffset_read_internal
+ .globl amu_group0_voffset_write_internal
+ .globl amu_group1_voffset_read_internal
+ .globl amu_group1_voffset_write_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
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+/*
+ * 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
+#endif
+
+/*
+ * Accessor functions for virtual offset registers added with FEAT_AMUv1p1
+ */
+
+/*
+ * uint64_t amu_group0_voffset_read_internal(int idx);
+ *
+ * Given `idx`, read the corresponding AMU virtual offset register
+ * and return it in `x0`.
+ */
+func amu_group0_voffset_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)
+ /* Make sure idx != 1 since AMEVCNTVOFF01_EL2 does not exist */
+ cmp x0, #1
+ ASM_ASSERT(ne)
+#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 AMEVCNTVOFF00_EL2 /* index 0 */
+ .skip 8 /* AMEVCNTVOFF01_EL2 does not exist */
+#if ENABLE_BTI
+ .skip 4
+#endif
+ read AMEVCNTVOFF02_EL2 /* index 2 */
+ read AMEVCNTVOFF03_EL2 /* index 3 */
+endfunc amu_group0_voffset_read_internal
+
+/*
+ * void amu_group0_voffset_write_internal(int idx, uint64_t val);
+ *
+ * Given `idx`, write `val` to the corresponding AMU virtual offset register.
+ */
+func amu_group0_voffset_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)
+ /* Make sure idx != 1 since AMEVCNTVOFF01_EL2 does not exist */
+ cmp x0, #1
+ ASM_ASSERT(ne)
+#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 AMEVCNTVOFF00_EL2 /* index 0 */
+ .skip 8 /* AMEVCNTVOFF01_EL2 does not exist */
+#if ENABLE_BTI
+ .skip 4
+#endif
+ write AMEVCNTVOFF02_EL2 /* index 2 */
+ write AMEVCNTVOFF03_EL2 /* index 3 */
+endfunc amu_group0_voffset_write_internal
+
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+/*
+ * uint64_t amu_group1_voffset_read_internal(int idx);
+ *
+ * Given `idx`, read the corresponding AMU virtual offset register
+ * and return it in `x0`.
+ */
+func amu_group1_voffset_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 AMEVCNTVOFF10_EL2 /* index 0 */
+ read AMEVCNTVOFF11_EL2 /* index 1 */
+ read AMEVCNTVOFF12_EL2 /* index 2 */
+ read AMEVCNTVOFF13_EL2 /* index 3 */
+ read AMEVCNTVOFF14_EL2 /* index 4 */
+ read AMEVCNTVOFF15_EL2 /* index 5 */
+ read AMEVCNTVOFF16_EL2 /* index 6 */
+ read AMEVCNTVOFF17_EL2 /* index 7 */
+ read AMEVCNTVOFF18_EL2 /* index 8 */
+ read AMEVCNTVOFF19_EL2 /* index 9 */
+ read AMEVCNTVOFF1A_EL2 /* index 10 */
+ read AMEVCNTVOFF1B_EL2 /* index 11 */
+ read AMEVCNTVOFF1C_EL2 /* index 12 */
+ read AMEVCNTVOFF1D_EL2 /* index 13 */
+ read AMEVCNTVOFF1E_EL2 /* index 14 */
+ read AMEVCNTVOFF1F_EL2 /* index 15 */
+endfunc amu_group1_voffset_read_internal
+
+/*
+ * void amu_group1_voffset_write_internal(int idx, uint64_t val);
+ *
+ * Given `idx`, write `val` to the corresponding AMU virtual offset register.
+ */
+func amu_group1_voffset_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 AMEVCNTVOFF10_EL2 /* index 0 */
+ write AMEVCNTVOFF11_EL2 /* index 1 */
+ write AMEVCNTVOFF12_EL2 /* index 2 */
+ write AMEVCNTVOFF13_EL2 /* index 3 */
+ write AMEVCNTVOFF14_EL2 /* index 4 */
+ write AMEVCNTVOFF15_EL2 /* index 5 */
+ write AMEVCNTVOFF16_EL2 /* index 6 */
+ write AMEVCNTVOFF17_EL2 /* index 7 */
+ write AMEVCNTVOFF18_EL2 /* index 8 */
+ write AMEVCNTVOFF19_EL2 /* index 9 */
+ write AMEVCNTVOFF1A_EL2 /* index 10 */
+ write AMEVCNTVOFF1B_EL2 /* index 11 */
+ write AMEVCNTVOFF1C_EL2 /* index 12 */
+ write AMEVCNTVOFF1D_EL2 /* index 13 */
+ write AMEVCNTVOFF1E_EL2 /* index 14 */
+ write AMEVCNTVOFF1F_EL2 /* index 15 */
+endfunc amu_group1_voffset_write_internal
+#endif
diff --git a/lib/extensions/amu/amu.mk b/lib/extensions/amu/amu.mk
new file mode 100644
index 0000000..0d203cb
--- /dev/null
+++ b/lib/extensions/amu/amu.mk
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include lib/fconf/fconf.mk
+
+AMU_SOURCES := lib/extensions/amu/${ARCH}/amu.c \
+ lib/extensions/amu/${ARCH}/amu_helpers.S
+
+ifneq (${ENABLE_AMU_AUXILIARY_COUNTERS},0)
+ ifeq (${ENABLE_AMU},0)
+ $(error AMU auxiliary counter support (`ENABLE_AMU_AUXILIARY_COUNTERS`) requires AMU support (`ENABLE_AMU`))
+ endif
+endif
+
+ifneq (${ENABLE_AMU_FCONF},0)
+ ifeq (${ENABLE_AMU_AUXILIARY_COUNTERS},0)
+ $(error AMU FCONF support (`ENABLE_AMU_FCONF`) is not necessary when auxiliary counter support (`ENABLE_AMU_AUXILIARY_COUNTERS`) is disabled)
+ endif
+
+ AMU_SOURCES += ${FCONF_AMU_SOURCES}
+endif
diff --git a/lib/extensions/amu/amu_private.h b/lib/extensions/amu/amu_private.h
new file mode 100644
index 0000000..eb7ff0e
--- /dev/null
+++ b/lib/extensions/amu/amu_private.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AMU_PRIVATE_H
+#define AMU_PRIVATE_H
+
+#include <stdint.h>
+
+#include <lib/cassert.h>
+#include <lib/extensions/amu.h>
+#include <lib/utils_def.h>
+
+#include <platform_def.h>
+
+#define AMU_GROUP0_MAX_COUNTERS U(16)
+#define AMU_GROUP1_MAX_COUNTERS U(16)
+
+#define AMU_AMCGCR_CG0NC_MAX U(16)
+
+uint64_t amu_group0_cnt_read_internal(unsigned int idx);
+void amu_group0_cnt_write_internal(unsigned int idx, uint64_t val);
+
+uint64_t amu_group1_cnt_read_internal(unsigned int idx);
+void amu_group1_cnt_write_internal(unsigned int idx, uint64_t val);
+void amu_group1_set_evtype_internal(unsigned int idx, unsigned int val);
+
+#if __aarch64__
+uint64_t amu_group0_voffset_read_internal(unsigned int idx);
+void amu_group0_voffset_write_internal(unsigned int idx, uint64_t val);
+
+uint64_t amu_group1_voffset_read_internal(unsigned int idx);
+void amu_group1_voffset_write_internal(unsigned int idx, uint64_t val);
+#endif
+
+#endif /* AMU_PRIVATE_H */
diff --git a/lib/extensions/brbe/brbe.c b/lib/extensions/brbe/brbe.c
new file mode 100644
index 0000000..1982619
--- /dev/null
+++ b/lib/extensions/brbe/brbe.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+
+void brbe_enable(void)
+{
+ uint64_t val;
+
+ if (is_feat_brbe_present()) {
+ /*
+ * MDCR_EL3.SBRBE = 0b01
+ *
+ * Allows BRBE usage in non-secure world and prohibited in
+ * secure world.
+ */
+ val = read_mdcr_el3();
+ val &= ~(MDCR_SBRBE_MASK << MDCR_SBRBE_SHIFT);
+ val |= (0x1UL << MDCR_SBRBE_SHIFT);
+ write_mdcr_el3(val);
+ }
+}
diff --git a/lib/extensions/mpam/mpam.c b/lib/extensions/mpam/mpam.c
new file mode 100644
index 0000000..884d480
--- /dev/null
+++ b/lib/extensions/mpam/mpam.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <lib/extensions/mpam.h>
+
+void mpam_enable(bool el2_unused)
+{
+ /* Check if MPAM is implemented */
+ if (get_mpam_version() == 0U) {
+ 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_unused) {
+ write_mpam2_el2(0ULL);
+
+ if ((read_mpamidr_el1() & MPAMIDR_HAS_HCR_BIT) != 0U) {
+ write_mpamhcr_el2(0ULL);
+ }
+ }
+}
diff --git a/lib/extensions/mtpmu/aarch32/mtpmu.S b/lib/extensions/mtpmu/aarch32/mtpmu.S
new file mode 100644
index 0000000..834cee3
--- /dev/null
+++ b/lib/extensions/mtpmu/aarch32/mtpmu.S
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+ .global mtpmu_disable
+
+/* -------------------------------------------------------------
+ * The functions in this file are called at entrypoint, before
+ * the CPU has decided whether this is a cold or a warm boot.
+ * Therefore there are no stack yet to rely on for a C function
+ * call.
+ * -------------------------------------------------------------
+ */
+
+/*
+ * bool mtpmu_supported(void)
+ *
+ * Return a boolean indicating whether FEAT_MTPMU is supported or not.
+ *
+ * Trash registers: r0.
+ */
+func mtpmu_supported
+ ldcopr r0, ID_DFR1
+ and r0, r0, #(ID_DFR1_MTPMU_MASK >> ID_DFR1_MTPMU_SHIFT)
+ cmp r0, #ID_DFR1_MTPMU_SUPPORTED
+ mov r0, #0
+ addeq r0, r0, #1
+ bx lr
+endfunc mtpmu_supported
+
+/*
+ * bool el_implemented(unsigned int el)
+ *
+ * Return a boolean indicating if the specified EL (2 or 3) is implemented.
+ *
+ * Trash registers: r0
+ */
+func el_implemented
+ cmp r0, #3
+ ldcopr r0, ID_PFR1
+ lsreq r0, r0, #ID_PFR1_SEC_SHIFT
+ lsrne r0, r0, #ID_PFR1_VIRTEXT_SHIFT
+ /*
+ * ID_PFR1_VIRTEXT_MASK is the same as ID_PFR1_SEC_MASK
+ * so use any one of them
+ */
+ and r0, r0, #ID_PFR1_VIRTEXT_MASK
+ cmp r0, #ID_PFR1_ELx_ENABLED
+ mov r0, #0
+ addeq r0, r0, #1
+ bx lr
+endfunc el_implemented
+
+/*
+ * void mtpmu_disable(void)
+ *
+ * Disable mtpmu feature if supported.
+ *
+ * Trash register: r0, r1, r2
+ */
+func mtpmu_disable
+ mov r2, lr
+ bl mtpmu_supported
+ cmp r0, #0
+ bxeq r2 /* FEAT_MTPMU not supported */
+
+ /* FEAT_MTMPU Supported */
+ mov r0, #3
+ bl el_implemented
+ cmp r0, #0
+ beq 1f
+
+ /* EL3 implemented */
+ ldcopr r0, SDCR
+ ldr r1, =SDCR_MTPME_BIT
+ bic r0, r0, r1
+ stcopr r0, SDCR
+
+ /*
+ * If EL3 is implemented, HDCR.MTPME is implemented as Res0 and
+ * FEAT_MTPMU is controlled only from EL3, so no need to perform
+ * any operations for EL2.
+ */
+ isb
+ bx r2
+1:
+ /* EL3 not implemented */
+ mov r0, #2
+ bl el_implemented
+ cmp r0, #0
+ bxeq r2 /* No EL2 or EL3 implemented */
+
+ /* EL2 implemented */
+ ldcopr r0, HDCR
+ ldr r1, =HDCR_MTPME_BIT
+ orr r0, r0, r1
+ stcopr r0, HDCR
+ isb
+ bx r2
+endfunc mtpmu_disable
diff --git a/lib/extensions/mtpmu/aarch64/mtpmu.S b/lib/extensions/mtpmu/aarch64/mtpmu.S
new file mode 100644
index 0000000..0a1d57b
--- /dev/null
+++ b/lib/extensions/mtpmu/aarch64/mtpmu.S
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+ .global mtpmu_disable
+
+/* -------------------------------------------------------------
+ * The functions in this file are called at entrypoint, before
+ * the CPU has decided whether this is a cold or a warm boot.
+ * Therefore there are no stack yet to rely on for a C function
+ * call.
+ * -------------------------------------------------------------
+ */
+
+/*
+ * bool mtpmu_supported(void)
+ *
+ * Return a boolean indicating whether FEAT_MTPMU is supported or not.
+ *
+ * Trash registers: x0, x1
+ */
+func mtpmu_supported
+ mrs x0, id_aa64dfr0_el1
+ mov_imm x1, ID_AA64DFR0_MTPMU_MASK
+ and x0, x1, x0, LSR #ID_AA64DFR0_MTPMU_SHIFT
+ cmp x0, ID_AA64DFR0_MTPMU_SUPPORTED
+ cset x0, eq
+ ret
+endfunc mtpmu_supported
+
+/*
+ * bool el_implemented(unsigned int el_shift)
+ *
+ * Return a boolean indicating if the specified EL is implemented.
+ * The EL is represented as the bitmask shift on id_aa64pfr0_el1 register.
+ *
+ * Trash registers: x0, x1
+ */
+func el_implemented
+ mrs x1, id_aa64pfr0_el1
+ lsr x1, x1, x0
+ cmp x1, #ID_AA64PFR0_ELX_MASK
+ cset x0, eq
+ ret
+endfunc el_implemented
+
+/*
+ * void mtpmu_disable(void)
+ *
+ * Disable mtpmu feature if supported.
+ *
+ * Trash register: x0, x1, x30
+ */
+func mtpmu_disable
+ mov x10, x30
+ bl mtpmu_supported
+ cbz x0, exit_disable
+
+ /* FEAT_MTMPU Supported */
+ mov_imm x0, ID_AA64PFR0_EL3_SHIFT
+ bl el_implemented
+ cbz x0, 1f
+
+ /* EL3 implemented */
+ mrs x0, mdcr_el3
+ mov_imm x1, MDCR_MTPME_BIT
+ bic x0, x0, x1
+ msr mdcr_el3, x0
+
+ /*
+ * If EL3 is implemented, MDCR_EL2.MTPME is implemented as Res0 and
+ * FEAT_MTPMU is controlled only from EL3, so no need to perform
+ * any operations for EL2.
+ */
+ isb
+exit_disable:
+ ret x10
+1:
+ /* EL3 not implemented */
+ mov_imm x0, ID_AA64PFR0_EL2_SHIFT
+ bl el_implemented
+ cbz x0, exit_disable
+
+ /* EL2 implemented */
+ mrs x0, mdcr_el2
+ mov_imm x1, MDCR_EL2_MTPME
+ bic x0, x0, x1
+ msr mdcr_el2, x0
+ isb
+ ret x10
+endfunc mtpmu_disable
diff --git a/lib/extensions/pauth/pauth_helpers.S b/lib/extensions/pauth/pauth_helpers.S
new file mode 100644
index 0000000..d483c7d
--- /dev/null
+++ b/lib/extensions/pauth/pauth_helpers.S
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <lib/el3_runtime/cpu_data.h>
+
+ .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
diff --git a/lib/extensions/ras/ras_common.c b/lib/extensions/ras/ras_common.c
new file mode 100644
index 0000000..622879e
--- /dev/null
+++ b/lib/extensions/ras/ras_common.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+#include <bl31/ea_handle.h>
+#include <bl31/ehf.h>
+#include <common/debug.h>
+#include <lib/extensions/ras.h>
+#include <lib/extensions/ras_arch.h>
+#include <plat/common/platform.h>
+
+#ifndef PLAT_RAS_PRI
+# error Platform must define RAS priority value
+#endif
+
+/*
+ * Function to convert architecturally-defined primary error code SERR,
+ * bits[7:0] from ERR<n>STATUS to its corresponding error string.
+ */
+const char *ras_serr_to_str(unsigned int serr)
+{
+ const char *str[ERROR_STATUS_NUM_SERR] = {
+ "No error",
+ "IMPLEMENTATION DEFINED error",
+ "Data value from (non-associative) internal memory",
+ "IMPLEMENTATION DEFINED pin",
+ "Assertion failure",
+ "Error detected on internal data path",
+ "Data value from associative memory",
+ "Address/control value from associative memory",
+ "Data value from a TLB",
+ "Address/control value from a TLB",
+ "Data value from producer",
+ "Address/control value from producer",
+ "Data value from (non-associative) external memory",
+ "Illegal address (software fault)",
+ "Illegal access (software fault)",
+ "Illegal state (software fault)",
+ "Internal data register",
+ "Internal control register",
+ "Error response from slave",
+ "External timeout",
+ "Internal timeout",
+ "Deferred error from slave not supported at master"
+ };
+
+ /*
+ * All other values are reserved. Reserved values might be defined
+ * in a future version of the architecture
+ */
+ if (serr >= ERROR_STATUS_NUM_SERR)
+ return "unknown SERR";
+
+ return str[serr];
+}
+
+/* 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 - 1;
+ 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);
+}
diff --git a/lib/extensions/ras/std_err_record.c b/lib/extensions/ras/std_err_record.c
new file mode 100644
index 0000000..c03fbbe
--- /dev/null
+++ b/lib/extensions/ras/std_err_record.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/extensions/ras_arch.h>
+#include <lib/utils_def.h>
+
+/*
+ * 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;
+}
diff --git a/lib/extensions/sme/sme.c b/lib/extensions/sme/sme.c
new file mode 100644
index 0000000..ec8cca8
--- /dev/null
+++ b/lib/extensions/sme/sme.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/extensions/sme.h>
+#include <lib/extensions/sve.h>
+
+static bool feat_sme_supported(void)
+{
+ uint64_t features;
+
+ features = read_id_aa64pfr1_el1() >> ID_AA64PFR1_EL1_SME_SHIFT;
+ return (features & ID_AA64PFR1_EL1_SME_MASK) != 0U;
+}
+
+static bool feat_sme_fa64_supported(void)
+{
+ uint64_t features;
+
+ features = read_id_aa64smfr0_el1();
+ return (features & ID_AA64SMFR0_EL1_FA64_BIT) != 0U;
+}
+
+void sme_enable(cpu_context_t *context)
+{
+ u_register_t reg;
+ u_register_t cptr_el3;
+ el3_state_t *state;
+
+ /* Make sure SME is implemented in hardware before continuing. */
+ if (!feat_sme_supported()) {
+ /* Perhaps the hardware supports SVE only */
+ sve_enable(context);
+ return;
+ }
+
+ /* Get the context state. */
+ state = get_el3state_ctx(context);
+
+ /* Enable SME in CPTR_EL3. */
+ reg = read_ctx_reg(state, CTX_CPTR_EL3);
+ reg |= ESM_BIT;
+ write_ctx_reg(state, CTX_CPTR_EL3, reg);
+
+ /* Set the ENTP2 bit in SCR_EL3 to enable access to TPIDR2_EL0. */
+ reg = read_ctx_reg(state, CTX_SCR_EL3);
+ reg |= SCR_ENTP2_BIT;
+ write_ctx_reg(state, CTX_SCR_EL3, reg);
+
+ /* Set CPTR_EL3.ESM bit so we can write SMCR_EL3 without trapping. */
+ cptr_el3 = read_cptr_el3();
+ write_cptr_el3(cptr_el3 | ESM_BIT);
+ isb();
+
+ /*
+ * Set the max LEN value and FA64 bit. This register is set up globally
+ * to be the least restrictive, then lower ELs can restrict as needed
+ * using SMCR_EL2 and SMCR_EL1.
+ */
+ reg = SMCR_ELX_LEN_MASK;
+ if (feat_sme_fa64_supported()) {
+ VERBOSE("[SME] FA64 enabled\n");
+ reg |= SMCR_ELX_FA64_BIT;
+ }
+ write_smcr_el3(reg);
+
+ /* Reset CPTR_EL3 value. */
+ write_cptr_el3(cptr_el3);
+ isb();
+
+ /* Enable SVE/FPU in addition to SME. */
+ sve_enable(context);
+}
+
+void sme_disable(cpu_context_t *context)
+{
+ u_register_t reg;
+ el3_state_t *state;
+
+ /* Make sure SME is implemented in hardware before continuing. */
+ if (!feat_sme_supported()) {
+ /* Perhaps the hardware supports SVE only */
+ sve_disable(context);
+ return;
+ }
+
+ /* Get the context state. */
+ state = get_el3state_ctx(context);
+
+ /* Disable SME, SVE, and FPU since they all share registers. */
+ reg = read_ctx_reg(state, CTX_CPTR_EL3);
+ reg &= ~ESM_BIT; /* Trap SME */
+ reg &= ~CPTR_EZ_BIT; /* Trap SVE */
+ reg |= TFP_BIT; /* Trap FPU/SIMD */
+ write_ctx_reg(state, CTX_CPTR_EL3, reg);
+
+ /* Disable access to TPIDR2_EL0. */
+ reg = read_ctx_reg(state, CTX_SCR_EL3);
+ reg &= ~SCR_ENTP2_BIT;
+ write_ctx_reg(state, CTX_SCR_EL3, reg);
+}
diff --git a/lib/extensions/spe/spe.c b/lib/extensions/spe/spe.c
new file mode 100644
index 0000000..d747efc
--- /dev/null
+++ b/lib/extensions/spe/spe.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/el3_runtime/pubsub.h>
+#include <lib/extensions/spe.h>
+
+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) > 0ULL;
+}
+
+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.
+ *
+ * MDCR_EL3.EnPMSN (ARM v8.7): Do not trap access to PMSNEVFR_EL1
+ * register at NS-EL1 or NS-EL2 to EL3 if FEAT_SPEv1p2 is implemented.
+ * Setting this bit to 1 doesn't have any effect on it when
+ * FEAT_SPEv1p2 not implemented.
+ */
+ v = read_mdcr_el3();
+ v |= MDCR_NSPB(MDCR_NSPB_EL1) | MDCR_EnPMSN_BIT;
+ 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);
diff --git a/lib/extensions/sve/sve.c b/lib/extensions/sve/sve.c
new file mode 100644
index 0000000..f7dcc76
--- /dev/null
+++ b/lib/extensions/sve/sve.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/cassert.h>
+#include <lib/el3_runtime/pubsub.h>
+#include <lib/extensions/sve.h>
+
+CASSERT(SVE_VECTOR_LEN <= 2048, assert_sve_vl_too_long);
+CASSERT(SVE_VECTOR_LEN >= 128, assert_sve_vl_too_short);
+CASSERT((SVE_VECTOR_LEN % 128) == 0, assert_sve_vl_granule);
+
+/*
+ * Converts SVE vector size restriction in bytes to LEN according to ZCR_EL3 documentation.
+ * VECTOR_SIZE = (LEN+1) * 128
+ */
+#define CONVERT_SVE_LENGTH(x) (((x / 128) - 1))
+
+static bool sve_supported(void)
+{
+ uint64_t features;
+
+ features = read_id_aa64pfr0_el1() >> ID_AA64PFR0_SVE_SHIFT;
+ return (features & ID_AA64PFR0_SVE_MASK) == 1U;
+}
+
+void sve_enable(cpu_context_t *context)
+{
+ u_register_t cptr_el3;
+
+ if (!sve_supported()) {
+ return;
+ }
+
+ cptr_el3 = read_ctx_reg(get_el3state_ctx(context), CTX_CPTR_EL3);
+
+ /* Enable access to SVE functionality for all ELs. */
+ cptr_el3 = (cptr_el3 | CPTR_EZ_BIT) & ~(TFP_BIT);
+ write_ctx_reg(get_el3state_ctx(context), CTX_CPTR_EL3, cptr_el3);
+
+ /* Restrict maximum SVE vector length (SVE_VECTOR_LEN+1) * 128. */
+ write_ctx_reg(get_el3state_ctx(context), CTX_ZCR_EL3,
+ (ZCR_EL3_LEN_MASK & CONVERT_SVE_LENGTH(SVE_VECTOR_LEN)));
+}
+
+void sve_disable(cpu_context_t *context)
+{
+ u_register_t reg;
+ el3_state_t *state;
+
+ /* Make sure SME is implemented in hardware before continuing. */
+ if (!sve_supported()) {
+ return;
+ }
+
+ /* Get the context state. */
+ state = get_el3state_ctx(context);
+
+ /* Disable SVE and FPU since they share registers. */
+ reg = read_ctx_reg(state, CTX_CPTR_EL3);
+ reg &= ~CPTR_EZ_BIT; /* Trap SVE */
+ reg |= TFP_BIT; /* Trap FPU/SIMD */
+ write_ctx_reg(state, CTX_CPTR_EL3, reg);
+}
diff --git a/lib/extensions/sys_reg_trace/aarch32/sys_reg_trace.c b/lib/extensions/sys_reg_trace/aarch32/sys_reg_trace.c
new file mode 100644
index 0000000..89b8029
--- /dev/null
+++ b/lib/extensions/sys_reg_trace/aarch32/sys_reg_trace.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/extensions/sys_reg_trace.h>
+
+static bool sys_reg_trace_supported(void)
+{
+ uint32_t features;
+
+ features = read_id_dfr0() >> ID_DFR0_COPTRC_SHIFT;
+ return ((features & ID_DFR0_COPTRC_MASK) ==
+ ID_DFR0_COPTRC_SUPPORTED);
+}
+
+void sys_reg_trace_enable(void)
+{
+ uint32_t val;
+
+ if (sys_reg_trace_supported()) {
+ /*
+ * NSACR.NSTRCDIS = b0
+ * enable NS system register access to implemented trace
+ * registers.
+ */
+ val = read_nsacr();
+ val &= ~NSTRCDIS_BIT;
+ write_nsacr(val);
+ }
+}
diff --git a/lib/extensions/sys_reg_trace/aarch64/sys_reg_trace.c b/lib/extensions/sys_reg_trace/aarch64/sys_reg_trace.c
new file mode 100644
index 0000000..960d698
--- /dev/null
+++ b/lib/extensions/sys_reg_trace/aarch64/sys_reg_trace.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/extensions/sys_reg_trace.h>
+
+static bool sys_reg_trace_supported(void)
+{
+ uint64_t features;
+
+ features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_TRACEVER_SHIFT;
+ return ((features & ID_AA64DFR0_TRACEVER_MASK) ==
+ ID_AA64DFR0_TRACEVER_SUPPORTED);
+}
+
+void sys_reg_trace_enable(cpu_context_t *ctx)
+{
+ uint64_t val;
+
+ if (sys_reg_trace_supported()) {
+ /* Retrieve CPTR_EL3 value from the given context 'ctx',
+ * and update CPTR_EL3.TTA bit to 0.
+ * This function is called while switching context to NS to
+ * allow system trace register access to NS-EL2 and NS-EL1
+ * when NS-EL2 is implemented but not used.
+ */
+ val = read_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3);
+ val &= ~TTA_BIT;
+ write_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3, val);
+ }
+}
diff --git a/lib/extensions/trbe/trbe.c b/lib/extensions/trbe/trbe.c
new file mode 100644
index 0000000..b346387
--- /dev/null
+++ b/lib/extensions/trbe/trbe.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <lib/el3_runtime/pubsub.h>
+#include <lib/extensions/trbe.h>
+
+static void tsb_csync(void)
+{
+ /*
+ * The assembler does not yet understand the tsb csync mnemonic
+ * so use the equivalent hint instruction.
+ */
+ __asm__ volatile("hint #18");
+}
+
+void trbe_enable(void)
+{
+ uint64_t val;
+
+ if (is_feat_trbe_present()) {
+ /*
+ * MDCR_EL3.NSTB = 0b11
+ * Allow access of trace buffer control registers from NS-EL1
+ * and NS-EL2, tracing is prohibited in Secure and Realm state
+ * (if implemented).
+ */
+ val = read_mdcr_el3();
+ val |= MDCR_NSTB(MDCR_NSTB_EL1);
+ write_mdcr_el3(val);
+ }
+}
+
+static void *trbe_drain_trace_buffers_hook(const void *arg __unused)
+{
+ if (is_feat_trbe_present()) {
+ /*
+ * Before switching from normal world to secure world
+ * the trace buffers need to be drained out to memory. This is
+ * required to avoid an invalid memory access when TTBR is switched
+ * for entry to S-EL1.
+ */
+ tsb_csync();
+ dsbnsh();
+ }
+
+ return (void *)0;
+}
+
+SUBSCRIBE_TO_EVENT(cm_entering_secure_world, trbe_drain_trace_buffers_hook);
diff --git a/lib/extensions/trf/aarch32/trf.c b/lib/extensions/trf/aarch32/trf.c
new file mode 100644
index 0000000..834092d
--- /dev/null
+++ b/lib/extensions/trf/aarch32/trf.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/extensions/trf.h>
+
+static bool trf_supported(void)
+{
+ uint32_t features;
+
+ features = read_id_dfr0() >> ID_DFR0_TRACEFILT_SHIFT;
+ return ((features & ID_DFR0_TRACEFILT_MASK) ==
+ ID_DFR0_TRACEFILT_SUPPORTED);
+}
+
+void trf_enable(void)
+{
+ uint32_t val;
+
+ if (trf_supported()) {
+ /*
+ * Allow access of trace filter control registers from
+ * non-monitor mode
+ */
+ val = read_sdcr();
+ val &= ~SDCR_TTRF_BIT;
+ write_sdcr(val);
+ }
+}
diff --git a/lib/extensions/trf/aarch64/trf.c b/lib/extensions/trf/aarch64/trf.c
new file mode 100644
index 0000000..1da5dce
--- /dev/null
+++ b/lib/extensions/trf/aarch64/trf.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/extensions/trf.h>
+
+static bool trf_supported(void)
+{
+ uint64_t features;
+
+ features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_TRACEFILT_SHIFT;
+ return ((features & ID_AA64DFR0_TRACEFILT_MASK) ==
+ ID_AA64DFR0_TRACEFILT_SUPPORTED);
+}
+
+void trf_enable(void)
+{
+ uint64_t val;
+
+ if (trf_supported()) {
+ /*
+ * MDCR_EL3.TTRF = b0
+ * Allow access of trace filter control registers from NS-EL2
+ * and NS-EL1 when NS-EL2 is implemented but not used
+ */
+ val = read_mdcr_el3();
+ val &= ~MDCR_TTRF_BIT;
+ write_mdcr_el3(val);
+ }
+}
diff --git a/lib/fconf/fconf.c b/lib/fconf/fconf.c
new file mode 100644
index 0000000..b1d6eaa
--- /dev/null
+++ b/lib/fconf/fconf.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_dyn_cfg_getter.h>
+#include <libfdt.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+int fconf_load_config(unsigned int image_id)
+{
+ int err;
+ const struct dyn_cfg_dtb_info_t *config_info;
+
+ assert((image_id == FW_CONFIG_ID) || (image_id == TB_FW_CONFIG_ID));
+
+ image_info_t config_image_info = {
+ .h.type = (uint8_t)PARAM_IMAGE_BINARY,
+ .h.version = (uint8_t)VERSION_2,
+ .h.size = (uint16_t)sizeof(image_info_t),
+ .h.attr = 0
+ };
+
+ config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, image_id);
+ assert(config_info != NULL);
+
+ config_image_info.image_base = config_info->config_addr;
+ config_image_info.image_max_size = config_info->config_max_size;
+
+ VERBOSE("FCONF: Loading config with image ID: %u\n", image_id);
+ err = load_auth_image(image_id, &config_image_info);
+ if (err != 0) {
+ VERBOSE("Failed to load config %u\n", image_id);
+ return err;
+ }
+
+ INFO("FCONF: Config file with image ID:%u loaded at address = 0x%lx\n",
+ image_id, config_image_info.image_base);
+
+ return 0;
+}
+
+void fconf_populate(const char *config_type, uintptr_t config)
+{
+ assert(config != 0UL);
+
+ /* Check if the pointer to DTB is correct */
+ if (fdt_check_header((void *)config) != 0) {
+ ERROR("FCONF: Invalid DTB file passed for %s\n", config_type);
+ panic();
+ }
+
+ INFO("FCONF: Reading %s firmware configuration file from: 0x%lx\n", config_type, config);
+
+ /* Go through all registered populate functions */
+ IMPORT_SYM(struct fconf_populator *, __FCONF_POPULATOR_START__, start);
+ IMPORT_SYM(struct fconf_populator *, __FCONF_POPULATOR_END__, end);
+ const struct fconf_populator *populator;
+
+ for (populator = start; populator != end; populator++) {
+ assert((populator->info != NULL) && (populator->populate != NULL));
+
+ if (strcmp(populator->config_type, config_type) == 0) {
+ INFO("FCONF: Reading firmware configuration information for: %s\n", populator->info);
+ if (populator->populate(config) != 0) {
+ /* TODO: handle property miss */
+ panic();
+ }
+ }
+ }
+}
diff --git a/lib/fconf/fconf.mk b/lib/fconf/fconf.mk
new file mode 100644
index 0000000..fb88910
--- /dev/null
+++ b/lib/fconf/fconf.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2019-2021, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include common/fdt_wrappers.mk
+
+FCONF_SOURCES := lib/fconf/fconf.c
+FCONF_SOURCES += ${FDT_WRAPPERS_SOURCES}
+
+FCONF_DYN_SOURCES := lib/fconf/fconf_dyn_cfg_getter.c
+FCONF_DYN_SOURCES += ${FDT_WRAPPERS_SOURCES}
+
+FCONF_AMU_SOURCES := lib/fconf/fconf_amu_getter.c
+FCONF_AMU_SOURCES += ${FDT_WRAPPERS_SOURCES}
+
+FCONF_MPMM_SOURCES := lib/fconf/fconf_mpmm_getter.c
+FCONF_MPMM_SOURCES += ${FDT_WRAPPERS_SOURCES}
diff --git a/lib/fconf/fconf_amu_getter.c b/lib/fconf/fconf_amu_getter.c
new file mode 100644
index 0000000..eff309c
--- /dev/null
+++ b/lib/fconf/fconf_amu_getter.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_amu_getter.h>
+#include <libfdt.h>
+
+#include <plat/common/platform.h>
+
+struct fconf_amu_config fconf_amu_config;
+static struct amu_topology fconf_amu_topology_;
+
+/*
+ * Populate the core-specific AMU structure with information retrieved from a
+ * device tree.
+ *
+ * Returns `0` on success, or a negative integer representing an error code.
+ */
+static int fconf_populate_amu_cpu_amu(const void *fdt, int parent,
+ struct amu_core *amu)
+{
+ int ret = 0;
+ int node = 0;
+
+ fdt_for_each_subnode(node, fdt, parent) {
+ const char *name;
+ const char *value;
+ int len;
+
+ uintptr_t idx = 0U;
+
+ name = fdt_get_name(fdt, node, &len);
+ if (strncmp(name, "counter@", 8) != 0) {
+ continue;
+ }
+
+ ret = fdt_get_reg_props_by_index(fdt, node, 0, &idx, NULL);
+ if (ret < 0) {
+ break;
+ }
+
+ value = fdt_getprop(fdt, node, "enable-at-el3", &len);
+ if ((value == NULL) && (len != -FDT_ERR_NOTFOUND)) {
+ break;
+ }
+
+ if (len != -FDT_ERR_NOTFOUND) {
+ amu->enable |= (1 << idx);
+ }
+ }
+
+ if ((node < 0) && (node != -FDT_ERR_NOTFOUND)) {
+ return node;
+ }
+
+ return ret;
+}
+
+/*
+ * Within a `cpu` node, attempt to dereference the `amu` property, and populate
+ * the AMU information for the core.
+ *
+ * Returns `0` on success, or a negative integer representing an error code.
+ */
+static int fconf_populate_amu_cpu(const void *fdt, int node, uintptr_t mpidr)
+{
+ int ret;
+ int idx;
+
+ uint32_t amu_phandle;
+ struct amu_core *amu;
+
+ ret = fdt_read_uint32(fdt, node, "amu", &amu_phandle);
+ if (ret < 0) {
+ if (ret == -FDT_ERR_NOTFOUND) {
+ ret = 0;
+ }
+
+ return ret;
+ }
+
+ node = fdt_node_offset_by_phandle(fdt, amu_phandle);
+ if (node < 0) {
+ return node;
+ }
+
+ idx = plat_core_pos_by_mpidr(mpidr);
+ if (idx < 0) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ amu = &fconf_amu_topology_.cores[idx];
+
+ return fconf_populate_amu_cpu_amu(fdt, node, amu);
+}
+
+/*
+ * Populates the global `amu_topology` structure based on what's described by
+ * the hardware configuration device tree blob.
+ *
+ * The device tree is expected to provide an `amu` property for each `cpu` node,
+ * like so:
+ *
+ * cpu@0 {
+ * amu = <&cpu0_amu>;
+ * };
+ *
+ * amus {
+ * cpu0_amu: amu-0 {
+ * counters {
+ * #address-cells = <2>;
+ * #size-cells = <0>;
+ *
+ * counter@x,y {
+ * reg = <x y>; // Group x, counter y
+ * };
+ * };
+ * };
+ * };
+ */
+static int fconf_populate_amu(uintptr_t config)
+{
+ int ret = fdtw_for_each_cpu(
+ (const void *)config, fconf_populate_amu_cpu);
+ if (ret == 0) {
+ fconf_amu_config.topology = &fconf_amu_topology_;
+ } else {
+ ERROR("FCONF: failed to parse AMU information: %d\n", ret);
+ }
+
+ return ret;
+}
+
+FCONF_REGISTER_POPULATOR(HW_CONFIG, amu, fconf_populate_amu);
diff --git a/lib/fconf/fconf_cot_getter.c b/lib/fconf/fconf_cot_getter.c
new file mode 100644
index 0000000..ae59d8c
--- /dev/null
+++ b/lib/fconf/fconf_cot_getter.c
@@ -0,0 +1,497 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+
+#include <common/fdt_wrappers.h>
+#include MBEDTLS_CONFIG_FILE
+#include <drivers/auth/auth_mod.h>
+#include <lib/fconf/fconf.h>
+#include <lib/object_pool.h>
+#include <libfdt.h>
+
+#include <tools_share/tbbr_oid.h>
+
+/* static structures used during authentication process */
+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);
+
+/* pointers to an array of CoT descriptors */
+static const auth_img_desc_t *cot_desc[MAX_NUMBER_IDS];
+/* array of CoT descriptors */
+static auth_img_desc_t auth_img_descs[MAX_NUMBER_IDS];
+
+/* array of authentication methods structures */
+static auth_method_desc_t auth_methods[MAX_NUMBER_IDS * AUTH_METHOD_NUM];
+static OBJECT_POOL_ARRAY(auth_methods_pool, auth_methods);
+
+/* array of authentication params structures */
+static auth_param_desc_t auth_params[MAX_NUMBER_IDS * COT_MAX_VERIFIED_PARAMS];
+static OBJECT_POOL_ARRAY(auth_params_pool, auth_params);
+
+/* array of authentication param type structures */
+static auth_param_type_desc_t auth_param_type_descs[MAX_NUMBER_IDS];
+static OBJECT_POOL_ARRAY(auth_param_type_descs_pool, auth_param_type_descs);
+
+/*
+ * array of OIDs
+ * Object IDs are used to search hash, pk, counter values in certificate.
+ * As per binding we have below 2 combinations:
+ * 1. Certificates are validated using nv-cntr and pk
+ * 2. Raw images are authenticated using hash
+ * Hence in worst case, there are maximum 2 OIDs per image/certificate
+ */
+static unsigned char oids[(MAX_NUMBER_IDS * 2)][MAX_OID_NAME_LEN];
+static OBJECT_POOL_ARRAY(oid_pool, oids);
+
+/* An array of auth buffer which holds hashes and pk
+ * ToDo: Size decided with the current number of images and
+ * certificates which are available in CoT. Size of these buffers bound to
+ * increase in the future on the addition of images/certificates.
+ */
+static unsigned char hash_auth_bufs[20][HASH_DER_LEN];
+static OBJECT_POOL_ARRAY(hash_auth_buf_pool, hash_auth_bufs);
+static unsigned char pk_auth_bufs[12][PK_DER_LEN];
+static OBJECT_POOL_ARRAY(pk_auth_buf_pool, pk_auth_bufs);
+
+/*******************************************************************************
+ * update_parent_auth_data() - Update authentication data structure
+ * @auth_desc[in]: Pointer to the auth image descriptor
+ * @type_desc[in]: Pointer to authentication parameter
+ * @auth_buf_size[in]: Buffer size to hold pk or hash
+ *
+ * Return 0 on success or an error value otherwise.
+ ******************************************************************************/
+static int update_parent_auth_data(const auth_img_desc_t *auth_desc,
+ auth_param_type_desc_t *type_desc,
+ unsigned int auth_buf_size)
+{
+ unsigned int i;
+ auth_param_desc_t *auth_data = &auth_desc->authenticated_data[0];
+ unsigned char *auth_buf;
+
+ for (i = 0U; i < COT_MAX_VERIFIED_PARAMS; i++) {
+ if (auth_data[i].type_desc == type_desc) {
+ return 0;
+ }
+ if (auth_data[i].type_desc == NULL) {
+ break;
+ }
+ }
+
+ if (auth_buf_size == HASH_DER_LEN) {
+ auth_buf = pool_alloc(&hash_auth_buf_pool);
+ } else if (auth_buf_size == PK_DER_LEN) {
+ auth_buf = pool_alloc(&pk_auth_buf_pool);
+ } else {
+ return -1;
+ }
+
+ if (i < COT_MAX_VERIFIED_PARAMS) {
+ auth_data[i].type_desc = type_desc;
+ auth_data[i].data.ptr = auth_buf;
+ auth_data[i].data.len = auth_buf_size;
+ } else {
+ ERROR("Out of authentication data array\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ * get_auth_param_type_desc() - Get pointer of authentication parameter
+ * @img_id[in]: Image Id
+ * @type_desc[out]: Pointer to authentication parameter
+ * @buf_size[out]: Buffer size which hold hash/pk
+ *
+ * Return 0 on success or an error value otherwise.
+ ******************************************************************************/
+static int get_auth_param_type_desc(unsigned int img_id,
+ auth_param_type_desc_t **type_desc,
+ unsigned int *buf_size)
+{
+ auth_method_desc_t *img_auth_method = NULL;
+ img_type_t type = auth_img_descs[img_id].img_type;
+
+ if (type == IMG_CERT) {
+ img_auth_method =
+ &auth_img_descs[img_id].img_auth_methods[AUTH_METHOD_SIG];
+ *type_desc = img_auth_method->param.sig.pk;
+ *buf_size = PK_DER_LEN;
+ } else if (type == IMG_RAW) {
+ img_auth_method =
+ &auth_img_descs[img_id].img_auth_methods[AUTH_METHOD_HASH];
+ *type_desc = img_auth_method->param.hash.hash;
+ *buf_size = HASH_DER_LEN;
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ * set_auth_method() - Update global auth image descriptors with authentication
+ * method data
+ * @auth_method_type[in]: Type of authentication method
+ * @oid[in]: Object Idetifier for pk/hash search
+ * @auth_method[in]: Pointer to authentication method to set
+ ******************************************************************************/
+static void set_auth_method(auth_method_type_t auth_method_type, char *oid,
+ auth_method_desc_t *auth_method)
+{
+ auth_param_type_t auth_param_type = AUTH_PARAM_NONE;
+ auth_param_type_desc_t *auth_param_type_desc;
+
+ assert(auth_method != NULL);
+
+ auth_param_type_desc = pool_alloc(&auth_param_type_descs_pool);
+ auth_method->type = auth_method_type;
+
+ if (auth_method_type == AUTH_METHOD_SIG) {
+ auth_param_type = AUTH_PARAM_PUB_KEY;
+ auth_method->param.sig.sig = &sig;
+ auth_method->param.sig.alg = &sig_alg;
+ auth_method->param.sig.data = &raw_data;
+ auth_method->param.sig.pk = auth_param_type_desc;
+ } else if (auth_method_type == AUTH_METHOD_HASH) {
+ auth_param_type = AUTH_PARAM_HASH;
+ auth_method->param.hash.data = &raw_data;
+ auth_method->param.hash.hash = auth_param_type_desc;
+ } else if (auth_method_type == AUTH_METHOD_NV_CTR) {
+ auth_param_type = AUTH_PARAM_NV_CTR;
+ auth_method->param.nv_ctr.cert_nv_ctr = auth_param_type_desc;
+ auth_method->param.nv_ctr.plat_nv_ctr = auth_param_type_desc;
+ }
+
+ auth_param_type_desc->type = auth_param_type;
+ auth_param_type_desc->cookie = (void *)oid;
+}
+
+/*******************************************************************************
+ * get_oid() - get object identifier from device tree
+ * @dtb[in]: Pointer to the device tree blob in memory
+ * @node[in]: Offset of the node
+ * @prop[in]: Property to read from the given node
+ * @oid[out]: Object Indentifier of key/hash/nv-counter in certificate
+ *
+ * Return 0 on success or an error value otherwise.
+ ******************************************************************************/
+static int get_oid(const void *dtb, int node, const char *prop, char **oid)
+{
+ uint32_t phandle;
+ int rc;
+
+ rc = fdt_read_uint32(dtb, node, prop, &phandle);
+ if (rc < 0) {
+ return rc;
+ }
+
+ node = fdt_node_offset_by_phandle(dtb, phandle);
+ if (node < 0) {
+ return node;
+ }
+
+ *oid = pool_alloc(&oid_pool);
+ rc = fdtw_read_string(dtb, node, "oid", *oid, MAX_OID_NAME_LEN);
+
+ return rc;
+}
+
+/*******************************************************************************
+ * populate_and_set_auth_methods() - Populate auth method parameters from
+ * device tree and set authentication method
+ * structure.
+ * @dtb[in]: Pointer to the device tree blob in memory
+ * @node[in]: Offset of the node
+ * @img_id[in]: Image identifier
+ * @type[in]: Type of image
+ * @root_certificate[in]:Root certificate (authenticated by ROTPK)
+ *
+ * Return 0 on success or an error value otherwise.
+ ******************************************************************************/
+static int populate_and_set_auth_methods(const void *dtb, int node,
+ unsigned int img_id, img_type_t type,
+ bool root_certificate)
+{
+ auth_method_type_t auth_method_type = AUTH_METHOD_NONE;
+ int rc;
+ char *oid = NULL;
+
+ auth_method_desc_t *auth_method = pool_alloc_n(&auth_methods_pool,
+ AUTH_METHOD_NUM);
+
+ /*
+ * This is as per binding document where certificates are
+ * verified by signature and images are verified by hash.
+ */
+ if (type == IMG_CERT) {
+ if (root_certificate) {
+ oid = NULL;
+ } else {
+ rc = get_oid(dtb, node, "signing-key", &oid);
+ if (rc < 0) {
+ ERROR("FCONF: Can't read %s property\n",
+ "signing-key");
+ return rc;
+ }
+ }
+ auth_method_type = AUTH_METHOD_SIG;
+ } else if (type == IMG_RAW) {
+ rc = get_oid(dtb, node, "hash", &oid);
+ if (rc < 0) {
+ ERROR("FCONF: Can't read %s property\n",
+ "hash");
+ return rc;
+ }
+ auth_method_type = AUTH_METHOD_HASH;
+ } else {
+ return -1;
+ }
+
+ set_auth_method(auth_method_type, oid,
+ &auth_method[auth_method_type]);
+
+ /* Retrieve the optional property */
+ rc = get_oid(dtb, node, "antirollback-counter", &oid);
+ if (rc == 0) {
+ auth_method_type = AUTH_METHOD_NV_CTR;
+ set_auth_method(auth_method_type, oid,
+ &auth_method[auth_method_type]);
+ }
+
+ auth_img_descs[img_id].img_auth_methods = &auth_method[0];
+
+ return 0;
+}
+
+/*******************************************************************************
+ * get_parent_img_id() - Get parent image id for given child node
+ * @dtb[in]: Pointer to the device tree blob in memory
+ * @node[in]: Offset of the child node
+ * @parent_img_id[out]: Image id of parent
+ *
+ * Return 0 on success or an error value otherwise.
+ ******************************************************************************/
+static int get_parent_img_id(const void *dtb, int node,
+ unsigned int *parent_img_id)
+{
+ uint32_t phandle;
+ int err;
+
+ err = fdt_read_uint32(dtb, node, "parent", &phandle);
+ if (err < 0) {
+ ERROR("FCONF: Could not read %s property in node\n",
+ "parent");
+ return err;
+ }
+
+ node = fdt_node_offset_by_phandle(dtb, phandle);
+ if (node < 0) {
+ ERROR("FCONF: Failed to locate node using its phandle\n");
+ return node;
+ }
+
+ err = fdt_read_uint32(dtb, node, "image-id", parent_img_id);
+ if (err < 0) {
+ ERROR("FCONF: Could not read %s property in node\n",
+ "image-id");
+ }
+
+ return err;
+}
+
+/*******************************************************************************
+ * set_desc_data() - Update data in descriptor's structure
+ * @dtb[in]: Pointer to the device tree blob in memory
+ * @node[in]: Offset of the node
+ * @type[in]: Type of image (RAW/CERT)
+ *
+ * Return 0 on success or an error value otherwise.
+ ******************************************************************************/
+static int set_desc_data(const void *dtb, int node, img_type_t type)
+{
+ int rc;
+ bool root_certificate = false;
+ unsigned int img_id, parent_img_id;
+
+ rc = fdt_read_uint32(dtb, node, "image-id", &img_id);
+ if (rc < 0) {
+ ERROR("FCONF: Can't find property %s in node\n",
+ "image-id");
+ return rc;
+ }
+
+ if (fdt_getprop(dtb, node, "root-certificate",
+ NULL) != NULL) {
+ root_certificate = true;
+ }
+
+ if (!root_certificate) {
+ rc = get_parent_img_id(dtb, node, &parent_img_id);
+ if (rc < 0) {
+ return rc;
+ }
+ auth_img_descs[img_id].parent = &auth_img_descs[parent_img_id];
+ }
+
+ auth_img_descs[img_id].img_id = img_id;
+ auth_img_descs[img_id].img_type = type;
+
+ rc = populate_and_set_auth_methods(dtb, node, img_id, type,
+ root_certificate);
+ if (rc < 0) {
+ return rc;
+ }
+
+ if (type == IMG_CERT) {
+ auth_param_desc_t *auth_param =
+ pool_alloc_n(&auth_params_pool,
+ COT_MAX_VERIFIED_PARAMS);
+ auth_img_descs[img_id].authenticated_data = &auth_param[0];
+ }
+
+ cot_desc[img_id] = &auth_img_descs[img_id];
+
+ return rc;
+}
+
+/*******************************************************************************
+ * populate_manifest_descs() - Populate CoT descriptors and update global
+ * certificate structures
+ * @dtb[in]: Pointer to the device tree blob in memory
+ *
+ * Return 0 on success or an error value otherwise.
+ ******************************************************************************/
+static int populate_manifest_descs(const void *dtb)
+{
+ int node, child;
+ int rc;
+
+ /*
+ * Assert the node offset points to "arm, cert-descs"
+ * compatible property
+ */
+ const char *compatible_str = "arm, cert-descs";
+
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
+ if (node < 0) {
+ ERROR("FCONF: Can't find %s compatible in node\n",
+ compatible_str);
+ return node;
+ }
+
+ fdt_for_each_subnode(child, dtb, node) {
+ rc = set_desc_data(dtb, child, IMG_CERT);
+ if (rc < 0) {
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ * populate_image_descs() - Populate CoT descriptors and update global
+ * image descriptor structures.
+ * @dtb[in]: Pointer to the device tree blob in memory
+ *
+ * Return 0 on success or an error value otherwise.
+ ******************************************************************************/
+static int populate_image_descs(const void *dtb)
+{
+ int node, child;
+ int rc;
+
+ /*
+ * Assert the node offset points to "arm, img-descs"
+ * compatible property
+ */
+ const char *compatible_str = "arm, img-descs";
+
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
+ if (node < 0) {
+ ERROR("FCONF: Can't find %s compatible in node\n",
+ compatible_str);
+ return node;
+ }
+
+ fdt_for_each_subnode(child, dtb, node) {
+ rc = set_desc_data(dtb, child, IMG_RAW);
+ if (rc < 0) {
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ * fconf_populate_cot_descs() - Populate CoT descriptors and update global
+ * structures
+ * @config[in]: Pointer to the device tree blob in memory
+ *
+ * Return 0 on success or an error value otherwise.
+ ******************************************************************************/
+static int fconf_populate_cot_descs(uintptr_t config)
+{
+ auth_param_type_desc_t *type_desc = NULL;
+ unsigned int auth_buf_size = 0U;
+ int rc;
+
+ /* As libfdt uses void *, we can't avoid this cast */
+ const void *dtb = (void *)config;
+
+ /* populate manifest descs information */
+ rc = populate_manifest_descs(dtb);
+ if (rc < 0) {
+ ERROR("FCONF: population of %s descs failed %d\n",
+ "manifest", rc);
+ return rc;
+ }
+
+ /* populate image descs information */
+ rc = populate_image_descs(dtb);
+ if (rc < 0) {
+ ERROR("FCONF: population of %s descs failed %d\n",
+ "images", rc);
+ return rc;
+ }
+
+ /* update parent's authentication data */
+ for (unsigned int i = 0U; i < MAX_NUMBER_IDS; i++) {
+ if (auth_img_descs[i].parent != NULL) {
+ rc = get_auth_param_type_desc(i,
+ &type_desc,
+ &auth_buf_size);
+ if (rc < 0) {
+ ERROR("FCONF: failed to get auth data %d\n",
+ rc);
+ return rc;
+ }
+
+ rc = update_parent_auth_data(auth_img_descs[i].parent,
+ type_desc,
+ auth_buf_size);
+ if (rc < 0) {
+ ERROR("FCONF: auth data update failed %d\n",
+ rc);
+ return rc;
+ }
+ }
+ }
+
+ return rc;
+}
+
+FCONF_REGISTER_POPULATOR(TB_FW, cot_desc, fconf_populate_cot_descs);
+REGISTER_COT(cot_desc);
diff --git a/lib/fconf/fconf_dyn_cfg_getter.c b/lib/fconf/fconf_dyn_cfg_getter.c
new file mode 100644
index 0000000..351772e
--- /dev/null
+++ b/lib/fconf/fconf_dyn_cfg_getter.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <lib/fconf/fconf_dyn_cfg_getter.h>
+#include <lib/object_pool.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+/* We currently use FW, TB_FW, SOC_FW, TOS_FW, NT_FW and HW configs */
+#define MAX_DTB_INFO U(6)
+/*
+ * Compile time assert if FW_CONFIG_ID is 0 which is more
+ * unlikely as 0 is a valid image ID for FIP as per the current
+ * code but still to avoid code breakage in case of unlikely
+ * event when image IDs get changed.
+ */
+CASSERT(FW_CONFIG_ID != U(0), assert_invalid_fw_config_id);
+
+static struct dyn_cfg_dtb_info_t dtb_infos[MAX_DTB_INFO];
+static OBJECT_POOL_ARRAY(dtb_info_pool, dtb_infos);
+
+/*
+ * This function is used to alloc memory for config information from
+ * global pool and set the configuration information.
+ */
+void set_config_info(uintptr_t config_addr, uintptr_t ns_config_addr,
+ uint32_t config_max_size,
+ unsigned int config_id)
+{
+ struct dyn_cfg_dtb_info_t *dtb_info;
+
+ dtb_info = pool_alloc(&dtb_info_pool);
+ dtb_info->config_addr = config_addr;
+ dtb_info->ns_config_addr = ns_config_addr;
+ dtb_info->config_max_size = config_max_size;
+ dtb_info->config_id = config_id;
+}
+
+/* Get index of the config_id image */
+unsigned int dyn_cfg_dtb_info_get_index(unsigned int config_id)
+{
+ unsigned int index;
+
+ /* Positions index to the proper config-id */
+ for (index = 0U; index < MAX_DTB_INFO; index++) {
+ if (dtb_infos[index].config_id == config_id) {
+ return index;
+ }
+ }
+
+ return FCONF_INVALID_IDX;
+}
+
+struct dyn_cfg_dtb_info_t *dyn_cfg_dtb_info_getter(unsigned int config_id)
+{
+ /* Positions index to the proper config-id */
+ unsigned int index = dyn_cfg_dtb_info_get_index(config_id);
+
+ if (index < MAX_DTB_INFO) {
+ return &dtb_infos[index];
+ }
+
+ WARN("FCONF: Invalid config id %u\n", config_id);
+
+ return NULL;
+}
+
+int fconf_populate_dtb_registry(uintptr_t config)
+{
+ int rc;
+ int node, child;
+
+ /* As libfdt use void *, we can't avoid this cast */
+ const void *dtb = (void *)config;
+
+ /*
+ * In case of BL1, fw_config dtb information is already
+ * populated in global dtb_infos array by 'set_fw_config_info'
+ * function, Below check is present to avoid re-population of
+ * fw_config information.
+ *
+ * Other BLs, satisfy below check and populate fw_config information
+ * in global dtb_infos array.
+ */
+ if (dtb_infos[0].config_id == 0U) {
+ uint32_t config_max_size = fdt_totalsize(dtb);
+ set_config_info(config, ~0UL, config_max_size, FW_CONFIG_ID);
+ }
+
+ /* Find the node offset point to "fconf,dyn_cfg-dtb_registry" compatible property */
+ const char *compatible_str = "fconf,dyn_cfg-dtb_registry";
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
+ if (node < 0) {
+ ERROR("FCONF: Can't find %s compatible in dtb\n", compatible_str);
+ return node;
+ }
+
+ fdt_for_each_subnode(child, dtb, node) {
+ uint32_t config_max_size, config_id;
+ uintptr_t config_addr;
+ uintptr_t ns_config_addr = ~0UL;
+ uint64_t val64;
+
+ /* Read configuration dtb information */
+ rc = fdt_read_uint64(dtb, child, "load-address", &val64);
+ if (rc < 0) {
+ ERROR("FCONF: Incomplete configuration property in dtb-registry.\n");
+ return rc;
+ }
+ config_addr = (uintptr_t)val64;
+
+ rc = fdt_read_uint32(dtb, child, "max-size", &config_max_size);
+ if (rc < 0) {
+ ERROR("FCONF: Incomplete configuration property in dtb-registry.\n");
+ return rc;
+ }
+
+ rc = fdt_read_uint32(dtb, child, "id", &config_id);
+ if (rc < 0) {
+ ERROR("FCONF: Incomplete configuration property in dtb-registry.\n");
+ return rc;
+ }
+
+ VERBOSE("FCONF: dyn_cfg.dtb_registry cell found with:\n");
+ VERBOSE("\tload-address = %lx\n", config_addr);
+ VERBOSE("\tmax-size = 0x%x\n", config_max_size);
+ VERBOSE("\tconfig-id = %u\n", config_id);
+
+ rc = fdt_read_uint64(dtb, child, "ns-load-address", &val64);
+ if (rc == 0) {
+ ns_config_addr = (uintptr_t)val64;
+ VERBOSE("\tns-load-address = %lx\n", ns_config_addr);
+ }
+
+ set_config_info(config_addr, ns_config_addr, config_max_size,
+ config_id);
+ }
+
+ if ((child < 0) && (child != -FDT_ERR_NOTFOUND)) {
+ ERROR("%d: fdt_for_each_subnode(): %d\n", __LINE__, node);
+ return child;
+ }
+
+ return 0;
+}
+
+FCONF_REGISTER_POPULATOR(FW_CONFIG, dyn_cfg, fconf_populate_dtb_registry);
diff --git a/lib/fconf/fconf_mpmm_getter.c b/lib/fconf/fconf_mpmm_getter.c
new file mode 100644
index 0000000..02a566d
--- /dev/null
+++ b/lib/fconf/fconf_mpmm_getter.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_mpmm_getter.h>
+#include <libfdt.h>
+
+#include <plat/common/platform.h>
+
+struct fconf_mpmm_config fconf_mpmm_config;
+static struct mpmm_topology fconf_mpmm_topology;
+
+/*
+ * Within a `cpu` node, determine support for MPMM via the `supports-mpmm`
+ * property.
+ *
+ * Returns `0` on success, or a negative integer representing an error code.
+ */
+static int fconf_populate_mpmm_cpu(const void *fdt, int off, uintptr_t mpidr)
+{
+ int ret, len;
+
+ int core_pos;
+ struct mpmm_core *core;
+
+ core_pos = plat_core_pos_by_mpidr(mpidr);
+ if (core_pos < 0) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ core = &fconf_mpmm_topology.cores[core_pos];
+
+ fdt_getprop(fdt, off, "supports-mpmm", &len);
+ if (len >= 0) {
+ core->supported = true;
+ ret = 0;
+ } else {
+ core->supported = false;
+ ret = len;
+ }
+
+ return ret;
+}
+
+/*
+ * Populates the global `fconf_mpmm_config` structure based on what's described
+ * by the hardware configuration device tree blob.
+ *
+ * The device tree is expected to provide a `supports-mpmm` property for each
+ * `cpu` node, like so:
+ *
+ * cpu@0 {
+ * supports-mpmm;
+ * };
+ *
+ * This property indicates whether the core implements MPMM, as we cannot detect
+ * support for it dynamically.
+ */
+static int fconf_populate_mpmm(uintptr_t config)
+{
+ int ret = fdtw_for_each_cpu(
+ (const void *)config, fconf_populate_mpmm_cpu);
+ if (ret == 0) {
+ fconf_mpmm_config.topology = &fconf_mpmm_topology;
+ } else {
+ ERROR("FCONF: failed to configure MPMM: %d\n", ret);
+ }
+
+ return ret;
+}
+
+FCONF_REGISTER_POPULATOR(HW_CONFIG, mpmm, fconf_populate_mpmm);
diff --git a/lib/fconf/fconf_tbbr_getter.c b/lib/fconf/fconf_tbbr_getter.c
new file mode 100644
index 0000000..c3b4b7e
--- /dev/null
+++ b/lib/fconf/fconf_tbbr_getter.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <lib/fconf/fconf_tbbr_getter.h>
+#include <libfdt.h>
+
+struct tbbr_dyn_config_t tbbr_dyn_config;
+
+int fconf_populate_tbbr_dyn_config(uintptr_t config)
+{
+ int err;
+ int node;
+ uint64_t val64;
+ uint32_t val32;
+
+ /* As libfdt use void *, we can't avoid this cast */
+ const void *dtb = (void *)config;
+
+ /* Assert the node offset point to "arm,tb_fw" compatible property */
+ const char *compatible_str = "arm,tb_fw";
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
+ if (node < 0) {
+ ERROR("FCONF: Can't find `%s` compatible in dtb\n",
+ compatible_str);
+ return node;
+ }
+
+ /* Locate the disable_auth cell and read the value */
+ err = fdt_read_uint32(dtb, node, "disable_auth",
+ &tbbr_dyn_config.disable_auth);
+ if (err < 0) {
+ WARN("FCONF: Read %s failed for `%s`\n",
+ "cell", "disable_auth");
+ return err;
+ }
+
+ /* Check if the value is boolean */
+ if ((tbbr_dyn_config.disable_auth != 0U) &&
+ (tbbr_dyn_config.disable_auth != 1U)) {
+ WARN("Invalid value for `%s` cell %u\n",
+ "disable_auth", tbbr_dyn_config.disable_auth);
+ return -1;
+ }
+
+#if defined(DYN_DISABLE_AUTH)
+ if (tbbr_dyn_config.disable_auth == 1)
+ dyn_disable_auth();
+#endif
+
+ /* Retrieve the Mbed TLS heap details from the DTB */
+ err = fdt_read_uint64(dtb, node, "mbedtls_heap_addr", &val64);
+ if (err < 0) {
+ ERROR("FCONF: Read %s failed for `%s`\n",
+ "cell", "mbedtls_heap_addr");
+ return err;
+ }
+ tbbr_dyn_config.mbedtls_heap_addr = (void *)(uintptr_t)val64;
+
+ err = fdt_read_uint32(dtb, node, "mbedtls_heap_size", &val32);
+ if (err < 0) {
+ ERROR("FCONF: Read %s failed for `%s`\n",
+ "cell", "mbedtls_heap_size");
+ return err;
+ }
+ tbbr_dyn_config.mbedtls_heap_size = val32;
+
+ VERBOSE("%s%s%s %u\n", "FCONF: `tbbr.", "disable_auth",
+ "` cell found with value =", tbbr_dyn_config.disable_auth);
+ VERBOSE("%s%s%s %p\n", "FCONF: `tbbr.", "mbedtls_heap_addr",
+ "` cell found with value =", tbbr_dyn_config.mbedtls_heap_addr);
+ VERBOSE("%s%s%s %zu\n", "FCONF: `tbbr.", "mbedtls_heap_size",
+ "` cell found with value =", tbbr_dyn_config.mbedtls_heap_size);
+
+ return 0;
+}
+
+FCONF_REGISTER_POPULATOR(TB_FW, tbbr, fconf_populate_tbbr_dyn_config);
diff --git a/lib/gpt_rme/gpt_rme.c b/lib/gpt_rme/gpt_rme.c
new file mode 100644
index 0000000..a6e17a3
--- /dev/null
+++ b/lib/gpt_rme/gpt_rme.c
@@ -0,0 +1,1260 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdint.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include "gpt_rme_private.h"
+#include <lib/gpt_rme/gpt_rme.h>
+#include <lib/smccc.h>
+#include <lib/spinlock.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#if !ENABLE_RME
+#error "ENABLE_RME must be enabled to use the GPT library."
+#endif
+
+/*
+ * Lookup T from PPS
+ *
+ * PPS Size T
+ * 0b000 4GB 32
+ * 0b001 64GB 36
+ * 0b010 1TB 40
+ * 0b011 4TB 42
+ * 0b100 16TB 44
+ * 0b101 256TB 48
+ * 0b110 4PB 52
+ *
+ * See section 15.1.27 of the RME specification.
+ */
+static const gpt_t_val_e gpt_t_lookup[] = {PPS_4GB_T, PPS_64GB_T,
+ PPS_1TB_T, PPS_4TB_T,
+ PPS_16TB_T, PPS_256TB_T,
+ PPS_4PB_T};
+
+/*
+ * Lookup P from PGS
+ *
+ * PGS Size P
+ * 0b00 4KB 12
+ * 0b10 16KB 14
+ * 0b01 64KB 16
+ *
+ * Note that pgs=0b10 is 16KB and pgs=0b01 is 64KB, this is not a typo.
+ *
+ * See section 15.1.27 of the RME specification.
+ */
+static const gpt_p_val_e gpt_p_lookup[] = {PGS_4KB_P, PGS_64KB_P, PGS_16KB_P};
+
+/*
+ * This structure contains GPT configuration data.
+ */
+typedef struct {
+ uintptr_t plat_gpt_l0_base;
+ gpccr_pps_e pps;
+ gpt_t_val_e t;
+ gpccr_pgs_e pgs;
+ gpt_p_val_e p;
+} gpt_config_t;
+
+static gpt_config_t gpt_config;
+
+/* These variables are used during initialization of the L1 tables. */
+static unsigned int gpt_next_l1_tbl_idx;
+static uintptr_t gpt_l1_tbl;
+
+/*
+ * This function checks to see if a GPI value is valid.
+ *
+ * These are valid GPI values.
+ * GPT_GPI_NO_ACCESS U(0x0)
+ * GPT_GPI_SECURE U(0x8)
+ * GPT_GPI_NS U(0x9)
+ * GPT_GPI_ROOT U(0xA)
+ * GPT_GPI_REALM U(0xB)
+ * GPT_GPI_ANY U(0xF)
+ *
+ * Parameters
+ * gpi GPI to check for validity.
+ *
+ * Return
+ * true for a valid GPI, false for an invalid one.
+ */
+static bool gpt_is_gpi_valid(unsigned int gpi)
+{
+ if ((gpi == GPT_GPI_NO_ACCESS) || (gpi == GPT_GPI_ANY) ||
+ ((gpi >= GPT_GPI_SECURE) && (gpi <= GPT_GPI_REALM))) {
+ return true;
+ }
+ return false;
+}
+
+/*
+ * This function checks to see if two PAS regions overlap.
+ *
+ * Parameters
+ * base_1: base address of first PAS
+ * size_1: size of first PAS
+ * base_2: base address of second PAS
+ * size_2: size of second PAS
+ *
+ * Return
+ * True if PAS regions overlap, false if they do not.
+ */
+static bool gpt_check_pas_overlap(uintptr_t base_1, size_t size_1,
+ uintptr_t base_2, size_t size_2)
+{
+ if (((base_1 + size_1) > base_2) && ((base_2 + size_2) > base_1)) {
+ return true;
+ }
+ return false;
+}
+
+/*
+ * This helper function checks to see if a PAS region from index 0 to
+ * (pas_idx - 1) occupies the L0 region at index l0_idx in the L0 table.
+ *
+ * Parameters
+ * l0_idx: Index of the L0 entry to check
+ * pas_regions: PAS region array
+ * pas_idx: Upper bound of the PAS array index.
+ *
+ * Return
+ * True if a PAS region occupies the L0 region in question, false if not.
+ */
+static bool gpt_does_previous_pas_exist_here(unsigned int l0_idx,
+ pas_region_t *pas_regions,
+ unsigned int pas_idx)
+{
+ /* Iterate over PAS regions up to pas_idx. */
+ for (unsigned int i = 0U; i < pas_idx; i++) {
+ if (gpt_check_pas_overlap((GPT_L0GPTSZ_ACTUAL_SIZE * l0_idx),
+ GPT_L0GPTSZ_ACTUAL_SIZE,
+ pas_regions[i].base_pa, pas_regions[i].size)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+ * This function iterates over all of the PAS regions and checks them to ensure
+ * proper alignment of base and size, that the GPI is valid, and that no regions
+ * overlap. As a part of the overlap checks, this function checks existing L0
+ * mappings against the new PAS regions in the event that gpt_init_pas_l1_tables
+ * is called multiple times to place L1 tables in different areas of memory. It
+ * also counts the number of L1 tables needed and returns it on success.
+ *
+ * Parameters
+ * *pas_regions Pointer to array of PAS region structures.
+ * pas_region_cnt Total number of PAS regions in the array.
+ *
+ * Return
+ * Negative Linux error code in the event of a failure, number of L1 regions
+ * required when successful.
+ */
+static int gpt_validate_pas_mappings(pas_region_t *pas_regions,
+ unsigned int pas_region_cnt)
+{
+ unsigned int idx;
+ unsigned int l1_cnt = 0U;
+ unsigned int pas_l1_cnt;
+ uint64_t *l0_desc = (uint64_t *)gpt_config.plat_gpt_l0_base;
+
+ assert(pas_regions != NULL);
+ assert(pas_region_cnt != 0U);
+
+ for (idx = 0U; idx < pas_region_cnt; idx++) {
+ /* Check for arithmetic overflow in region. */
+ if ((ULONG_MAX - pas_regions[idx].base_pa) <
+ pas_regions[idx].size) {
+ ERROR("[GPT] Address overflow in PAS[%u]!\n", idx);
+ return -EOVERFLOW;
+ }
+
+ /* Initial checks for PAS validity. */
+ if (((pas_regions[idx].base_pa + pas_regions[idx].size) >
+ GPT_PPS_ACTUAL_SIZE(gpt_config.t)) ||
+ !gpt_is_gpi_valid(GPT_PAS_ATTR_GPI(pas_regions[idx].attrs))) {
+ ERROR("[GPT] PAS[%u] is invalid!\n", idx);
+ return -EFAULT;
+ }
+
+ /*
+ * Make sure this PAS does not overlap with another one. We
+ * start from idx + 1 instead of 0 since prior PAS mappings will
+ * have already checked themselves against this one.
+ */
+ for (unsigned int i = idx + 1; i < pas_region_cnt; i++) {
+ if (gpt_check_pas_overlap(pas_regions[idx].base_pa,
+ pas_regions[idx].size,
+ pas_regions[i].base_pa,
+ pas_regions[i].size)) {
+ ERROR("[GPT] PAS[%u] overlaps with PAS[%u]\n",
+ i, idx);
+ return -EFAULT;
+ }
+ }
+
+ /*
+ * Since this function can be called multiple times with
+ * separate L1 tables we need to check the existing L0 mapping
+ * to see if this PAS would fall into one that has already been
+ * initialized.
+ */
+ for (unsigned int i = GPT_L0_IDX(pas_regions[idx].base_pa);
+ i <= GPT_L0_IDX(pas_regions[idx].base_pa + pas_regions[idx].size - 1);
+ i++) {
+ if ((GPT_L0_TYPE(l0_desc[i]) == GPT_L0_TYPE_BLK_DESC) &&
+ (GPT_L0_BLKD_GPI(l0_desc[i]) == GPT_GPI_ANY)) {
+ /* This descriptor is unused so continue. */
+ continue;
+ }
+
+ /*
+ * This descriptor has been initialized in a previous
+ * call to this function so cannot be initialized again.
+ */
+ ERROR("[GPT] PAS[%u] overlaps with previous L0[%d]!\n",
+ idx, i);
+ return -EFAULT;
+ }
+
+ /* Check for block mapping (L0) type. */
+ if (GPT_PAS_ATTR_MAP_TYPE(pas_regions[idx].attrs) ==
+ GPT_PAS_ATTR_MAP_TYPE_BLOCK) {
+ /* Make sure base and size are block-aligned. */
+ if (!GPT_IS_L0_ALIGNED(pas_regions[idx].base_pa) ||
+ !GPT_IS_L0_ALIGNED(pas_regions[idx].size)) {
+ ERROR("[GPT] PAS[%u] is not block-aligned!\n",
+ idx);
+ return -EFAULT;
+ }
+
+ continue;
+ }
+
+ /* Check for granule mapping (L1) type. */
+ if (GPT_PAS_ATTR_MAP_TYPE(pas_regions[idx].attrs) ==
+ GPT_PAS_ATTR_MAP_TYPE_GRANULE) {
+ /* Make sure base and size are granule-aligned. */
+ if (!GPT_IS_L1_ALIGNED(gpt_config.p, pas_regions[idx].base_pa) ||
+ !GPT_IS_L1_ALIGNED(gpt_config.p, pas_regions[idx].size)) {
+ ERROR("[GPT] PAS[%u] is not granule-aligned!\n",
+ idx);
+ return -EFAULT;
+ }
+
+ /* Find how many L1 tables this PAS occupies. */
+ pas_l1_cnt = (GPT_L0_IDX(pas_regions[idx].base_pa +
+ pas_regions[idx].size - 1) -
+ GPT_L0_IDX(pas_regions[idx].base_pa) + 1);
+
+ /*
+ * This creates a situation where, if multiple PAS
+ * regions occupy the same table descriptor, we can get
+ * an artificially high total L1 table count. The way we
+ * handle this is by checking each PAS against those
+ * before it in the array, and if they both occupy the
+ * same PAS we subtract from pas_l1_cnt and only the
+ * first PAS in the array gets to count it.
+ */
+
+ /*
+ * If L1 count is greater than 1 we know the start and
+ * end PAs are in different L0 regions so we must check
+ * both for overlap against other PAS.
+ */
+ if (pas_l1_cnt > 1) {
+ if (gpt_does_previous_pas_exist_here(
+ GPT_L0_IDX(pas_regions[idx].base_pa +
+ pas_regions[idx].size - 1),
+ pas_regions, idx)) {
+ pas_l1_cnt = pas_l1_cnt - 1;
+ }
+ }
+
+ if (gpt_does_previous_pas_exist_here(
+ GPT_L0_IDX(pas_regions[idx].base_pa),
+ pas_regions, idx)) {
+ pas_l1_cnt = pas_l1_cnt - 1;
+ }
+
+ l1_cnt += pas_l1_cnt;
+ continue;
+ }
+
+ /* If execution reaches this point, mapping type is invalid. */
+ ERROR("[GPT] PAS[%u] has invalid mapping type 0x%x.\n", idx,
+ GPT_PAS_ATTR_MAP_TYPE(pas_regions[idx].attrs));
+ return -EINVAL;
+ }
+
+ return l1_cnt;
+}
+
+/*
+ * This function validates L0 initialization parameters.
+ *
+ * Parameters
+ * l0_mem_base Base address of memory used for L0 tables.
+ * l1_mem_size Size of memory available for L0 tables.
+ *
+ * Return
+ * Negative Linux error code in the event of a failure, 0 for success.
+ */
+static int gpt_validate_l0_params(gpccr_pps_e pps, uintptr_t l0_mem_base,
+ size_t l0_mem_size)
+{
+ size_t l0_alignment;
+
+ /*
+ * Make sure PPS is valid and then store it since macros need this value
+ * to work.
+ */
+ if (pps > GPT_PPS_MAX) {
+ ERROR("[GPT] Invalid PPS: 0x%x\n", pps);
+ return -EINVAL;
+ }
+ gpt_config.pps = pps;
+ gpt_config.t = gpt_t_lookup[pps];
+
+ /* Alignment must be the greater of 4k or l0 table size. */
+ l0_alignment = PAGE_SIZE_4KB;
+ if (l0_alignment < GPT_L0_TABLE_SIZE(gpt_config.t)) {
+ l0_alignment = GPT_L0_TABLE_SIZE(gpt_config.t);
+ }
+
+ /* Check base address. */
+ if ((l0_mem_base == 0U) || ((l0_mem_base & (l0_alignment - 1)) != 0U)) {
+ ERROR("[GPT] Invalid L0 base address: 0x%lx\n", l0_mem_base);
+ return -EFAULT;
+ }
+
+ /* Check size. */
+ if (l0_mem_size < GPT_L0_TABLE_SIZE(gpt_config.t)) {
+ ERROR("[GPT] Inadequate L0 memory: need 0x%lx, have 0x%lx)\n",
+ GPT_L0_TABLE_SIZE(gpt_config.t),
+ l0_mem_size);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/*
+ * In the event that L1 tables are needed, this function validates
+ * the L1 table generation parameters.
+ *
+ * Parameters
+ * l1_mem_base Base address of memory used for L1 table allocation.
+ * l1_mem_size Total size of memory available for L1 tables.
+ * l1_gpt_cnt Number of L1 tables needed.
+ *
+ * Return
+ * Negative Linux error code in the event of a failure, 0 for success.
+ */
+static int gpt_validate_l1_params(uintptr_t l1_mem_base, size_t l1_mem_size,
+ unsigned int l1_gpt_cnt)
+{
+ size_t l1_gpt_mem_sz;
+
+ /* Check if the granularity is supported */
+ if (!xlat_arch_is_granule_size_supported(
+ GPT_PGS_ACTUAL_SIZE(gpt_config.p))) {
+ return -EPERM;
+ }
+
+ /* Make sure L1 tables are aligned to their size. */
+ if ((l1_mem_base & (GPT_L1_TABLE_SIZE(gpt_config.p) - 1)) != 0U) {
+ ERROR("[GPT] Unaligned L1 GPT base address: 0x%lx\n",
+ l1_mem_base);
+ return -EFAULT;
+ }
+
+ /* Get total memory needed for L1 tables. */
+ l1_gpt_mem_sz = l1_gpt_cnt * GPT_L1_TABLE_SIZE(gpt_config.p);
+
+ /* Check for overflow. */
+ if ((l1_gpt_mem_sz / GPT_L1_TABLE_SIZE(gpt_config.p)) != l1_gpt_cnt) {
+ ERROR("[GPT] Overflow calculating L1 memory size.\n");
+ return -ENOMEM;
+ }
+
+ /* Make sure enough space was supplied. */
+ if (l1_mem_size < l1_gpt_mem_sz) {
+ ERROR("[GPT] Inadequate memory for L1 GPTs. ");
+ ERROR(" Expected 0x%lx bytes. Got 0x%lx bytes\n",
+ l1_gpt_mem_sz, l1_mem_size);
+ return -ENOMEM;
+ }
+
+ VERBOSE("[GPT] Requested 0x%lx bytes for L1 GPTs.\n", l1_gpt_mem_sz);
+ return 0;
+}
+
+/*
+ * This function initializes L0 block descriptors (regions that cannot be
+ * transitioned at the granule level) according to the provided PAS.
+ *
+ * Parameters
+ * *pas Pointer to the structure defining the PAS region to
+ * initialize.
+ */
+static void gpt_generate_l0_blk_desc(pas_region_t *pas)
+{
+ uint64_t gpt_desc;
+ unsigned int end_idx;
+ unsigned int idx;
+ uint64_t *l0_gpt_arr;
+
+ assert(gpt_config.plat_gpt_l0_base != 0U);
+ assert(pas != NULL);
+
+ /*
+ * Checking of PAS parameters has already been done in
+ * gpt_validate_pas_mappings so no need to check the same things again.
+ */
+
+ l0_gpt_arr = (uint64_t *)gpt_config.plat_gpt_l0_base;
+
+ /* Create the GPT Block descriptor for this PAS region */
+ gpt_desc = GPT_L0_BLK_DESC(GPT_PAS_ATTR_GPI(pas->attrs));
+
+ /* Start index of this region in L0 GPTs */
+ idx = GPT_L0_IDX(pas->base_pa);
+
+ /*
+ * Determine number of L0 GPT descriptors covered by
+ * this PAS region and use the count to populate these
+ * descriptors.
+ */
+ end_idx = GPT_L0_IDX(pas->base_pa + pas->size);
+
+ /* Generate the needed block descriptors. */
+ for (; idx < end_idx; idx++) {
+ l0_gpt_arr[idx] = gpt_desc;
+ VERBOSE("[GPT] L0 entry (BLOCK) index %u [%p]: GPI = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
+ idx, &l0_gpt_arr[idx],
+ (gpt_desc >> GPT_L0_BLK_DESC_GPI_SHIFT) &
+ GPT_L0_BLK_DESC_GPI_MASK, l0_gpt_arr[idx]);
+ }
+}
+
+/*
+ * Helper function to determine if the end physical address lies in the same L0
+ * region as the current physical address. If true, the end physical address is
+ * returned else, the start address of the next region is returned.
+ *
+ * Parameters
+ * cur_pa Physical address of the current PA in the loop through
+ * the range.
+ * end_pa Physical address of the end PA in a PAS range.
+ *
+ * Return
+ * The PA of the end of the current range.
+ */
+static uintptr_t gpt_get_l1_end_pa(uintptr_t cur_pa, uintptr_t end_pa)
+{
+ uintptr_t cur_idx;
+ uintptr_t end_idx;
+
+ cur_idx = GPT_L0_IDX(cur_pa);
+ end_idx = GPT_L0_IDX(end_pa);
+
+ assert(cur_idx <= end_idx);
+
+ if (cur_idx == end_idx) {
+ return end_pa;
+ }
+
+ return (cur_idx + 1U) << GPT_L0_IDX_SHIFT;
+}
+
+/*
+ * Helper function to fill out GPI entries in a single L1 table. This function
+ * fills out entire L1 descriptors at a time to save memory writes.
+ *
+ * Parameters
+ * gpi GPI to set this range to
+ * l1 Pointer to L1 table to fill out
+ * first Address of first granule in range.
+ * last Address of last granule in range (inclusive).
+ */
+static void gpt_fill_l1_tbl(uint64_t gpi, uint64_t *l1, uintptr_t first,
+ uintptr_t last)
+{
+ uint64_t gpi_field = GPT_BUILD_L1_DESC(gpi);
+ uint64_t gpi_mask = 0xFFFFFFFFFFFFFFFF;
+
+ assert(first <= last);
+ assert((first & (GPT_PGS_ACTUAL_SIZE(gpt_config.p) - 1)) == 0U);
+ assert((last & (GPT_PGS_ACTUAL_SIZE(gpt_config.p) - 1)) == 0U);
+ assert(GPT_L0_IDX(first) == GPT_L0_IDX(last));
+ assert(l1 != NULL);
+
+ /* Shift the mask if we're starting in the middle of an L1 entry. */
+ gpi_mask = gpi_mask << (GPT_L1_GPI_IDX(gpt_config.p, first) << 2);
+
+ /* Fill out each L1 entry for this region. */
+ for (unsigned int i = GPT_L1_IDX(gpt_config.p, first);
+ i <= GPT_L1_IDX(gpt_config.p, last); i++) {
+ /* Account for stopping in the middle of an L1 entry. */
+ if (i == GPT_L1_IDX(gpt_config.p, last)) {
+ gpi_mask &= (gpi_mask >> ((15 -
+ GPT_L1_GPI_IDX(gpt_config.p, last)) << 2));
+ }
+
+ /* Write GPI values. */
+ assert((l1[i] & gpi_mask) ==
+ (GPT_BUILD_L1_DESC(GPT_GPI_ANY) & gpi_mask));
+ l1[i] = (l1[i] & ~gpi_mask) | (gpi_mask & gpi_field);
+
+ /* Reset mask. */
+ gpi_mask = 0xFFFFFFFFFFFFFFFF;
+ }
+}
+
+/*
+ * This function finds the next available unused L1 table and initializes all
+ * granules descriptor entries to GPI_ANY. This ensures that there are no chunks
+ * of GPI_NO_ACCESS (0b0000) memory floating around in the system in the
+ * event that a PAS region stops midway through an L1 table, thus guaranteeing
+ * that all memory not explicitly assigned is GPI_ANY. This function does not
+ * check for overflow conditions, that should be done by the caller.
+ *
+ * Return
+ * Pointer to the next available L1 table.
+ */
+static uint64_t *gpt_get_new_l1_tbl(void)
+{
+ /* Retrieve the next L1 table. */
+ uint64_t *l1 = (uint64_t *)((uint64_t)(gpt_l1_tbl) +
+ (GPT_L1_TABLE_SIZE(gpt_config.p) *
+ gpt_next_l1_tbl_idx));
+
+ /* Increment L1 counter. */
+ gpt_next_l1_tbl_idx++;
+
+ /* Initialize all GPIs to GPT_GPI_ANY */
+ for (unsigned int i = 0U; i < GPT_L1_ENTRY_COUNT(gpt_config.p); i++) {
+ l1[i] = GPT_BUILD_L1_DESC(GPT_GPI_ANY);
+ }
+
+ return l1;
+}
+
+/*
+ * When L1 tables are needed, this function creates the necessary L0 table
+ * descriptors and fills out the L1 table entries according to the supplied
+ * PAS range.
+ *
+ * Parameters
+ * *pas Pointer to the structure defining the PAS region.
+ */
+static void gpt_generate_l0_tbl_desc(pas_region_t *pas)
+{
+ uintptr_t end_pa;
+ uintptr_t cur_pa;
+ uintptr_t last_gran_pa;
+ uint64_t *l0_gpt_base;
+ uint64_t *l1_gpt_arr;
+ unsigned int l0_idx;
+
+ assert(gpt_config.plat_gpt_l0_base != 0U);
+ assert(pas != NULL);
+
+ /*
+ * Checking of PAS parameters has already been done in
+ * gpt_validate_pas_mappings so no need to check the same things again.
+ */
+
+ end_pa = pas->base_pa + pas->size;
+ l0_gpt_base = (uint64_t *)gpt_config.plat_gpt_l0_base;
+
+ /* We start working from the granule at base PA */
+ cur_pa = pas->base_pa;
+
+ /* Iterate over each L0 region in this memory range. */
+ for (l0_idx = GPT_L0_IDX(pas->base_pa);
+ l0_idx <= GPT_L0_IDX(end_pa - 1U);
+ l0_idx++) {
+
+ /*
+ * See if the L0 entry is already a table descriptor or if we
+ * need to create one.
+ */
+ if (GPT_L0_TYPE(l0_gpt_base[l0_idx]) == GPT_L0_TYPE_TBL_DESC) {
+ /* Get the L1 array from the L0 entry. */
+ l1_gpt_arr = GPT_L0_TBLD_ADDR(l0_gpt_base[l0_idx]);
+ } else {
+ /* Get a new L1 table from the L1 memory space. */
+ l1_gpt_arr = gpt_get_new_l1_tbl();
+
+ /* Fill out the L0 descriptor and flush it. */
+ l0_gpt_base[l0_idx] = GPT_L0_TBL_DESC(l1_gpt_arr);
+ }
+
+ VERBOSE("[GPT] L0 entry (TABLE) index %u [%p] ==> L1 Addr 0x%llx (0x%" PRIx64 ")\n",
+ l0_idx, &l0_gpt_base[l0_idx],
+ (unsigned long long)(l1_gpt_arr),
+ l0_gpt_base[l0_idx]);
+
+ /*
+ * Determine the PA of the last granule in this L0 descriptor.
+ */
+ last_gran_pa = gpt_get_l1_end_pa(cur_pa, end_pa) -
+ GPT_PGS_ACTUAL_SIZE(gpt_config.p);
+
+ /*
+ * Fill up L1 GPT entries between these two addresses. This
+ * function needs the addresses of the first granule and last
+ * granule in the range.
+ */
+ gpt_fill_l1_tbl(GPT_PAS_ATTR_GPI(pas->attrs), l1_gpt_arr,
+ cur_pa, last_gran_pa);
+
+ /* Advance cur_pa to first granule in next L0 region. */
+ cur_pa = gpt_get_l1_end_pa(cur_pa, end_pa);
+ }
+}
+
+/*
+ * This function flushes a range of L0 descriptors used by a given PAS region
+ * array. There is a chance that some unmodified L0 descriptors would be flushed
+ * in the case that there are "holes" in an array of PAS regions but overall
+ * this should be faster than individually flushing each modified L0 descriptor
+ * as they are created.
+ *
+ * Parameters
+ * *pas Pointer to an array of PAS regions.
+ * pas_count Number of entries in the PAS array.
+ */
+static void flush_l0_for_pas_array(pas_region_t *pas, unsigned int pas_count)
+{
+ unsigned int idx;
+ unsigned int start_idx;
+ unsigned int end_idx;
+ uint64_t *l0 = (uint64_t *)gpt_config.plat_gpt_l0_base;
+
+ assert(pas != NULL);
+ assert(pas_count > 0);
+
+ /* Initial start and end values. */
+ start_idx = GPT_L0_IDX(pas[0].base_pa);
+ end_idx = GPT_L0_IDX(pas[0].base_pa + pas[0].size - 1);
+
+ /* Find lowest and highest L0 indices used in this PAS array. */
+ for (idx = 1; idx < pas_count; idx++) {
+ if (GPT_L0_IDX(pas[idx].base_pa) < start_idx) {
+ start_idx = GPT_L0_IDX(pas[idx].base_pa);
+ }
+ if (GPT_L0_IDX(pas[idx].base_pa + pas[idx].size - 1) > end_idx) {
+ end_idx = GPT_L0_IDX(pas[idx].base_pa + pas[idx].size - 1);
+ }
+ }
+
+ /*
+ * Flush all covered L0 descriptors, add 1 because we need to include
+ * the end index value.
+ */
+ flush_dcache_range((uintptr_t)&l0[start_idx],
+ ((end_idx + 1) - start_idx) * sizeof(uint64_t));
+}
+
+/*
+ * Public API to enable granule protection checks once the tables have all been
+ * initialized. This function is called at first initialization and then again
+ * later during warm boots of CPU cores.
+ *
+ * Return
+ * Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_enable(void)
+{
+ u_register_t gpccr_el3;
+
+ /*
+ * Granule tables must be initialised before enabling
+ * granule protection.
+ */
+ if (gpt_config.plat_gpt_l0_base == 0U) {
+ ERROR("[GPT] Tables have not been initialized!\n");
+ return -EPERM;
+ }
+
+ /* Write the base address of the L0 tables into GPTBR */
+ write_gptbr_el3(((gpt_config.plat_gpt_l0_base >> GPTBR_BADDR_VAL_SHIFT)
+ >> GPTBR_BADDR_SHIFT) & GPTBR_BADDR_MASK);
+
+ /* GPCCR_EL3.PPS */
+ gpccr_el3 = SET_GPCCR_PPS(gpt_config.pps);
+
+ /* GPCCR_EL3.PGS */
+ gpccr_el3 |= SET_GPCCR_PGS(gpt_config.pgs);
+
+ /*
+ * Since EL3 maps the L1 region as Inner shareable, use the same
+ * shareability attribute for GPC as well so that
+ * GPC fetches are visible to PEs
+ */
+ gpccr_el3 |= SET_GPCCR_SH(GPCCR_SH_IS);
+
+ /* Outer and Inner cacheability set to Normal memory, WB, RA, WA. */
+ gpccr_el3 |= SET_GPCCR_ORGN(GPCCR_ORGN_WB_RA_WA);
+ gpccr_el3 |= SET_GPCCR_IRGN(GPCCR_IRGN_WB_RA_WA);
+
+ /* Prepopulate GPCCR_EL3 but don't enable GPC yet */
+ write_gpccr_el3(gpccr_el3);
+ isb();
+
+ /* Invalidate any stale TLB entries and any cached register fields */
+ tlbipaallos();
+ dsb();
+ isb();
+
+ /* Enable GPT */
+ gpccr_el3 |= GPCCR_GPC_BIT;
+
+ /* TODO: Configure GPCCR_EL3_GPCP for Fault control. */
+ write_gpccr_el3(gpccr_el3);
+ isb();
+ tlbipaallos();
+ dsb();
+ isb();
+
+ return 0;
+}
+
+/*
+ * Public API to disable granule protection checks.
+ */
+void gpt_disable(void)
+{
+ u_register_t gpccr_el3 = read_gpccr_el3();
+
+ write_gpccr_el3(gpccr_el3 & ~GPCCR_GPC_BIT);
+ dsbsy();
+ isb();
+}
+
+/*
+ * Public API that initializes the entire protected space to GPT_GPI_ANY using
+ * the L0 tables (block descriptors). Ideally, this function is invoked prior
+ * to DDR discovery and initialization. The MMU must be initialized before
+ * calling this function.
+ *
+ * Parameters
+ * pps PPS value to use for table generation
+ * l0_mem_base Base address of L0 tables in memory.
+ * l0_mem_size Total size of memory available for L0 tables.
+ *
+ * Return
+ * Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_init_l0_tables(unsigned int pps, uintptr_t l0_mem_base,
+ size_t l0_mem_size)
+{
+ int ret;
+ uint64_t gpt_desc;
+
+ /* Ensure that MMU and Data caches are enabled. */
+ assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
+
+ /* Validate other parameters. */
+ ret = gpt_validate_l0_params(pps, l0_mem_base, l0_mem_size);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Create the descriptor to initialize L0 entries with. */
+ gpt_desc = GPT_L0_BLK_DESC(GPT_GPI_ANY);
+
+ /* Iterate through all L0 entries */
+ for (unsigned int i = 0U; i < GPT_L0_REGION_COUNT(gpt_config.t); i++) {
+ ((uint64_t *)l0_mem_base)[i] = gpt_desc;
+ }
+
+ /* Flush updated L0 tables to memory. */
+ flush_dcache_range((uintptr_t)l0_mem_base,
+ (size_t)GPT_L0_TABLE_SIZE(gpt_config.t));
+
+ /* Stash the L0 base address once initial setup is complete. */
+ gpt_config.plat_gpt_l0_base = l0_mem_base;
+
+ return 0;
+}
+
+/*
+ * Public API that carves out PAS regions from the L0 tables and builds any L1
+ * tables that are needed. This function ideally is run after DDR discovery and
+ * initialization. The L0 tables must have already been initialized to GPI_ANY
+ * when this function is called.
+ *
+ * This function can be called multiple times with different L1 memory ranges
+ * and PAS regions if it is desirable to place L1 tables in different locations
+ * in memory. (ex: you have multiple DDR banks and want to place the L1 tables
+ * in the DDR bank that they control)
+ *
+ * Parameters
+ * pgs PGS value to use for table generation.
+ * l1_mem_base Base address of memory used for L1 tables.
+ * l1_mem_size Total size of memory available for L1 tables.
+ * *pas_regions Pointer to PAS regions structure array.
+ * pas_count Total number of PAS regions.
+ *
+ * Return
+ * Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_init_pas_l1_tables(gpccr_pgs_e pgs, uintptr_t l1_mem_base,
+ size_t l1_mem_size, pas_region_t *pas_regions,
+ unsigned int pas_count)
+{
+ int ret;
+ int l1_gpt_cnt;
+
+ /* Ensure that MMU and Data caches are enabled. */
+ assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
+
+ /* PGS is needed for gpt_validate_pas_mappings so check it now. */
+ if (pgs > GPT_PGS_MAX) {
+ ERROR("[GPT] Invalid PGS: 0x%x\n", pgs);
+ return -EINVAL;
+ }
+ gpt_config.pgs = pgs;
+ gpt_config.p = gpt_p_lookup[pgs];
+
+ /* Make sure L0 tables have been initialized. */
+ if (gpt_config.plat_gpt_l0_base == 0U) {
+ ERROR("[GPT] L0 tables must be initialized first!\n");
+ return -EPERM;
+ }
+
+ /* Check if L1 GPTs are required and how many. */
+ l1_gpt_cnt = gpt_validate_pas_mappings(pas_regions, pas_count);
+ if (l1_gpt_cnt < 0) {
+ return l1_gpt_cnt;
+ }
+
+ VERBOSE("[GPT] %u L1 GPTs requested.\n", l1_gpt_cnt);
+
+ /* If L1 tables are needed then validate the L1 parameters. */
+ if (l1_gpt_cnt > 0) {
+ ret = gpt_validate_l1_params(l1_mem_base, l1_mem_size,
+ l1_gpt_cnt);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Set up parameters for L1 table generation. */
+ gpt_l1_tbl = l1_mem_base;
+ gpt_next_l1_tbl_idx = 0U;
+ }
+
+ INFO("[GPT] Boot Configuration\n");
+ INFO(" PPS/T: 0x%x/%u\n", gpt_config.pps, gpt_config.t);
+ INFO(" PGS/P: 0x%x/%u\n", gpt_config.pgs, gpt_config.p);
+ INFO(" L0GPTSZ/S: 0x%x/%u\n", GPT_L0GPTSZ, GPT_S_VAL);
+ INFO(" PAS count: 0x%x\n", pas_count);
+ INFO(" L0 base: 0x%lx\n", gpt_config.plat_gpt_l0_base);
+
+ /* Generate the tables in memory. */
+ for (unsigned int idx = 0U; idx < pas_count; idx++) {
+ INFO("[GPT] PAS[%u]: base 0x%lx, size 0x%lx, GPI 0x%x, type 0x%x\n",
+ idx, pas_regions[idx].base_pa, pas_regions[idx].size,
+ GPT_PAS_ATTR_GPI(pas_regions[idx].attrs),
+ GPT_PAS_ATTR_MAP_TYPE(pas_regions[idx].attrs));
+
+ /* Check if a block or table descriptor is required */
+ if (GPT_PAS_ATTR_MAP_TYPE(pas_regions[idx].attrs) ==
+ GPT_PAS_ATTR_MAP_TYPE_BLOCK) {
+ gpt_generate_l0_blk_desc(&pas_regions[idx]);
+
+ } else {
+ gpt_generate_l0_tbl_desc(&pas_regions[idx]);
+ }
+ }
+
+ /* Flush modified L0 tables. */
+ flush_l0_for_pas_array(pas_regions, pas_count);
+
+ /* Flush L1 tables if needed. */
+ if (l1_gpt_cnt > 0) {
+ flush_dcache_range(l1_mem_base,
+ GPT_L1_TABLE_SIZE(gpt_config.p) *
+ l1_gpt_cnt);
+ }
+
+ /* Make sure that all the entries are written to the memory. */
+ dsbishst();
+ tlbipaallos();
+ dsb();
+ isb();
+
+ return 0;
+}
+
+/*
+ * Public API to initialize the runtime gpt_config structure based on the values
+ * present in the GPTBR_EL3 and GPCCR_EL3 registers. GPT initialization
+ * typically happens in a bootloader stage prior to setting up the EL3 runtime
+ * environment for the granule transition service so this function detects the
+ * initialization from a previous stage. Granule protection checks must be
+ * enabled already or this function will return an error.
+ *
+ * Return
+ * Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_runtime_init(void)
+{
+ u_register_t reg;
+
+ /* Ensure that MMU and Data caches are enabled. */
+ assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
+
+ /* Ensure GPC are already enabled. */
+ if ((read_gpccr_el3() & GPCCR_GPC_BIT) == 0U) {
+ ERROR("[GPT] Granule protection checks are not enabled!\n");
+ return -EPERM;
+ }
+
+ /*
+ * Read the L0 table address from GPTBR, we don't need the L1 base
+ * address since those are included in the L0 tables as needed.
+ */
+ reg = read_gptbr_el3();
+ gpt_config.plat_gpt_l0_base = ((reg >> GPTBR_BADDR_SHIFT) &
+ GPTBR_BADDR_MASK) <<
+ GPTBR_BADDR_VAL_SHIFT;
+
+ /* Read GPCCR to get PGS and PPS values. */
+ reg = read_gpccr_el3();
+ gpt_config.pps = (reg >> GPCCR_PPS_SHIFT) & GPCCR_PPS_MASK;
+ gpt_config.t = gpt_t_lookup[gpt_config.pps];
+ gpt_config.pgs = (reg >> GPCCR_PGS_SHIFT) & GPCCR_PGS_MASK;
+ gpt_config.p = gpt_p_lookup[gpt_config.pgs];
+
+ VERBOSE("[GPT] Runtime Configuration\n");
+ VERBOSE(" PPS/T: 0x%x/%u\n", gpt_config.pps, gpt_config.t);
+ VERBOSE(" PGS/P: 0x%x/%u\n", gpt_config.pgs, gpt_config.p);
+ VERBOSE(" L0GPTSZ/S: 0x%x/%u\n", GPT_L0GPTSZ, GPT_S_VAL);
+ VERBOSE(" L0 base: 0x%lx\n", gpt_config.plat_gpt_l0_base);
+
+ return 0;
+}
+
+/*
+ * The L1 descriptors are protected by a spinlock to ensure that multiple
+ * CPUs do not attempt to change the descriptors at once. In the future it
+ * would be better to have separate spinlocks for each L1 descriptor.
+ */
+static spinlock_t gpt_lock;
+
+/*
+ * A helper to write the value (target_pas << gpi_shift) to the index of
+ * the gpt_l1_addr
+ */
+static inline void write_gpt(uint64_t *gpt_l1_desc, uint64_t *gpt_l1_addr,
+ unsigned int gpi_shift, unsigned int idx,
+ unsigned int target_pas)
+{
+ *gpt_l1_desc &= ~(GPT_L1_GRAN_DESC_GPI_MASK << gpi_shift);
+ *gpt_l1_desc |= ((uint64_t)target_pas << gpi_shift);
+ gpt_l1_addr[idx] = *gpt_l1_desc;
+}
+
+/*
+ * Helper to retrieve the gpt_l1_* information from the base address
+ * returned in gpi_info
+ */
+static int get_gpi_params(uint64_t base, gpi_info_t *gpi_info)
+{
+ uint64_t gpt_l0_desc, *gpt_l0_base;
+
+ gpt_l0_base = (uint64_t *)gpt_config.plat_gpt_l0_base;
+ gpt_l0_desc = gpt_l0_base[GPT_L0_IDX(base)];
+ if (GPT_L0_TYPE(gpt_l0_desc) != GPT_L0_TYPE_TBL_DESC) {
+ VERBOSE("[GPT] Granule is not covered by a table descriptor!\n");
+ VERBOSE(" Base=0x%" PRIx64 "\n", base);
+ return -EINVAL;
+ }
+
+ /* Get the table index and GPI shift from PA. */
+ gpi_info->gpt_l1_addr = GPT_L0_TBLD_ADDR(gpt_l0_desc);
+ gpi_info->idx = GPT_L1_IDX(gpt_config.p, base);
+ gpi_info->gpi_shift = GPT_L1_GPI_IDX(gpt_config.p, base) << 2;
+
+ gpi_info->gpt_l1_desc = (gpi_info->gpt_l1_addr)[gpi_info->idx];
+ gpi_info->gpi = (gpi_info->gpt_l1_desc >> gpi_info->gpi_shift) &
+ GPT_L1_GRAN_DESC_GPI_MASK;
+ return 0;
+}
+
+/*
+ * This function is the granule transition delegate service. When a granule
+ * transition request occurs it is routed to this function to have the request,
+ * if valid, fulfilled following A1.1.1 Delegate of RME supplement
+ *
+ * TODO: implement support for transitioning multiple granules at once.
+ *
+ * Parameters
+ * base Base address of the region to transition, must be
+ * aligned to granule size.
+ * size Size of region to transition, must be aligned to granule
+ * size.
+ * src_sec_state Security state of the caller.
+ *
+ * Return
+ * Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_delegate_pas(uint64_t base, size_t size, unsigned int src_sec_state)
+{
+ gpi_info_t gpi_info;
+ uint64_t nse;
+ int res;
+ unsigned int target_pas;
+
+ /* Ensure that the tables have been set up before taking requests. */
+ assert(gpt_config.plat_gpt_l0_base != 0UL);
+
+ /* Ensure that caches are enabled. */
+ assert((read_sctlr_el3() & SCTLR_C_BIT) != 0UL);
+
+ /* Delegate request can only come from REALM or SECURE */
+ assert(src_sec_state == SMC_FROM_REALM ||
+ src_sec_state == SMC_FROM_SECURE);
+
+ /* See if this is a single or a range of granule transition. */
+ if (size != GPT_PGS_ACTUAL_SIZE(gpt_config.p)) {
+ return -EINVAL;
+ }
+
+ /* Check that base and size are valid */
+ if ((ULONG_MAX - base) < size) {
+ VERBOSE("[GPT] Transition request address overflow!\n");
+ VERBOSE(" Base=0x%" PRIx64 "\n", base);
+ VERBOSE(" Size=0x%lx\n", size);
+ return -EINVAL;
+ }
+
+ /* Make sure base and size are valid. */
+ if (((base & (GPT_PGS_ACTUAL_SIZE(gpt_config.p) - 1)) != 0UL) ||
+ ((size & (GPT_PGS_ACTUAL_SIZE(gpt_config.p) - 1)) != 0UL) ||
+ (size == 0UL) ||
+ ((base + size) >= GPT_PPS_ACTUAL_SIZE(gpt_config.t))) {
+ VERBOSE("[GPT] Invalid granule transition address range!\n");
+ VERBOSE(" Base=0x%" PRIx64 "\n", base);
+ VERBOSE(" Size=0x%lx\n", size);
+ return -EINVAL;
+ }
+
+ target_pas = GPT_GPI_REALM;
+ if (src_sec_state == SMC_FROM_SECURE) {
+ target_pas = GPT_GPI_SECURE;
+ }
+
+ /*
+ * Access to L1 tables is controlled by a global lock to ensure
+ * that no more than one CPU is allowed to make changes at any
+ * given time.
+ */
+ spin_lock(&gpt_lock);
+ res = get_gpi_params(base, &gpi_info);
+ if (res != 0) {
+ spin_unlock(&gpt_lock);
+ return res;
+ }
+
+ /* Check that the current address is in NS state */
+ if (gpi_info.gpi != GPT_GPI_NS) {
+ VERBOSE("[GPT] Only Granule in NS state can be delegated.\n");
+ VERBOSE(" Caller: %u, Current GPI: %u\n", src_sec_state,
+ gpi_info.gpi);
+ spin_unlock(&gpt_lock);
+ return -EPERM;
+ }
+
+ if (src_sec_state == SMC_FROM_SECURE) {
+ nse = (uint64_t)GPT_NSE_SECURE << GPT_NSE_SHIFT;
+ } else {
+ nse = (uint64_t)GPT_NSE_REALM << GPT_NSE_SHIFT;
+ }
+
+ /*
+ * In order to maintain mutual distrust between Realm and Secure
+ * states, remove any data speculatively fetched into the target
+ * physical address space. Issue DC CIPAPA over address range
+ */
+ flush_dcache_to_popa_range(nse | base,
+ GPT_PGS_ACTUAL_SIZE(gpt_config.p));
+
+ write_gpt(&gpi_info.gpt_l1_desc, gpi_info.gpt_l1_addr,
+ gpi_info.gpi_shift, gpi_info.idx, target_pas);
+ dsboshst();
+
+ gpt_tlbi_by_pa_ll(base, GPT_PGS_ACTUAL_SIZE(gpt_config.p));
+ dsbosh();
+
+ nse = (uint64_t)GPT_NSE_NS << GPT_NSE_SHIFT;
+
+ flush_dcache_to_popa_range(nse | base,
+ GPT_PGS_ACTUAL_SIZE(gpt_config.p));
+
+ /* Unlock access to the L1 tables. */
+ spin_unlock(&gpt_lock);
+
+ /*
+ * The isb() will be done as part of context
+ * synchronization when returning to lower EL
+ */
+ VERBOSE("[GPT] Granule 0x%" PRIx64 ", GPI 0x%x->0x%x\n",
+ base, gpi_info.gpi, target_pas);
+
+ return 0;
+}
+
+/*
+ * This function is the granule transition undelegate service. When a granule
+ * transition request occurs it is routed to this function where the request is
+ * validated then fulfilled if possible.
+ *
+ * TODO: implement support for transitioning multiple granules at once.
+ *
+ * Parameters
+ * base Base address of the region to transition, must be
+ * aligned to granule size.
+ * size Size of region to transition, must be aligned to granule
+ * size.
+ * src_sec_state Security state of the caller.
+ *
+ * Return
+ * Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_undelegate_pas(uint64_t base, size_t size, unsigned int src_sec_state)
+{
+ gpi_info_t gpi_info;
+ uint64_t nse;
+ int res;
+
+ /* Ensure that the tables have been set up before taking requests. */
+ assert(gpt_config.plat_gpt_l0_base != 0UL);
+
+ /* Ensure that MMU and caches are enabled. */
+ assert((read_sctlr_el3() & SCTLR_C_BIT) != 0UL);
+
+ /* Delegate request can only come from REALM or SECURE */
+ assert(src_sec_state == SMC_FROM_REALM ||
+ src_sec_state == SMC_FROM_SECURE);
+
+ /* See if this is a single or a range of granule transition. */
+ if (size != GPT_PGS_ACTUAL_SIZE(gpt_config.p)) {
+ return -EINVAL;
+ }
+
+ /* Check that base and size are valid */
+ if ((ULONG_MAX - base) < size) {
+ VERBOSE("[GPT] Transition request address overflow!\n");
+ VERBOSE(" Base=0x%" PRIx64 "\n", base);
+ VERBOSE(" Size=0x%lx\n", size);
+ return -EINVAL;
+ }
+
+ /* Make sure base and size are valid. */
+ if (((base & (GPT_PGS_ACTUAL_SIZE(gpt_config.p) - 1)) != 0UL) ||
+ ((size & (GPT_PGS_ACTUAL_SIZE(gpt_config.p) - 1)) != 0UL) ||
+ (size == 0UL) ||
+ ((base + size) >= GPT_PPS_ACTUAL_SIZE(gpt_config.t))) {
+ VERBOSE("[GPT] Invalid granule transition address range!\n");
+ VERBOSE(" Base=0x%" PRIx64 "\n", base);
+ VERBOSE(" Size=0x%lx\n", size);
+ return -EINVAL;
+ }
+
+ /*
+ * Access to L1 tables is controlled by a global lock to ensure
+ * that no more than one CPU is allowed to make changes at any
+ * given time.
+ */
+ spin_lock(&gpt_lock);
+
+ res = get_gpi_params(base, &gpi_info);
+ if (res != 0) {
+ spin_unlock(&gpt_lock);
+ return res;
+ }
+
+ /* Check that the current address is in the delegated state */
+ if ((src_sec_state == SMC_FROM_REALM &&
+ gpi_info.gpi != GPT_GPI_REALM) ||
+ (src_sec_state == SMC_FROM_SECURE &&
+ gpi_info.gpi != GPT_GPI_SECURE)) {
+ VERBOSE("[GPT] Only Granule in REALM or SECURE state can be undelegated.\n");
+ VERBOSE(" Caller: %u, Current GPI: %u\n", src_sec_state,
+ gpi_info.gpi);
+ spin_unlock(&gpt_lock);
+ return -EPERM;
+ }
+
+
+ /* In order to maintain mutual distrust between Realm and Secure
+ * states, remove access now, in order to guarantee that writes
+ * to the currently-accessible physical address space will not
+ * later become observable.
+ */
+ write_gpt(&gpi_info.gpt_l1_desc, gpi_info.gpt_l1_addr,
+ gpi_info.gpi_shift, gpi_info.idx, GPT_GPI_NO_ACCESS);
+ dsboshst();
+
+ gpt_tlbi_by_pa_ll(base, GPT_PGS_ACTUAL_SIZE(gpt_config.p));
+ dsbosh();
+
+ if (src_sec_state == SMC_FROM_SECURE) {
+ nse = (uint64_t)GPT_NSE_SECURE << GPT_NSE_SHIFT;
+ } else {
+ nse = (uint64_t)GPT_NSE_REALM << GPT_NSE_SHIFT;
+ }
+
+ /* Ensure that the scrubbed data has made it past the PoPA */
+ flush_dcache_to_popa_range(nse | base,
+ GPT_PGS_ACTUAL_SIZE(gpt_config.p));
+
+ /*
+ * Remove any data loaded speculatively
+ * in NS space from before the scrubbing
+ */
+ nse = (uint64_t)GPT_NSE_NS << GPT_NSE_SHIFT;
+
+ flush_dcache_to_popa_range(nse | base,
+ GPT_PGS_ACTUAL_SIZE(gpt_config.p));
+
+ /* Clear existing GPI encoding and transition granule. */
+ write_gpt(&gpi_info.gpt_l1_desc, gpi_info.gpt_l1_addr,
+ gpi_info.gpi_shift, gpi_info.idx, GPT_GPI_NS);
+ dsboshst();
+
+ /* Ensure that all agents observe the new NS configuration */
+ gpt_tlbi_by_pa_ll(base, GPT_PGS_ACTUAL_SIZE(gpt_config.p));
+ dsbosh();
+
+ /* Unlock access to the L1 tables. */
+ spin_unlock(&gpt_lock);
+
+ /*
+ * The isb() will be done as part of context
+ * synchronization when returning to lower EL
+ */
+ VERBOSE("[GPT] Granule 0x%" PRIx64 ", GPI 0x%x->0x%x\n",
+ base, gpi_info.gpi, GPT_GPI_NS);
+
+ return 0;
+}
diff --git a/lib/gpt_rme/gpt_rme.mk b/lib/gpt_rme/gpt_rme.mk
new file mode 100644
index 0000000..60176f4
--- /dev/null
+++ b/lib/gpt_rme/gpt_rme.mk
@@ -0,0 +1,8 @@
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+GPT_LIB_SRCS := $(addprefix lib/gpt_rme/, \
+ gpt_rme.c)
diff --git a/lib/gpt_rme/gpt_rme_private.h b/lib/gpt_rme/gpt_rme_private.h
new file mode 100644
index 0000000..3c817f3
--- /dev/null
+++ b/lib/gpt_rme/gpt_rme_private.h
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GPT_RME_PRIVATE_H
+#define GPT_RME_PRIVATE_H
+
+#include <arch.h>
+#include <lib/gpt_rme/gpt_rme.h>
+#include <lib/utils_def.h>
+
+/******************************************************************************/
+/* GPT descriptor definitions */
+/******************************************************************************/
+
+/* GPT level 0 descriptor bit definitions. */
+#define GPT_L0_TYPE_MASK UL(0xF)
+#define GPT_L0_TYPE_SHIFT U(0)
+
+/* For now, we don't support contiguous descriptors, only table and block. */
+#define GPT_L0_TYPE_TBL_DESC UL(0x3)
+#define GPT_L0_TYPE_BLK_DESC UL(0x1)
+
+#define GPT_L0_TBL_DESC_L1ADDR_MASK UL(0xFFFFFFFFFF)
+#define GPT_L0_TBL_DESC_L1ADDR_SHIFT U(12)
+
+#define GPT_L0_BLK_DESC_GPI_MASK UL(0xF)
+#define GPT_L0_BLK_DESC_GPI_SHIFT U(4)
+
+/* GPT level 1 descriptor bit definitions */
+#define GPT_L1_GRAN_DESC_GPI_MASK UL(0xF)
+
+/*
+ * This macro fills out every GPI entry in a granules descriptor to the same
+ * value.
+ */
+#define GPT_BUILD_L1_DESC(_gpi) (((uint64_t)(_gpi) << 4*0) | \
+ ((uint64_t)(_gpi) << 4*1) | \
+ ((uint64_t)(_gpi) << 4*2) | \
+ ((uint64_t)(_gpi) << 4*3) | \
+ ((uint64_t)(_gpi) << 4*4) | \
+ ((uint64_t)(_gpi) << 4*5) | \
+ ((uint64_t)(_gpi) << 4*6) | \
+ ((uint64_t)(_gpi) << 4*7) | \
+ ((uint64_t)(_gpi) << 4*8) | \
+ ((uint64_t)(_gpi) << 4*9) | \
+ ((uint64_t)(_gpi) << 4*10) | \
+ ((uint64_t)(_gpi) << 4*11) | \
+ ((uint64_t)(_gpi) << 4*12) | \
+ ((uint64_t)(_gpi) << 4*13) | \
+ ((uint64_t)(_gpi) << 4*14) | \
+ ((uint64_t)(_gpi) << 4*15))
+
+/******************************************************************************/
+/* GPT platform configuration */
+/******************************************************************************/
+
+/* This value comes from GPCCR_EL3 so no externally supplied definition. */
+#define GPT_L0GPTSZ ((unsigned int)((read_gpccr_el3() >> \
+ GPCCR_L0GPTSZ_SHIFT) & GPCCR_L0GPTSZ_MASK))
+
+/* The "S" value is directly related to L0GPTSZ */
+#define GPT_S_VAL (GPT_L0GPTSZ + 30U)
+
+/*
+ * Map PPS values to T values.
+ *
+ * PPS Size T
+ * 0b000 4GB 32
+ * 0b001 64GB 36
+ * 0b010 1TB 40
+ * 0b011 4TB 42
+ * 0b100 16TB 44
+ * 0b101 256TB 48
+ * 0b110 4PB 52
+ *
+ * See section 15.1.27 of the RME specification.
+ */
+typedef enum {
+ PPS_4GB_T = 32U,
+ PPS_64GB_T = 36U,
+ PPS_1TB_T = 40U,
+ PPS_4TB_T = 42U,
+ PPS_16TB_T = 44U,
+ PPS_256TB_T = 48U,
+ PPS_4PB_T = 52U
+} gpt_t_val_e;
+
+/*
+ * Map PGS values to P values.
+ *
+ * PGS Size P
+ * 0b00 4KB 12
+ * 0b10 16KB 14
+ * 0b01 64KB 16
+ *
+ * Note that pgs=0b10 is 16KB and pgs=0b01 is 64KB, this is not a typo.
+ *
+ * See section 15.1.27 of the RME specification.
+ */
+typedef enum {
+ PGS_4KB_P = 12U,
+ PGS_16KB_P = 14U,
+ PGS_64KB_P = 16U
+} gpt_p_val_e;
+
+/*
+ * Internal structure to retrieve the values from get_gpi_info();
+ */
+typedef struct gpi_info {
+ uint64_t gpt_l1_desc;
+ uint64_t *gpt_l1_addr;
+ unsigned int idx;
+ unsigned int gpi_shift;
+ unsigned int gpi;
+} gpi_info_t;
+
+/* Max valid value for PGS. */
+#define GPT_PGS_MAX (2U)
+
+/* Max valid value for PPS. */
+#define GPT_PPS_MAX (6U)
+
+/******************************************************************************/
+/* L0 address attribute macros */
+/******************************************************************************/
+
+/*
+ * Width of the L0 index field.
+ *
+ * If S is greater than or equal to T then there is a single L0 region covering
+ * the entire protected space so there is no L0 index, so the width (and the
+ * derivative mask value) are both zero. If we don't specifically handle this
+ * special case we'll get a negative width value which does not make sense and
+ * would cause problems.
+ */
+#define GPT_L0_IDX_WIDTH(_t) (((_t) > GPT_S_VAL) ? \
+ ((_t) - GPT_S_VAL) : (0U))
+
+/* Bit shift for the L0 index field in a PA. */
+#define GPT_L0_IDX_SHIFT (GPT_S_VAL)
+
+/*
+ * Mask for the L0 index field, must be shifted.
+ *
+ * The value 0x3FFFFF is 22 bits wide which is the maximum possible width of the
+ * L0 index within a physical address. This is calculated by
+ * ((t_max - 1) - s_min + 1) where t_max is 52 for 4PB, the largest PPS, and
+ * s_min is 30 for 1GB, the smallest L0GPTSZ.
+ */
+#define GPT_L0_IDX_MASK(_t) (0x3FFFFFUL >> (22U - \
+ (GPT_L0_IDX_WIDTH(_t))))
+
+/* Total number of L0 regions. */
+#define GPT_L0_REGION_COUNT(_t) ((GPT_L0_IDX_MASK(_t)) + 1U)
+
+/* Total size of each GPT L0 region in bytes. */
+#define GPT_L0_REGION_SIZE (1UL << (GPT_L0_IDX_SHIFT))
+
+/* Total size in bytes of the whole L0 table. */
+#define GPT_L0_TABLE_SIZE(_t) ((GPT_L0_REGION_COUNT(_t)) << 3U)
+
+/******************************************************************************/
+/* L1 address attribute macros */
+/******************************************************************************/
+
+/*
+ * Width of the L1 index field.
+ *
+ * This field does not have a special case to handle widths less than zero like
+ * the L0 index field above since all valid combinations of PGS (p) and L0GPTSZ
+ * (s) will result in a positive width value.
+ */
+#define GPT_L1_IDX_WIDTH(_p) ((GPT_S_VAL - 1U) - ((_p) + 3U))
+
+/* Bit shift for the L1 index field. */
+#define GPT_L1_IDX_SHIFT(_p) ((_p) + 4U)
+
+/*
+ * Mask for the L1 index field, must be shifted.
+ *
+ * The value 0x7FFFFF is 23 bits wide and is the maximum possible width of the
+ * L1 index within a physical address. It is calculated by
+ * ((s_max - 1) - (p_min + 4) + 1) where s_max is 39 for 512gb, the largest
+ * L0GPTSZ, and p_min is 12 for 4KB granules, the smallest PGS.
+ */
+#define GPT_L1_IDX_MASK(_p) (0x7FFFFFUL >> (23U - \
+ (GPT_L1_IDX_WIDTH(_p))))
+
+/* Bit shift for the index of the L1 GPI in a PA. */
+#define GPT_L1_GPI_IDX_SHIFT(_p) (_p)
+
+/* Mask for the index of the L1 GPI in a PA. */
+#define GPT_L1_GPI_IDX_MASK (0xF)
+
+/* Total number of entries in each L1 table. */
+#define GPT_L1_ENTRY_COUNT(_p) ((GPT_L1_IDX_MASK(_p)) + 1U)
+
+/* Total size in bytes of each L1 table. */
+#define GPT_L1_TABLE_SIZE(_p) ((GPT_L1_ENTRY_COUNT(_p)) << 3U)
+
+/******************************************************************************/
+/* General helper macros */
+/******************************************************************************/
+
+/* Protected space actual size in bytes. */
+#define GPT_PPS_ACTUAL_SIZE(_t) (1UL << (_t))
+
+/* Granule actual size in bytes. */
+#define GPT_PGS_ACTUAL_SIZE(_p) (1UL << (_p))
+
+/* L0 GPT region size in bytes. */
+#define GPT_L0GPTSZ_ACTUAL_SIZE (1UL << GPT_S_VAL)
+
+/* Get the index of the L0 entry from a physical address. */
+#define GPT_L0_IDX(_pa) ((_pa) >> GPT_L0_IDX_SHIFT)
+
+/*
+ * This definition is used to determine if a physical address lies on an L0
+ * region boundary.
+ */
+#define GPT_IS_L0_ALIGNED(_pa) (((_pa) & (GPT_L0_REGION_SIZE - U(1))) == U(0))
+
+/* Get the type field from an L0 descriptor. */
+#define GPT_L0_TYPE(_desc) (((_desc) >> GPT_L0_TYPE_SHIFT) & \
+ GPT_L0_TYPE_MASK)
+
+/* Create an L0 block descriptor. */
+#define GPT_L0_BLK_DESC(_gpi) (GPT_L0_TYPE_BLK_DESC | \
+ (((_gpi) & GPT_L0_BLK_DESC_GPI_MASK) << \
+ GPT_L0_BLK_DESC_GPI_SHIFT))
+
+/* Create an L0 table descriptor with an L1 table address. */
+#define GPT_L0_TBL_DESC(_pa) (GPT_L0_TYPE_TBL_DESC | ((uint64_t)(_pa) & \
+ (GPT_L0_TBL_DESC_L1ADDR_MASK << \
+ GPT_L0_TBL_DESC_L1ADDR_SHIFT)))
+
+/* Get the GPI from an L0 block descriptor. */
+#define GPT_L0_BLKD_GPI(_desc) (((_desc) >> GPT_L0_BLK_DESC_GPI_SHIFT) & \
+ GPT_L0_BLK_DESC_GPI_MASK)
+
+/* Get the L1 address from an L0 table descriptor. */
+#define GPT_L0_TBLD_ADDR(_desc) ((uint64_t *)(((_desc) & \
+ (GPT_L0_TBL_DESC_L1ADDR_MASK << \
+ GPT_L0_TBL_DESC_L1ADDR_SHIFT))))
+
+/* Get the index into the L1 table from a physical address. */
+#define GPT_L1_IDX(_p, _pa) (((_pa) >> GPT_L1_IDX_SHIFT(_p)) & \
+ GPT_L1_IDX_MASK(_p))
+
+/* Get the index of the GPI within an L1 table entry from a physical address. */
+#define GPT_L1_GPI_IDX(_p, _pa) (((_pa) >> GPT_L1_GPI_IDX_SHIFT(_p)) & \
+ GPT_L1_GPI_IDX_MASK)
+
+/* Determine if an address is granule-aligned. */
+#define GPT_IS_L1_ALIGNED(_p, _pa) (((_pa) & (GPT_PGS_ACTUAL_SIZE(_p) - U(1))) \
+ == U(0))
+
+#endif /* GPT_RME_PRIVATE_H */
diff --git a/lib/libc/aarch32/memset.S b/lib/libc/aarch32/memset.S
new file mode 100644
index 0000000..880ba83
--- /dev/null
+++ b/lib/libc/aarch32/memset.S
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+ .syntax unified
+ .global memset
+
+/* -----------------------------------------------------------------------
+ * void *memset(void *dst, int val, size_t count)
+ *
+ * Copy the value of 'val' (converted to an unsigned char) into
+ * each of the first 'count' characters of the object pointed to by 'dst'.
+ *
+ * Returns the value of 'dst'.
+ * -----------------------------------------------------------------------
+ */
+func memset
+ mov r12, r0 /* keep r0 */
+ tst r0, #3
+ beq aligned /* 4-bytes aligned */
+
+ /* Unaligned 'dst' */
+unaligned:
+ subs r2, r2, #1
+ strbhs r1, [r12], #1
+ bxls lr /* return if 0 */
+ tst r12, #3
+ bne unaligned /* continue while unaligned */
+
+ /* 4-bytes aligned */
+aligned:bfi r1, r1, #8, #8 /* propagate 'val' */
+ bfi r1, r1, #16, #16
+
+ mov r3, r1
+
+ cmp r2, #16
+ blo less_16 /* < 16 */
+
+ push {r4, lr}
+ mov r4, r1
+ mov lr, r1
+
+write_32:
+ subs r2, r2, #32
+ stmiahs r12!, {r1, r3, r4, lr}
+ stmiahs r12!, {r1, r3, r4, lr}
+ bhi write_32 /* write 32 bytes in a loop */
+ popeq {r4, pc} /* return if 0 */
+ lsls r2, r2, #28 /* C = r2[4]; N = r2[3]; Z = r2[3:0] */
+ stmiacs r12!, {r1, r3, r4, lr} /* write 16 bytes */
+ popeq {r4, pc} /* return if 16 */
+ stmiami r12!, {r1, r3} /* write 8 bytes */
+ lsls r2, r2, #2 /* C = r2[2]; N = r2[1]; Z = r2[1:0] */
+ strcs r1, [r12], #4 /* write 4 bytes */
+ popeq {r4, pc} /* return if 8 or 4 */
+ strhmi r1, [r12], #2 /* write 2 bytes */
+ lsls r2, r2, #1 /* N = Z = r2[0] */
+ strbmi r1, [r12] /* write 1 byte */
+ pop {r4, pc}
+
+less_16:lsls r2, r2, #29 /* C = r2[3]; N = r2[2]; Z = r2[2:0] */
+ stmiacs r12!, {r1, r3} /* write 8 bytes */
+ bxeq lr /* return if 8 */
+ strmi r1, [r12], #4 /* write 4 bytes */
+ lsls r2, r2, #2 /* C = r2[1]; N = Z = r2[0] */
+ strhcs r1, [r12], #2 /* write 2 bytes */
+ strbmi r1, [r12] /* write 1 byte */
+ bx lr
+
+endfunc memset
diff --git a/lib/libc/aarch64/memset.S b/lib/libc/aarch64/memset.S
new file mode 100644
index 0000000..0543704
--- /dev/null
+++ b/lib/libc/aarch64/memset.S
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+ .global memset
+
+/* -----------------------------------------------------------------------
+ * void *memset(void *dst, int val, size_t count)
+ *
+ * Copy the value of 'val' (converted to an unsigned char) into
+ * each of the first 'count' characters of the object pointed to by 'dst'.
+ *
+ * Returns the value of 'dst'.
+ * -----------------------------------------------------------------------
+ */
+func memset
+ cbz x2, exit /* exit if 'count' = 0 */
+ mov x3, x0 /* keep x0 */
+ tst x0, #7
+ b.eq aligned /* 8-bytes aligned */
+
+ /* Unaligned 'dst' */
+unaligned:
+ strb w1, [x3], #1
+ subs x2, x2, #1
+ b.eq exit /* exit if 0 */
+ tst x3, #7
+ b.ne unaligned /* continue while unaligned */
+
+ /* 8-bytes aligned */
+aligned:cbz x1, x1_zero
+ bfi w1, w1, #8, #8 /* propagate 'val' */
+ bfi w1, w1, #16, #16
+ bfi x1, x1, #32, #32
+
+x1_zero:ands x4, x2, #~0x3f
+ b.eq less_64
+
+write_64:
+ .rept 4
+ stp x1, x1, [x3], #16 /* write 64 bytes in a loop */
+ .endr
+ subs x4, x4, #64
+ b.ne write_64
+less_64:tbz w2, #5, less_32 /* < 32 bytes */
+ stp x1, x1, [x3], #16 /* write 32 bytes */
+ stp x1, x1, [x3], #16
+less_32:tbz w2, #4, less_16 /* < 16 bytes */
+ stp x1, x1, [x3], #16 /* write 16 bytes */
+less_16:tbz w2, #3, less_8 /* < 8 bytes */
+ str x1, [x3], #8 /* write 8 bytes */
+less_8: tbz w2, #2, less_4 /* < 4 bytes */
+ str w1, [x3], #4 /* write 4 bytes */
+less_4: tbz w2, #1, less_2 /* < 2 bytes */
+ strh w1, [x3], #2 /* write 2 bytes */
+less_2: tbz w2, #0, exit
+ strb w1, [x3] /* write 1 byte */
+exit: ret
+
+endfunc memset
diff --git a/lib/libc/aarch64/setjmp.S b/lib/libc/aarch64/setjmp.S
new file mode 100644
index 0000000..9d9eb49
--- /dev/null
+++ b/lib/libc/aarch64/setjmp.S
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <setjmp.h>
+
+ .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
diff --git a/lib/libc/abort.c b/lib/libc/abort.c
new file mode 100644
index 0000000..432b1d0
--- /dev/null
+++ b/lib/libc/abort.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+
+#include <common/debug.h>
+
+void abort(void)
+{
+ ERROR("ABORT\n");
+ panic();
+}
diff --git a/lib/libc/assert.c b/lib/libc/assert.c
new file mode 100644
index 0000000..8973ed5
--- /dev/null
+++ b/lib/libc/assert.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <cdefs.h>
+#include <stdio.h>
+
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <plat/common/platform.h>
+
+/*
+ * 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_INFO
+void __dead2 __assert(const char *file, unsigned int line)
+{
+ printf("ASSERT: %s:%u\n", file, line);
+ backtrace("assert");
+ console_flush();
+ plat_panic_handler();
+}
+#else
+void __dead2 __assert(void)
+{
+ backtrace("assert");
+ console_flush();
+ plat_panic_handler();
+}
+#endif
diff --git a/lib/libc/exit.c b/lib/libc/exit.c
new file mode 100644
index 0000000..f4ffe27
--- /dev/null
+++ b/lib/libc/exit.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+
+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;
+}
diff --git a/lib/libc/libc.mk b/lib/libc/libc.mk
new file mode 100644
index 0000000..b75d09c
--- /dev/null
+++ b/lib/libc/libc.mk
@@ -0,0 +1,41 @@
+#
+# Copyright (c) 2016-2021, 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 \
+ memrchr.c \
+ memset.c \
+ printf.c \
+ putchar.c \
+ puts.c \
+ snprintf.c \
+ strchr.c \
+ strcmp.c \
+ strlcat.c \
+ strlcpy.c \
+ strlen.c \
+ strncmp.c \
+ strnlen.c \
+ strrchr.c \
+ strtok.c \
+ strtoul.c \
+ strtoll.c \
+ strtoull.c \
+ strtol.c)
+
+ifeq (${ARCH},aarch64)
+LIBC_SRCS += $(addprefix lib/libc/aarch64/, \
+ setjmp.S)
+endif
+
+INCLUDES += -Iinclude/lib/libc \
+ -Iinclude/lib/libc/$(ARCH) \
diff --git a/lib/libc/libc_asm.mk b/lib/libc/libc_asm.mk
new file mode 100644
index 0000000..2f27265
--- /dev/null
+++ b/lib/libc/libc_asm.mk
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2020-2021, Arm Limited. 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 \
+ memrchr.c \
+ printf.c \
+ putchar.c \
+ puts.c \
+ snprintf.c \
+ strchr.c \
+ strcmp.c \
+ strlcat.c \
+ strlcpy.c \
+ strlen.c \
+ strncmp.c \
+ strnlen.c \
+ strrchr.c \
+ strtok.c \
+ strtoul.c \
+ strtoll.c \
+ strtoull.c \
+ strtol.c)
+
+ifeq (${ARCH},aarch64)
+LIBC_SRCS += $(addprefix lib/libc/aarch64/, \
+ memset.S \
+ setjmp.S)
+else
+LIBC_SRCS += $(addprefix lib/libc/aarch32/, \
+ memset.S)
+endif
+
+INCLUDES += -Iinclude/lib/libc \
+ -Iinclude/lib/libc/$(ARCH) \
diff --git a/lib/libc/memchr.c b/lib/libc/memchr.c
new file mode 100644
index 0000000..8cbb715
--- /dev/null
+++ b/lib/libc/memchr.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+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;
+}
diff --git a/lib/libc/memcmp.c b/lib/libc/memcmp.c
new file mode 100644
index 0000000..cd5f0df
--- /dev/null
+++ b/lib/libc/memcmp.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+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;
+}
diff --git a/lib/libc/memcpy.c b/lib/libc/memcpy.c
new file mode 100644
index 0000000..158df9b
--- /dev/null
+++ b/lib/libc/memcpy.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+void *memcpy(void *dst, const void *src, size_t len)
+{
+ const char *s = src;
+ char *d = dst;
+
+ while (len--)
+ *d++ = *s++;
+
+ return dst;
+}
diff --git a/lib/libc/memmove.c b/lib/libc/memmove.c
new file mode 100644
index 0000000..63acf26
--- /dev/null
+++ b/lib/libc/memmove.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+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;
+}
diff --git a/lib/libc/memrchr.c b/lib/libc/memrchr.c
new file mode 100644
index 0000000..01caef3
--- /dev/null
+++ b/lib/libc/memrchr.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#undef memrchr
+
+void *memrchr(const void *src, int c, size_t len)
+{
+ const unsigned char *s = src + (len - 1);
+
+ while (len--) {
+ if (*s == (unsigned char)c) {
+ return (void*) s;
+ }
+
+ s--;
+ }
+
+ return NULL;
+}
diff --git a/lib/libc/memset.c b/lib/libc/memset.c
new file mode 100644
index 0000000..17f798c
--- /dev/null
+++ b/lib/libc/memset.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <stdint.h>
+
+void *memset(void *dst, int val, size_t count)
+{
+ uint8_t *ptr = dst;
+ uint64_t *ptr64;
+ uint64_t fill = (unsigned char)val;
+
+ /* Simplify code below by making sure we write at least one byte. */
+ if (count == 0U) {
+ return dst;
+ }
+
+ /* Handle the first part, until the pointer becomes 64-bit aligned. */
+ while (((uintptr_t)ptr & 7U) != 0U) {
+ *ptr = (uint8_t)val;
+ ptr++;
+ if (--count == 0U) {
+ return dst;
+ }
+ }
+
+ /* Duplicate the fill byte to the rest of the 64-bit word. */
+ fill |= fill << 8;
+ fill |= fill << 16;
+ fill |= fill << 32;
+
+ /* Use 64-bit writes for as long as possible. */
+ ptr64 = (uint64_t *)ptr;
+ for (; count >= 8U; count -= 8) {
+ *ptr64 = fill;
+ ptr64++;
+ }
+
+ /* Handle the remaining part byte-per-byte. */
+ ptr = (uint8_t *)ptr64;
+ while (count-- > 0U) {
+ *ptr = (uint8_t)val;
+ ptr++;
+ }
+
+ return dst;
+}
diff --git a/lib/libc/printf.c b/lib/libc/printf.c
new file mode 100644
index 0000000..e52cbed
--- /dev/null
+++ b/lib/libc/printf.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#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;
+
+ /* num_buf is only large enough for radix >= 10 */
+ if (radix < 10) {
+ assert(0);
+ return 0;
+ }
+
+ 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 '%':
+ (void)putchar('%');
+ break;
+ 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;
+}
diff --git a/lib/libc/putchar.c b/lib/libc/putchar.c
new file mode 100644
index 0000000..3472b24
--- /dev/null
+++ b/lib/libc/putchar.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+
+int __putchar(int c)
+{
+ return c;
+}
+
+int putchar(int c) __attribute__((weak,alias("__putchar")));
diff --git a/lib/libc/puts.c b/lib/libc/puts.c
new file mode 100644
index 0000000..2a0ca11
--- /dev/null
+++ b/lib/libc/puts.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+
+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;
+}
diff --git a/lib/libc/snprintf.c b/lib/libc/snprintf.c
new file mode 100644
index 0000000..6a2f0ba
--- /dev/null
+++ b/lib/libc/snprintf.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#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)))
+
+#define CHECK_AND_PUT_CHAR(buf, size, chars_printed, ch) \
+ do { \
+ if ((chars_printed) < (size)) { \
+ *(buf) = (ch); \
+ (buf)++; \
+ } \
+ (chars_printed)++; \
+ } while (false)
+
+static void string_print(char **s, size_t n, size_t *chars_printed,
+ const char *str)
+{
+ while (*str != '\0') {
+ CHECK_AND_PUT_CHAR(*s, n, *chars_printed, *str);
+ str++;
+ }
+}
+
+static void unsigned_num_print(char **s, size_t n, size_t *chars_printed,
+ unsigned long long int unum,
+ unsigned int radix, char padc, int padn,
+ bool capitalise)
+{
+ /* Just need enough space to store 64 bit decimal integer */
+ char num_buf[20];
+ int i = 0;
+ int width;
+ unsigned int rem;
+ char ascii_a = capitalise ? 'A' : 'a';
+
+ /* num_buf is only large enough for radix >= 10 */
+ if (radix < 10) {
+ assert(0);
+ return;
+ }
+
+ do {
+ rem = unum % radix;
+ if (rem < 10U) {
+ num_buf[i] = '0' + rem;
+ } else {
+ num_buf[i] = ascii_a + (rem - 10U);
+ }
+ i++;
+ unum /= radix;
+ } while (unum > 0U);
+
+ width = i;
+ for (i = padn - width; i > 0; i--) {
+ CHECK_AND_PUT_CHAR(*s, n, *chars_printed, padc);
+ }
+ for (i = width; i > 0; i--) {
+ CHECK_AND_PUT_CHAR(*s, n, *chars_printed, num_buf[i - 1]);
+ }
+ for (i = width + padn; i < 0; i++) {
+ CHECK_AND_PUT_CHAR(*s, n, *chars_printed, padc);
+ }
+}
+
+/*******************************************************************
+ * Reduced vsnprintf to be used for Trusted firmware.
+ * The following type specifiers are supported:
+ *
+ * %x (or %X) - hexadecimal format
+ * %d or %i - signed decimal format
+ * %s - string format
+ * %u - unsigned decimal format
+ * %p - pointer format
+ *
+ * The following length specifiers are supported by this print
+ * %l - long int
+ * %ll - long long int
+ * %z - size_t sized integer formats
+ *
+ * The following padding specifiers are supported by this print
+ * %0NN - Left-pad the number with 0s (NN is a decimal number)
+ * %NN - Left-pad the number or string with spaces (NN is a decimal number)
+ * %-NN - Right-pad the number or string with spaces (NN is a decimal number)
+ *
+ * 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 vsnprintf(char *s, size_t n, const char *fmt, va_list args)
+{
+ int num;
+ unsigned long long int unum;
+ char *str;
+ char padc; /* Padding character */
+ int padn; /* Number of characters to pad */
+ bool left;
+ bool capitalise;
+ size_t chars_printed = 0U;
+ unsigned int l_count;
+
+ 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--;
+ }
+
+ while (*fmt != '\0') {
+ left = false;
+ padc ='\0';
+ padn = 0;
+ capitalise = false;
+ l_count = 0;
+
+ if (*fmt == '%') {
+ fmt++;
+ /* Check the format specifier. */
+loop:
+ switch (*fmt) {
+ case '%':
+ CHECK_AND_PUT_CHAR(s, n, chars_printed, '%');
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ padc = (*fmt == '0') ? '0' : ' ';
+ for (padn = 0; *fmt >= '0' && *fmt <= '9'; fmt++) {
+ padn = (padn * 10) + (*fmt - '0');
+ }
+ if (left) {
+ padn = -padn;
+ }
+ goto loop;
+ case '-':
+ left = true;
+ fmt++;
+ goto loop;
+
+ case 'i':
+ case 'd':
+ num = get_num_va_args(args, l_count);
+
+ if (num < 0) {
+ CHECK_AND_PUT_CHAR(s, n, chars_printed,
+ '-');
+ unum = (unsigned int)-num;
+ } else {
+ unum = (unsigned int)num;
+ }
+
+ unsigned_num_print(&s, n, &chars_printed,
+ unum, 10, padc, padn, false);
+ break;
+ case 's':
+ str = va_arg(args, char *);
+ string_print(&s, n, &chars_printed, str);
+ break;
+ case 'u':
+ unum = get_unum_va_args(args, l_count);
+ unsigned_num_print(&s, n, &chars_printed,
+ unum, 10, padc, padn, false);
+ break;
+ case 'z':
+ l_count = 1;
+ fmt++;
+ goto loop;
+ case 'l':
+ l_count++;
+ fmt++;
+ goto loop;
+ case 'p':
+ unum = (uintptr_t)va_arg(args, void *);
+ if (unum > 0U) {
+ string_print(&s, n, &chars_printed, "0x");
+ padn -= 2;
+ }
+ unsigned_num_print(&s, n, &chars_printed,
+ unum, 16, padc, padn, false);
+ break;
+ case 'X':
+ capitalise = true;
+ case 'x':
+ unum = get_unum_va_args(args, l_count);
+ unsigned_num_print(&s, n, &chars_printed,
+ unum, 16, padc, padn,
+ capitalise);
+ break;
+
+ default:
+ CHECK_AND_PUT_CHAR(s, n, chars_printed, '%');
+ CHECK_AND_PUT_CHAR(s, n, chars_printed, *fmt);
+ }
+ fmt++;
+ continue;
+ }
+
+ CHECK_AND_PUT_CHAR(s, n, chars_printed, *fmt);
+
+ fmt++;
+ }
+
+ if (n > 0U) {
+ *s = '\0';
+ }
+
+ return (int)chars_printed;
+}
+
+/*******************************************************************
+ * Reduced snprintf to be used for Trusted firmware.
+ * The following type specifiers are supported:
+ *
+ * %x (or %X) - hexadecimal format
+ * %d or %i - signed decimal format
+ * %s - string format
+ * %u - unsigned decimal format
+ * %p - pointer format
+ *
+ * The following padding specifiers are supported by this print
+ * %0NN - Left-pad the number with 0s (NN is a decimal number)
+ * %NN - Left-pad the number or string with spaces (NN is a decimal number)
+ * %-NN - Right-pad the number or string with spaces (NN is a decimal number)
+ *
+ * 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, ...)
+{
+ int count;
+ va_list all_args;
+
+ va_start(all_args, fmt);
+ count = vsnprintf(s, n, fmt, all_args);
+ va_end(all_args);
+
+ return count;
+}
diff --git a/lib/libc/strchr.c b/lib/libc/strchr.c
new file mode 100644
index 0000000..d94bb9e
--- /dev/null
+++ b/lib/libc/strchr.c
@@ -0,0 +1,53 @@
+/*-
+ * 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 <stddef.h>
+#include <string.h>
+
+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 */
+}
diff --git a/lib/libc/strcmp.c b/lib/libc/strcmp.c
new file mode 100644
index 0000000..b742f9b
--- /dev/null
+++ b/lib/libc/strcmp.c
@@ -0,0 +1,52 @@
+/*-
+ * 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 <string.h>
+
+/*
+ * 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));
+}
diff --git a/lib/libc/strlcat.c b/lib/libc/strlcat.c
new file mode 100644
index 0000000..e60c863
--- /dev/null
+++ b/lib/libc/strlcat.c
@@ -0,0 +1,56 @@
+/* $OpenBSD: strlcat.c,v 1.15 2015/03/02 21:41:08 millert Exp $ */
+
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * 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 <string.h>
+
+/*
+ * Appends src to string dst of size dsize (unlike strncat, dsize is the
+ * full size of dst, not space left). At most dsize-1 characters
+ * will be copied. Always NUL terminates (unless dsize <= strlen(dst)).
+ * Returns strlen(src) + MIN(dsize, strlen(initial dst)).
+ * If retval >= dsize, truncation occurred.
+ */
+size_t
+strlcat(char * dst, const char * src, size_t dsize)
+{
+ const char *odst = dst;
+ const char *osrc = src;
+ size_t n = dsize;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end. */
+ while (n-- != 0 && *dst != '\0')
+ dst++;
+ dlen = dst - odst;
+ n = dsize - dlen;
+
+ if (n-- == 0)
+ return(dlen + strlen(src));
+ while (*src != '\0') {
+ if (n != 0) {
+ *dst++ = *src;
+ n--;
+ }
+ src++;
+ }
+ *dst = '\0';
+
+ return(dlen + (src - osrc)); /* count does not include NUL */
+}
diff --git a/lib/libc/strlcpy.c b/lib/libc/strlcpy.c
new file mode 100644
index 0000000..c4f39bb
--- /dev/null
+++ b/lib/libc/strlcpy.c
@@ -0,0 +1,52 @@
+/* $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 <Todd.Miller@courtesan.com>
+ *
+ * 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 <stdint.h>
+#include <string.h>
+
+/*
+ * 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 */
+}
diff --git a/lib/libc/strlen.c b/lib/libc/strlen.c
new file mode 100644
index 0000000..3c27630
--- /dev/null
+++ b/lib/libc/strlen.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+size_t strlen(const char *s)
+{
+ const char *cursor = s;
+
+ while (*cursor)
+ cursor++;
+
+ return cursor - s;
+}
diff --git a/lib/libc/strncmp.c b/lib/libc/strncmp.c
new file mode 100644
index 0000000..ce9e5ed
--- /dev/null
+++ b/lib/libc/strncmp.c
@@ -0,0 +1,53 @@
+/*-
+ * 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 <string.h>
+
+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);
+}
diff --git a/lib/libc/strnlen.c b/lib/libc/strnlen.c
new file mode 100644
index 0000000..b944e95
--- /dev/null
+++ b/lib/libc/strnlen.c
@@ -0,0 +1,46 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * 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 <string.h>
+
+size_t
+strnlen(const char *s, size_t maxlen)
+{
+ size_t len;
+
+ for (len = 0; len < maxlen; len++, s++) {
+ if (!*s)
+ break;
+ }
+ return (len);
+}
diff --git a/lib/libc/strrchr.c b/lib/libc/strrchr.c
new file mode 100644
index 0000000..cd435ff
--- /dev/null
+++ b/lib/libc/strrchr.c
@@ -0,0 +1,49 @@
+/*-
+ * 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 <stddef.h>
+#include <string.h>
+
+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 */
+}
diff --git a/lib/libc/strtok.c b/lib/libc/strtok.c
new file mode 100644
index 0000000..7e1a4d2
--- /dev/null
+++ b/lib/libc/strtok.c
@@ -0,0 +1,83 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1998 Softweyr LLC. All rights reserved.
+ *
+ * strtok_r, from Berkeley strtok
+ * Oct 13, 1998 by Wes Peters <wes@softweyr.com>
+ *
+ * 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
+ * notices, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notices, 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 SOFTWEYR LLC, 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 SOFTWEYR LLC, 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 <string.h>
+
+char *
+strtok_r(char *s, const char *delim, char **last)
+{
+ char *spanp, *tok;
+ int c, sc;
+
+ if (s == NULL && (s = *last) == NULL)
+ return (NULL);
+
+ /*
+ * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
+ */
+cont:
+ c = *s++;
+ for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
+ if (c == sc)
+ goto cont;
+ }
+
+ if (c == 0) { /* no non-delimiter characters */
+ *last = NULL;
+ return (NULL);
+ }
+ tok = s - 1;
+
+ /*
+ * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
+ * Note that delim must have one NUL; we stop if we see that, too.
+ */
+ for (;;) {
+ c = *s++;
+ spanp = (char *)delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = '\0';
+ *last = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ /* NOTREACHED */
+}
diff --git a/lib/libc/strtol.c b/lib/libc/strtol.c
new file mode 100644
index 0000000..deb862c
--- /dev/null
+++ b/lib/libc/strtol.c
@@ -0,0 +1,133 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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 <errno.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to a long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+long strtol(const char *nptr, char **endptr, int base)
+{
+ const char *s;
+ unsigned long acc;
+ char c;
+ unsigned long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for longs is
+ * [-2147483648..2147483647] and the input base is 10,
+ * cutoff will be set to 214748364 and cutlim to either
+ * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
+ * a value > 214748364, or equal but the next digit is > 7 (or 8),
+ * the number is too big, and we will return a range error.
+ *
+ * Set 'any' if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? (unsigned long)-(LONG_MIN + LONG_MAX) + LONG_MAX
+ : LONG_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? LONG_MIN : LONG_MAX;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/lib/libc/strtoll.c b/lib/libc/strtoll.c
new file mode 100644
index 0000000..4e101e8
--- /dev/null
+++ b/lib/libc/strtoll.c
@@ -0,0 +1,134 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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 <errno.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to a long long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+long long strtoll(const char *nptr, char **endptr, int base)
+{
+ const char *s;
+ unsigned long long acc;
+ char c;
+ unsigned long long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for quads is
+ * [-9223372036854775808..9223372036854775807] and the input base
+ * is 10, cutoff will be set to 922337203685477580 and cutlim to
+ * either 7 (neg==0) or 8 (neg==1), meaning that if we have
+ * accumulated a value > 922337203685477580, or equal but the
+ * next digit is > 7 (or 8), the number is too big, and we will
+ * return a range error.
+ *
+ * Set 'any' if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX
+ : LLONG_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? LLONG_MIN : LLONG_MAX;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/lib/libc/strtoul.c b/lib/libc/strtoul.c
new file mode 100644
index 0000000..b42fb14
--- /dev/null
+++ b/lib/libc/strtoul.c
@@ -0,0 +1,112 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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 <errno.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to an unsigned long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long strtoul(const char *nptr, char **endptr, int base)
+{
+ const char *s;
+ unsigned long acc;
+ char c;
+ unsigned long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+
+ cutoff = ULONG_MAX / base;
+ cutlim = ULONG_MAX % base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULONG_MAX;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/lib/libc/strtoull.c b/lib/libc/strtoull.c
new file mode 100644
index 0000000..2e65a43
--- /dev/null
+++ b/lib/libc/strtoull.c
@@ -0,0 +1,112 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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 <errno.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to an unsigned long long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long long strtoull(const char *nptr, char **endptr, int base)
+{
+ const char *s;
+ unsigned long long acc;
+ char c;
+ unsigned long long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * See strtoq for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+
+ cutoff = ULLONG_MAX / base;
+ cutlim = ULLONG_MAX % base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULLONG_MAX;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/lib/libfdt/fdt.c b/lib/libfdt/fdt.c
new file mode 100644
index 0000000..9fe7cf4
--- /dev/null
+++ b/lib/libfdt/fdt.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+/*
+ * Minimal sanity check for a read-only tree. fdt_ro_probe_() checks
+ * that the given buffer contains what appears to be a flattened
+ * device tree with sane information in its header.
+ */
+int32_t fdt_ro_probe_(const void *fdt)
+{
+ uint32_t totalsize = fdt_totalsize(fdt);
+
+ if (can_assume(VALID_DTB))
+ return totalsize;
+
+ /* The device tree must be at an 8-byte aligned address */
+ if ((uintptr_t)fdt & 7)
+ return -FDT_ERR_ALIGNMENT;
+
+ if (fdt_magic(fdt) == FDT_MAGIC) {
+ /* Complete tree */
+ if (!can_assume(LATEST)) {
+ 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 (!can_assume(VALID_INPUT) && fdt_size_dt_struct(fdt) == 0)
+ return -FDT_ERR_BADSTATE;
+ } else {
+ return -FDT_ERR_BADMAGIC;
+ }
+
+ if (totalsize < INT32_MAX)
+ return totalsize;
+ else
+ return -FDT_ERR_TRUNCATED;
+}
+
+static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off)
+{
+ return (off >= hdrsize) && (off <= totalsize);
+}
+
+static int check_block_(uint32_t hdrsize, uint32_t totalsize,
+ uint32_t base, uint32_t size)
+{
+ if (!check_off_(hdrsize, totalsize, base))
+ return 0; /* block start out of bounds */
+ if ((base + size) < base)
+ return 0; /* overflow */
+ if (!check_off_(hdrsize, totalsize, base + size))
+ return 0; /* block end out of bounds */
+ return 1;
+}
+
+size_t fdt_header_size_(uint32_t version)
+{
+ if (version <= 1)
+ return FDT_V1_SIZE;
+ else if (version <= 2)
+ return FDT_V2_SIZE;
+ else if (version <= 3)
+ return FDT_V3_SIZE;
+ else if (version <= 16)
+ return FDT_V16_SIZE;
+ else
+ return FDT_V17_SIZE;
+}
+
+size_t fdt_header_size(const void *fdt)
+{
+ return can_assume(LATEST) ? FDT_V17_SIZE :
+ fdt_header_size_(fdt_version(fdt));
+}
+
+int fdt_check_header(const void *fdt)
+{
+ size_t hdrsize;
+
+ /* The device tree must be at an 8-byte aligned address */
+ if ((uintptr_t)fdt & 7)
+ return -FDT_ERR_ALIGNMENT;
+
+ if (fdt_magic(fdt) != FDT_MAGIC)
+ return -FDT_ERR_BADMAGIC;
+ if (!can_assume(LATEST)) {
+ if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
+ || (fdt_last_comp_version(fdt) >
+ FDT_LAST_SUPPORTED_VERSION))
+ return -FDT_ERR_BADVERSION;
+ if (fdt_version(fdt) < fdt_last_comp_version(fdt))
+ return -FDT_ERR_BADVERSION;
+ }
+ hdrsize = fdt_header_size(fdt);
+ if (!can_assume(VALID_DTB)) {
+
+ if ((fdt_totalsize(fdt) < hdrsize)
+ || (fdt_totalsize(fdt) > INT_MAX))
+ return -FDT_ERR_TRUNCATED;
+
+ /* Bounds check memrsv block */
+ if (!check_off_(hdrsize, fdt_totalsize(fdt),
+ fdt_off_mem_rsvmap(fdt)))
+ return -FDT_ERR_TRUNCATED;
+ }
+
+ if (!can_assume(VALID_DTB)) {
+ /* Bounds check structure block */
+ if (!can_assume(LATEST) && fdt_version(fdt) < 17) {
+ if (!check_off_(hdrsize, fdt_totalsize(fdt),
+ fdt_off_dt_struct(fdt)))
+ return -FDT_ERR_TRUNCATED;
+ } else {
+ if (!check_block_(hdrsize, fdt_totalsize(fdt),
+ fdt_off_dt_struct(fdt),
+ fdt_size_dt_struct(fdt)))
+ return -FDT_ERR_TRUNCATED;
+ }
+
+ /* Bounds check strings block */
+ if (!check_block_(hdrsize, fdt_totalsize(fdt),
+ fdt_off_dt_strings(fdt),
+ fdt_size_dt_strings(fdt)))
+ return -FDT_ERR_TRUNCATED;
+ }
+
+ return 0;
+}
+
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
+{
+ unsigned int uoffset = offset;
+ unsigned int absoffset = offset + fdt_off_dt_struct(fdt);
+
+ if (offset < 0)
+ return NULL;
+
+ if (!can_assume(VALID_INPUT))
+ if ((absoffset < uoffset)
+ || ((absoffset + len) < absoffset)
+ || (absoffset + len) > fdt_totalsize(fdt))
+ return NULL;
+
+ if (can_assume(LATEST) || fdt_version(fdt) >= 0x11)
+ if (((uoffset + len) < uoffset)
+ || ((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 (!can_assume(VALID_DTB) && !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 (!can_assume(VALID_DTB) && !p)
+ return FDT_END; /* premature end */
+ break;
+
+ case FDT_PROP:
+ lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
+ if (!can_assume(VALID_DTB) && !lenp)
+ return FDT_END; /* premature end */
+ /* skip-name offset, length and value */
+ offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+ + fdt32_to_cpu(*lenp);
+ if (!can_assume(LATEST) &&
+ 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 (!can_assume(VALID_INPUT)
+ && ((offset < 0) || (offset % FDT_TAGSIZE)))
+ return -FDT_ERR_BADOFFSET;
+
+ if (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 (!can_assume(VALID_INPUT)
+ && ((offset < 0) || (offset % FDT_TAGSIZE)))
+ return -FDT_ERR_BADOFFSET;
+
+ if (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)
+{
+ if (!can_assume(VALID_INPUT) && bufsize < 0)
+ return -FDT_ERR_NOSPACE;
+
+ FDT_RO_PROBE(fdt);
+
+ if (fdt_totalsize(fdt) > (unsigned int)bufsize)
+ return -FDT_ERR_NOSPACE;
+
+ memmove(buf, fdt, fdt_totalsize(fdt));
+ return 0;
+}
diff --git a/lib/libfdt/fdt_addresses.c b/lib/libfdt/fdt_addresses.c
new file mode 100644
index 0000000..c40ba09
--- /dev/null
+++ b/lib/libfdt/fdt_addresses.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
+ * Copyright (C) 2018 embedded brains GmbH
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int fdt_cells(const void *fdt, int nodeoffset, const char *name)
+{
+ const fdt32_t *c;
+ uint32_t val;
+ int len;
+
+ c = fdt_getprop(fdt, nodeoffset, name, &len);
+ if (!c)
+ return len;
+
+ if (len != sizeof(*c))
+ return -FDT_ERR_BADNCELLS;
+
+ val = fdt32_to_cpu(*c);
+ if (val > FDT_MAX_NCELLS)
+ return -FDT_ERR_BADNCELLS;
+
+ return (int)val;
+}
+
+int fdt_address_cells(const void *fdt, int nodeoffset)
+{
+ int val;
+
+ val = fdt_cells(fdt, nodeoffset, "#address-cells");
+ if (val == 0)
+ return -FDT_ERR_BADNCELLS;
+ if (val == -FDT_ERR_NOTFOUND)
+ return 2;
+ return val;
+}
+
+int fdt_size_cells(const void *fdt, int nodeoffset)
+{
+ int val;
+
+ val = fdt_cells(fdt, nodeoffset, "#size-cells");
+ if (val == -FDT_ERR_NOTFOUND)
+ return 1;
+ return val;
+}
+
+/* This function assumes that [address|size]_cells is 1 or 2 */
+int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
+ const char *name, uint64_t addr, uint64_t size)
+{
+ int addr_cells, size_cells, ret;
+ uint8_t data[sizeof(fdt64_t) * 2], *prop;
+
+ ret = fdt_address_cells(fdt, parent);
+ if (ret < 0)
+ return ret;
+ addr_cells = ret;
+
+ ret = fdt_size_cells(fdt, parent);
+ if (ret < 0)
+ return ret;
+ size_cells = ret;
+
+ /* check validity of address */
+ prop = data;
+ if (addr_cells == 1) {
+ if ((addr > UINT32_MAX) || (((uint64_t) UINT32_MAX + 1 - addr) < size))
+ return -FDT_ERR_BADVALUE;
+
+ fdt32_st(prop, (uint32_t)addr);
+ } else if (addr_cells == 2) {
+ fdt64_st(prop, addr);
+ } else {
+ return -FDT_ERR_BADNCELLS;
+ }
+
+ /* check validity of size */
+ prop += addr_cells * sizeof(fdt32_t);
+ if (size_cells == 1) {
+ if (size > UINT32_MAX)
+ return -FDT_ERR_BADVALUE;
+
+ fdt32_st(prop, (uint32_t)size);
+ } else if (size_cells == 2) {
+ fdt64_st(prop, size);
+ } else {
+ return -FDT_ERR_BADNCELLS;
+ }
+
+ return fdt_appendprop(fdt, nodeoffset, name, data,
+ (addr_cells + size_cells) * sizeof(fdt32_t));
+}
diff --git a/lib/libfdt/fdt_empty_tree.c b/lib/libfdt/fdt_empty_tree.c
new file mode 100644
index 0000000..49d54d4
--- /dev/null
+++ b/lib/libfdt/fdt_empty_tree.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2012 David Gibson, IBM Corporation.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#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);
+}
diff --git a/lib/libfdt/fdt_overlay.c b/lib/libfdt/fdt_overlay.c
new file mode 100644
index 0000000..5c0c398
--- /dev/null
+++ b/lib/libfdt/fdt_overlay.c
@@ -0,0 +1,867 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2016 Free Electrons
+ * Copyright (C) 2016 NextThing Co.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#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);
+}
+
+int fdt_overlay_target_offset(const void *fdt, const void *fdto,
+ int fragment_offset, 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_offset);
+ 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_offset, "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;
+ fixup_len /= sizeof(uint32_t);
+
+ 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; 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 = fdt_overlay_target_offset(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_RO_PROBE(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;
+
+ if (*path != '/')
+ return -FDT_ERR_BADVALUE;
+
+ /* get fragment name first */
+ s = strchr(path + 1, '/');
+ if (!s) {
+ /* Symbol refers to something that won't end
+ * up in the target tree */
+ continue;
+ }
+
+ 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) == 0)) {
+ /* /<fragment-name>/__overlay__/<relative-subnode-path> */
+ rel_path = s + len;
+ rel_path_len = e - rel_path - 1;
+ } else if ((e - s) == len
+ && (memcmp(s, "/__overlay__", len - 1) == 0)) {
+ /* /<fragment-name>/__overlay__ */
+ rel_path = "";
+ rel_path_len = 0;
+ } else {
+ /* Symbol refers to something that won't end
+ * up in the target tree */
+ continue;
+ }
+
+ /* 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 = fdt_overlay_target_offset(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 = fdt_overlay_target_offset(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;
+ int ret;
+
+ FDT_RO_PROBE(fdt);
+ FDT_RO_PROBE(fdto);
+
+ ret = fdt_find_max_phandle(fdt, &delta);
+ if (ret)
+ goto err;
+
+ 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;
+}
diff --git a/lib/libfdt/fdt_ro.c b/lib/libfdt/fdt_ro.c
new file mode 100644
index 0000000..9f6c551
--- /dev/null
+++ b/lib/libfdt/fdt_ro.c
@@ -0,0 +1,859 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#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_get_string(const void *fdt, int stroffset, int *lenp)
+{
+ int32_t totalsize;
+ uint32_t absoffset;
+ size_t len;
+ int err;
+ const char *s, *n;
+
+ if (can_assume(VALID_INPUT)) {
+ s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+
+ if (lenp)
+ *lenp = strlen(s);
+ return s;
+ }
+ totalsize = fdt_ro_probe_(fdt);
+ err = totalsize;
+ if (totalsize < 0)
+ goto fail;
+
+ err = -FDT_ERR_BADOFFSET;
+ absoffset = stroffset + fdt_off_dt_strings(fdt);
+ if (absoffset >= (unsigned)totalsize)
+ goto fail;
+ len = totalsize - absoffset;
+
+ if (fdt_magic(fdt) == FDT_MAGIC) {
+ if (stroffset < 0)
+ goto fail;
+ if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
+ if ((unsigned)stroffset >= fdt_size_dt_strings(fdt))
+ goto fail;
+ if ((fdt_size_dt_strings(fdt) - stroffset) < len)
+ len = fdt_size_dt_strings(fdt) - stroffset;
+ }
+ } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
+ unsigned int sw_stroffset = -stroffset;
+
+ if ((stroffset >= 0) ||
+ (sw_stroffset > fdt_size_dt_strings(fdt)))
+ goto fail;
+ if (sw_stroffset < len)
+ len = sw_stroffset;
+ } else {
+ err = -FDT_ERR_INTERNAL;
+ goto fail;
+ }
+
+ s = (const char *)fdt + absoffset;
+ n = memchr(s, '\0', len);
+ if (!n) {
+ /* missing terminating NULL */
+ err = -FDT_ERR_TRUNCATED;
+ goto fail;
+ }
+
+ if (lenp)
+ *lenp = n - s;
+ return s;
+
+fail:
+ if (lenp)
+ *lenp = err;
+ return NULL;
+}
+
+const char *fdt_string(const void *fdt, int stroffset)
+{
+ return fdt_get_string(fdt, stroffset, NULL);
+}
+
+static int fdt_string_eq_(const void *fdt, int stroffset,
+ const char *s, int len)
+{
+ int slen;
+ const char *p = fdt_get_string(fdt, stroffset, &slen);
+
+ return p && (slen == len) && (memcmp(p, s, len) == 0);
+}
+
+int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
+{
+ uint32_t max = 0;
+ int offset = -1;
+
+ while (true) {
+ uint32_t value;
+
+ offset = fdt_next_node(fdt, offset, NULL);
+ if (offset < 0) {
+ if (offset == -FDT_ERR_NOTFOUND)
+ break;
+
+ return offset;
+ }
+
+ value = fdt_get_phandle(fdt, offset);
+
+ if (value > max)
+ max = value;
+ }
+
+ if (phandle)
+ *phandle = max;
+
+ return 0;
+}
+
+int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
+{
+ uint32_t max;
+ int err;
+
+ err = fdt_find_max_phandle(fdt, &max);
+ if (err < 0)
+ return err;
+
+ if (max == FDT_MAX_PHANDLE)
+ return -FDT_ERR_NOPHANDLES;
+
+ if (phandle)
+ *phandle = max + 1;
+
+ return 0;
+}
+
+static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
+{
+ unsigned int offset = n * sizeof(struct fdt_reserve_entry);
+ unsigned int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
+
+ if (!can_assume(VALID_INPUT)) {
+ if (absoffset < fdt_off_mem_rsvmap(fdt))
+ return NULL;
+ if (absoffset > fdt_totalsize(fdt) -
+ sizeof(struct fdt_reserve_entry))
+ return NULL;
+ }
+ return fdt_mem_rsv_(fdt, n);
+}
+
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
+{
+ const struct fdt_reserve_entry *re;
+
+ FDT_RO_PROBE(fdt);
+ re = fdt_mem_rsv(fdt, n);
+ if (!can_assume(VALID_INPUT) && !re)
+ return -FDT_ERR_BADOFFSET;
+
+ *address = fdt64_ld_(&re->address);
+ *size = fdt64_ld_(&re->size);
+ return 0;
+}
+
+int fdt_num_mem_rsv(const void *fdt)
+{
+ int i;
+ const struct fdt_reserve_entry *re;
+
+ for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
+ if (fdt64_ld_(&re->size) == 0)
+ return i;
+ }
+ return -FDT_ERR_TRUNCATED;
+}
+
+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_RO_PROBE(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_RO_PROBE(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_ro_probe_(fdt)) < 0)
+ || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
+ goto fail;
+
+ nameptr = nh->name;
+
+ if (!can_assume(LATEST) && 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 (!can_assume(VALID_INPUT) &&
+ (err = fdt_check_prop_offset_(fdt, offset)) < 0) {
+ if (lenp)
+ *lenp = err;
+ return NULL;
+ }
+
+ prop = fdt_offset_ptr_(fdt, offset);
+
+ if (lenp)
+ *lenp = fdt32_ld_(&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 (!can_assume(LATEST) && 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;
+
+ prop = fdt_get_property_by_offset_(fdt, offset, lenp);
+ if (!can_assume(LIBFDT_FLAWLESS) && !prop) {
+ offset = -FDT_ERR_INTERNAL;
+ break;
+ }
+ if (fdt_string_eq_(fdt, fdt32_ld_(&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 (!can_assume(LATEST) && 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 (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
+ (poffset + sizeof(*prop)) % 8 && fdt32_ld_(&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) {
+ const char *name;
+ int namelen;
+
+ if (!can_assume(VALID_INPUT)) {
+ name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff),
+ &namelen);
+ *namep = name;
+ if (!name) {
+ if (lenp)
+ *lenp = namelen;
+ return NULL;
+ }
+ } else {
+ *namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff));
+ }
+ }
+
+ /* Handle realignment */
+ if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
+ (offset + sizeof(*prop)) % 8 && fdt32_ld_(&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_ld_(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_RO_PROBE(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_RO_PROBE(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 (!can_assume(VALID_INPUT)) {
+ 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 (can_assume(LIBFDT_FLAWLESS) || 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_RO_PROBE(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 == ~0U))
+ return -FDT_ERR_BADPHANDLE;
+
+ FDT_RO_PROBE(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_RO_PROBE(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() */
+}
diff --git a/lib/libfdt/fdt_rw.c b/lib/libfdt/fdt_rw.c
new file mode 100644
index 0000000..3621d36
--- /dev/null
+++ b/lib/libfdt/fdt_rw.c
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#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_probe_(void *fdt)
+{
+ if (can_assume(VALID_DTB))
+ return 0;
+ FDT_RO_PROBE(fdt);
+
+ if (!can_assume(LATEST) && 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 (!can_assume(LATEST) && fdt_version(fdt) > 17)
+ fdt_set_version(fdt, 17);
+
+ return 0;
+}
+
+#define FDT_RW_PROBE(fdt) \
+ { \
+ int err_; \
+ if ((err_ = fdt_rw_probe_(fdt)) != 0) \
+ return err_; \
+ }
+
+static inline unsigned 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;
+ unsigned int dsize = fdt_data_size_(fdt);
+ size_t soff = p - (char *)fdt;
+
+ if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize))
+ return -FDT_ERR_BADOFFSET;
+ if ((p < (char *)fdt) || (dsize + newlen < (unsigned)oldlen))
+ return -FDT_ERR_BADOFFSET;
+ if (dsize - oldlen + newlen > fdt_totalsize(fdt))
+ return -FDT_ERR_NOSPACE;
+ memmove(p + newlen, p + oldlen, ((char *)fdt + dsize) - (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;
+}
+
+/* Must only be used to roll back in case of error */
+static void fdt_del_last_string_(void *fdt, const char *s)
+{
+ int newlen = strlen(s) + 1;
+
+ fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) - newlen);
+}
+
+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;
+}
+
+/**
+ * fdt_find_add_string_() - Find or allocate a string
+ *
+ * @fdt: pointer to the device tree to check/adjust
+ * @s: string to find/add
+ * @allocated: Set to 0 if the string was found, 1 if not found and so
+ * allocated. Ignored if can_assume(NO_ROLLBACK)
+ * @return offset of string in the string table (whether found or added)
+ */
+static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
+{
+ char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
+ const char *p;
+ char *new;
+ int len = strlen(s) + 1;
+ int err;
+
+ if (!can_assume(NO_ROLLBACK))
+ *allocated = 0;
+
+ 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;
+
+ if (!can_assume(NO_ROLLBACK))
+ *allocated = 1;
+
+ 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_PROBE(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_PROBE(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;
+ int allocated;
+
+ if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
+ return nextoffset;
+
+ namestroff = fdt_find_add_string_(fdt, name, &allocated);
+ 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) {
+ /* Delete the string if we failed to add it */
+ if (!can_assume(NO_ROLLBACK) && allocated)
+ fdt_del_last_string_(fdt, name);
+ 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_PROBE(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_PROBE(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_PROBE(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_PROBE(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_PROBE(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 */
+ tag = fdt_next_tag(fdt, parentoffset, &nextoffset);
+ /* the fdt_subnode_offset_namelen() should ensure this never hits */
+ if (!can_assume(LIBFDT_FLAWLESS) && (tag != FDT_BEGIN_NODE))
+ return -FDT_ERR_INTERNAL;
+ 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_PROBE(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 strings_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), strings_size);
+ 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_RO_PROBE(fdt);
+
+ mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+ * sizeof(struct fdt_reserve_entry);
+
+ if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
+ struct_size = fdt_size_dt_struct(fdt);
+ } else if (fdt_version(fdt) == 16) {
+ struct_size = 0;
+ while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
+ ;
+ if (struct_size < 0)
+ return struct_size;
+ } else {
+ return -FDT_ERR_BADVERSION;
+ }
+
+ if (can_assume(LIBFDT_ORDER) ||
+ !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,
+ fdt_size_dt_strings(fdt));
+ 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_PROBE(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_size_dt_strings(fdt));
+ fdt_set_totalsize(fdt, fdt_data_size_(fdt));
+
+ return 0;
+}
diff --git a/lib/libfdt/fdt_strerror.c b/lib/libfdt/fdt_strerror.c
new file mode 100644
index 0000000..d852b77
--- /dev/null
+++ b/lib/libfdt/fdt_strerror.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#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),
+ FDT_ERRTABENT(FDT_ERR_BADFLAGS),
+ FDT_ERRTABENT(FDT_ERR_ALIGNMENT),
+};
+#define FDT_ERRTABSIZE ((int)(sizeof(fdt_errtable) / sizeof(fdt_errtable[0])))
+
+const char *fdt_strerror(int errval)
+{
+ if (errval > 0)
+ return "<valid offset/length>";
+ else if (errval == 0)
+ return "<no error>";
+ else if (-errval < FDT_ERRTABSIZE) {
+ const char *s = fdt_errtable[-errval].str;
+
+ if (s)
+ return s;
+ }
+
+ return "<unknown error>";
+}
diff --git a/lib/libfdt/fdt_sw.c b/lib/libfdt/fdt_sw.c
new file mode 100644
index 0000000..4c569ee
--- /dev/null
+++ b/lib/libfdt/fdt_sw.c
@@ -0,0 +1,384 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int fdt_sw_probe_(void *fdt)
+{
+ if (!can_assume(VALID_INPUT)) {
+ if (fdt_magic(fdt) == FDT_MAGIC)
+ return -FDT_ERR_BADSTATE;
+ else if (fdt_magic(fdt) != FDT_SW_MAGIC)
+ return -FDT_ERR_BADMAGIC;
+ }
+
+ return 0;
+}
+
+#define FDT_SW_PROBE(fdt) \
+ { \
+ int err; \
+ if ((err = fdt_sw_probe_(fdt)) != 0) \
+ return err; \
+ }
+
+/* 'memrsv' state: Initial state after fdt_create()
+ *
+ * Allowed functions:
+ * fdt_add_reservemap_entry()
+ * fdt_finish_reservemap() [moves to 'struct' state]
+ */
+static int fdt_sw_probe_memrsv_(void *fdt)
+{
+ int err = fdt_sw_probe_(fdt);
+ if (err)
+ return err;
+
+ if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0)
+ return -FDT_ERR_BADSTATE;
+ return 0;
+}
+
+#define FDT_SW_PROBE_MEMRSV(fdt) \
+ { \
+ int err; \
+ if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \
+ return err; \
+ }
+
+/* 'struct' state: Enter this state after fdt_finish_reservemap()
+ *
+ * Allowed functions:
+ * fdt_begin_node()
+ * fdt_end_node()
+ * fdt_property*()
+ * fdt_finish() [moves to 'complete' state]
+ */
+static int fdt_sw_probe_struct_(void *fdt)
+{
+ int err = fdt_sw_probe_(fdt);
+ if (err)
+ return err;
+
+ if (!can_assume(VALID_INPUT) &&
+ fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
+ return -FDT_ERR_BADSTATE;
+ return 0;
+}
+
+#define FDT_SW_PROBE_STRUCT(fdt) \
+ { \
+ int err; \
+ if ((err = fdt_sw_probe_struct_(fdt)) != 0) \
+ return err; \
+ }
+
+static inline uint32_t sw_flags(void *fdt)
+{
+ /* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */
+ return fdt_last_comp_version(fdt);
+}
+
+/* 'complete' state: Enter this state after fdt_finish()
+ *
+ * Allowed functions: none
+ */
+
+static void *fdt_grab_space_(void *fdt, size_t len)
+{
+ unsigned int offset = fdt_size_dt_struct(fdt);
+ unsigned 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_with_flags(void *buf, int bufsize, uint32_t flags)
+{
+ const int hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
+ sizeof(struct fdt_reserve_entry));
+ void *fdt = buf;
+
+ if (bufsize < hdrsize)
+ return -FDT_ERR_NOSPACE;
+
+ if (flags & ~FDT_CREATE_FLAGS_ALL)
+ return -FDT_ERR_BADFLAGS;
+
+ memset(buf, 0, bufsize);
+
+ /*
+ * magic and last_comp_version keep intermediate state during the fdt
+ * creation process, which is replaced with the proper FDT format by
+ * fdt_finish().
+ *
+ * flags should be accessed with sw_flags().
+ */
+ fdt_set_magic(fdt, FDT_SW_MAGIC);
+ fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+ fdt_set_last_comp_version(fdt, flags);
+
+ fdt_set_totalsize(fdt, bufsize);
+
+ fdt_set_off_mem_rsvmap(fdt, hdrsize);
+ fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
+ fdt_set_off_dt_strings(fdt, 0);
+
+ return 0;
+}
+
+int fdt_create(void *buf, int bufsize)
+{
+ return fdt_create_with_flags(buf, bufsize, 0);
+}
+
+int fdt_resize(void *fdt, void *buf, int bufsize)
+{
+ size_t headsize, tailsize;
+ char *oldtail, *newtail;
+
+ FDT_SW_PROBE(fdt);
+
+ if (bufsize < 0)
+ return -FDT_ERR_NOSPACE;
+
+ headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+ tailsize = fdt_size_dt_strings(fdt);
+
+ if (!can_assume(VALID_DTB) &&
+ headsize + tailsize > fdt_totalsize(fdt))
+ return -FDT_ERR_INTERNAL;
+
+ if ((headsize + tailsize) > (unsigned)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_totalsize(buf, bufsize);
+ if (fdt_off_dt_strings(buf))
+ fdt_set_off_dt_strings(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_PROBE_MEMRSV(fdt);
+
+ 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)
+{
+ int err = fdt_add_reservemap_entry(fdt, 0, 0);
+
+ if (err)
+ return err;
+
+ fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt));
+ return 0;
+}
+
+int fdt_begin_node(void *fdt, const char *name)
+{
+ struct fdt_node_header *nh;
+ int namelen;
+
+ FDT_SW_PROBE_STRUCT(fdt);
+
+ namelen = strlen(name) + 1;
+ 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_PROBE_STRUCT(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_add_string_(void *fdt, const char *s)
+{
+ char *strtab = (char *)fdt + fdt_totalsize(fdt);
+ unsigned int strtabsize = fdt_size_dt_strings(fdt);
+ unsigned int len = strlen(s) + 1;
+ unsigned int struct_top, offset;
+
+ 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;
+}
+
+/* Must only be used to roll back in case of error */
+static void fdt_del_last_string_(void *fdt, const char *s)
+{
+ int strtabsize = fdt_size_dt_strings(fdt);
+ int len = strlen(s) + 1;
+
+ fdt_set_size_dt_strings(fdt, strtabsize - len);
+}
+
+static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
+{
+ char *strtab = (char *)fdt + fdt_totalsize(fdt);
+ int strtabsize = fdt_size_dt_strings(fdt);
+ const char *p;
+
+ *allocated = 0;
+
+ p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
+ if (p)
+ return p - strtab;
+
+ *allocated = 1;
+
+ return fdt_add_string_(fdt, s);
+}
+
+int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
+{
+ struct fdt_property *prop;
+ int nameoff;
+ int allocated;
+
+ FDT_SW_PROBE_STRUCT(fdt);
+
+ /* String de-duplication can be slow, _NO_NAME_DEDUP skips it */
+ if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) {
+ allocated = 1;
+ nameoff = fdt_add_string_(fdt, name);
+ } else {
+ nameoff = fdt_find_add_string_(fdt, name, &allocated);
+ }
+ if (nameoff == 0)
+ return -FDT_ERR_NOSPACE;
+
+ prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
+ if (! prop) {
+ if (allocated)
+ fdt_del_last_string_(fdt, name);
+ 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_PROBE_STRUCT(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));
+
+ /* And fix up fields that were keeping intermediate state. */
+ fdt_set_last_comp_version(fdt, FDT_LAST_COMPATIBLE_VERSION);
+ fdt_set_magic(fdt, FDT_MAGIC);
+
+ return 0;
+}
diff --git a/lib/libfdt/fdt_wip.c b/lib/libfdt/fdt_wip.c
new file mode 100644
index 0000000..c2d7566
--- /dev/null
+++ b/lib/libfdt/fdt_wip.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#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 ((unsigned)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;
+}
diff --git a/lib/libfdt/libfdt.mk b/lib/libfdt/libfdt.mk
new file mode 100644
index 0000000..1cbbd78
--- /dev/null
+++ b/lib/libfdt/libfdt.mk
@@ -0,0 +1,19 @@
+#
+# 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))
diff --git a/lib/libfdt/libfdt_internal.h b/lib/libfdt/libfdt_internal.h
new file mode 100644
index 0000000..16bda19
--- /dev/null
+++ b/lib/libfdt/libfdt_internal.h
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
+#ifndef LIBFDT_INTERNAL_H
+#define LIBFDT_INTERNAL_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ */
+#include <fdt.h>
+
+#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
+#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
+
+int32_t fdt_ro_probe_(const void *fdt);
+#define FDT_RO_PROBE(fdt) \
+ { \
+ int32_t totalsize_; \
+ if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \
+ return totalsize_; \
+ }
+
+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);
+}
+
+/*
+ * Internal helpers to access tructural elements of the device tree
+ * blob (rather than for exaple reading integers from within property
+ * values). We assume that we are either given a naturally aligned
+ * address for the platform or if we are not, we are on a platform
+ * where unaligned memory reads will be handled in a graceful manner.
+ * If not the external helpers fdtXX_ld() from libfdt.h can be used
+ * instead.
+ */
+static inline uint32_t fdt32_ld_(const fdt32_t *p)
+{
+ return fdt32_to_cpu(*p);
+}
+
+static inline uint64_t fdt64_ld_(const fdt64_t *p)
+{
+ return fdt64_to_cpu(*p);
+}
+
+#define FDT_SW_MAGIC (~FDT_MAGIC)
+
+/**********************************************************************/
+/* Checking controls */
+/**********************************************************************/
+
+#ifndef FDT_ASSUME_MASK
+#define FDT_ASSUME_MASK 0
+#endif
+
+/*
+ * Defines assumptions which can be enabled. Each of these can be enabled
+ * individually. For maximum safety, don't enable any assumptions!
+ *
+ * For minimal code size and no safety, use ASSUME_PERFECT at your own risk.
+ * You should have another method of validating the device tree, such as a
+ * signature or hash check before using libfdt.
+ *
+ * For situations where security is not a concern it may be safe to enable
+ * ASSUME_SANE.
+ */
+enum {
+ /*
+ * This does essentially no checks. Only the latest device-tree
+ * version is correctly handled. Inconsistencies or errors in the device
+ * tree may cause undefined behaviour or crashes. Invalid parameters
+ * passed to libfdt may do the same.
+ *
+ * If an error occurs when modifying the tree it may leave the tree in
+ * an intermediate (but valid) state. As an example, adding a property
+ * where there is insufficient space may result in the property name
+ * being added to the string table even though the property itself is
+ * not added to the struct section.
+ *
+ * Only use this if you have a fully validated device tree with
+ * the latest supported version and wish to minimise code size.
+ */
+ ASSUME_PERFECT = 0xff,
+
+ /*
+ * This assumes that the device tree is sane. i.e. header metadata
+ * and basic hierarchy are correct.
+ *
+ * With this assumption enabled, normal device trees produced by libfdt
+ * and the compiler should be handled safely. Malicious device trees and
+ * complete garbage may cause libfdt to behave badly or crash. Truncated
+ * device trees (e.g. those only partially loaded) can also cause
+ * problems.
+ *
+ * Note: Only checks that relate exclusively to the device tree itself
+ * (not the parameters passed to libfdt) are disabled by this
+ * assumption. This includes checking headers, tags and the like.
+ */
+ ASSUME_VALID_DTB = 1 << 0,
+
+ /*
+ * This builds on ASSUME_VALID_DTB and further assumes that libfdt
+ * functions are called with valid parameters, i.e. not trigger
+ * FDT_ERR_BADOFFSET or offsets that are out of bounds. It disables any
+ * extensive checking of parameters and the device tree, making various
+ * assumptions about correctness.
+ *
+ * It doesn't make sense to enable this assumption unless
+ * ASSUME_VALID_DTB is also enabled.
+ */
+ ASSUME_VALID_INPUT = 1 << 1,
+
+ /*
+ * This disables checks for device-tree version and removes all code
+ * which handles older versions.
+ *
+ * Only enable this if you know you have a device tree with the latest
+ * version.
+ */
+ ASSUME_LATEST = 1 << 2,
+
+ /*
+ * This assumes that it is OK for a failed addition to the device tree,
+ * due to lack of space or some other problem, to skip any rollback
+ * steps (such as dropping the property name from the string table).
+ * This is safe to enable in most circumstances, even though it may
+ * leave the tree in a sub-optimal state.
+ */
+ ASSUME_NO_ROLLBACK = 1 << 3,
+
+ /*
+ * This assumes that the device tree components appear in a 'convenient'
+ * order, i.e. the memory reservation block first, then the structure
+ * block and finally the string block.
+ *
+ * This order is not specified by the device-tree specification,
+ * but is expected by libfdt. The device-tree compiler always created
+ * device trees with this order.
+ *
+ * This assumption disables a check in fdt_open_into() and removes the
+ * ability to fix the problem there. This is safe if you know that the
+ * device tree is correctly ordered. See fdt_blocks_misordered_().
+ */
+ ASSUME_LIBFDT_ORDER = 1 << 4,
+
+ /*
+ * This assumes that libfdt itself does not have any internal bugs. It
+ * drops certain checks that should never be needed unless libfdt has an
+ * undiscovered bug.
+ *
+ * This can generally be considered safe to enable.
+ */
+ ASSUME_LIBFDT_FLAWLESS = 1 << 5,
+};
+
+/**
+ * can_assume_() - check if a particular assumption is enabled
+ *
+ * @mask: Mask to check (ASSUME_...)
+ * @return true if that assumption is enabled, else false
+ */
+static inline bool can_assume_(int mask)
+{
+ return FDT_ASSUME_MASK & mask;
+}
+
+/** helper macros for checking assumptions */
+#define can_assume(_assume) can_assume_(ASSUME_ ## _assume)
+
+#endif /* LIBFDT_INTERNAL_H */
diff --git a/lib/locks/bakery/bakery_lock_coherent.c b/lib/locks/bakery/bakery_lock_coherent.c
new file mode 100644
index 0000000..748eedd
--- /dev/null
+++ b/lib/locks/bakery/bakery_lock_coherent.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <lib/bakery_lock.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <plat/common/platform.h>
+
+/*
+ * 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 and writes from a shared
+ * resource in the critical section read/write values after the lock is
+ * acquired.
+ */
+ dmbish();
+}
+
+
+/* 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. Also ensure all loads in the critical
+ * section are complete before releasing the lock. Release the lock by
+ * resetting ticket. Then signal other waiting contenders.
+ */
+ dmbish();
+ bakery->lock_data[me] = 0U;
+
+ /* Required to ensure ordering of the following sev */
+ dsb();
+ sev();
+}
diff --git a/lib/locks/bakery/bakery_lock_normal.c b/lib/locks/bakery/bakery_lock_normal.c
new file mode 100644
index 0000000..faea6c5
--- /dev/null
+++ b/lib/locks/bakery/bakery_lock_normal.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <lib/bakery_lock.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+
+/*
+ * 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);
+
+ dmbish();
+}
+
+/* Helper function to check if the lock is acquired */
+static inline __unused bool is_lock_acquired(const bakery_info_t *my_bakery_info,
+ bool 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, bool 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;
+ unsigned int my_ticket, my_prio, their_ticket;
+ bakery_info_t *their_bakery_info;
+ unsigned int their_bakery_data;
+ bool is_cached;
+
+ me = plat_my_core_pos();
+ is_cached = is_dcache_enabled();
+
+ /* 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 and writes from a shared
+ * resource in the critical section read/write values after the lock is
+ * acquired.
+ */
+ dmbish();
+}
+
+void bakery_lock_release(bakery_lock_t *lock)
+{
+ bakery_info_t *my_bakery_info;
+ bool is_cached = is_dcache_enabled();
+
+ 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. Also ensure all loads in the critical
+ * section are complete before releasing the lock. Release the lock by
+ * resetting ticket. Then signal other waiting contenders.
+ */
+ dmbish();
+ my_bakery_info->lock_data = 0U;
+ write_cache_op((uintptr_t)my_bakery_info, is_cached);
+
+ /* This sev is ordered by the dsbish in write_cahce_op */
+ sev();
+}
diff --git a/lib/locks/exclusive/aarch32/spinlock.S b/lib/locks/exclusive/aarch32/spinlock.S
new file mode 100644
index 0000000..9492cc0
--- /dev/null
+++ b/lib/locks/exclusive/aarch32/spinlock.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+ .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
diff --git a/lib/locks/exclusive/aarch64/spinlock.S b/lib/locks/exclusive/aarch64/spinlock.S
new file mode 100644
index 0000000..e941b8a
--- /dev/null
+++ b/lib/locks/exclusive/aarch64/spinlock.S
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+ .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
diff --git a/lib/mpmm/mpmm.c b/lib/mpmm/mpmm.c
new file mode 100644
index 0000000..dc61cf6
--- /dev/null
+++ b/lib/mpmm/mpmm.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <common/debug.h>
+#include <lib/mpmm/mpmm.h>
+
+#include <plat/common/platform.h>
+
+#if ENABLE_MPMM_FCONF
+# include <lib/fconf/fconf.h>
+# include <lib/fconf/fconf_mpmm_getter.h>
+#endif
+
+static uint64_t read_cpuppmcr_el3_mpmmpinctl(void)
+{
+ return (read_cpuppmcr_el3() >> CPUPPMCR_EL3_MPMMPINCTL_SHIFT) &
+ CPUPPMCR_EL3_MPMMPINCTL_MASK;
+}
+
+static void write_cpumpmmcr_el3_mpmm_en(uint64_t mpmm_en)
+{
+ uint64_t value = read_cpumpmmcr_el3();
+
+ value &= ~(CPUMPMMCR_EL3_MPMM_EN_MASK << CPUMPMMCR_EL3_MPMM_EN_SHIFT);
+ value |= (mpmm_en & CPUMPMMCR_EL3_MPMM_EN_MASK) <<
+ CPUMPMMCR_EL3_MPMM_EN_SHIFT;
+
+ write_cpumpmmcr_el3(value);
+}
+
+static bool mpmm_supported(void)
+{
+ bool supported = false;
+ const struct mpmm_topology *topology;
+
+#if ENABLE_MPMM_FCONF
+ topology = FCONF_GET_PROPERTY(mpmm, config, topology);
+#else
+ topology = plat_mpmm_topology();
+#endif /* ENABLE_MPMM_FCONF */
+
+ /*
+ * For the current core firstly try to find out if the platform
+ * configuration has claimed support for MPMM, then make sure that MPMM
+ * is controllable through the system registers.
+ */
+
+ if (topology != NULL) {
+ unsigned int core_pos = plat_my_core_pos();
+
+ supported = topology->cores[core_pos].supported &&
+ (read_cpuppmcr_el3_mpmmpinctl() == 0U);
+ } else {
+ ERROR("MPMM: failed to generate MPMM topology\n");
+ }
+
+ return supported;
+}
+
+/* Defaults to false */
+static bool mpmm_disable_for_errata;
+
+void mpmm_enable(void)
+{
+ if (mpmm_supported()) {
+ if (mpmm_disable_for_errata) {
+ WARN("MPMM: disabled by errata workaround\n");
+ return;
+ }
+ write_cpumpmmcr_el3_mpmm_en(1U);
+ }
+}
+
+/*
+ * This function is called from assembly code very early in BL31 so it must be
+ * small and simple.
+ */
+void mpmm_errata_disable(void)
+{
+ mpmm_disable_for_errata = true;
+}
diff --git a/lib/mpmm/mpmm.mk b/lib/mpmm/mpmm.mk
new file mode 100644
index 0000000..826f925
--- /dev/null
+++ b/lib/mpmm/mpmm.mk
@@ -0,0 +1,29 @@
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include lib/extensions/amu/amu.mk
+include lib/fconf/fconf.mk
+
+ifneq (${ENABLE_MPMM},0)
+ ifneq ($(ARCH),aarch64)
+ $(error MPMM support (`ENABLE_MPMM`) can only be enabled in AArch64 images (`ARCH`))
+ endif
+
+ ifeq (${ENABLE_AMU_AUXILIARY_COUNTERS},0) # For MPMM gear AMU counters
+ $(error MPMM support (`ENABLE_MPM`) requires auxiliary AMU counter support (`ENABLE_AMU_AUXILIARY_COUNTERS`))
+ endif
+endif
+
+MPMM_SOURCES := lib/mpmm/mpmm.c
+MPMM_SOURCES += ${AMU_SOURCES}
+
+ifneq (${ENABLE_MPMM_FCONF},0)
+ ifeq (${ENABLE_MPMM},0)
+ $(error MPMM FCONF support (`ENABLE_MPMM_FCONF`) requires MPMM support (`ENABLE_MPMM`))
+ endif
+
+ MPMM_SOURCES += ${FCONF_MPMM_SOURCES}
+endif
diff --git a/lib/optee/optee_utils.c b/lib/optee/optee_utils.c
new file mode 100644
index 0000000..6c87b0d
--- /dev/null
+++ b/lib/optee/optee_utils.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <lib/optee_utils.h>
+
+#include <platform_def.h>
+
+/*
+ * 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 true if valid
+ * Return false if invalid
+ ******************************************************************************/
+static bool tee_validate_header(optee_header_t *header)
+{
+ if ((header->magic == TEE_MAGIC_NUM_OPTEE) &&
+ (header->version == 2u) &&
+ (header->nb_images > 0u) &&
+ (header->nb_images <= OPTEE_MAX_NUM_IMAGES)) {
+ return true;
+ }
+
+ return false;
+}
+
+bool optee_header_is_valid(uintptr_t header_base)
+{
+ return tee_validate_header((optee_header_t *)header_base);
+}
+
+/*******************************************************************************
+ * 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;
+
+ /*
+ * image->load_addr_hi & image->load_addr_lo set to UINT32_MAX indicate
+ * loader decided address; take our pre-mapped area for current image
+ * since arm-tf could not allocate memory dynamically
+ */
+ if ((image->load_addr_hi == UINT32_MAX) &&
+ (image->load_addr_lo == UINT32_MAX)) {
+ 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;
+ uint32_t num;
+ int 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 = 0U; 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) {
+ if (paged_image_info == NULL) {
+ if (header->optee_image_list[num].size != 0U) {
+ ERROR("Paged image is not supported\n");
+ return -1;
+ }
+
+ continue;
+ } else {
+ 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.
+ */
+ if (paged_image_info != NULL) {
+ 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;
+}
diff --git a/lib/pmf/pmf_main.c b/lib/pmf/pmf_main.c
new file mode 100644
index 0000000..131a055
--- /dev/null
+++ b/lib/pmf/pmf_main.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/pmf/pmf.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * 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;
+}
diff --git a/lib/pmf/pmf_smc.c b/lib/pmf/pmf_smc.c
new file mode 100644
index 0000000..6d79502
--- /dev/null
+++ b/lib/pmf/pmf_smc.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <lib/pmf/pmf.h>
+#include <plat/common/platform.h>
+#include <smccc_helpers.h>
+
+/*
+ * 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);
+}
diff --git a/lib/psa/delegated_attestation.c b/lib/psa/delegated_attestation.c
new file mode 100644
index 0000000..399a3f1
--- /dev/null
+++ b/lib/psa/delegated_attestation.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <string.h>
+
+#include <delegated_attestation.h>
+#include <psa/client.h>
+#include <psa_manifest/sid.h>
+
+#if !PLAT_RSS_NOT_SUPPORTED
+psa_status_t
+rss_delegated_attest_get_delegated_key(uint8_t ecc_curve,
+ uint32_t key_bits,
+ uint8_t *key_buf,
+ size_t key_buf_size,
+ size_t *key_size,
+ uint32_t hash_algo)
+{
+ psa_status_t status;
+ psa_invec in_vec[] = {
+ {&ecc_curve, sizeof(ecc_curve)},
+ {&key_bits, sizeof(key_bits)},
+ {&hash_algo, sizeof(hash_algo)}
+ };
+ psa_outvec out_vec[] = {
+ {key_buf, key_buf_size}
+ };
+
+ if (key_size == NULL) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ status = psa_call(RSS_DELEGATED_SERVICE_HANDLE,
+ RSS_DELEGATED_ATTEST_GET_DELEGATED_KEY,
+ in_vec, IOVEC_LEN(in_vec),
+ out_vec, IOVEC_LEN(out_vec));
+ if (status == PSA_SUCCESS) {
+ *key_size = out_vec[0].len;
+ }
+
+ return status;
+}
+
+psa_status_t
+rss_delegated_attest_get_token(const uint8_t *dak_pub_hash,
+ size_t dak_pub_hash_size,
+ uint8_t *token_buf,
+ size_t token_buf_size,
+ size_t *token_size)
+{
+ psa_status_t status;
+ psa_invec in_vec[] = {
+ {dak_pub_hash, dak_pub_hash_size}
+ };
+ psa_outvec out_vec[] = {
+ {token_buf, token_buf_size}
+ };
+
+ if (token_size == NULL) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ status = psa_call(RSS_DELEGATED_SERVICE_HANDLE,
+ RSS_DELEGATED_ATTEST_GET_PLATFORM_TOKEN,
+ in_vec, IOVEC_LEN(in_vec),
+ out_vec, IOVEC_LEN(out_vec));
+ if (status == PSA_SUCCESS) {
+ *token_size = out_vec[0].len;
+ }
+
+ return status;
+}
+
+
+#else /* !PLAT_RSS_NOT_SUPPORTED */
+
+static const uint8_t delegated_key[] = {
+ 0x20, 0x11, 0xC7, 0xF0, 0x3C, 0xEE, 0x43, 0x25, 0x17, 0x6E,
+ 0x52, 0x4F, 0x03, 0x3C, 0x0C, 0xE1, 0xE2, 0x1A, 0x76, 0xE6,
+ 0xC1, 0xA4, 0xF0, 0xB8, 0x39, 0xAA, 0x1D, 0xF6, 0x1E, 0x0E,
+ 0x8A, 0x5C, 0x8A, 0x05, 0x74, 0x0F, 0x9B, 0x69, 0xEF, 0xA7,
+ 0xEB, 0x1A, 0x41, 0x85, 0xBD, 0x11, 0x7F, 0x68
+};
+
+static const uint8_t platform_token[] = {
+ 0xD2, 0x84, 0x43, 0xA1, 0x01, 0x26, 0xA0, 0x59,
+ 0x02, 0xBE, 0xAA, 0x3A, 0x00, 0x01, 0x24, 0xFF,
+ 0x58, 0x20, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,
+ 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,
+ 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,
+ 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,
+ 0xAB, 0xAB, 0x3A, 0x00, 0x01, 0x24, 0xFB, 0x58,
+ 0x20, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE,
+ 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6,
+ 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE,
+ 0xBF, 0x3A, 0x00, 0x01, 0x25, 0x00, 0x58, 0x21,
+ 0x01, 0xFA, 0x58, 0x75, 0x5F, 0x65, 0x86, 0x27,
+ 0xCE, 0x54, 0x60, 0xF2, 0x9B, 0x75, 0x29, 0x67,
+ 0x13, 0x24, 0x8C, 0xAE, 0x7A, 0xD9, 0xE2, 0x98,
+ 0x4B, 0x90, 0x28, 0x0E, 0xFC, 0xBC, 0xB5, 0x02,
+ 0x48, 0x3A, 0x00, 0x01, 0x24, 0xFA, 0x58, 0x20,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0x3A, 0x00, 0x01, 0x24, 0xF8, 0x20, 0x3A, 0x00,
+ 0x01, 0x24, 0xF9, 0x00, 0x3A, 0x00, 0x01, 0x24,
+ 0xFD, 0x85, 0xA5, 0x05, 0x58, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x60,
+ 0x01, 0x65, 0x42, 0x4C, 0x31, 0x5F, 0x32, 0x06,
+ 0x66, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x02,
+ 0x58, 0x20, 0xF8, 0xB7, 0xCE, 0xAD, 0x9B, 0xE4,
+ 0x5A, 0x8F, 0x5C, 0x52, 0x6F, 0x0C, 0x05, 0x25,
+ 0x8F, 0xF3, 0xE9, 0x81, 0xDC, 0xBC, 0xF2, 0x05,
+ 0x7F, 0x33, 0xF6, 0xBB, 0xDC, 0xD9, 0x4D, 0xA2,
+ 0x34, 0x3A, 0xA5, 0x05, 0x58, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x67,
+ 0x31, 0x2E, 0x37, 0x2E, 0x32, 0x2B, 0x30, 0x01,
+ 0x63, 0x42, 0x4C, 0x32, 0x06, 0x66, 0x53, 0x48,
+ 0x41, 0x32, 0x35, 0x36, 0x02, 0x58, 0x20, 0x3A,
+ 0xE5, 0x9E, 0x40, 0xA9, 0x6B, 0xD5, 0x29, 0x1C,
+ 0xAB, 0x7A, 0x5F, 0xBD, 0x1F, 0x9A, 0xA6, 0x52,
+ 0xFB, 0x77, 0x7D, 0xA3, 0xEC, 0x9C, 0x29, 0xBC,
+ 0xE6, 0x5B, 0x3B, 0x43, 0xFC, 0x9D, 0x26, 0xA5,
+ 0x05, 0x58, 0x20, 0xBF, 0xE6, 0xD8, 0x6F, 0x88,
+ 0x26, 0xF4, 0xFF, 0x97, 0xFB, 0x96, 0xC4, 0xE6,
+ 0xFB, 0xC4, 0x99, 0x3E, 0x46, 0x19, 0xFC, 0x56,
+ 0x5D, 0xA2, 0x6A, 0xDF, 0x34, 0xC3, 0x29, 0x48,
+ 0x9A, 0xDC, 0x38, 0x04, 0x67, 0x31, 0x2E, 0x35,
+ 0x2E, 0x30, 0x2B, 0x30, 0x01, 0x64, 0x52, 0x54,
+ 0x5F, 0x30, 0x06, 0x66, 0x53, 0x48, 0x41, 0x32,
+ 0x35, 0x36, 0x02, 0x58, 0x20, 0x47, 0x94, 0x9D,
+ 0x27, 0x33, 0x82, 0x45, 0x1A, 0xDD, 0x25, 0xF4,
+ 0x9A, 0x89, 0x6F, 0x5F, 0xD9, 0xB0, 0xE8, 0x14,
+ 0xD3, 0xA4, 0x9B, 0x53, 0xB0, 0x44, 0x0B, 0xCF,
+ 0x32, 0x1A, 0xC4, 0xD2, 0x65, 0xA5, 0x05, 0x58,
+ 0x20, 0xB3, 0x60, 0xCA, 0xF5, 0xC9, 0x8C, 0x6B,
+ 0x94, 0x2A, 0x48, 0x82, 0xFA, 0x9D, 0x48, 0x23,
+ 0xEF, 0xB1, 0x66, 0xA9, 0xEF, 0x6A, 0x6E, 0x4A,
+ 0xA3, 0x7C, 0x19, 0x19, 0xED, 0x1F, 0xCC, 0xC0,
+ 0x49, 0x04, 0x67, 0x30, 0x2E, 0x30, 0x2E, 0x37,
+ 0x2B, 0x30, 0x01, 0x64, 0x52, 0x54, 0x5F, 0x31,
+ 0x06, 0x66, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36,
+ 0x02, 0x58, 0x20, 0xCD, 0x38, 0xBE, 0xC8, 0xB7,
+ 0xC0, 0x9E, 0xD5, 0x24, 0x30, 0xFE, 0xC8, 0xD0,
+ 0x19, 0x12, 0x56, 0xB2, 0x7A, 0xA5, 0x53, 0x6F,
+ 0xBC, 0x7D, 0x09, 0xCA, 0x11, 0xDD, 0x90, 0xD7,
+ 0xD6, 0x70, 0xFD, 0xA5, 0x05, 0x58, 0x20, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x04,
+ 0x60, 0x01, 0x60, 0x06, 0x66, 0x53, 0x48, 0x41,
+ 0x32, 0x35, 0x36, 0x02, 0x58, 0x20, 0x28, 0x3D,
+ 0x0C, 0x25, 0x22, 0x0C, 0x87, 0x46, 0xA0, 0x58,
+ 0x64, 0x6C, 0x0B, 0x14, 0x37, 0x39, 0x40, 0x9D,
+ 0x2D, 0x11, 0xD1, 0xCC, 0x54, 0x51, 0xB4, 0x29,
+ 0x22, 0xCD, 0x70, 0x92, 0x71, 0xC3, 0x3A, 0x00,
+ 0x01, 0x25, 0x01, 0x77, 0x77, 0x77, 0x77, 0x2E,
+ 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x66,
+ 0x69, 0x72, 0x6D, 0x77, 0x61, 0x72, 0x65, 0x2E,
+ 0x6F, 0x72, 0x67, 0x3A, 0x00, 0x01, 0x24, 0xF7,
+ 0x71, 0x50, 0x53, 0x41, 0x5F, 0x49, 0x4F, 0x54,
+ 0x5F, 0x50, 0x52, 0x4F, 0x46, 0x49, 0x4C, 0x45,
+ 0x5F, 0x31, 0x3A, 0x00, 0x01, 0x24, 0xFC, 0x70,
+ 0x30, 0x36, 0x30, 0x34, 0x35, 0x36, 0x35, 0x32,
+ 0x37, 0x32, 0x38, 0x32, 0x39, 0x31, 0x30, 0x30,
+ 0x58, 0x40, 0x1E, 0x0D, 0x2B, 0xD8, 0x7A, 0xC9,
+ 0x2D, 0xCB, 0x73, 0xD1, 0x42, 0x2F, 0xBF, 0xDA,
+ 0x24, 0x71, 0xE2, 0xAF, 0xEA, 0x48, 0x60, 0x17,
+ 0x23, 0x75, 0x64, 0xAC, 0xCC, 0x23, 0xA2, 0x67,
+ 0xC4, 0xE7, 0x8F, 0x1C, 0x7C, 0x68, 0x49, 0x42,
+ 0x4D, 0xDA, 0xC6, 0xD6, 0x21, 0x1C, 0xAA, 0x00,
+ 0xDA, 0x1E, 0x68, 0x56, 0xA3, 0x48, 0xEE, 0xA7,
+ 0x92, 0xA9, 0x09, 0x83, 0x42, 0x04, 0x06, 0x9E,
+ 0x62, 0xBB
+};
+
+psa_status_t
+rss_delegated_attest_get_delegated_key(uint8_t ecc_curve,
+ uint32_t key_bits,
+ uint8_t *key_buf,
+ size_t key_buf_size,
+ size_t *key_size,
+ uint32_t hash_algo)
+{
+ (void)ecc_curve;
+ (void)key_bits;
+ (void)hash_algo;
+
+ if (key_buf_size < sizeof(delegated_key)) {
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+
+ (void)memcpy(key_buf, delegated_key, sizeof(delegated_key));
+ *key_size = sizeof(delegated_key);
+
+ return PSA_SUCCESS;
+}
+psa_status_t
+rss_delegated_attest_get_token(const uint8_t *dak_pub_hash,
+ size_t dak_pub_hash_size,
+ uint8_t *token_buf,
+ size_t token_buf_size,
+ size_t *token_size)
+{
+ (void)dak_pub_hash;
+ (void)dak_pub_hash_size;
+
+ if (token_buf_size < sizeof(platform_token)) {
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+
+ (void)memcpy(token_buf, platform_token, sizeof(platform_token));
+ *token_size = sizeof(platform_token);
+
+ return PSA_SUCCESS;
+}
+#endif /* !PLAT_RSS_NOT_SUPPORTED */
diff --git a/lib/psa/measured_boot.c b/lib/psa/measured_boot.c
new file mode 100644
index 0000000..6e9ff78
--- /dev/null
+++ b/lib/psa/measured_boot.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <string.h>
+
+#include <common/debug.h>
+#include <measured_boot.h>
+#include <psa/client.h>
+#include <psa_manifest/sid.h>
+
+#include "measured_boot_private.h"
+
+static void print_byte_array(const uint8_t *array __unused, size_t len __unused)
+{
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+ size_t i;
+
+ if (array == NULL || len == 0U) {
+ (void)printf("\n");
+ } else {
+ for (i = 0U; i < len; ++i) {
+ (void)printf(" %02x", array[i]);
+ if ((i & U(0xF)) == U(0xF)) {
+ (void)printf("\n");
+ if (i < (len - 1U)) {
+ INFO("\t\t:");
+ }
+ }
+ }
+ }
+#endif
+}
+
+static void log_measurement(uint8_t index,
+ const uint8_t *signer_id,
+ size_t signer_id_size,
+ const uint8_t *version, /* string */
+ size_t version_size,
+ const uint8_t *sw_type, /* string */
+ size_t sw_type_size,
+ uint32_t measurement_algo,
+ const uint8_t *measurement_value,
+ size_t measurement_value_size,
+ bool lock_measurement)
+{
+ INFO("Measured boot extend measurement:\n");
+ INFO(" - slot : %u\n", index);
+ INFO(" - signer_id :");
+ print_byte_array(signer_id, signer_id_size);
+ INFO(" - version : %s\n", version);
+ INFO(" - version_size: %zu\n", version_size);
+ INFO(" - sw_type : %s\n", sw_type);
+ INFO(" - sw_type_size: %zu\n", sw_type_size);
+ INFO(" - algorithm : %x\n", measurement_algo);
+ INFO(" - measurement :");
+ print_byte_array(measurement_value, measurement_value_size);
+ INFO(" - locking : %s\n", lock_measurement ? "true" : "false");
+}
+
+#if !PLAT_RSS_NOT_SUPPORTED
+psa_status_t
+rss_measured_boot_extend_measurement(uint8_t index,
+ const uint8_t *signer_id,
+ size_t signer_id_size,
+ const uint8_t *version,
+ size_t version_size,
+ uint32_t measurement_algo,
+ const uint8_t *sw_type,
+ size_t sw_type_size,
+ const uint8_t *measurement_value,
+ size_t measurement_value_size,
+ bool lock_measurement)
+{
+ struct measured_boot_extend_iovec_t extend_iov = {
+ .index = index,
+ .lock_measurement = lock_measurement,
+ .measurement_algo = measurement_algo,
+ .sw_type = {0},
+ .sw_type_size = sw_type_size,
+ };
+
+ psa_invec in_vec[] = {
+ {.base = &extend_iov,
+ .len = sizeof(struct measured_boot_extend_iovec_t)},
+ {.base = signer_id, .len = signer_id_size},
+ {.base = version, .len = version_size},
+ {.base = measurement_value, .len = measurement_value_size}
+ };
+
+ if (sw_type != NULL) {
+ if (sw_type_size > SW_TYPE_MAX_SIZE) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ memcpy(extend_iov.sw_type, sw_type, sw_type_size);
+ }
+
+ log_measurement(index, signer_id, signer_id_size,
+ version, version_size, sw_type, sw_type_size,
+ measurement_algo, measurement_value,
+ measurement_value_size, lock_measurement);
+
+ return psa_call(RSS_MEASURED_BOOT_HANDLE,
+ RSS_MEASURED_BOOT_EXTEND,
+ in_vec, IOVEC_LEN(in_vec),
+ NULL, 0);
+}
+
+#else /* !PLAT_RSS_NOT_SUPPORTED */
+
+psa_status_t
+rss_measured_boot_extend_measurement(uint8_t index,
+ const uint8_t *signer_id,
+ size_t signer_id_size,
+ const uint8_t *version,
+ size_t version_size,
+ uint32_t measurement_algo,
+ const uint8_t *sw_type,
+ size_t sw_type_size,
+ const uint8_t *measurement_value,
+ size_t measurement_value_size,
+ bool lock_measurement)
+{
+ log_measurement(index, signer_id, signer_id_size,
+ version, version_size, sw_type, sw_type_size,
+ measurement_algo, measurement_value,
+ measurement_value_size, lock_measurement);
+
+ return PSA_SUCCESS;
+}
+#endif /* !PLAT_RSS_NOT_SUPPORTED */
diff --git a/lib/psa/measured_boot_private.h b/lib/psa/measured_boot_private.h
new file mode 100644
index 0000000..649c3f6
--- /dev/null
+++ b/lib/psa/measured_boot_private.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PSA_MEASURED_BOOT_PRIVATE_H
+#define PSA_MEASURED_BOOT_PRIVATE_H
+
+#include <stdint.h>
+
+/* Measured boot message types that distinguish its services */
+#define RSS_MEASURED_BOOT_EXTEND 1002U
+
+struct measured_boot_extend_iovec_t {
+ uint8_t index;
+ uint8_t lock_measurement;
+ uint32_t measurement_algo;
+ uint8_t sw_type[SW_TYPE_MAX_SIZE];
+ uint8_t sw_type_size;
+};
+
+#endif /* PSA_MEASURED_BOOT_PRIVATE_H */
diff --git a/lib/psci/aarch32/psci_helpers.S b/lib/psci/aarch32/psci_helpers.S
new file mode 100644
index 0000000..5cc192e
--- /dev/null
+++ b/lib/psci/aarch32/psci_helpers.S
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <lib/psci/psci.h>
+#include <platform_def.h>
+
+ .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
diff --git a/lib/psci/aarch64/psci_helpers.S b/lib/psci/aarch64/psci_helpers.S
new file mode 100644
index 0000000..add968a
--- /dev/null
+++ b/lib/psci/aarch64/psci_helpers.S
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <lib/psci/psci.h>
+#include <platform_def.h>
+
+ .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
diff --git a/lib/psci/psci_common.c b/lib/psci/psci_common.c
new file mode 100644
index 0000000..8d736cc
--- /dev/null
+++ b/lib/psci/psci_common.c
@@ -0,0 +1,1052 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <drivers/delay_timer.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#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];
+
+unsigned int psci_plat_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 true, if the current CPU is the last ON CPU or false otherwise.
+ ******************************************************************************/
+bool psci_is_last_on_cpu(void)
+{
+ unsigned int cpu_idx, my_idx = plat_my_core_pos();
+
+ for (cpu_idx = 0; cpu_idx < psci_plat_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) {
+ VERBOSE("core=%u other than current core=%u %s\n",
+ cpu_idx, my_idx, "running in the system");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ * 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 < psci_plat_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;
+ unsigned int core;
+
+ for (pwrlvl = 0U; pwrlvl < PLAT_MAX_PWR_LVL; pwrlvl++) {
+ for (core = 0; core < psci_plat_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 < psci_plat_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((uint64_t)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((uint64_t)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.\n");
+ 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
+ unsigned 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 - psci_plat_core_count);
+ idx++) {
+ state_type = find_local_state_type(
+ psci_non_cpu_pd_nodes[idx].local_state);
+ INFO(" Domain Node : Level %u, parent_node %u,"
+ " 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 < psci_plat_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 %u,"
+ " 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_pwrdown_cpu(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
+}
+
+/*******************************************************************************
+ * This function invokes the callback 'stop_func()' with the 'mpidr' of each
+ * online PE. Caller can pass suitable method to stop a remote core.
+ *
+ * 'wait_ms' is the timeout value in milliseconds for the other cores to
+ * transition to power down state. Passing '0' makes it non-blocking.
+ *
+ * The function returns 'PSCI_E_DENIED' if some cores failed to stop within the
+ * given timeout.
+ ******************************************************************************/
+int psci_stop_other_cores(unsigned int wait_ms,
+ void (*stop_func)(u_register_t mpidr))
+{
+ unsigned int idx, this_cpu_idx;
+
+ this_cpu_idx = plat_my_core_pos();
+
+ /* Invoke stop_func for each core */
+ for (idx = 0U; idx < psci_plat_core_count; idx++) {
+ /* skip current CPU */
+ if (idx == this_cpu_idx) {
+ continue;
+ }
+
+ /* Check if the CPU is ON */
+ if (psci_get_aff_info_state_by_idx(idx) == AFF_STATE_ON) {
+ (*stop_func)(psci_cpu_pd_nodes[idx].mpidr);
+ }
+ }
+
+ /* Need to wait for other cores to shutdown */
+ if (wait_ms != 0U) {
+ while ((wait_ms-- != 0U) && (!psci_is_last_on_cpu())) {
+ mdelay(1U);
+ }
+
+ if (!psci_is_last_on_cpu()) {
+ WARN("Failed to stop all cores!\n");
+ psci_print_power_domain_map();
+ return PSCI_E_DENIED;
+ }
+ }
+
+ return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * This function verifies that all the other cores in the system have been
+ * turned OFF and the current CPU is the last running CPU in the system.
+ * Returns true if the current CPU is the last ON CPU or false otherwise.
+ *
+ * This API has following differences with psci_is_last_on_cpu
+ * 1. PSCI states are locked
+ ******************************************************************************/
+bool psci_is_last_on_cpu_safe(void)
+{
+ unsigned int this_core = plat_my_core_pos();
+ unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0};
+
+ psci_get_parent_pwr_domain_nodes(this_core, PLAT_MAX_PWR_LVL, parent_nodes);
+
+ psci_acquire_pwr_domain_locks(PLAT_MAX_PWR_LVL, parent_nodes);
+
+ if (!psci_is_last_on_cpu()) {
+ psci_release_pwr_domain_locks(PLAT_MAX_PWR_LVL, parent_nodes);
+ return false;
+ }
+
+ psci_release_pwr_domain_locks(PLAT_MAX_PWR_LVL, parent_nodes);
+
+ return true;
+}
diff --git a/lib/psci/psci_lib.mk b/lib/psci/psci_lib.mk
new file mode 100644
index 0000000..1d4aac4
--- /dev/null
+++ b/lib/psci/psci_lib.mk
@@ -0,0 +1,35 @@
+#
+# 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
diff --git a/lib/psci/psci_main.c b/lib/psci/psci_main.c
new file mode 100644
index 0000000..a631f3f
--- /dev/null
+++ b/lib/psci/psci_main.c
@@ -0,0 +1,545 @@
+/*
+ * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/pmf/pmf.h>
+#include <lib/runtime_instr.h>
+#include <lib/smccc.h>
+#include <plat/common/platform.h>
+#include <services/arm_arch_svc.h>
+
+#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())
+ 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 ret;
+ unsigned 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 */
+ ret = plat_core_pos_by_mpidr(target_affinity);
+ if (ret == -1) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+ target_idx = (unsigned int)ret;
+
+ /*
+ * 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(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;
+}
diff --git a/lib/psci/psci_mem_protect.c b/lib/psci/psci_mem_protect.c
new file mode 100644
index 0000000..481051f
--- /dev/null
+++ b/lib/psci/psci_mem_protect.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <limits.h>
+
+#include <lib/utils.h>
+
+#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;
+}
diff --git a/lib/psci/psci_off.c b/lib/psci/psci_off.c
new file mode 100644
index 0000000..637adb9
--- /dev/null
+++ b/lib/psci/psci_off.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/pmf/pmf.h>
+#include <lib/runtime_instr.h>
+#include <plat/common/platform.h>
+
+#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;
+ unsigned int idx = 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_pwrdown_cpu(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;
+}
diff --git a/lib/psci/psci_on.c b/lib/psci/psci_on.c
new file mode 100644
index 0000000..c70b377
--- /dev/null
+++ b/lib/psci/psci_on.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/el3_runtime/pubsub_events.h>
+#include <plat/common/platform.h>
+
+#include "psci_private.h"
+
+/*
+ * Helper functions for the CPU level spinlocks
+ */
+static inline void psci_spin_lock_cpu(unsigned int idx)
+{
+ spin_lock(&psci_cpu_pd_nodes[idx].cpu_lock);
+}
+
+static inline void psci_spin_unlock_cpu(unsigned 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 ret = plat_core_pos_by_mpidr(target_cpu);
+ unsigned int target_idx = (unsigned int)ret;
+
+ /* Calling function must supply valid input arguments */
+ assert(ret >= 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(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(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(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(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(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(unsigned 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_ns();
+}
diff --git a/lib/psci/psci_private.h b/lib/psci/psci_private.h
new file mode 100644
index 0000000..1901c17
--- /dev/null
+++ b/lib/psci/psci_private.h
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSCI_PRIVATE_H
+#define PSCI_PRIVATE_H
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <lib/bakery_lock.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/psci/psci.h>
+#include <lib/spinlock.h>
+
+/*
+ * 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))
+
+/* Internally PSCI uses a uint16_t for various cpu indexes so
+ * define a limit to number of CPUs that can be initialised.
+ */
+#define PSCI_MAX_CPUS_INDEX 0xFFFFU
+
+/* Invalid parent */
+#define PSCI_PARENT_NODE_INVALID 0xFFFFFFFFU
+
+/*
+ * 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*/
+ uint16_t 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,
+ uint16_t 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;
+extern unsigned int psci_plat_core_count;
+
+/*******************************************************************************
+ * 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);
+bool psci_is_last_on_cpu(void);
+int psci_spd_migrate_info(u_register_t *mpidr);
+
+/*
+ * 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(unsigned 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(unsigned 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 */
diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c
new file mode 100644
index 0000000..3cb4f7e
--- /dev/null
+++ b/lib/psci/psci_setup.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/cpus/errata_report.h>
+#include <plat/common/platform.h>
+
+#include "psci_private.h"
+
+/*
+ * Check that PLATFORM_CORE_COUNT fits into the number of cores
+ * that can be represented by PSCI_MAX_CPUS_INDEX.
+ */
+CASSERT(PLATFORM_CORE_COUNT <= (PSCI_MAX_CPUS_INDEX + 1U), assert_psci_cores_overflow);
+
+/*******************************************************************************
+ * 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(uint16_t node_idx,
+ unsigned int parent_idx,
+ unsigned char level)
+{
+ if (level > PSCI_CPU_PWR_LVL) {
+ assert(node_idx < PSCI_NUM_NON_CPU_PWR_DOMAINS);
+
+ 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;
+
+ assert(node_idx < PLATFORM_CORE_COUNT);
+
+ 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)
+{
+ unsigned int cpu_idx;
+ int j;
+ unsigned int nodes_idx[PLAT_MAX_PWR_LVL] = {0};
+ unsigned int temp_index[PLAT_MAX_PWR_LVL];
+
+ for (cpu_idx = 0; cpu_idx < psci_plat_core_count; cpu_idx++) {
+ psci_get_parent_pwr_domain_nodes(cpu_idx,
+ 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 unsigned int __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;
+ unsigned int parent_node_index = 0U;
+ 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((uint16_t)j,
+ parent_node_index - 1U,
+ (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(j <= PLATFORM_CORE_COUNT);
+ return j;
+}
+
+/*******************************************************************************
+ * 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 */
+ psci_plat_core_count = 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)) {
+ if (psci_plat_pm_ops->validate_power_state != 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);
+}
diff --git a/lib/psci/psci_stat.c b/lib/psci/psci_stat.c
new file mode 100644
index 0000000..ecef95a
--- /dev/null
+++ b/lib/psci/psci_stat.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+#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 - 1U] = -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;
+ unsigned int cpu_idx = 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] = (int)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;
+ unsigned int cpu_idx = 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,
+ (unsigned int)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;
+}
diff --git a/lib/psci/psci_suspend.c b/lib/psci/psci_suspend.c
new file mode 100644
index 0000000..f71994d
--- /dev/null
+++ b/lib/psci/psci_suspend.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/el3_runtime/pubsub_events.h>
+#include <lib/pmf/pmf.h>
+#include <lib/runtime_instr.h>
+#include <plat/common/platform.h>
+
+#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(unsigned 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_pwrdown_cpu(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;
+ unsigned int idx = 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(unsigned 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_ns();
+}
diff --git a/lib/psci/psci_system_off.c b/lib/psci/psci_system_off.c
new file mode 100644
index 0000000..002392c
--- /dev/null
+++ b/lib/psci/psci_system_off.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <plat/common/platform.h>
+
+#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();
+ }
+
+ 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();
+ }
+
+ 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();
+ }
+ console_flush();
+
+ return (u_register_t)
+ psci_plat_pm_ops->system_reset2((int) is_vendor, reset_type,
+ cookie);
+}
diff --git a/lib/romlib/Makefile b/lib/romlib/Makefile
new file mode 100644
index 0000000..2ff480b
--- /dev/null
+++ b/lib/romlib/Makefile
@@ -0,0 +1,98 @@
+#
+# 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
diff --git a/lib/romlib/gen_combined_bl1_romlib.sh b/lib/romlib/gen_combined_bl1_romlib.sh
new file mode 100755
index 0000000..1e3f73a
--- /dev/null
+++ b/lib/romlib/gen_combined_bl1_romlib.sh
@@ -0,0 +1,53 @@
+#!/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
diff --git a/lib/romlib/init.s b/lib/romlib/init.s
new file mode 100644
index 0000000..7d97e4d
--- /dev/null
+++ b/lib/romlib/init.s
@@ -0,0 +1,36 @@
+/*
+ * 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
diff --git a/lib/romlib/jmptbl.i b/lib/romlib/jmptbl.i
new file mode 100644
index 0000000..33710f5
--- /dev/null
+++ b/lib/romlib/jmptbl.i
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2018-2020, 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
+fdt fdt_setprop_inplace_namelen_partial
+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
diff --git a/lib/romlib/romlib.ld.S b/lib/romlib/romlib.ld.S
new file mode 100644
index 0000000..2aac4ad
--- /dev/null
+++ b/lib/romlib/romlib.ld.S
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <platform_def.h>
+
+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);
+}
diff --git a/lib/romlib/romlib_generator.py b/lib/romlib/romlib_generator.py
new file mode 100755
index 0000000..0682dd4
--- /dev/null
+++ b/lib/romlib/romlib_generator.py
@@ -0,0 +1,277 @@
+#!/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 <lib>_<fn_name>.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)
diff --git a/lib/romlib/templates/jmptbl_entry_function.S b/lib/romlib/templates/jmptbl_entry_function.S
new file mode 100644
index 0000000..a0f8456
--- /dev/null
+++ b/lib/romlib/templates/jmptbl_entry_function.S
@@ -0,0 +1,6 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+ b ${function_name}
diff --git a/lib/romlib/templates/jmptbl_entry_function_bti.S b/lib/romlib/templates/jmptbl_entry_function_bti.S
new file mode 100644
index 0000000..d96ee94
--- /dev/null
+++ b/lib/romlib/templates/jmptbl_entry_function_bti.S
@@ -0,0 +1,7 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+ bti j
+ b ${function_name}
diff --git a/lib/romlib/templates/jmptbl_entry_reserved.S b/lib/romlib/templates/jmptbl_entry_reserved.S
new file mode 100644
index 0000000..a9b5f18
--- /dev/null
+++ b/lib/romlib/templates/jmptbl_entry_reserved.S
@@ -0,0 +1,6 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+ b .
diff --git a/lib/romlib/templates/jmptbl_entry_reserved_bti.S b/lib/romlib/templates/jmptbl_entry_reserved_bti.S
new file mode 100644
index 0000000..a9f0375
--- /dev/null
+++ b/lib/romlib/templates/jmptbl_entry_reserved_bti.S
@@ -0,0 +1,7 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+ bti j
+ b .
diff --git a/lib/romlib/templates/jmptbl_glob_var.S b/lib/romlib/templates/jmptbl_glob_var.S
new file mode 100644
index 0000000..d306512
--- /dev/null
+++ b/lib/romlib/templates/jmptbl_glob_var.S
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+ .data
+ .globl jmptbl
+ .align 4
+jmptbl: .quad 0x${jmptbl_address}
diff --git a/lib/romlib/templates/jmptbl_header.S b/lib/romlib/templates/jmptbl_header.S
new file mode 100644
index 0000000..72b8ce5
--- /dev/null
+++ b/lib/romlib/templates/jmptbl_header.S
@@ -0,0 +1,8 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+ .text
+ .globl jmptbl
+jmptbl:
diff --git a/lib/romlib/templates/wrapper.S b/lib/romlib/templates/wrapper.S
new file mode 100644
index 0000000..734a68a
--- /dev/null
+++ b/lib/romlib/templates/wrapper.S
@@ -0,0 +1,12 @@
+/*
+ * 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
diff --git a/lib/romlib/templates/wrapper_bti.S b/lib/romlib/templates/wrapper_bti.S
new file mode 100644
index 0000000..ba9b11c
--- /dev/null
+++ b/lib/romlib/templates/wrapper_bti.S
@@ -0,0 +1,13 @@
+/*
+ * 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
diff --git a/lib/semihosting/aarch32/semihosting_call.S b/lib/semihosting/aarch32/semihosting_call.S
new file mode 100644
index 0000000..aced3d1
--- /dev/null
+++ b/lib/semihosting/aarch32/semihosting_call.S
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+ .globl semihosting_call
+
+func semihosting_call
+ svc #0x123456
+ bx lr
+endfunc semihosting_call
diff --git a/lib/semihosting/aarch64/semihosting_call.S b/lib/semihosting/aarch64/semihosting_call.S
new file mode 100644
index 0000000..97d2bca
--- /dev/null
+++ b/lib/semihosting/aarch64/semihosting_call.S
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+ .globl semihosting_call
+
+func semihosting_call
+ hlt #0xf000
+ ret
+endfunc semihosting_call
diff --git a/lib/semihosting/semihosting.c b/lib/semihosting/semihosting.c
new file mode 100644
index 0000000..163a82d
--- /dev/null
+++ b/lib/semihosting/semihosting.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <lib/semihosting.h>
+
+#ifndef SEMIHOSTING_SUPPORTED
+#define SEMIHOSTING_SUPPORTED 1
+#endif
+
+long semihosting_call(unsigned long operation, uintptr_t 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, (uintptr_t)&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, (uintptr_t)&seek_block);
+
+ if (result < 0) {
+ result = semihosting_call(SEMIHOSTING_SYS_ERRNO, 0);
+ } else {
+ result = 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, (uintptr_t)&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,
+ (uintptr_t)&write_block);
+
+ *length = result;
+
+ return (result == 0) ? 0 : -EINVAL;
+}
+
+long semihosting_file_close(long file_handle)
+{
+ return semihosting_call(SEMIHOSTING_SYS_CLOSE, (uintptr_t)&file_handle);
+}
+
+long semihosting_file_length(long file_handle)
+{
+ return semihosting_call(SEMIHOSTING_SYS_FLEN, (uintptr_t)&file_handle);
+}
+
+char semihosting_read_char(void)
+{
+ return semihosting_call(SEMIHOSTING_SYS_READC, 0);
+}
+
+void semihosting_write_char(char character)
+{
+ semihosting_call(SEMIHOSTING_SYS_WRITEC, (uintptr_t)&character);
+}
+
+void semihosting_write_string(char *string)
+{
+ semihosting_call(SEMIHOSTING_SYS_WRITE0, (uintptr_t)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,
+ (uintptr_t)&system_block);
+}
+
+long semihosting_get_flen(const char *file_name)
+{
+ long file_handle;
+ long length;
+
+ assert(semihosting_connection_supported() != 0);
+
+ 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) != 0) ? -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 == 0U) {
+ return ret;
+ }
+
+ assert(semihosting_connection_supported() != 0);
+
+ 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 == (size_t)(-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 != 0) {
+ goto semihosting_fail;
+ } else {
+ ret = (long)length;
+ }
+
+semihosting_fail:
+ semihosting_file_close(file_handle);
+ return ret;
+}
+
+void semihosting_exit(uint32_t reason, uint32_t subcode)
+{
+#ifdef __aarch64__
+ uint64_t parameters[] = {reason, subcode};
+
+ (void)semihosting_call(SEMIHOSTING_SYS_EXIT, (uintptr_t)&parameters);
+#else
+ /* The subcode is not supported on AArch32. */
+ (void)semihosting_call(SEMIHOSTING_SYS_EXIT, reason);
+#endif
+}
diff --git a/lib/stack_protector/aarch32/asm_stack_protector.S b/lib/stack_protector/aarch32/asm_stack_protector.S
new file mode 100644
index 0000000..19b7525
--- /dev/null
+++ b/lib/stack_protector/aarch32/asm_stack_protector.S
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+
+ .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
+
+
diff --git a/lib/stack_protector/aarch64/asm_stack_protector.S b/lib/stack_protector/aarch64/asm_stack_protector.S
new file mode 100644
index 0000000..c2245d3
--- /dev/null
+++ b/lib/stack_protector/aarch64/asm_stack_protector.S
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+
+ .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
+
+
diff --git a/lib/stack_protector/stack_protector.c b/lib/stack_protector/stack_protector.c
new file mode 100644
index 0000000..3ff74fc
--- /dev/null
+++ b/lib/stack_protector/stack_protector.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+/*
+ * 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();
+}
+
diff --git a/lib/stack_protector/stack_protector.mk b/lib/stack_protector/stack_protector.mk
new file mode 100644
index 0000000..b5aba15
--- /dev/null
+++ b/lib/stack_protector/stack_protector.mk
@@ -0,0 +1,28 @@
+#
+# 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
+
+ifeq (${ENABLE_STACK_PROTECTOR},none)
+ TF_CFLAGS += -fno-stack-protector
+else
+ 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))
diff --git a/lib/utils/mem_region.c b/lib/utils/mem_region.c
new file mode 100644
index 0000000..fec086b
--- /dev/null
+++ b/lib/utils/mem_region.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+
+/*
+ * 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 != NULL);
+ assert(nregions > 0U);
+
+ 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 != 0U);
+ assert(chunk != 0U);
+
+ for (unsigned int i = 0U; i < nregions; i++) {
+ begin = regions[i].base;
+ size = regions[i].nbytes;
+ if (((begin & (chunk-1U)) != 0U) ||
+ ((size & (chunk-1U)) != 0U)) {
+ INFO("PSCI: Not correctly aligned region\n");
+ panic();
+ }
+
+ while (size > 0U) {
+ r = mmap_add_dynamic_region(begin, va, chunk, attr);
+ if (r != 0) {
+ INFO("PSCI: %s failed with %d\n",
+ "mmap_add_dynamic_region", r);
+ panic();
+ }
+
+ zero_normalmem((void *)va, chunk);
+
+ r = mmap_remove_dynamic_region(va, chunk);
+ if (r != 0) {
+ INFO("PSCI: %s failed with %d\n",
+ "mmap_remove_dynamic_region", 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 != NULL);
+ assert(nbytes != 0U);
+ assert(!check_uptr_overflow(addr, nbytes-1));
+
+ region_start = addr;
+ region_end = addr + (nbytes - 1U);
+ for (i = 0U; 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;
+}
diff --git a/lib/xlat_mpu/aarch64/enable_mpu.S b/lib/xlat_mpu/aarch64/enable_mpu.S
new file mode 100644
index 0000000..3791f2d
--- /dev/null
+++ b/lib/xlat_mpu/aarch64/enable_mpu.S
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <platform_def.h>
+
+ .global enable_mpu_direct_el2
+
+ /* void enable_mmu_direct_el2(unsigned int flags) */
+func enable_mpu_direct_el2
+#if ENABLE_ASSERTIONS
+ mrs x1, sctlr_el2
+ tst x1, #SCTLR_M_BIT
+ ASM_ASSERT(eq)
+#endif
+ mov x7, x0
+ adrp x0, mmu_cfg_params
+ add x0, x0, :lo12:mmu_cfg_params
+
+ /* (MAIRs are already set up) */
+
+ /* TCR */
+ ldr x2, [x0, #(MMU_CFG_TCR << 3)]
+ msr tcr_el2, x2
+
+ /*
+ * 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_el2
+ 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_el2, x4
+ isb
+
+ ret
+endfunc enable_mpu_direct_el2
diff --git a/lib/xlat_mpu/aarch64/xlat_mpu_arch.c b/lib/xlat_mpu/aarch64/xlat_mpu_arch.c
new file mode 100644
index 0000000..5068eb8
--- /dev/null
+++ b/lib/xlat_mpu/aarch64/xlat_mpu_arch.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "../xlat_mpu_private.h"
+#include <arch.h>
+#include <arch_features.h>
+#include <lib/cassert.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <fvp_r_arch_helpers.h>
+
+#warning "xlat_mpu library is currently experimental and its API may change in future."
+
+#if ENABLE_ASSERTIONS
+/*
+ * 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_mpu_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 {
+ assert(xlat_arch_current_el() >= 2U);
+ return (read_sctlr_el2() & SCTLR_M_BIT) != 0U;
+ }
+}
+
+bool is_dcache_enabled(void)
+{
+ unsigned int el = get_current_el();
+
+ if (el == 1U) {
+ return (read_sctlr_el1() & SCTLR_C_BIT) != 0U;
+ } else { /* must be EL2 */
+ return (read_sctlr_el2() & SCTLR_C_BIT) != 0U;
+ }
+}
+
+unsigned int xlat_arch_current_el(void)
+{
+ unsigned int el = (unsigned int)GET_EL(read_CurrentEl());
+
+ assert(el > 0U);
+
+ return el;
+}
+
diff --git a/lib/xlat_mpu/ro_xlat_mpu.mk b/lib/xlat_mpu/ro_xlat_mpu.mk
new file mode 100644
index 0000000..23f1d46
--- /dev/null
+++ b/lib/xlat_mpu/ro_xlat_mpu.mk
@@ -0,0 +1,14 @@
+#
+# Copyright (c) 2021, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${USE_DEBUGFS}, 1)
+ $(error "Debugfs requires functionality from the dynamic translation \
+ library and is incompatible with ALLOW_RO_XLAT_TABLES.")
+endif
+
+ifeq (${ARCH},aarch32)
+ $(error "The xlat_mpu library does not currently support AArch32.")
+endif
diff --git a/lib/xlat_mpu/xlat_mpu.mk b/lib/xlat_mpu/xlat_mpu.mk
new file mode 100644
index 0000000..041b91c
--- /dev/null
+++ b/lib/xlat_mpu/xlat_mpu.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+XLAT_MPU_LIB_V1_SRCS := $(addprefix lib/xlat_mpu/, \
+ ${ARCH}/enable_mpu.S \
+ ${ARCH}/xlat_mpu_arch.c \
+ xlat_mpu_context.c \
+ xlat_mpu_core.c \
+ xlat_mpu_utils.c)
+
+XLAT_MPU_LIB_V1 := 1
+$(eval $(call add_define,XLAT_MPU_LIB_V1))
+
+ifeq (${ALLOW_XLAT_MPU}, 1)
+ include lib/xlat_mpu_v2/ro_xlat_mpu.mk
+endif
diff --git a/lib/xlat_mpu/xlat_mpu_context.c b/lib/xlat_mpu/xlat_mpu_context.c
new file mode 100644
index 0000000..28c463b
--- /dev/null
+++ b/lib/xlat_mpu/xlat_mpu_context.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+
+#include "lib/xlat_mpu/xlat_mpu.h"
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include "xlat_mpu_private.h"
+
+#include <fvp_r_arch_helpers.h>
+#include <platform_def.h>
+
+#warning "xlat_mpu library is currently experimental and its API may change in future."
+
+
+/*
+ * 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(const mmap_region_t *mm)
+{
+ mmap_add_ctx(&tf_xlat_ctx, mm);
+}
+
+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 {
+ assert(current_el == 2U);
+ tf_xlat_ctx.xlat_regime = EL2_REGIME;
+ }
+ /* Note: If EL3 is supported in future v8-R64, add EL3 assignment */
+ 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);
+}
+
+void enable_mpu_el2(unsigned int flags)
+{
+ /* EL2 is strictly MPU on v8-R64, so no need for setup_mpu_cfg() */
+ enable_mpu_direct_el2(flags);
+}
diff --git a/lib/xlat_mpu/xlat_mpu_core.c b/lib/xlat_mpu/xlat_mpu_core.c
new file mode 100644
index 0000000..6b4b0c2
--- /dev/null
+++ b/lib/xlat_mpu/xlat_mpu_core.c
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch_features.h>
+#include <common/debug.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include "xlat_mpu_private.h"
+
+#include <fvp_r_arch_helpers.h>
+#include <platform_def.h>
+
+#warning "xlat_mpu library is currently experimental and its API may change in future."
+
+
+/* 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);
+ }
+}
+
+
+
+/* Calculate region-attributes byte for PRBAR part of MPU-region descriptor: */
+uint64_t prbar_attr_value(uint32_t attr)
+{
+ uint64_t retValue = UL(0);
+ uint64_t extract; /* temp var holding bit extracted from attr */
+
+ /* Extract and stuff SH: */
+ extract = (uint64_t) ((attr >> MT_SHAREABILITY_SHIFT)
+ & MT_SHAREABILITY_MASK);
+ retValue |= (extract << PRBAR_SH_SHIFT);
+
+ /* Extract and stuff AP: */
+ extract = (uint64_t) ((attr >> MT_PERM_SHIFT) & MT_PERM_MASK);
+ if (extract == 0U) {
+ retValue |= (UL(2) << PRBAR_AP_SHIFT);
+ } else /* extract == 1 */ {
+ retValue |= (UL(0) << PRBAR_AP_SHIFT);
+ }
+
+ /* Extract and stuff XN: */
+ extract = (uint64_t) ((attr >> MT_EXECUTE_SHIFT) & MT_EXECUTE_MASK);
+ retValue |= (extract << PRBAR_XN_SHIFT);
+ /* However, also don't execute in peripheral space: */
+ extract = (uint64_t) ((attr >> MT_TYPE_SHIFT) & MT_TYPE_MASK);
+ if (extract == 0U) {
+ retValue |= (UL(1) << PRBAR_XN_SHIFT);
+ }
+ return retValue;
+}
+
+/* Calculate region-attributes byte for PRLAR part of MPU-region descriptor: */
+uint64_t prlar_attr_value(uint32_t attr)
+{
+ uint64_t retValue = UL(0);
+ uint64_t extract; /* temp var holding bit extracted from attr */
+
+ /* Extract and stuff AttrIndx: */
+ extract = (uint64_t) ((attr >> MT_TYPE_SHIFT)
+ & MT_TYPE_MASK);
+ switch (extract) {
+ case UL(0):
+ retValue |= (UL(1) << PRLAR_ATTR_SHIFT);
+ break;
+ case UL(2):
+ /* 0, so OR in nothing */
+ break;
+ case UL(3):
+ retValue |= (UL(2) << PRLAR_ATTR_SHIFT);
+ break;
+ default:
+ retValue |= (extract << PRLAR_ATTR_SHIFT);
+ break;
+ }
+
+ /* Stuff EN: */
+ retValue |= (UL(1) << PRLAR_EN_SHIFT);
+
+ /* Force NS to 0 (Secure); v8-R64 only supports Secure: */
+ extract = ~(1U << PRLAR_NS_SHIFT);
+ retValue &= extract;
+
+ return retValue;
+}
+
+/*
+ * Function that writes an MPU "translation" into the MPU registers. If not
+ * possible (e.g., if no more MPU regions available) boot is aborted.
+ */
+static void mpu_map_region(mmap_region_t *mm)
+{
+ uint64_t prenr_el2_value = 0UL;
+ uint64_t prbar_attrs = 0UL;
+ uint64_t prlar_attrs = 0UL;
+ int region_to_use = 0;
+
+ /* If all MPU regions in use, then abort boot: */
+ prenr_el2_value = read_prenr_el2();
+ assert(prenr_el2_value != 0xffffffff);
+
+ /* Find and select first-available MPU region (PRENR has an enable bit
+ * for each MPU region, 1 for in-use or 0 for unused):
+ */
+ for (region_to_use = 0; region_to_use < N_MPU_REGIONS;
+ region_to_use++) {
+ if (((prenr_el2_value >> region_to_use) & 1) == 0) {
+ break;
+ }
+ }
+ write_prselr_el2((uint64_t) (region_to_use));
+ isb();
+
+ /* Set base and limit addresses: */
+ write_prbar_el2(mm->base_pa & PRBAR_PRLAR_ADDR_MASK);
+ write_prlar_el2((mm->base_pa + mm->size - 1UL)
+ & PRBAR_PRLAR_ADDR_MASK);
+ dsbsy();
+ isb();
+
+ /* Set attributes: */
+ prbar_attrs = prbar_attr_value(mm->attr);
+ write_prbar_el2(read_prbar_el2() | prbar_attrs);
+ prlar_attrs = prlar_attr_value(mm->attr);
+ write_prlar_el2(read_prlar_el2() | prlar_attrs);
+ dsbsy();
+ isb();
+
+ /* Mark this MPU region as used: */
+ prenr_el2_value |= (1 << region_to_use);
+ write_prenr_el2(prenr_el2_value);
+ isb();
+}
+
+/*
+ * 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;
+
+ unsigned long long end_pa = base_pa + size - 1U;
+ uintptr_t end_va = base_va + size - 1U;
+
+ if (base_pa != base_va) {
+ return -EINVAL; /* MPU does not perform address translation */
+ }
+ if ((base_pa % 64ULL) != 0ULL) {
+ return -EINVAL; /* MPU requires 64-byte alignment */
+ }
+ /* Check for overflows */
+ if ((base_pa > end_pa) || (base_va > end_va)) {
+ return -ERANGE;
+ }
+ if (end_pa > 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 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;
+ }
+}
+
+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++;
+ }
+}
+
+void __init init_xlat_tables_ctx(xlat_ctx_t *ctx)
+{
+ uint64_t mair = UL(0);
+
+ assert(ctx != NULL);
+ assert(!ctx->initialized);
+ assert((ctx->xlat_regime == EL2_REGIME) ||
+ (ctx->xlat_regime == EL1_EL0_REGIME));
+ /* Note: Add EL3_REGIME if EL3 is supported in future v8-R64 cores. */
+ assert(!is_mpu_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;
+
+ /* Also mark all MPU regions as invalid in the MPU hardware itself: */
+ write_prenr_el2(0);
+ /* Sufficient for current, max-32-region implementations. */
+ dsbsy();
+ isb();
+ while (mm->size != 0U) {
+ if (read_prenr_el2() == ALL_MPU_EL2_REGIONS_USED) {
+ ERROR("Not enough MPU regions 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();
+ } else {
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+ xlat_clean_dcache_range((uintptr_t)mm->base_va,
+ mm->size);
+#endif
+ mpu_map_region(mm);
+ }
+ mm++;
+ }
+
+ ctx->initialized = true;
+
+ xlat_tables_print(ctx);
+
+ /* 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_el2(mair);
+ dsbsy();
+ isb();
+}
+
+/*
+ * Function to wipe clean and disable all MPU regions. This function expects
+ * that the MPU has already been turned off, and caching concerns addressed,
+ * but it nevertheless also explicitly turns off the MPU.
+ */
+void clear_all_mpu_regions(void)
+{
+ uint64_t sctlr_el2_value = 0UL;
+ uint64_t region_n = 0UL;
+
+ /*
+ * MPU should already be disabled, but explicitly disable it
+ * nevertheless:
+ */
+ sctlr_el2_value = read_sctlr_el2() & ~(1UL);
+ write_sctlr_el2(sctlr_el2_value);
+
+ /* Disable all regions: */
+ write_prenr_el2(0UL);
+
+ /* Sequence through all regions, zeroing them out and turning off: */
+ for (region_n = 0UL; region_n < N_MPU_REGIONS; region_n++) {
+ write_prselr_el2(region_n);
+ isb();
+ write_prbar_el2((uint64_t) 0);
+ write_prlar_el2((uint64_t) 0);
+ dsbsy();
+ isb();
+ }
+}
diff --git a/lib/xlat_mpu/xlat_mpu_private.h b/lib/xlat_mpu/xlat_mpu_private.h
new file mode 100644
index 0000000..e0e479d
--- /dev/null
+++ b/lib/xlat_mpu/xlat_mpu_private.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef XLAT_MPU_PRIVATE_H
+#define XLAT_MPU_PRIVATE_H
+
+#include <stdbool.h>
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <platform_def.h>
+
+#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.
+ */
+
+#endif /* PLAT_XLAT_TABLES_DYNAMIC */
+
+/* Calculate region-attributes byte for PRBAR part of MPU-region descriptor: */
+uint64_t prbar_attr_value(uint32_t attr);
+/* Calculate region-attributes byte for PRLAR part of MPU-region descriptor: */
+uint64_t prlar_attr_value(uint32_t attr);
+/* Calculates the attr value for a given PRBAR and PRLAR entry value: */
+uint32_t region_attr(uint64_t prbar_attr, uint64_t prlar_attr);
+
+#define PRBAR_PRLAR_ADDR_MASK UL(0xffffffffffc0)
+ /* mask for PRBAR & PRLAR MPU-region field */
+/* MPU region attribute bit fields: */
+#define PRBAR_SH_SHIFT UL(4)
+#define PRBAR_SH_MASK UL(0x3)
+#define PRBAR_AP_SHIFT UL(2)
+#define PRBAR_AP_MASK UL(0x3)
+#define PRBAR_XN_SHIFT UL(1)
+#define PRBAR_XN_MASK UL(0x3)
+#define PRLAR_NS_SHIFT UL(4)
+#define PRLAR_NS_MASK UL(0x3)
+#define PRBAR_ATTR_SHIFT UL(0)
+#define PRBAR_ATTR_MASK UL(0x3f)
+#define PRLAR_ATTR_SHIFT UL(1)
+#define PRLAR_ATTR_MASK UL(0x7)
+#define PRLAR_EN_SHIFT UL(0)
+#define PRLAR_EN_MASK UL(0x1)
+/* Aspects of the source attributes not defined elsewhere: */
+#define MT_PERM_MASK UL(0x1)
+#define MT_SEC_MASK UL(0x1)
+#define MT_EXECUTE_MASK UL(0x3)
+#define MT_TYPE_SHIFT UL(0)
+
+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);
+
+/* 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);
+
+/*
+ * Returns true if the MMU of the translation regime managed by the given
+ * xlat_ctx_t is enabled, false otherwise.
+ */
+bool is_mpu_enabled_ctx(const xlat_ctx_t *ctx);
+
+/*
+ * Returns minimum virtual address space size supported by the architecture
+ */
+uintptr_t xlat_get_min_virt_addr_space_size(void);
+
+#endif /* XLAT_MPU_PRIVATE_H */
diff --git a/lib/xlat_mpu/xlat_mpu_utils.c b/lib/xlat_mpu/xlat_mpu_utils.c
new file mode 100644
index 0000000..5400875
--- /dev/null
+++ b/lib/xlat_mpu/xlat_mpu_utils.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <common/debug.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include "xlat_mpu_private.h"
+
+#include <fvp_r_arch_helpers.h>
+#include <platform_def.h>
+
+#warning "xlat_mpu library is currently experimental and its API may change in future."
+
+
+void xlat_mmap_print(__unused const mmap_region_t *mmap)
+{
+ /* Empty */
+}
+
+#if LOG_LEVEL < LOG_LEVEL_VERBOSE
+
+void xlat_tables_print(__unused xlat_ctx_t *ctx)
+{
+ /* Empty */
+}
+
+#else /* if LOG_LEVEL >= LOG_LEVEL_VERBOSE */
+
+static void xlat_tables_print_internal(__unused xlat_ctx_t *ctx)
+{
+ int region_to_use = 0;
+ uintptr_t region_base;
+ size_t region_size;
+ uint64_t prenr_el2_value = 0U;
+
+ /*
+ * 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.
+ */
+
+ /*
+ * TODO: Remove this WARN() and comment when these API calls are more
+ * completely implemented and tested!
+ */
+ WARN("%s in this early version of xlat_mpu library may not produce reliable results!",
+ __func__);
+
+ /*
+ * Sequence through all regions and print those in-use (PRENR has an
+ * enable bit for each MPU region, 1 for in-use or 0 for unused):
+ */
+ prenr_el2_value = read_prenr_el2();
+ for (region_to_use = 0; region_to_use < N_MPU_REGIONS;
+ region_to_use++) {
+ if (((prenr_el2_value >> region_to_use) & 1U) == 0U) {
+ continue;
+ }
+ region_base = read_prbar_el2() & PRBAR_PRLAR_ADDR_MASK;
+ region_size = read_prlar_el2() & PRBAR_PRLAR_ADDR_MASK;
+ printf("Address: 0x%llx, size: 0x%llx ",
+ (long long) region_base,
+ (long long) region_size);
+ }
+}
+
+void xlat_tables_print(__unused xlat_ctx_t *ctx)
+{
+ xlat_tables_print_internal(ctx);
+}
+
+#endif /* LOG_LEVEL >= LOG_LEVEL_VERBOSE */
diff --git a/lib/xlat_tables/aarch32/nonlpae_tables.c b/lib/xlat_tables/aarch32/nonlpae_tables.c
new file mode 100644
index 0000000..7cd509d
--- /dev/null
+++ b/lib/xlat_tables/aarch32/nonlpae_tables.c
@@ -0,0 +1,566 @@
+/*
+ * Copyright (c) 2016-2017, Linaro Limited. All rights reserved.
+ * Copyright (c) 2014-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2014, STMicroelectronics International N.V.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/cassert.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+#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 (1U << 1)
+
+/* Not Outer Sharable */
+#define MMU32B_TTB_NOS (1U << 5)
+
+/* Normal memory, Inner Non-cacheable */
+#define MMU32B_TTB_IRGN_NC 0U
+
+/* Normal memory, Inner Write-Back Write-Allocate Cacheable */
+#define MMU32B_TTB_IRGN_WBWA (1U << 6)
+
+/* Normal memory, Inner Write-Through Cacheable */
+#define MMU32B_TTB_IRGN_WT 1U
+
+/* Normal memory, Inner Write-Back no Write-Allocate Cacheable */
+#define MMU32B_TTB_IRGN_WB (1U | (1U << 6))
+
+/* Normal memory, Outer Write-Back Write-Allocate Cacheable */
+#define MMU32B_TTB_RNG_WBWA (1U << 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 (0U << 19)
+#define SECTION_NOTSECURE (1U << 19)
+#define SECTION_SHARED (1U << 16)
+#define SECTION_NOTGLOBAL (1U << 17)
+#define SECTION_ACCESS_FLAG (1U << 10)
+#define SECTION_UNPRIV (1U << 11)
+#define SECTION_RO (1U << 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 (1U << 4)
+#define SECTION_PXN (1U << 0)
+#define SECTION_SECTION (2U << 0)
+
+#define SECTION_PT_NOTSECURE (1U << 3)
+#define SECTION_PT_PT (1U << 0)
+
+#define SMALL_PAGE_SMALL_PAGE (1U << 1)
+#define SMALL_PAGE_SHARED (1U << 10)
+#define SMALL_PAGE_NOTGLOBAL (1U << 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 (1U << 4)
+#define SMALL_PAGE_UNPRIV (1U << 5)
+#define SMALL_PAGE_RO (1U << 9)
+#define SMALL_PAGE_XN (1U << 0)
+
+/* The TEX, C and B bits concatenated */
+#define MMU32B_ATTR_DEVICE_INDEX 0U
+#define MMU32B_ATTR_IWBWA_OWBWA_INDEX 1U
+
+#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 (1U << 16)
+#define MMU32B_PRRR_DS1 (1U << 17)
+#define MMU32B_PRRR_NS0 (1U << 18)
+#define MMU32B_PRRR_NS1 (1U << 19)
+
+#define DACR_DOMAIN(num, perm) ((perm) << ((num) * 2))
+#define DACR_DOMAIN_PERM_NO_ACCESS 0U
+#define DACR_DOMAIN_PERM_CLIENT 1U
+#define DACR_DOMAIN_PERM_MANAGER 3U
+
+#define NUM_1MB_IN_4GB (1UL << 12)
+#define NUM_4K_IN_1MB (1UL << 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 (1U << 14)
+#define MMU32B_L2_TABLE_ALIGN (1U << 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 uint32_t mmap_desc(unsigned attr, unsigned int addr_pa,
+ unsigned int level)
+{
+ uint32_t desc;
+
+ switch (level) {
+ case 1U:
+ assert((addr_pa & (MMU32B_L1_TABLE_ALIGN - 1)) == 0U);
+
+ desc = SECTION_SECTION | SECTION_SHARED;
+
+ desc |= (attr & MT_NS) != 0U ? SECTION_NOTSECURE : 0U;
+
+ desc |= SECTION_ACCESS_FLAG;
+ desc |= (attr & MT_RW) != 0U ? 0U : SECTION_RO;
+
+ desc |= (attr & MT_MEMORY) != 0U ?
+ SECTION_NORMAL_CACHED : SECTION_DEVICE;
+
+ if (((attr & MT_RW) != 0U) || ((attr & MT_MEMORY) == 0U)) {
+ desc |= SECTION_XN;
+ }
+ break;
+ case 2U:
+ assert((addr_pa & (MMU32B_L2_TABLE_ALIGN - 1)) == 0U);
+
+ desc = SMALL_PAGE_SMALL_PAGE | SMALL_PAGE_SHARED;
+
+ desc |= SMALL_PAGE_ACCESS_FLAG;
+ desc |= (attr & MT_RW) != 0U ? 0U : SMALL_PAGE_RO;
+
+ desc |= (attr & MT_MEMORY) != 0U ?
+ SMALL_PAGE_NORMAL_CACHED : SMALL_PAGE_DEVICE;
+
+ if (((attr & MT_RW) != 0U) || ((attr & MT_MEMORY) == 0U)) {
+ desc |= SMALL_PAGE_XN;
+ }
+ break;
+ default:
+ panic();
+ }
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ /* dump only the non-lpae level 2 tables */
+ if (level == 2U) {
+ 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;
+ }
+}
+
+static mmap_region_t *init_xlation_table_inner(mmap_region_t *mm,
+ unsigned int base_va,
+ uint32_t *table,
+ unsigned int level)
+{
+ unsigned int level_size_shift = (level == 1U) ?
+ ONE_MB_SHIFT : FOUR_KB_SHIFT;
+ unsigned int level_size = 1U << level_size_shift;
+ unsigned int level_index_mask = (level == 1U) ?
+ (NUM_1MB_IN_4GB - 1) << ONE_MB_SHIFT :
+ (NUM_4K_IN_1MB - 1) << FOUR_KB_SHIFT;
+
+ assert((level == 1U) || (level == 2U));
+
+ VERBOSE("init xlat table at %p (level%1u)\n", (void *)table, level);
+
+ do {
+ uint32_t 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 == 2U) {
+ 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) {
+ uintptr_t 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) == 0U)
+ == ((mm->attr & MT_NS) == 0U));
+
+ xlat_table = (*table) &
+ ~(MMU32B_L1_TABLE_ALIGN - 1);
+ desc = *table;
+ } else {
+ xlat_table = (uintptr_t)mmu_l2_base +
+ next_xlat * MMU32B_L2_TABLE_SIZE;
+ next_xlat++;
+ assert(next_xlat <= MAX_XLAT_TABLES);
+ (void)memset((char *)xlat_table, 0,
+ MMU32B_L2_TABLE_SIZE);
+
+ desc = xlat_table | SECTION_PT_PT;
+ desc |= (mm->attr & MT_NS) != 0U ?
+ SECTION_PT_NOTSECURE : 0;
+ }
+ /* Recurse to fill in new table */
+ mm = init_xlation_table_inner(mm, base_va,
+ (uint32_t *)xlat_table,
+ level + 1);
+ }
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ /* dump only non-lpae level 2 tables content */
+ if (level == 2U) {
+ printf("\n");
+ }
+#endif
+ *table++ = desc;
+ base_va += level_size;
+ } while ((mm->size != 0U) && ((base_va & level_index_mask) != 0U));
+
+ return mm;
+}
+
+void init_xlat_tables(void)
+{
+ print_mmap();
+
+ assert(((unsigned int)mmu_l1_base & (MMU32B_L1_TABLE_ALIGN - 1)) == 0U);
+ assert(((unsigned int)mmu_l2_base & (MMU32B_L2_TABLE_ALIGN - 1)) == 0U);
+
+ (void)memset(mmu_l1_base, 0, MMU32B_L1_TABLE_SIZE);
+
+ init_xlation_table_inner(mmap, 0, (uint32_t *)mmu_l1_base, 1);
+
+ VERBOSE("init xlat - max_va=%p, max_pa=%llx\n",
+ (void *)xlat_max_va, xlat_max_pa);
+ 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) == 0U);
+
+ /* 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(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
+ */
+ dsb();
+ isb();
+
+ sctlr = read_sctlr();
+ sctlr |= SCTLR_M_BIT;
+#ifdef ARMV7_SUPPORTS_VIRTUALIZATION
+ sctlr |= SCTLR_WXN_BIT;
+#endif
+
+ 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();
+}
diff --git a/lib/xlat_tables/aarch32/xlat_tables.c b/lib/xlat_tables/aarch32/xlat_tables.c
new file mode 100644
index 0000000..4b01b9b
--- /dev/null
+++ b/lib/xlat_tables/aarch32/xlat_tables.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_arch.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+#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);
+}
diff --git a/lib/xlat_tables/aarch64/xlat_tables.c b/lib/xlat_tables/aarch64/xlat_tables.c
new file mode 100644
index 0000000..dc167e3
--- /dev/null
+++ b/lib/xlat_tables/aarch64/xlat_tables.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_features.h>
+#include <common/bl_common.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <lib/xlat_tables/xlat_tables_arch.h>
+#include <plat/common/common_def.h>
+
+#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)
diff --git a/lib/xlat_tables/xlat_tables_common.c b/lib/xlat_tables/xlat_tables_common.c
new file mode 100644
index 0000000..23fe3f0
--- /dev/null
+++ b/lib/xlat_tables/xlat_tables_common.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/cassert.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/common_def.h>
+
+#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;
+}
diff --git a/lib/xlat_tables/xlat_tables_private.h b/lib/xlat_tables/xlat_tables_private.h
new file mode 100644
index 0000000..82bc70c
--- /dev/null
+++ b/lib/xlat_tables/xlat_tables_private.h
@@ -0,0 +1,41 @@
+/*
+ * 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 <platform_def.h>
+
+#include <lib/cassert.h>
+#include <lib/xlat_tables/xlat_tables_arch.h>
+
+#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 */
diff --git a/lib/xlat_tables_v2/aarch32/enable_mmu.S b/lib/xlat_tables_v2/aarch32/enable_mmu.S
new file mode 100644
index 0000000..f2fff36
--- /dev/null
+++ b/lib/xlat_tables_v2/aarch32/enable_mmu.S
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+ .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
diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
new file mode 100644
index 0000000..a1a44af
--- /dev/null
+++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <lib/cassert.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#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;
+}
+
+/*
+ * Determine the physical address space encoded in the 'attr' parameter.
+ *
+ * The physical address will fall into one of two spaces; secure or
+ * nonsecure.
+ */
+uint32_t xlat_arch_get_pas(uint32_t attr)
+{
+ uint32_t pas = MT_PAS(attr);
+
+ if (pas == MT_NS) {
+ return LOWER_ATTRS(NS);
+ } else { /* MT_SECURE */
+ return 0U;
+ }
+}
+
+#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(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;
+}
diff --git a/lib/xlat_tables_v2/aarch64/enable_mmu.S b/lib/xlat_tables_v2/aarch64/enable_mmu.S
new file mode 100644
index 0000000..9f075e4
--- /dev/null
+++ b/lib/xlat_tables_v2/aarch64/enable_mmu.S
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+ .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<x>(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
diff --git a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
new file mode 100644
index 0000000..719110a
--- /dev/null
+++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <arch.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <lib/cassert.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#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;
+ }
+}
+
+/*
+ * Determine the physical address space encoded in the 'attr' parameter.
+ *
+ * The physical address will fall into one of four spaces; secure,
+ * nonsecure, root, or realm if RME is enabled, or one of two spaces;
+ * secure and nonsecure otherwise.
+ */
+uint32_t xlat_arch_get_pas(uint32_t attr)
+{
+ uint32_t pas = MT_PAS(attr);
+
+ switch (pas) {
+#if ENABLE_RME
+ /* TTD.NSE = 1 and TTD.NS = 1 for Realm PAS */
+ case MT_REALM:
+ return LOWER_ATTRS(EL3_S1_NSE | NS);
+ /* TTD.NSE = 1 and TTD.NS = 0 for Root PAS */
+ case MT_ROOT:
+ return LOWER_ATTRS(EL3_S1_NSE);
+#endif
+ case MT_NS:
+ return LOWER_ATTRS(NS);
+ default: /* MT_SECURE */
+ return 0U;
+ }
+}
+
+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 = get_current_el_maybe_constant();
+
+ 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;
+}
diff --git a/lib/xlat_tables_v2/ro_xlat_tables.mk b/lib/xlat_tables_v2/ro_xlat_tables.mk
new file mode 100644
index 0000000..fb8a426
--- /dev/null
+++ b/lib/xlat_tables_v2/ro_xlat_tables.mk
@@ -0,0 +1,41 @@
+#
+# Copyright (c) 2020-2022, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${USE_DEBUGFS}, 1)
+ $(error "Debugfs requires functionality from the dynamic translation \
+ library and is incompatible with ALLOW_RO_XLAT_TABLES.")
+endif
+
+ifeq (${ARCH},aarch32)
+ ifeq (${RESET_TO_SP_MIN},1)
+ $(error "RESET_TO_SP_MIN requires functionality from the dynamic \
+ translation library and is incompatible with \
+ ALLOW_RO_XLAT_TABLES.")
+ endif
+else # if AArch64
+ ifeq (${PLAT},tegra)
+ $(error "Tegra requires functionality from the dynamic translation \
+ library and is incompatible with ALLOW_RO_XLAT_TABLES.")
+ endif
+ ifeq (${RESET_TO_BL31},1)
+ $(error "RESET_TO_BL31 requires functionality from the dynamic \
+ translation library and is incompatible with \
+ ALLOW_RO_XLAT_TABLES.")
+ endif
+ ifeq (${SPD},trusty)
+ $(error "Trusty requires functionality from the dynamic translation \
+ library and is incompatible with ALLOW_RO_XLAT_TABLES.")
+ endif
+ ifeq (${SPM_MM},1)
+ $(error "SPM_MM requires functionality to change memory region \
+ attributes, which is not possible once the translation tables \
+ have been made read-only.")
+ endif
+ ifeq (${SPMC_AT_EL3},1)
+ $(error "EL3 SPMC requires functionality from the dynamic translation \
+ library and is incompatible with ALLOW_RO_XLAT_TABLES.")
+ endif
+endif
diff --git a/lib/xlat_tables_v2/xlat_tables.mk b/lib/xlat_tables_v2/xlat_tables.mk
new file mode 100644
index 0000000..bcc3e68
--- /dev/null
+++ b/lib/xlat_tables_v2/xlat_tables.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2017-2020, 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))
+
+ifeq (${ALLOW_RO_XLAT_TABLES}, 1)
+ include lib/xlat_tables_v2/ro_xlat_tables.mk
+endif
diff --git a/lib/xlat_tables_v2/xlat_tables_context.c b/lib/xlat_tables_v2/xlat_tables_context.c
new file mode 100644
index 0000000..95dae88
--- /dev/null
+++ b/lib/xlat_tables_v2/xlat_tables_context.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#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 PLAT_RO_XLAT_TABLES
+/* Change the memory attributes of the descriptors which resolve the address
+ * range that belongs to the translation tables themselves, which are by default
+ * mapped as part of read-write data in the BL image's memory.
+ *
+ * Since the translation tables map themselves via these level 3 (page)
+ * descriptors, any change applied to them with the MMU on would introduce a
+ * chicken and egg problem because of the break-before-make sequence.
+ * Eventually, it would reach the descriptor that resolves the very table it
+ * belongs to and the invalidation (break step) would cause the subsequent write
+ * (make step) to it to generate an MMU fault. Therefore, the MMU is disabled
+ * before making the change.
+ *
+ * No assumption is made about what data this function needs, therefore all the
+ * caches are flushed in order to ensure coherency. A future optimization would
+ * be to only flush the required data to main memory.
+ */
+int xlat_make_tables_readonly(void)
+{
+ assert(tf_xlat_ctx.initialized == true);
+#ifdef __aarch64__
+ if (tf_xlat_ctx.xlat_regime == EL1_EL0_REGIME) {
+ disable_mmu_el1();
+ } else if (tf_xlat_ctx.xlat_regime == EL3_REGIME) {
+ disable_mmu_el3();
+ } else {
+ assert(tf_xlat_ctx.xlat_regime == EL2_REGIME);
+ return -1;
+ }
+
+ /* Flush all caches. */
+ dcsw_op_all(DCCISW);
+#else /* !__aarch64__ */
+ assert(tf_xlat_ctx.xlat_regime == EL1_EL0_REGIME);
+ /* On AArch32, we flush the caches before disabling the MMU. The reason
+ * for this is that the dcsw_op_all AArch32 function pushes some
+ * registers onto the stack under the assumption that it is writing to
+ * cache, which is not true with the MMU off. This would result in the
+ * stack becoming corrupted and a wrong/junk value for the LR being
+ * restored at the end of the routine.
+ */
+ dcsw_op_all(DC_OP_CISW);
+ disable_mmu_secure();
+#endif
+
+ int rc = xlat_change_mem_attributes_ctx(&tf_xlat_ctx,
+ (uintptr_t)tf_xlat_ctx.tables,
+ tf_xlat_ctx.tables_num * XLAT_TABLE_SIZE,
+ MT_RO_DATA | MT_SECURE);
+
+#ifdef __aarch64__
+ if (tf_xlat_ctx.xlat_regime == EL1_EL0_REGIME) {
+ enable_mmu_el1(0U);
+ } else {
+ assert(tf_xlat_ctx.xlat_regime == EL3_REGIME);
+ enable_mmu_el3(0U);
+ }
+#else /* !__aarch64__ */
+ enable_mmu_svc_mon(0U);
+#endif
+
+ if (rc == 0) {
+ tf_xlat_ctx.readonly_tables = true;
+ }
+
+ return rc;
+}
+#endif /* PLAT_RO_XLAT_TABLES */
+
+/*
+ * 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);
+}
+
+void enable_mmu(unsigned int flags)
+{
+ switch (get_current_el_maybe_constant()) {
+ case 1:
+ enable_mmu_el1(flags);
+ break;
+ case 2:
+ enable_mmu_el2(flags);
+ break;
+ case 3:
+ enable_mmu_el3(flags);
+ break;
+ default:
+ panic();
+ }
+}
+
+#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__ */
diff --git a/lib/xlat_tables_v2/xlat_tables_core.c b/lib/xlat_tables_v2/xlat_tables_core.c
new file mode 100644
index 0000000..de57184
--- /dev/null
+++ b/lib/xlat_tables_v2/xlat_tables_core.c
@@ -0,0 +1,1244 @@
+/*
+ * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#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;
+ uint32_t shareability_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);
+
+ /* Determine the physical address space this region belongs to. */
+ desc |= xlat_arch_get_pas(attr);
+
+ /*
+ * Deduce other fields of the descriptor based on the MT_RW memory
+ * region attributes.
+ */
+ 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);
+ }
+
+ shareability_type = MT_SHAREABILITY(attr);
+ if (mem_type == MT_MEMORY) {
+ desc |= LOWER_ATTRS(ATTR_IWBWA_OWBWA_NTR_INDEX);
+ if (shareability_type == MT_SHAREABILITY_NSH) {
+ desc |= LOWER_ATTRS(NSH);
+ } else if (shareability_type == MT_SHAREABILITY_OSH) {
+ desc |= LOWER_ATTRS(OSH);
+ } else {
+ desc |= LOWER_ATTRS(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 | (uintptr_t)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 (end_va > ctx->va_max_address)
+ return -ERANGE;
+
+ if (end_pa > 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);
+}
diff --git a/lib/xlat_tables_v2/xlat_tables_private.h b/lib/xlat_tables_v2/xlat_tables_private.h
new file mode 100644
index 0000000..42c9a43
--- /dev/null
+++ b/lib/xlat_tables_v2/xlat_tables_private.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef XLAT_TABLES_PRIVATE_H
+#define XLAT_TABLES_PRIVATE_H
+
+#include <stdbool.h>
+
+#include <platform_def.h>
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#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];
+
+/* Determine the physical address space encoded in the 'attr' parameter. */
+uint32_t xlat_arch_get_pas(uint32_t attr);
+
+/*
+ * 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 minimum virtual address space size supported by the architecture
+ */
+uintptr_t xlat_get_min_virt_addr_space_size(void);
+
+#endif /* XLAT_TABLES_PRIVATE_H */
diff --git a/lib/xlat_tables_v2/xlat_tables_utils.c b/lib/xlat_tables_v2/xlat_tables_utils.c
new file mode 100644
index 0000000..38a375e
--- /dev/null
+++ b/lib/xlat_tables_v2/xlat_tables_utils.c
@@ -0,0 +1,592 @@
+/*
+ * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#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");
+ }
+
+#if ENABLE_RME
+ switch (desc & LOWER_ATTRS(EL3_S1_NSE | NS)) {
+ case 0ULL:
+ printf("-S");
+ break;
+ case LOWER_ATTRS(NS):
+ printf("-NS");
+ break;
+ case LOWER_ATTRS(EL3_S1_NSE):
+ printf("-RT");
+ break;
+ default: /* LOWER_ATTRS(EL3_S1_NSE | NS) */
+ printf("-RL");
+ }
+#else
+ printf(((LOWER_ATTRS(NS) & desc) != 0ULL) ? "-NS" : "-S");
+#endif
+
+#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%" PRIx64 " 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 (unsigned int 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%lx, should be 0x%lx.\n",
+ 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;
+}
diff --git a/lib/zlib/adler32.c b/lib/zlib/adler32.c
new file mode 100644
index 0000000..d0be438
--- /dev/null
+++ b/lib/zlib/adler32.c
@@ -0,0 +1,186 @@
+/* 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);
+}
diff --git a/lib/zlib/crc32.c b/lib/zlib/crc32.c
new file mode 100644
index 0000000..f8357b0
--- /dev/null
+++ b/lib/zlib/crc32.c
@@ -0,0 +1,1125 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2022 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * This interleaved implementation of a CRC makes use of pipelined multiple
+ * arithmetic-logic units, commonly found in modern CPU cores. It is due to
+ * Kadatch and Jenkins (2010). See doc/crc-doc.1.0.pdf in this distribution.
+ */
+
+/* @(#) $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().
+
+ MAKECRCH can be #defined to write out crc32.h. A main() routine is also
+ produced, so that this one source file can be compiled to an executable.
+ */
+
+#ifdef MAKECRCH
+# include <stdio.h>
+# ifndef DYNAMIC_CRC_TABLE
+# define DYNAMIC_CRC_TABLE
+# endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h" /* for Z_U4, Z_U8, z_crc_t, and FAR definitions */
+
+ /*
+ A CRC of a message is computed on N braids of words in the message, where
+ each word consists of W bytes (4 or 8). If N is 3, for example, then three
+ running sparse CRCs are calculated respectively on each braid, at these
+ indices in the array of words: 0, 3, 6, ..., 1, 4, 7, ..., and 2, 5, 8, ...
+ This is done starting at a word boundary, and continues until as many blocks
+ of N * W bytes as are available have been processed. The results are combined
+ into a single CRC at the end. For this code, N must be in the range 1..6 and
+ W must be 4 or 8. The upper limit on N can be increased if desired by adding
+ more #if blocks, extending the patterns apparent in the code. In addition,
+ crc32.h would need to be regenerated, if the maximum N value is increased.
+
+ N and W are chosen empirically by benchmarking the execution time on a given
+ processor. The choices for N and W below were based on testing on Intel Kaby
+ Lake i7, AMD Ryzen 7, ARM Cortex-A57, Sparc64-VII, PowerPC POWER9, and MIPS64
+ Octeon II processors. The Intel, AMD, and ARM processors were all fastest
+ with N=5, W=8. The Sparc, PowerPC, and MIPS64 were all fastest at N=5, W=4.
+ They were all tested with either gcc or clang, all using the -O3 optimization
+ level. Your mileage may vary.
+ */
+
+/* Define N */
+#ifdef Z_TESTN
+# define N Z_TESTN
+#else
+# define N 5
+#endif
+#if N < 1 || N > 6
+# error N must be in 1..6
+#endif
+
+/*
+ z_crc_t must be at least 32 bits. z_word_t must be at least as long as
+ z_crc_t. It is assumed here that z_word_t is either 32 bits or 64 bits, and
+ that bytes are eight bits.
+ */
+
+/*
+ Define W and the associated z_word_t type. If W is not defined, then a
+ braided calculation is not used, and the associated tables and code are not
+ compiled.
+ */
+#ifdef Z_TESTW
+# if Z_TESTW-1 != -1
+# define W Z_TESTW
+# endif
+#else
+# ifdef MAKECRCH
+# define W 8 /* required for MAKECRCH */
+# else
+# if defined(__x86_64__) || defined(__aarch64__)
+# define W 8
+# else
+# define W 4
+# endif
+# endif
+#endif
+#ifdef W
+# if W == 8 && defined(Z_U8)
+ typedef Z_U8 z_word_t;
+# elif defined(Z_U4)
+# undef W
+# define W 4
+ typedef Z_U4 z_word_t;
+# else
+# undef W
+# endif
+#endif
+
+/* If available, use the ARM processor CRC32 instruction. */
+#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8
+# define ARMCRC32
+#endif
+
+/* Local functions. */
+local z_crc_t multmodp OF((z_crc_t a, z_crc_t b));
+local z_crc_t x2nmodp OF((z_off64_t n, unsigned k));
+
+#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE))
+ local z_word_t byte_swap OF((z_word_t word));
+#endif
+
+#if defined(W) && !defined(ARMCRC32)
+ local z_crc_t crc_word OF((z_word_t data));
+ local z_word_t crc_word_big OF((z_word_t data));
+#endif
+
+#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE))
+/*
+ Swap the bytes in a z_word_t to convert between little and big endian. Any
+ self-respecting compiler will optimize this to a single machine byte-swap
+ instruction, if one is available. This assumes that word_t is either 32 bits
+ or 64 bits.
+ */
+local z_word_t byte_swap(word)
+ z_word_t word;
+{
+# if W == 8
+ return
+ (word & 0xff00000000000000) >> 56 |
+ (word & 0xff000000000000) >> 40 |
+ (word & 0xff0000000000) >> 24 |
+ (word & 0xff00000000) >> 8 |
+ (word & 0xff000000) << 8 |
+ (word & 0xff0000) << 24 |
+ (word & 0xff00) << 40 |
+ (word & 0xff) << 56;
+# else /* W == 4 */
+ return
+ (word & 0xff000000) >> 24 |
+ (word & 0xff0000) >> 8 |
+ (word & 0xff00) << 8 |
+ (word & 0xff) << 24;
+# endif
+}
+#endif
+
+/* CRC polynomial. */
+#define POLY 0xedb88320 /* p(x) reflected, with x^32 implied */
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local z_crc_t FAR crc_table[256];
+local z_crc_t FAR x2n_table[32];
+local void make_crc_table OF((void));
+#ifdef W
+ local z_word_t FAR crc_big_table[256];
+ local z_crc_t FAR crc_braid_table[W][256];
+ local z_word_t FAR crc_braid_big_table[W][256];
+ local void braid OF((z_crc_t [][256], z_word_t [][256], int, int));
+#endif
+#ifdef MAKECRCH
+ local void write_table OF((FILE *, const z_crc_t FAR *, int));
+ local void write_table32hi OF((FILE *, const z_word_t FAR *, int));
+ local void write_table64 OF((FILE *, const z_word_t FAR *, int));
+#endif /* MAKECRCH */
+
+/*
+ Define a once() function depending on the availability of atomics. If this is
+ compiled with DYNAMIC_CRC_TABLE defined, and if CRCs will be computed in
+ multiple threads, and if atomics are not available, then get_crc_table() must
+ be called to initialize the tables and must return before any threads are
+ allowed to compute or combine CRCs.
+ */
+
+/* Definition of once functionality. */
+typedef struct once_s once_t;
+local void once OF((once_t *, void (*)(void)));
+
+/* Check for the availability of atomics. */
+#if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \
+ !defined(__STDC_NO_ATOMICS__)
+
+#include <stdatomic.h>
+
+/* Structure for once(), which must be initialized with ONCE_INIT. */
+struct once_s {
+ atomic_flag begun;
+ atomic_int done;
+};
+#define ONCE_INIT {ATOMIC_FLAG_INIT, 0}
+
+/*
+ Run the provided init() function exactly once, even if multiple threads
+ invoke once() at the same time. The state must be a once_t initialized with
+ ONCE_INIT.
+ */
+local void once(state, init)
+ once_t *state;
+ void (*init)(void);
+{
+ if (!atomic_load(&state->done)) {
+ if (atomic_flag_test_and_set(&state->begun))
+ while (!atomic_load(&state->done))
+ ;
+ else {
+ init();
+ atomic_store(&state->done, 1);
+ }
+ }
+}
+
+#else /* no atomics */
+
+/* Structure for once(), which must be initialized with ONCE_INIT. */
+struct once_s {
+ volatile int begun;
+ volatile int done;
+};
+#define ONCE_INIT {0, 0}
+
+/* Test and set. Alas, not atomic, but tries to minimize the period of
+ vulnerability. */
+local int test_and_set OF((int volatile *));
+local int test_and_set(flag)
+ int volatile *flag;
+{
+ int was;
+
+ was = *flag;
+ *flag = 1;
+ return was;
+}
+
+/* Run the provided init() function once. This is not thread-safe. */
+local void once(state, init)
+ once_t *state;
+ void (*init)(void);
+{
+ if (!state->done) {
+ if (test_and_set(&state->begun))
+ while (!state->done)
+ ;
+ else {
+ init();
+ state->done = 1;
+ }
+ }
+}
+
+#endif
+
+/* State for once(). */
+local once_t made = ONCE_INIT;
+
+/*
+ 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^2+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 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.
+ */
+
+local void make_crc_table()
+{
+ unsigned i, j, n;
+ z_crc_t p;
+
+ /* initialize the CRC of bytes tables */
+ for (i = 0; i < 256; i++) {
+ p = i;
+ for (j = 0; j < 8; j++)
+ p = p & 1 ? (p >> 1) ^ POLY : p >> 1;
+ crc_table[i] = p;
+#ifdef W
+ crc_big_table[i] = byte_swap(p);
+#endif
+ }
+
+ /* initialize the x^2^n mod p(x) table */
+ p = (z_crc_t)1 << 30; /* x^1 */
+ x2n_table[0] = p;
+ for (n = 1; n < 32; n++)
+ x2n_table[n] = p = multmodp(p, p);
+
+#ifdef W
+ /* initialize the braiding tables -- needs x2n_table[] */
+ braid(crc_braid_table, crc_braid_big_table, N, W);
+#endif
+
+#ifdef MAKECRCH
+ {
+ /*
+ The crc32.h header file contains tables for both 32-bit and 64-bit
+ z_word_t's, and so requires a 64-bit type be available. In that case,
+ z_word_t must be defined to be 64-bits. This code then also generates
+ and writes out the tables for the case that z_word_t is 32 bits.
+ */
+#if !defined(W) || W != 8
+# error Need a 64-bit integer type in order to generate crc32.h.
+#endif
+ FILE *out;
+ int k, n;
+ z_crc_t ltl[8][256];
+ z_word_t big[8][256];
+
+ out = fopen("crc32.h", "w");
+ if (out == NULL) return;
+
+ /* write out little-endian CRC table to crc32.h */
+ fprintf(out,
+ "/* crc32.h -- tables for rapid CRC calculation\n"
+ " * Generated automatically by crc32.c\n */\n"
+ "\n"
+ "local const z_crc_t FAR crc_table[] = {\n"
+ " ");
+ write_table(out, crc_table, 256);
+ fprintf(out,
+ "};\n");
+
+ /* write out big-endian CRC table for 64-bit z_word_t to crc32.h */
+ fprintf(out,
+ "\n"
+ "#ifdef W\n"
+ "\n"
+ "#if W == 8\n"
+ "\n"
+ "local const z_word_t FAR crc_big_table[] = {\n"
+ " ");
+ write_table64(out, crc_big_table, 256);
+ fprintf(out,
+ "};\n");
+
+ /* write out big-endian CRC table for 32-bit z_word_t to crc32.h */
+ fprintf(out,
+ "\n"
+ "#else /* W == 4 */\n"
+ "\n"
+ "local const z_word_t FAR crc_big_table[] = {\n"
+ " ");
+ write_table32hi(out, crc_big_table, 256);
+ fprintf(out,
+ "};\n"
+ "\n"
+ "#endif\n");
+
+ /* write out braid tables for each value of N */
+ for (n = 1; n <= 6; n++) {
+ fprintf(out,
+ "\n"
+ "#if N == %d\n", n);
+
+ /* compute braid tables for this N and 64-bit word_t */
+ braid(ltl, big, n, 8);
+
+ /* write out braid tables for 64-bit z_word_t to crc32.h */
+ fprintf(out,
+ "\n"
+ "#if W == 8\n"
+ "\n"
+ "local const z_crc_t FAR crc_braid_table[][256] = {\n");
+ for (k = 0; k < 8; k++) {
+ fprintf(out, " {");
+ write_table(out, ltl[k], 256);
+ fprintf(out, "}%s", k < 7 ? ",\n" : "");
+ }
+ fprintf(out,
+ "};\n"
+ "\n"
+ "local const z_word_t FAR crc_braid_big_table[][256] = {\n");
+ for (k = 0; k < 8; k++) {
+ fprintf(out, " {");
+ write_table64(out, big[k], 256);
+ fprintf(out, "}%s", k < 7 ? ",\n" : "");
+ }
+ fprintf(out,
+ "};\n");
+
+ /* compute braid tables for this N and 32-bit word_t */
+ braid(ltl, big, n, 4);
+
+ /* write out braid tables for 32-bit z_word_t to crc32.h */
+ fprintf(out,
+ "\n"
+ "#else /* W == 4 */\n"
+ "\n"
+ "local const z_crc_t FAR crc_braid_table[][256] = {\n");
+ for (k = 0; k < 4; k++) {
+ fprintf(out, " {");
+ write_table(out, ltl[k], 256);
+ fprintf(out, "}%s", k < 3 ? ",\n" : "");
+ }
+ fprintf(out,
+ "};\n"
+ "\n"
+ "local const z_word_t FAR crc_braid_big_table[][256] = {\n");
+ for (k = 0; k < 4; k++) {
+ fprintf(out, " {");
+ write_table32hi(out, big[k], 256);
+ fprintf(out, "}%s", k < 3 ? ",\n" : "");
+ }
+ fprintf(out,
+ "};\n"
+ "\n"
+ "#endif\n"
+ "\n"
+ "#endif\n");
+ }
+ fprintf(out,
+ "\n"
+ "#endif\n");
+
+ /* write out zeros operator table to crc32.h */
+ fprintf(out,
+ "\n"
+ "local const z_crc_t FAR x2n_table[] = {\n"
+ " ");
+ write_table(out, x2n_table, 32);
+ fprintf(out,
+ "};\n");
+ fclose(out);
+ }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+
+/*
+ Write the 32-bit values in table[0..k-1] to out, five per line in
+ hexadecimal separated by commas.
+ */
+local void write_table(out, table, k)
+ FILE *out;
+ const z_crc_t FAR *table;
+ int k;
+{
+ int n;
+
+ for (n = 0; n < k; n++)
+ fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ",
+ (unsigned long)(table[n]),
+ n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", "));
+}
+
+/*
+ Write the high 32-bits of each value in table[0..k-1] to out, five per line
+ in hexadecimal separated by commas.
+ */
+local void write_table32hi(out, table, k)
+FILE *out;
+const z_word_t FAR *table;
+int k;
+{
+ int n;
+
+ for (n = 0; n < k; n++)
+ fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ",
+ (unsigned long)(table[n] >> 32),
+ n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", "));
+}
+
+/*
+ Write the 64-bit values in table[0..k-1] to out, three per line in
+ hexadecimal separated by commas. This assumes that if there is a 64-bit
+ type, then there is also a long long integer type, and it is at least 64
+ bits. If not, then the type cast and format string can be adjusted
+ accordingly.
+ */
+local void write_table64(out, table, k)
+ FILE *out;
+ const z_word_t FAR *table;
+ int k;
+{
+ int n;
+
+ for (n = 0; n < k; n++)
+ fprintf(out, "%s0x%016llx%s", n == 0 || n % 3 ? "" : " ",
+ (unsigned long long)(table[n]),
+ n == k - 1 ? "" : (n % 3 == 2 ? ",\n" : ", "));
+}
+
+/* Actually do the deed. */
+int main()
+{
+ make_crc_table();
+ return 0;
+}
+
+#endif /* MAKECRCH */
+
+#ifdef W
+/*
+ Generate the little and big-endian braid tables for the given n and z_word_t
+ size w. Each array must have room for w blocks of 256 elements.
+ */
+local void braid(ltl, big, n, w)
+ z_crc_t ltl[][256];
+ z_word_t big[][256];
+ int n;
+ int w;
+{
+ int k;
+ z_crc_t i, p, q;
+ for (k = 0; k < w; k++) {
+ p = x2nmodp((n * w + 3 - k) << 3, 0);
+ ltl[k][0] = 0;
+ big[w - 1 - k][0] = 0;
+ for (i = 1; i < 256; i++) {
+ ltl[k][i] = q = multmodp(i << 24, p);
+ big[w - 1 - k][i] = byte_swap(q);
+ }
+ }
+}
+#endif
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables for byte-wise and braided CRC-32 calculations, and a table of powers
+ * of x for combining CRC-32s, all made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* ========================================================================
+ * Routines used for CRC calculation. Some are also required for the table
+ * generation above.
+ */
+
+/*
+ Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial,
+ reflected. For speed, this requires that a not be zero.
+ */
+local z_crc_t multmodp(a, b)
+ z_crc_t a;
+ z_crc_t b;
+{
+ z_crc_t m, p;
+
+ m = (z_crc_t)1 << 31;
+ p = 0;
+ for (;;) {
+ if (a & m) {
+ p ^= b;
+ if ((a & (m - 1)) == 0)
+ break;
+ }
+ m >>= 1;
+ b = b & 1 ? (b >> 1) ^ POLY : b >> 1;
+ }
+ return p;
+}
+
+/*
+ Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been
+ initialized.
+ */
+local z_crc_t x2nmodp(n, k)
+ z_off64_t n;
+ unsigned k;
+{
+ z_crc_t p;
+
+ p = (z_crc_t)1 << 31; /* x^0 == 1 */
+ while (n) {
+ if (n & 1)
+ p = multmodp(x2n_table[k & 31], p);
+ n >>= 1;
+ k++;
+ }
+ return p;
+}
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32(), and to force the
+ * generation of the CRC tables in a threaded application.
+ */
+const z_crc_t FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+ once(&made, make_crc_table);
+#endif /* DYNAMIC_CRC_TABLE */
+ return (const z_crc_t FAR *)crc_table;
+}
+
+/* =========================================================================
+ * Use ARM machine instructions if available. This will compute the CRC about
+ * ten times faster than the braided calculation. This code does not check for
+ * the presence of the CRC instruction at run time. __ARM_FEATURE_CRC32 will
+ * only be defined if the compilation specifies an ARM processor architecture
+ * that has the instructions. For example, compiling with -march=armv8.1-a or
+ * -march=armv8-a+crc, or -march=native if the compile machine has the crc32
+ * instructions.
+ */
+#ifdef ARMCRC32
+
+/*
+ Constants empirically determined to maximize speed. These values are from
+ measurements on a Cortex-A57. Your mileage may vary.
+ */
+#define Z_BATCH 3990 /* number of words in a batch */
+#define Z_BATCH_ZEROS 0xa10d3d0c /* computed from Z_BATCH = 3990 */
+#define Z_BATCH_MIN 800 /* fewest words in a final batch */
+
+unsigned long ZEXPORT crc32_z(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ z_size_t len;
+{
+ z_crc_t val;
+ z_word_t crc1, crc2;
+ const z_word_t *word;
+ z_word_t val0, val1, val2;
+ z_size_t last, last2, i;
+ z_size_t num;
+
+ /* Return initial CRC, if requested. */
+ if (buf == Z_NULL) return 0;
+
+#ifdef DYNAMIC_CRC_TABLE
+ once(&made, make_crc_table);
+#endif /* DYNAMIC_CRC_TABLE */
+
+ /* Pre-condition the CRC */
+ crc = (~crc) & 0xffffffff;
+
+ /* Compute the CRC up to a word boundary. */
+ while (len && ((z_size_t)buf & 7) != 0) {
+ len--;
+ val = *buf++;
+ __asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val));
+ }
+
+ /* Prepare to compute the CRC on full 64-bit words word[0..num-1]. */
+ word = (z_word_t const *)buf;
+ num = len >> 3;
+ len &= 7;
+
+ /* Do three interleaved CRCs to realize the throughput of one crc32x
+ instruction per cycle. Each CRC is calculated on Z_BATCH words. The
+ three CRCs are combined into a single CRC after each set of batches. */
+ while (num >= 3 * Z_BATCH) {
+ crc1 = 0;
+ crc2 = 0;
+ for (i = 0; i < Z_BATCH; i++) {
+ val0 = word[i];
+ val1 = word[i + Z_BATCH];
+ val2 = word[i + 2 * Z_BATCH];
+ __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0));
+ __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc1) : "r"(val1));
+ __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc2) : "r"(val2));
+ }
+ word += 3 * Z_BATCH;
+ num -= 3 * Z_BATCH;
+ crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc1;
+ crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc2;
+ }
+
+ /* Do one last smaller batch with the remaining words, if there are enough
+ to pay for the combination of CRCs. */
+ last = num / 3;
+ if (last >= Z_BATCH_MIN) {
+ last2 = last << 1;
+ crc1 = 0;
+ crc2 = 0;
+ for (i = 0; i < last; i++) {
+ val0 = word[i];
+ val1 = word[i + last];
+ val2 = word[i + last2];
+ __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0));
+ __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc1) : "r"(val1));
+ __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc2) : "r"(val2));
+ }
+ word += 3 * last;
+ num -= 3 * last;
+ val = x2nmodp(last, 6);
+ crc = multmodp(val, crc) ^ crc1;
+ crc = multmodp(val, crc) ^ crc2;
+ }
+
+ /* Compute the CRC on any remaining words. */
+ for (i = 0; i < num; i++) {
+ val0 = word[i];
+ __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0));
+ }
+ word += num;
+
+ /* Complete the CRC on any remaining bytes. */
+ buf = (const unsigned char FAR *)word;
+ while (len) {
+ len--;
+ val = *buf++;
+ __asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val));
+ }
+
+ /* Return the CRC, post-conditioned. */
+ return crc ^ 0xffffffff;
+}
+
+#else
+
+#ifdef W
+
+/*
+ Return the CRC of the W bytes in the word_t data, taking the
+ least-significant byte of the word as the first byte of data, without any pre
+ or post conditioning. This is used to combine the CRCs of each braid.
+ */
+local z_crc_t crc_word(data)
+ z_word_t data;
+{
+ int k;
+ for (k = 0; k < W; k++)
+ data = (data >> 8) ^ crc_table[data & 0xff];
+ return (z_crc_t)data;
+}
+
+local z_word_t crc_word_big(data)
+ z_word_t data;
+{
+ int k;
+ for (k = 0; k < W; k++)
+ data = (data << 8) ^
+ crc_big_table[(data >> ((W - 1) << 3)) & 0xff];
+ return data;
+}
+
+#endif
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32_z(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ z_size_t len;
+{
+ /* Return initial CRC, if requested. */
+ if (buf == Z_NULL) return 0;
+
+#ifdef DYNAMIC_CRC_TABLE
+ once(&made, make_crc_table);
+#endif /* DYNAMIC_CRC_TABLE */
+
+ /* Pre-condition the CRC */
+ crc = (~crc) & 0xffffffff;
+
+#ifdef W
+
+ /* If provided enough bytes, do a braided CRC calculation. */
+ if (len >= N * W + W - 1) {
+ z_size_t blks;
+ z_word_t const *words;
+ unsigned endian;
+ int k;
+
+ /* Compute the CRC up to a z_word_t boundary. */
+ while (len && ((z_size_t)buf & (W - 1)) != 0) {
+ len--;
+ crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
+ }
+
+ /* Compute the CRC on as many N z_word_t blocks as are available. */
+ blks = len / (N * W);
+ len -= blks * N * W;
+ words = (z_word_t const *)buf;
+
+ /* Do endian check at execution time instead of compile time, since ARM
+ processors can change the endianess at execution time. If the
+ compiler knows what the endianess will be, it can optimize out the
+ check and the unused branch. */
+ endian = 1;
+ if (*(unsigned char *)&endian) {
+ /* Little endian. */
+
+ z_crc_t crc0;
+ z_word_t word0;
+#if N > 1
+ z_crc_t crc1;
+ z_word_t word1;
+#if N > 2
+ z_crc_t crc2;
+ z_word_t word2;
+#if N > 3
+ z_crc_t crc3;
+ z_word_t word3;
+#if N > 4
+ z_crc_t crc4;
+ z_word_t word4;
+#if N > 5
+ z_crc_t crc5;
+ z_word_t word5;
+#endif
+#endif
+#endif
+#endif
+#endif
+
+ /* Initialize the CRC for each braid. */
+ crc0 = crc;
+#if N > 1
+ crc1 = 0;
+#if N > 2
+ crc2 = 0;
+#if N > 3
+ crc3 = 0;
+#if N > 4
+ crc4 = 0;
+#if N > 5
+ crc5 = 0;
+#endif
+#endif
+#endif
+#endif
+#endif
+
+ /*
+ Process the first blks-1 blocks, computing the CRCs on each braid
+ independently.
+ */
+ while (--blks) {
+ /* Load the word for each braid into registers. */
+ word0 = crc0 ^ words[0];
+#if N > 1
+ word1 = crc1 ^ words[1];
+#if N > 2
+ word2 = crc2 ^ words[2];
+#if N > 3
+ word3 = crc3 ^ words[3];
+#if N > 4
+ word4 = crc4 ^ words[4];
+#if N > 5
+ word5 = crc5 ^ words[5];
+#endif
+#endif
+#endif
+#endif
+#endif
+ words += N;
+
+ /* Compute and update the CRC for each word. The loop should
+ get unrolled. */
+ crc0 = crc_braid_table[0][word0 & 0xff];
+#if N > 1
+ crc1 = crc_braid_table[0][word1 & 0xff];
+#if N > 2
+ crc2 = crc_braid_table[0][word2 & 0xff];
+#if N > 3
+ crc3 = crc_braid_table[0][word3 & 0xff];
+#if N > 4
+ crc4 = crc_braid_table[0][word4 & 0xff];
+#if N > 5
+ crc5 = crc_braid_table[0][word5 & 0xff];
+#endif
+#endif
+#endif
+#endif
+#endif
+ for (k = 1; k < W; k++) {
+ crc0 ^= crc_braid_table[k][(word0 >> (k << 3)) & 0xff];
+#if N > 1
+ crc1 ^= crc_braid_table[k][(word1 >> (k << 3)) & 0xff];
+#if N > 2
+ crc2 ^= crc_braid_table[k][(word2 >> (k << 3)) & 0xff];
+#if N > 3
+ crc3 ^= crc_braid_table[k][(word3 >> (k << 3)) & 0xff];
+#if N > 4
+ crc4 ^= crc_braid_table[k][(word4 >> (k << 3)) & 0xff];
+#if N > 5
+ crc5 ^= crc_braid_table[k][(word5 >> (k << 3)) & 0xff];
+#endif
+#endif
+#endif
+#endif
+#endif
+ }
+ }
+
+ /*
+ Process the last block, combining the CRCs of the N braids at the
+ same time.
+ */
+ crc = crc_word(crc0 ^ words[0]);
+#if N > 1
+ crc = crc_word(crc1 ^ words[1] ^ crc);
+#if N > 2
+ crc = crc_word(crc2 ^ words[2] ^ crc);
+#if N > 3
+ crc = crc_word(crc3 ^ words[3] ^ crc);
+#if N > 4
+ crc = crc_word(crc4 ^ words[4] ^ crc);
+#if N > 5
+ crc = crc_word(crc5 ^ words[5] ^ crc);
+#endif
+#endif
+#endif
+#endif
+#endif
+ words += N;
+ }
+ else {
+ /* Big endian. */
+
+ z_word_t crc0, word0, comb;
+#if N > 1
+ z_word_t crc1, word1;
+#if N > 2
+ z_word_t crc2, word2;
+#if N > 3
+ z_word_t crc3, word3;
+#if N > 4
+ z_word_t crc4, word4;
+#if N > 5
+ z_word_t crc5, word5;
+#endif
+#endif
+#endif
+#endif
+#endif
+
+ /* Initialize the CRC for each braid. */
+ crc0 = byte_swap(crc);
+#if N > 1
+ crc1 = 0;
+#if N > 2
+ crc2 = 0;
+#if N > 3
+ crc3 = 0;
+#if N > 4
+ crc4 = 0;
+#if N > 5
+ crc5 = 0;
+#endif
+#endif
+#endif
+#endif
+#endif
+
+ /*
+ Process the first blks-1 blocks, computing the CRCs on each braid
+ independently.
+ */
+ while (--blks) {
+ /* Load the word for each braid into registers. */
+ word0 = crc0 ^ words[0];
+#if N > 1
+ word1 = crc1 ^ words[1];
+#if N > 2
+ word2 = crc2 ^ words[2];
+#if N > 3
+ word3 = crc3 ^ words[3];
+#if N > 4
+ word4 = crc4 ^ words[4];
+#if N > 5
+ word5 = crc5 ^ words[5];
+#endif
+#endif
+#endif
+#endif
+#endif
+ words += N;
+
+ /* Compute and update the CRC for each word. The loop should
+ get unrolled. */
+ crc0 = crc_braid_big_table[0][word0 & 0xff];
+#if N > 1
+ crc1 = crc_braid_big_table[0][word1 & 0xff];
+#if N > 2
+ crc2 = crc_braid_big_table[0][word2 & 0xff];
+#if N > 3
+ crc3 = crc_braid_big_table[0][word3 & 0xff];
+#if N > 4
+ crc4 = crc_braid_big_table[0][word4 & 0xff];
+#if N > 5
+ crc5 = crc_braid_big_table[0][word5 & 0xff];
+#endif
+#endif
+#endif
+#endif
+#endif
+ for (k = 1; k < W; k++) {
+ crc0 ^= crc_braid_big_table[k][(word0 >> (k << 3)) & 0xff];
+#if N > 1
+ crc1 ^= crc_braid_big_table[k][(word1 >> (k << 3)) & 0xff];
+#if N > 2
+ crc2 ^= crc_braid_big_table[k][(word2 >> (k << 3)) & 0xff];
+#if N > 3
+ crc3 ^= crc_braid_big_table[k][(word3 >> (k << 3)) & 0xff];
+#if N > 4
+ crc4 ^= crc_braid_big_table[k][(word4 >> (k << 3)) & 0xff];
+#if N > 5
+ crc5 ^= crc_braid_big_table[k][(word5 >> (k << 3)) & 0xff];
+#endif
+#endif
+#endif
+#endif
+#endif
+ }
+ }
+
+ /*
+ Process the last block, combining the CRCs of the N braids at the
+ same time.
+ */
+ comb = crc_word_big(crc0 ^ words[0]);
+#if N > 1
+ comb = crc_word_big(crc1 ^ words[1] ^ comb);
+#if N > 2
+ comb = crc_word_big(crc2 ^ words[2] ^ comb);
+#if N > 3
+ comb = crc_word_big(crc3 ^ words[3] ^ comb);
+#if N > 4
+ comb = crc_word_big(crc4 ^ words[4] ^ comb);
+#if N > 5
+ comb = crc_word_big(crc5 ^ words[5] ^ comb);
+#endif
+#endif
+#endif
+#endif
+#endif
+ words += N;
+ crc = byte_swap(comb);
+ }
+
+ /*
+ Update the pointer to the remaining bytes to process.
+ */
+ buf = (unsigned char const *)words;
+ }
+
+#endif /* W */
+
+ /* Complete the computation of the CRC on any remaining bytes. */
+ while (len >= 8) {
+ len -= 8;
+ crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
+ crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
+ crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
+ crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
+ crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
+ crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
+ crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
+ crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
+ }
+ while (len) {
+ len--;
+ crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];
+ }
+
+ /* Return the CRC, post-conditioned. */
+ return crc ^ 0xffffffff;
+}
+
+#endif
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ uInt len;
+{
+ return crc32_z(crc, buf, len);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine64(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off64_t len2;
+{
+#ifdef DYNAMIC_CRC_TABLE
+ once(&made, make_crc_table);
+#endif /* DYNAMIC_CRC_TABLE */
+ return multmodp(x2nmodp(len2, 3), crc1) ^ (crc2 & 0xffffffff);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off_t len2;
+{
+ return crc32_combine64(crc1, crc2, (z_off64_t)len2);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine_gen64(len2)
+ z_off64_t len2;
+{
+#ifdef DYNAMIC_CRC_TABLE
+ once(&made, make_crc_table);
+#endif /* DYNAMIC_CRC_TABLE */
+ return x2nmodp(len2, 3);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine_gen(len2)
+ z_off_t len2;
+{
+ return crc32_combine_gen64((z_off64_t)len2);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine_op(crc1, crc2, op)
+ uLong crc1;
+ uLong crc2;
+ uLong op;
+{
+ return multmodp(op, crc1) ^ (crc2 & 0xffffffff);
+}
diff --git a/lib/zlib/crc32.h b/lib/zlib/crc32.h
new file mode 100644
index 0000000..137df68
--- /dev/null
+++ b/lib/zlib/crc32.h
@@ -0,0 +1,9446 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const z_crc_t FAR crc_table[] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d};
+
+#ifdef W
+
+#if W == 8
+
+local const z_word_t FAR crc_big_table[] = {
+ 0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000,
+ 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000,
+ 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000,
+ 0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000,
+ 0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000,
+ 0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000,
+ 0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000,
+ 0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000,
+ 0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000,
+ 0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000,
+ 0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000,
+ 0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000,
+ 0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000,
+ 0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000,
+ 0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000,
+ 0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000,
+ 0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000,
+ 0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000,
+ 0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000,
+ 0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000,
+ 0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000,
+ 0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000,
+ 0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000,
+ 0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000,
+ 0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000,
+ 0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000,
+ 0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000,
+ 0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000,
+ 0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000,
+ 0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000,
+ 0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000,
+ 0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000,
+ 0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000,
+ 0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000,
+ 0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000,
+ 0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000,
+ 0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000,
+ 0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000,
+ 0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000,
+ 0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000,
+ 0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000,
+ 0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000,
+ 0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000,
+ 0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000,
+ 0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000,
+ 0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000,
+ 0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000,
+ 0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000,
+ 0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000,
+ 0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000,
+ 0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000,
+ 0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000,
+ 0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000,
+ 0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000,
+ 0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000,
+ 0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000,
+ 0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000,
+ 0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000,
+ 0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000,
+ 0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000,
+ 0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000,
+ 0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000,
+ 0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000,
+ 0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000,
+ 0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000,
+ 0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000,
+ 0x8567077200000000, 0x1357000500000000, 0x824abf9500000000,
+ 0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000,
+ 0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000,
+ 0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000,
+ 0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000,
+ 0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000,
+ 0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000,
+ 0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000,
+ 0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000,
+ 0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000,
+ 0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000,
+ 0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000,
+ 0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000,
+ 0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000,
+ 0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000,
+ 0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000,
+ 0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000,
+ 0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000,
+ 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000,
+ 0x8def022d00000000};
+
+#else /* W == 4 */
+
+local const z_word_t FAR crc_big_table[] = {
+ 0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07,
+ 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79,
+ 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7,
+ 0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84,
+ 0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13,
+ 0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663,
+ 0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5,
+ 0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5,
+ 0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832,
+ 0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51,
+ 0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf,
+ 0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1,
+ 0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76,
+ 0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606,
+ 0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996,
+ 0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6,
+ 0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c,
+ 0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712,
+ 0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c,
+ 0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4,
+ 0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943,
+ 0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333,
+ 0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe,
+ 0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce,
+ 0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359,
+ 0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a,
+ 0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04,
+ 0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a,
+ 0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0,
+ 0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580,
+ 0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10,
+ 0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060,
+ 0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1,
+ 0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf,
+ 0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31,
+ 0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852,
+ 0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5,
+ 0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5,
+ 0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75,
+ 0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005,
+ 0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292,
+ 0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1,
+ 0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f,
+ 0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111,
+ 0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0,
+ 0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0,
+ 0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40,
+ 0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530,
+ 0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba,
+ 0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4,
+ 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a,
+ 0x8def022d};
+
+#endif
+
+#if N == 1
+
+#if W == 8
+
+local const z_crc_t FAR crc_braid_table[][256] = {
+ {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa,
+ 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b,
+ 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232,
+ 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8,
+ 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e,
+ 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa,
+ 0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b,
+ 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f,
+ 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719,
+ 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3,
+ 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa,
+ 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b,
+ 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed,
+ 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89,
+ 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25,
+ 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041,
+ 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c,
+ 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed,
+ 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4,
+ 0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758,
+ 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e,
+ 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a,
+ 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed,
+ 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889,
+ 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df,
+ 0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544,
+ 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d,
+ 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c,
+ 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1,
+ 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95,
+ 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839,
+ 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d,
+ 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976,
+ 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7,
+ 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be,
+ 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144,
+ 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12,
+ 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376,
+ 0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a,
+ 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e,
+ 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278,
+ 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682,
+ 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b,
+ 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a,
+ 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561,
+ 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05,
+ 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9,
+ 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd,
+ 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0,
+ 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61,
+ 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678,
+ 0x264b06e6},
+ {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413,
+ 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3,
+ 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d,
+ 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653,
+ 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9,
+ 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e,
+ 0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5,
+ 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712,
+ 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8,
+ 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6,
+ 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068,
+ 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8,
+ 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579,
+ 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade,
+ 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37,
+ 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590,
+ 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4,
+ 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64,
+ 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea,
+ 0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678,
+ 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282,
+ 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25,
+ 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102,
+ 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5,
+ 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f,
+ 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146,
+ 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8,
+ 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08,
+ 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c,
+ 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b,
+ 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972,
+ 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5,
+ 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d,
+ 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd,
+ 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833,
+ 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d,
+ 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7,
+ 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60,
+ 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2,
+ 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105,
+ 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff,
+ 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1,
+ 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f,
+ 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf,
+ 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617,
+ 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0,
+ 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959,
+ 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe,
+ 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca,
+ 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a,
+ 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184,
+ 0x92364a30},
+ {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216,
+ 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8,
+ 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170,
+ 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035,
+ 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6,
+ 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145,
+ 0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d,
+ 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e,
+ 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d,
+ 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408,
+ 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0,
+ 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e,
+ 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c,
+ 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf,
+ 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a,
+ 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9,
+ 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1,
+ 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f,
+ 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987,
+ 0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4,
+ 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37,
+ 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84,
+ 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca,
+ 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79,
+ 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba,
+ 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d,
+ 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5,
+ 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b,
+ 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643,
+ 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0,
+ 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525,
+ 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496,
+ 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8,
+ 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026,
+ 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e,
+ 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db,
+ 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118,
+ 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab,
+ 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf,
+ 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c,
+ 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf,
+ 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a,
+ 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32,
+ 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec,
+ 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82,
+ 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31,
+ 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4,
+ 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957,
+ 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f,
+ 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1,
+ 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869,
+ 0xe4c4abcc},
+ {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0,
+ 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271,
+ 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61,
+ 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52,
+ 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43,
+ 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333,
+ 0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64,
+ 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314,
+ 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205,
+ 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136,
+ 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26,
+ 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997,
+ 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849,
+ 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739,
+ 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8,
+ 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98,
+ 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b,
+ 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba,
+ 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa,
+ 0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d,
+ 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c,
+ 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc,
+ 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af,
+ 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf,
+ 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce,
+ 0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922,
+ 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532,
+ 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183,
+ 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710,
+ 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860,
+ 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1,
+ 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1,
+ 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956,
+ 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7,
+ 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7,
+ 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4,
+ 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5,
+ 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5,
+ 0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb,
+ 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb,
+ 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da,
+ 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9,
+ 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9,
+ 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48,
+ 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df,
+ 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af,
+ 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e,
+ 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e,
+ 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d,
+ 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c,
+ 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c,
+ 0xca64c78c},
+ {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757,
+ 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a,
+ 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733,
+ 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871,
+ 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70,
+ 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42,
+ 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5,
+ 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787,
+ 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086,
+ 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4,
+ 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d,
+ 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0,
+ 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d,
+ 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f,
+ 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859,
+ 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b,
+ 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5,
+ 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028,
+ 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891,
+ 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed,
+ 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec,
+ 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde,
+ 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817,
+ 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825,
+ 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24,
+ 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e,
+ 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7,
+ 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a,
+ 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4,
+ 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196,
+ 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0,
+ 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2,
+ 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52,
+ 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f,
+ 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36,
+ 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174,
+ 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675,
+ 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647,
+ 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d,
+ 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf,
+ 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be,
+ 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc,
+ 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645,
+ 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98,
+ 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138,
+ 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a,
+ 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c,
+ 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e,
+ 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0,
+ 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d,
+ 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194,
+ 0xde0506f1},
+ {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc,
+ 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f,
+ 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a,
+ 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29,
+ 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8,
+ 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023,
+ 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e,
+ 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065,
+ 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84,
+ 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7,
+ 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922,
+ 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71,
+ 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0,
+ 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b,
+ 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816,
+ 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd,
+ 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c,
+ 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f,
+ 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba,
+ 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579,
+ 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98,
+ 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873,
+ 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e,
+ 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5,
+ 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134,
+ 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7,
+ 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732,
+ 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461,
+ 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0,
+ 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b,
+ 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26,
+ 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd,
+ 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc,
+ 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef,
+ 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a,
+ 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049,
+ 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8,
+ 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43,
+ 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e,
+ 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5,
+ 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24,
+ 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07,
+ 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982,
+ 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1,
+ 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0,
+ 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b,
+ 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576,
+ 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d,
+ 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c,
+ 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f,
+ 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda,
+ 0xbe9834ed},
+ {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504,
+ 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49,
+ 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e,
+ 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192,
+ 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859,
+ 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c,
+ 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620,
+ 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265,
+ 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae,
+ 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2,
+ 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175,
+ 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38,
+ 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05,
+ 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40,
+ 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f,
+ 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca,
+ 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850,
+ 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d,
+ 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da,
+ 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864,
+ 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af,
+ 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea,
+ 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74,
+ 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31,
+ 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa,
+ 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a,
+ 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd,
+ 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180,
+ 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a,
+ 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f,
+ 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290,
+ 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5,
+ 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed,
+ 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0,
+ 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167,
+ 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b,
+ 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0,
+ 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5,
+ 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc,
+ 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189,
+ 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842,
+ 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e,
+ 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299,
+ 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4,
+ 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec,
+ 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9,
+ 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66,
+ 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23,
+ 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9,
+ 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4,
+ 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33,
+ 0x9324fd72},
+ {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d}};
+
+local const z_word_t FAR crc_braid_big_table[][256] = {
+ {0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000,
+ 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000,
+ 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000,
+ 0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000,
+ 0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000,
+ 0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000,
+ 0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000,
+ 0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000,
+ 0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000,
+ 0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000,
+ 0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000,
+ 0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000,
+ 0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000,
+ 0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000,
+ 0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000,
+ 0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000,
+ 0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000,
+ 0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000,
+ 0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000,
+ 0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000,
+ 0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000,
+ 0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000,
+ 0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000,
+ 0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000,
+ 0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000,
+ 0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000,
+ 0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000,
+ 0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000,
+ 0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000,
+ 0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000,
+ 0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000,
+ 0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000,
+ 0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000,
+ 0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000,
+ 0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000,
+ 0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000,
+ 0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000,
+ 0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000,
+ 0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000,
+ 0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000,
+ 0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000,
+ 0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000,
+ 0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000,
+ 0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000,
+ 0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000,
+ 0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000,
+ 0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000,
+ 0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000,
+ 0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000,
+ 0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000,
+ 0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000,
+ 0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000,
+ 0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000,
+ 0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000,
+ 0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000,
+ 0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000,
+ 0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000,
+ 0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000,
+ 0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000,
+ 0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000,
+ 0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000,
+ 0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000,
+ 0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000,
+ 0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000,
+ 0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000,
+ 0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000,
+ 0x8567077200000000, 0x1357000500000000, 0x824abf9500000000,
+ 0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000,
+ 0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000,
+ 0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000,
+ 0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000,
+ 0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000,
+ 0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000,
+ 0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000,
+ 0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000,
+ 0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000,
+ 0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000,
+ 0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000,
+ 0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000,
+ 0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000,
+ 0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000,
+ 0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000,
+ 0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000,
+ 0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000,
+ 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000,
+ 0x8def022d00000000},
+ {0x0000000000000000, 0x41311b1900000000, 0x8262363200000000,
+ 0xc3532d2b00000000, 0x04c56c6400000000, 0x45f4777d00000000,
+ 0x86a75a5600000000, 0xc796414f00000000, 0x088ad9c800000000,
+ 0x49bbc2d100000000, 0x8ae8effa00000000, 0xcbd9f4e300000000,
+ 0x0c4fb5ac00000000, 0x4d7eaeb500000000, 0x8e2d839e00000000,
+ 0xcf1c988700000000, 0x5112c24a00000000, 0x1023d95300000000,
+ 0xd370f47800000000, 0x9241ef6100000000, 0x55d7ae2e00000000,
+ 0x14e6b53700000000, 0xd7b5981c00000000, 0x9684830500000000,
+ 0x59981b8200000000, 0x18a9009b00000000, 0xdbfa2db000000000,
+ 0x9acb36a900000000, 0x5d5d77e600000000, 0x1c6c6cff00000000,
+ 0xdf3f41d400000000, 0x9e0e5acd00000000, 0xa224849500000000,
+ 0xe3159f8c00000000, 0x2046b2a700000000, 0x6177a9be00000000,
+ 0xa6e1e8f100000000, 0xe7d0f3e800000000, 0x2483dec300000000,
+ 0x65b2c5da00000000, 0xaaae5d5d00000000, 0xeb9f464400000000,
+ 0x28cc6b6f00000000, 0x69fd707600000000, 0xae6b313900000000,
+ 0xef5a2a2000000000, 0x2c09070b00000000, 0x6d381c1200000000,
+ 0xf33646df00000000, 0xb2075dc600000000, 0x715470ed00000000,
+ 0x30656bf400000000, 0xf7f32abb00000000, 0xb6c231a200000000,
+ 0x75911c8900000000, 0x34a0079000000000, 0xfbbc9f1700000000,
+ 0xba8d840e00000000, 0x79dea92500000000, 0x38efb23c00000000,
+ 0xff79f37300000000, 0xbe48e86a00000000, 0x7d1bc54100000000,
+ 0x3c2ade5800000000, 0x054f79f000000000, 0x447e62e900000000,
+ 0x872d4fc200000000, 0xc61c54db00000000, 0x018a159400000000,
+ 0x40bb0e8d00000000, 0x83e823a600000000, 0xc2d938bf00000000,
+ 0x0dc5a03800000000, 0x4cf4bb2100000000, 0x8fa7960a00000000,
+ 0xce968d1300000000, 0x0900cc5c00000000, 0x4831d74500000000,
+ 0x8b62fa6e00000000, 0xca53e17700000000, 0x545dbbba00000000,
+ 0x156ca0a300000000, 0xd63f8d8800000000, 0x970e969100000000,
+ 0x5098d7de00000000, 0x11a9ccc700000000, 0xd2fae1ec00000000,
+ 0x93cbfaf500000000, 0x5cd7627200000000, 0x1de6796b00000000,
+ 0xdeb5544000000000, 0x9f844f5900000000, 0x58120e1600000000,
+ 0x1923150f00000000, 0xda70382400000000, 0x9b41233d00000000,
+ 0xa76bfd6500000000, 0xe65ae67c00000000, 0x2509cb5700000000,
+ 0x6438d04e00000000, 0xa3ae910100000000, 0xe29f8a1800000000,
+ 0x21cca73300000000, 0x60fdbc2a00000000, 0xafe124ad00000000,
+ 0xeed03fb400000000, 0x2d83129f00000000, 0x6cb2098600000000,
+ 0xab2448c900000000, 0xea1553d000000000, 0x29467efb00000000,
+ 0x687765e200000000, 0xf6793f2f00000000, 0xb748243600000000,
+ 0x741b091d00000000, 0x352a120400000000, 0xf2bc534b00000000,
+ 0xb38d485200000000, 0x70de657900000000, 0x31ef7e6000000000,
+ 0xfef3e6e700000000, 0xbfc2fdfe00000000, 0x7c91d0d500000000,
+ 0x3da0cbcc00000000, 0xfa368a8300000000, 0xbb07919a00000000,
+ 0x7854bcb100000000, 0x3965a7a800000000, 0x4b98833b00000000,
+ 0x0aa9982200000000, 0xc9fab50900000000, 0x88cbae1000000000,
+ 0x4f5def5f00000000, 0x0e6cf44600000000, 0xcd3fd96d00000000,
+ 0x8c0ec27400000000, 0x43125af300000000, 0x022341ea00000000,
+ 0xc1706cc100000000, 0x804177d800000000, 0x47d7369700000000,
+ 0x06e62d8e00000000, 0xc5b500a500000000, 0x84841bbc00000000,
+ 0x1a8a417100000000, 0x5bbb5a6800000000, 0x98e8774300000000,
+ 0xd9d96c5a00000000, 0x1e4f2d1500000000, 0x5f7e360c00000000,
+ 0x9c2d1b2700000000, 0xdd1c003e00000000, 0x120098b900000000,
+ 0x533183a000000000, 0x9062ae8b00000000, 0xd153b59200000000,
+ 0x16c5f4dd00000000, 0x57f4efc400000000, 0x94a7c2ef00000000,
+ 0xd596d9f600000000, 0xe9bc07ae00000000, 0xa88d1cb700000000,
+ 0x6bde319c00000000, 0x2aef2a8500000000, 0xed796bca00000000,
+ 0xac4870d300000000, 0x6f1b5df800000000, 0x2e2a46e100000000,
+ 0xe136de6600000000, 0xa007c57f00000000, 0x6354e85400000000,
+ 0x2265f34d00000000, 0xe5f3b20200000000, 0xa4c2a91b00000000,
+ 0x6791843000000000, 0x26a09f2900000000, 0xb8aec5e400000000,
+ 0xf99fdefd00000000, 0x3accf3d600000000, 0x7bfde8cf00000000,
+ 0xbc6ba98000000000, 0xfd5ab29900000000, 0x3e099fb200000000,
+ 0x7f3884ab00000000, 0xb0241c2c00000000, 0xf115073500000000,
+ 0x32462a1e00000000, 0x7377310700000000, 0xb4e1704800000000,
+ 0xf5d06b5100000000, 0x3683467a00000000, 0x77b25d6300000000,
+ 0x4ed7facb00000000, 0x0fe6e1d200000000, 0xccb5ccf900000000,
+ 0x8d84d7e000000000, 0x4a1296af00000000, 0x0b238db600000000,
+ 0xc870a09d00000000, 0x8941bb8400000000, 0x465d230300000000,
+ 0x076c381a00000000, 0xc43f153100000000, 0x850e0e2800000000,
+ 0x42984f6700000000, 0x03a9547e00000000, 0xc0fa795500000000,
+ 0x81cb624c00000000, 0x1fc5388100000000, 0x5ef4239800000000,
+ 0x9da70eb300000000, 0xdc9615aa00000000, 0x1b0054e500000000,
+ 0x5a314ffc00000000, 0x996262d700000000, 0xd85379ce00000000,
+ 0x174fe14900000000, 0x567efa5000000000, 0x952dd77b00000000,
+ 0xd41ccc6200000000, 0x138a8d2d00000000, 0x52bb963400000000,
+ 0x91e8bb1f00000000, 0xd0d9a00600000000, 0xecf37e5e00000000,
+ 0xadc2654700000000, 0x6e91486c00000000, 0x2fa0537500000000,
+ 0xe836123a00000000, 0xa907092300000000, 0x6a54240800000000,
+ 0x2b653f1100000000, 0xe479a79600000000, 0xa548bc8f00000000,
+ 0x661b91a400000000, 0x272a8abd00000000, 0xe0bccbf200000000,
+ 0xa18dd0eb00000000, 0x62defdc000000000, 0x23efe6d900000000,
+ 0xbde1bc1400000000, 0xfcd0a70d00000000, 0x3f838a2600000000,
+ 0x7eb2913f00000000, 0xb924d07000000000, 0xf815cb6900000000,
+ 0x3b46e64200000000, 0x7a77fd5b00000000, 0xb56b65dc00000000,
+ 0xf45a7ec500000000, 0x370953ee00000000, 0x763848f700000000,
+ 0xb1ae09b800000000, 0xf09f12a100000000, 0x33cc3f8a00000000,
+ 0x72fd249300000000},
+ {0x0000000000000000, 0x376ac20100000000, 0x6ed4840300000000,
+ 0x59be460200000000, 0xdca8090700000000, 0xebc2cb0600000000,
+ 0xb27c8d0400000000, 0x85164f0500000000, 0xb851130e00000000,
+ 0x8f3bd10f00000000, 0xd685970d00000000, 0xe1ef550c00000000,
+ 0x64f91a0900000000, 0x5393d80800000000, 0x0a2d9e0a00000000,
+ 0x3d475c0b00000000, 0x70a3261c00000000, 0x47c9e41d00000000,
+ 0x1e77a21f00000000, 0x291d601e00000000, 0xac0b2f1b00000000,
+ 0x9b61ed1a00000000, 0xc2dfab1800000000, 0xf5b5691900000000,
+ 0xc8f2351200000000, 0xff98f71300000000, 0xa626b11100000000,
+ 0x914c731000000000, 0x145a3c1500000000, 0x2330fe1400000000,
+ 0x7a8eb81600000000, 0x4de47a1700000000, 0xe0464d3800000000,
+ 0xd72c8f3900000000, 0x8e92c93b00000000, 0xb9f80b3a00000000,
+ 0x3cee443f00000000, 0x0b84863e00000000, 0x523ac03c00000000,
+ 0x6550023d00000000, 0x58175e3600000000, 0x6f7d9c3700000000,
+ 0x36c3da3500000000, 0x01a9183400000000, 0x84bf573100000000,
+ 0xb3d5953000000000, 0xea6bd33200000000, 0xdd01113300000000,
+ 0x90e56b2400000000, 0xa78fa92500000000, 0xfe31ef2700000000,
+ 0xc95b2d2600000000, 0x4c4d622300000000, 0x7b27a02200000000,
+ 0x2299e62000000000, 0x15f3242100000000, 0x28b4782a00000000,
+ 0x1fdeba2b00000000, 0x4660fc2900000000, 0x710a3e2800000000,
+ 0xf41c712d00000000, 0xc376b32c00000000, 0x9ac8f52e00000000,
+ 0xada2372f00000000, 0xc08d9a7000000000, 0xf7e7587100000000,
+ 0xae591e7300000000, 0x9933dc7200000000, 0x1c25937700000000,
+ 0x2b4f517600000000, 0x72f1177400000000, 0x459bd57500000000,
+ 0x78dc897e00000000, 0x4fb64b7f00000000, 0x16080d7d00000000,
+ 0x2162cf7c00000000, 0xa474807900000000, 0x931e427800000000,
+ 0xcaa0047a00000000, 0xfdcac67b00000000, 0xb02ebc6c00000000,
+ 0x87447e6d00000000, 0xdefa386f00000000, 0xe990fa6e00000000,
+ 0x6c86b56b00000000, 0x5bec776a00000000, 0x0252316800000000,
+ 0x3538f36900000000, 0x087faf6200000000, 0x3f156d6300000000,
+ 0x66ab2b6100000000, 0x51c1e96000000000, 0xd4d7a66500000000,
+ 0xe3bd646400000000, 0xba03226600000000, 0x8d69e06700000000,
+ 0x20cbd74800000000, 0x17a1154900000000, 0x4e1f534b00000000,
+ 0x7975914a00000000, 0xfc63de4f00000000, 0xcb091c4e00000000,
+ 0x92b75a4c00000000, 0xa5dd984d00000000, 0x989ac44600000000,
+ 0xaff0064700000000, 0xf64e404500000000, 0xc124824400000000,
+ 0x4432cd4100000000, 0x73580f4000000000, 0x2ae6494200000000,
+ 0x1d8c8b4300000000, 0x5068f15400000000, 0x6702335500000000,
+ 0x3ebc755700000000, 0x09d6b75600000000, 0x8cc0f85300000000,
+ 0xbbaa3a5200000000, 0xe2147c5000000000, 0xd57ebe5100000000,
+ 0xe839e25a00000000, 0xdf53205b00000000, 0x86ed665900000000,
+ 0xb187a45800000000, 0x3491eb5d00000000, 0x03fb295c00000000,
+ 0x5a456f5e00000000, 0x6d2fad5f00000000, 0x801b35e100000000,
+ 0xb771f7e000000000, 0xeecfb1e200000000, 0xd9a573e300000000,
+ 0x5cb33ce600000000, 0x6bd9fee700000000, 0x3267b8e500000000,
+ 0x050d7ae400000000, 0x384a26ef00000000, 0x0f20e4ee00000000,
+ 0x569ea2ec00000000, 0x61f460ed00000000, 0xe4e22fe800000000,
+ 0xd388ede900000000, 0x8a36abeb00000000, 0xbd5c69ea00000000,
+ 0xf0b813fd00000000, 0xc7d2d1fc00000000, 0x9e6c97fe00000000,
+ 0xa90655ff00000000, 0x2c101afa00000000, 0x1b7ad8fb00000000,
+ 0x42c49ef900000000, 0x75ae5cf800000000, 0x48e900f300000000,
+ 0x7f83c2f200000000, 0x263d84f000000000, 0x115746f100000000,
+ 0x944109f400000000, 0xa32bcbf500000000, 0xfa958df700000000,
+ 0xcdff4ff600000000, 0x605d78d900000000, 0x5737bad800000000,
+ 0x0e89fcda00000000, 0x39e33edb00000000, 0xbcf571de00000000,
+ 0x8b9fb3df00000000, 0xd221f5dd00000000, 0xe54b37dc00000000,
+ 0xd80c6bd700000000, 0xef66a9d600000000, 0xb6d8efd400000000,
+ 0x81b22dd500000000, 0x04a462d000000000, 0x33cea0d100000000,
+ 0x6a70e6d300000000, 0x5d1a24d200000000, 0x10fe5ec500000000,
+ 0x27949cc400000000, 0x7e2adac600000000, 0x494018c700000000,
+ 0xcc5657c200000000, 0xfb3c95c300000000, 0xa282d3c100000000,
+ 0x95e811c000000000, 0xa8af4dcb00000000, 0x9fc58fca00000000,
+ 0xc67bc9c800000000, 0xf1110bc900000000, 0x740744cc00000000,
+ 0x436d86cd00000000, 0x1ad3c0cf00000000, 0x2db902ce00000000,
+ 0x4096af9100000000, 0x77fc6d9000000000, 0x2e422b9200000000,
+ 0x1928e99300000000, 0x9c3ea69600000000, 0xab54649700000000,
+ 0xf2ea229500000000, 0xc580e09400000000, 0xf8c7bc9f00000000,
+ 0xcfad7e9e00000000, 0x9613389c00000000, 0xa179fa9d00000000,
+ 0x246fb59800000000, 0x1305779900000000, 0x4abb319b00000000,
+ 0x7dd1f39a00000000, 0x3035898d00000000, 0x075f4b8c00000000,
+ 0x5ee10d8e00000000, 0x698bcf8f00000000, 0xec9d808a00000000,
+ 0xdbf7428b00000000, 0x8249048900000000, 0xb523c68800000000,
+ 0x88649a8300000000, 0xbf0e588200000000, 0xe6b01e8000000000,
+ 0xd1dadc8100000000, 0x54cc938400000000, 0x63a6518500000000,
+ 0x3a18178700000000, 0x0d72d58600000000, 0xa0d0e2a900000000,
+ 0x97ba20a800000000, 0xce0466aa00000000, 0xf96ea4ab00000000,
+ 0x7c78ebae00000000, 0x4b1229af00000000, 0x12ac6fad00000000,
+ 0x25c6adac00000000, 0x1881f1a700000000, 0x2feb33a600000000,
+ 0x765575a400000000, 0x413fb7a500000000, 0xc429f8a000000000,
+ 0xf3433aa100000000, 0xaafd7ca300000000, 0x9d97bea200000000,
+ 0xd073c4b500000000, 0xe71906b400000000, 0xbea740b600000000,
+ 0x89cd82b700000000, 0x0cdbcdb200000000, 0x3bb10fb300000000,
+ 0x620f49b100000000, 0x55658bb000000000, 0x6822d7bb00000000,
+ 0x5f4815ba00000000, 0x06f653b800000000, 0x319c91b900000000,
+ 0xb48adebc00000000, 0x83e01cbd00000000, 0xda5e5abf00000000,
+ 0xed3498be00000000},
+ {0x0000000000000000, 0x6567bcb800000000, 0x8bc809aa00000000,
+ 0xeeafb51200000000, 0x5797628f00000000, 0x32f0de3700000000,
+ 0xdc5f6b2500000000, 0xb938d79d00000000, 0xef28b4c500000000,
+ 0x8a4f087d00000000, 0x64e0bd6f00000000, 0x018701d700000000,
+ 0xb8bfd64a00000000, 0xddd86af200000000, 0x3377dfe000000000,
+ 0x5610635800000000, 0x9f57195000000000, 0xfa30a5e800000000,
+ 0x149f10fa00000000, 0x71f8ac4200000000, 0xc8c07bdf00000000,
+ 0xada7c76700000000, 0x4308727500000000, 0x266fcecd00000000,
+ 0x707fad9500000000, 0x1518112d00000000, 0xfbb7a43f00000000,
+ 0x9ed0188700000000, 0x27e8cf1a00000000, 0x428f73a200000000,
+ 0xac20c6b000000000, 0xc9477a0800000000, 0x3eaf32a000000000,
+ 0x5bc88e1800000000, 0xb5673b0a00000000, 0xd00087b200000000,
+ 0x6938502f00000000, 0x0c5fec9700000000, 0xe2f0598500000000,
+ 0x8797e53d00000000, 0xd187866500000000, 0xb4e03add00000000,
+ 0x5a4f8fcf00000000, 0x3f28337700000000, 0x8610e4ea00000000,
+ 0xe377585200000000, 0x0dd8ed4000000000, 0x68bf51f800000000,
+ 0xa1f82bf000000000, 0xc49f974800000000, 0x2a30225a00000000,
+ 0x4f579ee200000000, 0xf66f497f00000000, 0x9308f5c700000000,
+ 0x7da740d500000000, 0x18c0fc6d00000000, 0x4ed09f3500000000,
+ 0x2bb7238d00000000, 0xc518969f00000000, 0xa07f2a2700000000,
+ 0x1947fdba00000000, 0x7c20410200000000, 0x928ff41000000000,
+ 0xf7e848a800000000, 0x3d58149b00000000, 0x583fa82300000000,
+ 0xb6901d3100000000, 0xd3f7a18900000000, 0x6acf761400000000,
+ 0x0fa8caac00000000, 0xe1077fbe00000000, 0x8460c30600000000,
+ 0xd270a05e00000000, 0xb7171ce600000000, 0x59b8a9f400000000,
+ 0x3cdf154c00000000, 0x85e7c2d100000000, 0xe0807e6900000000,
+ 0x0e2fcb7b00000000, 0x6b4877c300000000, 0xa20f0dcb00000000,
+ 0xc768b17300000000, 0x29c7046100000000, 0x4ca0b8d900000000,
+ 0xf5986f4400000000, 0x90ffd3fc00000000, 0x7e5066ee00000000,
+ 0x1b37da5600000000, 0x4d27b90e00000000, 0x284005b600000000,
+ 0xc6efb0a400000000, 0xa3880c1c00000000, 0x1ab0db8100000000,
+ 0x7fd7673900000000, 0x9178d22b00000000, 0xf41f6e9300000000,
+ 0x03f7263b00000000, 0x66909a8300000000, 0x883f2f9100000000,
+ 0xed58932900000000, 0x546044b400000000, 0x3107f80c00000000,
+ 0xdfa84d1e00000000, 0xbacff1a600000000, 0xecdf92fe00000000,
+ 0x89b82e4600000000, 0x67179b5400000000, 0x027027ec00000000,
+ 0xbb48f07100000000, 0xde2f4cc900000000, 0x3080f9db00000000,
+ 0x55e7456300000000, 0x9ca03f6b00000000, 0xf9c783d300000000,
+ 0x176836c100000000, 0x720f8a7900000000, 0xcb375de400000000,
+ 0xae50e15c00000000, 0x40ff544e00000000, 0x2598e8f600000000,
+ 0x73888bae00000000, 0x16ef371600000000, 0xf840820400000000,
+ 0x9d273ebc00000000, 0x241fe92100000000, 0x4178559900000000,
+ 0xafd7e08b00000000, 0xcab05c3300000000, 0x3bb659ed00000000,
+ 0x5ed1e55500000000, 0xb07e504700000000, 0xd519ecff00000000,
+ 0x6c213b6200000000, 0x094687da00000000, 0xe7e932c800000000,
+ 0x828e8e7000000000, 0xd49eed2800000000, 0xb1f9519000000000,
+ 0x5f56e48200000000, 0x3a31583a00000000, 0x83098fa700000000,
+ 0xe66e331f00000000, 0x08c1860d00000000, 0x6da63ab500000000,
+ 0xa4e140bd00000000, 0xc186fc0500000000, 0x2f29491700000000,
+ 0x4a4ef5af00000000, 0xf376223200000000, 0x96119e8a00000000,
+ 0x78be2b9800000000, 0x1dd9972000000000, 0x4bc9f47800000000,
+ 0x2eae48c000000000, 0xc001fdd200000000, 0xa566416a00000000,
+ 0x1c5e96f700000000, 0x79392a4f00000000, 0x97969f5d00000000,
+ 0xf2f123e500000000, 0x05196b4d00000000, 0x607ed7f500000000,
+ 0x8ed162e700000000, 0xebb6de5f00000000, 0x528e09c200000000,
+ 0x37e9b57a00000000, 0xd946006800000000, 0xbc21bcd000000000,
+ 0xea31df8800000000, 0x8f56633000000000, 0x61f9d62200000000,
+ 0x049e6a9a00000000, 0xbda6bd0700000000, 0xd8c101bf00000000,
+ 0x366eb4ad00000000, 0x5309081500000000, 0x9a4e721d00000000,
+ 0xff29cea500000000, 0x11867bb700000000, 0x74e1c70f00000000,
+ 0xcdd9109200000000, 0xa8beac2a00000000, 0x4611193800000000,
+ 0x2376a58000000000, 0x7566c6d800000000, 0x10017a6000000000,
+ 0xfeaecf7200000000, 0x9bc973ca00000000, 0x22f1a45700000000,
+ 0x479618ef00000000, 0xa939adfd00000000, 0xcc5e114500000000,
+ 0x06ee4d7600000000, 0x6389f1ce00000000, 0x8d2644dc00000000,
+ 0xe841f86400000000, 0x51792ff900000000, 0x341e934100000000,
+ 0xdab1265300000000, 0xbfd69aeb00000000, 0xe9c6f9b300000000,
+ 0x8ca1450b00000000, 0x620ef01900000000, 0x07694ca100000000,
+ 0xbe519b3c00000000, 0xdb36278400000000, 0x3599929600000000,
+ 0x50fe2e2e00000000, 0x99b9542600000000, 0xfcdee89e00000000,
+ 0x12715d8c00000000, 0x7716e13400000000, 0xce2e36a900000000,
+ 0xab498a1100000000, 0x45e63f0300000000, 0x208183bb00000000,
+ 0x7691e0e300000000, 0x13f65c5b00000000, 0xfd59e94900000000,
+ 0x983e55f100000000, 0x2106826c00000000, 0x44613ed400000000,
+ 0xaace8bc600000000, 0xcfa9377e00000000, 0x38417fd600000000,
+ 0x5d26c36e00000000, 0xb389767c00000000, 0xd6eecac400000000,
+ 0x6fd61d5900000000, 0x0ab1a1e100000000, 0xe41e14f300000000,
+ 0x8179a84b00000000, 0xd769cb1300000000, 0xb20e77ab00000000,
+ 0x5ca1c2b900000000, 0x39c67e0100000000, 0x80fea99c00000000,
+ 0xe599152400000000, 0x0b36a03600000000, 0x6e511c8e00000000,
+ 0xa716668600000000, 0xc271da3e00000000, 0x2cde6f2c00000000,
+ 0x49b9d39400000000, 0xf081040900000000, 0x95e6b8b100000000,
+ 0x7b490da300000000, 0x1e2eb11b00000000, 0x483ed24300000000,
+ 0x2d596efb00000000, 0xc3f6dbe900000000, 0xa691675100000000,
+ 0x1fa9b0cc00000000, 0x7ace0c7400000000, 0x9461b96600000000,
+ 0xf10605de00000000},
+ {0x0000000000000000, 0xb029603d00000000, 0x6053c07a00000000,
+ 0xd07aa04700000000, 0xc0a680f500000000, 0x708fe0c800000000,
+ 0xa0f5408f00000000, 0x10dc20b200000000, 0xc14b703000000000,
+ 0x7162100d00000000, 0xa118b04a00000000, 0x1131d07700000000,
+ 0x01edf0c500000000, 0xb1c490f800000000, 0x61be30bf00000000,
+ 0xd197508200000000, 0x8297e06000000000, 0x32be805d00000000,
+ 0xe2c4201a00000000, 0x52ed402700000000, 0x4231609500000000,
+ 0xf21800a800000000, 0x2262a0ef00000000, 0x924bc0d200000000,
+ 0x43dc905000000000, 0xf3f5f06d00000000, 0x238f502a00000000,
+ 0x93a6301700000000, 0x837a10a500000000, 0x3353709800000000,
+ 0xe329d0df00000000, 0x5300b0e200000000, 0x042fc1c100000000,
+ 0xb406a1fc00000000, 0x647c01bb00000000, 0xd455618600000000,
+ 0xc489413400000000, 0x74a0210900000000, 0xa4da814e00000000,
+ 0x14f3e17300000000, 0xc564b1f100000000, 0x754dd1cc00000000,
+ 0xa537718b00000000, 0x151e11b600000000, 0x05c2310400000000,
+ 0xb5eb513900000000, 0x6591f17e00000000, 0xd5b8914300000000,
+ 0x86b821a100000000, 0x3691419c00000000, 0xe6ebe1db00000000,
+ 0x56c281e600000000, 0x461ea15400000000, 0xf637c16900000000,
+ 0x264d612e00000000, 0x9664011300000000, 0x47f3519100000000,
+ 0xf7da31ac00000000, 0x27a091eb00000000, 0x9789f1d600000000,
+ 0x8755d16400000000, 0x377cb15900000000, 0xe706111e00000000,
+ 0x572f712300000000, 0x4958f35800000000, 0xf971936500000000,
+ 0x290b332200000000, 0x9922531f00000000, 0x89fe73ad00000000,
+ 0x39d7139000000000, 0xe9adb3d700000000, 0x5984d3ea00000000,
+ 0x8813836800000000, 0x383ae35500000000, 0xe840431200000000,
+ 0x5869232f00000000, 0x48b5039d00000000, 0xf89c63a000000000,
+ 0x28e6c3e700000000, 0x98cfa3da00000000, 0xcbcf133800000000,
+ 0x7be6730500000000, 0xab9cd34200000000, 0x1bb5b37f00000000,
+ 0x0b6993cd00000000, 0xbb40f3f000000000, 0x6b3a53b700000000,
+ 0xdb13338a00000000, 0x0a84630800000000, 0xbaad033500000000,
+ 0x6ad7a37200000000, 0xdafec34f00000000, 0xca22e3fd00000000,
+ 0x7a0b83c000000000, 0xaa71238700000000, 0x1a5843ba00000000,
+ 0x4d77329900000000, 0xfd5e52a400000000, 0x2d24f2e300000000,
+ 0x9d0d92de00000000, 0x8dd1b26c00000000, 0x3df8d25100000000,
+ 0xed82721600000000, 0x5dab122b00000000, 0x8c3c42a900000000,
+ 0x3c15229400000000, 0xec6f82d300000000, 0x5c46e2ee00000000,
+ 0x4c9ac25c00000000, 0xfcb3a26100000000, 0x2cc9022600000000,
+ 0x9ce0621b00000000, 0xcfe0d2f900000000, 0x7fc9b2c400000000,
+ 0xafb3128300000000, 0x1f9a72be00000000, 0x0f46520c00000000,
+ 0xbf6f323100000000, 0x6f15927600000000, 0xdf3cf24b00000000,
+ 0x0eaba2c900000000, 0xbe82c2f400000000, 0x6ef862b300000000,
+ 0xded1028e00000000, 0xce0d223c00000000, 0x7e24420100000000,
+ 0xae5ee24600000000, 0x1e77827b00000000, 0x92b0e6b100000000,
+ 0x2299868c00000000, 0xf2e326cb00000000, 0x42ca46f600000000,
+ 0x5216664400000000, 0xe23f067900000000, 0x3245a63e00000000,
+ 0x826cc60300000000, 0x53fb968100000000, 0xe3d2f6bc00000000,
+ 0x33a856fb00000000, 0x838136c600000000, 0x935d167400000000,
+ 0x2374764900000000, 0xf30ed60e00000000, 0x4327b63300000000,
+ 0x102706d100000000, 0xa00e66ec00000000, 0x7074c6ab00000000,
+ 0xc05da69600000000, 0xd081862400000000, 0x60a8e61900000000,
+ 0xb0d2465e00000000, 0x00fb266300000000, 0xd16c76e100000000,
+ 0x614516dc00000000, 0xb13fb69b00000000, 0x0116d6a600000000,
+ 0x11caf61400000000, 0xa1e3962900000000, 0x7199366e00000000,
+ 0xc1b0565300000000, 0x969f277000000000, 0x26b6474d00000000,
+ 0xf6cce70a00000000, 0x46e5873700000000, 0x5639a78500000000,
+ 0xe610c7b800000000, 0x366a67ff00000000, 0x864307c200000000,
+ 0x57d4574000000000, 0xe7fd377d00000000, 0x3787973a00000000,
+ 0x87aef70700000000, 0x9772d7b500000000, 0x275bb78800000000,
+ 0xf72117cf00000000, 0x470877f200000000, 0x1408c71000000000,
+ 0xa421a72d00000000, 0x745b076a00000000, 0xc472675700000000,
+ 0xd4ae47e500000000, 0x648727d800000000, 0xb4fd879f00000000,
+ 0x04d4e7a200000000, 0xd543b72000000000, 0x656ad71d00000000,
+ 0xb510775a00000000, 0x0539176700000000, 0x15e537d500000000,
+ 0xa5cc57e800000000, 0x75b6f7af00000000, 0xc59f979200000000,
+ 0xdbe815e900000000, 0x6bc175d400000000, 0xbbbbd59300000000,
+ 0x0b92b5ae00000000, 0x1b4e951c00000000, 0xab67f52100000000,
+ 0x7b1d556600000000, 0xcb34355b00000000, 0x1aa365d900000000,
+ 0xaa8a05e400000000, 0x7af0a5a300000000, 0xcad9c59e00000000,
+ 0xda05e52c00000000, 0x6a2c851100000000, 0xba56255600000000,
+ 0x0a7f456b00000000, 0x597ff58900000000, 0xe95695b400000000,
+ 0x392c35f300000000, 0x890555ce00000000, 0x99d9757c00000000,
+ 0x29f0154100000000, 0xf98ab50600000000, 0x49a3d53b00000000,
+ 0x983485b900000000, 0x281de58400000000, 0xf86745c300000000,
+ 0x484e25fe00000000, 0x5892054c00000000, 0xe8bb657100000000,
+ 0x38c1c53600000000, 0x88e8a50b00000000, 0xdfc7d42800000000,
+ 0x6feeb41500000000, 0xbf94145200000000, 0x0fbd746f00000000,
+ 0x1f6154dd00000000, 0xaf4834e000000000, 0x7f3294a700000000,
+ 0xcf1bf49a00000000, 0x1e8ca41800000000, 0xaea5c42500000000,
+ 0x7edf646200000000, 0xcef6045f00000000, 0xde2a24ed00000000,
+ 0x6e0344d000000000, 0xbe79e49700000000, 0x0e5084aa00000000,
+ 0x5d50344800000000, 0xed79547500000000, 0x3d03f43200000000,
+ 0x8d2a940f00000000, 0x9df6b4bd00000000, 0x2ddfd48000000000,
+ 0xfda574c700000000, 0x4d8c14fa00000000, 0x9c1b447800000000,
+ 0x2c32244500000000, 0xfc48840200000000, 0x4c61e43f00000000,
+ 0x5cbdc48d00000000, 0xec94a4b000000000, 0x3cee04f700000000,
+ 0x8cc764ca00000000},
+ {0x0000000000000000, 0xa5d35ccb00000000, 0x0ba1c84d00000000,
+ 0xae72948600000000, 0x1642919b00000000, 0xb391cd5000000000,
+ 0x1de359d600000000, 0xb830051d00000000, 0x6d8253ec00000000,
+ 0xc8510f2700000000, 0x66239ba100000000, 0xc3f0c76a00000000,
+ 0x7bc0c27700000000, 0xde139ebc00000000, 0x70610a3a00000000,
+ 0xd5b256f100000000, 0x9b02d60300000000, 0x3ed18ac800000000,
+ 0x90a31e4e00000000, 0x3570428500000000, 0x8d40479800000000,
+ 0x28931b5300000000, 0x86e18fd500000000, 0x2332d31e00000000,
+ 0xf68085ef00000000, 0x5353d92400000000, 0xfd214da200000000,
+ 0x58f2116900000000, 0xe0c2147400000000, 0x451148bf00000000,
+ 0xeb63dc3900000000, 0x4eb080f200000000, 0x3605ac0700000000,
+ 0x93d6f0cc00000000, 0x3da4644a00000000, 0x9877388100000000,
+ 0x20473d9c00000000, 0x8594615700000000, 0x2be6f5d100000000,
+ 0x8e35a91a00000000, 0x5b87ffeb00000000, 0xfe54a32000000000,
+ 0x502637a600000000, 0xf5f56b6d00000000, 0x4dc56e7000000000,
+ 0xe81632bb00000000, 0x4664a63d00000000, 0xe3b7faf600000000,
+ 0xad077a0400000000, 0x08d426cf00000000, 0xa6a6b24900000000,
+ 0x0375ee8200000000, 0xbb45eb9f00000000, 0x1e96b75400000000,
+ 0xb0e423d200000000, 0x15377f1900000000, 0xc08529e800000000,
+ 0x6556752300000000, 0xcb24e1a500000000, 0x6ef7bd6e00000000,
+ 0xd6c7b87300000000, 0x7314e4b800000000, 0xdd66703e00000000,
+ 0x78b52cf500000000, 0x6c0a580f00000000, 0xc9d904c400000000,
+ 0x67ab904200000000, 0xc278cc8900000000, 0x7a48c99400000000,
+ 0xdf9b955f00000000, 0x71e901d900000000, 0xd43a5d1200000000,
+ 0x01880be300000000, 0xa45b572800000000, 0x0a29c3ae00000000,
+ 0xaffa9f6500000000, 0x17ca9a7800000000, 0xb219c6b300000000,
+ 0x1c6b523500000000, 0xb9b80efe00000000, 0xf7088e0c00000000,
+ 0x52dbd2c700000000, 0xfca9464100000000, 0x597a1a8a00000000,
+ 0xe14a1f9700000000, 0x4499435c00000000, 0xeaebd7da00000000,
+ 0x4f388b1100000000, 0x9a8adde000000000, 0x3f59812b00000000,
+ 0x912b15ad00000000, 0x34f8496600000000, 0x8cc84c7b00000000,
+ 0x291b10b000000000, 0x8769843600000000, 0x22bad8fd00000000,
+ 0x5a0ff40800000000, 0xffdca8c300000000, 0x51ae3c4500000000,
+ 0xf47d608e00000000, 0x4c4d659300000000, 0xe99e395800000000,
+ 0x47ecadde00000000, 0xe23ff11500000000, 0x378da7e400000000,
+ 0x925efb2f00000000, 0x3c2c6fa900000000, 0x99ff336200000000,
+ 0x21cf367f00000000, 0x841c6ab400000000, 0x2a6efe3200000000,
+ 0x8fbda2f900000000, 0xc10d220b00000000, 0x64de7ec000000000,
+ 0xcaacea4600000000, 0x6f7fb68d00000000, 0xd74fb39000000000,
+ 0x729cef5b00000000, 0xdcee7bdd00000000, 0x793d271600000000,
+ 0xac8f71e700000000, 0x095c2d2c00000000, 0xa72eb9aa00000000,
+ 0x02fde56100000000, 0xbacde07c00000000, 0x1f1ebcb700000000,
+ 0xb16c283100000000, 0x14bf74fa00000000, 0xd814b01e00000000,
+ 0x7dc7ecd500000000, 0xd3b5785300000000, 0x7666249800000000,
+ 0xce56218500000000, 0x6b857d4e00000000, 0xc5f7e9c800000000,
+ 0x6024b50300000000, 0xb596e3f200000000, 0x1045bf3900000000,
+ 0xbe372bbf00000000, 0x1be4777400000000, 0xa3d4726900000000,
+ 0x06072ea200000000, 0xa875ba2400000000, 0x0da6e6ef00000000,
+ 0x4316661d00000000, 0xe6c53ad600000000, 0x48b7ae5000000000,
+ 0xed64f29b00000000, 0x5554f78600000000, 0xf087ab4d00000000,
+ 0x5ef53fcb00000000, 0xfb26630000000000, 0x2e9435f100000000,
+ 0x8b47693a00000000, 0x2535fdbc00000000, 0x80e6a17700000000,
+ 0x38d6a46a00000000, 0x9d05f8a100000000, 0x33776c2700000000,
+ 0x96a430ec00000000, 0xee111c1900000000, 0x4bc240d200000000,
+ 0xe5b0d45400000000, 0x4063889f00000000, 0xf8538d8200000000,
+ 0x5d80d14900000000, 0xf3f245cf00000000, 0x5621190400000000,
+ 0x83934ff500000000, 0x2640133e00000000, 0x883287b800000000,
+ 0x2de1db7300000000, 0x95d1de6e00000000, 0x300282a500000000,
+ 0x9e70162300000000, 0x3ba34ae800000000, 0x7513ca1a00000000,
+ 0xd0c096d100000000, 0x7eb2025700000000, 0xdb615e9c00000000,
+ 0x63515b8100000000, 0xc682074a00000000, 0x68f093cc00000000,
+ 0xcd23cf0700000000, 0x189199f600000000, 0xbd42c53d00000000,
+ 0x133051bb00000000, 0xb6e30d7000000000, 0x0ed3086d00000000,
+ 0xab0054a600000000, 0x0572c02000000000, 0xa0a19ceb00000000,
+ 0xb41ee81100000000, 0x11cdb4da00000000, 0xbfbf205c00000000,
+ 0x1a6c7c9700000000, 0xa25c798a00000000, 0x078f254100000000,
+ 0xa9fdb1c700000000, 0x0c2eed0c00000000, 0xd99cbbfd00000000,
+ 0x7c4fe73600000000, 0xd23d73b000000000, 0x77ee2f7b00000000,
+ 0xcfde2a6600000000, 0x6a0d76ad00000000, 0xc47fe22b00000000,
+ 0x61acbee000000000, 0x2f1c3e1200000000, 0x8acf62d900000000,
+ 0x24bdf65f00000000, 0x816eaa9400000000, 0x395eaf8900000000,
+ 0x9c8df34200000000, 0x32ff67c400000000, 0x972c3b0f00000000,
+ 0x429e6dfe00000000, 0xe74d313500000000, 0x493fa5b300000000,
+ 0xececf97800000000, 0x54dcfc6500000000, 0xf10fa0ae00000000,
+ 0x5f7d342800000000, 0xfaae68e300000000, 0x821b441600000000,
+ 0x27c818dd00000000, 0x89ba8c5b00000000, 0x2c69d09000000000,
+ 0x9459d58d00000000, 0x318a894600000000, 0x9ff81dc000000000,
+ 0x3a2b410b00000000, 0xef9917fa00000000, 0x4a4a4b3100000000,
+ 0xe438dfb700000000, 0x41eb837c00000000, 0xf9db866100000000,
+ 0x5c08daaa00000000, 0xf27a4e2c00000000, 0x57a912e700000000,
+ 0x1919921500000000, 0xbccacede00000000, 0x12b85a5800000000,
+ 0xb76b069300000000, 0x0f5b038e00000000, 0xaa885f4500000000,
+ 0x04facbc300000000, 0xa129970800000000, 0x749bc1f900000000,
+ 0xd1489d3200000000, 0x7f3a09b400000000, 0xdae9557f00000000,
+ 0x62d9506200000000, 0xc70a0ca900000000, 0x6978982f00000000,
+ 0xccabc4e400000000},
+ {0x0000000000000000, 0xb40b77a600000000, 0x29119f9700000000,
+ 0x9d1ae83100000000, 0x13244ff400000000, 0xa72f385200000000,
+ 0x3a35d06300000000, 0x8e3ea7c500000000, 0x674eef3300000000,
+ 0xd345989500000000, 0x4e5f70a400000000, 0xfa54070200000000,
+ 0x746aa0c700000000, 0xc061d76100000000, 0x5d7b3f5000000000,
+ 0xe97048f600000000, 0xce9cde6700000000, 0x7a97a9c100000000,
+ 0xe78d41f000000000, 0x5386365600000000, 0xddb8919300000000,
+ 0x69b3e63500000000, 0xf4a90e0400000000, 0x40a279a200000000,
+ 0xa9d2315400000000, 0x1dd946f200000000, 0x80c3aec300000000,
+ 0x34c8d96500000000, 0xbaf67ea000000000, 0x0efd090600000000,
+ 0x93e7e13700000000, 0x27ec969100000000, 0x9c39bdcf00000000,
+ 0x2832ca6900000000, 0xb528225800000000, 0x012355fe00000000,
+ 0x8f1df23b00000000, 0x3b16859d00000000, 0xa60c6dac00000000,
+ 0x12071a0a00000000, 0xfb7752fc00000000, 0x4f7c255a00000000,
+ 0xd266cd6b00000000, 0x666dbacd00000000, 0xe8531d0800000000,
+ 0x5c586aae00000000, 0xc142829f00000000, 0x7549f53900000000,
+ 0x52a563a800000000, 0xe6ae140e00000000, 0x7bb4fc3f00000000,
+ 0xcfbf8b9900000000, 0x41812c5c00000000, 0xf58a5bfa00000000,
+ 0x6890b3cb00000000, 0xdc9bc46d00000000, 0x35eb8c9b00000000,
+ 0x81e0fb3d00000000, 0x1cfa130c00000000, 0xa8f164aa00000000,
+ 0x26cfc36f00000000, 0x92c4b4c900000000, 0x0fde5cf800000000,
+ 0xbbd52b5e00000000, 0x79750b4400000000, 0xcd7e7ce200000000,
+ 0x506494d300000000, 0xe46fe37500000000, 0x6a5144b000000000,
+ 0xde5a331600000000, 0x4340db2700000000, 0xf74bac8100000000,
+ 0x1e3be47700000000, 0xaa3093d100000000, 0x372a7be000000000,
+ 0x83210c4600000000, 0x0d1fab8300000000, 0xb914dc2500000000,
+ 0x240e341400000000, 0x900543b200000000, 0xb7e9d52300000000,
+ 0x03e2a28500000000, 0x9ef84ab400000000, 0x2af33d1200000000,
+ 0xa4cd9ad700000000, 0x10c6ed7100000000, 0x8ddc054000000000,
+ 0x39d772e600000000, 0xd0a73a1000000000, 0x64ac4db600000000,
+ 0xf9b6a58700000000, 0x4dbdd22100000000, 0xc38375e400000000,
+ 0x7788024200000000, 0xea92ea7300000000, 0x5e999dd500000000,
+ 0xe54cb68b00000000, 0x5147c12d00000000, 0xcc5d291c00000000,
+ 0x78565eba00000000, 0xf668f97f00000000, 0x42638ed900000000,
+ 0xdf7966e800000000, 0x6b72114e00000000, 0x820259b800000000,
+ 0x36092e1e00000000, 0xab13c62f00000000, 0x1f18b18900000000,
+ 0x9126164c00000000, 0x252d61ea00000000, 0xb83789db00000000,
+ 0x0c3cfe7d00000000, 0x2bd068ec00000000, 0x9fdb1f4a00000000,
+ 0x02c1f77b00000000, 0xb6ca80dd00000000, 0x38f4271800000000,
+ 0x8cff50be00000000, 0x11e5b88f00000000, 0xa5eecf2900000000,
+ 0x4c9e87df00000000, 0xf895f07900000000, 0x658f184800000000,
+ 0xd1846fee00000000, 0x5fbac82b00000000, 0xebb1bf8d00000000,
+ 0x76ab57bc00000000, 0xc2a0201a00000000, 0xf2ea168800000000,
+ 0x46e1612e00000000, 0xdbfb891f00000000, 0x6ff0feb900000000,
+ 0xe1ce597c00000000, 0x55c52eda00000000, 0xc8dfc6eb00000000,
+ 0x7cd4b14d00000000, 0x95a4f9bb00000000, 0x21af8e1d00000000,
+ 0xbcb5662c00000000, 0x08be118a00000000, 0x8680b64f00000000,
+ 0x328bc1e900000000, 0xaf9129d800000000, 0x1b9a5e7e00000000,
+ 0x3c76c8ef00000000, 0x887dbf4900000000, 0x1567577800000000,
+ 0xa16c20de00000000, 0x2f52871b00000000, 0x9b59f0bd00000000,
+ 0x0643188c00000000, 0xb2486f2a00000000, 0x5b3827dc00000000,
+ 0xef33507a00000000, 0x7229b84b00000000, 0xc622cfed00000000,
+ 0x481c682800000000, 0xfc171f8e00000000, 0x610df7bf00000000,
+ 0xd506801900000000, 0x6ed3ab4700000000, 0xdad8dce100000000,
+ 0x47c234d000000000, 0xf3c9437600000000, 0x7df7e4b300000000,
+ 0xc9fc931500000000, 0x54e67b2400000000, 0xe0ed0c8200000000,
+ 0x099d447400000000, 0xbd9633d200000000, 0x208cdbe300000000,
+ 0x9487ac4500000000, 0x1ab90b8000000000, 0xaeb27c2600000000,
+ 0x33a8941700000000, 0x87a3e3b100000000, 0xa04f752000000000,
+ 0x1444028600000000, 0x895eeab700000000, 0x3d559d1100000000,
+ 0xb36b3ad400000000, 0x07604d7200000000, 0x9a7aa54300000000,
+ 0x2e71d2e500000000, 0xc7019a1300000000, 0x730aedb500000000,
+ 0xee10058400000000, 0x5a1b722200000000, 0xd425d5e700000000,
+ 0x602ea24100000000, 0xfd344a7000000000, 0x493f3dd600000000,
+ 0x8b9f1dcc00000000, 0x3f946a6a00000000, 0xa28e825b00000000,
+ 0x1685f5fd00000000, 0x98bb523800000000, 0x2cb0259e00000000,
+ 0xb1aacdaf00000000, 0x05a1ba0900000000, 0xecd1f2ff00000000,
+ 0x58da855900000000, 0xc5c06d6800000000, 0x71cb1ace00000000,
+ 0xfff5bd0b00000000, 0x4bfecaad00000000, 0xd6e4229c00000000,
+ 0x62ef553a00000000, 0x4503c3ab00000000, 0xf108b40d00000000,
+ 0x6c125c3c00000000, 0xd8192b9a00000000, 0x56278c5f00000000,
+ 0xe22cfbf900000000, 0x7f3613c800000000, 0xcb3d646e00000000,
+ 0x224d2c9800000000, 0x96465b3e00000000, 0x0b5cb30f00000000,
+ 0xbf57c4a900000000, 0x3169636c00000000, 0x856214ca00000000,
+ 0x1878fcfb00000000, 0xac738b5d00000000, 0x17a6a00300000000,
+ 0xa3add7a500000000, 0x3eb73f9400000000, 0x8abc483200000000,
+ 0x0482eff700000000, 0xb089985100000000, 0x2d93706000000000,
+ 0x999807c600000000, 0x70e84f3000000000, 0xc4e3389600000000,
+ 0x59f9d0a700000000, 0xedf2a70100000000, 0x63cc00c400000000,
+ 0xd7c7776200000000, 0x4add9f5300000000, 0xfed6e8f500000000,
+ 0xd93a7e6400000000, 0x6d3109c200000000, 0xf02be1f300000000,
+ 0x4420965500000000, 0xca1e319000000000, 0x7e15463600000000,
+ 0xe30fae0700000000, 0x5704d9a100000000, 0xbe74915700000000,
+ 0x0a7fe6f100000000, 0x97650ec000000000, 0x236e796600000000,
+ 0xad50dea300000000, 0x195ba90500000000, 0x8441413400000000,
+ 0x304a369200000000},
+ {0x0000000000000000, 0x9e00aacc00000000, 0x7d07254200000000,
+ 0xe3078f8e00000000, 0xfa0e4a8400000000, 0x640ee04800000000,
+ 0x87096fc600000000, 0x1909c50a00000000, 0xb51be5d300000000,
+ 0x2b1b4f1f00000000, 0xc81cc09100000000, 0x561c6a5d00000000,
+ 0x4f15af5700000000, 0xd115059b00000000, 0x32128a1500000000,
+ 0xac1220d900000000, 0x2b31bb7c00000000, 0xb53111b000000000,
+ 0x56369e3e00000000, 0xc83634f200000000, 0xd13ff1f800000000,
+ 0x4f3f5b3400000000, 0xac38d4ba00000000, 0x32387e7600000000,
+ 0x9e2a5eaf00000000, 0x002af46300000000, 0xe32d7bed00000000,
+ 0x7d2dd12100000000, 0x6424142b00000000, 0xfa24bee700000000,
+ 0x1923316900000000, 0x87239ba500000000, 0x566276f900000000,
+ 0xc862dc3500000000, 0x2b6553bb00000000, 0xb565f97700000000,
+ 0xac6c3c7d00000000, 0x326c96b100000000, 0xd16b193f00000000,
+ 0x4f6bb3f300000000, 0xe379932a00000000, 0x7d7939e600000000,
+ 0x9e7eb66800000000, 0x007e1ca400000000, 0x1977d9ae00000000,
+ 0x8777736200000000, 0x6470fcec00000000, 0xfa70562000000000,
+ 0x7d53cd8500000000, 0xe353674900000000, 0x0054e8c700000000,
+ 0x9e54420b00000000, 0x875d870100000000, 0x195d2dcd00000000,
+ 0xfa5aa24300000000, 0x645a088f00000000, 0xc848285600000000,
+ 0x5648829a00000000, 0xb54f0d1400000000, 0x2b4fa7d800000000,
+ 0x324662d200000000, 0xac46c81e00000000, 0x4f41479000000000,
+ 0xd141ed5c00000000, 0xedc29d2900000000, 0x73c237e500000000,
+ 0x90c5b86b00000000, 0x0ec512a700000000, 0x17ccd7ad00000000,
+ 0x89cc7d6100000000, 0x6acbf2ef00000000, 0xf4cb582300000000,
+ 0x58d978fa00000000, 0xc6d9d23600000000, 0x25de5db800000000,
+ 0xbbdef77400000000, 0xa2d7327e00000000, 0x3cd798b200000000,
+ 0xdfd0173c00000000, 0x41d0bdf000000000, 0xc6f3265500000000,
+ 0x58f38c9900000000, 0xbbf4031700000000, 0x25f4a9db00000000,
+ 0x3cfd6cd100000000, 0xa2fdc61d00000000, 0x41fa499300000000,
+ 0xdffae35f00000000, 0x73e8c38600000000, 0xede8694a00000000,
+ 0x0eefe6c400000000, 0x90ef4c0800000000, 0x89e6890200000000,
+ 0x17e623ce00000000, 0xf4e1ac4000000000, 0x6ae1068c00000000,
+ 0xbba0ebd000000000, 0x25a0411c00000000, 0xc6a7ce9200000000,
+ 0x58a7645e00000000, 0x41aea15400000000, 0xdfae0b9800000000,
+ 0x3ca9841600000000, 0xa2a92eda00000000, 0x0ebb0e0300000000,
+ 0x90bba4cf00000000, 0x73bc2b4100000000, 0xedbc818d00000000,
+ 0xf4b5448700000000, 0x6ab5ee4b00000000, 0x89b261c500000000,
+ 0x17b2cb0900000000, 0x909150ac00000000, 0x0e91fa6000000000,
+ 0xed9675ee00000000, 0x7396df2200000000, 0x6a9f1a2800000000,
+ 0xf49fb0e400000000, 0x17983f6a00000000, 0x899895a600000000,
+ 0x258ab57f00000000, 0xbb8a1fb300000000, 0x588d903d00000000,
+ 0xc68d3af100000000, 0xdf84fffb00000000, 0x4184553700000000,
+ 0xa283dab900000000, 0x3c83707500000000, 0xda853b5300000000,
+ 0x4485919f00000000, 0xa7821e1100000000, 0x3982b4dd00000000,
+ 0x208b71d700000000, 0xbe8bdb1b00000000, 0x5d8c549500000000,
+ 0xc38cfe5900000000, 0x6f9ede8000000000, 0xf19e744c00000000,
+ 0x1299fbc200000000, 0x8c99510e00000000, 0x9590940400000000,
+ 0x0b903ec800000000, 0xe897b14600000000, 0x76971b8a00000000,
+ 0xf1b4802f00000000, 0x6fb42ae300000000, 0x8cb3a56d00000000,
+ 0x12b30fa100000000, 0x0bbacaab00000000, 0x95ba606700000000,
+ 0x76bdefe900000000, 0xe8bd452500000000, 0x44af65fc00000000,
+ 0xdaafcf3000000000, 0x39a840be00000000, 0xa7a8ea7200000000,
+ 0xbea12f7800000000, 0x20a185b400000000, 0xc3a60a3a00000000,
+ 0x5da6a0f600000000, 0x8ce74daa00000000, 0x12e7e76600000000,
+ 0xf1e068e800000000, 0x6fe0c22400000000, 0x76e9072e00000000,
+ 0xe8e9ade200000000, 0x0bee226c00000000, 0x95ee88a000000000,
+ 0x39fca87900000000, 0xa7fc02b500000000, 0x44fb8d3b00000000,
+ 0xdafb27f700000000, 0xc3f2e2fd00000000, 0x5df2483100000000,
+ 0xbef5c7bf00000000, 0x20f56d7300000000, 0xa7d6f6d600000000,
+ 0x39d65c1a00000000, 0xdad1d39400000000, 0x44d1795800000000,
+ 0x5dd8bc5200000000, 0xc3d8169e00000000, 0x20df991000000000,
+ 0xbedf33dc00000000, 0x12cd130500000000, 0x8ccdb9c900000000,
+ 0x6fca364700000000, 0xf1ca9c8b00000000, 0xe8c3598100000000,
+ 0x76c3f34d00000000, 0x95c47cc300000000, 0x0bc4d60f00000000,
+ 0x3747a67a00000000, 0xa9470cb600000000, 0x4a40833800000000,
+ 0xd44029f400000000, 0xcd49ecfe00000000, 0x5349463200000000,
+ 0xb04ec9bc00000000, 0x2e4e637000000000, 0x825c43a900000000,
+ 0x1c5ce96500000000, 0xff5b66eb00000000, 0x615bcc2700000000,
+ 0x7852092d00000000, 0xe652a3e100000000, 0x05552c6f00000000,
+ 0x9b5586a300000000, 0x1c761d0600000000, 0x8276b7ca00000000,
+ 0x6171384400000000, 0xff71928800000000, 0xe678578200000000,
+ 0x7878fd4e00000000, 0x9b7f72c000000000, 0x057fd80c00000000,
+ 0xa96df8d500000000, 0x376d521900000000, 0xd46add9700000000,
+ 0x4a6a775b00000000, 0x5363b25100000000, 0xcd63189d00000000,
+ 0x2e64971300000000, 0xb0643ddf00000000, 0x6125d08300000000,
+ 0xff257a4f00000000, 0x1c22f5c100000000, 0x82225f0d00000000,
+ 0x9b2b9a0700000000, 0x052b30cb00000000, 0xe62cbf4500000000,
+ 0x782c158900000000, 0xd43e355000000000, 0x4a3e9f9c00000000,
+ 0xa939101200000000, 0x3739bade00000000, 0x2e307fd400000000,
+ 0xb030d51800000000, 0x53375a9600000000, 0xcd37f05a00000000,
+ 0x4a146bff00000000, 0xd414c13300000000, 0x37134ebd00000000,
+ 0xa913e47100000000, 0xb01a217b00000000, 0x2e1a8bb700000000,
+ 0xcd1d043900000000, 0x531daef500000000, 0xff0f8e2c00000000,
+ 0x610f24e000000000, 0x8208ab6e00000000, 0x1c0801a200000000,
+ 0x0501c4a800000000, 0x9b016e6400000000, 0x7806e1ea00000000,
+ 0xe6064b2600000000}};
+
+#else /* W == 4 */
+
+local const z_crc_t FAR crc_braid_table[][256] = {
+ {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757,
+ 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a,
+ 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733,
+ 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871,
+ 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70,
+ 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42,
+ 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5,
+ 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787,
+ 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086,
+ 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4,
+ 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d,
+ 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0,
+ 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d,
+ 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f,
+ 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859,
+ 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b,
+ 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5,
+ 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028,
+ 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891,
+ 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed,
+ 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec,
+ 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde,
+ 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817,
+ 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825,
+ 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24,
+ 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e,
+ 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7,
+ 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a,
+ 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4,
+ 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196,
+ 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0,
+ 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2,
+ 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52,
+ 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f,
+ 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36,
+ 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174,
+ 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675,
+ 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647,
+ 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d,
+ 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf,
+ 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be,
+ 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc,
+ 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645,
+ 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98,
+ 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138,
+ 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a,
+ 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c,
+ 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e,
+ 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0,
+ 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d,
+ 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194,
+ 0xde0506f1},
+ {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc,
+ 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f,
+ 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a,
+ 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29,
+ 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8,
+ 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023,
+ 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e,
+ 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065,
+ 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84,
+ 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7,
+ 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922,
+ 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71,
+ 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0,
+ 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b,
+ 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816,
+ 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd,
+ 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c,
+ 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f,
+ 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba,
+ 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579,
+ 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98,
+ 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873,
+ 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e,
+ 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5,
+ 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134,
+ 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7,
+ 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732,
+ 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461,
+ 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0,
+ 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b,
+ 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26,
+ 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd,
+ 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc,
+ 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef,
+ 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a,
+ 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049,
+ 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8,
+ 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43,
+ 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e,
+ 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5,
+ 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24,
+ 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07,
+ 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982,
+ 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1,
+ 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0,
+ 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b,
+ 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576,
+ 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d,
+ 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c,
+ 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f,
+ 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda,
+ 0xbe9834ed},
+ {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504,
+ 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49,
+ 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e,
+ 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192,
+ 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859,
+ 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c,
+ 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620,
+ 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265,
+ 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae,
+ 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2,
+ 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175,
+ 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38,
+ 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05,
+ 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40,
+ 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f,
+ 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca,
+ 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850,
+ 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d,
+ 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da,
+ 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864,
+ 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af,
+ 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea,
+ 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74,
+ 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31,
+ 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa,
+ 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a,
+ 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd,
+ 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180,
+ 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a,
+ 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f,
+ 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290,
+ 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5,
+ 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed,
+ 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0,
+ 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167,
+ 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b,
+ 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0,
+ 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5,
+ 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc,
+ 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189,
+ 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842,
+ 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e,
+ 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299,
+ 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4,
+ 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec,
+ 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9,
+ 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66,
+ 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23,
+ 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9,
+ 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4,
+ 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33,
+ 0x9324fd72},
+ {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d}};
+
+local const z_word_t FAR crc_braid_big_table[][256] = {
+ {0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07,
+ 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79,
+ 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7,
+ 0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84,
+ 0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13,
+ 0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663,
+ 0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5,
+ 0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5,
+ 0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832,
+ 0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51,
+ 0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf,
+ 0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1,
+ 0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76,
+ 0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606,
+ 0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996,
+ 0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6,
+ 0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c,
+ 0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712,
+ 0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c,
+ 0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4,
+ 0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943,
+ 0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333,
+ 0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe,
+ 0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce,
+ 0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359,
+ 0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a,
+ 0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04,
+ 0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a,
+ 0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0,
+ 0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580,
+ 0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10,
+ 0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060,
+ 0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1,
+ 0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf,
+ 0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31,
+ 0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852,
+ 0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5,
+ 0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5,
+ 0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75,
+ 0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005,
+ 0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292,
+ 0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1,
+ 0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f,
+ 0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111,
+ 0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0,
+ 0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0,
+ 0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40,
+ 0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530,
+ 0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba,
+ 0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4,
+ 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a,
+ 0x8def022d},
+ {0x00000000, 0x41311b19, 0x82623632, 0xc3532d2b, 0x04c56c64,
+ 0x45f4777d, 0x86a75a56, 0xc796414f, 0x088ad9c8, 0x49bbc2d1,
+ 0x8ae8effa, 0xcbd9f4e3, 0x0c4fb5ac, 0x4d7eaeb5, 0x8e2d839e,
+ 0xcf1c9887, 0x5112c24a, 0x1023d953, 0xd370f478, 0x9241ef61,
+ 0x55d7ae2e, 0x14e6b537, 0xd7b5981c, 0x96848305, 0x59981b82,
+ 0x18a9009b, 0xdbfa2db0, 0x9acb36a9, 0x5d5d77e6, 0x1c6c6cff,
+ 0xdf3f41d4, 0x9e0e5acd, 0xa2248495, 0xe3159f8c, 0x2046b2a7,
+ 0x6177a9be, 0xa6e1e8f1, 0xe7d0f3e8, 0x2483dec3, 0x65b2c5da,
+ 0xaaae5d5d, 0xeb9f4644, 0x28cc6b6f, 0x69fd7076, 0xae6b3139,
+ 0xef5a2a20, 0x2c09070b, 0x6d381c12, 0xf33646df, 0xb2075dc6,
+ 0x715470ed, 0x30656bf4, 0xf7f32abb, 0xb6c231a2, 0x75911c89,
+ 0x34a00790, 0xfbbc9f17, 0xba8d840e, 0x79dea925, 0x38efb23c,
+ 0xff79f373, 0xbe48e86a, 0x7d1bc541, 0x3c2ade58, 0x054f79f0,
+ 0x447e62e9, 0x872d4fc2, 0xc61c54db, 0x018a1594, 0x40bb0e8d,
+ 0x83e823a6, 0xc2d938bf, 0x0dc5a038, 0x4cf4bb21, 0x8fa7960a,
+ 0xce968d13, 0x0900cc5c, 0x4831d745, 0x8b62fa6e, 0xca53e177,
+ 0x545dbbba, 0x156ca0a3, 0xd63f8d88, 0x970e9691, 0x5098d7de,
+ 0x11a9ccc7, 0xd2fae1ec, 0x93cbfaf5, 0x5cd76272, 0x1de6796b,
+ 0xdeb55440, 0x9f844f59, 0x58120e16, 0x1923150f, 0xda703824,
+ 0x9b41233d, 0xa76bfd65, 0xe65ae67c, 0x2509cb57, 0x6438d04e,
+ 0xa3ae9101, 0xe29f8a18, 0x21cca733, 0x60fdbc2a, 0xafe124ad,
+ 0xeed03fb4, 0x2d83129f, 0x6cb20986, 0xab2448c9, 0xea1553d0,
+ 0x29467efb, 0x687765e2, 0xf6793f2f, 0xb7482436, 0x741b091d,
+ 0x352a1204, 0xf2bc534b, 0xb38d4852, 0x70de6579, 0x31ef7e60,
+ 0xfef3e6e7, 0xbfc2fdfe, 0x7c91d0d5, 0x3da0cbcc, 0xfa368a83,
+ 0xbb07919a, 0x7854bcb1, 0x3965a7a8, 0x4b98833b, 0x0aa99822,
+ 0xc9fab509, 0x88cbae10, 0x4f5def5f, 0x0e6cf446, 0xcd3fd96d,
+ 0x8c0ec274, 0x43125af3, 0x022341ea, 0xc1706cc1, 0x804177d8,
+ 0x47d73697, 0x06e62d8e, 0xc5b500a5, 0x84841bbc, 0x1a8a4171,
+ 0x5bbb5a68, 0x98e87743, 0xd9d96c5a, 0x1e4f2d15, 0x5f7e360c,
+ 0x9c2d1b27, 0xdd1c003e, 0x120098b9, 0x533183a0, 0x9062ae8b,
+ 0xd153b592, 0x16c5f4dd, 0x57f4efc4, 0x94a7c2ef, 0xd596d9f6,
+ 0xe9bc07ae, 0xa88d1cb7, 0x6bde319c, 0x2aef2a85, 0xed796bca,
+ 0xac4870d3, 0x6f1b5df8, 0x2e2a46e1, 0xe136de66, 0xa007c57f,
+ 0x6354e854, 0x2265f34d, 0xe5f3b202, 0xa4c2a91b, 0x67918430,
+ 0x26a09f29, 0xb8aec5e4, 0xf99fdefd, 0x3accf3d6, 0x7bfde8cf,
+ 0xbc6ba980, 0xfd5ab299, 0x3e099fb2, 0x7f3884ab, 0xb0241c2c,
+ 0xf1150735, 0x32462a1e, 0x73773107, 0xb4e17048, 0xf5d06b51,
+ 0x3683467a, 0x77b25d63, 0x4ed7facb, 0x0fe6e1d2, 0xccb5ccf9,
+ 0x8d84d7e0, 0x4a1296af, 0x0b238db6, 0xc870a09d, 0x8941bb84,
+ 0x465d2303, 0x076c381a, 0xc43f1531, 0x850e0e28, 0x42984f67,
+ 0x03a9547e, 0xc0fa7955, 0x81cb624c, 0x1fc53881, 0x5ef42398,
+ 0x9da70eb3, 0xdc9615aa, 0x1b0054e5, 0x5a314ffc, 0x996262d7,
+ 0xd85379ce, 0x174fe149, 0x567efa50, 0x952dd77b, 0xd41ccc62,
+ 0x138a8d2d, 0x52bb9634, 0x91e8bb1f, 0xd0d9a006, 0xecf37e5e,
+ 0xadc26547, 0x6e91486c, 0x2fa05375, 0xe836123a, 0xa9070923,
+ 0x6a542408, 0x2b653f11, 0xe479a796, 0xa548bc8f, 0x661b91a4,
+ 0x272a8abd, 0xe0bccbf2, 0xa18dd0eb, 0x62defdc0, 0x23efe6d9,
+ 0xbde1bc14, 0xfcd0a70d, 0x3f838a26, 0x7eb2913f, 0xb924d070,
+ 0xf815cb69, 0x3b46e642, 0x7a77fd5b, 0xb56b65dc, 0xf45a7ec5,
+ 0x370953ee, 0x763848f7, 0xb1ae09b8, 0xf09f12a1, 0x33cc3f8a,
+ 0x72fd2493},
+ {0x00000000, 0x376ac201, 0x6ed48403, 0x59be4602, 0xdca80907,
+ 0xebc2cb06, 0xb27c8d04, 0x85164f05, 0xb851130e, 0x8f3bd10f,
+ 0xd685970d, 0xe1ef550c, 0x64f91a09, 0x5393d808, 0x0a2d9e0a,
+ 0x3d475c0b, 0x70a3261c, 0x47c9e41d, 0x1e77a21f, 0x291d601e,
+ 0xac0b2f1b, 0x9b61ed1a, 0xc2dfab18, 0xf5b56919, 0xc8f23512,
+ 0xff98f713, 0xa626b111, 0x914c7310, 0x145a3c15, 0x2330fe14,
+ 0x7a8eb816, 0x4de47a17, 0xe0464d38, 0xd72c8f39, 0x8e92c93b,
+ 0xb9f80b3a, 0x3cee443f, 0x0b84863e, 0x523ac03c, 0x6550023d,
+ 0x58175e36, 0x6f7d9c37, 0x36c3da35, 0x01a91834, 0x84bf5731,
+ 0xb3d59530, 0xea6bd332, 0xdd011133, 0x90e56b24, 0xa78fa925,
+ 0xfe31ef27, 0xc95b2d26, 0x4c4d6223, 0x7b27a022, 0x2299e620,
+ 0x15f32421, 0x28b4782a, 0x1fdeba2b, 0x4660fc29, 0x710a3e28,
+ 0xf41c712d, 0xc376b32c, 0x9ac8f52e, 0xada2372f, 0xc08d9a70,
+ 0xf7e75871, 0xae591e73, 0x9933dc72, 0x1c259377, 0x2b4f5176,
+ 0x72f11774, 0x459bd575, 0x78dc897e, 0x4fb64b7f, 0x16080d7d,
+ 0x2162cf7c, 0xa4748079, 0x931e4278, 0xcaa0047a, 0xfdcac67b,
+ 0xb02ebc6c, 0x87447e6d, 0xdefa386f, 0xe990fa6e, 0x6c86b56b,
+ 0x5bec776a, 0x02523168, 0x3538f369, 0x087faf62, 0x3f156d63,
+ 0x66ab2b61, 0x51c1e960, 0xd4d7a665, 0xe3bd6464, 0xba032266,
+ 0x8d69e067, 0x20cbd748, 0x17a11549, 0x4e1f534b, 0x7975914a,
+ 0xfc63de4f, 0xcb091c4e, 0x92b75a4c, 0xa5dd984d, 0x989ac446,
+ 0xaff00647, 0xf64e4045, 0xc1248244, 0x4432cd41, 0x73580f40,
+ 0x2ae64942, 0x1d8c8b43, 0x5068f154, 0x67023355, 0x3ebc7557,
+ 0x09d6b756, 0x8cc0f853, 0xbbaa3a52, 0xe2147c50, 0xd57ebe51,
+ 0xe839e25a, 0xdf53205b, 0x86ed6659, 0xb187a458, 0x3491eb5d,
+ 0x03fb295c, 0x5a456f5e, 0x6d2fad5f, 0x801b35e1, 0xb771f7e0,
+ 0xeecfb1e2, 0xd9a573e3, 0x5cb33ce6, 0x6bd9fee7, 0x3267b8e5,
+ 0x050d7ae4, 0x384a26ef, 0x0f20e4ee, 0x569ea2ec, 0x61f460ed,
+ 0xe4e22fe8, 0xd388ede9, 0x8a36abeb, 0xbd5c69ea, 0xf0b813fd,
+ 0xc7d2d1fc, 0x9e6c97fe, 0xa90655ff, 0x2c101afa, 0x1b7ad8fb,
+ 0x42c49ef9, 0x75ae5cf8, 0x48e900f3, 0x7f83c2f2, 0x263d84f0,
+ 0x115746f1, 0x944109f4, 0xa32bcbf5, 0xfa958df7, 0xcdff4ff6,
+ 0x605d78d9, 0x5737bad8, 0x0e89fcda, 0x39e33edb, 0xbcf571de,
+ 0x8b9fb3df, 0xd221f5dd, 0xe54b37dc, 0xd80c6bd7, 0xef66a9d6,
+ 0xb6d8efd4, 0x81b22dd5, 0x04a462d0, 0x33cea0d1, 0x6a70e6d3,
+ 0x5d1a24d2, 0x10fe5ec5, 0x27949cc4, 0x7e2adac6, 0x494018c7,
+ 0xcc5657c2, 0xfb3c95c3, 0xa282d3c1, 0x95e811c0, 0xa8af4dcb,
+ 0x9fc58fca, 0xc67bc9c8, 0xf1110bc9, 0x740744cc, 0x436d86cd,
+ 0x1ad3c0cf, 0x2db902ce, 0x4096af91, 0x77fc6d90, 0x2e422b92,
+ 0x1928e993, 0x9c3ea696, 0xab546497, 0xf2ea2295, 0xc580e094,
+ 0xf8c7bc9f, 0xcfad7e9e, 0x9613389c, 0xa179fa9d, 0x246fb598,
+ 0x13057799, 0x4abb319b, 0x7dd1f39a, 0x3035898d, 0x075f4b8c,
+ 0x5ee10d8e, 0x698bcf8f, 0xec9d808a, 0xdbf7428b, 0x82490489,
+ 0xb523c688, 0x88649a83, 0xbf0e5882, 0xe6b01e80, 0xd1dadc81,
+ 0x54cc9384, 0x63a65185, 0x3a181787, 0x0d72d586, 0xa0d0e2a9,
+ 0x97ba20a8, 0xce0466aa, 0xf96ea4ab, 0x7c78ebae, 0x4b1229af,
+ 0x12ac6fad, 0x25c6adac, 0x1881f1a7, 0x2feb33a6, 0x765575a4,
+ 0x413fb7a5, 0xc429f8a0, 0xf3433aa1, 0xaafd7ca3, 0x9d97bea2,
+ 0xd073c4b5, 0xe71906b4, 0xbea740b6, 0x89cd82b7, 0x0cdbcdb2,
+ 0x3bb10fb3, 0x620f49b1, 0x55658bb0, 0x6822d7bb, 0x5f4815ba,
+ 0x06f653b8, 0x319c91b9, 0xb48adebc, 0x83e01cbd, 0xda5e5abf,
+ 0xed3498be},
+ {0x00000000, 0x6567bcb8, 0x8bc809aa, 0xeeafb512, 0x5797628f,
+ 0x32f0de37, 0xdc5f6b25, 0xb938d79d, 0xef28b4c5, 0x8a4f087d,
+ 0x64e0bd6f, 0x018701d7, 0xb8bfd64a, 0xddd86af2, 0x3377dfe0,
+ 0x56106358, 0x9f571950, 0xfa30a5e8, 0x149f10fa, 0x71f8ac42,
+ 0xc8c07bdf, 0xada7c767, 0x43087275, 0x266fcecd, 0x707fad95,
+ 0x1518112d, 0xfbb7a43f, 0x9ed01887, 0x27e8cf1a, 0x428f73a2,
+ 0xac20c6b0, 0xc9477a08, 0x3eaf32a0, 0x5bc88e18, 0xb5673b0a,
+ 0xd00087b2, 0x6938502f, 0x0c5fec97, 0xe2f05985, 0x8797e53d,
+ 0xd1878665, 0xb4e03add, 0x5a4f8fcf, 0x3f283377, 0x8610e4ea,
+ 0xe3775852, 0x0dd8ed40, 0x68bf51f8, 0xa1f82bf0, 0xc49f9748,
+ 0x2a30225a, 0x4f579ee2, 0xf66f497f, 0x9308f5c7, 0x7da740d5,
+ 0x18c0fc6d, 0x4ed09f35, 0x2bb7238d, 0xc518969f, 0xa07f2a27,
+ 0x1947fdba, 0x7c204102, 0x928ff410, 0xf7e848a8, 0x3d58149b,
+ 0x583fa823, 0xb6901d31, 0xd3f7a189, 0x6acf7614, 0x0fa8caac,
+ 0xe1077fbe, 0x8460c306, 0xd270a05e, 0xb7171ce6, 0x59b8a9f4,
+ 0x3cdf154c, 0x85e7c2d1, 0xe0807e69, 0x0e2fcb7b, 0x6b4877c3,
+ 0xa20f0dcb, 0xc768b173, 0x29c70461, 0x4ca0b8d9, 0xf5986f44,
+ 0x90ffd3fc, 0x7e5066ee, 0x1b37da56, 0x4d27b90e, 0x284005b6,
+ 0xc6efb0a4, 0xa3880c1c, 0x1ab0db81, 0x7fd76739, 0x9178d22b,
+ 0xf41f6e93, 0x03f7263b, 0x66909a83, 0x883f2f91, 0xed589329,
+ 0x546044b4, 0x3107f80c, 0xdfa84d1e, 0xbacff1a6, 0xecdf92fe,
+ 0x89b82e46, 0x67179b54, 0x027027ec, 0xbb48f071, 0xde2f4cc9,
+ 0x3080f9db, 0x55e74563, 0x9ca03f6b, 0xf9c783d3, 0x176836c1,
+ 0x720f8a79, 0xcb375de4, 0xae50e15c, 0x40ff544e, 0x2598e8f6,
+ 0x73888bae, 0x16ef3716, 0xf8408204, 0x9d273ebc, 0x241fe921,
+ 0x41785599, 0xafd7e08b, 0xcab05c33, 0x3bb659ed, 0x5ed1e555,
+ 0xb07e5047, 0xd519ecff, 0x6c213b62, 0x094687da, 0xe7e932c8,
+ 0x828e8e70, 0xd49eed28, 0xb1f95190, 0x5f56e482, 0x3a31583a,
+ 0x83098fa7, 0xe66e331f, 0x08c1860d, 0x6da63ab5, 0xa4e140bd,
+ 0xc186fc05, 0x2f294917, 0x4a4ef5af, 0xf3762232, 0x96119e8a,
+ 0x78be2b98, 0x1dd99720, 0x4bc9f478, 0x2eae48c0, 0xc001fdd2,
+ 0xa566416a, 0x1c5e96f7, 0x79392a4f, 0x97969f5d, 0xf2f123e5,
+ 0x05196b4d, 0x607ed7f5, 0x8ed162e7, 0xebb6de5f, 0x528e09c2,
+ 0x37e9b57a, 0xd9460068, 0xbc21bcd0, 0xea31df88, 0x8f566330,
+ 0x61f9d622, 0x049e6a9a, 0xbda6bd07, 0xd8c101bf, 0x366eb4ad,
+ 0x53090815, 0x9a4e721d, 0xff29cea5, 0x11867bb7, 0x74e1c70f,
+ 0xcdd91092, 0xa8beac2a, 0x46111938, 0x2376a580, 0x7566c6d8,
+ 0x10017a60, 0xfeaecf72, 0x9bc973ca, 0x22f1a457, 0x479618ef,
+ 0xa939adfd, 0xcc5e1145, 0x06ee4d76, 0x6389f1ce, 0x8d2644dc,
+ 0xe841f864, 0x51792ff9, 0x341e9341, 0xdab12653, 0xbfd69aeb,
+ 0xe9c6f9b3, 0x8ca1450b, 0x620ef019, 0x07694ca1, 0xbe519b3c,
+ 0xdb362784, 0x35999296, 0x50fe2e2e, 0x99b95426, 0xfcdee89e,
+ 0x12715d8c, 0x7716e134, 0xce2e36a9, 0xab498a11, 0x45e63f03,
+ 0x208183bb, 0x7691e0e3, 0x13f65c5b, 0xfd59e949, 0x983e55f1,
+ 0x2106826c, 0x44613ed4, 0xaace8bc6, 0xcfa9377e, 0x38417fd6,
+ 0x5d26c36e, 0xb389767c, 0xd6eecac4, 0x6fd61d59, 0x0ab1a1e1,
+ 0xe41e14f3, 0x8179a84b, 0xd769cb13, 0xb20e77ab, 0x5ca1c2b9,
+ 0x39c67e01, 0x80fea99c, 0xe5991524, 0x0b36a036, 0x6e511c8e,
+ 0xa7166686, 0xc271da3e, 0x2cde6f2c, 0x49b9d394, 0xf0810409,
+ 0x95e6b8b1, 0x7b490da3, 0x1e2eb11b, 0x483ed243, 0x2d596efb,
+ 0xc3f6dbe9, 0xa6916751, 0x1fa9b0cc, 0x7ace0c74, 0x9461b966,
+ 0xf10605de}};
+
+#endif
+
+#endif
+
+#if N == 2
+
+#if W == 8
+
+local const z_crc_t FAR crc_braid_table[][256] = {
+ {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87,
+ 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede,
+ 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab,
+ 0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c,
+ 0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1,
+ 0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7,
+ 0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e,
+ 0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308,
+ 0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5,
+ 0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472,
+ 0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07,
+ 0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e,
+ 0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa,
+ 0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec,
+ 0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6,
+ 0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0,
+ 0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3,
+ 0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba,
+ 0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf,
+ 0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975,
+ 0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8,
+ 0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde,
+ 0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a,
+ 0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c,
+ 0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1,
+ 0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65,
+ 0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410,
+ 0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649,
+ 0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a,
+ 0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c,
+ 0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946,
+ 0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450,
+ 0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e,
+ 0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857,
+ 0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022,
+ 0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5,
+ 0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758,
+ 0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e,
+ 0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d,
+ 0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b,
+ 0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6,
+ 0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401,
+ 0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74,
+ 0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d,
+ 0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073,
+ 0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65,
+ 0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f,
+ 0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749,
+ 0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a,
+ 0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033,
+ 0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846,
+ 0x0d7139d7},
+ {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563,
+ 0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f,
+ 0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875,
+ 0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536,
+ 0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8,
+ 0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43,
+ 0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f,
+ 0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184,
+ 0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a,
+ 0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39,
+ 0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523,
+ 0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f,
+ 0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d,
+ 0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6,
+ 0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b,
+ 0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0,
+ 0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151,
+ 0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d,
+ 0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47,
+ 0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a,
+ 0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964,
+ 0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef,
+ 0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d,
+ 0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6,
+ 0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348,
+ 0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53,
+ 0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449,
+ 0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645,
+ 0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4,
+ 0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f,
+ 0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2,
+ 0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69,
+ 0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46,
+ 0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a,
+ 0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650,
+ 0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13,
+ 0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded,
+ 0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366,
+ 0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57,
+ 0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc,
+ 0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222,
+ 0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61,
+ 0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b,
+ 0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277,
+ 0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558,
+ 0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3,
+ 0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e,
+ 0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5,
+ 0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74,
+ 0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78,
+ 0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262,
+ 0x1c53e98a},
+ {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b,
+ 0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40,
+ 0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580,
+ 0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7,
+ 0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a,
+ 0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37,
+ 0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75,
+ 0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218,
+ 0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5,
+ 0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2,
+ 0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02,
+ 0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59,
+ 0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1,
+ 0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c,
+ 0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a,
+ 0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307,
+ 0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486,
+ 0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd,
+ 0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d,
+ 0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2,
+ 0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f,
+ 0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72,
+ 0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8,
+ 0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985,
+ 0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268,
+ 0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94,
+ 0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454,
+ 0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f,
+ 0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e,
+ 0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3,
+ 0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915,
+ 0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778,
+ 0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821,
+ 0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a,
+ 0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba,
+ 0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d,
+ 0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560,
+ 0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d,
+ 0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe,
+ 0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3,
+ 0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e,
+ 0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509,
+ 0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9,
+ 0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92,
+ 0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb,
+ 0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6,
+ 0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50,
+ 0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d,
+ 0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc,
+ 0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7,
+ 0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927,
+ 0x3f88e851},
+ {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96,
+ 0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8,
+ 0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0,
+ 0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14,
+ 0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7,
+ 0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4,
+ 0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe,
+ 0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad,
+ 0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e,
+ 0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa,
+ 0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2,
+ 0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c,
+ 0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab,
+ 0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8,
+ 0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d,
+ 0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e,
+ 0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7,
+ 0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99,
+ 0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1,
+ 0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690,
+ 0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933,
+ 0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20,
+ 0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf,
+ 0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc,
+ 0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f,
+ 0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92,
+ 0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca,
+ 0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4,
+ 0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd,
+ 0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de,
+ 0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb,
+ 0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8,
+ 0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474,
+ 0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a,
+ 0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252,
+ 0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6,
+ 0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55,
+ 0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846,
+ 0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7,
+ 0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4,
+ 0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47,
+ 0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3,
+ 0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb,
+ 0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5,
+ 0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49,
+ 0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a,
+ 0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f,
+ 0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c,
+ 0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305,
+ 0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b,
+ 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523,
+ 0x3dee8ca6},
+ {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f,
+ 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91,
+ 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e,
+ 0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c,
+ 0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02,
+ 0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12,
+ 0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567,
+ 0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277,
+ 0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679,
+ 0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b,
+ 0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4,
+ 0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a,
+ 0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0,
+ 0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0,
+ 0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91,
+ 0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881,
+ 0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173,
+ 0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d,
+ 0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912,
+ 0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8,
+ 0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6,
+ 0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6,
+ 0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b,
+ 0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b,
+ 0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75,
+ 0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f,
+ 0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00,
+ 0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee,
+ 0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c,
+ 0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c,
+ 0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d,
+ 0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d,
+ 0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67,
+ 0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89,
+ 0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706,
+ 0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14,
+ 0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a,
+ 0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a,
+ 0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f,
+ 0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f,
+ 0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591,
+ 0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983,
+ 0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c,
+ 0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2,
+ 0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8,
+ 0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8,
+ 0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89,
+ 0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99,
+ 0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b,
+ 0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485,
+ 0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a,
+ 0x36197165},
+ {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382,
+ 0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85,
+ 0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06,
+ 0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca,
+ 0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e,
+ 0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc,
+ 0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616,
+ 0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54,
+ 0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10,
+ 0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc,
+ 0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f,
+ 0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58,
+ 0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef,
+ 0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad,
+ 0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b,
+ 0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29,
+ 0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6,
+ 0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1,
+ 0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622,
+ 0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039,
+ 0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d,
+ 0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f,
+ 0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32,
+ 0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770,
+ 0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034,
+ 0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f,
+ 0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc,
+ 0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db,
+ 0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154,
+ 0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16,
+ 0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0,
+ 0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592,
+ 0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca,
+ 0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd,
+ 0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e,
+ 0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882,
+ 0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6,
+ 0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384,
+ 0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1,
+ 0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3,
+ 0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7,
+ 0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b,
+ 0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8,
+ 0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff,
+ 0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7,
+ 0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5,
+ 0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23,
+ 0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761,
+ 0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee,
+ 0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9,
+ 0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a,
+ 0x1a3b93aa},
+ {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a,
+ 0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca,
+ 0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3,
+ 0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb,
+ 0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c,
+ 0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58,
+ 0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed,
+ 0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9,
+ 0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e,
+ 0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906,
+ 0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f,
+ 0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf,
+ 0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0,
+ 0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4,
+ 0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769,
+ 0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d,
+ 0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632,
+ 0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82,
+ 0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb,
+ 0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73,
+ 0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484,
+ 0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0,
+ 0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5,
+ 0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1,
+ 0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516,
+ 0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f,
+ 0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946,
+ 0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6,
+ 0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9,
+ 0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad,
+ 0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820,
+ 0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364,
+ 0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab,
+ 0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b,
+ 0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62,
+ 0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a,
+ 0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd,
+ 0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089,
+ 0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c,
+ 0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8,
+ 0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f,
+ 0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477,
+ 0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e,
+ 0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be,
+ 0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71,
+ 0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635,
+ 0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8,
+ 0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc,
+ 0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3,
+ 0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753,
+ 0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a,
+ 0xe147d714},
+ {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c,
+ 0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b,
+ 0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92,
+ 0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4,
+ 0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069,
+ 0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526,
+ 0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25,
+ 0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a,
+ 0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7,
+ 0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491,
+ 0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958,
+ 0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f,
+ 0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307,
+ 0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648,
+ 0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999,
+ 0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6,
+ 0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a,
+ 0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d,
+ 0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4,
+ 0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61,
+ 0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc,
+ 0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3,
+ 0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53,
+ 0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c,
+ 0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1,
+ 0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c,
+ 0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5,
+ 0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92,
+ 0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e,
+ 0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771,
+ 0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0,
+ 0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def,
+ 0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0,
+ 0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7,
+ 0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e,
+ 0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58,
+ 0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285,
+ 0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca,
+ 0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce,
+ 0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81,
+ 0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c,
+ 0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a,
+ 0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3,
+ 0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4,
+ 0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb,
+ 0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4,
+ 0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75,
+ 0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a,
+ 0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296,
+ 0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1,
+ 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808,
+ 0x494f0c4b}};
+
+local const z_word_t FAR crc_braid_big_table[][256] = {
+ {0x0000000000000000, 0x43147b1700000000, 0x8628f62e00000000,
+ 0xc53c8d3900000000, 0x0c51ec5d00000000, 0x4f45974a00000000,
+ 0x8a791a7300000000, 0xc96d616400000000, 0x18a2d8bb00000000,
+ 0x5bb6a3ac00000000, 0x9e8a2e9500000000, 0xdd9e558200000000,
+ 0x14f334e600000000, 0x57e74ff100000000, 0x92dbc2c800000000,
+ 0xd1cfb9df00000000, 0x7142c0ac00000000, 0x3256bbbb00000000,
+ 0xf76a368200000000, 0xb47e4d9500000000, 0x7d132cf100000000,
+ 0x3e0757e600000000, 0xfb3bdadf00000000, 0xb82fa1c800000000,
+ 0x69e0181700000000, 0x2af4630000000000, 0xefc8ee3900000000,
+ 0xacdc952e00000000, 0x65b1f44a00000000, 0x26a58f5d00000000,
+ 0xe399026400000000, 0xa08d797300000000, 0xa382f18200000000,
+ 0xe0968a9500000000, 0x25aa07ac00000000, 0x66be7cbb00000000,
+ 0xafd31ddf00000000, 0xecc766c800000000, 0x29fbebf100000000,
+ 0x6aef90e600000000, 0xbb20293900000000, 0xf834522e00000000,
+ 0x3d08df1700000000, 0x7e1ca40000000000, 0xb771c56400000000,
+ 0xf465be7300000000, 0x3159334a00000000, 0x724d485d00000000,
+ 0xd2c0312e00000000, 0x91d44a3900000000, 0x54e8c70000000000,
+ 0x17fcbc1700000000, 0xde91dd7300000000, 0x9d85a66400000000,
+ 0x58b92b5d00000000, 0x1bad504a00000000, 0xca62e99500000000,
+ 0x8976928200000000, 0x4c4a1fbb00000000, 0x0f5e64ac00000000,
+ 0xc63305c800000000, 0x85277edf00000000, 0x401bf3e600000000,
+ 0x030f88f100000000, 0x070392de00000000, 0x4417e9c900000000,
+ 0x812b64f000000000, 0xc23f1fe700000000, 0x0b527e8300000000,
+ 0x4846059400000000, 0x8d7a88ad00000000, 0xce6ef3ba00000000,
+ 0x1fa14a6500000000, 0x5cb5317200000000, 0x9989bc4b00000000,
+ 0xda9dc75c00000000, 0x13f0a63800000000, 0x50e4dd2f00000000,
+ 0x95d8501600000000, 0xd6cc2b0100000000, 0x7641527200000000,
+ 0x3555296500000000, 0xf069a45c00000000, 0xb37ddf4b00000000,
+ 0x7a10be2f00000000, 0x3904c53800000000, 0xfc38480100000000,
+ 0xbf2c331600000000, 0x6ee38ac900000000, 0x2df7f1de00000000,
+ 0xe8cb7ce700000000, 0xabdf07f000000000, 0x62b2669400000000,
+ 0x21a61d8300000000, 0xe49a90ba00000000, 0xa78eebad00000000,
+ 0xa481635c00000000, 0xe795184b00000000, 0x22a9957200000000,
+ 0x61bdee6500000000, 0xa8d08f0100000000, 0xebc4f41600000000,
+ 0x2ef8792f00000000, 0x6dec023800000000, 0xbc23bbe700000000,
+ 0xff37c0f000000000, 0x3a0b4dc900000000, 0x791f36de00000000,
+ 0xb07257ba00000000, 0xf3662cad00000000, 0x365aa19400000000,
+ 0x754eda8300000000, 0xd5c3a3f000000000, 0x96d7d8e700000000,
+ 0x53eb55de00000000, 0x10ff2ec900000000, 0xd9924fad00000000,
+ 0x9a8634ba00000000, 0x5fbab98300000000, 0x1caec29400000000,
+ 0xcd617b4b00000000, 0x8e75005c00000000, 0x4b498d6500000000,
+ 0x085df67200000000, 0xc130971600000000, 0x8224ec0100000000,
+ 0x4718613800000000, 0x040c1a2f00000000, 0x4f00556600000000,
+ 0x0c142e7100000000, 0xc928a34800000000, 0x8a3cd85f00000000,
+ 0x4351b93b00000000, 0x0045c22c00000000, 0xc5794f1500000000,
+ 0x866d340200000000, 0x57a28ddd00000000, 0x14b6f6ca00000000,
+ 0xd18a7bf300000000, 0x929e00e400000000, 0x5bf3618000000000,
+ 0x18e71a9700000000, 0xdddb97ae00000000, 0x9ecfecb900000000,
+ 0x3e4295ca00000000, 0x7d56eedd00000000, 0xb86a63e400000000,
+ 0xfb7e18f300000000, 0x3213799700000000, 0x7107028000000000,
+ 0xb43b8fb900000000, 0xf72ff4ae00000000, 0x26e04d7100000000,
+ 0x65f4366600000000, 0xa0c8bb5f00000000, 0xe3dcc04800000000,
+ 0x2ab1a12c00000000, 0x69a5da3b00000000, 0xac99570200000000,
+ 0xef8d2c1500000000, 0xec82a4e400000000, 0xaf96dff300000000,
+ 0x6aaa52ca00000000, 0x29be29dd00000000, 0xe0d348b900000000,
+ 0xa3c733ae00000000, 0x66fbbe9700000000, 0x25efc58000000000,
+ 0xf4207c5f00000000, 0xb734074800000000, 0x72088a7100000000,
+ 0x311cf16600000000, 0xf871900200000000, 0xbb65eb1500000000,
+ 0x7e59662c00000000, 0x3d4d1d3b00000000, 0x9dc0644800000000,
+ 0xded41f5f00000000, 0x1be8926600000000, 0x58fce97100000000,
+ 0x9191881500000000, 0xd285f30200000000, 0x17b97e3b00000000,
+ 0x54ad052c00000000, 0x8562bcf300000000, 0xc676c7e400000000,
+ 0x034a4add00000000, 0x405e31ca00000000, 0x893350ae00000000,
+ 0xca272bb900000000, 0x0f1ba68000000000, 0x4c0fdd9700000000,
+ 0x4803c7b800000000, 0x0b17bcaf00000000, 0xce2b319600000000,
+ 0x8d3f4a8100000000, 0x44522be500000000, 0x074650f200000000,
+ 0xc27addcb00000000, 0x816ea6dc00000000, 0x50a11f0300000000,
+ 0x13b5641400000000, 0xd689e92d00000000, 0x959d923a00000000,
+ 0x5cf0f35e00000000, 0x1fe4884900000000, 0xdad8057000000000,
+ 0x99cc7e6700000000, 0x3941071400000000, 0x7a557c0300000000,
+ 0xbf69f13a00000000, 0xfc7d8a2d00000000, 0x3510eb4900000000,
+ 0x7604905e00000000, 0xb3381d6700000000, 0xf02c667000000000,
+ 0x21e3dfaf00000000, 0x62f7a4b800000000, 0xa7cb298100000000,
+ 0xe4df529600000000, 0x2db233f200000000, 0x6ea648e500000000,
+ 0xab9ac5dc00000000, 0xe88ebecb00000000, 0xeb81363a00000000,
+ 0xa8954d2d00000000, 0x6da9c01400000000, 0x2ebdbb0300000000,
+ 0xe7d0da6700000000, 0xa4c4a17000000000, 0x61f82c4900000000,
+ 0x22ec575e00000000, 0xf323ee8100000000, 0xb037959600000000,
+ 0x750b18af00000000, 0x361f63b800000000, 0xff7202dc00000000,
+ 0xbc6679cb00000000, 0x795af4f200000000, 0x3a4e8fe500000000,
+ 0x9ac3f69600000000, 0xd9d78d8100000000, 0x1ceb00b800000000,
+ 0x5fff7baf00000000, 0x96921acb00000000, 0xd58661dc00000000,
+ 0x10baece500000000, 0x53ae97f200000000, 0x82612e2d00000000,
+ 0xc175553a00000000, 0x0449d80300000000, 0x475da31400000000,
+ 0x8e30c27000000000, 0xcd24b96700000000, 0x0818345e00000000,
+ 0x4b0c4f4900000000},
+ {0x0000000000000000, 0x3e6bc2ef00000000, 0x3dd0f50400000000,
+ 0x03bb37eb00000000, 0x7aa0eb0900000000, 0x44cb29e600000000,
+ 0x47701e0d00000000, 0x791bdce200000000, 0xf440d71300000000,
+ 0xca2b15fc00000000, 0xc990221700000000, 0xf7fbe0f800000000,
+ 0x8ee03c1a00000000, 0xb08bfef500000000, 0xb330c91e00000000,
+ 0x8d5b0bf100000000, 0xe881ae2700000000, 0xd6ea6cc800000000,
+ 0xd5515b2300000000, 0xeb3a99cc00000000, 0x9221452e00000000,
+ 0xac4a87c100000000, 0xaff1b02a00000000, 0x919a72c500000000,
+ 0x1cc1793400000000, 0x22aabbdb00000000, 0x21118c3000000000,
+ 0x1f7a4edf00000000, 0x6661923d00000000, 0x580a50d200000000,
+ 0x5bb1673900000000, 0x65daa5d600000000, 0xd0035d4f00000000,
+ 0xee689fa000000000, 0xedd3a84b00000000, 0xd3b86aa400000000,
+ 0xaaa3b64600000000, 0x94c874a900000000, 0x9773434200000000,
+ 0xa91881ad00000000, 0x24438a5c00000000, 0x1a2848b300000000,
+ 0x19937f5800000000, 0x27f8bdb700000000, 0x5ee3615500000000,
+ 0x6088a3ba00000000, 0x6333945100000000, 0x5d5856be00000000,
+ 0x3882f36800000000, 0x06e9318700000000, 0x0552066c00000000,
+ 0x3b39c48300000000, 0x4222186100000000, 0x7c49da8e00000000,
+ 0x7ff2ed6500000000, 0x41992f8a00000000, 0xccc2247b00000000,
+ 0xf2a9e69400000000, 0xf112d17f00000000, 0xcf79139000000000,
+ 0xb662cf7200000000, 0x88090d9d00000000, 0x8bb23a7600000000,
+ 0xb5d9f89900000000, 0xa007ba9e00000000, 0x9e6c787100000000,
+ 0x9dd74f9a00000000, 0xa3bc8d7500000000, 0xdaa7519700000000,
+ 0xe4cc937800000000, 0xe777a49300000000, 0xd91c667c00000000,
+ 0x54476d8d00000000, 0x6a2caf6200000000, 0x6997988900000000,
+ 0x57fc5a6600000000, 0x2ee7868400000000, 0x108c446b00000000,
+ 0x1337738000000000, 0x2d5cb16f00000000, 0x488614b900000000,
+ 0x76edd65600000000, 0x7556e1bd00000000, 0x4b3d235200000000,
+ 0x3226ffb000000000, 0x0c4d3d5f00000000, 0x0ff60ab400000000,
+ 0x319dc85b00000000, 0xbcc6c3aa00000000, 0x82ad014500000000,
+ 0x811636ae00000000, 0xbf7df44100000000, 0xc66628a300000000,
+ 0xf80dea4c00000000, 0xfbb6dda700000000, 0xc5dd1f4800000000,
+ 0x7004e7d100000000, 0x4e6f253e00000000, 0x4dd412d500000000,
+ 0x73bfd03a00000000, 0x0aa40cd800000000, 0x34cfce3700000000,
+ 0x3774f9dc00000000, 0x091f3b3300000000, 0x844430c200000000,
+ 0xba2ff22d00000000, 0xb994c5c600000000, 0x87ff072900000000,
+ 0xfee4dbcb00000000, 0xc08f192400000000, 0xc3342ecf00000000,
+ 0xfd5fec2000000000, 0x988549f600000000, 0xa6ee8b1900000000,
+ 0xa555bcf200000000, 0x9b3e7e1d00000000, 0xe225a2ff00000000,
+ 0xdc4e601000000000, 0xdff557fb00000000, 0xe19e951400000000,
+ 0x6cc59ee500000000, 0x52ae5c0a00000000, 0x51156be100000000,
+ 0x6f7ea90e00000000, 0x166575ec00000000, 0x280eb70300000000,
+ 0x2bb580e800000000, 0x15de420700000000, 0x010905e600000000,
+ 0x3f62c70900000000, 0x3cd9f0e200000000, 0x02b2320d00000000,
+ 0x7ba9eeef00000000, 0x45c22c0000000000, 0x46791beb00000000,
+ 0x7812d90400000000, 0xf549d2f500000000, 0xcb22101a00000000,
+ 0xc89927f100000000, 0xf6f2e51e00000000, 0x8fe939fc00000000,
+ 0xb182fb1300000000, 0xb239ccf800000000, 0x8c520e1700000000,
+ 0xe988abc100000000, 0xd7e3692e00000000, 0xd4585ec500000000,
+ 0xea339c2a00000000, 0x932840c800000000, 0xad43822700000000,
+ 0xaef8b5cc00000000, 0x9093772300000000, 0x1dc87cd200000000,
+ 0x23a3be3d00000000, 0x201889d600000000, 0x1e734b3900000000,
+ 0x676897db00000000, 0x5903553400000000, 0x5ab862df00000000,
+ 0x64d3a03000000000, 0xd10a58a900000000, 0xef619a4600000000,
+ 0xecdaadad00000000, 0xd2b16f4200000000, 0xabaab3a000000000,
+ 0x95c1714f00000000, 0x967a46a400000000, 0xa811844b00000000,
+ 0x254a8fba00000000, 0x1b214d5500000000, 0x189a7abe00000000,
+ 0x26f1b85100000000, 0x5fea64b300000000, 0x6181a65c00000000,
+ 0x623a91b700000000, 0x5c51535800000000, 0x398bf68e00000000,
+ 0x07e0346100000000, 0x045b038a00000000, 0x3a30c16500000000,
+ 0x432b1d8700000000, 0x7d40df6800000000, 0x7efbe88300000000,
+ 0x40902a6c00000000, 0xcdcb219d00000000, 0xf3a0e37200000000,
+ 0xf01bd49900000000, 0xce70167600000000, 0xb76bca9400000000,
+ 0x8900087b00000000, 0x8abb3f9000000000, 0xb4d0fd7f00000000,
+ 0xa10ebf7800000000, 0x9f657d9700000000, 0x9cde4a7c00000000,
+ 0xa2b5889300000000, 0xdbae547100000000, 0xe5c5969e00000000,
+ 0xe67ea17500000000, 0xd815639a00000000, 0x554e686b00000000,
+ 0x6b25aa8400000000, 0x689e9d6f00000000, 0x56f55f8000000000,
+ 0x2fee836200000000, 0x1185418d00000000, 0x123e766600000000,
+ 0x2c55b48900000000, 0x498f115f00000000, 0x77e4d3b000000000,
+ 0x745fe45b00000000, 0x4a3426b400000000, 0x332ffa5600000000,
+ 0x0d4438b900000000, 0x0eff0f5200000000, 0x3094cdbd00000000,
+ 0xbdcfc64c00000000, 0x83a404a300000000, 0x801f334800000000,
+ 0xbe74f1a700000000, 0xc76f2d4500000000, 0xf904efaa00000000,
+ 0xfabfd84100000000, 0xc4d41aae00000000, 0x710de23700000000,
+ 0x4f6620d800000000, 0x4cdd173300000000, 0x72b6d5dc00000000,
+ 0x0bad093e00000000, 0x35c6cbd100000000, 0x367dfc3a00000000,
+ 0x08163ed500000000, 0x854d352400000000, 0xbb26f7cb00000000,
+ 0xb89dc02000000000, 0x86f602cf00000000, 0xffedde2d00000000,
+ 0xc1861cc200000000, 0xc23d2b2900000000, 0xfc56e9c600000000,
+ 0x998c4c1000000000, 0xa7e78eff00000000, 0xa45cb91400000000,
+ 0x9a377bfb00000000, 0xe32ca71900000000, 0xdd4765f600000000,
+ 0xdefc521d00000000, 0xe09790f200000000, 0x6dcc9b0300000000,
+ 0x53a759ec00000000, 0x501c6e0700000000, 0x6e77ace800000000,
+ 0x176c700a00000000, 0x2907b2e500000000, 0x2abc850e00000000,
+ 0x14d747e100000000},
+ {0x0000000000000000, 0xc0df8ec100000000, 0xc1b96c5800000000,
+ 0x0166e29900000000, 0x8273d9b000000000, 0x42ac577100000000,
+ 0x43cab5e800000000, 0x83153b2900000000, 0x45e1c3ba00000000,
+ 0x853e4d7b00000000, 0x8458afe200000000, 0x4487212300000000,
+ 0xc7921a0a00000000, 0x074d94cb00000000, 0x062b765200000000,
+ 0xc6f4f89300000000, 0xcbc4f6ae00000000, 0x0b1b786f00000000,
+ 0x0a7d9af600000000, 0xcaa2143700000000, 0x49b72f1e00000000,
+ 0x8968a1df00000000, 0x880e434600000000, 0x48d1cd8700000000,
+ 0x8e25351400000000, 0x4efabbd500000000, 0x4f9c594c00000000,
+ 0x8f43d78d00000000, 0x0c56eca400000000, 0xcc89626500000000,
+ 0xcdef80fc00000000, 0x0d300e3d00000000, 0xd78f9c8600000000,
+ 0x1750124700000000, 0x1636f0de00000000, 0xd6e97e1f00000000,
+ 0x55fc453600000000, 0x9523cbf700000000, 0x9445296e00000000,
+ 0x549aa7af00000000, 0x926e5f3c00000000, 0x52b1d1fd00000000,
+ 0x53d7336400000000, 0x9308bda500000000, 0x101d868c00000000,
+ 0xd0c2084d00000000, 0xd1a4ead400000000, 0x117b641500000000,
+ 0x1c4b6a2800000000, 0xdc94e4e900000000, 0xddf2067000000000,
+ 0x1d2d88b100000000, 0x9e38b39800000000, 0x5ee73d5900000000,
+ 0x5f81dfc000000000, 0x9f5e510100000000, 0x59aaa99200000000,
+ 0x9975275300000000, 0x9813c5ca00000000, 0x58cc4b0b00000000,
+ 0xdbd9702200000000, 0x1b06fee300000000, 0x1a601c7a00000000,
+ 0xdabf92bb00000000, 0xef1948d600000000, 0x2fc6c61700000000,
+ 0x2ea0248e00000000, 0xee7faa4f00000000, 0x6d6a916600000000,
+ 0xadb51fa700000000, 0xacd3fd3e00000000, 0x6c0c73ff00000000,
+ 0xaaf88b6c00000000, 0x6a2705ad00000000, 0x6b41e73400000000,
+ 0xab9e69f500000000, 0x288b52dc00000000, 0xe854dc1d00000000,
+ 0xe9323e8400000000, 0x29edb04500000000, 0x24ddbe7800000000,
+ 0xe40230b900000000, 0xe564d22000000000, 0x25bb5ce100000000,
+ 0xa6ae67c800000000, 0x6671e90900000000, 0x67170b9000000000,
+ 0xa7c8855100000000, 0x613c7dc200000000, 0xa1e3f30300000000,
+ 0xa085119a00000000, 0x605a9f5b00000000, 0xe34fa47200000000,
+ 0x23902ab300000000, 0x22f6c82a00000000, 0xe22946eb00000000,
+ 0x3896d45000000000, 0xf8495a9100000000, 0xf92fb80800000000,
+ 0x39f036c900000000, 0xbae50de000000000, 0x7a3a832100000000,
+ 0x7b5c61b800000000, 0xbb83ef7900000000, 0x7d7717ea00000000,
+ 0xbda8992b00000000, 0xbcce7bb200000000, 0x7c11f57300000000,
+ 0xff04ce5a00000000, 0x3fdb409b00000000, 0x3ebda20200000000,
+ 0xfe622cc300000000, 0xf35222fe00000000, 0x338dac3f00000000,
+ 0x32eb4ea600000000, 0xf234c06700000000, 0x7121fb4e00000000,
+ 0xb1fe758f00000000, 0xb098971600000000, 0x704719d700000000,
+ 0xb6b3e14400000000, 0x766c6f8500000000, 0x770a8d1c00000000,
+ 0xb7d503dd00000000, 0x34c038f400000000, 0xf41fb63500000000,
+ 0xf57954ac00000000, 0x35a6da6d00000000, 0x9f35e17700000000,
+ 0x5fea6fb600000000, 0x5e8c8d2f00000000, 0x9e5303ee00000000,
+ 0x1d4638c700000000, 0xdd99b60600000000, 0xdcff549f00000000,
+ 0x1c20da5e00000000, 0xdad422cd00000000, 0x1a0bac0c00000000,
+ 0x1b6d4e9500000000, 0xdbb2c05400000000, 0x58a7fb7d00000000,
+ 0x987875bc00000000, 0x991e972500000000, 0x59c119e400000000,
+ 0x54f117d900000000, 0x942e991800000000, 0x95487b8100000000,
+ 0x5597f54000000000, 0xd682ce6900000000, 0x165d40a800000000,
+ 0x173ba23100000000, 0xd7e42cf000000000, 0x1110d46300000000,
+ 0xd1cf5aa200000000, 0xd0a9b83b00000000, 0x107636fa00000000,
+ 0x93630dd300000000, 0x53bc831200000000, 0x52da618b00000000,
+ 0x9205ef4a00000000, 0x48ba7df100000000, 0x8865f33000000000,
+ 0x890311a900000000, 0x49dc9f6800000000, 0xcac9a44100000000,
+ 0x0a162a8000000000, 0x0b70c81900000000, 0xcbaf46d800000000,
+ 0x0d5bbe4b00000000, 0xcd84308a00000000, 0xcce2d21300000000,
+ 0x0c3d5cd200000000, 0x8f2867fb00000000, 0x4ff7e93a00000000,
+ 0x4e910ba300000000, 0x8e4e856200000000, 0x837e8b5f00000000,
+ 0x43a1059e00000000, 0x42c7e70700000000, 0x821869c600000000,
+ 0x010d52ef00000000, 0xc1d2dc2e00000000, 0xc0b43eb700000000,
+ 0x006bb07600000000, 0xc69f48e500000000, 0x0640c62400000000,
+ 0x072624bd00000000, 0xc7f9aa7c00000000, 0x44ec915500000000,
+ 0x84331f9400000000, 0x8555fd0d00000000, 0x458a73cc00000000,
+ 0x702ca9a100000000, 0xb0f3276000000000, 0xb195c5f900000000,
+ 0x714a4b3800000000, 0xf25f701100000000, 0x3280fed000000000,
+ 0x33e61c4900000000, 0xf339928800000000, 0x35cd6a1b00000000,
+ 0xf512e4da00000000, 0xf474064300000000, 0x34ab888200000000,
+ 0xb7beb3ab00000000, 0x77613d6a00000000, 0x7607dff300000000,
+ 0xb6d8513200000000, 0xbbe85f0f00000000, 0x7b37d1ce00000000,
+ 0x7a51335700000000, 0xba8ebd9600000000, 0x399b86bf00000000,
+ 0xf944087e00000000, 0xf822eae700000000, 0x38fd642600000000,
+ 0xfe099cb500000000, 0x3ed6127400000000, 0x3fb0f0ed00000000,
+ 0xff6f7e2c00000000, 0x7c7a450500000000, 0xbca5cbc400000000,
+ 0xbdc3295d00000000, 0x7d1ca79c00000000, 0xa7a3352700000000,
+ 0x677cbbe600000000, 0x661a597f00000000, 0xa6c5d7be00000000,
+ 0x25d0ec9700000000, 0xe50f625600000000, 0xe46980cf00000000,
+ 0x24b60e0e00000000, 0xe242f69d00000000, 0x229d785c00000000,
+ 0x23fb9ac500000000, 0xe324140400000000, 0x60312f2d00000000,
+ 0xa0eea1ec00000000, 0xa188437500000000, 0x6157cdb400000000,
+ 0x6c67c38900000000, 0xacb84d4800000000, 0xaddeafd100000000,
+ 0x6d01211000000000, 0xee141a3900000000, 0x2ecb94f800000000,
+ 0x2fad766100000000, 0xef72f8a000000000, 0x2986003300000000,
+ 0xe9598ef200000000, 0xe83f6c6b00000000, 0x28e0e2aa00000000,
+ 0xabf5d98300000000, 0x6b2a574200000000, 0x6a4cb5db00000000,
+ 0xaa933b1a00000000},
+ {0x0000000000000000, 0x6f4ca59b00000000, 0x9f9e3bec00000000,
+ 0xf0d29e7700000000, 0x7f3b060300000000, 0x1077a39800000000,
+ 0xe0a53def00000000, 0x8fe9987400000000, 0xfe760c0600000000,
+ 0x913aa99d00000000, 0x61e837ea00000000, 0x0ea4927100000000,
+ 0x814d0a0500000000, 0xee01af9e00000000, 0x1ed331e900000000,
+ 0x719f947200000000, 0xfced180c00000000, 0x93a1bd9700000000,
+ 0x637323e000000000, 0x0c3f867b00000000, 0x83d61e0f00000000,
+ 0xec9abb9400000000, 0x1c4825e300000000, 0x7304807800000000,
+ 0x029b140a00000000, 0x6dd7b19100000000, 0x9d052fe600000000,
+ 0xf2498a7d00000000, 0x7da0120900000000, 0x12ecb79200000000,
+ 0xe23e29e500000000, 0x8d728c7e00000000, 0xf8db311800000000,
+ 0x9797948300000000, 0x67450af400000000, 0x0809af6f00000000,
+ 0x87e0371b00000000, 0xe8ac928000000000, 0x187e0cf700000000,
+ 0x7732a96c00000000, 0x06ad3d1e00000000, 0x69e1988500000000,
+ 0x993306f200000000, 0xf67fa36900000000, 0x79963b1d00000000,
+ 0x16da9e8600000000, 0xe60800f100000000, 0x8944a56a00000000,
+ 0x0436291400000000, 0x6b7a8c8f00000000, 0x9ba812f800000000,
+ 0xf4e4b76300000000, 0x7b0d2f1700000000, 0x14418a8c00000000,
+ 0xe49314fb00000000, 0x8bdfb16000000000, 0xfa40251200000000,
+ 0x950c808900000000, 0x65de1efe00000000, 0x0a92bb6500000000,
+ 0x857b231100000000, 0xea37868a00000000, 0x1ae518fd00000000,
+ 0x75a9bd6600000000, 0xf0b7633000000000, 0x9ffbc6ab00000000,
+ 0x6f2958dc00000000, 0x0065fd4700000000, 0x8f8c653300000000,
+ 0xe0c0c0a800000000, 0x10125edf00000000, 0x7f5efb4400000000,
+ 0x0ec16f3600000000, 0x618dcaad00000000, 0x915f54da00000000,
+ 0xfe13f14100000000, 0x71fa693500000000, 0x1eb6ccae00000000,
+ 0xee6452d900000000, 0x8128f74200000000, 0x0c5a7b3c00000000,
+ 0x6316dea700000000, 0x93c440d000000000, 0xfc88e54b00000000,
+ 0x73617d3f00000000, 0x1c2dd8a400000000, 0xecff46d300000000,
+ 0x83b3e34800000000, 0xf22c773a00000000, 0x9d60d2a100000000,
+ 0x6db24cd600000000, 0x02fee94d00000000, 0x8d17713900000000,
+ 0xe25bd4a200000000, 0x12894ad500000000, 0x7dc5ef4e00000000,
+ 0x086c522800000000, 0x6720f7b300000000, 0x97f269c400000000,
+ 0xf8becc5f00000000, 0x7757542b00000000, 0x181bf1b000000000,
+ 0xe8c96fc700000000, 0x8785ca5c00000000, 0xf61a5e2e00000000,
+ 0x9956fbb500000000, 0x698465c200000000, 0x06c8c05900000000,
+ 0x8921582d00000000, 0xe66dfdb600000000, 0x16bf63c100000000,
+ 0x79f3c65a00000000, 0xf4814a2400000000, 0x9bcdefbf00000000,
+ 0x6b1f71c800000000, 0x0453d45300000000, 0x8bba4c2700000000,
+ 0xe4f6e9bc00000000, 0x142477cb00000000, 0x7b68d25000000000,
+ 0x0af7462200000000, 0x65bbe3b900000000, 0x95697dce00000000,
+ 0xfa25d85500000000, 0x75cc402100000000, 0x1a80e5ba00000000,
+ 0xea527bcd00000000, 0x851ede5600000000, 0xe06fc76000000000,
+ 0x8f2362fb00000000, 0x7ff1fc8c00000000, 0x10bd591700000000,
+ 0x9f54c16300000000, 0xf01864f800000000, 0x00cafa8f00000000,
+ 0x6f865f1400000000, 0x1e19cb6600000000, 0x71556efd00000000,
+ 0x8187f08a00000000, 0xeecb551100000000, 0x6122cd6500000000,
+ 0x0e6e68fe00000000, 0xfebcf68900000000, 0x91f0531200000000,
+ 0x1c82df6c00000000, 0x73ce7af700000000, 0x831ce48000000000,
+ 0xec50411b00000000, 0x63b9d96f00000000, 0x0cf57cf400000000,
+ 0xfc27e28300000000, 0x936b471800000000, 0xe2f4d36a00000000,
+ 0x8db876f100000000, 0x7d6ae88600000000, 0x12264d1d00000000,
+ 0x9dcfd56900000000, 0xf28370f200000000, 0x0251ee8500000000,
+ 0x6d1d4b1e00000000, 0x18b4f67800000000, 0x77f853e300000000,
+ 0x872acd9400000000, 0xe866680f00000000, 0x678ff07b00000000,
+ 0x08c355e000000000, 0xf811cb9700000000, 0x975d6e0c00000000,
+ 0xe6c2fa7e00000000, 0x898e5fe500000000, 0x795cc19200000000,
+ 0x1610640900000000, 0x99f9fc7d00000000, 0xf6b559e600000000,
+ 0x0667c79100000000, 0x692b620a00000000, 0xe459ee7400000000,
+ 0x8b154bef00000000, 0x7bc7d59800000000, 0x148b700300000000,
+ 0x9b62e87700000000, 0xf42e4dec00000000, 0x04fcd39b00000000,
+ 0x6bb0760000000000, 0x1a2fe27200000000, 0x756347e900000000,
+ 0x85b1d99e00000000, 0xeafd7c0500000000, 0x6514e47100000000,
+ 0x0a5841ea00000000, 0xfa8adf9d00000000, 0x95c67a0600000000,
+ 0x10d8a45000000000, 0x7f9401cb00000000, 0x8f469fbc00000000,
+ 0xe00a3a2700000000, 0x6fe3a25300000000, 0x00af07c800000000,
+ 0xf07d99bf00000000, 0x9f313c2400000000, 0xeeaea85600000000,
+ 0x81e20dcd00000000, 0x713093ba00000000, 0x1e7c362100000000,
+ 0x9195ae5500000000, 0xfed90bce00000000, 0x0e0b95b900000000,
+ 0x6147302200000000, 0xec35bc5c00000000, 0x837919c700000000,
+ 0x73ab87b000000000, 0x1ce7222b00000000, 0x930eba5f00000000,
+ 0xfc421fc400000000, 0x0c9081b300000000, 0x63dc242800000000,
+ 0x1243b05a00000000, 0x7d0f15c100000000, 0x8ddd8bb600000000,
+ 0xe2912e2d00000000, 0x6d78b65900000000, 0x023413c200000000,
+ 0xf2e68db500000000, 0x9daa282e00000000, 0xe803954800000000,
+ 0x874f30d300000000, 0x779daea400000000, 0x18d10b3f00000000,
+ 0x9738934b00000000, 0xf87436d000000000, 0x08a6a8a700000000,
+ 0x67ea0d3c00000000, 0x1675994e00000000, 0x79393cd500000000,
+ 0x89eba2a200000000, 0xe6a7073900000000, 0x694e9f4d00000000,
+ 0x06023ad600000000, 0xf6d0a4a100000000, 0x999c013a00000000,
+ 0x14ee8d4400000000, 0x7ba228df00000000, 0x8b70b6a800000000,
+ 0xe43c133300000000, 0x6bd58b4700000000, 0x04992edc00000000,
+ 0xf44bb0ab00000000, 0x9b07153000000000, 0xea98814200000000,
+ 0x85d424d900000000, 0x7506baae00000000, 0x1a4a1f3500000000,
+ 0x95a3874100000000, 0xfaef22da00000000, 0x0a3dbcad00000000,
+ 0x6571193600000000},
+ {0x0000000000000000, 0x85d996dd00000000, 0x4bb55c6000000000,
+ 0xce6ccabd00000000, 0x966ab9c000000000, 0x13b32f1d00000000,
+ 0xdddfe5a000000000, 0x5806737d00000000, 0x6dd3035a00000000,
+ 0xe80a958700000000, 0x26665f3a00000000, 0xa3bfc9e700000000,
+ 0xfbb9ba9a00000000, 0x7e602c4700000000, 0xb00ce6fa00000000,
+ 0x35d5702700000000, 0xdaa607b400000000, 0x5f7f916900000000,
+ 0x91135bd400000000, 0x14cacd0900000000, 0x4cccbe7400000000,
+ 0xc91528a900000000, 0x0779e21400000000, 0x82a074c900000000,
+ 0xb77504ee00000000, 0x32ac923300000000, 0xfcc0588e00000000,
+ 0x7919ce5300000000, 0x211fbd2e00000000, 0xa4c62bf300000000,
+ 0x6aaae14e00000000, 0xef73779300000000, 0xf54b7eb300000000,
+ 0x7092e86e00000000, 0xbefe22d300000000, 0x3b27b40e00000000,
+ 0x6321c77300000000, 0xe6f851ae00000000, 0x28949b1300000000,
+ 0xad4d0dce00000000, 0x98987de900000000, 0x1d41eb3400000000,
+ 0xd32d218900000000, 0x56f4b75400000000, 0x0ef2c42900000000,
+ 0x8b2b52f400000000, 0x4547984900000000, 0xc09e0e9400000000,
+ 0x2fed790700000000, 0xaa34efda00000000, 0x6458256700000000,
+ 0xe181b3ba00000000, 0xb987c0c700000000, 0x3c5e561a00000000,
+ 0xf2329ca700000000, 0x77eb0a7a00000000, 0x423e7a5d00000000,
+ 0xc7e7ec8000000000, 0x098b263d00000000, 0x8c52b0e000000000,
+ 0xd454c39d00000000, 0x518d554000000000, 0x9fe19ffd00000000,
+ 0x1a38092000000000, 0xab918dbd00000000, 0x2e481b6000000000,
+ 0xe024d1dd00000000, 0x65fd470000000000, 0x3dfb347d00000000,
+ 0xb822a2a000000000, 0x764e681d00000000, 0xf397fec000000000,
+ 0xc6428ee700000000, 0x439b183a00000000, 0x8df7d28700000000,
+ 0x082e445a00000000, 0x5028372700000000, 0xd5f1a1fa00000000,
+ 0x1b9d6b4700000000, 0x9e44fd9a00000000, 0x71378a0900000000,
+ 0xf4ee1cd400000000, 0x3a82d66900000000, 0xbf5b40b400000000,
+ 0xe75d33c900000000, 0x6284a51400000000, 0xace86fa900000000,
+ 0x2931f97400000000, 0x1ce4895300000000, 0x993d1f8e00000000,
+ 0x5751d53300000000, 0xd28843ee00000000, 0x8a8e309300000000,
+ 0x0f57a64e00000000, 0xc13b6cf300000000, 0x44e2fa2e00000000,
+ 0x5edaf30e00000000, 0xdb0365d300000000, 0x156faf6e00000000,
+ 0x90b639b300000000, 0xc8b04ace00000000, 0x4d69dc1300000000,
+ 0x830516ae00000000, 0x06dc807300000000, 0x3309f05400000000,
+ 0xb6d0668900000000, 0x78bcac3400000000, 0xfd653ae900000000,
+ 0xa563499400000000, 0x20badf4900000000, 0xeed615f400000000,
+ 0x6b0f832900000000, 0x847cf4ba00000000, 0x01a5626700000000,
+ 0xcfc9a8da00000000, 0x4a103e0700000000, 0x12164d7a00000000,
+ 0x97cfdba700000000, 0x59a3111a00000000, 0xdc7a87c700000000,
+ 0xe9aff7e000000000, 0x6c76613d00000000, 0xa21aab8000000000,
+ 0x27c33d5d00000000, 0x7fc54e2000000000, 0xfa1cd8fd00000000,
+ 0x3470124000000000, 0xb1a9849d00000000, 0x17256aa000000000,
+ 0x92fcfc7d00000000, 0x5c9036c000000000, 0xd949a01d00000000,
+ 0x814fd36000000000, 0x049645bd00000000, 0xcafa8f0000000000,
+ 0x4f2319dd00000000, 0x7af669fa00000000, 0xff2fff2700000000,
+ 0x3143359a00000000, 0xb49aa34700000000, 0xec9cd03a00000000,
+ 0x694546e700000000, 0xa7298c5a00000000, 0x22f01a8700000000,
+ 0xcd836d1400000000, 0x485afbc900000000, 0x8636317400000000,
+ 0x03efa7a900000000, 0x5be9d4d400000000, 0xde30420900000000,
+ 0x105c88b400000000, 0x95851e6900000000, 0xa0506e4e00000000,
+ 0x2589f89300000000, 0xebe5322e00000000, 0x6e3ca4f300000000,
+ 0x363ad78e00000000, 0xb3e3415300000000, 0x7d8f8bee00000000,
+ 0xf8561d3300000000, 0xe26e141300000000, 0x67b782ce00000000,
+ 0xa9db487300000000, 0x2c02deae00000000, 0x7404add300000000,
+ 0xf1dd3b0e00000000, 0x3fb1f1b300000000, 0xba68676e00000000,
+ 0x8fbd174900000000, 0x0a64819400000000, 0xc4084b2900000000,
+ 0x41d1ddf400000000, 0x19d7ae8900000000, 0x9c0e385400000000,
+ 0x5262f2e900000000, 0xd7bb643400000000, 0x38c813a700000000,
+ 0xbd11857a00000000, 0x737d4fc700000000, 0xf6a4d91a00000000,
+ 0xaea2aa6700000000, 0x2b7b3cba00000000, 0xe517f60700000000,
+ 0x60ce60da00000000, 0x551b10fd00000000, 0xd0c2862000000000,
+ 0x1eae4c9d00000000, 0x9b77da4000000000, 0xc371a93d00000000,
+ 0x46a83fe000000000, 0x88c4f55d00000000, 0x0d1d638000000000,
+ 0xbcb4e71d00000000, 0x396d71c000000000, 0xf701bb7d00000000,
+ 0x72d82da000000000, 0x2ade5edd00000000, 0xaf07c80000000000,
+ 0x616b02bd00000000, 0xe4b2946000000000, 0xd167e44700000000,
+ 0x54be729a00000000, 0x9ad2b82700000000, 0x1f0b2efa00000000,
+ 0x470d5d8700000000, 0xc2d4cb5a00000000, 0x0cb801e700000000,
+ 0x8961973a00000000, 0x6612e0a900000000, 0xe3cb767400000000,
+ 0x2da7bcc900000000, 0xa87e2a1400000000, 0xf078596900000000,
+ 0x75a1cfb400000000, 0xbbcd050900000000, 0x3e1493d400000000,
+ 0x0bc1e3f300000000, 0x8e18752e00000000, 0x4074bf9300000000,
+ 0xc5ad294e00000000, 0x9dab5a3300000000, 0x1872ccee00000000,
+ 0xd61e065300000000, 0x53c7908e00000000, 0x49ff99ae00000000,
+ 0xcc260f7300000000, 0x024ac5ce00000000, 0x8793531300000000,
+ 0xdf95206e00000000, 0x5a4cb6b300000000, 0x94207c0e00000000,
+ 0x11f9ead300000000, 0x242c9af400000000, 0xa1f50c2900000000,
+ 0x6f99c69400000000, 0xea40504900000000, 0xb246233400000000,
+ 0x379fb5e900000000, 0xf9f37f5400000000, 0x7c2ae98900000000,
+ 0x93599e1a00000000, 0x168008c700000000, 0xd8ecc27a00000000,
+ 0x5d3554a700000000, 0x053327da00000000, 0x80eab10700000000,
+ 0x4e867bba00000000, 0xcb5fed6700000000, 0xfe8a9d4000000000,
+ 0x7b530b9d00000000, 0xb53fc12000000000, 0x30e657fd00000000,
+ 0x68e0248000000000, 0xed39b25d00000000, 0x235578e000000000,
+ 0xa68cee3d00000000},
+ {0x0000000000000000, 0x76e10f9d00000000, 0xadc46ee100000000,
+ 0xdb25617c00000000, 0x1b8fac1900000000, 0x6d6ea38400000000,
+ 0xb64bc2f800000000, 0xc0aacd6500000000, 0x361e593300000000,
+ 0x40ff56ae00000000, 0x9bda37d200000000, 0xed3b384f00000000,
+ 0x2d91f52a00000000, 0x5b70fab700000000, 0x80559bcb00000000,
+ 0xf6b4945600000000, 0x6c3cb26600000000, 0x1addbdfb00000000,
+ 0xc1f8dc8700000000, 0xb719d31a00000000, 0x77b31e7f00000000,
+ 0x015211e200000000, 0xda77709e00000000, 0xac967f0300000000,
+ 0x5a22eb5500000000, 0x2cc3e4c800000000, 0xf7e685b400000000,
+ 0x81078a2900000000, 0x41ad474c00000000, 0x374c48d100000000,
+ 0xec6929ad00000000, 0x9a88263000000000, 0xd87864cd00000000,
+ 0xae996b5000000000, 0x75bc0a2c00000000, 0x035d05b100000000,
+ 0xc3f7c8d400000000, 0xb516c74900000000, 0x6e33a63500000000,
+ 0x18d2a9a800000000, 0xee663dfe00000000, 0x9887326300000000,
+ 0x43a2531f00000000, 0x35435c8200000000, 0xf5e991e700000000,
+ 0x83089e7a00000000, 0x582dff0600000000, 0x2eccf09b00000000,
+ 0xb444d6ab00000000, 0xc2a5d93600000000, 0x1980b84a00000000,
+ 0x6f61b7d700000000, 0xafcb7ab200000000, 0xd92a752f00000000,
+ 0x020f145300000000, 0x74ee1bce00000000, 0x825a8f9800000000,
+ 0xf4bb800500000000, 0x2f9ee17900000000, 0x597feee400000000,
+ 0x99d5238100000000, 0xef342c1c00000000, 0x34114d6000000000,
+ 0x42f042fd00000000, 0xf1f7b94100000000, 0x8716b6dc00000000,
+ 0x5c33d7a000000000, 0x2ad2d83d00000000, 0xea78155800000000,
+ 0x9c991ac500000000, 0x47bc7bb900000000, 0x315d742400000000,
+ 0xc7e9e07200000000, 0xb108efef00000000, 0x6a2d8e9300000000,
+ 0x1ccc810e00000000, 0xdc664c6b00000000, 0xaa8743f600000000,
+ 0x71a2228a00000000, 0x07432d1700000000, 0x9dcb0b2700000000,
+ 0xeb2a04ba00000000, 0x300f65c600000000, 0x46ee6a5b00000000,
+ 0x8644a73e00000000, 0xf0a5a8a300000000, 0x2b80c9df00000000,
+ 0x5d61c64200000000, 0xabd5521400000000, 0xdd345d8900000000,
+ 0x06113cf500000000, 0x70f0336800000000, 0xb05afe0d00000000,
+ 0xc6bbf19000000000, 0x1d9e90ec00000000, 0x6b7f9f7100000000,
+ 0x298fdd8c00000000, 0x5f6ed21100000000, 0x844bb36d00000000,
+ 0xf2aabcf000000000, 0x3200719500000000, 0x44e17e0800000000,
+ 0x9fc41f7400000000, 0xe92510e900000000, 0x1f9184bf00000000,
+ 0x69708b2200000000, 0xb255ea5e00000000, 0xc4b4e5c300000000,
+ 0x041e28a600000000, 0x72ff273b00000000, 0xa9da464700000000,
+ 0xdf3b49da00000000, 0x45b36fea00000000, 0x3352607700000000,
+ 0xe877010b00000000, 0x9e960e9600000000, 0x5e3cc3f300000000,
+ 0x28ddcc6e00000000, 0xf3f8ad1200000000, 0x8519a28f00000000,
+ 0x73ad36d900000000, 0x054c394400000000, 0xde69583800000000,
+ 0xa88857a500000000, 0x68229ac000000000, 0x1ec3955d00000000,
+ 0xc5e6f42100000000, 0xb307fbbc00000000, 0xe2ef738300000000,
+ 0x940e7c1e00000000, 0x4f2b1d6200000000, 0x39ca12ff00000000,
+ 0xf960df9a00000000, 0x8f81d00700000000, 0x54a4b17b00000000,
+ 0x2245bee600000000, 0xd4f12ab000000000, 0xa210252d00000000,
+ 0x7935445100000000, 0x0fd44bcc00000000, 0xcf7e86a900000000,
+ 0xb99f893400000000, 0x62bae84800000000, 0x145be7d500000000,
+ 0x8ed3c1e500000000, 0xf832ce7800000000, 0x2317af0400000000,
+ 0x55f6a09900000000, 0x955c6dfc00000000, 0xe3bd626100000000,
+ 0x3898031d00000000, 0x4e790c8000000000, 0xb8cd98d600000000,
+ 0xce2c974b00000000, 0x1509f63700000000, 0x63e8f9aa00000000,
+ 0xa34234cf00000000, 0xd5a33b5200000000, 0x0e865a2e00000000,
+ 0x786755b300000000, 0x3a97174e00000000, 0x4c7618d300000000,
+ 0x975379af00000000, 0xe1b2763200000000, 0x2118bb5700000000,
+ 0x57f9b4ca00000000, 0x8cdcd5b600000000, 0xfa3dda2b00000000,
+ 0x0c894e7d00000000, 0x7a6841e000000000, 0xa14d209c00000000,
+ 0xd7ac2f0100000000, 0x1706e26400000000, 0x61e7edf900000000,
+ 0xbac28c8500000000, 0xcc23831800000000, 0x56aba52800000000,
+ 0x204aaab500000000, 0xfb6fcbc900000000, 0x8d8ec45400000000,
+ 0x4d24093100000000, 0x3bc506ac00000000, 0xe0e067d000000000,
+ 0x9601684d00000000, 0x60b5fc1b00000000, 0x1654f38600000000,
+ 0xcd7192fa00000000, 0xbb909d6700000000, 0x7b3a500200000000,
+ 0x0ddb5f9f00000000, 0xd6fe3ee300000000, 0xa01f317e00000000,
+ 0x1318cac200000000, 0x65f9c55f00000000, 0xbedca42300000000,
+ 0xc83dabbe00000000, 0x089766db00000000, 0x7e76694600000000,
+ 0xa553083a00000000, 0xd3b207a700000000, 0x250693f100000000,
+ 0x53e79c6c00000000, 0x88c2fd1000000000, 0xfe23f28d00000000,
+ 0x3e893fe800000000, 0x4868307500000000, 0x934d510900000000,
+ 0xe5ac5e9400000000, 0x7f2478a400000000, 0x09c5773900000000,
+ 0xd2e0164500000000, 0xa40119d800000000, 0x64abd4bd00000000,
+ 0x124adb2000000000, 0xc96fba5c00000000, 0xbf8eb5c100000000,
+ 0x493a219700000000, 0x3fdb2e0a00000000, 0xe4fe4f7600000000,
+ 0x921f40eb00000000, 0x52b58d8e00000000, 0x2454821300000000,
+ 0xff71e36f00000000, 0x8990ecf200000000, 0xcb60ae0f00000000,
+ 0xbd81a19200000000, 0x66a4c0ee00000000, 0x1045cf7300000000,
+ 0xd0ef021600000000, 0xa60e0d8b00000000, 0x7d2b6cf700000000,
+ 0x0bca636a00000000, 0xfd7ef73c00000000, 0x8b9ff8a100000000,
+ 0x50ba99dd00000000, 0x265b964000000000, 0xe6f15b2500000000,
+ 0x901054b800000000, 0x4b3535c400000000, 0x3dd43a5900000000,
+ 0xa75c1c6900000000, 0xd1bd13f400000000, 0x0a98728800000000,
+ 0x7c797d1500000000, 0xbcd3b07000000000, 0xca32bfed00000000,
+ 0x1117de9100000000, 0x67f6d10c00000000, 0x9142455a00000000,
+ 0xe7a34ac700000000, 0x3c862bbb00000000, 0x4a67242600000000,
+ 0x8acde94300000000, 0xfc2ce6de00000000, 0x270987a200000000,
+ 0x51e8883f00000000},
+ {0x0000000000000000, 0xe8dbfbb900000000, 0x91b186a800000000,
+ 0x796a7d1100000000, 0x63657c8a00000000, 0x8bbe873300000000,
+ 0xf2d4fa2200000000, 0x1a0f019b00000000, 0x87cc89cf00000000,
+ 0x6f17727600000000, 0x167d0f6700000000, 0xfea6f4de00000000,
+ 0xe4a9f54500000000, 0x0c720efc00000000, 0x751873ed00000000,
+ 0x9dc3885400000000, 0x4f9f624400000000, 0xa74499fd00000000,
+ 0xde2ee4ec00000000, 0x36f51f5500000000, 0x2cfa1ece00000000,
+ 0xc421e57700000000, 0xbd4b986600000000, 0x559063df00000000,
+ 0xc853eb8b00000000, 0x2088103200000000, 0x59e26d2300000000,
+ 0xb139969a00000000, 0xab36970100000000, 0x43ed6cb800000000,
+ 0x3a8711a900000000, 0xd25cea1000000000, 0x9e3ec58800000000,
+ 0x76e53e3100000000, 0x0f8f432000000000, 0xe754b89900000000,
+ 0xfd5bb90200000000, 0x158042bb00000000, 0x6cea3faa00000000,
+ 0x8431c41300000000, 0x19f24c4700000000, 0xf129b7fe00000000,
+ 0x8843caef00000000, 0x6098315600000000, 0x7a9730cd00000000,
+ 0x924ccb7400000000, 0xeb26b66500000000, 0x03fd4ddc00000000,
+ 0xd1a1a7cc00000000, 0x397a5c7500000000, 0x4010216400000000,
+ 0xa8cbdadd00000000, 0xb2c4db4600000000, 0x5a1f20ff00000000,
+ 0x23755dee00000000, 0xcbaea65700000000, 0x566d2e0300000000,
+ 0xbeb6d5ba00000000, 0xc7dca8ab00000000, 0x2f07531200000000,
+ 0x3508528900000000, 0xddd3a93000000000, 0xa4b9d42100000000,
+ 0x4c622f9800000000, 0x7d7bfbca00000000, 0x95a0007300000000,
+ 0xecca7d6200000000, 0x041186db00000000, 0x1e1e874000000000,
+ 0xf6c57cf900000000, 0x8faf01e800000000, 0x6774fa5100000000,
+ 0xfab7720500000000, 0x126c89bc00000000, 0x6b06f4ad00000000,
+ 0x83dd0f1400000000, 0x99d20e8f00000000, 0x7109f53600000000,
+ 0x0863882700000000, 0xe0b8739e00000000, 0x32e4998e00000000,
+ 0xda3f623700000000, 0xa3551f2600000000, 0x4b8ee49f00000000,
+ 0x5181e50400000000, 0xb95a1ebd00000000, 0xc03063ac00000000,
+ 0x28eb981500000000, 0xb528104100000000, 0x5df3ebf800000000,
+ 0x249996e900000000, 0xcc426d5000000000, 0xd64d6ccb00000000,
+ 0x3e96977200000000, 0x47fcea6300000000, 0xaf2711da00000000,
+ 0xe3453e4200000000, 0x0b9ec5fb00000000, 0x72f4b8ea00000000,
+ 0x9a2f435300000000, 0x802042c800000000, 0x68fbb97100000000,
+ 0x1191c46000000000, 0xf94a3fd900000000, 0x6489b78d00000000,
+ 0x8c524c3400000000, 0xf538312500000000, 0x1de3ca9c00000000,
+ 0x07eccb0700000000, 0xef3730be00000000, 0x965d4daf00000000,
+ 0x7e86b61600000000, 0xacda5c0600000000, 0x4401a7bf00000000,
+ 0x3d6bdaae00000000, 0xd5b0211700000000, 0xcfbf208c00000000,
+ 0x2764db3500000000, 0x5e0ea62400000000, 0xb6d55d9d00000000,
+ 0x2b16d5c900000000, 0xc3cd2e7000000000, 0xbaa7536100000000,
+ 0x527ca8d800000000, 0x4873a94300000000, 0xa0a852fa00000000,
+ 0xd9c22feb00000000, 0x3119d45200000000, 0xbbf0874e00000000,
+ 0x532b7cf700000000, 0x2a4101e600000000, 0xc29afa5f00000000,
+ 0xd895fbc400000000, 0x304e007d00000000, 0x49247d6c00000000,
+ 0xa1ff86d500000000, 0x3c3c0e8100000000, 0xd4e7f53800000000,
+ 0xad8d882900000000, 0x4556739000000000, 0x5f59720b00000000,
+ 0xb78289b200000000, 0xcee8f4a300000000, 0x26330f1a00000000,
+ 0xf46fe50a00000000, 0x1cb41eb300000000, 0x65de63a200000000,
+ 0x8d05981b00000000, 0x970a998000000000, 0x7fd1623900000000,
+ 0x06bb1f2800000000, 0xee60e49100000000, 0x73a36cc500000000,
+ 0x9b78977c00000000, 0xe212ea6d00000000, 0x0ac911d400000000,
+ 0x10c6104f00000000, 0xf81debf600000000, 0x817796e700000000,
+ 0x69ac6d5e00000000, 0x25ce42c600000000, 0xcd15b97f00000000,
+ 0xb47fc46e00000000, 0x5ca43fd700000000, 0x46ab3e4c00000000,
+ 0xae70c5f500000000, 0xd71ab8e400000000, 0x3fc1435d00000000,
+ 0xa202cb0900000000, 0x4ad930b000000000, 0x33b34da100000000,
+ 0xdb68b61800000000, 0xc167b78300000000, 0x29bc4c3a00000000,
+ 0x50d6312b00000000, 0xb80dca9200000000, 0x6a51208200000000,
+ 0x828adb3b00000000, 0xfbe0a62a00000000, 0x133b5d9300000000,
+ 0x09345c0800000000, 0xe1efa7b100000000, 0x9885daa000000000,
+ 0x705e211900000000, 0xed9da94d00000000, 0x054652f400000000,
+ 0x7c2c2fe500000000, 0x94f7d45c00000000, 0x8ef8d5c700000000,
+ 0x66232e7e00000000, 0x1f49536f00000000, 0xf792a8d600000000,
+ 0xc68b7c8400000000, 0x2e50873d00000000, 0x573afa2c00000000,
+ 0xbfe1019500000000, 0xa5ee000e00000000, 0x4d35fbb700000000,
+ 0x345f86a600000000, 0xdc847d1f00000000, 0x4147f54b00000000,
+ 0xa99c0ef200000000, 0xd0f673e300000000, 0x382d885a00000000,
+ 0x222289c100000000, 0xcaf9727800000000, 0xb3930f6900000000,
+ 0x5b48f4d000000000, 0x89141ec000000000, 0x61cfe57900000000,
+ 0x18a5986800000000, 0xf07e63d100000000, 0xea71624a00000000,
+ 0x02aa99f300000000, 0x7bc0e4e200000000, 0x931b1f5b00000000,
+ 0x0ed8970f00000000, 0xe6036cb600000000, 0x9f6911a700000000,
+ 0x77b2ea1e00000000, 0x6dbdeb8500000000, 0x8566103c00000000,
+ 0xfc0c6d2d00000000, 0x14d7969400000000, 0x58b5b90c00000000,
+ 0xb06e42b500000000, 0xc9043fa400000000, 0x21dfc41d00000000,
+ 0x3bd0c58600000000, 0xd30b3e3f00000000, 0xaa61432e00000000,
+ 0x42bab89700000000, 0xdf7930c300000000, 0x37a2cb7a00000000,
+ 0x4ec8b66b00000000, 0xa6134dd200000000, 0xbc1c4c4900000000,
+ 0x54c7b7f000000000, 0x2dadcae100000000, 0xc576315800000000,
+ 0x172adb4800000000, 0xfff120f100000000, 0x869b5de000000000,
+ 0x6e40a65900000000, 0x744fa7c200000000, 0x9c945c7b00000000,
+ 0xe5fe216a00000000, 0x0d25dad300000000, 0x90e6528700000000,
+ 0x783da93e00000000, 0x0157d42f00000000, 0xe98c2f9600000000,
+ 0xf3832e0d00000000, 0x1b58d5b400000000, 0x6232a8a500000000,
+ 0x8ae9531c00000000},
+ {0x0000000000000000, 0x919168ae00000000, 0x6325a08700000000,
+ 0xf2b4c82900000000, 0x874c31d400000000, 0x16dd597a00000000,
+ 0xe469915300000000, 0x75f8f9fd00000000, 0x4f9f137300000000,
+ 0xde0e7bdd00000000, 0x2cbab3f400000000, 0xbd2bdb5a00000000,
+ 0xc8d322a700000000, 0x59424a0900000000, 0xabf6822000000000,
+ 0x3a67ea8e00000000, 0x9e3e27e600000000, 0x0faf4f4800000000,
+ 0xfd1b876100000000, 0x6c8aefcf00000000, 0x1972163200000000,
+ 0x88e37e9c00000000, 0x7a57b6b500000000, 0xebc6de1b00000000,
+ 0xd1a1349500000000, 0x40305c3b00000000, 0xb284941200000000,
+ 0x2315fcbc00000000, 0x56ed054100000000, 0xc77c6def00000000,
+ 0x35c8a5c600000000, 0xa459cd6800000000, 0x7d7b3f1700000000,
+ 0xecea57b900000000, 0x1e5e9f9000000000, 0x8fcff73e00000000,
+ 0xfa370ec300000000, 0x6ba6666d00000000, 0x9912ae4400000000,
+ 0x0883c6ea00000000, 0x32e42c6400000000, 0xa37544ca00000000,
+ 0x51c18ce300000000, 0xc050e44d00000000, 0xb5a81db000000000,
+ 0x2439751e00000000, 0xd68dbd3700000000, 0x471cd59900000000,
+ 0xe34518f100000000, 0x72d4705f00000000, 0x8060b87600000000,
+ 0x11f1d0d800000000, 0x6409292500000000, 0xf598418b00000000,
+ 0x072c89a200000000, 0x96bde10c00000000, 0xacda0b8200000000,
+ 0x3d4b632c00000000, 0xcfffab0500000000, 0x5e6ec3ab00000000,
+ 0x2b963a5600000000, 0xba0752f800000000, 0x48b39ad100000000,
+ 0xd922f27f00000000, 0xfaf67e2e00000000, 0x6b67168000000000,
+ 0x99d3dea900000000, 0x0842b60700000000, 0x7dba4ffa00000000,
+ 0xec2b275400000000, 0x1e9fef7d00000000, 0x8f0e87d300000000,
+ 0xb5696d5d00000000, 0x24f805f300000000, 0xd64ccdda00000000,
+ 0x47dda57400000000, 0x32255c8900000000, 0xa3b4342700000000,
+ 0x5100fc0e00000000, 0xc09194a000000000, 0x64c859c800000000,
+ 0xf559316600000000, 0x07edf94f00000000, 0x967c91e100000000,
+ 0xe384681c00000000, 0x721500b200000000, 0x80a1c89b00000000,
+ 0x1130a03500000000, 0x2b574abb00000000, 0xbac6221500000000,
+ 0x4872ea3c00000000, 0xd9e3829200000000, 0xac1b7b6f00000000,
+ 0x3d8a13c100000000, 0xcf3edbe800000000, 0x5eafb34600000000,
+ 0x878d413900000000, 0x161c299700000000, 0xe4a8e1be00000000,
+ 0x7539891000000000, 0x00c170ed00000000, 0x9150184300000000,
+ 0x63e4d06a00000000, 0xf275b8c400000000, 0xc812524a00000000,
+ 0x59833ae400000000, 0xab37f2cd00000000, 0x3aa69a6300000000,
+ 0x4f5e639e00000000, 0xdecf0b3000000000, 0x2c7bc31900000000,
+ 0xbdeaabb700000000, 0x19b366df00000000, 0x88220e7100000000,
+ 0x7a96c65800000000, 0xeb07aef600000000, 0x9eff570b00000000,
+ 0x0f6e3fa500000000, 0xfddaf78c00000000, 0x6c4b9f2200000000,
+ 0x562c75ac00000000, 0xc7bd1d0200000000, 0x3509d52b00000000,
+ 0xa498bd8500000000, 0xd160447800000000, 0x40f12cd600000000,
+ 0xb245e4ff00000000, 0x23d48c5100000000, 0xf4edfd5c00000000,
+ 0x657c95f200000000, 0x97c85ddb00000000, 0x0659357500000000,
+ 0x73a1cc8800000000, 0xe230a42600000000, 0x10846c0f00000000,
+ 0x811504a100000000, 0xbb72ee2f00000000, 0x2ae3868100000000,
+ 0xd8574ea800000000, 0x49c6260600000000, 0x3c3edffb00000000,
+ 0xadafb75500000000, 0x5f1b7f7c00000000, 0xce8a17d200000000,
+ 0x6ad3daba00000000, 0xfb42b21400000000, 0x09f67a3d00000000,
+ 0x9867129300000000, 0xed9feb6e00000000, 0x7c0e83c000000000,
+ 0x8eba4be900000000, 0x1f2b234700000000, 0x254cc9c900000000,
+ 0xb4dda16700000000, 0x4669694e00000000, 0xd7f801e000000000,
+ 0xa200f81d00000000, 0x339190b300000000, 0xc125589a00000000,
+ 0x50b4303400000000, 0x8996c24b00000000, 0x1807aae500000000,
+ 0xeab362cc00000000, 0x7b220a6200000000, 0x0edaf39f00000000,
+ 0x9f4b9b3100000000, 0x6dff531800000000, 0xfc6e3bb600000000,
+ 0xc609d13800000000, 0x5798b99600000000, 0xa52c71bf00000000,
+ 0x34bd191100000000, 0x4145e0ec00000000, 0xd0d4884200000000,
+ 0x2260406b00000000, 0xb3f128c500000000, 0x17a8e5ad00000000,
+ 0x86398d0300000000, 0x748d452a00000000, 0xe51c2d8400000000,
+ 0x90e4d47900000000, 0x0175bcd700000000, 0xf3c174fe00000000,
+ 0x62501c5000000000, 0x5837f6de00000000, 0xc9a69e7000000000,
+ 0x3b12565900000000, 0xaa833ef700000000, 0xdf7bc70a00000000,
+ 0x4eeaafa400000000, 0xbc5e678d00000000, 0x2dcf0f2300000000,
+ 0x0e1b837200000000, 0x9f8aebdc00000000, 0x6d3e23f500000000,
+ 0xfcaf4b5b00000000, 0x8957b2a600000000, 0x18c6da0800000000,
+ 0xea72122100000000, 0x7be37a8f00000000, 0x4184900100000000,
+ 0xd015f8af00000000, 0x22a1308600000000, 0xb330582800000000,
+ 0xc6c8a1d500000000, 0x5759c97b00000000, 0xa5ed015200000000,
+ 0x347c69fc00000000, 0x9025a49400000000, 0x01b4cc3a00000000,
+ 0xf300041300000000, 0x62916cbd00000000, 0x1769954000000000,
+ 0x86f8fdee00000000, 0x744c35c700000000, 0xe5dd5d6900000000,
+ 0xdfbab7e700000000, 0x4e2bdf4900000000, 0xbc9f176000000000,
+ 0x2d0e7fce00000000, 0x58f6863300000000, 0xc967ee9d00000000,
+ 0x3bd326b400000000, 0xaa424e1a00000000, 0x7360bc6500000000,
+ 0xe2f1d4cb00000000, 0x10451ce200000000, 0x81d4744c00000000,
+ 0xf42c8db100000000, 0x65bde51f00000000, 0x97092d3600000000,
+ 0x0698459800000000, 0x3cffaf1600000000, 0xad6ec7b800000000,
+ 0x5fda0f9100000000, 0xce4b673f00000000, 0xbbb39ec200000000,
+ 0x2a22f66c00000000, 0xd8963e4500000000, 0x490756eb00000000,
+ 0xed5e9b8300000000, 0x7ccff32d00000000, 0x8e7b3b0400000000,
+ 0x1fea53aa00000000, 0x6a12aa5700000000, 0xfb83c2f900000000,
+ 0x09370ad000000000, 0x98a6627e00000000, 0xa2c188f000000000,
+ 0x3350e05e00000000, 0xc1e4287700000000, 0x507540d900000000,
+ 0x258db92400000000, 0xb41cd18a00000000, 0x46a819a300000000,
+ 0xd739710d00000000}};
+
+#else /* W == 4 */
+
+local const z_crc_t FAR crc_braid_table[][256] = {
+ {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa,
+ 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b,
+ 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232,
+ 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8,
+ 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e,
+ 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa,
+ 0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b,
+ 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f,
+ 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719,
+ 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3,
+ 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa,
+ 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b,
+ 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed,
+ 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89,
+ 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25,
+ 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041,
+ 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c,
+ 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed,
+ 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4,
+ 0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758,
+ 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e,
+ 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a,
+ 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed,
+ 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889,
+ 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df,
+ 0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544,
+ 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d,
+ 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c,
+ 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1,
+ 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95,
+ 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839,
+ 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d,
+ 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976,
+ 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7,
+ 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be,
+ 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144,
+ 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12,
+ 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376,
+ 0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a,
+ 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e,
+ 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278,
+ 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682,
+ 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b,
+ 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a,
+ 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561,
+ 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05,
+ 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9,
+ 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd,
+ 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0,
+ 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61,
+ 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678,
+ 0x264b06e6},
+ {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413,
+ 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3,
+ 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d,
+ 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653,
+ 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9,
+ 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e,
+ 0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5,
+ 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712,
+ 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8,
+ 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6,
+ 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068,
+ 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8,
+ 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579,
+ 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade,
+ 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37,
+ 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590,
+ 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4,
+ 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64,
+ 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea,
+ 0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678,
+ 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282,
+ 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25,
+ 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102,
+ 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5,
+ 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f,
+ 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146,
+ 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8,
+ 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08,
+ 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c,
+ 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b,
+ 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972,
+ 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5,
+ 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d,
+ 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd,
+ 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833,
+ 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d,
+ 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7,
+ 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60,
+ 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2,
+ 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105,
+ 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff,
+ 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1,
+ 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f,
+ 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf,
+ 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617,
+ 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0,
+ 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959,
+ 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe,
+ 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca,
+ 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a,
+ 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184,
+ 0x92364a30},
+ {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216,
+ 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8,
+ 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170,
+ 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035,
+ 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6,
+ 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145,
+ 0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d,
+ 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e,
+ 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d,
+ 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408,
+ 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0,
+ 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e,
+ 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c,
+ 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf,
+ 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a,
+ 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9,
+ 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1,
+ 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f,
+ 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987,
+ 0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4,
+ 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37,
+ 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84,
+ 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca,
+ 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79,
+ 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba,
+ 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d,
+ 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5,
+ 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b,
+ 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643,
+ 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0,
+ 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525,
+ 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496,
+ 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8,
+ 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026,
+ 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e,
+ 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db,
+ 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118,
+ 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab,
+ 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf,
+ 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c,
+ 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf,
+ 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a,
+ 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32,
+ 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec,
+ 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82,
+ 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31,
+ 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4,
+ 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957,
+ 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f,
+ 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1,
+ 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869,
+ 0xe4c4abcc},
+ {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0,
+ 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271,
+ 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61,
+ 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52,
+ 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43,
+ 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333,
+ 0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64,
+ 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314,
+ 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205,
+ 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136,
+ 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26,
+ 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997,
+ 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849,
+ 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739,
+ 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8,
+ 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98,
+ 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b,
+ 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba,
+ 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa,
+ 0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d,
+ 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c,
+ 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc,
+ 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af,
+ 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf,
+ 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce,
+ 0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922,
+ 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532,
+ 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183,
+ 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710,
+ 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860,
+ 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1,
+ 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1,
+ 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956,
+ 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7,
+ 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7,
+ 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4,
+ 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5,
+ 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5,
+ 0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb,
+ 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb,
+ 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da,
+ 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9,
+ 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9,
+ 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48,
+ 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df,
+ 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af,
+ 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e,
+ 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e,
+ 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d,
+ 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c,
+ 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c,
+ 0xca64c78c}};
+
+local const z_word_t FAR crc_braid_big_table[][256] = {
+ {0x00000000, 0xb029603d, 0x6053c07a, 0xd07aa047, 0xc0a680f5,
+ 0x708fe0c8, 0xa0f5408f, 0x10dc20b2, 0xc14b7030, 0x7162100d,
+ 0xa118b04a, 0x1131d077, 0x01edf0c5, 0xb1c490f8, 0x61be30bf,
+ 0xd1975082, 0x8297e060, 0x32be805d, 0xe2c4201a, 0x52ed4027,
+ 0x42316095, 0xf21800a8, 0x2262a0ef, 0x924bc0d2, 0x43dc9050,
+ 0xf3f5f06d, 0x238f502a, 0x93a63017, 0x837a10a5, 0x33537098,
+ 0xe329d0df, 0x5300b0e2, 0x042fc1c1, 0xb406a1fc, 0x647c01bb,
+ 0xd4556186, 0xc4894134, 0x74a02109, 0xa4da814e, 0x14f3e173,
+ 0xc564b1f1, 0x754dd1cc, 0xa537718b, 0x151e11b6, 0x05c23104,
+ 0xb5eb5139, 0x6591f17e, 0xd5b89143, 0x86b821a1, 0x3691419c,
+ 0xe6ebe1db, 0x56c281e6, 0x461ea154, 0xf637c169, 0x264d612e,
+ 0x96640113, 0x47f35191, 0xf7da31ac, 0x27a091eb, 0x9789f1d6,
+ 0x8755d164, 0x377cb159, 0xe706111e, 0x572f7123, 0x4958f358,
+ 0xf9719365, 0x290b3322, 0x9922531f, 0x89fe73ad, 0x39d71390,
+ 0xe9adb3d7, 0x5984d3ea, 0x88138368, 0x383ae355, 0xe8404312,
+ 0x5869232f, 0x48b5039d, 0xf89c63a0, 0x28e6c3e7, 0x98cfa3da,
+ 0xcbcf1338, 0x7be67305, 0xab9cd342, 0x1bb5b37f, 0x0b6993cd,
+ 0xbb40f3f0, 0x6b3a53b7, 0xdb13338a, 0x0a846308, 0xbaad0335,
+ 0x6ad7a372, 0xdafec34f, 0xca22e3fd, 0x7a0b83c0, 0xaa712387,
+ 0x1a5843ba, 0x4d773299, 0xfd5e52a4, 0x2d24f2e3, 0x9d0d92de,
+ 0x8dd1b26c, 0x3df8d251, 0xed827216, 0x5dab122b, 0x8c3c42a9,
+ 0x3c152294, 0xec6f82d3, 0x5c46e2ee, 0x4c9ac25c, 0xfcb3a261,
+ 0x2cc90226, 0x9ce0621b, 0xcfe0d2f9, 0x7fc9b2c4, 0xafb31283,
+ 0x1f9a72be, 0x0f46520c, 0xbf6f3231, 0x6f159276, 0xdf3cf24b,
+ 0x0eaba2c9, 0xbe82c2f4, 0x6ef862b3, 0xded1028e, 0xce0d223c,
+ 0x7e244201, 0xae5ee246, 0x1e77827b, 0x92b0e6b1, 0x2299868c,
+ 0xf2e326cb, 0x42ca46f6, 0x52166644, 0xe23f0679, 0x3245a63e,
+ 0x826cc603, 0x53fb9681, 0xe3d2f6bc, 0x33a856fb, 0x838136c6,
+ 0x935d1674, 0x23747649, 0xf30ed60e, 0x4327b633, 0x102706d1,
+ 0xa00e66ec, 0x7074c6ab, 0xc05da696, 0xd0818624, 0x60a8e619,
+ 0xb0d2465e, 0x00fb2663, 0xd16c76e1, 0x614516dc, 0xb13fb69b,
+ 0x0116d6a6, 0x11caf614, 0xa1e39629, 0x7199366e, 0xc1b05653,
+ 0x969f2770, 0x26b6474d, 0xf6cce70a, 0x46e58737, 0x5639a785,
+ 0xe610c7b8, 0x366a67ff, 0x864307c2, 0x57d45740, 0xe7fd377d,
+ 0x3787973a, 0x87aef707, 0x9772d7b5, 0x275bb788, 0xf72117cf,
+ 0x470877f2, 0x1408c710, 0xa421a72d, 0x745b076a, 0xc4726757,
+ 0xd4ae47e5, 0x648727d8, 0xb4fd879f, 0x04d4e7a2, 0xd543b720,
+ 0x656ad71d, 0xb510775a, 0x05391767, 0x15e537d5, 0xa5cc57e8,
+ 0x75b6f7af, 0xc59f9792, 0xdbe815e9, 0x6bc175d4, 0xbbbbd593,
+ 0x0b92b5ae, 0x1b4e951c, 0xab67f521, 0x7b1d5566, 0xcb34355b,
+ 0x1aa365d9, 0xaa8a05e4, 0x7af0a5a3, 0xcad9c59e, 0xda05e52c,
+ 0x6a2c8511, 0xba562556, 0x0a7f456b, 0x597ff589, 0xe95695b4,
+ 0x392c35f3, 0x890555ce, 0x99d9757c, 0x29f01541, 0xf98ab506,
+ 0x49a3d53b, 0x983485b9, 0x281de584, 0xf86745c3, 0x484e25fe,
+ 0x5892054c, 0xe8bb6571, 0x38c1c536, 0x88e8a50b, 0xdfc7d428,
+ 0x6feeb415, 0xbf941452, 0x0fbd746f, 0x1f6154dd, 0xaf4834e0,
+ 0x7f3294a7, 0xcf1bf49a, 0x1e8ca418, 0xaea5c425, 0x7edf6462,
+ 0xcef6045f, 0xde2a24ed, 0x6e0344d0, 0xbe79e497, 0x0e5084aa,
+ 0x5d503448, 0xed795475, 0x3d03f432, 0x8d2a940f, 0x9df6b4bd,
+ 0x2ddfd480, 0xfda574c7, 0x4d8c14fa, 0x9c1b4478, 0x2c322445,
+ 0xfc488402, 0x4c61e43f, 0x5cbdc48d, 0xec94a4b0, 0x3cee04f7,
+ 0x8cc764ca},
+ {0x00000000, 0xa5d35ccb, 0x0ba1c84d, 0xae729486, 0x1642919b,
+ 0xb391cd50, 0x1de359d6, 0xb830051d, 0x6d8253ec, 0xc8510f27,
+ 0x66239ba1, 0xc3f0c76a, 0x7bc0c277, 0xde139ebc, 0x70610a3a,
+ 0xd5b256f1, 0x9b02d603, 0x3ed18ac8, 0x90a31e4e, 0x35704285,
+ 0x8d404798, 0x28931b53, 0x86e18fd5, 0x2332d31e, 0xf68085ef,
+ 0x5353d924, 0xfd214da2, 0x58f21169, 0xe0c21474, 0x451148bf,
+ 0xeb63dc39, 0x4eb080f2, 0x3605ac07, 0x93d6f0cc, 0x3da4644a,
+ 0x98773881, 0x20473d9c, 0x85946157, 0x2be6f5d1, 0x8e35a91a,
+ 0x5b87ffeb, 0xfe54a320, 0x502637a6, 0xf5f56b6d, 0x4dc56e70,
+ 0xe81632bb, 0x4664a63d, 0xe3b7faf6, 0xad077a04, 0x08d426cf,
+ 0xa6a6b249, 0x0375ee82, 0xbb45eb9f, 0x1e96b754, 0xb0e423d2,
+ 0x15377f19, 0xc08529e8, 0x65567523, 0xcb24e1a5, 0x6ef7bd6e,
+ 0xd6c7b873, 0x7314e4b8, 0xdd66703e, 0x78b52cf5, 0x6c0a580f,
+ 0xc9d904c4, 0x67ab9042, 0xc278cc89, 0x7a48c994, 0xdf9b955f,
+ 0x71e901d9, 0xd43a5d12, 0x01880be3, 0xa45b5728, 0x0a29c3ae,
+ 0xaffa9f65, 0x17ca9a78, 0xb219c6b3, 0x1c6b5235, 0xb9b80efe,
+ 0xf7088e0c, 0x52dbd2c7, 0xfca94641, 0x597a1a8a, 0xe14a1f97,
+ 0x4499435c, 0xeaebd7da, 0x4f388b11, 0x9a8adde0, 0x3f59812b,
+ 0x912b15ad, 0x34f84966, 0x8cc84c7b, 0x291b10b0, 0x87698436,
+ 0x22bad8fd, 0x5a0ff408, 0xffdca8c3, 0x51ae3c45, 0xf47d608e,
+ 0x4c4d6593, 0xe99e3958, 0x47ecadde, 0xe23ff115, 0x378da7e4,
+ 0x925efb2f, 0x3c2c6fa9, 0x99ff3362, 0x21cf367f, 0x841c6ab4,
+ 0x2a6efe32, 0x8fbda2f9, 0xc10d220b, 0x64de7ec0, 0xcaacea46,
+ 0x6f7fb68d, 0xd74fb390, 0x729cef5b, 0xdcee7bdd, 0x793d2716,
+ 0xac8f71e7, 0x095c2d2c, 0xa72eb9aa, 0x02fde561, 0xbacde07c,
+ 0x1f1ebcb7, 0xb16c2831, 0x14bf74fa, 0xd814b01e, 0x7dc7ecd5,
+ 0xd3b57853, 0x76662498, 0xce562185, 0x6b857d4e, 0xc5f7e9c8,
+ 0x6024b503, 0xb596e3f2, 0x1045bf39, 0xbe372bbf, 0x1be47774,
+ 0xa3d47269, 0x06072ea2, 0xa875ba24, 0x0da6e6ef, 0x4316661d,
+ 0xe6c53ad6, 0x48b7ae50, 0xed64f29b, 0x5554f786, 0xf087ab4d,
+ 0x5ef53fcb, 0xfb266300, 0x2e9435f1, 0x8b47693a, 0x2535fdbc,
+ 0x80e6a177, 0x38d6a46a, 0x9d05f8a1, 0x33776c27, 0x96a430ec,
+ 0xee111c19, 0x4bc240d2, 0xe5b0d454, 0x4063889f, 0xf8538d82,
+ 0x5d80d149, 0xf3f245cf, 0x56211904, 0x83934ff5, 0x2640133e,
+ 0x883287b8, 0x2de1db73, 0x95d1de6e, 0x300282a5, 0x9e701623,
+ 0x3ba34ae8, 0x7513ca1a, 0xd0c096d1, 0x7eb20257, 0xdb615e9c,
+ 0x63515b81, 0xc682074a, 0x68f093cc, 0xcd23cf07, 0x189199f6,
+ 0xbd42c53d, 0x133051bb, 0xb6e30d70, 0x0ed3086d, 0xab0054a6,
+ 0x0572c020, 0xa0a19ceb, 0xb41ee811, 0x11cdb4da, 0xbfbf205c,
+ 0x1a6c7c97, 0xa25c798a, 0x078f2541, 0xa9fdb1c7, 0x0c2eed0c,
+ 0xd99cbbfd, 0x7c4fe736, 0xd23d73b0, 0x77ee2f7b, 0xcfde2a66,
+ 0x6a0d76ad, 0xc47fe22b, 0x61acbee0, 0x2f1c3e12, 0x8acf62d9,
+ 0x24bdf65f, 0x816eaa94, 0x395eaf89, 0x9c8df342, 0x32ff67c4,
+ 0x972c3b0f, 0x429e6dfe, 0xe74d3135, 0x493fa5b3, 0xececf978,
+ 0x54dcfc65, 0xf10fa0ae, 0x5f7d3428, 0xfaae68e3, 0x821b4416,
+ 0x27c818dd, 0x89ba8c5b, 0x2c69d090, 0x9459d58d, 0x318a8946,
+ 0x9ff81dc0, 0x3a2b410b, 0xef9917fa, 0x4a4a4b31, 0xe438dfb7,
+ 0x41eb837c, 0xf9db8661, 0x5c08daaa, 0xf27a4e2c, 0x57a912e7,
+ 0x19199215, 0xbccacede, 0x12b85a58, 0xb76b0693, 0x0f5b038e,
+ 0xaa885f45, 0x04facbc3, 0xa1299708, 0x749bc1f9, 0xd1489d32,
+ 0x7f3a09b4, 0xdae9557f, 0x62d95062, 0xc70a0ca9, 0x6978982f,
+ 0xccabc4e4},
+ {0x00000000, 0xb40b77a6, 0x29119f97, 0x9d1ae831, 0x13244ff4,
+ 0xa72f3852, 0x3a35d063, 0x8e3ea7c5, 0x674eef33, 0xd3459895,
+ 0x4e5f70a4, 0xfa540702, 0x746aa0c7, 0xc061d761, 0x5d7b3f50,
+ 0xe97048f6, 0xce9cde67, 0x7a97a9c1, 0xe78d41f0, 0x53863656,
+ 0xddb89193, 0x69b3e635, 0xf4a90e04, 0x40a279a2, 0xa9d23154,
+ 0x1dd946f2, 0x80c3aec3, 0x34c8d965, 0xbaf67ea0, 0x0efd0906,
+ 0x93e7e137, 0x27ec9691, 0x9c39bdcf, 0x2832ca69, 0xb5282258,
+ 0x012355fe, 0x8f1df23b, 0x3b16859d, 0xa60c6dac, 0x12071a0a,
+ 0xfb7752fc, 0x4f7c255a, 0xd266cd6b, 0x666dbacd, 0xe8531d08,
+ 0x5c586aae, 0xc142829f, 0x7549f539, 0x52a563a8, 0xe6ae140e,
+ 0x7bb4fc3f, 0xcfbf8b99, 0x41812c5c, 0xf58a5bfa, 0x6890b3cb,
+ 0xdc9bc46d, 0x35eb8c9b, 0x81e0fb3d, 0x1cfa130c, 0xa8f164aa,
+ 0x26cfc36f, 0x92c4b4c9, 0x0fde5cf8, 0xbbd52b5e, 0x79750b44,
+ 0xcd7e7ce2, 0x506494d3, 0xe46fe375, 0x6a5144b0, 0xde5a3316,
+ 0x4340db27, 0xf74bac81, 0x1e3be477, 0xaa3093d1, 0x372a7be0,
+ 0x83210c46, 0x0d1fab83, 0xb914dc25, 0x240e3414, 0x900543b2,
+ 0xb7e9d523, 0x03e2a285, 0x9ef84ab4, 0x2af33d12, 0xa4cd9ad7,
+ 0x10c6ed71, 0x8ddc0540, 0x39d772e6, 0xd0a73a10, 0x64ac4db6,
+ 0xf9b6a587, 0x4dbdd221, 0xc38375e4, 0x77880242, 0xea92ea73,
+ 0x5e999dd5, 0xe54cb68b, 0x5147c12d, 0xcc5d291c, 0x78565eba,
+ 0xf668f97f, 0x42638ed9, 0xdf7966e8, 0x6b72114e, 0x820259b8,
+ 0x36092e1e, 0xab13c62f, 0x1f18b189, 0x9126164c, 0x252d61ea,
+ 0xb83789db, 0x0c3cfe7d, 0x2bd068ec, 0x9fdb1f4a, 0x02c1f77b,
+ 0xb6ca80dd, 0x38f42718, 0x8cff50be, 0x11e5b88f, 0xa5eecf29,
+ 0x4c9e87df, 0xf895f079, 0x658f1848, 0xd1846fee, 0x5fbac82b,
+ 0xebb1bf8d, 0x76ab57bc, 0xc2a0201a, 0xf2ea1688, 0x46e1612e,
+ 0xdbfb891f, 0x6ff0feb9, 0xe1ce597c, 0x55c52eda, 0xc8dfc6eb,
+ 0x7cd4b14d, 0x95a4f9bb, 0x21af8e1d, 0xbcb5662c, 0x08be118a,
+ 0x8680b64f, 0x328bc1e9, 0xaf9129d8, 0x1b9a5e7e, 0x3c76c8ef,
+ 0x887dbf49, 0x15675778, 0xa16c20de, 0x2f52871b, 0x9b59f0bd,
+ 0x0643188c, 0xb2486f2a, 0x5b3827dc, 0xef33507a, 0x7229b84b,
+ 0xc622cfed, 0x481c6828, 0xfc171f8e, 0x610df7bf, 0xd5068019,
+ 0x6ed3ab47, 0xdad8dce1, 0x47c234d0, 0xf3c94376, 0x7df7e4b3,
+ 0xc9fc9315, 0x54e67b24, 0xe0ed0c82, 0x099d4474, 0xbd9633d2,
+ 0x208cdbe3, 0x9487ac45, 0x1ab90b80, 0xaeb27c26, 0x33a89417,
+ 0x87a3e3b1, 0xa04f7520, 0x14440286, 0x895eeab7, 0x3d559d11,
+ 0xb36b3ad4, 0x07604d72, 0x9a7aa543, 0x2e71d2e5, 0xc7019a13,
+ 0x730aedb5, 0xee100584, 0x5a1b7222, 0xd425d5e7, 0x602ea241,
+ 0xfd344a70, 0x493f3dd6, 0x8b9f1dcc, 0x3f946a6a, 0xa28e825b,
+ 0x1685f5fd, 0x98bb5238, 0x2cb0259e, 0xb1aacdaf, 0x05a1ba09,
+ 0xecd1f2ff, 0x58da8559, 0xc5c06d68, 0x71cb1ace, 0xfff5bd0b,
+ 0x4bfecaad, 0xd6e4229c, 0x62ef553a, 0x4503c3ab, 0xf108b40d,
+ 0x6c125c3c, 0xd8192b9a, 0x56278c5f, 0xe22cfbf9, 0x7f3613c8,
+ 0xcb3d646e, 0x224d2c98, 0x96465b3e, 0x0b5cb30f, 0xbf57c4a9,
+ 0x3169636c, 0x856214ca, 0x1878fcfb, 0xac738b5d, 0x17a6a003,
+ 0xa3add7a5, 0x3eb73f94, 0x8abc4832, 0x0482eff7, 0xb0899851,
+ 0x2d937060, 0x999807c6, 0x70e84f30, 0xc4e33896, 0x59f9d0a7,
+ 0xedf2a701, 0x63cc00c4, 0xd7c77762, 0x4add9f53, 0xfed6e8f5,
+ 0xd93a7e64, 0x6d3109c2, 0xf02be1f3, 0x44209655, 0xca1e3190,
+ 0x7e154636, 0xe30fae07, 0x5704d9a1, 0xbe749157, 0x0a7fe6f1,
+ 0x97650ec0, 0x236e7966, 0xad50dea3, 0x195ba905, 0x84414134,
+ 0x304a3692},
+ {0x00000000, 0x9e00aacc, 0x7d072542, 0xe3078f8e, 0xfa0e4a84,
+ 0x640ee048, 0x87096fc6, 0x1909c50a, 0xb51be5d3, 0x2b1b4f1f,
+ 0xc81cc091, 0x561c6a5d, 0x4f15af57, 0xd115059b, 0x32128a15,
+ 0xac1220d9, 0x2b31bb7c, 0xb53111b0, 0x56369e3e, 0xc83634f2,
+ 0xd13ff1f8, 0x4f3f5b34, 0xac38d4ba, 0x32387e76, 0x9e2a5eaf,
+ 0x002af463, 0xe32d7bed, 0x7d2dd121, 0x6424142b, 0xfa24bee7,
+ 0x19233169, 0x87239ba5, 0x566276f9, 0xc862dc35, 0x2b6553bb,
+ 0xb565f977, 0xac6c3c7d, 0x326c96b1, 0xd16b193f, 0x4f6bb3f3,
+ 0xe379932a, 0x7d7939e6, 0x9e7eb668, 0x007e1ca4, 0x1977d9ae,
+ 0x87777362, 0x6470fcec, 0xfa705620, 0x7d53cd85, 0xe3536749,
+ 0x0054e8c7, 0x9e54420b, 0x875d8701, 0x195d2dcd, 0xfa5aa243,
+ 0x645a088f, 0xc8482856, 0x5648829a, 0xb54f0d14, 0x2b4fa7d8,
+ 0x324662d2, 0xac46c81e, 0x4f414790, 0xd141ed5c, 0xedc29d29,
+ 0x73c237e5, 0x90c5b86b, 0x0ec512a7, 0x17ccd7ad, 0x89cc7d61,
+ 0x6acbf2ef, 0xf4cb5823, 0x58d978fa, 0xc6d9d236, 0x25de5db8,
+ 0xbbdef774, 0xa2d7327e, 0x3cd798b2, 0xdfd0173c, 0x41d0bdf0,
+ 0xc6f32655, 0x58f38c99, 0xbbf40317, 0x25f4a9db, 0x3cfd6cd1,
+ 0xa2fdc61d, 0x41fa4993, 0xdffae35f, 0x73e8c386, 0xede8694a,
+ 0x0eefe6c4, 0x90ef4c08, 0x89e68902, 0x17e623ce, 0xf4e1ac40,
+ 0x6ae1068c, 0xbba0ebd0, 0x25a0411c, 0xc6a7ce92, 0x58a7645e,
+ 0x41aea154, 0xdfae0b98, 0x3ca98416, 0xa2a92eda, 0x0ebb0e03,
+ 0x90bba4cf, 0x73bc2b41, 0xedbc818d, 0xf4b54487, 0x6ab5ee4b,
+ 0x89b261c5, 0x17b2cb09, 0x909150ac, 0x0e91fa60, 0xed9675ee,
+ 0x7396df22, 0x6a9f1a28, 0xf49fb0e4, 0x17983f6a, 0x899895a6,
+ 0x258ab57f, 0xbb8a1fb3, 0x588d903d, 0xc68d3af1, 0xdf84fffb,
+ 0x41845537, 0xa283dab9, 0x3c837075, 0xda853b53, 0x4485919f,
+ 0xa7821e11, 0x3982b4dd, 0x208b71d7, 0xbe8bdb1b, 0x5d8c5495,
+ 0xc38cfe59, 0x6f9ede80, 0xf19e744c, 0x1299fbc2, 0x8c99510e,
+ 0x95909404, 0x0b903ec8, 0xe897b146, 0x76971b8a, 0xf1b4802f,
+ 0x6fb42ae3, 0x8cb3a56d, 0x12b30fa1, 0x0bbacaab, 0x95ba6067,
+ 0x76bdefe9, 0xe8bd4525, 0x44af65fc, 0xdaafcf30, 0x39a840be,
+ 0xa7a8ea72, 0xbea12f78, 0x20a185b4, 0xc3a60a3a, 0x5da6a0f6,
+ 0x8ce74daa, 0x12e7e766, 0xf1e068e8, 0x6fe0c224, 0x76e9072e,
+ 0xe8e9ade2, 0x0bee226c, 0x95ee88a0, 0x39fca879, 0xa7fc02b5,
+ 0x44fb8d3b, 0xdafb27f7, 0xc3f2e2fd, 0x5df24831, 0xbef5c7bf,
+ 0x20f56d73, 0xa7d6f6d6, 0x39d65c1a, 0xdad1d394, 0x44d17958,
+ 0x5dd8bc52, 0xc3d8169e, 0x20df9910, 0xbedf33dc, 0x12cd1305,
+ 0x8ccdb9c9, 0x6fca3647, 0xf1ca9c8b, 0xe8c35981, 0x76c3f34d,
+ 0x95c47cc3, 0x0bc4d60f, 0x3747a67a, 0xa9470cb6, 0x4a408338,
+ 0xd44029f4, 0xcd49ecfe, 0x53494632, 0xb04ec9bc, 0x2e4e6370,
+ 0x825c43a9, 0x1c5ce965, 0xff5b66eb, 0x615bcc27, 0x7852092d,
+ 0xe652a3e1, 0x05552c6f, 0x9b5586a3, 0x1c761d06, 0x8276b7ca,
+ 0x61713844, 0xff719288, 0xe6785782, 0x7878fd4e, 0x9b7f72c0,
+ 0x057fd80c, 0xa96df8d5, 0x376d5219, 0xd46add97, 0x4a6a775b,
+ 0x5363b251, 0xcd63189d, 0x2e649713, 0xb0643ddf, 0x6125d083,
+ 0xff257a4f, 0x1c22f5c1, 0x82225f0d, 0x9b2b9a07, 0x052b30cb,
+ 0xe62cbf45, 0x782c1589, 0xd43e3550, 0x4a3e9f9c, 0xa9391012,
+ 0x3739bade, 0x2e307fd4, 0xb030d518, 0x53375a96, 0xcd37f05a,
+ 0x4a146bff, 0xd414c133, 0x37134ebd, 0xa913e471, 0xb01a217b,
+ 0x2e1a8bb7, 0xcd1d0439, 0x531daef5, 0xff0f8e2c, 0x610f24e0,
+ 0x8208ab6e, 0x1c0801a2, 0x0501c4a8, 0x9b016e64, 0x7806e1ea,
+ 0xe6064b26}};
+
+#endif
+
+#endif
+
+#if N == 3
+
+#if W == 8
+
+local const z_crc_t FAR crc_braid_table[][256] = {
+ {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f,
+ 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999,
+ 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee,
+ 0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615,
+ 0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383,
+ 0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb,
+ 0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275,
+ 0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d,
+ 0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b,
+ 0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460,
+ 0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317,
+ 0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1,
+ 0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5,
+ 0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd,
+ 0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04,
+ 0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c,
+ 0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7,
+ 0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11,
+ 0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66,
+ 0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7,
+ 0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871,
+ 0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309,
+ 0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd,
+ 0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85,
+ 0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913,
+ 0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d,
+ 0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a,
+ 0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc,
+ 0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57,
+ 0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f,
+ 0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6,
+ 0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e,
+ 0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f,
+ 0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289,
+ 0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe,
+ 0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05,
+ 0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893,
+ 0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb,
+ 0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0,
+ 0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8,
+ 0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e,
+ 0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5,
+ 0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2,
+ 0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574,
+ 0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5,
+ 0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add,
+ 0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114,
+ 0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c,
+ 0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7,
+ 0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701,
+ 0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076,
+ 0x09cd8551},
+ {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193,
+ 0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2,
+ 0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c,
+ 0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71,
+ 0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a,
+ 0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d,
+ 0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71,
+ 0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436,
+ 0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d,
+ 0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000,
+ 0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae,
+ 0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf,
+ 0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930,
+ 0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277,
+ 0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff,
+ 0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8,
+ 0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef,
+ 0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e,
+ 0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20,
+ 0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95,
+ 0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e,
+ 0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9,
+ 0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d,
+ 0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a,
+ 0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151,
+ 0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4,
+ 0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a,
+ 0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b,
+ 0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c,
+ 0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b,
+ 0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3,
+ 0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4,
+ 0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b,
+ 0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a,
+ 0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4,
+ 0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189,
+ 0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92,
+ 0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5,
+ 0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9,
+ 0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe,
+ 0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5,
+ 0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8,
+ 0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66,
+ 0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707,
+ 0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8,
+ 0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f,
+ 0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707,
+ 0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40,
+ 0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017,
+ 0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876,
+ 0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8,
+ 0x7bc97a0c},
+ {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300,
+ 0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0,
+ 0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80,
+ 0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701,
+ 0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41,
+ 0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81,
+ 0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43,
+ 0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83,
+ 0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3,
+ 0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42,
+ 0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202,
+ 0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2,
+ 0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7,
+ 0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407,
+ 0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47,
+ 0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87,
+ 0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86,
+ 0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46,
+ 0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506,
+ 0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44,
+ 0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704,
+ 0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4,
+ 0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5,
+ 0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505,
+ 0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45,
+ 0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f,
+ 0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f,
+ 0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f,
+ 0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e,
+ 0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e,
+ 0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e,
+ 0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce,
+ 0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c,
+ 0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc,
+ 0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c,
+ 0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d,
+ 0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d,
+ 0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d,
+ 0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88,
+ 0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48,
+ 0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708,
+ 0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89,
+ 0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9,
+ 0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309,
+ 0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb,
+ 0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b,
+ 0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b,
+ 0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b,
+ 0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a,
+ 0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a,
+ 0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a,
+ 0x7851a2ca},
+ {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb,
+ 0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8,
+ 0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0,
+ 0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f,
+ 0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a,
+ 0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf,
+ 0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5,
+ 0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380,
+ 0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815,
+ 0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa,
+ 0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2,
+ 0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1,
+ 0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1,
+ 0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4,
+ 0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa,
+ 0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df,
+ 0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6,
+ 0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5,
+ 0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad,
+ 0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca,
+ 0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f,
+ 0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a,
+ 0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8,
+ 0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d,
+ 0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708,
+ 0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d,
+ 0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865,
+ 0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636,
+ 0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f,
+ 0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a,
+ 0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744,
+ 0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061,
+ 0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0,
+ 0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293,
+ 0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb,
+ 0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874,
+ 0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1,
+ 0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4,
+ 0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f,
+ 0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a,
+ 0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f,
+ 0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120,
+ 0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778,
+ 0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b,
+ 0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a,
+ 0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af,
+ 0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81,
+ 0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4,
+ 0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd,
+ 0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e,
+ 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6,
+ 0x566b6848},
+ {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59,
+ 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4,
+ 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67,
+ 0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef,
+ 0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97,
+ 0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88,
+ 0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687,
+ 0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698,
+ 0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0,
+ 0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068,
+ 0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb,
+ 0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056,
+ 0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016,
+ 0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009,
+ 0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028,
+ 0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037,
+ 0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a,
+ 0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7,
+ 0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054,
+ 0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7,
+ 0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af,
+ 0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0,
+ 0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4,
+ 0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab,
+ 0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3,
+ 0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a,
+ 0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9,
+ 0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54,
+ 0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09,
+ 0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16,
+ 0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37,
+ 0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28,
+ 0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e,
+ 0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3,
+ 0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40,
+ 0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8,
+ 0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0,
+ 0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf,
+ 0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6,
+ 0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9,
+ 0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1,
+ 0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059,
+ 0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca,
+ 0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067,
+ 0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031,
+ 0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e,
+ 0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f,
+ 0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010,
+ 0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d,
+ 0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0,
+ 0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073,
+ 0xd8ac6b35},
+ {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2,
+ 0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd,
+ 0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696,
+ 0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3,
+ 0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f,
+ 0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35,
+ 0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5,
+ 0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f,
+ 0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673,
+ 0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46,
+ 0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d,
+ 0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632,
+ 0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28,
+ 0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192,
+ 0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c,
+ 0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6,
+ 0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0,
+ 0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff,
+ 0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4,
+ 0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95,
+ 0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9,
+ 0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03,
+ 0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7,
+ 0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d,
+ 0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151,
+ 0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808,
+ 0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343,
+ 0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c,
+ 0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a,
+ 0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0,
+ 0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e,
+ 0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594,
+ 0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6,
+ 0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399,
+ 0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2,
+ 0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7,
+ 0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb,
+ 0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571,
+ 0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289,
+ 0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33,
+ 0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f,
+ 0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a,
+ 0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461,
+ 0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e,
+ 0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c,
+ 0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6,
+ 0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918,
+ 0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2,
+ 0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484,
+ 0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb,
+ 0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0,
+ 0xa140efa8},
+ {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706,
+ 0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed,
+ 0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289,
+ 0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a,
+ 0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214,
+ 0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3,
+ 0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3,
+ 0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254,
+ 0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a,
+ 0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9,
+ 0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad,
+ 0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746,
+ 0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060,
+ 0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187,
+ 0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef,
+ 0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408,
+ 0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e,
+ 0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495,
+ 0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1,
+ 0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532,
+ 0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c,
+ 0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb,
+ 0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb,
+ 0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c,
+ 0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42,
+ 0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060,
+ 0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04,
+ 0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef,
+ 0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99,
+ 0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e,
+ 0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16,
+ 0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1,
+ 0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7,
+ 0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c,
+ 0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38,
+ 0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb,
+ 0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5,
+ 0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42,
+ 0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62,
+ 0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85,
+ 0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb,
+ 0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18,
+ 0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c,
+ 0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997,
+ 0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1,
+ 0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36,
+ 0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e,
+ 0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9,
+ 0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf,
+ 0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24,
+ 0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040,
+ 0x917cd6a1},
+ {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf,
+ 0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd,
+ 0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896,
+ 0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9,
+ 0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3,
+ 0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f,
+ 0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d,
+ 0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1,
+ 0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab,
+ 0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4,
+ 0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f,
+ 0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d,
+ 0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4,
+ 0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978,
+ 0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad,
+ 0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621,
+ 0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46,
+ 0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854,
+ 0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f,
+ 0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a,
+ 0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890,
+ 0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c,
+ 0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4,
+ 0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238,
+ 0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622,
+ 0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab,
+ 0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0,
+ 0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2,
+ 0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295,
+ 0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19,
+ 0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc,
+ 0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140,
+ 0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd,
+ 0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf,
+ 0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184,
+ 0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb,
+ 0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1,
+ 0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d,
+ 0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb,
+ 0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257,
+ 0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d,
+ 0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22,
+ 0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069,
+ 0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b,
+ 0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6,
+ 0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a,
+ 0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf,
+ 0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33,
+ 0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254,
+ 0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146,
+ 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d,
+ 0x18ba364e}};
+
+local const z_word_t FAR crc_braid_big_table[][256] = {
+ {0x0000000000000000, 0x43cba68700000000, 0xc7903cd400000000,
+ 0x845b9a5300000000, 0xcf27087300000000, 0x8cecaef400000000,
+ 0x08b734a700000000, 0x4b7c922000000000, 0x9e4f10e600000000,
+ 0xdd84b66100000000, 0x59df2c3200000000, 0x1a148ab500000000,
+ 0x5168189500000000, 0x12a3be1200000000, 0x96f8244100000000,
+ 0xd53382c600000000, 0x7d99511700000000, 0x3e52f79000000000,
+ 0xba096dc300000000, 0xf9c2cb4400000000, 0xb2be596400000000,
+ 0xf175ffe300000000, 0x752e65b000000000, 0x36e5c33700000000,
+ 0xe3d641f100000000, 0xa01de77600000000, 0x24467d2500000000,
+ 0x678ddba200000000, 0x2cf1498200000000, 0x6f3aef0500000000,
+ 0xeb61755600000000, 0xa8aad3d100000000, 0xfa32a32e00000000,
+ 0xb9f905a900000000, 0x3da29ffa00000000, 0x7e69397d00000000,
+ 0x3515ab5d00000000, 0x76de0dda00000000, 0xf285978900000000,
+ 0xb14e310e00000000, 0x647db3c800000000, 0x27b6154f00000000,
+ 0xa3ed8f1c00000000, 0xe026299b00000000, 0xab5abbbb00000000,
+ 0xe8911d3c00000000, 0x6cca876f00000000, 0x2f0121e800000000,
+ 0x87abf23900000000, 0xc46054be00000000, 0x403bceed00000000,
+ 0x03f0686a00000000, 0x488cfa4a00000000, 0x0b475ccd00000000,
+ 0x8f1cc69e00000000, 0xccd7601900000000, 0x19e4e2df00000000,
+ 0x5a2f445800000000, 0xde74de0b00000000, 0x9dbf788c00000000,
+ 0xd6c3eaac00000000, 0x95084c2b00000000, 0x1153d67800000000,
+ 0x529870ff00000000, 0xf465465d00000000, 0xb7aee0da00000000,
+ 0x33f57a8900000000, 0x703edc0e00000000, 0x3b424e2e00000000,
+ 0x7889e8a900000000, 0xfcd272fa00000000, 0xbf19d47d00000000,
+ 0x6a2a56bb00000000, 0x29e1f03c00000000, 0xadba6a6f00000000,
+ 0xee71cce800000000, 0xa50d5ec800000000, 0xe6c6f84f00000000,
+ 0x629d621c00000000, 0x2156c49b00000000, 0x89fc174a00000000,
+ 0xca37b1cd00000000, 0x4e6c2b9e00000000, 0x0da78d1900000000,
+ 0x46db1f3900000000, 0x0510b9be00000000, 0x814b23ed00000000,
+ 0xc280856a00000000, 0x17b307ac00000000, 0x5478a12b00000000,
+ 0xd0233b7800000000, 0x93e89dff00000000, 0xd8940fdf00000000,
+ 0x9b5fa95800000000, 0x1f04330b00000000, 0x5ccf958c00000000,
+ 0x0e57e57300000000, 0x4d9c43f400000000, 0xc9c7d9a700000000,
+ 0x8a0c7f2000000000, 0xc170ed0000000000, 0x82bb4b8700000000,
+ 0x06e0d1d400000000, 0x452b775300000000, 0x9018f59500000000,
+ 0xd3d3531200000000, 0x5788c94100000000, 0x14436fc600000000,
+ 0x5f3ffde600000000, 0x1cf45b6100000000, 0x98afc13200000000,
+ 0xdb6467b500000000, 0x73ceb46400000000, 0x300512e300000000,
+ 0xb45e88b000000000, 0xf7952e3700000000, 0xbce9bc1700000000,
+ 0xff221a9000000000, 0x7b7980c300000000, 0x38b2264400000000,
+ 0xed81a48200000000, 0xae4a020500000000, 0x2a11985600000000,
+ 0x69da3ed100000000, 0x22a6acf100000000, 0x616d0a7600000000,
+ 0xe536902500000000, 0xa6fd36a200000000, 0xe8cb8cba00000000,
+ 0xab002a3d00000000, 0x2f5bb06e00000000, 0x6c9016e900000000,
+ 0x27ec84c900000000, 0x6427224e00000000, 0xe07cb81d00000000,
+ 0xa3b71e9a00000000, 0x76849c5c00000000, 0x354f3adb00000000,
+ 0xb114a08800000000, 0xf2df060f00000000, 0xb9a3942f00000000,
+ 0xfa6832a800000000, 0x7e33a8fb00000000, 0x3df80e7c00000000,
+ 0x9552ddad00000000, 0xd6997b2a00000000, 0x52c2e17900000000,
+ 0x110947fe00000000, 0x5a75d5de00000000, 0x19be735900000000,
+ 0x9de5e90a00000000, 0xde2e4f8d00000000, 0x0b1dcd4b00000000,
+ 0x48d66bcc00000000, 0xcc8df19f00000000, 0x8f46571800000000,
+ 0xc43ac53800000000, 0x87f163bf00000000, 0x03aaf9ec00000000,
+ 0x40615f6b00000000, 0x12f92f9400000000, 0x5132891300000000,
+ 0xd569134000000000, 0x96a2b5c700000000, 0xddde27e700000000,
+ 0x9e15816000000000, 0x1a4e1b3300000000, 0x5985bdb400000000,
+ 0x8cb63f7200000000, 0xcf7d99f500000000, 0x4b2603a600000000,
+ 0x08eda52100000000, 0x4391370100000000, 0x005a918600000000,
+ 0x84010bd500000000, 0xc7caad5200000000, 0x6f607e8300000000,
+ 0x2cabd80400000000, 0xa8f0425700000000, 0xeb3be4d000000000,
+ 0xa04776f000000000, 0xe38cd07700000000, 0x67d74a2400000000,
+ 0x241ceca300000000, 0xf12f6e6500000000, 0xb2e4c8e200000000,
+ 0x36bf52b100000000, 0x7574f43600000000, 0x3e08661600000000,
+ 0x7dc3c09100000000, 0xf9985ac200000000, 0xba53fc4500000000,
+ 0x1caecae700000000, 0x5f656c6000000000, 0xdb3ef63300000000,
+ 0x98f550b400000000, 0xd389c29400000000, 0x9042641300000000,
+ 0x1419fe4000000000, 0x57d258c700000000, 0x82e1da0100000000,
+ 0xc12a7c8600000000, 0x4571e6d500000000, 0x06ba405200000000,
+ 0x4dc6d27200000000, 0x0e0d74f500000000, 0x8a56eea600000000,
+ 0xc99d482100000000, 0x61379bf000000000, 0x22fc3d7700000000,
+ 0xa6a7a72400000000, 0xe56c01a300000000, 0xae10938300000000,
+ 0xeddb350400000000, 0x6980af5700000000, 0x2a4b09d000000000,
+ 0xff788b1600000000, 0xbcb32d9100000000, 0x38e8b7c200000000,
+ 0x7b23114500000000, 0x305f836500000000, 0x739425e200000000,
+ 0xf7cfbfb100000000, 0xb404193600000000, 0xe69c69c900000000,
+ 0xa557cf4e00000000, 0x210c551d00000000, 0x62c7f39a00000000,
+ 0x29bb61ba00000000, 0x6a70c73d00000000, 0xee2b5d6e00000000,
+ 0xade0fbe900000000, 0x78d3792f00000000, 0x3b18dfa800000000,
+ 0xbf4345fb00000000, 0xfc88e37c00000000, 0xb7f4715c00000000,
+ 0xf43fd7db00000000, 0x70644d8800000000, 0x33afeb0f00000000,
+ 0x9b0538de00000000, 0xd8ce9e5900000000, 0x5c95040a00000000,
+ 0x1f5ea28d00000000, 0x542230ad00000000, 0x17e9962a00000000,
+ 0x93b20c7900000000, 0xd079aafe00000000, 0x054a283800000000,
+ 0x46818ebf00000000, 0xc2da14ec00000000, 0x8111b26b00000000,
+ 0xca6d204b00000000, 0x89a686cc00000000, 0x0dfd1c9f00000000,
+ 0x4e36ba1800000000},
+ {0x0000000000000000, 0xe1b652ef00000000, 0x836bd40500000000,
+ 0x62dd86ea00000000, 0x06d7a80b00000000, 0xe761fae400000000,
+ 0x85bc7c0e00000000, 0x640a2ee100000000, 0x0cae511700000000,
+ 0xed1803f800000000, 0x8fc5851200000000, 0x6e73d7fd00000000,
+ 0x0a79f91c00000000, 0xebcfabf300000000, 0x89122d1900000000,
+ 0x68a47ff600000000, 0x185ca32e00000000, 0xf9eaf1c100000000,
+ 0x9b37772b00000000, 0x7a8125c400000000, 0x1e8b0b2500000000,
+ 0xff3d59ca00000000, 0x9de0df2000000000, 0x7c568dcf00000000,
+ 0x14f2f23900000000, 0xf544a0d600000000, 0x9799263c00000000,
+ 0x762f74d300000000, 0x12255a3200000000, 0xf39308dd00000000,
+ 0x914e8e3700000000, 0x70f8dcd800000000, 0x30b8465d00000000,
+ 0xd10e14b200000000, 0xb3d3925800000000, 0x5265c0b700000000,
+ 0x366fee5600000000, 0xd7d9bcb900000000, 0xb5043a5300000000,
+ 0x54b268bc00000000, 0x3c16174a00000000, 0xdda045a500000000,
+ 0xbf7dc34f00000000, 0x5ecb91a000000000, 0x3ac1bf4100000000,
+ 0xdb77edae00000000, 0xb9aa6b4400000000, 0x581c39ab00000000,
+ 0x28e4e57300000000, 0xc952b79c00000000, 0xab8f317600000000,
+ 0x4a39639900000000, 0x2e334d7800000000, 0xcf851f9700000000,
+ 0xad58997d00000000, 0x4ceecb9200000000, 0x244ab46400000000,
+ 0xc5fce68b00000000, 0xa721606100000000, 0x4697328e00000000,
+ 0x229d1c6f00000000, 0xc32b4e8000000000, 0xa1f6c86a00000000,
+ 0x40409a8500000000, 0x60708dba00000000, 0x81c6df5500000000,
+ 0xe31b59bf00000000, 0x02ad0b5000000000, 0x66a725b100000000,
+ 0x8711775e00000000, 0xe5ccf1b400000000, 0x047aa35b00000000,
+ 0x6cdedcad00000000, 0x8d688e4200000000, 0xefb508a800000000,
+ 0x0e035a4700000000, 0x6a0974a600000000, 0x8bbf264900000000,
+ 0xe962a0a300000000, 0x08d4f24c00000000, 0x782c2e9400000000,
+ 0x999a7c7b00000000, 0xfb47fa9100000000, 0x1af1a87e00000000,
+ 0x7efb869f00000000, 0x9f4dd47000000000, 0xfd90529a00000000,
+ 0x1c26007500000000, 0x74827f8300000000, 0x95342d6c00000000,
+ 0xf7e9ab8600000000, 0x165ff96900000000, 0x7255d78800000000,
+ 0x93e3856700000000, 0xf13e038d00000000, 0x1088516200000000,
+ 0x50c8cbe700000000, 0xb17e990800000000, 0xd3a31fe200000000,
+ 0x32154d0d00000000, 0x561f63ec00000000, 0xb7a9310300000000,
+ 0xd574b7e900000000, 0x34c2e50600000000, 0x5c669af000000000,
+ 0xbdd0c81f00000000, 0xdf0d4ef500000000, 0x3ebb1c1a00000000,
+ 0x5ab132fb00000000, 0xbb07601400000000, 0xd9dae6fe00000000,
+ 0x386cb41100000000, 0x489468c900000000, 0xa9223a2600000000,
+ 0xcbffbccc00000000, 0x2a49ee2300000000, 0x4e43c0c200000000,
+ 0xaff5922d00000000, 0xcd2814c700000000, 0x2c9e462800000000,
+ 0x443a39de00000000, 0xa58c6b3100000000, 0xc751eddb00000000,
+ 0x26e7bf3400000000, 0x42ed91d500000000, 0xa35bc33a00000000,
+ 0xc18645d000000000, 0x2030173f00000000, 0x81e66bae00000000,
+ 0x6050394100000000, 0x028dbfab00000000, 0xe33bed4400000000,
+ 0x8731c3a500000000, 0x6687914a00000000, 0x045a17a000000000,
+ 0xe5ec454f00000000, 0x8d483ab900000000, 0x6cfe685600000000,
+ 0x0e23eebc00000000, 0xef95bc5300000000, 0x8b9f92b200000000,
+ 0x6a29c05d00000000, 0x08f446b700000000, 0xe942145800000000,
+ 0x99bac88000000000, 0x780c9a6f00000000, 0x1ad11c8500000000,
+ 0xfb674e6a00000000, 0x9f6d608b00000000, 0x7edb326400000000,
+ 0x1c06b48e00000000, 0xfdb0e66100000000, 0x9514999700000000,
+ 0x74a2cb7800000000, 0x167f4d9200000000, 0xf7c91f7d00000000,
+ 0x93c3319c00000000, 0x7275637300000000, 0x10a8e59900000000,
+ 0xf11eb77600000000, 0xb15e2df300000000, 0x50e87f1c00000000,
+ 0x3235f9f600000000, 0xd383ab1900000000, 0xb78985f800000000,
+ 0x563fd71700000000, 0x34e251fd00000000, 0xd554031200000000,
+ 0xbdf07ce400000000, 0x5c462e0b00000000, 0x3e9ba8e100000000,
+ 0xdf2dfa0e00000000, 0xbb27d4ef00000000, 0x5a91860000000000,
+ 0x384c00ea00000000, 0xd9fa520500000000, 0xa9028edd00000000,
+ 0x48b4dc3200000000, 0x2a695ad800000000, 0xcbdf083700000000,
+ 0xafd526d600000000, 0x4e63743900000000, 0x2cbef2d300000000,
+ 0xcd08a03c00000000, 0xa5acdfca00000000, 0x441a8d2500000000,
+ 0x26c70bcf00000000, 0xc771592000000000, 0xa37b77c100000000,
+ 0x42cd252e00000000, 0x2010a3c400000000, 0xc1a6f12b00000000,
+ 0xe196e61400000000, 0x0020b4fb00000000, 0x62fd321100000000,
+ 0x834b60fe00000000, 0xe7414e1f00000000, 0x06f71cf000000000,
+ 0x642a9a1a00000000, 0x859cc8f500000000, 0xed38b70300000000,
+ 0x0c8ee5ec00000000, 0x6e53630600000000, 0x8fe531e900000000,
+ 0xebef1f0800000000, 0x0a594de700000000, 0x6884cb0d00000000,
+ 0x893299e200000000, 0xf9ca453a00000000, 0x187c17d500000000,
+ 0x7aa1913f00000000, 0x9b17c3d000000000, 0xff1ded3100000000,
+ 0x1eabbfde00000000, 0x7c76393400000000, 0x9dc06bdb00000000,
+ 0xf564142d00000000, 0x14d246c200000000, 0x760fc02800000000,
+ 0x97b992c700000000, 0xf3b3bc2600000000, 0x1205eec900000000,
+ 0x70d8682300000000, 0x916e3acc00000000, 0xd12ea04900000000,
+ 0x3098f2a600000000, 0x5245744c00000000, 0xb3f326a300000000,
+ 0xd7f9084200000000, 0x364f5aad00000000, 0x5492dc4700000000,
+ 0xb5248ea800000000, 0xdd80f15e00000000, 0x3c36a3b100000000,
+ 0x5eeb255b00000000, 0xbf5d77b400000000, 0xdb57595500000000,
+ 0x3ae10bba00000000, 0x583c8d5000000000, 0xb98adfbf00000000,
+ 0xc972036700000000, 0x28c4518800000000, 0x4a19d76200000000,
+ 0xabaf858d00000000, 0xcfa5ab6c00000000, 0x2e13f98300000000,
+ 0x4cce7f6900000000, 0xad782d8600000000, 0xc5dc527000000000,
+ 0x246a009f00000000, 0x46b7867500000000, 0xa701d49a00000000,
+ 0xc30bfa7b00000000, 0x22bda89400000000, 0x40602e7e00000000,
+ 0xa1d67c9100000000},
+ {0x0000000000000000, 0x5880e2d700000000, 0xf106b47400000000,
+ 0xa98656a300000000, 0xe20d68e900000000, 0xba8d8a3e00000000,
+ 0x130bdc9d00000000, 0x4b8b3e4a00000000, 0x851da10900000000,
+ 0xdd9d43de00000000, 0x741b157d00000000, 0x2c9bf7aa00000000,
+ 0x6710c9e000000000, 0x3f902b3700000000, 0x96167d9400000000,
+ 0xce969f4300000000, 0x0a3b421300000000, 0x52bba0c400000000,
+ 0xfb3df66700000000, 0xa3bd14b000000000, 0xe8362afa00000000,
+ 0xb0b6c82d00000000, 0x19309e8e00000000, 0x41b07c5900000000,
+ 0x8f26e31a00000000, 0xd7a601cd00000000, 0x7e20576e00000000,
+ 0x26a0b5b900000000, 0x6d2b8bf300000000, 0x35ab692400000000,
+ 0x9c2d3f8700000000, 0xc4addd5000000000, 0x1476842600000000,
+ 0x4cf666f100000000, 0xe570305200000000, 0xbdf0d28500000000,
+ 0xf67beccf00000000, 0xaefb0e1800000000, 0x077d58bb00000000,
+ 0x5ffdba6c00000000, 0x916b252f00000000, 0xc9ebc7f800000000,
+ 0x606d915b00000000, 0x38ed738c00000000, 0x73664dc600000000,
+ 0x2be6af1100000000, 0x8260f9b200000000, 0xdae01b6500000000,
+ 0x1e4dc63500000000, 0x46cd24e200000000, 0xef4b724100000000,
+ 0xb7cb909600000000, 0xfc40aedc00000000, 0xa4c04c0b00000000,
+ 0x0d461aa800000000, 0x55c6f87f00000000, 0x9b50673c00000000,
+ 0xc3d085eb00000000, 0x6a56d34800000000, 0x32d6319f00000000,
+ 0x795d0fd500000000, 0x21dded0200000000, 0x885bbba100000000,
+ 0xd0db597600000000, 0x28ec084d00000000, 0x706cea9a00000000,
+ 0xd9eabc3900000000, 0x816a5eee00000000, 0xcae160a400000000,
+ 0x9261827300000000, 0x3be7d4d000000000, 0x6367360700000000,
+ 0xadf1a94400000000, 0xf5714b9300000000, 0x5cf71d3000000000,
+ 0x0477ffe700000000, 0x4ffcc1ad00000000, 0x177c237a00000000,
+ 0xbefa75d900000000, 0xe67a970e00000000, 0x22d74a5e00000000,
+ 0x7a57a88900000000, 0xd3d1fe2a00000000, 0x8b511cfd00000000,
+ 0xc0da22b700000000, 0x985ac06000000000, 0x31dc96c300000000,
+ 0x695c741400000000, 0xa7caeb5700000000, 0xff4a098000000000,
+ 0x56cc5f2300000000, 0x0e4cbdf400000000, 0x45c783be00000000,
+ 0x1d47616900000000, 0xb4c137ca00000000, 0xec41d51d00000000,
+ 0x3c9a8c6b00000000, 0x641a6ebc00000000, 0xcd9c381f00000000,
+ 0x951cdac800000000, 0xde97e48200000000, 0x8617065500000000,
+ 0x2f9150f600000000, 0x7711b22100000000, 0xb9872d6200000000,
+ 0xe107cfb500000000, 0x4881991600000000, 0x10017bc100000000,
+ 0x5b8a458b00000000, 0x030aa75c00000000, 0xaa8cf1ff00000000,
+ 0xf20c132800000000, 0x36a1ce7800000000, 0x6e212caf00000000,
+ 0xc7a77a0c00000000, 0x9f2798db00000000, 0xd4aca69100000000,
+ 0x8c2c444600000000, 0x25aa12e500000000, 0x7d2af03200000000,
+ 0xb3bc6f7100000000, 0xeb3c8da600000000, 0x42badb0500000000,
+ 0x1a3a39d200000000, 0x51b1079800000000, 0x0931e54f00000000,
+ 0xa0b7b3ec00000000, 0xf837513b00000000, 0x50d8119a00000000,
+ 0x0858f34d00000000, 0xa1dea5ee00000000, 0xf95e473900000000,
+ 0xb2d5797300000000, 0xea559ba400000000, 0x43d3cd0700000000,
+ 0x1b532fd000000000, 0xd5c5b09300000000, 0x8d45524400000000,
+ 0x24c304e700000000, 0x7c43e63000000000, 0x37c8d87a00000000,
+ 0x6f483aad00000000, 0xc6ce6c0e00000000, 0x9e4e8ed900000000,
+ 0x5ae3538900000000, 0x0263b15e00000000, 0xabe5e7fd00000000,
+ 0xf365052a00000000, 0xb8ee3b6000000000, 0xe06ed9b700000000,
+ 0x49e88f1400000000, 0x11686dc300000000, 0xdffef28000000000,
+ 0x877e105700000000, 0x2ef846f400000000, 0x7678a42300000000,
+ 0x3df39a6900000000, 0x657378be00000000, 0xccf52e1d00000000,
+ 0x9475ccca00000000, 0x44ae95bc00000000, 0x1c2e776b00000000,
+ 0xb5a821c800000000, 0xed28c31f00000000, 0xa6a3fd5500000000,
+ 0xfe231f8200000000, 0x57a5492100000000, 0x0f25abf600000000,
+ 0xc1b334b500000000, 0x9933d66200000000, 0x30b580c100000000,
+ 0x6835621600000000, 0x23be5c5c00000000, 0x7b3ebe8b00000000,
+ 0xd2b8e82800000000, 0x8a380aff00000000, 0x4e95d7af00000000,
+ 0x1615357800000000, 0xbf9363db00000000, 0xe713810c00000000,
+ 0xac98bf4600000000, 0xf4185d9100000000, 0x5d9e0b3200000000,
+ 0x051ee9e500000000, 0xcb8876a600000000, 0x9308947100000000,
+ 0x3a8ec2d200000000, 0x620e200500000000, 0x29851e4f00000000,
+ 0x7105fc9800000000, 0xd883aa3b00000000, 0x800348ec00000000,
+ 0x783419d700000000, 0x20b4fb0000000000, 0x8932ada300000000,
+ 0xd1b24f7400000000, 0x9a39713e00000000, 0xc2b993e900000000,
+ 0x6b3fc54a00000000, 0x33bf279d00000000, 0xfd29b8de00000000,
+ 0xa5a95a0900000000, 0x0c2f0caa00000000, 0x54afee7d00000000,
+ 0x1f24d03700000000, 0x47a432e000000000, 0xee22644300000000,
+ 0xb6a2869400000000, 0x720f5bc400000000, 0x2a8fb91300000000,
+ 0x8309efb000000000, 0xdb890d6700000000, 0x9002332d00000000,
+ 0xc882d1fa00000000, 0x6104875900000000, 0x3984658e00000000,
+ 0xf712facd00000000, 0xaf92181a00000000, 0x06144eb900000000,
+ 0x5e94ac6e00000000, 0x151f922400000000, 0x4d9f70f300000000,
+ 0xe419265000000000, 0xbc99c48700000000, 0x6c429df100000000,
+ 0x34c27f2600000000, 0x9d44298500000000, 0xc5c4cb5200000000,
+ 0x8e4ff51800000000, 0xd6cf17cf00000000, 0x7f49416c00000000,
+ 0x27c9a3bb00000000, 0xe95f3cf800000000, 0xb1dfde2f00000000,
+ 0x1859888c00000000, 0x40d96a5b00000000, 0x0b52541100000000,
+ 0x53d2b6c600000000, 0xfa54e06500000000, 0xa2d402b200000000,
+ 0x6679dfe200000000, 0x3ef93d3500000000, 0x977f6b9600000000,
+ 0xcfff894100000000, 0x8474b70b00000000, 0xdcf455dc00000000,
+ 0x7572037f00000000, 0x2df2e1a800000000, 0xe3647eeb00000000,
+ 0xbbe49c3c00000000, 0x1262ca9f00000000, 0x4ae2284800000000,
+ 0x0169160200000000, 0x59e9f4d500000000, 0xf06fa27600000000,
+ 0xa8ef40a100000000},
+ {0x0000000000000000, 0x463b676500000000, 0x8c76ceca00000000,
+ 0xca4da9af00000000, 0x59ebed4e00000000, 0x1fd08a2b00000000,
+ 0xd59d238400000000, 0x93a644e100000000, 0xb2d6db9d00000000,
+ 0xf4edbcf800000000, 0x3ea0155700000000, 0x789b723200000000,
+ 0xeb3d36d300000000, 0xad0651b600000000, 0x674bf81900000000,
+ 0x21709f7c00000000, 0x25abc6e000000000, 0x6390a18500000000,
+ 0xa9dd082a00000000, 0xefe66f4f00000000, 0x7c402bae00000000,
+ 0x3a7b4ccb00000000, 0xf036e56400000000, 0xb60d820100000000,
+ 0x977d1d7d00000000, 0xd1467a1800000000, 0x1b0bd3b700000000,
+ 0x5d30b4d200000000, 0xce96f03300000000, 0x88ad975600000000,
+ 0x42e03ef900000000, 0x04db599c00000000, 0x0b50fc1a00000000,
+ 0x4d6b9b7f00000000, 0x872632d000000000, 0xc11d55b500000000,
+ 0x52bb115400000000, 0x1480763100000000, 0xdecddf9e00000000,
+ 0x98f6b8fb00000000, 0xb986278700000000, 0xffbd40e200000000,
+ 0x35f0e94d00000000, 0x73cb8e2800000000, 0xe06dcac900000000,
+ 0xa656adac00000000, 0x6c1b040300000000, 0x2a20636600000000,
+ 0x2efb3afa00000000, 0x68c05d9f00000000, 0xa28df43000000000,
+ 0xe4b6935500000000, 0x7710d7b400000000, 0x312bb0d100000000,
+ 0xfb66197e00000000, 0xbd5d7e1b00000000, 0x9c2de16700000000,
+ 0xda16860200000000, 0x105b2fad00000000, 0x566048c800000000,
+ 0xc5c60c2900000000, 0x83fd6b4c00000000, 0x49b0c2e300000000,
+ 0x0f8ba58600000000, 0x16a0f83500000000, 0x509b9f5000000000,
+ 0x9ad636ff00000000, 0xdced519a00000000, 0x4f4b157b00000000,
+ 0x0970721e00000000, 0xc33ddbb100000000, 0x8506bcd400000000,
+ 0xa47623a800000000, 0xe24d44cd00000000, 0x2800ed6200000000,
+ 0x6e3b8a0700000000, 0xfd9dcee600000000, 0xbba6a98300000000,
+ 0x71eb002c00000000, 0x37d0674900000000, 0x330b3ed500000000,
+ 0x753059b000000000, 0xbf7df01f00000000, 0xf946977a00000000,
+ 0x6ae0d39b00000000, 0x2cdbb4fe00000000, 0xe6961d5100000000,
+ 0xa0ad7a3400000000, 0x81dde54800000000, 0xc7e6822d00000000,
+ 0x0dab2b8200000000, 0x4b904ce700000000, 0xd836080600000000,
+ 0x9e0d6f6300000000, 0x5440c6cc00000000, 0x127ba1a900000000,
+ 0x1df0042f00000000, 0x5bcb634a00000000, 0x9186cae500000000,
+ 0xd7bdad8000000000, 0x441be96100000000, 0x02208e0400000000,
+ 0xc86d27ab00000000, 0x8e5640ce00000000, 0xaf26dfb200000000,
+ 0xe91db8d700000000, 0x2350117800000000, 0x656b761d00000000,
+ 0xf6cd32fc00000000, 0xb0f6559900000000, 0x7abbfc3600000000,
+ 0x3c809b5300000000, 0x385bc2cf00000000, 0x7e60a5aa00000000,
+ 0xb42d0c0500000000, 0xf2166b6000000000, 0x61b02f8100000000,
+ 0x278b48e400000000, 0xedc6e14b00000000, 0xabfd862e00000000,
+ 0x8a8d195200000000, 0xccb67e3700000000, 0x06fbd79800000000,
+ 0x40c0b0fd00000000, 0xd366f41c00000000, 0x955d937900000000,
+ 0x5f103ad600000000, 0x192b5db300000000, 0x2c40f16b00000000,
+ 0x6a7b960e00000000, 0xa0363fa100000000, 0xe60d58c400000000,
+ 0x75ab1c2500000000, 0x33907b4000000000, 0xf9ddd2ef00000000,
+ 0xbfe6b58a00000000, 0x9e962af600000000, 0xd8ad4d9300000000,
+ 0x12e0e43c00000000, 0x54db835900000000, 0xc77dc7b800000000,
+ 0x8146a0dd00000000, 0x4b0b097200000000, 0x0d306e1700000000,
+ 0x09eb378b00000000, 0x4fd050ee00000000, 0x859df94100000000,
+ 0xc3a69e2400000000, 0x5000dac500000000, 0x163bbda000000000,
+ 0xdc76140f00000000, 0x9a4d736a00000000, 0xbb3dec1600000000,
+ 0xfd068b7300000000, 0x374b22dc00000000, 0x717045b900000000,
+ 0xe2d6015800000000, 0xa4ed663d00000000, 0x6ea0cf9200000000,
+ 0x289ba8f700000000, 0x27100d7100000000, 0x612b6a1400000000,
+ 0xab66c3bb00000000, 0xed5da4de00000000, 0x7efbe03f00000000,
+ 0x38c0875a00000000, 0xf28d2ef500000000, 0xb4b6499000000000,
+ 0x95c6d6ec00000000, 0xd3fdb18900000000, 0x19b0182600000000,
+ 0x5f8b7f4300000000, 0xcc2d3ba200000000, 0x8a165cc700000000,
+ 0x405bf56800000000, 0x0660920d00000000, 0x02bbcb9100000000,
+ 0x4480acf400000000, 0x8ecd055b00000000, 0xc8f6623e00000000,
+ 0x5b5026df00000000, 0x1d6b41ba00000000, 0xd726e81500000000,
+ 0x911d8f7000000000, 0xb06d100c00000000, 0xf656776900000000,
+ 0x3c1bdec600000000, 0x7a20b9a300000000, 0xe986fd4200000000,
+ 0xafbd9a2700000000, 0x65f0338800000000, 0x23cb54ed00000000,
+ 0x3ae0095e00000000, 0x7cdb6e3b00000000, 0xb696c79400000000,
+ 0xf0ada0f100000000, 0x630be41000000000, 0x2530837500000000,
+ 0xef7d2ada00000000, 0xa9464dbf00000000, 0x8836d2c300000000,
+ 0xce0db5a600000000, 0x04401c0900000000, 0x427b7b6c00000000,
+ 0xd1dd3f8d00000000, 0x97e658e800000000, 0x5dabf14700000000,
+ 0x1b90962200000000, 0x1f4bcfbe00000000, 0x5970a8db00000000,
+ 0x933d017400000000, 0xd506661100000000, 0x46a022f000000000,
+ 0x009b459500000000, 0xcad6ec3a00000000, 0x8ced8b5f00000000,
+ 0xad9d142300000000, 0xeba6734600000000, 0x21ebdae900000000,
+ 0x67d0bd8c00000000, 0xf476f96d00000000, 0xb24d9e0800000000,
+ 0x780037a700000000, 0x3e3b50c200000000, 0x31b0f54400000000,
+ 0x778b922100000000, 0xbdc63b8e00000000, 0xfbfd5ceb00000000,
+ 0x685b180a00000000, 0x2e607f6f00000000, 0xe42dd6c000000000,
+ 0xa216b1a500000000, 0x83662ed900000000, 0xc55d49bc00000000,
+ 0x0f10e01300000000, 0x492b877600000000, 0xda8dc39700000000,
+ 0x9cb6a4f200000000, 0x56fb0d5d00000000, 0x10c06a3800000000,
+ 0x141b33a400000000, 0x522054c100000000, 0x986dfd6e00000000,
+ 0xde569a0b00000000, 0x4df0deea00000000, 0x0bcbb98f00000000,
+ 0xc186102000000000, 0x87bd774500000000, 0xa6cde83900000000,
+ 0xe0f68f5c00000000, 0x2abb26f300000000, 0x6c80419600000000,
+ 0xff26057700000000, 0xb91d621200000000, 0x7350cbbd00000000,
+ 0x356bacd800000000},
+ {0x0000000000000000, 0x9e83da9f00000000, 0x7d01c4e400000000,
+ 0xe3821e7b00000000, 0xbb04f91200000000, 0x2587238d00000000,
+ 0xc6053df600000000, 0x5886e76900000000, 0x7609f22500000000,
+ 0xe88a28ba00000000, 0x0b0836c100000000, 0x958bec5e00000000,
+ 0xcd0d0b3700000000, 0x538ed1a800000000, 0xb00ccfd300000000,
+ 0x2e8f154c00000000, 0xec12e44b00000000, 0x72913ed400000000,
+ 0x911320af00000000, 0x0f90fa3000000000, 0x57161d5900000000,
+ 0xc995c7c600000000, 0x2a17d9bd00000000, 0xb494032200000000,
+ 0x9a1b166e00000000, 0x0498ccf100000000, 0xe71ad28a00000000,
+ 0x7999081500000000, 0x211fef7c00000000, 0xbf9c35e300000000,
+ 0x5c1e2b9800000000, 0xc29df10700000000, 0xd825c89700000000,
+ 0x46a6120800000000, 0xa5240c7300000000, 0x3ba7d6ec00000000,
+ 0x6321318500000000, 0xfda2eb1a00000000, 0x1e20f56100000000,
+ 0x80a32ffe00000000, 0xae2c3ab200000000, 0x30afe02d00000000,
+ 0xd32dfe5600000000, 0x4dae24c900000000, 0x1528c3a000000000,
+ 0x8bab193f00000000, 0x6829074400000000, 0xf6aadddb00000000,
+ 0x34372cdc00000000, 0xaab4f64300000000, 0x4936e83800000000,
+ 0xd7b532a700000000, 0x8f33d5ce00000000, 0x11b00f5100000000,
+ 0xf232112a00000000, 0x6cb1cbb500000000, 0x423edef900000000,
+ 0xdcbd046600000000, 0x3f3f1a1d00000000, 0xa1bcc08200000000,
+ 0xf93a27eb00000000, 0x67b9fd7400000000, 0x843be30f00000000,
+ 0x1ab8399000000000, 0xf14de1f400000000, 0x6fce3b6b00000000,
+ 0x8c4c251000000000, 0x12cfff8f00000000, 0x4a4918e600000000,
+ 0xd4cac27900000000, 0x3748dc0200000000, 0xa9cb069d00000000,
+ 0x874413d100000000, 0x19c7c94e00000000, 0xfa45d73500000000,
+ 0x64c60daa00000000, 0x3c40eac300000000, 0xa2c3305c00000000,
+ 0x41412e2700000000, 0xdfc2f4b800000000, 0x1d5f05bf00000000,
+ 0x83dcdf2000000000, 0x605ec15b00000000, 0xfedd1bc400000000,
+ 0xa65bfcad00000000, 0x38d8263200000000, 0xdb5a384900000000,
+ 0x45d9e2d600000000, 0x6b56f79a00000000, 0xf5d52d0500000000,
+ 0x1657337e00000000, 0x88d4e9e100000000, 0xd0520e8800000000,
+ 0x4ed1d41700000000, 0xad53ca6c00000000, 0x33d010f300000000,
+ 0x2968296300000000, 0xb7ebf3fc00000000, 0x5469ed8700000000,
+ 0xcaea371800000000, 0x926cd07100000000, 0x0cef0aee00000000,
+ 0xef6d149500000000, 0x71eece0a00000000, 0x5f61db4600000000,
+ 0xc1e201d900000000, 0x22601fa200000000, 0xbce3c53d00000000,
+ 0xe465225400000000, 0x7ae6f8cb00000000, 0x9964e6b000000000,
+ 0x07e73c2f00000000, 0xc57acd2800000000, 0x5bf917b700000000,
+ 0xb87b09cc00000000, 0x26f8d35300000000, 0x7e7e343a00000000,
+ 0xe0fdeea500000000, 0x037ff0de00000000, 0x9dfc2a4100000000,
+ 0xb3733f0d00000000, 0x2df0e59200000000, 0xce72fbe900000000,
+ 0x50f1217600000000, 0x0877c61f00000000, 0x96f41c8000000000,
+ 0x757602fb00000000, 0xebf5d86400000000, 0xa39db33200000000,
+ 0x3d1e69ad00000000, 0xde9c77d600000000, 0x401fad4900000000,
+ 0x18994a2000000000, 0x861a90bf00000000, 0x65988ec400000000,
+ 0xfb1b545b00000000, 0xd594411700000000, 0x4b179b8800000000,
+ 0xa89585f300000000, 0x36165f6c00000000, 0x6e90b80500000000,
+ 0xf013629a00000000, 0x13917ce100000000, 0x8d12a67e00000000,
+ 0x4f8f577900000000, 0xd10c8de600000000, 0x328e939d00000000,
+ 0xac0d490200000000, 0xf48bae6b00000000, 0x6a0874f400000000,
+ 0x898a6a8f00000000, 0x1709b01000000000, 0x3986a55c00000000,
+ 0xa7057fc300000000, 0x448761b800000000, 0xda04bb2700000000,
+ 0x82825c4e00000000, 0x1c0186d100000000, 0xff8398aa00000000,
+ 0x6100423500000000, 0x7bb87ba500000000, 0xe53ba13a00000000,
+ 0x06b9bf4100000000, 0x983a65de00000000, 0xc0bc82b700000000,
+ 0x5e3f582800000000, 0xbdbd465300000000, 0x233e9ccc00000000,
+ 0x0db1898000000000, 0x9332531f00000000, 0x70b04d6400000000,
+ 0xee3397fb00000000, 0xb6b5709200000000, 0x2836aa0d00000000,
+ 0xcbb4b47600000000, 0x55376ee900000000, 0x97aa9fee00000000,
+ 0x0929457100000000, 0xeaab5b0a00000000, 0x7428819500000000,
+ 0x2cae66fc00000000, 0xb22dbc6300000000, 0x51afa21800000000,
+ 0xcf2c788700000000, 0xe1a36dcb00000000, 0x7f20b75400000000,
+ 0x9ca2a92f00000000, 0x022173b000000000, 0x5aa794d900000000,
+ 0xc4244e4600000000, 0x27a6503d00000000, 0xb9258aa200000000,
+ 0x52d052c600000000, 0xcc53885900000000, 0x2fd1962200000000,
+ 0xb1524cbd00000000, 0xe9d4abd400000000, 0x7757714b00000000,
+ 0x94d56f3000000000, 0x0a56b5af00000000, 0x24d9a0e300000000,
+ 0xba5a7a7c00000000, 0x59d8640700000000, 0xc75bbe9800000000,
+ 0x9fdd59f100000000, 0x015e836e00000000, 0xe2dc9d1500000000,
+ 0x7c5f478a00000000, 0xbec2b68d00000000, 0x20416c1200000000,
+ 0xc3c3726900000000, 0x5d40a8f600000000, 0x05c64f9f00000000,
+ 0x9b45950000000000, 0x78c78b7b00000000, 0xe64451e400000000,
+ 0xc8cb44a800000000, 0x56489e3700000000, 0xb5ca804c00000000,
+ 0x2b495ad300000000, 0x73cfbdba00000000, 0xed4c672500000000,
+ 0x0ece795e00000000, 0x904da3c100000000, 0x8af59a5100000000,
+ 0x147640ce00000000, 0xf7f45eb500000000, 0x6977842a00000000,
+ 0x31f1634300000000, 0xaf72b9dc00000000, 0x4cf0a7a700000000,
+ 0xd2737d3800000000, 0xfcfc687400000000, 0x627fb2eb00000000,
+ 0x81fdac9000000000, 0x1f7e760f00000000, 0x47f8916600000000,
+ 0xd97b4bf900000000, 0x3af9558200000000, 0xa47a8f1d00000000,
+ 0x66e77e1a00000000, 0xf864a48500000000, 0x1be6bafe00000000,
+ 0x8565606100000000, 0xdde3870800000000, 0x43605d9700000000,
+ 0xa0e243ec00000000, 0x3e61997300000000, 0x10ee8c3f00000000,
+ 0x8e6d56a000000000, 0x6def48db00000000, 0xf36c924400000000,
+ 0xabea752d00000000, 0x3569afb200000000, 0xd6ebb1c900000000,
+ 0x48686b5600000000},
+ {0x0000000000000000, 0xc064281700000000, 0x80c9502e00000000,
+ 0x40ad783900000000, 0x0093a15c00000000, 0xc0f7894b00000000,
+ 0x805af17200000000, 0x403ed96500000000, 0x002643b900000000,
+ 0xc0426bae00000000, 0x80ef139700000000, 0x408b3b8000000000,
+ 0x00b5e2e500000000, 0xc0d1caf200000000, 0x807cb2cb00000000,
+ 0x40189adc00000000, 0x414af7a900000000, 0x812edfbe00000000,
+ 0xc183a78700000000, 0x01e78f9000000000, 0x41d956f500000000,
+ 0x81bd7ee200000000, 0xc11006db00000000, 0x01742ecc00000000,
+ 0x416cb41000000000, 0x81089c0700000000, 0xc1a5e43e00000000,
+ 0x01c1cc2900000000, 0x41ff154c00000000, 0x819b3d5b00000000,
+ 0xc136456200000000, 0x01526d7500000000, 0xc3929f8800000000,
+ 0x03f6b79f00000000, 0x435bcfa600000000, 0x833fe7b100000000,
+ 0xc3013ed400000000, 0x036516c300000000, 0x43c86efa00000000,
+ 0x83ac46ed00000000, 0xc3b4dc3100000000, 0x03d0f42600000000,
+ 0x437d8c1f00000000, 0x8319a40800000000, 0xc3277d6d00000000,
+ 0x0343557a00000000, 0x43ee2d4300000000, 0x838a055400000000,
+ 0x82d8682100000000, 0x42bc403600000000, 0x0211380f00000000,
+ 0xc275101800000000, 0x824bc97d00000000, 0x422fe16a00000000,
+ 0x0282995300000000, 0xc2e6b14400000000, 0x82fe2b9800000000,
+ 0x429a038f00000000, 0x02377bb600000000, 0xc25353a100000000,
+ 0x826d8ac400000000, 0x4209a2d300000000, 0x02a4daea00000000,
+ 0xc2c0f2fd00000000, 0xc7234eca00000000, 0x074766dd00000000,
+ 0x47ea1ee400000000, 0x878e36f300000000, 0xc7b0ef9600000000,
+ 0x07d4c78100000000, 0x4779bfb800000000, 0x871d97af00000000,
+ 0xc7050d7300000000, 0x0761256400000000, 0x47cc5d5d00000000,
+ 0x87a8754a00000000, 0xc796ac2f00000000, 0x07f2843800000000,
+ 0x475ffc0100000000, 0x873bd41600000000, 0x8669b96300000000,
+ 0x460d917400000000, 0x06a0e94d00000000, 0xc6c4c15a00000000,
+ 0x86fa183f00000000, 0x469e302800000000, 0x0633481100000000,
+ 0xc657600600000000, 0x864ffada00000000, 0x462bd2cd00000000,
+ 0x0686aaf400000000, 0xc6e282e300000000, 0x86dc5b8600000000,
+ 0x46b8739100000000, 0x06150ba800000000, 0xc67123bf00000000,
+ 0x04b1d14200000000, 0xc4d5f95500000000, 0x8478816c00000000,
+ 0x441ca97b00000000, 0x0422701e00000000, 0xc446580900000000,
+ 0x84eb203000000000, 0x448f082700000000, 0x049792fb00000000,
+ 0xc4f3baec00000000, 0x845ec2d500000000, 0x443aeac200000000,
+ 0x040433a700000000, 0xc4601bb000000000, 0x84cd638900000000,
+ 0x44a94b9e00000000, 0x45fb26eb00000000, 0x859f0efc00000000,
+ 0xc53276c500000000, 0x05565ed200000000, 0x456887b700000000,
+ 0x850cafa000000000, 0xc5a1d79900000000, 0x05c5ff8e00000000,
+ 0x45dd655200000000, 0x85b94d4500000000, 0xc514357c00000000,
+ 0x05701d6b00000000, 0x454ec40e00000000, 0x852aec1900000000,
+ 0xc587942000000000, 0x05e3bc3700000000, 0xcf41ed4f00000000,
+ 0x0f25c55800000000, 0x4f88bd6100000000, 0x8fec957600000000,
+ 0xcfd24c1300000000, 0x0fb6640400000000, 0x4f1b1c3d00000000,
+ 0x8f7f342a00000000, 0xcf67aef600000000, 0x0f0386e100000000,
+ 0x4faefed800000000, 0x8fcad6cf00000000, 0xcff40faa00000000,
+ 0x0f9027bd00000000, 0x4f3d5f8400000000, 0x8f59779300000000,
+ 0x8e0b1ae600000000, 0x4e6f32f100000000, 0x0ec24ac800000000,
+ 0xcea662df00000000, 0x8e98bbba00000000, 0x4efc93ad00000000,
+ 0x0e51eb9400000000, 0xce35c38300000000, 0x8e2d595f00000000,
+ 0x4e49714800000000, 0x0ee4097100000000, 0xce80216600000000,
+ 0x8ebef80300000000, 0x4edad01400000000, 0x0e77a82d00000000,
+ 0xce13803a00000000, 0x0cd372c700000000, 0xccb75ad000000000,
+ 0x8c1a22e900000000, 0x4c7e0afe00000000, 0x0c40d39b00000000,
+ 0xcc24fb8c00000000, 0x8c8983b500000000, 0x4cedaba200000000,
+ 0x0cf5317e00000000, 0xcc91196900000000, 0x8c3c615000000000,
+ 0x4c58494700000000, 0x0c66902200000000, 0xcc02b83500000000,
+ 0x8cafc00c00000000, 0x4ccbe81b00000000, 0x4d99856e00000000,
+ 0x8dfdad7900000000, 0xcd50d54000000000, 0x0d34fd5700000000,
+ 0x4d0a243200000000, 0x8d6e0c2500000000, 0xcdc3741c00000000,
+ 0x0da75c0b00000000, 0x4dbfc6d700000000, 0x8ddbeec000000000,
+ 0xcd7696f900000000, 0x0d12beee00000000, 0x4d2c678b00000000,
+ 0x8d484f9c00000000, 0xcde537a500000000, 0x0d811fb200000000,
+ 0x0862a38500000000, 0xc8068b9200000000, 0x88abf3ab00000000,
+ 0x48cfdbbc00000000, 0x08f102d900000000, 0xc8952ace00000000,
+ 0x883852f700000000, 0x485c7ae000000000, 0x0844e03c00000000,
+ 0xc820c82b00000000, 0x888db01200000000, 0x48e9980500000000,
+ 0x08d7416000000000, 0xc8b3697700000000, 0x881e114e00000000,
+ 0x487a395900000000, 0x4928542c00000000, 0x894c7c3b00000000,
+ 0xc9e1040200000000, 0x09852c1500000000, 0x49bbf57000000000,
+ 0x89dfdd6700000000, 0xc972a55e00000000, 0x09168d4900000000,
+ 0x490e179500000000, 0x896a3f8200000000, 0xc9c747bb00000000,
+ 0x09a36fac00000000, 0x499db6c900000000, 0x89f99ede00000000,
+ 0xc954e6e700000000, 0x0930cef000000000, 0xcbf03c0d00000000,
+ 0x0b94141a00000000, 0x4b396c2300000000, 0x8b5d443400000000,
+ 0xcb639d5100000000, 0x0b07b54600000000, 0x4baacd7f00000000,
+ 0x8bcee56800000000, 0xcbd67fb400000000, 0x0bb257a300000000,
+ 0x4b1f2f9a00000000, 0x8b7b078d00000000, 0xcb45dee800000000,
+ 0x0b21f6ff00000000, 0x4b8c8ec600000000, 0x8be8a6d100000000,
+ 0x8abacba400000000, 0x4adee3b300000000, 0x0a739b8a00000000,
+ 0xca17b39d00000000, 0x8a296af800000000, 0x4a4d42ef00000000,
+ 0x0ae03ad600000000, 0xca8412c100000000, 0x8a9c881d00000000,
+ 0x4af8a00a00000000, 0x0a55d83300000000, 0xca31f02400000000,
+ 0x8a0f294100000000, 0x4a6b015600000000, 0x0ac6796f00000000,
+ 0xcaa2517800000000},
+ {0x0000000000000000, 0xd4ea739b00000000, 0xe9d396ed00000000,
+ 0x3d39e57600000000, 0x93a15c0000000000, 0x474b2f9b00000000,
+ 0x7a72caed00000000, 0xae98b97600000000, 0x2643b90000000000,
+ 0xf2a9ca9b00000000, 0xcf902fed00000000, 0x1b7a5c7600000000,
+ 0xb5e2e50000000000, 0x6108969b00000000, 0x5c3173ed00000000,
+ 0x88db007600000000, 0x4c86720100000000, 0x986c019a00000000,
+ 0xa555e4ec00000000, 0x71bf977700000000, 0xdf272e0100000000,
+ 0x0bcd5d9a00000000, 0x36f4b8ec00000000, 0xe21ecb7700000000,
+ 0x6ac5cb0100000000, 0xbe2fb89a00000000, 0x83165dec00000000,
+ 0x57fc2e7700000000, 0xf964970100000000, 0x2d8ee49a00000000,
+ 0x10b701ec00000000, 0xc45d727700000000, 0x980ce50200000000,
+ 0x4ce6969900000000, 0x71df73ef00000000, 0xa535007400000000,
+ 0x0badb90200000000, 0xdf47ca9900000000, 0xe27e2fef00000000,
+ 0x36945c7400000000, 0xbe4f5c0200000000, 0x6aa52f9900000000,
+ 0x579ccaef00000000, 0x8376b97400000000, 0x2dee000200000000,
+ 0xf904739900000000, 0xc43d96ef00000000, 0x10d7e57400000000,
+ 0xd48a970300000000, 0x0060e49800000000, 0x3d5901ee00000000,
+ 0xe9b3727500000000, 0x472bcb0300000000, 0x93c1b89800000000,
+ 0xaef85dee00000000, 0x7a122e7500000000, 0xf2c92e0300000000,
+ 0x26235d9800000000, 0x1b1ab8ee00000000, 0xcff0cb7500000000,
+ 0x6168720300000000, 0xb582019800000000, 0x88bbe4ee00000000,
+ 0x5c51977500000000, 0x3019ca0500000000, 0xe4f3b99e00000000,
+ 0xd9ca5ce800000000, 0x0d202f7300000000, 0xa3b8960500000000,
+ 0x7752e59e00000000, 0x4a6b00e800000000, 0x9e81737300000000,
+ 0x165a730500000000, 0xc2b0009e00000000, 0xff89e5e800000000,
+ 0x2b63967300000000, 0x85fb2f0500000000, 0x51115c9e00000000,
+ 0x6c28b9e800000000, 0xb8c2ca7300000000, 0x7c9fb80400000000,
+ 0xa875cb9f00000000, 0x954c2ee900000000, 0x41a65d7200000000,
+ 0xef3ee40400000000, 0x3bd4979f00000000, 0x06ed72e900000000,
+ 0xd207017200000000, 0x5adc010400000000, 0x8e36729f00000000,
+ 0xb30f97e900000000, 0x67e5e47200000000, 0xc97d5d0400000000,
+ 0x1d972e9f00000000, 0x20aecbe900000000, 0xf444b87200000000,
+ 0xa8152f0700000000, 0x7cff5c9c00000000, 0x41c6b9ea00000000,
+ 0x952cca7100000000, 0x3bb4730700000000, 0xef5e009c00000000,
+ 0xd267e5ea00000000, 0x068d967100000000, 0x8e56960700000000,
+ 0x5abce59c00000000, 0x678500ea00000000, 0xb36f737100000000,
+ 0x1df7ca0700000000, 0xc91db99c00000000, 0xf4245cea00000000,
+ 0x20ce2f7100000000, 0xe4935d0600000000, 0x30792e9d00000000,
+ 0x0d40cbeb00000000, 0xd9aab87000000000, 0x7732010600000000,
+ 0xa3d8729d00000000, 0x9ee197eb00000000, 0x4a0be47000000000,
+ 0xc2d0e40600000000, 0x163a979d00000000, 0x2b0372eb00000000,
+ 0xffe9017000000000, 0x5171b80600000000, 0x859bcb9d00000000,
+ 0xb8a22eeb00000000, 0x6c485d7000000000, 0x6032940b00000000,
+ 0xb4d8e79000000000, 0x89e102e600000000, 0x5d0b717d00000000,
+ 0xf393c80b00000000, 0x2779bb9000000000, 0x1a405ee600000000,
+ 0xceaa2d7d00000000, 0x46712d0b00000000, 0x929b5e9000000000,
+ 0xafa2bbe600000000, 0x7b48c87d00000000, 0xd5d0710b00000000,
+ 0x013a029000000000, 0x3c03e7e600000000, 0xe8e9947d00000000,
+ 0x2cb4e60a00000000, 0xf85e959100000000, 0xc56770e700000000,
+ 0x118d037c00000000, 0xbf15ba0a00000000, 0x6bffc99100000000,
+ 0x56c62ce700000000, 0x822c5f7c00000000, 0x0af75f0a00000000,
+ 0xde1d2c9100000000, 0xe324c9e700000000, 0x37ceba7c00000000,
+ 0x9956030a00000000, 0x4dbc709100000000, 0x708595e700000000,
+ 0xa46fe67c00000000, 0xf83e710900000000, 0x2cd4029200000000,
+ 0x11ede7e400000000, 0xc507947f00000000, 0x6b9f2d0900000000,
+ 0xbf755e9200000000, 0x824cbbe400000000, 0x56a6c87f00000000,
+ 0xde7dc80900000000, 0x0a97bb9200000000, 0x37ae5ee400000000,
+ 0xe3442d7f00000000, 0x4ddc940900000000, 0x9936e79200000000,
+ 0xa40f02e400000000, 0x70e5717f00000000, 0xb4b8030800000000,
+ 0x6052709300000000, 0x5d6b95e500000000, 0x8981e67e00000000,
+ 0x27195f0800000000, 0xf3f32c9300000000, 0xcecac9e500000000,
+ 0x1a20ba7e00000000, 0x92fbba0800000000, 0x4611c99300000000,
+ 0x7b282ce500000000, 0xafc25f7e00000000, 0x015ae60800000000,
+ 0xd5b0959300000000, 0xe88970e500000000, 0x3c63037e00000000,
+ 0x502b5e0e00000000, 0x84c12d9500000000, 0xb9f8c8e300000000,
+ 0x6d12bb7800000000, 0xc38a020e00000000, 0x1760719500000000,
+ 0x2a5994e300000000, 0xfeb3e77800000000, 0x7668e70e00000000,
+ 0xa282949500000000, 0x9fbb71e300000000, 0x4b51027800000000,
+ 0xe5c9bb0e00000000, 0x3123c89500000000, 0x0c1a2de300000000,
+ 0xd8f05e7800000000, 0x1cad2c0f00000000, 0xc8475f9400000000,
+ 0xf57ebae200000000, 0x2194c97900000000, 0x8f0c700f00000000,
+ 0x5be6039400000000, 0x66dfe6e200000000, 0xb235957900000000,
+ 0x3aee950f00000000, 0xee04e69400000000, 0xd33d03e200000000,
+ 0x07d7707900000000, 0xa94fc90f00000000, 0x7da5ba9400000000,
+ 0x409c5fe200000000, 0x94762c7900000000, 0xc827bb0c00000000,
+ 0x1ccdc89700000000, 0x21f42de100000000, 0xf51e5e7a00000000,
+ 0x5b86e70c00000000, 0x8f6c949700000000, 0xb25571e100000000,
+ 0x66bf027a00000000, 0xee64020c00000000, 0x3a8e719700000000,
+ 0x07b794e100000000, 0xd35de77a00000000, 0x7dc55e0c00000000,
+ 0xa92f2d9700000000, 0x9416c8e100000000, 0x40fcbb7a00000000,
+ 0x84a1c90d00000000, 0x504bba9600000000, 0x6d725fe000000000,
+ 0xb9982c7b00000000, 0x1700950d00000000, 0xc3eae69600000000,
+ 0xfed303e000000000, 0x2a39707b00000000, 0xa2e2700d00000000,
+ 0x7608039600000000, 0x4b31e6e000000000, 0x9fdb957b00000000,
+ 0x31432c0d00000000, 0xe5a95f9600000000, 0xd890bae000000000,
+ 0x0c7ac97b00000000},
+ {0x0000000000000000, 0x2765258100000000, 0x0fcc3bd900000000,
+ 0x28a91e5800000000, 0x5f9e066900000000, 0x78fb23e800000000,
+ 0x50523db000000000, 0x7737183100000000, 0xbe3c0dd200000000,
+ 0x9959285300000000, 0xb1f0360b00000000, 0x9695138a00000000,
+ 0xe1a20bbb00000000, 0xc6c72e3a00000000, 0xee6e306200000000,
+ 0xc90b15e300000000, 0x3d7f6b7f00000000, 0x1a1a4efe00000000,
+ 0x32b350a600000000, 0x15d6752700000000, 0x62e16d1600000000,
+ 0x4584489700000000, 0x6d2d56cf00000000, 0x4a48734e00000000,
+ 0x834366ad00000000, 0xa426432c00000000, 0x8c8f5d7400000000,
+ 0xabea78f500000000, 0xdcdd60c400000000, 0xfbb8454500000000,
+ 0xd3115b1d00000000, 0xf4747e9c00000000, 0x7afed6fe00000000,
+ 0x5d9bf37f00000000, 0x7532ed2700000000, 0x5257c8a600000000,
+ 0x2560d09700000000, 0x0205f51600000000, 0x2aaceb4e00000000,
+ 0x0dc9cecf00000000, 0xc4c2db2c00000000, 0xe3a7fead00000000,
+ 0xcb0ee0f500000000, 0xec6bc57400000000, 0x9b5cdd4500000000,
+ 0xbc39f8c400000000, 0x9490e69c00000000, 0xb3f5c31d00000000,
+ 0x4781bd8100000000, 0x60e4980000000000, 0x484d865800000000,
+ 0x6f28a3d900000000, 0x181fbbe800000000, 0x3f7a9e6900000000,
+ 0x17d3803100000000, 0x30b6a5b000000000, 0xf9bdb05300000000,
+ 0xded895d200000000, 0xf6718b8a00000000, 0xd114ae0b00000000,
+ 0xa623b63a00000000, 0x814693bb00000000, 0xa9ef8de300000000,
+ 0x8e8aa86200000000, 0xb5fadc2600000000, 0x929ff9a700000000,
+ 0xba36e7ff00000000, 0x9d53c27e00000000, 0xea64da4f00000000,
+ 0xcd01ffce00000000, 0xe5a8e19600000000, 0xc2cdc41700000000,
+ 0x0bc6d1f400000000, 0x2ca3f47500000000, 0x040aea2d00000000,
+ 0x236fcfac00000000, 0x5458d79d00000000, 0x733df21c00000000,
+ 0x5b94ec4400000000, 0x7cf1c9c500000000, 0x8885b75900000000,
+ 0xafe092d800000000, 0x87498c8000000000, 0xa02ca90100000000,
+ 0xd71bb13000000000, 0xf07e94b100000000, 0xd8d78ae900000000,
+ 0xffb2af6800000000, 0x36b9ba8b00000000, 0x11dc9f0a00000000,
+ 0x3975815200000000, 0x1e10a4d300000000, 0x6927bce200000000,
+ 0x4e42996300000000, 0x66eb873b00000000, 0x418ea2ba00000000,
+ 0xcf040ad800000000, 0xe8612f5900000000, 0xc0c8310100000000,
+ 0xe7ad148000000000, 0x909a0cb100000000, 0xb7ff293000000000,
+ 0x9f56376800000000, 0xb83312e900000000, 0x7138070a00000000,
+ 0x565d228b00000000, 0x7ef43cd300000000, 0x5991195200000000,
+ 0x2ea6016300000000, 0x09c324e200000000, 0x216a3aba00000000,
+ 0x060f1f3b00000000, 0xf27b61a700000000, 0xd51e442600000000,
+ 0xfdb75a7e00000000, 0xdad27fff00000000, 0xade567ce00000000,
+ 0x8a80424f00000000, 0xa2295c1700000000, 0x854c799600000000,
+ 0x4c476c7500000000, 0x6b2249f400000000, 0x438b57ac00000000,
+ 0x64ee722d00000000, 0x13d96a1c00000000, 0x34bc4f9d00000000,
+ 0x1c1551c500000000, 0x3b70744400000000, 0x6af5b94d00000000,
+ 0x4d909ccc00000000, 0x6539829400000000, 0x425ca71500000000,
+ 0x356bbf2400000000, 0x120e9aa500000000, 0x3aa784fd00000000,
+ 0x1dc2a17c00000000, 0xd4c9b49f00000000, 0xf3ac911e00000000,
+ 0xdb058f4600000000, 0xfc60aac700000000, 0x8b57b2f600000000,
+ 0xac32977700000000, 0x849b892f00000000, 0xa3feacae00000000,
+ 0x578ad23200000000, 0x70eff7b300000000, 0x5846e9eb00000000,
+ 0x7f23cc6a00000000, 0x0814d45b00000000, 0x2f71f1da00000000,
+ 0x07d8ef8200000000, 0x20bdca0300000000, 0xe9b6dfe000000000,
+ 0xced3fa6100000000, 0xe67ae43900000000, 0xc11fc1b800000000,
+ 0xb628d98900000000, 0x914dfc0800000000, 0xb9e4e25000000000,
+ 0x9e81c7d100000000, 0x100b6fb300000000, 0x376e4a3200000000,
+ 0x1fc7546a00000000, 0x38a271eb00000000, 0x4f9569da00000000,
+ 0x68f04c5b00000000, 0x4059520300000000, 0x673c778200000000,
+ 0xae37626100000000, 0x895247e000000000, 0xa1fb59b800000000,
+ 0x869e7c3900000000, 0xf1a9640800000000, 0xd6cc418900000000,
+ 0xfe655fd100000000, 0xd9007a5000000000, 0x2d7404cc00000000,
+ 0x0a11214d00000000, 0x22b83f1500000000, 0x05dd1a9400000000,
+ 0x72ea02a500000000, 0x558f272400000000, 0x7d26397c00000000,
+ 0x5a431cfd00000000, 0x9348091e00000000, 0xb42d2c9f00000000,
+ 0x9c8432c700000000, 0xbbe1174600000000, 0xccd60f7700000000,
+ 0xebb32af600000000, 0xc31a34ae00000000, 0xe47f112f00000000,
+ 0xdf0f656b00000000, 0xf86a40ea00000000, 0xd0c35eb200000000,
+ 0xf7a67b3300000000, 0x8091630200000000, 0xa7f4468300000000,
+ 0x8f5d58db00000000, 0xa8387d5a00000000, 0x613368b900000000,
+ 0x46564d3800000000, 0x6eff536000000000, 0x499a76e100000000,
+ 0x3ead6ed000000000, 0x19c84b5100000000, 0x3161550900000000,
+ 0x1604708800000000, 0xe2700e1400000000, 0xc5152b9500000000,
+ 0xedbc35cd00000000, 0xcad9104c00000000, 0xbdee087d00000000,
+ 0x9a8b2dfc00000000, 0xb22233a400000000, 0x9547162500000000,
+ 0x5c4c03c600000000, 0x7b29264700000000, 0x5380381f00000000,
+ 0x74e51d9e00000000, 0x03d205af00000000, 0x24b7202e00000000,
+ 0x0c1e3e7600000000, 0x2b7b1bf700000000, 0xa5f1b39500000000,
+ 0x8294961400000000, 0xaa3d884c00000000, 0x8d58adcd00000000,
+ 0xfa6fb5fc00000000, 0xdd0a907d00000000, 0xf5a38e2500000000,
+ 0xd2c6aba400000000, 0x1bcdbe4700000000, 0x3ca89bc600000000,
+ 0x1401859e00000000, 0x3364a01f00000000, 0x4453b82e00000000,
+ 0x63369daf00000000, 0x4b9f83f700000000, 0x6cfaa67600000000,
+ 0x988ed8ea00000000, 0xbfebfd6b00000000, 0x9742e33300000000,
+ 0xb027c6b200000000, 0xc710de8300000000, 0xe075fb0200000000,
+ 0xc8dce55a00000000, 0xefb9c0db00000000, 0x26b2d53800000000,
+ 0x01d7f0b900000000, 0x297eeee100000000, 0x0e1bcb6000000000,
+ 0x792cd35100000000, 0x5e49f6d000000000, 0x76e0e88800000000,
+ 0x5185cd0900000000}};
+
+#else /* W == 4 */
+
+local const z_crc_t FAR crc_braid_table[][256] = {
+ {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f,
+ 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91,
+ 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e,
+ 0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c,
+ 0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02,
+ 0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12,
+ 0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567,
+ 0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277,
+ 0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679,
+ 0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b,
+ 0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4,
+ 0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a,
+ 0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0,
+ 0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0,
+ 0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91,
+ 0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881,
+ 0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173,
+ 0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d,
+ 0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912,
+ 0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8,
+ 0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6,
+ 0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6,
+ 0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b,
+ 0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b,
+ 0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75,
+ 0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f,
+ 0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00,
+ 0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee,
+ 0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c,
+ 0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c,
+ 0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d,
+ 0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d,
+ 0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67,
+ 0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89,
+ 0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706,
+ 0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14,
+ 0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a,
+ 0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a,
+ 0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f,
+ 0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f,
+ 0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591,
+ 0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983,
+ 0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c,
+ 0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2,
+ 0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8,
+ 0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8,
+ 0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89,
+ 0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99,
+ 0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b,
+ 0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485,
+ 0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a,
+ 0x36197165},
+ {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382,
+ 0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85,
+ 0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06,
+ 0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca,
+ 0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e,
+ 0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc,
+ 0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616,
+ 0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54,
+ 0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10,
+ 0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc,
+ 0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f,
+ 0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58,
+ 0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef,
+ 0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad,
+ 0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b,
+ 0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29,
+ 0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6,
+ 0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1,
+ 0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622,
+ 0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039,
+ 0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d,
+ 0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f,
+ 0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32,
+ 0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770,
+ 0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034,
+ 0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f,
+ 0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc,
+ 0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db,
+ 0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154,
+ 0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16,
+ 0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0,
+ 0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592,
+ 0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca,
+ 0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd,
+ 0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e,
+ 0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882,
+ 0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6,
+ 0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384,
+ 0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1,
+ 0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3,
+ 0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7,
+ 0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b,
+ 0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8,
+ 0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff,
+ 0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7,
+ 0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5,
+ 0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23,
+ 0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761,
+ 0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee,
+ 0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9,
+ 0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a,
+ 0x1a3b93aa},
+ {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a,
+ 0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca,
+ 0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3,
+ 0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb,
+ 0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c,
+ 0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58,
+ 0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed,
+ 0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9,
+ 0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e,
+ 0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906,
+ 0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f,
+ 0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf,
+ 0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0,
+ 0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4,
+ 0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769,
+ 0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d,
+ 0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632,
+ 0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82,
+ 0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb,
+ 0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73,
+ 0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484,
+ 0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0,
+ 0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5,
+ 0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1,
+ 0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516,
+ 0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f,
+ 0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946,
+ 0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6,
+ 0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9,
+ 0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad,
+ 0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820,
+ 0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364,
+ 0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab,
+ 0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b,
+ 0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62,
+ 0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a,
+ 0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd,
+ 0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089,
+ 0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c,
+ 0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8,
+ 0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f,
+ 0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477,
+ 0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e,
+ 0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be,
+ 0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71,
+ 0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635,
+ 0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8,
+ 0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc,
+ 0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3,
+ 0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753,
+ 0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a,
+ 0xe147d714},
+ {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c,
+ 0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b,
+ 0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92,
+ 0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4,
+ 0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069,
+ 0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526,
+ 0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25,
+ 0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a,
+ 0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7,
+ 0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491,
+ 0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958,
+ 0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f,
+ 0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307,
+ 0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648,
+ 0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999,
+ 0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6,
+ 0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a,
+ 0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d,
+ 0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4,
+ 0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61,
+ 0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc,
+ 0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3,
+ 0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53,
+ 0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c,
+ 0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1,
+ 0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c,
+ 0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5,
+ 0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92,
+ 0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e,
+ 0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771,
+ 0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0,
+ 0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def,
+ 0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0,
+ 0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7,
+ 0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e,
+ 0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58,
+ 0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285,
+ 0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca,
+ 0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce,
+ 0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81,
+ 0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c,
+ 0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a,
+ 0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3,
+ 0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4,
+ 0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb,
+ 0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4,
+ 0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75,
+ 0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a,
+ 0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296,
+ 0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1,
+ 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808,
+ 0x494f0c4b}};
+
+local const z_word_t FAR crc_braid_big_table[][256] = {
+ {0x00000000, 0x43147b17, 0x8628f62e, 0xc53c8d39, 0x0c51ec5d,
+ 0x4f45974a, 0x8a791a73, 0xc96d6164, 0x18a2d8bb, 0x5bb6a3ac,
+ 0x9e8a2e95, 0xdd9e5582, 0x14f334e6, 0x57e74ff1, 0x92dbc2c8,
+ 0xd1cfb9df, 0x7142c0ac, 0x3256bbbb, 0xf76a3682, 0xb47e4d95,
+ 0x7d132cf1, 0x3e0757e6, 0xfb3bdadf, 0xb82fa1c8, 0x69e01817,
+ 0x2af46300, 0xefc8ee39, 0xacdc952e, 0x65b1f44a, 0x26a58f5d,
+ 0xe3990264, 0xa08d7973, 0xa382f182, 0xe0968a95, 0x25aa07ac,
+ 0x66be7cbb, 0xafd31ddf, 0xecc766c8, 0x29fbebf1, 0x6aef90e6,
+ 0xbb202939, 0xf834522e, 0x3d08df17, 0x7e1ca400, 0xb771c564,
+ 0xf465be73, 0x3159334a, 0x724d485d, 0xd2c0312e, 0x91d44a39,
+ 0x54e8c700, 0x17fcbc17, 0xde91dd73, 0x9d85a664, 0x58b92b5d,
+ 0x1bad504a, 0xca62e995, 0x89769282, 0x4c4a1fbb, 0x0f5e64ac,
+ 0xc63305c8, 0x85277edf, 0x401bf3e6, 0x030f88f1, 0x070392de,
+ 0x4417e9c9, 0x812b64f0, 0xc23f1fe7, 0x0b527e83, 0x48460594,
+ 0x8d7a88ad, 0xce6ef3ba, 0x1fa14a65, 0x5cb53172, 0x9989bc4b,
+ 0xda9dc75c, 0x13f0a638, 0x50e4dd2f, 0x95d85016, 0xd6cc2b01,
+ 0x76415272, 0x35552965, 0xf069a45c, 0xb37ddf4b, 0x7a10be2f,
+ 0x3904c538, 0xfc384801, 0xbf2c3316, 0x6ee38ac9, 0x2df7f1de,
+ 0xe8cb7ce7, 0xabdf07f0, 0x62b26694, 0x21a61d83, 0xe49a90ba,
+ 0xa78eebad, 0xa481635c, 0xe795184b, 0x22a99572, 0x61bdee65,
+ 0xa8d08f01, 0xebc4f416, 0x2ef8792f, 0x6dec0238, 0xbc23bbe7,
+ 0xff37c0f0, 0x3a0b4dc9, 0x791f36de, 0xb07257ba, 0xf3662cad,
+ 0x365aa194, 0x754eda83, 0xd5c3a3f0, 0x96d7d8e7, 0x53eb55de,
+ 0x10ff2ec9, 0xd9924fad, 0x9a8634ba, 0x5fbab983, 0x1caec294,
+ 0xcd617b4b, 0x8e75005c, 0x4b498d65, 0x085df672, 0xc1309716,
+ 0x8224ec01, 0x47186138, 0x040c1a2f, 0x4f005566, 0x0c142e71,
+ 0xc928a348, 0x8a3cd85f, 0x4351b93b, 0x0045c22c, 0xc5794f15,
+ 0x866d3402, 0x57a28ddd, 0x14b6f6ca, 0xd18a7bf3, 0x929e00e4,
+ 0x5bf36180, 0x18e71a97, 0xdddb97ae, 0x9ecfecb9, 0x3e4295ca,
+ 0x7d56eedd, 0xb86a63e4, 0xfb7e18f3, 0x32137997, 0x71070280,
+ 0xb43b8fb9, 0xf72ff4ae, 0x26e04d71, 0x65f43666, 0xa0c8bb5f,
+ 0xe3dcc048, 0x2ab1a12c, 0x69a5da3b, 0xac995702, 0xef8d2c15,
+ 0xec82a4e4, 0xaf96dff3, 0x6aaa52ca, 0x29be29dd, 0xe0d348b9,
+ 0xa3c733ae, 0x66fbbe97, 0x25efc580, 0xf4207c5f, 0xb7340748,
+ 0x72088a71, 0x311cf166, 0xf8719002, 0xbb65eb15, 0x7e59662c,
+ 0x3d4d1d3b, 0x9dc06448, 0xded41f5f, 0x1be89266, 0x58fce971,
+ 0x91918815, 0xd285f302, 0x17b97e3b, 0x54ad052c, 0x8562bcf3,
+ 0xc676c7e4, 0x034a4add, 0x405e31ca, 0x893350ae, 0xca272bb9,
+ 0x0f1ba680, 0x4c0fdd97, 0x4803c7b8, 0x0b17bcaf, 0xce2b3196,
+ 0x8d3f4a81, 0x44522be5, 0x074650f2, 0xc27addcb, 0x816ea6dc,
+ 0x50a11f03, 0x13b56414, 0xd689e92d, 0x959d923a, 0x5cf0f35e,
+ 0x1fe48849, 0xdad80570, 0x99cc7e67, 0x39410714, 0x7a557c03,
+ 0xbf69f13a, 0xfc7d8a2d, 0x3510eb49, 0x7604905e, 0xb3381d67,
+ 0xf02c6670, 0x21e3dfaf, 0x62f7a4b8, 0xa7cb2981, 0xe4df5296,
+ 0x2db233f2, 0x6ea648e5, 0xab9ac5dc, 0xe88ebecb, 0xeb81363a,
+ 0xa8954d2d, 0x6da9c014, 0x2ebdbb03, 0xe7d0da67, 0xa4c4a170,
+ 0x61f82c49, 0x22ec575e, 0xf323ee81, 0xb0379596, 0x750b18af,
+ 0x361f63b8, 0xff7202dc, 0xbc6679cb, 0x795af4f2, 0x3a4e8fe5,
+ 0x9ac3f696, 0xd9d78d81, 0x1ceb00b8, 0x5fff7baf, 0x96921acb,
+ 0xd58661dc, 0x10baece5, 0x53ae97f2, 0x82612e2d, 0xc175553a,
+ 0x0449d803, 0x475da314, 0x8e30c270, 0xcd24b967, 0x0818345e,
+ 0x4b0c4f49},
+ {0x00000000, 0x3e6bc2ef, 0x3dd0f504, 0x03bb37eb, 0x7aa0eb09,
+ 0x44cb29e6, 0x47701e0d, 0x791bdce2, 0xf440d713, 0xca2b15fc,
+ 0xc9902217, 0xf7fbe0f8, 0x8ee03c1a, 0xb08bfef5, 0xb330c91e,
+ 0x8d5b0bf1, 0xe881ae27, 0xd6ea6cc8, 0xd5515b23, 0xeb3a99cc,
+ 0x9221452e, 0xac4a87c1, 0xaff1b02a, 0x919a72c5, 0x1cc17934,
+ 0x22aabbdb, 0x21118c30, 0x1f7a4edf, 0x6661923d, 0x580a50d2,
+ 0x5bb16739, 0x65daa5d6, 0xd0035d4f, 0xee689fa0, 0xedd3a84b,
+ 0xd3b86aa4, 0xaaa3b646, 0x94c874a9, 0x97734342, 0xa91881ad,
+ 0x24438a5c, 0x1a2848b3, 0x19937f58, 0x27f8bdb7, 0x5ee36155,
+ 0x6088a3ba, 0x63339451, 0x5d5856be, 0x3882f368, 0x06e93187,
+ 0x0552066c, 0x3b39c483, 0x42221861, 0x7c49da8e, 0x7ff2ed65,
+ 0x41992f8a, 0xccc2247b, 0xf2a9e694, 0xf112d17f, 0xcf791390,
+ 0xb662cf72, 0x88090d9d, 0x8bb23a76, 0xb5d9f899, 0xa007ba9e,
+ 0x9e6c7871, 0x9dd74f9a, 0xa3bc8d75, 0xdaa75197, 0xe4cc9378,
+ 0xe777a493, 0xd91c667c, 0x54476d8d, 0x6a2caf62, 0x69979889,
+ 0x57fc5a66, 0x2ee78684, 0x108c446b, 0x13377380, 0x2d5cb16f,
+ 0x488614b9, 0x76edd656, 0x7556e1bd, 0x4b3d2352, 0x3226ffb0,
+ 0x0c4d3d5f, 0x0ff60ab4, 0x319dc85b, 0xbcc6c3aa, 0x82ad0145,
+ 0x811636ae, 0xbf7df441, 0xc66628a3, 0xf80dea4c, 0xfbb6dda7,
+ 0xc5dd1f48, 0x7004e7d1, 0x4e6f253e, 0x4dd412d5, 0x73bfd03a,
+ 0x0aa40cd8, 0x34cfce37, 0x3774f9dc, 0x091f3b33, 0x844430c2,
+ 0xba2ff22d, 0xb994c5c6, 0x87ff0729, 0xfee4dbcb, 0xc08f1924,
+ 0xc3342ecf, 0xfd5fec20, 0x988549f6, 0xa6ee8b19, 0xa555bcf2,
+ 0x9b3e7e1d, 0xe225a2ff, 0xdc4e6010, 0xdff557fb, 0xe19e9514,
+ 0x6cc59ee5, 0x52ae5c0a, 0x51156be1, 0x6f7ea90e, 0x166575ec,
+ 0x280eb703, 0x2bb580e8, 0x15de4207, 0x010905e6, 0x3f62c709,
+ 0x3cd9f0e2, 0x02b2320d, 0x7ba9eeef, 0x45c22c00, 0x46791beb,
+ 0x7812d904, 0xf549d2f5, 0xcb22101a, 0xc89927f1, 0xf6f2e51e,
+ 0x8fe939fc, 0xb182fb13, 0xb239ccf8, 0x8c520e17, 0xe988abc1,
+ 0xd7e3692e, 0xd4585ec5, 0xea339c2a, 0x932840c8, 0xad438227,
+ 0xaef8b5cc, 0x90937723, 0x1dc87cd2, 0x23a3be3d, 0x201889d6,
+ 0x1e734b39, 0x676897db, 0x59035534, 0x5ab862df, 0x64d3a030,
+ 0xd10a58a9, 0xef619a46, 0xecdaadad, 0xd2b16f42, 0xabaab3a0,
+ 0x95c1714f, 0x967a46a4, 0xa811844b, 0x254a8fba, 0x1b214d55,
+ 0x189a7abe, 0x26f1b851, 0x5fea64b3, 0x6181a65c, 0x623a91b7,
+ 0x5c515358, 0x398bf68e, 0x07e03461, 0x045b038a, 0x3a30c165,
+ 0x432b1d87, 0x7d40df68, 0x7efbe883, 0x40902a6c, 0xcdcb219d,
+ 0xf3a0e372, 0xf01bd499, 0xce701676, 0xb76bca94, 0x8900087b,
+ 0x8abb3f90, 0xb4d0fd7f, 0xa10ebf78, 0x9f657d97, 0x9cde4a7c,
+ 0xa2b58893, 0xdbae5471, 0xe5c5969e, 0xe67ea175, 0xd815639a,
+ 0x554e686b, 0x6b25aa84, 0x689e9d6f, 0x56f55f80, 0x2fee8362,
+ 0x1185418d, 0x123e7666, 0x2c55b489, 0x498f115f, 0x77e4d3b0,
+ 0x745fe45b, 0x4a3426b4, 0x332ffa56, 0x0d4438b9, 0x0eff0f52,
+ 0x3094cdbd, 0xbdcfc64c, 0x83a404a3, 0x801f3348, 0xbe74f1a7,
+ 0xc76f2d45, 0xf904efaa, 0xfabfd841, 0xc4d41aae, 0x710de237,
+ 0x4f6620d8, 0x4cdd1733, 0x72b6d5dc, 0x0bad093e, 0x35c6cbd1,
+ 0x367dfc3a, 0x08163ed5, 0x854d3524, 0xbb26f7cb, 0xb89dc020,
+ 0x86f602cf, 0xffedde2d, 0xc1861cc2, 0xc23d2b29, 0xfc56e9c6,
+ 0x998c4c10, 0xa7e78eff, 0xa45cb914, 0x9a377bfb, 0xe32ca719,
+ 0xdd4765f6, 0xdefc521d, 0xe09790f2, 0x6dcc9b03, 0x53a759ec,
+ 0x501c6e07, 0x6e77ace8, 0x176c700a, 0x2907b2e5, 0x2abc850e,
+ 0x14d747e1},
+ {0x00000000, 0xc0df8ec1, 0xc1b96c58, 0x0166e299, 0x8273d9b0,
+ 0x42ac5771, 0x43cab5e8, 0x83153b29, 0x45e1c3ba, 0x853e4d7b,
+ 0x8458afe2, 0x44872123, 0xc7921a0a, 0x074d94cb, 0x062b7652,
+ 0xc6f4f893, 0xcbc4f6ae, 0x0b1b786f, 0x0a7d9af6, 0xcaa21437,
+ 0x49b72f1e, 0x8968a1df, 0x880e4346, 0x48d1cd87, 0x8e253514,
+ 0x4efabbd5, 0x4f9c594c, 0x8f43d78d, 0x0c56eca4, 0xcc896265,
+ 0xcdef80fc, 0x0d300e3d, 0xd78f9c86, 0x17501247, 0x1636f0de,
+ 0xd6e97e1f, 0x55fc4536, 0x9523cbf7, 0x9445296e, 0x549aa7af,
+ 0x926e5f3c, 0x52b1d1fd, 0x53d73364, 0x9308bda5, 0x101d868c,
+ 0xd0c2084d, 0xd1a4ead4, 0x117b6415, 0x1c4b6a28, 0xdc94e4e9,
+ 0xddf20670, 0x1d2d88b1, 0x9e38b398, 0x5ee73d59, 0x5f81dfc0,
+ 0x9f5e5101, 0x59aaa992, 0x99752753, 0x9813c5ca, 0x58cc4b0b,
+ 0xdbd97022, 0x1b06fee3, 0x1a601c7a, 0xdabf92bb, 0xef1948d6,
+ 0x2fc6c617, 0x2ea0248e, 0xee7faa4f, 0x6d6a9166, 0xadb51fa7,
+ 0xacd3fd3e, 0x6c0c73ff, 0xaaf88b6c, 0x6a2705ad, 0x6b41e734,
+ 0xab9e69f5, 0x288b52dc, 0xe854dc1d, 0xe9323e84, 0x29edb045,
+ 0x24ddbe78, 0xe40230b9, 0xe564d220, 0x25bb5ce1, 0xa6ae67c8,
+ 0x6671e909, 0x67170b90, 0xa7c88551, 0x613c7dc2, 0xa1e3f303,
+ 0xa085119a, 0x605a9f5b, 0xe34fa472, 0x23902ab3, 0x22f6c82a,
+ 0xe22946eb, 0x3896d450, 0xf8495a91, 0xf92fb808, 0x39f036c9,
+ 0xbae50de0, 0x7a3a8321, 0x7b5c61b8, 0xbb83ef79, 0x7d7717ea,
+ 0xbda8992b, 0xbcce7bb2, 0x7c11f573, 0xff04ce5a, 0x3fdb409b,
+ 0x3ebda202, 0xfe622cc3, 0xf35222fe, 0x338dac3f, 0x32eb4ea6,
+ 0xf234c067, 0x7121fb4e, 0xb1fe758f, 0xb0989716, 0x704719d7,
+ 0xb6b3e144, 0x766c6f85, 0x770a8d1c, 0xb7d503dd, 0x34c038f4,
+ 0xf41fb635, 0xf57954ac, 0x35a6da6d, 0x9f35e177, 0x5fea6fb6,
+ 0x5e8c8d2f, 0x9e5303ee, 0x1d4638c7, 0xdd99b606, 0xdcff549f,
+ 0x1c20da5e, 0xdad422cd, 0x1a0bac0c, 0x1b6d4e95, 0xdbb2c054,
+ 0x58a7fb7d, 0x987875bc, 0x991e9725, 0x59c119e4, 0x54f117d9,
+ 0x942e9918, 0x95487b81, 0x5597f540, 0xd682ce69, 0x165d40a8,
+ 0x173ba231, 0xd7e42cf0, 0x1110d463, 0xd1cf5aa2, 0xd0a9b83b,
+ 0x107636fa, 0x93630dd3, 0x53bc8312, 0x52da618b, 0x9205ef4a,
+ 0x48ba7df1, 0x8865f330, 0x890311a9, 0x49dc9f68, 0xcac9a441,
+ 0x0a162a80, 0x0b70c819, 0xcbaf46d8, 0x0d5bbe4b, 0xcd84308a,
+ 0xcce2d213, 0x0c3d5cd2, 0x8f2867fb, 0x4ff7e93a, 0x4e910ba3,
+ 0x8e4e8562, 0x837e8b5f, 0x43a1059e, 0x42c7e707, 0x821869c6,
+ 0x010d52ef, 0xc1d2dc2e, 0xc0b43eb7, 0x006bb076, 0xc69f48e5,
+ 0x0640c624, 0x072624bd, 0xc7f9aa7c, 0x44ec9155, 0x84331f94,
+ 0x8555fd0d, 0x458a73cc, 0x702ca9a1, 0xb0f32760, 0xb195c5f9,
+ 0x714a4b38, 0xf25f7011, 0x3280fed0, 0x33e61c49, 0xf3399288,
+ 0x35cd6a1b, 0xf512e4da, 0xf4740643, 0x34ab8882, 0xb7beb3ab,
+ 0x77613d6a, 0x7607dff3, 0xb6d85132, 0xbbe85f0f, 0x7b37d1ce,
+ 0x7a513357, 0xba8ebd96, 0x399b86bf, 0xf944087e, 0xf822eae7,
+ 0x38fd6426, 0xfe099cb5, 0x3ed61274, 0x3fb0f0ed, 0xff6f7e2c,
+ 0x7c7a4505, 0xbca5cbc4, 0xbdc3295d, 0x7d1ca79c, 0xa7a33527,
+ 0x677cbbe6, 0x661a597f, 0xa6c5d7be, 0x25d0ec97, 0xe50f6256,
+ 0xe46980cf, 0x24b60e0e, 0xe242f69d, 0x229d785c, 0x23fb9ac5,
+ 0xe3241404, 0x60312f2d, 0xa0eea1ec, 0xa1884375, 0x6157cdb4,
+ 0x6c67c389, 0xacb84d48, 0xaddeafd1, 0x6d012110, 0xee141a39,
+ 0x2ecb94f8, 0x2fad7661, 0xef72f8a0, 0x29860033, 0xe9598ef2,
+ 0xe83f6c6b, 0x28e0e2aa, 0xabf5d983, 0x6b2a5742, 0x6a4cb5db,
+ 0xaa933b1a},
+ {0x00000000, 0x6f4ca59b, 0x9f9e3bec, 0xf0d29e77, 0x7f3b0603,
+ 0x1077a398, 0xe0a53def, 0x8fe99874, 0xfe760c06, 0x913aa99d,
+ 0x61e837ea, 0x0ea49271, 0x814d0a05, 0xee01af9e, 0x1ed331e9,
+ 0x719f9472, 0xfced180c, 0x93a1bd97, 0x637323e0, 0x0c3f867b,
+ 0x83d61e0f, 0xec9abb94, 0x1c4825e3, 0x73048078, 0x029b140a,
+ 0x6dd7b191, 0x9d052fe6, 0xf2498a7d, 0x7da01209, 0x12ecb792,
+ 0xe23e29e5, 0x8d728c7e, 0xf8db3118, 0x97979483, 0x67450af4,
+ 0x0809af6f, 0x87e0371b, 0xe8ac9280, 0x187e0cf7, 0x7732a96c,
+ 0x06ad3d1e, 0x69e19885, 0x993306f2, 0xf67fa369, 0x79963b1d,
+ 0x16da9e86, 0xe60800f1, 0x8944a56a, 0x04362914, 0x6b7a8c8f,
+ 0x9ba812f8, 0xf4e4b763, 0x7b0d2f17, 0x14418a8c, 0xe49314fb,
+ 0x8bdfb160, 0xfa402512, 0x950c8089, 0x65de1efe, 0x0a92bb65,
+ 0x857b2311, 0xea37868a, 0x1ae518fd, 0x75a9bd66, 0xf0b76330,
+ 0x9ffbc6ab, 0x6f2958dc, 0x0065fd47, 0x8f8c6533, 0xe0c0c0a8,
+ 0x10125edf, 0x7f5efb44, 0x0ec16f36, 0x618dcaad, 0x915f54da,
+ 0xfe13f141, 0x71fa6935, 0x1eb6ccae, 0xee6452d9, 0x8128f742,
+ 0x0c5a7b3c, 0x6316dea7, 0x93c440d0, 0xfc88e54b, 0x73617d3f,
+ 0x1c2dd8a4, 0xecff46d3, 0x83b3e348, 0xf22c773a, 0x9d60d2a1,
+ 0x6db24cd6, 0x02fee94d, 0x8d177139, 0xe25bd4a2, 0x12894ad5,
+ 0x7dc5ef4e, 0x086c5228, 0x6720f7b3, 0x97f269c4, 0xf8becc5f,
+ 0x7757542b, 0x181bf1b0, 0xe8c96fc7, 0x8785ca5c, 0xf61a5e2e,
+ 0x9956fbb5, 0x698465c2, 0x06c8c059, 0x8921582d, 0xe66dfdb6,
+ 0x16bf63c1, 0x79f3c65a, 0xf4814a24, 0x9bcdefbf, 0x6b1f71c8,
+ 0x0453d453, 0x8bba4c27, 0xe4f6e9bc, 0x142477cb, 0x7b68d250,
+ 0x0af74622, 0x65bbe3b9, 0x95697dce, 0xfa25d855, 0x75cc4021,
+ 0x1a80e5ba, 0xea527bcd, 0x851ede56, 0xe06fc760, 0x8f2362fb,
+ 0x7ff1fc8c, 0x10bd5917, 0x9f54c163, 0xf01864f8, 0x00cafa8f,
+ 0x6f865f14, 0x1e19cb66, 0x71556efd, 0x8187f08a, 0xeecb5511,
+ 0x6122cd65, 0x0e6e68fe, 0xfebcf689, 0x91f05312, 0x1c82df6c,
+ 0x73ce7af7, 0x831ce480, 0xec50411b, 0x63b9d96f, 0x0cf57cf4,
+ 0xfc27e283, 0x936b4718, 0xe2f4d36a, 0x8db876f1, 0x7d6ae886,
+ 0x12264d1d, 0x9dcfd569, 0xf28370f2, 0x0251ee85, 0x6d1d4b1e,
+ 0x18b4f678, 0x77f853e3, 0x872acd94, 0xe866680f, 0x678ff07b,
+ 0x08c355e0, 0xf811cb97, 0x975d6e0c, 0xe6c2fa7e, 0x898e5fe5,
+ 0x795cc192, 0x16106409, 0x99f9fc7d, 0xf6b559e6, 0x0667c791,
+ 0x692b620a, 0xe459ee74, 0x8b154bef, 0x7bc7d598, 0x148b7003,
+ 0x9b62e877, 0xf42e4dec, 0x04fcd39b, 0x6bb07600, 0x1a2fe272,
+ 0x756347e9, 0x85b1d99e, 0xeafd7c05, 0x6514e471, 0x0a5841ea,
+ 0xfa8adf9d, 0x95c67a06, 0x10d8a450, 0x7f9401cb, 0x8f469fbc,
+ 0xe00a3a27, 0x6fe3a253, 0x00af07c8, 0xf07d99bf, 0x9f313c24,
+ 0xeeaea856, 0x81e20dcd, 0x713093ba, 0x1e7c3621, 0x9195ae55,
+ 0xfed90bce, 0x0e0b95b9, 0x61473022, 0xec35bc5c, 0x837919c7,
+ 0x73ab87b0, 0x1ce7222b, 0x930eba5f, 0xfc421fc4, 0x0c9081b3,
+ 0x63dc2428, 0x1243b05a, 0x7d0f15c1, 0x8ddd8bb6, 0xe2912e2d,
+ 0x6d78b659, 0x023413c2, 0xf2e68db5, 0x9daa282e, 0xe8039548,
+ 0x874f30d3, 0x779daea4, 0x18d10b3f, 0x9738934b, 0xf87436d0,
+ 0x08a6a8a7, 0x67ea0d3c, 0x1675994e, 0x79393cd5, 0x89eba2a2,
+ 0xe6a70739, 0x694e9f4d, 0x06023ad6, 0xf6d0a4a1, 0x999c013a,
+ 0x14ee8d44, 0x7ba228df, 0x8b70b6a8, 0xe43c1333, 0x6bd58b47,
+ 0x04992edc, 0xf44bb0ab, 0x9b071530, 0xea988142, 0x85d424d9,
+ 0x7506baae, 0x1a4a1f35, 0x95a38741, 0xfaef22da, 0x0a3dbcad,
+ 0x65711936}};
+
+#endif
+
+#endif
+
+#if N == 4
+
+#if W == 8
+
+local const z_crc_t FAR crc_braid_table[][256] = {
+ {0x00000000, 0xf1da05aa, 0x38c50d15, 0xc91f08bf, 0x718a1a2a,
+ 0x80501f80, 0x494f173f, 0xb8951295, 0xe3143454, 0x12ce31fe,
+ 0xdbd13941, 0x2a0b3ceb, 0x929e2e7e, 0x63442bd4, 0xaa5b236b,
+ 0x5b8126c1, 0x1d596ee9, 0xec836b43, 0x259c63fc, 0xd4466656,
+ 0x6cd374c3, 0x9d097169, 0x541679d6, 0xa5cc7c7c, 0xfe4d5abd,
+ 0x0f975f17, 0xc68857a8, 0x37525202, 0x8fc74097, 0x7e1d453d,
+ 0xb7024d82, 0x46d84828, 0x3ab2ddd2, 0xcb68d878, 0x0277d0c7,
+ 0xf3add56d, 0x4b38c7f8, 0xbae2c252, 0x73fdcaed, 0x8227cf47,
+ 0xd9a6e986, 0x287cec2c, 0xe163e493, 0x10b9e139, 0xa82cf3ac,
+ 0x59f6f606, 0x90e9feb9, 0x6133fb13, 0x27ebb33b, 0xd631b691,
+ 0x1f2ebe2e, 0xeef4bb84, 0x5661a911, 0xa7bbacbb, 0x6ea4a404,
+ 0x9f7ea1ae, 0xc4ff876f, 0x352582c5, 0xfc3a8a7a, 0x0de08fd0,
+ 0xb5759d45, 0x44af98ef, 0x8db09050, 0x7c6a95fa, 0x7565bba4,
+ 0x84bfbe0e, 0x4da0b6b1, 0xbc7ab31b, 0x04efa18e, 0xf535a424,
+ 0x3c2aac9b, 0xcdf0a931, 0x96718ff0, 0x67ab8a5a, 0xaeb482e5,
+ 0x5f6e874f, 0xe7fb95da, 0x16219070, 0xdf3e98cf, 0x2ee49d65,
+ 0x683cd54d, 0x99e6d0e7, 0x50f9d858, 0xa123ddf2, 0x19b6cf67,
+ 0xe86ccacd, 0x2173c272, 0xd0a9c7d8, 0x8b28e119, 0x7af2e4b3,
+ 0xb3edec0c, 0x4237e9a6, 0xfaa2fb33, 0x0b78fe99, 0xc267f626,
+ 0x33bdf38c, 0x4fd76676, 0xbe0d63dc, 0x77126b63, 0x86c86ec9,
+ 0x3e5d7c5c, 0xcf8779f6, 0x06987149, 0xf74274e3, 0xacc35222,
+ 0x5d195788, 0x94065f37, 0x65dc5a9d, 0xdd494808, 0x2c934da2,
+ 0xe58c451d, 0x145640b7, 0x528e089f, 0xa3540d35, 0x6a4b058a,
+ 0x9b910020, 0x230412b5, 0xd2de171f, 0x1bc11fa0, 0xea1b1a0a,
+ 0xb19a3ccb, 0x40403961, 0x895f31de, 0x78853474, 0xc01026e1,
+ 0x31ca234b, 0xf8d52bf4, 0x090f2e5e, 0xeacb7748, 0x1b1172e2,
+ 0xd20e7a5d, 0x23d47ff7, 0x9b416d62, 0x6a9b68c8, 0xa3846077,
+ 0x525e65dd, 0x09df431c, 0xf80546b6, 0x311a4e09, 0xc0c04ba3,
+ 0x78555936, 0x898f5c9c, 0x40905423, 0xb14a5189, 0xf79219a1,
+ 0x06481c0b, 0xcf5714b4, 0x3e8d111e, 0x8618038b, 0x77c20621,
+ 0xbedd0e9e, 0x4f070b34, 0x14862df5, 0xe55c285f, 0x2c4320e0,
+ 0xdd99254a, 0x650c37df, 0x94d63275, 0x5dc93aca, 0xac133f60,
+ 0xd079aa9a, 0x21a3af30, 0xe8bca78f, 0x1966a225, 0xa1f3b0b0,
+ 0x5029b51a, 0x9936bda5, 0x68ecb80f, 0x336d9ece, 0xc2b79b64,
+ 0x0ba893db, 0xfa729671, 0x42e784e4, 0xb33d814e, 0x7a2289f1,
+ 0x8bf88c5b, 0xcd20c473, 0x3cfac1d9, 0xf5e5c966, 0x043fcccc,
+ 0xbcaade59, 0x4d70dbf3, 0x846fd34c, 0x75b5d6e6, 0x2e34f027,
+ 0xdfeef58d, 0x16f1fd32, 0xe72bf898, 0x5fbeea0d, 0xae64efa7,
+ 0x677be718, 0x96a1e2b2, 0x9faeccec, 0x6e74c946, 0xa76bc1f9,
+ 0x56b1c453, 0xee24d6c6, 0x1ffed36c, 0xd6e1dbd3, 0x273bde79,
+ 0x7cbaf8b8, 0x8d60fd12, 0x447ff5ad, 0xb5a5f007, 0x0d30e292,
+ 0xfceae738, 0x35f5ef87, 0xc42fea2d, 0x82f7a205, 0x732da7af,
+ 0xba32af10, 0x4be8aaba, 0xf37db82f, 0x02a7bd85, 0xcbb8b53a,
+ 0x3a62b090, 0x61e39651, 0x903993fb, 0x59269b44, 0xa8fc9eee,
+ 0x10698c7b, 0xe1b389d1, 0x28ac816e, 0xd97684c4, 0xa51c113e,
+ 0x54c61494, 0x9dd91c2b, 0x6c031981, 0xd4960b14, 0x254c0ebe,
+ 0xec530601, 0x1d8903ab, 0x4608256a, 0xb7d220c0, 0x7ecd287f,
+ 0x8f172dd5, 0x37823f40, 0xc6583aea, 0x0f473255, 0xfe9d37ff,
+ 0xb8457fd7, 0x499f7a7d, 0x808072c2, 0x715a7768, 0xc9cf65fd,
+ 0x38156057, 0xf10a68e8, 0x00d06d42, 0x5b514b83, 0xaa8b4e29,
+ 0x63944696, 0x924e433c, 0x2adb51a9, 0xdb015403, 0x121e5cbc,
+ 0xe3c45916},
+ {0x00000000, 0x0ee7e8d1, 0x1dcfd1a2, 0x13283973, 0x3b9fa344,
+ 0x35784b95, 0x265072e6, 0x28b79a37, 0x773f4688, 0x79d8ae59,
+ 0x6af0972a, 0x64177ffb, 0x4ca0e5cc, 0x42470d1d, 0x516f346e,
+ 0x5f88dcbf, 0xee7e8d10, 0xe09965c1, 0xf3b15cb2, 0xfd56b463,
+ 0xd5e12e54, 0xdb06c685, 0xc82efff6, 0xc6c91727, 0x9941cb98,
+ 0x97a62349, 0x848e1a3a, 0x8a69f2eb, 0xa2de68dc, 0xac39800d,
+ 0xbf11b97e, 0xb1f651af, 0x078c1c61, 0x096bf4b0, 0x1a43cdc3,
+ 0x14a42512, 0x3c13bf25, 0x32f457f4, 0x21dc6e87, 0x2f3b8656,
+ 0x70b35ae9, 0x7e54b238, 0x6d7c8b4b, 0x639b639a, 0x4b2cf9ad,
+ 0x45cb117c, 0x56e3280f, 0x5804c0de, 0xe9f29171, 0xe71579a0,
+ 0xf43d40d3, 0xfadaa802, 0xd26d3235, 0xdc8adae4, 0xcfa2e397,
+ 0xc1450b46, 0x9ecdd7f9, 0x902a3f28, 0x8302065b, 0x8de5ee8a,
+ 0xa55274bd, 0xabb59c6c, 0xb89da51f, 0xb67a4dce, 0x0f1838c2,
+ 0x01ffd013, 0x12d7e960, 0x1c3001b1, 0x34879b86, 0x3a607357,
+ 0x29484a24, 0x27afa2f5, 0x78277e4a, 0x76c0969b, 0x65e8afe8,
+ 0x6b0f4739, 0x43b8dd0e, 0x4d5f35df, 0x5e770cac, 0x5090e47d,
+ 0xe166b5d2, 0xef815d03, 0xfca96470, 0xf24e8ca1, 0xdaf91696,
+ 0xd41efe47, 0xc736c734, 0xc9d12fe5, 0x9659f35a, 0x98be1b8b,
+ 0x8b9622f8, 0x8571ca29, 0xadc6501e, 0xa321b8cf, 0xb00981bc,
+ 0xbeee696d, 0x089424a3, 0x0673cc72, 0x155bf501, 0x1bbc1dd0,
+ 0x330b87e7, 0x3dec6f36, 0x2ec45645, 0x2023be94, 0x7fab622b,
+ 0x714c8afa, 0x6264b389, 0x6c835b58, 0x4434c16f, 0x4ad329be,
+ 0x59fb10cd, 0x571cf81c, 0xe6eaa9b3, 0xe80d4162, 0xfb257811,
+ 0xf5c290c0, 0xdd750af7, 0xd392e226, 0xc0badb55, 0xce5d3384,
+ 0x91d5ef3b, 0x9f3207ea, 0x8c1a3e99, 0x82fdd648, 0xaa4a4c7f,
+ 0xa4ada4ae, 0xb7859ddd, 0xb962750c, 0x1e307184, 0x10d79955,
+ 0x03ffa026, 0x0d1848f7, 0x25afd2c0, 0x2b483a11, 0x38600362,
+ 0x3687ebb3, 0x690f370c, 0x67e8dfdd, 0x74c0e6ae, 0x7a270e7f,
+ 0x52909448, 0x5c777c99, 0x4f5f45ea, 0x41b8ad3b, 0xf04efc94,
+ 0xfea91445, 0xed812d36, 0xe366c5e7, 0xcbd15fd0, 0xc536b701,
+ 0xd61e8e72, 0xd8f966a3, 0x8771ba1c, 0x899652cd, 0x9abe6bbe,
+ 0x9459836f, 0xbcee1958, 0xb209f189, 0xa121c8fa, 0xafc6202b,
+ 0x19bc6de5, 0x175b8534, 0x0473bc47, 0x0a945496, 0x2223cea1,
+ 0x2cc42670, 0x3fec1f03, 0x310bf7d2, 0x6e832b6d, 0x6064c3bc,
+ 0x734cfacf, 0x7dab121e, 0x551c8829, 0x5bfb60f8, 0x48d3598b,
+ 0x4634b15a, 0xf7c2e0f5, 0xf9250824, 0xea0d3157, 0xe4ead986,
+ 0xcc5d43b1, 0xc2baab60, 0xd1929213, 0xdf757ac2, 0x80fda67d,
+ 0x8e1a4eac, 0x9d3277df, 0x93d59f0e, 0xbb620539, 0xb585ede8,
+ 0xa6add49b, 0xa84a3c4a, 0x11284946, 0x1fcfa197, 0x0ce798e4,
+ 0x02007035, 0x2ab7ea02, 0x245002d3, 0x37783ba0, 0x399fd371,
+ 0x66170fce, 0x68f0e71f, 0x7bd8de6c, 0x753f36bd, 0x5d88ac8a,
+ 0x536f445b, 0x40477d28, 0x4ea095f9, 0xff56c456, 0xf1b12c87,
+ 0xe29915f4, 0xec7efd25, 0xc4c96712, 0xca2e8fc3, 0xd906b6b0,
+ 0xd7e15e61, 0x886982de, 0x868e6a0f, 0x95a6537c, 0x9b41bbad,
+ 0xb3f6219a, 0xbd11c94b, 0xae39f038, 0xa0de18e9, 0x16a45527,
+ 0x1843bdf6, 0x0b6b8485, 0x058c6c54, 0x2d3bf663, 0x23dc1eb2,
+ 0x30f427c1, 0x3e13cf10, 0x619b13af, 0x6f7cfb7e, 0x7c54c20d,
+ 0x72b32adc, 0x5a04b0eb, 0x54e3583a, 0x47cb6149, 0x492c8998,
+ 0xf8dad837, 0xf63d30e6, 0xe5150995, 0xebf2e144, 0xc3457b73,
+ 0xcda293a2, 0xde8aaad1, 0xd06d4200, 0x8fe59ebf, 0x8102766e,
+ 0x922a4f1d, 0x9ccda7cc, 0xb47a3dfb, 0xba9dd52a, 0xa9b5ec59,
+ 0xa7520488},
+ {0x00000000, 0x3c60e308, 0x78c1c610, 0x44a12518, 0xf1838c20,
+ 0xcde36f28, 0x89424a30, 0xb522a938, 0x38761e01, 0x0416fd09,
+ 0x40b7d811, 0x7cd73b19, 0xc9f59221, 0xf5957129, 0xb1345431,
+ 0x8d54b739, 0x70ec3c02, 0x4c8cdf0a, 0x082dfa12, 0x344d191a,
+ 0x816fb022, 0xbd0f532a, 0xf9ae7632, 0xc5ce953a, 0x489a2203,
+ 0x74fac10b, 0x305be413, 0x0c3b071b, 0xb919ae23, 0x85794d2b,
+ 0xc1d86833, 0xfdb88b3b, 0xe1d87804, 0xddb89b0c, 0x9919be14,
+ 0xa5795d1c, 0x105bf424, 0x2c3b172c, 0x689a3234, 0x54fad13c,
+ 0xd9ae6605, 0xe5ce850d, 0xa16fa015, 0x9d0f431d, 0x282dea25,
+ 0x144d092d, 0x50ec2c35, 0x6c8ccf3d, 0x91344406, 0xad54a70e,
+ 0xe9f58216, 0xd595611e, 0x60b7c826, 0x5cd72b2e, 0x18760e36,
+ 0x2416ed3e, 0xa9425a07, 0x9522b90f, 0xd1839c17, 0xede37f1f,
+ 0x58c1d627, 0x64a1352f, 0x20001037, 0x1c60f33f, 0x18c1f649,
+ 0x24a11541, 0x60003059, 0x5c60d351, 0xe9427a69, 0xd5229961,
+ 0x9183bc79, 0xade35f71, 0x20b7e848, 0x1cd70b40, 0x58762e58,
+ 0x6416cd50, 0xd1346468, 0xed548760, 0xa9f5a278, 0x95954170,
+ 0x682dca4b, 0x544d2943, 0x10ec0c5b, 0x2c8cef53, 0x99ae466b,
+ 0xa5cea563, 0xe16f807b, 0xdd0f6373, 0x505bd44a, 0x6c3b3742,
+ 0x289a125a, 0x14faf152, 0xa1d8586a, 0x9db8bb62, 0xd9199e7a,
+ 0xe5797d72, 0xf9198e4d, 0xc5796d45, 0x81d8485d, 0xbdb8ab55,
+ 0x089a026d, 0x34fae165, 0x705bc47d, 0x4c3b2775, 0xc16f904c,
+ 0xfd0f7344, 0xb9ae565c, 0x85ceb554, 0x30ec1c6c, 0x0c8cff64,
+ 0x482dda7c, 0x744d3974, 0x89f5b24f, 0xb5955147, 0xf134745f,
+ 0xcd549757, 0x78763e6f, 0x4416dd67, 0x00b7f87f, 0x3cd71b77,
+ 0xb183ac4e, 0x8de34f46, 0xc9426a5e, 0xf5228956, 0x4000206e,
+ 0x7c60c366, 0x38c1e67e, 0x04a10576, 0x3183ec92, 0x0de30f9a,
+ 0x49422a82, 0x7522c98a, 0xc00060b2, 0xfc6083ba, 0xb8c1a6a2,
+ 0x84a145aa, 0x09f5f293, 0x3595119b, 0x71343483, 0x4d54d78b,
+ 0xf8767eb3, 0xc4169dbb, 0x80b7b8a3, 0xbcd75bab, 0x416fd090,
+ 0x7d0f3398, 0x39ae1680, 0x05cef588, 0xb0ec5cb0, 0x8c8cbfb8,
+ 0xc82d9aa0, 0xf44d79a8, 0x7919ce91, 0x45792d99, 0x01d80881,
+ 0x3db8eb89, 0x889a42b1, 0xb4faa1b9, 0xf05b84a1, 0xcc3b67a9,
+ 0xd05b9496, 0xec3b779e, 0xa89a5286, 0x94fab18e, 0x21d818b6,
+ 0x1db8fbbe, 0x5919dea6, 0x65793dae, 0xe82d8a97, 0xd44d699f,
+ 0x90ec4c87, 0xac8caf8f, 0x19ae06b7, 0x25cee5bf, 0x616fc0a7,
+ 0x5d0f23af, 0xa0b7a894, 0x9cd74b9c, 0xd8766e84, 0xe4168d8c,
+ 0x513424b4, 0x6d54c7bc, 0x29f5e2a4, 0x159501ac, 0x98c1b695,
+ 0xa4a1559d, 0xe0007085, 0xdc60938d, 0x69423ab5, 0x5522d9bd,
+ 0x1183fca5, 0x2de31fad, 0x29421adb, 0x1522f9d3, 0x5183dccb,
+ 0x6de33fc3, 0xd8c196fb, 0xe4a175f3, 0xa00050eb, 0x9c60b3e3,
+ 0x113404da, 0x2d54e7d2, 0x69f5c2ca, 0x559521c2, 0xe0b788fa,
+ 0xdcd76bf2, 0x98764eea, 0xa416ade2, 0x59ae26d9, 0x65cec5d1,
+ 0x216fe0c9, 0x1d0f03c1, 0xa82daaf9, 0x944d49f1, 0xd0ec6ce9,
+ 0xec8c8fe1, 0x61d838d8, 0x5db8dbd0, 0x1919fec8, 0x25791dc0,
+ 0x905bb4f8, 0xac3b57f0, 0xe89a72e8, 0xd4fa91e0, 0xc89a62df,
+ 0xf4fa81d7, 0xb05ba4cf, 0x8c3b47c7, 0x3919eeff, 0x05790df7,
+ 0x41d828ef, 0x7db8cbe7, 0xf0ec7cde, 0xcc8c9fd6, 0x882dbace,
+ 0xb44d59c6, 0x016ff0fe, 0x3d0f13f6, 0x79ae36ee, 0x45ced5e6,
+ 0xb8765edd, 0x8416bdd5, 0xc0b798cd, 0xfcd77bc5, 0x49f5d2fd,
+ 0x759531f5, 0x313414ed, 0x0d54f7e5, 0x800040dc, 0xbc60a3d4,
+ 0xf8c186cc, 0xc4a165c4, 0x7183ccfc, 0x4de32ff4, 0x09420aec,
+ 0x3522e9e4},
+ {0x00000000, 0x6307d924, 0xc60fb248, 0xa5086b6c, 0x576e62d1,
+ 0x3469bbf5, 0x9161d099, 0xf26609bd, 0xaedcc5a2, 0xcddb1c86,
+ 0x68d377ea, 0x0bd4aece, 0xf9b2a773, 0x9ab57e57, 0x3fbd153b,
+ 0x5cbacc1f, 0x86c88d05, 0xe5cf5421, 0x40c73f4d, 0x23c0e669,
+ 0xd1a6efd4, 0xb2a136f0, 0x17a95d9c, 0x74ae84b8, 0x281448a7,
+ 0x4b139183, 0xee1bfaef, 0x8d1c23cb, 0x7f7a2a76, 0x1c7df352,
+ 0xb975983e, 0xda72411a, 0xd6e01c4b, 0xb5e7c56f, 0x10efae03,
+ 0x73e87727, 0x818e7e9a, 0xe289a7be, 0x4781ccd2, 0x248615f6,
+ 0x783cd9e9, 0x1b3b00cd, 0xbe336ba1, 0xdd34b285, 0x2f52bb38,
+ 0x4c55621c, 0xe95d0970, 0x8a5ad054, 0x5028914e, 0x332f486a,
+ 0x96272306, 0xf520fa22, 0x0746f39f, 0x64412abb, 0xc14941d7,
+ 0xa24e98f3, 0xfef454ec, 0x9df38dc8, 0x38fbe6a4, 0x5bfc3f80,
+ 0xa99a363d, 0xca9def19, 0x6f958475, 0x0c925d51, 0x76b13ed7,
+ 0x15b6e7f3, 0xb0be8c9f, 0xd3b955bb, 0x21df5c06, 0x42d88522,
+ 0xe7d0ee4e, 0x84d7376a, 0xd86dfb75, 0xbb6a2251, 0x1e62493d,
+ 0x7d659019, 0x8f0399a4, 0xec044080, 0x490c2bec, 0x2a0bf2c8,
+ 0xf079b3d2, 0x937e6af6, 0x3676019a, 0x5571d8be, 0xa717d103,
+ 0xc4100827, 0x6118634b, 0x021fba6f, 0x5ea57670, 0x3da2af54,
+ 0x98aac438, 0xfbad1d1c, 0x09cb14a1, 0x6acccd85, 0xcfc4a6e9,
+ 0xacc37fcd, 0xa051229c, 0xc356fbb8, 0x665e90d4, 0x055949f0,
+ 0xf73f404d, 0x94389969, 0x3130f205, 0x52372b21, 0x0e8de73e,
+ 0x6d8a3e1a, 0xc8825576, 0xab858c52, 0x59e385ef, 0x3ae45ccb,
+ 0x9fec37a7, 0xfcebee83, 0x2699af99, 0x459e76bd, 0xe0961dd1,
+ 0x8391c4f5, 0x71f7cd48, 0x12f0146c, 0xb7f87f00, 0xd4ffa624,
+ 0x88456a3b, 0xeb42b31f, 0x4e4ad873, 0x2d4d0157, 0xdf2b08ea,
+ 0xbc2cd1ce, 0x1924baa2, 0x7a236386, 0xed627dae, 0x8e65a48a,
+ 0x2b6dcfe6, 0x486a16c2, 0xba0c1f7f, 0xd90bc65b, 0x7c03ad37,
+ 0x1f047413, 0x43beb80c, 0x20b96128, 0x85b10a44, 0xe6b6d360,
+ 0x14d0dadd, 0x77d703f9, 0xd2df6895, 0xb1d8b1b1, 0x6baaf0ab,
+ 0x08ad298f, 0xada542e3, 0xcea29bc7, 0x3cc4927a, 0x5fc34b5e,
+ 0xfacb2032, 0x99ccf916, 0xc5763509, 0xa671ec2d, 0x03798741,
+ 0x607e5e65, 0x921857d8, 0xf11f8efc, 0x5417e590, 0x37103cb4,
+ 0x3b8261e5, 0x5885b8c1, 0xfd8dd3ad, 0x9e8a0a89, 0x6cec0334,
+ 0x0febda10, 0xaae3b17c, 0xc9e46858, 0x955ea447, 0xf6597d63,
+ 0x5351160f, 0x3056cf2b, 0xc230c696, 0xa1371fb2, 0x043f74de,
+ 0x6738adfa, 0xbd4aece0, 0xde4d35c4, 0x7b455ea8, 0x1842878c,
+ 0xea248e31, 0x89235715, 0x2c2b3c79, 0x4f2ce55d, 0x13962942,
+ 0x7091f066, 0xd5999b0a, 0xb69e422e, 0x44f84b93, 0x27ff92b7,
+ 0x82f7f9db, 0xe1f020ff, 0x9bd34379, 0xf8d49a5d, 0x5ddcf131,
+ 0x3edb2815, 0xccbd21a8, 0xafbaf88c, 0x0ab293e0, 0x69b54ac4,
+ 0x350f86db, 0x56085fff, 0xf3003493, 0x9007edb7, 0x6261e40a,
+ 0x01663d2e, 0xa46e5642, 0xc7698f66, 0x1d1bce7c, 0x7e1c1758,
+ 0xdb147c34, 0xb813a510, 0x4a75acad, 0x29727589, 0x8c7a1ee5,
+ 0xef7dc7c1, 0xb3c70bde, 0xd0c0d2fa, 0x75c8b996, 0x16cf60b2,
+ 0xe4a9690f, 0x87aeb02b, 0x22a6db47, 0x41a10263, 0x4d335f32,
+ 0x2e348616, 0x8b3ced7a, 0xe83b345e, 0x1a5d3de3, 0x795ae4c7,
+ 0xdc528fab, 0xbf55568f, 0xe3ef9a90, 0x80e843b4, 0x25e028d8,
+ 0x46e7f1fc, 0xb481f841, 0xd7862165, 0x728e4a09, 0x1189932d,
+ 0xcbfbd237, 0xa8fc0b13, 0x0df4607f, 0x6ef3b95b, 0x9c95b0e6,
+ 0xff9269c2, 0x5a9a02ae, 0x399ddb8a, 0x65271795, 0x0620ceb1,
+ 0xa328a5dd, 0xc02f7cf9, 0x32497544, 0x514eac60, 0xf446c70c,
+ 0x97411e28},
+ {0x00000000, 0x01b5fd1d, 0x036bfa3a, 0x02de0727, 0x06d7f474,
+ 0x07620969, 0x05bc0e4e, 0x0409f353, 0x0dafe8e8, 0x0c1a15f5,
+ 0x0ec412d2, 0x0f71efcf, 0x0b781c9c, 0x0acde181, 0x0813e6a6,
+ 0x09a61bbb, 0x1b5fd1d0, 0x1aea2ccd, 0x18342bea, 0x1981d6f7,
+ 0x1d8825a4, 0x1c3dd8b9, 0x1ee3df9e, 0x1f562283, 0x16f03938,
+ 0x1745c425, 0x159bc302, 0x142e3e1f, 0x1027cd4c, 0x11923051,
+ 0x134c3776, 0x12f9ca6b, 0x36bfa3a0, 0x370a5ebd, 0x35d4599a,
+ 0x3461a487, 0x306857d4, 0x31ddaac9, 0x3303adee, 0x32b650f3,
+ 0x3b104b48, 0x3aa5b655, 0x387bb172, 0x39ce4c6f, 0x3dc7bf3c,
+ 0x3c724221, 0x3eac4506, 0x3f19b81b, 0x2de07270, 0x2c558f6d,
+ 0x2e8b884a, 0x2f3e7557, 0x2b378604, 0x2a827b19, 0x285c7c3e,
+ 0x29e98123, 0x204f9a98, 0x21fa6785, 0x232460a2, 0x22919dbf,
+ 0x26986eec, 0x272d93f1, 0x25f394d6, 0x244669cb, 0x6d7f4740,
+ 0x6ccaba5d, 0x6e14bd7a, 0x6fa14067, 0x6ba8b334, 0x6a1d4e29,
+ 0x68c3490e, 0x6976b413, 0x60d0afa8, 0x616552b5, 0x63bb5592,
+ 0x620ea88f, 0x66075bdc, 0x67b2a6c1, 0x656ca1e6, 0x64d95cfb,
+ 0x76209690, 0x77956b8d, 0x754b6caa, 0x74fe91b7, 0x70f762e4,
+ 0x71429ff9, 0x739c98de, 0x722965c3, 0x7b8f7e78, 0x7a3a8365,
+ 0x78e48442, 0x7951795f, 0x7d588a0c, 0x7ced7711, 0x7e337036,
+ 0x7f868d2b, 0x5bc0e4e0, 0x5a7519fd, 0x58ab1eda, 0x591ee3c7,
+ 0x5d171094, 0x5ca2ed89, 0x5e7ceaae, 0x5fc917b3, 0x566f0c08,
+ 0x57daf115, 0x5504f632, 0x54b10b2f, 0x50b8f87c, 0x510d0561,
+ 0x53d30246, 0x5266ff5b, 0x409f3530, 0x412ac82d, 0x43f4cf0a,
+ 0x42413217, 0x4648c144, 0x47fd3c59, 0x45233b7e, 0x4496c663,
+ 0x4d30ddd8, 0x4c8520c5, 0x4e5b27e2, 0x4feedaff, 0x4be729ac,
+ 0x4a52d4b1, 0x488cd396, 0x49392e8b, 0xdafe8e80, 0xdb4b739d,
+ 0xd99574ba, 0xd82089a7, 0xdc297af4, 0xdd9c87e9, 0xdf4280ce,
+ 0xdef77dd3, 0xd7516668, 0xd6e49b75, 0xd43a9c52, 0xd58f614f,
+ 0xd186921c, 0xd0336f01, 0xd2ed6826, 0xd358953b, 0xc1a15f50,
+ 0xc014a24d, 0xc2caa56a, 0xc37f5877, 0xc776ab24, 0xc6c35639,
+ 0xc41d511e, 0xc5a8ac03, 0xcc0eb7b8, 0xcdbb4aa5, 0xcf654d82,
+ 0xced0b09f, 0xcad943cc, 0xcb6cbed1, 0xc9b2b9f6, 0xc80744eb,
+ 0xec412d20, 0xedf4d03d, 0xef2ad71a, 0xee9f2a07, 0xea96d954,
+ 0xeb232449, 0xe9fd236e, 0xe848de73, 0xe1eec5c8, 0xe05b38d5,
+ 0xe2853ff2, 0xe330c2ef, 0xe73931bc, 0xe68ccca1, 0xe452cb86,
+ 0xe5e7369b, 0xf71efcf0, 0xf6ab01ed, 0xf47506ca, 0xf5c0fbd7,
+ 0xf1c90884, 0xf07cf599, 0xf2a2f2be, 0xf3170fa3, 0xfab11418,
+ 0xfb04e905, 0xf9daee22, 0xf86f133f, 0xfc66e06c, 0xfdd31d71,
+ 0xff0d1a56, 0xfeb8e74b, 0xb781c9c0, 0xb63434dd, 0xb4ea33fa,
+ 0xb55fcee7, 0xb1563db4, 0xb0e3c0a9, 0xb23dc78e, 0xb3883a93,
+ 0xba2e2128, 0xbb9bdc35, 0xb945db12, 0xb8f0260f, 0xbcf9d55c,
+ 0xbd4c2841, 0xbf922f66, 0xbe27d27b, 0xacde1810, 0xad6be50d,
+ 0xafb5e22a, 0xae001f37, 0xaa09ec64, 0xabbc1179, 0xa962165e,
+ 0xa8d7eb43, 0xa171f0f8, 0xa0c40de5, 0xa21a0ac2, 0xa3aff7df,
+ 0xa7a6048c, 0xa613f991, 0xa4cdfeb6, 0xa57803ab, 0x813e6a60,
+ 0x808b977d, 0x8255905a, 0x83e06d47, 0x87e99e14, 0x865c6309,
+ 0x8482642e, 0x85379933, 0x8c918288, 0x8d247f95, 0x8ffa78b2,
+ 0x8e4f85af, 0x8a4676fc, 0x8bf38be1, 0x892d8cc6, 0x889871db,
+ 0x9a61bbb0, 0x9bd446ad, 0x990a418a, 0x98bfbc97, 0x9cb64fc4,
+ 0x9d03b2d9, 0x9fddb5fe, 0x9e6848e3, 0x97ce5358, 0x967bae45,
+ 0x94a5a962, 0x9510547f, 0x9119a72c, 0x90ac5a31, 0x92725d16,
+ 0x93c7a00b},
+ {0x00000000, 0x6e8c1b41, 0xdd183682, 0xb3942dc3, 0x61416b45,
+ 0x0fcd7004, 0xbc595dc7, 0xd2d54686, 0xc282d68a, 0xac0ecdcb,
+ 0x1f9ae008, 0x7116fb49, 0xa3c3bdcf, 0xcd4fa68e, 0x7edb8b4d,
+ 0x1057900c, 0x5e74ab55, 0x30f8b014, 0x836c9dd7, 0xede08696,
+ 0x3f35c010, 0x51b9db51, 0xe22df692, 0x8ca1edd3, 0x9cf67ddf,
+ 0xf27a669e, 0x41ee4b5d, 0x2f62501c, 0xfdb7169a, 0x933b0ddb,
+ 0x20af2018, 0x4e233b59, 0xbce956aa, 0xd2654deb, 0x61f16028,
+ 0x0f7d7b69, 0xdda83def, 0xb32426ae, 0x00b00b6d, 0x6e3c102c,
+ 0x7e6b8020, 0x10e79b61, 0xa373b6a2, 0xcdffade3, 0x1f2aeb65,
+ 0x71a6f024, 0xc232dde7, 0xacbec6a6, 0xe29dfdff, 0x8c11e6be,
+ 0x3f85cb7d, 0x5109d03c, 0x83dc96ba, 0xed508dfb, 0x5ec4a038,
+ 0x3048bb79, 0x201f2b75, 0x4e933034, 0xfd071df7, 0x938b06b6,
+ 0x415e4030, 0x2fd25b71, 0x9c4676b2, 0xf2ca6df3, 0xa2a3ab15,
+ 0xcc2fb054, 0x7fbb9d97, 0x113786d6, 0xc3e2c050, 0xad6edb11,
+ 0x1efaf6d2, 0x7076ed93, 0x60217d9f, 0x0ead66de, 0xbd394b1d,
+ 0xd3b5505c, 0x016016da, 0x6fec0d9b, 0xdc782058, 0xb2f43b19,
+ 0xfcd70040, 0x925b1b01, 0x21cf36c2, 0x4f432d83, 0x9d966b05,
+ 0xf31a7044, 0x408e5d87, 0x2e0246c6, 0x3e55d6ca, 0x50d9cd8b,
+ 0xe34de048, 0x8dc1fb09, 0x5f14bd8f, 0x3198a6ce, 0x820c8b0d,
+ 0xec80904c, 0x1e4afdbf, 0x70c6e6fe, 0xc352cb3d, 0xadded07c,
+ 0x7f0b96fa, 0x11878dbb, 0xa213a078, 0xcc9fbb39, 0xdcc82b35,
+ 0xb2443074, 0x01d01db7, 0x6f5c06f6, 0xbd894070, 0xd3055b31,
+ 0x609176f2, 0x0e1d6db3, 0x403e56ea, 0x2eb24dab, 0x9d266068,
+ 0xf3aa7b29, 0x217f3daf, 0x4ff326ee, 0xfc670b2d, 0x92eb106c,
+ 0x82bc8060, 0xec309b21, 0x5fa4b6e2, 0x3128ada3, 0xe3fdeb25,
+ 0x8d71f064, 0x3ee5dda7, 0x5069c6e6, 0x9e36506b, 0xf0ba4b2a,
+ 0x432e66e9, 0x2da27da8, 0xff773b2e, 0x91fb206f, 0x226f0dac,
+ 0x4ce316ed, 0x5cb486e1, 0x32389da0, 0x81acb063, 0xef20ab22,
+ 0x3df5eda4, 0x5379f6e5, 0xe0eddb26, 0x8e61c067, 0xc042fb3e,
+ 0xaecee07f, 0x1d5acdbc, 0x73d6d6fd, 0xa103907b, 0xcf8f8b3a,
+ 0x7c1ba6f9, 0x1297bdb8, 0x02c02db4, 0x6c4c36f5, 0xdfd81b36,
+ 0xb1540077, 0x638146f1, 0x0d0d5db0, 0xbe997073, 0xd0156b32,
+ 0x22df06c1, 0x4c531d80, 0xffc73043, 0x914b2b02, 0x439e6d84,
+ 0x2d1276c5, 0x9e865b06, 0xf00a4047, 0xe05dd04b, 0x8ed1cb0a,
+ 0x3d45e6c9, 0x53c9fd88, 0x811cbb0e, 0xef90a04f, 0x5c048d8c,
+ 0x328896cd, 0x7cabad94, 0x1227b6d5, 0xa1b39b16, 0xcf3f8057,
+ 0x1deac6d1, 0x7366dd90, 0xc0f2f053, 0xae7eeb12, 0xbe297b1e,
+ 0xd0a5605f, 0x63314d9c, 0x0dbd56dd, 0xdf68105b, 0xb1e40b1a,
+ 0x027026d9, 0x6cfc3d98, 0x3c95fb7e, 0x5219e03f, 0xe18dcdfc,
+ 0x8f01d6bd, 0x5dd4903b, 0x33588b7a, 0x80cca6b9, 0xee40bdf8,
+ 0xfe172df4, 0x909b36b5, 0x230f1b76, 0x4d830037, 0x9f5646b1,
+ 0xf1da5df0, 0x424e7033, 0x2cc26b72, 0x62e1502b, 0x0c6d4b6a,
+ 0xbff966a9, 0xd1757de8, 0x03a03b6e, 0x6d2c202f, 0xdeb80dec,
+ 0xb03416ad, 0xa06386a1, 0xceef9de0, 0x7d7bb023, 0x13f7ab62,
+ 0xc122ede4, 0xafaef6a5, 0x1c3adb66, 0x72b6c027, 0x807cadd4,
+ 0xeef0b695, 0x5d649b56, 0x33e88017, 0xe13dc691, 0x8fb1ddd0,
+ 0x3c25f013, 0x52a9eb52, 0x42fe7b5e, 0x2c72601f, 0x9fe64ddc,
+ 0xf16a569d, 0x23bf101b, 0x4d330b5a, 0xfea72699, 0x902b3dd8,
+ 0xde080681, 0xb0841dc0, 0x03103003, 0x6d9c2b42, 0xbf496dc4,
+ 0xd1c57685, 0x62515b46, 0x0cdd4007, 0x1c8ad00b, 0x7206cb4a,
+ 0xc192e689, 0xaf1efdc8, 0x7dcbbb4e, 0x1347a00f, 0xa0d38dcc,
+ 0xce5f968d},
+ {0x00000000, 0xe71da697, 0x154a4b6f, 0xf257edf8, 0x2a9496de,
+ 0xcd893049, 0x3fdeddb1, 0xd8c37b26, 0x55292dbc, 0xb2348b2b,
+ 0x406366d3, 0xa77ec044, 0x7fbdbb62, 0x98a01df5, 0x6af7f00d,
+ 0x8dea569a, 0xaa525b78, 0x4d4ffdef, 0xbf181017, 0x5805b680,
+ 0x80c6cda6, 0x67db6b31, 0x958c86c9, 0x7291205e, 0xff7b76c4,
+ 0x1866d053, 0xea313dab, 0x0d2c9b3c, 0xd5efe01a, 0x32f2468d,
+ 0xc0a5ab75, 0x27b80de2, 0x8fd5b0b1, 0x68c81626, 0x9a9ffbde,
+ 0x7d825d49, 0xa541266f, 0x425c80f8, 0xb00b6d00, 0x5716cb97,
+ 0xdafc9d0d, 0x3de13b9a, 0xcfb6d662, 0x28ab70f5, 0xf0680bd3,
+ 0x1775ad44, 0xe52240bc, 0x023fe62b, 0x2587ebc9, 0xc29a4d5e,
+ 0x30cda0a6, 0xd7d00631, 0x0f137d17, 0xe80edb80, 0x1a593678,
+ 0xfd4490ef, 0x70aec675, 0x97b360e2, 0x65e48d1a, 0x82f92b8d,
+ 0x5a3a50ab, 0xbd27f63c, 0x4f701bc4, 0xa86dbd53, 0xc4da6723,
+ 0x23c7c1b4, 0xd1902c4c, 0x368d8adb, 0xee4ef1fd, 0x0953576a,
+ 0xfb04ba92, 0x1c191c05, 0x91f34a9f, 0x76eeec08, 0x84b901f0,
+ 0x63a4a767, 0xbb67dc41, 0x5c7a7ad6, 0xae2d972e, 0x493031b9,
+ 0x6e883c5b, 0x89959acc, 0x7bc27734, 0x9cdfd1a3, 0x441caa85,
+ 0xa3010c12, 0x5156e1ea, 0xb64b477d, 0x3ba111e7, 0xdcbcb770,
+ 0x2eeb5a88, 0xc9f6fc1f, 0x11358739, 0xf62821ae, 0x047fcc56,
+ 0xe3626ac1, 0x4b0fd792, 0xac127105, 0x5e459cfd, 0xb9583a6a,
+ 0x619b414c, 0x8686e7db, 0x74d10a23, 0x93ccacb4, 0x1e26fa2e,
+ 0xf93b5cb9, 0x0b6cb141, 0xec7117d6, 0x34b26cf0, 0xd3afca67,
+ 0x21f8279f, 0xc6e58108, 0xe15d8cea, 0x06402a7d, 0xf417c785,
+ 0x130a6112, 0xcbc91a34, 0x2cd4bca3, 0xde83515b, 0x399ef7cc,
+ 0xb474a156, 0x536907c1, 0xa13eea39, 0x46234cae, 0x9ee03788,
+ 0x79fd911f, 0x8baa7ce7, 0x6cb7da70, 0x52c5c807, 0xb5d86e90,
+ 0x478f8368, 0xa09225ff, 0x78515ed9, 0x9f4cf84e, 0x6d1b15b6,
+ 0x8a06b321, 0x07ece5bb, 0xe0f1432c, 0x12a6aed4, 0xf5bb0843,
+ 0x2d787365, 0xca65d5f2, 0x3832380a, 0xdf2f9e9d, 0xf897937f,
+ 0x1f8a35e8, 0xedddd810, 0x0ac07e87, 0xd20305a1, 0x351ea336,
+ 0xc7494ece, 0x2054e859, 0xadbebec3, 0x4aa31854, 0xb8f4f5ac,
+ 0x5fe9533b, 0x872a281d, 0x60378e8a, 0x92606372, 0x757dc5e5,
+ 0xdd1078b6, 0x3a0dde21, 0xc85a33d9, 0x2f47954e, 0xf784ee68,
+ 0x109948ff, 0xe2cea507, 0x05d30390, 0x8839550a, 0x6f24f39d,
+ 0x9d731e65, 0x7a6eb8f2, 0xa2adc3d4, 0x45b06543, 0xb7e788bb,
+ 0x50fa2e2c, 0x774223ce, 0x905f8559, 0x620868a1, 0x8515ce36,
+ 0x5dd6b510, 0xbacb1387, 0x489cfe7f, 0xaf8158e8, 0x226b0e72,
+ 0xc576a8e5, 0x3721451d, 0xd03ce38a, 0x08ff98ac, 0xefe23e3b,
+ 0x1db5d3c3, 0xfaa87554, 0x961faf24, 0x710209b3, 0x8355e44b,
+ 0x644842dc, 0xbc8b39fa, 0x5b969f6d, 0xa9c17295, 0x4edcd402,
+ 0xc3368298, 0x242b240f, 0xd67cc9f7, 0x31616f60, 0xe9a21446,
+ 0x0ebfb2d1, 0xfce85f29, 0x1bf5f9be, 0x3c4df45c, 0xdb5052cb,
+ 0x2907bf33, 0xce1a19a4, 0x16d96282, 0xf1c4c415, 0x039329ed,
+ 0xe48e8f7a, 0x6964d9e0, 0x8e797f77, 0x7c2e928f, 0x9b333418,
+ 0x43f04f3e, 0xa4ede9a9, 0x56ba0451, 0xb1a7a2c6, 0x19ca1f95,
+ 0xfed7b902, 0x0c8054fa, 0xeb9df26d, 0x335e894b, 0xd4432fdc,
+ 0x2614c224, 0xc10964b3, 0x4ce33229, 0xabfe94be, 0x59a97946,
+ 0xbeb4dfd1, 0x6677a4f7, 0x816a0260, 0x733def98, 0x9420490f,
+ 0xb39844ed, 0x5485e27a, 0xa6d20f82, 0x41cfa915, 0x990cd233,
+ 0x7e1174a4, 0x8c46995c, 0x6b5b3fcb, 0xe6b16951, 0x01accfc6,
+ 0xf3fb223e, 0x14e684a9, 0xcc25ff8f, 0x2b385918, 0xd96fb4e0,
+ 0x3e721277},
+ {0x00000000, 0xa58b900e, 0x9066265d, 0x35edb653, 0xfbbd4afb,
+ 0x5e36daf5, 0x6bdb6ca6, 0xce50fca8, 0x2c0b93b7, 0x898003b9,
+ 0xbc6db5ea, 0x19e625e4, 0xd7b6d94c, 0x723d4942, 0x47d0ff11,
+ 0xe25b6f1f, 0x5817276e, 0xfd9cb760, 0xc8710133, 0x6dfa913d,
+ 0xa3aa6d95, 0x0621fd9b, 0x33cc4bc8, 0x9647dbc6, 0x741cb4d9,
+ 0xd19724d7, 0xe47a9284, 0x41f1028a, 0x8fa1fe22, 0x2a2a6e2c,
+ 0x1fc7d87f, 0xba4c4871, 0xb02e4edc, 0x15a5ded2, 0x20486881,
+ 0x85c3f88f, 0x4b930427, 0xee189429, 0xdbf5227a, 0x7e7eb274,
+ 0x9c25dd6b, 0x39ae4d65, 0x0c43fb36, 0xa9c86b38, 0x67989790,
+ 0xc213079e, 0xf7feb1cd, 0x527521c3, 0xe83969b2, 0x4db2f9bc,
+ 0x785f4fef, 0xddd4dfe1, 0x13842349, 0xb60fb347, 0x83e20514,
+ 0x2669951a, 0xc432fa05, 0x61b96a0b, 0x5454dc58, 0xf1df4c56,
+ 0x3f8fb0fe, 0x9a0420f0, 0xafe996a3, 0x0a6206ad, 0xbb2d9bf9,
+ 0x1ea60bf7, 0x2b4bbda4, 0x8ec02daa, 0x4090d102, 0xe51b410c,
+ 0xd0f6f75f, 0x757d6751, 0x9726084e, 0x32ad9840, 0x07402e13,
+ 0xa2cbbe1d, 0x6c9b42b5, 0xc910d2bb, 0xfcfd64e8, 0x5976f4e6,
+ 0xe33abc97, 0x46b12c99, 0x735c9aca, 0xd6d70ac4, 0x1887f66c,
+ 0xbd0c6662, 0x88e1d031, 0x2d6a403f, 0xcf312f20, 0x6ababf2e,
+ 0x5f57097d, 0xfadc9973, 0x348c65db, 0x9107f5d5, 0xa4ea4386,
+ 0x0161d388, 0x0b03d525, 0xae88452b, 0x9b65f378, 0x3eee6376,
+ 0xf0be9fde, 0x55350fd0, 0x60d8b983, 0xc553298d, 0x27084692,
+ 0x8283d69c, 0xb76e60cf, 0x12e5f0c1, 0xdcb50c69, 0x793e9c67,
+ 0x4cd32a34, 0xe958ba3a, 0x5314f24b, 0xf69f6245, 0xc372d416,
+ 0x66f94418, 0xa8a9b8b0, 0x0d2228be, 0x38cf9eed, 0x9d440ee3,
+ 0x7f1f61fc, 0xda94f1f2, 0xef7947a1, 0x4af2d7af, 0x84a22b07,
+ 0x2129bb09, 0x14c40d5a, 0xb14f9d54, 0xad2a31b3, 0x08a1a1bd,
+ 0x3d4c17ee, 0x98c787e0, 0x56977b48, 0xf31ceb46, 0xc6f15d15,
+ 0x637acd1b, 0x8121a204, 0x24aa320a, 0x11478459, 0xb4cc1457,
+ 0x7a9ce8ff, 0xdf1778f1, 0xeafacea2, 0x4f715eac, 0xf53d16dd,
+ 0x50b686d3, 0x655b3080, 0xc0d0a08e, 0x0e805c26, 0xab0bcc28,
+ 0x9ee67a7b, 0x3b6dea75, 0xd936856a, 0x7cbd1564, 0x4950a337,
+ 0xecdb3339, 0x228bcf91, 0x87005f9f, 0xb2ede9cc, 0x176679c2,
+ 0x1d047f6f, 0xb88fef61, 0x8d625932, 0x28e9c93c, 0xe6b93594,
+ 0x4332a59a, 0x76df13c9, 0xd35483c7, 0x310fecd8, 0x94847cd6,
+ 0xa169ca85, 0x04e25a8b, 0xcab2a623, 0x6f39362d, 0x5ad4807e,
+ 0xff5f1070, 0x45135801, 0xe098c80f, 0xd5757e5c, 0x70feee52,
+ 0xbeae12fa, 0x1b2582f4, 0x2ec834a7, 0x8b43a4a9, 0x6918cbb6,
+ 0xcc935bb8, 0xf97eedeb, 0x5cf57de5, 0x92a5814d, 0x372e1143,
+ 0x02c3a710, 0xa748371e, 0x1607aa4a, 0xb38c3a44, 0x86618c17,
+ 0x23ea1c19, 0xedbae0b1, 0x483170bf, 0x7ddcc6ec, 0xd85756e2,
+ 0x3a0c39fd, 0x9f87a9f3, 0xaa6a1fa0, 0x0fe18fae, 0xc1b17306,
+ 0x643ae308, 0x51d7555b, 0xf45cc555, 0x4e108d24, 0xeb9b1d2a,
+ 0xde76ab79, 0x7bfd3b77, 0xb5adc7df, 0x102657d1, 0x25cbe182,
+ 0x8040718c, 0x621b1e93, 0xc7908e9d, 0xf27d38ce, 0x57f6a8c0,
+ 0x99a65468, 0x3c2dc466, 0x09c07235, 0xac4be23b, 0xa629e496,
+ 0x03a27498, 0x364fc2cb, 0x93c452c5, 0x5d94ae6d, 0xf81f3e63,
+ 0xcdf28830, 0x6879183e, 0x8a227721, 0x2fa9e72f, 0x1a44517c,
+ 0xbfcfc172, 0x719f3dda, 0xd414add4, 0xe1f91b87, 0x44728b89,
+ 0xfe3ec3f8, 0x5bb553f6, 0x6e58e5a5, 0xcbd375ab, 0x05838903,
+ 0xa008190d, 0x95e5af5e, 0x306e3f50, 0xd235504f, 0x77bec041,
+ 0x42537612, 0xe7d8e61c, 0x29881ab4, 0x8c038aba, 0xb9ee3ce9,
+ 0x1c65ace7}};
+
+local const z_word_t FAR crc_braid_big_table[][256] = {
+ {0x0000000000000000, 0x0e908ba500000000, 0x5d26669000000000,
+ 0x53b6ed3500000000, 0xfb4abdfb00000000, 0xf5da365e00000000,
+ 0xa66cdb6b00000000, 0xa8fc50ce00000000, 0xb7930b2c00000000,
+ 0xb903808900000000, 0xeab56dbc00000000, 0xe425e61900000000,
+ 0x4cd9b6d700000000, 0x42493d7200000000, 0x11ffd04700000000,
+ 0x1f6f5be200000000, 0x6e27175800000000, 0x60b79cfd00000000,
+ 0x330171c800000000, 0x3d91fa6d00000000, 0x956daaa300000000,
+ 0x9bfd210600000000, 0xc84bcc3300000000, 0xc6db479600000000,
+ 0xd9b41c7400000000, 0xd72497d100000000, 0x84927ae400000000,
+ 0x8a02f14100000000, 0x22fea18f00000000, 0x2c6e2a2a00000000,
+ 0x7fd8c71f00000000, 0x71484cba00000000, 0xdc4e2eb000000000,
+ 0xd2dea51500000000, 0x8168482000000000, 0x8ff8c38500000000,
+ 0x2704934b00000000, 0x299418ee00000000, 0x7a22f5db00000000,
+ 0x74b27e7e00000000, 0x6bdd259c00000000, 0x654dae3900000000,
+ 0x36fb430c00000000, 0x386bc8a900000000, 0x9097986700000000,
+ 0x9e0713c200000000, 0xcdb1fef700000000, 0xc321755200000000,
+ 0xb26939e800000000, 0xbcf9b24d00000000, 0xef4f5f7800000000,
+ 0xe1dfd4dd00000000, 0x4923841300000000, 0x47b30fb600000000,
+ 0x1405e28300000000, 0x1a95692600000000, 0x05fa32c400000000,
+ 0x0b6ab96100000000, 0x58dc545400000000, 0x564cdff100000000,
+ 0xfeb08f3f00000000, 0xf020049a00000000, 0xa396e9af00000000,
+ 0xad06620a00000000, 0xf99b2dbb00000000, 0xf70ba61e00000000,
+ 0xa4bd4b2b00000000, 0xaa2dc08e00000000, 0x02d1904000000000,
+ 0x0c411be500000000, 0x5ff7f6d000000000, 0x51677d7500000000,
+ 0x4e08269700000000, 0x4098ad3200000000, 0x132e400700000000,
+ 0x1dbecba200000000, 0xb5429b6c00000000, 0xbbd210c900000000,
+ 0xe864fdfc00000000, 0xe6f4765900000000, 0x97bc3ae300000000,
+ 0x992cb14600000000, 0xca9a5c7300000000, 0xc40ad7d600000000,
+ 0x6cf6871800000000, 0x62660cbd00000000, 0x31d0e18800000000,
+ 0x3f406a2d00000000, 0x202f31cf00000000, 0x2ebfba6a00000000,
+ 0x7d09575f00000000, 0x7399dcfa00000000, 0xdb658c3400000000,
+ 0xd5f5079100000000, 0x8643eaa400000000, 0x88d3610100000000,
+ 0x25d5030b00000000, 0x2b4588ae00000000, 0x78f3659b00000000,
+ 0x7663ee3e00000000, 0xde9fbef000000000, 0xd00f355500000000,
+ 0x83b9d86000000000, 0x8d2953c500000000, 0x9246082700000000,
+ 0x9cd6838200000000, 0xcf606eb700000000, 0xc1f0e51200000000,
+ 0x690cb5dc00000000, 0x679c3e7900000000, 0x342ad34c00000000,
+ 0x3aba58e900000000, 0x4bf2145300000000, 0x45629ff600000000,
+ 0x16d472c300000000, 0x1844f96600000000, 0xb0b8a9a800000000,
+ 0xbe28220d00000000, 0xed9ecf3800000000, 0xe30e449d00000000,
+ 0xfc611f7f00000000, 0xf2f194da00000000, 0xa14779ef00000000,
+ 0xafd7f24a00000000, 0x072ba28400000000, 0x09bb292100000000,
+ 0x5a0dc41400000000, 0x549d4fb100000000, 0xb3312aad00000000,
+ 0xbda1a10800000000, 0xee174c3d00000000, 0xe087c79800000000,
+ 0x487b975600000000, 0x46eb1cf300000000, 0x155df1c600000000,
+ 0x1bcd7a6300000000, 0x04a2218100000000, 0x0a32aa2400000000,
+ 0x5984471100000000, 0x5714ccb400000000, 0xffe89c7a00000000,
+ 0xf17817df00000000, 0xa2cefaea00000000, 0xac5e714f00000000,
+ 0xdd163df500000000, 0xd386b65000000000, 0x80305b6500000000,
+ 0x8ea0d0c000000000, 0x265c800e00000000, 0x28cc0bab00000000,
+ 0x7b7ae69e00000000, 0x75ea6d3b00000000, 0x6a8536d900000000,
+ 0x6415bd7c00000000, 0x37a3504900000000, 0x3933dbec00000000,
+ 0x91cf8b2200000000, 0x9f5f008700000000, 0xcce9edb200000000,
+ 0xc279661700000000, 0x6f7f041d00000000, 0x61ef8fb800000000,
+ 0x3259628d00000000, 0x3cc9e92800000000, 0x9435b9e600000000,
+ 0x9aa5324300000000, 0xc913df7600000000, 0xc78354d300000000,
+ 0xd8ec0f3100000000, 0xd67c849400000000, 0x85ca69a100000000,
+ 0x8b5ae20400000000, 0x23a6b2ca00000000, 0x2d36396f00000000,
+ 0x7e80d45a00000000, 0x70105fff00000000, 0x0158134500000000,
+ 0x0fc898e000000000, 0x5c7e75d500000000, 0x52eefe7000000000,
+ 0xfa12aebe00000000, 0xf482251b00000000, 0xa734c82e00000000,
+ 0xa9a4438b00000000, 0xb6cb186900000000, 0xb85b93cc00000000,
+ 0xebed7ef900000000, 0xe57df55c00000000, 0x4d81a59200000000,
+ 0x43112e3700000000, 0x10a7c30200000000, 0x1e3748a700000000,
+ 0x4aaa071600000000, 0x443a8cb300000000, 0x178c618600000000,
+ 0x191cea2300000000, 0xb1e0baed00000000, 0xbf70314800000000,
+ 0xecc6dc7d00000000, 0xe25657d800000000, 0xfd390c3a00000000,
+ 0xf3a9879f00000000, 0xa01f6aaa00000000, 0xae8fe10f00000000,
+ 0x0673b1c100000000, 0x08e33a6400000000, 0x5b55d75100000000,
+ 0x55c55cf400000000, 0x248d104e00000000, 0x2a1d9beb00000000,
+ 0x79ab76de00000000, 0x773bfd7b00000000, 0xdfc7adb500000000,
+ 0xd157261000000000, 0x82e1cb2500000000, 0x8c71408000000000,
+ 0x931e1b6200000000, 0x9d8e90c700000000, 0xce387df200000000,
+ 0xc0a8f65700000000, 0x6854a69900000000, 0x66c42d3c00000000,
+ 0x3572c00900000000, 0x3be24bac00000000, 0x96e429a600000000,
+ 0x9874a20300000000, 0xcbc24f3600000000, 0xc552c49300000000,
+ 0x6dae945d00000000, 0x633e1ff800000000, 0x3088f2cd00000000,
+ 0x3e18796800000000, 0x2177228a00000000, 0x2fe7a92f00000000,
+ 0x7c51441a00000000, 0x72c1cfbf00000000, 0xda3d9f7100000000,
+ 0xd4ad14d400000000, 0x871bf9e100000000, 0x898b724400000000,
+ 0xf8c33efe00000000, 0xf653b55b00000000, 0xa5e5586e00000000,
+ 0xab75d3cb00000000, 0x0389830500000000, 0x0d1908a000000000,
+ 0x5eafe59500000000, 0x503f6e3000000000, 0x4f5035d200000000,
+ 0x41c0be7700000000, 0x1276534200000000, 0x1ce6d8e700000000,
+ 0xb41a882900000000, 0xba8a038c00000000, 0xe93ceeb900000000,
+ 0xe7ac651c00000000},
+ {0x0000000000000000, 0x97a61de700000000, 0x6f4b4a1500000000,
+ 0xf8ed57f200000000, 0xde96942a00000000, 0x493089cd00000000,
+ 0xb1ddde3f00000000, 0x267bc3d800000000, 0xbc2d295500000000,
+ 0x2b8b34b200000000, 0xd366634000000000, 0x44c07ea700000000,
+ 0x62bbbd7f00000000, 0xf51da09800000000, 0x0df0f76a00000000,
+ 0x9a56ea8d00000000, 0x785b52aa00000000, 0xeffd4f4d00000000,
+ 0x171018bf00000000, 0x80b6055800000000, 0xa6cdc68000000000,
+ 0x316bdb6700000000, 0xc9868c9500000000, 0x5e20917200000000,
+ 0xc4767bff00000000, 0x53d0661800000000, 0xab3d31ea00000000,
+ 0x3c9b2c0d00000000, 0x1ae0efd500000000, 0x8d46f23200000000,
+ 0x75aba5c000000000, 0xe20db82700000000, 0xb1b0d58f00000000,
+ 0x2616c86800000000, 0xdefb9f9a00000000, 0x495d827d00000000,
+ 0x6f2641a500000000, 0xf8805c4200000000, 0x006d0bb000000000,
+ 0x97cb165700000000, 0x0d9dfcda00000000, 0x9a3be13d00000000,
+ 0x62d6b6cf00000000, 0xf570ab2800000000, 0xd30b68f000000000,
+ 0x44ad751700000000, 0xbc4022e500000000, 0x2be63f0200000000,
+ 0xc9eb872500000000, 0x5e4d9ac200000000, 0xa6a0cd3000000000,
+ 0x3106d0d700000000, 0x177d130f00000000, 0x80db0ee800000000,
+ 0x7836591a00000000, 0xef9044fd00000000, 0x75c6ae7000000000,
+ 0xe260b39700000000, 0x1a8de46500000000, 0x8d2bf98200000000,
+ 0xab503a5a00000000, 0x3cf627bd00000000, 0xc41b704f00000000,
+ 0x53bd6da800000000, 0x2367dac400000000, 0xb4c1c72300000000,
+ 0x4c2c90d100000000, 0xdb8a8d3600000000, 0xfdf14eee00000000,
+ 0x6a57530900000000, 0x92ba04fb00000000, 0x051c191c00000000,
+ 0x9f4af39100000000, 0x08ecee7600000000, 0xf001b98400000000,
+ 0x67a7a46300000000, 0x41dc67bb00000000, 0xd67a7a5c00000000,
+ 0x2e972dae00000000, 0xb931304900000000, 0x5b3c886e00000000,
+ 0xcc9a958900000000, 0x3477c27b00000000, 0xa3d1df9c00000000,
+ 0x85aa1c4400000000, 0x120c01a300000000, 0xeae1565100000000,
+ 0x7d474bb600000000, 0xe711a13b00000000, 0x70b7bcdc00000000,
+ 0x885aeb2e00000000, 0x1ffcf6c900000000, 0x3987351100000000,
+ 0xae2128f600000000, 0x56cc7f0400000000, 0xc16a62e300000000,
+ 0x92d70f4b00000000, 0x057112ac00000000, 0xfd9c455e00000000,
+ 0x6a3a58b900000000, 0x4c419b6100000000, 0xdbe7868600000000,
+ 0x230ad17400000000, 0xb4accc9300000000, 0x2efa261e00000000,
+ 0xb95c3bf900000000, 0x41b16c0b00000000, 0xd61771ec00000000,
+ 0xf06cb23400000000, 0x67caafd300000000, 0x9f27f82100000000,
+ 0x0881e5c600000000, 0xea8c5de100000000, 0x7d2a400600000000,
+ 0x85c717f400000000, 0x12610a1300000000, 0x341ac9cb00000000,
+ 0xa3bcd42c00000000, 0x5b5183de00000000, 0xccf79e3900000000,
+ 0x56a174b400000000, 0xc107695300000000, 0x39ea3ea100000000,
+ 0xae4c234600000000, 0x8837e09e00000000, 0x1f91fd7900000000,
+ 0xe77caa8b00000000, 0x70dab76c00000000, 0x07c8c55200000000,
+ 0x906ed8b500000000, 0x68838f4700000000, 0xff2592a000000000,
+ 0xd95e517800000000, 0x4ef84c9f00000000, 0xb6151b6d00000000,
+ 0x21b3068a00000000, 0xbbe5ec0700000000, 0x2c43f1e000000000,
+ 0xd4aea61200000000, 0x4308bbf500000000, 0x6573782d00000000,
+ 0xf2d565ca00000000, 0x0a38323800000000, 0x9d9e2fdf00000000,
+ 0x7f9397f800000000, 0xe8358a1f00000000, 0x10d8dded00000000,
+ 0x877ec00a00000000, 0xa10503d200000000, 0x36a31e3500000000,
+ 0xce4e49c700000000, 0x59e8542000000000, 0xc3bebead00000000,
+ 0x5418a34a00000000, 0xacf5f4b800000000, 0x3b53e95f00000000,
+ 0x1d282a8700000000, 0x8a8e376000000000, 0x7263609200000000,
+ 0xe5c57d7500000000, 0xb67810dd00000000, 0x21de0d3a00000000,
+ 0xd9335ac800000000, 0x4e95472f00000000, 0x68ee84f700000000,
+ 0xff48991000000000, 0x07a5cee200000000, 0x9003d30500000000,
+ 0x0a55398800000000, 0x9df3246f00000000, 0x651e739d00000000,
+ 0xf2b86e7a00000000, 0xd4c3ada200000000, 0x4365b04500000000,
+ 0xbb88e7b700000000, 0x2c2efa5000000000, 0xce23427700000000,
+ 0x59855f9000000000, 0xa168086200000000, 0x36ce158500000000,
+ 0x10b5d65d00000000, 0x8713cbba00000000, 0x7ffe9c4800000000,
+ 0xe85881af00000000, 0x720e6b2200000000, 0xe5a876c500000000,
+ 0x1d45213700000000, 0x8ae33cd000000000, 0xac98ff0800000000,
+ 0x3b3ee2ef00000000, 0xc3d3b51d00000000, 0x5475a8fa00000000,
+ 0x24af1f9600000000, 0xb309027100000000, 0x4be4558300000000,
+ 0xdc42486400000000, 0xfa398bbc00000000, 0x6d9f965b00000000,
+ 0x9572c1a900000000, 0x02d4dc4e00000000, 0x988236c300000000,
+ 0x0f242b2400000000, 0xf7c97cd600000000, 0x606f613100000000,
+ 0x4614a2e900000000, 0xd1b2bf0e00000000, 0x295fe8fc00000000,
+ 0xbef9f51b00000000, 0x5cf44d3c00000000, 0xcb5250db00000000,
+ 0x33bf072900000000, 0xa4191ace00000000, 0x8262d91600000000,
+ 0x15c4c4f100000000, 0xed29930300000000, 0x7a8f8ee400000000,
+ 0xe0d9646900000000, 0x777f798e00000000, 0x8f922e7c00000000,
+ 0x1834339b00000000, 0x3e4ff04300000000, 0xa9e9eda400000000,
+ 0x5104ba5600000000, 0xc6a2a7b100000000, 0x951fca1900000000,
+ 0x02b9d7fe00000000, 0xfa54800c00000000, 0x6df29deb00000000,
+ 0x4b895e3300000000, 0xdc2f43d400000000, 0x24c2142600000000,
+ 0xb36409c100000000, 0x2932e34c00000000, 0xbe94feab00000000,
+ 0x4679a95900000000, 0xd1dfb4be00000000, 0xf7a4776600000000,
+ 0x60026a8100000000, 0x98ef3d7300000000, 0x0f49209400000000,
+ 0xed4498b300000000, 0x7ae2855400000000, 0x820fd2a600000000,
+ 0x15a9cf4100000000, 0x33d20c9900000000, 0xa474117e00000000,
+ 0x5c99468c00000000, 0xcb3f5b6b00000000, 0x5169b1e600000000,
+ 0xc6cfac0100000000, 0x3e22fbf300000000, 0xa984e61400000000,
+ 0x8fff25cc00000000, 0x1859382b00000000, 0xe0b46fd900000000,
+ 0x7712723e00000000},
+ {0x0000000000000000, 0x411b8c6e00000000, 0x823618dd00000000,
+ 0xc32d94b300000000, 0x456b416100000000, 0x0470cd0f00000000,
+ 0xc75d59bc00000000, 0x8646d5d200000000, 0x8ad682c200000000,
+ 0xcbcd0eac00000000, 0x08e09a1f00000000, 0x49fb167100000000,
+ 0xcfbdc3a300000000, 0x8ea64fcd00000000, 0x4d8bdb7e00000000,
+ 0x0c90571000000000, 0x55ab745e00000000, 0x14b0f83000000000,
+ 0xd79d6c8300000000, 0x9686e0ed00000000, 0x10c0353f00000000,
+ 0x51dbb95100000000, 0x92f62de200000000, 0xd3eda18c00000000,
+ 0xdf7df69c00000000, 0x9e667af200000000, 0x5d4bee4100000000,
+ 0x1c50622f00000000, 0x9a16b7fd00000000, 0xdb0d3b9300000000,
+ 0x1820af2000000000, 0x593b234e00000000, 0xaa56e9bc00000000,
+ 0xeb4d65d200000000, 0x2860f16100000000, 0x697b7d0f00000000,
+ 0xef3da8dd00000000, 0xae2624b300000000, 0x6d0bb00000000000,
+ 0x2c103c6e00000000, 0x20806b7e00000000, 0x619be71000000000,
+ 0xa2b673a300000000, 0xe3adffcd00000000, 0x65eb2a1f00000000,
+ 0x24f0a67100000000, 0xe7dd32c200000000, 0xa6c6beac00000000,
+ 0xfffd9de200000000, 0xbee6118c00000000, 0x7dcb853f00000000,
+ 0x3cd0095100000000, 0xba96dc8300000000, 0xfb8d50ed00000000,
+ 0x38a0c45e00000000, 0x79bb483000000000, 0x752b1f2000000000,
+ 0x3430934e00000000, 0xf71d07fd00000000, 0xb6068b9300000000,
+ 0x30405e4100000000, 0x715bd22f00000000, 0xb276469c00000000,
+ 0xf36dcaf200000000, 0x15aba3a200000000, 0x54b02fcc00000000,
+ 0x979dbb7f00000000, 0xd686371100000000, 0x50c0e2c300000000,
+ 0x11db6ead00000000, 0xd2f6fa1e00000000, 0x93ed767000000000,
+ 0x9f7d216000000000, 0xde66ad0e00000000, 0x1d4b39bd00000000,
+ 0x5c50b5d300000000, 0xda16600100000000, 0x9b0dec6f00000000,
+ 0x582078dc00000000, 0x193bf4b200000000, 0x4000d7fc00000000,
+ 0x011b5b9200000000, 0xc236cf2100000000, 0x832d434f00000000,
+ 0x056b969d00000000, 0x44701af300000000, 0x875d8e4000000000,
+ 0xc646022e00000000, 0xcad6553e00000000, 0x8bcdd95000000000,
+ 0x48e04de300000000, 0x09fbc18d00000000, 0x8fbd145f00000000,
+ 0xcea6983100000000, 0x0d8b0c8200000000, 0x4c9080ec00000000,
+ 0xbffd4a1e00000000, 0xfee6c67000000000, 0x3dcb52c300000000,
+ 0x7cd0dead00000000, 0xfa960b7f00000000, 0xbb8d871100000000,
+ 0x78a013a200000000, 0x39bb9fcc00000000, 0x352bc8dc00000000,
+ 0x743044b200000000, 0xb71dd00100000000, 0xf6065c6f00000000,
+ 0x704089bd00000000, 0x315b05d300000000, 0xf276916000000000,
+ 0xb36d1d0e00000000, 0xea563e4000000000, 0xab4db22e00000000,
+ 0x6860269d00000000, 0x297baaf300000000, 0xaf3d7f2100000000,
+ 0xee26f34f00000000, 0x2d0b67fc00000000, 0x6c10eb9200000000,
+ 0x6080bc8200000000, 0x219b30ec00000000, 0xe2b6a45f00000000,
+ 0xa3ad283100000000, 0x25ebfde300000000, 0x64f0718d00000000,
+ 0xa7dde53e00000000, 0xe6c6695000000000, 0x6b50369e00000000,
+ 0x2a4bbaf000000000, 0xe9662e4300000000, 0xa87da22d00000000,
+ 0x2e3b77ff00000000, 0x6f20fb9100000000, 0xac0d6f2200000000,
+ 0xed16e34c00000000, 0xe186b45c00000000, 0xa09d383200000000,
+ 0x63b0ac8100000000, 0x22ab20ef00000000, 0xa4edf53d00000000,
+ 0xe5f6795300000000, 0x26dbede000000000, 0x67c0618e00000000,
+ 0x3efb42c000000000, 0x7fe0ceae00000000, 0xbccd5a1d00000000,
+ 0xfdd6d67300000000, 0x7b9003a100000000, 0x3a8b8fcf00000000,
+ 0xf9a61b7c00000000, 0xb8bd971200000000, 0xb42dc00200000000,
+ 0xf5364c6c00000000, 0x361bd8df00000000, 0x770054b100000000,
+ 0xf146816300000000, 0xb05d0d0d00000000, 0x737099be00000000,
+ 0x326b15d000000000, 0xc106df2200000000, 0x801d534c00000000,
+ 0x4330c7ff00000000, 0x022b4b9100000000, 0x846d9e4300000000,
+ 0xc576122d00000000, 0x065b869e00000000, 0x47400af000000000,
+ 0x4bd05de000000000, 0x0acbd18e00000000, 0xc9e6453d00000000,
+ 0x88fdc95300000000, 0x0ebb1c8100000000, 0x4fa090ef00000000,
+ 0x8c8d045c00000000, 0xcd96883200000000, 0x94adab7c00000000,
+ 0xd5b6271200000000, 0x169bb3a100000000, 0x57803fcf00000000,
+ 0xd1c6ea1d00000000, 0x90dd667300000000, 0x53f0f2c000000000,
+ 0x12eb7eae00000000, 0x1e7b29be00000000, 0x5f60a5d000000000,
+ 0x9c4d316300000000, 0xdd56bd0d00000000, 0x5b1068df00000000,
+ 0x1a0be4b100000000, 0xd926700200000000, 0x983dfc6c00000000,
+ 0x7efb953c00000000, 0x3fe0195200000000, 0xfccd8de100000000,
+ 0xbdd6018f00000000, 0x3b90d45d00000000, 0x7a8b583300000000,
+ 0xb9a6cc8000000000, 0xf8bd40ee00000000, 0xf42d17fe00000000,
+ 0xb5369b9000000000, 0x761b0f2300000000, 0x3700834d00000000,
+ 0xb146569f00000000, 0xf05ddaf100000000, 0x33704e4200000000,
+ 0x726bc22c00000000, 0x2b50e16200000000, 0x6a4b6d0c00000000,
+ 0xa966f9bf00000000, 0xe87d75d100000000, 0x6e3ba00300000000,
+ 0x2f202c6d00000000, 0xec0db8de00000000, 0xad1634b000000000,
+ 0xa18663a000000000, 0xe09defce00000000, 0x23b07b7d00000000,
+ 0x62abf71300000000, 0xe4ed22c100000000, 0xa5f6aeaf00000000,
+ 0x66db3a1c00000000, 0x27c0b67200000000, 0xd4ad7c8000000000,
+ 0x95b6f0ee00000000, 0x569b645d00000000, 0x1780e83300000000,
+ 0x91c63de100000000, 0xd0ddb18f00000000, 0x13f0253c00000000,
+ 0x52eba95200000000, 0x5e7bfe4200000000, 0x1f60722c00000000,
+ 0xdc4de69f00000000, 0x9d566af100000000, 0x1b10bf2300000000,
+ 0x5a0b334d00000000, 0x9926a7fe00000000, 0xd83d2b9000000000,
+ 0x810608de00000000, 0xc01d84b000000000, 0x0330100300000000,
+ 0x422b9c6d00000000, 0xc46d49bf00000000, 0x8576c5d100000000,
+ 0x465b516200000000, 0x0740dd0c00000000, 0x0bd08a1c00000000,
+ 0x4acb067200000000, 0x89e692c100000000, 0xc8fd1eaf00000000,
+ 0x4ebbcb7d00000000, 0x0fa0471300000000, 0xcc8dd3a000000000,
+ 0x8d965fce00000000},
+ {0x0000000000000000, 0x1dfdb50100000000, 0x3afa6b0300000000,
+ 0x2707de0200000000, 0x74f4d70600000000, 0x6909620700000000,
+ 0x4e0ebc0500000000, 0x53f3090400000000, 0xe8e8af0d00000000,
+ 0xf5151a0c00000000, 0xd212c40e00000000, 0xcfef710f00000000,
+ 0x9c1c780b00000000, 0x81e1cd0a00000000, 0xa6e6130800000000,
+ 0xbb1ba60900000000, 0xd0d15f1b00000000, 0xcd2cea1a00000000,
+ 0xea2b341800000000, 0xf7d6811900000000, 0xa425881d00000000,
+ 0xb9d83d1c00000000, 0x9edfe31e00000000, 0x8322561f00000000,
+ 0x3839f01600000000, 0x25c4451700000000, 0x02c39b1500000000,
+ 0x1f3e2e1400000000, 0x4ccd271000000000, 0x5130921100000000,
+ 0x76374c1300000000, 0x6bcaf91200000000, 0xa0a3bf3600000000,
+ 0xbd5e0a3700000000, 0x9a59d43500000000, 0x87a4613400000000,
+ 0xd457683000000000, 0xc9aadd3100000000, 0xeead033300000000,
+ 0xf350b63200000000, 0x484b103b00000000, 0x55b6a53a00000000,
+ 0x72b17b3800000000, 0x6f4cce3900000000, 0x3cbfc73d00000000,
+ 0x2142723c00000000, 0x0645ac3e00000000, 0x1bb8193f00000000,
+ 0x7072e02d00000000, 0x6d8f552c00000000, 0x4a888b2e00000000,
+ 0x57753e2f00000000, 0x0486372b00000000, 0x197b822a00000000,
+ 0x3e7c5c2800000000, 0x2381e92900000000, 0x989a4f2000000000,
+ 0x8567fa2100000000, 0xa260242300000000, 0xbf9d912200000000,
+ 0xec6e982600000000, 0xf1932d2700000000, 0xd694f32500000000,
+ 0xcb69462400000000, 0x40477f6d00000000, 0x5dbaca6c00000000,
+ 0x7abd146e00000000, 0x6740a16f00000000, 0x34b3a86b00000000,
+ 0x294e1d6a00000000, 0x0e49c36800000000, 0x13b4766900000000,
+ 0xa8afd06000000000, 0xb552656100000000, 0x9255bb6300000000,
+ 0x8fa80e6200000000, 0xdc5b076600000000, 0xc1a6b26700000000,
+ 0xe6a16c6500000000, 0xfb5cd96400000000, 0x9096207600000000,
+ 0x8d6b957700000000, 0xaa6c4b7500000000, 0xb791fe7400000000,
+ 0xe462f77000000000, 0xf99f427100000000, 0xde989c7300000000,
+ 0xc365297200000000, 0x787e8f7b00000000, 0x65833a7a00000000,
+ 0x4284e47800000000, 0x5f79517900000000, 0x0c8a587d00000000,
+ 0x1177ed7c00000000, 0x3670337e00000000, 0x2b8d867f00000000,
+ 0xe0e4c05b00000000, 0xfd19755a00000000, 0xda1eab5800000000,
+ 0xc7e31e5900000000, 0x9410175d00000000, 0x89eda25c00000000,
+ 0xaeea7c5e00000000, 0xb317c95f00000000, 0x080c6f5600000000,
+ 0x15f1da5700000000, 0x32f6045500000000, 0x2f0bb15400000000,
+ 0x7cf8b85000000000, 0x61050d5100000000, 0x4602d35300000000,
+ 0x5bff665200000000, 0x30359f4000000000, 0x2dc82a4100000000,
+ 0x0acff44300000000, 0x1732414200000000, 0x44c1484600000000,
+ 0x593cfd4700000000, 0x7e3b234500000000, 0x63c6964400000000,
+ 0xd8dd304d00000000, 0xc520854c00000000, 0xe2275b4e00000000,
+ 0xffdaee4f00000000, 0xac29e74b00000000, 0xb1d4524a00000000,
+ 0x96d38c4800000000, 0x8b2e394900000000, 0x808efeda00000000,
+ 0x9d734bdb00000000, 0xba7495d900000000, 0xa78920d800000000,
+ 0xf47a29dc00000000, 0xe9879cdd00000000, 0xce8042df00000000,
+ 0xd37df7de00000000, 0x686651d700000000, 0x759be4d600000000,
+ 0x529c3ad400000000, 0x4f618fd500000000, 0x1c9286d100000000,
+ 0x016f33d000000000, 0x2668edd200000000, 0x3b9558d300000000,
+ 0x505fa1c100000000, 0x4da214c000000000, 0x6aa5cac200000000,
+ 0x77587fc300000000, 0x24ab76c700000000, 0x3956c3c600000000,
+ 0x1e511dc400000000, 0x03aca8c500000000, 0xb8b70ecc00000000,
+ 0xa54abbcd00000000, 0x824d65cf00000000, 0x9fb0d0ce00000000,
+ 0xcc43d9ca00000000, 0xd1be6ccb00000000, 0xf6b9b2c900000000,
+ 0xeb4407c800000000, 0x202d41ec00000000, 0x3dd0f4ed00000000,
+ 0x1ad72aef00000000, 0x072a9fee00000000, 0x54d996ea00000000,
+ 0x492423eb00000000, 0x6e23fde900000000, 0x73de48e800000000,
+ 0xc8c5eee100000000, 0xd5385be000000000, 0xf23f85e200000000,
+ 0xefc230e300000000, 0xbc3139e700000000, 0xa1cc8ce600000000,
+ 0x86cb52e400000000, 0x9b36e7e500000000, 0xf0fc1ef700000000,
+ 0xed01abf600000000, 0xca0675f400000000, 0xd7fbc0f500000000,
+ 0x8408c9f100000000, 0x99f57cf000000000, 0xbef2a2f200000000,
+ 0xa30f17f300000000, 0x1814b1fa00000000, 0x05e904fb00000000,
+ 0x22eedaf900000000, 0x3f136ff800000000, 0x6ce066fc00000000,
+ 0x711dd3fd00000000, 0x561a0dff00000000, 0x4be7b8fe00000000,
+ 0xc0c981b700000000, 0xdd3434b600000000, 0xfa33eab400000000,
+ 0xe7ce5fb500000000, 0xb43d56b100000000, 0xa9c0e3b000000000,
+ 0x8ec73db200000000, 0x933a88b300000000, 0x28212eba00000000,
+ 0x35dc9bbb00000000, 0x12db45b900000000, 0x0f26f0b800000000,
+ 0x5cd5f9bc00000000, 0x41284cbd00000000, 0x662f92bf00000000,
+ 0x7bd227be00000000, 0x1018deac00000000, 0x0de56bad00000000,
+ 0x2ae2b5af00000000, 0x371f00ae00000000, 0x64ec09aa00000000,
+ 0x7911bcab00000000, 0x5e1662a900000000, 0x43ebd7a800000000,
+ 0xf8f071a100000000, 0xe50dc4a000000000, 0xc20a1aa200000000,
+ 0xdff7afa300000000, 0x8c04a6a700000000, 0x91f913a600000000,
+ 0xb6fecda400000000, 0xab0378a500000000, 0x606a3e8100000000,
+ 0x7d978b8000000000, 0x5a90558200000000, 0x476de08300000000,
+ 0x149ee98700000000, 0x09635c8600000000, 0x2e64828400000000,
+ 0x3399378500000000, 0x8882918c00000000, 0x957f248d00000000,
+ 0xb278fa8f00000000, 0xaf854f8e00000000, 0xfc76468a00000000,
+ 0xe18bf38b00000000, 0xc68c2d8900000000, 0xdb71988800000000,
+ 0xb0bb619a00000000, 0xad46d49b00000000, 0x8a410a9900000000,
+ 0x97bcbf9800000000, 0xc44fb69c00000000, 0xd9b2039d00000000,
+ 0xfeb5dd9f00000000, 0xe348689e00000000, 0x5853ce9700000000,
+ 0x45ae7b9600000000, 0x62a9a59400000000, 0x7f54109500000000,
+ 0x2ca7199100000000, 0x315aac9000000000, 0x165d729200000000,
+ 0x0ba0c79300000000},
+ {0x0000000000000000, 0x24d9076300000000, 0x48b20fc600000000,
+ 0x6c6b08a500000000, 0xd1626e5700000000, 0xf5bb693400000000,
+ 0x99d0619100000000, 0xbd0966f200000000, 0xa2c5dcae00000000,
+ 0x861cdbcd00000000, 0xea77d36800000000, 0xceaed40b00000000,
+ 0x73a7b2f900000000, 0x577eb59a00000000, 0x3b15bd3f00000000,
+ 0x1fccba5c00000000, 0x058dc88600000000, 0x2154cfe500000000,
+ 0x4d3fc74000000000, 0x69e6c02300000000, 0xd4efa6d100000000,
+ 0xf036a1b200000000, 0x9c5da91700000000, 0xb884ae7400000000,
+ 0xa748142800000000, 0x8391134b00000000, 0xeffa1bee00000000,
+ 0xcb231c8d00000000, 0x762a7a7f00000000, 0x52f37d1c00000000,
+ 0x3e9875b900000000, 0x1a4172da00000000, 0x4b1ce0d600000000,
+ 0x6fc5e7b500000000, 0x03aeef1000000000, 0x2777e87300000000,
+ 0x9a7e8e8100000000, 0xbea789e200000000, 0xd2cc814700000000,
+ 0xf615862400000000, 0xe9d93c7800000000, 0xcd003b1b00000000,
+ 0xa16b33be00000000, 0x85b234dd00000000, 0x38bb522f00000000,
+ 0x1c62554c00000000, 0x70095de900000000, 0x54d05a8a00000000,
+ 0x4e91285000000000, 0x6a482f3300000000, 0x0623279600000000,
+ 0x22fa20f500000000, 0x9ff3460700000000, 0xbb2a416400000000,
+ 0xd74149c100000000, 0xf3984ea200000000, 0xec54f4fe00000000,
+ 0xc88df39d00000000, 0xa4e6fb3800000000, 0x803ffc5b00000000,
+ 0x3d369aa900000000, 0x19ef9dca00000000, 0x7584956f00000000,
+ 0x515d920c00000000, 0xd73eb17600000000, 0xf3e7b61500000000,
+ 0x9f8cbeb000000000, 0xbb55b9d300000000, 0x065cdf2100000000,
+ 0x2285d84200000000, 0x4eeed0e700000000, 0x6a37d78400000000,
+ 0x75fb6dd800000000, 0x51226abb00000000, 0x3d49621e00000000,
+ 0x1990657d00000000, 0xa499038f00000000, 0x804004ec00000000,
+ 0xec2b0c4900000000, 0xc8f20b2a00000000, 0xd2b379f000000000,
+ 0xf66a7e9300000000, 0x9a01763600000000, 0xbed8715500000000,
+ 0x03d117a700000000, 0x270810c400000000, 0x4b63186100000000,
+ 0x6fba1f0200000000, 0x7076a55e00000000, 0x54afa23d00000000,
+ 0x38c4aa9800000000, 0x1c1dadfb00000000, 0xa114cb0900000000,
+ 0x85cdcc6a00000000, 0xe9a6c4cf00000000, 0xcd7fc3ac00000000,
+ 0x9c2251a000000000, 0xb8fb56c300000000, 0xd4905e6600000000,
+ 0xf049590500000000, 0x4d403ff700000000, 0x6999389400000000,
+ 0x05f2303100000000, 0x212b375200000000, 0x3ee78d0e00000000,
+ 0x1a3e8a6d00000000, 0x765582c800000000, 0x528c85ab00000000,
+ 0xef85e35900000000, 0xcb5ce43a00000000, 0xa737ec9f00000000,
+ 0x83eeebfc00000000, 0x99af992600000000, 0xbd769e4500000000,
+ 0xd11d96e000000000, 0xf5c4918300000000, 0x48cdf77100000000,
+ 0x6c14f01200000000, 0x007ff8b700000000, 0x24a6ffd400000000,
+ 0x3b6a458800000000, 0x1fb342eb00000000, 0x73d84a4e00000000,
+ 0x57014d2d00000000, 0xea082bdf00000000, 0xced12cbc00000000,
+ 0xa2ba241900000000, 0x8663237a00000000, 0xae7d62ed00000000,
+ 0x8aa4658e00000000, 0xe6cf6d2b00000000, 0xc2166a4800000000,
+ 0x7f1f0cba00000000, 0x5bc60bd900000000, 0x37ad037c00000000,
+ 0x1374041f00000000, 0x0cb8be4300000000, 0x2861b92000000000,
+ 0x440ab18500000000, 0x60d3b6e600000000, 0xdddad01400000000,
+ 0xf903d77700000000, 0x9568dfd200000000, 0xb1b1d8b100000000,
+ 0xabf0aa6b00000000, 0x8f29ad0800000000, 0xe342a5ad00000000,
+ 0xc79ba2ce00000000, 0x7a92c43c00000000, 0x5e4bc35f00000000,
+ 0x3220cbfa00000000, 0x16f9cc9900000000, 0x093576c500000000,
+ 0x2dec71a600000000, 0x4187790300000000, 0x655e7e6000000000,
+ 0xd857189200000000, 0xfc8e1ff100000000, 0x90e5175400000000,
+ 0xb43c103700000000, 0xe561823b00000000, 0xc1b8855800000000,
+ 0xadd38dfd00000000, 0x890a8a9e00000000, 0x3403ec6c00000000,
+ 0x10daeb0f00000000, 0x7cb1e3aa00000000, 0x5868e4c900000000,
+ 0x47a45e9500000000, 0x637d59f600000000, 0x0f16515300000000,
+ 0x2bcf563000000000, 0x96c630c200000000, 0xb21f37a100000000,
+ 0xde743f0400000000, 0xfaad386700000000, 0xe0ec4abd00000000,
+ 0xc4354dde00000000, 0xa85e457b00000000, 0x8c87421800000000,
+ 0x318e24ea00000000, 0x1557238900000000, 0x793c2b2c00000000,
+ 0x5de52c4f00000000, 0x4229961300000000, 0x66f0917000000000,
+ 0x0a9b99d500000000, 0x2e429eb600000000, 0x934bf84400000000,
+ 0xb792ff2700000000, 0xdbf9f78200000000, 0xff20f0e100000000,
+ 0x7943d39b00000000, 0x5d9ad4f800000000, 0x31f1dc5d00000000,
+ 0x1528db3e00000000, 0xa821bdcc00000000, 0x8cf8baaf00000000,
+ 0xe093b20a00000000, 0xc44ab56900000000, 0xdb860f3500000000,
+ 0xff5f085600000000, 0x933400f300000000, 0xb7ed079000000000,
+ 0x0ae4616200000000, 0x2e3d660100000000, 0x42566ea400000000,
+ 0x668f69c700000000, 0x7cce1b1d00000000, 0x58171c7e00000000,
+ 0x347c14db00000000, 0x10a513b800000000, 0xadac754a00000000,
+ 0x8975722900000000, 0xe51e7a8c00000000, 0xc1c77def00000000,
+ 0xde0bc7b300000000, 0xfad2c0d000000000, 0x96b9c87500000000,
+ 0xb260cf1600000000, 0x0f69a9e400000000, 0x2bb0ae8700000000,
+ 0x47dba62200000000, 0x6302a14100000000, 0x325f334d00000000,
+ 0x1686342e00000000, 0x7aed3c8b00000000, 0x5e343be800000000,
+ 0xe33d5d1a00000000, 0xc7e45a7900000000, 0xab8f52dc00000000,
+ 0x8f5655bf00000000, 0x909aefe300000000, 0xb443e88000000000,
+ 0xd828e02500000000, 0xfcf1e74600000000, 0x41f881b400000000,
+ 0x652186d700000000, 0x094a8e7200000000, 0x2d93891100000000,
+ 0x37d2fbcb00000000, 0x130bfca800000000, 0x7f60f40d00000000,
+ 0x5bb9f36e00000000, 0xe6b0959c00000000, 0xc26992ff00000000,
+ 0xae029a5a00000000, 0x8adb9d3900000000, 0x9517276500000000,
+ 0xb1ce200600000000, 0xdda528a300000000, 0xf97c2fc000000000,
+ 0x4475493200000000, 0x60ac4e5100000000, 0x0cc746f400000000,
+ 0x281e419700000000},
+ {0x0000000000000000, 0x08e3603c00000000, 0x10c6c17800000000,
+ 0x1825a14400000000, 0x208c83f100000000, 0x286fe3cd00000000,
+ 0x304a428900000000, 0x38a922b500000000, 0x011e763800000000,
+ 0x09fd160400000000, 0x11d8b74000000000, 0x193bd77c00000000,
+ 0x2192f5c900000000, 0x297195f500000000, 0x315434b100000000,
+ 0x39b7548d00000000, 0x023cec7000000000, 0x0adf8c4c00000000,
+ 0x12fa2d0800000000, 0x1a194d3400000000, 0x22b06f8100000000,
+ 0x2a530fbd00000000, 0x3276aef900000000, 0x3a95cec500000000,
+ 0x03229a4800000000, 0x0bc1fa7400000000, 0x13e45b3000000000,
+ 0x1b073b0c00000000, 0x23ae19b900000000, 0x2b4d798500000000,
+ 0x3368d8c100000000, 0x3b8bb8fd00000000, 0x0478d8e100000000,
+ 0x0c9bb8dd00000000, 0x14be199900000000, 0x1c5d79a500000000,
+ 0x24f45b1000000000, 0x2c173b2c00000000, 0x34329a6800000000,
+ 0x3cd1fa5400000000, 0x0566aed900000000, 0x0d85cee500000000,
+ 0x15a06fa100000000, 0x1d430f9d00000000, 0x25ea2d2800000000,
+ 0x2d094d1400000000, 0x352cec5000000000, 0x3dcf8c6c00000000,
+ 0x0644349100000000, 0x0ea754ad00000000, 0x1682f5e900000000,
+ 0x1e6195d500000000, 0x26c8b76000000000, 0x2e2bd75c00000000,
+ 0x360e761800000000, 0x3eed162400000000, 0x075a42a900000000,
+ 0x0fb9229500000000, 0x179c83d100000000, 0x1f7fe3ed00000000,
+ 0x27d6c15800000000, 0x2f35a16400000000, 0x3710002000000000,
+ 0x3ff3601c00000000, 0x49f6c11800000000, 0x4115a12400000000,
+ 0x5930006000000000, 0x51d3605c00000000, 0x697a42e900000000,
+ 0x619922d500000000, 0x79bc839100000000, 0x715fe3ad00000000,
+ 0x48e8b72000000000, 0x400bd71c00000000, 0x582e765800000000,
+ 0x50cd166400000000, 0x686434d100000000, 0x608754ed00000000,
+ 0x78a2f5a900000000, 0x7041959500000000, 0x4bca2d6800000000,
+ 0x43294d5400000000, 0x5b0cec1000000000, 0x53ef8c2c00000000,
+ 0x6b46ae9900000000, 0x63a5cea500000000, 0x7b806fe100000000,
+ 0x73630fdd00000000, 0x4ad45b5000000000, 0x42373b6c00000000,
+ 0x5a129a2800000000, 0x52f1fa1400000000, 0x6a58d8a100000000,
+ 0x62bbb89d00000000, 0x7a9e19d900000000, 0x727d79e500000000,
+ 0x4d8e19f900000000, 0x456d79c500000000, 0x5d48d88100000000,
+ 0x55abb8bd00000000, 0x6d029a0800000000, 0x65e1fa3400000000,
+ 0x7dc45b7000000000, 0x75273b4c00000000, 0x4c906fc100000000,
+ 0x44730ffd00000000, 0x5c56aeb900000000, 0x54b5ce8500000000,
+ 0x6c1cec3000000000, 0x64ff8c0c00000000, 0x7cda2d4800000000,
+ 0x74394d7400000000, 0x4fb2f58900000000, 0x475195b500000000,
+ 0x5f7434f100000000, 0x579754cd00000000, 0x6f3e767800000000,
+ 0x67dd164400000000, 0x7ff8b70000000000, 0x771bd73c00000000,
+ 0x4eac83b100000000, 0x464fe38d00000000, 0x5e6a42c900000000,
+ 0x568922f500000000, 0x6e20004000000000, 0x66c3607c00000000,
+ 0x7ee6c13800000000, 0x7605a10400000000, 0x92ec833100000000,
+ 0x9a0fe30d00000000, 0x822a424900000000, 0x8ac9227500000000,
+ 0xb26000c000000000, 0xba8360fc00000000, 0xa2a6c1b800000000,
+ 0xaa45a18400000000, 0x93f2f50900000000, 0x9b11953500000000,
+ 0x8334347100000000, 0x8bd7544d00000000, 0xb37e76f800000000,
+ 0xbb9d16c400000000, 0xa3b8b78000000000, 0xab5bd7bc00000000,
+ 0x90d06f4100000000, 0x98330f7d00000000, 0x8016ae3900000000,
+ 0x88f5ce0500000000, 0xb05cecb000000000, 0xb8bf8c8c00000000,
+ 0xa09a2dc800000000, 0xa8794df400000000, 0x91ce197900000000,
+ 0x992d794500000000, 0x8108d80100000000, 0x89ebb83d00000000,
+ 0xb1429a8800000000, 0xb9a1fab400000000, 0xa1845bf000000000,
+ 0xa9673bcc00000000, 0x96945bd000000000, 0x9e773bec00000000,
+ 0x86529aa800000000, 0x8eb1fa9400000000, 0xb618d82100000000,
+ 0xbefbb81d00000000, 0xa6de195900000000, 0xae3d796500000000,
+ 0x978a2de800000000, 0x9f694dd400000000, 0x874cec9000000000,
+ 0x8faf8cac00000000, 0xb706ae1900000000, 0xbfe5ce2500000000,
+ 0xa7c06f6100000000, 0xaf230f5d00000000, 0x94a8b7a000000000,
+ 0x9c4bd79c00000000, 0x846e76d800000000, 0x8c8d16e400000000,
+ 0xb424345100000000, 0xbcc7546d00000000, 0xa4e2f52900000000,
+ 0xac01951500000000, 0x95b6c19800000000, 0x9d55a1a400000000,
+ 0x857000e000000000, 0x8d9360dc00000000, 0xb53a426900000000,
+ 0xbdd9225500000000, 0xa5fc831100000000, 0xad1fe32d00000000,
+ 0xdb1a422900000000, 0xd3f9221500000000, 0xcbdc835100000000,
+ 0xc33fe36d00000000, 0xfb96c1d800000000, 0xf375a1e400000000,
+ 0xeb5000a000000000, 0xe3b3609c00000000, 0xda04341100000000,
+ 0xd2e7542d00000000, 0xcac2f56900000000, 0xc221955500000000,
+ 0xfa88b7e000000000, 0xf26bd7dc00000000, 0xea4e769800000000,
+ 0xe2ad16a400000000, 0xd926ae5900000000, 0xd1c5ce6500000000,
+ 0xc9e06f2100000000, 0xc1030f1d00000000, 0xf9aa2da800000000,
+ 0xf1494d9400000000, 0xe96cecd000000000, 0xe18f8cec00000000,
+ 0xd838d86100000000, 0xd0dbb85d00000000, 0xc8fe191900000000,
+ 0xc01d792500000000, 0xf8b45b9000000000, 0xf0573bac00000000,
+ 0xe8729ae800000000, 0xe091fad400000000, 0xdf629ac800000000,
+ 0xd781faf400000000, 0xcfa45bb000000000, 0xc7473b8c00000000,
+ 0xffee193900000000, 0xf70d790500000000, 0xef28d84100000000,
+ 0xe7cbb87d00000000, 0xde7cecf000000000, 0xd69f8ccc00000000,
+ 0xceba2d8800000000, 0xc6594db400000000, 0xfef06f0100000000,
+ 0xf6130f3d00000000, 0xee36ae7900000000, 0xe6d5ce4500000000,
+ 0xdd5e76b800000000, 0xd5bd168400000000, 0xcd98b7c000000000,
+ 0xc57bd7fc00000000, 0xfdd2f54900000000, 0xf531957500000000,
+ 0xed14343100000000, 0xe5f7540d00000000, 0xdc40008000000000,
+ 0xd4a360bc00000000, 0xcc86c1f800000000, 0xc465a1c400000000,
+ 0xfccc837100000000, 0xf42fe34d00000000, 0xec0a420900000000,
+ 0xe4e9223500000000},
+ {0x0000000000000000, 0xd1e8e70e00000000, 0xa2d1cf1d00000000,
+ 0x7339281300000000, 0x44a39f3b00000000, 0x954b783500000000,
+ 0xe672502600000000, 0x379ab72800000000, 0x88463f7700000000,
+ 0x59aed87900000000, 0x2a97f06a00000000, 0xfb7f176400000000,
+ 0xcce5a04c00000000, 0x1d0d474200000000, 0x6e346f5100000000,
+ 0xbfdc885f00000000, 0x108d7eee00000000, 0xc16599e000000000,
+ 0xb25cb1f300000000, 0x63b456fd00000000, 0x542ee1d500000000,
+ 0x85c606db00000000, 0xf6ff2ec800000000, 0x2717c9c600000000,
+ 0x98cb419900000000, 0x4923a69700000000, 0x3a1a8e8400000000,
+ 0xebf2698a00000000, 0xdc68dea200000000, 0x0d8039ac00000000,
+ 0x7eb911bf00000000, 0xaf51f6b100000000, 0x611c8c0700000000,
+ 0xb0f46b0900000000, 0xc3cd431a00000000, 0x1225a41400000000,
+ 0x25bf133c00000000, 0xf457f43200000000, 0x876edc2100000000,
+ 0x56863b2f00000000, 0xe95ab37000000000, 0x38b2547e00000000,
+ 0x4b8b7c6d00000000, 0x9a639b6300000000, 0xadf92c4b00000000,
+ 0x7c11cb4500000000, 0x0f28e35600000000, 0xdec0045800000000,
+ 0x7191f2e900000000, 0xa07915e700000000, 0xd3403df400000000,
+ 0x02a8dafa00000000, 0x35326dd200000000, 0xe4da8adc00000000,
+ 0x97e3a2cf00000000, 0x460b45c100000000, 0xf9d7cd9e00000000,
+ 0x283f2a9000000000, 0x5b06028300000000, 0x8aeee58d00000000,
+ 0xbd7452a500000000, 0x6c9cb5ab00000000, 0x1fa59db800000000,
+ 0xce4d7ab600000000, 0xc238180f00000000, 0x13d0ff0100000000,
+ 0x60e9d71200000000, 0xb101301c00000000, 0x869b873400000000,
+ 0x5773603a00000000, 0x244a482900000000, 0xf5a2af2700000000,
+ 0x4a7e277800000000, 0x9b96c07600000000, 0xe8afe86500000000,
+ 0x39470f6b00000000, 0x0eddb84300000000, 0xdf355f4d00000000,
+ 0xac0c775e00000000, 0x7de4905000000000, 0xd2b566e100000000,
+ 0x035d81ef00000000, 0x7064a9fc00000000, 0xa18c4ef200000000,
+ 0x9616f9da00000000, 0x47fe1ed400000000, 0x34c736c700000000,
+ 0xe52fd1c900000000, 0x5af3599600000000, 0x8b1bbe9800000000,
+ 0xf822968b00000000, 0x29ca718500000000, 0x1e50c6ad00000000,
+ 0xcfb821a300000000, 0xbc8109b000000000, 0x6d69eebe00000000,
+ 0xa324940800000000, 0x72cc730600000000, 0x01f55b1500000000,
+ 0xd01dbc1b00000000, 0xe7870b3300000000, 0x366fec3d00000000,
+ 0x4556c42e00000000, 0x94be232000000000, 0x2b62ab7f00000000,
+ 0xfa8a4c7100000000, 0x89b3646200000000, 0x585b836c00000000,
+ 0x6fc1344400000000, 0xbe29d34a00000000, 0xcd10fb5900000000,
+ 0x1cf81c5700000000, 0xb3a9eae600000000, 0x62410de800000000,
+ 0x117825fb00000000, 0xc090c2f500000000, 0xf70a75dd00000000,
+ 0x26e292d300000000, 0x55dbbac000000000, 0x84335dce00000000,
+ 0x3befd59100000000, 0xea07329f00000000, 0x993e1a8c00000000,
+ 0x48d6fd8200000000, 0x7f4c4aaa00000000, 0xaea4ada400000000,
+ 0xdd9d85b700000000, 0x0c7562b900000000, 0x8471301e00000000,
+ 0x5599d71000000000, 0x26a0ff0300000000, 0xf748180d00000000,
+ 0xc0d2af2500000000, 0x113a482b00000000, 0x6203603800000000,
+ 0xb3eb873600000000, 0x0c370f6900000000, 0xdddfe86700000000,
+ 0xaee6c07400000000, 0x7f0e277a00000000, 0x4894905200000000,
+ 0x997c775c00000000, 0xea455f4f00000000, 0x3badb84100000000,
+ 0x94fc4ef000000000, 0x4514a9fe00000000, 0x362d81ed00000000,
+ 0xe7c566e300000000, 0xd05fd1cb00000000, 0x01b736c500000000,
+ 0x728e1ed600000000, 0xa366f9d800000000, 0x1cba718700000000,
+ 0xcd52968900000000, 0xbe6bbe9a00000000, 0x6f83599400000000,
+ 0x5819eebc00000000, 0x89f109b200000000, 0xfac821a100000000,
+ 0x2b20c6af00000000, 0xe56dbc1900000000, 0x34855b1700000000,
+ 0x47bc730400000000, 0x9654940a00000000, 0xa1ce232200000000,
+ 0x7026c42c00000000, 0x031fec3f00000000, 0xd2f70b3100000000,
+ 0x6d2b836e00000000, 0xbcc3646000000000, 0xcffa4c7300000000,
+ 0x1e12ab7d00000000, 0x29881c5500000000, 0xf860fb5b00000000,
+ 0x8b59d34800000000, 0x5ab1344600000000, 0xf5e0c2f700000000,
+ 0x240825f900000000, 0x57310dea00000000, 0x86d9eae400000000,
+ 0xb1435dcc00000000, 0x60abbac200000000, 0x139292d100000000,
+ 0xc27a75df00000000, 0x7da6fd8000000000, 0xac4e1a8e00000000,
+ 0xdf77329d00000000, 0x0e9fd59300000000, 0x390562bb00000000,
+ 0xe8ed85b500000000, 0x9bd4ada600000000, 0x4a3c4aa800000000,
+ 0x4649281100000000, 0x97a1cf1f00000000, 0xe498e70c00000000,
+ 0x3570000200000000, 0x02eab72a00000000, 0xd302502400000000,
+ 0xa03b783700000000, 0x71d39f3900000000, 0xce0f176600000000,
+ 0x1fe7f06800000000, 0x6cded87b00000000, 0xbd363f7500000000,
+ 0x8aac885d00000000, 0x5b446f5300000000, 0x287d474000000000,
+ 0xf995a04e00000000, 0x56c456ff00000000, 0x872cb1f100000000,
+ 0xf41599e200000000, 0x25fd7eec00000000, 0x1267c9c400000000,
+ 0xc38f2eca00000000, 0xb0b606d900000000, 0x615ee1d700000000,
+ 0xde82698800000000, 0x0f6a8e8600000000, 0x7c53a69500000000,
+ 0xadbb419b00000000, 0x9a21f6b300000000, 0x4bc911bd00000000,
+ 0x38f039ae00000000, 0xe918dea000000000, 0x2755a41600000000,
+ 0xf6bd431800000000, 0x85846b0b00000000, 0x546c8c0500000000,
+ 0x63f63b2d00000000, 0xb21edc2300000000, 0xc127f43000000000,
+ 0x10cf133e00000000, 0xaf139b6100000000, 0x7efb7c6f00000000,
+ 0x0dc2547c00000000, 0xdc2ab37200000000, 0xebb0045a00000000,
+ 0x3a58e35400000000, 0x4961cb4700000000, 0x98892c4900000000,
+ 0x37d8daf800000000, 0xe6303df600000000, 0x950915e500000000,
+ 0x44e1f2eb00000000, 0x737b45c300000000, 0xa293a2cd00000000,
+ 0xd1aa8ade00000000, 0x00426dd000000000, 0xbf9ee58f00000000,
+ 0x6e76028100000000, 0x1d4f2a9200000000, 0xcca7cd9c00000000,
+ 0xfb3d7ab400000000, 0x2ad59dba00000000, 0x59ecb5a900000000,
+ 0x880452a700000000},
+ {0x0000000000000000, 0xaa05daf100000000, 0x150dc53800000000,
+ 0xbf081fc900000000, 0x2a1a8a7100000000, 0x801f508000000000,
+ 0x3f174f4900000000, 0x951295b800000000, 0x543414e300000000,
+ 0xfe31ce1200000000, 0x4139d1db00000000, 0xeb3c0b2a00000000,
+ 0x7e2e9e9200000000, 0xd42b446300000000, 0x6b235baa00000000,
+ 0xc126815b00000000, 0xe96e591d00000000, 0x436b83ec00000000,
+ 0xfc639c2500000000, 0x566646d400000000, 0xc374d36c00000000,
+ 0x6971099d00000000, 0xd679165400000000, 0x7c7ccca500000000,
+ 0xbd5a4dfe00000000, 0x175f970f00000000, 0xa85788c600000000,
+ 0x0252523700000000, 0x9740c78f00000000, 0x3d451d7e00000000,
+ 0x824d02b700000000, 0x2848d84600000000, 0xd2ddb23a00000000,
+ 0x78d868cb00000000, 0xc7d0770200000000, 0x6dd5adf300000000,
+ 0xf8c7384b00000000, 0x52c2e2ba00000000, 0xedcafd7300000000,
+ 0x47cf278200000000, 0x86e9a6d900000000, 0x2cec7c2800000000,
+ 0x93e463e100000000, 0x39e1b91000000000, 0xacf32ca800000000,
+ 0x06f6f65900000000, 0xb9fee99000000000, 0x13fb336100000000,
+ 0x3bb3eb2700000000, 0x91b631d600000000, 0x2ebe2e1f00000000,
+ 0x84bbf4ee00000000, 0x11a9615600000000, 0xbbacbba700000000,
+ 0x04a4a46e00000000, 0xaea17e9f00000000, 0x6f87ffc400000000,
+ 0xc582253500000000, 0x7a8a3afc00000000, 0xd08fe00d00000000,
+ 0x459d75b500000000, 0xef98af4400000000, 0x5090b08d00000000,
+ 0xfa956a7c00000000, 0xa4bb657500000000, 0x0ebebf8400000000,
+ 0xb1b6a04d00000000, 0x1bb37abc00000000, 0x8ea1ef0400000000,
+ 0x24a435f500000000, 0x9bac2a3c00000000, 0x31a9f0cd00000000,
+ 0xf08f719600000000, 0x5a8aab6700000000, 0xe582b4ae00000000,
+ 0x4f876e5f00000000, 0xda95fbe700000000, 0x7090211600000000,
+ 0xcf983edf00000000, 0x659de42e00000000, 0x4dd53c6800000000,
+ 0xe7d0e69900000000, 0x58d8f95000000000, 0xf2dd23a100000000,
+ 0x67cfb61900000000, 0xcdca6ce800000000, 0x72c2732100000000,
+ 0xd8c7a9d000000000, 0x19e1288b00000000, 0xb3e4f27a00000000,
+ 0x0cecedb300000000, 0xa6e9374200000000, 0x33fba2fa00000000,
+ 0x99fe780b00000000, 0x26f667c200000000, 0x8cf3bd3300000000,
+ 0x7666d74f00000000, 0xdc630dbe00000000, 0x636b127700000000,
+ 0xc96ec88600000000, 0x5c7c5d3e00000000, 0xf67987cf00000000,
+ 0x4971980600000000, 0xe37442f700000000, 0x2252c3ac00000000,
+ 0x8857195d00000000, 0x375f069400000000, 0x9d5adc6500000000,
+ 0x084849dd00000000, 0xa24d932c00000000, 0x1d458ce500000000,
+ 0xb740561400000000, 0x9f088e5200000000, 0x350d54a300000000,
+ 0x8a054b6a00000000, 0x2000919b00000000, 0xb512042300000000,
+ 0x1f17ded200000000, 0xa01fc11b00000000, 0x0a1a1bea00000000,
+ 0xcb3c9ab100000000, 0x6139404000000000, 0xde315f8900000000,
+ 0x7434857800000000, 0xe12610c000000000, 0x4b23ca3100000000,
+ 0xf42bd5f800000000, 0x5e2e0f0900000000, 0x4877cbea00000000,
+ 0xe272111b00000000, 0x5d7a0ed200000000, 0xf77fd42300000000,
+ 0x626d419b00000000, 0xc8689b6a00000000, 0x776084a300000000,
+ 0xdd655e5200000000, 0x1c43df0900000000, 0xb64605f800000000,
+ 0x094e1a3100000000, 0xa34bc0c000000000, 0x3659557800000000,
+ 0x9c5c8f8900000000, 0x2354904000000000, 0x89514ab100000000,
+ 0xa11992f700000000, 0x0b1c480600000000, 0xb41457cf00000000,
+ 0x1e118d3e00000000, 0x8b03188600000000, 0x2106c27700000000,
+ 0x9e0eddbe00000000, 0x340b074f00000000, 0xf52d861400000000,
+ 0x5f285ce500000000, 0xe020432c00000000, 0x4a2599dd00000000,
+ 0xdf370c6500000000, 0x7532d69400000000, 0xca3ac95d00000000,
+ 0x603f13ac00000000, 0x9aaa79d000000000, 0x30afa32100000000,
+ 0x8fa7bce800000000, 0x25a2661900000000, 0xb0b0f3a100000000,
+ 0x1ab5295000000000, 0xa5bd369900000000, 0x0fb8ec6800000000,
+ 0xce9e6d3300000000, 0x649bb7c200000000, 0xdb93a80b00000000,
+ 0x719672fa00000000, 0xe484e74200000000, 0x4e813db300000000,
+ 0xf189227a00000000, 0x5b8cf88b00000000, 0x73c420cd00000000,
+ 0xd9c1fa3c00000000, 0x66c9e5f500000000, 0xcccc3f0400000000,
+ 0x59deaabc00000000, 0xf3db704d00000000, 0x4cd36f8400000000,
+ 0xe6d6b57500000000, 0x27f0342e00000000, 0x8df5eedf00000000,
+ 0x32fdf11600000000, 0x98f82be700000000, 0x0deabe5f00000000,
+ 0xa7ef64ae00000000, 0x18e77b6700000000, 0xb2e2a19600000000,
+ 0xecccae9f00000000, 0x46c9746e00000000, 0xf9c16ba700000000,
+ 0x53c4b15600000000, 0xc6d624ee00000000, 0x6cd3fe1f00000000,
+ 0xd3dbe1d600000000, 0x79de3b2700000000, 0xb8f8ba7c00000000,
+ 0x12fd608d00000000, 0xadf57f4400000000, 0x07f0a5b500000000,
+ 0x92e2300d00000000, 0x38e7eafc00000000, 0x87eff53500000000,
+ 0x2dea2fc400000000, 0x05a2f78200000000, 0xafa72d7300000000,
+ 0x10af32ba00000000, 0xbaaae84b00000000, 0x2fb87df300000000,
+ 0x85bda70200000000, 0x3ab5b8cb00000000, 0x90b0623a00000000,
+ 0x5196e36100000000, 0xfb93399000000000, 0x449b265900000000,
+ 0xee9efca800000000, 0x7b8c691000000000, 0xd189b3e100000000,
+ 0x6e81ac2800000000, 0xc48476d900000000, 0x3e111ca500000000,
+ 0x9414c65400000000, 0x2b1cd99d00000000, 0x8119036c00000000,
+ 0x140b96d400000000, 0xbe0e4c2500000000, 0x010653ec00000000,
+ 0xab03891d00000000, 0x6a25084600000000, 0xc020d2b700000000,
+ 0x7f28cd7e00000000, 0xd52d178f00000000, 0x403f823700000000,
+ 0xea3a58c600000000, 0x5532470f00000000, 0xff379dfe00000000,
+ 0xd77f45b800000000, 0x7d7a9f4900000000, 0xc272808000000000,
+ 0x68775a7100000000, 0xfd65cfc900000000, 0x5760153800000000,
+ 0xe8680af100000000, 0x426dd00000000000, 0x834b515b00000000,
+ 0x294e8baa00000000, 0x9646946300000000, 0x3c434e9200000000,
+ 0xa951db2a00000000, 0x035401db00000000, 0xbc5c1e1200000000,
+ 0x1659c4e300000000}};
+
+#else /* W == 4 */
+
+local const z_crc_t FAR crc_braid_table[][256] = {
+ {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87,
+ 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede,
+ 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab,
+ 0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c,
+ 0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1,
+ 0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7,
+ 0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e,
+ 0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308,
+ 0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5,
+ 0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472,
+ 0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07,
+ 0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e,
+ 0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa,
+ 0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec,
+ 0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6,
+ 0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0,
+ 0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3,
+ 0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba,
+ 0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf,
+ 0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975,
+ 0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8,
+ 0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde,
+ 0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a,
+ 0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c,
+ 0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1,
+ 0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65,
+ 0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410,
+ 0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649,
+ 0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a,
+ 0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c,
+ 0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946,
+ 0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450,
+ 0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e,
+ 0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857,
+ 0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022,
+ 0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5,
+ 0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758,
+ 0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e,
+ 0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d,
+ 0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b,
+ 0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6,
+ 0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401,
+ 0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74,
+ 0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d,
+ 0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073,
+ 0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65,
+ 0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f,
+ 0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749,
+ 0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a,
+ 0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033,
+ 0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846,
+ 0x0d7139d7},
+ {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563,
+ 0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f,
+ 0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875,
+ 0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536,
+ 0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8,
+ 0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43,
+ 0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f,
+ 0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184,
+ 0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a,
+ 0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39,
+ 0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523,
+ 0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f,
+ 0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d,
+ 0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6,
+ 0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b,
+ 0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0,
+ 0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151,
+ 0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d,
+ 0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47,
+ 0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a,
+ 0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964,
+ 0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef,
+ 0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d,
+ 0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6,
+ 0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348,
+ 0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53,
+ 0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449,
+ 0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645,
+ 0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4,
+ 0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f,
+ 0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2,
+ 0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69,
+ 0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46,
+ 0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a,
+ 0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650,
+ 0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13,
+ 0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded,
+ 0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366,
+ 0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57,
+ 0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc,
+ 0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222,
+ 0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61,
+ 0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b,
+ 0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277,
+ 0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558,
+ 0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3,
+ 0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e,
+ 0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5,
+ 0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74,
+ 0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78,
+ 0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262,
+ 0x1c53e98a},
+ {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b,
+ 0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40,
+ 0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580,
+ 0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7,
+ 0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a,
+ 0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37,
+ 0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75,
+ 0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218,
+ 0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5,
+ 0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2,
+ 0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02,
+ 0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59,
+ 0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1,
+ 0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c,
+ 0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a,
+ 0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307,
+ 0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486,
+ 0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd,
+ 0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d,
+ 0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2,
+ 0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f,
+ 0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72,
+ 0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8,
+ 0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985,
+ 0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268,
+ 0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94,
+ 0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454,
+ 0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f,
+ 0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e,
+ 0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3,
+ 0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915,
+ 0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778,
+ 0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821,
+ 0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a,
+ 0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba,
+ 0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d,
+ 0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560,
+ 0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d,
+ 0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe,
+ 0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3,
+ 0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e,
+ 0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509,
+ 0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9,
+ 0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92,
+ 0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb,
+ 0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6,
+ 0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50,
+ 0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d,
+ 0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc,
+ 0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7,
+ 0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927,
+ 0x3f88e851},
+ {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96,
+ 0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8,
+ 0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0,
+ 0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14,
+ 0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7,
+ 0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4,
+ 0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe,
+ 0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad,
+ 0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e,
+ 0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa,
+ 0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2,
+ 0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c,
+ 0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab,
+ 0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8,
+ 0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d,
+ 0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e,
+ 0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7,
+ 0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99,
+ 0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1,
+ 0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690,
+ 0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933,
+ 0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20,
+ 0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf,
+ 0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc,
+ 0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f,
+ 0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92,
+ 0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca,
+ 0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4,
+ 0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd,
+ 0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de,
+ 0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb,
+ 0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8,
+ 0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474,
+ 0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a,
+ 0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252,
+ 0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6,
+ 0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55,
+ 0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846,
+ 0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7,
+ 0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4,
+ 0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47,
+ 0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3,
+ 0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb,
+ 0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5,
+ 0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49,
+ 0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a,
+ 0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f,
+ 0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c,
+ 0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305,
+ 0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b,
+ 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523,
+ 0x3dee8ca6}};
+
+local const z_word_t FAR crc_braid_big_table[][256] = {
+ {0x00000000, 0x85d996dd, 0x4bb55c60, 0xce6ccabd, 0x966ab9c0,
+ 0x13b32f1d, 0xdddfe5a0, 0x5806737d, 0x6dd3035a, 0xe80a9587,
+ 0x26665f3a, 0xa3bfc9e7, 0xfbb9ba9a, 0x7e602c47, 0xb00ce6fa,
+ 0x35d57027, 0xdaa607b4, 0x5f7f9169, 0x91135bd4, 0x14cacd09,
+ 0x4cccbe74, 0xc91528a9, 0x0779e214, 0x82a074c9, 0xb77504ee,
+ 0x32ac9233, 0xfcc0588e, 0x7919ce53, 0x211fbd2e, 0xa4c62bf3,
+ 0x6aaae14e, 0xef737793, 0xf54b7eb3, 0x7092e86e, 0xbefe22d3,
+ 0x3b27b40e, 0x6321c773, 0xe6f851ae, 0x28949b13, 0xad4d0dce,
+ 0x98987de9, 0x1d41eb34, 0xd32d2189, 0x56f4b754, 0x0ef2c429,
+ 0x8b2b52f4, 0x45479849, 0xc09e0e94, 0x2fed7907, 0xaa34efda,
+ 0x64582567, 0xe181b3ba, 0xb987c0c7, 0x3c5e561a, 0xf2329ca7,
+ 0x77eb0a7a, 0x423e7a5d, 0xc7e7ec80, 0x098b263d, 0x8c52b0e0,
+ 0xd454c39d, 0x518d5540, 0x9fe19ffd, 0x1a380920, 0xab918dbd,
+ 0x2e481b60, 0xe024d1dd, 0x65fd4700, 0x3dfb347d, 0xb822a2a0,
+ 0x764e681d, 0xf397fec0, 0xc6428ee7, 0x439b183a, 0x8df7d287,
+ 0x082e445a, 0x50283727, 0xd5f1a1fa, 0x1b9d6b47, 0x9e44fd9a,
+ 0x71378a09, 0xf4ee1cd4, 0x3a82d669, 0xbf5b40b4, 0xe75d33c9,
+ 0x6284a514, 0xace86fa9, 0x2931f974, 0x1ce48953, 0x993d1f8e,
+ 0x5751d533, 0xd28843ee, 0x8a8e3093, 0x0f57a64e, 0xc13b6cf3,
+ 0x44e2fa2e, 0x5edaf30e, 0xdb0365d3, 0x156faf6e, 0x90b639b3,
+ 0xc8b04ace, 0x4d69dc13, 0x830516ae, 0x06dc8073, 0x3309f054,
+ 0xb6d06689, 0x78bcac34, 0xfd653ae9, 0xa5634994, 0x20badf49,
+ 0xeed615f4, 0x6b0f8329, 0x847cf4ba, 0x01a56267, 0xcfc9a8da,
+ 0x4a103e07, 0x12164d7a, 0x97cfdba7, 0x59a3111a, 0xdc7a87c7,
+ 0xe9aff7e0, 0x6c76613d, 0xa21aab80, 0x27c33d5d, 0x7fc54e20,
+ 0xfa1cd8fd, 0x34701240, 0xb1a9849d, 0x17256aa0, 0x92fcfc7d,
+ 0x5c9036c0, 0xd949a01d, 0x814fd360, 0x049645bd, 0xcafa8f00,
+ 0x4f2319dd, 0x7af669fa, 0xff2fff27, 0x3143359a, 0xb49aa347,
+ 0xec9cd03a, 0x694546e7, 0xa7298c5a, 0x22f01a87, 0xcd836d14,
+ 0x485afbc9, 0x86363174, 0x03efa7a9, 0x5be9d4d4, 0xde304209,
+ 0x105c88b4, 0x95851e69, 0xa0506e4e, 0x2589f893, 0xebe5322e,
+ 0x6e3ca4f3, 0x363ad78e, 0xb3e34153, 0x7d8f8bee, 0xf8561d33,
+ 0xe26e1413, 0x67b782ce, 0xa9db4873, 0x2c02deae, 0x7404add3,
+ 0xf1dd3b0e, 0x3fb1f1b3, 0xba68676e, 0x8fbd1749, 0x0a648194,
+ 0xc4084b29, 0x41d1ddf4, 0x19d7ae89, 0x9c0e3854, 0x5262f2e9,
+ 0xd7bb6434, 0x38c813a7, 0xbd11857a, 0x737d4fc7, 0xf6a4d91a,
+ 0xaea2aa67, 0x2b7b3cba, 0xe517f607, 0x60ce60da, 0x551b10fd,
+ 0xd0c28620, 0x1eae4c9d, 0x9b77da40, 0xc371a93d, 0x46a83fe0,
+ 0x88c4f55d, 0x0d1d6380, 0xbcb4e71d, 0x396d71c0, 0xf701bb7d,
+ 0x72d82da0, 0x2ade5edd, 0xaf07c800, 0x616b02bd, 0xe4b29460,
+ 0xd167e447, 0x54be729a, 0x9ad2b827, 0x1f0b2efa, 0x470d5d87,
+ 0xc2d4cb5a, 0x0cb801e7, 0x8961973a, 0x6612e0a9, 0xe3cb7674,
+ 0x2da7bcc9, 0xa87e2a14, 0xf0785969, 0x75a1cfb4, 0xbbcd0509,
+ 0x3e1493d4, 0x0bc1e3f3, 0x8e18752e, 0x4074bf93, 0xc5ad294e,
+ 0x9dab5a33, 0x1872ccee, 0xd61e0653, 0x53c7908e, 0x49ff99ae,
+ 0xcc260f73, 0x024ac5ce, 0x87935313, 0xdf95206e, 0x5a4cb6b3,
+ 0x94207c0e, 0x11f9ead3, 0x242c9af4, 0xa1f50c29, 0x6f99c694,
+ 0xea405049, 0xb2462334, 0x379fb5e9, 0xf9f37f54, 0x7c2ae989,
+ 0x93599e1a, 0x168008c7, 0xd8ecc27a, 0x5d3554a7, 0x053327da,
+ 0x80eab107, 0x4e867bba, 0xcb5fed67, 0xfe8a9d40, 0x7b530b9d,
+ 0xb53fc120, 0x30e657fd, 0x68e02480, 0xed39b25d, 0x235578e0,
+ 0xa68cee3d},
+ {0x00000000, 0x76e10f9d, 0xadc46ee1, 0xdb25617c, 0x1b8fac19,
+ 0x6d6ea384, 0xb64bc2f8, 0xc0aacd65, 0x361e5933, 0x40ff56ae,
+ 0x9bda37d2, 0xed3b384f, 0x2d91f52a, 0x5b70fab7, 0x80559bcb,
+ 0xf6b49456, 0x6c3cb266, 0x1addbdfb, 0xc1f8dc87, 0xb719d31a,
+ 0x77b31e7f, 0x015211e2, 0xda77709e, 0xac967f03, 0x5a22eb55,
+ 0x2cc3e4c8, 0xf7e685b4, 0x81078a29, 0x41ad474c, 0x374c48d1,
+ 0xec6929ad, 0x9a882630, 0xd87864cd, 0xae996b50, 0x75bc0a2c,
+ 0x035d05b1, 0xc3f7c8d4, 0xb516c749, 0x6e33a635, 0x18d2a9a8,
+ 0xee663dfe, 0x98873263, 0x43a2531f, 0x35435c82, 0xf5e991e7,
+ 0x83089e7a, 0x582dff06, 0x2eccf09b, 0xb444d6ab, 0xc2a5d936,
+ 0x1980b84a, 0x6f61b7d7, 0xafcb7ab2, 0xd92a752f, 0x020f1453,
+ 0x74ee1bce, 0x825a8f98, 0xf4bb8005, 0x2f9ee179, 0x597feee4,
+ 0x99d52381, 0xef342c1c, 0x34114d60, 0x42f042fd, 0xf1f7b941,
+ 0x8716b6dc, 0x5c33d7a0, 0x2ad2d83d, 0xea781558, 0x9c991ac5,
+ 0x47bc7bb9, 0x315d7424, 0xc7e9e072, 0xb108efef, 0x6a2d8e93,
+ 0x1ccc810e, 0xdc664c6b, 0xaa8743f6, 0x71a2228a, 0x07432d17,
+ 0x9dcb0b27, 0xeb2a04ba, 0x300f65c6, 0x46ee6a5b, 0x8644a73e,
+ 0xf0a5a8a3, 0x2b80c9df, 0x5d61c642, 0xabd55214, 0xdd345d89,
+ 0x06113cf5, 0x70f03368, 0xb05afe0d, 0xc6bbf190, 0x1d9e90ec,
+ 0x6b7f9f71, 0x298fdd8c, 0x5f6ed211, 0x844bb36d, 0xf2aabcf0,
+ 0x32007195, 0x44e17e08, 0x9fc41f74, 0xe92510e9, 0x1f9184bf,
+ 0x69708b22, 0xb255ea5e, 0xc4b4e5c3, 0x041e28a6, 0x72ff273b,
+ 0xa9da4647, 0xdf3b49da, 0x45b36fea, 0x33526077, 0xe877010b,
+ 0x9e960e96, 0x5e3cc3f3, 0x28ddcc6e, 0xf3f8ad12, 0x8519a28f,
+ 0x73ad36d9, 0x054c3944, 0xde695838, 0xa88857a5, 0x68229ac0,
+ 0x1ec3955d, 0xc5e6f421, 0xb307fbbc, 0xe2ef7383, 0x940e7c1e,
+ 0x4f2b1d62, 0x39ca12ff, 0xf960df9a, 0x8f81d007, 0x54a4b17b,
+ 0x2245bee6, 0xd4f12ab0, 0xa210252d, 0x79354451, 0x0fd44bcc,
+ 0xcf7e86a9, 0xb99f8934, 0x62bae848, 0x145be7d5, 0x8ed3c1e5,
+ 0xf832ce78, 0x2317af04, 0x55f6a099, 0x955c6dfc, 0xe3bd6261,
+ 0x3898031d, 0x4e790c80, 0xb8cd98d6, 0xce2c974b, 0x1509f637,
+ 0x63e8f9aa, 0xa34234cf, 0xd5a33b52, 0x0e865a2e, 0x786755b3,
+ 0x3a97174e, 0x4c7618d3, 0x975379af, 0xe1b27632, 0x2118bb57,
+ 0x57f9b4ca, 0x8cdcd5b6, 0xfa3dda2b, 0x0c894e7d, 0x7a6841e0,
+ 0xa14d209c, 0xd7ac2f01, 0x1706e264, 0x61e7edf9, 0xbac28c85,
+ 0xcc238318, 0x56aba528, 0x204aaab5, 0xfb6fcbc9, 0x8d8ec454,
+ 0x4d240931, 0x3bc506ac, 0xe0e067d0, 0x9601684d, 0x60b5fc1b,
+ 0x1654f386, 0xcd7192fa, 0xbb909d67, 0x7b3a5002, 0x0ddb5f9f,
+ 0xd6fe3ee3, 0xa01f317e, 0x1318cac2, 0x65f9c55f, 0xbedca423,
+ 0xc83dabbe, 0x089766db, 0x7e766946, 0xa553083a, 0xd3b207a7,
+ 0x250693f1, 0x53e79c6c, 0x88c2fd10, 0xfe23f28d, 0x3e893fe8,
+ 0x48683075, 0x934d5109, 0xe5ac5e94, 0x7f2478a4, 0x09c57739,
+ 0xd2e01645, 0xa40119d8, 0x64abd4bd, 0x124adb20, 0xc96fba5c,
+ 0xbf8eb5c1, 0x493a2197, 0x3fdb2e0a, 0xe4fe4f76, 0x921f40eb,
+ 0x52b58d8e, 0x24548213, 0xff71e36f, 0x8990ecf2, 0xcb60ae0f,
+ 0xbd81a192, 0x66a4c0ee, 0x1045cf73, 0xd0ef0216, 0xa60e0d8b,
+ 0x7d2b6cf7, 0x0bca636a, 0xfd7ef73c, 0x8b9ff8a1, 0x50ba99dd,
+ 0x265b9640, 0xe6f15b25, 0x901054b8, 0x4b3535c4, 0x3dd43a59,
+ 0xa75c1c69, 0xd1bd13f4, 0x0a987288, 0x7c797d15, 0xbcd3b070,
+ 0xca32bfed, 0x1117de91, 0x67f6d10c, 0x9142455a, 0xe7a34ac7,
+ 0x3c862bbb, 0x4a672426, 0x8acde943, 0xfc2ce6de, 0x270987a2,
+ 0x51e8883f},
+ {0x00000000, 0xe8dbfbb9, 0x91b186a8, 0x796a7d11, 0x63657c8a,
+ 0x8bbe8733, 0xf2d4fa22, 0x1a0f019b, 0x87cc89cf, 0x6f177276,
+ 0x167d0f67, 0xfea6f4de, 0xe4a9f545, 0x0c720efc, 0x751873ed,
+ 0x9dc38854, 0x4f9f6244, 0xa74499fd, 0xde2ee4ec, 0x36f51f55,
+ 0x2cfa1ece, 0xc421e577, 0xbd4b9866, 0x559063df, 0xc853eb8b,
+ 0x20881032, 0x59e26d23, 0xb139969a, 0xab369701, 0x43ed6cb8,
+ 0x3a8711a9, 0xd25cea10, 0x9e3ec588, 0x76e53e31, 0x0f8f4320,
+ 0xe754b899, 0xfd5bb902, 0x158042bb, 0x6cea3faa, 0x8431c413,
+ 0x19f24c47, 0xf129b7fe, 0x8843caef, 0x60983156, 0x7a9730cd,
+ 0x924ccb74, 0xeb26b665, 0x03fd4ddc, 0xd1a1a7cc, 0x397a5c75,
+ 0x40102164, 0xa8cbdadd, 0xb2c4db46, 0x5a1f20ff, 0x23755dee,
+ 0xcbaea657, 0x566d2e03, 0xbeb6d5ba, 0xc7dca8ab, 0x2f075312,
+ 0x35085289, 0xddd3a930, 0xa4b9d421, 0x4c622f98, 0x7d7bfbca,
+ 0x95a00073, 0xecca7d62, 0x041186db, 0x1e1e8740, 0xf6c57cf9,
+ 0x8faf01e8, 0x6774fa51, 0xfab77205, 0x126c89bc, 0x6b06f4ad,
+ 0x83dd0f14, 0x99d20e8f, 0x7109f536, 0x08638827, 0xe0b8739e,
+ 0x32e4998e, 0xda3f6237, 0xa3551f26, 0x4b8ee49f, 0x5181e504,
+ 0xb95a1ebd, 0xc03063ac, 0x28eb9815, 0xb5281041, 0x5df3ebf8,
+ 0x249996e9, 0xcc426d50, 0xd64d6ccb, 0x3e969772, 0x47fcea63,
+ 0xaf2711da, 0xe3453e42, 0x0b9ec5fb, 0x72f4b8ea, 0x9a2f4353,
+ 0x802042c8, 0x68fbb971, 0x1191c460, 0xf94a3fd9, 0x6489b78d,
+ 0x8c524c34, 0xf5383125, 0x1de3ca9c, 0x07eccb07, 0xef3730be,
+ 0x965d4daf, 0x7e86b616, 0xacda5c06, 0x4401a7bf, 0x3d6bdaae,
+ 0xd5b02117, 0xcfbf208c, 0x2764db35, 0x5e0ea624, 0xb6d55d9d,
+ 0x2b16d5c9, 0xc3cd2e70, 0xbaa75361, 0x527ca8d8, 0x4873a943,
+ 0xa0a852fa, 0xd9c22feb, 0x3119d452, 0xbbf0874e, 0x532b7cf7,
+ 0x2a4101e6, 0xc29afa5f, 0xd895fbc4, 0x304e007d, 0x49247d6c,
+ 0xa1ff86d5, 0x3c3c0e81, 0xd4e7f538, 0xad8d8829, 0x45567390,
+ 0x5f59720b, 0xb78289b2, 0xcee8f4a3, 0x26330f1a, 0xf46fe50a,
+ 0x1cb41eb3, 0x65de63a2, 0x8d05981b, 0x970a9980, 0x7fd16239,
+ 0x06bb1f28, 0xee60e491, 0x73a36cc5, 0x9b78977c, 0xe212ea6d,
+ 0x0ac911d4, 0x10c6104f, 0xf81debf6, 0x817796e7, 0x69ac6d5e,
+ 0x25ce42c6, 0xcd15b97f, 0xb47fc46e, 0x5ca43fd7, 0x46ab3e4c,
+ 0xae70c5f5, 0xd71ab8e4, 0x3fc1435d, 0xa202cb09, 0x4ad930b0,
+ 0x33b34da1, 0xdb68b618, 0xc167b783, 0x29bc4c3a, 0x50d6312b,
+ 0xb80dca92, 0x6a512082, 0x828adb3b, 0xfbe0a62a, 0x133b5d93,
+ 0x09345c08, 0xe1efa7b1, 0x9885daa0, 0x705e2119, 0xed9da94d,
+ 0x054652f4, 0x7c2c2fe5, 0x94f7d45c, 0x8ef8d5c7, 0x66232e7e,
+ 0x1f49536f, 0xf792a8d6, 0xc68b7c84, 0x2e50873d, 0x573afa2c,
+ 0xbfe10195, 0xa5ee000e, 0x4d35fbb7, 0x345f86a6, 0xdc847d1f,
+ 0x4147f54b, 0xa99c0ef2, 0xd0f673e3, 0x382d885a, 0x222289c1,
+ 0xcaf97278, 0xb3930f69, 0x5b48f4d0, 0x89141ec0, 0x61cfe579,
+ 0x18a59868, 0xf07e63d1, 0xea71624a, 0x02aa99f3, 0x7bc0e4e2,
+ 0x931b1f5b, 0x0ed8970f, 0xe6036cb6, 0x9f6911a7, 0x77b2ea1e,
+ 0x6dbdeb85, 0x8566103c, 0xfc0c6d2d, 0x14d79694, 0x58b5b90c,
+ 0xb06e42b5, 0xc9043fa4, 0x21dfc41d, 0x3bd0c586, 0xd30b3e3f,
+ 0xaa61432e, 0x42bab897, 0xdf7930c3, 0x37a2cb7a, 0x4ec8b66b,
+ 0xa6134dd2, 0xbc1c4c49, 0x54c7b7f0, 0x2dadcae1, 0xc5763158,
+ 0x172adb48, 0xfff120f1, 0x869b5de0, 0x6e40a659, 0x744fa7c2,
+ 0x9c945c7b, 0xe5fe216a, 0x0d25dad3, 0x90e65287, 0x783da93e,
+ 0x0157d42f, 0xe98c2f96, 0xf3832e0d, 0x1b58d5b4, 0x6232a8a5,
+ 0x8ae9531c},
+ {0x00000000, 0x919168ae, 0x6325a087, 0xf2b4c829, 0x874c31d4,
+ 0x16dd597a, 0xe4699153, 0x75f8f9fd, 0x4f9f1373, 0xde0e7bdd,
+ 0x2cbab3f4, 0xbd2bdb5a, 0xc8d322a7, 0x59424a09, 0xabf68220,
+ 0x3a67ea8e, 0x9e3e27e6, 0x0faf4f48, 0xfd1b8761, 0x6c8aefcf,
+ 0x19721632, 0x88e37e9c, 0x7a57b6b5, 0xebc6de1b, 0xd1a13495,
+ 0x40305c3b, 0xb2849412, 0x2315fcbc, 0x56ed0541, 0xc77c6def,
+ 0x35c8a5c6, 0xa459cd68, 0x7d7b3f17, 0xecea57b9, 0x1e5e9f90,
+ 0x8fcff73e, 0xfa370ec3, 0x6ba6666d, 0x9912ae44, 0x0883c6ea,
+ 0x32e42c64, 0xa37544ca, 0x51c18ce3, 0xc050e44d, 0xb5a81db0,
+ 0x2439751e, 0xd68dbd37, 0x471cd599, 0xe34518f1, 0x72d4705f,
+ 0x8060b876, 0x11f1d0d8, 0x64092925, 0xf598418b, 0x072c89a2,
+ 0x96bde10c, 0xacda0b82, 0x3d4b632c, 0xcfffab05, 0x5e6ec3ab,
+ 0x2b963a56, 0xba0752f8, 0x48b39ad1, 0xd922f27f, 0xfaf67e2e,
+ 0x6b671680, 0x99d3dea9, 0x0842b607, 0x7dba4ffa, 0xec2b2754,
+ 0x1e9fef7d, 0x8f0e87d3, 0xb5696d5d, 0x24f805f3, 0xd64ccdda,
+ 0x47dda574, 0x32255c89, 0xa3b43427, 0x5100fc0e, 0xc09194a0,
+ 0x64c859c8, 0xf5593166, 0x07edf94f, 0x967c91e1, 0xe384681c,
+ 0x721500b2, 0x80a1c89b, 0x1130a035, 0x2b574abb, 0xbac62215,
+ 0x4872ea3c, 0xd9e38292, 0xac1b7b6f, 0x3d8a13c1, 0xcf3edbe8,
+ 0x5eafb346, 0x878d4139, 0x161c2997, 0xe4a8e1be, 0x75398910,
+ 0x00c170ed, 0x91501843, 0x63e4d06a, 0xf275b8c4, 0xc812524a,
+ 0x59833ae4, 0xab37f2cd, 0x3aa69a63, 0x4f5e639e, 0xdecf0b30,
+ 0x2c7bc319, 0xbdeaabb7, 0x19b366df, 0x88220e71, 0x7a96c658,
+ 0xeb07aef6, 0x9eff570b, 0x0f6e3fa5, 0xfddaf78c, 0x6c4b9f22,
+ 0x562c75ac, 0xc7bd1d02, 0x3509d52b, 0xa498bd85, 0xd1604478,
+ 0x40f12cd6, 0xb245e4ff, 0x23d48c51, 0xf4edfd5c, 0x657c95f2,
+ 0x97c85ddb, 0x06593575, 0x73a1cc88, 0xe230a426, 0x10846c0f,
+ 0x811504a1, 0xbb72ee2f, 0x2ae38681, 0xd8574ea8, 0x49c62606,
+ 0x3c3edffb, 0xadafb755, 0x5f1b7f7c, 0xce8a17d2, 0x6ad3daba,
+ 0xfb42b214, 0x09f67a3d, 0x98671293, 0xed9feb6e, 0x7c0e83c0,
+ 0x8eba4be9, 0x1f2b2347, 0x254cc9c9, 0xb4dda167, 0x4669694e,
+ 0xd7f801e0, 0xa200f81d, 0x339190b3, 0xc125589a, 0x50b43034,
+ 0x8996c24b, 0x1807aae5, 0xeab362cc, 0x7b220a62, 0x0edaf39f,
+ 0x9f4b9b31, 0x6dff5318, 0xfc6e3bb6, 0xc609d138, 0x5798b996,
+ 0xa52c71bf, 0x34bd1911, 0x4145e0ec, 0xd0d48842, 0x2260406b,
+ 0xb3f128c5, 0x17a8e5ad, 0x86398d03, 0x748d452a, 0xe51c2d84,
+ 0x90e4d479, 0x0175bcd7, 0xf3c174fe, 0x62501c50, 0x5837f6de,
+ 0xc9a69e70, 0x3b125659, 0xaa833ef7, 0xdf7bc70a, 0x4eeaafa4,
+ 0xbc5e678d, 0x2dcf0f23, 0x0e1b8372, 0x9f8aebdc, 0x6d3e23f5,
+ 0xfcaf4b5b, 0x8957b2a6, 0x18c6da08, 0xea721221, 0x7be37a8f,
+ 0x41849001, 0xd015f8af, 0x22a13086, 0xb3305828, 0xc6c8a1d5,
+ 0x5759c97b, 0xa5ed0152, 0x347c69fc, 0x9025a494, 0x01b4cc3a,
+ 0xf3000413, 0x62916cbd, 0x17699540, 0x86f8fdee, 0x744c35c7,
+ 0xe5dd5d69, 0xdfbab7e7, 0x4e2bdf49, 0xbc9f1760, 0x2d0e7fce,
+ 0x58f68633, 0xc967ee9d, 0x3bd326b4, 0xaa424e1a, 0x7360bc65,
+ 0xe2f1d4cb, 0x10451ce2, 0x81d4744c, 0xf42c8db1, 0x65bde51f,
+ 0x97092d36, 0x06984598, 0x3cffaf16, 0xad6ec7b8, 0x5fda0f91,
+ 0xce4b673f, 0xbbb39ec2, 0x2a22f66c, 0xd8963e45, 0x490756eb,
+ 0xed5e9b83, 0x7ccff32d, 0x8e7b3b04, 0x1fea53aa, 0x6a12aa57,
+ 0xfb83c2f9, 0x09370ad0, 0x98a6627e, 0xa2c188f0, 0x3350e05e,
+ 0xc1e42877, 0x507540d9, 0x258db924, 0xb41cd18a, 0x46a819a3,
+ 0xd739710d}};
+
+#endif
+
+#endif
+
+#if N == 5
+
+#if W == 8
+
+local const z_crc_t FAR crc_braid_table[][256] = {
+ {0x00000000, 0xaf449247, 0x85f822cf, 0x2abcb088, 0xd08143df,
+ 0x7fc5d198, 0x55796110, 0xfa3df357, 0x7a7381ff, 0xd53713b8,
+ 0xff8ba330, 0x50cf3177, 0xaaf2c220, 0x05b65067, 0x2f0ae0ef,
+ 0x804e72a8, 0xf4e703fe, 0x5ba391b9, 0x711f2131, 0xde5bb376,
+ 0x24664021, 0x8b22d266, 0xa19e62ee, 0x0edaf0a9, 0x8e948201,
+ 0x21d01046, 0x0b6ca0ce, 0xa4283289, 0x5e15c1de, 0xf1515399,
+ 0xdbede311, 0x74a97156, 0x32bf01bd, 0x9dfb93fa, 0xb7472372,
+ 0x1803b135, 0xe23e4262, 0x4d7ad025, 0x67c660ad, 0xc882f2ea,
+ 0x48cc8042, 0xe7881205, 0xcd34a28d, 0x627030ca, 0x984dc39d,
+ 0x370951da, 0x1db5e152, 0xb2f17315, 0xc6580243, 0x691c9004,
+ 0x43a0208c, 0xece4b2cb, 0x16d9419c, 0xb99dd3db, 0x93216353,
+ 0x3c65f114, 0xbc2b83bc, 0x136f11fb, 0x39d3a173, 0x96973334,
+ 0x6caac063, 0xc3ee5224, 0xe952e2ac, 0x461670eb, 0x657e037a,
+ 0xca3a913d, 0xe08621b5, 0x4fc2b3f2, 0xb5ff40a5, 0x1abbd2e2,
+ 0x3007626a, 0x9f43f02d, 0x1f0d8285, 0xb04910c2, 0x9af5a04a,
+ 0x35b1320d, 0xcf8cc15a, 0x60c8531d, 0x4a74e395, 0xe53071d2,
+ 0x91990084, 0x3edd92c3, 0x1461224b, 0xbb25b00c, 0x4118435b,
+ 0xee5cd11c, 0xc4e06194, 0x6ba4f3d3, 0xebea817b, 0x44ae133c,
+ 0x6e12a3b4, 0xc15631f3, 0x3b6bc2a4, 0x942f50e3, 0xbe93e06b,
+ 0x11d7722c, 0x57c102c7, 0xf8859080, 0xd2392008, 0x7d7db24f,
+ 0x87404118, 0x2804d35f, 0x02b863d7, 0xadfcf190, 0x2db28338,
+ 0x82f6117f, 0xa84aa1f7, 0x070e33b0, 0xfd33c0e7, 0x527752a0,
+ 0x78cbe228, 0xd78f706f, 0xa3260139, 0x0c62937e, 0x26de23f6,
+ 0x899ab1b1, 0x73a742e6, 0xdce3d0a1, 0xf65f6029, 0x591bf26e,
+ 0xd95580c6, 0x76111281, 0x5cada209, 0xf3e9304e, 0x09d4c319,
+ 0xa690515e, 0x8c2ce1d6, 0x23687391, 0xcafc06f4, 0x65b894b3,
+ 0x4f04243b, 0xe040b67c, 0x1a7d452b, 0xb539d76c, 0x9f8567e4,
+ 0x30c1f5a3, 0xb08f870b, 0x1fcb154c, 0x3577a5c4, 0x9a333783,
+ 0x600ec4d4, 0xcf4a5693, 0xe5f6e61b, 0x4ab2745c, 0x3e1b050a,
+ 0x915f974d, 0xbbe327c5, 0x14a7b582, 0xee9a46d5, 0x41ded492,
+ 0x6b62641a, 0xc426f65d, 0x446884f5, 0xeb2c16b2, 0xc190a63a,
+ 0x6ed4347d, 0x94e9c72a, 0x3bad556d, 0x1111e5e5, 0xbe5577a2,
+ 0xf8430749, 0x5707950e, 0x7dbb2586, 0xd2ffb7c1, 0x28c24496,
+ 0x8786d6d1, 0xad3a6659, 0x027ef41e, 0x823086b6, 0x2d7414f1,
+ 0x07c8a479, 0xa88c363e, 0x52b1c569, 0xfdf5572e, 0xd749e7a6,
+ 0x780d75e1, 0x0ca404b7, 0xa3e096f0, 0x895c2678, 0x2618b43f,
+ 0xdc254768, 0x7361d52f, 0x59dd65a7, 0xf699f7e0, 0x76d78548,
+ 0xd993170f, 0xf32fa787, 0x5c6b35c0, 0xa656c697, 0x091254d0,
+ 0x23aee458, 0x8cea761f, 0xaf82058e, 0x00c697c9, 0x2a7a2741,
+ 0x853eb506, 0x7f034651, 0xd047d416, 0xfafb649e, 0x55bff6d9,
+ 0xd5f18471, 0x7ab51636, 0x5009a6be, 0xff4d34f9, 0x0570c7ae,
+ 0xaa3455e9, 0x8088e561, 0x2fcc7726, 0x5b650670, 0xf4219437,
+ 0xde9d24bf, 0x71d9b6f8, 0x8be445af, 0x24a0d7e8, 0x0e1c6760,
+ 0xa158f527, 0x2116878f, 0x8e5215c8, 0xa4eea540, 0x0baa3707,
+ 0xf197c450, 0x5ed35617, 0x746fe69f, 0xdb2b74d8, 0x9d3d0433,
+ 0x32799674, 0x18c526fc, 0xb781b4bb, 0x4dbc47ec, 0xe2f8d5ab,
+ 0xc8446523, 0x6700f764, 0xe74e85cc, 0x480a178b, 0x62b6a703,
+ 0xcdf23544, 0x37cfc613, 0x988b5454, 0xb237e4dc, 0x1d73769b,
+ 0x69da07cd, 0xc69e958a, 0xec222502, 0x4366b745, 0xb95b4412,
+ 0x161fd655, 0x3ca366dd, 0x93e7f49a, 0x13a98632, 0xbced1475,
+ 0x9651a4fd, 0x391536ba, 0xc328c5ed, 0x6c6c57aa, 0x46d0e722,
+ 0xe9947565},
+ {0x00000000, 0x4e890ba9, 0x9d121752, 0xd39b1cfb, 0xe15528e5,
+ 0xafdc234c, 0x7c473fb7, 0x32ce341e, 0x19db578b, 0x57525c22,
+ 0x84c940d9, 0xca404b70, 0xf88e7f6e, 0xb60774c7, 0x659c683c,
+ 0x2b156395, 0x33b6af16, 0x7d3fa4bf, 0xaea4b844, 0xe02db3ed,
+ 0xd2e387f3, 0x9c6a8c5a, 0x4ff190a1, 0x01789b08, 0x2a6df89d,
+ 0x64e4f334, 0xb77fefcf, 0xf9f6e466, 0xcb38d078, 0x85b1dbd1,
+ 0x562ac72a, 0x18a3cc83, 0x676d5e2c, 0x29e45585, 0xfa7f497e,
+ 0xb4f642d7, 0x863876c9, 0xc8b17d60, 0x1b2a619b, 0x55a36a32,
+ 0x7eb609a7, 0x303f020e, 0xe3a41ef5, 0xad2d155c, 0x9fe32142,
+ 0xd16a2aeb, 0x02f13610, 0x4c783db9, 0x54dbf13a, 0x1a52fa93,
+ 0xc9c9e668, 0x8740edc1, 0xb58ed9df, 0xfb07d276, 0x289cce8d,
+ 0x6615c524, 0x4d00a6b1, 0x0389ad18, 0xd012b1e3, 0x9e9bba4a,
+ 0xac558e54, 0xe2dc85fd, 0x31479906, 0x7fce92af, 0xcedabc58,
+ 0x8053b7f1, 0x53c8ab0a, 0x1d41a0a3, 0x2f8f94bd, 0x61069f14,
+ 0xb29d83ef, 0xfc148846, 0xd701ebd3, 0x9988e07a, 0x4a13fc81,
+ 0x049af728, 0x3654c336, 0x78ddc89f, 0xab46d464, 0xe5cfdfcd,
+ 0xfd6c134e, 0xb3e518e7, 0x607e041c, 0x2ef70fb5, 0x1c393bab,
+ 0x52b03002, 0x812b2cf9, 0xcfa22750, 0xe4b744c5, 0xaa3e4f6c,
+ 0x79a55397, 0x372c583e, 0x05e26c20, 0x4b6b6789, 0x98f07b72,
+ 0xd67970db, 0xa9b7e274, 0xe73ee9dd, 0x34a5f526, 0x7a2cfe8f,
+ 0x48e2ca91, 0x066bc138, 0xd5f0ddc3, 0x9b79d66a, 0xb06cb5ff,
+ 0xfee5be56, 0x2d7ea2ad, 0x63f7a904, 0x51399d1a, 0x1fb096b3,
+ 0xcc2b8a48, 0x82a281e1, 0x9a014d62, 0xd48846cb, 0x07135a30,
+ 0x499a5199, 0x7b546587, 0x35dd6e2e, 0xe64672d5, 0xa8cf797c,
+ 0x83da1ae9, 0xcd531140, 0x1ec80dbb, 0x50410612, 0x628f320c,
+ 0x2c0639a5, 0xff9d255e, 0xb1142ef7, 0x46c47ef1, 0x084d7558,
+ 0xdbd669a3, 0x955f620a, 0xa7915614, 0xe9185dbd, 0x3a834146,
+ 0x740a4aef, 0x5f1f297a, 0x119622d3, 0xc20d3e28, 0x8c843581,
+ 0xbe4a019f, 0xf0c30a36, 0x235816cd, 0x6dd11d64, 0x7572d1e7,
+ 0x3bfbda4e, 0xe860c6b5, 0xa6e9cd1c, 0x9427f902, 0xdaaef2ab,
+ 0x0935ee50, 0x47bce5f9, 0x6ca9866c, 0x22208dc5, 0xf1bb913e,
+ 0xbf329a97, 0x8dfcae89, 0xc375a520, 0x10eeb9db, 0x5e67b272,
+ 0x21a920dd, 0x6f202b74, 0xbcbb378f, 0xf2323c26, 0xc0fc0838,
+ 0x8e750391, 0x5dee1f6a, 0x136714c3, 0x38727756, 0x76fb7cff,
+ 0xa5606004, 0xebe96bad, 0xd9275fb3, 0x97ae541a, 0x443548e1,
+ 0x0abc4348, 0x121f8fcb, 0x5c968462, 0x8f0d9899, 0xc1849330,
+ 0xf34aa72e, 0xbdc3ac87, 0x6e58b07c, 0x20d1bbd5, 0x0bc4d840,
+ 0x454dd3e9, 0x96d6cf12, 0xd85fc4bb, 0xea91f0a5, 0xa418fb0c,
+ 0x7783e7f7, 0x390aec5e, 0x881ec2a9, 0xc697c900, 0x150cd5fb,
+ 0x5b85de52, 0x694bea4c, 0x27c2e1e5, 0xf459fd1e, 0xbad0f6b7,
+ 0x91c59522, 0xdf4c9e8b, 0x0cd78270, 0x425e89d9, 0x7090bdc7,
+ 0x3e19b66e, 0xed82aa95, 0xa30ba13c, 0xbba86dbf, 0xf5216616,
+ 0x26ba7aed, 0x68337144, 0x5afd455a, 0x14744ef3, 0xc7ef5208,
+ 0x896659a1, 0xa2733a34, 0xecfa319d, 0x3f612d66, 0x71e826cf,
+ 0x432612d1, 0x0daf1978, 0xde340583, 0x90bd0e2a, 0xef739c85,
+ 0xa1fa972c, 0x72618bd7, 0x3ce8807e, 0x0e26b460, 0x40afbfc9,
+ 0x9334a332, 0xddbda89b, 0xf6a8cb0e, 0xb821c0a7, 0x6bbadc5c,
+ 0x2533d7f5, 0x17fde3eb, 0x5974e842, 0x8aeff4b9, 0xc466ff10,
+ 0xdcc53393, 0x924c383a, 0x41d724c1, 0x0f5e2f68, 0x3d901b76,
+ 0x731910df, 0xa0820c24, 0xee0b078d, 0xc51e6418, 0x8b976fb1,
+ 0x580c734a, 0x168578e3, 0x244b4cfd, 0x6ac24754, 0xb9595baf,
+ 0xf7d05006},
+ {0x00000000, 0x8d88fde2, 0xc060fd85, 0x4de80067, 0x5bb0fd4b,
+ 0xd63800a9, 0x9bd000ce, 0x1658fd2c, 0xb761fa96, 0x3ae90774,
+ 0x77010713, 0xfa89faf1, 0xecd107dd, 0x6159fa3f, 0x2cb1fa58,
+ 0xa13907ba, 0xb5b2f36d, 0x383a0e8f, 0x75d20ee8, 0xf85af30a,
+ 0xee020e26, 0x638af3c4, 0x2e62f3a3, 0xa3ea0e41, 0x02d309fb,
+ 0x8f5bf419, 0xc2b3f47e, 0x4f3b099c, 0x5963f4b0, 0xd4eb0952,
+ 0x99030935, 0x148bf4d7, 0xb014e09b, 0x3d9c1d79, 0x70741d1e,
+ 0xfdfce0fc, 0xeba41dd0, 0x662ce032, 0x2bc4e055, 0xa64c1db7,
+ 0x07751a0d, 0x8afde7ef, 0xc715e788, 0x4a9d1a6a, 0x5cc5e746,
+ 0xd14d1aa4, 0x9ca51ac3, 0x112de721, 0x05a613f6, 0x882eee14,
+ 0xc5c6ee73, 0x484e1391, 0x5e16eebd, 0xd39e135f, 0x9e761338,
+ 0x13feeeda, 0xb2c7e960, 0x3f4f1482, 0x72a714e5, 0xff2fe907,
+ 0xe977142b, 0x64ffe9c9, 0x2917e9ae, 0xa49f144c, 0xbb58c777,
+ 0x36d03a95, 0x7b383af2, 0xf6b0c710, 0xe0e83a3c, 0x6d60c7de,
+ 0x2088c7b9, 0xad003a5b, 0x0c393de1, 0x81b1c003, 0xcc59c064,
+ 0x41d13d86, 0x5789c0aa, 0xda013d48, 0x97e93d2f, 0x1a61c0cd,
+ 0x0eea341a, 0x8362c9f8, 0xce8ac99f, 0x4302347d, 0x555ac951,
+ 0xd8d234b3, 0x953a34d4, 0x18b2c936, 0xb98bce8c, 0x3403336e,
+ 0x79eb3309, 0xf463ceeb, 0xe23b33c7, 0x6fb3ce25, 0x225bce42,
+ 0xafd333a0, 0x0b4c27ec, 0x86c4da0e, 0xcb2cda69, 0x46a4278b,
+ 0x50fcdaa7, 0xdd742745, 0x909c2722, 0x1d14dac0, 0xbc2ddd7a,
+ 0x31a52098, 0x7c4d20ff, 0xf1c5dd1d, 0xe79d2031, 0x6a15ddd3,
+ 0x27fdddb4, 0xaa752056, 0xbefed481, 0x33762963, 0x7e9e2904,
+ 0xf316d4e6, 0xe54e29ca, 0x68c6d428, 0x252ed44f, 0xa8a629ad,
+ 0x099f2e17, 0x8417d3f5, 0xc9ffd392, 0x44772e70, 0x522fd35c,
+ 0xdfa72ebe, 0x924f2ed9, 0x1fc7d33b, 0xadc088af, 0x2048754d,
+ 0x6da0752a, 0xe02888c8, 0xf67075e4, 0x7bf88806, 0x36108861,
+ 0xbb987583, 0x1aa17239, 0x97298fdb, 0xdac18fbc, 0x5749725e,
+ 0x41118f72, 0xcc997290, 0x817172f7, 0x0cf98f15, 0x18727bc2,
+ 0x95fa8620, 0xd8128647, 0x559a7ba5, 0x43c28689, 0xce4a7b6b,
+ 0x83a27b0c, 0x0e2a86ee, 0xaf138154, 0x229b7cb6, 0x6f737cd1,
+ 0xe2fb8133, 0xf4a37c1f, 0x792b81fd, 0x34c3819a, 0xb94b7c78,
+ 0x1dd46834, 0x905c95d6, 0xddb495b1, 0x503c6853, 0x4664957f,
+ 0xcbec689d, 0x860468fa, 0x0b8c9518, 0xaab592a2, 0x273d6f40,
+ 0x6ad56f27, 0xe75d92c5, 0xf1056fe9, 0x7c8d920b, 0x3165926c,
+ 0xbced6f8e, 0xa8669b59, 0x25ee66bb, 0x680666dc, 0xe58e9b3e,
+ 0xf3d66612, 0x7e5e9bf0, 0x33b69b97, 0xbe3e6675, 0x1f0761cf,
+ 0x928f9c2d, 0xdf679c4a, 0x52ef61a8, 0x44b79c84, 0xc93f6166,
+ 0x84d76101, 0x095f9ce3, 0x16984fd8, 0x9b10b23a, 0xd6f8b25d,
+ 0x5b704fbf, 0x4d28b293, 0xc0a04f71, 0x8d484f16, 0x00c0b2f4,
+ 0xa1f9b54e, 0x2c7148ac, 0x619948cb, 0xec11b529, 0xfa494805,
+ 0x77c1b5e7, 0x3a29b580, 0xb7a14862, 0xa32abcb5, 0x2ea24157,
+ 0x634a4130, 0xeec2bcd2, 0xf89a41fe, 0x7512bc1c, 0x38fabc7b,
+ 0xb5724199, 0x144b4623, 0x99c3bbc1, 0xd42bbba6, 0x59a34644,
+ 0x4ffbbb68, 0xc273468a, 0x8f9b46ed, 0x0213bb0f, 0xa68caf43,
+ 0x2b0452a1, 0x66ec52c6, 0xeb64af24, 0xfd3c5208, 0x70b4afea,
+ 0x3d5caf8d, 0xb0d4526f, 0x11ed55d5, 0x9c65a837, 0xd18da850,
+ 0x5c0555b2, 0x4a5da89e, 0xc7d5557c, 0x8a3d551b, 0x07b5a8f9,
+ 0x133e5c2e, 0x9eb6a1cc, 0xd35ea1ab, 0x5ed65c49, 0x488ea165,
+ 0xc5065c87, 0x88ee5ce0, 0x0566a102, 0xa45fa6b8, 0x29d75b5a,
+ 0x643f5b3d, 0xe9b7a6df, 0xffef5bf3, 0x7267a611, 0x3f8fa676,
+ 0xb2075b94},
+ {0x00000000, 0x80f0171f, 0xda91287f, 0x5a613f60, 0x6e5356bf,
+ 0xeea341a0, 0xb4c27ec0, 0x343269df, 0xdca6ad7e, 0x5c56ba61,
+ 0x06378501, 0x86c7921e, 0xb2f5fbc1, 0x3205ecde, 0x6864d3be,
+ 0xe894c4a1, 0x623c5cbd, 0xe2cc4ba2, 0xb8ad74c2, 0x385d63dd,
+ 0x0c6f0a02, 0x8c9f1d1d, 0xd6fe227d, 0x560e3562, 0xbe9af1c3,
+ 0x3e6ae6dc, 0x640bd9bc, 0xe4fbcea3, 0xd0c9a77c, 0x5039b063,
+ 0x0a588f03, 0x8aa8981c, 0xc478b97a, 0x4488ae65, 0x1ee99105,
+ 0x9e19861a, 0xaa2befc5, 0x2adbf8da, 0x70bac7ba, 0xf04ad0a5,
+ 0x18de1404, 0x982e031b, 0xc24f3c7b, 0x42bf2b64, 0x768d42bb,
+ 0xf67d55a4, 0xac1c6ac4, 0x2cec7ddb, 0xa644e5c7, 0x26b4f2d8,
+ 0x7cd5cdb8, 0xfc25daa7, 0xc817b378, 0x48e7a467, 0x12869b07,
+ 0x92768c18, 0x7ae248b9, 0xfa125fa6, 0xa07360c6, 0x208377d9,
+ 0x14b11e06, 0x94410919, 0xce203679, 0x4ed02166, 0x538074b5,
+ 0xd37063aa, 0x89115cca, 0x09e14bd5, 0x3dd3220a, 0xbd233515,
+ 0xe7420a75, 0x67b21d6a, 0x8f26d9cb, 0x0fd6ced4, 0x55b7f1b4,
+ 0xd547e6ab, 0xe1758f74, 0x6185986b, 0x3be4a70b, 0xbb14b014,
+ 0x31bc2808, 0xb14c3f17, 0xeb2d0077, 0x6bdd1768, 0x5fef7eb7,
+ 0xdf1f69a8, 0x857e56c8, 0x058e41d7, 0xed1a8576, 0x6dea9269,
+ 0x378bad09, 0xb77bba16, 0x8349d3c9, 0x03b9c4d6, 0x59d8fbb6,
+ 0xd928eca9, 0x97f8cdcf, 0x1708dad0, 0x4d69e5b0, 0xcd99f2af,
+ 0xf9ab9b70, 0x795b8c6f, 0x233ab30f, 0xa3caa410, 0x4b5e60b1,
+ 0xcbae77ae, 0x91cf48ce, 0x113f5fd1, 0x250d360e, 0xa5fd2111,
+ 0xff9c1e71, 0x7f6c096e, 0xf5c49172, 0x7534866d, 0x2f55b90d,
+ 0xafa5ae12, 0x9b97c7cd, 0x1b67d0d2, 0x4106efb2, 0xc1f6f8ad,
+ 0x29623c0c, 0xa9922b13, 0xf3f31473, 0x7303036c, 0x47316ab3,
+ 0xc7c17dac, 0x9da042cc, 0x1d5055d3, 0xa700e96a, 0x27f0fe75,
+ 0x7d91c115, 0xfd61d60a, 0xc953bfd5, 0x49a3a8ca, 0x13c297aa,
+ 0x933280b5, 0x7ba64414, 0xfb56530b, 0xa1376c6b, 0x21c77b74,
+ 0x15f512ab, 0x950505b4, 0xcf643ad4, 0x4f942dcb, 0xc53cb5d7,
+ 0x45cca2c8, 0x1fad9da8, 0x9f5d8ab7, 0xab6fe368, 0x2b9ff477,
+ 0x71fecb17, 0xf10edc08, 0x199a18a9, 0x996a0fb6, 0xc30b30d6,
+ 0x43fb27c9, 0x77c94e16, 0xf7395909, 0xad586669, 0x2da87176,
+ 0x63785010, 0xe388470f, 0xb9e9786f, 0x39196f70, 0x0d2b06af,
+ 0x8ddb11b0, 0xd7ba2ed0, 0x574a39cf, 0xbfdefd6e, 0x3f2eea71,
+ 0x654fd511, 0xe5bfc20e, 0xd18dabd1, 0x517dbcce, 0x0b1c83ae,
+ 0x8bec94b1, 0x01440cad, 0x81b41bb2, 0xdbd524d2, 0x5b2533cd,
+ 0x6f175a12, 0xefe74d0d, 0xb586726d, 0x35766572, 0xdde2a1d3,
+ 0x5d12b6cc, 0x077389ac, 0x87839eb3, 0xb3b1f76c, 0x3341e073,
+ 0x6920df13, 0xe9d0c80c, 0xf4809ddf, 0x74708ac0, 0x2e11b5a0,
+ 0xaee1a2bf, 0x9ad3cb60, 0x1a23dc7f, 0x4042e31f, 0xc0b2f400,
+ 0x282630a1, 0xa8d627be, 0xf2b718de, 0x72470fc1, 0x4675661e,
+ 0xc6857101, 0x9ce44e61, 0x1c14597e, 0x96bcc162, 0x164cd67d,
+ 0x4c2de91d, 0xccddfe02, 0xf8ef97dd, 0x781f80c2, 0x227ebfa2,
+ 0xa28ea8bd, 0x4a1a6c1c, 0xcaea7b03, 0x908b4463, 0x107b537c,
+ 0x24493aa3, 0xa4b92dbc, 0xfed812dc, 0x7e2805c3, 0x30f824a5,
+ 0xb00833ba, 0xea690cda, 0x6a991bc5, 0x5eab721a, 0xde5b6505,
+ 0x843a5a65, 0x04ca4d7a, 0xec5e89db, 0x6cae9ec4, 0x36cfa1a4,
+ 0xb63fb6bb, 0x820ddf64, 0x02fdc87b, 0x589cf71b, 0xd86ce004,
+ 0x52c47818, 0xd2346f07, 0x88555067, 0x08a54778, 0x3c972ea7,
+ 0xbc6739b8, 0xe60606d8, 0x66f611c7, 0x8e62d566, 0x0e92c279,
+ 0x54f3fd19, 0xd403ea06, 0xe03183d9, 0x60c194c6, 0x3aa0aba6,
+ 0xba50bcb9},
+ {0x00000000, 0x9570d495, 0xf190af6b, 0x64e07bfe, 0x38505897,
+ 0xad208c02, 0xc9c0f7fc, 0x5cb02369, 0x70a0b12e, 0xe5d065bb,
+ 0x81301e45, 0x1440cad0, 0x48f0e9b9, 0xdd803d2c, 0xb96046d2,
+ 0x2c109247, 0xe141625c, 0x7431b6c9, 0x10d1cd37, 0x85a119a2,
+ 0xd9113acb, 0x4c61ee5e, 0x288195a0, 0xbdf14135, 0x91e1d372,
+ 0x049107e7, 0x60717c19, 0xf501a88c, 0xa9b18be5, 0x3cc15f70,
+ 0x5821248e, 0xcd51f01b, 0x19f3c2f9, 0x8c83166c, 0xe8636d92,
+ 0x7d13b907, 0x21a39a6e, 0xb4d34efb, 0xd0333505, 0x4543e190,
+ 0x695373d7, 0xfc23a742, 0x98c3dcbc, 0x0db30829, 0x51032b40,
+ 0xc473ffd5, 0xa093842b, 0x35e350be, 0xf8b2a0a5, 0x6dc27430,
+ 0x09220fce, 0x9c52db5b, 0xc0e2f832, 0x55922ca7, 0x31725759,
+ 0xa40283cc, 0x8812118b, 0x1d62c51e, 0x7982bee0, 0xecf26a75,
+ 0xb042491c, 0x25329d89, 0x41d2e677, 0xd4a232e2, 0x33e785f2,
+ 0xa6975167, 0xc2772a99, 0x5707fe0c, 0x0bb7dd65, 0x9ec709f0,
+ 0xfa27720e, 0x6f57a69b, 0x434734dc, 0xd637e049, 0xb2d79bb7,
+ 0x27a74f22, 0x7b176c4b, 0xee67b8de, 0x8a87c320, 0x1ff717b5,
+ 0xd2a6e7ae, 0x47d6333b, 0x233648c5, 0xb6469c50, 0xeaf6bf39,
+ 0x7f866bac, 0x1b661052, 0x8e16c4c7, 0xa2065680, 0x37768215,
+ 0x5396f9eb, 0xc6e62d7e, 0x9a560e17, 0x0f26da82, 0x6bc6a17c,
+ 0xfeb675e9, 0x2a14470b, 0xbf64939e, 0xdb84e860, 0x4ef43cf5,
+ 0x12441f9c, 0x8734cb09, 0xe3d4b0f7, 0x76a46462, 0x5ab4f625,
+ 0xcfc422b0, 0xab24594e, 0x3e548ddb, 0x62e4aeb2, 0xf7947a27,
+ 0x937401d9, 0x0604d54c, 0xcb552557, 0x5e25f1c2, 0x3ac58a3c,
+ 0xafb55ea9, 0xf3057dc0, 0x6675a955, 0x0295d2ab, 0x97e5063e,
+ 0xbbf59479, 0x2e8540ec, 0x4a653b12, 0xdf15ef87, 0x83a5ccee,
+ 0x16d5187b, 0x72356385, 0xe745b710, 0x67cf0be4, 0xf2bfdf71,
+ 0x965fa48f, 0x032f701a, 0x5f9f5373, 0xcaef87e6, 0xae0ffc18,
+ 0x3b7f288d, 0x176fbaca, 0x821f6e5f, 0xe6ff15a1, 0x738fc134,
+ 0x2f3fe25d, 0xba4f36c8, 0xdeaf4d36, 0x4bdf99a3, 0x868e69b8,
+ 0x13febd2d, 0x771ec6d3, 0xe26e1246, 0xbede312f, 0x2baee5ba,
+ 0x4f4e9e44, 0xda3e4ad1, 0xf62ed896, 0x635e0c03, 0x07be77fd,
+ 0x92cea368, 0xce7e8001, 0x5b0e5494, 0x3fee2f6a, 0xaa9efbff,
+ 0x7e3cc91d, 0xeb4c1d88, 0x8fac6676, 0x1adcb2e3, 0x466c918a,
+ 0xd31c451f, 0xb7fc3ee1, 0x228cea74, 0x0e9c7833, 0x9becaca6,
+ 0xff0cd758, 0x6a7c03cd, 0x36cc20a4, 0xa3bcf431, 0xc75c8fcf,
+ 0x522c5b5a, 0x9f7dab41, 0x0a0d7fd4, 0x6eed042a, 0xfb9dd0bf,
+ 0xa72df3d6, 0x325d2743, 0x56bd5cbd, 0xc3cd8828, 0xefdd1a6f,
+ 0x7aadcefa, 0x1e4db504, 0x8b3d6191, 0xd78d42f8, 0x42fd966d,
+ 0x261ded93, 0xb36d3906, 0x54288e16, 0xc1585a83, 0xa5b8217d,
+ 0x30c8f5e8, 0x6c78d681, 0xf9080214, 0x9de879ea, 0x0898ad7f,
+ 0x24883f38, 0xb1f8ebad, 0xd5189053, 0x406844c6, 0x1cd867af,
+ 0x89a8b33a, 0xed48c8c4, 0x78381c51, 0xb569ec4a, 0x201938df,
+ 0x44f94321, 0xd18997b4, 0x8d39b4dd, 0x18496048, 0x7ca91bb6,
+ 0xe9d9cf23, 0xc5c95d64, 0x50b989f1, 0x3459f20f, 0xa129269a,
+ 0xfd9905f3, 0x68e9d166, 0x0c09aa98, 0x99797e0d, 0x4ddb4cef,
+ 0xd8ab987a, 0xbc4be384, 0x293b3711, 0x758b1478, 0xe0fbc0ed,
+ 0x841bbb13, 0x116b6f86, 0x3d7bfdc1, 0xa80b2954, 0xcceb52aa,
+ 0x599b863f, 0x052ba556, 0x905b71c3, 0xf4bb0a3d, 0x61cbdea8,
+ 0xac9a2eb3, 0x39eafa26, 0x5d0a81d8, 0xc87a554d, 0x94ca7624,
+ 0x01baa2b1, 0x655ad94f, 0xf02a0dda, 0xdc3a9f9d, 0x494a4b08,
+ 0x2daa30f6, 0xb8dae463, 0xe46ac70a, 0x711a139f, 0x15fa6861,
+ 0x808abcf4},
+ {0x00000000, 0xcf9e17c8, 0x444d29d1, 0x8bd33e19, 0x889a53a2,
+ 0x4704446a, 0xccd77a73, 0x03496dbb, 0xca45a105, 0x05dbb6cd,
+ 0x8e0888d4, 0x41969f1c, 0x42dff2a7, 0x8d41e56f, 0x0692db76,
+ 0xc90cccbe, 0x4ffa444b, 0x80645383, 0x0bb76d9a, 0xc4297a52,
+ 0xc76017e9, 0x08fe0021, 0x832d3e38, 0x4cb329f0, 0x85bfe54e,
+ 0x4a21f286, 0xc1f2cc9f, 0x0e6cdb57, 0x0d25b6ec, 0xc2bba124,
+ 0x49689f3d, 0x86f688f5, 0x9ff48896, 0x506a9f5e, 0xdbb9a147,
+ 0x1427b68f, 0x176edb34, 0xd8f0ccfc, 0x5323f2e5, 0x9cbde52d,
+ 0x55b12993, 0x9a2f3e5b, 0x11fc0042, 0xde62178a, 0xdd2b7a31,
+ 0x12b56df9, 0x996653e0, 0x56f84428, 0xd00eccdd, 0x1f90db15,
+ 0x9443e50c, 0x5bddf2c4, 0x58949f7f, 0x970a88b7, 0x1cd9b6ae,
+ 0xd347a166, 0x1a4b6dd8, 0xd5d57a10, 0x5e064409, 0x919853c1,
+ 0x92d13e7a, 0x5d4f29b2, 0xd69c17ab, 0x19020063, 0xe498176d,
+ 0x2b0600a5, 0xa0d53ebc, 0x6f4b2974, 0x6c0244cf, 0xa39c5307,
+ 0x284f6d1e, 0xe7d17ad6, 0x2eddb668, 0xe143a1a0, 0x6a909fb9,
+ 0xa50e8871, 0xa647e5ca, 0x69d9f202, 0xe20acc1b, 0x2d94dbd3,
+ 0xab625326, 0x64fc44ee, 0xef2f7af7, 0x20b16d3f, 0x23f80084,
+ 0xec66174c, 0x67b52955, 0xa82b3e9d, 0x6127f223, 0xaeb9e5eb,
+ 0x256adbf2, 0xeaf4cc3a, 0xe9bda181, 0x2623b649, 0xadf08850,
+ 0x626e9f98, 0x7b6c9ffb, 0xb4f28833, 0x3f21b62a, 0xf0bfa1e2,
+ 0xf3f6cc59, 0x3c68db91, 0xb7bbe588, 0x7825f240, 0xb1293efe,
+ 0x7eb72936, 0xf564172f, 0x3afa00e7, 0x39b36d5c, 0xf62d7a94,
+ 0x7dfe448d, 0xb2605345, 0x3496dbb0, 0xfb08cc78, 0x70dbf261,
+ 0xbf45e5a9, 0xbc0c8812, 0x73929fda, 0xf841a1c3, 0x37dfb60b,
+ 0xfed37ab5, 0x314d6d7d, 0xba9e5364, 0x750044ac, 0x76492917,
+ 0xb9d73edf, 0x320400c6, 0xfd9a170e, 0x1241289b, 0xdddf3f53,
+ 0x560c014a, 0x99921682, 0x9adb7b39, 0x55456cf1, 0xde9652e8,
+ 0x11084520, 0xd804899e, 0x179a9e56, 0x9c49a04f, 0x53d7b787,
+ 0x509eda3c, 0x9f00cdf4, 0x14d3f3ed, 0xdb4de425, 0x5dbb6cd0,
+ 0x92257b18, 0x19f64501, 0xd66852c9, 0xd5213f72, 0x1abf28ba,
+ 0x916c16a3, 0x5ef2016b, 0x97fecdd5, 0x5860da1d, 0xd3b3e404,
+ 0x1c2df3cc, 0x1f649e77, 0xd0fa89bf, 0x5b29b7a6, 0x94b7a06e,
+ 0x8db5a00d, 0x422bb7c5, 0xc9f889dc, 0x06669e14, 0x052ff3af,
+ 0xcab1e467, 0x4162da7e, 0x8efccdb6, 0x47f00108, 0x886e16c0,
+ 0x03bd28d9, 0xcc233f11, 0xcf6a52aa, 0x00f44562, 0x8b277b7b,
+ 0x44b96cb3, 0xc24fe446, 0x0dd1f38e, 0x8602cd97, 0x499cda5f,
+ 0x4ad5b7e4, 0x854ba02c, 0x0e989e35, 0xc10689fd, 0x080a4543,
+ 0xc794528b, 0x4c476c92, 0x83d97b5a, 0x809016e1, 0x4f0e0129,
+ 0xc4dd3f30, 0x0b4328f8, 0xf6d93ff6, 0x3947283e, 0xb2941627,
+ 0x7d0a01ef, 0x7e436c54, 0xb1dd7b9c, 0x3a0e4585, 0xf590524d,
+ 0x3c9c9ef3, 0xf302893b, 0x78d1b722, 0xb74fa0ea, 0xb406cd51,
+ 0x7b98da99, 0xf04be480, 0x3fd5f348, 0xb9237bbd, 0x76bd6c75,
+ 0xfd6e526c, 0x32f045a4, 0x31b9281f, 0xfe273fd7, 0x75f401ce,
+ 0xba6a1606, 0x7366dab8, 0xbcf8cd70, 0x372bf369, 0xf8b5e4a1,
+ 0xfbfc891a, 0x34629ed2, 0xbfb1a0cb, 0x702fb703, 0x692db760,
+ 0xa6b3a0a8, 0x2d609eb1, 0xe2fe8979, 0xe1b7e4c2, 0x2e29f30a,
+ 0xa5facd13, 0x6a64dadb, 0xa3681665, 0x6cf601ad, 0xe7253fb4,
+ 0x28bb287c, 0x2bf245c7, 0xe46c520f, 0x6fbf6c16, 0xa0217bde,
+ 0x26d7f32b, 0xe949e4e3, 0x629adafa, 0xad04cd32, 0xae4da089,
+ 0x61d3b741, 0xea008958, 0x259e9e90, 0xec92522e, 0x230c45e6,
+ 0xa8df7bff, 0x67416c37, 0x6408018c, 0xab961644, 0x2045285d,
+ 0xefdb3f95},
+ {0x00000000, 0x24825136, 0x4904a26c, 0x6d86f35a, 0x920944d8,
+ 0xb68b15ee, 0xdb0de6b4, 0xff8fb782, 0xff638ff1, 0xdbe1dec7,
+ 0xb6672d9d, 0x92e57cab, 0x6d6acb29, 0x49e89a1f, 0x246e6945,
+ 0x00ec3873, 0x25b619a3, 0x01344895, 0x6cb2bbcf, 0x4830eaf9,
+ 0xb7bf5d7b, 0x933d0c4d, 0xfebbff17, 0xda39ae21, 0xdad59652,
+ 0xfe57c764, 0x93d1343e, 0xb7536508, 0x48dcd28a, 0x6c5e83bc,
+ 0x01d870e6, 0x255a21d0, 0x4b6c3346, 0x6fee6270, 0x0268912a,
+ 0x26eac01c, 0xd965779e, 0xfde726a8, 0x9061d5f2, 0xb4e384c4,
+ 0xb40fbcb7, 0x908ded81, 0xfd0b1edb, 0xd9894fed, 0x2606f86f,
+ 0x0284a959, 0x6f025a03, 0x4b800b35, 0x6eda2ae5, 0x4a587bd3,
+ 0x27de8889, 0x035cd9bf, 0xfcd36e3d, 0xd8513f0b, 0xb5d7cc51,
+ 0x91559d67, 0x91b9a514, 0xb53bf422, 0xd8bd0778, 0xfc3f564e,
+ 0x03b0e1cc, 0x2732b0fa, 0x4ab443a0, 0x6e361296, 0x96d8668c,
+ 0xb25a37ba, 0xdfdcc4e0, 0xfb5e95d6, 0x04d12254, 0x20537362,
+ 0x4dd58038, 0x6957d10e, 0x69bbe97d, 0x4d39b84b, 0x20bf4b11,
+ 0x043d1a27, 0xfbb2ada5, 0xdf30fc93, 0xb2b60fc9, 0x96345eff,
+ 0xb36e7f2f, 0x97ec2e19, 0xfa6add43, 0xdee88c75, 0x21673bf7,
+ 0x05e56ac1, 0x6863999b, 0x4ce1c8ad, 0x4c0df0de, 0x688fa1e8,
+ 0x050952b2, 0x218b0384, 0xde04b406, 0xfa86e530, 0x9700166a,
+ 0xb382475c, 0xddb455ca, 0xf93604fc, 0x94b0f7a6, 0xb032a690,
+ 0x4fbd1112, 0x6b3f4024, 0x06b9b37e, 0x223be248, 0x22d7da3b,
+ 0x06558b0d, 0x6bd37857, 0x4f512961, 0xb0de9ee3, 0x945ccfd5,
+ 0xf9da3c8f, 0xdd586db9, 0xf8024c69, 0xdc801d5f, 0xb106ee05,
+ 0x9584bf33, 0x6a0b08b1, 0x4e895987, 0x230faadd, 0x078dfbeb,
+ 0x0761c398, 0x23e392ae, 0x4e6561f4, 0x6ae730c2, 0x95688740,
+ 0xb1ead676, 0xdc6c252c, 0xf8ee741a, 0xf6c1cb59, 0xd2439a6f,
+ 0xbfc56935, 0x9b473803, 0x64c88f81, 0x404adeb7, 0x2dcc2ded,
+ 0x094e7cdb, 0x09a244a8, 0x2d20159e, 0x40a6e6c4, 0x6424b7f2,
+ 0x9bab0070, 0xbf295146, 0xd2afa21c, 0xf62df32a, 0xd377d2fa,
+ 0xf7f583cc, 0x9a737096, 0xbef121a0, 0x417e9622, 0x65fcc714,
+ 0x087a344e, 0x2cf86578, 0x2c145d0b, 0x08960c3d, 0x6510ff67,
+ 0x4192ae51, 0xbe1d19d3, 0x9a9f48e5, 0xf719bbbf, 0xd39bea89,
+ 0xbdadf81f, 0x992fa929, 0xf4a95a73, 0xd02b0b45, 0x2fa4bcc7,
+ 0x0b26edf1, 0x66a01eab, 0x42224f9d, 0x42ce77ee, 0x664c26d8,
+ 0x0bcad582, 0x2f4884b4, 0xd0c73336, 0xf4456200, 0x99c3915a,
+ 0xbd41c06c, 0x981be1bc, 0xbc99b08a, 0xd11f43d0, 0xf59d12e6,
+ 0x0a12a564, 0x2e90f452, 0x43160708, 0x6794563e, 0x67786e4d,
+ 0x43fa3f7b, 0x2e7ccc21, 0x0afe9d17, 0xf5712a95, 0xd1f37ba3,
+ 0xbc7588f9, 0x98f7d9cf, 0x6019add5, 0x449bfce3, 0x291d0fb9,
+ 0x0d9f5e8f, 0xf210e90d, 0xd692b83b, 0xbb144b61, 0x9f961a57,
+ 0x9f7a2224, 0xbbf87312, 0xd67e8048, 0xf2fcd17e, 0x0d7366fc,
+ 0x29f137ca, 0x4477c490, 0x60f595a6, 0x45afb476, 0x612de540,
+ 0x0cab161a, 0x2829472c, 0xd7a6f0ae, 0xf324a198, 0x9ea252c2,
+ 0xba2003f4, 0xbacc3b87, 0x9e4e6ab1, 0xf3c899eb, 0xd74ac8dd,
+ 0x28c57f5f, 0x0c472e69, 0x61c1dd33, 0x45438c05, 0x2b759e93,
+ 0x0ff7cfa5, 0x62713cff, 0x46f36dc9, 0xb97cda4b, 0x9dfe8b7d,
+ 0xf0787827, 0xd4fa2911, 0xd4161162, 0xf0944054, 0x9d12b30e,
+ 0xb990e238, 0x461f55ba, 0x629d048c, 0x0f1bf7d6, 0x2b99a6e0,
+ 0x0ec38730, 0x2a41d606, 0x47c7255c, 0x6345746a, 0x9ccac3e8,
+ 0xb84892de, 0xd5ce6184, 0xf14c30b2, 0xf1a008c1, 0xd52259f7,
+ 0xb8a4aaad, 0x9c26fb9b, 0x63a94c19, 0x472b1d2f, 0x2aadee75,
+ 0x0e2fbf43},
+ {0x00000000, 0x36f290f3, 0x6de521e6, 0x5b17b115, 0xdbca43cc,
+ 0xed38d33f, 0xb62f622a, 0x80ddf2d9, 0x6ce581d9, 0x5a17112a,
+ 0x0100a03f, 0x37f230cc, 0xb72fc215, 0x81dd52e6, 0xdacae3f3,
+ 0xec387300, 0xd9cb03b2, 0xef399341, 0xb42e2254, 0x82dcb2a7,
+ 0x0201407e, 0x34f3d08d, 0x6fe46198, 0x5916f16b, 0xb52e826b,
+ 0x83dc1298, 0xd8cba38d, 0xee39337e, 0x6ee4c1a7, 0x58165154,
+ 0x0301e041, 0x35f370b2, 0x68e70125, 0x5e1591d6, 0x050220c3,
+ 0x33f0b030, 0xb32d42e9, 0x85dfd21a, 0xdec8630f, 0xe83af3fc,
+ 0x040280fc, 0x32f0100f, 0x69e7a11a, 0x5f1531e9, 0xdfc8c330,
+ 0xe93a53c3, 0xb22de2d6, 0x84df7225, 0xb12c0297, 0x87de9264,
+ 0xdcc92371, 0xea3bb382, 0x6ae6415b, 0x5c14d1a8, 0x070360bd,
+ 0x31f1f04e, 0xddc9834e, 0xeb3b13bd, 0xb02ca2a8, 0x86de325b,
+ 0x0603c082, 0x30f15071, 0x6be6e164, 0x5d147197, 0xd1ce024a,
+ 0xe73c92b9, 0xbc2b23ac, 0x8ad9b35f, 0x0a044186, 0x3cf6d175,
+ 0x67e16060, 0x5113f093, 0xbd2b8393, 0x8bd91360, 0xd0cea275,
+ 0xe63c3286, 0x66e1c05f, 0x501350ac, 0x0b04e1b9, 0x3df6714a,
+ 0x080501f8, 0x3ef7910b, 0x65e0201e, 0x5312b0ed, 0xd3cf4234,
+ 0xe53dd2c7, 0xbe2a63d2, 0x88d8f321, 0x64e08021, 0x521210d2,
+ 0x0905a1c7, 0x3ff73134, 0xbf2ac3ed, 0x89d8531e, 0xd2cfe20b,
+ 0xe43d72f8, 0xb929036f, 0x8fdb939c, 0xd4cc2289, 0xe23eb27a,
+ 0x62e340a3, 0x5411d050, 0x0f066145, 0x39f4f1b6, 0xd5cc82b6,
+ 0xe33e1245, 0xb829a350, 0x8edb33a3, 0x0e06c17a, 0x38f45189,
+ 0x63e3e09c, 0x5511706f, 0x60e200dd, 0x5610902e, 0x0d07213b,
+ 0x3bf5b1c8, 0xbb284311, 0x8ddad3e2, 0xd6cd62f7, 0xe03ff204,
+ 0x0c078104, 0x3af511f7, 0x61e2a0e2, 0x57103011, 0xd7cdc2c8,
+ 0xe13f523b, 0xba28e32e, 0x8cda73dd, 0x78ed02d5, 0x4e1f9226,
+ 0x15082333, 0x23fab3c0, 0xa3274119, 0x95d5d1ea, 0xcec260ff,
+ 0xf830f00c, 0x1408830c, 0x22fa13ff, 0x79eda2ea, 0x4f1f3219,
+ 0xcfc2c0c0, 0xf9305033, 0xa227e126, 0x94d571d5, 0xa1260167,
+ 0x97d49194, 0xccc32081, 0xfa31b072, 0x7aec42ab, 0x4c1ed258,
+ 0x1709634d, 0x21fbf3be, 0xcdc380be, 0xfb31104d, 0xa026a158,
+ 0x96d431ab, 0x1609c372, 0x20fb5381, 0x7bece294, 0x4d1e7267,
+ 0x100a03f0, 0x26f89303, 0x7def2216, 0x4b1db2e5, 0xcbc0403c,
+ 0xfd32d0cf, 0xa62561da, 0x90d7f129, 0x7cef8229, 0x4a1d12da,
+ 0x110aa3cf, 0x27f8333c, 0xa725c1e5, 0x91d75116, 0xcac0e003,
+ 0xfc3270f0, 0xc9c10042, 0xff3390b1, 0xa42421a4, 0x92d6b157,
+ 0x120b438e, 0x24f9d37d, 0x7fee6268, 0x491cf29b, 0xa524819b,
+ 0x93d61168, 0xc8c1a07d, 0xfe33308e, 0x7eeec257, 0x481c52a4,
+ 0x130be3b1, 0x25f97342, 0xa923009f, 0x9fd1906c, 0xc4c62179,
+ 0xf234b18a, 0x72e94353, 0x441bd3a0, 0x1f0c62b5, 0x29fef246,
+ 0xc5c68146, 0xf33411b5, 0xa823a0a0, 0x9ed13053, 0x1e0cc28a,
+ 0x28fe5279, 0x73e9e36c, 0x451b739f, 0x70e8032d, 0x461a93de,
+ 0x1d0d22cb, 0x2bffb238, 0xab2240e1, 0x9dd0d012, 0xc6c76107,
+ 0xf035f1f4, 0x1c0d82f4, 0x2aff1207, 0x71e8a312, 0x471a33e1,
+ 0xc7c7c138, 0xf13551cb, 0xaa22e0de, 0x9cd0702d, 0xc1c401ba,
+ 0xf7369149, 0xac21205c, 0x9ad3b0af, 0x1a0e4276, 0x2cfcd285,
+ 0x77eb6390, 0x4119f363, 0xad218063, 0x9bd31090, 0xc0c4a185,
+ 0xf6363176, 0x76ebc3af, 0x4019535c, 0x1b0ee249, 0x2dfc72ba,
+ 0x180f0208, 0x2efd92fb, 0x75ea23ee, 0x4318b31d, 0xc3c541c4,
+ 0xf537d137, 0xae206022, 0x98d2f0d1, 0x74ea83d1, 0x42181322,
+ 0x190fa237, 0x2ffd32c4, 0xaf20c01d, 0x99d250ee, 0xc2c5e1fb,
+ 0xf4377108}};
+
+local const z_word_t FAR crc_braid_big_table[][256] = {
+ {0x0000000000000000, 0xf390f23600000000, 0xe621e56d00000000,
+ 0x15b1175b00000000, 0xcc43cadb00000000, 0x3fd338ed00000000,
+ 0x2a622fb600000000, 0xd9f2dd8000000000, 0xd981e56c00000000,
+ 0x2a11175a00000000, 0x3fa0000100000000, 0xcc30f23700000000,
+ 0x15c22fb700000000, 0xe652dd8100000000, 0xf3e3cada00000000,
+ 0x007338ec00000000, 0xb203cbd900000000, 0x419339ef00000000,
+ 0x54222eb400000000, 0xa7b2dc8200000000, 0x7e40010200000000,
+ 0x8dd0f33400000000, 0x9861e46f00000000, 0x6bf1165900000000,
+ 0x6b822eb500000000, 0x9812dc8300000000, 0x8da3cbd800000000,
+ 0x7e3339ee00000000, 0xa7c1e46e00000000, 0x5451165800000000,
+ 0x41e0010300000000, 0xb270f33500000000, 0x2501e76800000000,
+ 0xd691155e00000000, 0xc320020500000000, 0x30b0f03300000000,
+ 0xe9422db300000000, 0x1ad2df8500000000, 0x0f63c8de00000000,
+ 0xfcf33ae800000000, 0xfc80020400000000, 0x0f10f03200000000,
+ 0x1aa1e76900000000, 0xe931155f00000000, 0x30c3c8df00000000,
+ 0xc3533ae900000000, 0xd6e22db200000000, 0x2572df8400000000,
+ 0x97022cb100000000, 0x6492de8700000000, 0x7123c9dc00000000,
+ 0x82b33bea00000000, 0x5b41e66a00000000, 0xa8d1145c00000000,
+ 0xbd60030700000000, 0x4ef0f13100000000, 0x4e83c9dd00000000,
+ 0xbd133beb00000000, 0xa8a22cb000000000, 0x5b32de8600000000,
+ 0x82c0030600000000, 0x7150f13000000000, 0x64e1e66b00000000,
+ 0x9771145d00000000, 0x4a02ced100000000, 0xb9923ce700000000,
+ 0xac232bbc00000000, 0x5fb3d98a00000000, 0x8641040a00000000,
+ 0x75d1f63c00000000, 0x6060e16700000000, 0x93f0135100000000,
+ 0x93832bbd00000000, 0x6013d98b00000000, 0x75a2ced000000000,
+ 0x86323ce600000000, 0x5fc0e16600000000, 0xac50135000000000,
+ 0xb9e1040b00000000, 0x4a71f63d00000000, 0xf801050800000000,
+ 0x0b91f73e00000000, 0x1e20e06500000000, 0xedb0125300000000,
+ 0x3442cfd300000000, 0xc7d23de500000000, 0xd2632abe00000000,
+ 0x21f3d88800000000, 0x2180e06400000000, 0xd210125200000000,
+ 0xc7a1050900000000, 0x3431f73f00000000, 0xedc32abf00000000,
+ 0x1e53d88900000000, 0x0be2cfd200000000, 0xf8723de400000000,
+ 0x6f0329b900000000, 0x9c93db8f00000000, 0x8922ccd400000000,
+ 0x7ab23ee200000000, 0xa340e36200000000, 0x50d0115400000000,
+ 0x4561060f00000000, 0xb6f1f43900000000, 0xb682ccd500000000,
+ 0x45123ee300000000, 0x50a329b800000000, 0xa333db8e00000000,
+ 0x7ac1060e00000000, 0x8951f43800000000, 0x9ce0e36300000000,
+ 0x6f70115500000000, 0xdd00e26000000000, 0x2e90105600000000,
+ 0x3b21070d00000000, 0xc8b1f53b00000000, 0x114328bb00000000,
+ 0xe2d3da8d00000000, 0xf762cdd600000000, 0x04f23fe000000000,
+ 0x0481070c00000000, 0xf711f53a00000000, 0xe2a0e26100000000,
+ 0x1130105700000000, 0xc8c2cdd700000000, 0x3b523fe100000000,
+ 0x2ee328ba00000000, 0xdd73da8c00000000, 0xd502ed7800000000,
+ 0x26921f4e00000000, 0x3323081500000000, 0xc0b3fa2300000000,
+ 0x194127a300000000, 0xead1d59500000000, 0xff60c2ce00000000,
+ 0x0cf030f800000000, 0x0c83081400000000, 0xff13fa2200000000,
+ 0xeaa2ed7900000000, 0x19321f4f00000000, 0xc0c0c2cf00000000,
+ 0x335030f900000000, 0x26e127a200000000, 0xd571d59400000000,
+ 0x670126a100000000, 0x9491d49700000000, 0x8120c3cc00000000,
+ 0x72b031fa00000000, 0xab42ec7a00000000, 0x58d21e4c00000000,
+ 0x4d63091700000000, 0xbef3fb2100000000, 0xbe80c3cd00000000,
+ 0x4d1031fb00000000, 0x58a126a000000000, 0xab31d49600000000,
+ 0x72c3091600000000, 0x8153fb2000000000, 0x94e2ec7b00000000,
+ 0x67721e4d00000000, 0xf0030a1000000000, 0x0393f82600000000,
+ 0x1622ef7d00000000, 0xe5b21d4b00000000, 0x3c40c0cb00000000,
+ 0xcfd032fd00000000, 0xda6125a600000000, 0x29f1d79000000000,
+ 0x2982ef7c00000000, 0xda121d4a00000000, 0xcfa30a1100000000,
+ 0x3c33f82700000000, 0xe5c125a700000000, 0x1651d79100000000,
+ 0x03e0c0ca00000000, 0xf07032fc00000000, 0x4200c1c900000000,
+ 0xb19033ff00000000, 0xa42124a400000000, 0x57b1d69200000000,
+ 0x8e430b1200000000, 0x7dd3f92400000000, 0x6862ee7f00000000,
+ 0x9bf21c4900000000, 0x9b8124a500000000, 0x6811d69300000000,
+ 0x7da0c1c800000000, 0x8e3033fe00000000, 0x57c2ee7e00000000,
+ 0xa4521c4800000000, 0xb1e30b1300000000, 0x4273f92500000000,
+ 0x9f0023a900000000, 0x6c90d19f00000000, 0x7921c6c400000000,
+ 0x8ab134f200000000, 0x5343e97200000000, 0xa0d31b4400000000,
+ 0xb5620c1f00000000, 0x46f2fe2900000000, 0x4681c6c500000000,
+ 0xb51134f300000000, 0xa0a023a800000000, 0x5330d19e00000000,
+ 0x8ac20c1e00000000, 0x7952fe2800000000, 0x6ce3e97300000000,
+ 0x9f731b4500000000, 0x2d03e87000000000, 0xde931a4600000000,
+ 0xcb220d1d00000000, 0x38b2ff2b00000000, 0xe14022ab00000000,
+ 0x12d0d09d00000000, 0x0761c7c600000000, 0xf4f135f000000000,
+ 0xf4820d1c00000000, 0x0712ff2a00000000, 0x12a3e87100000000,
+ 0xe1331a4700000000, 0x38c1c7c700000000, 0xcb5135f100000000,
+ 0xdee022aa00000000, 0x2d70d09c00000000, 0xba01c4c100000000,
+ 0x499136f700000000, 0x5c2021ac00000000, 0xafb0d39a00000000,
+ 0x76420e1a00000000, 0x85d2fc2c00000000, 0x9063eb7700000000,
+ 0x63f3194100000000, 0x638021ad00000000, 0x9010d39b00000000,
+ 0x85a1c4c000000000, 0x763136f600000000, 0xafc3eb7600000000,
+ 0x5c53194000000000, 0x49e20e1b00000000, 0xba72fc2d00000000,
+ 0x08020f1800000000, 0xfb92fd2e00000000, 0xee23ea7500000000,
+ 0x1db3184300000000, 0xc441c5c300000000, 0x37d137f500000000,
+ 0x226020ae00000000, 0xd1f0d29800000000, 0xd183ea7400000000,
+ 0x2213184200000000, 0x37a20f1900000000, 0xc432fd2f00000000,
+ 0x1dc020af00000000, 0xee50d29900000000, 0xfbe1c5c200000000,
+ 0x087137f400000000},
+ {0x0000000000000000, 0x3651822400000000, 0x6ca2044900000000,
+ 0x5af3866d00000000, 0xd844099200000000, 0xee158bb600000000,
+ 0xb4e60ddb00000000, 0x82b78fff00000000, 0xf18f63ff00000000,
+ 0xc7dee1db00000000, 0x9d2d67b600000000, 0xab7ce59200000000,
+ 0x29cb6a6d00000000, 0x1f9ae84900000000, 0x45696e2400000000,
+ 0x7338ec0000000000, 0xa319b62500000000, 0x9548340100000000,
+ 0xcfbbb26c00000000, 0xf9ea304800000000, 0x7b5dbfb700000000,
+ 0x4d0c3d9300000000, 0x17ffbbfe00000000, 0x21ae39da00000000,
+ 0x5296d5da00000000, 0x64c757fe00000000, 0x3e34d19300000000,
+ 0x086553b700000000, 0x8ad2dc4800000000, 0xbc835e6c00000000,
+ 0xe670d80100000000, 0xd0215a2500000000, 0x46336c4b00000000,
+ 0x7062ee6f00000000, 0x2a91680200000000, 0x1cc0ea2600000000,
+ 0x9e7765d900000000, 0xa826e7fd00000000, 0xf2d5619000000000,
+ 0xc484e3b400000000, 0xb7bc0fb400000000, 0x81ed8d9000000000,
+ 0xdb1e0bfd00000000, 0xed4f89d900000000, 0x6ff8062600000000,
+ 0x59a9840200000000, 0x035a026f00000000, 0x350b804b00000000,
+ 0xe52ada6e00000000, 0xd37b584a00000000, 0x8988de2700000000,
+ 0xbfd95c0300000000, 0x3d6ed3fc00000000, 0x0b3f51d800000000,
+ 0x51ccd7b500000000, 0x679d559100000000, 0x14a5b99100000000,
+ 0x22f43bb500000000, 0x7807bdd800000000, 0x4e563ffc00000000,
+ 0xcce1b00300000000, 0xfab0322700000000, 0xa043b44a00000000,
+ 0x9612366e00000000, 0x8c66d89600000000, 0xba375ab200000000,
+ 0xe0c4dcdf00000000, 0xd6955efb00000000, 0x5422d10400000000,
+ 0x6273532000000000, 0x3880d54d00000000, 0x0ed1576900000000,
+ 0x7de9bb6900000000, 0x4bb8394d00000000, 0x114bbf2000000000,
+ 0x271a3d0400000000, 0xa5adb2fb00000000, 0x93fc30df00000000,
+ 0xc90fb6b200000000, 0xff5e349600000000, 0x2f7f6eb300000000,
+ 0x192eec9700000000, 0x43dd6afa00000000, 0x758ce8de00000000,
+ 0xf73b672100000000, 0xc16ae50500000000, 0x9b99636800000000,
+ 0xadc8e14c00000000, 0xdef00d4c00000000, 0xe8a18f6800000000,
+ 0xb252090500000000, 0x84038b2100000000, 0x06b404de00000000,
+ 0x30e586fa00000000, 0x6a16009700000000, 0x5c4782b300000000,
+ 0xca55b4dd00000000, 0xfc0436f900000000, 0xa6f7b09400000000,
+ 0x90a632b000000000, 0x1211bd4f00000000, 0x24403f6b00000000,
+ 0x7eb3b90600000000, 0x48e23b2200000000, 0x3bdad72200000000,
+ 0x0d8b550600000000, 0x5778d36b00000000, 0x6129514f00000000,
+ 0xe39edeb000000000, 0xd5cf5c9400000000, 0x8f3cdaf900000000,
+ 0xb96d58dd00000000, 0x694c02f800000000, 0x5f1d80dc00000000,
+ 0x05ee06b100000000, 0x33bf849500000000, 0xb1080b6a00000000,
+ 0x8759894e00000000, 0xddaa0f2300000000, 0xebfb8d0700000000,
+ 0x98c3610700000000, 0xae92e32300000000, 0xf461654e00000000,
+ 0xc230e76a00000000, 0x4087689500000000, 0x76d6eab100000000,
+ 0x2c256cdc00000000, 0x1a74eef800000000, 0x59cbc1f600000000,
+ 0x6f9a43d200000000, 0x3569c5bf00000000, 0x0338479b00000000,
+ 0x818fc86400000000, 0xb7de4a4000000000, 0xed2dcc2d00000000,
+ 0xdb7c4e0900000000, 0xa844a20900000000, 0x9e15202d00000000,
+ 0xc4e6a64000000000, 0xf2b7246400000000, 0x7000ab9b00000000,
+ 0x465129bf00000000, 0x1ca2afd200000000, 0x2af32df600000000,
+ 0xfad277d300000000, 0xcc83f5f700000000, 0x9670739a00000000,
+ 0xa021f1be00000000, 0x22967e4100000000, 0x14c7fc6500000000,
+ 0x4e347a0800000000, 0x7865f82c00000000, 0x0b5d142c00000000,
+ 0x3d0c960800000000, 0x67ff106500000000, 0x51ae924100000000,
+ 0xd3191dbe00000000, 0xe5489f9a00000000, 0xbfbb19f700000000,
+ 0x89ea9bd300000000, 0x1ff8adbd00000000, 0x29a92f9900000000,
+ 0x735aa9f400000000, 0x450b2bd000000000, 0xc7bca42f00000000,
+ 0xf1ed260b00000000, 0xab1ea06600000000, 0x9d4f224200000000,
+ 0xee77ce4200000000, 0xd8264c6600000000, 0x82d5ca0b00000000,
+ 0xb484482f00000000, 0x3633c7d000000000, 0x006245f400000000,
+ 0x5a91c39900000000, 0x6cc041bd00000000, 0xbce11b9800000000,
+ 0x8ab099bc00000000, 0xd0431fd100000000, 0xe6129df500000000,
+ 0x64a5120a00000000, 0x52f4902e00000000, 0x0807164300000000,
+ 0x3e56946700000000, 0x4d6e786700000000, 0x7b3ffa4300000000,
+ 0x21cc7c2e00000000, 0x179dfe0a00000000, 0x952a71f500000000,
+ 0xa37bf3d100000000, 0xf98875bc00000000, 0xcfd9f79800000000,
+ 0xd5ad196000000000, 0xe3fc9b4400000000, 0xb90f1d2900000000,
+ 0x8f5e9f0d00000000, 0x0de910f200000000, 0x3bb892d600000000,
+ 0x614b14bb00000000, 0x571a969f00000000, 0x24227a9f00000000,
+ 0x1273f8bb00000000, 0x48807ed600000000, 0x7ed1fcf200000000,
+ 0xfc66730d00000000, 0xca37f12900000000, 0x90c4774400000000,
+ 0xa695f56000000000, 0x76b4af4500000000, 0x40e52d6100000000,
+ 0x1a16ab0c00000000, 0x2c47292800000000, 0xaef0a6d700000000,
+ 0x98a124f300000000, 0xc252a29e00000000, 0xf40320ba00000000,
+ 0x873bccba00000000, 0xb16a4e9e00000000, 0xeb99c8f300000000,
+ 0xddc84ad700000000, 0x5f7fc52800000000, 0x692e470c00000000,
+ 0x33ddc16100000000, 0x058c434500000000, 0x939e752b00000000,
+ 0xa5cff70f00000000, 0xff3c716200000000, 0xc96df34600000000,
+ 0x4bda7cb900000000, 0x7d8bfe9d00000000, 0x277878f000000000,
+ 0x1129fad400000000, 0x621116d400000000, 0x544094f000000000,
+ 0x0eb3129d00000000, 0x38e290b900000000, 0xba551f4600000000,
+ 0x8c049d6200000000, 0xd6f71b0f00000000, 0xe0a6992b00000000,
+ 0x3087c30e00000000, 0x06d6412a00000000, 0x5c25c74700000000,
+ 0x6a74456300000000, 0xe8c3ca9c00000000, 0xde9248b800000000,
+ 0x8461ced500000000, 0xb2304cf100000000, 0xc108a0f100000000,
+ 0xf75922d500000000, 0xadaaa4b800000000, 0x9bfb269c00000000,
+ 0x194ca96300000000, 0x2f1d2b4700000000, 0x75eead2a00000000,
+ 0x43bf2f0e00000000},
+ {0x0000000000000000, 0xc8179ecf00000000, 0xd1294d4400000000,
+ 0x193ed38b00000000, 0xa2539a8800000000, 0x6a44044700000000,
+ 0x737ad7cc00000000, 0xbb6d490300000000, 0x05a145ca00000000,
+ 0xcdb6db0500000000, 0xd488088e00000000, 0x1c9f964100000000,
+ 0xa7f2df4200000000, 0x6fe5418d00000000, 0x76db920600000000,
+ 0xbecc0cc900000000, 0x4b44fa4f00000000, 0x8353648000000000,
+ 0x9a6db70b00000000, 0x527a29c400000000, 0xe91760c700000000,
+ 0x2100fe0800000000, 0x383e2d8300000000, 0xf029b34c00000000,
+ 0x4ee5bf8500000000, 0x86f2214a00000000, 0x9fccf2c100000000,
+ 0x57db6c0e00000000, 0xecb6250d00000000, 0x24a1bbc200000000,
+ 0x3d9f684900000000, 0xf588f68600000000, 0x9688f49f00000000,
+ 0x5e9f6a5000000000, 0x47a1b9db00000000, 0x8fb6271400000000,
+ 0x34db6e1700000000, 0xfcccf0d800000000, 0xe5f2235300000000,
+ 0x2de5bd9c00000000, 0x9329b15500000000, 0x5b3e2f9a00000000,
+ 0x4200fc1100000000, 0x8a1762de00000000, 0x317a2bdd00000000,
+ 0xf96db51200000000, 0xe053669900000000, 0x2844f85600000000,
+ 0xddcc0ed000000000, 0x15db901f00000000, 0x0ce5439400000000,
+ 0xc4f2dd5b00000000, 0x7f9f945800000000, 0xb7880a9700000000,
+ 0xaeb6d91c00000000, 0x66a147d300000000, 0xd86d4b1a00000000,
+ 0x107ad5d500000000, 0x0944065e00000000, 0xc153989100000000,
+ 0x7a3ed19200000000, 0xb2294f5d00000000, 0xab179cd600000000,
+ 0x6300021900000000, 0x6d1798e400000000, 0xa500062b00000000,
+ 0xbc3ed5a000000000, 0x74294b6f00000000, 0xcf44026c00000000,
+ 0x07539ca300000000, 0x1e6d4f2800000000, 0xd67ad1e700000000,
+ 0x68b6dd2e00000000, 0xa0a143e100000000, 0xb99f906a00000000,
+ 0x71880ea500000000, 0xcae547a600000000, 0x02f2d96900000000,
+ 0x1bcc0ae200000000, 0xd3db942d00000000, 0x265362ab00000000,
+ 0xee44fc6400000000, 0xf77a2fef00000000, 0x3f6db12000000000,
+ 0x8400f82300000000, 0x4c1766ec00000000, 0x5529b56700000000,
+ 0x9d3e2ba800000000, 0x23f2276100000000, 0xebe5b9ae00000000,
+ 0xf2db6a2500000000, 0x3accf4ea00000000, 0x81a1bde900000000,
+ 0x49b6232600000000, 0x5088f0ad00000000, 0x989f6e6200000000,
+ 0xfb9f6c7b00000000, 0x3388f2b400000000, 0x2ab6213f00000000,
+ 0xe2a1bff000000000, 0x59ccf6f300000000, 0x91db683c00000000,
+ 0x88e5bbb700000000, 0x40f2257800000000, 0xfe3e29b100000000,
+ 0x3629b77e00000000, 0x2f1764f500000000, 0xe700fa3a00000000,
+ 0x5c6db33900000000, 0x947a2df600000000, 0x8d44fe7d00000000,
+ 0x455360b200000000, 0xb0db963400000000, 0x78cc08fb00000000,
+ 0x61f2db7000000000, 0xa9e545bf00000000, 0x12880cbc00000000,
+ 0xda9f927300000000, 0xc3a141f800000000, 0x0bb6df3700000000,
+ 0xb57ad3fe00000000, 0x7d6d4d3100000000, 0x64539eba00000000,
+ 0xac44007500000000, 0x1729497600000000, 0xdf3ed7b900000000,
+ 0xc600043200000000, 0x0e179afd00000000, 0x9b28411200000000,
+ 0x533fdfdd00000000, 0x4a010c5600000000, 0x8216929900000000,
+ 0x397bdb9a00000000, 0xf16c455500000000, 0xe85296de00000000,
+ 0x2045081100000000, 0x9e8904d800000000, 0x569e9a1700000000,
+ 0x4fa0499c00000000, 0x87b7d75300000000, 0x3cda9e5000000000,
+ 0xf4cd009f00000000, 0xedf3d31400000000, 0x25e44ddb00000000,
+ 0xd06cbb5d00000000, 0x187b259200000000, 0x0145f61900000000,
+ 0xc95268d600000000, 0x723f21d500000000, 0xba28bf1a00000000,
+ 0xa3166c9100000000, 0x6b01f25e00000000, 0xd5cdfe9700000000,
+ 0x1dda605800000000, 0x04e4b3d300000000, 0xccf32d1c00000000,
+ 0x779e641f00000000, 0xbf89fad000000000, 0xa6b7295b00000000,
+ 0x6ea0b79400000000, 0x0da0b58d00000000, 0xc5b72b4200000000,
+ 0xdc89f8c900000000, 0x149e660600000000, 0xaff32f0500000000,
+ 0x67e4b1ca00000000, 0x7eda624100000000, 0xb6cdfc8e00000000,
+ 0x0801f04700000000, 0xc0166e8800000000, 0xd928bd0300000000,
+ 0x113f23cc00000000, 0xaa526acf00000000, 0x6245f40000000000,
+ 0x7b7b278b00000000, 0xb36cb94400000000, 0x46e44fc200000000,
+ 0x8ef3d10d00000000, 0x97cd028600000000, 0x5fda9c4900000000,
+ 0xe4b7d54a00000000, 0x2ca04b8500000000, 0x359e980e00000000,
+ 0xfd8906c100000000, 0x43450a0800000000, 0x8b5294c700000000,
+ 0x926c474c00000000, 0x5a7bd98300000000, 0xe116908000000000,
+ 0x29010e4f00000000, 0x303fddc400000000, 0xf828430b00000000,
+ 0xf63fd9f600000000, 0x3e28473900000000, 0x271694b200000000,
+ 0xef010a7d00000000, 0x546c437e00000000, 0x9c7bddb100000000,
+ 0x85450e3a00000000, 0x4d5290f500000000, 0xf39e9c3c00000000,
+ 0x3b8902f300000000, 0x22b7d17800000000, 0xeaa04fb700000000,
+ 0x51cd06b400000000, 0x99da987b00000000, 0x80e44bf000000000,
+ 0x48f3d53f00000000, 0xbd7b23b900000000, 0x756cbd7600000000,
+ 0x6c526efd00000000, 0xa445f03200000000, 0x1f28b93100000000,
+ 0xd73f27fe00000000, 0xce01f47500000000, 0x06166aba00000000,
+ 0xb8da667300000000, 0x70cdf8bc00000000, 0x69f32b3700000000,
+ 0xa1e4b5f800000000, 0x1a89fcfb00000000, 0xd29e623400000000,
+ 0xcba0b1bf00000000, 0x03b72f7000000000, 0x60b72d6900000000,
+ 0xa8a0b3a600000000, 0xb19e602d00000000, 0x7989fee200000000,
+ 0xc2e4b7e100000000, 0x0af3292e00000000, 0x13cdfaa500000000,
+ 0xdbda646a00000000, 0x651668a300000000, 0xad01f66c00000000,
+ 0xb43f25e700000000, 0x7c28bb2800000000, 0xc745f22b00000000,
+ 0x0f526ce400000000, 0x166cbf6f00000000, 0xde7b21a000000000,
+ 0x2bf3d72600000000, 0xe3e449e900000000, 0xfada9a6200000000,
+ 0x32cd04ad00000000, 0x89a04dae00000000, 0x41b7d36100000000,
+ 0x588900ea00000000, 0x909e9e2500000000, 0x2e5292ec00000000,
+ 0xe6450c2300000000, 0xff7bdfa800000000, 0x376c416700000000,
+ 0x8c01086400000000, 0x441696ab00000000, 0x5d28452000000000,
+ 0x953fdbef00000000},
+ {0x0000000000000000, 0x95d4709500000000, 0x6baf90f100000000,
+ 0xfe7be06400000000, 0x9758503800000000, 0x028c20ad00000000,
+ 0xfcf7c0c900000000, 0x6923b05c00000000, 0x2eb1a07000000000,
+ 0xbb65d0e500000000, 0x451e308100000000, 0xd0ca401400000000,
+ 0xb9e9f04800000000, 0x2c3d80dd00000000, 0xd24660b900000000,
+ 0x4792102c00000000, 0x5c6241e100000000, 0xc9b6317400000000,
+ 0x37cdd11000000000, 0xa219a18500000000, 0xcb3a11d900000000,
+ 0x5eee614c00000000, 0xa095812800000000, 0x3541f1bd00000000,
+ 0x72d3e19100000000, 0xe707910400000000, 0x197c716000000000,
+ 0x8ca801f500000000, 0xe58bb1a900000000, 0x705fc13c00000000,
+ 0x8e24215800000000, 0x1bf051cd00000000, 0xf9c2f31900000000,
+ 0x6c16838c00000000, 0x926d63e800000000, 0x07b9137d00000000,
+ 0x6e9aa32100000000, 0xfb4ed3b400000000, 0x053533d000000000,
+ 0x90e1434500000000, 0xd773536900000000, 0x42a723fc00000000,
+ 0xbcdcc39800000000, 0x2908b30d00000000, 0x402b035100000000,
+ 0xd5ff73c400000000, 0x2b8493a000000000, 0xbe50e33500000000,
+ 0xa5a0b2f800000000, 0x3074c26d00000000, 0xce0f220900000000,
+ 0x5bdb529c00000000, 0x32f8e2c000000000, 0xa72c925500000000,
+ 0x5957723100000000, 0xcc8302a400000000, 0x8b11128800000000,
+ 0x1ec5621d00000000, 0xe0be827900000000, 0x756af2ec00000000,
+ 0x1c4942b000000000, 0x899d322500000000, 0x77e6d24100000000,
+ 0xe232a2d400000000, 0xf285e73300000000, 0x675197a600000000,
+ 0x992a77c200000000, 0x0cfe075700000000, 0x65ddb70b00000000,
+ 0xf009c79e00000000, 0x0e7227fa00000000, 0x9ba6576f00000000,
+ 0xdc34474300000000, 0x49e037d600000000, 0xb79bd7b200000000,
+ 0x224fa72700000000, 0x4b6c177b00000000, 0xdeb867ee00000000,
+ 0x20c3878a00000000, 0xb517f71f00000000, 0xaee7a6d200000000,
+ 0x3b33d64700000000, 0xc548362300000000, 0x509c46b600000000,
+ 0x39bff6ea00000000, 0xac6b867f00000000, 0x5210661b00000000,
+ 0xc7c4168e00000000, 0x805606a200000000, 0x1582763700000000,
+ 0xebf9965300000000, 0x7e2de6c600000000, 0x170e569a00000000,
+ 0x82da260f00000000, 0x7ca1c66b00000000, 0xe975b6fe00000000,
+ 0x0b47142a00000000, 0x9e9364bf00000000, 0x60e884db00000000,
+ 0xf53cf44e00000000, 0x9c1f441200000000, 0x09cb348700000000,
+ 0xf7b0d4e300000000, 0x6264a47600000000, 0x25f6b45a00000000,
+ 0xb022c4cf00000000, 0x4e5924ab00000000, 0xdb8d543e00000000,
+ 0xb2aee46200000000, 0x277a94f700000000, 0xd901749300000000,
+ 0x4cd5040600000000, 0x572555cb00000000, 0xc2f1255e00000000,
+ 0x3c8ac53a00000000, 0xa95eb5af00000000, 0xc07d05f300000000,
+ 0x55a9756600000000, 0xabd2950200000000, 0x3e06e59700000000,
+ 0x7994f5bb00000000, 0xec40852e00000000, 0x123b654a00000000,
+ 0x87ef15df00000000, 0xeecca58300000000, 0x7b18d51600000000,
+ 0x8563357200000000, 0x10b745e700000000, 0xe40bcf6700000000,
+ 0x71dfbff200000000, 0x8fa45f9600000000, 0x1a702f0300000000,
+ 0x73539f5f00000000, 0xe687efca00000000, 0x18fc0fae00000000,
+ 0x8d287f3b00000000, 0xcaba6f1700000000, 0x5f6e1f8200000000,
+ 0xa115ffe600000000, 0x34c18f7300000000, 0x5de23f2f00000000,
+ 0xc8364fba00000000, 0x364dafde00000000, 0xa399df4b00000000,
+ 0xb8698e8600000000, 0x2dbdfe1300000000, 0xd3c61e7700000000,
+ 0x46126ee200000000, 0x2f31debe00000000, 0xbae5ae2b00000000,
+ 0x449e4e4f00000000, 0xd14a3eda00000000, 0x96d82ef600000000,
+ 0x030c5e6300000000, 0xfd77be0700000000, 0x68a3ce9200000000,
+ 0x01807ece00000000, 0x94540e5b00000000, 0x6a2fee3f00000000,
+ 0xfffb9eaa00000000, 0x1dc93c7e00000000, 0x881d4ceb00000000,
+ 0x7666ac8f00000000, 0xe3b2dc1a00000000, 0x8a916c4600000000,
+ 0x1f451cd300000000, 0xe13efcb700000000, 0x74ea8c2200000000,
+ 0x33789c0e00000000, 0xa6acec9b00000000, 0x58d70cff00000000,
+ 0xcd037c6a00000000, 0xa420cc3600000000, 0x31f4bca300000000,
+ 0xcf8f5cc700000000, 0x5a5b2c5200000000, 0x41ab7d9f00000000,
+ 0xd47f0d0a00000000, 0x2a04ed6e00000000, 0xbfd09dfb00000000,
+ 0xd6f32da700000000, 0x43275d3200000000, 0xbd5cbd5600000000,
+ 0x2888cdc300000000, 0x6f1addef00000000, 0xfacead7a00000000,
+ 0x04b54d1e00000000, 0x91613d8b00000000, 0xf8428dd700000000,
+ 0x6d96fd4200000000, 0x93ed1d2600000000, 0x06396db300000000,
+ 0x168e285400000000, 0x835a58c100000000, 0x7d21b8a500000000,
+ 0xe8f5c83000000000, 0x81d6786c00000000, 0x140208f900000000,
+ 0xea79e89d00000000, 0x7fad980800000000, 0x383f882400000000,
+ 0xadebf8b100000000, 0x539018d500000000, 0xc644684000000000,
+ 0xaf67d81c00000000, 0x3ab3a88900000000, 0xc4c848ed00000000,
+ 0x511c387800000000, 0x4aec69b500000000, 0xdf38192000000000,
+ 0x2143f94400000000, 0xb49789d100000000, 0xddb4398d00000000,
+ 0x4860491800000000, 0xb61ba97c00000000, 0x23cfd9e900000000,
+ 0x645dc9c500000000, 0xf189b95000000000, 0x0ff2593400000000,
+ 0x9a2629a100000000, 0xf30599fd00000000, 0x66d1e96800000000,
+ 0x98aa090c00000000, 0x0d7e799900000000, 0xef4cdb4d00000000,
+ 0x7a98abd800000000, 0x84e34bbc00000000, 0x11373b2900000000,
+ 0x78148b7500000000, 0xedc0fbe000000000, 0x13bb1b8400000000,
+ 0x866f6b1100000000, 0xc1fd7b3d00000000, 0x54290ba800000000,
+ 0xaa52ebcc00000000, 0x3f869b5900000000, 0x56a52b0500000000,
+ 0xc3715b9000000000, 0x3d0abbf400000000, 0xa8decb6100000000,
+ 0xb32e9aac00000000, 0x26faea3900000000, 0xd8810a5d00000000,
+ 0x4d557ac800000000, 0x2476ca9400000000, 0xb1a2ba0100000000,
+ 0x4fd95a6500000000, 0xda0d2af000000000, 0x9d9f3adc00000000,
+ 0x084b4a4900000000, 0xf630aa2d00000000, 0x63e4dab800000000,
+ 0x0ac76ae400000000, 0x9f131a7100000000, 0x6168fa1500000000,
+ 0xf4bc8a8000000000},
+ {0x0000000000000000, 0x1f17f08000000000, 0x7f2891da00000000,
+ 0x603f615a00000000, 0xbf56536e00000000, 0xa041a3ee00000000,
+ 0xc07ec2b400000000, 0xdf69323400000000, 0x7eada6dc00000000,
+ 0x61ba565c00000000, 0x0185370600000000, 0x1e92c78600000000,
+ 0xc1fbf5b200000000, 0xdeec053200000000, 0xbed3646800000000,
+ 0xa1c494e800000000, 0xbd5c3c6200000000, 0xa24bcce200000000,
+ 0xc274adb800000000, 0xdd635d3800000000, 0x020a6f0c00000000,
+ 0x1d1d9f8c00000000, 0x7d22fed600000000, 0x62350e5600000000,
+ 0xc3f19abe00000000, 0xdce66a3e00000000, 0xbcd90b6400000000,
+ 0xa3cefbe400000000, 0x7ca7c9d000000000, 0x63b0395000000000,
+ 0x038f580a00000000, 0x1c98a88a00000000, 0x7ab978c400000000,
+ 0x65ae884400000000, 0x0591e91e00000000, 0x1a86199e00000000,
+ 0xc5ef2baa00000000, 0xdaf8db2a00000000, 0xbac7ba7000000000,
+ 0xa5d04af000000000, 0x0414de1800000000, 0x1b032e9800000000,
+ 0x7b3c4fc200000000, 0x642bbf4200000000, 0xbb428d7600000000,
+ 0xa4557df600000000, 0xc46a1cac00000000, 0xdb7dec2c00000000,
+ 0xc7e544a600000000, 0xd8f2b42600000000, 0xb8cdd57c00000000,
+ 0xa7da25fc00000000, 0x78b317c800000000, 0x67a4e74800000000,
+ 0x079b861200000000, 0x188c769200000000, 0xb948e27a00000000,
+ 0xa65f12fa00000000, 0xc66073a000000000, 0xd977832000000000,
+ 0x061eb11400000000, 0x1909419400000000, 0x793620ce00000000,
+ 0x6621d04e00000000, 0xb574805300000000, 0xaa6370d300000000,
+ 0xca5c118900000000, 0xd54be10900000000, 0x0a22d33d00000000,
+ 0x153523bd00000000, 0x750a42e700000000, 0x6a1db26700000000,
+ 0xcbd9268f00000000, 0xd4ced60f00000000, 0xb4f1b75500000000,
+ 0xabe647d500000000, 0x748f75e100000000, 0x6b98856100000000,
+ 0x0ba7e43b00000000, 0x14b014bb00000000, 0x0828bc3100000000,
+ 0x173f4cb100000000, 0x77002deb00000000, 0x6817dd6b00000000,
+ 0xb77eef5f00000000, 0xa8691fdf00000000, 0xc8567e8500000000,
+ 0xd7418e0500000000, 0x76851aed00000000, 0x6992ea6d00000000,
+ 0x09ad8b3700000000, 0x16ba7bb700000000, 0xc9d3498300000000,
+ 0xd6c4b90300000000, 0xb6fbd85900000000, 0xa9ec28d900000000,
+ 0xcfcdf89700000000, 0xd0da081700000000, 0xb0e5694d00000000,
+ 0xaff299cd00000000, 0x709babf900000000, 0x6f8c5b7900000000,
+ 0x0fb33a2300000000, 0x10a4caa300000000, 0xb1605e4b00000000,
+ 0xae77aecb00000000, 0xce48cf9100000000, 0xd15f3f1100000000,
+ 0x0e360d2500000000, 0x1121fda500000000, 0x711e9cff00000000,
+ 0x6e096c7f00000000, 0x7291c4f500000000, 0x6d86347500000000,
+ 0x0db9552f00000000, 0x12aea5af00000000, 0xcdc7979b00000000,
+ 0xd2d0671b00000000, 0xb2ef064100000000, 0xadf8f6c100000000,
+ 0x0c3c622900000000, 0x132b92a900000000, 0x7314f3f300000000,
+ 0x6c03037300000000, 0xb36a314700000000, 0xac7dc1c700000000,
+ 0xcc42a09d00000000, 0xd355501d00000000, 0x6ae900a700000000,
+ 0x75fef02700000000, 0x15c1917d00000000, 0x0ad661fd00000000,
+ 0xd5bf53c900000000, 0xcaa8a34900000000, 0xaa97c21300000000,
+ 0xb580329300000000, 0x1444a67b00000000, 0x0b5356fb00000000,
+ 0x6b6c37a100000000, 0x747bc72100000000, 0xab12f51500000000,
+ 0xb405059500000000, 0xd43a64cf00000000, 0xcb2d944f00000000,
+ 0xd7b53cc500000000, 0xc8a2cc4500000000, 0xa89dad1f00000000,
+ 0xb78a5d9f00000000, 0x68e36fab00000000, 0x77f49f2b00000000,
+ 0x17cbfe7100000000, 0x08dc0ef100000000, 0xa9189a1900000000,
+ 0xb60f6a9900000000, 0xd6300bc300000000, 0xc927fb4300000000,
+ 0x164ec97700000000, 0x095939f700000000, 0x696658ad00000000,
+ 0x7671a82d00000000, 0x1050786300000000, 0x0f4788e300000000,
+ 0x6f78e9b900000000, 0x706f193900000000, 0xaf062b0d00000000,
+ 0xb011db8d00000000, 0xd02ebad700000000, 0xcf394a5700000000,
+ 0x6efddebf00000000, 0x71ea2e3f00000000, 0x11d54f6500000000,
+ 0x0ec2bfe500000000, 0xd1ab8dd100000000, 0xcebc7d5100000000,
+ 0xae831c0b00000000, 0xb194ec8b00000000, 0xad0c440100000000,
+ 0xb21bb48100000000, 0xd224d5db00000000, 0xcd33255b00000000,
+ 0x125a176f00000000, 0x0d4de7ef00000000, 0x6d7286b500000000,
+ 0x7265763500000000, 0xd3a1e2dd00000000, 0xccb6125d00000000,
+ 0xac89730700000000, 0xb39e838700000000, 0x6cf7b1b300000000,
+ 0x73e0413300000000, 0x13df206900000000, 0x0cc8d0e900000000,
+ 0xdf9d80f400000000, 0xc08a707400000000, 0xa0b5112e00000000,
+ 0xbfa2e1ae00000000, 0x60cbd39a00000000, 0x7fdc231a00000000,
+ 0x1fe3424000000000, 0x00f4b2c000000000, 0xa130262800000000,
+ 0xbe27d6a800000000, 0xde18b7f200000000, 0xc10f477200000000,
+ 0x1e66754600000000, 0x017185c600000000, 0x614ee49c00000000,
+ 0x7e59141c00000000, 0x62c1bc9600000000, 0x7dd64c1600000000,
+ 0x1de92d4c00000000, 0x02feddcc00000000, 0xdd97eff800000000,
+ 0xc2801f7800000000, 0xa2bf7e2200000000, 0xbda88ea200000000,
+ 0x1c6c1a4a00000000, 0x037beaca00000000, 0x63448b9000000000,
+ 0x7c537b1000000000, 0xa33a492400000000, 0xbc2db9a400000000,
+ 0xdc12d8fe00000000, 0xc305287e00000000, 0xa524f83000000000,
+ 0xba3308b000000000, 0xda0c69ea00000000, 0xc51b996a00000000,
+ 0x1a72ab5e00000000, 0x05655bde00000000, 0x655a3a8400000000,
+ 0x7a4dca0400000000, 0xdb895eec00000000, 0xc49eae6c00000000,
+ 0xa4a1cf3600000000, 0xbbb63fb600000000, 0x64df0d8200000000,
+ 0x7bc8fd0200000000, 0x1bf79c5800000000, 0x04e06cd800000000,
+ 0x1878c45200000000, 0x076f34d200000000, 0x6750558800000000,
+ 0x7847a50800000000, 0xa72e973c00000000, 0xb83967bc00000000,
+ 0xd80606e600000000, 0xc711f66600000000, 0x66d5628e00000000,
+ 0x79c2920e00000000, 0x19fdf35400000000, 0x06ea03d400000000,
+ 0xd98331e000000000, 0xc694c16000000000, 0xa6aba03a00000000,
+ 0xb9bc50ba00000000},
+ {0x0000000000000000, 0xe2fd888d00000000, 0x85fd60c000000000,
+ 0x6700e84d00000000, 0x4bfdb05b00000000, 0xa90038d600000000,
+ 0xce00d09b00000000, 0x2cfd581600000000, 0x96fa61b700000000,
+ 0x7407e93a00000000, 0x1307017700000000, 0xf1fa89fa00000000,
+ 0xdd07d1ec00000000, 0x3ffa596100000000, 0x58fab12c00000000,
+ 0xba0739a100000000, 0x6df3b2b500000000, 0x8f0e3a3800000000,
+ 0xe80ed27500000000, 0x0af35af800000000, 0x260e02ee00000000,
+ 0xc4f38a6300000000, 0xa3f3622e00000000, 0x410eeaa300000000,
+ 0xfb09d30200000000, 0x19f45b8f00000000, 0x7ef4b3c200000000,
+ 0x9c093b4f00000000, 0xb0f4635900000000, 0x5209ebd400000000,
+ 0x3509039900000000, 0xd7f48b1400000000, 0x9be014b000000000,
+ 0x791d9c3d00000000, 0x1e1d747000000000, 0xfce0fcfd00000000,
+ 0xd01da4eb00000000, 0x32e02c6600000000, 0x55e0c42b00000000,
+ 0xb71d4ca600000000, 0x0d1a750700000000, 0xefe7fd8a00000000,
+ 0x88e715c700000000, 0x6a1a9d4a00000000, 0x46e7c55c00000000,
+ 0xa41a4dd100000000, 0xc31aa59c00000000, 0x21e72d1100000000,
+ 0xf613a60500000000, 0x14ee2e8800000000, 0x73eec6c500000000,
+ 0x91134e4800000000, 0xbdee165e00000000, 0x5f139ed300000000,
+ 0x3813769e00000000, 0xdaeefe1300000000, 0x60e9c7b200000000,
+ 0x82144f3f00000000, 0xe514a77200000000, 0x07e92fff00000000,
+ 0x2b1477e900000000, 0xc9e9ff6400000000, 0xaee9172900000000,
+ 0x4c149fa400000000, 0x77c758bb00000000, 0x953ad03600000000,
+ 0xf23a387b00000000, 0x10c7b0f600000000, 0x3c3ae8e000000000,
+ 0xdec7606d00000000, 0xb9c7882000000000, 0x5b3a00ad00000000,
+ 0xe13d390c00000000, 0x03c0b18100000000, 0x64c059cc00000000,
+ 0x863dd14100000000, 0xaac0895700000000, 0x483d01da00000000,
+ 0x2f3de99700000000, 0xcdc0611a00000000, 0x1a34ea0e00000000,
+ 0xf8c9628300000000, 0x9fc98ace00000000, 0x7d34024300000000,
+ 0x51c95a5500000000, 0xb334d2d800000000, 0xd4343a9500000000,
+ 0x36c9b21800000000, 0x8cce8bb900000000, 0x6e33033400000000,
+ 0x0933eb7900000000, 0xebce63f400000000, 0xc7333be200000000,
+ 0x25ceb36f00000000, 0x42ce5b2200000000, 0xa033d3af00000000,
+ 0xec274c0b00000000, 0x0edac48600000000, 0x69da2ccb00000000,
+ 0x8b27a44600000000, 0xa7dafc5000000000, 0x452774dd00000000,
+ 0x22279c9000000000, 0xc0da141d00000000, 0x7add2dbc00000000,
+ 0x9820a53100000000, 0xff204d7c00000000, 0x1dddc5f100000000,
+ 0x31209de700000000, 0xd3dd156a00000000, 0xb4ddfd2700000000,
+ 0x562075aa00000000, 0x81d4febe00000000, 0x6329763300000000,
+ 0x04299e7e00000000, 0xe6d416f300000000, 0xca294ee500000000,
+ 0x28d4c66800000000, 0x4fd42e2500000000, 0xad29a6a800000000,
+ 0x172e9f0900000000, 0xf5d3178400000000, 0x92d3ffc900000000,
+ 0x702e774400000000, 0x5cd32f5200000000, 0xbe2ea7df00000000,
+ 0xd92e4f9200000000, 0x3bd3c71f00000000, 0xaf88c0ad00000000,
+ 0x4d75482000000000, 0x2a75a06d00000000, 0xc88828e000000000,
+ 0xe47570f600000000, 0x0688f87b00000000, 0x6188103600000000,
+ 0x837598bb00000000, 0x3972a11a00000000, 0xdb8f299700000000,
+ 0xbc8fc1da00000000, 0x5e72495700000000, 0x728f114100000000,
+ 0x907299cc00000000, 0xf772718100000000, 0x158ff90c00000000,
+ 0xc27b721800000000, 0x2086fa9500000000, 0x478612d800000000,
+ 0xa57b9a5500000000, 0x8986c24300000000, 0x6b7b4ace00000000,
+ 0x0c7ba28300000000, 0xee862a0e00000000, 0x548113af00000000,
+ 0xb67c9b2200000000, 0xd17c736f00000000, 0x3381fbe200000000,
+ 0x1f7ca3f400000000, 0xfd812b7900000000, 0x9a81c33400000000,
+ 0x787c4bb900000000, 0x3468d41d00000000, 0xd6955c9000000000,
+ 0xb195b4dd00000000, 0x53683c5000000000, 0x7f95644600000000,
+ 0x9d68eccb00000000, 0xfa68048600000000, 0x18958c0b00000000,
+ 0xa292b5aa00000000, 0x406f3d2700000000, 0x276fd56a00000000,
+ 0xc5925de700000000, 0xe96f05f100000000, 0x0b928d7c00000000,
+ 0x6c92653100000000, 0x8e6fedbc00000000, 0x599b66a800000000,
+ 0xbb66ee2500000000, 0xdc66066800000000, 0x3e9b8ee500000000,
+ 0x1266d6f300000000, 0xf09b5e7e00000000, 0x979bb63300000000,
+ 0x75663ebe00000000, 0xcf61071f00000000, 0x2d9c8f9200000000,
+ 0x4a9c67df00000000, 0xa861ef5200000000, 0x849cb74400000000,
+ 0x66613fc900000000, 0x0161d78400000000, 0xe39c5f0900000000,
+ 0xd84f981600000000, 0x3ab2109b00000000, 0x5db2f8d600000000,
+ 0xbf4f705b00000000, 0x93b2284d00000000, 0x714fa0c000000000,
+ 0x164f488d00000000, 0xf4b2c00000000000, 0x4eb5f9a100000000,
+ 0xac48712c00000000, 0xcb48996100000000, 0x29b511ec00000000,
+ 0x054849fa00000000, 0xe7b5c17700000000, 0x80b5293a00000000,
+ 0x6248a1b700000000, 0xb5bc2aa300000000, 0x5741a22e00000000,
+ 0x30414a6300000000, 0xd2bcc2ee00000000, 0xfe419af800000000,
+ 0x1cbc127500000000, 0x7bbcfa3800000000, 0x994172b500000000,
+ 0x23464b1400000000, 0xc1bbc39900000000, 0xa6bb2bd400000000,
+ 0x4446a35900000000, 0x68bbfb4f00000000, 0x8a4673c200000000,
+ 0xed469b8f00000000, 0x0fbb130200000000, 0x43af8ca600000000,
+ 0xa152042b00000000, 0xc652ec6600000000, 0x24af64eb00000000,
+ 0x08523cfd00000000, 0xeaafb47000000000, 0x8daf5c3d00000000,
+ 0x6f52d4b000000000, 0xd555ed1100000000, 0x37a8659c00000000,
+ 0x50a88dd100000000, 0xb255055c00000000, 0x9ea85d4a00000000,
+ 0x7c55d5c700000000, 0x1b553d8a00000000, 0xf9a8b50700000000,
+ 0x2e5c3e1300000000, 0xcca1b69e00000000, 0xaba15ed300000000,
+ 0x495cd65e00000000, 0x65a18e4800000000, 0x875c06c500000000,
+ 0xe05cee8800000000, 0x02a1660500000000, 0xb8a65fa400000000,
+ 0x5a5bd72900000000, 0x3d5b3f6400000000, 0xdfa6b7e900000000,
+ 0xf35befff00000000, 0x11a6677200000000, 0x76a68f3f00000000,
+ 0x945b07b200000000},
+ {0x0000000000000000, 0xa90b894e00000000, 0x5217129d00000000,
+ 0xfb1c9bd300000000, 0xe52855e100000000, 0x4c23dcaf00000000,
+ 0xb73f477c00000000, 0x1e34ce3200000000, 0x8b57db1900000000,
+ 0x225c525700000000, 0xd940c98400000000, 0x704b40ca00000000,
+ 0x6e7f8ef800000000, 0xc77407b600000000, 0x3c689c6500000000,
+ 0x9563152b00000000, 0x16afb63300000000, 0xbfa43f7d00000000,
+ 0x44b8a4ae00000000, 0xedb32de000000000, 0xf387e3d200000000,
+ 0x5a8c6a9c00000000, 0xa190f14f00000000, 0x089b780100000000,
+ 0x9df86d2a00000000, 0x34f3e46400000000, 0xcfef7fb700000000,
+ 0x66e4f6f900000000, 0x78d038cb00000000, 0xd1dbb18500000000,
+ 0x2ac72a5600000000, 0x83cca31800000000, 0x2c5e6d6700000000,
+ 0x8555e42900000000, 0x7e497ffa00000000, 0xd742f6b400000000,
+ 0xc976388600000000, 0x607db1c800000000, 0x9b612a1b00000000,
+ 0x326aa35500000000, 0xa709b67e00000000, 0x0e023f3000000000,
+ 0xf51ea4e300000000, 0x5c152dad00000000, 0x4221e39f00000000,
+ 0xeb2a6ad100000000, 0x1036f10200000000, 0xb93d784c00000000,
+ 0x3af1db5400000000, 0x93fa521a00000000, 0x68e6c9c900000000,
+ 0xc1ed408700000000, 0xdfd98eb500000000, 0x76d207fb00000000,
+ 0x8dce9c2800000000, 0x24c5156600000000, 0xb1a6004d00000000,
+ 0x18ad890300000000, 0xe3b112d000000000, 0x4aba9b9e00000000,
+ 0x548e55ac00000000, 0xfd85dce200000000, 0x0699473100000000,
+ 0xaf92ce7f00000000, 0x58bcdace00000000, 0xf1b7538000000000,
+ 0x0aabc85300000000, 0xa3a0411d00000000, 0xbd948f2f00000000,
+ 0x149f066100000000, 0xef839db200000000, 0x468814fc00000000,
+ 0xd3eb01d700000000, 0x7ae0889900000000, 0x81fc134a00000000,
+ 0x28f79a0400000000, 0x36c3543600000000, 0x9fc8dd7800000000,
+ 0x64d446ab00000000, 0xcddfcfe500000000, 0x4e136cfd00000000,
+ 0xe718e5b300000000, 0x1c047e6000000000, 0xb50ff72e00000000,
+ 0xab3b391c00000000, 0x0230b05200000000, 0xf92c2b8100000000,
+ 0x5027a2cf00000000, 0xc544b7e400000000, 0x6c4f3eaa00000000,
+ 0x9753a57900000000, 0x3e582c3700000000, 0x206ce20500000000,
+ 0x89676b4b00000000, 0x727bf09800000000, 0xdb7079d600000000,
+ 0x74e2b7a900000000, 0xdde93ee700000000, 0x26f5a53400000000,
+ 0x8ffe2c7a00000000, 0x91cae24800000000, 0x38c16b0600000000,
+ 0xc3ddf0d500000000, 0x6ad6799b00000000, 0xffb56cb000000000,
+ 0x56bee5fe00000000, 0xada27e2d00000000, 0x04a9f76300000000,
+ 0x1a9d395100000000, 0xb396b01f00000000, 0x488a2bcc00000000,
+ 0xe181a28200000000, 0x624d019a00000000, 0xcb4688d400000000,
+ 0x305a130700000000, 0x99519a4900000000, 0x8765547b00000000,
+ 0x2e6edd3500000000, 0xd57246e600000000, 0x7c79cfa800000000,
+ 0xe91ada8300000000, 0x401153cd00000000, 0xbb0dc81e00000000,
+ 0x1206415000000000, 0x0c328f6200000000, 0xa539062c00000000,
+ 0x5e259dff00000000, 0xf72e14b100000000, 0xf17ec44600000000,
+ 0x58754d0800000000, 0xa369d6db00000000, 0x0a625f9500000000,
+ 0x145691a700000000, 0xbd5d18e900000000, 0x4641833a00000000,
+ 0xef4a0a7400000000, 0x7a291f5f00000000, 0xd322961100000000,
+ 0x283e0dc200000000, 0x8135848c00000000, 0x9f014abe00000000,
+ 0x360ac3f000000000, 0xcd16582300000000, 0x641dd16d00000000,
+ 0xe7d1727500000000, 0x4edafb3b00000000, 0xb5c660e800000000,
+ 0x1ccde9a600000000, 0x02f9279400000000, 0xabf2aeda00000000,
+ 0x50ee350900000000, 0xf9e5bc4700000000, 0x6c86a96c00000000,
+ 0xc58d202200000000, 0x3e91bbf100000000, 0x979a32bf00000000,
+ 0x89aefc8d00000000, 0x20a575c300000000, 0xdbb9ee1000000000,
+ 0x72b2675e00000000, 0xdd20a92100000000, 0x742b206f00000000,
+ 0x8f37bbbc00000000, 0x263c32f200000000, 0x3808fcc000000000,
+ 0x9103758e00000000, 0x6a1fee5d00000000, 0xc314671300000000,
+ 0x5677723800000000, 0xff7cfb7600000000, 0x046060a500000000,
+ 0xad6be9eb00000000, 0xb35f27d900000000, 0x1a54ae9700000000,
+ 0xe148354400000000, 0x4843bc0a00000000, 0xcb8f1f1200000000,
+ 0x6284965c00000000, 0x99980d8f00000000, 0x309384c100000000,
+ 0x2ea74af300000000, 0x87acc3bd00000000, 0x7cb0586e00000000,
+ 0xd5bbd12000000000, 0x40d8c40b00000000, 0xe9d34d4500000000,
+ 0x12cfd69600000000, 0xbbc45fd800000000, 0xa5f091ea00000000,
+ 0x0cfb18a400000000, 0xf7e7837700000000, 0x5eec0a3900000000,
+ 0xa9c21e8800000000, 0x00c997c600000000, 0xfbd50c1500000000,
+ 0x52de855b00000000, 0x4cea4b6900000000, 0xe5e1c22700000000,
+ 0x1efd59f400000000, 0xb7f6d0ba00000000, 0x2295c59100000000,
+ 0x8b9e4cdf00000000, 0x7082d70c00000000, 0xd9895e4200000000,
+ 0xc7bd907000000000, 0x6eb6193e00000000, 0x95aa82ed00000000,
+ 0x3ca10ba300000000, 0xbf6da8bb00000000, 0x166621f500000000,
+ 0xed7aba2600000000, 0x4471336800000000, 0x5a45fd5a00000000,
+ 0xf34e741400000000, 0x0852efc700000000, 0xa159668900000000,
+ 0x343a73a200000000, 0x9d31faec00000000, 0x662d613f00000000,
+ 0xcf26e87100000000, 0xd112264300000000, 0x7819af0d00000000,
+ 0x830534de00000000, 0x2a0ebd9000000000, 0x859c73ef00000000,
+ 0x2c97faa100000000, 0xd78b617200000000, 0x7e80e83c00000000,
+ 0x60b4260e00000000, 0xc9bfaf4000000000, 0x32a3349300000000,
+ 0x9ba8bddd00000000, 0x0ecba8f600000000, 0xa7c021b800000000,
+ 0x5cdcba6b00000000, 0xf5d7332500000000, 0xebe3fd1700000000,
+ 0x42e8745900000000, 0xb9f4ef8a00000000, 0x10ff66c400000000,
+ 0x9333c5dc00000000, 0x3a384c9200000000, 0xc124d74100000000,
+ 0x682f5e0f00000000, 0x761b903d00000000, 0xdf10197300000000,
+ 0x240c82a000000000, 0x8d070bee00000000, 0x18641ec500000000,
+ 0xb16f978b00000000, 0x4a730c5800000000, 0xe378851600000000,
+ 0xfd4c4b2400000000, 0x5447c26a00000000, 0xaf5b59b900000000,
+ 0x0650d0f700000000},
+ {0x0000000000000000, 0x479244af00000000, 0xcf22f88500000000,
+ 0x88b0bc2a00000000, 0xdf4381d000000000, 0x98d1c57f00000000,
+ 0x1061795500000000, 0x57f33dfa00000000, 0xff81737a00000000,
+ 0xb81337d500000000, 0x30a38bff00000000, 0x7731cf5000000000,
+ 0x20c2f2aa00000000, 0x6750b60500000000, 0xefe00a2f00000000,
+ 0xa8724e8000000000, 0xfe03e7f400000000, 0xb991a35b00000000,
+ 0x31211f7100000000, 0x76b35bde00000000, 0x2140662400000000,
+ 0x66d2228b00000000, 0xee629ea100000000, 0xa9f0da0e00000000,
+ 0x0182948e00000000, 0x4610d02100000000, 0xcea06c0b00000000,
+ 0x893228a400000000, 0xdec1155e00000000, 0x995351f100000000,
+ 0x11e3eddb00000000, 0x5671a97400000000, 0xbd01bf3200000000,
+ 0xfa93fb9d00000000, 0x722347b700000000, 0x35b1031800000000,
+ 0x62423ee200000000, 0x25d07a4d00000000, 0xad60c66700000000,
+ 0xeaf282c800000000, 0x4280cc4800000000, 0x051288e700000000,
+ 0x8da234cd00000000, 0xca30706200000000, 0x9dc34d9800000000,
+ 0xda51093700000000, 0x52e1b51d00000000, 0x1573f1b200000000,
+ 0x430258c600000000, 0x04901c6900000000, 0x8c20a04300000000,
+ 0xcbb2e4ec00000000, 0x9c41d91600000000, 0xdbd39db900000000,
+ 0x5363219300000000, 0x14f1653c00000000, 0xbc832bbc00000000,
+ 0xfb116f1300000000, 0x73a1d33900000000, 0x3433979600000000,
+ 0x63c0aa6c00000000, 0x2452eec300000000, 0xace252e900000000,
+ 0xeb70164600000000, 0x7a037e6500000000, 0x3d913aca00000000,
+ 0xb52186e000000000, 0xf2b3c24f00000000, 0xa540ffb500000000,
+ 0xe2d2bb1a00000000, 0x6a62073000000000, 0x2df0439f00000000,
+ 0x85820d1f00000000, 0xc21049b000000000, 0x4aa0f59a00000000,
+ 0x0d32b13500000000, 0x5ac18ccf00000000, 0x1d53c86000000000,
+ 0x95e3744a00000000, 0xd27130e500000000, 0x8400999100000000,
+ 0xc392dd3e00000000, 0x4b22611400000000, 0x0cb025bb00000000,
+ 0x5b43184100000000, 0x1cd15cee00000000, 0x9461e0c400000000,
+ 0xd3f3a46b00000000, 0x7b81eaeb00000000, 0x3c13ae4400000000,
+ 0xb4a3126e00000000, 0xf33156c100000000, 0xa4c26b3b00000000,
+ 0xe3502f9400000000, 0x6be093be00000000, 0x2c72d71100000000,
+ 0xc702c15700000000, 0x809085f800000000, 0x082039d200000000,
+ 0x4fb27d7d00000000, 0x1841408700000000, 0x5fd3042800000000,
+ 0xd763b80200000000, 0x90f1fcad00000000, 0x3883b22d00000000,
+ 0x7f11f68200000000, 0xf7a14aa800000000, 0xb0330e0700000000,
+ 0xe7c033fd00000000, 0xa052775200000000, 0x28e2cb7800000000,
+ 0x6f708fd700000000, 0x390126a300000000, 0x7e93620c00000000,
+ 0xf623de2600000000, 0xb1b19a8900000000, 0xe642a77300000000,
+ 0xa1d0e3dc00000000, 0x29605ff600000000, 0x6ef21b5900000000,
+ 0xc68055d900000000, 0x8112117600000000, 0x09a2ad5c00000000,
+ 0x4e30e9f300000000, 0x19c3d40900000000, 0x5e5190a600000000,
+ 0xd6e12c8c00000000, 0x9173682300000000, 0xf406fcca00000000,
+ 0xb394b86500000000, 0x3b24044f00000000, 0x7cb640e000000000,
+ 0x2b457d1a00000000, 0x6cd739b500000000, 0xe467859f00000000,
+ 0xa3f5c13000000000, 0x0b878fb000000000, 0x4c15cb1f00000000,
+ 0xc4a5773500000000, 0x8337339a00000000, 0xd4c40e6000000000,
+ 0x93564acf00000000, 0x1be6f6e500000000, 0x5c74b24a00000000,
+ 0x0a051b3e00000000, 0x4d975f9100000000, 0xc527e3bb00000000,
+ 0x82b5a71400000000, 0xd5469aee00000000, 0x92d4de4100000000,
+ 0x1a64626b00000000, 0x5df626c400000000, 0xf584684400000000,
+ 0xb2162ceb00000000, 0x3aa690c100000000, 0x7d34d46e00000000,
+ 0x2ac7e99400000000, 0x6d55ad3b00000000, 0xe5e5111100000000,
+ 0xa27755be00000000, 0x490743f800000000, 0x0e95075700000000,
+ 0x8625bb7d00000000, 0xc1b7ffd200000000, 0x9644c22800000000,
+ 0xd1d6868700000000, 0x59663aad00000000, 0x1ef47e0200000000,
+ 0xb686308200000000, 0xf114742d00000000, 0x79a4c80700000000,
+ 0x3e368ca800000000, 0x69c5b15200000000, 0x2e57f5fd00000000,
+ 0xa6e749d700000000, 0xe1750d7800000000, 0xb704a40c00000000,
+ 0xf096e0a300000000, 0x78265c8900000000, 0x3fb4182600000000,
+ 0x684725dc00000000, 0x2fd5617300000000, 0xa765dd5900000000,
+ 0xe0f799f600000000, 0x4885d77600000000, 0x0f1793d900000000,
+ 0x87a72ff300000000, 0xc0356b5c00000000, 0x97c656a600000000,
+ 0xd054120900000000, 0x58e4ae2300000000, 0x1f76ea8c00000000,
+ 0x8e0582af00000000, 0xc997c60000000000, 0x41277a2a00000000,
+ 0x06b53e8500000000, 0x5146037f00000000, 0x16d447d000000000,
+ 0x9e64fbfa00000000, 0xd9f6bf5500000000, 0x7184f1d500000000,
+ 0x3616b57a00000000, 0xbea6095000000000, 0xf9344dff00000000,
+ 0xaec7700500000000, 0xe95534aa00000000, 0x61e5888000000000,
+ 0x2677cc2f00000000, 0x7006655b00000000, 0x379421f400000000,
+ 0xbf249dde00000000, 0xf8b6d97100000000, 0xaf45e48b00000000,
+ 0xe8d7a02400000000, 0x60671c0e00000000, 0x27f558a100000000,
+ 0x8f87162100000000, 0xc815528e00000000, 0x40a5eea400000000,
+ 0x0737aa0b00000000, 0x50c497f100000000, 0x1756d35e00000000,
+ 0x9fe66f7400000000, 0xd8742bdb00000000, 0x33043d9d00000000,
+ 0x7496793200000000, 0xfc26c51800000000, 0xbbb481b700000000,
+ 0xec47bc4d00000000, 0xabd5f8e200000000, 0x236544c800000000,
+ 0x64f7006700000000, 0xcc854ee700000000, 0x8b170a4800000000,
+ 0x03a7b66200000000, 0x4435f2cd00000000, 0x13c6cf3700000000,
+ 0x54548b9800000000, 0xdce437b200000000, 0x9b76731d00000000,
+ 0xcd07da6900000000, 0x8a959ec600000000, 0x022522ec00000000,
+ 0x45b7664300000000, 0x12445bb900000000, 0x55d61f1600000000,
+ 0xdd66a33c00000000, 0x9af4e79300000000, 0x3286a91300000000,
+ 0x7514edbc00000000, 0xfda4519600000000, 0xba36153900000000,
+ 0xedc528c300000000, 0xaa576c6c00000000, 0x22e7d04600000000,
+ 0x657594e900000000}};
+
+#else /* W == 4 */
+
+local const z_crc_t FAR crc_braid_table[][256] = {
+ {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59,
+ 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4,
+ 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67,
+ 0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef,
+ 0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97,
+ 0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88,
+ 0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687,
+ 0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698,
+ 0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0,
+ 0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068,
+ 0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb,
+ 0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056,
+ 0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016,
+ 0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009,
+ 0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028,
+ 0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037,
+ 0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a,
+ 0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7,
+ 0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054,
+ 0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7,
+ 0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af,
+ 0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0,
+ 0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4,
+ 0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab,
+ 0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3,
+ 0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a,
+ 0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9,
+ 0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54,
+ 0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09,
+ 0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16,
+ 0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37,
+ 0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28,
+ 0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e,
+ 0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3,
+ 0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40,
+ 0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8,
+ 0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0,
+ 0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf,
+ 0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6,
+ 0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9,
+ 0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1,
+ 0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059,
+ 0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca,
+ 0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067,
+ 0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031,
+ 0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e,
+ 0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f,
+ 0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010,
+ 0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d,
+ 0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0,
+ 0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073,
+ 0xd8ac6b35},
+ {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2,
+ 0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd,
+ 0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696,
+ 0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3,
+ 0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f,
+ 0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35,
+ 0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5,
+ 0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f,
+ 0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673,
+ 0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46,
+ 0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d,
+ 0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632,
+ 0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28,
+ 0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192,
+ 0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c,
+ 0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6,
+ 0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0,
+ 0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff,
+ 0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4,
+ 0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95,
+ 0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9,
+ 0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03,
+ 0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7,
+ 0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d,
+ 0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151,
+ 0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808,
+ 0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343,
+ 0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c,
+ 0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a,
+ 0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0,
+ 0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e,
+ 0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594,
+ 0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6,
+ 0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399,
+ 0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2,
+ 0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7,
+ 0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb,
+ 0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571,
+ 0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289,
+ 0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33,
+ 0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f,
+ 0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a,
+ 0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461,
+ 0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e,
+ 0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c,
+ 0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6,
+ 0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918,
+ 0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2,
+ 0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484,
+ 0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb,
+ 0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0,
+ 0xa140efa8},
+ {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706,
+ 0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed,
+ 0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289,
+ 0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a,
+ 0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214,
+ 0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3,
+ 0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3,
+ 0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254,
+ 0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a,
+ 0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9,
+ 0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad,
+ 0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746,
+ 0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060,
+ 0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187,
+ 0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef,
+ 0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408,
+ 0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e,
+ 0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495,
+ 0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1,
+ 0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532,
+ 0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c,
+ 0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb,
+ 0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb,
+ 0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c,
+ 0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42,
+ 0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060,
+ 0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04,
+ 0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef,
+ 0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99,
+ 0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e,
+ 0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16,
+ 0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1,
+ 0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7,
+ 0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c,
+ 0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38,
+ 0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb,
+ 0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5,
+ 0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42,
+ 0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62,
+ 0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85,
+ 0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb,
+ 0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18,
+ 0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c,
+ 0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997,
+ 0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1,
+ 0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36,
+ 0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e,
+ 0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9,
+ 0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf,
+ 0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24,
+ 0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040,
+ 0x917cd6a1},
+ {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf,
+ 0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd,
+ 0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896,
+ 0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9,
+ 0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3,
+ 0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f,
+ 0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d,
+ 0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1,
+ 0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab,
+ 0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4,
+ 0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f,
+ 0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d,
+ 0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4,
+ 0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978,
+ 0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad,
+ 0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621,
+ 0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46,
+ 0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854,
+ 0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f,
+ 0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a,
+ 0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890,
+ 0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c,
+ 0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4,
+ 0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238,
+ 0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622,
+ 0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab,
+ 0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0,
+ 0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2,
+ 0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295,
+ 0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19,
+ 0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc,
+ 0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140,
+ 0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd,
+ 0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf,
+ 0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184,
+ 0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb,
+ 0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1,
+ 0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d,
+ 0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb,
+ 0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257,
+ 0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d,
+ 0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22,
+ 0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069,
+ 0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b,
+ 0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6,
+ 0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a,
+ 0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf,
+ 0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33,
+ 0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254,
+ 0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146,
+ 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d,
+ 0x18ba364e}};
+
+local const z_word_t FAR crc_braid_big_table[][256] = {
+ {0x00000000, 0x43cba687, 0xc7903cd4, 0x845b9a53, 0xcf270873,
+ 0x8cecaef4, 0x08b734a7, 0x4b7c9220, 0x9e4f10e6, 0xdd84b661,
+ 0x59df2c32, 0x1a148ab5, 0x51681895, 0x12a3be12, 0x96f82441,
+ 0xd53382c6, 0x7d995117, 0x3e52f790, 0xba096dc3, 0xf9c2cb44,
+ 0xb2be5964, 0xf175ffe3, 0x752e65b0, 0x36e5c337, 0xe3d641f1,
+ 0xa01de776, 0x24467d25, 0x678ddba2, 0x2cf14982, 0x6f3aef05,
+ 0xeb617556, 0xa8aad3d1, 0xfa32a32e, 0xb9f905a9, 0x3da29ffa,
+ 0x7e69397d, 0x3515ab5d, 0x76de0dda, 0xf2859789, 0xb14e310e,
+ 0x647db3c8, 0x27b6154f, 0xa3ed8f1c, 0xe026299b, 0xab5abbbb,
+ 0xe8911d3c, 0x6cca876f, 0x2f0121e8, 0x87abf239, 0xc46054be,
+ 0x403bceed, 0x03f0686a, 0x488cfa4a, 0x0b475ccd, 0x8f1cc69e,
+ 0xccd76019, 0x19e4e2df, 0x5a2f4458, 0xde74de0b, 0x9dbf788c,
+ 0xd6c3eaac, 0x95084c2b, 0x1153d678, 0x529870ff, 0xf465465d,
+ 0xb7aee0da, 0x33f57a89, 0x703edc0e, 0x3b424e2e, 0x7889e8a9,
+ 0xfcd272fa, 0xbf19d47d, 0x6a2a56bb, 0x29e1f03c, 0xadba6a6f,
+ 0xee71cce8, 0xa50d5ec8, 0xe6c6f84f, 0x629d621c, 0x2156c49b,
+ 0x89fc174a, 0xca37b1cd, 0x4e6c2b9e, 0x0da78d19, 0x46db1f39,
+ 0x0510b9be, 0x814b23ed, 0xc280856a, 0x17b307ac, 0x5478a12b,
+ 0xd0233b78, 0x93e89dff, 0xd8940fdf, 0x9b5fa958, 0x1f04330b,
+ 0x5ccf958c, 0x0e57e573, 0x4d9c43f4, 0xc9c7d9a7, 0x8a0c7f20,
+ 0xc170ed00, 0x82bb4b87, 0x06e0d1d4, 0x452b7753, 0x9018f595,
+ 0xd3d35312, 0x5788c941, 0x14436fc6, 0x5f3ffde6, 0x1cf45b61,
+ 0x98afc132, 0xdb6467b5, 0x73ceb464, 0x300512e3, 0xb45e88b0,
+ 0xf7952e37, 0xbce9bc17, 0xff221a90, 0x7b7980c3, 0x38b22644,
+ 0xed81a482, 0xae4a0205, 0x2a119856, 0x69da3ed1, 0x22a6acf1,
+ 0x616d0a76, 0xe5369025, 0xa6fd36a2, 0xe8cb8cba, 0xab002a3d,
+ 0x2f5bb06e, 0x6c9016e9, 0x27ec84c9, 0x6427224e, 0xe07cb81d,
+ 0xa3b71e9a, 0x76849c5c, 0x354f3adb, 0xb114a088, 0xf2df060f,
+ 0xb9a3942f, 0xfa6832a8, 0x7e33a8fb, 0x3df80e7c, 0x9552ddad,
+ 0xd6997b2a, 0x52c2e179, 0x110947fe, 0x5a75d5de, 0x19be7359,
+ 0x9de5e90a, 0xde2e4f8d, 0x0b1dcd4b, 0x48d66bcc, 0xcc8df19f,
+ 0x8f465718, 0xc43ac538, 0x87f163bf, 0x03aaf9ec, 0x40615f6b,
+ 0x12f92f94, 0x51328913, 0xd5691340, 0x96a2b5c7, 0xddde27e7,
+ 0x9e158160, 0x1a4e1b33, 0x5985bdb4, 0x8cb63f72, 0xcf7d99f5,
+ 0x4b2603a6, 0x08eda521, 0x43913701, 0x005a9186, 0x84010bd5,
+ 0xc7caad52, 0x6f607e83, 0x2cabd804, 0xa8f04257, 0xeb3be4d0,
+ 0xa04776f0, 0xe38cd077, 0x67d74a24, 0x241ceca3, 0xf12f6e65,
+ 0xb2e4c8e2, 0x36bf52b1, 0x7574f436, 0x3e086616, 0x7dc3c091,
+ 0xf9985ac2, 0xba53fc45, 0x1caecae7, 0x5f656c60, 0xdb3ef633,
+ 0x98f550b4, 0xd389c294, 0x90426413, 0x1419fe40, 0x57d258c7,
+ 0x82e1da01, 0xc12a7c86, 0x4571e6d5, 0x06ba4052, 0x4dc6d272,
+ 0x0e0d74f5, 0x8a56eea6, 0xc99d4821, 0x61379bf0, 0x22fc3d77,
+ 0xa6a7a724, 0xe56c01a3, 0xae109383, 0xeddb3504, 0x6980af57,
+ 0x2a4b09d0, 0xff788b16, 0xbcb32d91, 0x38e8b7c2, 0x7b231145,
+ 0x305f8365, 0x739425e2, 0xf7cfbfb1, 0xb4041936, 0xe69c69c9,
+ 0xa557cf4e, 0x210c551d, 0x62c7f39a, 0x29bb61ba, 0x6a70c73d,
+ 0xee2b5d6e, 0xade0fbe9, 0x78d3792f, 0x3b18dfa8, 0xbf4345fb,
+ 0xfc88e37c, 0xb7f4715c, 0xf43fd7db, 0x70644d88, 0x33afeb0f,
+ 0x9b0538de, 0xd8ce9e59, 0x5c95040a, 0x1f5ea28d, 0x542230ad,
+ 0x17e9962a, 0x93b20c79, 0xd079aafe, 0x054a2838, 0x46818ebf,
+ 0xc2da14ec, 0x8111b26b, 0xca6d204b, 0x89a686cc, 0x0dfd1c9f,
+ 0x4e36ba18},
+ {0x00000000, 0xe1b652ef, 0x836bd405, 0x62dd86ea, 0x06d7a80b,
+ 0xe761fae4, 0x85bc7c0e, 0x640a2ee1, 0x0cae5117, 0xed1803f8,
+ 0x8fc58512, 0x6e73d7fd, 0x0a79f91c, 0xebcfabf3, 0x89122d19,
+ 0x68a47ff6, 0x185ca32e, 0xf9eaf1c1, 0x9b37772b, 0x7a8125c4,
+ 0x1e8b0b25, 0xff3d59ca, 0x9de0df20, 0x7c568dcf, 0x14f2f239,
+ 0xf544a0d6, 0x9799263c, 0x762f74d3, 0x12255a32, 0xf39308dd,
+ 0x914e8e37, 0x70f8dcd8, 0x30b8465d, 0xd10e14b2, 0xb3d39258,
+ 0x5265c0b7, 0x366fee56, 0xd7d9bcb9, 0xb5043a53, 0x54b268bc,
+ 0x3c16174a, 0xdda045a5, 0xbf7dc34f, 0x5ecb91a0, 0x3ac1bf41,
+ 0xdb77edae, 0xb9aa6b44, 0x581c39ab, 0x28e4e573, 0xc952b79c,
+ 0xab8f3176, 0x4a396399, 0x2e334d78, 0xcf851f97, 0xad58997d,
+ 0x4ceecb92, 0x244ab464, 0xc5fce68b, 0xa7216061, 0x4697328e,
+ 0x229d1c6f, 0xc32b4e80, 0xa1f6c86a, 0x40409a85, 0x60708dba,
+ 0x81c6df55, 0xe31b59bf, 0x02ad0b50, 0x66a725b1, 0x8711775e,
+ 0xe5ccf1b4, 0x047aa35b, 0x6cdedcad, 0x8d688e42, 0xefb508a8,
+ 0x0e035a47, 0x6a0974a6, 0x8bbf2649, 0xe962a0a3, 0x08d4f24c,
+ 0x782c2e94, 0x999a7c7b, 0xfb47fa91, 0x1af1a87e, 0x7efb869f,
+ 0x9f4dd470, 0xfd90529a, 0x1c260075, 0x74827f83, 0x95342d6c,
+ 0xf7e9ab86, 0x165ff969, 0x7255d788, 0x93e38567, 0xf13e038d,
+ 0x10885162, 0x50c8cbe7, 0xb17e9908, 0xd3a31fe2, 0x32154d0d,
+ 0x561f63ec, 0xb7a93103, 0xd574b7e9, 0x34c2e506, 0x5c669af0,
+ 0xbdd0c81f, 0xdf0d4ef5, 0x3ebb1c1a, 0x5ab132fb, 0xbb076014,
+ 0xd9dae6fe, 0x386cb411, 0x489468c9, 0xa9223a26, 0xcbffbccc,
+ 0x2a49ee23, 0x4e43c0c2, 0xaff5922d, 0xcd2814c7, 0x2c9e4628,
+ 0x443a39de, 0xa58c6b31, 0xc751eddb, 0x26e7bf34, 0x42ed91d5,
+ 0xa35bc33a, 0xc18645d0, 0x2030173f, 0x81e66bae, 0x60503941,
+ 0x028dbfab, 0xe33bed44, 0x8731c3a5, 0x6687914a, 0x045a17a0,
+ 0xe5ec454f, 0x8d483ab9, 0x6cfe6856, 0x0e23eebc, 0xef95bc53,
+ 0x8b9f92b2, 0x6a29c05d, 0x08f446b7, 0xe9421458, 0x99bac880,
+ 0x780c9a6f, 0x1ad11c85, 0xfb674e6a, 0x9f6d608b, 0x7edb3264,
+ 0x1c06b48e, 0xfdb0e661, 0x95149997, 0x74a2cb78, 0x167f4d92,
+ 0xf7c91f7d, 0x93c3319c, 0x72756373, 0x10a8e599, 0xf11eb776,
+ 0xb15e2df3, 0x50e87f1c, 0x3235f9f6, 0xd383ab19, 0xb78985f8,
+ 0x563fd717, 0x34e251fd, 0xd5540312, 0xbdf07ce4, 0x5c462e0b,
+ 0x3e9ba8e1, 0xdf2dfa0e, 0xbb27d4ef, 0x5a918600, 0x384c00ea,
+ 0xd9fa5205, 0xa9028edd, 0x48b4dc32, 0x2a695ad8, 0xcbdf0837,
+ 0xafd526d6, 0x4e637439, 0x2cbef2d3, 0xcd08a03c, 0xa5acdfca,
+ 0x441a8d25, 0x26c70bcf, 0xc7715920, 0xa37b77c1, 0x42cd252e,
+ 0x2010a3c4, 0xc1a6f12b, 0xe196e614, 0x0020b4fb, 0x62fd3211,
+ 0x834b60fe, 0xe7414e1f, 0x06f71cf0, 0x642a9a1a, 0x859cc8f5,
+ 0xed38b703, 0x0c8ee5ec, 0x6e536306, 0x8fe531e9, 0xebef1f08,
+ 0x0a594de7, 0x6884cb0d, 0x893299e2, 0xf9ca453a, 0x187c17d5,
+ 0x7aa1913f, 0x9b17c3d0, 0xff1ded31, 0x1eabbfde, 0x7c763934,
+ 0x9dc06bdb, 0xf564142d, 0x14d246c2, 0x760fc028, 0x97b992c7,
+ 0xf3b3bc26, 0x1205eec9, 0x70d86823, 0x916e3acc, 0xd12ea049,
+ 0x3098f2a6, 0x5245744c, 0xb3f326a3, 0xd7f90842, 0x364f5aad,
+ 0x5492dc47, 0xb5248ea8, 0xdd80f15e, 0x3c36a3b1, 0x5eeb255b,
+ 0xbf5d77b4, 0xdb575955, 0x3ae10bba, 0x583c8d50, 0xb98adfbf,
+ 0xc9720367, 0x28c45188, 0x4a19d762, 0xabaf858d, 0xcfa5ab6c,
+ 0x2e13f983, 0x4cce7f69, 0xad782d86, 0xc5dc5270, 0x246a009f,
+ 0x46b78675, 0xa701d49a, 0xc30bfa7b, 0x22bda894, 0x40602e7e,
+ 0xa1d67c91},
+ {0x00000000, 0x5880e2d7, 0xf106b474, 0xa98656a3, 0xe20d68e9,
+ 0xba8d8a3e, 0x130bdc9d, 0x4b8b3e4a, 0x851da109, 0xdd9d43de,
+ 0x741b157d, 0x2c9bf7aa, 0x6710c9e0, 0x3f902b37, 0x96167d94,
+ 0xce969f43, 0x0a3b4213, 0x52bba0c4, 0xfb3df667, 0xa3bd14b0,
+ 0xe8362afa, 0xb0b6c82d, 0x19309e8e, 0x41b07c59, 0x8f26e31a,
+ 0xd7a601cd, 0x7e20576e, 0x26a0b5b9, 0x6d2b8bf3, 0x35ab6924,
+ 0x9c2d3f87, 0xc4addd50, 0x14768426, 0x4cf666f1, 0xe5703052,
+ 0xbdf0d285, 0xf67beccf, 0xaefb0e18, 0x077d58bb, 0x5ffdba6c,
+ 0x916b252f, 0xc9ebc7f8, 0x606d915b, 0x38ed738c, 0x73664dc6,
+ 0x2be6af11, 0x8260f9b2, 0xdae01b65, 0x1e4dc635, 0x46cd24e2,
+ 0xef4b7241, 0xb7cb9096, 0xfc40aedc, 0xa4c04c0b, 0x0d461aa8,
+ 0x55c6f87f, 0x9b50673c, 0xc3d085eb, 0x6a56d348, 0x32d6319f,
+ 0x795d0fd5, 0x21dded02, 0x885bbba1, 0xd0db5976, 0x28ec084d,
+ 0x706cea9a, 0xd9eabc39, 0x816a5eee, 0xcae160a4, 0x92618273,
+ 0x3be7d4d0, 0x63673607, 0xadf1a944, 0xf5714b93, 0x5cf71d30,
+ 0x0477ffe7, 0x4ffcc1ad, 0x177c237a, 0xbefa75d9, 0xe67a970e,
+ 0x22d74a5e, 0x7a57a889, 0xd3d1fe2a, 0x8b511cfd, 0xc0da22b7,
+ 0x985ac060, 0x31dc96c3, 0x695c7414, 0xa7caeb57, 0xff4a0980,
+ 0x56cc5f23, 0x0e4cbdf4, 0x45c783be, 0x1d476169, 0xb4c137ca,
+ 0xec41d51d, 0x3c9a8c6b, 0x641a6ebc, 0xcd9c381f, 0x951cdac8,
+ 0xde97e482, 0x86170655, 0x2f9150f6, 0x7711b221, 0xb9872d62,
+ 0xe107cfb5, 0x48819916, 0x10017bc1, 0x5b8a458b, 0x030aa75c,
+ 0xaa8cf1ff, 0xf20c1328, 0x36a1ce78, 0x6e212caf, 0xc7a77a0c,
+ 0x9f2798db, 0xd4aca691, 0x8c2c4446, 0x25aa12e5, 0x7d2af032,
+ 0xb3bc6f71, 0xeb3c8da6, 0x42badb05, 0x1a3a39d2, 0x51b10798,
+ 0x0931e54f, 0xa0b7b3ec, 0xf837513b, 0x50d8119a, 0x0858f34d,
+ 0xa1dea5ee, 0xf95e4739, 0xb2d57973, 0xea559ba4, 0x43d3cd07,
+ 0x1b532fd0, 0xd5c5b093, 0x8d455244, 0x24c304e7, 0x7c43e630,
+ 0x37c8d87a, 0x6f483aad, 0xc6ce6c0e, 0x9e4e8ed9, 0x5ae35389,
+ 0x0263b15e, 0xabe5e7fd, 0xf365052a, 0xb8ee3b60, 0xe06ed9b7,
+ 0x49e88f14, 0x11686dc3, 0xdffef280, 0x877e1057, 0x2ef846f4,
+ 0x7678a423, 0x3df39a69, 0x657378be, 0xccf52e1d, 0x9475ccca,
+ 0x44ae95bc, 0x1c2e776b, 0xb5a821c8, 0xed28c31f, 0xa6a3fd55,
+ 0xfe231f82, 0x57a54921, 0x0f25abf6, 0xc1b334b5, 0x9933d662,
+ 0x30b580c1, 0x68356216, 0x23be5c5c, 0x7b3ebe8b, 0xd2b8e828,
+ 0x8a380aff, 0x4e95d7af, 0x16153578, 0xbf9363db, 0xe713810c,
+ 0xac98bf46, 0xf4185d91, 0x5d9e0b32, 0x051ee9e5, 0xcb8876a6,
+ 0x93089471, 0x3a8ec2d2, 0x620e2005, 0x29851e4f, 0x7105fc98,
+ 0xd883aa3b, 0x800348ec, 0x783419d7, 0x20b4fb00, 0x8932ada3,
+ 0xd1b24f74, 0x9a39713e, 0xc2b993e9, 0x6b3fc54a, 0x33bf279d,
+ 0xfd29b8de, 0xa5a95a09, 0x0c2f0caa, 0x54afee7d, 0x1f24d037,
+ 0x47a432e0, 0xee226443, 0xb6a28694, 0x720f5bc4, 0x2a8fb913,
+ 0x8309efb0, 0xdb890d67, 0x9002332d, 0xc882d1fa, 0x61048759,
+ 0x3984658e, 0xf712facd, 0xaf92181a, 0x06144eb9, 0x5e94ac6e,
+ 0x151f9224, 0x4d9f70f3, 0xe4192650, 0xbc99c487, 0x6c429df1,
+ 0x34c27f26, 0x9d442985, 0xc5c4cb52, 0x8e4ff518, 0xd6cf17cf,
+ 0x7f49416c, 0x27c9a3bb, 0xe95f3cf8, 0xb1dfde2f, 0x1859888c,
+ 0x40d96a5b, 0x0b525411, 0x53d2b6c6, 0xfa54e065, 0xa2d402b2,
+ 0x6679dfe2, 0x3ef93d35, 0x977f6b96, 0xcfff8941, 0x8474b70b,
+ 0xdcf455dc, 0x7572037f, 0x2df2e1a8, 0xe3647eeb, 0xbbe49c3c,
+ 0x1262ca9f, 0x4ae22848, 0x01691602, 0x59e9f4d5, 0xf06fa276,
+ 0xa8ef40a1},
+ {0x00000000, 0x463b6765, 0x8c76ceca, 0xca4da9af, 0x59ebed4e,
+ 0x1fd08a2b, 0xd59d2384, 0x93a644e1, 0xb2d6db9d, 0xf4edbcf8,
+ 0x3ea01557, 0x789b7232, 0xeb3d36d3, 0xad0651b6, 0x674bf819,
+ 0x21709f7c, 0x25abc6e0, 0x6390a185, 0xa9dd082a, 0xefe66f4f,
+ 0x7c402bae, 0x3a7b4ccb, 0xf036e564, 0xb60d8201, 0x977d1d7d,
+ 0xd1467a18, 0x1b0bd3b7, 0x5d30b4d2, 0xce96f033, 0x88ad9756,
+ 0x42e03ef9, 0x04db599c, 0x0b50fc1a, 0x4d6b9b7f, 0x872632d0,
+ 0xc11d55b5, 0x52bb1154, 0x14807631, 0xdecddf9e, 0x98f6b8fb,
+ 0xb9862787, 0xffbd40e2, 0x35f0e94d, 0x73cb8e28, 0xe06dcac9,
+ 0xa656adac, 0x6c1b0403, 0x2a206366, 0x2efb3afa, 0x68c05d9f,
+ 0xa28df430, 0xe4b69355, 0x7710d7b4, 0x312bb0d1, 0xfb66197e,
+ 0xbd5d7e1b, 0x9c2de167, 0xda168602, 0x105b2fad, 0x566048c8,
+ 0xc5c60c29, 0x83fd6b4c, 0x49b0c2e3, 0x0f8ba586, 0x16a0f835,
+ 0x509b9f50, 0x9ad636ff, 0xdced519a, 0x4f4b157b, 0x0970721e,
+ 0xc33ddbb1, 0x8506bcd4, 0xa47623a8, 0xe24d44cd, 0x2800ed62,
+ 0x6e3b8a07, 0xfd9dcee6, 0xbba6a983, 0x71eb002c, 0x37d06749,
+ 0x330b3ed5, 0x753059b0, 0xbf7df01f, 0xf946977a, 0x6ae0d39b,
+ 0x2cdbb4fe, 0xe6961d51, 0xa0ad7a34, 0x81dde548, 0xc7e6822d,
+ 0x0dab2b82, 0x4b904ce7, 0xd8360806, 0x9e0d6f63, 0x5440c6cc,
+ 0x127ba1a9, 0x1df0042f, 0x5bcb634a, 0x9186cae5, 0xd7bdad80,
+ 0x441be961, 0x02208e04, 0xc86d27ab, 0x8e5640ce, 0xaf26dfb2,
+ 0xe91db8d7, 0x23501178, 0x656b761d, 0xf6cd32fc, 0xb0f65599,
+ 0x7abbfc36, 0x3c809b53, 0x385bc2cf, 0x7e60a5aa, 0xb42d0c05,
+ 0xf2166b60, 0x61b02f81, 0x278b48e4, 0xedc6e14b, 0xabfd862e,
+ 0x8a8d1952, 0xccb67e37, 0x06fbd798, 0x40c0b0fd, 0xd366f41c,
+ 0x955d9379, 0x5f103ad6, 0x192b5db3, 0x2c40f16b, 0x6a7b960e,
+ 0xa0363fa1, 0xe60d58c4, 0x75ab1c25, 0x33907b40, 0xf9ddd2ef,
+ 0xbfe6b58a, 0x9e962af6, 0xd8ad4d93, 0x12e0e43c, 0x54db8359,
+ 0xc77dc7b8, 0x8146a0dd, 0x4b0b0972, 0x0d306e17, 0x09eb378b,
+ 0x4fd050ee, 0x859df941, 0xc3a69e24, 0x5000dac5, 0x163bbda0,
+ 0xdc76140f, 0x9a4d736a, 0xbb3dec16, 0xfd068b73, 0x374b22dc,
+ 0x717045b9, 0xe2d60158, 0xa4ed663d, 0x6ea0cf92, 0x289ba8f7,
+ 0x27100d71, 0x612b6a14, 0xab66c3bb, 0xed5da4de, 0x7efbe03f,
+ 0x38c0875a, 0xf28d2ef5, 0xb4b64990, 0x95c6d6ec, 0xd3fdb189,
+ 0x19b01826, 0x5f8b7f43, 0xcc2d3ba2, 0x8a165cc7, 0x405bf568,
+ 0x0660920d, 0x02bbcb91, 0x4480acf4, 0x8ecd055b, 0xc8f6623e,
+ 0x5b5026df, 0x1d6b41ba, 0xd726e815, 0x911d8f70, 0xb06d100c,
+ 0xf6567769, 0x3c1bdec6, 0x7a20b9a3, 0xe986fd42, 0xafbd9a27,
+ 0x65f03388, 0x23cb54ed, 0x3ae0095e, 0x7cdb6e3b, 0xb696c794,
+ 0xf0ada0f1, 0x630be410, 0x25308375, 0xef7d2ada, 0xa9464dbf,
+ 0x8836d2c3, 0xce0db5a6, 0x04401c09, 0x427b7b6c, 0xd1dd3f8d,
+ 0x97e658e8, 0x5dabf147, 0x1b909622, 0x1f4bcfbe, 0x5970a8db,
+ 0x933d0174, 0xd5066611, 0x46a022f0, 0x009b4595, 0xcad6ec3a,
+ 0x8ced8b5f, 0xad9d1423, 0xeba67346, 0x21ebdae9, 0x67d0bd8c,
+ 0xf476f96d, 0xb24d9e08, 0x780037a7, 0x3e3b50c2, 0x31b0f544,
+ 0x778b9221, 0xbdc63b8e, 0xfbfd5ceb, 0x685b180a, 0x2e607f6f,
+ 0xe42dd6c0, 0xa216b1a5, 0x83662ed9, 0xc55d49bc, 0x0f10e013,
+ 0x492b8776, 0xda8dc397, 0x9cb6a4f2, 0x56fb0d5d, 0x10c06a38,
+ 0x141b33a4, 0x522054c1, 0x986dfd6e, 0xde569a0b, 0x4df0deea,
+ 0x0bcbb98f, 0xc1861020, 0x87bd7745, 0xa6cde839, 0xe0f68f5c,
+ 0x2abb26f3, 0x6c804196, 0xff260577, 0xb91d6212, 0x7350cbbd,
+ 0x356bacd8}};
+
+#endif
+
+#endif
+
+#if N == 6
+
+#if W == 8
+
+local const z_crc_t FAR crc_braid_table[][256] = {
+ {0x00000000, 0x3db1ecdc, 0x7b63d9b8, 0x46d23564, 0xf6c7b370,
+ 0xcb765fac, 0x8da46ac8, 0xb0158614, 0x36fe60a1, 0x0b4f8c7d,
+ 0x4d9db919, 0x702c55c5, 0xc039d3d1, 0xfd883f0d, 0xbb5a0a69,
+ 0x86ebe6b5, 0x6dfcc142, 0x504d2d9e, 0x169f18fa, 0x2b2ef426,
+ 0x9b3b7232, 0xa68a9eee, 0xe058ab8a, 0xdde94756, 0x5b02a1e3,
+ 0x66b34d3f, 0x2061785b, 0x1dd09487, 0xadc51293, 0x9074fe4f,
+ 0xd6a6cb2b, 0xeb1727f7, 0xdbf98284, 0xe6486e58, 0xa09a5b3c,
+ 0x9d2bb7e0, 0x2d3e31f4, 0x108fdd28, 0x565de84c, 0x6bec0490,
+ 0xed07e225, 0xd0b60ef9, 0x96643b9d, 0xabd5d741, 0x1bc05155,
+ 0x2671bd89, 0x60a388ed, 0x5d126431, 0xb60543c6, 0x8bb4af1a,
+ 0xcd669a7e, 0xf0d776a2, 0x40c2f0b6, 0x7d731c6a, 0x3ba1290e,
+ 0x0610c5d2, 0x80fb2367, 0xbd4acfbb, 0xfb98fadf, 0xc6291603,
+ 0x763c9017, 0x4b8d7ccb, 0x0d5f49af, 0x30eea573, 0x6c820349,
+ 0x5133ef95, 0x17e1daf1, 0x2a50362d, 0x9a45b039, 0xa7f45ce5,
+ 0xe1266981, 0xdc97855d, 0x5a7c63e8, 0x67cd8f34, 0x211fba50,
+ 0x1cae568c, 0xacbbd098, 0x910a3c44, 0xd7d80920, 0xea69e5fc,
+ 0x017ec20b, 0x3ccf2ed7, 0x7a1d1bb3, 0x47acf76f, 0xf7b9717b,
+ 0xca089da7, 0x8cdaa8c3, 0xb16b441f, 0x3780a2aa, 0x0a314e76,
+ 0x4ce37b12, 0x715297ce, 0xc14711da, 0xfcf6fd06, 0xba24c862,
+ 0x879524be, 0xb77b81cd, 0x8aca6d11, 0xcc185875, 0xf1a9b4a9,
+ 0x41bc32bd, 0x7c0dde61, 0x3adfeb05, 0x076e07d9, 0x8185e16c,
+ 0xbc340db0, 0xfae638d4, 0xc757d408, 0x7742521c, 0x4af3bec0,
+ 0x0c218ba4, 0x31906778, 0xda87408f, 0xe736ac53, 0xa1e49937,
+ 0x9c5575eb, 0x2c40f3ff, 0x11f11f23, 0x57232a47, 0x6a92c69b,
+ 0xec79202e, 0xd1c8ccf2, 0x971af996, 0xaaab154a, 0x1abe935e,
+ 0x270f7f82, 0x61dd4ae6, 0x5c6ca63a, 0xd9040692, 0xe4b5ea4e,
+ 0xa267df2a, 0x9fd633f6, 0x2fc3b5e2, 0x1272593e, 0x54a06c5a,
+ 0x69118086, 0xeffa6633, 0xd24b8aef, 0x9499bf8b, 0xa9285357,
+ 0x193dd543, 0x248c399f, 0x625e0cfb, 0x5fefe027, 0xb4f8c7d0,
+ 0x89492b0c, 0xcf9b1e68, 0xf22af2b4, 0x423f74a0, 0x7f8e987c,
+ 0x395cad18, 0x04ed41c4, 0x8206a771, 0xbfb74bad, 0xf9657ec9,
+ 0xc4d49215, 0x74c11401, 0x4970f8dd, 0x0fa2cdb9, 0x32132165,
+ 0x02fd8416, 0x3f4c68ca, 0x799e5dae, 0x442fb172, 0xf43a3766,
+ 0xc98bdbba, 0x8f59eede, 0xb2e80202, 0x3403e4b7, 0x09b2086b,
+ 0x4f603d0f, 0x72d1d1d3, 0xc2c457c7, 0xff75bb1b, 0xb9a78e7f,
+ 0x841662a3, 0x6f014554, 0x52b0a988, 0x14629cec, 0x29d37030,
+ 0x99c6f624, 0xa4771af8, 0xe2a52f9c, 0xdf14c340, 0x59ff25f5,
+ 0x644ec929, 0x229cfc4d, 0x1f2d1091, 0xaf389685, 0x92897a59,
+ 0xd45b4f3d, 0xe9eaa3e1, 0xb58605db, 0x8837e907, 0xcee5dc63,
+ 0xf35430bf, 0x4341b6ab, 0x7ef05a77, 0x38226f13, 0x059383cf,
+ 0x8378657a, 0xbec989a6, 0xf81bbcc2, 0xc5aa501e, 0x75bfd60a,
+ 0x480e3ad6, 0x0edc0fb2, 0x336de36e, 0xd87ac499, 0xe5cb2845,
+ 0xa3191d21, 0x9ea8f1fd, 0x2ebd77e9, 0x130c9b35, 0x55deae51,
+ 0x686f428d, 0xee84a438, 0xd33548e4, 0x95e77d80, 0xa856915c,
+ 0x18431748, 0x25f2fb94, 0x6320cef0, 0x5e91222c, 0x6e7f875f,
+ 0x53ce6b83, 0x151c5ee7, 0x28adb23b, 0x98b8342f, 0xa509d8f3,
+ 0xe3dbed97, 0xde6a014b, 0x5881e7fe, 0x65300b22, 0x23e23e46,
+ 0x1e53d29a, 0xae46548e, 0x93f7b852, 0xd5258d36, 0xe89461ea,
+ 0x0383461d, 0x3e32aac1, 0x78e09fa5, 0x45517379, 0xf544f56d,
+ 0xc8f519b1, 0x8e272cd5, 0xb396c009, 0x357d26bc, 0x08ccca60,
+ 0x4e1eff04, 0x73af13d8, 0xc3ba95cc, 0xfe0b7910, 0xb8d94c74,
+ 0x8568a0a8},
+ {0x00000000, 0x69790b65, 0xd2f216ca, 0xbb8b1daf, 0x7e952bd5,
+ 0x17ec20b0, 0xac673d1f, 0xc51e367a, 0xfd2a57aa, 0x94535ccf,
+ 0x2fd84160, 0x46a14a05, 0x83bf7c7f, 0xeac6771a, 0x514d6ab5,
+ 0x383461d0, 0x2125a915, 0x485ca270, 0xf3d7bfdf, 0x9aaeb4ba,
+ 0x5fb082c0, 0x36c989a5, 0x8d42940a, 0xe43b9f6f, 0xdc0ffebf,
+ 0xb576f5da, 0x0efde875, 0x6784e310, 0xa29ad56a, 0xcbe3de0f,
+ 0x7068c3a0, 0x1911c8c5, 0x424b522a, 0x2b32594f, 0x90b944e0,
+ 0xf9c04f85, 0x3cde79ff, 0x55a7729a, 0xee2c6f35, 0x87556450,
+ 0xbf610580, 0xd6180ee5, 0x6d93134a, 0x04ea182f, 0xc1f42e55,
+ 0xa88d2530, 0x1306389f, 0x7a7f33fa, 0x636efb3f, 0x0a17f05a,
+ 0xb19cedf5, 0xd8e5e690, 0x1dfbd0ea, 0x7482db8f, 0xcf09c620,
+ 0xa670cd45, 0x9e44ac95, 0xf73da7f0, 0x4cb6ba5f, 0x25cfb13a,
+ 0xe0d18740, 0x89a88c25, 0x3223918a, 0x5b5a9aef, 0x8496a454,
+ 0xedefaf31, 0x5664b29e, 0x3f1db9fb, 0xfa038f81, 0x937a84e4,
+ 0x28f1994b, 0x4188922e, 0x79bcf3fe, 0x10c5f89b, 0xab4ee534,
+ 0xc237ee51, 0x0729d82b, 0x6e50d34e, 0xd5dbcee1, 0xbca2c584,
+ 0xa5b30d41, 0xccca0624, 0x77411b8b, 0x1e3810ee, 0xdb262694,
+ 0xb25f2df1, 0x09d4305e, 0x60ad3b3b, 0x58995aeb, 0x31e0518e,
+ 0x8a6b4c21, 0xe3124744, 0x260c713e, 0x4f757a5b, 0xf4fe67f4,
+ 0x9d876c91, 0xc6ddf67e, 0xafa4fd1b, 0x142fe0b4, 0x7d56ebd1,
+ 0xb848ddab, 0xd131d6ce, 0x6abacb61, 0x03c3c004, 0x3bf7a1d4,
+ 0x528eaab1, 0xe905b71e, 0x807cbc7b, 0x45628a01, 0x2c1b8164,
+ 0x97909ccb, 0xfee997ae, 0xe7f85f6b, 0x8e81540e, 0x350a49a1,
+ 0x5c7342c4, 0x996d74be, 0xf0147fdb, 0x4b9f6274, 0x22e66911,
+ 0x1ad208c1, 0x73ab03a4, 0xc8201e0b, 0xa159156e, 0x64472314,
+ 0x0d3e2871, 0xb6b535de, 0xdfcc3ebb, 0xd25c4ee9, 0xbb25458c,
+ 0x00ae5823, 0x69d75346, 0xacc9653c, 0xc5b06e59, 0x7e3b73f6,
+ 0x17427893, 0x2f761943, 0x460f1226, 0xfd840f89, 0x94fd04ec,
+ 0x51e33296, 0x389a39f3, 0x8311245c, 0xea682f39, 0xf379e7fc,
+ 0x9a00ec99, 0x218bf136, 0x48f2fa53, 0x8deccc29, 0xe495c74c,
+ 0x5f1edae3, 0x3667d186, 0x0e53b056, 0x672abb33, 0xdca1a69c,
+ 0xb5d8adf9, 0x70c69b83, 0x19bf90e6, 0xa2348d49, 0xcb4d862c,
+ 0x90171cc3, 0xf96e17a6, 0x42e50a09, 0x2b9c016c, 0xee823716,
+ 0x87fb3c73, 0x3c7021dc, 0x55092ab9, 0x6d3d4b69, 0x0444400c,
+ 0xbfcf5da3, 0xd6b656c6, 0x13a860bc, 0x7ad16bd9, 0xc15a7676,
+ 0xa8237d13, 0xb132b5d6, 0xd84bbeb3, 0x63c0a31c, 0x0ab9a879,
+ 0xcfa79e03, 0xa6de9566, 0x1d5588c9, 0x742c83ac, 0x4c18e27c,
+ 0x2561e919, 0x9eeaf4b6, 0xf793ffd3, 0x328dc9a9, 0x5bf4c2cc,
+ 0xe07fdf63, 0x8906d406, 0x56caeabd, 0x3fb3e1d8, 0x8438fc77,
+ 0xed41f712, 0x285fc168, 0x4126ca0d, 0xfaadd7a2, 0x93d4dcc7,
+ 0xabe0bd17, 0xc299b672, 0x7912abdd, 0x106ba0b8, 0xd57596c2,
+ 0xbc0c9da7, 0x07878008, 0x6efe8b6d, 0x77ef43a8, 0x1e9648cd,
+ 0xa51d5562, 0xcc645e07, 0x097a687d, 0x60036318, 0xdb887eb7,
+ 0xb2f175d2, 0x8ac51402, 0xe3bc1f67, 0x583702c8, 0x314e09ad,
+ 0xf4503fd7, 0x9d2934b2, 0x26a2291d, 0x4fdb2278, 0x1481b897,
+ 0x7df8b3f2, 0xc673ae5d, 0xaf0aa538, 0x6a149342, 0x036d9827,
+ 0xb8e68588, 0xd19f8eed, 0xe9abef3d, 0x80d2e458, 0x3b59f9f7,
+ 0x5220f292, 0x973ec4e8, 0xfe47cf8d, 0x45ccd222, 0x2cb5d947,
+ 0x35a41182, 0x5cdd1ae7, 0xe7560748, 0x8e2f0c2d, 0x4b313a57,
+ 0x22483132, 0x99c32c9d, 0xf0ba27f8, 0xc88e4628, 0xa1f74d4d,
+ 0x1a7c50e2, 0x73055b87, 0xb61b6dfd, 0xdf626698, 0x64e97b37,
+ 0x0d907052},
+ {0x00000000, 0x7fc99b93, 0xff933726, 0x805aacb5, 0x2457680d,
+ 0x5b9ef39e, 0xdbc45f2b, 0xa40dc4b8, 0x48aed01a, 0x37674b89,
+ 0xb73de73c, 0xc8f47caf, 0x6cf9b817, 0x13302384, 0x936a8f31,
+ 0xeca314a2, 0x915da034, 0xee943ba7, 0x6ece9712, 0x11070c81,
+ 0xb50ac839, 0xcac353aa, 0x4a99ff1f, 0x3550648c, 0xd9f3702e,
+ 0xa63aebbd, 0x26604708, 0x59a9dc9b, 0xfda41823, 0x826d83b0,
+ 0x02372f05, 0x7dfeb496, 0xf9ca4629, 0x8603ddba, 0x0659710f,
+ 0x7990ea9c, 0xdd9d2e24, 0xa254b5b7, 0x220e1902, 0x5dc78291,
+ 0xb1649633, 0xcead0da0, 0x4ef7a115, 0x313e3a86, 0x9533fe3e,
+ 0xeafa65ad, 0x6aa0c918, 0x1569528b, 0x6897e61d, 0x175e7d8e,
+ 0x9704d13b, 0xe8cd4aa8, 0x4cc08e10, 0x33091583, 0xb353b936,
+ 0xcc9a22a5, 0x20393607, 0x5ff0ad94, 0xdfaa0121, 0xa0639ab2,
+ 0x046e5e0a, 0x7ba7c599, 0xfbfd692c, 0x8434f2bf, 0x28e58a13,
+ 0x572c1180, 0xd776bd35, 0xa8bf26a6, 0x0cb2e21e, 0x737b798d,
+ 0xf321d538, 0x8ce84eab, 0x604b5a09, 0x1f82c19a, 0x9fd86d2f,
+ 0xe011f6bc, 0x441c3204, 0x3bd5a997, 0xbb8f0522, 0xc4469eb1,
+ 0xb9b82a27, 0xc671b1b4, 0x462b1d01, 0x39e28692, 0x9def422a,
+ 0xe226d9b9, 0x627c750c, 0x1db5ee9f, 0xf116fa3d, 0x8edf61ae,
+ 0x0e85cd1b, 0x714c5688, 0xd5419230, 0xaa8809a3, 0x2ad2a516,
+ 0x551b3e85, 0xd12fcc3a, 0xaee657a9, 0x2ebcfb1c, 0x5175608f,
+ 0xf578a437, 0x8ab13fa4, 0x0aeb9311, 0x75220882, 0x99811c20,
+ 0xe64887b3, 0x66122b06, 0x19dbb095, 0xbdd6742d, 0xc21fefbe,
+ 0x4245430b, 0x3d8cd898, 0x40726c0e, 0x3fbbf79d, 0xbfe15b28,
+ 0xc028c0bb, 0x64250403, 0x1bec9f90, 0x9bb63325, 0xe47fa8b6,
+ 0x08dcbc14, 0x77152787, 0xf74f8b32, 0x888610a1, 0x2c8bd419,
+ 0x53424f8a, 0xd318e33f, 0xacd178ac, 0x51cb1426, 0x2e028fb5,
+ 0xae582300, 0xd191b893, 0x759c7c2b, 0x0a55e7b8, 0x8a0f4b0d,
+ 0xf5c6d09e, 0x1965c43c, 0x66ac5faf, 0xe6f6f31a, 0x993f6889,
+ 0x3d32ac31, 0x42fb37a2, 0xc2a19b17, 0xbd680084, 0xc096b412,
+ 0xbf5f2f81, 0x3f058334, 0x40cc18a7, 0xe4c1dc1f, 0x9b08478c,
+ 0x1b52eb39, 0x649b70aa, 0x88386408, 0xf7f1ff9b, 0x77ab532e,
+ 0x0862c8bd, 0xac6f0c05, 0xd3a69796, 0x53fc3b23, 0x2c35a0b0,
+ 0xa801520f, 0xd7c8c99c, 0x57926529, 0x285bfeba, 0x8c563a02,
+ 0xf39fa191, 0x73c50d24, 0x0c0c96b7, 0xe0af8215, 0x9f661986,
+ 0x1f3cb533, 0x60f52ea0, 0xc4f8ea18, 0xbb31718b, 0x3b6bdd3e,
+ 0x44a246ad, 0x395cf23b, 0x469569a8, 0xc6cfc51d, 0xb9065e8e,
+ 0x1d0b9a36, 0x62c201a5, 0xe298ad10, 0x9d513683, 0x71f22221,
+ 0x0e3bb9b2, 0x8e611507, 0xf1a88e94, 0x55a54a2c, 0x2a6cd1bf,
+ 0xaa367d0a, 0xd5ffe699, 0x792e9e35, 0x06e705a6, 0x86bda913,
+ 0xf9743280, 0x5d79f638, 0x22b06dab, 0xa2eac11e, 0xdd235a8d,
+ 0x31804e2f, 0x4e49d5bc, 0xce137909, 0xb1dae29a, 0x15d72622,
+ 0x6a1ebdb1, 0xea441104, 0x958d8a97, 0xe8733e01, 0x97baa592,
+ 0x17e00927, 0x682992b4, 0xcc24560c, 0xb3edcd9f, 0x33b7612a,
+ 0x4c7efab9, 0xa0ddee1b, 0xdf147588, 0x5f4ed93d, 0x208742ae,
+ 0x848a8616, 0xfb431d85, 0x7b19b130, 0x04d02aa3, 0x80e4d81c,
+ 0xff2d438f, 0x7f77ef3a, 0x00be74a9, 0xa4b3b011, 0xdb7a2b82,
+ 0x5b208737, 0x24e91ca4, 0xc84a0806, 0xb7839395, 0x37d93f20,
+ 0x4810a4b3, 0xec1d600b, 0x93d4fb98, 0x138e572d, 0x6c47ccbe,
+ 0x11b97828, 0x6e70e3bb, 0xee2a4f0e, 0x91e3d49d, 0x35ee1025,
+ 0x4a278bb6, 0xca7d2703, 0xb5b4bc90, 0x5917a832, 0x26de33a1,
+ 0xa6849f14, 0xd94d0487, 0x7d40c03f, 0x02895bac, 0x82d3f719,
+ 0xfd1a6c8a},
+ {0x00000000, 0xa396284c, 0x9c5d56d9, 0x3fcb7e95, 0xe3cbabf3,
+ 0x405d83bf, 0x7f96fd2a, 0xdc00d566, 0x1ce651a7, 0xbf7079eb,
+ 0x80bb077e, 0x232d2f32, 0xff2dfa54, 0x5cbbd218, 0x6370ac8d,
+ 0xc0e684c1, 0x39cca34e, 0x9a5a8b02, 0xa591f597, 0x0607dddb,
+ 0xda0708bd, 0x799120f1, 0x465a5e64, 0xe5cc7628, 0x252af2e9,
+ 0x86bcdaa5, 0xb977a430, 0x1ae18c7c, 0xc6e1591a, 0x65777156,
+ 0x5abc0fc3, 0xf92a278f, 0x7399469c, 0xd00f6ed0, 0xefc41045,
+ 0x4c523809, 0x9052ed6f, 0x33c4c523, 0x0c0fbbb6, 0xaf9993fa,
+ 0x6f7f173b, 0xcce93f77, 0xf32241e2, 0x50b469ae, 0x8cb4bcc8,
+ 0x2f229484, 0x10e9ea11, 0xb37fc25d, 0x4a55e5d2, 0xe9c3cd9e,
+ 0xd608b30b, 0x759e9b47, 0xa99e4e21, 0x0a08666d, 0x35c318f8,
+ 0x965530b4, 0x56b3b475, 0xf5259c39, 0xcaeee2ac, 0x6978cae0,
+ 0xb5781f86, 0x16ee37ca, 0x2925495f, 0x8ab36113, 0xe7328d38,
+ 0x44a4a574, 0x7b6fdbe1, 0xd8f9f3ad, 0x04f926cb, 0xa76f0e87,
+ 0x98a47012, 0x3b32585e, 0xfbd4dc9f, 0x5842f4d3, 0x67898a46,
+ 0xc41fa20a, 0x181f776c, 0xbb895f20, 0x844221b5, 0x27d409f9,
+ 0xdefe2e76, 0x7d68063a, 0x42a378af, 0xe13550e3, 0x3d358585,
+ 0x9ea3adc9, 0xa168d35c, 0x02fefb10, 0xc2187fd1, 0x618e579d,
+ 0x5e452908, 0xfdd30144, 0x21d3d422, 0x8245fc6e, 0xbd8e82fb,
+ 0x1e18aab7, 0x94abcba4, 0x373de3e8, 0x08f69d7d, 0xab60b531,
+ 0x77606057, 0xd4f6481b, 0xeb3d368e, 0x48ab1ec2, 0x884d9a03,
+ 0x2bdbb24f, 0x1410ccda, 0xb786e496, 0x6b8631f0, 0xc81019bc,
+ 0xf7db6729, 0x544d4f65, 0xad6768ea, 0x0ef140a6, 0x313a3e33,
+ 0x92ac167f, 0x4eacc319, 0xed3aeb55, 0xd2f195c0, 0x7167bd8c,
+ 0xb181394d, 0x12171101, 0x2ddc6f94, 0x8e4a47d8, 0x524a92be,
+ 0xf1dcbaf2, 0xce17c467, 0x6d81ec2b, 0x15141c31, 0xb682347d,
+ 0x89494ae8, 0x2adf62a4, 0xf6dfb7c2, 0x55499f8e, 0x6a82e11b,
+ 0xc914c957, 0x09f24d96, 0xaa6465da, 0x95af1b4f, 0x36393303,
+ 0xea39e665, 0x49afce29, 0x7664b0bc, 0xd5f298f0, 0x2cd8bf7f,
+ 0x8f4e9733, 0xb085e9a6, 0x1313c1ea, 0xcf13148c, 0x6c853cc0,
+ 0x534e4255, 0xf0d86a19, 0x303eeed8, 0x93a8c694, 0xac63b801,
+ 0x0ff5904d, 0xd3f5452b, 0x70636d67, 0x4fa813f2, 0xec3e3bbe,
+ 0x668d5aad, 0xc51b72e1, 0xfad00c74, 0x59462438, 0x8546f15e,
+ 0x26d0d912, 0x191ba787, 0xba8d8fcb, 0x7a6b0b0a, 0xd9fd2346,
+ 0xe6365dd3, 0x45a0759f, 0x99a0a0f9, 0x3a3688b5, 0x05fdf620,
+ 0xa66bde6c, 0x5f41f9e3, 0xfcd7d1af, 0xc31caf3a, 0x608a8776,
+ 0xbc8a5210, 0x1f1c7a5c, 0x20d704c9, 0x83412c85, 0x43a7a844,
+ 0xe0318008, 0xdffafe9d, 0x7c6cd6d1, 0xa06c03b7, 0x03fa2bfb,
+ 0x3c31556e, 0x9fa77d22, 0xf2269109, 0x51b0b945, 0x6e7bc7d0,
+ 0xcdedef9c, 0x11ed3afa, 0xb27b12b6, 0x8db06c23, 0x2e26446f,
+ 0xeec0c0ae, 0x4d56e8e2, 0x729d9677, 0xd10bbe3b, 0x0d0b6b5d,
+ 0xae9d4311, 0x91563d84, 0x32c015c8, 0xcbea3247, 0x687c1a0b,
+ 0x57b7649e, 0xf4214cd2, 0x282199b4, 0x8bb7b1f8, 0xb47ccf6d,
+ 0x17eae721, 0xd70c63e0, 0x749a4bac, 0x4b513539, 0xe8c71d75,
+ 0x34c7c813, 0x9751e05f, 0xa89a9eca, 0x0b0cb686, 0x81bfd795,
+ 0x2229ffd9, 0x1de2814c, 0xbe74a900, 0x62747c66, 0xc1e2542a,
+ 0xfe292abf, 0x5dbf02f3, 0x9d598632, 0x3ecfae7e, 0x0104d0eb,
+ 0xa292f8a7, 0x7e922dc1, 0xdd04058d, 0xe2cf7b18, 0x41595354,
+ 0xb87374db, 0x1be55c97, 0x242e2202, 0x87b80a4e, 0x5bb8df28,
+ 0xf82ef764, 0xc7e589f1, 0x6473a1bd, 0xa495257c, 0x07030d30,
+ 0x38c873a5, 0x9b5e5be9, 0x475e8e8f, 0xe4c8a6c3, 0xdb03d856,
+ 0x7895f01a},
+ {0x00000000, 0x2a283862, 0x545070c4, 0x7e7848a6, 0xa8a0e188,
+ 0x8288d9ea, 0xfcf0914c, 0xd6d8a92e, 0x8a30c551, 0xa018fd33,
+ 0xde60b595, 0xf4488df7, 0x229024d9, 0x08b81cbb, 0x76c0541d,
+ 0x5ce86c7f, 0xcf108ce3, 0xe538b481, 0x9b40fc27, 0xb168c445,
+ 0x67b06d6b, 0x4d985509, 0x33e01daf, 0x19c825cd, 0x452049b2,
+ 0x6f0871d0, 0x11703976, 0x3b580114, 0xed80a83a, 0xc7a89058,
+ 0xb9d0d8fe, 0x93f8e09c, 0x45501f87, 0x6f7827e5, 0x11006f43,
+ 0x3b285721, 0xedf0fe0f, 0xc7d8c66d, 0xb9a08ecb, 0x9388b6a9,
+ 0xcf60dad6, 0xe548e2b4, 0x9b30aa12, 0xb1189270, 0x67c03b5e,
+ 0x4de8033c, 0x33904b9a, 0x19b873f8, 0x8a409364, 0xa068ab06,
+ 0xde10e3a0, 0xf438dbc2, 0x22e072ec, 0x08c84a8e, 0x76b00228,
+ 0x5c983a4a, 0x00705635, 0x2a586e57, 0x542026f1, 0x7e081e93,
+ 0xa8d0b7bd, 0x82f88fdf, 0xfc80c779, 0xd6a8ff1b, 0x8aa03f0e,
+ 0xa088076c, 0xdef04fca, 0xf4d877a8, 0x2200de86, 0x0828e6e4,
+ 0x7650ae42, 0x5c789620, 0x0090fa5f, 0x2ab8c23d, 0x54c08a9b,
+ 0x7ee8b2f9, 0xa8301bd7, 0x821823b5, 0xfc606b13, 0xd6485371,
+ 0x45b0b3ed, 0x6f988b8f, 0x11e0c329, 0x3bc8fb4b, 0xed105265,
+ 0xc7386a07, 0xb94022a1, 0x93681ac3, 0xcf8076bc, 0xe5a84ede,
+ 0x9bd00678, 0xb1f83e1a, 0x67209734, 0x4d08af56, 0x3370e7f0,
+ 0x1958df92, 0xcff02089, 0xe5d818eb, 0x9ba0504d, 0xb188682f,
+ 0x6750c101, 0x4d78f963, 0x3300b1c5, 0x192889a7, 0x45c0e5d8,
+ 0x6fe8ddba, 0x1190951c, 0x3bb8ad7e, 0xed600450, 0xc7483c32,
+ 0xb9307494, 0x93184cf6, 0x00e0ac6a, 0x2ac89408, 0x54b0dcae,
+ 0x7e98e4cc, 0xa8404de2, 0x82687580, 0xfc103d26, 0xd6380544,
+ 0x8ad0693b, 0xa0f85159, 0xde8019ff, 0xf4a8219d, 0x227088b3,
+ 0x0858b0d1, 0x7620f877, 0x5c08c015, 0xce31785d, 0xe419403f,
+ 0x9a610899, 0xb04930fb, 0x669199d5, 0x4cb9a1b7, 0x32c1e911,
+ 0x18e9d173, 0x4401bd0c, 0x6e29856e, 0x1051cdc8, 0x3a79f5aa,
+ 0xeca15c84, 0xc68964e6, 0xb8f12c40, 0x92d91422, 0x0121f4be,
+ 0x2b09ccdc, 0x5571847a, 0x7f59bc18, 0xa9811536, 0x83a92d54,
+ 0xfdd165f2, 0xd7f95d90, 0x8b1131ef, 0xa139098d, 0xdf41412b,
+ 0xf5697949, 0x23b1d067, 0x0999e805, 0x77e1a0a3, 0x5dc998c1,
+ 0x8b6167da, 0xa1495fb8, 0xdf31171e, 0xf5192f7c, 0x23c18652,
+ 0x09e9be30, 0x7791f696, 0x5db9cef4, 0x0151a28b, 0x2b799ae9,
+ 0x5501d24f, 0x7f29ea2d, 0xa9f14303, 0x83d97b61, 0xfda133c7,
+ 0xd7890ba5, 0x4471eb39, 0x6e59d35b, 0x10219bfd, 0x3a09a39f,
+ 0xecd10ab1, 0xc6f932d3, 0xb8817a75, 0x92a94217, 0xce412e68,
+ 0xe469160a, 0x9a115eac, 0xb03966ce, 0x66e1cfe0, 0x4cc9f782,
+ 0x32b1bf24, 0x18998746, 0x44914753, 0x6eb97f31, 0x10c13797,
+ 0x3ae90ff5, 0xec31a6db, 0xc6199eb9, 0xb861d61f, 0x9249ee7d,
+ 0xcea18202, 0xe489ba60, 0x9af1f2c6, 0xb0d9caa4, 0x6601638a,
+ 0x4c295be8, 0x3251134e, 0x18792b2c, 0x8b81cbb0, 0xa1a9f3d2,
+ 0xdfd1bb74, 0xf5f98316, 0x23212a38, 0x0909125a, 0x77715afc,
+ 0x5d59629e, 0x01b10ee1, 0x2b993683, 0x55e17e25, 0x7fc94647,
+ 0xa911ef69, 0x8339d70b, 0xfd419fad, 0xd769a7cf, 0x01c158d4,
+ 0x2be960b6, 0x55912810, 0x7fb91072, 0xa961b95c, 0x8349813e,
+ 0xfd31c998, 0xd719f1fa, 0x8bf19d85, 0xa1d9a5e7, 0xdfa1ed41,
+ 0xf589d523, 0x23517c0d, 0x0979446f, 0x77010cc9, 0x5d2934ab,
+ 0xced1d437, 0xe4f9ec55, 0x9a81a4f3, 0xb0a99c91, 0x667135bf,
+ 0x4c590ddd, 0x3221457b, 0x18097d19, 0x44e11166, 0x6ec92904,
+ 0x10b161a2, 0x3a9959c0, 0xec41f0ee, 0xc669c88c, 0xb811802a,
+ 0x9239b848},
+ {0x00000000, 0x4713f6fb, 0x8e27edf6, 0xc9341b0d, 0xc73eddad,
+ 0x802d2b56, 0x4919305b, 0x0e0ac6a0, 0x550cbd1b, 0x121f4be0,
+ 0xdb2b50ed, 0x9c38a616, 0x923260b6, 0xd521964d, 0x1c158d40,
+ 0x5b067bbb, 0xaa197a36, 0xed0a8ccd, 0x243e97c0, 0x632d613b,
+ 0x6d27a79b, 0x2a345160, 0xe3004a6d, 0xa413bc96, 0xff15c72d,
+ 0xb80631d6, 0x71322adb, 0x3621dc20, 0x382b1a80, 0x7f38ec7b,
+ 0xb60cf776, 0xf11f018d, 0x8f43f22d, 0xc85004d6, 0x01641fdb,
+ 0x4677e920, 0x487d2f80, 0x0f6ed97b, 0xc65ac276, 0x8149348d,
+ 0xda4f4f36, 0x9d5cb9cd, 0x5468a2c0, 0x137b543b, 0x1d71929b,
+ 0x5a626460, 0x93567f6d, 0xd4458996, 0x255a881b, 0x62497ee0,
+ 0xab7d65ed, 0xec6e9316, 0xe26455b6, 0xa577a34d, 0x6c43b840,
+ 0x2b504ebb, 0x70563500, 0x3745c3fb, 0xfe71d8f6, 0xb9622e0d,
+ 0xb768e8ad, 0xf07b1e56, 0x394f055b, 0x7e5cf3a0, 0xc5f6e21b,
+ 0x82e514e0, 0x4bd10fed, 0x0cc2f916, 0x02c83fb6, 0x45dbc94d,
+ 0x8cefd240, 0xcbfc24bb, 0x90fa5f00, 0xd7e9a9fb, 0x1eddb2f6,
+ 0x59ce440d, 0x57c482ad, 0x10d77456, 0xd9e36f5b, 0x9ef099a0,
+ 0x6fef982d, 0x28fc6ed6, 0xe1c875db, 0xa6db8320, 0xa8d14580,
+ 0xefc2b37b, 0x26f6a876, 0x61e55e8d, 0x3ae32536, 0x7df0d3cd,
+ 0xb4c4c8c0, 0xf3d73e3b, 0xfdddf89b, 0xbace0e60, 0x73fa156d,
+ 0x34e9e396, 0x4ab51036, 0x0da6e6cd, 0xc492fdc0, 0x83810b3b,
+ 0x8d8bcd9b, 0xca983b60, 0x03ac206d, 0x44bfd696, 0x1fb9ad2d,
+ 0x58aa5bd6, 0x919e40db, 0xd68db620, 0xd8877080, 0x9f94867b,
+ 0x56a09d76, 0x11b36b8d, 0xe0ac6a00, 0xa7bf9cfb, 0x6e8b87f6,
+ 0x2998710d, 0x2792b7ad, 0x60814156, 0xa9b55a5b, 0xeea6aca0,
+ 0xb5a0d71b, 0xf2b321e0, 0x3b873aed, 0x7c94cc16, 0x729e0ab6,
+ 0x358dfc4d, 0xfcb9e740, 0xbbaa11bb, 0x509cc277, 0x178f348c,
+ 0xdebb2f81, 0x99a8d97a, 0x97a21fda, 0xd0b1e921, 0x1985f22c,
+ 0x5e9604d7, 0x05907f6c, 0x42838997, 0x8bb7929a, 0xcca46461,
+ 0xc2aea2c1, 0x85bd543a, 0x4c894f37, 0x0b9ab9cc, 0xfa85b841,
+ 0xbd964eba, 0x74a255b7, 0x33b1a34c, 0x3dbb65ec, 0x7aa89317,
+ 0xb39c881a, 0xf48f7ee1, 0xaf89055a, 0xe89af3a1, 0x21aee8ac,
+ 0x66bd1e57, 0x68b7d8f7, 0x2fa42e0c, 0xe6903501, 0xa183c3fa,
+ 0xdfdf305a, 0x98ccc6a1, 0x51f8ddac, 0x16eb2b57, 0x18e1edf7,
+ 0x5ff21b0c, 0x96c60001, 0xd1d5f6fa, 0x8ad38d41, 0xcdc07bba,
+ 0x04f460b7, 0x43e7964c, 0x4ded50ec, 0x0afea617, 0xc3cabd1a,
+ 0x84d94be1, 0x75c64a6c, 0x32d5bc97, 0xfbe1a79a, 0xbcf25161,
+ 0xb2f897c1, 0xf5eb613a, 0x3cdf7a37, 0x7bcc8ccc, 0x20caf777,
+ 0x67d9018c, 0xaeed1a81, 0xe9feec7a, 0xe7f42ada, 0xa0e7dc21,
+ 0x69d3c72c, 0x2ec031d7, 0x956a206c, 0xd279d697, 0x1b4dcd9a,
+ 0x5c5e3b61, 0x5254fdc1, 0x15470b3a, 0xdc731037, 0x9b60e6cc,
+ 0xc0669d77, 0x87756b8c, 0x4e417081, 0x0952867a, 0x075840da,
+ 0x404bb621, 0x897fad2c, 0xce6c5bd7, 0x3f735a5a, 0x7860aca1,
+ 0xb154b7ac, 0xf6474157, 0xf84d87f7, 0xbf5e710c, 0x766a6a01,
+ 0x31799cfa, 0x6a7fe741, 0x2d6c11ba, 0xe4580ab7, 0xa34bfc4c,
+ 0xad413aec, 0xea52cc17, 0x2366d71a, 0x647521e1, 0x1a29d241,
+ 0x5d3a24ba, 0x940e3fb7, 0xd31dc94c, 0xdd170fec, 0x9a04f917,
+ 0x5330e21a, 0x142314e1, 0x4f256f5a, 0x083699a1, 0xc10282ac,
+ 0x86117457, 0x881bb2f7, 0xcf08440c, 0x063c5f01, 0x412fa9fa,
+ 0xb030a877, 0xf7235e8c, 0x3e174581, 0x7904b37a, 0x770e75da,
+ 0x301d8321, 0xf929982c, 0xbe3a6ed7, 0xe53c156c, 0xa22fe397,
+ 0x6b1bf89a, 0x2c080e61, 0x2202c8c1, 0x65113e3a, 0xac252537,
+ 0xeb36d3cc},
+ {0x00000000, 0xa13984ee, 0x99020f9d, 0x383b8b73, 0xe975197b,
+ 0x484c9d95, 0x707716e6, 0xd14e9208, 0x099b34b7, 0xa8a2b059,
+ 0x90993b2a, 0x31a0bfc4, 0xe0ee2dcc, 0x41d7a922, 0x79ec2251,
+ 0xd8d5a6bf, 0x1336696e, 0xb20fed80, 0x8a3466f3, 0x2b0de21d,
+ 0xfa437015, 0x5b7af4fb, 0x63417f88, 0xc278fb66, 0x1aad5dd9,
+ 0xbb94d937, 0x83af5244, 0x2296d6aa, 0xf3d844a2, 0x52e1c04c,
+ 0x6ada4b3f, 0xcbe3cfd1, 0x266cd2dc, 0x87555632, 0xbf6edd41,
+ 0x1e5759af, 0xcf19cba7, 0x6e204f49, 0x561bc43a, 0xf72240d4,
+ 0x2ff7e66b, 0x8ece6285, 0xb6f5e9f6, 0x17cc6d18, 0xc682ff10,
+ 0x67bb7bfe, 0x5f80f08d, 0xfeb97463, 0x355abbb2, 0x94633f5c,
+ 0xac58b42f, 0x0d6130c1, 0xdc2fa2c9, 0x7d162627, 0x452dad54,
+ 0xe41429ba, 0x3cc18f05, 0x9df80beb, 0xa5c38098, 0x04fa0476,
+ 0xd5b4967e, 0x748d1290, 0x4cb699e3, 0xed8f1d0d, 0x4cd9a5b8,
+ 0xede02156, 0xd5dbaa25, 0x74e22ecb, 0xa5acbcc3, 0x0495382d,
+ 0x3caeb35e, 0x9d9737b0, 0x4542910f, 0xe47b15e1, 0xdc409e92,
+ 0x7d791a7c, 0xac378874, 0x0d0e0c9a, 0x353587e9, 0x940c0307,
+ 0x5fefccd6, 0xfed64838, 0xc6edc34b, 0x67d447a5, 0xb69ad5ad,
+ 0x17a35143, 0x2f98da30, 0x8ea15ede, 0x5674f861, 0xf74d7c8f,
+ 0xcf76f7fc, 0x6e4f7312, 0xbf01e11a, 0x1e3865f4, 0x2603ee87,
+ 0x873a6a69, 0x6ab57764, 0xcb8cf38a, 0xf3b778f9, 0x528efc17,
+ 0x83c06e1f, 0x22f9eaf1, 0x1ac26182, 0xbbfbe56c, 0x632e43d3,
+ 0xc217c73d, 0xfa2c4c4e, 0x5b15c8a0, 0x8a5b5aa8, 0x2b62de46,
+ 0x13595535, 0xb260d1db, 0x79831e0a, 0xd8ba9ae4, 0xe0811197,
+ 0x41b89579, 0x90f60771, 0x31cf839f, 0x09f408ec, 0xa8cd8c02,
+ 0x70182abd, 0xd121ae53, 0xe91a2520, 0x4823a1ce, 0x996d33c6,
+ 0x3854b728, 0x006f3c5b, 0xa156b8b5, 0x99b34b70, 0x388acf9e,
+ 0x00b144ed, 0xa188c003, 0x70c6520b, 0xd1ffd6e5, 0xe9c45d96,
+ 0x48fdd978, 0x90287fc7, 0x3111fb29, 0x092a705a, 0xa813f4b4,
+ 0x795d66bc, 0xd864e252, 0xe05f6921, 0x4166edcf, 0x8a85221e,
+ 0x2bbca6f0, 0x13872d83, 0xb2bea96d, 0x63f03b65, 0xc2c9bf8b,
+ 0xfaf234f8, 0x5bcbb016, 0x831e16a9, 0x22279247, 0x1a1c1934,
+ 0xbb259dda, 0x6a6b0fd2, 0xcb528b3c, 0xf369004f, 0x525084a1,
+ 0xbfdf99ac, 0x1ee61d42, 0x26dd9631, 0x87e412df, 0x56aa80d7,
+ 0xf7930439, 0xcfa88f4a, 0x6e910ba4, 0xb644ad1b, 0x177d29f5,
+ 0x2f46a286, 0x8e7f2668, 0x5f31b460, 0xfe08308e, 0xc633bbfd,
+ 0x670a3f13, 0xace9f0c2, 0x0dd0742c, 0x35ebff5f, 0x94d27bb1,
+ 0x459ce9b9, 0xe4a56d57, 0xdc9ee624, 0x7da762ca, 0xa572c475,
+ 0x044b409b, 0x3c70cbe8, 0x9d494f06, 0x4c07dd0e, 0xed3e59e0,
+ 0xd505d293, 0x743c567d, 0xd56aeec8, 0x74536a26, 0x4c68e155,
+ 0xed5165bb, 0x3c1ff7b3, 0x9d26735d, 0xa51df82e, 0x04247cc0,
+ 0xdcf1da7f, 0x7dc85e91, 0x45f3d5e2, 0xe4ca510c, 0x3584c304,
+ 0x94bd47ea, 0xac86cc99, 0x0dbf4877, 0xc65c87a6, 0x67650348,
+ 0x5f5e883b, 0xfe670cd5, 0x2f299edd, 0x8e101a33, 0xb62b9140,
+ 0x171215ae, 0xcfc7b311, 0x6efe37ff, 0x56c5bc8c, 0xf7fc3862,
+ 0x26b2aa6a, 0x878b2e84, 0xbfb0a5f7, 0x1e892119, 0xf3063c14,
+ 0x523fb8fa, 0x6a043389, 0xcb3db767, 0x1a73256f, 0xbb4aa181,
+ 0x83712af2, 0x2248ae1c, 0xfa9d08a3, 0x5ba48c4d, 0x639f073e,
+ 0xc2a683d0, 0x13e811d8, 0xb2d19536, 0x8aea1e45, 0x2bd39aab,
+ 0xe030557a, 0x4109d194, 0x79325ae7, 0xd80bde09, 0x09454c01,
+ 0xa87cc8ef, 0x9047439c, 0x317ec772, 0xe9ab61cd, 0x4892e523,
+ 0x70a96e50, 0xd190eabe, 0x00de78b6, 0xa1e7fc58, 0x99dc772b,
+ 0x38e5f3c5},
+ {0x00000000, 0xe81790a1, 0x0b5e2703, 0xe349b7a2, 0x16bc4e06,
+ 0xfeabdea7, 0x1de26905, 0xf5f5f9a4, 0x2d789c0c, 0xc56f0cad,
+ 0x2626bb0f, 0xce312bae, 0x3bc4d20a, 0xd3d342ab, 0x309af509,
+ 0xd88d65a8, 0x5af13818, 0xb2e6a8b9, 0x51af1f1b, 0xb9b88fba,
+ 0x4c4d761e, 0xa45ae6bf, 0x4713511d, 0xaf04c1bc, 0x7789a414,
+ 0x9f9e34b5, 0x7cd78317, 0x94c013b6, 0x6135ea12, 0x89227ab3,
+ 0x6a6bcd11, 0x827c5db0, 0xb5e27030, 0x5df5e091, 0xbebc5733,
+ 0x56abc792, 0xa35e3e36, 0x4b49ae97, 0xa8001935, 0x40178994,
+ 0x989aec3c, 0x708d7c9d, 0x93c4cb3f, 0x7bd35b9e, 0x8e26a23a,
+ 0x6631329b, 0x85788539, 0x6d6f1598, 0xef134828, 0x0704d889,
+ 0xe44d6f2b, 0x0c5aff8a, 0xf9af062e, 0x11b8968f, 0xf2f1212d,
+ 0x1ae6b18c, 0xc26bd424, 0x2a7c4485, 0xc935f327, 0x21226386,
+ 0xd4d79a22, 0x3cc00a83, 0xdf89bd21, 0x379e2d80, 0xb0b5e621,
+ 0x58a27680, 0xbbebc122, 0x53fc5183, 0xa609a827, 0x4e1e3886,
+ 0xad578f24, 0x45401f85, 0x9dcd7a2d, 0x75daea8c, 0x96935d2e,
+ 0x7e84cd8f, 0x8b71342b, 0x6366a48a, 0x802f1328, 0x68388389,
+ 0xea44de39, 0x02534e98, 0xe11af93a, 0x090d699b, 0xfcf8903f,
+ 0x14ef009e, 0xf7a6b73c, 0x1fb1279d, 0xc73c4235, 0x2f2bd294,
+ 0xcc626536, 0x2475f597, 0xd1800c33, 0x39979c92, 0xdade2b30,
+ 0x32c9bb91, 0x05579611, 0xed4006b0, 0x0e09b112, 0xe61e21b3,
+ 0x13ebd817, 0xfbfc48b6, 0x18b5ff14, 0xf0a26fb5, 0x282f0a1d,
+ 0xc0389abc, 0x23712d1e, 0xcb66bdbf, 0x3e93441b, 0xd684d4ba,
+ 0x35cd6318, 0xdddaf3b9, 0x5fa6ae09, 0xb7b13ea8, 0x54f8890a,
+ 0xbcef19ab, 0x491ae00f, 0xa10d70ae, 0x4244c70c, 0xaa5357ad,
+ 0x72de3205, 0x9ac9a2a4, 0x79801506, 0x919785a7, 0x64627c03,
+ 0x8c75eca2, 0x6f3c5b00, 0x872bcba1, 0xba1aca03, 0x520d5aa2,
+ 0xb144ed00, 0x59537da1, 0xaca68405, 0x44b114a4, 0xa7f8a306,
+ 0x4fef33a7, 0x9762560f, 0x7f75c6ae, 0x9c3c710c, 0x742be1ad,
+ 0x81de1809, 0x69c988a8, 0x8a803f0a, 0x6297afab, 0xe0ebf21b,
+ 0x08fc62ba, 0xebb5d518, 0x03a245b9, 0xf657bc1d, 0x1e402cbc,
+ 0xfd099b1e, 0x151e0bbf, 0xcd936e17, 0x2584feb6, 0xc6cd4914,
+ 0x2edad9b5, 0xdb2f2011, 0x3338b0b0, 0xd0710712, 0x386697b3,
+ 0x0ff8ba33, 0xe7ef2a92, 0x04a69d30, 0xecb10d91, 0x1944f435,
+ 0xf1536494, 0x121ad336, 0xfa0d4397, 0x2280263f, 0xca97b69e,
+ 0x29de013c, 0xc1c9919d, 0x343c6839, 0xdc2bf898, 0x3f624f3a,
+ 0xd775df9b, 0x5509822b, 0xbd1e128a, 0x5e57a528, 0xb6403589,
+ 0x43b5cc2d, 0xaba25c8c, 0x48ebeb2e, 0xa0fc7b8f, 0x78711e27,
+ 0x90668e86, 0x732f3924, 0x9b38a985, 0x6ecd5021, 0x86dac080,
+ 0x65937722, 0x8d84e783, 0x0aaf2c22, 0xe2b8bc83, 0x01f10b21,
+ 0xe9e69b80, 0x1c136224, 0xf404f285, 0x174d4527, 0xff5ad586,
+ 0x27d7b02e, 0xcfc0208f, 0x2c89972d, 0xc49e078c, 0x316bfe28,
+ 0xd97c6e89, 0x3a35d92b, 0xd222498a, 0x505e143a, 0xb849849b,
+ 0x5b003339, 0xb317a398, 0x46e25a3c, 0xaef5ca9d, 0x4dbc7d3f,
+ 0xa5abed9e, 0x7d268836, 0x95311897, 0x7678af35, 0x9e6f3f94,
+ 0x6b9ac630, 0x838d5691, 0x60c4e133, 0x88d37192, 0xbf4d5c12,
+ 0x575accb3, 0xb4137b11, 0x5c04ebb0, 0xa9f11214, 0x41e682b5,
+ 0xa2af3517, 0x4ab8a5b6, 0x9235c01e, 0x7a2250bf, 0x996be71d,
+ 0x717c77bc, 0x84898e18, 0x6c9e1eb9, 0x8fd7a91b, 0x67c039ba,
+ 0xe5bc640a, 0x0dabf4ab, 0xeee24309, 0x06f5d3a8, 0xf3002a0c,
+ 0x1b17baad, 0xf85e0d0f, 0x10499dae, 0xc8c4f806, 0x20d368a7,
+ 0xc39adf05, 0x2b8d4fa4, 0xde78b600, 0x366f26a1, 0xd5269103,
+ 0x3d3101a2}};
+
+local const z_word_t FAR crc_braid_big_table[][256] = {
+ {0x0000000000000000, 0xa19017e800000000, 0x03275e0b00000000,
+ 0xa2b749e300000000, 0x064ebc1600000000, 0xa7deabfe00000000,
+ 0x0569e21d00000000, 0xa4f9f5f500000000, 0x0c9c782d00000000,
+ 0xad0c6fc500000000, 0x0fbb262600000000, 0xae2b31ce00000000,
+ 0x0ad2c43b00000000, 0xab42d3d300000000, 0x09f59a3000000000,
+ 0xa8658dd800000000, 0x1838f15a00000000, 0xb9a8e6b200000000,
+ 0x1b1faf5100000000, 0xba8fb8b900000000, 0x1e764d4c00000000,
+ 0xbfe65aa400000000, 0x1d51134700000000, 0xbcc104af00000000,
+ 0x14a4897700000000, 0xb5349e9f00000000, 0x1783d77c00000000,
+ 0xb613c09400000000, 0x12ea356100000000, 0xb37a228900000000,
+ 0x11cd6b6a00000000, 0xb05d7c8200000000, 0x3070e2b500000000,
+ 0x91e0f55d00000000, 0x3357bcbe00000000, 0x92c7ab5600000000,
+ 0x363e5ea300000000, 0x97ae494b00000000, 0x351900a800000000,
+ 0x9489174000000000, 0x3cec9a9800000000, 0x9d7c8d7000000000,
+ 0x3fcbc49300000000, 0x9e5bd37b00000000, 0x3aa2268e00000000,
+ 0x9b32316600000000, 0x3985788500000000, 0x98156f6d00000000,
+ 0x284813ef00000000, 0x89d8040700000000, 0x2b6f4de400000000,
+ 0x8aff5a0c00000000, 0x2e06aff900000000, 0x8f96b81100000000,
+ 0x2d21f1f200000000, 0x8cb1e61a00000000, 0x24d46bc200000000,
+ 0x85447c2a00000000, 0x27f335c900000000, 0x8663222100000000,
+ 0x229ad7d400000000, 0x830ac03c00000000, 0x21bd89df00000000,
+ 0x802d9e3700000000, 0x21e6b5b000000000, 0x8076a25800000000,
+ 0x22c1ebbb00000000, 0x8351fc5300000000, 0x27a809a600000000,
+ 0x86381e4e00000000, 0x248f57ad00000000, 0x851f404500000000,
+ 0x2d7acd9d00000000, 0x8ceada7500000000, 0x2e5d939600000000,
+ 0x8fcd847e00000000, 0x2b34718b00000000, 0x8aa4666300000000,
+ 0x28132f8000000000, 0x8983386800000000, 0x39de44ea00000000,
+ 0x984e530200000000, 0x3af91ae100000000, 0x9b690d0900000000,
+ 0x3f90f8fc00000000, 0x9e00ef1400000000, 0x3cb7a6f700000000,
+ 0x9d27b11f00000000, 0x35423cc700000000, 0x94d22b2f00000000,
+ 0x366562cc00000000, 0x97f5752400000000, 0x330c80d100000000,
+ 0x929c973900000000, 0x302bdeda00000000, 0x91bbc93200000000,
+ 0x1196570500000000, 0xb00640ed00000000, 0x12b1090e00000000,
+ 0xb3211ee600000000, 0x17d8eb1300000000, 0xb648fcfb00000000,
+ 0x14ffb51800000000, 0xb56fa2f000000000, 0x1d0a2f2800000000,
+ 0xbc9a38c000000000, 0x1e2d712300000000, 0xbfbd66cb00000000,
+ 0x1b44933e00000000, 0xbad484d600000000, 0x1863cd3500000000,
+ 0xb9f3dadd00000000, 0x09aea65f00000000, 0xa83eb1b700000000,
+ 0x0a89f85400000000, 0xab19efbc00000000, 0x0fe01a4900000000,
+ 0xae700da100000000, 0x0cc7444200000000, 0xad5753aa00000000,
+ 0x0532de7200000000, 0xa4a2c99a00000000, 0x0615807900000000,
+ 0xa785979100000000, 0x037c626400000000, 0xa2ec758c00000000,
+ 0x005b3c6f00000000, 0xa1cb2b8700000000, 0x03ca1aba00000000,
+ 0xa25a0d5200000000, 0x00ed44b100000000, 0xa17d535900000000,
+ 0x0584a6ac00000000, 0xa414b14400000000, 0x06a3f8a700000000,
+ 0xa733ef4f00000000, 0x0f56629700000000, 0xaec6757f00000000,
+ 0x0c713c9c00000000, 0xade12b7400000000, 0x0918de8100000000,
+ 0xa888c96900000000, 0x0a3f808a00000000, 0xabaf976200000000,
+ 0x1bf2ebe000000000, 0xba62fc0800000000, 0x18d5b5eb00000000,
+ 0xb945a20300000000, 0x1dbc57f600000000, 0xbc2c401e00000000,
+ 0x1e9b09fd00000000, 0xbf0b1e1500000000, 0x176e93cd00000000,
+ 0xb6fe842500000000, 0x1449cdc600000000, 0xb5d9da2e00000000,
+ 0x11202fdb00000000, 0xb0b0383300000000, 0x120771d000000000,
+ 0xb397663800000000, 0x33baf80f00000000, 0x922aefe700000000,
+ 0x309da60400000000, 0x910db1ec00000000, 0x35f4441900000000,
+ 0x946453f100000000, 0x36d31a1200000000, 0x97430dfa00000000,
+ 0x3f26802200000000, 0x9eb697ca00000000, 0x3c01de2900000000,
+ 0x9d91c9c100000000, 0x39683c3400000000, 0x98f82bdc00000000,
+ 0x3a4f623f00000000, 0x9bdf75d700000000, 0x2b82095500000000,
+ 0x8a121ebd00000000, 0x28a5575e00000000, 0x893540b600000000,
+ 0x2dccb54300000000, 0x8c5ca2ab00000000, 0x2eebeb4800000000,
+ 0x8f7bfca000000000, 0x271e717800000000, 0x868e669000000000,
+ 0x24392f7300000000, 0x85a9389b00000000, 0x2150cd6e00000000,
+ 0x80c0da8600000000, 0x2277936500000000, 0x83e7848d00000000,
+ 0x222caf0a00000000, 0x83bcb8e200000000, 0x210bf10100000000,
+ 0x809be6e900000000, 0x2462131c00000000, 0x85f204f400000000,
+ 0x27454d1700000000, 0x86d55aff00000000, 0x2eb0d72700000000,
+ 0x8f20c0cf00000000, 0x2d97892c00000000, 0x8c079ec400000000,
+ 0x28fe6b3100000000, 0x896e7cd900000000, 0x2bd9353a00000000,
+ 0x8a4922d200000000, 0x3a145e5000000000, 0x9b8449b800000000,
+ 0x3933005b00000000, 0x98a317b300000000, 0x3c5ae24600000000,
+ 0x9dcaf5ae00000000, 0x3f7dbc4d00000000, 0x9eedaba500000000,
+ 0x3688267d00000000, 0x9718319500000000, 0x35af787600000000,
+ 0x943f6f9e00000000, 0x30c69a6b00000000, 0x91568d8300000000,
+ 0x33e1c46000000000, 0x9271d38800000000, 0x125c4dbf00000000,
+ 0xb3cc5a5700000000, 0x117b13b400000000, 0xb0eb045c00000000,
+ 0x1412f1a900000000, 0xb582e64100000000, 0x1735afa200000000,
+ 0xb6a5b84a00000000, 0x1ec0359200000000, 0xbf50227a00000000,
+ 0x1de76b9900000000, 0xbc777c7100000000, 0x188e898400000000,
+ 0xb91e9e6c00000000, 0x1ba9d78f00000000, 0xba39c06700000000,
+ 0x0a64bce500000000, 0xabf4ab0d00000000, 0x0943e2ee00000000,
+ 0xa8d3f50600000000, 0x0c2a00f300000000, 0xadba171b00000000,
+ 0x0f0d5ef800000000, 0xae9d491000000000, 0x06f8c4c800000000,
+ 0xa768d32000000000, 0x05df9ac300000000, 0xa44f8d2b00000000,
+ 0x00b678de00000000, 0xa1266f3600000000, 0x039126d500000000,
+ 0xa201313d00000000},
+ {0x0000000000000000, 0xee8439a100000000, 0x9d0f029900000000,
+ 0x738b3b3800000000, 0x7b1975e900000000, 0x959d4c4800000000,
+ 0xe616777000000000, 0x08924ed100000000, 0xb7349b0900000000,
+ 0x59b0a2a800000000, 0x2a3b999000000000, 0xc4bfa03100000000,
+ 0xcc2deee000000000, 0x22a9d74100000000, 0x5122ec7900000000,
+ 0xbfa6d5d800000000, 0x6e69361300000000, 0x80ed0fb200000000,
+ 0xf366348a00000000, 0x1de20d2b00000000, 0x157043fa00000000,
+ 0xfbf47a5b00000000, 0x887f416300000000, 0x66fb78c200000000,
+ 0xd95dad1a00000000, 0x37d994bb00000000, 0x4452af8300000000,
+ 0xaad6962200000000, 0xa244d8f300000000, 0x4cc0e15200000000,
+ 0x3f4bda6a00000000, 0xd1cfe3cb00000000, 0xdcd26c2600000000,
+ 0x3256558700000000, 0x41dd6ebf00000000, 0xaf59571e00000000,
+ 0xa7cb19cf00000000, 0x494f206e00000000, 0x3ac41b5600000000,
+ 0xd44022f700000000, 0x6be6f72f00000000, 0x8562ce8e00000000,
+ 0xf6e9f5b600000000, 0x186dcc1700000000, 0x10ff82c600000000,
+ 0xfe7bbb6700000000, 0x8df0805f00000000, 0x6374b9fe00000000,
+ 0xb2bb5a3500000000, 0x5c3f639400000000, 0x2fb458ac00000000,
+ 0xc130610d00000000, 0xc9a22fdc00000000, 0x2726167d00000000,
+ 0x54ad2d4500000000, 0xba2914e400000000, 0x058fc13c00000000,
+ 0xeb0bf89d00000000, 0x9880c3a500000000, 0x7604fa0400000000,
+ 0x7e96b4d500000000, 0x90128d7400000000, 0xe399b64c00000000,
+ 0x0d1d8fed00000000, 0xb8a5d94c00000000, 0x5621e0ed00000000,
+ 0x25aadbd500000000, 0xcb2ee27400000000, 0xc3bcaca500000000,
+ 0x2d38950400000000, 0x5eb3ae3c00000000, 0xb037979d00000000,
+ 0x0f91424500000000, 0xe1157be400000000, 0x929e40dc00000000,
+ 0x7c1a797d00000000, 0x748837ac00000000, 0x9a0c0e0d00000000,
+ 0xe987353500000000, 0x07030c9400000000, 0xd6ccef5f00000000,
+ 0x3848d6fe00000000, 0x4bc3edc600000000, 0xa547d46700000000,
+ 0xadd59ab600000000, 0x4351a31700000000, 0x30da982f00000000,
+ 0xde5ea18e00000000, 0x61f8745600000000, 0x8f7c4df700000000,
+ 0xfcf776cf00000000, 0x12734f6e00000000, 0x1ae101bf00000000,
+ 0xf465381e00000000, 0x87ee032600000000, 0x696a3a8700000000,
+ 0x6477b56a00000000, 0x8af38ccb00000000, 0xf978b7f300000000,
+ 0x17fc8e5200000000, 0x1f6ec08300000000, 0xf1eaf92200000000,
+ 0x8261c21a00000000, 0x6ce5fbbb00000000, 0xd3432e6300000000,
+ 0x3dc717c200000000, 0x4e4c2cfa00000000, 0xa0c8155b00000000,
+ 0xa85a5b8a00000000, 0x46de622b00000000, 0x3555591300000000,
+ 0xdbd160b200000000, 0x0a1e837900000000, 0xe49abad800000000,
+ 0x971181e000000000, 0x7995b84100000000, 0x7107f69000000000,
+ 0x9f83cf3100000000, 0xec08f40900000000, 0x028ccda800000000,
+ 0xbd2a187000000000, 0x53ae21d100000000, 0x20251ae900000000,
+ 0xcea1234800000000, 0xc6336d9900000000, 0x28b7543800000000,
+ 0x5b3c6f0000000000, 0xb5b856a100000000, 0x704bb39900000000,
+ 0x9ecf8a3800000000, 0xed44b10000000000, 0x03c088a100000000,
+ 0x0b52c67000000000, 0xe5d6ffd100000000, 0x965dc4e900000000,
+ 0x78d9fd4800000000, 0xc77f289000000000, 0x29fb113100000000,
+ 0x5a702a0900000000, 0xb4f413a800000000, 0xbc665d7900000000,
+ 0x52e264d800000000, 0x21695fe000000000, 0xcfed664100000000,
+ 0x1e22858a00000000, 0xf0a6bc2b00000000, 0x832d871300000000,
+ 0x6da9beb200000000, 0x653bf06300000000, 0x8bbfc9c200000000,
+ 0xf834f2fa00000000, 0x16b0cb5b00000000, 0xa9161e8300000000,
+ 0x4792272200000000, 0x34191c1a00000000, 0xda9d25bb00000000,
+ 0xd20f6b6a00000000, 0x3c8b52cb00000000, 0x4f0069f300000000,
+ 0xa184505200000000, 0xac99dfbf00000000, 0x421de61e00000000,
+ 0x3196dd2600000000, 0xdf12e48700000000, 0xd780aa5600000000,
+ 0x390493f700000000, 0x4a8fa8cf00000000, 0xa40b916e00000000,
+ 0x1bad44b600000000, 0xf5297d1700000000, 0x86a2462f00000000,
+ 0x68267f8e00000000, 0x60b4315f00000000, 0x8e3008fe00000000,
+ 0xfdbb33c600000000, 0x133f0a6700000000, 0xc2f0e9ac00000000,
+ 0x2c74d00d00000000, 0x5fffeb3500000000, 0xb17bd29400000000,
+ 0xb9e99c4500000000, 0x576da5e400000000, 0x24e69edc00000000,
+ 0xca62a77d00000000, 0x75c472a500000000, 0x9b404b0400000000,
+ 0xe8cb703c00000000, 0x064f499d00000000, 0x0edd074c00000000,
+ 0xe0593eed00000000, 0x93d205d500000000, 0x7d563c7400000000,
+ 0xc8ee6ad500000000, 0x266a537400000000, 0x55e1684c00000000,
+ 0xbb6551ed00000000, 0xb3f71f3c00000000, 0x5d73269d00000000,
+ 0x2ef81da500000000, 0xc07c240400000000, 0x7fdaf1dc00000000,
+ 0x915ec87d00000000, 0xe2d5f34500000000, 0x0c51cae400000000,
+ 0x04c3843500000000, 0xea47bd9400000000, 0x99cc86ac00000000,
+ 0x7748bf0d00000000, 0xa6875cc600000000, 0x4803656700000000,
+ 0x3b885e5f00000000, 0xd50c67fe00000000, 0xdd9e292f00000000,
+ 0x331a108e00000000, 0x40912bb600000000, 0xae15121700000000,
+ 0x11b3c7cf00000000, 0xff37fe6e00000000, 0x8cbcc55600000000,
+ 0x6238fcf700000000, 0x6aaab22600000000, 0x842e8b8700000000,
+ 0xf7a5b0bf00000000, 0x1921891e00000000, 0x143c06f300000000,
+ 0xfab83f5200000000, 0x8933046a00000000, 0x67b73dcb00000000,
+ 0x6f25731a00000000, 0x81a14abb00000000, 0xf22a718300000000,
+ 0x1cae482200000000, 0xa3089dfa00000000, 0x4d8ca45b00000000,
+ 0x3e079f6300000000, 0xd083a6c200000000, 0xd811e81300000000,
+ 0x3695d1b200000000, 0x451eea8a00000000, 0xab9ad32b00000000,
+ 0x7a5530e000000000, 0x94d1094100000000, 0xe75a327900000000,
+ 0x09de0bd800000000, 0x014c450900000000, 0xefc87ca800000000,
+ 0x9c43479000000000, 0x72c77e3100000000, 0xcd61abe900000000,
+ 0x23e5924800000000, 0x506ea97000000000, 0xbeea90d100000000,
+ 0xb678de0000000000, 0x58fce7a100000000, 0x2b77dc9900000000,
+ 0xc5f3e53800000000},
+ {0x0000000000000000, 0xfbf6134700000000, 0xf6ed278e00000000,
+ 0x0d1b34c900000000, 0xaddd3ec700000000, 0x562b2d8000000000,
+ 0x5b30194900000000, 0xa0c60a0e00000000, 0x1bbd0c5500000000,
+ 0xe04b1f1200000000, 0xed502bdb00000000, 0x16a6389c00000000,
+ 0xb660329200000000, 0x4d9621d500000000, 0x408d151c00000000,
+ 0xbb7b065b00000000, 0x367a19aa00000000, 0xcd8c0aed00000000,
+ 0xc0973e2400000000, 0x3b612d6300000000, 0x9ba7276d00000000,
+ 0x6051342a00000000, 0x6d4a00e300000000, 0x96bc13a400000000,
+ 0x2dc715ff00000000, 0xd63106b800000000, 0xdb2a327100000000,
+ 0x20dc213600000000, 0x801a2b3800000000, 0x7bec387f00000000,
+ 0x76f70cb600000000, 0x8d011ff100000000, 0x2df2438f00000000,
+ 0xd60450c800000000, 0xdb1f640100000000, 0x20e9774600000000,
+ 0x802f7d4800000000, 0x7bd96e0f00000000, 0x76c25ac600000000,
+ 0x8d34498100000000, 0x364f4fda00000000, 0xcdb95c9d00000000,
+ 0xc0a2685400000000, 0x3b547b1300000000, 0x9b92711d00000000,
+ 0x6064625a00000000, 0x6d7f569300000000, 0x968945d400000000,
+ 0x1b885a2500000000, 0xe07e496200000000, 0xed657dab00000000,
+ 0x16936eec00000000, 0xb65564e200000000, 0x4da377a500000000,
+ 0x40b8436c00000000, 0xbb4e502b00000000, 0x0035567000000000,
+ 0xfbc3453700000000, 0xf6d871fe00000000, 0x0d2e62b900000000,
+ 0xade868b700000000, 0x561e7bf000000000, 0x5b054f3900000000,
+ 0xa0f35c7e00000000, 0x1be2f6c500000000, 0xe014e58200000000,
+ 0xed0fd14b00000000, 0x16f9c20c00000000, 0xb63fc80200000000,
+ 0x4dc9db4500000000, 0x40d2ef8c00000000, 0xbb24fccb00000000,
+ 0x005ffa9000000000, 0xfba9e9d700000000, 0xf6b2dd1e00000000,
+ 0x0d44ce5900000000, 0xad82c45700000000, 0x5674d71000000000,
+ 0x5b6fe3d900000000, 0xa099f09e00000000, 0x2d98ef6f00000000,
+ 0xd66efc2800000000, 0xdb75c8e100000000, 0x2083dba600000000,
+ 0x8045d1a800000000, 0x7bb3c2ef00000000, 0x76a8f62600000000,
+ 0x8d5ee56100000000, 0x3625e33a00000000, 0xcdd3f07d00000000,
+ 0xc0c8c4b400000000, 0x3b3ed7f300000000, 0x9bf8ddfd00000000,
+ 0x600eceba00000000, 0x6d15fa7300000000, 0x96e3e93400000000,
+ 0x3610b54a00000000, 0xcde6a60d00000000, 0xc0fd92c400000000,
+ 0x3b0b818300000000, 0x9bcd8b8d00000000, 0x603b98ca00000000,
+ 0x6d20ac0300000000, 0x96d6bf4400000000, 0x2dadb91f00000000,
+ 0xd65baa5800000000, 0xdb409e9100000000, 0x20b68dd600000000,
+ 0x807087d800000000, 0x7b86949f00000000, 0x769da05600000000,
+ 0x8d6bb31100000000, 0x006aace000000000, 0xfb9cbfa700000000,
+ 0xf6878b6e00000000, 0x0d71982900000000, 0xadb7922700000000,
+ 0x5641816000000000, 0x5b5ab5a900000000, 0xa0aca6ee00000000,
+ 0x1bd7a0b500000000, 0xe021b3f200000000, 0xed3a873b00000000,
+ 0x16cc947c00000000, 0xb60a9e7200000000, 0x4dfc8d3500000000,
+ 0x40e7b9fc00000000, 0xbb11aabb00000000, 0x77c29c5000000000,
+ 0x8c348f1700000000, 0x812fbbde00000000, 0x7ad9a89900000000,
+ 0xda1fa29700000000, 0x21e9b1d000000000, 0x2cf2851900000000,
+ 0xd704965e00000000, 0x6c7f900500000000, 0x9789834200000000,
+ 0x9a92b78b00000000, 0x6164a4cc00000000, 0xc1a2aec200000000,
+ 0x3a54bd8500000000, 0x374f894c00000000, 0xccb99a0b00000000,
+ 0x41b885fa00000000, 0xba4e96bd00000000, 0xb755a27400000000,
+ 0x4ca3b13300000000, 0xec65bb3d00000000, 0x1793a87a00000000,
+ 0x1a889cb300000000, 0xe17e8ff400000000, 0x5a0589af00000000,
+ 0xa1f39ae800000000, 0xace8ae2100000000, 0x571ebd6600000000,
+ 0xf7d8b76800000000, 0x0c2ea42f00000000, 0x013590e600000000,
+ 0xfac383a100000000, 0x5a30dfdf00000000, 0xa1c6cc9800000000,
+ 0xacddf85100000000, 0x572beb1600000000, 0xf7ede11800000000,
+ 0x0c1bf25f00000000, 0x0100c69600000000, 0xfaf6d5d100000000,
+ 0x418dd38a00000000, 0xba7bc0cd00000000, 0xb760f40400000000,
+ 0x4c96e74300000000, 0xec50ed4d00000000, 0x17a6fe0a00000000,
+ 0x1abdcac300000000, 0xe14bd98400000000, 0x6c4ac67500000000,
+ 0x97bcd53200000000, 0x9aa7e1fb00000000, 0x6151f2bc00000000,
+ 0xc197f8b200000000, 0x3a61ebf500000000, 0x377adf3c00000000,
+ 0xcc8ccc7b00000000, 0x77f7ca2000000000, 0x8c01d96700000000,
+ 0x811aedae00000000, 0x7aecfee900000000, 0xda2af4e700000000,
+ 0x21dce7a000000000, 0x2cc7d36900000000, 0xd731c02e00000000,
+ 0x6c206a9500000000, 0x97d679d200000000, 0x9acd4d1b00000000,
+ 0x613b5e5c00000000, 0xc1fd545200000000, 0x3a0b471500000000,
+ 0x371073dc00000000, 0xcce6609b00000000, 0x779d66c000000000,
+ 0x8c6b758700000000, 0x8170414e00000000, 0x7a86520900000000,
+ 0xda40580700000000, 0x21b64b4000000000, 0x2cad7f8900000000,
+ 0xd75b6cce00000000, 0x5a5a733f00000000, 0xa1ac607800000000,
+ 0xacb754b100000000, 0x574147f600000000, 0xf7874df800000000,
+ 0x0c715ebf00000000, 0x016a6a7600000000, 0xfa9c793100000000,
+ 0x41e77f6a00000000, 0xba116c2d00000000, 0xb70a58e400000000,
+ 0x4cfc4ba300000000, 0xec3a41ad00000000, 0x17cc52ea00000000,
+ 0x1ad7662300000000, 0xe121756400000000, 0x41d2291a00000000,
+ 0xba243a5d00000000, 0xb73f0e9400000000, 0x4cc91dd300000000,
+ 0xec0f17dd00000000, 0x17f9049a00000000, 0x1ae2305300000000,
+ 0xe114231400000000, 0x5a6f254f00000000, 0xa199360800000000,
+ 0xac8202c100000000, 0x5774118600000000, 0xf7b21b8800000000,
+ 0x0c4408cf00000000, 0x015f3c0600000000, 0xfaa92f4100000000,
+ 0x77a830b000000000, 0x8c5e23f700000000, 0x8145173e00000000,
+ 0x7ab3047900000000, 0xda750e7700000000, 0x21831d3000000000,
+ 0x2c9829f900000000, 0xd76e3abe00000000, 0x6c153ce500000000,
+ 0x97e32fa200000000, 0x9af81b6b00000000, 0x610e082c00000000,
+ 0xc1c8022200000000, 0x3a3e116500000000, 0x372525ac00000000,
+ 0xccd336eb00000000},
+ {0x0000000000000000, 0x6238282a00000000, 0xc470505400000000,
+ 0xa648787e00000000, 0x88e1a0a800000000, 0xead9888200000000,
+ 0x4c91f0fc00000000, 0x2ea9d8d600000000, 0x51c5308a00000000,
+ 0x33fd18a000000000, 0x95b560de00000000, 0xf78d48f400000000,
+ 0xd924902200000000, 0xbb1cb80800000000, 0x1d54c07600000000,
+ 0x7f6ce85c00000000, 0xe38c10cf00000000, 0x81b438e500000000,
+ 0x27fc409b00000000, 0x45c468b100000000, 0x6b6db06700000000,
+ 0x0955984d00000000, 0xaf1de03300000000, 0xcd25c81900000000,
+ 0xb249204500000000, 0xd071086f00000000, 0x7639701100000000,
+ 0x1401583b00000000, 0x3aa880ed00000000, 0x5890a8c700000000,
+ 0xfed8d0b900000000, 0x9ce0f89300000000, 0x871f504500000000,
+ 0xe527786f00000000, 0x436f001100000000, 0x2157283b00000000,
+ 0x0ffef0ed00000000, 0x6dc6d8c700000000, 0xcb8ea0b900000000,
+ 0xa9b6889300000000, 0xd6da60cf00000000, 0xb4e248e500000000,
+ 0x12aa309b00000000, 0x709218b100000000, 0x5e3bc06700000000,
+ 0x3c03e84d00000000, 0x9a4b903300000000, 0xf873b81900000000,
+ 0x6493408a00000000, 0x06ab68a000000000, 0xa0e310de00000000,
+ 0xc2db38f400000000, 0xec72e02200000000, 0x8e4ac80800000000,
+ 0x2802b07600000000, 0x4a3a985c00000000, 0x3556700000000000,
+ 0x576e582a00000000, 0xf126205400000000, 0x931e087e00000000,
+ 0xbdb7d0a800000000, 0xdf8ff88200000000, 0x79c780fc00000000,
+ 0x1bffa8d600000000, 0x0e3fa08a00000000, 0x6c0788a000000000,
+ 0xca4ff0de00000000, 0xa877d8f400000000, 0x86de002200000000,
+ 0xe4e6280800000000, 0x42ae507600000000, 0x2096785c00000000,
+ 0x5ffa900000000000, 0x3dc2b82a00000000, 0x9b8ac05400000000,
+ 0xf9b2e87e00000000, 0xd71b30a800000000, 0xb523188200000000,
+ 0x136b60fc00000000, 0x715348d600000000, 0xedb3b04500000000,
+ 0x8f8b986f00000000, 0x29c3e01100000000, 0x4bfbc83b00000000,
+ 0x655210ed00000000, 0x076a38c700000000, 0xa12240b900000000,
+ 0xc31a689300000000, 0xbc7680cf00000000, 0xde4ea8e500000000,
+ 0x7806d09b00000000, 0x1a3ef8b100000000, 0x3497206700000000,
+ 0x56af084d00000000, 0xf0e7703300000000, 0x92df581900000000,
+ 0x8920f0cf00000000, 0xeb18d8e500000000, 0x4d50a09b00000000,
+ 0x2f6888b100000000, 0x01c1506700000000, 0x63f9784d00000000,
+ 0xc5b1003300000000, 0xa789281900000000, 0xd8e5c04500000000,
+ 0xbadde86f00000000, 0x1c95901100000000, 0x7eadb83b00000000,
+ 0x500460ed00000000, 0x323c48c700000000, 0x947430b900000000,
+ 0xf64c189300000000, 0x6aace00000000000, 0x0894c82a00000000,
+ 0xaedcb05400000000, 0xcce4987e00000000, 0xe24d40a800000000,
+ 0x8075688200000000, 0x263d10fc00000000, 0x440538d600000000,
+ 0x3b69d08a00000000, 0x5951f8a000000000, 0xff1980de00000000,
+ 0x9d21a8f400000000, 0xb388702200000000, 0xd1b0580800000000,
+ 0x77f8207600000000, 0x15c0085c00000000, 0x5d7831ce00000000,
+ 0x3f4019e400000000, 0x9908619a00000000, 0xfb3049b000000000,
+ 0xd599916600000000, 0xb7a1b94c00000000, 0x11e9c13200000000,
+ 0x73d1e91800000000, 0x0cbd014400000000, 0x6e85296e00000000,
+ 0xc8cd511000000000, 0xaaf5793a00000000, 0x845ca1ec00000000,
+ 0xe66489c600000000, 0x402cf1b800000000, 0x2214d99200000000,
+ 0xbef4210100000000, 0xdccc092b00000000, 0x7a84715500000000,
+ 0x18bc597f00000000, 0x361581a900000000, 0x542da98300000000,
+ 0xf265d1fd00000000, 0x905df9d700000000, 0xef31118b00000000,
+ 0x8d0939a100000000, 0x2b4141df00000000, 0x497969f500000000,
+ 0x67d0b12300000000, 0x05e8990900000000, 0xa3a0e17700000000,
+ 0xc198c95d00000000, 0xda67618b00000000, 0xb85f49a100000000,
+ 0x1e1731df00000000, 0x7c2f19f500000000, 0x5286c12300000000,
+ 0x30bee90900000000, 0x96f6917700000000, 0xf4ceb95d00000000,
+ 0x8ba2510100000000, 0xe99a792b00000000, 0x4fd2015500000000,
+ 0x2dea297f00000000, 0x0343f1a900000000, 0x617bd98300000000,
+ 0xc733a1fd00000000, 0xa50b89d700000000, 0x39eb714400000000,
+ 0x5bd3596e00000000, 0xfd9b211000000000, 0x9fa3093a00000000,
+ 0xb10ad1ec00000000, 0xd332f9c600000000, 0x757a81b800000000,
+ 0x1742a99200000000, 0x682e41ce00000000, 0x0a1669e400000000,
+ 0xac5e119a00000000, 0xce6639b000000000, 0xe0cfe16600000000,
+ 0x82f7c94c00000000, 0x24bfb13200000000, 0x4687991800000000,
+ 0x5347914400000000, 0x317fb96e00000000, 0x9737c11000000000,
+ 0xf50fe93a00000000, 0xdba631ec00000000, 0xb99e19c600000000,
+ 0x1fd661b800000000, 0x7dee499200000000, 0x0282a1ce00000000,
+ 0x60ba89e400000000, 0xc6f2f19a00000000, 0xa4cad9b000000000,
+ 0x8a63016600000000, 0xe85b294c00000000, 0x4e13513200000000,
+ 0x2c2b791800000000, 0xb0cb818b00000000, 0xd2f3a9a100000000,
+ 0x74bbd1df00000000, 0x1683f9f500000000, 0x382a212300000000,
+ 0x5a12090900000000, 0xfc5a717700000000, 0x9e62595d00000000,
+ 0xe10eb10100000000, 0x8336992b00000000, 0x257ee15500000000,
+ 0x4746c97f00000000, 0x69ef11a900000000, 0x0bd7398300000000,
+ 0xad9f41fd00000000, 0xcfa769d700000000, 0xd458c10100000000,
+ 0xb660e92b00000000, 0x1028915500000000, 0x7210b97f00000000,
+ 0x5cb961a900000000, 0x3e81498300000000, 0x98c931fd00000000,
+ 0xfaf119d700000000, 0x859df18b00000000, 0xe7a5d9a100000000,
+ 0x41eda1df00000000, 0x23d589f500000000, 0x0d7c512300000000,
+ 0x6f44790900000000, 0xc90c017700000000, 0xab34295d00000000,
+ 0x37d4d1ce00000000, 0x55ecf9e400000000, 0xf3a4819a00000000,
+ 0x919ca9b000000000, 0xbf35716600000000, 0xdd0d594c00000000,
+ 0x7b45213200000000, 0x197d091800000000, 0x6611e14400000000,
+ 0x0429c96e00000000, 0xa261b11000000000, 0xc059993a00000000,
+ 0xeef041ec00000000, 0x8cc869c600000000, 0x2a8011b800000000,
+ 0x48b8399200000000},
+ {0x0000000000000000, 0x4c2896a300000000, 0xd9565d9c00000000,
+ 0x957ecb3f00000000, 0xf3abcbe300000000, 0xbf835d4000000000,
+ 0x2afd967f00000000, 0x66d500dc00000000, 0xa751e61c00000000,
+ 0xeb7970bf00000000, 0x7e07bb8000000000, 0x322f2d2300000000,
+ 0x54fa2dff00000000, 0x18d2bb5c00000000, 0x8dac706300000000,
+ 0xc184e6c000000000, 0x4ea3cc3900000000, 0x028b5a9a00000000,
+ 0x97f591a500000000, 0xdbdd070600000000, 0xbd0807da00000000,
+ 0xf120917900000000, 0x645e5a4600000000, 0x2876cce500000000,
+ 0xe9f22a2500000000, 0xa5dabc8600000000, 0x30a477b900000000,
+ 0x7c8ce11a00000000, 0x1a59e1c600000000, 0x5671776500000000,
+ 0xc30fbc5a00000000, 0x8f272af900000000, 0x9c46997300000000,
+ 0xd06e0fd000000000, 0x4510c4ef00000000, 0x0938524c00000000,
+ 0x6fed529000000000, 0x23c5c43300000000, 0xb6bb0f0c00000000,
+ 0xfa9399af00000000, 0x3b177f6f00000000, 0x773fe9cc00000000,
+ 0xe24122f300000000, 0xae69b45000000000, 0xc8bcb48c00000000,
+ 0x8494222f00000000, 0x11eae91000000000, 0x5dc27fb300000000,
+ 0xd2e5554a00000000, 0x9ecdc3e900000000, 0x0bb308d600000000,
+ 0x479b9e7500000000, 0x214e9ea900000000, 0x6d66080a00000000,
+ 0xf818c33500000000, 0xb430559600000000, 0x75b4b35600000000,
+ 0x399c25f500000000, 0xace2eeca00000000, 0xe0ca786900000000,
+ 0x861f78b500000000, 0xca37ee1600000000, 0x5f49252900000000,
+ 0x1361b38a00000000, 0x388d32e700000000, 0x74a5a44400000000,
+ 0xe1db6f7b00000000, 0xadf3f9d800000000, 0xcb26f90400000000,
+ 0x870e6fa700000000, 0x1270a49800000000, 0x5e58323b00000000,
+ 0x9fdcd4fb00000000, 0xd3f4425800000000, 0x468a896700000000,
+ 0x0aa21fc400000000, 0x6c771f1800000000, 0x205f89bb00000000,
+ 0xb521428400000000, 0xf909d42700000000, 0x762efede00000000,
+ 0x3a06687d00000000, 0xaf78a34200000000, 0xe35035e100000000,
+ 0x8585353d00000000, 0xc9ada39e00000000, 0x5cd368a100000000,
+ 0x10fbfe0200000000, 0xd17f18c200000000, 0x9d578e6100000000,
+ 0x0829455e00000000, 0x4401d3fd00000000, 0x22d4d32100000000,
+ 0x6efc458200000000, 0xfb828ebd00000000, 0xb7aa181e00000000,
+ 0xa4cbab9400000000, 0xe8e33d3700000000, 0x7d9df60800000000,
+ 0x31b560ab00000000, 0x5760607700000000, 0x1b48f6d400000000,
+ 0x8e363deb00000000, 0xc21eab4800000000, 0x039a4d8800000000,
+ 0x4fb2db2b00000000, 0xdacc101400000000, 0x96e486b700000000,
+ 0xf031866b00000000, 0xbc1910c800000000, 0x2967dbf700000000,
+ 0x654f4d5400000000, 0xea6867ad00000000, 0xa640f10e00000000,
+ 0x333e3a3100000000, 0x7f16ac9200000000, 0x19c3ac4e00000000,
+ 0x55eb3aed00000000, 0xc095f1d200000000, 0x8cbd677100000000,
+ 0x4d3981b100000000, 0x0111171200000000, 0x946fdc2d00000000,
+ 0xd8474a8e00000000, 0xbe924a5200000000, 0xf2badcf100000000,
+ 0x67c417ce00000000, 0x2bec816d00000000, 0x311c141500000000,
+ 0x7d3482b600000000, 0xe84a498900000000, 0xa462df2a00000000,
+ 0xc2b7dff600000000, 0x8e9f495500000000, 0x1be1826a00000000,
+ 0x57c914c900000000, 0x964df20900000000, 0xda6564aa00000000,
+ 0x4f1baf9500000000, 0x0333393600000000, 0x65e639ea00000000,
+ 0x29ceaf4900000000, 0xbcb0647600000000, 0xf098f2d500000000,
+ 0x7fbfd82c00000000, 0x33974e8f00000000, 0xa6e985b000000000,
+ 0xeac1131300000000, 0x8c1413cf00000000, 0xc03c856c00000000,
+ 0x55424e5300000000, 0x196ad8f000000000, 0xd8ee3e3000000000,
+ 0x94c6a89300000000, 0x01b863ac00000000, 0x4d90f50f00000000,
+ 0x2b45f5d300000000, 0x676d637000000000, 0xf213a84f00000000,
+ 0xbe3b3eec00000000, 0xad5a8d6600000000, 0xe1721bc500000000,
+ 0x740cd0fa00000000, 0x3824465900000000, 0x5ef1468500000000,
+ 0x12d9d02600000000, 0x87a71b1900000000, 0xcb8f8dba00000000,
+ 0x0a0b6b7a00000000, 0x4623fdd900000000, 0xd35d36e600000000,
+ 0x9f75a04500000000, 0xf9a0a09900000000, 0xb588363a00000000,
+ 0x20f6fd0500000000, 0x6cde6ba600000000, 0xe3f9415f00000000,
+ 0xafd1d7fc00000000, 0x3aaf1cc300000000, 0x76878a6000000000,
+ 0x10528abc00000000, 0x5c7a1c1f00000000, 0xc904d72000000000,
+ 0x852c418300000000, 0x44a8a74300000000, 0x088031e000000000,
+ 0x9dfefadf00000000, 0xd1d66c7c00000000, 0xb7036ca000000000,
+ 0xfb2bfa0300000000, 0x6e55313c00000000, 0x227da79f00000000,
+ 0x099126f200000000, 0x45b9b05100000000, 0xd0c77b6e00000000,
+ 0x9cefedcd00000000, 0xfa3aed1100000000, 0xb6127bb200000000,
+ 0x236cb08d00000000, 0x6f44262e00000000, 0xaec0c0ee00000000,
+ 0xe2e8564d00000000, 0x77969d7200000000, 0x3bbe0bd100000000,
+ 0x5d6b0b0d00000000, 0x11439dae00000000, 0x843d569100000000,
+ 0xc815c03200000000, 0x4732eacb00000000, 0x0b1a7c6800000000,
+ 0x9e64b75700000000, 0xd24c21f400000000, 0xb499212800000000,
+ 0xf8b1b78b00000000, 0x6dcf7cb400000000, 0x21e7ea1700000000,
+ 0xe0630cd700000000, 0xac4b9a7400000000, 0x3935514b00000000,
+ 0x751dc7e800000000, 0x13c8c73400000000, 0x5fe0519700000000,
+ 0xca9e9aa800000000, 0x86b60c0b00000000, 0x95d7bf8100000000,
+ 0xd9ff292200000000, 0x4c81e21d00000000, 0x00a974be00000000,
+ 0x667c746200000000, 0x2a54e2c100000000, 0xbf2a29fe00000000,
+ 0xf302bf5d00000000, 0x3286599d00000000, 0x7eaecf3e00000000,
+ 0xebd0040100000000, 0xa7f892a200000000, 0xc12d927e00000000,
+ 0x8d0504dd00000000, 0x187bcfe200000000, 0x5453594100000000,
+ 0xdb7473b800000000, 0x975ce51b00000000, 0x02222e2400000000,
+ 0x4e0ab88700000000, 0x28dfb85b00000000, 0x64f72ef800000000,
+ 0xf189e5c700000000, 0xbda1736400000000, 0x7c2595a400000000,
+ 0x300d030700000000, 0xa573c83800000000, 0xe95b5e9b00000000,
+ 0x8f8e5e4700000000, 0xc3a6c8e400000000, 0x56d803db00000000,
+ 0x1af0957800000000},
+ {0x0000000000000000, 0x939bc97f00000000, 0x263793ff00000000,
+ 0xb5ac5a8000000000, 0x0d68572400000000, 0x9ef39e5b00000000,
+ 0x2b5fc4db00000000, 0xb8c40da400000000, 0x1ad0ae4800000000,
+ 0x894b673700000000, 0x3ce73db700000000, 0xaf7cf4c800000000,
+ 0x17b8f96c00000000, 0x8423301300000000, 0x318f6a9300000000,
+ 0xa214a3ec00000000, 0x34a05d9100000000, 0xa73b94ee00000000,
+ 0x1297ce6e00000000, 0x810c071100000000, 0x39c80ab500000000,
+ 0xaa53c3ca00000000, 0x1fff994a00000000, 0x8c64503500000000,
+ 0x2e70f3d900000000, 0xbdeb3aa600000000, 0x0847602600000000,
+ 0x9bdca95900000000, 0x2318a4fd00000000, 0xb0836d8200000000,
+ 0x052f370200000000, 0x96b4fe7d00000000, 0x2946caf900000000,
+ 0xbadd038600000000, 0x0f71590600000000, 0x9cea907900000000,
+ 0x242e9ddd00000000, 0xb7b554a200000000, 0x02190e2200000000,
+ 0x9182c75d00000000, 0x339664b100000000, 0xa00dadce00000000,
+ 0x15a1f74e00000000, 0x863a3e3100000000, 0x3efe339500000000,
+ 0xad65faea00000000, 0x18c9a06a00000000, 0x8b52691500000000,
+ 0x1de6976800000000, 0x8e7d5e1700000000, 0x3bd1049700000000,
+ 0xa84acde800000000, 0x108ec04c00000000, 0x8315093300000000,
+ 0x36b953b300000000, 0xa5229acc00000000, 0x0736392000000000,
+ 0x94adf05f00000000, 0x2101aadf00000000, 0xb29a63a000000000,
+ 0x0a5e6e0400000000, 0x99c5a77b00000000, 0x2c69fdfb00000000,
+ 0xbff2348400000000, 0x138ae52800000000, 0x80112c5700000000,
+ 0x35bd76d700000000, 0xa626bfa800000000, 0x1ee2b20c00000000,
+ 0x8d797b7300000000, 0x38d521f300000000, 0xab4ee88c00000000,
+ 0x095a4b6000000000, 0x9ac1821f00000000, 0x2f6dd89f00000000,
+ 0xbcf611e000000000, 0x04321c4400000000, 0x97a9d53b00000000,
+ 0x22058fbb00000000, 0xb19e46c400000000, 0x272ab8b900000000,
+ 0xb4b171c600000000, 0x011d2b4600000000, 0x9286e23900000000,
+ 0x2a42ef9d00000000, 0xb9d926e200000000, 0x0c757c6200000000,
+ 0x9feeb51d00000000, 0x3dfa16f100000000, 0xae61df8e00000000,
+ 0x1bcd850e00000000, 0x88564c7100000000, 0x309241d500000000,
+ 0xa30988aa00000000, 0x16a5d22a00000000, 0x853e1b5500000000,
+ 0x3acc2fd100000000, 0xa957e6ae00000000, 0x1cfbbc2e00000000,
+ 0x8f60755100000000, 0x37a478f500000000, 0xa43fb18a00000000,
+ 0x1193eb0a00000000, 0x8208227500000000, 0x201c819900000000,
+ 0xb38748e600000000, 0x062b126600000000, 0x95b0db1900000000,
+ 0x2d74d6bd00000000, 0xbeef1fc200000000, 0x0b43454200000000,
+ 0x98d88c3d00000000, 0x0e6c724000000000, 0x9df7bb3f00000000,
+ 0x285be1bf00000000, 0xbbc028c000000000, 0x0304256400000000,
+ 0x909fec1b00000000, 0x2533b69b00000000, 0xb6a87fe400000000,
+ 0x14bcdc0800000000, 0x8727157700000000, 0x328b4ff700000000,
+ 0xa110868800000000, 0x19d48b2c00000000, 0x8a4f425300000000,
+ 0x3fe318d300000000, 0xac78d1ac00000000, 0x2614cb5100000000,
+ 0xb58f022e00000000, 0x002358ae00000000, 0x93b891d100000000,
+ 0x2b7c9c7500000000, 0xb8e7550a00000000, 0x0d4b0f8a00000000,
+ 0x9ed0c6f500000000, 0x3cc4651900000000, 0xaf5fac6600000000,
+ 0x1af3f6e600000000, 0x89683f9900000000, 0x31ac323d00000000,
+ 0xa237fb4200000000, 0x179ba1c200000000, 0x840068bd00000000,
+ 0x12b496c000000000, 0x812f5fbf00000000, 0x3483053f00000000,
+ 0xa718cc4000000000, 0x1fdcc1e400000000, 0x8c47089b00000000,
+ 0x39eb521b00000000, 0xaa709b6400000000, 0x0864388800000000,
+ 0x9bfff1f700000000, 0x2e53ab7700000000, 0xbdc8620800000000,
+ 0x050c6fac00000000, 0x9697a6d300000000, 0x233bfc5300000000,
+ 0xb0a0352c00000000, 0x0f5201a800000000, 0x9cc9c8d700000000,
+ 0x2965925700000000, 0xbafe5b2800000000, 0x023a568c00000000,
+ 0x91a19ff300000000, 0x240dc57300000000, 0xb7960c0c00000000,
+ 0x1582afe000000000, 0x8619669f00000000, 0x33b53c1f00000000,
+ 0xa02ef56000000000, 0x18eaf8c400000000, 0x8b7131bb00000000,
+ 0x3edd6b3b00000000, 0xad46a24400000000, 0x3bf25c3900000000,
+ 0xa869954600000000, 0x1dc5cfc600000000, 0x8e5e06b900000000,
+ 0x369a0b1d00000000, 0xa501c26200000000, 0x10ad98e200000000,
+ 0x8336519d00000000, 0x2122f27100000000, 0xb2b93b0e00000000,
+ 0x0715618e00000000, 0x948ea8f100000000, 0x2c4aa55500000000,
+ 0xbfd16c2a00000000, 0x0a7d36aa00000000, 0x99e6ffd500000000,
+ 0x359e2e7900000000, 0xa605e70600000000, 0x13a9bd8600000000,
+ 0x803274f900000000, 0x38f6795d00000000, 0xab6db02200000000,
+ 0x1ec1eaa200000000, 0x8d5a23dd00000000, 0x2f4e803100000000,
+ 0xbcd5494e00000000, 0x097913ce00000000, 0x9ae2dab100000000,
+ 0x2226d71500000000, 0xb1bd1e6a00000000, 0x041144ea00000000,
+ 0x978a8d9500000000, 0x013e73e800000000, 0x92a5ba9700000000,
+ 0x2709e01700000000, 0xb492296800000000, 0x0c5624cc00000000,
+ 0x9fcdedb300000000, 0x2a61b73300000000, 0xb9fa7e4c00000000,
+ 0x1beedda000000000, 0x887514df00000000, 0x3dd94e5f00000000,
+ 0xae42872000000000, 0x16868a8400000000, 0x851d43fb00000000,
+ 0x30b1197b00000000, 0xa32ad00400000000, 0x1cd8e48000000000,
+ 0x8f432dff00000000, 0x3aef777f00000000, 0xa974be0000000000,
+ 0x11b0b3a400000000, 0x822b7adb00000000, 0x3787205b00000000,
+ 0xa41ce92400000000, 0x06084ac800000000, 0x959383b700000000,
+ 0x203fd93700000000, 0xb3a4104800000000, 0x0b601dec00000000,
+ 0x98fbd49300000000, 0x2d578e1300000000, 0xbecc476c00000000,
+ 0x2878b91100000000, 0xbbe3706e00000000, 0x0e4f2aee00000000,
+ 0x9dd4e39100000000, 0x2510ee3500000000, 0xb68b274a00000000,
+ 0x03277dca00000000, 0x90bcb4b500000000, 0x32a8175900000000,
+ 0xa133de2600000000, 0x149f84a600000000, 0x87044dd900000000,
+ 0x3fc0407d00000000, 0xac5b890200000000, 0x19f7d38200000000,
+ 0x8a6c1afd00000000},
+ {0x0000000000000000, 0x650b796900000000, 0xca16f2d200000000,
+ 0xaf1d8bbb00000000, 0xd52b957e00000000, 0xb020ec1700000000,
+ 0x1f3d67ac00000000, 0x7a361ec500000000, 0xaa572afd00000000,
+ 0xcf5c539400000000, 0x6041d82f00000000, 0x054aa14600000000,
+ 0x7f7cbf8300000000, 0x1a77c6ea00000000, 0xb56a4d5100000000,
+ 0xd061343800000000, 0x15a9252100000000, 0x70a25c4800000000,
+ 0xdfbfd7f300000000, 0xbab4ae9a00000000, 0xc082b05f00000000,
+ 0xa589c93600000000, 0x0a94428d00000000, 0x6f9f3be400000000,
+ 0xbffe0fdc00000000, 0xdaf576b500000000, 0x75e8fd0e00000000,
+ 0x10e3846700000000, 0x6ad59aa200000000, 0x0fdee3cb00000000,
+ 0xa0c3687000000000, 0xc5c8111900000000, 0x2a524b4200000000,
+ 0x4f59322b00000000, 0xe044b99000000000, 0x854fc0f900000000,
+ 0xff79de3c00000000, 0x9a72a75500000000, 0x356f2cee00000000,
+ 0x5064558700000000, 0x800561bf00000000, 0xe50e18d600000000,
+ 0x4a13936d00000000, 0x2f18ea0400000000, 0x552ef4c100000000,
+ 0x30258da800000000, 0x9f38061300000000, 0xfa337f7a00000000,
+ 0x3ffb6e6300000000, 0x5af0170a00000000, 0xf5ed9cb100000000,
+ 0x90e6e5d800000000, 0xead0fb1d00000000, 0x8fdb827400000000,
+ 0x20c609cf00000000, 0x45cd70a600000000, 0x95ac449e00000000,
+ 0xf0a73df700000000, 0x5fbab64c00000000, 0x3ab1cf2500000000,
+ 0x4087d1e000000000, 0x258ca88900000000, 0x8a91233200000000,
+ 0xef9a5a5b00000000, 0x54a4968400000000, 0x31afefed00000000,
+ 0x9eb2645600000000, 0xfbb91d3f00000000, 0x818f03fa00000000,
+ 0xe4847a9300000000, 0x4b99f12800000000, 0x2e92884100000000,
+ 0xfef3bc7900000000, 0x9bf8c51000000000, 0x34e54eab00000000,
+ 0x51ee37c200000000, 0x2bd8290700000000, 0x4ed3506e00000000,
+ 0xe1cedbd500000000, 0x84c5a2bc00000000, 0x410db3a500000000,
+ 0x2406cacc00000000, 0x8b1b417700000000, 0xee10381e00000000,
+ 0x942626db00000000, 0xf12d5fb200000000, 0x5e30d40900000000,
+ 0x3b3bad6000000000, 0xeb5a995800000000, 0x8e51e03100000000,
+ 0x214c6b8a00000000, 0x444712e300000000, 0x3e710c2600000000,
+ 0x5b7a754f00000000, 0xf467fef400000000, 0x916c879d00000000,
+ 0x7ef6ddc600000000, 0x1bfda4af00000000, 0xb4e02f1400000000,
+ 0xd1eb567d00000000, 0xabdd48b800000000, 0xced631d100000000,
+ 0x61cbba6a00000000, 0x04c0c30300000000, 0xd4a1f73b00000000,
+ 0xb1aa8e5200000000, 0x1eb705e900000000, 0x7bbc7c8000000000,
+ 0x018a624500000000, 0x64811b2c00000000, 0xcb9c909700000000,
+ 0xae97e9fe00000000, 0x6b5ff8e700000000, 0x0e54818e00000000,
+ 0xa1490a3500000000, 0xc442735c00000000, 0xbe746d9900000000,
+ 0xdb7f14f000000000, 0x74629f4b00000000, 0x1169e62200000000,
+ 0xc108d21a00000000, 0xa403ab7300000000, 0x0b1e20c800000000,
+ 0x6e1559a100000000, 0x1423476400000000, 0x71283e0d00000000,
+ 0xde35b5b600000000, 0xbb3eccdf00000000, 0xe94e5cd200000000,
+ 0x8c4525bb00000000, 0x2358ae0000000000, 0x4653d76900000000,
+ 0x3c65c9ac00000000, 0x596eb0c500000000, 0xf6733b7e00000000,
+ 0x9378421700000000, 0x4319762f00000000, 0x26120f4600000000,
+ 0x890f84fd00000000, 0xec04fd9400000000, 0x9632e35100000000,
+ 0xf3399a3800000000, 0x5c24118300000000, 0x392f68ea00000000,
+ 0xfce779f300000000, 0x99ec009a00000000, 0x36f18b2100000000,
+ 0x53faf24800000000, 0x29ccec8d00000000, 0x4cc795e400000000,
+ 0xe3da1e5f00000000, 0x86d1673600000000, 0x56b0530e00000000,
+ 0x33bb2a6700000000, 0x9ca6a1dc00000000, 0xf9add8b500000000,
+ 0x839bc67000000000, 0xe690bf1900000000, 0x498d34a200000000,
+ 0x2c864dcb00000000, 0xc31c179000000000, 0xa6176ef900000000,
+ 0x090ae54200000000, 0x6c019c2b00000000, 0x163782ee00000000,
+ 0x733cfb8700000000, 0xdc21703c00000000, 0xb92a095500000000,
+ 0x694b3d6d00000000, 0x0c40440400000000, 0xa35dcfbf00000000,
+ 0xc656b6d600000000, 0xbc60a81300000000, 0xd96bd17a00000000,
+ 0x76765ac100000000, 0x137d23a800000000, 0xd6b532b100000000,
+ 0xb3be4bd800000000, 0x1ca3c06300000000, 0x79a8b90a00000000,
+ 0x039ea7cf00000000, 0x6695dea600000000, 0xc988551d00000000,
+ 0xac832c7400000000, 0x7ce2184c00000000, 0x19e9612500000000,
+ 0xb6f4ea9e00000000, 0xd3ff93f700000000, 0xa9c98d3200000000,
+ 0xccc2f45b00000000, 0x63df7fe000000000, 0x06d4068900000000,
+ 0xbdeaca5600000000, 0xd8e1b33f00000000, 0x77fc388400000000,
+ 0x12f741ed00000000, 0x68c15f2800000000, 0x0dca264100000000,
+ 0xa2d7adfa00000000, 0xc7dcd49300000000, 0x17bde0ab00000000,
+ 0x72b699c200000000, 0xddab127900000000, 0xb8a06b1000000000,
+ 0xc29675d500000000, 0xa79d0cbc00000000, 0x0880870700000000,
+ 0x6d8bfe6e00000000, 0xa843ef7700000000, 0xcd48961e00000000,
+ 0x62551da500000000, 0x075e64cc00000000, 0x7d687a0900000000,
+ 0x1863036000000000, 0xb77e88db00000000, 0xd275f1b200000000,
+ 0x0214c58a00000000, 0x671fbce300000000, 0xc802375800000000,
+ 0xad094e3100000000, 0xd73f50f400000000, 0xb234299d00000000,
+ 0x1d29a22600000000, 0x7822db4f00000000, 0x97b8811400000000,
+ 0xf2b3f87d00000000, 0x5dae73c600000000, 0x38a50aaf00000000,
+ 0x4293146a00000000, 0x27986d0300000000, 0x8885e6b800000000,
+ 0xed8e9fd100000000, 0x3defabe900000000, 0x58e4d28000000000,
+ 0xf7f9593b00000000, 0x92f2205200000000, 0xe8c43e9700000000,
+ 0x8dcf47fe00000000, 0x22d2cc4500000000, 0x47d9b52c00000000,
+ 0x8211a43500000000, 0xe71add5c00000000, 0x480756e700000000,
+ 0x2d0c2f8e00000000, 0x573a314b00000000, 0x3231482200000000,
+ 0x9d2cc39900000000, 0xf827baf000000000, 0x28468ec800000000,
+ 0x4d4df7a100000000, 0xe2507c1a00000000, 0x875b057300000000,
+ 0xfd6d1bb600000000, 0x986662df00000000, 0x377be96400000000,
+ 0x5270900d00000000},
+ {0x0000000000000000, 0xdcecb13d00000000, 0xb8d9637b00000000,
+ 0x6435d24600000000, 0x70b3c7f600000000, 0xac5f76cb00000000,
+ 0xc86aa48d00000000, 0x148615b000000000, 0xa160fe3600000000,
+ 0x7d8c4f0b00000000, 0x19b99d4d00000000, 0xc5552c7000000000,
+ 0xd1d339c000000000, 0x0d3f88fd00000000, 0x690a5abb00000000,
+ 0xb5e6eb8600000000, 0x42c1fc6d00000000, 0x9e2d4d5000000000,
+ 0xfa189f1600000000, 0x26f42e2b00000000, 0x32723b9b00000000,
+ 0xee9e8aa600000000, 0x8aab58e000000000, 0x5647e9dd00000000,
+ 0xe3a1025b00000000, 0x3f4db36600000000, 0x5b78612000000000,
+ 0x8794d01d00000000, 0x9312c5ad00000000, 0x4ffe749000000000,
+ 0x2bcba6d600000000, 0xf72717eb00000000, 0x8482f9db00000000,
+ 0x586e48e600000000, 0x3c5b9aa000000000, 0xe0b72b9d00000000,
+ 0xf4313e2d00000000, 0x28dd8f1000000000, 0x4ce85d5600000000,
+ 0x9004ec6b00000000, 0x25e207ed00000000, 0xf90eb6d000000000,
+ 0x9d3b649600000000, 0x41d7d5ab00000000, 0x5551c01b00000000,
+ 0x89bd712600000000, 0xed88a36000000000, 0x3164125d00000000,
+ 0xc64305b600000000, 0x1aafb48b00000000, 0x7e9a66cd00000000,
+ 0xa276d7f000000000, 0xb6f0c24000000000, 0x6a1c737d00000000,
+ 0x0e29a13b00000000, 0xd2c5100600000000, 0x6723fb8000000000,
+ 0xbbcf4abd00000000, 0xdffa98fb00000000, 0x031629c600000000,
+ 0x17903c7600000000, 0xcb7c8d4b00000000, 0xaf495f0d00000000,
+ 0x73a5ee3000000000, 0x4903826c00000000, 0x95ef335100000000,
+ 0xf1dae11700000000, 0x2d36502a00000000, 0x39b0459a00000000,
+ 0xe55cf4a700000000, 0x816926e100000000, 0x5d8597dc00000000,
+ 0xe8637c5a00000000, 0x348fcd6700000000, 0x50ba1f2100000000,
+ 0x8c56ae1c00000000, 0x98d0bbac00000000, 0x443c0a9100000000,
+ 0x2009d8d700000000, 0xfce569ea00000000, 0x0bc27e0100000000,
+ 0xd72ecf3c00000000, 0xb31b1d7a00000000, 0x6ff7ac4700000000,
+ 0x7b71b9f700000000, 0xa79d08ca00000000, 0xc3a8da8c00000000,
+ 0x1f446bb100000000, 0xaaa2803700000000, 0x764e310a00000000,
+ 0x127be34c00000000, 0xce97527100000000, 0xda1147c100000000,
+ 0x06fdf6fc00000000, 0x62c824ba00000000, 0xbe24958700000000,
+ 0xcd817bb700000000, 0x116dca8a00000000, 0x755818cc00000000,
+ 0xa9b4a9f100000000, 0xbd32bc4100000000, 0x61de0d7c00000000,
+ 0x05ebdf3a00000000, 0xd9076e0700000000, 0x6ce1858100000000,
+ 0xb00d34bc00000000, 0xd438e6fa00000000, 0x08d457c700000000,
+ 0x1c52427700000000, 0xc0bef34a00000000, 0xa48b210c00000000,
+ 0x7867903100000000, 0x8f4087da00000000, 0x53ac36e700000000,
+ 0x3799e4a100000000, 0xeb75559c00000000, 0xfff3402c00000000,
+ 0x231ff11100000000, 0x472a235700000000, 0x9bc6926a00000000,
+ 0x2e2079ec00000000, 0xf2ccc8d100000000, 0x96f91a9700000000,
+ 0x4a15abaa00000000, 0x5e93be1a00000000, 0x827f0f2700000000,
+ 0xe64add6100000000, 0x3aa66c5c00000000, 0x920604d900000000,
+ 0x4eeab5e400000000, 0x2adf67a200000000, 0xf633d69f00000000,
+ 0xe2b5c32f00000000, 0x3e59721200000000, 0x5a6ca05400000000,
+ 0x8680116900000000, 0x3366faef00000000, 0xef8a4bd200000000,
+ 0x8bbf999400000000, 0x575328a900000000, 0x43d53d1900000000,
+ 0x9f398c2400000000, 0xfb0c5e6200000000, 0x27e0ef5f00000000,
+ 0xd0c7f8b400000000, 0x0c2b498900000000, 0x681e9bcf00000000,
+ 0xb4f22af200000000, 0xa0743f4200000000, 0x7c988e7f00000000,
+ 0x18ad5c3900000000, 0xc441ed0400000000, 0x71a7068200000000,
+ 0xad4bb7bf00000000, 0xc97e65f900000000, 0x1592d4c400000000,
+ 0x0114c17400000000, 0xddf8704900000000, 0xb9cda20f00000000,
+ 0x6521133200000000, 0x1684fd0200000000, 0xca684c3f00000000,
+ 0xae5d9e7900000000, 0x72b12f4400000000, 0x66373af400000000,
+ 0xbadb8bc900000000, 0xdeee598f00000000, 0x0202e8b200000000,
+ 0xb7e4033400000000, 0x6b08b20900000000, 0x0f3d604f00000000,
+ 0xd3d1d17200000000, 0xc757c4c200000000, 0x1bbb75ff00000000,
+ 0x7f8ea7b900000000, 0xa362168400000000, 0x5445016f00000000,
+ 0x88a9b05200000000, 0xec9c621400000000, 0x3070d32900000000,
+ 0x24f6c69900000000, 0xf81a77a400000000, 0x9c2fa5e200000000,
+ 0x40c314df00000000, 0xf525ff5900000000, 0x29c94e6400000000,
+ 0x4dfc9c2200000000, 0x91102d1f00000000, 0x859638af00000000,
+ 0x597a899200000000, 0x3d4f5bd400000000, 0xe1a3eae900000000,
+ 0xdb0586b500000000, 0x07e9378800000000, 0x63dce5ce00000000,
+ 0xbf3054f300000000, 0xabb6414300000000, 0x775af07e00000000,
+ 0x136f223800000000, 0xcf83930500000000, 0x7a65788300000000,
+ 0xa689c9be00000000, 0xc2bc1bf800000000, 0x1e50aac500000000,
+ 0x0ad6bf7500000000, 0xd63a0e4800000000, 0xb20fdc0e00000000,
+ 0x6ee36d3300000000, 0x99c47ad800000000, 0x4528cbe500000000,
+ 0x211d19a300000000, 0xfdf1a89e00000000, 0xe977bd2e00000000,
+ 0x359b0c1300000000, 0x51aede5500000000, 0x8d426f6800000000,
+ 0x38a484ee00000000, 0xe44835d300000000, 0x807de79500000000,
+ 0x5c9156a800000000, 0x4817431800000000, 0x94fbf22500000000,
+ 0xf0ce206300000000, 0x2c22915e00000000, 0x5f877f6e00000000,
+ 0x836bce5300000000, 0xe75e1c1500000000, 0x3bb2ad2800000000,
+ 0x2f34b89800000000, 0xf3d809a500000000, 0x97eddbe300000000,
+ 0x4b016ade00000000, 0xfee7815800000000, 0x220b306500000000,
+ 0x463ee22300000000, 0x9ad2531e00000000, 0x8e5446ae00000000,
+ 0x52b8f79300000000, 0x368d25d500000000, 0xea6194e800000000,
+ 0x1d46830300000000, 0xc1aa323e00000000, 0xa59fe07800000000,
+ 0x7973514500000000, 0x6df544f500000000, 0xb119f5c800000000,
+ 0xd52c278e00000000, 0x09c096b300000000, 0xbc267d3500000000,
+ 0x60cacc0800000000, 0x04ff1e4e00000000, 0xd813af7300000000,
+ 0xcc95bac300000000, 0x10790bfe00000000, 0x744cd9b800000000,
+ 0xa8a0688500000000}};
+
+#else /* W == 4 */
+
+local const z_crc_t FAR crc_braid_table[][256] = {
+ {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f,
+ 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999,
+ 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee,
+ 0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615,
+ 0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383,
+ 0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb,
+ 0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275,
+ 0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d,
+ 0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b,
+ 0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460,
+ 0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317,
+ 0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1,
+ 0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5,
+ 0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd,
+ 0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04,
+ 0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c,
+ 0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7,
+ 0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11,
+ 0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66,
+ 0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7,
+ 0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871,
+ 0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309,
+ 0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd,
+ 0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85,
+ 0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913,
+ 0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d,
+ 0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a,
+ 0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc,
+ 0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57,
+ 0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f,
+ 0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6,
+ 0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e,
+ 0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f,
+ 0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289,
+ 0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe,
+ 0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05,
+ 0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893,
+ 0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb,
+ 0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0,
+ 0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8,
+ 0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e,
+ 0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5,
+ 0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2,
+ 0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574,
+ 0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5,
+ 0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add,
+ 0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114,
+ 0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c,
+ 0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7,
+ 0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701,
+ 0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076,
+ 0x09cd8551},
+ {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193,
+ 0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2,
+ 0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c,
+ 0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71,
+ 0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a,
+ 0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d,
+ 0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71,
+ 0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436,
+ 0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d,
+ 0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000,
+ 0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae,
+ 0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf,
+ 0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930,
+ 0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277,
+ 0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff,
+ 0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8,
+ 0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef,
+ 0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e,
+ 0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20,
+ 0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95,
+ 0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e,
+ 0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9,
+ 0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d,
+ 0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a,
+ 0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151,
+ 0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4,
+ 0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a,
+ 0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b,
+ 0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c,
+ 0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b,
+ 0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3,
+ 0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4,
+ 0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b,
+ 0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a,
+ 0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4,
+ 0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189,
+ 0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92,
+ 0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5,
+ 0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9,
+ 0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe,
+ 0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5,
+ 0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8,
+ 0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66,
+ 0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707,
+ 0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8,
+ 0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f,
+ 0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707,
+ 0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40,
+ 0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017,
+ 0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876,
+ 0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8,
+ 0x7bc97a0c},
+ {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300,
+ 0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0,
+ 0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80,
+ 0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701,
+ 0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41,
+ 0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81,
+ 0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43,
+ 0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83,
+ 0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3,
+ 0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42,
+ 0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202,
+ 0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2,
+ 0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7,
+ 0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407,
+ 0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47,
+ 0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87,
+ 0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86,
+ 0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46,
+ 0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506,
+ 0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44,
+ 0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704,
+ 0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4,
+ 0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5,
+ 0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505,
+ 0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45,
+ 0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f,
+ 0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f,
+ 0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f,
+ 0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e,
+ 0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e,
+ 0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e,
+ 0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce,
+ 0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c,
+ 0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc,
+ 0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c,
+ 0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d,
+ 0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d,
+ 0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d,
+ 0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88,
+ 0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48,
+ 0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708,
+ 0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89,
+ 0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9,
+ 0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309,
+ 0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb,
+ 0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b,
+ 0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b,
+ 0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b,
+ 0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a,
+ 0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a,
+ 0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a,
+ 0x7851a2ca},
+ {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb,
+ 0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8,
+ 0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0,
+ 0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f,
+ 0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a,
+ 0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf,
+ 0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5,
+ 0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380,
+ 0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815,
+ 0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa,
+ 0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2,
+ 0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1,
+ 0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1,
+ 0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4,
+ 0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa,
+ 0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df,
+ 0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6,
+ 0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5,
+ 0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad,
+ 0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca,
+ 0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f,
+ 0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a,
+ 0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8,
+ 0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d,
+ 0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708,
+ 0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d,
+ 0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865,
+ 0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636,
+ 0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f,
+ 0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a,
+ 0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744,
+ 0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061,
+ 0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0,
+ 0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293,
+ 0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb,
+ 0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874,
+ 0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1,
+ 0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4,
+ 0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f,
+ 0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a,
+ 0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f,
+ 0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120,
+ 0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778,
+ 0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b,
+ 0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a,
+ 0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af,
+ 0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81,
+ 0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4,
+ 0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd,
+ 0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e,
+ 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6,
+ 0x566b6848}};
+
+local const z_word_t FAR crc_braid_big_table[][256] = {
+ {0x00000000, 0x9e83da9f, 0x7d01c4e4, 0xe3821e7b, 0xbb04f912,
+ 0x2587238d, 0xc6053df6, 0x5886e769, 0x7609f225, 0xe88a28ba,
+ 0x0b0836c1, 0x958bec5e, 0xcd0d0b37, 0x538ed1a8, 0xb00ccfd3,
+ 0x2e8f154c, 0xec12e44b, 0x72913ed4, 0x911320af, 0x0f90fa30,
+ 0x57161d59, 0xc995c7c6, 0x2a17d9bd, 0xb4940322, 0x9a1b166e,
+ 0x0498ccf1, 0xe71ad28a, 0x79990815, 0x211fef7c, 0xbf9c35e3,
+ 0x5c1e2b98, 0xc29df107, 0xd825c897, 0x46a61208, 0xa5240c73,
+ 0x3ba7d6ec, 0x63213185, 0xfda2eb1a, 0x1e20f561, 0x80a32ffe,
+ 0xae2c3ab2, 0x30afe02d, 0xd32dfe56, 0x4dae24c9, 0x1528c3a0,
+ 0x8bab193f, 0x68290744, 0xf6aadddb, 0x34372cdc, 0xaab4f643,
+ 0x4936e838, 0xd7b532a7, 0x8f33d5ce, 0x11b00f51, 0xf232112a,
+ 0x6cb1cbb5, 0x423edef9, 0xdcbd0466, 0x3f3f1a1d, 0xa1bcc082,
+ 0xf93a27eb, 0x67b9fd74, 0x843be30f, 0x1ab83990, 0xf14de1f4,
+ 0x6fce3b6b, 0x8c4c2510, 0x12cfff8f, 0x4a4918e6, 0xd4cac279,
+ 0x3748dc02, 0xa9cb069d, 0x874413d1, 0x19c7c94e, 0xfa45d735,
+ 0x64c60daa, 0x3c40eac3, 0xa2c3305c, 0x41412e27, 0xdfc2f4b8,
+ 0x1d5f05bf, 0x83dcdf20, 0x605ec15b, 0xfedd1bc4, 0xa65bfcad,
+ 0x38d82632, 0xdb5a3849, 0x45d9e2d6, 0x6b56f79a, 0xf5d52d05,
+ 0x1657337e, 0x88d4e9e1, 0xd0520e88, 0x4ed1d417, 0xad53ca6c,
+ 0x33d010f3, 0x29682963, 0xb7ebf3fc, 0x5469ed87, 0xcaea3718,
+ 0x926cd071, 0x0cef0aee, 0xef6d1495, 0x71eece0a, 0x5f61db46,
+ 0xc1e201d9, 0x22601fa2, 0xbce3c53d, 0xe4652254, 0x7ae6f8cb,
+ 0x9964e6b0, 0x07e73c2f, 0xc57acd28, 0x5bf917b7, 0xb87b09cc,
+ 0x26f8d353, 0x7e7e343a, 0xe0fdeea5, 0x037ff0de, 0x9dfc2a41,
+ 0xb3733f0d, 0x2df0e592, 0xce72fbe9, 0x50f12176, 0x0877c61f,
+ 0x96f41c80, 0x757602fb, 0xebf5d864, 0xa39db332, 0x3d1e69ad,
+ 0xde9c77d6, 0x401fad49, 0x18994a20, 0x861a90bf, 0x65988ec4,
+ 0xfb1b545b, 0xd5944117, 0x4b179b88, 0xa89585f3, 0x36165f6c,
+ 0x6e90b805, 0xf013629a, 0x13917ce1, 0x8d12a67e, 0x4f8f5779,
+ 0xd10c8de6, 0x328e939d, 0xac0d4902, 0xf48bae6b, 0x6a0874f4,
+ 0x898a6a8f, 0x1709b010, 0x3986a55c, 0xa7057fc3, 0x448761b8,
+ 0xda04bb27, 0x82825c4e, 0x1c0186d1, 0xff8398aa, 0x61004235,
+ 0x7bb87ba5, 0xe53ba13a, 0x06b9bf41, 0x983a65de, 0xc0bc82b7,
+ 0x5e3f5828, 0xbdbd4653, 0x233e9ccc, 0x0db18980, 0x9332531f,
+ 0x70b04d64, 0xee3397fb, 0xb6b57092, 0x2836aa0d, 0xcbb4b476,
+ 0x55376ee9, 0x97aa9fee, 0x09294571, 0xeaab5b0a, 0x74288195,
+ 0x2cae66fc, 0xb22dbc63, 0x51afa218, 0xcf2c7887, 0xe1a36dcb,
+ 0x7f20b754, 0x9ca2a92f, 0x022173b0, 0x5aa794d9, 0xc4244e46,
+ 0x27a6503d, 0xb9258aa2, 0x52d052c6, 0xcc538859, 0x2fd19622,
+ 0xb1524cbd, 0xe9d4abd4, 0x7757714b, 0x94d56f30, 0x0a56b5af,
+ 0x24d9a0e3, 0xba5a7a7c, 0x59d86407, 0xc75bbe98, 0x9fdd59f1,
+ 0x015e836e, 0xe2dc9d15, 0x7c5f478a, 0xbec2b68d, 0x20416c12,
+ 0xc3c37269, 0x5d40a8f6, 0x05c64f9f, 0x9b459500, 0x78c78b7b,
+ 0xe64451e4, 0xc8cb44a8, 0x56489e37, 0xb5ca804c, 0x2b495ad3,
+ 0x73cfbdba, 0xed4c6725, 0x0ece795e, 0x904da3c1, 0x8af59a51,
+ 0x147640ce, 0xf7f45eb5, 0x6977842a, 0x31f16343, 0xaf72b9dc,
+ 0x4cf0a7a7, 0xd2737d38, 0xfcfc6874, 0x627fb2eb, 0x81fdac90,
+ 0x1f7e760f, 0x47f89166, 0xd97b4bf9, 0x3af95582, 0xa47a8f1d,
+ 0x66e77e1a, 0xf864a485, 0x1be6bafe, 0x85656061, 0xdde38708,
+ 0x43605d97, 0xa0e243ec, 0x3e619973, 0x10ee8c3f, 0x8e6d56a0,
+ 0x6def48db, 0xf36c9244, 0xabea752d, 0x3569afb2, 0xd6ebb1c9,
+ 0x48686b56},
+ {0x00000000, 0xc0642817, 0x80c9502e, 0x40ad7839, 0x0093a15c,
+ 0xc0f7894b, 0x805af172, 0x403ed965, 0x002643b9, 0xc0426bae,
+ 0x80ef1397, 0x408b3b80, 0x00b5e2e5, 0xc0d1caf2, 0x807cb2cb,
+ 0x40189adc, 0x414af7a9, 0x812edfbe, 0xc183a787, 0x01e78f90,
+ 0x41d956f5, 0x81bd7ee2, 0xc11006db, 0x01742ecc, 0x416cb410,
+ 0x81089c07, 0xc1a5e43e, 0x01c1cc29, 0x41ff154c, 0x819b3d5b,
+ 0xc1364562, 0x01526d75, 0xc3929f88, 0x03f6b79f, 0x435bcfa6,
+ 0x833fe7b1, 0xc3013ed4, 0x036516c3, 0x43c86efa, 0x83ac46ed,
+ 0xc3b4dc31, 0x03d0f426, 0x437d8c1f, 0x8319a408, 0xc3277d6d,
+ 0x0343557a, 0x43ee2d43, 0x838a0554, 0x82d86821, 0x42bc4036,
+ 0x0211380f, 0xc2751018, 0x824bc97d, 0x422fe16a, 0x02829953,
+ 0xc2e6b144, 0x82fe2b98, 0x429a038f, 0x02377bb6, 0xc25353a1,
+ 0x826d8ac4, 0x4209a2d3, 0x02a4daea, 0xc2c0f2fd, 0xc7234eca,
+ 0x074766dd, 0x47ea1ee4, 0x878e36f3, 0xc7b0ef96, 0x07d4c781,
+ 0x4779bfb8, 0x871d97af, 0xc7050d73, 0x07612564, 0x47cc5d5d,
+ 0x87a8754a, 0xc796ac2f, 0x07f28438, 0x475ffc01, 0x873bd416,
+ 0x8669b963, 0x460d9174, 0x06a0e94d, 0xc6c4c15a, 0x86fa183f,
+ 0x469e3028, 0x06334811, 0xc6576006, 0x864ffada, 0x462bd2cd,
+ 0x0686aaf4, 0xc6e282e3, 0x86dc5b86, 0x46b87391, 0x06150ba8,
+ 0xc67123bf, 0x04b1d142, 0xc4d5f955, 0x8478816c, 0x441ca97b,
+ 0x0422701e, 0xc4465809, 0x84eb2030, 0x448f0827, 0x049792fb,
+ 0xc4f3baec, 0x845ec2d5, 0x443aeac2, 0x040433a7, 0xc4601bb0,
+ 0x84cd6389, 0x44a94b9e, 0x45fb26eb, 0x859f0efc, 0xc53276c5,
+ 0x05565ed2, 0x456887b7, 0x850cafa0, 0xc5a1d799, 0x05c5ff8e,
+ 0x45dd6552, 0x85b94d45, 0xc514357c, 0x05701d6b, 0x454ec40e,
+ 0x852aec19, 0xc5879420, 0x05e3bc37, 0xcf41ed4f, 0x0f25c558,
+ 0x4f88bd61, 0x8fec9576, 0xcfd24c13, 0x0fb66404, 0x4f1b1c3d,
+ 0x8f7f342a, 0xcf67aef6, 0x0f0386e1, 0x4faefed8, 0x8fcad6cf,
+ 0xcff40faa, 0x0f9027bd, 0x4f3d5f84, 0x8f597793, 0x8e0b1ae6,
+ 0x4e6f32f1, 0x0ec24ac8, 0xcea662df, 0x8e98bbba, 0x4efc93ad,
+ 0x0e51eb94, 0xce35c383, 0x8e2d595f, 0x4e497148, 0x0ee40971,
+ 0xce802166, 0x8ebef803, 0x4edad014, 0x0e77a82d, 0xce13803a,
+ 0x0cd372c7, 0xccb75ad0, 0x8c1a22e9, 0x4c7e0afe, 0x0c40d39b,
+ 0xcc24fb8c, 0x8c8983b5, 0x4cedaba2, 0x0cf5317e, 0xcc911969,
+ 0x8c3c6150, 0x4c584947, 0x0c669022, 0xcc02b835, 0x8cafc00c,
+ 0x4ccbe81b, 0x4d99856e, 0x8dfdad79, 0xcd50d540, 0x0d34fd57,
+ 0x4d0a2432, 0x8d6e0c25, 0xcdc3741c, 0x0da75c0b, 0x4dbfc6d7,
+ 0x8ddbeec0, 0xcd7696f9, 0x0d12beee, 0x4d2c678b, 0x8d484f9c,
+ 0xcde537a5, 0x0d811fb2, 0x0862a385, 0xc8068b92, 0x88abf3ab,
+ 0x48cfdbbc, 0x08f102d9, 0xc8952ace, 0x883852f7, 0x485c7ae0,
+ 0x0844e03c, 0xc820c82b, 0x888db012, 0x48e99805, 0x08d74160,
+ 0xc8b36977, 0x881e114e, 0x487a3959, 0x4928542c, 0x894c7c3b,
+ 0xc9e10402, 0x09852c15, 0x49bbf570, 0x89dfdd67, 0xc972a55e,
+ 0x09168d49, 0x490e1795, 0x896a3f82, 0xc9c747bb, 0x09a36fac,
+ 0x499db6c9, 0x89f99ede, 0xc954e6e7, 0x0930cef0, 0xcbf03c0d,
+ 0x0b94141a, 0x4b396c23, 0x8b5d4434, 0xcb639d51, 0x0b07b546,
+ 0x4baacd7f, 0x8bcee568, 0xcbd67fb4, 0x0bb257a3, 0x4b1f2f9a,
+ 0x8b7b078d, 0xcb45dee8, 0x0b21f6ff, 0x4b8c8ec6, 0x8be8a6d1,
+ 0x8abacba4, 0x4adee3b3, 0x0a739b8a, 0xca17b39d, 0x8a296af8,
+ 0x4a4d42ef, 0x0ae03ad6, 0xca8412c1, 0x8a9c881d, 0x4af8a00a,
+ 0x0a55d833, 0xca31f024, 0x8a0f2941, 0x4a6b0156, 0x0ac6796f,
+ 0xcaa25178},
+ {0x00000000, 0xd4ea739b, 0xe9d396ed, 0x3d39e576, 0x93a15c00,
+ 0x474b2f9b, 0x7a72caed, 0xae98b976, 0x2643b900, 0xf2a9ca9b,
+ 0xcf902fed, 0x1b7a5c76, 0xb5e2e500, 0x6108969b, 0x5c3173ed,
+ 0x88db0076, 0x4c867201, 0x986c019a, 0xa555e4ec, 0x71bf9777,
+ 0xdf272e01, 0x0bcd5d9a, 0x36f4b8ec, 0xe21ecb77, 0x6ac5cb01,
+ 0xbe2fb89a, 0x83165dec, 0x57fc2e77, 0xf9649701, 0x2d8ee49a,
+ 0x10b701ec, 0xc45d7277, 0x980ce502, 0x4ce69699, 0x71df73ef,
+ 0xa5350074, 0x0badb902, 0xdf47ca99, 0xe27e2fef, 0x36945c74,
+ 0xbe4f5c02, 0x6aa52f99, 0x579ccaef, 0x8376b974, 0x2dee0002,
+ 0xf9047399, 0xc43d96ef, 0x10d7e574, 0xd48a9703, 0x0060e498,
+ 0x3d5901ee, 0xe9b37275, 0x472bcb03, 0x93c1b898, 0xaef85dee,
+ 0x7a122e75, 0xf2c92e03, 0x26235d98, 0x1b1ab8ee, 0xcff0cb75,
+ 0x61687203, 0xb5820198, 0x88bbe4ee, 0x5c519775, 0x3019ca05,
+ 0xe4f3b99e, 0xd9ca5ce8, 0x0d202f73, 0xa3b89605, 0x7752e59e,
+ 0x4a6b00e8, 0x9e817373, 0x165a7305, 0xc2b0009e, 0xff89e5e8,
+ 0x2b639673, 0x85fb2f05, 0x51115c9e, 0x6c28b9e8, 0xb8c2ca73,
+ 0x7c9fb804, 0xa875cb9f, 0x954c2ee9, 0x41a65d72, 0xef3ee404,
+ 0x3bd4979f, 0x06ed72e9, 0xd2070172, 0x5adc0104, 0x8e36729f,
+ 0xb30f97e9, 0x67e5e472, 0xc97d5d04, 0x1d972e9f, 0x20aecbe9,
+ 0xf444b872, 0xa8152f07, 0x7cff5c9c, 0x41c6b9ea, 0x952cca71,
+ 0x3bb47307, 0xef5e009c, 0xd267e5ea, 0x068d9671, 0x8e569607,
+ 0x5abce59c, 0x678500ea, 0xb36f7371, 0x1df7ca07, 0xc91db99c,
+ 0xf4245cea, 0x20ce2f71, 0xe4935d06, 0x30792e9d, 0x0d40cbeb,
+ 0xd9aab870, 0x77320106, 0xa3d8729d, 0x9ee197eb, 0x4a0be470,
+ 0xc2d0e406, 0x163a979d, 0x2b0372eb, 0xffe90170, 0x5171b806,
+ 0x859bcb9d, 0xb8a22eeb, 0x6c485d70, 0x6032940b, 0xb4d8e790,
+ 0x89e102e6, 0x5d0b717d, 0xf393c80b, 0x2779bb90, 0x1a405ee6,
+ 0xceaa2d7d, 0x46712d0b, 0x929b5e90, 0xafa2bbe6, 0x7b48c87d,
+ 0xd5d0710b, 0x013a0290, 0x3c03e7e6, 0xe8e9947d, 0x2cb4e60a,
+ 0xf85e9591, 0xc56770e7, 0x118d037c, 0xbf15ba0a, 0x6bffc991,
+ 0x56c62ce7, 0x822c5f7c, 0x0af75f0a, 0xde1d2c91, 0xe324c9e7,
+ 0x37ceba7c, 0x9956030a, 0x4dbc7091, 0x708595e7, 0xa46fe67c,
+ 0xf83e7109, 0x2cd40292, 0x11ede7e4, 0xc507947f, 0x6b9f2d09,
+ 0xbf755e92, 0x824cbbe4, 0x56a6c87f, 0xde7dc809, 0x0a97bb92,
+ 0x37ae5ee4, 0xe3442d7f, 0x4ddc9409, 0x9936e792, 0xa40f02e4,
+ 0x70e5717f, 0xb4b80308, 0x60527093, 0x5d6b95e5, 0x8981e67e,
+ 0x27195f08, 0xf3f32c93, 0xcecac9e5, 0x1a20ba7e, 0x92fbba08,
+ 0x4611c993, 0x7b282ce5, 0xafc25f7e, 0x015ae608, 0xd5b09593,
+ 0xe88970e5, 0x3c63037e, 0x502b5e0e, 0x84c12d95, 0xb9f8c8e3,
+ 0x6d12bb78, 0xc38a020e, 0x17607195, 0x2a5994e3, 0xfeb3e778,
+ 0x7668e70e, 0xa2829495, 0x9fbb71e3, 0x4b510278, 0xe5c9bb0e,
+ 0x3123c895, 0x0c1a2de3, 0xd8f05e78, 0x1cad2c0f, 0xc8475f94,
+ 0xf57ebae2, 0x2194c979, 0x8f0c700f, 0x5be60394, 0x66dfe6e2,
+ 0xb2359579, 0x3aee950f, 0xee04e694, 0xd33d03e2, 0x07d77079,
+ 0xa94fc90f, 0x7da5ba94, 0x409c5fe2, 0x94762c79, 0xc827bb0c,
+ 0x1ccdc897, 0x21f42de1, 0xf51e5e7a, 0x5b86e70c, 0x8f6c9497,
+ 0xb25571e1, 0x66bf027a, 0xee64020c, 0x3a8e7197, 0x07b794e1,
+ 0xd35de77a, 0x7dc55e0c, 0xa92f2d97, 0x9416c8e1, 0x40fcbb7a,
+ 0x84a1c90d, 0x504bba96, 0x6d725fe0, 0xb9982c7b, 0x1700950d,
+ 0xc3eae696, 0xfed303e0, 0x2a39707b, 0xa2e2700d, 0x76080396,
+ 0x4b31e6e0, 0x9fdb957b, 0x31432c0d, 0xe5a95f96, 0xd890bae0,
+ 0x0c7ac97b},
+ {0x00000000, 0x27652581, 0x0fcc3bd9, 0x28a91e58, 0x5f9e0669,
+ 0x78fb23e8, 0x50523db0, 0x77371831, 0xbe3c0dd2, 0x99592853,
+ 0xb1f0360b, 0x9695138a, 0xe1a20bbb, 0xc6c72e3a, 0xee6e3062,
+ 0xc90b15e3, 0x3d7f6b7f, 0x1a1a4efe, 0x32b350a6, 0x15d67527,
+ 0x62e16d16, 0x45844897, 0x6d2d56cf, 0x4a48734e, 0x834366ad,
+ 0xa426432c, 0x8c8f5d74, 0xabea78f5, 0xdcdd60c4, 0xfbb84545,
+ 0xd3115b1d, 0xf4747e9c, 0x7afed6fe, 0x5d9bf37f, 0x7532ed27,
+ 0x5257c8a6, 0x2560d097, 0x0205f516, 0x2aaceb4e, 0x0dc9cecf,
+ 0xc4c2db2c, 0xe3a7fead, 0xcb0ee0f5, 0xec6bc574, 0x9b5cdd45,
+ 0xbc39f8c4, 0x9490e69c, 0xb3f5c31d, 0x4781bd81, 0x60e49800,
+ 0x484d8658, 0x6f28a3d9, 0x181fbbe8, 0x3f7a9e69, 0x17d38031,
+ 0x30b6a5b0, 0xf9bdb053, 0xded895d2, 0xf6718b8a, 0xd114ae0b,
+ 0xa623b63a, 0x814693bb, 0xa9ef8de3, 0x8e8aa862, 0xb5fadc26,
+ 0x929ff9a7, 0xba36e7ff, 0x9d53c27e, 0xea64da4f, 0xcd01ffce,
+ 0xe5a8e196, 0xc2cdc417, 0x0bc6d1f4, 0x2ca3f475, 0x040aea2d,
+ 0x236fcfac, 0x5458d79d, 0x733df21c, 0x5b94ec44, 0x7cf1c9c5,
+ 0x8885b759, 0xafe092d8, 0x87498c80, 0xa02ca901, 0xd71bb130,
+ 0xf07e94b1, 0xd8d78ae9, 0xffb2af68, 0x36b9ba8b, 0x11dc9f0a,
+ 0x39758152, 0x1e10a4d3, 0x6927bce2, 0x4e429963, 0x66eb873b,
+ 0x418ea2ba, 0xcf040ad8, 0xe8612f59, 0xc0c83101, 0xe7ad1480,
+ 0x909a0cb1, 0xb7ff2930, 0x9f563768, 0xb83312e9, 0x7138070a,
+ 0x565d228b, 0x7ef43cd3, 0x59911952, 0x2ea60163, 0x09c324e2,
+ 0x216a3aba, 0x060f1f3b, 0xf27b61a7, 0xd51e4426, 0xfdb75a7e,
+ 0xdad27fff, 0xade567ce, 0x8a80424f, 0xa2295c17, 0x854c7996,
+ 0x4c476c75, 0x6b2249f4, 0x438b57ac, 0x64ee722d, 0x13d96a1c,
+ 0x34bc4f9d, 0x1c1551c5, 0x3b707444, 0x6af5b94d, 0x4d909ccc,
+ 0x65398294, 0x425ca715, 0x356bbf24, 0x120e9aa5, 0x3aa784fd,
+ 0x1dc2a17c, 0xd4c9b49f, 0xf3ac911e, 0xdb058f46, 0xfc60aac7,
+ 0x8b57b2f6, 0xac329777, 0x849b892f, 0xa3feacae, 0x578ad232,
+ 0x70eff7b3, 0x5846e9eb, 0x7f23cc6a, 0x0814d45b, 0x2f71f1da,
+ 0x07d8ef82, 0x20bdca03, 0xe9b6dfe0, 0xced3fa61, 0xe67ae439,
+ 0xc11fc1b8, 0xb628d989, 0x914dfc08, 0xb9e4e250, 0x9e81c7d1,
+ 0x100b6fb3, 0x376e4a32, 0x1fc7546a, 0x38a271eb, 0x4f9569da,
+ 0x68f04c5b, 0x40595203, 0x673c7782, 0xae376261, 0x895247e0,
+ 0xa1fb59b8, 0x869e7c39, 0xf1a96408, 0xd6cc4189, 0xfe655fd1,
+ 0xd9007a50, 0x2d7404cc, 0x0a11214d, 0x22b83f15, 0x05dd1a94,
+ 0x72ea02a5, 0x558f2724, 0x7d26397c, 0x5a431cfd, 0x9348091e,
+ 0xb42d2c9f, 0x9c8432c7, 0xbbe11746, 0xccd60f77, 0xebb32af6,
+ 0xc31a34ae, 0xe47f112f, 0xdf0f656b, 0xf86a40ea, 0xd0c35eb2,
+ 0xf7a67b33, 0x80916302, 0xa7f44683, 0x8f5d58db, 0xa8387d5a,
+ 0x613368b9, 0x46564d38, 0x6eff5360, 0x499a76e1, 0x3ead6ed0,
+ 0x19c84b51, 0x31615509, 0x16047088, 0xe2700e14, 0xc5152b95,
+ 0xedbc35cd, 0xcad9104c, 0xbdee087d, 0x9a8b2dfc, 0xb22233a4,
+ 0x95471625, 0x5c4c03c6, 0x7b292647, 0x5380381f, 0x74e51d9e,
+ 0x03d205af, 0x24b7202e, 0x0c1e3e76, 0x2b7b1bf7, 0xa5f1b395,
+ 0x82949614, 0xaa3d884c, 0x8d58adcd, 0xfa6fb5fc, 0xdd0a907d,
+ 0xf5a38e25, 0xd2c6aba4, 0x1bcdbe47, 0x3ca89bc6, 0x1401859e,
+ 0x3364a01f, 0x4453b82e, 0x63369daf, 0x4b9f83f7, 0x6cfaa676,
+ 0x988ed8ea, 0xbfebfd6b, 0x9742e333, 0xb027c6b2, 0xc710de83,
+ 0xe075fb02, 0xc8dce55a, 0xefb9c0db, 0x26b2d538, 0x01d7f0b9,
+ 0x297eeee1, 0x0e1bcb60, 0x792cd351, 0x5e49f6d0, 0x76e0e888,
+ 0x5185cd09}};
+
+#endif
+
+#endif
+
+#endif
+
+local const z_crc_t FAR x2n_table[] = {
+ 0x40000000, 0x20000000, 0x08000000, 0x00800000, 0x00008000,
+ 0xedb88320, 0xb1e6b092, 0xa06a2517, 0xed627dae, 0x88d14467,
+ 0xd7bbfe6a, 0xec447f11, 0x8e7ea170, 0x6427800e, 0x4d47bae0,
+ 0x09fe548f, 0x83852d0f, 0x30362f1a, 0x7b5a9cc3, 0x31fec169,
+ 0x9fec022a, 0x6c8dedc4, 0x15d6874d, 0x5fde7a4e, 0xbad90e37,
+ 0x2e4e5eef, 0x4eaba214, 0xa8a472c0, 0x429a969e, 0x148d302a,
+ 0xc40ba6d0, 0xc4e22c3c};
diff --git a/lib/zlib/inffast.c b/lib/zlib/inffast.c
new file mode 100644
index 0000000..1fec7f3
--- /dev/null
+++ b/lib/zlib/inffast.c
@@ -0,0 +1,323 @@
+/* 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 const *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 */
diff --git a/lib/zlib/inffast.h b/lib/zlib/inffast.h
new file mode 100644
index 0000000..e5c1aa4
--- /dev/null
+++ b/lib/zlib/inffast.h
@@ -0,0 +1,11 @@
+/* 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));
diff --git a/lib/zlib/inffixed.h b/lib/zlib/inffixed.h
new file mode 100644
index 0000000..d628327
--- /dev/null
+++ b/lib/zlib/inffixed.h
@@ -0,0 +1,94 @@
+ /* 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}
+ };
diff --git a/lib/zlib/inflate.c b/lib/zlib/inflate.c
new file mode 100644
index 0000000..8acbef4
--- /dev/null
+++ b/lib/zlib/inflate.c
@@ -0,0 +1,1595 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2022 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->flags = -1;
+ 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) {
+ if (windowBits < -15)
+ return Z_STREAM_ERROR;
+ 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 <stdio.h>
+
+/*
+ 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(check, buf, len) \
+ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+# define UPDATE_CHECK(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;
+ }
+ 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;
+ state->flags = 0; /* indicate zlib header */
+ 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;
+ /* fallthrough */
+ 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;
+ /* fallthrough */
+ 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;
+ /* fallthrough */
+ 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;
+ /* fallthrough */
+ 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) <
+ state->head->extra_max) {
+ 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;
+ /* fallthrough */
+ 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;
+ /* fallthrough */
+ 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;
+ /* fallthrough */
+ 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;
+ /* fallthrough */
+ case DICT:
+ if (state->havedict == 0) {
+ RESTORE();
+ return Z_NEED_DICT;
+ }
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ /* fallthrough */
+ case TYPE:
+ if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
+ /* fallthrough */
+ 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;
+ /* fallthrough */
+ case COPY_:
+ state->mode = COPY;
+ /* fallthrough */
+ 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;
+ /* fallthrough */
+ 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;
+ /* fallthrough */
+ 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;
+ /* fallthrough */
+ case LEN_:
+ state->mode = LEN;
+ /* fallthrough */
+ 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;
+ /* fallthrough */
+ 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;
+ /* fallthrough */
+ 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;
+ /* fallthrough */
+ 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;
+ /* fallthrough */
+ 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_CHECK(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;
+ /* fallthrough */
+ case LENGTH:
+ if (state->wrap && state->flags) {
+ NEEDBITS(32);
+ if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) {
+ strm->msg = (char *)"incorrect length check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: length matches trailer\n"));
+ }
+#endif
+ state->mode = DONE;
+ /* fallthrough */
+ 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:
+ /* fallthrough */
+ 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_CHECK(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 */
+ int flags; /* temporary to save header status */
+ 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;
+ if (state->flags == -1)
+ state->wrap = 0; /* if no header yet, treat as raw */
+ else
+ state->wrap &= ~4; /* no point in computing a check value now */
+ flags = state->flags;
+ in = strm->total_in; out = strm->total_out;
+ inflateReset(strm);
+ strm->total_in = in; strm->total_out = out;
+ state->flags = flags;
+ 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)
+ 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);
+}
diff --git a/lib/zlib/inflate.h b/lib/zlib/inflate.h
new file mode 100644
index 0000000..f127b6b
--- /dev/null
+++ b/lib/zlib/inflate.h
@@ -0,0 +1,126 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2019 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, or
+ -1 if raw or no header yet */
+ 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 */
+};
diff --git a/lib/zlib/inftrees.c b/lib/zlib/inftrees.c
new file mode 100644
index 0000000..57d2793
--- /dev/null
+++ b/lib/zlib/inftrees.c
@@ -0,0 +1,304 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2022 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.13 Copyright 1995-2022 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, 194, 65};
+ 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;
+}
diff --git a/lib/zlib/inftrees.h b/lib/zlib/inftrees.h
new file mode 100644
index 0000000..f536653
--- /dev/null
+++ b/lib/zlib/inftrees.h
@@ -0,0 +1,62 @@
+/* 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 distribution. 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));
diff --git a/lib/zlib/tf_gunzip.c b/lib/zlib/tf_gunzip.c
new file mode 100644
index 0000000..3ac80bc
--- /dev/null
+++ b/lib/zlib/tf_gunzip.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/tf_crc32.h>
+#include <lib/utils.h>
+#include <tf_gunzip.h>
+
+#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;
+}
+
+/* Wrapper function to calculate CRC
+ * @crc: previous accumulated CRC
+ * @buf: buffer base address
+ * @size: size of the buffer
+ *
+ * Return calculated CRC32 value
+ */
+uint32_t tf_crc32(uint32_t crc, const unsigned char *buf, size_t size)
+{
+ return (uint32_t)crc32((unsigned long)crc, buf, size);
+}
diff --git a/lib/zlib/zconf.h b/lib/zlib/zconf.h
new file mode 100644
index 0000000..bf977d3
--- /dev/null
+++ b/lib/zlib/zconf.h
@@ -0,0 +1,547 @@
+/* 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_combine_gen z_crc32_combine_gen
+# define crc32_combine_gen64 z_crc32_combine_gen64
+# define crc32_combine_op z_crc32_combine_op
+# 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 <stddef.h>
+ 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
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+ /* 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 <limits.h>
+# 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 <sys/types.h> /* for off_t */
+# endif
+#endif
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+# ifndef Z_SOLO
+# include <stdarg.h> /* for va_list */
+# endif
+#endif
+
+#ifdef _WIN32
+# ifndef Z_SOLO
+# include <stddef.h> /* 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
+
+#ifndef Z_HAVE_UNISTD_H
+# ifdef __WATCOMC__
+# define Z_HAVE_UNISTD_H
+# endif
+#endif
+#ifndef Z_HAVE_UNISTD_H
+# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32)
+# define Z_HAVE_UNISTD_H
+# endif
+#endif
+#ifndef Z_SOLO
+# if defined(Z_HAVE_UNISTD_H)
+# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
+# ifdef VMS
+# include <unixio.h> /* 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 */
diff --git a/lib/zlib/zlib.h b/lib/zlib/zlib.h
new file mode 100644
index 0000000..953cb50
--- /dev/null
+++ b/lib/zlib/zlib.h
@@ -0,0 +1,1935 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.2.13, October 13th, 2022
+
+ Copyright (C) 1995-2022 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.13"
+#define ZLIB_VERNUM 0x12d0
+#define ZLIB_VER_MAJOR 1
+#define ZLIB_VER_MINOR 2
+#define ZLIB_VER_REVISION 13
+#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 output
+ 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 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.
+ Similarly, 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 there have been any deflate() calls since the
+ state was initialized or reset, 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 members.
+ inflate() will return Z_STREAM_END at the end of the gzip member. The state
+ would need to be reset to continue decoding a subsequent gzip member. This
+ *must* be done if there is more data after a gzip member, in order for the
+ decompression to be compliant with the gzip standard (RFC 1952).
+
+ 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.
+ Similarly, 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));
+
+ Open the gzip (.gz) file at path for reading and decompressing, or
+ compressing and 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));
+/*
+ Associate 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 for file to
+ size. 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 and strategy for file. See the
+ description of deflateInit2 for the meaning of these parameters. Previously
+ provided data is flushed before applying the parameter changes.
+
+ 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));
+/*
+ Read and decompress up to len uncompressed bytes from file into buf. 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 and decompress up to nitems items of size size from file into 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 nevertheless 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, resetting and retrying on end-of-file, when size is not 1.
+*/
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file, voidpc buf, unsigned len));
+/*
+ Compress and write the len uncompressed bytes at buf to 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));
+/*
+ Compress and write 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, ...));
+/*
+ Convert, format, compress, and write the arguments (...) to file under
+ control of the string format, 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));
+/*
+ Compress and write the given null-terminated string s to 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));
+/*
+ Read and decompress bytes from file into buf, until len-1 characters are
+ read, or until 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
+ is one, the string is terminated with a null character. If no characters
+ are read due to an end-of-file or len is less than one, 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));
+/*
+ Compress and write c, converted to an unsigned char, into file. gzputc
+ returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+ Read and decompress one byte from 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 c back onto the stream for file to be read as the first character on
+ the next read. At least one character of push-back is always 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));
+/*
+ Flush all pending output to 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));
+
+ Set the starting position to offset relative to whence for the next gzread
+ or gzwrite on 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));
+/*
+ Rewind 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));
+
+ Return the starting position for the next gzread or gzwrite on 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));
+
+ Return the current compressed (actual) read or write offset of file. 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));
+/*
+ Return true (1) if the end-of-file indicator for file 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));
+/*
+ Return 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));
+/*
+ Flush all pending output for file, if necessary, close file and
+ deallocate 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));
+/*
+ Return the error message for the last error which occurred on 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));
+/*
+ Clear 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. An Adler-32 value is in the range of a 32-bit
+ unsigned integer. 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. A CRC-32 value is in the range of a 32-bit unsigned integer.
+ 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 crc, 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.
+*/
+
+/*
+ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t len2));
+
+ Return the operator corresponding to length len2, to be used with
+ crc32_combine_op().
+*/
+
+ZEXTERN uLong ZEXPORT crc32_combine_op OF((uLong crc1, uLong crc2, uLong op));
+/*
+ Give the same result as crc32_combine(), using op in place of len2. op is
+ is generated from len2 by crc32_combine_gen(). This will be faster than
+ crc32_combine() if the generated op is used more than once.
+*/
+
+
+ /* 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));
+ ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((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
+# define z_crc32_combine_gen z_crc32_combine_gen64
+# else
+# define gzopen gzopen64
+# define gzseek gzseek64
+# define gztell gztell64
+# define gzoffset gzoffset64
+# define adler32_combine adler32_combine64
+# define crc32_combine crc32_combine64
+# define crc32_combine_gen crc32_combine_gen64
+# 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));
+ ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((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));
+ ZEXTERN uLong ZEXPORT crc32_combine_gen OF((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));
+ ZEXTERN uLong ZEXPORT crc32_combine_gen OF((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(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 */
diff --git a/lib/zlib/zlib.mk b/lib/zlib/zlib.mk
new file mode 100644
index 0000000..98d4efa
--- /dev/null
+++ b/lib/zlib/zlib.mk
@@ -0,0 +1,25 @@
+#
+# 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
diff --git a/lib/zlib/zutil.c b/lib/zlib/zutil.c
new file mode 100644
index 0000000..9543ae8
--- /dev/null
+++ b/lib/zlib/zutil.c
@@ -0,0 +1,327 @@
+/* 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 <stdlib.h>
+# 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) && _WIN32_WCE < 0x800
+ /* The older 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 */
diff --git a/lib/zlib/zutil.h b/lib/zlib/zutil.h
new file mode 100644
index 0000000..0bc7f4e
--- /dev/null
+++ b/lib/zlib/zutil.h
@@ -0,0 +1,275 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2022 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 <stddef.h>
+# endif
+# include <string.h>
+# include <stdlib.h>
+#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;
+
+#if !defined(Z_U8) && !defined(Z_SOLO) && defined(STDC)
+# include <limits.h>
+# if (ULONG_MAX == 0xffffffffffffffff)
+# define Z_U8 unsigned long
+# elif (ULLONG_MAX == 0xffffffffffffffff)
+# define Z_U8 unsigned long long
+# elif (UINT_MAX == 0xffffffffffffffff)
+# define Z_U8 unsigned
+# endif
+#endif
+
+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 <alloc.h>
+# endif
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# 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 <malloc.h>
+# 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 <unix.h> /* 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() */
+# 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));
+ ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((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 <stdio.h>
+ 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 */
diff --git a/license.rst b/license.rst
new file mode 100644
index 0000000..3ec3b74
--- /dev/null
+++ b/license.rst
@@ -0,0 +1 @@
+See docs/license.rst
diff --git a/licenses/LICENSE.MIT b/licenses/LICENSE.MIT
new file mode 100644
index 0000000..8aa2645
--- /dev/null
+++ b/licenses/LICENSE.MIT
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) [year] [fullname]
+
+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.
diff --git a/make_helpers/arch_features.mk b/make_helpers/arch_features.mk
new file mode 100644
index 0000000..01e3e09
--- /dev/null
+++ b/make_helpers/arch_features.mk
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# This file lists all the checks related to the Architectural Feature
+# Enablement flags, based on the Architectural version.
+
+# Enable the features which are mandatory from ARCH version 8.1 and upwards.
+ifeq "8.1" "$(word 1, $(sort 8.1 $(ARM_ARCH_MAJOR).$(ARM_ARCH_MINOR)))"
+ENABLE_FEAT_PAN = 1
+ENABLE_FEAT_VHE = 1
+endif
+
+# Enable the features which are mandatory from ARCH version 8.4 and upwards.
+ifeq "8.4" "$(word 1, $(sort 8.4 $(ARM_ARCH_MAJOR).$(ARM_ARCH_MINOR)))"
+ENABLE_FEAT_DIT = 1
+ENABLE_FEAT_SEL2 = 1
+endif
+
+# Enable the features which are mandatory from ARCH version 8.5 and upwards.
+ifeq "8.5" "$(word 1, $(sort 8.5 $(ARM_ARCH_MAJOR).$(ARM_ARCH_MINOR)))"
+ENABLE_FEAT_SB = 1
+endif
+
+# Enable the features which are mandatory from ARCH version 8.6 and upwards.
+ifeq "8.6" "$(word 1, $(sort 8.6 $(ARM_ARCH_MAJOR).$(ARM_ARCH_MINOR)))"
+ENABLE_FEAT_FGT = 1
+ENABLE_FEAT_ECV = 1
+endif
+
+# Enable the features which are mandatory from ARCH version 8.7 and upwards.
+ifeq "8.7" "$(word 1, $(sort 8.7 $(ARM_ARCH_MAJOR).$(ARM_ARCH_MINOR)))"
+ENABLE_FEAT_HCX = 1
+endif
diff --git a/make_helpers/armv7-a-cpus.mk b/make_helpers/armv7-a-cpus.mk
new file mode 100644
index 0000000..eec85cc
--- /dev/null
+++ b/make_helpers/armv7-a-cpus.mk
@@ -0,0 +1,58 @@
+#
+# 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_defines,\
+ $(sort \
+ ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING \
+ ARMV7_SUPPORTS_VIRTUALIZATION \
+ ARMV7_SUPPORTS_GENERIC_TIMER \
+ ARMV7_SUPPORTS_VFP \
+)))
+endif
+
+ifeq ($(ARM_CORTEX_A5),yes)
+$(eval $(call add_define,ARM_CORTEX_A5))
+endif
diff --git a/make_helpers/build_env.mk b/make_helpers/build_env.mk
new file mode 100644
index 0000000..83093bd
--- /dev/null
+++ b/make_helpers/build_env.mk
@@ -0,0 +1,72 @@
+#
+# 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
diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk
new file mode 100644
index 0000000..426e344
--- /dev/null
+++ b/make_helpers/build_macros.mk
@@ -0,0 +1,633 @@
+#
+# Copyright (c) 2015-2022, 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 addding multiple build definitions
+# $(eval $(call add_defines,FOO BOO))
+define add_defines
+ $(foreach def,$1,$(eval $(call add_define,$(def))))
+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
+
+# Convenience function for verifying options have boolean values
+# $(eval $(call assert_booleans,FOO BOO)) will assert FOO and BOO for 0 or 1 values
+define assert_booleans
+ $(foreach bool,$1,$(eval $(call assert_boolean,$(bool))))
+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
+
+# Convenience function for verifying options have numeric values
+# $(eval $(call assert_numerics,FOO BOO)) will assert FOO and BOO contain numeric values
+define assert_numerics
+ $(foreach num,$1,$(eval $(call assert_numeric,$(num))))
+endef
+
+# CREATE_SEQ is a recursive function to create sequence of numbers from 1 to
+# $(2) and assign the sequence to $(1)
+define CREATE_SEQ
+$(if $(word $(2), $($(1))),\
+ $(eval $(1) += $(words $($(1))))\
+ $(eval $(1) := $(filter-out 0,$($(1)))),\
+ $(eval $(1) += $(words $($(1))))\
+ $(call CREATE_SEQ,$(1),$(2))\
+)
+endef
+
+# IMG_LINKERFILE defines the linker script corresponding to a BL stage
+# $(1) = BL stage
+define IMG_LINKERFILE
+ ${BUILD_DIR}/$(1).ld
+endef
+
+# IMG_MAPFILE defines the output file describing the memory map corresponding
+# to a BL stage
+# $(1) = BL stage
+define IMG_MAPFILE
+ ${BUILD_DIR}/$(1).map
+endef
+
+# IMG_ELF defines the elf file corresponding to a BL stage
+# $(1) = BL stage
+define IMG_ELF
+ ${BUILD_DIR}/$(1).elf
+endef
+
+# IMG_DUMP defines the symbols dump file corresponding to a BL stage
+# $(1) = BL stage
+define IMG_DUMP
+ ${BUILD_DIR}/$(1).dump
+endef
+
+# IMG_BIN defines the default image file corresponding to a BL stage
+# $(1) = BL stage
+define IMG_BIN
+ ${BUILD_PLAT}/$(1).bin
+endef
+
+# IMG_ENC_BIN defines the default encrypted image file corresponding to a
+# BL stage
+# $(1) = BL stage
+define IMG_ENC_BIN
+ ${BUILD_PLAT}/$(1)_enc.bin
+endef
+
+# ENCRYPT_FW invokes enctool to encrypt firmware binary
+# $(1) = input firmware binary
+# $(2) = output encrypted firmware binary
+define ENCRYPT_FW
+$(2): $(1) enctool
+ $$(ECHO) " ENC $$<"
+ $$(Q)$$(ENCTOOL) $$(ENC_ARGS) -i $$< -o $$@
+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)
+# $(5) = encrypted payload (optional) (ex. build/fvp/release/bl31_enc.bin)
+define TOOL_ADD_PAYLOAD
+ifneq ($(5),)
+ $(4)FIP_ARGS += $(2) $(5)
+ $(if $(3),$(4)CRT_DEPS += $(1))
+else
+ $(4)FIP_ARGS += $(2) $(1)
+ $(if $(3),$(4)CRT_DEPS += $(3))
+endif
+ $(if $(3),$(4)FIP_DEPS += $(3))
+ $(4)CRT_ARGS += $(2) $(1)
+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)
+# $(6) = encrypted payload (optional) (ex. build/fvp/release/bl31_enc.bin)
+
+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),$(6))
+
+else
+$(call TOOL_ADD_PAYLOAD,$(2),$(3),$(4),$(5),$(6))
+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)
+# $(4) = Image encryption flag (optional) (0, 1)
+# 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)))
+
+ # $(check_$(1)_cmd) variable is executed in the check_$(1) target and also
+ # is put into the ${CHECK_$(3)FIP_CMD} variable which is executed by the
+ # target ${BUILD_PLAT}/${$(3)FIP_NAME}.
+ $(eval check_$(1)_cmd := \
+ $(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)) \
+ )
+
+ $(3)CRT_DEPS += check_$(1)
+ CHECK_$(3)FIP_CMD += $$(check_$(1)_cmd)
+ifeq ($(4),1)
+ $(eval ENC_BIN := ${BUILD_PLAT}/$(1)_enc.bin)
+ $(call ENCRYPT_FW,$(value $(_V)),$(ENC_BIN))
+ $(call TOOL_ADD_IMG_PAYLOAD,$(1),$(value $(_V)),$(2),$(ENC_BIN),$(3), \
+ $(ENC_BIN))
+else
+ $(call TOOL_ADD_IMG_PAYLOAD,$(1),$(value $(_V)),$(2),$(if $(wildcard $(value $(_V))),$(value $(_V)),FORCE),$(3))
+endif
+
+.PHONY: check_$(1)
+check_$(1):
+ $(check_$(1)_cmd)
+endef
+
+# SELECT_OPENSSL_API_VERSION selects the OpenSSL API version to be used to
+# build the host tools by checking the version of OpenSSL located under
+# the path defined by the OPENSSL_DIR variable. It receives no parameters.
+define SELECT_OPENSSL_API_VERSION
+ # Set default value for USING_OPENSSL3 macro to 0
+ $(eval USING_OPENSSL3 = 0)
+ # Obtain the OpenSSL version for the build located under OPENSSL_DIR
+ $(eval OPENSSL_INFO := $(shell LD_LIBRARY_PATH=${OPENSSL_DIR}:${OPENSSL_DIR}/lib ${OPENSSL_BIN_PATH}/openssl version))
+ $(eval OPENSSL_CURRENT_VER = $(word 2, ${OPENSSL_INFO}))
+ $(eval OPENSSL_CURRENT_VER_MAJOR = $(firstword $(subst ., ,$(OPENSSL_CURRENT_VER))))
+ # If OpenSSL version is 3.x, then set USING_OPENSSL3 flag to 1
+ $(if $(filter 3,$(OPENSSL_CURRENT_VER_MAJOR)), $(eval USING_OPENSSL3 = 1))
+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
+define MAKE_C
+
+$(eval OBJ := $(1)/$(patsubst %.c,%.o,$(notdir $(2))))
+$(eval DEP := $(patsubst %.o,%.d,$(OBJ)))
+$(eval BL_CPPFLAGS := $($(call uppercase,$(3))_CPPFLAGS) -DIMAGE_$(call uppercase,$(3)))
+$(eval BL_CFLAGS := $($(call uppercase,$(3))_CFLAGS))
+
+$(OBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | $(3)_dirs
+ $$(ECHO) " CC $$<"
+ $$(Q)$$(CC) $$(LTO_CFLAGS) $$(TF_CFLAGS) $$(CFLAGS) $(BL_CPPFLAGS) $(BL_CFLAGS) $(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
+define MAKE_S
+
+$(eval OBJ := $(1)/$(patsubst %.S,%.o,$(notdir $(2))))
+$(eval DEP := $(patsubst %.o,%.d,$(OBJ)))
+$(eval BL_CPPFLAGS := $($(call uppercase,$(3))_CPPFLAGS) -DIMAGE_$(call uppercase,$(3)))
+$(eval BL_ASFLAGS := $($(call uppercase,$(3))_ASFLAGS))
+
+$(OBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | $(3)_dirs
+ $$(ECHO) " AS $$<"
+ $$(Q)$$(AS) $$(ASFLAGS) $(BL_CPPFLAGS) $(BL_ASFLAGS) $(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
+define MAKE_LD
+
+$(eval DEP := $(1).d)
+$(eval BL_CPPFLAGS := $($(call uppercase,$(3))_CPPFLAGS) -DIMAGE_$(call uppercase,$(3)))
+
+$(1): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | $(3)_dirs
+ $$(ECHO) " PP $$<"
+ $$(Q)$$(CPP) $$(CPPFLAGS) $(BL_CPPFLAGS) $(TF_CFLAGS_$(ARCH)) -P -x assembler-with-cpp -D__LINKER__ $(MAKE_DEP) -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
+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) = 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)
+# $(4) = BL encryption flag (optional) (0, 1)
+define MAKE_BL
+ $(eval BUILD_DIR := ${BUILD_PLAT}/$(1))
+ $(eval BL_SOURCES := $($(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 ENC_BIN := $(call IMG_ENC_BIN,$(1)))
+ $(eval BL_LINKERFILE := $($(call uppercase,$(1))_LINKERFILE))
+ $(eval BL_LIBS := $($(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 : ${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.
+${1}_dirs: | ${OBJ_DIRS}
+
+$(eval $(call MAKE_OBJS,$(BUILD_DIR),$(SOURCES),$(1)))
+$(eval $(call MAKE_LD,$(LINKERFILE),$(BL_LINKERFILE),$(1)))
+$(eval BL_LDFLAGS := $($(call uppercase,$(1))_LDFLAGS))
+
+ifeq ($(USE_ROMLIB),1)
+$(ELF): romlib.bin
+endif
+
+# MODULE_OBJS can be assigned by vendors with different compiled
+# object file path, and prebuilt object file path.
+$(eval OBJS += $(MODULE_OBJS))
+
+$(ELF): $(OBJS) $(LINKERFILE) | $(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}"; \
+ const char version[] = "${VERSION}";' | \
+ $$(CC) $$(TF_CFLAGS) $$(CFLAGS) -xc -c - -o $(BUILD_DIR)/build_message.o
+endif
+ifneq ($(findstring armlink,$(notdir $(LD))),)
+ $$(Q)$$(LD) -o $$@ $$(TF_LDFLAGS) $$(LDFLAGS) $(BL_LDFLAGS) --entry=${1}_entrypoint \
+ --predefine="-D__LINKER__=$(__LINKER__)" \
+ --predefine="-DTF_CFLAGS=$(TF_CFLAGS)" \
+ --map --list="$(MAPFILE)" --scatter=${PLAT_DIR}/scat/${1}.scat \
+ $(LDPATHS) $(LIBWRAPPER) $(LDLIBS) $(BL_LIBS) \
+ $(BUILD_DIR)/build_message.o $(OBJS)
+else ifneq ($(findstring gcc,$(notdir $(LD))),)
+ $$(Q)$$(LD) -o $$@ $$(TF_LDFLAGS) $$(LDFLAGS) -Wl,-Map=$(MAPFILE) \
+ -Wl,-dT $(LINKERFILE) $(EXTRA_LINKERFILE) $(BUILD_DIR)/build_message.o \
+ $(OBJS) $(LDPATHS) $(LIBWRAPPER) $(LDLIBS) $(BL_LIBS)
+else
+ $$(Q)$$(LD) -o $$@ $$(TF_LDFLAGS) $$(LDFLAGS) $(BL_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: $(1)
+ifeq ($(DISABLE_BIN_GENERATION),1)
+$(1): $(ELF) $(DUMP)
+else
+$(1): $(BIN) $(DUMP)
+endif
+
+all: $(1)
+
+ifeq ($(4),1)
+$(call ENCRYPT_FW,$(BIN),$(ENC_BIN))
+$(if $(2),$(call TOOL_ADD_IMG_PAYLOAD,$(1),$(BIN),--$(2),$(ENC_BIN),$(3), \
+ $(ENC_BIN)))
+else
+$(if $(2),$(call TOOL_ADD_IMG_PAYLOAD,$(1),$(BIN),--$(2),$(BIN),$(3)))
+endif
+
+endef
+
+# Convert device tree source file names to matching blobs
+# $(1) = input dts
+define SOURCES_TO_DTBS
+ $(notdir $(patsubst %.dts,%.dtb,$(filter %.dts,$(1))))
+endef
+
+# MAKE_FDT_DIRS macro creates the prerequisite directories that host the
+# FDT binaries
+# $(1) = output directory
+# $(2) = input dts
+define MAKE_FDT_DIRS
+ $(eval DTBS := $(addprefix $(1)/,$(call SOURCES_TO_DTBS,$(2))))
+ $(eval TEMP_DTB_DIRS := $(sort $(dir ${DTBS})))
+ # The $(dir ) function leaves a trailing / on the directory names
+ # Rip off the / to match directory names with make rule targets.
+ $(eval DTB_DIRS := $(patsubst %/,%,$(TEMP_DTB_DIRS)))
+
+$(eval $(foreach objd,${DTB_DIRS},$(call MAKE_PREREQ_DIR,${objd},${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) -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
diff --git a/make_helpers/cygwin.mk b/make_helpers/cygwin.mk
new file mode 100644
index 0000000..04a963f
--- /dev/null
+++ b/make_helpers/cygwin.mk
@@ -0,0 +1,19 @@
+#
+# 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
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
new file mode 100644
index 0000000..683d7ac
--- /dev/null
+++ b/make_helpers/defaults.mk
@@ -0,0 +1,486 @@
+#
+# Copyright (c) 2016-2022, Arm Limited. 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 feature modifiers: none by default
+ARM_ARCH_FEATURE := none
+
+# 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
+
+# Only use SP packages if SP layout JSON is defined
+BL2_ENABLE_SP_LOAD := 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
+
+# Include Nested virtualization control (Armv8.4-NV) registers in cpu context.
+# This must be set to 1 if architecture implements Nested Virtualization
+# Extension and platform wants to use this feature in the Secure world
+CTX_INCLUDE_NEVE_REGS := 0
+
+# Debug build
+DEBUG := 0
+
+# By default disable authenticated decryption support.
+DECRYPTION_SUPPORT := none
+
+# Build platform
+DEFAULT_PLAT := fvp
+
+# Disable the generation of the binary image (ELF only).
+DISABLE_BIN_GENERATION := 0
+
+# Disable MTPMU if FEAT_MTPMU is supported. Default is 0 to keep backwards
+# compatibility.
+DISABLE_MTPMU := 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
+
+# Enable the Maximum Power Mitigation Mechanism on supporting cores.
+ENABLE_MPMM := 0
+
+# Enable MPMM configuration via FCONF.
+ENABLE_MPMM_FCONF := 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 Realm Management Extension (FEAT_RME)
+ENABLE_RME := 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
+
+# Flag to enable access to the HAFGRTR_EL2 register
+ENABLE_FEAT_AMUv1 := 0
+
+# Flag to enable AMUv1p1 extension.
+ENABLE_FEAT_AMUv1p1 := 0
+
+# Flag to enable CSV2_2 extension.
+ENABLE_FEAT_CSV2_2 := 0
+
+# Flag to enable access to the HCRX_EL2 register by setting SCR_EL3.HXEn.
+ENABLE_FEAT_HCX := 0
+
+# Flag to enable access to the HDFGRTR_EL2 register
+ENABLE_FEAT_FGT := 0
+
+# Flag to enable access to the CNTPOFF_EL2 register
+ENABLE_FEAT_ECV := 0
+
+# Flag to enable use of the DIT feature.
+ENABLE_FEAT_DIT := 0
+
+# Flag to enable access to Privileged Access Never bit of PSTATE.
+ENABLE_FEAT_PAN := 0
+
+# Flag to enable access to the Random Number Generator registers
+ENABLE_FEAT_RNG := 0
+
+# Flag to enable support for EL3 trapping of reads of the RNDR and RNDRRS
+# registers, by setting SCR_EL3.TRNDR.
+ENABLE_FEAT_RNG_TRAP := 0
+
+# Flag to enable Speculation Barrier Instruction
+ENABLE_FEAT_SB := 0
+
+# Flag to enable Secure EL-2 feature.
+ENABLE_FEAT_SEL2 := 0
+
+# Flag to enable Virtualization Host Extensions
+ENABLE_FEAT_VHE := 0
+
+# Flag to enable delayed trapping of WFE instruction (FEAT_TWED)
+ENABLE_FEAT_TWED := 0
+
+# By default BL31 encryption disabled
+ENCRYPT_BL31 := 0
+
+# By default BL32 encryption disabled
+ENCRYPT_BL32 := 0
+
+# Default dummy firmware encryption key
+ENC_KEY := 1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
+
+# Default dummy nonce for firmware encryption
+ENC_NONCE := 1234567890abcdef12345678
+
+# Build flag to treat usage of deprecated platform and framework APIs as error.
+ERROR_DEPRECATED := 0
+
+# Fault injection support
+FAULT_INJECTION_SUPPORT := 0
+
+# Flag to enable architectural features detection mechanism
+FEATURE_DETECTION := 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
+
+# By default firmware encryption with SSK
+FW_ENC_STATUS := 0
+
+# 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 NS External Aborts to EL3. Disabled by default; External Aborts are handled
+# by lower ELs.
+HANDLE_EA_EL3_FIRST_NS := 0
+
+# Secure hash algorithm flag, accepts 3 values: sha256, sha384 and sha512.
+# The default value is sha256.
+HASH_ALG := sha256
+
+# 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
+
+# Set the default key size in case KEY_ALG is rsa
+ifeq ($(KEY_ALG),rsa)
+KEY_SIZE := 2048
+endif
+
+# Option to build TF with Measured Boot support
+MEASURED_BOOT := 0
+
+# 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
+
+# By default, clear the input registers when RESET_TO_BL31 is enabled
+RESET_TO_BL31_WITH_PARAMS := 0
+
+# For Chain of Trust
+SAVE_KEYS := 0
+
+# Software Delegated Exception support
+SDEI_SUPPORT := 0
+
+# True Random Number firmware Interface support
+TRNG_SUPPORT := 0
+
+# SMCCC PCI support
+SMC_PCI_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
+
+# Put NOBITS sections (.bss, stacks, page tables, and coherent memory) in a
+# separate memory region, which may be discontiguous from the rest of BL31.
+SEPARATE_NOBITS_REGION := 0
+
+# Put BL2 NOLOAD sections (.bss, stacks, page tables) in a separate memory
+# region, platform Makefile is free to override this value.
+SEPARATE_BL2_NOLOAD_REGION := 0
+
+# If the BL31 image initialisation code is recalimed after use for the secondary
+# cores stack
+RECLAIM_INIT_CODE := 0
+
+# SPD choice
+SPD := none
+
+# Enable the Management Mode (MM)-based Secure Partition Manager implementation
+SPM_MM := 0
+
+# Use the FF-A SPMC implementation in EL3.
+SPMC_AT_EL3 := 0
+
+# Use SPM at S-EL2 as a default config for SPMD
+SPMD_SPM_AT_SEL2 := 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 add debugfs support
+USE_DEBUGFS := 0
+
+# Build option to fconf based io
+ARM_IO_IN_DTB := 0
+
+# Build option to support SDEI through fconf
+SDEI_IN_FCONF := 0
+
+# Build option to support Secure Interrupt descriptors through fconf
+SEC_INT_DESC_IN_FCONF := 0
+
+# Build option to choose whether Trusted Firmware uses library at ROM
+USE_ROMLIB := 0
+
+# Build option to choose whether the xlat tables of BL images can be read-only.
+# Note that this only serves as a higher level option to PLAT_RO_XLAT_TABLES,
+# which is the per BL-image option that actually enables the read-only tables
+# API. The reason for having this additional option is to have a common high
+# level makefile where we can check for incompatible features/build options.
+ALLOW_RO_XLAT_TABLES := 0
+
+# Chain of trust.
+COT := tbbr
+
+# 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
+ENABLE_AMU_AUXILIARY_COUNTERS := 0
+ENABLE_AMU_FCONF := 0
+AMU_RESTRICT_COUNTERS := 0
+
+# Enable SVE for non-secure world by default
+ENABLE_SVE_FOR_NS := 1
+# SVE is only supported on AArch64 so disable it on AArch32.
+ifeq (${ARCH},aarch32)
+ override ENABLE_SVE_FOR_NS := 0
+endif
+ENABLE_SVE_FOR_SWD := 0
+
+# Default SVE vector length to maximum architected value
+SVE_VECTOR_LEN := 2048
+
+# SME defaults to disabled
+ENABLE_SME_FOR_NS := 0
+ENABLE_SME_FOR_SWD := 0
+
+# If SME is enabled then force SVE off
+ifeq (${ENABLE_SME_FOR_NS},1)
+ override ENABLE_SVE_FOR_NS := 0
+ override ENABLE_SVE_FOR_SWD := 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
+
+# Enable Link Time Optimization
+ENABLE_LTO := 0
+
+# Build flag to include EL2 registers in cpu context save and restore during
+# S-EL2 firmware entry/exit. This flag is to be used with SPD=spmd option.
+# Default is 0.
+CTX_INCLUDE_EL2_REGS := 0
+
+# Enable Memory tag extension which is supported for architecture greater
+# than Armv8.5-A
+# By default it is set to "no"
+SUPPORT_STACK_MEMTAG := no
+
+# Select workaround for AT speculative behaviour.
+ERRATA_SPECULATIVE_AT := 0
+
+# Trap RAS error record access from Non secure
+RAS_TRAP_NS_ERR_REC_ACCESS := 0
+
+# Build option to create cot descriptors using fconf
+COT_DESC_IN_DTB := 0
+
+# Build option to provide OpenSSL directory path
+OPENSSL_DIR := /usr
+
+# Select the openssl binary provided in OPENSSL_DIR variable
+ifeq ("$(wildcard ${OPENSSL_DIR}/bin)", "")
+ OPENSSL_BIN_PATH = ${OPENSSL_DIR}/apps
+else
+ OPENSSL_BIN_PATH = ${OPENSSL_DIR}/bin
+endif
+
+# Build option to use the SP804 timer instead of the generic one
+USE_SP804_TIMER := 0
+
+# Build option to define number of firmware banks, used in firmware update
+# metadata structure.
+NR_OF_FW_BANKS := 2
+
+# Build option to define number of images in firmware bank, used in firmware
+# update metadata structure.
+NR_OF_IMAGES_IN_FW_BANK := 1
+
+# Disable Firmware update support by default
+PSA_FWU_SUPPORT := 0
+
+# By default, disable access of trace buffer control registers from NS
+# lower ELs i.e. NS-EL2, or NS-EL1 if NS-EL2 implemented but unused
+# if FEAT_TRBE is implemented.
+# Note FEAT_TRBE is only supported on AArch64 - therefore do not enable in
+# AArch32.
+ifneq (${ARCH},aarch32)
+ ENABLE_TRBE_FOR_NS := 0
+else
+ override ENABLE_TRBE_FOR_NS := 0
+endif
+
+# By default, disable access to branch record buffer control registers from NS
+# lower ELs i.e. NS-EL2, or NS-EL1 if NS-EL2 implemented but unused
+# if FEAT_BRBE is implemented.
+ENABLE_BRBE_FOR_NS := 0
+
+# By default, disable access of trace system registers from NS lower
+# ELs i.e. NS-EL2, or NS-EL1 if NS-EL2 implemented but unused if
+# system register trace is implemented.
+ENABLE_SYS_REG_TRACE_FOR_NS := 0
+
+# By default, disable trace filter control registers access to NS
+# lower ELs, i.e. NS-EL2, or NS-EL1 if NS-EL2 implemented but unused
+# if FEAT_TRF is implemented.
+ENABLE_TRF_FOR_NS := 0
+
+# In v8.6+ platforms with delayed trapping of WFE being supported
+# via FEAT_TWED, this flag takes the delay value to be set in the
+# SCR_EL3.TWEDEL(4bit) field, when FEAT_TWED is implemented.
+# By default it takes 0, and need to be updated by the platforms.
+TWED_DELAY := 0
+
+# By default, disable the mocking of RSS provided services
+PLAT_RSS_NOT_SUPPORTED := 0
+
+# Dynamic Root of Trust for Measurement support
+DRTM_SUPPORT := 0
+
+# Check platform if cache management operations should be performed.
+# Disabled by default.
+CONDITIONAL_CMO := 0
diff --git a/make_helpers/msys.mk b/make_helpers/msys.mk
new file mode 100644
index 0000000..7e60d57
--- /dev/null
+++ b/make_helpers/msys.mk
@@ -0,0 +1,20 @@
+#
+# 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
+
diff --git a/make_helpers/plat_helpers.mk b/make_helpers/plat_helpers.mk
new file mode 100644
index 0000000..a7ae9a2
--- /dev/null
+++ b/make_helpers/plat_helpers.mk
@@ -0,0 +1,38 @@
+#
+# 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=<platform name> 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
diff --git a/make_helpers/tbbr/tbbr_tools.mk b/make_helpers/tbbr/tbbr_tools.mk
new file mode 100644
index 0000000..5ef2d85
--- /dev/null
+++ b/make_helpers/tbbr/tbbr_tools.mk
@@ -0,0 +1,140 @@
+#
+# Copyright (c) 2015-2022, 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_BL2: indicates whether BL2 is needed by the platform
+# 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
+# PROT_KEY
+# PLAT_KEY
+# SWD_ROT_KEY
+# CORE_SWD_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
+ifneq (${COT},cca)
+$(eval $(call TOOL_ADD_PAYLOAD,${TRUSTED_KEY_CERT},--trusted-key-cert))
+else
+$(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/cca.crt,--cca-cert))
+$(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/core-swd.crt,--core-swd-cert))
+$(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/plat-key.crt,--plat-key-cert))
+endif
+
+# Add fwu certificate to the fiptool and cert_create command line options
+ifneq (${COT},cca)
+$(eval $(call TOOL_ADD_PAYLOAD,${FWU_CERT},--fwu-cert,,FWU_))
+endif
+
+# 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_ALG},$(eval $(call CERT_ADD_CMD_OPT,${KEY_ALG},--key-alg,FWU_)))
+$(if ${KEY_SIZE},$(eval $(call CERT_ADD_CMD_OPT,${KEY_SIZE},--key-size)))
+$(if ${KEY_SIZE},$(eval $(call CERT_ADD_CMD_OPT,${KEY_SIZE},--key-size,FWU_)))
+$(if ${HASH_ALG},$(eval $(call CERT_ADD_CMD_OPT,${HASH_ALG},--hash-alg)))
+$(if ${HASH_ALG},$(eval $(call CERT_ADD_CMD_OPT,${HASH_ALG},--hash-alg,FWU_)))
+$(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 ${PROT_KEY},$(eval $(call CERT_ADD_CMD_OPT,${PROT_KEY},--prot-key)))
+$(if ${PLAT_KEY},$(eval $(call CERT_ADD_CMD_OPT,${PLAT_KEY},--plat-key)))
+$(if ${SWD_ROT_KEY},$(eval $(call CERT_ADD_CMD_OPT,${SWD_ROT_KEY},--swd-rot-key)))
+$(if ${CORE_SWD_KEY},$(eval $(call CERT_ADD_CMD_OPT,${CORE_SWD_KEY},--core-swd-key)))
+$(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 (${NEED_BL2},yes)
+ifeq (${BL2_AT_EL3}, 0)
+ifneq (${COT},cca)
+$(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/tb_fw.crt,--tb-fw-cert))
+endif
+endif
+endif
+
+# Add the SCP_BL2 CoT (key cert + img cert)
+ifneq (${SCP_BL2},)
+ifneq (${COT},cca)
+ $(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
+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)))
+ifneq (${COT},cca)
+$(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
+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))
+ifneq (${COT},dualroot)
+ ifneq (${COT},cca)
+ $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/nt_fw_key.crt,--nt-fw-key-cert))
+ endif
+endif
+endif
+
+# Add SiP owned Secure Partitions CoT (image cert)
+ifneq (${SP_LAYOUT_FILE},)
+ $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/sip_sp_content.crt,--sip-sp-cert))
+ifeq (${COT},dualroot)
+ $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/plat_sp_content.crt,--plat-sp-cert))
+endif
+ifeq (${COT},cca)
+ $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/plat_sp_content.crt,--plat-sp-cert))
+endif
+endif
diff --git a/make_helpers/unix.mk b/make_helpers/unix.mk
new file mode 100644
index 0000000..545ddfd
--- /dev/null
+++ b/make_helpers/unix.mk
@@ -0,0 +1,60 @@
+#
+# 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
diff --git a/make_helpers/windows.mk b/make_helpers/windows.mk
new file mode 100644
index 0000000..b6d6f0b
--- /dev/null
+++ b/make_helpers/windows.mk
@@ -0,0 +1,91 @@
+#
+# Copyright (c) 2016-2022, 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}";
+VERSION_MESSAGE = const char version[] = "${VERSION}";
+define MAKE_BUILD_STRINGS
+ @echo $$(BUILT_TIME_DATE_STRING) $$(VERSION_STRING_MESSAGE) $$(VERSION_MESSAGE) | \
+ $$(CC) $$(TF_CFLAGS) $$(CFLAGS) -x c -c - -o $1
+endef
+
+MSVC_NMAKE := nmake.exe
+
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..a3e0ff9
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,7075 @@
+{
+ "name": "trusted-firmware-a",
+ "version": "2.8.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "trusted-firmware-a",
+ "version": "2.8.0",
+ "hasInstallScript": true,
+ "license": "BSD-3-Clause",
+ "devDependencies": {
+ "@commitlint/cli": "^16.1.0",
+ "@commitlint/config-conventional": "^16.0.0",
+ "@commitlint/cz-commitlint": "^16.1.0",
+ "commitizen": "^4.2.4",
+ "conventional-changelog-tf-a": "file:tools/conventional-changelog-tf-a",
+ "husky": "^7.0.4",
+ "js-yaml": "^4.1.0",
+ "standard-version": "^9.3.2"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
+ "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/highlight": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.19.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
+ "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/highlight": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
+ "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.18.6",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true
+ },
+ "node_modules/@babel/highlight/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@commitlint/cli": {
+ "version": "16.3.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-16.3.0.tgz",
+ "integrity": "sha512-P+kvONlfsuTMnxSwWE1H+ZcPMY3STFaHb2kAacsqoIkNx66O0T7sTpBxpxkMrFPyhkJiLJnJWMhk4bbvYD3BMA==",
+ "dev": true,
+ "dependencies": {
+ "@commitlint/format": "^16.2.1",
+ "@commitlint/lint": "^16.2.4",
+ "@commitlint/load": "^16.3.0",
+ "@commitlint/read": "^16.2.1",
+ "@commitlint/types": "^16.2.1",
+ "lodash": "^4.17.19",
+ "resolve-from": "5.0.0",
+ "resolve-global": "1.0.0",
+ "yargs": "^17.0.0"
+ },
+ "bin": {
+ "commitlint": "cli.js"
+ },
+ "engines": {
+ "node": ">=v12"
+ }
+ },
+ "node_modules/@commitlint/config-conventional": {
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-16.2.4.tgz",
+ "integrity": "sha512-av2UQJa3CuE5P0dzxj/o/B9XVALqYzEViHrMXtDrW9iuflrqCStWBAioijppj9URyz6ONpohJKAtSdgAOE0gkA==",
+ "dev": true,
+ "dependencies": {
+ "conventional-changelog-conventionalcommits": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=v12"
+ }
+ },
+ "node_modules/@commitlint/config-validator": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-16.2.1.tgz",
+ "integrity": "sha512-hogSe0WGg7CKmp4IfNbdNES3Rq3UEI4XRPB8JL4EPgo/ORq5nrGTVzxJh78omibNuB8Ho4501Czb1Er1MoDWpw==",
+ "dev": true,
+ "dependencies": {
+ "@commitlint/types": "^16.2.1",
+ "ajv": "^6.12.6"
+ },
+ "engines": {
+ "node": ">=v12"
+ }
+ },
+ "node_modules/@commitlint/cz-commitlint": {
+ "version": "16.3.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/cz-commitlint/-/cz-commitlint-16.3.0.tgz",
+ "integrity": "sha512-Q+QLQmSIHEgzI18F3/7mqq3vwL0IN9k+Tjp9Um4adFnRXMtUTnEa0er0CXAXxWvoA/x/6nt3t7faAv2HugDIGg==",
+ "dev": true,
+ "dependencies": {
+ "@commitlint/ensure": "^16.2.1",
+ "@commitlint/load": "^16.3.0",
+ "@commitlint/types": "^16.2.1",
+ "chalk": "^4.1.0",
+ "lodash": "^4.17.21",
+ "word-wrap": "^1.2.3"
+ },
+ "engines": {
+ "node": ">=v12"
+ },
+ "peerDependencies": {
+ "commitizen": "^4.0.3",
+ "inquirer": "^8.0.0"
+ }
+ },
+ "node_modules/@commitlint/ensure": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-16.2.1.tgz",
+ "integrity": "sha512-/h+lBTgf1r5fhbDNHOViLuej38i3rZqTQnBTk+xEg+ehOwQDXUuissQ5GsYXXqI5uGy+261ew++sT4EA3uBJ+A==",
+ "dev": true,
+ "dependencies": {
+ "@commitlint/types": "^16.2.1",
+ "lodash": "^4.17.19"
+ },
+ "engines": {
+ "node": ">=v12"
+ }
+ },
+ "node_modules/@commitlint/execute-rule": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-16.2.1.tgz",
+ "integrity": "sha512-oSls82fmUTLM6cl5V3epdVo4gHhbmBFvCvQGHBRdQ50H/690Uq1Dyd7hXMuKITCIdcnr9umyDkr8r5C6HZDF3g==",
+ "dev": true,
+ "engines": {
+ "node": ">=v12"
+ }
+ },
+ "node_modules/@commitlint/format": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-16.2.1.tgz",
+ "integrity": "sha512-Yyio9bdHWmNDRlEJrxHKglamIk3d6hC0NkEUW6Ti6ipEh2g0BAhy8Od6t4vLhdZRa1I2n+gY13foy+tUgk0i1Q==",
+ "dev": true,
+ "dependencies": {
+ "@commitlint/types": "^16.2.1",
+ "chalk": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=v12"
+ }
+ },
+ "node_modules/@commitlint/is-ignored": {
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-16.2.4.tgz",
+ "integrity": "sha512-Lxdq9aOAYCOOOjKi58ulbwK/oBiiKz+7Sq0+/SpFIEFwhHkIVugvDvWjh2VRBXmRC/x5lNcjDcYEwS/uYUvlYQ==",
+ "dev": true,
+ "dependencies": {
+ "@commitlint/types": "^16.2.1",
+ "semver": "7.3.7"
+ },
+ "engines": {
+ "node": ">=v12"
+ }
+ },
+ "node_modules/@commitlint/lint": {
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-16.2.4.tgz",
+ "integrity": "sha512-AUDuwOxb2eGqsXbTMON3imUGkc1jRdtXrbbohiLSCSk3jFVXgJLTMaEcr39pR00N8nE9uZ+V2sYaiILByZVmxQ==",
+ "dev": true,
+ "dependencies": {
+ "@commitlint/is-ignored": "^16.2.4",
+ "@commitlint/parse": "^16.2.1",
+ "@commitlint/rules": "^16.2.4",
+ "@commitlint/types": "^16.2.1"
+ },
+ "engines": {
+ "node": ">=v12"
+ }
+ },
+ "node_modules/@commitlint/load": {
+ "version": "16.3.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-16.3.0.tgz",
+ "integrity": "sha512-3tykjV/iwbkv2FU9DG+NZ/JqmP0Nm3b7aDwgCNQhhKV5P74JAuByULkafnhn+zsFGypG1qMtI5u+BZoa9APm0A==",
+ "dev": true,
+ "dependencies": {
+ "@commitlint/config-validator": "^16.2.1",
+ "@commitlint/execute-rule": "^16.2.1",
+ "@commitlint/resolve-extends": "^16.2.1",
+ "@commitlint/types": "^16.2.1",
+ "@types/node": ">=12",
+ "chalk": "^4.0.0",
+ "cosmiconfig": "^7.0.0",
+ "cosmiconfig-typescript-loader": "^2.0.0",
+ "lodash": "^4.17.19",
+ "resolve-from": "^5.0.0",
+ "typescript": "^4.4.3"
+ },
+ "engines": {
+ "node": ">=v12"
+ }
+ },
+ "node_modules/@commitlint/message": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-16.2.1.tgz",
+ "integrity": "sha512-2eWX/47rftViYg7a3axYDdrgwKv32mxbycBJT6OQY/MJM7SUfYNYYvbMFOQFaA4xIVZt7t2Alyqslbl6blVwWw==",
+ "dev": true,
+ "engines": {
+ "node": ">=v12"
+ }
+ },
+ "node_modules/@commitlint/parse": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-16.2.1.tgz",
+ "integrity": "sha512-2NP2dDQNL378VZYioLrgGVZhWdnJO4nAxQl5LXwYb08nEcN+cgxHN1dJV8OLJ5uxlGJtDeR8UZZ1mnQ1gSAD/g==",
+ "dev": true,
+ "dependencies": {
+ "@commitlint/types": "^16.2.1",
+ "conventional-changelog-angular": "^5.0.11",
+ "conventional-commits-parser": "^3.2.2"
+ },
+ "engines": {
+ "node": ">=v12"
+ }
+ },
+ "node_modules/@commitlint/read": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-16.2.1.tgz",
+ "integrity": "sha512-tViXGuaxLTrw2r7PiYMQOFA2fueZxnnt0lkOWqKyxT+n2XdEMGYcI9ID5ndJKXnfPGPppD0w/IItKsIXlZ+alw==",
+ "dev": true,
+ "dependencies": {
+ "@commitlint/top-level": "^16.2.1",
+ "@commitlint/types": "^16.2.1",
+ "fs-extra": "^10.0.0",
+ "git-raw-commits": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=v12"
+ }
+ },
+ "node_modules/@commitlint/resolve-extends": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-16.2.1.tgz",
+ "integrity": "sha512-NbbCMPKTFf2J805kwfP9EO+vV+XvnaHRcBy6ud5dF35dxMsvdJqke54W3XazXF1ZAxC4a3LBy4i/GNVBAthsEg==",
+ "dev": true,
+ "dependencies": {
+ "@commitlint/config-validator": "^16.2.1",
+ "@commitlint/types": "^16.2.1",
+ "import-fresh": "^3.0.0",
+ "lodash": "^4.17.19",
+ "resolve-from": "^5.0.0",
+ "resolve-global": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=v12"
+ }
+ },
+ "node_modules/@commitlint/rules": {
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-16.2.4.tgz",
+ "integrity": "sha512-rK5rNBIN2ZQNQK+I6trRPK3dWa0MtaTN4xnwOma1qxa4d5wQMQJtScwTZjTJeallFxhOgbNOgr48AMHkdounVg==",
+ "dev": true,
+ "dependencies": {
+ "@commitlint/ensure": "^16.2.1",
+ "@commitlint/message": "^16.2.1",
+ "@commitlint/to-lines": "^16.2.1",
+ "@commitlint/types": "^16.2.1",
+ "execa": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=v12"
+ }
+ },
+ "node_modules/@commitlint/to-lines": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-16.2.1.tgz",
+ "integrity": "sha512-9/VjpYj5j1QeY3eiog1zQWY6axsdWAc0AonUUfyZ7B0MVcRI0R56YsHAfzF6uK/g/WwPZaoe4Lb1QCyDVnpVaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=v12"
+ }
+ },
+ "node_modules/@commitlint/top-level": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-16.2.1.tgz",
+ "integrity": "sha512-lS6GSieHW9y6ePL73ied71Z9bOKyK+Ib9hTkRsB8oZFAyQZcyRwq2w6nIa6Fngir1QW51oKzzaXfJL94qwImyw==",
+ "dev": true,
+ "dependencies": {
+ "find-up": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=v12"
+ }
+ },
+ "node_modules/@commitlint/types": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-16.2.1.tgz",
+ "integrity": "sha512-7/z7pA7BM0i8XvMSBynO7xsB3mVQPUZbVn6zMIlp/a091XJ3qAXRXc+HwLYhiIdzzS5fuxxNIHZMGHVD4HJxdA==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=v12"
+ }
+ },
+ "node_modules/@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@hutson/parse-repository-url": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz",
+ "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+ "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.4.14",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+ "dev": true
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ },
+ "node_modules/@tsconfig/node10": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
+ "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
+ "dev": true
+ },
+ "node_modules/@tsconfig/node12": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+ "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
+ "dev": true
+ },
+ "node_modules/@tsconfig/node14": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
+ "dev": true
+ },
+ "node_modules/@tsconfig/node16": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
+ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
+ "dev": true
+ },
+ "node_modules/@types/minimist": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz",
+ "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==",
+ "dev": true
+ },
+ "node_modules/@types/node": {
+ "version": "18.8.3",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz",
+ "integrity": "sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==",
+ "dev": true
+ },
+ "node_modules/@types/normalize-package-data": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz",
+ "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==",
+ "dev": true
+ },
+ "node_modules/@types/parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
+ "dev": true
+ },
+ "node_modules/acorn": {
+ "version": "8.8.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz",
+ "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-walk": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/add-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz",
+ "integrity": "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==",
+ "dev": true
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ansi-escapes": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+ "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.21.3"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "dev": true
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "node_modules/array-ify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz",
+ "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==",
+ "dev": true
+ },
+ "node_modules/arrify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+ "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/at-least-node": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "dev": true,
+ "dependencies": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "dev": true
+ },
+ "node_modules/cachedir": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz",
+ "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/camelcase-keys": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz",
+ "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==",
+ "dev": true,
+ "dependencies": {
+ "camelcase": "^5.3.1",
+ "map-obj": "^4.0.0",
+ "quick-lru": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chardet": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+ "dev": true
+ },
+ "node_modules/cli-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+ "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+ "dev": true,
+ "dependencies": {
+ "restore-cursor": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cli-spinners": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz",
+ "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/cli-width": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
+ "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/clone": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+ "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/commitizen": {
+ "version": "4.2.5",
+ "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.2.5.tgz",
+ "integrity": "sha512-9sXju8Qrz1B4Tw7kC5KhnvwYQN88qs2zbiB8oyMsnXZyJ24PPGiNM3nHr73d32dnE3i8VJEXddBFIbOgYSEXtQ==",
+ "dev": true,
+ "dependencies": {
+ "cachedir": "2.3.0",
+ "cz-conventional-changelog": "3.3.0",
+ "dedent": "0.7.0",
+ "detect-indent": "6.1.0",
+ "find-node-modules": "^2.1.2",
+ "find-root": "1.1.0",
+ "fs-extra": "9.1.0",
+ "glob": "7.2.3",
+ "inquirer": "8.2.4",
+ "is-utf8": "^0.2.1",
+ "lodash": "4.17.21",
+ "minimist": "1.2.6",
+ "strip-bom": "4.0.0",
+ "strip-json-comments": "3.1.1"
+ },
+ "bin": {
+ "commitizen": "bin/commitizen",
+ "cz": "bin/git-cz",
+ "git-cz": "bin/git-cz"
+ },
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/commitizen/node_modules/fs-extra": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+ "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+ "dev": true,
+ "dependencies": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/compare-func": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz",
+ "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==",
+ "dev": true,
+ "dependencies": {
+ "array-ify": "^1.0.0",
+ "dot-prop": "^5.1.0"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "node_modules/concat-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
+ "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
+ "dev": true,
+ "engines": [
+ "node >= 6.0"
+ ],
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.0.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "node_modules/conventional-changelog": {
+ "version": "3.1.25",
+ "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.25.tgz",
+ "integrity": "sha512-ryhi3fd1mKf3fSjbLXOfK2D06YwKNic1nC9mWqybBHdObPd8KJ2vjaXZfYj1U23t+V8T8n0d7gwnc9XbIdFbyQ==",
+ "dev": true,
+ "dependencies": {
+ "conventional-changelog-angular": "^5.0.12",
+ "conventional-changelog-atom": "^2.0.8",
+ "conventional-changelog-codemirror": "^2.0.8",
+ "conventional-changelog-conventionalcommits": "^4.5.0",
+ "conventional-changelog-core": "^4.2.1",
+ "conventional-changelog-ember": "^2.0.9",
+ "conventional-changelog-eslint": "^3.0.9",
+ "conventional-changelog-express": "^2.0.6",
+ "conventional-changelog-jquery": "^3.0.11",
+ "conventional-changelog-jshint": "^2.0.9",
+ "conventional-changelog-preset-loader": "^2.3.4"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-angular": {
+ "version": "5.0.13",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz",
+ "integrity": "sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==",
+ "dev": true,
+ "dependencies": {
+ "compare-func": "^2.0.0",
+ "q": "^1.5.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-atom": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-atom/-/conventional-changelog-atom-2.0.8.tgz",
+ "integrity": "sha512-xo6v46icsFTK3bb7dY/8m2qvc8sZemRgdqLb/bjpBsH2UyOS8rKNTgcb5025Hri6IpANPApbXMg15QLb1LJpBw==",
+ "dev": true,
+ "dependencies": {
+ "q": "^1.5.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-codemirror": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.8.tgz",
+ "integrity": "sha512-z5DAsn3uj1Vfp7po3gpt2Boc+Bdwmw2++ZHa5Ak9k0UKsYAO5mH1UBTN0qSCuJZREIhX6WU4E1p3IW2oRCNzQw==",
+ "dev": true,
+ "dependencies": {
+ "q": "^1.5.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-config-spec": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-config-spec/-/conventional-changelog-config-spec-2.1.0.tgz",
+ "integrity": "sha512-IpVePh16EbbB02V+UA+HQnnPIohgXvJRxHcS5+Uwk4AT5LjzCZJm5sp/yqs5C6KZJ1jMsV4paEV13BN1pvDuxQ==",
+ "dev": true
+ },
+ "node_modules/conventional-changelog-conventionalcommits": {
+ "version": "4.6.3",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.3.tgz",
+ "integrity": "sha512-LTTQV4fwOM4oLPad317V/QNQ1FY4Hju5qeBIM1uTHbrnCE+Eg4CdRZ3gO2pUeR+tzWdp80M2j3qFFEDWVqOV4g==",
+ "dev": true,
+ "dependencies": {
+ "compare-func": "^2.0.0",
+ "lodash": "^4.17.15",
+ "q": "^1.5.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-core": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz",
+ "integrity": "sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg==",
+ "dev": true,
+ "dependencies": {
+ "add-stream": "^1.0.0",
+ "conventional-changelog-writer": "^5.0.0",
+ "conventional-commits-parser": "^3.2.0",
+ "dateformat": "^3.0.0",
+ "get-pkg-repo": "^4.0.0",
+ "git-raw-commits": "^2.0.8",
+ "git-remote-origin-url": "^2.0.0",
+ "git-semver-tags": "^4.1.1",
+ "lodash": "^4.17.15",
+ "normalize-package-data": "^3.0.0",
+ "q": "^1.5.1",
+ "read-pkg": "^3.0.0",
+ "read-pkg-up": "^3.0.0",
+ "through2": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-core/node_modules/find-up": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+ "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/conventional-changelog-core/node_modules/hosted-git-info": {
+ "version": "2.8.9",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
+ "dev": true
+ },
+ "node_modules/conventional-changelog-core/node_modules/locate-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+ "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^2.0.0",
+ "path-exists": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/conventional-changelog-core/node_modules/p-limit": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
+ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/conventional-changelog-core/node_modules/p-locate": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+ "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/conventional-changelog-core/node_modules/path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/conventional-changelog-core/node_modules/path-type": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+ "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+ "dev": true,
+ "dependencies": {
+ "pify": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/conventional-changelog-core/node_modules/pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/conventional-changelog-core/node_modules/read-pkg": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
+ "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==",
+ "dev": true,
+ "dependencies": {
+ "load-json-file": "^4.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/conventional-changelog-core/node_modules/read-pkg-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz",
+ "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==",
+ "dev": true,
+ "dependencies": {
+ "find-up": "^2.0.0",
+ "read-pkg": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/conventional-changelog-core/node_modules/read-pkg/node_modules/normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "dev": true,
+ "dependencies": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "node_modules/conventional-changelog-core/node_modules/semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
+ "node_modules/conventional-changelog-ember": {
+ "version": "2.0.9",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-ember/-/conventional-changelog-ember-2.0.9.tgz",
+ "integrity": "sha512-ulzIReoZEvZCBDhcNYfDIsLTHzYHc7awh+eI44ZtV5cx6LVxLlVtEmcO+2/kGIHGtw+qVabJYjdI5cJOQgXh1A==",
+ "dev": true,
+ "dependencies": {
+ "q": "^1.5.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-eslint": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.9.tgz",
+ "integrity": "sha512-6NpUCMgU8qmWmyAMSZO5NrRd7rTgErjrm4VASam2u5jrZS0n38V7Y9CzTtLT2qwz5xEChDR4BduoWIr8TfwvXA==",
+ "dev": true,
+ "dependencies": {
+ "q": "^1.5.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-express": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-express/-/conventional-changelog-express-2.0.6.tgz",
+ "integrity": "sha512-SDez2f3iVJw6V563O3pRtNwXtQaSmEfTCaTBPCqn0oG0mfkq0rX4hHBq5P7De2MncoRixrALj3u3oQsNK+Q0pQ==",
+ "dev": true,
+ "dependencies": {
+ "q": "^1.5.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-jquery": {
+ "version": "3.0.11",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.11.tgz",
+ "integrity": "sha512-x8AWz5/Td55F7+o/9LQ6cQIPwrCjfJQ5Zmfqi8thwUEKHstEn4kTIofXub7plf1xvFA2TqhZlq7fy5OmV6BOMw==",
+ "dev": true,
+ "dependencies": {
+ "q": "^1.5.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-jshint": {
+ "version": "2.0.9",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.9.tgz",
+ "integrity": "sha512-wMLdaIzq6TNnMHMy31hql02OEQ8nCQfExw1SE0hYL5KvU+JCTuPaDO+7JiogGT2gJAxiUGATdtYYfh+nT+6riA==",
+ "dev": true,
+ "dependencies": {
+ "compare-func": "^2.0.0",
+ "q": "^1.5.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-preset-loader": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz",
+ "integrity": "sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-tf-a": {
+ "resolved": "tools/conventional-changelog-tf-a",
+ "link": true
+ },
+ "node_modules/conventional-changelog-writer": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.1.tgz",
+ "integrity": "sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ==",
+ "dev": true,
+ "dependencies": {
+ "conventional-commits-filter": "^2.0.7",
+ "dateformat": "^3.0.0",
+ "handlebars": "^4.7.7",
+ "json-stringify-safe": "^5.0.1",
+ "lodash": "^4.17.15",
+ "meow": "^8.0.0",
+ "semver": "^6.0.0",
+ "split": "^1.0.0",
+ "through2": "^4.0.0"
+ },
+ "bin": {
+ "conventional-changelog-writer": "cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-writer/node_modules/semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/conventional-commit-types": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz",
+ "integrity": "sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg==",
+ "dev": true
+ },
+ "node_modules/conventional-commits-filter": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz",
+ "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==",
+ "dev": true,
+ "dependencies": {
+ "lodash.ismatch": "^4.4.0",
+ "modify-values": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-commits-parser": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz",
+ "integrity": "sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==",
+ "dev": true,
+ "dependencies": {
+ "is-text-path": "^1.0.1",
+ "JSONStream": "^1.0.4",
+ "lodash": "^4.17.15",
+ "meow": "^8.0.0",
+ "split2": "^3.0.0",
+ "through2": "^4.0.0"
+ },
+ "bin": {
+ "conventional-commits-parser": "cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-recommended-bump": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz",
+ "integrity": "sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw==",
+ "dev": true,
+ "dependencies": {
+ "concat-stream": "^2.0.0",
+ "conventional-changelog-preset-loader": "^2.3.4",
+ "conventional-commits-filter": "^2.0.7",
+ "conventional-commits-parser": "^3.2.0",
+ "git-raw-commits": "^2.0.8",
+ "git-semver-tags": "^4.1.1",
+ "meow": "^8.0.0",
+ "q": "^1.5.1"
+ },
+ "bin": {
+ "conventional-recommended-bump": "cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+ "dev": true
+ },
+ "node_modules/cosmiconfig": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz",
+ "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/parse-json": "^4.0.0",
+ "import-fresh": "^3.2.1",
+ "parse-json": "^5.0.0",
+ "path-type": "^4.0.0",
+ "yaml": "^1.10.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/cosmiconfig-typescript-loader": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-2.0.2.tgz",
+ "integrity": "sha512-KmE+bMjWMXJbkWCeY4FJX/npHuZPNr9XF9q9CIQ/bpFwi1qHfCmSiKarrCcRa0LO4fWjk93pVoeRtJAkTGcYNw==",
+ "dev": true,
+ "dependencies": {
+ "cosmiconfig": "^7",
+ "ts-node": "^10.8.1"
+ },
+ "engines": {
+ "node": ">=12",
+ "npm": ">=6"
+ },
+ "peerDependencies": {
+ "@types/node": "*",
+ "cosmiconfig": ">=7",
+ "typescript": ">=3"
+ }
+ },
+ "node_modules/create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+ "dev": true
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/cz-conventional-changelog": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz",
+ "integrity": "sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.1",
+ "commitizen": "^4.0.3",
+ "conventional-commit-types": "^3.0.0",
+ "lodash.map": "^4.5.1",
+ "longest": "^2.0.1",
+ "word-wrap": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 10"
+ },
+ "optionalDependencies": {
+ "@commitlint/load": ">6.1.1"
+ }
+ },
+ "node_modules/cz-conventional-changelog/node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cz-conventional-changelog/node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cz-conventional-changelog/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/cz-conventional-changelog/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true
+ },
+ "node_modules/cz-conventional-changelog/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cz-conventional-changelog/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/dargs": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz",
+ "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/dateformat": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
+ "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/decamelize-keys": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz",
+ "integrity": "sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==",
+ "dev": true,
+ "dependencies": {
+ "decamelize": "^1.1.0",
+ "map-obj": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/decamelize-keys/node_modules/map-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+ "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/dedent": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
+ "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==",
+ "dev": true
+ },
+ "node_modules/defaults": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
+ "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
+ "dev": true,
+ "dependencies": {
+ "clone": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/detect-file": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
+ "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/detect-indent": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
+ "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/detect-newline": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
+ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/dot-prop": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
+ "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
+ "dev": true,
+ "dependencies": {
+ "is-obj": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/dotgitignore": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/dotgitignore/-/dotgitignore-2.1.0.tgz",
+ "integrity": "sha512-sCm11ak2oY6DglEPpCB8TixLjWAxd3kJTs6UIcSasNYxXdFPV+YKlye92c8H4kKFqV5qYMIh7d+cYecEg0dIkA==",
+ "dev": true,
+ "dependencies": {
+ "find-up": "^3.0.0",
+ "minimatch": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/dotgitignore/node_modules/find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/dotgitignore/node_modules/locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/dotgitignore/node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/dotgitignore/node_modules/p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/dotgitignore/node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/dotgitignore/node_modules/path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "node_modules/error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/execa": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
+ "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^7.0.3",
+ "get-stream": "^6.0.0",
+ "human-signals": "^2.1.0",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.1",
+ "onetime": "^5.1.2",
+ "signal-exit": "^3.0.3",
+ "strip-final-newline": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
+ "node_modules/expand-tilde": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+ "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==",
+ "dev": true,
+ "dependencies": {
+ "homedir-polyfill": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/external-editor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+ "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+ "dev": true,
+ "dependencies": {
+ "chardet": "^0.7.0",
+ "iconv-lite": "^0.4.24",
+ "tmp": "^0.0.33"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "node_modules/figures": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+ "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^1.0.5"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-node-modules": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.3.tgz",
+ "integrity": "sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==",
+ "dev": true,
+ "dependencies": {
+ "findup-sync": "^4.0.0",
+ "merge": "^2.1.1"
+ }
+ },
+ "node_modules/find-root": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
+ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
+ "dev": true
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/findup-sync": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz",
+ "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==",
+ "dev": true,
+ "dependencies": {
+ "detect-file": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "micromatch": "^4.0.2",
+ "resolve-dir": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/fs-extra": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-pkg-repo": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz",
+ "integrity": "sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==",
+ "dev": true,
+ "dependencies": {
+ "@hutson/parse-repository-url": "^3.0.0",
+ "hosted-git-info": "^4.0.0",
+ "through2": "^2.0.0",
+ "yargs": "^16.2.0"
+ },
+ "bin": {
+ "get-pkg-repo": "src/cli.js"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-pkg-repo/node_modules/cliui": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "node_modules/get-pkg-repo/node_modules/readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "dev": true,
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/get-pkg-repo/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "node_modules/get-pkg-repo/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/get-pkg-repo/node_modules/through2": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+ "dev": true,
+ "dependencies": {
+ "readable-stream": "~2.3.6",
+ "xtend": "~4.0.1"
+ }
+ },
+ "node_modules/get-pkg-repo/node_modules/yargs": {
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/get-stream": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/git-raw-commits": {
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz",
+ "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==",
+ "dev": true,
+ "dependencies": {
+ "dargs": "^7.0.0",
+ "lodash": "^4.17.15",
+ "meow": "^8.0.0",
+ "split2": "^3.0.0",
+ "through2": "^4.0.0"
+ },
+ "bin": {
+ "git-raw-commits": "cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/git-remote-origin-url": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz",
+ "integrity": "sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==",
+ "dev": true,
+ "dependencies": {
+ "gitconfiglocal": "^1.0.0",
+ "pify": "^2.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/git-semver-tags": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz",
+ "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==",
+ "dev": true,
+ "dependencies": {
+ "meow": "^8.0.0",
+ "semver": "^6.0.0"
+ },
+ "bin": {
+ "git-semver-tags": "cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/git-semver-tags/node_modules/semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/gitconfiglocal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz",
+ "integrity": "sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==",
+ "dev": true,
+ "dependencies": {
+ "ini": "^1.3.2"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/global-dirs": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz",
+ "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==",
+ "dev": true,
+ "dependencies": {
+ "ini": "^1.3.4"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/global-modules": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+ "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
+ "dev": true,
+ "dependencies": {
+ "global-prefix": "^1.0.1",
+ "is-windows": "^1.0.1",
+ "resolve-dir": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/global-prefix": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+ "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==",
+ "dev": true,
+ "dependencies": {
+ "expand-tilde": "^2.0.2",
+ "homedir-polyfill": "^1.0.1",
+ "ini": "^1.3.4",
+ "is-windows": "^1.0.1",
+ "which": "^1.2.14"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/global-prefix/node_modules/which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "which": "bin/which"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.10",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+ "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
+ "dev": true
+ },
+ "node_modules/handlebars": {
+ "version": "4.7.7",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
+ "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.5",
+ "neo-async": "^2.6.0",
+ "source-map": "^0.6.1",
+ "wordwrap": "^1.0.0"
+ },
+ "bin": {
+ "handlebars": "bin/handlebars"
+ },
+ "engines": {
+ "node": ">=0.4.7"
+ },
+ "optionalDependencies": {
+ "uglify-js": "^3.1.4"
+ }
+ },
+ "node_modules/hard-rejection": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz",
+ "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/homedir-polyfill": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+ "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+ "dev": true,
+ "dependencies": {
+ "parse-passwd": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/hosted-git-info": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
+ "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/human-signals": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
+ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10.17.0"
+ }
+ },
+ "node_modules/husky": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz",
+ "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==",
+ "dev": true,
+ "bin": {
+ "husky": "lib/bin.js"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/typicode"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dev": true,
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/import-fresh/node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "node_modules/ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+ "dev": true
+ },
+ "node_modules/inquirer": {
+ "version": "8.2.4",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz",
+ "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==",
+ "dev": true,
+ "dependencies": {
+ "ansi-escapes": "^4.2.1",
+ "chalk": "^4.1.1",
+ "cli-cursor": "^3.1.0",
+ "cli-width": "^3.0.0",
+ "external-editor": "^3.0.3",
+ "figures": "^3.0.0",
+ "lodash": "^4.17.21",
+ "mute-stream": "0.0.8",
+ "ora": "^5.4.1",
+ "run-async": "^2.4.0",
+ "rxjs": "^7.5.5",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0",
+ "through": "^2.3.6",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "dev": true
+ },
+ "node_modules/is-core-module": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz",
+ "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==",
+ "dev": true,
+ "dependencies": {
+ "has": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-interactive": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
+ "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-obj": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
+ "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-plain-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+ "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-text-path": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz",
+ "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==",
+ "dev": true,
+ "dependencies": {
+ "text-extensions": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-unicode-supported": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-utf8": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+ "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==",
+ "dev": true
+ },
+ "node_modules/is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+ "dev": true
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/json-parse-better-errors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+ "dev": true
+ },
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "dev": true
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "node_modules/json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
+ "dev": true
+ },
+ "node_modules/jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/jsonparse": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+ "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==",
+ "dev": true,
+ "engines": [
+ "node >= 0.2.0"
+ ]
+ },
+ "node_modules/JSONStream": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
+ "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
+ "dev": true,
+ "dependencies": {
+ "jsonparse": "^1.2.0",
+ "through": ">=2.2.7 <3"
+ },
+ "bin": {
+ "JSONStream": "bin.js"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "dev": true
+ },
+ "node_modules/load-json-file": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
+ "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^4.0.0",
+ "pify": "^3.0.0",
+ "strip-bom": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/load-json-file/node_modules/parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
+ "dev": true,
+ "dependencies": {
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/load-json-file/node_modules/pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/load-json-file/node_modules/strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true
+ },
+ "node_modules/lodash.ismatch": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz",
+ "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==",
+ "dev": true
+ },
+ "node_modules/lodash.map": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz",
+ "integrity": "sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==",
+ "dev": true
+ },
+ "node_modules/log-symbols": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+ "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/longest": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/longest/-/longest-2.0.1.tgz",
+ "integrity": "sha512-Ajzxb8CM6WAnFjgiloPsI3bF+WCxcvhdIG3KNA2KN962+tdBsHcuQ4k4qX/EcS/2CRkcc0iAkR956Nib6aXU/Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "dev": true
+ },
+ "node_modules/map-obj": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
+ "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/meow": {
+ "version": "8.1.2",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz",
+ "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==",
+ "dev": true,
+ "dependencies": {
+ "@types/minimist": "^1.2.0",
+ "camelcase-keys": "^6.2.2",
+ "decamelize-keys": "^1.1.0",
+ "hard-rejection": "^2.1.0",
+ "minimist-options": "4.1.0",
+ "normalize-package-data": "^3.0.0",
+ "read-pkg-up": "^7.0.1",
+ "redent": "^3.0.0",
+ "trim-newlines": "^3.0.0",
+ "type-fest": "^0.18.0",
+ "yargs-parser": "^20.2.3"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/meow/node_modules/type-fest": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz",
+ "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/merge": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz",
+ "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==",
+ "dev": true
+ },
+ "node_modules/merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "dev": true
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+ "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "dev": true,
+ "dependencies": {
+ "braces": "^3.0.2",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/min-indent": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
+ "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
+ "dev": true
+ },
+ "node_modules/minimist-options": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz",
+ "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==",
+ "dev": true,
+ "dependencies": {
+ "arrify": "^1.0.1",
+ "is-plain-obj": "^1.1.0",
+ "kind-of": "^6.0.3"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/modify-values": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz",
+ "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/mute-stream": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+ "dev": true
+ },
+ "node_modules/neo-async": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+ "dev": true
+ },
+ "node_modules/normalize-package-data": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz",
+ "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==",
+ "dev": true,
+ "dependencies": {
+ "hosted-git-info": "^4.0.1",
+ "is-core-module": "^2.5.0",
+ "semver": "^7.3.4",
+ "validate-npm-package-license": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/npm-run-path": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dev": true,
+ "dependencies": {
+ "mimic-fn": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
+ "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==",
+ "dev": true,
+ "dependencies": {
+ "bl": "^4.1.0",
+ "chalk": "^4.1.0",
+ "cli-cursor": "^3.1.0",
+ "cli-spinners": "^2.5.0",
+ "is-interactive": "^1.0.0",
+ "is-unicode-supported": "^0.1.0",
+ "log-symbols": "^4.1.0",
+ "strip-ansi": "^6.0.0",
+ "wcwidth": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-try": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
+ "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/parse-passwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+ "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true
+ },
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true
+ },
+ "node_modules/punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/q": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
+ "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6.0",
+ "teleport": ">=0.2.0"
+ }
+ },
+ "node_modules/quick-lru": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz",
+ "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/read-pkg": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
+ "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
+ "dev": true,
+ "dependencies": {
+ "@types/normalize-package-data": "^2.4.0",
+ "normalize-package-data": "^2.5.0",
+ "parse-json": "^5.0.0",
+ "type-fest": "^0.6.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/read-pkg-up": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
+ "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
+ "dev": true,
+ "dependencies": {
+ "find-up": "^4.1.0",
+ "read-pkg": "^5.2.0",
+ "type-fest": "^0.8.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/type-fest": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/read-pkg/node_modules/hosted-git-info": {
+ "version": "2.8.9",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
+ "dev": true
+ },
+ "node_modules/read-pkg/node_modules/normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "dev": true,
+ "dependencies": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "node_modules/read-pkg/node_modules/semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
+ "node_modules/read-pkg/node_modules/type-fest": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
+ "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/redent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
+ "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
+ "dev": true,
+ "dependencies": {
+ "indent-string": "^4.0.0",
+ "strip-indent": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+ "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+ "dev": true,
+ "dependencies": {
+ "is-core-module": "^2.9.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-dir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+ "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==",
+ "dev": true,
+ "dependencies": {
+ "expand-tilde": "^2.0.0",
+ "global-modules": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/resolve-global": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz",
+ "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==",
+ "dev": true,
+ "dependencies": {
+ "global-dirs": "^0.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/restore-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+ "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+ "dev": true,
+ "dependencies": {
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/run-async": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
+ "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/rxjs": {
+ "version": "7.5.7",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz",
+ "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true
+ },
+ "node_modules/semver": {
+ "version": "7.3.7",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+ "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "dev": true
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/spdx-correct": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
+ "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
+ "dev": true,
+ "dependencies": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "node_modules/spdx-exceptions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
+ "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
+ "dev": true
+ },
+ "node_modules/spdx-expression-parse": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+ "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+ "dev": true,
+ "dependencies": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "node_modules/spdx-license-ids": {
+ "version": "3.0.12",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz",
+ "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==",
+ "dev": true
+ },
+ "node_modules/split": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
+ "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
+ "dev": true,
+ "dependencies": {
+ "through": "2"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/split2": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz",
+ "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==",
+ "dev": true,
+ "dependencies": {
+ "readable-stream": "^3.0.0"
+ }
+ },
+ "node_modules/standard-version": {
+ "version": "9.5.0",
+ "resolved": "https://registry.npmjs.org/standard-version/-/standard-version-9.5.0.tgz",
+ "integrity": "sha512-3zWJ/mmZQsOaO+fOlsa0+QK90pwhNd042qEcw6hKFNoLFs7peGyvPffpEBbK/DSGPbyOvli0mUIFv5A4qTjh2Q==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.2",
+ "conventional-changelog": "3.1.25",
+ "conventional-changelog-config-spec": "2.1.0",
+ "conventional-changelog-conventionalcommits": "4.6.3",
+ "conventional-recommended-bump": "6.1.0",
+ "detect-indent": "^6.0.0",
+ "detect-newline": "^3.1.0",
+ "dotgitignore": "^2.1.0",
+ "figures": "^3.1.0",
+ "find-up": "^5.0.0",
+ "git-semver-tags": "^4.0.0",
+ "semver": "^7.1.1",
+ "stringify-package": "^1.0.1",
+ "yargs": "^16.0.0"
+ },
+ "bin": {
+ "standard-version": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/standard-version/node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/standard-version/node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/standard-version/node_modules/cliui": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "node_modules/standard-version/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/standard-version/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true
+ },
+ "node_modules/standard-version/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/standard-version/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/standard-version/node_modules/yargs": {
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stringify-package": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/stringify-package/-/stringify-package-1.0.1.tgz",
+ "integrity": "sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg==",
+ "dev": true
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-bom": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
+ "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-final-newline": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/strip-indent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+ "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+ "dev": true,
+ "dependencies": {
+ "min-indent": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/text-extensions": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz",
+ "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+ "dev": true
+ },
+ "node_modules/through2": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz",
+ "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==",
+ "dev": true,
+ "dependencies": {
+ "readable-stream": "3"
+ }
+ },
+ "node_modules/tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "dev": true,
+ "dependencies": {
+ "os-tmpdir": "~1.0.2"
+ },
+ "engines": {
+ "node": ">=0.6.0"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/trim-newlines": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
+ "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ts-node": {
+ "version": "10.9.1",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
+ "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
+ "dev": true,
+ "dependencies": {
+ "@cspotcode/source-map-support": "^0.8.0",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "v8-compile-cache-lib": "^3.0.1",
+ "yn": "3.1.1"
+ },
+ "bin": {
+ "ts-node": "dist/bin.js",
+ "ts-node-cwd": "dist/bin-cwd.js",
+ "ts-node-esm": "dist/bin-esm.js",
+ "ts-node-script": "dist/bin-script.js",
+ "ts-node-transpile-only": "dist/bin-transpile.js",
+ "ts-script": "dist/bin-script-deprecated.js"
+ },
+ "peerDependencies": {
+ "@swc/core": ">=1.2.50",
+ "@swc/wasm": ">=1.2.50",
+ "@types/node": "*",
+ "typescript": ">=2.7"
+ },
+ "peerDependenciesMeta": {
+ "@swc/core": {
+ "optional": true
+ },
+ "@swc/wasm": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
+ "dev": true
+ },
+ "node_modules/type-fest": {
+ "version": "0.21.3",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
+ "dev": true
+ },
+ "node_modules/typescript": {
+ "version": "4.8.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
+ "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
+ "node_modules/uglify-js": {
+ "version": "3.17.3",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.3.tgz",
+ "integrity": "sha512-JmMFDME3iufZnBpyKL+uS78LRiC+mK55zWfM5f/pWBJfpOttXAqYfdDGRukYhJuyRinvPVAtUhvy7rlDybNtFg==",
+ "dev": true,
+ "optional": true,
+ "bin": {
+ "uglifyjs": "bin/uglifyjs"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/universalify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true
+ },
+ "node_modules/v8-compile-cache-lib": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
+ "dev": true
+ },
+ "node_modules/validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "dev": true,
+ "dependencies": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
+ "node_modules/wcwidth": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
+ "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
+ "dev": true,
+ "dependencies": {
+ "defaults": "^1.0.3"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
+ "dev": true
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true
+ },
+ "node_modules/xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4"
+ }
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
+ "node_modules/yaml": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/yargs": {
+ "version": "17.6.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz",
+ "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "20.2.9",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yargs/node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "tools/conventional-changelog-tf-a": {
+ "version": "2.7.0",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "conventional-changelog-conventionalcommits": "^4.6.1",
+ "execa": "^5.1.1",
+ "lodash": "^4.17.21",
+ "q": "^1.5.1"
+ }
+ }
+ },
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
+ "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.18.6"
+ }
+ },
+ "@babel/helper-validator-identifier": {
+ "version": "7.19.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
+ "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
+ "dev": true
+ },
+ "@babel/highlight": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
+ "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.18.6",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "@commitlint/cli": {
+ "version": "16.3.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-16.3.0.tgz",
+ "integrity": "sha512-P+kvONlfsuTMnxSwWE1H+ZcPMY3STFaHb2kAacsqoIkNx66O0T7sTpBxpxkMrFPyhkJiLJnJWMhk4bbvYD3BMA==",
+ "dev": true,
+ "requires": {
+ "@commitlint/format": "^16.2.1",
+ "@commitlint/lint": "^16.2.4",
+ "@commitlint/load": "^16.3.0",
+ "@commitlint/read": "^16.2.1",
+ "@commitlint/types": "^16.2.1",
+ "lodash": "^4.17.19",
+ "resolve-from": "5.0.0",
+ "resolve-global": "1.0.0",
+ "yargs": "^17.0.0"
+ }
+ },
+ "@commitlint/config-conventional": {
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-16.2.4.tgz",
+ "integrity": "sha512-av2UQJa3CuE5P0dzxj/o/B9XVALqYzEViHrMXtDrW9iuflrqCStWBAioijppj9URyz6ONpohJKAtSdgAOE0gkA==",
+ "dev": true,
+ "requires": {
+ "conventional-changelog-conventionalcommits": "^4.3.1"
+ }
+ },
+ "@commitlint/config-validator": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-16.2.1.tgz",
+ "integrity": "sha512-hogSe0WGg7CKmp4IfNbdNES3Rq3UEI4XRPB8JL4EPgo/ORq5nrGTVzxJh78omibNuB8Ho4501Czb1Er1MoDWpw==",
+ "dev": true,
+ "requires": {
+ "@commitlint/types": "^16.2.1",
+ "ajv": "^6.12.6"
+ }
+ },
+ "@commitlint/cz-commitlint": {
+ "version": "16.3.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/cz-commitlint/-/cz-commitlint-16.3.0.tgz",
+ "integrity": "sha512-Q+QLQmSIHEgzI18F3/7mqq3vwL0IN9k+Tjp9Um4adFnRXMtUTnEa0er0CXAXxWvoA/x/6nt3t7faAv2HugDIGg==",
+ "dev": true,
+ "requires": {
+ "@commitlint/ensure": "^16.2.1",
+ "@commitlint/load": "^16.3.0",
+ "@commitlint/types": "^16.2.1",
+ "chalk": "^4.1.0",
+ "lodash": "^4.17.21",
+ "word-wrap": "^1.2.3"
+ }
+ },
+ "@commitlint/ensure": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-16.2.1.tgz",
+ "integrity": "sha512-/h+lBTgf1r5fhbDNHOViLuej38i3rZqTQnBTk+xEg+ehOwQDXUuissQ5GsYXXqI5uGy+261ew++sT4EA3uBJ+A==",
+ "dev": true,
+ "requires": {
+ "@commitlint/types": "^16.2.1",
+ "lodash": "^4.17.19"
+ }
+ },
+ "@commitlint/execute-rule": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-16.2.1.tgz",
+ "integrity": "sha512-oSls82fmUTLM6cl5V3epdVo4gHhbmBFvCvQGHBRdQ50H/690Uq1Dyd7hXMuKITCIdcnr9umyDkr8r5C6HZDF3g==",
+ "dev": true
+ },
+ "@commitlint/format": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-16.2.1.tgz",
+ "integrity": "sha512-Yyio9bdHWmNDRlEJrxHKglamIk3d6hC0NkEUW6Ti6ipEh2g0BAhy8Od6t4vLhdZRa1I2n+gY13foy+tUgk0i1Q==",
+ "dev": true,
+ "requires": {
+ "@commitlint/types": "^16.2.1",
+ "chalk": "^4.0.0"
+ }
+ },
+ "@commitlint/is-ignored": {
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-16.2.4.tgz",
+ "integrity": "sha512-Lxdq9aOAYCOOOjKi58ulbwK/oBiiKz+7Sq0+/SpFIEFwhHkIVugvDvWjh2VRBXmRC/x5lNcjDcYEwS/uYUvlYQ==",
+ "dev": true,
+ "requires": {
+ "@commitlint/types": "^16.2.1",
+ "semver": "7.3.7"
+ }
+ },
+ "@commitlint/lint": {
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-16.2.4.tgz",
+ "integrity": "sha512-AUDuwOxb2eGqsXbTMON3imUGkc1jRdtXrbbohiLSCSk3jFVXgJLTMaEcr39pR00N8nE9uZ+V2sYaiILByZVmxQ==",
+ "dev": true,
+ "requires": {
+ "@commitlint/is-ignored": "^16.2.4",
+ "@commitlint/parse": "^16.2.1",
+ "@commitlint/rules": "^16.2.4",
+ "@commitlint/types": "^16.2.1"
+ }
+ },
+ "@commitlint/load": {
+ "version": "16.3.0",
+ "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-16.3.0.tgz",
+ "integrity": "sha512-3tykjV/iwbkv2FU9DG+NZ/JqmP0Nm3b7aDwgCNQhhKV5P74JAuByULkafnhn+zsFGypG1qMtI5u+BZoa9APm0A==",
+ "dev": true,
+ "requires": {
+ "@commitlint/config-validator": "^16.2.1",
+ "@commitlint/execute-rule": "^16.2.1",
+ "@commitlint/resolve-extends": "^16.2.1",
+ "@commitlint/types": "^16.2.1",
+ "@types/node": ">=12",
+ "chalk": "^4.0.0",
+ "cosmiconfig": "^7.0.0",
+ "cosmiconfig-typescript-loader": "^2.0.0",
+ "lodash": "^4.17.19",
+ "resolve-from": "^5.0.0",
+ "typescript": "^4.4.3"
+ }
+ },
+ "@commitlint/message": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-16.2.1.tgz",
+ "integrity": "sha512-2eWX/47rftViYg7a3axYDdrgwKv32mxbycBJT6OQY/MJM7SUfYNYYvbMFOQFaA4xIVZt7t2Alyqslbl6blVwWw==",
+ "dev": true
+ },
+ "@commitlint/parse": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-16.2.1.tgz",
+ "integrity": "sha512-2NP2dDQNL378VZYioLrgGVZhWdnJO4nAxQl5LXwYb08nEcN+cgxHN1dJV8OLJ5uxlGJtDeR8UZZ1mnQ1gSAD/g==",
+ "dev": true,
+ "requires": {
+ "@commitlint/types": "^16.2.1",
+ "conventional-changelog-angular": "^5.0.11",
+ "conventional-commits-parser": "^3.2.2"
+ }
+ },
+ "@commitlint/read": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-16.2.1.tgz",
+ "integrity": "sha512-tViXGuaxLTrw2r7PiYMQOFA2fueZxnnt0lkOWqKyxT+n2XdEMGYcI9ID5ndJKXnfPGPppD0w/IItKsIXlZ+alw==",
+ "dev": true,
+ "requires": {
+ "@commitlint/top-level": "^16.2.1",
+ "@commitlint/types": "^16.2.1",
+ "fs-extra": "^10.0.0",
+ "git-raw-commits": "^2.0.0"
+ }
+ },
+ "@commitlint/resolve-extends": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-16.2.1.tgz",
+ "integrity": "sha512-NbbCMPKTFf2J805kwfP9EO+vV+XvnaHRcBy6ud5dF35dxMsvdJqke54W3XazXF1ZAxC4a3LBy4i/GNVBAthsEg==",
+ "dev": true,
+ "requires": {
+ "@commitlint/config-validator": "^16.2.1",
+ "@commitlint/types": "^16.2.1",
+ "import-fresh": "^3.0.0",
+ "lodash": "^4.17.19",
+ "resolve-from": "^5.0.0",
+ "resolve-global": "^1.0.0"
+ }
+ },
+ "@commitlint/rules": {
+ "version": "16.2.4",
+ "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-16.2.4.tgz",
+ "integrity": "sha512-rK5rNBIN2ZQNQK+I6trRPK3dWa0MtaTN4xnwOma1qxa4d5wQMQJtScwTZjTJeallFxhOgbNOgr48AMHkdounVg==",
+ "dev": true,
+ "requires": {
+ "@commitlint/ensure": "^16.2.1",
+ "@commitlint/message": "^16.2.1",
+ "@commitlint/to-lines": "^16.2.1",
+ "@commitlint/types": "^16.2.1",
+ "execa": "^5.0.0"
+ }
+ },
+ "@commitlint/to-lines": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-16.2.1.tgz",
+ "integrity": "sha512-9/VjpYj5j1QeY3eiog1zQWY6axsdWAc0AonUUfyZ7B0MVcRI0R56YsHAfzF6uK/g/WwPZaoe4Lb1QCyDVnpVaQ==",
+ "dev": true
+ },
+ "@commitlint/top-level": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-16.2.1.tgz",
+ "integrity": "sha512-lS6GSieHW9y6ePL73ied71Z9bOKyK+Ib9hTkRsB8oZFAyQZcyRwq2w6nIa6Fngir1QW51oKzzaXfJL94qwImyw==",
+ "dev": true,
+ "requires": {
+ "find-up": "^5.0.0"
+ }
+ },
+ "@commitlint/types": {
+ "version": "16.2.1",
+ "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-16.2.1.tgz",
+ "integrity": "sha512-7/z7pA7BM0i8XvMSBynO7xsB3mVQPUZbVn6zMIlp/a091XJ3qAXRXc+HwLYhiIdzzS5fuxxNIHZMGHVD4HJxdA==",
+ "dev": true,
+ "requires": {
+ "chalk": "^4.0.0"
+ }
+ },
+ "@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "dev": true,
+ "requires": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ }
+ },
+ "@hutson/parse-repository-url": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz",
+ "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==",
+ "dev": true
+ },
+ "@jridgewell/resolve-uri": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+ "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+ "dev": true
+ },
+ "@jridgewell/sourcemap-codec": {
+ "version": "1.4.14",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+ "dev": true
+ },
+ "@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "dev": true,
+ "requires": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ },
+ "@tsconfig/node10": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
+ "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
+ "dev": true
+ },
+ "@tsconfig/node12": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+ "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
+ "dev": true
+ },
+ "@tsconfig/node14": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
+ "dev": true
+ },
+ "@tsconfig/node16": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
+ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
+ "dev": true
+ },
+ "@types/minimist": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz",
+ "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==",
+ "dev": true
+ },
+ "@types/node": {
+ "version": "18.8.3",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz",
+ "integrity": "sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==",
+ "dev": true
+ },
+ "@types/normalize-package-data": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz",
+ "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==",
+ "dev": true
+ },
+ "@types/parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
+ "dev": true
+ },
+ "acorn": {
+ "version": "8.8.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz",
+ "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==",
+ "dev": true
+ },
+ "acorn-walk": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+ "dev": true
+ },
+ "add-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz",
+ "integrity": "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==",
+ "dev": true
+ },
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "ansi-escapes": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+ "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+ "dev": true,
+ "requires": {
+ "type-fest": "^0.21.3"
+ }
+ },
+ "ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "dev": true
+ },
+ "argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "array-ify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz",
+ "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==",
+ "dev": true
+ },
+ "arrify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+ "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==",
+ "dev": true
+ },
+ "at-least-node": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
+ "dev": true
+ },
+ "balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "dev": true
+ },
+ "bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "dev": true,
+ "requires": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "dev": true,
+ "requires": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "dev": true
+ },
+ "cachedir": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz",
+ "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==",
+ "dev": true
+ },
+ "callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true
+ },
+ "camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true
+ },
+ "camelcase-keys": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz",
+ "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.3.1",
+ "map-obj": "^4.0.0",
+ "quick-lru": "^4.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "chardet": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+ "dev": true
+ },
+ "cli-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+ "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+ "dev": true,
+ "requires": {
+ "restore-cursor": "^3.1.0"
+ }
+ },
+ "cli-spinners": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz",
+ "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==",
+ "dev": true
+ },
+ "cli-width": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
+ "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
+ "dev": true
+ },
+ "cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
+ "requires": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "clone": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+ "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
+ "dev": true
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "commitizen": {
+ "version": "4.2.5",
+ "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.2.5.tgz",
+ "integrity": "sha512-9sXju8Qrz1B4Tw7kC5KhnvwYQN88qs2zbiB8oyMsnXZyJ24PPGiNM3nHr73d32dnE3i8VJEXddBFIbOgYSEXtQ==",
+ "dev": true,
+ "requires": {
+ "cachedir": "2.3.0",
+ "cz-conventional-changelog": "3.3.0",
+ "dedent": "0.7.0",
+ "detect-indent": "6.1.0",
+ "find-node-modules": "^2.1.2",
+ "find-root": "1.1.0",
+ "fs-extra": "9.1.0",
+ "glob": "7.2.3",
+ "inquirer": "8.2.4",
+ "is-utf8": "^0.2.1",
+ "lodash": "4.17.21",
+ "minimist": "1.2.6",
+ "strip-bom": "4.0.0",
+ "strip-json-comments": "3.1.1"
+ },
+ "dependencies": {
+ "fs-extra": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+ "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+ "dev": true,
+ "requires": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ }
+ }
+ }
+ },
+ "compare-func": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz",
+ "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==",
+ "dev": true,
+ "requires": {
+ "array-ify": "^1.0.0",
+ "dot-prop": "^5.1.0"
+ }
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "concat-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
+ "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
+ "dev": true,
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.0.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "conventional-changelog": {
+ "version": "3.1.25",
+ "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.25.tgz",
+ "integrity": "sha512-ryhi3fd1mKf3fSjbLXOfK2D06YwKNic1nC9mWqybBHdObPd8KJ2vjaXZfYj1U23t+V8T8n0d7gwnc9XbIdFbyQ==",
+ "dev": true,
+ "requires": {
+ "conventional-changelog-angular": "^5.0.12",
+ "conventional-changelog-atom": "^2.0.8",
+ "conventional-changelog-codemirror": "^2.0.8",
+ "conventional-changelog-conventionalcommits": "^4.5.0",
+ "conventional-changelog-core": "^4.2.1",
+ "conventional-changelog-ember": "^2.0.9",
+ "conventional-changelog-eslint": "^3.0.9",
+ "conventional-changelog-express": "^2.0.6",
+ "conventional-changelog-jquery": "^3.0.11",
+ "conventional-changelog-jshint": "^2.0.9",
+ "conventional-changelog-preset-loader": "^2.3.4"
+ }
+ },
+ "conventional-changelog-angular": {
+ "version": "5.0.13",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz",
+ "integrity": "sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==",
+ "dev": true,
+ "requires": {
+ "compare-func": "^2.0.0",
+ "q": "^1.5.1"
+ }
+ },
+ "conventional-changelog-atom": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-atom/-/conventional-changelog-atom-2.0.8.tgz",
+ "integrity": "sha512-xo6v46icsFTK3bb7dY/8m2qvc8sZemRgdqLb/bjpBsH2UyOS8rKNTgcb5025Hri6IpANPApbXMg15QLb1LJpBw==",
+ "dev": true,
+ "requires": {
+ "q": "^1.5.1"
+ }
+ },
+ "conventional-changelog-codemirror": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.8.tgz",
+ "integrity": "sha512-z5DAsn3uj1Vfp7po3gpt2Boc+Bdwmw2++ZHa5Ak9k0UKsYAO5mH1UBTN0qSCuJZREIhX6WU4E1p3IW2oRCNzQw==",
+ "dev": true,
+ "requires": {
+ "q": "^1.5.1"
+ }
+ },
+ "conventional-changelog-config-spec": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-config-spec/-/conventional-changelog-config-spec-2.1.0.tgz",
+ "integrity": "sha512-IpVePh16EbbB02V+UA+HQnnPIohgXvJRxHcS5+Uwk4AT5LjzCZJm5sp/yqs5C6KZJ1jMsV4paEV13BN1pvDuxQ==",
+ "dev": true
+ },
+ "conventional-changelog-conventionalcommits": {
+ "version": "4.6.3",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.3.tgz",
+ "integrity": "sha512-LTTQV4fwOM4oLPad317V/QNQ1FY4Hju5qeBIM1uTHbrnCE+Eg4CdRZ3gO2pUeR+tzWdp80M2j3qFFEDWVqOV4g==",
+ "dev": true,
+ "requires": {
+ "compare-func": "^2.0.0",
+ "lodash": "^4.17.15",
+ "q": "^1.5.1"
+ }
+ },
+ "conventional-changelog-core": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz",
+ "integrity": "sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg==",
+ "dev": true,
+ "requires": {
+ "add-stream": "^1.0.0",
+ "conventional-changelog-writer": "^5.0.0",
+ "conventional-commits-parser": "^3.2.0",
+ "dateformat": "^3.0.0",
+ "get-pkg-repo": "^4.0.0",
+ "git-raw-commits": "^2.0.8",
+ "git-remote-origin-url": "^2.0.0",
+ "git-semver-tags": "^4.1.1",
+ "lodash": "^4.17.15",
+ "normalize-package-data": "^3.0.0",
+ "q": "^1.5.1",
+ "read-pkg": "^3.0.0",
+ "read-pkg-up": "^3.0.0",
+ "through2": "^4.0.0"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+ "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^2.0.0"
+ }
+ },
+ "hosted-git-info": {
+ "version": "2.8.9",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
+ "dev": true
+ },
+ "locate-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+ "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^2.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "p-limit": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
+ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+ "dev": true,
+ "requires": {
+ "p-try": "^1.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+ "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^1.1.0"
+ }
+ },
+ "path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
+ "dev": true
+ },
+ "path-type": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+ "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+ "dev": true,
+ "requires": {
+ "pify": "^3.0.0"
+ }
+ },
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==",
+ "dev": true
+ },
+ "read-pkg": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
+ "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==",
+ "dev": true,
+ "requires": {
+ "load-json-file": "^4.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^3.0.0"
+ },
+ "dependencies": {
+ "normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ }
+ }
+ },
+ "read-pkg-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz",
+ "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==",
+ "dev": true,
+ "requires": {
+ "find-up": "^2.0.0",
+ "read-pkg": "^3.0.0"
+ }
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ }
+ }
+ },
+ "conventional-changelog-ember": {
+ "version": "2.0.9",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-ember/-/conventional-changelog-ember-2.0.9.tgz",
+ "integrity": "sha512-ulzIReoZEvZCBDhcNYfDIsLTHzYHc7awh+eI44ZtV5cx6LVxLlVtEmcO+2/kGIHGtw+qVabJYjdI5cJOQgXh1A==",
+ "dev": true,
+ "requires": {
+ "q": "^1.5.1"
+ }
+ },
+ "conventional-changelog-eslint": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.9.tgz",
+ "integrity": "sha512-6NpUCMgU8qmWmyAMSZO5NrRd7rTgErjrm4VASam2u5jrZS0n38V7Y9CzTtLT2qwz5xEChDR4BduoWIr8TfwvXA==",
+ "dev": true,
+ "requires": {
+ "q": "^1.5.1"
+ }
+ },
+ "conventional-changelog-express": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-express/-/conventional-changelog-express-2.0.6.tgz",
+ "integrity": "sha512-SDez2f3iVJw6V563O3pRtNwXtQaSmEfTCaTBPCqn0oG0mfkq0rX4hHBq5P7De2MncoRixrALj3u3oQsNK+Q0pQ==",
+ "dev": true,
+ "requires": {
+ "q": "^1.5.1"
+ }
+ },
+ "conventional-changelog-jquery": {
+ "version": "3.0.11",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.11.tgz",
+ "integrity": "sha512-x8AWz5/Td55F7+o/9LQ6cQIPwrCjfJQ5Zmfqi8thwUEKHstEn4kTIofXub7plf1xvFA2TqhZlq7fy5OmV6BOMw==",
+ "dev": true,
+ "requires": {
+ "q": "^1.5.1"
+ }
+ },
+ "conventional-changelog-jshint": {
+ "version": "2.0.9",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.9.tgz",
+ "integrity": "sha512-wMLdaIzq6TNnMHMy31hql02OEQ8nCQfExw1SE0hYL5KvU+JCTuPaDO+7JiogGT2gJAxiUGATdtYYfh+nT+6riA==",
+ "dev": true,
+ "requires": {
+ "compare-func": "^2.0.0",
+ "q": "^1.5.1"
+ }
+ },
+ "conventional-changelog-preset-loader": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz",
+ "integrity": "sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==",
+ "dev": true
+ },
+ "conventional-changelog-tf-a": {
+ "version": "file:tools/conventional-changelog-tf-a",
+ "requires": {
+ "conventional-changelog-conventionalcommits": "^4.6.1",
+ "execa": "^5.1.1",
+ "lodash": "^4.17.21",
+ "q": "^1.5.1"
+ }
+ },
+ "conventional-changelog-writer": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.1.tgz",
+ "integrity": "sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ==",
+ "dev": true,
+ "requires": {
+ "conventional-commits-filter": "^2.0.7",
+ "dateformat": "^3.0.0",
+ "handlebars": "^4.7.7",
+ "json-stringify-safe": "^5.0.1",
+ "lodash": "^4.17.15",
+ "meow": "^8.0.0",
+ "semver": "^6.0.0",
+ "split": "^1.0.0",
+ "through2": "^4.0.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "conventional-commit-types": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz",
+ "integrity": "sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg==",
+ "dev": true
+ },
+ "conventional-commits-filter": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz",
+ "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==",
+ "dev": true,
+ "requires": {
+ "lodash.ismatch": "^4.4.0",
+ "modify-values": "^1.0.0"
+ }
+ },
+ "conventional-commits-parser": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz",
+ "integrity": "sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==",
+ "dev": true,
+ "requires": {
+ "is-text-path": "^1.0.1",
+ "JSONStream": "^1.0.4",
+ "lodash": "^4.17.15",
+ "meow": "^8.0.0",
+ "split2": "^3.0.0",
+ "through2": "^4.0.0"
+ }
+ },
+ "conventional-recommended-bump": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz",
+ "integrity": "sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw==",
+ "dev": true,
+ "requires": {
+ "concat-stream": "^2.0.0",
+ "conventional-changelog-preset-loader": "^2.3.4",
+ "conventional-commits-filter": "^2.0.7",
+ "conventional-commits-parser": "^3.2.0",
+ "git-raw-commits": "^2.0.8",
+ "git-semver-tags": "^4.1.1",
+ "meow": "^8.0.0",
+ "q": "^1.5.1"
+ }
+ },
+ "core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+ "dev": true
+ },
+ "cosmiconfig": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz",
+ "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==",
+ "dev": true,
+ "requires": {
+ "@types/parse-json": "^4.0.0",
+ "import-fresh": "^3.2.1",
+ "parse-json": "^5.0.0",
+ "path-type": "^4.0.0",
+ "yaml": "^1.10.0"
+ }
+ },
+ "cosmiconfig-typescript-loader": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-2.0.2.tgz",
+ "integrity": "sha512-KmE+bMjWMXJbkWCeY4FJX/npHuZPNr9XF9q9CIQ/bpFwi1qHfCmSiKarrCcRa0LO4fWjk93pVoeRtJAkTGcYNw==",
+ "dev": true,
+ "requires": {
+ "cosmiconfig": "^7",
+ "ts-node": "^10.8.1"
+ }
+ },
+ "create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+ "dev": true
+ },
+ "cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "requires": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ }
+ },
+ "cz-conventional-changelog": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz",
+ "integrity": "sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==",
+ "dev": true,
+ "requires": {
+ "@commitlint/load": ">6.1.1",
+ "chalk": "^2.4.1",
+ "commitizen": "^4.0.3",
+ "conventional-commit-types": "^3.0.0",
+ "lodash.map": "^4.5.1",
+ "longest": "^2.0.1",
+ "word-wrap": "^1.0.3"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "dargs": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz",
+ "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==",
+ "dev": true
+ },
+ "dateformat": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
+ "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==",
+ "dev": true
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+ "dev": true
+ },
+ "decamelize-keys": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz",
+ "integrity": "sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==",
+ "dev": true,
+ "requires": {
+ "decamelize": "^1.1.0",
+ "map-obj": "^1.0.0"
+ },
+ "dependencies": {
+ "map-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+ "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==",
+ "dev": true
+ }
+ }
+ },
+ "dedent": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
+ "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==",
+ "dev": true
+ },
+ "defaults": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
+ "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
+ "dev": true,
+ "requires": {
+ "clone": "^1.0.2"
+ }
+ },
+ "detect-file": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
+ "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==",
+ "dev": true
+ },
+ "detect-indent": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
+ "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==",
+ "dev": true
+ },
+ "detect-newline": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
+ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
+ "dev": true
+ },
+ "diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true
+ },
+ "dot-prop": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
+ "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
+ "dev": true,
+ "requires": {
+ "is-obj": "^2.0.0"
+ }
+ },
+ "dotgitignore": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/dotgitignore/-/dotgitignore-2.1.0.tgz",
+ "integrity": "sha512-sCm11ak2oY6DglEPpCB8TixLjWAxd3kJTs6UIcSasNYxXdFPV+YKlye92c8H4kKFqV5qYMIh7d+cYecEg0dIkA==",
+ "dev": true,
+ "requires": {
+ "find-up": "^3.0.0",
+ "minimatch": "^3.0.4"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^3.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.0.0"
+ }
+ },
+ "p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true
+ },
+ "path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
+ "dev": true
+ }
+ }
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "requires": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": true
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true
+ },
+ "execa": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
+ "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
+ "dev": true,
+ "requires": {
+ "cross-spawn": "^7.0.3",
+ "get-stream": "^6.0.0",
+ "human-signals": "^2.1.0",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.1",
+ "onetime": "^5.1.2",
+ "signal-exit": "^3.0.3",
+ "strip-final-newline": "^2.0.0"
+ }
+ },
+ "expand-tilde": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+ "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==",
+ "dev": true,
+ "requires": {
+ "homedir-polyfill": "^1.0.1"
+ }
+ },
+ "external-editor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+ "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+ "dev": true,
+ "requires": {
+ "chardet": "^0.7.0",
+ "iconv-lite": "^0.4.24",
+ "tmp": "^0.0.33"
+ }
+ },
+ "fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "figures": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+ "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.5"
+ }
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "find-node-modules": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.3.tgz",
+ "integrity": "sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==",
+ "dev": true,
+ "requires": {
+ "findup-sync": "^4.0.0",
+ "merge": "^2.1.1"
+ }
+ },
+ "find-root": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
+ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
+ "dev": true
+ },
+ "find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "findup-sync": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz",
+ "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==",
+ "dev": true,
+ "requires": {
+ "detect-file": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "micromatch": "^4.0.2",
+ "resolve-dir": "^1.0.1"
+ }
+ },
+ "fs-extra": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true
+ },
+ "get-pkg-repo": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz",
+ "integrity": "sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==",
+ "dev": true,
+ "requires": {
+ "@hutson/parse-repository-url": "^3.0.0",
+ "hosted-git-info": "^4.0.0",
+ "through2": "^2.0.0",
+ "yargs": "^16.2.0"
+ },
+ "dependencies": {
+ "cliui": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "dev": true,
+ "requires": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "through2": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+ "dev": true,
+ "requires": {
+ "readable-stream": "~2.3.6",
+ "xtend": "~4.0.1"
+ }
+ },
+ "yargs": {
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+ "dev": true,
+ "requires": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ }
+ }
+ }
+ },
+ "get-stream": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+ "dev": true
+ },
+ "git-raw-commits": {
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz",
+ "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==",
+ "dev": true,
+ "requires": {
+ "dargs": "^7.0.0",
+ "lodash": "^4.17.15",
+ "meow": "^8.0.0",
+ "split2": "^3.0.0",
+ "through2": "^4.0.0"
+ }
+ },
+ "git-remote-origin-url": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz",
+ "integrity": "sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==",
+ "dev": true,
+ "requires": {
+ "gitconfiglocal": "^1.0.0",
+ "pify": "^2.3.0"
+ }
+ },
+ "git-semver-tags": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz",
+ "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==",
+ "dev": true,
+ "requires": {
+ "meow": "^8.0.0",
+ "semver": "^6.0.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "gitconfiglocal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz",
+ "integrity": "sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==",
+ "dev": true,
+ "requires": {
+ "ini": "^1.3.2"
+ }
+ },
+ "glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "global-dirs": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz",
+ "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==",
+ "dev": true,
+ "requires": {
+ "ini": "^1.3.4"
+ }
+ },
+ "global-modules": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+ "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
+ "dev": true,
+ "requires": {
+ "global-prefix": "^1.0.1",
+ "is-windows": "^1.0.1",
+ "resolve-dir": "^1.0.0"
+ }
+ },
+ "global-prefix": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+ "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==",
+ "dev": true,
+ "requires": {
+ "expand-tilde": "^2.0.2",
+ "homedir-polyfill": "^1.0.1",
+ "ini": "^1.3.4",
+ "is-windows": "^1.0.1",
+ "which": "^1.2.14"
+ },
+ "dependencies": {
+ "which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ }
+ }
+ },
+ "graceful-fs": {
+ "version": "4.2.10",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+ "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
+ "dev": true
+ },
+ "handlebars": {
+ "version": "4.7.7",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
+ "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.5",
+ "neo-async": "^2.6.0",
+ "source-map": "^0.6.1",
+ "uglify-js": "^3.1.4",
+ "wordwrap": "^1.0.0"
+ }
+ },
+ "hard-rejection": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz",
+ "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==",
+ "dev": true
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "homedir-polyfill": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+ "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+ "dev": true,
+ "requires": {
+ "parse-passwd": "^1.0.0"
+ }
+ },
+ "hosted-git-info": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
+ "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ },
+ "human-signals": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
+ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+ "dev": true
+ },
+ "husky": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz",
+ "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==",
+ "dev": true
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dev": true,
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "dev": true
+ },
+ "import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "requires": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "dependencies": {
+ "resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true
+ }
+ }
+ },
+ "indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "dev": true
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dev": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+ "dev": true
+ },
+ "inquirer": {
+ "version": "8.2.4",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz",
+ "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==",
+ "dev": true,
+ "requires": {
+ "ansi-escapes": "^4.2.1",
+ "chalk": "^4.1.1",
+ "cli-cursor": "^3.1.0",
+ "cli-width": "^3.0.0",
+ "external-editor": "^3.0.3",
+ "figures": "^3.0.0",
+ "lodash": "^4.17.21",
+ "mute-stream": "0.0.8",
+ "ora": "^5.4.1",
+ "run-async": "^2.4.0",
+ "rxjs": "^7.5.5",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0",
+ "through": "^2.3.6",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "dev": true
+ },
+ "is-core-module": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz",
+ "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==",
+ "dev": true,
+ "requires": {
+ "has": "^1.0.3"
+ }
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-interactive": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
+ "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
+ "dev": true
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true
+ },
+ "is-obj": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
+ "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
+ "dev": true
+ },
+ "is-plain-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+ "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==",
+ "dev": true
+ },
+ "is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "dev": true
+ },
+ "is-text-path": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz",
+ "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==",
+ "dev": true,
+ "requires": {
+ "text-extensions": "^1.0.0"
+ }
+ },
+ "is-unicode-supported": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "dev": true
+ },
+ "is-utf8": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+ "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==",
+ "dev": true
+ },
+ "is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+ "dev": true
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+ "dev": true
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true
+ },
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
+ "js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "requires": {
+ "argparse": "^2.0.1"
+ }
+ },
+ "json-parse-better-errors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+ "dev": true
+ },
+ "json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "dev": true
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
+ "dev": true
+ },
+ "jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.6",
+ "universalify": "^2.0.0"
+ }
+ },
+ "jsonparse": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+ "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==",
+ "dev": true
+ },
+ "JSONStream": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
+ "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
+ "dev": true,
+ "requires": {
+ "jsonparse": "^1.2.0",
+ "through": ">=2.2.7 <3"
+ }
+ },
+ "kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true
+ },
+ "lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "dev": true
+ },
+ "load-json-file": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
+ "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^4.0.0",
+ "pify": "^3.0.0",
+ "strip-bom": "^3.0.0"
+ },
+ "dependencies": {
+ "parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
+ "dev": true,
+ "requires": {
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1"
+ }
+ },
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==",
+ "dev": true
+ },
+ "strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+ "dev": true
+ }
+ }
+ },
+ "locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^5.0.0"
+ }
+ },
+ "lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true
+ },
+ "lodash.ismatch": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz",
+ "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==",
+ "dev": true
+ },
+ "lodash.map": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz",
+ "integrity": "sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==",
+ "dev": true
+ },
+ "log-symbols": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+ "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
+ }
+ },
+ "longest": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/longest/-/longest-2.0.1.tgz",
+ "integrity": "sha512-Ajzxb8CM6WAnFjgiloPsI3bF+WCxcvhdIG3KNA2KN962+tdBsHcuQ4k4qX/EcS/2CRkcc0iAkR956Nib6aXU/Q==",
+ "dev": true
+ },
+ "lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "requires": {
+ "yallist": "^4.0.0"
+ }
+ },
+ "make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "dev": true
+ },
+ "map-obj": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
+ "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
+ "dev": true
+ },
+ "meow": {
+ "version": "8.1.2",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz",
+ "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==",
+ "dev": true,
+ "requires": {
+ "@types/minimist": "^1.2.0",
+ "camelcase-keys": "^6.2.2",
+ "decamelize-keys": "^1.1.0",
+ "hard-rejection": "^2.1.0",
+ "minimist-options": "4.1.0",
+ "normalize-package-data": "^3.0.0",
+ "read-pkg-up": "^7.0.1",
+ "redent": "^3.0.0",
+ "trim-newlines": "^3.0.0",
+ "type-fest": "^0.18.0",
+ "yargs-parser": "^20.2.3"
+ },
+ "dependencies": {
+ "type-fest": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz",
+ "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==",
+ "dev": true
+ }
+ }
+ },
+ "merge": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz",
+ "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==",
+ "dev": true
+ },
+ "merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "dev": true
+ },
+ "micromatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+ "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "dev": true,
+ "requires": {
+ "braces": "^3.0.2",
+ "picomatch": "^2.3.1"
+ }
+ },
+ "mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true
+ },
+ "min-indent": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
+ "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+ "dev": true
+ },
+ "minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
+ "dev": true
+ },
+ "minimist-options": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz",
+ "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==",
+ "dev": true,
+ "requires": {
+ "arrify": "^1.0.1",
+ "is-plain-obj": "^1.1.0",
+ "kind-of": "^6.0.3"
+ }
+ },
+ "modify-values": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz",
+ "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==",
+ "dev": true
+ },
+ "mute-stream": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+ "dev": true
+ },
+ "neo-async": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+ "dev": true
+ },
+ "normalize-package-data": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz",
+ "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "^4.0.1",
+ "is-core-module": "^2.5.0",
+ "semver": "^7.3.4",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "npm-run-path": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+ "dev": true,
+ "requires": {
+ "path-key": "^3.0.0"
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dev": true,
+ "requires": {
+ "mimic-fn": "^2.1.0"
+ }
+ },
+ "ora": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
+ "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==",
+ "dev": true,
+ "requires": {
+ "bl": "^4.1.0",
+ "chalk": "^4.1.0",
+ "cli-cursor": "^3.1.0",
+ "cli-spinners": "^2.5.0",
+ "is-interactive": "^1.0.0",
+ "is-unicode-supported": "^0.1.0",
+ "log-symbols": "^4.1.0",
+ "strip-ansi": "^6.0.0",
+ "wcwidth": "^1.0.1"
+ }
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
+ "dev": true
+ },
+ "p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "requires": {
+ "yocto-queue": "^0.1.0"
+ }
+ },
+ "p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^3.0.2"
+ }
+ },
+ "p-try": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
+ "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==",
+ "dev": true
+ },
+ "parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "requires": {
+ "callsites": "^3.0.0"
+ }
+ },
+ "parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ }
+ },
+ "parse-passwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+ "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==",
+ "dev": true
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true
+ },
+ "path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true
+ },
+ "path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true
+ },
+ "path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true
+ },
+ "picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "dev": true
+ },
+ "process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true
+ },
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true
+ },
+ "q": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
+ "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==",
+ "dev": true
+ },
+ "quick-lru": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz",
+ "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
+ "dev": true
+ },
+ "read-pkg": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
+ "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
+ "dev": true,
+ "requires": {
+ "@types/normalize-package-data": "^2.4.0",
+ "normalize-package-data": "^2.5.0",
+ "parse-json": "^5.0.0",
+ "type-fest": "^0.6.0"
+ },
+ "dependencies": {
+ "hosted-git-info": {
+ "version": "2.8.9",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
+ "dev": true
+ },
+ "normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ },
+ "type-fest": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
+ "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
+ "dev": true
+ }
+ }
+ },
+ "read-pkg-up": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
+ "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
+ "dev": true,
+ "requires": {
+ "find-up": "^4.1.0",
+ "read-pkg": "^5.2.0",
+ "type-fest": "^0.8.1"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true
+ },
+ "type-fest": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+ "dev": true
+ }
+ }
+ },
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ },
+ "redent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
+ "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
+ "dev": true,
+ "requires": {
+ "indent-string": "^4.0.0",
+ "strip-indent": "^3.0.0"
+ }
+ },
+ "require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true
+ },
+ "resolve": {
+ "version": "1.22.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+ "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+ "dev": true,
+ "requires": {
+ "is-core-module": "^2.9.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ }
+ },
+ "resolve-dir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+ "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==",
+ "dev": true,
+ "requires": {
+ "expand-tilde": "^2.0.0",
+ "global-modules": "^1.0.0"
+ }
+ },
+ "resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "dev": true
+ },
+ "resolve-global": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz",
+ "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==",
+ "dev": true,
+ "requires": {
+ "global-dirs": "^0.1.1"
+ }
+ },
+ "restore-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+ "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+ "dev": true,
+ "requires": {
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "run-async": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
+ "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
+ "dev": true
+ },
+ "rxjs": {
+ "version": "7.5.7",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz",
+ "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==",
+ "dev": true,
+ "requires": {
+ "tslib": "^2.1.0"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true
+ },
+ "semver": {
+ "version": "7.3.7",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+ "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ },
+ "shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "requires": {
+ "shebang-regex": "^3.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true
+ },
+ "signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "dev": true
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ },
+ "spdx-correct": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
+ "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
+ "dev": true,
+ "requires": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-exceptions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
+ "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
+ "dev": true
+ },
+ "spdx-expression-parse": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+ "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+ "dev": true,
+ "requires": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-license-ids": {
+ "version": "3.0.12",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz",
+ "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==",
+ "dev": true
+ },
+ "split": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
+ "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
+ "dev": true,
+ "requires": {
+ "through": "2"
+ }
+ },
+ "split2": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz",
+ "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==",
+ "dev": true,
+ "requires": {
+ "readable-stream": "^3.0.0"
+ }
+ },
+ "standard-version": {
+ "version": "9.5.0",
+ "resolved": "https://registry.npmjs.org/standard-version/-/standard-version-9.5.0.tgz",
+ "integrity": "sha512-3zWJ/mmZQsOaO+fOlsa0+QK90pwhNd042qEcw6hKFNoLFs7peGyvPffpEBbK/DSGPbyOvli0mUIFv5A4qTjh2Q==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.2",
+ "conventional-changelog": "3.1.25",
+ "conventional-changelog-config-spec": "2.1.0",
+ "conventional-changelog-conventionalcommits": "4.6.3",
+ "conventional-recommended-bump": "6.1.0",
+ "detect-indent": "^6.0.0",
+ "detect-newline": "^3.1.0",
+ "dotgitignore": "^2.1.0",
+ "figures": "^3.1.0",
+ "find-up": "^5.0.0",
+ "git-semver-tags": "^4.0.0",
+ "semver": "^7.1.1",
+ "stringify-package": "^1.0.1",
+ "yargs": "^16.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "cliui": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "dev": true,
+ "requires": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "yargs": {
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+ "dev": true,
+ "requires": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ }
+ }
+ }
+ },
+ "string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ }
+ },
+ "stringify-package": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/stringify-package/-/stringify-package-1.0.1.tgz",
+ "integrity": "sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg==",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.1"
+ }
+ },
+ "strip-bom": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
+ "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
+ "dev": true
+ },
+ "strip-final-newline": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+ "dev": true
+ },
+ "strip-indent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+ "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+ "dev": true,
+ "requires": {
+ "min-indent": "^1.0.0"
+ }
+ },
+ "strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ },
+ "supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true
+ },
+ "text-extensions": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz",
+ "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==",
+ "dev": true
+ },
+ "through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+ "dev": true
+ },
+ "through2": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz",
+ "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==",
+ "dev": true,
+ "requires": {
+ "readable-stream": "3"
+ }
+ },
+ "tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "dev": true,
+ "requires": {
+ "os-tmpdir": "~1.0.2"
+ }
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ },
+ "trim-newlines": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
+ "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==",
+ "dev": true
+ },
+ "ts-node": {
+ "version": "10.9.1",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
+ "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
+ "dev": true,
+ "requires": {
+ "@cspotcode/source-map-support": "^0.8.0",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "v8-compile-cache-lib": "^3.0.1",
+ "yn": "3.1.1"
+ }
+ },
+ "tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
+ "dev": true
+ },
+ "type-fest": {
+ "version": "0.21.3",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+ "dev": true
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
+ "dev": true
+ },
+ "typescript": {
+ "version": "4.8.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
+ "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
+ "dev": true
+ },
+ "uglify-js": {
+ "version": "3.17.3",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.3.tgz",
+ "integrity": "sha512-JmMFDME3iufZnBpyKL+uS78LRiC+mK55zWfM5f/pWBJfpOttXAqYfdDGRukYhJuyRinvPVAtUhvy7rlDybNtFg==",
+ "dev": true,
+ "optional": true
+ },
+ "universalify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+ "dev": true
+ },
+ "uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true
+ },
+ "v8-compile-cache-lib": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
+ "dev": true
+ },
+ "validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "dev": true,
+ "requires": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
+ "wcwidth": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
+ "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
+ "dev": true,
+ "requires": {
+ "defaults": "^1.0.3"
+ }
+ },
+ "which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "dev": true
+ },
+ "wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
+ "dev": true
+ },
+ "wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true
+ },
+ "xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "dev": true
+ },
+ "y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true
+ },
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
+ "yaml": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+ "dev": true
+ },
+ "yargs": {
+ "version": "17.6.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz",
+ "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==",
+ "dev": true,
+ "requires": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.0.0"
+ },
+ "dependencies": {
+ "yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true
+ }
+ }
+ },
+ "yargs-parser": {
+ "version": "20.2.9",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+ "dev": true
+ },
+ "yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "dev": true
+ },
+ "yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..8d4dd54
--- /dev/null
+++ b/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "trusted-firmware-a",
+ "version": "2.8.0",
+ "license": "BSD-3-Clause",
+ "private": true,
+ "scripts": {
+ "postinstall": "husky install",
+ "release": "standard-version"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ },
+ "devDependencies": {
+ "@commitlint/cli": "^16.1.0",
+ "@commitlint/config-conventional": "^16.0.0",
+ "@commitlint/cz-commitlint": "^16.1.0",
+ "commitizen": "^4.2.4",
+ "conventional-changelog-tf-a": "file:tools/conventional-changelog-tf-a",
+ "husky": "^7.0.4",
+ "js-yaml": "^4.1.0",
+ "standard-version": "^9.3.2"
+ }
+}
diff --git a/plat/allwinner/common/allwinner-common.mk b/plat/allwinner/common/allwinner-common.mk
new file mode 100644
index 0000000..61c1dbe
--- /dev/null
+++ b/plat/allwinner/common/allwinner-common.mk
@@ -0,0 +1,114 @@
+#
+# Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include lib/xlat_tables_v2/xlat_tables.mk
+include lib/libfdt/libfdt.mk
+include drivers/arm/gic/v2/gicv2.mk
+
+AW_PLAT := plat/allwinner
+
+PLAT_INCLUDES := -Iinclude/plat/arm/common/aarch64 \
+ -I${AW_PLAT}/common/include \
+ -I${AW_PLAT}/${PLAT}/include
+
+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/allwinner/axp/common.c \
+ ${GICV2_SOURCES} \
+ 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}/${PLAT}/sunxi_idle_states.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
+
+# By default, attempt to use SCPI to the ARISC management processor. If SCPI
+# is not enabled or SCP firmware is not loaded, fall back to a simpler native
+# implementation that does not support CPU or system suspend.
+#
+# If SCP firmware will always be present (or absent), the unused implementation
+# can be compiled out.
+SUNXI_PSCI_USE_NATIVE ?= 1
+SUNXI_PSCI_USE_SCPI ?= 1
+
+$(eval $(call assert_boolean,SUNXI_PSCI_USE_NATIVE))
+$(eval $(call assert_boolean,SUNXI_PSCI_USE_SCPI))
+$(eval $(call add_define,SUNXI_PSCI_USE_NATIVE))
+$(eval $(call add_define,SUNXI_PSCI_USE_SCPI))
+
+ifeq (${SUNXI_PSCI_USE_NATIVE}${SUNXI_PSCI_USE_SCPI},00)
+$(error "At least one of SCPI or native PSCI ops must be enabled")
+endif
+
+ifeq (${SUNXI_PSCI_USE_NATIVE},1)
+BL31_SOURCES += ${AW_PLAT}/common/sunxi_cpu_ops.c \
+ ${AW_PLAT}/common/sunxi_native_pm.c
+endif
+
+ifeq (${SUNXI_PSCI_USE_SCPI},1)
+BL31_SOURCES += drivers/allwinner/sunxi_msgbox.c \
+ drivers/arm/css/scpi/css_scpi.c \
+ ${AW_PLAT}/common/sunxi_scpi_pm.c
+endif
+
+SUNXI_SETUP_REGULATORS ?= 1
+$(eval $(call assert_boolean,SUNXI_SETUP_REGULATORS))
+$(eval $(call add_define,SUNXI_SETUP_REGULATORS))
+
+SUNXI_BL31_IN_DRAM ?= 0
+$(eval $(call assert_boolean,SUNXI_BL31_IN_DRAM))
+
+ifeq (${SUNXI_BL31_IN_DRAM},1)
+SUNXI_AMEND_DTB := 1
+$(eval $(call add_define,SUNXI_BL31_IN_DRAM))
+endif
+
+SUNXI_AMEND_DTB ?= 0
+$(eval $(call assert_boolean,SUNXI_AMEND_DTB))
+$(eval $(call add_define,SUNXI_AMEND_DTB))
+
+ifeq (${SUNXI_AMEND_DTB},1)
+BL31_SOURCES += common/fdt_fixup.c \
+ ${AW_PLAT}/common/sunxi_prepare_dtb.c
+endif
+
+# 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
+ERRATA_A53_1530924 := 1
+
+# The traditional U-Boot load address is 160MB into DRAM.
+PRELOADED_BL33_BASE ?= 0x4a000000
+
+# 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
+
+# This platform is single-cluster and does not require coherency setup.
+WARMBOOT_ENABLE_DCACHE_EARLY := 1
diff --git a/plat/allwinner/common/arisc_off.S b/plat/allwinner/common/arisc_off.S
new file mode 100644
index 0000000..ed10832
--- /dev/null
+++ b/plat/allwinner/common/arisc_off.S
@@ -0,0 +1,115 @@
+# turn_off_core.S
+#
+# Copyright (c) 2018, Andre Przywara <osp@andrep.de>
+# 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)
diff --git a/plat/allwinner/common/include/mentor_i2c_plat.h b/plat/allwinner/common/include/mentor_i2c_plat.h
new file mode 100644
index 0000000..d03f2d1
--- /dev/null
+++ b/plat/allwinner/common/include/mentor_i2c_plat.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * 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 */
diff --git a/plat/allwinner/common/include/plat_macros.S b/plat/allwinner/common/include/plat_macros.S
new file mode 100644
index 0000000..77f183d
--- /dev/null
+++ b/plat/allwinner/common/include/plat_macros.S
@@ -0,0 +1,27 @@
+/*
+ * 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 <arm_macros.S>
+#include <sunxi_mmap.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, SUNXI_GICC_BASE
+ mov_imm x16, SUNXI_GICD_BASE
+ arm_print_gic_regs
+ .endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/allwinner/common/include/platform_def.h b/plat/allwinner/common/include/platform_def.h
new file mode 100644
index 0000000..c9d075a
--- /dev/null
+++ b/plat/allwinner/common/include/platform_def.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#include <sunxi_mmap.h>
+
+#ifdef SUNXI_BL31_IN_DRAM
+
+#define BL31_BASE SUNXI_DRAM_BASE
+#define BL31_LIMIT (SUNXI_DRAM_BASE + 0x40000)
+
+#define MAX_XLAT_TABLES 4
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
+
+#define SUNXI_BL33_VIRT_BASE PRELOADED_BL33_BASE
+
+#else /* !SUNXI_BL31_IN_DRAM */
+
+#define BL31_BASE (SUNXI_SRAM_A2_BASE + \
+ SUNXI_SRAM_A2_BL31_OFFSET)
+#define BL31_LIMIT (SUNXI_SRAM_A2_BASE + \
+ SUNXI_SRAM_A2_SIZE - SUNXI_SCP_SIZE)
+
+/* Overwrite U-Boot SPL, but reserve the first page for the SPL header. */
+#define BL31_NOBITS_BASE (SUNXI_SRAM_A1_BASE + 0x1000)
+#define BL31_NOBITS_LIMIT (SUNXI_SRAM_A1_BASE + SUNXI_SRAM_A1_SIZE)
+
+#define MAX_XLAT_TABLES 1
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 28)
+
+#define SUNXI_BL33_VIRT_BASE SUNXI_DRAM_VIRT_BASE
+
+/* The SCP firmware is allocated the last 16KiB of SRAM A2. */
+#define SUNXI_SCP_BASE BL31_LIMIT
+#define SUNXI_SCP_SIZE 0x4000
+
+#endif /* SUNXI_BL31_IN_DRAM */
+
+/* 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_STATIC_MMAP_REGIONS 3
+#define MAX_MMAP_REGIONS (5 + MAX_STATIC_MMAP_REGIONS)
+
+#define PLAT_CSS_SCP_COM_SHARED_MEM_BASE \
+ (SUNXI_SRAM_A2_BASE + SUNXI_SRAM_A2_SIZE - 0x200)
+
+/* These states are used directly for SCPI communication. */
+#define PLAT_MAX_PWR_LVL_STATES U(3)
+#define PLAT_MAX_RET_STATE U(1)
+#define PLAT_MAX_OFF_STATE U(3)
+
+#define PLAT_MAX_PWR_LVL U(2)
+#define PLAT_NUM_PWR_DOMAINS (U(1) + \
+ PLATFORM_CLUSTER_COUNT + \
+ PLATFORM_CORE_COUNT)
+
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
+
+#define PLATFORM_CLUSTER_COUNT U(1)
+#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \
+ PLATFORM_MAX_CPUS_PER_CLUSTER)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER U(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 */
diff --git a/plat/allwinner/common/include/sunxi_def.h b/plat/allwinner/common/include/sunxi_def.h
new file mode 100644
index 0000000..c17ef95
--- /dev/null
+++ b/plat/allwinner/common/include/sunxi_def.h
@@ -0,0 +1,26 @@
+/*
+ * 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
+#define SUNXI_SOC_H616 0x1823
+#define SUNXI_SOC_R329 0x1851
+
+#define JEDEC_ALLWINNER_BKID 9U
+#define JEDEC_ALLWINNER_MFID 0x9eU
+
+#endif /* SUNXI_DEF_H */
diff --git a/plat/allwinner/common/include/sunxi_private.h b/plat/allwinner/common/include/sunxi_private.h
new file mode 100644
index 0000000..6a38657
--- /dev/null
+++ b/plat/allwinner/common/include/sunxi_private.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_PRIVATE_H
+#define SUNXI_PRIVATE_H
+
+#include <common/fdt_fixup.h>
+
+#include <lib/psci/psci.h>
+
+extern const struct psci_cpu_idle_state sunxi_idle_states[];
+
+void sunxi_configure_mmu_el3(int flags);
+
+void sunxi_cpu_on(u_register_t mpidr);
+void sunxi_cpu_power_off_others(void);
+void sunxi_cpu_power_off_self(void);
+void sunxi_power_down(void);
+
+#if SUNXI_PSCI_USE_NATIVE
+void sunxi_set_native_psci_ops(const plat_psci_ops_t **psci_ops);
+#else
+static inline void sunxi_set_native_psci_ops(const plat_psci_ops_t **psci_ops)
+{
+}
+#endif
+#if SUNXI_PSCI_USE_SCPI
+bool sunxi_psci_is_scpi(void);
+int sunxi_set_scpi_psci_ops(const plat_psci_ops_t **psci_ops);
+#else
+static inline bool sunxi_psci_is_scpi(void)
+{
+ return false;
+}
+static inline int sunxi_set_scpi_psci_ops(const plat_psci_ops_t **psci_ops)
+{
+ return -1;
+}
+#endif
+int sunxi_validate_ns_entrypoint(uintptr_t ns_entrypoint);
+
+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, uint16_t param);
+
+#if SUNXI_AMEND_DTB
+void sunxi_prepare_dtb(void *fdt);
+#else
+static inline void sunxi_prepare_dtb(void *fdt)
+{
+}
+#endif
+
+#endif /* SUNXI_PRIVATE_H */
diff --git a/plat/allwinner/common/plat_helpers.S b/plat/allwinner/common/plat_helpers.S
new file mode 100644
index 0000000..b00c7ae
--- /dev/null
+++ b/plat/allwinner/common/plat_helpers.S
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <sunxi_def.h>
+#include <sunxi_mmap.h>
+
+ .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
diff --git a/plat/allwinner/common/sunxi_bl31_setup.c b/plat/allwinner/common/sunxi_bl31_setup.c
new file mode 100644
index 0000000..a32124a
--- /dev/null
+++ b/plat/allwinner/common/sunxi_bl31_setup.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/fdt_fixup.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <sunxi_def.h>
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+static console_t console;
+
+static void *fdt;
+
+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_BL33_VIRT_BASE;
+
+ for (i = 0; i < 2048 / sizeof(uint64_t); i++) {
+ void *dtb_base;
+
+ if (u_boot_base[i] != PRELOADED_BL33_BASE)
+ 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 = (char *)u_boot_base + u_boot_base[i + 1];
+
+ if (fdt_check_header(dtb_base) == 0) {
+ fdt = dtb_base;
+ return;
+ }
+ }
+}
+
+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 = PRELOADED_BL33_BASE;
+ 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);
+}
+
+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();
+
+ 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;
+ case SUNXI_SOC_H616:
+ soc_name = "H616";
+ break;
+ case SUNXI_SOC_R329:
+ soc_name = "R329";
+ break;
+ default:
+ soc_name = "unknown";
+ break;
+ }
+ NOTICE("BL31: Detected Allwinner %s SoC (%04x)\n", soc_name, soc_id);
+
+ generic_delay_timer_init();
+
+ 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");
+}
+
+void bl31_plat_runtime_setup(void)
+{
+ /* Change the DTB if the configuration requires so. */
+ sunxi_prepare_dtb(fdt);
+
+ console_switch_state(CONSOLE_FLAG_RUNTIME);
+}
+
+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;
+}
diff --git a/plat/allwinner/common/sunxi_common.c b/plat/allwinner/common/sunxi_common.c
new file mode 100644
index 0000000..092659c
--- /dev/null
+++ b/plat/allwinner/common/sunxi_common.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/smccc.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <services/arm_arch_svc.h>
+
+#include <sunxi_def.h>
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+static const mmap_region_t sunxi_mmap[MAX_STATIC_MMAP_REGIONS + 1] = {
+ MAP_REGION_FLAT(SUNXI_SRAM_BASE, SUNXI_SRAM_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER),
+ MAP_REGION_FLAT(SUNXI_DEV_BASE, SUNXI_DEV_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER),
+ MAP_REGION(PRELOADED_BL33_BASE, SUNXI_BL33_VIRT_BASE,
+ SUNXI_DRAM_MAP_SIZE, MT_RW_DATA | MT_NS),
+ {},
+};
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+ return SUNXI_OSC24M_CLK_IN_HZ;
+}
+
+void sunxi_configure_mmu_el3(int flags)
+{
+ mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
+ BL_CODE_END - BL_CODE_BASE,
+ MT_CODE | MT_SECURE);
+ mmap_add_region(BL_CODE_END, BL_CODE_END,
+ BL_END - BL_CODE_END,
+ MT_RW_DATA | MT_SECURE);
+#if SEPARATE_CODE_AND_RODATA
+ mmap_add_region(BL_RO_DATA_BASE, BL_RO_DATA_BASE,
+ BL_RO_DATA_END - BL_RO_DATA_BASE,
+ MT_RO_DATA | MT_SECURE);
+#endif
+#if SEPARATE_NOBITS_REGION
+ mmap_add_region(BL_NOBITS_BASE, BL_NOBITS_BASE,
+ BL_NOBITS_END - BL_NOBITS_BASE,
+ MT_RW_DATA | MT_SECURE);
+#endif
+#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 | MT_EXECUTE_NEVER);
+#endif
+
+ 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:
+ case SUNXI_SOC_H616:
+ pin_func = use_rsb ? 0x22 : 0x33;
+ device_bit = BIT(16);
+ reset_offset = use_rsb ? 0x1bc : 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 && socid != SUNXI_SOC_H616)
+ 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);
+
+ /* un-gate clock */
+ if (socid != SUNXI_SOC_H6 && socid != SUNXI_SOC_H616)
+ mmio_setbits_32(SUNXI_R_PRCM_BASE + 0x28, device_bit);
+ else
+ mmio_setbits_32(SUNXI_R_PRCM_BASE + reset_offset, BIT(0));
+
+ /* 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);
+
+ return 0;
+}
+
+int32_t plat_is_smccc_feature_available(u_register_t fid)
+{
+ switch (fid) {
+ case SMCCC_ARCH_SOC_ID:
+ return SMC_ARCH_CALL_SUCCESS;
+ default:
+ return SMC_ARCH_CALL_NOT_SUPPORTED;
+ }
+}
+
+int32_t plat_get_soc_version(void)
+{
+ int32_t ret;
+
+ ret = SOC_ID_SET_JEP_106(JEDEC_ALLWINNER_BKID, JEDEC_ALLWINNER_MFID);
+
+ return ret | (sunxi_read_soc_id() & SOC_ID_IMPL_DEF_MASK);
+}
+
+int32_t plat_get_soc_revision(void)
+{
+ uint32_t reg = mmio_read_32(SRAM_VER_REG);
+
+ return reg & GENMASK_32(7, 0);
+}
diff --git a/plat/allwinner/common/sunxi_cpu_ops.c b/plat/allwinner/common/sunxi_cpu_ops.c
new file mode 100644
index 0000000..46e7090
--- /dev/null
+++ b/plat/allwinner/common/sunxi_cpu_ops.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+
+#include <sunxi_cpucfg.h>
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+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);
+ udelay(1);
+}
+
+/* We can't turn ourself off like this, but it works for other cores. */
+static 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));
+ /* 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);
+}
+
+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_AA64nAA32_REG(cluster),
+ BIT(SUNXI_AA64nAA32_OFFSET + 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_cpu_power_off_others(void)
+{
+ u_register_t self = read_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 != self)
+ sunxi_cpu_off(mpidr);
+ }
+ }
+}
diff --git a/plat/allwinner/common/sunxi_native_pm.c b/plat/allwinner/common/sunxi_native_pm.c
new file mode 100644
index 0000000..148f50e
--- /dev/null
+++ b/plat/allwinner/common/sunxi_native_pm.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+#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)
+
+static int sunxi_pwr_domain_on(u_register_t mpidr)
+{
+ sunxi_cpu_on(mpidr);
+
+ return PSCI_E_SUCCESS;
+}
+
+static void sunxi_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ gicv2_cpuif_disable();
+
+ sunxi_cpu_power_off_self();
+}
+
+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)
+{
+ gicv2_cpuif_disable();
+
+ /* Attempt to power down the board (may not return) */
+ sunxi_power_down();
+
+ /* Turn off all CPUs */
+ sunxi_cpu_power_off_others();
+ sunxi_cpu_power_off_self();
+ psci_power_down_wfi();
+}
+
+static void __dead2 sunxi_system_reset(void)
+{
+ gicv2_cpuif_disable();
+
+ /* 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");
+ panic();
+}
+
+static const plat_psci_ops_t sunxi_native_psci_ops = {
+ .pwr_domain_on = sunxi_pwr_domain_on,
+ .pwr_domain_off = sunxi_pwr_domain_off,
+ .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,
+};
+
+void sunxi_set_native_psci_ops(const plat_psci_ops_t **psci_ops)
+{
+ *psci_ops = &sunxi_native_psci_ops;
+}
diff --git a/plat/allwinner/common/sunxi_pm.c b/plat/allwinner/common/sunxi_pm.c
new file mode 100644
index 0000000..3772b4a
--- /dev/null
+++ b/plat/allwinner/common/sunxi_pm.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <common/fdt_fixup.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <sunxi_cpucfg.h>
+#include <sunxi_private.h>
+
+static bool psci_is_scpi;
+
+#if SUNXI_PSCI_USE_SCPI
+bool sunxi_psci_is_scpi(void)
+{
+ return psci_is_scpi;
+}
+#endif
+
+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_INVALID_ADDRESS;
+ }
+
+ return PSCI_E_SUCCESS;
+}
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const plat_psci_ops_t **psci_ops)
+{
+ assert(psci_ops);
+
+ /* Program all CPU entry points. */
+ for (unsigned int cpu = 0; cpu < PLATFORM_CORE_COUNT; ++cpu) {
+ mmio_write_32(SUNXI_CPUCFG_RVBAR_LO_REG(cpu),
+ sec_entrypoint & 0xffffffff);
+ mmio_write_32(SUNXI_CPUCFG_RVBAR_HI_REG(cpu),
+ sec_entrypoint >> 32);
+ }
+
+ if (sunxi_set_scpi_psci_ops(psci_ops) == 0) {
+ INFO("PSCI: Suspend is available via SCPI\n");
+ psci_is_scpi = true;
+ } else {
+ INFO("PSCI: Suspend is unavailable\n");
+ sunxi_set_native_psci_ops(psci_ops);
+ }
+
+ return 0;
+}
diff --git a/plat/allwinner/common/sunxi_prepare_dtb.c b/plat/allwinner/common/sunxi_prepare_dtb.c
new file mode 100644
index 0000000..66af35a
--- /dev/null
+++ b/plat/allwinner/common/sunxi_prepare_dtb.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2021, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <libfdt.h>
+
+#include <common/debug.h>
+#include <common/fdt_fixup.h>
+#include <common/fdt_wrappers.h>
+
+#include <sunxi_private.h>
+
+void sunxi_prepare_dtb(void *fdt)
+{
+ int ret;
+
+ if (fdt == NULL || fdt_check_header(fdt) != 0) {
+ return;
+ }
+
+ ret = fdt_open_into(fdt, fdt, 0x10000);
+ if (ret < 0) {
+ ERROR("Preparing devicetree at %p: error %d\n", fdt, ret);
+ return;
+ }
+
+#ifdef SUNXI_BL31_IN_DRAM
+ /* Reserve memory used by Trusted Firmware. */
+ if (fdt_add_reserved_memory(fdt, "tf-a@40000000", BL31_BASE,
+ BL31_LIMIT - BL31_BASE)) {
+ WARN("Failed to add reserved memory nodes to DT.\n");
+ }
+#endif
+
+ if (sunxi_psci_is_scpi()) {
+ ret = fdt_add_cpu_idle_states(fdt, sunxi_idle_states);
+ if (ret < 0) {
+ WARN("Failed to add idle states to DT: %d\n", ret);
+ }
+ }
+
+ ret = fdt_pack(fdt);
+ if (ret < 0) {
+ ERROR("Failed to pack devicetree at %p: error %d\n",
+ fdt, ret);
+ }
+
+ clean_dcache_range((uintptr_t)fdt, fdt_blob_size(fdt));
+ INFO("Changed devicetree.\n");
+}
diff --git a/plat/allwinner/common/sunxi_scpi_pm.c b/plat/allwinner/common/sunxi_scpi_pm.c
new file mode 100644
index 0000000..41dc563
--- /dev/null
+++ b/plat/allwinner/common/sunxi_scpi_pm.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_scpi.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+/*
+ * The addresses for the SCP exception vectors are defined in the or1k
+ * architecture specification.
+ */
+#define OR1K_VEC_FIRST 0x01
+#define OR1K_VEC_LAST 0x0e
+#define OR1K_VEC_ADDR(n) (0x100 * (n))
+
+/*
+ * This magic value is the little-endian representation of the or1k
+ * instruction "l.mfspr r2, r0, 0x12", which is guaranteed to be the
+ * first instruction in the SCP firmware.
+ */
+#define SCP_FIRMWARE_MAGIC 0xb4400012
+
+#define PLAT_LOCAL_PSTATE_WIDTH U(4)
+#define PLAT_LOCAL_PSTATE_MASK ((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1)
+
+#define CPU_PWR_LVL MPIDR_AFFLVL0
+#define CLUSTER_PWR_LVL MPIDR_AFFLVL1
+#define SYSTEM_PWR_LVL MPIDR_AFFLVL2
+
+#define CPU_PWR_STATE(state) \
+ ((state)->pwr_domain_state[CPU_PWR_LVL])
+#define CLUSTER_PWR_STATE(state) \
+ ((state)->pwr_domain_state[CLUSTER_PWR_LVL])
+#define SYSTEM_PWR_STATE(state) \
+ ((state)->pwr_domain_state[SYSTEM_PWR_LVL])
+
+static void sunxi_cpu_standby(plat_local_state_t cpu_state)
+{
+ u_register_t scr = read_scr_el3();
+
+ assert(is_local_state_retn(cpu_state));
+
+ write_scr_el3(scr | SCR_IRQ_BIT);
+ wfi();
+ write_scr_el3(scr);
+}
+
+static int sunxi_pwr_domain_on(u_register_t mpidr)
+{
+ scpi_set_css_power_state(mpidr,
+ scpi_power_on,
+ scpi_power_on,
+ scpi_power_on);
+
+ return PSCI_E_SUCCESS;
+}
+
+static void sunxi_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ plat_local_state_t cpu_pwr_state = CPU_PWR_STATE(target_state);
+ plat_local_state_t cluster_pwr_state = CLUSTER_PWR_STATE(target_state);
+ plat_local_state_t system_pwr_state = SYSTEM_PWR_STATE(target_state);
+
+ if (is_local_state_off(cpu_pwr_state)) {
+ gicv2_cpuif_disable();
+ }
+
+ scpi_set_css_power_state(read_mpidr(),
+ cpu_pwr_state,
+ cluster_pwr_state,
+ system_pwr_state);
+}
+
+static void sunxi_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) {
+ gicv2_distif_init();
+ }
+ if (is_local_state_off(CPU_PWR_STATE(target_state))) {
+ gicv2_pcpu_distif_init();
+ gicv2_cpuif_enable();
+ }
+}
+
+static void __dead2 sunxi_system_off(void)
+{
+ uint32_t ret;
+
+ gicv2_cpuif_disable();
+
+ /* Send the power down request to the SCP. */
+ ret = scpi_sys_power_state(scpi_system_shutdown);
+ if (ret != SCP_OK) {
+ ERROR("PSCI: SCPI %s failed: %d\n", "shutdown", ret);
+ }
+
+ psci_power_down_wfi();
+}
+
+static void __dead2 sunxi_system_reset(void)
+{
+ uint32_t ret;
+
+ gicv2_cpuif_disable();
+
+ /* Send the system reset request to the SCP. */
+ ret = scpi_sys_power_state(scpi_system_reboot);
+ if (ret != SCP_OK) {
+ ERROR("PSCI: SCPI %s failed: %d\n", "reboot", ret);
+ }
+
+ psci_power_down_wfi();
+}
+
+static int sunxi_validate_power_state(unsigned int power_state,
+ psci_power_state_t *req_state)
+{
+ unsigned int power_level = psci_get_pstate_pwrlvl(power_state);
+ unsigned int state_id = psci_get_pstate_id(power_state);
+ unsigned int type = psci_get_pstate_type(power_state);
+ unsigned int i;
+
+ assert(req_state != NULL);
+
+ if (power_level > PLAT_MAX_PWR_LVL) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ if (type == PSTATE_TYPE_STANDBY) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ /* Pass through the requested PSCI state as-is. */
+ for (i = 0; i <= power_level; ++i) {
+ unsigned int local_pstate = state_id & PLAT_LOCAL_PSTATE_MASK;
+
+ req_state->pwr_domain_state[i] = local_pstate;
+ state_id >>= PLAT_LOCAL_PSTATE_WIDTH;
+ }
+
+ /* Higher power domain levels should all remain running */
+ for (; i <= PLAT_MAX_PWR_LVL; ++i) {
+ req_state->pwr_domain_state[i] = PSCI_LOCAL_STATE_RUN;
+ }
+
+ return PSCI_E_SUCCESS;
+}
+
+static void sunxi_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+ assert(req_state != NULL);
+
+ for (unsigned int i = 0; i <= PLAT_MAX_PWR_LVL; ++i) {
+ req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+ }
+}
+
+static const plat_psci_ops_t sunxi_scpi_psci_ops = {
+ .cpu_standby = sunxi_cpu_standby,
+ .pwr_domain_on = sunxi_pwr_domain_on,
+ .pwr_domain_off = sunxi_pwr_domain_off,
+ .pwr_domain_suspend = sunxi_pwr_domain_off,
+ .pwr_domain_on_finish = sunxi_pwr_domain_on_finish,
+ .pwr_domain_suspend_finish = sunxi_pwr_domain_on_finish,
+ .system_off = sunxi_system_off,
+ .system_reset = sunxi_system_reset,
+ .validate_power_state = sunxi_validate_power_state,
+ .validate_ns_entrypoint = sunxi_validate_ns_entrypoint,
+ .get_sys_suspend_power_state = sunxi_get_sys_suspend_power_state,
+};
+
+int sunxi_set_scpi_psci_ops(const plat_psci_ops_t **psci_ops)
+{
+ *psci_ops = &sunxi_scpi_psci_ops;
+
+ /* Check for a valid SCP firmware. */
+ if (mmio_read_32(SUNXI_SCP_BASE) != SCP_FIRMWARE_MAGIC) {
+ return -1;
+ }
+
+ /* Program SCP exception vectors to the firmware entrypoint. */
+ for (unsigned int i = OR1K_VEC_FIRST; i <= OR1K_VEC_LAST; ++i) {
+ uint32_t vector = SUNXI_SRAM_A2_BASE + OR1K_VEC_ADDR(i);
+ uint32_t offset = SUNXI_SCP_BASE - vector;
+
+ mmio_write_32(vector, offset >> 2);
+ }
+
+ /* Take the SCP out of reset. */
+ mmio_setbits_32(SUNXI_R_CPUCFG_BASE, BIT(0));
+
+ /* Wait for the SCP firmware to boot. */
+ return scpi_wait_ready();
+}
diff --git a/plat/allwinner/common/sunxi_security.c b/plat/allwinner/common/sunxi_security.c
new file mode 100644
index 0000000..98b91c3
--- /dev/null
+++ b/plat/allwinner/common/sunxi_security.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <sunxi_ccu.h>
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+#include <sunxi_spc.h>
+
+#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)
+{
+ int i;
+
+ INFO("Configuring SPC Controller\n");
+ /* SPC setup: set all devices to non-secure */
+ for (i = 0; i < SUNXI_SPC_NUM_PORTS; i++)
+ mmio_write_32(SUNXI_SPC_DECPORT_SET_REG(i), 0xffffffff);
+
+ /* 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 bus clocks to non-secure */
+ mmio_write_32(SUNXI_R_PRCM_SEC_SWITCH_REG, 0x1);
+
+ /* Set all DMA channels (16 max.) to non-secure */
+ mmio_write_32(SUNXI_DMA_BASE + DMA_SEC_REG, 0xffff);
+}
diff --git a/plat/allwinner/common/sunxi_topology.c b/plat/allwinner/common/sunxi_topology.c
new file mode 100644
index 0000000..45be1e0
--- /dev/null
+++ b/plat/allwinner/common/sunxi_topology.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <plat/common/platform.h>
+
+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;
+}
diff --git a/plat/allwinner/sun50i_a64/include/core_off_arisc.h b/plat/allwinner/sun50i_a64/include/core_off_arisc.h
new file mode 100644
index 0000000..ae436ca
--- /dev/null
+++ b/plat/allwinner/sun50i_a64/include/core_off_arisc.h
@@ -0,0 +1,39 @@
+/*
+ * 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, <corenr> */
+ 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 */
+};
diff --git a/plat/allwinner/sun50i_a64/include/sunxi_ccu.h b/plat/allwinner/sun50i_a64/include/sunxi_ccu.h
new file mode 100644
index 0000000..2a24886
--- /dev/null
+++ b/plat/allwinner/sun50i_a64/include/sunxi_ccu.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_CCU_H
+#define SUNXI_CCU_H
+
+#define SUNXI_CCU_SEC_SWITCH_REG (SUNXI_CCU_BASE + 0x02f0)
+
+#define SUNXI_R_PRCM_SEC_SWITCH_REG (SUNXI_R_PRCM_BASE + 0x01d0)
+
+#endif /* SUNXI_CCU_H */
diff --git a/plat/allwinner/sun50i_a64/include/sunxi_cpucfg.h b/plat/allwinner/sun50i_a64/include/sunxi_cpucfg.h
new file mode 100644
index 0000000..aed3585
--- /dev/null
+++ b/plat/allwinner/sun50i_a64/include/sunxi_cpucfg.h
@@ -0,0 +1,39 @@
+/*
+ * 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 <sunxi_mmap.h>
+
+/* 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)
+
+#define SUNXI_AA64nAA32_REG SUNXI_CPUCFG_CLS_CTRL_REG0
+#define SUNXI_AA64nAA32_OFFSET 24
+
+#endif /* SUNXI_CPUCFG_H */
diff --git a/plat/allwinner/sun50i_a64/include/sunxi_mmap.h b/plat/allwinner/sun50i_a64/include/sunxi_mmap.h
new file mode 100644
index 0000000..6d10921
--- /dev/null
+++ b/plat/allwinner/sun50i_a64/include/sunxi_mmap.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017-2019, 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 0x00040000
+#define SUNXI_SRAM_A2_BL31_OFFSET 0x00004000
+#define SUNXI_SRAM_A2_SIZE 0x00014000
+#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_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 */
diff --git a/plat/allwinner/sun50i_a64/include/sunxi_spc.h b/plat/allwinner/sun50i_a64/include/sunxi_spc.h
new file mode 100644
index 0000000..5ba7e18
--- /dev/null
+++ b/plat/allwinner/sun50i_a64/include/sunxi_spc.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_SPC_H
+#define SUNXI_SPC_H
+
+#define SUNXI_SPC_NUM_PORTS 6
+
+#define SUNXI_SPC_DECPORT_STA_REG(p) (SUNXI_SPC_BASE + 0x0004 + 0x0c * (p))
+#define SUNXI_SPC_DECPORT_SET_REG(p) (SUNXI_SPC_BASE + 0x0008 + 0x0c * (p))
+#define SUNXI_SPC_DECPORT_CLR_REG(p) (SUNXI_SPC_BASE + 0x000c + 0x0c * (p))
+
+#endif /* SUNXI_SPC_H */
diff --git a/plat/allwinner/sun50i_a64/platform.mk b/plat/allwinner/sun50i_a64/platform.mk
new file mode 100644
index 0000000..e3c7c52
--- /dev/null
+++ b/plat/allwinner/sun50i_a64/platform.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (c) 2017-2019, 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
+
+BL31_SOURCES += drivers/allwinner/axp/axp803.c \
+ drivers/allwinner/sunxi_rsb.c
+
+FDT_ASSUME_MASK := "(ASSUME_LATEST | ASSUME_NO_ROLLBACK | ASSUME_LIBFDT_ORDER)"
+$(eval $(call add_define,FDT_ASSUME_MASK))
+
+# Put NOBITS memory in SRAM A1, overwriting U-Boot's SPL.
+SEPARATE_NOBITS_REGION := 1
diff --git a/plat/allwinner/sun50i_a64/sunxi_idle_states.c b/plat/allwinner/sun50i_a64/sunxi_idle_states.c
new file mode 100644
index 0000000..2918bb7
--- /dev/null
+++ b/plat/allwinner/sun50i_a64/sunxi_idle_states.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <sunxi_private.h>
+
+const struct psci_cpu_idle_state sunxi_idle_states[] = {
+ {
+ .name = "cpu-sleep",
+ .power_state = 0x00010003,
+ .local_timer_stop = true,
+ .entry_latency_us = 800,
+ .exit_latency_us = 1500,
+ .min_residency_us = 25000
+ },
+ {
+ .name = "cluster-sleep",
+ .power_state = 0x01010013,
+ .local_timer_stop = true,
+ .entry_latency_us = 850,
+ .exit_latency_us = 1500,
+ .min_residency_us = 50000
+ },
+ {}
+};
diff --git a/plat/allwinner/sun50i_a64/sunxi_power.c b/plat/allwinner/sun50i_a64/sunxi_power.c
new file mode 100644
index 0000000..a35b9dd
--- /dev/null
+++ b/plat/allwinner/sun50i_a64/sunxi_power.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/allwinner/axp.h>
+#include <drivers/allwinner/sunxi_rsb.h>
+#include <lib/mmio.h>
+
+#include <core_off_arisc.h>
+#include <sunxi_def.h>
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+static enum pmic_type {
+ UNKNOWN,
+ 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.
+ */
+static 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;
+
+ /* Switch to the recommended 3 MHz bus clock. */
+ ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000);
+ if (ret)
+ return ret;
+
+ /* Initiate an I2C transaction to switch the PMIC to RSB mode. */
+ ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8);
+ if (ret)
+ return ret;
+
+ /* Associate the 8-bit runtime address with the 12-bit bus address. */
+ ret = rsb_assign_runtime_address(AXP803_HW_ADDR,
+ AXP803_RT_ADDR);
+ if (ret)
+ return ret;
+
+ return axp_check_id();
+}
+
+int axp_read(uint8_t reg)
+{
+ return rsb_read(AXP803_RT_ADDR, reg);
+}
+
+int axp_write(uint8_t reg, uint8_t val)
+{
+ return rsb_write(AXP803_RT_ADDR, reg, val);
+}
+
+int sunxi_pmic_setup(uint16_t socid, const void *fdt)
+{
+ int ret;
+
+ switch (socid) {
+ case SUNXI_SOC_H5:
+ NOTICE("PMIC: Assuming H5 reference regulator design\n");
+
+ pmic = REF_DESIGN_H5;
+
+ break;
+ case SUNXI_SOC_A64:
+ pmic = GENERIC_A64;
+
+ INFO("PMIC: Probing AXP803 on RSB\n");
+
+ ret = sunxi_init_platform_r_twi(socid, true);
+ if (ret)
+ return ret;
+
+ ret = rsb_init();
+ if (ret)
+ return ret;
+
+ pmic = AXP803_RSB;
+ axp_setup_regulators(fdt);
+
+ /* Switch the PMIC back to I2C mode. */
+ ret = axp_write(AXP20X_MODE_REG, AXP20X_MODE_I2C);
+ if (ret)
+ return ret;
+
+ break;
+ default:
+ return -ENODEV;
+ }
+ return 0;
+}
+
+void 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();
+ axp_power_off();
+ break;
+ default:
+ break;
+ }
+
+}
+
+/* This lock synchronises access to the arisc management processor. */
+static DEFINE_BAKERY_LOCK(arisc_lock);
+
+/*
+ * If we are supposed to turn ourself off, tell the arisc SCP to do that
+ * work for us. Without any SCPI provider running there, we place some
+ * OpenRISC code into SRAM, put the address of that into the reset vector
+ * and release the arisc reset line. The SCP will wait for the core to enter
+ * WFI, then execute that code and pull the line up again.
+ * The code expects the core mask to be patched into the first instruction.
+ */
+void sunxi_cpu_power_off_self(void)
+{
+ u_register_t mpidr = read_mpidr();
+ unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
+ uintptr_t arisc_reset_vec = SUNXI_SRAM_A2_BASE + 0x100;
+ uint32_t *code = arisc_core_off;
+
+ 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. */
+ code[0] = (code[0] & ~0xffff) | BIT_32(core);
+ clean_dcache_range((uintptr_t)code, sizeof(arisc_core_off));
+
+ /*
+ * 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);
+
+ /* 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);
+}
diff --git a/plat/allwinner/sun50i_h6/include/sunxi_ccu.h b/plat/allwinner/sun50i_h6/include/sunxi_ccu.h
new file mode 100644
index 0000000..85fbb90
--- /dev/null
+++ b/plat/allwinner/sun50i_h6/include/sunxi_ccu.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_CCU_H
+#define SUNXI_CCU_H
+
+#define SUNXI_CCU_SEC_SWITCH_REG (SUNXI_CCU_BASE + 0x0f00)
+
+#define SUNXI_R_PRCM_SEC_SWITCH_REG (SUNXI_R_PRCM_BASE + 0x0290)
+
+#endif /* SUNXI_CCU_H */
diff --git a/plat/allwinner/sun50i_h6/include/sunxi_cpucfg.h b/plat/allwinner/sun50i_h6/include/sunxi_cpucfg.h
new file mode 100644
index 0000000..5bfda5d
--- /dev/null
+++ b/plat/allwinner/sun50i_h6/include/sunxi_cpucfg.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_CPUCFG_H
+#define SUNXI_CPUCFG_H
+
+#include <sunxi_mmap.h>
+
+/* 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)
+
+#define SUNXI_CPUIDLE_EN_REG (SUNXI_R_CPUCFG_BASE + 0x0100)
+#define SUNXI_CORE_CLOSE_REG (SUNXI_R_CPUCFG_BASE + 0x0104)
+#define SUNXI_PWR_SW_DELAY_REG (SUNXI_R_CPUCFG_BASE + 0x0140)
+#define SUNXI_CONFIG_DELAY_REG (SUNXI_R_CPUCFG_BASE + 0x0144)
+
+#define SUNXI_AA64nAA32_REG SUNXI_CPUCFG_CLS_CTRL_REG0
+#define SUNXI_AA64nAA32_OFFSET 24
+
+#endif /* SUNXI_CPUCFG_H */
diff --git a/plat/allwinner/sun50i_h6/include/sunxi_mmap.h b/plat/allwinner/sun50i_h6/include/sunxi_mmap.h
new file mode 100644
index 0000000..58216d8
--- /dev/null
+++ b/plat/allwinner/sun50i_h6/include/sunxi_mmap.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2017-2019, 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 0x00100000
+#define SUNXI_SRAM_A2_BL31_OFFSET 0x00004000
+#define SUNXI_SRAM_A2_SIZE 0x00018000
+#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 0x03001000
+#define SUNXI_PIO_BASE 0x0300b000
+#define SUNXI_SPC_BASE 0x03008000
+#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_RSB_BASE 0x07083000
+#define SUNXI_R_UART_BASE 0x07080000
+#define SUNXI_R_PIO_BASE 0x07022000
+
+#endif /* SUNXI_MMAP_H */
diff --git a/plat/allwinner/sun50i_h6/include/sunxi_spc.h b/plat/allwinner/sun50i_h6/include/sunxi_spc.h
new file mode 100644
index 0000000..0f5965b
--- /dev/null
+++ b/plat/allwinner/sun50i_h6/include/sunxi_spc.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_SPC_H
+#define SUNXI_SPC_H
+
+#define SUNXI_SPC_NUM_PORTS 14
+
+#define SUNXI_SPC_DECPORT_STA_REG(p) (SUNXI_SPC_BASE + 0x0000 + 0x10 * (p))
+#define SUNXI_SPC_DECPORT_SET_REG(p) (SUNXI_SPC_BASE + 0x0004 + 0x10 * (p))
+#define SUNXI_SPC_DECPORT_CLR_REG(p) (SUNXI_SPC_BASE + 0x0008 + 0x10 * (p))
+
+#endif /* SUNXI_SPC_H */
diff --git a/plat/allwinner/sun50i_h6/platform.mk b/plat/allwinner/sun50i_h6/platform.mk
new file mode 100644
index 0000000..e13e8cb
--- /dev/null
+++ b/plat/allwinner/sun50i_h6/platform.mk
@@ -0,0 +1,14 @@
+#
+# Copyright (c) 2017-2019, 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
+
+BL31_SOURCES += drivers/allwinner/axp/axp805.c \
+ drivers/allwinner/sunxi_rsb.c
+
+# Put NOBITS memory in SRAM A1, overwriting U-Boot's SPL.
+SEPARATE_NOBITS_REGION := 1
diff --git a/plat/allwinner/sun50i_h6/sunxi_idle_states.c b/plat/allwinner/sun50i_h6/sunxi_idle_states.c
new file mode 100644
index 0000000..4339bcd
--- /dev/null
+++ b/plat/allwinner/sun50i_h6/sunxi_idle_states.c
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <sunxi_private.h>
+
+const struct psci_cpu_idle_state sunxi_idle_states[] = {
+ {}
+};
diff --git a/plat/allwinner/sun50i_h6/sunxi_power.c b/plat/allwinner/sun50i_h6/sunxi_power.c
new file mode 100644
index 0000000..d298e6b
--- /dev/null
+++ b/plat/allwinner/sun50i_h6/sunxi_power.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/allwinner/axp.h>
+#include <drivers/allwinner/sunxi_rsb.h>
+#include <lib/mmio.h>
+
+#include <sunxi_cpucfg.h>
+#include <sunxi_def.h>
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+#define AXP805_HW_ADDR 0x745
+#define AXP805_RT_ADDR 0x3a
+
+static enum pmic_type {
+ UNKNOWN,
+ AXP805,
+} pmic;
+
+int axp_read(uint8_t reg)
+{
+ return rsb_read(AXP805_RT_ADDR, reg);
+}
+
+int axp_write(uint8_t reg, uint8_t val)
+{
+ return rsb_write(AXP805_RT_ADDR, reg, val);
+}
+
+static int rsb_init(void)
+{
+ int ret;
+
+ ret = rsb_init_controller();
+ if (ret)
+ return ret;
+
+ /* Switch to the recommended 3 MHz bus clock. */
+ ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000);
+ if (ret)
+ return ret;
+
+ /* Initiate an I2C transaction to switch the PMIC to RSB mode. */
+ ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8);
+ if (ret)
+ return ret;
+
+ /* Associate the 8-bit runtime address with the 12-bit bus address. */
+ ret = rsb_assign_runtime_address(AXP805_HW_ADDR, AXP805_RT_ADDR);
+ if (ret)
+ return ret;
+
+ return axp_check_id();
+}
+
+int sunxi_pmic_setup(uint16_t socid, const void *fdt)
+{
+ int ret;
+
+ INFO("PMIC: Probing AXP805 on RSB\n");
+
+ ret = sunxi_init_platform_r_twi(socid, true);
+ if (ret)
+ return ret;
+
+ ret = rsb_init();
+ if (ret)
+ return ret;
+
+ /* Switch the AXP805 to master/single-PMIC mode. */
+ ret = axp_write(0xff, 0x0);
+ if (ret)
+ return ret;
+
+ pmic = AXP805;
+ axp_setup_regulators(fdt);
+
+ /* Switch the PMIC back to I2C mode. */
+ ret = axp_write(AXP20X_MODE_REG, AXP20X_MODE_I2C);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+void sunxi_power_down(void)
+{
+ switch (pmic) {
+ case AXP805:
+ /* (Re-)init RSB in case the rich OS has disabled it. */
+ sunxi_init_platform_r_twi(SUNXI_SOC_H6, true);
+ rsb_init();
+ axp_power_off();
+ break;
+ default:
+ break;
+ }
+}
+
+void sunxi_cpu_power_off_self(void)
+{
+ u_register_t mpidr = read_mpidr();
+ unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
+
+ /* Enable the CPUIDLE hardware (only really needs to be done once). */
+ mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000);
+ mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001);
+
+ /* Trigger power off for this core. */
+ mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core));
+}
diff --git a/plat/allwinner/sun50i_h616/include/sunxi_ccu.h b/plat/allwinner/sun50i_h616/include/sunxi_ccu.h
new file mode 100644
index 0000000..85fbb90
--- /dev/null
+++ b/plat/allwinner/sun50i_h616/include/sunxi_ccu.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_CCU_H
+#define SUNXI_CCU_H
+
+#define SUNXI_CCU_SEC_SWITCH_REG (SUNXI_CCU_BASE + 0x0f00)
+
+#define SUNXI_R_PRCM_SEC_SWITCH_REG (SUNXI_R_PRCM_BASE + 0x0290)
+
+#endif /* SUNXI_CCU_H */
diff --git a/plat/allwinner/sun50i_h616/include/sunxi_cpucfg.h b/plat/allwinner/sun50i_h616/include/sunxi_cpucfg.h
new file mode 100644
index 0000000..dab663b
--- /dev/null
+++ b/plat/allwinner/sun50i_h616/include/sunxi_cpucfg.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_CPUCFG_H
+#define SUNXI_CPUCFG_H
+
+#include <sunxi_mmap.h>
+
+/* 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)
+
+#define SUNXI_CPUIDLE_EN_REG (SUNXI_R_CPUCFG_BASE + 0x0100)
+#define SUNXI_CORE_CLOSE_REG (SUNXI_R_CPUCFG_BASE + 0x0104)
+#define SUNXI_PWR_SW_DELAY_REG (SUNXI_R_CPUCFG_BASE + 0x0140)
+#define SUNXI_CONFIG_DELAY_REG (SUNXI_R_CPUCFG_BASE + 0x0144)
+
+#define SUNXI_AA64nAA32_REG SUNXI_CPUCFG_CLS_CTRL_REG0
+#define SUNXI_AA64nAA32_OFFSET 24
+
+#endif /* SUNXI_CPUCFG_H */
diff --git a/plat/allwinner/sun50i_h616/include/sunxi_mmap.h b/plat/allwinner/sun50i_h616/include/sunxi_mmap.h
new file mode 100644
index 0000000..3b4f4a0
--- /dev/null
+++ b/plat/allwinner/sun50i_h616/include/sunxi_mmap.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017-2019, 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 0x00038000
+#define SUNXI_SRAM_A1_BASE 0x00020000
+#define SUNXI_SRAM_A1_SIZE 0x00008000
+#define SUNXI_SRAM_C_BASE 0x00028000
+#define SUNXI_SRAM_C_SIZE 0x00030000
+#define SUNXI_DEV_BASE 0x01000000
+#define SUNXI_DEV_SIZE 0x09000000
+#define SUNXI_DRAM_BASE 0x40000000
+#define SUNXI_DRAM_VIRT_BASE SUNXI_DRAM_BASE
+
+/* Memory-mapped devices */
+#define SUNXI_SYSCON_BASE 0x03000000
+#define SUNXI_CCU_BASE 0x03001000
+#define SUNXI_DMA_BASE 0x03002000
+#define SUNXI_SID_BASE 0x03006000
+#define SUNXI_SPC_BASE 0x03008000
+#define SUNXI_WDOG_BASE 0x030090a0
+#define SUNXI_PIO_BASE 0x0300b000
+#define SUNXI_GICD_BASE 0x03021000
+#define SUNXI_GICC_BASE 0x03022000
+#define SUNXI_UART0_BASE 0x05000000
+#define SUNXI_SPI0_BASE 0x05010000
+#define SUNXI_R_CPUCFG_BASE 0x07000400
+#define SUNXI_R_PRCM_BASE 0x07010000
+//#define SUNXI_R_WDOG_BASE 0x07020400
+#define SUNXI_R_WDOG_BASE SUNXI_WDOG_BASE
+#define SUNXI_R_PIO_BASE 0x07022000
+#define SUNXI_R_UART_BASE 0x07080000
+#define SUNXI_R_I2C_BASE 0x07081400
+#define SUNXI_R_RSB_BASE 0x07083000
+#define SUNXI_CPUCFG_BASE 0x09010000
+
+#endif /* SUNXI_MMAP_H */
diff --git a/plat/allwinner/sun50i_h616/include/sunxi_spc.h b/plat/allwinner/sun50i_h616/include/sunxi_spc.h
new file mode 100644
index 0000000..0f5965b
--- /dev/null
+++ b/plat/allwinner/sun50i_h616/include/sunxi_spc.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_SPC_H
+#define SUNXI_SPC_H
+
+#define SUNXI_SPC_NUM_PORTS 14
+
+#define SUNXI_SPC_DECPORT_STA_REG(p) (SUNXI_SPC_BASE + 0x0000 + 0x10 * (p))
+#define SUNXI_SPC_DECPORT_SET_REG(p) (SUNXI_SPC_BASE + 0x0004 + 0x10 * (p))
+#define SUNXI_SPC_DECPORT_CLR_REG(p) (SUNXI_SPC_BASE + 0x0008 + 0x10 * (p))
+
+#endif /* SUNXI_SPC_H */
diff --git a/plat/allwinner/sun50i_h616/platform.mk b/plat/allwinner/sun50i_h616/platform.mk
new file mode 100644
index 0000000..de494a2
--- /dev/null
+++ b/plat/allwinner/sun50i_h616/platform.mk
@@ -0,0 +1,22 @@
+#
+# Copyright (c) 2017-2020, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+SUNXI_BL31_IN_DRAM := 1
+
+# Without a management processor there is no SCPI support.
+SUNXI_PSCI_USE_SCPI := 0
+SUNXI_PSCI_USE_NATIVE := 1
+
+# The differences between the platforms are covered by the include files.
+include plat/allwinner/common/allwinner-common.mk
+
+# the above could be overwritten on the command line
+ifeq (${SUNXI_PSCI_USE_SCPI}, 1)
+ $(error "H616 does not support SCPI PSCI ops")
+endif
+
+BL31_SOURCES += drivers/allwinner/axp/axp805.c \
+ drivers/allwinner/sunxi_rsb.c \
diff --git a/plat/allwinner/sun50i_h616/sunxi_idle_states.c b/plat/allwinner/sun50i_h616/sunxi_idle_states.c
new file mode 100644
index 0000000..4339bcd
--- /dev/null
+++ b/plat/allwinner/sun50i_h616/sunxi_idle_states.c
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <sunxi_private.h>
+
+const struct psci_cpu_idle_state sunxi_idle_states[] = {
+ {}
+};
diff --git a/plat/allwinner/sun50i_h616/sunxi_power.c b/plat/allwinner/sun50i_h616/sunxi_power.c
new file mode 100644
index 0000000..dd6ebba
--- /dev/null
+++ b/plat/allwinner/sun50i_h616/sunxi_power.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited. All rights reserved.
+ * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/allwinner/axp.h>
+#include <drivers/allwinner/sunxi_rsb.h>
+#include <lib/mmio.h>
+
+#include <sunxi_cpucfg.h>
+#include <sunxi_def.h>
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+#define AXP305_I2C_ADDR 0x36
+#define AXP305_HW_ADDR 0x745
+#define AXP305_RT_ADDR 0x3a
+
+static enum pmic_type {
+ UNKNOWN,
+ AXP305,
+} pmic;
+
+int axp_read(uint8_t reg)
+{
+ return rsb_read(AXP305_RT_ADDR, reg);
+}
+
+int axp_write(uint8_t reg, uint8_t val)
+{
+ return rsb_write(AXP305_RT_ADDR, reg, val);
+}
+
+static int rsb_init(void)
+{
+ int ret;
+
+ ret = rsb_init_controller();
+ if (ret)
+ return ret;
+
+ /* Switch to the recommended 3 MHz bus clock. */
+ ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000);
+ if (ret)
+ return ret;
+
+ /* Initiate an I2C transaction to switch the PMIC to RSB mode. */
+ ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8);
+ if (ret)
+ return ret;
+
+ /* Associate the 8-bit runtime address with the 12-bit bus address. */
+ ret = rsb_assign_runtime_address(AXP305_HW_ADDR, AXP305_RT_ADDR);
+ if (ret)
+ return ret;
+
+ return axp_check_id();
+}
+
+int sunxi_pmic_setup(uint16_t socid, const void *fdt)
+{
+ int ret;
+
+ INFO("PMIC: Probing AXP305 on RSB\n");
+
+ ret = sunxi_init_platform_r_twi(socid, true);
+ if (ret) {
+ INFO("Could not init platform bus: %d\n", ret);
+ return ret;
+ }
+
+ ret = rsb_init();
+ if (ret) {
+ INFO("Could not init RSB: %d\n", ret);
+ return ret;
+ }
+
+ pmic = AXP305;
+ axp_setup_regulators(fdt);
+
+ /* Switch the PMIC back to I2C mode. */
+ ret = axp_write(AXP20X_MODE_REG, AXP20X_MODE_I2C);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+void sunxi_power_down(void)
+{
+ switch (pmic) {
+ case AXP305:
+ /* Re-initialise after rich OS might have used it. */
+ sunxi_init_platform_r_twi(SUNXI_SOC_H616, true);
+ rsb_init();
+ axp_power_off();
+ break;
+ default:
+ break;
+ }
+}
+
+void sunxi_cpu_power_off_self(void)
+{
+ u_register_t mpidr = read_mpidr();
+ unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
+
+ /* Enable the CPUIDLE hardware (only really needs to be done once). */
+ mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0x16aa0000);
+ mmio_write_32(SUNXI_CPUIDLE_EN_REG, 0xaa160001);
+
+ /* Trigger power off for this core. */
+ mmio_write_32(SUNXI_CORE_CLOSE_REG, BIT_32(core));
+}
diff --git a/plat/allwinner/sun50i_r329/include/sunxi_ccu.h b/plat/allwinner/sun50i_r329/include/sunxi_ccu.h
new file mode 100644
index 0000000..0e6b543
--- /dev/null
+++ b/plat/allwinner/sun50i_r329/include/sunxi_ccu.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2021 Sipeed
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_CCU_H
+#define SUNXI_CCU_H
+
+#define SUNXI_CCU_SEC_SWITCH_REG (SUNXI_CCU_BASE + 0x0f00)
+
+#define SUNXI_R_PRCM_SEC_SWITCH_REG (SUNXI_R_PRCM_BASE + 0x0290)
+
+#endif /* SUNXI_CCU_H */
diff --git a/plat/allwinner/sun50i_r329/include/sunxi_cpucfg.h b/plat/allwinner/sun50i_r329/include/sunxi_cpucfg.h
new file mode 100644
index 0000000..9478f32
--- /dev/null
+++ b/plat/allwinner/sun50i_r329/include/sunxi_cpucfg.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2021 Sipeed
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_CPUCFG_H
+#define SUNXI_CPUCFG_H
+
+#include <sunxi_mmap.h>
+
+/* c = cluster, n = core */
+#define SUNXI_CPUCFG_CLS_CTRL_REG0(c) (SUNXI_C0_CPUXCFG_BASE + 0x0010)
+#define SUNXI_CPUCFG_CLS_CTRL_REG1(c) (SUNXI_C0_CPUXCFG_BASE + 0x0014)
+#define SUNXI_CPUCFG_CACHE_CFG_REG (SUNXI_C0_CPUXCFG_BASE + 0x0024)
+#define SUNXI_CPUCFG_DBG_REG0 (SUNXI_C0_CPUXCFG_BASE + 0x00c0)
+
+#define SUNXI_CPUCFG_RST_CTRL_REG(c) (SUNXI_C0_CPUXCFG_BASE + 0x0000)
+#define SUNXI_CPUCFG_GEN_CTRL_REG0(c) (SUNXI_CPUCFG_BASE + 0x0000)
+#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)
+
+#define SUNXI_AA64nAA32_REG SUNXI_CPUCFG_GEN_CTRL_REG0
+#define SUNXI_AA64nAA32_OFFSET 4
+
+#endif /* SUNXI_CPUCFG_H */
diff --git a/plat/allwinner/sun50i_r329/include/sunxi_mmap.h b/plat/allwinner/sun50i_r329/include/sunxi_mmap.h
new file mode 100644
index 0000000..a4469b5
--- /dev/null
+++ b/plat/allwinner/sun50i_r329/include/sunxi_mmap.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017-2019, 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
+/*
+ * In fact all SRAM from 0x100000 is SRAM A2. However as it's too big for
+ * firmware, and the user manual gives a tip on a 2*64K/27*64K partition,
+ * only use the first 2*64K for firmwares now, with the SPL using the first
+ * 64K and BL3-1 using the second one.
+ *
+ * Only the used 2*64K SRAM is defined here, to prevent a gaint translation
+ * table to be generated.
+ */
+#define SUNXI_SRAM_BASE 0x00100000
+#define SUNXI_SRAM_SIZE 0x00020000
+#define SUNXI_SRAM_A1_BASE 0x00100000
+#define SUNXI_SRAM_A1_SIZE 0x00010000
+#define SUNXI_SRAM_A2_BASE 0x00110000
+#define SUNXI_SRAM_A2_BL31_OFFSET 0x00000000
+#define SUNXI_SRAM_A2_SIZE 0x00010000
+#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_WDOG_BASE 0x020000a0
+#define SUNXI_R_WDOG_BASE SUNXI_WDOG_BASE
+#define SUNXI_PIO_BASE 0x02000400
+#define SUNXI_SPC_BASE 0x02000800
+#define SUNXI_CCU_BASE 0x02001000
+#define SUNXI_UART0_BASE 0x02500000
+#define SUNXI_SYSCON_BASE 0x03000000
+#define SUNXI_DMA_BASE 0x03002000
+#define SUNXI_SID_BASE 0x03006000
+#define SUNXI_GICD_BASE 0x03021000
+#define SUNXI_GICC_BASE 0x03022000
+#define SUNXI_SPI0_BASE 0x04025000
+#define SUNXI_R_CPUCFG_BASE 0x07000400
+#define SUNXI_R_PRCM_BASE 0x07010000
+#define SUNXI_R_PIO_BASE 0x07022000
+#define SUNXI_R_UART_BASE 0x07080000
+#define SUNXI_R_I2C_BASE 0x07081400
+#define SUNXI_CPUCFG_BASE 0x08100000
+#define SUNXI_C0_CPUXCFG_BASE 0x09010000
+
+#endif /* SUNXI_MMAP_H */
diff --git a/plat/allwinner/sun50i_r329/include/sunxi_spc.h b/plat/allwinner/sun50i_r329/include/sunxi_spc.h
new file mode 100644
index 0000000..2c87bca
--- /dev/null
+++ b/plat/allwinner/sun50i_r329/include/sunxi_spc.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2021 Sipeed
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_SPC_H
+#define SUNXI_SPC_H
+
+/* Get by REing stock ATF and checking initialization loop boundary */
+#define SUNXI_SPC_NUM_PORTS 11
+
+#define SUNXI_SPC_DECPORT_STA_REG(p) (SUNXI_SPC_BASE + 0x0000 + 0x10 * (p))
+#define SUNXI_SPC_DECPORT_SET_REG(p) (SUNXI_SPC_BASE + 0x0004 + 0x10 * (p))
+#define SUNXI_SPC_DECPORT_CLR_REG(p) (SUNXI_SPC_BASE + 0x0008 + 0x10 * (p))
+
+#endif /* SUNXI_SPC_H */
diff --git a/plat/allwinner/sun50i_r329/platform.mk b/plat/allwinner/sun50i_r329/platform.mk
new file mode 100644
index 0000000..05d7cde
--- /dev/null
+++ b/plat/allwinner/sun50i_r329/platform.mk
@@ -0,0 +1,20 @@
+#
+# Copyright (c) 2021 Sipeed
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Without a management processor there is no SCPI support.
+SUNXI_PSCI_USE_SCPI := 0
+SUNXI_PSCI_USE_NATIVE := 1
+
+# The differences between the platforms are covered by the include files.
+include plat/allwinner/common/allwinner-common.mk
+
+# the above could be overwritten on the command line
+ifeq (${SUNXI_PSCI_USE_SCPI}, 1)
+ $(error "R329 does not support SCPI PSCI ops")
+endif
+
+# Put NOBITS memory in the first 64K of SRAM A2, overwriting U-Boot's SPL.
+SEPARATE_NOBITS_REGION := 1
diff --git a/plat/allwinner/sun50i_r329/sunxi_idle_states.c b/plat/allwinner/sun50i_r329/sunxi_idle_states.c
new file mode 100644
index 0000000..4339bcd
--- /dev/null
+++ b/plat/allwinner/sun50i_r329/sunxi_idle_states.c
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <sunxi_private.h>
+
+const struct psci_cpu_idle_state sunxi_idle_states[] = {
+ {}
+};
diff --git a/plat/allwinner/sun50i_r329/sunxi_power.c b/plat/allwinner/sun50i_r329/sunxi_power.c
new file mode 100644
index 0000000..96a24d5
--- /dev/null
+++ b/plat/allwinner/sun50i_r329/sunxi_power.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2021 Sipeed
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <sunxi_mmap.h>
+#include <sunxi_cpucfg.h>
+#include <sunxi_private.h>
+
+int sunxi_pmic_setup(uint16_t socid, const void *fdt)
+{
+ /* Currently known hardware has no PMIC */
+
+ return 0;
+}
+
+void sunxi_power_down(void)
+{
+}
+
+void sunxi_cpu_power_off_self(void)
+{
+ /* TODO: It's still unknown whether CPUIDLE exists on R329 */
+}
diff --git a/plat/amlogic/axg/axg_bl31_setup.c b/plat/amlogic/axg/axg_bl31_setup.c
new file mode 100644
index 0000000..8cc9d69
--- /dev/null
+++ b/plat/amlogic/axg/axg_bl31_setup.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#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 axg_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 axg_bl31_param *from_bl2;
+
+ /* Initialize the console to provide early debug support */
+ aml_console_init();
+
+ from_bl2 = (struct axg_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 AML_USE_ATOS
+ /*
+ * BL2 is unconditionally setting 0 (OPTEE_AARCH64) in arg0 even when
+ * the BL32 image is 32bit (OPTEE_AARCH32). This is causing the boot to
+ * hang when ATOS (32bit Amlogic BL32 binary-only TEE OS) is used.
+ *
+ * Hardcode to OPTEE_AARCH32 / MODE_RW_32.
+ */
+ bl32_image_ep_info.args.arg0 = MODE_RW_32;
+#endif
+
+ 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 axg_scp_ready(void)
+{
+ return AML_AO_RTI_SCP_IS_READY(mmio_read_32(AML_AO_RTI_SCP_STAT));
+}
+
+static inline void axg_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 (!axg_scp_ready())
+ ;
+}
+
+/*******************************************************************************
+ * GICv2 driver setup information
+ ******************************************************************************/
+static const interrupt_prop_t axg_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 axg_gic_data = {
+ .gicd_base = AML_GICD_BASE,
+ .gicc_base = AML_GICC_BASE,
+ .interrupt_props = axg_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(axg_interrupt_props)
+};
+
+void bl31_platform_setup(void)
+{
+ aml_mhu_secure_init();
+
+ gicv2_driver_init(&axg_gic_data);
+ gicv2_distif_init();
+ gicv2_pcpu_distif_init();
+ gicv2_cpuif_enable();
+
+ axg_scp_boot();
+}
diff --git a/plat/amlogic/axg/axg_common.c b/plat/amlogic/axg/axg_common.c
new file mode 100644
index 0000000..870daf4
--- /dev/null
+++ b/plat/amlogic/axg/axg_common.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/ep_info.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <platform_def.h>
+#include <stdint.h>
+
+/*******************************************************************************
+ * 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_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 axg_mmap[] = {
+ MAP_NSDRAM0,
+ MAP_NS_SHARE_MEM,
+ MAP_SEC_SHARE_MEM,
+ MAP_SEC_DEVICE0,
+ 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 axg_bl_mmap[] = {
+ MAP_BL31,
+ MAP_BL_CODE,
+ MAP_BL_RO_DATA,
+#if USE_COHERENT_MEM
+ MAP_BL_COHERENT,
+#endif
+ {0}
+ };
+#endif
+
+ mmap_add(axg_bl_mmap);
+
+ mmap_add(axg_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, PLAT_SYS_CPU_CFG7);
+ mmio_clrbits_32(AML_AO_TIMESTAMP_CNTL, PLAT_AO_TIMESTAMP_CNTL);
+
+ return AML_OSC24M_CLK_IN_HZ;
+}
diff --git a/plat/amlogic/axg/axg_def.h b/plat/amlogic/axg/axg_def.h
new file mode 100644
index 0000000..d90681a
--- /dev/null
+++ b/plat/amlogic/axg/axg_def.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AXG_DEF_H
+#define AXG_DEF_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * System oscillator
+ ******************************************************************************/
+#define AML_OSC24M_CLK_IN_HZ ULL(24000000) /* 24 MHz */
+
+/*******************************************************************************
+ * Memory regions
+ ******************************************************************************/
+#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_SEC_DEVICE2_BASE UL(0xFF620000)
+#define AML_SEC_DEVICE2_SIZE UL(0x00028000)
+
+#define AML_TZRAM_BASE UL(0xFFFC0000)
+#define AML_TZRAM_SIZE UL(0x00020000)
+
+/* Mailboxes */
+#define AML_MHU_SECURE_SCP_TO_AP_PAYLOAD UL(0xFFFD3800)
+#define AML_MHU_SECURE_AP_TO_SCP_PAYLOAD UL(0xFFFD3A00)
+#define AML_PSCI_MAILBOX_BASE UL(0xFFFD3F00)
+
+/*******************************************************************************
+ * 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 /* AXG_DEF_H */
diff --git a/plat/amlogic/axg/axg_pm.c b/plat/amlogic/axg/axg_pm.c
new file mode 100644
index 0000000..e67f263
--- /dev/null
+++ b/plat/amlogic/axg/axg_pm.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/console.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#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 axg_sec_entrypoint;
+
+static void axg_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 axg_pm_reset(u_register_t mpidr, uint32_t value)
+{
+ 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, value);
+}
+
+static void __dead2 axg_system_reset(void)
+{
+ u_register_t mpidr = read_mpidr_el1();
+ int ret;
+
+ INFO("BL31: PSCI_SYSTEM_RESET\n");
+
+ ret = aml_scpi_sys_power_state(SCPI_SYSTEM_REBOOT);
+ if (ret != 0) {
+ ERROR("BL31: PSCI_SYSTEM_RESET: SCP error: %i\n", ret);
+ panic();
+ }
+
+ axg_pm_reset(mpidr, 0);
+
+ wfi();
+
+ ERROR("BL31: PSCI_SYSTEM_RESET: Operation not handled\n");
+ panic();
+}
+
+static void __dead2 axg_system_off(void)
+{
+ u_register_t mpidr = read_mpidr_el1();
+ int ret;
+
+ INFO("BL31: PSCI_SYSTEM_OFF\n");
+
+ ret = aml_scpi_sys_power_state(SCPI_SYSTEM_SHUTDOWN);
+ if (ret != 0) {
+ ERROR("BL31: PSCI_SYSTEM_OFF: SCP error %i\n", ret);
+ panic();
+ }
+
+ axg_pm_set_reset_addr(mpidr, 0);
+ axg_pm_reset(mpidr, 0);
+
+ dmbsy();
+ wfi();
+
+ ERROR("BL31: PSCI_SYSTEM_OFF: Operation not handled\n");
+ panic();
+}
+
+static int32_t axg_pwr_domain_on(u_register_t mpidr)
+{
+ axg_pm_set_reset_addr(mpidr, axg_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 axg_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
+ PLAT_LOCAL_STATE_OFF);
+
+ gicv2_pcpu_distif_init();
+ gicv2_cpuif_enable();
+
+ axg_pm_set_reset_addr(read_mpidr_el1(), 0);
+}
+
+static void axg_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ u_register_t mpidr = read_mpidr_el1();
+ uint32_t system_state = SCPI_POWER_ON;
+ uint32_t cluster_state = SCPI_POWER_ON;
+
+ assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
+ PLAT_LOCAL_STATE_OFF);
+
+ axg_pm_reset(mpidr, -1);
+
+ gicv2_cpuif_disable();
+
+ if (target_state->pwr_domain_state[MPIDR_AFFLVL2] ==
+ PLAT_LOCAL_STATE_OFF)
+ system_state = SCPI_POWER_OFF;
+
+ if (target_state->pwr_domain_state[MPIDR_AFFLVL1] ==
+ PLAT_LOCAL_STATE_OFF)
+ cluster_state = SCPI_POWER_OFF;
+
+
+ aml_scpi_set_css_power_state(mpidr,
+ SCPI_POWER_OFF, cluster_state,
+ system_state);
+}
+
+static void __dead2 axg_pwr_domain_pwr_down_wfi(const psci_power_state_t
+ *target_state)
+{
+ dsbsy();
+ axg_pm_reset(read_mpidr_el1(), 0);
+
+ for (;;)
+ wfi();
+}
+
+/*******************************************************************************
+ * Platform handlers and setup function.
+ ******************************************************************************/
+static const plat_psci_ops_t axg_ops = {
+ .pwr_domain_on = axg_pwr_domain_on,
+ .pwr_domain_on_finish = axg_pwr_domain_on_finish,
+ .pwr_domain_off = axg_pwr_domain_off,
+ .pwr_domain_pwr_down_wfi = axg_pwr_domain_pwr_down_wfi,
+ .system_off = axg_system_off,
+ .system_reset = axg_system_reset
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const plat_psci_ops_t **psci_ops)
+{
+ axg_sec_entrypoint = sec_entrypoint;
+ *psci_ops = &axg_ops;
+ return 0;
+}
diff --git a/plat/amlogic/axg/include/platform_def.h b/plat/amlogic/axg/include/platform_def.h
new file mode 100644
index 0000000..c97687e
--- /dev/null
+++ b/plat/amlogic/axg/include/platform_def.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <lib/utils_def.h>
+
+#include "../axg_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_AFFLVL2
+#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)
+
+#define PLAT_SYS_CPU_CFG7 (U(1) << 25)
+#define PLAT_AO_TIMESTAMP_CNTL U(0x1ff)
+
+/* 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 */
diff --git a/plat/amlogic/axg/platform.mk b/plat/amlogic/axg/platform.mk
new file mode 100644
index 0000000..3560b0c
--- /dev/null
+++ b/plat/amlogic/axg/platform.mk
@@ -0,0 +1,95 @@
+#
+# Copyright (c) 2020, 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
+
+AML_USE_ATOS := 0
+$(eval $(call assert_boolean,AML_USE_ATOS))
+$(eval $(call add_define,AML_USE_ATOS))
+
+# 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
+
diff --git a/plat/amlogic/common/aarch64/aml_helpers.S b/plat/amlogic/common/aarch64/aml_helpers.S
new file mode 100644
index 0000000..159c7d1
--- /dev/null
+++ b/plat/amlogic/common/aarch64/aml_helpers.S
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+
+ .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
+
+ /* ---------------------------------------------
+ * void plat_crash_console_flush()
+ * Out : void.
+ * 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
diff --git a/plat/amlogic/common/aml_console.c b/plat/amlogic/common/aml_console.c
new file mode 100644
index 0000000..e21d707
--- /dev/null
+++ b/plat/amlogic/common/aml_console.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019, Carlo Caione <ccaione@baylibre.com>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <meson_console.h>
+#include <platform_def.h>
+
+/*******************************************************************************
+ * Function that sets up the console
+ ******************************************************************************/
+static console_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_FLAG_BOOT | CONSOLE_FLAG_RUNTIME);
+}
diff --git a/plat/amlogic/common/aml_efuse.c b/plat/amlogic/common/aml_efuse.c
new file mode 100644
index 0000000..00884eb
--- /dev/null
+++ b/plat/amlogic/common/aml_efuse.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#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;
+}
diff --git a/plat/amlogic/common/aml_mhu.c b/plat/amlogic/common/aml_mhu.c
new file mode 100644
index 0000000..001686a
--- /dev/null
+++ b/plat/amlogic/common/aml_mhu.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+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);
+}
diff --git a/plat/amlogic/common/aml_scpi.c b/plat/amlogic/common/aml_scpi.c
new file mode 100644
index 0000000..c8a6772
--- /dev/null
+++ b/plat/amlogic/common/aml_scpi.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <crypto/sha_dma.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <string.h>
+
+#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));
+}
diff --git a/plat/amlogic/common/aml_sip_svc.c b/plat/amlogic/common/aml_sip_svc.c
new file mode 100644
index 0000000..ab4c015
--- /dev/null
+++ b/plat/amlogic/common/aml_sip_svc.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+#include <stdint.h>
+#include <string.h>
+
+#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
+);
diff --git a/plat/amlogic/common/aml_thermal.c b/plat/amlogic/common/aml_thermal.c
new file mode 100644
index 0000000..53ed103
--- /dev/null
+++ b/plat/amlogic/common/aml_thermal.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#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 */
+}
diff --git a/plat/amlogic/common/aml_topology.c b/plat/amlogic/common/aml_topology.c
new file mode 100644
index 0000000..0a04c11
--- /dev/null
+++ b/plat/amlogic/common/aml_topology.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <platform_def.h>
+#include <stdint.h>
+
+#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);
+}
diff --git a/plat/amlogic/common/include/aml_private.h b/plat/amlogic/common/include/aml_private.h
new file mode 100644
index 0000000..724f382
--- /dev/null
+++ b/plat/amlogic/common/include/aml_private.h
@@ -0,0 +1,41 @@
+/*
+ * 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 <stddef.h>
+#include <stdint.h>
+
+/* 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 */
diff --git a/plat/amlogic/common/include/plat_macros.S b/plat/amlogic/common/include/plat_macros.S
new file mode 100644
index 0000000..d620fcf
--- /dev/null
+++ b/plat/amlogic/common/include/plat_macros.S
@@ -0,0 +1,71 @@
+/*
+ * 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 <drivers/arm/gicv2.h>
+#include <platform_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 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 */
diff --git a/plat/amlogic/g12a/g12a_bl31_setup.c b/plat/amlogic/g12a/g12a_bl31_setup.c
new file mode 100644
index 0000000..77057a1
--- /dev/null
+++ b/plat/amlogic/g12a/g12a_bl31_setup.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#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();
+}
diff --git a/plat/amlogic/g12a/g12a_common.c b/plat/amlogic/g12a/g12a_common.c
new file mode 100644
index 0000000..e74ed04
--- /dev/null
+++ b/plat/amlogic/g12a/g12a_common.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/ep_info.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <platform_def.h>
+#include <stdint.h>
+
+/*******************************************************************************
+ * 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;
+}
diff --git a/plat/amlogic/g12a/g12a_def.h b/plat/amlogic/g12a/g12a_def.h
new file mode 100644
index 0000000..d032815
--- /dev/null
+++ b/plat/amlogic/g12a/g12a_def.h
@@ -0,0 +1,135 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/*******************************************************************************
+ * 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 */
diff --git a/plat/amlogic/g12a/g12a_pm.c b/plat/amlogic/g12a/g12a_pm.c
new file mode 100644
index 0000000..c9fe3e9
--- /dev/null
+++ b/plat/amlogic/g12a/g12a_pm.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/console.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#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;
+}
diff --git a/plat/amlogic/g12a/include/platform_def.h b/plat/amlogic/g12a/include/platform_def.h
new file mode 100644
index 0000000..23d816d
--- /dev/null
+++ b/plat/amlogic/g12a/include/platform_def.h
@@ -0,0 +1,63 @@
+/*
+ * 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 <arch.h>
+#include <lib/utils_def.h>
+
+#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 */
diff --git a/plat/amlogic/g12a/platform.mk b/plat/amlogic/g12a/platform.mk
new file mode 100644
index 0000000..b0c91b0
--- /dev/null
+++ b/plat/amlogic/g12a/platform.mk
@@ -0,0 +1,91 @@
+#
+# 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
+
diff --git a/plat/amlogic/gxbb/gxbb_bl31_setup.c b/plat/amlogic/gxbb/gxbb_bl31_setup.c
new file mode 100644
index 0000000..cc7a1c4
--- /dev/null
+++ b/plat/amlogic/gxbb/gxbb_bl31_setup.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#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();
+}
diff --git a/plat/amlogic/gxbb/gxbb_common.c b/plat/amlogic/gxbb/gxbb_common.c
new file mode 100644
index 0000000..260a347
--- /dev/null
+++ b/plat/amlogic/gxbb/gxbb_common.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/ep_info.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <platform_def.h>
+#include <stdint.h>
+
+/*******************************************************************************
+ * 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;
+}
diff --git a/plat/amlogic/gxbb/gxbb_def.h b/plat/amlogic/gxbb/gxbb_def.h
new file mode 100644
index 0000000..fa5e4fa
--- /dev/null
+++ b/plat/amlogic/gxbb/gxbb_def.h
@@ -0,0 +1,123 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/*******************************************************************************
+ * 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 */
diff --git a/plat/amlogic/gxbb/gxbb_pm.c b/plat/amlogic/gxbb/gxbb_pm.c
new file mode 100644
index 0000000..48bff7b
--- /dev/null
+++ b/plat/amlogic/gxbb/gxbb_pm.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/console.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#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;
+}
diff --git a/plat/amlogic/gxbb/include/platform_def.h b/plat/amlogic/gxbb/include/platform_def.h
new file mode 100644
index 0000000..a5cbe78
--- /dev/null
+++ b/plat/amlogic/gxbb/include/platform_def.h
@@ -0,0 +1,66 @@
+/*
+ * 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 <arch.h>
+#include <lib/utils_def.h>
+
+#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 */
diff --git a/plat/amlogic/gxbb/platform.mk b/plat/amlogic/gxbb/platform.mk
new file mode 100644
index 0000000..62384d2
--- /dev/null
+++ b/plat/amlogic/gxbb/platform.mk
@@ -0,0 +1,75 @@
+#
+# 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
diff --git a/plat/amlogic/gxl/gxl_bl31_setup.c b/plat/amlogic/gxl/gxl_bl31_setup.c
new file mode 100644
index 0000000..f581dd1
--- /dev/null
+++ b/plat/amlogic/gxl/gxl_bl31_setup.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#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();
+}
diff --git a/plat/amlogic/gxl/gxl_common.c b/plat/amlogic/gxl/gxl_common.c
new file mode 100644
index 0000000..e1d7bfb
--- /dev/null
+++ b/plat/amlogic/gxl/gxl_common.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/ep_info.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <platform_def.h>
+#include <stdint.h>
+
+/*******************************************************************************
+ * 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;
+}
diff --git a/plat/amlogic/gxl/gxl_def.h b/plat/amlogic/gxl/gxl_def.h
new file mode 100644
index 0000000..f30eb28
--- /dev/null
+++ b/plat/amlogic/gxl/gxl_def.h
@@ -0,0 +1,133 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/*******************************************************************************
+ * 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 */
diff --git a/plat/amlogic/gxl/gxl_pm.c b/plat/amlogic/gxl/gxl_pm.c
new file mode 100644
index 0000000..433140b
--- /dev/null
+++ b/plat/amlogic/gxl/gxl_pm.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/console.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#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;
+}
diff --git a/plat/amlogic/gxl/include/platform_def.h b/plat/amlogic/gxl/include/platform_def.h
new file mode 100644
index 0000000..ec64d68
--- /dev/null
+++ b/plat/amlogic/gxl/include/platform_def.h
@@ -0,0 +1,63 @@
+/*
+ * 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 <arch.h>
+#include <lib/utils_def.h>
+
+#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 */
diff --git a/plat/amlogic/gxl/platform.mk b/plat/amlogic/gxl/platform.mk
new file mode 100644
index 0000000..641d177
--- /dev/null
+++ b/plat/amlogic/gxl/platform.mk
@@ -0,0 +1,91 @@
+#
+# 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
+
diff --git a/plat/arm/board/a5ds/a5ds_bl1_setup.c b/plat/arm/board/a5ds/a5ds_bl1_setup.c
new file mode 100644
index 0000000..629c928
--- /dev/null
+++ b/plat/arm/board/a5ds/a5ds_bl1_setup.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*******************************************************************************
+ * 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();
+}
diff --git a/plat/arm/board/a5ds/a5ds_bl2_setup.c b/plat/arm/board/a5ds/a5ds_bl2_setup.c
new file mode 100644
index 0000000..1979c50
--- /dev/null
+++ b/plat/arm/board/a5ds/a5ds_bl2_setup.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.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);
+}
+
+void bl2_platform_setup(void)
+{
+ arm_bl2_platform_setup();
+}
diff --git a/plat/arm/board/a5ds/a5ds_common.c b/plat/arm/board/a5ds/a5ds_common.c
new file mode 100644
index 0000000..a4a0cff
--- /dev/null
+++ b/plat/arm/board/a5ds/a5ds_common.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+
+#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_PERIPHBASE,
+ MAP_A5_PERIPHERALS,
+ MAP_BOOT_RW,
+ {0}
+};
+#endif
+#ifdef IMAGE_BL2
+const mmap_region_t plat_arm_mmap[] = {
+ ARM_MAP_SHARED_RAM,
+ MAP_PERIPHBASE,
+ MAP_A5_PERIPHERALS,
+ MAP_BOOT_RW,
+ 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;
+}
diff --git a/plat/arm/board/a5ds/a5ds_err.c b/plat/arm/board/a5ds/a5ds_err.c
new file mode 100644
index 0000000..feb9fdf
--- /dev/null
+++ b/plat/arm/board/a5ds/a5ds_err.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * a5ds error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+ while (true) {
+ wfi();
+ }
+}
diff --git a/plat/arm/board/a5ds/a5ds_pm.c b/plat/arm/board/a5ds/a5ds_pm.c
new file mode 100644
index 0000000..7774002
--- /dev/null
+++ b/plat/arm/board/a5ds/a5ds_pm.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * 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;
+}
diff --git a/plat/arm/board/a5ds/a5ds_private.h b/plat/arm/board/a5ds/a5ds_private.h
new file mode 100644
index 0000000..f577249
--- /dev/null
+++ b/plat/arm/board/a5ds/a5ds_private.h
@@ -0,0 +1,15 @@
+/*
+ * 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 */
diff --git a/plat/arm/board/a5ds/a5ds_security.c b/plat/arm/board/a5ds/a5ds_security.c
new file mode 100644
index 0000000..5593ae0
--- /dev/null
+++ b/plat/arm/board/a5ds/a5ds_security.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * 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.
+ */
+}
diff --git a/plat/arm/board/a5ds/a5ds_topology.c b/plat/arm/board/a5ds/a5ds_topology.c
new file mode 100644
index 0000000..94fa71f
--- /dev/null
+++ b/plat/arm/board/a5ds/a5ds_topology.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+/* 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));
+
+}
diff --git a/plat/arm/board/a5ds/aarch32/a5ds_helpers.S b/plat/arm/board/a5ds/aarch32/a5ds_helpers.S
new file mode 100644
index 0000000..ed7ad9c
--- /dev/null
+++ b/plat/arm/board/a5ds/aarch32/a5ds_helpers.S
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/arm/board/a5ds/fdts/a5ds_fw_config.dts b/plat/arm/board/a5ds/fdts/a5ds_fw_config.dts
new file mode 100644
index 0000000..b9ff8bf
--- /dev/null
+++ b/plat/arm/board/a5ds/fdts/a5ds_fw_config.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/tbbr/tbbr_img_def.h>
+
+/dts-v1/;
+
+/ {
+ dtb-registry {
+ compatible = "fconf,dyn_cfg-dtb_registry";
+
+ tb_fw-config {
+ load-address = <0x0 0x2001300>;
+ max-size = <0x200>;
+ id = <TB_FW_CONFIG_ID>;
+ };
+
+ hw-config {
+ load-address = <0x0 0x83000000>;
+ max-size = <0x01000000>;
+ id = <HW_CONFIG_ID>;
+ };
+ };
+};
diff --git a/plat/arm/board/a5ds/fdts/a5ds_tb_fw_config.dts b/plat/arm/board/a5ds/fdts/a5ds_tb_fw_config.dts
new file mode 100644
index 0000000..c66186f
--- /dev/null
+++ b/plat/arm/board/a5ds/fdts/a5ds_tb_fw_config.dts
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+ tb_fw-config {
+ compatible = "arm,tb_fw";
+
+ /* Disable authentication for development */
+ disable_auth = <0x0>;
+ };
+};
diff --git a/plat/arm/board/a5ds/include/platform_def.h b/plat/arm/board/a5ds/include/platform_def.h
new file mode 100644
index 0000000..9f3df1e
--- /dev/null
+++ b/plat/arm/board/a5ds/include/platform_def.h
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/common/smccc_def.h>
+#include <plat/common/common_def.h>
+
+/* 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 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 5
+
+#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 U(1)
+
+/* Default number of CPUs per cluster on A5DS */
+#define A5DS_MAX_CPUS_PER_CLUSTER U(4)
+
+/* Default number of threads per CPU on A5DS */
+#define A5DS_MAX_PE_PER_CPU U(1)
+
+#define A5DS_CORE_COUNT U(4)
+
+#define A5DS_PRIMARY_CPU 0x0
+
+#define BOOT_BASE ARM_DRAM1_BASE
+#define BOOT_SIZE UL(0x2800000)
+
+#define ARM_NS_DRAM1_BASE (ARM_DRAM1_BASE + BOOT_SIZE)
+/*
+ * The last 2MB is meant to be NOLOAD and will not be zero
+ * initialized.
+ */
+#define ARM_NS_DRAM1_SIZE (ARM_DRAM1_SIZE - \
+ BOOT_SIZE - \
+ 0x00200000)
+
+#define MAP_BOOT_RW MAP_REGION_FLAT( \
+ BOOT_BASE, \
+ BOOT_SIZE, \
+ MT_DEVICE | MT_RW | 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
+
+/*
+ * Map the region for device tree configuration with read and write permissions
+ */
+#define ARM_MAP_BL_CONFIG_REGION MAP_REGION_FLAT(ARM_BL_RAM_BASE, \
+ (ARM_FW_CONFIGS_LIMIT \
+ - ARM_BL_RAM_BASE), \
+ MT_MEMORY | 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 6
+
+#define MAX_MMAP_REGIONS (PLAT_ARM_MMAP_ENTRIES + \
+ ARM_BL_REGIONS)
+
+/* Memory mapped Generic timer interfaces */
+#define A5DS_TIMER_BASE_FREQUENCY UL(7500000)
+
+#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 FW_CONFIG to be loaded by BL1, define the corresponding base
+ * and limit. Leave enough space of BL2 meminfo.
+ */
+#define ARM_FW_CONFIG_BASE (ARM_BL_RAM_BASE + sizeof(meminfo_t))
+#define ARM_FW_CONFIG_LIMIT (ARM_BL_RAM_BASE + PAGE_SIZE)
+
+/*
+ * Define limit of firmware configuration memory:
+ * ARM_FW_CONFIG + ARM_BL2_MEM_DESC memory
+ */
+#define ARM_FW_CONFIGS_LIMIT (ARM_BL_RAM_BASE + (PAGE_SIZE * 2))
+
+/*******************************************************************************
+ * 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_FW_CONFIG_LIMIT
+#define ARM_BL2_MEM_DESC_LIMIT (ARM_BL2_MEM_DESC_BASE \
+ + (PAGE_SIZE / 2U))
+
+#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) + U(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_FLASH_IMAGE_BASE BOOT_BASE
+#define PLAT_ARM_FLASH_IMAGE_MAX_SIZE (BOOT_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+#define PLAT_ARM_NVM_BASE BOOT_BASE
+#define PLAT_ARM_NVM_SIZE (BOOT_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+/*
+ * PL011 related constants
+ */
+#define PLAT_ARM_BOOT_UART_BASE 0x1A200000
+#define PLAT_ARM_BOOT_UART_CLK_IN_HZ UL(7500000)
+
+#define PLAT_ARM_RUN_UART_BASE 0x1A210000
+#define PLAT_ARM_RUN_UART_CLK_IN_HZ UL(7500000)
+
+#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(7500000)
+
+/* 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
+
+/* Snoop Control Unit base address */
+#define A5DS_SCU_BASE 0x1C000000
+
+/*
+ * 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 */
diff --git a/plat/arm/board/a5ds/platform.mk b/plat/arm/board/a5ds/platform.mk
new file mode 100644
index 0000000..4f87306
--- /dev/null
+++ b/plat/arm/board/a5ds/platform.mk
@@ -0,0 +1,111 @@
+#
+# Copyright (c) 2019-2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Firmware Configuration Framework sources
+include common/fdt_wrappers.mk
+include lib/fconf/fconf.mk
+
+BL1_SOURCES += ${FCONF_SOURCES} ${FCONF_DYN_SOURCES}
+BL2_SOURCES += ${FCONF_SOURCES} ${FCONF_DYN_SOURCES}
+
+# 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
+
+DYN_CFG_SOURCES += ${FDT_WRAPPERS_SOURCES}
+
+# Include GICv2 driver files
+include drivers/arm/gic/v2/gicv2.mk
+
+A5DS_GIC_SOURCES := ${GICV2_SOURCES} \
+ 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/common/fconf/arm_fconf_io.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/fconf/arm_fconf_io.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
+
+FW_CONFIG := ${BUILD_PLAT}/fdts/a5ds_fw_config.dtb
+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,${TB_FW_CONFIG},--tb-fw-config,${TB_FW_CONFIG}))
+# Add the FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FW_CONFIG},--fw-config,${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,${FVP_HW_CONFIG}))
+
+FDT_SOURCES += plat/arm/board/a5ds/fdts/a5ds_fw_config.dts \
+ 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))
diff --git a/plat/arm/board/a5ds/sp_min/a5ds_sp_min_setup.c b/plat/arm/board/a5ds/sp_min/a5ds_sp_min_setup.c
new file mode 100644
index 0000000..a951dc7
--- /dev/null
+++ b/plat/arm/board/a5ds/sp_min/a5ds_sp_min_setup.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/scu.h>
+#include <plat/arm/common/plat_arm.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);
+
+ /* enable snoop control unit */
+ enable_snoop_ctrl_unit(A5DS_SCU_BASE);
+}
+
+/*
+ * A5DS will only have one always-on power domain and there
+ * is no power control present.
+ */
+void plat_arm_pwrc_setup(void)
+{
+}
+
diff --git a/plat/arm/board/a5ds/sp_min/sp_min-a5ds.mk b/plat/arm/board/a5ds/sp_min/sp_min-a5ds.mk
new file mode 100644
index 0000000..4b0c97d
--- /dev/null
+++ b/plat/arm/board/a5ds/sp_min/sp_min-a5ds.mk
@@ -0,0 +1,22 @@
+#
+# 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/arm/scu/scu.c \
+ 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}
diff --git a/plat/arm/board/arm_fpga/aarch64/fpga_helpers.S b/plat/arm/board/arm_fpga/aarch64/fpga_helpers.S
new file mode 100644
index 0000000..20120c9
--- /dev/null
+++ b/plat/arm/board/arm_fpga/aarch64/fpga_helpers.S
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include "../fpga_private.h"
+
+#include <platform_def.h>
+
+ .globl plat_get_my_entrypoint
+ .globl plat_secondary_cold_boot_setup
+ .globl plat_is_my_cpu_primary
+ .globl platform_mem_init
+ .globl plat_my_core_pos
+ .globl plat_crash_console_init
+ .globl plat_crash_console_putc
+ .globl plat_crash_console_flush
+ .globl plat_fpga_calc_core_pos
+
+/* -----------------------------------------------------------------------
+ * Indicate a cold boot for every CPU - warm boot is unsupported for the
+ * holding pen PSCI implementation.
+ * -----------------------------------------------------------------------
+ */
+func plat_get_my_entrypoint
+ mov x0, #0
+ ret
+endfunc plat_get_my_entrypoint
+
+/* -----------------------------------------------------------------------
+ * void plat_secondary_cold_boot_setup (void);
+ * -----------------------------------------------------------------------
+ */
+func plat_secondary_cold_boot_setup
+
+ /*
+ * Wait for the primary processor to initialise the .BSS segment
+ * to avoid a race condition that would erase fpga_valid_mpids
+ * if it is populated before the C runtime is ready.
+ *
+ * We cannot use the current spin-lock implementation until the
+ * runtime is up and we should not rely on sevl/wfe instructions as
+ * it is optional whether they are implemented or not, so we use
+ * a global variable as lock and wait for the primary processor to
+ * finish the C runtime bring-up.
+ */
+
+ ldr w0, =C_RUNTIME_READY_KEY
+ adrp x1, secondary_core_spinlock
+ add x1, x1, :lo12:secondary_core_spinlock
+1:
+ wfe
+ ldr w2, [x1]
+ cmp w2, w0
+ b.ne 1b
+ /* Prevent reordering of the store into fpga_valid_mpids below */
+ dmb ish
+
+ mov x10, x30
+ bl plat_my_core_pos
+ mov x30, x10
+
+ adrp x4, fpga_valid_mpids
+ add x4, x4, :lo12:fpga_valid_mpids
+ mov x5, #VALID_MPID
+ strb w5, [x4, x0]
+
+ /*
+ * Poll the CPU's hold entry until it indicates to jump
+ * to the entrypoint address.
+ */
+
+ adrp x1, hold_base
+ add x1, x1, :lo12:hold_base
+poll_hold_entry:
+ ldr x3, [x1, x0, LSL #PLAT_FPGA_HOLD_ENTRY_SHIFT]
+ cmp x3, #PLAT_FPGA_HOLD_STATE_GO
+ b.ne 1f
+
+ adrp x2, fpga_sec_entrypoint
+ add x2, x2, :lo12:fpga_sec_entrypoint
+ ldr x3, [x2]
+ br x3
+1:
+ wfe
+ b poll_hold_entry
+
+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
+ mrs x0, mpidr_el1
+ mov_imm x1, MPIDR_AFFINITY_MASK
+ and x0, x0, x1
+ cmp x0, #FPGA_PRIMARY_CPU
+ cset w0, eq
+ ret
+endfunc plat_is_my_cpu_primary
+
+func platform_mem_init
+ ret
+endfunc platform_mem_init
+
+func plat_my_core_pos
+ ldr x1, =(MPID_MASK & ~(MPIDR_AFFLVL_MASK << MPIDR_AFF3_SHIFT))
+ mrs x0, mpidr_el1
+ and x0, x0, x1
+ b plat_fpga_calc_core_pos
+
+endfunc plat_my_core_pos
+
+/* -----------------------------------------------------------------------
+ * unsigned int plat_fpga_calc_core_pos (uint32_t mpid)
+ * Clobber registers: x0 to x5
+ * -----------------------------------------------------------------------
+ */
+func plat_fpga_calc_core_pos
+ /*
+ * Check for MT bit in MPIDR, which may be either value for images
+ * running on the FPGA.
+ *
+ * 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
+
+ mov x4, #FPGA_MAX_CPUS_PER_CLUSTER
+ mov x5, #FPGA_MAX_PE_PER_CPU
+
+ /* Compute linear position */
+ madd x1, x2, x4, x1
+ madd x0, x1, x5, x0
+
+ ret
+endfunc plat_fpga_calc_core_pos
+
+func plat_crash_console_init
+ mov_imm x0, PLAT_FPGA_CRASH_UART_BASE
+ b console_pl011_core_init
+endfunc plat_crash_console_init
+
+func plat_crash_console_putc
+ mov_imm x1, PLAT_FPGA_CRASH_UART_BASE
+ b console_pl011_core_putc
+endfunc plat_crash_console_putc
+
+func plat_crash_console_flush
+ mov_imm x0, PLAT_FPGA_CRASH_UART_BASE
+ b console_pl011_core_flush
+endfunc plat_crash_console_flush
diff --git a/plat/arm/board/arm_fpga/build_axf.ld.S b/plat/arm/board/arm_fpga/build_axf.ld.S
new file mode 100644
index 0000000..d8254e5
--- /dev/null
+++ b/plat/arm/board/arm_fpga/build_axf.ld.S
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Linker script for the Arm Ltd. FPGA boards to generate an ELF file that
+ * contains the ROM trampoline, BL31 and the DTB.
+ *
+ * This allows to pass just one file to the uploader tool, and automatically
+ * provides the correct load addresses.
+ */
+
+#include <platform_def.h>
+
+OUTPUT_FORMAT("elf64-littleaarch64")
+OUTPUT_ARCH(aarch64)
+
+INPUT(./rom_trampoline.o)
+INPUT(./kernel_trampoline.o)
+
+TARGET(binary)
+INPUT(./bl31.bin)
+INPUT(./fdts/arm_fpga.dtb)
+
+ENTRY(_start)
+
+SECTIONS
+{
+ .rom (0x0): {
+ *rom_trampoline.o(.text*)
+ KEEP(*(.rom))
+ }
+
+ .bl31 (BL31_BASE): {
+ ASSERT(. == ALIGN(PAGE_SIZE), "BL31_BASE is not page aligned");
+ *bl31.bin
+ }
+
+ .dtb (FPGA_PRELOADED_DTB_BASE): {
+ ASSERT(. == ALIGN(8), "DTB address is not 8-byte aligned");
+ *arm_fpga.dtb
+ }
+
+ .kern_tramp (PRELOADED_BL33_BASE): {
+ *kernel_trampoline.o(.text*)
+ KEEP(*(.kern_tramp))
+ }
+
+ /DISCARD/ : { *(stacks) }
+ /DISCARD/ : { *(.debug_*) }
+ /DISCARD/ : { *(.note*) }
+ /DISCARD/ : { *(.comment*) }
+}
diff --git a/plat/arm/board/arm_fpga/fpga_bl31_setup.c b/plat/arm/board/arm_fpga/fpga_bl31_setup.c
new file mode 100644
index 0000000..e1b3abb
--- /dev/null
+++ b/plat/arm/board/arm_fpga/fpga_bl31_setup.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <common/fdt_fixup.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/delay_timer.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/extensions/spe.h>
+#include <lib/mmio.h>
+#include <libfdt.h>
+
+#include "fpga_private.h"
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+static entry_point_info_t bl33_image_ep_info;
+static unsigned int system_freq;
+volatile uint32_t secondary_core_spinlock;
+
+uintptr_t plat_get_ns_image_entrypoint(void)
+{
+#ifdef PRELOADED_BL33_BASE
+ return PRELOADED_BL33_BASE;
+#else
+ return 0ULL;
+#endif
+}
+
+uint32_t fpga_get_spsr_for_bl33_entry(void)
+{
+ return SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3)
+{
+ /* Add this core to the VALID mpids list */
+ fpga_valid_mpids[plat_my_core_pos()] = VALID_MPID;
+
+ /*
+ * Notify the secondary CPUs that the C runtime is ready
+ * so they can announce themselves.
+ */
+ secondary_core_spinlock = C_RUNTIME_READY_KEY;
+ dsbish();
+ sev();
+
+ fpga_console_init();
+
+ bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
+ bl33_image_ep_info.spsr = fpga_get_spsr_for_bl33_entry();
+ SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+ /* Set x0-x3 for the primary CPU as expected by the kernel */
+ bl33_image_ep_info.args.arg0 = (u_register_t)FPGA_PRELOADED_DTB_BASE;
+ bl33_image_ep_info.args.arg1 = 0U;
+ bl33_image_ep_info.args.arg2 = 0U;
+ bl33_image_ep_info.args.arg3 = 0U;
+}
+
+void bl31_plat_arch_setup(void)
+{
+}
+
+void bl31_platform_setup(void)
+{
+ /* Write frequency to CNTCRL and initialize timer */
+ generic_delay_timer_init();
+
+ /*
+ * Before doing anything else, wait for some time to ensure that
+ * the secondary CPUs have populated the fpga_valid_mpids array.
+ * As the number of secondary cores is unknown and can even be 0,
+ * it is not possible to rely on any signal from them, so use a
+ * delay instead.
+ */
+ mdelay(5);
+
+ /*
+ * On the event of a cold reset issued by, for instance, a reset pin
+ * assertion, we cannot guarantee memory to be initialized to zero.
+ * In such scenario, if the secondary cores reached
+ * plat_secondary_cold_boot_setup before the primary one initialized
+ * .BSS, we could end up having a race condition if the spinlock
+ * was not cleared before.
+ *
+ * Similarly, if there were a reset before the spinlock had been
+ * cleared, the secondary cores would find the lock opened before
+ * .BSS is cleared, causing another race condition.
+ *
+ * So clean the spinlock as soon as we think it is safe to reduce the
+ * chances of any race condition on a reset.
+ */
+ secondary_core_spinlock = 0UL;
+
+ /* Initialize the GIC driver, cpu and distributor interfaces */
+ plat_fpga_gic_init();
+}
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+ entry_point_info_t *next_image_info;
+ next_image_info = &bl33_image_ep_info;
+
+ /* Only expecting BL33: the kernel will run in EL2NS */
+ assert(type == NON_SECURE);
+
+ /* None of the images can have 0x0 as the entrypoint */
+ if (next_image_info->pc) {
+ return next_image_info;
+ } else {
+ return NULL;
+ }
+}
+
+/*
+ * Even though we sell the FPGA UART as an SBSA variant, it is actually
+ * a full fledged PL011. So the baudrate divider registers exist.
+ */
+#ifndef UARTIBRD
+#define UARTIBRD 0x024
+#define UARTFBRD 0x028
+#endif
+
+/* Round an integer to the closest multiple of a value. */
+static unsigned int round_multiple(unsigned int x, unsigned int multiple)
+{
+ if (multiple < 2) {
+ return x;
+ }
+
+ return ((x + (multiple / 2 - 1)) / multiple) * multiple;
+}
+
+#define PL011_FRAC_SHIFT 6
+#define FPGA_DEFAULT_BAUDRATE 38400
+#define PL011_OVERSAMPLING 16
+static unsigned int pl011_freq_from_divider(unsigned int divider)
+{
+ unsigned int freq;
+
+ freq = divider * FPGA_DEFAULT_BAUDRATE * PL011_OVERSAMPLING;
+
+ return freq >> PL011_FRAC_SHIFT;
+}
+
+/*
+ * The FPGAs run most peripherals from one main clock, among them the CPUs,
+ * the arch timer, and the UART baud base clock.
+ * The SCP knows this frequency and programs the UART clock divider for a
+ * 38400 bps baudrate. Recalculate the base input clock from there.
+ */
+static unsigned int fpga_get_system_frequency(void)
+{
+ const void *fdt = (void *)(uintptr_t)FPGA_PRELOADED_DTB_BASE;
+ int node, err;
+
+ /*
+ * If the arch timer DT node has an explicit clock-frequency property
+ * set, use that, to allow people overriding auto-detection.
+ */
+ node = fdt_node_offset_by_compatible(fdt, 0, "arm,armv8-timer");
+ if (node >= 0) {
+ uint32_t freq;
+
+ err = fdt_read_uint32(fdt, node, "clock-frequency", &freq);
+ if (err >= 0) {
+ return freq;
+ }
+ }
+
+ node = fdt_node_offset_by_compatible(fdt, 0, "arm,pl011");
+ if (node >= 0) {
+ uintptr_t pl011_base;
+ unsigned int divider;
+
+ err = fdt_get_reg_props_by_index(fdt, node, 0,
+ &pl011_base, NULL);
+ if (err >= 0) {
+ divider = mmio_read_32(pl011_base + UARTIBRD);
+ divider <<= PL011_FRAC_SHIFT;
+ divider += mmio_read_32(pl011_base + UARTFBRD);
+
+ /*
+ * The result won't be exact, due to rounding errors,
+ * but the input frequency was a multiple of 250 KHz.
+ */
+ return round_multiple(pl011_freq_from_divider(divider),
+ 250000);
+ } else {
+ WARN("Cannot read PL011 MMIO base\n");
+ }
+ } else {
+ WARN("No PL011 DT node\n");
+ }
+
+ /* No PL011 DT node or calculation failed. */
+ return FPGA_DEFAULT_TIMER_FREQUENCY;
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+ if (system_freq == 0U) {
+ system_freq = fpga_get_system_frequency();
+ }
+
+ return system_freq;
+}
+
+static void fpga_dtb_update_clock(void *fdt, unsigned int freq)
+{
+ uint32_t freq_dtb = fdt32_to_cpu(freq);
+ uint32_t phandle;
+ int node, err;
+
+ node = fdt_node_offset_by_compatible(fdt, 0, "arm,pl011");
+ if (node < 0) {
+ WARN("%s(): No PL011 DT node found\n", __func__);
+
+ return;
+ }
+
+ err = fdt_read_uint32(fdt, node, "clocks", &phandle);
+ if (err != 0) {
+ WARN("Cannot find clocks property\n");
+
+ return;
+ }
+
+ node = fdt_node_offset_by_phandle(fdt, phandle);
+ if (node < 0) {
+ WARN("Cannot get phandle\n");
+
+ return;
+ }
+
+ err = fdt_setprop_inplace(fdt, node,
+ "clock-frequency",
+ &freq_dtb,
+ sizeof(freq_dtb));
+ if (err < 0) {
+ WARN("Could not update DT baud clock frequency\n");
+
+ return;
+ }
+}
+
+#define CMDLINE_SIGNATURE "CMD:"
+
+static int fpga_dtb_set_commandline(void *fdt, const char *cmdline)
+{
+ int chosen;
+ const char *eol;
+ char nul = 0;
+ int slen, err;
+
+ chosen = fdt_add_subnode(fdt, 0, "chosen");
+ if (chosen == -FDT_ERR_EXISTS) {
+ chosen = fdt_path_offset(fdt, "/chosen");
+ }
+
+ if (chosen < 0) {
+ return chosen;
+ }
+
+ /*
+ * There is most likely an EOL at the end of the
+ * command line, make sure we terminate the line there.
+ * We can't replace the EOL with a NUL byte in the
+ * source, as this is in read-only memory. So we first
+ * create the property without any termination, then
+ * append a single NUL byte.
+ */
+ eol = strchr(cmdline, '\n');
+ if (eol == NULL) {
+ eol = strchr(cmdline, 0);
+ }
+ /* Skip the signature and omit the EOL/NUL byte. */
+ slen = eol - (cmdline + strlen(CMDLINE_SIGNATURE));
+ /*
+ * Let's limit the size of the property, just in case
+ * we find the signature by accident. The Linux kernel
+ * limits to 4096 characters at most (in fact 2048 for
+ * arm64), so that sounds like a reasonable number.
+ */
+ if (slen > 4095) {
+ slen = 4095;
+ }
+
+ err = fdt_setprop(fdt, chosen, "bootargs",
+ cmdline + strlen(CMDLINE_SIGNATURE), slen);
+ if (err != 0) {
+ return err;
+ }
+
+ return fdt_appendprop(fdt, chosen, "bootargs", &nul, 1);
+}
+
+static void fpga_prepare_dtb(void)
+{
+ void *fdt = (void *)(uintptr_t)FPGA_PRELOADED_DTB_BASE;
+ const char *cmdline = (void *)(uintptr_t)FPGA_PRELOADED_CMD_LINE;
+ int err;
+
+ err = fdt_open_into(fdt, fdt, FPGA_MAX_DTB_SIZE);
+ if (err < 0) {
+ ERROR("cannot open devicetree at %p: %d\n", fdt, err);
+ panic();
+ }
+
+ /* Reserve memory used by Trusted Firmware. */
+ if (fdt_add_reserved_memory(fdt, "tf-a@80000000", BL31_BASE,
+ BL31_LIMIT - BL31_BASE)) {
+ WARN("Failed to add reserved memory node to DT\n");
+ }
+
+ /* Check for the command line signature. */
+ if (!strncmp(cmdline, CMDLINE_SIGNATURE, strlen(CMDLINE_SIGNATURE))) {
+ err = fpga_dtb_set_commandline(fdt, cmdline);
+ if (err == 0) {
+ INFO("using command line at 0x%x\n",
+ FPGA_PRELOADED_CMD_LINE);
+ } else {
+ ERROR("failed to put command line into DTB: %d\n", err);
+ }
+ }
+
+ if (err < 0) {
+ ERROR("Error %d extending Device Tree\n", err);
+ panic();
+ }
+
+ err = fdt_add_cpus_node(fdt, FPGA_MAX_PE_PER_CPU,
+ FPGA_MAX_CPUS_PER_CLUSTER,
+ FPGA_MAX_CLUSTER_COUNT);
+
+ if (err == -EEXIST) {
+ WARN("Not overwriting already existing /cpus node in DTB\n");
+ } else {
+ if (err < 0) {
+ ERROR("Error %d creating the /cpus DT node\n", err);
+ panic();
+ } else {
+ unsigned int nr_cores = fpga_get_nr_gic_cores();
+
+ INFO("Adjusting GICR DT region to cover %u cores\n",
+ nr_cores);
+ err = fdt_adjust_gic_redist(fdt, nr_cores,
+ fpga_get_redist_base(),
+ fpga_get_redist_size());
+ if (err < 0) {
+ ERROR("Error %d fixing up GIC DT node\n", err);
+ }
+ }
+ }
+
+ fpga_dtb_update_clock(fdt, system_freq);
+
+ /* Check whether we support the SPE PMU. Remove the DT node if not. */
+ if (!spe_supported()) {
+ int node = fdt_node_offset_by_compatible(fdt, 0,
+ "arm,statistical-profiling-extension-v1");
+
+ if (node >= 0) {
+ fdt_del_node(fdt, node);
+ }
+ }
+
+ /* Check whether we have an ITS. Remove the DT node if not. */
+ if (!fpga_has_its()) {
+ int node = fdt_node_offset_by_compatible(fdt, 0,
+ "arm,gic-v3-its");
+
+ if (node >= 0) {
+ fdt_del_node(fdt, node);
+ }
+ }
+
+ err = fdt_pack(fdt);
+ if (err < 0) {
+ ERROR("Failed to pack Device Tree at %p: error %d\n", fdt, err);
+ }
+
+ clean_dcache_range((uintptr_t)fdt, fdt_blob_size(fdt));
+}
+
+void bl31_plat_runtime_setup(void)
+{
+ fpga_prepare_dtb();
+}
+
+void bl31_plat_enable_mmu(uint32_t flags)
+{
+ /* TODO: determine if MMU needs to be enabled */
+}
diff --git a/plat/arm/board/arm_fpga/fpga_console.c b/plat/arm/board/arm_fpga/fpga_console.c
new file mode 100644
index 0000000..8c1da62
--- /dev/null
+++ b/plat/arm/board/arm_fpga/fpga_console.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <common/fdt_wrappers.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+
+#include <platform_def.h>
+
+static console_t console;
+
+void fpga_console_init(void)
+{
+ const void *fdt = (void *)(uintptr_t)FPGA_PRELOADED_DTB_BASE;
+ uintptr_t base_addr = PLAT_FPGA_CRASH_UART_BASE;
+ int node;
+
+ /*
+ * Try to read the UART base address from the DT, by chasing the
+ * stdout-path property of the chosen node.
+ * If this does not work, use the crash console address as a fallback.
+ */
+ node = fdt_get_stdout_node_offset(fdt);
+ if (node >= 0) {
+ fdt_get_reg_props_by_index(fdt, node, 0, &base_addr, NULL);
+ }
+
+ (void)console_pl011_register(base_addr, 0, 0, &console);
+
+ console_set_scope(&console, CONSOLE_FLAG_BOOT |
+ CONSOLE_FLAG_RUNTIME);
+}
diff --git a/plat/arm/board/arm_fpga/fpga_def.h b/plat/arm/board/arm_fpga/fpga_def.h
new file mode 100644
index 0000000..2884ea6
--- /dev/null
+++ b/plat/arm/board/arm_fpga/fpga_def.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/utils_def.h>
+
+#ifndef FPGA_DEF_H
+#define FPGA_DEF_H
+
+/*
+ * These are set to large values to account for images describing systems with
+ * larger cluster configurations.
+ *
+ * For cases where the number of clusters, cores or threads is smaller than a
+ * maximum value below, this does not affect the PSCI functionality as any PEs
+ * that are present will still be indexed appropriately regardless of any empty
+ * entries in the array used to represent the topology.
+ */
+
+#define FPGA_MAX_CLUSTER_COUNT 4
+#define FPGA_MAX_CPUS_PER_CLUSTER 8
+#define FPGA_MAX_PE_PER_CPU 4
+
+#define FPGA_PRIMARY_CPU 0x0
+/*******************************************************************************
+ * FPGA image memory map related constants
+ ******************************************************************************/
+
+/*
+ * UART base address, just for the crash console, as a fallback.
+ * The actual console UART address is taken from the DT.
+ */
+#define PLAT_FPGA_CRASH_UART_BASE 0x7ff80000
+
+#define FPGA_DEFAULT_TIMER_FREQUENCY 10000000
+
+#endif
diff --git a/plat/arm/board/arm_fpga/fpga_gicv3.c b/plat/arm/board/arm_fpga/fpga_gicv3.c
new file mode 100644
index 0000000..e06a9da
--- /dev/null
+++ b/plat/arm/board/arm_fpga/fpga_gicv3.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/arm/arm_gicv3_common.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/mmio.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+static const interrupt_prop_t fpga_interrupt_props[] = {
+ PLATFORM_G1S_PROPS(INTR_GROUP1S),
+ PLATFORM_G0_PROPS(INTR_GROUP0)
+};
+
+static uintptr_t fpga_rdistif_base_addrs[PLATFORM_CORE_COUNT];
+static int nr_itses;
+
+static unsigned int fpga_mpidr_to_core_pos(unsigned long mpidr)
+{
+ return (unsigned int)plat_core_pos_by_mpidr(mpidr);
+}
+
+static gicv3_driver_data_t fpga_gicv3_driver_data = {
+ .interrupt_props = fpga_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(fpga_interrupt_props),
+ .rdistif_num = PLATFORM_CORE_COUNT,
+ .rdistif_base_addrs = fpga_rdistif_base_addrs,
+ .mpidr_to_core_pos = fpga_mpidr_to_core_pos
+};
+
+void plat_fpga_gic_init(void)
+{
+ const void *fdt = (void *)(uintptr_t)FPGA_PRELOADED_DTB_BASE;
+ uintptr_t gicr_base = 0U;
+ uint32_t iidr;
+ int node, ret;
+
+ node = fdt_node_offset_by_compatible(fdt, 0, "arm,gic-v3");
+ if (node < 0) {
+ WARN("No \"arm,gic-v3\" compatible node found in DT, no GIC support.\n");
+ return;
+ }
+
+ /* TODO: Assuming only empty "ranges;" properties up the bus path. */
+ ret = fdt_get_reg_props_by_index(fdt, node, 0,
+ &fpga_gicv3_driver_data.gicd_base, NULL);
+ if (ret < 0) {
+ WARN("Could not read GIC distributor address from DT.\n");
+ return;
+ }
+
+ iidr = mmio_read_32(fpga_gicv3_driver_data.gicd_base + GICD_IIDR);
+ if (((iidr & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600) ||
+ ((iidr & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_700)) {
+ unsigned int frame_id;
+
+ /*
+ * According to the GIC TRMs, if there are any ITSes, they
+ * start four 64K pages after the distributor. After all
+ * the ITSes then follow the redistributors.
+ */
+ gicr_base = fpga_gicv3_driver_data.gicd_base + (4U << 16);
+
+ do {
+ uint64_t its_typer;
+
+ /* Each GIC component can be identified by its ID. */
+ frame_id = gicv3_get_component_partnum(gicr_base);
+
+ if (frame_id == PIDR_COMPONENT_ARM_REDIST) {
+ INFO("Found %d ITSes, redistributors start at 0x%llx\n",
+ nr_itses, (unsigned long long)gicr_base);
+ break;
+ }
+
+ if (frame_id != PIDR_COMPONENT_ARM_ITS) {
+ WARN("GICv3: found unexpected frame 0x%x\n",
+ frame_id);
+ gicr_base = 0U;
+ break;
+ }
+
+ /*
+ * Found an ITS, now work out if it supports virtual
+ * SGIs (for direct guest injection). If yes, each
+ * ITS occupies four 64K pages, otherwise just two.
+ */
+ its_typer = mmio_read_64(gicr_base + GITS_TYPER);
+ if ((its_typer & GITS_TYPER_VSGI) != 0U) {
+ gicr_base += 4U << 16;
+ } else {
+ gicr_base += 2U << 16;
+ }
+ nr_itses++;
+ } while (true);
+ }
+
+ /*
+ * If this is not a GIC-600 or -700, or the autodetection above failed,
+ * use the base address from the device tree.
+ */
+ if (gicr_base == 0U) {
+ ret = fdt_get_reg_props_by_index(fdt, node, 1,
+ &fpga_gicv3_driver_data.gicr_base,
+ NULL);
+ if (ret < 0) {
+ WARN("Could not read GIC redistributor address from DT.\n");
+ return;
+ }
+ } else {
+ fpga_gicv3_driver_data.gicr_base = gicr_base;
+ }
+
+ gicv3_driver_init(&fpga_gicv3_driver_data);
+ gicv3_distif_init();
+ gicv3_rdistif_init(plat_my_core_pos());
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void fpga_pwr_gic_on_finish(void)
+{
+ gicv3_rdistif_init(plat_my_core_pos());
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void fpga_pwr_gic_off(void)
+{
+ gicv3_cpuif_disable(plat_my_core_pos());
+ gicv3_rdistif_off(plat_my_core_pos());
+}
+
+unsigned int fpga_get_nr_gic_cores(void)
+{
+ return gicv3_rdistif_get_number_frames(fpga_gicv3_driver_data.gicr_base);
+}
+
+uintptr_t fpga_get_redist_size(void)
+{
+ uint64_t typer_val = mmio_read_64(fpga_gicv3_driver_data.gicr_base +
+ GICR_TYPER);
+
+ return gicv3_redist_size(typer_val);
+}
+
+uintptr_t fpga_get_redist_base(void)
+{
+ return fpga_gicv3_driver_data.gicr_base;
+}
+
+bool fpga_has_its(void)
+{
+ return nr_itses > 0;
+}
diff --git a/plat/arm/board/arm_fpga/fpga_pm.c b/plat/arm/board/arm_fpga/fpga_pm.c
new file mode 100644
index 0000000..a306a23
--- /dev/null
+++ b/plat/arm/board/arm_fpga/fpga_pm.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#include "fpga_private.h"
+#include <platform_def.h>
+
+/*
+ * This is a basic PSCI implementation that allows secondary CPUs to be
+ * released from their initial state and continue to the warm boot entrypoint.
+ *
+ * The secondary CPUs are placed in a holding pen and released by calls
+ * to fpga_pwr_domain_on(mpidr), which updates the hold entry for the CPU
+ * specified by the mpidr argument - the (polling) target CPU will then branch
+ * to the BL31 warm boot sequence at the entrypoint address.
+ *
+ * Additionally, the secondary CPUs are kept in a low-power wfe() state
+ * (placed there at the end of each poll) and woken when necessary through
+ * calls to sev() in fpga_pwr_domain_on(mpidr), once the hold state for the
+ * relevant CPU has been updated.
+ *
+ * Hotplug is currently implemented using a wfi-loop, which removes the
+ * dependencies on any power controllers or other mechanism that is specific
+ * to the running system as specified by the FPGA image.
+ */
+
+uint64_t hold_base[PLATFORM_CORE_COUNT];
+uintptr_t fpga_sec_entrypoint;
+
+/*
+ * Calls to the CPU specified by the mpidr will set its hold entry to a value
+ * indicating that it should stop polling and branch off to the warm entrypoint.
+ */
+static int fpga_pwr_domain_on(u_register_t mpidr)
+{
+ int pos = plat_core_pos_by_mpidr(mpidr);
+ unsigned long current_mpidr = read_mpidr_el1();
+
+ if (pos < 0) {
+ panic();
+ }
+
+ if (mpidr == current_mpidr) {
+ return PSCI_E_ALREADY_ON;
+ }
+ hold_base[pos] = PLAT_FPGA_HOLD_STATE_GO;
+ flush_dcache_range((uintptr_t)&hold_base[pos], sizeof(uint64_t));
+ sev(); /* Wake any CPUs from wfe */
+
+ return PSCI_E_SUCCESS;
+}
+
+void fpga_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ fpga_pwr_gic_on_finish();
+}
+
+static void fpga_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ fpga_pwr_gic_off();
+
+ while (1) {
+ wfi();
+ }
+}
+
+static void fpga_cpu_standby(plat_local_state_t cpu_state)
+{
+ /*
+ * Enter standby state
+ * dsb is good practice before using wfi to enter low power states
+ */
+ u_register_t scr = read_scr_el3();
+ write_scr_el3(scr|SCR_IRQ_BIT);
+ dsb();
+ wfi();
+ write_scr_el3(scr);
+}
+
+plat_psci_ops_t plat_fpga_psci_pm_ops = {
+ .pwr_domain_on = fpga_pwr_domain_on,
+ .pwr_domain_on_finish = fpga_pwr_domain_on_finish,
+ .pwr_domain_off = fpga_pwr_domain_off,
+ .cpu_standby = fpga_cpu_standby
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const plat_psci_ops_t **psci_ops)
+{
+ fpga_sec_entrypoint = sec_entrypoint;
+ flush_dcache_range((uint64_t)&fpga_sec_entrypoint,
+ sizeof(fpga_sec_entrypoint));
+ *psci_ops = &plat_fpga_psci_pm_ops;
+ return 0;
+}
diff --git a/plat/arm/board/arm_fpga/fpga_private.h b/plat/arm/board/arm_fpga/fpga_private.h
new file mode 100644
index 0000000..84d651c
--- /dev/null
+++ b/plat/arm/board/arm_fpga/fpga_private.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FPGA_PRIVATE_H
+#define FPGA_PRIVATE_H
+
+#include "../fpga_def.h"
+#include <platform_def.h>
+
+#define C_RUNTIME_READY_KEY (0xaa55aa55)
+#define VALID_MPID (1U)
+#define FPGA_MAX_DTB_SIZE 0x10000
+
+#ifndef __ASSEMBLER__
+
+extern unsigned char fpga_valid_mpids[PLATFORM_CORE_COUNT];
+
+void fpga_console_init(void);
+
+void plat_fpga_gic_init(void);
+void fpga_pwr_gic_on_finish(void);
+void fpga_pwr_gic_off(void);
+unsigned int plat_fpga_calc_core_pos(uint32_t mpid);
+unsigned int fpga_get_nr_gic_cores(void);
+uintptr_t fpga_get_redist_size(void);
+uintptr_t fpga_get_redist_base(void);
+bool fpga_has_its(void);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* FPGA_PRIVATE_H */
diff --git a/plat/arm/board/arm_fpga/fpga_topology.c b/plat/arm/board/arm_fpga/fpga_topology.c
new file mode 100644
index 0000000..7fead86
--- /dev/null
+++ b/plat/arm/board/arm_fpga/fpga_topology.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/spinlock.h>
+
+#include "fpga_private.h"
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+unsigned char fpga_power_domain_tree_desc[FPGA_MAX_CLUSTER_COUNT + 2];
+unsigned char fpga_valid_mpids[PLATFORM_CORE_COUNT];
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ unsigned int i;
+
+ /*
+ * The highest level is the system level. The next level is constituted
+ * by clusters and then cores in clusters.
+ *
+ * This description of the power domain topology is aligned with the CPU
+ * indices returned by the plat_core_pos_by_mpidr() and plat_my_core_pos()
+ * APIs.
+ *
+ * A description of the topology tree can be found at
+ * https://trustedfirmware-a.readthedocs.io/en/latest/design/psci-pd-tree.html#design
+ */
+
+ if (fpga_power_domain_tree_desc[0] == 0U) {
+ /*
+ * As fpga_power_domain_tree_desc[0] == 0, assume that the
+ * Power Domain Topology Tree has not been initialized, so
+ * perform the initialization here.
+ */
+
+ fpga_power_domain_tree_desc[0] = 1U;
+ fpga_power_domain_tree_desc[1] = FPGA_MAX_CLUSTER_COUNT;
+
+ for (i = 0U; i < FPGA_MAX_CLUSTER_COUNT; i++) {
+ fpga_power_domain_tree_desc[2 + i] =
+ (FPGA_MAX_CPUS_PER_CLUSTER *
+ FPGA_MAX_PE_PER_CPU);
+ }
+ }
+
+ return fpga_power_domain_tree_desc;
+}
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+ unsigned int core_pos;
+
+ mpidr &= (MPID_MASK & ~(MPIDR_AFFLVL_MASK << MPIDR_AFF3_SHIFT));
+ mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK);
+
+ if ((MPIDR_AFFLVL2_VAL(mpidr) >= FPGA_MAX_CLUSTER_COUNT) ||
+ (MPIDR_AFFLVL1_VAL(mpidr) >= FPGA_MAX_CPUS_PER_CLUSTER) ||
+ (MPIDR_AFFLVL0_VAL(mpidr) >= FPGA_MAX_PE_PER_CPU)) {
+ ERROR ("Invalid mpidr: 0x%08x\n", (uint32_t)mpidr);
+ panic();
+ }
+
+ /* Calculate the core position, based on the maximum topology. */
+ core_pos = plat_fpga_calc_core_pos(mpidr);
+
+ /* Check whether this core is actually present. */
+ if (fpga_valid_mpids[core_pos] != VALID_MPID) {
+ return -1;
+ }
+
+ return core_pos;
+}
diff --git a/plat/arm/board/arm_fpga/include/plat_macros.S b/plat/arm/board/arm_fpga/include/plat_macros.S
new file mode 100644
index 0000000..44cddeb
--- /dev/null
+++ b/plat/arm/board/arm_fpga/include/plat_macros.S
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2020, 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
diff --git a/plat/arm/board/arm_fpga/include/platform_def.h b/plat/arm/board/arm_fpga/include/platform_def.h
new file mode 100644
index 0000000..2350d87
--- /dev/null
+++ b/plat/arm/board/arm_fpga/include/platform_def.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <plat/common/common_def.h>
+#include <platform_def.h>
+#include "../fpga_def.h"
+
+#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64"
+
+#define PLATFORM_LINKER_ARCH aarch64
+
+#define PLATFORM_STACK_SIZE UL(0x800)
+
+#define CACHE_WRITEBACK_SHIFT U(6)
+#define CACHE_WRITEBACK_GRANULE (U(1) << CACHE_WRITEBACK_SHIFT)
+
+#define PLATFORM_CORE_COUNT \
+ (FPGA_MAX_CLUSTER_COUNT * \
+ FPGA_MAX_CPUS_PER_CLUSTER * \
+ FPGA_MAX_PE_PER_CPU)
+
+#define PLAT_NUM_PWR_DOMAINS (FPGA_MAX_CLUSTER_COUNT + PLATFORM_CORE_COUNT + 1)
+
+#if !ENABLE_PIE
+#define BL31_BASE UL(0x80000000)
+#define BL31_LIMIT UL(0x80070000)
+#else
+#define BL31_BASE UL(0x0)
+#define BL31_LIMIT UL(0x01000000)
+#endif
+
+#define PLAT_SDEI_NORMAL_PRI 0x70
+
+#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 PLATFORM_G1S_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 PLATFORM_G0_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 PLAT_MAX_RET_STATE 1
+#define PLAT_MAX_OFF_STATE 2
+
+#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2
+
+#define PLAT_FPGA_HOLD_ENTRY_SHIFT 3
+#define PLAT_FPGA_HOLD_STATE_WAIT 0
+#define PLAT_FPGA_HOLD_STATE_GO 1
+
+#endif
diff --git a/plat/arm/board/arm_fpga/kernel_trampoline.S b/plat/arm/board/arm_fpga/kernel_trampoline.S
new file mode 100644
index 0000000..f4c08ef
--- /dev/null
+++ b/plat/arm/board/arm_fpga/kernel_trampoline.S
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2021, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * The traditional arm64 Linux kernel load address is 512KiB from the
+ * beginning of DRAM, caused by this having been the default value of the
+ * kernel's CONFIG_TEXT_OFFSET Kconfig value.
+ * However kernel version 5.8 changed the default offset (into a 2MB page)
+ * to 0, so TF-A's default assumption is no longer true. Fortunately the
+ * kernel got more relaxed about this offset at the same time, so it
+ * tolerates the wrong offset, but issues a warning:
+ * [Firmware Bug]: Kernel image misaligned at boot, please fix your bootloader!
+ *
+ * We cannot easily change the load address offset in TF-A to be 2MiB, because
+ * this would break older kernels - and they are not as forgiving in this
+ * respect.
+ *
+ * But we can allow users to load the kernel at the right offset, and
+ * offer this trampoline here to transition to this new load address.
+ * Any older kernels, or newer kernels misloaded, will overwrite this code
+ * here, so it does no harm in this case.
+ */
+
+#include <asm_macros.S>
+#include <common/bl_common.ld.h>
+
+.text
+.global _tramp_start
+
+_tramp_start:
+ adr x4, _tramp_start
+ orr x4, x4, #0x1fffff
+ add x4, x4, #1 /* align up to 2MB */
+ br x4
diff --git a/plat/arm/board/arm_fpga/platform.mk b/plat/arm/board/arm_fpga/platform.mk
new file mode 100644
index 0000000..a14a0d8
--- /dev/null
+++ b/plat/arm/board/arm_fpga/platform.mk
@@ -0,0 +1,130 @@
+#
+# Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include common/fdt_wrappers.mk
+include lib/libfdt/libfdt.mk
+
+RESET_TO_BL31 := 1
+ifeq (${RESET_TO_BL31}, 0)
+$(error "This is a BL31-only port; RESET_TO_BL31 must be enabled")
+endif
+
+ifeq (${ENABLE_PIE}, 1)
+override SEPARATE_CODE_AND_RODATA := 1
+endif
+
+CTX_INCLUDE_AARCH32_REGS := 0
+ifeq (${CTX_INCLUDE_AARCH32_REGS}, 1)
+$(error "This is an AArch64-only port; CTX_INCLUDE_AARCH32_REGS must be disabled")
+endif
+
+ifeq (${TRUSTED_BOARD_BOOT}, 1)
+$(error "TRUSTED_BOARD_BOOT must be disabled")
+endif
+
+PRELOADED_BL33_BASE := 0x80080000
+
+FPGA_PRELOADED_DTB_BASE := 0x80070000
+$(eval $(call add_define,FPGA_PRELOADED_DTB_BASE))
+
+FPGA_PRELOADED_CMD_LINE := 0x1000
+$(eval $(call add_define,FPGA_PRELOADED_CMD_LINE))
+
+ENABLE_AMU := 1
+
+# Treating this as a memory-constrained port for now
+USE_COHERENT_MEM := 0
+
+# This can be overridden depending on CPU(s) used in the FPGA image
+HW_ASSISTED_COHERENCY := 1
+
+PL011_GENERIC_UART := 1
+
+SUPPORT_UNKNOWN_MPID ?= 1
+
+FPGA_CPU_LIBS := lib/cpus/${ARCH}/aem_generic.S
+
+# 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
+ FPGA_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
+# AArch64-only cores
+ FPGA_CPU_LIBS += lib/cpus/aarch64/cortex_a76.S \
+ lib/cpus/aarch64/cortex_a76ae.S \
+ lib/cpus/aarch64/cortex_a77.S \
+ lib/cpus/aarch64/cortex_a78.S \
+ lib/cpus/aarch64/neoverse_n_common.S \
+ lib/cpus/aarch64/neoverse_n1.S \
+ lib/cpus/aarch64/neoverse_n2.S \
+ lib/cpus/aarch64/neoverse_e1.S \
+ lib/cpus/aarch64/neoverse_v1.S \
+ lib/cpus/aarch64/cortex_a78_ae.S \
+ lib/cpus/aarch64/cortex_a65.S \
+ lib/cpus/aarch64/cortex_a65ae.S \
+ lib/cpus/aarch64/cortex_a510.S \
+ lib/cpus/aarch64/cortex_a710.S \
+ lib/cpus/aarch64/cortex_a715.S \
+ lib/cpus/aarch64/cortex_x3.S \
+ lib/cpus/aarch64/cortex_a78c.S
+
+# AArch64/AArch32 cores
+ FPGA_CPU_LIBS += lib/cpus/aarch64/cortex_a55.S \
+ lib/cpus/aarch64/cortex_a75.S
+endif
+
+ifeq (${SUPPORT_UNKNOWN_MPID}, 1)
+# Add support for unknown/invalid MPIDs (aarch64 only)
+$(eval $(call add_define,SUPPORT_UNKNOWN_MPID))
+ FPGA_CPU_LIBS += lib/cpus/aarch64/generic.S
+endif
+
+# Allow detection of GIC-600
+GICV3_SUPPORT_GIC600 := 1
+
+GIC_ENABLE_V4_EXTN := 1
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+FPGA_GIC_SOURCES := ${GICV3_SOURCES} \
+ plat/common/plat_gicv3.c \
+ plat/arm/board/arm_fpga/fpga_gicv3.c
+
+FDT_SOURCES := fdts/arm_fpga.dts
+
+PLAT_INCLUDES := -Iplat/arm/board/arm_fpga/include
+
+PLAT_BL_COMMON_SOURCES := plat/arm/board/arm_fpga/${ARCH}/fpga_helpers.S
+
+BL31_SOURCES += common/fdt_fixup.c \
+ drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ drivers/arm/pl011/${ARCH}/pl011_console.S \
+ plat/common/plat_psci_common.c \
+ plat/arm/board/arm_fpga/fpga_pm.c \
+ plat/arm/board/arm_fpga/fpga_topology.c \
+ plat/arm/board/arm_fpga/fpga_console.c \
+ plat/arm/board/arm_fpga/fpga_bl31_setup.c \
+ ${FPGA_CPU_LIBS} \
+ ${FPGA_GIC_SOURCES}
+
+BL31_SOURCES += ${FDT_WRAPPERS_SOURCES}
+
+$(eval $(call MAKE_S,$(BUILD_PLAT),plat/arm/board/arm_fpga/rom_trampoline.S,bl31))
+$(eval $(call MAKE_S,$(BUILD_PLAT),plat/arm/board/arm_fpga/kernel_trampoline.S,bl31))
+$(eval $(call MAKE_LD,$(BUILD_PLAT)/build_axf.ld,plat/arm/board/arm_fpga/build_axf.ld.S,bl31))
+
+bl31.axf: bl31 dtbs ${BUILD_PLAT}/rom_trampoline.o ${BUILD_PLAT}/kernel_trampoline.o ${BUILD_PLAT}/build_axf.ld
+ $(ECHO) " LD $@"
+ $(Q)$(LD) -T ${BUILD_PLAT}/build_axf.ld -L ${BUILD_PLAT} --strip-debug -s -n -o ${BUILD_PLAT}/bl31.axf
+
+all: bl31.axf
diff --git a/plat/arm/board/arm_fpga/rom_trampoline.S b/plat/arm/board/arm_fpga/rom_trampoline.S
new file mode 100644
index 0000000..cd66c79
--- /dev/null
+++ b/plat/arm/board/arm_fpga/rom_trampoline.S
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2020, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * The Arm Ltd. FPGA images start execution at address 0x0, which is
+ * mapped at an (emulated) ROM image. The payload uploader can write to
+ * this memory, but write access by the CPU cores is prohibited.
+ *
+ * Provide a simple trampoline to start BL31 execution at the actual
+ * load address. We put the DTB address in x0, so any code in DRAM could
+ * make use of that information (not yet used in BL31 right now).
+ */
+
+#include <asm_macros.S>
+#include <common/bl_common.ld.h>
+
+.text
+.global _start
+
+_start:
+ mov_imm x1, BL31_BASE /* beginning of DRAM */
+ mov_imm x0, FPGA_PRELOADED_DTB_BASE
+ br x1
diff --git a/plat/arm/board/common/aarch32/board_arm_helpers.S b/plat/arm/board/common/aarch32/board_arm_helpers.S
new file mode 100644
index 0000000..8c63693
--- /dev/null
+++ b/plat/arm/board/common/aarch32/board_arm_helpers.S
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/arm/board/common/aarch64/board_arm_helpers.S b/plat/arm/board/common/aarch64/board_arm_helpers.S
new file mode 100644
index 0000000..cde6b00
--- /dev/null
+++ b/plat/arm/board/common/aarch64/board_arm_helpers.S
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/arm/board/common/board_arm_trusted_boot.c b/plat/arm/board/common/board_arm_trusted_boot.c
new file mode 100644
index 0000000..714c444
--- /dev/null
+++ b/plat/arm/board/common/board_arm_trusted_boot.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/arm/cryptocell/cc_rotpk.h>
+#include <drivers/delay_timer.h>
+#include <lib/cassert.h>
+#include <lib/fconf/fconf.h>
+#include <plat/common/common_def.h>
+#include <plat/common/platform.h>
+#if defined(ARM_COT_cca)
+#include <tools_share/cca_oid.h>
+#elif defined(ARM_COT_dualroot)
+#include <tools_share/dualroot_oid.h>
+#elif defined(ARM_COT_tbbr)
+#include <tools_share/tbbr_oid.h>
+#endif
+
+#include <plat/arm/common/fconf_nv_cntr_getter.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+#if !ARM_CRYPTOCELL_INTEG
+#if !ARM_ROTPK_LOCATION_ID
+ #error "ARM_ROTPK_LOCATION_ID not defined"
+#endif
+#endif
+
+#if COT_DESC_IN_DTB && defined(IMAGE_BL2)
+uintptr_t nv_cntr_base_addr[MAX_NV_CTR_IDS];
+#else
+uintptr_t nv_cntr_base_addr[MAX_NV_CTR_IDS] = {
+ TFW_NVCTR_BASE,
+ NTFW_CTR_BASE
+};
+#endif
+
+
+/* Weak definition may be overridden in specific platform */
+#pragma weak plat_get_nv_ctr
+#pragma weak plat_set_nv_ctr
+
+extern unsigned char arm_rotpk_header[], arm_rotpk_hash_end[];
+
+#if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_REGS_ID) || ARM_CRYPTOCELL_INTEG
+static unsigned char rotpk_hash_der[ARM_ROTPK_HEADER_LEN + ARM_ROTPK_HASH_LEN];
+#endif
+
+#if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_REGS_ID)
+/*
+ * Return the ROTPK hash stored in dedicated registers.
+ */
+int arm_get_rotpk_info_regs(void **key_ptr, unsigned int *key_len,
+ unsigned int *flags)
+{
+ uint8_t *dst;
+ uint32_t *src, tmp;
+ unsigned int words, i;
+
+ assert(key_ptr != NULL);
+ assert(key_len != NULL);
+ assert(flags != NULL);
+
+ /* Copy the DER header */
+
+ memcpy(rotpk_hash_der, arm_rotpk_header, ARM_ROTPK_HEADER_LEN);
+ dst = (uint8_t *)&rotpk_hash_der[ARM_ROTPK_HEADER_LEN];
+
+ words = ARM_ROTPK_HASH_LEN >> 2;
+
+ 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 & 0xFF);
+ *dst++ = (uint8_t)((tmp >> 8) & 0xFF);
+ *dst++ = (uint8_t)((tmp >> 16) & 0xFF);
+ *dst++ = (uint8_t)((tmp >> 24) & 0xFF);
+ }
+
+ *key_ptr = (void *)rotpk_hash_der;
+ *key_len = (unsigned int)sizeof(rotpk_hash_der);
+ *flags = ROTPK_IS_HASH;
+ return 0;
+}
+#endif
+
+#if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID) || \
+ (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_ECDSA_ID)
+/*
+ * Return development ROTPK hash generated from ROT_KEY.
+ */
+int arm_get_rotpk_info_dev(void **key_ptr, unsigned int *key_len,
+ unsigned int *flags)
+{
+ *key_ptr = arm_rotpk_header;
+ *key_len = arm_rotpk_hash_end - arm_rotpk_header;
+ *flags = ROTPK_IS_HASH;
+ return 0;
+}
+#endif
+
+#if ARM_CRYPTOCELL_INTEG
+/*
+ * Return ROTPK hash from CryptoCell.
+ */
+int arm_get_rotpk_info_cc(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, arm_rotpk_header, ARM_ROTPK_HEADER_LEN);
+ dst = &rotpk_hash_der[ARM_ROTPK_HEADER_LEN];
+ *key_ptr = rotpk_hash_der;
+ *key_len = sizeof(rotpk_hash_der);
+ return cc_get_rotpk_hash(dst, ARM_ROTPK_HASH_LEN, flags);
+}
+#endif
+
+/*
+ * Wrapper function for most Arm platforms to get ROTPK hash.
+ */
+static int get_rotpk_info(void **key_ptr, unsigned int *key_len,
+ unsigned int *flags)
+{
+#if ARM_CRYPTOCELL_INTEG
+ return arm_get_rotpk_info_cc(key_ptr, key_len, flags);
+#else
+
+#if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID) || \
+ (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_ECDSA_ID)
+ return arm_get_rotpk_info_dev(key_ptr, key_len, flags);
+#elif (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_REGS_ID)
+ return arm_get_rotpk_info_regs(key_ptr, key_len, flags);
+#else
+ return 1;
+#endif
+#endif /* ARM_CRYPTOCELL_INTEG */
+}
+
+#if defined(ARM_COT_tbbr)
+
+int arm_get_rotpk_info(void *cookie __unused, void **key_ptr,
+ unsigned int *key_len, unsigned int *flags)
+{
+ return get_rotpk_info(key_ptr, key_len, flags);
+}
+
+#elif defined(ARM_COT_dualroot)
+
+int arm_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+ unsigned int *flags)
+{
+ /*
+ * Return the right root of trust key hash based on the cookie value:
+ * - NULL means the primary ROTPK.
+ * - Otherwise, interpret cookie as the OID of the certificate
+ * extension containing the key.
+ */
+ if (cookie == NULL) {
+ return get_rotpk_info(key_ptr, key_len, flags);
+ } else if (strcmp(cookie, PROT_PK_OID) == 0) {
+ extern unsigned char arm_protpk_hash[];
+ extern unsigned char arm_protpk_hash_end[];
+ *key_ptr = arm_protpk_hash;
+ *key_len = arm_protpk_hash_end - arm_protpk_hash;
+ *flags = ROTPK_IS_HASH;
+ return 0;
+ } else {
+ /* Invalid key ID. */
+ return 1;
+ }
+}
+
+#elif defined(ARM_COT_cca)
+
+int arm_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+ unsigned int *flags)
+{
+ /*
+ * Return the right root of trust key hash based on the cookie value:
+ * - NULL means the primary ROTPK.
+ * - Otherwise, interpret cookie as the OID of the certificate
+ * extension containing the key.
+ */
+ if (cookie == NULL) {
+ return get_rotpk_info(key_ptr, key_len, flags);
+ } else if (strcmp(cookie, PROT_PK_OID) == 0) {
+ extern unsigned char arm_protpk_hash[];
+ extern unsigned char arm_protpk_hash_end[];
+ *key_ptr = arm_protpk_hash;
+ *key_len = arm_protpk_hash_end - arm_protpk_hash;
+ *flags = ROTPK_IS_HASH;
+ return 0;
+ } else if (strcmp(cookie, SWD_ROT_PK_OID) == 0) {
+ extern unsigned char arm_swd_rotpk_hash[];
+ extern unsigned char arm_swd_rotpk_hash_end[];
+ *key_ptr = arm_swd_rotpk_hash;
+ *key_len = arm_swd_rotpk_hash_end - arm_swd_rotpk_hash;
+ *flags = ROTPK_IS_HASH;
+ return 0;
+ } else {
+ /* Invalid key ID. */
+ return 1;
+ }
+}
+
+#endif
+
+/*
+ * 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 *)FCONF_GET_PROPERTY(cot, nv_cntr_addr,
+ TRUSTED_NV_CTR_ID);
+ } else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) {
+ nv_ctr_addr = (uint32_t *)FCONF_GET_PROPERTY(cot, nv_cntr_addr,
+ NON_TRUSTED_NV_CTR_ID);
+ } 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;
+}
diff --git a/plat/arm/board/common/board_common.mk b/plat/arm/board/common/board_common.mk
new file mode 100644
index 0000000..1d0eb13
--- /dev/null
+++ b/plat/arm/board/common/board_common.mk
@@ -0,0 +1,120 @@
+#
+# Copyright (c) 2015-2022, 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)
+ CRYPTO_ALG=rsa
+ ARM_ROTPK_LOCATION_ID = ARM_ROTPK_DEVEL_RSA_ID
+ ARM_ROTPK_HASH = plat/arm/board/common/rotpk/arm_rotpk_rsa_sha256.bin
+$(eval $(call add_define_val,ARM_ROTPK_HASH,'"$(ARM_ROTPK_HASH)"'))
+$(BUILD_PLAT)/bl2/arm_dev_rotpk.o : $(ARM_ROTPK_HASH)
+$(warning Development keys support for FVP is deprecated. Use `regs` \
+option instead)
+else ifeq (${ARM_ROTPK_LOCATION}, devel_ecdsa)
+ CRYPTO_ALG=ec
+ ARM_ROTPK_LOCATION_ID = ARM_ROTPK_DEVEL_ECDSA_ID
+ ARM_ROTPK_HASH = plat/arm/board/common/rotpk/arm_rotpk_ecdsa_sha256.bin
+$(eval $(call add_define_val,ARM_ROTPK_HASH,'"$(ARM_ROTPK_HASH)"'))
+$(BUILD_PLAT)/bl2/arm_dev_rotpk.o : $(ARM_ROTPK_HASH)
+$(warning Development keys support for FVP is deprecated. Use `regs` \
+option instead)
+else
+$(error "Unsupported ARM_ROTPK_LOCATION value")
+endif
+
+$(eval $(call add_define,ARM_ROTPK_LOCATION_ID))
+
+ifeq (${ENABLE_RME}, 1)
+COT := cca
+endif
+
+# Force generation of the new hash if ROT_KEY is specified
+ifdef ROT_KEY
+ HASH_PREREQUISITES = $(ROT_KEY) FORCE
+else
+ HASH_PREREQUISITES = $(ROT_KEY)
+endif
+
+$(ARM_ROTPK_HASH) : $(HASH_PREREQUISITES)
+ifndef ROT_KEY
+ $(error Cannot generate hash: no ROT_KEY defined)
+endif
+ ${OPENSSL_BIN_PATH}/openssl ${CRYPTO_ALG} -in $< -pubout -outform DER | \
+ ${OPENSSL_BIN_PATH}/openssl dgst -sha256 -binary > $@
+
+# 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 \
+ plat/arm/board/common/rotpk/arm_dev_rotpk.S
+BL2_SOURCES += plat/arm/board/common/board_arm_trusted_boot.c \
+ plat/arm/board/common/rotpk/arm_dev_rotpk.S
+
+# Allows platform code to provide implementation variants depending on the
+# selected chain of trust.
+$(eval $(call add_define,ARM_COT_${COT}))
+
+ifeq (${COT},dualroot)
+# Platform Root of Trust key files.
+ARM_PROT_KEY := plat/arm/board/common/protpk/arm_protprivk_rsa.pem
+ARM_PROTPK_HASH := plat/arm/board/common/protpk/arm_protpk_rsa_sha256.bin
+
+# Provide the private key to cert_create tool. It needs it to sign the images.
+PROT_KEY := ${ARM_PROT_KEY}
+
+$(eval $(call add_define_val,ARM_PROTPK_HASH,'"$(ARM_PROTPK_HASH)"'))
+
+BL1_SOURCES += plat/arm/board/common/protpk/arm_dev_protpk.S
+BL2_SOURCES += plat/arm/board/common/protpk/arm_dev_protpk.S
+
+$(BUILD_PLAT)/bl1/arm_dev_protpk.o: $(ARM_PROTPK_HASH)
+$(BUILD_PLAT)/bl2/arm_dev_protpk.o: $(ARM_PROTPK_HASH)
+endif
+
+ifeq (${COT},cca)
+# Platform and Secure World Root of Trust key files.
+ARM_PROT_KEY := plat/arm/board/common/protpk/arm_protprivk_rsa.pem
+ARM_PROTPK_HASH := plat/arm/board/common/protpk/arm_protpk_rsa_sha256.bin
+ARM_SWD_ROT_KEY := plat/arm/board/common/swd_rotpk/arm_swd_rotprivk_rsa.pem
+ARM_SWD_ROTPK_HASH := plat/arm/board/common/swd_rotpk/arm_swd_rotpk_rsa_sha256.bin
+
+# Provide the private keys to cert_create tool. It needs them to sign the images.
+PROT_KEY := ${ARM_PROT_KEY}
+SWD_ROT_KEY := ${ARM_SWD_ROT_KEY}
+
+$(eval $(call add_define_val,ARM_PROTPK_HASH,'"$(ARM_PROTPK_HASH)"'))
+$(eval $(call add_define_val,ARM_SWD_ROTPK_HASH,'"$(ARM_SWD_ROTPK_HASH)"'))
+
+BL1_SOURCES += plat/arm/board/common/protpk/arm_dev_protpk.S \
+ plat/arm/board/common/swd_rotpk/arm_dev_swd_rotpk.S
+BL2_SOURCES += plat/arm/board/common/protpk/arm_dev_protpk.S \
+ plat/arm/board/common/swd_rotpk/arm_dev_swd_rotpk.S
+
+$(BUILD_PLAT)/bl1/arm_dev_protpk.o: $(ARM_PROTPK_HASH)
+$(BUILD_PLAT)/bl1/arm_dev_swd_rotpk.o: $(ARM_SWD_ROTPK_HASH)
+$(BUILD_PLAT)/bl2/arm_dev_protpk.o: $(ARM_PROTPK_HASH)
+$(BUILD_PLAT)/bl2/arm_dev_swd_rotpk.o: $(ARM_SWD_ROTPK_HASH)
+endif
+
+endif
diff --git a/plat/arm/board/common/protpk/README b/plat/arm/board/common/protpk/README
new file mode 100644
index 0000000..3aca180
--- /dev/null
+++ b/plat/arm/board/common/protpk/README
@@ -0,0 +1,14 @@
+This directory contains some development keys to be used as the platform
+root-of-trust key.
+
+* arm_protprivk_rsa.pem is a 2K RSA private key in PEM format. It has been
+ generated using the openssl command line tool:
+
+ openssl genrsa 2048 > arm_protprivk_rsa.pem
+
+* arm_protpk_rsa_sha256.bin is the SHA-256 hash of the DER-encoded public key
+ associated with the above private key. It has been generated using the openssl
+ command line tool:
+
+ openssl rsa -in arm_protprivk_rsa.pem -pubout -outform DER | \
+ openssl dgst -sha256 -binary > arm_protpk_rsa_sha256.bin
diff --git a/plat/arm/board/common/protpk/arm_dev_protpk.S b/plat/arm/board/common/protpk/arm_dev_protpk.S
new file mode 100644
index 0000000..2688cbb
--- /dev/null
+++ b/plat/arm/board/common/protpk/arm_dev_protpk.S
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+ .global arm_protpk_hash
+ .global arm_protpk_hash_end
+
+ .section .rodata.arm_protpk_hash, "a"
+
+arm_protpk_hash:
+ /* DER header. */
+ .byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
+ .byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+ /* Key hash. */
+ .incbin ARM_PROTPK_HASH
+arm_protpk_hash_end:
diff --git a/plat/arm/board/common/protpk/arm_protprivk_rsa.pem b/plat/arm/board/common/protpk/arm_protprivk_rsa.pem
new file mode 100644
index 0000000..eeaad9e
--- /dev/null
+++ b/plat/arm/board/common/protpk/arm_protprivk_rsa.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAzR0h/Z4Up17wfuRlYrUWseGDmlGKpl1PflGiYbyVmI7PwTTp
+y/T77EiljGp52suLWntHsc0lee50pW16DU2c5bVfmyofau3GjJ1Yqw5XFAahr6eM
+/0mkN8utrevvcRT9CP07D+zdhb/WlRUAnedqr/AUHU8BXS+Bxe8P0Z0Z7+DKjYZp
+thzXxsjKM02BFFzNwyVrlyBFDkW/53A4M+dpmuWDjAGCJH88W/u0LdmLcii11IzD
+/Ofz8Jxc/ZhqL+9FFK4qU+AJp8yXAnACSB46DlNltJrode0y5tmPhtS37ZF7EFb8
+UZWwZVgtuQyuyz9RYUS6jtiGuq6s8GlRwjTe7wIDAQABAoIBAFoWIYeyln+sQxR4
+W88umfkmgxaUGcFX2kIwuJEUst9+WeERzF24C62LeqphWYOvQlVLMAH3iC41fSXr
+H2AYZoC9WHBd386nAD1iHj+C3Nv+zaTIgjTdszKOUonAxjl0bm40SmyELAdCaoyv
+3MV9jm4Xk74LpR24b9bvWJNH3MxttH9hiYS+n0IzeTXDfO8GrNvHh92zx+jo8yMm
+Khhu+TDC9jA2pHpJcF/0EXxYMhwYiQT16nnHb+xMgS4JpalQhvVK01s4VYGHRoFk
+K6xh4TIS336LDLyalrGsPlfNfEdx+DimShDIfBUx9Jp3Pp11TUQUz4rhIHB9WdfG
+b6bV4wECgYEA+cgPS2TQ7XQ1RJq1S7OGePtBXvnoH226KwGS6Fey8838tLxbblim
+MU+EOYs3O66V6U2YpzmIakXo8030k8thY+jKbZl3l0m/hMuPOG66hfE5i7dYsiP4
+atok5wFiNeNYYjHMEayzk53MhG8EOh36msAO7ohKmenONUBA7pk6yTkCgYEA0jhk
+HPshwi+wKkx+JLTnuoEgx40tkRgSF2xBqKssMTasaQmX8qG+w9CEs0R8nZCI70Vc
+tXSFcidjdkHUVE2WsygIFuS1tbsAnpaxtn3E6rjie30X/Z280+TV0HjR0EMETmwl
+ShC5lZ0oP3LpEZfjbR5qs2kFW4MOxA7tjQVaMWcCgYEA5ZbVMBifzdMl70RA5i9C
+qEtSQAl3KgRCvar5rKSHsX+iC0Kiy9+iCusq/3WONEZ6NvMDIJpKYFyYDaOW7o5f
+m2TrRChu+1lnN5mfsGBfBCTBH0JMvZlAin6ussLb0eqBX+ijyY8zlLjTttsQSJcr
+tThZwTj3UVfOGbZQuL+RgEkCgYBXO3U3nXI9vUIx2zoBC1yZRNoQVGITMlTXiWGZ
+lyYoadKTZ5q44Sti4BUguounaoGYIEU/OtHhM70PJnPwY53kS/lHXrKUbbvtEwU9
+f+UFraC1s4wP/rOLjgq3jlsqO5T+4dt7Z4NLNUKtSYazeT6zWgrW1f6WIcUv0C38
+9bqegwKBgFCK3Oa5ibL5sPaPQ/1UfdeW4JVuu6A4JhHS7r+cVLsmcrvE1Qv7Wcvw
+B5aqXeqLu2dtIN8/f++3tzccs9LXKY/fh72D4TVjfrqOSSZoGTH9l4U5NXbqWM3I
+skkAYb2bMST/d1qSyYesgXVNAlaQHRh3vEz8x853nJ3v9OFj8/rW
+-----END RSA PRIVATE KEY-----
diff --git a/plat/arm/board/common/rotpk/arm_dev_rotpk.S b/plat/arm/board/common/rotpk/arm_dev_rotpk.S
new file mode 100644
index 0000000..06e2a06
--- /dev/null
+++ b/plat/arm/board/common/rotpk/arm_dev_rotpk.S
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* corstone1000 platform provides custom values for the macros defined in
+ * arm_def.h , so only platform_def.h needs to be included
+ */
+#if !defined(TARGET_PLATFORM_FVP) && !defined(TARGET_PLATFORM_FPGA)
+#include "plat/arm/common/arm_def.h"
+#else
+#include <platform_def.h>
+#endif
+
+ .global arm_rotpk_header
+ .global arm_rotpk_header_end
+ .section .rodata.arm_rotpk_hash, "a"
+
+arm_rotpk_header:
+ .byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
+ .byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+arm_rotpk_header_len:
+
+#ifdef ARM_ROTPK_HASH
+ .global arm_rotpk_hash_end
+ .incbin ARM_ROTPK_HASH
+arm_rotpk_hash_end:
+#endif
+
+.if ARM_ROTPK_HEADER_LEN != arm_rotpk_header_len - arm_rotpk_header
+.error "Invalid ROTPK header length."
+.endif
diff --git a/plat/arm/board/common/rotpk/arm_rotpk_ecdsa.der b/plat/arm/board/common/rotpk/arm_rotpk_ecdsa.der
new file mode 100644
index 0000000..2547877
--- /dev/null
+++ b/plat/arm/board/common/rotpk/arm_rotpk_ecdsa.der
Binary files differ
diff --git a/plat/arm/board/common/rotpk/arm_rotpk_rsa.der b/plat/arm/board/common/rotpk/arm_rotpk_rsa.der
new file mode 100644
index 0000000..661f899
--- /dev/null
+++ b/plat/arm/board/common/rotpk/arm_rotpk_rsa.der
Binary files differ
diff --git a/plat/arm/board/common/rotpk/arm_rotprivk_ecdsa.pem b/plat/arm/board/common/rotpk/arm_rotprivk_ecdsa.pem
new file mode 100644
index 0000000..fb328e3
--- /dev/null
+++ b/plat/arm/board/common/rotpk/arm_rotprivk_ecdsa.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEINSaX6nvzS3teiBJA7WlTLRKJOajpy29o2cArLbUXoZBoAoGCCqGSM49
+AwEHoUQDQgAEm+ZIvTQ44aKk83DhVLsvsFpKDP/Ch9vA+4Hp+fmVfX6gDH8K1OBi
+SpRf7FJ9RGPIn2H6xst+a1OtLMWUDRqGkQ==
+-----END EC PRIVATE KEY-----
diff --git a/plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem b/plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem
new file mode 100644
index 0000000..71410ec
--- /dev/null
+++ b/plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem
@@ -0,0 +1,28 @@
+-----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-----
diff --git a/plat/arm/board/common/swd_rotpk/README b/plat/arm/board/common/swd_rotpk/README
new file mode 100644
index 0000000..b628a5f
--- /dev/null
+++ b/plat/arm/board/common/swd_rotpk/README
@@ -0,0 +1,14 @@
+This directory contains some development keys to be used as the secure world
+root-of-trust key used in the CCA chain of trust.
+
+* swd_rotprivk_rsa.pem is a 2K RSA private key in PEM format. It has been
+ generated using the openssl command line tool:
+
+ openssl genrsa 2048 > arm_swd_rotprivk_rsa.pem
+
+* swd_rotpk_rsa_sha256.bin is the SHA-256 hash of the DER-encoded public key
+ associated with the above private key. It has been generated using the openssl
+ command line tool:
+
+ openssl rsa -in arm_swd_rotprivk_rsa.pem -pubout -outform DER | \
+ openssl dgst -sha256 -binary > arm_swd_rotpk_rsa_sha256.bin
diff --git a/plat/arm/board/common/swd_rotpk/arm_dev_swd_rotpk.S b/plat/arm/board/common/swd_rotpk/arm_dev_swd_rotpk.S
new file mode 100644
index 0000000..ae4f9d2
--- /dev/null
+++ b/plat/arm/board/common/swd_rotpk/arm_dev_swd_rotpk.S
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+ .global arm_swd_rotpk_hash
+ .global arm_swd_rotpk_hash_end
+
+ .section .rodata.arm_swd_rotpk_hash, "a"
+
+arm_swd_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
+ /* Key hash. */
+ .incbin ARM_SWD_ROTPK_HASH
+arm_swd_rotpk_hash_end:
diff --git a/plat/arm/board/common/swd_rotpk/arm_swd_rotpk_rsa_sha256.bin b/plat/arm/board/common/swd_rotpk/arm_swd_rotpk_rsa_sha256.bin
new file mode 100644
index 0000000..b2f3e60
--- /dev/null
+++ b/plat/arm/board/common/swd_rotpk/arm_swd_rotpk_rsa_sha256.bin
@@ -0,0 +1 @@
+0¾âà ’æœÈË“(ì¨0ŠwIÓÕéã¡gk \ No newline at end of file
diff --git a/plat/arm/board/common/swd_rotpk/arm_swd_rotprivk_rsa.pem b/plat/arm/board/common/swd_rotpk/arm_swd_rotprivk_rsa.pem
new file mode 100644
index 0000000..0de655d
--- /dev/null
+++ b/plat/arm/board/common/swd_rotpk/arm_swd_rotprivk_rsa.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEA8igTd5QdZd181kz9vINr7Au34Rr/pQ1jpesfLlc1ZXCNAI9y
+/rhQlpw00y8rwOfgZsf18gPwGWWGhDJMsXI7OPem7BEUr8xKumuJuCiOdJh1STcR
+/JoFvz8wJPyycj/DOERRGsz+RvFBs6cLjSZHNQdzKDW+DE5vVJpmNWBVkoK7MCRD
+Wh/PMZVSoq9PeJOzayYcsipKvifT1+Wo9y2MG5zTDxi28rLr/FBm0CpTepBcRe8L
+pmgS7XJKhCQYxdDSzxi/0t/qXAwWuME4jv2HbNxsUZjahiBYpA0BafXanSuxVHly
+qpD0BmKAu7PpgKrEnUcPuHpZ2W+a05lNk6zjewIDAQABAoIBAG3twYCcTYgrtvs1
+8k38vyZl33CiKAGOhXkRtpL75fKJ2IizljmKBJOKj/R6ynsFCHrANadLIFj3HMyw
+ZN59A+OFkVJDIsf3jsj3/ooKZzkI6N120YSBizBZiAqSaJOy3HWTldn7y0b7SJ88
+quLFyLeLDTzowMCnbqTSfqmmdNJQAn+Q+7RX5sZGyBQUF2pRAA67cOYzc3a5MZ5E
+zBOs2u8VboC3ulEq876XWQbcXpRh/ap3eplQ1kAdyy64IPp2WbxqyXW0IQAQqaqh
+6oj19ME6mVD5wtELcYscJCDb7pA6WJtPp6nz/og2ifCJE/75T5RJ6fc6eBFMcofQ
+STIClGECgYEA/ZC0GX1HTKEKK3c1TiS3Zy0DS5ZoN5KFK7Sp1ZAjPE63iAr1a3z9
+Kepb+L8TBSw50tVD74MF5ChEid/ghF5BrVC3/YJkiiNpM1F51SMLGFeiDPRzJcx5
+KJkSflX7Q36BAXqj85Yz5AjgTPKcBqQRVZ6pNZN1HY99MloMg22WPRECgYEA9HtU
+FXmnTplXaNnihdq+vL5Z4/KDM+1f1E95y1PB8vkLI+o1szVNFP+BYz+w42lKtHW+
+c+z40AhFBGZQ0QCx83NOyObCReFjEbP8Nz71BsHe6GyMk9tSPIpzu9XB49Rs+9EO
+DAvFM5y2j5bH+lXE0pSyS3oBf51L9ZCPhp/vB8sCgYEAydwB1Gzsbu+hFfs/v2bx
+brzh67HgY6VMSP/5WF/3/RG5gB8hQ6HsNQsyjrMmZC7SFarb+3e2H+2CqrREm3wi
+EuS4pKPCgEoyfL03HVtZgNZ61o9gf83pAk3h8Bto/VFfSBsnHEsOIlKCph9Z4NuK
+RTwa/uDWEmNhyszvO03pldECgYEA2zB7GWnhc1mNgabfLY0JtuSeaPzzXqnyYcID
+eyUT3QglUcTY8lvWSP4ufdILgEfVP2fVIdAS30iawDAPQuLxqEf4Gayx/r7s+GE6
+vjlGqxFEDXPMsX9QApFK49voop/AOiCbDHe9DOHy11ei4TDmbrn8BClVkJlxEa/S
+ziszvfMCgYEA2V0zXziooI0toaOJEWZlAYhEONS5SG2z28HMLNgbdMcueGNhseaR
+NBGgPcu3EQhbL/hD0tBs09u6gjy1WD1i0HYnm1K1YQ1flzfbjUa3BqZETMbNhugd
+CM9yv0GEL/udZyOmO401aYl+QGXZX/WwlLQOe7WqQXOXJvW73oSqy7M=
+-----END RSA PRIVATE KEY-----
diff --git a/plat/arm/board/corstone1000/common/corstone1000_bl2_mem_params_desc.c b/plat/arm/board/corstone1000/common/corstone1000_bl2_mem_params_desc.c
new file mode 100644
index 0000000..fe521a9
--- /dev/null
+++ b/plat/arm/board/corstone1000/common/corstone1000_bl2_mem_params_desc.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/desc_image_load.h>
+
+#include <platform_def.h>
+
+/*******************************************************************************
+ * 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),
+ .ep_info.args.arg3 = ARM_BL31_PLAT_PARAM_VAL,
+ 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 = BL32_IMAGE_ID,
+ },
+
+ /* 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,
+ .ep_info.args.arg0 = CORSTONE1000_TOS_FW_CONFIG_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 TOS_FW_CONFIG related information */
+ {
+ .image_id = TOS_FW_CONFIG_ID,
+ .image_info.image_base = CORSTONE1000_TOS_FW_CONFIG_BASE,
+ .image_info.image_max_size = (CORSTONE1000_TOS_FW_CONFIG_LIMIT -
+ CORSTONE1000_TOS_FW_CONFIG_BASE),
+ 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),
+ .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),
+ .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 = BL33_LIMIT - BL33_BASE,
+
+ .next_handoff_image_id = INVALID_IMAGE_ID,
+ },
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
diff --git a/plat/arm/board/corstone1000/common/corstone1000_err.c b/plat/arm/board/corstone1000/common/corstone1000_err.c
new file mode 100644
index 0000000..376799f
--- /dev/null
+++ b/plat/arm/board/corstone1000/common/corstone1000_err.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * corstone1000 error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+ while (1) {
+ wfi();
+ }
+}
diff --git a/plat/arm/board/corstone1000/common/corstone1000_helpers.S b/plat/arm/board/corstone1000/common/corstone1000_helpers.S
new file mode 100644
index 0000000..cbe27c3
--- /dev/null
+++ b/plat/arm/board/corstone1000/common/corstone1000_helpers.S
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .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 corstone1000, 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 x0, #0
+ 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
+ mov_imm x1, MPIDR_AFFINITY_MASK
+ and x0, x0, x1
+ cmp x0, #CORSTONE1000_PRIMARY_CPU
+ cset w0, eq
+ ret
+endfunc plat_is_my_cpu_primary
diff --git a/plat/arm/board/corstone1000/common/corstone1000_plat.c b/plat/arm/board/corstone1000/common/corstone1000_plat.c
new file mode 100644
index 0000000..0235f8b
--- /dev/null
+++ b/plat/arm/board/corstone1000/common/corstone1000_plat.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/bl_common.h>
+
+#include <drivers/generic_delay_timer.h>
+#include <drivers/io/io_storage.h>
+#include <plat/common/platform.h>
+#include <plat/arm/common/arm_fconf_getter.h>
+#include <plat/arm/common/arm_fconf_io_storage.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_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,
+ ARM_MAP_NS_SHARED_RAM,
+ ARM_MAP_NS_DRAM1,
+ CORSTONE1000_MAP_DEVICE,
+ CORSTONE1000_EXTERNAL_FLASH,
+ {0}
+};
+
+static void set_fip_image_source(void)
+{
+ const struct plat_io_policy *policy;
+ /*
+ * metadata for firmware update is written at 0x0000 offset of the flash.
+ * PLAT_ARM_BOOT_BANK_FLAG contains the boot bank that TF-M is booted.
+ * As per firmware update spec, at a given point of time, only one bank
+ * is active. This means, TF-A should boot from the same bank as TF-M.
+ */
+ volatile uint32_t *boot_bank_flag = (uint32_t *)(PLAT_ARM_BOOT_BANK_FLAG);
+
+ if (*boot_bank_flag > 1) {
+ VERBOSE("Boot_bank is set higher than possible values");
+ }
+
+ VERBOSE("Boot bank flag = %u.\n\r", *boot_bank_flag);
+
+ policy = FCONF_GET_PROPERTY(arm, io_policies, FIP_IMAGE_ID);
+
+ assert(policy != NULL);
+ assert(policy->image_spec != 0UL);
+
+ io_block_spec_t *spec = (io_block_spec_t *)policy->image_spec;
+
+ if ((*boot_bank_flag) == 0) {
+ VERBOSE("Booting from bank 0: fip offset = 0x%lx\n\r",
+ PLAT_ARM_FIP_BASE_BANK0);
+ spec->offset = PLAT_ARM_FIP_BASE_BANK0;
+ } else {
+ VERBOSE("Booting from bank 1: fip offset = 0x%lx\n\r",
+ PLAT_ARM_FIP_BASE_BANK1);
+ spec->offset = PLAT_ARM_FIP_BASE_BANK1;
+ }
+}
+
+void bl2_platform_setup(void)
+{
+ arm_bl2_platform_setup();
+ /*
+ * Identify the start address of the FIP by reading the boot
+ * index flag from the flash.
+ */
+ set_fip_image_source();
+}
+
+/* corstone1000 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)
+{
+ /* Returning the Generic Timer Frequency */
+ return SYS_COUNTER_FREQ_IN_TICKS;
+}
+
+
+/*
+ * 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)
+{
+}
+
+/*
+ * This function is invoked during Mbed TLS library initialisation to get a heap
+ * The function simply returns the default allocated heap.
+ */
+
+#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
diff --git a/plat/arm/board/corstone1000/common/corstone1000_pm.c b/plat/arm/board/corstone1000/common/corstone1000_pm.c
new file mode 100644
index 0000000..4b0a791
--- /dev/null
+++ b/plat/arm/board/corstone1000/common/corstone1000_pm.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+/*******************************************************************************
+ * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
+ * platform layer will take care of registering the handlers with PSCI.
+ ******************************************************************************/
+
+static void __dead2 corstone1000_system_reset(void)
+{
+
+ uint32_t volatile * const watchdog_ctrl_reg = (uint32_t *) SECURE_WATCHDOG_ADDR_CTRL_REG;
+ uint32_t volatile * const watchdog_val_reg = (uint32_t *) SECURE_WATCHDOG_ADDR_VAL_REG;
+
+ *(watchdog_val_reg) = SECURE_WATCHDOG_COUNTDOWN_VAL;
+ *watchdog_ctrl_reg = SECURE_WATCHDOG_MASK_ENABLE;
+ while (1) {
+ wfi();
+ }
+}
+
+plat_psci_ops_t plat_arm_psci_pm_ops = {
+ .system_reset = corstone1000_system_reset,
+ .validate_ns_entrypoint = NULL
+};
+
+const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
+{
+ ops = &plat_arm_psci_pm_ops;
+ return ops;
+}
diff --git a/plat/arm/board/corstone1000/common/corstone1000_security.c b/plat/arm/board/corstone1000/common/corstone1000_security.c
new file mode 100644
index 0000000..c88201b
--- /dev/null
+++ b/plat/arm/board/corstone1000/common/corstone1000_security.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2021-2022, 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.
+ */
+}
diff --git a/plat/arm/board/corstone1000/common/corstone1000_stack_protector.c b/plat/arm/board/corstone1000/common/corstone1000_stack_protector.c
new file mode 100644
index 0000000..393235e
--- /dev/null
+++ b/plat/arm/board/corstone1000/common/corstone1000_stack_protector.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <plat/common/platform.h>
+
+static uint32_t plat_generate_random_number(void)
+{
+ uintptr_t return_addr = (uintptr_t)__builtin_return_address(0U);
+ uintptr_t frame_addr = (uintptr_t)__builtin_frame_address(0U);
+ uint64_t cntpct = read_cntpct_el0();
+
+ /* Generate 32-bit pattern: saving the 2 least significant bytes
+ * in random_lo and random_hi
+ */
+ uint16_t random_lo = (uint16_t)(
+ (((uint64_t)return_addr) << 13) ^ frame_addr ^ cntpct
+ );
+
+ uint16_t random_hi = (uint16_t)(
+ (((uint64_t)frame_addr) << 15) ^ return_addr ^ cntpct
+ );
+
+ return (((uint32_t)random_hi) << 16) | random_lo;
+}
+
+u_register_t plat_get_stack_protector_canary(void)
+{
+ return plat_generate_random_number(); /* a 32-bit pattern returned */
+}
diff --git a/plat/arm/board/corstone1000/common/corstone1000_topology.c b/plat/arm/board/corstone1000/common/corstone1000_topology.c
new file mode 100644
index 0000000..5351896
--- /dev/null
+++ b/plat/arm/board/corstone1000/common/corstone1000_topology.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/* The corstone1000 power domain tree descriptor */
+static unsigned char corstone1000_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.
+ */
+ corstone1000_power_domain_tree_desc[0] = 1;
+ corstone1000_power_domain_tree_desc[1] = PLAT_ARM_CLUSTER_COUNT;
+
+ for (i = 0; i < PLAT_ARM_CLUSTER_COUNT; i++)
+ corstone1000_power_domain_tree_desc[i + 2] = PLATFORM_CORE_COUNT;
+
+ return corstone1000_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);
+}
diff --git a/plat/arm/board/corstone1000/common/corstone1000_trusted_boot.c b/plat/arm/board/corstone1000/common/corstone1000_trusted_boot.c
new file mode 100644
index 0000000..7e8fbb2
--- /dev/null
+++ b/plat/arm/board/corstone1000/common/corstone1000_trusted_boot.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * 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
+ * }
+ *
+ * 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, ROTPK_NOT_DEPLOYED.
+ *
+ * Refer to the TF-A porting-guide document for more details.
+ */
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+ unsigned int *flags)
+{
+ return arm_get_rotpk_info(cookie, key_ptr, key_len, flags);
+}
+
+/*
+ * STUB overriding the non-volatile counter reading.
+ * NV counters are not implemented at this stage of development.
+ * Return: 0 = success
+ */
+int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
+{
+ *nv_ctr = CORSTONE1000_FW_NVCTR_VAL;
+ return 0;
+}
+
+/*
+ * STUB overriding the non-volatile counter updating.
+ * NV counters are not implemented at this stage of development.
+ * Return: 0 = success
+ */
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+ return 0;
+}
diff --git a/plat/arm/board/corstone1000/common/fdts/corstone1000_spmc_manifest.dts b/plat/arm/board/corstone1000/common/fdts/corstone1000_spmc_manifest.dts
new file mode 100644
index 0000000..8e49ab8
--- /dev/null
+++ b/plat/arm/board/corstone1000/common/fdts/corstone1000_spmc_manifest.dts
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/dts-v1/;
+
+/ {
+ compatible = "arm,ffa-core-manifest-1.0";
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ /*
+ * BL32 image details needed by SPMC
+ *
+ * Note:
+ * binary_size: size of BL32 + TOS_FW_CONFIG
+ */
+
+ attribute {
+ spmc_id = <0x8000>;
+ maj_ver = <0x1>;
+ min_ver = <0x1>;
+ exec_state = <0x0>;
+ load_address = <0x0 0x2002000>;
+ entrypoint = <0x0 0x2002000>;
+ binary_size = <0xae000>;
+ };
+
+};
diff --git a/plat/arm/board/corstone1000/common/include/platform_def.h b/plat/arm/board/corstone1000/common/include/platform_def.h
new file mode 100644
index 0000000..584d485
--- /dev/null
+++ b/plat/arm/board/corstone1000/common/include/platform_def.h
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/common/arm_spm_def.h>
+#include <plat/arm/common/smccc_def.h>
+#include <plat/common/common_def.h>
+#include <plat/arm/soc/common/soc_css_def.h>
+
+#define ARM_ROTPK_HEADER_LEN 19
+#define ARM_ROTPK_HASH_LEN 32
+
+/* Special value used to verify platform parameters from BL2 to BL31 */
+#define ARM_BL31_PLAT_PARAM_VAL ULL(0x0f1e2d3c4b5a6978)
+
+/* PL011 UART related constants */
+#ifdef V2M_IOFPGA_UART0_CLK_IN_HZ
+#undef V2M_IOFPGA_UART0_CLK_IN_HZ
+#endif
+
+#ifdef V2M_IOFPGA_UART1_CLK_IN_HZ
+#undef V2M_IOFPGA_UART1_CLK_IN_HZ
+#endif
+
+#define V2M_IOFPGA_UART0_CLK_IN_HZ 50000000
+#define V2M_IOFPGA_UART1_CLK_IN_HZ 50000000
+
+/* Core/Cluster/Thread counts for corstone1000 */
+#define CORSTONE1000_CLUSTER_COUNT U(1)
+#define CORSTONE1000_MAX_CPUS_PER_CLUSTER U(4)
+#define CORSTONE1000_MAX_PE_PER_CPU U(1)
+#define CORSTONE1000_PRIMARY_CPU U(0)
+
+#define PLAT_ARM_CLUSTER_COUNT CORSTONE1000_CLUSTER_COUNT
+
+#define PLATFORM_CORE_COUNT (PLAT_ARM_CLUSTER_COUNT * \
+ CORSTONE1000_MAX_CPUS_PER_CLUSTER * \
+ CORSTONE1000_MAX_PE_PER_CPU)
+
+/* 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 */
+
+/* SRAM (CVM) memory layout
+ *
+ * <ARM_TRUSTED_SRAM_BASE>
+ * partition size: sizeof(meminfo_t) = 16 bytes
+ * content: memory info area used by the next BL
+ *
+ * <ARM_FW_CONFIG_BASE>
+ * partition size: 4080 bytes
+ *
+ * <ARM_BL2_MEM_DESC_BASE>
+ * partition size: 4 KB
+ * content: Area where BL2 copies the images descriptors
+ *
+ * <ARM_BL_RAM_BASE> = <BL32_BASE>
+ * partition size: 688 KB
+ * content: BL32 (optee-os)
+ *
+ * <CORSTONE1000_TOS_FW_CONFIG_BASE> = 0x20ae000
+ * partition size: 8 KB
+ * content: BL32 config (TOS_FW_CONFIG)
+ *
+ * <BL31_BASE>
+ * partition size: 140 KB
+ * content: BL31
+ *
+ * <BL2_SIGNATURE_BASE>
+ * partition size: 4 KB
+ * content: MCUBOOT data needed to verify TF-A BL2
+ *
+ * <BL2_BASE>
+ * partition size: 176 KB
+ * content: BL2
+ *
+ * <ARM_NS_SHARED_RAM_BASE> = <ARM_TRUSTED_SRAM_BASE> + 1 MB
+ * partition size: 512 KB
+ * content: BL33 (u-boot)
+ */
+
+/* DDR memory */
+#define ARM_DRAM1_BASE UL(0x80000000)
+#define ARM_DRAM1_SIZE (SZ_2G) /* 2GB*/
+#define ARM_DRAM1_END (ARM_DRAM1_BASE + ARM_DRAM1_SIZE - 1)
+
+/* DRAM1 and DRAM2 are the same for corstone1000 */
+#define ARM_DRAM2_BASE ARM_DRAM1_BASE
+#define ARM_DRAM2_SIZE ARM_DRAM1_SIZE
+#define ARM_DRAM2_END ARM_DRAM1_END
+
+#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)
+
+/* The first 8 KB of Trusted SRAM are used as shared memory */
+#define ARM_TRUSTED_SRAM_BASE UL(0x02000000)
+#define ARM_SHARED_RAM_SIZE (SZ_8K) /* 8 KB */
+#define ARM_SHARED_RAM_BASE ARM_TRUSTED_SRAM_BASE
+
+/* The remaining Trusted SRAM is used to load the BL images */
+#define TOTAL_SRAM_SIZE (SZ_4M) /* 4 MB */
+
+/* Last 512KB of CVM is allocated for shared RAM as an example openAMP */
+#define ARM_NS_SHARED_RAM_SIZE (512 * SZ_1K)
+
+#define PLAT_ARM_TRUSTED_SRAM_SIZE (TOTAL_SRAM_SIZE - \
+ ARM_NS_SHARED_RAM_SIZE - \
+ ARM_SHARED_RAM_SIZE)
+
+#define PLAT_ARM_MAX_BL2_SIZE (180 * SZ_1K) /* 180 KB */
+
+#define PLAT_ARM_MAX_BL31_SIZE (140 * SZ_1K) /* 140 KB */
+
+#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)
+
+#define BL2_SIGNATURE_SIZE (SZ_4K) /* 4 KB */
+
+#define BL2_SIGNATURE_BASE (BL2_LIMIT - PLAT_ARM_MAX_BL2_SIZE)
+#define BL2_BASE (BL2_LIMIT - \
+ PLAT_ARM_MAX_BL2_SIZE + \
+ BL2_SIGNATURE_SIZE)
+#define BL2_LIMIT (ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)
+
+#define BL31_BASE (BL2_SIGNATURE_BASE - PLAT_ARM_MAX_BL31_SIZE)
+#define BL31_LIMIT BL2_SIGNATURE_BASE
+
+#define CORSTONE1000_TOS_FW_CONFIG_BASE (BL31_BASE - \
+ CORSTONE1000_TOS_FW_CONFIG_SIZE)
+#define CORSTONE1000_TOS_FW_CONFIG_SIZE (SZ_8K) /* 8 KB */
+#define CORSTONE1000_TOS_FW_CONFIG_LIMIT BL31_BASE
+
+#define BL32_BASE ARM_BL_RAM_BASE
+#define PLAT_ARM_MAX_BL32_SIZE (CORSTONE1000_TOS_FW_CONFIG_BASE - BL32_BASE)
+
+#define BL32_LIMIT (BL32_BASE + PLAT_ARM_MAX_BL32_SIZE)
+
+/* SPD_spmd settings */
+
+#define PLAT_ARM_SPMC_BASE BL32_BASE
+#define PLAT_ARM_SPMC_SIZE PLAT_ARM_MAX_BL32_SIZE
+
+/* NS memory */
+
+/* The last 512KB of the SRAM is allocated as shared memory */
+#define ARM_NS_SHARED_RAM_BASE (ARM_TRUSTED_SRAM_BASE + TOTAL_SRAM_SIZE - \
+ (PLAT_ARM_MAX_BL31_SIZE + \
+ PLAT_ARM_MAX_BL32_SIZE))
+
+#define BL33_BASE ARM_DRAM1_BASE
+#define PLAT_ARM_MAX_BL33_SIZE (12 * SZ_1M) /* 12 MB*/
+#define BL33_LIMIT (ARM_DRAM1_BASE + PLAT_ARM_MAX_BL33_SIZE)
+
+/* end of the definition of SRAM memory layout */
+
+/* NOR Flash */
+
+#define PLAT_ARM_BOOT_BANK_FLAG UL(0x08002000)
+#define PLAT_ARM_FIP_BASE_BANK0 UL(0x081EF000)
+#define PLAT_ARM_FIP_BASE_BANK1 UL(0x0916F000)
+#define PLAT_ARM_FIP_MAX_SIZE UL(0x1ff000) /* 1.996 MB */
+
+#define PLAT_ARM_NVM_BASE V2M_FLASH0_BASE
+#define PLAT_ARM_NVM_SIZE (SZ_32M) /* 32 MB */
+
+#define PLAT_ARM_FLASH_IMAGE_BASE PLAT_ARM_FIP_BASE_BANK0
+#define PLAT_ARM_FLASH_IMAGE_MAX_SIZE PLAT_ARM_FIP_MAX_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
+
+/*
+ * Define FW_CONFIG area base and limit. Leave enough space for BL2 meminfo.
+ * FW_CONFIG is intended to host the device tree. Currently, This area is not
+ * used because corstone1000 platform doesn't use a device tree at TF-A level.
+ */
+#define ARM_FW_CONFIG_BASE (ARM_SHARED_RAM_BASE + sizeof(meminfo_t))
+#define ARM_FW_CONFIG_LIMIT (ARM_SHARED_RAM_BASE + \
+ (ARM_SHARED_RAM_SIZE >> 1))
+
+/*
+ * Boot parameters passed from BL2 to BL31/BL32 are stored here
+ */
+#define ARM_BL2_MEM_DESC_BASE ARM_FW_CONFIG_LIMIT
+#define ARM_BL2_MEM_DESC_LIMIT ARM_BL_RAM_BASE
+
+/*
+ * 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 3
+#define PLAT_ARM_MMAP_ENTRIES 8
+#define MAX_XLAT_TABLES 5
+#define MAX_MMAP_REGIONS (PLAT_ARM_MMAP_ENTRIES + ARM_BL_REGIONS)
+#define MAX_IO_DEVICES 2
+#define MAX_IO_HANDLES 3
+#define MAX_IO_BLOCK_DEVICES 1
+
+/* GIC related constants */
+#define PLAT_ARM_GICD_BASE 0x1C010000
+#define PLAT_ARM_GICC_BASE 0x1C02F000
+
+/* MHUv2 Secure Channel receiver and sender */
+#define PLAT_SDK700_MHU0_SEND 0x1B800000
+#define PLAT_SDK700_MHU0_RECV 0x1B810000
+
+/* 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 SECURE_WATCHDOG_ADDR_CTRL_REG 0x1A320000
+#define SECURE_WATCHDOG_ADDR_VAL_REG 0x1A320008
+#define SECURE_WATCHDOG_MASK_ENABLE 0x01
+#define SECURE_WATCHDOG_COUNTDOWN_VAL 0x1000
+
+#define SYS_COUNTER_FREQ_IN_TICKS UL(50000000) /* 50MHz */
+
+#define CORSTONE1000_IRQ_TZ_WDOG 32
+#define CORSTONE1000_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_BASE (ARM_NS_SHARED_RAM_BASE)
+
+#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 CORSTONE1000_EXTERNAL_FLASH MAP_REGION_FLAT( \
+ PLAT_ARM_NVM_BASE, \
+ PLAT_ARM_NVM_SIZE, \
+ MT_DEVICE | MT_RO | MT_SECURE)
+
+#define ARM_MAP_SHARED_RAM MAP_REGION_FLAT( \
+ ARM_SHARED_RAM_BASE, \
+ ARM_SHARED_RAM_SIZE, \
+ MT_MEMORY | MT_RW | MT_SECURE)
+
+#define ARM_MAP_NS_SHARED_RAM MAP_REGION_FLAT( \
+ ARM_NS_SHARED_RAM_BASE, \
+ ARM_NS_SHARED_RAM_SIZE, \
+ MT_MEMORY | MT_RW | MT_NS)
+
+#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
+
+/*
+ * Map the region for the optional device tree configuration with read and
+ * write permissions
+ */
+#define ARM_MAP_BL_CONFIG_REGION MAP_REGION_FLAT( \
+ ARM_FW_CONFIG_BASE, \
+ (ARM_FW_CONFIG_LIMIT \
+ - ARM_FW_CONFIG_BASE), \
+ MT_MEMORY | MT_RW | MT_SECURE)
+
+#define CORSTONE1000_DEVICE_BASE (0x1A000000)
+#define CORSTONE1000_DEVICE_SIZE (0x26000000)
+#define CORSTONE1000_MAP_DEVICE MAP_REGION_FLAT( \
+ CORSTONE1000_DEVICE_BASE, \
+ CORSTONE1000_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(CORSTONE1000_IRQ_TZ_WDOG, \
+ GIC_HIGHEST_SEC_PRIORITY, \
+ (grp), GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(CORSTONE1000_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 */
diff --git a/plat/arm/board/corstone1000/include/plat_macros.S b/plat/arm/board/corstone1000/include/plat_macros.S
new file mode 100644
index 0000000..9334201
--- /dev/null
+++ b/plat/arm/board/corstone1000/include/plat_macros.S
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <css_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
+ css_print_gic_regs
+ .endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/arm/board/corstone1000/platform.mk b/plat/arm/board/corstone1000/platform.mk
new file mode 100644
index 0000000..d891691
--- /dev/null
+++ b/plat/arm/board/corstone1000/platform.mk
@@ -0,0 +1,83 @@
+#
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Making sure the corstone1000 platform type is specified
+ifeq ($(filter ${TARGET_PLATFORM}, fpga fvp),)
+ $(error TARGET_PLATFORM must be fpga or fvp)
+endif
+
+CORSTONE1000_CPU_LIBS +=lib/cpus/aarch64/cortex_a35.S
+
+PLAT_INCLUDES := -Iplat/arm/board/corstone1000/common/include \
+ -Iplat/arm/board/corstone1000/include \
+ -Iinclude/plat/arm/common \
+ -Iinclude/plat/arm/css/common/aarch64
+
+
+CORSTONE1000_FW_NVCTR_VAL := 255
+TFW_NVCTR_VAL := ${CORSTONE1000_FW_NVCTR_VAL}
+NTFW_NVCTR_VAL := ${CORSTONE1000_FW_NVCTR_VAL}
+
+override NEED_BL1 := no
+
+override NEED_BL2 := yes
+FIP_BL2_ARGS := tb-fw
+
+override NEED_BL2U := no
+override NEED_BL31 := yes
+NEED_BL32 := yes
+override NEED_BL33 := yes
+
+# Include GICv2 driver files
+include drivers/arm/gic/v2/gicv2.mk
+
+CORSTONE1000_GIC_SOURCES := ${GICV2_SOURCES} \
+ plat/common/plat_gicv2.c \
+ plat/arm/common/arm_gicv2.c
+
+
+BL2_SOURCES += plat/arm/board/corstone1000/common/corstone1000_security.c \
+ plat/arm/board/corstone1000/common/corstone1000_err.c \
+ plat/arm/board/corstone1000/common/corstone1000_trusted_boot.c \
+ lib/utils/mem_region.c \
+ plat/arm/board/corstone1000/common/corstone1000_helpers.S \
+ plat/arm/board/corstone1000/common/corstone1000_plat.c \
+ plat/arm/board/corstone1000/common/corstone1000_bl2_mem_params_desc.c \
+ ${CORSTONE1000_CPU_LIBS} \
+
+
+BL31_SOURCES += drivers/cfi/v2m/v2m_flash.c \
+ lib/utils/mem_region.c \
+ plat/arm/board/corstone1000/common/corstone1000_helpers.S \
+ plat/arm/board/corstone1000/common/corstone1000_topology.c \
+ plat/arm/board/corstone1000/common/corstone1000_security.c \
+ plat/arm/board/corstone1000/common/corstone1000_plat.c \
+ plat/arm/board/corstone1000/common/corstone1000_pm.c \
+ ${CORSTONE1000_CPU_LIBS} \
+ ${CORSTONE1000_GIC_SOURCES}
+
+ifneq (${ENABLE_STACK_PROTECTOR},0)
+ ifneq (${ENABLE_STACK_PROTECTOR},none)
+ CORSTONE1000_SECURITY_SOURCES := plat/arm/board/corstone1000/common/corstone1000_stack_protector.c
+ BL2_SOURCES += ${CORSTONE1000_SECURITY_SOURCES}
+ BL31_SOURCES += ${CORSTONE1000_SECURITY_SOURCES}
+ endif
+endif
+
+FDT_SOURCES += plat/arm/board/corstone1000/common/fdts/corstone1000_spmc_manifest.dts
+CORSTONE1000_TOS_FW_CONFIG := ${BUILD_PLAT}/fdts/corstone1000_spmc_manifest.dtb
+
+# Add the SPMC manifest to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${CORSTONE1000_TOS_FW_CONFIG},--tos-fw-config,${CORSTONE1000_TOS_FW_CONFIG}))
+
+# Adding TARGET_PLATFORM as a GCC define (-D option)
+$(eval $(call add_define,TARGET_PLATFORM_$(call uppercase,${TARGET_PLATFORM})))
+
+# Adding CORSTONE1000_FW_NVCTR_VAL as a GCC define (-D option)
+$(eval $(call add_define,CORSTONE1000_FW_NVCTR_VAL))
+
+include plat/arm/common/arm_common.mk
+include plat/arm/board/common/board_common.mk
diff --git a/plat/arm/board/corstone700/common/corstone700_helpers.S b/plat/arm/board/corstone700/common/corstone700_helpers.S
new file mode 100644
index 0000000..c713f4f
--- /dev/null
+++ b/plat/arm/board/corstone700/common/corstone700_helpers.S
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/arm/board/corstone700/common/corstone700_plat.c b/plat/arm/board/corstone700/common/corstone700_plat.c
new file mode 100644
index 0000000..dd7531d
--- /dev/null
+++ b/plat/arm/board/corstone700/common/corstone700_plat.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+
+#include <corstone700_mhu.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_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,
+ ARM_MAP_NS_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)
+{
+ mhu_secure_init();
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+ /* Returning the Generic Timer Frequency */
+ return SYS_COUNTER_FREQ_IN_TICKS;
+}
diff --git a/plat/arm/board/corstone700/common/corstone700_pm.c b/plat/arm/board/corstone700/common/corstone700_pm.c
new file mode 100644
index 0000000..4884ea5
--- /dev/null
+++ b/plat/arm/board/corstone700/common/corstone700_pm.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+
+/*******************************************************************************
+ * 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;
+}
diff --git a/plat/arm/board/corstone700/common/corstone700_security.c b/plat/arm/board/corstone700/common/corstone700_security.c
new file mode 100644
index 0000000..39b2fc9
--- /dev/null
+++ b/plat/arm/board/corstone700/common/corstone700_security.c
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */
+}
diff --git a/plat/arm/board/corstone700/common/corstone700_stack_protector.c b/plat/arm/board/corstone700/common/corstone700_stack_protector.c
new file mode 100644
index 0000000..6fd09da
--- /dev/null
+++ b/plat/arm/board/corstone700/common/corstone700_stack_protector.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <plat/common/platform.h>
+
+static uint32_t plat_generate_random_number(void)
+{
+ uintptr_t return_addr = (uintptr_t)__builtin_return_address(0U);
+ uintptr_t frame_addr = (uintptr_t)__builtin_frame_address(0U);
+ uint64_t cntpct = read_cntpct_el0();
+
+ /* Generate 32-bit pattern: saving the 2 least significant bytes
+ * in random_lo and random_hi
+ */
+ uint16_t random_lo = (uint16_t)(
+ (((uint64_t)return_addr) << 13) ^ frame_addr ^ cntpct
+ );
+
+ uint16_t random_hi = (uint16_t)(
+ (((uint64_t)frame_addr) << 15) ^ return_addr ^ cntpct
+ );
+
+ return (((uint32_t)random_hi) << 16) | random_lo;
+}
+
+u_register_t plat_get_stack_protector_canary(void)
+{
+ return plat_generate_random_number(); /* a 32-bit pattern is returned */
+}
diff --git a/plat/arm/board/corstone700/common/corstone700_topology.c b/plat/arm/board/corstone700/common/corstone700_topology.c
new file mode 100644
index 0000000..904f5ab
--- /dev/null
+++ b/plat/arm/board/corstone700/common/corstone700_topology.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/* 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);
+}
diff --git a/plat/arm/board/corstone700/common/drivers/mhu/corstone700_mhu.c b/plat/arm/board/corstone700/common/drivers/mhu/corstone700_mhu.c
new file mode 100644
index 0000000..832cfb7
--- /dev/null
+++ b/plat/arm/board/corstone700/common/drivers/mhu/corstone700_mhu.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include "corstone700_mhu.h"
+#include <plat_arm.h>
+#include <platform_def.h>
+
+ARM_INSTANTIATE_LOCK;
+
+#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(uintptr_t address, unsigned int slot_id)
+{
+ unsigned int intr_stat_check;
+ uint64_t timeout_cnt;
+ volatile uint8_t expiration;
+
+ assert(slot_id <= MHU_MAX_SLOT_ID);
+ arm_lock_get();
+
+ /*
+ * Make sure any previous command has finished
+ * and polling timeout not expired
+ */
+
+ timeout_cnt = timeout_init_us(MHU_POLL_INTR_STAT_TIMEOUT);
+
+ do {
+ intr_stat_check = (mmio_read_32(address + CPU_INTR_S_STAT) &
+ (1 << slot_id));
+
+ expiration = timeout_elapsed(timeout_cnt);
+
+ } while ((intr_stat_check != 0U) && (expiration == 0U));
+
+ /*
+ * Note: No risk of timer overflows while waiting
+ * for the timeout expiration.
+ * According to Armv8 TRM: System counter roll-over
+ * time of not less than 40 years
+ */
+}
+
+void mhu_secure_message_send(uintptr_t address,
+ unsigned int slot_id,
+ unsigned int message)
+{
+ unsigned char access_ready;
+ uint64_t timeout_cnt;
+ volatile uint8_t expiration;
+
+ assert(slot_id <= MHU_MAX_SLOT_ID);
+ assert((mmio_read_32(address + CPU_INTR_S_STAT) &
+ (1 << slot_id)) == 0U);
+
+ MHU_V2_ACCESS_REQUEST(address);
+
+ timeout_cnt = timeout_init_us(MHU_POLL_INTR_STAT_TIMEOUT);
+
+ do {
+ access_ready = MHU_V2_IS_ACCESS_READY(address);
+ expiration = timeout_elapsed(timeout_cnt);
+
+ } while ((access_ready == 0U) && (expiration == 0U));
+
+ /*
+ * Note: No risk of timer overflows while waiting
+ * for the timeout expiration.
+ * According to Armv8 TRM: System counter roll-over
+ * time of not less than 40 years
+ */
+
+ mmio_write_32(address + CPU_INTR_S_SET, message);
+}
+
+void mhu_secure_message_end(uintptr_t address, 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
+ */
+ MHU_V2_CLEAR_REQUEST(address);
+
+ 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_SDK700_MHU0_SEND + CPU_INTR_S_STAT) == 0);
+}
diff --git a/plat/arm/board/corstone700/common/drivers/mhu/corstone700_mhu.h b/plat/arm/board/corstone700/common/drivers/mhu/corstone700_mhu.h
new file mode 100644
index 0000000..7f14ca5
--- /dev/null
+++ b/plat/arm/board/corstone700/common/drivers/mhu/corstone700_mhu.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORSTONE700_MHU_H
+#define CORSTONE700_MHU_H
+
+#define MHU_POLL_INTR_STAT_TIMEOUT 50000 /*timeout value in us*/
+
+/* CPU MHU secure channel registers */
+#define CPU_INTR_S_STAT 0x00
+#define CPU_INTR_S_SET 0x0C
+
+/* MHUv2 Control Registers Offsets */
+#define MHU_V2_MSG_CFG_OFFSET 0xF80
+#define MHU_V2_ACCESS_REQ_OFFSET 0xF88
+#define MHU_V2_ACCESS_READY_OFFSET 0xF8C
+
+#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)
+
+void mhu_secure_message_start(uintptr_t address, unsigned int slot_id);
+void mhu_secure_message_send(uintptr_t address,
+ unsigned int slot_id,
+ unsigned int message);
+void mhu_secure_message_end(uintptr_t address, unsigned int slot_id);
+void mhu_secure_init(void);
+
+#endif /* CORSTONE700_MHU_H */
diff --git a/plat/arm/board/corstone700/common/include/platform_def.h b/plat/arm/board/corstone700/common/include/platform_def.h
new file mode 100644
index 0000000..57b0551
--- /dev/null
+++ b/plat/arm/board/corstone700/common/include/platform_def.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/common/arm_spm_def.h>
+#include <plat/arm/common/smccc_def.h>
+#include <plat/common/common_def.h>
+
+/* PL011 UART related constants */
+#ifdef V2M_IOFPGA_UART0_CLK_IN_HZ
+#undef V2M_IOFPGA_UART0_CLK_IN_HZ
+#endif
+
+#ifdef V2M_IOFPGA_UART1_CLK_IN_HZ
+#undef V2M_IOFPGA_UART1_CLK_IN_HZ
+#endif
+
+#define V2M_IOFPGA_UART0_CLK_IN_HZ 32000000
+#define V2M_IOFPGA_UART1_CLK_IN_HZ 32000000
+
+/* Core/Cluster/Thread counts for Corstone700 */
+#define CORSTONE700_CLUSTER_COUNT U(1)
+#define CORSTONE700_MAX_CPUS_PER_CLUSTER U(4)
+#define CORSTONE700_MAX_PE_PER_CPU U(1)
+
+#define PLAT_ARM_CLUSTER_COUNT CORSTONE700_CLUSTER_COUNT
+
+#define PLATFORM_CORE_COUNT (PLAT_ARM_CLUSTER_COUNT * \
+ CORSTONE700_MAX_CPUS_PER_CLUSTER * \
+ CORSTONE700_MAX_PE_PER_CPU)
+
+
+/* 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)
+
+#define ARM_NS_SHARED_RAM_BASE ARM_TRUSTED_SRAM_BASE + UL(0x00100000)
+#define ARM_NS_SHARED_RAM_SIZE 0x00300000
+
+/*
+ * 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 FW_CONFIG to be loaded by BL1, define the corresponding base
+ * and limit. Leave enough space for BL2 meminfo.
+ */
+#define ARM_FW_CONFIG_BASE (ARM_BL_RAM_BASE + sizeof(meminfo_t))
+#define ARM_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_FW_CONFIG_LIMIT)
+#define ARM_BL2_MEM_DESC_LIMIT (ARM_BL2_MEM_DESC_BASE \
+ + (PAGE_SIZE / 2U))
+
+/*
+ * Define limit of firmware configuration memory:
+ * ARM_FW_CONFIG + ARM_BL2_MEM_DESC memory
+ */
+#define ARM_FW_CONFIGS_LIMIT (ARM_BL_RAM_BASE + (PAGE_SIZE * 2))
+
+/*
+ * 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 3
+#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
+
+/* MHUv2 Secure Channel receiver and sender */
+#define PLAT_SDK700_MHU0_SEND 0x1B800000
+#define PLAT_SDK700_MHU0_RECV 0x1B810000
+
+/* 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)
+
+#ifdef TARGET_PLATFORM_FVP
+#define SYS_COUNTER_FREQ_IN_TICKS UL(50000000) /* 50MHz */
+#else
+#define SYS_COUNTER_FREQ_IN_TICKS UL(32000000) /* 32MHz */
+#endif
+
+#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_BASE (ARM_NS_SHARED_RAM_BASE)
+
+#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_MEMORY | MT_RW | MT_SECURE)
+
+#define ARM_MAP_NS_SHARED_RAM MAP_REGION_FLAT( \
+ ARM_NS_SHARED_RAM_BASE, \
+ ARM_NS_SHARED_RAM_SIZE, \
+ MT_MEMORY | MT_RW | MT_NS)
+
+#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
+
+/*
+ * Map the region for device tree configuration with read and write permissions
+ */
+#define ARM_MAP_BL_CONFIG_REGION MAP_REGION_FLAT(ARM_BL_RAM_BASE, \
+ (ARM_FW_CONFIGS_LIMIT \
+ - ARM_BL_RAM_BASE), \
+ MT_MEMORY | MT_RW | MT_SECURE)
+
+#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 */
diff --git a/plat/arm/board/corstone700/platform.mk b/plat/arm/board/corstone700/platform.mk
new file mode 100644
index 0000000..75833f6
--- /dev/null
+++ b/plat/arm/board/corstone700/platform.mk
@@ -0,0 +1,63 @@
+#
+# Copyright (c) 2019-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Making sure the corstone700 platform type is specified
+ifeq ($(filter ${TARGET_PLATFORM}, fpga fvp),)
+ $(error TARGET_PLATFORM must be fpga or fvp)
+endif
+
+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/arm/board/corstone700/common/drivers/mhu/corstone700_mhu.c
+
+PLAT_INCLUDES := -Iplat/arm/board/corstone700/common/include \
+ -Iinclude/plat/arm/common \
+ -Iplat/arm/board/corstone700/common/drivers/mhu
+
+NEED_BL32 := yes
+
+# Include GICv2 driver files
+include drivers/arm/gic/v2/gicv2.mk
+
+CORSTONE700_GIC_SOURCES := ${GICV2_SOURCES} \
+ 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
+override NEED_BL33 := yes
+
+#TFA for Corstone700 starts from BL32
+override RESET_TO_SP_MIN := 1
+
+#Device tree
+CORSTONE700_HW_CONFIG_DTS := fdts/corstone700_${TARGET_PLATFORM}.dts
+CORSTONE700_HW_CONFIG := ${BUILD_PLAT}/fdts/corstone700_${TARGET_PLATFORM}.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,${CORSTONE700_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))
+
+# Adding TARGET_PLATFORM as a GCC define (-D option)
+$(eval $(call add_define,TARGET_PLATFORM_$(call uppercase,${TARGET_PLATFORM})))
+
+include plat/arm/board/common/board_common.mk
diff --git a/plat/arm/board/corstone700/sp_min/corstone700_sp_min_setup.c b/plat/arm/board/corstone700/sp_min/corstone700_sp_min_setup.c
new file mode 100644
index 0000000..2fc0e0d
--- /dev/null
+++ b/plat/arm/board/corstone700/sp_min/corstone700_sp_min_setup.c
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.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);
+}
diff --git a/plat/arm/board/corstone700/sp_min/sp_min-corstone700.mk b/plat/arm/board/corstone700/sp_min/sp_min-corstone700.mk
new file mode 100644
index 0000000..75dc0f1
--- /dev/null
+++ b/plat/arm/board/corstone700/sp_min/sp_min-corstone700.mk
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2019-2020, 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/common/corstone700_helpers.S \
+ plat/arm/board/corstone700/common/corstone700_topology.c \
+ plat/arm/board/corstone700/common/corstone700_security.c \
+ plat/arm/board/corstone700/common/corstone700_plat.c \
+ plat/arm/board/corstone700/common/corstone700_pm.c \
+ plat/arm/board/corstone700/sp_min/corstone700_sp_min_setup.c \
+ ${CORSTONE700_GIC_SOURCES}
+
+ifneq (${ENABLE_STACK_PROTECTOR},0)
+ ifneq (${ENABLE_STACK_PROTECTOR},none)
+ BL32_SOURCES += plat/arm/board/corstone700/common/corstone700_stack_protector.c
+ endif
+endif
+
+include plat/arm/common/sp_min/arm_sp_min.mk
diff --git a/plat/arm/board/fvp/aarch32/fvp_helpers.S b/plat/arm/board/fvp/aarch32/fvp_helpers.S
new file mode 100644
index 0000000..9985c1d
--- /dev/null
+++ b/plat/arm/board/fvp/aarch32/fvp_helpers.S
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/fvp/fvp_pwrc.h>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/arm/board/fvp/aarch64/fvp_helpers.S b/plat/arm/board/fvp/aarch64/fvp_helpers.S
new file mode 100644
index 0000000..8efc238
--- /dev/null
+++ b/plat/arm/board/fvp/aarch64/fvp_helpers.S
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/arm/fvp/fvp_pwrc.h>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/arm/board/fvp/aarch64/fvp_ras.c b/plat/arm/board/fvp/aarch64/fvp_ras.c
new file mode 100644
index 0000000..759f6d0
--- /dev/null
+++ b/plat/arm/board/fvp/aarch64/fvp_ras.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/extensions/ras.h>
+
+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);
diff --git a/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c b/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c
new file mode 100644
index 0000000..45e3b7e
--- /dev/null
+++ b/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <fconf_hw_config_getter.h>
+#include <libfdt.h>
+#include <plat/common/platform.h>
+
+struct gicv3_config_t gicv3_config;
+struct hw_topology_t soc_topology;
+struct uart_serial_config_t uart_serial_config;
+struct cpu_timer_t cpu_timer;
+
+#define ILLEGAL_ADDR ULL(~0)
+
+int fconf_populate_gicv3_config(uintptr_t config)
+{
+ int err;
+ int node;
+ uintptr_t addr;
+
+ /* Necessary to work with libfdt APIs */
+ const void *hw_config_dtb = (const void *)config;
+
+ /*
+ * Find the offset of the node containing "arm,gic-v3" compatible property.
+ * Populating fconf strucutures dynamically is not supported for legacy
+ * systems which use GICv2 IP. Simply skip extracting GIC properties.
+ */
+ node = fdt_node_offset_by_compatible(hw_config_dtb, -1, "arm,gic-v3");
+ if (node < 0) {
+ WARN("FCONF: Unable to locate node with arm,gic-v3 compatible property\n");
+ return 0;
+ }
+ /* The GICv3 DT binding holds at least two address/size pairs,
+ * the first describing the distributor, the second the redistributors.
+ * See: bindings/interrupt-controller/arm,gic-v3.yaml
+ */
+ err = fdt_get_reg_props_by_index(hw_config_dtb, node, 0, &addr, NULL);
+ if (err < 0) {
+ ERROR("FCONF: Failed to read GICD reg property of GIC node\n");
+ return err;
+ }
+ gicv3_config.gicd_base = addr;
+
+ err = fdt_get_reg_props_by_index(hw_config_dtb, node, 1, &addr, NULL);
+ if (err < 0) {
+ ERROR("FCONF: Failed to read GICR reg property of GIC node\n");
+ } else {
+ gicv3_config.gicr_base = addr;
+ }
+
+ return err;
+}
+
+int fconf_populate_topology(uintptr_t config)
+{
+ int err, node, cluster_node, core_node, thread_node;
+ uint32_t cluster_count = 0, max_cpu_per_cluster = 0, total_cpu_count = 0;
+ uint32_t max_pwr_lvl = 0;
+
+ /* Necessary to work with libfdt APIs */
+ const void *hw_config_dtb = (const void *)config;
+
+ /* Find the offset of the node containing "arm,psci-1.0" compatible property */
+ node = fdt_node_offset_by_compatible(hw_config_dtb, -1, "arm,psci-1.0");
+ if (node < 0) {
+ ERROR("FCONF: Unable to locate node with arm,psci-1.0 compatible property\n");
+ return node;
+ }
+
+ err = fdt_read_uint32(hw_config_dtb, node, "max-pwr-lvl", &max_pwr_lvl);
+ if (err < 0) {
+ /*
+ * Some legacy FVP dts may not have this property. Assign the default
+ * value.
+ */
+ WARN("FCONF: Could not locate max-pwr-lvl property\n");
+ max_pwr_lvl = 2;
+ }
+
+ assert(max_pwr_lvl <= MPIDR_AFFLVL2);
+
+ /* Find the offset of the "cpus" node */
+ node = fdt_path_offset(hw_config_dtb, "/cpus");
+ if (node < 0) {
+ ERROR("FCONF: Node '%s' not found in hardware configuration dtb\n", "cpus");
+ return node;
+ }
+
+ /* A typical cpu-map node in a device tree is shown here for reference
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&CPU0>;
+ };
+ core1 {
+ cpu = <&CPU1>;
+ };
+ };
+
+ cluster1 {
+ core0 {
+ cpu = <&CPU2>;
+ };
+ core1 {
+ cpu = <&CPU3>;
+ };
+ };
+ };
+ */
+
+ /* Locate the cpu-map child node */
+ node = fdt_subnode_offset(hw_config_dtb, node, "cpu-map");
+ if (node < 0) {
+ ERROR("FCONF: Node '%s' not found in hardware configuration dtb\n", "cpu-map");
+ return node;
+ }
+
+ uint32_t cpus_per_cluster[PLAT_ARM_CLUSTER_COUNT] = {0};
+
+ /* Iterate through cluster nodes */
+ fdt_for_each_subnode(cluster_node, hw_config_dtb, node) {
+ assert(cluster_count < PLAT_ARM_CLUSTER_COUNT);
+
+ /* Iterate through core nodes */
+ fdt_for_each_subnode(core_node, hw_config_dtb, cluster_node) {
+ /* core nodes may have child nodes i.e., "thread" nodes */
+ if (fdt_first_subnode(hw_config_dtb, core_node) < 0) {
+ cpus_per_cluster[cluster_count]++;
+ } else {
+ /* Multi-threaded CPU description is found in dtb */
+ fdt_for_each_subnode(thread_node, hw_config_dtb, core_node) {
+ cpus_per_cluster[cluster_count]++;
+ }
+
+ /* Since in some dtbs, core nodes may not have thread node,
+ * no need to error if even one child node is not found.
+ */
+ }
+ }
+
+ /* Ensure every cluster node has at least 1 child node */
+ if (cpus_per_cluster[cluster_count] < 1U) {
+ ERROR("FCONF: Unable to locate the core node in cluster %d\n", cluster_count);
+ return -1;
+ }
+
+ VERBOSE("CLUSTER ID: %d cpu-count: %d\n", cluster_count,
+ cpus_per_cluster[cluster_count]);
+
+ /* Find the maximum number of cpus in any cluster */
+ max_cpu_per_cluster = MAX(max_cpu_per_cluster, cpus_per_cluster[cluster_count]);
+ total_cpu_count += cpus_per_cluster[cluster_count];
+ cluster_count++;
+ }
+
+
+ /* At least one cluster node is expected in hardware configuration dtb */
+ if (cluster_count < 1U) {
+ ERROR("FCONF: Unable to locate the cluster node in cpu-map node\n");
+ return -1;
+ }
+
+ soc_topology.plat_max_pwr_level = max_pwr_lvl;
+ soc_topology.plat_cluster_count = cluster_count;
+ soc_topology.cluster_cpu_count = max_cpu_per_cluster;
+ soc_topology.plat_cpu_count = total_cpu_count;
+
+ return 0;
+}
+
+int fconf_populate_uart_config(uintptr_t config)
+{
+ int uart_node, node, err;
+ uintptr_t addr;
+ const char *path;
+ uint32_t phandle;
+ uint64_t translated_addr;
+
+ /* Necessary to work with libfdt APIs */
+ const void *hw_config_dtb = (const void *)config;
+
+ /*
+ * uart child node is indirectly referenced through its path which is
+ * specified in the `serial1` property of the "aliases" node.
+ * Note that TF-A boot console is mapped to serial0 while runtime
+ * console is mapped to serial1.
+ */
+
+ path = fdt_get_alias(hw_config_dtb, "serial1");
+ if (path == NULL) {
+ ERROR("FCONF: Could not read serial1 property in aliases node\n");
+ return -1;
+ }
+
+ /* Find the offset of the uart serial node */
+ uart_node = fdt_path_offset(hw_config_dtb, path);
+ if (uart_node < 0) {
+ ERROR("FCONF: Failed to locate uart serial node using its path\n");
+ return -1;
+ }
+
+ /* uart serial node has its offset and size of address in reg property */
+ err = fdt_get_reg_props_by_index(hw_config_dtb, uart_node, 0, &addr,
+ NULL);
+ if (err < 0) {
+ ERROR("FCONF: Failed to read reg property of '%s' node\n",
+ "uart serial");
+ return err;
+ }
+ VERBOSE("FCONF: UART node address: %lx\n", addr);
+
+ /*
+ * Perform address translation of local device address to CPU address
+ * domain.
+ */
+ translated_addr = fdtw_translate_address(hw_config_dtb,
+ uart_node, (uint64_t)addr);
+ if (translated_addr == ILLEGAL_ADDR) {
+ ERROR("FCONF: failed to translate UART node base address");
+ return -1;
+ }
+
+ uart_serial_config.uart_base = translated_addr;
+
+ VERBOSE("FCONF: UART serial device base address: %" PRIx64 "\n",
+ uart_serial_config.uart_base);
+
+ /*
+ * The phandle of the DT node which captures the clock info of uart
+ * serial node is specified in the "clocks" property.
+ */
+ err = fdt_read_uint32(hw_config_dtb, uart_node, "clocks", &phandle);
+ if (err < 0) {
+ ERROR("FCONF: Could not read clocks property in uart serial node\n");
+ return err;
+ }
+
+ node = fdt_node_offset_by_phandle(hw_config_dtb, phandle);
+ if (node < 0) {
+ ERROR("FCONF: Failed to locate clk node using its path\n");
+ return node;
+ }
+
+ /*
+ * Retrieve clock frequency. We assume clock provider generates a fixed
+ * clock.
+ */
+ err = fdt_read_uint32(hw_config_dtb, node, "clock-frequency",
+ &uart_serial_config.uart_clk);
+ if (err < 0) {
+ ERROR("FCONF: Could not read clock-frequency property in clk node\n");
+ return err;
+ }
+
+ VERBOSE("FCONF: UART serial device clk frequency: %x\n",
+ uart_serial_config.uart_clk);
+
+ return 0;
+}
+
+int fconf_populate_cpu_timer(uintptr_t config)
+{
+ int err, node;
+
+ /* Necessary to work with libfdt APIs */
+ const void *hw_config_dtb = (const void *)config;
+
+ /* Find the node offset point to "arm,armv8-timer" compatible property,
+ * a per-core architected timer attached to a GIC to deliver its per-processor
+ * interrupts via PPIs */
+ node = fdt_node_offset_by_compatible(hw_config_dtb, -1, "arm,armv8-timer");
+ if (node < 0) {
+ ERROR("FCONF: Unrecognized hardware configuration dtb (%d)\n", node);
+ return node;
+ }
+
+ /* Locate the cell holding the clock-frequency, an optional field */
+ err = fdt_read_uint32(hw_config_dtb, node, "clock-frequency", &cpu_timer.clock_freq);
+ if (err < 0) {
+ WARN("FCONF failed to read clock-frequency property\n");
+ }
+
+ return 0;
+}
+
+FCONF_REGISTER_POPULATOR(HW_CONFIG, gicv3_config, fconf_populate_gicv3_config);
+FCONF_REGISTER_POPULATOR(HW_CONFIG, topology, fconf_populate_topology);
+FCONF_REGISTER_POPULATOR(HW_CONFIG, uart_config, fconf_populate_uart_config);
+FCONF_REGISTER_POPULATOR(HW_CONFIG, cpu_timer, fconf_populate_cpu_timer);
diff --git a/plat/arm/board/fvp/fconf/fconf_nt_config_getter.c b/plat/arm/board/fvp/fconf/fconf_nt_config_getter.c
new file mode 100644
index 0000000..e258015
--- /dev/null
+++ b/plat/arm/board/fvp/fconf/fconf_nt_config_getter.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+
+#include <libfdt.h>
+#include <fconf_nt_config_getter.h>
+
+#include <plat/common/platform.h>
+
+struct event_log_config_t event_log_config;
+
+int fconf_populate_event_log_config(uintptr_t config)
+{
+ int err;
+ int node;
+
+ /* Necessary to work with libfdt APIs */
+ const void *dtb = (const void *)config;
+
+ /*
+ * Find the offset of the node containing "arm,tpm_event_log"
+ * compatible property
+ */
+ const char *compatible_str = "arm,tpm_event_log";
+
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
+ if (node < 0) {
+ ERROR("FCONF: Can't find '%s' compatible in dtb\n",
+ compatible_str);
+ return node;
+ }
+
+ /* Retrieve Event Log details from the DTB */
+#ifdef SPD_opteed
+ err = fdtw_read_cells(dtb, node, "tpm_event_log_sm_addr", 2,
+ &event_log_config.tpm_event_log_sm_addr);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'tpm_event_log_sm_addr'\n");
+ return err;
+ }
+#endif
+ err = fdtw_read_cells(dtb, node,
+ "tpm_event_log_addr", 2, &event_log_config.tpm_event_log_addr);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'tpm_event_log_addr'\n");
+ return err;
+ }
+
+ err = fdtw_read_cells(dtb, node,
+ "tpm_event_log_size", 1, &event_log_config.tpm_event_log_size);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'tpm_event_log_size'\n");
+ }
+
+ return err;
+}
+
+FCONF_REGISTER_POPULATOR(NT_CONFIG, event_log_config,
+ fconf_populate_event_log_config);
diff --git a/plat/arm/board/fvp/fdts/event_log.dtsi b/plat/arm/board/fvp/fdts/event_log.dtsi
new file mode 100644
index 0000000..47af672
--- /dev/null
+++ b/plat/arm/board/fvp/fdts/event_log.dtsi
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2020, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* TPM Event Log Config */
+event_log: tpm_event_log {
+ compatible = "arm,tpm_event_log";
+ tpm_event_log_addr = <0x0 0x0>;
+ tpm_event_log_size = <0x0>;
+};
diff --git a/plat/arm/board/fvp/fdts/fvp_fw_config.dts b/plat/arm/board/fvp/fdts/fvp_fw_config.dts
new file mode 100644
index 0000000..577ac74
--- /dev/null
+++ b/plat/arm/board/fvp/fdts/fvp_fw_config.dts
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/tbbr/tbbr_img_def.h>
+
+/dts-v1/;
+
+/ {
+ dtb-registry {
+ compatible = "fconf,dyn_cfg-dtb_registry";
+
+ tb_fw-config {
+ load-address = <0x0 0x4001300>;
+ max-size = <0x1800>;
+ id = <TB_FW_CONFIG_ID>;
+ };
+
+ hw-config {
+ load-address = <0x0 0x07f00000>;
+ max-size = <0x00100000>;
+ id = <HW_CONFIG_ID>;
+ ns-load-address = <0x0 0x82000000>;
+ };
+
+ /*
+ * 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 {
+ load-address = <0x0 0x04001300>;
+ max-size = <0x200>;
+ id = <SOC_FW_CONFIG_ID>;
+ };
+
+/* If required, SPD should enable loading of trusted OS fw config */
+#if defined(SPD_tspd) || defined(SPD_spmd)
+ tos_fw-config {
+ load-address = <0x0 0x04001500>;
+ max-size = <0xB00>;
+ id = <TOS_FW_CONFIG_ID>;
+ };
+#endif
+
+ nt_fw-config {
+ load-address = <0x0 0x80000000>;
+ max-size = <0x200>;
+ id = <NT_FW_CONFIG_ID>;
+ };
+ };
+};
diff --git a/plat/arm/board/fvp/fdts/fvp_nt_fw_config.dts b/plat/arm/board/fvp/fdts/fvp_nt_fw_config.dts
new file mode 100644
index 0000000..8f32b98
--- /dev/null
+++ b/plat/arm/board/fvp/fdts/fvp_nt_fw_config.dts
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+#if MEASURED_BOOT
+#include "event_log.dtsi"
+#endif
+};
+
+#if MEASURED_BOOT && defined(SPD_opteed)
+&event_log {
+ tpm_event_log_sm_addr = <0x0 0x0>;
+};
+#endif
diff --git a/plat/arm/board/fvp/fdts/fvp_soc_fw_config.dts b/plat/arm/board/fvp/fdts/fvp_soc_fw_config.dts
new file mode 100644
index 0000000..7ab980b
--- /dev/null
+++ b/plat/arm/board/fvp/fdts/fvp_soc_fw_config.dts
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+
+};
diff --git a/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts b/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
new file mode 100644
index 0000000..4543671
--- /dev/null
+++ b/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/dts-v1/;
+
+#define AFF 00
+
+#include "fvp-defs.dtsi"
+#undef POST
+#define POST \
+ };
+
+/ {
+ compatible = "arm,ffa-core-manifest-1.0";
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ attribute {
+ spmc_id = <0x8000>;
+ maj_ver = <0x1>;
+ min_ver = <0x1>;
+ exec_state = <0x0>;
+ load_address = <0x0 0x6000000>;
+ entrypoint = <0x0 0x6000000>;
+ binary_size = <0x80000>;
+ };
+
+ hypervisor {
+ compatible = "hafnium,hafnium";
+ vm1 {
+ is_ffa_partition;
+ debug_name = "cactus-primary";
+ load_address = <0x7000000>;
+ vcpu_count = <8>;
+ mem_size = <1048576>;
+ };
+ vm2 {
+ is_ffa_partition;
+ debug_name = "cactus-secondary";
+ load_address = <0x7100000>;
+ vcpu_count = <8>;
+ mem_size = <1048576>;
+ };
+ vm3 {
+ is_ffa_partition;
+ debug_name = "cactus-tertiary";
+ load_address = <0x7200000>;
+ vcpu_count = <1>;
+ mem_size = <1048576>;
+ };
+ vm4 {
+ is_ffa_partition;
+ debug_name = "ivy";
+ load_address = <0x7600000>;
+ vcpu_count = <1>;
+ mem_size = <1048576>;
+ };
+ };
+
+ cpus {
+ #address-cells = <0x2>;
+ #size-cells = <0x0>;
+
+ CPU_0
+
+ /*
+ * SPMC (Hafnium) requires secondary core nodes are declared
+ * in descending order.
+ */
+ CPU_7
+ CPU_6
+ CPU_5
+ CPU_4
+ CPU_3
+ CPU_2
+ CPU_1
+ };
+
+ memory@6000000 {
+ device_type = "memory";
+ reg = <0x0 0x6000000 0x2000000>; /* Trusted DRAM */
+ };
+
+#if MEASURED_BOOT
+#include "event_log.dtsi"
+#endif
+};
diff --git a/plat/arm/board/fvp/fdts/fvp_spmc_optee_sp_manifest.dts b/plat/arm/board/fvp/fdts/fvp_spmc_optee_sp_manifest.dts
new file mode 100644
index 0000000..041dade
--- /dev/null
+++ b/plat/arm/board/fvp/fdts/fvp_spmc_optee_sp_manifest.dts
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/dts-v1/;
+
+#define AFF 00
+
+#include "fvp-defs.dtsi"
+#undef POST
+#define POST \
+ };
+
+/ {
+ compatible = "arm,ffa-core-manifest-1.0";
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ attribute {
+ spmc_id = <0x8000>;
+ maj_ver = <0x1>;
+ min_ver = <0x1>;
+ exec_state = <0x0>;
+ load_address = <0x0 0x6000000>;
+ entrypoint = <0x0 0x6000000>;
+ binary_size = <0x80000>;
+ };
+
+ hypervisor {
+ compatible = "hafnium,hafnium";
+ vm1 {
+ is_ffa_partition;
+ debug_name = "op-tee";
+ load_address = <0x6280000>;
+ vcpu_count = <8>;
+ mem_size = <1048576>;
+ };
+ };
+
+ cpus {
+ #address-cells = <0x2>;
+ #size-cells = <0x0>;
+
+ CPU_0
+
+ /*
+ * SPMC (Hafnium) requires secondary core nodes are declared
+ * in descending order.
+ */
+ CPU_7
+ CPU_6
+ CPU_5
+ CPU_4
+ CPU_3
+ CPU_2
+ CPU_1
+ };
+
+ memory@6000000 {
+ device_type = "memory";
+ reg = <0x0 0x6000000 0x2000000>; /* Trusted DRAM */
+ };
+};
diff --git a/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts b/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts
new file mode 100644
index 0000000..6fd334d
--- /dev/null
+++ b/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2020-2022, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/libc/cdefs.h>
+
+/dts-v1/;
+
+/ {
+ tb_fw-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>;
+ };
+
+ /*
+ * UUID's here are UUID RFC 4122 compliant meaning fieds are stored in
+ * network order (big endian)
+ */
+
+#if ARM_IO_IN_DTB
+ arm-io_policies {
+ fip-handles {
+ compatible = "arm,io-fip-handle";
+ scp_bl2_uuid = "9766fd3d-89be-e849-ae5d-78a140608213";
+ bl31_uuid = "47d4086d-4cfe-9846-9b95-2950cbbd5a00";
+ bl32_uuid = "05d0e189-53dc-1347-8d2b-500a4b7a3e38";
+ bl32_extra1_uuid = "0b70c29b-2a5a-7840-9f65-0a5682738288";
+ bl32_extra2_uuid = "8ea87bb1-cfa2-3f4d-85fd-e7bba50220d9";
+ bl33_uuid = "d6d0eea7-fcea-d54b-9782-9934f234b6e4";
+ hw_cfg_uuid = "08b8f1d9-c9cf-9349-a962-6fbc6b7265cc";
+ soc_fw_cfg_uuid = "9979814b-0376-fb46-8c8e-8d267f7859e0";
+ tos_fw_cfg_uuid = "26257c1a-dbc6-7f47-8d96-c4c4b0248021";
+ nt_fw_cfg_uuid = "28da9815-93e8-7e44-ac66-1aaf801550f9";
+ cca_cert_uuid = "36d83d85-761d-4daf-96f1-cd99d6569b00";
+ core_swd_cert_uuid = "52222d31-820f-494d-8bbc-ea6825d3c35a";
+ plat_cert_uuid = "d43cd902-5b9f-412e-8ac6-92b6d18be60d";
+ t_key_cert_uuid = "827ee890-f860-e411-a1b4-777a21b4f94c";
+ scp_fw_key_uuid = "024221a1-f860-e411-8d9b-f33c0e15a014";
+ soc_fw_key_uuid = "8ab8becc-f960-e411-9ad0-eb4822d8dcf8";
+ tos_fw_key_cert_uuid = "9477d603-fb60-e411-85dd-b7105b8cee04";
+ nt_fw_key_cert_uuid = "8ad5832a-fb60-e411-8aaf-df30bbc49859";
+ scp_fw_content_cert_uuid = "44be6f04-5e63-e411-b28b-73d8eaae9656";
+ soc_fw_content_cert_uuid = "e2b20c20-5e63-e411-9ce8-abccf92bb666";
+ tos_fw_content_cert_uuid = "a49f4411-5e63-e411-8728-3f05722af33d";
+ nt_fw_content_cert_uuid = "8ec4c1f3-5d63-e411-a7a9-87ee40b23fa7";
+ sp_content_cert_uuid = "776dfd44-8697-4c3b-91eb-c13e025a2a6f";
+ };
+ };
+#endif /* ARM_IO_IN_DTB */
+
+ secure-partitions {
+ compatible = "arm,sp";
+
+#ifdef ARM_BL2_SP_LIST_DTS
+ #include __XSTRING(ARM_BL2_SP_LIST_DTS)
+#else
+#ifdef OPTEE_SP_FW_CONFIG
+ op-tee {
+ uuid = "486178e0-e7f8-11e3-bc5e-0002a5d5c51b";
+ load-address = <0x6280000>;
+ };
+#else
+ cactus-primary {
+ uuid = "b4b5671e-4a90-4fe1-b81f-fb13dae1dacb";
+ load-address = <0x7000000>;
+ owner = "SiP";
+ };
+
+ cactus-secondary {
+ uuid = "d1582309-f023-47b9-827c-4464f5578fc8";
+ load-address = <0x7100000>;
+ owner = "Plat";
+ };
+
+ cactus-tertiary {
+ uuid = "79b55c73-1d8c-44b9-8593-61e1770ad8d2";
+ load-address = <0x7200000>;
+ owner = "Plat";
+ };
+
+ ivy {
+ uuid = "eaba83d8-baaf-4eaf-8144-f7fdcbe544a7";
+ load-address = <0x7600000>;
+ owner = "Plat";
+ };
+#endif
+#endif /* ARM_BL2_SP_LIST_DTS */
+ };
+
+#if COT_DESC_IN_DTB
+ #include "cot_descriptors.dtsi"
+#endif
+
+#if MEASURED_BOOT
+ #include "event_log.dtsi"
+#endif
+
+};
+
+#if COT_DESC_IN_DTB
+
+#include "../fvp_def.h"
+
+&trusted_nv_counter {
+ reg = <TFW_NVCTR_BASE>;
+};
+
+&non_trusted_nv_counter {
+ reg = <NTFW_CTR_BASE>;
+};
+#endif
diff --git a/plat/arm/board/fvp/fdts/fvp_tsp_fw_config.dts b/plat/arm/board/fvp/fdts/fvp_tsp_fw_config.dts
new file mode 100644
index 0000000..7bed6cb
--- /dev/null
+++ b/plat/arm/board/fvp/fdts/fvp_tsp_fw_config.dts
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+#if MEASURED_BOOT
+#include "event_log.dtsi"
+#endif
+};
diff --git a/plat/arm/board/fvp/fdts/fvp_tsp_sp_manifest.dts b/plat/arm/board/fvp/fdts/fvp_tsp_sp_manifest.dts
new file mode 100644
index 0000000..1587c72
--- /dev/null
+++ b/plat/arm/board/fvp/fdts/fvp_tsp_sp_manifest.dts
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/dts-v1/;
+
+#define AFF 00
+
+#include "fvp-defs.dtsi"
+#undef POST
+#define POST \
+ };
+
+#define S_EL0 (0x1)
+#define S_EL1 (0x2)
+
+/* For consumption by EL3 SPMC. */
+/ {
+ compatible = "arm,ffa-manifest-1.0";
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ ffa-version = <0x00010001>; /* 31:16 - Major, 15:0 - Minor */
+ id = <0x8001>;
+ uuid = <0x6b43b460 0x74a24b78 0xade24502 0x40682886>;
+ messaging-method = <0x3>; /* Direct Messaging Only */
+ exception-level = <S_EL1>;
+ execution-state = <0>;
+ execution-ctx-count = <8>;
+ gp-register-num = <0>;
+ /* Subscribe to CPU_OFF, CPU_SUSPEND and CPU_SUSPEND_RESUME PM Msgs */
+ power-management-messages = <0x7>;
+};
diff --git a/plat/arm/board/fvp/fdts/optee_sp_manifest.dts b/plat/arm/board/fvp/fdts/optee_sp_manifest.dts
new file mode 100644
index 0000000..27f4724
--- /dev/null
+++ b/plat/arm/board/fvp/fdts/optee_sp_manifest.dts
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file is a Partition Manifest (PM) for a minimal Secure Partition (SP)
+ * that has additional optional properties defined.
+ *
+ */
+
+/dts-v1/;
+
+/ {
+ compatible = "arm,ffa-manifest-1.0";
+
+ /* Properties */
+ description = "op-tee";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <0xe0786148 0xe311f8e7 0x02005ebc 0x1bc5d5a5>;
+ id = <1>;
+ execution-ctx-count = <8>;
+ exception-level = <2>; /* S-EL1 */
+ execution-state = <0>; /* AARCH64 */
+ load-address = <0x6280000>;
+ entrypoint-offset = <0x4000>;
+ xlat-granule = <0>; /* 4KiB */
+ boot-order = <0>;
+ messaging-method = <0x3>; /* Direct request/response supported. */
+ managed-exit;
+ run-time-model = <1>; /* SP pre-emptible. */
+
+ /* Boot protocol */
+ gp-register-num = <0x0>;
+
+ device-regions {
+ compatible = "arm,ffa-manifest-device-regions";
+
+ uart1 {
+ base-address = <0x00000000 0x1c0a0000>;
+ pages-count = <1>;
+ attributes = <0x3>; /* read-write */
+ };
+ };
+};
diff --git a/plat/arm/board/fvp/fvp_bl1_measured_boot.c b/plat/arm/board/fvp/fvp_bl1_measured_boot.c
new file mode 100644
index 0000000..76cd918
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_bl1_measured_boot.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <drivers/measured_boot/event_log/event_log.h>
+#include <drivers/measured_boot/rss/rss_measured_boot.h>
+#include <plat/arm/common/plat_arm.h>
+
+/* Event Log data */
+static uint8_t event_log[PLAT_ARM_EVENT_LOG_MAX_SIZE];
+
+/* FVP table with platform specific image IDs, names and PCRs */
+const event_log_metadata_t fvp_event_log_metadata[] = {
+ { FW_CONFIG_ID, EVLOG_FW_CONFIG_STRING, PCR_0 },
+ { TB_FW_CONFIG_ID, EVLOG_TB_FW_CONFIG_STRING, PCR_0 },
+ { BL2_IMAGE_ID, EVLOG_BL2_STRING, PCR_0 },
+
+ { EVLOG_INVALID_ID, NULL, (unsigned int)(-1) } /* Terminator */
+};
+
+/* FVP table with platform specific image IDs and metadata. Intentionally not a
+ * const struct, some members might set by bootloaders during trusted boot.
+ */
+struct rss_mboot_metadata fvp_rss_mboot_metadata[] = {
+ {
+ .id = FW_CONFIG_ID,
+ .slot = U(6),
+ .signer_id_size = SIGNER_ID_MIN_SIZE,
+ .sw_type = RSS_MBOOT_FW_CONFIG_STRING,
+ .lock_measurement = true },
+ {
+ .id = TB_FW_CONFIG_ID,
+ .slot = U(7),
+ .signer_id_size = SIGNER_ID_MIN_SIZE,
+ .sw_type = RSS_MBOOT_TB_FW_CONFIG_STRING,
+ .lock_measurement = true },
+ {
+ .id = BL2_IMAGE_ID,
+ .slot = U(8),
+ .signer_id_size = SIGNER_ID_MIN_SIZE,
+ .sw_type = RSS_MBOOT_BL2_STRING,
+ .lock_measurement = true },
+
+ {
+ .id = RSS_MBOOT_INVALID_ID }
+};
+
+void bl1_plat_mboot_init(void)
+{
+ event_log_init(event_log, event_log + sizeof(event_log));
+ event_log_write_header();
+
+ rss_measured_boot_init();
+}
+
+void bl1_plat_mboot_finish(void)
+{
+ size_t event_log_cur_size;
+
+ event_log_cur_size = event_log_get_cur_size(event_log);
+ int rc = arm_set_tb_fw_info((uintptr_t)event_log,
+ event_log_cur_size);
+ if (rc != 0) {
+ /*
+ * It is a fatal error because on FVP platform, BL2 software
+ * assumes that a valid Event Log buffer exist and it will use
+ * same Event Log buffer to append image measurements.
+ */
+ panic();
+ }
+}
diff --git a/plat/arm/board/fvp/fvp_bl1_setup.c b/plat/arm/board/fvp/fvp_bl1_setup.c
new file mode 100644
index 0000000..59fc0f3
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_bl1_setup.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <bl1/bl1.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/arm/smmu_v3.h>
+#include <drivers/arm/sp805.h>
+#include <lib/mmio.h>
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/common/arm_def.h>
+#include <plat/common/platform.h>
+#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)
+{
+ uint32_t nv_flags = mmio_read_32(V2M_SYS_NVFLAGS_ADDR);
+
+ /* Clear the NV flags register. */
+ mmio_write_32((V2M_SYSREGS_BASE + V2M_SYS_NVFLAGSCLR),
+ nv_flags);
+
+ /* Setup the watchdog to reset the system as soon as possible */
+ sp805_refresh(ARM_SP805_TWDG_BASE, 1U);
+
+ while (true)
+ wfi();
+}
+
+/*******************************************************************************
+ * The following function checks if Firmware update is needed by checking error
+ * reported in NV flag.
+ ******************************************************************************/
+bool plat_arm_bl1_fwu_needed(void)
+{
+ int32_t nv_flags = (int32_t)mmio_read_32(V2M_SYS_NVFLAGS_ADDR);
+
+ /* if image load/authentication failed */
+ return ((nv_flags == -EAUTH) || (nv_flags == -ENOENT));
+}
diff --git a/plat/arm/board/fvp/fvp_bl2_el3_setup.c b/plat/arm/board/fvp/fvp_bl2_el3_setup.c
new file mode 100644
index 0000000..7def56a
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_bl2_el3_setup.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+#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();
+}
diff --git a/plat/arm/board/fvp/fvp_bl2_measured_boot.c b/plat/arm/board/fvp/fvp_bl2_measured_boot.c
new file mode 100644
index 0000000..e938e24
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_bl2_measured_boot.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/measured_boot/event_log/event_log.h>
+#include <drivers/measured_boot/rss/rss_measured_boot.h>
+#include <tools_share/tbbr_oid.h>
+#include <fvp_critical_data.h>
+
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/common_def.h>
+
+/* Event Log data */
+static uint64_t event_log_base;
+
+/* FVP table with platform specific image IDs, names and PCRs */
+const event_log_metadata_t fvp_event_log_metadata[] = {
+ { BL31_IMAGE_ID, EVLOG_BL31_STRING, PCR_0 },
+ { BL32_IMAGE_ID, EVLOG_BL32_STRING, PCR_0 },
+ { BL32_EXTRA1_IMAGE_ID, EVLOG_BL32_EXTRA1_STRING, PCR_0 },
+ { BL32_EXTRA2_IMAGE_ID, EVLOG_BL32_EXTRA2_STRING, PCR_0 },
+ { BL33_IMAGE_ID, EVLOG_BL33_STRING, PCR_0 },
+ { HW_CONFIG_ID, EVLOG_HW_CONFIG_STRING, PCR_0 },
+ { NT_FW_CONFIG_ID, EVLOG_NT_FW_CONFIG_STRING, PCR_0 },
+ { SCP_BL2_IMAGE_ID, EVLOG_SCP_BL2_STRING, PCR_0 },
+ { SOC_FW_CONFIG_ID, EVLOG_SOC_FW_CONFIG_STRING, PCR_0 },
+ { TOS_FW_CONFIG_ID, EVLOG_TOS_FW_CONFIG_STRING, PCR_0 },
+ { RMM_IMAGE_ID, EVLOG_RMM_STRING, PCR_0},
+
+#if defined(SPD_spmd)
+ { SP_PKG1_ID, EVLOG_SP1_STRING, PCR_0 },
+ { SP_PKG2_ID, EVLOG_SP2_STRING, PCR_0 },
+ { SP_PKG3_ID, EVLOG_SP3_STRING, PCR_0 },
+ { SP_PKG4_ID, EVLOG_SP4_STRING, PCR_0 },
+ { SP_PKG5_ID, EVLOG_SP5_STRING, PCR_0 },
+ { SP_PKG6_ID, EVLOG_SP6_STRING, PCR_0 },
+ { SP_PKG7_ID, EVLOG_SP7_STRING, PCR_0 },
+ { SP_PKG8_ID, EVLOG_SP8_STRING, PCR_0 },
+#endif
+
+ { CRITICAL_DATA_ID, EVLOG_CRITICAL_DATA_STRING, PCR_1 },
+
+ { EVLOG_INVALID_ID, NULL, (unsigned int)(-1) } /* Terminator */
+};
+
+/* FVP table with platform specific image IDs and metadata. Intentionally not a
+ * const struct, some members might set by bootloaders during trusted boot.
+ */
+struct rss_mboot_metadata fvp_rss_mboot_metadata[] = {
+ {
+ .id = BL31_IMAGE_ID,
+ .slot = U(9),
+ .signer_id_size = SIGNER_ID_MIN_SIZE,
+ .sw_type = RSS_MBOOT_BL31_STRING,
+ .lock_measurement = true },
+ {
+ .id = HW_CONFIG_ID,
+ .slot = U(10),
+ .signer_id_size = SIGNER_ID_MIN_SIZE,
+ .sw_type = RSS_MBOOT_HW_CONFIG_STRING,
+ .lock_measurement = true },
+ {
+ .id = SOC_FW_CONFIG_ID,
+ .slot = U(11),
+ .signer_id_size = SIGNER_ID_MIN_SIZE,
+ .sw_type = RSS_MBOOT_SOC_FW_CONFIG_STRING,
+ .lock_measurement = true },
+ {
+ .id = RMM_IMAGE_ID,
+ .slot = U(12),
+ .signer_id_size = SIGNER_ID_MIN_SIZE,
+ .sw_type = RSS_MBOOT_RMM_STRING,
+ .lock_measurement = true },
+ {
+ .id = RSS_MBOOT_INVALID_ID }
+};
+
+void bl2_plat_mboot_init(void)
+{
+ uint8_t *event_log_start;
+ uint8_t *event_log_finish;
+ size_t bl1_event_log_size;
+ int rc;
+
+ rc = arm_get_tb_fw_info(&event_log_base, &bl1_event_log_size);
+ if (rc != 0) {
+ ERROR("%s(): Unable to get Event Log info from TB_FW_CONFIG\n",
+ __func__);
+ /*
+ * It is a fatal error because on FVP platform, BL2 software
+ * assumes that a valid Event Log buffer exist and it will use
+ * same Event Log buffer to append image measurements.
+ */
+ panic();
+ }
+
+ /*
+ * BL1 and BL2 share the same Event Log buffer and that BL2 will
+ * append its measurements after BL1's
+ */
+ event_log_start = (uint8_t *)((uintptr_t)event_log_base +
+ bl1_event_log_size);
+ event_log_finish = (uint8_t *)((uintptr_t)event_log_base +
+ PLAT_ARM_EVENT_LOG_MAX_SIZE);
+
+ event_log_init((uint8_t *)event_log_start, event_log_finish);
+
+ rss_measured_boot_init();
+}
+
+int plat_mboot_measure_critical_data(unsigned int critical_data_id,
+ const void *base, size_t size)
+{
+ /*
+ * It is very unlikely that the critical data size would be
+ * bigger than 2^32 bytes
+ */
+ assert(size < UINT32_MAX);
+ assert(base != NULL);
+
+ /* Calculate image hash and record data in Event Log */
+ int err = event_log_measure_and_record((uintptr_t)base, (uint32_t)size,
+ critical_data_id);
+ if (err != 0) {
+ ERROR("%s%s critical data (%i)\n",
+ "Failed to ", "record", err);
+ return err;
+ }
+
+ return 0;
+}
+
+#if TRUSTED_BOARD_BOOT
+static int fvp_populate_critical_data(struct fvp_critical_data *critical_data)
+{
+ char *nv_ctr_oids[MAX_NV_CTR_IDS] = {
+ [TRUSTED_NV_CTR_ID] = TRUSTED_FW_NVCOUNTER_OID,
+ [NON_TRUSTED_NV_CTR_ID] = NON_TRUSTED_FW_NVCOUNTER_OID,
+ };
+
+ for (int i = 0; i < MAX_NV_CTR_IDS; i++) {
+ int rc = plat_get_nv_ctr(nv_ctr_oids[i],
+ &critical_data->nv_ctr[i]);
+ if (rc != 0) {
+ return rc;
+ }
+ }
+
+ return 0;
+}
+#endif /* TRUSTED_BOARD_BOOT */
+
+static int fvp_populate_and_measure_critical_data(void)
+{
+ int rc = 0;
+
+/*
+ * FVP platform only measures 'platform NV-counter' and hence its
+ * measurement makes sense during Trusted-Boot flow only.
+ */
+#if TRUSTED_BOARD_BOOT
+ struct fvp_critical_data populate_critical_data;
+
+ rc = fvp_populate_critical_data(&populate_critical_data);
+ if (rc == 0) {
+ rc = plat_mboot_measure_critical_data(CRITICAL_DATA_ID,
+ &populate_critical_data,
+ sizeof(populate_critical_data));
+ }
+#endif /* TRUSTED_BOARD_BOOT */
+
+ return rc;
+}
+
+void bl2_plat_mboot_finish(void)
+{
+ int rc;
+
+ /* Event Log address in Non-Secure memory */
+ uintptr_t ns_log_addr;
+
+ /* Event Log filled size */
+ size_t event_log_cur_size;
+
+ rc = fvp_populate_and_measure_critical_data();
+ if (rc != 0) {
+ panic();
+ }
+
+ event_log_cur_size = event_log_get_cur_size((uint8_t *)event_log_base);
+
+ rc = arm_set_nt_fw_info(
+#ifdef SPD_opteed
+ (uintptr_t)event_log_base,
+#endif
+ event_log_cur_size, &ns_log_addr);
+ if (rc != 0) {
+ ERROR("%s(): Unable to update %s_FW_CONFIG\n",
+ __func__, "NT");
+ /*
+ * It is a fatal error because on FVP secure world software
+ * assumes that a valid event log exists and will use it to
+ * record the measurements into the fTPM.
+ * Note: In FVP platform, OP-TEE uses nt_fw_config to get the
+ * secure Event Log buffer address.
+ */
+ panic();
+ }
+
+ /* Copy Event Log to Non-secure memory */
+ (void)memcpy((void *)ns_log_addr, (const void *)event_log_base,
+ event_log_cur_size);
+
+ /* Ensure that the Event Log is visible in Non-secure memory */
+ flush_dcache_range(ns_log_addr, event_log_cur_size);
+
+#if defined(SPD_tspd) || defined(SPD_spmd)
+ /* Set Event Log data in TOS_FW_CONFIG */
+ rc = arm_set_tos_fw_info((uintptr_t)event_log_base,
+ event_log_cur_size);
+ if (rc != 0) {
+ ERROR("%s(): Unable to update %s_FW_CONFIG\n",
+ __func__, "TOS");
+ panic();
+ }
+#endif /* defined(SPD_tspd) || defined(SPD_spmd) */
+
+ dump_event_log((uint8_t *)event_log_base, event_log_cur_size);
+}
diff --git a/plat/arm/board/fvp/fvp_bl2_setup.c b/plat/arm/board/fvp/fvp_bl2_setup.c
new file mode 100644
index 0000000..74e5d72
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_bl2_setup.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/arm/sp804_delay_timer.h>
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_dyn_cfg_getter.h>
+
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#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();
+}
+
+/*******************************************************************************
+ * This function returns the list of executable images
+ ******************************************************************************/
+struct bl_params *plat_get_next_bl_params(void)
+{
+ struct bl_params *arm_bl_params;
+ const struct dyn_cfg_dtb_info_t *hw_config_info __unused;
+ bl_mem_params_node_t *param_node __unused;
+
+ arm_bl_params = arm_get_next_bl_params();
+
+#if !BL2_AT_EL3 && !EL3_PAYLOAD_BASE
+ const struct dyn_cfg_dtb_info_t *fw_config_info;
+ uintptr_t fw_config_base = 0UL;
+ entry_point_info_t *ep_info;
+
+#if __aarch64__
+ /* Get BL31 image node */
+ param_node = get_bl_mem_params_node(BL31_IMAGE_ID);
+#else /* aarch32 */
+ /* Get SP_MIN image node */
+ param_node = get_bl_mem_params_node(BL32_IMAGE_ID);
+#endif /* __aarch64__ */
+ assert(param_node != NULL);
+
+ /* get fw_config load address */
+ fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, FW_CONFIG_ID);
+ assert(fw_config_info != NULL);
+
+ fw_config_base = fw_config_info->config_addr;
+ assert(fw_config_base != 0UL);
+
+ /*
+ * Get the entry point info of next executable image and override
+ * arg1 of entry point info with fw_config base address
+ */
+ ep_info = &param_node->ep_info;
+ ep_info->args.arg1 = (uint32_t)fw_config_base;
+
+ /* grab NS HW config address */
+ hw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, HW_CONFIG_ID);
+ assert(hw_config_info != NULL);
+
+ /* To retrieve actual size of the HW_CONFIG */
+ param_node = get_bl_mem_params_node(HW_CONFIG_ID);
+ assert(param_node != NULL);
+
+ /* Copy HW config from Secure address to NS address */
+ memcpy((void *)hw_config_info->ns_config_addr,
+ (void *)hw_config_info->config_addr,
+ (size_t)param_node->image_info.image_size);
+
+ /*
+ * Ensure HW-config device tree committed to memory, as there is
+ * a possibility to use HW-config without cache and MMU enabled
+ * at BL33
+ */
+ flush_dcache_range(hw_config_info->ns_config_addr,
+ param_node->image_info.image_size);
+
+ param_node = get_bl_mem_params_node(BL33_IMAGE_ID);
+ assert(param_node != NULL);
+
+ /* Update BL33's ep info with NS HW config address */
+ param_node->ep_info.args.arg1 = hw_config_info->ns_config_addr;
+#endif /* !BL2_AT_EL3 && !EL3_PAYLOAD_BASE */
+
+ return arm_bl_params;
+}
diff --git a/plat/arm/board/fvp/fvp_bl2u_setup.c b/plat/arm/board/fvp/fvp_bl2u_setup.c
new file mode 100644
index 0000000..fd73767
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_bl2u_setup.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#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();
+}
diff --git a/plat/arm/board/fvp/fvp_bl31_setup.c b/plat/arm/board/fvp/fvp_bl31_setup.c
new file mode 100644
index 0000000..dd90965
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_bl31_setup.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/debug.h>
+#include <drivers/arm/smmu_v3.h>
+#include <fconf_hw_config_getter.h>
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_dyn_cfg_getter.h>
+#include <lib/mmio.h>
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#include "fvp_private.h"
+
+static const struct dyn_cfg_dtb_info_t *hw_config_info __unused;
+
+void __init 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 */
+ arm_console_boot_init();
+
+#if !RESET_TO_BL31 && !BL2_AT_EL3
+ const struct dyn_cfg_dtb_info_t *soc_fw_config_info;
+
+ INFO("BL31 FCONF: FW_CONFIG address = %lx\n", (uintptr_t)arg1);
+ /* Fill the properties struct with the info from the config dtb */
+ fconf_populate("FW_CONFIG", arg1);
+
+ soc_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, SOC_FW_CONFIG_ID);
+ if (soc_fw_config_info != NULL) {
+ arg1 = soc_fw_config_info->config_addr;
+ }
+
+ /*
+ * arg2 is currently holding the 'secure' address of HW_CONFIG.
+ * But arm_bl31_early_platform_setup() below expects the 'non-secure'
+ * address of HW_CONFIG (which it will pass to BL33).
+ * This why we need to override arg2 here.
+ */
+ hw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, HW_CONFIG_ID);
+ assert(hw_config_info != NULL);
+ assert(hw_config_info->ns_config_addr != 0UL);
+ arg2 = hw_config_info->ns_config_addr;
+#endif /* !RESET_TO_BL31 && !BL2_AT_EL3 */
+
+ 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);
+}
+
+void __init bl31_plat_arch_setup(void)
+{
+ int rc __unused;
+ uintptr_t hw_config_base_align __unused;
+ size_t mapped_size_align __unused;
+
+ arm_bl31_plat_arch_setup();
+
+ /*
+ * For RESET_TO_BL31 systems, BL31 is the first bootloader to run.
+ * So there is no BL2 to load the HW_CONFIG dtb into memory before
+ * control is passed to BL31. The code below relies on dynamic mapping
+ * capability, which is not supported by xlat tables lib V1.
+ * TODO: remove the ARM_XLAT_TABLES_LIB_V1 check when its support
+ * gets deprecated.
+ */
+#if !RESET_TO_BL31 && !BL2_AT_EL3 && !ARM_XLAT_TABLES_LIB_V1
+ assert(hw_config_info != NULL);
+ assert(hw_config_info->config_addr != 0UL);
+
+ /* Page aligned address and size if necessary */
+ hw_config_base_align = page_align(hw_config_info->config_addr, DOWN);
+ mapped_size_align = page_align(hw_config_info->config_max_size, UP);
+
+ if ((hw_config_info->config_addr != hw_config_base_align) &&
+ (hw_config_info->config_max_size == mapped_size_align)) {
+ mapped_size_align += PAGE_SIZE;
+ }
+
+ /*
+ * map dynamically HW config region with its aligned base address and
+ * size
+ */
+ rc = mmap_add_dynamic_region((unsigned long long)hw_config_base_align,
+ hw_config_base_align,
+ mapped_size_align,
+ MT_RO_DATA);
+ if (rc != 0) {
+ ERROR("Error while mapping HW_CONFIG device tree (%d).\n", rc);
+ panic();
+ }
+
+ /* Populate HW_CONFIG device tree with the mapped address */
+ fconf_populate("HW_CONFIG", hw_config_info->config_addr);
+
+ /* unmap the HW_CONFIG memory region */
+ rc = mmap_remove_dynamic_region(hw_config_base_align, mapped_size_align);
+ if (rc != 0) {
+ ERROR("Error while unmapping HW_CONFIG device tree (%d).\n",
+ rc);
+ panic();
+ }
+#endif /* !RESET_TO_BL31 && !BL2_AT_EL3 && !ARM_XLAT_TABLES_LIB_V1 */
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+ unsigned int counter_base_frequency;
+
+#if !RESET_TO_BL31 && !BL2_AT_EL3
+ /* Get the frequency through FCONF API for HW_CONFIG */
+ counter_base_frequency = FCONF_GET_PROPERTY(hw_config, cpu_timer, clock_freq);
+ if (counter_base_frequency > 0U) {
+ return counter_base_frequency;
+ }
+#endif
+
+ /* 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;
+}
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
new file mode 100644
index 0000000..f8463f1
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -0,0 +1,544 @@
+/*
+ * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/arm/ccn.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/sp804_delay_timer.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/smccc.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+#include <platform_def.h>
+#include <services/arm_arch_svc.h>
+#if ENABLE_RME
+#include <services/rmm_core_manifest.h>
+#endif
+#if SPM_MM
+#include <services/spm_mm_partition.h>
+#endif
+
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#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)
+
+#if FVP_GICR_REGION_PROTECTION
+#define MAP_GICD_MEM MAP_REGION_FLAT(BASE_GICD_BASE, \
+ BASE_GICD_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+/* Map all core's redistributor memory as read-only. After boots up,
+ * per-core map its redistributor memory as read-write */
+#define MAP_GICR_MEM MAP_REGION_FLAT(BASE_GICR_BASE, \
+ (BASE_GICR_SIZE * PLATFORM_CORE_COUNT),\
+ MT_DEVICE | MT_RO | MT_SECURE)
+#endif /* FVP_GICR_REGION_PROTECTION */
+
+/*
+ * 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.
+ */
+#ifdef IMAGE_BL1
+const mmap_region_t plat_arm_mmap[] = {
+ ARM_MAP_SHARED_RAM,
+ V2M_MAP_FLASH0_RO,
+ V2M_MAP_IOFPGA,
+ MAP_DEVICE0,
+#if FVP_INTERCONNECT_DRIVER == FVP_CCN
+ MAP_DEVICE1,
+#endif
+#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,
+#if FVP_INTERCONNECT_DRIVER == FVP_CCN
+ MAP_DEVICE1,
+#endif
+ ARM_MAP_NS_DRAM1,
+#ifdef __aarch64__
+ ARM_MAP_DRAM2,
+#endif
+ /*
+ * Required to load HW_CONFIG, SPMC and SPs to trusted DRAM.
+ */
+ ARM_MAP_TRUSTED_DRAM,
+#if ENABLE_RME
+ ARM_MAP_RMM_DRAM,
+ ARM_MAP_GPT_L1_DRAM,
+#endif /* ENABLE_RME */
+#ifdef SPD_tspd
+ ARM_MAP_TSP_SEC_MEM,
+#endif
+#if TRUSTED_BOARD_BOOT
+ /* To access the Root of Trust Public Key registers. */
+ MAP_DEVICE2,
+#endif /* TRUSTED_BOARD_BOOT */
+
+#if CRYPTO_SUPPORT && !BL2_AT_EL3
+ /*
+ * To access shared the Mbed TLS heap while booting the
+ * system with Crypto support
+ */
+ ARM_MAP_BL1_RW,
+#endif /* CRYPTO_SUPPORT && !BL2_AT_EL3 */
+#if SPM_MM || SPMC_AT_EL3
+ ARM_SP_IMAGE_MMAP,
+#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,
+#if USE_DEBUGFS
+ /* Required by devfip, can be removed if devfip is not used */
+ V2M_MAP_FLASH0_RW,
+#endif /* USE_DEBUGFS */
+ ARM_MAP_EL3_TZC_DRAM,
+ V2M_MAP_IOFPGA,
+ MAP_DEVICE0,
+#if FVP_GICR_REGION_PROTECTION
+ MAP_GICD_MEM,
+ MAP_GICR_MEM,
+#else
+ MAP_DEVICE1,
+#endif /* FVP_GICR_REGION_PROTECTION */
+ ARM_V2M_MAP_MEM_PROTECT,
+#if SPM_MM
+ ARM_SPM_BUF_EL3_MMAP,
+#endif
+#if ENABLE_RME
+ ARM_MAP_GPT_L1_DRAM,
+ ARM_MAP_EL3_RMM_SHARED_MEM,
+#endif
+ {0}
+};
+
+#if 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
+
+#ifdef IMAGE_RMM
+const mmap_region_t plat_arm_mmap[] = {
+ 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 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 spm_mm_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 spm_mm_boot_info_t plat_arm_secure_partition_boot_info = {
+ .h.type = PARAM_SP_IMAGE_BOOT_INFO,
+ .h.version = VERSION_1,
+ .h.size = sizeof(spm_mm_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 spm_mm_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 CRYPTO_SUPPORT
+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 /* CRYPTO_SUPPORT */
+
+void fvp_timer_init(void)
+{
+#if 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 /* USE_SP804_TIMER */
+}
+
+/*****************************************************************************
+ * plat_is_smccc_feature_available() - This function checks whether SMCCC
+ * feature is availabile for platform.
+ * @fid: SMCCC function id
+ *
+ * Return SMC_ARCH_CALL_SUCCESS if SMCCC feature is available and
+ * SMC_ARCH_CALL_NOT_SUPPORTED otherwise.
+ *****************************************************************************/
+int32_t plat_is_smccc_feature_available(u_register_t fid)
+{
+ switch (fid) {
+ case SMCCC_ARCH_SOC_ID:
+ return SMC_ARCH_CALL_SUCCESS;
+ default:
+ return SMC_ARCH_CALL_NOT_SUPPORTED;
+ }
+}
+
+/* Get SOC version */
+int32_t plat_get_soc_version(void)
+{
+ return (int32_t)
+ (SOC_ID_SET_JEP_106(ARM_SOC_CONTINUATION_CODE,
+ ARM_SOC_IDENTIFICATION_CODE) |
+ (FVP_SOC_ID & SOC_ID_IMPL_DEF_MASK));
+}
+
+/* Get SOC revision */
+int32_t plat_get_soc_revision(void)
+{
+ unsigned int sys_id;
+
+ sys_id = mmio_read_32(V2M_SYSREGS_BASE + V2M_SYS_ID);
+ return (int32_t)(((sys_id >> V2M_SYS_ID_REV_SHIFT) &
+ V2M_SYS_ID_REV_MASK) & SOC_ID_REV_MASK);
+}
+
+#if ENABLE_RME
+/*
+ * Get a pointer to the RMM-EL3 Shared buffer and return it
+ * through the pointer passed as parameter.
+ *
+ * This function returns the size of the shared buffer.
+ */
+size_t plat_rmmd_get_el3_rmm_shared_mem(uintptr_t *shared)
+{
+ *shared = (uintptr_t)RMM_SHARED_BASE;
+
+ return (size_t)RMM_SHARED_SIZE;
+}
+
+int plat_rmmd_load_manifest(rmm_manifest_t *manifest)
+{
+ assert(manifest != NULL);
+
+ manifest->version = RMMD_MANIFEST_VERSION;
+ manifest->plat_data = (uintptr_t)NULL;
+
+ return 0;
+}
+
+#endif
diff --git a/plat/arm/board/fvp/fvp_common_measured_boot.c b/plat/arm/board/fvp/fvp_common_measured_boot.c
new file mode 100644
index 0000000..93aa055
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_common_measured_boot.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <common/desc_image_load.h>
+#include <drivers/measured_boot/event_log/event_log.h>
+#include <drivers/measured_boot/rss/rss_measured_boot.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+extern event_log_metadata_t fvp_event_log_metadata[];
+extern struct rss_mboot_metadata fvp_rss_mboot_metadata[];
+
+const event_log_metadata_t *plat_event_log_get_metadata(void)
+{
+ return fvp_event_log_metadata;
+}
+
+struct rss_mboot_metadata *plat_rss_mboot_get_metadata(void)
+{
+ return fvp_rss_mboot_metadata;
+}
+
+int plat_mboot_measure_image(unsigned int image_id, image_info_t *image_data)
+{
+ int err;
+ int rc = 0;
+
+ /* Calculate image hash and record data in Event Log */
+ err = event_log_measure_and_record(image_data->image_base,
+ image_data->image_size,
+ image_id);
+ if (err != 0) {
+ ERROR("%s%s image id %u (%i)\n",
+ "Failed to ", "record in event log", image_id, err);
+ rc = err;
+ }
+
+ /* Calculate image hash and record data in RSS */
+ err = rss_mboot_measure_and_record(image_data->image_base,
+ image_data->image_size,
+ image_id);
+ if (err != 0) {
+ ERROR("%s%s image id %u (%i)\n",
+ "Failed to ", "record in RSS", image_id, err);
+ rc = (rc == 0) ? err : -1;
+ }
+
+ return rc;
+}
diff --git a/plat/arm/board/fvp/fvp_console.c b/plat/arm/board/fvp/fvp_console.c
new file mode 100644
index 0000000..1a6cd42
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_console.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <fconf_hw_config_getter.h>
+#include <plat/arm/common/plat_arm.h>
+
+static console_t fvp_runtime_console;
+
+/* Initialize the runtime console */
+void arm_console_runtime_init(void)
+{
+ uintptr_t uart_base;
+ uint32_t uart_clk;
+
+ /*
+ * fconf APIs are not supported for RESET_TO_SP_MIN, RESET_TO_BL31 and
+ * BL2_AT_EL3 systems.
+ */
+#if RESET_TO_SP_MIN || RESET_TO_BL31 || BL2_AT_EL3
+ uart_base = PLAT_ARM_RUN_UART_BASE;
+ uart_clk = PLAT_ARM_RUN_UART_CLK_IN_HZ;
+#else
+ uart_base = FCONF_GET_PROPERTY(hw_config, uart_serial_config,
+ uart_base);
+ uart_clk = FCONF_GET_PROPERTY(hw_config, uart_serial_config,
+ uart_clk);
+#endif
+
+ int rc = console_pl011_register(uart_base, uart_clk,
+ ARM_CONSOLE_BAUDRATE,
+ &fvp_runtime_console);
+
+ if (rc == 0) {
+ panic();
+ }
+
+ console_set_scope(&fvp_runtime_console, CONSOLE_FLAG_RUNTIME);
+}
+
+void arm_console_runtime_end(void)
+{
+ console_flush();
+ (void)console_unregister(&fvp_runtime_console);
+}
diff --git a/plat/arm/board/fvp/fvp_def.h b/plat/arm/board/fvp/fvp_def.h
new file mode 100644
index 0000000..831eb35
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_def.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FVP_DEF_H
+#define FVP_DEF_H
+
+#include <lib/utils_def.h>
+
+#ifndef FVP_CLUSTER_COUNT
+#error "FVP_CLUSTER_COUNT is not set in makefile"
+#endif
+
+#ifndef FVP_MAX_CPUS_PER_CLUSTER
+#error "FVP_MAX_CPUS_PER_CLUSTER is not set in makefile"
+#endif
+
+#ifndef FVP_MAX_PE_PER_CPU
+#error "FVP_MAX_PE_PER_CPU is not set in makefile"
+#endif
+
+#define FVP_PRIMARY_CPU 0x0
+
+/* Defines for the Interconnect build selection */
+#define FVP_CCI 1
+#define FVP_CCN 2
+
+/******************************************************************************
+ * Definition of platform soc id
+ *****************************************************************************/
+#define FVP_SOC_ID 0
+
+/*******************************************************************************
+ * 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 BASE_GICD_BASE
+
+#if GIC_ENABLE_V4_EXTN
+/* GICv4 mapping: GICD + CORE_COUNT * 256KB */
+#define DEVICE1_SIZE ((BASE_GICR_BASE - BASE_GICD_BASE) + \
+ (PLATFORM_CORE_COUNT * 0x40000))
+#else
+/* GICv2 and GICv3 mapping: GICD + CORE_COUNT * 128KB */
+#define DEVICE1_SIZE ((BASE_GICR_BASE - BASE_GICD_BASE) + \
+ (PLATFORM_CORE_COUNT * 0x20000))
+#endif /* GIC_ENABLE_V4_EXTN */
+
+#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 & 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_GICD_SIZE UL(0x10000)
+#define BASE_GICR_BASE UL(0x2f100000)
+
+#if GIC_ENABLE_V4_EXTN
+/* GICv4 redistributor size: 256KB */
+#define BASE_GICR_SIZE UL(0x40000)
+#else
+#define BASE_GICR_SIZE UL(0x20000)
+#endif /* GIC_ENABLE_V4_EXTN */
+
+#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 */
diff --git a/plat/arm/board/fvp/fvp_drtm_addr.c b/plat/arm/board/fvp/fvp_drtm_addr.c
new file mode 100644
index 0000000..eeaa342
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_drtm_addr.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2022 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+/*******************************************************************************
+ * Check passed region is within Non-Secure region of DRAM
+ ******************************************************************************/
+int plat_drtm_validate_ns_region(uintptr_t region_start,
+ size_t region_size)
+{
+ uintptr_t region_end = region_start + region_size - 1;
+
+ if (region_start >= region_end) {
+ return -1;
+ } else if ((region_start >= ARM_NS_DRAM1_BASE) &&
+ (region_start < (ARM_NS_DRAM1_BASE + ARM_NS_DRAM1_SIZE)) &&
+ (region_end >= ARM_NS_DRAM1_BASE) &&
+ (region_end < (ARM_NS_DRAM1_BASE + ARM_NS_DRAM1_SIZE))) {
+ return 0;
+ } else if ((region_start >= ARM_DRAM2_BASE) &&
+ (region_start < (ARM_DRAM2_BASE + ARM_DRAM2_SIZE)) &&
+ (region_end >= ARM_DRAM2_BASE) &&
+ (region_end < (ARM_DRAM2_BASE + ARM_DRAM2_SIZE))) {
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/plat/arm/board/fvp/fvp_drtm_dma_prot.c b/plat/arm/board/fvp/fvp_drtm_dma_prot.c
new file mode 100644
index 0000000..38ff7fe
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_drtm_dma_prot.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include <drivers/arm/smmu_v3.h>
+#include <lib/utils_def.h>
+#include <plat/arm/common/arm_config.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+/**
+ * Array mentioning number of SMMUs supported by FVP
+ */
+static const uintptr_t fvp_smmus[] = {
+ PLAT_FVP_SMMUV3_BASE,
+};
+
+bool plat_has_non_host_platforms(void)
+{
+ /* FVP base platforms typically have GPU, as per FVP Reference guide */
+ return true;
+}
+
+bool plat_has_unmanaged_dma_peripherals(void)
+{
+ /*
+ * FVP Reference guide does not show devices that are described as
+ * DMA-capable but not managed by an SMMU in the FVP documentation.
+ * However, the SMMU seems to have only been introduced in the RevC
+ * revision.
+ */
+ return (arm_config.flags & ARM_CONFIG_FVP_HAS_SMMUV3) == 0;
+}
+
+unsigned int plat_get_total_smmus(void)
+{
+ if ((arm_config.flags & ARM_CONFIG_FVP_HAS_SMMUV3) != 0U) {
+ return ARRAY_SIZE(fvp_smmus);
+ } else {
+ return 0;
+ }
+}
+
+void plat_enumerate_smmus(const uintptr_t **smmus_out,
+ size_t *smmu_count_out)
+{
+ if ((arm_config.flags & ARM_CONFIG_FVP_HAS_SMMUV3) != 0U) {
+ *smmus_out = fvp_smmus;
+ *smmu_count_out = ARRAY_SIZE(fvp_smmus);
+ } else {
+ *smmus_out = NULL;
+ *smmu_count_out = 0;
+ }
+}
+
+/* DRTM DMA Protection Features */
+static const plat_drtm_dma_prot_features_t dma_prot_features = {
+ .max_num_mem_prot_regions = 0, /* No protection regions are present */
+ .dma_protection_support = 0x1 /* Complete DMA protection only */
+};
+
+const plat_drtm_dma_prot_features_t *plat_drtm_get_dma_prot_features(void)
+{
+ return &dma_prot_features;
+}
+
+uint64_t plat_drtm_dma_prot_get_max_table_bytes(void)
+{
+ return 0U;
+}
diff --git a/plat/arm/board/fvp/fvp_drtm_err.c b/plat/arm/board/fvp/fvp_drtm_err.c
new file mode 100644
index 0000000..95259fa
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_drtm_err.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <plat/common/platform.h>
+
+int plat_set_drtm_error(uint64_t error_code)
+{
+ /* TODO: Set DRTM error in NV-storage */
+ return 0;
+}
+
+int plat_get_drtm_error(uint64_t *error_code)
+{
+ /* TODO: Get DRTM error from NV-storage */
+ *error_code = 0;
+ return 0;
+}
diff --git a/plat/arm/board/fvp/fvp_drtm_measurement.c b/plat/arm/board/fvp/fvp_drtm_measurement.c
new file mode 100644
index 0000000..4fbedd8
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_drtm_measurement.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <drivers/measured_boot/event_log/event_log.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+/* DRTM TPM Features */
+static const plat_drtm_tpm_features_t tpm_features = {
+ /* No TPM-based hashing supported. */
+ .tpm_based_hash_support = false,
+
+ /* Set to decided algorithm by Event Log driver */
+ .firmware_hash_algorithm = TPM_ALG_ID
+
+};
+
+const plat_drtm_tpm_features_t *plat_drtm_get_tpm_features(void)
+{
+ return &tpm_features;
+}
diff --git a/plat/arm/board/fvp/fvp_drtm_stub.c b/plat/arm/board/fvp/fvp_drtm_stub.c
new file mode 100644
index 0000000..e2bc516
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_drtm_stub.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#include <stdint.h>
+
+#include <services/drtm_svc.h>
+
+/*
+ * This file contains DRTM platform functions which don't really do anything on
+ * FVP but are needed for DRTM to function.
+ */
+
+uint64_t plat_drtm_get_min_size_normal_world_dce(void)
+{
+ return 0ULL;
+}
+
+uint64_t plat_drtm_get_imp_def_dlme_region_size(void)
+{
+ return 0ULL;
+}
+
+uint64_t plat_drtm_get_tcb_hash_features(void)
+{
+ return 0ULL;
+}
+
+uint64_t plat_drtm_get_tcb_hash_table_size(void)
+{
+ return 0ULL;
+}
diff --git a/plat/arm/board/fvp/fvp_el3_spmc.c b/plat/arm/board/fvp/fvp_el3_spmc.c
new file mode 100644
index 0000000..2b347ed
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_el3_spmc.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <services/el3_spmc_ffa_memory.h>
+
+#include <platform_def.h>
+
+/*
+ * On the FVP platform when using the EL3 SPMC implementation allocate the
+ * datastore for tracking shared memory descriptors in the TZC DRAM section
+ * to ensure sufficient storage can be allocated.
+ * Provide an implementation of the accessor method to allow the datastore
+ * details to be retrieved by the SPMC.
+ * The SPMC will take care of initializing the memory region.
+ */
+
+#define PLAT_SPMC_SHMEM_DATASTORE_SIZE 512 * 1024
+
+__section("arm_el3_tzc_dram") static uint8_t
+plat_spmc_shmem_datastore[PLAT_SPMC_SHMEM_DATASTORE_SIZE];
+
+int plat_spmc_shmem_datastore_get(uint8_t **datastore, size_t *size)
+{
+ *datastore = plat_spmc_shmem_datastore;
+ *size = PLAT_SPMC_SHMEM_DATASTORE_SIZE;
+ return 0;
+}
+
+/*
+ * Add dummy implementations of memory management related platform hooks.
+ * These can be used to implement platform specific functionality to support
+ * a memory sharing/lending operation.
+ *
+ * Note: The hooks must be located as part of the initial share request and
+ * final reclaim to prevent order dependencies with operations that may take
+ * place in the normal world without visibility of the SPMC.
+ */
+int plat_spmc_shmem_begin(struct ffa_mtd *desc)
+{
+ return 0;
+}
+int plat_spmc_shmem_reclaim(struct ffa_mtd *desc)
+{
+ return 0;
+}
diff --git a/plat/arm/board/fvp/fvp_el3_spmc_logical_sp.c b/plat/arm/board/fvp/fvp_el3_spmc_logical_sp.c
new file mode 100644
index 0000000..b9e4f86
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_el3_spmc_logical_sp.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <services/el3_spmc_logical_sp.h>
+#include <services/ffa_svc.h>
+#include <smccc_helpers.h>
+
+#define LP_PARTITION_ID 0xC001
+#define LP_UUID {0x47a3bf57, 0xe98e43ad, 0xb7db524f, 0x1588f4e3}
+
+/* Our Logical SP currently only supports receipt of direct messaging. */
+#define PARTITION_PROPERTIES FFA_PARTITION_DIRECT_REQ_RECV
+
+static int32_t sp_init(void)
+{
+ INFO("LSP: Init function called.\n");
+ return 0;
+}
+
+static uint64_t handle_ffa_direct_request(uint32_t smc_fid, bool secure_origin,
+ uint64_t x1, uint64_t x2, uint64_t x3,
+ uint64_t x4, void *cookie,
+ void *handle, uint64_t flags)
+{
+ uint64_t ret;
+
+ /* Determine if we have a 64 or 32 direct request. */
+ if (smc_fid == FFA_MSG_SEND_DIRECT_REQ_SMC32) {
+ ret = FFA_MSG_SEND_DIRECT_RESP_SMC32;
+ } else if (smc_fid == FFA_MSG_SEND_DIRECT_REQ_SMC64) {
+ ret = FFA_MSG_SEND_DIRECT_RESP_SMC64;
+ } else {
+ panic(); /* Unknown SMC. */
+ }
+ /*
+ * Handle the incoming request. For testing purposes we echo the
+ * incoming message.
+ */
+ INFO("Logical Partition: Received Direct Request from %s world!\n",
+ secure_origin ? "Secure" : "Normal");
+
+ /*
+ * Logical SP's must always send a direct response so we can populate
+ * our response directly.
+ */
+ SMC_RET8(handle, ret, 0, 0, x4, 0, 0, 0, 0);
+}
+
+/* Register logical partition */
+DECLARE_LOGICAL_PARTITION(
+ my_logical_partition,
+ sp_init, /* Init Function */
+ LP_PARTITION_ID, /* FF-A Partition ID */
+ LP_UUID, /* UUID */
+ PARTITION_PROPERTIES, /* Partition Properties. */
+ handle_ffa_direct_request /* Callback for direct requests. */
+);
diff --git a/plat/arm/board/fvp/fvp_err.c b/plat/arm/board/fvp/fvp_err.c
new file mode 100644
index 0000000..244659a
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_err.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/arm/sp805.h>
+#include <drivers/cfi/v2m_flash.h>
+#include <lib/mmio.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+/*
+ * FVP error handler
+ */
+__dead2 void plat_arm_error_handler(int err)
+{
+ /* Propagate the err code in the NV-flags register */
+ mmio_write_32(V2M_SYS_NVFLAGS_ADDR, (uint32_t)err);
+
+ console_flush();
+
+ /* Setup the watchdog to reset the system as soon as possible */
+ sp805_refresh(ARM_SP805_TWDG_BASE, 1U);
+
+ for (;;)
+ wfi();
+}
+
+void __dead2 plat_arm_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();
+}
diff --git a/plat/arm/board/fvp/fvp_gicv3.c b/plat/arm/board/fvp/fvp_gicv3.c
new file mode 100644
index 0000000..e780f21
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_gicv3.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <fconf_hw_config_getter.h>
+#include <lib/utils.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/common/fconf_sec_intr_config.h>
+#include <plat/common/platform.h>
+
+#if FVP_GICR_REGION_PROTECTION
+/* To indicate GICR region of the core initialized as Read-Write */
+static bool fvp_gicr_rw_region_init[PLATFORM_CORE_COUNT] = {false};
+#endif /* FVP_GICR_REGION_PROTECTION */
+
+/* The GICv3 driver only needs to be initialized in EL3 */
+static uintptr_t fvp_rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+/* Default GICR base address to be used for GICR probe. */
+static uint64_t fvp_gicr_base_addrs[2] = { 0U };
+
+/* List of zero terminated GICR frame addresses which CPUs will probe */
+static uint64_t *fvp_gicr_frames = fvp_gicr_base_addrs;
+
+#if !(SEC_INT_DESC_IN_FCONF && ((!defined(__aarch64__) && defined(IMAGE_BL32)) || \
+ (defined(__aarch64__) && defined(IMAGE_BL31))))
+static const interrupt_prop_t fvp_interrupt_props[] = {
+ PLAT_ARM_G1S_IRQ_PROPS(INTR_GROUP1S),
+ PLAT_ARM_G0_IRQ_PROPS(INTR_GROUP0)
+};
+#endif
+
+/*
+ * 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 fvp_gicv3_mpidr_hash(u_register_t mpidr)
+{
+ u_register_t temp_mpidr = mpidr;
+
+ temp_mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK);
+ return plat_arm_calc_core_pos(temp_mpidr);
+}
+
+
+static gicv3_driver_data_t fvp_gic_data = {
+ .rdistif_num = PLATFORM_CORE_COUNT,
+ .rdistif_base_addrs = fvp_rdistif_base_addrs,
+ .mpidr_to_core_pos = fvp_gicv3_mpidr_hash
+};
+
+/******************************************************************************
+ * This function gets called per core to make its redistributor frame rw
+ *****************************************************************************/
+static void fvp_gicv3_make_rdistrif_rw(void)
+{
+#if FVP_GICR_REGION_PROTECTION
+ unsigned int core_pos = plat_my_core_pos();
+
+ /* Make the redistributor frame RW if it is not done previously */
+ if (fvp_gicr_rw_region_init[core_pos] != true) {
+ int ret = xlat_change_mem_attributes(BASE_GICR_BASE +
+ (core_pos * BASE_GICR_SIZE),
+ BASE_GICR_SIZE,
+ MT_EXECUTE_NEVER |
+ MT_DEVICE | MT_RW |
+ MT_SECURE);
+
+ if (ret != 0) {
+ ERROR("Failed to make redistributor frame \
+ read write = %d\n", ret);
+ panic();
+ } else {
+ fvp_gicr_rw_region_init[core_pos] = true;
+ }
+ }
+#else
+ return;
+#endif /* FVP_GICR_REGION_PROTECTION */
+}
+
+void plat_arm_gic_driver_init(void)
+{
+ fvp_gicv3_make_rdistrif_rw();
+ /*
+ * Get GICD and GICR base addressed through FCONF APIs.
+ * FCONF is not supported in BL32 for FVP.
+ */
+#if (!defined(__aarch64__) && defined(IMAGE_BL32)) || \
+ (defined(__aarch64__) && defined(IMAGE_BL31))
+ fvp_gic_data.gicd_base = (uintptr_t)FCONF_GET_PROPERTY(hw_config,
+ gicv3_config,
+ gicd_base);
+ fvp_gicr_base_addrs[0] = FCONF_GET_PROPERTY(hw_config, gicv3_config,
+ gicr_base);
+#if SEC_INT_DESC_IN_FCONF
+ fvp_gic_data.interrupt_props = FCONF_GET_PROPERTY(hw_config,
+ sec_intr_prop, descriptor);
+ fvp_gic_data.interrupt_props_num = FCONF_GET_PROPERTY(hw_config,
+ sec_intr_prop, count);
+#else
+ fvp_gic_data.interrupt_props = fvp_interrupt_props;
+ fvp_gic_data.interrupt_props_num = ARRAY_SIZE(fvp_interrupt_props);
+#endif
+#else
+ fvp_gic_data.gicd_base = PLAT_ARM_GICD_BASE;
+ fvp_gicr_base_addrs[0] = PLAT_ARM_GICR_BASE;
+ fvp_gic_data.interrupt_props = fvp_interrupt_props;
+ fvp_gic_data.interrupt_props_num = ARRAY_SIZE(fvp_interrupt_props);
+#endif
+
+ /*
+ * 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(&fvp_gic_data);
+ if (gicv3_rdistif_probe((uintptr_t)fvp_gicr_base_addrs[0]) == -1) {
+ ERROR("No GICR base frame found for Primary CPU\n");
+ panic();
+ }
+#endif
+}
+
+/******************************************************************************
+ * Function to iterate over all GICR frames and discover the corresponding
+ * per-cpu redistributor frame as well as initialize the corresponding
+ * interface in GICv3.
+ *****************************************************************************/
+void plat_arm_gic_pcpu_init(void)
+{
+ int result;
+ const uint64_t *plat_gicr_frames = fvp_gicr_frames;
+
+ fvp_gicv3_make_rdistrif_rw();
+
+ do {
+ result = gicv3_rdistif_probe(*plat_gicr_frames);
+
+ /* If the probe is successful, no need to proceed further */
+ if (result == 0)
+ break;
+
+ plat_gicr_frames++;
+ } while (*plat_gicr_frames != 0U);
+
+ if (result == -1) {
+ ERROR("No GICR base frame found for CPU 0x%lx\n", read_mpidr());
+ panic();
+ }
+ gicv3_rdistif_init(plat_my_core_pos());
+}
diff --git a/plat/arm/board/fvp/fvp_io_storage.c b/plat/arm/board/fvp/fvp_io_storage.c
new file mode 100644
index 0000000..4eef51c
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_io_storage.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_semihosting.h>
+#include <drivers/io/io_storage.h>
+#include <lib/semihosting.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/common_def.h>
+
+/* 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 SOC_FW_CONFIG_NAME "fvp_soc_fw_config.dtb"
+#define TOS_FW_CONFIG_NAME "fvp_tsp_fw_config.dtb"
+#define NT_FW_CONFIG_NAME "fvp_nt_fw_config.dtb"
+#define FW_CONFIG_NAME "fvp_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
+ },
+ [SOC_FW_CONFIG_ID] = {
+ .path = SOC_FW_CONFIG_NAME,
+ .mode = FOPEN_MODE_RB
+ },
+ [TOS_FW_CONFIG_ID] = {
+ .path = TOS_FW_CONFIG_NAME,
+ .mode = FOPEN_MODE_RB
+ },
+ [NT_FW_CONFIG_ID] = {
+ .path = NT_FW_CONFIG_NAME,
+ .mode = FOPEN_MODE_RB
+ },
+ [FW_CONFIG_ID] = {
+ .path = 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;
+
+ io_result = arm_io_setup();
+ if (io_result < 0) {
+ panic();
+ }
+
+ /* Register the additional IO devices on this platform */
+ io_result = register_io_dev_sh(&sh_dev_con);
+ if (io_result < 0) {
+ panic();
+ }
+
+ /* Open connections to devices and cache the handles */
+ io_result = io_dev_open(sh_dev_con, (uintptr_t)NULL, &sh_dev_handle);
+ if (io_result < 0) {
+ panic();
+ }
+}
+
+/*
+ * 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;
+}
diff --git a/plat/arm/board/fvp/fvp_plat_attest_token.c b/plat/arm/board/fvp/fvp_plat_attest_token.c
new file mode 100644
index 0000000..4dd37a4
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_plat_attest_token.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+/* Using hardcoded token values for AEM FVP */
+static uint8_t platform_token[] = {
+ 0xD2, 0x84, 0x40, 0xA0, 0x59, 0x02, 0x46, 0xA9,
+ 0x19, 0x01, 0x09, 0x78, 0x1C, 0x68, 0x74, 0x74,
+ 0x70, 0x3A, 0x2F, 0x2F, 0x61, 0x72, 0x6D, 0x2E,
+ 0x63, 0x6F, 0x6D, 0x2F, 0x43, 0x43, 0x41, 0x2D,
+ 0x53, 0x53, 0x44, 0x2F, 0x31, 0x2E, 0x30, 0x2E,
+ 0x30, 0x0A, 0x58, 0x20, 0x07, 0x06, 0x05, 0x04,
+ 0x03, 0x02, 0x01, 0x00, 0x0F, 0x0E, 0x0D, 0x0C,
+ 0x0B, 0x0A, 0x09, 0x08, 0x17, 0x16, 0x15, 0x14,
+ 0x13, 0x12, 0x11, 0x10, 0x1F, 0x1E, 0x1D, 0x1C,
+ 0x1B, 0x1A, 0x19, 0x18, 0x19, 0x09, 0x5C, 0x58,
+ 0x40, 0x7F, 0x45, 0x4C, 0x46, 0x02, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x3E, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x50, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xA0, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38,
+ 0x00, 0x09, 0x00, 0x40, 0x00, 0x1C, 0x00, 0x1B,
+ 0x00, 0x19, 0x01, 0x00, 0x58, 0x21, 0x01, 0x07,
+ 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0F,
+ 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x17,
+ 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1F,
+ 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x19,
+ 0x09, 0x61, 0x58, 0x21, 0x01, 0x07, 0x06, 0x05,
+ 0x04, 0x03, 0x02, 0x01, 0x00, 0x0F, 0x0E, 0x0D,
+ 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x17, 0x16, 0x15,
+ 0x14, 0x13, 0x12, 0x11, 0x10, 0x1F, 0x1E, 0x1D,
+ 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x19, 0x09, 0x5B,
+ 0x19, 0x30, 0x03, 0x19, 0x09, 0x62, 0x67, 0x73,
+ 0x68, 0x61, 0x2D, 0x32, 0x35, 0x36, 0x19, 0x09,
+ 0x5F, 0x84, 0xA5, 0x01, 0x62, 0x42, 0x4C, 0x05,
+ 0x58, 0x20, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02,
+ 0x01, 0x00, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A,
+ 0x09, 0x08, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12,
+ 0x11, 0x10, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A,
+ 0x19, 0x18, 0x04, 0x65, 0x33, 0x2E, 0x34, 0x2E,
+ 0x32, 0x02, 0x58, 0x20, 0x07, 0x06, 0x05, 0x04,
+ 0x03, 0x02, 0x01, 0x00, 0x0F, 0x0E, 0x0D, 0x0C,
+ 0x0B, 0x0A, 0x09, 0x08, 0x17, 0x16, 0x15, 0x14,
+ 0x13, 0x12, 0x11, 0x10, 0x1F, 0x1E, 0x1D, 0x1C,
+ 0x1B, 0x1A, 0x19, 0x18, 0x06, 0x67, 0x73, 0x68,
+ 0x61, 0x2D, 0x32, 0x35, 0x36, 0xA4, 0x01, 0x62,
+ 0x4D, 0x31, 0x05, 0x58, 0x20, 0x07, 0x06, 0x05,
+ 0x04, 0x03, 0x02, 0x01, 0x00, 0x0F, 0x0E, 0x0D,
+ 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x17, 0x16, 0x15,
+ 0x14, 0x13, 0x12, 0x11, 0x10, 0x1F, 0x1E, 0x1D,
+ 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x04, 0x63, 0x31,
+ 0x2E, 0x32, 0x02, 0x58, 0x20, 0x07, 0x06, 0x05,
+ 0x04, 0x03, 0x02, 0x01, 0x00, 0x0F, 0x0E, 0x0D,
+ 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x17, 0x16, 0x15,
+ 0x14, 0x13, 0x12, 0x11, 0x10, 0x1F, 0x1E, 0x1D,
+ 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0xA4, 0x01, 0x62,
+ 0x4D, 0x32, 0x05, 0x58, 0x20, 0x07, 0x06, 0x05,
+ 0x04, 0x03, 0x02, 0x01, 0x00, 0x0F, 0x0E, 0x0D,
+ 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x17, 0x16, 0x15,
+ 0x14, 0x13, 0x12, 0x11, 0x10, 0x1F, 0x1E, 0x1D,
+ 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x04, 0x65, 0x31,
+ 0x2E, 0x32, 0x2E, 0x33, 0x02, 0x58, 0x20, 0x07,
+ 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0F,
+ 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x17,
+ 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1F,
+ 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0xA4,
+ 0x01, 0x62, 0x4D, 0x33, 0x05, 0x58, 0x20, 0x07,
+ 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0F,
+ 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x17,
+ 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1F,
+ 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x04,
+ 0x61, 0x31, 0x02, 0x58, 0x20, 0x07, 0x06, 0x05,
+ 0x04, 0x03, 0x02, 0x01, 0x00, 0x0F, 0x0E, 0x0D,
+ 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x17, 0x16, 0x15,
+ 0x14, 0x13, 0x12, 0x11, 0x10, 0x1F, 0x1E, 0x1D,
+ 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x19, 0x09, 0x60,
+ 0x6C, 0x77, 0x68, 0x61, 0x74, 0x65, 0x76, 0x65,
+ 0x72, 0x2E, 0x63, 0x6F, 0x6D, 0x58, 0x40, 0x84,
+ 0x32, 0x12, 0x5B, 0x92, 0x6B, 0x20, 0xD8, 0x14,
+ 0xC1, 0xC1, 0x8C, 0x3C, 0x73, 0xB8, 0x29, 0x0F,
+ 0x42, 0xBC, 0x0B, 0x25, 0x87, 0x5C, 0x4F, 0xA4,
+ 0xFA, 0xD9, 0xDE, 0xC1, 0x2B, 0x20, 0xED, 0xDF,
+ 0x1C, 0xDD, 0x1A, 0x09, 0xBD, 0xA0, 0x25, 0x48,
+ 0xC6, 0xBB, 0x99, 0xA1, 0x30, 0x4F, 0x2C, 0xDC,
+ 0x89, 0xE8, 0xB7, 0xFF, 0x32, 0xE9, 0x3F, 0xBB,
+ 0xC6, 0xBF, 0x9D, 0x38, 0x68, 0xE1, 0xB2,
+};
+
+int plat_rmmd_get_cca_attest_token(uintptr_t buf, size_t *len,
+ uintptr_t hash, size_t hash_size)
+{
+ (void)hash;
+ (void)hash_size;
+
+ if (*len < sizeof(platform_token)) {
+ return -EINVAL;
+ }
+
+ (void)memcpy((void *)buf, platform_token, sizeof(platform_token));
+ *len = sizeof(platform_token);
+
+ return 0;
+}
diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c
new file mode 100644
index 0000000..6b9d618
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_pm.c
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/arm/fvp/fvp_pwrc.h>
+#include <lib/extensions/spe.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+#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();
+
+#if HW_ASSISTED_COHERENCY
+ uint32_t reg;
+
+ /*
+ * If we have determined this core to be the last man standing and we
+ * intend to power down the cluster proactively, we provide a hint to
+ * the power controller that cluster power is not required when all
+ * cores are powered down.
+ * Note that this is only an advisory to power controller and is supported
+ * by SoCs with DynamIQ Shared Units only.
+ */
+ reg = read_clusterpwrdn();
+
+ /* Clear and set bit 0 : Cluster power not required */
+ reg &= ~DSU_CLUSTER_PWR_MASK;
+ reg |= DSU_CLUSTER_PWR_OFF;
+ write_clusterpwrdn(reg);
+#endif
+
+ /* 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)
+{
+ u_register_t scr = read_scr_el3();
+
+ assert(cpu_state == ARM_LOCAL_STATE_RET);
+
+ /*
+ * Enable the Non-secure interrupt to wake the CPU.
+ * In GICv3 affinity routing mode, the Non-secure Group 1 interrupts
+ * use Physical FIQ at EL3 whereas in GICv2, Physical IRQ is used.
+ * 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();
+
+ /*
+ * Enter standby state.
+ * dsb is good practice before using wfi to enter low power states.
+ */
+ dsb();
+ wfi();
+
+ /*
+ * Restore SCR_EL3 to the original value, synchronisation of SCR_EL3
+ * is done by eret in el3_exit() to save some execution cycles.
+ */
+ write_scr_el3(scr);
+}
+
+/*******************************************************************************
+ * 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;
+}
diff --git a/plat/arm/board/fvp/fvp_private.h b/plat/arm/board/fvp/fvp_private.h
new file mode 100644
index 0000000..3590370
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_private.h
@@ -0,0 +1,24 @@
+/*
+ * 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 <plat/arm/common/plat_arm.h>
+
+/*******************************************************************************
+ * 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 */
diff --git a/plat/arm/board/fvp/fvp_realm_attest_key.c b/plat/arm/board/fvp/fvp_realm_attest_key.c
new file mode 100644
index 0000000..1af1f0d
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_realm_attest_key.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <services/rmmd_svc.h>
+
+static uint8_t sample_attest_priv_key[] = {
+ 0x20, 0x11, 0xC7, 0xF0, 0x3C, 0xEE, 0x43, 0x25, 0x17, 0x6E,
+ 0x52, 0x4F, 0x03, 0x3C, 0x0C, 0xE1, 0xE2, 0x1A, 0x76, 0xE6,
+ 0xC1, 0xA4, 0xF0, 0xB8, 0x39, 0xAA, 0x1D, 0xF6, 0x1E, 0x0E,
+ 0x8A, 0x5C, 0x8A, 0x05, 0x74, 0x0F, 0x9B, 0x69, 0xEF, 0xA7,
+ 0xEB, 0x1A, 0x41, 0x85, 0xBD, 0x11, 0x7F, 0x68
+};
+
+int plat_rmmd_get_cca_realm_attest_key(uintptr_t buf, size_t *len,
+ unsigned int type)
+{
+ assert(type == ATTEST_KEY_CURVE_ECC_SECP384R1);
+
+ if (*len < sizeof(sample_attest_priv_key)) {
+ return -EINVAL;
+ }
+
+ (void)memcpy((void *)buf, sample_attest_priv_key,
+ sizeof(sample_attest_priv_key));
+ *len = sizeof(sample_attest_priv_key);
+
+ return 0;
+}
diff --git a/plat/arm/board/fvp/fvp_security.c b/plat/arm/board/fvp/fvp_security.c
new file mode 100644
index 0000000..573d92e
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_security.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+/*
+ * 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.
+ */
+
+ const arm_tzc_regions_info_t fvp_tzc_regions[] = {
+ ARM_TZC_REGIONS_DEF,
+#if !SPM_MM && !ENABLE_RME
+ {FVP_DRAM3_BASE, FVP_DRAM3_END,
+ ARM_TZC_NS_DRAM_S_ACCESS, PLAT_ARM_TZC_NS_DEV_ACCESS},
+ {FVP_DRAM4_BASE, FVP_DRAM4_END,
+ ARM_TZC_NS_DRAM_S_ACCESS, PLAT_ARM_TZC_NS_DEV_ACCESS},
+ {FVP_DRAM5_BASE, FVP_DRAM5_END,
+ ARM_TZC_NS_DRAM_S_ACCESS, PLAT_ARM_TZC_NS_DEV_ACCESS},
+ {FVP_DRAM6_BASE, FVP_DRAM6_END,
+ ARM_TZC_NS_DRAM_S_ACCESS, PLAT_ARM_TZC_NS_DEV_ACCESS},
+#endif
+ {0}
+ };
+
+ if ((get_arm_config()->flags & ARM_CONFIG_HAS_TZC) != 0U)
+ arm_tzc400_setup(PLAT_ARM_TZC_BASE, fvp_tzc_regions);
+}
diff --git a/plat/arm/board/fvp/fvp_stack_protector.c b/plat/arm/board/fvp/fvp_stack_protector.c
new file mode 100644
index 0000000..e940a12
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_stack_protector.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <plat/common/platform.h>
+
+#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();
+}
+
diff --git a/plat/arm/board/fvp/fvp_topology.c b/plat/arm/board/fvp/fvp_topology.c
new file mode 100644
index 0000000..80cfbd5
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_topology.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <drivers/arm/fvp/fvp_pwrc.h>
+#include <fconf_hw_config_getter.h>
+#include <lib/cassert.h>
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+/* 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 cpu-map node
+ * in HW_CONFIG dtb and returns it.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ unsigned int i;
+ uint32_t cluster_count, cpus_per_cluster;
+
+ /*
+ * fconf APIs are not supported for RESET_TO_SP_MIN, RESET_TO_BL31 and
+ * BL2_AT_EL3 systems.
+ */
+#if RESET_TO_SP_MIN || RESET_TO_BL31 || BL2_AT_EL3
+ cluster_count = FVP_CLUSTER_COUNT;
+ cpus_per_cluster = FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU;
+#else
+ cluster_count = FCONF_GET_PROPERTY(hw_config, topology, plat_cluster_count);
+ cpus_per_cluster = FCONF_GET_PROPERTY(hw_config, topology, cluster_cpu_count);
+ /* Several FVP Models use the same blanket dts. Ex: FVP_Base_Cortex-A65x4
+ * and FVP_Base_Cortex-A65AEx8 both use same dts but have different number of
+ * CPUs in the cluster, as reflected by build flags FVP_MAX_CPUS_PER_CLUSTER.
+ * Take the minimum of two to ensure PSCI functions do not exceed the size of
+ * the PSCI data structures allocated at build time.
+ */
+ cpus_per_cluster = MIN(cpus_per_cluster,
+ (uint32_t)(FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU));
+
+#endif
+
+ assert(cluster_count > 0U);
+ assert(cpus_per_cluster > 0U);
+
+ /*
+ * 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] = (unsigned char)cluster_count;
+
+ for (i = 0; i < cluster_count; i++)
+ fvp_power_domain_tree_desc[i + 2] = (unsigned char)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);
+}
diff --git a/plat/arm/board/fvp/fvp_trusted_boot.c b/plat/arm/board/fvp/fvp_trusted_boot.c
new file mode 100644
index 0000000..1ea37f7
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_trusted_boot.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <lib/mmio.h>
+#include <lib/fconf/fconf.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/common/fconf_nv_cntr_getter.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <tools_share/tbbr_oid.h>
+
+/*
+ * 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)
+{
+ return arm_get_rotpk_info(cookie, key_ptr, key_len, flags);
+}
+
+/*
+ * 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 = FCONF_GET_PROPERTY(cot, nv_cntr_addr,
+ TRUSTED_NV_CTR_ID);
+ } else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) {
+ nv_ctr_addr = FCONF_GET_PROPERTY(cot, nv_cntr_addr,
+ NON_TRUSTED_NV_CTR_ID);
+ } 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;
+}
diff --git a/plat/arm/board/fvp/include/fconf_hw_config_getter.h b/plat/arm/board/fvp/include/fconf_hw_config_getter.h
new file mode 100644
index 0000000..ca85f7a
--- /dev/null
+++ b/plat/arm/board/fvp/include/fconf_hw_config_getter.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FCONF_HW_CONFIG_GETTER_H
+#define FCONF_HW_CONFIG_GETTER_H
+
+#include <lib/fconf/fconf.h>
+
+/* Hardware Config related getter */
+#define hw_config__gicv3_config_getter(prop) gicv3_config.prop
+#define hw_config__topology_getter(prop) soc_topology.prop
+#define hw_config__uart_serial_config_getter(prop) uart_serial_config.prop
+#define hw_config__cpu_timer_getter(prop) cpu_timer.prop
+
+struct gicv3_config_t {
+ uint64_t gicd_base;
+ uint64_t gicr_base;
+};
+
+struct hw_topology_t {
+ uint32_t plat_cluster_count;
+ uint32_t cluster_cpu_count;
+ uint32_t plat_cpu_count;
+ uint32_t plat_max_pwr_level;
+};
+
+struct uart_serial_config_t {
+ uint64_t uart_base;
+ uint32_t uart_clk;
+};
+
+struct cpu_timer_t {
+ uint32_t clock_freq;
+};
+
+int fconf_populate_gicv3_config(uintptr_t config);
+int fconf_populate_topology(uintptr_t config);
+int fconf_populate_uart_config(uintptr_t config);
+int fconf_populate_cpu_timer(uintptr_t config);
+
+extern struct gicv3_config_t gicv3_config;
+extern struct hw_topology_t soc_topology;
+extern struct uart_serial_config_t uart_serial_config;
+extern struct cpu_timer_t cpu_timer;
+#endif /* FCONF_HW_CONFIG_GETTER_H */
diff --git a/plat/arm/board/fvp/include/fconf_nt_config_getter.h b/plat/arm/board/fvp/include/fconf_nt_config_getter.h
new file mode 100644
index 0000000..0824c35
--- /dev/null
+++ b/plat/arm/board/fvp/include/fconf_nt_config_getter.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FCONF_NT_CONFIG_GETTER_H
+#define FCONF_NT_CONFIG_GETTER_H
+
+#include <lib/fconf/fconf.h>
+
+/* NT Firmware Config related getter */
+#define nt_config__event_log_config_getter(prop) event_log.prop
+
+struct event_log_config_t {
+#ifdef SPD_opteed
+ void *tpm_event_log_sm_addr;
+#endif
+ void *tpm_event_log_addr;
+ size_t tpm_event_log_size;
+};
+
+int fconf_populate_event_log_config(uintptr_t config);
+
+extern struct event_log_config_t event_log_config;
+
+#endif /* FCONF_NT_CONFIG_GETTER_H */
diff --git a/plat/arm/board/fvp/include/fvp_critical_data.h b/plat/arm/board/fvp/include/fvp_critical_data.h
new file mode 100644
index 0000000..04bd5b2
--- /dev/null
+++ b/plat/arm/board/fvp/include/fvp_critical_data.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef FVP_CRITICAL_DATA_H
+#define FVP_CRITICAL_DATA_H
+
+#include <common/nv_cntr_ids.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+
+#define EVLOG_CRITICAL_DATA_STRING "CRITICAL DATA"
+
+#define CRITICAL_DATA_ID CRITICAL_DATA_ID_BASE
+
+struct fvp_critical_data {
+
+ /* platform NV counters */
+ unsigned int nv_ctr[MAX_NV_CTR_IDS];
+};
+
+#endif /* FVP_CRITICAL_DATA_H */
diff --git a/plat/arm/board/fvp/include/plat.ld.S b/plat/arm/board/fvp/include/plat.ld.S
new file mode 100644
index 0000000..7c8bf06
--- /dev/null
+++ b/plat/arm/board/fvp/include/plat.ld.S
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_LD_S
+#define PLAT_LD_S
+
+#include <plat/arm/common/arm_tzc_dram.ld.S>
+
+#if RECLAIM_INIT_CODE
+#include <plat/arm/common/arm_reclaim_init.ld.S>
+#endif /* RECLAIM_INIT_CODE */
+
+#endif /* PLAT_LD_S */
diff --git a/plat/arm/board/fvp/include/plat_macros.S b/plat/arm/board/fvp/include/plat_macros.S
new file mode 100644
index 0000000..57f5924
--- /dev/null
+++ b/plat/arm/board/fvp/include/plat_macros.S
@@ -0,0 +1,42 @@
+/*
+ * 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 <arm_macros.S>
+#include <platform_def.h>
+
+ /* ---------------------------------------------
+ * 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 */
diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h
new file mode 100644
index 0000000..1ef6c87
--- /dev/null
+++ b/plat/arm/board/fvp/include/platform_def.h
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2014-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <drivers/arm/tzc400.h>
+#include <lib/utils_def.h>
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/common/arm_def.h>
+#include <plat/arm/common/arm_spm_def.h>
+#include <plat/common/common_def.h>
+
+#include "../fvp_def.h"
+
+/* Required platform porting definitions */
+#define PLATFORM_CORE_COUNT (U(FVP_CLUSTER_COUNT) * \
+ U(FVP_MAX_CPUS_PER_CLUSTER) * \
+ U(FVP_MAX_PE_PER_CPU))
+
+#define PLAT_NUM_PWR_DOMAINS (U(FVP_CLUSTER_COUNT) + \
+ PLATFORM_CORE_COUNT + U(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 U(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 */
+
+#if ENABLE_RME
+#define PLAT_ARM_RMM_BASE (RMM_BASE)
+#define PLAT_ARM_RMM_SIZE (RMM_LIMIT - RMM_BASE)
+#endif
+
+/*
+ * Max size of SPMC is 2MB for fvp. With SPMD enabled this value corresponds to
+ * max size of BL32 image.
+ */
+#if defined(SPD_spmd)
+#define PLAT_ARM_SPMC_BASE PLAT_ARM_TRUSTED_DRAM_BASE
+#define PLAT_ARM_SPMC_SIZE UL(0x200000) /* 2 MB */
+#endif
+
+/* 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) /* 36-bit range */
+#define PLAT_ARM_DRAM2_SIZE ULL(0x780000000) /* 30 GB */
+
+#define FVP_DRAM3_BASE ULL(0x8800000000) /* 40-bit range */
+#define FVP_DRAM3_SIZE ULL(0x7800000000) /* 480 GB */
+#define FVP_DRAM3_END (FVP_DRAM3_BASE + FVP_DRAM3_SIZE - 1U)
+
+#define FVP_DRAM4_BASE ULL(0x88000000000) /* 44-bit range */
+#define FVP_DRAM4_SIZE ULL(0x78000000000) /* 7.5 TB */
+#define FVP_DRAM4_END (FVP_DRAM4_BASE + FVP_DRAM4_SIZE - 1U)
+
+#define FVP_DRAM5_BASE ULL(0x880000000000) /* 48-bit range */
+#define FVP_DRAM5_SIZE ULL(0x780000000000) /* 120 TB */
+#define FVP_DRAM5_END (FVP_DRAM5_BASE + FVP_DRAM5_SIZE - 1U)
+
+#define FVP_DRAM6_BASE ULL(0x8800000000000) /* 52-bit range */
+#define FVP_DRAM6_SIZE ULL(0x7800000000000) /* 1920 TB */
+#define FVP_DRAM6_END (FVP_DRAM6_BASE + FVP_DRAM6_SIZE - 1U)
+
+/* Range of kernel DTB load address */
+#define FVP_DTB_DRAM_MAP_START ULL(0x82000000)
+#define FVP_DTB_DRAM_MAP_SIZE ULL(0x02000000) /* 32 MB */
+
+#define ARM_DTB_DRAM_NS MAP_REGION_FLAT( \
+ FVP_DTB_DRAM_MAP_START, \
+ FVP_DTB_DRAM_MAP_SIZE, \
+ MT_MEMORY | MT_RO | MT_NS)
+
+#if SPMC_AT_EL3
+/*
+ * Number of Secure Partitions supported.
+ * SPMC at EL3, uses this count to configure the maximum number of supported
+ * secure partitions.
+ */
+#define SECURE_PARTITION_COUNT 1
+
+/*
+ * Number of Normal World Partitions supported.
+ * SPMC at EL3, uses this count to configure the maximum number of supported
+ * NWd partitions.
+ */
+#define NS_PARTITION_COUNT 1
+
+/*
+ * Number of Logical Partitions supported.
+ * SPMC at EL3, uses this count to configure the maximum number of supported
+ * logical partitions.
+ */
+#define MAX_EL3_LP_DESCS_COUNT 1
+
+#endif /* SPMC_AT_EL3 */
+
+/*
+ * 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 SPM_MM
+# define PLAT_ARM_MMAP_ENTRIES 10
+# define MAX_XLAT_TABLES 9
+# define PLAT_SP_IMAGE_MMAP_REGIONS 30
+# define PLAT_SP_IMAGE_MAX_XLAT_TABLES 10
+# elif SPMC_AT_EL3
+# define PLAT_ARM_MMAP_ENTRIES 13
+# define MAX_XLAT_TABLES 11
+# else
+# define PLAT_ARM_MMAP_ENTRIES 9
+# if USE_DEBUGFS
+# if ENABLE_RME
+# define MAX_XLAT_TABLES 9
+# else
+# define MAX_XLAT_TABLES 8
+# endif
+# else
+# if ENABLE_RME
+# define MAX_XLAT_TABLES 8
+# elif DRTM_SUPPORT
+# define MAX_XLAT_TABLES 8
+# else
+# define MAX_XLAT_TABLES 7
+# endif
+# endif
+# endif
+#elif defined(IMAGE_BL32)
+# if SPMC_AT_EL3
+# define PLAT_ARM_MMAP_ENTRIES 270
+# define MAX_XLAT_TABLES 10
+# else
+# define PLAT_ARM_MMAP_ENTRIES 9
+# define MAX_XLAT_TABLES 6
+# endif
+#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)
+#define FVP_BL2_ROMLIB_OPTIMIZATION UL(0x5000)
+#else
+#define PLAT_ARM_MAX_ROMLIB_RW_SIZE UL(0)
+#define PLAT_ARM_MAX_ROMLIB_RO_SIZE UL(0)
+#define FVP_BL2_ROMLIB_OPTIMIZATION 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 && COT_DESC_IN_DTB
+# define PLAT_ARM_MAX_BL2_SIZE (UL(0x1E000) - FVP_BL2_ROMLIB_OPTIMIZATION)
+#elif CRYPTO_SUPPORT
+# define PLAT_ARM_MAX_BL2_SIZE (UL(0x1D000) - FVP_BL2_ROMLIB_OPTIMIZATION)
+#elif ARM_BL31_IN_DRAM
+/* When ARM_BL31_IN_DRAM is set, BL2 can use almost all of Trusted SRAM. */
+# define PLAT_ARM_MAX_BL2_SIZE (UL(0x1F000) - FVP_BL2_ROMLIB_OPTIMIZATION)
+#else
+# define PLAT_ARM_MAX_BL2_SIZE (UL(0x13000) - FVP_BL2_ROMLIB_OPTIMIZATION)
+#endif
+
+#if RESET_TO_BL31
+/* Size of Trusted SRAM - the first 4KB of shared memory - GPT L0 Tables */
+#define PLAT_ARM_MAX_BL31_SIZE (PLAT_ARM_TRUSTED_SRAM_SIZE - \
+ ARM_SHARED_RAM_SIZE - \
+ ARM_L0_GPT_SIZE)
+#else
+/*
+ * 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 (UL(0x3D000) - ARM_L0_GPT_SIZE)
+#endif /* RESET_TO_BL31 */
+
+#ifndef __aarch64__
+#if RESET_TO_SP_MIN
+/* Size of Trusted SRAM - the first 4KB of shared memory */
+#define PLAT_ARM_MAX_BL32_SIZE (PLAT_ARM_TRUSTED_SRAM_SIZE - \
+ ARM_SHARED_RAM_SIZE)
+#else
+/*
+ * 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 /* RESET_TO_SP_MIN */
+#endif
+
+/*
+ * Size of cacheable stacks
+ */
+#if defined(IMAGE_BL1)
+# if CRYPTO_SUPPORT
+# define PLATFORM_STACK_SIZE UL(0x1000)
+# else
+# define PLATFORM_STACK_SIZE UL(0x500)
+# endif /* CRYPTO_SUPPORT */
+#elif defined(IMAGE_BL2)
+# if CRYPTO_SUPPORT
+# define PLATFORM_STACK_SIZE UL(0x1000)
+# else
+# define PLATFORM_STACK_SIZE UL(0x600)
+# endif /* CRYPTO_SUPPORT */
+#elif defined(IMAGE_BL2U)
+# define PLATFORM_STACK_SIZE UL(0x400)
+#elif defined(IMAGE_BL31)
+# if DRTM_SUPPORT
+# define PLATFORM_STACK_SIZE UL(0x1000)
+# else
+# define PLATFORM_STACK_SIZE UL(0x800)
+# endif /* DRTM_SUPPORT */
+#elif defined(IMAGE_BL32)
+# if SPMC_AT_EL3
+# define PLATFORM_STACK_SIZE UL(0x1000)
+# else
+# define PLATFORM_STACK_SIZE UL(0x440)
+# endif /* SPMC_AT_EL3 */
+#elif defined(IMAGE_RMM)
+# 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_FLASH_IMAGE_BASE V2M_FLASH0_BASE
+#define PLAT_ARM_FLASH_IMAGE_MAX_SIZE (V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+#if ARM_GPT_SUPPORT
+/*
+ * Offset of the FIP in the GPT image. BL1 component uses this option
+ * as it does not load the partition table to get the FIP base
+ * address. At sector 34 by default (i.e. after reserved sectors 0-33)
+ * Offset = 34 * 512(sector size) = 17408 i.e. 0x4400
+ */
+#define PLAT_ARM_FIP_OFFSET_IN_GPT 0x4400
+#endif /* ARM_GPT_SUPPORT */
+
+#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_ARM_TRP_UART_BASE V2M_IOFPGA_UART3_BASE
+#define PLAT_ARM_TRP_UART_CLK_IN_HZ V2M_IOFPGA_UART3_CLK_IN_HZ
+
+#define PLAT_FVP_SMMUV3_BASE UL(0x2b400000)
+#define PLAT_ARM_SMMUV3_ROOT_REG_OFFSET UL(0x20000)
+
+/* 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 overridden 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)
+
+#if SDEI_IN_FCONF
+#define PLAT_SDEI_DP_EVENT_MAX_CNT ARM_SDEI_DP_EVENT_MAX_CNT
+#define PLAT_SDEI_DS_EVENT_MAX_CNT ARM_SDEI_DS_EVENT_MAX_CNT
+#else
+#define PLAT_ARM_PRIVATE_SDEI_EVENTS ARM_SDEI_PRIVATE_EVENTS
+#define PLAT_ARM_SHARED_SDEI_EVENTS ARM_SDEI_SHARED_EVENTS
+#endif
+
+#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
+
+/*
+ * Maximum size of Event Log buffer used in Measured Boot Event Log driver
+ */
+#define PLAT_ARM_EVENT_LOG_MAX_SIZE UL(0x400)
+
+/*
+ * Maximum size of Event Log buffer used for DRTM
+ */
+#define PLAT_DRTM_EVENT_LOG_MAX_SIZE UL(0x300)
+
+/*
+ * Number of MMAP entries used by DRTM implementation
+ */
+#define PLAT_DRTM_MMAP_ENTRIES PLAT_ARM_MMAP_ENTRIES
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/fvp/jmptbl.i b/plat/arm/board/fvp/jmptbl.i
new file mode 100644
index 0000000..85e6e3a
--- /dev/null
+++ b/plat/arm/board/fvp/jmptbl.i
@@ -0,0 +1,63 @@
+#
+# Copyright (c) 2018-2022, 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
+fdt fdt_get_property
+fdt fdt_getprop_namelen
+fdt fdt_setprop_inplace
+fdt fdt_check_header
+fdt fdt_node_offset_by_compatible
+fdt fdt_setprop_inplace_namelen_partial
+fdt fdt_first_subnode
+fdt fdt_next_subnode
+fdt fdt_path_offset
+fdt fdt_path_offset_namelen
+fdt fdt_subnode_offset
+fdt fdt_address_cells
+fdt fdt_size_cells
+fdt fdt_parent_offset
+fdt fdt_stringlist_search
+fdt fdt_get_alias_namelen
+fdt fdt_get_name
+fdt fdt_get_alias
+fdt fdt_node_offset_by_phandle
+fdt fdt_subnode_offset
+fdt fdt_add_subnode
+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
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
new file mode 100644
index 0000000..51ba035
--- /dev/null
+++ b/plat/arm/board/fvp/platform.mk
@@ -0,0 +1,464 @@
+#
+# Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include common/fdt_wrappers.mk
+
+# Use the GICv3 driver on the FVP by default
+FVP_USE_GIC_DRIVER := FVP_GICV3
+
+# 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
+
+# Disable redistributor frame of inactive/fused CPU cores by marking it as read
+# only; enable redistributor frames of all CPU cores by default.
+FVP_GICR_REGION_PROTECTION := 0
+
+FVP_DT_PREFIX := fvp-base-gicv3-psci
+
+# 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))
+
+# Pass FVP_GICR_REGION_PROTECTION to the build system.
+$(eval $(call add_define,FVP_GICR_REGION_PROTECTION))
+
+# 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))
+
+# Choose the GIC sources depending upon the how the FVP will be invoked
+ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3)
+
+# The GIC model (GIC-600 or GIC-500) will be detected at runtime
+GICV3_SUPPORT_GIC600 := 1
+GICV3_OVERRIDE_DISTIF_PWR_OPS := 1
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+FVP_GIC_SOURCES := ${GICV3_SOURCES} \
+ plat/common/plat_gicv3.c \
+ plat/arm/common/arm_gicv3.c
+
+ ifeq ($(filter 1,${BL2_AT_EL3} ${RESET_TO_BL31} ${RESET_TO_SP_MIN}),)
+ FVP_GIC_SOURCES += plat/arm/board/fvp/fvp_gicv3.c
+ endif
+
+else ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV2)
+
+# No GICv4 extension
+GIC_ENABLE_V4_EXTN := 0
+$(eval $(call add_define,GIC_ENABLE_V4_EXTN))
+
+# Include GICv2 driver files
+include drivers/arm/gic/v2/gicv2.mk
+
+FVP_GIC_SOURCES := ${GICV2_SOURCES} \
+ 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/cortex_a78.S \
+ lib/cpus/aarch64/neoverse_n_common.S \
+ lib/cpus/aarch64/neoverse_n1.S \
+ lib/cpus/aarch64/neoverse_n2.S \
+ lib/cpus/aarch64/neoverse_e1.S \
+ lib/cpus/aarch64/neoverse_v1.S \
+ lib/cpus/aarch64/neoverse_v2.S \
+ lib/cpus/aarch64/cortex_a78_ae.S \
+ lib/cpus/aarch64/cortex_a510.S \
+ lib/cpus/aarch64/cortex_a710.S \
+ lib/cpus/aarch64/cortex_a715.S \
+ lib/cpus/aarch64/cortex_x3.S \
+ lib/cpus/aarch64/cortex_a65.S \
+ lib/cpus/aarch64/cortex_a65ae.S \
+ lib/cpus/aarch64/cortex_a78c.S \
+ lib/cpus/aarch64/cortex_hayes.S \
+ lib/cpus/aarch64/cortex_hunter.S \
+ lib/cpus/aarch64/cortex_hunter_elp_arm.S \
+ lib/cpus/aarch64/cortex_x2.S \
+ lib/cpus/aarch64/neoverse_poseidon.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 \
+ ${FVP_CPU_LIBS} \
+ ${FVP_INTERCONNECT_SOURCES}
+
+ifeq (${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/common/arm_nor_psci_mem_protect.c \
+ ${FVP_SECURITY_SOURCES}
+
+
+ifeq (${COT_DESC_IN_DTB},1)
+BL2_SOURCES += plat/arm/common/fconf/fconf_nv_cntr_getter.c
+endif
+
+ifeq (${ENABLE_RME},1)
+BL2_SOURCES += plat/arm/board/fvp/aarch64/fvp_helpers.S
+BL31_SOURCES += plat/arm/board/fvp/fvp_plat_attest_token.c \
+ plat/arm/board/fvp/fvp_realm_attest_key.c
+endif
+
+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 (${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 (${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_console.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}
+
+# Support for fconf in BL31
+# Added separately from the above list for better readability
+ifeq ($(filter 1,${BL2_AT_EL3} ${RESET_TO_BL31}),)
+BL31_SOURCES += lib/fconf/fconf.c \
+ lib/fconf/fconf_dyn_cfg_getter.c \
+ plat/arm/board/fvp/fconf/fconf_hw_config_getter.c
+
+BL31_SOURCES += ${FDT_WRAPPERS_SOURCES}
+
+ifeq (${SEC_INT_DESC_IN_FCONF},1)
+BL31_SOURCES += plat/arm/common/fconf/fconf_sec_intr_config.c
+endif
+
+endif
+
+ifeq (${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}_fw_config.dts \
+ ${PLAT}_tb_fw_config.dts \
+ ${PLAT}_soc_fw_config.dts \
+ ${PLAT}_nt_fw_config.dts \
+ )
+
+FVP_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_fw_config.dtb
+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,${FVP_TOS_FW_CONFIG}))
+endif
+
+ifeq (${SPD},spmd)
+
+ifeq ($(ARM_SPMC_MANIFEST_DTS),)
+ARM_SPMC_MANIFEST_DTS := plat/arm/board/fvp/fdts/${PLAT}_spmc_manifest.dts
+endif
+
+FDT_SOURCES += ${ARM_SPMC_MANIFEST_DTS}
+FVP_TOS_FW_CONFIG := ${BUILD_PLAT}/fdts/$(notdir $(basename ${ARM_SPMC_MANIFEST_DTS})).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,${FVP_TOS_FW_CONFIG}))
+endif
+
+# Add the FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FVP_FW_CONFIG},--fw-config,${FVP_FW_CONFIG}))
+# 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,${FVP_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,${FVP_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,${FVP_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,${FVP_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
+
+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 ($(filter 1,${BL2_AT_EL3} ${ARM_XLAT_TABLES_LIB_V1}),)
+ ifeq (${ARCH},aarch32)
+ BL32_CPPFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC
+ else # AArch64
+ BL31_CPPFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC
+ endif
+endif
+
+ifeq (${ALLOW_RO_XLAT_TABLES}, 1)
+ ifeq (${ARCH},aarch32)
+ BL32_CPPFLAGS += -DPLAT_RO_XLAT_TABLES
+ else # AArch64
+ BL31_CPPFLAGS += -DPLAT_RO_XLAT_TABLES
+ ifeq (${SPD},tspd)
+ BL32_CPPFLAGS += -DPLAT_RO_XLAT_TABLES
+ endif
+ endif
+endif
+
+ifeq (${USE_DEBUGFS},1)
+ BL31_CPPFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC
+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 Measured Boot makefile before any Crypto library makefile.
+# Crypto library makefile may need default definitions of Measured Boot build
+# flags present in Measured Boot makefile.
+ifeq (${MEASURED_BOOT},1)
+ RSS_MEASURED_BOOT_MK := drivers/measured_boot/rss/rss_measured_boot.mk
+ $(info Including ${RSS_MEASURED_BOOT_MK})
+ include ${RSS_MEASURED_BOOT_MK}
+
+ ifneq (${MBOOT_RSS_HASH_ALG}, sha256)
+ $(eval $(call add_define,TF_MBEDTLS_MBOOT_USE_SHA512))
+ endif
+
+ BL1_SOURCES += ${MEASURED_BOOT_SOURCES}
+ BL2_SOURCES += ${MEASURED_BOOT_SOURCES}
+endif
+
+include plat/arm/board/common/board_common.mk
+include plat/arm/common/arm_common.mk
+
+ifeq (${MEASURED_BOOT},1)
+BL1_SOURCES += plat/arm/board/fvp/fvp_common_measured_boot.c \
+ plat/arm/board/fvp/fvp_bl1_measured_boot.c \
+ lib/psa/measured_boot.c
+
+BL2_SOURCES += plat/arm/board/fvp/fvp_common_measured_boot.c \
+ plat/arm/board/fvp/fvp_bl2_measured_boot.c \
+ lib/psa/measured_boot.c
+
+# Note that attestation code does not depend on measured boot interfaces per se,
+# but the two features go together - attestation without boot measurements is
+# pretty much pointless...
+BL31_SOURCES += lib/psa/delegated_attestation.c
+
+PLAT_INCLUDES += -Iinclude/lib/psa
+
+# RSS is not supported on FVP right now. Thus, we use the mocked version
+# of the provided PSA APIs. They return with success and hard-coded data.
+PLAT_RSS_NOT_SUPPORTED := 1
+
+# Even though RSS is not supported on FVP (see above), we support overriding
+# PLAT_RSS_NOT_SUPPORTED from the command line, just for the purpose of building
+# the code to detect any build regressions. The resulting firmware will not be
+# functional.
+ifneq (${PLAT_RSS_NOT_SUPPORTED},1)
+ $(warning "RSS is not supported on FVP. The firmware will not be functional.")
+ include drivers/arm/rss/rss_comms.mk
+ BL1_SOURCES += ${RSS_COMMS_SOURCES}
+ BL2_SOURCES += ${RSS_COMMS_SOURCES}
+ BL31_SOURCES += ${RSS_COMMS_SOURCES} \
+ lib/psa/delegated_attestation.c
+
+ BL1_CFLAGS += -DPLAT_RSS_COMMS_PAYLOAD_MAX_SIZE=0
+ BL2_CFLAGS += -DPLAT_RSS_COMMS_PAYLOAD_MAX_SIZE=0
+ BL31_CFLAGS += -DPLAT_RSS_COMMS_PAYLOAD_MAX_SIZE=0
+endif
+
+endif
+
+ifeq (${DRTM_SUPPORT}, 1)
+BL31_SOURCES += plat/arm/board/fvp/fvp_drtm_addr.c \
+ plat/arm/board/fvp/fvp_drtm_dma_prot.c \
+ plat/arm/board/fvp/fvp_drtm_err.c \
+ plat/arm/board/fvp/fvp_drtm_measurement.c \
+ plat/arm/board/fvp/fvp_drtm_stub.c \
+ plat/arm/common/arm_dyn_cfg.c \
+ plat/arm/board/fvp/fvp_err.c
+endif
+
+ifeq (${TRUSTED_BOARD_BOOT}, 1)
+BL1_SOURCES += plat/arm/board/fvp/fvp_trusted_boot.c
+BL2_SOURCES += plat/arm/board/fvp/fvp_trusted_boot.c
+
+# FVP being a development platform, enable capability to disable Authentication
+# dynamically if TRUSTED_BOARD_BOOT is set.
+DYN_DISABLE_AUTH := 1
+endif
+
+# enable trace buffer control registers access to NS by default
+ENABLE_TRBE_FOR_NS := 1
+
+# enable branch record buffer control registers access in NS by default
+# only enable for aarch64
+# do not enable when ENABLE_RME=1
+ifeq (${ARCH}, aarch64)
+ifeq (${ENABLE_RME},0)
+ ENABLE_BRBE_FOR_NS := 1
+endif
+endif
+
+# enable trace system registers access to NS by default
+ENABLE_SYS_REG_TRACE_FOR_NS := 1
+
+# enable trace filter control registers access to NS by default
+ENABLE_TRF_FOR_NS := 1
+
+ifeq (${SPMC_AT_EL3}, 1)
+PLAT_BL_COMMON_SOURCES += plat/arm/board/fvp/fvp_el3_spmc.c
+endif
diff --git a/plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c b/plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c
new file mode 100644
index 0000000..9ab36a6
--- /dev/null
+++ b/plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2016-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <bl32/sp_min/platform_sp_min.h>
+#include <common/debug.h>
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_dyn_cfg_getter.h>
+#include <plat/arm/common/plat_arm.h>
+
+#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)
+{
+ const struct dyn_cfg_dtb_info_t *tos_fw_config_info __unused;
+
+ /* Initialize the console to provide early debug support */
+ arm_console_boot_init();
+
+#if !RESET_TO_SP_MIN && !BL2_AT_EL3
+
+ INFO("SP_MIN FCONF: FW_CONFIG address = %lx\n", (uintptr_t)arg1);
+ /* Fill the properties struct with the info from the config dtb */
+ fconf_populate("FW_CONFIG", arg1);
+
+ tos_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TOS_FW_CONFIG_ID);
+ if (tos_fw_config_info != NULL) {
+ arg1 = tos_fw_config_info->config_addr;
+ }
+#endif /* !RESET_TO_SP_MIN && !BL2_AT_EL3 */
+
+ 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();
+}
+
+void sp_min_plat_arch_setup(void)
+{
+ int rc __unused;
+ const struct dyn_cfg_dtb_info_t *hw_config_info __unused;
+ uintptr_t hw_config_base_align __unused;
+ size_t mapped_size_align __unused;
+
+ arm_sp_min_plat_arch_setup();
+
+ /*
+ * For RESET_TO_SP_MIN systems, SP_MIN(BL32) is the first bootloader
+ * to run. So there is no BL2 to load the HW_CONFIG dtb into memory
+ * before control is passed to SP_MIN.
+ * Also, BL2 skips loading HW_CONFIG dtb for BL2_AT_EL3 builds.
+ * The code below relies on dynamic mapping capability, which is not
+ * supported by xlat tables lib V1.
+ * TODO: remove the ARM_XLAT_TABLES_LIB_V1 check when its support
+ * gets deprecated.
+ */
+#if !RESET_TO_SP_MIN && !BL2_AT_EL3 && !ARM_XLAT_TABLES_LIB_V1
+ hw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, HW_CONFIG_ID);
+ assert(hw_config_info != NULL);
+ assert(hw_config_info->config_addr != 0UL);
+
+ INFO("SP_MIN FCONF: HW_CONFIG address = %p\n",
+ (void *)hw_config_info->config_addr);
+
+ /*
+ * Preferrably we expect this address and size are page aligned,
+ * but if they are not then align it.
+ */
+ hw_config_base_align = page_align(hw_config_info->config_addr, DOWN);
+ mapped_size_align = page_align(hw_config_info->config_max_size, UP);
+
+ if ((hw_config_info->config_addr != hw_config_base_align) &&
+ (hw_config_info->config_max_size == mapped_size_align)) {
+ mapped_size_align += PAGE_SIZE;
+ }
+
+ /*
+ * map dynamically HW config region with its aligned base address and
+ * size
+ */
+ rc = mmap_add_dynamic_region((unsigned long long)hw_config_base_align,
+ hw_config_base_align,
+ mapped_size_align,
+ MT_RO_DATA);
+ if (rc != 0) {
+ ERROR("Error while mapping HW_CONFIG device tree (%d).\n", rc);
+ panic();
+ }
+
+ /* Populate HW_CONFIG device tree with the mapped address */
+ fconf_populate("HW_CONFIG", hw_config_info->config_addr);
+
+ /* unmap the HW_CONFIG memory region */
+ rc = mmap_remove_dynamic_region(hw_config_base_align, mapped_size_align);
+ if (rc != 0) {
+ ERROR("Error while unmapping HW_CONFIG device tree (%d).\n",
+ rc);
+ panic();
+ }
+#endif /* !RESET_TO_SP_MIN && !BL2_AT_EL3 && !ARM_XLAT_TABLES_LIB_V1 */
+}
diff --git a/plat/arm/board/fvp/sp_min/sp_min-fvp.mk b/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
new file mode 100644
index 0000000..183d802
--- /dev/null
+++ b/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2016-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include common/fdt_wrappers.mk
+
+# 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_console.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}
+
+# Support for fconf in SP_MIN(BL32)
+# Added separately from the above list for better readability
+ifeq ($(filter 1,${BL2_AT_EL3} ${RESET_TO_SP_MIN}),)
+BL32_SOURCES += lib/fconf/fconf.c \
+ lib/fconf/fconf_dyn_cfg_getter.c \
+ plat/arm/board/fvp/fconf/fconf_hw_config_getter.c \
+
+BL32_SOURCES += ${FDT_WRAPPERS_SOURCES}
+
+ifeq (${SEC_INT_DESC_IN_FCONF},1)
+BL32_SOURCES += plat/arm/common/fconf/fconf_sec_intr_config.c
+endif
+
+endif
+
+include plat/arm/common/sp_min/arm_sp_min.mk
diff --git a/plat/arm/board/fvp/trp/trp-fvp.mk b/plat/arm/board/fvp/trp/trp-fvp.mk
new file mode 100644
index 0000000..a450541
--- /dev/null
+++ b/plat/arm/board/fvp/trp/trp-fvp.mk
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# TRP source files specific to FVP platform
+
+RMM_SOURCES += plat/arm/board/fvp/aarch64/fvp_helpers.S
+
+include plat/arm/common/trp/arm_trp.mk
+
diff --git a/plat/arm/board/fvp/tsp/fvp_tsp_setup.c b/plat/arm/board/fvp/tsp/fvp_tsp_setup.c
new file mode 100644
index 0000000..3c8a963
--- /dev/null
+++ b/plat/arm/board/fvp/tsp/fvp_tsp_setup.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+#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();
+}
diff --git a/plat/arm/board/fvp/tsp/tsp-fvp.mk b/plat/arm/board/fvp/tsp/tsp-fvp.mk
new file mode 100644
index 0000000..ab3f225
--- /dev/null
+++ b/plat/arm/board/fvp/tsp/tsp-fvp.mk
@@ -0,0 +1,14 @@
+#
+# 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
diff --git a/plat/arm/board/fvp_r/fvp_r_bl1_arch_setup.c b/plat/arm/board/fvp_r/fvp_r_bl1_arch_setup.c
new file mode 100644
index 0000000..ae6af6c
--- /dev/null
+++ b/plat/arm/board/fvp_r/fvp_r_bl1_arch_setup.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "../../../../bl1/bl1_private.h"
+#include <arch.h>
+
+#include <fvp_r_arch_helpers.h>
+
+/*******************************************************************************
+ * Function that does the first bit of architectural setup that affects
+ * execution in the non-secure address space.
+ ******************************************************************************/
+void bl1_arch_setup(void)
+{
+ /* v8-R64 does not include SCRs. */
+}
+
+/*******************************************************************************
+ * 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_el2() & SCTLR_EE_BIT);
+
+ /* Set SCTLR Secure EL1 */
+ next_sctlr |= SCTLR_EL1_RES1;
+
+ write_sctlr_el1(next_sctlr);
+}
diff --git a/plat/arm/board/fvp_r/fvp_r_bl1_entrypoint.S b/plat/arm/board/fvp_r/fvp_r_bl1_entrypoint.S
new file mode 100644
index 0000000..15f4c43
--- /dev/null
+++ b/plat/arm/board/fvp_r/fvp_r_bl1_entrypoint.S
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <el2_common_macros.S>
+#include <lib/xlat_mpu/xlat_mpu.h>
+
+ .globl bl1_entrypoint
+ .globl bl1_run_next_image
+
+
+ /* -----------------------------------------------------
+ * 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.
+ * ---------------------------------------------------------------------
+ */
+ el2_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 \
+ _pie_fixup_size=0
+
+ /* --------------------------------------------------------------------
+ * Perform BL1 setup
+ * --------------------------------------------------------------------
+ */
+ bl bl1_setup
+
+ /* --------------------------------------------------------------------
+ * Initialize platform and jump to our c-entry point
+ * for this type of reset.
+ * --------------------------------------------------------------------
+ */
+ bl bl1_main
+
+ /* ---------------------------------------------
+ * Should never reach this point.
+ * ---------------------------------------------
+ */
+ no_ret plat_panic_handler
+endfunc bl1_entrypoint
+
+func bl1_run_next_image
+ mov x20,x0
+
+ /* ---------------------------------------------
+ * MPU needs to be disabled because both BL1 and BL33 execute
+ * in EL2, and therefore share the same address space.
+ * BL33 will initialize the address space according to its
+ * own requirement.
+ * ---------------------------------------------
+ */
+ bl disable_mpu_icache_el2
+
+ /* ---------------------------------------------
+ * Wipe clean and disable all MPU regions. This function expects
+ * that the MPU has already been turned off, and caching concerns
+ * addressed, but it also explicitly turns off the MPU.
+ * ---------------------------------------------
+ */
+ bl clear_all_mpu_regions
+
+ /* --------------------------------------------------
+ * Do the transition to next boot image.
+ * --------------------------------------------------
+ */
+ ldp x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET]
+ msr elr_el2, x0
+ msr spsr_el2, 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)]
+ exception_return
+endfunc bl1_run_next_image
diff --git a/plat/arm/board/fvp_r/fvp_r_bl1_exceptions.S b/plat/arm/board/fvp_r/fvp_r_bl1_exceptions.S
new file mode 100644
index 0000000..43c2e01
--- /dev/null
+++ b/plat/arm/board/fvp_r/fvp_r_bl1_exceptions.S
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <context.h>
+
+/* -----------------------------------------------------------------------------
+ * File contains an EL2 equivalent of the EL3 vector table from:
+ * .../bl1/aarch64/bl1_exceptions.S
+ * -----------------------------------------------------------------------------
+ */
+
+/* -----------------------------------------------------------------------------
+ * 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
+ /* The current v8-R64 implementation does not support conduit calls */
+ b el2_panic
+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
+
+
+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.
+ * -----------------------------------------------------
+ */
diff --git a/plat/arm/board/fvp_r/fvp_r_bl1_main.c b/plat/arm/board/fvp_r/fvp_r_bl1_main.c
new file mode 100644
index 0000000..841a176
--- /dev/null
+++ b/plat/arm/board/fvp_r/fvp_r_bl1_main.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include "../../../../bl1/bl1_private.h"
+#include <arch.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/auth/auth_mod.h>
+#include <drivers/console.h>
+#include <lib/cpus/errata_report.h>
+#include <lib/utils.h>
+#include <smccc_helpers.h>
+#include <tools_share/uuid.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+
+void cm_prepare_el2_exit(void);
+
+void bl1_run_next_image(const struct entry_point_info *bl_ep_info);
+
+/*******************************************************************************
+ * 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_transfer_bl33(void)
+{
+ unsigned int image_id;
+
+ /* Get the image id of next image to load and run. */
+ image_id = bl1_plat_get_next_image_id();
+
+#if !ARM_DISABLE_TRUSTED_WDOG
+ /* Disable watchdog before leaving BL1 */
+ plat_arm_secure_wdt_stop();
+#endif
+
+ bl1_run_next_image(&bl1_plat_get_image_desc(image_id)->ep_info);
+}
+
+/*******************************************************************************
+ * This function locates and loads the BL33 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.
+ ******************************************************************************/
+void bl1_load_bl33(void)
+{
+ image_desc_t *desc;
+ image_info_t *info;
+ int err;
+
+ /* Get the image descriptor */
+ desc = bl1_plat_get_image_desc(BL33_IMAGE_ID);
+ assert(desc != NULL);
+
+ /* Get the image info */
+ info = &desc->image_info;
+ INFO("BL1: Loading BL33\n");
+
+ err = bl1_plat_handle_pre_image_load(BL33_IMAGE_ID);
+ if (err != 0) {
+ ERROR("Failure in pre image load handling of BL33 (%d)\n", err);
+ plat_error_handler(err);
+ }
+
+ err = load_auth_image(BL33_IMAGE_ID, info);
+ if (err != 0) {
+ ERROR("Failed to load BL33 firmware.\n");
+ plat_error_handler(err);
+ }
+
+ /* Allow platform to handle image information. */
+ err = bl1_plat_handle_post_image_load(BL33_IMAGE_ID);
+ if (err != 0) {
+ ERROR("Failure in post image load handling of BL33 (%d)\n", err);
+ plat_error_handler(err);
+ }
+
+ NOTICE("BL1: Booting BL33\n");
+}
+
+/*******************************************************************************
+ * 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_mem_layout->total_base < BL1_RW_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));
+}
+
+/*******************************************************************************
+ * This function prepares for entry to BL33
+ ******************************************************************************/
+void bl1_prepare_next_image(unsigned int image_id)
+{
+ unsigned int mode = MODE_EL1;
+ image_desc_t *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 %s",
+ "CTX_INCLUDE_AARCH32_REGS = 0\n");
+ panic();
+ }
+#endif
+
+ /* Get the image descriptor. */
+ desc = bl1_plat_get_image_desc(image_id);
+ assert(desc != NULL);
+
+ /* Get the entry point info. */
+ next_bl_ep = &desc->ep_info;
+
+ /* FVP-R is only secure */
+ assert(GET_SECURITY_STATE(next_bl_ep->h.attr) == SECURE);
+
+ /* Prepare the SPSR for the next BL image. */
+ next_bl_ep->spsr = (uint32_t)SPSR_64((uint64_t) mode,
+ (uint64_t)MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+
+ /* Allow platform to make change */
+ bl1_plat_set_ep_info(image_id, next_bl_ep);
+
+ /* Prepare context for the next EL */
+ cm_prepare_el2_exit();
+
+ /* Indicate that image is in execution state. */
+ desc->state = IMAGE_STATE_EXECUTED;
+
+ print_entry_point_info(next_bl_ep);
+}
+
+/*******************************************************************************
+ * 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();
+}
+
+/*******************************************************************************
+ * 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
+ */
+ val = read_sctlr_el2();
+
+ assert((val & SCTLR_M_BIT) != 0U);
+ assert((val & SCTLR_C_BIT) != 0U);
+ assert((val & SCTLR_I_BIT) != 0U);
+ /*
+ * 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(SIZE_FROM_LOG2_WORDS(val) == CACHE_WRITEBACK_GRANULE);
+ } else {
+ assert(MAX_CACHE_LINE_SIZE >= CACHE_WRITEBACK_GRANULE);
+ }
+#endif /* ENABLE_ASSERTIONS */
+
+ /* Perform remaining generic architectural setup from ELmax */
+ 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();
+
+ /* 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 == BL33_IMAGE_ID) {
+ bl1_load_bl33();
+ } else {
+ NOTICE("BL1-FWU: *******FWU Process Started*******\n");
+ }
+
+ bl1_prepare_next_image(image_id);
+
+ console_flush();
+
+ bl1_transfer_bl33();
+}
+
+/*******************************************************************************
+ * 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)
+{
+ NOTICE("BL1: Booting BL31\n");
+ 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
+
diff --git a/plat/arm/board/fvp_r/fvp_r_bl1_setup.c b/plat/arm/board/fvp_r/fvp_r_bl1_setup.c
new file mode 100644
index 0000000..1ac0a9c
--- /dev/null
+++ b/plat/arm/board/fvp_r/fvp_r_bl1_setup.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Use the xlat_tables_v2 data structures: */
+#define XLAT_TABLES_LIB_V2 1
+
+#include <assert.h>
+
+#include <bl1/bl1.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/arm/sp805.h>
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_dyn_cfg_getter.h>
+#include <lib/xlat_mpu/xlat_mpu.h>
+
+#include "fvp_r_private.h"
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/arm_def.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#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;
+}
+
+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;
+}
+
+/* Boolean variable to hold condition whether firmware update needed or not */
+static bool is_fwu_needed;
+
+/*******************************************************************************
+ * 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 arm_bl1_plat_arch_setup(void)
+{
+ 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
+ /* DRAM1_region: */
+ MAP_REGION_FLAT( \
+ PLAT_ARM_DRAM1_BASE, \
+ PLAT_ARM_DRAM1_SIZE, \
+ MT_MEMORY | MT_SECURE | MT_EXECUTE \
+ | MT_RW | MT_NON_CACHEABLE),
+ /* NULL terminator: */
+ {0}
+ };
+
+ setup_page_tables(bl_regions, plat_arm_get_mmap());
+ enable_mpu_el2(0);
+
+ arm_setup_romlib();
+}
+
+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);
+}
+
+/*
+ * Perform the platform specific architecture setup shared between
+ * ARM standard platforms.
+ */
+void arm_bl1_platform_setup(void)
+{
+ uint32_t fw_config_max_size;
+
+ /* Initialise the IO layer and register platform IO devices */
+ plat_arm_io_setup();
+
+ /* Check if we need FWU before further processing */
+ is_fwu_needed = plat_arm_bl1_fwu_needed();
+ if (is_fwu_needed) {
+ ERROR("Skip platform setup as FWU detected\n");
+ return;
+ }
+
+ /* Set global DTB info for fixed fw_config information */
+ fw_config_max_size = ARM_FW_CONFIG_LIMIT - ARM_FW_CONFIG_BASE;
+ set_config_info(ARM_FW_CONFIG_BASE, ~0UL, fw_config_max_size,
+ FW_CONFIG_ID);
+
+ assert(bl1_plat_get_image_desc(BL33_IMAGE_ID) != NULL);
+
+ /*
+ * 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_platform_setup(void)
+{
+ arm_bl1_platform_setup();
+
+ /* Initialize System level generic or SP804 timer */
+ fvp_timer_init();
+}
+
+__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 (true) {
+ wfi();
+ }
+}
+
+unsigned int bl1_plat_get_next_image_id(void)
+{
+ return is_fwu_needed ? NS_BL1U_IMAGE_ID : BL33_IMAGE_ID;
+}
+
+/*
+ * Returns BL33 image details.
+ */
+struct image_desc *bl1_plat_get_image_desc(unsigned int image_id)
+{
+ static image_desc_t bl33_img_desc = BL33_IMAGE_DESC;
+
+ return &bl33_img_desc;
+}
+
+/*
+ * This function populates the default arguments to BL33.
+ * The BL33 memory layout structure is allocated and the
+ * calculated layout is populated in arg1 to BL33.
+ */
+int bl1_plat_handle_post_image_load(unsigned int image_id)
+{
+ meminfo_t *bl33_secram_layout;
+ meminfo_t *bl1_secram_layout;
+ image_desc_t *image_desc;
+ entry_point_info_t *ep_info;
+
+ if (image_id != BL33_IMAGE_ID) {
+ return 0;
+ }
+ /* Get the image descriptor */
+ image_desc = bl1_plat_get_image_desc(BL33_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_secram_layout = bl1_plat_sec_mem_layout();
+
+ /*
+ * Create a new layout of memory for BL33 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 BL33. BL33 will read the memory layout before using its
+ * memory for other purposes.
+ */
+ bl33_secram_layout = (meminfo_t *) bl1_secram_layout->total_base;
+
+ bl1_calc_bl2_mem_layout(bl1_secram_layout, bl33_secram_layout);
+
+ ep_info->args.arg1 = (uintptr_t)bl33_secram_layout;
+
+ VERBOSE("BL1: BL3 memory layout address = %p\n",
+ (void *) bl33_secram_layout);
+ return 0;
+}
diff --git a/plat/arm/board/fvp_r/fvp_r_common.c b/plat/arm/board/fvp_r/fvp_r_common.c
new file mode 100644
index 0000000..edcf658
--- /dev/null
+++ b/plat/arm/board/fvp_r/fvp_r_common.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* This uses xlat_mpu, but tables are set up using V2 mmap_region_t */
+#define XLAT_TABLES_LIB_V2 1
+
+#include <assert.h>
+#include <common/debug.h>
+
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/sp804_delay_timer.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/smccc.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+#include <services/arm_arch_svc.h>
+
+#include "fvp_r_private.h"
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+
+/* Defines for GIC Driver build time selection */
+#define FVP_R_GICV3 2
+
+/*******************************************************************************
+ * arm_config holds the characteristics of the differences between the FVP_R
+ * platforms. It will be populated during cold boot at each boot stage by the
+ * primary before enabling the MPU (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 MPU.
+ * 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,
+#endif
+ {0}
+};
+#endif
+
+ARM_CASSERT_MMAP
+
+static const int fvp_cci400_map[] = {
+ PLAT_FVP_R_CCI400_CLUS0_SL_PORT,
+ PLAT_FVP_R_CCI400_CLUS1_SL_PORT,
+};
+
+static const int fvp_cci5xx_map[] = {
+ PLAT_FVP_R_CCI5XX_CLUS0_SL_PORT,
+ PLAT_FVP_R_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_R_CLUSTER_COUNT);
+ return master;
+}
+
+/*******************************************************************************
+ * Initialize the platform config for future decision making
+ ******************************************************************************/
+void __init fvp_config_setup(void)
+{
+ unsigned int rev, hbi, bld, arch, sys_id;
+
+ arm_config.flags |= ARM_CONFIG_BASE_MMAP;
+ sys_id = mmio_read_32(V2M_FVP_R_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_R 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 %s",
+ "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_R & 0x010
+ * for the Foundation FVP_R.
+ */
+ switch (hbi) {
+ case HBI_FOUNDATION_FVP_R:
+ arm_config.flags = 0;
+
+ /*
+ * Check for supported revisions of Foundation FVP_R
+ * Allow future revisions to run but emit warning diagnostic
+ */
+ switch (rev) {
+ case REV_FOUNDATION_FVP_R_V2_0:
+ case REV_FOUNDATION_FVP_R_V2_1:
+ case REV_FOUNDATION_FVP_R_v9_1:
+ case REV_FOUNDATION_FVP_R_v9_6:
+ break;
+ default:
+ WARN("Unrecognized Foundation FVP_R revision %x\n", rev);
+ break;
+ }
+ break;
+ case HBI_BASE_FVP_R:
+ 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_R_V0:
+ arm_config.flags |= ARM_CONFIG_FVP_HAS_CCI400;
+ break;
+ default:
+ WARN("Unrecognized Base FVP_R 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)
+{
+ 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_R_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_R_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);
+}
+
+void fvp_interconnect_enable(void)
+{
+ 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);
+ }
+}
+
+void fvp_interconnect_disable(void)
+{
+ 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);
+ }
+}
+
+#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 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_R_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 /* USE_SP804_TIMER */
+}
+
+/* Get SOC version */
+int32_t plat_get_soc_version(void)
+{
+ return (int32_t)
+ ((ARM_SOC_IDENTIFICATION_CODE << ARM_SOC_IDENTIFICATION_SHIFT)
+ | (ARM_SOC_CONTINUATION_CODE << ARM_SOC_CONTINUATION_SHIFT)
+ | FVP_R_SOC_ID);
+}
+
+/* Get SOC revision */
+int32_t plat_get_soc_revision(void)
+{
+ unsigned int sys_id;
+
+ sys_id = mmio_read_32(V2M_SYSREGS_BASE + V2M_SYS_ID);
+ return (int32_t)((sys_id >> V2M_SYS_ID_REV_SHIFT) &
+ V2M_SYS_ID_REV_MASK);
+}
diff --git a/plat/arm/board/fvp_r/fvp_r_context_mgmt.c b/plat/arm/board/fvp_r/fvp_r_context_mgmt.c
new file mode 100644
index 0000000..d172d2d
--- /dev/null
+++ b/plat/arm/board/fvp_r/fvp_r_context_mgmt.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+
+/************************************************************
+ * For R-class everything is in secure world.
+ * Prepare the CPU system registers for first entry into EL1
+ ************************************************************/
+void cm_prepare_el2_exit(void)
+{
+ uint64_t hcr_el2 = 0U;
+
+ /*
+ * The use of ARMv8.3 pointer authentication (PAuth) is governed
+ * by fields in HCR_EL2, which trigger a 'trap to EL2' if not
+ * enabled. This register initialized at boot up, update PAuth
+ * bits.
+ *
+ * HCR_API_BIT: Set to one to disable traps to EL2 if lower ELs
+ * access PAuth registers
+ *
+ * HCR_APK_BIT: Set to one to disable traps to EL2 if lower ELs
+ * access PAuth instructions
+ */
+ hcr_el2 = read_hcr_el2();
+ write_hcr_el2(hcr_el2 | HCR_API_BIT | HCR_APK_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 EL2
+ * if lower ELs accesses to the physical timer registers.
+ *
+ * CNTHCTL_EL2.EL1PCTEN: Set to one to disable traps to EL2
+ * if lower ELs access to the physical counter registers.
+ */
+ write_cnthctl_el2(CNTHCTL_RESET_VAL | EL1PCEN_BIT | EL1PCTEN_BIT);
+
+ /*
+ * On Armv8-R, the EL1&0 memory system architecture is configurable
+ * as a VMSA or PMSA. All the fields architecturally UNKNOWN on reset
+ * and are set to zero except for field listed below.
+ *
+ * VCTR_EL2.MSA: Set to one to ensure the VMSA is enabled so that
+ * rich OS can boot.
+ */
+ write_vtcr_el2(VTCR_RESET_VAL | VTCR_EL2_MSA);
+}
diff --git a/plat/arm/board/fvp_r/fvp_r_debug.S b/plat/arm/board/fvp_r/fvp_r_debug.S
new file mode 100644
index 0000000..88f0a29
--- /dev/null
+++ b/plat/arm/board/fvp_r/fvp_r_debug.S
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/debug.h>
+
+ .globl el2_panic
+
+ /***********************************************************
+ * The common implementation of do_panic for all BL stages
+ ***********************************************************/
+
+.section .rodata.panic_str, "aS"
+ panic_msg: .asciz "PANIC at PC : 0x"
+
+/*
+ * el2_panic will be redefined by the
+ * crash reporting mechanism (if enabled)
+ */
+el2_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 el2_panic was
+ * called, not the address of the call from el2_panic.
+ */
+ mov x30, x6
+ b plat_panic_handler
diff --git a/plat/arm/board/fvp_r/fvp_r_def.h b/plat/arm/board/fvp_r/fvp_r_def.h
new file mode 100644
index 0000000..eda39cf
--- /dev/null
+++ b/plat/arm/board/fvp_r/fvp_r_def.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FVP_R_DEF_H
+#define FVP_R_DEF_H
+
+#include <lib/utils_def.h>
+
+/******************************************************************************
+ * FVP-R topology constants
+ *****************************************************************************/
+#define FVP_R_CLUSTER_COUNT 2
+#define FVP_R_MAX_CPUS_PER_CLUSTER 4
+#define FVP_R_MAX_PE_PER_CPU 1
+#define FVP_R_PRIMARY_CPU 0x0
+
+/******************************************************************************
+ * Definition of platform soc id
+ *****************************************************************************/
+#define FVP_R_SOC_ID 0
+
+/*******************************************************************************
+ * FVP_R memory map related constants
+ ******************************************************************************/
+
+#define FLASH1_BASE UL(0x8c000000)
+#define FLASH1_SIZE UL(0x04000000)
+
+#define PSRAM_BASE UL(0x94000000)
+#define PSRAM_SIZE UL(0x04000000)
+
+#define VRAM_BASE UL(0x98000000)
+#define VRAM_SIZE UL(0x02000000)
+
+/* Aggregate of all devices in the first GB */
+#define DEVICE0_BASE UL(0xa0000000)
+#define DEVICE0_SIZE UL(0x0c200000)
+
+/*
+ * In case of FVP_R models with CCN, the CCN register space overlaps into
+ * the NSRAM area.
+ */
+#define DEVICE1_BASE UL(0xae000000)
+#define DEVICE1_SIZE UL(0x1A00000)
+
+#define NSRAM_BASE UL(0xae000000)
+#define NSRAM_SIZE UL(0x10000)
+/* Devices in the second GB */
+#define DEVICE2_BASE UL(0xffe00000)
+#define DEVICE2_SIZE UL(0x00200000)
+
+#define PCIE_EXP_BASE UL(0xc0000000)
+#define TZRNG_BASE UL(0x7fe60000)
+
+/* Non-volatile counters */
+#define TRUSTED_NVCTR_BASE UL(0xffe70000)
+#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(0xffe80000)
+#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_R type */
+#define HBI_BASE_FVP_R U(0x020)
+#define REV_BASE_FVP_R_V0 U(0x0)
+#define REV_BASE_FVP_R_REVC U(0x2)
+
+#define HBI_FOUNDATION_FVP_R U(0x010)
+#define REV_FOUNDATION_FVP_R_V2_0 U(0x0)
+#define REV_FOUNDATION_FVP_R_V2_1 U(0x1)
+#define REV_FOUNDATION_FVP_R_v9_1 U(0x2)
+#define REV_FOUNDATION_FVP_R_v9_6 U(0x3)
+
+#define BLD_GIC_VE_MMAP U(0x0)
+#define BLD_GIC_A53A57_MMAP U(0x1)
+
+#define ARCH_MODEL U(0x1)
+
+/* FVP_R Power controller base address*/
+#define PWRC_BASE UL(0x1c100000)
+
+/* FVP_R SP804 timer frequency is 35 MHz*/
+#define SP804_TIMER_CLKMULT 1
+#define SP804_TIMER_CLKDIV 35
+
+/* SP810 controller. FVP_R specific flags */
+#define FVP_R_SP810_CTRL_TIM0_OV BIT_32(16)
+#define FVP_R_SP810_CTRL_TIM1_OV BIT_32(18)
+#define FVP_R_SP810_CTRL_TIM2_OV BIT_32(20)
+#define FVP_R_SP810_CTRL_TIM3_OV BIT_32(22)
+
+#endif /* FVP_R_DEF_H */
diff --git a/plat/arm/board/fvp_r/fvp_r_err.c b/plat/arm/board/fvp_r/fvp_r_err.c
new file mode 100644
index 0000000..7ee752b
--- /dev/null
+++ b/plat/arm/board/fvp_r/fvp_r_err.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/arm/sp805.h>
+#include <drivers/cfi/v2m_flash.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+/*
+ * FVP_R 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_FLASH_IMAGE_BASE);
+ ret = nor_word_program(PLAT_ARM_FLASH_IMAGE_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);
+
+ while (true) {
+ wfi();
+ }
+}
diff --git a/plat/arm/board/fvp_r/fvp_r_helpers.S b/plat/arm/board/fvp_r/fvp_r_helpers.S
new file mode 100644
index 0000000..ba85777
--- /dev/null
+++ b/plat/arm/board/fvp_r/fvp_r_helpers.S
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/fvp/fvp_pwrc.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gicv3.h>
+
+#include <platform_def.h>
+
+
+ .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.
+ * TODO: Should we read the PSYS register to make sure
+ * that the request has gone through.
+ * -----------------------------------------------------
+ */
+func plat_secondary_cold_boot_setup
+ /* ---------------------------------------------
+ * 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
+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_R, 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_R_PRIMARY_CPU
+ cset w0, eq
+ ret
+endfunc plat_is_my_cpu_primary
diff --git a/plat/arm/board/fvp_r/fvp_r_io_storage.c b/plat/arm/board/fvp_r/fvp_r_io_storage.c
new file mode 100644
index 0000000..3b44828
--- /dev/null
+++ b/plat/arm/board/fvp_r/fvp_r_io_storage.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_semihosting.h>
+#include <drivers/io/io_storage.h>
+#include <lib/semihosting.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/common_def.h>
+
+/* Semihosting filenames */
+#define BL33_IMAGE_NAME "bl33.bin"
+
+#if TRUSTED_BOARD_BOOT
+#define TRUSTED_KEY_CERT_NAME "trusted_key.crt"
+#define NT_FW_KEY_CERT_NAME "nt_fw_key.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[] = {
+ [BL33_IMAGE_ID] = {
+ .path = BL33_IMAGE_NAME,
+ .mode = FOPEN_MODE_RB
+ },
+#if TRUSTED_BOARD_BOOT
+ [TRUSTED_KEY_CERT_ID] = {
+ .path = TRUSTED_KEY_CERT_NAME,
+ .mode = FOPEN_MODE_RB
+ },
+ [NON_TRUSTED_FW_KEY_CERT_ID] = {
+ .path = NT_FW_KEY_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;
+
+ io_result = arm_io_setup();
+ if (io_result < 0) {
+ panic();
+ }
+
+ /* Register the additional IO devices on this platform */
+ io_result = register_io_dev_sh(&sh_dev_con);
+ if (io_result < 0) {
+ panic();
+ }
+
+ /* Open connections to devices and cache the handles */
+ io_result = io_dev_open(sh_dev_con, (uintptr_t)NULL, &sh_dev_handle);
+ if (io_result < 0) {
+ panic();
+ }
+}
+
+/*
+ * FVP_R 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;
+}
diff --git a/plat/arm/board/fvp_r/fvp_r_misc_helpers.S b/plat/arm/board/fvp_r/fvp_r_misc_helpers.S
new file mode 100644
index 0000000..67ad164
--- /dev/null
+++ b/plat/arm/board/fvp_r/fvp_r_misc_helpers.S
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+ .globl disable_mpu_el2
+ .globl disable_mpu_icache_el2
+
+/* ---------------------------------------------------------------------------
+ * Disable the MPU at EL2.
+ * ---------------------------------------------------------------------------
+ */
+
+func disable_mpu_el2
+ mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT)
+do_disable_mpu_el2:
+ mrs x0, sctlr_el2
+ bic x0, x0, x1
+ msr sctlr_el2, x0
+ isb /* ensure MMU is off */
+ dsb sy
+ ret
+endfunc disable_mpu_el2
+
+
+func disable_mpu_icache_el2
+ mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT)
+ b do_disable_mpu_el2
+endfunc disable_mpu_icache_el2
diff --git a/plat/arm/board/fvp_r/fvp_r_private.h b/plat/arm/board/fvp_r/fvp_r_private.h
new file mode 100644
index 0000000..48f6e89
--- /dev/null
+++ b/plat/arm/board/fvp_r/fvp_r_private.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FVP_R_PRIVATE_H
+#define FVP_R_PRIVATE_H
+
+#include <plat/arm/common/plat_arm.h>
+
+/*******************************************************************************
+ * 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);
+
+#endif /* FVP_R_PRIVATE_H */
diff --git a/plat/arm/board/fvp_r/fvp_r_stack_protector.c b/plat/arm/board/fvp_r/fvp_r_stack_protector.c
new file mode 100644
index 0000000..69b6312
--- /dev/null
+++ b/plat/arm/board/fvp_r/fvp_r_stack_protector.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <fvp_r_arch_helpers.h>
+#include <plat/common/platform.h>
+
+#define RANDOM_CANARY_VALUE ((u_register_t) 8092347823957523895ULL)
+
+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_R does not have any random number generator, this is better than
+ * nothing but not necessarily really secure.
+ */
+ return RANDOM_CANARY_VALUE ^ read_cntpct_el0();
+}
+
diff --git a/plat/arm/board/fvp_r/fvp_r_trusted_boot.c b/plat/arm/board/fvp_r/fvp_r_trusted_boot.c
new file mode 100644
index 0000000..de0b28f
--- /dev/null
+++ b/plat/arm/board/fvp_r/fvp_r_trusted_boot.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <lib/fconf/fconf.h>
+#include <lib/mmio.h>
+#include <tools_share/tbbr_oid.h>
+
+#include <plat/arm/common/fconf_nv_cntr_getter.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+
+/*
+ * 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)
+{
+ return arm_get_rotpk_info(cookie, key_ptr, key_len, flags);
+}
+
+/*
+ * Store a new non-volatile counter value.
+ *
+ * On some FVP_R 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 = FCONF_GET_PROPERTY(cot, nv_cntr_addr,
+ TRUSTED_NV_CTR_ID);
+ } else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) {
+ nv_ctr_addr = FCONF_GET_PROPERTY(cot, nv_cntr_addr,
+ NON_TRUSTED_NV_CTR_ID);
+ } else {
+ return 1;
+ }
+
+ mmio_write_32(nv_ctr_addr, nv_ctr);
+
+ /*
+ * If the FVP_R 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;
+}
diff --git a/plat/arm/board/fvp_r/include/fvp_r_arch_helpers.h b/plat/arm/board/fvp_r/include/fvp_r_arch_helpers.h
new file mode 100644
index 0000000..92bf484
--- /dev/null
+++ b/plat/arm/board/fvp_r/include/fvp_r_arch_helpers.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FVP_R_ARCH_HELPERS_H
+#define FVP_R_ARCH_HELPERS_H
+
+#include <arch_helpers.h>
+
+/*******************************************************************************
+ * MPU register definitions
+ ******************************************************************************/
+#define MPUIR_EL2 S3_4_C0_C0_4
+#define PRBAR_EL2 S3_4_C6_C8_0
+#define PRLAR_EL2 S3_4_C6_C8_1
+#define PRSELR_EL2 S3_4_C6_C2_1
+#define PRENR_EL2 S3_4_C6_C1_1
+
+/* v8-R64 MPU registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(mpuir_el2, MPUIR_EL2)
+DEFINE_RENAME_SYSREG_RW_FUNCS(prenr_el2, PRENR_EL2)
+DEFINE_RENAME_SYSREG_RW_FUNCS(prselr_el2, PRSELR_EL2)
+DEFINE_RENAME_SYSREG_RW_FUNCS(prbar_el2, PRBAR_EL2)
+DEFINE_RENAME_SYSREG_RW_FUNCS(prlar_el2, PRLAR_EL2)
+
+#endif /* FVP_R_ARCH_HELPERS_H */
diff --git a/plat/arm/board/fvp_r/include/platform_def.h b/plat/arm/board/fvp_r/include/platform_def.h
new file mode 100644
index 0000000..ea3a258
--- /dev/null
+++ b/plat/arm/board/fvp_r/include/platform_def.h
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FVP_R_PLATFORM_DEF_H
+#define FVP_R_PLATFORM_DEF_H
+
+#define PLAT_V2M_OFFSET 0x80000000
+
+#define BL33_IMAGE_DESC { \
+ .image_id = BL33_IMAGE_ID, \
+ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, \
+ VERSION_2, image_info_t, 0), \
+ .image_info.image_base = PLAT_ARM_DRAM1_BASE + 0x1000, \
+ .image_info.image_max_size = UL(0x3ffff000), \
+ SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, \
+ VERSION_2, entry_point_info_t, SECURE | EXECUTABLE),\
+ .ep_info.pc = PLAT_ARM_DRAM1_BASE + 0x1000, \
+ .ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), \
+}
+
+#include "../fvp_r_def.h"
+#include <drivers/arm/tzc400.h>
+#include <lib/utils_def.h>
+#include <plat/arm/board/common/v2m_def.h>
+
+/* These are referenced by arm_def.h #included next, so #define first. */
+#define PLAT_ARM_TRUSTED_ROM_BASE UL(0x80000000)
+#define PLAT_ARM_TRUSTED_SRAM_BASE UL(0x84000000)
+#define PLAT_ARM_TRUSTED_DRAM_BASE UL(0x86000000)
+#define PLAT_ARM_DRAM1_BASE ULL(0x0)
+#define PLAT_ARM_DRAM2_BASE ULL(0x080000000)
+
+#define PLAT_HW_CONFIG_DTB_BASE ULL(0x12000000)
+#define PLAT_ARM_SYS_CNTCTL_BASE UL(0xaa430000)
+#define PLAT_ARM_SYS_CNTREAD_BASE UL(0xaa800000)
+#define PLAT_ARM_SYS_TIMCTL_BASE UL(0xaa810000)
+#define PLAT_ARM_SYS_CNT_BASE_S UL(0xaa820000)
+#define PLAT_ARM_SYS_CNT_BASE_NS UL(0xaa830000)
+#define PLAT_ARM_SP805_TWDG_BASE UL(0xaa490000)
+
+#include <plat/arm/common/arm_def.h>
+#include <plat/common/common_def.h>
+
+
+/* Required to create plat_regions: */
+#define MIN_LVL_BLOCK_DESC U(1)
+
+/* Required platform porting definitions */
+#define PLATFORM_CORE_COUNT (U(FVP_R_CLUSTER_COUNT) * \
+ U(FVP_R_MAX_CPUS_PER_CLUSTER) * \
+ U(FVP_R_MAX_PE_PER_CPU))
+
+#define PLAT_NUM_PWR_DOMAINS (U(FVP_R_CLUSTER_COUNT) + \
+ PLATFORM_CORE_COUNT + U(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 U(FVP_R_CLUSTER_COUNT)
+#define PLAT_ARM_DRAM1_SIZE ULL(0x7fffffff)
+#define PLAT_ARM_TRUSTED_SRAM_SIZE UL(0x00040000) /* 256 KB */
+#define PLAT_ARM_TRUSTED_ROM_SIZE UL(0x04000000) /* 64 MB */
+#define PLAT_ARM_TRUSTED_DRAM_SIZE UL(0x02000000) /* 32 MB */
+
+/* These two are defined thus in arm_def.h, but doesn't seem to see it... */
+#define PLAT_BL1_RO_LIMIT (BL1_RO_BASE \
+ + PLAT_ARM_TRUSTED_ROM_SIZE)
+
+#define PLAT_ARM_SYS_CNTCTL_BASE UL(0xaa430000)
+#define PLAT_ARM_SYS_CNTREAD_BASE UL(0xaa800000)
+#define PLAT_ARM_SYS_TIMCTL_BASE UL(0xaa810000)
+#define PLAT_ARM_SYS_CNT_BASE_S UL(0xaa820000)
+#define PLAT_ARM_SYS_CNT_BASE_NS UL(0xaa830000)
+#define PLAT_ARM_SP805_TWDG_BASE UL(0xaa490000)
+
+/* virtual address used by dynamic mem_protect for chunk_base */
+#define PLAT_ARM_MEM_PROTEC_VA_FRAME UL(0xc0000000)
+
+/* No SCP in FVP_R */
+#define PLAT_ARM_SCP_TZC_DRAM1_SIZE UL(0x0)
+
+#define PLAT_ARM_DRAM2_SIZE UL(0x80000000)
+
+#define PLAT_HW_CONFIG_DTB_SIZE ULL(0x8000)
+
+#define ARM_DTB_DRAM_NS MAP_REGION_FLAT( \
+ PLAT_HW_CONFIG_DTB_BASE, \
+ PLAT_HW_CONFIG_DTB_SIZE, \
+ MT_MEMORY | MT_RO | MT_NS)
+
+#define V2M_FVP_R_SYSREGS_BASE UL(0x9c010000)
+
+/*
+ * Load address of BL33 for this platform port,
+ * U-Boot specifically must be loaded at a 4K aligned address.
+ */
+#define PLAT_ARM_NS_IMAGE_BASE (PLAT_ARM_DRAM1_BASE + 0x1000)
+
+/*
+ * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the
+ * plat_arm_mmap array defined for each BL stage.
+ */
+#if !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
+# define N_MPU_REGIONS 16 /* number of MPU regions */
+# define ALL_MPU_EL2_REGIONS_USED 0xffffffff
+ /* this is the PRENR_EL2 value if all MPU regions are in use */
+
+/*
+ * 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)
+#define FVP_R_BL2_ROMLIB_OPTIMIZATION UL(0x6000)
+#else
+#define PLAT_ARM_MAX_ROMLIB_RW_SIZE UL(0)
+#define PLAT_ARM_MAX_ROMLIB_RO_SIZE UL(0)
+#define FVP_R_BL2_ROMLIB_OPTIMIZATION 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
+#if COT_DESC_IN_DTB
+# define PLAT_ARM_MAX_BL2_SIZE (UL(0x1E000) - FVP_R_BL2_ROMLIB_OPTIMIZATION)
+#else
+# define PLAT_ARM_MAX_BL2_SIZE (UL(0x1D000) - FVP_R_BL2_ROMLIB_OPTIMIZATION)
+#endif
+#else
+# define PLAT_ARM_MAX_BL2_SIZE (UL(0x13000) - FVP_R_BL2_ROMLIB_OPTIMIZATION)
+#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 UL(0x3D000)
+
+/*
+ * Size of cacheable stacks
+ */
+#if defined(IMAGE_BL1)
+# if TRUSTED_BOARD_BOOT
+# define PLATFORM_STACK_SIZE UL(0x1000)
+# else
+# define PLATFORM_STACK_SIZE UL(0x500)
+# endif
+#endif
+
+#define MAX_IO_DEVICES 3
+#define MAX_IO_HANDLES 4
+
+/*
+ * These nominally reserve the last block of flash for PSCI MEM PROTECT flag,
+ * but no PSCI in FVP_R platform, so reserve nothing:
+ */
+#define PLAT_ARM_FLASH_IMAGE_BASE (PLAT_ARM_DRAM1_BASE + UL(0x40000000))
+#define PLAT_ARM_FLASH_IMAGE_MAX_SIZE (PLAT_ARM_DRAM1_SIZE - UL(0x40000000))
+
+#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
+
+/* CCI related constants */
+#define PLAT_FVP_R_CCI400_BASE UL(0xac090000)
+#define PLAT_FVP_R_CCI400_CLUS0_SL_PORT 3
+#define PLAT_FVP_R_CCI400_CLUS1_SL_PORT 4
+
+/* CCI-500/CCI-550 on Base platform */
+#define PLAT_FVP_R_CCI5XX_BASE UL(0xaa000000)
+#define PLAT_FVP_R_CCI5XX_CLUS0_SL_PORT 5
+#define PLAT_FVP_R_CCI5XX_CLUS1_SL_PORT 6
+
+/* 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_R.
+ * 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(0xaa4a0000)
+#define PLAT_ARM_TZC_FILTERS TZC_400_REGION_ATTR_FILTER_BIT(0)
+
+#define PLAT_ARM_TZC_NS_DEV_ACCESS ( \
+ TZC_REGION_ACCESS_RDWR(FVP_R_NSAID_DEFAULT) | \
+ TZC_REGION_ACCESS_RDWR(FVP_R_NSAID_PCI) | \
+ TZC_REGION_ACCESS_RDWR(FVP_R_NSAID_AP) | \
+ TZC_REGION_ACCESS_RDWR(FVP_R_NSAID_VIRTIO) | \
+ TZC_REGION_ACCESS_RDWR(FVP_R_NSAID_VIRTIO_OLD))
+
+/*
+ * GIC related constants to cater for both GICv2 and GICv3 instances of an
+ * FVP_R. They could be overridden at runtime in case the FVP_R 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 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 MPU in AARCH64 & AARCH32 modes
+ */
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 36)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 36)
+
+#define ARM_SOC_CONTINUATION_SHIFT U(24)
+#define ARM_SOC_IDENTIFICATION_SHIFT U(16)
+
+#endif /* FVP_R_PLATFORM_DEF_H */
diff --git a/plat/arm/board/fvp_r/platform.mk b/plat/arm/board/fvp_r/platform.mk
new file mode 100644
index 0000000..93b5cf2
--- /dev/null
+++ b/plat/arm/board/fvp_r/platform.mk
@@ -0,0 +1,99 @@
+#
+# Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Only aarch64 ARCH supported for FVP_R
+ARCH := aarch64
+
+# Override to exclude BL2, BL2U, BL31, and BL33 for FVP_R
+override NEED_BL2 := no
+override NEED_BL2U := no
+override NEED_BL31 := no
+NEED_BL32 := no
+
+override CTX_INCLUDE_AARCH32_REGS := 0
+
+# Use MPU-based memory management:
+XLAT_MPU_LIB_V1 := 1
+
+# FVP R will not have more than 2 clusters so just use CCI interconnect
+FVP_R_INTERCONNECT_SOURCES := drivers/arm/cci/cci.c
+
+
+include plat/arm/board/common/board_common.mk
+include plat/arm/common/arm_common.mk
+
+PLAT_INCLUDES := -Iplat/arm/board/fvp_r/include
+
+FVP_R_BL_COMMON_SOURCES := plat/arm/board/fvp_r/fvp_r_common.c \
+ plat/arm/board/fvp_r/fvp_r_context_mgmt.c \
+ plat/arm/board/fvp_r/fvp_r_debug.S \
+ plat/arm/board/fvp_r/fvp_r_err.c \
+ plat/arm/board/fvp_r/fvp_r_helpers.S \
+ plat/arm/board/fvp_r/fvp_r_misc_helpers.S
+
+FVP_R_BL1_SOURCES := plat/arm/board/fvp_r/fvp_r_bl1_arch_setup.c \
+ plat/arm/board/fvp_r/fvp_r_bl1_setup.c \
+ plat/arm/board/fvp_r/fvp_r_io_storage.c \
+ plat/arm/board/fvp_r/fvp_r_bl1_entrypoint.S \
+ plat/arm/board/fvp_r/fvp_r_bl1_exceptions.S \
+ plat/arm/board/fvp_r/fvp_r_bl1_main.c
+
+FVP_R_CPU_LIBS := lib/cpus/${ARCH}/aem_generic.S
+
+FVP_R_DYNC_CFG_SOURCES := common/fdt_wrappers.c \
+ plat/arm/common/arm_dyn_cfg.c
+
+ifeq (${TRUSTED_BOARD_BOOT},1)
+FVP_R_AUTH_SOURCES := drivers/auth/auth_mod.c \
+ drivers/auth/crypto_mod.c \
+ drivers/auth/img_parser_mod.c \
+ lib/fconf/fconf_tbbr_getter.c \
+ plat/common/tbbr/plat_tbbr.c \
+ drivers/auth/tbbr/tbbr_cot_bl1_r64.c \
+ drivers/auth/tbbr/tbbr_cot_common.c \
+ plat/arm/board/common/board_arm_trusted_boot.c \
+ plat/arm/board/common/rotpk/arm_dev_rotpk.S \
+ plat/arm/board/fvp_r/fvp_r_trusted_boot.c
+
+FVP_R_BL1_SOURCES += ${MBEDTLS_SOURCES} \
+ ${FVP_R_AUTH_SOURCES}
+endif
+
+ifeq (${USE_SP804_TIMER},1)
+FVP_R_BL_COMMON_SOURCES += drivers/arm/sp804/sp804_delay_timer.c
+else
+FVP_R_BL_COMMON_SOURCES += drivers/delay_timer/generic_delay_timer.c
+endif
+
+# Enable Activity Monitor Unit extensions by default
+ENABLE_AMU := 1
+
+ifneq (${ENABLE_STACK_PROTECTOR},0)
+FVP_R_BL_COMMON_SOURCES += plat/arm/board/fvp_r/fvp_r_stack_protector.c
+endif
+
+override BL1_SOURCES := drivers/arm/sp805/sp805.c \
+ drivers/cfi/v2m/v2m_flash.c \
+ drivers/delay_timer/delay_timer.c \
+ drivers/io/io_fip.c \
+ drivers/io/io_memmap.c \
+ drivers/io/io_storage.c \
+ drivers/io/io_semihosting.c \
+ lib/cpus/aarch64/cpu_helpers.S \
+ lib/fconf/fconf_dyn_cfg_getter.c \
+ lib/semihosting/semihosting.c \
+ lib/semihosting/${ARCH}/semihosting_call.S \
+ plat/arm/common/arm_bl1_setup.c \
+ plat/arm/common/arm_err.c \
+ plat/arm/common/arm_io_storage.c \
+ plat/arm/common/fconf/arm_fconf_io.c \
+ plat/common/plat_bl1_common.c \
+ plat/common/aarch64/platform_up_stack.S \
+ ${FVP_R_BL1_SOURCES} \
+ ${FVP_R_BL_COMMON_SOURCES} \
+ ${FVP_R_CPU_LIBS} \
+ ${FVP_R_DYNC_CFG_SOURCES} \
+ ${FVP_R_INTERCONNECT_SOURCES}
diff --git a/plat/arm/board/fvp_ve/aarch32/fvp_ve_helpers.S b/plat/arm/board/fvp_ve/aarch32/fvp_ve_helpers.S
new file mode 100644
index 0000000..78f6c68
--- /dev/null
+++ b/plat/arm/board/fvp_ve/aarch32/fvp_ve_helpers.S
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/arm/board/fvp_ve/fdts/fvp_ve_fw_config.dts b/plat/arm/board/fvp_ve/fdts/fvp_ve_fw_config.dts
new file mode 100644
index 0000000..6e5691b
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fdts/fvp_ve_fw_config.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/tbbr/tbbr_img_def.h>
+
+/dts-v1/;
+
+/ {
+ dtb-registry {
+ compatible = "fconf,dyn_cfg-dtb_registry";
+
+ tb_fw-config {
+ load-address = <0x0 0x80001300>;
+ max-size = <0x200>;
+ id = <TB_FW_CONFIG_ID>;
+ };
+
+ hw-config {
+ load-address = <0x0 0x82000000>;
+ max-size = <0x01000000>;
+ id = <HW_CONFIG_ID>;
+ };
+ };
+};
diff --git a/plat/arm/board/fvp_ve/fdts/fvp_ve_tb_fw_config.dts b/plat/arm/board/fvp_ve/fdts/fvp_ve_tb_fw_config.dts
new file mode 100644
index 0000000..c66186f
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fdts/fvp_ve_tb_fw_config.dts
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+ tb_fw-config {
+ compatible = "arm,tb_fw";
+
+ /* Disable authentication for development */
+ disable_auth = <0x0>;
+ };
+};
diff --git a/plat/arm/board/fvp_ve/fvp_ve_bl1_setup.c b/plat/arm/board/fvp_ve/fvp_ve_bl1_setup.c
new file mode 100644
index 0000000..736cf42
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fvp_ve_bl1_setup.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/sp805.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+/*******************************************************************************
+ * 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();
+}
diff --git a/plat/arm/board/fvp_ve/fvp_ve_bl2_setup.c b/plat/arm/board/fvp_ve/fvp_ve_bl2_setup.c
new file mode 100644
index 0000000..4ccae27
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fvp_ve_bl2_setup.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/sp804_delay_timer.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#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();
+
+#if 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 /* USE_SP804_TIMER */
+}
diff --git a/plat/arm/board/fvp_ve/fvp_ve_common.c b/plat/arm/board/fvp_ve/fvp_ve_common.c
new file mode 100644
index 0000000..768dad5
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fvp_ve_common.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+
+#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;
+}
diff --git a/plat/arm/board/fvp_ve/fvp_ve_def.h b/plat/arm/board/fvp_ve/fvp_ve_def.h
new file mode 100644
index 0000000..98de5f6
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fvp_ve_def.h
@@ -0,0 +1,84 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/* Default cluster count for FVP VE */
+#define FVP_VE_CLUSTER_COUNT U(1)
+
+/* Default number of CPUs per cluster on FVP VE */
+#define FVP_VE_MAX_CPUS_PER_CLUSTER U(1)
+
+/* Default number of threads per CPU on FVP VE */
+#define FVP_VE_MAX_PE_PER_CPU U(1)
+
+#define FVP_VE_CORE_COUNT U(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 */
diff --git a/plat/arm/board/fvp_ve/fvp_ve_err.c b/plat/arm/board/fvp_ve/fvp_ve_err.c
new file mode 100644
index 0000000..8d35688
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fvp_ve_err.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * FVP VE error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+ while (true) {
+ wfi();
+ }
+}
diff --git a/plat/arm/board/fvp_ve/fvp_ve_pm.c b/plat/arm/board/fvp_ve/fvp_ve_pm.c
new file mode 100644
index 0000000..a4d627b
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fvp_ve_pm.c
@@ -0,0 +1,25 @@
+/*
+* Copyright (c) 2019, Arm Limited. All rights reserved.
+*
+* SPDX-License-Identifier: BSD-3-Clause
+*/
+
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+
+/*******************************************************************************
+ * 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;
+}
diff --git a/plat/arm/board/fvp_ve/fvp_ve_private.h b/plat/arm/board/fvp_ve/fvp_ve_private.h
new file mode 100644
index 0000000..5d396bc
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fvp_ve_private.h
@@ -0,0 +1,18 @@
+/*
+ * 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 <plat/arm/common/plat_arm.h>
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+
+void fvp_ve_config_setup(void);
+
+#endif /* FVP_VE_PRIVATE_H */
diff --git a/plat/arm/board/fvp_ve/fvp_ve_security.c b/plat/arm/board/fvp_ve/fvp_ve_security.c
new file mode 100644
index 0000000..24465cb
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fvp_ve_security.c
@@ -0,0 +1,22 @@
+/*
+ * 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;
+}
diff --git a/plat/arm/board/fvp_ve/fvp_ve_topology.c b/plat/arm/board/fvp_ve/fvp_ve_topology.c
new file mode 100644
index 0000000..51cc9da
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fvp_ve_topology.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <drivers/arm/fvp/fvp_pwrc.h>
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/* 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;
+}
diff --git a/plat/arm/board/fvp_ve/include/platform_def.h b/plat/arm/board/fvp_ve/include/platform_def.h
new file mode 100644
index 0000000..bd8ef6a
--- /dev/null
+++ b/plat/arm/board/fvp_ve/include/platform_def.h
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/common/smccc_def.h>
+#include <plat/common/common_def.h>
+
+#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
+
+/*
+ * Map the region for device tree configuration with read and write permissions
+ */
+#define ARM_MAP_BL_CONFIG_REGION MAP_REGION_FLAT(ARM_BL_RAM_BASE, \
+ (ARM_FW_CONFIGS_LIMIT \
+ - ARM_BL_RAM_BASE), \
+ MT_MEMORY | 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 6
+
+#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 FW_CONFIG to be loaded by BL1, define the corresponding base
+ * and limit. Leave enough space of BL2 meminfo.
+ */
+#define ARM_FW_CONFIG_BASE (ARM_BL_RAM_BASE + sizeof(meminfo_t))
+#define ARM_FW_CONFIG_LIMIT ((ARM_BL_RAM_BASE + PAGE_SIZE) \
+ + (PAGE_SIZE / 2U))
+
+/*
+ * Define limit of firmware configuration memory:
+ * ARM_FW_CONFIG + ARM_BL2_MEM_DESC memory
+ */
+#define ARM_FW_CONFIGS_LIMIT (ARM_BL_RAM_BASE + (PAGE_SIZE * 2))
+
+/*******************************************************************************
+ * 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_FW_CONFIG_LIMIT
+#define ARM_BL2_MEM_DESC_LIMIT (ARM_BL2_MEM_DESC_BASE \
+ + (PAGE_SIZE / 2U))
+
+#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 FVP_VE_CLUSTER_COUNT
+#define PLAT_NUM_PWR_DOMAINS ((FVP_VE_CLUSTER_COUNT + \
+ PLATFORM_CORE_COUNT) + U(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_FLASH_IMAGE_BASE V2M_FLASH1_BASE
+#define PLAT_ARM_FLASH_IMAGE_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 */
diff --git a/plat/arm/board/fvp_ve/platform.mk b/plat/arm/board/fvp_ve/platform.mk
new file mode 100644
index 0000000..f7eace8
--- /dev/null
+++ b/plat/arm/board/fvp_ve/platform.mk
@@ -0,0 +1,139 @@
+#
+# Copyright (c) 2019-2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include common/fdt_wrappers.mk
+
+ifdef ARM_CORTEX_A5
+# Use the SP804 timer instead of the generic one
+USE_SP804_TIMER := 1
+BL2_SOURCES += drivers/arm/sp804/sp804_delay_timer.c
+endif
+
+# Include GICv2 driver files
+include drivers/arm/gic/v2/gicv2.mk
+
+FVP_VE_GIC_SOURCES := ${GICV2_SOURCES} \
+ 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 \
+ plat/arm/common/fconf/arm_fconf_io.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/fconf/arm_fconf_io.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_fw_config.dts \
+ plat/arm/board/fvp_ve/fdts/fvp_ve_tb_fw_config.dts
+
+FVP_FW_CONFIG := ${BUILD_PLAT}/fdts/fvp_ve_fw_config.dtb
+FVP_TB_FW_CONFIG := ${BUILD_PLAT}/fdts/fvp_ve_tb_fw_config.dtb
+
+# Add the FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FVP_FW_CONFIG},--fw-config,${FVP_FW_CONFIG}))
+# 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,${FVP_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,${FVP_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
+
+# Firmware Configuration Framework sources
+include lib/fconf/fconf.mk
+
+BL1_SOURCES += ${FCONF_SOURCES} ${FCONF_DYN_SOURCES}
+BL2_SOURCES += ${FCONF_SOURCES} ${FCONF_DYN_SOURCES}
+
+# 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
+
+DYN_CFG_SOURCES += ${FDT_WRAPPERS_SOURCES}
diff --git a/plat/arm/board/fvp_ve/sp_min/fvp_ve_sp_min_setup.c b/plat/arm/board/fvp_ve/sp_min/fvp_ve_sp_min_setup.c
new file mode 100644
index 0000000..e6a1bbe
--- /dev/null
+++ b/plat/arm/board/fvp_ve/sp_min/fvp_ve_sp_min_setup.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <plat/arm/common/plat_arm.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);
+}
diff --git a/plat/arm/board/fvp_ve/sp_min/sp_min-fvp_ve.mk b/plat/arm/board/fvp_ve/sp_min/sp_min-fvp_ve.mk
new file mode 100644
index 0000000..4ca810d
--- /dev/null
+++ b/plat/arm/board/fvp_ve/sp_min/sp_min-fvp_ve.mk
@@ -0,0 +1,22 @@
+#
+# 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}
diff --git a/plat/arm/board/juno/aarch32/juno_helpers.S b/plat/arm/board/juno/aarch32/juno_helpers.S
new file mode 100644
index 0000000..8f9561c
--- /dev/null
+++ b/plat/arm/board/juno/aarch32/juno_helpers.S
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a53.h>
+#include <cortex_a57.h>
+#include <cortex_a72.h>
+#include <cpu_macros.S>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/arm/board/juno/aarch64/juno_helpers.S b/plat/arm/board/juno/aarch64/juno_helpers.S
new file mode 100644
index 0000000..c94fa3e
--- /dev/null
+++ b/plat/arm/board/juno/aarch64/juno_helpers.S
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a53.h>
+#include <cortex_a57.h>
+#include <cortex_a72.h>
+#include <cpu_macros.S>
+#include <platform_def.h>
+
+ .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 */
diff --git a/plat/arm/board/juno/fdts/juno_fw_config.dts b/plat/arm/board/juno/fdts/juno_fw_config.dts
new file mode 100644
index 0000000..4b88efe
--- /dev/null
+++ b/plat/arm/board/juno/fdts/juno_fw_config.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019-2021, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/tbbr/tbbr_img_def.h>
+
+/dts-v1/;
+
+/ {
+ dtb-registry {
+ compatible = "fconf,dyn_cfg-dtb_registry";
+
+ tb_fw-config {
+ load-address = <0x0 0x4001300>;
+ max-size = <0x200>;
+ id = <TB_FW_CONFIG_ID>;
+ };
+
+ hw-config {
+ load-address = <0x0 0x82000000>;
+ max-size = <0x8000>;
+ id = <HW_CONFIG_ID>;
+ };
+ };
+};
diff --git a/plat/arm/board/juno/fdts/juno_tb_fw_config.dts b/plat/arm/board/juno/fdts/juno_tb_fw_config.dts
new file mode 100644
index 0000000..80cfa3e
--- /dev/null
+++ b/plat/arm/board/juno/fdts/juno_tb_fw_config.dts
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+ tb_fw-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>;
+ };
+};
diff --git a/plat/arm/board/juno/include/plat_macros.S b/plat/arm/board/juno/include/plat_macros.S
new file mode 100644
index 0000000..ec94a4f
--- /dev/null
+++ b/plat/arm/board/juno/include/plat_macros.S
@@ -0,0 +1,24 @@
+/*
+ * 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 <cci_macros.S>
+#include <css_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
+ css_print_gic_regs
+ print_cci_regs
+ .endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/arm/board/juno/include/platform_def.h b/plat/arm/board/juno/include/platform_def.h
new file mode 100644
index 0000000..409d7a6
--- /dev/null
+++ b/plat/arm/board/juno/include/platform_def.h
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <drivers/arm/tzc400.h>
+#if TRUSTED_BOARD_BOOT
+#include MBEDTLS_CONFIG_FILE
+#endif
+#include <plat/arm/board/common/board_css_def.h>
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/common/arm_def.h>
+#include <plat/arm/css/common/css_def.h>
+#include <plat/arm/soc/common/soc_css_def.h>
+#include <plat/common/common_def.h>
+
+#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 */
+
+#define PLAT_ARM_DRAM2_BASE ULL(0x880000000)
+#define PLAT_ARM_DRAM2_SIZE ULL(0x180000000)
+
+/* Range of kernel DTB load address */
+#define JUNO_DTB_DRAM_MAP_START ULL(0x82000000)
+#define JUNO_DTB_DRAM_MAP_SIZE ULL(0x00008000) /* 32KB */
+
+#define ARM_DTB_DRAM_NS MAP_REGION_FLAT( \
+ JUNO_DTB_DRAM_MAP_START, \
+ JUNO_DTB_DRAM_MAP_SIZE, \
+ MT_MEMORY | MT_RO | MT_NS)
+
+/* 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)
+#define JUNO_BL2_ROMLIB_OPTIMIZATION UL(0x8000)
+#else
+#define PLAT_ARM_MAX_ROMLIB_RW_SIZE UL(0)
+#define PLAT_ARM_MAX_ROMLIB_RO_SIZE UL(0)
+#define JUNO_BL2_ROMLIB_OPTIMIZATION 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 5
+#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) - JUNO_BL2_ROMLIB_OPTIMIZATION)
+#elif TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA
+# define PLAT_ARM_MAX_BL2_SIZE (UL(0x1D000) - JUNO_BL2_ROMLIB_OPTIMIZATION)
+#else
+# define PLAT_ARM_MAX_BL2_SIZE (UL(0x1D000) - JUNO_BL2_ROMLIB_OPTIMIZATION)
+#endif
+#else
+# define PLAT_ARM_MAX_BL2_SIZE (UL(0x13000) - JUNO_BL2_ROMLIB_OPTIMIZATION)
+#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(0x3D000)
+
+#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(0x3D000)
+#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
+
+/* 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))
+
+/* TZC related constants */
+#define PLAT_ARM_TZC_FILTERS TZC_400_REGION_ATTR_FILTER_BIT_ALL
+
+/*
+ * 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)
+
+/*
+ * 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
+
+/*
+ * SCP_BL2 uses up whatever remaining space is available as it is loaded before
+ * anything else in this memory region and is handed over to the SCP before
+ * BL31 is loaded over the top.
+ */
+#define PLAT_CSS_MAX_SCP_BL2_SIZE \
+ ((SCP_BL2_LIMIT - ARM_FW_CONFIG_LIMIT) & ~PAGE_SIZE_MASK)
+
+#define PLAT_CSS_MAX_SCP_BL2U_SIZE PLAT_CSS_MAX_SCP_BL2_SIZE
+
+#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
+
+/* Number of SCMI channels on the platform */
+#define PLAT_ARM_SCMI_CHANNEL_COUNT U(1)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/juno/jmptbl.i b/plat/arm/board/juno/jmptbl.i
new file mode 100644
index 0000000..8932aa0
--- /dev/null
+++ b/plat/arm/board/juno/jmptbl.i
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2018-2022, 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
+fdt fdt_get_property
+fdt fdt_getprop_namelen
+fdt fdt_setprop_inplace
+fdt fdt_check_header
+fdt fdt_node_offset_by_compatible
+fdt fdt_setprop_inplace_namelen_partial
+fdt fdt_first_subnode
+fdt fdt_next_subnode
+fdt fdt_parent_offset
+fdt fdt_stringlist_search
+fdt fdt_get_alias_namelen
+fdt fdt_path_offset
+fdt fdt_path_offset_namelen
+fdt fdt_address_cells
+fdt fdt_size_cells
+fdt fdt_get_name
+fdt fdt_get_alias
+fdt fdt_node_offset_by_phandle
+fdt fdt_subnode_offset
+fdt fdt_add_subnode
+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
diff --git a/plat/arm/board/juno/juno_bl1_setup.c b/plat/arm/board/juno/juno_bl1_setup.c
new file mode 100644
index 0000000..a9d5cc3
--- /dev/null
+++ b/plat/arm/board/juno/juno_bl1_setup.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/arm/css/sds.h>
+#include <drivers/arm/sp805.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/common/arm_def.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+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.
+ ******************************************************************************/
+bool plat_arm_bl1_fwu_needed(void)
+{
+ int32_t nv_flags = (int32_t)mmio_read_32(V2M_SYS_NVFLAGS_ADDR);
+
+ /* Check if TOC is invalid or watchdog reset happened. */
+ return (!arm_io_is_toc_valid() || (((nv_flags == -EAUTH) ||
+ (nv_flags == -ENOENT)) && is_watchdog_reset()));
+}
+
+/*******************************************************************************
+ * 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)
+{
+ uint32_t nv_flags = mmio_read_32(V2M_SYS_NVFLAGS_ADDR);
+
+ /* Clear the NV flags register. */
+ mmio_write_32((V2M_SYSREGS_BASE + V2M_SYS_NVFLAGSCLR),
+ nv_flags);
+
+ /* Setup the watchdog to reset the system as soon as possible */
+ sp805_refresh(ARM_SP805_TWDG_BASE, 1U);
+
+ while (true)
+ 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);
+}
diff --git a/plat/arm/board/juno/juno_bl2_setup.c b/plat/arm/board/juno/juno_bl2_setup.c
new file mode 100644
index 0000000..849acd6
--- /dev/null
+++ b/plat/arm/board/juno/juno_bl2_setup.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2016-2017,2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_dyn_cfg_getter.h>
+
+#include <plat/arm/common/plat_arm.h>
+
+#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;
+}
+
+#else
+
+/*******************************************************************************
+ * This function returns the list of executable images
+ ******************************************************************************/
+struct bl_params *plat_get_next_bl_params(void)
+{
+ struct bl_params *arm_bl_params = arm_get_next_bl_params();
+
+#if __aarch64__
+ const struct dyn_cfg_dtb_info_t *fw_config_info;
+ bl_mem_params_node_t *param_node;
+ uintptr_t fw_config_base = 0U;
+ entry_point_info_t *ep_info;
+
+ /* Get BL31 image node */
+ param_node = get_bl_mem_params_node(BL31_IMAGE_ID);
+ assert(param_node != NULL);
+
+ /* Get fw_config load address */
+ fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, FW_CONFIG_ID);
+ assert(fw_config_info != NULL);
+
+ fw_config_base = fw_config_info->config_addr;
+ assert(fw_config_base != 0U);
+
+ /*
+ * Get the entry point info of BL31 image and override
+ * arg1 of entry point info with fw_config base address
+ */
+ ep_info = &param_node->ep_info;
+ ep_info->args.arg1 = (uint32_t)fw_config_base;
+#endif /* __aarch64__ */
+
+ return arm_bl_params;
+}
+#endif /* JUNO_AARCH32_EL3_RUNTIME */
diff --git a/plat/arm/board/juno/juno_bl31_setup.c b/plat/arm/board/juno/juno_bl31_setup.c
new file mode 100644
index 0000000..7a0a6d9
--- /dev/null
+++ b/plat/arm/board/juno/juno_bl31_setup.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_dyn_cfg_getter.h>
+
+#include <plat/arm/common/plat_arm.h>
+
+void __init bl31_early_platform_setup2(u_register_t arg0,
+ u_register_t arg1, u_register_t arg2, u_register_t arg3)
+{
+ const struct dyn_cfg_dtb_info_t *soc_fw_config_info;
+
+ INFO("BL31 FCONF: FW_CONFIG address = %lx\n", (uintptr_t)arg1);
+
+ /* Fill the properties struct with the info from the config dtb */
+ fconf_populate("FW_CONFIG", arg1);
+
+ soc_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, SOC_FW_CONFIG_ID);
+ if (soc_fw_config_info != NULL) {
+ arg1 = soc_fw_config_info->config_addr;
+ }
+
+ 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();
+}
+
+void __init bl31_plat_arch_setup(void)
+{
+ arm_bl31_plat_arch_setup();
+
+ /* HW_CONFIG was also loaded by BL2 */
+ const struct dyn_cfg_dtb_info_t *hw_config_info;
+
+ hw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, HW_CONFIG_ID);
+ assert(hw_config_info != NULL);
+
+ fconf_populate("HW_CONFIG", hw_config_info->config_addr);
+}
diff --git a/plat/arm/board/juno/juno_common.c b/plat/arm/board/juno/juno_common.c
new file mode 100644
index 0000000..038f604
--- /dev/null
+++ b/plat/arm/board/juno/juno_common.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/smccc.h>
+#include <platform_def.h>
+#include <services/arm_arch_svc.h>
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * 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,
+ ARM_DTB_DRAM_NS,
+ {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
+
+/*****************************************************************************
+ * plat_is_smccc_feature_available() - This function checks whether SMCCC
+ * feature is availabile for platform.
+ * @fid: SMCCC function id
+ *
+ * Return SMC_ARCH_CALL_SUCCESS if SMCCC feature is available and
+ * SMC_ARCH_CALL_NOT_SUPPORTED otherwise.
+ *****************************************************************************/
+int32_t plat_is_smccc_feature_available(u_register_t fid)
+{
+ switch (fid) {
+ case SMCCC_ARCH_SOC_ID:
+ return SMC_ARCH_CALL_SUCCESS;
+ default:
+ return SMC_ARCH_CALL_NOT_SUPPORTED;
+ }
+}
+
+/* Get SOC version */
+int32_t plat_get_soc_version(void)
+{
+ return (int32_t)
+ (SOC_ID_SET_JEP_106(ARM_SOC_CONTINUATION_CODE,
+ ARM_SOC_IDENTIFICATION_CODE) |
+ (JUNO_SOC_ID & SOC_ID_IMPL_DEF_MASK));
+}
+
+/* Get SOC revision */
+int32_t plat_get_soc_revision(void)
+{
+ unsigned int sys_id;
+
+ sys_id = mmio_read_32(V2M_SYSREGS_BASE + V2M_SYS_ID);
+ return (int32_t)(((sys_id >> V2M_SYS_ID_REV_SHIFT) &
+ V2M_SYS_ID_REV_MASK) & SOC_ID_REV_MASK);
+}
diff --git a/plat/arm/board/juno/juno_def.h b/plat/arm/board/juno/juno_def.h
new file mode 100644
index 0000000..ddf99dc
--- /dev/null
+++ b/plat/arm/board/juno/juno_def.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef JUNO_DEF_H
+#define JUNO_DEF_H
+
+#include <lib/utils_def.h>
+
+/******************************************************************************
+ * Definition of platform soc id
+ *****************************************************************************/
+#define JUNO_SOC_ID 1
+
+/*******************************************************************************
+ * 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 U(2)
+#define JUNO_CLUSTER0_CORE_COUNT U(2)
+#define JUNO_CLUSTER1_CORE_COUNT U(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 */
diff --git a/plat/arm/board/juno/juno_err.c b/plat/arm/board/juno/juno_err.c
new file mode 100644
index 0000000..02d751e
--- /dev/null
+++ b/plat/arm/board/juno/juno_err.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <drivers/arm/sp805.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+/*
+ * Juno error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+ /* Propagate the err code in the NV-flags register */
+ mmio_write_32(V2M_SYS_NVFLAGS_ADDR, (uint32_t)err);
+
+ /* Setup the watchdog to reset the system as soon as possible */
+ sp805_refresh(ARM_SP805_TWDG_BASE, 1U);
+
+ for (;;)
+ wfi();
+}
diff --git a/plat/arm/board/juno/juno_pm.c b/plat/arm/board/juno/juno_pm.c
new file mode 100644
index 0000000..cc80651
--- /dev/null
+++ b/plat/arm/board/juno/juno_pm.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/css/scmi.h>
+#include <plat/arm/common/plat_arm.h>
+
+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 */
+}
diff --git a/plat/arm/board/juno/juno_security.c b/plat/arm/board/juno/juno_security.c
new file mode 100644
index 0000000..654a7f1
--- /dev/null
+++ b/plat/arm/board/juno/juno_security.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/arm/nic_400.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/soc/common/soc_css.h>
+#include <plat/common/platform.h>
+
+#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);
+
+ /* Set internal drive selection for SPNIDEN. */
+ mmio_write_32(SSC_REG_BASE + SSC_DBGCFG_SET,
+ 1U << SPNIDEN_SEL_SET_SHIFT);
+
+ /* Drive SPNIDEN LOW to disable non-invasive debug of secure state. */
+ mmio_write_32(SSC_REG_BASE + SSC_DBGCFG_CLR,
+ 1U << SPNIDEN_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(PLAT_ARM_TZC_BASE, 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(PLAT_ARM_TZC_BASE, 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
diff --git a/plat/arm/board/juno/juno_stack_protector.c b/plat/arm/board/juno/juno_stack_protector.c
new file mode 100644
index 0000000..3924af8
--- /dev/null
+++ b/plat/arm/board/juno/juno_stack_protector.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/utils.h>
+#include <plat/common/plat_trng.h>
+#include <platform_def.h>
+
+u_register_t plat_get_stack_protector_canary(void)
+{
+ uint64_t entropy;
+
+ if (!plat_get_entropy(&entropy)) {
+ ERROR("Not enough entropy to initialize canary value\n");
+ panic();
+ }
+
+ if (sizeof(entropy) == sizeof(u_register_t)) {
+ return entropy;
+ }
+
+ return (entropy & 0xffffffffULL) ^ (entropy >> 32);
+}
diff --git a/plat/arm/board/juno/juno_topology.c b/plat/arm/board/juno/juno_topology.c
new file mode 100644
index 0000000..075f512
--- /dev/null
+++ b/plat/arm/board/juno/juno_topology.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/css/css_mhu_doorbell.h>
+#include <drivers/arm/css/scmi.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#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(int channel_id)
+{
+ 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 };
diff --git a/plat/arm/board/juno/juno_trng.c b/plat/arm/board/juno/juno_trng.c
new file mode 100644
index 0000000..09552a6
--- /dev/null
+++ b/plat/arm/board/juno/juno_trng.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arm_acle.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <platform_def.h>
+
+#include <lib/smccc.h>
+#include <services/trng_svc.h>
+#include <smccc_helpers.h>
+
+#include <plat/common/platform.h>
+
+#define NSAMPLE_CLOCKS 1 /* min 1 cycle, max 231 cycles */
+#define NRETRIES 5
+
+/* initialised to false */
+static bool juno_trng_initialized;
+
+static bool 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)
+ return true;
+ }
+ return false; /* No output data available. */
+}
+
+DEFINE_SVC_UUID2(_plat_trng_uuid,
+ 0x23523c58, 0x7448, 0x4083, 0x9d, 0x16,
+ 0xe3, 0xfa, 0xb9, 0xf1, 0x73, 0xbc
+);
+uuid_t plat_trng_uuid;
+
+static uint32_t crc_value = ~0U;
+
+/*
+ * Uses the Trusted Entropy Source peripheral on Juno to return 8 bytes of
+ * entropy. Returns 'true' when done successfully, 'false' otherwise.
+ */
+bool plat_get_entropy(uint64_t *out)
+{
+ uint64_t ret;
+
+ assert(out);
+ assert(!check_uptr_overflow((uintptr_t)out, sizeof(*out)));
+
+ if (!juno_trng_initialized) {
+ /* 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);
+ /* Abort any potentially pending sampling. */
+ mmio_write_32(TRNG_BASE + TRNG_CONTROL, 2);
+ /* Reset TRNG outputs. */
+ mmio_write_32(TRNG_BASE + TRNG_STATUS, 1);
+
+ juno_trng_initialized = true;
+ }
+
+ if (!output_valid()) {
+ /* Start TRNG. */
+ mmio_write_32(TRNG_BASE + TRNG_CONTROL, 1);
+
+ if (!output_valid())
+ return false;
+ }
+
+ /* CRC each two 32-bit registers together, combine the pairs */
+ crc_value = __crc32w(crc_value, mmio_read_32(TRNG_BASE + 0));
+ crc_value = __crc32w(crc_value, mmio_read_32(TRNG_BASE + 4));
+ ret = (uint64_t)crc_value << 32;
+
+ crc_value = __crc32w(crc_value, mmio_read_32(TRNG_BASE + 8));
+ crc_value = __crc32w(crc_value, mmio_read_32(TRNG_BASE + 12));
+ *out = ret | crc_value;
+
+ /* Acknowledge current cycle, clear output registers. */
+ mmio_write_32(TRNG_BASE + TRNG_STATUS, 1);
+ /* Trigger next TRNG cycle. */
+ mmio_write_32(TRNG_BASE + TRNG_CONTROL, 1);
+
+ return true;
+}
+
+void plat_entropy_setup(void)
+{
+ uint64_t dummy;
+
+ plat_trng_uuid = _plat_trng_uuid;
+
+ /* Initialise the entropy source and trigger RNG generation */
+ plat_get_entropy(&dummy);
+}
diff --git a/plat/arm/board/juno/juno_trusted_boot.c b/plat/arm/board/juno/juno_trusted_boot.c
new file mode 100644
index 0000000..25a7470
--- /dev/null
+++ b/plat/arm/board/juno/juno_trusted_boot.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <drivers/arm/cryptocell/cc_rotpk.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/common_def.h>
+#include <plat/common/platform.h>
+
+#if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_REGS_ID)
+
+static unsigned char rotpk_hash_der[ARM_ROTPK_HEADER_LEN + ARM_ROTPK_HASH_LEN];
+
+extern unsigned char arm_rotpk_header[];
+
+/*
+ * Return the ROTPK hash stored in the registers of Juno board.
+ */
+static int juno_get_rotpk_info_regs(void **key_ptr, unsigned int *key_len,
+ unsigned int *flags)
+{
+ uint8_t *dst;
+ uint32_t *src, tmp;
+ unsigned int words, i;
+
+ assert(key_ptr != NULL);
+ assert(key_len != NULL);
+ assert(flags != NULL);
+
+ /* Copy the DER header */
+ memcpy(rotpk_hash_der, arm_rotpk_header, ARM_ROTPK_HEADER_LEN);
+ dst = (uint8_t *)&rotpk_hash_der[ARM_ROTPK_HEADER_LEN];
+
+
+ /*
+ * 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 = ARM_ROTPK_HASH_LEN >> 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 + ARM_ROTPK_HASH_LEN / 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);
+ }
+
+ *key_ptr = (void *)rotpk_hash_der;
+ *key_len = (unsigned int)sizeof(rotpk_hash_der);
+ *flags = ROTPK_IS_HASH;
+ return 0;
+}
+
+#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)
+{
+#if ARM_CRYPTOCELL_INTEG
+ return arm_get_rotpk_info_cc(key_ptr, key_len, flags);
+#else
+
+#if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID) || \
+ (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_ECDSA_ID)
+ return arm_get_rotpk_info_dev(key_ptr, key_len, flags);
+#elif (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_REGS_ID)
+ return juno_get_rotpk_info_regs(key_ptr, key_len, flags);
+#else
+ return 1;
+#endif
+
+#endif /* ARM_CRYPTOCELL_INTEG */
+}
diff --git a/plat/arm/board/juno/juno_tzmp1_def.h b/plat/arm/board/juno/juno_tzmp1_def.h
new file mode 100644
index 0000000..4186d02
--- /dev/null
+++ b/plat/arm/board/juno/juno_tzmp1_def.h
@@ -0,0 +1,83 @@
+/*
+ * 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 */
diff --git a/plat/arm/board/juno/platform.mk b/plat/arm/board/juno/platform.mk
new file mode 100644
index 0000000..2c84eb3
--- /dev/null
+++ b/plat/arm/board/juno/platform.mk
@@ -0,0 +1,201 @@
+#
+# Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include common/fdt_wrappers.mk
+
+# Include GICv2 driver files
+include drivers/arm/gic/v2/gicv2.mk
+
+JUNO_GIC_SOURCES := ${GICV2_SOURCES} \
+ 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
+
+TRNG_SUPPORT := 1
+
+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 \
+ lib/fconf/fconf.c \
+ lib/fconf/fconf_dyn_cfg_getter.c \
+ plat/arm/board/juno/juno_bl31_setup.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}
+
+BL31_SOURCES += ${FDT_WRAPPERS_SOURCES}
+
+ifeq (${CSS_USE_SCMI_SDS_DRIVER},1)
+BL1_SOURCES += drivers/arm/css/sds/sds.c
+endif
+
+ifeq (${TRUSTED_BOARD_BOOT}, 1)
+BL1_SOURCES += plat/arm/board/juno/juno_trusted_boot.c
+BL2_SOURCES += plat/arm/board/juno/juno_trusted_boot.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 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_CPPFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC
+ endif
+else
+ ifeq (${RESET_TO_BL31},1)
+ BL31_CPPFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC
+ endif
+endif
+
+ifeq (${ALLOW_RO_XLAT_TABLES}, 1)
+ ifeq (${JUNO_AARCH32_EL3_RUNTIME}, 1)
+ BL32_CPPFLAGS += -DPLAT_RO_XLAT_TABLES
+ else
+ BL31_CPPFLAGS += -DPLAT_RO_XLAT_TABLES
+ endif
+endif
+
+BL1_CPPFLAGS += -march=armv8-a+crc
+BL2_CPPFLAGS += -march=armv8-a+crc
+BL2U_CPPFLAGS += -march=armv8-a+crc
+BL31_CPPFLAGS += -march=armv8-a+crc
+BL32_CPPFLAGS += -march=armv8-a+crc
+
+# Add the FDT_SOURCES and options for Dynamic Config
+FDT_SOURCES += plat/arm/board/juno/fdts/${PLAT}_fw_config.dts \
+ plat/arm/board/juno/fdts/${PLAT}_tb_fw_config.dts \
+ fdts/${PLAT}.dts
+
+FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_fw_config.dtb
+TB_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb
+HW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}.dtb
+
+# Add the FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FW_CONFIG},--fw-config,${FW_CONFIG}))
+# Add the TB_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--tb-fw-config,${TB_FW_CONFIG}))
+# Add the HW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${HW_CONFIG},--hw-config,${HW_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
diff --git a/plat/arm/board/juno/sp_min/sp_min-juno.mk b/plat/arm/board/juno/sp_min/sp_min-juno.mk
new file mode 100644
index 0000000..b3471c1
--- /dev/null
+++ b/plat/arm/board/juno/sp_min/sp_min-juno.mk
@@ -0,0 +1,22 @@
+#
+# 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
diff --git a/plat/arm/board/juno/tsp/tsp-juno.mk b/plat/arm/board/juno/tsp/tsp-juno.mk
new file mode 100644
index 0000000..be75c4d
--- /dev/null
+++ b/plat/arm/board/juno/tsp/tsp-juno.mk
@@ -0,0 +1,12 @@
+#
+# 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
diff --git a/plat/arm/board/morello/aarch64/morello_helper.S b/plat/arm/board/morello/aarch64/morello_helper.S
new file mode 100644
index 0000000..60470a8
--- /dev/null
+++ b/plat/arm/board/morello/aarch64/morello_helper.S
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cpu_macros.S>
+#include <rainier.h>
+
+#include <platform_def.h>
+
+ .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.
+ * ((ChipId * MORELLO_MAX_CLUSTERS_PER_CHIP + ClusterId) *
+ * MORELLO_MAX_CPUS_PER_CLUSTER * MORELLO_MAX_PE_PER_CPU) +
+ * (CPUId * MORELLO_MAX_PE_PER_CPU) + ThreadId
+ *
+ * which can be simplified as:
+ *
+ * (((ChipId * MORELLO_MAX_CLUSTERS_PER_CHIP + ClusterId) *
+ * MORELLO_MAX_CPUS_PER_CLUSTER + CPUId) * MORELLO_MAX_PE_PER_CPU) +
+ * ThreadId
+ * ------------------------------------------------------
+ */
+
+func plat_arm_calc_core_pos
+ mov x4, x0
+
+ /*
+ * The MT bit in MPIDR is always set for morello and the
+ * affinity level 0 corresponds to thread affinity level.
+ */
+
+ /* Extract individual affinity fields from MPIDR */
+ ubfx x0, x4, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
+ ubfx x1, x4, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
+ ubfx x2, x4, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
+ ubfx x3, x4, #MPIDR_AFF3_SHIFT, #MPIDR_AFFINITY_BITS
+
+ /* Compute linear position */
+ mov x4, #MORELLO_MAX_CLUSTERS_PER_CHIP
+ madd x2, x3, x4, x2
+ mov x4, #MORELLO_MAX_CPUS_PER_CLUSTER
+ madd x1, x2, x4, x1
+ mov x4, #MORELLO_MAX_PE_PER_CPU
+ madd x0, x1, x4, x0
+ ret
+endfunc plat_arm_calc_core_pos
diff --git a/plat/arm/board/morello/fdts/morello_fw_config.dts b/plat/arm/board/morello/fdts/morello_fw_config.dts
new file mode 100644
index 0000000..c47bae5
--- /dev/null
+++ b/plat/arm/board/morello/fdts/morello_fw_config.dts
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/tbbr/tbbr_img_def.h>
+
+/dts-v1/;
+/ {
+ dtb-registry {
+ compatible = "fconf,dyn_cfg-dtb_registry";
+
+ tb_fw-config {
+ load-address = <0x0 0x4001300>;
+ max-size = <0x200>;
+ id = <TB_FW_CONFIG_ID>;
+ };
+
+ nt_fw-config {
+ load-address = <0x0 0xFEF00000>;
+ max-size = <0x0100000>;
+ id = <NT_FW_CONFIG_ID>;
+ };
+ };
+};
diff --git a/plat/arm/board/morello/fdts/morello_nt_fw_config.dts b/plat/arm/board/morello/fdts/morello_nt_fw_config.dts
new file mode 100644
index 0000000..e730d34
--- /dev/null
+++ b/plat/arm/board/morello/fdts/morello_nt_fw_config.dts
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+/ {
+ /* compatible string */
+ compatible = "arm,morello";
+
+ /*
+ * Place holder for platform-info node with default values.
+ * The values will be set to the correct values during
+ * the BL2 stage of boot.
+ */
+ platform-info {
+ local-ddr-size = <0x0 0x0>;
+#ifdef TARGET_PLATFORM_SOC
+ remote-ddr-size = <0x0 0x0>;
+ remote-chip-count = <0x0>;
+ multichip-mode = <0x0>;
+ scc-config = <0x0>;
+#endif
+ };
+};
diff --git a/plat/arm/board/morello/fdts/morello_tb_fw_config.dts b/plat/arm/board/morello/fdts/morello_tb_fw_config.dts
new file mode 100644
index 0000000..305a818
--- /dev/null
+++ b/plat/arm/board/morello/fdts/morello_tb_fw_config.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+/ {
+ tb_fw-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>;
+ };
+};
diff --git a/plat/arm/board/morello/include/plat_macros.S b/plat/arm/board/morello/include/plat_macros.S
new file mode 100644
index 0000000..195be84
--- /dev/null
+++ b/plat/arm/board/morello/include/plat_macros.S
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <css_macros.S>
+
+/* ---------------------------------------------
+ * 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 */
diff --git a/plat/arm/board/morello/include/platform_def.h b/plat/arm/board/morello/include/platform_def.h
new file mode 100644
index 0000000..08e2d60
--- /dev/null
+++ b/plat/arm/board/morello/include/platform_def.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/common/arm_def.h>
+#include <plat/arm/css/common/css_def.h>
+
+/* UART related constants */
+#define PLAT_ARM_BOOT_UART_BASE ULL(0x2A400000)
+#define PLAT_ARM_BOOT_UART_CLK_IN_HZ U(50000000)
+
+/* IOFPGA UART0 */
+#define PLAT_ARM_RUN_UART_BASE ULL(0x1C090000)
+#define PLAT_ARM_RUN_UART_CLK_IN_HZ U(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 PLAT_ARM_DRAM2_BASE ULL(0x8080000000)
+#define PLAT_ARM_DRAM2_SIZE ULL(0xF80000000)
+
+#define MAX_IO_DEVICES U(3)
+#define MAX_IO_HANDLES U(4)
+
+#define PLAT_ARM_FLASH_IMAGE_BASE ULL(0x1A000000)
+#define PLAT_ARM_FLASH_IMAGE_MAX_SIZE ULL(0x01000000)
+
+#define PLAT_ARM_NVM_BASE ULL(0x1A000000)
+#define PLAT_ARM_NVM_SIZE ULL(0x01000000)
+
+#if defined NS_BL1U_BASE
+#undef NS_BL1U_BASE
+#define NS_BL1U_BASE (PLAT_ARM_NVM_BASE + UL(0x00800000))
+#endif
+
+/*
+ * There are no non-volatile counters in morello, these macros points
+ * to unused addresses.
+ */
+#define SOC_TRUSTED_NVCTR_BASE ULL(0x7FE70000)
+#define TFW_NVCTR_BASE (SOC_TRUSTED_NVCTR_BASE + U(0x0000))
+#define TFW_NVCTR_SIZE U(4)
+#define NTFW_CTR_BASE (SOC_TRUSTED_NVCTR_BASE + U(0x0004))
+#define NTFW_CTR_SIZE U(4)
+
+/*
+ * To access the complete DDR memory along with remote chip's DDR memory,
+ * which is at 4 TB offset, physical and virtual address space limits are
+ * extended to 43-bits.
+ */
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 43)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 43)
+
+#if CSS_USE_SCMI_SDS_DRIVER
+#define MORELLO_SCMI_PAYLOAD_BASE ULL(0x45400000)
+#else
+#define PLAT_CSS_SCP_COM_SHARED_MEM_BASE ULL(0x45400000)
+#endif
+
+#define PLAT_ARM_TRUSTED_SRAM_SIZE UL(0x00080000)
+
+/*
+ * 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(0xC000)
+
+/*
+ * 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 U(0)
+#define PLAT_ARM_MAX_ROMLIB_RO_SIZE U(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(0x14000)
+#endif
+
+#define PLAT_ARM_MAX_BL31_SIZE UL(0x3B000)
+
+/*******************************************************************************
+ * MORELLO topology related constants
+ ******************************************************************************/
+#define MORELLO_MAX_CPUS_PER_CLUSTER U(2)
+#define PLAT_ARM_CLUSTER_COUNT U(2)
+#define PLAT_MORELLO_CHIP_COUNT U(1)
+#define MORELLO_MAX_CLUSTERS_PER_CHIP U(2)
+#define MORELLO_MAX_PE_PER_CPU U(1)
+
+#define PLATFORM_CORE_COUNT (PLAT_MORELLO_CHIP_COUNT * \
+ PLAT_ARM_CLUSTER_COUNT * \
+ MORELLO_MAX_CPUS_PER_CLUSTER * \
+ MORELLO_MAX_PE_PER_CPU)
+
+/* System power domain level */
+#define CSS_SYSTEM_PWR_DMN_LVL ARM_PWR_LVL3
+
+/*
+ * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the
+ * plat_arm_mmap array defined for each BL stage.
+ */
+#if IMAGE_BL1 || IMAGE_BL31
+# define PLAT_ARM_MMAP_ENTRIES U(6)
+# define MAX_XLAT_TABLES U(7)
+#else
+# define PLAT_ARM_MMAP_ENTRIES U(5)
+# define MAX_XLAT_TABLES U(6)
+#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 SPM_MM
+# define PLATFORM_STACK_SIZE UL(0x500)
+# else
+# define PLATFORM_STACK_SIZE UL(0x400)
+# endif
+#elif defined(IMAGE_BL32)
+# define PLATFORM_STACK_SIZE UL(0x440)
+#endif
+
+#define PLAT_ARM_NSTIMER_FRAME_ID U(0)
+
+#define PLAT_ARM_TRUSTED_ROM_BASE U(0x0)
+#define PLAT_ARM_TRUSTED_ROM_SIZE UL(0x00020000) /* 128KB */
+
+#define PLAT_ARM_NSRAM_BASE ULL(0x06000000)
+#define PLAT_ARM_NSRAM_SIZE UL(0x00010000) /* 64KB */
+
+#define PLAT_CSS_MHU_BASE UL(0x45000000)
+#define PLAT_MHUV2_BASE PLAT_CSS_MHU_BASE
+#define PLAT_MAX_PWR_LVL U(2)
+
+#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 MORELLO_DEVICE_BASE ULL(0x08000000)
+#define MORELLO_DEVICE_SIZE ULL(0x48000000)
+
+/*Secure Watchdog Constants */
+#define SBSA_SECURE_WDOG_BASE UL(0x2A480000)
+#define SBSA_SECURE_WDOG_TIMEOUT UL(1000)
+
+#define MORELLO_MAP_DEVICE MAP_REGION_FLAT( \
+ MORELLO_DEVICE_BASE, \
+ MORELLO_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 UL(0x30000000)
+#define PLAT_ARM_GICC_BASE UL(0x2C000000)
+#define PLAT_ARM_GICR_BASE UL(0x300C0000)
+
+/* Number of SCMI channels on the platform */
+#define PLAT_ARM_SCMI_CHANNEL_COUNT U(1)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/morello/morello_bl1_setup.c b/plat/arm/board/morello/morello_bl1_setup.c
new file mode 100644
index 0000000..9155542
--- /dev/null
+++ b/plat/arm/board/morello/morello_bl1_setup.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*******************************************************************************
+ * Perform any BL1 specific platform actions.
+ ******************************************************************************/
+
+void soc_css_init_nic400(void)
+{
+}
+
+void soc_css_init_pcie(void)
+{
+}
diff --git a/plat/arm/board/morello/morello_bl2_setup.c b/plat/arm/board/morello/morello_bl2_setup.c
new file mode 100644
index 0000000..da1f7ae
--- /dev/null
+++ b/plat/arm/board/morello/morello_bl2_setup.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/arm/css/sds.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <plat/arm/common/plat_arm.h>
+
+#include "morello_def.h"
+#include <platform_def.h>
+
+#ifdef TARGET_PLATFORM_FVP
+/*
+ * Platform information structure stored in SDS.
+ * This structure holds information about platform's DDR
+ * size
+ * - Local DDR size in bytes, DDR memory in main board
+ */
+struct morello_plat_info {
+ uint64_t local_ddr_size;
+} __packed;
+#else
+/*
+ * Platform information structure stored in SDS.
+ * This structure holds information about platform's DDR
+ * size which is an information about multichip setup
+ * - Local DDR size in bytes, DDR memory in main board
+ * - Remote DDR size in bytes, DDR memory in remote board
+ * - remote_chip_count
+ * - multichip mode
+ * - scc configuration
+ */
+struct morello_plat_info {
+ uint64_t local_ddr_size;
+ uint64_t remote_ddr_size;
+ uint8_t remote_chip_count;
+ bool multichip_mode;
+ uint32_t scc_config;
+} __packed;
+#endif
+
+/* Compile time assertion to ensure the size of structure is 18 bytes */
+CASSERT(sizeof(struct morello_plat_info) == MORELLO_SDS_PLATFORM_INFO_SIZE,
+ assert_invalid_plat_info_size);
+
+#ifdef TARGET_PLATFORM_SOC
+/*
+ * Morello 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 DMC-Bing. 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.
+ */
+
+static void dmc_ecc_setup(struct morello_plat_info *plat_info)
+{
+ uint64_t dram2_size;
+ uint32_t val;
+ uint64_t tag_mem_base;
+ uint64_t usable_mem_size;
+
+ INFO("Total DIMM size: %uGB\n",
+ (uint32_t)(plat_info->local_ddr_size / 0x40000000));
+
+ assert(plat_info->local_ddr_size > ARM_DRAM1_SIZE);
+ dram2_size = plat_info->local_ddr_size - ARM_DRAM1_SIZE;
+
+ INFO("Zeroing DDR memory range 0x80000000 - 0xFFFFFFFF\n");
+ zero_normalmem((void *)ARM_DRAM1_BASE, ARM_DRAM1_SIZE);
+ flush_dcache_range(ARM_DRAM1_BASE, ARM_DRAM1_SIZE);
+
+ INFO("Zeroing DDR memory range 0x%llx - 0x%llx\n",
+ ARM_DRAM2_BASE, ARM_DRAM2_BASE + dram2_size);
+ zero_normalmem((void *)ARM_DRAM2_BASE, dram2_size);
+ flush_dcache_range(ARM_DRAM2_BASE, dram2_size);
+
+ /* Clear previous ECC errors while zeroing out the memory */
+ val = mmio_read_32(MORELLO_DMC0_ERR2STATUS_REG);
+ mmio_write_32(MORELLO_DMC0_ERR2STATUS_REG, val);
+
+ val = mmio_read_32(MORELLO_DMC1_ERR2STATUS_REG);
+ mmio_write_32(MORELLO_DMC1_ERR2STATUS_REG, val);
+
+ /* Set DMCs to CONFIG state before writing ERR0CTLR0 register */
+ mmio_write_32(MORELLO_DMC0_MEMC_CMD_REG, MORELLO_DMC_MEMC_CMD_CONFIG);
+ mmio_write_32(MORELLO_DMC1_MEMC_CMD_REG, MORELLO_DMC_MEMC_CMD_CONFIG);
+
+ while ((mmio_read_32(MORELLO_DMC0_MEMC_STATUS_REG) &
+ MORELLO_DMC_MEMC_STATUS_MASK) !=
+ MORELLO_DMC_MEMC_CMD_CONFIG) {
+ continue;
+ }
+
+ while ((mmio_read_32(MORELLO_DMC1_MEMC_STATUS_REG) &
+ MORELLO_DMC_MEMC_STATUS_MASK) !=
+ MORELLO_DMC_MEMC_CMD_CONFIG) {
+ continue;
+ }
+
+ /* Configure Bing client/server mode based on SCC configuration */
+ if (plat_info->scc_config & MORELLO_SCC_CLIENT_MODE_MASK) {
+ INFO("Configuring DMC Bing in client mode\n");
+ usable_mem_size = plat_info->local_ddr_size -
+ (plat_info->local_ddr_size / 128ULL);
+
+ /* Linear DDR address */
+ tag_mem_base = usable_mem_size;
+ tag_mem_base = tag_mem_base / 4;
+
+ /* Reverse translation */
+ if (tag_mem_base < ARM_DRAM1_BASE) {
+ tag_mem_base += ARM_DRAM1_BASE;
+ } else {
+ tag_mem_base = tag_mem_base - ARM_DRAM1_BASE +
+ ARM_DRAM2_BASE;
+ }
+
+ mmio_write_32(MORELLO_DMC0_CAP_CTRL_REG, 0x1);
+ mmio_write_32(MORELLO_DMC1_CAP_CTRL_REG, 0x1);
+ mmio_write_32(MORELLO_DMC0_TAG_CACHE_CFG, 0x1);
+ mmio_write_32(MORELLO_DMC1_TAG_CACHE_CFG, 0x1);
+
+ if (plat_info->scc_config & MORELLO_SCC_C1_TAG_CACHE_EN_MASK) {
+ mmio_setbits_32(MORELLO_DMC0_TAG_CACHE_CFG, 0x2);
+ mmio_setbits_32(MORELLO_DMC1_TAG_CACHE_CFG, 0x2);
+ INFO("C1 Tag Cache Enabled\n");
+ }
+
+ if (plat_info->scc_config & MORELLO_SCC_C2_TAG_CACHE_EN_MASK) {
+ mmio_setbits_32(MORELLO_DMC0_TAG_CACHE_CFG, 0x4);
+ mmio_setbits_32(MORELLO_DMC1_TAG_CACHE_CFG, 0x4);
+ INFO("C2 Tag Cache Enabled\n");
+ }
+
+ mmio_write_32(MORELLO_DMC0_MEM_ADDR_CTL,
+ (uint32_t)tag_mem_base);
+ mmio_write_32(MORELLO_DMC1_MEM_ADDR_CTL,
+ (uint32_t)tag_mem_base);
+ mmio_write_32(MORELLO_DMC0_MEM_ADDR_CTL2,
+ (uint32_t)(tag_mem_base >> 32));
+ mmio_write_32(MORELLO_DMC1_MEM_ADDR_CTL2,
+ (uint32_t)(tag_mem_base >> 32));
+
+ mmio_setbits_32(MORELLO_DMC0_MEM_ACCESS_CTL,
+ MORELLO_DMC_MEM_ACCESS_DIS);
+ mmio_setbits_32(MORELLO_DMC1_MEM_ACCESS_CTL,
+ MORELLO_DMC_MEM_ACCESS_DIS);
+
+ INFO("Tag base set to 0x%lx\n", tag_mem_base);
+ plat_info->local_ddr_size = usable_mem_size;
+ } else {
+ INFO("Configuring DMC Bing in server mode\n");
+ mmio_write_32(MORELLO_DMC0_CAP_CTRL_REG, 0x0);
+ mmio_write_32(MORELLO_DMC1_CAP_CTRL_REG, 0x0);
+ }
+
+ INFO("Enabling ECC on DMCs\n");
+ /* Enable ECC in DMCs */
+ mmio_setbits_32(MORELLO_DMC0_ERR0CTLR0_REG,
+ MORELLO_DMC_ERR0CTLR0_ECC_EN);
+ mmio_setbits_32(MORELLO_DMC1_ERR0CTLR0_REG,
+ MORELLO_DMC_ERR0CTLR0_ECC_EN);
+
+ /* Set DMCs to READY state */
+ mmio_write_32(MORELLO_DMC0_MEMC_CMD_REG, MORELLO_DMC_MEMC_CMD_READY);
+ mmio_write_32(MORELLO_DMC1_MEMC_CMD_REG, MORELLO_DMC_MEMC_CMD_READY);
+
+ while ((mmio_read_32(MORELLO_DMC0_MEMC_STATUS_REG) &
+ MORELLO_DMC_MEMC_STATUS_MASK) !=
+ MORELLO_DMC_MEMC_CMD_READY) {
+ continue;
+ }
+
+ while ((mmio_read_32(MORELLO_DMC1_MEMC_STATUS_REG) &
+ MORELLO_DMC_MEMC_STATUS_MASK) !=
+ MORELLO_DMC_MEMC_CMD_READY) {
+ continue;
+ }
+}
+#endif
+
+void bl2_platform_setup(void)
+{
+ int ret;
+ struct morello_plat_info plat_info;
+
+ ret = sds_init();
+ if (ret != SDS_OK) {
+ ERROR("SDS initialization failed. ret:%d\n", ret);
+ panic();
+ }
+
+ ret = sds_struct_read(MORELLO_SDS_PLATFORM_INFO_STRUCT_ID,
+ MORELLO_SDS_PLATFORM_INFO_OFFSET,
+ &plat_info,
+ MORELLO_SDS_PLATFORM_INFO_SIZE,
+ SDS_ACCESS_MODE_NON_CACHED);
+ if (ret != SDS_OK) {
+ ERROR("Error getting platform info from SDS. ret:%d\n", ret);
+ panic();
+ }
+
+ /* Validate plat_info SDS */
+#ifdef TARGET_PLATFORM_FVP
+ if (plat_info.local_ddr_size == 0U) {
+#else
+ if ((plat_info.local_ddr_size == 0U)
+ || (plat_info.local_ddr_size > MORELLO_MAX_DDR_CAPACITY)
+ || (plat_info.remote_ddr_size > MORELLO_MAX_DDR_CAPACITY)
+ || (plat_info.remote_chip_count > MORELLO_MAX_REMOTE_CHIP_COUNT)
+ ) {
+#endif
+ ERROR("platform info SDS is corrupted\n");
+ panic();
+ }
+
+#ifdef TARGET_PLATFORM_SOC
+ dmc_ecc_setup(&plat_info);
+#endif
+ arm_bl2_platform_setup();
+}
diff --git a/plat/arm/board/morello/morello_bl31_setup.c b/plat/arm/board/morello/morello_bl31_setup.c
new file mode 100644
index 0000000..a044212
--- /dev/null
+++ b/plat/arm/board/morello/morello_bl31_setup.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/css/css_mhu_doorbell.h>
+#include <drivers/arm/css/scmi.h>
+#include <plat/arm/common/plat_arm.h>
+
+#include "morello_def.h"
+#include <platform_def.h>
+
+static scmi_channel_plat_info_t morello_scmi_plat_info = {
+ .scmi_mbx_mem = MORELLO_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(int channel_id)
+{
+ return &morello_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);
+}
+
+void bl31_platform_setup(void)
+{
+ arm_bl31_platform_setup();
+}
diff --git a/plat/arm/board/morello/morello_def.h b/plat/arm/board/morello/morello_def.h
new file mode 100644
index 0000000..f154924
--- /dev/null
+++ b/plat/arm/board/morello/morello_def.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MORELLO_DEF_H
+#define MORELLO_DEF_H
+
+/* Non-secure SRAM MMU mapping */
+#define MORELLO_NS_SRAM_BASE UL(0x06000000)
+#define MORELLO_NS_SRAM_SIZE UL(0x00010000)
+#define MORELLO_MAP_NS_SRAM MAP_REGION_FLAT( \
+ MORELLO_NS_SRAM_BASE, \
+ MORELLO_NS_SRAM_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+/* SDS Platform information defines */
+#define MORELLO_SDS_PLATFORM_INFO_STRUCT_ID U(8)
+#define MORELLO_SDS_PLATFORM_INFO_OFFSET U(0)
+#ifdef TARGET_PLATFORM_FVP
+# define MORELLO_SDS_PLATFORM_INFO_SIZE U(8)
+#else
+# define MORELLO_SDS_PLATFORM_INFO_SIZE U(22)
+#endif
+#define MORELLO_MAX_DDR_CAPACITY U(0x1000000000)
+#define MORELLO_MAX_REMOTE_CHIP_COUNT U(16)
+
+#define MORELLO_SCC_SERVER_MODE U(0)
+#define MORELLO_SCC_CLIENT_MODE_MASK U(1)
+#define MORELLO_SCC_C1_TAG_CACHE_EN_MASK U(4)
+#define MORELLO_SCC_C2_TAG_CACHE_EN_MASK U(8)
+
+/* Base address of non-secure SRAM where Platform information will be filled */
+#define MORELLO_PLATFORM_INFO_BASE UL(0x06000000)
+
+/* DMC memory status registers */
+#define MORELLO_DMC0_MEMC_STATUS_REG UL(0x4E000000)
+#define MORELLO_DMC1_MEMC_STATUS_REG UL(0x4E100000)
+
+#define MORELLO_DMC_MEMC_STATUS_MASK U(7)
+
+/* DMC memory command registers */
+#define MORELLO_DMC0_MEMC_CMD_REG UL(0x4E000008)
+#define MORELLO_DMC1_MEMC_CMD_REG UL(0x4E100008)
+
+/* DMC capability control register */
+#define MORELLO_DMC0_CAP_CTRL_REG UL(0x4E000D00)
+#define MORELLO_DMC1_CAP_CTRL_REG UL(0x4E100D00)
+
+/* DMC tag cache control register */
+#define MORELLO_DMC0_TAG_CACHE_CTL UL(0x4E000D04)
+#define MORELLO_DMC1_TAG_CACHE_CTL UL(0x4E100D04)
+
+/* DMC tag cache config register */
+#define MORELLO_DMC0_TAG_CACHE_CFG UL(0x4E000D08)
+#define MORELLO_DMC1_TAG_CACHE_CFG UL(0x4E100D08)
+
+/* DMC memory access control register */
+#define MORELLO_DMC0_MEM_ACCESS_CTL UL(0x4E000D0C)
+#define MORELLO_DMC1_MEM_ACCESS_CTL UL(0x4E100D0C)
+
+#define MORELLO_DMC_MEM_ACCESS_DIS (1UL << 16)
+
+/* DMC memory address control register */
+#define MORELLO_DMC0_MEM_ADDR_CTL UL(0x4E000D10)
+#define MORELLO_DMC1_MEM_ADDR_CTL UL(0x4E100D10)
+
+/* DMC memory address control 2 register */
+#define MORELLO_DMC0_MEM_ADDR_CTL2 UL(0x4E000D14)
+#define MORELLO_DMC1_MEM_ADDR_CTL2 UL(0x4E100D14)
+
+/* DMC special control register */
+#define MORELLO_DMC0_SPL_CTL_REG UL(0x4E000D18)
+#define MORELLO_DMC1_SPL_CTL_REG UL(0x4E100D18)
+
+/* DMC ERR0CTLR0 registers */
+#define MORELLO_DMC0_ERR0CTLR0_REG UL(0x4E000708)
+#define MORELLO_DMC1_ERR0CTLR0_REG UL(0x4E100708)
+
+/* DMC ECC in ERR0CTLR0 register */
+#define MORELLO_DMC_ERR0CTLR0_ECC_EN U(9)
+
+/* DMC ERR2STATUS register */
+#define MORELLO_DMC0_ERR2STATUS_REG UL(0x4E000790)
+#define MORELLO_DMC1_ERR2STATUS_REG UL(0x4E100790)
+
+/* DMC memory commands */
+#define MORELLO_DMC_MEMC_CMD_CONFIG U(0)
+#define MORELLO_DMC_MEMC_CMD_READY U(3)
+
+#endif /* MORELLO_DEF_H */
diff --git a/plat/arm/board/morello/morello_err.c b/plat/arm/board/morello/morello_err.c
new file mode 100644
index 0000000..4d20a09
--- /dev/null
+++ b/plat/arm/board/morello/morello_err.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * morello error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+ while (true) {
+ wfi();
+ }
+}
diff --git a/plat/arm/board/morello/morello_image_load.c b/plat/arm/board/morello/morello_image_load.c
new file mode 100644
index 0000000..52d46f3
--- /dev/null
+++ b/plat/arm/board/morello/morello_image_load.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/arm/css/sds.h>
+#include <libfdt.h>
+
+#include "morello_def.h"
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#ifdef TARGET_PLATFORM_FVP
+/*
+ * Platform information structure stored in SDS.
+ * This structure holds information about platform's DDR
+ * size which is an information about multichip setup
+ * - Local DDR size in bytes, DDR memory in main board
+ */
+struct morello_plat_info {
+ uint64_t local_ddr_size;
+} __packed;
+#else
+/*
+ * Platform information structure stored in SDS.
+ * This structure holds information about platform's DDR
+ * size which is an information about multichip setup
+ * - Local DDR size in bytes, DDR memory in main board
+ * - Remote DDR size in bytes, DDR memory in remote board
+ * - remote_chip_count
+ * - multichip mode
+ * - scc configuration
+ */
+struct morello_plat_info {
+ uint64_t local_ddr_size;
+ uint64_t remote_ddr_size;
+ uint8_t remote_chip_count;
+ bool multichip_mode;
+ uint32_t scc_config;
+} __packed;
+#endif
+
+/* In client mode, a part of the DDR memory is reserved for Tag bits.
+ * Calculate the usable memory size after subtracting the Tag memory.
+ */
+static inline uint64_t get_mem_client_mode(uint64_t size)
+{
+ return (size - (size / 128ULL));
+}
+
+/*******************************************************************************
+ * This function inserts Platform information via device tree nodes as,
+ * platform-info {
+ * local-ddr-size = <0x0 0x0>;
+ *#ifdef TARGET_PLATFORM_SOC
+ * remote-ddr-size = <0x0 0x0>;
+ * remote-chip-count = <0x0>;
+ * multichip-mode = <0x0>;
+ * scc-config = <0x0>;
+ *#endif
+ * };
+ ******************************************************************************/
+static int plat_morello_append_config_node(struct morello_plat_info *plat_info)
+{
+ bl_mem_params_node_t *mem_params;
+ void *fdt;
+ int nodeoffset, err;
+ uint64_t usable_mem_size;
+
+ usable_mem_size = plat_info->local_ddr_size;
+
+ mem_params = get_bl_mem_params_node(NT_FW_CONFIG_ID);
+ if (mem_params == NULL) {
+ ERROR("NT_FW CONFIG base address is NULL\n");
+ 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, "platform-info");
+ if (nodeoffset < 0) {
+ ERROR("NT_FW_CONFIG: Failed to get platform-info node offset\n");
+ return -1;
+ }
+
+#ifdef TARGET_PLATFORM_SOC
+ err = fdt_setprop_u64(fdt, nodeoffset, "remote-ddr-size",
+ plat_info->remote_ddr_size);
+ if (err < 0) {
+ ERROR("NT_FW_CONFIG: Failed to set remote-ddr-size\n");
+ return -1;
+ }
+
+ err = fdt_setprop_u32(fdt, nodeoffset, "remote-chip-count",
+ plat_info->remote_chip_count);
+ if (err < 0) {
+ ERROR("NT_FW_CONFIG: Failed to set remote-chip-count\n");
+ return -1;
+ }
+
+ err = fdt_setprop_u32(fdt, nodeoffset, "multichip-mode",
+ plat_info->multichip_mode);
+ if (err < 0) {
+ ERROR("NT_FW_CONFIG: Failed to set multichip-mode\n");
+ return -1;
+ }
+
+ err = fdt_setprop_u32(fdt, nodeoffset, "scc-config",
+ plat_info->scc_config);
+ if (err < 0) {
+ ERROR("NT_FW_CONFIG: Failed to set scc-config\n");
+ return -1;
+ }
+
+ if (plat_info->scc_config & MORELLO_SCC_CLIENT_MODE_MASK) {
+ usable_mem_size = get_mem_client_mode(plat_info->local_ddr_size);
+ }
+#endif
+ err = fdt_setprop_u64(fdt, nodeoffset, "local-ddr-size",
+ usable_mem_size);
+ if (err < 0) {
+ ERROR("NT_FW_CONFIG: Failed to set local-ddr-size\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;
+ struct morello_plat_info plat_info;
+
+ ret = sds_init();
+ if (ret != SDS_OK) {
+ ERROR("SDS initialization failed. ret:%d\n", ret);
+ panic();
+ }
+
+ ret = sds_struct_read(MORELLO_SDS_PLATFORM_INFO_STRUCT_ID,
+ MORELLO_SDS_PLATFORM_INFO_OFFSET,
+ &plat_info,
+ MORELLO_SDS_PLATFORM_INFO_SIZE,
+ SDS_ACCESS_MODE_NON_CACHED);
+ if (ret != SDS_OK) {
+ ERROR("Error getting platform info from SDS. ret:%d\n", ret);
+ panic();
+ }
+
+ /* Validate plat_info SDS */
+#ifdef TARGET_PLATFORM_FVP
+ if (plat_info.local_ddr_size == 0U) {
+#else
+ if ((plat_info.local_ddr_size == 0U)
+ || (plat_info.local_ddr_size > MORELLO_MAX_DDR_CAPACITY)
+ || (plat_info.remote_ddr_size > MORELLO_MAX_DDR_CAPACITY)
+ || (plat_info.remote_chip_count > MORELLO_MAX_REMOTE_CHIP_COUNT)
+ ){
+#endif
+ ERROR("platform info SDS is corrupted\n");
+ panic();
+ }
+
+ ret = plat_morello_append_config_node(&plat_info);
+ if (ret != 0) {
+ panic();
+ }
+
+ return arm_get_next_bl_params();
+}
diff --git a/plat/arm/board/morello/morello_interconnect.c b/plat/arm/board/morello/morello_interconnect.c
new file mode 100644
index 0000000..d941bfe
--- /dev/null
+++ b/plat/arm/board/morello/morello_interconnect.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+/*
+ * For MORELLO which 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 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)
+{
+}
diff --git a/plat/arm/board/morello/morello_plat.c b/plat/arm/board/morello/morello_plat.c
new file mode 100644
index 0000000..1da0ff9
--- /dev/null
+++ b/plat/arm/board/morello/morello_plat.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <drivers/arm/sbsa.h>
+#include <plat/arm/common/plat_arm.h>
+
+#include "morello_def.h"
+
+/*
+ * Table of regions to map using the MMU.
+ * Replace or extend the below regions as required
+ */
+#if IMAGE_BL1
+const mmap_region_t plat_arm_mmap[] = {
+ ARM_MAP_SHARED_RAM,
+ MORELLO_MAP_DEVICE,
+ MORELLO_MAP_NS_SRAM,
+ ARM_MAP_DRAM1,
+ ARM_MAP_DRAM2,
+ {0}
+};
+#endif
+
+#if IMAGE_BL31
+const mmap_region_t plat_arm_mmap[] = {
+ ARM_MAP_SHARED_RAM,
+ MORELLO_MAP_DEVICE,
+ MORELLO_MAP_NS_SRAM,
+ {0}
+};
+#endif
+
+#if IMAGE_BL2
+const mmap_region_t plat_arm_mmap[] = {
+ ARM_MAP_SHARED_RAM,
+ MORELLO_MAP_DEVICE,
+ MORELLO_MAP_NS_SRAM,
+ ARM_MAP_DRAM1,
+ ARM_MAP_DRAM2,
+#if TRUSTED_BOARD_BOOT && !BL2_AT_EL3
+ ARM_MAP_BL1_RW,
+#endif
+ {0}
+};
+#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 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);
+}
diff --git a/plat/arm/board/morello/morello_security.c b/plat/arm/board/morello/morello_security.c
new file mode 100644
index 0000000..a388a80
--- /dev/null
+++ b/plat/arm/board/morello/morello_security.c
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * TZC programming is currently not done.
+ */
+void plat_arm_security_setup(void)
+{
+}
diff --git a/plat/arm/board/morello/morello_topology.c b/plat/arm/board/morello/morello_topology.c
new file mode 100644
index 0000000..ef2f753
--- /dev/null
+++ b/plat/arm/board/morello/morello_topology.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/cassert.h>
+#include <plat/arm/common/plat_arm.h>
+
+/* Compile time assertion to ensure the core count is 4 */
+CASSERT(PLATFORM_CORE_COUNT == 4U, assert_invalid_platform_core_count);
+
+/* Topology */
+typedef struct morello_topology {
+ const unsigned char *power_tree;
+ unsigned int plat_cluster_core_count;
+} morello_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 morello_pd_tree_desc[] = {
+ PLAT_MORELLO_CHIP_COUNT,
+ PLAT_ARM_CLUSTER_COUNT,
+ MORELLO_MAX_CPUS_PER_CLUSTER,
+ MORELLO_MAX_CPUS_PER_CLUSTER,
+};
+
+/* Topology configuration for morello */
+const morello_topology_t morello_topology = {
+ .power_tree = morello_pd_tree_desc,
+ .plat_cluster_core_count = MORELLO_MAX_CPUS_PER_CLUSTER
+};
+
+/*******************************************************************************
+ * This function returns the topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ return morello_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 morello_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};
diff --git a/plat/arm/board/morello/morello_trusted_boot.c b/plat/arm/board/morello/morello_trusted_boot.c
new file mode 100644
index 0000000..f9bc009
--- /dev/null
+++ b/plat/arm/board/morello/morello_trusted_boot.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * 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)
+{
+ *nv_ctr = MORELLO_FW_NVCTR_VAL;
+
+ 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;
+}
+
+/*
+ * 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)
+{
+ return arm_get_rotpk_info(cookie, key_ptr, key_len, flags);
+}
diff --git a/plat/arm/board/morello/platform.mk b/plat/arm/board/morello/platform.mk
new file mode 100644
index 0000000..156b7ea
--- /dev/null
+++ b/plat/arm/board/morello/platform.mk
@@ -0,0 +1,110 @@
+#
+# Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Making sure the Morello platform type is specified
+ifeq ($(filter ${TARGET_PLATFORM}, fvp soc),)
+ $(error TARGET_PLATFORM must be fvp or soc)
+endif
+
+MORELLO_BASE := plat/arm/board/morello
+
+INTERCONNECT_SOURCES := ${MORELLO_BASE}/morello_interconnect.c
+
+PLAT_INCLUDES := -I${MORELLO_BASE}/include
+
+MORELLO_CPU_SOURCES := lib/cpus/aarch64/rainier.S
+
+# GIC-600 configuration
+GICV3_SUPPORT_GIC600 := 1
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+MORELLO_GIC_SOURCES := ${GICV3_SOURCES} \
+ plat/common/plat_gicv3.c \
+ plat/arm/common/arm_gicv3.c \
+
+PLAT_BL_COMMON_SOURCES := ${MORELLO_BASE}/morello_plat.c \
+ ${MORELLO_BASE}/aarch64/morello_helper.S
+
+BL1_SOURCES := ${MORELLO_CPU_SOURCES} \
+ ${INTERCONNECT_SOURCES} \
+ ${MORELLO_BASE}/morello_err.c \
+ ${MORELLO_BASE}/morello_trusted_boot.c \
+ ${MORELLO_BASE}/morello_bl1_setup.c \
+ drivers/arm/sbsa/sbsa.c
+
+BL2_SOURCES := ${MORELLO_BASE}/morello_security.c \
+ ${MORELLO_BASE}/morello_err.c \
+ ${MORELLO_BASE}/morello_trusted_boot.c \
+ ${MORELLO_BASE}/morello_bl2_setup.c \
+ ${MORELLO_BASE}/morello_image_load.c \
+ lib/utils/mem_region.c \
+ drivers/arm/css/sds/sds.c
+
+BL31_SOURCES := ${MORELLO_CPU_SOURCES} \
+ ${INTERCONNECT_SOURCES} \
+ ${MORELLO_GIC_SOURCES} \
+ ${MORELLO_BASE}/morello_bl31_setup.c \
+ ${MORELLO_BASE}/morello_topology.c \
+ ${MORELLO_BASE}/morello_security.c \
+ drivers/arm/css/sds/sds.c
+
+FDT_SOURCES += fdts/morello-${TARGET_PLATFORM}.dts \
+ ${MORELLO_BASE}/fdts/morello_fw_config.dts \
+ ${MORELLO_BASE}/fdts/morello_tb_fw_config.dts \
+ ${MORELLO_BASE}/fdts/morello_nt_fw_config.dts
+
+FW_CONFIG := ${BUILD_PLAT}/fdts/morello_fw_config.dtb
+TB_FW_CONFIG := ${BUILD_PLAT}/fdts/morello_tb_fw_config.dtb
+NT_FW_CONFIG := ${BUILD_PLAT}/fdts/morello_nt_fw_config.dtb
+
+# Add the FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FW_CONFIG},--fw-config,${FW_CONFIG}))
+# Add the TB_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--tb-fw-config,${TB_FW_CONFIG}))
+# Add the NT_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${NT_FW_CONFIG},--nt-fw-config,${NT_FW_CONFIG}))
+
+MORELLO_FW_NVCTR_VAL := 0
+TFW_NVCTR_VAL := ${MORELLO_FW_NVCTR_VAL}
+NTFW_NVCTR_VAL := ${MORELLO_FW_NVCTR_VAL}
+
+# TF-A not required to load the SCP Images
+override CSS_LOAD_SCP_IMAGES := 0
+
+override NEED_BL2U := no
+
+# 32 bit mode not supported
+override CTX_INCLUDE_AARCH32_REGS := 0
+
+override ARM_PLAT_MT := 1
+
+override ARM_BL31_IN_DRAM := 1
+
+# Errata workarounds:
+ERRATA_N1_1868343 := 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
+
+# Add TARGET_PLATFORM to differentiate between Morello FVP and Morello SoC platform
+$(eval $(call add_define,TARGET_PLATFORM_$(call uppercase,${TARGET_PLATFORM})))
+
+# Add MORELLO_FW_NVCTR_VAL
+$(eval $(call add_define,MORELLO_FW_NVCTR_VAL))
+
+include plat/arm/common/arm_common.mk
+include plat/arm/css/common/css_common.mk
+include plat/arm/board/common/board_common.mk
diff --git a/plat/arm/board/n1sdp/aarch64/n1sdp_helper.S b/plat/arm/board/n1sdp/aarch64/n1sdp_helper.S
new file mode 100644
index 0000000..3da55b6
--- /dev/null
+++ b/plat/arm/board/n1sdp/aarch64/n1sdp_helper.S
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <neoverse_n1.h>
+#include <cpu_macros.S>
+#include <platform_def.h>
+
+ .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.
+ * ((ChipId * N1SDP_MAX_CLUSTERS_PER_CHIP + ClusterId) *
+ * N1SDP_MAX_CPUS_PER_CLUSTER * N1SDP_MAX_PE_PER_CPU) +
+ * (CPUId * N1SDP_MAX_PE_PER_CPU) + ThreadId
+ *
+ * which can be simplified as:
+ *
+ * (((ChipId * N1SDP_MAX_CLUSTERS_PER_CHIP + ClusterId) *
+ * N1SDP_MAX_CPUS_PER_CLUSTER + CPUId) * N1SDP_MAX_PE_PER_CPU) +
+ * ThreadId
+ * ------------------------------------------------------
+ */
+
+func plat_arm_calc_core_pos
+ mov x4, 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, x4, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
+ ubfx x1, x4, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
+ ubfx x2, x4, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
+ ubfx x3, x4, #MPIDR_AFF3_SHIFT, #MPIDR_AFFINITY_BITS
+
+ /* Compute linear position */
+ mov x4, #N1SDP_MAX_CLUSTERS_PER_CHIP
+ madd x2, x3, x4, x2
+ mov x4, #N1SDP_MAX_CPUS_PER_CLUSTER
+ madd x1, x2, x4, x1
+ mov x4, #N1SDP_MAX_PE_PER_CPU
+ madd x0, x1, x4, 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
diff --git a/plat/arm/board/n1sdp/fdts/n1sdp_fw_config.dts b/plat/arm/board/n1sdp/fdts/n1sdp_fw_config.dts
new file mode 100644
index 0000000..700b900
--- /dev/null
+++ b/plat/arm/board/n1sdp/fdts/n1sdp_fw_config.dts
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/tbbr/tbbr_img_def.h>
+
+/dts-v1/;
+/ {
+ dtb-registry {
+ compatible = "fconf,dyn_cfg-dtb_registry";
+ tb_fw-config {
+ load-address = <0x0 0x4001300>;
+ max-size = <0x200>;
+ id = <TB_FW_CONFIG_ID>;
+ };
+ tos_fw-config {
+ load-address = <0x0 0x4001600>;
+ max-size = <0x1000>;
+ id = <TOS_FW_CONFIG_ID>;
+ };
+ nt_fw-config {
+ load-address = <0x0 0xFEF00000>;
+ max-size = <0x0100000>;
+ id = <NT_FW_CONFIG_ID>;
+ };
+ };
+};
diff --git a/plat/arm/board/n1sdp/fdts/n1sdp_nt_fw_config.dts b/plat/arm/board/n1sdp/fdts/n1sdp_nt_fw_config.dts
new file mode 100644
index 0000000..da5e04d
--- /dev/null
+++ b/plat/arm/board/n1sdp/fdts/n1sdp_nt_fw_config.dts
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+/ {
+ /* compatible string */
+ compatible = "arm,n1sdp";
+
+ /*
+ * Place holder for platform-info node with default values.
+ * The values will be set to the correct values during
+ * the BL2 stage of boot.
+ */
+ platform-info {
+ multichip-mode = <0x0>;
+ secondary-chip-count = <0x0>;
+ local-ddr-size = <0x0>;
+ remote-ddr-size = <0x0>;
+ };
+}; \ No newline at end of file
diff --git a/plat/arm/board/n1sdp/fdts/n1sdp_optee_spmc_manifest.dts b/plat/arm/board/n1sdp/fdts/n1sdp_optee_spmc_manifest.dts
new file mode 100644
index 0000000..ed87080
--- /dev/null
+++ b/plat/arm/board/n1sdp/fdts/n1sdp_optee_spmc_manifest.dts
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2022 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/dts-v1/;
+
+/ {
+ compatible = "arm,ffa-core-manifest-1.0";
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ /*
+ * BL32 image details needed by SPMC
+ *
+ * Note:
+ * binary_size: size of BL32 + TOS_FW_CONFIG
+ */
+
+ attribute {
+ spmc_id = <0x8000>;
+ maj_ver = <0x1>;
+ min_ver = <0x0>;
+ exec_state = <0x0>;
+ load_address = <0x0 0x08000000>;
+ entrypoint = <0x0 0x08000000>;
+ binary_size = <0x2000000>;
+ };
+
+};
diff --git a/plat/arm/board/n1sdp/fdts/n1sdp_tb_fw_config.dts b/plat/arm/board/n1sdp/fdts/n1sdp_tb_fw_config.dts
new file mode 100644
index 0000000..e5ffba3
--- /dev/null
+++ b/plat/arm/board/n1sdp/fdts/n1sdp_tb_fw_config.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+/ {
+ tb_fw-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>;
+ };
+};
diff --git a/plat/arm/board/n1sdp/include/plat_macros.S b/plat/arm/board/n1sdp/include/plat_macros.S
new file mode 100644
index 0000000..521bcc3
--- /dev/null
+++ b/plat/arm/board/n1sdp/include/plat_macros.S
@@ -0,0 +1,24 @@
+/*
+ * 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 <css_macros.S>
+
+/* ---------------------------------------------
+ * 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 */
diff --git a/plat/arm/board/n1sdp/include/platform_def.h b/plat/arm/board/n1sdp/include/platform_def.h
new file mode 100644
index 0000000..b3799a7
--- /dev/null
+++ b/plat/arm/board/n1sdp/include/platform_def.h
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/common/arm_def.h>
+#include <plat/arm/css/common/css_def.h>
+
+/* UART related constants */
+#define PLAT_ARM_BOOT_UART_BASE 0x2A400000
+#define PLAT_ARM_BOOT_UART_CLK_IN_HZ 50000000
+
+/* IOFPGA UART0 */
+#define PLAT_ARM_RUN_UART_BASE 0x1C090000
+#define PLAT_ARM_RUN_UART_CLK_IN_HZ 24000000
+
+#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)
+
+#define MAX_IO_DEVICES U(3)
+#define MAX_IO_HANDLES U(4)
+
+#define PLAT_ARM_FLASH_IMAGE_BASE 0x18200000
+#define PLAT_ARM_FLASH_IMAGE_MAX_SIZE 0x00800000
+
+#define PLAT_ARM_NVM_BASE 0x18200000
+#define PLAT_ARM_NVM_SIZE 0x00800000
+
+#if defined NS_BL1U_BASE
+# undef NS_BL1U_BASE
+# define NS_BL1U_BASE (PLAT_ARM_NVM_BASE + UL(0x00800000))
+#endif
+
+/* Non-volatile counters */
+#define SOC_TRUSTED_NVCTR_BASE 0x7fe70000
+#define TFW_NVCTR_BASE (SOC_TRUSTED_NVCTR_BASE)
+#define TFW_NVCTR_SIZE U(4)
+#define NTFW_CTR_BASE (SOC_TRUSTED_NVCTR_BASE + 0x0004)
+#define NTFW_CTR_SIZE U(4)
+
+/* N1SDP remote chip at 4 TB offset */
+#define PLAT_ARM_REMOTE_CHIP_OFFSET (ULL(1) << 42)
+
+#define N1SDP_REMOTE_DRAM1_BASE ARM_DRAM1_BASE + \
+ PLAT_ARM_REMOTE_CHIP_OFFSET
+#define N1SDP_REMOTE_DRAM1_SIZE ARM_DRAM1_SIZE
+
+#define N1SDP_REMOTE_DRAM2_BASE PLAT_ARM_DRAM2_BASE + \
+ PLAT_ARM_REMOTE_CHIP_OFFSET
+#define N1SDP_REMOTE_DRAM2_SIZE PLAT_ARM_DRAM2_SIZE
+
+/*
+ * 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. To access the complete DDR memory
+ * along with remote chip's DDR memory, which is at 4 TB offset, physical
+ * and virtual address space limits are extended to 43-bits.
+ */
+#ifdef __aarch64__
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 43)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 43)
+#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
+
+/*
+ * Trusted SRAM in N1SDP is 512 KB but only the bottom 384 KB
+ * is used for trusted board boot flow. The top 128 KB is used
+ * to load AP-BL1 image.
+ */
+#define PLAT_ARM_TRUSTED_SRAM_SIZE 0x00060000 /* 384 KB */
+
+/*
+ * 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 0xC000
+
+/*
+ * 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 U(0)
+# define PLAT_ARM_MAX_ROMLIB_RO_SIZE U(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 0x22000
+#else
+# define PLAT_ARM_MAX_BL2_SIZE 0x14000
+#endif
+
+#define PLAT_ARM_MAX_BL31_SIZE UL(0x40000)
+
+#define PLAT_ARM_SPMC_BASE U(0x08000000)
+#define PLAT_ARM_SPMC_SIZE UL(0x02000000) /* 32 MB */
+
+
+/*******************************************************************************
+ * N1SDP topology related constants
+ ******************************************************************************/
+#define N1SDP_MAX_CPUS_PER_CLUSTER U(2)
+#define PLAT_ARM_CLUSTER_COUNT U(2)
+#define PLAT_N1SDP_CHIP_COUNT U(2)
+#define N1SDP_MAX_CLUSTERS_PER_CHIP U(2)
+#define N1SDP_MAX_PE_PER_CPU U(1)
+
+#define PLATFORM_CORE_COUNT (PLAT_N1SDP_CHIP_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_LVL3
+
+/*
+ * 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 U(6)
+# define MAX_XLAT_TABLES U(5)
+#endif
+
+#ifdef IMAGE_BL2
+# define PLAT_ARM_MMAP_ENTRIES U(11)
+# define MAX_XLAT_TABLES U(10)
+#endif
+
+#ifdef IMAGE_BL31
+# define PLAT_ARM_MMAP_ENTRIES U(12)
+# define MAX_XLAT_TABLES U(12)
+#endif
+
+/*
+ * 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 SPM_MM
+# 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_CSS_MHU_BASE 0x45000000
+#define PLAT_MAX_PWR_LVL 2
+
+#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 ULL(0x08000000)
+#define N1SDP_DEVICE_SIZE ULL(0x48000000)
+#define N1SDP_REMOTE_DEVICE_BASE N1SDP_DEVICE_BASE + \
+ PLAT_ARM_REMOTE_CHIP_OFFSET
+#define N1SDP_REMOTE_DEVICE_SIZE N1SDP_DEVICE_SIZE
+
+/* Real base is 0x0. Changed to load BL1 at this address */
+# define PLAT_ARM_TRUSTED_ROM_BASE 0x04060000
+# define PLAT_ARM_TRUSTED_ROM_SIZE 0x00020000 /* 128KB */
+
+#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)
+
+#define N1SDP_MAP_REMOTE_DEVICE MAP_REGION_FLAT( \
+ N1SDP_REMOTE_DEVICE_BASE, \
+ N1SDP_REMOTE_DEVICE_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+#define N1SDP_MAP_REMOTE_DRAM1 MAP_REGION_FLAT( \
+ N1SDP_REMOTE_DRAM1_BASE, \
+ N1SDP_REMOTE_DRAM1_SIZE, \
+ MT_MEMORY | MT_RW | MT_NS)
+
+#define N1SDP_MAP_REMOTE_DRAM2 MAP_REGION_FLAT( \
+ N1SDP_REMOTE_DRAM2_BASE, \
+ N1SDP_REMOTE_DRAM2_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)
+
+/* Number of SCMI channels on the platform */
+#define PLAT_ARM_SCMI_CHANNEL_COUNT U(1)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/n1sdp/n1sdp_bl1_setup.c b/plat/arm/board/n1sdp/n1sdp_bl1_setup.c
new file mode 100644
index 0000000..ed93222
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_bl1_setup.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*******************************************************************************
+ * Perform any BL1 specific platform actions.
+ ******************************************************************************/
+
+void soc_css_init_nic400(void)
+{
+}
+
+void soc_css_init_pcie(void)
+{
+}
diff --git a/plat/arm/board/n1sdp/n1sdp_bl2_setup.c b/plat/arm/board/n1sdp/n1sdp_bl2_setup.c
new file mode 100644
index 0000000..5f8af9f
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_bl2_setup.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/arm/css/sds.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+
+#include "n1sdp_def.h"
+#include <plat/arm/common/plat_arm.h>
+
+struct n1sdp_plat_info {
+ bool multichip_mode;
+ uint8_t secondary_count;
+ uint8_t local_ddr_size;
+ uint8_t remote_ddr_size;
+} __packed;
+
+/*
+ * 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.
+ */
+
+void dmc_ecc_setup(uint8_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 bl2_platform_setup(void)
+{
+ int ret;
+ struct n1sdp_plat_info plat_info;
+
+ ret = sds_init();
+ if (ret != SDS_OK) {
+ ERROR("SDS initialization failed\n");
+ panic();
+ }
+
+ ret = sds_struct_read(N1SDP_SDS_PLATFORM_INFO_STRUCT_ID,
+ N1SDP_SDS_PLATFORM_INFO_OFFSET,
+ &plat_info,
+ N1SDP_SDS_PLATFORM_INFO_SIZE,
+ SDS_ACCESS_MODE_NON_CACHED);
+ if (ret != SDS_OK) {
+ ERROR("Error getting platform info from SDS\n");
+ panic();
+ }
+ /* Validate plat_info SDS */
+ if ((plat_info.local_ddr_size == 0)
+ || (plat_info.local_ddr_size > N1SDP_MAX_DDR_CAPACITY_GB)
+ || (plat_info.remote_ddr_size > N1SDP_MAX_DDR_CAPACITY_GB)
+ || (plat_info.secondary_count > N1SDP_MAX_SECONDARY_COUNT)) {
+ ERROR("platform info SDS is corrupted\n");
+ panic();
+ }
+
+ dmc_ecc_setup(plat_info.local_ddr_size);
+ arm_bl2_platform_setup();
+}
diff --git a/plat/arm/board/n1sdp/n1sdp_bl31_setup.c b/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
new file mode 100644
index 0000000..5e897fe
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/arm/css/css_mhu_doorbell.h>
+#include <drivers/arm/css/scmi.h>
+#include <drivers/arm/css/sds.h>
+#include <drivers/arm/gic600_multichip.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <plat/arm/common/plat_arm.h>
+
+#include "n1sdp_def.h"
+#include <platform_def.h>
+
+/*
+ * Platform information structure stored in SDS.
+ * This structure holds information about platform's DDR
+ * size which will be used to zero out the memory before
+ * enabling the ECC capability as well as information
+ * about multichip setup
+ * - multichip mode
+ * - secondary_count
+ * - Local DDR size in GB, DDR memory in master board
+ * - Remote DDR size in GB, DDR memory in secondary board
+ */
+struct n1sdp_plat_info {
+ bool multichip_mode;
+ uint8_t secondary_count;
+ uint8_t local_ddr_size;
+ uint8_t remote_ddr_size;
+} __packed;
+
+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
+};
+
+static struct gic600_multichip_data n1sdp_multichip_data __init = {
+ .rt_owner_base = PLAT_ARM_GICD_BASE,
+ .rt_owner = 0,
+ .chip_count = 1,
+ .chip_addrs = {
+ PLAT_ARM_GICD_BASE >> 16,
+ PLAT_ARM_GICD_BASE >> 16
+ },
+ .spi_ids = {
+ {32, 479},
+ {512, 959}
+ }
+};
+
+static uintptr_t n1sdp_multichip_gicr_frames[3] = {
+ PLAT_ARM_GICR_BASE,
+ PLAT_ARM_GICR_BASE + PLAT_ARM_REMOTE_CHIP_OFFSET,
+ 0
+};
+
+scmi_channel_plat_info_t *plat_css_get_scmi_info(int channel_id)
+{
+ 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. Local DDR memory is zeroed out during BL2
+ * stage. If remote chip is connected, it's DDR memory is zeroed out here.
+ */
+
+void remote_dmc_ecc_setup(uint8_t remote_ddr_size)
+{
+ uint64_t remote_dram2_size;
+
+ remote_dram2_size = (remote_ddr_size * 1024UL * 1024UL * 1024UL) -
+ N1SDP_REMOTE_DRAM1_SIZE;
+ /* multichip setup */
+ INFO("Zeroing remote DDR memories\n");
+ zero_normalmem((void *)N1SDP_REMOTE_DRAM1_BASE,
+ N1SDP_REMOTE_DRAM1_SIZE);
+ flush_dcache_range(N1SDP_REMOTE_DRAM1_BASE, N1SDP_REMOTE_DRAM1_SIZE);
+ zero_normalmem((void *)N1SDP_REMOTE_DRAM2_BASE, remote_dram2_size);
+ flush_dcache_range(N1SDP_REMOTE_DRAM2_BASE, remote_dram2_size);
+
+ INFO("Enabling ECC on remote DMCs\n");
+ /* Set DMCs to CONFIG state before writing ERR0CTLR0 register */
+ mmio_write_32(N1SDP_REMOTE_DMC0_MEMC_CMD_REG,
+ N1SDP_DMC_MEMC_CMD_CONFIG);
+ mmio_write_32(N1SDP_REMOTE_DMC1_MEMC_CMD_REG,
+ N1SDP_DMC_MEMC_CMD_CONFIG);
+
+ /* Enable ECC in DMCs */
+ mmio_setbits_32(N1SDP_REMOTE_DMC0_ERR0CTLR0_REG,
+ N1SDP_DMC_ERR0CTLR0_ECC_EN);
+ mmio_setbits_32(N1SDP_REMOTE_DMC1_ERR0CTLR0_REG,
+ N1SDP_DMC_ERR0CTLR0_ECC_EN);
+
+ /* Set DMCs to READY state */
+ mmio_write_32(N1SDP_REMOTE_DMC0_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_READY);
+ mmio_write_32(N1SDP_REMOTE_DMC1_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_READY);
+}
+
+void n1sdp_bl31_multichip_setup(void)
+{
+ plat_arm_override_gicr_frames(n1sdp_multichip_gicr_frames);
+ gic600_multichip_init(&n1sdp_multichip_data);
+}
+
+void bl31_platform_setup(void)
+{
+ int ret;
+ struct n1sdp_plat_info plat_info;
+
+ ret = sds_init();
+ if (ret != SDS_OK) {
+ ERROR("SDS initialization failed\n");
+ panic();
+ }
+
+ ret = sds_struct_read(N1SDP_SDS_PLATFORM_INFO_STRUCT_ID,
+ N1SDP_SDS_PLATFORM_INFO_OFFSET,
+ &plat_info,
+ N1SDP_SDS_PLATFORM_INFO_SIZE,
+ SDS_ACCESS_MODE_NON_CACHED);
+ if (ret != SDS_OK) {
+ ERROR("Error getting platform info from SDS\n");
+ panic();
+ }
+ /* Validate plat_info SDS */
+ if ((plat_info.local_ddr_size == 0)
+ || (plat_info.local_ddr_size > N1SDP_MAX_DDR_CAPACITY_GB)
+ || (plat_info.remote_ddr_size > N1SDP_MAX_DDR_CAPACITY_GB)
+ || (plat_info.secondary_count > N1SDP_MAX_SECONDARY_COUNT)) {
+ ERROR("platform info SDS is corrupted\n");
+ panic();
+ }
+
+ if (plat_info.multichip_mode) {
+ n1sdp_multichip_data.chip_count = plat_info.secondary_count + 1;
+ n1sdp_bl31_multichip_setup();
+ }
+ arm_bl31_platform_setup();
+
+ /* Check if remote memory is present */
+ if ((plat_info.multichip_mode) && (plat_info.remote_ddr_size != 0))
+ remote_dmc_ecc_setup(plat_info.remote_ddr_size);
+}
diff --git a/plat/arm/board/n1sdp/n1sdp_def.h b/plat/arm/board/n1sdp/n1sdp_def.h
new file mode 100644
index 0000000..ffa6a03
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_def.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018-2022, Arm Limited. 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 Platform information defines */
+#define N1SDP_SDS_PLATFORM_INFO_STRUCT_ID 8
+#define N1SDP_SDS_PLATFORM_INFO_OFFSET 0
+#define N1SDP_SDS_PLATFORM_INFO_SIZE 4
+#define N1SDP_MAX_DDR_CAPACITY_GB 64
+#define N1SDP_MAX_SECONDARY_COUNT 16
+
+/* 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
+
+/* Remote DMC memory command registers */
+#define N1SDP_REMOTE_DMC0_MEMC_CMD_REG PLAT_ARM_REMOTE_CHIP_OFFSET +\
+ N1SDP_DMC0_MEMC_CMD_REG
+#define N1SDP_REMOTE_DMC1_MEMC_CMD_REG PLAT_ARM_REMOTE_CHIP_OFFSET +\
+ N1SDP_DMC1_MEMC_CMD_REG
+
+/* Remote DMC ERR0CTLR0 registers */
+#define N1SDP_REMOTE_DMC0_ERR0CTLR0_REG PLAT_ARM_REMOTE_CHIP_OFFSET +\
+ N1SDP_DMC0_ERR0CTLR0_REG
+#define N1SDP_REMOTE_DMC1_ERR0CTLR0_REG PLAT_ARM_REMOTE_CHIP_OFFSET +\
+ N1SDP_DMC1_ERR0CTLR0_REG
+
+/* 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
+
+#endif /* N1SDP_DEF_H */
diff --git a/plat/arm/board/n1sdp/n1sdp_err.c b/plat/arm/board/n1sdp/n1sdp_err.c
new file mode 100644
index 0000000..629e76a
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_err.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * n1sdp error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+ while (true) {
+ wfi();
+ }
+}
diff --git a/plat/arm/board/n1sdp/n1sdp_image_load.c b/plat/arm/board/n1sdp/n1sdp_image_load.c
new file mode 100644
index 0000000..6c3528c
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_image_load.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/arm/css/sds.h>
+#include <libfdt.h>
+#include <plat/common/platform.h>
+
+#include "n1sdp_def.h"
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * Platform information structure stored in SDS.
+ * This structure holds information about platform's DDR
+ * size which will be used to zero out the memory before
+ * enabling the ECC capability as well as information
+ * about multichip setup
+ * - multichip mode
+ * - secondary_count
+ * - Local DDR size in GB, DDR memory in master board
+ * - Remote DDR size in GB, DDR memory in secondary board
+ */
+struct n1sdp_plat_info {
+ bool multichip_mode;
+ uint8_t secondary_count;
+ uint8_t local_ddr_size;
+ uint8_t remote_ddr_size;
+} __packed;
+
+/*******************************************************************************
+ * This function inserts Platform information via device tree nodes as,
+ * platform-info {
+ * multichip-mode = <0x0>;
+ * secondary-chip-count = <0x0>;
+ * local-ddr-size = <0x0>;
+ * remote-ddr-size = <0x0>;
+ * };
+ ******************************************************************************/
+static int plat_n1sdp_append_config_node(struct n1sdp_plat_info *plat_info)
+{
+ bl_mem_params_node_t *mem_params;
+ void *fdt;
+ int nodeoffset, err;
+
+ mem_params = get_bl_mem_params_node(NT_FW_CONFIG_ID);
+ if (mem_params == NULL) {
+ ERROR("NT_FW CONFIG base address is NULL\n");
+ 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, "platform-info");
+ if (nodeoffset < 0) {
+ ERROR("NT_FW_CONFIG: Failed to get platform-info node offset\n");
+ return -1;
+ }
+
+ err = fdt_setprop_u32(fdt, nodeoffset, "multichip-mode",
+ plat_info->multichip_mode);
+ if (err < 0) {
+ ERROR("NT_FW_CONFIG: Failed to set multichip-mode\n");
+ return -1;
+ }
+
+ err = fdt_setprop_u32(fdt, nodeoffset, "secondary-chip-count",
+ plat_info->secondary_count);
+ if (err < 0) {
+ ERROR("NT_FW_CONFIG: Failed to set secondary-chip-count\n");
+ return -1;
+ }
+
+ err = fdt_setprop_u32(fdt, nodeoffset, "local-ddr-size",
+ plat_info->local_ddr_size);
+ if (err < 0) {
+ ERROR("NT_FW_CONFIG: Failed to set local-ddr-size\n");
+ return -1;
+ }
+
+ err = fdt_setprop_u32(fdt, nodeoffset, "remote-ddr-size",
+ plat_info->remote_ddr_size);
+ if (err < 0) {
+ ERROR("NT_FW_CONFIG: Failed to set remote-ddr-size\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;
+ struct n1sdp_plat_info plat_info;
+
+ ret = sds_init();
+ if (ret != SDS_OK) {
+ ERROR("SDS initialization failed. ret:%d\n", ret);
+ panic();
+ }
+
+ ret = sds_struct_read(N1SDP_SDS_PLATFORM_INFO_STRUCT_ID,
+ N1SDP_SDS_PLATFORM_INFO_OFFSET,
+ &plat_info,
+ N1SDP_SDS_PLATFORM_INFO_SIZE,
+ SDS_ACCESS_MODE_NON_CACHED);
+ if (ret != SDS_OK) {
+ ERROR("Error getting platform info from SDS. ret:%d\n", ret);
+ panic();
+ }
+
+ /* Validate plat_info SDS */
+ if ((plat_info.local_ddr_size == 0U)
+ || (plat_info.local_ddr_size > N1SDP_MAX_DDR_CAPACITY_GB)
+ || (plat_info.remote_ddr_size > N1SDP_MAX_DDR_CAPACITY_GB)
+ || (plat_info.secondary_count > N1SDP_MAX_SECONDARY_COUNT)
+ ){
+ ERROR("platform info SDS is corrupted\n");
+ panic();
+ }
+
+ ret = plat_n1sdp_append_config_node(&plat_info);
+ if (ret != 0) {
+ panic();
+ }
+
+ return arm_get_next_bl_params();
+}
diff --git a/plat/arm/board/n1sdp/n1sdp_interconnect.c b/plat/arm/board/n1sdp/n1sdp_interconnect.c
new file mode 100644
index 0000000..908f41c
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_interconnect.c
@@ -0,0 +1,33 @@
+/*
+ * 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)
+{
+}
diff --git a/plat/arm/board/n1sdp/n1sdp_plat.c b/plat/arm/board/n1sdp/n1sdp_plat.c
new file mode 100644
index 0000000..502268c
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_plat.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <drivers/arm/sbsa.h>
+#include <plat/arm/common/plat_arm.h>
+
+#include "n1sdp_def.h"
+
+/*
+ * Table of regions to map using the MMU.
+ * Replace or extend the below regions as required
+ */
+
+#if IMAGE_BL1
+const mmap_region_t plat_arm_mmap[] = {
+ ARM_MAP_SHARED_RAM,
+ N1SDP_MAP_DEVICE,
+ N1SDP_MAP_NS_SRAM,
+ ARM_MAP_DRAM1,
+ {0}
+};
+#endif
+
+#if IMAGE_BL2
+const mmap_region_t plat_arm_mmap[] = {
+ ARM_MAP_SHARED_RAM,
+ N1SDP_MAP_DEVICE,
+ N1SDP_MAP_NS_SRAM,
+ ARM_MAP_DRAM1,
+ ARM_MAP_DRAM2,
+#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,
+ N1SDP_MAP_DEVICE,
+ N1SDP_MAP_NS_SRAM,
+ N1SDP_MAP_REMOTE_DEVICE,
+ N1SDP_MAP_REMOTE_DRAM1,
+ N1SDP_MAP_REMOTE_DRAM2,
+ {0}
+};
+#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 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);
+}
diff --git a/plat/arm/board/n1sdp/n1sdp_security.c b/plat/arm/board/n1sdp/n1sdp_security.c
new file mode 100644
index 0000000..d2a187b
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_security.c
@@ -0,0 +1,12 @@
+/*
+ * 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)
+{
+}
diff --git a/plat/arm/board/n1sdp/n1sdp_topology.c b/plat/arm/board/n1sdp/n1sdp_topology.c
new file mode 100644
index 0000000..5c2db71
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_topology.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/* 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_N1SDP_CHIP_COUNT,
+ PLAT_ARM_CLUSTER_COUNT,
+ PLAT_ARM_CLUSTER_COUNT,
+ N1SDP_MAX_CPUS_PER_CLUSTER,
+ N1SDP_MAX_CPUS_PER_CLUSTER,
+ 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, 4, 5, 6, 7};
diff --git a/plat/arm/board/n1sdp/n1sdp_trusted_boot.c b/plat/arm/board/n1sdp/n1sdp_trusted_boot.c
new file mode 100644
index 0000000..c7dc47f
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_trusted_boot.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * 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)
+{
+ *nv_ctr = N1SDP_FW_NVCTR_VAL;
+ 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;
+}
+
+/*
+ * 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)
+{
+ return arm_get_rotpk_info(cookie, key_ptr, key_len, flags);
+}
+
diff --git a/plat/arm/board/n1sdp/platform.mk b/plat/arm/board/n1sdp/platform.mk
new file mode 100644
index 0000000..9c0cc02
--- /dev/null
+++ b/plat/arm/board/n1sdp/platform.mk
@@ -0,0 +1,111 @@
+#
+# Copyright (c) 2018-2022, Arm Limited. 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
+
+# GIC-600 configuration
+GICV3_SUPPORT_GIC600 := 1
+GICV3_IMPL_GIC600_MULTICHIP := 1
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+N1SDP_GIC_SOURCES := ${GICV3_SOURCES} \
+ plat/common/plat_gicv3.c \
+ plat/arm/common/arm_gicv3.c \
+
+PLAT_BL_COMMON_SOURCES := ${N1SDP_BASE}/n1sdp_plat.c \
+ ${N1SDP_BASE}/aarch64/n1sdp_helper.S
+
+BL1_SOURCES := ${N1SDP_CPU_SOURCES} \
+ ${INTERCONNECT_SOURCES} \
+ ${N1SDP_BASE}/n1sdp_err.c \
+ ${N1SDP_BASE}/n1sdp_trusted_boot.c \
+ ${N1SDP_BASE}/n1sdp_bl1_setup.c \
+ drivers/arm/sbsa/sbsa.c
+
+BL2_SOURCES := ${N1SDP_BASE}/n1sdp_security.c \
+ ${N1SDP_BASE}/n1sdp_err.c \
+ ${N1SDP_BASE}/n1sdp_trusted_boot.c \
+ lib/utils/mem_region.c \
+ ${N1SDP_BASE}/n1sdp_bl2_setup.c \
+ ${N1SDP_BASE}/n1sdp_image_load.c \
+ drivers/arm/css/sds/sds.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
+
+FDT_SOURCES += fdts/${PLAT}-single-chip.dts \
+ fdts/${PLAT}-multi-chip.dts \
+ ${N1SDP_BASE}/fdts/n1sdp_fw_config.dts \
+ ${N1SDP_BASE}/fdts/n1sdp_tb_fw_config.dts \
+ ${N1SDP_BASE}/fdts/n1sdp_nt_fw_config.dts
+
+FW_CONFIG := ${BUILD_PLAT}/fdts/n1sdp_fw_config.dtb
+TB_FW_CONFIG := ${BUILD_PLAT}/fdts/n1sdp_tb_fw_config.dtb
+NT_FW_CONFIG := ${BUILD_PLAT}/fdts/n1sdp_nt_fw_config.dtb
+
+# Add the FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FW_CONFIG},--fw-config,${FW_CONFIG}))
+# Add the TB_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--tb-fw-config,${TB_FW_CONFIG}))
+# Add the NT_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${NT_FW_CONFIG},--nt-fw-config,${NT_FW_CONFIG}))
+
+N1SDP_SPMC_MANIFEST_DTS := ${N1SDP_BASE}/fdts/${PLAT}_optee_spmc_manifest.dts
+FDT_SOURCES += ${N1SDP_SPMC_MANIFEST_DTS}
+N1SDP_TOS_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_optee_spmc_manifest.dtb
+
+# Add the TOS_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${N1SDP_TOS_FW_CONFIG},--tos-fw-config,${N1SDP_TOS_FW_CONFIG}))
+
+# Setting to 0 as no NVCTR in N1SDP
+N1SDP_FW_NVCTR_VAL := 0
+TFW_NVCTR_VAL := ${N1SDP_FW_NVCTR_VAL}
+NTFW_NVCTR_VAL := ${N1SDP_FW_NVCTR_VAL}
+
+# Add N1SDP_FW_NVCTR_VAL
+$(eval $(call add_define,N1SDP_FW_NVCTR_VAL))
+
+# TF-A not required to load the SCP Images
+override CSS_LOAD_SCP_IMAGES := 0
+
+override NEED_BL2U := no
+
+# 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
+
+# Enable the flag since N1SDP has a system level cache
+NEOVERSE_Nx_EXTERNAL_LLC := 1
+include plat/arm/common/arm_common.mk
+include plat/arm/css/common/css_common.mk
+include plat/arm/board/common/board_common.mk
diff --git a/plat/arm/board/rde1edge/fdts/rde1edge_fw_config.dts b/plat/arm/board/rde1edge/fdts/rde1edge_fw_config.dts
new file mode 100644
index 0000000..69fb0d4
--- /dev/null
+++ b/plat/arm/board/rde1edge/fdts/rde1edge_fw_config.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/tbbr/tbbr_img_def.h>
+
+/dts-v1/;
+
+/ {
+ dtb-registry {
+ compatible = "fconf,dyn_cfg-dtb_registry";
+
+ tb_fw-config {
+ load-address = <0x0 0x4001300>;
+ max-size = <0x200>;
+ id = <TB_FW_CONFIG_ID>;
+ };
+
+ nt_fw-config {
+ load-address = <0x0 0xFEF00000>;
+ max-size = <0x0100000>;
+ id = <NT_FW_CONFIG_ID>;
+ };
+ };
+};
diff --git a/plat/arm/board/rde1edge/fdts/rde1edge_nt_fw_config.dts b/plat/arm/board/rde1edge/fdts/rde1edge_nt_fw_config.dts
new file mode 100644
index 0000000..0af821e
--- /dev/null
+++ b/plat/arm/board/rde1edge/fdts/rde1edge_nt_fw_config.dts
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018-2020, 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>;
+ multi-chip-mode = <0x0>;
+ };
+
+};
diff --git a/plat/arm/board/rde1edge/fdts/rde1edge_tb_fw_config.dts b/plat/arm/board/rde1edge/fdts/rde1edge_tb_fw_config.dts
new file mode 100644
index 0000000..dba91e5
--- /dev/null
+++ b/plat/arm/board/rde1edge/fdts/rde1edge_tb_fw_config.dts
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2020, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+ tb_fw-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>;
+ };
+};
diff --git a/plat/arm/board/rde1edge/include/platform_def.h b/plat/arm/board/rde1edge/include/platform_def.h
new file mode 100644
index 0000000..69bfd7b
--- /dev/null
+++ b/plat/arm/board/rde1edge/include/platform_def.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+
+#include <sgi_sdei.h>
+#include <sgi_soc_platform_def.h>
+
+#define PLAT_ARM_CLUSTER_COUNT U(2)
+#define CSS_SGI_MAX_CPUS_PER_CLUSTER U(8)
+#define CSS_SGI_MAX_PE_PER_CPU U(2)
+
+#define PLAT_CSS_MHU_BASE UL(0x45400000)
+
+/* 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
+
+/* Maximum number of address bits used per chip */
+#define CSS_SGI_ADDR_BITS_PER_CHIP U(36)
+
+/*
+ * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
+ */
+#ifdef __aarch64__
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << CSS_SGI_ADDR_BITS_PER_CHIP)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << CSS_SGI_ADDR_BITS_PER_CHIP)
+#else
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
+#endif
+
+/* GIC related constants */
+#define PLAT_ARM_GICD_BASE UL(0x30000000)
+#define PLAT_ARM_GICC_BASE UL(0x2C000000)
+#define PLAT_ARM_GICR_BASE UL(0x300C0000)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/rde1edge/platform.mk b/plat/arm/board/rde1edge/platform.mk
new file mode 100644
index 0000000..0f9dd49
--- /dev/null
+++ b/plat/arm/board/rde1edge/platform.mk
@@ -0,0 +1,66 @@
+#
+# Copyright (c) 2018-2020, 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
+
+PLAT_BL_COMMON_SOURCES += ${CSS_ENT_BASE}/sgi_plat.c
+
+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 \
+ ${RDE1EDGE_BASE}/rde1edge_topology.c \
+ drivers/cfi/v2m/v2m_flash.c \
+ lib/utils/mem_region.c \
+ plat/arm/common/arm_nor_psci_mem_protect.c
+
+ifeq (${TRUSTED_BOARD_BOOT}, 1)
+BL1_SOURCES += ${RDE1EDGE_BASE}/rde1edge_trusted_boot.c
+BL2_SOURCES += ${RDE1EDGE_BASE}/rde1edge_trusted_boot.c
+endif
+
+# Add the FDT_SOURCES and options for Dynamic Config
+FDT_SOURCES += ${RDE1EDGE_BASE}/fdts/${PLAT}_fw_config.dts \
+ ${RDE1EDGE_BASE}/fdts/${PLAT}_tb_fw_config.dts
+FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_fw_config.dtb
+TB_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb
+
+# Add the FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FW_CONFIG},--fw-config,${FW_CONFIG}))
+# Add the TB_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--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,${NT_FW_CONFIG}))
+
+ifneq ($(CSS_SGI_CHIP_COUNT),1)
+ $(error "Chip count for RDE1Edge should be 1, currently set to \
+ ${CSS_SGI_CHIP_COUNT}.")
+endif
+
+ifneq ($(CSS_SGI_PLATFORM_VARIANT),0)
+ $(error "CSS_SGI_PLATFORM_VARIANT for RD-E1-Edge should always be 0, \
+ currently set to ${CSS_SGI_PLATFORM_VARIANT}.")
+endif
+
+override CTX_INCLUDE_AARCH32_REGS := 0
diff --git a/plat/arm/board/rde1edge/rde1edge_err.c b/plat/arm/board/rde1edge/rde1edge_err.c
new file mode 100644
index 0000000..c72c18c
--- /dev/null
+++ b/plat/arm/board/rde1edge/rde1edge_err.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * rde1edge error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+ while (true) {
+ wfi();
+ }
+}
diff --git a/plat/arm/board/rde1edge/rde1edge_plat.c b/plat/arm/board/rde1edge/rde1edge_plat.c
new file mode 100644
index 0000000..44d818a
--- /dev/null
+++ b/plat/arm/board/rde1edge/rde1edge_plat.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+#include <sgi_plat.h>
+
+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);
+}
+
+unsigned int plat_arm_sgi_get_multi_chip_mode(void)
+{
+ return 0;
+}
+
+void bl31_platform_setup(void)
+{
+ sgi_bl31_common_platform_setup();
+}
diff --git a/plat/arm/board/rde1edge/rde1edge_security.c b/plat/arm/board/rde1edge/rde1edge_security.c
new file mode 100644
index 0000000..35f81d1
--- /dev/null
+++ b/plat/arm/board/rde1edge/rde1edge_security.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <sgi_dmc620_tzc_regions.h>
+
+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[] = {
+ CSS_SGI_DMC620_TZC_REGIONS_DEF
+};
+
+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);
+}
diff --git a/plat/arm/board/rde1edge/rde1edge_topology.c b/plat/arm/board/rde1edge/rde1edge_topology.c
new file mode 100644
index 0000000..a16283e
--- /dev/null
+++ b/plat/arm/board/rde1edge/rde1edge_topology.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/******************************************************************************
+ * The power domain tree descriptor. RD-E1-Edge platform consists of two
+ * clusters with eight CPUs in each cluster. The CPUs are multi-threaded with
+ * two threads per CPU.
+ ******************************************************************************/
+static const unsigned char rde1edge_pd_tree_desc[] = {
+ CSS_SGI_CHIP_COUNT,
+ PLAT_ARM_CLUSTER_COUNT,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER * CSS_SGI_MAX_PE_PER_CPU,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER * CSS_SGI_MAX_PE_PER_CPU
+};
+
+/******************************************************************************
+ * This function returns the topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ return rde1edge_pd_tree_desc;
+}
+
+/*******************************************************************************
+ * 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[] = {
+ 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
+};
diff --git a/plat/arm/board/rde1edge/rde1edge_trusted_boot.c b/plat/arm/board/rde1edge/rde1edge_trusted_boot.c
new file mode 100644
index 0000000..4592b8f
--- /dev/null
+++ b/plat/arm/board/rde1edge/rde1edge_trusted_boot.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * 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)
+{
+ return arm_get_rotpk_info(cookie, key_ptr, key_len, flags);
+}
diff --git a/plat/arm/board/rdn1edge/fdts/rdn1edge_fw_config.dts b/plat/arm/board/rdn1edge/fdts/rdn1edge_fw_config.dts
new file mode 100644
index 0000000..d3b7fba
--- /dev/null
+++ b/plat/arm/board/rdn1edge/fdts/rdn1edge_fw_config.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/tbbr/tbbr_img_def.h>
+
+/dts-v1/;
+/ {
+ dtb-registry {
+ compatible = "fconf,dyn_cfg-dtb_registry";
+
+ tb_fw-config {
+ load-address = <0x0 0x4001300>;
+ max-size = <0x200>;
+ id = <TB_FW_CONFIG_ID>;
+ };
+
+ nt_fw-config {
+ load-address = <0x0 0xFEF00000>;
+ max-size = <0x0100000>;
+ id = <NT_FW_CONFIG_ID>;
+ };
+ };
+};
+
diff --git a/plat/arm/board/rdn1edge/fdts/rdn1edge_nt_fw_config.dts b/plat/arm/board/rdn1edge/fdts/rdn1edge_nt_fw_config.dts
new file mode 100644
index 0000000..68366c5
--- /dev/null
+++ b/plat/arm/board/rdn1edge/fdts/rdn1edge_nt_fw_config.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018-2020, 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>;
+ multi-chip-mode = <0x0>;
+ };
+};
diff --git a/plat/arm/board/rdn1edge/fdts/rdn1edge_tb_fw_config.dts b/plat/arm/board/rdn1edge/fdts/rdn1edge_tb_fw_config.dts
new file mode 100644
index 0000000..257ef4a
--- /dev/null
+++ b/plat/arm/board/rdn1edge/fdts/rdn1edge_tb_fw_config.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+/ {
+ tb_fw-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>;
+ };
+};
diff --git a/plat/arm/board/rdn1edge/include/platform_def.h b/plat/arm/board/rdn1edge/include/platform_def.h
new file mode 100644
index 0000000..de01902
--- /dev/null
+++ b/plat/arm/board/rdn1edge/include/platform_def.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+
+#include <sgi_sdei.h>
+#include <sgi_soc_platform_def.h>
+
+#define PLAT_ARM_CLUSTER_COUNT U(2)
+#define CSS_SGI_MAX_CPUS_PER_CLUSTER U(4)
+#define CSS_SGI_MAX_PE_PER_CPU U(1)
+
+#define PLAT_CSS_MHU_BASE UL(0x45400000)
+
+/* 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
+
+/* Virtual address used by dynamic mem_protect for chunk_base */
+#define PLAT_ARM_MEM_PROTEC_VA_FRAME UL(0xc0000000)
+
+/* Maximum number of address bits used per chip */
+#define CSS_SGI_ADDR_BITS_PER_CHIP U(42)
+
+/*
+ * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
+ */
+#ifdef __aarch64__
+#define PLAT_PHY_ADDR_SPACE_SIZE CSS_SGI_REMOTE_CHIP_MEM_OFFSET( \
+ CSS_SGI_CHIP_COUNT)
+#define PLAT_VIRT_ADDR_SPACE_SIZE CSS_SGI_REMOTE_CHIP_MEM_OFFSET( \
+ CSS_SGI_CHIP_COUNT)
+#else
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
+#endif
+
+/* GIC related constants */
+#define PLAT_ARM_GICD_BASE UL(0x30000000)
+#define PLAT_ARM_GICC_BASE UL(0x2C000000)
+#define PLAT_ARM_GICR_BASE UL(0x300C0000)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/rdn1edge/platform.mk b/plat/arm/board/rdn1edge/platform.mk
new file mode 100644
index 0000000..95753aa
--- /dev/null
+++ b/plat/arm/board/rdn1edge/platform.mk
@@ -0,0 +1,75 @@
+#
+# Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+$(warning Platform ${PLAT} is deprecated. Some of the features might not work as expected)
+
+# GIC-600 configuration
+GICV3_IMPL_GIC600_MULTICHIP := 1
+
+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
+
+PLAT_BL_COMMON_SOURCES += ${CSS_ENT_BASE}/sgi_plat.c
+
+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 \
+ ${RDN1EDGE_BASE}/rdn1edge_topology.c \
+ drivers/cfi/v2m/v2m_flash.c \
+ lib/utils/mem_region.c \
+ plat/arm/common/arm_nor_psci_mem_protect.c
+
+ifeq (${TRUSTED_BOARD_BOOT}, 1)
+BL1_SOURCES += ${RDN1EDGE_BASE}/rdn1edge_trusted_boot.c
+BL2_SOURCES += ${RDN1EDGE_BASE}/rdn1edge_trusted_boot.c
+endif
+
+# Enable dynamic addition of MMAP regions in BL31
+BL31_CPPFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC
+
+# Add the FDT_SOURCES and options for Dynamic Config
+FDT_SOURCES += ${RDN1EDGE_BASE}/fdts/${PLAT}_fw_config.dts \
+ ${RDN1EDGE_BASE}/fdts/${PLAT}_tb_fw_config.dts
+FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_fw_config.dtb
+TB_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb
+
+# Add the FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FW_CONFIG},--fw-config,${FW_CONFIG}))
+# Add the TB_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--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,${NT_FW_CONFIG}))
+
+$(eval $(call CREATE_SEQ,SEQ,2))
+ifneq ($(CSS_SGI_CHIP_COUNT),$(filter $(CSS_SGI_CHIP_COUNT),$(SEQ)))
+ $(error "Chip count for RDN1Edge platform should be one of $(SEQ), currently \
+ set to ${CSS_SGI_CHIP_COUNT}.")
+endif
+
+ifneq ($(CSS_SGI_PLATFORM_VARIANT),0)
+ $(error "CSS_SGI_PLATFORM_VARIANT for RD-N1-Edge should always be 0, \
+ currently set to ${CSS_SGI_PLATFORM_VARIANT}.")
+endif
+
+override CTX_INCLUDE_AARCH32_REGS := 0
diff --git a/plat/arm/board/rdn1edge/rdn1edge_err.c b/plat/arm/board/rdn1edge/rdn1edge_err.c
new file mode 100644
index 0000000..46d318c
--- /dev/null
+++ b/plat/arm/board/rdn1edge/rdn1edge_err.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * rdn1edge error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+ while (true) {
+ wfi();
+ }
+}
diff --git a/plat/arm/board/rdn1edge/rdn1edge_plat.c b/plat/arm/board/rdn1edge/rdn1edge_plat.c
new file mode 100644
index 0000000..1dbbf26
--- /dev/null
+++ b/plat/arm/board/rdn1edge/rdn1edge_plat.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/arm/gic600_multichip.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <sgi_soc_platform_def.h>
+#include <sgi_plat.h>
+
+#if defined(IMAGE_BL31)
+static const mmap_region_t rdn1edge_dynamic_mmap[] = {
+ ARM_MAP_SHARED_RAM_REMOTE_CHIP(1),
+ CSS_SGI_MAP_DEVICE_REMOTE_CHIP(1),
+ SOC_CSS_MAP_DEVICE_REMOTE_CHIP(1)
+};
+
+static struct gic600_multichip_data rdn1e1_multichip_data __init = {
+ .rt_owner_base = PLAT_ARM_GICD_BASE,
+ .rt_owner = 0,
+ .chip_count = CSS_SGI_CHIP_COUNT,
+ .chip_addrs = {
+ PLAT_ARM_GICD_BASE >> 16,
+ (PLAT_ARM_GICD_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1)) >> 16
+ },
+ .spi_ids = {
+ {32, 255},
+ {0, 0}
+ }
+};
+
+static uintptr_t rdn1e1_multichip_gicr_frames[] = {
+ PLAT_ARM_GICR_BASE, /* Chip 0's GICR Base */
+ PLAT_ARM_GICR_BASE +
+ CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1), /* Chip 1's GICR BASE */
+ UL(0) /* Zero Termination */
+};
+#endif /* IMAGE_BL31 */
+
+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);
+}
+
+unsigned int plat_arm_sgi_get_multi_chip_mode(void)
+{
+ return (mmio_read_32(SID_REG_BASE + SID_NODE_ID_OFFSET) &
+ SID_MULTI_CHIP_MODE_MASK) >> SID_MULTI_CHIP_MODE_SHIFT;
+}
+
+/*
+ * IMAGE_BL31 macro is added to build bl31_platform_setup function only for BL31
+ * because PLAT_XLAT_TABLES_DYNAMIC macro is set to build only for BL31 and not
+ * for other stages.
+ */
+#if defined(IMAGE_BL31)
+void bl31_platform_setup(void)
+{
+ int i, ret;
+
+ if (plat_arm_sgi_get_multi_chip_mode() == 0 && CSS_SGI_CHIP_COUNT > 1) {
+ ERROR("Chip Count is set to %d but multi-chip mode not enabled\n",
+ CSS_SGI_CHIP_COUNT);
+ panic();
+ } else if (plat_arm_sgi_get_multi_chip_mode() == 1 &&
+ CSS_SGI_CHIP_COUNT > 1) {
+ INFO("Enabling support for multi-chip in RD-N1-Edge\n");
+
+ for (i = 0; i < ARRAY_SIZE(rdn1edge_dynamic_mmap); i++) {
+ ret = mmap_add_dynamic_region(
+ rdn1edge_dynamic_mmap[i].base_pa,
+ rdn1edge_dynamic_mmap[i].base_va,
+ rdn1edge_dynamic_mmap[i].size,
+ rdn1edge_dynamic_mmap[i].attr
+ );
+ if (ret != 0) {
+ ERROR("Failed to add dynamic mmap entry\n");
+ panic();
+ }
+ }
+
+ plat_arm_override_gicr_frames(rdn1e1_multichip_gicr_frames);
+ gic600_multichip_init(&rdn1e1_multichip_data);
+ }
+
+ sgi_bl31_common_platform_setup();
+}
+#endif /* IMAGE_BL31 */
diff --git a/plat/arm/board/rdn1edge/rdn1edge_security.c b/plat/arm/board/rdn1edge/rdn1edge_security.c
new file mode 100644
index 0000000..4943532
--- /dev/null
+++ b/plat/arm/board/rdn1edge/rdn1edge_security.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <sgi_dmc620_tzc_regions.h>
+
+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[] = {
+ CSS_SGI_DMC620_TZC_REGIONS_DEF
+};
+
+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);
+}
diff --git a/plat/arm/board/rdn1edge/rdn1edge_topology.c b/plat/arm/board/rdn1edge/rdn1edge_topology.c
new file mode 100644
index 0000000..5bbea69
--- /dev/null
+++ b/plat/arm/board/rdn1edge/rdn1edge_topology.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
+
+/******************************************************************************
+ * The power domain tree descriptor.
+ ******************************************************************************/
+static const unsigned char rdn1edge_pd_tree_desc[] = {
+ (PLAT_ARM_CLUSTER_COUNT) * (CSS_SGI_CHIP_COUNT),
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+#if (CSS_SGI_CHIP_COUNT > 1)
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER
+#endif
+};
+
+/*******************************************************************************
+ * This function returns the topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ return rdn1edge_pd_tree_desc;
+}
+
+/*******************************************************************************
+ * 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[] = {
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x0)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x1)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x2)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x3)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x4)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x5)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x6)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x7)),
+#if (CSS_SGI_CHIP_COUNT > 1)
+ (SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x0)),
+ (SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x1)),
+ (SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x2)),
+ (SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x3)),
+ (SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x4)),
+ (SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x5)),
+ (SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x6)),
+ (SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x7)),
+#endif
+};
diff --git a/plat/arm/board/rdn1edge/rdn1edge_trusted_boot.c b/plat/arm/board/rdn1edge/rdn1edge_trusted_boot.c
new file mode 100644
index 0000000..4592b8f
--- /dev/null
+++ b/plat/arm/board/rdn1edge/rdn1edge_trusted_boot.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * 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)
+{
+ return arm_get_rotpk_info(cookie, key_ptr, key_len, flags);
+}
diff --git a/plat/arm/board/rdn2/fdts/rdn2_fw_config.dts b/plat/arm/board/rdn2/fdts/rdn2_fw_config.dts
new file mode 100644
index 0000000..9c9cefe
--- /dev/null
+++ b/plat/arm/board/rdn2/fdts/rdn2_fw_config.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/tbbr/tbbr_img_def.h>
+
+/dts-v1/;
+
+/ {
+ dtb-registry {
+ compatible = "fconf,dyn_cfg-dtb_registry";
+
+ tb_fw-config {
+ load-address = <0x0 0x4001300>;
+ max-size = <0x200>;
+ id = <TB_FW_CONFIG_ID>;
+ };
+
+ nt_fw-config {
+ load-address = <0x0 0xFEF00000>;
+ max-size = <0x0100000>;
+ id = <NT_FW_CONFIG_ID>;
+ };
+ };
+};
diff --git a/plat/arm/board/rdn2/fdts/rdn2_nt_fw_config.dts b/plat/arm/board/rdn2/fdts/rdn2_nt_fw_config.dts
new file mode 100644
index 0000000..dd70141
--- /dev/null
+++ b/plat/arm/board/rdn2/fdts/rdn2_nt_fw_config.dts
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 - 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+/ {
+ /* compatible string */
+ compatible = "arm,rd-n2";
+
+ /*
+ * 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>;
+ multi-chip-mode = <0x0>;
+ /*
+ * First cell pair: Count of isolated CPUs in the list.
+ * Rest of the cells: MPID list of the isolated CPUs.
+ */
+ isolated-cpu-list = <0x0 0x0
+ 0x0 0x0
+ 0x0 0x0
+ 0x0 0x0
+ 0x0 0x0
+ 0x0 0x0
+ 0x0 0x0
+ 0x0 0x0
+ 0x0 0x0
+ 0x0 0x0
+ 0x0 0x0
+ 0x0 0x0
+ 0x0 0x0
+ 0x0 0x0
+ 0x0 0x0
+ 0x0 0x0
+ 0x0 0x0>;
+ };
+};
diff --git a/plat/arm/board/rdn2/fdts/rdn2_tb_fw_config.dts b/plat/arm/board/rdn2/fdts/rdn2_tb_fw_config.dts
new file mode 100644
index 0000000..49eda27
--- /dev/null
+++ b/plat/arm/board/rdn2/fdts/rdn2_tb_fw_config.dts
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+ tb_fw-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>;
+ };
+};
diff --git a/plat/arm/board/rdn2/include/platform_def.h b/plat/arm/board/rdn2/include/platform_def.h
new file mode 100644
index 0000000..3474016
--- /dev/null
+++ b/plat/arm/board/rdn2/include/platform_def.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+
+#include <sgi_soc_platform_def_v2.h>
+
+#if (CSS_SGI_PLATFORM_VARIANT == 1)
+#define PLAT_ARM_CLUSTER_COUNT U(8)
+#elif (CSS_SGI_PLATFORM_VARIANT == 2)
+#define PLAT_ARM_CLUSTER_COUNT U(4)
+#else
+#define PLAT_ARM_CLUSTER_COUNT U(16)
+#endif
+
+#define CSS_SGI_MAX_CPUS_PER_CLUSTER U(1)
+#define CSS_SGI_MAX_PE_PER_CPU U(1)
+
+#define PLAT_CSS_MHU_BASE UL(0x2A920000)
+#define PLAT_MHUV2_BASE PLAT_CSS_MHU_BASE
+
+#define CSS_SYSTEM_PWR_DMN_LVL ARM_PWR_LVL2
+#define PLAT_MAX_PWR_LVL ARM_PWR_LVL1
+
+/* TZC Related Constants */
+#define PLAT_ARM_TZC_BASE UL(0x10720000)
+#define PLAT_ARM_TZC_FILTERS TZC_400_REGION_ATTR_FILTER_BIT(0)
+
+#define TZC400_OFFSET UL(0x1000000)
+
+#if (CSS_SGI_PLATFORM_VARIANT == 1)
+#define TZC400_COUNT U(2)
+#elif (CSS_SGI_PLATFORM_VARIANT == 2)
+#define TZC400_COUNT U(4)
+#else
+#define TZC400_COUNT U(8)
+#endif
+
+#define TZC400_BASE(n) (PLAT_ARM_TZC_BASE + \
+ (n * TZC400_OFFSET))
+
+#define TZC_NSAID_ALL_AP U(0)
+#define TZC_NSAID_PCI U(1)
+#define TZC_NSAID_HDLCD0 U(2)
+#define TZC_NSAID_DMA U(5)
+#define TZC_NSAID_DMA2 U(8)
+#define TZC_NSAID_CLCD U(7)
+#define TZC_NSAID_AP U(9)
+#define TZC_NSAID_VIRTIO U(15)
+
+#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_PCI)) | \
+ (TZC_REGION_ACCESS_RDWR(TZC_NSAID_DMA)) | \
+ (TZC_REGION_ACCESS_RDWR(TZC_NSAID_DMA2)) | \
+ (TZC_REGION_ACCESS_RDWR(TZC_NSAID_AP)) | \
+ (TZC_REGION_ACCESS_RDWR(TZC_NSAID_CLCD)) | \
+ (TZC_REGION_ACCESS_RDWR(TZC_NSAID_VIRTIO))
+
+/*
+ * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
+ */
+#ifdef __aarch64__
+#if (CSS_SGI_PLATFORM_VARIANT == 2)
+#define CSS_SGI_ADDR_BITS_PER_CHIP U(46) /* 64TB */
+#else
+#define CSS_SGI_ADDR_BITS_PER_CHIP U(42) /* 4TB */
+#endif
+
+#define PLAT_PHY_ADDR_SPACE_SIZE CSS_SGI_REMOTE_CHIP_MEM_OFFSET( \
+ CSS_SGI_CHIP_COUNT)
+#define PLAT_VIRT_ADDR_SPACE_SIZE CSS_SGI_REMOTE_CHIP_MEM_OFFSET( \
+ CSS_SGI_CHIP_COUNT)
+#else
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
+#endif
+
+/* GIC related constants */
+#define PLAT_ARM_GICD_BASE UL(0x30000000)
+#define PLAT_ARM_GICC_BASE UL(0x2C000000)
+
+/* Virtual address used by dynamic mem_protect for chunk_base */
+#define PLAT_ARM_MEM_PROTEC_VA_FRAME UL(0xC0000000)
+
+#if (CSS_SGI_PLATFORM_VARIANT == 1)
+#define PLAT_ARM_GICR_BASE UL(0x30100000)
+#else
+#define PLAT_ARM_GICR_BASE UL(0x301C0000)
+#endif
+
+/* Interrupt priority level for shutdown/reboot */
+#define PLAT_REBOOT_PRI GIC_HIGHEST_SEC_PRIORITY
+#define PLAT_EHF_DESC EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_REBOOT_PRI)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/rdn2/platform.mk b/plat/arm/board/rdn2/platform.mk
new file mode 100644
index 0000000..7492fe5
--- /dev/null
+++ b/plat/arm/board/rdn2/platform.mk
@@ -0,0 +1,90 @@
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+RD_N2_VARIANTS := 0 1 2
+ifneq ($(CSS_SGI_PLATFORM_VARIANT),\
+ $(filter $(CSS_SGI_PLATFORM_VARIANT),$(RD_N2_VARIANTS)))
+ $(error "CSS_SGI_PLATFORM_VARIANT for RD-N2 should be 0, 1 or 2, currently set \
+ to ${CSS_SGI_PLATFORM_VARIANT}.")
+endif
+
+$(eval $(call CREATE_SEQ,SEQ,4))
+ifneq ($(CSS_SGI_CHIP_COUNT),$(filter $(CSS_SGI_CHIP_COUNT),$(SEQ)))
+ $(error "Chip count for RD-N2-MC should be either $(SEQ) \
+ currently it is set to ${CSS_SGI_CHIP_COUNT}.")
+endif
+
+# RD-N2 platform uses GIC-700 which is based on GICv4.1
+GIC_ENABLE_V4_EXTN := 1
+GIC_EXT_INTID := 1
+
+#Enable GIC Multichip Extension only for Multichip Platforms
+ifeq (${CSS_SGI_PLATFORM_VARIANT}, 2)
+GICV3_IMPL_GIC600_MULTICHIP := 1
+endif
+
+override CSS_SYSTEM_GRACEFUL_RESET := 1
+override EL3_EXCEPTION_HANDLING := 1
+
+include plat/arm/css/sgi/sgi-common.mk
+
+RDN2_BASE = plat/arm/board/rdn2
+
+PLAT_INCLUDES += -I${RDN2_BASE}/include/
+
+SGI_CPU_SOURCES := lib/cpus/aarch64/neoverse_n2.S \
+ lib/cpus/aarch64/neoverse_v2.S
+
+PLAT_BL_COMMON_SOURCES += ${CSS_ENT_BASE}/sgi_plat_v2.c
+
+BL1_SOURCES += ${SGI_CPU_SOURCES} \
+ ${RDN2_BASE}/rdn2_err.c
+
+BL2_SOURCES += ${RDN2_BASE}/rdn2_plat.c \
+ ${RDN2_BASE}/rdn2_security.c \
+ ${RDN2_BASE}/rdn2_err.c \
+ lib/utils/mem_region.c \
+ drivers/arm/tzc/tzc400.c \
+ plat/arm/common/arm_tzc400.c \
+ plat/arm/common/arm_nor_psci_mem_protect.c
+
+BL31_SOURCES += ${SGI_CPU_SOURCES} \
+ ${RDN2_BASE}/rdn2_plat.c \
+ ${RDN2_BASE}/rdn2_topology.c \
+ drivers/cfi/v2m/v2m_flash.c \
+ lib/utils/mem_region.c \
+ plat/arm/common/arm_nor_psci_mem_protect.c
+
+ifeq (${TRUSTED_BOARD_BOOT}, 1)
+BL1_SOURCES += ${RDN2_BASE}/rdn2_trusted_boot.c
+BL2_SOURCES += ${RDN2_BASE}/rdn2_trusted_boot.c
+endif
+
+ifeq (${CSS_SGI_PLATFORM_VARIANT}, 2)
+BL31_SOURCES += drivers/arm/gic/v3/gic600_multichip.c
+
+# Enable dynamic addition of MMAP regions in BL31
+BL31_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC
+endif
+
+# Add the FDT_SOURCES and options for Dynamic Config
+FDT_SOURCES += ${RDN2_BASE}/fdts/${PLAT}_fw_config.dts \
+ ${RDN2_BASE}/fdts/${PLAT}_tb_fw_config.dts
+FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_fw_config.dtb
+TB_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb
+
+# Add the FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FW_CONFIG},--fw-config,${FW_CONFIG}))
+# Add the TB_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--tb-fw-config,${TB_FW_CONFIG}))
+
+FDT_SOURCES += ${RDN2_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
+override ENABLE_AMU := 1
diff --git a/plat/arm/board/rdn2/rdn2_err.c b/plat/arm/board/rdn2/rdn2_err.c
new file mode 100644
index 0000000..802ac21
--- /dev/null
+++ b/plat/arm/board/rdn2/rdn2_err.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * rdn2 error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+ while (1) {
+ wfi();
+ }
+}
diff --git a/plat/arm/board/rdn2/rdn2_plat.c b/plat/arm/board/rdn2/rdn2_plat.c
new file mode 100644
index 0000000..2506f9d
--- /dev/null
+++ b/plat/arm/board/rdn2/rdn2_plat.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/arm/gic600_multichip.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <sgi_soc_platform_def_v2.h>
+#include <sgi_plat.h>
+
+#if defined(IMAGE_BL31)
+#if (CSS_SGI_PLATFORM_VARIANT == 2)
+static const mmap_region_t rdn2mc_dynamic_mmap[] = {
+#if CSS_SGI_CHIP_COUNT > 1
+ ARM_MAP_SHARED_RAM_REMOTE_CHIP(1),
+ CSS_SGI_MAP_DEVICE_REMOTE_CHIP(1),
+#endif
+#if CSS_SGI_CHIP_COUNT > 2
+ ARM_MAP_SHARED_RAM_REMOTE_CHIP(2),
+ CSS_SGI_MAP_DEVICE_REMOTE_CHIP(2),
+#endif
+#if CSS_SGI_CHIP_COUNT > 3
+ ARM_MAP_SHARED_RAM_REMOTE_CHIP(3),
+ CSS_SGI_MAP_DEVICE_REMOTE_CHIP(3),
+#endif
+};
+#endif
+
+#if (CSS_SGI_PLATFORM_VARIANT == 2)
+static struct gic600_multichip_data rdn2mc_multichip_data __init = {
+ .rt_owner_base = PLAT_ARM_GICD_BASE,
+ .rt_owner = 0,
+ .chip_count = CSS_SGI_CHIP_COUNT,
+ .chip_addrs = {
+ PLAT_ARM_GICD_BASE >> 16,
+#if CSS_SGI_CHIP_COUNT > 1
+ (PLAT_ARM_GICD_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+#endif
+#if CSS_SGI_CHIP_COUNT > 2
+ (PLAT_ARM_GICD_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+#endif
+#if CSS_SGI_CHIP_COUNT > 3
+ (PLAT_ARM_GICD_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+#endif
+ },
+ .spi_ids = {
+ {32, 511},
+ #if CSS_SGI_CHIP_COUNT > 1
+ {512, 991},
+ #endif
+ #if CSS_SGI_CHIP_COUNT > 2
+ {4096, 4575},
+ #endif
+ #if CSS_SGI_CHIP_COUNT > 3
+ {4576, 5055},
+ #endif
+ }
+};
+#endif
+
+#if (CSS_SGI_PLATFORM_VARIANT == 2)
+static uintptr_t rdn2mc_multichip_gicr_frames[] = {
+ /* Chip 0's GICR Base */
+ PLAT_ARM_GICR_BASE,
+#if CSS_SGI_CHIP_COUNT > 1
+ /* Chip 1's GICR BASE */
+ PLAT_ARM_GICR_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1),
+#endif
+#if CSS_SGI_CHIP_COUNT > 2
+ /* Chip 2's GICR BASE */
+ PLAT_ARM_GICR_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(2),
+#endif
+#if CSS_SGI_CHIP_COUNT > 3
+ /* Chip 3's GICR BASE */
+ PLAT_ARM_GICR_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(3),
+#endif
+ UL(0) /* Zero Termination */
+};
+#endif
+#endif /* IMAGE_BL31 */
+
+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);
+}
+
+unsigned int plat_arm_sgi_get_multi_chip_mode(void)
+{
+ return (mmio_read_32(SID_REG_BASE + SID_NODE_ID_OFFSET) &
+ SID_MULTI_CHIP_MODE_MASK) >>
+ SID_MULTI_CHIP_MODE_SHIFT;
+}
+
+#if defined(IMAGE_BL31)
+void bl31_platform_setup(void)
+{
+#if (CSS_SGI_PLATFORM_VARIANT == 2)
+ int ret;
+ unsigned int i;
+
+ if (plat_arm_sgi_get_multi_chip_mode() == 0) {
+ ERROR("Chip Count is set to %u but multi-chip mode is not "
+ "enabled\n", CSS_SGI_CHIP_COUNT);
+ panic();
+ } else {
+ INFO("Enabling multi-chip support for RD-N2 variant\n");
+
+ for (i = 0; i < ARRAY_SIZE(rdn2mc_dynamic_mmap); i++) {
+ ret = mmap_add_dynamic_region(
+ rdn2mc_dynamic_mmap[i].base_pa,
+ rdn2mc_dynamic_mmap[i].base_va,
+ rdn2mc_dynamic_mmap[i].size,
+ rdn2mc_dynamic_mmap[i].attr);
+ if (ret != 0) {
+ ERROR("Failed to add dynamic mmap entry for"
+ " i: %d " "(ret=%d)\n", i, ret);
+ panic();
+ }
+ }
+
+ plat_arm_override_gicr_frames(
+ rdn2mc_multichip_gicr_frames);
+ gic600_multichip_init(&rdn2mc_multichip_data);
+ }
+#endif
+
+ sgi_bl31_common_platform_setup();
+}
+#endif /* IMAGE_BL31 */
diff --git a/plat/arm/board/rdn2/rdn2_security.c b/plat/arm/board/rdn2/rdn2_security.c
new file mode 100644
index 0000000..dff6a19
--- /dev/null
+++ b/plat/arm/board/rdn2/rdn2_security.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+static const arm_tzc_regions_info_t tzc_regions[] = {
+ ARM_TZC_REGIONS_DEF,
+ {}
+};
+
+#if (CSS_SGI_PLATFORM_VARIANT == 2 && CSS_SGI_CHIP_COUNT > 1)
+static const arm_tzc_regions_info_t tzc_regions_mc[][CSS_SGI_CHIP_COUNT - 1] = {
+ {
+ /* TZC memory regions for second chip */
+ SGI_PLAT_TZC_NS_REMOTE_REGIONS_DEF(1),
+ {}
+ },
+#if CSS_SGI_CHIP_COUNT > 2
+ {
+ /* TZC memory regions for third chip */
+ SGI_PLAT_TZC_NS_REMOTE_REGIONS_DEF(2),
+ {}
+ },
+#endif
+#if CSS_SGI_CHIP_COUNT > 3
+ {
+ /* TZC memory regions for fourth chip */
+ SGI_PLAT_TZC_NS_REMOTE_REGIONS_DEF(3),
+ {}
+ },
+#endif
+};
+#endif /* CSS_SGI_PLATFORM_VARIANT && CSS_SGI_CHIP_COUNT */
+
+/* Initialize the secure environment */
+void plat_arm_security_setup(void)
+{
+ unsigned int i;
+
+ INFO("Configuring TrustZone Controller for Chip 0\n");
+
+ for (i = 0; i < TZC400_COUNT; i++) {
+ arm_tzc400_setup(TZC400_BASE(i), tzc_regions);
+ }
+
+#if (CSS_SGI_PLATFORM_VARIANT == 2 && CSS_SGI_CHIP_COUNT > 1)
+ unsigned int j;
+
+ for (i = 1; i < CSS_SGI_CHIP_COUNT; i++) {
+ INFO("Configuring TrustZone Controller for Chip %u\n", i);
+
+ for (j = 0; j < TZC400_COUNT; j++) {
+ arm_tzc400_setup(CSS_SGI_REMOTE_CHIP_MEM_OFFSET(i)
+ + TZC400_BASE(j), tzc_regions_mc[i-1]);
+ }
+ }
+#endif
+}
diff --git a/plat/arm/board/rdn2/rdn2_topology.c b/plat/arm/board/rdn2/rdn2_topology.c
new file mode 100644
index 0000000..89300f8
--- /dev/null
+++ b/plat/arm/board/rdn2/rdn2_topology.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
+
+/******************************************************************************
+ * The power domain tree descriptor.
+ ******************************************************************************/
+const unsigned char rd_n2_pd_tree_desc[] = {
+ (PLAT_ARM_CLUSTER_COUNT) * (CSS_SGI_CHIP_COUNT),
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+#if (CSS_SGI_PLATFORM_VARIANT != 2 || (CSS_SGI_PLATFORM_VARIANT == 2 && CSS_SGI_CHIP_COUNT > 1))
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+#endif
+#if (CSS_SGI_PLATFORM_VARIANT == 0 || (CSS_SGI_PLATFORM_VARIANT == 2 && CSS_SGI_CHIP_COUNT > 2))
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+#endif
+#if (CSS_SGI_PLATFORM_VARIANT == 0 || (CSS_SGI_PLATFORM_VARIANT == 2 && CSS_SGI_CHIP_COUNT > 3))
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+#endif
+};
+
+/*******************************************************************************
+ * This function returns the topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ return rd_n2_pd_tree_desc;
+}
+
+/*******************************************************************************
+ * The array mapping platform core position (implemented by plat_my_core_pos())
+ * to the SCMI power domain ID implemented by SCP.
+ ******************************************************************************/
+#if (CSS_SGI_PLATFORM_VARIANT == 2)
+const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[] = {
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x0)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x1)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x2)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x3)),
+#if (CSS_SGI_CHIP_COUNT > 1)
+ (SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x0)),
+ (SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x1)),
+ (SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x2)),
+ (SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x3)),
+#endif
+#if (CSS_SGI_CHIP_COUNT > 2)
+ (SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x0)),
+ (SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x1)),
+ (SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x2)),
+ (SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x3)),
+#endif
+#if (CSS_SGI_CHIP_COUNT > 3)
+ (SET_SCMI_CHANNEL_ID(0x3) | SET_SCMI_DOMAIN_ID(0x0)),
+ (SET_SCMI_CHANNEL_ID(0x3) | SET_SCMI_DOMAIN_ID(0x1)),
+ (SET_SCMI_CHANNEL_ID(0x3) | SET_SCMI_DOMAIN_ID(0x2)),
+ (SET_SCMI_CHANNEL_ID(0x3) | SET_SCMI_DOMAIN_ID(0x3)),
+#endif
+};
+#else
+const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[] = {
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x0)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x1)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x2)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x3)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x4)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x5)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x6)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x7)),
+#if (CSS_SGI_PLATFORM_VARIANT == 0)
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x8)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x9)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0xA)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0xB)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0xC)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0xD)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0xE)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0xF)),
+#endif
+};
+#endif
diff --git a/plat/arm/board/rdn2/rdn2_trusted_boot.c b/plat/arm/board/rdn2/rdn2_trusted_boot.c
new file mode 100644
index 0000000..4592b8f
--- /dev/null
+++ b/plat/arm/board/rdn2/rdn2_trusted_boot.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * 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)
+{
+ return arm_get_rotpk_info(cookie, key_ptr, key_len, flags);
+}
diff --git a/plat/arm/board/rdv1/fdts/rdv1_fw_config.dts b/plat/arm/board/rdv1/fdts/rdv1_fw_config.dts
new file mode 100644
index 0000000..9c9cefe
--- /dev/null
+++ b/plat/arm/board/rdv1/fdts/rdv1_fw_config.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/tbbr/tbbr_img_def.h>
+
+/dts-v1/;
+
+/ {
+ dtb-registry {
+ compatible = "fconf,dyn_cfg-dtb_registry";
+
+ tb_fw-config {
+ load-address = <0x0 0x4001300>;
+ max-size = <0x200>;
+ id = <TB_FW_CONFIG_ID>;
+ };
+
+ nt_fw-config {
+ load-address = <0x0 0xFEF00000>;
+ max-size = <0x0100000>;
+ id = <NT_FW_CONFIG_ID>;
+ };
+ };
+};
diff --git a/plat/arm/board/rdv1/fdts/rdv1_nt_fw_config.dts b/plat/arm/board/rdv1/fdts/rdv1_nt_fw_config.dts
new file mode 100644
index 0000000..62ba2c3
--- /dev/null
+++ b/plat/arm/board/rdv1/fdts/rdv1_nt_fw_config.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+/ {
+ /* compatible string */
+ compatible = "arm,rd-v1";
+
+ /*
+ * 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>;
+ multi-chip-mode = <0x0>;
+ };
+};
diff --git a/plat/arm/board/rdv1/fdts/rdv1_tb_fw_config.dts b/plat/arm/board/rdv1/fdts/rdv1_tb_fw_config.dts
new file mode 100644
index 0000000..49eda27
--- /dev/null
+++ b/plat/arm/board/rdv1/fdts/rdv1_tb_fw_config.dts
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+ tb_fw-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>;
+ };
+};
diff --git a/plat/arm/board/rdv1/include/platform_def.h b/plat/arm/board/rdv1/include/platform_def.h
new file mode 100644
index 0000000..620fa3e
--- /dev/null
+++ b/plat/arm/board/rdv1/include/platform_def.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+
+#include <sgi_soc_platform_def.h>
+
+#define PLAT_ARM_CLUSTER_COUNT U(16)
+#define CSS_SGI_MAX_CPUS_PER_CLUSTER U(1)
+#define CSS_SGI_MAX_PE_PER_CPU U(1)
+
+#define PLAT_CSS_MHU_BASE UL(0x45400000)
+#define PLAT_MHUV2_BASE PLAT_CSS_MHU_BASE
+
+#define CSS_SYSTEM_PWR_DMN_LVL ARM_PWR_LVL2
+#define PLAT_MAX_PWR_LVL ARM_PWR_LVL1
+
+/* TZC Related Constants */
+#define PLAT_ARM_TZC_BASE UL(0x21830000)
+#define PLAT_ARM_TZC_FILTERS TZC_400_REGION_ATTR_FILTER_BIT(0)
+
+#define TZC400_OFFSET UL(0x1000000)
+#define TZC400_COUNT 4
+
+#define TZC400_BASE(n) (PLAT_ARM_TZC_BASE + \
+ (n * TZC400_OFFSET))
+
+#define TZC_NSAID_ALL_AP U(0)
+#define TZC_NSAID_PCI U(1)
+#define TZC_NSAID_HDLCD0 U(2)
+#define TZC_NSAID_CLCD U(7)
+#define TZC_NSAID_AP U(9)
+#define TZC_NSAID_VIRTIO U(15)
+
+#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_PCI)) | \
+ (TZC_REGION_ACCESS_RDWR(TZC_NSAID_AP)) | \
+ (TZC_REGION_ACCESS_RDWR(TZC_NSAID_CLCD)) | \
+ (TZC_REGION_ACCESS_RDWR(TZC_NSAID_VIRTIO))
+
+/* Maximum number of address bits used per chip */
+#define CSS_SGI_ADDR_BITS_PER_CHIP U(42)
+
+/*
+ * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
+ */
+#ifdef __aarch64__
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << CSS_SGI_ADDR_BITS_PER_CHIP)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << CSS_SGI_ADDR_BITS_PER_CHIP)
+#else
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
+#endif
+
+/* GIC related constants */
+#define PLAT_ARM_GICD_BASE UL(0x30000000)
+#define PLAT_ARM_GICC_BASE UL(0x2C000000)
+#define PLAT_ARM_GICR_BASE UL(0x30140000)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/rdv1/platform.mk b/plat/arm/board/rdv1/platform.mk
new file mode 100644
index 0000000..11f5212
--- /dev/null
+++ b/plat/arm/board/rdv1/platform.mk
@@ -0,0 +1,65 @@
+# Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# RD-V1 platform uses GIC-700 which is based on GICv4.1
+GIC_ENABLE_V4_EXTN := 1
+
+include plat/arm/css/sgi/sgi-common.mk
+
+RDV1_BASE = plat/arm/board/rdv1
+
+PLAT_INCLUDES += -I${RDV1_BASE}/include/
+
+SGI_CPU_SOURCES := lib/cpus/aarch64/neoverse_v1.S
+
+PLAT_BL_COMMON_SOURCES += ${CSS_ENT_BASE}/sgi_plat.c
+
+BL1_SOURCES += ${SGI_CPU_SOURCES} \
+ ${RDV1_BASE}/rdv1_err.c
+
+BL2_SOURCES += ${RDV1_BASE}/rdv1_plat.c \
+ ${RDV1_BASE}/rdv1_security.c \
+ ${RDV1_BASE}/rdv1_err.c \
+ lib/utils/mem_region.c \
+ drivers/arm/tzc/tzc400.c \
+ plat/arm/common/arm_tzc400.c \
+ plat/arm/common/arm_nor_psci_mem_protect.c
+
+BL31_SOURCES += ${SGI_CPU_SOURCES} \
+ ${RDV1_BASE}/rdv1_plat.c \
+ ${RDV1_BASE}/rdv1_topology.c \
+ drivers/cfi/v2m/v2m_flash.c \
+ lib/utils/mem_region.c \
+ plat/arm/common/arm_nor_psci_mem_protect.c
+
+ifeq (${TRUSTED_BOARD_BOOT}, 1)
+BL1_SOURCES += ${RDV1_BASE}/rdv1_trusted_boot.c
+BL2_SOURCES += ${RDV1_BASE}/rdv1_trusted_boot.c
+endif
+
+# Add the FDT_SOURCES and options for Dynamic Config
+FDT_SOURCES += ${RDV1_BASE}/fdts/${PLAT}_fw_config.dts \
+ ${RDV1_BASE}/fdts/${PLAT}_tb_fw_config.dts
+FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_fw_config.dtb
+TB_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb
+
+# Add the FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FW_CONFIG},--fw-config,${FW_CONFIG}))
+# Add the TB_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--tb-fw-config,${TB_FW_CONFIG}))
+
+FDT_SOURCES += ${RDV1_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,${NT_FW_CONFIG}))
+
+override CTX_INCLUDE_AARCH32_REGS := 0
+override ENABLE_AMU := 1
+
+ifneq ($(CSS_SGI_PLATFORM_VARIANT),0)
+ $(error "CSS_SGI_PLATFORM_VARIANT for RD-V1 should always be 0, \
+ currently set to ${CSS_SGI_PLATFORM_VARIANT}.")
+endif
diff --git a/plat/arm/board/rdv1/rdv1_err.c b/plat/arm/board/rdv1/rdv1_err.c
new file mode 100644
index 0000000..68f9a3e
--- /dev/null
+++ b/plat/arm/board/rdv1/rdv1_err.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * rdv1 error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+ while (1) {
+ wfi();
+ }
+}
diff --git a/plat/arm/board/rdv1/rdv1_plat.c b/plat/arm/board/rdv1/rdv1_plat.c
new file mode 100644
index 0000000..ab5251e
--- /dev/null
+++ b/plat/arm/board/rdv1/rdv1_plat.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+#include <sgi_plat.h>
+
+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);
+}
+
+unsigned int plat_arm_sgi_get_multi_chip_mode(void)
+{
+ return (mmio_read_32(SID_REG_BASE + SID_NODE_ID_OFFSET) &
+ SID_MULTI_CHIP_MODE_MASK) >> SID_MULTI_CHIP_MODE_SHIFT;
+}
+
+void bl31_platform_setup(void)
+{
+ sgi_bl31_common_platform_setup();
+}
diff --git a/plat/arm/board/rdv1/rdv1_security.c b/plat/arm/board/rdv1/rdv1_security.c
new file mode 100644
index 0000000..1247db8
--- /dev/null
+++ b/plat/arm/board/rdv1/rdv1_security.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+static const arm_tzc_regions_info_t tzc_regions[] = {
+ ARM_TZC_REGIONS_DEF,
+ {}
+};
+
+/* Initialize the secure environment */
+void plat_arm_security_setup(void)
+{
+ int i;
+
+ for (i = 0; i < TZC400_COUNT; i++)
+ arm_tzc400_setup(TZC400_BASE(i), tzc_regions);
+}
diff --git a/plat/arm/board/rdv1/rdv1_topology.c b/plat/arm/board/rdv1/rdv1_topology.c
new file mode 100644
index 0000000..ab64fd8
--- /dev/null
+++ b/plat/arm/board/rdv1/rdv1_topology.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
+
+/******************************************************************************
+ * The power domain tree descriptor.
+ ******************************************************************************/
+const unsigned char rd_v1_pd_tree_desc[] = {
+ PLAT_ARM_CLUSTER_COUNT,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER
+};
+
+/*******************************************************************************
+ * This function returns the topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ return rd_v1_pd_tree_desc;
+}
+
+/*******************************************************************************
+ * 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[] = {
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x0)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x1)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x2)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x3)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x4)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x5)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x6)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x7)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x8)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x9)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0xA)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0xB)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0xC)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0xD)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0xE)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0xF))
+};
diff --git a/plat/arm/board/rdv1/rdv1_trusted_boot.c b/plat/arm/board/rdv1/rdv1_trusted_boot.c
new file mode 100644
index 0000000..4592b8f
--- /dev/null
+++ b/plat/arm/board/rdv1/rdv1_trusted_boot.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * 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)
+{
+ return arm_get_rotpk_info(cookie, key_ptr, key_len, flags);
+}
diff --git a/plat/arm/board/rdv1mc/fdts/rdv1mc_fw_config.dts b/plat/arm/board/rdv1mc/fdts/rdv1mc_fw_config.dts
new file mode 100644
index 0000000..9c9cefe
--- /dev/null
+++ b/plat/arm/board/rdv1mc/fdts/rdv1mc_fw_config.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/tbbr/tbbr_img_def.h>
+
+/dts-v1/;
+
+/ {
+ dtb-registry {
+ compatible = "fconf,dyn_cfg-dtb_registry";
+
+ tb_fw-config {
+ load-address = <0x0 0x4001300>;
+ max-size = <0x200>;
+ id = <TB_FW_CONFIG_ID>;
+ };
+
+ nt_fw-config {
+ load-address = <0x0 0xFEF00000>;
+ max-size = <0x0100000>;
+ id = <NT_FW_CONFIG_ID>;
+ };
+ };
+};
diff --git a/plat/arm/board/rdv1mc/fdts/rdv1mc_nt_fw_config.dts b/plat/arm/board/rdv1mc/fdts/rdv1mc_nt_fw_config.dts
new file mode 100644
index 0000000..71c7db3
--- /dev/null
+++ b/plat/arm/board/rdv1mc/fdts/rdv1mc_nt_fw_config.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+/ {
+ /* compatible string */
+ compatible = "arm,rd-v1-mc";
+
+ /*
+ * 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>;
+ multi-chip-mode = <0x0>;
+ };
+};
diff --git a/plat/arm/board/rdv1mc/fdts/rdv1mc_tb_fw_config.dts b/plat/arm/board/rdv1mc/fdts/rdv1mc_tb_fw_config.dts
new file mode 100644
index 0000000..49eda27
--- /dev/null
+++ b/plat/arm/board/rdv1mc/fdts/rdv1mc_tb_fw_config.dts
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+ tb_fw-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>;
+ };
+};
diff --git a/plat/arm/board/rdv1mc/include/platform_def.h b/plat/arm/board/rdv1mc/include/platform_def.h
new file mode 100644
index 0000000..3670904
--- /dev/null
+++ b/plat/arm/board/rdv1mc/include/platform_def.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+#include <sgi_soc_platform_def.h>
+
+#define PLAT_ARM_CLUSTER_COUNT U(4)
+#define CSS_SGI_MAX_CPUS_PER_CLUSTER U(1)
+#define CSS_SGI_MAX_PE_PER_CPU U(1)
+
+#define PLAT_CSS_MHU_BASE UL(0x45400000)
+#define PLAT_MHUV2_BASE PLAT_CSS_MHU_BASE
+
+#define CSS_SYSTEM_PWR_DMN_LVL ARM_PWR_LVL2
+#define PLAT_MAX_PWR_LVL ARM_PWR_LVL1
+
+/* TZC Related Constants */
+#define PLAT_ARM_TZC_BASE UL(0x21830000)
+#define TZC400_BASE(n) (PLAT_ARM_TZC_BASE + \
+ (n * TZC400_OFFSET))
+#define TZC400_OFFSET UL(0x1000000)
+#define TZC400_COUNT U(8)
+#define PLAT_ARM_TZC_FILTERS TZC_400_REGION_ATTR_FILTER_BIT(0)
+
+#define TZC_NSAID_ALL_AP U(0)
+#define TZC_NSAID_PCI U(1)
+#define TZC_NSAID_HDLCD0 U(2)
+#define TZC_NSAID_CLCD U(7)
+#define TZC_NSAID_AP U(9)
+#define TZC_NSAID_VIRTIO U(15)
+
+#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_PCI)) | \
+ (TZC_REGION_ACCESS_RDWR(TZC_NSAID_AP)) | \
+ (TZC_REGION_ACCESS_RDWR(TZC_NSAID_CLCD)) | \
+ (TZC_REGION_ACCESS_RDWR(TZC_NSAID_VIRTIO))
+
+/* Virtual address used by dynamic mem_protect for chunk_base */
+#define PLAT_ARM_MEM_PROTEC_VA_FRAME UL(0xC0000000)
+
+/* Remote chip address offset (4TB per chip) */
+#define CSS_SGI_ADDR_BITS_PER_CHIP U(42)
+
+/* Physical and virtual address space limits for MMU in AARCH64 mode */
+#define PLAT_PHY_ADDR_SPACE_SIZE CSS_SGI_REMOTE_CHIP_MEM_OFFSET( \
+ CSS_SGI_CHIP_COUNT)
+#define PLAT_VIRT_ADDR_SPACE_SIZE CSS_SGI_REMOTE_CHIP_MEM_OFFSET( \
+ CSS_SGI_CHIP_COUNT)
+
+/* GIC related constants */
+#define PLAT_ARM_GICD_BASE UL(0x30000000)
+#define PLAT_ARM_GICC_BASE UL(0x2C000000)
+#define PLAT_ARM_GICR_BASE UL(0x30140000)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/rdv1mc/platform.mk b/plat/arm/board/rdv1mc/platform.mk
new file mode 100644
index 0000000..df0b09a
--- /dev/null
+++ b/plat/arm/board/rdv1mc/platform.mk
@@ -0,0 +1,76 @@
+# Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Enable GICv4 extension with multichip driver
+GIC_ENABLE_V4_EXTN := 1
+GICV3_IMPL_GIC600_MULTICHIP := 1
+
+include plat/arm/css/sgi/sgi-common.mk
+
+RDV1MC_BASE = plat/arm/board/rdv1mc
+
+PLAT_INCLUDES += -I${RDV1MC_BASE}/include/
+
+SGI_CPU_SOURCES := lib/cpus/aarch64/neoverse_v1.S
+
+PLAT_BL_COMMON_SOURCES += ${CSS_ENT_BASE}/sgi_plat.c
+
+BL1_SOURCES += ${SGI_CPU_SOURCES} \
+ ${RDV1MC_BASE}/rdv1mc_err.c
+
+BL2_SOURCES += ${RDV1MC_BASE}/rdv1mc_plat.c \
+ ${RDV1MC_BASE}/rdv1mc_security.c \
+ ${RDV1MC_BASE}/rdv1mc_err.c \
+ drivers/arm/tzc/tzc400.c \
+ plat/arm/common/arm_tzc400.c \
+ lib/utils/mem_region.c \
+ plat/arm/common/arm_nor_psci_mem_protect.c
+
+BL31_SOURCES += ${SGI_CPU_SOURCES} \
+ ${RDV1MC_BASE}/rdv1mc_plat.c \
+ ${RDV1MC_BASE}/rdv1mc_topology.c \
+ drivers/cfi/v2m/v2m_flash.c \
+ drivers/arm/gic/v3/gic600_multichip.c \
+ lib/utils/mem_region.c \
+ plat/arm/common/arm_nor_psci_mem_protect.c
+
+ifeq (${TRUSTED_BOARD_BOOT}, 1)
+BL1_SOURCES += ${RDV1MC_BASE}/rdv1mc_trusted_boot.c
+BL2_SOURCES += ${RDV1MC_BASE}/rdv1mc_trusted_boot.c
+endif
+
+# Enable dynamic addition of MMAP regions in BL31
+BL31_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC
+
+# Add the FDT_SOURCES and options for Dynamic Config
+FDT_SOURCES += ${RDV1MC_BASE}/fdts/${PLAT}_fw_config.dts \
+ ${RDV1MC_BASE}/fdts/${PLAT}_tb_fw_config.dts
+FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_fw_config.dtb
+TB_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb
+
+# Add the FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FW_CONFIG},--fw-config,${FW_CONFIG}))
+# Add the TB_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--tb-fw-config,${TB_FW_CONFIG}))
+
+$(eval $(call CREATE_SEQ,SEQ,4))
+ifneq ($(CSS_SGI_CHIP_COUNT),$(filter $(CSS_SGI_CHIP_COUNT),$(SEQ)))
+ $(error "Chip count for RD-V1-MC should be either $(SEQ) \
+ currently it is set to ${CSS_SGI_CHIP_COUNT}.")
+endif
+
+FDT_SOURCES += ${RDV1MC_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,${NT_FW_CONFIG}))
+
+override CTX_INCLUDE_AARCH32_REGS := 0
+override ENABLE_AMU := 1
+
+ifneq ($(CSS_SGI_PLATFORM_VARIANT),0)
+ $(error "CSS_SGI_PLATFORM_VARIANT for RD-V1-MC should always be 0, \
+ currently set to ${CSS_SGI_PLATFORM_VARIANT}.")
+endif
diff --git a/plat/arm/board/rdv1mc/rdv1mc_err.c b/plat/arm/board/rdv1mc/rdv1mc_err.c
new file mode 100644
index 0000000..755a503
--- /dev/null
+++ b/plat/arm/board/rdv1mc/rdv1mc_err.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * rdv1mc error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+ while (true) {
+ wfi();
+ }
+}
diff --git a/plat/arm/board/rdv1mc/rdv1mc_plat.c b/plat/arm/board/rdv1mc/rdv1mc_plat.c
new file mode 100644
index 0000000..d859400
--- /dev/null
+++ b/plat/arm/board/rdv1mc/rdv1mc_plat.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/arm/gic600_multichip.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <sgi_soc_platform_def.h>
+#include <sgi_plat.h>
+
+#if defined(IMAGE_BL31)
+static const mmap_region_t rdv1mc_dynamic_mmap[] = {
+ ARM_MAP_SHARED_RAM_REMOTE_CHIP(1),
+ CSS_SGI_MAP_DEVICE_REMOTE_CHIP(1),
+ SOC_CSS_MAP_DEVICE_REMOTE_CHIP(1),
+#if (CSS_SGI_CHIP_COUNT > 2)
+ ARM_MAP_SHARED_RAM_REMOTE_CHIP(2),
+ CSS_SGI_MAP_DEVICE_REMOTE_CHIP(2),
+ SOC_CSS_MAP_DEVICE_REMOTE_CHIP(2),
+#endif
+#if (CSS_SGI_CHIP_COUNT > 3)
+ ARM_MAP_SHARED_RAM_REMOTE_CHIP(3),
+ CSS_SGI_MAP_DEVICE_REMOTE_CHIP(3),
+ SOC_CSS_MAP_DEVICE_REMOTE_CHIP(3)
+#endif
+};
+
+static struct gic600_multichip_data rdv1mc_multichip_data __init = {
+ .rt_owner_base = PLAT_ARM_GICD_BASE,
+ .rt_owner = 0,
+ .chip_count = CSS_SGI_CHIP_COUNT,
+ .chip_addrs = {
+ PLAT_ARM_GICD_BASE >> 16,
+ (PLAT_ARM_GICD_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+#if (CSS_SGI_CHIP_COUNT > 2)
+ (PLAT_ARM_GICD_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+#endif
+#if (CSS_SGI_CHIP_COUNT > 3)
+ (PLAT_ARM_GICD_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+#endif
+ },
+ .spi_ids = {
+ {32, 255},
+ {0, 0},
+#if (CSS_SGI_CHIP_COUNT > 2)
+ {0, 0},
+#endif
+#if (CSS_SGI_CHIP_COUNT > 3)
+ {0, 0},
+#endif
+ }
+};
+
+static uintptr_t rdv1mc_multichip_gicr_frames[] = {
+ /* Chip 0's GICR Base */
+ PLAT_ARM_GICR_BASE,
+ /* Chip 1's GICR BASE */
+ PLAT_ARM_GICR_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1),
+#if (CSS_SGI_CHIP_COUNT > 2)
+ /* Chip 2's GICR BASE */
+ PLAT_ARM_GICR_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(2),
+#endif
+#if (CSS_SGI_CHIP_COUNT > 3)
+ /* Chip 3's GICR BASE */
+ PLAT_ARM_GICR_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(3),
+#endif
+ UL(0) /* Zero Termination */
+};
+#endif /* IMAGE_BL31 */
+
+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);
+}
+
+unsigned int plat_arm_sgi_get_multi_chip_mode(void)
+{
+ return (mmio_read_32(SID_REG_BASE + SID_NODE_ID_OFFSET) &
+ SID_MULTI_CHIP_MODE_MASK) >> SID_MULTI_CHIP_MODE_SHIFT;
+}
+
+/*
+ * bl31_platform_setup_function is guarded by IMAGE_BL31 macro because
+ * PLAT_XLAT_TABLES_DYNAMIC macro is set to build only for BL31 and not
+ * for other stages.
+ */
+#if defined(IMAGE_BL31)
+void bl31_platform_setup(void)
+{
+ int ret;
+ unsigned int i;
+
+ if ((plat_arm_sgi_get_multi_chip_mode() == 0) &&
+ (CSS_SGI_CHIP_COUNT > 1)) {
+ ERROR("Chip Count is set to %u but multi-chip mode is not "
+ "enabled\n", CSS_SGI_CHIP_COUNT);
+ panic();
+ } else if ((plat_arm_sgi_get_multi_chip_mode() == 1) &&
+ (CSS_SGI_CHIP_COUNT > 1)) {
+ INFO("Enabling support for multi-chip in RD-V1-MC\n");
+
+ for (i = 0; i < ARRAY_SIZE(rdv1mc_dynamic_mmap); i++) {
+ ret = mmap_add_dynamic_region(
+ rdv1mc_dynamic_mmap[i].base_pa,
+ rdv1mc_dynamic_mmap[i].base_va,
+ rdv1mc_dynamic_mmap[i].size,
+ rdv1mc_dynamic_mmap[i].attr);
+ if (ret != 0) {
+ ERROR("Failed to add dynamic mmap entry "
+ "(ret=%d)\n", ret);
+ panic();
+ }
+ }
+
+ plat_arm_override_gicr_frames(
+ rdv1mc_multichip_gicr_frames);
+ gic600_multichip_init(&rdv1mc_multichip_data);
+ }
+
+ sgi_bl31_common_platform_setup();
+}
+#endif /* IMAGE_BL31 */
diff --git a/plat/arm/board/rdv1mc/rdv1mc_security.c b/plat/arm/board/rdv1mc/rdv1mc_security.c
new file mode 100644
index 0000000..adc0bf8
--- /dev/null
+++ b/plat/arm/board/rdv1mc/rdv1mc_security.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+/* TZC memory regions for the first chip */
+static const arm_tzc_regions_info_t tzc_regions[] = {
+ ARM_TZC_REGIONS_DEF,
+ {}
+};
+
+#if CSS_SGI_CHIP_COUNT > 1
+static const arm_tzc_regions_info_t tzc_regions_mc[][CSS_SGI_CHIP_COUNT - 1] = {
+ {
+ /* TZC memory regions for second chip */
+ SGI_PLAT_TZC_NS_REMOTE_REGIONS_DEF(1),
+ {}
+ },
+#if CSS_SGI_CHIP_COUNT > 2
+ {
+ /* TZC memory regions for third chip */
+ SGI_PLAT_TZC_NS_REMOTE_REGIONS_DEF(2),
+ {}
+ },
+#endif
+#if CSS_SGI_CHIP_COUNT > 3
+ {
+ /* TZC memory regions for fourth chip */
+ SGI_PLAT_TZC_NS_REMOTE_REGIONS_DEF(3),
+ {}
+ },
+#endif
+};
+#endif /* CSS_SGI_CHIP_COUNT */
+
+/* Initialize the secure environment */
+void plat_arm_security_setup(void)
+{
+ unsigned int i;
+
+ INFO("Configuring TrustZone Controller for Chip 0\n");
+
+ for (i = 0; i < TZC400_COUNT; i++) {
+ arm_tzc400_setup(TZC400_BASE(i), tzc_regions);
+ }
+
+#if CSS_SGI_CHIP_COUNT > 1
+ unsigned int j;
+
+ for (i = 1; i < CSS_SGI_CHIP_COUNT; i++) {
+ INFO("Configuring TrustZone Controller for Chip %u\n", i);
+
+ for (j = 0; j < TZC400_COUNT; j++) {
+ arm_tzc400_setup(CSS_SGI_REMOTE_CHIP_MEM_OFFSET(i)
+ + TZC400_BASE(j), tzc_regions_mc[i-1]);
+ }
+ }
+#endif
+}
diff --git a/plat/arm/board/rdv1mc/rdv1mc_topology.c b/plat/arm/board/rdv1mc/rdv1mc_topology.c
new file mode 100644
index 0000000..4486e5c
--- /dev/null
+++ b/plat/arm/board/rdv1mc/rdv1mc_topology.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
+#include <sgi_variant.h>
+
+/******************************************************************************
+ * The power domain tree descriptor.
+ ******************************************************************************/
+const unsigned char rd_v1_mc_pd_tree_desc_multi_chip[] = {
+ ((PLAT_ARM_CLUSTER_COUNT) * (CSS_SGI_CHIP_COUNT)),
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+#if (CSS_SGI_CHIP_COUNT > 1)
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+#endif
+#if (CSS_SGI_CHIP_COUNT > 2)
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+#endif
+#if (CSS_SGI_CHIP_COUNT > 3)
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER
+#endif
+};
+
+/*******************************************************************************
+ * This function returns the topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ if (plat_arm_sgi_get_multi_chip_mode() == 1)
+ return rd_v1_mc_pd_tree_desc_multi_chip;
+ panic();
+}
+
+/*******************************************************************************
+ * 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[] = {
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x0)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x1)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x2)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x3)),
+#if (CSS_SGI_CHIP_COUNT > 1)
+ (SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x0)),
+ (SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x1)),
+ (SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x2)),
+ (SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x3)),
+#endif
+#if (CSS_SGI_CHIP_COUNT > 2)
+ (SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x0)),
+ (SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x1)),
+ (SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x2)),
+ (SET_SCMI_CHANNEL_ID(0x2) | SET_SCMI_DOMAIN_ID(0x3)),
+#endif
+#if (CSS_SGI_CHIP_COUNT > 3)
+ (SET_SCMI_CHANNEL_ID(0x3) | SET_SCMI_DOMAIN_ID(0x0)),
+ (SET_SCMI_CHANNEL_ID(0x3) | SET_SCMI_DOMAIN_ID(0x1)),
+ (SET_SCMI_CHANNEL_ID(0x3) | SET_SCMI_DOMAIN_ID(0x2)),
+ (SET_SCMI_CHANNEL_ID(0x3) | SET_SCMI_DOMAIN_ID(0x3))
+#endif
+};
diff --git a/plat/arm/board/rdv1mc/rdv1mc_trusted_boot.c b/plat/arm/board/rdv1mc/rdv1mc_trusted_boot.c
new file mode 100644
index 0000000..4592b8f
--- /dev/null
+++ b/plat/arm/board/rdv1mc/rdv1mc_trusted_boot.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * 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)
+{
+ return arm_get_rotpk_info(cookie, key_ptr, key_len, flags);
+}
diff --git a/plat/arm/board/sgi575/fdts/sgi575_fw_config.dts b/plat/arm/board/sgi575/fdts/sgi575_fw_config.dts
new file mode 100644
index 0000000..84fc1ad
--- /dev/null
+++ b/plat/arm/board/sgi575/fdts/sgi575_fw_config.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/tbbr/tbbr_img_def.h>
+
+/dts-v1/;
+
+/ {
+ dtb-registry {
+ compatible = "fconf,dyn_cfg-dtb_registry";
+
+ tb_fw-config {
+ load-address = <0x0 0x4001300>;
+ max-size = <0x200>;
+ id = <TB_FW_CONFIG_ID>;
+ };
+
+ nt_fw-config {
+ load-address = <0x0 0xFEF00000>;
+ max-size = <0x0100000>;
+ id = <NT_FW_CONFIG_ID>;
+ };
+ };
+};
diff --git a/plat/arm/board/sgi575/fdts/sgi575_nt_fw_config.dts b/plat/arm/board/sgi575/fdts/sgi575_nt_fw_config.dts
new file mode 100644
index 0000000..260247a
--- /dev/null
+++ b/plat/arm/board/sgi575/fdts/sgi575_nt_fw_config.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018-2020, 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>;
+ multi-chip-mode = <0x0>;
+ };
+};
diff --git a/plat/arm/board/sgi575/fdts/sgi575_tb_fw_config.dts b/plat/arm/board/sgi575/fdts/sgi575_tb_fw_config.dts
new file mode 100644
index 0000000..49eda27
--- /dev/null
+++ b/plat/arm/board/sgi575/fdts/sgi575_tb_fw_config.dts
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+ tb_fw-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>;
+ };
+};
diff --git a/plat/arm/board/sgi575/include/platform_def.h b/plat/arm/board/sgi575/include/platform_def.h
new file mode 100644
index 0000000..82a38c5
--- /dev/null
+++ b/plat/arm/board/sgi575/include/platform_def.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+
+#include <sgi_sdei.h>
+#include <sgi_soc_platform_def.h>
+
+#define PLAT_ARM_CLUSTER_COUNT U(2)
+#define CSS_SGI_MAX_CPUS_PER_CLUSTER U(4)
+#define CSS_SGI_MAX_PE_PER_CPU U(1)
+
+#define PLAT_CSS_MHU_BASE UL(0x45000000)
+
+/* 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
+
+/* Maximum number of address bits used per chip */
+#define CSS_SGI_ADDR_BITS_PER_CHIP U(36)
+
+/*
+ * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
+ */
+#ifdef __aarch64__
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << CSS_SGI_ADDR_BITS_PER_CHIP)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << CSS_SGI_ADDR_BITS_PER_CHIP)
+#else
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
+#endif
+
+/* GIC related constants */
+#define PLAT_ARM_GICD_BASE UL(0x30000000)
+#define PLAT_ARM_GICC_BASE UL(0x2C000000)
+#define PLAT_ARM_GICR_BASE UL(0x300C0000)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/sgi575/platform.mk b/plat/arm/board/sgi575/platform.mk
new file mode 100644
index 0000000..2f2bf73
--- /dev/null
+++ b/plat/arm/board/sgi575/platform.mk
@@ -0,0 +1,67 @@
+#
+# Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+$(warning Platform ${PLAT} is deprecated. Some of the features might not work as expected)
+
+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
+
+PLAT_BL_COMMON_SOURCES += ${CSS_ENT_BASE}/sgi_plat.c
+
+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 \
+ ${SGI575_BASE}/sgi575_topology.c \
+ drivers/cfi/v2m/v2m_flash.c \
+ lib/utils/mem_region.c \
+ plat/arm/common/arm_nor_psci_mem_protect.c
+
+ifeq (${TRUSTED_BOARD_BOOT}, 1)
+BL1_SOURCES += ${SGI575_BASE}/sgi575_trusted_boot.c
+BL2_SOURCES += ${SGI575_BASE}/sgi575_trusted_boot.c
+endif
+
+# Add the FDT_SOURCES and options for Dynamic Config
+FDT_SOURCES += ${SGI575_BASE}/fdts/${PLAT}_fw_config.dts \
+ ${SGI575_BASE}/fdts/${PLAT}_tb_fw_config.dts
+
+FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_fw_config.dtb
+TB_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb
+
+# Add the FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FW_CONFIG},--fw-config,${FW_CONFIG}))
+# Add the TB_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--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,${NT_FW_CONFIG}))
+
+ifneq ($(CSS_SGI_CHIP_COUNT),1)
+ $(error "Chip count for SGI575 should be 1, currently set to \
+ ${CSS_SGI_CHIP_COUNT}.")
+endif
+
+ifneq ($(CSS_SGI_PLATFORM_VARIANT),0)
+ $(error "CSS_SGI_PLATFORM_VARIANT for SGI575 should always be 0,\
+ currently set to ${CSS_SGI_PLATFORM_VARIANT}.")
+endif
diff --git a/plat/arm/board/sgi575/sgi575_err.c b/plat/arm/board/sgi575/sgi575_err.c
new file mode 100644
index 0000000..21bfcb7
--- /dev/null
+++ b/plat/arm/board/sgi575/sgi575_err.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * sgi575 error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+ while (true) {
+ wfi();
+ }
+}
diff --git a/plat/arm/board/sgi575/sgi575_plat.c b/plat/arm/board/sgi575/sgi575_plat.c
new file mode 100644
index 0000000..dc294e6
--- /dev/null
+++ b/plat/arm/board/sgi575/sgi575_plat.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+#include <sgi_plat.h>
+#include <sgi_variant.h>
+
+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;
+}
+
+unsigned int plat_arm_sgi_get_multi_chip_mode(void)
+{
+ return 0;
+}
+
+void bl31_platform_setup(void)
+{
+ sgi_bl31_common_platform_setup();
+}
diff --git a/plat/arm/board/sgi575/sgi575_security.c b/plat/arm/board/sgi575/sgi575_security.c
new file mode 100644
index 0000000..17d07d1
--- /dev/null
+++ b/plat/arm/board/sgi575/sgi575_security.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <sgi_dmc620_tzc_regions.h>
+
+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[] = {
+ CSS_SGI_DMC620_TZC_REGIONS_DEF
+};
+
+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);
+}
diff --git a/plat/arm/board/sgi575/sgi575_topology.c b/plat/arm/board/sgi575/sgi575_topology.c
new file mode 100644
index 0000000..f7c3856
--- /dev/null
+++ b/plat/arm/board/sgi575/sgi575_topology.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/******************************************************************************
+ * The power domain tree descriptor.
+ ******************************************************************************/
+static const unsigned char sgi575_pd_tree_desc[] = {
+ PLAT_ARM_CLUSTER_COUNT,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER,
+ CSS_SGI_MAX_CPUS_PER_CLUSTER
+};
+
+/*******************************************************************************
+ * This function returns the topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ return sgi575_pd_tree_desc;
+}
+
+/*******************************************************************************
+ * 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[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7
+};
diff --git a/plat/arm/board/sgi575/sgi575_trusted_boot.c b/plat/arm/board/sgi575/sgi575_trusted_boot.c
new file mode 100644
index 0000000..4592b8f
--- /dev/null
+++ b/plat/arm/board/sgi575/sgi575_trusted_boot.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * 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)
+{
+ return arm_get_rotpk_info(cookie, key_ptr, key_len, flags);
+}
diff --git a/plat/arm/board/tc/fdts/tc_fw_config.dts b/plat/arm/board/tc/fdts/tc_fw_config.dts
new file mode 100644
index 0000000..a84c7f8
--- /dev/null
+++ b/plat/arm/board/tc/fdts/tc_fw_config.dts
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/tbbr/tbbr_img_def.h>
+
+/dts-v1/;
+
+/ {
+ dtb-registry {
+ compatible = "fconf,dyn_cfg-dtb_registry";
+
+ tb_fw-config {
+ load-address = <0x0 0x4001300>;
+ max-size = <0x400>;
+ id = <TB_FW_CONFIG_ID>;
+ };
+
+ tos_fw-config {
+ load-address = <0x0 0x04001700>;
+ max-size = <0x1000>;
+ id = <TOS_FW_CONFIG_ID>;
+ };
+
+ hw-config {
+ load-address = <0x0 0x83000000>;
+ max-size = <0x8000>;
+ id = <HW_CONFIG_ID>;
+ };
+ };
+};
diff --git a/plat/arm/board/tc/fdts/tc_spmc_manifest.dts b/plat/arm/board/tc/fdts/tc_spmc_manifest.dts
new file mode 100644
index 0000000..d3a5e1a
--- /dev/null
+++ b/plat/arm/board/tc/fdts/tc_spmc_manifest.dts
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/dts-v1/;
+
+/ {
+ compatible = "arm,ffa-core-manifest-1.0";
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ attribute {
+ spmc_id = <0x8000>;
+ maj_ver = <0x1>;
+ min_ver = <0x1>;
+ exec_state = <0x0>;
+ load_address = <0x0 0xfd000000>;
+ entrypoint = <0x0 0xfd000000>;
+ binary_size = <0x80000>;
+ };
+
+ hypervisor {
+ compatible = "hafnium,hafnium";
+ vm1 {
+ is_ffa_partition;
+ debug_name = "cactus-primary";
+ load_address = <0xfe000000>;
+ vcpu_count = <8>;
+ mem_size = <1048576>;
+ };
+ vm2 {
+ is_ffa_partition;
+ debug_name = "cactus-secondary";
+ load_address = <0xfe100000>;
+ vcpu_count = <8>;
+ mem_size = <1048576>;
+ };
+ vm3 {
+ is_ffa_partition;
+ debug_name = "cactus-tertiary";
+ load_address = <0xfe200000>;
+ vcpu_count = <1>;
+ mem_size = <1048576>;
+ };
+ vm4 {
+ is_ffa_partition;
+ debug_name = "ivy";
+ load_address = <0xfe600000>;
+ vcpu_count = <1>;
+ mem_size = <1048576>;
+ };
+ };
+
+ cpus {
+ #address-cells = <0x2>;
+ #size-cells = <0x0>;
+
+ CPU0:cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x0>;
+ enable-method = "psci";
+ };
+
+ /*
+ * SPMC (Hafnium) requires secondary cpu nodes are declared in
+ * descending order
+ */
+ CPU7:cpu@700 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x700>;
+ enable-method = "psci";
+ };
+
+ CPU6:cpu@600 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x600>;
+ enable-method = "psci";
+ };
+
+ CPU5:cpu@500 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x500>;
+ enable-method = "psci";
+ };
+
+ CPU4:cpu@400 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x400>;
+ enable-method = "psci";
+ };
+
+ CPU3:cpu@300 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x300>;
+ enable-method = "psci";
+ };
+
+ CPU2:cpu@200 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x200>;
+ enable-method = "psci";
+ };
+
+ CPU1:cpu@100 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x100>;
+ enable-method = "psci";
+ };
+ };
+
+ /* 32MB of TC_TZC_DRAM1_BASE */
+ memory@fd000000 {
+ device_type = "memory";
+ reg = <0x0 0xfd000000 0x2000000>;
+ };
+};
diff --git a/plat/arm/board/tc/fdts/tc_spmc_optee_sp_manifest.dts b/plat/arm/board/tc/fdts/tc_spmc_optee_sp_manifest.dts
new file mode 100644
index 0000000..92e2ddd
--- /dev/null
+++ b/plat/arm/board/tc/fdts/tc_spmc_optee_sp_manifest.dts
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/dts-v1/;
+
+/ {
+ compatible = "arm,ffa-core-manifest-1.0";
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ attribute {
+ spmc_id = <0x8000>;
+ maj_ver = <0x1>;
+ min_ver = <0x1>;
+ exec_state = <0x0>;
+ load_address = <0x0 0xfd000000>;
+ entrypoint = <0x0 0xfd000000>;
+ binary_size = <0x80000>;
+ };
+
+ hypervisor {
+ compatible = "hafnium,hafnium";
+ vm1 {
+ is_ffa_partition;
+ debug_name = "op-tee";
+ load_address = <0xfd280000>;
+ vcpu_count = <8>;
+#ifdef TS_SP_FW_CONFIG
+ mem_size = <26738688>; /* 25MB TZC DRAM */
+#else
+ mem_size = <30928896>; /* 29MB TZC DRAM */
+#endif
+ };
+#ifdef TS_SP_FW_CONFIG
+ vm2 {
+ is_ffa_partition;
+ debug_name = "internal-trusted-storage";
+ load_address = <0xfee00000>;
+ vcpu_count = <1>;
+ mem_size = <2097152>; /* 2MB TZC DRAM */
+ };
+ vm3 {
+ is_ffa_partition;
+ debug_name = "crypto";
+ load_address = <0xfec00000>;
+ vcpu_count = <1>;
+ mem_size = <2097152>; /* 2MB TZC DRAM */
+ };
+#endif
+ };
+
+ cpus {
+ #address-cells = <0x2>;
+ #size-cells = <0x0>;
+
+ CPU0:cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x0>;
+ enable-method = "psci";
+ };
+
+ /*
+ * SPMC (Hafnium) requires secondary cpu nodes are declared in
+ * descending order
+ */
+ CPU7:cpu@700 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x700>;
+ enable-method = "psci";
+ };
+
+ CPU6:cpu@600 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x600>;
+ enable-method = "psci";
+ };
+
+ CPU5:cpu@500 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x500>;
+ enable-method = "psci";
+ };
+
+ CPU4:cpu@400 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x400>;
+ enable-method = "psci";
+ };
+
+ CPU3:cpu@300 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x300>;
+ enable-method = "psci";
+ };
+
+ CPU2:cpu@200 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x200>;
+ enable-method = "psci";
+ };
+
+ CPU1:cpu@100 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x100>;
+ enable-method = "psci";
+ };
+ };
+
+ /* 32MB of TC_TZC_DRAM1_BASE */
+ memory@fd000000 {
+ device_type = "memory";
+ reg = <0x0 0xfd000000 0x2000000>;
+ };
+};
diff --git a/plat/arm/board/tc/fdts/tc_tb_fw_config.dts b/plat/arm/board/tc/fdts/tc_tb_fw_config.dts
new file mode 100644
index 0000000..4c6ccef
--- /dev/null
+++ b/plat/arm/board/tc/fdts/tc_tb_fw_config.dts
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/libc/cdefs.h>
+
+/dts-v1/;
+
+/ {
+ tb_fw-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>;
+ };
+
+ secure-partitions {
+ compatible = "arm,sp";
+#ifdef ARM_BL2_SP_LIST_DTS
+ #include __XSTRING(ARM_BL2_SP_LIST_DTS)
+#else
+#ifdef TS_SP_FW_CONFIG
+ internal-trusted-storage {
+ uuid = "dc1eef48-b17a-4ccf-ac8b-dfcff7711b14";
+ load-address = <0xfee00000>;
+ };
+ crypto {
+ uuid = "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0";
+ load-address = <0xfec00000>;
+ };
+#endif
+#if OPTEE_SP_FW_CONFIG
+ op-tee {
+ uuid = "486178e0-e7f8-11e3-bc5e-0002a5d5c51b";
+ load-address = <0xfd280000>;
+ };
+#else
+ cactus-primary {
+ uuid = "b4b5671e-4a90-4fe1-b81f-fb13dae1dacb";
+ load-address = <0xfe000000>;
+ owner = "SiP";
+ };
+
+ cactus-secondary {
+ uuid = "d1582309-f023-47b9-827c-4464f5578fc8";
+ load-address = <0xfe100000>;
+ owner = "Plat";
+ };
+
+ cactus-tertiary {
+ uuid = "79b55c73-1d8c-44b9-8593-61e1770ad8d2";
+ load-address = <0xfe200000>;
+ };
+
+ ivy {
+ uuid = "eaba83d8-baaf-4eaf-8144-f7fdcbe544a7";
+ load-address = <0xfe600000>;
+ owner = "Plat";
+ };
+#endif
+#endif /* ARM_BL2_SP_LIST_DTS */
+ };
+};
diff --git a/plat/arm/board/tc/include/plat_macros.S b/plat/arm/board/tc/include/plat_macros.S
new file mode 100644
index 0000000..6006fa5
--- /dev/null
+++ b/plat/arm/board/tc/include/plat_macros.S
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <arm_macros.S>
+
+/* ---------------------------------------------
+ * 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 */
diff --git a/plat/arm/board/tc/include/platform_def.h b/plat/arm/board/tc/include/platform_def.h
new file mode 100644
index 0000000..bc4f254
--- /dev/null
+++ b/plat/arm/board/tc/include/platform_def.h
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/arm/board/common/board_css_def.h>
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/common/arm_def.h>
+#include <plat/arm/common/arm_spm_def.h>
+#include <plat/arm/css/common/css_def.h>
+#include <plat/arm/soc/common/soc_css_def.h>
+#include <plat/common/common_def.h>
+
+#define PLATFORM_CORE_COUNT 8
+
+#define PLAT_ARM_TRUSTED_SRAM_SIZE 0x00080000 /* 512 KB */
+
+/*
+ * The top 16MB of ARM_DRAM1 is configured as secure access only using the TZC,
+ * its base is ARM_AP_TZC_DRAM1_BASE.
+ *
+ * Reserve 32MB below ARM_AP_TZC_DRAM1_BASE for:
+ * - BL32_BASE when SPD_spmd is enabled
+ * - Region to load Trusted OS
+ */
+#define TC_TZC_DRAM1_BASE (ARM_AP_TZC_DRAM1_BASE - \
+ TC_TZC_DRAM1_SIZE)
+#define TC_TZC_DRAM1_SIZE UL(0x02000000) /* 32 MB */
+#define TC_TZC_DRAM1_END (TC_TZC_DRAM1_BASE + \
+ TC_TZC_DRAM1_SIZE - 1)
+
+#define TC_NS_DRAM1_BASE ARM_DRAM1_BASE
+#define TC_NS_DRAM1_SIZE (ARM_DRAM1_SIZE - \
+ ARM_TZC_DRAM1_SIZE - \
+ TC_TZC_DRAM1_SIZE)
+#define TC_NS_DRAM1_END (TC_NS_DRAM1_BASE + \
+ TC_NS_DRAM1_SIZE - 1)
+
+/*
+ * Mappings for TC DRAM1 (non-secure) and TC TZC DRAM1 (secure)
+ */
+#define TC_MAP_NS_DRAM1 MAP_REGION_FLAT( \
+ TC_NS_DRAM1_BASE, \
+ TC_NS_DRAM1_SIZE, \
+ MT_MEMORY | MT_RW | MT_NS)
+
+
+#define TC_MAP_TZC_DRAM1 MAP_REGION_FLAT( \
+ TC_TZC_DRAM1_BASE, \
+ TC_TZC_DRAM1_SIZE, \
+ MT_MEMORY | MT_RW | MT_SECURE)
+
+#define PLAT_HW_CONFIG_DTB_BASE ULL(0x83000000)
+#define PLAT_HW_CONFIG_DTB_SIZE ULL(0x8000)
+
+#define PLAT_DTB_DRAM_NS MAP_REGION_FLAT( \
+ PLAT_HW_CONFIG_DTB_BASE, \
+ PLAT_HW_CONFIG_DTB_SIZE, \
+ MT_MEMORY | MT_RO | MT_NS)
+/*
+ * Max size of SPMC is 2MB for tc. With SPMD enabled this value corresponds to
+ * max size of BL32 image.
+ */
+#if defined(SPD_spmd)
+#define PLAT_ARM_SPMC_BASE TC_TZC_DRAM1_BASE
+#define PLAT_ARM_SPMC_SIZE UL(0x200000) /* 2 MB */
+#endif
+
+/*
+ * 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 SPM_MM
+# 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 8
+# 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 7
+#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 0xD000
+
+/*
+ * 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. Current size is considering that TRUSTED_BOARD_BOOT
+ * and MEASURED_BOOT is enabled.
+ */
+# define PLAT_ARM_MAX_BL2_SIZE 0x26000
+
+
+/*
+ * 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. Current size is considering that TRUSTED_BOARD_BOOT and
+ * MEASURED_BOOT is enabled.
+ */
+#define PLAT_ARM_MAX_BL31_SIZE 0x47000
+
+/*
+ * 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 SPM_MM
+# define PLATFORM_STACK_SIZE 0x500
+# else
+# define PLATFORM_STACK_SIZE 0x400
+# endif
+#elif defined(IMAGE_BL32)
+# define PLATFORM_STACK_SIZE 0x440
+#endif
+
+/*
+ * In the current implementation the RoT Service request that requires the
+ * biggest message buffer is the RSS_DELEGATED_ATTEST_GET_PLATFORM_TOKEN. The
+ * maximum required buffer size is calculated based on the platform-specific
+ * needs of this request.
+ */
+#define PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE 0x500
+
+#define TC_DEVICE_BASE 0x21000000
+#define TC_DEVICE_SIZE 0x5f000000
+
+// TC_MAP_DEVICE covers different peripherals
+// available to the platform
+#define TC_MAP_DEVICE MAP_REGION_FLAT( \
+ TC_DEVICE_BASE, \
+ TC_DEVICE_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+
+#define TC_FLASH0_RO MAP_REGION_FLAT(V2M_FLASH0_BASE,\
+ V2M_FLASH0_SIZE, \
+ MT_DEVICE | MT_RO | MT_SECURE)
+
+#define PLAT_ARM_NSTIMER_FRAME_ID 0
+
+#if (TARGET_PLATFORM >= 2)
+#define PLAT_ARM_TRUSTED_ROM_BASE 0x1000
+#else
+#define PLAT_ARM_TRUSTED_ROM_BASE 0x0
+#endif
+
+/* PLAT_ARM_TRUSTED_ROM_SIZE 512KB minus ROM base. */
+#define PLAT_ARM_TRUSTED_ROM_SIZE (0x00080000 - PLAT_ARM_TRUSTED_ROM_BASE)
+
+#define PLAT_ARM_NSRAM_BASE 0x06000000
+#define PLAT_ARM_NSRAM_SIZE 0x00080000 /* 512KB */
+
+#define PLAT_ARM_DRAM2_BASE ULL(0x8080000000)
+#define PLAT_ARM_DRAM2_SIZE ULL(0x180000000)
+#define PLAT_ARM_DRAM2_END (PLAT_ARM_DRAM2_BASE + PLAT_ARM_DRAM2_SIZE - 1ULL)
+
+#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 PLAT_ARM_SP_IMAGE_STACK_BASE (PLAT_SP_IMAGE_NS_BUF_BASE + \
+ PLAT_SP_IMAGE_NS_BUF_SIZE)
+
+/*******************************************************************************
+ * 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)
+
+#define PLAT_ARM_SCMI_CHANNEL_COUNT 1
+
+#define PLAT_ARM_CLUSTER_COUNT U(1)
+#define PLAT_MAX_CPUS_PER_CLUSTER U(8)
+#define PLAT_MAX_PE_PER_CPU U(1)
+
+/* Message Handling Unit (MHU) base addresses */
+#define PLAT_CSS_MHU_BASE UL(0x45400000)
+#define PLAT_MHUV2_BASE PLAT_CSS_MHU_BASE
+
+/* TC2: AP<->RSS MHUs */
+#define PLAT_RSS_AP_SND_MHU_BASE UL(0x2A840000)
+#define PLAT_RSS_AP_RCV_MHU_BASE UL(0x2A850000)
+
+#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
+ */
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 36)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 36)
+
+/* GIC related constants */
+#define PLAT_ARM_GICD_BASE UL(0x30000000)
+#define PLAT_ARM_GICC_BASE UL(0x2C000000)
+#define PLAT_ARM_GICR_BASE UL(0x30080000)
+
+/*
+ * 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 0x20000
+
+/*
+ * 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 0x20000
+
+/* TZC Related Constants */
+#define PLAT_ARM_TZC_BASE UL(0x25000000)
+#define PLAT_ARM_TZC_FILTERS TZC_400_REGION_ATTR_FILTER_BIT(0)
+
+#define TZC400_OFFSET UL(0x1000000)
+#define TZC400_COUNT 4
+
+#define TZC400_BASE(n) (PLAT_ARM_TZC_BASE + \
+ (n * TZC400_OFFSET))
+
+#define TZC_NSAID_DEFAULT U(0)
+
+#define PLAT_ARM_TZC_NS_DEV_ACCESS \
+ (TZC_REGION_ACCESS_RDWR(TZC_NSAID_DEFAULT))
+
+/*
+ * The first region below, TC_TZC_DRAM1_BASE (0xfd000000) to
+ * ARM_SCP_TZC_DRAM1_END (0xffffffff) will mark the last 48 MB of DRAM as
+ * secure. The second and third regions gives non secure access to rest of DRAM.
+ */
+#define TC_TZC_REGIONS_DEF \
+ {TC_TZC_DRAM1_BASE, ARM_SCP_TZC_DRAM1_END, \
+ TZC_REGION_S_RDWR, PLAT_ARM_TZC_NS_DEV_ACCESS}, \
+ {TC_NS_DRAM1_BASE, TC_NS_DRAM1_END, ARM_TZC_NS_DRAM_S_ACCESS, \
+ PLAT_ARM_TZC_NS_DEV_ACCESS}, \
+ {PLAT_ARM_DRAM2_BASE, PLAT_ARM_DRAM2_END, \
+ ARM_TZC_NS_DRAM_S_ACCESS, PLAT_ARM_TZC_NS_DEV_ACCESS}
+
+/* virtual address used by dynamic mem_protect for chunk_base */
+#define PLAT_ARM_MEM_PROTEC_VA_FRAME UL(0xc0000000)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/tc/include/tc_helpers.S b/plat/arm/board/tc/include/tc_helpers.S
new file mode 100644
index 0000000..5f54856
--- /dev/null
+++ b/plat/arm/board/tc/include/tc_helpers.S
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+#include <cpu_macros.S>
+
+ .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 TC.
+ *
+ * (ClusterId * PLAT_MAX_CPUS_PER_CLUSTER * PLAT_MAX_PE_PER_CPU) +
+ * (CPUId * PLAT_MAX_PE_PER_CPU) +
+ * ThreadId
+ *
+ * which can be simplified as:
+ *
+ * ((ClusterId * PLAT_MAX_CPUS_PER_CLUSTER + CPUId) * PLAT_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, #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
+ ret
+endfunc plat_reset_handler
diff --git a/plat/arm/board/tc/include/tc_plat.h b/plat/arm/board/tc/include/tc_plat.h
new file mode 100644
index 0000000..28c0308
--- /dev/null
+++ b/plat/arm/board/tc/include/tc_plat.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TC_PLAT_H
+#define TC_PLAT_H
+
+void tc_bl31_common_platform_setup(void);
+
+#endif /* TC_PLAT_H */
diff --git a/plat/arm/board/tc/platform.mk b/plat/arm/board/tc/platform.mk
new file mode 100644
index 0000000..37ba229
--- /dev/null
+++ b/plat/arm/board/tc/platform.mk
@@ -0,0 +1,199 @@
+# Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include common/fdt_wrappers.mk
+
+ifeq ($(TARGET_PLATFORM), 0)
+$(warning Platform ${PLAT}$(TARGET_PLATFORM) is deprecated. \
+Some of the features might not work as expected)
+endif
+
+ifeq ($(shell expr $(TARGET_PLATFORM) \<= 2), 0)
+ $(error TARGET_PLATFORM must be less than or equal to 2)
+endif
+
+$(eval $(call add_define,TARGET_PLATFORM))
+
+CSS_LOAD_SCP_IMAGES := 1
+
+CSS_USE_SCMI_SDS_DRIVER := 1
+
+RAS_EXTENSION := 0
+
+SDEI_SUPPORT := 0
+
+EL3_EXCEPTION_HANDLING := 0
+
+HANDLE_EA_EL3_FIRST_NS := 0
+
+# 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
+
+GIC_ENABLE_V4_EXTN := 1
+
+# GIC-600 configuration
+GICV3_SUPPORT_GIC600 := 1
+
+# Enable SVE
+ENABLE_SVE_FOR_NS := 1
+ENABLE_SVE_FOR_SWD := 1
+
+# enable trace buffer control registers access to NS by default
+ENABLE_TRBE_FOR_NS := 1
+
+# enable trace system registers access to NS by default
+ENABLE_SYS_REG_TRACE_FOR_NS := 1
+
+# enable trace filter control registers access to NS by default
+ENABLE_TRF_FOR_NS := 1
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+ENT_GIC_SOURCES := ${GICV3_SOURCES} \
+ plat/common/plat_gicv3.c \
+ plat/arm/common/arm_gicv3.c
+
+override NEED_BL2U := no
+
+override ARM_PLAT_MT := 1
+
+TC_BASE = plat/arm/board/tc
+
+PLAT_INCLUDES += -I${TC_BASE}/include/
+
+# CPU libraries for TARGET_PLATFORM=0
+ifeq (${TARGET_PLATFORM}, 0)
+TC_CPU_SOURCES += lib/cpus/aarch64/cortex_a510.S \
+ lib/cpus/aarch64/cortex_a710.S \
+ lib/cpus/aarch64/cortex_x2.S
+endif
+
+# CPU libraries for TARGET_PLATFORM=1
+ifeq (${TARGET_PLATFORM}, 1)
+TC_CPU_SOURCES += lib/cpus/aarch64/cortex_a510.S \
+ lib/cpus/aarch64/cortex_a715.S \
+ lib/cpus/aarch64/cortex_x3.S
+endif
+
+# CPU libraries for TARGET_PLATFORM=2
+ifeq (${TARGET_PLATFORM}, 2)
+TC_CPU_SOURCES += lib/cpus/aarch64/cortex_hayes.S \
+ lib/cpus/aarch64/cortex_hunter.S \
+ lib/cpus/aarch64/cortex_hunter_elp_arm.S
+endif
+
+INTERCONNECT_SOURCES := ${TC_BASE}/tc_interconnect.c
+
+PLAT_BL_COMMON_SOURCES += ${TC_BASE}/tc_plat.c \
+ ${TC_BASE}/include/tc_helpers.S
+
+BL1_SOURCES += ${INTERCONNECT_SOURCES} \
+ ${TC_CPU_SOURCES} \
+ ${TC_BASE}/tc_trusted_boot.c \
+ ${TC_BASE}/tc_err.c \
+ drivers/arm/sbsa/sbsa.c
+
+BL2_SOURCES += ${TC_BASE}/tc_security.c \
+ ${TC_BASE}/tc_err.c \
+ ${TC_BASE}/tc_trusted_boot.c \
+ ${TC_BASE}/tc_bl2_setup.c \
+ lib/utils/mem_region.c \
+ drivers/arm/tzc/tzc400.c \
+ plat/arm/common/arm_tzc400.c \
+ plat/arm/common/arm_nor_psci_mem_protect.c
+
+BL31_SOURCES += ${INTERCONNECT_SOURCES} \
+ ${TC_CPU_SOURCES} \
+ ${ENT_GIC_SOURCES} \
+ ${TC_BASE}/tc_bl31_setup.c \
+ ${TC_BASE}/tc_topology.c \
+ lib/fconf/fconf.c \
+ lib/fconf/fconf_dyn_cfg_getter.c \
+ drivers/cfi/v2m/v2m_flash.c \
+ lib/utils/mem_region.c \
+ plat/arm/common/arm_nor_psci_mem_protect.c
+
+BL31_SOURCES += ${FDT_WRAPPERS_SOURCES}
+
+# Add the FDT_SOURCES and options for Dynamic Config
+FDT_SOURCES += ${TC_BASE}/fdts/${PLAT}_fw_config.dts \
+ ${TC_BASE}/fdts/${PLAT}_tb_fw_config.dts
+FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_fw_config.dtb
+TB_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb
+
+# Add the FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FW_CONFIG},--fw-config,${FW_CONFIG}))
+# Add the TB_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--tb-fw-config,${TB_FW_CONFIG}))
+
+ifeq (${SPD},spmd)
+ifeq ($(ARM_SPMC_MANIFEST_DTS),)
+ARM_SPMC_MANIFEST_DTS := ${TC_BASE}/fdts/${PLAT}_spmc_manifest.dts
+endif
+
+FDT_SOURCES += ${ARM_SPMC_MANIFEST_DTS}
+TC_TOS_FW_CONFIG := ${BUILD_PLAT}/fdts/$(notdir $(basename ${ARM_SPMC_MANIFEST_DTS})).dtb
+
+# Add the TOS_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${TC_TOS_FW_CONFIG},--tos-fw-config,${TC_TOS_FW_CONFIG}))
+endif
+
+#Device tree
+TC_HW_CONFIG_DTS := fdts/tc.dts
+TC_HW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}.dtb
+FDT_SOURCES += ${TC_HW_CONFIG_DTS}
+$(eval TC_HW_CONFIG := ${BUILD_PLAT}/$(patsubst %.dts,%.dtb,$(TC_HW_CONFIG_DTS)))
+
+# Add the HW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${TC_HW_CONFIG},--hw-config,${TC_HW_CONFIG}))
+
+override CTX_INCLUDE_AARCH32_REGS := 0
+
+override CTX_INCLUDE_PAUTH_REGS := 1
+
+override ENABLE_SPE_FOR_LOWER_ELS := 0
+
+override ENABLE_AMU := 1
+override ENABLE_AMU_AUXILIARY_COUNTERS := 1
+override ENABLE_AMU_FCONF := 1
+
+override ENABLE_MPMM := 1
+override ENABLE_MPMM_FCONF := 1
+
+# Include Measured Boot makefile before any Crypto library makefile.
+# Crypto library makefile may need default definitions of Measured Boot build
+# flags present in Measured Boot makefile.
+ifeq (${MEASURED_BOOT},1)
+ MEASURED_BOOT_MK := drivers/measured_boot/rss/rss_measured_boot.mk
+ $(info Including ${MEASURED_BOOT_MK})
+ include ${MEASURED_BOOT_MK}
+ $(info Including rss_comms.mk)
+ include drivers/arm/rss/rss_comms.mk
+
+ BL1_SOURCES += ${MEASURED_BOOT_SOURCES} \
+ plat/arm/board/tc/tc_common_measured_boot.c \
+ plat/arm/board/tc/tc_bl1_measured_boot.c \
+ lib/psa/measured_boot.c \
+ ${RSS_COMMS_SOURCES}
+
+ BL2_SOURCES += ${MEASURED_BOOT_SOURCES} \
+ plat/arm/board/tc/tc_common_measured_boot.c \
+ plat/arm/board/tc/tc_bl2_measured_boot.c \
+ lib/psa/measured_boot.c \
+ ${RSS_COMMS_SOURCES}
+
+PLAT_INCLUDES += -Iinclude/lib/psa
+
+endif
+
+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
diff --git a/plat/arm/board/tc/tc_bl1_measured_boot.c b/plat/arm/board/tc/tc_bl1_measured_boot.c
new file mode 100644
index 0000000..0d29c51
--- /dev/null
+++ b/plat/arm/board/tc/tc_bl1_measured_boot.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <drivers/arm/rss_comms.h>
+#include <drivers/measured_boot/rss/rss_measured_boot.h>
+#include <lib/psa/measured_boot.h>
+
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+/* Table with platform specific image IDs and metadata. Intentionally not a
+ * const struct, some members might set by bootloaders during trusted boot.
+ */
+struct rss_mboot_metadata tc_rss_mboot_metadata[] = {
+ {
+ .id = FW_CONFIG_ID,
+ .slot = U(6),
+ .signer_id_size = SIGNER_ID_MIN_SIZE,
+ .sw_type = RSS_MBOOT_FW_CONFIG_STRING,
+ .lock_measurement = true },
+ {
+ .id = TB_FW_CONFIG_ID,
+ .slot = U(7),
+ .signer_id_size = SIGNER_ID_MIN_SIZE,
+ .sw_type = RSS_MBOOT_TB_FW_CONFIG_STRING,
+ .lock_measurement = true },
+ {
+ .id = BL2_IMAGE_ID,
+ .slot = U(8),
+ .signer_id_size = SIGNER_ID_MIN_SIZE,
+ .sw_type = RSS_MBOOT_BL2_STRING,
+ .lock_measurement = true },
+
+ {
+ .id = RSS_MBOOT_INVALID_ID }
+};
+
+void bl1_plat_mboot_init(void)
+{
+ /* Initialize the communication channel between AP and RSS */
+ (void)rss_comms_init(PLAT_RSS_AP_SND_MHU_BASE,
+ PLAT_RSS_AP_RCV_MHU_BASE);
+
+ rss_measured_boot_init();
+}
+
+void bl1_plat_mboot_finish(void)
+{
+ /* Nothing to do. */
+}
diff --git a/plat/arm/board/tc/tc_bl2_measured_boot.c b/plat/arm/board/tc/tc_bl2_measured_boot.c
new file mode 100644
index 0000000..7ea2c2e
--- /dev/null
+++ b/plat/arm/board/tc/tc_bl2_measured_boot.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <drivers/arm/rss_comms.h>
+#include <drivers/measured_boot/rss/rss_measured_boot.h>
+#include <lib/psa/measured_boot.h>
+
+#include <plat/common/common_def.h>
+#include <platform_def.h>
+
+/* TC specific table with image IDs and metadata. Intentionally not a
+ * const struct, some members might set by bootloaders during trusted boot.
+ */
+struct rss_mboot_metadata tc_rss_mboot_metadata[] = {
+ {
+ .id = BL31_IMAGE_ID,
+ .slot = U(9),
+ .signer_id_size = SIGNER_ID_MIN_SIZE,
+ .sw_type = RSS_MBOOT_BL31_STRING,
+ .lock_measurement = true },
+ {
+ .id = HW_CONFIG_ID,
+ .slot = U(10),
+ .signer_id_size = SIGNER_ID_MIN_SIZE,
+ .sw_type = RSS_MBOOT_HW_CONFIG_STRING,
+ .lock_measurement = true },
+ {
+ .id = SOC_FW_CONFIG_ID,
+ .slot = U(11),
+ .signer_id_size = SIGNER_ID_MIN_SIZE,
+ .sw_type = RSS_MBOOT_SOC_FW_CONFIG_STRING,
+ .lock_measurement = true },
+ {
+ .id = RSS_MBOOT_INVALID_ID }
+};
+
+void bl2_plat_mboot_init(void)
+{
+ /* Initialize the communication channel between AP and RSS */
+ (void)rss_comms_init(PLAT_RSS_AP_SND_MHU_BASE,
+ PLAT_RSS_AP_RCV_MHU_BASE);
+
+ rss_measured_boot_init();
+}
+
+void bl2_plat_mboot_finish(void)
+{
+ /* Nothing to do. */
+}
diff --git a/plat/arm/board/tc/tc_bl2_setup.c b/plat/arm/board/tc/tc_bl2_setup.c
new file mode 100644
index 0000000..74ef569
--- /dev/null
+++ b/plat/arm/board/tc/tc_bl2_setup.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2021, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_dyn_cfg_getter.h>
+
+#include <plat/arm/common/plat_arm.h>
+
+/*******************************************************************************
+ * This function returns the list of executable images
+ ******************************************************************************/
+struct bl_params *plat_get_next_bl_params(void)
+{
+ struct bl_params *arm_bl_params = arm_get_next_bl_params();
+
+ const struct dyn_cfg_dtb_info_t *fw_config_info;
+ bl_mem_params_node_t *param_node;
+ uintptr_t fw_config_base = 0U;
+ entry_point_info_t *ep_info;
+
+ /* Get BL31 image node */
+ param_node = get_bl_mem_params_node(BL31_IMAGE_ID);
+ assert(param_node != NULL);
+
+ /* Get fw_config load address */
+ fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, FW_CONFIG_ID);
+ assert(fw_config_info != NULL);
+
+ fw_config_base = fw_config_info->config_addr;
+ assert(fw_config_base != 0U);
+
+ /*
+ * Get the entry point info of BL31 image and override
+ * arg1 of entry point info with fw_config base address
+ */
+ ep_info = &param_node->ep_info;
+ ep_info->args.arg1 = (uint32_t)fw_config_base;
+
+ return arm_bl_params;
+}
diff --git a/plat/arm/board/tc/tc_bl31_setup.c b/plat/arm/board/tc/tc_bl31_setup.c
new file mode 100644
index 0000000..0523ef8
--- /dev/null
+++ b/plat/arm/board/tc/tc_bl31_setup.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <libfdt.h>
+#include <tc_plat.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_mhu_doorbell.h>
+#include <drivers/arm/css/scmi.h>
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_dyn_cfg_getter.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+static scmi_channel_plat_info_t tc_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,
+ }
+};
+
+void bl31_platform_setup(void)
+{
+ tc_bl31_common_platform_setup();
+}
+
+scmi_channel_plat_info_t *plat_css_get_scmi_info(int channel_id)
+{
+
+ return &tc_scmi_plat_info[channel_id];
+
+}
+
+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);
+
+ /* Fill the properties struct with the info from the config dtb */
+ fconf_populate("FW_CONFIG", arg1);
+}
+
+void tc_bl31_common_platform_setup(void)
+{
+ arm_bl31_platform_setup();
+}
+
+const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
+{
+ return css_scmi_override_pm_ops(ops);
+}
+
+void __init bl31_plat_arch_setup(void)
+{
+ arm_bl31_plat_arch_setup();
+
+ /* HW_CONFIG was also loaded by BL2 */
+ const struct dyn_cfg_dtb_info_t *hw_config_info;
+
+ hw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, HW_CONFIG_ID);
+ assert(hw_config_info != NULL);
+
+ fconf_populate("HW_CONFIG", hw_config_info->config_addr);
+}
diff --git a/plat/arm/board/tc/tc_common_measured_boot.c b/plat/arm/board/tc/tc_common_measured_boot.c
new file mode 100644
index 0000000..fe71899
--- /dev/null
+++ b/plat/arm/board/tc/tc_common_measured_boot.c
@@ -0,0 +1,35 @@
+
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <common/desc_image_load.h>
+#include <drivers/measured_boot/rss/rss_measured_boot.h>
+
+extern struct rss_mboot_metadata tc_rss_mboot_metadata[];
+
+struct rss_mboot_metadata *plat_rss_mboot_get_metadata(void)
+{
+ return tc_rss_mboot_metadata;
+}
+
+int plat_mboot_measure_image(unsigned int image_id, image_info_t *image_data)
+{
+ int err;
+
+ /* Calculate image hash and record data in RSS */
+ err = rss_mboot_measure_and_record(image_data->image_base,
+ image_data->image_size,
+ image_id);
+ if (err != 0) {
+ ERROR("%s%s image id %u (%i)\n",
+ "Failed to ", "record in RSS", image_id, err);
+ }
+
+ return err;
+}
diff --git a/plat/arm/board/tc/tc_err.c b/plat/arm/board/tc/tc_err.c
new file mode 100644
index 0000000..9ed7e92
--- /dev/null
+++ b/plat/arm/board/tc/tc_err.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * tc error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+ while (true) {
+ wfi();
+ }
+}
diff --git a/plat/arm/board/tc/tc_interconnect.c b/plat/arm/board/tc/tc_interconnect.c
new file mode 100644
index 0000000..e2fc4e1
--- /dev/null
+++ b/plat/arm/board/tc/tc_interconnect.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * For Total Compute 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)
+{
+}
diff --git a/plat/arm/board/tc/tc_plat.c b/plat/arm/board/tc/tc_plat.c
new file mode 100644
index 0000000..77db023
--- /dev/null
+++ b/plat/arm/board/tc/tc_plat.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <plat/common/platform.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/ccn.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <drivers/arm/sbsa.h>
+
+#if SPM_MM
+#include <services/spm_mm_partition.h>
+#endif
+
+/*
+ * 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,
+ TC_FLASH0_RO,
+ TC_MAP_DEVICE,
+ {0}
+};
+#endif
+#if IMAGE_BL2
+const mmap_region_t plat_arm_mmap[] = {
+ ARM_MAP_SHARED_RAM,
+ TC_FLASH0_RO,
+ TC_MAP_DEVICE,
+ TC_MAP_NS_DRAM1,
+#if defined(SPD_spmd)
+ TC_MAP_TZC_DRAM1,
+#endif
+#if ARM_BL31_IN_DRAM
+ ARM_MAP_BL31_SEC_DRAM,
+#endif
+#if SPM_MM
+ ARM_SP_IMAGE_MMAP,
+#endif
+#if TRUSTED_BOARD_BOOT && !BL2_AT_EL3
+ ARM_MAP_BL1_RW,
+#endif
+#ifdef SPD_opteed
+ ARM_MAP_OPTEE_CORE_MEM,
+ ARM_OPTEE_PAGEABLE_LOAD_MEM,
+#endif
+ {0}
+};
+#endif
+#if IMAGE_BL31
+const mmap_region_t plat_arm_mmap[] = {
+ ARM_MAP_SHARED_RAM,
+ V2M_MAP_IOFPGA,
+ TC_MAP_DEVICE,
+ PLAT_DTB_DRAM_NS,
+#if SPM_MM
+ ARM_SPM_BUF_EL3_MMAP,
+#endif
+ {0}
+};
+
+#if SPM_MM && 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 /* SPM_MM && defined(IMAGE_BL31) */
+#endif
+
+ARM_CASSERT_MMAP
+
+#if SPM_MM && defined(IMAGE_BL31)
+/*
+ * Boot information passed to a secure partition during initialisation. Linear
+ * indices in MP information will be filled at runtime.
+ */
+static spm_mm_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 spm_mm_boot_info_t plat_arm_secure_partition_boot_info = {
+ .h.type = PARAM_SP_IMAGE_BOOT_INFO,
+ .h.version = VERSION_1,
+ .h.size = sizeof(spm_mm_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 spm_mm_boot_info *plat_get_secure_partition_boot_info(
+ void *cookie)
+{
+ return &plat_arm_secure_partition_boot_info;
+}
+#endif /* SPM_MM && defined(IMAGE_BL31) */
+
+#if TRUSTED_BOARD_BOOT || MEASURED_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);
+}
diff --git a/plat/arm/board/tc/tc_security.c b/plat/arm/board/tc/tc_security.c
new file mode 100644
index 0000000..6a34501
--- /dev/null
+++ b/plat/arm/board/tc/tc_security.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+static const arm_tzc_regions_info_t tzc_regions[] = {
+ TC_TZC_REGIONS_DEF,
+ {}
+};
+
+/* Initialize the secure environment */
+void plat_arm_security_setup(void)
+{
+ unsigned int i;
+
+ for (i = 0U; i < TZC400_COUNT; i++) {
+ arm_tzc400_setup(TZC400_BASE(i), tzc_regions);
+ }
+}
diff --git a/plat/arm/board/tc/tc_topology.c b/plat/arm/board/tc/tc_topology.c
new file mode 100644
index 0000000..9e18da6
--- /dev/null
+++ b/plat/arm/board/tc/tc_topology.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
+
+/******************************************************************************
+ * The power domain tree descriptor.
+ ******************************************************************************/
+const unsigned char tc_pd_tree_desc[] = {
+ PLAT_ARM_CLUSTER_COUNT,
+ PLAT_MAX_CPUS_PER_CLUSTER,
+};
+
+/*******************************************************************************
+ * This function returns the topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ return tc_pd_tree_desc;
+}
+
+/*******************************************************************************
+ * 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[] = {
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x0)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x1)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x2)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x3)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x4)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x5)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x6)),
+ (SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x7)),
+};
+
+/*******************************************************************************
+ * 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 PLAT_MAX_CPUS_PER_CLUSTER;
+}
+
+#if ARM_PLAT_MT
+/******************************************************************************
+ * Return the number of PE's supported by the CPU.
+ *****************************************************************************/
+unsigned int plat_arm_get_cpu_pe_count(u_register_t mpidr)
+{
+ return PLAT_MAX_PE_PER_CPU;
+}
+#endif
diff --git a/plat/arm/board/tc/tc_trusted_boot.c b/plat/arm/board/tc/tc_trusted_boot.c
new file mode 100644
index 0000000..614f7e2
--- /dev/null
+++ b/plat/arm/board/tc/tc_trusted_boot.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * 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)
+{
+ return arm_get_rotpk_info(cookie, key_ptr, key_len, flags);
+}
diff --git a/plat/arm/common/aarch32/arm_bl2_mem_params_desc.c b/plat/arm/common/aarch32/arm_bl2_mem_params_desc.c
new file mode 100644
index 0000000..18f1a37
--- /dev/null
+++ b/plat/arm/common/aarch32/arm_bl2_mem_params_desc.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+
+/*******************************************************************************
+ * 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)
diff --git a/plat/arm/common/aarch32/arm_helpers.S b/plat/arm/common/aarch32/arm_helpers.S
new file mode 100644
index 0000000..1da2d4c
--- /dev/null
+++ b/plat/arm/common/aarch32/arm_helpers.S
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .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
+
+ /* ---------------------------------------------
+ * void plat_crash_console_flush()
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * Out : void.
+ * 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
diff --git a/plat/arm/common/aarch64/arm_bl2_mem_params_desc.c b/plat/arm/common/aarch64/arm_bl2_mem_params_desc.c
new file mode 100644
index 0000000..3d7b361
--- /dev/null
+++ b/plat/arm/common/aarch64/arm_bl2_mem_params_desc.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+
+/*******************************************************************************
+ * 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,
+
+# if defined(BL32_BASE)
+ .next_handoff_image_id = BL32_IMAGE_ID,
+# elif ENABLE_RME
+ .next_handoff_image_id = RMM_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,
+ },
+
+# if ENABLE_RME
+ /* Fill RMM related information */
+ {
+ .image_id = RMM_IMAGE_ID,
+ SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+ VERSION_2, entry_point_info_t, EP_REALM | EXECUTABLE),
+ .ep_info.pc = RMM_BASE,
+ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+ VERSION_2, image_info_t, 0),
+ .image_info.image_base = RMM_BASE,
+ .image_info.image_max_size = RMM_LIMIT - RMM_BASE,
+ .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,
+
+# if ENABLE_RME
+ .next_handoff_image_id = RMM_IMAGE_ID,
+# else
+ .next_handoff_image_id = BL33_IMAGE_ID,
+# endif
+ },
+
+ /*
+ * 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)
diff --git a/plat/arm/common/aarch64/arm_helpers.S b/plat/arm/common/aarch64/arm_helpers.S
new file mode 100644
index 0000000..b470781
--- /dev/null
+++ b/plat/arm/common/aarch64/arm_helpers.S
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .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
+
+ /* ---------------------------------------------
+ * void plat_crash_console_flush()
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * Out : void.
+ * 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 */
diff --git a/plat/arm/common/aarch64/arm_pauth.c b/plat/arm/common/aarch64/arm_pauth.c
new file mode 100644
index 0000000..7cea8a0
--- /dev/null
+++ b/plat/arm/common/aarch64/arm_pauth.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <cdefs.h>
+#include <stdint.h>
+
+/*
+ * 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;
+}
diff --git a/plat/arm/common/aarch64/arm_sdei.c b/plat/arm/common/aarch64/arm_sdei.c
new file mode 100644
index 0000000..3c74a46
--- /dev/null
+++ b/plat/arm/common/aarch64/arm_sdei.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* SDEI configuration for ARM platforms */
+
+#include <bl31/ehf.h>
+#include <common/debug.h>
+#include <services/sdei.h>
+
+#if SDEI_IN_FCONF
+#include <plat/arm/common/fconf_sdei_getter.h>
+#endif
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+
+#if SDEI_IN_FCONF
+/* Private event mappings */
+static sdei_ev_map_t arm_sdei_private[PLAT_SDEI_DP_EVENT_MAX_CNT + 1] = { 0 };
+
+/* Shared event mappings */
+static sdei_ev_map_t arm_sdei_shared[PLAT_SDEI_DS_EVENT_MAX_CNT] = { 0 };
+
+void plat_sdei_setup(void)
+{
+ uint32_t i;
+
+ arm_sdei_private[0] = (sdei_ev_map_t)SDEI_DEFINE_EVENT_0(ARM_SDEI_SGI);
+
+ for (i = 0; i < FCONF_GET_PROPERTY(sdei, dyn_config, private_ev_cnt); i++) {
+ arm_sdei_private[i + 1] = (sdei_ev_map_t)SDEI_PRIVATE_EVENT(
+ FCONF_GET_PROPERTY(sdei, dyn_config, private_ev_nums[i]),
+ FCONF_GET_PROPERTY(sdei, dyn_config, private_ev_intrs[i]),
+ FCONF_GET_PROPERTY(sdei, dyn_config, private_ev_flags[i]));
+ }
+
+ for (i = 0; i < FCONF_GET_PROPERTY(sdei, dyn_config, shared_ev_cnt); i++) {
+ arm_sdei_shared[i] = (sdei_ev_map_t)SDEI_SHARED_EVENT( \
+ FCONF_GET_PROPERTY(sdei, dyn_config, shared_ev_nums[i]),
+ FCONF_GET_PROPERTY(sdei, dyn_config, shared_ev_intrs[i]),
+ FCONF_GET_PROPERTY(sdei, dyn_config, shared_ev_flags[i]));
+ }
+ INFO("FCONF: SDEI platform setup\n");
+}
+#else
+/* 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
+};
+
+void plat_sdei_setup(void)
+{
+ INFO("SDEI platform setup\n");
+}
+#endif /* SDEI_IN_FCONF */
+
+/* Export ARM SDEI events */
+REGISTER_SDEI_MAP(arm_sdei_private, arm_sdei_shared);
diff --git a/plat/arm/common/aarch64/execution_state_switch.c b/plat/arm/common/aarch64/execution_state_switch.c
new file mode 100644
index 0000000..2353e6a
--- /dev/null
+++ b/plat/arm/common/aarch64/execution_state_switch.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/psci/psci.h>
+#include <lib/utils.h>
+#include <plat/arm/common/plat_arm.h>
+#include <smccc_helpers.h>
+
+/*
+ * 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)
+{
+ 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);
+
+ /* Validate supplied entry point */
+ pc = (u_register_t) (((uint64_t) pc_hi << 32) | pc_lo);
+ if (arm_validate_ns_entrypoint(pc) != 0)
+ goto invalid_param;
+
+ /* 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_ns();
+
+ /*
+ * 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:
+ /* State switch denied */
+ SMC_RET1(handle, STATE_SW_E_DENIED);
+}
diff --git a/plat/arm/common/arm_bl1_fwu.c b/plat/arm/common/arm_bl1_fwu.c
new file mode 100644
index 0000000..ce2c356
--- /dev/null
+++ b/plat/arm/common/arm_bl1_fwu.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <bl1/tbbr/tbbr_img_desc.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/utils.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#pragma weak bl1_plat_get_image_desc
+
+/* 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;
+}
diff --git a/plat/arm/common/arm_bl1_setup.c b/plat/arm/common/arm_bl1_setup.c
new file mode 100644
index 0000000..7000236
--- /dev/null
+++ b/plat/arm/common/arm_bl1_setup.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_dyn_cfg_getter.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/* 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 arm_bl1_early_platform_setup
+#pragma weak bl1_plat_prepare_exit
+#pragma weak bl1_plat_get_next_image_id
+#pragma weak plat_arm_bl1_fwu_needed
+#pragma weak arm_bl1_plat_arch_setup
+#pragma weak arm_bl1_platform_setup
+
+#define MAP_BL1_TOTAL MAP_REGION_FLAT( \
+ bl1_tzram_layout.total_base, \
+ bl1_tzram_layout.total_size, \
+ MT_MEMORY | MT_RW | EL3_PAS)
+/*
+ * 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 | EL3_PAS), \
+ MAP_REGION_FLAT( \
+ BL1_RO_DATA_BASE, \
+ BL1_RO_DATA_END \
+ - BL_RO_DATA_BASE, \
+ MT_RO_DATA | EL3_PAS)
+#else
+#define MAP_BL1_RO MAP_REGION_FLAT( \
+ BL_CODE_BASE, \
+ BL1_CODE_END - BL_CODE_BASE, \
+ MT_CODE | EL3_PAS)
+#endif
+
+/* Data structure which holds the extents of the trusted SRAM for BL1*/
+static meminfo_t bl1_tzram_layout;
+
+/* Boolean variable to hold condition whether firmware update needed or not */
+static bool is_fwu_needed;
+
+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)
+{
+ const struct dyn_cfg_dtb_info_t *fw_config_info;
+ image_desc_t *desc;
+ uint32_t fw_config_max_size;
+ int err = -1;
+
+ /* Initialise the IO layer and register platform IO devices */
+ plat_arm_io_setup();
+
+ /* Check if we need FWU before further processing */
+ is_fwu_needed = plat_arm_bl1_fwu_needed();
+ if (is_fwu_needed) {
+ ERROR("Skip platform setup as FWU detected\n");
+ return;
+ }
+
+ /* Set global DTB info for fixed fw_config information */
+ fw_config_max_size = ARM_FW_CONFIG_LIMIT - ARM_FW_CONFIG_BASE;
+ set_config_info(ARM_FW_CONFIG_BASE, ~0UL, fw_config_max_size, FW_CONFIG_ID);
+
+ /* Fill the device tree information struct with the info from the config dtb */
+ err = fconf_load_config(FW_CONFIG_ID);
+ if (err < 0) {
+ ERROR("Loading of FW_CONFIG failed %d\n", err);
+ plat_error_handler(err);
+ }
+
+ /*
+ * FW_CONFIG loaded successfully. If FW_CONFIG device tree parsing
+ * is successful then load TB_FW_CONFIG device tree.
+ */
+ fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, FW_CONFIG_ID);
+ if (fw_config_info != NULL) {
+ err = fconf_populate_dtb_registry(fw_config_info->config_addr);
+ if (err < 0) {
+ ERROR("Parsing of FW_CONFIG failed %d\n", err);
+ plat_error_handler(err);
+ }
+ /* load TB_FW_CONFIG */
+ err = fconf_load_config(TB_FW_CONFIG_ID);
+ if (err < 0) {
+ ERROR("Loading of TB_FW_CONFIG failed %d\n", err);
+ plat_error_handler(err);
+ }
+ } else {
+ ERROR("Invalid FW_CONFIG address\n");
+ plat_error_handler(err);
+ }
+
+ /* The BL2 ep_info arg0 is modified to point to FW_CONFIG */
+ desc = bl1_plat_get_image_desc(BL2_IMAGE_ID);
+ assert(desc != NULL);
+ desc->ep_info.args.arg0 = fw_config_info->config_addr;
+
+#if CRYPTO_SUPPORT
+ /* Share the Mbed TLS heap info with other images */
+ arm_bl1_set_mbedtls_heap();
+#endif /* CRYPTO_SUPPORT */
+
+ /*
+ * 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.
+ */
+bool plat_arm_bl1_fwu_needed(void)
+{
+ return !arm_io_is_toc_valid();
+}
+
+/*******************************************************************************
+ * 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)
+{
+ return is_fwu_needed ? NS_BL1U_IMAGE_ID : BL2_IMAGE_ID;
+}
diff --git a/plat/arm/common/arm_bl2_el3_setup.c b/plat/arm/common/arm_bl2_el3_setup.c
new file mode 100644
index 0000000..97b5a88
--- /dev/null
+++ b/plat/arm/common/arm_bl2_el3_setup.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <drivers/generic_delay_timer.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#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)
+{
+}
diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
new file mode 100644
index 0000000..08c014d
--- /dev/null
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/partition/partition.h>
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_dyn_cfg_getter.h>
+#if ENABLE_RME
+#include <lib/gpt_rme/gpt_rme.h>
+#endif /* ENABLE_RME */
+#ifdef SPD_opteed
+#include <lib/optee_utils.h>
+#endif
+#include <lib/utils.h>
+#if ENABLE_RME
+#include <plat/arm/common/arm_pas_def.h>
+#endif /* ENABLE_RME */
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/* Data structure which holds the extents of the trusted SRAM for BL2 */
+static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
+
+/* Base address of fw_config received from BL1 */
+static uintptr_t config_base;
+
+/*
+ * Check that BL2_BASE is above ARM_FW_CONFIG_LIMIT. This reserved page is
+ * for `meminfo_t` data structure and fw_configs passed from BL1.
+ */
+CASSERT(BL2_BASE >= ARM_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
+
+#if ENABLE_RME
+#define MAP_BL2_TOTAL MAP_REGION_FLAT( \
+ bl2_tzram_layout.total_base, \
+ bl2_tzram_layout.total_size, \
+ MT_MEMORY | MT_RW | MT_ROOT)
+#else
+#define MAP_BL2_TOTAL MAP_REGION_FLAT( \
+ bl2_tzram_layout.total_base, \
+ bl2_tzram_layout.total_size, \
+ MT_MEMORY | MT_RW | MT_SECURE)
+#endif /* ENABLE_RME */
+
+#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 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;
+
+ config_base = fw_config;
+
+ /* Initialise the IO layer and register platform IO devices */
+ plat_arm_io_setup();
+
+ /* Load partition table */
+#if ARM_GPT_SUPPORT
+ partition_init(GPT_IMAGE_ID);
+#endif /* ARM_GPT_SUPPORT */
+
+}
+
+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();
+
+#if ARM_GPT_SUPPORT && !PSA_FWU_SUPPORT
+ /* Always use the FIP from bank 0 */
+ arm_set_fip_addr(0U);
+#endif /* ARM_GPT_SUPPORT && !PSA_FWU_SUPPORT */
+}
+
+/*
+ * Perform ARM standard platform setup.
+ */
+void arm_bl2_platform_setup(void)
+{
+#if !ENABLE_RME
+ /* Initialize the secure environment */
+ plat_arm_security_setup();
+#endif
+
+#if defined(PLAT_ARM_MEM_PROT_ADDR)
+ arm_nor_psci_do_static_mem_protect();
+#endif
+}
+
+void bl2_platform_setup(void)
+{
+ arm_bl2_platform_setup();
+}
+
+#if ENABLE_RME
+
+static void arm_bl2_plat_gpt_setup(void)
+{
+ /*
+ * The GPT library might modify the gpt regions structure to optimize
+ * the layout, so the array cannot be constant.
+ */
+ pas_region_t pas_regions[] = {
+ ARM_PAS_KERNEL,
+ ARM_PAS_SECURE,
+ ARM_PAS_REALM,
+ ARM_PAS_EL3_DRAM,
+ ARM_PAS_GPTS
+ };
+
+ /* Initialize entire protected space to GPT_GPI_ANY. */
+ if (gpt_init_l0_tables(GPCCR_PPS_4GB, ARM_L0_GPT_ADDR_BASE,
+ ARM_L0_GPT_SIZE) < 0) {
+ ERROR("gpt_init_l0_tables() failed!\n");
+ panic();
+ }
+
+ /* Carve out defined PAS ranges. */
+ if (gpt_init_pas_l1_tables(GPCCR_PGS_4K,
+ ARM_L1_GPT_ADDR_BASE,
+ ARM_L1_GPT_SIZE,
+ pas_regions,
+ (unsigned int)(sizeof(pas_regions) /
+ sizeof(pas_region_t))) < 0) {
+ ERROR("gpt_init_pas_l1_tables() failed!\n");
+ panic();
+ }
+
+ INFO("Enabling Granule Protection Checks\n");
+ if (gpt_enable() < 0) {
+ ERROR("gpt_enable() failed!\n");
+ panic();
+ }
+}
+
+#endif /* ENABLE_RME */
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here.
+ * When RME is enabled the secure environment is initialised before
+ * initialising and enabling Granule Protection.
+ * This function initialises 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
+ ARM_MAP_BL_CONFIG_REGION,
+#if ENABLE_RME
+ ARM_MAP_L0_GPT_REGION,
+#endif
+ {0}
+ };
+
+#if ENABLE_RME
+ /* Initialise the secure environment */
+ plat_arm_security_setup();
+#endif
+ setup_page_tables(bl_regions, plat_arm_get_mmap());
+
+#ifdef __aarch64__
+#if ENABLE_RME
+ /* BL2 runs in EL3 when RME enabled. */
+ assert(get_armv9_2_feat_rme_support() != 0U);
+ enable_mmu_el3(0);
+
+ /* Initialise and enable granule protection after MMU. */
+ arm_bl2_plat_gpt_setup();
+#else
+ enable_mmu_el1(0);
+#endif
+#else
+ enable_mmu_svc_mon(0);
+#endif
+
+ arm_setup_romlib();
+}
+
+void bl2_plat_arch_setup(void)
+{
+ const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
+
+ arm_bl2_plat_arch_setup();
+
+ /* Fill the properties struct with the info from the config dtb */
+ fconf_populate("FW_CONFIG", config_base);
+
+ /* TB_FW_CONFIG was also loaded by BL1 */
+ tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
+ assert(tb_fw_config_info != NULL);
+
+ fconf_populate("TB_FW", tb_fw_config_info->config_addr);
+}
+
+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 != NULL);
+
+ 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)
+{
+#if defined(SPD_spmd) && BL2_ENABLE_SP_LOAD
+ /* For Secure Partitions we don't need post processing */
+ if ((image_id >= (MAX_NUMBER_IDS - MAX_SP_IDS)) &&
+ (image_id < MAX_NUMBER_IDS)) {
+ return 0;
+ }
+#endif
+ 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);
+}
diff --git a/plat/arm/common/arm_bl2u_setup.c b/plat/arm/common/arm_bl2u_setup.c
new file mode 100644
index 0000000..3614c7d
--- /dev/null
+++ b/plat/arm/common/arm_bl2u_setup.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <drivers/generic_delay_timer.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/* 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();
+}
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
new file mode 100644
index 0000000..cf403b1
--- /dev/null
+++ b/plat/arm/common/arm_bl31_setup.c
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/debugfs.h>
+#include <lib/extensions/ras.h>
+#if ENABLE_RME
+#include <lib/gpt_rme/gpt_rme.h>
+#endif
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.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;
+#if ENABLE_RME
+static entry_point_info_t rmm_image_ep_info;
+#endif
+
+#if !RESET_TO_BL31
+/*
+ * Check that BL31_BASE is above ARM_FW_CONFIG_LIMIT. The reserved page
+ * is required for SOC_FW_CONFIG/TOS_FW_CONFIG passed from BL2.
+ */
+CASSERT(BL31_BASE >= ARM_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 | EL3_PAS)
+#if RECLAIM_INIT_CODE
+IMPORT_SYM(unsigned long, __INIT_CODE_START__, BL_INIT_CODE_BASE);
+IMPORT_SYM(unsigned long, __INIT_CODE_END__, BL_CODE_END_UNALIGNED);
+IMPORT_SYM(unsigned long, __STACKS_END__, BL_STACKS_END_UNALIGNED);
+
+#define BL_INIT_CODE_END ((BL_CODE_END_UNALIGNED + PAGE_SIZE - 1) & \
+ ~(PAGE_SIZE - 1))
+#define BL_STACKS_END ((BL_STACKS_END_UNALIGNED + PAGE_SIZE - 1) & \
+ ~(PAGE_SIZE - 1))
+
+#define MAP_BL_INIT_CODE MAP_REGION_FLAT( \
+ BL_INIT_CODE_BASE, \
+ BL_INIT_CODE_END \
+ - BL_INIT_CODE_BASE, \
+ MT_CODE | EL3_PAS)
+#endif
+
+#if SEPARATE_NOBITS_REGION
+#define MAP_BL31_NOBITS MAP_REGION_FLAT( \
+ BL31_NOBITS_BASE, \
+ BL31_NOBITS_LIMIT \
+ - BL31_NOBITS_BASE, \
+ MT_MEMORY | MT_RW | EL3_PAS)
+
+#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));
+ if (type == NON_SECURE) {
+ next_image_info = &bl33_image_ep_info;
+ }
+#if ENABLE_RME
+ else if (type == REALM) {
+ next_image_info = &rmm_image_ep_info;
+ }
+#endif
+ else {
+ next_image_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();
+
+#if defined(SPD_spmd)
+ /* SPM (hafnium in secure world) expects SPM Core manifest base address
+ * in x0, which in !RESET_TO_BL31 case loaded after base of non shared
+ * SRAM(after 4KB offset of SRAM). But in RESET_TO_BL31 case all non
+ * shared SRAM is allocated to BL31, so to avoid overwriting of manifest
+ * keep it in the last page.
+ */
+ bl32_image_ep_info.args.arg0 = ARM_TRUSTED_SRAM_BASE +
+ PLAT_ARM_TRUSTED_SRAM_SIZE - PAGE_SIZE;
+#endif
+
+# 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 ENABLE_RME
+ /*
+ * Populate entry point information for RMM.
+ * Only PC needs to be set as other fields are determined by RMMD.
+ */
+ rmm_image_ep_info.pc = RMM_BASE;
+#endif /* ENABLE_RME */
+
+#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, BL32 and RMM (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 ENABLE_RME
+ else if (bl_params->image_id == RMM_IMAGE_ID) {
+ rmm_image_ep_info = *bl_params->ep_info;
+ }
+#endif
+ else 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();
+#if ENABLE_RME
+ if (rmm_image_ep_info.pc == 0U)
+ panic();
+#endif
+#endif /* RESET_TO_BL31 */
+
+# 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.
+ * Repurpose the option to load Hafnium hypervisor in the normal world.
+ * It expects its manifest address in x0. This is essentially the linux
+ * dts (passed to the primary VM) by adding 'hypervisor' and chosen
+ * nodes specifying the Hypervisor configuration.
+ */
+#if RESET_TO_BL31
+ bl33_image_ep_info.args.arg0 = (u_register_t)ARM_PRELOADED_DTB_BASE;
+#else
+ bl33_image_ep_info.args.arg0 = (u_register_t)hw_config;
+#endif
+ bl33_image_ep_info.args.arg1 = 0U;
+ bl33_image_ep_info.args.arg2 = 0U;
+ bl33_image_ep_info.args.arg3 = 0U;
+# endif
+}
+
+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
+
+#if USE_DEBUGFS
+ debugfs_init();
+#endif /* USE_DEBUGFS */
+}
+
+/*******************************************************************************
+ * 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 PLAT_RO_XLAT_TABLES
+ arm_xlat_make_tables_readonly();
+#endif
+}
+
+#if RECLAIM_INIT_CODE
+/*
+ * Make memory for image boot time code RW to reclaim it as stack for the
+ * secondary cores, or RO where it cannot be reclaimed:
+ *
+ * |-------- INIT SECTION --------|
+ * -----------------------------------------
+ * | CORE 0 | CORE 1 | CORE 2 | EXTRA |
+ * | STACK | STACK | STACK | SPACE |
+ * -----------------------------------------
+ * <-------------------> <------>
+ * MAKE RW AND XN MAKE
+ * FOR STACKS RO AND XN
+ */
+void arm_free_init_memory(void)
+{
+ int ret = 0;
+
+ if (BL_STACKS_END < BL_INIT_CODE_END) {
+ /* Reclaim some of the init section as stack if possible. */
+ if (BL_INIT_CODE_BASE < BL_STACKS_END) {
+ ret |= xlat_change_mem_attributes(BL_INIT_CODE_BASE,
+ BL_STACKS_END - BL_INIT_CODE_BASE,
+ MT_RW_DATA);
+ }
+ /* Make the rest of the init section read-only. */
+ ret |= xlat_change_mem_attributes(BL_STACKS_END,
+ BL_INIT_CODE_END - BL_STACKS_END,
+ MT_RO_DATA);
+ } else {
+ /* The stacks cover the init section, so reclaim it all. */
+ 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 ENABLE_RME
+ ARM_MAP_L0_GPT_REGION,
+#endif
+#if RECLAIM_INIT_CODE
+ MAP_BL_INIT_CODE,
+#endif
+#if SEPARATE_NOBITS_REGION
+ MAP_BL31_NOBITS,
+#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);
+
+#if ENABLE_RME
+ /*
+ * Initialise Granule Protection library and enable GPC for the primary
+ * processor. The tables have already been initialized by a previous BL
+ * stage, so there is no need to provide any PAS here. This function
+ * sets up pointers to those tables.
+ */
+ if (gpt_runtime_init() < 0) {
+ ERROR("gpt_runtime_init() failed!\n");
+ panic();
+ }
+#endif /* ENABLE_RME */
+
+ arm_setup_romlib();
+}
+
+void __init bl31_plat_arch_setup(void)
+{
+ arm_bl31_plat_arch_setup();
+}
diff --git a/plat/arm/common/arm_cci.c b/plat/arm/common/arm_cci.c
new file mode 100644
index 0000000..3795fc5
--- /dev/null
+++ b/plat/arm/common/arm_cci.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <drivers/arm/cci.h>
+#include <lib/utils.h>
+#include <plat/arm/common/plat_arm.h>
+
+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()));
+}
diff --git a/plat/arm/common/arm_ccn.c b/plat/arm/common/arm_ccn.c
new file mode 100644
index 0000000..2e681ca
--- /dev/null
+++ b/plat/arm/common/arm_ccn.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <drivers/arm/ccn.h>
+#include <plat/arm/common/plat_arm.h>
+
+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()));
+}
diff --git a/plat/arm/common/arm_common.c b/plat/arm/common/arm_common.c
new file mode 100644
index 0000000..fc68114
--- /dev/null
+++ b/plat/arm/common/arm_common.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/romlib.h>
+#include <lib/mmio.h>
+#include <lib/smccc.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+#include <services/arm_arch_svc.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/* 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
+
+/* Get ARM SOC-ID */
+#pragma weak plat_arm_get_soc_id
+
+/*******************************************************************************
+ * Changes the memory attributes for the region of mapped memory where the BL
+ * image's translation tables are located such that the tables will have
+ * read-only permissions.
+ ******************************************************************************/
+#if PLAT_RO_XLAT_TABLES
+void arm_xlat_make_tables_readonly(void)
+{
+ int rc = xlat_make_tables_readonly();
+
+ if (rc != 0) {
+ ERROR("Failed to make translation tables read-only at EL%u.\n",
+ get_current_el());
+ panic();
+ }
+
+ INFO("Translation tables are now read-only at EL%u.\n",
+ get_current_el());
+}
+#endif
+
+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((uint64_t)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) || defined(PLAT_morello)
+ /*
+ * Initialize CNTFRQ register in Non-secure CNTBase frame.
+ * This is required for Juno, N1SDP and Morello 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;
+ u_register_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.
+ */
+ AT(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
+
+const mmap_region_t *plat_get_addr_mmap(void)
+{
+ return plat_arm_mmap;
+}
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
new file mode 100644
index 0000000..7162ce9
--- /dev/null
+++ b/plat/arm/common/arm_common.mk
@@ -0,0 +1,456 @@
+#
+# Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include common/fdt_wrappers.mk
+
+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 or ENABLE_RME is set
+ARM_DISABLE_TRUSTED_WDOG := 0
+ifneq ($(filter 1,${SPIN_ON_BL1_EXIT} ${ENABLE_RME}),)
+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))
+
+# As per CCA security model, all root firmware must execute from on-chip secure
+# memory. This means we must not run BL31 from TZC-protected DRAM.
+ifeq (${ARM_BL31_IN_DRAM},1)
+ ifeq (${ENABLE_RME},1)
+ $(error "BL31 must not run from DRAM on RME-systems. Please set ARM_BL31_IN_DRAM to 0")
+ endif
+endif
+
+# 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)
+ ifneq (${ARCH},aarch64)
+ 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
+ ifeq (${RESET_TO_BL31},1)
+ ifndef ARM_PRELOADED_DTB_BASE
+ $(error "ARM_PRELOADED_DTB_BASE must be set if ARM_LINUX_KERNEL_AS_BL33 is
+ used with RESET_TO_BL31.")
+ endif
+ $(eval $(call add_define,ARM_PRELOADED_DTB_BASE))
+ endif
+endif
+
+# Arm(R) Ethos(TM)-N NPU SiP service
+ARM_ETHOSN_NPU_DRIVER := 0
+$(eval $(call assert_boolean,ARM_ETHOSN_NPU_DRIVER))
+$(eval $(call add_define,ARM_ETHOSN_NPU_DRIVER))
+
+# 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
+
+# Override the standard libc with optimised libc_asm
+OVERRIDE_LIBC := 1
+ifeq (${OVERRIDE_LIBC},1)
+ include lib/libc/libc_asm.mk
+endif
+
+# 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
+
+# On ARM platforms, disable SEPARATE_NOBITS_REGION by default. Both PROGBITS
+# and NOBITS sections of BL31 image are adjacent to each other and loaded
+# into Trusted SRAM.
+SEPARATE_NOBITS_REGION := 0
+
+# In order to support SEPARATE_NOBITS_REGION for Arm platforms, we need to load
+# BL31 PROGBITS into secure DRAM space and BL31 NOBITS into SRAM. Hence mandate
+# the build to require that ARM_BL31_IN_DRAM is enabled as well.
+ifeq ($(SEPARATE_NOBITS_REGION),1)
+ ifneq ($(ARM_BL31_IN_DRAM),1)
+ $(error For SEPARATE_NOBITS_REGION, ARM_BL31_IN_DRAM must be enabled)
+ endif
+ ifneq ($(RECLAIM_INIT_CODE),0)
+ $(error For SEPARATE_NOBITS_REGION, RECLAIM_INIT_CODE cannot be supported)
+ endif
+endif
+
+# Disable ARM Cryptocell by default
+ARM_CRYPTOCELL_INTEG := 0
+$(eval $(call assert_boolean,ARM_CRYPTOCELL_INTEG))
+$(eval $(call add_define,ARM_CRYPTOCELL_INTEG))
+
+# Enable PIE support for RESET_TO_BL31/RESET_TO_SP_MIN case
+ifneq ($(filter 1,${RESET_TO_BL31} ${RESET_TO_SP_MIN}),)
+ ENABLE_PIE := 1
+endif
+
+# 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
+
+# Disable GPT parser support, use FIP image by default
+ARM_GPT_SUPPORT := 0
+$(eval $(call assert_boolean,ARM_GPT_SUPPORT))
+$(eval $(call add_define,ARM_GPT_SUPPORT))
+
+# Include necessary sources to parse GPT image
+ifeq (${ARM_GPT_SUPPORT}, 1)
+ BL2_SOURCES += drivers/partition/gpt.c \
+ drivers/partition/partition.c
+endif
+
+# Enable CRC instructions via extension for ARMv8-A CPUs.
+# For ARMv8.1-A, and onwards CRC instructions are default enabled.
+# Enable HW computed CRC support unconditionally in BL2 component.
+ifeq (${ARM_ARCH_MAJOR},8)
+ ifeq (${ARM_ARCH_MINOR},0)
+ BL2_CPPFLAGS += -march=armv8-a+crc
+ endif
+endif
+
+ifeq ($(PSA_FWU_SUPPORT),1)
+ # GPT support is recommended as per PSA FWU specification hence
+ # PSA FWU implementation is tightly coupled with GPT support,
+ # and it does not support other formats.
+ ifneq ($(ARM_GPT_SUPPORT),1)
+ $(error For PSA_FWU_SUPPORT, ARM_GPT_SUPPORT must be enabled)
+ endif
+ FWU_MK := drivers/fwu/fwu.mk
+ $(info Including ${FWU_MK})
+ include ${FWU_MK}
+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
+ifeq (${XLAT_MPU_LIB_V1}, 1)
+include lib/xlat_mpu/xlat_mpu.mk
+PLAT_BL_COMMON_SOURCES += ${XLAT_MPU_LIB_V1_SRCS}
+else
+include lib/xlat_tables_v2/xlat_tables.mk
+PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS}
+endif
+endif
+
+ARM_IO_SOURCES += plat/arm/common/arm_io_storage.c \
+ plat/arm/common/fconf/arm_fconf_io.c
+ifeq (${SPD},spmd)
+ ifeq (${BL2_ENABLE_SP_LOAD},1)
+ ARM_IO_SOURCES += plat/arm/common/fconf/arm_fconf_sp.c
+ endif
+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 \
+ ${ARM_IO_SOURCES}
+
+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 \
+ common/tf_crc32.c \
+ ${ARM_IO_SOURCES}
+
+# Firmware Configuration Framework sources
+include lib/fconf/fconf.mk
+
+BL1_SOURCES += ${FCONF_SOURCES} ${FCONF_DYN_SOURCES}
+BL2_SOURCES += ${FCONF_SOURCES} ${FCONF_DYN_SOURCES}
+
+# 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/uuid.c
+
+DYN_CFG_SOURCES += ${FDT_WRAPPERS_SOURCES}
+
+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
+ifneq (${PLAT}, corstone1000)
+BL2_SOURCES += plat/arm/common/${ARCH}/arm_bl2_mem_params_desc.c
+endif
+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/common/plat_psci_common.c
+
+ifneq ($(filter 1,${ENABLE_PMF} ${ARM_ETHOSN_NPU_DRIVER}),)
+ARM_SVC_HANDLER_SRCS :=
+
+ifeq (${ENABLE_PMF},1)
+ARM_SVC_HANDLER_SRCS += lib/pmf/pmf_smc.c
+endif
+
+ifeq (${ARM_ETHOSN_NPU_DRIVER},1)
+ARM_SVC_HANDLER_SRCS += plat/arm/common/fconf/fconf_ethosn_getter.c \
+ drivers/delay_timer/delay_timer.c \
+ drivers/arm/ethosn/ethosn_smc.c
+endif
+
+ifeq (${ARCH}, aarch64)
+BL31_SOURCES += plat/arm/common/aarch64/execution_state_switch.c\
+ plat/arm/common/arm_sip_svc.c \
+ ${ARM_SVC_HANDLER_SRCS}
+else
+BL32_SOURCES += plat/arm/common/arm_sip_svc.c \
+ ${ARM_SVC_HANDLER_SRCS}
+endif
+endif
+
+ifeq (${EL3_EXCEPTION_HANDLING},1)
+BL31_SOURCES += plat/common/aarch64/plat_ehf.c
+endif
+
+ifeq (${SDEI_SUPPORT},1)
+BL31_SOURCES += plat/arm/common/aarch64/arm_sdei.c
+ifeq (${SDEI_IN_FCONF},1)
+BL31_SOURCES += plat/arm/common/fconf/fconf_sdei_getter.c
+endif
+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
+
+ifeq (${SPD},spmd)
+BL31_SOURCES += plat/common/plat_spmd_manifest.c \
+ common/uuid.c \
+ ${LIBFDT_SRCS}
+
+BL31_SOURCES += ${FDT_WRAPPERS_SOURCES}
+endif
+
+ifeq (${DRTM_SUPPORT},1)
+BL31_SOURCES += plat/arm/common/arm_err.c
+endif
+
+ifneq (${TRUSTED_BOARD_BOOT},0)
+
+ # Include common TBB sources
+ AUTH_SOURCES := drivers/auth/auth_mod.c \
+ drivers/auth/img_parser_mod.c
+
+ # Include the selected chain of trust sources.
+ ifeq (${COT},tbbr)
+ BL1_SOURCES += drivers/auth/tbbr/tbbr_cot_common.c \
+ drivers/auth/tbbr/tbbr_cot_bl1.c
+ ifneq (${COT_DESC_IN_DTB},0)
+ BL2_SOURCES += lib/fconf/fconf_cot_getter.c
+ else
+ BL2_SOURCES += drivers/auth/tbbr/tbbr_cot_common.c \
+ drivers/auth/tbbr/tbbr_cot_bl2.c
+ endif
+ else ifeq (${COT},dualroot)
+ AUTH_SOURCES += drivers/auth/dualroot/cot.c
+ else ifeq (${COT},cca)
+ AUTH_SOURCES += drivers/auth/cca/cot.c
+ else
+ $(error Unknown chain of trust ${COT})
+ endif
+
+ 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_))
+
+ IMG_PARSER_LIB_MK := drivers/auth/mbedtls/mbedtls_x509.mk
+
+ $(info Including ${IMG_PARSER_LIB_MK})
+ include ${IMG_PARSER_LIB_MK}
+endif
+
+# Include Measured Boot makefile before any Crypto library makefile.
+# Crypto library makefile may need default definitions of Measured Boot build
+# flags present in Measured Boot makefile.
+ifneq ($(filter 1,${MEASURED_BOOT} ${DRTM_SUPPORT}),)
+ MEASURED_BOOT_MK := drivers/measured_boot/event_log/event_log.mk
+ $(info Including ${MEASURED_BOOT_MK})
+ include ${MEASURED_BOOT_MK}
+
+ ifneq (${MBOOT_EL_HASH_ALG}, sha256)
+ $(eval $(call add_define,TF_MBEDTLS_MBOOT_USE_SHA512))
+ endif
+
+ ifeq (${MEASURED_BOOT},1)
+ BL1_SOURCES += ${EVENT_LOG_SOURCES}
+ BL2_SOURCES += ${EVENT_LOG_SOURCES}
+ endif
+
+ ifeq (${DRTM_SUPPORT},1)
+ BL31_SOURCES += ${EVENT_LOG_SOURCES}
+ endif
+endif
+
+ifneq ($(filter 1,${MEASURED_BOOT} ${TRUSTED_BOARD_BOOT} ${DRTM_SUPPORT}),)
+ CRYPTO_SOURCES := drivers/auth/crypto_mod.c \
+ lib/fconf/fconf_tbbr_getter.c
+ BL1_SOURCES += ${CRYPTO_SOURCES}
+ BL2_SOURCES += ${CRYPTO_SOURCES}
+ BL31_SOURCES += drivers/auth/crypto_mod.c
+
+ # 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
+
+ $(info Including ${CRYPTO_LIB_MK})
+ include ${CRYPTO_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
diff --git a/plat/arm/common/arm_console.c b/plat/arm/common/arm_console.c
new file mode 100644
index 0000000..51830c9
--- /dev/null
+++ b/plat/arm/common/arm_console.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <plat/arm/common/plat_arm.h>
+
+#pragma weak arm_console_runtime_init
+#pragma weak arm_console_runtime_end
+
+/*******************************************************************************
+ * Functions that set up the console
+ ******************************************************************************/
+static console_t arm_boot_console;
+static console_t arm_runtime_console;
+
+/* Initialize the console to provide early debug support */
+void __init arm_console_boot_init(void)
+{
+ /* If the console was initialized already, don't initialize again */
+ if (arm_boot_console.base == PLAT_ARM_BOOT_UART_BASE) {
+ return;
+ }
+
+ 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_FLAG_BOOT);
+}
+
+void arm_console_boot_end(void)
+{
+ console_flush();
+ (void)console_unregister(&arm_boot_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_FLAG_RUNTIME);
+}
+
+void arm_console_runtime_end(void)
+{
+ console_flush();
+}
diff --git a/plat/arm/common/arm_dyn_cfg.c b/plat/arm/common/arm_dyn_cfg.c
new file mode 100644
index 0000000..c88621e
--- /dev/null
+++ b/plat/arm/common/arm_dyn_cfg.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2018-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <common/tbbr/tbbr_img_def.h>
+#if CRYPTO_SUPPORT
+#include MBEDTLS_CONFIG_FILE
+#endif /* CRYPTO_SUPPORT */
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_dyn_cfg_getter.h>
+#include <lib/fconf/fconf_tbbr_getter.h>
+
+#include <plat/arm/common/arm_dyn_cfg_helpers.h>
+#include <plat/arm/common/plat_arm.h>
+
+#if CRYPTO_SUPPORT
+
+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 || defined(IMAGE_BL31)
+
+ /* 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)
+
+ /* If in BL2, retrieve the already allocated heap's info from DTB */
+ *heap_addr = FCONF_GET_PROPERTY(tbbr, dyn_config, mbedtls_heap_addr);
+ *heap_size = FCONF_GET_PROPERTY(tbbr, dyn_config, mbedtls_heap_size);
+
+#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;
+ uintptr_t tb_fw_cfg_dtb;
+ const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
+
+ /*
+ * 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.
+ */
+
+ tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
+ assert(tb_fw_config_info != NULL);
+
+ tb_fw_cfg_dtb = tb_fw_config_info->config_addr;
+
+ if ((tb_fw_cfg_dtb != 0UL) && (mbedtls_heap_addr != NULL)) {
+ /* As libfdt uses void *, we can't avoid this cast */
+ void *dtb = (void *)tb_fw_cfg_dtb;
+
+ err = arm_set_dtb_mbedtls_heap_info(dtb,
+ mbedtls_heap_addr, mbedtls_heap_size);
+ if (err < 0) {
+ ERROR("%swrite shared Mbed TLS heap information%s",
+ "BL1: unable to ", " to DTB\n");
+ panic();
+ }
+#if !MEASURED_BOOT
+ /*
+ * 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.
+ *
+ * In MEASURED_BOOT case flushing is done in a function which
+ * is called after heap information is written in the DTB.
+ */
+ flush_dcache_range(tb_fw_cfg_dtb, fdt_totalsize(dtb));
+#endif /* !MEASURED_BOOT */
+ }
+}
+#endif /* CRYPTO_SUPPORT */
+
+/*
+ * BL2 utility function to initialize dynamic configuration specified by
+ * FW_CONFIG. Populate the bl_mem_params_node_t of other FW_CONFIGs if
+ * specified in FW_CONFIG.
+ */
+void arm_bl2_dyn_cfg_init(void)
+{
+ unsigned int i;
+ bl_mem_params_node_t *cfg_mem_params = NULL;
+ uintptr_t image_base;
+ uint32_t image_size;
+ unsigned int error_config_id = MAX_IMAGE_IDS;
+ const unsigned int config_ids[] = {
+ HW_CONFIG_ID,
+ SOC_FW_CONFIG_ID,
+ NT_FW_CONFIG_ID,
+ TOS_FW_CONFIG_ID
+ };
+
+ const struct dyn_cfg_dtb_info_t *dtb_info;
+
+ /* Iterate through all the fw config IDs */
+ for (i = 0; i < ARRAY_SIZE(config_ids); i++) {
+ /* Get the config load address and size */
+ cfg_mem_params = get_bl_mem_params_node(config_ids[i]);
+ if (cfg_mem_params == NULL) {
+ VERBOSE("%sconfig_id = %d in bl_mem_params_node\n",
+ "Couldn't find ", config_ids[i]);
+ continue;
+ }
+
+ dtb_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, config_ids[i]);
+ if (dtb_info == NULL) {
+ VERBOSE("%sconfig_id %d load info in FW_CONFIG\n",
+ "Couldn't find ", config_ids[i]);
+ continue;
+ }
+
+ image_base = dtb_info->config_addr;
+ image_size = dtb_info->config_max_size;
+
+ /*
+ * 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)) {
+ VERBOSE("%s=%d as its %s is overflowing uptr\n",
+ "skip loading of firmware config",
+ config_ids[i],
+ "load-address");
+ error_config_id = config_ids[i];
+ continue;
+ }
+#ifdef BL31_BASE
+ /* Ensure the configs don't overlap with BL31 */
+ if ((image_base >= BL31_BASE) &&
+ (image_base <= BL31_LIMIT)) {
+ VERBOSE("%s=%d as its %s is overlapping BL31\n",
+ "skip loading of firmware config",
+ config_ids[i],
+ "load-address");
+ error_config_id = config_ids[i];
+ continue;
+ }
+#endif
+ /* Ensure the configs are loaded in a valid address */
+ if (image_base < ARM_BL_RAM_BASE) {
+ VERBOSE("%s=%d as its %s is invalid\n",
+ "skip loading of firmware config",
+ config_ids[i],
+ "load-address");
+ error_config_id = config_ids[i];
+ 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)) {
+ VERBOSE("%s=%d as its %s is overlapping BL32\n",
+ "skip loading of firmware config",
+ config_ids[i],
+ "load-address");
+ error_config_id = config_ids[i];
+ continue;
+ }
+#endif
+ }
+
+ cfg_mem_params->image_info.image_base = image_base;
+ cfg_mem_params->image_info.image_max_size = (uint32_t)image_size;
+
+ /*
+ * Remove the IMAGE_ATTRIB_SKIP_LOADING attribute from
+ * HW_CONFIG or FW_CONFIG nodes
+ */
+ cfg_mem_params->image_info.h.attr &= ~IMAGE_ATTRIB_SKIP_LOADING;
+ }
+
+ if (error_config_id != MAX_IMAGE_IDS) {
+ ERROR("Invalid config file %u\n", error_config_id);
+ panic();
+ }
+}
diff --git a/plat/arm/common/arm_dyn_cfg_helpers.c b/plat/arm/common/arm_dyn_cfg_helpers.c
new file mode 100644
index 0000000..e88ea65
--- /dev/null
+++ b/plat/arm/common/arm_dyn_cfg_helpers.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#if MEASURED_BOOT
+#include <common/desc_image_load.h>
+#endif
+#include <common/fdt_wrappers.h>
+
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_dyn_cfg_getter.h>
+#include <libfdt.h>
+
+#include <plat/arm/common/arm_dyn_cfg_helpers.h>
+#include <plat/arm/common/plat_arm.h>
+
+#define DTB_PROP_MBEDTLS_HEAP_ADDR "mbedtls_heap_addr"
+#define DTB_PROP_MBEDTLS_HEAP_SIZE "mbedtls_heap_size"
+
+#if MEASURED_BOOT
+#ifdef SPD_opteed
+/*
+ * Currently OP-TEE does not support reading DTBs from Secure memory
+ * and this property should be removed when this feature is supported.
+ */
+#define DTB_PROP_HW_SM_LOG_ADDR "tpm_event_log_sm_addr"
+#endif /* SPD_opteed */
+#define DTB_PROP_HW_LOG_ADDR "tpm_event_log_addr"
+#define DTB_PROP_HW_LOG_SIZE "tpm_event_log_size"
+#endif /* MEASURED_BOOT */
+
+/*******************************************************************************
+ * 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%s\n", " TB_FW_CONFIG");
+ 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 '%s' not%s", "arm,tb_fw",
+ " found in the config\n");
+ return -1;
+ }
+
+ VERBOSE("Dyn cfg: '%s'%s", "arm,tb_fw", " found in the config\n");
+ 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 dtb_root;
+
+ /*
+ * Verify that the DTB is valid, before attempting to write to it,
+ * and get the DTB root node.
+ */
+ int err = arm_dyn_tb_fw_cfg_init(dtb, &dtb_root);
+ if (err < 0) {
+ ERROR("Invalid%s loaded. Unable to get root node\n",
+ " TB_FW_CONFIG");
+ 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("%sDTB property '%s'\n",
+ "Unable to write ", 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("%sDTB property '%s'\n",
+ "Unable to write ", DTB_PROP_MBEDTLS_HEAP_SIZE);
+ return -1;
+ }
+
+ return 0;
+}
+
+#if MEASURED_BOOT
+/*
+ * Write the Event Log address and its size in the DTB.
+ *
+ * Returns:
+ * 0 = success
+ * < 0 = error
+ */
+static int arm_set_event_log_info(uintptr_t config_base,
+#ifdef SPD_opteed
+ uintptr_t sm_log_addr,
+#endif
+ uintptr_t log_addr, size_t log_size)
+{
+ /* As libfdt uses void *, we can't avoid this cast */
+ void *dtb = (void *)config_base;
+ const char *compatible = "arm,tpm_event_log";
+ int err, node;
+
+ /*
+ * Verify that the DTB is valid, before attempting to write to it,
+ * and get the DTB root node.
+ */
+
+ /* Check if the pointer to DT is correct */
+ err = fdt_check_header(dtb);
+ if (err < 0) {
+ WARN("Invalid DTB file passed\n");
+ return err;
+ }
+
+ /* Assert the node offset point to compatible property */
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible);
+ if (node < 0) {
+ WARN("The compatible property '%s' not%s", compatible,
+ " found in the config\n");
+ return node;
+ }
+
+ VERBOSE("Dyn cfg: '%s'%s", compatible, " found in the config\n");
+
+#ifdef SPD_opteed
+ if (sm_log_addr != 0UL) {
+ err = fdtw_write_inplace_cells(dtb, node,
+ DTB_PROP_HW_SM_LOG_ADDR, 2, &sm_log_addr);
+ if (err < 0) {
+ ERROR("%sDTB property '%s'\n",
+ "Unable to write ", DTB_PROP_HW_SM_LOG_ADDR);
+ return err;
+ }
+ }
+#endif
+ err = fdtw_write_inplace_cells(dtb, node,
+ DTB_PROP_HW_LOG_ADDR, 2, &log_addr);
+ if (err < 0) {
+ ERROR("%sDTB property '%s'\n",
+ "Unable to write ", DTB_PROP_HW_LOG_ADDR);
+ return err;
+ }
+
+ err = fdtw_write_inplace_cells(dtb, node,
+ DTB_PROP_HW_LOG_SIZE, 1, &log_size);
+ if (err < 0) {
+ ERROR("%sDTB property '%s'\n",
+ "Unable to write ", DTB_PROP_HW_LOG_SIZE);
+ } else {
+ /*
+ * Ensure that the info written to the DTB is visible
+ * to other images.
+ */
+ flush_dcache_range(config_base, fdt_totalsize(dtb));
+ }
+
+ return err;
+}
+
+/*
+ * This function writes the Event Log address and its size
+ * in the TOS_FW_CONFIG DTB.
+ *
+ * This function is supposed to be called only by BL2.
+ *
+ * Returns:
+ * 0 = success
+ * < 0 = error
+ */
+int arm_set_tos_fw_info(uintptr_t log_addr, size_t log_size)
+{
+ uintptr_t config_base;
+ const bl_mem_params_node_t *cfg_mem_params;
+ int err;
+
+ assert(log_addr != 0UL);
+
+ /* Get the config load address and size of TOS_FW_CONFIG */
+ cfg_mem_params = get_bl_mem_params_node(TOS_FW_CONFIG_ID);
+ assert(cfg_mem_params != NULL);
+
+ config_base = cfg_mem_params->image_info.image_base;
+
+ /* Write the Event Log address and its size in the DTB */
+ err = arm_set_event_log_info(config_base,
+#ifdef SPD_opteed
+ 0UL,
+#endif
+ log_addr, log_size);
+ if (err < 0) {
+ ERROR("%sEvent Log data to TOS_FW_CONFIG\n",
+ "Unable to write ");
+ }
+
+ return err;
+}
+
+/*
+ * This function writes the Event Log address and its size
+ * in the NT_FW_CONFIG DTB.
+ *
+ * This function is supposed to be called only by BL2.
+ *
+ * Returns:
+ * 0 = success
+ * < 0 = error
+ */
+int arm_set_nt_fw_info(
+#ifdef SPD_opteed
+ uintptr_t log_addr,
+#endif
+ size_t log_size, uintptr_t *ns_log_addr)
+{
+ uintptr_t config_base;
+ uintptr_t ns_addr;
+ const bl_mem_params_node_t *cfg_mem_params;
+ int err;
+
+ assert(ns_log_addr != NULL);
+
+ /* Get the config load address and size from NT_FW_CONFIG */
+ cfg_mem_params = get_bl_mem_params_node(NT_FW_CONFIG_ID);
+ assert(cfg_mem_params != NULL);
+
+ config_base = cfg_mem_params->image_info.image_base;
+
+ /* Calculate Event Log address in Non-secure memory */
+ ns_addr = cfg_mem_params->image_info.image_base +
+ cfg_mem_params->image_info.image_max_size;
+
+ /* Check for memory space */
+ if ((uint64_t)(ns_addr + log_size) > ARM_NS_DRAM1_END) {
+ return -1;
+ }
+
+ /* Write the Event Log address and its size in the DTB */
+ err = arm_set_event_log_info(config_base,
+#ifdef SPD_opteed
+ log_addr,
+#endif
+ ns_addr, log_size);
+
+ /* Return Event Log address in Non-secure memory */
+ *ns_log_addr = (err < 0) ? 0UL : ns_addr;
+ return err;
+}
+
+/*
+ * This function writes the Event Log address and its size
+ * in the TB_FW_CONFIG DTB.
+ *
+ * This function is supposed to be called only by BL1.
+ *
+ * Returns:
+ * 0 = success
+ * < 0 = error
+ */
+int arm_set_tb_fw_info(uintptr_t log_addr, size_t log_size)
+{
+ /*
+ * Read tb_fw_config device tree for Event Log properties
+ * and write the Event Log address and its size in the DTB
+ */
+ const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
+ uintptr_t tb_fw_cfg_dtb;
+ int err;
+
+ tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
+ assert(tb_fw_config_info != NULL);
+
+ tb_fw_cfg_dtb = tb_fw_config_info->config_addr;
+
+ err = arm_set_event_log_info(tb_fw_cfg_dtb,
+#ifdef SPD_opteed
+ 0UL,
+#endif
+ log_addr, log_size);
+ return err;
+}
+
+/*
+ * This function reads the Event Log address and its size
+ * properties present in TB_FW_CONFIG DTB.
+ *
+ * This function is supposed to be called only by BL2.
+ *
+ * Returns:
+ * 0 = success
+ * < 0 = error
+ * Alongside returns Event Log address and its size.
+ */
+
+int arm_get_tb_fw_info(uint64_t *log_addr, size_t *log_size)
+{
+ /* As libfdt uses void *, we can't avoid this cast */
+ const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
+ int node, rc;
+
+ tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
+ assert(tb_fw_config_info != NULL);
+
+ void *dtb = (void *)tb_fw_config_info->config_addr;
+ const char *compatible = "arm,tpm_event_log";
+
+ /* Assert the node offset point to compatible property */
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible);
+ if (node < 0) {
+ WARN("The compatible property '%s'%s", compatible,
+ " not specified in TB_FW config.\n");
+ return node;
+ }
+
+ VERBOSE("Dyn cfg: '%s'%s", compatible, " found in the config\n");
+
+ rc = fdt_read_uint64(dtb, node, DTB_PROP_HW_LOG_ADDR, log_addr);
+ if (rc != 0) {
+ ERROR("%s%s", DTB_PROP_HW_LOG_ADDR,
+ " not specified in TB_FW config.\n");
+ return rc;
+ }
+
+ rc = fdt_read_uint32(dtb, node, DTB_PROP_HW_LOG_SIZE, (uint32_t *)log_size);
+ if (rc != 0) {
+ ERROR("%s%s", DTB_PROP_HW_LOG_SIZE,
+ " not specified in TB_FW config.\n");
+ }
+
+ return rc;
+}
+#endif /* MEASURED_BOOT */
diff --git a/plat/arm/common/arm_err.c b/plat/arm/common/arm_err.c
new file mode 100644
index 0000000..fa36e8d
--- /dev/null
+++ b/plat/arm/common/arm_err.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+void __dead2 plat_error_handler(int err)
+{
+ plat_arm_error_handler(err);
+}
+
+void __dead2 plat_system_reset(void)
+{
+ plat_arm_system_reset();
+}
diff --git a/plat/arm/common/arm_gicv2.c b/plat/arm/common/arm_gicv2.c
new file mode 100644
index 0000000..80a845f
--- /dev/null
+++ b/plat/arm/common/arm_gicv2.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <drivers/arm/gicv2.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/******************************************************************************
+ * 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();
+}
diff --git a/plat/arm/common/arm_gicv3.c b/plat/arm/common/arm_gicv3.c
new file mode 100644
index 0000000..469e22a
--- /dev/null
+++ b/plat/arm/common/arm_gicv3.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/utils.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.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_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];
+
+/* Default GICR base address to be used for GICR probe. */
+static const uintptr_t gicr_base_addrs[2] = {
+ PLAT_ARM_GICR_BASE, /* GICR Base address of the primary CPU */
+ 0U /* Zero Termination */
+};
+
+/* List of zero terminated GICR frame addresses which CPUs will probe */
+static const uintptr_t *gicr_frames = gicr_base_addrs;
+
+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 `used` attribute
+ * is used to prevent the compiler from removing the gicv3 contexts.
+ */
+static gicv3_redist_ctx_t rdist_ctx __section("arm_el3_tzc_dram") __used;
+static gicv3_dist_ctx_t dist_ctx __section("arm_el3_tzc_dram") __used;
+
+/* 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
+};
+
+/*
+ * By default, gicr_frames will be pointing to gicr_base_addrs. If
+ * the platform supports a non-contiguous GICR frames (GICR frames located
+ * at uneven offset), plat_arm_override_gicr_frames function can be used by
+ * such platform to override the gicr_frames.
+ */
+void plat_arm_override_gicr_frames(const uintptr_t *plat_gicr_frames)
+{
+ assert(plat_gicr_frames != NULL);
+ gicr_frames = plat_gicr_frames;
+}
+
+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(gicr_base_addrs[0]) == -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.
+ *****************************************************************************/
+void plat_arm_gic_pcpu_init(void)
+{
+ int result;
+ const uintptr_t *plat_gicr_frames = gicr_frames;
+
+ do {
+ result = gicv3_rdistif_probe(*plat_gicr_frames);
+
+ /* If the probe is successful, no need to proceed further */
+ if (result == 0)
+ break;
+
+ plat_gicr_frames++;
+ } while (*plat_gicr_frames != 0U);
+
+ 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.
+ */
+}
diff --git a/plat/arm/common/arm_image_load.c b/plat/arm/common/arm_image_load.c
new file mode 100644
index 0000000..c411c6c
--- /dev/null
+++ b/plat/arm/common/arm_image_load.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#if defined(SPD_spmd)
+#include <plat/arm/common/fconf_arm_sp_getter.h>
+#endif
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#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);
+}
+
+#if defined(SPD_spmd) && BL2_ENABLE_SP_LOAD
+/*******************************************************************************
+ * This function appends Secure Partitions to list of loadable images.
+ ******************************************************************************/
+static void plat_add_sp_images_load_info(struct bl_load_info *load_info)
+{
+ bl_load_info_node_t *curr_node = load_info->head;
+ bl_load_info_node_t *prev_node;
+
+ /* Shortcut for empty SP list */
+ if (sp_mem_params_descs[0].image_id == 0) {
+ ERROR("No Secure Partition Image available\n");
+ return;
+ }
+
+ /* Traverse through the bl images list */
+ do {
+ curr_node = curr_node->next_load_info;
+ } while (curr_node->next_load_info != NULL);
+
+ prev_node = curr_node;
+
+ for (unsigned int index = 0; index < MAX_SP_IDS; index++) {
+ if (sp_mem_params_descs[index].image_id == 0) {
+ return;
+ }
+ curr_node = &sp_mem_params_descs[index].load_node_mem;
+ /* Populate the image information */
+ curr_node->image_id = sp_mem_params_descs[index].image_id;
+ curr_node->image_info = &sp_mem_params_descs[index].image_info;
+
+ prev_node->next_load_info = curr_node;
+ prev_node = curr_node;
+ }
+
+ INFO("Reached Max number of SPs\n");
+}
+#endif
+
+/*******************************************************************************
+ * This function returns the list of loadable images.
+ ******************************************************************************/
+struct bl_load_info *plat_get_bl_image_load_info(void)
+{
+#if defined(SPD_spmd) && BL2_ENABLE_SP_LOAD
+ bl_load_info_t *bl_load_info;
+
+ bl_load_info = get_bl_load_info_from_mem_params_desc();
+ plat_add_sp_images_load_info(bl_load_info);
+
+ return bl_load_info;
+#else
+ return get_bl_load_info_from_mem_params_desc();
+#endif
+}
+
+/*******************************************************************************
+ * 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();
+}
+
diff --git a/plat/arm/common/arm_io_storage.c b/plat/arm/common/arm_io_storage.c
new file mode 100644
index 0000000..19ee1b0
--- /dev/null
+++ b/plat/arm/common/arm_io_storage.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2015-2021, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/fwu/fwu_metadata.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/partition/partition.h>
+#include <lib/utils.h>
+
+#include <plat/arm/common/arm_fconf_getter.h>
+#include <plat/arm/common/arm_fconf_io_storage.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+/* IO devices */
+static const io_dev_connector_t *fip_dev_con;
+uintptr_t fip_dev_handle;
+static const io_dev_connector_t *memmap_dev_con;
+uintptr_t memmap_dev_handle;
+
+#if ARM_GPT_SUPPORT
+/* fip partition names */
+static const char * const fip_part_names[] = {"FIP_A", "FIP_B"};
+CASSERT(sizeof(fip_part_names)/sizeof(char *) == NR_OF_FW_BANKS,
+ assert_fip_partition_names_missing);
+#endif /* ARM_GPT_SUPPORT */
+
+/* Weak definitions may be overridden in specific ARM standard platform */
+#pragma weak plat_arm_io_setup
+#pragma weak plat_arm_get_alt_image_source
+
+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;
+}
+
+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;
+}
+
+int arm_io_setup(void)
+{
+ int io_result;
+
+ io_result = register_io_dev_fip(&fip_dev_con);
+ if (io_result < 0) {
+ return io_result;
+ }
+
+ io_result = register_io_dev_memmap(&memmap_dev_con);
+ if (io_result < 0) {
+ return io_result;
+ }
+
+ /* Open connections to devices and cache the handles */
+ io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL,
+ &fip_dev_handle);
+ if (io_result < 0) {
+ return io_result;
+ }
+
+ io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL,
+ &memmap_dev_handle);
+
+ return io_result;
+}
+
+void plat_arm_io_setup(void)
+{
+ int err;
+
+ err = arm_io_setup();
+ if (err < 0) {
+ panic();
+ }
+}
+
+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;
+
+ policy = FCONF_GET_PROPERTY(arm, io_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.
+ */
+bool arm_io_is_toc_valid(void)
+{
+ return (io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID) == 0);
+}
+
+#if ARM_GPT_SUPPORT
+/******************************************************************************
+ * Retrieve partition entry details such as offset and length, and set these
+ * details in the I/O policy of the requested image.
+ *
+ * @image_id: image id whose I/O policy to be updated
+ *
+ * @part_name: partition name whose details to be retrieved
+ *
+ * Returns 0 on success, error otherwise
+ * Alongside, returns device handle and image specification of requested
+ * image.
+ ******************************************************************************/
+int arm_set_image_source(unsigned int image_id, const char *part_name,
+ uintptr_t *dev_handle, uintptr_t *image_spec)
+{
+ const partition_entry_t *entry = get_partition_entry(part_name);
+
+ if (entry == NULL) {
+ ERROR("Unable to find the %s partition\n", part_name);
+ return -ENOENT;
+ }
+
+ struct plat_io_policy *policy = FCONF_GET_PROPERTY(arm,
+ io_policies,
+ image_id);
+
+ assert(policy != NULL);
+ assert(policy->image_spec != 0UL);
+
+ io_block_spec_t *spec = (io_block_spec_t *)policy->image_spec;
+ /* set offset and length of the image */
+ spec->offset = PLAT_ARM_FLASH_IMAGE_BASE + entry->start;
+ spec->length = entry->length;
+
+ *dev_handle = *(policy->dev_handle);
+ *image_spec = policy->image_spec;
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Set the source offset and length of the FIP image in its I/O policy.
+ *
+ * @active_fw_bank_idx: active firmware bank index gathered from FWU metadata.
+ ******************************************************************************/
+void arm_set_fip_addr(uint32_t active_fw_bank_idx)
+{
+ uintptr_t dev_handle __unused;
+ uintptr_t image_spec __unused;
+
+ assert(active_fw_bank_idx < NR_OF_FW_BANKS);
+
+ INFO("Booting with partition %s\n", fip_part_names[active_fw_bank_idx]);
+
+ int result = arm_set_image_source(FIP_IMAGE_ID,
+ fip_part_names[active_fw_bank_idx],
+ &dev_handle,
+ &image_spec);
+ if (result != 0) {
+ panic();
+ }
+}
+#endif /* ARM_GPT_SUPPORT */
+
+#if PSA_FWU_SUPPORT
+/*******************************************************************************
+ * Read the FIP partition of the GPT image corresponding to the active firmware
+ * bank to get its offset and length, and update these details in the I/O policy
+ * of the FIP image.
+ ******************************************************************************/
+void plat_fwu_set_images_source(const struct fwu_metadata *metadata)
+{
+ arm_set_fip_addr(metadata->active_index);
+}
+
+/*******************************************************************************
+ * Read the requested FWU metadata partition of the GPT image to get its offset
+ * and length, and update these details in the I/O policy of the requested FWU
+ * metadata image.
+ ******************************************************************************/
+int plat_fwu_set_metadata_image_source(unsigned int image_id,
+ uintptr_t *dev_handle,
+ uintptr_t *image_spec)
+{
+ int result = -1;
+
+ if (image_id == FWU_METADATA_IMAGE_ID) {
+ result = arm_set_image_source(FWU_METADATA_IMAGE_ID,
+ "FWU-Metadata",
+ dev_handle,
+ image_spec);
+ } else if (image_id == BKUP_FWU_METADATA_IMAGE_ID) {
+ result = arm_set_image_source(BKUP_FWU_METADATA_IMAGE_ID,
+ "Bkup-FWU-Metadata",
+ dev_handle,
+ image_spec);
+ }
+
+ return result;
+}
+#endif /* PSA_FWU_SUPPORT */
diff --git a/plat/arm/common/arm_nor_psci_mem_protect.c b/plat/arm/common/arm_nor_psci_mem_protect.c
new file mode 100644
index 0000000..1fa234d
--- /dev/null
+++ b/plat/arm/common/arm_nor_psci_mem_protect.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/cfi/v2m_flash.h>
+#include <lib/psci/psci.h>
+#include <lib/utils.h>
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * 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);
+}
diff --git a/plat/arm/common/arm_pm.c b/plat/arm/common/arm_pm.c
new file mode 100644
index 0000000..5434c94
--- /dev/null
+++ b/plat/arm/common/arm_pm.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/* 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;
+}
diff --git a/plat/arm/common/arm_sip_svc.c b/plat/arm/common/arm_sip_svc.c
new file mode 100644
index 0000000..6456c78
--- /dev/null
+++ b/plat/arm/common/arm_sip_svc.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2016-2019,2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <drivers/arm/ethosn.h>
+#include <lib/debugfs.h>
+#include <lib/pmf/pmf.h>
+#include <plat/arm/common/arm_sip_svc.h>
+#include <plat/arm/common/plat_arm.h>
+#include <tools_share/uuid.h>
+
+/* 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;
+ }
+
+#if USE_DEBUGFS
+
+ if (debugfs_smc_setup() != 0) {
+ return 1;
+ }
+
+#endif /* USE_DEBUGFS */
+
+ 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;
+
+#if ENABLE_PMF
+
+ /*
+ * 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);
+ }
+
+#endif /* ENABLE_PMF */
+
+#if USE_DEBUGFS
+
+ if (is_debugfs_fid(smc_fid)) {
+ return debugfs_smc_handler(smc_fid, x1, x2, x3, x4, cookie,
+ handle, flags);
+ }
+
+#endif /* USE_DEBUGFS */
+
+#if ARM_ETHOSN_NPU_DRIVER
+
+ if (is_ethosn_fid(smc_fid)) {
+ return ethosn_smc_handler(smc_fid, x1, x2, x3, x4, cookie,
+ handle, flags);
+ }
+
+#endif /* ARM_ETHOSN_NPU_DRIVER */
+
+ switch (smc_fid) {
+ case ARM_SIP_SVC_EXE_STATE_SWITCH: {
+ /* Execution state can be switched only if EL3 is AArch64 */
+#ifdef __aarch64__
+ /* Allow calls from non-secure only */
+ if (!is_caller_non_secure(flags))
+ SMC_RET1(handle, STATE_SW_E_DENIED);
+
+ /*
+ * 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);
+#else
+ /* State switch denied */
+ SMC_RET1(handle, STATE_SW_E_DENIED);
+#endif /* __aarch64__ */
+ }
+
+ case ARM_SIP_SVC_CALL_COUNT:
+ /* PMF calls */
+ call_count += PMF_NUM_SMC_CALLS;
+
+#if ARM_ETHOSN_NPU_DRIVER
+ /* ETHOSN calls */
+ call_count += ETHOSN_NUM_SMC_CALLS;
+#endif /* ARM_ETHOSN_NPU_DRIVER */
+
+ /* 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
+);
diff --git a/plat/arm/common/arm_topology.c b/plat/arm/common/arm_topology.c
new file mode 100644
index 0000000..c9993a7
--- /dev/null
+++ b/plat/arm/common/arm_topology.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <plat/arm/common/plat_arm.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 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) |
+ (MPIDR_AFFLVL_MASK << MPIDR_AFF3_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;
+}
diff --git a/plat/arm/common/arm_tzc400.c b/plat/arm/common/arm_tzc400.c
new file mode 100644
index 0000000..370ef0a
--- /dev/null
+++ b/plat/arm/common/arm_tzc400.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/arm/tzc400.h>
+#include <plat/arm/common/plat_arm.h>
+
+/* 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(uintptr_t tzc_base,
+ 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(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(PLAT_ARM_TZC_BASE, NULL);
+}
diff --git a/plat/arm/common/arm_tzc_dmc500.c b/plat/arm/common/arm_tzc_dmc500.c
new file mode 100644
index 0000000..e9f897f
--- /dev/null
+++ b/plat/arm/common/arm_tzc_dmc500.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/arm/tzc_dmc500.h>
+#include <plat/arm/common/plat_arm.h>
+
+/*******************************************************************************
+ * 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())
+ ;
+}
diff --git a/plat/arm/common/fconf/arm_fconf_io.c b/plat/arm/common/fconf/arm_fconf_io.c
new file mode 100644
index 0000000..6c32331
--- /dev/null
+++ b/plat/arm/common/fconf/arm_fconf_io.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/partition/partition.h>
+#include <lib/object_pool.h>
+#include <libfdt.h>
+#include <tools_share/firmware_image_package.h>
+
+#include <plat/arm/common/arm_fconf_getter.h>
+#include <plat/arm/common/arm_fconf_io_storage.h>
+#include <platform_def.h>
+
+#if PSA_FWU_SUPPORT
+/* metadata entry details */
+static io_block_spec_t fwu_metadata_spec;
+#endif /* PSA_FWU_SUPPORT */
+
+io_block_spec_t fip_block_spec = {
+/*
+ * This is fixed FIP address used by BL1, BL2 loads partition table
+ * to get FIP address.
+ */
+#if ARM_GPT_SUPPORT
+ .offset = PLAT_ARM_FLASH_IMAGE_BASE + PLAT_ARM_FIP_OFFSET_IN_GPT,
+#else
+ .offset = PLAT_ARM_FLASH_IMAGE_BASE,
+#endif /* ARM_GPT_SUPPORT */
+ .length = PLAT_ARM_FLASH_IMAGE_MAX_SIZE
+};
+
+#if ARM_GPT_SUPPORT
+static const io_block_spec_t gpt_spec = {
+ .offset = PLAT_ARM_FLASH_IMAGE_BASE,
+ /*
+ * PLAT_PARTITION_BLOCK_SIZE = 512
+ * PLAT_PARTITION_MAX_ENTRIES = 128
+ * each sector has 4 partition entries, and there are
+ * 2 reserved sectors i.e. protective MBR and primary
+ * GPT header hence length gets calculated as,
+ * length = 512 * (128/4 + 2)
+ */
+ .length = PLAT_PARTITION_BLOCK_SIZE *
+ (PLAT_PARTITION_MAX_ENTRIES / 4 + 2),
+};
+#endif /* ARM_GPT_SUPPORT */
+
+const io_uuid_spec_t arm_uuid_spec[MAX_NUMBER_IDS] = {
+ [BL2_IMAGE_ID] = {UUID_TRUSTED_BOOT_FIRMWARE_BL2},
+ [TB_FW_CONFIG_ID] = {UUID_TB_FW_CONFIG},
+ [FW_CONFIG_ID] = {UUID_FW_CONFIG},
+#if !ARM_IO_IN_DTB
+ [SCP_BL2_IMAGE_ID] = {UUID_SCP_FIRMWARE_SCP_BL2},
+ [BL31_IMAGE_ID] = {UUID_EL3_RUNTIME_FIRMWARE_BL31},
+ [BL32_IMAGE_ID] = {UUID_SECURE_PAYLOAD_BL32},
+ [BL32_EXTRA1_IMAGE_ID] = {UUID_SECURE_PAYLOAD_BL32_EXTRA1},
+ [BL32_EXTRA2_IMAGE_ID] = {UUID_SECURE_PAYLOAD_BL32_EXTRA2},
+ [BL33_IMAGE_ID] = {UUID_NON_TRUSTED_FIRMWARE_BL33},
+ [HW_CONFIG_ID] = {UUID_HW_CONFIG},
+ [SOC_FW_CONFIG_ID] = {UUID_SOC_FW_CONFIG},
+ [TOS_FW_CONFIG_ID] = {UUID_TOS_FW_CONFIG},
+ [NT_FW_CONFIG_ID] = {UUID_NT_FW_CONFIG},
+ [RMM_IMAGE_ID] = {UUID_REALM_MONITOR_MGMT_FIRMWARE},
+#endif /* ARM_IO_IN_DTB */
+#if TRUSTED_BOARD_BOOT
+ [TRUSTED_BOOT_FW_CERT_ID] = {UUID_TRUSTED_BOOT_FW_CERT},
+#if !ARM_IO_IN_DTB
+ [CCA_CONTENT_CERT_ID] = {UUID_CCA_CONTENT_CERT},
+ [CORE_SWD_KEY_CERT_ID] = {UUID_CORE_SWD_KEY_CERT},
+ [PLAT_KEY_CERT_ID] = {UUID_PLAT_KEY_CERT},
+ [TRUSTED_KEY_CERT_ID] = {UUID_TRUSTED_KEY_CERT},
+ [SCP_FW_KEY_CERT_ID] = {UUID_SCP_FW_KEY_CERT},
+ [SOC_FW_KEY_CERT_ID] = {UUID_SOC_FW_KEY_CERT},
+ [TRUSTED_OS_FW_KEY_CERT_ID] = {UUID_TRUSTED_OS_FW_KEY_CERT},
+ [NON_TRUSTED_FW_KEY_CERT_ID] = {UUID_NON_TRUSTED_FW_KEY_CERT},
+ [SCP_FW_CONTENT_CERT_ID] = {UUID_SCP_FW_CONTENT_CERT},
+ [SOC_FW_CONTENT_CERT_ID] = {UUID_SOC_FW_CONTENT_CERT},
+ [TRUSTED_OS_FW_CONTENT_CERT_ID] = {UUID_TRUSTED_OS_FW_CONTENT_CERT},
+ [NON_TRUSTED_FW_CONTENT_CERT_ID] = {UUID_NON_TRUSTED_FW_CONTENT_CERT},
+#if defined(SPD_spmd)
+ [SIP_SP_CONTENT_CERT_ID] = {UUID_SIP_SECURE_PARTITION_CONTENT_CERT},
+ [PLAT_SP_CONTENT_CERT_ID] = {UUID_PLAT_SECURE_PARTITION_CONTENT_CERT},
+#endif
+#endif /* ARM_IO_IN_DTB */
+#endif /* TRUSTED_BOARD_BOOT */
+};
+
+/* By default, ARM platforms load images from the FIP */
+struct plat_io_policy policies[MAX_NUMBER_IDS] = {
+#if ARM_GPT_SUPPORT
+ [GPT_IMAGE_ID] = {
+ &memmap_dev_handle,
+ (uintptr_t)&gpt_spec,
+ open_memmap
+ },
+#endif /* ARM_GPT_SUPPORT */
+#if PSA_FWU_SUPPORT
+ [FWU_METADATA_IMAGE_ID] = {
+ &memmap_dev_handle,
+ /* filled runtime from partition information */
+ (uintptr_t)&fwu_metadata_spec,
+ open_memmap
+ },
+ [BKUP_FWU_METADATA_IMAGE_ID] = {
+ &memmap_dev_handle,
+ /* filled runtime from partition information */
+ (uintptr_t)&fwu_metadata_spec,
+ open_memmap
+ },
+#endif /* PSA_FWU_SUPPORT */
+ [FIP_IMAGE_ID] = {
+ &memmap_dev_handle,
+ (uintptr_t)&fip_block_spec,
+ open_memmap
+ },
+ [BL2_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[BL2_IMAGE_ID],
+ open_fip
+ },
+ [TB_FW_CONFIG_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[TB_FW_CONFIG_ID],
+ open_fip
+ },
+ [FW_CONFIG_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[FW_CONFIG_ID],
+ open_fip
+ },
+#if !ARM_IO_IN_DTB
+ [SCP_BL2_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[SCP_BL2_IMAGE_ID],
+ open_fip
+ },
+ [BL31_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[BL31_IMAGE_ID],
+ open_fip
+ },
+ [BL32_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[BL32_IMAGE_ID],
+ open_fip
+ },
+ [BL32_EXTRA1_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[BL32_EXTRA1_IMAGE_ID],
+ open_fip
+ },
+ [BL32_EXTRA2_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[BL32_EXTRA2_IMAGE_ID],
+ open_fip
+ },
+ [BL33_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[BL33_IMAGE_ID],
+ open_fip
+ },
+ [RMM_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[RMM_IMAGE_ID],
+ open_fip
+ },
+ [HW_CONFIG_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[HW_CONFIG_ID],
+ open_fip
+ },
+ [SOC_FW_CONFIG_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[SOC_FW_CONFIG_ID],
+ open_fip
+ },
+ [TOS_FW_CONFIG_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[TOS_FW_CONFIG_ID],
+ open_fip
+ },
+ [NT_FW_CONFIG_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[NT_FW_CONFIG_ID],
+ open_fip
+ },
+#endif /* ARM_IO_IN_DTB */
+#if TRUSTED_BOARD_BOOT
+ [TRUSTED_BOOT_FW_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[TRUSTED_BOOT_FW_CERT_ID],
+ open_fip
+ },
+#if !ARM_IO_IN_DTB
+ [CCA_CONTENT_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[CCA_CONTENT_CERT_ID],
+ open_fip
+ },
+ [CORE_SWD_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[CORE_SWD_KEY_CERT_ID],
+ open_fip
+ },
+ [PLAT_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[PLAT_KEY_CERT_ID],
+ open_fip
+ },
+ [TRUSTED_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[TRUSTED_KEY_CERT_ID],
+ open_fip
+ },
+ [SCP_FW_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[SCP_FW_KEY_CERT_ID],
+ open_fip
+ },
+ [SOC_FW_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[SOC_FW_KEY_CERT_ID],
+ open_fip
+ },
+ [TRUSTED_OS_FW_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[TRUSTED_OS_FW_KEY_CERT_ID],
+ open_fip
+ },
+ [NON_TRUSTED_FW_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[NON_TRUSTED_FW_KEY_CERT_ID],
+ open_fip
+ },
+ [SCP_FW_CONTENT_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[SCP_FW_CONTENT_CERT_ID],
+ open_fip
+ },
+ [SOC_FW_CONTENT_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[SOC_FW_CONTENT_CERT_ID],
+ open_fip
+ },
+ [TRUSTED_OS_FW_CONTENT_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[TRUSTED_OS_FW_CONTENT_CERT_ID],
+ open_fip
+ },
+ [NON_TRUSTED_FW_CONTENT_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[NON_TRUSTED_FW_CONTENT_CERT_ID],
+ open_fip
+ },
+#if defined(SPD_spmd)
+ [SIP_SP_CONTENT_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[SIP_SP_CONTENT_CERT_ID],
+ open_fip
+ },
+ [PLAT_SP_CONTENT_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&arm_uuid_spec[PLAT_SP_CONTENT_CERT_ID],
+ open_fip
+ },
+#endif
+#endif /* ARM_IO_IN_DTB */
+#endif /* TRUSTED_BOARD_BOOT */
+};
+
+#ifdef IMAGE_BL2
+
+#if TRUSTED_BOARD_BOOT
+#define FCONF_ARM_IO_UUID_NUMBER U(24)
+#else
+#define FCONF_ARM_IO_UUID_NUMBER U(10)
+#endif
+
+static io_uuid_spec_t fconf_arm_uuids[FCONF_ARM_IO_UUID_NUMBER];
+static OBJECT_POOL_ARRAY(fconf_arm_uuids_pool, fconf_arm_uuids);
+
+struct policies_load_info {
+ unsigned int image_id;
+ const char *name;
+};
+
+/* image id to property name table */
+static const struct policies_load_info load_info[FCONF_ARM_IO_UUID_NUMBER] = {
+ {SCP_BL2_IMAGE_ID, "scp_bl2_uuid"},
+ {BL31_IMAGE_ID, "bl31_uuid"},
+ {BL32_IMAGE_ID, "bl32_uuid"},
+ {BL32_EXTRA1_IMAGE_ID, "bl32_extra1_uuid"},
+ {BL32_EXTRA2_IMAGE_ID, "bl32_extra2_uuid"},
+ {BL33_IMAGE_ID, "bl33_uuid"},
+ {HW_CONFIG_ID, "hw_cfg_uuid"},
+ {SOC_FW_CONFIG_ID, "soc_fw_cfg_uuid"},
+ {TOS_FW_CONFIG_ID, "tos_fw_cfg_uuid"},
+ {NT_FW_CONFIG_ID, "nt_fw_cfg_uuid"},
+#if TRUSTED_BOARD_BOOT
+ {CCA_CONTENT_CERT_ID, "cca_cert_uuid"},
+ {CORE_SWD_KEY_CERT_ID, "core_swd_cert_uuid"},
+ {PLAT_KEY_CERT_ID, "plat_cert_uuid"},
+ {TRUSTED_KEY_CERT_ID, "t_key_cert_uuid"},
+ {SCP_FW_KEY_CERT_ID, "scp_fw_key_uuid"},
+ {SOC_FW_KEY_CERT_ID, "soc_fw_key_uuid"},
+ {TRUSTED_OS_FW_KEY_CERT_ID, "tos_fw_key_cert_uuid"},
+ {NON_TRUSTED_FW_KEY_CERT_ID, "nt_fw_key_cert_uuid"},
+ {SCP_FW_CONTENT_CERT_ID, "scp_fw_content_cert_uuid"},
+ {SOC_FW_CONTENT_CERT_ID, "soc_fw_content_cert_uuid"},
+ {TRUSTED_OS_FW_CONTENT_CERT_ID, "tos_fw_content_cert_uuid"},
+ {NON_TRUSTED_FW_CONTENT_CERT_ID, "nt_fw_content_cert_uuid"},
+#if defined(SPD_spmd)
+ {SIP_SP_CONTENT_CERT_ID, "sip_sp_content_cert_uuid"},
+ {PLAT_SP_CONTENT_CERT_ID, "plat_sp_content_cert_uuid"},
+#endif
+#endif /* TRUSTED_BOARD_BOOT */
+};
+
+int fconf_populate_arm_io_policies(uintptr_t config)
+{
+ int err, node;
+ unsigned int i;
+
+ union uuid_helper_t uuid_helper;
+ io_uuid_spec_t *uuid_ptr;
+
+ /* As libfdt uses void *, we can't avoid this cast */
+ const void *dtb = (void *)config;
+
+ /* Assert the node offset point to "arm,io-fip-handle" compatible property */
+ const char *compatible_str = "arm,io-fip-handle";
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
+ if (node < 0) {
+ ERROR("FCONF: Can't find %s compatible in dtb\n", compatible_str);
+ return node;
+ }
+
+ /* Locate the uuid cells and read the value for all the load info uuid */
+ for (i = 0; i < FCONF_ARM_IO_UUID_NUMBER; i++) {
+ uuid_ptr = pool_alloc(&fconf_arm_uuids_pool);
+ err = fdtw_read_uuid(dtb, node, load_info[i].name, 16,
+ (uint8_t *)&uuid_helper);
+ if (err < 0) {
+ WARN("FCONF: Read cell failed for %s\n", load_info[i].name);
+ return err;
+ }
+
+ VERBOSE("FCONF: arm-io_policies.%s cell found with value = "
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
+ load_info[i].name,
+ uuid_helper.uuid_struct.time_low[0], uuid_helper.uuid_struct.time_low[1],
+ uuid_helper.uuid_struct.time_low[2], uuid_helper.uuid_struct.time_low[3],
+ uuid_helper.uuid_struct.time_mid[0], uuid_helper.uuid_struct.time_mid[1],
+ uuid_helper.uuid_struct.time_hi_and_version[0],
+ uuid_helper.uuid_struct.time_hi_and_version[1],
+ uuid_helper.uuid_struct.clock_seq_hi_and_reserved,
+ uuid_helper.uuid_struct.clock_seq_low,
+ uuid_helper.uuid_struct.node[0], uuid_helper.uuid_struct.node[1],
+ uuid_helper.uuid_struct.node[2], uuid_helper.uuid_struct.node[3],
+ uuid_helper.uuid_struct.node[4], uuid_helper.uuid_struct.node[5]);
+
+ uuid_ptr->uuid = uuid_helper.uuid_struct;
+ policies[load_info[i].image_id].image_spec = (uintptr_t)uuid_ptr;
+ policies[load_info[i].image_id].dev_handle = &fip_dev_handle;
+ policies[load_info[i].image_id].check = open_fip;
+ }
+ return 0;
+}
+
+#if ARM_IO_IN_DTB
+FCONF_REGISTER_POPULATOR(TB_FW, arm_io, fconf_populate_arm_io_policies);
+#endif /* ARM_IO_IN_DTB */
+
+#endif /* IMAGE_BL2 */
diff --git a/plat/arm/common/fconf/arm_fconf_sp.c b/plat/arm/common/fconf/arm_fconf_sp.c
new file mode 100644
index 0000000..18c83c7
--- /dev/null
+++ b/plat/arm/common/fconf/arm_fconf_sp.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/io/io_storage.h>
+#include <lib/object_pool.h>
+#include <libfdt.h>
+#include <plat/arm/common/arm_fconf_getter.h>
+#include <plat/arm/common/arm_fconf_io_storage.h>
+#include <plat/arm/common/fconf_arm_sp_getter.h>
+#include <platform_def.h>
+#include <tools_share/firmware_image_package.h>
+
+#ifdef IMAGE_BL2
+
+bl_mem_params_node_t sp_mem_params_descs[MAX_SP_IDS];
+
+struct arm_sp_t arm_sp;
+
+int fconf_populate_arm_sp(uintptr_t config)
+{
+ int sp_node, node, err;
+ union uuid_helper_t uuid_helper;
+ unsigned int index = 0;
+ uint32_t val32;
+ const unsigned int sip_start = SP_PKG1_ID;
+ unsigned int sip_index = sip_start;
+#if defined(ARM_COT_dualroot)
+ const unsigned int sip_end = sip_start + MAX_SP_IDS / 2;
+ /* Allocating index range for platform SPs */
+ const unsigned int plat_start = SP_PKG5_ID;
+ unsigned int plat_index = plat_start;
+ const unsigned int plat_end = plat_start + MAX_SP_IDS / 2;
+ bool is_plat_owned = false;
+#endif /* ARM_COT_dualroot */
+
+ /* As libfdt use void *, we can't avoid this cast */
+ const void *dtb = (void *)config;
+
+ /* Assert the node offset point to "arm,sp" compatible property */
+ const char *compatible_str = "arm,sp";
+
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
+ if (node < 0) {
+ ERROR("FCONF: Can't find %s in dtb\n", compatible_str);
+ return node;
+ }
+
+ fdt_for_each_subnode(sp_node, dtb, node) {
+ if (index == MAX_SP_IDS) {
+ ERROR("FCONF: Reached max number of SPs\n");
+ return -1;
+ }
+
+#if defined(ARM_COT_dualroot)
+ if ((sip_index == sip_end) || (plat_index == plat_end)) {
+ ERROR("FCONF: Reached max number of plat/SiP SPs\n");
+ return -1;
+ }
+#endif /* ARM_COT_dualroot */
+
+ /* Read UUID */
+ err = fdtw_read_uuid(dtb, sp_node, "uuid", 16,
+ (uint8_t *)&uuid_helper);
+ if (err < 0) {
+ ERROR("FCONF: cannot read SP uuid\n");
+ return -1;
+ }
+
+ arm_sp.uuids[index] = uuid_helper;
+
+ /* Read Load address */
+ err = fdt_read_uint32(dtb, sp_node, "load-address", &val32);
+ if (err < 0) {
+ ERROR("FCONF: cannot read SP load address\n");
+ return -1;
+ }
+ arm_sp.load_addr[index] = val32;
+
+ VERBOSE("FCONF: %s UUID"
+ " %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
+ " load_addr=%lx\n",
+ __func__,
+ uuid_helper.uuid_struct.time_low[0], uuid_helper.uuid_struct.time_low[1],
+ uuid_helper.uuid_struct.time_low[2], uuid_helper.uuid_struct.time_low[3],
+ uuid_helper.uuid_struct.time_mid[0], uuid_helper.uuid_struct.time_mid[1],
+ uuid_helper.uuid_struct.time_hi_and_version[0],
+ uuid_helper.uuid_struct.time_hi_and_version[1],
+ uuid_helper.uuid_struct.clock_seq_hi_and_reserved,
+ uuid_helper.uuid_struct.clock_seq_low,
+ uuid_helper.uuid_struct.node[0], uuid_helper.uuid_struct.node[1],
+ uuid_helper.uuid_struct.node[2], uuid_helper.uuid_struct.node[3],
+ uuid_helper.uuid_struct.node[4], uuid_helper.uuid_struct.node[5],
+ arm_sp.load_addr[index]);
+
+ /* Read owner field only for dualroot CoT */
+#if defined(ARM_COT_dualroot)
+ /* Owner is an optional field, no need to catch error */
+ fdtw_read_string(dtb, sp_node, "owner",
+ arm_sp.owner[index], ARM_SP_OWNER_NAME_LEN);
+
+ /* If owner is empty mark it as SiP owned */
+ if ((strncmp(arm_sp.owner[index], "SiP",
+ ARM_SP_OWNER_NAME_LEN) == 0) ||
+ (strncmp(arm_sp.owner[index], "",
+ ARM_SP_OWNER_NAME_LEN) == 0)) {
+ is_plat_owned = false;
+ } else if (strcmp(arm_sp.owner[index], "Plat") == 0) {
+ is_plat_owned = true;
+ } else {
+ ERROR("FCONF: %s is not a valid SP owner\n",
+ arm_sp.owner[index]);
+ return -1;
+ }
+ /*
+ * Add SP information in mem param descriptor and IO policies
+ * structure.
+ */
+ if (is_plat_owned) {
+ sp_mem_params_descs[index].image_id = plat_index;
+ policies[plat_index].image_spec =
+ (uintptr_t)&arm_sp.uuids[index];
+ policies[plat_index].dev_handle = &fip_dev_handle;
+ policies[plat_index].check = open_fip;
+ plat_index++;
+ } else
+#endif /* ARM_COT_dualroot */
+ {
+ sp_mem_params_descs[index].image_id = sip_index;
+ policies[sip_index].image_spec =
+ (uintptr_t)&arm_sp.uuids[index];
+ policies[sip_index].dev_handle = &fip_dev_handle;
+ policies[sip_index].check = open_fip;
+ sip_index++;
+ }
+ SET_PARAM_HEAD(&sp_mem_params_descs[index].image_info,
+ PARAM_IMAGE_BINARY, VERSION_2, 0);
+ sp_mem_params_descs[index].image_info.image_max_size =
+ ARM_SP_MAX_SIZE;
+ sp_mem_params_descs[index].next_handoff_image_id =
+ INVALID_IMAGE_ID;
+ sp_mem_params_descs[index].image_info.image_base =
+ arm_sp.load_addr[index];
+ index++;
+ }
+
+ if ((sp_node < 0) && (sp_node != -FDT_ERR_NOTFOUND)) {
+ ERROR("%u: fdt_for_each_subnode(): %d\n", __LINE__, node);
+ return sp_node;
+ }
+
+ arm_sp.number_of_sp = index;
+ return 0;
+}
+
+FCONF_REGISTER_POPULATOR(TB_FW, arm_sp, fconf_populate_arm_sp);
+
+#endif /* IMAGE_BL2 */
diff --git a/plat/arm/common/fconf/fconf_ethosn_getter.c b/plat/arm/common/fconf/fconf_ethosn_getter.c
new file mode 100644
index 0000000..0b48a98
--- /dev/null
+++ b/plat/arm/common/fconf/fconf_ethosn_getter.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <libfdt.h>
+#include <plat/arm/common/fconf_ethosn_getter.h>
+
+struct ethosn_config_t ethosn_config = {0};
+
+struct ethosn_sub_allocator_t {
+ const char *name;
+ size_t name_len;
+ uint32_t stream_id;
+};
+
+static bool fdt_node_is_enabled(const void *fdt, int node)
+{
+ int len;
+ const char *node_status;
+
+ node_status = fdt_getprop(fdt, node, "status", &len);
+ if (node_status == NULL ||
+ (len == 5 && /* Includes null character */
+ strncmp(node_status, "okay", 4U) == 0)) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool fdt_node_has_reserved_memory(const void *fdt, int dev_node)
+{
+ return fdt_get_property(fdt, dev_node, "memory-region", NULL) != NULL;
+}
+
+static int fdt_node_get_iommus_stream_id(const void *fdt, int node, uint32_t *stream_id)
+{
+ int err;
+ uint32_t iommus_array[2] = {0U};
+
+ err = fdt_read_uint32_array(fdt, node, "iommus", 2U, iommus_array);
+ if (err) {
+ return err;
+ }
+
+ *stream_id = iommus_array[1];
+ return 0;
+}
+
+static int fdt_node_populate_sub_allocators(const void *fdt,
+ int alloc_node,
+ struct ethosn_sub_allocator_t *sub_allocators,
+ size_t num_allocs)
+{
+ int sub_node;
+ size_t i;
+ int err = -FDT_ERR_NOTFOUND;
+ uint32_t found_sub_allocators = 0U;
+
+ fdt_for_each_subnode(sub_node, fdt, alloc_node) {
+ const char *node_name;
+
+ if (!fdt_node_is_enabled(fdt, sub_node)) {
+ /* Ignore disabled node */
+ continue;
+ }
+
+ if (fdt_node_check_compatible(fdt, sub_node, "ethosn-memory") != 0) {
+ continue;
+ }
+
+ node_name = fdt_get_name(fdt, sub_node, NULL);
+ for (i = 0U; i < num_allocs; ++i) {
+ if (strncmp(node_name, sub_allocators[i].name,
+ sub_allocators[i].name_len) != 0) {
+ continue;
+ }
+
+ err = fdt_node_get_iommus_stream_id(fdt, sub_node,
+ &sub_allocators[i].stream_id);
+ if (err) {
+ ERROR("FCONF: Failed to get stream ID from sub-allocator %s\n",
+ node_name);
+ return err;
+ }
+
+ ++found_sub_allocators;
+ /* Nothing more to do for this node */
+ break;
+ }
+
+ /* Check that at least one of the sub-allocators matched */
+ if (i == num_allocs) {
+ ERROR("FCONF: Unknown sub-allocator %s\n", node_name);
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+ }
+
+ if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
+ ERROR("FCONF: Failed to parse sub-allocators\n");
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ if (err == -FDT_ERR_NOTFOUND) {
+ ERROR("FCONF: No matching sub-allocator found\n");
+ return err;
+ }
+
+ if (found_sub_allocators != num_allocs) {
+ ERROR("FCONF: Not all sub-allocators were found\n");
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ return 0;
+}
+
+static int fdt_node_populate_main_allocator(const void *fdt,
+ int alloc_node,
+ struct ethosn_main_allocator_t *allocator)
+{
+ int err;
+ struct ethosn_sub_allocator_t sub_allocators[] = {
+ {.name = "firmware", .name_len = 8U},
+ {.name = "working_data", .name_len = 12U}
+ };
+
+ err = fdt_node_populate_sub_allocators(fdt, alloc_node, sub_allocators,
+ ARRAY_SIZE(sub_allocators));
+ if (err) {
+ return err;
+ }
+
+ allocator->firmware.stream_id = sub_allocators[0].stream_id;
+ allocator->working_data.stream_id = sub_allocators[1].stream_id;
+
+ return 0;
+}
+
+static int fdt_node_populate_asset_allocator(const void *fdt,
+ int alloc_node,
+ struct ethosn_asset_allocator_t *allocator)
+{
+ int err;
+ struct ethosn_sub_allocator_t sub_allocators[] = {
+ {.name = "command_stream", .name_len = 14U},
+ {.name = "weight_data", .name_len = 11U},
+ {.name = "buffer_data", .name_len = 11U},
+ {.name = "intermediate_data", .name_len = 17U}
+ };
+
+ err = fdt_node_populate_sub_allocators(fdt, alloc_node, sub_allocators,
+ ARRAY_SIZE(sub_allocators));
+ if (err) {
+ return err;
+ }
+
+
+ allocator->command_stream.stream_id = sub_allocators[0].stream_id;
+ allocator->weight_data.stream_id = sub_allocators[1].stream_id;
+ allocator->buffer_data.stream_id = sub_allocators[2].stream_id;
+ allocator->intermediate_data.stream_id = sub_allocators[3].stream_id;
+ return 0;
+}
+
+static int fdt_node_populate_core(const void *fdt,
+ int device_node,
+ int core_node,
+ bool has_reserved_memory,
+ uint32_t core_index,
+ struct ethosn_core_t *core)
+{
+ int err;
+ int sub_node;
+ uintptr_t core_addr;
+
+ err = fdt_get_reg_props_by_index(fdt, device_node, core_index,
+ &core_addr, NULL);
+ if (err < 0) {
+ ERROR("FCONF: Failed to read reg property for NPU core %u\n",
+ core_index);
+ return err;
+ }
+
+ err = -FDT_ERR_NOTFOUND;
+ fdt_for_each_subnode(sub_node, fdt, core_node) {
+
+ if (!fdt_node_is_enabled(fdt, sub_node)) {
+ continue;
+ }
+
+ if (fdt_node_check_compatible(fdt,
+ sub_node,
+ "ethosn-main_allocator") != 0) {
+ continue;
+ }
+
+ if (has_reserved_memory) {
+ ERROR("FCONF: Main allocator not supported when using reserved memory\n");
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ if (err != -FDT_ERR_NOTFOUND) {
+ ERROR("FCONF: NPU core 0x%lx has more than one main allocator\n",
+ core_addr);
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ err = fdt_node_populate_main_allocator(fdt, sub_node, &core->main_allocator);
+ if (err) {
+ ERROR("FCONF: Failed to parse main allocator for NPU core 0x%lx\n",
+ core_addr);
+ return err;
+ }
+ }
+
+ if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
+ ERROR("FCONF: Failed to parse core sub nodes\n");
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ if (!has_reserved_memory && err) {
+ ERROR("FCONF: Main allocator not found for NPU core 0x%lx\n",
+ core_addr);
+ return err;
+ }
+
+ core->addr = core_addr;
+
+ return 0;
+}
+
+int fconf_populate_ethosn_config(uintptr_t config)
+{
+ int ethosn_node;
+ uint32_t dev_count = 0U;
+ const void *hw_conf_dtb = (const void *)config;
+
+ INFO("Probing Arm(R) Ethos(TM)-N NPU\n");
+
+ fdt_for_each_compatible_node(hw_conf_dtb, ethosn_node, "ethosn") {
+ struct ethosn_device_t *dev = &ethosn_config.devices[dev_count];
+ uint32_t dev_asset_alloc_count = 0U;
+ uint32_t dev_core_count = 0U;
+ bool has_reserved_memory;
+ int sub_node;
+
+ if (!fdt_node_is_enabled(hw_conf_dtb, ethosn_node)) {
+ continue;
+ }
+
+ if (dev_count >= ETHOSN_DEV_NUM_MAX) {
+ ERROR("FCONF: Reached max number of NPUs\n");
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ has_reserved_memory = fdt_node_has_reserved_memory(hw_conf_dtb, ethosn_node);
+ fdt_for_each_subnode(sub_node, hw_conf_dtb, ethosn_node) {
+ int err;
+
+ if (!fdt_node_is_enabled(hw_conf_dtb, sub_node)) {
+ /* Ignore disabled sub node */
+ continue;
+ }
+
+ if (fdt_node_check_compatible(hw_conf_dtb,
+ sub_node,
+ "ethosn-core") == 0) {
+
+ if (dev_core_count >= ETHOSN_DEV_CORE_NUM_MAX) {
+ ERROR("FCONF: Reached max number of NPU cores for NPU %u\n",
+ dev_count);
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ err = fdt_node_populate_core(hw_conf_dtb,
+ ethosn_node,
+ sub_node,
+ has_reserved_memory,
+ dev_core_count,
+ &(dev->cores[dev_core_count]));
+ if (err) {
+ return err;
+ }
+ ++dev_core_count;
+ } else if (fdt_node_check_compatible(hw_conf_dtb,
+ sub_node,
+ "ethosn-asset_allocator") == 0) {
+
+ if (dev_asset_alloc_count >=
+ ETHOSN_DEV_ASSET_ALLOCATOR_NUM_MAX) {
+ ERROR("FCONF: Reached max number of asset allocators for NPU %u\n",
+ dev_count);
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ if (has_reserved_memory) {
+ ERROR("FCONF: Asset allocator not supported when using reserved memory\n");
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ err = fdt_node_populate_asset_allocator(hw_conf_dtb,
+ sub_node,
+ &(dev->asset_allocators[dev_asset_alloc_count]));
+ if (err) {
+ ERROR("FCONF: Failed to parse asset allocator for NPU %u\n",
+ dev_count);
+ return err;
+ }
+ ++dev_asset_alloc_count;
+ }
+ }
+
+ if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
+ ERROR("FCONF: Failed to parse sub nodes for NPU %u\n",
+ dev_count);
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ if (dev_core_count == 0U) {
+ ERROR("FCONF: NPU %u must have at least one enabled core\n",
+ dev_count);
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ if (!has_reserved_memory && dev_asset_alloc_count == 0U) {
+ ERROR("FCONF: NPU %u must have at least one asset allocator\n",
+ dev_count);
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ dev->num_cores = dev_core_count;
+ dev->num_allocators = dev_asset_alloc_count;
+ dev->has_reserved_memory = has_reserved_memory;
+ ++dev_count;
+ }
+
+ if (dev_count == 0U) {
+ ERROR("FCONF: Can't find 'ethosn' compatible node in dtb\n");
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+
+ ethosn_config.num_devices = dev_count;
+
+ return 0;
+}
+
+FCONF_REGISTER_POPULATOR(HW_CONFIG, ethosn_config, fconf_populate_ethosn_config);
diff --git a/plat/arm/common/fconf/fconf_nv_cntr_getter.c b/plat/arm/common/fconf/fconf_nv_cntr_getter.c
new file mode 100644
index 0000000..8d645ef
--- /dev/null
+++ b/plat/arm/common/fconf/fconf_nv_cntr_getter.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+
+#include <libfdt.h>
+
+#include <plat/arm/common/fconf_nv_cntr_getter.h>
+
+/*******************************************************************************
+ * fconf_populate_cot_descs() - Populate available nv-counters and update global
+ * structure.
+ * @config[in]: Pointer to the device tree blob in memory
+ *
+ * Return 0 on success or an error value otherwise.
+ ******************************************************************************/
+static int fconf_populate_nv_cntrs(uintptr_t config)
+{
+ int rc, node, child;
+ uint32_t id;
+ uintptr_t reg;
+
+ /* As libfdt uses void *, we can't avoid this cast */
+ const void *dtb = (void *)config;
+ const char *compatible_str = "arm, non-volatile-counter";
+
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
+ if (node < 0) {
+ ERROR("FCONF: Can't find %s compatible in node\n",
+ compatible_str);
+ return node;
+ }
+
+ fdt_for_each_subnode(child, dtb, node) {
+
+ rc = fdt_read_uint32(dtb, child, "id", &id);
+ if (rc < 0) {
+ ERROR("FCONF: Can't find %s property in node\n", "id");
+ return rc;
+ }
+
+ assert(id < MAX_NV_CTR_IDS);
+
+ rc = fdt_get_reg_props_by_index(dtb, child, 0, &reg, NULL);
+ if (rc < 0) {
+ ERROR("FCONF: Can't find %s property in node\n", "reg");
+ return rc;
+ }
+
+ nv_cntr_base_addr[id] = reg;
+ }
+
+ return 0;
+}
+
+FCONF_REGISTER_POPULATOR(TB_FW, nv_cntrs, fconf_populate_nv_cntrs);
diff --git a/plat/arm/common/fconf/fconf_sdei_getter.c b/plat/arm/common/fconf/fconf_sdei_getter.c
new file mode 100644
index 0000000..c26e316
--- /dev/null
+++ b/plat/arm/common/fconf/fconf_sdei_getter.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <libfdt.h>
+#include <plat/arm/common/fconf_sdei_getter.h>
+
+#define PRIVATE_EVENT_NUM(i) private_events[3 * (i)]
+#define PRIVATE_EVENT_INTR(i) private_events[3 * (i) + 1]
+#define PRIVATE_EVENT_FLAGS(i) private_events[3 * (i) + 2]
+
+#define SHARED_EVENT_NUM(i) shared_events[3 * (i)]
+#define SHARED_EVENT_INTR(i) shared_events[3 * (i) + 1]
+#define SHARED_EVENT_FLAGS(i) shared_events[3 * (i) + 2]
+
+struct sdei_dyn_config_t sdei_dyn_config;
+
+int fconf_populate_sdei_dyn_config(uintptr_t config)
+{
+ uint32_t i;
+ int node, err;
+ uint32_t private_events[PLAT_SDEI_DP_EVENT_MAX_CNT * 3];
+ uint32_t shared_events[PLAT_SDEI_DS_EVENT_MAX_CNT * 3];
+
+ const void *dtb = (void *)config;
+
+ /* Check that the node offset points to compatible property */
+ node = fdt_node_offset_by_compatible(dtb, -1, "arm,sdei-1.0");
+ if (node < 0) {
+ ERROR("FCONF: Can't find 'arm,sdei-1.0' compatible node in dtb\n");
+ return node;
+ }
+
+ /* Read number of private mappings */
+ err = fdt_read_uint32(dtb, node, "private_event_count",
+ &sdei_dyn_config.private_ev_cnt);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'private_event_count': %u\n",
+ sdei_dyn_config.private_ev_cnt);
+ return err;
+ }
+
+ /* Check if the value is in range */
+ if (sdei_dyn_config.private_ev_cnt > PLAT_SDEI_DP_EVENT_MAX_CNT) {
+ ERROR("FCONF: Invalid value for 'private_event_count': %u\n",
+ sdei_dyn_config.private_ev_cnt);
+ return -1;
+ }
+
+ /* Read private mappings */
+ err = fdt_read_uint32_array(dtb, node, "private_events",
+ sdei_dyn_config.private_ev_cnt * 3, private_events);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'private_events': %d\n", err);
+ return err;
+ }
+
+ /* Move data to fconf struct */
+ for (i = 0; i < sdei_dyn_config.private_ev_cnt; i++) {
+ sdei_dyn_config.private_ev_nums[i] = PRIVATE_EVENT_NUM(i);
+ sdei_dyn_config.private_ev_intrs[i] = PRIVATE_EVENT_INTR(i);
+ sdei_dyn_config.private_ev_flags[i] = PRIVATE_EVENT_FLAGS(i);
+ }
+
+ /* Read number of shared mappings */
+ err = fdt_read_uint32(dtb, node, "shared_event_count",
+ &sdei_dyn_config.shared_ev_cnt);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'shared_event_count'\n");
+ return err;
+ }
+
+ /* Check if the value is in range */
+ if (sdei_dyn_config.shared_ev_cnt > PLAT_SDEI_DS_EVENT_MAX_CNT) {
+ ERROR("FCONF: Invalid value for 'shared_event_count': %u\n",
+ sdei_dyn_config.shared_ev_cnt);
+ return -1;
+ }
+
+ /* Read shared mappings */
+ err = fdt_read_uint32_array(dtb, node, "shared_events",
+ sdei_dyn_config.shared_ev_cnt * 3, shared_events);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'shared_events': %d\n", err);
+ return err;
+ }
+
+ /* Move data to fconf struct */
+ for (i = 0; i < sdei_dyn_config.shared_ev_cnt; i++) {
+ sdei_dyn_config.shared_ev_nums[i] = SHARED_EVENT_NUM(i);
+ sdei_dyn_config.shared_ev_intrs[i] = SHARED_EVENT_INTR(i);
+ sdei_dyn_config.shared_ev_flags[i] = SHARED_EVENT_FLAGS(i);
+ }
+
+ return 0;
+}
+
+FCONF_REGISTER_POPULATOR(HW_CONFIG, sdei, fconf_populate_sdei_dyn_config);
diff --git a/plat/arm/common/fconf/fconf_sec_intr_config.c b/plat/arm/common/fconf/fconf_sec_intr_config.c
new file mode 100644
index 0000000..f28be24
--- /dev/null
+++ b/plat/arm/common/fconf/fconf_sec_intr_config.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <libfdt.h>
+#include <plat/arm/common/fconf_sec_intr_config.h>
+
+#define G0_INTR_NUM(i) g0_intr_prop[3U * (i)]
+#define G0_INTR_PRIORITY(i) g0_intr_prop[3U * (i) + 1]
+#define G0_INTR_CONFIG(i) g0_intr_prop[3U * (i) + 2]
+
+#define G1S_INTR_NUM(i) g1s_intr_prop[3U * (i)]
+#define G1S_INTR_PRIORITY(i) g1s_intr_prop[3U * (i) + 1]
+#define G1S_INTR_CONFIG(i) g1s_intr_prop[3U * (i) + 2]
+
+struct sec_intr_prop_t sec_intr_prop;
+
+static void print_intr_prop(interrupt_prop_t prop)
+{
+ VERBOSE("FCONF: Secure Interrupt NUM: %d, PRI: %d, TYPE: %d\n",
+ prop.intr_num, prop.intr_pri, prop.intr_cfg);
+}
+
+int fconf_populate_sec_intr_config(uintptr_t config)
+{
+ int node, err;
+ uint32_t g0_intr_count, g1s_intr_count;
+ uint32_t g0_intr_prop[SEC_INT_COUNT_MAX * 3];
+ uint32_t g1s_intr_prop[SEC_INT_COUNT_MAX * 3];
+
+ /* Necessary to work with libfdt APIs */
+ const void *hw_config_dtb = (const void *)config;
+
+ node = fdt_node_offset_by_compatible(hw_config_dtb, -1,
+ "arm,secure_interrupt_desc");
+ if (node < 0) {
+ ERROR("FCONF: Unable to locate node with %s compatible property\n",
+ "arm,secure_interrupt_desc");
+ return node;
+ }
+
+ /* Read number of Group 0 interrupts specified by platform */
+ err = fdt_read_uint32(hw_config_dtb, node, "g0_intr_cnt", &g0_intr_count);
+ if (err < 0) {
+ ERROR("FCONF: Could not locate g0s_intr_cnt property\n");
+ return err;
+ }
+
+ /* At least 1 Group 0 interrupt description has to be provided*/
+ if (g0_intr_count < 1U) {
+ ERROR("FCONF: Invalid number of Group 0 interrupts count specified\n");
+ return -1;
+ }
+
+ /* Read number of Group 1 secure interrupts specified by platform */
+ err = fdt_read_uint32(hw_config_dtb, node, "g1s_intr_cnt",
+ &g1s_intr_count);
+ if (err < 0) {
+ ERROR("FCONF: Could not locate g1s_intr_cnt property\n");
+ return err;
+ }
+
+ /* At least one Group 1 interrupt description has to be provided*/
+ if (g1s_intr_count < 1U) {
+ ERROR("FCONF: Invalid number of Group 1 secure interrupts count specified\n");
+ return -1;
+ }
+
+ /*
+ * Check if the total number of secure interrupts described are within
+ * the limit defined statically by the platform.
+ */
+ if ((g0_intr_count + g1s_intr_count) > SEC_INT_COUNT_MAX) {
+ ERROR("FCONF: Total number of secure interrupts exceed limit the of %d\n",
+ SEC_INT_COUNT_MAX);
+ return -1;
+ }
+
+ sec_intr_prop.count = g0_intr_count + g1s_intr_count;
+
+ /* Read the Group 0 interrupt descriptors */
+ err = fdt_read_uint32_array(hw_config_dtb, node, "g0_intr_desc",
+ g0_intr_count * 3, g0_intr_prop);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'g0s_intr_desc': %d\n", err);
+ return err;
+ }
+
+ /* Read the Group 1 secure interrupt descriptors */
+ err = fdt_read_uint32_array(hw_config_dtb, node, "g1s_intr_desc",
+ g1s_intr_count * 3, g1s_intr_prop);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'g1s_intr_desc': %d\n", err);
+ return err;
+ }
+
+ /* Populate Group 0 interrupt descriptors into fconf based C struct */
+ for (uint32_t i = 0; i < g0_intr_count; i++) {
+ interrupt_prop_t sec_intr_property;
+
+ /* Secure Interrupt Group: INTR_GROUP0 i.e., 0x1 */
+ sec_intr_property.intr_grp = 1;
+ sec_intr_property.intr_num = G0_INTR_NUM(i);
+ sec_intr_property.intr_pri = G0_INTR_PRIORITY(i);
+ sec_intr_property.intr_cfg = G0_INTR_CONFIG(i);
+ sec_intr_prop.descriptor[i] = sec_intr_property;
+ print_intr_prop(sec_intr_property);
+ }
+
+ /* Populate G1 secure interrupt descriptors into fconf based C struct */
+ for (uint32_t i = 0; i < g1s_intr_count; i++) {
+ interrupt_prop_t sec_intr_property;
+
+ /* Secure Interrupt Group: INTR_GROUP1S i.e., 0x0 */
+ sec_intr_property.intr_grp = 0;
+ sec_intr_property.intr_num = G1S_INTR_NUM(i);
+ sec_intr_property.intr_pri = G1S_INTR_PRIORITY(i);
+ sec_intr_property.intr_cfg = G1S_INTR_CONFIG(i);
+ sec_intr_prop.descriptor[i + g0_intr_count] = sec_intr_property;
+ print_intr_prop(sec_intr_property);
+ }
+
+ return 0;
+}
+
+FCONF_REGISTER_POPULATOR(HW_CONFIG, sec_intr_prop, fconf_populate_sec_intr_config);
diff --git a/plat/arm/common/sp_min/arm_sp_min.mk b/plat/arm/common/sp_min/arm_sp_min.mk
new file mode 100644
index 0000000..dbd451c
--- /dev/null
+++ b/plat/arm/common/sp_min/arm_sp_min.mk
@@ -0,0 +1,20 @@
+#
+# 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
diff --git a/plat/arm/common/sp_min/arm_sp_min_setup.c b/plat/arm/common/sp_min/arm_sp_min_setup.c
new file mode 100644
index 0000000..f15c137
--- /dev/null
+++ b/plat/arm/common/sp_min/arm_sp_min_setup.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <bl32/sp_min/platform_sp_min.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+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_FW_CONFIG_LIMIT. The reserved page
+ * is required for SOC_FW_CONFIG/TOS_FW_CONFIG passed from BL2.
+ */
+#if !RESET_TO_SP_MIN
+CASSERT(BL32_BASE >= ARM_FW_CONFIG_LIMIT, assert_bl32_base_overflows);
+#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.
+ ******************************************************************************/
+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();
+
+#if PLAT_RO_XLAT_TABLES
+ arm_xlat_make_tables_readonly();
+#endif
+}
+
+/*******************************************************************************
+ * 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 && !JUNO_AARCH32_EL3_RUNTIME
+ 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 arm_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);
+}
+
+void sp_min_plat_arch_setup(void)
+{
+ arm_sp_min_plat_arch_setup();
+}
diff --git a/plat/arm/common/trp/arm_trp.mk b/plat/arm/common/trp/arm_trp.mk
new file mode 100644
index 0000000..204c14a
--- /dev/null
+++ b/plat/arm/common/trp/arm_trp.mk
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# TRP source files common to ARM standard platforms
+RMM_SOURCES += plat/arm/common/trp/arm_trp_setup.c \
+ plat/arm/common/arm_topology.c \
+ plat/common/aarch64/platform_mp_stack.S
+
+INCLUDES += -Iinclude/services/trp
diff --git a/plat/arm/common/trp/arm_trp_setup.c b/plat/arm/common/trp/arm_trp_setup.c
new file mode 100644
index 0000000..59b4c06
--- /dev/null
+++ b/plat/arm/common/trp/arm_trp_setup.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <services/rmm_core_manifest.h>
+#include <services/rmmd_svc.h>
+#include <services/trp/platform_trp.h>
+#include <trp_helpers.h>
+
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+/*******************************************************************************
+ * Received from boot manifest and populated here
+ ******************************************************************************/
+extern uint32_t trp_boot_manifest_version;
+
+/*******************************************************************************
+ * Initialize the UART
+ ******************************************************************************/
+static console_t arm_trp_runtime_console;
+
+static int arm_trp_process_manifest(rmm_manifest_t *manifest)
+{
+ /* Verify the Boot Manifest Version. Only the Major is considered */
+ if (RMMD_MANIFEST_VERSION_MAJOR !=
+ RMMD_GET_MANIFEST_VERSION_MAJOR(manifest->version)) {
+ return E_RMM_BOOT_MANIFEST_VERSION_NOT_SUPPORTED;
+ }
+
+ trp_boot_manifest_version = manifest->version;
+ flush_dcache_range((uintptr_t)manifest, sizeof(rmm_manifest_t));
+
+ return 0;
+}
+
+void arm_trp_early_platform_setup(rmm_manifest_t *manifest)
+{
+ int rc;
+
+ rc = arm_trp_process_manifest(manifest);
+ if (rc != 0) {
+ trp_boot_abort(rc);
+ }
+
+ /*
+ * Initialize a different console than already in use to display
+ * messages from trp
+ */
+ rc = console_pl011_register(PLAT_ARM_TRP_UART_BASE,
+ PLAT_ARM_TRP_UART_CLK_IN_HZ,
+ ARM_CONSOLE_BAUDRATE,
+ &arm_trp_runtime_console);
+ if (rc == 0) {
+ panic();
+ }
+
+ console_set_scope(&arm_trp_runtime_console,
+ CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME);
+
+}
+
+void trp_early_platform_setup(rmm_manifest_t *manifest)
+{
+ arm_trp_early_platform_setup(manifest);
+}
diff --git a/plat/arm/common/tsp/arm_tsp.mk b/plat/arm/common/tsp/arm_tsp.mk
new file mode 100644
index 0000000..4ad77c6
--- /dev/null
+++ b/plat/arm/common/tsp/arm_tsp.mk
@@ -0,0 +1,10 @@
+#
+# 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
diff --git a/plat/arm/common/tsp/arm_tsp_setup.c b/plat/arm/common/tsp/arm_tsp_setup.c
new file mode 100644
index 0000000..a4da8c3
--- /dev/null
+++ b/plat/arm/common/tsp/arm_tsp_setup.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <bl32/tsp/platform_tsp.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <plat/arm/common/plat_arm.h>
+
+/* 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_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_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);
+
+#if PLAT_RO_XLAT_TABLES
+ arm_xlat_make_tables_readonly();
+#endif
+}
diff --git a/plat/arm/css/common/aarch32/css_helpers.S b/plat/arm/css/common/aarch32/css_helpers.S
new file mode 100644
index 0000000..d47e13d
--- /dev/null
+++ b/plat/arm/css/common/aarch32/css_helpers.S
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cpu_macros.S>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/arm/css/common/aarch64/css_helpers.S b/plat/arm/css/common/aarch64/css_helpers.S
new file mode 100644
index 0000000..01669be
--- /dev/null
+++ b/plat/arm/css/common/aarch64/css_helpers.S
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cpu_macros.S>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/arm/css/common/css_bl1_setup.c b/plat/arm/css/common/css_bl1_setup.c
new file mode 100644
index 0000000..596cc3d
--- /dev/null
+++ b/plat/arm/css/common/css_bl1_setup.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/soc/common/soc_css.h>
+#include <plat/common/platform.h>
+
+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();
+}
+
diff --git a/plat/arm/css/common/css_bl2_setup.c b/plat/arm/css/common/css_bl2_setup.c
new file mode 100644
index 0000000..002c6eb
--- /dev/null
+++ b/plat/arm/css/common/css_bl2_setup.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_scp.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+/* 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 */
diff --git a/plat/arm/css/common/css_bl2u_setup.c b/plat/arm/css/common/css_bl2u_setup.c
new file mode 100644
index 0000000..15cf4f6
--- /dev/null
+++ b/plat/arm/css/common/css_bl2u_setup.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_scp.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/* 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;
+}
diff --git a/plat/arm/css/common/css_common.mk b/plat/arm/css/common/css_common.mk
new file mode 100644
index 0000000..1e4851c
--- /dev/null
+++ b/plat/arm/css/common/css_common.mk
@@ -0,0 +1,97 @@
+#
+# Copyright (c) 2015-2022, 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/delay_timer/delay_timer.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))
+
+# Process CSS_SYSTEM_GRACEFUL_RESET flag
+# This build option can be used on CSS platforms that require all the CPUs
+# to execute the CPU specific power down sequence to complete a warm reboot
+# sequence in which only the CPUs are power cycled.
+CSS_SYSTEM_GRACEFUL_RESET := 0
+$(eval $(call add_define,CSS_SYSTEM_GRACEFUL_RESET))
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c
new file mode 100644
index 0000000..9b2639c
--- /dev/null
+++ b/plat/arm/css/common/css_pm.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_scp.h>
+#include <lib/cassert.h>
+#include <plat/arm/common/plat_arm.h>
+
+#include <plat/common/platform.h>
+
+#include <plat/arm/css/common/css_pm.h>
+
+/* 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();
+
+ /* Setup the CPU power down request interrupt for secondary core(s) */
+ css_setup_cpu_pwr_down_intr();
+}
+
+/*******************************************************************************
+ * 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();
+
+ /* Turn redistributor off */
+ plat_arm_gic_redistif_off();
+
+ /* 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();
+
+#if HW_ASSISTED_COHERENCY
+ uint32_t reg;
+
+ /*
+ * If we have determined this core to be the last man standing and we
+ * intend to power down the cluster proactively, we provide a hint to
+ * the power controller that cluster power is not required when all
+ * cores are powered down.
+ * Note that this is only an advisory to power controller and is supported
+ * by SoCs with DynamIQ Shared Units only.
+ */
+ reg = read_clusterpwrdn();
+
+ /* Clear and set bit 0 : Cluster power not required */
+ reg &= ~DSU_CLUSTER_PWR_MASK;
+ reg |= DSU_CLUSTER_PWR_OFF;
+ write_clusterpwrdn(reg);
+#endif
+ }
+}
+
+/*******************************************************************************
+ * 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);
+}
+
+/*
+ * Setup the SGI interrupt that will be used trigger the execution of power
+ * down sequence for all the secondary cores. This interrupt is setup to be
+ * handled in EL3 context at a priority defined by the platform.
+ */
+void css_setup_cpu_pwr_down_intr(void)
+{
+#if CSS_SYSTEM_GRACEFUL_RESET
+ plat_ic_set_interrupt_type(CSS_CPU_PWR_DOWN_REQ_INTR, INTR_TYPE_EL3);
+ plat_ic_set_interrupt_priority(CSS_CPU_PWR_DOWN_REQ_INTR,
+ PLAT_REBOOT_PRI);
+ plat_ic_enable_interrupt(CSS_CPU_PWR_DOWN_REQ_INTR);
+#endif
+}
+
+/*
+ * For a graceful shutdown/reboot, each CPU in the system should do their power
+ * down sequence. On a PSCI shutdown/reboot request, only one CPU gets an
+ * opportunity to do the powerdown sequence. To achieve graceful reset, of all
+ * cores in the system, the CPU gets the opportunity raise warm reboot SGI to
+ * rest of the CPUs which are online. Add handler for the reboot SGI where the
+ * rest of the CPU execute the powerdown sequence.
+ */
+int css_reboot_interrupt_handler(uint32_t intr_raw, uint32_t flags,
+ void *handle, void *cookie)
+{
+ assert(intr_raw == CSS_CPU_PWR_DOWN_REQ_INTR);
+
+ /* Deactivate warm reboot SGI */
+ plat_ic_end_of_interrupt(CSS_CPU_PWR_DOWN_REQ_INTR);
+
+ /*
+ * Disable GIC CPU interface to prevent pending interrupt from waking
+ * up the AP from WFI.
+ */
+ plat_arm_gic_cpuif_disable();
+ plat_arm_gic_redistif_off();
+
+ psci_pwrdown_cpu(PLAT_MAX_PWR_LVL);
+
+ dmbsy();
+
+ wfi();
+ return 0;
+}
+
+/*******************************************************************************
+ * 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
+};
diff --git a/plat/arm/css/common/css_topology.c b/plat/arm/css/common/css_topology.c
new file mode 100644
index 0000000..8aca744
--- /dev/null
+++ b/plat/arm/css/common/css_topology.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#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 */
diff --git a/plat/arm/css/common/sp_min/css_sp_min.mk b/plat/arm/css/common/sp_min/css_sp_min.mk
new file mode 100644
index 0000000..ae489fd
--- /dev/null
+++ b/plat/arm/css/common/sp_min/css_sp_min.mk
@@ -0,0 +1,22 @@
+#
+# 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/delay_timer/delay_timer.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
diff --git a/plat/arm/css/sgi/aarch64/sgi_helper.S b/plat/arm/css/sgi/aarch64/sgi_helper.S
new file mode 100644
index 0000000..ced59e8
--- /dev/null
+++ b/plat/arm/css/sgi/aarch64/sgi_helper.S
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+#include <cortex_a75.h>
+#include <neoverse_n1.h>
+#include <neoverse_v1.h>
+#include <neoverse_n2.h>
+#include <cpu_macros.S>
+
+ .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.
+ * (ChipId * PLAT_ARM_CLUSTER_COUNT *
+ * CSS_SGI_MAX_CPUS_PER_CLUSTER * CSS_SGI_MAX_PE_PER_CPU) +
+ * (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:
+ *
+ * ((((ChipId * PLAT_ARM_CLUSTER_COUNT) + ClusterId) *
+ * CSS_SGI_MAX_CPUS_PER_CLUSTER) + CPUId) * CSS_SGI_MAX_PE_PER_CPU +
+ * ThreadId
+ * ------------------------------------------------------
+ */
+
+func plat_arm_calc_core_pos
+ mov x4, 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, x4, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
+ ubfx x1, x4, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
+ ubfx x2, x4, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
+ ubfx x3, x4, #MPIDR_AFF3_SHIFT, #MPIDR_AFFINITY_BITS
+
+ /* Compute linear position */
+ mov x4, #PLAT_ARM_CLUSTER_COUNT
+ madd x2, x3, x4, x2
+ mov x4, #CSS_SGI_MAX_CPUS_PER_CLUSTER
+ madd x1, x2, x4, x1
+ mov x4, #CSS_SGI_MAX_PE_PER_CPU
+ madd x0, x1, x4, 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
+ jump_if_cpu_midr NEOVERSE_V1_MIDR, V1
+ jump_if_cpu_midr NEOVERSE_N2_MIDR, N2
+ 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
+
+V1:
+ mrs x0, NEOVERSE_V1_CPUPWRCTLR_EL1
+ bic x0, x0, #NEOVERSE_V1_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+ msr NEOVERSE_V1_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+
+N2:
+ mrs x0, NEOVERSE_N2_CPUPWRCTLR_EL1
+ bic x0, x0, #NEOVERSE_N2_CORE_PWRDN_EN_BIT
+ msr NEOVERSE_N2_CPUPWRCTLR_EL1, x0
+ isb
+ ret
+endfunc plat_reset_handler
diff --git a/plat/arm/css/sgi/include/plat_macros.S b/plat/arm/css/sgi/include/plat_macros.S
new file mode 100644
index 0000000..521bcc3
--- /dev/null
+++ b/plat/arm/css/sgi/include/plat_macros.S
@@ -0,0 +1,24 @@
+/*
+ * 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 <css_macros.S>
+
+/* ---------------------------------------------
+ * 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 */
diff --git a/plat/arm/css/sgi/include/sgi_base_platform_def.h b/plat/arm/css/sgi/include/sgi_base_platform_def.h
new file mode 100644
index 0000000..c1fadc6
--- /dev/null
+++ b/plat/arm/css/sgi/include/sgi_base_platform_def.h
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2018-2022, 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 <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/arm/common/arm_def.h>
+#include <plat/arm/common/arm_spm_def.h>
+#include <plat/arm/css/common/css_def.h>
+#include <plat/common/common_def.h>
+
+#define PLATFORM_CORE_COUNT (CSS_SGI_CHIP_COUNT * \
+ PLAT_ARM_CLUSTER_COUNT * \
+ CSS_SGI_MAX_CPUS_PER_CLUSTER * \
+ CSS_SGI_MAX_PE_PER_CPU)
+
+#define PLAT_ARM_TRUSTED_SRAM_SIZE 0x00080000 /* 512 KB */
+
+/* Remote chip address offset */
+#define CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) \
+ ((ULL(1) << CSS_SGI_ADDR_BITS_PER_CHIP) * (n))
+
+/*
+ * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the
+ * plat_arm_mmap array defined for each BL stage. In addition to that, on
+ * multi-chip platforms, address regions on each of the remote chips are
+ * also mapped. In BL31, for instance, three address regions on the remote
+ * chips are accessed - secure ram, css device and soc device regions.
+ */
+#if defined(IMAGE_BL31)
+# if SPM_MM
+# define PLAT_ARM_MMAP_ENTRIES (9 + ((CSS_SGI_CHIP_COUNT - 1) * 3))
+# define MAX_XLAT_TABLES (7 + ((CSS_SGI_CHIP_COUNT - 1) * 3))
+# define PLAT_SP_IMAGE_MMAP_REGIONS 10
+# define PLAT_SP_IMAGE_MAX_XLAT_TABLES 12
+# else
+# define PLAT_ARM_MMAP_ENTRIES (5 + ((CSS_SGI_CHIP_COUNT - 1) * 3))
+# define MAX_XLAT_TABLES (6 + ((CSS_SGI_CHIP_COUNT - 1) * 3))
+# endif
+#elif defined(IMAGE_BL32)
+# define PLAT_ARM_MMAP_ENTRIES 8
+# define MAX_XLAT_TABLES 5
+#elif defined(IMAGE_BL2)
+# define PLAT_ARM_MMAP_ENTRIES (11 + (CSS_SGI_CHIP_COUNT - 1))
+
+/*
+ * MAX_XLAT_TABLES entries need to be doubled because when the address width
+ * exceeds 40 bits an additional level of translation is required. In case of
+ * multichip platforms peripherals also fall into address space with width
+ * > 40 bits
+ *
+ */
+# define MAX_XLAT_TABLES (7 + ((CSS_SGI_CHIP_COUNT - 1) * 2))
+#elif !USE_ROMLIB
+# define PLAT_ARM_MMAP_ENTRIES 11
+# define MAX_XLAT_TABLES 7
+#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 (64 * 1024) /* 64 KB */
+
+/*
+ * 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. Additional 8KiB space is added per chip in
+ * order to accommodate the additional level of translation required for "TZC"
+ * peripheral access which lies in >4TB address space.
+ *
+ */
+#if TRUSTED_BOARD_BOOT
+# define PLAT_ARM_MAX_BL2_SIZE (0x20000 + ((CSS_SGI_CHIP_COUNT - 1) * \
+ 0x2000))
+#else
+# define PLAT_ARM_MAX_BL2_SIZE (0x14000 + ((CSS_SGI_CHIP_COUNT - 1) * \
+ 0x2000))
+#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. CSS_SGI_BL31_SIZE - is tuned with respect to the actual BL31
+ * PROGBITS size which is around 64-68KB at the time this change is being made.
+ * A buffer of ~35KB is added to account for future expansion of the image,
+ * making it a total of 100KB.
+ */
+#define CSS_SGI_BL31_SIZE (100 * 1024) /* 100 KB */
+#define PLAT_ARM_MAX_BL31_SIZE (CSS_SGI_BL31_SIZE + \
+ PLAT_ARM_MAX_BL2_SIZE + \
+ PLAT_ARM_MAX_BL1_RW_SIZE)
+
+/*
+ * 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 SPM_MM
+# define PLATFORM_STACK_SIZE 0x500
+# else
+# define PLATFORM_STACK_SIZE 0x400
+# endif
+#elif defined(IMAGE_BL32)
+# define PLATFORM_STACK_SIZE 0x440
+#endif
+
+/* PL011 UART related constants */
+#define SOC_CSS_SEC_UART_BASE UL(0x2A410000)
+#define SOC_CSS_NSEC_UART_BASE UL(0x2A400000)
+#define SOC_CSS_UART_SIZE UL(0x10000)
+#define SOC_CSS_UART_CLK_IN_HZ UL(7372800)
+
+/* UART related constants */
+#define PLAT_ARM_BOOT_UART_BASE SOC_CSS_SEC_UART_BASE
+#define PLAT_ARM_BOOT_UART_CLK_IN_HZ SOC_CSS_UART_CLK_IN_HZ
+
+#define PLAT_ARM_RUN_UART_BASE SOC_CSS_SEC_UART_BASE
+#define PLAT_ARM_RUN_UART_CLK_IN_HZ SOC_CSS_UART_CLK_IN_HZ
+
+#define PLAT_ARM_CRASH_UART_BASE SOC_CSS_SEC_UART_BASE
+#define PLAT_ARM_CRASH_UART_CLK_IN_HZ SOC_CSS_UART_CLK_IN_HZ
+
+#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_DRAM2_BASE ULL(0x8080000000)
+#define PLAT_ARM_DRAM2_SIZE ULL(0x180000000)
+
+#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)
+
+#define ARM_MAP_SHARED_RAM_REMOTE_CHIP(n) \
+ MAP_REGION_FLAT( \
+ CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + \
+ ARM_SHARED_RAM_BASE, \
+ ARM_SHARED_RAM_SIZE, \
+ MT_NON_CACHEABLE | MT_RW | MT_SECURE \
+ )
+
+#define CSS_SGI_MAP_DEVICE_REMOTE_CHIP(n) \
+ MAP_REGION_FLAT( \
+ CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + \
+ CSS_SGI_DEVICE_BASE, \
+ CSS_SGI_DEVICE_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE \
+ )
+
+#define SOC_CSS_MAP_DEVICE_REMOTE_CHIP(n) \
+ MAP_REGION_FLAT( \
+ CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + \
+ SOC_CSS_DEVICE_BASE, \
+ SOC_CSS_DEVICE_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE \
+ )
+
+/* 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 SPM_MM && RAS_EXTENSION
+/*
+ * CPER buffer memory of 128KB is reserved and it is placed adjacent to the
+ * memory shared between EL3 and S-EL0.
+ */
+#define CSS_SGI_SP_CPER_BUF_BASE (PLAT_SP_IMAGE_NS_BUF_BASE + \
+ PLAT_SP_IMAGE_NS_BUF_SIZE)
+#define CSS_SGI_SP_CPER_BUF_SIZE ULL(0x20000)
+#define CSS_SGI_SP_CPER_BUF_MMAP MAP_REGION2( \
+ CSS_SGI_SP_CPER_BUF_BASE, \
+ CSS_SGI_SP_CPER_BUF_BASE, \
+ CSS_SGI_SP_CPER_BUF_SIZE, \
+ MT_RW_DATA | MT_NS | MT_USER, \
+ PAGE_SIZE)
+
+/*
+ * Secure partition stack follows right after the memory space reserved for
+ * CPER buffer memory.
+ */
+#define PLAT_ARM_SP_IMAGE_STACK_BASE (PLAT_SP_IMAGE_NS_BUF_BASE + \
+ PLAT_SP_IMAGE_NS_BUF_SIZE + \
+ CSS_SGI_SP_CPER_BUF_SIZE)
+#elif SPM_MM
+/*
+ * Secure partition stack follows right after the memory region that is shared
+ * between EL3 and S-EL0.
+ */
+#define PLAT_ARM_SP_IMAGE_STACK_BASE (PLAT_SP_IMAGE_NS_BUF_BASE + \
+ PLAT_SP_IMAGE_NS_BUF_SIZE)
+#endif /* SPM_MM && 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)
+
+/* Number of SCMI channels on the platform */
+#define PLAT_ARM_SCMI_CHANNEL_COUNT CSS_SGI_CHIP_COUNT
+
+/*
+ * Mapping definition of the TrustZone Controller for ARM SGI/RD platforms
+ * where both the DRAM regions are marked for non-secure access. This applies
+ * to multi-chip platforms.
+ */
+#define SGI_PLAT_TZC_NS_REMOTE_REGIONS_DEF(n) \
+ {CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + ARM_DRAM1_BASE, \
+ CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + ARM_DRAM1_END, \
+ ARM_TZC_NS_DRAM_S_ACCESS, PLAT_ARM_TZC_NS_DEV_ACCESS}, \
+ {CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + ARM_DRAM2_BASE, \
+ CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + ARM_DRAM2_END, \
+ ARM_TZC_NS_DRAM_S_ACCESS, PLAT_ARM_TZC_NS_DEV_ACCESS}
+
+#if SPM_MM
+
+/*
+ * Stand-alone MM logs would be routed via secure UART. Define page table
+ * entry for secure UART which would be common to all platforms.
+ */
+#define SOC_PLATFORM_SECURE_UART MAP_REGION_FLAT( \
+ SOC_CSS_SEC_UART_BASE, \
+ SOC_CSS_UART_SIZE, \
+ MT_DEVICE | MT_RW | \
+ MT_SECURE | MT_USER)
+
+#endif
+
+/* SDS ID for unusable CPU MPID list structure */
+#define SDS_ISOLATED_CPU_LIST_ID U(128)
+
+#endif /* SGI_BASE_PLATFORM_DEF_H */
diff --git a/plat/arm/css/sgi/include/sgi_dmc620_tzc_regions.h b/plat/arm/css/sgi/include/sgi_dmc620_tzc_regions.h
new file mode 100644
index 0000000..e939163
--- /dev/null
+++ b/plat/arm/css/sgi/include/sgi_dmc620_tzc_regions.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SGI_DMC620_TZC_REGIONS_H
+#define SGI_DMC620_TZC_REGIONS_H
+
+#include <drivers/arm/tzc_dmc620.h>
+
+#if SPM_MM
+#define CSS_SGI_DMC620_TZC_REGIONS_DEF \
+ { \
+ .region_base = ARM_AP_TZC_DRAM1_BASE, \
+ .region_top = PLAT_SP_IMAGE_NS_BUF_BASE - 1, \
+ .sec_attr = TZC_DMC620_REGION_S_RDWR \
+ }, { \
+ .region_base = PLAT_SP_IMAGE_NS_BUF_BASE, \
+ .region_top = PLAT_ARM_SP_IMAGE_STACK_BASE - 1, \
+ .sec_attr = TZC_DMC620_REGION_S_NS_RDWR \
+ }, { \
+ .region_base = PLAT_ARM_SP_IMAGE_STACK_BASE, \
+ .region_top = ARM_AP_TZC_DRAM1_END, \
+ .sec_attr = TZC_DMC620_REGION_S_RDWR \
+ }
+#else
+#define CSS_SGI_DMC620_TZC_REGIONS_DEF \
+ { \
+ .region_base = ARM_AP_TZC_DRAM1_BASE, \
+ .region_top = ARM_AP_TZC_DRAM1_END, \
+ .sec_attr = TZC_DMC620_REGION_S_RDWR \
+ }
+#endif /* SPM_MM */
+
+#endif /* SGI_DMC620_TZC_REGIONS_H */
diff --git a/plat/arm/css/sgi/include/sgi_plat.h b/plat/arm/css/sgi/include/sgi_plat.h
new file mode 100644
index 0000000..a5fbded
--- /dev/null
+++ b/plat/arm/css/sgi/include/sgi_plat.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SGI_PLAT_H
+#define SGI_PLAT_H
+
+/* BL31 platform setup common to all SGI based platforms */
+void sgi_bl31_common_platform_setup(void);
+
+#endif /* SGI_PLAT_H */
diff --git a/plat/arm/css/sgi/include/sgi_ras.h b/plat/arm/css/sgi/include/sgi_ras.h
new file mode 100644
index 0000000..e69a684
--- /dev/null
+++ b/plat/arm/css/sgi/include/sgi_ras.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2018-2021, 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 sdei_ev_num; /* SDEI Event number */
+ int intr; /* Physical intr number */
+};
+
+int sgi_ras_intr_handler_setup(void);
+
+#endif /* SGI_RAS_H */
diff --git a/plat/arm/css/sgi/include/sgi_sdei.h b/plat/arm/css/sgi/include/sgi_sdei.h
new file mode 100644
index 0000000..f380122
--- /dev/null
+++ b/plat/arm/css/sgi/include/sgi_sdei.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SGI_SDEI_H
+#define SGI_SDEI_H
+
+#if SDEI_SUPPORT
+
+/* ARM SDEI dynamic shared event numbers */
+#define SGI_SDEI_DS_EVENT_0 U(804)
+#define SGI_SDEI_DS_EVENT_1 U(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
+
+#endif /* SDEI_SUPPORT */
+
+#endif /* SGI_SDEI_H */
diff --git a/plat/arm/css/sgi/include/sgi_soc_css_def.h b/plat/arm/css/sgi/include/sgi_soc_css_def.h
new file mode 100644
index 0000000..f78b45a
--- /dev/null
+++ b/plat/arm/css/sgi/include/sgi_soc_css_def.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SGI_SOC_CSS_DEF_H
+#define SGI_SOC_CSS_DEF_H
+
+#include <lib/utils_def.h>
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/soc/common/soc_css_def.h>
+#include <plat/common/common_def.h>
+
+/*
+ * Definitions common to all ARM CSSv1-based development platforms
+ */
+
+/* Platform ID address */
+#define BOARD_CSS_PLAT_ID_REG_ADDR UL(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_TYPE_EMULATOR 0x02
+
+#ifndef __ASSEMBLER__
+
+#include <lib/mmio.h>
+
+#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_FLASH_IMAGE_BASE V2M_FLASH0_BASE
+#define PLAT_ARM_FLASH_IMAGE_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)
+
+#endif /* SGI_SOC_CSS_DEF_H */
diff --git a/plat/arm/css/sgi/include/sgi_soc_css_def_v2.h b/plat/arm/css/sgi/include/sgi_soc_css_def_v2.h
new file mode 100644
index 0000000..acf31eb
--- /dev/null
+++ b/plat/arm/css/sgi/include/sgi_soc_css_def_v2.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SGI_SOC_CSS_DEF_V2_H
+#define SGI_SOC_CSS_DEF_V2_H
+
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+/*
+ * Definitions common to all ARM CSS SoCs
+ */
+
+/* Following covers ARM CSS SoC Peripherals */
+
+#define SOC_SYSTEM_PERIPH_BASE UL(0x0C000000)
+#define SOC_SYSTEM_PERIPH_SIZE UL(0x02000000)
+
+#define SOC_PLATFORM_PERIPH_BASE UL(0x0E000000)
+#define SOC_PLATFORM_PERIPH_SIZE UL(0x02000000)
+
+#define SOC_CSS_PCIE_CONTROL_BASE UL(0x0ef20000)
+
+/* Memory controller */
+#define SOC_MEMCNTRL_BASE UL(0x10000000)
+#define SOC_MEMCNTRL_SIZE UL(0x10000000)
+
+/* SoC NIC-400 Global Programmers View (GPV) */
+#define SOC_CSS_NIC400_BASE UL(0x0ED00000)
+
+#define SOC_CSS_NIC400_USB_EHCI U(0)
+#define SOC_CSS_NIC400_TLX_MASTER U(1)
+#define SOC_CSS_NIC400_USB_OHCI U(2)
+#define SOC_CSS_NIC400_PL354_SMC U(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 U(4)
+
+/* Non-volatile counters */
+#define SOC_TRUSTED_NVCTR_BASE UL(0x0EE70000)
+#define TFW_NVCTR_BASE (SOC_TRUSTED_NVCTR_BASE + 0x0000)
+#define TFW_NVCTR_SIZE U(4)
+#define NTFW_CTR_BASE (SOC_TRUSTED_NVCTR_BASE + 0x0004)
+#define NTFW_CTR_SIZE U(4)
+
+/* Keys */
+#define SOC_KEYS_BASE UL(0x0EE80000)
+#define TZ_PUB_KEY_HASH_BASE (SOC_KEYS_BASE + 0x0000)
+#define TZ_PUB_KEY_HASH_SIZE U(32)
+#define HU_KEY_BASE (SOC_KEYS_BASE + 0x0020)
+#define HU_KEY_SIZE U(16)
+#define END_KEY_BASE (SOC_KEYS_BASE + 0x0044)
+#define END_KEY_SIZE U(32)
+
+#define SOC_PLATFORM_PERIPH_MAP_DEVICE MAP_REGION_FLAT( \
+ SOC_PLATFORM_PERIPH_BASE, \
+ SOC_PLATFORM_PERIPH_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+#if SPM_MM
+/*
+ * Memory map definition for the platform peripheral memory region that is
+ * accessible from S-EL0 (with secure user mode access).
+ */
+#define SOC_PLATFORM_PERIPH_MAP_DEVICE_USER \
+ MAP_REGION_FLAT( \
+ SOC_PLATFORM_PERIPH_BASE, \
+ SOC_PLATFORM_PERIPH_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE | MT_USER)
+#endif
+
+#define SOC_SYSTEM_PERIPH_MAP_DEVICE MAP_REGION_FLAT( \
+ SOC_SYSTEM_PERIPH_BASE, \
+ SOC_SYSTEM_PERIPH_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+#define SOC_MEMCNTRL_MAP_DEVICE MAP_REGION_FLAT( \
+ SOC_MEMCNTRL_BASE, \
+ SOC_MEMCNTRL_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+#define SOC_MEMCNTRL_MAP_DEVICE_REMOTE_CHIP(n) \
+ MAP_REGION_FLAT( \
+ CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + SOC_MEMCNTRL_BASE, \
+ SOC_MEMCNTRL_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 U(5)
+#define SOC_CSS_NIC400_BOOTSEC_BRIDGE_UART1 UL(1 << 12)
+
+/*
+ * Required platform porting definitions common to all ARM CSS SoCs
+ */
+/* 2MB used for SCP DDR retraining */
+#define PLAT_ARM_SCP_TZC_DRAM1_SIZE UL(0x00200000)
+
+/* V2M motherboard system registers & offsets */
+#define V2M_SYSREGS_BASE UL(0x0C010000)
+#define V2M_SYS_LED U(0x8)
+
+/*
+ * 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 U(0)
+#define V2M_SYS_LED_EL_SHIFT U(1)
+#define V2M_SYS_LED_EC_SHIFT U(3)
+
+#define V2M_SYS_LED_SS_MASK U(0x01)
+#define V2M_SYS_LED_EL_MASK U(0x03)
+#define V2M_SYS_LED_EC_MASK U(0x1f)
+
+/* NOR Flash */
+#define V2M_FLASH0_BASE UL(0x08000000)
+#define V2M_FLASH0_SIZE UL(0x04000000)
+#define V2M_FLASH_BLOCK_SIZE UL(0x00040000) /* 256 KB */
+
+/*
+ * 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 SGI_MAP_FLASH0_RO MAP_REGION_FLAT(V2M_FLASH0_BASE,\
+ V2M_FLASH0_SIZE, \
+ MT_DEVICE | MT_RO | MT_SECURE)
+
+/* Platform ID address */
+#define BOARD_CSS_PLAT_ID_REG_ADDR UL(0x0EFE00E0)
+
+/* Platform ID related accessors */
+#define BOARD_CSS_PLAT_ID_REG_ID_MASK U(0x0F)
+#define BOARD_CSS_PLAT_ID_REG_ID_SHIFT U(0x00)
+#define BOARD_CSS_PLAT_ID_REG_VERSION_MASK U(0xF00)
+#define BOARD_CSS_PLAT_ID_REG_VERSION_SHIFT U(0x08)
+#define BOARD_CSS_PLAT_TYPE_RTL U(0x00)
+#define BOARD_CSS_PLAT_TYPE_FPGA U(0x01)
+#define BOARD_CSS_PLAT_TYPE_EMULATOR U(0x02)
+#define BOARD_CSS_PLAT_TYPE_FVP U(0x03)
+
+#ifndef __ASSEMBLER__
+
+#include <lib/mmio.h>
+
+#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 U(3)
+#define MAX_IO_HANDLES U(4)
+
+/* Reserve the last block of flash for PSCI MEM PROTECT flag */
+#define PLAT_ARM_FLASH_IMAGE_BASE V2M_FLASH0_BASE
+#define PLAT_ARM_FLASH_IMAGE_MAX_SIZE (V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+#if ARM_GPT_SUPPORT
+/*
+ * Offset of the FIP in the GPT image. BL1 component uses this option
+ * as it does not load the partition table to get the FIP base
+ * address. At sector 34 by default (i.e. after reserved sectors 0-33)
+ * Offset = 34 * 512(sector size) = 17408 i.e. 0x4400
+ */
+#define PLAT_ARM_FIP_OFFSET_IN_GPT 0x4400
+#endif /* ARM_GPT_SUPPORT */
+
+#define PLAT_ARM_NVM_BASE V2M_FLASH0_BASE
+#define PLAT_ARM_NVM_SIZE (V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+#endif /* SGI_SOC_CSS_DEF_V2_H */
diff --git a/plat/arm/css/sgi/include/sgi_soc_platform_def.h b/plat/arm/css/sgi/include/sgi_soc_platform_def.h
new file mode 100644
index 0000000..3b8d9c6
--- /dev/null
+++ b/plat/arm/css/sgi/include/sgi_soc_platform_def.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SGI_SOC_PLATFORM_DEF_H
+#define SGI_SOC_PLATFORM_DEF_H
+
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/soc/common/soc_css_def.h>
+#include <sgi_base_platform_def.h>
+#include <sgi_soc_css_def.h>
+
+/* Map the System registers to access from S-EL0 */
+#define CSS_SYSTEMREG_DEVICE_BASE (0x1C010000)
+#define CSS_SYSTEMREG_DEVICE_SIZE (0x00010000)
+#define PLAT_ARM_SECURE_MAP_SYSTEMREG MAP_REGION_FLAT( \
+ CSS_SYSTEMREG_DEVICE_BASE, \
+ CSS_SYSTEMREG_DEVICE_SIZE, \
+ (MT_DEVICE | MT_RW | \
+ MT_SECURE | MT_USER))
+
+/* Map the NOR2 Flash to access from S-EL0 */
+#define CSS_NOR2_FLASH_DEVICE_BASE (0x10000000)
+#define CSS_NOR2_FLASH_DEVICE_SIZE (0x04000000)
+#define PLAT_ARM_SECURE_MAP_NOR2 MAP_REGION_FLAT( \
+ CSS_NOR2_FLASH_DEVICE_BASE, \
+ CSS_NOR2_FLASH_DEVICE_SIZE, \
+ (MT_DEVICE | MT_RW | \
+ MT_SECURE | MT_USER))
+
+#endif /* SGI_SOC_PLATFORM_DEF_H */
diff --git a/plat/arm/css/sgi/include/sgi_soc_platform_def_v2.h b/plat/arm/css/sgi/include/sgi_soc_platform_def_v2.h
new file mode 100644
index 0000000..20dd682
--- /dev/null
+++ b/plat/arm/css/sgi/include/sgi_soc_platform_def_v2.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SGI_SOC_PLATFORM_DEF_V2_H
+#define SGI_SOC_PLATFORM_DEF_V2_H
+
+#include <sgi_base_platform_def.h>
+#include <sgi_soc_css_def_v2.h>
+
+/* Map the System registers to access from S-EL0 */
+#define CSS_SYSTEMREG_DEVICE_BASE (0x0C010000)
+#define CSS_SYSTEMREG_DEVICE_SIZE (0x00010000)
+#define PLAT_ARM_SECURE_MAP_SYSTEMREG MAP_REGION_FLAT( \
+ CSS_SYSTEMREG_DEVICE_BASE, \
+ CSS_SYSTEMREG_DEVICE_SIZE, \
+ (MT_DEVICE | MT_RW | \
+ MT_SECURE | MT_USER))
+
+/* Map the NOR2 Flash to access from S-EL0 */
+#define CSS_NOR2_FLASH_DEVICE_BASE (0x001054000000)
+#define CSS_NOR2_FLASH_DEVICE_SIZE (0x000004000000)
+#define PLAT_ARM_SECURE_MAP_NOR2 MAP_REGION_FLAT( \
+ CSS_NOR2_FLASH_DEVICE_BASE, \
+ CSS_NOR2_FLASH_DEVICE_SIZE, \
+ (MT_DEVICE | MT_RW | \
+ MT_SECURE | MT_USER))
+
+#endif /* SGI_SOC_PLATFORM_DEF_V2_H */
diff --git a/plat/arm/css/sgi/include/sgi_variant.h b/plat/arm/css/sgi/include/sgi_variant.h
new file mode 100644
index 0000000..223ac3e
--- /dev/null
+++ b/plat/arm/css/sgi/include/sgi_variant.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018-2022, 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
+
+/* SID Version values for RD-V1 */
+#define RD_V1_SID_VER_PART_NUM 0x078a
+
+/* SID Version values for RD-N2 */
+#define RD_N2_SID_VER_PART_NUM 0x07B7
+
+/* SID Version values for RD-N2 variants */
+#define RD_N2_CFG1_SID_VER_PART_NUM 0x07B6
+
+/* SID Version values for RD-V2 */
+#define RD_V2_SID_VER_PART_NUM 0x07F2
+#define RD_V2_CONFIG_ID 0x1
+
+/* 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 */
+ unsigned int chip_id; /* Chip Id or Node number */
+ unsigned int multi_chip_mode; /* Multi-chip mode availability */
+} 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);
+
+/* returns true if operating in multi-chip configuration */
+unsigned int plat_arm_sgi_get_multi_chip_mode(void);
+
+#endif /* SGI_VARIANT_H */
diff --git a/plat/arm/css/sgi/sgi-common.mk b/plat/arm/css/sgi/sgi-common.mk
new file mode 100644
index 0000000..282a5f0
--- /dev/null
+++ b/plat/arm/css/sgi/sgi-common.mk
@@ -0,0 +1,86 @@
+#
+# Copyright (c) 2018-2022, 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
+
+SDEI_SUPPORT := 0
+
+EL3_EXCEPTION_HANDLING := 0
+
+HANDLE_EA_EL3_FIRST_NS := 0
+
+CSS_SGI_CHIP_COUNT := 1
+
+CSS_SGI_PLATFORM_VARIANT := 0
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS := 0
+
+CTX_INCLUDE_FPREGS := 1
+
+INTERCONNECT_SOURCES := ${CSS_ENT_BASE}/sgi_interconnect.c
+
+PLAT_INCLUDES += -I${CSS_ENT_BASE}/include
+
+# GIC-600 configuration
+GICV3_SUPPORT_GIC600 := 1
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+ENT_GIC_SOURCES := ${GICV3_SOURCES} \
+ plat/common/plat_gicv3.c \
+ plat/arm/common/arm_gicv3.c
+
+PLAT_BL_COMMON_SOURCES += ${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 \
+ drivers/arm/css/sds/sds.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))
+
+$(eval $(call add_define,CSS_SGI_CHIP_COUNT))
+
+$(eval $(call add_define,CSS_SGI_PLATFORM_VARIANT))
+
+override CSS_LOAD_SCP_IMAGES := 0
+override NEED_BL2U := no
+override ARM_PLAT_MT := 1
+override PSCI_EXTENDED_STATE_ID := 1
+override ARM_RECOM_STATE_ID_ENC := 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
diff --git a/plat/arm/css/sgi/sgi_bl31_setup.c b/plat/arm/css/sgi/sgi_bl31_setup.c
new file mode 100644
index 0000000..27cf183
--- /dev/null
+++ b/plat/arm/css/sgi/sgi_bl31_setup.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2018-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <libfdt.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_mhu_doorbell.h>
+#include <drivers/arm/css/scmi.h>
+#include <plat/arm/common/plat_arm.h>
+
+#include <plat/common/platform.h>
+
+#include <plat/arm/css/common/css_pm.h>
+
+#include <sgi_ras.h>
+#include <sgi_variant.h>
+
+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 plat_rd_scmi_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,
+ },
+ #if (CSS_SGI_CHIP_COUNT > 1)
+ {
+ .scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE +
+ CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1),
+ .db_reg_addr = PLAT_CSS_MHU_BASE
+ + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1) + SENDER_REG_SET(0),
+ .db_preserve_mask = 0xfffffffe,
+ .db_modify_mask = 0x1,
+ .ring_doorbell = &mhuv2_ring_doorbell,
+ },
+ #endif
+ #if (CSS_SGI_CHIP_COUNT > 2)
+ {
+ .scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE +
+ CSS_SGI_REMOTE_CHIP_MEM_OFFSET(2),
+ .db_reg_addr = PLAT_CSS_MHU_BASE +
+ CSS_SGI_REMOTE_CHIP_MEM_OFFSET(2) + SENDER_REG_SET(0),
+ .db_preserve_mask = 0xfffffffe,
+ .db_modify_mask = 0x1,
+ .ring_doorbell = &mhuv2_ring_doorbell,
+ },
+ #endif
+ #if (CSS_SGI_CHIP_COUNT > 3)
+ {
+ .scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE +
+ CSS_SGI_REMOTE_CHIP_MEM_OFFSET(3),
+ .db_reg_addr = PLAT_CSS_MHU_BASE +
+ CSS_SGI_REMOTE_CHIP_MEM_OFFSET(3) + SENDER_REG_SET(0),
+ .db_preserve_mask = 0xfffffffe,
+ .db_modify_mask = 0x1,
+ .ring_doorbell = &mhuv2_ring_doorbell,
+ },
+ #endif
+};
+
+scmi_channel_plat_info_t *plat_css_get_scmi_info(int channel_id)
+{
+ if (sgi_plat_info.platform_id == RD_N1E1_EDGE_SID_VER_PART_NUM ||
+ sgi_plat_info.platform_id == RD_V1_SID_VER_PART_NUM ||
+ sgi_plat_info.platform_id == RD_N2_SID_VER_PART_NUM ||
+ sgi_plat_info.platform_id == RD_V2_SID_VER_PART_NUM ||
+ sgi_plat_info.platform_id == RD_N2_CFG1_SID_VER_PART_NUM) {
+ if (channel_id >= ARRAY_SIZE(plat_rd_scmi_info))
+ panic();
+ return &plat_rd_scmi_info[channel_id];
+ }
+ 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();
+ sgi_plat_info.multi_chip_mode = plat_arm_sgi_get_multi_chip_mode();
+
+ arm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+}
+
+void sgi_bl31_common_platform_setup(void)
+{
+ arm_bl31_platform_setup();
+
+#if RAS_EXTENSION
+ sgi_ras_intr_handler_setup();
+#endif
+
+ /* Configure the warm reboot SGI for primary core */
+ css_setup_cpu_pwr_down_intr();
+
+#if CSS_SYSTEM_GRACEFUL_RESET
+ /* Register priority level handlers for reboot */
+ ehf_register_priority_handler(PLAT_REBOOT_PRI,
+ css_reboot_interrupt_handler);
+#endif
+}
+
+const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
+{
+ /*
+ * For RD-E1-Edge, only CPU power ON/OFF, PSCI platform callbacks are
+ * 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);
+}
diff --git a/plat/arm/css/sgi/sgi_image_load.c b/plat/arm/css/sgi/sgi_image_load.c
new file mode 100644
index 0000000..ac4bfd2
--- /dev/null
+++ b/plat/arm/css/sgi/sgi_image_load.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <libfdt.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/arm/css/sds.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+#include <sgi_base_platform_def.h>
+#include <sgi_variant.h>
+
+/*
+ * Information about the isolated CPUs obtained from SDS.
+ */
+struct isolated_cpu_mpid_list {
+ uint64_t num_entries; /* Number of entries in the list */
+ uint64_t mpid_list[PLATFORM_CORE_COUNT]; /* List of isolated CPU MPIDs */
+};
+
+/* Function to read isolated CPU MPID list from SDS. */
+void plat_arm_sgi_get_isolated_cpu_list(struct isolated_cpu_mpid_list *list)
+{
+ int ret;
+
+ ret = sds_init();
+ if (ret != SDS_OK) {
+ ERROR("SDS initialization failed, error: %d\n", ret);
+ panic();
+ }
+
+ ret = sds_struct_read(SDS_ISOLATED_CPU_LIST_ID, 0, &list->num_entries,
+ sizeof(list->num_entries), SDS_ACCESS_MODE_CACHED);
+ if (ret != SDS_OK) {
+ INFO("SDS CPU num elements read failed, error: %d\n", ret);
+ list->num_entries = 0;
+ return;
+ }
+
+ if (list->num_entries > PLATFORM_CORE_COUNT) {
+ ERROR("Isolated CPU list count %ld greater than max"
+ " number supported %d\n",
+ list->num_entries, PLATFORM_CORE_COUNT);
+ panic();
+ } else if (list->num_entries == 0) {
+ INFO("SDS isolated CPU list is empty\n");
+ return;
+ }
+
+ ret = sds_struct_read(SDS_ISOLATED_CPU_LIST_ID,
+ sizeof(list->num_entries),
+ &list->mpid_list,
+ sizeof(list->mpid_list[0]) * list->num_entries,
+ SDS_ACCESS_MODE_CACHED);
+ if (ret != SDS_OK) {
+ ERROR("SDS CPU list read failed. error: %d\n", ret);
+ panic();
+ }
+}
+
+/*******************************************************************************
+ * This function inserts Platform information via device tree nodes as,
+ * system-id {
+ * platform-id = <0>;
+ * config-id = <0>;
+ * isolated-cpu-list = <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;
+ struct isolated_cpu_mpid_list cpu_mpid_list = {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;
+ }
+
+ platcfg = plat_arm_sgi_get_multi_chip_mode();
+ err = fdt_setprop_u32(fdt, nodeoffset, "multi-chip-mode", platcfg);
+ if (err < 0) {
+ ERROR("Failed to set multi-chip-mode\n");
+ return -1;
+ }
+
+ plat_arm_sgi_get_isolated_cpu_list(&cpu_mpid_list);
+ if (cpu_mpid_list.num_entries > 0) {
+ err = fdt_setprop(fdt, nodeoffset, "isolated-cpu-list",
+ &cpu_mpid_list,
+ (sizeof(cpu_mpid_list.num_entries) *
+ (cpu_mpid_list.num_entries + 1)));
+ if (err < 0) {
+ ERROR("Failed to set isolated-cpu-list, error: %d\n",
+ err);
+ }
+ }
+
+ 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();
+}
+
diff --git a/plat/arm/css/sgi/sgi_interconnect.c b/plat/arm/css/sgi/sgi_interconnect.c
new file mode 100644
index 0000000..e9cd812
--- /dev/null
+++ b/plat/arm/css/sgi/sgi_interconnect.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * 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)
+{
+}
diff --git a/plat/arm/css/sgi/sgi_plat.c b/plat/arm/css/sgi/sgi_plat.c
new file mode 100644
index 0000000..a0199c3
--- /dev/null
+++ b/plat/arm/css/sgi/sgi_plat.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2018-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/ccn.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <drivers/arm/sbsa.h>
+#include <sgi_base_platform_def.h>
+
+#if SPM_MM
+#include <services/spm_mm_partition.h>
+#endif
+
+#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,
+#ifdef PLAT_ARM_MEM_PROT_ADDR
+ ARM_V2M_MAP_MEM_PROTECT,
+#endif
+ CSS_SGI_MAP_DEVICE,
+ SOC_CSS_MAP_DEVICE,
+ ARM_MAP_NS_DRAM1,
+#if CSS_SGI_CHIP_COUNT > 1
+ CSS_SGI_MAP_DEVICE_REMOTE_CHIP(1),
+#endif
+#if CSS_SGI_CHIP_COUNT > 2
+ CSS_SGI_MAP_DEVICE_REMOTE_CHIP(2),
+#endif
+#if CSS_SGI_CHIP_COUNT > 3
+ CSS_SGI_MAP_DEVICE_REMOTE_CHIP(3),
+#endif
+#if ARM_BL31_IN_DRAM
+ ARM_MAP_BL31_SEC_DRAM,
+#endif
+#if SPM_MM
+ 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,
+#ifdef PLAT_ARM_MEM_PROT_ADDR
+ ARM_V2M_MAP_MEM_PROTECT,
+#endif
+ SOC_CSS_MAP_DEVICE,
+#if SPM_MM
+ ARM_SPM_BUF_EL3_MMAP,
+#endif
+ {0}
+};
+
+#if SPM_MM && defined(IMAGE_BL31)
+const mmap_region_t plat_arm_secure_partition_mmap[] = {
+ PLAT_ARM_SECURE_MAP_SYSTEMREG,
+ PLAT_ARM_SECURE_MAP_NOR2,
+ SOC_PLATFORM_SECURE_UART,
+ PLAT_ARM_SECURE_MAP_DEVICE,
+ ARM_SP_IMAGE_MMAP,
+ ARM_SP_IMAGE_NS_BUF_MMAP,
+#if RAS_EXTENSION
+ CSS_SGI_SP_CPER_BUF_MMAP,
+#endif
+ ARM_SP_IMAGE_RW_MMAP,
+ ARM_SPM_BUF_EL0_MMAP,
+ {0}
+};
+#endif /* SPM_MM && defined(IMAGE_BL31) */
+#endif
+
+ARM_CASSERT_MMAP
+
+#if SPM_MM && defined(IMAGE_BL31)
+/*
+ * Boot information passed to a secure partition during initialisation. Linear
+ * indices in MP information will be filled at runtime.
+ */
+static spm_mm_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 spm_mm_boot_info_t plat_arm_secure_partition_boot_info = {
+ .h.type = PARAM_SP_IMAGE_BOOT_INFO,
+ .h.version = VERSION_1,
+ .h.size = sizeof(spm_mm_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 spm_mm_boot_info *plat_get_secure_partition_boot_info(
+ void *cookie)
+{
+ return &plat_arm_secure_partition_boot_info;
+}
+#endif /* SPM_MM && 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);
+}
diff --git a/plat/arm/css/sgi/sgi_plat_v2.c b/plat/arm/css/sgi/sgi_plat_v2.c
new file mode 100644
index 0000000..cef5345
--- /dev/null
+++ b/plat/arm/css/sgi/sgi_plat_v2.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <drivers/arm/sbsa.h>
+
+#if SPM_MM
+#include <services/spm_mm_partition.h>
+#endif
+
+/*
+ * Table of regions for different BL stages to map using the MMU.
+ */
+#if IMAGE_BL1
+const mmap_region_t plat_arm_mmap[] = {
+ ARM_MAP_SHARED_RAM,
+ SGI_MAP_FLASH0_RO,
+ CSS_SGI_MAP_DEVICE,
+ SOC_PLATFORM_PERIPH_MAP_DEVICE,
+ SOC_SYSTEM_PERIPH_MAP_DEVICE,
+ {0}
+};
+#endif
+
+#if IMAGE_BL2
+const mmap_region_t plat_arm_mmap[] = {
+ ARM_MAP_SHARED_RAM,
+ SGI_MAP_FLASH0_RO,
+#ifdef PLAT_ARM_MEM_PROT_ADDR
+ ARM_V2M_MAP_MEM_PROTECT,
+#endif
+ CSS_SGI_MAP_DEVICE,
+ SOC_MEMCNTRL_MAP_DEVICE,
+ SOC_PLATFORM_PERIPH_MAP_DEVICE,
+ SOC_SYSTEM_PERIPH_MAP_DEVICE,
+ ARM_MAP_NS_DRAM1,
+#if CSS_SGI_CHIP_COUNT > 1
+ SOC_MEMCNTRL_MAP_DEVICE_REMOTE_CHIP(1),
+#endif
+#if CSS_SGI_CHIP_COUNT > 2
+ SOC_MEMCNTRL_MAP_DEVICE_REMOTE_CHIP(2),
+#endif
+#if CSS_SGI_CHIP_COUNT > 3
+ SOC_MEMCNTRL_MAP_DEVICE_REMOTE_CHIP(3),
+#endif
+#if ARM_BL31_IN_DRAM
+ ARM_MAP_BL31_SEC_DRAM,
+#endif
+#if SPM_MM
+ 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,
+#ifdef PLAT_ARM_MEM_PROT_ADDR
+ ARM_V2M_MAP_MEM_PROTECT,
+#endif
+ CSS_SGI_MAP_DEVICE,
+ SOC_PLATFORM_PERIPH_MAP_DEVICE,
+ SOC_SYSTEM_PERIPH_MAP_DEVICE,
+#if SPM_MM
+ ARM_SPM_BUF_EL3_MMAP,
+#endif
+ {0}
+};
+
+#if SPM_MM && defined(IMAGE_BL31)
+const mmap_region_t plat_arm_secure_partition_mmap[] = {
+ PLAT_ARM_SECURE_MAP_SYSTEMREG,
+ PLAT_ARM_SECURE_MAP_NOR2,
+ SOC_PLATFORM_SECURE_UART,
+ SOC_PLATFORM_PERIPH_MAP_DEVICE_USER,
+ ARM_SP_IMAGE_MMAP,
+ ARM_SP_IMAGE_NS_BUF_MMAP,
+ ARM_SP_IMAGE_RW_MMAP,
+ ARM_SPM_BUF_EL0_MMAP,
+ {0}
+};
+#endif /* SPM_MM && defined(IMAGE_BL31) */
+#endif
+
+ARM_CASSERT_MMAP
+
+#if SPM_MM && defined(IMAGE_BL31)
+/*
+ * Boot information passed to a secure partition during initialisation. Linear
+ * indices in MP information will be filled at runtime.
+ */
+static spm_mm_mp_info_t sp_mp_info[] = {
+ [0] = {0x81000000, 0},
+ [1] = {0x81010000, 0},
+ [2] = {0x81020000, 0},
+ [3] = {0x81030000, 0},
+ [4] = {0x81040000, 0},
+ [5] = {0x81050000, 0},
+ [6] = {0x81060000, 0},
+ [7] = {0x81070000, 0},
+ [8] = {0x81080000, 0},
+ [9] = {0x81090000, 0},
+ [10] = {0x810a0000, 0},
+ [11] = {0x810b0000, 0},
+ [12] = {0x810c0000, 0},
+ [13] = {0x810d0000, 0},
+ [14] = {0x810e0000, 0},
+ [15] = {0x810f0000, 0},
+};
+
+const spm_mm_boot_info_t plat_arm_secure_partition_boot_info = {
+ .h.type = PARAM_SP_IMAGE_BOOT_INFO,
+ .h.version = VERSION_1,
+ .h.size = sizeof(spm_mm_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 spm_mm_boot_info *plat_get_secure_partition_boot_info(
+ void *cookie)
+{
+ return &plat_arm_secure_partition_boot_info;
+}
+#endif /* SPM_MM && 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);
+}
diff --git a/plat/arm/css/sgi/sgi_ras.c b/plat/arm/css/sgi/sgi_ras.c
new file mode 100644
index 0000000..4f03ac4
--- /dev/null
+++ b/plat/arm/css/sgi/sgi_ras.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <bl31/interrupt_mgmt.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/extensions/ras.h>
+#include <plat/arm/common/arm_spm_def.h>
+#include <plat/common/platform.h>
+#include <services/sdei.h>
+#include <services/spm_mm_svc.h>
+
+#include <sgi_ras.h>
+
+static int sgi_ras_intr_handler(const struct err_record_info *err_rec,
+ int probe_data,
+ const struct err_handler_data *const data);
+typedef struct mm_communicate_header {
+ struct efi_guid header_guid;
+ size_t message_len;
+ uint8_t data[8];
+} mm_communicate_header_t;
+
+/*
+ * GUID to indicate that the MM communication message is intended for DMC-620
+ * MM driver.
+ */
+const struct efi_guid dmc620_ecc_event_guid = {
+ 0x5ef0afd5, 0xe01a, 0x4c30,
+ {0x86, 0x19, 0x45, 0x46, 0x26, 0x91, 0x80, 0x98}
+};
+
+struct sgi_ras_ev_map sgi575_ras_map[] = {
+
+ /* DMC 0 error ECC error interrupt*/
+ {SGI_SDEI_DS_EVENT_0, 35},
+
+ /* DMC 1 error ECC error interrupt*/
+ {SGI_SDEI_DS_EVENT_1, 39},
+};
+
+#define SGI575_RAS_MAP_SIZE ARRAY_SIZE(sgi575_ras_map)
+
+struct err_record_info sgi_err_records[] = {
+ {
+ /* DMC 0 error record info */
+ .handler = &sgi_ras_intr_handler,
+ .aux_data = (void *)0,
+ }, {
+ /* DMC 1 error record info */
+ .handler = &sgi_ras_intr_handler,
+ .aux_data = (void *)1,
+ },
+};
+
+struct ras_interrupt sgi_ras_interrupts[] = {
+ {
+ .intr_number = 35,
+ .err_record = &sgi_err_records[0],
+ }, {
+ .intr_number = 39,
+ .err_record = &sgi_err_records[1],
+ }
+};
+
+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;
+ int ret;
+
+ 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 != NULL);
+
+ /*
+ * 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, &err_rec->aux_data, sizeof(err_rec->aux_data));
+ header->message_len = sizeof(err_rec->aux_data);
+ memcpy(&header->header_guid, (void *) &dmc620_ecc_event_guid,
+ sizeof(const struct efi_guid));
+
+ spm_mm_sp_call(MM_COMMUNICATE_AARCH64, (uint64_t)header, 0,
+ plat_my_core_pos());
+
+ /*
+ * Do an EOI of the RAS interrupt. 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 */
+ ret = sdei_dispatch_event(ras_map->sdei_ev_num);
+ if (ret != 0) {
+ /*
+ * sdei_dispatch_event() may return failing result in some cases,
+ * for example kernel may not have registered a handler or RAS event
+ * may happen early during boot. We restore the NS context when
+ * sdei_dispatch_event() returns failing result.
+ */
+ ERROR("SDEI dispatch failed: %d", ret);
+ cm_el1_sysregs_context_restore(NON_SECURE);
+ cm_set_next_eret_context(NON_SECURE);
+ }
+
+ return ret;
+}
+
+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;
+}
diff --git a/plat/arm/css/sgi/sgi_topology.c b/plat/arm/css/sgi/sgi_topology.c
new file mode 100644
index 0000000..1c3b5bf
--- /dev/null
+++ b/plat/arm/css/sgi/sgi_topology.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * Common topology related methods for SGI and RD based platforms
+ */
+/*******************************************************************************
+ * 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;
+}
+
+#if ARM_PLAT_MT
+/******************************************************************************
+ * 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;
+}
+#endif
diff --git a/plat/arm/soc/common/soc_css.mk b/plat/arm/soc/common/soc_css.mk
new file mode 100644
index 0000000..8cad2a5
--- /dev/null
+++ b/plat/arm/soc/common/soc_css.mk
@@ -0,0 +1,15 @@
+#
+# 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
diff --git a/plat/arm/soc/common/soc_css_security.c b/plat/arm/soc/common/soc_css_security.c
new file mode 100644
index 0000000..4f6bf61
--- /dev/null
+++ b/plat/arm/soc/common/soc_css_security.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <drivers/arm/nic_400.h>
+#include <lib/mmio.h>
+#include <plat/arm/soc/common/soc_css.h>
+
+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);
+}
diff --git a/plat/brcm/board/common/bcm_console.c b/plat/brcm/board/common/bcm_console.c
new file mode 100644
index 0000000..5f20094
--- /dev/null
+++ b/plat/brcm/board/common/bcm_console.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/ti/uart/uart_16550.h>
+
+#include <platform_def.h>
+
+/*******************************************************************************
+ * Functions that set up the console
+ ******************************************************************************/
+static console_t bcm_boot_console;
+static console_t bcm_runtime_console;
+
+/* Initialize the console to provide early debug support */
+void bcm_console_boot_init(void)
+{
+ int rc = console_16550_register(PLAT_BRCM_BOOT_UART_BASE,
+ PLAT_BRCM_BOOT_UART_CLK_IN_HZ,
+ BRCM_CONSOLE_BAUDRATE,
+ &bcm_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(&bcm_boot_console, CONSOLE_FLAG_BOOT);
+}
+
+void bcm_console_boot_end(void)
+{
+ console_flush();
+
+ (void)console_unregister(&bcm_boot_console);
+}
+
+/* Initialize the runtime console */
+void bcm_console_runtime_init(void)
+{
+ int rc = console_16550_register(PLAT_BRCM_BL31_RUN_UART_BASE,
+ PLAT_BRCM_BL31_RUN_UART_CLK_IN_HZ,
+ BRCM_CONSOLE_BAUDRATE,
+ &bcm_runtime_console);
+ if (rc == 0)
+ panic();
+
+ console_set_scope(&bcm_runtime_console, CONSOLE_FLAG_RUNTIME);
+}
+
+void bcm_console_runtime_end(void)
+{
+ console_flush();
+
+ (void)console_unregister(&bcm_runtime_console);
+}
diff --git a/plat/brcm/board/common/bcm_elog.c b/plat/brcm/board/common/bcm_elog.c
new file mode 100644
index 0000000..093157e
--- /dev/null
+++ b/plat/brcm/board/common/bcm_elog.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2018 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+#include <bcm_elog.h>
+
+/* error logging signature */
+#define BCM_ELOG_SIG_OFFSET 0x0000
+#define BCM_ELOG_SIG_VAL 0x75767971
+
+/* current logging offset that points to where new logs should be added */
+#define BCM_ELOG_OFF_OFFSET 0x0004
+
+/* current logging length (excluding header) */
+#define BCM_ELOG_LEN_OFFSET 0x0008
+
+#define BCM_ELOG_HEADER_LEN 12
+
+/*
+ * @base: base address of memory where log is saved
+ * @max_size: max size of memory reserved for logging
+ * @is_active: indicates logging is currently active
+ * @level: current logging level
+ */
+struct bcm_elog {
+ uintptr_t base;
+ uint32_t max_size;
+ unsigned int is_active;
+ unsigned int level;
+};
+
+static struct bcm_elog global_elog;
+
+extern void memcpy16(void *dst, const void *src, unsigned int len);
+
+/*
+ * Log one character
+ */
+static void elog_putchar(struct bcm_elog *elog, unsigned char c)
+{
+ uint32_t offset, len;
+
+ offset = mmio_read_32(elog->base + BCM_ELOG_OFF_OFFSET);
+ len = mmio_read_32(elog->base + BCM_ELOG_LEN_OFFSET);
+ mmio_write_8(elog->base + offset, c);
+ offset++;
+
+ /* log buffer is now full and need to wrap around */
+ if (offset >= elog->max_size)
+ offset = BCM_ELOG_HEADER_LEN;
+
+ /* only increment length when log buffer is not full */
+ if (len < elog->max_size - BCM_ELOG_HEADER_LEN)
+ len++;
+
+ mmio_write_32(elog->base + BCM_ELOG_OFF_OFFSET, offset);
+ mmio_write_32(elog->base + BCM_ELOG_LEN_OFFSET, len);
+}
+
+static void elog_unsigned_num(struct bcm_elog *elog, unsigned long unum,
+ unsigned int radix)
+{
+ /* Just need enough space to store 64 bit decimal integer */
+ unsigned char num_buf[20];
+ int i = 0, rem;
+
+ do {
+ rem = unum % radix;
+ if (rem < 0xa)
+ num_buf[i++] = '0' + rem;
+ else
+ num_buf[i++] = 'a' + (rem - 0xa);
+ } while (unum /= radix);
+
+ while (--i >= 0)
+ elog_putchar(elog, num_buf[i]);
+}
+
+static void elog_string(struct bcm_elog *elog, const char *str)
+{
+ while (*str)
+ elog_putchar(elog, *str++);
+}
+
+/*
+ * Routine to initialize error logging
+ */
+int bcm_elog_init(void *base, uint32_t size, unsigned int level)
+{
+ struct bcm_elog *elog = &global_elog;
+ uint32_t val;
+
+ elog->base = (uintptr_t)base;
+ elog->max_size = size;
+ elog->is_active = 1;
+ elog->level = level / 10;
+
+ /*
+ * If a valid signature can be found, it means logs have been copied
+ * into designated memory by another software. In this case, we should
+ * not re-initialize the entry header in the designated memory
+ */
+ val = mmio_read_32(elog->base + BCM_ELOG_SIG_OFFSET);
+ if (val != BCM_ELOG_SIG_VAL) {
+ mmio_write_32(elog->base + BCM_ELOG_SIG_OFFSET,
+ BCM_ELOG_SIG_VAL);
+ mmio_write_32(elog->base + BCM_ELOG_OFF_OFFSET,
+ BCM_ELOG_HEADER_LEN);
+ mmio_write_32(elog->base + BCM_ELOG_LEN_OFFSET, 0);
+ }
+
+ return 0;
+}
+
+/*
+ * Routine to disable error logging
+ */
+void bcm_elog_exit(void)
+{
+ struct bcm_elog *elog = &global_elog;
+
+ if (!elog->is_active)
+ return;
+
+ elog->is_active = 0;
+
+ flush_dcache_range(elog->base, elog->max_size);
+}
+
+/*
+ * Routine to copy error logs from current memory to 'dst' memory and continue
+ * logging from the new 'dst' memory.
+ * dst and base addresses must be 16-bytes aligned.
+ */
+int bcm_elog_copy_log(void *dst, uint32_t max_size)
+{
+ struct bcm_elog *elog = &global_elog;
+ uint32_t offset, len;
+
+ if (!elog->is_active || ((uintptr_t)dst == elog->base))
+ return -1;
+
+ /* flush cache before copying logs */
+ flush_dcache_range(elog->base, max_size);
+
+ /*
+ * If current offset exceeds the new max size, then that is considered
+ * as a buffer overflow situation. In this case, we reset the offset
+ * back to the beginning
+ */
+ offset = mmio_read_32(elog->base + BCM_ELOG_OFF_OFFSET);
+ if (offset >= max_size) {
+ offset = BCM_ELOG_HEADER_LEN;
+ mmio_write_32(elog->base + BCM_ELOG_OFF_OFFSET, offset);
+ }
+
+ /* note payload length does not include header */
+ len = mmio_read_32(elog->base + BCM_ELOG_LEN_OFFSET);
+ if (len > max_size - BCM_ELOG_HEADER_LEN) {
+ len = max_size - BCM_ELOG_HEADER_LEN;
+ mmio_write_32(elog->base + BCM_ELOG_LEN_OFFSET, len);
+ }
+
+ /* Need to copy everything including the header. */
+ memcpy16(dst, (const void *)elog->base, len + BCM_ELOG_HEADER_LEN);
+ elog->base = (uintptr_t)dst;
+ elog->max_size = max_size;
+
+ return 0;
+}
+
+/*
+ * Main routine to save logs into memory
+ */
+void bcm_elog(const char *fmt, ...)
+{
+ va_list args;
+ const char *prefix_str;
+ int bit64;
+ int64_t num;
+ uint64_t unum;
+ char *str;
+ struct bcm_elog *elog = &global_elog;
+
+ /* We expect the LOG_MARKER_* macro as the first character */
+ unsigned int level = fmt[0];
+
+ if (!elog->is_active || level > elog->level)
+ return;
+
+ prefix_str = plat_log_get_prefix(level);
+
+ while (*prefix_str != '\0') {
+ elog_putchar(elog, *prefix_str);
+ prefix_str++;
+ }
+
+ va_start(args, fmt);
+ fmt++;
+ while (*fmt) {
+ bit64 = 0;
+
+ if (*fmt == '%') {
+ fmt++;
+ /* Check the format specifier */
+loop:
+ switch (*fmt) {
+ case 'i': /* Fall through to next one */
+ case 'd':
+ if (bit64)
+ num = va_arg(args, int64_t);
+ else
+ num = va_arg(args, int32_t);
+
+ if (num < 0) {
+ elog_putchar(elog, '-');
+ unum = (unsigned long)-num;
+ } else
+ unum = (unsigned long)num;
+
+ elog_unsigned_num(elog, unum, 10);
+ break;
+ case 's':
+ str = va_arg(args, char *);
+ elog_string(elog, str);
+ break;
+ case 'x':
+ if (bit64)
+ unum = va_arg(args, uint64_t);
+ else
+ unum = va_arg(args, uint32_t);
+
+ elog_unsigned_num(elog, unum, 16);
+ break;
+ case 'l':
+ bit64 = 1;
+ fmt++;
+ goto loop;
+ case 'u':
+ if (bit64)
+ unum = va_arg(args, uint64_t);
+ else
+ unum = va_arg(args, uint32_t);
+
+ elog_unsigned_num(elog, unum, 10);
+ break;
+ default:
+ /* Exit on any other format specifier */
+ goto exit;
+ }
+ fmt++;
+ continue;
+ }
+ elog_putchar(elog, *fmt++);
+ }
+exit:
+ va_end(args);
+}
diff --git a/plat/brcm/board/common/bcm_elog_ddr.c b/plat/brcm/board/common/bcm_elog_ddr.c
new file mode 100644
index 0000000..89e7bff
--- /dev/null
+++ b/plat/brcm/board/common/bcm_elog_ddr.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2019-2020 Broadcom.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#include <ddr_init.h>
+#include <scp_cmd.h>
+#include <scp_utils.h>
+#include <platform_def.h>
+
+#include "bcm_elog_ddr.h"
+#include "m0_cfg.h"
+#include "m0_ipc.h"
+
+void elog_init_ddr_log(void)
+{
+ struct elog_setup setup = {0};
+ struct elog_global_header global;
+ struct elog_meta_record rec;
+ unsigned int rec_idx = 0;
+ uint32_t log_offset;
+ uintptr_t metadata;
+ char *rec_desc[ELOG_SUPPORTED_REC_CNT] = {"SYSRESET", "THERMAL",
+ "DDR_ECC", "APBOOTLG",
+ "IDM"};
+
+ /*
+ * If this is warm boot, return immediately.
+ * We expect metadata to be initialized already
+ */
+ if (is_warmboot()) {
+ WARN("Warmboot detected, skip ELOG metadata initialization\n");
+ return;
+ }
+
+ memset(&global, 0, sizeof(global));
+
+ global.sector_size = ELOG_SECTOR_SIZE;
+ global.signature = ELOG_GLOBAL_META_HDR_SIG;
+ global.rec_count = ELOG_SUPPORTED_REC_CNT;
+
+ /* Start of logging area in DDR memory */
+ log_offset = ELOG_STORE_OFFSET;
+
+ /* Shift to the first RECORD header */
+ log_offset += 2 * global.sector_size;
+
+ /* Temporary place to hold metadata */
+ metadata = TMP_ELOG_METADATA_BASE;
+
+ memcpy((void *)metadata, &global, sizeof(global));
+ metadata += sizeof(global);
+
+ while (rec_idx < global.rec_count) {
+ memset(&rec, 0, sizeof(rec));
+
+ rec.type = rec_idx;
+ if (rec_idx == ELOG_REC_UART_LOG) {
+ rec.format = ELOG_REC_FMT_ASCII;
+ rec.src_mem_type = ELOG_SRC_MEM_TYPE_DDR;
+ rec.alt_src_mem_type = ELOG_SRC_MEM_TYPE_FS4_SCRATCH;
+ rec.src_mem_addr = BCM_ELOG_BL31_BASE;
+ rec.alt_src_mem_addr = BCM_ELOG_BL2_BASE;
+ rec.rec_size = ELOG_APBOOTLG_REC_SIZE;
+ } else if (rec_idx == ELOG_REC_IDM_LOG) {
+ rec.type = IDM_ELOG_REC_TYPE;
+ rec.format = ELOG_REC_FMT_CUSTOM;
+ rec.src_mem_type = ELOG_SRC_MEM_TYPE_DDR;
+ rec.alt_src_mem_type = ELOG_SRC_MEM_TYPE_CRMU_SCRATCH;
+ rec.src_mem_addr = ELOG_IDM_SRC_MEM_ADDR;
+ rec.alt_src_mem_addr = 0x0;
+ rec.rec_size = ELOG_DEFAULT_REC_SIZE;
+ } else {
+ rec.format = ELOG_REC_FMT_CUSTOM;
+ rec.src_mem_type = ELOG_SRC_MEM_TYPE_CRMU_SCRATCH;
+ rec.alt_src_mem_type = ELOG_SRC_MEM_TYPE_CRMU_SCRATCH;
+ rec.src_mem_addr = ELOG_USE_DEFAULT_MEM_ADDR;
+ rec.alt_src_mem_addr = ELOG_USE_DEFAULT_MEM_ADDR;
+ rec.rec_size = ELOG_DEFAULT_REC_SIZE;
+ }
+
+ rec.nvm_type = LOG_MEDIA_DDR;
+ rec.sector_size = ELOG_SECTOR_SIZE;
+
+ rec.rec_addr = (uint64_t)log_offset;
+ log_offset += rec.rec_size;
+
+ /* Sanity checks */
+ if (rec.type > ELOG_MAX_REC_COUNT ||
+ rec.format > ELOG_MAX_REC_FORMAT ||
+ (rec.nvm_type > ELOG_MAX_NVM_TYPE &&
+ rec.nvm_type != ELOG_NVM_DEFAULT) ||
+ !rec.rec_size ||
+ !rec.sector_size ||
+ rec_idx >= ELOG_SUPPORTED_REC_CNT) {
+ ERROR("Invalid ELOG record(%u) detected\n", rec_idx);
+ return;
+ }
+
+ memset(rec.rec_desc, ' ', sizeof(rec.rec_desc));
+
+ memcpy(rec.rec_desc, rec_desc[rec_idx],
+ strlen(rec_desc[rec_idx]));
+
+ memcpy((void *)metadata, &rec, sizeof(rec));
+ metadata += sizeof(rec);
+
+ rec_idx++;
+ }
+
+ setup.params[0] = TMP_ELOG_METADATA_BASE;
+ setup.params[1] = (sizeof(global) + global.rec_count * sizeof(rec));
+ setup.cmd = ELOG_SETUP_CMD_WRITE_META;
+
+ flush_dcache_range((uintptr_t)&setup, sizeof(struct elog_setup));
+ flush_dcache_range((uintptr_t)setup.params[0], setup.params[1]);
+
+ /* initialize DDR Logging METADATA if this is NOT warmboot */
+ if (!is_warmboot()) {
+ if (scp_send_cmd(MCU_IPC_MCU_CMD_ELOG_SETUP,
+ (uint32_t)(uintptr_t)(&setup),
+ SCP_CMD_DEFAULT_TIMEOUT_US)) {
+ ERROR("scp_send_cmd: timeout/error for elog setup\n");
+ return;
+ }
+ }
+
+ NOTICE("MCU Error logging initialized\n");
+}
diff --git a/plat/brcm/board/common/bcm_elog_ddr.h b/plat/brcm/board/common/bcm_elog_ddr.h
new file mode 100644
index 0000000..6f21a68
--- /dev/null
+++ b/plat/brcm/board/common/bcm_elog_ddr.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2019-2020 Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BCM_ELOG_DDR_H
+#define BCM_ELOG_DDR_H
+
+#define ELOG_GLOBAL_META_HDR_SIG 0x45524c47
+#define ELOG_MAX_REC_COUNT 13
+#define ELOG_MAX_REC_FORMAT 1
+#define ELOG_MAX_NVM_TYPE 4
+/* Use a default NVM, set by m0 configuration */
+#define ELOG_NVM_DEFAULT 0xff
+
+/* Max. number of cmd parameters per elog spec */
+#define ELOG_PARAM_COUNT 3
+/*
+ * Number of supported RECORD Types-
+ * SYSRESET, THERMAL, DDR_ECC, APBOOTLG, IDM
+ */
+#define ELOG_SUPPORTED_REC_CNT 5
+
+#define ELOG_REC_DESC_LENGTH 8
+
+#define ELOG_SECTOR_SIZE 0x1000
+
+/* Default Record size for all record types except APBOOTLOG */
+#define ELOG_DEFAULT_REC_SIZE 0x10000
+
+/* Default record size for APBOOTLOG record */
+#define ELOG_APBOOTLG_REC_SIZE 0x60000
+
+/* Use default CRMU provided mem address */
+#define ELOG_USE_DEFAULT_MEM_ADDR 0x0
+
+/* Temporary place to hold metadata */
+#define TMP_ELOG_METADATA_BASE (ELOG_AP_UART_LOG_BASE + \
+ BCM_ELOG_BL2_SIZE)
+/* IDM ELOG source memory address */
+#define ELOG_IDM_SRC_MEM_ADDR 0x8f213000
+
+#define IDM_ELOG_REC_TYPE 5
+
+enum elog_record_type {
+ ELOG_REC_SYS_RESET_EVT = 0,
+ ELOG_REC_THERMAL_EVT,
+ ELOG_REC_DDR_ECC,
+ ELOG_REC_UART_LOG,
+ ELOG_REC_IDM_LOG,
+ ELOG_REC_MAX
+};
+
+enum elog_record_format {
+ ELOG_REC_FMT_ASCII = 0,
+ ELOG_REC_FMT_CUSTOM
+};
+
+enum elog_src_memory_type {
+ ELOG_SRC_MEM_TYPE_CRMU_SCRATCH = 0,
+ ELOG_SRC_MEM_TYPE_FS4_SCRATCH,
+ ELOG_SRC_MEM_TYPE_DDR,
+ ELOG_SRC_MEM_TYPE_CHIMP_SCRATCH
+};
+
+enum elog_setup_cmd {
+ ELOG_SETUP_CMD_VALIDATE_META,
+ ELOG_SETUP_CMD_WRITE_META,
+ ELOG_SETUP_CMD_ERASE,
+ ELOG_SETUP_CMD_READ,
+ ELOG_SETUP_CMD_CHECK
+};
+
+struct elog_setup {
+ uint32_t cmd;
+ uint32_t params[ELOG_PARAM_COUNT];
+ uint32_t result;
+ uint32_t ret_code;
+};
+
+struct elog_meta_record {
+ uint8_t type;
+ uint8_t format;
+ uint8_t src_mem_type;
+ uint8_t alt_src_mem_type;
+ uint8_t nvm_type;
+ char rec_desc[ELOG_REC_DESC_LENGTH];
+ uint64_t src_mem_addr;
+ uint64_t alt_src_mem_addr;
+ uint64_t rec_addr;
+ uint32_t rec_size;
+ uint32_t sector_size;
+ uint8_t padding[3];
+} __packed;
+
+struct elog_global_header {
+ uint32_t signature;
+ uint32_t sector_size;
+ uint8_t revision;
+ uint8_t rec_count;
+ uint16_t padding;
+} __packed;
+
+void elog_init_ddr_log(void);
+
+#endif /* BCM_ELOG_DDR_H */
diff --git a/plat/brcm/board/common/board_arm_trusted_boot.c b/plat/brcm/board/common/board_arm_trusted_boot.c
new file mode 100644
index 0000000..da18c31
--- /dev/null
+++ b/plat/brcm/board/common/board_arm_trusted_boot.c
@@ -0,0 +1,625 @@
+/*
+ * Copyright 2015 - 2020 Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <tools_share/tbbr_oid.h>
+
+#include <sbl_util.h>
+#include <sotp.h>
+
+/* Weak definition may be overridden in specific platform */
+#pragma weak plat_match_rotpk
+#pragma weak plat_get_nv_ctr
+#pragma weak plat_set_nv_ctr
+
+/* SHA256 algorithm */
+#define SHA256_BYTES 32
+
+/* ROTPK locations */
+#define ARM_ROTPK_REGS_ID 1
+#define ARM_ROTPK_DEVEL_RSA_ID 2
+#define BRCM_ROTPK_SOTP_RSA_ID 3
+
+#if !ARM_ROTPK_LOCATION_ID
+ #error "ARM_ROTPK_LOCATION_ID not defined"
+#endif
+
+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];
+
+#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";
+#endif
+
+#pragma weak plat_rotpk_hash
+const unsigned char plat_rotpk_hash[] =
+ "\xdb\x06\x67\x95\x4f\x88\x2b\x88"
+ "\x49\xbf\x70\x3f\xde\x50\x4a\x96"
+ "\xd8\x17\x69\xd4\xa0\x6c\xba\xee"
+ "\x66\x3e\x71\x82\x2d\x95\x69\xe4";
+
+#pragma weak rom_slice
+const unsigned char rom_slice[] =
+ "\x77\x06\xbc\x98\x40\xbe\xfd\xab"
+ "\x60\x4b\x74\x3c\x9a\xb3\x80\x75"
+ "\x39\xb6\xda\x27\x07\x2e\x5b\xbf"
+ "\x5c\x47\x91\xc9\x95\x26\x26\x0c";
+
+#if (ARM_ROTPK_LOCATION_ID == BRCM_ROTPK_SOTP_RSA_ID)
+static int plat_is_trusted_boot(void)
+{
+ uint64_t section3_row0_data;
+
+ section3_row0_data = sotp_mem_read(SOTP_DEVICE_SECURE_CFG0_ROW, 0);
+
+ if ((section3_row0_data & SOTP_DEVICE_SECURE_CFG0_AB_MASK) == 0) {
+ INFO("NOT AB\n");
+ return 0;
+ }
+
+ INFO("AB\n");
+ return TRUSTED_BOARD_BOOT;
+}
+
+/*
+ * FAST AUTH is enabled if all following conditions are met:
+ * - AB part
+ * - SOTP.DEV != 0
+ * - SOTP.CID != 0
+ * - SOTP.ENC_DEV_TYPE = ENC_AB_DEV
+ * - Manuf_debug strap set high
+ */
+static int plat_fast_auth_enabled(void)
+{
+ uint32_t chip_state;
+ uint64_t section3_row0_data;
+ uint64_t section3_row1_data;
+
+ section3_row0_data =
+ sotp_mem_read(SOTP_DEVICE_SECURE_CFG0_ROW, 0);
+ section3_row1_data =
+ sotp_mem_read(SOTP_DEVICE_SECURE_CFG1_ROW, 0);
+
+ chip_state = mmio_read_32(SOTP_REGS_SOTP_CHIP_STATES);
+
+ if (plat_is_trusted_boot() &&
+ (section3_row0_data & SOTP_DEVICE_SECURE_CFG0_DEV_MASK) &&
+ (section3_row0_data & SOTP_DEVICE_SECURE_CFG0_CID_MASK) &&
+ ((section3_row1_data & SOTP_ENC_DEV_TYPE_MASK) ==
+ SOTP_ENC_DEV_TYPE_AB_DEV) &&
+ (chip_state & SOTP_CHIP_STATES_MANU_DEBUG_MASK))
+ return 1;
+
+ return 0;
+}
+#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);
+
+ *flags = 0;
+
+ /* 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)
+ 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);
+ }
+#elif (ARM_ROTPK_LOCATION_ID == BRCM_ROTPK_SOTP_RSA_ID)
+{
+ int i;
+ int ret = -1;
+
+ /*
+ * In non-AB mode, we do not read the key.
+ * In AB mode:
+ * - The Dauth is in BL11 if SBL is enabled
+ * - The Dauth is in SOTP if SBL is disabled.
+ */
+ if (plat_is_trusted_boot() == 0) {
+
+ INFO("NON-AB: Do not read DAUTH!\n");
+ *flags = ROTPK_NOT_DEPLOYED;
+ ret = 0;
+
+ } else if ((sbl_status() == SBL_ENABLED) &&
+ (mmio_read_32(BL11_DAUTH_BASE) == BL11_DAUTH_ID)) {
+
+ /* Read hash from BL11 */
+ INFO("readKeys (DAUTH) from BL11\n");
+
+ memcpy(dst,
+ (void *)(BL11_DAUTH_BASE + sizeof(uint32_t)),
+ SHA256_BYTES);
+
+ for (i = 0; i < SHA256_BYTES; i++)
+ if (dst[i] != 0)
+ break;
+
+ if (i >= SHA256_BYTES)
+ ERROR("Hash not valid from BL11\n");
+ else
+ ret = 0;
+
+ } else if (sotp_key_erased()) {
+
+ memcpy(dst, plat_rotpk_hash, SHA256_BYTES);
+
+ INFO("SOTP erased, Use internal key hash.\n");
+ ret = 0;
+
+ } else if (plat_fast_auth_enabled()) {
+
+ INFO("AB DEV: FAST AUTH!\n");
+ *flags = ROTPK_NOT_DEPLOYED;
+ ret = 0;
+
+ } else if (!(mmio_read_32(SOTP_STATUS_1) & SOTP_DAUTH_ECC_ERROR_MASK)) {
+
+ /* Read hash from SOTP */
+ ret = sotp_read_key(dst,
+ SHA256_BYTES,
+ SOTP_DAUTH_ROW,
+ SOTP_K_HMAC_ROW-1);
+
+ INFO("sotp_read_key (DAUTH): %i\n", ret);
+
+ } else {
+
+ uint64_t row_data;
+ uint32_t k;
+
+ for (k = 0; k < (SOTP_K_HMAC_ROW - SOTP_DAUTH_ROW); k++) {
+ row_data = sotp_mem_read(SOTP_DAUTH_ROW + k,
+ SOTP_ROW_NO_ECC);
+
+ if (row_data != 0)
+ break;
+ }
+
+ if (k == (SOTP_K_HMAC_ROW - SOTP_DAUTH_ROW)) {
+ INFO("SOTP NOT PROGRAMMED: Do not use DAUTH!\n");
+
+ if (sotp_mem_read(SOTP_ATF2_CFG_ROW_ID,
+ SOTP_ROW_NO_ECC) & SOTP_ROMKEY_MASK) {
+ memcpy(dst, plat_rotpk_hash, SHA256_BYTES);
+
+ INFO("Use internal key hash.\n");
+ ret = 0;
+ } else {
+ *flags = ROTPK_NOT_DEPLOYED;
+ ret = 0;
+ }
+ } else {
+ INFO("No hash found in SOTP\n");
+ }
+ }
+ if (ret)
+ return ret;
+}
+#endif
+
+ *key_ptr = (void *)rotpk_hash_der;
+ *key_len = (unsigned int)sizeof(rotpk_hash_der);
+ *flags |= ROTPK_IS_HASH;
+
+ return 0;
+}
+
+#define SOTP_NUM_BITS_PER_ROW 41
+#define SOTP_NVCTR_ROW_ALL_ONES 0x1ffffffffff
+#define SOTP_NVCTR_TRUSTED_IN_USE \
+ ((uint64_t)0x3 << (SOTP_NUM_BITS_PER_ROW-2))
+#define SOTP_NVCTR_NON_TRUSTED_IN_USE ((uint64_t)0x3)
+#define SOTP_NVCTR_TRUSTED_NEAR_END SOTP_NVCTR_NON_TRUSTED_IN_USE
+#define SOTP_NVCTR_NON_TRUSTED_NEAR_END SOTP_NVCTR_TRUSTED_IN_USE
+
+#define SOTP_NVCTR_ROW_START 64
+#define SOTP_NVCTR_ROW_END 75
+
+/*
+ * SOTP NVCTR are stored in section 10 of SOTP (rows 64-75).
+ * Each row of SOTP is 41 bits.
+ * NVCTR's are stored in a bitstream format.
+ * We are tolerant to consecutive bit errors.
+ * Trusted NVCTR starts at the top of row 64 in bitstream format.
+ * Non Trusted NVCTR starts at the bottom of row 75 in reverse bitstream.
+ * Each row can only be used by 1 of the 2 counters. This is determined
+ * by 2 zeros remaining at the beginning or end of the last available row.
+ * If one counter has already starting using a row, the other will be
+ * prevent from writing to that row.
+ *
+ * Example counter values for SOTP programmed below:
+ * Trusted Counter (rows64-69) = 5 * 41 + 40 = 245
+ * NonTrusted Counter (row75-71) = 3 * 41 + 4 = 127
+ * 40 39 38 37 36 ..... 5 4 3 2 1 0
+ * row 64 1 1 1 1 1 1 1 1 1 1 1
+ * row 65 1 1 1 1 1 1 1 1 1 1 1
+ * row 66 1 1 1 1 1 1 1 1 1 1 1
+ * row 67 1 1 1 1 1 1 1 1 1 1 1
+ * row 68 1 1 1 1 1 1 1 1 1 1 1
+ * row 69 1 1 1 1 1 1 1 1 1 1 0
+ * row 71 0 0 0 0 0 0 0 0 0 0 0
+ * row 71 0 0 0 0 0 0 0 0 0 0 0
+ * row 71 0 0 0 0 0 0 0 1 1 1 1
+ * row 73 1 1 1 1 1 1 1 1 1 1 1
+ * row 74 1 1 1 1 1 1 1 1 1 1 1
+ * row 75 1 1 1 1 1 1 1 1 1 1 1
+ *
+ */
+
+#if (DEBUG == 1)
+/*
+ * Dump sotp rows
+ */
+void sotp_dump_rows(uint32_t start_row, uint32_t end_row)
+{
+ int32_t rownum;
+ uint64_t rowdata;
+
+ for (rownum = start_row; rownum <= end_row; rownum++) {
+ rowdata = sotp_mem_read(rownum, SOTP_ROW_NO_ECC);
+ INFO("%d 0x%" PRIx64 "\n", rownum, rowdata);
+ }
+}
+#endif
+
+/*
+ * Get SOTP Trusted nvctr
+ */
+unsigned int sotp_get_trusted_nvctr(void)
+{
+ uint64_t rowdata;
+ uint64_t nextrowdata;
+ uint32_t rownum;
+ unsigned int nvctr;
+
+ rownum = SOTP_NVCTR_ROW_START;
+ nvctr = SOTP_NUM_BITS_PER_ROW;
+
+ /*
+ * Determine what row has last valid data for trusted ctr
+ */
+ rowdata = sotp_mem_read(rownum, SOTP_ROW_NO_ECC);
+ while ((rowdata & SOTP_NVCTR_TRUSTED_IN_USE) &&
+ (rowdata & SOTP_NVCTR_TRUSTED_NEAR_END) &&
+ (rownum < SOTP_NVCTR_ROW_END)) {
+ /*
+ * Current row in use and has data in last 2 bits as well.
+ * Check if next row also has data for this counter
+ */
+ nextrowdata = sotp_mem_read(rownum+1, SOTP_ROW_NO_ECC);
+ if (nextrowdata & SOTP_NVCTR_TRUSTED_IN_USE) {
+ /* Next row also has data so increment rownum */
+ rownum++;
+ nvctr += SOTP_NUM_BITS_PER_ROW;
+ rowdata = nextrowdata;
+ } else {
+ /* Next row does not have data */
+ break;
+ }
+ }
+
+ if (rowdata & SOTP_NVCTR_TRUSTED_IN_USE) {
+ while ((rowdata & 0x1) == 0) {
+ nvctr--;
+ rowdata >>= 1;
+ }
+ } else
+ nvctr -= SOTP_NUM_BITS_PER_ROW;
+
+ INFO("CTR %i\n", nvctr);
+ return nvctr;
+}
+
+/*
+ * Get SOTP NonTrusted nvctr
+ */
+unsigned int sotp_get_nontrusted_nvctr(void)
+{
+ uint64_t rowdata;
+ uint64_t nextrowdata;
+ uint32_t rownum;
+ unsigned int nvctr;
+
+ nvctr = SOTP_NUM_BITS_PER_ROW;
+ rownum = SOTP_NVCTR_ROW_END;
+
+ /*
+ * Determine what row has last valid data for nontrusted ctr
+ */
+ rowdata = sotp_mem_read(rownum, SOTP_ROW_NO_ECC);
+ while ((rowdata & SOTP_NVCTR_NON_TRUSTED_NEAR_END) &&
+ (rowdata & SOTP_NVCTR_NON_TRUSTED_IN_USE) &&
+ (rownum > SOTP_NVCTR_ROW_START)) {
+ /*
+ * Current row in use and has data in last 2 bits as well.
+ * Check if next row also has data for this counter
+ */
+ nextrowdata = sotp_mem_read(rownum-1, SOTP_ROW_NO_ECC);
+ if (nextrowdata & SOTP_NVCTR_NON_TRUSTED_IN_USE) {
+ /* Next row also has data so decrement rownum */
+ rownum--;
+ nvctr += SOTP_NUM_BITS_PER_ROW;
+ rowdata = nextrowdata;
+ } else {
+ /* Next row does not have data */
+ break;
+ }
+ }
+
+ if (rowdata & SOTP_NVCTR_NON_TRUSTED_IN_USE) {
+ while ((rowdata & ((uint64_t)0x1 << (SOTP_NUM_BITS_PER_ROW-1)))
+ ==
+ 0) {
+ nvctr--;
+ rowdata <<= 1;
+ }
+ } else
+ nvctr -= SOTP_NUM_BITS_PER_ROW;
+
+ INFO("NCTR %i\n", nvctr);
+ return nvctr;
+}
+
+/*
+ * Set SOTP Trusted nvctr
+ */
+int sotp_set_trusted_nvctr(unsigned int nvctr)
+{
+ int numrows_available;
+ uint32_t nontrusted_rownum;
+ uint32_t trusted_rownum;
+ uint64_t rowdata;
+ unsigned int maxnvctr;
+
+ /*
+ * Read SOTP to find out how many rows are used by the
+ * NON Trusted nvctr
+ */
+ nontrusted_rownum = SOTP_NVCTR_ROW_END;
+ do {
+ rowdata = sotp_mem_read(nontrusted_rownum, SOTP_ROW_NO_ECC);
+ if (rowdata & SOTP_NVCTR_NON_TRUSTED_IN_USE)
+ nontrusted_rownum--;
+ else
+ break;
+ } while (nontrusted_rownum >= SOTP_NVCTR_ROW_START);
+
+ /*
+ * Calculate maximum value we can have for nvctr based on
+ * number of available rows.
+ */
+ numrows_available = nontrusted_rownum - SOTP_NVCTR_ROW_START + 1;
+ maxnvctr = numrows_available * SOTP_NUM_BITS_PER_ROW;
+ if (maxnvctr) {
+ /*
+ * Last 2 bits of counter can't be written or it will
+ * overflow with nontrusted counter
+ */
+ maxnvctr -= 2;
+ }
+
+ if (nvctr > maxnvctr) {
+ /* Error - not enough room */
+ WARN("tctr not set\n");
+ return 1;
+ }
+
+ /*
+ * It is safe to write the nvctr, fill all 1's up to the
+ * last row and then fill the last row with partial bitstream
+ */
+ trusted_rownum = SOTP_NVCTR_ROW_START;
+ rowdata = SOTP_NVCTR_ROW_ALL_ONES;
+
+ while (nvctr >= SOTP_NUM_BITS_PER_ROW) {
+ sotp_mem_write(trusted_rownum, SOTP_ROW_NO_ECC, rowdata);
+ nvctr -= SOTP_NUM_BITS_PER_ROW;
+ trusted_rownum++;
+ }
+ rowdata <<= (SOTP_NUM_BITS_PER_ROW - nvctr);
+ sotp_mem_write(trusted_rownum, SOTP_ROW_NO_ECC, rowdata);
+ return 0;
+}
+
+/*
+ * Set SOTP NonTrusted nvctr
+ */
+int sotp_set_nontrusted_nvctr(unsigned int nvctr)
+{
+ int numrows_available;
+ uint32_t nontrusted_rownum;
+ uint32_t trusted_rownum;
+ uint64_t rowdata;
+ unsigned int maxnvctr;
+
+ /*
+ * Read SOTP to find out how many rows are used by the
+ * Trusted nvctr
+ */
+ trusted_rownum = SOTP_NVCTR_ROW_START;
+ do {
+ rowdata = sotp_mem_read(trusted_rownum, SOTP_ROW_NO_ECC);
+ if (rowdata & SOTP_NVCTR_TRUSTED_IN_USE)
+ trusted_rownum++;
+ else
+ break;
+ } while (trusted_rownum <= SOTP_NVCTR_ROW_END);
+
+ /*
+ * Calculate maximum value we can have for nvctr based on
+ * number of available rows.
+ */
+ numrows_available = SOTP_NVCTR_ROW_END - trusted_rownum + 1;
+ maxnvctr = numrows_available * SOTP_NUM_BITS_PER_ROW;
+ if (maxnvctr) {
+ /*
+ * Last 2 bits of counter can't be written or it will
+ * overflow with nontrusted counter
+ */
+ maxnvctr -= 2;
+ }
+
+ if (nvctr > maxnvctr) {
+ /* Error - not enough room */
+ WARN("nctr not set\n");
+ return 1;
+ }
+
+ /*
+ * It is safe to write the nvctr, fill all 1's up to the
+ * last row and then fill the last row with partial bitstream
+ */
+ nontrusted_rownum = SOTP_NVCTR_ROW_END;
+ rowdata = SOTP_NVCTR_ROW_ALL_ONES;
+
+ while (nvctr >= SOTP_NUM_BITS_PER_ROW) {
+ sotp_mem_write(nontrusted_rownum, SOTP_ROW_NO_ECC, rowdata);
+ nvctr -= SOTP_NUM_BITS_PER_ROW;
+ nontrusted_rownum--;
+ }
+ rowdata >>= (SOTP_NUM_BITS_PER_ROW - nvctr);
+ sotp_mem_write(nontrusted_rownum, SOTP_ROW_NO_ECC, rowdata);
+ 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;
+
+ assert(cookie != NULL);
+ assert(nv_ctr != NULL);
+
+ *nv_ctr = 0;
+ if ((sotp_mem_read(SOTP_ATF_CFG_ROW_ID, SOTP_ROW_NO_ECC) &
+ SOTP_ATF_NVCOUNTER_ENABLE_MASK)) {
+ oid = (const char *)cookie;
+ if (strcmp(oid, TRUSTED_FW_NVCOUNTER_OID) == 0)
+ *nv_ctr = sotp_get_trusted_nvctr();
+ else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0)
+ *nv_ctr = sotp_get_nontrusted_nvctr();
+ else
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Store a new non-volatile counter value.
+ *
+ * Return: 0 = success, Otherwise = error
+ */
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+ const char *oid;
+
+ if (sotp_mem_read(SOTP_ATF_CFG_ROW_ID, SOTP_ROW_NO_ECC) &
+ SOTP_ATF_NVCOUNTER_ENABLE_MASK) {
+ INFO("set CTR %i\n", nv_ctr);
+ oid = (const char *)cookie;
+ if (strcmp(oid, TRUSTED_FW_NVCOUNTER_OID) == 0)
+ return sotp_set_trusted_nvctr(nv_ctr);
+ else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0)
+ return sotp_set_nontrusted_nvctr(nv_ctr);
+ return 1;
+ }
+ return 0;
+}
+
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+ return get_mbedtls_heap_helper(heap_addr, heap_size);
+}
diff --git a/plat/brcm/board/common/board_common.c b/plat/brcm/board/common/board_common.c
new file mode 100644
index 0000000..2f764ab
--- /dev/null
+++ b/plat/brcm/board/common/board_common.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <brcm_def.h>
+#include <plat_brcm.h>
+
+#if IMAGE_BL2
+const mmap_region_t plat_brcm_mmap[] = {
+ HSLS_REGION,
+ BRCM_MAP_SHARED_RAM,
+ BRCM_MAP_NAND_RO,
+ BRCM_MAP_QSPI_RO,
+#ifdef PERIPH0_REGION
+ PERIPH0_REGION,
+#endif
+#ifdef PERIPH1_REGION
+ PERIPH1_REGION,
+#endif
+#ifdef USE_DDR
+ BRCM_MAP_NS_DRAM1,
+#if BRCM_BL31_IN_DRAM
+ BRCM_MAP_BL31_SEC_DRAM,
+#endif
+#else
+#ifdef BRCM_MAP_EXT_SRAM
+ BRCM_MAP_EXT_SRAM,
+#endif
+#endif
+#if defined(USE_CRMU_SRAM) && defined(CRMU_SRAM_BASE)
+ CRMU_SRAM_REGION,
+#endif
+ {0}
+};
+#endif
+
+#if IMAGE_BL31
+const mmap_region_t plat_brcm_mmap[] = {
+ HSLS_REGION,
+#ifdef PERIPH0_REGION
+ PERIPH0_REGION,
+#endif
+#ifdef PERIPH1_REGION
+ PERIPH1_REGION,
+#endif
+#ifdef PERIPH2_REGION
+ PERIPH2_REGION,
+#endif
+#ifdef USB_REGION
+ USB_REGION,
+#endif
+#ifdef USE_DDR
+ BRCM_MAP_NS_DRAM1,
+#ifdef BRCM_MAP_NS_SHARED_DRAM
+ BRCM_MAP_NS_SHARED_DRAM,
+#endif
+#else
+#ifdef BRCM_MAP_EXT_SRAM
+ BRCM_MAP_EXT_SRAM,
+#endif
+#endif
+#if defined(USE_CRMU_SRAM) && defined(CRMU_SRAM_BASE)
+ CRMU_SRAM_REGION,
+#endif
+ {0}
+};
+#endif
+
+CASSERT((ARRAY_SIZE(plat_brcm_mmap) - 1) <= PLAT_BRCM_MMAP_ENTRIES,
+ assert_plat_brcm_mmap_mismatch);
+CASSERT((PLAT_BRCM_MMAP_ENTRIES + BRCM_BL_REGIONS) <= MAX_MMAP_REGIONS,
+ assert_max_mmap_regions);
diff --git a/plat/brcm/board/common/board_common.mk b/plat/brcm/board/common/board_common.mk
new file mode 100644
index 0000000..24a27ed
--- /dev/null
+++ b/plat/brcm/board/common/board_common.mk
@@ -0,0 +1,294 @@
+#
+# Copyright (c) 2015 - 2021, Broadcom
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT_BL_COMMON_SOURCES += plat/brcm/board/common/board_common.c
+
+# If no board config makefile, do not include it
+ifneq (${BOARD_CFG},)
+BOARD_CFG_MAKE := $(shell find plat/brcm/board/${PLAT} -name '${BOARD_CFG}.mk')
+$(eval $(call add_define,BOARD_CFG))
+ifneq (${BOARD_CFG_MAKE},)
+$(info Including ${BOARD_CFG_MAKE})
+include ${BOARD_CFG_MAKE}
+else
+$(error Error: File ${BOARD_CFG}.mk not found in plat/brcm/board/${PLAT})
+endif
+endif
+
+# To compile with highest log level (VERBOSE) set value to 50
+LOG_LEVEL := 40
+
+# Use custom generic timer clock
+ifneq (${GENTIMER_ACTUAL_CLOCK},)
+$(info Using GENTIMER_ACTUAL_CLOCK=$(GENTIMER_ACTUAL_CLOCK))
+SYSCNT_FREQ := $(GENTIMER_ACTUAL_CLOCK)
+$(eval $(call add_define,SYSCNT_FREQ))
+endif
+
+ifeq (${DRIVER_EMMC_ENABLE},)
+DRIVER_EMMC_ENABLE :=1
+endif
+
+ifeq (${DRIVER_SPI_ENABLE},)
+DRIVER_SPI_ENABLE := 0
+endif
+
+ifeq (${DRIVER_I2C_ENABLE},)
+DRIVER_I2C_ENABLE := 0
+endif
+
+# By default, Trusted Watchdog is always enabled unless SPIN_ON_BL1_EXIT is set
+ifeq (${BRCM_DISABLE_TRUSTED_WDOG},)
+BRCM_DISABLE_TRUSTED_WDOG := 0
+endif
+ifeq (${SPIN_ON_BL1_EXIT}, 1)
+BRCM_DISABLE_TRUSTED_WDOG := 1
+endif
+
+$(eval $(call assert_boolean,BRCM_DISABLE_TRUSTED_WDOG))
+$(eval $(call add_define,BRCM_DISABLE_TRUSTED_WDOG))
+
+# Process ARM_BL31_IN_DRAM flag
+ifeq (${ARM_BL31_IN_DRAM},)
+ARM_BL31_IN_DRAM := 0
+endif
+$(eval $(call assert_boolean,ARM_BL31_IN_DRAM))
+$(eval $(call add_define,ARM_BL31_IN_DRAM))
+
+ifeq (${STANDALONE_BL2},yes)
+BL2_LOG_LEVEL := 40
+$(eval $(call add_define,MMU_DISABLED))
+endif
+
+# BL2 XIP from QSPI
+RUN_BL2_FROM_QSPI := 0
+ifeq (${RUN_BL2_FROM_QSPI},1)
+$(eval $(call add_define,RUN_BL2_FROM_QSPI))
+endif
+
+# BL2 XIP from NAND
+RUN_BL2_FROM_NAND := 0
+ifeq (${RUN_BL2_FROM_NAND},1)
+$(eval $(call add_define,RUN_BL2_FROM_NAND))
+endif
+
+ifneq (${ELOG_AP_UART_LOG_BASE},)
+$(eval $(call add_define,ELOG_AP_UART_LOG_BASE))
+endif
+
+ifeq (${ELOG_SUPPORT},1)
+ifeq (${ELOG_STORE_MEDIA},DDR)
+$(eval $(call add_define,ELOG_STORE_MEDIA_DDR))
+ifneq (${ELOG_STORE_OFFSET},)
+$(eval $(call add_define,ELOG_STORE_OFFSET))
+endif
+endif
+endif
+
+ifneq (${BL2_LOG_LEVEL},)
+$(eval $(call add_define,BL2_LOG_LEVEL))
+endif
+
+ifneq (${BL31_LOG_LEVEL},)
+$(eval $(call add_define,BL31_LOG_LEVEL))
+endif
+
+# Use CRMU SRAM from iHOST
+ifneq (${USE_CRMU_SRAM},)
+$(eval $(call add_define,USE_CRMU_SRAM))
+endif
+
+# Use PIO mode if DDR is not used
+ifeq (${USE_DDR},yes)
+EMMC_USE_DMA := 1
+else
+EMMC_USE_DMA := 0
+endif
+$(eval $(call add_define,EMMC_USE_DMA))
+
+# On BRCM 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
+
+# Use generic OID definition (tbbr_oid.h)
+USE_TBBR_DEFS := 1
+
+PLAT_INCLUDES += -Iplat/brcm/board/common \
+ -Iinclude/drivers/brcm \
+ -Iinclude/drivers/brcm/emmc \
+ -Iinclude/drivers/brcm/mdio
+
+PLAT_BL_COMMON_SOURCES += plat/brcm/common/brcm_common.c \
+ plat/brcm/board/common/cmn_sec.c \
+ plat/brcm/board/common/bcm_console.c \
+ plat/brcm/board/common/brcm_mbedtls.c \
+ plat/brcm/board/common/plat_setup.c \
+ plat/brcm/board/common/platform_common.c \
+ drivers/arm/sp804/sp804_delay_timer.c \
+ drivers/brcm/sotp.c \
+ drivers/delay_timer/delay_timer.c \
+ drivers/io/io_fip.c \
+ drivers/io/io_memmap.c \
+ drivers/io/io_storage.c \
+ plat/brcm/common/brcm_io_storage.c \
+ plat/brcm/board/common/err.c \
+ plat/brcm/board/common/sbl_util.c \
+ drivers/arm/sp805/sp805.c
+
+# Add RNG driver
+DRIVER_RNG_ENABLE := 1
+ifeq (${DRIVER_RNG_ENABLE},1)
+PLAT_BL_COMMON_SOURCES += drivers/brcm/rng.c
+endif
+
+# Add eMMC driver
+ifeq (${DRIVER_EMMC_ENABLE},1)
+$(eval $(call add_define,DRIVER_EMMC_ENABLE))
+
+EMMC_SOURCES += drivers/brcm/emmc/emmc_chal_sd.c \
+ drivers/brcm/emmc/emmc_csl_sdcard.c \
+ drivers/brcm/emmc/emmc_csl_sdcmd.c \
+ drivers/brcm/emmc/emmc_pboot_hal_memory_drv.c
+
+PLAT_BL_COMMON_SOURCES += ${EMMC_SOURCES}
+
+ifeq (${DRIVER_EMMC_ENABLE_DATA_WIDTH_8BIT},)
+$(eval $(call add_define,DRIVER_EMMC_ENABLE_DATA_WIDTH_8BIT))
+endif
+endif
+
+BL2_SOURCES += plat/brcm/common/brcm_bl2_mem_params_desc.c \
+ plat/brcm/common/brcm_image_load.c \
+ common/desc_image_load.c
+
+BL2_SOURCES += plat/brcm/common/brcm_bl2_setup.c
+
+BL31_SOURCES += plat/brcm/common/brcm_bl31_setup.c
+
+ifeq (${BCM_ELOG},yes)
+ELOG_SOURCES += plat/brcm/board/common/bcm_elog.c
+BL2_SOURCES += ${ELOG_SOURCES}
+BL31_SOURCES += ${ELOG_SOURCES}
+endif
+
+# Add spi driver
+ifeq (${DRIVER_SPI_ENABLE},1)
+PLAT_BL_COMMON_SOURCES += drivers/brcm/spi/iproc_spi.c \
+ drivers/brcm/spi/iproc_qspi.c
+endif
+
+# Add spi nor/flash driver
+ifeq (${DRIVER_SPI_NOR_ENABLE},1)
+PLAT_BL_COMMON_SOURCES += drivers/brcm/spi_sf.c \
+ drivers/brcm/spi_flash.c
+endif
+
+ifeq (${DRIVER_I2C_ENABLE},1)
+$(eval $(call add_define,DRIVER_I2C_ENABLE))
+BL2_SOURCES += drivers/brcm/i2c/i2c.c
+PLAT_INCLUDES += -Iinclude/drivers/brcm/i2c
+endif
+
+ifeq (${DRIVER_OCOTP_ENABLE},1)
+$(eval $(call add_define,DRIVER_OCOTP_ENABLE))
+BL2_SOURCES += drivers/brcm/ocotp.c
+endif
+
+# Enable FRU table support
+ifeq (${USE_FRU},yes)
+$(eval $(call add_define,USE_FRU))
+BL2_SOURCES += drivers/brcm/fru.c
+endif
+
+# Enable GPIO support
+ifeq (${USE_GPIO},yes)
+$(eval $(call add_define,USE_GPIO))
+BL2_SOURCES += drivers/gpio/gpio.c
+BL2_SOURCES += drivers/brcm/iproc_gpio.c
+ifeq (${GPIO_SUPPORT_FLOAT_DETECTION},yes)
+$(eval $(call add_define,GPIO_SUPPORT_FLOAT_DETECTION))
+endif
+endif
+
+# Include mbedtls if it can be located
+MBEDTLS_DIR ?= mbedtls
+MBEDTLS_CHECK := $(shell find ${MBEDTLS_DIR}/include -name '$(notdir ${MBEDTLS_DIR})')
+
+ifneq (${MBEDTLS_CHECK},)
+$(info Found mbedTLS at ${MBEDTLS_DIR})
+PLAT_INCLUDES += -I${MBEDTLS_DIR}/include/mbedtls
+
+# By default, use RSA keys
+KEY_ALG := rsa_1_5
+
+# 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_common.c \
+ drivers/auth/tbbr/tbbr_cot_bl2.c
+
+BL2_SOURCES += ${AUTH_SOURCES}
+
+# Use ATF framework for MBEDTLS
+TRUSTED_BOARD_BOOT := 1
+CRYPTO_LIB_MK := drivers/auth/mbedtls/mbedtls_crypto.mk
+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}
+
+# Use ATF secure boot functions
+# Use Hardcoded hash for devel
+
+ARM_ROTPK_LOCATION=arm_rsa
+ifeq (${ARM_ROTPK_LOCATION}, arm_rsa)
+ARM_ROTPK_LOCATION_ID=ARM_ROTPK_DEVEL_RSA_ID
+ROT_KEY=plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem
+else ifeq (${ARM_ROTPK_LOCATION}, brcm_rsa)
+ARM_ROTPK_LOCATION_ID=BRCM_ROTPK_SOTP_RSA_ID
+ifeq (${ROT_KEY},)
+ROT_KEY=plat/brcm/board/common/rotpk/rsa_dauth2048_key.pem
+endif
+KEY_FIND := $(shell m="${ROT_KEY}"; [ -f "$$m" ] && echo "$$m")
+ifeq (${KEY_FIND},)
+$(error Error: No ${ROT_KEY} located)
+else
+$(info Using ROT_KEY: ${ROT_KEY})
+endif
+else
+$(error "Unsupported ARM_ROTPK_LOCATION value")
+endif
+
+$(eval $(call add_define,ARM_ROTPK_LOCATION_ID))
+PLAT_BL_COMMON_SOURCES+=plat/brcm/board/common/board_arm_trusted_boot.c
+endif
+
+#M0 runtime firmware
+ifdef SCP_BL2
+$(eval $(call add_define,NEED_SCP_BL2))
+SCP_CFG_DIR=$(dir ${SCP_BL2})
+PLAT_INCLUDES += -I${SCP_CFG_DIR}
+endif
+
+ifneq (${NEED_BL33},yes)
+# If there is no BL33, BL31 will jump to this address.
+ifeq (${USE_DDR},yes)
+PRELOADED_BL33_BASE := 0x80000000
+else
+PRELOADED_BL33_BASE := 0x74000000
+endif
+endif
+
+# Use translation tables library v1 by default
+ARM_XLAT_TABLES_LIB_V1 := 1
+ifeq (${ARM_XLAT_TABLES_LIB_V1}, 1)
+$(eval $(call assert_boolean,ARM_XLAT_TABLES_LIB_V1))
+$(eval $(call add_define,ARM_XLAT_TABLES_LIB_V1))
+PLAT_BL_COMMON_SOURCES += lib/xlat_tables/aarch64/xlat_tables.c \
+ lib/xlat_tables/xlat_tables_common.c
+endif
diff --git a/plat/brcm/board/common/brcm_mbedtls.c b/plat/brcm/board/common/brcm_mbedtls.c
new file mode 100644
index 0000000..af42b86
--- /dev/null
+++ b/plat/brcm/board/common/brcm_mbedtls.c
@@ -0,0 +1,12 @@
+/*
+ * Copyright 2015 - 2020 Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+
+void tls_exit(int code)
+{
+ INFO("%s: 0x%x\n", __func__, code);
+}
diff --git a/plat/brcm/board/common/chip_id.h b/plat/brcm/board/common/chip_id.h
new file mode 100644
index 0000000..842ac1f
--- /dev/null
+++ b/plat/brcm/board/common/chip_id.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CHIP_ID_H
+#define CHIP_ID_H
+
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+#define CHIP_REV_MAJOR_MASK 0xF0
+#define CHIP_REV_MAJOR_AX 0x00
+#define CHIP_REV_MAJOR_BX 0x10
+#define CHIP_REV_MAJOR_CX 0x20
+#define CHIP_REV_MAJOR_DX 0x30
+
+/* Get Chip ID (product number) of the chip */
+static inline unsigned int chip_get_product_id(void)
+{
+ return PLAT_CHIP_ID_GET;
+}
+
+/* Get Revision ID (major and minor) number of the chip */
+static inline unsigned int chip_get_rev_id(void)
+{
+ return PLAT_CHIP_REV_GET;
+}
+
+static inline unsigned int chip_get_rev_id_major(void)
+{
+ return (chip_get_rev_id() & CHIP_REV_MAJOR_MASK);
+}
+
+#endif
diff --git a/plat/brcm/board/common/cmn_plat_def.h b/plat/brcm/board/common/cmn_plat_def.h
new file mode 100644
index 0000000..79d9a29
--- /dev/null
+++ b/plat/brcm/board/common/cmn_plat_def.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CMN_PLAT_DEF_H
+#define CMN_PLAT_DEF_H
+
+#include <bcm_elog.h>
+#include <platform_def.h>
+
+#ifndef GET_LOG_LEVEL
+#define GET_LOG_LEVEL() LOG_LEVEL
+#endif
+
+#ifndef SET_LOG_LEVEL
+#define SET_LOG_LEVEL(x) ((void)(x))
+#endif
+
+#define PLAT_LOG_NOTICE(...) \
+ do { \
+ if (GET_LOG_LEVEL() >= LOG_LEVEL_NOTICE) { \
+ bcm_elog(LOG_MARKER_NOTICE __VA_ARGS__); \
+ tf_log(LOG_MARKER_NOTICE __VA_ARGS__); \
+ } \
+ } while (0)
+
+#define PLAT_LOG_ERROR(...) \
+ do { \
+ if (GET_LOG_LEVEL() >= LOG_LEVEL_ERROR) { \
+ bcm_elog(LOG_MARKER_ERROR, __VA_ARGS__); \
+ tf_log(LOG_MARKER_ERROR __VA_ARGS__); \
+ } \
+ } while (0)
+
+#define PLAT_LOG_WARN(...) \
+ do { \
+ if (GET_LOG_LEVEL() >= LOG_LEVEL_WARNING) { \
+ bcm_elog(LOG_MARKER_WARNING, __VA_ARGS__);\
+ tf_log(LOG_MARKER_WARNING __VA_ARGS__); \
+ } \
+ } while (0)
+
+#define PLAT_LOG_INFO(...) \
+ do { \
+ if (GET_LOG_LEVEL() >= LOG_LEVEL_INFO) { \
+ bcm_elog(LOG_MARKER_INFO __VA_ARGS__); \
+ tf_log(LOG_MARKER_INFO __VA_ARGS__); \
+ } \
+ } while (0)
+
+#define PLAT_LOG_VERBOSE(...) \
+ do { \
+ if (GET_LOG_LEVEL() >= LOG_LEVEL_VERBOSE) { \
+ bcm_elog(LOG_MARKER_VERBOSE __VA_ARGS__);\
+ tf_log(LOG_MARKER_VERBOSE __VA_ARGS__); \
+ } \
+ } while (0)
+
+/*
+ * 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 CMN_BL_REGIONS 3
+#else
+#define CMN_BL_REGIONS 2
+#endif
+
+/*
+ * FIP definitions
+ */
+#define PLAT_FIP_ATTEMPT_OFFSET 0x20000
+#define PLAT_FIP_NUM_ATTEMPTS 128
+
+#define PLAT_BRCM_FIP_QSPI_BASE QSPI_BASE_ADDR
+#define PLAT_BRCM_FIP_NAND_BASE NAND_BASE_ADDR
+#define PLAT_BRCM_FIP_MAX_SIZE 0x01000000
+
+#define PLAT_BRCM_FIP_BASE PLAT_BRCM_FIP_QSPI_BASE
+#endif
diff --git a/plat/brcm/board/common/cmn_plat_util.h b/plat/brcm/board/common/cmn_plat_util.h
new file mode 100644
index 0000000..178c843
--- /dev/null
+++ b/plat/brcm/board/common/cmn_plat_util.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CMN_PLAT_UTIL_H
+#define CMN_PLAT_UTIL_H
+
+#include <lib/mmio.h>
+
+/* BOOT source */
+#define BOOT_SOURCE_MASK 7
+#define BOOT_SOURCE_QSPI 0
+#define BOOT_SOURCE_NAND 1
+#define BOOT_SOURCE_SPI_NAND 2
+#define BOOT_SOURCE_UART 3
+#define BOOT_SOURCE_RES4 4
+#define BOOT_SOURCE_EMMC 5
+#define BOOT_SOURCE_ATE 6
+#define BOOT_SOURCE_USB 7
+#define BOOT_SOURCE_MAX 8
+#define BOOT_SOURCE_UNKNOWN (-1)
+
+#define KHMAC_SHA256_KEY_SIZE 32
+
+#define SOFT_PWR_UP_RESET_L0 0
+#define SOFT_SYS_RESET_L1 1
+#define SOFT_RESET_L3 0x3
+
+#define BOOT_SOURCE_SOFT_DATA_OFFSET 8
+#define BOOT_SOURCE_SOFT_ENABLE_OFFSET 14
+#define BOOT_SOURCE_SOFT_ENABLE_MASK BIT(BOOT_SOURCE_SOFT_ENABLE_OFFSET)
+
+typedef struct _key {
+ uint8_t hmac_sha256[KHMAC_SHA256_KEY_SIZE];
+} cmn_key_t;
+
+uint32_t boot_source_get(void);
+void bl1_platform_wait_events(void);
+void plat_soft_reset(uint32_t reset);
+
+#endif
diff --git a/plat/brcm/board/common/cmn_sec.c b/plat/brcm/board/common/cmn_sec.c
new file mode 100644
index 0000000..c80d5dd
--- /dev/null
+++ b/plat/brcm/board/common/cmn_sec.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <cmn_sec.h>
+
+#pragma weak plat_tz_master_default_cfg
+#pragma weak plat_tz_sdio_ns_master_set
+#pragma weak plat_tz_usb_ns_master_set
+
+void plat_tz_master_default_cfg(void)
+{
+ /* This function should be implemented in the platform side. */
+ ERROR("%s: TZ CONFIGURATION NOT SET!!!\n", __func__);
+}
+
+void plat_tz_sdio_ns_master_set(uint32_t ns)
+{
+ /* This function should be implemented in the platform side. */
+ ERROR("%s: TZ CONFIGURATION NOT SET!!!\n", __func__);
+}
+
+void plat_tz_usb_ns_master_set(uint32_t ns)
+{
+ /* This function should be implemented in the platform side. */
+ ERROR("%s: TZ CONFIGURATION NOT SET!!!\n", __func__);
+}
+
+void tz_master_default_cfg(void)
+{
+ plat_tz_master_default_cfg();
+}
+
+void tz_sdio_ns_master_set(uint32_t ns)
+{
+ plat_tz_sdio_ns_master_set(ns);
+}
+
+void tz_usb_ns_master_set(uint32_t ns)
+{
+ plat_tz_usb_ns_master_set(ns);
+}
diff --git a/plat/brcm/board/common/cmn_sec.h b/plat/brcm/board/common/cmn_sec.h
new file mode 100644
index 0000000..f74863d
--- /dev/null
+++ b/plat/brcm/board/common/cmn_sec.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2015-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CMN_SEC_H
+#define CMN_SEC_H
+
+#include <stdint.h>
+
+#define SECURE_MASTER 0
+#define NS_MASTER 1
+
+void tz_master_default_cfg(void);
+void tz_usb_ns_master_set(uint32_t ns);
+void tz_sdio_ns_master_set(uint32_t ns);
+
+#endif
diff --git a/plat/brcm/board/common/err.c b/plat/brcm/board/common/err.c
new file mode 100644
index 0000000..1fc73c4
--- /dev/null
+++ b/plat/brcm/board/common/err.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+#define L0_RESET 0x2
+
+/*
+ * Brcm error handler
+ */
+void plat_error_handler(int err)
+{
+ INFO("L0 reset...\n");
+
+ /* Ensure the characters are flushed out */
+ console_flush();
+
+ mmio_write_32(CRMU_SOFT_RESET_CTRL, L0_RESET);
+
+ /*
+ * In case we get here:
+ * Loop until the watchdog resets the system
+ */
+ while (1) {
+ wfi();
+ }
+}
diff --git a/plat/brcm/board/common/plat_setup.c b/plat/brcm/board/common/plat_setup.c
new file mode 100644
index 0000000..95e12ed
--- /dev/null
+++ b/plat/brcm/board/common/plat_setup.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+/*
+ * This function returns the fixed clock frequency at which private
+ * timers run. This value will be programmed into CNTFRQ_EL0.
+ */
+unsigned int plat_get_syscnt_freq2(void)
+{
+ return SYSCNT_FREQ;
+}
+
+static const char * const plat_prefix_str[] = {
+ "E: ", "N: ", "W: ", "I: ", "V: "
+};
+
+const char *plat_log_get_prefix(unsigned int log_level)
+{
+ return plat_prefix_str[log_level - 1U];
+}
diff --git a/plat/brcm/board/common/platform_common.c b/plat/brcm/board/common/platform_common.c
new file mode 100644
index 0000000..f4c9a73
--- /dev/null
+++ b/plat/brcm/board/common/platform_common.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/brcm/sotp.h>
+
+#include <cmn_plat_util.h>
+#include <platform_def.h>
+
+uint32_t boot_source_get(void)
+{
+ uint32_t data;
+
+#ifdef FORCE_BOOTSOURCE
+ data = FORCE_BOOTSOURCE;
+#else
+ /* Read primary boot strap from CRMU persistent registers */
+ data = mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG1);
+ if (data & BOOT_SOURCE_SOFT_ENABLE_MASK) {
+ data >>= BOOT_SOURCE_SOFT_DATA_OFFSET;
+ } else {
+ uint64_t sotp_atf_row;
+
+ sotp_atf_row =
+ sotp_mem_read(SOTP_ATF_CFG_ROW_ID, SOTP_ROW_NO_ECC);
+
+ if (sotp_atf_row & SOTP_BOOT_SOURCE_ENABLE_MASK) {
+ /* Construct the boot source based on SOTP bits */
+ data = 0;
+ if (sotp_atf_row & SOTP_BOOT_SOURCE_BITS0)
+ data |= 0x1;
+ if (sotp_atf_row & SOTP_BOOT_SOURCE_BITS1)
+ data |= 0x2;
+ if (sotp_atf_row & SOTP_BOOT_SOURCE_BITS2)
+ data |= 0x4;
+ } else {
+
+ /*
+ * This path is for L0 reset with
+ * Primary Boot source disabled in SOTP.
+ * BOOT_SOURCE_FROM_PR_ON_L1 compile flag will allow
+ * to never come back here so that the
+ * external straps will not be read on L1 reset.
+ */
+
+ /* Use the external straps */
+ data = mmio_read_32(ROM_S0_IDM_IO_STATUS);
+
+#ifdef BOOT_SOURCE_FROM_PR_ON_L1
+ /* Enable boot source read from PR#1 */
+ mmio_setbits_32(CRMU_IHOST_SW_PERSISTENT_REG1,
+ BOOT_SOURCE_SOFT_ENABLE_MASK);
+
+ /* set boot source */
+ data &= BOOT_SOURCE_MASK;
+ mmio_clrsetbits_32(CRMU_IHOST_SW_PERSISTENT_REG1,
+ BOOT_SOURCE_MASK << BOOT_SOURCE_SOFT_DATA_OFFSET,
+ data << BOOT_SOURCE_SOFT_DATA_OFFSET);
+#endif
+ }
+ }
+#endif
+ return (data & BOOT_SOURCE_MASK);
+}
+
+void __dead2 plat_soft_reset(uint32_t reset)
+{
+ if (reset == SOFT_RESET_L3) {
+ mmio_setbits_32(CRMU_IHOST_SW_PERSISTENT_REG1, reset);
+ mmio_write_32(CRMU_MAIL_BOX0, 0x0);
+ mmio_write_32(CRMU_MAIL_BOX1, 0xFFFFFFFF);
+ }
+
+ if (reset != SOFT_SYS_RESET_L1)
+ reset = SOFT_PWR_UP_RESET_L0;
+
+ if (reset == SOFT_PWR_UP_RESET_L0)
+ INFO("L0 RESET...\n");
+
+ if (reset == SOFT_SYS_RESET_L1)
+ INFO("L1 RESET...\n");
+
+ console_flush();
+
+ mmio_clrbits_32(CRMU_SOFT_RESET_CTRL, 1 << reset);
+
+ while (1) {
+ ;
+ }
+}
diff --git a/plat/brcm/board/common/sbl_util.c b/plat/brcm/board/common/sbl_util.c
new file mode 100644
index 0000000..06e5b33
--- /dev/null
+++ b/plat/brcm/board/common/sbl_util.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include <platform_def.h>
+#include <sbl_util.h>
+#include <sotp.h>
+
+#pragma weak plat_sbl_status
+
+int plat_sbl_status(uint64_t sbl_status)
+{
+ return sbl_status ? 1:0;
+}
+
+int sbl_status(void)
+{
+ uint64_t sbl_sotp = 0;
+ int ret = SBL_DISABLED;
+
+ sbl_sotp = sotp_mem_read(SOTP_ATF_CFG_ROW_ID, SOTP_ROW_NO_ECC);
+
+ if (sbl_sotp != SOTP_ECC_ERR_DETECT) {
+
+ sbl_sotp &= SOTP_SBL_MASK;
+
+ if (plat_sbl_status(sbl_sotp))
+ ret = SBL_ENABLED;
+ }
+
+ VERBOSE("SBL status: %d\n", ret);
+
+ return ret;
+}
diff --git a/plat/brcm/board/common/sbl_util.h b/plat/brcm/board/common/sbl_util.h
new file mode 100644
index 0000000..0747389
--- /dev/null
+++ b/plat/brcm/board/common/sbl_util.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2015 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SBL_UTIL_H
+#define SBL_UTIL_H
+
+#include <stdint.h>
+
+#include <sotp.h>
+
+#define SBL_DISABLED 0
+#define SBL_ENABLED 1
+
+int sbl_status(void);
+
+#endif /* #ifdef SBL_UTIL_H */
diff --git a/plat/brcm/board/common/timer_sync.c b/plat/brcm/board/common/timer_sync.c
new file mode 100644
index 0000000..7e33a94
--- /dev/null
+++ b/plat/brcm/board/common/timer_sync.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+#include <timer_sync.h>
+
+/*******************************************************************************
+ * Defines related to time sync and satelite timers
+ ******************************************************************************/
+#define TIME_SYNC_WR_ENA ((uint32_t)0xACCE55 << 8)
+#define IHOST_STA_TMR_CTRL 0x1800
+#define IHOST_SAT_TMR_INC_L 0x1814
+#define IHOST_SAT_TMR_INC_H 0x1818
+
+#define SAT_TMR_CYCLE_DELAY 2
+#define SAT_TMR_32BIT_WRAP_VAL (BIT_64(32) - SAT_TMR_CYCLE_DELAY)
+
+void ihost_enable_satellite_timer(unsigned int cluster_id)
+{
+ uintptr_t ihost_base;
+ uint32_t time_lx, time_h;
+ uintptr_t ihost_enable;
+
+ VERBOSE("Program iHost%u satellite timer\n", cluster_id);
+ ihost_base = IHOST0_BASE + cluster_id * IHOST_ADDR_SPACE;
+
+ /* this read starts the satellite timer counting from 0 */
+ ihost_enable = CENTRAL_TIMER_GET_IHOST_ENA_BASE + cluster_id * 4;
+ time_lx = mmio_read_32(ihost_enable);
+
+ /*
+ * Increment the satellite timer by the central timer plus 2
+ * to accommodate for a 1 cycle delay through NOC
+ * plus counter starting from 0.
+ */
+ mmio_write_32(ihost_base + IHOST_SAT_TMR_INC_L,
+ time_lx + SAT_TMR_CYCLE_DELAY);
+
+ /*
+ * Read the latched upper data, if lx will wrap by adding 2 to it
+ * we need to handle the wrap
+ */
+ time_h = mmio_read_32(CENTRAL_TIMER_GET_H);
+ if (time_lx >= SAT_TMR_32BIT_WRAP_VAL)
+ mmio_write_32(ihost_base + IHOST_SAT_TMR_INC_H, time_h + 1);
+ else
+ mmio_write_32(ihost_base + IHOST_SAT_TMR_INC_H, time_h);
+}
+
+void brcm_timer_sync_init(void)
+{
+ unsigned int cluster_id;
+
+ /* Get the Time Sync module out of reset */
+ mmio_setbits_32(CDRU_MISC_RESET_CONTROL,
+ BIT(CDRU_MISC_RESET_CONTROL_TS_RESET_N));
+
+ /* Deassert the Central Timer TIMER_EN signal for all module */
+ mmio_write_32(CENTRAL_TIMER_SAT_TMR_ENA, TIME_SYNC_WR_ENA);
+
+ /* enables/programs iHost0 satellite timer*/
+ cluster_id = MPIDR_AFFLVL1_VAL(read_mpidr());
+ ihost_enable_satellite_timer(cluster_id);
+}
diff --git a/plat/brcm/board/stingray/aarch64/plat_helpers.S b/plat/brcm/board/stingray/aarch64/plat_helpers.S
new file mode 100644
index 0000000..9a2039d
--- /dev/null
+++ b/plat/brcm/board/stingray/aarch64/plat_helpers.S
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2015-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cpu_macros.S>
+#include <cortex_a72.h>
+#include <drivers/ti/uart/uart_16550.h>
+
+#include <platform_def.h>
+
+ .globl plat_reset_handler
+ .globl platform_get_entrypoint
+ .globl plat_secondary_cold_boot_setup
+ .globl platform_mem_init
+ .globl platform_check_mpidr
+ .globl plat_crash_console_init
+ .globl plat_crash_console_putc
+ .globl plat_crash_console_flush
+ .globl plat_disable_acp
+ .globl plat_is_my_cpu_primary
+ .globl plat_my_core_pos
+ .globl platform_is_primary_cpu
+ .globl plat_brcm_calc_core_pos
+ .globl plat_get_my_entrypoint
+
+
+ /* ------------------------------------------------------------
+ * void plat_l2_init(void);
+ *
+ * BL1 and BL2 run with one core, one cluster
+ * This is safe to disable cluster coherency
+ * to make use of the data cache MMU WB attribute
+ * for the SRAM.
+ *
+ * Set L2 Auxiliary Control Register
+ * --------------------------------------------------------------------
+ */
+func plat_l2_init
+ mrs x0, CORTEX_A72_L2ACTLR_EL1
+#if (IMAGE_BL1 || IMAGE_BL2) || defined(USE_SINGLE_CLUSTER)
+ orr x0, x0, #CORTEX_A72_L2ACTLR_DISABLE_ACE_SH_OR_CHI
+#else
+ bic x0, x0, #CORTEX_A72_L2ACTLR_DISABLE_ACE_SH_OR_CHI
+#endif
+ msr CORTEX_A72_L2ACTLR_EL1, x0
+
+ /* Set L2 Control Register */
+ mrs x0, CORTEX_A72_L2CTLR_EL1
+ mov x1, #((CORTEX_A72_L2_DATA_RAM_LATENCY_MASK << \
+ CORTEX_A72_L2CTLR_DATA_RAM_LATENCY_SHIFT) | \
+ (CORTEX_A72_L2_TAG_RAM_LATENCY_MASK << \
+ CORTEX_A72_L2CTLR_TAG_RAM_LATENCY_SHIFT) | \
+ (U(0x1) << CORTEX_A72_L2CTLR_TAG_RAM_SETUP_SHIFT) | \
+ (U(0x1) << CORTEX_A72_L2CTLR_DATA_RAM_SETUP_SHIFT))
+ bic x0, x0, x1
+ mov x1, #((CORTEX_A72_L2_DATA_RAM_LATENCY_3_CYCLES << \
+ CORTEX_A72_L2CTLR_DATA_RAM_LATENCY_SHIFT) | \
+ (U(0x1) << CORTEX_A72_L2CTLR_TAG_RAM_SETUP_SHIFT) | \
+ (U(0x1) << CORTEX_A72_L2CTLR_DATA_RAM_SETUP_SHIFT))
+ orr x0, x0, x1
+ msr CORTEX_A72_L2CTLR_EL1, x0
+
+ isb
+ ret
+endfunc plat_l2_init
+
+ /* --------------------------------------------------------------------
+ * void plat_reset_handler(void);
+ *
+ * Before adding code in this function, refer to the guidelines in
+ * docs/firmware-design.md.
+ *
+ * --------------------------------------------------------------------
+ */
+func plat_reset_handler
+ mov x9, x30
+ bl plat_l2_init
+ mov x30, x9
+ ret
+endfunc plat_reset_handler
+
+ /* -----------------------------------------------------
+ * void platform_get_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.
+ * -----------------------------------------------------
+ */
+func platform_get_entrypoint
+ /*TBD-STINGRAY*/
+ mov x0, #0
+ ret
+endfunc platform_get_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
+ bl plat_my_core_pos
+ mov_imm x1, SECONDARY_CPU_SPIN_BASE_ADDR
+ add x0, x1, x0, LSL #3
+ mov x1, #0
+ str x1, [x0]
+
+ /* Wait until the entrypoint gets populated */
+poll_mailbox:
+ ldr x1, [x0]
+ cbz x1, 1f
+ br x1
+1:
+ wfe
+ b poll_mailbox
+endfunc plat_secondary_cold_boot_setup
+
+
+ /* -----------------------------------------------------
+ * void platform_mem_init(void);
+ *
+ * We don't need to carry out any memory initialization
+ * on CSS platforms. The Secure RAM is accessible straight away.
+ * -----------------------------------------------------
+ */
+func platform_mem_init
+ /*TBD-STINGRAY*/
+ ret
+endfunc platform_mem_init
+
+ /* -----------------------------------------------------
+ * Placeholder function which should be redefined by
+ * each platform.
+ * -----------------------------------------------------
+ */
+func platform_check_mpidr
+ /*TBD-STINGRAY*/
+ mov x0, xzr
+ ret
+endfunc platform_check_mpidr
+
+ /* ---------------------------------------------
+ * 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, BRCM_CRASH_CONSOLE_BASE
+ mov_imm x1, BRCM_CRASH_CONSOLE_REFCLK
+ mov_imm x2, BRCM_CRASH_CONSOLE_BAUDRATE
+ b console_16550_core_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, x3
+ * ---------------------------------------------
+ */
+
+func plat_crash_console_putc
+ mov_imm x1, BRCM_CRASH_CONSOLE_BASE
+ b console_16550_core_putc
+ ret
+endfunc plat_crash_console_putc
+
+ /* ---------------------------------------------
+ * void plat_crash_console_flush(void)
+ * Function to flush crash console
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func plat_crash_console_flush
+ mov_imm x0, BRCM_CRASH_CONSOLE_BASE
+ b console_16550_core_flush
+ ret
+endfunc plat_crash_console_flush
+
+ /* -----------------------------------------------------
+ * Placeholder function which should be redefined by
+ * each platform. This function is allowed to use
+ * registers x0 - x17.
+ * -----------------------------------------------------
+ */
+
+func plat_disable_acp
+ /*TBD-STINGRAY*/
+ ret
+endfunc plat_disable_acp
+
+ /* -----------------------------------------------------
+ * unsigned int plat_is_my_cpu_primary (void);
+ *
+ * Find out whether the current cpu is the primary
+ * cpu (applicable only after a cold boot)
+ * -----------------------------------------------------
+ */
+func plat_is_my_cpu_primary
+ mrs x0, mpidr_el1
+ b platform_is_primary_cpu
+endfunc plat_is_my_cpu_primary
+
+ /* -----------------------------------------------------
+ * unsigned int plat_my_core_pos(void)
+ * This function uses the plat_brcm_calc_core_pos()
+ * definition to get the index of the calling CPU.
+ * -----------------------------------------------------
+ */
+func plat_my_core_pos
+ mrs x0, mpidr_el1
+ b plat_brcm_calc_core_pos
+endfunc plat_my_core_pos
+
+ /* -----------------------------------------------------
+ * unsigned int platform_is_primary_cpu (void);
+ *
+ * Find out whether the current cpu is the primary
+ * cpu (applicable only after a cold boot)
+ * -----------------------------------------------------
+ */
+func platform_is_primary_cpu
+ mov x9, x30
+ bl plat_my_core_pos
+ cmp x0, #PRIMARY_CPU
+ cset x0, eq
+ ret x9
+endfunc platform_is_primary_cpu
+
+ /* -----------------------------------------------------
+ * unsigned int plat_brcm_calc_core_pos(uint64_t mpidr)
+ * Helper function to calculate the core position.
+ * With this function: CorePos = (ClusterId * 4) +
+ * CoreId
+ * -----------------------------------------------------
+ */
+func plat_brcm_calc_core_pos
+ and x1, x0, #MPIDR_CPU_MASK
+ and x0, x0, #MPIDR_CLUSTER_MASK
+ add x0, x1, x0, LSR #7
+ ret
+endfunc plat_brcm_calc_core_pos
+
+func plat_get_my_entrypoint
+ mrs x0, mpidr_el1
+ b platform_get_entrypoint
+endfunc plat_get_my_entrypoint
diff --git a/plat/brcm/board/stingray/bcm958742t-ns3.mk b/plat/brcm/board/stingray/bcm958742t-ns3.mk
new file mode 100644
index 0000000..5164eeb
--- /dev/null
+++ b/plat/brcm/board/stingray/bcm958742t-ns3.mk
@@ -0,0 +1,22 @@
+#
+# Copyright (c) 2015 - 2020, Broadcom
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+#######################################################
+# Board config file for bcm958742t-ns3 Stingray SST100-NS3
+#######################################################
+
+include plat/brcm/board/stingray/bcm958742t.mk
+
+# Load BL33 at 0xFF00_0000 address
+ifneq (${BL33_OVERRIDE_LOAD_ADDR},)
+$(eval $(call add_define_val,BL33_OVERRIDE_LOAD_ADDR,0xFF000000))
+endif
+
+# Nitro DDR secure memory
+# Nitro FW and config 0x8AE00000 - 0x8B000000
+# Nitro Crash dump 0x8B000000 - 0x8D000000
+DDR_NITRO_SECURE_REGION_START := 0x8AE00000
+DDR_NITRO_SECURE_REGION_END := 0x8D000000
diff --git a/plat/brcm/board/stingray/bcm958742t.mk b/plat/brcm/board/stingray/bcm958742t.mk
new file mode 100644
index 0000000..5e164b8
--- /dev/null
+++ b/plat/brcm/board/stingray/bcm958742t.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2015 - 2020, Broadcom
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+#######################################################
+# Board config file for bcm958742t Stingray SST100
+#######################################################
+BOARD_FAMILY := "<bcm958742t.h>"
+$(eval $(call add_define,BOARD_FAMILY))
+
+# Board has internal programmable regulator
+IHOST_REG_TYPE := IHOST_REG_INTEGRATED
+$(eval $(call add_define,IHOST_REG_TYPE))
+
+# Board has internal programmable regulator
+VDDC_REG_TYPE := VDDC_REG_INTEGRATED
+$(eval $(call add_define,VDDC_REG_TYPE))
diff --git a/plat/brcm/board/stingray/driver/ddr/soc/include/board_family.h b/plat/brcm/board/stingray/driver/ddr/soc/include/board_family.h
new file mode 100644
index 0000000..b2427cf
--- /dev/null
+++ b/plat/brcm/board/stingray/driver/ddr/soc/include/board_family.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BOARD_FAMILY_H
+#define BOARD_FAMILY_H
+
+#if defined(DRIVER_SPD_ENABLE) && !defined(DRIVER_SPD_SPOOF)
+#include <spd.h>
+#endif
+
+#ifdef USE_GPIO
+/* max number of supported GPIOs to construct the bitmap for board detection */
+#define MAX_NR_GPIOS 4
+
+/* max GPIO bitmap value */
+#define MAX_GPIO_BITMAP_VAL (BIT(MAX_NR_GPIOS) - 1)
+#endif
+
+struct mcb_ref_group {
+ uint32_t mcb_ref;
+ unsigned int *mcb_cfg;
+};
+
+#define MCB_REF_GROUP(ref) \
+{ \
+ .mcb_ref = 0x ## ref, \
+ .mcb_cfg = mcb_ ## ref, \
+}
+
+#endif
diff --git a/plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.c b/plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.c
new file mode 100644
index 0000000..74d2077
--- /dev/null
+++ b/plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2016-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+static void brcm_stingray_pnor_pinmux_init(void)
+{
+ unsigned int i;
+
+ INFO(" - pnor pinmux init start.\n");
+
+ /* Set PNOR_ADV_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2dc),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_BAA_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2e0),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_BLS_0_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2e4),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_BLS_1_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2e8),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_CRE_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2ec),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_CS_2_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2f0),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_CS_1_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2f4),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_CS_0_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2f8),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_WE_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2fc),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_OE_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x300),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_INTR_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x304),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_DAT_x_MODE_SEL_CONTROL.fsel = 0x2 */
+ for (i = 0; i < 0x40; i += 0x4) {
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x308 + i),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+ }
+
+ /* Set NAND_CE1_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x348),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set NAND_CE0_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x34c),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set NAND_WE_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x350),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set NAND_WP_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x354),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set NAND_RE_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x358),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set NAND_RDY_BSY_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x35c),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set NAND_IOx_0_MODE_SEL_CONTROL.fsel = 0x2 */
+ for (i = 0; i < 0x40; i += 0x4) {
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x360 + i),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+ }
+
+ /* Set NAND_ALE_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x3a0),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set NAND_CLE_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x3a4),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x40), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x44), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x48), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x4c), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x50), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x54), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x58), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x5c), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x60), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x64), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x68), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x6c), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x70), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x74), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x78), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x7c), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x80), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x84), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x88), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x8c), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x90), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x94), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x98), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x9c), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0xa0), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0xa4), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0xa8), (7 << 1), 0x8);
+
+ INFO(" - pnor pinmux init done.\n");
+}
+
+#if BL2_TEST_EXT_SRAM
+#define SRAM_CHECKS_GRANUL 0x100000
+#define SRAM_CHECKS_CNT 8
+static unsigned int sram_checks[SRAM_CHECKS_CNT] = {
+ /* offset, magic */
+ 0xd00dfeed,
+ 0xfadebabe,
+ 0xc001d00d,
+ 0xa5a5b5b5,
+ 0x5a5a5b5b,
+ 0xc5c5d5d5,
+ 0x5c5c5d5d,
+ 0xe5e5f5f5,
+};
+#endif
+
+static void brcm_stingray_pnor_sram_init(void)
+{
+ unsigned int val, tmp;
+#if BL2_TEST_EXT_SRAM
+ unsigned int off, i;
+#endif
+ INFO(" - pnor sram init start.\n");
+
+ /* Enable PNOR Clock */
+ INFO(" -- enable pnor clock\n");
+ mmio_write_32((uintptr_t)(PNOR_IDM_IO_CONTROL_DIRECT), 0x1);
+ udelay(500);
+
+ /* Reset PNOR */
+ INFO(" -- reset pnor\n");
+ mmio_setbits_32((uintptr_t)(PNOR_IDM_IO_RESET_CONTROL), 0x1);
+ udelay(500);
+ mmio_clrbits_32((uintptr_t)(PNOR_IDM_IO_RESET_CONTROL), 0x1);
+ udelay(500);
+
+ /* Configure slave address to chip-select mapping */
+ INFO(" -- configure pnor slave address to chip-select mapping\n");
+ /* 0x74000000-0x75ffffff => CS0 (32MB) */
+ val = (0xfe << PNOR_ICFG_CS_x_MASK0_SHIFT);
+ val |= (0x74);
+ mmio_write_32((uintptr_t)(PNOR_ICFG_CS_0), val);
+ /* 0x76000000-0x77ffffff => CS1 (32MB) */
+ val = (0xfe << PNOR_ICFG_CS_x_MASK0_SHIFT);
+ val |= (0x76);
+ mmio_write_32((uintptr_t)(PNOR_ICFG_CS_1), val);
+ /* 0xffffffff-0xffffffff => CS2 (0MB) */
+ val = (0x00 << PNOR_ICFG_CS_x_MASK0_SHIFT);
+ val |= (0xff);
+ mmio_write_32((uintptr_t)(PNOR_ICFG_CS_2), val);
+
+ /* Print PNOR ID */
+ tmp = 0x0;
+ val = mmio_read_32((uintptr_t)(PNOR_REG_PERIPH_ID0));
+ tmp |= (val & PNOR_REG_PERIPH_IDx_MASK);
+ val = mmio_read_32((uintptr_t)(PNOR_REG_PERIPH_ID1));
+ tmp |= ((val & PNOR_REG_PERIPH_IDx_MASK) << 8);
+ val = mmio_read_32((uintptr_t)(PNOR_REG_PERIPH_ID2));
+ tmp |= ((val & PNOR_REG_PERIPH_IDx_MASK) << 16);
+ val = mmio_read_32((uintptr_t)(PNOR_REG_PERIPH_ID3));
+ tmp |= ((val & PNOR_REG_PERIPH_IDx_MASK) << 24);
+ INFO(" -- pnor primecell_id = 0x%x\n", tmp);
+
+ /* PNOR set_cycles */
+#ifdef EMULATION_SETUP
+ val = 0x00129A44;
+#else
+ val = 0x00125954; /* 0x00002DEF; */
+#endif
+ mmio_write_32((uintptr_t)(PNOR_REG_SET_CYCLES), val);
+ INFO(" -- pnor set_cycles = 0x%x\n", val);
+
+ /* PNOR set_opmode */
+ val = 0x0;
+#ifdef EMULATION_SETUP
+ /* TODO: Final values to be provided by DV folks */
+ val &= ~(0x7 << 7); /* set_wr_bl */
+ val &= ~(0x7 << 3); /* set_rd_bl */
+ val &= ~(0x3);
+ val |= (0x1); /* set_mw */
+#else
+ /* TODO: Final values to be provided by DV folks */
+ val &= ~(0x7 << 7); /* set_wr_bl */
+ val &= ~(0x7 << 3); /* set_rd_bl */
+ val &= ~(0x3);
+ val |= (0x1); /* set_mw */
+#endif
+ mmio_write_32((uintptr_t)(PNOR_REG_SET_OPMODE), val);
+ INFO(" -- pnor set_opmode = 0x%x\n", val);
+
+#ifndef EMULATION_SETUP
+ /* Actual SRAM chip will require self-refresh */
+ val = 0x1;
+ mmio_write_32((uintptr_t)(PNOR_REG_REFRESH_0), val);
+ INFO(" -- pnor refresh_0 = 0x%x\n", val);
+#endif
+
+#if BL2_TEST_EXT_SRAM
+ /* Check PNOR SRAM access */
+ for (off = 0; off < NOR_SIZE; off += SRAM_CHECKS_GRANUL) {
+ i = (off / SRAM_CHECKS_GRANUL) % SRAM_CHECKS_CNT;
+ val = sram_checks[i];
+ INFO(" -- pnor sram write addr=0x%lx value=0x%lx\n",
+ (unsigned long)(NOR_BASE_ADDR + off),
+ (unsigned long)val);
+ mmio_write_32((uintptr_t)(NOR_BASE_ADDR + off), val);
+ }
+ tmp = 0;
+ for (off = 0; off < NOR_SIZE; off += SRAM_CHECKS_GRANUL) {
+ i = (off / SRAM_CHECKS_GRANUL) % SRAM_CHECKS_CNT;
+ val = mmio_read_32((uintptr_t)(NOR_BASE_ADDR + off));
+ INFO(" -- pnor sram read addr=0x%lx value=0x%lx\n",
+ (unsigned long)(NOR_BASE_ADDR + off),
+ (unsigned long)val);
+ if (val == sram_checks[i])
+ tmp++;
+ }
+ INFO(" -- pnor sram checks pass=%d total=%d\n",
+ tmp, (NOR_SIZE / SRAM_CHECKS_GRANUL));
+
+ if (tmp != (NOR_SIZE / SRAM_CHECKS_GRANUL)) {
+ INFO(" - pnor sram init failed.\n");
+ while (1)
+ ;
+ } else {
+ INFO(" - pnor sram init done.\n");
+ }
+#endif
+}
+
+void ext_sram_init(void)
+{
+ INFO("%s start.\n", __func__);
+
+ brcm_stingray_pnor_pinmux_init();
+
+ brcm_stingray_pnor_sram_init();
+
+ INFO("%s done.\n", __func__);
+}
diff --git a/plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.h b/plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.h
new file mode 100644
index 0000000..8508653
--- /dev/null
+++ b/plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.h
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2016-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EXT_SRAM_INIT_H
+#define EXT_SRAM_INIT_H
+
+void ext_sram_init(void);
+#endif
diff --git a/plat/brcm/board/stingray/driver/ihost_pll_config.c b/plat/brcm/board/stingray/driver/ihost_pll_config.c
new file mode 100644
index 0000000..1184928
--- /dev/null
+++ b/plat/brcm/board/stingray/driver/ihost_pll_config.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2016-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <dmu.h>
+
+#define IHOST0_CONFIG_ROOT 0x66000000
+#define IHOST1_CONFIG_ROOT 0x66002000
+#define IHOST2_CONFIG_ROOT 0x66004000
+#define IHOST3_CONFIG_ROOT 0x66006000
+#define A72_CRM_PLL_PWR_ON 0x00000070
+#define A72_CRM_PLL_PWR_ON__PLL0_RESETB_R 4
+#define A72_CRM_PLL_PWR_ON__PLL0_POST_RESETB_R 5
+#define A72_CRM_PLL_CHNL_BYPS_EN 0x000000ac
+#define A72_CRM_PLL_CHNL_BYPS_EN__PLL_0_CHNL_0_BYPS_EN_R 0
+#define A72_CRM_PLL_CHNL_BYPS_EN_DATAMASK 0x0000ec1f
+#define A72_CRM_PLL_CMD 0x00000080
+#define A72_CRM_PLL_CMD__UPDATE_PLL0_FREQUENCY_VCO_R 0
+#define A72_CRM_PLL_CMD__UPDATE_PLL0_FREQUENCY_POST_R 1
+#define A72_CRM_PLL_STATUS 0x00000084
+#define A72_CRM_PLL_STATUS__PLL0_LOCK_R 9
+#define A72_CRM_PLL0_CTRL1 0x00000100
+#define A72_CRM_PLL0_CTRL2 0x00000104
+#define A72_CRM_PLL0_CTRL3 0x00000108
+#define A72_CRM_PLL0_CTRL3__PLL0_PDIV_R 12
+#define A72_CRM_PLL0_CTRL4 0x0000010c
+#define A72_CRM_PLL0_CTRL4__PLL0_KP_R 0
+#define A72_CRM_PLL0_CTRL4__PLL0_KI_R 4
+#define A72_CRM_PLL0_CTRL4__PLL0_KA_R 7
+#define A72_CRM_PLL0_CTRL4__PLL0_FREFEFF_INFO_R 10
+
+#define PLL_MODE_VCO 0x0
+#define PLL_MODE_BYPASS 0x1
+#define PLL_RESET_TYPE_PLL 0x1
+#define PLL_RESET_TYPE_POST 0x2
+#define PLL_VCO 0x1
+#define PLL_POSTDIV 0x2
+#define ARM_FREQ_3G PLL_FREQ_FULL
+#define ARM_FREQ_1P5G PLL_FREQ_HALF
+#define ARM_FREQ_750M PLL_FREQ_QRTR
+
+static unsigned int ARMCOE_crm_getBaseAddress(unsigned int cluster_num)
+{
+ unsigned int ihostx_config_root;
+
+ switch (cluster_num) {
+ case 0:
+ default:
+ ihostx_config_root = IHOST0_CONFIG_ROOT;
+ break;
+ case 1:
+ ihostx_config_root = IHOST1_CONFIG_ROOT;
+ break;
+ case 2:
+ ihostx_config_root = IHOST2_CONFIG_ROOT;
+ break;
+ case 3:
+ ihostx_config_root = IHOST3_CONFIG_ROOT;
+ break;
+ }
+
+ return ihostx_config_root;
+}
+
+static void ARMCOE_crm_pllAssertReset(unsigned int cluster_num,
+ unsigned int reset_type)
+{
+ unsigned long ihostx_config_root;
+ unsigned int pll_rst_ctrl;
+
+ ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num);
+ pll_rst_ctrl = mmio_read_32(ihostx_config_root + A72_CRM_PLL_PWR_ON);
+
+ // PLL reset
+ if (reset_type & PLL_RESET_TYPE_PLL) {
+ pll_rst_ctrl &= ~(0x1<<A72_CRM_PLL_PWR_ON__PLL0_RESETB_R);
+ }
+ // post-div channel reset
+ if (reset_type & PLL_RESET_TYPE_POST) {
+ pll_rst_ctrl &= ~(0x1<<A72_CRM_PLL_PWR_ON__PLL0_POST_RESETB_R);
+ }
+
+ mmio_write_32(ihostx_config_root + A72_CRM_PLL_PWR_ON, pll_rst_ctrl);
+}
+
+static void ARMCOE_crm_pllSetMode(unsigned int cluster_num, unsigned int mode)
+{
+ unsigned long ihostx_config_root;
+ unsigned int pll_byp_ctrl;
+
+ ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num);
+ pll_byp_ctrl = mmio_read_32(ihostx_config_root +
+ A72_CRM_PLL_CHNL_BYPS_EN);
+
+ if (mode == PLL_MODE_VCO) {
+ // use PLL DCO output
+ pll_byp_ctrl &=
+ ~BIT(A72_CRM_PLL_CHNL_BYPS_EN__PLL_0_CHNL_0_BYPS_EN_R);
+ } else {
+ // use PLL bypass sources
+ pll_byp_ctrl |=
+ BIT(A72_CRM_PLL_CHNL_BYPS_EN__PLL_0_CHNL_0_BYPS_EN_R);
+ }
+
+ mmio_write_32(ihostx_config_root + A72_CRM_PLL_CHNL_BYPS_EN,
+ pll_byp_ctrl);
+}
+
+static void ARMCOE_crm_pllFreqSet(unsigned int cluster_num,
+ unsigned int ihost_pll_freq_sel,
+ unsigned int pdiv)
+{
+ unsigned int ndiv_int;
+ unsigned int ndiv_frac_low, ndiv_frac_high;
+ unsigned long ihostx_config_root;
+
+ ndiv_frac_low = 0x0;
+ ndiv_frac_high = 0x0;
+
+ if (ihost_pll_freq_sel == ARM_FREQ_3G) {
+ ndiv_int = 0x78;
+ } else if (ihost_pll_freq_sel == ARM_FREQ_1P5G) {
+ ndiv_int = 0x3c;
+ } else if (ihost_pll_freq_sel == ARM_FREQ_750M) {
+ ndiv_int = 0x1e;
+ } else {
+ return;
+ }
+
+ ndiv_int &= 0x3FF; // low 10 bits
+ ndiv_frac_low &= 0x3FF;
+ ndiv_frac_high &= 0x3FF;
+
+ ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num);
+
+ mmio_write_32(ihostx_config_root+A72_CRM_PLL0_CTRL1, ndiv_frac_low);
+ mmio_write_32(ihostx_config_root+A72_CRM_PLL0_CTRL2, ndiv_frac_high);
+ mmio_write_32(ihostx_config_root+A72_CRM_PLL0_CTRL3,
+ ndiv_int |
+ ((pdiv << A72_CRM_PLL0_CTRL3__PLL0_PDIV_R & 0xF000)));
+
+ mmio_write_32(ihostx_config_root + A72_CRM_PLL0_CTRL4,
+ /* From Section 10 of PLL spec */
+ (3 << A72_CRM_PLL0_CTRL4__PLL0_KP_R) |
+ /* From Section 10 of PLL spec */
+ (2 << A72_CRM_PLL0_CTRL4__PLL0_KI_R) |
+ /* Normal mode (i.e. not fast-locking) */
+ (0 << A72_CRM_PLL0_CTRL4__PLL0_KA_R) |
+ /* 50 MHz */
+ (50 << A72_CRM_PLL0_CTRL4__PLL0_FREFEFF_INFO_R));
+}
+
+static void ARMCOE_crm_pllDeassertReset(unsigned int cluster_num,
+ unsigned int reset_type)
+{
+ unsigned long ihostx_config_root;
+ unsigned int pll_rst_ctrl;
+
+ ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num);
+ pll_rst_ctrl = mmio_read_32(ihostx_config_root + A72_CRM_PLL_PWR_ON);
+
+ // PLL reset
+ if (reset_type & PLL_RESET_TYPE_PLL) {
+ pll_rst_ctrl |= (0x1 << A72_CRM_PLL_PWR_ON__PLL0_RESETB_R);
+ }
+
+ // post-div channel reset
+ if (reset_type & PLL_RESET_TYPE_POST) {
+ pll_rst_ctrl |= (0x1 << A72_CRM_PLL_PWR_ON__PLL0_POST_RESETB_R);
+ }
+
+ mmio_write_32(ihostx_config_root + A72_CRM_PLL_PWR_ON, pll_rst_ctrl);
+}
+
+static void ARMCOE_crm_pllUpdate(unsigned int cluster_num, unsigned int type)
+{
+ unsigned long ihostx_config_root;
+ unsigned int pll_cmd;
+
+ ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num);
+ pll_cmd = mmio_read_32(ihostx_config_root + A72_CRM_PLL_CMD);
+
+ // VCO update
+ if (type & PLL_VCO) {
+ pll_cmd |= BIT(A72_CRM_PLL_CMD__UPDATE_PLL0_FREQUENCY_VCO_R);
+ }
+ // post-div channel update
+ if (type & PLL_POSTDIV) {
+ pll_cmd |= BIT(A72_CRM_PLL_CMD__UPDATE_PLL0_FREQUENCY_POST_R);
+ }
+
+ mmio_write_32(ihostx_config_root+A72_CRM_PLL_CMD, pll_cmd);
+}
+
+static void insert_delay(unsigned int delay)
+{
+ volatile unsigned int index;
+
+ for (index = 0; index < delay; index++)
+ ;
+}
+
+
+/*
+ * Returns 1 if PLL locked within certain interval
+ */
+static unsigned int ARMCOE_crm_pllIsLocked(unsigned int cluster_num)
+{
+ unsigned long ihostx_config_root;
+ unsigned int lock_status;
+ unsigned int i;
+
+ ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num);
+
+ /* wait a while for pll to lock before returning from this function */
+ for (i = 0; i < 1500; i++) {
+ insert_delay(256);
+ lock_status = mmio_read_32(ihostx_config_root +
+ A72_CRM_PLL_STATUS);
+ if (lock_status & BIT(A72_CRM_PLL_STATUS__PLL0_LOCK_R))
+ return 1;
+ }
+
+ ERROR("PLL of Cluster #%u failed to lock\n", cluster_num);
+ return 0;
+}
+
+/*
+ * ihost PLL Variable Frequency Configuration
+ *
+ * Frequency Limit {VCO,ARM} (GHz):
+ * 0 - no limit,
+ * 1 - {3.0,1.5},
+ * 2 - {4.0,2.0},
+ * 3 - {5.0,2.5}
+ */
+uint32_t bcm_set_ihost_pll_freq(uint32_t cluster_num, int ihost_pll_freq_sel)
+{
+ NOTICE("cluster: %u, freq_sel:0x%x\n", cluster_num, ihost_pll_freq_sel);
+
+ //bypass PLL
+ ARMCOE_crm_pllSetMode(cluster_num, PLL_MODE_BYPASS);
+ //assert reset
+ ARMCOE_crm_pllAssertReset(cluster_num,
+ PLL_RESET_TYPE_PLL | PLL_RESET_TYPE_POST);
+ //set ndiv_int for different freq
+ ARMCOE_crm_pllFreqSet(cluster_num, ihost_pll_freq_sel, 0x1);
+ //de-assert reset
+ ARMCOE_crm_pllDeassertReset(cluster_num, PLL_RESET_TYPE_PLL);
+ ARMCOE_crm_pllUpdate(cluster_num, PLL_VCO);
+ //waiting for PLL lock
+ ARMCOE_crm_pllIsLocked(cluster_num);
+ ARMCOE_crm_pllDeassertReset(cluster_num, PLL_RESET_TYPE_POST);
+ //disable bypass PLL
+ ARMCOE_crm_pllSetMode(cluster_num, PLL_MODE_VCO);
+
+ return 0;
+}
+
+uint32_t bcm_get_ihost_pll_freq(uint32_t cluster_num)
+{
+ unsigned long ihostx_config_root;
+ uint32_t ndiv_int;
+ uint32_t ihost_pll_freq_sel;
+
+ ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num);
+ ndiv_int = mmio_read_32(ihostx_config_root+A72_CRM_PLL0_CTRL3) & 0x3FF;
+
+ if (ndiv_int == 0x78) {
+ ihost_pll_freq_sel = ARM_FREQ_3G;
+ } else if (ndiv_int == 0x3c) {
+ ihost_pll_freq_sel = ARM_FREQ_1P5G;
+ } else if (ndiv_int == 0x1e) {
+ ihost_pll_freq_sel = ARM_FREQ_750M;
+ } else {
+ /* return unlimit otherwise*/
+ ihost_pll_freq_sel = 0;
+ }
+ return ihost_pll_freq_sel;
+}
diff --git a/plat/brcm/board/stingray/driver/plat_emmc.c b/plat/brcm/board/stingray/driver/plat_emmc.c
new file mode 100644
index 0000000..82085e1
--- /dev/null
+++ b/plat/brcm/board/stingray/driver/plat_emmc.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+#define ICFG_IPROC_IOPAD_CTRL_4 (IPROC_ROOT + 0x9c0)
+#define ICFG_IPROC_IOPAD_CTRL_5 (IPROC_ROOT + 0x9c4)
+#define ICFG_IPROC_IOPAD_CTRL_6 (IPROC_ROOT + 0x9c8)
+#define ICFG_IPROC_IOPAD_CTRL_7 (IPROC_ROOT + 0x9cc)
+
+#define IOPAD_CTRL4_SDIO0_CD_IND_R 30
+#define IOPAD_CTRL4_SDIO0_CD_SRC_R 31
+#define IOPAD_CTRL4_SDIO0_CD_HYS_R 29
+#define IOPAD_CTRL4_SDIO0_CD_PULL_R 28
+#define IOPAD_CTRL4_SDIO0_CD_DRIVE_R 24
+#define IOPAD_CTRL4_SDIO0_CLK_SDCARD_SRC_R 23
+#define IOPAD_CTRL4_SDIO0_CLK_SDCARD_HYS_R 21
+#define IOPAD_CTRL4_SDIO0_CLK_SDCARD_DRIVE_R 17
+
+#define IOPAD_CTRL4_SDIO0_DATA0_SRC_R 15
+#define IOPAD_CTRL4_SDIO0_DATA0_HYS_R 13
+#define IOPAD_CTRL4_SDIO0_DATA0_DRIVE_R 9
+#define IOPAD_CTRL4_SDIO0_DATA1_SRC_R 7
+#define IOPAD_CTRL4_SDIO0_DATA1_HYS_R 5
+#define IOPAD_CTRL4_SDIO0_DATA1_DRIVE_R 1
+
+#define IOPAD_CTRL5_SDIO0_DATA2_SRC_R 31
+#define IOPAD_CTRL5_SDIO0_DATA2_HYS_R 29
+#define IOPAD_CTRL5_SDIO0_DATA2_DRIVE_R 25
+#define IOPAD_CTRL5_SDIO0_DATA3_SRC_R 23
+#define IOPAD_CTRL5_SDIO0_DATA3_IND_R 22
+#define IOPAD_CTRL5_SDIO0_DATA3_HYS_R 21
+#define IOPAD_CTRL5_SDIO0_DATA3_DRIVE_R 17
+#define IOPAD_CTRL5_SDIO0_DATA4_SRC_R 15
+#define IOPAD_CTRL5_SDIO0_DATA4_HYS_R 13
+#define IOPAD_CTRL5_SDIO0_DATA4_DRIVE_R 9
+#define IOPAD_CTRL5_SDIO0_DATA5_SRC_R 7
+#define IOPAD_CTRL5_SDIO0_DATA5_HYS_R 5
+#define IOPAD_CTRL5_SDIO0_DATA5_DRIVE_R 1
+
+#define IOPAD_CTRL6_SDIO0_DATA6_SRC_R 31
+#define IOPAD_CTRL6_SDIO0_DATA6_HYS_R 29
+#define IOPAD_CTRL6_SDIO0_DATA6_DRIVE_R 25
+#define IOPAD_CTRL6_SDIO0_DATA7_SRC_R 23
+#define IOPAD_CTRL6_SDIO0_DATA7_HYS_R 21
+#define IOPAD_CTRL6_SDIO0_DATA7_DRIVE_R 17
+
+void emmc_soft_reset(void)
+{
+ uint32_t val = 0;
+
+ val = (BIT(IOPAD_CTRL6_SDIO0_DATA7_SRC_R) |
+ BIT(IOPAD_CTRL6_SDIO0_DATA7_HYS_R) |
+ BIT(IOPAD_CTRL6_SDIO0_DATA7_DRIVE_R) |
+ BIT(IOPAD_CTRL6_SDIO0_DATA6_SRC_R) |
+ BIT(IOPAD_CTRL6_SDIO0_DATA6_HYS_R) |
+ BIT(IOPAD_CTRL6_SDIO0_DATA6_DRIVE_R));
+
+ mmio_write_32(ICFG_IPROC_IOPAD_CTRL_6, val);
+
+ val = (BIT(IOPAD_CTRL5_SDIO0_DATA3_SRC_R) |
+ BIT(IOPAD_CTRL5_SDIO0_DATA3_HYS_R) |
+ BIT(IOPAD_CTRL5_SDIO0_DATA3_DRIVE_R) |
+ BIT(IOPAD_CTRL5_SDIO0_DATA4_SRC_R) |
+ BIT(IOPAD_CTRL5_SDIO0_DATA4_HYS_R) |
+ BIT(IOPAD_CTRL5_SDIO0_DATA4_DRIVE_R) |
+ BIT(IOPAD_CTRL5_SDIO0_DATA5_SRC_R) |
+ BIT(IOPAD_CTRL5_SDIO0_DATA5_HYS_R) |
+ BIT(IOPAD_CTRL5_SDIO0_DATA5_DRIVE_R));
+
+ mmio_write_32(ICFG_IPROC_IOPAD_CTRL_5, val);
+
+ val = (BIT(IOPAD_CTRL4_SDIO0_DATA0_SRC_R) |
+ BIT(IOPAD_CTRL4_SDIO0_DATA0_HYS_R) |
+ BIT(IOPAD_CTRL4_SDIO0_DATA0_DRIVE_R) |
+ BIT(IOPAD_CTRL4_SDIO0_DATA1_SRC_R) |
+ BIT(IOPAD_CTRL4_SDIO0_DATA1_HYS_R) |
+ BIT(IOPAD_CTRL4_SDIO0_DATA1_DRIVE_R) |
+ BIT(IOPAD_CTRL5_SDIO0_DATA2_SRC_R) |
+ BIT(IOPAD_CTRL5_SDIO0_DATA2_HYS_R) |
+ BIT(IOPAD_CTRL5_SDIO0_DATA2_DRIVE_R));
+
+ mmio_write_32(ICFG_IPROC_IOPAD_CTRL_6, val);
+
+ val = (BIT(IOPAD_CTRL4_SDIO0_CLK_SDCARD_SRC_R) |
+ BIT(IOPAD_CTRL4_SDIO0_CLK_SDCARD_HYS_R) |
+ BIT(IOPAD_CTRL4_SDIO0_CLK_SDCARD_DRIVE_R) |
+ BIT(IOPAD_CTRL4_SDIO0_CD_SRC_R) |
+ BIT(IOPAD_CTRL4_SDIO0_CD_HYS_R));
+
+ /*
+ * set pull-down, clear pull-up=0
+ * bit 12: pull-down bit 11: pull-up
+ * Note: In emulation, this pull-down setting was not
+ * sufficient. Board design likely requires pull down on
+ * this pin for eMMC.
+ */
+
+ val |= BIT(IOPAD_CTRL4_SDIO0_CD_PULL_R);
+
+ mmio_write_32(ICFG_IPROC_IOPAD_CTRL_4, val);
+}
diff --git a/plat/brcm/board/stingray/driver/sr_usb.h b/plat/brcm/board/stingray/driver/sr_usb.h
new file mode 100644
index 0000000..5033683
--- /dev/null
+++ b/plat/brcm/board/stingray/driver/sr_usb.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2019 - 2021, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SR_USB_H
+#define SR_USB_H
+
+#define CDRU_PM_RESET_N_R BIT(CDRU_MISC_RESET_CONTROL__CDRU_PM_RESET_N_R)
+#define CDRU_USBSS_RESET_N BIT(CDRU_MISC_RESET_CONTROL__CDRU_USBSS_RESET_N)
+#define CDRU_MISC_CLK_USBSS \
+ BIT(CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_USBSS_CLK_EN_R)
+
+#define RESCAL_I_RSTB BIT(26)
+#define RESCAL_I_PWRDNB BIT(27)
+
+#define DRDU3_U3PHY_CTRL 0x68500014
+#define PHY_RESET BIT(1)
+#define POR_RESET BIT(28)
+#define MDIO_RESET BIT(29)
+
+#define DRDU3_PWR_CTRL 0x6850002c
+#define POWER_CTRL_OVRD BIT(2)
+
+#define USB3H_U3PHY_CTRL 0x68510014
+#define USB3H_U3SOFT_RST_N BIT(30)
+
+#define USB3H_PWR_CTRL 0x68510028
+
+#define USB3_PHY_MDIO_BLOCK_BASE_REG 0x1f
+#define BDC_AXI_SOFT_RST_N_OFFSET 0
+#define XHC_AXI_SOFT_RST_N_OFFSET 1
+#define MDIO_BUS_ID 3
+#define USB3H_PHY_ID 5
+#define USB3DRD_PHY_ID 2
+
+#define USB3_PHY_RXPMD_BLOCK_BASE 0x8020
+#define USB3_PHY_RXPMD_REG1 0x1
+#define USB3_PHY_RXPMD_REG2 0x2
+#define USB3_PHY_RXPMD_REG5 0x5
+#define USB3_PHY_RXPMD_REG7 0x7
+
+#define USB3_PHY_TXPMD_BLOCK_BASE 0x8040
+#define USB3_PHY_TXPMD_REG1 0x1
+#define USB3_PHY_TXPMD_REG2 0x2
+
+#define USB3_PHY_ANA_BLOCK_BASE 0x8090
+#define USB3_PHY_ANA_REG0 0x0
+#define USB3_PHY_ANA_REG1 0x1
+#define USB3_PHY_ANA_REG2 0x2
+#define USB3_PHY_ANA_REG5 0x5
+#define USB3_PHY_ANA_REG8 0x8
+#define USB3_PHY_ANA_REG11 0xb
+
+#define USB3_PHY_AEQ_BLOCK_BASE 0x80e0
+#define USB3_PHY_AEQ_REG1 0x1
+#define USB3_PHY_AEQ_REG3 0x3
+
+#ifdef USB_DMA_COHERENT
+#define DRDU3_U3XHC_SOFT_RST_N BIT(31)
+#define DRDU3_U3BDC_SOFT_RST_N BIT(30)
+
+#define DRDU3_SOFT_RESET_CTRL 0x68500030
+#define DRDU3_XHC_AXI_SOFT_RST_N BIT(1)
+#define DRDU3_BDC_AXI_SOFT_RST_N BIT(0)
+
+#define DRDU2_PHY_CTRL 0x6852000c
+#define DRDU2_U2SOFT_RST_N BIT(29)
+
+#define USB3H_SOFT_RESET_CTRL 0x6851002c
+#define USB3H_XHC_AXI_SOFT_RST_N BIT(1)
+
+#define DRDU2_SOFT_RESET_CTRL 0x68520020
+#define DRDU2_BDC_AXI_SOFT_RST_N BIT(0)
+
+#define DRD2U3H_XHC_REGS_AXIWRA 0x68511c08
+#define DRD2U3H_XHC_REGS_AXIRDA 0x68511c0c
+#define DRDU2D_BDC_REGS_AXIWRA 0x68521c08
+#define DRDU2D_BDC_REGS_AXIRDA 0x68521c0c
+#define DRDU3H_XHC_REGS_AXIWRA 0x68501c08
+#define DRDU3H_XHC_REGS_AXIRDA 0x68501c0c
+#define DRDU3D_BDC_REGS_AXIWRA 0x68502c08
+#define DRDU3D_BDC_REGS_AXIRDA 0x68502c0c
+/* cacheable write-back, allocate on both reads and writes */
+#define USBAXI_AWCACHE 0xf
+#define USBAXI_ARCACHE 0xf
+/* non-secure */
+#define USBAXI_AWPROT 0x8
+#define USBAXI_ARPROT 0x8
+#define USBAXIWR_SA_VAL ((USBAXI_AWCACHE << 4 | USBAXI_AWPROT) << 0)
+#define USBAXIWR_SA_MASK ((0xf << 4 | 0xf) << 0)
+#define USBAXIWR_UA_VAL ((USBAXI_AWCACHE << 4 | USBAXI_AWPROT) << 16)
+#define USBAXIWR_UA_MASK ((0xf << 4 | 0xf) << 0)
+#define USBAXIRD_SA_VAL ((USBAXI_ARCACHE << 4 | USBAXI_ARPROT) << 0)
+#define USBAXIRD_SA_MASK ((0xf << 4 | 0xf) << 0)
+#define USBAXIRD_UA_VAL ((USBAXI_ARCACHE << 4 | USBAXI_ARPROT) << 16)
+#define USBAXIRD_UA_MASK ((0xf << 4 | 0xf) << 0)
+#endif /* USB_DMA_COHERENT */
+
+#define ICFG_DRDU3_SID_CTRL 0x6850001c
+#define ICFG_USB3H_SID_CTRL 0x6851001c
+#define ICFG_DRDU2_SID_CTRL 0x68520010
+#define ICFG_USB_SID_SHIFT 5
+#define ICFG_USB_SID_AWADDR_OFFSET 0x0
+#define ICFG_USB_SID_ARADDR_OFFSET 0x4
+
+#define USBIC_GPV_BASE 0x68600000
+#define USBIC_GPV_SECURITY0 (USBIC_GPV_BASE + 0x8)
+#define USBIC_GPV_SECURITY0_FIELD BIT(0)
+#define USBIC_GPV_SECURITY1 (USBIC_GPV_BASE + 0xc)
+#define USBIC_GPV_SECURITY1_FIELD (BIT(0) | BIT(1))
+#define USBIC_GPV_SECURITY2 (USBIC_GPV_BASE + 0x10)
+#define USBIC_GPV_SECURITY2_FIELD (BIT(0) | BIT(1))
+#define USBIC_GPV_SECURITY4 (USBIC_GPV_BASE + 0x18)
+#define USBIC_GPV_SECURITY4_FIELD BIT(0)
+#define USBIC_GPV_SECURITY10 (USBIC_GPV_BASE + 0x30)
+#define USBIC_GPV_SECURITY10_FIELD (0x7 << 0)
+
+#define USBSS_TZPCDECPROT_BASE 0x68540800
+#define USBSS_TZPCDECPROT0set (USBSS_TZPCDECPROT_BASE + 0x4)
+#define USBSS_TZPCDECPROT0clr (USBSS_TZPCDECPROT_BASE + 0x8)
+#define DECPROT0_USBSS_DRD2U3H BIT(3)
+#define DECPROT0_USBSS_DRDU2H BIT(2)
+#define DECPROT0_USBSS_DRDU3D BIT(1)
+#define DECPROT0_USBSS_DRDU2D BIT(0)
+#define USBSS_TZPCDECPROT0 \
+ (DECPROT0_USBSS_DRD2U3H | \
+ DECPROT0_USBSS_DRDU2H | \
+ DECPROT0_USBSS_DRDU3D | \
+ DECPROT0_USBSS_DRDU2D)
+
+int32_t usb_device_init(unsigned int);
+
+#endif /* SR_USB_H */
diff --git a/plat/brcm/board/stingray/driver/swreg.c b/plat/brcm/board/stingray/driver/swreg.c
new file mode 100644
index 0000000..2b7c53b
--- /dev/null
+++ b/plat/brcm/board/stingray/driver/swreg.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <sr_utils.h>
+#include <swreg.h>
+
+#define MIN_VOLT 760000
+#define MAX_VOLT 1060000
+
+#define BSTI_WRITE 0x1
+#define BSTI_READ 0x2
+#define BSTI_COMMAND_TA 0x2
+#define BSTI_COMMAND_DATA 0xFF
+#define BSTI_CONTROL_VAL 0x81
+#define BSTI_CONTROL_BUSY 0x100
+#define BSTI_TOGGLE_BIT 0x2
+#define BSTI_CONFI_DONE_MASK 0xFFFFFFFD
+#define BSTI_REG_DATA_MASK 0xFFFF
+#define BSTI_CMD(sb, op, pa, ra, ta, data) \
+ ((((sb) & 0x3) << 30) | (((op) & 0x3) << 28) | \
+ (((pa) & 0x1F) << 23) | (((ra) & 0x1F) << 18) | \
+ (((ta) & 0x3) << 16) | (data))
+
+#define PHY_REG0 0x0
+#define PHY_REG1 0x1
+#define PHY_REG4 0x4
+#define PHY_REG5 0x5
+#define PHY_REG6 0x6
+#define PHY_REG7 0x7
+#define PHY_REGC 0xc
+
+#define IHOST_VDDC_DATA 0x560
+#define DDR_CORE_DATA 0x2560
+#define UPDATE_POS_EDGE(data, set) ((data) | ((set) << 1))
+
+/*
+ * Formula for SR A2 reworked board:
+ * step = ((vol/(1.4117 * 0.98)) - 500000)/3125
+ * where,
+ * vol - input voltage
+ * 500000 - Reference voltage
+ * 3125 - one step value
+ */
+#define A2_VOL_REF 500000
+#define ONE_STEP_VALUE 3125
+#define VOL_DIV(vol) (((vol*10000ull)/(14117*98ull)) * 100ull)
+#define STEP_VALUE(vol) \
+ ((((((VOL_DIV(vol)) - A2_VOL_REF) / ONE_STEP_VALUE) & 0xFF) << 8) | 4)
+
+#define B0_VOL_REF ((500000/100)*98)
+#define B0_ONE_STEP_VALUE 3125
+/*
+ * Formula for SR B0 chip for IHOST12/03 and VDDC_CORE
+ * step = ((vol/1.56) - (500000 * 0.98))/3125
+ * where,
+ * vol - input voltage
+ * 500000 - Reference voltage
+ * 3125 - one step value
+ */
+#define B0_VOL_DIV(vol) (((vol)*100ull)/156)
+#define B0_STEP_VALUE(vol) \
+ ((((((B0_VOL_DIV(vol)) - B0_VOL_REF) / B0_ONE_STEP_VALUE) \
+ & 0xFF) << 8) | 4)
+
+/*
+ * Formula for SR B0 chip for DDR-CORE
+ * step = ((vol/1) - (500000 * 0.98))/3125
+ * where,
+ * vol - input voltage
+ * 500000 - Reference voltage
+ * 3125 - one step value
+ */
+#define B0_DDR_VDDC_VOL_DIV(vol) ((vol)/1)
+#define B0_DDR_VDDC_STEP_VALUE(vol) \
+ ((((((B0_DDR_VDDC_VOL_DIV(vol)) - B0_VOL_REF) / B0_ONE_STEP_VALUE) \
+ & 0xFF) << 8) | 4)
+
+#define MAX_SWREG_CNT 8
+#define MAX_ADDR_PER_SWREG 16
+#define MAX_REG_ADDR 0xF
+#define MIN_REG_ADDR 0x0
+
+static const char *sw_reg_name[MAX_SWREG_CNT] = {
+ "DDR_VDDC",
+ "IHOST03",
+ "IHOST12",
+ "IHOST_ARRAY",
+ "DDRIO_SLAVE",
+ "VDDC_CORE",
+ "VDDC1",
+ "DDRIO_MASTER"
+};
+
+/* firmware values for all SWREG for 3.3V input operation */
+static const uint16_t swreg_fm_data_bx[MAX_SWREG_CNT][MAX_ADDR_PER_SWREG] = {
+ /* DDR logic: Power Domains independent of 12v or 3p3v */
+ {0x25E0, 0x2D54, 0x0EC6, 0x01EC, 0x28BB, 0x1144, 0x0200, 0x69C0,
+ 0x0010, 0x0EDF, 0x90D7, 0x8000, 0x820C, 0x0003, 0x0001, 0x0000},
+
+ /* ihost03, 3p3V */
+ {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
+ 0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
+
+ /* ihost12 3p3v */
+ {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
+ 0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
+
+ /* ihost array */
+ {0x25E0, 0x2D94, 0x0EC6, 0x01EC, 0x2ABB, 0x1144, 0x0340, 0x69C0,
+ 0x0010, 0x0EDF, 0x90D7, 0x8000, 0x860C, 0x0003, 0x0001, 0x0000},
+
+ /* ddr io slave : 3p3v */
+ {0x0560, 0x4438, 0x0000, 0x001F, 0x8028, 0x4444, 0x0300, 0x4380,
+ 0x003F, 0x0FFF, 0x10D7, 0x8000, 0xA70C, 0x0003, 0x0001, 0x0000},
+
+ /* core master 3p3v */
+ {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
+ 0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
+
+ /* core slave 3p3v */
+ {0x0560, 0x4438, 0x0000, 0x001F, 0x8028, 0x4444, 0x0300, 0x4380,
+ 0x003F, 0x0FFF, 0x10D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
+
+ /* ddr io master : 3p3v */
+ {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
+ 0x003F, 0x0FFF, 0x90D7, 0x8000, 0xA70C, 0x0003, 0x0001, 0x0000},
+};
+
+#define FM_DATA swreg_fm_data_bx
+
+static int swreg_poll(void)
+{
+ uint32_t data;
+ int retry = 100;
+
+ do {
+ data = mmio_read_32(BSTI_CONTROL_OFFSET);
+ if ((data & BSTI_CONTROL_BUSY) != BSTI_CONTROL_BUSY)
+ return 0;
+ retry--;
+ udelay(1);
+ } while (retry > 0);
+
+ return -ETIMEDOUT;
+}
+
+static int write_swreg_config(enum sw_reg reg_id, uint32_t addr, uint32_t data)
+{
+ uint32_t cmd;
+ int ret;
+
+ cmd = BSTI_CMD(0x1, BSTI_WRITE, reg_id, addr, BSTI_COMMAND_TA, data);
+ mmio_write_32(BSTI_CONTROL_OFFSET, BSTI_CONTROL_VAL);
+ mmio_write_32(BSTI_COMMAND_OFFSET, cmd);
+ ret = swreg_poll();
+ if (ret) {
+ ERROR("Failed to write swreg %s addr 0x%x\n",
+ sw_reg_name[reg_id-1], addr);
+ return ret;
+ }
+ return ret;
+}
+
+static int read_swreg_config(enum sw_reg reg_id, uint32_t addr, uint32_t *data)
+{
+ uint32_t cmd;
+ int ret;
+
+ cmd = BSTI_CMD(0x1, BSTI_READ, reg_id, addr, BSTI_COMMAND_TA, PHY_REG0);
+ mmio_write_32(BSTI_CONTROL_OFFSET, BSTI_CONTROL_VAL);
+ mmio_write_32(BSTI_COMMAND_OFFSET, cmd);
+ ret = swreg_poll();
+ if (ret) {
+ ERROR("Failed to read swreg %s addr 0x%x\n",
+ sw_reg_name[reg_id-1], addr);
+ return ret;
+ }
+
+ *data = mmio_read_32(BSTI_COMMAND_OFFSET);
+ *data &= BSTI_REG_DATA_MASK;
+ return ret;
+}
+
+static int swreg_config_done(enum sw_reg reg_id)
+{
+ uint32_t read_data;
+ int ret;
+
+ ret = read_swreg_config(reg_id, PHY_REG0, &read_data);
+ if (ret)
+ return ret;
+
+ read_data &= BSTI_CONFI_DONE_MASK;
+ read_data |= BSTI_TOGGLE_BIT;
+ ret = write_swreg_config(reg_id, PHY_REG0, read_data);
+ if (ret)
+ return ret;
+
+ ret = read_swreg_config(reg_id, PHY_REG0, &read_data);
+ if (ret)
+ return ret;
+
+ read_data &= BSTI_CONFI_DONE_MASK;
+ ret = write_swreg_config(reg_id, PHY_REG0, read_data);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+#ifdef DUMP_SWREG
+static void dump_swreg_firmware(void)
+{
+ enum sw_reg reg_id;
+ uint32_t data;
+ int addr;
+ int ret;
+
+ for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
+ INFO("SWREG: %s\n", sw_reg_name[reg_id - 1]);
+ for (addr = MIN_REG_ADDR; addr <= MAX_REG_ADDR; addr++) {
+ ret = read_swreg_config(reg_id, addr, &data);
+ if (ret)
+ ERROR("Failed to read offset %d\n", addr);
+ INFO("\t0x%x: 0x%04x\n", addr, data);
+ }
+ }
+}
+#endif
+
+int set_swreg(enum sw_reg reg_id, uint32_t micro_volts)
+{
+ uint32_t step, programmed_step;
+ uint32_t data = IHOST_VDDC_DATA;
+ int ret;
+
+ if ((micro_volts > MAX_VOLT) || (micro_volts < MIN_VOLT)) {
+ ERROR("input voltage out-of-range\n");
+ ret = -EINVAL;
+ goto failed;
+ }
+
+ ret = read_swreg_config(reg_id, PHY_REGC, &programmed_step);
+ if (ret)
+ goto failed;
+
+ if (reg_id == DDR_VDDC)
+ step = B0_DDR_VDDC_STEP_VALUE(micro_volts);
+ else
+ step = B0_STEP_VALUE(micro_volts);
+
+ if ((step >> 8) != (programmed_step >> 8)) {
+ ret = write_swreg_config(reg_id, PHY_REGC, step);
+ if (ret)
+ goto failed;
+
+ if (reg_id == DDR_VDDC)
+ data = DDR_CORE_DATA;
+
+ ret = write_swreg_config(reg_id, PHY_REG0,
+ UPDATE_POS_EDGE(data, 1));
+ if (ret)
+ goto failed;
+
+ ret = write_swreg_config(reg_id, PHY_REG0,
+ UPDATE_POS_EDGE(data, 0));
+ if (ret)
+ goto failed;
+ }
+
+ INFO("%s voltage updated to %duV\n", sw_reg_name[reg_id-1],
+ micro_volts);
+ return ret;
+
+failed:
+ /*
+ * Stop booting if voltages are not set
+ * correctly. Booting will fail at random point
+ * if we continue with wrong voltage settings.
+ */
+ ERROR("Failed to set %s voltage to %duV\n", sw_reg_name[reg_id-1],
+ micro_volts);
+ assert(0);
+
+ return ret;
+}
+
+/* Update SWREG firmware for all power doman for A2 chip */
+int swreg_firmware_update(void)
+{
+ enum sw_reg reg_id;
+ uint32_t data;
+ int addr;
+ int ret;
+
+ /* write firmware values */
+ for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
+ /* write higher location first */
+ for (addr = MAX_REG_ADDR; addr >= MIN_REG_ADDR; addr--) {
+ ret = write_swreg_config(reg_id, addr,
+ FM_DATA[reg_id - 1][addr]);
+ if (ret)
+ goto exit;
+ }
+ }
+
+ /* trigger SWREG firmware update */
+ for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
+ /*
+ * Slave regulator doesn't have to be updated,
+ * Updating Master is enough
+ */
+ if ((reg_id == DDRIO_SLAVE) || (reg_id == VDDC1))
+ continue;
+
+ ret = swreg_config_done(reg_id);
+ if (ret) {
+ ERROR("Failed to trigger SWREG firmware update for %s\n"
+ , sw_reg_name[reg_id-1]);
+ return ret;
+ }
+ }
+
+ for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
+ /*
+ * IHOST_ARRAY will be used on some boards like STRATUS and
+ * there will not be any issue even if it is updated on other
+ * boards where it is not used.
+ */
+ if (reg_id == IHOST_ARRAY)
+ continue;
+
+ for (addr = MIN_REG_ADDR; addr <= MAX_REG_ADDR; addr++) {
+ ret = read_swreg_config(reg_id, addr, &data);
+ if (ret || (!ret &&
+ (data != FM_DATA[reg_id - 1][addr]))) {
+ ERROR("swreg fm update failed: %s at off %d\n",
+ sw_reg_name[reg_id - 1], addr);
+ ERROR("Read val: 0x%x, expected val: 0x%x\n",
+ data, FM_DATA[reg_id - 1][addr]);
+ return -1;
+ }
+ }
+ }
+
+ INFO("Updated SWREG firmware\n");
+
+#ifdef DUMP_SWREG
+ dump_swreg_firmware();
+#endif
+ return ret;
+
+exit:
+ /*
+ * Stop booting if swreg firmware update fails.
+ * Booting will fail at random point if we
+ * continue with wrong voltage settings.
+ */
+ ERROR("Failed to update firmware for %s SWREG\n",
+ sw_reg_name[reg_id-1]);
+ assert(0);
+
+ return ret;
+}
diff --git a/plat/brcm/board/stingray/driver/usb.c b/plat/brcm/board/stingray/driver/usb.c
new file mode 100644
index 0000000..4a84141
--- /dev/null
+++ b/plat/brcm/board/stingray/driver/usb.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2019 - 2021, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <mdio.h>
+#include <platform_usb.h>
+#include <sr_utils.h>
+#include "sr_usb.h"
+#include <usbh_xhci_regs.h>
+
+static uint32_t usb_func = USB3_DRD | USB3H_USB2DRD;
+
+static void usb_pm_rescal_init(void)
+{
+ uint32_t data;
+ uint32_t try;
+
+ mmio_setbits_32(CDRU_MISC_RESET_CONTROL, CDRU_PM_RESET_N_R);
+ /* release reset */
+ mmio_setbits_32(CDRU_CHIP_TOP_SPARE_REG0, RESCAL_I_RSTB);
+ udelay(10U);
+ /* power up */
+ mmio_setbits_32(CDRU_CHIP_TOP_SPARE_REG0,
+ RESCAL_I_RSTB | RESCAL_I_PWRDNB);
+ try = 1000U;
+ do {
+ udelay(1U);
+ data = mmio_read_32(CDRU_CHIP_TOP_SPARE_REG1);
+ try--;
+ } while ((data & RESCAL_I_PWRDNB) == 0x0U && (try != 0U));
+
+ if (try == 0U) {
+ ERROR("CDRU_CHIP_TOP_SPARE_REG1: 0x%x\n", data);
+ }
+
+ INFO("USB and PM Rescal Init done..\n");
+}
+
+const unsigned int xhc_portsc_reg_offset[MAX_USB_PORTS] = {
+ XHC_PORTSC1_OFFSET,
+ XHC_PORTSC2_OFFSET,
+ XHC_PORTSC3_OFFSET,
+};
+
+static void usb3h_usb2drd_init(void)
+{
+ uint32_t val;
+
+ INFO("USB3H + USB 2DRD init\n");
+ mmio_clrbits_32(USB3H_U3PHY_CTRL, POR_RESET);
+ val = mmio_read_32(USB3H_PWR_CTRL);
+ val &= ~(0x3U << POWER_CTRL_OVRD);
+ val |= (1U << POWER_CTRL_OVRD);
+ mmio_write_32(USB3H_PWR_CTRL, val);
+ mmio_setbits_32(USB3H_U3PHY_CTRL, PHY_RESET);
+ /* Phy to come out of reset */
+ udelay(2U);
+ mmio_clrbits_32(USB3H_U3PHY_CTRL, MDIO_RESET);
+
+ /* MDIO in reset */
+ udelay(2U);
+ mmio_setbits_32(USB3H_U3PHY_CTRL, MDIO_RESET);
+
+ /* After MDIO reset release */
+ udelay(2U);
+
+ /* USB 3.0 phy Analog Block Initialization */
+ mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_MDIO_BLOCK_BASE_REG,
+ USB3_PHY_ANA_BLOCK_BASE);
+ mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_ANA_REG0, 0x4646U);
+ mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_ANA_REG1, 0x80c9U);
+ mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_ANA_REG2, 0x88a6U);
+ mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_ANA_REG5, 0x7c12U);
+ mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_ANA_REG8, 0x1d07U);
+ mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_ANA_REG11, 0x25cU);
+
+ /* USB 3.0 phy RXPMD Block initialization*/
+ mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_MDIO_BLOCK_BASE_REG,
+ USB3_PHY_RXPMD_BLOCK_BASE);
+ mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_RXPMD_REG1, 0x4052U);
+ mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_RXPMD_REG2, 0x4cU);
+ mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_RXPMD_REG5, 0x7U);
+ mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_RXPMD_REG7, 0x173U);
+
+ /* USB 3.0 phy AEQ Block initialization*/
+ mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_MDIO_BLOCK_BASE_REG,
+ USB3_PHY_AEQ_BLOCK_BASE);
+ mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_AEQ_REG1, 0x3000U);
+ mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_AEQ_REG3, 0x2c70U);
+
+ /* USB 3.0 phy TXPMD Block initialization*/
+ mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_MDIO_BLOCK_BASE_REG,
+ USB3_PHY_TXPMD_BLOCK_BASE);
+ mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_TXPMD_REG1, 0x100fU);
+ mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_TXPMD_REG2, 0x238cU);
+}
+
+static void usb3drd_init(void)
+{
+ uint32_t val;
+
+ INFO("USB3DRD init\n");
+ mmio_clrbits_32(DRDU3_U3PHY_CTRL, POR_RESET);
+ val = mmio_read_32(DRDU3_PWR_CTRL);
+ val &= ~(0x3U << POWER_CTRL_OVRD);
+ val |= (1U << POWER_CTRL_OVRD);
+ mmio_write_32(DRDU3_PWR_CTRL, val);
+ mmio_setbits_32(DRDU3_U3PHY_CTRL, PHY_RESET);
+ /* Phy to come out of reset */
+ udelay(2U);
+ mmio_clrbits_32(DRDU3_U3PHY_CTRL, MDIO_RESET);
+
+ /* MDIO in reset */
+ udelay(2U);
+ mmio_setbits_32(DRDU3_U3PHY_CTRL, MDIO_RESET);
+
+ /* After MDIO reset release */
+ udelay(2U);
+
+ /* USB 3.0 DRD phy Analog Block Initialization */
+ mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_MDIO_BLOCK_BASE_REG,
+ USB3_PHY_ANA_BLOCK_BASE);
+ mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_ANA_REG0, 0x4646U);
+ mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_ANA_REG1, 0x80c9U);
+ mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_ANA_REG2, 0x88a6U);
+ mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_ANA_REG5, 0x7c12U);
+ mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_ANA_REG8, 0x1d07U);
+ mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_ANA_REG11, 0x25cU);
+
+ /* USB 3.0 DRD phy RXPMD Block initialization*/
+ mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_MDIO_BLOCK_BASE_REG,
+ USB3_PHY_RXPMD_BLOCK_BASE);
+ mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_RXPMD_REG1, 0x4052U);
+ mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_RXPMD_REG2, 0x4cU);
+ mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_RXPMD_REG5, 0x7U);
+ mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_RXPMD_REG7, 0x173U);
+
+ /* USB 3.0 DRD phy AEQ Block initialization*/
+ mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_MDIO_BLOCK_BASE_REG,
+ USB3_PHY_AEQ_BLOCK_BASE);
+ mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_AEQ_REG1, 0x3000U);
+ mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_AEQ_REG3, 0x2c70U);
+
+ /* USB 3.0 DRD phy TXPMD Block initialization*/
+ mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_MDIO_BLOCK_BASE_REG,
+ USB3_PHY_TXPMD_BLOCK_BASE);
+ mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_TXPMD_REG1, 0x100fU);
+ mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_TXPMD_REG2, 0x238cU);
+}
+
+static void usb3_phy_init(void)
+{
+ usb_pm_rescal_init();
+
+ if ((usb_func & USB3H_USB2DRD) != 0U) {
+ usb3h_usb2drd_init();
+ }
+
+ if ((usb_func & USB3_DRD) != 0U) {
+ usb3drd_init();
+ }
+}
+
+#ifdef USB_DMA_COHERENT
+void usb_enable_coherence(void)
+{
+ if (usb_func & USB3H_USB2DRD) {
+ mmio_setbits_32(USB3H_SOFT_RESET_CTRL,
+ USB3H_XHC_AXI_SOFT_RST_N);
+ mmio_setbits_32(DRDU2_SOFT_RESET_CTRL,
+ DRDU2_BDC_AXI_SOFT_RST_N);
+ mmio_setbits_32(USB3H_U3PHY_CTRL, USB3H_U3SOFT_RST_N);
+ mmio_setbits_32(DRDU2_PHY_CTRL, DRDU2_U2SOFT_RST_N);
+
+ mmio_clrsetbits_32(DRD2U3H_XHC_REGS_AXIWRA,
+ (USBAXIWR_UA_MASK | USBAXIWR_SA_MASK),
+ (USBAXIWR_UA_VAL | USBAXIWR_SA_VAL));
+
+ mmio_clrsetbits_32(DRD2U3H_XHC_REGS_AXIRDA,
+ (USBAXIRD_UA_MASK | USBAXIRD_SA_MASK),
+ (USBAXIRD_UA_VAL | USBAXIRD_SA_VAL));
+
+ mmio_clrsetbits_32(DRDU2D_BDC_REGS_AXIWRA,
+ (USBAXIWR_UA_MASK | USBAXIWR_SA_MASK),
+ (USBAXIWR_UA_VAL | USBAXIWR_SA_VAL));
+
+ mmio_clrsetbits_32(DRDU2D_BDC_REGS_AXIRDA,
+ (USBAXIRD_UA_MASK | USBAXIRD_SA_MASK),
+ (USBAXIRD_UA_VAL | USBAXIRD_SA_VAL));
+
+ }
+
+ if (usb_func & USB3_DRD) {
+ mmio_setbits_32(DRDU3_SOFT_RESET_CTRL,
+ (DRDU3_XHC_AXI_SOFT_RST_N |
+ DRDU3_BDC_AXI_SOFT_RST_N));
+ mmio_setbits_32(DRDU3_U3PHY_CTRL,
+ (DRDU3_U3XHC_SOFT_RST_N |
+ DRDU3_U3BDC_SOFT_RST_N));
+
+ mmio_clrsetbits_32(DRDU3H_XHC_REGS_AXIWRA,
+ (USBAXIWR_UA_MASK | USBAXIWR_SA_MASK),
+ (USBAXIWR_UA_VAL | USBAXIWR_SA_VAL));
+
+ mmio_clrsetbits_32(DRDU3H_XHC_REGS_AXIRDA,
+ (USBAXIRD_UA_MASK | USBAXIRD_SA_MASK),
+ (USBAXIRD_UA_VAL | USBAXIRD_SA_VAL));
+
+ mmio_clrsetbits_32(DRDU3D_BDC_REGS_AXIWRA,
+ (USBAXIWR_UA_MASK | USBAXIWR_SA_MASK),
+ (USBAXIWR_UA_VAL | USBAXIWR_SA_VAL));
+
+ mmio_clrsetbits_32(DRDU3D_BDC_REGS_AXIRDA,
+ (USBAXIRD_UA_MASK | USBAXIRD_SA_MASK),
+ (USBAXIRD_UA_VAL | USBAXIRD_SA_VAL));
+ }
+}
+#endif
+
+void xhci_phy_init(void)
+{
+ uint32_t val;
+
+ INFO("usb init start\n");
+ mmio_setbits_32(CDRU_MISC_CLK_ENABLE_CONTROL,
+ CDRU_MISC_CLK_USBSS);
+
+ mmio_setbits_32(CDRU_MISC_RESET_CONTROL, CDRU_USBSS_RESET_N);
+
+ if (usb_func & USB3_DRD) {
+ VERBOSE(" - configure stream_id = 0x6800 for DRDU3\n");
+ val = SR_SID_VAL(0x3U, 0x1U, 0x0U) << ICFG_USB_SID_SHIFT;
+ mmio_write_32(ICFG_DRDU3_SID_CTRL + ICFG_USB_SID_AWADDR_OFFSET,
+ val);
+ mmio_write_32(ICFG_DRDU3_SID_CTRL + ICFG_USB_SID_ARADDR_OFFSET,
+ val);
+
+ /*
+ * DRDU3 Device USB Space, DRDU3 Host USB Space,
+ * DRDU3 SS Config
+ */
+ mmio_setbits_32(USBIC_GPV_SECURITY10,
+ USBIC_GPV_SECURITY10_FIELD);
+ }
+
+ if (usb_func & USB3H_USB2DRD) {
+ VERBOSE(" - configure stream_id = 0x6801 for USB3H\n");
+ val = SR_SID_VAL(0x3U, 0x1U, 0x1U) << ICFG_USB_SID_SHIFT;
+ mmio_write_32(ICFG_USB3H_SID_CTRL + ICFG_USB_SID_AWADDR_OFFSET,
+ val);
+ mmio_write_32(ICFG_USB3H_SID_CTRL + ICFG_USB_SID_ARADDR_OFFSET,
+ val);
+
+ VERBOSE(" - configure stream_id = 0x6802 for DRDU2\n");
+ val = SR_SID_VAL(0x3U, 0x1U, 0x2U) << ICFG_USB_SID_SHIFT;
+ mmio_write_32(ICFG_DRDU2_SID_CTRL + ICFG_USB_SID_AWADDR_OFFSET,
+ val);
+ mmio_write_32(ICFG_DRDU2_SID_CTRL + ICFG_USB_SID_ARADDR_OFFSET,
+ val);
+
+ /* DRDU2 APB Bridge:DRDU2 USB Device, USB3H SS Config */
+ mmio_setbits_32(USBIC_GPV_SECURITY1, USBIC_GPV_SECURITY1_FIELD);
+
+ /*
+ * USB3H APB Bridge:DRDU2 Host + USB3 Host USB Space,
+ * USB3H SS Config
+ */
+ mmio_setbits_32(USBIC_GPV_SECURITY2, USBIC_GPV_SECURITY2_FIELD);
+ }
+
+ /* Configure Host masters as non-Secure */
+ mmio_setbits_32(USBSS_TZPCDECPROT0set, USBSS_TZPCDECPROT0);
+
+ /* CCN Slave on USBIC */
+ mmio_setbits_32(USBIC_GPV_SECURITY0, USBIC_GPV_SECURITY0_FIELD);
+
+ /* SLAVE_8:IDM Register Space */
+ mmio_setbits_32(USBIC_GPV_SECURITY4, USBIC_GPV_SECURITY4_FIELD);
+
+ usb3_phy_init();
+#ifdef USB_DMA_COHERENT
+ usb_enable_coherence();
+#endif
+
+ usb_device_init(usb_func);
+
+ INFO("PLAT USB: init done.\n");
+}
diff --git a/plat/brcm/board/stingray/driver/usb_phy.c b/plat/brcm/board/stingray/driver/usb_phy.c
new file mode 100644
index 0000000..54c98e1
--- /dev/null
+++ b/plat/brcm/board/stingray/driver/usb_phy.c
@@ -0,0 +1,601 @@
+/*
+ * Copyright (c) 2019 - 2021, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_usb.h>
+#include <usb_phy.h>
+
+#define USB_PHY_ALREADY_STARTED (-2)
+#define USB_MAX_DEVICES 2
+#define USB3H_USB2DRD_PHY 0
+#define USB3_DRD_PHY 1
+
+/* Common bit fields for all the USB2 phy */
+#define USB2_PHY_ISO DRDU2_U2PHY_ISO
+#define USB2_AFE_PLL_PWRDWNB DRDU2_U2AFE_PLL_PWRDWNB
+#define USB2_AFE_BG_PWRDWNB DRDU2_U2AFE_BG_PWRDWNB
+#define USB2_AFE_LDO_PWRDWNB DRDU2_U2AFE_LDO_PWRDWNB
+#define USB2_CTRL_CORERDY DRDU2_U2CTRL_CORERDY
+
+#define USB2_PHY_PCTL_MASK DRDU2_U2PHY_PCTL_MASK
+#define USB2_PHY_PCTL_OFFSET DRDU2_U2PHY_PCTL_OFFSET
+#define USB2_PHY_PCTL_VAL U2PHY_PCTL_VAL
+
+#define USB2_PLL_RESETB DRDU2_U2PLL_RESETB
+#define USB2_PHY_RESETB DRDU2_U2PHY_RESETB
+
+static usb_phy_port_t usb_phy_port[2U][MAX_NR_PORTS];
+
+static usb_phy_t usb_phy_info[2U] = {
+ {DRDU2_U2PLL_NDIV_FRAC, USB3H_PIPE_CTRL, 0U, USB3H_DRDU2_PHY},
+ {0U, 0U, DRDU3_PIPE_CTRL, DRDU3_PHY}
+};
+
+typedef struct {
+ void *pcd_id;
+} usb_platform_dev;
+
+/* index 0: USB3H + USB2 DRD, 1: USB3 DRD */
+static usb_platform_dev xhci_devices_configs[USB_MAX_DEVICES] = {
+ {&usb_phy_info[0U]},
+ {&usb_phy_info[1U]}
+};
+
+static int32_t pll_lock_check(uint32_t address, uint32_t bit)
+{
+ uint32_t retry;
+ uint32_t data;
+
+ retry = PLL_LOCK_RETRY_COUNT;
+ do {
+ data = mmio_read_32(address);
+ if ((data & bit) != 0U) {
+ return 0;
+ }
+ udelay(1);
+ } while (--retry != 0);
+
+ ERROR("%s(): FAIL (0x%08x)\n", __func__, address);
+ return -1;
+}
+
+/*
+ * USB2 PHY using external FSM bringup sequence
+ * Total #3 USB2 phys. All phys has the same
+ * bringup sequence. Register bit fields for
+ * some of the PHY's are different.
+ * Bit fields which are different are passed using
+ * struct u2_phy_ext_fsm with bit-fields and register addr.
+ */
+
+static void u2_phy_ext_fsm_power_on(struct u2_phy_ext_fsm *u2_phy)
+{
+ mmio_setbits_32(u2_phy->phy_ctrl_reg, USB2_PHY_ISO);
+ /* Delay as per external FSM spec */
+ udelay(10U);
+
+ mmio_setbits_32(u2_phy->phy_ctrl_reg, u2_phy->phy_iddq);
+ /* Delay as per external FSM spec */
+ udelay(10U);
+
+ mmio_clrbits_32(u2_phy->phy_ctrl_reg,
+ (USB2_AFE_BG_PWRDWNB |
+ USB2_AFE_PLL_PWRDWNB |
+ USB2_AFE_LDO_PWRDWNB |
+ USB2_CTRL_CORERDY));
+
+ mmio_clrsetbits_32(u2_phy->phy_ctrl_reg,
+ (USB2_PHY_PCTL_MASK << USB2_PHY_PCTL_OFFSET),
+ (USB2_PHY_PCTL_VAL << USB2_PHY_PCTL_OFFSET));
+ /* Delay as per external FSM spec */
+ udelay(160U);
+
+ mmio_setbits_32(u2_phy->phy_ctrl_reg, USB2_CTRL_CORERDY);
+ /* Delay as per external FSM spec */
+ udelay(50U);
+
+ mmio_setbits_32(u2_phy->phy_ctrl_reg, USB2_AFE_BG_PWRDWNB);
+ /* Delay as per external FSM spec */
+ udelay(200U);
+
+ mmio_setbits_32(u2_phy->pwr_ctrl_reg, u2_phy->pwr_onin);
+ mmio_setbits_32(u2_phy->phy_ctrl_reg, USB2_AFE_LDO_PWRDWNB);
+ /* Delay as per external FSM spec */
+ udelay(10U);
+
+ mmio_setbits_32(u2_phy->pwr_ctrl_reg, u2_phy->pwr_okin);
+ /* Delay as per external FSM spec */
+ udelay(10U);
+
+ mmio_setbits_32(u2_phy->phy_ctrl_reg, USB2_AFE_PLL_PWRDWNB);
+ /* Delay as per external FSM spec */
+ udelay(10U);
+
+ mmio_clrbits_32(u2_phy->phy_ctrl_reg, USB2_PHY_ISO);
+ /* Delay as per external FSM spec */
+ udelay(10U);
+ mmio_clrbits_32(u2_phy->phy_ctrl_reg, u2_phy->phy_iddq);
+ /* Delay as per external FSM spec */
+ udelay(1U);
+
+ mmio_setbits_32(u2_phy->pll_ctrl_reg, USB2_PLL_RESETB);
+ mmio_setbits_32(u2_phy->phy_ctrl_reg, USB2_PHY_RESETB);
+
+}
+
+static int32_t usb3h_u2_phy_power_on(uint32_t base)
+{
+ int32_t status;
+ struct u2_phy_ext_fsm u2_phy;
+
+ u2_phy.pll_ctrl_reg = base + USB3H_U2PLL_CTRL;
+ u2_phy.phy_ctrl_reg = base + USB3H_U2PHY_CTRL;
+ u2_phy.phy_iddq = USB3H_U2PHY_IDDQ;
+ u2_phy.pwr_ctrl_reg = base + USB3H_PWR_CTRL;
+ u2_phy.pwr_okin = USB3H_PWR_CTRL_U2PHY_DFE_SWITCH_PWROKIN;
+ u2_phy.pwr_onin = USB3H_PWR_CTRL_U2PHY_DFE_SWITCH_PWRONIN;
+
+ u2_phy_ext_fsm_power_on(&u2_phy);
+
+ status = pll_lock_check(base + USB3H_U2PLL_CTRL, USB3H_U2PLL_LOCK);
+ if (status != 0) {
+ /* re-try by toggling the PLL reset */
+ mmio_clrbits_32(base + USB3H_U2PLL_CTRL,
+ (uint32_t)USB3H_U2PLL_RESETB);
+ mmio_setbits_32(base + USB3H_U2PLL_CTRL, USB3H_U2PLL_RESETB);
+ status = pll_lock_check(base + USB3H_U2PLL_CTRL,
+ USB3H_U2PLL_LOCK);
+ if (status != 0)
+ ERROR("%s() re-try PLL lock FAIL (0x%08x)\n", __func__,
+ base + USB3H_U2PLL_CTRL);
+ }
+
+ mmio_clrsetbits_32(base + USB3H_U2PHY_CTRL,
+ (USB3H_U2PHY_PCTL_MASK << USB3H_U2PHY_PCTL_OFFSET),
+ (U2PHY_PCTL_NON_DRV_LOW << USB3H_U2PHY_PCTL_OFFSET));
+ return status;
+}
+
+static int32_t usb3h_u3_phy_power_on(uint32_t base)
+{
+ int32_t status;
+
+ /* Set pctl with mode and soft reset */
+ mmio_clrsetbits_32(base + USB3H_U3PHY_CTRL,
+ (USB3H_U3PHY_PCTL_MASK << USB3H_U3PHY_PCTL_OFFSET),
+ (U3PHY_PCTL_VAL << USB3H_U3PHY_PCTL_OFFSET));
+
+ mmio_clrbits_32(base + USB3H_U3PHY_PLL_CTRL,
+ (uint32_t) USB3H_U3SSPLL_SUSPEND_EN);
+ mmio_setbits_32(base + USB3H_U3PHY_PLL_CTRL, USB3H_U3PLL_SEQ_START);
+ mmio_setbits_32(base + USB3H_U3PHY_PLL_CTRL, USB3H_U3PLL_RESETB);
+
+ /* Time to stabilize the PLL Control */
+ mdelay(1U);
+
+ status = pll_lock_check(base + USB3H_U3PHY_PLL_CTRL,
+ USB3H_U3PLL_SS_LOCK);
+
+ return status;
+}
+
+static int32_t drdu3_u2_phy_power_on(uint32_t base)
+{
+ int32_t status;
+ struct u2_phy_ext_fsm u2_phy;
+
+ u2_phy.pll_ctrl_reg = base + DRDU3_U2PLL_CTRL;
+ u2_phy.phy_ctrl_reg = base + DRDU3_U2PHY_CTRL;
+ u2_phy.phy_iddq = DRDU3_U2PHY_IDDQ;
+ u2_phy.pwr_ctrl_reg = base + DRDU3_PWR_CTRL;
+ u2_phy.pwr_okin = DRDU3_U2PHY_DFE_SWITCH_PWROKIN;
+ u2_phy.pwr_onin = DRDU3_U2PHY_DFE_SWITCH_PWRONIN;
+
+ u2_phy_ext_fsm_power_on(&u2_phy);
+
+ status = pll_lock_check(base + DRDU3_U2PLL_CTRL, DRDU3_U2PLL_LOCK);
+ if (status != 0) {
+ /* re-try by toggling the PLL reset */
+ mmio_clrbits_32(base + DRDU3_U2PLL_CTRL,
+ (uint32_t)DRDU2_U2PLL_RESETB);
+ mmio_setbits_32(base + DRDU3_U2PLL_CTRL, DRDU3_U2PLL_RESETB);
+
+ status = pll_lock_check(base + DRDU3_U2PLL_CTRL,
+ DRDU3_U2PLL_LOCK);
+ if (status != 0) {
+ ERROR("%s() re-try PLL lock FAIL (0x%08x)\n", __func__,
+ base + DRDU3_U2PLL_CTRL);
+ }
+ }
+ mmio_clrsetbits_32(base + DRDU3_U2PHY_CTRL,
+ (DRDU3_U2PHY_PCTL_MASK << DRDU3_U2PHY_PCTL_OFFSET),
+ (U2PHY_PCTL_NON_DRV_LOW << DRDU3_U2PHY_PCTL_OFFSET));
+
+ return status;
+}
+
+static int32_t drdu3_u3_phy_power_on(uint32_t base)
+{
+ int32_t status;
+
+ /* Set pctl with mode and soft reset */
+ mmio_clrsetbits_32(base + DRDU3_U3PHY_CTRL,
+ (DRDU3_U3PHY_PCTL_MASK << DRDU3_U3PHY_PCTL_OFFSET),
+ (U3PHY_PCTL_VAL << DRDU3_U3PHY_PCTL_OFFSET));
+
+ mmio_clrbits_32(base + DRDU3_U3PHY_PLL_CTRL,
+ (uint32_t) DRDU3_U3SSPLL_SUSPEND_EN);
+ mmio_setbits_32(base + DRDU3_U3PHY_PLL_CTRL, DRDU3_U3PLL_SEQ_START);
+ mmio_setbits_32(base + DRDU3_U3PHY_PLL_CTRL, DRDU3_U3PLL_RESETB);
+
+ /* Time to stabilize the PLL Control */
+ mdelay(1U);
+
+ status = pll_lock_check(base + DRDU3_U3PHY_PLL_CTRL,
+ DRDU3_U3PLL_SS_LOCK);
+
+ return status;
+}
+
+static int32_t drdu2_u2_phy_power_on(uint32_t base)
+{
+ int32_t status;
+ struct u2_phy_ext_fsm u2_phy;
+
+ u2_phy.pll_ctrl_reg = base + DRDU2_U2PLL_CTRL;
+ u2_phy.phy_ctrl_reg = base + DRDU2_PHY_CTRL;
+ u2_phy.phy_iddq = DRDU2_U2IDDQ;
+ u2_phy.pwr_ctrl_reg = base + DRDU2_PWR_CTRL;
+ u2_phy.pwr_okin = DRDU2_U2PHY_DFE_SWITCH_PWROKIN_I;
+ u2_phy.pwr_onin = DRDU2_U2PHY_DFE_SWITCH_PWRONIN_I;
+
+ u2_phy_ext_fsm_power_on(&u2_phy);
+
+ status = pll_lock_check(base + DRDU2_U2PLL_CTRL, DRDU2_U2PLL_LOCK);
+ if (status != 0) {
+ /* re-try by toggling the PLL reset */
+ mmio_clrbits_32(base + DRDU2_U2PLL_CTRL,
+ (uint32_t)DRDU2_U2PLL_RESETB);
+ mmio_setbits_32(base + DRDU2_U2PLL_CTRL, DRDU2_U2PLL_RESETB);
+
+ status = pll_lock_check(base + DRDU2_U2PLL_CTRL,
+ DRDU2_U2PLL_LOCK);
+ if (status != 0)
+ ERROR("%s() re-try PLL lock FAIL (0x%08x)\n", __func__,
+ base + DRDU2_U2PLL_CTRL);
+ }
+ mmio_clrsetbits_32(base + DRDU2_PHY_CTRL,
+ (DRDU2_U2PHY_PCTL_MASK << DRDU2_U2PHY_PCTL_OFFSET),
+ (U2PHY_PCTL_NON_DRV_LOW << DRDU2_U2PHY_PCTL_OFFSET));
+
+ return status;
+}
+
+void u3h_u2drd_phy_reset(usb_phy_port_t *phy_port)
+{
+ usb_phy_t *phy = phy_port->p;
+
+ switch (phy_port->port_id) {
+ case USB3HS_PORT:
+ mmio_clrbits_32(phy->usb3hreg + USB3H_U2PHY_CTRL,
+ (uint32_t) USB3H_U2CTRL_CORERDY);
+ mmio_setbits_32(phy->usb3hreg + USB3H_U2PHY_CTRL,
+ USB3H_U2CTRL_CORERDY);
+ break;
+ case DRDU2_PORT:
+ mmio_clrbits_32(phy->drdu2reg + DRDU2_PHY_CTRL,
+ (uint32_t) DRDU2_U2CTRL_CORERDY);
+ mmio_setbits_32(phy->drdu2reg + DRDU2_PHY_CTRL,
+ DRDU2_U2CTRL_CORERDY);
+ break;
+ }
+}
+
+void u3drd_phy_reset(usb_phy_port_t *phy_port)
+{
+ usb_phy_t *phy = phy_port->p;
+
+ if (phy_port->port_id == DRD3HS_PORT) {
+ mmio_clrbits_32(phy->drdu3reg + DRDU3_U2PHY_CTRL,
+ (uint32_t) DRDU3_U2CTRL_CORERDY);
+ mmio_setbits_32(phy->drdu3reg + DRDU3_U2PHY_CTRL,
+ DRDU3_U2CTRL_CORERDY);
+ }
+}
+
+static int32_t u3h_u2drd_phy_power_on(usb_phy_port_t *phy_port)
+{
+ usb_phy_t *phy = phy_port->p;
+ int32_t status;
+
+ switch (phy_port->port_id) {
+ case USB3SS_PORT:
+ mmio_clrbits_32(phy->usb3hreg + USB3H_PHY_PWR_CTRL,
+ (uint32_t) USB3H_DISABLE_USB30_P0);
+ status = usb3h_u3_phy_power_on(phy->usb3hreg);
+ if (status != 0) {
+ goto err_usb3h_phy_on;
+ }
+ break;
+ case USB3HS_PORT:
+ mmio_clrbits_32(phy->usb3hreg + USB3H_PHY_PWR_CTRL,
+ (uint32_t) USB3H_DISABLE_EUSB_P1);
+ mmio_setbits_32(AXI_DEBUG_CTRL,
+ AXI_DBG_CTRL_SSPHY_DRD_MODE_DISABLE);
+ mmio_setbits_32(USB3H_DEBUG_CTRL,
+ USB3H_DBG_CTRL_SSPHY_DRD_MODE_DISABLE);
+
+ mmio_clrbits_32(phy->usb3hreg + USB3H_PWR_CTRL,
+ USB3H_PWR_CTRL_U2PHY_DFE_SWITCH_PWRONIN);
+ /* Delay as per external FSM spec */
+ udelay(10U);
+ mmio_clrbits_32(phy->usb3hreg + USB3H_PWR_CTRL,
+ USB3H_PWR_CTRL_U2PHY_DFE_SWITCH_PWROKIN);
+ status = usb3h_u2_phy_power_on(phy->usb3hreg);
+ if (status != 0) {
+ goto err_usb3h_phy_on;
+ }
+ break;
+ case DRDU2_PORT:
+ mmio_clrbits_32(phy->usb3hreg + USB3H_PHY_PWR_CTRL,
+ (uint32_t) USB3H_DISABLE_EUSB_P0);
+ mmio_setbits_32(AXI_DEBUG_CTRL,
+ AXI_DBG_CTRL_SSPHY_DRD_MODE_DISABLE);
+ mmio_setbits_32(USB3H_DEBUG_CTRL,
+ USB3H_DBG_CTRL_SSPHY_DRD_MODE_DISABLE);
+
+ mmio_clrbits_32(phy->usb3hreg + DRDU2_PWR_CTRL,
+ DRDU2_U2PHY_DFE_SWITCH_PWRONIN_I);
+ /* Delay as per external FSM spec */
+ udelay(10U);
+ mmio_clrbits_32(phy->usb3hreg + DRDU2_PWR_CTRL,
+ DRDU2_U2PHY_DFE_SWITCH_PWROKIN_I);
+
+ status = drdu2_u2_phy_power_on(phy->drdu2reg);
+ if (status != 0) {
+ mmio_setbits_32(phy->usb3hreg + USB3H_PHY_PWR_CTRL,
+ USB3H_DISABLE_EUSB_P0);
+ goto err_drdu2_phy_on;
+ }
+ break;
+ }
+
+ /* Device Mode */
+ if (phy_port->port_id == DRDU2_PORT) {
+ mmio_write_32(phy->drdu2reg + DRDU2_SOFT_RESET_CTRL,
+ DRDU2_BDC_AXI_SOFT_RST_N);
+ mmio_setbits_32(phy->drdu2reg + DRDU2_PHY_CTRL,
+ DRDU2_U2SOFT_RST_N);
+ }
+ /* Host Mode */
+ mmio_write_32(phy->usb3hreg + USB3H_SOFT_RESET_CTRL,
+ USB3H_XHC_AXI_SOFT_RST_N);
+ mmio_setbits_32(phy->usb3hreg + USB3H_U3PHY_CTRL, USB3H_U3SOFT_RST_N);
+
+ return 0U;
+ err_usb3h_phy_on:mmio_setbits_32(phy->usb3hreg + USB3H_PHY_PWR_CTRL,
+ (USB3H_DISABLE_EUSB_P1 |
+ USB3H_DISABLE_USB30_P0));
+ err_drdu2_phy_on:
+
+ return status;
+}
+
+static int32_t u3drd_phy_power_on(usb_phy_port_t *phy_port)
+{
+ usb_phy_t *phy = phy_port->p;
+ int32_t status;
+
+ switch (phy_port->port_id) {
+ case DRD3SS_PORT:
+ mmio_clrbits_32(phy->drdu3reg + DRDU3_PHY_PWR_CTRL,
+ (uint32_t) DRDU3_DISABLE_USB30_P0);
+
+ status = drdu3_u3_phy_power_on(phy->drdu3reg);
+ if (status != 0) {
+ goto err_drdu3_phy_on;
+ }
+ break;
+ case DRD3HS_PORT:
+ mmio_clrbits_32(phy->drdu3reg + DRDU3_PHY_PWR_CTRL,
+ (uint32_t) DRDU3_DISABLE_EUSB_P0);
+ mmio_setbits_32(AXI_DEBUG_CTRL,
+ AXI_DBG_CTRL_SSPHY_DRD_MODE_DISABLE);
+ mmio_setbits_32(USB3H_DEBUG_CTRL,
+ USB3H_DBG_CTRL_SSPHY_DRD_MODE_DISABLE);
+
+ mmio_clrbits_32(phy->drdu3reg + DRDU3_PWR_CTRL,
+ DRDU3_U2PHY_DFE_SWITCH_PWRONIN);
+ /* Delay as per external FSM spec */
+ udelay(10U);
+ mmio_clrbits_32(phy->drdu3reg + DRDU3_PWR_CTRL,
+ DRDU3_U2PHY_DFE_SWITCH_PWROKIN);
+
+ status = drdu3_u2_phy_power_on(phy->drdu3reg);
+ if (status != 0) {
+ goto err_drdu3_phy_on;
+ }
+
+ /* Host Mode */
+ mmio_setbits_32(phy->drdu3reg + DRDU3_SOFT_RESET_CTRL,
+ DRDU3_XHC_AXI_SOFT_RST_N);
+ mmio_setbits_32(phy->drdu3reg + DRDU3_U3PHY_CTRL,
+ DRDU3_U3XHC_SOFT_RST_N);
+ /* Device Mode */
+ mmio_setbits_32(phy->drdu3reg + DRDU3_SOFT_RESET_CTRL,
+ DRDU3_BDC_AXI_SOFT_RST_N);
+ mmio_setbits_32(phy->drdu3reg + DRDU3_U3PHY_CTRL,
+ DRDU3_U3BDC_SOFT_RST_N);
+ break;
+ }
+
+ return 0U;
+ err_drdu3_phy_on:mmio_setbits_32(phy->drdu3reg + DRDU3_PHY_PWR_CTRL,
+ (DRDU3_DISABLE_EUSB_P0 |
+ DRDU3_DISABLE_USB30_P0));
+
+ return status;
+}
+
+static void u3h_u2drd_phy_power_off(usb_phy_port_t *phy_port)
+{
+ usb_phy_t *p = phy_port->p;
+
+ switch (phy_port->port_id) {
+ case USB3SS_PORT:
+ mmio_setbits_32(p->usb3hreg + USB3H_PHY_PWR_CTRL,
+ USB3H_DISABLE_USB30_P0);
+ break;
+ case USB3HS_PORT:
+ mmio_setbits_32(p->usb3hreg + USB3H_PHY_PWR_CTRL,
+ USB3H_DISABLE_EUSB_P1);
+ break;
+ case DRDU2_PORT:
+ mmio_setbits_32(p->usb3hreg + USB3H_PHY_PWR_CTRL,
+ USB3H_DISABLE_EUSB_P0);
+ break;
+ }
+}
+
+static void u3drd_phy_power_off(usb_phy_port_t *phy_port)
+{
+ usb_phy_t *p = phy_port->p;
+
+ switch (phy_port->port_id) {
+ case DRD3SS_PORT:
+ mmio_setbits_32(p->drdu3reg + DRDU3_PHY_PWR_CTRL,
+ DRDU3_DISABLE_USB30_P0);
+ break;
+ case DRD3HS_PORT:
+ mmio_setbits_32(p->drdu3reg + DRDU3_PHY_PWR_CTRL,
+ DRDU3_DISABLE_EUSB_P0);
+ break;
+ }
+}
+
+int32_t usb_info_fill(usb_phy_t *phy_info)
+{
+ int32_t index;
+
+ if (phy_info->initialized != 0U) {
+ return USB_PHY_ALREADY_STARTED;
+ }
+
+ if (phy_info->phy_id == USB3H_DRDU2_PHY) {
+ phy_info->phy_port = usb_phy_port[USB3H_DRDU2_PHY - 1U];
+ phy_info->ports_enabled = 0x7U;
+ } else {
+ phy_info->phy_port = usb_phy_port[DRDU3_PHY - 1U];
+ phy_info->ports_enabled = 0x3U;
+ }
+
+ for (index = MAX_NR_PORTS - 1U; index > -1; index--) {
+ phy_info->phy_port[index].enabled = (phy_info->ports_enabled
+ >> index) & 0x1U;
+ phy_info->phy_port[index].p = phy_info;
+ phy_info->phy_port[index].port_id = index;
+ }
+
+ return 0U;
+}
+
+int32_t usb_phy_init(usb_platform_dev *device)
+{
+ int32_t status;
+ usb_phy_t *phy_info;
+ uint32_t index;
+
+ phy_info = (usb_phy_t *)device->pcd_id;
+
+ status = usb_info_fill(phy_info);
+ if (status != 0) {
+ return (status == USB_PHY_ALREADY_STARTED) ? 0 : status;
+ }
+
+ for (index = 0U; index < MAX_NR_PORTS; index++) {
+ if (phy_info->phy_port[index].enabled != 0U) {
+ switch (phy_info->phy_id) {
+ case USB3H_DRDU2_PHY:
+ status =
+ u3h_u2drd_phy_power_on(&phy_info->
+ phy_port[index]);
+ break;
+ default:
+ status =
+ u3drd_phy_power_on(&phy_info->
+ phy_port[index]);
+ }
+ }
+ }
+
+ phy_info->initialized = !status;
+ return status;
+}
+
+void usb_phy_shutdown(usb_platform_dev *device)
+{
+ usb_phy_t *phy_info;
+ uint32_t index;
+
+ phy_info = (usb_phy_t *)device->pcd_id;
+
+ phy_info->initialized = 0U;
+
+ for (index = 0U; index < MAX_NR_PORTS; index++) {
+ if (phy_info->phy_port[index].enabled != 0U) {
+ switch (phy_info->phy_id) {
+ case USB3H_DRDU2_PHY:
+ u3h_u2drd_phy_power_off(&phy_info->
+ phy_port[index]);
+ break;
+ case DRDU3_PHY:
+ u3drd_phy_power_off(&phy_info->phy_port[index]);
+ break;
+ default:
+ INFO("%s: invalid phy id 0x%x\n", __func__,
+ phy_info->phy_id);
+ }
+ }
+ }
+}
+
+int32_t usb_xhci_init(usb_platform_dev *device)
+{
+ int32_t status;
+
+ status = usb_phy_init(device);
+ if (status == USB_PHY_ALREADY_STARTED) {
+ status = 0U;
+ }
+
+ return status;
+}
+
+int32_t usb_device_init(unsigned int usb_func)
+{
+ int32_t status;
+ int32_t devices_initialized = 0U;
+
+ if ((usb_func & USB3H_USB2DRD) != 0U) {
+ status = usb_xhci_init(
+ &xhci_devices_configs[USB3H_USB2DRD_PHY]);
+ if (status == 0) {
+ devices_initialized++;
+ } else {
+ ERROR("%s(): USB3H_USB2DRD init failure\n", __func__);
+ }
+ }
+
+ if ((usb_func & USB3_DRD) != 0U) {
+ status = usb_xhci_init(&xhci_devices_configs[USB3_DRD_PHY]);
+ if (status == 0) {
+ devices_initialized++;
+ } else {
+ ERROR("%s(): USB3_DRD init failure\n", __func__);
+ }
+ }
+
+ return devices_initialized;
+}
diff --git a/plat/brcm/board/stingray/include/bl33_info.h b/plat/brcm/board/stingray/include/bl33_info.h
new file mode 100644
index 0000000..1dac48c
--- /dev/null
+++ b/plat/brcm/board/stingray/include/bl33_info.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BL33_INFO_H
+#define BL33_INFO_H
+
+/* Increase version number each time this file is modified */
+#define BL33_INFO_VERSION 4
+
+struct chip_info {
+ unsigned int chip_id;
+ unsigned int rev_id;
+};
+
+struct boot_time_info {
+ unsigned int bl1_start;
+ unsigned int bl1_end;
+ unsigned int bl2_start;
+ unsigned int bl2_end;
+ unsigned int bl31_start;
+ unsigned int bl31_end;
+ unsigned int bl32_start;
+ unsigned int bl32_end;
+ unsigned int bl33_start;
+ unsigned int bl33_prompt;
+ unsigned int bl33_end;
+};
+
+struct bl33_info {
+ unsigned int version;
+ struct chip_info chip;
+ struct boot_time_info boot_time_info;
+};
+
+#endif
diff --git a/plat/brcm/board/stingray/include/board_info.h b/plat/brcm/board/stingray/include/board_info.h
new file mode 100644
index 0000000..8901259
--- /dev/null
+++ b/plat/brcm/board/stingray/include/board_info.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BOARD_INFO_H
+#define BOARD_INFO_H
+
+#define IHOST_REG_INTEGRATED 0
+#define IHOST_REG_EXT_PROGRAMMABLE 1
+#define IHOST_REG_EXT_FIXED 2
+
+#if defined(IHOST_REG_TYPE)
+ #if ((IHOST_REG_TYPE != IHOST_REG_INTEGRATED) && \
+ (IHOST_REG_TYPE != IHOST_REG_EXT_PROGRAMMABLE) && \
+ (IHOST_REG_TYPE != IHOST_REG_EXT_FIXED))
+ #error "IHOST_REG_TYPE not valid"
+ #endif
+#else
+ #define IHOST_REG_TYPE IHOST_REG_INTEGRATED
+#endif
+
+#define VDDC_REG_INTEGRATED 0
+#define VDDC_REG_EXT_PROGRAMMABLE 1
+#define VDDC_REG_EXT_FIXED 2
+
+#if defined(VDDC_REG_TYPE)
+ #if ((VDDC_REG_TYPE != VDDC_REG_INTEGRATED) && \
+ (VDDC_REG_TYPE != VDDC_REG_EXT_PROGRAMMABLE) && \
+ (VDDC_REG_TYPE != VDDC_REG_EXT_FIXED))
+ #error "VDDC_REG_TYPE not valid"
+ #endif
+#else
+ #define VDDC_REG_TYPE VDDC_REG_INTEGRATED
+#endif
+
+#endif
diff --git a/plat/brcm/board/stingray/include/crmu_def.h b/plat/brcm/board/stingray/include/crmu_def.h
new file mode 100644
index 0000000..ebc2bb6
--- /dev/null
+++ b/plat/brcm/board/stingray/include/crmu_def.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CRMU_DEF_H
+#define CRMU_DEF_H
+
+#define CRMU_REGS_BASE 0x66410000
+/* 32 kB IDRAM */
+#define CRMU_IDRAM_BASE_ADDR CRMU_REGS_BASE
+#define CRMU_IDRAM_SIZE 0x8000
+/* 4 kB Scratch RAM */
+#define CRMU_SRAM_BASE (CRMU_IDRAM_BASE_ADDR + CRMU_IDRAM_SIZE)
+#define CRMU_SRAM_SIZE 0x1000
+
+#define CRMU_RESERVED_SPACE 0x3000
+#define CRMU_CORE_BASE (CRMU_SRAM_BASE + CRMU_SRAM_SIZE + \
+ CRMU_RESERVED_SPACE)
+
+#define CRMU_SHARED_SRAM_BASE CRMU_SRAM_BASE
+#define CRMU_SHARED_SRAM_SIZE 0x200
+#define CRMU_CFG_BASE (CRMU_SHARED_SRAM_BASE + \
+ CRMU_SHARED_SRAM_SIZE)
+
+#define CRMU_PWR_GOOD_STATUS CRMU_CORE_BASE
+#define CRMU_PWR_GOOD_STATUS__BBL_POWER_GOOD 0
+#define CRMU_ISO_CELL_CONTROL (CRMU_CORE_BASE + 0x4)
+#define CRMU_ISO_CELL_CONTROL__CRMU_ISO_PDBBL 16
+#define CRMU_ISO_CELL_CONTROL__CRMU_ISO_PDBBL_TAMPER 24
+#define CRMU_SPRU_SOURCE_SEL_STAT (CRMU_CORE_BASE + 0xc)
+#define CRMU_SPRU_SOURCE_SEL_STAT__SPRU_SOURCE_SELECT 0
+#define BSTI_BASE (CRMU_CORE_BASE + 0x28)
+#define BSTI_CONTROL_OFFSET BSTI_BASE
+#define BSTI_COMMAND_OFFSET (BSTI_BASE + 0x4)
+
+#define OCOTP_REGS_BASE (CRMU_CORE_BASE + 0x400)
+
+#define CRMU_TCI_BASE (CRMU_CORE_BASE + 0x800)
+#define CRMU_SWREG_STATUS_ADDR (CRMU_TCI_BASE + 0x0c)
+#define CRMU_CHIP_OTPC_STATUS (CRMU_TCI_BASE + 0x10)
+#define CRMU_CHIP_OTPC_STATUS__OTP_BISR_LOAD_DONE 19
+#define CRMU_BISR_PDG_MASK (CRMU_TCI_BASE + 0x4c)
+#define CRMU_BISR_PDG_MASK__CRMU_BISR_IHOST0 2
+#define CRMU_BISR_PDG_MASK__CRMU_BISR_IHOST1 3
+#define CRMU_BISR_PDG_MASK__CRMU_BISR_IHOST2 4
+#define CRMU_BISR_PDG_MASK__CRMU_BISR_IHOST3 0
+#define CRMU_POWER_POLL (CRMU_TCI_BASE + 0x60)
+#define CRMU_OTP_STATUS CRMU_POWER_POLL
+#define CRMU_OTP_STATUS_BIT 1
+#define CRMU_DDR_PHY_AON_CTRL (CRMU_TCI_BASE + 0x64)
+#define CRMU_DDRPHY2_HW_RESETN_R BIT(21)
+#define CRMU_DDRPHY2_PWROKIN_PHY_R BIT(20)
+#define CRMU_DDRPHY2_PWRONIN_PHY_R BIT(19)
+#define CRMU_DDRPHY2_ISO_PHY_DFI_R BIT(18)
+#define CRMU_DDRPHY2_ISO_PHY_REGS_R BIT(17)
+#define CRMU_DDRPHY2_ISO_PHY_PLL_R BIT(16)
+#define CRMU_DDRPHY1_HW_RESETN_R BIT(13)
+#define CRMU_DDRPHY1_PWROKIN_PHY_R BIT(12)
+#define CRMU_DDRPHY1_PWRONIN_PHY_R BIT(11)
+#define CRMU_DDRPHY1_ISO_PHY_DFI_R BIT(10)
+#define CRMU_DDRPHY1_ISO_PHY_REGS_R BIT(9)
+#define CRMU_DDRPHY1_ISO_PHY_PLL_R BIT(8)
+#define CRMU_DDRPHY0_HW_RESETN_R BIT(5)
+#define CRMU_DDRPHY0_PWROKIN_PHY_R BIT(4)
+#define CRMU_DDRPHY0_PWRONIN_PHY_R BIT(3)
+#define CRMU_DDRPHY0_ISO_PHY_DFI_R BIT(2)
+#define CRMU_DDRPHY0_ISO_PHY_REGS_R BIT(1)
+#define CRMU_DDRPHY0_ISO_PHY_PLL_R BIT(0)
+#define CRMU_EMEM_RESET_N_R BIT(16)
+#define CRMU_EMEM_PRESET_N_R BIT(0)
+#define CRMU_SWREG_CTRL_ADDR (CRMU_TCI_BASE + 0x6c)
+#define CRMU_AON_CTRL1 (CRMU_TCI_BASE + 0x70)
+#define CRMU_AON_CTRL1__LCPLL1_ISO_IN 18
+#define CRMU_AON_CTRL1__LCPLL1_PWRON_LDO 19
+#define CRMU_AON_CTRL1__LCPLL1_PWR_ON 20
+#define CRMU_AON_CTRL1__LCPLL0_ISO_IN 21
+#define CRMU_AON_CTRL1__LCPLL0_PWRON_LDO 22
+#define CRMU_AON_CTRL1__LCPLL0_PWR_ON 23
+#define CRMU_PCIE_LCPLL_PWR_ON_SHIFT 29
+#define CRMU_PCIE_LCPLL_PWR_ON_MASK BIT(CRMU_PCIE_LCPLL_PWR_ON_SHIFT)
+#define CRMU_PCIE_LCPLL_PWRON_LDO_SHIFT 28
+#define CRMU_PCIE_LCPLL_PWRON_LDO_MASK BIT(CRMU_PCIE_LCPLL_PWRON_LDO_SHIFT)
+#define CRMU_PCIE_LCPLL_ISO_IN_SHIFT 27
+#define CRMU_PCIE_LCPLL_ISO_IN_MASK BIT(CRMU_PCIE_LCPLL_ISO_IN_SHIFT)
+#define CRMU_MASTER_AXI_ARUSER_CONFIG (CRMU_TCI_BASE + 0x74)
+#define CRMU_MASTER_AXI_AWUSER_CONFIG (CRMU_TCI_BASE + 0x78)
+#define CRMU_DDR_PHY_AON_CTRL_1 (CRMU_TCI_BASE + 0x8c)
+
+#define CDRU_BASE_ADDR (CRMU_CORE_BASE + 0x1000)
+#define CDRU_MISC_RESET_CONTROL CDRU_BASE_ADDR
+#define CDRU_MISC_RESET_CONTROL_TS_RESET_N 16
+#define CDRU_MISC_RESET_CONTROL__CDRU_USBSS_RESET_N 14
+#define CDRU_MISC_RESET_CONTROL__CDRU_SATA_RESET_N_R 15
+#define CDRU_MISC_RESET_CONTROL__CDRU_MHB_RESET_N_R 13
+#define CDRU_MISC_RESET_CONTROL__CDRU_PCIE_RESET_N_R 3
+#define CDRU_MISC_RESET_CONTROL__CDRU_PM_RESET_N_R 2
+#define CDRU_MISC_RESET_CONTROL__CDRU_NITRO_RESET_N_R 1
+
+#define CDRU_PROC_EVENT_CLEAR (CDRU_BASE_ADDR + 0x48)
+#define CDRU_PROC_EVENT_CLEAR__IH0_CDRU_STANDBYWFIL2 0
+#define CDRU_PROC_EVENT_CLEAR__IH0_CDRU_STANDBYWFI 3
+#define CDRU_PROC_EVENT_CLEAR__IH1_CDRU_STANDBYWFIL2 5
+#define CDRU_PROC_EVENT_CLEAR__IH1_CDRU_STANDBYWFI 8
+#define CDRU_PROC_EVENT_CLEAR__IH2_CDRU_STANDBYWFIL2 10
+#define CDRU_PROC_EVENT_CLEAR__IH2_CDRU_STANDBYWFI 13
+#define CDRU_PROC_EVENT_CLEAR__IH3_CDRU_STANDBYWFIL2 15
+#define CDRU_PROC_EVENT_CLEAR__IH3_CDRU_STANDBYWFI 18
+
+#define CDRU_CHIP_STRAP_CTRL (CDRU_BASE_ADDR + 0x50)
+#define CDRU_CHIP_STRAP_CTRL__SOFTWARE_OVERRIDE 31
+
+#define CDRU_CHIP_IO_PAD_CONTROL (CDRU_BASE_ADDR + 0x58)
+#define CDRU_CHIP_IO_PAD_CONTROL__CDRU_IOMUX_FORCE_PDN_R 8
+#define CDRU_CHIP_IO_PAD_CONTROL__CDRU_IOMUX_FORCE_PAD_IN_R 0
+
+#define CDRU_CHIP_STRAP_DATA_LSW (CDRU_BASE_ADDR + 0x5c)
+#define CDRU_CHIP_STRAP_DATA_LSW__BISR_BYPASS_MODE 18
+#define CDRU_CHIP_STRAP_DATA_LSW__NIC_MODE_MASK BIT(8)
+#define CDRU_CHIP_STRAP_DATA_LSW_PAD_USB_MODE BIT(26)
+
+#define CDRU_CHIP_STRAP_DATA (CDRU_BASE_ADDR + 0x5c)
+#define CDRU_DDR0_CONTROL_OFFSET (CDRU_BASE_ADDR + 0xb8)
+#define CDRU_DDR1_CONTROL_OFFSET (CDRU_BASE_ADDR + 0xbc)
+#define CDRU_DDR2_CONTROL_OFFSET (CDRU_BASE_ADDR + 0xc0)
+#define CRMU_SW_POR_RESET_CTRL (CDRU_BASE_ADDR + 0x100)
+
+#define CDRU_GENPLL2_CONTROL1 (CDRU_BASE_ADDR + 0x1b0)
+#define CDRU_GENPLL2_CONTROL1__CHNL6_FS4_CLK BIT(11)
+#define CDRU_GENPLL5_CONTROL1 (CDRU_BASE_ADDR + 0x24c)
+#define CDRU_GENPLL5_CONTROL1__CHNL0_DME_CLK BIT(6)
+#define CDRU_GENPLL5_CONTROL1__CHNL1_CRYPTO_AE_CLK BIT(7)
+#define CDRU_GENPLL5_CONTROL1__CHNL2_RAID_AE_CLK BIT(8)
+
+#define CDRU_NITRO_CONTROL (CDRU_BASE_ADDR + 0x2c4)
+#define CDRU_NITRO_CONTROL__CDRU_NITRO_SEC_MODE_R 20
+#define CDRU_NITRO_CONTROL__CDRU_NITRO_SEC_OVERRIDE_R 16
+
+#define CDRU_MISC_CLK_ENABLE_CONTROL (CDRU_BASE_ADDR + 0x2c8)
+#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_EMEM2_CLK_EN_R 11
+#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_EMEM1_CLK_EN_R 10
+#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_EMEM0_CLK_EN_R 9
+#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_SATA_CLK_EN_R 8
+#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_USBSS_CLK_EN_R 7
+#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_MHB_CLK_EN_R 6
+#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_HSLS_CLK_EN_R 5
+#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_SCR_CLK_EN_R 4
+#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_FS4_CLK_EN_R 3
+#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_PCIE_CLK_EN_R 2
+#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_PM_CLK_EN_R 1
+#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_NITRO_CLK_EN_R 0
+
+#define CDRU_CCN_REGISTER_CONTROL_1 (CDRU_BASE_ADDR + 0x324)
+#define CDRU_CCN_REGISTER_CONTROL_1__D2XS_PD_EMEM0_BIT 6
+#define CDRU_CCN_REGISTER_CONTROL_1__D2XS_PD_EMEM1_BIT 5
+#define CDRU_CCN_REGISTER_CONTROL_1__D2XS_PD_EMEM2_BIT 4
+
+#define CDRU_CHIP_TOP_SPARE_REG0 (CDRU_BASE_ADDR + 0x378)
+#define CDRU_CHIP_TOP_SPARE_REG1 (CDRU_BASE_ADDR + 0x37c)
+
+#define CENTRAL_TIMER_BASE (CRMU_CORE_BASE + 0x5000)
+#define CENTRAL_TIMER_CTRL (CENTRAL_TIMER_BASE + 0x0)
+#define CENTRAL_TIMER_GET_L (CENTRAL_TIMER_BASE + 0x4)
+#define CENTRAL_TIMER_GET_L0 (CENTRAL_TIMER_BASE + 0x8) /* SCR STM */
+#define CENTRAL_TIMER_GET_L1 (CENTRAL_TIMER_BASE + 0xC) /* FS STM */
+#define CENTRAL_TIMER_GET_L2 (CENTRAL_TIMER_BASE + 0x10) /* iHost0 */
+#define CENTRAL_TIMER_GET_L3 (CENTRAL_TIMER_BASE + 0x14) /* iHost1 */
+#define CENTRAL_TIMER_GET_L4 (CENTRAL_TIMER_BASE + 0x18) /* iHost2 */
+#define CENTRAL_TIMER_GET_L5 (CENTRAL_TIMER_BASE + 0x1C) /* iHost3 */
+#define CENTRAL_TIMER_GET_H (CENTRAL_TIMER_BASE + 0x28)
+#define CENTRAL_TIMER_SAT_TMR_ENA (CENTRAL_TIMER_BASE + 0x34)
+#define CENTRAL_TIMER_GET_IHOST_ENA_BASE (CENTRAL_TIMER_GET_L2)
+
+#define CRMU_WDT_REGS_BASE (CRMU_CORE_BASE + 0x6000)
+
+#define CRMU_MAIL_BOX0 (CRMU_CORE_BASE + 0x8024)
+#define CRMU_MAIL_BOX1 (CRMU_CORE_BASE + 0x8028)
+#define CRMU_READ_MAIL_BOX0 (CRMU_CORE_BASE + 0x802c)
+#define CRMU_READ_MAIL_BOX1 (CRMU_CORE_BASE + 0x8030)
+#define AP_TO_SCP_MAILBOX1 CRMU_MAIL_BOX1
+#define SCP_TO_AP_MAILBOX1 CRMU_READ_MAIL_BOX1
+#define CRMU_IHOST_POWER_CONFIG (CRMU_CORE_BASE + 0x8038)
+#define CRMU_RESET_EVENT_LOG (CRMU_CORE_BASE + 0x8064)
+#define CRMU_SOFT_RESET_CTRL (CRMU_CORE_BASE + 0x8090)
+#define CRMU_SOFT_RESET_CTRL__SOFT_PWR_UP_RST 0
+#define CRMU_SOFT_RESET_CTRL__SOFT_SYS_RST 1
+#define CRMU_SPARE_REG_0 (CRMU_CORE_BASE + 0x80b8)
+#define CRMU_SPARE_REG_1 (CRMU_CORE_BASE + 0x80bc)
+#define CRMU_SPARE_REG_2 (CRMU_CORE_BASE + 0x80c0)
+#define CRMU_SPARE_REG_3 (CRMU_CORE_BASE + 0x80c4)
+#define CRMU_SPARE_REG_4 (CRMU_CORE_BASE + 0x80c8)
+#define CRMU_SPARE_REG_5 (CRMU_CORE_BASE + 0x80cc)
+#define CRMU_CORE_ADDR_RANGE0_LOW (CRMU_CORE_BASE + 0x8c30)
+#define CRMU_CORE_ADDR_RANGE1_LOW (CRMU_CORE_BASE + 0x8c38)
+#define CRMU_CORE_ADDR_RANGE2_LOW (CRMU_CORE_BASE + 0x8c40)
+#define CRMU_IHOST_SW_PERSISTENT_REG0 (CRMU_CORE_BASE + 0x8c54)
+#define CRMU_IHOST_SW_PERSISTENT_REG1 (CRMU_CORE_BASE + 0x8c58)
+#define CRMU_IHOST_SW_PERSISTENT_REG2 (CRMU_CORE_BASE + 0x8c5c)
+#define CRMU_IHOST_SW_PERSISTENT_REG3 (CRMU_CORE_BASE + 0x8c60)
+#define CRMU_IHOST_SW_PERSISTENT_REG4 (CRMU_CORE_BASE + 0x8c64)
+#define CRMU_IHOST_SW_PERSISTENT_REG5 (CRMU_CORE_BASE + 0x8c68)
+#define CRMU_IHOST_SW_PERSISTENT_REG6 (CRMU_CORE_BASE + 0x8c6c)
+#define CRMU_IHOST_SW_PERSISTENT_REG7 (CRMU_CORE_BASE + 0x8c70)
+#define CRMU_BBL_AUTH_CHECK (CRMU_CORE_BASE + 0x8c78)
+#define CRMU_SOTP_NEUTRALIZE_ENABLE (CRMU_CORE_BASE + 0x8c84)
+#define CRMU_IHOST_SW_PERSISTENT_REG8 (CRMU_CORE_BASE + 0x8c88)
+#define CRMU_IHOST_SW_PERSISTENT_REG9 (CRMU_CORE_BASE + 0x8c8c)
+#define CRMU_IHOST_SW_PERSISTENT_REG10 (CRMU_CORE_BASE + 0x8c90)
+#define CRMU_IHOST_SW_PERSISTENT_REG11 (CRMU_CORE_BASE + 0x8c94)
+
+#define CNT_CONTROL_BASE (CRMU_CORE_BASE + 0x9000)
+#define CNTCR (CNT_CONTROL_BASE)
+#define CNTCR__EN BIT(0)
+
+#define SPRU_BBL_WDATA (CRMU_CORE_BASE + 0xa000)
+#define SPRU_BBL_CMD (CRMU_CORE_BASE + 0xa004)
+#define SPRU_BBL_CMD__IND_SOFT_RST_N 10
+#define SPRU_BBL_CMD__IND_WR 11
+#define SPRU_BBL_CMD__BBL_ADDR_R 0
+#define SPRU_BBL_CMD__IND_RD 12
+#define SPRU_BBL_CMD__BBL_ADDR_R 0
+#define SPRU_BBL_STATUS (CRMU_CORE_BASE + 0xa008)
+#define SPRU_BBL_STATUS__ACC_DONE 0
+#define SPRU_BBL_RDATA (CRMU_CORE_BASE + 0xa00c)
+
+#endif /* CRMU_DEF_H */
diff --git a/plat/brcm/board/stingray/include/ddr_init.h b/plat/brcm/board/stingray/include/ddr_init.h
new file mode 100644
index 0000000..0c135b1
--- /dev/null
+++ b/plat/brcm/board/stingray/include/ddr_init.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DDR_INIT_H
+#define DDR_INIT_H
+
+#include <fru.h>
+
+#pragma weak ddr_initialize
+#pragma weak ddr_secure_region_config
+#pragma weak ddr_info_save
+#pragma weak get_active_ddr_channel
+#pragma weak is_warmboot
+
+void ddr_initialize(struct ddr_info *ddr)
+{
+}
+
+void ddr_secure_region_config(uint64_t start, uint64_t end)
+{
+}
+
+void ddr_info_save(void)
+{
+}
+
+unsigned char get_active_ddr_channel(void)
+{
+ return 0;
+}
+
+static inline unsigned int is_warmboot(void)
+{
+ return 0;
+}
+#endif
diff --git a/plat/brcm/board/stingray/include/fsx.h b/plat/brcm/board/stingray/include/fsx.h
new file mode 100644
index 0000000..c52ff0a
--- /dev/null
+++ b/plat/brcm/board/stingray/include/fsx.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FSX_H
+#define FSX_H
+
+#include <stdbool.h>
+
+typedef enum FSX_TYPE {
+ eFS4_RAID,
+ eFS4_CRYPTO,
+ eFS6_PKI,
+} eFSX_TYPE;
+
+void fsx_init(eFSX_TYPE fsx_type,
+ unsigned int ring_count,
+ unsigned int dme_count,
+ unsigned int ae_count,
+ unsigned int start_stream_id,
+ unsigned int msi_dev_id,
+ uintptr_t idm_io_control_direct,
+ uintptr_t idm_reset_control,
+ uintptr_t base,
+ uintptr_t dme_base);
+
+void fsx_meminit(const char *name,
+ uintptr_t idm_io_control_direct,
+ uintptr_t idm_io_status);
+
+void fs4_disable_clocks(bool disable_sram,
+ bool disable_crypto,
+ bool disable_raid);
+
+#endif /* FSX_H */
diff --git a/plat/brcm/board/stingray/include/ihost_pm.h b/plat/brcm/board/stingray/include/ihost_pm.h
new file mode 100644
index 0000000..83493ab
--- /dev/null
+++ b/plat/brcm/board/stingray/include/ihost_pm.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IHOST_PM
+#define IHOST_PM
+
+#include <stdint.h>
+
+#define CLUSTER_POWER_ON 0x1
+#define CLUSTER_POWER_OFF 0x0
+
+void ihost_power_on_cluster(u_register_t mpidr);
+void ihost_power_on_secondary_core(u_register_t mpidr, uint64_t rvbar);
+void ihost_enable_satellite_timer(unsigned int cluster_id);
+
+#endif
diff --git a/plat/brcm/board/stingray/include/iommu.h b/plat/brcm/board/stingray/include/iommu.h
new file mode 100644
index 0000000..e7b2985
--- /dev/null
+++ b/plat/brcm/board/stingray/include/iommu.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IOMMU_H
+#define IOMMU_H
+
+enum iommu_domain {
+ PCIE_PAXC,
+ DOMAIN_CRMU,
+};
+
+void arm_smmu_create_identity_map(enum iommu_domain dom);
+void arm_smmu_reserve_secure_cntxt(void);
+void arm_smmu_enable_secure_client_port(void);
+
+#endif /* IOMMU_H */
diff --git a/plat/brcm/board/stingray/include/ncsi.h b/plat/brcm/board/stingray/include/ncsi.h
new file mode 100644
index 0000000..04dd640
--- /dev/null
+++ b/plat/brcm/board/stingray/include/ncsi.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NCSI_H
+#define NCSI_H
+
+/*
+ * There are 10 registers for NCSI IO drivers.
+ */
+#define NITRO_NCSI_IOPAD_CONTROL_NUM 10
+#define NITRO_NCSI_IOPAD_CONTROL_BASE 0x60e05080
+
+/*
+ * NCSI IO Drive strength
+ * 000 - Drives 2mA
+ * 001 - Drives 4mA
+ * 010 - Drives 6mA
+ * 011 - Drives 8mA
+ * 100 - Drives 10mA
+ * 101 - Drives 12mA
+ * 110 - Drives 14mA
+ * 111 - Drives 16mA
+ */
+#define PAD_SELX_VALUE(selx) ((selx) << 1)
+#define PAD_SELX_MASK (0x7 << 1)
+
+void brcm_stingray_ncsi_init(void);
+
+#endif
diff --git a/plat/brcm/board/stingray/include/paxb.h b/plat/brcm/board/stingray/include/paxb.h
new file mode 100644
index 0000000..c64c8a6
--- /dev/null
+++ b/plat/brcm/board/stingray/include/paxb.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PAXB_H
+#define PAXB_H
+
+/* total number of PCIe cores */
+#define NUM_OF_SR_PCIE_CORES 8
+#define NUM_OF_NS3Z_PCIE_CORES 1
+
+/*
+ * List of PCIe core and PAXB wrapper memory power registers
+ */
+#define PCIE_CORE_BASE 0x40000800
+#define PCIE_CORE_SOFT_RST_CFG_BASE (PCIE_CORE_BASE + 0x40)
+#define PCIE_CORE_SOFT_RST 0x1
+#define PCIE_CORE_ISO_CFG_BASE (PCIE_CORE_BASE + 0x54)
+#define PCIE_CORE_MEM_ISO 0x2
+#define PCIE_CORE_ISO 0x1
+
+#define PCIE_CORE_MEM_PWR_BASE (PCIE_CORE_BASE + 0x58)
+#define PCIE_PAXB_MEM_PWR_BASE (PCIE_CORE_BASE + 0x5c)
+#define PCIE_CORE_PMI_CFG_BASE (PCIE_CORE_BASE + 0x64)
+#define PCIE_CORE_RESERVED_CFG (PCIE_CORE_BASE + 0x6c)
+#define PCIE_CORE_MEM_PWR_STATUS_BASE (PCIE_CORE_BASE + 0x74)
+#define PCIE_PAXB_MEM_PWR_STATUS_BASE (PCIE_CORE_BASE + 0x78)
+#define PCIE_CORE_PWR_OFFSET 0x100
+
+#define SR_A0_DEVICE_ID 0xd713
+#define SR_B0_DEVICE_ID 0xd714
+/* TODO: Modify device ID once available */
+#define NS3Z_DEVICE_ID 0xd715
+
+/* FIXME: change link speed to GEN3 when it's ready */
+#define GEN1_LINK_SPEED 1
+#define GEN2_LINK_SPEED 2
+#define GEN3_LINK_SPEED 3
+
+typedef struct {
+ uint32_t type;
+ uint32_t device_id;
+ uint32_t pipemux_idx;
+ uint32_t num_cores;
+ int (*pipemux_init)(void);
+ int (*phy_init)(void);
+ int (*core_needs_enable)(unsigned int core_idx);
+ unsigned int (*get_link_width)(unsigned int core_idx);
+ unsigned int (*get_link_speed)(void);
+} paxb_cfg;
+
+enum paxb_type {
+ PAXB_SR,
+ PAXB_NS3Z,
+};
+
+extern const paxb_cfg *paxb;
+
+#ifdef USE_PAXB
+void paxb_init(void);
+void paxb_rc_cfg_write(unsigned int core_idx, unsigned int where,
+ uint32_t val);
+unsigned int paxb_rc_cfg_read(unsigned int core_idx, unsigned int where);
+int pcie_core_needs_enable(unsigned int core_idx);
+const paxb_cfg *paxb_get_sr_config(void);
+#else
+static inline void paxb_init(void)
+{
+}
+#endif
+
+#endif /* PAXB_H */
diff --git a/plat/brcm/board/stingray/include/paxc.h b/plat/brcm/board/stingray/include/paxc.h
new file mode 100644
index 0000000..ae1af2e
--- /dev/null
+++ b/plat/brcm/board/stingray/include/paxc.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PAXC_H
+#define PAXC_H
+
+#ifdef USE_PAXC
+void paxc_init(void);
+void paxc_mhb_ns_init(void);
+#else
+static inline void paxc_init(void)
+{
+}
+
+static inline void paxc_mhb_ns_init(void)
+{
+}
+#endif
+
+#endif /* PAXC_H */
diff --git a/plat/brcm/board/stingray/include/plat_macros.S b/plat/brcm/board/stingray/include/plat_macros.S
new file mode 100644
index 0000000..dccd54a
--- /dev/null
+++ b/plat/brcm/board/stingray/include/plat_macros.S
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+.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 registers whenever an
+ * unhandled exception is taken in BL31.
+ * ---------------------------------------------
+ */
+.macro plat_crash_print_regs
+ nop
+.endm
+
+/* ---------------------------------------------
+ * The below macro prints out relevant GIC
+ * registers whenever an unhandled exception is
+ * taken in BL31.
+ * ---------------------------------------------
+ */
+.macro plat_print_gic_regs
+ nop
+ /*TBD-STINGRAY*/
+.endm
+
+/* ------------------------------------------------
+ * The below required platform porting macro prints
+ * out relevant interconnect registers whenever an
+ * unhandled exception is taken in BL3-1.
+ * ------------------------------------------------
+ */
+.macro plat_print_interconnect_regs
+ nop
+ /*TBD-STINGRAY*/
+.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/brcm/board/stingray/include/platform_def.h b/plat/brcm/board/stingray/include/platform_def.h
new file mode 100644
index 0000000..4742124
--- /dev/null
+++ b/plat/brcm/board/stingray/include/platform_def.h
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2015-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <plat/common/common_def.h>
+
+#include <brcm_def.h>
+#include "sr_def.h"
+#include <cmn_plat_def.h>
+
+/*
+ * Most platform porting definitions provided by included headers
+ */
+#define PLAT_BRCM_SCP_TZC_DRAM1_SIZE ULL(0x0)
+
+/*
+ * Required by standard platform porting definitions
+ */
+#define PLATFORM_CLUSTER0_CORE_COUNT 2
+#define PLATFORM_CLUSTER1_CORE_COUNT 2
+#define PLATFORM_CLUSTER2_CORE_COUNT 2
+#define PLATFORM_CLUSTER3_CORE_COUNT 2
+
+#define BRCM_SYSTEM_COUNT 1
+#define BRCM_CLUSTER_COUNT 4
+
+#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT + \
+ PLATFORM_CLUSTER1_CORE_COUNT+ \
+ PLATFORM_CLUSTER2_CORE_COUNT+ \
+ PLATFORM_CLUSTER3_CORE_COUNT)
+
+#define PLAT_NUM_PWR_DOMAINS (BRCM_SYSTEM_COUNT + \
+ BRCM_CLUSTER_COUNT + \
+ PLATFORM_CORE_COUNT)
+
+#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2
+
+/* TBD-STINGRAY */
+#define CACHE_WRITEBACK_SHIFT 6
+/*
+ * 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 << CACHE_WRITEBACK_SHIFT)
+
+/* TBD-STINGRAY */
+#define PLATFORM_MAX_AFFLVL MPIDR_AFFLVL1
+
+#define BL1_PLATFORM_STACK_SIZE 0x3300
+#define BL2_PLATFORM_STACK_SIZE 0xc000
+#define BL11_PLATFORM_STACK_SIZE 0x2b00
+#define DEFAULT_PLATFORM_STACK_SIZE 0x400
+#if IMAGE_BL1
+# define PLATFORM_STACK_SIZE BL1_PLATFORM_STACK_SIZE
+#else
+#if IMAGE_BL2
+#ifdef USE_BL1_RW
+# define PLATFORM_STACK_SIZE BL2_PLATFORM_STACK_SIZE
+#else
+# define PLATFORM_STACK_SIZE BL1_PLATFORM_STACK_SIZE
+#endif
+#else
+#if IMAGE_BL11
+# define PLATFORM_STACK_SIZE BL11_PLATFORM_STACK_SIZE
+#else
+# define PLATFORM_STACK_SIZE DEFAULT_PLATFORM_STACK_SIZE
+#endif
+#endif
+#endif
+
+#define PLAT_BRCM_TRUSTED_SRAM_BASE 0x66D00000
+#define PLAT_BRCM_TRUSTED_SRAM_SIZE 0x00040000
+
+#ifdef RUN_BL1_FROM_QSPI /* BL1 XIP from QSPI */
+# define PLAT_BRCM_TRUSTED_ROM_BASE QSPI_BASE_ADDR
+#elif RUN_BL1_FROM_NAND /* BL1 XIP from NAND */
+# define PLAT_BRCM_TRUSTED_ROM_BASE NAND_BASE_ADDR
+#else /* BL1 executed in ROM */
+# define PLAT_BRCM_TRUSTED_ROM_BASE ROM_BASE_ADDR
+#endif
+#define PLAT_BRCM_TRUSTED_ROM_SIZE 0x00040000
+
+/*******************************************************************************
+ * BL1 specific defines.
+ ******************************************************************************/
+#define BL1_RO_BASE PLAT_BRCM_TRUSTED_ROM_BASE
+#define BL1_RO_LIMIT (PLAT_BRCM_TRUSTED_ROM_BASE \
+ + PLAT_BRCM_TRUSTED_ROM_SIZE)
+
+/*
+ * Put BL1 RW at the beginning of the Trusted SRAM.
+ */
+#define BL1_RW_BASE (BRCM_BL_RAM_BASE)
+#define BL1_RW_LIMIT (BL1_RW_BASE + 0x12000)
+
+#define BL11_RW_BASE BL1_RW_LIMIT
+#define BL11_RW_LIMIT (PLAT_BRCM_TRUSTED_SRAM_BASE + \
+ PLAT_BRCM_TRUSTED_SRAM_SIZE)
+
+/*******************************************************************************
+ * BL2 specific defines.
+ ******************************************************************************/
+#if RUN_BL2_FROM_QSPI /* BL2 XIP from QSPI */
+#define BL2_BASE QSPI_BASE_ADDR
+#define BL2_LIMIT (BL2_BASE + 0x40000)
+#define BL2_RW_BASE BL1_RW_LIMIT
+#define BL2_RW_LIMIT (PLAT_BRCM_TRUSTED_SRAM_BASE + \
+ PLAT_BRCM_TRUSTED_SRAM_SIZE)
+#elif RUN_BL2_FROM_NAND /* BL2 XIP from NAND */
+#define BL2_BASE NAND_BASE_ADDR
+#define BL2_LIMIT (BL2_BASE + 0x40000)
+#define BL2_RW_BASE BL1_RW_LIMIT
+#define BL2_RW_LIMIT (PLAT_BRCM_TRUSTED_SRAM_BASE + \
+ PLAT_BRCM_TRUSTED_SRAM_SIZE)
+#else
+#define BL2_BASE (BL1_RW_LIMIT + PAGE_SIZE)
+#define BL2_LIMIT (BRCM_BL_RAM_BASE + BRCM_BL_RAM_SIZE)
+#endif
+
+/*
+ * BL1 persistent area in internal SRAM
+ * This area will increase as more features gets into BL1
+ */
+#define BL1_PERSISTENT_DATA_SIZE 0x2000
+
+/* To reduce BL2 runtime footprint, we can re-use some BL1_RW area */
+#define BL1_RW_RECLAIM_BASE (PLAT_BRCM_TRUSTED_SRAM_BASE + \
+ BL1_PERSISTENT_DATA_SIZE)
+
+/*******************************************************************************
+ * BL3-1 specific defines.
+ ******************************************************************************/
+/* Max Size of BL31 (in DRAM) */
+#define PLAT_BRCM_MAX_BL31_SIZE 0x30000
+
+#ifdef USE_DDR
+#define BL31_BASE BRCM_AP_TZC_DRAM1_BASE
+
+#define BL31_LIMIT (BRCM_AP_TZC_DRAM1_BASE + \
+ PLAT_BRCM_MAX_BL31_SIZE)
+#else
+/* Put BL3-1 at the end of external on-board SRAM connected as NOR flash */
+#define BL31_BASE (NOR_BASE_ADDR + NOR_SIZE - \
+ PLAT_BRCM_MAX_BL31_SIZE)
+
+#define BL31_LIMIT (NOR_BASE_ADDR + NOR_SIZE)
+#endif
+
+#define SECURE_DDR_END_ADDRESS BL31_LIMIT
+
+#ifdef NEED_SCP_BL2
+#define SCP_BL2_BASE BL31_BASE
+#define PLAT_MAX_SCP_BL2_SIZE 0x9000
+#define PLAT_SCP_COM_SHARED_MEM_BASE (CRMU_SHARED_SRAM_BASE)
+/* dummy defined */
+#define PLAT_BRCM_MHU_BASE 0x0
+#endif
+
+#define SECONDARY_CPU_SPIN_BASE_ADDR BRCM_SHARED_RAM_BASE
+
+/* Generic system timer counter frequency */
+#ifndef SYSCNT_FREQ
+#define SYSCNT_FREQ (125 * 1000 * 1000)
+#endif
+
+/*
+ * Enable the BL32 definitions, only when optee os is selected as secure
+ * payload (BL32).
+ */
+#ifdef SPD_opteed
+/*
+ * Reserved Memory Map : SHMEM & TZDRAM.
+ *
+ * +--------+----------+ 0x8D000000
+ * | SHMEM (NS) | 16MB
+ * +-------------------+ 0x8E000000
+ * | | TEE_RAM(S)| 4MB
+ * + TZDRAM +----------+ 0x8E400000
+ * | | TA_RAM(S) | 12MB
+ * +-------------------+ 0x8F000000
+ * | BL31 Binary (S) | 192KB
+ * +-------------------+ 0x8F030000
+ */
+
+#define BL32_VA_SIZE (4 * 1024 * 1024)
+#define BL32_BASE (0x8E000000)
+#define BL32_LIMIT (BL32_BASE + BL32_VA_SIZE)
+#define TSP_SEC_MEM_BASE BL32_BASE
+#define TSP_SEC_MEM_SIZE BL32_VA_SIZE
+#endif
+
+#ifdef SPD_opteed
+ #define SECURE_DDR_BASE_ADDRESS BL32_BASE
+#else
+ #define SECURE_DDR_BASE_ADDRESS BL31_BASE
+#endif
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+
+#define MAX_XLAT_TABLES 7
+
+#define PLAT_BRCM_MMAP_ENTRIES 10
+
+#define MAX_MMAP_REGIONS (PLAT_BRCM_MMAP_ENTRIES + \
+ BRCM_BL_REGIONS)
+
+#ifdef USE_DDR
+#ifdef BL33_OVERRIDE_LOAD_ADDR
+#define PLAT_BRCM_NS_IMAGE_OFFSET BL33_OVERRIDE_LOAD_ADDR
+#else
+/*
+ * BL3-3 image starting offset.
+ * Putting start of DRAM as of now.
+ */
+#define PLAT_BRCM_NS_IMAGE_OFFSET 0x80000000
+#endif /* BL33_OVERRIDE_LOAD_ADDR */
+#else
+/*
+ * BL3-3 image starting offset.
+ * Putting start of external on-board SRAM as of now.
+ */
+#define PLAT_BRCM_NS_IMAGE_OFFSET NOR_BASE_ADDR
+#endif /* USE_DDR */
+/******************************************************************************
+ * Required platform porting definitions common to all BRCM platforms
+ *****************************************************************************/
+
+#define MAX_IO_DEVICES 5
+#define MAX_IO_HANDLES 6
+
+#define PRIMARY_CPU 0
+
+/* GIC Parameter */
+#define PLAT_BRCM_GICD_BASE GIC500_BASE
+#define PLAT_BRCM_GICR_BASE (GIC500_BASE + 0x200000)
+
+/* Define secure interrupt as per Group here */
+#define PLAT_BRCM_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(BRCM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(BRCM_IRQ_SEC_SPI_0, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+ GIC_INTR_CFG_EDGE)
+
+#define PLAT_BRCM_G0_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(BRCM_IRQ_SEC_SGI_0, PLAT_SDEI_NORMAL_PRI, (grp), \
+ GIC_INTR_CFG_EDGE), \
+
+/*
+ *CCN 502 related constants.
+ */
+#define PLAT_BRCM_CLUSTER_COUNT 4 /* Number of RN-F Masters */
+#define PLAT_BRCM_CLUSTER_TO_CCN_ID_MAP CLUSTER0_NODE_ID, CLUSTER1_NODE_ID, CLUSTER2_NODE_ID, CLUSTER3_NODE_ID
+#define CCN_SIZE 0x1000000
+#define CLUSTER0_NODE_ID 1
+#define CLUSTER1_NODE_ID 7
+#define CLUSTER2_NODE_ID 9
+#define CLUSTER3_NODE_ID 15
+
+#endif
diff --git a/plat/brcm/board/stingray/include/platform_sotp.h b/plat/brcm/board/stingray/include/platform_sotp.h
new file mode 100644
index 0000000..0389f38
--- /dev/null
+++ b/plat/brcm/board/stingray/include/platform_sotp.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_SOTP_H
+#define PLATFORM_SOTP_H
+
+#define SOTP_DEVICE_SECURE_CFG0_ROW 17
+#define SOTP_DEVICE_SECURE_CFG1_ROW 18
+#define SOTP_DEVICE_SECURE_CFG2_ROW 19
+#define SOTP_DEVICE_SECURE_CFG3_ROW 20
+#define SOTP_BRCM_SOFTWARE_CFG0_ROW 21
+#define SOTP_BRCM_SOFTWARE_CFG1_ROW 22
+#define SOTP_BRCM_SOFTWARE_CFG2_ROW 23
+#define SOTP_BRCM_SOFTWARE_CFG3_ROW 24
+#define SOTP_CUSTOMER_ID_CFG0_ROW 25
+#define SOTP_CUSTOMER_ID_CFG1_ROW 26
+#define SOTP_CUSTOMER_ID_CFG2_ROW 27
+#define SOTP_CUSTOMER_ID_CFG3_ROW 28
+#define SOTP_CUSTOMER_DEV_CFG0_ROW 29
+#define SOTP_CUSTOMER_DEV_CFG1_ROW 30
+#define SOTP_CUSTOMER_DEV_CFG2_ROW 31
+#define SOTP_CUSTOMER_DEV_CFG3_ROW 32
+#define SOTP_DAUTH_ROW 33
+#define SOTP_K_HMAC_ROW 45
+#define SOTP_K_AES_ROW 57
+#define SOTP_NVCOUNTER_ROW 69
+
+#define SOTP_BRCM_CFG_ECC_ERROR_MASK 0x100000
+#define SOTP_DAUTH_ECC_ERROR_MASK 0x800000
+#define SOTP_K_HMAC_ECC_ERROR_MASK 0x1000000
+#define SOTP_K_AES_ECC_ERROR_MASK 0x2000000
+
+#endif
diff --git a/plat/brcm/board/stingray/include/platform_usb.h b/plat/brcm/board/stingray/include/platform_usb.h
new file mode 100644
index 0000000..5b5309f
--- /dev/null
+++ b/plat/brcm/board/stingray/include/platform_usb.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2019 - 2021, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_USB_H
+#define PLATFORM_USB_H
+
+#include <platform_def.h>
+
+#define USB3_DRD BIT(0U)
+#define USB3H_USB2DRD BIT(1U)
+
+extern const unsigned int xhc_portsc_reg_offset[MAX_USB_PORTS];
+
+void xhci_phy_init(void);
+
+#endif /* PLATFORM_USB_H */
diff --git a/plat/brcm/board/stingray/include/scp_cmd.h b/plat/brcm/board/stingray/include/scp_cmd.h
new file mode 100644
index 0000000..806ef56
--- /dev/null
+++ b/plat/brcm/board/stingray/include/scp_cmd.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SCP_CMD_H
+#define SCP_SMD_H
+
+#include <stdint.h>
+
+typedef struct {
+ int cmd;
+ int completed;
+ int ret;
+} crmu_response_t;
+
+
+#define SCP_CMD_MASK 0xffff
+#define SCP_CMD_DEFAULT_TIMEOUT_US 1000
+#define SCP_CMD_SCP_BOOT_TIMEOUT_US 5000
+
+int scp_send_cmd(uint32_t cmd, uint32_t param, uint32_t timeout);
+
+#endif
diff --git a/plat/brcm/board/stingray/include/scp_utils.h b/plat/brcm/board/stingray/include/scp_utils.h
new file mode 100644
index 0000000..c39b18c
--- /dev/null
+++ b/plat/brcm/board/stingray/include/scp_utils.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SCP_UTILS_H
+#define SCP_UTILS_H
+
+#include <common/bl_common.h>
+#include <lib/mmio.h>
+
+#include <m0_cfg.h>
+
+int plat_bcm_bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info);
+
+bool is_crmu_alive(void);
+bool bcm_scp_issue_sys_reset(void);
+
+#define SCP_READ_CFG(cfg) mmio_read_32(CRMU_CFG_BASE + \
+ offsetof(M0CFG, cfg))
+#define SCP_WRITE_CFG(cfg, value) mmio_write_32(CRMU_CFG_BASE + \
+ offsetof(M0CFG, cfg), value)
+
+#define SCP_READ_CFG16(cfg) mmio_read_16(CRMU_CFG_BASE + \
+ offsetof(M0CFG, cfg))
+#define SCP_WRITE_CFG16(cfg, value) mmio_write_16(CRMU_CFG_BASE + \
+ offsetof(M0CFG, cfg), value)
+
+#define SCP_READ_CFG8(cfg) mmio_read_8(CRMU_CFG_BASE + \
+ offsetof(M0CFG, cfg))
+#define SCP_WRITE_CFG8(cfg, value) mmio_write_8(CRMU_CFG_BASE + \
+ offsetof(M0CFG, cfg), value)
+#endif
diff --git a/plat/brcm/board/stingray/include/sdio.h b/plat/brcm/board/stingray/include/sdio.h
new file mode 100644
index 0000000..e08904e
--- /dev/null
+++ b/plat/brcm/board/stingray/include/sdio.h
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SDIO_H
+#define SDIO_H
+
+#include <stdbool.h>
+
+#define SR_IPROC_SDIO0_CFG_BASE 0x689006e4
+#define SR_IPROC_SDIO0_SID_BASE 0x68900b00
+#define SR_IPROC_SDIO0_PAD_BASE 0x68a4017c
+#define SR_IPROC_SDIO0_IOCTRL_BASE 0x68e02408
+
+#define SR_IPROC_SDIO1_CFG_BASE 0x68900734
+#define SR_IPROC_SDIO1_SID_BASE 0x68900b08
+#define SR_IPROC_SDIO1_PAD_BASE 0x68a401b4
+#define SR_IPROC_SDIO1_IOCTRL_BASE 0x68e03408
+
+#define NS3Z_IPROC_SDIO0_CFG_BASE 0x68a20540
+#define NS3Z_IPROC_SDIO0_SID_BASE 0x68900b00
+#define NS3Z_IPROC_SDIO0_TP_OUT_SEL 0x68a20308
+#define NS3Z_IPROC_SDIO0_PAD_BASE 0x68a20500
+#define NS3Z_IPROC_SDIO0_IOCTRL_BASE 0x68e02408
+
+#define PHY_BYPASS BIT(14)
+#define LEGACY_EN BIT(31)
+#define PHY_DISABLE (LEGACY_EN | PHY_BYPASS)
+
+#define NS3Z_IPROC_SDIO1_CFG_BASE 0x68a30540
+#define NS3Z_IPROC_SDIO1_SID_BASE 0x68900b08
+#define NS3Z_IPROC_SDIO1_PAD_BASE 0x68a30500
+#define NS3Z_IPROC_SDIO1_IOCTRL_BASE 0x68e03408
+
+#define ICFG_SDIO_CAP0 0x10
+#define ICFG_SDIO_CAP1 0x14
+#define ICFG_SDIO_STRAPSTATUS_0 0x0
+#define ICFG_SDIO_STRAPSTATUS_1 0x4
+#define ICFG_SDIO_STRAPSTATUS_2 0x8
+#define ICFG_SDIO_STRAPSTATUS_3 0xc
+#define ICFG_SDIO_STRAPSTATUS_4 0x18
+
+#define ICFG_SDIO_SID_ARADDR 0x0
+#define ICFG_SDIO_SID_AWADDR 0x4
+
+#define ICFG_SDIOx_CAP0__SLOT_TYPE_MASK 0x3
+#define ICFG_SDIOx_CAP0__SLOT_TYPE_SHIFT 27
+#define ICFG_SDIOx_CAP0__INT_MODE_SHIFT 26
+#define ICFG_SDIOx_CAP0__SYS_BUS_64BIT_SHIFT 25
+#define ICFG_SDIOx_CAP0__VOLTAGE_1P8V_SHIFT 24
+#define ICFG_SDIOx_CAP0__VOLTAGE_3P0V_SHIFT 23
+#define ICFG_SDIOx_CAP0__VOLTAGE_3P3V_SHIFT 22
+#define ICFG_SDIOx_CAP0__SUSPEND_RESUME_SHIFT 21
+#define ICFG_SDIOx_CAP0__SDMA_SHIFT 20
+#define ICFG_SDIOx_CAP0__HIGH_SPEED_SHIFT 19
+#define ICFG_SDIOx_CAP0__ADMA2_SHIFT 18
+#define ICFG_SDIOx_CAP0__EXTENDED_MEDIA_SHIFT 17
+#define ICFG_SDIOx_CAP0__MAX_BLOCK_LEN_MASK 0x3
+#define ICFG_SDIOx_CAP0__MAX_BLOCK_LEN_SHIFT 15
+#define ICFG_SDIOx_CAP0__BASE_CLK_FREQ_MASK 0xff
+#define ICFG_SDIOx_CAP0__BASE_CLK_FREQ_SHIFT 7
+#define ICFG_SDIOx_CAP0__TIMEOUT_UNIT_SHIFT 6
+#define ICFG_SDIOx_CAP0__TIMEOUT_CLK_FREQ_MASK 0x3f
+#define ICFG_SDIOx_CAP0__TIMEOUT_CLK_FREQ_SHIFT 0
+
+#define ICFG_SDIOx_CAP1__SPI_BLOCK_MODE_SHIFT 22
+#define ICFG_SDIOx_CAP1__SPI_MODE_SHIFT 21
+#define ICFG_SDIOx_CAP1__CLK_MULT_MASK 0xff
+#define ICFG_SDIOx_CAP1__CLK_MULT_SHIFT 13
+#define ICFG_SDIOx_CAP1__RETUNING_MODE_MASK 0x3
+#define ICFG_SDIOx_CAP1__RETUNING_MODE_SHIFT 11
+#define ICFG_SDIOx_CAP1__TUNE_SDR50_SHIFT 10
+#define ICFG_SDIOx_CAP1__TIME_RETUNE_MASK 0xf
+#define ICFG_SDIOx_CAP1__TIME_RETUNE_SHIFT 6
+#define ICFG_SDIOx_CAP1__DRIVER_D_SHIFT 5
+#define ICFG_SDIOx_CAP1__DRIVER_C_SHIFT 4
+#define ICFG_SDIOx_CAP1__DRIVER_A_SHIFT 3
+#define ICFG_SDIOx_CAP1__DDR50_SHIFT 2
+#define ICFG_SDIOx_CAP1__SDR104_SHIFT 1
+#define ICFG_SDIOx_CAP1__SDR50_SHIFT 0
+
+#ifdef USE_DDR
+#define SDIO_DMA 1
+#else
+#define SDIO_DMA 0
+#endif
+
+#define SDIO0_CAP0_CFG \
+ (0x1 << ICFG_SDIOx_CAP0__SLOT_TYPE_SHIFT) \
+ | (0x0 << ICFG_SDIOx_CAP0__INT_MODE_SHIFT) \
+ | (0x0 << ICFG_SDIOx_CAP0__SYS_BUS_64BIT_SHIFT) \
+ | (0x1 << ICFG_SDIOx_CAP0__VOLTAGE_1P8V_SHIFT) \
+ | (0x1 << ICFG_SDIOx_CAP0__VOLTAGE_3P0V_SHIFT) \
+ | (0x1 << ICFG_SDIOx_CAP0__VOLTAGE_3P3V_SHIFT) \
+ | (0x1 << ICFG_SDIOx_CAP0__SUSPEND_RESUME_SHIFT) \
+ | (SDIO_DMA << ICFG_SDIOx_CAP0__SDMA_SHIFT) \
+ | (SDIO_DMA << ICFG_SDIOx_CAP0__ADMA2_SHIFT) \
+ | (0x1 << ICFG_SDIOx_CAP0__HIGH_SPEED_SHIFT) \
+ | (0x1 << ICFG_SDIOx_CAP0__EXTENDED_MEDIA_SHIFT) \
+ | (0x2 << ICFG_SDIOx_CAP0__MAX_BLOCK_LEN_SHIFT) \
+ | (0xc8 << ICFG_SDIOx_CAP0__BASE_CLK_FREQ_SHIFT) \
+ | (0x1 << ICFG_SDIOx_CAP0__TIMEOUT_UNIT_SHIFT) \
+ | (0x30 << ICFG_SDIOx_CAP0__TIMEOUT_CLK_FREQ_SHIFT)
+
+#define SDIO0_CAP1_CFG \
+ (0x1 << ICFG_SDIOx_CAP1__SPI_BLOCK_MODE_SHIFT)\
+ | (0x1 << ICFG_SDIOx_CAP1__SPI_MODE_SHIFT)\
+ | (0x0 << ICFG_SDIOx_CAP1__CLK_MULT_SHIFT)\
+ | (0x2 << ICFG_SDIOx_CAP1__RETUNING_MODE_SHIFT)\
+ | (0x1 << ICFG_SDIOx_CAP1__TUNE_SDR50_SHIFT)\
+ | (0x0 << ICFG_SDIOx_CAP1__DRIVER_D_SHIFT)\
+ | (0x0 << ICFG_SDIOx_CAP1__DRIVER_C_SHIFT)\
+ | (0x1 << ICFG_SDIOx_CAP1__DRIVER_A_SHIFT)\
+ | (0x1 << ICFG_SDIOx_CAP1__DDR50_SHIFT)\
+ | (0x1 << ICFG_SDIOx_CAP1__SDR104_SHIFT)\
+ | (0x1 << ICFG_SDIOx_CAP1__SDR50_SHIFT)
+
+#define SDIO1_CAP0_CFG \
+ (0x0 << ICFG_SDIOx_CAP0__SLOT_TYPE_SHIFT) \
+ | (0x0 << ICFG_SDIOx_CAP0__INT_MODE_SHIFT) \
+ | (0x0 << ICFG_SDIOx_CAP0__SYS_BUS_64BIT_SHIFT) \
+ | (0x1 << ICFG_SDIOx_CAP0__VOLTAGE_1P8V_SHIFT) \
+ | (0x1 << ICFG_SDIOx_CAP0__VOLTAGE_3P0V_SHIFT) \
+ | (0x1 << ICFG_SDIOx_CAP0__VOLTAGE_3P3V_SHIFT) \
+ | (0x1 << ICFG_SDIOx_CAP0__SUSPEND_RESUME_SHIFT) \
+ | (SDIO_DMA << ICFG_SDIOx_CAP0__SDMA_SHIFT) \
+ | (SDIO_DMA << ICFG_SDIOx_CAP0__ADMA2_SHIFT) \
+ | (0x1 << ICFG_SDIOx_CAP0__HIGH_SPEED_SHIFT) \
+ | (0x1 << ICFG_SDIOx_CAP0__EXTENDED_MEDIA_SHIFT) \
+ | (0x2 << ICFG_SDIOx_CAP0__MAX_BLOCK_LEN_SHIFT) \
+ | (0xc8 << ICFG_SDIOx_CAP0__BASE_CLK_FREQ_SHIFT) \
+ | (0x1 << ICFG_SDIOx_CAP0__TIMEOUT_UNIT_SHIFT) \
+ | (0x30 << ICFG_SDIOx_CAP0__TIMEOUT_CLK_FREQ_SHIFT)
+
+#define SDIO1_CAP1_CFG \
+ (0x1 << ICFG_SDIOx_CAP1__SPI_BLOCK_MODE_SHIFT)\
+ | (0x1 << ICFG_SDIOx_CAP1__SPI_MODE_SHIFT)\
+ | (0x0 << ICFG_SDIOx_CAP1__CLK_MULT_SHIFT)\
+ | (0x2 << ICFG_SDIOx_CAP1__RETUNING_MODE_SHIFT)\
+ | (0x1 << ICFG_SDIOx_CAP1__TUNE_SDR50_SHIFT)\
+ | (0x0 << ICFG_SDIOx_CAP1__DRIVER_D_SHIFT)\
+ | (0x0 << ICFG_SDIOx_CAP1__DRIVER_C_SHIFT)\
+ | (0x1 << ICFG_SDIOx_CAP1__DRIVER_A_SHIFT)\
+ | (0x1 << ICFG_SDIOx_CAP1__DDR50_SHIFT)\
+ | (0x1 << ICFG_SDIOx_CAP1__SDR104_SHIFT)\
+ | (0x1 << ICFG_SDIOx_CAP1__SDR50_SHIFT)
+
+#define PAD_SDIO_CLK 0x4
+#define PAD_SDIO_DATA0 0x8
+#define PAD_SDIO_DATA1 0xc
+#define PAD_SDIO_DATA2 0x10
+#define PAD_SDIO_DATA3 0x14
+#define PAD_SDIO_DATA4 0x18
+#define PAD_SDIO_DATA5 0x1c
+#define PAD_SDIO_DATA6 0x20
+#define PAD_SDIO_DATA7 0x24
+#define PAD_SDIO_CMD 0x28
+
+/* 12mA Drive strength*/
+#define PAD_SDIO_SELX (0x5 << 1)
+#define PAD_SDIO_SRC (1 << 0)
+#define PAD_SDIO_MASK (0xF << 0)
+#define PAD_SDIO_VALUE (PAD_SDIO_SELX | PAD_SDIO_SRC)
+
+/*
+ * SDIO_PRESETVAL0
+ *
+ * Each 13 Bit filed consists:
+ * drivestrength - 12:11
+ * clkgensel - b10
+ * sdkclkfreqsel - 9:0
+ * Field Bit(s) Description
+ * ============================================================
+ * SDR25_PRESET 25:13 Preset Value for SDR25
+ * SDR50_PRESET 12:0 Preset Value for SDR50
+ */
+#define SDIO_PRESETVAL0 0x01005001
+
+/*
+ * SDIO_PRESETVAL1
+ *
+ * Each 13 Bit filed consists:
+ * drivestrength - 12:11
+ * clkgensel - b10
+ * sdkclkfreqsel - 9:0
+ * Field Bit(s) Description
+ * ============================================================
+ * SDR104_PRESET 25:13 Preset Value for SDR104
+ * SDR12_PRESET 12:0 Preset Value for SDR12
+ */
+#define SDIO_PRESETVAL1 0x03000004
+
+/*
+ * SDIO_PRESETVAL2
+ *
+ * Each 13 Bit filed consists:
+ * drivestrength - 12:11
+ * clkgensel - b10
+ * sdkclkfreqsel - 9:0
+ * Field Bit(s) Description
+ * ============================================================
+ * HIGH_SPEED_PRESET 25:13 Preset Value for High Speed
+ * INIT_PRESET 12:0 Preset Value for Initialization
+ */
+#define SDIO_PRESETVAL2 0x010040FA
+
+/*
+ * SDIO_PRESETVAL3
+ *
+ * Each 13 Bit filed consists:
+ * drivestrength - 12:11
+ * clkgensel - b10
+ * sdkclkfreqsel - 9:0
+ * Field Bit(s) Description
+ * ============================================================
+ * DDR50_PRESET 25:13 Preset Value for DDR50
+ * DEFAULT_PRESET 12:0 Preset Value for Default Speed
+ */
+#define SDIO_PRESETVAL3 0x01004004
+
+/*
+ * SDIO_PRESETVAL4
+ *
+ * Field Bit(s) Description
+ * ============================================================
+ * FORCE_USE_IP_TUNE_CLK 30 Force use IP clock
+ * TUNING_COUNT 29:24 Tuning count
+ * OVERRIDE_1P8V 23:16
+ * OVERRIDE_3P3V 15:8
+ * OVERRIDE_3P0V 7:0
+ */
+#define SDIO_PRESETVAL4 0x20010101
+
+#define SDIO_SID_SHIFT 5
+
+typedef struct {
+ uintptr_t cfg_base;
+ uintptr_t sid_base;
+ uintptr_t io_ctrl_base;
+ uintptr_t pad_base;
+} SDIO_CFG;
+
+void brcm_stingray_sdio_init(void);
+
+#endif /* SDIO_H */
diff --git a/plat/brcm/board/stingray/include/sr_def.h b/plat/brcm/board/stingray/include/sr_def.h
new file mode 100644
index 0000000..277836e
--- /dev/null
+++ b/plat/brcm/board/stingray/include/sr_def.h
@@ -0,0 +1,624 @@
+/*
+ * Copyright (c) 2016-2021, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SR_DEF_H
+#define SR_DEF_H
+
+#ifndef __ASSEMBLER__
+#include <lib/mmio.h>
+#endif
+
+#include <common/interrupt_props.h>
+#include <drivers/arm/gic_common.h>
+
+#include <crmu_def.h>
+
+/* Special value used to verify platform parameters from BL2 to BL3-1 */
+#define BRCM_BL31_PLAT_PARAM_VAL ULL(0x0f1e2d3c4b5a6978)
+
+#define MHB_BASE_ADDR 0x60000000
+#define PLAT_BRCM_CCN_BASE 0x61000000
+#define CORESIGHT_BASE_ADDR 0x62000000
+#define SMMU_BASE 0x64000000
+
+/* memory map entries*/
+/* Grouping block device for bigger MMU region */
+/* covers MHB, CNN, coresight, GIC, MMU, APB, CRMU */
+#define PERIPH0_BASE MHB_BASE_ADDR
+#define PERIPH0_SIZE 0x06d00000
+
+#define PERIPH1_BASE 0x66d80000
+#define PERIPH1_SIZE 0x00f80000
+
+#define HSLS_BASE_ADDR 0x68900000
+#define HSLS_SIZE 0x04500000
+
+#define GIC500_BASE 0x63c00000
+#define GIC500_SIZE 0x400000
+
+/*******************************************************************************
+ * CCN related constants
+ ******************************************************************************/
+#define OLY_MN_REGISTERS_NODE0_SECURE_ACCESS (PLAT_BRCM_CCN_BASE + 0x0)
+
+#define OLY_RNI3PDVM_REGISTERS_NODE8_AUX_CTL (PLAT_BRCM_CCN_BASE + 0x880500)
+
+/* Used for acceleration of coherent ordered writes */
+#define OLY_RNI3PDVM_REGISTERS_NODE8_AUX_CTL_WUO BIT(4)
+/* Wait for completion of requests at RN-I */
+#define OLY_RNI3PDVM_REGISTERS_NODE8_AUX_CTL_WFC BIT(3)
+
+/*
+ * Forces all reads from the RN-I to be sent with the request order bit set
+ * and this ensures ordered allocation of read data buffers in the RN-I
+ */
+#define OLY_RNI3PDVM_REGISTERS_NODE8_AUX_CTL_RQO BIT(5)
+
+#define OLY_RNI3PDVM_REGISTERS_NODE14_AUX_CTL (PLAT_BRCM_CCN_BASE + 0x8e0500)
+
+/* Wait for completion of requests at RN-I */
+#define OLY_RNI3PDVM_REGISTERS_NODE14_AUX_CTL_WFC BIT(3)
+
+#define OLY_HNI_REGISTERS_NODE0_POS_CONTROL (PLAT_BRCM_CCN_BASE + 0x80000)
+#define POS_CONTROL_HNI_POS_EN BIT(0)
+
+#define OLY_HNI_REGISTERS_NODE0_PCIERC_RNI_NODEID_LIST \
+ (PLAT_BRCM_CCN_BASE + 0x80008)
+/* PAXB and PAXC connected to 8th Node */
+#define SR_RNI_PCIE_CONNECTED BIT(8)
+/* PAXB connected to 6th Node */
+#define SRP_RNI_PCIE_CONNECTED BIT(6)
+
+#define OLY_HNI_REGISTERS_NODE0_SA_AUX_CTL (PLAT_BRCM_CCN_BASE + 0x80500)
+#define SA_AUX_CTL_POS_EARLY_WR_COMP_EN BIT(5)
+#define SA_AUX_CTL_SER_DEVNE_WR BIT(9)
+
+/*******************************************************************************
+ * Coresight related constants
+ ******************************************************************************/
+#define CORESIGHT_BASE_ADDR 0x62000000
+
+#define IHOST0_BASE 0x66000000
+#define IHOST_ADDR_SPACE 0x2000
+
+/*******************************************************************************
+ * SCR related constants
+ ******************************************************************************/
+#define SCR_BASE 0x6600a000
+#define SCR_ARCACHE_OFFSET 4
+#define SCR_ARCACHE_MASK (0x3 << SCR_ARCACHE_OFFSET)
+#define SCR_AWCACHE_OFFSET 6
+#define SCR_AWCACHE_MASK (0x3 << SCR_AWCACHE_OFFSET)
+#define SCR_AXCACHE_CONFIG_MASK (SCR_ARCACHE_MASK | SCR_AWCACHE_MASK)
+#define SCR_TBUX_AXCACHE_CONFIG ((0x1 << SCR_AWCACHE_OFFSET) | \
+ (0x1 << SCR_ARCACHE_OFFSET))
+
+#define SCR_REGS_SCR_SOFT_RESET (SCR_BASE + 0x1c)
+#define SCR_REGS_GIC_SOFT_RESET BIT(0)
+
+#define SCR_GPV_BASE 0x66100000
+#define SCR_NOC_SECURITY0 (SCR_GPV_BASE + 0x08)
+#define SCR_NOC_DDR_REGISTER_ACCESS (SCR_GPV_BASE + 0x30)
+
+/*******************************************************************************
+ * MEMC and DDR related constants
+ ******************************************************************************/
+#define DDR0_CONTROL_ROOT 0x66200000
+#define EMEM_SS_CFG_0_ROOT 0x66202000
+#define EMEM_SYS_IF_0_ROOT 0x66204000
+#define DDR_PHY0_ROOT 0x66240000
+
+#define DDR1_CONTROL_ROOT 0x66280000
+#define EMEM_SS_CFG_1_ROOT 0x66282000
+#define EMEM_SYS_IF_1_ROOT 0x66284000
+#define DDR_PHY1_ROOT 0x662c0000
+
+#define DDR2_CONTROL_ROOT 0x66300000
+#define EMEM_SS_CFG_2_ROOT 0x66302000
+#define EMEM_SYS_IF_2_ROOT 0x66304000
+#define DDR_PHY2_ROOT 0x66340000
+
+/*******************************************************************************
+ * TZC400 related constants
+ ******************************************************************************/
+#define TZC_400_BASE 0x66d84000
+
+/*******************************************************************************
+ * FS4 related constants
+ ******************************************************************************/
+#define FS4_SRAM_IDM_IO_CONTROL_DIRECT 0x66d8a408
+
+#define FS4_CRYPTO_IDM_IO_CONTROL_DIRECT 0x66d8e408
+#define FS4_CRYPTO_IDM_RESET_CONTROL 0x66d8e800
+#define FS4_CRYPTO_BASE 0x67000000
+#define FS4_CRYPTO_DME_BASE (FS4_CRYPTO_BASE + 0x280000)
+
+#define FS4_RAID_IDM_IO_CONTROL_DIRECT 0x66d8f408
+#define FS4_RAID_IDM_IO_STATUS 0x66d8f500
+#define FS4_RAID_IDM_RESET_CONTROL 0x66d8f800
+#define FS4_RAID_BASE 0x67400000
+#define FS4_RAID_DME_BASE (FS4_RAID_BASE + 0x280000)
+
+#define FS4_CRYPTO_GPV_BASE 0x67300000
+#define FS4_RAID_GPV_BASE 0x67700000
+
+#define FS6_PKI_BASE 0x67400000
+#define FS6_PKI_DME_BASE 0x66D90000
+
+#define TZC400_FS_SRAM_ROOT 0x66d84000
+#define GATE_KEEPER_OFFSET 0x8
+#define REGION_ATTRIBUTES_0_OFFSET 0x110
+#define REGION_ID_ACCESS_0_OFFSET 0x114
+
+#define NIC400_FS_NOC_ROOT 0x66e00000
+#define NIC400_FS_NOC_SECURITY2_OFFSET 0x10
+#define NIC400_FS_NOC_SECURITY4_OFFSET 0x18
+#define NIC400_FS_NOC_SECURITY7_OFFSET 0x24
+
+/*******************************************************************************
+ * SATA PHY related constants
+ ******************************************************************************/
+#define SATA_BASE 0x67d00000
+
+/*******************************************************************************
+ * USB related constants
+ ******************************************************************************/
+#define USB_BASE 0x68500000
+#define USB_SIZE 0x00400000
+#define XHC_BASE (USB_BASE + 0x11000)
+#define MAX_USB_PORTS 3
+
+/*******************************************************************************
+ * HSLS related constants
+ ******************************************************************************/
+#define IPROC_ROOT 0x68900000
+#define HSLS_ICFG_REGS_BASE IPROC_ROOT
+#define HSLS_IDM_REGS_BASE 0x68e00000
+#define HSLS_MODE_SEL_CONTROL 0x68a40000
+#define HSLS_TZPC_BASE 0x68b40000
+#define HSLS_GPV_BASE 0x6cd00000
+
+/*******************************************************************************
+ * Chip ID related constants
+ ******************************************************************************/
+#define ICFG_CHIP_ID HSLS_ICFG_REGS_BASE
+#define CHIP_ID_SR 0xd730
+#define CHIP_ID_NS3Z 0xe56d
+#define CHIP_ID_MASK 0xf000
+#define ICFG_CHIP_REVISION_ID (HSLS_ICFG_REGS_BASE + 0x4)
+#define PLAT_CHIP_ID_GET (mmio_read_32(ICFG_CHIP_ID))
+#define PLAT_CHIP_REV_GET (mmio_read_32(ICFG_CHIP_REVISION_ID))
+
+/*******************************************************************************
+ * CMIC MII (MDIO) related constant
+ ******************************************************************************/
+#define PLAT_CMIC_MIIM_BASE 0x68920000U
+
+/*******************************************************************************
+ * Timers related constants
+ ******************************************************************************/
+/* ChipcommonG_tim0_TIM_TIMER1Load 0x68930000 */
+#define SP804_TIMER0_BASE 0x68930000
+#define SP804_TIMER1_BASE 0x68940000
+#define SP804_TIMER0_TIMER_VAL_REG_OFFSET 0x4
+#define SP804_TIMER0_CLKMULT 2
+#define SP804_TIMER0_CLKDIV 25
+
+/*******************************************************************************
+ * GPIO related constants
+ ******************************************************************************/
+#define IPROC_GPIO_NS_BASE 0x689d0000
+#define IPROC_GPIO_S_BASE 0x68b00000
+#define IPROC_GPIO_NR 151
+#define GPIO_S_CNTRL_REG 0x68b60000
+
+/*******************************************************************************
+ * I2C SMBUS related constants
+ ******************************************************************************/
+#define SMBUS0_REGS_BASE 0x689b0000
+#define SMBUS1_REGS_BASE 0x689e0000
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define ChipcommonG_UART0_UART_RBR_THR_DLL 0x68a00000
+#define ChipcommonG_UART1_UART_RBR_THR_DLL 0x68a10000
+#define ChipcommonG_UART2_UART_RBR_THR_DLL 0x68a20000
+#define ChipcommonG_UART3_UART_RBR_THR_DLL 0x68a30000
+
+#define UART0_BASE_ADDR ChipcommonG_UART0_UART_RBR_THR_DLL
+#define UART1_BASE_ADDR ChipcommonG_UART1_UART_RBR_THR_DLL
+#define UART2_BASE_ADDR ChipcommonG_UART2_UART_RBR_THR_DLL
+#define UART3_BASE_ADDR ChipcommonG_UART3_UART_RBR_THR_DLL
+
+#define UART_SPR_OFFSET 0x1c /* Scratch Pad Register */
+
+#define LOG_LEVEL_REGISTER CRMU_SPARE_REG_3
+#define GET_LOG_LEVEL() (mmio_read_32(LOG_LEVEL_REGISTER))
+#define SET_LOG_LEVEL(x) (mmio_write_32(LOG_LEVEL_REGISTER, x))
+
+#define IO_RETRY_REGISTER CRMU_SPARE_REG_4
+
+#define DWC_UART_REFCLK (25 * 1000 * 1000)
+#define DWC_UART_REFCLK_DIV 16
+/* Baud rate in emulation will vary based on setting of 25MHz SCLK */
+#define DWC_UART_BAUDRATE 115200
+
+#define BRCM_CRASH_CONSOLE_BASE UART1_BASE_ADDR
+#define BRCM_CRASH_CONSOLE_REFCLK DWC_UART_REFCLK
+#define BRCM_CRASH_CONSOLE_BAUDRATE DWC_UART_BAUDRATE
+
+#ifdef BOARD_CONSOLE_UART
+#define PLAT_BRCM_BOOT_UART_BASE BOARD_CONSOLE_UART
+#else
+#define PLAT_BRCM_BOOT_UART_BASE UART1_BASE_ADDR
+#endif
+#define CONSOLE_UART_ID ((PLAT_BRCM_BOOT_UART_BASE >> 16) & 0x3)
+
+#define PLAT_BRCM_BOOT_UART_CLK_IN_HZ DWC_UART_REFCLK
+#define BRCM_CONSOLE_BAUDRATE DWC_UART_BAUDRATE
+
+#define PLAT_BRCM_BL31_RUN_UART_BASE PLAT_BRCM_BOOT_UART_BASE
+#define PLAT_BRCM_BL31_RUN_UART_CLK_IN_HZ PLAT_BRCM_BOOT_UART_CLK_IN_HZ
+
+/*******************************************************************************
+ * IOMUX related constants
+ ******************************************************************************/
+#define HSLS_IOPAD_BASE HSLS_MODE_SEL_CONTROL
+#define MODE_SEL_CONTROL_FSEL_MASK 0x7
+#define MODE_SEL_CONTROL_FSEL_MODE0 0x0
+#define MODE_SEL_CONTROL_FSEL_MODE1 0x1
+#define MODE_SEL_CONTROL_FSEL_MODE2 0x2
+#define MODE_SEL_CONTROL_FSEL_MODE3 0x3
+#define MODE_SEL_CONTROL_FSEL_DEBUG 0x4
+#define IPROC_IOPAD_MODE_BASE (HSLS_MODE_SEL_CONTROL + 0x29c)
+#define UART0_SIN_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x4a8)
+#define UART0_SOUT_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x4ac)
+#define UART1_SIN_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x3b8)
+#define UART1_SOUT_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x3bc)
+#define UARTx_SIN_MODE_SEL_CONTROL_FSEL 0
+#define UARTx_SOUT_MODE_SEL_CONTROL_FSEL 0
+
+/*******************************************************************************
+ * PKA constants
+ ******************************************************************************/
+#define ICFG_PKA_MEM_PWR_CTRL (HSLS_ICFG_REGS_BASE + 0xac0)
+#define ICFG_PKA_MEM_PWR_CTRL__POWERONIN BIT(0)
+#define ICFG_PKA_MEM_PWR_CTRL__POWEROKIN BIT(1)
+#define ICFG_PKA_MEM_PWR_CTRL__ARRPOWERONIN BIT(2)
+#define ICFG_PKA_MEM_PWR_CTRL__ARRPOWEROKIN BIT(3)
+#define ICFG_PKA_MEM_PWR_CTRL__POWERONOUT BIT(4)
+#define ICFG_PKA_MEM_PWR_CTRL__POWEROKOUT BIT(5)
+#define ICFG_PKA_MEM_PWR_CTRL__ARRPOWERONOUT BIT(6)
+#define ICFG_PKA_MEM_PWR_CTRL__ARRPOWEROKOUT BIT(7)
+#define ICFG_PKA_MEM_PWR_CTRL__ISO BIT(8)
+
+/*******************************************************************************
+ * RNG constants
+ ******************************************************************************/
+#define RNG_BASE_ADDR 0x68b20000
+
+/*******************************************************************************
+ * Trusted Watchdog constants
+ ******************************************************************************/
+#define ARM_SP805_TWDG_BASE 0x68b30000
+#define ARM_SP805_TWDG_CLK_HZ ((25 * 1000 * 1000) / 2)
+/*
+ * 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)
+
+/*******************************************************************************
+ * SOTP related constants
+ ******************************************************************************/
+#define SOTP_REGS_OTP_BASE 0x68b50000
+#define SOTP_CHIP_CTRL (SOTP_REGS_OTP_BASE + 0x4c)
+#define SOTP_CLEAR_SYSCTRL_ALL_MASTER_NS 0
+
+/*******************************************************************************
+ * DMAC/PL330 related constants
+ ******************************************************************************/
+#define DMAC_M0_IDM_IO_CONTROL_DIRECT (HSLS_IDM_REGS_BASE + 0x408)
+#define BOOT_MANAGER_NS BIT(25)
+#define DMAC_M0_IDM_RESET_CONTROL (HSLS_IDM_REGS_BASE + 0x800)
+#define ICFG_DMAC_CONFIG_0 (HSLS_ICFG_REGS_BASE + 0x190)
+#define ICFG_DMAC_CONFIG_1 (HSLS_ICFG_REGS_BASE + 0x194)
+#define ICFG_DMAC_CONFIG_2 (HSLS_ICFG_REGS_BASE + 0x198)
+#define BOOT_PERIPHERAL_NS 0xffffffff
+#define ICFG_DMAC_CONFIG_3 (HSLS_ICFG_REGS_BASE + 0x19c)
+#define BOOT_IRQ_NS 0x0000ffff
+#define ICFG_DMAC_SID_ARADDR_CONTROL (HSLS_ICFG_REGS_BASE + 0xaf0)
+#define ICFG_DMAC_SID_AWADDR_CONTROL (HSLS_ICFG_REGS_BASE + 0xaf4)
+#define ICFG_DMAC_MEM_PWR_CTRL__POWERONIN BIT(0)
+#define ICFG_DMAC_MEM_PWR_CTRL__POWEROKIN BIT(1)
+#define ICFG_DMAC_MEM_PWR_CTRL__ARRPOWERONIN BIT(2)
+#define ICFG_DMAC_MEM_PWR_CTRL__ARRPOWEROKIN BIT(3)
+#define ICFG_DMAC_MEM_PWR_CTRL__POWERONOUT BIT(4)
+#define ICFG_DMAC_MEM_PWR_CTRL__POWEROKOUT BIT(5)
+#define ICFG_DMAC_MEM_PWR_CTRL__ARRPOWERONOUT BIT(6)
+#define ICFG_DMAC_MEM_PWR_CTRL__ARRPOWEROKOUT BIT(7)
+#define ICFG_DMAC_MEM_PWR_CTRL__ISO BIT(8)
+#define ICFG_DMAC_MEM_PWR_CTRL (HSLS_ICFG_REGS_BASE + 0xadc)
+
+/*******************************************************************************
+ * PNOR related constants
+ ******************************************************************************/
+#define PNOR_ICFG_BASE (HSLS_ICFG_REGS_BASE + 0x780)
+#define PNOR_ICFG_CS_0 PNOR_ICFG_BASE
+#define PNOR_ICFG_CS_1 (PNOR_ICFG_BASE + 0x4)
+#define PNOR_ICFG_CS_2 (PNOR_ICFG_BASE + 0x8)
+#define PNOR_ICFG_CS_x_MASK0_MASK 0xff
+#define PNOR_ICFG_CS_x_MASK0_SHIFT 8
+#define PNOR_ICFG_CS_x_MATCH0_MASK 0xff
+#define PNOR_ICFG_CS_x_MATCH0_SHIFT 0
+
+#define PNOR_IDM_BASE (HSLS_IDM_REGS_BASE + 0xb000)
+#define PNOR_IDM_IO_CONTROL_DIRECT (PNOR_IDM_BASE + 0x408)
+#define PNOR_IDM_IO_RESET_CONTROL (PNOR_IDM_BASE + 0x800)
+
+#define PNOR_REG_BASE 0x68c50000
+#define PNOR_REG_DIRECT_CMD (PNOR_REG_BASE + 0x010)
+#define PNOR_REG_SET_CYCLES (PNOR_REG_BASE + 0x014)
+#define PNOR_REG_SET_OPMODE (PNOR_REG_BASE + 0x018)
+#define PNOR_REG_REFRESH_0 (PNOR_REG_BASE + 0x020)
+#define PNOR_REG_PERIPH_ID0 (PNOR_REG_BASE + 0xfe0)
+#define PNOR_REG_PERIPH_ID1 (PNOR_REG_BASE + 0xfe4)
+#define PNOR_REG_PERIPH_ID2 (PNOR_REG_BASE + 0xfe8)
+#define PNOR_REG_PERIPH_ID3 (PNOR_REG_BASE + 0xfec)
+#define PNOR_REG_PERIPH_IDx_MASK 0xff
+
+/*******************************************************************************
+ * NAND related constants
+ ******************************************************************************/
+#define NAND_FLASH_REVISION 0x68c60000
+#define NAND_IDM_IDM_IO_CONTROL_DIRECT (HSLS_IDM_REGS_BASE + 0xa408)
+#define NAND_IDM_IDM_RESET_CONTROL (HSLS_IDM_REGS_BASE + 0xa800)
+
+/*******************************************************************************
+ * eMMC related constants
+ ******************************************************************************/
+#define PLAT_SD_MAX_READ_LENGTH 0x400
+
+#define SDIO0_EMMCSDXC_SYSADDR 0x68cf1000
+#define SDIO_IDM0_IO_CONTROL_DIRECT (HSLS_IDM_REGS_BASE + 0x2408)
+#define SDIO_IDM1_IO_CONTROL_DIRECT (HSLS_IDM_REGS_BASE + 0x3408)
+#define SDIO_IDM0_IDM_RESET_CONTROL (HSLS_IDM_REGS_BASE + 0x2800)
+#define ICFG_SDIO0_BASE (HSLS_ICFG_REGS_BASE + 0x6e4)
+#define ICFG_SDIO1_BASE (HSLS_ICFG_REGS_BASE + 0x734)
+#define ICFG_SDIO0_CAP0 (ICFG_SDIO0_BASE + 0x10)
+#define ICFG_SDIO0_CAP1 (ICFG_SDIO0_BASE + 0x14)
+#define ICFG_SDIO0_SID (HSLS_ICFG_REGS_BASE + 0xb00)
+#define ICFG_SDIO1_SID (HSLS_ICFG_REGS_BASE + 0xb08)
+
+/*******************************************************************************
+ * Bootstrap related constants
+ ******************************************************************************/
+#define ROM_S0_IDM_IO_STATUS (HSLS_IDM_REGS_BASE + 0x9500)
+
+/*******************************************************************************
+ * ROM related constants
+ ******************************************************************************/
+#define ROM_BASE_ADDR 0x6ce00000
+#define ROM_VERSION_STRING_ADDR (ROM_BASE_ADDR + 0x28000)
+#define ROM_BUILD_MESSAGE_ADDR (ROM_BASE_ADDR + 0x28018)
+
+/*******************************************************************************
+ * Boot source peripheral related constants
+ ******************************************************************************/
+#define QSPI_CTRL_BASE_ADDR 0x68c70000
+#define QSPI_BASE_ADDR 0x70000000
+#define QSPI_SIZE 0x08000000
+#define NOR_BASE_ADDR 0x74000000
+#define NOR_SIZE 0x04000000
+#define NAND_BASE_ADDR 0x78000000
+#define NAND_SIZE 0x08000000
+
+#define QSPI_IDM_RESET_CONTROL (HSLS_IDM_REGS_BASE + 0xc800)
+
+#define APBR_IDM_RESET_CONTROL (HSLS_IDM_REGS_BASE + 0xe800)
+#define APBS_IDM_IDM_RESET_CONTROL (HSLS_IDM_REGS_BASE + 0xf800)
+
+#define APBX_IDM_IDM_IO_CONTROL_DIRECT (HSLS_IDM_REGS_BASE + 0x10408)
+#define APBX_IDM_IDM_IO_CONTROL_DIRECT_CLK_ENABLE 0
+#define APBX_IDM_IDM_IO_CONTROL_DIRECT_WDOG_SCLK_SEL 2
+#define APBX_IDM_IDM_IO_CONTROL_DIRECT_TIM0_SCLK_SEL 4
+#define APBX_IDM_IDM_IO_CONTROL_DIRECT_TIM1_SCLK_SEL 6
+#define APBX_IDM_IDM_IO_CONTROL_DIRECT_TIM2_SCLK_SEL 8
+#define APBX_IDM_IDM_IO_CONTROL_DIRECT_TIM3_SCLK_SEL 10
+#define APBX_IDM_IDM_IO_CONTROL_DIRECT_TIM4_SCLK_SEL 12
+#define APBX_IDM_IDM_IO_CONTROL_DIRECT_TIM5_SCLK_SEL 13
+#define APBX_IDM_IDM_IO_CONTROL_DIRECT_TIM6_SCLK_SEL 14
+#define APBX_IDM_IDM_IO_CONTROL_DIRECT_TIM7_SCLK_SEL 15
+
+#define APBY_IDM_IDM_IO_CONTROL_DIRECT (HSLS_IDM_REGS_BASE + 0x11408)
+#define APBY_IDM_IDM_IO_CONTROL_DIRECT_CLK_ENABLE 0
+#define APBY_IDM_IDM_IO_CONTROL_DIRECT_UART0_SCLK_SEL 2
+#define APBY_IDM_IDM_IO_CONTROL_DIRECT_UART1_SCLK_SEL 4
+#define APBY_IDM_IDM_IO_CONTROL_DIRECT_UART2_SCLK_SEL 6
+#define APBY_IDM_IDM_IO_CONTROL_DIRECT_UART3_SCLK_SEL 8
+
+#define APBZ_IDM_IDM_IO_CONTROL_DIRECT (HSLS_IDM_REGS_BASE + 0x12408)
+#define APBZ_IDM_IDM_IO_CONTROL_DIRECT_CLK_ENABLE 0
+#define APBZ_IDM_IDM_IO_CONTROL_DIRECT_WDOG_SCLK_SEL 2
+
+/*******************************************************************************
+ * Stingray memory map related constants
+ ******************************************************************************/
+
+/* The last 4KB of Trusted SRAM are used as shared memory */
+#define BRCM_SHARED_RAM_SIZE 0x0
+#define BRCM_SHARED_RAM_BASE (PLAT_BRCM_TRUSTED_SRAM_BASE + \
+ PLAT_BRCM_TRUSTED_SRAM_SIZE - \
+ BRCM_SHARED_RAM_SIZE)
+
+/* Reserve 4 KB to store error logs in BL2 */
+#define BCM_ELOG_BL2_SIZE 0x00001000
+#define BCM_ELOG_BL2_BASE BL1_RW_LIMIT
+
+/* The remaining Trusted SRAM is used to load the BL images */
+#define BRCM_BL_RAM_BASE (PLAT_BRCM_TRUSTED_SRAM_BASE)
+#define BRCM_BL_RAM_SIZE (PLAT_BRCM_TRUSTED_SRAM_SIZE - \
+ BRCM_SHARED_RAM_SIZE)
+
+/* DDR Address where TMON temperature values are written */
+#define TMON_SHARED_DDR_ADDRESS 0x8f100000
+
+/* Reserve 4 kB to pass data to BL33 */
+#define BL33_SHARED_DDR_BASE 0x8f102000
+#define BL33_SHARED_DDR_SIZE 0x1000
+
+/* Default AP error logging base addr */
+#ifndef ELOG_AP_UART_LOG_BASE
+#define ELOG_AP_UART_LOG_BASE 0x8f110000
+#endif
+
+/* Reserve 16 to store error logs in BL31 */
+#define BCM_ELOG_BL31_BASE ELOG_AP_UART_LOG_BASE
+#define BCM_ELOG_BL31_SIZE 0x4000
+
+/*******************************************************************************
+ * Non-secure DDR Map
+ ******************************************************************************/
+#define BRCM_DRAM1_BASE ULL(0x80000000)
+#define BRCM_DRAM1_SIZE ULL(0x10000000)
+#define BRCM_DRAM2_BASE ULL(0x880000000)
+#define BRCM_DRAM2_SIZE ULL(0x780000000)
+#define BRCM_DRAM3_BASE ULL(0x8800000000)
+#define BRCM_DRAM3_SIZE ULL(0x7800000000)
+#define BRCM_SHARED_DRAM_BASE BL33_SHARED_DDR_BASE
+#define BRCM_SHARED_DRAM_SIZE BL33_SHARED_DDR_SIZE
+#define BRCM_EXT_SRAM_BASE ULL(0x74000000)
+#define BRCM_EXT_SRAM_SIZE ULL(0x4000000)
+
+/* Priority levels for platforms */
+#define PLAT_RAS_PRI 0x10
+#define PLAT_SDEI_CRITICAL_PRI 0x60
+#define PLAT_SDEI_NORMAL_PRI 0x70
+
+/* Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 */
+#define BRCM_IRQ_SEC_SGI_0 14
+#define BRCM_IRQ_SEC_SGI_1 15
+
+/* RTC periodic interrupt */
+#define BRCM_IRQ_SEC_SPI_0 49
+
+/*
+ * Macros for local power states in SR platforms encoded by State-ID field
+ * within the power-state parameter.
+ */
+
+/* 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
+
+/*
+ * 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 PLAT_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 PLAT_LOCAL_STATE_OFF
+
+/* ChiMP-related constants */
+
+#define NITRO_TZPC_TZPCDECPROT0clr 0x60c01808
+#define NITRO_TZPC_TZPCDECPROT0clr__DECPROT0_chimp_m_clr_R 1
+
+#define NIC400_NITRO_CHIMP_S_IDM_IO_CONTROL_DIRECT 0x60e00408
+
+#define CHIMP_INDIRECT_ADDR_MASK 0x3fffff
+#define CHIMP_INDIRECT_BASE 0x60800000
+
+#define CHIMP_REG_ECO_RESERVED 0x3042400
+
+#define CHIMP_FLASH_ACCESS_DONE_BIT 2
+
+/* indicate FRU table programming is done successfully */
+#define CHIMP_FRU_PROG_DONE_BIT 9
+
+#define CHIMP_REG_CTRL_BPE_MODE_REG 0x0
+#define CHIMP_REG_CTRL_BPE_STAT_REG 0x4
+#define CHIMP_REG_CTRL_FSTBOOT_PTR_REG 0x8
+#define CHIMP_REG_CHIMP_REG_CTRL_BPE_MODE_REG__cm3_rst_L 1
+#define CHIMP_REG_CHIMP_REG_CTRL_BPE_MODE_REG__cm3_rst_R 1
+#define CHIMP_REG_CTRL_BASE 0x3040000
+#define CHIMP_FAST_BOOT_MODE_BIT 2
+#define CHIMP_REG_CHIMP_APE_SCPAD 0x3300000
+#define CHIMP_REG_CHIMP_SCPAD 0x3100000
+
+/* Chimp health status offset in scratch pad ram */
+#define CHIMP_HEALTH_STATUS_OFFSET 0x8
+/*
+ * If not in NIC mode then FASTBOOT can be enabled.
+ * "Not in NIC mode" means that FORCE_FASTBOOT is set
+ * and a valid (1 or 2) fastboot type is specified.
+ *
+ * Three types of fastboot are supported:
+ * 0 = No fastboot. Boots Nitro/ChiMP and lets ROM loader
+ * initialize ChiMP from NVRAM (QSPI).
+ *
+ * 1 = Jump in place (need a flat image)
+ * This is intended to speedup Nitro FW boot on Palladium,
+ * can be used with a real chip as well.
+ * 2 = Jump normally with decompression
+ * Modus operandi for a real chip. Works also on Palladium
+ * Note: image decompressing takes time on Palladium.
+ * 3 = No fastboot support. No ChiMP bringup
+ * (use only for AP debug or for ChiMP's deferred setup).
+ */
+#define CHIMP_FASTBOOT_JUMP_DECOMPRESS 2
+#define CHIMP_FASTBOOT_JUMP_IN_PLACE 1
+#define CHIMP_FASTBOOT_NITRO_RESET 0
+/*
+ * Definitions for a non-Nitro access
+ * to QSPI PAD after the handshake
+ */
+#define QSPI_HOLD_N_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x3e8)
+#define QSPI_WP_N_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x3ec)
+#define QSPI_SCK_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x3f0)
+#define QSPI_CS_N_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x3f4)
+#define QSPI_MOSI_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x3f8)
+#define QSPI_MISO_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x3fc)
+
+/*******************************************************************************
+ * Stream IDs for different blocks of SR
+ * block_id for different blocks is as follows:
+ * PCIE : 0x0
+ * PAXC : 0x1
+ * FS4 : 0x2
+ * Rest of the masters(includes MHB via RNI): 0x3
+ ******************************************************************************/
+#define SR_SID_VAL(block_id, subblock_id, device_num) ((block_id << 13) | \
+ (subblock_id << 11) | \
+ (device_num))
+
+#define CRMU_STREAM_ID SR_SID_VAL(0x3, 0x0, 0x7)
+#define CRMU_SID_SHIFT 5
+
+#define DMAC_STREAM_ID SR_SID_VAL(0x3, 0x0, 0x0)
+#define DMAC_SID_SHIFT 5
+
+/* DDR SHMOO Values defines */
+#define IDRAM_SHMOO_VALUES_ADDR CRMU_IDRAM_BASE_ADDR
+#define DDR_SHMOO_VALUES_ADDR 0x8f103000
+#define SHMOO_SIZE_PER_CHANNEL 0x1000
+
+#endif /* SR_DEF_H */
diff --git a/plat/brcm/board/stingray/include/sr_utils.h b/plat/brcm/board/stingray/include/sr_utils.h
new file mode 100644
index 0000000..b3fc735
--- /dev/null
+++ b/plat/brcm/board/stingray/include/sr_utils.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SR_UTILS_H
+#define SR_UTILS_H
+
+#include <lib/mmio.h>
+
+#include <chip_id.h>
+#include <cmn_plat_util.h>
+#include <sr_def.h>
+
+static inline void brcm_stingray_set_qspi_mux(int enable_ap)
+{
+ mmio_write_32(QSPI_HOLD_N_MODE_SEL_CONTROL, enable_ap);
+ mmio_write_32(QSPI_WP_N_MODE_SEL_CONTROL, enable_ap);
+ mmio_write_32(QSPI_SCK_MODE_SEL_CONTROL, enable_ap);
+ mmio_write_32(QSPI_CS_N_MODE_SEL_CONTROL, enable_ap);
+ mmio_write_32(QSPI_MOSI_MODE_SEL_CONTROL, enable_ap);
+ mmio_write_32(QSPI_MISO_MODE_SEL_CONTROL, enable_ap);
+}
+
+static inline void brcm_stingray_set_straps(uint32_t boot_source)
+{
+ /* Enable software strap override */
+ mmio_setbits_32(CDRU_CHIP_STRAP_CTRL,
+ BIT(CDRU_CHIP_STRAP_CTRL__SOFTWARE_OVERRIDE));
+
+ /* set straps to the next boot source */
+ mmio_clrsetbits_32(CDRU_CHIP_STRAP_DATA,
+ BOOT_SOURCE_MASK,
+ boot_source);
+
+ /* Disable software strap override */
+ mmio_clrbits_32(CDRU_CHIP_STRAP_CTRL,
+ BIT(CDRU_CHIP_STRAP_CTRL__SOFTWARE_OVERRIDE));
+}
+
+#endif
diff --git a/plat/brcm/board/stingray/include/swreg.h b/plat/brcm/board/stingray/include/swreg.h
new file mode 100644
index 0000000..6e971ce
--- /dev/null
+++ b/plat/brcm/board/stingray/include/swreg.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SWREG_H
+#define SWREG_H
+
+/* default voltage if no valid OTP */
+#define VDDC_CORE_DEF_VOLT 910000 /* 0.91v */
+#define IHOST_DEF_VOLT 940000 /* 0.94v */
+
+#define B0_VDDC_CORE_DEF_VOLT 950000 /* 0.95v */
+#define B0_IHOST_DEF_VOLT 950000 /* 0.95v */
+#define B0_DDR_VDDC_DEF_VOLT 1000000 /* 1v */
+
+#define SWREG_IHOST1_DIS 4
+#define SWREG_IHOST1_REG_RESETB 5
+#define SWREG_IHOST1_PMU_STABLE 2
+
+enum sw_reg {
+ DDR_VDDC = 1,
+ IHOST03,
+ IHOST12,
+ IHOST_ARRAY,
+ DDRIO_SLAVE,
+ VDDC_CORE,
+ VDDC1,
+ DDRIO_MASTER
+};
+
+int set_swreg(enum sw_reg reg_id, uint32_t micro_volts);
+int swreg_firmware_update(void);
+
+#endif
diff --git a/plat/brcm/board/stingray/include/timer_sync.h b/plat/brcm/board/stingray/include/timer_sync.h
new file mode 100644
index 0000000..1f15bb0
--- /dev/null
+++ b/plat/brcm/board/stingray/include/timer_sync.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TIMER_SYNC_H
+#define TIMER_SYNC_H
+
+void brcm_timer_sync_init(void);
+
+#endif
diff --git a/plat/brcm/board/stingray/include/usb_phy.h b/plat/brcm/board/stingray/include/usb_phy.h
new file mode 100644
index 0000000..7d83182
--- /dev/null
+++ b/plat/brcm/board/stingray/include/usb_phy.h
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2017 - 2021, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef USB_PHY_H
+#define USB_PHY_H
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+#define DRDU2_U2PLL_NDIV_FRAC_OFFSET 0x0U
+
+#define DRDU2_U2PLL_NDIV_INT 0x4U
+
+#define DRDU2_U2PLL_CTRL 0x8U
+#define DRDU2_U2PLL_LOCK BIT(6U)
+#define DRDU2_U2PLL_RESETB BIT(5U)
+#define DRDU2_U2PLL_PDIV_MASK 0xFU
+#define DRDU2_U2PLL_PDIV_OFFSET 1U
+#define DRDU2_U2PLL_SUSPEND_EN BIT(0U)
+
+#define DRDU2_PHY_CTRL 0x0CU
+#define DRDU2_U2IDDQ BIT(30U)
+#define DRDU2_U2SOFT_RST_N BIT(29U)
+#define DRDU2_U2PHY_ON_FLAG BIT(22U)
+#define DRDU2_U2PHY_PCTL_MASK 0xFFFFU
+#define DRDU2_U2PHY_PCTL_OFFSET 6U
+#define DRDU2_U2PHY_RESETB BIT(5U)
+#define DRDU2_U2PHY_ISO BIT(4U)
+#define DRDU2_U2AFE_BG_PWRDWNB BIT(3U)
+#define DRDU2_U2AFE_PLL_PWRDWNB BIT(2U)
+#define DRDU2_U2AFE_LDO_PWRDWNB BIT(1U)
+#define DRDU2_U2CTRL_CORERDY BIT(0U)
+
+#define DRDU2_STRAP_CTRL 0x18U
+#define DRDU2_FORCE_HOST_MODE BIT(5U)
+#define DRDU2_FORCE_DEVICE_MODE BIT(4U)
+#define BDC_USB_STP_SPD_MASK 0x7U
+#define BDC_USB_STP_SPD_OFFSET 0U
+
+#define DRDU2_PWR_CTRL 0x1CU
+#define DRDU2_U2PHY_DFE_SWITCH_PWROKIN_I BIT(2U)
+#define DRDU2_U2PHY_DFE_SWITCH_PWRONIN_I BIT(1U)
+
+#define DRDU2_SOFT_RESET_CTRL 0x20U
+#define DRDU2_BDC_AXI_SOFT_RST_N BIT(0U)
+
+#define USB3H_U2PLL_NDIV_FRAC 0x4U
+
+#define USB3H_U2PLL_NDIV_INT 0x8U
+
+#define USB3H_U2PLL_CTRL 0xCU
+#define USB3H_U2PLL_LOCK BIT(6U)
+#define USB3H_U2PLL_RESETB BIT(5U)
+#define USB3H_U2PLL_PDIV_MASK 0xFU
+#define USB3H_U2PLL_PDIV_OFFSET 1U
+
+#define USB3H_U2PHY_CTRL 0x10U
+#define USB3H_U2PHY_ON_FLAG 22U
+#define USB3H_U2PHY_PCTL_MASK 0xFFFFU
+#define USB3H_U2PHY_PCTL_OFFSET 6U
+#define USB3H_U2PHY_IDDQ BIT(29U)
+#define USB3H_U2PHY_RESETB BIT(5U)
+#define USB3H_U2PHY_ISO BIT(4U)
+#define USB3H_U2AFE_BG_PWRDWNB BIT(3U)
+#define USB3H_U2AFE_PLL_PWRDWNB BIT(2U)
+#define USB3H_U2AFE_LDO_PWRDWNB BIT(1U)
+#define USB3H_U2CTRL_CORERDY BIT(0U)
+
+#define USB3H_U3PHY_CTRL 0x14U
+#define USB3H_U3SOFT_RST_N BIT(30U)
+#define USB3H_U3MDIO_RESETB_I BIT(29U)
+#define USB3H_U3POR_RESET_I BIT(28U)
+#define USB3H_U3PHY_PCTL_MASK 0xFFFFU
+#define USB3H_U3PHY_PCTL_OFFSET 2U
+#define USB3H_U3PHY_RESETB BIT(1U)
+
+#define USB3H_U3PHY_PLL_CTRL 0x18U
+#define USB3H_U3PLL_REFCLK_MASK 0x7U
+#define USB3H_U3PLL_REFCLK_OFFSET 4U
+#define USB3H_U3PLL_SS_LOCK BIT(3U)
+#define USB3H_U3PLL_SEQ_START BIT(2U)
+#define USB3H_U3SSPLL_SUSPEND_EN BIT(1U)
+#define USB3H_U3PLL_RESETB BIT(0U)
+
+#define USB3H_PWR_CTRL 0x28U
+#define USB3H_PWR_CTRL_OVERRIDE_I_R 4U
+#define USB3H_PWR_CTRL_U2PHY_DFE_SWITCH_PWROKIN BIT(11U)
+#define USB3H_PWR_CTRL_U2PHY_DFE_SWITCH_PWRONIN BIT(10U)
+
+#define USB3H_SOFT_RESET_CTRL 0x2CU
+#define USB3H_XHC_AXI_SOFT_RST_N BIT(1U)
+
+#define USB3H_PHY_PWR_CTRL 0x38U
+#define USB3H_DISABLE_USB30_P0 BIT(2U)
+#define USB3H_DISABLE_EUSB_P1 BIT(1U)
+#define USB3H_DISABLE_EUSB_P0 BIT(0U)
+
+
+#define DRDU3_U2PLL_NDIV_FRAC 0x4U
+
+#define DRDU3_U2PLL_NDIV_INT 0x8U
+
+#define DRDU3_U2PLL_CTRL 0xCU
+#define DRDU3_U2PLL_LOCK BIT(6U)
+#define DRDU3_U2PLL_RESETB BIT(5U)
+#define DRDU3_U2PLL_PDIV_MASK 0xFU
+#define DRDU3_U2PLL_PDIV_OFFSET 1U
+
+#define DRDU3_U2PHY_CTRL 0x10U
+#define DRDU3_U2PHY_IDDQ BIT(29U)
+#define DRDU3_U2PHY_ON_FLAG BIT(22U)
+#define DRDU3_U2PHY_PCTL_MASK 0xFFFFU
+#define DRDU3_U2PHY_PCTL_OFFSET 6U
+#define DRDU3_U2PHY_RESETB BIT(5U)
+#define DRDU3_U2PHY_ISO BIT(4U)
+#define DRDU3_U2AFE_BG_PWRDWNB BIT(3U)
+#define DRDU3_U2AFE_PLL_PWRDWNB BIT(2U)
+#define DRDU3_U2AFE_LDO_PWRDWNB BIT(1U)
+#define DRDU3_U2CTRL_CORERDY BIT(0U)
+
+#define DRDU3_U3PHY_CTRL 0x14U
+#define DRDU3_U3XHC_SOFT_RST_N BIT(31U)
+#define DRDU3_U3BDC_SOFT_RST_N BIT(30U)
+#define DRDU3_U3MDIO_RESETB_I BIT(29U)
+#define DRDU3_U3POR_RESET_I BIT(28U)
+#define DRDU3_U3PHY_PCTL_MASK 0xFFFFU
+#define DRDU3_U3PHY_PCTL_OFFSET 2U
+#define DRDU3_U3PHY_RESETB BIT(1U)
+
+#define DRDU3_U3PHY_PLL_CTRL 0x18U
+#define DRDU3_U3PLL_REFCLK_MASK 0x7U
+#define DRDU3_U3PLL_REFCLK_OFFSET 4U
+#define DRDU3_U3PLL_SS_LOCK BIT(3U)
+#define DRDU3_U3PLL_SEQ_START BIT(2U)
+#define DRDU3_U3SSPLL_SUSPEND_EN BIT(1U)
+#define DRDU3_U3PLL_RESETB BIT(0U)
+
+#define DRDU3_STRAP_CTRL 0x28U
+#define BDC_USB_STP_SPD_MASK 0x7U
+#define BDC_USB_STP_SPD_OFFSET 0U
+#define BDC_USB_STP_SPD_SS 0x0U
+#define BDC_USB_STP_SPD_HS 0x2U
+
+#define DRDU3_PWR_CTRL 0x2cU
+#define DRDU3_U2PHY_DFE_SWITCH_PWROKIN BIT(12U)
+#define DRDU3_U2PHY_DFE_SWITCH_PWRONIN BIT(11U)
+#define DRDU3_PWR_CTRL_OVERRIDE_I_R 4U
+
+#define DRDU3_SOFT_RESET_CTRL 0x30U
+#define DRDU3_XHC_AXI_SOFT_RST_N BIT(1U)
+#define DRDU3_BDC_AXI_SOFT_RST_N BIT(0U)
+
+#define DRDU3_PHY_PWR_CTRL 0x3cU
+#define DRDU3_DISABLE_USB30_P0 BIT(2U)
+#define DRDU3_DISABLE_EUSB_P1 BIT(1U)
+#define DRDU3_DISABLE_EUSB_P0 BIT(0U)
+
+#define PLL_REFCLK_PAD 0x0U
+#define PLL_REFCLK_25MHZ 0x1U
+#define PLL_REFCLK_96MHZ 0x2U
+#define PLL_REFCLK_INTERNAL 0x3U
+/* USB PLL lock time out for 10 ms */
+#define PLL_LOCK_RETRY_COUNT 10000U
+
+
+#define U2PLL_NDIV_INT_VAL 0x13U
+#define U2PLL_NDIV_FRAC_VAL 0x1005U
+#define U2PLL_PDIV_VAL 0x1U
+/*
+ * Using external FSM
+ * BIT-3:2: device mode; mode is not effect
+ * BIT-1: soft reset active low
+ */
+#define U2PHY_PCTL_VAL 0x0003U
+/* Non-driving signal low */
+#define U2PHY_PCTL_NON_DRV_LOW 0x0002U
+#define U3PHY_PCTL_VAL 0x0006U
+
+#define MAX_NR_PORTS 3U
+
+#define USB3H_DRDU2_PHY 1U
+#define DRDU3_PHY 2U
+
+#define USB_HOST_MODE 1U
+#define USB_DEV_MODE 2U
+
+#define USB3SS_PORT 0U
+#define DRDU2_PORT 1U
+#define USB3HS_PORT 2U
+
+#define DRD3SS_PORT 0U
+#define DRD3HS_PORT 1U
+
+#define SR_USB_PHY_COUNT 2U
+
+#define DRDU3_PIPE_CTRL 0x68500000U
+#define DRDU3H_XHC_REGS_CPLIVER 0x68501000U
+#define USB3H_PIPE_CTRL 0x68510000U
+#define DRD2U3H_XHC_REGS_CPLIVER 0x68511000U
+#define DRDU2_U2PLL_NDIV_FRAC 0x68520000U
+
+#define AXI_DEBUG_CTRL 0x68500038U
+#define AXI_DBG_CTRL_SSPHY_DRD_MODE_DISABLE BIT(12U)
+
+#define USB3H_DEBUG_CTRL 0x68510034U
+#define USB3H_DBG_CTRL_SSPHY_DRD_MODE_DISABLE BIT(7U)
+
+typedef struct _usb_phy_port usb_phy_port_t;
+
+typedef struct {
+ uint32_t drdu2reg;
+ uint32_t usb3hreg;
+ uint32_t drdu3reg;
+ uint32_t phy_id;
+ uint32_t ports_enabled;
+ uint32_t initialized;
+ usb_phy_port_t *phy_port;
+} usb_phy_t;
+
+struct _usb_phy_port {
+ uint32_t port_id;
+ uint32_t mode;
+ uint32_t enabled;
+ usb_phy_t *p;
+};
+
+struct u2_phy_ext_fsm {
+ uint32_t pll_ctrl_reg;
+ uint32_t phy_ctrl_reg;
+ uint32_t phy_iddq;
+ uint32_t pwr_ctrl_reg;
+ uint32_t pwr_okin;
+ uint32_t pwr_onin;
+};
+
+#endif /* USB_PHY_H */
diff --git a/plat/brcm/board/stingray/platform.mk b/plat/brcm/board/stingray/platform.mk
new file mode 100644
index 0000000..aa2fe86
--- /dev/null
+++ b/plat/brcm/board/stingray/platform.mk
@@ -0,0 +1,304 @@
+#
+# Copyright (c) 2019-2021, Broadcom
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Set the toc_flags to 1 for 100% speed operation
+# Set the toc_flags to 2 for 50% speed operation
+# Set the toc_flags to 3 for 25% speed operation
+# Set the toc_flags bit 3 to indicate ignore the fip in UEFI copy mode
+PLAT_TOC_FLAGS := 0x0
+
+# Set the IHOST_PLL_FREQ to,
+# 1 for full speed
+# 2 for 50% speed
+# 3 for 25% speed
+# 0 for bypass
+$(eval $(call add_define_val,IHOST_PLL_FREQ,1))
+
+# Enable workaround for ERRATA_A72_859971
+ERRATA_A72_859971 := 1
+
+# Cache Coherency Interconnect Driver needed
+DRIVER_CC_ENABLE := 1
+$(eval $(call add_define,DRIVER_CC_ENABLE))
+
+# Enable to erase eMMC
+INCLUDE_EMMC_DRIVER_ERASE_CODE := 0
+
+ifeq (${INCLUDE_EMMC_DRIVER_ERASE_CODE},1)
+$(eval $(call add_define,INCLUDE_EMMC_DRIVER_ERASE_CODE))
+endif
+
+# BL31 is in DRAM
+ARM_BL31_IN_DRAM := 1
+
+ifneq (${USE_EMULATOR},yes)
+STINGRAY_EMULATION_SETUP := 0
+ifeq (${FASTBOOT_TYPE},)
+override FASTBOOT_TYPE := 0
+endif
+USE_PAXB := yes
+USE_PAXC := yes
+USE_CHIMP := yes
+endif
+
+USE_CRMU_SRAM := yes
+
+# Disable FS4 clocks - they can be reenabled when needed by linux
+FS4_DISABLE_CLOCK := yes
+
+# Enable error logging by default for Stingray
+BCM_ELOG := yes
+
+# Enable FRU support by default for Stingray
+ifeq (${USE_FRU},)
+USE_FRU := no
+endif
+
+# Use single cluster
+ifeq (${USE_SINGLE_CLUSTER},yes)
+$(info Using Single Cluster)
+$(eval $(call add_define,USE_SINGLE_CLUSTER))
+endif
+
+# Use DDR
+ifeq (${USE_DDR},yes)
+$(info Using DDR)
+$(eval $(call add_define,USE_DDR))
+endif
+
+ifeq (${BOARD_CFG},)
+BOARD_CFG := bcm958742t
+endif
+
+# Use USB
+ifeq (${USE_USB},yes)
+$(info Using USB)
+$(eval $(call add_define,USE_USB))
+endif
+
+# Use PAXB
+ifeq (${USE_PAXB},yes)
+$(info Using PAXB)
+$(eval $(call add_define,USE_PAXB))
+endif
+
+# Use FS4
+ifeq (${USE_FS4},yes)
+$(info Using FS4)
+$(eval $(call add_define,USE_FS4))
+endif
+
+# Use FS6
+ifeq (${USE_FS6},yes)
+$(info Using FS6)
+$(eval $(call add_define,USE_FS6))
+endif
+
+# Disable FS4 clock
+ifeq (${FS4_DISABLE_CLOCK},yes)
+$(info Using FS4_DISABLE_CLOCK)
+$(eval $(call add_define,FS4_DISABLE_CLOCK))
+endif
+
+ifneq (${NCSI_IO_DRIVE_STRENGTH_MA},)
+$(info Using NCSI_IO_DRIVE_STRENGTH_MA)
+$(eval $(call add_define,NCSI_IO_DRIVE_STRENGTH_MA))
+endif
+
+# Use NAND
+ifeq (${USE_NAND},$(filter yes, ${USE_NAND}))
+$(info Using NAND)
+$(eval $(call add_define,USE_NAND))
+endif
+
+# Enable Broadcom error logging support
+ifeq (${BCM_ELOG},yes)
+$(info Using BCM_ELOG)
+$(eval $(call add_define,BCM_ELOG))
+endif
+
+# BL31 build for standalone mode
+ifeq (${STANDALONE_BL31},yes)
+RESET_TO_BL31 := 1
+$(info Using RESET_TO_BL31)
+endif
+
+# BL31 force full frequency for all CPUs
+ifeq (${BL31_FORCE_CPU_FULL_FREQ},yes)
+$(info Using BL31_FORCE_CPU_FULL_FREQ)
+$(eval $(call add_define,BL31_FORCE_CPU_FULL_FREQ))
+endif
+
+# Enable non-secure accesses to CCN registers
+ifeq (${BL31_CCN_NONSECURE},yes)
+$(info Using BL31_CCN_NONSECURE)
+$(eval $(call add_define,BL31_CCN_NONSECURE))
+endif
+
+# Use ChiMP
+ifeq (${USE_CHIMP},yes)
+$(info Using ChiMP)
+$(eval $(call add_define,USE_CHIMP))
+endif
+
+# Use PAXC
+ifeq (${USE_PAXC},yes)
+$(info Using PAXC)
+$(eval $(call add_define,USE_PAXC))
+ifeq (${CHIMPFW_USE_SIDELOAD},yes)
+$(info Using ChiMP FW sideload)
+$(eval $(call add_define,CHIMPFW_USE_SIDELOAD))
+endif
+$(eval $(call add_define,FASTBOOT_TYPE))
+$(eval $(call add_define,CHIMP_FB1_ENTRY))
+endif
+
+ifeq (${DEFAULT_SWREG_CONFIG}, 1)
+$(eval $(call add_define,DEFAULT_SWREG_CONFIG))
+endif
+
+ifeq (${CHIMP_ALWAYS_NEEDS_QSPI},yes)
+$(eval $(call add_define,CHIMP_ALWAYS_NEEDS_QSPI))
+endif
+
+# For testing purposes, use memsys stubs. Remove once memsys is fully tested.
+USE_MEMSYS_STUBS := yes
+
+# Default, use BL1_RW area
+ifneq (${BL2_USE_BL1_RW},no)
+$(eval $(call add_define,USE_BL1_RW))
+endif
+
+# Default soft reset is L3
+$(eval $(call add_define,CONFIG_SOFT_RESET_L3))
+
+# Enable Chip OTP driver
+DRIVER_OCOTP_ENABLE := 1
+
+ifneq (${WARMBOOT_DDR_S3_SUPPORT},)
+DRIVER_SPI_ENABLE := 1
+endif
+
+include plat/brcm/board/common/board_common.mk
+
+SOC_DIR := brcm/board/stingray
+
+PLAT_INCLUDES += -Iplat/${SOC_DIR}/include/ \
+ -Iinclude/plat/brcm/common/ \
+ -Iplat/brcm/common/
+
+PLAT_BL_COMMON_SOURCES += lib/cpus/aarch64/cortex_a72.S \
+ plat/${SOC_DIR}/aarch64/plat_helpers.S \
+ drivers/ti/uart/aarch64/16550_console.S \
+ plat/${SOC_DIR}/src/tz_sec.c \
+ drivers/arm/tzc/tzc400.c \
+ plat/${SOC_DIR}/driver/plat_emmc.c \
+ plat/${SOC_DIR}/src/topology.c \
+ drivers/brcm/mdio/mdio.c
+
+ifeq (${USE_CHIMP},yes)
+PLAT_BL_COMMON_SOURCES += drivers/brcm/chimp.c
+endif
+
+ifeq (${USE_USB},yes)
+PLAT_BL_COMMON_SOURCES += plat/${SOC_DIR}/driver/usb.c \
+ plat/${SOC_DIR}/driver/usb_phy.c
+endif
+
+BL2_SOURCES += plat/${SOC_DIR}/driver/ihost_pll_config.c \
+ plat/${SOC_DIR}/src/bl2_setup.c \
+ plat/${SOC_DIR}/driver/swreg.c
+
+ifeq (${USE_DDR},yes)
+PLAT_INCLUDES += -Iplat/${SOC_DIR}/driver/ddr/soc/include
+else
+PLAT_INCLUDES += -Iplat/${SOC_DIR}/driver/ext_sram_init
+BL2_SOURCES += plat/${SOC_DIR}/driver/ext_sram_init/ext_sram_init.c
+endif
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+BRCM_GIC_SOURCES := ${GICV3_SOURCES} \
+ plat/common/plat_gicv3.c \
+ plat/brcm/common/brcm_gicv3.c
+
+BL31_SOURCES += \
+ drivers/arm/ccn/ccn.c \
+ plat/brcm/board/common/timer_sync.c \
+ plat/brcm/common/brcm_ccn.c \
+ plat/common/plat_psci_common.c \
+ plat/${SOC_DIR}/driver/ihost_pll_config.c \
+ plat/${SOC_DIR}/src/bl31_setup.c \
+ plat/${SOC_DIR}/src/fsx.c \
+ plat/${SOC_DIR}/src/iommu.c \
+ plat/${SOC_DIR}/src/sdio.c \
+ ${BRCM_GIC_SOURCES}
+
+ifneq (${NCSI_IO_DRIVE_STRENGTH_MA},)
+BL31_SOURCES += plat/${SOC_DIR}/src/ncsi.c
+endif
+
+ifeq (${USE_PAXB},yes)
+BL31_SOURCES += plat/${SOC_DIR}/src/paxb.c
+BL31_SOURCES += plat/${SOC_DIR}/src/sr_paxb_phy.c
+endif
+
+ifeq (${USE_PAXC},yes)
+BL31_SOURCES += plat/${SOC_DIR}/src/paxc.c
+endif
+
+ifdef SCP_BL2
+PLAT_INCLUDES += -Iplat/brcm/common/
+
+BL2_SOURCES += plat/brcm/common/brcm_mhu.c \
+ plat/brcm/common/brcm_scpi.c \
+ plat/${SOC_DIR}/src/scp_utils.c \
+ plat/${SOC_DIR}/src/scp_cmd.c \
+ drivers/brcm/scp.c
+
+BL31_SOURCES += plat/brcm/common/brcm_mhu.c \
+ plat/brcm/common/brcm_scpi.c \
+ plat/${SOC_DIR}/src/brcm_pm_ops.c
+else
+BL31_SOURCES += plat/${SOC_DIR}/src/ihost_pm.c \
+ plat/${SOC_DIR}/src/pm.c
+endif
+
+ifeq (${ELOG_SUPPORT},1)
+ifeq (${ELOG_STORE_MEDIA},DDR)
+BL2_SOURCES += plat/brcm/board/common/bcm_elog_ddr.c
+endif
+endif
+
+ifeq (${BL31_BOOT_PRELOADED_SCP}, 1)
+ifdef SCP_BL2
+SCP_CFG_DIR=$(dir ${SCP_BL2})
+PLAT_INCLUDES += -I${SCP_CFG_DIR}
+endif
+PLAT_INCLUDES += -Iplat/brcm/common/
+
+# By default use OPTEE Assigned memory
+PRELOADED_SCP_BASE ?= 0x8E000000
+PRELOADED_SCP_SIZE ?= 0x10000
+$(eval $(call add_define,PRELOADED_SCP_BASE))
+$(eval $(call add_define,PRELOADED_SCP_SIZE))
+$(eval $(call add_define,BL31_BOOT_PRELOADED_SCP))
+BL31_SOURCES += plat/${SOC_DIR}/src/scp_utils.c \
+ plat/${SOC_DIR}/src/scp_cmd.c \
+ drivers/brcm/scp.c
+endif
+
+# Do not execute the startup code on warm reset.
+PROGRAMMABLE_RESET_ADDRESS := 1
+
+# Nitro FW, config and Crash log uses secure DDR memory
+# Inaddition to above, Nitro master and slave is also secure
+ifneq ($(NITRO_SECURE_ACCESS),)
+$(eval $(call add_define,NITRO_SECURE_ACCESS))
+$(eval $(call add_define,DDR_NITRO_SECURE_REGION_START))
+$(eval $(call add_define,DDR_NITRO_SECURE_REGION_END))
+endif
diff --git a/plat/brcm/board/stingray/src/bl2_setup.c b/plat/brcm/board/stingray/src/bl2_setup.c
new file mode 100644
index 0000000..b2c8aec
--- /dev/null
+++ b/plat/brcm/board/stingray/src/bl2_setup.c
@@ -0,0 +1,743 @@
+/*
+ * Copyright (c) 2016-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/sp805.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <chimp.h>
+#include <chip_id.h>
+#include <cmn_plat_util.h>
+#include <dmu.h>
+#include <emmc_api.h>
+#include <fru.h>
+#ifdef USE_GPIO
+#include <drivers/gpio.h>
+#include <iproc_gpio.h>
+#endif
+#include <platform_def.h>
+#include <sotp.h>
+#include <swreg.h>
+#include <sr_utils.h>
+#ifdef USE_DDR
+#include <ddr_init.h>
+#else
+#include <ext_sram_init.h>
+#endif
+#if DRIVER_OCOTP_ENABLE
+#include <ocotp.h>
+#endif
+#include "board_info.h"
+
+#define WORD_SIZE 8
+#define SWREG_AVS_OTP_OFFSET (13 * WORD_SIZE) /* 13th row byte offset */
+#define AON_GPIO_OTP_OFFSET (28 * WORD_SIZE) /* 28th row byte offset */
+#define BYTES_TO_READ 8
+
+/* OTP voltage step definitions */
+#define MVOLT_STEP_MAX 0x18 /* 1v */
+#define MVOLT_PER_STEP 10 /* 0.01mv per step */
+#define MVOLT_BASE 760 /* 0.76v */
+
+#define STEP_TO_UVOLTS(step) \
+ ((MVOLT_BASE + (MVOLT_PER_STEP * (step))) * 1000)
+
+#define GET_BITS(first, last, data) \
+ ((data >> first) & ((1 << (last - first + 1)) - 1))
+
+/*
+ * SW-REG OTP encoding:
+ *
+ * SWREG_bits[11:0] = OTP 13th row 12 bits[55:44]
+ * SWREG_bits[11:10] - Valid Bits (0x2 - valid, if not 0x2 - Invalid)
+ * SWREG_bits[9:5] - iHost03, iHost12
+ * SWREG_bits[4:0] - Core VDDC
+ */
+#define SWREG_OTP_BITS_START 12 /* 44th bit in MSB 32-bits */
+#define SWREG_OTP_BITS_END 23 /* 55th bit in MSB 32-bits */
+#define SWREG_VDDC_FIELD_START 0
+#define SWREG_VDDC_FIELD_END 4
+#define SWREG_IHOST_FIELD_START 5
+#define SWREG_IHOST_FIELD_END 9
+#define SWREG_VALID_BIT_START 10
+#define SWREG_VALID_BIT_END 11
+#define SWREG_VALID_BITS 0x2
+
+/*
+ * Row 13 bit 56 is programmed as '1' today. It is not being used, so plan
+ * is to flip this bit to '0' for B1 rev. Hence SW can leverage this bit
+ * to identify Bx chip to program different sw-regulators.
+ */
+#define SPARE_BIT 24
+
+#define IS_SR_B0(data) (((data) >> SPARE_BIT) & 0x1)
+
+#if DRIVER_OCOTP_ENABLE
+static struct otpc_map otp_stingray_map = {
+ .otpc_row_size = 2,
+ .data_r_offset = {0x10, 0x5c},
+ .data_w_offset = {0x2c, 0x64},
+ .word_size = 8,
+ .stride = 8,
+};
+#endif
+
+void plat_bcm_bl2_early_platform_setup(void)
+{
+ /* Select UART0 for AP via mux setting*/
+ if (PLAT_BRCM_BOOT_UART_BASE == UART0_BASE_ADDR) {
+ mmio_write_32(UART0_SIN_MODE_SEL_CONTROL, 1);
+ mmio_write_32(UART0_SOUT_MODE_SEL_CONTROL, 1);
+ }
+}
+
+#ifdef USE_NAND
+static void brcm_stingray_nand_init(void)
+{
+ unsigned int val;
+ unsigned int nand_idm_reset_control = 0x68e0a800;
+
+ VERBOSE(" stingray nand init start.\n");
+
+ /* Reset NAND */
+ VERBOSE(" - reset nand\n");
+ val = mmio_read_32((uintptr_t)(nand_idm_reset_control + 0x0));
+ mmio_write_32((uintptr_t)(nand_idm_reset_control + 0x0), val | 0x1);
+ udelay(500);
+ val = mmio_read_32((uintptr_t)(nand_idm_reset_control + 0x0));
+ mmio_write_32((uintptr_t)(nand_idm_reset_control + 0x0), val & ~0x1);
+ udelay(500);
+
+ VERBOSE(" stingray nand init done.\n");
+}
+#endif
+
+#if defined(USE_PAXB) || defined(USE_PAXC) || defined(USE_SATA)
+#define PCIE_RESCAL_CFG_0 0x40000130
+#define PCIE_CFG_RESCAL_RSTB_R (1 << 16)
+#define PCIE_CFG_RESCAL_PWRDNB_R (1 << 8)
+#define PCIE_RESCAL_STATUS_0 0x4000014c
+#define PCIE_STAT_PON_VALID_R (1 << 0)
+#define PCIE_RESCAL_OUTPUT_STATUS 0x40000154
+#define CDRU_PCIE_RESET_N_R (1 << CDRU_MISC_RESET_CONTROL__CDRU_PCIE_RESET_N_R)
+
+#ifdef EMULATION_SETUP
+static void brcm_stingray_pcie_reset(void)
+{
+}
+#else
+static void brcm_stingray_pcie_reset(void)
+{
+ unsigned int data;
+ int try;
+
+ if (bcm_chimp_is_nic_mode()) {
+ INFO("NIC mode detected; PCIe reset/rescal not executed\n");
+ return;
+ }
+
+ mmio_clrbits_32(CDRU_MISC_RESET_CONTROL, CDRU_PCIE_RESET_N_R);
+ mmio_setbits_32(CDRU_MISC_RESET_CONTROL, CDRU_PCIE_RESET_N_R);
+ /* Release reset */
+ mmio_setbits_32(PCIE_RESCAL_CFG_0, PCIE_CFG_RESCAL_RSTB_R);
+ mdelay(1);
+ /* Power UP */
+ mmio_setbits_32(PCIE_RESCAL_CFG_0,
+ (PCIE_CFG_RESCAL_RSTB_R | PCIE_CFG_RESCAL_PWRDNB_R));
+
+ try = 1000;
+ do {
+ udelay(1);
+ data = mmio_read_32(PCIE_RESCAL_STATUS_0);
+ try--;
+ } while ((data & PCIE_STAT_PON_VALID_R) == 0x0 && (try > 0));
+
+ if (try <= 0)
+ ERROR("PCIE_RESCAL_STATUS_0: 0x%x\n", data);
+
+ VERBOSE("PCIE_SATA_RESCAL_STATUS_0 0x%x.\n",
+ mmio_read_32(PCIE_RESCAL_STATUS_0));
+ VERBOSE("PCIE_SATA_RESCAL_OUTPUT_STATUS 0x%x.\n",
+ mmio_read_32(PCIE_RESCAL_OUTPUT_STATUS));
+ INFO("PCIE SATA Rescal Init done\n");
+}
+#endif /* EMULATION_SETUP */
+#endif /* USE_PAXB || USE_PAXC || USE_SATA */
+
+#ifdef USE_PAXC
+void brcm_stingray_chimp_check_and_fastboot(void)
+{
+ int fastboot_init_result;
+
+ if (bcm_chimp_is_nic_mode())
+ /* Do not wait here */
+ return;
+
+#if WARMBOOT_DDR_S3_SUPPORT
+ /*
+ * Currently DDR shmoo parameters and QSPI boot source are
+ * tied. DDR shmoo parameters are stored in QSPI, which is
+ * used for warmboot.
+ * Do not reset nitro for warmboot
+ */
+ if (is_warmboot() && (boot_source_get() == BOOT_SOURCE_QSPI))
+ return;
+#endif /* WARMBOOT_DDR_S3_SUPPORT */
+
+ /*
+ * Not in NIC mode,
+ * initiate fastboot (if enabled)
+ */
+ if (FASTBOOT_TYPE == CHIMP_FASTBOOT_NITRO_RESET) {
+
+ VERBOSE("Bring up Nitro/ChiMP\n");
+
+ if (boot_source_get() == BOOT_SOURCE_QSPI)
+ WARN("Nitro boots from QSPI when AP has booted from QSPI.\n");
+ brcm_stingray_set_qspi_mux(0);
+ VERBOSE("Nitro controls the QSPI\n");
+ }
+
+ fastboot_init_result = bcm_chimp_initiate_fastboot(FASTBOOT_TYPE);
+ if (fastboot_init_result && boot_source_get() != BOOT_SOURCE_QSPI)
+ ERROR("Nitro init error %d. Status: 0x%x; bpe_mod reg: 0x%x\n"
+ "fastboot register: 0x%x; handshake register 0x%x\n",
+ fastboot_init_result,
+ bcm_chimp_read_ctrl(CHIMP_REG_CTRL_BPE_STAT_REG),
+ bcm_chimp_read_ctrl(CHIMP_REG_CTRL_BPE_MODE_REG),
+ bcm_chimp_read_ctrl(CHIMP_REG_CTRL_FSTBOOT_PTR_REG),
+ bcm_chimp_read(CHIMP_REG_ECO_RESERVED));
+
+ /*
+ * CRMU watchdog kicks is an example, which is L1 reset,
+ * does not clear Nitro scratch pad ram.
+ * For Nitro resets: Clear the Nitro health status memory.
+ */
+ bcm_chimp_write((CHIMP_REG_CHIMP_SCPAD + CHIMP_HEALTH_STATUS_OFFSET),
+ 0);
+}
+#endif
+
+void set_ihost_vddc_swreg(uint32_t ihost_uvolts, uint32_t vddc_uvolts)
+{
+ NOTICE("ihost_uvolts: %duv, vddc_uvolts: %duv\n",
+ ihost_uvolts, vddc_uvolts);
+
+ set_swreg(VDDC_CORE, vddc_uvolts);
+ set_swreg(IHOST03, ihost_uvolts);
+ set_swreg(IHOST12, ihost_uvolts);
+}
+
+/*
+ * Reads SWREG AVS OTP bits (13th row) with ECC enabled and get voltage
+ * defined in OTP if valid OTP is found
+ */
+void read_avs_otp_bits(uint32_t *ihost_uvolts, uint32_t *vddc_uvolts)
+{
+ uint32_t offset = SWREG_AVS_OTP_OFFSET;
+ uint32_t ihost_step, vddc_step;
+ uint32_t avs_bits;
+ uint32_t buf[2];
+
+ if (bcm_otpc_read(offset, &buf[0], BYTES_TO_READ, 1) == -1)
+ return;
+
+ VERBOSE("AVS OTP %d ROW: 0x%x.0x%x\n",
+ offset/WORD_SIZE, buf[1], buf[0]);
+
+ /* get voltage readings from AVS OTP bits */
+ avs_bits = GET_BITS(SWREG_OTP_BITS_START,
+ SWREG_OTP_BITS_END,
+ buf[1]);
+
+ /* check for valid otp bits */
+ if (GET_BITS(SWREG_VALID_BIT_START, SWREG_VALID_BIT_END, avs_bits) !=
+ SWREG_VALID_BITS) {
+ WARN("Invalid AVS OTP bits at %d row\n", offset/WORD_SIZE);
+ return;
+ }
+
+ /* get ihost and vddc step value */
+ vddc_step = GET_BITS(SWREG_VDDC_FIELD_START,
+ SWREG_VDDC_FIELD_END,
+ avs_bits);
+
+ ihost_step = GET_BITS(SWREG_IHOST_FIELD_START,
+ SWREG_IHOST_FIELD_END,
+ avs_bits);
+
+ if ((ihost_step > MVOLT_STEP_MAX) || (vddc_step > MVOLT_STEP_MAX)) {
+ WARN("OTP entry invalid\n");
+ return;
+ }
+
+ /* get voltage in micro-volts */
+ *ihost_uvolts = STEP_TO_UVOLTS(ihost_step);
+ *vddc_uvolts = STEP_TO_UVOLTS(vddc_step);
+}
+
+/*
+ * This api reads otp bits and program internal swreg's - ihos12, ihost03,
+ * vddc_core and ddr_core based on different chip. External swreg's
+ * programming will be done from crmu.
+ *
+ * For A2 chip:
+ * Read OTP row 20, bit 50. This bit will be set for A2 chip. Once A2 chip is
+ * found, read AVS OTP row 13, 12bits[55:44], if valid otp bits are found
+ * then set ihost and vddc according to avs otp bits else set them to 0.94v
+ * and 0.91v respectively. Also update the firmware after setting voltage.
+ *
+ * For B0 chip:
+ * Read OTP row 13, bit 56. This bit will be set for B0 chip. Once B0 chip is
+ * found then set ihost and vddc to 0.95v and ddr_core to 1v. No AVS OTP bits
+ * are used get ihost/vddc voltages.
+ *
+ * For B1 chip:
+ * Read AVS OTP row 13, 12bits[55:44], if valid otp bits are found then set
+ * ihost and vddc according to avs otp bits else set them to 0.94v and 0.91v
+ * respectively.
+ */
+void set_swreg_based_on_otp(void)
+{
+ /* default voltage if no valid OTP */
+ uint32_t vddc_uvolts = VDDC_CORE_DEF_VOLT;
+ uint32_t ihost_uvolts = IHOST_DEF_VOLT;
+ uint32_t ddrc_uvolts;
+ uint32_t offset;
+ uint32_t buf[2];
+
+ offset = SWREG_AVS_OTP_OFFSET;
+ if (bcm_otpc_read(offset, &buf[0], BYTES_TO_READ, 1) == -1)
+ return;
+
+ VERBOSE("OTP %d ROW: 0x%x.0x%x\n",
+ offset/WORD_SIZE, buf[1], buf[0]);
+
+ if (IS_SR_B0(buf[1])) {
+ /* don't read AVS OTP for B0 */
+ ihost_uvolts = B0_IHOST_DEF_VOLT;
+ vddc_uvolts = B0_VDDC_CORE_DEF_VOLT;
+ ddrc_uvolts = B0_DDR_VDDC_DEF_VOLT;
+ } else {
+ read_avs_otp_bits(&ihost_uvolts, &vddc_uvolts);
+ }
+
+#if (IHOST_REG_TYPE == IHOST_REG_INTEGRATED) && \
+ (VDDC_REG_TYPE == VDDC_REG_INTEGRATED)
+ /* enable IHOST12 cluster before changing voltage */
+ NOTICE("Switching on the Regulator idx: %u\n",
+ SWREG_IHOST1_DIS);
+ mmio_clrsetbits_32(CRMU_SWREG_CTRL_ADDR,
+ BIT(SWREG_IHOST1_DIS),
+ BIT(SWREG_IHOST1_REG_RESETB));
+
+ /* wait for regulator supply gets stable */
+ while (!(mmio_read_32(CRMU_SWREG_STATUS_ADDR) &
+ (1 << SWREG_IHOST1_PMU_STABLE)))
+ ;
+
+ INFO("Regulator supply got stable\n");
+
+#ifndef DEFAULT_SWREG_CONFIG
+ swreg_firmware_update();
+#endif
+
+ set_ihost_vddc_swreg(ihost_uvolts, vddc_uvolts);
+#endif
+ if (IS_SR_B0(buf[1])) {
+ NOTICE("ddrc_uvolts: %duv\n", ddrc_uvolts);
+ set_swreg(DDR_VDDC, ddrc_uvolts);
+ }
+}
+
+#ifdef USE_DDR
+static struct ddr_info ddr_info;
+#endif
+#ifdef USE_FRU
+static struct fru_area_info fru_area[FRU_MAX_NR_AREAS];
+static struct fru_board_info board_info;
+static struct fru_time fru_tm;
+static uint8_t fru_tbl[BCM_MAX_FRU_LEN];
+
+static void board_detect_fru(void)
+{
+ uint32_t i, result;
+ int ret = -1;
+
+ result = bcm_emmc_init(false);
+ if (!result) {
+ ERROR("eMMC init failed\n");
+ return;
+ }
+
+ /* go through eMMC boot partitions looking for FRU table */
+ for (i = EMMC_BOOT_PARTITION1; i <= EMMC_BOOT_PARTITION2; i++) {
+ result = emmc_partition_select(i);
+ if (!result) {
+ ERROR("Switching to eMMC part %u failed\n", i);
+ return;
+ }
+
+ result = emmc_read(BCM_FRU_TBL_OFFSET, (uintptr_t)fru_tbl,
+ BCM_MAX_FRU_LEN, BCM_MAX_FRU_LEN);
+ if (!result) {
+ ERROR("Failed to read from eMMC part %u\n", i);
+ return;
+ }
+
+ /*
+ * Run sanity check and checksum to make sure valid FRU table
+ * is detected
+ */
+ ret = fru_validate(fru_tbl, fru_area);
+ if (ret < 0) {
+ WARN("FRU table not found in eMMC part %u\n", i);
+ continue;
+ }
+
+ /* parse DDR information from FRU table */
+ ret = fru_parse_ddr(fru_tbl, &fru_area[FRU_AREA_INTERNAL],
+ &ddr_info);
+ if (ret < 0) {
+ WARN("No FRU DDR info found in eMMC part %u\n", i);
+ continue;
+ }
+
+ /* parse board information from FRU table */
+ ret = fru_parse_board(fru_tbl, &fru_area[FRU_AREA_BOARD_INFO],
+ &board_info);
+ if (ret < 0) {
+ WARN("No FRU board info found in eMMC part %u\n", i);
+ continue;
+ }
+
+ /* if we reach here, valid FRU table is parsed */
+ break;
+ }
+
+ if (ret < 0) {
+ WARN("FRU table missing for this board\n");
+ return;
+ }
+
+ for (i = 0; i < BCM_MAX_NR_DDR; i++) {
+ INFO("DDR channel index: %d\n", ddr_info.mcb[i].idx);
+ INFO("DDR size %u GB\n", ddr_info.mcb[i].size_mb / 1024);
+ INFO("DDR ref ID by SW (Not MCB Ref ID) 0x%x\n",
+ ddr_info.mcb[i].ref_id);
+ }
+
+ fru_format_time(board_info.mfg_date, &fru_tm);
+
+ INFO("**** FRU board information ****\n");
+ INFO("Language 0x%x\n", board_info.lang);
+ INFO("Manufacturing Date %u.%02u.%02u, %02u:%02u\n",
+ fru_tm.year, fru_tm.month, fru_tm.day,
+ fru_tm.hour, fru_tm.min);
+ INFO("Manufacturing Date(Raw) 0x%x\n", board_info.mfg_date);
+ INFO("Manufacturer %s\n", board_info.manufacturer);
+ INFO("Product Name %s\n", board_info.product_name);
+ INFO("Serial number %s\n", board_info.serial_number);
+ INFO("Part number %s\n", board_info.part_number);
+ INFO("File ID %s\n", board_info.file_id);
+}
+#endif /* USE_FRU */
+
+#ifdef USE_GPIO
+
+#define INVALID_GPIO 0xffff
+
+static const int gpio_cfg_bitmap[MAX_NR_GPIOS] = {
+#ifdef BRD_DETECT_GPIO_BIT0
+ BRD_DETECT_GPIO_BIT0,
+#else
+ INVALID_GPIO,
+#endif
+#ifdef BRD_DETECT_GPIO_BIT1
+ BRD_DETECT_GPIO_BIT1,
+#else
+ INVALID_GPIO,
+#endif
+#ifdef BRD_DETECT_GPIO_BIT2
+ BRD_DETECT_GPIO_BIT2,
+#else
+ INVALID_GPIO,
+#endif
+#ifdef BRD_DETECT_GPIO_BIT3
+ BRD_DETECT_GPIO_BIT3,
+#else
+ INVALID_GPIO,
+#endif
+};
+
+static uint8_t gpio_bitmap;
+
+/*
+ * Use an odd number to avoid potential conflict with public GPIO level
+ * defines
+ */
+#define GPIO_STATE_FLOAT 15
+
+/*
+ * If GPIO_SUPPORT_FLOAT_DETECTION is disabled, simply return GPIO level
+ *
+ * If GPIO_SUPPORT_FLOAT_DETECTION is enabled, add additional test for possible
+ * pin floating (unconnected) scenario. This support is assuming externally
+ * applied pull up / pull down will have a stronger pull than the internal pull
+ * up / pull down.
+ */
+static uint8_t gpio_get_state(int gpio)
+{
+ uint8_t val;
+
+ /* set direction to GPIO input */
+ gpio_set_direction(gpio, GPIO_DIR_IN);
+
+#ifndef GPIO_SUPPORT_FLOAT_DETECTION
+ if (gpio_get_value(gpio) == GPIO_LEVEL_HIGH)
+ val = GPIO_LEVEL_HIGH;
+ else
+ val = GPIO_LEVEL_LOW;
+
+ return val;
+#else
+ /*
+ * Enable internal pull down. If GPIO level is still high, there must
+ * be an external pull up
+ */
+ gpio_set_pull(gpio, GPIO_PULL_DOWN);
+ if (gpio_get_value(gpio) == GPIO_LEVEL_HIGH) {
+ val = GPIO_LEVEL_HIGH;
+ goto exit;
+ }
+
+ /*
+ * Enable internal pull up. If GPIO level is still low, there must
+ * be an external pull down
+ */
+ gpio_set_pull(gpio, GPIO_PULL_UP);
+ if (gpio_get_value(gpio) == GPIO_LEVEL_LOW) {
+ val = GPIO_LEVEL_LOW;
+ goto exit;
+ }
+
+ /* if reached here, the pin must be not connected */
+ val = GPIO_STATE_FLOAT;
+
+exit:
+ /* make sure internall pull is disabled */
+ if (gpio_get_pull(gpio) != GPIO_PULL_NONE)
+ gpio_set_pull(gpio, GPIO_PULL_NONE);
+
+ return val;
+#endif
+}
+
+static void board_detect_gpio(void)
+{
+ unsigned int i, val;
+ int gpio;
+
+ iproc_gpio_init(IPROC_GPIO_S_BASE, IPROC_GPIO_NR,
+ IPROC_IOPAD_MODE_BASE, HSLS_IOPAD_BASE);
+
+ gpio_bitmap = 0;
+ for (i = 0; i < MAX_NR_GPIOS; i++) {
+ if (gpio_cfg_bitmap[i] == INVALID_GPIO)
+ continue;
+
+ /*
+ * Construct the bitmap based on GPIO value. Floating pin
+ * detection is a special case. As soon as a floating pin is
+ * detected, a special value of MAX_GPIO_BITMAP_VAL is
+ * assigned and we break out of the loop immediately
+ */
+ gpio = gpio_cfg_bitmap[i];
+ val = gpio_get_state(gpio);
+ if (val == GPIO_STATE_FLOAT) {
+ gpio_bitmap = MAX_GPIO_BITMAP_VAL;
+ break;
+ }
+
+ if (val == GPIO_LEVEL_HIGH)
+ gpio_bitmap |= BIT(i);
+ }
+
+ memcpy(&ddr_info, &gpio_ddr_info[gpio_bitmap], sizeof(ddr_info));
+ INFO("Board detection GPIO bitmap = 0x%x\n", gpio_bitmap);
+}
+#endif /* USE_GPIO */
+
+static void bcm_board_detect(void)
+{
+#ifdef DDR_LEGACY_MCB_SUPPORTED
+ /* Loading default DDR info */
+ memcpy(&ddr_info, &default_ddr_info, sizeof(ddr_info));
+#endif
+#ifdef USE_FRU
+ board_detect_fru();
+#endif
+#ifdef USE_GPIO
+ board_detect_gpio();
+#endif
+}
+
+static void dump_persistent_regs(void)
+{
+ NOTICE("pr0: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG0));
+ NOTICE("pr1: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG1));
+ NOTICE("pr2: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG2));
+ NOTICE("pr3: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG3));
+ NOTICE("pr4: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG4));
+ NOTICE("pr5: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG5));
+ NOTICE("pr6: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG6));
+ NOTICE("pr7: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG7));
+ NOTICE("pr8: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG8));
+ NOTICE("pr9: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG9));
+ NOTICE("pr10: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG10));
+ NOTICE("pr11: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG11));
+}
+
+void plat_bcm_bl2_plat_arch_setup(void)
+{
+ if (chip_get_rev_id_major() == CHIP_REV_MAJOR_AX) {
+ if (!(sotp_mem_read(SOTP_ATF_CFG_ROW_ID, SOTP_ROW_NO_ECC) &
+ SOTP_ATF_WATCHDOG_ENABLE_MASK)) {
+ /*
+ * Stop sp805 watchdog timer immediately.
+ * It might has been set up by MCU patch earlier for
+ * eMMC workaround.
+ *
+ * Note the watchdog timer started in CRMU has a very
+ * short timeout and needs to be stopped immediately.
+ * Down below we restart it with a much longer timeout
+ * for BL2 and BL31
+ */
+ sp805_stop(ARM_SP805_TWDG_BASE);
+ }
+ }
+
+#if !BRCM_DISABLE_TRUSTED_WDOG
+ /*
+ * start secure watchdog for BL2 and BL31.
+ * Note that UART download can take a longer time,
+ * so do not allow watchdog for UART download,
+ * as this boot source is not a standard modus operandi.
+ */
+ if (boot_source_get() != BOOT_SOURCE_UART)
+ sp805_start(ARM_SP805_TWDG_BASE, ARM_TWDG_LOAD_VAL);
+#endif
+
+#ifdef BCM_ELOG
+ /* Ensure logging is started out fresh in BL2. */
+ mmio_write_32(BCM_ELOG_BL2_BASE, 0);
+#endif
+ /*
+ * In BL2, since we have very limited space to store logs, we only
+ * save logs that are >= the WARNING level.
+ */
+ bcm_elog_init((void *)BCM_ELOG_BL2_BASE, BCM_ELOG_BL2_SIZE,
+ LOG_LEVEL_WARNING);
+
+ dump_persistent_regs();
+
+ /* Read CRMU mailbox 0 */
+ NOTICE("RESET (reported by CRMU): 0x%x\n",
+ mmio_read_32(CRMU_READ_MAIL_BOX0));
+
+ /*
+ * All non-boot-source PADs are in forced input-mode at
+ * reset so clear the force on non-boot-source PADs using
+ * CDRU register.
+ */
+ mmio_clrbits_32((uintptr_t)CDRU_CHIP_IO_PAD_CONTROL,
+ (1 << CDRU_CHIP_IO_PAD_CONTROL__CDRU_IOMUX_FORCE_PAD_IN_R));
+
+#if DRIVER_OCOTP_ENABLE
+ bcm_otpc_init(&otp_stingray_map);
+#endif
+
+ set_swreg_based_on_otp();
+
+#if IHOST_PLL_FREQ != 0
+ bcm_set_ihost_pll_freq(0x0, IHOST_PLL_FREQ);
+#endif
+
+#ifdef INCLUDE_EMMC_DRIVER_ERASE_CODE
+ /* The erasable unit of the eMMC is the "Erase Group";
+ * Erase group is measured in write blocks which are the
+ * basic writable units of the Device.
+ * The size of the Erase Group is a Device specific parameter
+ */
+ emmc_erase(EMMC_ERASE_START_BLOCK, EMMC_ERASE_BLOCK_COUNT,
+ EMMC_ERASE_PARTITION);
+#endif
+
+ bcm_board_detect();
+#ifdef DRIVER_EMMC_ENABLE
+ /* Initialize the card, if it is not */
+ if (bcm_emmc_init(true) == 0)
+ WARN("eMMC Card Initialization Failed!!!\n");
+#endif
+
+#if BL2_TEST_I2C
+ i2c_test();
+#endif
+
+#ifdef USE_DDR
+ ddr_initialize(&ddr_info);
+
+ ddr_secure_region_config(SECURE_DDR_BASE_ADDRESS,
+ SECURE_DDR_END_ADDRESS);
+#ifdef NITRO_SECURE_ACCESS
+ ddr_secure_region_config(DDR_NITRO_SECURE_REGION_START,
+ DDR_NITRO_SECURE_REGION_END);
+#endif
+#else
+ ext_sram_init();
+#endif
+
+#if BL2_TEST_MEM
+ ddr_test();
+#endif
+
+#ifdef USE_NAND
+ brcm_stingray_nand_init();
+#endif
+
+#if defined(USE_PAXB) || defined(USE_PAXC) || defined(USE_SATA)
+ brcm_stingray_pcie_reset();
+#endif
+
+#ifdef USE_PAXC
+ if (boot_source_get() != BOOT_SOURCE_QSPI)
+ brcm_stingray_chimp_check_and_fastboot();
+#endif
+
+#if ((!CLEAN_DDR || MMU_DISABLED))
+ /*
+ * Now DDR has been initialized. We want to copy all the logs in SRAM
+ * into DDR so we will have much more space to store the logs in the
+ * next boot stage
+ */
+ bcm_elog_copy_log((void *)BCM_ELOG_BL31_BASE,
+ MIN(BCM_ELOG_BL2_SIZE, BCM_ELOG_BL31_SIZE)
+ );
+
+ /*
+ * We are not yet at the end of BL2, but we can stop log here so we do
+ * not need to add 'bcm_elog_exit' to the standard BL2 code. The
+ * benefit of capturing BL2 logs after this is very minimal in a
+ * production system
+ * NOTE: BL2 logging must be exited before going forward to setup
+ * page tables
+ */
+ bcm_elog_exit();
+#endif
+}
diff --git a/plat/brcm/board/stingray/src/bl31_setup.c b/plat/brcm/board/stingray/src/bl31_setup.c
new file mode 100644
index 0000000..04df6a0
--- /dev/null
+++ b/plat/brcm/board/stingray/src/bl31_setup.c
@@ -0,0 +1,1071 @@
+/*
+ * Copyright (c) 2015 - 2021, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <cortex_a72.h>
+#include <drivers/arm/sp805.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+#include <plat/common/platform.h>
+
+#include <bl33_info.h>
+#include <chimp.h>
+#include <cmn_plat_util.h>
+#include <dmu.h>
+#include <fsx.h>
+#include <iommu.h>
+#include <ncsi.h>
+#include <paxb.h>
+#include <paxc.h>
+#include <platform_def.h>
+#ifdef USE_USB
+#include <platform_usb.h>
+#endif
+#include <sdio.h>
+#include <sr_utils.h>
+#include <timer_sync.h>
+
+/*******************************************************************************
+ * Perform any BL3-1 platform setup common to ARM standard platforms
+ ******************************************************************************/
+
+static void brcm_stingray_gain_qspi_control(void)
+{
+ if (boot_source_get() != BOOT_SOURCE_QSPI) {
+ if (bcm_chimp_is_nic_mode() &&
+ (!bcm_chimp_handshake_done())) {
+ /*
+ * Last chance to wait for ChiMP firmware to report
+ * "I am done" before grabbing the QSPI
+ */
+ WARN("ChiMP still not booted\n");
+#ifndef CHIMP_ALWAYS_NEEDS_QSPI
+ WARN("ChiMP is given the last chance to boot (%d s)\n",
+ CHIMP_HANDSHAKE_TIMEOUT_MS / 1000);
+
+ if (!bcm_chimp_wait_handshake()) {
+ ERROR("ChiMP failed to boot\n");
+ } else {
+ INFO("ChiMP booted successfully\n");
+ }
+#endif
+ }
+
+#ifndef CHIMP_ALWAYS_NEEDS_QSPI
+ INFO("AP grabs QSPI\n");
+ /*
+ * For QSPI boot sbl/bl1 has already taken care.
+ * For other boot sources QSPI needs to be muxed to
+ * AP for exclusive use
+ */
+ brcm_stingray_set_qspi_mux(1);
+ INFO("AP (bl31) gained control over QSPI\n");
+#endif
+ }
+}
+
+static void brcm_stingray_dma_pl330_init(void)
+{
+ unsigned int val;
+
+ VERBOSE("dma pl330 init start\n");
+
+ /* Set DMAC boot_manager_ns = 0x1 */
+ VERBOSE(" - configure boot security state\n");
+ mmio_setbits_32(DMAC_M0_IDM_IO_CONTROL_DIRECT, BOOT_MANAGER_NS);
+ /* Set boot_peripheral_ns[n:0] = 0xffffffff */
+ mmio_write_32(ICFG_DMAC_CONFIG_2, BOOT_PERIPHERAL_NS);
+ /* Set boot_irq_ns[n:0] = 0x0000ffff */
+ mmio_write_32(ICFG_DMAC_CONFIG_3, BOOT_IRQ_NS);
+
+ /* Set DMAC stream_id */
+ VERBOSE(" - configure stream_id = 0x6000\n");
+ val = (DMAC_STREAM_ID << DMAC_SID_SHIFT);
+ mmio_write_32(ICFG_DMAC_SID_ARADDR_CONTROL, val);
+ mmio_write_32(ICFG_DMAC_SID_AWADDR_CONTROL, val);
+
+ /* Reset DMAC */
+ VERBOSE(" - reset dma pl330\n");
+
+ mmio_setbits_32(DMAC_M0_IDM_RESET_CONTROL, 0x1);
+ udelay(500);
+
+ mmio_clrbits_32(DMAC_M0_IDM_RESET_CONTROL, 0x1);
+ udelay(500);
+
+ INFO("dma pl330 init done\n");
+}
+
+static void brcm_stingray_spi_pl022_init(uintptr_t idm_reset_control)
+{
+ VERBOSE("spi pl022 init start\n");
+
+ /* Reset APB SPI bridge */
+ VERBOSE(" - reset apb spi bridge\n");
+ mmio_setbits_32(idm_reset_control, 0x1);
+ udelay(500);
+
+ mmio_clrbits_32(idm_reset_control, 0x1);
+ udelay(500);
+
+ INFO("spi pl022 init done\n");
+}
+
+#define CDRU_SATA_RESET_N \
+ BIT(CDRU_MISC_RESET_CONTROL__CDRU_SATA_RESET_N_R)
+#define CDRU_MISC_CLK_SATA \
+ BIT(CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_SATA_CLK_EN_R)
+#define CCN_CONFIG_CLK_ENABLE (1 << 2)
+#define MMU_CONFIG_CLK_ENABLE (0x3F << 16)
+
+#define SATA_SATA_TOP_CTRL_BUS_CTRL (SATA_BASE + 0x2044)
+#define DMA_BIT_CTRL_MASK 0x003
+#define DMA_DESCR_ENDIAN_CTRL (DMA_BIT_CTRL_MASK << 0x002)
+#define DMA_DATA_ENDIAN_CTRL (DMA_BIT_CTRL_MASK << 0x004)
+
+#define SATA_PORT_SATA3_PCB_REG8 (SATA_BASE + 0x2320)
+#define SATA_PORT_SATA3_PCB_REG11 (SATA_BASE + 0x232c)
+#define SATA_PORT_SATA3_PCB_BLOCK_ADDR (SATA_BASE + 0x233c)
+
+#define SATA3_AFE_TXRX_ACTRL 0x1d0
+/* TXDriver swing setting is 800mV */
+#define DFS_SWINGNOPE_VALUE (0x0 << 6)
+#define DFS_SWINGNOPE_MASK (0x3 << 6)
+
+#define DFS_SWINGPE_VALUE (0x1 << 4)
+#define DFS_SWINGPE_MASK (0x3 << 4)
+
+#define DFS_INJSTRENGTH_VALUE (0x0 << 4)
+#define DFS_INJSTRENGTH_MASK (0x3 << 4)
+
+#define DFS_INJEN (0x1 << 3)
+
+#define SATA_CORE_MEM_CTRL (SATA_BASE + 0x3a08)
+#define SATA_CORE_MEM_CTRL_ISO BIT(0)
+#define SATA_CORE_MEM_CTRL_ARRPOWEROKIN BIT(1)
+#define SATA_CORE_MEM_CTRL_ARRPOWERONIN BIT(2)
+#define SATA_CORE_MEM_CTRL_POWEROKIN BIT(3)
+#define SATA_CORE_MEM_CTRL_POWERONIN BIT(4)
+
+#define SATA0_IDM_RESET_CONTROL (SATA_BASE + 0x500800)
+#define SATA_APBT0_IDM_IO_CONTROL_DIRECT (SATA_BASE + 0x51a408)
+#define IO_CONTROL_DIRECT_CLK_ENABLE BIT(0)
+#define SATA_APBT0_IDM_RESET_CONTROL (SATA_BASE + 0x51a800)
+#define IDM_RESET_CONTROL_RESET BIT(0)
+
+#define NIC400_SATA_NOC_SECURITY1 0x6830000c
+#define SATA_NOC_SECURITY1_FIELD 0xf
+#define NIC400_SATA_NOC_SECURITY2 0x68300010
+#define SATA_NOC_SECURITY2_FIELD 0xf
+#define NIC400_SATA_NOC_SECURITY3 0x68300014
+#define SATA_NOC_SECURITY3_FIELD 0x1
+#define NIC400_SATA_NOC_SECURITY4 0x68300018
+#define SATA_NOC_SECURITY4_FIELD 0x1
+#define NIC400_SATA_NOC_SECURITY5 0x6830001c
+#define SATA_NOC_SECURITY5_FIELD 0xf
+#define NIC400_SATA_NOC_SECURITY6 0x68300020
+#define SATA_NOC_SECURITY6_FIELD 0x1
+#define NIC400_SATA_NOC_SECURITY7 0x68300024
+#define SATA_NOC_SECURITY7_FIELD 0xf
+#define NIC400_SATA_NOC_SECURITY8 0x68300028
+#define SATA_NOC_SECURITY8_FIELD 0xf
+#define NIC400_SATA_NOC_SECURITY9 0x6830002c
+#define SATA_NOC_SECURITY9_FIELD 0x1
+
+#define SATA_APBT_IDM_PORT_REG(port, reg) \
+ (((port/4) << 12) + reg)
+
+#define SATA_IDM_PORT_REG(port, reg) ((port << 12) + reg)
+
+#define SATA_PORT_REG(port, reg) \
+ (((port%4) << 16) + ((port/4) << 20) + reg)
+
+#define MAX_SATA_PORTS 8
+#define USE_SATA_PORTS 8
+
+#ifdef USE_SATA
+static const uint8_t sr_b0_sata_port[MAX_SATA_PORTS] = {
+ 0, 1, 2, 3, 4, 5, 6, 7
+};
+
+static uint32_t brcm_stingray_get_sata_port(unsigned int port)
+{
+ return sr_b0_sata_port[port];
+}
+
+static void brcm_stingray_sata_init(void)
+{
+ unsigned int port = 0;
+ uint32_t sata_port;
+
+ mmio_setbits_32(CDRU_MISC_CLK_ENABLE_CONTROL,
+ CDRU_MISC_CLK_SATA);
+
+ mmio_clrbits_32(CDRU_MISC_RESET_CONTROL, CDRU_SATA_RESET_N);
+ mmio_setbits_32(CDRU_MISC_RESET_CONTROL, CDRU_SATA_RESET_N);
+
+ for (port = 0; port < USE_SATA_PORTS; port++) {
+
+ sata_port = brcm_stingray_get_sata_port(port);
+ mmio_write_32(SATA_APBT_IDM_PORT_REG(sata_port,
+ SATA_APBT0_IDM_RESET_CONTROL),
+ 0x0);
+ mmio_setbits_32(SATA_APBT_IDM_PORT_REG(sata_port,
+ SATA_APBT0_IDM_IO_CONTROL_DIRECT),
+ IO_CONTROL_DIRECT_CLK_ENABLE);
+ mmio_write_32(SATA_IDM_PORT_REG(sata_port,
+ SATA0_IDM_RESET_CONTROL),
+ 0x0);
+
+ mmio_setbits_32(SATA_PORT_REG(sata_port, SATA_CORE_MEM_CTRL),
+ SATA_CORE_MEM_CTRL_ARRPOWERONIN);
+ mmio_setbits_32(SATA_PORT_REG(sata_port, SATA_CORE_MEM_CTRL),
+ SATA_CORE_MEM_CTRL_ARRPOWEROKIN);
+ mmio_setbits_32(SATA_PORT_REG(sata_port, SATA_CORE_MEM_CTRL),
+ SATA_CORE_MEM_CTRL_POWERONIN);
+ mmio_setbits_32(SATA_PORT_REG(sata_port, SATA_CORE_MEM_CTRL),
+ SATA_CORE_MEM_CTRL_POWEROKIN);
+ mmio_clrbits_32(SATA_PORT_REG(sata_port, SATA_CORE_MEM_CTRL),
+ SATA_CORE_MEM_CTRL_ISO);
+
+ mmio_clrbits_32(SATA_PORT_REG(sata_port,
+ SATA_SATA_TOP_CTRL_BUS_CTRL),
+ (DMA_DESCR_ENDIAN_CTRL | DMA_DATA_ENDIAN_CTRL));
+ }
+
+ mmio_setbits_32(NIC400_SATA_NOC_SECURITY1, SATA_NOC_SECURITY1_FIELD);
+ mmio_setbits_32(NIC400_SATA_NOC_SECURITY2, SATA_NOC_SECURITY2_FIELD);
+ mmio_setbits_32(NIC400_SATA_NOC_SECURITY3, SATA_NOC_SECURITY3_FIELD);
+ mmio_setbits_32(NIC400_SATA_NOC_SECURITY4, SATA_NOC_SECURITY4_FIELD);
+ mmio_setbits_32(NIC400_SATA_NOC_SECURITY5, SATA_NOC_SECURITY5_FIELD);
+ mmio_setbits_32(NIC400_SATA_NOC_SECURITY6, SATA_NOC_SECURITY6_FIELD);
+ mmio_setbits_32(NIC400_SATA_NOC_SECURITY7, SATA_NOC_SECURITY7_FIELD);
+ mmio_setbits_32(NIC400_SATA_NOC_SECURITY8, SATA_NOC_SECURITY8_FIELD);
+ mmio_setbits_32(NIC400_SATA_NOC_SECURITY9, SATA_NOC_SECURITY9_FIELD);
+
+ INFO("sata init done\n");
+}
+#else
+static void poweroff_sata_pll(void)
+{
+ /*
+ * SATA subsystem is clocked by LCPLL0 which is enabled by
+ * default by bootrom. Poweroff the PLL if SATA is not used
+ */
+
+ /* enable isolation */
+ mmio_setbits_32(CRMU_AON_CTRL1,
+ BIT(CRMU_AON_CTRL1__LCPLL0_ISO_IN));
+
+ /* Power off the SATA PLL/LDO */
+ mmio_clrbits_32(CRMU_AON_CTRL1,
+ (BIT(CRMU_AON_CTRL1__LCPLL0_PWRON_LDO) |
+ BIT(CRMU_AON_CTRL1__LCPLL0_PWR_ON)));
+}
+#endif
+
+#ifdef USE_AMAC
+#ifdef EMULATION_SETUP
+#define ICFG_AMAC_STRAP_CONFIG (HSLS_ICFG_REGS_BASE + 0xa5c)
+#define ICFG_AMAC_STRAP_DLL_BYPASS (1 << 2)
+#endif
+#define ICFG_AMAC_MAC_CTRL_REG (HSLS_ICFG_REGS_BASE + 0xa6c)
+#define ICFG_AMAC_MAC_FULL_DUPLEX (1 << 1)
+#define ICFG_AMAC_RGMII_PHY_CONFIG (HSLS_ICFG_REGS_BASE + 0xa60)
+#define ICFG_AMAC_SID_CONTROL (HSLS_ICFG_REGS_BASE + 0xb10)
+#define ICFG_AMAC_SID_SHIFT 5
+#define ICFG_AMAC_SID_AWADDR_OFFSET 0x0
+#define ICFG_AMAC_SID_ARADDR_OFFSET 0x4
+#define AMAC_RPHY_1000_DATARATE (1 << 20)
+#define AMAC_RPHY_FULL_DUPLEX (1 << 5)
+#define AMAC_RPHY_SPEED_OFFSET 2
+#define AMAC_RPHY_SPEED_MASK (7 << AMAC_RPHY_SPEED_OFFSET)
+#define AMAC_RPHY_1G_SPEED (2 << AMAC_RPHY_SPEED_OFFSET)
+#define ICFG_AMAC_MEM_PWR_CTRL (HSLS_ICFG_REGS_BASE + 0xa68)
+#define AMAC_ISO BIT(9)
+#define AMAC_STDBY BIT(8)
+#define AMAC_ARRPOWEROKIN BIT(7)
+#define AMAC_ARRPOWERONIN BIT(6)
+#define AMAC_POWEROKIN BIT(5)
+#define AMAC_POWERONIN BIT(4)
+
+#define AMAC_IDM0_IO_CONTROL_DIRECT (HSLS_IDM_REGS_BASE + 0x4408)
+#define AMAC_IDM0_ARCACHE_OFFSET 16
+#define AMAC_IDM0_AWCACHE_OFFSET 7
+#define AMAC_IDM0_ARCACHE_MASK (0xF << AMAC_IDM0_ARCACHE_OFFSET)
+#define AMAC_IDM0_AWCACHE_MASK (0xF << AMAC_IDM0_AWCACHE_OFFSET)
+/* ARCACHE - AWCACHE is 0xB7 for write-back no allocate */
+#define AMAC_IDM0_ARCACHE_VAL (0xb << AMAC_IDM0_ARCACHE_OFFSET)
+#define AMAC_IDM0_AWCACHE_VAL (0x7 << AMAC_IDM0_AWCACHE_OFFSET)
+
+static void brcm_stingray_amac_init(void)
+{
+ unsigned int val;
+ uintptr_t icfg_amac_sid = ICFG_AMAC_SID_CONTROL;
+
+ VERBOSE("amac init start\n");
+
+ val = SR_SID_VAL(0x3, 0x0, 0x4) << ICFG_AMAC_SID_SHIFT;
+ mmio_write_32(icfg_amac_sid + ICFG_AMAC_SID_AWADDR_OFFSET, val);
+ mmio_write_32(icfg_amac_sid + ICFG_AMAC_SID_ARADDR_OFFSET, val);
+
+ mmio_setbits_32(ICFG_AMAC_MEM_PWR_CTRL, AMAC_ARRPOWEROKIN);
+ mmio_setbits_32(ICFG_AMAC_MEM_PWR_CTRL, AMAC_ARRPOWERONIN);
+ mmio_setbits_32(ICFG_AMAC_MEM_PWR_CTRL, AMAC_POWEROKIN);
+ mmio_setbits_32(ICFG_AMAC_MEM_PWR_CTRL, AMAC_POWERONIN);
+ mmio_clrbits_32(ICFG_AMAC_MEM_PWR_CTRL, AMAC_ISO);
+ mmio_write_32(APBR_IDM_RESET_CONTROL, 0x0);
+ mmio_clrsetbits_32(ICFG_AMAC_RGMII_PHY_CONFIG, AMAC_RPHY_SPEED_MASK,
+ AMAC_RPHY_1G_SPEED); /*1 Gbps line rate*/
+ /* 1000 datarate set */
+ mmio_setbits_32(ICFG_AMAC_RGMII_PHY_CONFIG, AMAC_RPHY_1000_DATARATE);
+ /* full duplex */
+ mmio_setbits_32(ICFG_AMAC_RGMII_PHY_CONFIG, AMAC_RPHY_FULL_DUPLEX);
+#ifdef EMULATION_SETUP
+ /* DLL bypass */
+ mmio_setbits_32(ICFG_AMAC_STRAP_CONFIG, ICFG_AMAC_STRAP_DLL_BYPASS);
+#endif
+ /* serdes full duplex */
+ mmio_setbits_32(ICFG_AMAC_MAC_CTRL_REG, ICFG_AMAC_MAC_FULL_DUPLEX);
+ mmio_clrsetbits_32(AMAC_IDM0_IO_CONTROL_DIRECT, AMAC_IDM0_ARCACHE_MASK,
+ AMAC_IDM0_ARCACHE_VAL);
+ mmio_clrsetbits_32(AMAC_IDM0_IO_CONTROL_DIRECT, AMAC_IDM0_AWCACHE_MASK,
+ AMAC_IDM0_AWCACHE_VAL);
+ INFO("amac init done\n");
+}
+#endif /* USE_AMAC */
+
+static void brcm_stingray_pka_meminit(void)
+{
+ uintptr_t icfg_mem_ctrl = ICFG_PKA_MEM_PWR_CTRL;
+
+ VERBOSE("pka meminit start\n");
+
+ VERBOSE(" - arrpoweron\n");
+ mmio_setbits_32(icfg_mem_ctrl,
+ ICFG_PKA_MEM_PWR_CTRL__ARRPOWERONIN);
+ while (!(mmio_read_32(icfg_mem_ctrl) &
+ ICFG_PKA_MEM_PWR_CTRL__ARRPOWERONOUT))
+ ;
+
+ VERBOSE(" - arrpowerok\n");
+ mmio_setbits_32(icfg_mem_ctrl,
+ ICFG_PKA_MEM_PWR_CTRL__ARRPOWEROKIN);
+ while (!(mmio_read_32(icfg_mem_ctrl) &
+ ICFG_PKA_MEM_PWR_CTRL__ARRPOWEROKOUT))
+ ;
+
+ VERBOSE(" - poweron\n");
+ mmio_setbits_32(icfg_mem_ctrl,
+ ICFG_PKA_MEM_PWR_CTRL__POWERONIN);
+ while (!(mmio_read_32(icfg_mem_ctrl) &
+ ICFG_PKA_MEM_PWR_CTRL__POWERONOUT))
+ ;
+
+ VERBOSE(" - powerok\n");
+ mmio_setbits_32(icfg_mem_ctrl,
+ ICFG_PKA_MEM_PWR_CTRL__POWEROKIN);
+ while (!(mmio_read_32(icfg_mem_ctrl) &
+ ICFG_PKA_MEM_PWR_CTRL__POWEROKOUT))
+ ;
+
+ /* Wait sometime */
+ mdelay(1);
+
+ VERBOSE(" - remove isolation\n");
+ mmio_clrbits_32(icfg_mem_ctrl, ICFG_PKA_MEM_PWR_CTRL__ISO);
+
+ INFO("pka meminit done\n");
+}
+
+static void brcm_stingray_smmu_init(void)
+{
+ unsigned int val;
+ uintptr_t smmu_base = SMMU_BASE;
+
+ VERBOSE("smmu init start\n");
+
+ /* Configure SCR0 */
+ VERBOSE(" - configure scr0\n");
+ val = mmio_read_32(smmu_base + 0x0);
+ val |= (0x1 << 12);
+ mmio_write_32(smmu_base + 0x0, val);
+
+ /* Reserve context banks for secure masters */
+ arm_smmu_reserve_secure_cntxt();
+
+ /* Print configuration */
+ VERBOSE(" - scr0=0x%x scr1=0x%x scr2=0x%x\n",
+ mmio_read_32(smmu_base + 0x0),
+ mmio_read_32(smmu_base + 0x4),
+ mmio_read_32(smmu_base + 0x8));
+
+ VERBOSE(" - idr0=0x%x idr1=0x%x idr2=0x%x\n",
+ mmio_read_32(smmu_base + 0x20),
+ mmio_read_32(smmu_base + 0x24),
+ mmio_read_32(smmu_base + 0x28));
+
+ VERBOSE(" - idr3=0x%x idr4=0x%x idr5=0x%x\n",
+ mmio_read_32(smmu_base + 0x2c),
+ mmio_read_32(smmu_base + 0x30),
+ mmio_read_32(smmu_base + 0x34));
+
+ VERBOSE(" - idr6=0x%x idr7=0x%x\n",
+ mmio_read_32(smmu_base + 0x38),
+ mmio_read_32(smmu_base + 0x3c));
+
+ INFO("smmu init done\n");
+}
+
+static void brcm_stingray_dma_pl330_meminit(void)
+{
+ uintptr_t icfg_mem_ctrl = ICFG_DMAC_MEM_PWR_CTRL;
+
+ VERBOSE("dmac meminit start\n");
+
+ VERBOSE(" - arrpoweron\n");
+ mmio_setbits_32(icfg_mem_ctrl,
+ ICFG_DMAC_MEM_PWR_CTRL__ARRPOWERONIN);
+ while (!(mmio_read_32(icfg_mem_ctrl) &
+ ICFG_DMAC_MEM_PWR_CTRL__ARRPOWERONOUT))
+ ;
+
+ VERBOSE(" - arrpowerok\n");
+ mmio_setbits_32(icfg_mem_ctrl,
+ ICFG_DMAC_MEM_PWR_CTRL__ARRPOWEROKIN);
+ while (!(mmio_read_32(icfg_mem_ctrl) &
+ ICFG_DMAC_MEM_PWR_CTRL__ARRPOWEROKOUT))
+ ;
+
+ VERBOSE(" - poweron\n");
+ mmio_setbits_32(icfg_mem_ctrl,
+ ICFG_DMAC_MEM_PWR_CTRL__POWERONIN);
+ while (!(mmio_read_32(icfg_mem_ctrl) &
+ ICFG_DMAC_MEM_PWR_CTRL__POWERONOUT))
+ ;
+
+ VERBOSE(" - powerok\n");
+ mmio_setbits_32(icfg_mem_ctrl,
+ ICFG_DMAC_MEM_PWR_CTRL__POWEROKIN);
+ while (!(mmio_read_32(icfg_mem_ctrl) &
+ ICFG_DMAC_MEM_PWR_CTRL__POWEROKOUT))
+ ;
+
+ /* Wait sometime */
+ mdelay(1);
+
+ VERBOSE(" - remove isolation\n");
+ mmio_clrbits_32(icfg_mem_ctrl, ICFG_DMAC_MEM_PWR_CTRL__ISO);
+
+ INFO("dmac meminit done\n");
+}
+
+/* program the crmu access ranges for allowing non sec access*/
+static void brcm_stingray_crmu_access_init(void)
+{
+ /* Enable 0x6641c001 - 0x6641c701 for non secure access */
+ mmio_write_32(CRMU_CORE_ADDR_RANGE0_LOW, 0x6641c001);
+ mmio_write_32(CRMU_CORE_ADDR_RANGE0_LOW + 0x4, 0x6641c701);
+
+ /* Enable 0x6641d001 - 0x66424b01 for non secure access */
+ mmio_write_32(CRMU_CORE_ADDR_RANGE1_LOW, 0x6641d001);
+ mmio_write_32(CRMU_CORE_ADDR_RANGE1_LOW + 0x4, 0x66424b01);
+
+ /* Enable 0x66425001 - 0x66425f01 for non secure access */
+ mmio_write_32(CRMU_CORE_ADDR_RANGE2_LOW, 0x66425001);
+ mmio_write_32(CRMU_CORE_ADDR_RANGE2_LOW + 0x4, 0x66425f01);
+
+ INFO("crmu access init done\n");
+}
+
+static void brcm_stingray_scr_init(void)
+{
+ unsigned int val;
+ uintptr_t scr_base = SCR_BASE;
+ unsigned int clr_mask = SCR_AXCACHE_CONFIG_MASK;
+ unsigned int set_mask = SCR_TBUX_AXCACHE_CONFIG;
+
+ VERBOSE("scr init start\n");
+
+ /* awdomain=0x1 and ardomain=0x1 */
+ mmio_clrsetbits_32(scr_base + 0x0, clr_mask, set_mask);
+ val = mmio_read_32(scr_base + 0x0);
+ VERBOSE(" - set tbu0_config=0x%x\n", val);
+
+ /* awdomain=0x1 and ardomain=0x1 */
+ mmio_clrsetbits_32(scr_base + 0x4, clr_mask, set_mask);
+ val = mmio_read_32(scr_base + 0x4);
+ VERBOSE(" - set tbu1_config=0x%x\n", val);
+
+ /* awdomain=0x1 and ardomain=0x1 */
+ mmio_clrsetbits_32(scr_base + 0x8, clr_mask, set_mask);
+ val = mmio_read_32(scr_base + 0x8);
+ VERBOSE(" - set tbu2_config=0x%x\n", val);
+
+ /* awdomain=0x1 and ardomain=0x1 */
+ mmio_clrsetbits_32(scr_base + 0xc, clr_mask, set_mask);
+ val = mmio_read_32(scr_base + 0xc);
+ VERBOSE(" - set tbu3_config=0x%x\n", val);
+
+ /* awdomain=0x1 and ardomain=0x1 */
+ mmio_clrsetbits_32(scr_base + 0x10, clr_mask, set_mask);
+ val = mmio_read_32(scr_base + 0x10);
+ VERBOSE(" - set tbu4_config=0x%x\n", val);
+
+ /* awdomain=0x0 and ardomain=0x0 */
+ mmio_clrbits_32(scr_base + 0x14, clr_mask);
+ val = mmio_read_32(scr_base + 0x14);
+ VERBOSE(" - set gic_config=0x%x\n", val);
+
+ INFO("scr init done\n");
+}
+
+static void brcm_stingray_hsls_tzpcprot_init(void)
+{
+ unsigned int val;
+ uintptr_t tzpcdecprot_base = HSLS_TZPC_BASE;
+
+ VERBOSE("hsls tzpcprot init start\n");
+
+ /* Treat third-party masters as non-secured */
+ val = 0;
+ val |= BIT(6); /* SDIO1 */
+ val |= BIT(5); /* SDIO0 */
+ val |= BIT(0); /* AMAC */
+ mmio_write_32(tzpcdecprot_base + 0x810, val);
+
+ /* Print TZPC decode status registers */
+ VERBOSE(" - tzpcdecprot0=0x%x\n",
+ mmio_read_32(tzpcdecprot_base + 0x800));
+
+ VERBOSE(" - tzpcdecprot1=0x%x\n",
+ mmio_read_32(tzpcdecprot_base + 0x80c));
+
+ INFO("hsls tzpcprot init done\n");
+}
+
+#ifdef USE_I2S
+#define ICFG_AUDIO_POWER_CTRL (HSLS_ICFG_REGS_BASE + 0xaa8)
+#define ICFG_AUDIO_POWER_CTRL__POWERONIN BIT(0)
+#define ICFG_AUDIO_POWER_CTRL__POWEROKIN BIT(1)
+#define ICFG_AUDIO_POWER_CTRL__ARRPOWERONIN BIT(2)
+#define ICFG_AUDIO_POWER_CTRL__ARRPOWEROKIN BIT(3)
+#define ICFG_AUDIO_POWER_CTRL__POWERONOUT BIT(4)
+#define ICFG_AUDIO_POWER_CTRL__POWEROKOUT BIT(5)
+#define ICFG_AUDIO_POWER_CTRL__ARRPOWERONOUT BIT(6)
+#define ICFG_AUDIO_POWER_CTRL__ARRPOWEROKOUT BIT(7)
+#define ICFG_AUDIO_POWER_CTRL__ISO BIT(8)
+#define ICFG_AUDIO_SID_CONTROL (HSLS_ICFG_REGS_BASE + 0xaf8)
+#define ICFG_AUDIO_SID_SHIFT 5
+#define ICFG_AUDIO_SID_AWADDR_OFFSET 0x0
+#define ICFG_AUDIO_SID_ARADDR_OFFSET 0x4
+
+#define I2S_RESET_CONTROL (HSLS_IDM_REGS_BASE + 0x1800)
+#define I2S_IDM_IO_CONTROL (HSLS_IDM_REGS_BASE + 0x1408)
+#define IO_CONTROL_CLK_ENABLE BIT(0)
+#define I2S_IDM0_ARCACHE_OFFSET 16
+#define I2S_IDM0_AWCACHE_OFFSET 20
+#define I2S_IDM0_ARCACHE_MASK (0xF << I2S_IDM0_ARCACHE_OFFSET)
+#define I2S_IDM0_AWCACHE_MASK (0xF << I2S_IDM0_AWCACHE_OFFSET)
+/* ARCACHE - AWCACHE is 0x22 Normal Non-cacheable Non-bufferable. */
+#define I2S_IDM0_ARCACHE_VAL (0x2 << I2S_IDM0_ARCACHE_OFFSET)
+#define I2S_IDM0_AWCACHE_VAL (0x2 << I2S_IDM0_AWCACHE_OFFSET)
+
+static void brcm_stingray_audio_init(void)
+{
+ unsigned int val;
+ uintptr_t icfg_mem_ctrl = ICFG_AUDIO_POWER_CTRL;
+ uintptr_t icfg_audio_sid = ICFG_AUDIO_SID_CONTROL;
+
+ mmio_write_32(I2S_RESET_CONTROL, 0x0);
+
+ mmio_clrsetbits_32(I2S_IDM_IO_CONTROL, I2S_IDM0_ARCACHE_MASK,
+ I2S_IDM0_ARCACHE_VAL);
+
+ mmio_clrsetbits_32(I2S_IDM_IO_CONTROL, I2S_IDM0_AWCACHE_MASK,
+ I2S_IDM0_AWCACHE_VAL);
+
+ mmio_setbits_32(I2S_IDM_IO_CONTROL, IO_CONTROL_CLK_ENABLE);
+
+ VERBOSE("audio meminit start\n");
+
+ VERBOSE(" - configure stream_id = 0x6001\n");
+ val = SR_SID_VAL(0x3, 0x0, 0x1) << ICFG_AUDIO_SID_SHIFT;
+ mmio_write_32(icfg_audio_sid + ICFG_AUDIO_SID_AWADDR_OFFSET, val);
+ mmio_write_32(icfg_audio_sid + ICFG_AUDIO_SID_ARADDR_OFFSET, val);
+
+ VERBOSE(" - arrpoweron\n");
+ mmio_setbits_32(icfg_mem_ctrl,
+ ICFG_AUDIO_POWER_CTRL__ARRPOWERONIN);
+ while (!(mmio_read_32(icfg_mem_ctrl) &
+ ICFG_AUDIO_POWER_CTRL__ARRPOWERONOUT))
+ ;
+
+ VERBOSE(" - arrpowerok\n");
+ mmio_setbits_32(icfg_mem_ctrl,
+ ICFG_AUDIO_POWER_CTRL__ARRPOWEROKIN);
+ while (!(mmio_read_32(icfg_mem_ctrl) &
+ ICFG_AUDIO_POWER_CTRL__ARRPOWEROKOUT))
+ ;
+
+ VERBOSE(" - poweron\n");
+ mmio_setbits_32(icfg_mem_ctrl,
+ ICFG_AUDIO_POWER_CTRL__POWERONIN);
+ while (!(mmio_read_32(icfg_mem_ctrl) &
+ ICFG_AUDIO_POWER_CTRL__POWERONOUT))
+ ;
+
+ VERBOSE(" - powerok\n");
+ mmio_setbits_32(icfg_mem_ctrl,
+ ICFG_AUDIO_POWER_CTRL__POWEROKIN);
+ while (!(mmio_read_32(icfg_mem_ctrl) &
+ ICFG_AUDIO_POWER_CTRL__POWEROKOUT))
+ ;
+
+ /* Wait sometime */
+ mdelay(1);
+
+ VERBOSE(" - remove isolation\n");
+ mmio_clrbits_32(icfg_mem_ctrl, ICFG_AUDIO_POWER_CTRL__ISO);
+
+ INFO("audio meminit done\n");
+}
+#endif /* USE_I2S */
+
+/*
+ * These defines do not match the regfile but they are renamed in a way such
+ * that they are much more readible
+ */
+
+#define SCR_GPV_SMMU_NS (SCR_GPV_BASE + 0x28)
+#define SCR_GPV_GIC500_NS (SCR_GPV_BASE + 0x34)
+#define HSLS_GPV_NOR_S0_NS (HSLS_GPV_BASE + 0x14)
+#define HSLS_GPV_IDM1_NS (HSLS_GPV_BASE + 0x18)
+#define HSLS_GPV_IDM2_NS (HSLS_GPV_BASE + 0x1c)
+#define HSLS_SDIO0_SLAVE_NS (HSLS_GPV_BASE + 0x20)
+#define HSLS_SDIO1_SLAVE_NS (HSLS_GPV_BASE + 0x24)
+#define HSLS_GPV_APBY_NS (HSLS_GPV_BASE + 0x2c)
+#define HSLS_GPV_APBZ_NS (HSLS_GPV_BASE + 0x30)
+#define HSLS_GPV_APBX_NS (HSLS_GPV_BASE + 0x34)
+#define HSLS_GPV_APBS_NS (HSLS_GPV_BASE + 0x38)
+#define HSLS_GPV_QSPI_S0_NS (HSLS_GPV_BASE + 0x68)
+#define HSLS_GPV_APBR_NS (HSLS_GPV_BASE + 0x6c)
+#define FS4_CRYPTO_GPV_RM_SLAVE_NS (FS4_CRYPTO_GPV_BASE + 0x8)
+#define FS4_CRYPTO_GPV_APB_SWITCH_NS (FS4_CRYPTO_GPV_BASE + 0xc)
+#define FS4_RAID_GPV_RM_SLAVE_NS (FS4_RAID_GPV_BASE + 0x8)
+#define FS4_RAID_GPV_APB_SWITCH_NS (FS4_RAID_GPV_BASE + 0xc)
+#define FS4_CRYPTO_IDM_NS (NIC400_FS_NOC_ROOT + 0x1c)
+#define FS4_RAID_IDM_NS (NIC400_FS_NOC_ROOT + 0x28)
+
+#define FS4_CRYPTO_RING_COUNT 32
+#define FS4_CRYPTO_DME_COUNT 10
+#define FS4_CRYPTO_AE_COUNT 10
+#define FS4_CRYPTO_START_STREAM_ID 0x4000
+#define FS4_CRYPTO_MSI_DEVICE_ID 0x4100
+
+#define FS4_RAID_RING_COUNT 32
+#define FS4_RAID_DME_COUNT 8
+#define FS4_RAID_AE_COUNT 8
+#define FS4_RAID_START_STREAM_ID 0x4200
+#define FS4_RAID_MSI_DEVICE_ID 0x4300
+
+#define FS6_PKI_AXI_SLAVE_NS \
+ (NIC400_FS_NOC_ROOT + NIC400_FS_NOC_SECURITY2_OFFSET)
+
+#define FS6_PKI_AE_DME_APB_NS \
+ (NIC400_FS_NOC_ROOT + NIC400_FS_NOC_SECURITY7_OFFSET)
+#define FS6_PKI_IDM_IO_CONTROL_DIRECT 0x0
+#define FS6_PKI_IDM_RESET_CONTROL 0x0
+#define FS6_PKI_RING_COUNT 32
+#define FS6_PKI_DME_COUNT 1
+#define FS6_PKI_AE_COUNT 4
+#define FS6_PKI_START_STREAM_ID 0x4000
+#define FS6_PKI_MSI_DEVICE_ID 0x4100
+
+static void brcm_stingray_security_init(void)
+{
+ unsigned int val;
+
+ val = mmio_read_32(SCR_GPV_SMMU_NS);
+ val |= BIT(0); /* SMMU NS = 1 */
+ mmio_write_32(SCR_GPV_SMMU_NS, val);
+
+ val = mmio_read_32(SCR_GPV_GIC500_NS);
+ val |= BIT(0); /* GIC-500 NS = 1 */
+ mmio_write_32(SCR_GPV_GIC500_NS, val);
+
+ val = mmio_read_32(HSLS_GPV_NOR_S0_NS);
+ val |= BIT(0); /* NOR SLAVE NS = 1 */
+ mmio_write_32(HSLS_GPV_NOR_S0_NS, val);
+
+ val = mmio_read_32(HSLS_GPV_IDM1_NS);
+ val |= BIT(0); /* DMA IDM NS = 1 */
+ val |= BIT(1); /* I2S IDM NS = 1 */
+ val |= BIT(2); /* AMAC IDM NS = 1 */
+ val |= BIT(3); /* SDIO0 IDM NS = 1 */
+ val |= BIT(4); /* SDIO1 IDM NS = 1 */
+ val |= BIT(5); /* DS_3 IDM NS = 1 */
+ mmio_write_32(HSLS_GPV_IDM1_NS, val);
+
+ val = mmio_read_32(HSLS_GPV_IDM2_NS);
+ val |= BIT(2); /* QSPI IDM NS = 1 */
+ val |= BIT(1); /* NOR IDM NS = 1 */
+ val |= BIT(0); /* NAND IDM NS = 1 */
+ mmio_write_32(HSLS_GPV_IDM2_NS, val);
+
+ val = mmio_read_32(HSLS_GPV_APBY_NS);
+ val |= BIT(10); /* I2S NS = 1 */
+ val |= BIT(4); /* IOPAD NS = 1 */
+ val |= 0xf; /* UARTx NS = 1 */
+ mmio_write_32(HSLS_GPV_APBY_NS, val);
+
+ val = mmio_read_32(HSLS_GPV_APBZ_NS);
+ val |= BIT(2); /* RNG NS = 1 */
+ mmio_write_32(HSLS_GPV_APBZ_NS, val);
+
+ val = mmio_read_32(HSLS_GPV_APBS_NS);
+ val |= 0x3; /* SPIx NS = 1 */
+ mmio_write_32(HSLS_GPV_APBS_NS, val);
+
+ val = mmio_read_32(HSLS_GPV_APBR_NS);
+ val |= BIT(7); /* QSPI APB NS = 1 */
+ val |= BIT(6); /* NAND APB NS = 1 */
+ val |= BIT(5); /* NOR APB NS = 1 */
+ val |= BIT(4); /* AMAC APB NS = 1 */
+ val |= BIT(1); /* DMA S1 APB NS = 1 */
+ mmio_write_32(HSLS_GPV_APBR_NS, val);
+
+ val = mmio_read_32(HSLS_SDIO0_SLAVE_NS);
+ val |= BIT(0); /* SDIO0 NS = 1 */
+ mmio_write_32(HSLS_SDIO0_SLAVE_NS, val);
+
+ val = mmio_read_32(HSLS_SDIO1_SLAVE_NS);
+ val |= BIT(0); /* SDIO1 NS = 1 */
+ mmio_write_32(HSLS_SDIO1_SLAVE_NS, val);
+
+ val = mmio_read_32(HSLS_GPV_APBX_NS);
+ val |= BIT(14); /* SMBUS1 NS = 1 */
+ val |= BIT(13); /* GPIO NS = 1 */
+ val |= BIT(12); /* WDT NS = 1 */
+ val |= BIT(11); /* SMBUS0 NS = 1 */
+ val |= BIT(10); /* Timer7 NS = 1 */
+ val |= BIT(9); /* Timer6 NS = 1 */
+ val |= BIT(8); /* Timer5 NS = 1 */
+ val |= BIT(7); /* Timer4 NS = 1 */
+ val |= BIT(6); /* Timer3 NS = 1 */
+ val |= BIT(5); /* Timer2 NS = 1 */
+ val |= BIT(4); /* Timer1 NS = 1 */
+ val |= BIT(3); /* Timer0 NS = 1 */
+ val |= BIT(2); /* MDIO NS = 1 */
+ val |= BIT(1); /* PWM NS = 1 */
+ mmio_write_32(HSLS_GPV_APBX_NS, val);
+
+ val = mmio_read_32(HSLS_GPV_QSPI_S0_NS);
+ val |= BIT(0); /* QSPI NS = 1 */
+ mmio_write_32(HSLS_GPV_QSPI_S0_NS, val);
+
+#ifdef USE_FS4
+ val = 0x1; /* FS4 Crypto rm_slave */
+ mmio_write_32(FS4_CRYPTO_GPV_RM_SLAVE_NS, val);
+ val = 0x1; /* FS4 Crypto apb_switch */
+ mmio_write_32(FS4_CRYPTO_GPV_APB_SWITCH_NS, val);
+
+ val = 0x1; /* FS4 Raid rm_slave */
+ mmio_write_32(FS4_RAID_GPV_RM_SLAVE_NS, val);
+ val = 0x1; /* FS4 Raid apb_switch */
+ mmio_write_32(FS4_RAID_GPV_APB_SWITCH_NS, val);
+
+ val = 0x1; /* FS4 Crypto IDM */
+ mmio_write_32(FS4_CRYPTO_IDM_NS, val);
+ val = 0x1; /* FS4 RAID IDM */
+ mmio_write_32(FS4_RAID_IDM_NS, val);
+#endif
+
+#ifdef BL31_CCN_NONSECURE
+ /* Enable non-secure access to CCN registers */
+ mmio_write_32(OLY_MN_REGISTERS_NODE0_SECURE_ACCESS, 0x1);
+#endif
+
+#ifdef DDR_CTRL_PHY_NONSECURE
+ mmio_write_32(SCR_NOC_DDR_REGISTER_ACCESS, 0x1);
+#endif
+
+ paxc_mhb_ns_init();
+
+ /* unlock scr idm for non secure access */
+ mmio_write_32(SCR_NOC_SECURITY0, 0xffffffff);
+
+ INFO("security init done\r\n");
+}
+
+void brcm_gpio_pad_ns_init(void)
+{
+ /* configure all GPIO pads for non secure world access*/
+ mmio_write_32(GPIO_S_CNTRL_REG, 0xffffffff); /* 128-140 gpio pads */
+ mmio_write_32(GPIO_S_CNTRL_REG + 0x4, 0xffffffff); /* 96-127 gpio pad */
+ mmio_write_32(GPIO_S_CNTRL_REG + 0x8, 0xffffffff); /* 64-95 gpio pad */
+ mmio_write_32(GPIO_S_CNTRL_REG + 0xc, 0xffffffff); /* 32-63 gpio pad */
+ mmio_write_32(GPIO_S_CNTRL_REG + 0x10, 0xffffffff); /* 0-31 gpio pad */
+}
+
+#ifndef USE_DDR
+static void brcm_stingray_sram_ns_init(void)
+{
+ uintptr_t sram_root = TZC400_FS_SRAM_ROOT;
+ uintptr_t noc_root = NIC400_FS_NOC_ROOT;
+
+ mmio_write_32(sram_root + GATE_KEEPER_OFFSET, 1);
+ mmio_write_32(sram_root + REGION_ATTRIBUTES_0_OFFSET, 0xc0000000);
+ mmio_write_32(sram_root + REGION_ID_ACCESS_0_OFFSET, 0x00010001);
+ mmio_write_32(noc_root + NIC400_FS_NOC_SECURITY4_OFFSET, 0x1);
+ INFO(" stingray sram ns init done.\n");
+}
+#endif
+
+static void ccn_pre_init(void)
+{
+ /*
+ * Set WFC bit of RN-I nodes where FS4 is connected.
+ * This is required inorder to wait for read/write requests
+ * completion acknowledgment. Otherwise FS4 Ring Manager is
+ * getting stale data because of re-ordering of read/write
+ * requests at CCN level
+ */
+ mmio_setbits_32(OLY_RNI3PDVM_REGISTERS_NODE8_AUX_CTL,
+ OLY_RNI3PDVM_REGISTERS_NODE8_AUX_CTL_WFC);
+}
+
+static void ccn_post_init(void)
+{
+ mmio_setbits_32(OLY_HNI_REGISTERS_NODE0_PCIERC_RNI_NODEID_LIST,
+ SRP_RNI_PCIE_CONNECTED);
+ mmio_setbits_32(OLY_HNI_REGISTERS_NODE0_SA_AUX_CTL,
+ SA_AUX_CTL_SER_DEVNE_WR);
+
+ mmio_clrbits_32(OLY_HNI_REGISTERS_NODE0_POS_CONTROL,
+ POS_CONTROL_HNI_POS_EN);
+ mmio_clrbits_32(OLY_HNI_REGISTERS_NODE0_SA_AUX_CTL,
+ SA_AUX_CTL_POS_EARLY_WR_COMP_EN);
+}
+
+#ifndef BL31_BOOT_PRELOADED_SCP
+static void crmu_init(void)
+{
+ /*
+ * Configure CRMU for using SMMU
+ */
+
+ /*Program CRMU Stream ID */
+ mmio_write_32(CRMU_MASTER_AXI_ARUSER_CONFIG,
+ (CRMU_STREAM_ID << CRMU_SID_SHIFT));
+ mmio_write_32(CRMU_MASTER_AXI_AWUSER_CONFIG,
+ (CRMU_STREAM_ID << CRMU_SID_SHIFT));
+
+ /* Create Identity mapping */
+ arm_smmu_create_identity_map(DOMAIN_CRMU);
+
+ /* Enable Client Port for Secure Masters*/
+ arm_smmu_enable_secure_client_port();
+}
+#endif
+
+static void brcm_fsx_init(void)
+{
+#if defined(USE_FS4) && defined(USE_FS6)
+ #error "USE_FS4 and USE_FS6 should not be used together"
+#endif
+
+#ifdef USE_FS4
+ fsx_init(eFS4_CRYPTO, FS4_CRYPTO_RING_COUNT, FS4_CRYPTO_DME_COUNT,
+ FS4_CRYPTO_AE_COUNT, FS4_CRYPTO_START_STREAM_ID,
+ FS4_CRYPTO_MSI_DEVICE_ID, FS4_CRYPTO_IDM_IO_CONTROL_DIRECT,
+ FS4_CRYPTO_IDM_RESET_CONTROL, FS4_CRYPTO_BASE,
+ FS4_CRYPTO_DME_BASE);
+
+ fsx_init(eFS4_RAID, FS4_RAID_RING_COUNT, FS4_RAID_DME_COUNT,
+ FS4_RAID_AE_COUNT, FS4_RAID_START_STREAM_ID,
+ FS4_RAID_MSI_DEVICE_ID, FS4_RAID_IDM_IO_CONTROL_DIRECT,
+ FS4_RAID_IDM_RESET_CONTROL, FS4_RAID_BASE,
+ FS4_RAID_DME_BASE);
+
+ fsx_meminit("raid",
+ FS4_RAID_IDM_IO_CONTROL_DIRECT,
+ FS4_RAID_IDM_IO_STATUS);
+#endif
+}
+
+static void bcm_bl33_pass_info(void)
+{
+ struct bl33_info *info = (struct bl33_info *)BL33_SHARED_DDR_BASE;
+
+ if (sizeof(*info) > BL33_SHARED_DDR_SIZE)
+ WARN("bl33 shared area not reserved\n");
+
+ info->version = BL33_INFO_VERSION;
+ info->chip.chip_id = PLAT_CHIP_ID_GET;
+ info->chip.rev_id = PLAT_CHIP_REV_GET;
+}
+
+DEFINE_RENAME_SYSREG_RW_FUNCS(l2ctlr_el1, CORTEX_A72_L2CTLR_EL1)
+
+void plat_bcm_bl31_early_platform_setup(void *from_bl2,
+ bl_params_t *plat_params_from_bl2)
+{
+#ifdef BL31_BOOT_PRELOADED_SCP
+ image_info_t scp_image_info;
+
+ scp_image_info.image_base = PRELOADED_SCP_BASE;
+ scp_image_info.image_size = PRELOADED_SCP_SIZE;
+ plat_bcm_bl2_plat_handle_scp_bl2(&scp_image_info);
+#endif
+ /*
+ * In BL31, logs are saved to DDR and we have much larger space to
+ * store logs. We can now afford to save all logs >= the 'INFO' level
+ */
+ bcm_elog_init((void *)BCM_ELOG_BL31_BASE, BCM_ELOG_BL31_SIZE,
+ LOG_LEVEL_INFO);
+
+ INFO("L2CTLR = 0x%lx\n", read_l2ctlr_el1());
+
+ brcm_timer_sync_init();
+
+ brcm_stingray_dma_pl330_init();
+
+ brcm_stingray_dma_pl330_meminit();
+
+ brcm_stingray_spi_pl022_init(APBS_IDM_IDM_RESET_CONTROL);
+
+#ifdef USE_AMAC
+ brcm_stingray_amac_init();
+#endif
+
+ brcm_stingray_sdio_init();
+
+#ifdef NCSI_IO_DRIVE_STRENGTH_MA
+ brcm_stingray_ncsi_init();
+#endif
+
+#ifdef USE_USB
+ xhci_phy_init();
+#endif
+
+#ifdef USE_SATA
+ brcm_stingray_sata_init();
+#else
+ poweroff_sata_pll();
+#endif
+
+ ccn_pre_init();
+
+ brcm_fsx_init();
+
+ brcm_stingray_smmu_init();
+
+ brcm_stingray_pka_meminit();
+
+ brcm_stingray_crmu_access_init();
+
+ brcm_stingray_scr_init();
+
+ brcm_stingray_hsls_tzpcprot_init();
+
+#ifdef USE_I2S
+ brcm_stingray_audio_init();
+#endif
+
+ ccn_post_init();
+
+ paxb_init();
+
+ paxc_init();
+
+#ifndef BL31_BOOT_PRELOADED_SCP
+ crmu_init();
+#endif
+
+ /* Note: this should be last thing because
+ * FS4 GPV registers only work after FS4 block
+ * (i.e. crypto,raid,cop) is out of reset.
+ */
+ brcm_stingray_security_init();
+
+ brcm_gpio_pad_ns_init();
+
+#ifndef USE_DDR
+ brcm_stingray_sram_ns_init();
+#endif
+
+#ifdef BL31_FORCE_CPU_FULL_FREQ
+ bcm_set_ihost_pll_freq(0x0, PLL_FREQ_FULL);
+#endif
+
+ brcm_stingray_gain_qspi_control();
+
+#ifdef USE_PAXC
+ /*
+ * Check that the handshake has occurred and report ChiMP status.
+ * This is required. Otherwise (especially on Palladium)
+ * Linux might have booted to the pcie stage whereas
+ * ChiMP has not yet booted. Note that nic_mode case has already
+ * been considered above.
+ */
+ if ((boot_source_get() != BOOT_SOURCE_QSPI) &&
+ (!bcm_chimp_is_nic_mode()) &&
+ (!bcm_chimp_wait_handshake())
+ ) {
+ /* Does ChiMP report an error ? */
+ uint32_t err;
+
+ err = bcm_chimp_read_ctrl(CHIMP_REG_CTRL_BPE_STAT_REG);
+ if ((err & CHIMP_ERROR_MASK) == 0)
+ /* ChiMP has not booted yet, but no error reported */
+ WARN("ChiMP not booted yet, but no error reported.\n");
+ }
+
+#if DEBUG
+ if (boot_source_get() != BOOT_SOURCE_QSPI)
+ INFO("Current ChiMP Status: 0x%x; bpe_mod reg: 0x%x\n"
+ "fastboot register: 0x%x; handshake register 0x%x\n",
+ bcm_chimp_read_ctrl(CHIMP_REG_CTRL_BPE_STAT_REG),
+ bcm_chimp_read_ctrl(CHIMP_REG_CTRL_BPE_MODE_REG),
+ bcm_chimp_read_ctrl(CHIMP_REG_CTRL_FSTBOOT_PTR_REG),
+ bcm_chimp_read(CHIMP_REG_ECO_RESERVED));
+#endif /* DEBUG */
+#endif
+
+#ifdef FS4_DISABLE_CLOCK
+ flush_dcache_range(
+ PLAT_BRCM_TRUSTED_SRAM_BASE,
+ PLAT_BRCM_TRUSTED_SRAM_SIZE);
+ fs4_disable_clocks(true, true, true);
+#endif
+
+ /* pass information to BL33 through shared DDR region */
+ bcm_bl33_pass_info();
+
+ /*
+ * We are not yet at the end of BL31, but we can stop log here so we do
+ * not need to add 'bcm_elog_exit' to the standard BL31 code. The
+ * benefit of capturing BL31 logs after this is very minimal in a
+ * production system
+ */
+ bcm_elog_exit();
+
+#if !BRCM_DISABLE_TRUSTED_WDOG
+ /*
+ * Secure watchdog was started earlier in BL2, now it's time to stop
+ * it
+ */
+ sp805_stop(ARM_SP805_TWDG_BASE);
+#endif
+}
diff --git a/plat/brcm/board/stingray/src/brcm_pm_ops.c b/plat/brcm/board/stingray/src/brcm_pm_ops.c
new file mode 100644
index 0000000..5e07fac
--- /dev/null
+++ b/plat/brcm/board/stingray/src/brcm_pm_ops.c
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/ccn.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <lib/spinlock.h>
+
+#include <brcm_scpi.h>
+#include <chimp.h>
+#include <cmn_plat_util.h>
+#include <plat_brcm.h>
+#include <platform_def.h>
+#include <sr_utils.h>
+
+#include "m0_cfg.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[MPIDR_AFFLVL2])
+
+#define VENDOR_RST_TYPE_SHIFT 4
+
+#if HW_ASSISTED_COHERENCY
+/*
+ * On systems where participant CPUs are cache-coherent, we can use spinlocks
+ * instead of bakery locks.
+ */
+spinlock_t event_lock;
+#define event_lock_get(_lock) spin_lock(&_lock)
+#define event_lock_release(_lock) spin_unlock(&_lock)
+
+#else
+/*
+ * Use bakery locks for state coordination as not all participants are
+ * cache coherent now.
+ */
+DEFINE_BAKERY_LOCK(event_lock);
+#define event_lock_get(_lock) bakery_lock_get(&_lock)
+#define event_lock_release(_lock) bakery_lock_release(&_lock)
+#endif
+
+static int brcm_pwr_domain_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_brcm_power_state(mpidr, scpi_power_on, scpi_power_on,
+ scpi_power_on);
+
+ return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+static void brcm_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ unsigned long cluster_id = MPIDR_AFFLVL1_VAL(read_mpidr());
+
+ /* Assert that the system power domain need not be initialized */
+ assert(SYSTEM_PWR_STATE(target_state) == PLAT_LOCAL_STATE_RUN);
+
+ assert(CORE_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF);
+
+ /*
+ * Perform the common cluster specific operations i.e enable coherency
+ * if this cluster was off.
+ */
+ if (CLUSTER_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF) {
+ INFO("Cluster #%lu entering to snoop/dvm domain\n", cluster_id);
+ ccn_enter_snoop_dvm_domain(1 << cluster_id);
+ }
+
+ /* Program the gic per-cpu distributor or re-distributor interface */
+ plat_brcm_gic_pcpu_init();
+
+ /* Enable the gic cpu interface */
+ plat_brcm_gic_cpuif_enable();
+}
+
+static void brcm_power_down_common(void)
+{
+ unsigned int standbywfil2, standbywfi;
+ uint64_t mpidr = read_mpidr_el1();
+
+ switch (MPIDR_AFFLVL1_VAL(mpidr)) {
+ case 0x0:
+ standbywfi = CDRU_PROC_EVENT_CLEAR__IH0_CDRU_STANDBYWFI;
+ standbywfil2 = CDRU_PROC_EVENT_CLEAR__IH0_CDRU_STANDBYWFIL2;
+ break;
+ case 0x1:
+ standbywfi = CDRU_PROC_EVENT_CLEAR__IH1_CDRU_STANDBYWFI;
+ standbywfil2 = CDRU_PROC_EVENT_CLEAR__IH1_CDRU_STANDBYWFIL2;
+ break;
+ case 0x2:
+ standbywfi = CDRU_PROC_EVENT_CLEAR__IH2_CDRU_STANDBYWFI;
+ standbywfil2 = CDRU_PROC_EVENT_CLEAR__IH2_CDRU_STANDBYWFIL2;
+ break;
+ case 0x3:
+ standbywfi = CDRU_PROC_EVENT_CLEAR__IH3_CDRU_STANDBYWFI;
+ standbywfil2 = CDRU_PROC_EVENT_CLEAR__IH3_CDRU_STANDBYWFIL2;
+ break;
+ default:
+ ERROR("Invalid cluster #%" PRIx64 "\n", MPIDR_AFFLVL1_VAL(mpidr));
+ return;
+ }
+ /* Clear the WFI status bit */
+ event_lock_get(event_lock);
+ mmio_setbits_32(CDRU_PROC_EVENT_CLEAR,
+ (1 << (standbywfi + MPIDR_AFFLVL0_VAL(mpidr))) |
+ (1 << standbywfil2));
+ event_lock_release(event_lock);
+}
+
+/*
+ * Helper function to inform power down state to SCP.
+ */
+static void brcm_scp_suspend(const psci_power_state_t *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 (SYSTEM_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF)
+ system_state = scpi_power_retention;
+
+ /* Check if Cluster is to be turned off */
+ if (CLUSTER_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF)
+ cluster_state = scpi_power_off;
+
+ /*
+ * Ask the SCP to power down the appropriate components depending upon
+ * their state.
+ */
+ scpi_set_brcm_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.
+ */
+static void brcm_scp_off(const psci_power_state_t *target_state)
+{
+ brcm_scp_suspend(target_state);
+}
+
+static void brcm_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ unsigned long cluster_id = MPIDR_AFFLVL1_VAL(read_mpidr_el1());
+
+ assert(CORE_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF);
+ /* Prevent interrupts from spuriously waking up this cpu */
+ plat_brcm_gic_cpuif_disable();
+
+ /* Turn redistributor off */
+ plat_brcm_gic_redistif_off();
+
+ /* If Cluster is to be turned off, disable coherency */
+ if (CLUSTER_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF)
+ ccn_exit_snoop_dvm_domain(1 << cluster_id);
+
+ brcm_power_down_common();
+
+ brcm_scp_off(target_state);
+}
+
+/*******************************************************************************
+ * Handler called when the CPU power domain is about to enter standby.
+ ******************************************************************************/
+static void brcm_cpu_standby(plat_local_state_t cpu_state)
+{
+ unsigned int scr;
+
+ assert(cpu_state == PLAT_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);
+}
+
+/*
+ * Helper function to shutdown the system via SCPI.
+ */
+static void __dead2 brcm_scp_sys_shutdown(void)
+{
+ /*
+ * Disable GIC CPU interface to prevent pending interrupt
+ * from waking up the AP from WFI.
+ */
+ plat_brcm_gic_cpuif_disable();
+
+ /* Flush and invalidate data cache */
+ dcsw_op_all(DCCISW);
+
+ /* Bring Cluster out of coherency domain as its going to die */
+ plat_brcm_interconnect_exit_coherency();
+
+ brcm_power_down_common();
+
+ /* Send the power down request to the SCP */
+ scpi_sys_power_state(scpi_system_shutdown);
+
+ wfi();
+ ERROR("BRCM System Off: operation not handled.\n");
+ panic();
+}
+
+/*
+ * Helper function to reset the system
+ */
+static void __dead2 brcm_scp_sys_reset(unsigned int reset_type)
+{
+ /*
+ * Disable GIC CPU interface to prevent pending interrupt
+ * from waking up the AP from WFI.
+ */
+ plat_brcm_gic_cpuif_disable();
+
+ /* Flush and invalidate data cache */
+ dcsw_op_all(DCCISW);
+
+ /* Bring Cluster out of coherency domain as its going to die */
+ plat_brcm_interconnect_exit_coherency();
+
+ brcm_power_down_common();
+
+ /* Send the system reset request to the SCP
+ *
+ * As per PSCI spec system power state could be
+ * 0-> Shutdown
+ * 1-> Reboot- Board level Reset
+ * 2-> Reset - SoC level Reset
+ *
+ * Spec allocates 8 bits, 2 nibble, for this. One nibble is sufficient
+ * for sending the state hence We are utilizing 2nd nibble for vendor
+ * define reset type.
+ */
+ scpi_sys_power_state((reset_type << VENDOR_RST_TYPE_SHIFT) |
+ scpi_system_reboot);
+
+ wfi();
+ ERROR("BRCM System Reset: operation not handled.\n");
+ panic();
+}
+
+static void __dead2 brcm_system_reset(void)
+{
+ unsigned int reset_type;
+
+ if (bcm_chimp_is_nic_mode())
+ reset_type = SOFT_RESET_L3;
+ else
+ reset_type = SOFT_SYS_RESET_L1;
+
+ brcm_scp_sys_reset(reset_type);
+}
+
+static int brcm_system_reset2(int is_vendor, int reset_type,
+ u_register_t cookie)
+{
+ if (!is_vendor) {
+ /* Architectural warm boot: only warm reset is supported */
+ reset_type = SOFT_RESET_L3;
+ } else {
+ uint32_t boot_source = (uint32_t)cookie;
+
+ boot_source &= BOOT_SOURCE_MASK;
+ brcm_stingray_set_straps(boot_source);
+ }
+ brcm_scp_sys_reset(reset_type);
+
+ /*
+ * brcm_scp_sys_reset cannot return (it is a __dead function),
+ * but brcm_system_reset2 has to return some value, even in
+ * this case.
+ */
+ return 0;
+}
+
+static int brcm_validate_ns_entrypoint(uintptr_t entrypoint)
+{
+ /*
+ * Check if the non secure entrypoint lies within the non
+ * secure DRAM.
+ */
+ if ((entrypoint >= BRCM_NS_DRAM1_BASE) &&
+ (entrypoint < (BRCM_NS_DRAM1_BASE + BRCM_NS_DRAM1_SIZE)))
+ return PSCI_E_SUCCESS;
+#ifdef __aarch64__
+ if ((entrypoint >= BRCM_DRAM2_BASE) &&
+ (entrypoint < (BRCM_DRAM2_BASE + BRCM_DRAM2_SIZE)))
+ return PSCI_E_SUCCESS;
+
+ if ((entrypoint >= BRCM_DRAM3_BASE) &&
+ (entrypoint < (BRCM_DRAM3_BASE + BRCM_DRAM3_SIZE)))
+ return PSCI_E_SUCCESS;
+#endif
+
+ return PSCI_E_INVALID_ADDRESS;
+}
+
+/*******************************************************************************
+ * ARM standard platform handler called to check the validity of the power state
+ * parameter.
+ ******************************************************************************/
+static int brcm_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_LOCAL_STATE_RET;
+ } else {
+ for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
+ req_state->pwr_domain_state[i] =
+ PLAT_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;
+}
+
+/*******************************************************************************
+ * Export the platform handlers via plat_brcm_psci_pm_ops. The ARM Standard
+ * platform will take care of registering the handlers with PSCI.
+ ******************************************************************************/
+plat_psci_ops_t plat_brcm_psci_pm_ops = {
+ .pwr_domain_on = brcm_pwr_domain_on,
+ .pwr_domain_on_finish = brcm_pwr_domain_on_finish,
+ .pwr_domain_off = brcm_pwr_domain_off,
+ .cpu_standby = brcm_cpu_standby,
+ .system_off = brcm_scp_sys_shutdown,
+ .system_reset = brcm_system_reset,
+ .system_reset2 = brcm_system_reset2,
+ .validate_ns_entrypoint = brcm_validate_ns_entrypoint,
+ .validate_power_state = brcm_validate_power_state,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const struct plat_psci_ops **psci_ops)
+{
+ *psci_ops = &plat_brcm_psci_pm_ops;
+
+ /* Setup mailbox with entry point. */
+ mmio_write_64(CRMU_CFG_BASE + offsetof(M0CFG, core_cfg.rvbar),
+ sec_entrypoint);
+
+ return 0;
+}
diff --git a/plat/brcm/board/stingray/src/fsx.c b/plat/brcm/board/stingray/src/fsx.c
new file mode 100644
index 0000000..5725a2e
--- /dev/null
+++ b/plat/brcm/board/stingray/src/fsx.c
@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <plat/common/common_def.h>
+
+#include <fsx.h>
+#include <platform_def.h>
+#include <sr_utils.h>
+
+#define FS4_IDM_IO_CONTROL_DIRECT__SRAM_CLK_EN 0
+
+#define FS4_IDM_IO_CONTROL_DIRECT__MEM_POWERON 11
+#define FS4_IDM_IO_CONTROL_DIRECT__MEM_POWEROK 12
+#define FS4_IDM_IO_CONTROL_DIRECT__MEM_ARRPOWERON 13
+#define FS4_IDM_IO_CONTROL_DIRECT__MEM_ARRPOWEROK 14
+#define FS4_IDM_IO_CONTROL_DIRECT__MEM_ISO 15
+#define FS4_IDM_IO_CONTROL_DIRECT__CLK_EN 31
+
+#define FS4_IDM_IO_STATUS__MEM_POWERON 0
+#define FS4_IDM_IO_STATUS__MEM_POWEROK 1
+#define FS4_IDM_IO_STATUS__MEM_ARRPOWERON 2
+#define FS4_IDM_IO_STATUS__MEM_ARRPOWEROK 3
+#define FS4_IDM_IO_STATUS__MEM_ALLOK 0xf
+
+#define FS4_IDM_RESET_CONTROL__RESET 0
+
+#define FSX_RINGx_BASE(__b, __i) \
+ ((__b) + (__i) * 0x10000)
+
+#define FSX_RINGx_VERSION_NUMBER(__b, __i) \
+ (FSX_RINGx_BASE(__b, __i) + 0x0)
+
+#define FSX_RINGx_MSI_DEV_ID(__b, __i) \
+ (FSX_RINGx_BASE(__b, __i) + 0x44)
+
+#define FSX_COMM_RINGx_BASE(__b, __i) \
+ ((__b) + 0x200000 + (__i) * 0x100)
+
+#define FSX_COMM_RINGx_CONTROL(__b, __i) \
+ (FSX_COMM_RINGx_BASE(__b, __i) + 0x0)
+#define FSX_COMM_RINGx_CONTROL__AXI_ID 8
+#define FSX_COMM_RINGx_CONTROL__AXI_ID_MASK 0x1f
+#define FSX_COMM_RINGx_CONTROL__PRIORITY 4
+#define FSX_COMM_RINGx_CONTROL__PRIORITY_MASK 0x7
+#define FSX_COMM_RINGx_CONTROL__AE_GROUP 0
+#define FSX_COMM_RINGx_CONTROL__AE_GROUP_MASK 0x7
+
+#define FSX_COMM_RINGx_MSI_DEV_ID(__b, __i) \
+ (FSX_COMM_RINGx_BASE(__b, __i) + 0x4)
+
+#define FSX_AEx_BASE(__b, __i) \
+ ((__b) + 0x202000 + (__i) * 0x100)
+
+#define FSX_AEx_CONTROL_REGISTER(__b, __i) \
+ (FSX_AEx_BASE(__b, __i) + 0x0)
+#define FSX_AEx_CONTROL_REGISTER__ACTIVE 4
+#define FSX_AEx_CONTROL_REGISTER__GROUP_ID 0
+#define FSX_AEx_CONTROL_REGISTER__GROUP_ID_MASK 0x7
+
+#define FSX_COMM_RM_RING_SECURITY_SETTING 0x0
+
+#define FSX_COMM_RM_SSID_CONTROL 0x4
+#define FSX_COMM_RM_SSID_CONTROL__RING_BITS 5
+#define FSX_COMM_RM_SSID_CONTROL__MASK 0x3ff
+
+#define FSX_COMM_RM_CONTROL_REGISTER 0x8
+#define FSX_COMM_RM_CONTROL_REGISTER__CONFIG_DONE 2
+#define FSX_COMM_RM_CONTROL_REGISTER__AE_TIMEOUT 5
+#define FSX_COMM_RM_CONTROL_REGISTER__AE_LOCKING 7
+
+#define FSX_COMM_RM_TIMER_CONTROL_0 0xc
+#define FSX_COMM_RM_TIMER_CONTROL_0__FAST 16
+#define FSX_COMM_RM_TIMER_CONTROL_0__MEDIUM 0
+
+#define FSX_COMM_RM_TIMER_CONTROL_1 0x10
+#define FSX_COMM_RM_TIMER_CONTROL_1__SLOW 16
+#define FSX_COMM_RM_TIMER_CONTROL_1__IDLE 0
+
+#define FSX_COMM_RM_BURST_BD_THRESHOLD 0x14
+#define FSX_COMM_RM_BURST_BD_THRESHOLD_LOW 0
+#define FSX_COMM_RM_BURST_BD_THRESHOLD_HIGH 16
+
+#define FSX_COMM_RM_BURST_LENGTH 0x18
+#define FSX_COMM_RM_BURST_LENGTH__FOR_DDR_ADDR_GEN 16
+#define FSX_COMM_RM_BURST_LENGTH__FOR_DDR_ADDR_GEN_MASK 0x1ff
+#define FSX_COMM_RM_BURST_LENGTH__FOR_TOGGLE 0
+#define FSX_COMM_RM_BURST_LENGTH__FOR_TOGGLE_MASK 0x1ff
+
+#define FSX_COMM_RM_FIFO_THRESHOLD 0x1c
+#define FSX_COMM_RM_FIFO_THRESHOLD__BD_FIFO_FULL 16
+#define FSX_COMM_RM_FIFO_THRESHOLD__BD_FIFO_FULL_MASK 0x1ff
+#define FSX_COMM_RM_FIFO_THRESHOLD__AE_FIFO_FULL 0
+#define FSX_COMM_RM_FIFO_THRESHOLD__AE_FIFO_FULL_MASK 0x1f
+
+#define FSX_COMM_RM_AE_TIMEOUT 0x24
+
+#define FSX_COMM_RM_RING_FLUSH_TIMEOUT 0x2c
+
+#define FSX_COMM_RM_MEMORY_CONFIGURATION 0x30
+#define FSX_COMM_RM_MEMORY_CONFIGURATION__ARRPOWERONIN 12
+#define FSX_COMM_RM_MEMORY_CONFIGURATION__ARRPOWEROKIN 13
+#define FSX_COMM_RM_MEMORY_CONFIGURATION__POWERONIN 14
+#define FSX_COMM_RM_MEMORY_CONFIGURATION__POWEROKIN 15
+
+#define FSX_COMM_RM_AXI_CONTROL 0x34
+#define FSX_COMM_RM_AXI_CONTROL__WRITE_CHANNEL_EN 28
+#define FSX_COMM_RM_AXI_CONTROL__READ_CHANNEL_EN 24
+#define FSX_COMM_RM_AXI_CONTROL__AWQOS 20
+#define FSX_COMM_RM_AXI_CONTROL__ARQOS 16
+#define FSX_COMM_RM_AXI_CONTROL__AWPROT 12
+#define FSX_COMM_RM_AXI_CONTROL__ARPROT 8
+#define FSX_COMM_RM_AXI_CONTROL__AWCACHE 4
+#define FSX_COMM_RM_AXI_CONTROL__ARCACHE 0
+
+#define FSX_COMM_RM_CONFIG_INTERRUPT_STATUS_CLEAR 0x48
+
+#define FSX_COMM_RM_GROUP_PKT_EXTENSION_SUPPORT 0xc0
+
+#define FSX_COMM_RM_AXI_READ_BURST_THRESHOLD 0xc8
+#define FSX_COMM_RM_AXI_READ_BURST_THRESHOLD__MASK 0x1ff
+#define FSX_COMM_RM_AXI_READ_BURST_THRESHOLD__MAX 16
+#define FSX_COMM_RM_AXI_READ_BURST_THRESHOLD__MIN 0
+
+#define FSX_COMM_RM_GROUP_RING_COUNT 0xcc
+
+#define FSX_COMM_RM_MAIN_HW_INIT_DONE 0x12c
+#define FSX_COMM_RM_MAIN_HW_INIT_DONE__MASK 0x1
+
+#define FSX_DMEx_BASE(__b, __i) \
+ ((__b) + (__i) * 0x1000)
+
+#define FSX_DMEx_AXI_CONTROL(__b, __i) \
+ (FSX_DMEx_BASE(__b, __i) + 0x4)
+#define FSX_DMEx_AXI_CONTROL__WRITE_CHANNEL_EN 28
+#define FSX_DMEx_AXI_CONTROL__READ_CHANNEL_EN 24
+#define FSX_DMEx_AXI_CONTROL__AWQOS 20
+#define FSX_DMEx_AXI_CONTROL__ARQOS 16
+#define FSX_DMEx_AXI_CONTROL__AWCACHE 4
+#define FSX_DMEx_AXI_CONTROL__ARCACHE 0
+
+#define FSX_DMEx_WR_FIFO_THRESHOLD(__b, __i) \
+ (FSX_DMEx_BASE(__b, __i) + 0xc)
+#define FSX_DMEx_WR_FIFO_THRESHOLD__MASK 0x3ff
+#define FSX_DMEx_WR_FIFO_THRESHOLD__MAX 10
+#define FSX_DMEx_WR_FIFO_THRESHOLD__MIN 0
+
+#define FSX_DMEx_RD_FIFO_THRESHOLD(__b, __i) \
+ (FSX_DMEx_BASE(__b, __i) + 0x14)
+#define FSX_DMEx_RD_FIFO_THRESHOLD__MASK 0x3ff
+#define FSX_DMEx_RD_FIFO_THRESHOLD__MAX 10
+#define FSX_DMEx_RD_FIFO_THRESHOLD__MIN 0
+
+#define FS6_SUB_TOP_BASE 0x66D8F800
+#define FS6_PKI_DME_RESET 0x4
+#define PKI_DME_RESET 1
+
+char *fsx_type_names[] = {
+ "fs4-raid",
+ "fs4-crypto",
+ "fs6-pki",
+};
+
+void fsx_init(eFSX_TYPE fsx_type,
+ unsigned int ring_count,
+ unsigned int dme_count,
+ unsigned int ae_count,
+ unsigned int start_stream_id,
+ unsigned int msi_dev_id,
+ uintptr_t idm_io_control_direct,
+ uintptr_t idm_reset_control,
+ uintptr_t base,
+ uintptr_t dme_base)
+{
+ int try;
+ unsigned int i, v, data;
+ uintptr_t fs4_idm_io_control_direct = idm_io_control_direct;
+ uintptr_t fs4_idm_reset_control = idm_reset_control;
+ uintptr_t fsx_comm_rm = (base + 0x203000);
+
+ VERBOSE("fsx %s init start\n", fsx_type_names[fsx_type]);
+
+ if (fsx_type == eFS4_RAID || fsx_type == eFS4_CRYPTO) {
+ /* Enable FSx engine clock */
+ VERBOSE(" - enable fsx clock\n");
+ mmio_write_32(fs4_idm_io_control_direct,
+ (1U << FS4_IDM_IO_CONTROL_DIRECT__CLK_EN));
+ udelay(500);
+
+ /* Reset FSx engine */
+ VERBOSE(" - reset fsx\n");
+ v = mmio_read_32(fs4_idm_reset_control);
+ v |= (1 << FS4_IDM_RESET_CONTROL__RESET);
+ mmio_write_32(fs4_idm_reset_control, v);
+ udelay(500);
+ v = mmio_read_32(fs4_idm_reset_control);
+ v &= ~(1 << FS4_IDM_RESET_CONTROL__RESET);
+ mmio_write_32(fs4_idm_reset_control, v);
+ } else {
+ /*
+ * Default RM and AE are out of reset,
+ * So only DME Reset added here
+ */
+ v = mmio_read_32(FS6_SUB_TOP_BASE + FS6_PKI_DME_RESET);
+ v &= ~(PKI_DME_RESET);
+ mmio_write_32(FS6_SUB_TOP_BASE + FS6_PKI_DME_RESET, v);
+ }
+
+ /* Wait for HW-init done */
+ VERBOSE(" - wait for HW-init done\n");
+ try = 10000;
+ do {
+ udelay(1);
+ data = mmio_read_32(fsx_comm_rm +
+ FSX_COMM_RM_MAIN_HW_INIT_DONE);
+ try--;
+ } while (!(data & FSX_COMM_RM_MAIN_HW_INIT_DONE__MASK) && (try > 0));
+
+ if (try <= 0)
+ ERROR("fsx_comm_rm + 0x%x: 0x%x\n",
+ data, FSX_COMM_RM_MAIN_HW_INIT_DONE);
+
+ /* Make all rings non-secured */
+ VERBOSE(" - make all rings non-secured\n");
+ v = 0xffffffff;
+ mmio_write_32(fsx_comm_rm + FSX_COMM_RM_RING_SECURITY_SETTING, v);
+
+ /* Set start stream-id for rings to */
+ VERBOSE(" - set start stream-id for rings to 0x%x\n",
+ start_stream_id);
+ v = start_stream_id >> FSX_COMM_RM_SSID_CONTROL__RING_BITS;
+ v &= FSX_COMM_RM_SSID_CONTROL__MASK;
+ mmio_write_32(fsx_comm_rm + FSX_COMM_RM_SSID_CONTROL, v);
+
+ /* Set timer configuration */
+ VERBOSE(" - set timer configuration\n");
+ v = 0x0271 << FSX_COMM_RM_TIMER_CONTROL_0__MEDIUM;
+ v |= (0x0138 << FSX_COMM_RM_TIMER_CONTROL_0__FAST);
+ mmio_write_32(fsx_comm_rm + FSX_COMM_RM_TIMER_CONTROL_0, v);
+ v = 0x09c4 << FSX_COMM_RM_TIMER_CONTROL_1__IDLE;
+ v |= (0x04e2 << FSX_COMM_RM_TIMER_CONTROL_1__SLOW);
+ mmio_write_32(fsx_comm_rm + FSX_COMM_RM_TIMER_CONTROL_1, v);
+ v = 0x0000f424;
+ mmio_write_32(fsx_comm_rm + FSX_COMM_RM_RING_FLUSH_TIMEOUT, v);
+
+ /* Set burst length and fifo threshold */
+ VERBOSE(" - set burst length, fifo and bd threshold\n");
+ v = 0x0;
+ v |= (0x8 << FSX_COMM_RM_BURST_LENGTH__FOR_DDR_ADDR_GEN);
+ v |= (0x8 << FSX_COMM_RM_BURST_LENGTH__FOR_TOGGLE);
+ mmio_write_32(fsx_comm_rm + FSX_COMM_RM_BURST_LENGTH, v);
+ v = 0x0;
+ v |= (0x67 << FSX_COMM_RM_FIFO_THRESHOLD__BD_FIFO_FULL);
+ v |= (0x18 << FSX_COMM_RM_FIFO_THRESHOLD__AE_FIFO_FULL);
+ mmio_write_32(fsx_comm_rm + FSX_COMM_RM_FIFO_THRESHOLD, v);
+ v = 0x0;
+ v |= (0x8 << FSX_COMM_RM_BURST_BD_THRESHOLD_LOW);
+ v |= (0x8 << FSX_COMM_RM_BURST_BD_THRESHOLD_HIGH);
+ mmio_write_32(fsx_comm_rm + FSX_COMM_RM_BURST_BD_THRESHOLD, v);
+
+ /* Set memory configuration */
+ VERBOSE(" - set memory configuration\n");
+ v = 0x0;
+ v |= (1 << FSX_COMM_RM_MEMORY_CONFIGURATION__POWERONIN);
+ v |= (1 << FSX_COMM_RM_MEMORY_CONFIGURATION__POWEROKIN);
+ v |= (1 << FSX_COMM_RM_MEMORY_CONFIGURATION__ARRPOWERONIN);
+ v |= (1 << FSX_COMM_RM_MEMORY_CONFIGURATION__ARRPOWEROKIN);
+ mmio_write_32(fsx_comm_rm + FSX_COMM_RM_MEMORY_CONFIGURATION, v);
+
+ /* AXI configuration for RM */
+ v = 0;
+ v |= (0x1 << FSX_COMM_RM_AXI_CONTROL__WRITE_CHANNEL_EN);
+ v |= (0x1 << FSX_COMM_RM_AXI_CONTROL__READ_CHANNEL_EN);
+ v |= (0xe << FSX_COMM_RM_AXI_CONTROL__AWQOS);
+ v |= (0xa << FSX_COMM_RM_AXI_CONTROL__ARQOS);
+ v |= (0x2 << FSX_COMM_RM_AXI_CONTROL__AWPROT);
+ v |= (0x2 << FSX_COMM_RM_AXI_CONTROL__ARPROT);
+ v |= (0xf << FSX_COMM_RM_AXI_CONTROL__AWCACHE);
+ v |= (0xf << FSX_COMM_RM_AXI_CONTROL__ARCACHE);
+ mmio_write_32(fsx_comm_rm + FSX_COMM_RM_AXI_CONTROL, v);
+ VERBOSE(" - set AXI control = 0x%x\n",
+ mmio_read_32(fsx_comm_rm + FSX_COMM_RM_AXI_CONTROL));
+ v = 0x0;
+ v |= (0x10 << FSX_COMM_RM_AXI_READ_BURST_THRESHOLD__MAX);
+ v |= (0x10 << FSX_COMM_RM_AXI_READ_BURST_THRESHOLD__MIN);
+ mmio_write_32(fsx_comm_rm + FSX_COMM_RM_AXI_READ_BURST_THRESHOLD, v);
+ VERBOSE(" - set AXI read burst threshold = 0x%x\n",
+ mmio_read_32(fsx_comm_rm + FSX_COMM_RM_AXI_READ_BURST_THRESHOLD));
+
+ /* Configure group ring count for all groups */
+ /* By default we schedule extended packets
+ * on all AEs/DMEs in a group.
+ */
+ v = (dme_count & 0xf) << 0;
+ v |= (dme_count & 0xf) << 4;
+ v |= (dme_count & 0xf) << 8;
+ v |= (dme_count & 0xf) << 12;
+ v |= (dme_count & 0xf) << 16;
+ v |= (dme_count & 0xf) << 20;
+ v |= (dme_count & 0xf) << 24;
+ v |= (dme_count & 0xf) << 28;
+ mmio_write_32(fsx_comm_rm + FSX_COMM_RM_GROUP_RING_COUNT, v);
+
+ /*
+ * Due to HW issue spurious interrupts are getting generated.
+ * To fix sw needs to clear the config status interrupts
+ * before setting CONFIG_DONE.
+ */
+ mmio_write_32(fsx_comm_rm +
+ FSX_COMM_RM_CONFIG_INTERRUPT_STATUS_CLEAR,
+ 0xffffffff);
+
+ /* Configure RM control */
+ VERBOSE(" - configure RM control\n");
+ v = mmio_read_32(fsx_comm_rm + FSX_COMM_RM_CONTROL_REGISTER);
+ v |= (1 << FSX_COMM_RM_CONTROL_REGISTER__AE_LOCKING);
+ mmio_write_32(fsx_comm_rm + FSX_COMM_RM_CONTROL_REGISTER, v);
+ v |= (1 << FSX_COMM_RM_CONTROL_REGISTER__CONFIG_DONE);
+ mmio_write_32(fsx_comm_rm + FSX_COMM_RM_CONTROL_REGISTER, v);
+
+ /* Configure AE timeout */
+ VERBOSE(" - configure AE timeout\n");
+ v = 0x00003fff;
+ mmio_write_32(fsx_comm_rm + FSX_COMM_RM_AE_TIMEOUT, v);
+
+ /* Initialize all AEs */
+ for (i = 0; i < ae_count; i++) {
+ VERBOSE(" - initialize AE%d\n", i);
+ v = (0x1 << FSX_AEx_CONTROL_REGISTER__ACTIVE);
+ mmio_write_32(FSX_AEx_CONTROL_REGISTER(base, i), v);
+ }
+
+ /* Initialize all DMEs */
+ for (i = 0; i < dme_count; i++) {
+ VERBOSE(" - initialize DME%d\n", i);
+ v = 0;
+ v |= (0x1 << FSX_DMEx_AXI_CONTROL__WRITE_CHANNEL_EN);
+ v |= (0x1 << FSX_DMEx_AXI_CONTROL__READ_CHANNEL_EN);
+ v |= (0xe << FSX_DMEx_AXI_CONTROL__AWQOS);
+ v |= (0xa << FSX_DMEx_AXI_CONTROL__ARQOS);
+ v |= (0xf << FSX_DMEx_AXI_CONTROL__AWCACHE);
+ v |= (0xf << FSX_DMEx_AXI_CONTROL__ARCACHE);
+ mmio_write_32(FSX_DMEx_AXI_CONTROL(dme_base, i), v);
+ VERBOSE(" -- AXI_CONTROL = 0x%x\n",
+ mmio_read_32(FSX_DMEx_AXI_CONTROL(dme_base, i)));
+ v = 0;
+ v |= (0x4 << FSX_DMEx_WR_FIFO_THRESHOLD__MIN);
+ v |= (0x4 << FSX_DMEx_WR_FIFO_THRESHOLD__MAX);
+ mmio_write_32(FSX_DMEx_WR_FIFO_THRESHOLD(dme_base, i), v);
+ VERBOSE(" -- WR_FIFO_THRESHOLD = 0x%x\n",
+ mmio_read_32(FSX_DMEx_WR_FIFO_THRESHOLD(dme_base, i)));
+ v = 0;
+ v |= (0x4 << FSX_DMEx_RD_FIFO_THRESHOLD__MIN);
+ v |= (0x4 << FSX_DMEx_RD_FIFO_THRESHOLD__MAX);
+ mmio_write_32(FSX_DMEx_RD_FIFO_THRESHOLD(dme_base, i), v);
+ VERBOSE(" -- RD_FIFO_THRESHOLD = 0x%x\n",
+ mmio_read_32(FSX_DMEx_RD_FIFO_THRESHOLD(dme_base, i)));
+ }
+
+ /* Configure ring axi id and msi device id */
+ for (i = 0; i < ring_count; i++) {
+ VERBOSE(" - ring%d version=0x%x\n", i,
+ mmio_read_32(FSX_RINGx_VERSION_NUMBER(base, i)));
+ mmio_write_32(FSX_COMM_RINGx_MSI_DEV_ID(base, i),
+ msi_dev_id);
+ v = 0;
+ v |= ((i & FSX_COMM_RINGx_CONTROL__AXI_ID_MASK) <<
+ FSX_COMM_RINGx_CONTROL__AXI_ID);
+ mmio_write_32(FSX_COMM_RINGx_CONTROL(base, i), v);
+ }
+
+ INFO("fsx %s init done\n", fsx_type_names[fsx_type]);
+}
+
+void fsx_meminit(const char *name,
+ uintptr_t idm_io_control_direct,
+ uintptr_t idm_io_status)
+{
+ int try;
+ unsigned int val;
+
+ VERBOSE("fsx %s meminit start\n", name);
+
+ VERBOSE(" - arrpoweron\n");
+ mmio_setbits_32(idm_io_control_direct,
+ BIT(FS4_IDM_IO_CONTROL_DIRECT__MEM_ARRPOWERON));
+ while (!(mmio_read_32(idm_io_status) &
+ BIT(FS4_IDM_IO_STATUS__MEM_ARRPOWERON)))
+ ;
+
+ VERBOSE(" - arrpowerok\n");
+ mmio_setbits_32(idm_io_control_direct,
+ (1 << FS4_IDM_IO_CONTROL_DIRECT__MEM_ARRPOWEROK));
+ while (!(mmio_read_32(idm_io_status) &
+ BIT(FS4_IDM_IO_STATUS__MEM_ARRPOWEROK)))
+ ;
+
+ VERBOSE(" - poweron\n");
+ mmio_setbits_32(idm_io_control_direct,
+ (1 << FS4_IDM_IO_CONTROL_DIRECT__MEM_POWERON));
+ while (!(mmio_read_32(idm_io_status) &
+ BIT(FS4_IDM_IO_STATUS__MEM_POWERON)))
+ ;
+
+ VERBOSE(" - powerok\n");
+ mmio_setbits_32(idm_io_control_direct,
+ (1 << FS4_IDM_IO_CONTROL_DIRECT__MEM_POWEROK));
+ while (!(mmio_read_32(idm_io_status) &
+ BIT(FS4_IDM_IO_STATUS__MEM_POWEROK)))
+ ;
+
+ /* Final check on all power bits */
+ try = 10;
+ do {
+ val = mmio_read_32(idm_io_status);
+ if (val == FS4_IDM_IO_STATUS__MEM_ALLOK)
+ break;
+
+ /* Wait sometime */
+ mdelay(1);
+
+ try--;
+ } while (try > 0);
+
+ /* Remove memory isolation if things are fine. */
+ if (try <= 0) {
+ INFO(" - powerup failed\n");
+ } else {
+ VERBOSE(" - remove isolation\n");
+ mmio_clrbits_32(idm_io_control_direct,
+ (1 << FS4_IDM_IO_CONTROL_DIRECT__MEM_ISO));
+ VERBOSE(" - powerup done\n");
+ }
+
+ INFO("fsx %s meminit done\n", name);
+}
+
+void fs4_disable_clocks(bool disable_sram,
+ bool disable_crypto,
+ bool disable_raid)
+{
+ VERBOSE("fs4 disable clocks start\n");
+
+ if (disable_sram) {
+ VERBOSE(" - disable sram clock\n");
+ mmio_clrbits_32(FS4_SRAM_IDM_IO_CONTROL_DIRECT,
+ (1 << FS4_IDM_IO_CONTROL_DIRECT__SRAM_CLK_EN));
+ }
+
+ if (disable_crypto) {
+ VERBOSE(" - disable crypto clock\n");
+ mmio_setbits_32(CDRU_GENPLL5_CONTROL1,
+ CDRU_GENPLL5_CONTROL1__CHNL1_CRYPTO_AE_CLK);
+ }
+
+ if (disable_raid) {
+ VERBOSE(" - disable raid clock\n");
+ mmio_setbits_32(CDRU_GENPLL5_CONTROL1,
+ CDRU_GENPLL5_CONTROL1__CHNL2_RAID_AE_CLK);
+ }
+
+ if (disable_sram && disable_crypto && disable_raid) {
+ VERBOSE(" - disable root clock\n");
+ mmio_setbits_32(CDRU_GENPLL5_CONTROL1,
+ CDRU_GENPLL5_CONTROL1__CHNL0_DME_CLK);
+ mmio_setbits_32(CDRU_GENPLL2_CONTROL1,
+ CDRU_GENPLL2_CONTROL1__CHNL6_FS4_CLK);
+ }
+
+ INFO("fs4 disable clocks done\n");
+}
diff --git a/plat/brcm/board/stingray/src/ihost_pm.c b/plat/brcm/board/stingray/src/ihost_pm.c
new file mode 100644
index 0000000..9141d3e
--- /dev/null
+++ b/plat/brcm/board/stingray/src/ihost_pm.c
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <dmu.h>
+#include <ihost_pm.h>
+#include <platform_def.h>
+
+#define CDRU_CCN_REGISTER_CONTROL_1__D2XS_PD_IHOST1 2
+#define CDRU_CCN_REGISTER_CONTROL_1__D2XS_PD_IHOST2 1
+#define CDRU_CCN_REGISTER_CONTROL_1__D2XS_PD_IHOST3 0
+#define CDRU_MISC_RESET_CONTROL__CDRU_IH1_RESET 9
+#define CDRU_MISC_RESET_CONTROL__CDRU_IH2_RESET 8
+#define CDRU_MISC_RESET_CONTROL__CDRU_IH3_RESET 7
+#define A72_CRM_SOFTRESETN_0 0x480
+#define A72_CRM_SOFTRESETN_1 0x484
+#define A72_CRM_DOMAIN_4_CONTROL 0x810
+#define A72_CRM_DOMAIN_4_CONTROL__DOMAIN_4_ISO_DFT 3
+#define A72_CRM_DOMAIN_4_CONTROL__DOMAIN_4_ISO_MEM 6
+#define A72_CRM_DOMAIN_4_CONTROL__DOMAIN_4_ISO_I_O 0
+#define A72_CRM_SUBSYSTEM_MEMORY_CONTROL_3 0xB4C
+#define MEMORY_PDA_HI_SHIFT 0x0
+#define A72_CRM_PLL_PWR_ON 0x70
+#define A72_CRM_PLL_PWR_ON__PLL0_ISO_PLLOUT 4
+#define A72_CRM_PLL_PWR_ON__PLL0_PWRON_LDO 1
+#define A72_CRM_PLL_PWR_ON__PLL0_PWRON_PLL 0
+#define A72_CRM_SUBSYSTEM_MEMORY_CONTROL_2 0xB48
+#define A72_CRM_PLL_INTERRUPT_STATUS 0x8c
+#define A72_CRM_PLL_INTERRUPT_STATUS__PLL0_LOCK_LOST_STATUS 8
+#define A72_CRM_PLL_INTERRUPT_STATUS__PLL0_LOCK_STATUS 9
+#define A72_CRM_INTERRUPT_ENABLE 0x4
+#define A72_CRM_INTERRUPT_ENABLE__PLL0_INT_ENABLE 4
+#define A72_CRM_PLL_INTERRUPT_ENABLE 0x88
+#define A72_CRM_PLL_INTERRUPT_ENABLE__PLL0_LOCK_STATUS_INT_ENB 9
+#define A72_CRM_PLL_INTERRUPT_ENABLE__PLL0_LOCK_LOST_STATUS_INT_ENB 8
+#define A72_CRM_PLL0_CFG0_CTRL 0x120
+#define A72_CRM_PLL0_CFG1_CTRL 0x124
+#define A72_CRM_PLL0_CFG2_CTRL 0x128
+#define A72_CRM_PLL0_CFG3_CTRL 0x12C
+#define A72_CRM_CORE_CONFIG_DBGCTRL__DBGROMADDRV 0
+#define A72_CRM_CORE_CONFIG_DBGCTRL 0xD50
+#define A72_CRM_CORE_CONFIG_DBGROM_LO 0xD54
+#define A72_CRM_CORE_CONFIG_DBGROM_HI 0xD58
+#define A72_CRM_SUBSYSTEM_CONFIG_1__DBGL1RSTDISABLE 2
+#define A72_CRM_SOFTRESETN_0__CRYSTAL26_SOFTRESETN 0
+#define A72_CRM_SOFTRESETN_0__CRM_PLL0_SOFTRESETN 1
+#define A72_CRM_AXI_CLK_DESC 0x304
+#define A72_CRM_ACP_CLK_DESC 0x308
+#define A72_CRM_ATB_CLK_DESC 0x30C
+#define A72_CRM_PCLKDBG_DESC 0x310
+#define A72_CRM_CLOCK_MODE_CONTROL 0x40
+#define A72_CRM_CLOCK_MODE_CONTROL__CLK_CHANGE_TRIGGER 0
+#define A72_CRM_CLOCK_CONTROL_0 0x200
+#define A72_CRM_CLOCK_CONTROL_0__ARM_HW_SW_ENABLE_SEL 0
+#define A72_CRM_CLOCK_CONTROL_0__AXI_HW_SW_ENABLE_SEL 2
+#define A72_CRM_CLOCK_CONTROL_0__ACP_HW_SW_ENABLE_SEL 4
+#define A72_CRM_CLOCK_CONTROL_0__ATB_HW_SW_ENABLE_SEL 6
+#define A72_CRM_CLOCK_CONTROL_0__PCLKDBG_HW_SW_ENA_SEL 8
+#define A72_CRM_CLOCK_CONTROL_1 0x204
+#define A72_CRM_CLOCK_CONTROL_1__TMON_HW_SW_ENABLE_SEL 6
+#define A72_CRM_CLOCK_CONTROL_1__APB_HW_SW_ENABLE_SEL 8
+#define A72_CRM_SOFTRESETN_0__CRYSTAL26_SOFTRESETN 0
+#define A72_CRM_SOFTRESETN_0__CRM_PLL0_SOFTRESETN 1
+#define A72_CRM_SOFTRESETN_0__AXI_SOFTRESETN 9
+#define A72_CRM_SOFTRESETN_0__ACP_SOFTRESETN 10
+#define A72_CRM_SOFTRESETN_0__ATB_SOFTRESETN 11
+#define A72_CRM_SOFTRESETN_0__PCLKDBG_SOFTRESETN 12
+#define A72_CRM_SOFTRESETN_0__TMON_SOFTRESETN 15
+#define A72_CRM_SOFTRESETN_0__L2_SOFTRESETN 3
+#define A72_CRM_SOFTRESETN_1__APB_SOFTRESETN 8
+
+/* core related regs */
+#define A72_CRM_DOMAIN_0_CONTROL 0x800
+#define A72_CRM_DOMAIN_0_CONTROL__DOMAIN_0_ISO_MEM 0x6
+#define A72_CRM_DOMAIN_0_CONTROL__DOMAIN_0_ISO_I_O 0x0
+#define A72_CRM_DOMAIN_1_CONTROL 0x804
+#define A72_CRM_DOMAIN_1_CONTROL__DOMAIN_1_ISO_MEM 0x6
+#define A72_CRM_DOMAIN_1_CONTROL__DOMAIN_1_ISO_I_O 0x0
+#define A72_CRM_CORE_CONFIG_RVBA0_LO 0xD10
+#define A72_CRM_CORE_CONFIG_RVBA0_MID 0xD14
+#define A72_CRM_CORE_CONFIG_RVBA0_HI 0xD18
+#define A72_CRM_CORE_CONFIG_RVBA1_LO 0xD20
+#define A72_CRM_CORE_CONFIG_RVBA1_MID 0xD24
+#define A72_CRM_CORE_CONFIG_RVBA1_HI 0xD28
+#define A72_CRM_SUBSYSTEM_CONFIG_0 0xC80
+#define A72_CRM_SUBSYSTEM_CONFIG_0__DBGPWRDUP_CFG_SHIFT 4
+#define A72_CRM_SOFTRESETN_0__COREPOR0_SOFTRESETN 4
+#define A72_CRM_SOFTRESETN_0__COREPOR1_SOFTRESETN 5
+#define A72_CRM_SOFTRESETN_1__CORE0_SOFTRESETN 0
+#define A72_CRM_SOFTRESETN_1__DEBUG0_SOFTRESETN 4
+#define A72_CRM_SOFTRESETN_1__CORE1_SOFTRESETN 1
+#define A72_CRM_SOFTRESETN_1__DEBUG1_SOFTRESETN 5
+
+#define SPROC_MEMORY_BISR 0
+
+static int cluster_power_status[PLAT_BRCM_CLUSTER_COUNT] = {CLUSTER_POWER_ON,
+ CLUSTER_POWER_OFF,
+ CLUSTER_POWER_OFF,
+ CLUSTER_POWER_OFF};
+
+void ihost_power_on_cluster(u_register_t mpidr)
+{
+ uint32_t rst, d2xs;
+ uint32_t cluster_id;
+ uint32_t ihost_base;
+#if SPROC_MEMORY_BISR
+ uint32_t bisr, cnt;
+#endif
+ cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
+ uint32_t cluster0_freq_sel;
+
+ if (cluster_power_status[cluster_id] == CLUSTER_POWER_ON)
+ return;
+
+ cluster_power_status[cluster_id] = CLUSTER_POWER_ON;
+ INFO("enabling Cluster #%u\n", cluster_id);
+
+ switch (cluster_id) {
+ case 1:
+ rst = (1 << CDRU_MISC_RESET_CONTROL__CDRU_IH1_RESET);
+ d2xs = (1 << CDRU_CCN_REGISTER_CONTROL_1__D2XS_PD_IHOST1);
+#if SPROC_MEMORY_BISR
+ bisr = CRMU_BISR_PDG_MASK__CRMU_BISR_IHOST1;
+#endif
+ break;
+ case 2:
+ rst = (1 << CDRU_MISC_RESET_CONTROL__CDRU_IH2_RESET);
+ d2xs = (1 << CDRU_CCN_REGISTER_CONTROL_1__D2XS_PD_IHOST2);
+#if SPROC_MEMORY_BISR
+ bisr = CRMU_BISR_PDG_MASK__CRMU_BISR_IHOST2;
+#endif
+ break;
+ case 3:
+ rst = (1 << CDRU_MISC_RESET_CONTROL__CDRU_IH3_RESET);
+ d2xs = (1 << CDRU_CCN_REGISTER_CONTROL_1__D2XS_PD_IHOST3);
+#if SPROC_MEMORY_BISR
+ bisr = CRMU_BISR_PDG_MASK__CRMU_BISR_IHOST3;
+#endif
+ break;
+ default:
+ ERROR("Invalid cluster :%u\n", cluster_id);
+ return;
+ }
+
+ /* Releasing ihost resets */
+ mmio_setbits_32(CDRU_MISC_RESET_CONTROL, rst);
+
+ /* calculate cluster/ihost base address */
+ ihost_base = IHOST0_BASE + cluster_id * IHOST_ADDR_SPACE;
+
+ /* Remove Cluster IO isolation */
+ mmio_clrsetbits_32(ihost_base + A72_CRM_DOMAIN_4_CONTROL,
+ (1 << A72_CRM_DOMAIN_4_CONTROL__DOMAIN_4_ISO_I_O),
+ (1 << A72_CRM_DOMAIN_4_CONTROL__DOMAIN_4_ISO_DFT) |
+ (1 << A72_CRM_DOMAIN_4_CONTROL__DOMAIN_4_ISO_MEM));
+
+ /*
+ * Since BISR sequence requires that all cores of cluster should
+ * have removed I/O isolation hence doing same here.
+ */
+ /* Remove core0 memory IO isolations */
+ mmio_clrsetbits_32(ihost_base + A72_CRM_DOMAIN_0_CONTROL,
+ (1 << A72_CRM_DOMAIN_0_CONTROL__DOMAIN_0_ISO_I_O),
+ (1 << A72_CRM_DOMAIN_0_CONTROL__DOMAIN_0_ISO_MEM));
+
+ /* Remove core1 memory IO isolations */
+ mmio_clrsetbits_32(ihost_base + A72_CRM_DOMAIN_1_CONTROL,
+ (1 << A72_CRM_DOMAIN_1_CONTROL__DOMAIN_1_ISO_I_O),
+ (1 << A72_CRM_DOMAIN_1_CONTROL__DOMAIN_1_ISO_MEM));
+
+#if SPROC_MEMORY_BISR
+ mmio_setbits_32(CRMU_BISR_PDG_MASK, (1 << bisr));
+
+ if (!(mmio_read_32(CDRU_CHIP_STRAP_DATA_LSW) &
+ (1 << CDRU_CHIP_STRAP_DATA_LSW__BISR_BYPASS_MODE))) {
+ /* BISR completion would take max 2 usec */
+ cnt = 0;
+ while (cnt < 2) {
+ udelay(1);
+ if (mmio_read_32(CRMU_CHIP_OTPC_STATUS) &
+ (1 << CRMU_CHIP_OTPC_STATUS__OTP_BISR_LOAD_DONE))
+ break;
+ cnt++;
+ }
+ }
+
+ /* if BISR is not completed, need to be checked with ASIC team */
+ if (((mmio_read_32(CRMU_CHIP_OTPC_STATUS)) &
+ (1 << CRMU_CHIP_OTPC_STATUS__OTP_BISR_LOAD_DONE)) == 0) {
+ WARN("BISR did not completed and need to be addressed\n");
+ }
+#endif
+
+ /* PLL Power up. supply is already on. Turn on PLL LDO/PWR */
+ mmio_write_32(ihost_base + A72_CRM_PLL_PWR_ON,
+ (1 << A72_CRM_PLL_PWR_ON__PLL0_ISO_PLLOUT) |
+ (1 << A72_CRM_PLL_PWR_ON__PLL0_PWRON_LDO) |
+ (1 << A72_CRM_PLL_PWR_ON__PLL0_PWRON_PLL));
+
+ /* 1us in spec; Doubling it to be safe*/
+ udelay(2);
+
+ /* Remove PLL output ISO */
+ mmio_write_32(ihost_base + A72_CRM_PLL_PWR_ON,
+ (1 << A72_CRM_PLL_PWR_ON__PLL0_PWRON_LDO) |
+ (1 << A72_CRM_PLL_PWR_ON__PLL0_PWRON_PLL));
+
+ /*
+ * PLL0 Configuration Control Register
+ * these 4 registers drive the i_pll_ctrl[63:0] input of pll
+ * (16b per register).
+ * the values are derived from the spec (sections 8 and 10).
+ */
+
+ mmio_write_32(ihost_base + A72_CRM_PLL0_CFG0_CTRL, 0x00000000);
+ mmio_write_32(ihost_base + A72_CRM_PLL0_CFG1_CTRL, 0x00008400);
+ mmio_write_32(ihost_base + A72_CRM_PLL0_CFG2_CTRL, 0x00000001);
+ mmio_write_32(ihost_base + A72_CRM_PLL0_CFG3_CTRL, 0x00000000);
+
+ /* Read the freq_sel from cluster 0, which is up already */
+ cluster0_freq_sel = bcm_get_ihost_pll_freq(0);
+ bcm_set_ihost_pll_freq(cluster_id, cluster0_freq_sel);
+
+ udelay(1);
+
+ /* Release clock source reset */
+ mmio_setbits_32(ihost_base + A72_CRM_SOFTRESETN_0,
+ (1 << A72_CRM_SOFTRESETN_0__CRYSTAL26_SOFTRESETN) |
+ (1 << A72_CRM_SOFTRESETN_0__CRM_PLL0_SOFTRESETN));
+
+ udelay(1);
+
+ /*
+ * Integer division for clks (divider value = n+1).
+ * These are the divisor of ARM PLL clock frequecy.
+ */
+ mmio_write_32(ihost_base + A72_CRM_AXI_CLK_DESC, 0x00000001);
+ mmio_write_32(ihost_base + A72_CRM_ACP_CLK_DESC, 0x00000001);
+ mmio_write_32(ihost_base + A72_CRM_ATB_CLK_DESC, 0x00000004);
+ mmio_write_32(ihost_base + A72_CRM_PCLKDBG_DESC, 0x0000000b);
+
+ /*
+ * clock change trigger - must set to take effect after clock
+ * source change
+ */
+ mmio_setbits_32(ihost_base + A72_CRM_CLOCK_MODE_CONTROL,
+ (1 << A72_CRM_CLOCK_MODE_CONTROL__CLK_CHANGE_TRIGGER));
+
+ /* turn on functional clocks */
+ mmio_setbits_32(ihost_base + A72_CRM_CLOCK_CONTROL_0,
+ (3 << A72_CRM_CLOCK_CONTROL_0__ARM_HW_SW_ENABLE_SEL) |
+ (3 << A72_CRM_CLOCK_CONTROL_0__AXI_HW_SW_ENABLE_SEL) |
+ (3 << A72_CRM_CLOCK_CONTROL_0__ACP_HW_SW_ENABLE_SEL) |
+ (3 << A72_CRM_CLOCK_CONTROL_0__ATB_HW_SW_ENABLE_SEL) |
+ (3 << A72_CRM_CLOCK_CONTROL_0__PCLKDBG_HW_SW_ENA_SEL));
+
+ mmio_setbits_32(ihost_base + A72_CRM_CLOCK_CONTROL_1,
+ (3 << A72_CRM_CLOCK_CONTROL_1__TMON_HW_SW_ENABLE_SEL) |
+ (3 << A72_CRM_CLOCK_CONTROL_1__APB_HW_SW_ENABLE_SEL));
+
+ /* Program D2XS Power Down Registers */
+ mmio_setbits_32(CDRU_CCN_REGISTER_CONTROL_1, d2xs);
+
+ /* Program Core Config Debug ROM Address Registers */
+ /* mark valid for Debug ROM base address */
+ mmio_write_32(ihost_base + A72_CRM_CORE_CONFIG_DBGCTRL,
+ (1 << A72_CRM_CORE_CONFIG_DBGCTRL__DBGROMADDRV));
+
+ /* Program Lo and HI address of coresight DBG rom address */
+ mmio_write_32(ihost_base + A72_CRM_CORE_CONFIG_DBGROM_LO,
+ (CORESIGHT_BASE_ADDR >> 12) & 0xffff);
+ mmio_write_32(ihost_base + A72_CRM_CORE_CONFIG_DBGROM_HI,
+ (CORESIGHT_BASE_ADDR >> 28) & 0xffff);
+
+ /*
+ * Release soft resets of different components.
+ * Order: Bus clocks --> PERIPH --> L2 --> cores
+ */
+
+ /* Bus clocks soft resets */
+ mmio_setbits_32(ihost_base + A72_CRM_SOFTRESETN_0,
+ (1 << A72_CRM_SOFTRESETN_0__CRYSTAL26_SOFTRESETN) |
+ (1 << A72_CRM_SOFTRESETN_0__CRM_PLL0_SOFTRESETN) |
+ (1 << A72_CRM_SOFTRESETN_0__AXI_SOFTRESETN) |
+ (1 << A72_CRM_SOFTRESETN_0__ACP_SOFTRESETN) |
+ (1 << A72_CRM_SOFTRESETN_0__ATB_SOFTRESETN) |
+ (1 << A72_CRM_SOFTRESETN_0__PCLKDBG_SOFTRESETN));
+
+ mmio_setbits_32(ihost_base + A72_CRM_SOFTRESETN_1,
+ (1 << A72_CRM_SOFTRESETN_1__APB_SOFTRESETN));
+
+ /* Periph component softreset */
+ mmio_setbits_32(ihost_base + A72_CRM_SOFTRESETN_0,
+ (1 << A72_CRM_SOFTRESETN_0__TMON_SOFTRESETN));
+
+ /* L2 softreset */
+ mmio_setbits_32(ihost_base + A72_CRM_SOFTRESETN_0,
+ (1 << A72_CRM_SOFTRESETN_0__L2_SOFTRESETN));
+
+ /* Enable and program Satellite timer */
+ ihost_enable_satellite_timer(cluster_id);
+}
+
+void ihost_power_on_secondary_core(u_register_t mpidr, uint64_t rvbar)
+{
+ uint32_t ihost_base;
+ uint32_t coreid = MPIDR_AFFLVL0_VAL(mpidr);
+ uint32_t cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
+
+ ihost_base = IHOST0_BASE + cluster_id * IHOST_ADDR_SPACE;
+ INFO("programming core #%u\n", coreid);
+
+ if (coreid) {
+ /* program the entry point for core1 */
+ mmio_write_32(ihost_base + A72_CRM_CORE_CONFIG_RVBA1_LO,
+ rvbar & 0xFFFF);
+ mmio_write_32(ihost_base + A72_CRM_CORE_CONFIG_RVBA1_MID,
+ (rvbar >> 16) & 0xFFFF);
+ mmio_write_32(ihost_base + A72_CRM_CORE_CONFIG_RVBA1_HI,
+ (rvbar >> 32) & 0xFFFF);
+ } else {
+ /* program the entry point for core */
+ mmio_write_32(ihost_base + A72_CRM_CORE_CONFIG_RVBA0_LO,
+ rvbar & 0xFFFF);
+ mmio_write_32(ihost_base + A72_CRM_CORE_CONFIG_RVBA0_MID,
+ (rvbar >> 16) & 0xFFFF);
+ mmio_write_32(ihost_base + A72_CRM_CORE_CONFIG_RVBA0_HI,
+ (rvbar >> 32) & 0xFFFF);
+ }
+
+ /* Tell debug logic which processor is up */
+ mmio_setbits_32(ihost_base + A72_CRM_SUBSYSTEM_CONFIG_0,
+ (coreid ?
+ (2 << A72_CRM_SUBSYSTEM_CONFIG_0__DBGPWRDUP_CFG_SHIFT) :
+ (1 << A72_CRM_SUBSYSTEM_CONFIG_0__DBGPWRDUP_CFG_SHIFT)));
+
+ /* releasing soft resets for IHOST core */
+ mmio_setbits_32(ihost_base + A72_CRM_SOFTRESETN_0,
+ (coreid ?
+ (1 << A72_CRM_SOFTRESETN_0__COREPOR1_SOFTRESETN) :
+ (1 << A72_CRM_SOFTRESETN_0__COREPOR0_SOFTRESETN)));
+
+ mmio_setbits_32(ihost_base + A72_CRM_SOFTRESETN_1,
+ (coreid ?
+ ((1 << A72_CRM_SOFTRESETN_1__CORE1_SOFTRESETN) |
+ (1 << A72_CRM_SOFTRESETN_1__DEBUG1_SOFTRESETN)) :
+ ((1 << A72_CRM_SOFTRESETN_1__CORE0_SOFTRESETN) |
+ (1 << A72_CRM_SOFTRESETN_1__DEBUG0_SOFTRESETN))));
+}
diff --git a/plat/brcm/board/stingray/src/iommu.c b/plat/brcm/board/stingray/src/iommu.c
new file mode 100644
index 0000000..de8b995
--- /dev/null
+++ b/plat/brcm/board/stingray/src/iommu.c
@@ -0,0 +1,536 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <iommu.h>
+#include <platform_def.h>
+
+#define SMMU_BASE 0x64000000
+#define ARM_SMMU_MAX_NUM_CNTXT_BANK 64
+#define SMMU_CTX_BANK_IDX_SECURE_CRMU 63
+#define ARM_SMMU_NUM_SECURE_MASTER 1
+#define ARM_SMMU_NSNUMCBO (ARM_SMMU_MAX_NUM_CNTXT_BANK - \
+ ARM_SMMU_NUM_SECURE_MASTER)
+#define ARM_SMMU_NSNUMSMRGO (ARM_SMMU_MAX_NUM_CNTXT_BANK - \
+ ARM_SMMU_NUM_SECURE_MASTER)
+/* Reserved Banks. */
+#define SMMU_CTX_BANK_IDX (SMMU_CTX_BANK_IDX_SECURE_CRMU - \
+ ARM_SMMU_NUM_SECURE_MASTER)
+#define NUM_OF_SMRS 1
+
+#define STG1_WITH_STG2_BYPASS 1
+#define ARM_LPAE_PGTBL_PHYS_CRMU 0x880000000
+#define ARM_LPAE_PGTBL_PHYS 0x880200000
+#define ARM_LPAE_PGTBL_PTE_CNT 512
+#define ARM_LPAE_PTE_L1_BLOCK_SIZE 0x40000000
+#define ARM_LPAE_PTE_L1_ADDR_MASK 0x0000FFFFC0000000UL
+#define ARM_LPAE_PTE_TABLE 0x2UL
+#define ARM_LPAE_PTE_VALID 0x1UL
+#define ARM_LPAE_PTE_ATTRINDX 2
+#define ARM_LPAE_PTE_NS 5
+#define ARM_LPAE_PTE_AP 6
+#define ARM_LPAE_PTE_AP_EL1_RW 0x0
+#define ARM_LPAE_PTE_AP_EL0_RW 0x1
+#define ARM_LPAE_PTE_SH 8
+#define ARM_LPAE_PTE_SH_NON 0x0
+#define ARM_LPAE_PTE_SH_OUTER 0x2
+#define ARM_LPAE_PTE_SH_INNER 0x3
+#define ARM_LPAE_PTE_AF 10
+#define ARM_SMMU_RES_SIZE 0x80000
+
+#define ARM_LPAE_PTE_NSTABLE 0x8000000000000000UL
+#define ARM_LPAE_PTE_L1_INDEX_SHIFT 30
+#define ARM_LPAE_PTE_L1_INDEX_MASK 0x1ff
+#define ARM_LPAE_PTE_L0_INDEX_SHIFT 39
+#define ARM_LPAE_PTE_L0_INDEX_MASK 0x1ff
+#define ARM_LPAE_PTE_TABLE_MASK ~(0xfffUL)
+/* Configuration registers */
+#define ARM_SMMU_GR0_sCR0 0x0
+#define sCR0_CLIENTPD (1 << 0)
+#define sCR0_GFRE (1 << 1)
+#define sCR0_GFIE (1 << 2)
+#define sCR0_GCFGFRE (1 << 4)
+#define sCR0_GCFGFIE (1 << 5)
+#define sCR0_USFCFG (1 << 10)
+#define sCR0_VMIDPNE (1 << 11)
+#define sCR0_PTM (1 << 12)
+#define sCR0_FB (1 << 13)
+#define sCR0_VMID16EN (1 << 31)
+#define sCR0_BSU_SHIFT 14
+#define sCR0_BSU_MASK 0x3
+#define ARM_SMMU_SMMU_SCR1 0x4
+#define SCR1_NSNUMCBO_MASK 0xFF
+#define SCR1_NSNUMCBO_SHIFT 0x0
+#define SCR1_NSNUMSMRGO_MASK 0xFF00
+#define SCR1_NSNUMSMRGO_SHIFT 0x8
+
+/* Identification registers */
+#define ARM_SMMU_GR0_ID0 0x20
+#define ARM_SMMU_GR0_ID1 0x24
+#define ARM_SMMU_GR0_ID2 0x28
+#define ARM_SMMU_GR0_ID3 0x2c
+#define ARM_SMMU_GR0_ID4 0x30
+#define ARM_SMMU_GR0_ID5 0x34
+#define ARM_SMMU_GR0_ID6 0x38
+#define ARM_SMMU_GR0_ID7 0x3c
+#define ARM_SMMU_GR0_sGFSR 0x48
+#define ARM_SMMU_GR0_sGFSYNR0 0x50
+#define ARM_SMMU_GR0_sGFSYNR1 0x54
+#define ARM_SMMU_GR0_sGFSYNR2 0x58
+
+#define ID1_PAGESIZE (1U << 31)
+#define ID1_NUMPAGENDXB_SHIFT 28
+#define ID1_NUMPAGENDXB_MASK 7
+#define ID1_NUMS2CB_SHIFT 16
+#define ID1_NUMS2CB_MASK 0xff
+#define ID1_NUMCB_SHIFT 0
+#define ID1_NUMCB_MASK 0xff
+
+/* SMMU global address space */
+#define ARM_SMMU_GR0(smmu) ((smmu)->base)
+#define ARM_SMMU_GR1(smmu) ((smmu)->base + (1 << (smmu)->pgshift))
+
+/* Stream mapping registers */
+#define ARM_SMMU_GR0_SMR(n) (0x800 + (n << 2))
+#define SMR_VALID (1U << 31)
+#define SMR_MASK_SHIFT 16
+#define SMR_ID_SHIFT 0
+
+#define ARM_SMMU_GR0_S2CR(n) (0xc00 + (n << 2))
+#define S2CR_CBNDX_SHIFT 0
+#define S2CR_CBNDX_MASK 0xff
+#define S2CR_TYPE_SHIFT 16
+#define S2CR_TYPE_MASK 0x3
+
+#define ARM_SMMU_GR1_CBA2R(n) (0x800 + (n << 2))
+#define CBA2R_RW64_32BIT (0 << 0)
+#define CBA2R_RW64_64BIT (1 << 0)
+#define CBA2R_VMID_SHIFT 16
+#define CBA2R_VMID_MASK 0xffff
+
+#define ARM_SMMU_GR1_CBAR(n) (0x0 + (n << 2))
+#define CBAR_VMID_SHIFT 0
+#define CBAR_VMID_MASK 0xff
+#define CBAR_S1_BPSHCFG_SHIFT 8
+#define CBAR_S1_BPSHCFG_MASK 3
+#define CBAR_S1_BPSHCFG_NSH 3
+#define CBAR_S1_MEMATTR_SHIFT 12
+#define CBAR_S1_MEMATTR_MASK 0xf
+#define CBAR_S1_MEMATTR_WB 0xf
+#define CBAR_TYPE_SHIFT 16
+#define CBAR_TYPE_MASK 0x3
+#define CBAR_TYPE_S2_TRANS (0 << CBAR_TYPE_SHIFT)
+#define CBAR_TYPE_S1_TRANS_S2_BYPASS (1 << CBAR_TYPE_SHIFT)
+#define CBAR_TYPE_S1_TRANS_S2_FAULT (2 << CBAR_TYPE_SHIFT)
+#define CBAR_TYPE_S1_TRANS_S2_TRANS (3 << CBAR_TYPE_SHIFT)
+#define CBAR_IRPTNDX_SHIFT 24
+#define CBAR_IRPTNDX_MASK 0xff
+
+/* Translation context bank */
+#define ARM_SMMU_CB_BASE(smmu) ((smmu)->base + ((smmu)->size >> 1))
+#define ARM_SMMU_CB(smmu, n) ((n) * (1 << (smmu)->pgshift))
+
+#define ARM_SMMU_CB_SCTLR 0x0
+#define ARM_SMMU_CB_ACTLR 0x4
+#define ARM_SMMU_CB_RESUME 0x8
+#define ARM_SMMU_CB_TTBCR2 0x10
+#define ARM_SMMU_CB_TTBR0 0x20
+#define ARM_SMMU_CB_TTBR1 0x28
+#define ARM_SMMU_CB_TTBCR 0x30
+#define ARM_SMMU_CB_CONTEXTIDR 0x34
+#define ARM_SMMU_CB_S1_MAIR0 0x38
+#define ARM_SMMU_CB_S1_MAIR1 0x3c
+#define ARM_SMMU_CB_PAR 0x50
+#define ARM_SMMU_CB_FSR 0x58
+#define ARM_SMMU_CB_FAR 0x60
+#define ARM_SMMU_CB_FSYNR0 0x68
+#define ARM_SMMU_CB_S1_TLBIVA 0x600
+#define ARM_SMMU_CB_S1_TLBIASID 0x610
+#define ARM_SMMU_CB_S1_TLBIVAL 0x620
+#define ARM_SMMU_CB_S2_TLBIIPAS2 0x630
+#define ARM_SMMU_CB_S2_TLBIIPAS2L 0x638
+#define ARM_SMMU_CB_ATS1PR 0x800
+#define ARM_SMMU_CB_ATSR 0x8f0
+
+#define SCTLR_S1_ASIDPNE (1 << 12)
+#define SCTLR_CFCFG (1 << 7)
+#define SCTLR_CFIE (1 << 6)
+#define SCTLR_CFRE (1 << 5)
+#define SCTLR_E (1 << 4)
+#define SCTLR_AFE (1 << 2)
+#define SCTLR_TRE (1 << 1)
+#define SCTLR_M (1 << 0)
+
+/* ARM LPAE configuration. */
+/**************************************************************/
+/* Register bits */
+#define ARM_32_LPAE_TCR_EAE (1 << 31)
+#define ARM_64_LPAE_S2_TCR_RES1 (1 << 31)
+
+#define ARM_LPAE_TCR_EPD1 (1 << 23)
+
+#define ARM_LPAE_TCR_TG0_4K (0 << 14)
+#define ARM_LPAE_TCR_TG0_64K (1 << 14)
+#define ARM_LPAE_TCR_TG0_16K (2 << 14)
+
+#define ARM_LPAE_TCR_SH0_SHIFT 12
+#define ARM_LPAE_TCR_SH0_MASK 0x3
+#define ARM_LPAE_TCR_SH_NS 0
+#define ARM_LPAE_TCR_SH_OS 2
+#define ARM_LPAE_TCR_SH_IS 3
+
+#define ARM_LPAE_TCR_ORGN0_SHIFT 10
+#define ARM_LPAE_TCR_IRGN0_SHIFT 8
+#define ARM_LPAE_TCR_RGN_MASK 0x3
+#define ARM_LPAE_TCR_RGN_NC 0
+#define ARM_LPAE_TCR_RGN_WBWA 1
+#define ARM_LPAE_TCR_RGN_WT 2
+#define ARM_LPAE_TCR_RGN_WB 3
+
+#define ARM_LPAE_TCR_SL0_SHIFT 6
+#define ARM_LPAE_TCR_SL0_MASK 0x3
+
+#define ARM_LPAE_TCR_T0SZ_SHIFT 0
+#define ARM_LPAE_TCR_SZ_MASK 0xf
+
+#define ARM_LPAE_TCR_PS_SHIFT 16
+#define ARM_LPAE_TCR_PS_MASK 0x7
+
+#define ARM_LPAE_TCR_IPS_SHIFT 32
+#define ARM_LPAE_TCR_IPS_MASK 0x7
+
+#define ARM_LPAE_TCR_PS_32_BIT 0x0ULL
+#define ARM_LPAE_TCR_PS_36_BIT 0x1ULL
+#define ARM_LPAE_TCR_PS_40_BIT 0x2ULL
+#define ARM_LPAE_TCR_PS_42_BIT 0x3ULL
+#define ARM_LPAE_TCR_PS_44_BIT 0x4ULL
+#define ARM_LPAE_TCR_PS_48_BIT 0x5ULL
+
+#define ARM_LPAE_MAIR_ATTR_SHIFT(n) ((n) << 3)
+#define ARM_LPAE_MAIR_ATTR_MASK 0xff
+#define ARM_LPAE_MAIR_ATTR_DEVICE 0x04
+#define ARM_LPAE_MAIR_ATTR_NC 0x44
+#define ARM_LPAE_MAIR_ATTR_WBRWA 0xff
+#define ARM_LPAE_MAIR_ATTR_IDX_NC 0
+#define ARM_LPAE_MAIR_ATTR_IDX_CACHE 1
+#define ARM_LPAE_MAIR_ATTR_IDX_DEV 2
+
+#define TTBRn_ASID_SHIFT 48
+#define TTBCR2_SEP_SHIFT 15
+#define TTBCR2_SEP_UPSTREAM (0x7 << TTBCR2_SEP_SHIFT)
+#define TTBCR2_AS (1 << 4)
+#define TTBCR_T0SZ(ia_bits) (64 - (ia_bits))
+
+#define S2CR_PRIVCFG_SHIFT 24
+#define S2CR_PRIVCFG_MASK 0x3
+
+/**************************************************************/
+
+uint16_t paxc_stream_ids[] = { 0x2000 };
+
+uint16_t paxc_stream_ids_mask[] = { 0x1fff };
+uint16_t crmu_stream_ids[] = { CRMU_STREAM_ID };
+uint16_t crmu_stream_ids_mask[] = { 0x0 };
+
+enum arm_smmu_s2cr_type {
+ S2CR_TYPE_TRANS,
+ S2CR_TYPE_BYPASS,
+ S2CR_TYPE_FAULT,
+};
+
+enum arm_smmu_s2cr_privcfg {
+ S2CR_PRIVCFG_DEFAULT,
+ S2CR_PRIVCFG_DIPAN,
+ S2CR_PRIVCFG_UNPRIV,
+ S2CR_PRIVCFG_PRIV,
+};
+
+struct arm_smmu_smr {
+ uint16_t mask;
+ uint16_t id;
+ uint32_t valid;
+};
+
+struct arm_smmu_s2cr {
+ int count;
+ enum arm_smmu_s2cr_type type;
+ enum arm_smmu_s2cr_privcfg privcfg;
+ uint8_t cbndx;
+};
+
+struct arm_smmu_cfg {
+ uint8_t cbndx;
+ uint8_t irptndx;
+ uint32_t cbar;
+};
+
+struct arm_smmu_device {
+ uint8_t *base;
+ uint32_t streams;
+ unsigned long size;
+ unsigned long pgshift;
+ unsigned long va_size;
+ unsigned long ipa_size;
+ unsigned long pa_size;
+ struct arm_smmu_smr smr[NUM_OF_SMRS];
+ struct arm_smmu_s2cr s2cr[NUM_OF_SMRS];
+ struct arm_smmu_cfg cfg[NUM_OF_SMRS];
+ uint16_t *stream_ids;
+ uint16_t *stream_ids_mask;
+};
+
+void arm_smmu_enable_secure_client_port(void)
+{
+ uintptr_t smmu_base = SMMU_BASE;
+
+ mmio_clrbits_32(smmu_base, sCR0_CLIENTPD);
+}
+
+void arm_smmu_reserve_secure_cntxt(void)
+{
+ uintptr_t smmu_base = SMMU_BASE;
+
+ mmio_clrsetbits_32(smmu_base + ARM_SMMU_SMMU_SCR1,
+ (SCR1_NSNUMSMRGO_MASK | SCR1_NSNUMCBO_MASK),
+ ((ARM_SMMU_NSNUMCBO << SCR1_NSNUMCBO_SHIFT) |
+ (ARM_SMMU_NSNUMSMRGO << SCR1_NSNUMSMRGO_SHIFT)));
+}
+
+static void arm_smmu_smr_cfg(struct arm_smmu_device *smmu, uint32_t index)
+{
+ uint32_t idx = smmu->cfg[index].cbndx;
+ struct arm_smmu_smr *smr = &smmu->smr[index];
+ uint32_t reg = smr->id << SMR_ID_SHIFT | smr->mask << SMR_MASK_SHIFT;
+
+ if (smr->valid)
+ reg |= SMR_VALID;
+
+ mmio_write_32((uintptr_t) (ARM_SMMU_GR0(smmu) +
+ ARM_SMMU_GR0_SMR(idx)), reg);
+}
+
+static void arm_smmu_s2cr_cfg(struct arm_smmu_device *smmu, uint32_t index)
+{
+ uint32_t idx = smmu->cfg[index].cbndx;
+ struct arm_smmu_s2cr *s2cr = &smmu->s2cr[index];
+
+ uint32_t reg = (s2cr->type & S2CR_TYPE_MASK) << S2CR_TYPE_SHIFT |
+ (s2cr->cbndx & S2CR_CBNDX_MASK) << S2CR_CBNDX_SHIFT |
+ (s2cr->privcfg & S2CR_PRIVCFG_MASK) << S2CR_PRIVCFG_SHIFT;
+
+ mmio_write_32((uintptr_t) (ARM_SMMU_GR0(smmu) +
+ ARM_SMMU_GR0_S2CR(idx)), reg);
+}
+
+static void smmu_set_pgtbl(struct arm_smmu_device *smmu,
+ enum iommu_domain dom,
+ uint64_t *pg_table_base)
+{
+ int i, l0_index, l1_index;
+ uint64_t addr, *pte, *l0_base, *l1_base;
+ uint64_t addr_space_limit;
+
+ if (dom == PCIE_PAXC) {
+ addr_space_limit = 0xffffffffff;
+ } else if (dom == DOMAIN_CRMU) {
+ addr_space_limit = 0xffffffff;
+ } else {
+ ERROR("dom is not supported\n");
+ return;
+ }
+
+ l0_base = pg_table_base;
+ /* clear L0 descriptors. */
+ for (i = 0; i < ARM_LPAE_PGTBL_PTE_CNT; i++)
+ l0_base[i] = 0x0;
+
+ addr = 0x0;
+ while (addr < addr_space_limit) {
+ /* find L0 pte */
+ l0_index = ((addr >> ARM_LPAE_PTE_L0_INDEX_SHIFT) &
+ ARM_LPAE_PTE_L0_INDEX_MASK);
+ l1_base = l0_base + ((l0_index + 1) * ARM_LPAE_PGTBL_PTE_CNT);
+
+ /* setup L0 pte if required */
+ pte = l0_base + l0_index;
+ if (*pte == 0x0) {
+ *pte |= ((uint64_t)l1_base & ARM_LPAE_PTE_TABLE_MASK);
+ if (dom == PCIE_PAXC)
+ *pte |= ARM_LPAE_PTE_NSTABLE;
+ *pte |= ARM_LPAE_PTE_TABLE;
+ *pte |= ARM_LPAE_PTE_VALID;
+ }
+
+ /* find L1 pte */
+ l1_index = ((addr >> ARM_LPAE_PTE_L1_INDEX_SHIFT) &
+ ARM_LPAE_PTE_L1_INDEX_MASK);
+ pte = l1_base + l1_index;
+
+ /* setup L1 pte */
+ *pte = 0x0;
+ *pte |= (addr & ARM_LPAE_PTE_L1_ADDR_MASK);
+ if (addr < 0x80000000) {
+ *pte |= (ARM_LPAE_MAIR_ATTR_IDX_DEV <<
+ ARM_LPAE_PTE_ATTRINDX);
+ if (dom == PCIE_PAXC)
+ *pte |= (1 << ARM_LPAE_PTE_NS);
+ } else {
+ *pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE <<
+ ARM_LPAE_PTE_ATTRINDX);
+ *pte |= (1 << ARM_LPAE_PTE_NS);
+ }
+ *pte |= (ARM_LPAE_PTE_AP_EL0_RW << ARM_LPAE_PTE_AP);
+ *pte |= (ARM_LPAE_PTE_SH_INNER << ARM_LPAE_PTE_SH);
+ *pte |= (1 << ARM_LPAE_PTE_AF);
+ *pte |= ARM_LPAE_PTE_VALID;
+
+ addr += ARM_LPAE_PTE_L1_BLOCK_SIZE;
+ }
+}
+
+void arm_smmu_create_identity_map(enum iommu_domain dom)
+{
+ struct arm_smmu_device iommu;
+ struct arm_smmu_device *smmu = &iommu;
+ uint32_t reg, reg2;
+ unsigned long long reg64;
+ uint32_t idx;
+ uint16_t asid;
+ unsigned int context_bank_index;
+ unsigned long long pg_table_base;
+
+ smmu->base = (uint8_t *) SMMU_BASE;
+ reg = mmio_read_32((uintptr_t) (ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_ID1));
+ smmu->pgshift = (reg & ID1_PAGESIZE) ? 16 : 12;
+ smmu->size = ARM_SMMU_RES_SIZE;
+ smmu->stream_ids = NULL;
+
+ switch (dom) {
+ case PCIE_PAXC:
+ smmu->stream_ids = &paxc_stream_ids[0];
+ smmu->stream_ids_mask = &paxc_stream_ids_mask[0];
+ smmu->streams = ARRAY_SIZE(paxc_stream_ids);
+ context_bank_index = SMMU_CTX_BANK_IDX;
+ pg_table_base = ARM_LPAE_PGTBL_PHYS;
+ break;
+ case DOMAIN_CRMU:
+ smmu->stream_ids = &crmu_stream_ids[0];
+ smmu->stream_ids_mask = &crmu_stream_ids_mask[0];
+ smmu->streams = ARRAY_SIZE(crmu_stream_ids);
+ context_bank_index = SMMU_CTX_BANK_IDX_SECURE_CRMU;
+ pg_table_base = ARM_LPAE_PGTBL_PHYS_CRMU;
+ break;
+ default:
+ ERROR("domain not supported\n");
+ return;
+ }
+
+ if (smmu->streams > NUM_OF_SMRS) {
+ INFO("can not support more than %d sids\n", NUM_OF_SMRS);
+ return;
+ }
+
+ /* set up iommu dev. */
+ for (idx = 0; idx < smmu->streams; idx++) {
+ /* S2CR. */
+ smmu->s2cr[idx].type = S2CR_TYPE_TRANS;
+ smmu->s2cr[idx].privcfg = S2CR_PRIVCFG_DEFAULT;
+ smmu->s2cr[idx].cbndx = context_bank_index;
+ smmu->cfg[idx].cbndx = context_bank_index;
+ smmu->cfg[idx].cbar = STG1_WITH_STG2_BYPASS << CBAR_TYPE_SHIFT;
+ arm_smmu_s2cr_cfg(smmu, idx);
+
+ /* SMR. */
+ smmu->smr[idx].mask = smmu->stream_ids_mask[idx];
+ smmu->smr[idx].id = smmu->stream_ids[idx];
+ smmu->smr[idx].valid = 1;
+ arm_smmu_smr_cfg(smmu, idx);
+
+ /* CBA2R. 64-bit Translation */
+ mmio_write_32((uintptr_t) (ARM_SMMU_GR1(smmu) +
+ ARM_SMMU_GR1_CBA2R(smmu->cfg[idx].cbndx)),
+ 0x1);
+ /* CBAR.*/
+ reg = smmu->cfg[idx].cbar;
+ reg |= (CBAR_S1_BPSHCFG_NSH << CBAR_S1_BPSHCFG_SHIFT) |
+ (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
+
+ mmio_write_32((uintptr_t) (ARM_SMMU_GR1(smmu) +
+ ARM_SMMU_GR1_CBAR(smmu->cfg[idx].cbndx)),
+ reg);
+
+ /* TTBCR. */
+ reg64 = (ARM_LPAE_TCR_SH_IS << ARM_LPAE_TCR_SH0_SHIFT) |
+ (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_IRGN0_SHIFT) |
+ (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT);
+ reg64 |= ARM_LPAE_TCR_TG0_4K;
+ reg64 |= (ARM_LPAE_TCR_PS_40_BIT << ARM_LPAE_TCR_IPS_SHIFT);
+ /* ias 40 bits.*/
+ reg64 |= TTBCR_T0SZ(40) << ARM_LPAE_TCR_T0SZ_SHIFT;
+ /* Disable speculative walks through TTBR1 */
+ reg64 |= ARM_LPAE_TCR_EPD1;
+ reg = (uint32_t) reg64;
+ reg2 = (uint32_t) (reg64 >> 32);
+ reg2 |= TTBCR2_SEP_UPSTREAM;
+ reg2 |= TTBCR2_AS;
+
+ mmio_write_32((uintptr_t) (ARM_SMMU_CB_BASE(smmu) +
+ ARM_SMMU_CB(smmu, smmu->cfg[idx].cbndx) +
+ ARM_SMMU_CB_TTBCR2), reg2);
+
+ mmio_write_32((uintptr_t) (ARM_SMMU_CB_BASE(smmu) +
+ ARM_SMMU_CB(smmu, smmu->cfg[idx].cbndx) +
+ ARM_SMMU_CB_TTBCR), reg);
+
+ /* TTBR0. */
+ asid = smmu->cfg[idx].cbndx;
+ reg64 = pg_table_base;
+ reg64 |= (unsigned long long) asid << TTBRn_ASID_SHIFT;
+
+ mmio_write_64((uintptr_t) (ARM_SMMU_CB_BASE(smmu) +
+ ARM_SMMU_CB(smmu, smmu->cfg[idx].cbndx) +
+ ARM_SMMU_CB_TTBR0), reg64);
+ /* TTBR1. */
+ reg64 = 0;
+ reg64 |= (unsigned long long) asid << TTBRn_ASID_SHIFT;
+
+ mmio_write_64((uintptr_t) (ARM_SMMU_CB_BASE(smmu) +
+ ARM_SMMU_CB(smmu, smmu->cfg[idx].cbndx) +
+ ARM_SMMU_CB_TTBR1), reg64);
+ /* MAIR. */
+ reg = (ARM_LPAE_MAIR_ATTR_NC
+ << ARM_LPAE_MAIR_ATTR_SHIFT
+ (ARM_LPAE_MAIR_ATTR_IDX_NC)) |
+ (ARM_LPAE_MAIR_ATTR_WBRWA <<
+ ARM_LPAE_MAIR_ATTR_SHIFT
+ (ARM_LPAE_MAIR_ATTR_IDX_CACHE)) |
+ (ARM_LPAE_MAIR_ATTR_DEVICE <<
+ ARM_LPAE_MAIR_ATTR_SHIFT
+ (ARM_LPAE_MAIR_ATTR_IDX_DEV));
+
+ mmio_write_32((uintptr_t) (ARM_SMMU_CB_BASE(smmu) +
+ ARM_SMMU_CB(smmu, smmu->cfg[idx].cbndx) +
+ ARM_SMMU_CB_S1_MAIR0), reg);
+
+ /* MAIR1. */
+ reg = 0;
+ mmio_write_32((uintptr_t) (ARM_SMMU_CB_BASE(smmu) +
+ ARM_SMMU_CB(smmu, smmu->cfg[idx].cbndx) +
+ ARM_SMMU_CB_S1_MAIR1), reg);
+ /* SCTLR. */
+ reg = SCTLR_CFIE | SCTLR_CFRE | SCTLR_AFE | SCTLR_TRE | SCTLR_M;
+ /* stage 1.*/
+ reg |= SCTLR_S1_ASIDPNE;
+ mmio_write_32((uintptr_t) (ARM_SMMU_CB_BASE(smmu) +
+ ARM_SMMU_CB(smmu, smmu->cfg[idx].cbndx) +
+ ARM_SMMU_CB_SCTLR), reg);
+ }
+ smmu_set_pgtbl(smmu, dom, (uint64_t *)pg_table_base);
+}
diff --git a/plat/brcm/board/stingray/src/ncsi.c b/plat/brcm/board/stingray/src/ncsi.c
new file mode 100644
index 0000000..58ea9e2
--- /dev/null
+++ b/plat/brcm/board/stingray/src/ncsi.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <ncsi.h>
+#include <sr_def.h>
+#include <sr_utils.h>
+
+static const char *const io_drives[] = {
+ "2mA", "4mA", "6mA", "8mA",
+ "10mA", "12mA", "14mA", "16mA"
+};
+
+void brcm_stingray_ncsi_init(void)
+{
+ unsigned int i = 0;
+ unsigned int selx = 0;
+
+#if NCSI_IO_DRIVE_STRENGTH_MA == 2
+ selx = 0x0;
+#elif NCSI_IO_DRIVE_STRENGTH_MA == 4
+ selx = 0x1;
+#elif NCSI_IO_DRIVE_STRENGTH_MA == 6
+ selx = 0x2;
+#elif NCSI_IO_DRIVE_STRENGTH_MA == 8
+ selx = 0x3;
+#elif NCSI_IO_DRIVE_STRENGTH_MA == 10
+ selx = 0x4;
+#elif NCSI_IO_DRIVE_STRENGTH_MA == 12
+ selx = 0x5;
+#elif NCSI_IO_DRIVE_STRENGTH_MA == 14
+ selx = 0x6;
+#elif NCSI_IO_DRIVE_STRENGTH_MA == 16
+ selx = 0x7;
+#else
+ ERROR("Unsupported NCSI_IO_DRIVE_STRENGTH_MA. Please check it.\n");
+ return;
+#endif
+ INFO("ncsi io drives: %s\n", io_drives[selx]);
+
+ for (i = 0; i < NITRO_NCSI_IOPAD_CONTROL_NUM; i++) {
+ mmio_clrsetbits_32((NITRO_NCSI_IOPAD_CONTROL_BASE + (i * 4)),
+ PAD_SELX_MASK, PAD_SELX_VALUE(selx));
+ }
+
+ INFO("ncsi init done\n");
+}
diff --git a/plat/brcm/board/stingray/src/paxb.c b/plat/brcm/board/stingray/src/paxb.c
new file mode 100644
index 0000000..89f76d0
--- /dev/null
+++ b/plat/brcm/board/stingray/src/paxb.c
@@ -0,0 +1,911 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <paxb.h>
+#include <sr_def.h>
+#include <sr_utils.h>
+
+#define PCIE_CORE_PWR_ARR_POWERON 0x8
+#define PCIE_CORE_PWR_ARR_POWEROK 0x4
+#define PCIE_CORE_PWR_POWERON 0x2
+#define PCIE_CORE_PWR_POWEROK 0x1
+
+#define PCIE_CORE_USER_CFG (PCIE_CORE_BASE + 0x38)
+#define PCIE_PAXB_SMMU_SID_CFG (PCIE_CORE_BASE + 0x60)
+#ifdef SID_B8_D1_F1
+#define PAXB_SMMU_SID_CFG_BUS_WIDTH (0x8 << 8)
+#define PAXB_SMMU_SID_CFG_DEV_WIDTH (0x1 << 12)
+#define PAXB_SMMU_SID_CFG_FUN_WIDTH (0x1 << 16)
+#else
+#define PAXB_SMMU_SID_CFG_BUS_WIDTH (0x2 << 8)
+#define PAXB_SMMU_SID_CFG_DEV_WIDTH (0x5 << 12)
+#define PAXB_SMMU_SID_CFG_FUN_WIDTH (0x3 << 16)
+#endif
+
+#define PAXB_APB_TIMEOUT_COUNT_OFFSET 0x034
+
+/* allow up to 5 ms for each power switch to stabilize */
+#define PCIE_CORE_PWR_TIMEOUT_MS 5
+
+/* wait 1 microsecond for PCIe core soft reset */
+#define PCIE_CORE_SOFT_RST_DELAY_US 1
+
+/*
+ * List of PAXB APB registers
+ */
+#define PAXB_BASE 0x48000000
+#define PAXB_BASE_OFFSET 0x4000
+#define PAXB_OFFSET(core) (PAXB_BASE + \
+ (core) * PAXB_BASE_OFFSET)
+
+#define PAXB_CLK_CTRL_OFFSET 0x000
+#define PAXB_EP_PERST_SRC_SEL_MASK (1 << 2)
+#define PAXB_EP_MODE_PERST_MASK (1 << 1)
+#define PAXB_RC_PCIE_RST_OUT_MASK (1 << 0)
+
+#define PAXB_MAX_IMAP_WINDOWS 8
+#define PAXB_IMAP_REG_WIDTH 8
+#define PAXB_IMAP0_REG_WIDTH 4
+#define PAXB_AXUSER_REG_WIDTH 4
+
+#define PAXB_CFG_IND_ADDR_OFFSET 0x120
+#define PAXB_CFG_IND_DATA_OFFSET 0x124
+#define PAXB_CFG_IND_ADDR_MASK 0x1ffc
+#define PAXB_CFG_CFG_TYPE_MASK 0x1
+
+#define PAXB_EP_CFG_ADDR_OFFSET 0x1f8
+#define PAXB_EP_CFG_DATA_OFFSET 0x1fc
+#define PAXB_EP_CFG_ADDR_MASK 0xffc
+#define PAXB_EP_CFG_TYPE_MASK 0x1
+
+#define PAXB_0_DEFAULT_IMAP 0xed0
+#define DEFAULT_ADDR_INVALID BIT(0)
+#define PAXB_0_DEFAULT_IMAP_AXUSER 0xed8
+#define PAXB_0_DEFAULT_IMAP_AXCACHE 0xedc
+#define IMAP_AXCACHE 0xff
+#define OARR_VALID BIT(0)
+#define IMAP_VALID BIT(0)
+
+#define PAXB_IMAP0_BASE_OFFSET 0xc00
+#define PAXB_IARR0_BASE_OFFSET 0xd00
+#define PAXB_IMAP0_OFFSET(idx) (PAXB_IMAP0_BASE_OFFSET + \
+ (idx) * PAXB_IMAP0_REG_WIDTH)
+#define PAXB_IMAP0_WINDOW_SIZE 0x1000
+
+#define PAXB_IMAP2_OFFSET 0xcc0
+#define PAXB_IMAP0_REGS_TYPE_OFFSET 0xcd0
+#define PAXB_IARR2_LOWER_OFFSET 0xd10
+
+#define PAXB_IMAP3_BASE_OFFSET 0xe08
+#define PAXB_IMAP3_OFFSET(idx) (PAXB_IMAP3_BASE_OFFSET + \
+ (idx) * PAXB_IMAP_REG_WIDTH)
+
+#define PAXB_IMAP3_0_AXUSER_B_OFFSET 0xe48
+#define PAXB_IMAP3_0_AXUSER_OFFSET(idx) (PAXB_IMAP3_0_AXUSER_B_OFFSET + \
+ (idx) * PAXB_AXUSER_REG_WIDTH)
+
+#define PAXB_IMAP4_BASE_OFFSET 0xe70
+#define PAXB_IMAP4_OFFSET(idx) (PAXB_IMAP4_BASE_OFFSET + \
+ (idx) * PAXB_IMAP_REG_WIDTH)
+
+#define PAXB_IMAP4_0_AXUSER_B_OFFSET 0xeb0
+#define PAXB_IMAP4_0_AXUSER_OFFSET(idx) (PAXB_IMAP4_0_AXUSER_B_OFFSET + \
+ (idx) * PAXB_AXUSER_REG_WIDTH)
+
+#define PAXB_CFG_LINK_STATUS_OFFSET 0xf0c
+#define PAXB_CFG_PHYLINKUP_MASK (1 << 3)
+#define PAXB_CFG_DL_ACTIVE_MASK (1 << 2)
+
+#define PAXB_IMAP0_0_AXUSER_OFFSET 0xf60
+#define PAXB_IMAP2_AXUSER_OFFSET 0xfe0
+
+/* cacheable write-back, allocate on both reads and writes */
+#define IMAP_ARCACHE 0x0f0
+#define IMAP_AWCACHE 0xf00
+/* normal access, nonsecure access, and data access */
+/* AWQOS:0xe and ARQOS:0xa */
+/* AWPROT:0x2 and ARPROT:0x1 */
+#define IMAP_AXUSER 0x002e002a
+
+/*
+ * List of NIC security and PIPEMUX related registers
+ */
+#define SR_PCIE_NIC_SECURITY_BASE 0x58100000
+#define NS3Z_PCIE_NIC_SECURITY_BASE 0x48100000
+
+#define GITS_TRANSLATER 0x63c30000
+
+#define VENDOR_ID 0x14e4
+#define CFG_RC_DEV_ID 0x434
+#define CFG_RC_DEV_SUBID 0x438
+#define PCI_BRIDGE_CTRL_REG_OFFSET 0x43c
+#define PCI_CLASS_BRIDGE_MASK 0xffff00
+#define PCI_CLASS_BRIDGE_SHIFT 8
+#define PCI_CLASS_BRIDGE_PCI 0x0604
+
+/*
+ * List of PAXB RC configuration space registers
+ */
+
+/* first capability list entry */
+#define PCI_CAPABILITY_LIST_OFFSET 0x34
+#define PCI_CAPABILITY_SPEED_OFFSET 0xc
+#define PCI_EP_CAPABILITY_OFFSET 0x10
+
+#define CFG_RC_LINK_STATUS_CTRL_2 0x0dc
+#define CFG_RC_LINK_SPEED_SHIFT 0
+#define CFG_RC_LINK_SPEED_MASK (0xf << CFG_RC_LINK_SPEED_SHIFT)
+
+#define CFG_RC_DEVICE_CAP 0x4d4
+#define CFG_RC_DEVICE_CAP_MPS_SHIFT 0
+#define CFG_RC_DEVICE_CAP_MPS_MASK (0x7 << CFG_RC_DEVICE_CAP_MPS_SHIFT)
+/* MPS 256 bytes */
+#define CFG_RC_DEVICE_CAP_MPS_256B (0x1 << CFG_RC_DEVICE_CAP_MPS_SHIFT)
+/* MPS 512 bytes */
+#define CFG_RC_DEVICE_CAP_MPS_512B (0x2 << CFG_RC_DEVICE_CAP_MPS_SHIFT)
+
+#define CFG_RC_TL_FCIMM_NP_LIMIT 0xa10
+#define CFG_RC_TL_FCIMM_NP_VAL 0x01500000
+#define CFG_RC_TL_FCIMM_P_LIMIT 0xa14
+#define CFG_RC_TL_FCIMM_P_VAL 0x03408080
+
+#define CFG_RC_LINK_CAP 0x4dc
+#define CFG_RC_LINK_CAP_SPEED_SHIFT 0
+#define CFG_RC_LINK_CAP_SPEED_MASK (0xf << CFG_RC_LINK_CAP_SPEED_SHIFT)
+#define CFG_RC_LINK_CAP_WIDTH_SHIFT 4
+#define CFG_RC_LINK_CAP_WIDTH_MASK (0x1f << CFG_RC_LINK_CAP_WIDTH_SHIFT)
+
+#define CFG_LINK_CAP_RC 0x4f0
+#define CFG_RC_DL_ACTIVE_SHIFT 0
+#define CFG_RC_DL_ACTIVE_MASK (0x1 << CFG_RC_DL_ACTIVE_SHIFT)
+#define CFG_RC_SLOT_CLK_SHIFT 1
+#define CFG_RC_SLOT_CLK_MASK (0x1 << CFG_RC_SLOT_CLK_SHIFT)
+
+#define CFG_ROOT_CAP_RC 0x4f8
+#define CFG_ROOT_CAP_LTR_SHIFT 1
+#define CFG_ROOT_CAP_LTR_MASK (0x1 << CFG_ROOT_CAP_LTR_SHIFT)
+
+#define CFG_RC_CLKREQ_ENABLED 0x4fc
+#define CFG_RC_CLKREQ_ENABLED_SHIFT 0
+#define CFG_RC_CLKREQ_ENABLED_MASK (0x1 << CFG_RC_CLKREQ_ENABLED_SHIFT)
+
+#define CFG_RC_COEFF_ADDR 0x638
+
+#define CFG_RC_TL_CTRL_0 0x800
+#define RC_MEM_DW_CHK_MASK 0x03fe
+
+#define CFG_RC_PDL_CTRL_4 0x1010
+#define NPH_FC_INIT_SHIFT 24
+#define NPH_FC_INIT_MASK (U(0xff) << NPH_FC_INIT_SHIFT)
+#define PD_FC_INIT_SHIFT 12
+#define PD_FC_INIT_MASK (0xffff << PD_FC_INIT_SHIFT)
+
+#define CFG_RC_PDL_CTRL_5 0x1014
+#define PH_INIT_SHIFT 0
+#define PH_INIT_MASK (0xff << PH_INIT_SHIFT)
+
+#define DL_STATUS_OFFSET 0x1048
+#define PHYLINKUP BIT(13)
+
+#define PH_INIT 0x10
+#define PD_FC_INIT 0x100
+#define NPH_FC_INIT 0x8
+
+#define SRP_PH_INIT 0x7F
+#define SRP_PD_FC_INIT 0x200
+#define SRP_NPH_FC_INIT 0x7F
+
+#define CFG_ADDR_BUS_NUM_SHIFT 20
+#define CFG_ADDR_DEV_NUM_SHIFT 15
+#define CFG_ADDR_FUNC_NUM_SHIFT 12
+#define CFG_ADDR_REG_NUM_SHIFT 2
+#define CFG_ADDR_REG_NUM_MASK 0x00000ffc
+#define CFG_ADDR_CFG_TYPE_MASK 0x00000003
+
+#define DL_LINK_UP_TIMEOUT_MS 1000
+
+#define CFG_RETRY_STATUS 0xffff0001
+#define CRS_TIMEOUT_MS 5000
+
+/* create EP config data to write */
+#define DEF_BUS_NO 1 /* default bus 1 */
+#define DEF_SLOT_NO 0 /* default slot 0 */
+#define DEF_FN_NO 0 /* default fn 0 */
+
+#define EP_CONFIG_VAL(bus_no, slot, fn, where) \
+ (((bus_no) << CFG_ADDR_BUS_NUM_SHIFT) | \
+ ((slot) << CFG_ADDR_DEV_NUM_SHIFT) | \
+ ((fn) << CFG_ADDR_FUNC_NUM_SHIFT) | \
+ ((where) & CFG_ADDR_REG_NUM_MASK) | \
+ (1 & CFG_ADDR_CFG_TYPE_MASK))
+
+/* PAXB security offset */
+#define PAXB_SECURITY_IDM_OFFSET 0x1c
+#define PAXB_SECURITY_APB_OFFSET 0x24
+#define PAXB_SECURITY_ECAM_OFFSET 0x3c
+
+#define paxb_get_config(type) paxb_get_##type##_config()
+
+static unsigned int paxb_sec_reg_offset[] = {
+ 0x0c, /* PAXB0 AXI */
+ 0x10, /* PAXB1 AXI */
+ 0x14, /* PAXB2 AXI */
+ 0x18, /* PAXB3 AXI */
+ 0x20, /* PAXB4 AXI */
+ 0x28, /* PAXB5 AXI */
+ 0x2c, /* PAXB6 AXI */
+ 0x30, /* PAXB7 AXI */
+ 0x24, /* PAXB APB */
+};
+
+const paxb_cfg *paxb;
+
+/*
+ * Given a PIPEMUX strap and PCIe core index, this function returns 1 if a
+ * PCIe core needs to be enabled
+ */
+int pcie_core_needs_enable(unsigned int core_idx)
+{
+ if (paxb->core_needs_enable)
+ return paxb->core_needs_enable(core_idx);
+
+ return 0;
+}
+
+static void pcie_set_default_tx_coeff(uint32_t core_idx, uint32_t link_width)
+{
+ unsigned int lanes = 0;
+ uint32_t data, addr;
+
+ addr = CFG_RC_COEFF_ADDR;
+ for (lanes = 0; lanes < link_width; lanes = lanes + 2) {
+ data = paxb_rc_cfg_read(core_idx, addr);
+ data &= 0xf0f0f0f0;
+ data |= (7 & 0xf);
+ data |= (7 & 0xf) << 8;
+ data |= (7 & 0xf) << 16;
+ data |= (7 & 0xf) << 24;
+
+ paxb_rc_cfg_write(core_idx, addr, data);
+ addr += 4;
+ }
+}
+
+static int paxb_rc_link_init(void)
+{
+ uint32_t val, link_speed;
+ unsigned int link_width;
+ uint32_t core_idx;
+
+ for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) {
+ if (!pcie_core_needs_enable(core_idx))
+ continue;
+
+ link_width = paxb->get_link_width(core_idx);
+ if (!link_width) {
+ ERROR("Unsupported PIPEMUX\n");
+ return -EOPNOTSUPP;
+ }
+
+ link_speed = paxb->get_link_speed();
+ /* program RC's link cap reg to advertise proper link width */
+ val = paxb_rc_cfg_read(core_idx, CFG_RC_LINK_CAP);
+ val &= ~CFG_RC_LINK_CAP_WIDTH_MASK;
+ val |= (link_width << CFG_RC_LINK_CAP_WIDTH_SHIFT);
+ paxb_rc_cfg_write(core_idx, CFG_RC_LINK_CAP, val);
+
+ /* program RC's link cap reg to advertise proper link speed */
+ val = paxb_rc_cfg_read(core_idx, CFG_RC_LINK_CAP);
+ val &= ~CFG_RC_LINK_CAP_SPEED_MASK;
+ val |= link_speed << CFG_RC_LINK_CAP_SPEED_SHIFT;
+ paxb_rc_cfg_write(core_idx, CFG_RC_LINK_CAP, val);
+
+ /* also need to program RC's link status control register */
+ val = paxb_rc_cfg_read(core_idx, CFG_RC_LINK_STATUS_CTRL_2);
+ val &= ~(CFG_RC_LINK_SPEED_MASK);
+ val |= link_speed << CFG_RC_LINK_SPEED_SHIFT;
+ paxb_rc_cfg_write(core_idx, CFG_RC_LINK_STATUS_CTRL_2, val);
+
+#ifdef WAR_PLX_PRESET_PARITY_FAIL
+ /* WAR to avoid crash with PLX switch in GEN3*/
+ /* While PRESET, PLX switch is not fixing parity so disabled */
+ val = paxb_rc_cfg_read(core_idx, CFG_RC_REG_PHY_CTL_10);
+ val &= ~(PHY_CTL_10_GEN3_MATCH_PARITY);
+ paxb_rc_cfg_write(core_idx, CFG_RC_REG_PHY_CTL_10, val);
+#endif
+ pcie_set_default_tx_coeff(core_idx, link_width);
+ }
+ return 0;
+}
+
+#ifdef PAXB_LINKUP
+static void paxb_perst_ctrl(unsigned int core_idx, bool assert)
+{
+ uint32_t clk_ctrl = PAXB_OFFSET(core_idx) + PAXB_CLK_CTRL_OFFSET;
+
+ if (assert) {
+ mmio_clrbits_32(clk_ctrl, PAXB_EP_PERST_SRC_SEL_MASK |
+ PAXB_EP_MODE_PERST_MASK |
+ PAXB_RC_PCIE_RST_OUT_MASK);
+ udelay(250);
+ } else {
+ mmio_setbits_32(clk_ctrl, PAXB_RC_PCIE_RST_OUT_MASK);
+ mdelay(100);
+ }
+}
+
+static void paxb_start_link_up(void)
+{
+ unsigned int core_idx;
+ uint32_t val, timeout;
+
+ for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) {
+ if (!pcie_core_needs_enable(core_idx))
+ continue;
+
+ /* toggle PERST */
+ paxb_perst_ctrl(core_idx, true);
+ paxb_perst_ctrl(core_idx, false);
+
+ timeout = DL_LINK_UP_TIMEOUT_MS;
+ /* wait for Link up */
+ do {
+ val = mmio_read_32(PAXB_OFFSET(core_idx) +
+ PAXB_CFG_LINK_STATUS_OFFSET);
+ if (val & PAXB_CFG_DL_ACTIVE_MASK)
+ break;
+
+ mdelay(1);
+ } while (--timeout);
+
+ if (!timeout)
+ ERROR("PAXB core %u link is down\n", core_idx);
+ }
+}
+#endif
+
+static void pcie_core_soft_reset(unsigned int core_idx)
+{
+ uint32_t offset = core_idx * PCIE_CORE_PWR_OFFSET;
+ uintptr_t ctrl = (uintptr_t)(PCIE_CORE_SOFT_RST_CFG_BASE + offset);
+
+ /* Put PCIe core in soft reset */
+ mmio_clrbits_32(ctrl, PCIE_CORE_SOFT_RST);
+
+ /* Wait for 1 us before pulling PCIe core out of soft reset */
+ udelay(PCIE_CORE_SOFT_RST_DELAY_US);
+
+ mmio_setbits_32(ctrl, PCIE_CORE_SOFT_RST);
+}
+
+static int pcie_core_pwron_switch(uintptr_t ctrl, uintptr_t status,
+ uint32_t mask)
+{
+ uint32_t val;
+ unsigned int timeout = PCIE_CORE_PWR_TIMEOUT_MS;
+
+ /* enable switch */
+ mmio_setbits_32(ctrl, mask);
+
+ /* now wait for it to stabilize */
+ do {
+ val = mmio_read_32(status);
+ if ((val & mask) == mask)
+ return 0;
+ mdelay(1);
+ } while (--timeout);
+
+ return -EIO;
+}
+
+static int pcie_core_pwr_seq(uintptr_t ctrl, uintptr_t status)
+{
+ int ret;
+
+ /*
+ * Enable the switch with the following sequence:
+ * 1. Array weak switch output switch
+ * 2. Array strong switch
+ * 3. Weak switch output acknowledge
+ * 4. Strong switch output acknowledge
+ */
+ ret = pcie_core_pwron_switch(ctrl, status, PCIE_CORE_PWR_ARR_POWERON);
+ if (ret)
+ return ret;
+
+ ret = pcie_core_pwron_switch(ctrl, status, PCIE_CORE_PWR_ARR_POWEROK);
+ if (ret)
+ return ret;
+
+ ret = pcie_core_pwron_switch(ctrl, status, PCIE_CORE_PWR_POWERON);
+ if (ret)
+ return ret;
+
+ ret = pcie_core_pwron_switch(ctrl, status, PCIE_CORE_PWR_POWEROK);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * This function enables PCIe core and PAXB memory buffer power, and then
+ * remove the PCIe core from isolation
+ */
+static int pcie_core_pwr_init(unsigned int core_idx)
+{
+ int ret;
+ uint32_t offset = core_idx * PCIE_CORE_PWR_OFFSET;
+ uintptr_t ctrl, status;
+
+ /* enable mem power to PCIe core */
+ ctrl = (uintptr_t)(PCIE_CORE_MEM_PWR_BASE + offset);
+ status = (uintptr_t)(PCIE_CORE_MEM_PWR_STATUS_BASE + offset);
+ ret = pcie_core_pwr_seq(ctrl, status);
+ if (ret) {
+ ERROR("PCIe core mem power failed\n");
+ return ret;
+ }
+
+ /* now enable mem power to PAXB wrapper */
+ ctrl = (uintptr_t)(PCIE_PAXB_MEM_PWR_BASE + offset);
+ status = (uintptr_t)(PCIE_PAXB_MEM_PWR_STATUS_BASE + offset);
+ ret = pcie_core_pwr_seq(ctrl, status);
+ if (ret) {
+ ERROR("PAXB mem power failed\n");
+ return ret;
+ }
+
+ /* now remove power isolation */
+ ctrl = (uintptr_t)(PCIE_CORE_ISO_CFG_BASE + offset);
+ mmio_clrbits_32(ctrl, PCIE_CORE_ISO | PCIE_CORE_MEM_ISO);
+
+ return 0;
+}
+
+static void pcie_ss_reset(void)
+{
+ mmio_setbits_32(CDRU_MISC_RESET_CONTROL,
+ 1 << CDRU_MISC_RESET_CONTROL__CDRU_PCIE_RESET_N_R);
+}
+
+/*
+ * This function reads the PIPEMUX strap, figures out all the PCIe cores that
+ * need to be enabled and enable the mem power for those cores
+ */
+static int pcie_cores_init(void)
+{
+ int ret = 0;
+ uint32_t core_idx;
+
+ if (paxb->pipemux_init) {
+ ret = paxb->pipemux_init();
+ if (ret)
+ return ret;
+ }
+
+ /* bring PCIe subsystem out of reset */
+ pcie_ss_reset();
+
+ /* power up all PCIe cores that will be used as RC */
+ for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) {
+ if (!pcie_core_needs_enable(core_idx))
+ continue;
+
+ ret = pcie_core_pwr_init(core_idx);
+ if (ret) {
+ ERROR("PCIe core %u power up failed\n", core_idx);
+ return ret;
+ }
+
+ pcie_core_soft_reset(core_idx);
+
+ VERBOSE("PCIe core %u is powered up\n", core_idx);
+ }
+
+ return ret;
+}
+
+void paxb_rc_cfg_write(unsigned int core_idx, unsigned int where,
+ uint32_t val)
+{
+ mmio_write_32(PAXB_OFFSET(core_idx) + PAXB_CFG_IND_ADDR_OFFSET,
+ (where & PAXB_CFG_IND_ADDR_MASK) |
+ PAXB_CFG_CFG_TYPE_MASK);
+ mmio_write_32(PAXB_OFFSET(core_idx) + PAXB_CFG_IND_DATA_OFFSET, val);
+}
+
+unsigned int paxb_rc_cfg_read(unsigned int core_idx, unsigned int where)
+{
+ unsigned int val;
+
+ mmio_write_32(PAXB_OFFSET(core_idx) + PAXB_CFG_IND_ADDR_OFFSET,
+ (where & PAXB_CFG_IND_ADDR_MASK) |
+ PAXB_CFG_CFG_TYPE_MASK);
+ val = mmio_read_32(PAXB_OFFSET(core_idx) + PAXB_CFG_IND_DATA_OFFSET);
+
+ return val;
+}
+
+static void paxb_cfg_mps(void)
+{
+ uint32_t val, core_idx, mps;
+
+ for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) {
+ if (!pcie_core_needs_enable(core_idx))
+ continue;
+
+ val = paxb_rc_cfg_read(core_idx, CFG_RC_DEVICE_CAP);
+ val &= ~CFG_RC_DEVICE_CAP_MPS_MASK;
+ mps = CFG_RC_DEVICE_CAP_MPS_256B;
+ if (core_idx == 0 || core_idx == 1 ||
+ core_idx == 6 || core_idx == 7) {
+ mps = CFG_RC_DEVICE_CAP_MPS_512B;
+ }
+ val |= mps;
+ paxb_rc_cfg_write(core_idx, CFG_RC_DEVICE_CAP, val);
+ }
+}
+
+static void paxb_cfg_dev_id(void)
+{
+ uint32_t val, core_idx;
+ uint32_t device_id;
+
+ device_id = paxb->device_id;
+
+ for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) {
+ if (!pcie_core_needs_enable(core_idx))
+ continue;
+
+ /* Set Core in RC mode */
+ mmio_setbits_32(PCIE_CORE_USER_CFG +
+ (core_idx * PCIE_CORE_PWR_OFFSET), 1);
+
+ /* force class to PCI_CLASS_BRIDGE_PCI (0x0604) */
+ val = paxb_rc_cfg_read(core_idx, PCI_BRIDGE_CTRL_REG_OFFSET);
+ val &= ~PCI_CLASS_BRIDGE_MASK;
+ val |= (PCI_CLASS_BRIDGE_PCI << PCI_CLASS_BRIDGE_SHIFT);
+ paxb_rc_cfg_write(core_idx, PCI_BRIDGE_CTRL_REG_OFFSET, val);
+
+ val = (VENDOR_ID << 16) | device_id;
+ paxb_rc_cfg_write(core_idx, CFG_RC_DEV_ID, val);
+
+ val = (device_id << 16) | VENDOR_ID;
+ paxb_rc_cfg_write(core_idx, CFG_RC_DEV_SUBID, val);
+ }
+}
+
+static void paxb_cfg_tgt_trn(void)
+{
+ uint32_t val, core_idx;
+
+ /*
+ * Disable all mem Rd/Wr size check so it allows target read/write
+ * transactions to be more than stipulated DW. As a result, PAXB root
+ * complex will not abort these read/write transcations beyond
+ * stipulated limit
+ */
+ for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) {
+ if (!pcie_core_needs_enable(core_idx))
+ continue;
+
+ val = paxb_rc_cfg_read(core_idx, CFG_RC_TL_CTRL_0);
+ val &= ~(RC_MEM_DW_CHK_MASK);
+ paxb_rc_cfg_write(core_idx, CFG_RC_TL_CTRL_0, val);
+ }
+}
+
+static void paxb_cfg_pdl_ctrl(void)
+{
+ uint32_t val, core_idx;
+ uint32_t nph, ph, pd;
+
+ /* increase the credit counter to 4 for non-posted header */
+ for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) {
+ if (!pcie_core_needs_enable(core_idx))
+ continue;
+
+ nph = NPH_FC_INIT;
+ ph = PH_INIT;
+ pd = PD_FC_INIT;
+
+ if (core_idx == 0 || core_idx == 1 ||
+ core_idx == 6 || core_idx == 7) {
+ nph = SRP_NPH_FC_INIT;
+ ph = SRP_PH_INIT;
+ pd = SRP_PD_FC_INIT;
+ }
+ val = paxb_rc_cfg_read(core_idx, CFG_RC_PDL_CTRL_4);
+ val &= ~NPH_FC_INIT_MASK;
+ val &= ~PD_FC_INIT_MASK;
+ val = val | (nph << NPH_FC_INIT_SHIFT);
+ val = val | (pd << PD_FC_INIT_SHIFT);
+ paxb_rc_cfg_write(core_idx, CFG_RC_PDL_CTRL_4, val);
+
+ val = paxb_rc_cfg_read(core_idx, CFG_RC_PDL_CTRL_5);
+ val &= ~PH_INIT_MASK;
+ val = val | (ph << PH_INIT_SHIFT);
+ paxb_rc_cfg_write(core_idx, CFG_RC_PDL_CTRL_5, val);
+
+ /*
+ * ASIC to give more optmized value after further investigation.
+ * till then this is important to have to get similar
+ * performance on all the slots.
+ */
+ paxb_rc_cfg_write(core_idx, CFG_RC_TL_FCIMM_NP_LIMIT,
+ CFG_RC_TL_FCIMM_NP_VAL);
+
+ paxb_rc_cfg_write(core_idx, CFG_RC_TL_FCIMM_P_LIMIT,
+ CFG_RC_TL_FCIMM_P_VAL);
+ }
+}
+
+static void paxb_cfg_clkreq(void)
+{
+ uint32_t val, core_idx;
+
+ for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) {
+ if (!pcie_core_needs_enable(core_idx))
+ continue;
+
+ val = paxb_rc_cfg_read(core_idx, CFG_RC_CLKREQ_ENABLED);
+ val &= ~CFG_RC_CLKREQ_ENABLED_MASK;
+ paxb_rc_cfg_write(core_idx, CFG_RC_CLKREQ_ENABLED, val);
+ }
+}
+
+static void paxb_cfg_dl_active(bool enable)
+{
+ uint32_t val, core_idx;
+
+ for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) {
+ if (!pcie_core_needs_enable(core_idx))
+ continue;
+
+ val = paxb_rc_cfg_read(core_idx, CFG_LINK_CAP_RC);
+ if (enable)
+ val |= CFG_RC_DL_ACTIVE_MASK;
+ else
+ val &= ~CFG_RC_DL_ACTIVE_MASK;
+ paxb_rc_cfg_write(core_idx, CFG_LINK_CAP_RC, val);
+ }
+}
+
+static void paxb_cfg_LTR(int enable)
+{
+ uint32_t val, core_idx;
+
+ for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) {
+ if (!pcie_core_needs_enable(core_idx))
+ continue;
+
+ val = paxb_rc_cfg_read(core_idx, CFG_ROOT_CAP_RC);
+ if (enable)
+ val |= CFG_ROOT_CAP_LTR_MASK;
+ else
+ val &= ~CFG_ROOT_CAP_LTR_MASK;
+ paxb_rc_cfg_write(core_idx, CFG_ROOT_CAP_RC, val);
+ }
+}
+
+static void paxb_ib_regs_bypass(void)
+{
+ unsigned int i, j;
+
+ for (i = 0; i < paxb->num_cores; i++) {
+ if (!pcie_core_needs_enable(i))
+ continue;
+
+ /* Configure Default IMAP window */
+ mmio_write_32(PAXB_OFFSET(i) + PAXB_0_DEFAULT_IMAP,
+ DEFAULT_ADDR_INVALID);
+ mmio_write_32(PAXB_OFFSET(i) + PAXB_0_DEFAULT_IMAP_AXUSER,
+ IMAP_AXUSER);
+ mmio_write_32(PAXB_OFFSET(i) + PAXB_0_DEFAULT_IMAP_AXCACHE,
+ IMAP_AXCACHE);
+
+ /* Configure MSI IMAP window */
+ mmio_setbits_32(PAXB_OFFSET(i) +
+ PAXB_IMAP0_REGS_TYPE_OFFSET,
+ 0x1);
+ mmio_write_32(PAXB_OFFSET(i) + PAXB_IARR0_BASE_OFFSET,
+ GITS_TRANSLATER | OARR_VALID);
+ for (j = 0; j < PAXB_MAX_IMAP_WINDOWS; j++) {
+ mmio_write_32(PAXB_OFFSET(i) + PAXB_IMAP0_OFFSET(j),
+ (GITS_TRANSLATER +
+ (j * PAXB_IMAP0_WINDOW_SIZE)) |
+ IMAP_VALID);
+ }
+ }
+}
+
+static void paxb_ib_regs_init(void)
+{
+ unsigned int core_idx;
+
+ for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) {
+ if (!pcie_core_needs_enable(core_idx))
+ continue;
+
+ /* initialize IARR2 to zero */
+ mmio_write_32(PAXB_OFFSET(core_idx) + PAXB_IARR2_LOWER_OFFSET,
+ 0x0);
+ mmio_setbits_32(PAXB_OFFSET(core_idx) +
+ PAXB_IMAP0_REGS_TYPE_OFFSET,
+ 0x1);
+ }
+}
+
+static void paxb_cfg_apb_timeout(void)
+{
+ unsigned int core_idx;
+
+ for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) {
+ if (!pcie_core_needs_enable(core_idx))
+ continue;
+
+ /* allow unlimited timeout */
+ mmio_write_32(PAXB_OFFSET(core_idx) +
+ PAXB_APB_TIMEOUT_COUNT_OFFSET,
+ 0xFFFFFFFF);
+ }
+}
+
+static void paxb_smmu_cfg(void)
+{
+ unsigned int core_idx;
+ uint32_t offset;
+ uint32_t val;
+
+ for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) {
+ if (!pcie_core_needs_enable(core_idx))
+ continue;
+
+ offset = core_idx * PCIE_CORE_PWR_OFFSET;
+ val = mmio_read_32(PCIE_PAXB_SMMU_SID_CFG + offset);
+ val &= ~(0xFFF00);
+ val |= (PAXB_SMMU_SID_CFG_FUN_WIDTH |
+ PAXB_SMMU_SID_CFG_DEV_WIDTH |
+ PAXB_SMMU_SID_CFG_BUS_WIDTH);
+ mmio_write_32(PCIE_PAXB_SMMU_SID_CFG + offset, val);
+ val = mmio_read_32(PCIE_PAXB_SMMU_SID_CFG + offset);
+ VERBOSE("smmu cfg reg 0x%x\n", val);
+ }
+}
+
+static void paxb_cfg_coherency(void)
+{
+ unsigned int i, j;
+
+ for (i = 0; i < paxb->num_cores; i++) {
+ if (!pcie_core_needs_enable(i))
+ continue;
+
+#ifdef USE_DDR
+ mmio_write_32(PAXB_OFFSET(i) + PAXB_IMAP2_OFFSET,
+ IMAP_ARCACHE | IMAP_AWCACHE);
+#endif
+
+ mmio_write_32(PAXB_OFFSET(i) + PAXB_IMAP0_0_AXUSER_OFFSET,
+ IMAP_AXUSER);
+
+ mmio_write_32(PAXB_OFFSET(i) + PAXB_IMAP2_AXUSER_OFFSET,
+ IMAP_AXUSER);
+
+ for (j = 0; j < PAXB_MAX_IMAP_WINDOWS; j++) {
+#ifdef USE_DDR
+ mmio_write_32(PAXB_OFFSET(i) + PAXB_IMAP3_OFFSET(j),
+ IMAP_ARCACHE | IMAP_AWCACHE);
+ mmio_write_32(PAXB_OFFSET(i) + PAXB_IMAP4_OFFSET(j),
+ IMAP_ARCACHE | IMAP_AWCACHE);
+#endif
+ /* zero out IMAP0 mapping windows for MSI/MSI-X */
+ mmio_write_32(PAXB_OFFSET(i) + PAXB_IMAP0_OFFSET(j),
+ 0x0);
+
+ mmio_write_32(PAXB_OFFSET(i) +
+ PAXB_IMAP3_0_AXUSER_OFFSET(j),
+ IMAP_AXUSER);
+ mmio_write_32(PAXB_OFFSET(i) +
+ PAXB_IMAP4_0_AXUSER_OFFSET(j),
+ IMAP_AXUSER);
+ }
+ }
+}
+
+/*
+ * This function configures all PAXB related blocks to allow non-secure access
+ */
+void paxb_ns_init(enum paxb_type type)
+{
+ unsigned int reg;
+
+ switch (type) {
+ case PAXB_SR:
+ for (reg = 0; reg < ARRAY_SIZE(paxb_sec_reg_offset); reg++) {
+
+ mmio_setbits_32(SR_PCIE_NIC_SECURITY_BASE +
+ paxb_sec_reg_offset[reg], 0x1);
+ }
+ /* Enabled all PAXB's relevant IDM blocks access in non-secure mode */
+ mmio_setbits_32(SR_PCIE_NIC_SECURITY_BASE + PAXB_SECURITY_IDM_OFFSET,
+ 0xffff);
+ break;
+ case PAXB_NS3Z:
+ mmio_setbits_32(NS3Z_PCIE_NIC_SECURITY_BASE +
+ paxb_sec_reg_offset[0], 0x1);
+ mmio_setbits_32(NS3Z_PCIE_NIC_SECURITY_BASE +
+ PAXB_SECURITY_IDM_OFFSET, 0xffff);
+ mmio_setbits_32(NS3Z_PCIE_NIC_SECURITY_BASE +
+ PAXB_SECURITY_APB_OFFSET, 0x7);
+ mmio_setbits_32(NS3Z_PCIE_NIC_SECURITY_BASE +
+ PAXB_SECURITY_ECAM_OFFSET, 0x1);
+ break;
+ }
+}
+
+static int paxb_set_config(void)
+{
+ paxb = paxb_get_config(sr);
+ if (paxb)
+ return 0;
+
+ return -ENODEV;
+}
+
+void paxb_init(void)
+{
+ int ret;
+
+ ret = paxb_set_config();
+ if (ret)
+ return;
+
+ paxb_ns_init(paxb->type);
+
+ ret = pcie_cores_init();
+ if (ret)
+ return;
+
+ if (paxb->phy_init) {
+ ret = paxb->phy_init();
+ if (ret)
+ return;
+ }
+
+ paxb_cfg_dev_id();
+ paxb_cfg_tgt_trn();
+ paxb_cfg_pdl_ctrl();
+ if (paxb->type == PAXB_SR) {
+ paxb_ib_regs_init();
+ paxb_cfg_coherency();
+ } else
+ paxb_ib_regs_bypass();
+
+ paxb_cfg_apb_timeout();
+ paxb_smmu_cfg();
+ paxb_cfg_clkreq();
+ paxb_rc_link_init();
+
+ /* Stingray Doesn't support LTR */
+ paxb_cfg_LTR(false);
+ paxb_cfg_dl_active(true);
+
+ paxb_cfg_mps();
+
+#ifdef PAXB_LINKUP
+ paxb_start_link_up();
+#endif
+ INFO("PAXB init done\n");
+}
diff --git a/plat/brcm/board/stingray/src/paxc.c b/plat/brcm/board/stingray/src/paxc.c
new file mode 100644
index 0000000..44af4b0
--- /dev/null
+++ b/plat/brcm/board/stingray/src/paxc.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <iommu.h>
+#include <platform_def.h>
+#include <sr_utils.h>
+
+#define PAXC_BASE 0x60400000
+#define PAXC_AXI_CFG_PF 0x10
+#define PAXC_AXI_CFG_PF_OFFSET(pf) (PAXC_AXI_CFG_PF + (pf) * 4)
+#define PAXC_ARPROT_PF_CFG 0x40
+#define PAXC_AWPROT_PF_CFG 0x44
+
+#define PAXC_ARQOS_PF_CFG 0x48
+#define PAXC_ARQOS_VAL 0xaaaaaaaa
+
+#define PAXC_AWQOS_PF_CFG 0x4c
+#define PAXC_AWQOS_VAL 0xeeeeeeee
+
+#define PAXC_CFG_IND_ADDR_OFFSET 0x1f0
+#define PAXC_CFG_IND_ADDR_MASK 0xffc
+#define PAXC_CFG_IND_DATA_OFFSET 0x1f4
+
+/* offsets for PAXC root complex configuration space registers */
+
+#define PAXC_CFG_ID_OFFSET 0x434
+#define PAXC_RC_VENDOR_ID 0x14e4
+#define PAXC_RC_VENDOR_ID_SHIFT 16
+
+#define PAXC_RC_DEVICE_ID 0xd750
+
+#define PAXC_CFG_LINK_CAP_OFFSET 0x4dc
+#define PAXC_RC_LINK_CAP_SPD_SHIFT 0
+#define PAXC_RC_LINK_CAP_SPD_MASK (0xf << PAXC_RC_LINK_CAP_SPD_SHIFT)
+#define PAXC_RC_LINK_CAP_SPD 3
+#define PAXC_RC_LINK_CAP_WIDTH_SHIFT 4
+#define PAXC_RC_LINK_CAP_WIDTH_MASK (0x1f << PAXC_RC_LINK_CAP_WIDTH_SHIFT)
+#define PAXC_RC_LINK_CAP_WIDTH 16
+
+/* offsets for MHB registers */
+
+#define MHB_BASE 0x60401000
+#define MHB_MEM_PWR_STATUS_PAXC (MHB_BASE + 0x1c0)
+#define MHB_PWR_ARR_POWERON 0x8
+#define MHB_PWR_ARR_POWEROK 0x4
+#define MHB_PWR_POWERON 0x2
+#define MHB_PWR_POWEROK 0x1
+#define MHB_PWR_STATUS_MASK (MHB_PWR_ARR_POWERON | \
+ MHB_PWR_ARR_POWEROK | \
+ MHB_PWR_POWERON | \
+ MHB_PWR_POWEROK)
+
+/* max number of PFs from Nitro that PAXC sees */
+#define MAX_NR_NITRO_PF 8
+
+#ifdef EMULATION_SETUP
+static void paxc_reg_dump(void)
+{
+}
+#else
+/* total number of PAXC registers */
+#define NR_PAXC_REGS 53
+static void paxc_reg_dump(void)
+{
+ uint32_t idx, offset = 0;
+
+ VERBOSE("PAXC register dump start\n");
+ for (idx = 0; idx < NR_PAXC_REGS; idx++, offset += 4)
+ VERBOSE("offset: 0x%x val: 0x%x\n", offset,
+ mmio_read_32(PAXC_BASE + offset));
+ VERBOSE("PAXC register dump end\n");
+}
+#endif /* EMULATION_SETUP */
+
+#ifdef EMULATION_SETUP
+static void mhb_reg_dump(void)
+{
+}
+#else
+#define NR_MHB_REGS 227
+static void mhb_reg_dump(void)
+{
+ uint32_t idx, offset = 0;
+
+ VERBOSE("MHB register dump start\n");
+ for (idx = 0; idx < NR_MHB_REGS; idx++, offset += 4)
+ VERBOSE("offset: 0x%x val: 0x%x\n", offset,
+ mmio_read_32(MHB_BASE + offset));
+ VERBOSE("MHB register dump end\n");
+}
+#endif /* EMULATION_SETUP */
+
+static void paxc_rc_cfg_write(uint32_t where, uint32_t val)
+{
+ mmio_write_32(PAXC_BASE + PAXC_CFG_IND_ADDR_OFFSET,
+ where & PAXC_CFG_IND_ADDR_MASK);
+ mmio_write_32(PAXC_BASE + PAXC_CFG_IND_DATA_OFFSET, val);
+}
+
+static uint32_t paxc_rc_cfg_read(uint32_t where)
+{
+ mmio_write_32(PAXC_BASE + PAXC_CFG_IND_ADDR_OFFSET,
+ where & PAXC_CFG_IND_ADDR_MASK);
+ return mmio_read_32(PAXC_BASE + PAXC_CFG_IND_DATA_OFFSET);
+}
+
+/*
+ * Function to program PAXC root complex link capability register
+ */
+static void paxc_cfg_link_cap(void)
+{
+ uint32_t val;
+
+ val = paxc_rc_cfg_read(PAXC_CFG_LINK_CAP_OFFSET);
+ val &= ~(PAXC_RC_LINK_CAP_SPD_MASK | PAXC_RC_LINK_CAP_WIDTH_MASK);
+ val |= (PAXC_RC_LINK_CAP_SPD << PAXC_RC_LINK_CAP_SPD_SHIFT) |
+ (PAXC_RC_LINK_CAP_WIDTH << PAXC_RC_LINK_CAP_WIDTH_SHIFT);
+ paxc_rc_cfg_write(PAXC_CFG_LINK_CAP_OFFSET, val);
+}
+
+/*
+ * Function to program PAXC root complex vendor ID and device ID
+ */
+static void paxc_cfg_id(void)
+{
+ uint32_t val;
+
+ val = (PAXC_RC_VENDOR_ID << PAXC_RC_VENDOR_ID_SHIFT) |
+ PAXC_RC_DEVICE_ID;
+ paxc_rc_cfg_write(PAXC_CFG_ID_OFFSET, val);
+}
+
+void paxc_init(void)
+{
+ unsigned int pf_index;
+ unsigned int val;
+
+ val = mmio_read_32(MHB_MEM_PWR_STATUS_PAXC);
+ if ((val & MHB_PWR_STATUS_MASK) != MHB_PWR_STATUS_MASK) {
+ INFO("PAXC not powered\n");
+ return;
+ }
+
+ paxc_cfg_id();
+ paxc_cfg_link_cap();
+
+ paxc_reg_dump();
+ mhb_reg_dump();
+
+#ifdef USE_DDR
+ /*
+ * Set AWCACHE and ARCACHE to 0xff (Cacheable write-back,
+ * allocate on both reads and writes) per
+ * recommendation from the ASIC team
+ */
+ val = 0xff;
+#else
+ /* disable IO cache if non-DDR memory is used, e.g., external SRAM */
+ val = 0x0;
+#endif
+ for (pf_index = 0; pf_index < MAX_NR_NITRO_PF; pf_index++)
+ mmio_write_32(PAXC_BASE + PAXC_AXI_CFG_PF_OFFSET(pf_index),
+ val);
+
+ /*
+ * Set ARPROT and AWPROT to enable non-secure access from
+ * PAXC to all PFs, PF0 to PF7
+ */
+ mmio_write_32(PAXC_BASE + PAXC_ARPROT_PF_CFG, 0x22222222);
+ mmio_write_32(PAXC_BASE + PAXC_AWPROT_PF_CFG, 0x22222222);
+
+ mmio_write_32(PAXC_BASE + PAXC_ARQOS_PF_CFG, PAXC_ARQOS_VAL);
+ mmio_write_32(PAXC_BASE + PAXC_AWQOS_PF_CFG, PAXC_AWQOS_VAL);
+
+ INFO("PAXC init done\n");
+}
+
+/*
+ * These defines do not match the regfile but they are renamed in a way such
+ * that they are much more readible
+ */
+
+#define MHB_NIC_SECURITY_BASE 0x60500000
+#define MHB_NIC_PAXC_AXI_NS 0x0008
+#define MHB_NIC_IDM_NS 0x000c
+#define MHB_NIC_MHB_APB_NS 0x0010
+#define MHB_NIC_NITRO_AXI_NS 0x0014
+#define MHB_NIC_PCIE_AXI_NS 0x0018
+#define MHB_NIC_PAXC_APB_NS 0x001c
+#define MHB_NIC_EP_APB_NS 0x0020
+
+#define MHB_NIC_PAXC_APB_S_IDM_SHIFT 5
+#define MHB_NIC_EP_APB_S_IDM_SHIFT 4
+#define MHB_NIC_MHB_APB_S_IDM_SHIFT 3
+#define MHB_NIC_PAXC_AXI_S_IDM_SHIFT 2
+#define MHB_NIC_PCIE_AXI_S_IDM_SHIFT 1
+#define MHB_NIC_NITRO_AXI_S_IDM_SHIFT 0
+
+#define NIC400_NITRO_TOP_NIC_SECURITY_BASE 0x60d00000
+
+#define NITRO_NIC_SECURITY_3_SHIFT 0x14
+#define NITRO_NIC_SECURITY_4_SHIFT 0x18
+#define NITRO_NIC_SECURITY_5_SHIFT 0x1c
+#define NITRO_NIC_SECURITY_6_SHIFT 0x20
+
+void paxc_mhb_ns_init(void)
+{
+ unsigned int val;
+ uintptr_t mhb_nic_gpv = MHB_NIC_SECURITY_BASE;
+#ifndef NITRO_SECURE_ACCESS
+ uintptr_t nic400_nitro_gpv = NIC400_NITRO_TOP_NIC_SECURITY_BASE;
+#endif /* NITRO_SECURE_ACCESS */
+
+ /* set PAXC AXI to allow non-secure access */
+ val = mmio_read_32(mhb_nic_gpv + MHB_NIC_PAXC_AXI_NS);
+ val |= 0x1;
+ mmio_write_32(mhb_nic_gpv + MHB_NIC_PAXC_AXI_NS, val);
+
+ /* set various MHB IDM interfaces to allow non-secure access */
+ val = mmio_read_32(mhb_nic_gpv + MHB_NIC_IDM_NS);
+ val |= (0x1 << MHB_NIC_PAXC_APB_S_IDM_SHIFT);
+ val |= (0x1 << MHB_NIC_EP_APB_S_IDM_SHIFT);
+ val |= (0x1 << MHB_NIC_MHB_APB_S_IDM_SHIFT);
+ val |= (0x1 << MHB_NIC_PAXC_AXI_S_IDM_SHIFT);
+ val |= (0x1 << MHB_NIC_PCIE_AXI_S_IDM_SHIFT);
+ val |= (0x1 << MHB_NIC_NITRO_AXI_S_IDM_SHIFT);
+ mmio_write_32(mhb_nic_gpv + MHB_NIC_IDM_NS, val);
+
+ /* set MHB APB to allow non-secure access */
+ val = mmio_read_32(mhb_nic_gpv + MHB_NIC_MHB_APB_NS);
+ val |= 0x1;
+ mmio_write_32(mhb_nic_gpv + MHB_NIC_MHB_APB_NS, val);
+
+ /* set Nitro AXI to allow non-secure access */
+ val = mmio_read_32(mhb_nic_gpv + MHB_NIC_NITRO_AXI_NS);
+ val |= 0x1;
+ mmio_write_32(mhb_nic_gpv + MHB_NIC_NITRO_AXI_NS, val);
+
+ /* set PCIe AXI to allow non-secure access */
+ val = mmio_read_32(mhb_nic_gpv + MHB_NIC_PCIE_AXI_NS);
+ val |= 0x1;
+ mmio_write_32(mhb_nic_gpv + MHB_NIC_PCIE_AXI_NS, val);
+
+ /* set PAXC APB to allow non-secure access */
+ val = mmio_read_32(mhb_nic_gpv + MHB_NIC_PAXC_APB_NS);
+ val |= 0x1;
+ mmio_write_32(mhb_nic_gpv + MHB_NIC_PAXC_APB_NS, val);
+
+ /* set EP APB to allow non-secure access */
+ val = mmio_read_32(mhb_nic_gpv + MHB_NIC_EP_APB_NS);
+ val |= 0x1;
+ mmio_write_32(mhb_nic_gpv + MHB_NIC_EP_APB_NS, val);
+
+#ifndef NITRO_SECURE_ACCESS
+ /* Set NIC400 to allow non-secure access */
+ mmio_setbits_32(nic400_nitro_gpv + NITRO_NIC_SECURITY_3_SHIFT, 0x1);
+ mmio_setbits_32(nic400_nitro_gpv + NITRO_NIC_SECURITY_4_SHIFT, 0x1);
+ mmio_setbits_32(nic400_nitro_gpv + NITRO_NIC_SECURITY_5_SHIFT, 0x1);
+ mmio_setbits_32(nic400_nitro_gpv + NITRO_NIC_SECURITY_6_SHIFT, 0x1);
+#endif /* NITRO_SECURE_ACCESS */
+}
diff --git a/plat/brcm/board/stingray/src/pm.c b/plat/brcm/board/stingray/src/pm.c
new file mode 100644
index 0000000..a5ac2e7
--- /dev/null
+++ b/plat/brcm/board/stingray/src/pm.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2015 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/ccn.h>
+#include <drivers/delay_timer.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <lib/spinlock.h>
+#include <plat/common/platform.h>
+
+#ifdef USE_PAXC
+#include <chimp.h>
+#endif
+#include <cmn_plat_util.h>
+#include <ihost_pm.h>
+#include <plat_brcm.h>
+#include <platform_def.h>
+
+static uint64_t plat_sec_entrypoint;
+
+/*******************************************************************************
+ * SR handler called when a power domain is about to be turned on. The
+ * mpidr determines the CPU to be turned on.
+ ******************************************************************************/
+static int brcm_pwr_domain_on(u_register_t mpidr)
+{
+ int cpuid;
+
+ cpuid = plat_brcm_calc_core_pos(mpidr);
+ INFO("mpidr :%lu, cpuid:%d\n", mpidr, cpuid);
+
+#ifdef USE_SINGLE_CLUSTER
+ if (cpuid > 1)
+ return PSCI_E_INTERN_FAIL;
+#endif
+
+ ihost_power_on_cluster(mpidr);
+
+ ihost_power_on_secondary_core(mpidr, plat_sec_entrypoint);
+
+ return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * SR 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 brcm_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ unsigned long cluster_id = MPIDR_AFFLVL1_VAL(read_mpidr());
+
+ assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
+ PLAT_LOCAL_STATE_OFF);
+
+ if (target_state->pwr_domain_state[MPIDR_AFFLVL1] ==
+ PLAT_LOCAL_STATE_OFF) {
+ INFO("Cluster #%lu entering to snoop/dvm domain\n", cluster_id);
+ ccn_enter_snoop_dvm_domain(1 << cluster_id);
+ }
+
+ /* Enable the gic cpu interface */
+ plat_brcm_gic_pcpu_init();
+
+ /* Program the gic per-cpu distributor or re-distributor interface */
+ plat_brcm_gic_cpuif_enable();
+
+ INFO("Gic Initialization done for this affinity instance\n");
+}
+
+static void __dead2 brcm_system_reset(void)
+{
+ uint32_t reset_type = SOFT_SYS_RESET_L1;
+
+#ifdef USE_PAXC
+ if (bcm_chimp_is_nic_mode())
+ reset_type = SOFT_RESET_L3;
+#endif
+ INFO("System rebooting - L%d...\n", reset_type);
+
+ plat_soft_reset(reset_type);
+
+ /* Prevent the function to return due to the attribute */
+ while (1)
+ ;
+}
+
+static int brcm_system_reset2(int is_vendor, int reset_type,
+ u_register_t cookie)
+{
+ INFO("System rebooting - L%d...\n", reset_type);
+
+ plat_soft_reset(reset_type);
+
+ /*
+ * plat_soft_reset cannot return (it is a __dead function),
+ * but brcm_system_reset2 has to return some value, even in
+ * this case.
+ */
+ return 0;
+}
+
+/*******************************************************************************
+ * Export the platform handlers via plat_brcm_psci_pm_ops. The ARM Standard
+ * platform will take care of registering the handlers with PSCI.
+ ******************************************************************************/
+const plat_psci_ops_t plat_brcm_psci_pm_ops = {
+ .pwr_domain_on = brcm_pwr_domain_on,
+ .pwr_domain_on_finish = brcm_pwr_domain_on_finish,
+ .system_reset = brcm_system_reset,
+ .system_reset2 = brcm_system_reset2
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const plat_psci_ops_t **psci_ops)
+{
+ *psci_ops = &plat_brcm_psci_pm_ops;
+ plat_sec_entrypoint = sec_entrypoint;
+
+ return 0;
+}
diff --git a/plat/brcm/board/stingray/src/scp_cmd.c b/plat/brcm/board/stingray/src/scp_cmd.c
new file mode 100644
index 0000000..2aa9519
--- /dev/null
+++ b/plat/brcm/board/stingray/src/scp_cmd.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <drivers/delay_timer.h>
+
+#include <platform_def.h>
+#include <scp.h>
+#include <scp_cmd.h>
+
+#include "m0_ipc.h"
+
+/*
+ * Reads a response from CRMU MAILBOX
+ * Assumes that access has been granted and locked.
+ * Note that this is just a temporary implementation until
+ * channels are introduced
+ */
+static void scp_read_response(crmu_response_t *resp)
+{
+ uint32_t code;
+
+ code = mmio_read_32(CRMU_MAIL_BOX0);
+ resp->completed = code & MCU_IPC_CMD_DONE_MASK;
+ resp->cmd = code & SCP_CMD_MASK;
+ resp->ret = (code & MCU_IPC_CMD_REPLY_MASK) >> MCU_IPC_CMD_REPLY_SHIFT;
+}
+
+/*
+ * Send a command to SCP and wait for timeout us.
+ * Return: 0 on success
+ * -1 if there was no proper reply from SCP
+ * >0 if there was a response from MCU, but
+ * command completed with an error.
+ */
+int scp_send_cmd(uint32_t cmd, uint32_t param, uint32_t timeout)
+{
+ int ret = -1;
+
+ mmio_write_32(CRMU_MAIL_BOX0, cmd);
+ mmio_write_32(CRMU_MAIL_BOX1, param);
+ do {
+ crmu_response_t scp_resp;
+
+ udelay(1);
+ scp_read_response(&scp_resp);
+ if (scp_resp.completed &&
+ (scp_resp.cmd == cmd)) {
+ /* This command has completed */
+ ret = scp_resp.ret;
+ break;
+ }
+ } while (--timeout);
+
+ return ret;
+}
diff --git a/plat/brcm/board/stingray/src/scp_utils.c b/plat/brcm/board/stingray/src/scp_utils.c
new file mode 100644
index 0000000..1d82cef
--- /dev/null
+++ b/plat/brcm/board/stingray/src/scp_utils.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2017-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+
+#include <bcm_elog_ddr.h>
+#include <brcm_mhu.h>
+#include <brcm_scpi.h>
+#include <chimp.h>
+#include <cmn_plat_util.h>
+#include <ddr_init.h>
+#include <scp.h>
+#include <scp_cmd.h>
+#include <scp_utils.h>
+
+#include "m0_cfg.h"
+#include "m0_ipc.h"
+
+#ifdef BCM_ELOG
+static void prepare_elog(void)
+{
+#if (CLEAN_DDR && !defined(MMU_DISABLED))
+ /*
+ * Now DDR has been initialized. We want to copy all the logs in SRAM
+ * into DDR so we will have much more space to store the logs in the
+ * next boot stage
+ */
+ bcm_elog_copy_log((void *)BCM_ELOG_BL31_BASE,
+ MIN(BCM_ELOG_BL2_SIZE, BCM_ELOG_BL31_SIZE)
+ );
+
+ /*
+ * We are almost at the end of BL2, and we can stop log here so we do
+ * not need to add 'bcm_elog_exit' to the standard BL2 code. The
+ * benefit of capturing BL2 logs after this is very minimal in a
+ * production system.
+ */
+ bcm_elog_exit();
+#endif
+
+ /*
+ * Notify CRMU that now it should pull logs from DDR instead of from
+ * FS4 SRAM.
+ */
+ SCP_WRITE_CFG(flash_log.can_use_ddr, 1);
+}
+#endif
+
+bool is_crmu_alive(void)
+{
+ return (scp_send_cmd(MCU_IPC_MCU_CMD_NOP, 0, SCP_CMD_DEFAULT_TIMEOUT_US)
+ == 0);
+}
+
+bool bcm_scp_issue_sys_reset(void)
+{
+ return (scp_send_cmd(MCU_IPC_MCU_CMD_L1_RESET, 0,
+ SCP_CMD_DEFAULT_TIMEOUT_US));
+}
+
+/*
+ * Note that this is just a temporary implementation until
+ * channels are introduced
+ */
+
+int plat_bcm_bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info)
+{
+ int scp_patch_activated, scp_patch_version;
+#ifndef EMULATION_SETUP
+ uint8_t active_ch_bitmap, i;
+#endif
+ uint32_t reset_state = 0;
+ uint32_t mcu_ap_init_param = 0;
+
+ /*
+ * First check if SCP patch has already been loaded
+ * Send NOP command and see if there is a valid response
+ */
+ scp_patch_activated =
+ (scp_send_cmd(MCU_IPC_MCU_CMD_NOP, 0,
+ SCP_CMD_DEFAULT_TIMEOUT_US) == 0);
+ if (scp_patch_activated) {
+ INFO("SCP Patch is already active.\n");
+
+ reset_state = SCP_READ_CFG(board_cfg.reset_state);
+ mcu_ap_init_param = SCP_READ_CFG(board_cfg.mcu_init_param);
+
+ /* Clear reset state, it's been already read */
+ SCP_WRITE_CFG(board_cfg.reset_state, 0);
+
+ if (mcu_ap_init_param & MCU_PATCH_LOADED_BY_NITRO) {
+ /*
+ * Reset "MCU_PATCH_LOADED_BY_NITRO" flag, but
+ * Preserve any other flags we don't deal with here
+ */
+ INFO("AP booted by Nitro\n");
+ SCP_WRITE_CFG(
+ board_cfg.mcu_init_param,
+ mcu_ap_init_param &
+ ~MCU_PATCH_LOADED_BY_NITRO
+ );
+ }
+ } else {
+ /*
+ * MCU Patch not loaded, so load it.
+ * MCU patch stamps critical points in REG9 (debug test-point)
+ * Display its last content here. This helps to locate
+ * where crash occurred if a CRMU watchdog kicked in.
+ */
+ int ret;
+
+ INFO("MCU Patch Point: 0x%x\n",
+ mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG9));
+
+ ret = download_scp_patch((void *)scp_bl2_image_info->image_base,
+ scp_bl2_image_info->image_size);
+ if (ret != 0)
+ return ret;
+
+ VERBOSE("SCP Patch loaded OK.\n");
+
+ ret = scp_send_cmd(MCU_IPC_MCU_CMD_INIT,
+ MCU_PATCH_LOADED_BY_AP,
+ SCP_CMD_SCP_BOOT_TIMEOUT_US);
+ if (ret) {
+ ERROR("SCP Patch could not initialize; error %d\n",
+ ret);
+ return ret;
+ }
+
+ INFO("SCP Patch successfully initialized.\n");
+ }
+
+ scp_patch_version = scp_send_cmd(MCU_IPC_MCU_CMD_GET_FW_VERSION, 0,
+ SCP_CMD_DEFAULT_TIMEOUT_US);
+ INFO("SCP Patch version :0x%x\n", scp_patch_version);
+
+ /* Next block just reports current AVS voltages (if applicable) */
+ {
+ uint16_t vcore_mv, ihost03_mv, ihost12_mv;
+
+ vcore_mv = SCP_READ_CFG16(vcore.millivolts) +
+ SCP_READ_CFG8(vcore.avs_cfg.additive_margin);
+ ihost03_mv = SCP_READ_CFG16(ihost03.millivolts) +
+ SCP_READ_CFG8(ihost03.avs_cfg.additive_margin);
+ ihost12_mv = SCP_READ_CFG16(ihost12.millivolts) +
+ SCP_READ_CFG8(ihost12.avs_cfg.additive_margin);
+
+ if (vcore_mv || ihost03_mv || ihost12_mv) {
+ INFO("AVS voltages from cfg (including margin)\n");
+ if (vcore_mv > 0)
+ INFO("%s\tVCORE: %dmv\n",
+ SCP_READ_CFG8(vcore.avs_cfg.avs_set) ?
+ "*" : "n/a", vcore_mv);
+ if (ihost03_mv > 0)
+ INFO("%s\tIHOST03: %dmv\n",
+ SCP_READ_CFG8(ihost03.avs_cfg.avs_set) ?
+ "*" : "n/a", ihost03_mv);
+ if (ihost12_mv > 0)
+ INFO("%s\tIHOST12: %dmv\n",
+ SCP_READ_CFG8(ihost12.avs_cfg.avs_set) ?
+ "*" : "n/a", ihost12_mv);
+ } else {
+ INFO("AVS settings not applicable\n");
+ }
+ }
+
+#if (CLEAN_DDR && !defined(MMU_DISABLED) && !defined(EMULATION_SETUP))
+ /* This will clean the DDR and enable ECC if set */
+ check_ddr_clean();
+#endif
+
+#if (WARMBOOT_DDR_S3_SUPPORT && ELOG_STORE_MEDIA_DDR)
+ elog_init_ddr_log();
+#endif
+
+#ifdef BCM_ELOG
+ /* Prepare ELOG to use DDR */
+ prepare_elog();
+#endif
+
+#ifndef EMULATION_SETUP
+ /* Ask ddr_init to save obtained DDR information into DDR */
+ ddr_info_save();
+#endif
+
+ /*
+ * Configure TMON DDR address.
+ * This cfg is common for all cases
+ */
+ SCP_WRITE_CFG(tmon_cfg.ddr_desc, TMON_SHARED_DDR_ADDRESS);
+
+ if (reset_state == SOFT_RESET_L3 && !mcu_ap_init_param) {
+ INFO("SCP configuration after L3 RESET done.\n");
+ return 0;
+ }
+
+ if (bcm_chimp_is_nic_mode())
+ /* Configure AP WDT to not reset the NIC interface */
+ SCP_WRITE_CFG(board_cfg.apwdt_reset_type, SOFT_RESET_L3);
+
+#if (WARMBOOT_DDR_S3_SUPPORT && ELOG_STORE_MEDIA_DDR)
+ /* When AP WDog triggers perform L3 reset if DDR err logging enabled */
+ SCP_WRITE_CFG(board_cfg.apwdt_reset_type, SOFT_RESET_L3);
+#endif
+
+#ifndef EMULATION_SETUP
+
+#ifdef DDR_SCRUB_ENA
+ ddr_scrub_enable();
+#endif
+ /* Fill the Active channel information */
+ active_ch_bitmap = get_active_ddr_channel();
+ for (i = 0; i < MAX_NR_DDR_CH; i++)
+ SCP_WRITE_CFG(ddr_cfg.ddr_cfg[i],
+ (active_ch_bitmap & BIT(i)) ? 1 : 0);
+#endif
+ return 0;
+}
diff --git a/plat/brcm/board/stingray/src/sdio.c b/plat/brcm/board/stingray/src/sdio.c
new file mode 100644
index 0000000..aa2b71a
--- /dev/null
+++ b/plat/brcm/board/stingray/src/sdio.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <sdio.h>
+#include <sr_def.h>
+#include <sr_utils.h>
+
+const SDIO_CFG sr_sdio0_cfg = {
+ .cfg_base = SR_IPROC_SDIO0_CFG_BASE,
+ .sid_base = SR_IPROC_SDIO0_SID_BASE,
+ .io_ctrl_base = SR_IPROC_SDIO0_IOCTRL_BASE,
+ .pad_base = SR_IPROC_SDIO0_PAD_BASE,
+};
+const SDIO_CFG sr_sdio1_cfg = {
+ .cfg_base = SR_IPROC_SDIO1_CFG_BASE,
+ .sid_base = SR_IPROC_SDIO1_SID_BASE,
+ .io_ctrl_base = SR_IPROC_SDIO1_IOCTRL_BASE,
+ .pad_base = SR_IPROC_SDIO1_PAD_BASE,
+};
+
+void brcm_stingray_sdio_init(void)
+{
+ unsigned int val;
+ const SDIO_CFG *sdio0_cfg, *sdio1_cfg;
+
+ sdio0_cfg = &sr_sdio0_cfg;
+ sdio1_cfg = &sr_sdio1_cfg;
+
+ INFO("set sdio0 caps\n");
+ /* SDIO0 CAPS0 */
+ val = SDIO0_CAP0_CFG;
+ INFO("caps0 0x%x\n", val);
+ mmio_write_32(sdio0_cfg->cfg_base + ICFG_SDIO_CAP0, val);
+
+ /* SDIO0 CAPS1 */
+ val = SDIO0_CAP1_CFG;
+ INFO("caps1 0x%x\n", val);
+ mmio_write_32(sdio0_cfg->cfg_base + ICFG_SDIO_CAP1, val);
+
+ mmio_write_32(sdio0_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_0,
+ SDIO_PRESETVAL0);
+ mmio_write_32(sdio0_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_1,
+ SDIO_PRESETVAL1);
+ mmio_write_32(sdio0_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_2,
+ SDIO_PRESETVAL2);
+ mmio_write_32(sdio0_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_3,
+ SDIO_PRESETVAL3);
+ mmio_write_32(sdio0_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_4,
+ SDIO_PRESETVAL4);
+
+ val = SR_SID_VAL(0x3, 0x0, 0x2) << SDIO_SID_SHIFT;
+ mmio_write_32(sdio0_cfg->sid_base + ICFG_SDIO_SID_ARADDR, val);
+ mmio_write_32(sdio0_cfg->sid_base + ICFG_SDIO_SID_AWADDR, val);
+
+ val = mmio_read_32(sdio0_cfg->io_ctrl_base);
+ val &= ~(0xff << 23); /* Clear ARCACHE and AWCACHE */
+ val |= (0xb7 << 23); /* Set ARCACHE and AWCACHE */
+ mmio_write_32(sdio0_cfg->io_ctrl_base, val);
+
+ mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_CLK,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+ mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_DATA0,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+ mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_DATA1,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+ mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_DATA2,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+ mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_DATA3,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+ mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_DATA4,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+ mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_DATA5,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+ mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_DATA6,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+ mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_DATA7,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+ mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_CMD,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+
+ INFO("set sdio1 caps\n");
+
+ /* SDIO1 CAPS0 */
+ val = SDIO1_CAP0_CFG;
+ INFO("caps0 0x%x\n", val);
+ mmio_write_32(sdio1_cfg->cfg_base + ICFG_SDIO_CAP0, val);
+ /* SDIO1 CAPS1 */
+ val = SDIO1_CAP1_CFG;
+ INFO("caps1 0x%x\n", val);
+ mmio_write_32(sdio1_cfg->cfg_base + ICFG_SDIO_CAP1, val);
+
+ mmio_write_32(sdio1_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_0,
+ SDIO_PRESETVAL0);
+ mmio_write_32(sdio1_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_1,
+ SDIO_PRESETVAL1);
+ mmio_write_32(sdio1_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_2,
+ SDIO_PRESETVAL2);
+ mmio_write_32(sdio1_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_3,
+ SDIO_PRESETVAL3);
+ mmio_write_32(sdio1_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_4,
+ SDIO_PRESETVAL4);
+
+ val = SR_SID_VAL(0x3, 0x0, 0x3) << SDIO_SID_SHIFT;
+ mmio_write_32(sdio1_cfg->sid_base + ICFG_SDIO_SID_ARADDR, val);
+ mmio_write_32(sdio1_cfg->sid_base + ICFG_SDIO_SID_AWADDR, val);
+
+ val = mmio_read_32(sdio1_cfg->io_ctrl_base);
+ val &= ~(0xff << 23); /* Clear ARCACHE and AWCACHE */
+ val |= (0xb7 << 23); /* Set ARCACHE and AWCACHE */
+ mmio_write_32(sdio1_cfg->io_ctrl_base, val);
+
+ mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_CLK,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+ mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_DATA0,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+ mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_DATA1,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+ mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_DATA2,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+ mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_DATA3,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+ mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_DATA4,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+ mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_DATA5,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+ mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_DATA6,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+ mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_DATA7,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+ mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_CMD,
+ PAD_SDIO_MASK, PAD_SDIO_VALUE);
+
+ INFO("sdio init done\n");
+}
diff --git a/plat/brcm/board/stingray/src/sr_paxb_phy.c b/plat/brcm/board/stingray/src/sr_paxb_phy.c
new file mode 100644
index 0000000..7380e09
--- /dev/null
+++ b/plat/brcm/board/stingray/src/sr_paxb_phy.c
@@ -0,0 +1,806 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <paxb.h>
+#include <sr_def.h>
+#include <sr_utils.h>
+
+/* total number of PCIe Phys */
+#define NUM_OF_PCIE_SERDES 8
+
+#define CFG_RC_PMI_ADDR 0x1130
+#define PMI_RX_TERM_SEQ ((0x1 << 27) | (0x1ff << 16) | (0xd090))
+#define PMI_RX_TERM_VAL 0x4c00
+#define PMI_PLL_CTRL_4 0xd0b4
+#define PMI_SERDES_CLK_ENABLE (1 << 12)
+
+#define WAR_PLX_PRESET_PARITY_FAIL
+
+#define CFG_RC_REG_PHY_CTL_10 0x1838
+#define PHY_CTL_10_GEN3_MATCH_PARITY (1 << 15)
+
+#define PMI_X8_CORE0_7_PATCH_SEQ ((0x1 << 27) | (0x1ff << 16) | (0xd2a5))
+#define PMI_X8_CORE0_7_PATCH_VAL 0xd864
+
+#define PMI_ADDR_BCAST(addr) ((0x1 << 27) | (0x1ff << 16) | (addr))
+#define PMI_ADDR_LANE0(addr) ((0x1 << 27) | (addr))
+#define PMI_ADDR_LANE1(addr) ((0x1 << 27) | (0x1 << 16) | (addr))
+
+#define MERLIN16_PCIE_BLK2_PWRMGMT_7 ((0x1 << 27) | (0x1ff << 16) | 0x1208)
+#define MERLIN16_PCIE_BLK2_PWRMGMT_8 ((0x1 << 27) | (0x1ff << 16) | 0x1209)
+#define MERLIN16_AMS_TX_CTRL_5 ((0x1 << 27) | (0x1ff << 16) | 0xd0a5)
+#define MERLIN16_AMS_TX_CTRL_5_VAL \
+ ((1 << 13) | (1 << 12) | (1 << 11) | (1 << 10))
+#define MERLIN16_PCIE_BLK2_PWRMGMT_7_VAL 0x96
+#define MERLIN16_PCIE_BLK2_PWRMGMT_8_VAL 0x12c
+
+#define CFG_RC_PMI_WDATA 0x1134
+#define CFG_RC_WCMD_SHIFT 31
+#define CFG_RC_WCMD_MASK ((uint32_t)1U << CFG_RC_WCMD_SHIFT)
+#define CFG_RC_RCMD_SHIFT 30
+#define CFG_RC_RCMD_MASK ((uint32_t)1U << CFG_RC_RCMD_SHIFT)
+#define CFG_RC_RWCMD_MASK (CFG_RC_RCMD_MASK | CFG_RC_WCMD_MASK)
+#define CFG_RC_PMI_RDATA 0x1138
+#define CFG_RC_RACK_SHIFT 31
+#define CFG_RC_RACK_MASK ((uint32_t)1U << CFG_RC_RACK_SHIFT)
+
+/* allow up to 5 ms for PMI write to finish */
+#define PMI_TIMEOUT_MS 5
+
+/* in 2x8 RC mode, one needs to patch up Serdes 3 and 7 for link to come up */
+#define SERDES_PATCH_PIPEMUX_INDEX 0x3
+#define SERDES_PATCH_INDEX 0x8
+
+#define DSC_UC_CTRL 0xd00d
+#define DSC_UC_CTRL_RDY_CMD (1 << 7)
+#define LANE_DBG_RST_CTRL 0xd164
+#define UC_A_CLK_CTRL0 0xd200
+#define UC_A_RST_CTRL0 0xd201
+#define UC_A_AHB_CTRL0 0xd202
+#define UC_A_AHB_STAT0 0xd203
+#define UC_A_AHB_WADDR_LSW 0xd204
+#define UC_A_AHB_WADDR_MSW 0xd205
+#define UC_A_AHB_WDATA_LSW 0xd206
+#define UC_A_AHB_WDATA_MSW 0xd207
+#define UC_A_AHB_RADDR_LSW 0xd208
+#define UC_A_AHB_RADDR_MSW 0xd209
+#define UC_A_AHB_RDATA_LSW 0xd20a
+#define UC_A_AHB_RDATA_MSW 0xd20b
+#define UC_VERSION_NUM 0xd230
+#define DSC_SM_CTL22 0xd267
+#define UC_DBG1 0xd251
+
+#define LOAD_UC_CHECK 0
+#define UC_RAM_INIT_TIMEOUT 100
+#define UC_RAM_CONTROL 0xd225
+#define UC_INIT_TIMEOUT 100
+#define SIZE_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
+#define SZ_4 4
+#define GET_2_BYTES(p, i) ((uint16_t)p[i] | (uint16_t)p[i+1] << 8)
+
+/*
+ * List of PCIe LCPLL related registers
+ *
+ * LCPLL channel 0 provides the Serdes pad clock when running in RC mode
+ */
+#define PCIE_LCPLL_BASE 0x40000000
+
+#define PCIE_LCPLL_CTRL0_OFFSET 0x00
+#define PCIE_LCPLL_RESETB_SHIFT 31
+#define PCIE_LCPLL_RESETB_MASK BIT(PCIE_LCPLL_RESETB_SHIFT)
+#define PCIE_LCPLL_P_RESETB_SHIFT 30
+#define PCIE_LCPLL_P_RESETB_MASK BIT(PCIE_LCPLL_P_RESETB_SHIFT)
+
+#define PCIE_LCPLL_CTRL3_OFFSET 0x0c
+#define PCIE_LCPLL_EN_CTRL_SHIFT 16
+#define PCIE_LCPLL_CM_ENA 0x1a
+#define PCIE_LCPLL_CM_BUF_ENA 0x18
+#define PCIE_LCPLL_D2C2_ENA 0x2
+#define PCIE_LCPLL_REF_CLK_SHIFT 1
+#define PCIE_LCPLL_REF_CLK_MASK BIT(PCIE_LCPLL_REF_CLK_SHIFT)
+#define PCIE_LCPLL_CTRL13_OFFSET 0x34
+#define PCIE_LCPLL_D2C2_CTRL_SHIFT 16
+#define PCIE_LCPLL_D2C2_TERM_DISC 0xe0
+
+#define PCIE_LCPLL_STATUS_OFFSET 0x40
+#define PCIE_LCPLL_LOCK_SHIFT 12
+#define PCIE_LCPLL_LOCK_MASK BIT(PCIE_LCPLL_LOCK_SHIFT)
+
+#define PCIE_PIPE_MUX_RC_MODE_OVERRIDE_CFG 0x114
+#define PCIE_TX_CLKMASTER_CTRL_OVERRIDE_CFG 0x11c
+
+/* wait 500 microseconds for PCIe LCPLL to power up */
+#define PCIE_LCPLL_DELAY_US 500
+
+/* allow up to 5 ms for PCIe LCPLL VCO to lock */
+#define PCIE_LCPLL_TIMEOUT_MS 5
+
+#define PCIE_PIPE_MUX_CONFIGURATION_CFG 0x4000010c
+
+#define PCIE_PIPEMUX_SHIFT 19
+#define PCIE_PIPEMUX_MASK 0xf
+
+/* keep track of PIPEMUX index to use */
+static unsigned int pipemux_idx;
+
+/*
+ * PCIe PIPEMUX lookup table
+ *
+ * Each array index represents a PIPEMUX strap setting
+ * The array element represents a bitmap where a set bit means the PCIe core
+ * needs to be enabled as RC
+ */
+static uint8_t pipemux_table[] = {
+ /* PIPEMUX = 0, EP 1x16 */
+ 0x00,
+ /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */
+ 0x80,
+ /* PIPEMUX = 2, EP 4x4 */
+ 0x00,
+ /* PIPEMUX = 3, RC 2x8, cores 0, 7 */
+ 0x81,
+ /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */
+ 0xc3,
+ /* PIPEMUX = 5, RC 8x2, all 8 cores */
+ 0xff,
+ /* PIPEMUX = 6, RC 3x4 + 2x2, cores 0, 2, 3, 6, 7 */
+ 0xcd,
+ /* PIPEMUX = 7, RC 1x4 + 6x2, cores 0, 2, 3, 4, 5, 6, 7 */
+ 0xfd,
+ /* PIPEMUX = 8, EP 1x8 + RC 4x2, cores 4, 5, 6, 7 */
+ 0xf0,
+ /* PIPEMUX = 9, EP 1x8 + RC 2x4, cores 6, 7 */
+ 0xc0,
+ /* PIPEMUX = 10, EP 2x4 + RC 2x4, cores 1, 6 */
+ 0x42,
+ /* PIPEMUX = 11, EP 2x4 + RC 4x2, cores 2, 3, 4, 5 */
+ 0x3c,
+ /* PIPEMUX = 12, EP 1x4 + RC 6x2, cores 2, 3, 4, 5, 6, 7 */
+ 0xfc,
+ /* PIPEMUX = 13, RC 2x4 + RC 1x4 + 2x2, cores 2, 3, 6 */
+ 0x4c,
+};
+
+/*
+ * Return 1 if pipemux strap is supported
+ */
+static int pipemux_strap_is_valid(uint32_t pipemux)
+{
+ if (pipemux < ARRAY_SIZE(pipemux_table))
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * Read the PCIe PIPEMUX from strap
+ */
+static uint32_t pipemux_strap_read(void)
+{
+ uint32_t pipemux;
+
+ pipemux = mmio_read_32(PCIE_PIPE_MUX_CONFIGURATION_CFG);
+ pipemux &= PCIE_PIPEMUX_MASK;
+ if (pipemux == PCIE_PIPEMUX_MASK) {
+ /* read the PCIe PIPEMUX strap setting */
+ pipemux = mmio_read_32(CDRU_CHIP_STRAP_DATA_LSW);
+ pipemux >>= PCIE_PIPEMUX_SHIFT;
+ pipemux &= PCIE_PIPEMUX_MASK;
+ }
+
+ return pipemux;
+}
+
+/*
+ * Store the PIPEMUX index (set for each boot)
+ */
+static void pipemux_save_index(unsigned int idx)
+{
+ pipemux_idx = idx;
+}
+
+static int paxb_sr_core_needs_enable(unsigned int core_idx)
+{
+ return !!((pipemux_table[pipemux_idx] >> core_idx) & 0x1);
+}
+
+static int pipemux_sr_init(void)
+{
+ uint32_t pipemux;
+
+ /* read the PCIe PIPEMUX strap setting */
+ pipemux = pipemux_strap_read();
+ if (!pipemux_strap_is_valid(pipemux)) {
+ ERROR("Invalid PCIe PIPEMUX strap %u\n", pipemux);
+ return -EIO;
+ }
+
+ /* no PCIe RC is needed */
+ if (!pipemux_table[pipemux]) {
+ WARN("PIPEMUX indicates no PCIe RC required\n");
+ return -ENODEV;
+ }
+
+ /* save the PIPEMUX strap */
+ pipemux_save_index(pipemux);
+
+ return 0;
+}
+
+/*
+ * PCIe RC serdes link width
+ *
+ * The array is first organized in rows as indexed by the PIPEMUX setting.
+ * Within each row, eight lane width entries are specified -- one entry
+ * per PCIe core, from 0 to 7.
+ *
+ * Note: The EP lanes/cores are not mapped in this table! EP cores are
+ * controlled and thus configured by Nitro.
+ */
+static uint8_t link_width_table[][NUM_OF_SR_PCIE_CORES] = {
+ /* PIPEMUX = 0, EP 1x16 */
+ {0, 0, 0, 0, 0, 0, 0, 0},
+ /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */
+ {0, 0, 0, 0, 0, 0, 0, 8},
+ /* PIPEMUX = 2, EP 4x4 */
+ {0, 0, 0, 0, 0, 0, 0, 0},
+ /* PIPEMUX = 3, RC 2x8, cores 0, 7 */
+ {8, 0, 0, 0, 0, 0, 0, 8},
+ /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */
+ {4, 4, 0, 0, 0, 0, 4, 4},
+ /* PIPEMUX = 5, RC 8x2, all 8 cores */
+ {2, 2, 2, 2, 2, 2, 2, 2},
+ /* PIPEMUX = 6, RC 3x4 (cores 0, 6, 7), RC 2x2 (cores 2, 3) */
+ {4, 0, 2, 2, 0, 0, 4, 4},
+ /* PIPEMUX = 7, RC 1x4 (core 0), RC 6x2 (cores 2, 3, 4, 5, 6, 7 */
+ {4, 0, 2, 2, 2, 2, 2, 2},
+ /* PIPEMUX = 8, EP 1x8 + RC 4x2 (cores 4, 5, 6, 7) */
+ {0, 0, 0, 0, 2, 2, 2, 2},
+ /* PIPEMUX = 9, EP 1x8 + RC 2x4 (cores 6, 7) */
+ {0, 0, 0, 0, 0, 0, 4, 4},
+ /* PIPEMUX = 10, EP 2x4 + RC 2x4 (cores 1, 6) */
+ {0, 4, 0, 0, 0, 0, 4, 0},
+ /* PIPEMUX = 11, EP 2x4 + RC 4x2 (cores 2, 3, 4, 5) */
+ {0, 0, 2, 2, 2, 2, 0, 0},
+ /* PIPEMUX = 12, EP 1x4 + RC 6x2 (cores 2, 3, 4, 5, 6, 7) */
+ {0, 0, 2, 2, 2, 2, 2, 2},
+ /* PIPEMUX = 13, EP 2x4 + RC 1x4 (core 6) + RC 2x2 (cores 2, 3) */
+ {0, 0, 2, 2, 0, 0, 4, 0}
+};
+
+/*
+ * function for writes to the Serdes registers through the PMI interface
+ */
+static int paxb_pmi_write(unsigned int core_idx, uint32_t pmi, uint32_t val)
+{
+ uint32_t status;
+ unsigned int timeout = PMI_TIMEOUT_MS;
+
+ paxb_rc_cfg_write(core_idx, CFG_RC_PMI_ADDR, pmi);
+
+ val &= ~CFG_RC_RWCMD_MASK;
+ val |= CFG_RC_WCMD_MASK;
+ paxb_rc_cfg_write(core_idx, CFG_RC_PMI_WDATA, val);
+
+ do {
+ status = paxb_rc_cfg_read(core_idx, CFG_RC_PMI_WDATA);
+
+ /* wait for write command bit to clear */
+ if ((status & CFG_RC_WCMD_MASK) == 0)
+ return 0;
+ } while (--timeout);
+
+ return -EIO;
+}
+
+/*
+ * function for reads from the Serdes registers through the PMI interface
+ */
+static int paxb_pmi_read(unsigned int core_idx, uint32_t pmi, uint32_t *val)
+{
+ uint32_t status;
+ unsigned int timeout = PMI_TIMEOUT_MS;
+
+ paxb_rc_cfg_write(core_idx, CFG_RC_PMI_ADDR, pmi);
+
+ paxb_rc_cfg_write(core_idx, CFG_RC_PMI_WDATA, CFG_RC_RCMD_MASK);
+
+ do {
+ status = paxb_rc_cfg_read(core_idx, CFG_RC_PMI_RDATA);
+
+ /* wait for read ack bit set */
+ if ((status & CFG_RC_RACK_MASK)) {
+ *val = paxb_rc_cfg_read(core_idx, CFG_RC_PMI_RDATA);
+ return 0;
+ }
+ } while (--timeout);
+
+ return -EIO;
+}
+
+
+#ifndef BOARD_PCIE_EXT_CLK
+/*
+ * PCIe Override clock lookup table
+ *
+ * Each array index represents pcie override clock has been done
+ * by CFW or not.
+ */
+static uint8_t pcie_override_clk_table[] = {
+ /* PIPEMUX = 0, EP 1x16 */
+ 0x0,
+ /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */
+ 0x1,
+ /* PIPEMUX = 2, EP 4x4 */
+ 0x0,
+ /* PIPEMUX = 3, RC 2x8, cores 0, 7 */
+ 0x0,
+ /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */
+ 0x0,
+ /* PIPEMUX = 5, RC 8x2, all 8 cores */
+ 0x0,
+ /* PIPEMUX = 6, RC 3x4 + 2x2, cores 0, 2, 3, 6, 7 */
+ 0x0,
+ /* PIPEMUX = 7, RC 1x4 + 6x2, cores 0, 2, 3, 4, 5, 6, 7 */
+ 0x0,
+ /* PIPEMUX = 8, EP 1x8 + RC 4x2, cores 4, 5, 6, 7 */
+ 0x0,
+ /* PIPEMUX = 9, EP 1x8 + RC 2x4, cores 6, 7 */
+ 0x0,
+ /* PIPEMUX = 10, EP 2x4 + RC 2x4, cores 1, 6 */
+ 0x0,
+ /* PIPEMUX = 11, EP 2x4 + RC 4x2, cores 2, 3, 4, 5 */
+ 0x0,
+ /* PIPEMUX = 12, EP 1x4 + RC 6x2, cores 2, 3, 4, 5, 6, 7 */
+ 0x0,
+ /* PIPEMUX = 13, RC 2x4 + RC 1x4 + 2x2, cores 2, 3, 6 */
+ 0x0,
+};
+
+/*
+ * Bring up LCPLL channel 0 reference clock for PCIe serdes used in RC mode
+ */
+static int pcie_lcpll_init(void)
+{
+ uintptr_t reg;
+ unsigned int timeout = PCIE_LCPLL_TIMEOUT_MS;
+ uint32_t val;
+
+ if (pcie_override_clk_table[pipemux_idx]) {
+ /*
+ * Check rc_mode_override again to avoid halt
+ * because of cfw uninitialized lcpll.
+ */
+ reg = (uintptr_t)(PCIE_LCPLL_BASE +
+ PCIE_PIPE_MUX_RC_MODE_OVERRIDE_CFG);
+ val = mmio_read_32(reg);
+ if (val & 0x1)
+ return 0;
+ else
+ return -ENODEV;
+ }
+
+ /* power on PCIe LCPLL and its LDO */
+ reg = (uintptr_t)CRMU_AON_CTRL1;
+ mmio_setbits_32(reg, CRMU_PCIE_LCPLL_PWR_ON_MASK |
+ CRMU_PCIE_LCPLL_PWRON_LDO_MASK);
+ udelay(PCIE_LCPLL_DELAY_US);
+
+ /* remove isolation */
+ mmio_clrbits_32(reg, CRMU_PCIE_LCPLL_ISO_IN_MASK);
+ udelay(PCIE_LCPLL_DELAY_US);
+
+ /* disconnect termination */
+ reg = (uintptr_t)(PCIE_LCPLL_BASE + PCIE_LCPLL_CTRL13_OFFSET);
+ mmio_setbits_32(reg, PCIE_LCPLL_D2C2_TERM_DISC <<
+ PCIE_LCPLL_D2C2_CTRL_SHIFT);
+
+ /* enable CML buf1/2 and D2C2 */
+ reg = (uintptr_t)(PCIE_LCPLL_BASE + PCIE_LCPLL_CTRL3_OFFSET);
+ mmio_setbits_32(reg, PCIE_LCPLL_CM_ENA << PCIE_LCPLL_EN_CTRL_SHIFT);
+
+ /* select diff clock mux out as ref clock */
+ mmio_clrbits_32(reg, PCIE_LCPLL_REF_CLK_MASK);
+
+ /* delay for 500 microseconds per ASIC spec for PCIe LCPLL */
+ udelay(PCIE_LCPLL_DELAY_US);
+
+ /* now bring PCIe LCPLL out of reset */
+ reg = (uintptr_t)(PCIE_LCPLL_BASE + PCIE_LCPLL_CTRL0_OFFSET);
+ mmio_setbits_32(reg, PCIE_LCPLL_RESETB_MASK);
+
+ /* wait for PLL to lock */
+ reg = (uintptr_t)(PCIE_LCPLL_BASE + PCIE_LCPLL_STATUS_OFFSET);
+ do {
+ val = mmio_read_32(reg);
+ if ((val & PCIE_LCPLL_LOCK_MASK) == PCIE_LCPLL_LOCK_MASK) {
+ /* now bring the post divider out of reset */
+ reg = (uintptr_t)(PCIE_LCPLL_BASE +
+ PCIE_LCPLL_CTRL0_OFFSET);
+ mmio_setbits_32(reg, PCIE_LCPLL_P_RESETB_MASK);
+ VERBOSE("PCIe LCPLL locked\n");
+ return 0;
+ }
+ mdelay(1);
+ } while (--timeout);
+
+ ERROR("PCIe LCPLL failed to lock\n");
+ return -EIO;
+}
+#else
+/*
+ * Bring up EXT CLK reference clock for PCIe serdes used in RC mode
+ * XTAL_BYPASS (3 << 0)
+ * INTR_LC_REF (5 << 0)
+ * PD_CML_LC_REF_OUT (1 << 4)
+ * PD_CML_REF_CH_OUT (1 << 8)
+ * CLK_MASTER_SEL (1 << 11)
+ * CLK_MASTER_CTRL_A (1 << 12)
+ * CLK_MASTER_CTRL_B (2 << 14)
+ */
+static const uint16_t pcie_ext_clk[][NUM_OF_PCIE_SERDES] = {
+ /* PIPEMUX = 0, EP 1x16 */
+ {0},
+ /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */
+ {0},
+ /* PIPEMUX = 2, EP 4x4 */
+ {0},
+ /* PIPEMUX = 3, RC 2x8, cores 0, 7 */
+ {0x8803, 0x9115, 0x9115, 0x1115, 0x8803, 0x9115, 0x9115, 0x1115},
+ /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */
+ {0x8803, 0x1115, 0x8915, 0x1115, 0x8803, 0x1115, 0x8915, 0x1115,},
+ /* PIPEMUX = 5, RC 8x2, all 8 cores */
+ {0x0803, 0x0915, 0x0915, 0x0915, 0x0803, 0x0915, 0x0915, 0x0915,},
+ /* PIPEMUX = 6, RC 3x4 + 2x2, cores 0, 2, 3, 6, 7 */
+ {0},
+ /* PIPEMUX = 7, RC 1x4 + 6x2, cores 0, 2, 3, 4, 5, 6, 7 */
+ {0},
+ /* PIPEMUX = 8, EP 1x8 + RC 4x2, cores 4, 5, 6, 7 */
+ {0},
+ /* PIPEMUX = 9, EP 1x8 + RC 2x4, cores 6, 7 */
+ {0},
+ /* PIPEMUX = 10, EP 2x4 + RC 2x4, cores 1, 6 */
+ {0},
+ /* PIPEMUX = 11, EP 2x4 + RC 4x2, cores 2, 3, 4, 5 */
+ {0},
+ /* PIPEMUX = 12, EP 1x4 + RC 6x2, cores 2, 3, 4, 5, 6, 7 */
+ {0},
+ /* PIPEMUX = 13, RC 2x4 + RC 1x4 + 2x2, cores 2, 3, 6 */
+ {0},
+};
+
+static void pcie_ext_clk_init(void)
+{
+ unsigned int serdes;
+ uint32_t val;
+
+ for (serdes = 0; serdes < NUM_OF_PCIE_SERDES; serdes++) {
+ val = pcie_ext_clk[pipemux_idx][serdes];
+ if (!val)
+ return;
+ mmio_write_32(PCIE_CORE_RESERVED_CFG +
+ serdes * PCIE_CORE_PWR_OFFSET, val);
+ }
+ /* disable CML buf1/2 and enable D2C2 */
+ mmio_clrsetbits_32((PCIE_LCPLL_BASE + PCIE_LCPLL_CTRL3_OFFSET),
+ PCIE_LCPLL_CM_BUF_ENA << PCIE_LCPLL_EN_CTRL_SHIFT,
+ PCIE_LCPLL_D2C2_ENA << PCIE_LCPLL_EN_CTRL_SHIFT);
+ mmio_write_32(PCIE_LCPLL_BASE + PCIE_TX_CLKMASTER_CTRL_OVERRIDE_CFG, 1);
+ INFO("Overriding Clocking - using REF clock from PAD...\n");
+}
+#endif
+
+static int load_uc(unsigned int core_idx)
+{
+ return 0;
+}
+
+static int paxb_serdes_gate_clock(unsigned int core_idx, int gate_clk)
+{
+ unsigned int link_width, serdes, nr_serdes;
+ uintptr_t pmi_base;
+ unsigned int rdata;
+ uint32_t core_offset = core_idx * PCIE_CORE_PWR_OFFSET;
+
+ link_width = paxb->get_link_width(core_idx);
+ if (!link_width) {
+ ERROR("Unsupported PIPEMUX\n");
+ return -EOPNOTSUPP;
+ }
+
+ nr_serdes = link_width / 2;
+ pmi_base = (uintptr_t)(PCIE_CORE_PMI_CFG_BASE + core_offset);
+
+ for (serdes = 0; serdes < nr_serdes; serdes++) {
+ mmio_write_32(pmi_base, serdes);
+ paxb_pmi_read(core_idx, PMI_ADDR_LANE0(PMI_PLL_CTRL_4), &rdata);
+ if (!gate_clk)
+ rdata |= PMI_SERDES_CLK_ENABLE;
+ else
+ rdata &= ~PMI_SERDES_CLK_ENABLE;
+ paxb_pmi_write(core_idx, PMI_ADDR_BCAST(PMI_PLL_CTRL_4), rdata);
+ }
+ return 0;
+}
+
+static int paxb_gen3_serdes_init(unsigned int core_idx, uint32_t nSerdes)
+{
+ uint32_t rdata;
+ int serdes;
+ uintptr_t pmi_base;
+ unsigned int timeout;
+ unsigned int reg_d230, reg_d267;
+
+
+ pmi_base = (uintptr_t)(PCIE_CORE_PMI_CFG_BASE +
+ (core_idx * PCIE_CORE_PWR_OFFSET));
+
+ for (serdes = 0; serdes < nSerdes; serdes++) {
+ /* select the PMI interface */
+ mmio_write_32(pmi_base, serdes);
+
+ /* Clock enable */
+ paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_A_CLK_CTRL0),
+ 0x3);
+
+ /* Release reset of master */
+ paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_A_RST_CTRL0),
+ 0x1);
+
+ /* clearing PRAM memory */
+ paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_A_AHB_CTRL0),
+ 0x100);
+
+ timeout = UC_RAM_INIT_TIMEOUT;
+ do {
+ paxb_pmi_read(core_idx,
+ PMI_ADDR_LANE0(UC_A_AHB_STAT0),
+ &rdata);
+ } while ((rdata & 0x01) == 0 && timeout--);
+
+ if (!timeout)
+ return -EIO;
+
+ timeout = UC_RAM_INIT_TIMEOUT;
+ do {
+ paxb_pmi_read(core_idx,
+ PMI_ADDR_LANE1(UC_A_AHB_STAT0),
+ &rdata);
+ } while ((rdata & 0x01) == 0 && timeout--);
+
+ if (!timeout)
+ return -EIO;
+
+ /* clearing PRAM memory */
+ paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_A_AHB_CTRL0),
+ 0);
+
+ /* to identify 2 lane serdes */
+ paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_DBG1), 0x1);
+
+ /* De-Assert Pram & master resets */
+ paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_A_RST_CTRL0),
+ 0x9);
+
+ if (load_uc(core_idx))
+ return -EIO;
+
+ /* UC UC ready for command */
+ paxb_pmi_read(core_idx, PMI_ADDR_LANE0(DSC_UC_CTRL),
+ &rdata);
+ rdata |= DSC_UC_CTRL_RDY_CMD;
+ paxb_pmi_write(core_idx, PMI_ADDR_LANE0(DSC_UC_CTRL),
+ rdata);
+
+ paxb_pmi_read(core_idx, PMI_ADDR_LANE1(DSC_UC_CTRL),
+ &rdata);
+ rdata |= DSC_UC_CTRL_RDY_CMD;
+ paxb_pmi_write(core_idx, PMI_ADDR_LANE1(DSC_UC_CTRL),
+ rdata);
+
+ /* Lane reset */
+ paxb_pmi_write(core_idx,
+ PMI_ADDR_BCAST(LANE_DBG_RST_CTRL), 0x3);
+
+ /* De-Assert Core and Master resets */
+ paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_A_RST_CTRL0),
+ 0x3);
+
+ timeout = UC_INIT_TIMEOUT;
+ while (timeout--) {
+ paxb_pmi_read(core_idx,
+ PMI_ADDR_LANE0(UC_VERSION_NUM),
+ &reg_d230);
+ paxb_pmi_read(core_idx,
+ PMI_ADDR_LANE0(DSC_SM_CTL22),
+ &reg_d267);
+
+ if (((reg_d230 & 0xffff) != 0) &
+ ((reg_d267 & 0xc000) == 0xc000)) {
+ break;
+ }
+ mdelay(1);
+ }
+
+ if (!timeout)
+ return -EIO;
+
+ timeout = UC_INIT_TIMEOUT;
+ while (timeout--) {
+ paxb_pmi_read(core_idx,
+ PMI_ADDR_LANE1(UC_VERSION_NUM),
+ &reg_d230);
+ paxb_pmi_read(core_idx,
+ PMI_ADDR_LANE1(DSC_SM_CTL22),
+ &reg_d267);
+
+ if (((reg_d230 & 0xffff) != 0) &
+ ((reg_d267 & 0xc000) == 0xc000)) {
+ break;
+ }
+ mdelay(1);
+ }
+
+ if (!timeout)
+ return -EIO;
+ }
+ return 0;
+}
+
+static int pcie_serdes_requires_patch(unsigned int serdes_idx)
+{
+ if (pipemux_idx != SERDES_PATCH_PIPEMUX_INDEX)
+ return 0;
+
+ return !!((SERDES_PATCH_INDEX >> serdes_idx) & 0x1);
+}
+
+static void pcie_tx_coeff_p7(unsigned int core_idx)
+{
+ paxb_pmi_write(core_idx, PMI_ADDR_BCAST(0xd11b), 0x00aa);
+ paxb_pmi_write(core_idx, PMI_ADDR_BCAST(0xd11c), 0x1155);
+ paxb_pmi_write(core_idx, PMI_ADDR_BCAST(0xd11d), 0x2449);
+ paxb_pmi_write(core_idx, PMI_ADDR_BCAST(0xd11e), 0x000f);
+ paxb_pmi_write(core_idx, PMI_ADDR_BCAST(0xd307), 0x0001);
+}
+
+
+static unsigned int paxb_sr_get_rc_link_width(unsigned int core_idx)
+{
+ return link_width_table[pipemux_idx][core_idx];
+}
+
+static uint32_t paxb_sr_get_rc_link_speed(void)
+{
+ return GEN3_LINK_SPEED;
+}
+
+
+static int paxb_serdes_init(unsigned int core_idx, unsigned int nr_serdes)
+{
+ uint32_t core_offset = core_idx * PCIE_CORE_PWR_OFFSET;
+ unsigned int serdes;
+ uintptr_t pmi_base;
+ int ret;
+
+ /*
+ * Each serdes has a x2 link width
+ *
+ * Use PAXB to patch the serdes for proper RX termination through the
+ * PMI interface
+ */
+ pmi_base = (uintptr_t)(PCIE_CORE_PMI_CFG_BASE + core_offset);
+ for (serdes = 0; serdes < nr_serdes; serdes++) {
+ /* select the PMI interface */
+ mmio_write_32(pmi_base, serdes);
+
+ /* patch Serdes for RX termination */
+ ret = paxb_pmi_write(core_idx, PMI_RX_TERM_SEQ,
+ PMI_RX_TERM_VAL);
+ if (ret)
+ goto err_pmi;
+
+ ret = paxb_pmi_write(core_idx, MERLIN16_PCIE_BLK2_PWRMGMT_7,
+ MERLIN16_PCIE_BLK2_PWRMGMT_7_VAL);
+ if (ret)
+ goto err_pmi;
+
+ ret = paxb_pmi_write(core_idx, MERLIN16_PCIE_BLK2_PWRMGMT_8,
+ MERLIN16_PCIE_BLK2_PWRMGMT_8_VAL);
+ if (ret)
+ goto err_pmi;
+
+ ret = paxb_pmi_write(core_idx, MERLIN16_AMS_TX_CTRL_5,
+ MERLIN16_AMS_TX_CTRL_5_VAL);
+ if (ret)
+ goto err_pmi;
+
+ pcie_tx_coeff_p7(core_idx);
+
+ if (pcie_serdes_requires_patch(serdes)) {
+ if (((core_idx == 0) || (core_idx == 7))) {
+ ret = paxb_pmi_write(core_idx,
+ PMI_X8_CORE0_7_PATCH_SEQ,
+ PMI_X8_CORE0_7_PATCH_VAL);
+ if (ret)
+ goto err_pmi;
+ }
+ }
+ }
+
+ return 0;
+
+err_pmi:
+ ERROR("PCIe PMI write failed\n");
+ return ret;
+}
+
+static int paxb_sr_phy_init(void)
+{
+ int ret;
+ unsigned int core_idx;
+
+#ifndef BOARD_PCIE_EXT_CLK
+ ret = pcie_lcpll_init();
+ if (ret)
+ return ret;
+#else
+ pcie_ext_clk_init();
+#endif
+
+ for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) {
+ if (!pcie_core_needs_enable(core_idx))
+ continue;
+ unsigned int link_width;
+
+ paxb_serdes_gate_clock(core_idx, 0);
+
+ link_width = paxb->get_link_width(core_idx);
+ if (!link_width) {
+ ERROR("Unsupported PIPEMUX\n");
+ return -EOPNOTSUPP;
+ }
+
+ ret = paxb_serdes_init(core_idx, link_width / 2);
+ if (ret) {
+ ERROR("PCIe serdes initialization failed for core %u\n",
+ core_idx);
+ return ret;
+ }
+
+
+ ret = paxb_gen3_serdes_init(core_idx, link_width / 2);
+ if (ret) {
+ ERROR("PCIe GEN3 serdes initialization failed\n");
+ return ret;
+ }
+
+ }
+ return 0;
+}
+
+const paxb_cfg sr_paxb_cfg = {
+ .type = PAXB_SR,
+ .device_id = SR_B0_DEVICE_ID,
+ .pipemux_init = pipemux_sr_init,
+ .phy_init = paxb_sr_phy_init,
+ .core_needs_enable = paxb_sr_core_needs_enable,
+ .num_cores = NUM_OF_SR_PCIE_CORES,
+ .get_link_width = paxb_sr_get_rc_link_width,
+ .get_link_speed = paxb_sr_get_rc_link_speed,
+};
+
+const paxb_cfg *paxb_get_sr_config(void)
+{
+ return &sr_paxb_cfg;
+}
diff --git a/plat/brcm/board/stingray/src/topology.c b/plat/brcm/board/stingray/src/topology.c
new file mode 100644
index 0000000..24718e5
--- /dev/null
+++ b/plat/brcm/board/stingray/src/topology.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stdint.h>
+
+#include <plat_brcm.h>
+#include <platform_def.h>
+
+/*
+ * On Stingray, 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 SR_PWR_DOMAINS_AT_MAX_PWR_LVL 1
+
+/*
+ * The Stingray 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. CLUSTER0 CPUs are allocated indices from 0 to 1 and the higher
+ * indices for other Cluster CPUs.
+ */
+const unsigned char sr_power_domain_tree_desc[] = {
+ /* No of root nodes */
+ SR_PWR_DOMAINS_AT_MAX_PWR_LVL,
+ /* No of children for the root node */
+ BRCM_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,
+ /* No of children for the third cluster node */
+ PLATFORM_CLUSTER2_CORE_COUNT,
+ /* No of children for the fourth cluster node */
+ PLATFORM_CLUSTER3_CORE_COUNT,
+};
+
+/*******************************************************************************
+ * This function returns the Stingray topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ return sr_power_domain_tree_desc;
+}
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+ return plat_brcm_calc_core_pos(mpidr);
+}
diff --git a/plat/brcm/board/stingray/src/tz_sec.c b/plat/brcm/board/stingray/src/tz_sec.c
new file mode 100644
index 0000000..07b12a7
--- /dev/null
+++ b/plat/brcm/board/stingray/src/tz_sec.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2016 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/arm/tzc400.h>
+#include <lib/mmio.h>
+
+#include <cmn_sec.h>
+#include <platform_def.h>
+
+/*
+ * Trust Zone controllers
+ */
+#define TZC400_FS_SRAM_ROOT 0x66d84000
+
+/*
+ * TZPC Master configure registers
+ */
+
+/* TZPC_TZPCDECPROT0set */
+#define TZPC0_MASTER_NS_BASE 0x68b40804
+#define TZPC0_SATA3_BIT 5
+#define TZPC0_SATA2_BIT 4
+#define TZPC0_SATA1_BIT 3
+#define TZPC0_SATA0_BIT 2
+#define TZPC0_USB3H1_BIT 1
+#define TZPC0_USB3H0_BIT 0
+#define TZPC0_MASTER_SEC_DEFAULT 0
+
+/* TZPC_TZPCDECPROT1set */
+#define TZPC1_MASTER_NS_BASE 0x68b40810
+#define TZPC1_SDIO1_BIT 6
+#define TZPC1_SDIO0_BIT 5
+#define TZPC1_AUDIO0_BIT 4
+#define TZPC1_USB2D_BIT 3
+#define TZPC1_USB2H1_BIT 2
+#define TZPC1_USB2H0_BIT 1
+#define TZPC1_AMAC0_BIT 0
+#define TZPC1_MASTER_SEC_DEFAULT 0
+
+
+struct tz_sec_desc {
+ uintptr_t addr;
+ uint32_t val;
+};
+
+static const struct tz_sec_desc tz_master_defaults[] = {
+{ TZPC0_MASTER_NS_BASE, TZPC0_MASTER_SEC_DEFAULT },
+{ TZPC1_MASTER_NS_BASE, TZPC1_MASTER_SEC_DEFAULT }
+};
+
+/*
+ * Initialize the TrustZone Controller for SRAM partitioning.
+ */
+static void bcm_tzc_setup(void)
+{
+ VERBOSE("Configuring SRAM TrustZone Controller\n");
+
+ /* Init the TZASC controller */
+ tzc400_init(TZC400_FS_SRAM_ROOT);
+
+ /*
+ * Close the entire SRAM space
+ * Region 0 covers the entire SRAM space
+ * None of the NS device can access it.
+ */
+ tzc400_configure_region0(TZC_REGION_S_RDWR, 0);
+
+ /* Do raise an exception if a NS device tries to access secure memory */
+ tzc400_set_action(TZC_ACTION_ERR);
+}
+
+/*
+ * Configure TZ Master as NS_MASTER or SECURE_MASTER
+ * To set a Master to non-secure, use *_SET registers
+ * To set a Master to secure, use *_CLR registers (set + 0x4 address)
+ */
+static void tz_master_set(uint32_t base, uint32_t value, uint32_t ns)
+{
+ if (ns == SECURE_MASTER) {
+ mmio_write_32(base + 4, value);
+ } else {
+ mmio_write_32(base, value);
+ }
+}
+
+/*
+ * Initialize the secure environment for sdio.
+ */
+void plat_tz_sdio_ns_master_set(uint32_t ns)
+{
+ tz_master_set(TZPC1_MASTER_NS_BASE,
+ 1 << TZPC1_SDIO0_BIT,
+ ns);
+}
+
+/*
+ * Initialize the secure environment for usb.
+ */
+void plat_tz_usb_ns_master_set(uint32_t ns)
+{
+ tz_master_set(TZPC1_MASTER_NS_BASE,
+ 1 << TZPC1_USB2H0_BIT,
+ ns);
+}
+
+/*
+ * Set masters to default configuration.
+ *
+ * DMA security settings are programmed into the PL-330 controller and
+ * are not set by iProc TZPC registers.
+ * DMA always comes up as secure master (*NS bit is 0).
+ *
+ * Because the default reset values of TZPC are 0 (== Secure),
+ * ARM Verilog code makes all masters, including PCIe, come up as
+ * secure.
+ * However, SOTP has a bit called SOTP_ALLMASTER_NS that overrides
+ * TZPC and makes all masters non-secure for AB devices.
+ *
+ * Hence we first set all the TZPC bits to program all masters,
+ * including PCIe, as non-secure, then set the CLEAR_ALLMASTER_NS bit
+ * so that the SOTP_ALLMASTER_NS cannot override TZPC.
+ * now security settings for each masters come from TZPC
+ * (which makes all masters other than DMA as non-secure).
+ *
+ * During the boot, all masters other than DMA Ctrlr + list
+ * are non-secure in an AB Prod/AB Dev/AB Pending device.
+ *
+ */
+void plat_tz_master_default_cfg(void)
+{
+ int i;
+
+ /* Configure default secure and non-secure TZ Masters */
+ for (i = 0; i < ARRAY_SIZE(tz_master_defaults); i++) {
+ tz_master_set(tz_master_defaults[i].addr,
+ tz_master_defaults[i].val,
+ SECURE_MASTER);
+ tz_master_set(tz_master_defaults[i].addr,
+ ~tz_master_defaults[i].val,
+ NS_MASTER);
+ }
+
+ /* Clear all master NS */
+ mmio_setbits_32(SOTP_CHIP_CTRL,
+ 1 << SOTP_CLEAR_SYSCTRL_ALL_MASTER_NS);
+
+ /* Initialize TZ controller and Set SRAM to secure */
+ bcm_tzc_setup();
+}
diff --git a/plat/brcm/common/brcm_bl2_mem_params_desc.c b/plat/brcm/common/brcm_bl2_mem_params_desc.c
new file mode 100644
index 0000000..aed99d9
--- /dev/null
+++ b/plat/brcm/common/brcm_bl2_mem_params_desc.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+/*******************************************************************************
+ * 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_MAX_SCP_BL2_SIZE,
+
+ .next_handoff_image_id = INVALID_IMAGE_ID,
+ },
+#endif /* SCP_BL2_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 = BRCM_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 = PLAT_BRCM_NS_IMAGE_OFFSET,
+
+ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+ VERSION_2, image_info_t, 0),
+ .image_info.image_base = PLAT_BRCM_NS_IMAGE_OFFSET,
+ .image_info.image_max_size = BRCM_DRAM1_SIZE,
+#endif /* PRELOADED_BL33_BASE */
+
+ .next_handoff_image_id = INVALID_IMAGE_ID,
+ }
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
diff --git a/plat/brcm/common/brcm_bl2_setup.c b/plat/brcm/common/brcm_bl2_setup.c
new file mode 100644
index 0000000..9a7153b
--- /dev/null
+++ b/plat/brcm/common/brcm_bl2_setup.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/arm/sp804_delay_timer.h>
+#include <lib/mmio.h>
+
+#include <bcm_console.h>
+#include <platform_def.h>
+#include <plat/brcm/common/plat_brcm.h>
+
+/* 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 BRCM platform */
+#pragma weak plat_bcm_bl2_platform_setup
+#pragma weak plat_bcm_bl2_plat_arch_setup
+#pragma weak plat_bcm_security_setup
+#pragma weak plat_bcm_bl2_plat_handle_scp_bl2
+#pragma weak plat_bcm_bl2_early_platform_setup
+
+void plat_bcm_bl2_early_platform_setup(void)
+{
+}
+
+void plat_bcm_bl2_platform_setup(void)
+{
+}
+
+void plat_bcm_bl2_plat_arch_setup(void)
+{
+}
+
+void plat_bcm_security_setup(void)
+{
+}
+
+void bcm_bl2_early_platform_setup(uintptr_t tb_fw_config,
+ meminfo_t *mem_layout)
+{
+ /* Initialize the console to provide early debug support */
+ bcm_console_boot_init();
+
+ /* Setup the BL2 memory layout */
+ bl2_tzram_layout = *mem_layout;
+
+ /* Initialise the IO layer and register platform IO devices */
+ plat_brcm_io_setup();
+
+ /* Log HW reset event */
+ INFO("RESET: 0x%x\n",
+ mmio_read_32(CRMU_RESET_EVENT_LOG));
+}
+
+void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3)
+{
+ /* SoC specific setup */
+ plat_bcm_bl2_early_platform_setup();
+
+ /* Initialize delay timer driver using SP804 dual timer 0 */
+ sp804_timer_init(SP804_TIMER0_BASE,
+ SP804_TIMER0_CLKMULT, SP804_TIMER0_CLKDIV);
+
+ /* BRCM platforms generic setup */
+ bcm_bl2_early_platform_setup((uintptr_t)arg0, (meminfo_t *)arg1);
+}
+
+/*
+ * Perform Broadcom platform setup.
+ */
+void bcm_bl2_platform_setup(void)
+{
+ /* Initialize the secure environment */
+ plat_bcm_security_setup();
+}
+
+void bl2_platform_setup(void)
+{
+ bcm_bl2_platform_setup();
+ plat_bcm_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 bcm_bl2_plat_arch_setup(void)
+{
+#ifndef MMU_DISABLED
+ if (!(read_sctlr_el1() & SCTLR_M_BIT)) {
+ const mmap_region_t bl_regions[] = {
+ MAP_REGION_FLAT(bl2_tzram_layout.total_base,
+ bl2_tzram_layout.total_size,
+ 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_brcm_get_mmap());
+ enable_mmu_el1(0);
+ }
+#endif
+}
+
+void bl2_plat_arch_setup(void)
+{
+#ifdef ENA_MMU_BEFORE_DDR_INIT
+ /*
+ * Once MMU is enabled before DDR, MEMORY TESTS
+ * get affected as read/write transaction might occures from
+ * caches. So For running memory test, one should not set this
+ * flag.
+ */
+ bcm_bl2_plat_arch_setup();
+ plat_bcm_bl2_plat_arch_setup();
+#else
+ plat_bcm_bl2_plat_arch_setup();
+ bcm_bl2_plat_arch_setup();
+#endif
+}
+
+int bcm_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 BL32_IMAGE_ID:
+ bl_mem_params->ep_info.spsr = brcm_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 = brcm_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 = bcm_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 bcm_bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+ return bcm_bl2_handle_post_image_load(image_id);
+}
+
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+ return bcm_bl2_plat_handle_post_image_load(image_id);
+}
+
+#ifdef SCP_BL2_BASE
+int plat_bcm_bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info)
+{
+ return 0;
+}
+
+int bcm_bl2_handle_scp_bl2(image_info_t *scp_bl2_image_info)
+{
+ return plat_bcm_bl2_plat_handle_scp_bl2(scp_bl2_image_info);
+}
+#endif
diff --git a/plat/brcm/common/brcm_bl31_setup.c b/plat/brcm/common/brcm_bl31_setup.c
new file mode 100644
index 0000000..d3fa83d
--- /dev/null
+++ b/plat/brcm/common/brcm_bl31_setup.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/sp804_delay_timer.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#include <bcm_console.h>
+#include <plat_brcm.h>
+#include <platform_def.h>
+
+#ifdef BL33_SHARED_DDR_BASE
+struct bl33_info *bl33_info = (struct bl33_info *)BL33_SHARED_DDR_BASE;
+#endif
+
+/*
+ * 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 BRCM platform */
+#pragma weak plat_bcm_bl31_early_platform_setup
+#pragma weak plat_brcm_pwrc_setup
+#pragma weak plat_brcm_security_setup
+
+void plat_brcm_security_setup(void)
+{
+
+}
+
+void plat_brcm_pwrc_setup(void)
+{
+
+}
+
+void plat_bcm_bl31_early_platform_setup(void *from_bl2,
+ bl_params_t *plat_params_from_bl2)
+{
+
+}
+
+/*******************************************************************************
+ * 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 brcm_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 */
+ bcm_console_boot_init();
+
+ /* Initialize delay timer driver using SP804 dual timer 0 */
+ sp804_timer_init(SP804_TIMER0_BASE,
+ SP804_TIMER0_CLKMULT, SP804_TIMER0_CLKDIV);
+
+#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 = brcm_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 = brcm_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)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) ==
+ BRCM_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 &&
+ bl_params->image_info->h.attr != IMAGE_ATTRIB_SKIP_LOADING)
+ 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 */
+
+#ifdef BL33_SHARED_DDR_BASE
+ /* Pass information to BL33 thorugh x0 */
+ bl33_image_ep_info.args.arg0 = (u_register_t)BL33_SHARED_DDR_BASE;
+ bl33_image_ep_info.args.arg1 = 0ULL;
+ bl33_image_ep_info.args.arg2 = 0ULL;
+ bl33_image_ep_info.args.arg3 = 0ULL;
+#endif
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3)
+{
+#ifdef BL31_LOG_LEVEL
+ SET_LOG_LEVEL(BL31_LOG_LEVEL);
+#endif
+
+ brcm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+
+ plat_bcm_bl31_early_platform_setup((void *)arg0, (void *)arg3);
+
+#ifdef DRIVER_CC_ENABLE
+ /*
+ * Initialize Interconnect for this cluster during cold boot.
+ * No need for locks as no other CPU is active.
+ */
+ plat_brcm_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_brcm_interconnect_enter_coherency();
+#endif
+}
+
+/*******************************************************************************
+ * Perform any BL31 platform setup common to ARM standard platforms
+ ******************************************************************************/
+void brcm_bl31_platform_setup(void)
+{
+ /* Initialize the GIC driver, cpu and distributor interfaces */
+ plat_brcm_gic_driver_init();
+ plat_brcm_gic_init();
+
+ /* Initialize power controller before setting up topology */
+ plat_brcm_pwrc_setup();
+}
+
+/*******************************************************************************
+ * Perform any BL31 platform runtime setup prior to BL31 exit common to ARM
+ * standard platforms
+ * Perform BL31 platform setup
+ ******************************************************************************/
+void brcm_bl31_plat_runtime_setup(void)
+{
+ console_switch_state(CONSOLE_FLAG_RUNTIME);
+
+ /* Initialize the runtime console */
+ bcm_console_runtime_init();
+}
+
+void bl31_platform_setup(void)
+{
+ brcm_bl31_platform_setup();
+
+ /* Initialize the secure environment */
+ plat_brcm_security_setup();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+ brcm_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 brcm_bl31_plat_arch_setup(void)
+{
+#ifndef MMU_DISABLED
+ 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_brcm_get_mmap());
+
+ enable_mmu_el3(0);
+#endif
+}
+
+void __init bl31_plat_arch_setup(void)
+{
+ brcm_bl31_plat_arch_setup();
+}
diff --git a/plat/brcm/common/brcm_ccn.c b/plat/brcm/common/brcm_ccn.c
new file mode 100644
index 0000000..9396aaa
--- /dev/null
+++ b/plat/brcm/common/brcm_ccn.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <drivers/arm/ccn.h>
+
+#include <platform_def.h>
+
+static const unsigned char master_to_rn_id_map[] = {
+ PLAT_BRCM_CLUSTER_TO_CCN_ID_MAP
+};
+
+static const ccn_desc_t bcm_ccn_desc = {
+ .periphbase = PLAT_BRCM_CCN_BASE,
+ .num_masters = ARRAY_SIZE(master_to_rn_id_map),
+ .master_to_rn_id_map = master_to_rn_id_map
+};
+
+void plat_brcm_interconnect_init(void)
+{
+ ccn_init(&bcm_ccn_desc);
+}
+
+void plat_brcm_interconnect_enter_coherency(void)
+{
+ ccn_enter_snoop_dvm_domain(1 << MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
+
+void plat_brcm_interconnect_exit_coherency(void)
+{
+ ccn_exit_snoop_dvm_domain(1 << MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
diff --git a/plat/brcm/common/brcm_common.c b/plat/brcm/common/brcm_common.c
new file mode 100644
index 0000000..f23719d
--- /dev/null
+++ b/plat/brcm/common/brcm_common.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+#include <plat_brcm.h>
+#include <platform_def.h>
+
+/* Weak definitions may be overridden in specific BRCM platform */
+#pragma weak plat_get_ns_image_entrypoint
+#pragma weak plat_brcm_get_mmap
+
+uintptr_t plat_get_ns_image_entrypoint(void)
+{
+#ifdef PRELOADED_BL33_BASE
+ return PRELOADED_BL33_BASE;
+#else
+ return PLAT_BRCM_NS_IMAGE_OFFSET;
+#endif
+}
+
+uint32_t brcm_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;
+}
+
+uint32_t brcm_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) ? 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;
+}
+
+const mmap_region_t *plat_brcm_get_mmap(void)
+{
+ return plat_brcm_mmap;
+}
diff --git a/plat/brcm/common/brcm_gicv3.c b/plat/brcm/common/brcm_gicv3.c
new file mode 100644
index 0000000..c4137c0
--- /dev/null
+++ b/plat/brcm/common/brcm_gicv3.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/gicv3.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+/* The GICv3 driver only needs to be initialized in EL3 */
+static uintptr_t brcm_rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static const interrupt_prop_t brcm_interrupt_props[] = {
+ /* G1S interrupts */
+ PLAT_BRCM_G1S_IRQ_PROPS(INTR_GROUP1S),
+ /* G0 interrupts */
+ PLAT_BRCM_G0_IRQ_PROPS(INTR_GROUP0)
+};
+
+/*
+ * 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 brcm_gicv3_mpidr_hash(u_register_t mpidr)
+{
+ mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK);
+ return plat_core_pos_by_mpidr(mpidr);
+}
+
+static const gicv3_driver_data_t brcm_gic_data = {
+ .gicd_base = PLAT_BRCM_GICD_BASE,
+ .gicr_base = PLAT_BRCM_GICR_BASE,
+ .interrupt_props = brcm_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(brcm_interrupt_props),
+ .rdistif_num = PLATFORM_CORE_COUNT,
+ .rdistif_base_addrs = brcm_rdistif_base_addrs,
+ .mpidr_to_core_pos = brcm_gicv3_mpidr_hash
+};
+
+void plat_brcm_gic_driver_init(void)
+{
+ /* TODO Check if this is required to be initialized here
+ * after getting initialized in EL3, should we re-init this here
+ * in S-EL1
+ */
+ gicv3_driver_init(&brcm_gic_data);
+}
+
+void plat_brcm_gic_init(void)
+{
+ gicv3_distif_init();
+ gicv3_rdistif_init(plat_my_core_pos());
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void plat_brcm_gic_cpuif_enable(void)
+{
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void plat_brcm_gic_cpuif_disable(void)
+{
+ gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+void plat_brcm_gic_pcpu_init(void)
+{
+ gicv3_rdistif_init(plat_my_core_pos());
+}
+
+void plat_brcm_gic_redistif_on(void)
+{
+ gicv3_rdistif_on(plat_my_core_pos());
+}
+
+void plat_brcm_gic_redistif_off(void)
+{
+ gicv3_rdistif_off(plat_my_core_pos());
+}
diff --git a/plat/brcm/common/brcm_image_load.c b/plat/brcm/common/brcm_image_load.c
new file mode 100644
index 0000000..ba02bda
--- /dev/null
+++ b/plat/brcm/common/brcm_image_load.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+#pragma weak plat_flush_next_bl_params
+#pragma weak plat_get_bl_image_load_info
+#pragma weak plat_get_next_bl_params
+
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+struct bl_load_info *plat_get_bl_image_load_info(void)
+{
+ return get_bl_load_info_from_mem_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of executable images.
+ ******************************************************************************/
+struct bl_params *plat_get_next_bl_params(void)
+{
+ bl_params_t *next_bl_params = get_next_bl_params_from_mem_params_desc();
+
+ populate_next_bl_params_config(next_bl_params);
+ return next_bl_params;
+}
diff --git a/plat/brcm/common/brcm_io_storage.c b/plat/brcm/common/brcm_io_storage.c
new file mode 100644
index 0000000..66ec292
--- /dev/null
+++ b/plat/brcm/common/brcm_io_storage.c
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <tools_share/firmware_image_package.h>
+
+#include <cmn_plat_def.h>
+#include <cmn_plat_util.h>
+#include <plat_brcm.h>
+#include <platform_def.h>
+
+/* 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_BRCM_FIP_BASE,
+ .length = PLAT_BRCM_FIP_MAX_SIZE
+};
+
+static const io_block_spec_t qspi_fip_block_spec = {
+ .offset = PLAT_BRCM_FIP_QSPI_BASE,
+ .length = PLAT_BRCM_FIP_MAX_SIZE
+};
+
+static const io_block_spec_t nand_fip_block_spec = {
+ .offset = PLAT_BRCM_FIP_NAND_BASE,
+ .length = PLAT_BRCM_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);
+static int open_qspi(const uintptr_t spec);
+static int open_nand(const uintptr_t spec);
+
+struct plat_io_policy {
+ uintptr_t *dev_handle;
+ uintptr_t image_spec;
+ int (*check)(const uintptr_t spec);
+};
+
+/* By default, BRCM 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 */
+};
+
+/* By default, BRCM platforms load images from the FIP */
+static const struct plat_io_policy boot_source_policies[] = {
+ [BOOT_SOURCE_QSPI] = {
+ &memmap_dev_handle,
+ (uintptr_t)&qspi_fip_block_spec,
+ open_qspi
+ },
+ [BOOT_SOURCE_NAND] = {
+ &memmap_dev_handle,
+ (uintptr_t)&nand_fip_block_spec,
+ open_nand
+ },
+};
+
+/* Weak definitions may be overridden in specific brcm platform */
+#pragma weak plat_brcm_io_setup
+#pragma weak plat_brcm_process_flags
+
+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_qspi(const uintptr_t spec)
+{
+ return open_memmap(spec);
+}
+
+static int open_nand(const uintptr_t spec)
+{
+ return open_memmap(spec);
+}
+
+
+void brcm_io_setup(void)
+{
+ int io_result;
+ uint32_t boot_source;
+
+ 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);
+
+ boot_source = boot_source_get();
+ switch (boot_source) {
+ case BOOT_SOURCE_QSPI:
+ case BOOT_SOURCE_NAND:
+ default:
+ io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL,
+ &memmap_dev_handle);
+ break;
+ }
+ assert(io_result == 0);
+
+ /* Ignore improbable errors in release builds */
+ (void)io_result;
+}
+
+void plat_brcm_io_setup(void)
+{
+ brcm_io_setup();
+}
+
+void plat_brcm_process_flags(uint16_t plat_toc_flags __unused)
+{
+ WARN("%s not implemented\n", __func__);
+}
+
+/*
+ * 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;
+ uint32_t boot_source;
+ uint16_t lcl_plat_toc_flg;
+
+ assert(image_id < ARRAY_SIZE(policies));
+
+ boot_source = boot_source_get();
+ if (image_id == FIP_IMAGE_ID)
+ policy = &boot_source_policies[boot_source];
+ else
+ policy = &policies[image_id];
+
+ result = policy->check(policy->image_spec);
+ if (result == 0) {
+ *image_spec = policy->image_spec;
+ *dev_handle = *(policy->dev_handle);
+
+ if (image_id == TRUSTED_BOOT_FW_CERT_ID) {
+ /*
+ * Process the header flags to perform
+ * such custom actions as speeding up PLL.
+ * CERT seems to be the first image accessed
+ * by BL1 so this is where we process the flags.
+ */
+ fip_dev_get_plat_toc_flag((io_dev_info_t *)fip_dev_handle,
+ &lcl_plat_toc_flg);
+ plat_brcm_process_flags(lcl_plat_toc_flg);
+ }
+ }
+
+ return result;
+}
diff --git a/plat/brcm/common/brcm_mhu.c b/plat/brcm/common/brcm_mhu.c
new file mode 100644
index 0000000..56f44e0
--- /dev/null
+++ b/plat/brcm/common/brcm_mhu.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <drivers/delay_timer.h>
+#include <lib/bakery_lock.h>
+
+#include <brcm_mhu.h>
+#include <platform_def.h>
+
+#include "m0_ipc.h"
+
+#define PLAT_MHU_INTR_REG AP_TO_SCP_MAILBOX1
+
+/* SCP MHU secure channel registers */
+#define SCP_INTR_S_STAT CRMU_IHOST_SW_PERSISTENT_REG11
+#define SCP_INTR_S_SET CRMU_IHOST_SW_PERSISTENT_REG11
+#define SCP_INTR_S_CLEAR CRMU_IHOST_SW_PERSISTENT_REG11
+
+/* CPU MHU secure channel registers */
+#define CPU_INTR_S_STAT CRMU_IHOST_SW_PERSISTENT_REG10
+#define CPU_INTR_S_SET CRMU_IHOST_SW_PERSISTENT_REG10
+#define CPU_INTR_S_CLEAR CRMU_IHOST_SW_PERSISTENT_REG10
+
+static DEFINE_BAKERY_LOCK(bcm_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)
+{
+ int iter = 1000000;
+
+ assert(slot_id <= MHU_MAX_SLOT_ID);
+
+ bakery_lock_get(&bcm_lock);
+ /* Make sure any previous command has finished */
+ do {
+ if (!(mmio_read_32(PLAT_BRCM_MHU_BASE + CPU_INTR_S_STAT) &
+ (1 << slot_id)))
+ break;
+
+ udelay(1);
+
+ } while (--iter);
+
+ assert(iter != 0);
+}
+
+void mhu_secure_message_send(unsigned int slot_id)
+{
+ uint32_t response, iter = 1000000;
+
+ assert(slot_id <= MHU_MAX_SLOT_ID);
+ assert(!(mmio_read_32(PLAT_BRCM_MHU_BASE + CPU_INTR_S_STAT) &
+ (1 << slot_id)));
+
+ /* Send command to SCP */
+ mmio_setbits_32(PLAT_BRCM_MHU_BASE + CPU_INTR_S_SET, 1 << slot_id);
+ mmio_write_32(CRMU_MAIL_BOX0, MCU_IPC_MCU_CMD_SCPI);
+ mmio_write_32(PLAT_BRCM_MHU_BASE + PLAT_MHU_INTR_REG, 0x1);
+
+ /* Wait until IPC transport acknowledges reception of SCP command */
+ do {
+ response = mmio_read_32(CRMU_MAIL_BOX0);
+ if ((response & ~MCU_IPC_CMD_REPLY_MASK) ==
+ (MCU_IPC_CMD_DONE_MASK | MCU_IPC_MCU_CMD_SCPI))
+ break;
+
+ udelay(1);
+
+ } while (--iter);
+
+ assert(iter != 0);
+}
+
+uint32_t mhu_secure_message_wait(void)
+{
+ /* Wait for response from SCP */
+ uint32_t response, iter = 1000000;
+
+ do {
+ response = mmio_read_32(PLAT_BRCM_MHU_BASE + SCP_INTR_S_STAT);
+ if (!response)
+ break;
+
+ udelay(1);
+ } while (--iter);
+ assert(iter != 0);
+
+ 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_clrbits_32(PLAT_BRCM_MHU_BASE + SCP_INTR_S_CLEAR, 1 << slot_id);
+ bakery_lock_release(&bcm_lock);
+}
+
+void mhu_secure_init(void)
+{
+ bakery_lock_init(&bcm_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.
+ */
+ mmio_write_32(PLAT_BRCM_MHU_BASE + CPU_INTR_S_STAT, 0);
+ mmio_write_32(PLAT_BRCM_MHU_BASE + SCP_INTR_S_STAT, 0);
+}
+
+void plat_brcm_pwrc_setup(void)
+{
+ mhu_secure_init();
+}
diff --git a/plat/brcm/common/brcm_mhu.h b/plat/brcm/common/brcm_mhu.h
new file mode 100644
index 0000000..6c89a34
--- /dev/null
+++ b/plat/brcm/common/brcm_mhu.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BRCM_MHU_H
+#define BRCM_MHU_H
+
+#include <stdint.h>
+
+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 /* BRCM_MHU_H */
diff --git a/plat/brcm/common/brcm_scpi.c b/plat/brcm/common/brcm_scpi.c
new file mode 100644
index 0000000..0a703cb
--- /dev/null
+++ b/plat/brcm/common/brcm_scpi.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#include <brcm_mhu.h>
+#include <brcm_scpi.h>
+#include <platform_def.h>
+
+#define SCPI_SHARED_MEM_SCP_TO_AP (PLAT_SCP_COM_SHARED_MEM_BASE)
+#define SCPI_SHARED_MEM_AP_TO_SCP (PLAT_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 #%u, received #%u\n",
+ SCPI_CMD_SCP_READY, scpi_cmd.id);
+ status = SCP_E_SUPPORT;
+ } else if (scpi_cmd.size != 0) {
+ ERROR("SCP_READY cmd 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_brcm_power_state(unsigned int mpidr,
+ scpi_power_state_t cpu_state, scpi_power_state_t cluster_state,
+ scpi_power_state_t brcm_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 |= brcm_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();
+}
+
+/*
+ * Query and obtain 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_brcm_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
+ */
+ cpu = mpidr & MPIDR_AFFLVL_MASK;
+ cluster = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+ 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_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_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_end();
+
+ return SCP_OK;
+}
diff --git a/plat/brcm/common/brcm_scpi.h b/plat/brcm/common/brcm_scpi.h
new file mode 100644
index 0000000..f3b658f
--- /dev/null
+++ b/plat/brcm/common/brcm_scpi.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BRCM_SCPI_H
+#define BRCM_SCPI_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/*
+ * 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_GET_POWER_STATE = 0x04,
+ SCPI_CMD_SYS_POWER_STATE = 0x05
+} scpi_command_t;
+
+/*
+ * Macros to parse SCP response to GET_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_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;
+
+extern int scpi_wait_ready(void);
+extern void scpi_set_brcm_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_brcm_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 /* BRCM_SCPI_H */
diff --git a/plat/common/aarch32/crash_console_helpers.S b/plat/common/aarch32/crash_console_helpers.S
new file mode 100644
index 0000000..ea04f56
--- /dev/null
+++ b/plat/common/aarch32/crash_console_helpers.S
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * If a platform wishes to use the functions in this file it has to be added to
+ * the Makefile of the platform. It is not included in the common Makefile.
+ */
+
+#include <asm_macros.S>
+#include <drivers/console.h>
+
+ .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
diff --git a/plat/common/aarch32/plat_common.c b/plat/common/aarch32/plat_common.c
new file mode 100644
index 0000000..2c1a8fa
--- /dev/null
+++ b/plat/common/aarch32/plat_common.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <plat/common/platform.h>
+
+/*
+ * 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);
+}
diff --git a/plat/common/aarch32/plat_sp_min_common.c b/plat/common/aarch32/plat_sp_min_common.c
new file mode 100644
index 0000000..9493587
--- /dev/null
+++ b/plat/common/aarch32/plat_sp_min_common.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/console.h>
+#include <plat/common/platform.h>
+#include <platform_sp_min.h>
+
+/*
+ * 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);
+}
diff --git a/plat/common/aarch32/platform_helpers.S b/plat/common/aarch32/platform_helpers.S
new file mode 100644
index 0000000..75cc456
--- /dev/null
+++ b/plat/common/aarch32/platform_helpers.S
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+ .weak plat_report_exception
+ .weak plat_report_prefetch_abort
+ .weak plat_report_data_abort
+ .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_report_prefetch_abort
+ bx lr
+endfunc plat_report_prefetch_abort
+
+ /* -----------------------------------------------------
+ * Placeholder function which should be redefined by
+ * each platform.
+ * -----------------------------------------------------
+ */
+func plat_report_data_abort
+ bx lr
+endfunc plat_report_data_abort
+
+ /* -----------------------------------------------------
+ * 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
diff --git a/plat/common/aarch32/platform_mp_stack.S b/plat/common/aarch32/platform_mp_stack.S
new file mode 100644
index 0000000..6c3d08d
--- /dev/null
+++ b/plat/common/aarch32/platform_mp_stack.S
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/common/aarch32/platform_up_stack.S b/plat/common/aarch32/platform_up_stack.S
new file mode 100644
index 0000000..836c13a
--- /dev/null
+++ b/plat/common/aarch32/platform_up_stack.S
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/common/aarch64/crash_console_helpers.S b/plat/common/aarch64/crash_console_helpers.S
new file mode 100644
index 0000000..e2950f5
--- /dev/null
+++ b/plat/common/aarch64/crash_console_helpers.S
@@ -0,0 +1,187 @@
+/*
+ * 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 <asm_macros.S>
+#include <drivers/console.h>
+
+ .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
diff --git a/plat/common/aarch64/plat_common.c b/plat/common/aarch64/plat_common.c
new file mode 100644
index 0000000..8ce1d6c
--- /dev/null
+++ b/plat/common/aarch64/plat_common.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2014-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#if RAS_EXTENSION
+#include <lib/extensions/ras.h>
+#endif
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <plat/common/platform.h>
+
+/*
+ * 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 = plat_default_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 %" PRIx64 "\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
+
+const char *get_el_str(unsigned int el)
+{
+ if (el == MODE_EL3) {
+ return "EL3";
+ } else if (el == MODE_EL2) {
+ return "EL2";
+ }
+ return "EL1";
+}
+
+/* RAS functions common to AArch64 ARM platforms */
+void plat_default_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
+ unsigned int level = (unsigned int)GET_EL(read_spsr_el3());
+
+ ERROR_NL();
+ ERROR("Unhandled External Abort received on 0x%lx from %s\n",
+ read_mpidr_el1(), get_el_str(level));
+ ERROR("exception reason=%u syndrome=0x%" PRIx64 "\n", ea_reason, syndrome);
+#if HANDLE_EA_EL3_FIRST_NS
+ /* Skip backtrace for lower EL */
+ if (level != MODE_EL3) {
+ console_flush();
+ do_panic();
+ }
+#endif
+ panic();
+}
diff --git a/plat/common/aarch64/plat_ehf.c b/plat/common/aarch64/plat_ehf.c
new file mode 100644
index 0000000..da76884
--- /dev/null
+++ b/plat/common/aarch64/plat_ehf.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, Broadcom
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <bl31/ehf.h>
+
+#include <platform_def.h>
+
+/*
+ * Enumeration of priority levels on ARM platforms.
+ */
+ehf_pri_desc_t plat_exceptions[] = {
+#if RAS_EXTENSION
+ /* RAS Priority */
+ EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_RAS_PRI),
+#endif
+
+#if SDEI_SUPPORT
+ /* Critical priority SDEI */
+ EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SDEI_CRITICAL_PRI),
+
+ /* Normal priority SDEI */
+ EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SDEI_NORMAL_PRI),
+#endif
+#if SPM_MM
+ EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SP_PRI),
+#endif
+ /* Plaform specific exceptions description */
+#ifdef PLAT_EHF_DESC
+ PLAT_EHF_DESC,
+#endif
+};
+
+/* Plug in ARM exceptions to Exception Handling Framework. */
+EHF_REGISTER_PRIORITIES(plat_exceptions, ARRAY_SIZE(plat_exceptions), PLAT_PRI_BITS);
diff --git a/plat/common/aarch64/platform_helpers.S b/plat/common/aarch64/platform_helpers.S
new file mode 100644
index 0000000..bc650c9
--- /dev/null
+++ b/plat/common/aarch64/platform_helpers.S
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/console.h>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/common/aarch64/platform_mp_stack.S b/plat/common/aarch64/platform_mp_stack.S
new file mode 100644
index 0000000..c0668ea
--- /dev/null
+++ b/plat/common/aarch64/platform_mp_stack.S
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+
+ .local platform_normal_stacks
+ .weak plat_get_my_stack
+ .weak plat_set_my_stack
+
+ /* ---------------------------------------------------------------------
+ * When the compatibility 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
+ 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
+ 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
diff --git a/plat/common/aarch64/platform_up_stack.S b/plat/common/aarch64/platform_up_stack.S
new file mode 100644
index 0000000..c6e5e2d
--- /dev/null
+++ b/plat/common/aarch64/platform_up_stack.S
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+
+ .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
diff --git a/plat/common/plat_bl1_common.c b/plat/common/plat_bl1_common.c
new file mode 100644
index 0000000..bcf9f89
--- /dev/null
+++ b/plat/common/plat_bl1_common.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2015-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+/*
+ * 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 (true)
+ 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_secram_layout;
+ meminfo_t *bl1_secram_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_secram_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_secram_layout = (meminfo_t *) bl1_secram_layout->total_base;
+
+ bl1_calc_bl2_mem_layout(bl1_secram_layout, bl2_secram_layout);
+
+ ep_info->args.arg1 = (uintptr_t)bl2_secram_layout;
+
+ VERBOSE("BL1: BL2 memory layout address = %p\n",
+ (void *) bl2_secram_layout);
+ return 0;
+}
diff --git a/plat/common/plat_bl_common.c b/plat/common/plat_bl_common.c
new file mode 100644
index 0000000..89b77ba
--- /dev/null
+++ b/plat/common/plat_bl_common.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+#include <plat/common/platform.h>
+#include <services/arm_arch_svc.h>
+#include <smccc_helpers.h>
+#include <tools_share/firmware_encrypted.h>
+
+/*
+ * 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
+#pragma weak plat_get_enc_key_info
+#pragma weak plat_is_smccc_feature_available
+#pragma weak plat_get_soc_version
+#pragma weak plat_get_soc_revision
+
+int32_t plat_get_soc_version(void)
+{
+ return SMC_ARCH_CALL_NOT_SUPPORTED;
+}
+
+int32_t plat_get_soc_revision(void)
+{
+ return SMC_ARCH_CALL_NOT_SUPPORTED;
+}
+
+int32_t plat_is_smccc_feature_available(u_register_t fid __unused)
+{
+ return SMC_ARCH_CALL_NOT_SUPPORTED;
+}
+
+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;
+}
+
+/*
+ * Weak implementation to provide dummy decryption key only for test purposes,
+ * platforms must override this API for any real world firmware encryption
+ * use-case.
+ */
+int plat_get_enc_key_info(enum fw_enc_status_t fw_enc_status, uint8_t *key,
+ size_t *key_len, unsigned int *flags,
+ const uint8_t *img_id, size_t img_id_len)
+{
+#define DUMMY_FIP_ENC_KEY { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, \
+ 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, \
+ 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, \
+ 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef }
+
+ const uint8_t dummy_key[] = DUMMY_FIP_ENC_KEY;
+
+ assert(*key_len >= sizeof(dummy_key));
+
+ *key_len = sizeof(dummy_key);
+ memcpy(key, dummy_key, *key_len);
+ *flags = 0;
+
+ 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();
+}
diff --git a/plat/common/plat_gicv2.c b/plat/common/plat_gicv2.c
new file mode 100644
index 0000000..0f988dc
--- /dev/null
+++ b/plat/common/plat_gicv2.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Portions copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <bl31/interrupt_mgmt.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <plat/common/platform.h>
+
+/*
+ * 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_raise_ns_sgi
+#pragma weak plat_ic_raise_s_el1_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, false, id);
+#else
+ assert(false);
+#endif
+}
+
+void plat_ic_raise_ns_sgi(int sgi_num, u_register_t target)
+{
+ 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 non-secure SGI */
+ assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_NS);
+
+ gicv2_raise_sgi(sgi_num, true, id);
+}
+
+void plat_ic_raise_s_el1_sgi(int sgi_num, u_register_t target)
+{
+#if GICV2_G0_FOR_EL3
+ assert(false);
+#else
+ 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 EL1 SGI */
+ assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_S_EL1);
+
+ gicv2_raise_sgi(sgi_num, false, id);
+#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;
+}
diff --git a/plat/common/plat_gicv3.c b/plat/common/plat_gicv3.c
new file mode 100644
index 0000000..e1420bb
--- /dev/null
+++ b/plat/common/plat_gicv3.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Portions copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <bl31/interrupt_mgmt.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/cassert.h>
+#include <plat/common/platform.h>
+
+#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_raise_ns_sgi
+#pragma weak plat_ic_raise_s_el1_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_sgi((unsigned int)sgi_num, GICV3_G0, target);
+}
+
+void plat_ic_raise_ns_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 non-secure SGI */
+ assert(plat_ic_get_interrupt_type((unsigned int)sgi_num) ==
+ INTR_TYPE_NS);
+
+ gicv3_raise_sgi((unsigned int)sgi_num, GICV3_G1NS, target);
+}
+
+void plat_ic_raise_s_el1_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 EL1 SGI */
+ assert(plat_ic_get_interrupt_type((unsigned int)sgi_num) ==
+ INTR_TYPE_S_EL1);
+
+ gicv3_raise_sgi((unsigned int)sgi_num, GICV3_G1S, 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
diff --git a/plat/common/plat_log_common.c b/plat/common/plat_log_common.c
new file mode 100644
index 0000000..66b9758
--- /dev/null
+++ b/plat/common/plat_log_common.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+/* 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];
+}
diff --git a/plat/common/plat_psci_common.c b/plat/common/plat_psci_common.c
new file mode 100644
index 0000000..c32e59f
--- /dev/null
+++ b/plat/common/plat_psci_common.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <lib/pmf/pmf.h>
+#include <lib/psci/psci.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+
+#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
+
+/* 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_DECLARE_CAPTURE_TIMESTAMP(psci_svc)
+PMF_DECLARE_GET_TIMESTAMP(psci_svc)
+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.
+ * 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_CACHE_MAINT);
+}
+
+/*
+ * Capture timestamp after exiting a low power state.
+ * 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_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,
+ unsigned 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(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;
+}
diff --git a/plat/common/plat_spmd_manifest.c b/plat/common/plat_spmd_manifest.c
new file mode 100644
index 0000000..b1fc13c
--- /dev/null
+++ b/plat/common/plat_spmd_manifest.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <libfdt.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <platform_def.h>
+#include <services/spm_core_manifest.h>
+
+#define ATTRIBUTE_ROOT_NODE_STR "attribute"
+
+/*******************************************************************************
+ * SPMC attribute node parser
+ ******************************************************************************/
+static int manifest_parse_attribute(spmc_manifest_attribute_t *attr,
+ const void *fdt,
+ int node)
+{
+ uint32_t val32;
+ int rc;
+
+ assert((attr != NULL) && (fdt != NULL));
+
+ rc = fdt_read_uint32(fdt, node, "maj_ver", &attr->major_version);
+ if (rc != 0) {
+ ERROR("Missing FFA %s version in SPM Core manifest.\n",
+ "major");
+ return rc;
+ }
+
+ rc = fdt_read_uint32(fdt, node, "min_ver", &attr->minor_version);
+ if (rc != 0) {
+ ERROR("Missing FFA %s version in SPM Core manifest.\n",
+ "minor");
+ return rc;
+ }
+
+ rc = fdt_read_uint32(fdt, node, "spmc_id", &val32);
+ if (rc != 0) {
+ ERROR("Missing SPMC ID in manifest.\n");
+ return rc;
+ }
+
+ attr->spmc_id = val32 & 0xffff;
+
+ rc = fdt_read_uint32(fdt, node, "exec_state", &attr->exec_state);
+ if (rc != 0) {
+ NOTICE("%s not specified in SPM Core manifest.\n",
+ "Execution state");
+ }
+
+ rc = fdt_read_uint32(fdt, node, "binary_size", &attr->binary_size);
+ if (rc != 0) {
+ NOTICE("%s not specified in SPM Core manifest.\n",
+ "Binary size");
+ }
+
+ rc = fdt_read_uint64(fdt, node, "load_address", &attr->load_address);
+ if (rc != 0) {
+ NOTICE("%s not specified in SPM Core manifest.\n",
+ "Load address");
+ }
+
+ rc = fdt_read_uint64(fdt, node, "entrypoint", &attr->entrypoint);
+ if (rc != 0) {
+ NOTICE("%s not specified in SPM Core manifest.\n",
+ "Entry point");
+ }
+
+ VERBOSE("SPM Core manifest attribute section:\n");
+ VERBOSE(" version: %u.%u\n", attr->major_version, attr->minor_version);
+ VERBOSE(" spmc_id: 0x%x\n", attr->spmc_id);
+ VERBOSE(" binary_size: 0x%x\n", attr->binary_size);
+ VERBOSE(" load_address: 0x%" PRIx64 "\n", attr->load_address);
+ VERBOSE(" entrypoint: 0x%" PRIx64 "\n", attr->entrypoint);
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Root node handler
+ ******************************************************************************/
+static int manifest_parse_root(spmc_manifest_attribute_t *manifest,
+ const void *fdt,
+ int root)
+{
+ int node;
+
+ assert(manifest != NULL);
+
+ node = fdt_subnode_offset_namelen(fdt, root, ATTRIBUTE_ROOT_NODE_STR,
+ sizeof(ATTRIBUTE_ROOT_NODE_STR) - 1);
+ if (node < 0) {
+ ERROR("Root node doesn't contain subnode '%s'\n",
+ ATTRIBUTE_ROOT_NODE_STR);
+ return node;
+ }
+
+ return manifest_parse_attribute(manifest, fdt, node);
+}
+
+/*******************************************************************************
+ * Platform handler to parse a SPM Core manifest.
+ ******************************************************************************/
+int plat_spm_core_manifest_load(spmc_manifest_attribute_t *manifest,
+ const void *pm_addr)
+{
+ int rc, unmap_ret;
+ uintptr_t pm_base, pm_base_align;
+ size_t mapped_size;
+
+ assert(manifest != NULL);
+ assert(pm_addr != NULL);
+
+ /*
+ * Assume TOS_FW_CONFIG is not necessarily aligned to a page
+ * boundary, thus calculate the remaining space between SPMC
+ * manifest start address and upper page limit.
+ *
+ */
+ pm_base = (uintptr_t)pm_addr;
+ pm_base_align = page_align(pm_base, UP);
+
+ if (pm_base == pm_base_align) {
+ /* Page aligned */
+ mapped_size = PAGE_SIZE;
+ } else {
+ mapped_size = pm_base_align - pm_base;
+ }
+
+ /* Check space within the page at least maps the FDT header */
+ if (mapped_size < sizeof(struct fdt_header)) {
+ ERROR("Error while mapping SPM Core manifest.\n");
+ return -EINVAL;
+ }
+
+ /* Map first SPMC manifest page in the SPMD translation regime */
+ pm_base_align = page_align(pm_base, DOWN);
+ rc = mmap_add_dynamic_region((unsigned long long)pm_base_align,
+ pm_base_align,
+ PAGE_SIZE,
+ MT_RO_DATA);
+ if (rc != 0) {
+ ERROR("Error while mapping SPM Core manifest (%d).\n", rc);
+ return rc;
+ }
+
+ rc = fdt_check_header(pm_addr);
+ if (rc != 0) {
+ ERROR("Wrong format for SPM Core manifest (%d).\n", rc);
+ goto exit_unmap;
+ }
+
+ /* Check SPMC manifest fits within the upper mapped page boundary */
+ if (mapped_size < fdt_totalsize(pm_addr)) {
+ ERROR("SPM Core manifest too large.\n");
+ rc = -EINVAL;
+ goto exit_unmap;
+ }
+
+ VERBOSE("Reading SPM Core manifest at address %p\n", pm_addr);
+
+ rc = fdt_node_offset_by_compatible(pm_addr, -1,
+ "arm,ffa-core-manifest-1.0");
+ if (rc < 0) {
+ ERROR("Unrecognized SPM Core manifest\n");
+ goto exit_unmap;
+ }
+
+ rc = manifest_parse_root(manifest, pm_addr, rc);
+
+exit_unmap:
+ unmap_ret = mmap_remove_dynamic_region(pm_base_align, PAGE_SIZE);
+ if (unmap_ret != 0) {
+ ERROR("Error while unmapping SPM Core manifest (%d).\n",
+ unmap_ret);
+ if (rc == 0) {
+ rc = unmap_ret;
+ }
+ }
+
+ return rc;
+}
diff --git a/plat/common/tbbr/plat_tbbr.c b/plat/common/tbbr/plat_tbbr.c
new file mode 100644
index 0000000..12ab0a9
--- /dev/null
+++ b/plat/common/tbbr/plat_tbbr.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <drivers/auth/auth_mod.h>
+#include <plat/common/platform.h>
+#if USE_TBBR_DEFS
+#include <tools_share/tbbr_oid.h>
+#else
+#include <platform_oid.h>
+#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;
+}
diff --git a/plat/common/ubsan.c b/plat/common/ubsan.c
new file mode 100644
index 0000000..45b0f7c
--- /dev/null
+++ b/plat/common/ubsan.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * Copyright (c) 2019, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <arch_helpers.h>
+#include <context.h>
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+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();
+}
diff --git a/plat/hisilicon/hikey/aarch64/hikey_common.c b/plat/hisilicon/hikey/aarch64/hikey_common.c
new file mode 100644
index 0000000..702fc2d
--- /dev/null
+++ b/plat/hisilicon/hikey/aarch64/hikey_common.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.h>
+
+#include <hikey_def.h>
+#include <hikey_layout.h>
+
+#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;
+}
diff --git a/plat/hisilicon/hikey/aarch64/hikey_helpers.S b/plat/hisilicon/hikey/aarch64/hikey_helpers.S
new file mode 100644
index 0000000..82a404a
--- /dev/null
+++ b/plat/hisilicon/hikey/aarch64/hikey_helpers.S
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <hikey_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
+
+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
+
+ /* ---------------------------------------------
+ * void plat_crash_console_flush()
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * Out : void.
+ * 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: "
diff --git a/plat/hisilicon/hikey/hikey_bl1_setup.c b/plat/hisilicon/hikey/hikey_bl1_setup.c
new file mode 100644
index 0000000..31ff820
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_bl1_setup.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <bl1/tbbr/tbbr_img_desc.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/mmc.h>
+#include <drivers/synopsys/dw_mmc.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <hi6220.h>
+#include <hikey_def.h>
+#include <hikey_layout.h>
+
+#include "hikey_private.h"
+
+/* Data structure which holds the extents of the trusted RAM for BL1 */
+static meminfo_t bl1_tzram_layout;
+static console_t console;
+static struct mmc_device_info mmc_info;
+
+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;
+
+ 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(&params, 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;
+ mmc_info.mmc_dev_type = MMC_IS_EMMC;
+ dw_mmc_init(&params, &mmc_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%" PRIx64 "\n", data);
+
+ ep_info->args.arg0 = 0xffff & read_mpidr();
+ ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS);
+}
diff --git a/plat/hisilicon/hikey/hikey_bl2_mem_params_desc.c b/plat/hisilicon/hikey/hikey_bl2_mem_params_desc.c
new file mode 100644
index 0000000..d029703
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_bl2_mem_params_desc.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h> /* also includes hikey_def.h and hikey_layout.h*/
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * 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)
diff --git a/plat/hisilicon/hikey/hikey_bl2_setup.c b/plat/hisilicon/hikey/hikey_bl2_setup.c
new file mode 100644
index 0000000..a90f12c
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_bl2_setup.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h> /* also includes hikey_def.h and hikey_layout.h*/
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/delay_timer.h>
+#include <drivers/mmc.h>
+#include <drivers/synopsys/dw_mmc.h>
+#include <lib/mmio.h>
+#ifdef SPD_opteed
+#include <lib/optee_utils.h>
+#endif
+#include <plat/common/platform.h>
+
+#include <hi6220.h>
+#include <hisi_mcu.h>
+#include <hisi_sram_map.h>
+#include "hikey_private.h"
+
+#define BL2_RW_BASE (BL_CODE_END)
+
+static meminfo_t bl2_el3_tzram_layout;
+static console_t console;
+static struct mmc_device_info mmc_info;
+
+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;
+
+ 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(&params, 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;
+ mmc_info.mmc_dev_type = MMC_IS_EMMC;
+ dw_mmc_init(&params, &mmc_info);
+
+ hikey_io_setup();
+}
diff --git a/plat/hisilicon/hikey/hikey_bl31_setup.c b/plat/hisilicon/hikey/hikey_bl31_setup.c
new file mode 100644
index 0000000..7d008e7
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_bl31_setup.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/pl011.h>
+#include <lib/mmio.h>
+
+#include <hi6220.h>
+#include <hikey_def.h>
+#include <hisi_ipc.h>
+#include <hisi_pwrc.h>
+
+#include "hikey_private.h"
+
+static entry_point_info_t bl32_ep_info;
+static entry_point_info_t bl33_ep_info;
+static console_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)
+{
+}
diff --git a/plat/hisilicon/hikey/hikey_bl_common.c b/plat/hisilicon/hikey/hikey_bl_common.c
new file mode 100644
index 0000000..d062de4
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_bl_common.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <drivers/arm/pl061_gpio.h>
+#include <drivers/arm/sp804_delay_timer.h>
+#include <drivers/gpio.h>
+#include <lib/mmio.h>
+
+#include <hi6220.h>
+#include <hi6553.h>
+#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);
+}
diff --git a/plat/hisilicon/hikey/hikey_ddr.c b/plat/hisilicon/hikey/hikey_ddr.c
new file mode 100644
index 0000000..cd9e9a2
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_ddr.c
@@ -0,0 +1,1451 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/sp804_delay_timer.h>
+#include <lib/mmio.h>
+
+#include <hi6220.h>
+#include <hi6553.h>
+#include <hisi_sram_map.h>
+#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();
+}
diff --git a/plat/hisilicon/hikey/hikey_image_load.c b/plat/hisilicon/hikey/hikey_image_load.c
new file mode 100644
index 0000000..0ab1ca4
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_image_load.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.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();
+}
diff --git a/plat/hisilicon/hikey/hikey_io_storage.c b/plat/hisilicon/hikey/hikey_io_storage.c
new file mode 100644
index 0000000..fd610d8
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_io_storage.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/mmc.h>
+#include <drivers/partition/partition.h>
+#include <lib/mmio.h>
+#include <lib/semihosting.h>
+#include <tools_share/firmware_image_package.h>
+
+#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;
+}
diff --git a/plat/hisilicon/hikey/hikey_pm.c b/plat/hisilicon/hikey/hikey_pm.c
new file mode 100644
index 0000000..05c1e7f
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_pm.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/sp804_delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <hi6220.h>
+#include <hikey_def.h>
+#include <hisi_ipc.h>
+#include <hisi_pwrc.h>
+#include <hisi_sram_map.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])
+
+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;
+}
diff --git a/plat/hisilicon/hikey/hikey_private.h b/plat/hisilicon/hikey/hikey_private.h
new file mode 100644
index 0000000..b75bc72
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_private.h
@@ -0,0 +1,77 @@
+/*
+ * 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 <common/bl_common.h>
+
+#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 */
diff --git a/plat/hisilicon/hikey/hikey_rotpk.S b/plat/hisilicon/hikey/hikey_rotpk.S
new file mode 100644
index 0000000..f308eee
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_rotpk.S
@@ -0,0 +1,16 @@
+/*
+ * 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:
diff --git a/plat/hisilicon/hikey/hikey_security.c b/plat/hisilicon/hikey/hikey_security.c
new file mode 100644
index 0000000..4b95939
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_security.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/utils_def.h>
+
+#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);
+}
diff --git a/plat/hisilicon/hikey/hikey_tbbr.c b/plat/hisilicon/hikey/hikey_tbbr.c
new file mode 100644
index 0000000..b7dda8d
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_tbbr.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+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);
+}
diff --git a/plat/hisilicon/hikey/hikey_topology.c b/plat/hisilicon/hikey/hikey_topology.c
new file mode 100644
index 0000000..7890eb7
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_topology.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <lib/psci/psci.h>
+
+/*
+ * 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));
+}
diff --git a/plat/hisilicon/hikey/hisi_dvfs.c b/plat/hisilicon/hikey/hisi_dvfs.c
new file mode 100644
index 0000000..22a67fd
--- /dev/null
+++ b/plat/hisilicon/hikey/hisi_dvfs.c
@@ -0,0 +1,781 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <hi6220.h>
+#include <hi6553.h>
+#include <hisi_sram_map.h>
+
+#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();
+}
diff --git a/plat/hisilicon/hikey/hisi_ipc.c b/plat/hisilicon/hikey/hisi_ipc.c
new file mode 100644
index 0000000..43ee0b2
--- /dev/null
+++ b/plat/hisilicon/hikey/hisi_ipc.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <hisi_ipc.h>
+#include <hisi_sram_map.h>
+
+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;
+}
diff --git a/plat/hisilicon/hikey/hisi_mcu.c b/plat/hisilicon/hikey/hisi_mcu.c
new file mode 100644
index 0000000..ac83bd8
--- /dev/null
+++ b/plat/hisilicon/hikey/hisi_mcu.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <hi6220.h>
+
+#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;
+}
diff --git a/plat/hisilicon/hikey/hisi_pwrc.c b/plat/hisilicon/hikey/hisi_pwrc.c
new file mode 100644
index 0000000..e2e3db7
--- /dev/null
+++ b/plat/hisilicon/hikey/hisi_pwrc.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <hi6220_regs_acpu.h>
+#include <hi6220_regs_ao.h>
+#include <hisi_ipc.h>
+#include <hisi_pwrc.h>
+#include <hisi_sram_map.h>
+
+#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;
+}
diff --git a/plat/hisilicon/hikey/hisi_pwrc_sram.S b/plat/hisilicon/hikey/hisi_pwrc_sram.S
new file mode 100644
index 0000000..62542f2
--- /dev/null
+++ b/plat/hisilicon/hikey/hisi_pwrc_sram.S
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cortex_a53.h>
+#include <hi6220.h>
+#include <hisi_sram_map.h>
+
+ .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:
diff --git a/plat/hisilicon/hikey/hisi_sip_svc.c b/plat/hisilicon/hikey/hisi_sip_svc.c
new file mode 100644
index 0000000..3cd1bd0
--- /dev/null
+++ b/plat/hisilicon/hikey/hisi_sip_svc.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/pmf/pmf.h>
+#include <tools_share/uuid.h>
+
+#include <hisi_sip_svc.h>
+
+/* 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
+);
diff --git a/plat/hisilicon/hikey/include/hi6220.h b/plat/hisilicon/hikey/include/hi6220.h
new file mode 100644
index 0000000..f67ee5c
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hi6220.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HI6220_H
+#define HI6220_H
+
+#include <hi6220_regs_acpu.h>
+#include <hi6220_regs_ao.h>
+#include <hi6220_regs_peri.h>
+#include <hi6220_regs_pin.h>
+#include <hi6220_regs_pmctrl.h>
+
+/*******************************************************************************
+ * 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 */
diff --git a/plat/hisilicon/hikey/include/hi6220_regs_acpu.h b/plat/hisilicon/hikey/include/hi6220_regs_acpu.h
new file mode 100644
index 0000000..a43db68
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hi6220_regs_acpu.h
@@ -0,0 +1,300 @@
+/*
+ * 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 */
diff --git a/plat/hisilicon/hikey/include/hi6220_regs_ao.h b/plat/hisilicon/hikey/include/hi6220_regs_ao.h
new file mode 100644
index 0000000..614eba2
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hi6220_regs_ao.h
@@ -0,0 +1,334 @@
+/*
+ * 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 */
diff --git a/plat/hisilicon/hikey/include/hi6220_regs_peri.h b/plat/hisilicon/hikey/include/hi6220_regs_peri.h
new file mode 100644
index 0000000..77236e8
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hi6220_regs_peri.h
@@ -0,0 +1,380 @@
+/*
+ * 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 */
diff --git a/plat/hisilicon/hikey/include/hi6220_regs_pin.h b/plat/hisilicon/hikey/include/hi6220_regs_pin.h
new file mode 100644
index 0000000..05620ea
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hi6220_regs_pin.h
@@ -0,0 +1,43 @@
+/*
+ * 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 */
diff --git a/plat/hisilicon/hikey/include/hi6220_regs_pmctrl.h b/plat/hisilicon/hikey/include/hi6220_regs_pmctrl.h
new file mode 100644
index 0000000..404405b
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hi6220_regs_pmctrl.h
@@ -0,0 +1,101 @@
+/*
+ * 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 */
diff --git a/plat/hisilicon/hikey/include/hi6553.h b/plat/hisilicon/hikey/include/hi6553.h
new file mode 100644
index 0000000..fc991f8
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hi6553.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HI6553_H
+#define HI6553_H
+
+#include <lib/mmio.h>
+
+#include <hi6220.h>
+
+#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 */
diff --git a/plat/hisilicon/hikey/include/hikey_def.h b/plat/hisilicon/hikey/include/hikey_def.h
new file mode 100644
index 0000000..590700d
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hikey_def.h
@@ -0,0 +1,106 @@
+/*
+ * 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 */
diff --git a/plat/hisilicon/hikey/include/hikey_layout.h b/plat/hisilicon/hikey/include/hikey_layout.h
new file mode 100644
index 0000000..4b8dc53
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hikey_layout.h
@@ -0,0 +1,122 @@
+/*
+ * 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 */
diff --git a/plat/hisilicon/hikey/include/hisi_ipc.h b/plat/hisilicon/hikey/include/hisi_ipc.h
new file mode 100644
index 0000000..b0c0ae8
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hisi_ipc.h
@@ -0,0 +1,46 @@
+/*
+ * 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 */
diff --git a/plat/hisilicon/hikey/include/hisi_mcu.h b/plat/hisilicon/hikey/include/hisi_mcu.h
new file mode 100644
index 0000000..731c51a
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hisi_mcu.h
@@ -0,0 +1,16 @@
+/*
+ * 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 <stdint.h>
+
+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 */
diff --git a/plat/hisilicon/hikey/include/hisi_pwrc.h b/plat/hisilicon/hikey/include/hisi_pwrc.h
new file mode 100644
index 0000000..cbb4651
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hisi_pwrc.h
@@ -0,0 +1,22 @@
+/*
+ * 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 */
diff --git a/plat/hisilicon/hikey/include/hisi_sip_svc.h b/plat/hisilicon/hikey/include/hisi_sip_svc.h
new file mode 100644
index 0000000..a1fad7a
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hisi_sip_svc.h
@@ -0,0 +1,21 @@
+/*
+ * 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 */
diff --git a/plat/hisilicon/hikey/include/hisi_sram_map.h b/plat/hisilicon/hikey/include/hisi_sram_map.h
new file mode 100644
index 0000000..f93e418
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hisi_sram_map.h
@@ -0,0 +1,327 @@
+/*
+ * 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 */
diff --git a/plat/hisilicon/hikey/include/plat_macros.S b/plat/hisilicon/hikey/include/plat_macros.S
new file mode 100644
index 0000000..9cd276a
--- /dev/null
+++ b/plat/hisilicon/hikey/include/plat_macros.S
@@ -0,0 +1,78 @@
+/*
+ * 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 <drivers/arm/cci.h>
+#include <drivers/arm/gicv2.h>
+#include <hi6220.h>
+#include <platform_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"
+
+.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 */
diff --git a/plat/hisilicon/hikey/include/platform_def.h b/plat/hisilicon/hikey/include/platform_def.h
new file mode 100644
index 0000000..04ea71f
--- /dev/null
+++ b/plat/hisilicon/hikey/include/platform_def.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#include <hikey_def.h>
+#include <hikey_layout.h> /* 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 U(2)
+#define PLATFORM_CORE_COUNT_PER_CLUSTER U(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 + U(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 */
diff --git a/plat/hisilicon/hikey/platform.mk b/plat/hisilicon/hikey/platform.mk
new file mode 100644
index 0000000..2bfc582
--- /dev/null
+++ b/plat/hisilicon/hikey/platform.mk
@@ -0,0 +1,172 @@
+#
+# Copyright (c) 2017-2022, 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
+
+include lib/zlib/zlib.mk
+PLAT_INCLUDES += -Ilib/zlib
+BL2_SOURCES += $(ZLIB_SOURCES)
+
+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_common.c
+
+BL1_SOURCES += ${AUTH_SOURCES} \
+ plat/common/tbbr/plat_tbbr.c \
+ plat/hisilicon/hikey/hikey_tbbr.c \
+ plat/hisilicon/hikey/hikey_rotpk.S \
+ drivers/auth/tbbr/tbbr_cot_bl1.c
+
+BL2_SOURCES += ${AUTH_SOURCES} \
+ plat/common/tbbr/plat_tbbr.c \
+ plat/hisilicon/hikey/hikey_tbbr.c \
+ plat/hisilicon/hikey/hikey_rotpk.S \
+ drivers/auth/tbbr/tbbr_cot_bl2.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)/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_BIN_PATH}/openssl genrsa 2048 > $@ 2>/dev/null
+
+$(ROTPK_HASH): $(ROT_KEY)
+ @echo " OPENSSL $@"
+ $(Q)${OPENSSL_BIN_PATH}/openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+ ${OPENSSL_BIN_PATH}/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
diff --git a/plat/hisilicon/hikey960/aarch64/hikey960_common.c b/plat/hisilicon/hikey960/aarch64/hikey960_common.c
new file mode 100644
index 0000000..c70286f
--- /dev/null
+++ b/plat/hisilicon/hikey960/aarch64/hikey960_common.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#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,
+ {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;
+}
diff --git a/plat/hisilicon/hikey960/aarch64/hikey960_helpers.S b/plat/hisilicon/hikey960/aarch64/hikey960_helpers.S
new file mode 100644
index 0000000..5381369
--- /dev/null
+++ b/plat/hisilicon/hikey960/aarch64/hikey960_helpers.S
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cortex_a53.h>
+#include <cortex_a73.h>
+#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
+
+ /* ---------------------------------------------
+ * void plat_crash_console_flush()
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * Out : void.
+ * 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: "
diff --git a/plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c b/plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c
new file mode 100644
index 0000000..a6a4949
--- /dev/null
+++ b/plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <hi3660.h>
+#include <hisi_ipc.h>
+#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;
+}
diff --git a/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c
new file mode 100644
index 0000000..91d8033
--- /dev/null
+++ b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <../hikey960_def.h>
+#include <hisi_ipc.h>
+#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);
+}
diff --git a/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h
new file mode 100644
index 0000000..e0cb381
--- /dev/null
+++ b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h
@@ -0,0 +1,57 @@
+/*
+ * 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 <hi3660.h>
+#include <hi3660_crg.h>
+
+#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 */
diff --git a/plat/hisilicon/hikey960/hikey960_bl1_setup.c b/plat/hisilicon/hikey960/hikey960_bl1_setup.c
new file mode 100644
index 0000000..0a2d062
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_bl1_setup.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl1/tbbr/tbbr_img_desc.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/delay_timer.h>
+#include <drivers/dw_ufs.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/ufs.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <hi3660.h>
+#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_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);
+}
diff --git a/plat/hisilicon/hikey960/hikey960_bl2_mem_params_desc.c b/plat/hisilicon/hikey960/hikey960_bl2_mem_params_desc.c
new file mode 100644
index 0000000..e42785a
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_bl2_mem_params_desc.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * 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,
+ },
+
+#ifdef SPD_spmd
+ /* 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, 0),
+ .image_info.image_base = DDR_SEC_CONFIG_BASE,
+ .image_info.image_max_size = DDR_SEC_CONFIG_SIZE,
+
+ .next_handoff_image_id = INVALID_IMAGE_ID,
+ },
+#endif
+
+# 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)
diff --git a/plat/hisilicon/hikey960/hikey960_bl2_setup.c b/plat/hisilicon/hikey960/hikey960_bl2_setup.c
new file mode 100644
index 0000000..7334853
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_bl2_setup.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/delay_timer.h>
+#include <drivers/dw_ufs.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/partition/partition.h>
+#include <drivers/ufs.h>
+#include <lib/mmio.h>
+#ifdef SPD_opteed
+#include <lib/optee_utils.h>
+#endif
+
+#include <hi3660.h>
+#include "hikey960_def.h"
+#include "hikey960_private.h"
+
+#define BL2_RW_BASE (BL_CODE_END)
+
+/* BL2 platform parameters passed to BL31 */
+static plat_params_from_bl2_t plat_params_from_bl2;
+
+static meminfo_t bl2_el3_tzram_layout;
+static console_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) {
+ case BL31_IMAGE_ID:
+ /* Pass BL2 platform parameter to BL31 */
+ bl_mem_params->ep_info.args.arg1 = (uint64_t) &plat_params_from_bl2;
+ break;
+
+#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)
+{
+ int ret;
+
+ /* 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();
+
+ /* Read serial number from storage */
+ plat_params_from_bl2.fastboot_serno = 0;
+ ret = hikey960_load_serialno(&plat_params_from_bl2.fastboot_serno);
+ if (ret != 0) {
+ ERROR("BL2: could not read serial number\n");
+ }
+ INFO("BL2: fastboot_serno %lx\n", plat_params_from_bl2.fastboot_serno);
+ flush_dcache_range((uintptr_t)&plat_params_from_bl2, sizeof(plat_params_from_bl2_t));
+}
diff --git a/plat/hisilicon/hikey960/hikey960_bl31_setup.c b/plat/hisilicon/hikey960/hikey960_bl31_setup.c
new file mode 100644
index 0000000..0debe1e
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_bl31_setup.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#include <services/el3_spmc_ffa_memory.h>
+
+#include <hi3660.h>
+#include <hisi_ipc.h>
+#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_t console;
+
+/* fastboot serial number consumed by Kinibi SPD/LP for gpd.tee.deviceID. */
+uint64_t fastboot_serno;
+
+/******************************************************************************
+ * 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;
+ plat_params_from_bl2_t *plat_params_from_bl2 = (plat_params_from_bl2_t *) arg1;
+
+ 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()));
+
+ /* Fastboot serial number passed from BL2 as a platform parameter */
+ fastboot_serno = plat_params_from_bl2->fastboot_serno;
+ INFO("BL31: fastboot_serno %lx\n", fastboot_serno);
+
+ /*
+ * 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)
+{
+#if SPMC_AT_EL3
+ mmap_add_region(DDR2_SEC_BASE, DDR2_SEC_BASE, DDR2_SEC_SIZE,
+ MT_MEMORY | MT_RW | MT_SECURE);
+#endif
+
+ 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);
+ }
+}
+
+#if SPMC_AT_EL3
+/*
+ * On the hikey960 platform when using the EL3 SPMC implementation allocate the
+ * datastore for tracking shared memory descriptors in the RAM2 DRAM section
+ * to ensure sufficient storage can be allocated.
+ * Provide an implementation of the accessor method to allow the datastore
+ * details to be retrieved by the SPMC.
+ * The SPMC will take care of initializing the memory region.
+ */
+
+#define SPMC_SHARED_MEMORY_OBJ_SIZE (512 * 1024)
+
+__section("ram2_region") uint8_t plat_spmc_shmem_datastore[SPMC_SHARED_MEMORY_OBJ_SIZE];
+
+int plat_spmc_shmem_datastore_get(uint8_t **datastore, size_t *size)
+{
+ *datastore = plat_spmc_shmem_datastore;
+ *size = SPMC_SHARED_MEMORY_OBJ_SIZE;
+ return 0;
+}
+
+/*
+ * Add dummy implementations of memory management related platform hooks.
+ * These can be used to implement platform specific functionality to support
+ * a memory sharing/lending operation.
+ *
+ * Note: The hooks must be located as part of the initial share request and
+ * final reclaim to prevent order dependencies with operations that may take
+ * place in the normal world without visibility of the SPMC.
+ */
+int plat_spmc_shmem_begin(struct ffa_mtd *desc)
+{
+ return 0;
+}
+
+int plat_spmc_shmem_reclaim(struct ffa_mtd *desc)
+{
+ return 0;
+}
+
+#endif
+
+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();
+ hikey960_gpio_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
+}
diff --git a/plat/hisilicon/hikey960/hikey960_bl_common.c b/plat/hisilicon/hikey960/hikey960_bl_common.c
new file mode 100644
index 0000000..3c4a164
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_bl_common.c
@@ -0,0 +1,480 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/arm/pl061_gpio.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <hi3660.h>
+#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);
+ pl061_gpio_register(GPIO22_BASE, 22);
+ pl061_gpio_register(GPIO23_BASE, 23);
+ pl061_gpio_register(GPIO24_BASE, 24);
+ pl061_gpio_register(GPIO25_BASE, 25);
+ pl061_gpio_register(GPIO26_BASE, 26);
+ pl061_gpio_register(GPIO27_BASE, 27);
+ pl061_gpio_register(GPIO28_BASE, 28);
+
+ /* PCIE_PERST_N output low */
+ gpio_set_direction(89, GPIO_DIR_OUT);
+ gpio_set_value(89, GPIO_LEVEL_LOW);
+}
diff --git a/plat/hisilicon/hikey960/hikey960_boardid.c b/plat/hisilicon/hikey960/hikey960_boardid.c
new file mode 100644
index 0000000..1e1126f
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_boardid.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <hi3660.h>
+#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;
+}
diff --git a/plat/hisilicon/hikey960/hikey960_def.h b/plat/hisilicon/hikey960/hikey960_def.h
new file mode 100644
index 0000000..e103cf4
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_def.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HIKEY960_DEF_H
+#define HIKEY960_DEF_H
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <plat/common/common_def.h>
+
+#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 TEE (80MB from 0x3E00000-0x43000FFF) is divided into several
+ * regions:
+ * - SPMC manifest (4KB at the top) used by SPMC_AT_EL3 and the TEE
+ * - Datastore for SPMC_AT_EL3 (4MB at the top) used by BL31
+ * - Secure DDR (default is the top 60MB) 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 0x03C00000 /* reserve 60MB secure memory */
+#define DDR_SEC_BASE 0x3F000000
+#define DDR2_SEC_SIZE 0x00400000 /* SPMC_AT_EL3: 4MB for BL31 RAM2 */
+#define DDR2_SEC_BASE 0x42C00000
+#define DDR_SEC_CONFIG_SIZE 0x00001000 /* SPMC_AT_EL3: SPMC manifest */
+#define DDR_SEC_CONFIG_BASE 0x43000000
+
+#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 */
+
+#if defined(SPMC_AT_EL3)
+/*
+ * Number of Secure Partitions supported.
+ * SPMC at EL3, uses this count to configure the maximum number of supported
+ * secure partitions.
+ */
+#define SECURE_PARTITION_COUNT 1
+
+/*
+ * Number of Nwld Partitions supported.
+ * SPMC at EL3, uses this count to configure the maximum number of supported
+ * nwld partitions.
+ */
+#define NS_PARTITION_COUNT 1
+/*
+ * Number of Logical Partitions supported.
+ * SPMC at EL3, uses this count to configure the maximum number of supported
+ * logical partitions.
+ */
+#define MAX_EL3_LP_DESCS_COUNT 1
+
+#endif /* SPMC_AT_EL3 */
+
+#endif /* HIKEY960_DEF_H */
diff --git a/plat/hisilicon/hikey960/hikey960_el3_spmc_logical_sp.c b/plat/hisilicon/hikey960/hikey960_el3_spmc_logical_sp.c
new file mode 100644
index 0000000..b9e4f86
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_el3_spmc_logical_sp.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <services/el3_spmc_logical_sp.h>
+#include <services/ffa_svc.h>
+#include <smccc_helpers.h>
+
+#define LP_PARTITION_ID 0xC001
+#define LP_UUID {0x47a3bf57, 0xe98e43ad, 0xb7db524f, 0x1588f4e3}
+
+/* Our Logical SP currently only supports receipt of direct messaging. */
+#define PARTITION_PROPERTIES FFA_PARTITION_DIRECT_REQ_RECV
+
+static int32_t sp_init(void)
+{
+ INFO("LSP: Init function called.\n");
+ return 0;
+}
+
+static uint64_t handle_ffa_direct_request(uint32_t smc_fid, bool secure_origin,
+ uint64_t x1, uint64_t x2, uint64_t x3,
+ uint64_t x4, void *cookie,
+ void *handle, uint64_t flags)
+{
+ uint64_t ret;
+
+ /* Determine if we have a 64 or 32 direct request. */
+ if (smc_fid == FFA_MSG_SEND_DIRECT_REQ_SMC32) {
+ ret = FFA_MSG_SEND_DIRECT_RESP_SMC32;
+ } else if (smc_fid == FFA_MSG_SEND_DIRECT_REQ_SMC64) {
+ ret = FFA_MSG_SEND_DIRECT_RESP_SMC64;
+ } else {
+ panic(); /* Unknown SMC. */
+ }
+ /*
+ * Handle the incoming request. For testing purposes we echo the
+ * incoming message.
+ */
+ INFO("Logical Partition: Received Direct Request from %s world!\n",
+ secure_origin ? "Secure" : "Normal");
+
+ /*
+ * Logical SP's must always send a direct response so we can populate
+ * our response directly.
+ */
+ SMC_RET8(handle, ret, 0, 0, x4, 0, 0, 0, 0);
+}
+
+/* Register logical partition */
+DECLARE_LOGICAL_PARTITION(
+ my_logical_partition,
+ sp_init, /* Init Function */
+ LP_PARTITION_ID, /* FF-A Partition ID */
+ LP_UUID, /* UUID */
+ PARTITION_PROPERTIES, /* Partition Properties. */
+ handle_ffa_direct_request /* Callback for direct requests. */
+);
diff --git a/plat/hisilicon/hikey960/hikey960_image_load.c b/plat/hisilicon/hikey960/hikey960_image_load.c
new file mode 100644
index 0000000..9a5b74e
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_image_load.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.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();
+}
+
+
+/*******************************************************************************
+ * 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 *hikey960_get_next_bl_params(void)
+{
+ bl_params_t *next_bl_params;
+
+ next_bl_params = get_next_bl_params_from_mem_params_desc();
+ assert(next_bl_params != NULL);
+
+ populate_next_bl_params_config(next_bl_params);
+
+ return next_bl_params;
+}
+
+
+/*******************************************************************************
+ * This function returns the list of executable images.
+ ******************************************************************************/
+bl_params_t *plat_get_next_bl_params(void)
+{
+ return hikey960_get_next_bl_params();
+}
diff --git a/plat/hisilicon/hikey960/hikey960_io_storage.c b/plat/hisilicon/hikey960/hikey960_io_storage.c
new file mode 100644
index 0000000..475e416
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_io_storage.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/ufs.h>
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/partition/partition.h>
+#include <lib/mmio.h>
+#include <lib/semihosting.h>
+#include <tools_share/firmware_image_package.h>
+
+#include "hikey960_def.h"
+#include "hikey960_private.h"
+
+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),
+};
+
+/* Fastboot serial number stored within first UFS device blocks */
+static const io_block_spec_t ufs_fastboot_spec = {
+ .offset = UFS_BASE,
+ .length = 1 << 20,
+};
+
+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,
+};
+
+#ifdef SPD_spmd
+static const io_uuid_spec_t bl32_tos_fw_spec = {
+ .uuid = UUID_TOS_FW_CONFIG,
+};
+#endif
+
+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
+ },
+
+#ifdef SPD_spmd
+ [TOS_FW_CONFIG_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&bl32_tos_fw_spec,
+ check_fip
+ },
+#endif
+
+ [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;
+}
+
+int hikey960_load_serialno(uint64_t *serno)
+{
+ int result;
+ size_t len = 0;
+ uintptr_t local_handle;
+ uint64_t buf[HIKEY960_SERIAL_NUMBER_SIZE / sizeof(uint64_t)];
+
+ if (serno == NULL) {
+ return -1;
+ }
+
+ result = io_dev_init(ufs_dev_handle, (uintptr_t)NULL);
+ if (result != 0) {
+ return result;
+ }
+
+ result = io_open(ufs_dev_handle,
+ (uintptr_t)&ufs_fastboot_spec, &local_handle);
+ if (result != 0) {
+ return result;
+ }
+
+ result = io_seek(local_handle, IO_SEEK_SET,
+ HIKEY960_SERIAL_NUMBER_LBA * UFS_BLOCK_SIZE);
+ if (result != 0) {
+ goto closing;
+ }
+
+ result = io_read(local_handle, (uintptr_t)buf,
+ HIKEY960_SERIAL_NUMBER_SIZE, &len);
+ if (result != 0) {
+ goto closing;
+ }
+
+ if (len != HIKEY960_SERIAL_NUMBER_SIZE) {
+ result = -1;
+ goto closing;
+ }
+
+ /* UEFI fastboot app stores a 16 bytes blob */
+ /* We extract only relevant 8 bytes serial number */
+ *serno = buf[1];
+
+closing:
+ io_close(local_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);
+}
diff --git a/plat/hisilicon/hikey960/hikey960_mcu_load.c b/plat/hisilicon/hikey960/hikey960_mcu_load.c
new file mode 100644
index 0000000..b9ae313
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_mcu_load.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <hi3660.h>
+
+#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;
+}
diff --git a/plat/hisilicon/hikey960/hikey960_pm.c b/plat/hisilicon/hikey960/hikey960_pm.c
new file mode 100644
index 0000000..f836508
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_pm.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/arm/pl061_gpio.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <hi3660.h>
+#include <hi3660_crg.h>
+
+#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_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_off(void)
+{
+ gpio_set_direction(176, GPIO_DIR_OUT);
+ gpio_set_value(176, GPIO_LEVEL_LOW);
+ panic();
+}
+
+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 = hikey960_system_off,
+ .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;
+}
diff --git a/plat/hisilicon/hikey960/hikey960_private.h b/plat/hisilicon/hikey960/hikey960_private.h
new file mode 100644
index 0000000..742725c
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_private.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HIKEY960_PRIVATE_H
+#define HIKEY960_PRIVATE_H
+
+#include <common/bl_common.h>
+
+/* Fastboot serial number */
+#define HIKEY960_SERIAL_NUMBER_LBA (UFS_BASE + 20)
+#define HIKEY960_SERIAL_NUMBER_SIZE 16
+
+/*
+ * 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);
+int hikey960_load_serialno(uint64_t *serno);
+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);
+
+/*******************************************************************************
+ * Struct for parameters received from BL2
+ ******************************************************************************/
+typedef struct plat_params_from_bl2 {
+ /* Fastboot serial number gathered from UFS */
+ uint64_t fastboot_serno;
+} plat_params_from_bl2_t;
+
+#endif /* HIKEY960_PRIVATE_H */
diff --git a/plat/hisilicon/hikey960/hikey960_rotpk.S b/plat/hisilicon/hikey960/hikey960_rotpk.S
new file mode 100644
index 0000000..f230ed6
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_rotpk.S
@@ -0,0 +1,16 @@
+/*
+ * 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:
diff --git a/plat/hisilicon/hikey960/hikey960_tbbr.c b/plat/hisilicon/hikey960/hikey960_tbbr.c
new file mode 100644
index 0000000..ed4da3b
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_tbbr.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+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);
+}
diff --git a/plat/hisilicon/hikey960/hikey960_topology.c b/plat/hisilicon/hikey960/hikey960_topology.c
new file mode 100644
index 0000000..a242bb1
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_topology.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <lib/psci/psci.h>
+
+/*
+ * 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));
+}
diff --git a/plat/hisilicon/hikey960/include/hi3660.h b/plat/hisilicon/hikey960/include/hi3660.h
new file mode 100644
index 0000000..17b495f
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660.h
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef HI3660_H
+#define HI3660_H
+
+#include <hi3660_crg.h>
+#include <hi3660_hkadc.h>
+#include <hi3660_mem_map.h>
+
+#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 GPIO22_BASE UL(0xFFF0B000)
+#define GPIO23_BASE UL(0xFFF0C000)
+#define GPIO24_BASE UL(0xFFF0D000)
+#define GPIO25_BASE UL(0xFFF0E000)
+#define GPIO26_BASE UL(0xFFF0F000)
+#define GPIO27_BASE UL(0xFFF10000)
+#define GPIO28_BASE UL(0xFFF1D000)
+
+#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 */
diff --git a/plat/hisilicon/hikey960/include/hi3660_crg.h b/plat/hisilicon/hikey960/include/hi3660_crg.h
new file mode 100644
index 0000000..eb5a6c5
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660_crg.h
@@ -0,0 +1,179 @@
+/*
+ * 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 */
diff --git a/plat/hisilicon/hikey960/include/hi3660_hkadc.h b/plat/hisilicon/hikey960/include/hi3660_hkadc.h
new file mode 100644
index 0000000..dc9e813
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660_hkadc.h
@@ -0,0 +1,61 @@
+/*
+ * 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 */
diff --git a/plat/hisilicon/hikey960/include/hi3660_mem_map.h b/plat/hisilicon/hikey960/include/hi3660_mem_map.h
new file mode 100644
index 0000000..cadc4a4
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660_mem_map.h
@@ -0,0 +1,20 @@
+/*
+ * 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 */
diff --git a/plat/hisilicon/hikey960/include/hisi_ipc.h b/plat/hisilicon/hikey960/include/hisi_ipc.h
new file mode 100644
index 0000000..6a97968
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hisi_ipc.h
@@ -0,0 +1,24 @@
+/*
+ * 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 */
diff --git a/plat/hisilicon/hikey960/include/plat.ld.S b/plat/hisilicon/hikey960/include/plat.ld.S
new file mode 100644
index 0000000..0cc25cd
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/plat.ld.S
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_LD_S
+#define PLAT_LD_S
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+MEMORY {
+ RAM2 (rw): ORIGIN = DDR2_SEC_BASE, LENGTH = DDR2_SEC_SIZE
+}
+
+SECTIONS
+{
+ ram2_region (NOLOAD) : {
+ *(ram2_region)
+ }>RAM2
+}
+
+#endif /* PLAT_LD_S */
diff --git a/plat/hisilicon/hikey960/include/plat_macros.S b/plat/hisilicon/hikey960/include/plat_macros.S
new file mode 100644
index 0000000..8765562
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/plat_macros.S
@@ -0,0 +1,78 @@
+/*
+ * 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 <drivers/arm/cci.h>
+#include <drivers/arm/gicv2.h>
+#include <hi3660.h>
+#include <platform_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"
+
+.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 */
diff --git a/plat/hisilicon/hikey960/include/platform_def.h b/plat/hisilicon/hikey960/include/platform_def.h
new file mode 100644
index 0000000..10eff01
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/platform_def.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <lib/utils_def.h>
+
+#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 U(2)
+#define PLATFORM_CORE_COUNT_PER_CLUSTER U(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 << 36)
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 36)
+
+#if defined(IMAGE_BL1) || defined(IMAGE_BL32)
+#define MAX_XLAT_TABLES 3
+#endif
+
+#if defined(IMAGE_BL2)
+#define MAX_XLAT_TABLES 5
+#endif
+
+#if defined(IMAGE_BL31)
+#if defined(SPMC_AT_EL3)
+#define MAX_XLAT_TABLES 17
+#else
+#define MAX_XLAT_TABLES 5
+#endif
+#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 */
diff --git a/plat/hisilicon/hikey960/platform.mk b/plat/hisilicon/hikey960/platform.mk
new file mode 100644
index 0000000..4c3c817
--- /dev/null
+++ b/plat/hisilicon/hikey960/platform.mk
@@ -0,0 +1,182 @@
+#
+# Copyright (c) 2017-2022, 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 := 232
+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 \
+ plat/hisilicon/hikey960/aarch64/hikey960_common.c \
+ plat/hisilicon/hikey960/hikey960_boardid.c
+
+include lib/xlat_tables_v2/xlat_tables.mk
+PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS}
+
+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
+
+include lib/zlib/zlib.mk
+PLAT_INCLUDES += -Ilib/zlib
+BL2_SOURCES += $(ZLIB_SOURCES)
+
+BL31_SOURCES += drivers/arm/cci/cci.c \
+ drivers/arm/pl061/pl061_gpio.c \
+ drivers/gpio/gpio.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_bl_common.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_common.c
+
+BL1_SOURCES += ${AUTH_SOURCES} \
+ plat/common/tbbr/plat_tbbr.c \
+ plat/hisilicon/hikey960/hikey960_tbbr.c \
+ plat/hisilicon/hikey960/hikey960_rotpk.S \
+ drivers/auth/tbbr/tbbr_cot_bl1.c
+
+BL2_SOURCES += ${AUTH_SOURCES} \
+ plat/common/tbbr/plat_tbbr.c \
+ plat/hisilicon/hikey960/hikey960_tbbr.c \
+ plat/hisilicon/hikey960/hikey960_rotpk.S \
+ drivers/auth/tbbr/tbbr_cot_bl2.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)/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_BIN_PATH}/openssl genrsa 2048 > $@ 2>/dev/null
+
+$(ROTPK_HASH): $(ROT_KEY)
+ @echo " OPENSSL $@"
+ $(Q)${OPENSSL_BIN_PATH}/openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+ ${OPENSSL_BIN_PATH}/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
+
+# SPM dispatcher
+ifeq (${SPD},spmd)
+ifeq (${SPMC_AT_EL3},1)
+# include device tree helper library
+include lib/libfdt/libfdt.mk
+BL31_SOURCES += common/fdt_wrappers.c \
+ ${LIBFDT_SRCS} \
+ common/uuid.c
+
+# Add support for platform supplied linker script for BL31 build
+$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
+endif
+
+ifeq ($(PLAT_SP_MANIFEST_DTS),)
+ $(error "Error: A SP manifest is required for the SPMC.")
+endif
+FDT_SOURCES += ${PLAT_SP_MANIFEST_DTS}
+endif
diff --git a/plat/hisilicon/poplar/aarch64/platform_common.c b/plat/hisilicon/poplar/aarch64/platform_common.c
new file mode 100644
index 0000000..fcd0a8b
--- /dev/null
+++ b/plat/hisilicon/poplar/aarch64/platform_common.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.h>
+
+#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;
+}
diff --git a/plat/hisilicon/poplar/aarch64/poplar_helpers.S b/plat/hisilicon/poplar/aarch64/poplar_helpers.S
new file mode 100644
index 0000000..063ee64
--- /dev/null
+++ b/plat/hisilicon/poplar/aarch64/poplar_helpers.S
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .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
+
+ /* ---------------------------------------------
+ * void plat_crash_console_flush()
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * Out : void.
+ * 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
diff --git a/plat/hisilicon/poplar/bl1_plat_setup.c b/plat/hisilicon/poplar/bl1_plat_setup.c
new file mode 100644
index 0000000..acc1f0e
--- /dev/null
+++ b/plat/hisilicon/poplar/bl1_plat_setup.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/arm/pl061_gpio.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/mmc.h>
+#include <drivers/synopsys/dw_mmc.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#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_t console;
+
+#if !POPLAR_RECOVERY
+static struct mmc_device_info mmc_info;
+#endif
+
+/*
+ * 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
+ 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");
+ mmc_info.mmc_dev_type = MMC_IS_EMMC;
+ dw_mmc_init(&params, &mmc_info);
+#endif
+
+ plat_io_setup();
+}
+
+unsigned int bl1_plat_get_next_image_id(void)
+{
+ return BL2_IMAGE_ID;
+}
diff --git a/plat/hisilicon/poplar/bl2_plat_mem_params_desc.c b/plat/hisilicon/poplar/bl2_plat_mem_params_desc.c
new file mode 100644
index 0000000..9bda02e
--- /dev/null
+++ b/plat/hisilicon/poplar/bl2_plat_mem_params_desc.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * 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)
diff --git a/plat/hisilicon/poplar/bl2_plat_setup.c b/plat/hisilicon/poplar/bl2_plat_setup.c
new file mode 100644
index 0000000..ee46772
--- /dev/null
+++ b/plat/hisilicon/poplar/bl2_plat_setup.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/partition/partition.h>
+#include <drivers/synopsys/dw_mmc.h>
+#include <drivers/mmc.h>
+#include <lib/mmio.h>
+#include <lib/optee_utils.h>
+#include <plat/common/platform.h>
+
+#include "hi3798cv200.h"
+#include "plat_private.h"
+
+static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
+static console_t console;
+#if !POPLAR_RECOVERY
+static struct mmc_device_info mmc_info;
+#endif
+
+/*******************************************************************************
+ * 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
+ 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");
+ mmc_info.mmc_dev_type = MMC_IS_EMMC;
+ dw_mmc_init(&params, &mmc_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
+}
diff --git a/plat/hisilicon/poplar/bl31_plat_setup.c b/plat/hisilicon/poplar/bl31_plat_setup.c
new file mode 100644
index 0000000..fe60ddc
--- /dev/null
+++ b/plat/hisilicon/poplar/bl31_plat_setup.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <cortex_a53.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#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_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 %" PRIu64 " Bytes\n",
+ bl33_image_ep_info.pc, bl33_image_ep_info.args.arg2);
+}
diff --git a/plat/hisilicon/poplar/include/hi3798cv200.h b/plat/hisilicon/poplar/include/hi3798cv200.h
new file mode 100644
index 0000000..e31f4b3
--- /dev/null
+++ b/plat/hisilicon/poplar/include/hi3798cv200.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HI3798CV200_H
+#define HI3798CV200_H
+
+#include <lib/utils_def.h>
+
+/* 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 */
diff --git a/plat/hisilicon/poplar/include/plat_macros.S b/plat/hisilicon/poplar/include/plat_macros.S
new file mode 100644
index 0000000..82d10c1
--- /dev/null
+++ b/plat/hisilicon/poplar/include/plat_macros.S
@@ -0,0 +1,10 @@
+/*
+ * 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
diff --git a/plat/hisilicon/poplar/include/plat_private.h b/plat/hisilicon/poplar/include/plat_private.h
new file mode 100644
index 0000000..a34f138
--- /dev/null
+++ b/plat/hisilicon/poplar/include/plat_private.h
@@ -0,0 +1,37 @@
+/*
+ * 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 <common/bl_common.h>
+
+#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 */
diff --git a/plat/hisilicon/poplar/include/platform_def.h b/plat/hisilicon/poplar/include/platform_def.h
new file mode 100644
index 0000000..ce0fbbc
--- /dev/null
+++ b/plat/hisilicon/poplar/include/platform_def.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <common/interrupt_props.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#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 U(1)
+#define PLATFORM_CORE_COUNT U(4)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER U(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 */
diff --git a/plat/hisilicon/poplar/include/poplar_layout.h b/plat/hisilicon/poplar/include/poplar_layout.h
new file mode 100644
index 0000000..03047f9
--- /dev/null
+++ b/plat/hisilicon/poplar/include/poplar_layout.h
@@ -0,0 +1,132 @@
+/*
+ * 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 */
diff --git a/plat/hisilicon/poplar/plat_pm.c b/plat/hisilicon/poplar/plat_pm.c
new file mode 100644
index 0000000..67ebca1
--- /dev/null
+++ b/plat/hisilicon/poplar/plat_pm.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#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;
+}
diff --git a/plat/hisilicon/poplar/plat_storage.c b/plat/hisilicon/poplar/plat_storage.c
new file mode 100644
index 0000000..a17e0f1
--- /dev/null
+++ b/plat/hisilicon/poplar/plat_storage.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/mmc.h>
+#include <drivers/partition/partition.h>
+#include <lib/mmio.h>
+#include <lib/semihosting.h>
+#include <lib/utils.h>
+#include <tools_share/firmware_image_package.h>
+
+#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;
+}
diff --git a/plat/hisilicon/poplar/plat_topology.c b/plat/hisilicon/poplar/plat_topology.c
new file mode 100644
index 0000000..764008e
--- /dev/null
+++ b/plat/hisilicon/poplar/plat_topology.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <lib/psci/psci.h>
+
+#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);
+}
diff --git a/plat/hisilicon/poplar/platform.mk b/plat/hisilicon/poplar/platform.mk
new file mode 100644
index 0000000..b5d9867
--- /dev/null
+++ b/plat/hisilicon/poplar/platform.mk
@@ -0,0 +1,112 @@
+#
+# 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
diff --git a/plat/hisilicon/poplar/poplar_gicv2.c b/plat/hisilicon/poplar/poplar_gicv2.c
new file mode 100644
index 0000000..59f7b76
--- /dev/null
+++ b/plat/hisilicon/poplar/poplar_gicv2.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <drivers/arm/gicv2.h>
+#include <plat/common/platform.h>
+
+/******************************************************************************
+ * 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());
+}
diff --git a/plat/hisilicon/poplar/poplar_image_load.c b/plat/hisilicon/poplar/poplar_image_load.c
new file mode 100644
index 0000000..0ab1ca4
--- /dev/null
+++ b/plat/hisilicon/poplar/poplar_image_load.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.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();
+}
diff --git a/plat/imx/common/aarch32/imx_uart_console.S b/plat/imx/common/aarch32/imx_uart_console.S
new file mode 100644
index 0000000..1a1229a
--- /dev/null
+++ b/plat/imx/common/aarch32/imx_uart_console.S
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <console_macros.S>
+#include <assert_macros.S>
+#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_BASE]
+
+ 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_BASE]
+ b console_imx_uart_core_putc
+endfunc console_imx_uart_putc
+
+func console_imx_uart_getc
+ ldr r0, [r0, #CONSOLE_T_BASE]
+ b console_imx_uart_core_getc
+endfunc console_imx_uart_getc
+
+func console_imx_uart_flush
+ ldr r0, [r0, #CONSOLE_T_BASE]
+ b console_imx_uart_core_flush
+endfunc console_imx_uart_flush
diff --git a/plat/imx/common/imx7_clock.c b/plat/imx/common/imx7_clock.c
new file mode 100644
index 0000000..6bd2e0e
--- /dev/null
+++ b/plat/imx/common/imx7_clock.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <imx_regs.h>
+#include <imx_clock.h>
+
+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();
+
+}
diff --git a/plat/imx/common/imx8_helpers.S b/plat/imx/common/imx8_helpers.S
new file mode 100644
index 0000000..19293bf
--- /dev/null
+++ b/plat/imx/common/imx8_helpers.S
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <platform_def.h>
+#include <cortex_a35.h>
+
+ .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
diff --git a/plat/imx/common/imx8_psci.c b/plat/imx/common/imx8_psci.c
new file mode 100644
index 0000000..91d3370
--- /dev/null
+++ b/plat/imx/common/imx8_psci.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#include <plat_imx8.h>
+#include <sci/sci.h>
+
+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;
+}
+
diff --git a/plat/imx/common/imx8_topology.c b/plat/imx/common/imx8_topology.c
new file mode 100644
index 0000000..5e14d17
--- /dev/null
+++ b/plat/imx/common/imx8_topology.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <plat/common/platform.h>
+
+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));
+}
diff --git a/plat/imx/common/imx_aips.c b/plat/imx/common/imx_aips.c
new file mode 100644
index 0000000..532d9c0
--- /dev/null
+++ b/plat/imx/common/imx_aips.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include <imx_aips.h>
+#include <imx_regs.h>
+
+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]);
+}
diff --git a/plat/imx/common/imx_caam.c b/plat/imx/common/imx_caam.c
new file mode 100644
index 0000000..d9c141f
--- /dev/null
+++ b/plat/imx/common/imx_caam.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <lib/mmio.h>
+
+#include <imx_caam.h>
+
+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);
+ }
+}
diff --git a/plat/imx/common/imx_clock.c b/plat/imx/common/imx_clock.c
new file mode 100644
index 0000000..743de55
--- /dev/null
+++ b/plat/imx/common/imx_clock.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <arch.h>
+#include <lib/mmio.h>
+
+#include <imx_regs.h>
+#include <imx_clock.h>
+
+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);
+}
diff --git a/plat/imx/common/imx_csu.c b/plat/imx/common/imx_csu.c
new file mode 100644
index 0000000..7e165d9
--- /dev/null
+++ b/plat/imx/common/imx_csu.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include <imx_csu.h>
+#include <imx_regs.h>
+
+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);
+}
diff --git a/plat/imx/common/imx_ehf.c b/plat/imx/common/imx_ehf.c
new file mode 100644
index 0000000..a9396cd
--- /dev/null
+++ b/plat/imx/common/imx_ehf.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <bl31/ehf.h>
+
+#include <platform_def.h>
+
+ehf_pri_desc_t imx_exceptions[] = {
+#if SDEI_SUPPORT
+ /* Critical priority SDEI */
+ EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SDEI_CRITICAL_PRI),
+
+ /* Normal priority SDEI */
+ EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SDEI_NORMAL_PRI),
+#endif
+};
+
+/* Plug in ARM exceptions to Exception Handling Framework. */
+EHF_REGISTER_PRIORITIES(imx_exceptions, ARRAY_SIZE(imx_exceptions), PLAT_PRI_BITS);
diff --git a/plat/imx/common/imx_io_mux.c b/plat/imx/common/imx_io_mux.c
new file mode 100644
index 0000000..75de5d1
--- /dev/null
+++ b/plat/imx/common/imx_io_mux.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include <imx_regs.h>
+#include <imx_io_mux.h>
+
+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);
+}
diff --git a/plat/imx/common/imx_io_storage.c b/plat/imx/common/imx_io_storage.c
new file mode 100644
index 0000000..bb35662
--- /dev/null
+++ b/plat/imx/common/imx_io_storage.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/mmc.h>
+#include <lib/utils_def.h>
+#include <tbbr_img_def.h>
+#include <tools_share/firmware_image_package.h>
+
+#include <platform_def.h>
+
+static const io_dev_connector_t *fip_dev_con;
+static uintptr_t fip_dev_handle;
+
+#ifndef IMX_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 = IMX_FIP_MMC_BASE,
+ .length = IMX_FIP_SIZE
+};
+
+static const io_block_dev_spec_t mmc_dev_spec = {
+ /* It's used as temp buffer in block driver. */
+ .buffer = {
+ .offset = IMX_FIP_BASE,
+ /* do we need a new value? */
+ .length = IMX_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 = IMX_FIP_BASE,
+ .length = IMX_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 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 tos_fw_cert_uuid_spec = {
+ .uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t soc_fw_content_cert_uuid_spec = {
+ .uuid = UUID_SOC_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 IMX_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
+ [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
+ },
+ [SOC_FW_KEY_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&soc_fw_key_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
+ },
+ [SOC_FW_CONTENT_CERT_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&soc_fw_content_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 IMX_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_imx_io_setup(void)
+{
+ int result __unused;
+
+#ifndef IMX_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);
+}
diff --git a/plat/imx/common/imx_sdei.c b/plat/imx/common/imx_sdei.c
new file mode 100644
index 0000000..4b6033f
--- /dev/null
+++ b/plat/imx/common/imx_sdei.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* SDEI configuration for ARM platforms */
+
+#include <bl31/ehf.h>
+#include <common/debug.h>
+#include <services/sdei.h>
+#include <lib/utils_def.h>
+
+#include <platform_def.h>
+
+/* Private event mappings */
+static sdei_ev_map_t imx_sdei_private[] = {
+ SDEI_DEFINE_EVENT_0(PLAT_SDEI_SGI_PRIVATE),
+};
+
+/* Shared event mappings */
+static sdei_ev_map_t imx_sdei_shared[] = {
+};
+
+void plat_sdei_setup(void)
+{
+ INFO("SDEI platform setup\n");
+}
+
+/* Export ARM SDEI events */
+REGISTER_SDEI_MAP(imx_sdei_private, imx_sdei_shared);
diff --git a/plat/imx/common/imx_sip_handler.c b/plat/imx/common/imx_sip_handler.c
new file mode 100644
index 0000000..d4b3425
--- /dev/null
+++ b/plat/imx/common/imx_sip_handler.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2019 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <services/std_svc.h>
+#include <string.h>
+#include <platform_def.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <imx_sip_svc.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <sci/sci.h>
+
+#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) */
+
+#if defined(PLAT_imx8mm) || defined(PLAT_imx8mq)
+int imx_src_handler(uint32_t smc_fid,
+ u_register_t x1,
+ u_register_t x2,
+ u_register_t x3,
+ void *handle)
+{
+ uint32_t val;
+
+ switch (x1) {
+ case IMX_SIP_SRC_SET_SECONDARY_BOOT:
+ if (x2 != 0U) {
+ mmio_setbits_32(IMX_SRC_BASE + SRC_GPR10_OFFSET,
+ SRC_GPR10_PERSIST_SECONDARY_BOOT);
+ } else {
+ mmio_clrbits_32(IMX_SRC_BASE + SRC_GPR10_OFFSET,
+ SRC_GPR10_PERSIST_SECONDARY_BOOT);
+ }
+ break;
+ case IMX_SIP_SRC_IS_SECONDARY_BOOT:
+ val = mmio_read_32(IMX_SRC_BASE + SRC_GPR10_OFFSET);
+ return !!(val & SRC_GPR10_PERSIST_SECONDARY_BOOT);
+ default:
+ return SMC_UNK;
+
+ };
+
+ return 0;
+}
+#endif /* defined(PLAT_imx8mm) || defined(PLAT_imx8mq) */
+
+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;
+}
+
+int imx_kernel_entry_handler(uint32_t smc_fid,
+ u_register_t x1,
+ u_register_t x2,
+ u_register_t x3,
+ u_register_t x4)
+{
+ static entry_point_info_t bl33_image_ep_info;
+ entry_point_info_t *next_image_info;
+ unsigned int mode;
+
+ if (x1 < (PLAT_NS_IMAGE_OFFSET & 0xF0000000))
+ return SMC_UNK;
+
+ mode = MODE32_svc;
+
+ next_image_info = &bl33_image_ep_info;
+
+ next_image_info->pc = x1;
+
+ 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->args.arg0 = 0;
+ next_image_info->args.arg1 = 0;
+ next_image_info->args.arg2 = x3;
+
+ SET_SECURITY_STATE(next_image_info->h.attr, NON_SECURE);
+
+ cm_init_my_context(next_image_info);
+ cm_prepare_el3_exit(NON_SECURE);
+
+ return 0;
+}
diff --git a/plat/imx/common/imx_sip_svc.c b/plat/imx/common/imx_sip_svc.c
new file mode 100644
index 0000000..11d02f3
--- /dev/null
+++ b/plat/imx/common/imx_sip_svc.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/pmf/pmf.h>
+#include <tools_share/uuid.h>
+#include <imx_sip_svc.h>
+
+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) {
+ case IMX_SIP_AARCH32:
+ SMC_RET1(handle, imx_kernel_entry_handler(smc_fid, x1, x2, x3, x4));
+ break;
+#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_imx8mm) || defined(PLAT_imx8mn) || defined(PLAT_imx8mp)
+ case IMX_SIP_DDR_DVFS:
+ return dram_dvfs_handler(smc_fid, handle, x1, x2, x3);
+ case IMX_SIP_GPC:
+ SMC_RET1(handle, imx_gpc_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
+#if defined(PLAT_imx8mm) || defined(PLAT_imx8mq)
+ case IMX_SIP_SRC:
+ SMC_RET1(handle, imx_src_handler(smc_fid, x1, x2, x3, handle));
+ break;
+#endif
+#if defined(PLAT_imx8mm) || defined(PLAT_imx8mn) || defined(PLAT_imx8mp)
+ case IMX_SIP_HAB:
+ SMC_RET1(handle, imx_hab_handler(smc_fid, x1, x2, x3, x4));
+ break;
+#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
+);
diff --git a/plat/imx/common/imx_snvs.c b/plat/imx/common/imx_snvs.c
new file mode 100644
index 0000000..9b3a737
--- /dev/null
+++ b/plat/imx/common/imx_snvs.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include <imx_regs.h>
+#include <imx_snvs.h>
+
+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);
+}
diff --git a/plat/imx/common/imx_uart_console.S b/plat/imx/common/imx_uart_console.S
new file mode 100644
index 0000000..ceeb3a7
--- /dev/null
+++ b/plat/imx/common/imx_uart_console.S
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <console_macros.S>
+#include <assert_macros.S>
+#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_BASE]
+
+ 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_BASE]
+ 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_BASE]
+ 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
+ ret
+endfunc console_imx_uart_flush
diff --git a/plat/imx/common/imx_wdog.c b/plat/imx/common/imx_wdog.c
new file mode 100644
index 0000000..af6d767
--- /dev/null
+++ b/plat/imx/common/imx_wdog.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include <imx_regs.h>
+#include <imx_wdog.h>
+
+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);
+}
diff --git a/plat/imx/common/include/imx8_iomux.h b/plat/imx/common/include/imx8_iomux.h
new file mode 100644
index 0000000..264c295
--- /dev/null
+++ b/plat/imx/common/include/imx8_iomux.h
@@ -0,0 +1,25 @@
+/*
+ * 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 U(31)
+#define PADRING_IFMUX_EN_MASK (U(0x1) << PADRING_IFMUX_EN_SHIFT)
+#define PADRING_GP_EN_SHIFT U(30)
+#define PADRING_GP_EN_MASK (U(0x1) << PADRING_GP_EN_SHIFT)
+#define PADRING_IFMUX_SHIFT U(27)
+#define PADRING_IFMUX_MASK (U(0x7) << PADRING_IFMUX_SHIFT)
+#define PADRING_CONFIG_SHIFT U(25)
+#define PADRING_CONFIG_MASK (U(0x3) << PADRING_CONFIG_SHIFT)
+#define PADRING_LPCONFIG_SHIFT U(23)
+#define PADRING_LPCONFIG_MASK (U(0x3) << PADRING_LPCONFIG_SHIFT)
+#define PADRING_PULL_SHIFT U(5)
+#define PADRING_PULL_MASK (U(0x3) << PADRING_PULL_SHIFT)
+#define PADRING_DSE_SHIFT U(0)
+#define PADRING_DSE_MASK (U(0x7) << PADRING_DSE_SHIFT)
+
+#endif /* IMX8_IOMUX_H */
diff --git a/plat/imx/common/include/imx8_lpuart.h b/plat/imx/common/include/imx8_lpuart.h
new file mode 100644
index 0000000..26470e0
--- /dev/null
+++ b/plat/imx/common/include/imx8_lpuart.h
@@ -0,0 +1,61 @@
+/*
+ * 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 <drivers/console.h>
+
+#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 <stdint.h>
+
+int console_lpuart_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
+ console_t *console);
+#endif /*__ASSEMBLER__*/
+
+#endif /* IMX8_LPUART_H */
diff --git a/plat/imx/common/include/imx8qm_pads.h b/plat/imx/common/include/imx8qm_pads.h
new file mode 100644
index 0000000..a5c1d2c
--- /dev/null
+++ b/plat/imx/common/include/imx8qm_pads.h
@@ -0,0 +1,293 @@
+/*
+ * 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 */
diff --git a/plat/imx/common/include/imx8qx_pads.h b/plat/imx/common/include/imx8qx_pads.h
new file mode 100644
index 0000000..5445aa1
--- /dev/null
+++ b/plat/imx/common/include/imx8qx_pads.h
@@ -0,0 +1,198 @@
+/*
+ * 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 */
diff --git a/plat/imx/common/include/imx_aips.h b/plat/imx/common/include/imx_aips.h
new file mode 100644
index 0000000..1d41fe0
--- /dev/null
+++ b/plat/imx/common/include/imx_aips.h
@@ -0,0 +1,22 @@
+/*
+ * 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 <stdint.h>
+
+#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 */
diff --git a/plat/imx/common/include/imx_caam.h b/plat/imx/common/include/imx_caam.h
new file mode 100644
index 0000000..61005b5
--- /dev/null
+++ b/plat/imx/common/include/imx_caam.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_CAAM_H
+#define IMX_CAAM_H
+
+#include <cdefs.h>
+#include <stdint.h>
+#include <arch.h>
+#include <imx_regs.h>
+
+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 */
diff --git a/plat/imx/common/include/imx_clock.h b/plat/imx/common/include/imx_clock.h
new file mode 100644
index 0000000..d75dcff
--- /dev/null
+++ b/plat/imx/common/include/imx_clock.h
@@ -0,0 +1,1003 @@
+/*
+ * 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 <stdint.h>
+#include <stdbool.h>
+
+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 */
diff --git a/plat/imx/common/include/imx_csu.h b/plat/imx/common/include/imx_csu.h
new file mode 100644
index 0000000..879d10b
--- /dev/null
+++ b/plat/imx/common/include/imx_csu.h
@@ -0,0 +1,44 @@
+/*
+ * 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 <arch.h>
+
+/*
+ * 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 */
diff --git a/plat/imx/common/include/imx_hab.h b/plat/imx/common/include/imx_hab.h
new file mode 100644
index 0000000..22c0742
--- /dev/null
+++ b/plat/imx/common/include/imx_hab.h
@@ -0,0 +1,33 @@
+/*
+ * 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 <imx_hab_arch.h>
+#include <imx_regs.h>
+
+#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 */
diff --git a/plat/imx/common/include/imx_io_mux.h b/plat/imx/common/include/imx_io_mux.h
new file mode 100644
index 0000000..d588cfd
--- /dev/null
+++ b/plat/imx/common/include/imx_io_mux.h
@@ -0,0 +1,652 @@
+/*
+ * 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 <stdint.h>
+#include <lib/utils_def.h>
+
+/*
+ * 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 */
diff --git a/plat/imx/common/include/imx_sip_svc.h b/plat/imx/common/include/imx_sip_svc.h
new file mode 100644
index 0000000..1f45985
--- /dev/null
+++ b/plat/imx/common/include/imx_sip_svc.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015-2022, 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_GPC 0xC2000000
+
+#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_DDR_DVFS 0xc2000004
+
+#define IMX_SIP_SRC 0xC2000005
+#define IMX_SIP_SRC_SET_SECONDARY_BOOT 0x10
+#define IMX_SIP_SRC_IS_SECONDARY_BOOT 0x11
+
+#define IMX_SIP_GET_SOC_INFO 0xC2000006
+
+#define IMX_SIP_HAB 0xC2000007
+#define IMX_SIP_HAB_AUTH_IMG 0x00
+#define IMX_SIP_HAB_ENTRY 0x01
+#define IMX_SIP_HAB_EXIT 0x02
+#define IMX_SIP_HAB_REPORT_EVENT 0x03
+#define IMX_SIP_HAB_REPORT_STATUS 0x04
+#define IMX_SIP_HAB_FAILSAFE 0x05
+#define IMX_SIP_HAB_CHECK_TARGET 0x06
+#define IMX_SIP_HAB_GET_VERSION 0x07
+#define IMX_SIP_HAB_AUTH_IMG_NO_DCD 0x08
+
+#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
+
+#define IMX_SIP_AARCH32 0xC20000FD
+
+int imx_kernel_entry_handler(uint32_t smc_fid, u_register_t x1,
+ u_register_t x2, u_register_t x3,
+ u_register_t x4);
+#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_imx8mm) || defined(PLAT_imx8mn) || defined(PLAT_imx8mp)
+int dram_dvfs_handler(uint32_t smc_fid, void *handle,
+ u_register_t x1, u_register_t x2, u_register_t x3);
+
+int imx_gpc_handler(uint32_t smc_fid, u_register_t x1,
+ u_register_t x2, u_register_t x3);
+#endif
+
+#if defined(PLAT_imx8mm) || defined(PLAT_imx8mq)
+int imx_src_handler(uint32_t smc_fid, u_register_t x1,
+ u_register_t x2, u_register_t x3, void *handle);
+#endif
+
+#if defined(PLAT_imx8mm) || defined(PLAT_imx8mn) || defined(PLAT_imx8mp)
+int imx_hab_handler(uint32_t smc_fid, u_register_t x1,
+ u_register_t x2, u_register_t x3, u_register_t x4);
+#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__ */
diff --git a/plat/imx/common/include/imx_snvs.h b/plat/imx/common/include/imx_snvs.h
new file mode 100644
index 0000000..565c451
--- /dev/null
+++ b/plat/imx/common/include/imx_snvs.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef IMX_SNVS_H
+#define IMX_SNVS_H
+
+#include <cdefs.h>
+#include <stdint.h>
+
+#include <arch.h>
+
+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 */
diff --git a/plat/imx/common/include/imx_uart.h b/plat/imx/common/include/imx_uart.h
new file mode 100644
index 0000000..6c4d62f
--- /dev/null
+++ b/plat/imx/common/include/imx_uart.h
@@ -0,0 +1,18 @@
+/*
+ * 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 <drivers/console.h>
+
+#ifndef __ASSEMBLER__
+
+int console_imx_uart_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
+ console_t *console);
+#endif /*__ASSEMBLER__*/
+
+#endif /* IMX_UART_H */
diff --git a/plat/imx/common/include/imx_wdog.h b/plat/imx/common/include/imx_wdog.h
new file mode 100644
index 0000000..75a729a
--- /dev/null
+++ b/plat/imx/common/include/imx_wdog.h
@@ -0,0 +1,62 @@
+/*
+ * 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 <stdint.h>
+
+#include <arch.h>
+
+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 */
diff --git a/plat/imx/common/include/plat_imx8.h b/plat/imx/common/include/plat_imx8.h
new file mode 100644
index 0000000..be99b97
--- /dev/null
+++ b/plat/imx/common/include/plat_imx8.h
@@ -0,0 +1,35 @@
+/*
+ * 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 <drivers/arm/gicv3.h>
+#include <lib/psci/psci.h>
+
+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 */
diff --git a/plat/imx/common/include/plat_macros.S b/plat/imx/common/include/plat_macros.S
new file mode 100644
index 0000000..30cce0a
--- /dev/null
+++ b/plat/imx/common/include/plat_macros.S
@@ -0,0 +1,34 @@
+/*
+ * 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
diff --git a/plat/imx/common/include/sci/sci.h b/plat/imx/common/include/sci/sci.h
new file mode 100644
index 0000000..2c45bb8
--- /dev/null
+++ b/plat/imx/common/include/sci/sci.h
@@ -0,0 +1,21 @@
+/*
+ * 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 <sci/sci_ipc.h>
+#include <sci/svc/pad/sci_pad_api.h>
+#include <sci/svc/pm/sci_pm_api.h>
+#include <sci/svc/rm/sci_rm_api.h>
+#include <sci/svc/timer/sci_timer_api.h>
+#include <sci/svc/misc/sci_misc_api.h>
+
+#endif /* SCI_H */
diff --git a/plat/imx/common/include/sci/sci_ipc.h b/plat/imx/common/include/sci/sci_ipc.h
new file mode 100644
index 0000000..39e9012
--- /dev/null
+++ b/plat/imx/common/include/sci/sci_ipc.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015-2019, 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 <sci/sci_types.h>
+
+/* 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);
+
+extern sc_ipc_t ipc_handle;
+
+#endif /* SCI_IPC_H */
diff --git a/plat/imx/common/include/sci/sci_rpc.h b/plat/imx/common/include/sci/sci_rpc.h
new file mode 100644
index 0000000..60dbc27
--- /dev/null
+++ b/plat/imx/common/include/sci/sci_rpc.h
@@ -0,0 +1,128 @@
+/*
+ * 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 <stdbool.h>
+
+#include <sci/sci_types.h>
+#include <sci/sci_ipc.h>
+
+/* 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 */
diff --git a/plat/imx/common/include/sci/sci_scfw.h b/plat/imx/common/include/sci/sci_scfw.h
new file mode 100644
index 0000000..a169f88
--- /dev/null
+++ b/plat/imx/common/include/sci/sci_scfw.h
@@ -0,0 +1,36 @@
+/*
+ * 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 <stdint.h>
+
+#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 */
diff --git a/plat/imx/common/include/sci/sci_types.h b/plat/imx/common/include/sci/sci_types.h
new file mode 100644
index 0000000..6ade01c
--- /dev/null
+++ b/plat/imx/common/include/sci/sci_types.h
@@ -0,0 +1,849 @@
+/*
+ * 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 <sci/sci_scfw.h>
+
+/* 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 */
diff --git a/plat/imx/common/include/sci/svc/misc/sci_misc_api.h b/plat/imx/common/include/sci/svc/misc/sci_misc_api.h
new file mode 100644
index 0000000..d9dd49d
--- /dev/null
+++ b/plat/imx/common/include/sci/svc/misc/sci_misc_api.h
@@ -0,0 +1,539 @@
+/*
+ * 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 <sci/svc/rm/sci_rm_api.h>
+#include <sci/sci_types.h>
+
+/* 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 */
+
+/**@}*/
diff --git a/plat/imx/common/include/sci/svc/pad/sci_pad_api.h b/plat/imx/common/include/sci/svc/pad/sci_pad_api.h
new file mode 100644
index 0000000..dc23eed
--- /dev/null
+++ b/plat/imx/common/include/sci/svc/pad/sci_pad_api.h
@@ -0,0 +1,572 @@
+/*
+ * 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 <sci/sci_types.h>
+#include <sci/svc/rm/sci_rm_api.h>
+
+/* 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 */
+
+/**@}*/
diff --git a/plat/imx/common/include/sci/svc/pm/sci_pm_api.h b/plat/imx/common/include/sci/svc/pm/sci_pm_api.h
new file mode 100644
index 0000000..76ca5c4
--- /dev/null
+++ b/plat/imx/common/include/sci/svc/pm/sci_pm_api.h
@@ -0,0 +1,684 @@
+/*
+ * 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 <sci/sci_types.h>
+#include <sci/svc/rm/sci_rm_api.h>
+
+/* 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 */
+
+/**@}*/
diff --git a/plat/imx/common/include/sci/svc/rm/sci_rm_api.h b/plat/imx/common/include/sci/svc/rm/sci_rm_api.h
new file mode 100644
index 0000000..df1bc40
--- /dev/null
+++ b/plat/imx/common/include/sci/svc/rm/sci_rm_api.h
@@ -0,0 +1,757 @@
+/*
+ * 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 <sci/sci_types.h>
+
+/* 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 */
+
+/**@}*/
diff --git a/plat/imx/common/include/sci/svc/timer/sci_timer_api.h b/plat/imx/common/include/sci/svc/timer/sci_timer_api.h
new file mode 100644
index 0000000..f8423ab
--- /dev/null
+++ b/plat/imx/common/include/sci/svc/timer/sci_timer_api.h
@@ -0,0 +1,358 @@
+/*
+ * 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 <sci/sci_types.h>
+
+/* 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 */
+
+/**@}*/
diff --git a/plat/imx/common/lpuart_console.S b/plat/imx/common/lpuart_console.S
new file mode 100644
index 0000000..ff01e35
--- /dev/null
+++ b/plat/imx/common/lpuart_console.S
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <console_macros.S>
+#include <assert_macros.S>
+#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_BASE]
+
+ 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_BASE]
+ 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_BASE]
+ 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
+ ret
+endfunc console_lpuart_flush
diff --git a/plat/imx/common/plat_imx8_gic.c b/plat/imx/common/plat_imx8_gic.c
new file mode 100644
index 0000000..150e81e
--- /dev/null
+++ b/plat/imx/common/plat_imx8_gic.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/arm/arm_gicv3_common.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#include <plat_imx8.h>
+
+/* 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(8, GIC_HIGHEST_SEC_PRIORITY,
+ INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+#if SDEI_SUPPORT
+ INTR_PROP_DESC(PLAT_SDEI_SGI_PRIVATE, PLAT_SDEI_NORMAL_PRI,
+ INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+#endif
+};
+
+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]);
+}
diff --git a/plat/imx/common/sci/imx8_mu.c b/plat/imx/common/sci/imx8_mu.c
new file mode 100644
index 0000000..66e956d
--- /dev/null
+++ b/plat/imx/common/sci/imx8_mu.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#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);
+}
diff --git a/plat/imx/common/sci/imx8_mu.h b/plat/imx/common/sci/imx8_mu.h
new file mode 100644
index 0000000..7885219
--- /dev/null
+++ b/plat/imx/common/sci/imx8_mu.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#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);
diff --git a/plat/imx/common/sci/ipc.c b/plat/imx/common/sci/ipc.c
new file mode 100644
index 0000000..5769119
--- /dev/null
+++ b/plat/imx/common/sci/ipc.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+
+#include <lib/bakery_lock.h>
+
+#include <sci/sci_scfw.h>
+#include <sci/sci_ipc.h>
+#include <sci/sci_rpc.h>
+#include "imx8_mu.h"
+
+sc_ipc_t ipc_handle;
+
+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++;
+ }
+}
+
diff --git a/plat/imx/common/sci/sci_api.mk b/plat/imx/common/sci/sci_api.mk
new file mode 100644
index 0000000..92c7190
--- /dev/null
+++ b/plat/imx/common/sci/sci_api.mk
@@ -0,0 +1,13 @@
+#
+# 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
diff --git a/plat/imx/common/sci/svc/misc/misc_rpc_clnt.c b/plat/imx/common/sci/svc/misc/misc_rpc_clnt.c
new file mode 100644
index 0000000..080de6a
--- /dev/null
+++ b/plat/imx/common/sci/svc/misc/misc_rpc_clnt.c
@@ -0,0 +1,506 @@
+/*
+ * 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 <sci/sci_types.h>
+#include <sci/svc/rm/sci_rm_api.h>
+#include <sci/svc/misc/sci_misc_api.h>
+#include <sci/sci_rpc.h>
+#include <stdlib.h>
+#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);
+}
+
+/**@}*/
diff --git a/plat/imx/common/sci/svc/misc/sci_misc_rpc.h b/plat/imx/common/sci/svc/misc/sci_misc_rpc.h
new file mode 100644
index 0000000..03b1a51
--- /dev/null
+++ b/plat/imx/common/sci/svc/misc/sci_misc_rpc.h
@@ -0,0 +1,76 @@
+/*
+ * 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 */
+
+/**@}*/
diff --git a/plat/imx/common/sci/svc/pad/pad_rpc_clnt.c b/plat/imx/common/sci/svc/pad/pad_rpc_clnt.c
new file mode 100644
index 0000000..319d469
--- /dev/null
+++ b/plat/imx/common/sci/svc/pad/pad_rpc_clnt.c
@@ -0,0 +1,454 @@
+/*
+ * 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 <stdlib.h>
+
+#include <sci/sci_types.h>
+#include <sci/svc/rm/sci_rm_api.h>
+#include <sci/svc/pad/sci_pad_api.h>
+#include <sci/sci_rpc.h>
+#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;
+}
+
+/**@}*/
diff --git a/plat/imx/common/sci/svc/pad/sci_pad_rpc.h b/plat/imx/common/sci/svc/pad/sci_pad_rpc.h
new file mode 100644
index 0000000..8e9c4bb
--- /dev/null
+++ b/plat/imx/common/sci/svc/pad/sci_pad_rpc.h
@@ -0,0 +1,66 @@
+/*
+ * 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 */
+
+/**@}*/
diff --git a/plat/imx/common/sci/svc/pm/pm_rpc_clnt.c b/plat/imx/common/sci/svc/pm/pm_rpc_clnt.c
new file mode 100644
index 0000000..66a57a1
--- /dev/null
+++ b/plat/imx/common/sci/svc/pm/pm_rpc_clnt.c
@@ -0,0 +1,459 @@
+/*
+ * 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 <stdlib.h>
+
+#include <sci/sci_types.h>
+#include <sci/svc/rm/sci_rm_api.h>
+#include <sci/svc/pm/sci_pm_api.h>
+#include <sci/sci_rpc.h>
+
+#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;
+}
+
+/**@}*/
diff --git a/plat/imx/common/sci/svc/pm/sci_pm_rpc.h b/plat/imx/common/sci/svc/pm/sci_pm_rpc.h
new file mode 100644
index 0000000..8bad3c7
--- /dev/null
+++ b/plat/imx/common/sci/svc/pm/sci_pm_rpc.h
@@ -0,0 +1,71 @@
+/*
+ * 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 */
+
+/**@}*/
diff --git a/plat/imx/common/sci/svc/rm/rm_rpc_clnt.c b/plat/imx/common/sci/svc/rm/rm_rpc_clnt.c
new file mode 100644
index 0000000..16771a5
--- /dev/null
+++ b/plat/imx/common/sci/svc/rm/rm_rpc_clnt.c
@@ -0,0 +1,639 @@
+/*
+ * 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 <stdlib.h>
+
+#include <sci/sci_types.h>
+#include <sci/svc/rm/sci_rm_api.h>
+#include <sci/sci_rpc.h>
+
+#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;
+}
+
+/**@}*/
diff --git a/plat/imx/common/sci/svc/rm/sci_rm_rpc.h b/plat/imx/common/sci/svc/rm/sci_rm_rpc.h
new file mode 100644
index 0000000..45d05f9
--- /dev/null
+++ b/plat/imx/common/sci/svc/rm/sci_rm_rpc.h
@@ -0,0 +1,81 @@
+/*
+ * 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 */
+
+/**@}*/
diff --git a/plat/imx/common/sci/svc/timer/sci_timer_rpc.h b/plat/imx/common/sci/svc/timer/sci_timer_rpc.h
new file mode 100644
index 0000000..6716399
--- /dev/null
+++ b/plat/imx/common/sci/svc/timer/sci_timer_rpc.h
@@ -0,0 +1,69 @@
+/*
+ * 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 */
+
+/**@}*/
diff --git a/plat/imx/common/sci/svc/timer/timer_rpc_clnt.c b/plat/imx/common/sci/svc/timer/timer_rpc_clnt.c
new file mode 100644
index 0000000..a82be96
--- /dev/null
+++ b/plat/imx/common/sci/svc/timer/timer_rpc_clnt.c
@@ -0,0 +1,396 @@
+/*
+ * 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 <sci/sci_types.h>
+#include <sci/svc/rm/sci_rm_api.h>
+#include <sci/svc/timer/sci_timer_api.h>
+#include <sci/sci_rpc.h>
+#include <stdlib.h>
+#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;
+}
+
+/**@}*/
diff --git a/plat/imx/imx7/common/imx7.mk b/plat/imx/imx7/common/imx7.mk
new file mode 100644
index 0000000..f4f5bfc
--- /dev/null
+++ b/plat/imx/imx7/common/imx7.mk
@@ -0,0 +1,112 @@
+#
+# Copyright (c) 2018-2022, 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 \
+ -Iinclude/common/tbbr
+
+# 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/common/imx_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_common.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 \
+ drivers/auth/tbbr/tbbr_cot_bl2.c
+
+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_BIN_PATH}/openssl genrsa 2048 > $@ 2>/dev/null; \
+ fi
+
+$(ROTPK_HASH): $(ROT_KEY)
+ @echo " OPENSSL $@"
+ $(Q)${OPENSSL_BIN_PATH}/openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+ ${OPENSSL_BIN_PATH}/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
diff --git a/plat/imx/imx7/common/imx7_bl2_el3_common.c b/plat/imx/imx7/common/imx7_bl2_el3_common.c
new file mode 100644
index 0000000..4e5028c
--- /dev/null
+++ b/plat/imx/imx7/common/imx7_bl2_el3_common.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/mmc.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <lib/mmio.h>
+#include <lib/optee_utils.h>
+#include <lib/utils.h>
+
+#include <imx_aips.h>
+#include <imx_caam.h>
+#include <imx_clock.h>
+#include <imx_csu.h>
+#include <imx_gpt.h>
+#include <imx_uart.h>
+#include <imx_snvs.h>
+#include <imx_wdog.h>
+#include <imx7_def.h>
+
+#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_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_scope);
+
+ /* Open handles to persistent storage */
+ plat_imx_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", IMX_FIP_BASE, IMX_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)
+{
+}
diff --git a/plat/imx/imx7/common/imx7_bl2_mem_params_desc.c b/plat/imx/imx7/common/imx7_bl2_mem_params_desc.c
new file mode 100644
index 0000000..f9b2983
--- /dev/null
+++ b/plat/imx/imx7/common/imx7_bl2_mem_params_desc.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+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);
diff --git a/plat/imx/imx7/common/imx7_helpers.S b/plat/imx/imx7/common/imx7_helpers.S
new file mode 100644
index 0000000..661fd29
--- /dev/null
+++ b/plat/imx/imx7/common/imx7_helpers.S
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) Linaro 2018-2019 Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+#include <imx_hab.h>
+
+ .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
diff --git a/plat/imx/imx7/common/imx7_image_load.c b/plat/imx/imx7/common/imx7_image_load.c
new file mode 100644
index 0000000..c3e47b9
--- /dev/null
+++ b/plat/imx/imx7/common/imx7_image_load.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+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();
+}
diff --git a/plat/imx/imx7/common/imx7_rotpk.S b/plat/imx/imx7/common/imx7_rotpk.S
new file mode 100644
index 0000000..8bd53c2
--- /dev/null
+++ b/plat/imx/imx7/common/imx7_rotpk.S
@@ -0,0 +1,15 @@
+/*
+ * 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:
diff --git a/plat/imx/imx7/common/imx7_trusted_boot.c b/plat/imx/imx7/common/imx7_trusted_boot.c
new file mode 100644
index 0000000..cd27128
--- /dev/null
+++ b/plat/imx/imx7/common/imx7_trusted_boot.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+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);
+}
diff --git a/plat/imx/imx7/include/imx7_def.h b/plat/imx/imx7/include/imx7_def.h
new file mode 100644
index 0000000..d92a2d1
--- /dev/null
+++ b/plat/imx/imx7/include/imx7_def.h
@@ -0,0 +1,20 @@
+/*
+ * 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 <stdint.h>
+
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+void plat_imx_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 */
diff --git a/plat/imx/imx7/include/imx_hab_arch.h b/plat/imx/imx7/include/imx_hab_arch.h
new file mode 100644
index 0000000..2a34c6a
--- /dev/null
+++ b/plat/imx/imx7/include/imx_hab_arch.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/plat/imx/imx7/include/imx_regs.h b/plat/imx/imx7/include/imx_regs.h
new file mode 100644
index 0000000..3c7e20f
--- /dev/null
+++ b/plat/imx/imx7/include/imx_regs.h
@@ -0,0 +1,108 @@
+/*
+ * 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 */
diff --git a/plat/imx/imx7/picopi/include/platform_def.h b/plat/imx/imx7/picopi/include/platform_def.h
new file mode 100644
index 0000000..5f2975d
--- /dev/null
+++ b/plat/imx/imx7/picopi/include/platform_def.h
@@ -0,0 +1,204 @@
+/*
+ * 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 <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <plat/common/common_def.h>
+
+#define PLATFORM_STACK_SIZE 0x1000
+
+#define PLATFORM_MAX_CPUS_PER_CLUSTER U(2)
+#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 PICOPI_PRIMARY_CPU U(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 IMX_FIP_SIZE 0x00100000
+#define IMX_FIP_BASE (DRAM_BASE)
+#define IMX_FIP_LIMIT (IMX_FIP_BASE + IMX_FIP_SIZE)
+
+/* Define FIP image location at 1MB offset */
+#define IMX_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 */
diff --git a/plat/imx/imx7/picopi/picopi_bl2_el3_setup.c b/plat/imx/imx7/picopi/picopi_bl2_el3_setup.c
new file mode 100644
index 0000000..2df96ae
--- /dev/null
+++ b/plat/imx/imx7/picopi/picopi_bl2_el3_setup.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/mmc.h>
+#include <lib/utils.h>
+
+#include <imx_caam.h>
+#include <imx_clock.h>
+#include <imx_io_mux.h>
+#include <imx_uart.h>
+#include <imx_usdhc.h>
+#include <imx7_def.h>
+
+#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 struct mmc_device_info mmc_info;
+
+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;
+
+ zeromem(&params, sizeof(imx_usdhc_params_t));
+ params.reg_base = PLAT_PICOPI_BOOT_MMC_BASE;
+ params.clk_rate = 25000000;
+ params.bus_width = MMC_BUS_WIDTH_8;
+ mmc_info.mmc_dev_type = MMC_IS_EMMC;
+ imx_usdhc_init(&params, &mmc_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();
+}
diff --git a/plat/imx/imx7/picopi/platform.mk b/plat/imx/imx7/picopi/platform.mk
new file mode 100644
index 0000000..5901001
--- /dev/null
+++ b/plat/imx/imx7/picopi/platform.mk
@@ -0,0 +1,40 @@
+#
+# 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))
diff --git a/plat/imx/imx7/warp7/include/platform_def.h b/plat/imx/imx7/warp7/include/platform_def.h
new file mode 100644
index 0000000..683e50d
--- /dev/null
+++ b/plat/imx/imx7/warp7/include/platform_def.h
@@ -0,0 +1,218 @@
+/*
+ * 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 <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <plat/common/common_def.h>
+
+#define PLATFORM_STACK_SIZE 0x1000
+
+#define PLATFORM_MAX_CPUS_PER_CLUSTER U(2)
+#define PLATFORM_CLUSTER_COUNT U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER
+#define PLATFORM_CLUSTER1_CORE_COUNT U(0)
+
+#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT + \
+ PLATFORM_CLUSTER1_CORE_COUNT)
+
+#define WARP7_PRIMARY_CPU U(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 IMX_FIP_SIZE 0x00100000
+#define IMX_FIP_BASE (DRAM_BASE)
+#define IMX_FIP_LIMIT (IMX_FIP_BASE + IMX_FIP_SIZE)
+
+/* Define FIP image location at 1MB offset */
+#define IMX_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 */
diff --git a/plat/imx/imx7/warp7/platform.mk b/plat/imx/imx7/warp7/platform.mk
new file mode 100644
index 0000000..ea0f001
--- /dev/null
+++ b/plat/imx/imx7/warp7/platform.mk
@@ -0,0 +1,37 @@
+#
+# 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))
diff --git a/plat/imx/imx7/warp7/warp7_bl2_el3_setup.c b/plat/imx/imx7/warp7/warp7_bl2_el3_setup.c
new file mode 100644
index 0000000..ec13ade
--- /dev/null
+++ b/plat/imx/imx7/warp7/warp7_bl2_el3_setup.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/mmc.h>
+#include <lib/utils.h>
+
+#include <imx_caam.h>
+#include <imx_clock.h>
+#include <imx_io_mux.h>
+#include <imx_uart.h>
+#include <imx_usdhc.h>
+#include <imx7_def.h>
+
+#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 struct mmc_device_info mmc_info;
+
+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;
+
+ zeromem(&params, sizeof(imx_usdhc_params_t));
+ params.reg_base = PLAT_WARP7_BOOT_MMC_BASE;
+ params.clk_rate = 25000000;
+ params.bus_width = MMC_BUS_WIDTH_8;
+ mmc_info.mmc_dev_type = MMC_IS_EMMC;
+ imx_usdhc_init(&params, &mmc_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();
+}
diff --git a/plat/imx/imx8m/ddr/clock.c b/plat/imx/imx8m/ddr/clock.c
new file mode 100644
index 0000000..7fb5730
--- /dev/null
+++ b/plat/imx/imx8m/ddr/clock.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#define IMX_CCM_IP_BASE (IMX_CCM_BASE + 0xa000)
+#define DRAM_SEL_CFG (IMX_CCM_BASE + 0x9800)
+#define CCM_IP_CLK_ROOT_GEN_TAGET(i) (IMX_CCM_IP_BASE + 0x80 * (i) + 0x00)
+#define CCM_IP_CLK_ROOT_GEN_TAGET_SET(i) (IMX_CCM_IP_BASE + 0x80 * (i) + 0x04)
+#define CCM_IP_CLK_ROOT_GEN_TAGET_CLR(i) (IMX_CCM_IP_BASE + 0x80 * (i) + 0x08)
+#define PLL_FREQ_800M U(0x00ece580)
+#define PLL_FREQ_400M U(0x00ec6984)
+#define PLL_FREQ_167M U(0x00f5a406)
+
+void ddr_pll_bypass_100mts(void)
+{
+ /* change the clock source of dram_alt_clk_root to source 2 --100MHz */
+ mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_CLR(0), (0x7 << 24) | (0x7 << 16));
+ mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_SET(0), (0x2 << 24));
+
+ /* change the clock source of dram_apb_clk_root to source 2 --40MHz/2 */
+ mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_CLR(1), (0x7 << 24) | (0x7 << 16));
+ mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_SET(1), (0x2 << 24) | (0x1 << 16));
+
+ /* configure pll bypass mode */
+ mmio_write_32(DRAM_SEL_CFG + 0x4, BIT(24));
+}
+
+void ddr_pll_bypass_400mts(void)
+{
+ /* change the clock source of dram_alt_clk_root to source 1 --400MHz */
+ mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_CLR(0), (0x7 << 24) | (0x7 << 16));
+ mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_SET(0), (0x1 << 24) | (0x1 << 16));
+
+ /* change the clock source of dram_apb_clk_root to source 3 --160MHz/2 */
+ mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_CLR(1), (0x7 << 24) | (0x7 << 16));
+ mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_SET(1), (0x3 << 24) | (0x1 << 16));
+
+ /* configure pll bypass mode */
+ mmio_write_32(DRAM_SEL_CFG + 0x4, BIT(24));
+}
+
+void ddr_pll_unbypass(void)
+{
+ mmio_write_32(DRAM_SEL_CFG + 0x8, BIT(24));
+ mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_CLR(1), (0x7 << 24) | (0x7 << 16));
+ /* to source 4 --800MHz/5 */
+ mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_SET(1), (0x4 << 24) | (0x4 << 16));
+}
+
+#if defined(PLAT_imx8mq)
+void dram_pll_init(unsigned int drate)
+{
+ /* bypass the PLL */
+ mmio_setbits_32(HW_DRAM_PLL_CFG0, 0x30);
+
+ switch (drate) {
+ case 3200:
+ mmio_write_32(HW_DRAM_PLL_CFG2, PLL_FREQ_800M);
+ break;
+ case 1600:
+ mmio_write_32(HW_DRAM_PLL_CFG2, PLL_FREQ_400M);
+ break;
+ case 667:
+ mmio_write_32(HW_DRAM_PLL_CFG2, PLL_FREQ_167M);
+ break;
+ default:
+ break;
+ }
+
+ /* unbypass the PLL */
+ mmio_clrbits_32(HW_DRAM_PLL_CFG0, 0x30);
+ while (!(mmio_read_32(HW_DRAM_PLL_CFG0) & (1 << 31))) {
+ ;
+ }
+}
+#else
+void dram_pll_init(unsigned int drate)
+{
+ /* bypass the PLL */
+ mmio_setbits_32(DRAM_PLL_CTRL, (1 << 16));
+ mmio_clrbits_32(DRAM_PLL_CTRL, (1 << 9));
+
+ switch (drate) {
+ case 2400:
+ mmio_write_32(DRAM_PLL_CTRL + 0x4, (300 << 12) | (3 << 4) | 2);
+ break;
+ case 1600:
+ mmio_write_32(DRAM_PLL_CTRL + 0x4, (400 << 12) | (3 << 4) | 3);
+ break;
+ case 1066:
+ mmio_write_32(DRAM_PLL_CTRL + 0x4, (266 << 12) | (3 << 4) | 3);
+ break;
+ case 667:
+ mmio_write_32(DRAM_PLL_CTRL + 0x4, (334 << 12) | (3 << 4) | 4);
+ break;
+ default:
+ break;
+ }
+
+ mmio_setbits_32(DRAM_PLL_CTRL, BIT(9));
+ /* wait for PLL locked */
+ while (!(mmio_read_32(DRAM_PLL_CTRL) & BIT(31))) {
+ ;
+ }
+
+ /* unbypass the PLL */
+ mmio_clrbits_32(DRAM_PLL_CTRL, BIT(16));
+}
+#endif
+
+/* change the dram clock frequency */
+void dram_clock_switch(unsigned int target_drate, bool bypass_mode)
+{
+ if (bypass_mode) {
+ switch (target_drate) {
+ case 400:
+ ddr_pll_bypass_400mts();
+ break;
+ case 100:
+ ddr_pll_bypass_100mts();
+ break;
+ default:
+ ddr_pll_unbypass();
+ break;
+ }
+ } else {
+ dram_pll_init(target_drate);
+ }
+}
diff --git a/plat/imx/imx8m/ddr/ddr4_dvfs.c b/plat/imx/imx8m/ddr/ddr4_dvfs.c
new file mode 100644
index 0000000..cdc7dc2
--- /dev/null
+++ b/plat/imx/imx8m/ddr/ddr4_dvfs.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <dram.h>
+
+void ddr4_mr_write(uint32_t mr, uint32_t data, uint32_t mr_type, uint32_t rank)
+{
+ uint32_t val, mr_mirror, data_mirror;
+
+ /*
+ * 1. Poll MRSTAT.mr_wr_busy until it is 0 to make sure
+ * that there is no outstanding MR transAction.
+ */
+ while (mmio_read_32(DDRC_MRSTAT(0)) & 0x1) {
+ ;
+ }
+
+ /*
+ * 2. Write the MRCTRL0.mr_type, MRCTRL0.mr_addr, MRCTRL0.mr_rank
+ * and (for MRWs) MRCTRL1.mr_data to define the MR transaction.
+ */
+ val = mmio_read_32(DDRC_DIMMCTL(0));
+ if ((val & 0x2) && (rank == 0x2)) {
+ mr_mirror = (mr & 0x4) | ((mr & 0x1) << 1) | ((mr & 0x2) >> 1); /* BA0, BA1 swap */
+ data_mirror = (data & 0x1607) | ((data & 0x8) << 1) | ((data & 0x10) >> 1) |
+ ((data & 0x20) << 1) | ((data & 0x40) >> 1) | ((data & 0x80) << 1) |
+ ((data & 0x100) >> 1) | ((data & 0x800) << 2) | ((data & 0x2000) >> 2) ;
+ } else {
+ mr_mirror = mr;
+ data_mirror = data;
+ }
+
+ mmio_write_32(DDRC_MRCTRL0(0), mr_type | (mr_mirror << 12) | (rank << 4));
+ mmio_write_32(DDRC_MRCTRL1(0), data_mirror);
+
+ /*
+ * 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 accesses can be
+ * initiated until it is deasserted.
+ */
+ mmio_setbits_32(DDRC_MRCTRL0(0), BIT(31));
+
+ while (mmio_read_32(DDRC_MRSTAT(0))) {
+ ;
+ }
+}
+
+void dram_cfg_all_mr(struct dram_info *info, uint32_t pstate)
+{
+ uint32_t num_rank = info->num_rank;
+ /*
+ * 15. 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).
+ */
+
+ for (int i = 1; i <= num_rank; i++) {
+ for (int j = 0; j < 6; j++) {
+ ddr4_mr_write(j, info->mr_table[pstate][j], 0, i);
+ }
+ ddr4_mr_write(6, info->mr_table[pstate][7], 0, i);
+ }
+}
+
+void sw_pstate(uint32_t pstate, uint32_t drate)
+{
+ uint32_t val;
+
+ mmio_write_32(DDRC_SWCTL(0), 0x0);
+
+ /*
+ * Update any registers which may be required to
+ * change for the new frequency.
+ */
+ mmio_write_32(DDRC_MSTR2(0), pstate);
+ mmio_setbits_32(DDRC_MSTR(0), (0x1 << 29));
+
+ /*
+ * Toggle RFSHCTL3.refresh_update_level to allow the
+ * new refresh-related register values to propagate
+ * to the refresh logic.
+ */
+ val = mmio_read_32(DDRC_RFSHCTL3(0));
+ if (val & 0x2) {
+ mmio_write_32(DDRC_RFSHCTL3(0), val & 0xFFFFFFFD);
+ } else {
+ mmio_write_32(DDRC_RFSHCTL3(0), val | 0x2);
+ }
+
+ /*
+ * 19. If required, trigger the initialization in the PHY.
+ * If using the gen2 multiPHY, PLL initialization should
+ * be triggered at this point. See the PHY databook for
+ * details about the frequency change procedure.
+ */
+ mmio_write_32(DDRC_DFIMISC(0), 0x00000000 | (pstate << 8));
+ mmio_write_32(DDRC_DFIMISC(0), 0x00000020 | (pstate << 8));
+
+ /* wait DFISTAT.dfi_init_complete to 0 */
+ while (mmio_read_32(DDRC_DFISTAT(0)) & 0x1) {
+ ;
+ }
+
+ /* change the clock to the target frequency */
+ dram_clock_switch(drate, false);
+
+ mmio_write_32(DDRC_DFIMISC(0), 0x00000000 | (pstate << 8));
+
+ /* wait DFISTAT.dfi_init_complete to 1 */
+ while (!(mmio_read_32(DDRC_DFISTAT(0)) & 0x1)) {
+ ;
+ }
+
+ /*
+ * When changing frequencies the controller may violate the JEDEC
+ * requirement that no more than 16 refreshes should be issued within
+ * 2*tREFI. These extra refreshes are not expected to cause a problem
+ * in the SDRAM. This issue can be avoided by waiting for at least 2*tREFI
+ * before exiting self-refresh in step 19.
+ */
+ udelay(14);
+
+ /* 14. Exit the self-refresh state by setting PWRCTL.selfref_sw = 0. */
+ mmio_clrbits_32(DDRC_PWRCTL(0), (1 << 5));
+
+ while ((mmio_read_32(DDRC_STAT(0)) & 0x3f) == 0x23) {
+ ;
+ }
+}
+
+void ddr4_swffc(struct dram_info *info, unsigned int pstate)
+{
+ uint32_t drate = info->timing_info->fsp_table[pstate];
+
+ /*
+ * 1. set SWCTL.sw_done to disable quasi-dynamic register
+ * programming outside reset.
+ */
+ mmio_write_32(DDRC_SWCTL(0), 0x0);
+
+ /*
+ * 2. Write 0 to PCTRL_n.port_en. This blocks AXI port(s)
+ * from taking any transaction (blocks traffic on AXI ports).
+ */
+ mmio_write_32(DDRC_PCTRL_0(0), 0x0);
+
+ /*
+ * 3. Poll PSTAT.rd_port_busy_n=0 and PSTAT.wr_port_busy_n=0.
+ * Wait until all AXI ports are idle (the uMCTL2 core has to
+ * be idle).
+ */
+ while (mmio_read_32(DDRC_PSTAT(0)) & 0x10001) {
+ ;
+ }
+
+ /*
+ * 4. Write 0 to SBRCTL.scrub_en. Disable SBR, required only if
+ * SBR instantiated.
+ * 5. Poll SBRSTAT.scrub_busy=0.
+ * 6. Set DERATEEN.derate_enable = 0, if DERATEEN.derate_eanble = 1
+ * and the read latency (RL) value needs to change after the frequency
+ * change (LPDDR2/3/4 only).
+ * 7. Set DBG1.dis_hif=1 so that no new commands will be accepted by the uMCTL2.
+ */
+ mmio_setbits_32(DDRC_DBG1(0), (0x1 << 1));
+
+ /*
+ * 8. Poll DBGCAM.dbg_wr_q_empty and DBGCAM.dbg_rd_q_empty to ensure
+ * that write and read data buffers are empty.
+ */
+ while ((mmio_read_32(DDRC_DBGCAM(0)) & 0x06000000) != 0x06000000) {
+ ;
+ }
+
+ /*
+ * 9. For DDR4, update MR6 with the new tDLLK value via the Mode
+ * Register Write signals
+ * 10. Set DFILPCFG0.dfi_lp_en_sr = 0, if DFILPCFG0.dfi_lp_en_sr = 1,
+ * and wait until DFISTAT.dfi_lp_ack
+ * 11. If DFI PHY Master interface is active in uMCTL2, then disable it
+ * 12. Wait until STAT.operating_mode[1:0]!=11 indicating that the
+ * controller is not in self-refresh mode.
+ */
+ while ((mmio_read_32(DDRC_STAT(0)) & 0x3) == 0x3) {
+ ;
+ }
+
+ /*
+ * 13. Assert PWRCTL.selfref_sw for the DWC_ddr_umctl2 core to enter
+ * the self-refresh mode.
+ */
+ mmio_setbits_32(DDRC_PWRCTL(0), (1 << 5));
+
+ /*
+ * 14. Wait until STAT.operating_mode[1:0]==11 indicating that the
+ * controller core is in self-refresh mode.
+ */
+ while ((mmio_read_32(DDRC_STAT(0)) & 0x3f) != 0x23) {
+ ;
+ }
+
+ sw_pstate(pstate, drate);
+ dram_cfg_all_mr(info, pstate);
+
+ /* 23. Enable HIF commands by setting DBG1.dis_hif=0. */
+ mmio_clrbits_32(DDRC_DBG1(0), (0x1 << 1));
+
+ /*
+ * 24. Reset DERATEEN.derate_enable = 1 if DERATEEN.derate_enable
+ * has been set to 0 in step 6.
+ * 25. If DFI PHY Master interface was active before step 11 then
+ * enable it back by programming DFIPHYMSTR.phymstr_en = 1'b1.
+ * 26. Write 1 to PCTRL_n.port_en. AXI port(s) are no longer blocked
+ * from taking transactions (Re-enable traffic on AXI ports)
+ */
+ mmio_write_32(DDRC_PCTRL_0(0), 0x1);
+
+ /*
+ * 27. Write 1 to SBRCTL.scrub_en. Enable SBR if desired, only
+ * required if SBR instantiated.
+ */
+
+ /*
+ * set SWCTL.sw_done to enable quasi-dynamic register programming
+ * outside reset.
+ */
+ mmio_write_32(DDRC_SWCTL(0), 0x1);
+
+ /* wait SWSTAT.sw_done_ack to 1 */
+ while (!(mmio_read_32(DDRC_SWSTAT(0)) & 0x1)) {
+ ;
+ }
+}
diff --git a/plat/imx/imx8m/ddr/dram.c b/plat/imx/imx8m/ddr/dram.c
new file mode 100644
index 0000000..8ea9ba1
--- /dev/null
+++ b/plat/imx/imx8m/ddr/dram.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2019-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <bl31/interrupt_mgmt.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <plat/common/platform.h>
+
+#include <dram.h>
+
+#define IMX_SIP_DDR_DVFS_GET_FREQ_COUNT 0x10
+#define IMX_SIP_DDR_DVFS_GET_FREQ_INFO 0x11
+
+struct dram_info dram_info;
+
+/* lock used for DDR DVFS */
+spinlock_t dfs_lock;
+
+static volatile uint32_t wfe_done;
+static volatile bool wait_ddrc_hwffc_done = true;
+static unsigned int dev_fsp = 0x1;
+
+static uint32_t fsp_init_reg[3][4] = {
+ { DDRC_INIT3(0), DDRC_INIT4(0), DDRC_INIT6(0), DDRC_INIT7(0) },
+ { DDRC_FREQ1_INIT3(0), DDRC_FREQ1_INIT4(0), DDRC_FREQ1_INIT6(0), DDRC_FREQ1_INIT7(0) },
+ { DDRC_FREQ2_INIT3(0), DDRC_FREQ2_INIT4(0), DDRC_FREQ2_INIT6(0), DDRC_FREQ2_INIT7(0) },
+};
+
+static void get_mr_values(uint32_t (*mr_value)[8])
+{
+ uint32_t init_val;
+ unsigned int i, fsp_index;
+
+ for (fsp_index = 0U; fsp_index < 3U; fsp_index++) {
+ for (i = 0U; i < 4U; i++) {
+ init_val = mmio_read_32(fsp_init_reg[fsp_index][i]);
+ mr_value[fsp_index][2*i] = init_val >> 16;
+ mr_value[fsp_index][2*i + 1] = init_val & 0xFFFF;
+ }
+ }
+}
+
+/* Restore the ddrc configs */
+void dram_umctl2_init(struct dram_timing_info *timing)
+{
+ struct dram_cfg_param *ddrc_cfg = timing->ddrc_cfg;
+ unsigned int i;
+
+ for (i = 0U; i < timing->ddrc_cfg_num; i++) {
+ mmio_write_32(ddrc_cfg->reg, ddrc_cfg->val);
+ ddrc_cfg++;
+ }
+
+ /* set the default fsp to P0 */
+ mmio_write_32(DDRC_MSTR2(0), 0x0);
+}
+
+/* Restore the dram PHY config */
+void dram_phy_init(struct dram_timing_info *timing)
+{
+ struct dram_cfg_param *cfg = timing->ddrphy_cfg;
+ unsigned int i;
+
+ /* Restore the PHY init config */
+ cfg = timing->ddrphy_cfg;
+ for (i = 0U; i < timing->ddrphy_cfg_num; i++) {
+ dwc_ddrphy_apb_wr(cfg->reg, cfg->val);
+ cfg++;
+ }
+
+ /* Restore the DDR PHY CSRs */
+ cfg = timing->ddrphy_trained_csr;
+ for (i = 0U; i < timing->ddrphy_trained_csr_num; i++) {
+ dwc_ddrphy_apb_wr(cfg->reg, cfg->val);
+ cfg++;
+ }
+
+ /* Load the PIE image */
+ cfg = timing->ddrphy_pie;
+ for (i = 0U; i < timing->ddrphy_pie_num; i++) {
+ dwc_ddrphy_apb_wr(cfg->reg, cfg->val);
+ cfg++;
+ }
+}
+
+/* EL3 SGI-8 IPI handler for DDR Dynamic frequency scaling */
+static uint64_t waiting_dvfs(uint32_t id, uint32_t flags,
+ void *handle, void *cookie)
+{
+ uint64_t mpidr = read_mpidr_el1();
+ unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+ uint32_t irq;
+
+ irq = plat_ic_acknowledge_interrupt();
+ if (irq < 1022U) {
+ plat_ic_end_of_interrupt(irq);
+ }
+
+ /* set the WFE done status */
+ spin_lock(&dfs_lock);
+ wfe_done |= (1 << cpu_id * 8);
+ dsb();
+ spin_unlock(&dfs_lock);
+
+ while (1) {
+ /* ddr frequency change done */
+ if (!wait_ddrc_hwffc_done)
+ break;
+
+ wfe();
+ }
+
+ return 0;
+}
+
+void dram_info_init(unsigned long dram_timing_base)
+{
+ uint32_t ddrc_mstr, current_fsp;
+ unsigned int idx = 0;
+ uint32_t flags = 0;
+ uint32_t rc;
+ unsigned int i;
+
+ /* Get the dram type & rank */
+ ddrc_mstr = mmio_read_32(DDRC_MSTR(0));
+
+ dram_info.dram_type = ddrc_mstr & DDR_TYPE_MASK;
+ dram_info.num_rank = (ddrc_mstr >> 24) & ACTIVE_RANK_MASK;
+
+ /* Get current fsp info */
+ current_fsp = mmio_read_32(DDRC_DFIMISC(0)) & 0xf;
+ dram_info.boot_fsp = current_fsp;
+ dram_info.current_fsp = current_fsp;
+
+ get_mr_values(dram_info.mr_table);
+
+ dram_info.timing_info = (struct dram_timing_info *)dram_timing_base;
+
+ /* get the num of supported fsp */
+ for (i = 0U; i < 4U; ++i) {
+ if (!dram_info.timing_info->fsp_table[i]) {
+ break;
+ }
+ idx = i;
+ }
+ dram_info.num_fsp = i;
+
+ /* check if has bypass mode support */
+ if (dram_info.timing_info->fsp_table[idx] < 666) {
+ dram_info.bypass_mode = true;
+ } else {
+ dram_info.bypass_mode = false;
+ }
+
+ /* Register the EL3 handler for DDR DVFS */
+ set_interrupt_rm_flag(flags, NON_SECURE);
+ rc = register_interrupt_type_handler(INTR_TYPE_EL3, waiting_dvfs, flags);
+ if (rc != 0) {
+ panic();
+ }
+}
+
+
+/*
+ * For each freq return the following info:
+ *
+ * r1: data rate
+ * r2: 1 + dram_core parent
+ * r3: 1 + dram_alt parent index
+ * r4: 1 + dram_apb parent index
+ *
+ * The parent indices can be used by an OS who manages source clocks to enabled
+ * them ahead of the switch.
+ *
+ * A parent value of "0" means "don't care".
+ *
+ * Current implementation of freq switch is hardcoded in
+ * plat/imx/common/imx8m/clock.c but in theory this can be enhanced to support
+ * a wide variety of rates.
+ */
+int dram_dvfs_get_freq_info(void *handle, u_register_t index)
+{
+ switch (index) {
+ case 0:
+ SMC_RET4(handle, dram_info.timing_info->fsp_table[0],
+ 1, 0, 5);
+ case 1:
+ if (!dram_info.bypass_mode) {
+ SMC_RET4(handle, dram_info.timing_info->fsp_table[1],
+ 1, 0, 0);
+ }
+ SMC_RET4(handle, dram_info.timing_info->fsp_table[1],
+ 2, 2, 4);
+ case 2:
+ if (!dram_info.bypass_mode) {
+ SMC_RET4(handle, dram_info.timing_info->fsp_table[2],
+ 1, 0, 0);
+ }
+ SMC_RET4(handle, dram_info.timing_info->fsp_table[2],
+ 2, 3, 3);
+ case 3:
+ SMC_RET4(handle, dram_info.timing_info->fsp_table[3],
+ 1, 0, 0);
+ default:
+ SMC_RET1(handle, -3);
+ }
+}
+
+int dram_dvfs_handler(uint32_t smc_fid, void *handle,
+ u_register_t x1, u_register_t x2, u_register_t x3)
+{
+ uint64_t mpidr = read_mpidr_el1();
+ unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+ unsigned int fsp_index = x1;
+ uint32_t online_cores = x2;
+
+ if (x1 == IMX_SIP_DDR_DVFS_GET_FREQ_COUNT) {
+ SMC_RET1(handle, dram_info.num_fsp);
+ } else if (x1 == IMX_SIP_DDR_DVFS_GET_FREQ_INFO) {
+ return dram_dvfs_get_freq_info(handle, x2);
+ } else if (x1 < 4) {
+ wait_ddrc_hwffc_done = true;
+ dsb();
+
+ /* trigger the SGI IPI to info other cores */
+ for (int i = 0; i < PLATFORM_CORE_COUNT; i++) {
+ if (cpu_id != i && (online_cores & (0x1 << (i * 8)))) {
+ plat_ic_raise_el3_sgi(0x8, i);
+ }
+ }
+
+ /* make sure all the core in WFE */
+ online_cores &= ~(0x1 << (cpu_id * 8));
+ while (1) {
+ if (online_cores == wfe_done) {
+ break;
+ }
+ }
+
+ /* flush the L1/L2 cache */
+ dcsw_op_all(DCCSW);
+
+ if (dram_info.dram_type == DDRC_LPDDR4) {
+ lpddr4_swffc(&dram_info, dev_fsp, fsp_index);
+ dev_fsp = (~dev_fsp) & 0x1;
+ } else if (dram_info.dram_type == DDRC_DDR4) {
+ ddr4_swffc(&dram_info, fsp_index);
+ }
+
+ dram_info.current_fsp = fsp_index;
+ wait_ddrc_hwffc_done = false;
+ wfe_done = 0;
+ dsb();
+ sev();
+ isb();
+ }
+
+ SMC_RET1(handle, 0);
+}
diff --git a/plat/imx/imx8m/ddr/dram_retention.c b/plat/imx/imx8m/ddr/dram_retention.c
new file mode 100644
index 0000000..7d4f823
--- /dev/null
+++ b/plat/imx/imx8m/ddr/dram_retention.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <lib/mmio.h>
+
+#include <dram.h>
+#include <platform_def.h>
+
+#define SRC_DDR1_RCR (IMX_SRC_BASE + 0x1000)
+#define SRC_DDR2_RCR (IMX_SRC_BASE + 0x1004)
+
+#define PU_PGC_UP_TRG 0xf8
+#define PU_PGC_DN_TRG 0x104
+#define GPC_PU_PWRHSK (IMX_GPC_BASE + 0x01FC)
+#define CCM_SRC_CTRL_OFFSET (IMX_CCM_BASE + 0x800)
+#define CCM_CCGR_OFFSET (IMX_CCM_BASE + 0x4000)
+#define CCM_SRC_CTRL(n) (CCM_SRC_CTRL_OFFSET + 0x10 * (n))
+#define CCM_CCGR(n) (CCM_CCGR_OFFSET + 0x10 * (n))
+
+#define DRAM_PLL_CTRL (IMX_ANAMIX_BASE + 0x50)
+
+#define DBGCAM_EMPTY 0x36000000
+
+void dram_enter_retention(void)
+{
+ /* Wait DBGCAM to be empty */
+ while (mmio_read_32(DDRC_DBGCAM(0)) != DBGCAM_EMPTY) {
+ ;
+ }
+
+ /* Block AXI ports from taking anymore transactions */
+ mmio_write_32(DDRC_PCTRL_0(0), 0x0);
+ /* Wait until all AXI ports are idle */
+ while (mmio_read_32(DDRC_PSTAT(0)) & 0x10001) {
+ ;
+ }
+
+ /* Enter self refresh */
+ mmio_write_32(DDRC_PWRCTL(0), 0xaa);
+
+ /* LPDDR4 & DDR4/DDR3L need to check different status */
+ if (dram_info.dram_type == DDRC_LPDDR4) {
+ while (0x223 != (mmio_read_32(DDRC_STAT(0)) & 0x33f)) {
+ ;
+ }
+ } else {
+ while (0x23 != (mmio_read_32(DDRC_STAT(0)) & 0x3f)) {
+ ;
+ }
+ }
+
+ mmio_write_32(DDRC_DFIMISC(0), 0x0);
+ mmio_write_32(DDRC_SWCTL(0), 0x0);
+ mmio_write_32(DDRC_DFIMISC(0), 0x1f00);
+ mmio_write_32(DDRC_DFIMISC(0), 0x1f20);
+
+ while (mmio_read_32(DDRC_DFISTAT(0)) & 0x1) {
+ ;
+ }
+
+ mmio_write_32(DDRC_DFIMISC(0), 0x1f00);
+ /* wait DFISTAT.dfi_init_complete to 1 */
+ while (!(mmio_read_32(DDRC_DFISTAT(0)) & 0x1)) {
+ ;
+ }
+
+ mmio_write_32(DDRC_SWCTL(0), 0x1);
+
+ /* should check PhyInLP3 pub reg */
+ dwc_ddrphy_apb_wr(0xd0000, 0x0);
+ if (!(dwc_ddrphy_apb_rd(0x90028) & 0x1)) {
+ INFO("PhyInLP3 = 1\n");
+ }
+ dwc_ddrphy_apb_wr(0xd0000, 0x1);
+
+#if defined(PLAT_imx8mq)
+ /* pwrdnreqn_async adbm/adbs of ddr */
+ mmio_clrbits_32(GPC_PU_PWRHSK, BIT(1));
+ while (mmio_read_32(GPC_PU_PWRHSK) & BIT(18)) {
+ ;
+ }
+ mmio_setbits_32(GPC_PU_PWRHSK, BIT(1));
+#else
+ /* pwrdnreqn_async adbm/adbs of ddr */
+ mmio_clrbits_32(GPC_PU_PWRHSK, BIT(2));
+ while (mmio_read_32(GPC_PU_PWRHSK) & BIT(20)) {
+ ;
+ }
+ mmio_setbits_32(GPC_PU_PWRHSK, BIT(2));
+#endif
+ /* remove PowerOk */
+ mmio_write_32(SRC_DDR1_RCR, 0x8F000008);
+
+ mmio_write_32(CCM_CCGR(5), 0);
+ mmio_write_32(CCM_SRC_CTRL(15), 2);
+
+ /* enable the phy iso */
+ mmio_setbits_32(IMX_GPC_BASE + 0xd40, 1);
+ mmio_setbits_32(IMX_GPC_BASE + PU_PGC_DN_TRG, BIT(5));
+
+ VERBOSE("dram enter retention\n");
+}
+
+void dram_exit_retention(void)
+{
+ VERBOSE("dram exit retention\n");
+ /* assert all reset */
+#if defined(PLAT_imx8mq)
+ mmio_write_32(SRC_DDR2_RCR, 0x8F000003);
+ mmio_write_32(SRC_DDR1_RCR, 0x8F00000F);
+ mmio_write_32(SRC_DDR2_RCR, 0x8F000000);
+#else
+ mmio_write_32(SRC_DDR1_RCR, 0x8F00001F);
+ mmio_write_32(SRC_DDR1_RCR, 0x8F00000F);
+#endif
+ mmio_write_32(CCM_CCGR(5), 2);
+ mmio_write_32(CCM_SRC_CTRL(15), 2);
+
+ /* disable iso */
+ mmio_setbits_32(IMX_GPC_BASE + PU_PGC_UP_TRG, BIT(5));
+ mmio_write_32(SRC_DDR1_RCR, 0x8F000006);
+
+ /* wait dram pll locked */
+ while (!(mmio_read_32(DRAM_PLL_CTRL) & BIT(31))) {
+ ;
+ }
+
+ /* ddrc re-init */
+ dram_umctl2_init(dram_info.timing_info);
+
+ /*
+ * Skips the DRAM init routine and starts up in selfrefresh mode
+ * Program INIT0.skip_dram_init = 2'b11
+ */
+ mmio_setbits_32(DDRC_INIT0(0), 0xc0000000);
+ /* Keeps the controller in self-refresh mode */
+ mmio_write_32(DDRC_PWRCTL(0), 0xaa);
+ mmio_write_32(DDRC_DBG1(0), 0x0);
+ mmio_write_32(SRC_DDR1_RCR, 0x8F000004);
+ mmio_write_32(SRC_DDR1_RCR, 0x8F000000);
+
+ /* before write Dynamic reg, sw_done should be 0 */
+ mmio_write_32(DDRC_SWCTL(0), 0x0);
+
+#if !PLAT_imx8mn
+ if (dram_info.dram_type == DDRC_LPDDR4) {
+ mmio_write_32(DDRC_DDR_SS_GPR0, 0x01); /*LPDDR4 mode */
+ }
+#endif /* !PLAT_imx8mn */
+
+ mmio_write_32(DDRC_DFIMISC(0), 0x0);
+
+ /* dram phy re-init */
+ dram_phy_init(dram_info.timing_info);
+
+ /* DWC_DDRPHYA_APBONLY0_MicroContMuxSel */
+ dwc_ddrphy_apb_wr(0xd0000, 0x0);
+ while (dwc_ddrphy_apb_rd(0x20097)) {
+ ;
+ }
+ dwc_ddrphy_apb_wr(0xd0000, 0x1);
+
+ /* before write Dynamic reg, sw_done should be 0 */
+ mmio_write_32(DDRC_SWCTL(0), 0x0);
+ mmio_write_32(DDRC_DFIMISC(0), 0x20);
+ /* wait DFISTAT.dfi_init_complete to 1 */
+ while (!(mmio_read_32(DDRC_DFISTAT(0)) & 0x1)) {
+ ;
+ }
+
+ /* clear DFIMISC.dfi_init_start */
+ mmio_write_32(DDRC_DFIMISC(0), 0x0);
+ /* set DFIMISC.dfi_init_complete_en */
+ mmio_write_32(DDRC_DFIMISC(0), 0x1);
+
+ /* set SWCTL.sw_done to enable quasi-dynamic register programming */
+ mmio_write_32(DDRC_SWCTL(0), 0x1);
+ /* wait SWSTAT.sw_done_ack to 1 */
+ while (!(mmio_read_32(DDRC_SWSTAT(0)) & 0x1)) {
+ ;
+ }
+
+ mmio_write_32(DDRC_PWRCTL(0), 0x88);
+ /* wait STAT to normal state */
+ while (0x1 != (mmio_read_32(DDRC_STAT(0)) & 0x7)) {
+ ;
+ }
+
+ mmio_write_32(DDRC_PCTRL_0(0), 0x1);
+ /* dis_auto-refresh is set to 0 */
+ mmio_write_32(DDRC_RFSHCTL3(0), 0x0);
+
+ /* should check PhyInLP3 pub reg */
+ dwc_ddrphy_apb_wr(0xd0000, 0x0);
+ if (!(dwc_ddrphy_apb_rd(0x90028) & 0x1)) {
+ VERBOSE("PHYInLP3 = 0\n");
+ }
+ dwc_ddrphy_apb_wr(0xd0000, 0x1);
+}
diff --git a/plat/imx/imx8m/ddr/lpddr4_dvfs.c b/plat/imx/imx8m/ddr/lpddr4_dvfs.c
new file mode 100644
index 0000000..2b4f300
--- /dev/null
+++ b/plat/imx/imx8m/ddr/lpddr4_dvfs.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include <dram.h>
+
+static void lpddr4_mr_write(uint32_t mr_rank, uint32_t mr_addr, uint32_t mr_data)
+{
+ /*
+ * 1. Poll MRSTAT.mr_wr_busy until it is 0. This checks that there
+ * is no outstanding MR transaction. No
+ * writes should be performed to MRCTRL0 and MRCTRL1 if MRSTAT.mr_wr_busy = 1.
+ */
+ while (mmio_read_32(DDRC_MRSTAT(0)) & 0x1)
+ ;
+
+ /*
+ * 2. Write the MRCTRL0.mr_type, MRCTRL0.mr_addr,
+ * MRCTRL0.mr_rank and (for MRWs)
+ * MRCTRL1.mr_data to define the MR transaction.
+ */
+ mmio_write_32(DDRC_MRCTRL0(0), (mr_rank << 4));
+ mmio_write_32(DDRC_MRCTRL1(0), (mr_addr << 8) | mr_data);
+ mmio_setbits_32(DDRC_MRCTRL0(0), BIT(31));
+}
+
+void lpddr4_swffc(struct dram_info *info, unsigned int init_fsp,
+ unsigned int fsp_index)
+
+{
+ uint32_t mr, emr, emr2, emr3;
+ uint32_t mr11, mr12, mr22, mr14;
+ uint32_t val;
+ uint32_t derate_backup[3];
+ uint32_t (*mr_data)[8];
+
+ /* 1. program targetd UMCTL2_REGS_FREQ1/2/3,already done, skip it. */
+
+ /* 2. MR13.FSP-WR=1, MRW to update MR registers */
+ mr_data = info->mr_table;
+ mr = mr_data[fsp_index][0];
+ emr = mr_data[fsp_index][1];
+ emr2 = mr_data[fsp_index][2];
+ emr3 = mr_data[fsp_index][3];
+ mr11 = mr_data[fsp_index][4];
+ mr12 = mr_data[fsp_index][5];
+ mr22 = mr_data[fsp_index][6];
+ mr14 = mr_data[fsp_index][7];
+
+ val = (init_fsp == 1) ? 0x2 << 6 : 0x1 << 6;
+ emr3 = (emr3 & 0x003f) | val | 0x0d00;
+
+ /* 12. set PWRCTL.selfref_en=0 */
+ mmio_clrbits_32(DDRC_PWRCTL(0), 0xf);
+
+ /* It is more safe to config it here */
+ mmio_clrbits_32(DDRC_DFIPHYMSTR(0), 0x1);
+
+ lpddr4_mr_write(3, 13, emr3);
+ lpddr4_mr_write(3, 1, mr);
+ lpddr4_mr_write(3, 2, emr);
+ lpddr4_mr_write(3, 3, emr2);
+ lpddr4_mr_write(3, 11, mr11);
+ lpddr4_mr_write(3, 12, mr12);
+ lpddr4_mr_write(3, 14, mr14);
+ lpddr4_mr_write(3, 22, mr22);
+
+ do {
+ val = mmio_read_32(DDRC_MRSTAT(0));
+ } while (val & 0x1);
+
+ /* 3. disable AXI ports */
+ mmio_write_32(DDRC_PCTRL_0(0), 0x0);
+
+ /* 4.Poll PSTAT.rd_port_busy_n=0 and PSTAT.wr_port_busy_n=0. */
+ do {
+ val = mmio_read_32(DDRC_PSTAT(0));
+ } while (val != 0);
+
+ /* 6.disable SBRCTL.scrub_en, skip if never enable it */
+ /* 7.poll SBRSTAT.scrub_busy Q2: should skip phy master if never enable it */
+ /* Disable phy master */
+#ifdef DFILP_SPT
+ /* 8. disable DFI LP */
+ /* DFILPCFG0.dfi_lp_en_sr */
+ val = mmio_read_32(DDRC_DFILPCFG0(0));
+ if (val & 0x100) {
+ mmio_write_32(DDRC_DFILPCFG0(0), 0x0);
+ do {
+ val = mmio_read_32(DDRC_DFISTAT(0)); // dfi_lp_ack
+ val2 = mmio_read_32(DDRC_STAT(0)); // operating_mode
+ } while (((val & 0x2) == 0x2) && ((val2 & 0x7) == 3));
+ }
+#endif
+ /* 9. wait until in normal or power down states */
+ do {
+ /* operating_mode */
+ val = mmio_read_32(DDRC_STAT(0));
+ } while (((val & 0x7) != 1) && ((val & 0x7) != 2));
+
+ /* 10. Disable automatic derating: derate_enable */
+ val = mmio_read_32(DDRC_DERATEEN(0));
+ derate_backup[0] = val;
+ mmio_clrbits_32(DDRC_DERATEEN(0), 0x1);
+
+ val = mmio_read_32(DDRC_FREQ1_DERATEEN(0));
+ derate_backup[1] = val;
+ mmio_clrbits_32(DDRC_FREQ1_DERATEEN(0), 0x1);
+
+ val = mmio_read_32(DDRC_FREQ2_DERATEEN(0));
+ derate_backup[2] = val;
+ mmio_clrbits_32(DDRC_FREQ2_DERATEEN(0), 0x1);
+
+ /* 11. disable automatic ZQ calibration */
+ mmio_setbits_32(DDRC_ZQCTL0(0), BIT(31));
+ mmio_setbits_32(DDRC_FREQ1_ZQCTL0(0), BIT(31));
+ mmio_setbits_32(DDRC_FREQ2_ZQCTL0(0), BIT(31));
+
+ /* 12. set PWRCTL.selfref_en=0 */
+ mmio_clrbits_32(DDRC_PWRCTL(0), 0x1);
+
+ /* 13.Poll STAT.operating_mode is in "Normal" (001) or "Power-down" (010) */
+ do {
+ val = mmio_read_32(DDRC_STAT(0));
+ } while (((val & 0x7) != 1) && ((val & 0x7) != 2));
+
+ /* 14-15. trigger SW SR */
+ /* bit 5: selfref_sw, bit 6: stay_in_selfref */
+ mmio_setbits_32(DDRC_PWRCTL(0), 0x60);
+
+ /* 16. Poll STAT.selfref_state in "Self Refresh 1" */
+ do {
+ val = mmio_read_32(DDRC_STAT(0));
+ } while ((val & 0x300) != 0x100);
+
+ /* 17. disable dq */
+ mmio_setbits_32(DDRC_DBG1(0), 0x1);
+
+ /* 18. Poll DBGCAM.wr_data_pipeline_empty and DBGCAM.rd_data_pipeline_empty */
+ do {
+ val = mmio_read_32(DDRC_DBGCAM(0));
+ val &= 0x30000000;
+ } while (val != 0x30000000);
+
+ /* 19. change MR13.FSP-OP to new FSP and MR13.VRCG to high current */
+ emr3 = (((~init_fsp) & 0x1) << 7) | (0x1 << 3) | (emr3 & 0x0077) | 0x0d00;
+ lpddr4_mr_write(3, 13, emr3);
+
+ /* 20. enter SR Power Down */
+ mmio_clrsetbits_32(DDRC_PWRCTL(0), 0x60, 0x20);
+
+ /* 21. Poll STAT.selfref_state is in "SR Power down" */
+ do {
+ val = mmio_read_32(DDRC_STAT(0));
+ } while ((val & 0x300) != 0x200);
+
+ /* 22. set dfi_init_complete_en = 0 */
+
+ /* 23. switch clock */
+ /* set SWCTL.dw_done to 0 */
+ mmio_write_32(DDRC_SWCTL(0), 0x0000);
+
+ /* 24. program frequency mode=1(bit 29), target_frequency=target_freq (bit 29) */
+ mmio_write_32(DDRC_MSTR2(0), fsp_index);
+
+ /* 25. DBICTL for FSP-OP[1], skip it if never enable it */
+
+ /* 26.trigger initialization in the PHY */
+
+ /* Q3: if refresh level is updated, then should program */
+ /* as updating refresh, need to toggle refresh_update_level signal */
+ val = mmio_read_32(DDRC_RFSHCTL3(0));
+ val = val ^ 0x2;
+ mmio_write_32(DDRC_RFSHCTL3(0), val);
+
+ /* Q4: only for legacy PHY, so here can skipped */
+
+ /* dfi_frequency -> 0x1x */
+ val = mmio_read_32(DDRC_DFIMISC(0));
+ val &= 0xFE;
+ val |= (fsp_index << 8);
+ mmio_write_32(DDRC_DFIMISC(0), val);
+ /* dfi_init_start */
+ val |= 0x20;
+ mmio_write_32(DDRC_DFIMISC(0), val);
+
+ /* polling dfi_init_complete de-assert */
+ do {
+ val = mmio_read_32(DDRC_DFISTAT(0));
+ } while ((val & 0x1) == 0x1);
+
+ /* change the clock frequency */
+ dram_clock_switch(info->timing_info->fsp_table[fsp_index], info->bypass_mode);
+
+ /* dfi_init_start de-assert */
+ mmio_clrbits_32(DDRC_DFIMISC(0), 0x20);
+
+ /* polling dfi_init_complete re-assert */
+ do {
+ val = mmio_read_32(DDRC_DFISTAT(0));
+ } while ((val & 0x1) == 0x0);
+
+ /* 27. set ZQCTL0.dis_srx_zqcl = 1 */
+ if (fsp_index == 0) {
+ mmio_setbits_32(DDRC_ZQCTL0(0), BIT(30));
+ } else if (fsp_index == 1) {
+ mmio_setbits_32(DDRC_FREQ1_ZQCTL0(0), BIT(30));
+ } else {
+ mmio_setbits_32(DDRC_FREQ2_ZQCTL0(0), BIT(30));
+ }
+
+ /* 28,29. exit "self refresh power down" to stay "self refresh 2" */
+ /* exit SR power down */
+ mmio_clrsetbits_32(DDRC_PWRCTL(0), 0x60, 0x40);
+ /* 30. Poll STAT.selfref_state in "Self refresh 2" */
+ do {
+ val = mmio_read_32(DDRC_STAT(0));
+ } while ((val & 0x300) != 0x300);
+
+ /* 31. change MR13.VRCG to normal */
+ emr3 = (emr3 & 0x00f7) | 0x0d00;
+ lpddr4_mr_write(3, 13, emr3);
+
+ /* enable PHY master */
+ mmio_write_32(DDRC_DFIPHYMSTR(0), 0x1);
+
+ /* 32. issue ZQ if required: zq_calib_short, bit 4 */
+ /* polling zq_calib_short_busy */
+ mmio_setbits_32(DDRC_DBGCMD(0), 0x10);
+
+ do {
+ val = mmio_read_32(DDRC_DBGSTAT(0));
+ } while ((val & 0x10) != 0x0);
+
+ /* 33. Reset ZQCTL0.dis_srx_zqcl=0 */
+ if (fsp_index == 1)
+ mmio_clrbits_32(DDRC_FREQ1_ZQCTL0(0), BIT(30));
+ else if (fsp_index == 2)
+ mmio_clrbits_32(DDRC_FREQ2_ZQCTL0(0), BIT(30));
+ else
+ mmio_clrbits_32(DDRC_ZQCTL0(0), BIT(30));
+
+ /* set SWCTL.dw_done to 1 and poll SWSTAT.sw_done_ack=1 */
+ mmio_write_32(DDRC_SWCTL(0), 0x1);
+
+ /* wait SWSTAT.sw_done_ack to 1 */
+ do {
+ val = mmio_read_32(DDRC_SWSTAT(0));
+ } while ((val & 0x1) == 0x0);
+
+ /* 34. set PWRCTL.stay_in_selfreh=0, exit SR */
+ mmio_clrbits_32(DDRC_PWRCTL(0), 0x40);
+ /* wait tXSR */
+
+ /* 35. Poll STAT.selfref_state in "Idle" */
+ do {
+ val = mmio_read_32(DDRC_STAT(0));
+ } while ((val & 0x300) != 0x0);
+
+#ifdef DFILP_SPT
+ /* 36. restore dfi_lp.dfi_lp_en_sr */
+ mmio_setbits_32(DDRC_DFILPCFG0(0), BIT(8));
+#endif
+
+ /* 37. re-enable CAM: dis_dq */
+ mmio_clrbits_32(DDRC_DBG1(0), 0x1);
+
+ /* 38. re-enable automatic SR: selfref_en */
+ mmio_setbits_32(DDRC_PWRCTL(0), 0x1);
+
+ /* 39. re-enable automatic ZQ: dis_auto_zq=0 */
+ /* disable automatic ZQ calibration */
+ if (fsp_index == 1)
+ mmio_clrbits_32(DDRC_FREQ1_ZQCTL0(0), BIT(31));
+ else if (fsp_index == 2)
+ mmio_clrbits_32(DDRC_FREQ2_ZQCTL0(0), BIT(31));
+ else
+ mmio_clrbits_32(DDRC_ZQCTL0(0), BIT(31));
+ /* 40. re-emable automatic derating: derate_enable */
+ mmio_write_32(DDRC_DERATEEN(0), derate_backup[0]);
+ mmio_write_32(DDRC_FREQ1_DERATEEN(0), derate_backup[1]);
+ mmio_write_32(DDRC_FREQ2_DERATEEN(0), derate_backup[2]);
+
+ /* 41. write 1 to PCTRL.port_en */
+ mmio_write_32(DDRC_PCTRL_0(0), 0x1);
+
+ /* 42. enable SBRCTL.scrub_en, skip if never enable it */
+}
diff --git a/plat/imx/imx8m/gpc_common.c b/plat/imx/imx8m/gpc_common.c
new file mode 100644
index 0000000..e674d7a
--- /dev/null
+++ b/plat/imx/imx8m/gpc_common.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <gpc.h>
+#include <imx8m_psci.h>
+#include <plat_imx8.h>
+
+#define MAX_PLL_NUM U(10)
+
+static uint32_t gpc_imr_offset[] = { IMR1_CORE0_A53, IMR1_CORE1_A53, IMR1_CORE2_A53, IMR1_CORE3_A53, };
+
+DEFINE_BAKERY_LOCK(gpc_lock);
+
+#define FSL_SIP_CONFIG_GPC_PM_DOMAIN 0x03
+
+#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)
+{
+
+ bakery_lock_get(&gpc_lock);
+
+ /* enable the wfi power down of the core */
+ mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id));
+
+ bakery_lock_release(&gpc_lock);
+
+ /* 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)
+{
+ bakery_lock_get(&gpc_lock);
+
+ /* clear the wfi power down bit of the core */
+ mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id));
+
+ bakery_lock_release(&gpc_lock);
+
+ /* 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)
+{
+ bakery_lock_get(&gpc_lock);
+
+ 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);
+ }
+
+ bakery_lock_release(&gpc_lock);
+}
+
+/*
+ * 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);
+ imx_a53_plat_slot_config(true);
+ }
+
+ mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val);
+ } 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));
+}
+
+struct pll_override {
+ uint32_t reg;
+ uint32_t override_mask;
+};
+
+struct pll_override pll[MAX_PLL_NUM] = {
+ {.reg = 0x0, .override_mask = (1 << 12) | (1 << 8), },
+ {.reg = 0x14, .override_mask = (1 << 12) | (1 << 8), },
+ {.reg = 0x28, .override_mask = (1 << 12) | (1 << 8), },
+ {.reg = 0x50, .override_mask = (1 << 12) | (1 << 8), },
+ {.reg = 0x64, .override_mask = (1 << 10) | (1 << 8), },
+ {.reg = 0x74, .override_mask = (1 << 10) | (1 << 8), },
+ {.reg = 0x84, .override_mask = (1 << 10) | (1 << 8), },
+ {.reg = 0x94, .override_mask = 0x5555500, },
+ {.reg = 0x104, .override_mask = 0x5555500, },
+ {.reg = 0x114, .override_mask = 0x500, },
+};
+
+#define PLL_BYPASS BIT(4)
+void imx_anamix_override(bool enter)
+{
+ unsigned int i;
+
+ /*
+ * bypass all the plls & enable the override bit before
+ * entering DSM mode.
+ */
+ for (i = 0U; i < MAX_PLL_NUM; i++) {
+ if (enter) {
+ mmio_setbits_32(IMX_ANAMIX_BASE + pll[i].reg, PLL_BYPASS);
+ mmio_setbits_32(IMX_ANAMIX_BASE + pll[i].reg, pll[i].override_mask);
+ } else {
+ mmio_clrbits_32(IMX_ANAMIX_BASE + pll[i].reg, PLL_BYPASS);
+ mmio_clrbits_32(IMX_ANAMIX_BASE + pll[i].reg, pll[i].override_mask);
+ }
+ }
+}
+
+int imx_gpc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, u_register_t x3)
+{
+ switch (x1) {
+ case FSL_SIP_CONFIG_GPC_PM_DOMAIN:
+ imx_gpc_pm_domain_enable(x2, x3);
+ break;
+ default:
+ return SMC_UNK;
+ }
+
+ return 0;
+}
diff --git a/plat/imx/imx8m/imx8m_caam.c b/plat/imx/imx8m/imx8m_caam.c
new file mode 100644
index 0000000..a491550
--- /dev/null
+++ b/plat/imx/imx8m/imx8m_caam.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019-2022 NXP. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <imx8m_caam.h>
+
+#define HAB_JR0_DID U(0x8011)
+
+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 */
+ if (mmio_read_32(CAAM_JR0MID) == HAB_JR0_DID) {
+ NOTICE("Do not release JR0 to NS as it can be used by HAB\n");
+ } else {
+ 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);
+}
diff --git a/plat/imx/imx8m/imx8m_csu.c b/plat/imx/imx8m/imx8m_csu.c
new file mode 100644
index 0000000..2b3a7d9
--- /dev/null
+++ b/plat/imx/imx8m/imx8m_csu.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2020-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include <imx8m_csu.h>
+
+void imx_csu_init(const struct imx_csu_cfg *csu_cfg)
+{
+ const struct imx_csu_cfg *csu = csu_cfg;
+ uint32_t val;
+
+ while (csu->type != CSU_INVALID) {
+ switch (csu->type) {
+ case CSU_CSL:
+ val = mmio_read_32(CSLx_REG(csu->idx));
+ if (val & CSLx_LOCK(csu->idx)) {
+ break;
+ }
+ mmio_clrsetbits_32(CSLx_REG(csu->idx), CSLx_CFG(0xff, csu->idx),
+ CSLx_CFG(csu->csl_level | (csu->lock << 8), csu->idx));
+ break;
+ case CSU_HP:
+ val = mmio_read_32(CSU_HP_REG(csu->idx));
+ if (val & CSU_HP_LOCK(csu->idx)) {
+ break;
+ }
+ mmio_clrsetbits_32(CSU_HP_REG(csu->idx), CSU_HP_CFG(0x1, csu->idx),
+ CSU_HP_CFG(csu->hp | (csu->lock << 0x1), csu->idx));
+ break;
+ case CSU_SA:
+ val = mmio_read_32(CSU_SA_REG(csu->idx));
+ if (val & CSU_SA_LOCK(csu->idx)) {
+ break;
+ }
+ mmio_clrsetbits_32(CSU_SA_REG(csu->idx), CSU_SA_CFG(0x1, csu->idx),
+ CSU_SA_CFG(csu->sa | (csu->lock << 0x1), csu->idx));
+ break;
+ case CSU_HPCONTROL:
+ val = mmio_read_32(CSU_HPCONTROL_REG(csu->idx));
+ if (val & CSU_HPCONTROL_LOCK(csu->idx)) {
+ break;
+ }
+ mmio_clrsetbits_32(CSU_HPCONTROL_REG(csu->idx), CSU_HPCONTROL_CFG(0x1, csu->idx),
+ CSU_HPCONTROL_CFG(csu->hpctrl | (csu->lock << 0x1), csu->idx));
+ break;
+ default:
+ break;
+ }
+
+ csu++;
+ }
+}
diff --git a/plat/imx/imx8m/imx8m_dyn_cfg_helpers.c b/plat/imx/imx8m/imx8m_dyn_cfg_helpers.c
new file mode 100644
index 0000000..5d65ef2
--- /dev/null
+++ b/plat/imx/imx8m/imx8m_dyn_cfg_helpers.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022, Linaro.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#if MEASURED_BOOT
+#include <common/desc_image_load.h>
+#endif
+#include <common/fdt_wrappers.h>
+#include <libfdt.h>
+#include <platform_def.h>
+
+#define DTB_PROP_HW_LOG_ADDR "tpm_event_log_addr"
+#define DTB_PROP_HW_LOG_SIZE "tpm_event_log_size"
+
+#if MEASURED_BOOT
+
+static int imx8m_event_log_fdt_init_overlay(uintptr_t dt_base, int dt_size)
+{
+ int ret;
+ int offset;
+ void *dtb = (void *)dt_base;
+
+ ret = fdt_create_empty_tree(dtb, dt_size);
+ if (ret < 0) {
+ ERROR("cannot create empty dtb tree: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ }
+
+ offset = fdt_path_offset(dtb, "/");
+ if (offset < 0) {
+ ERROR("cannot find root of the tree: %s\n",
+ fdt_strerror(offset));
+ return offset;
+ }
+
+ offset = fdt_add_subnode(dtb, offset, "fragment@0");
+ if (offset < 0) {
+ ERROR("cannot add fragment node: %s\n",
+ fdt_strerror(offset));
+ return offset;
+ }
+
+ ret = fdt_setprop_string(dtb, offset, "target-path", "/");
+ if (ret < 0) {
+ ERROR("cannot set target-path property: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ }
+
+ offset = fdt_add_subnode(dtb, offset, "__overlay__");
+ if (offset < 0) {
+ ERROR("cannot add __overlay__ node: %s\n",
+ fdt_strerror(offset));
+ return ret;
+ }
+
+ offset = fdt_add_subnode(dtb, offset, "tpm_event_log");
+ if (offset < 0) {
+ ERROR("cannot add tpm_event_log node: %s\n",
+ fdt_strerror(offset));
+ return offset;
+ }
+
+ ret = fdt_setprop_string(dtb, offset, "compatible",
+ "arm,tpm_event_log");
+ if (ret < 0) {
+ ERROR("cannot set compatible property: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ }
+
+ ret = fdt_setprop_u64(dtb, offset, "tpm_event_log_addr", 0);
+ if (ret < 0) {
+ ERROR("cannot set tpm_event_log_addr property: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ }
+
+ ret = fdt_setprop_u32(dtb, offset, "tpm_event_log_size", 0);
+ if (ret < 0) {
+ ERROR("cannot set tpm_event_log_size property: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ }
+
+ return ret;
+}
+
+/*
+ * Write the Event Log address and its size in the DTB.
+ *
+ * This function is supposed to be called only by BL2.
+ *
+ * Returns:
+ * 0 = success
+ * < 0 = error
+ */
+static int imx8m_set_event_log_info(uintptr_t config_base,
+ uintptr_t log_addr, size_t log_size)
+{
+ /* As libfdt uses void *, we can't avoid this cast */
+ void *dtb = (void *)config_base;
+ const char *compatible_tpm = "arm,tpm_event_log";
+ uint64_t base = cpu_to_fdt64(log_addr);
+ uint32_t sz = cpu_to_fdt32(log_size);
+ int err, node;
+
+ err = fdt_open_into(dtb, dtb, PLAT_IMX8M_DTO_MAX_SIZE);
+ if (err < 0) {
+ ERROR("Invalid Device Tree at %p: error %d\n", dtb, err);
+ return err;
+ }
+
+ /*
+ * Verify that the DTB is valid, before attempting to write to it,
+ * and get the DTB root node.
+ */
+
+ /* Check if the pointer to DT is correct */
+ err = fdt_check_header(dtb);
+ if (err < 0) {
+ WARN("Invalid DTB file passed\n");
+ return err;
+ }
+
+ /*
+ * Find the TPM node in device tree.
+ */
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible_tpm);
+ if (node < 0) {
+ ERROR("The compatible property '%s' not%s", compatible_tpm,
+ " found in the config\n");
+ return node;
+ }
+
+ err = fdt_setprop(dtb, node, DTB_PROP_HW_LOG_ADDR, &base, 8);
+ if (err < 0) {
+ ERROR("Failed to add log addr err %d\n", err);
+ return err;
+ }
+
+ err = fdt_setprop(dtb, node, DTB_PROP_HW_LOG_SIZE, &sz, 4);
+ if (err < 0) {
+ ERROR("Failed to add log addr err %d\n", err);
+ return err;
+ }
+
+ err = fdt_pack(dtb);
+ if (err < 0) {
+ ERROR("Failed to pack Device Tree at %p: error %d\n", dtb, err);
+ return err;
+ }
+
+ /*
+ * Ensure that the info written to the DTB is visible
+ * to other images.
+ */
+ flush_dcache_range(config_base, fdt_totalsize(dtb));
+
+ return err;
+}
+
+/*
+ * This function writes the Event Log address and its size
+ * in the QEMU DTB.
+ *
+ * This function is supposed to be called only by BL2.
+ *
+ * Returns:
+ * 0 = success
+ * < 0 = error
+ */
+int imx8m_set_nt_fw_info(size_t log_size, uintptr_t *ns_log_addr)
+{
+ uintptr_t ns_addr;
+ int err;
+
+ assert(ns_log_addr != NULL);
+
+ ns_addr = PLAT_IMX8M_DTO_BASE + PLAT_IMX8M_DTO_MAX_SIZE;
+
+ imx8m_event_log_fdt_init_overlay(PLAT_IMX8M_DTO_BASE,
+ PLAT_IMX8M_DTO_MAX_SIZE);
+
+ /* Write the Event Log address and its size in the DTB */
+ err = imx8m_set_event_log_info(PLAT_IMX8M_DTO_BASE,
+ ns_addr, log_size);
+
+ /* Return Event Log address in Non-secure memory */
+ *ns_log_addr = (err < 0) ? 0UL : ns_addr;
+ return err;
+}
+
+#endif /* MEASURED_BOOT */
diff --git a/plat/imx/imx8m/imx8m_image_load.c b/plat/imx/imx8m/imx8m_image_load.c
new file mode 100644
index 0000000..3a03069
--- /dev/null
+++ b/plat/imx/imx8m/imx8m_image_load.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+
+#include <platform_def.h>
+#include <plat/common/platform.h>
+
+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();
+}
diff --git a/plat/imx/imx8m/imx8m_measured_boot.c b/plat/imx/imx8m/imx8m_measured_boot.c
new file mode 100644
index 0000000..ec61606
--- /dev/null
+++ b/plat/imx/imx8m/imx8m_measured_boot.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2022, Linaro.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include "./include/imx8m_measured_boot.h"
+#include <drivers/measured_boot/event_log/event_log.h>
+#include <plat/arm/common/plat_arm.h>
+
+/* Event Log data */
+static uint8_t event_log[PLAT_IMX_EVENT_LOG_MAX_SIZE];
+
+/* FVP table with platform specific image IDs, names and PCRs */
+static const event_log_metadata_t imx8m_event_log_metadata[] = {
+ { BL31_IMAGE_ID, EVLOG_BL31_STRING, PCR_0 },
+ { BL32_IMAGE_ID, EVLOG_BL32_STRING, PCR_0 },
+ { BL32_EXTRA1_IMAGE_ID, EVLOG_BL32_EXTRA1_STRING, PCR_0 },
+ { BL32_EXTRA2_IMAGE_ID, EVLOG_BL32_EXTRA2_STRING, PCR_0 },
+ { BL33_IMAGE_ID, EVLOG_BL33_STRING, PCR_0 },
+ { EVLOG_INVALID_ID, NULL, (unsigned int)(-1) } /* Terminator */
+};
+
+const event_log_metadata_t *plat_event_log_get_metadata(void)
+{
+ return imx8m_event_log_metadata;
+}
+
+int plat_mboot_measure_image(unsigned int image_id, image_info_t *image_data)
+{
+ /* Calculate image hash and record data in Event Log */
+ int err = event_log_measure_and_record(image_data->image_base,
+ image_data->image_size,
+ image_id);
+ if (err != 0) {
+ ERROR("%s%s image id %u (%i)\n",
+ "Failed to ", "record", image_id, err);
+ return err;
+ }
+
+ return 0;
+}
+
+void bl2_plat_mboot_init(void)
+{
+ event_log_init(event_log, event_log + sizeof(event_log));
+ event_log_write_header();
+}
+
+void bl2_plat_mboot_finish(void)
+{
+ int rc = 0;
+
+ /* Event Log address in Non-Secure memory */
+ uintptr_t ns_log_addr;
+
+ /* Event Log filled size */
+ size_t event_log_cur_size;
+
+ event_log_cur_size = event_log_get_cur_size(event_log);
+
+ rc = imx8m_set_nt_fw_info(event_log_cur_size, &ns_log_addr);
+ if (rc != 0) {
+ ERROR("%s(): Unable to update %s_FW_CONFIG\n",
+ __func__, "NT");
+ /*
+ * It is a fatal error because on i.MX U-boot assumes that
+ * a valid event log exists and will use it to record the
+ * measurements into the fTPM.
+ */
+ panic();
+ }
+
+ /* Copy Event Log to Non-secure memory */
+ (void)memcpy((void *)ns_log_addr, (const void *)event_log,
+ event_log_cur_size);
+
+ /* Ensure that the Event Log is visible in Non-secure memory */
+ flush_dcache_range(ns_log_addr, event_log_cur_size);
+
+ dump_event_log((uint8_t *)event_log, event_log_cur_size);
+}
diff --git a/plat/imx/imx8m/imx8m_psci_common.c b/plat/imx/imx8m/imx8m_psci_common.c
new file mode 100644
index 0000000..8f545d6
--- /dev/null
+++ b/plat/imx/imx8m/imx8m_psci_common.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <dram.h>
+#include <gpc.h>
+#include <imx8m_psci.h>
+#include <plat_imx8.h>
+
+/*
+ * 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_START;
+
+ 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_START;
+ 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);
+ dram_enter_retention();
+ imx_anamix_override(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_anamix_override(false);
+ dram_exit_retention();
+ 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;
+}
+
+static void __dead2 imx_wdog_restart(bool external_reset)
+{
+ uintptr_t wdog_base = IMX_WDOG_BASE;
+ unsigned int val;
+
+ val = mmio_read_16(wdog_base);
+ /*
+ * Common watchdog init flags, for additional details check
+ * 6.6.4.1 Watchdog Control Register (WDOGx_WCR)
+ *
+ * Initial bit selection:
+ * WDOG_WCR_WDE - Enable the watchdog.
+ *
+ * 0x000E mask is used to keep previous values (that could be set
+ * in SPL) of WDBG and WDE/WDT (both are write-one once-only bits).
+ */
+ val = (val & 0x000E) | WDOG_WCR_WDE;
+ if (external_reset) {
+ /*
+ * To assert WDOG_B (external reset) we have
+ * to set WDA bit 0 (already set in previous step).
+ * SRS bits are required to be set to 1 (no effect on the
+ * system).
+ */
+ val |= WDOG_WCR_SRS;
+ } else {
+ /*
+ * To assert Software Reset Signal (internal reset) we have
+ * to set SRS bit to 0 (already set in previous step).
+ * SRE bit is required to be set to 1 when used in
+ * conjunction with the Software Reset Signal before
+ * SRS asserton, otherwise SRS bit will just automatically
+ * reset to 1.
+ *
+ * Also we set WDA to 1 (no effect on system).
+ */
+ val |= WDOG_WCR_SRE | WDOG_WCR_WDA;
+ }
+
+ 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_reset(void)
+{
+#ifdef IMX_WDOG_B_RESET
+ imx_wdog_restart(true);
+#else
+ imx_wdog_restart(false);
+#endif
+}
+
+int imx_system_reset2(int is_vendor, int reset_type, u_register_t cookie)
+{
+ imx_wdog_restart(false);
+
+ /*
+ * imx_wdog_restart cannot return (as it's a __dead function),
+ * however imx_system_reset2 has to return some value according
+ * to PSCI v1.1 spec.
+ */
+ return 0;
+}
+
+void __dead2 imx_system_off(void)
+{
+ uint32_t val;
+
+ val = mmio_read_32(IMX_SNVS_BASE + SNVS_LPCR);
+ val |= SNVS_LPCR_SRTC_ENV | SNVS_LPCR_DP_EN | SNVS_LPCR_TOP;
+ mmio_write_32(IMX_SNVS_BASE + SNVS_LPCR, val);
+
+ 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_off(CLUSTER_PWR_STATE(target_state))) {
+ imx_set_rbc_count();
+ udelay(30);
+ }
+
+ while (1)
+ wfi();
+}
diff --git a/plat/imx/imx8m/imx8mm/gpc.c b/plat/imx/imx8m/imx8mm/gpc.c
new file mode 100644
index 0000000..cc1cb10
--- /dev/null
+++ b/plat/imx/imx8m/imx8mm/gpc.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <lib/smccc.h>
+#include <platform_def.h>
+#include <services/std_svc.h>
+
+#include <gpc.h>
+#include <imx_sip_svc.h>
+
+#define MIPI_PWR_REQ BIT(0)
+#define PCIE_PWR_REQ BIT(1)
+#define OTG1_PWR_REQ BIT(2)
+#define OTG2_PWR_REQ BIT(3)
+#define HSIOMIX_PWR_REQ BIT(4)
+#define GPU2D_PWR_REQ BIT(6)
+#define GPUMIX_PWR_REQ BIT(7)
+#define VPUMIX_PWR_REQ BIT(8)
+#define GPU3D_PWR_REQ BIT(9)
+#define DISPMIX_PWR_REQ BIT(10)
+#define VPU_G1_PWR_REQ BIT(11)
+#define VPU_G2_PWR_REQ BIT(12)
+#define VPU_H1_PWR_REQ BIT(13)
+
+#define HSIOMIX_ADB400_SYNC (0x3 << 5)
+#define DISPMIX_ADB400_SYNC BIT(7)
+#define VPUMIX_ADB400_SYNC BIT(8)
+#define GPU3D_ADB400_SYNC BIT(9)
+#define GPU2D_ADB400_SYNC BIT(10)
+#define GPUMIX_ADB400_SYNC BIT(11)
+#define HSIOMIX_ADB400_ACK (0x3 << 23)
+#define DISPMIX_ADB400_ACK BIT(25)
+#define VPUMIX_ADB400_ACK BIT(26)
+#define GPU3D_ADB400_ACK BIT(27)
+#define GPU2D_ADB400_ACK BIT(28)
+#define GPUMIX_ADB400_ACK BIT(29)
+
+#define MIPI_PGC 0xc00
+#define PCIE_PGC 0xc40
+#define OTG1_PGC 0xc80
+#define OTG2_PGC 0xcc0
+#define HSIOMIX_PGC 0xd00
+#define GPU2D_PGC 0xd80
+#define GPUMIX_PGC 0xdc0
+#define VPUMIX_PGC 0xe00
+#define GPU3D_PGC 0xe40
+#define DISPMIX_PGC 0xe80
+#define VPU_G1_PGC 0xec0
+#define VPU_G2_PGC 0xf00
+#define VPU_H1_PGC 0xf40
+
+enum pu_domain_id {
+ HSIOMIX,
+ PCIE,
+ OTG1,
+ OTG2,
+ GPUMIX,
+ VPUMIX,
+ VPU_G1,
+ VPU_G2,
+ VPU_H1,
+ DISPMIX,
+ MIPI,
+ /* below two domain only for ATF internal use */
+ GPU2D,
+ GPU3D,
+ MAX_DOMAINS,
+};
+
+/* PU domain */
+static struct imx_pwr_domain pu_domains[] = {
+ IMX_MIX_DOMAIN(HSIOMIX, false),
+ IMX_PD_DOMAIN(PCIE, false),
+ IMX_PD_DOMAIN(OTG1, true),
+ IMX_PD_DOMAIN(OTG2, true),
+ IMX_MIX_DOMAIN(GPUMIX, false),
+ IMX_MIX_DOMAIN(VPUMIX, false),
+ IMX_PD_DOMAIN(VPU_G1, false),
+ IMX_PD_DOMAIN(VPU_G2, false),
+ IMX_PD_DOMAIN(VPU_H1, false),
+ IMX_MIX_DOMAIN(DISPMIX, false),
+ IMX_PD_DOMAIN(MIPI, false),
+ /* below two domain only for ATF internal use */
+ IMX_MIX_DOMAIN(GPU2D, false),
+ IMX_MIX_DOMAIN(GPU3D, false),
+};
+
+static unsigned int pu_domain_status;
+
+#define GPU_RCR 0x40
+#define VPU_RCR 0x44
+
+#define VPU_CTL_BASE 0x38330000
+#define BLK_SFT_RSTN_CSR 0x0
+#define H1_SFT_RSTN BIT(2)
+#define G1_SFT_RSTN BIT(1)
+#define G2_SFT_RSTN BIT(0)
+
+#define DISP_CTL_BASE 0x32e28000
+
+void vpu_sft_reset_assert(uint32_t domain_id)
+{
+ uint32_t val;
+
+ val = mmio_read_32(VPU_CTL_BASE + BLK_SFT_RSTN_CSR);
+
+ switch (domain_id) {
+ case VPU_G1:
+ val &= ~G1_SFT_RSTN;
+ mmio_write_32(VPU_CTL_BASE + BLK_SFT_RSTN_CSR, val);
+ break;
+ case VPU_G2:
+ val &= ~G2_SFT_RSTN;
+ mmio_write_32(VPU_CTL_BASE + BLK_SFT_RSTN_CSR, val);
+ break;
+ case VPU_H1:
+ val &= ~H1_SFT_RSTN;
+ mmio_write_32(VPU_CTL_BASE + BLK_SFT_RSTN_CSR, val);
+ break;
+ default:
+ break;
+ }
+}
+
+void vpu_sft_reset_deassert(uint32_t domain_id)
+{
+ uint32_t val;
+
+ val = mmio_read_32(VPU_CTL_BASE + BLK_SFT_RSTN_CSR);
+
+ switch (domain_id) {
+ case VPU_G1:
+ val |= G1_SFT_RSTN;
+ mmio_write_32(VPU_CTL_BASE + BLK_SFT_RSTN_CSR, val);
+ break;
+ case VPU_G2:
+ val |= G2_SFT_RSTN;
+ mmio_write_32(VPU_CTL_BASE + BLK_SFT_RSTN_CSR, val);
+ break;
+ case VPU_H1:
+ val |= H1_SFT_RSTN;
+ mmio_write_32(VPU_CTL_BASE + BLK_SFT_RSTN_CSR, val);
+ break;
+ default:
+ break;
+ }
+}
+
+void imx_gpc_pm_domain_enable(uint32_t domain_id, bool on)
+{
+ if (domain_id >= MAX_DOMAINS) {
+ return;
+ }
+
+ struct imx_pwr_domain *pwr_domain = &pu_domains[domain_id];
+
+ if (on) {
+ pu_domain_status |= (1 << domain_id);
+
+ if (domain_id == VPU_G1 || domain_id == VPU_G2 ||
+ domain_id == VPU_H1) {
+ vpu_sft_reset_assert(domain_id);
+ }
+
+ /* HSIOMIX has no PU bit, so skip for it */
+ if (domain_id != HSIOMIX) {
+ /* clear the PGC bit */
+ mmio_clrbits_32(IMX_GPC_BASE + pwr_domain->pgc_offset, 0x1);
+
+ /* power up the domain */
+ mmio_setbits_32(IMX_GPC_BASE + PU_PGC_UP_TRG, pwr_domain->pwr_req);
+
+ /* wait for power request done */
+ while (mmio_read_32(IMX_GPC_BASE + PU_PGC_UP_TRG) & pwr_domain->pwr_req) {
+ ;
+ }
+ }
+
+ if (domain_id == VPU_G1 || domain_id == VPU_G2 ||
+ domain_id == VPU_H1) {
+ vpu_sft_reset_deassert(domain_id);
+ /* dealy for a while to make sure reset done */
+ udelay(100);
+ }
+
+ if (domain_id == GPUMIX) {
+ /* assert reset */
+ mmio_write_32(IMX_SRC_BASE + GPU_RCR, 0x1);
+
+ /* power up GPU2D */
+ mmio_clrbits_32(IMX_GPC_BASE + GPU2D_PGC, 0x1);
+
+ mmio_setbits_32(IMX_GPC_BASE + PU_PGC_UP_TRG, GPU2D_PWR_REQ);
+
+ /* wait for power request done */
+ while (mmio_read_32(IMX_GPC_BASE + PU_PGC_UP_TRG) & GPU2D_PWR_REQ) {
+ ;
+ }
+
+ udelay(1);
+
+ /* power up GPU3D */
+ mmio_clrbits_32(IMX_GPC_BASE + GPU3D_PGC, 0x1);
+
+ mmio_setbits_32(IMX_GPC_BASE + PU_PGC_UP_TRG, GPU3D_PWR_REQ);
+
+ /* wait for power request done */
+ while (mmio_read_32(IMX_GPC_BASE + PU_PGC_UP_TRG) & GPU3D_PWR_REQ) {
+ ;
+ }
+
+ udelay(10);
+ /* release the gpumix reset */
+ mmio_write_32(IMX_SRC_BASE + GPU_RCR, 0x0);
+ udelay(10);
+ }
+
+ /* vpu sft clock enable */
+ if (domain_id == VPUMIX) {
+ mmio_write_32(IMX_SRC_BASE + VPU_RCR, 0x1);
+ udelay(5);
+ mmio_write_32(IMX_SRC_BASE + VPU_RCR, 0x0);
+ udelay(5);
+
+ /* enable all clock */
+ mmio_write_32(VPU_CTL_BASE + 0x4, 0x7);
+ }
+
+ if (domain_id == DISPMIX) {
+ /* special setting for DISPMIX */
+ mmio_write_32(DISP_CTL_BASE + 0x4, 0x1fff);
+ mmio_write_32(DISP_CTL_BASE, 0x7f);
+ mmio_write_32(DISP_CTL_BASE + 0x8, 0x30000);
+ }
+
+ /* handle the ADB400 sync */
+ if (pwr_domain->need_sync) {
+ /* clear adb power down request */
+ mmio_setbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, pwr_domain->adb400_sync);
+
+ /* wait for adb power request ack */
+ while (!(mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & pwr_domain->adb400_ack)) {
+ ;
+ }
+ }
+
+ if (domain_id == GPUMIX) {
+ /* power up GPU2D ADB */
+ mmio_setbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, GPU2D_ADB400_SYNC);
+
+ /* wait for adb power request ack */
+ while (!(mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & GPU2D_ADB400_ACK)) {
+ ;
+ }
+
+ /* power up GPU3D ADB */
+ mmio_setbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, GPU3D_ADB400_SYNC);
+
+ /* wait for adb power request ack */
+ while (!(mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & GPU3D_ADB400_ACK)) {
+ ;
+ }
+ }
+ } else {
+ pu_domain_status &= ~(1 << domain_id);
+
+ if (domain_id == OTG1 || domain_id == OTG2) {
+ return;
+ }
+
+ /* GPU2D & GPU3D ADB power down */
+ if (domain_id == GPUMIX) {
+ mmio_clrbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, GPU2D_ADB400_SYNC);
+
+ /* wait for adb power request ack */
+ while ((mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & GPU2D_ADB400_ACK)) {
+ ;
+ }
+
+ mmio_clrbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, GPU3D_ADB400_SYNC);
+
+ /* wait for adb power request ack */
+ while ((mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & GPU3D_ADB400_ACK)) {
+ ;
+ }
+ }
+
+ /* handle the ADB400 sync */
+ if (pwr_domain->need_sync) {
+ /* set adb power down request */
+ mmio_clrbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, pwr_domain->adb400_sync);
+
+ /* wait for adb power request ack */
+ while ((mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & pwr_domain->adb400_ack)) {
+ ;
+ }
+ }
+
+ if (domain_id == GPUMIX) {
+ /* power down GPU2D */
+ mmio_setbits_32(IMX_GPC_BASE + GPU2D_PGC, 0x1);
+
+ mmio_setbits_32(IMX_GPC_BASE + PU_PGC_DN_TRG, GPU2D_PWR_REQ);
+
+ /* wait for power request done */
+ while (mmio_read_32(IMX_GPC_BASE + PU_PGC_DN_TRG) & GPU2D_PWR_REQ) {
+ ;
+ }
+
+ /* power down GPU3D */
+ mmio_setbits_32(IMX_GPC_BASE + GPU3D_PGC, 0x1);
+
+ mmio_setbits_32(IMX_GPC_BASE + PU_PGC_DN_TRG, GPU3D_PWR_REQ);
+
+ /* wait for power request done */
+ while (mmio_read_32(IMX_GPC_BASE + PU_PGC_DN_TRG) & GPU3D_PWR_REQ) {
+ ;
+ }
+ }
+
+ /* HSIOMIX has no PU bit, so skip for it */
+ if (domain_id != HSIOMIX) {
+ /* set the PGC bit */
+ mmio_setbits_32(IMX_GPC_BASE + pwr_domain->pgc_offset, 0x1);
+
+ /* power down the domain */
+ mmio_setbits_32(IMX_GPC_BASE + PU_PGC_DN_TRG, pwr_domain->pwr_req);
+
+ /* wait for power request done */
+ while (mmio_read_32(IMX_GPC_BASE + PU_PGC_DN_TRG) & pwr_domain->pwr_req) {
+ ;
+ }
+ }
+ }
+}
+
+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);
+}
diff --git a/plat/imx/imx8m/imx8mm/imx8mm_bl2_el3_setup.c b/plat/imx/imx8m/imx8mm/imx8mm_bl2_el3_setup.c
new file mode 100644
index 0000000..c39dd93
--- /dev/null
+++ b/plat/imx/imx8m/imx8mm/imx8mm_bl2_el3_setup.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2017-2021 NXP
+ * Copyright 2021 Arm
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <context.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/mmc.h>
+#include <lib/mmio.h>
+#include <lib/optee_utils.h>
+#include <lib/utils.h>
+#include <stdbool.h>
+#include <tbbr_img_def.h>
+
+#include <imx_aipstz.h>
+#include <imx_csu.h>
+#include <imx_uart.h>
+#include <imx_usdhc.h>
+#include <plat/common/platform.h>
+
+#include "imx8mm_private.h"
+#include "platform_def.h"
+
+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 void imx8mm_usdhc_setup(void)
+{
+ imx_usdhc_params_t params;
+ struct mmc_device_info info;
+
+ params.reg_base = PLAT_IMX8MM_BOOT_MMC_BASE;
+ /*
+ The imx8mm SD Card Speed modes for USDHC2
+ +--------------+--------------------+--------------+--------------+
+ |Bus Speed Mode|Max. Clock Frequency|Max. Bus Speed|Signal Voltage|
+ +--------------+--------------------+--------------+--------------+
+ |Default Speed | 25 MHz | 12.5 MB/s | 3.3V |
+ |High Speed | 50 MHz | 25 MB/s | 3.3V |
+ +--------------+--------------------+--------------+--------------+
+
+ We pick 50 Mhz here for High Speed access.
+ */
+ params.clk_rate = 50000000;
+ params.bus_width = MMC_BUS_WIDTH_1;
+ params.flags = 0;
+ info.mmc_dev_type = MMC_IS_SD;
+ info.ocr_voltage = OCR_3_3_3_4 | OCR_3_2_3_3;
+ imx_usdhc_init(&params, &info);
+}
+
+void bl2_el3_early_platform_setup(u_register_t arg1, u_register_t arg2,
+ u_register_t arg3, u_register_t arg4)
+{
+ int i;
+ static console_t console;
+
+ /* enable CSU NS access permission */
+ for (i = 0; i < MAX_CSU_NUM; i++) {
+ mmio_write_32(IMX_CSU_BASE + i * 4, CSU_CSL_OPEN_ACCESS);
+ }
+
+ /* config the aips access permission */
+ imx_aipstz_init(aipstz);
+
+ console_imx_uart_register(IMX_BOOT_UART_BASE, IMX_BOOT_UART_CLK_IN_HZ,
+ IMX_CONSOLE_BAUDRATE, &console);
+
+ generic_delay_timer_init();
+
+ /* select the CKIL source to 32K OSC */
+ mmio_write_32(0x30360124, 0x1);
+
+ imx8mm_usdhc_setup();
+
+ /* Open handles to a FIP image */
+ plat_imx_io_setup();
+}
+
+void bl2_el3_plat_arch_setup(void)
+{
+}
+
+void bl2_platform_setup(void)
+{
+}
+
+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 *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");
+ }
+
+ break;
+ default:
+ /* Do nothing in default case */
+ break;
+ }
+
+ return err;
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+ return COUNTER_FREQUENCY;
+}
+
+void bl2_plat_runtime_setup(void)
+{
+ return;
+}
diff --git a/plat/imx/imx8m/imx8mm/imx8mm_bl2_mem_params_desc.c b/plat/imx/imx8m/imx8mm/imx8mm_bl2_mem_params_desc.c
new file mode 100644
index 0000000..e44345d
--- /dev/null
+++ b/plat/imx/imx8m/imx8mm/imx8mm_bl2_mem_params_desc.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+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.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 = INVALID_IMAGE_ID,
+ },
+ {
+ .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_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 = BL32_BASE,
+ .image_info.image_max_size = BL32_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 = PLAT_NS_IMAGE_OFFSET,
+
+ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+ VERSION_2, image_info_t,
+ IMAGE_ATTRIB_SKIP_LOADING),
+ # else
+ .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 = PLAT_NS_IMAGE_SIZE,
+ # endif /* PRELOADED_BL33_BASE */
+
+ .next_handoff_image_id = INVALID_IMAGE_ID,
+ }
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs);
diff --git a/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c b/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c
new file mode 100644
index 0000000..67bfd36
--- /dev/null
+++ b/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2019-2022 ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <drivers/arm/tzc380.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include <dram.h>
+#include <gpc.h>
+#include <imx_aipstz.h>
+#include <imx_uart.h>
+#include <imx_rdc.h>
+#include <imx8m_caam.h>
+#include <imx8m_csu.h>
+#include <plat_imx8.h>
+
+#define TRUSTY_PARAMS_LEN_BYTES (4096*2)
+
+/*
+ * Note: DRAM region is mapped with entire size available and uses MT_RW
+ * attributes.
+ * See details in docs/plat/imx8m.rst "High Assurance Boot (HABv4)" section
+ * for explanation of this mapping scheme.
+ */
+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 */
+ MAP_REGION_FLAT(OCRAM_S_BASE, OCRAM_S_SIZE, MT_DEVICE | MT_RW), /* OCRAM_S */
+ MAP_REGION_FLAT(IMX_DDRPHY_BASE, IMX_DDR_IPS_SIZE, MT_DEVICE | MT_RW), /* DDRMIX */
+ MAP_REGION_FLAT(IMX_VPUMIX_BASE, IMX_VPUMIX_SIZE, MT_DEVICE | MT_RW), /* VPUMIX */
+ MAP_REGION_FLAT(IMX_CAAM_RAM_BASE, IMX_CAAM_RAM_SIZE, MT_MEMORY | MT_RW), /* CAMM RAM */
+ MAP_REGION_FLAT(IMX_NS_OCRAM_BASE, IMX_NS_OCRAM_SIZE, MT_MEMORY | MT_RW), /* NS OCRAM */
+ MAP_REGION_FLAT(IMX_ROM_BASE, IMX_ROM_SIZE, MT_MEMORY | MT_RO), /* ROM code */
+ MAP_REGION_FLAT(IMX_DRAM_BASE, IMX_DRAM_SIZE, MT_MEMORY | MT_RW | MT_NS), /* DRAM */
+ {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(RDC_MDA_M4, DID1),
+
+ /* peripherals domain permission */
+ RDC_PDAPn(RDC_PDAP_UART4, D1R | D1W),
+ RDC_PDAPn(RDC_PDAP_UART2, D0R | D0W),
+
+ /* memory region */
+
+ /* Sentinel */
+ {0},
+};
+
+static const struct imx_csu_cfg csu_cfg[] = {
+ /* peripherals csl setting */
+ CSU_CSLx(0x1, CSU_SEC_LEVEL_0, UNLOCKED),
+
+ /* master HP0~1 */
+
+ /* SA setting */
+
+ /* HP control setting */
+
+ /* 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_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);
+
+ imx_csu_init(csu_cfg);
+
+ 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_FLAG_BOOT);
+
+ imx8m_caam_init();
+
+ /*
+ * 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);
+
+#if defined(SPD_opteed) || defined(SPD_trusty)
+ /* 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 = 0;
+
+ /* Pass TEE base and size to bl33 */
+ bl33_image_ep_info.args.arg1 = BL32_BASE;
+ bl33_image_ep_info.args.arg2 = BL32_SIZE;
+
+#ifdef SPD_trusty
+ bl32_image_ep_info.args.arg0 = BL32_SIZE;
+ bl32_image_ep_info.args.arg1 = BL32_BASE;
+#else
+ /* Make sure memory is clean */
+ mmio_write_32(BL32_FDT_OVERLAY_ADDR, 0);
+ bl33_image_ep_info.args.arg3 = BL32_FDT_OVERLAY_ADDR;
+ bl32_image_ep_info.args.arg3 = BL32_FDT_OVERLAY_ADDR;
+#endif
+#endif
+
+ bl31_tzc380_setup();
+}
+
+#define MAP_BL31_TOTAL \
+ MAP_REGION_FLAT(BL31_START, BL31_SIZE, MT_MEMORY | MT_RW | MT_SECURE)
+#define MAP_BL31_RO \
+ MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, MT_MEMORY | MT_RO | MT_SECURE)
+#define MAP_COHERENT_MEM \
+ MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+#define MAP_BL32_TOTAL \
+ MAP_REGION_FLAT(BL32_BASE, BL32_SIZE, MT_MEMORY | MT_RW)
+
+void bl31_plat_arch_setup(void)
+{
+ const mmap_region_t bl_regions[] = {
+ MAP_BL31_TOTAL,
+ MAP_BL31_RO,
+#if USE_COHERENT_MEM
+ MAP_COHERENT_MEM,
+#endif
+ /* Map TEE memory */
+ MAP_BL32_TOTAL,
+ {0}
+ };
+
+ setup_page_tables(bl_regions, imx_mmap);
+ 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);
+
+ /* Init the dram info */
+ dram_info_init(SAVED_DRAM_TIMING_BASE);
+
+ 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;
+}
+
+#ifdef SPD_trusty
+void plat_trusty_set_boot_args(aapcs64_params_t *args)
+{
+ args->arg0 = BL32_SIZE;
+ args->arg1 = BL32_BASE;
+ args->arg2 = TRUSTY_PARAMS_LEN_BYTES;
+}
+#endif
diff --git a/plat/imx/imx8m/imx8mm/imx8mm_psci.c b/plat/imx/imx8m/imx8mm/imx8mm_psci.c
new file mode 100644
index 0000000..815d3a2
--- /dev/null
+++ b/plat/imx/imx8m/imx8mm/imx8mm_psci.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <gpc.h>
+#include <imx8m_psci.h>
+#include <plat_imx8.h>
+
+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_reset2 = imx_system_reset2,
+ .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;
+}
diff --git a/plat/imx/imx8m/imx8mm/imx8mm_rotpk.S b/plat/imx/imx8m/imx8mm/imx8mm_rotpk.S
new file mode 100644
index 0000000..544ee8a
--- /dev/null
+++ b/plat/imx/imx8m/imx8mm/imx8mm_rotpk.S
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+ .global imx8mm_rotpk_hash
+ .global imx8mm_rotpk_hash_end
+imx8mm_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
+imx8mm_rotpk_hash_end:
diff --git a/plat/imx/imx8m/imx8mm/imx8mm_trusted_boot.c b/plat/imx/imx8m/imx8mm/imx8mm_trusted_boot.c
new file mode 100644
index 0000000..a4384d7
--- /dev/null
+++ b/plat/imx/imx8m/imx8mm/imx8mm_trusted_boot.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+extern char imx8mm_rotpk_hash[], imx8mm_rotpk_hash_end[];
+
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+ unsigned int *flags)
+{
+ *key_ptr = imx8mm_rotpk_hash;
+ *key_len = imx8mm_rotpk_hash_end - imx8mm_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);
+}
diff --git a/plat/imx/imx8m/imx8mm/include/gpc_reg.h b/plat/imx/imx8m/imx8mm/include/gpc_reg.h
new file mode 100644
index 0000000..1a4eae5
--- /dev/null
+++ b/plat/imx/imx8m/imx8mm/include/gpc_reg.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GPC_REG_H
+#define GPC_REG_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 LPS_CPU1 0x114
+#define A53_CORE0_PGC 0x800
+#define A53_PLAT_PGC 0x900
+#define PLAT_PGC_PCR 0x900
+#define NOC_PGC_PCR 0xa40
+#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 MASTER1_LPM_HSK BIT(7)
+#define MASTER2_LPM_HSK BIT(8)
+
+#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 NOC_PDN_SLT_CTRL BIT(10)
+#define NOC_PUP_SLT_CTRL BIT(11)
+#define NOC_PGC_PDN_ACK BIT(3)
+#define NOC_PGC_PUP_ACK BIT(19)
+
+#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)
+
+#define MIPI_PWR_REQ BIT(0)
+#define PCIE_PWR_REQ BIT(1)
+#define OTG1_PWR_REQ BIT(2)
+#define OTG2_PWR_REQ BIT(3)
+#define HSIOMIX_PWR_REQ BIT(4)
+#define DDRMIX_PWR_REQ BIT(5)
+#define GPU2D_PWR_REQ BIT(6)
+#define GPUMIX_PWR_REQ BIT(7)
+#define VPUMIX_PWR_REQ BIT(8)
+#define GPU3D_PWR_REQ BIT(9)
+#define DISPMIX_PWR_REQ BIT(10)
+#define VPU_G1_PWR_REQ BIT(11)
+#define VPU_G2_PWR_REQ BIT(12)
+#define VPU_H1_PWR_REQ BIT(13)
+
+#define DDRMIX_ADB400_SYNC BIT(2)
+#define HSIOMIX_ADB400_SYNC (0x3 << 5)
+#define DISPMIX_ADB400_SYNC BIT(7)
+#define VPUMIX_ADB400_SYNC BIT(8)
+#define GPU3D_ADB400_SYNC BIT(9)
+#define GPU2D_ADB400_SYNC BIT(10)
+#define GPUMIX_ADB400_SYNC BIT(11)
+#define DDRMIX_ADB400_ACK BIT(20)
+#define HSIOMIX_ADB400_ACK (0x3 << 23)
+#define DISPMIX_ADB400_ACK BIT(25)
+#define VPUMIX_ADB400_ACK BIT(26)
+#define GPU3D_ADB400_ACK BIT(27)
+#define GPU2D_ADB400_ACK BIT(28)
+#define GPUMIX_ADB400_ACK BIT(29)
+
+#define MIPI_PGC 0xc00
+#define PCIE_PGC 0xc40
+#define OTG1_PGC 0xc80
+#define OTG2_PGC 0xcc0
+#define HSIOMIX_PGC 0xd00
+#define DDRMIX_PGC 0xd40
+#define GPU2D_PGC 0xd80
+#define GPUMIX_PGC 0xdc0
+#define VPUMIX_PGC 0xe00
+#define GPU3D_PGC 0xe40
+#define DISPMIX_PGC 0xe80
+#define VPU_G1_PGC 0xec0
+#define VPU_G2_PGC 0xf00
+#define VPU_H1_PGC 0xf40
+
+#define IRQ_IMR_NUM U(4)
+
+#endif /* GPC_REG_H */
diff --git a/plat/imx/imx8m/imx8mm/include/imx8mm_private.h b/plat/imx/imx8m/imx8mm/include/imx8mm_private.h
new file mode 100644
index 0000000..5e0ef97
--- /dev/null
+++ b/plat/imx/imx8m/imx8mm/include/imx8mm_private.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX8MM_PRIVATE_H
+#define IMX8MM_PRIVATE_H
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+void plat_imx_io_setup(void);
+
+#endif /* IMX8MM_PRIVATE_H */
diff --git a/plat/imx/imx8m/imx8mm/include/imx_sec_def.h b/plat/imx/imx8m/imx8mm/include/imx_sec_def.h
new file mode 100644
index 0000000..6215983
--- /dev/null
+++ b/plat/imx/imx8m/imx8mm/include/imx_sec_def.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2020-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_SEC_DEF_H
+#define IMX_SEC_DEF_H
+
+/* RDC MDA index */
+enum rdc_mda_idx {
+ RDC_MDA_A53 = 0,
+ RDC_MDA_M4 = 1,
+ RDC_MDA_PCIE_CTRL1 = 2,
+ RDC_MDA_SDMA3p = 3,
+ RDC_MDA_VPU_Decoders = 4,
+ RDC_MDA_LCDIF = 5,
+ RDC_MDA_CSI1 = 6,
+ RDC_MDA_SDMA3b = 7,
+ RDC_MDA_Coresight = 8,
+ RDC_MDA_DAP = 9,
+ RDC_MDA_CAAM = 10,
+ RDC_MDA_SDMA1p = 11,
+ RDC_MDA_SDMA1b = 12,
+ RDC_MDA_APBHDMA = 13,
+ RDC_MDA_NAND = 14,
+ RDC_MDA_uSDHC1 = 15,
+ RDC_MDA_uSDHC2 = 16,
+ RDC_MDA_uSDHC3 = 17,
+ RDC_MDA_GPU = 18,
+ RDC_MDA_USB1 = 19,
+ RDC_MDA_USB2 = 20,
+ RDC_MDA_TESTPORT = 21,
+ RDC_MDA_ENET1_TX = 22,
+ RDC_MDA_ENET1_RX = 23,
+ RDC_MDA_SDMA2p = 24,
+ RDC_MDA_SDMA2b = 24,
+ RDC_MDA_SDMA2_to_SPBA2 = 24,
+ RDC_MDA_SDMA3_to_SPBA2 = 25,
+ RDC_MDA_SDMA1_to_SPBA1 = 26,
+};
+
+/* RDC Peripherals index */
+enum rdc_pdap_idx {
+ RDC_PDAP_GPIO2 = 1,
+ RDC_PDAP_GPIO3 = 2,
+ RDC_PDAP_GPIO4 = 3,
+ RDC_PDAP_GPIO5 = 4,
+ RDC_PDAP_ANA_TSENSOR = 6,
+ RDC_PDAP_ANA_OSC = 7,
+ RDC_PDAP_WDOG1 = 8,
+ RDC_PDAP_WDOG2 = 9,
+ RDC_PDAP_WDOG3 = 10,
+ RDC_PDAP_SDMA3 = 11,
+ RDC_PDAP_SDMA2 = 12,
+ RDC_PDAP_GPT1 = 13,
+ RDC_PDAP_GPT2 = 14,
+ RDC_PDAP_GPT3 = 15,
+ RDC_PDAP_ROMCP = 17,
+ RDC_PDAP_IOMUXC = 19,
+ RDC_PDAP_IOMUXC_GPR = 20,
+ RDC_PDAP_OCOTP_CTRL = 21,
+ RDC_PDAP_ANA_PLL = 22,
+ RDC_PDAP_SNVS_HP = 23,
+ RDC_PDAP_CCM = 24,
+ RDC_PDAP_SRC = 25,
+ RDC_PDAP_GPC = 26,
+ RDC_PDAP_SEMAPHORE1 = 27,
+ RDC_PDAP_SEMAPHORE2 = 28,
+ RDC_PDAP_RDC = 29,
+ RDC_PDAP_CSU = 30,
+ RDC_PDAP_LCDIF = 32,
+ RDC_PDAP_MIPI_DSI = 33,
+ RDC_PDAP_CSI = 34,
+ RDC_PDAP_MIPI_CSI = 35,
+ RDC_PDAP_USB1 = 36,
+ RDC_PDAP_PWM1 = 38,
+ RDC_PDAP_PWM2 = 39,
+ RDC_PDAP_PWM3 = 40,
+ RDC_PDAP_PWM4 = 41,
+ RDC_PDAP_System_Counter_RD = 42,
+ RDC_PDAP_System_Counter_CMP = 43,
+ RDC_PDAP_System_Counter_CTRL = 44,
+ RDC_PDAP_GPT6 = 46,
+ RDC_PDAP_GPT5 = 47,
+ RDC_PDAP_GPT4 = 48,
+ RDC_PDAP_TZASC = 56,
+ RDC_PDAP_USB2 = 59,
+ RDC_PDAP_PERFMON1 = 60,
+ RDC_PDAP_PERFMON2 = 61,
+ RDC_PDAP_PLATFORM_CTRL = 62,
+ RDC_PDAP_QoSC = 63,
+ RDC_PDAP_I2C1 = 66,
+ RDC_PDAP_I2C2 = 67,
+ RDC_PDAP_I2C3 = 68,
+ RDC_PDAP_I2C4 = 69,
+ RDC_PDAP_UART4 = 70,
+ RDC_PDAP_MU_A = 74,
+ RDC_PDAP_MU_B = 75,
+ RDC_PDAP_SEMAPHORE_HS = 76,
+ RDC_PDAP_SAI1 = 78,
+ RDC_PDAP_SAI2 = 79,
+ RDC_PDAP_SAI3 = 80,
+ RDC_PDAP_SAI5 = 82,
+ RDC_PDAP_SAI6 = 83,
+ RDC_PDAP_uSDHC1 = 84,
+ RDC_PDAP_uSDHC2 = 85,
+ RDC_PDAP_uSDHC3 = 86,
+ RDC_PDAP_PCIE_PHY1 = 88,
+ RDC_PDAP_SPBA2 = 90,
+ RDC_PDAP_QSPI = 91,
+ RDC_PDAP_SDMA1 = 93,
+ RDC_PDAP_ENET1 = 94,
+ RDC_PDAP_SPDIF1 = 97,
+ RDC_PDAP_eCSPI1 = 98,
+ RDC_PDAP_eCSPI2 = 99,
+ RDC_PDAP_eCSPI3 = 100,
+ RDC_PDAP_MICFIL = 101,
+ RDC_PDAP_UART1 = 102,
+ RDC_PDAP_UART3 = 104,
+ RDC_PDAP_UART2 = 105,
+ RDC_PDAP_SPDIF2 = 106,
+ RDC_PDAP_SPBA1 = 111,
+ RDC_PDAP_CAAM = 114,
+};
+
+enum csu_csl_idx {
+ CSU_CSL_GPIO1 = 0,
+ CSU_CSL_GPIO2 = 1,
+ CSU_CSL_GPIO3 = 2,
+ CSU_CSL_GPIO4 = 3,
+ CSU_CSL_GPIO5 = 4,
+ CSU_CSL_ANA_TSENSOR = 6,
+ CSU_CSL_ANA_OSC = 7,
+ CSU_CSL_WDOG1 = 8,
+ CSU_CSL_WDOG2 = 9,
+ CSU_CSL_WDOG3 = 10,
+ CSU_CSL_SDMA2 = 12,
+ CSU_CSL_GPT1 = 13,
+ CSU_CSL_GPT2 = 14,
+ CSU_CSL_GPT3 = 15,
+ CSU_CSL_ROMCP = 17,
+ CSU_CSL_LCDIF = 18,
+ CSU_CSL_IOMUXC = 19,
+ CSU_CSL_IOMUXC_GPR = 20,
+ CSU_CSL_OCOTP_CTRL = 21,
+ CSU_CSL_ANA_PLL = 22,
+ CSU_CSL_SNVS_HP = 23,
+ CSU_CSL_CCM = 24,
+ CSU_CSL_SRC = 25,
+ CSU_CSL_GPC = 26,
+ CSU_CSL_SEMAPHORE1 = 27,
+ CSU_CSL_SEMAPHORE2 = 28,
+ CSU_CSL_RDC = 29,
+ CSU_CSL_CSU = 30,
+ CSU_CSL_DC_MST0 = 32,
+ CSU_CSL_DC_MST1 = 33,
+ CSU_CSL_DC_MST2 = 34,
+ CSU_CSL_DC_MST3 = 35,
+ CSU_CSL_PWM1 = 38,
+ CSU_CSL_PWM2 = 39,
+ CSU_CSL_PWM3 = 40,
+ CSU_CSL_PWM4 = 41,
+ CSU_CSL_System_Counter_RD = 42,
+ CSU_CSL_System_Counter_CMP = 43,
+ CSU_CSL_System_Counter_CTRL = 44,
+ CSU_CSL_GPT6 = 46,
+ CSU_CSL_GPT5 = 47,
+ CSU_CSL_GPT4 = 48,
+ CSU_CSL_TZASC = 56,
+ CSU_CSL_MTR = 59,
+ CSU_CSL_PERFMON1 = 60,
+ CSU_CSL_PERFMON2 = 61,
+ CSU_CSL_PLATFORM_CTRL = 62,
+ CSU_CSL_QoSC = 63,
+ CSU_CSL_MIPI_PHY = 64,
+ CSU_CSL_MIPI_DSI = 65,
+ CSU_CSL_I2C1 = 66,
+ CSU_CSL_I2C2 = 67,
+ CSU_CSL_I2C3 = 68,
+ CSU_CSL_I2C4 = 69,
+ CSU_CSL_UART4 = 70,
+ CSU_CSL_MIPI_CSI1 = 71,
+ CSU_CSL_MIPI_CSI_PHY1 = 72,
+ CSU_CSL_CSI1 = 73,
+ CSU_CSL_MU_A = 74,
+ CSU_CSL_MU_B = 75,
+ CSU_CSL_SEMAPHORE_HS = 76,
+ CSU_CSL_SAI1 = 78,
+ CSU_CSL_SAI6 = 80,
+ CSU_CSL_SAI5 = 81,
+ CSU_CSL_SAI4 = 82,
+ CSU_CSL_uSDHC1 = 84,
+ CSU_CSL_uSDHC2 = 85,
+ CSU_CSL_MIPI_CSI2 = 86,
+ CSU_CSL_MIPI_CSI_PHY2 = 87,
+ CSU_CSL_CSI2 = 88,
+ CSU_CSL_SPBA2 = 90,
+ CSU_CSL_QSPI = 91,
+ CSU_CSL_SDMA1 = 93,
+ CSU_CSL_ENET1 = 94,
+ CSU_CSL_SPDIF1 = 97,
+ CSU_CSL_eCSPI1 = 98,
+ CSU_CSL_eCSPI2 = 99,
+ CSU_CSL_eCSPI3 = 100,
+ CSU_CSL_UART1 = 102,
+ CSU_CSL_UART3 = 104,
+ CSU_CSL_UART2 = 105,
+ CSU_CSL_SPDIF2 = 106,
+ CSU_CSL_SAI2 = 107,
+ CSU_CSL_SAI3 = 108,
+ CSU_CSL_SPBA1 = 111,
+ CSU_CSL_CAAM = 114,
+};
+
+#endif /* IMX_SEC_DEF_H */
diff --git a/plat/imx/imx8m/imx8mm/include/platform_def.h b/plat/imx/imx8m/imx8mm/include/platform_def.h
new file mode 100644
index 0000000..65749f3
--- /dev/null
+++ b/plat/imx/imx8m/imx8mm/include/platform_def.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#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 U(0x0)
+#define PLATFORM_MAX_CPU_PER_CLUSTER U(4)
+#define PLATFORM_CLUSTER_COUNT U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT U(4)
+#define PLATFORM_CLUSTER1_CORE_COUNT U(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 PLAT_PRI_BITS U(3)
+#define PLAT_SDEI_CRITICAL_PRI 0x10
+#define PLAT_SDEI_NORMAL_PRI 0x20
+#define PLAT_SDEI_SGI_PRIVATE U(9)
+
+#if defined(NEED_BL2)
+#define BL2_BASE U(0x920000)
+#define BL2_SIZE SZ_128K
+#define BL2_LIMIT (BL2_BASE + BL2_SIZE)
+#define BL31_BASE U(0x900000)
+#define IMX_FIP_BASE U(0x40310000)
+#define IMX_FIP_SIZE U(0x000300000)
+#define IMX_FIP_LIMIT U(FIP_BASE + FIP_SIZE)
+
+/* Define FIP image location on eMMC */
+#define IMX_FIP_MMC_BASE U(0x100000)
+
+#define PLAT_IMX8MM_BOOT_MMC_BASE U(0x30B50000) /* SD */
+#else
+#define BL31_BASE U(0x920000)
+#endif
+
+#define BL31_SIZE SZ_128K
+#define BL31_LIMIT (BL31_BASE + BL31_SIZE)
+
+/* non-secure uboot base */
+#define PLAT_NS_IMAGE_OFFSET U(0x40200000)
+#define PLAT_NS_IMAGE_SIZE U(0x00200000)
+
+#define BL32_FDT_OVERLAY_ADDR (PLAT_NS_IMAGE_OFFSET + 0x3000000)
+
+/* 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_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(0x3000000)
+#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_DDR_IPS_SIZE U(0x1800000)
+#define IMX_VPUMIX_BASE U(0x38330000)
+#define IMX_VPUMIX_SIZE U(0x100000)
+#define IMX_ROM_BASE U(0x0)
+#define IMX_ROM_SIZE U(0x40000)
+#define IMX_NS_OCRAM_BASE U(0x900000)
+#define IMX_NS_OCRAM_SIZE U(0x20000)
+#define IMX_CAAM_RAM_BASE U(0x100000)
+#define IMX_CAAM_RAM_SIZE U(0x10000)
+#define IMX_DRAM_BASE U(0x40000000)
+#define IMX_DRAM_SIZE U(0xc0000000)
+
+#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 SRC_GPR10_OFFSET U(0x98)
+#define SRC_GPR10_PERSIST_SECONDARY_BOOT BIT(30)
+
+#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 DRAM_PLL_CTRL (IMX_ANAMIX_BASE + 0x50)
+
+#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 SAVED_DRAM_TIMING_BASE OCRAM_S_BASE
+
+#define COUNTER_FREQUENCY 8000000 /* 8MHz */
+
+#define IMX_WDOG_B_RESET
+
+#define MAX_IO_HANDLES 3U
+#define MAX_IO_DEVICES 2U
+#define MAX_IO_BLOCK_DEVICES 1U
+
+#define PLAT_IMX8M_DTO_BASE 0x53000000
+#define PLAT_IMX8M_DTO_MAX_SIZE 0x1000
+#define PLAT_IMX_EVENT_LOG_MAX_SIZE UL(0x400)
diff --git a/plat/imx/imx8m/imx8mm/platform.mk b/plat/imx/imx8m/imx8mm/platform.mk
new file mode 100644
index 0000000..7a42554
--- /dev/null
+++ b/plat/imx/imx8m/imx8mm/platform.mk
@@ -0,0 +1,185 @@
+#
+# Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+# Translation tables library
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_INCLUDES := -Iplat/imx/common/include \
+ -Iplat/imx/imx8m/include \
+ -Iplat/imx/imx8m/imx8mm/include \
+ -Idrivers/imx/usdhc \
+ -Iinclude/common/tbbr \
+ -Iinclude/lib/libfdt
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+include lib/libfdt/libfdt.mk
+
+IMX_DRAM_SOURCES := plat/imx/imx8m/ddr/dram.c \
+ plat/imx/imx8m/ddr/clock.c \
+ plat/imx/imx8m/ddr/dram_retention.c \
+ plat/imx/imx8m/ddr/ddr4_dvfs.c \
+ plat/imx/imx8m/ddr/lpddr4_dvfs.c
+
+IMX_GIC_SOURCES := ${GICV3_SOURCES} \
+ 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_hab.c \
+ plat/imx/imx8m/imx_aipstz.c \
+ plat/imx/imx8m/imx_rdc.c \
+ plat/imx/imx8m/imx8m_csu.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/cpus/aarch64/cortex_a53.S \
+ drivers/arm/tzc/tzc380.c \
+ drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ ${XLAT_TABLES_LIB_SRCS} \
+ ${IMX_DRAM_SOURCES} \
+ ${IMX_GIC_SOURCES}
+
+ifeq (${NEED_BL2},yes)
+BL2_SOURCES += common/desc_image_load.c \
+ common/fdt_wrappers.c \
+ plat/imx/common/imx8_helpers.S \
+ plat/imx/common/imx_uart_console.S \
+ plat/imx/imx8m/imx8mm/imx8mm_bl2_el3_setup.c \
+ plat/imx/imx8m/imx8mm/gpc.c \
+ plat/imx/imx8m/imx_aipstz.c \
+ plat/common/plat_psci_common.c \
+ lib/xlat_tables/aarch64/xlat_tables.c \
+ lib/xlat_tables/xlat_tables_common.c \
+ lib/cpus/aarch64/cortex_a53.S \
+ drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ ${PLAT_GIC_SOURCES} \
+ ${PLAT_DRAM_SOURCES} \
+ 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/usdhc/imx_usdhc.c \
+ plat/imx/imx8m/imx8mm/imx8mm_bl2_mem_params_desc.c \
+ plat/imx/common/imx_io_storage.c \
+ plat/imx/imx8m/imx8m_image_load.c \
+ lib/optee/optee_utils.c
+endif
+
+# Add the build options to pack BLx images and kernel device tree
+# in the FIP if the platform requires.
+ifneq ($(BL2),)
+RESET_TO_BL31 := 0
+$(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
+
+ifeq (${NEED_BL2},yes)
+$(eval $(call add_define,NEED_BL2))
+LOAD_IMAGE_V2 := 1
+# Non-TF Boot ROM
+BL2_AT_EL3 := 1
+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_common.c \
+ drivers/auth/tbbr/tbbr_cot_bl2.c
+
+BL2_SOURCES += ${AUTH_SOURCES} \
+ plat/common/tbbr/plat_tbbr.c \
+ plat/imx/imx8m/imx8mm/imx8mm_trusted_boot.c \
+ plat/imx/imx8m/imx8mm/imx8mm_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/imx8mm_rotpk.o: $(ROTPK_HASH)
+
+certificates: $(ROT_KEY)
+
+$(ROT_KEY): | $(BUILD_PLAT)
+ @echo " OPENSSL $@"
+ @if [ ! -f $(ROT_KEY) ]; then \
+ ${OPENSSL_BIN_PATH}/openssl genrsa 2048 > $@ 2>/dev/null; \
+ fi
+
+$(ROTPK_HASH): $(ROT_KEY)
+ @echo " OPENSSL $@"
+ $(Q)${OPENSSL_BIN_PATH}/openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+ ${OPENSSL_BIN_PATH}/openssl dgst -sha256 -binary > $@ 2>/dev/null
+endif
+
+ENABLE_PIE := 1
+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
+
+BL32_BASE ?= 0xbe000000
+$(eval $(call add_define,BL32_BASE))
+
+BL32_SIZE ?= 0x2000000
+$(eval $(call add_define,BL32_SIZE))
+
+IMX_BOOT_UART_BASE ?= 0x30890000
+$(eval $(call add_define,IMX_BOOT_UART_BASE))
+
+EL3_EXCEPTION_HANDLING := $(SDEI_SUPPORT)
+ifeq (${SDEI_SUPPORT}, 1)
+BL31_SOURCES += plat/imx/common/imx_ehf.c \
+ plat/imx/common/imx_sdei.c
+endif
+
+ifeq (${MEASURED_BOOT},1)
+ MEASURED_BOOT_MK := drivers/measured_boot/event_log/event_log.mk
+ $(info Including ${MEASURED_BOOT_MK})
+ include ${MEASURED_BOOT_MK}
+
+ifneq (${MBOOT_EL_HASH_ALG}, sha256)
+ $(eval $(call add_define,TF_MBEDTLS_MBOOT_USE_SHA512))
+endif
+
+BL2_SOURCES += plat/imx/imx8m/imx8m_measured_boot.c \
+ plat/imx/imx8m/imx8m_dyn_cfg_helpers.c \
+ ${EVENT_LOG_SOURCES}
+endif
+
+ifeq (${SPD},trusty)
+ BL31_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC=1
+endif
diff --git a/plat/imx/imx8m/imx8mn/gpc.c b/plat/imx/imx8m/imx8mn/gpc.c
new file mode 100644
index 0000000..4e05297
--- /dev/null
+++ b/plat/imx/imx8m/imx8mn/gpc.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2019-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <lib/smccc.h>
+#include <services/std_svc.h>
+
+#include <gpc.h>
+#include <imx_sip_svc.h>
+#include <platform_def.h>
+
+#define CCGR(x) (0x4000 + (x) * 0x10)
+
+#define MIPI_PWR_REQ BIT(0)
+#define OTG1_PWR_REQ BIT(2)
+#define HSIOMIX_PWR_REQ BIT(4)
+#define GPUMIX_PWR_REQ BIT(7)
+#define DISPMIX_PWR_REQ BIT(10)
+
+#define HSIOMIX_ADB400_SYNC BIT(5)
+#define DISPMIX_ADB400_SYNC BIT(7)
+#define GPUMIX_ADB400_SYNC (0x5 << 9)
+#define HSIOMIX_ADB400_ACK BIT(23)
+#define DISPMIX_ADB400_ACK BIT(25)
+#define GPUMIX_ADB400_ACK (0x5 << 27)
+
+#define MIPI_PGC 0xc00
+#define OTG1_PGC 0xc80
+#define HSIOMIX_PGC 0xd00
+#define GPUMIX_PGC 0xdc0
+#define DISPMIX_PGC 0xe80
+
+enum pu_domain_id {
+ HSIOMIX,
+ OTG1 = 2,
+ GPUMIX = 4,
+ DISPMIX = 9,
+ MIPI,
+};
+
+/* PU domain, add some hole to minimize the uboot change */
+static struct imx_pwr_domain pu_domains[11] = {
+ [HSIOMIX] = IMX_MIX_DOMAIN(HSIOMIX, false),
+ [OTG1] = IMX_PD_DOMAIN(OTG1, true),
+ [GPUMIX] = IMX_MIX_DOMAIN(GPUMIX, false),
+ [DISPMIX] = IMX_MIX_DOMAIN(DISPMIX, false),
+ [MIPI] = IMX_PD_DOMAIN(MIPI, true),
+};
+
+static unsigned int pu_domain_status;
+
+void imx_gpc_pm_domain_enable(uint32_t domain_id, bool on)
+{
+ if (domain_id > MIPI) {
+ return;
+ }
+
+ struct imx_pwr_domain *pwr_domain = &pu_domains[domain_id];
+
+ if (on) {
+ if (pwr_domain->need_sync) {
+ pu_domain_status |= (1 << domain_id);
+ }
+
+ /* HSIOMIX has no PU bit, so skip for it */
+ if (domain_id != HSIOMIX) {
+ /* clear the PGC bit */
+ mmio_clrbits_32(IMX_GPC_BASE + pwr_domain->pgc_offset, 0x1);
+
+ /* power up the domain */
+ mmio_setbits_32(IMX_GPC_BASE + PU_PGC_UP_TRG, pwr_domain->pwr_req);
+
+ /* wait for power request done */
+ while (mmio_read_32(IMX_GPC_BASE + PU_PGC_UP_TRG) & pwr_domain->pwr_req) {
+ ;
+ }
+ }
+
+ if (domain_id == DISPMIX) {
+ /* de-reset bus_blk clk and
+ * enable bus_blk clk
+ */
+ mmio_write_32(0x32e28000, 0x100);
+ mmio_write_32(0x32e28004, 0x100);
+ }
+
+ /* handle the ADB400 sync */
+ if (pwr_domain->need_sync) {
+ /* clear adb power down request */
+ mmio_setbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, pwr_domain->adb400_sync);
+
+ /* wait for adb power request ack */
+ while (!(mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & pwr_domain->adb400_ack)) {
+ ;
+ }
+ }
+ } else {
+ pu_domain_status &= ~(1 << domain_id);
+
+ if (domain_id == OTG1) {
+ return;
+ }
+
+ /* handle the ADB400 sync */
+ if (pwr_domain->need_sync) {
+
+ /* set adb power down request */
+ mmio_clrbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, pwr_domain->adb400_sync);
+
+ /* wait for adb power request ack */
+ while ((mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & pwr_domain->adb400_ack)) {
+ ;
+ }
+ }
+
+ /* HSIOMIX has no PU bit, so skip for it */
+ if (domain_id != HSIOMIX) {
+ /* set the PGC bit */
+ mmio_setbits_32(IMX_GPC_BASE + pwr_domain->pgc_offset, 0x1);
+
+ /* power down the domain */
+ mmio_setbits_32(IMX_GPC_BASE + PU_PGC_DN_TRG, pwr_domain->pwr_req);
+
+ /* wait for power request done */
+ while (mmio_read_32(IMX_GPC_BASE + PU_PGC_DN_TRG) & pwr_domain->pwr_req) {
+ ;
+ }
+ }
+ }
+}
+
+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 |= CORE_WKUP_FROM_GIC;
+ /* clear the MASTER0 LPM handshake */
+ val &= ~MASTER0_LPM_HSK;
+ 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, 0x401);
+ mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(1) + 0x4, 0x401);
+ mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(2) + 0x4, 0x401);
+ mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(3) + 0x4, 0x401);
+ mmio_write_32(IMX_GPC_BASE + PLAT_PGC_PCR + 0x4, 0x401);
+ mmio_write_32(IMX_GPC_BASE + PGC_SCU_TIMING,
+ (0x59 << TMC_TMR_SHIFT) | 0x5B | (0x2 << TRC1_TMC_SHIFT));
+
+ /* 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);
+}
diff --git a/plat/imx/imx8m/imx8mn/imx8mn_bl31_setup.c b/plat/imx/imx8m/imx8mn/imx8mn_bl31_setup.c
new file mode 100644
index 0000000..eff198d
--- /dev/null
+++ b/plat/imx/imx8m/imx8mn/imx8mn_bl31_setup.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2019-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <drivers/arm/tzc380.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include <dram.h>
+#include <gpc.h>
+#include <imx_aipstz.h>
+#include <imx_uart.h>
+#include <imx_rdc.h>
+#include <imx8m_caam.h>
+#include <imx8m_csu.h>
+#include <platform_def.h>
+#include <plat_imx8.h>
+
+#define TRUSTY_PARAMS_LEN_BYTES (4096*2)
+
+static const mmap_region_t imx_mmap[] = {
+ GIC_MAP, AIPS_MAP, OCRAM_S_MAP, DDRC_MAP,
+ CAAM_RAM_MAP, NS_OCRAM_MAP, ROM_MAP, DRAM_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(RDC_MDA_M7, DID1),
+
+ /* peripherals domain permission */
+ RDC_PDAPn(RDC_PDAP_UART4, D1R | D1W),
+ RDC_PDAPn(RDC_PDAP_UART2, D0R | D0W),
+
+ /* memory region */
+ RDC_MEM_REGIONn(16, 0x0, 0x0, 0xff),
+ RDC_MEM_REGIONn(17, 0x0, 0x0, 0xff),
+ RDC_MEM_REGIONn(18, 0x0, 0x0, 0xff),
+
+ /* Sentinel */
+ {0},
+};
+
+static const struct imx_csu_cfg csu_cfg[] = {
+ /* peripherals csl setting */
+ CSU_CSLx(CSU_CSL_OCRAM, CSU_SEC_LEVEL_2, UNLOCKED),
+ CSU_CSLx(CSU_CSL_OCRAM_S, CSU_SEC_LEVEL_2, UNLOCKED),
+
+ /* master HP0~1 */
+
+ /* SA setting */
+
+ /* HP control setting */
+
+ /* 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;
+}
+
+static 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.mx8mn.
+ */
+
+ /* 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_t console;
+ unsigned int val;
+ 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);
+
+ imx_csu_init(csu_cfg);
+
+ /* config the ocram memory range for secure access */
+ mmio_write_32(IMX_IOMUX_GPR_BASE + 0x2c, 0x4c1);
+ val = mmio_read_32(IMX_IOMUX_GPR_BASE + 0x2c);
+ mmio_write_32(IMX_IOMUX_GPR_BASE + 0x2c, val | 0x3DFF0000);
+
+ 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_FLAG_BOOT);
+
+ imx8m_caam_init();
+
+ /*
+ * 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);
+
+#if defined(SPD_opteed) || defined(SPD_trusty)
+ /* 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 = 0;
+
+ /* Pass TEE base and size to bl33 */
+ bl33_image_ep_info.args.arg1 = BL32_BASE;
+ bl33_image_ep_info.args.arg2 = BL32_SIZE;
+
+#ifdef SPD_trusty
+ bl32_image_ep_info.args.arg0 = BL32_SIZE;
+ bl32_image_ep_info.args.arg1 = BL32_BASE;
+#else
+ /* Make sure memory is clean */
+ mmio_write_32(BL32_FDT_OVERLAY_ADDR, 0);
+ bl33_image_ep_info.args.arg3 = BL32_FDT_OVERLAY_ADDR;
+ bl32_image_ep_info.args.arg3 = BL32_FDT_OVERLAY_ADDR;
+#endif
+#endif
+
+ bl31_tzc380_setup();
+}
+
+#define MAP_BL31_TOTAL \
+ MAP_REGION_FLAT(BL31_START, BL31_SIZE, MT_MEMORY | MT_RW | MT_SECURE)
+#define MAP_BL31_RO \
+ MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, MT_MEMORY | MT_RO | MT_SECURE)
+#define MAP_COHERENT_MEM \
+ MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+#define MAP_BL32_TOTAL \
+ MAP_REGION_FLAT(BL32_BASE, BL32_SIZE, MT_MEMORY | MT_RW)
+
+void bl31_plat_arch_setup(void)
+{
+ const mmap_region_t bl_regions[] = {
+ MAP_BL31_TOTAL,
+ MAP_BL31_RO,
+#if USE_COHERENT_MEM
+ MAP_COHERENT_MEM,
+#endif
+ /* Map TEE memory */
+ MAP_BL32_TOTAL,
+ {0}
+ };
+
+ setup_page_tables(bl_regions, imx_mmap);
+ 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);
+
+ /* Init the dram info */
+ dram_info_init(SAVED_DRAM_TIMING_BASE);
+
+ 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;
+}
+
+#ifdef SPD_trusty
+void plat_trusty_set_boot_args(aapcs64_params_t *args)
+{
+ args->arg0 = BL32_SIZE;
+ args->arg1 = BL32_BASE;
+ args->arg2 = TRUSTY_PARAMS_LEN_BYTES;
+}
+#endif
diff --git a/plat/imx/imx8m/imx8mn/imx8mn_psci.c b/plat/imx/imx8m/imx8mn/imx8mn_psci.c
new file mode 100644
index 0000000..f541fc1
--- /dev/null
+++ b/plat/imx/imx8m/imx8mn/imx8mn_psci.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <gpc.h>
+#include <imx8m_psci.h>
+#include <plat_imx8.h>
+
+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;
+}
diff --git a/plat/imx/imx8m/imx8mn/include/gpc_reg.h b/plat/imx/imx8m/imx8mn/include/gpc_reg.h
new file mode 100644
index 0000000..8a81368
--- /dev/null
+++ b/plat/imx/imx8m/imx8mn/include/gpc_reg.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GPC_REG_H
+#define GPC_REG_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 LPS_CPU1 0x114
+#define A53_CORE0_PGC 0x800
+#define A53_PLAT_PGC 0x900
+#define PLAT_PGC_PCR 0x900
+#define NOC_PGC_PCR 0xa40
+#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 MASTER1_LPM_HSK BIT(7)
+#define MASTER2_LPM_HSK BIT(8)
+
+#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 NOC_PDN_SLT_CTRL BIT(10)
+#define NOC_PUP_SLT_CTRL BIT(11)
+#define NOC_PGC_PDN_ACK BIT(3)
+#define NOC_PGC_PUP_ACK BIT(19)
+
+#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)
+
+#define TMR_TCD2_SHIFT 0
+#define TMC_TMR_SHIFT 10
+#define TRC1_TMC_SHIFT 20
+
+#define MIPI_PWR_REQ BIT(0)
+#define OTG1_PWR_REQ BIT(2)
+#define HSIOMIX_PWR_REQ BIT(4)
+#define DDRMIX_PWR_REQ BIT(5)
+#define GPUMIX_PWR_REQ BIT(7)
+#define DISPMIX_PWR_REQ BIT(10)
+
+#define DDRMIX_ADB400_SYNC BIT(2)
+#define HSIOMIX_ADB400_SYNC BIT(5)
+#define DISPMIX_ADB400_SYNC BIT(7)
+#define GPUMIX_ADB400_SYNC (0x5 << 9)
+#define DDRMIX_ADB400_ACK BIT(20)
+#define HSIOMIX_ADB400_ACK BIT(23)
+#define DISPMIX_ADB400_ACK BIT(25)
+#define GPUMIX_ADB400_ACK (0x5 << 27)
+
+#define MIPI_PGC 0xc00
+#define OTG1_PGC 0xc80
+#define HSIOMIX_PGC 0xd00
+#define DDRMIX_PGC 0xd40
+#define GPUMIX_PGC 0xdc0
+#define DISPMIX_PGC 0xe80
+
+#define IRQ_IMR_NUM U(4)
+
+#endif /* GPC_REG_H */
diff --git a/plat/imx/imx8m/imx8mn/include/imx_sec_def.h b/plat/imx/imx8m/imx8mn/include/imx_sec_def.h
new file mode 100644
index 0000000..0ef14a9
--- /dev/null
+++ b/plat/imx/imx8m/imx8mn/include/imx_sec_def.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2020-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_SEC_DEF_H
+#define IMX_SEC_DEF_H
+
+/* RDC MDA index */
+enum rdc_mda_idx {
+ RDC_MDA_A53 = 0,
+ RDC_MDA_M7 = 1,
+ RDC_MDA_SDMA3p = 3,
+ RDC_MDA_LCDIF = 5,
+ RDC_MDA_ISI = 6,
+ RDC_MDA_SDMA3b = 7,
+ RDC_MDA_Coresight = 8,
+ RDC_MDA_DAP = 9,
+ RDC_MDA_CAAM = 10,
+ RDC_MDA_SDMA1p = 11,
+ RDC_MDA_SDMA1b = 12,
+ RDC_MDA_APBHDMA = 13,
+ RDC_MDA_RAWNAND = 14,
+ RDC_MDA_uSDHC1 = 15,
+ RDC_MDA_uSDHC2 = 16,
+ RDC_MDA_uSDHC3 = 17,
+ RDC_MDA_GPU = 18,
+ RDC_MDA_USB1 = 19,
+ RDC_MDA_TESTPORT = 21,
+ RDC_MDA_ENET1_TX = 22,
+ RDC_MDA_ENET1_RX = 23,
+ RDC_MDA_SDMA2 = 24,
+};
+
+/* RDC Peripherals index */
+enum rdc_pdap_idx {
+ RDC_PDAP_GPIO1 = 0,
+ RDC_PDAP_GPIO2 = 1,
+ RDC_PDAP_GPIO3 = 2,
+ RDC_PDAP_GPIO4 = 3,
+ RDC_PDAP_GPIO5 = 4,
+ RDC_PDAP_ANA_TSENSOR = 6,
+ RDC_PDAP_ANA_OSC = 7,
+ RDC_PDAP_WDOG1 = 8,
+ RDC_PDAP_WDOG2 = 9,
+ RDC_PDAP_WDOG3 = 10,
+ RDC_PDAP_SDMA3 = 11,
+ RDC_PDAP_SDMA2 = 12,
+ RDC_PDAP_GPT1 = 13,
+ RDC_PDAP_GPT2 = 14,
+ RDC_PDAP_GPT3 = 15,
+ RDC_PDAP_ROMCP = 17,
+ RDC_PDAP_IOMUXC = 19,
+ RDC_PDAP_IOMUXC_GPR = 20,
+ RDC_PDAP_OCOTP_CTRL = 21,
+ RDC_PDAP_ANA_PLL = 22,
+ RDC_PDAP_SNVS_HP = 23,
+ RDC_PDAP_CCM = 24,
+ RDC_PDAP_SRC = 25,
+ RDC_PDAP_GPC = 26,
+ RDC_PDAP_SEMAPHORE1 = 27,
+ RDC_PDAP_SEMAPHORE2 = 28,
+ RDC_PDAP_RDC = 29,
+ RDC_PDAP_CSU = 30,
+ RDC_PDAP_LCDIF = 32,
+ RDC_PDAP_MIPI_DSI = 33,
+ RDC_PDAP_ISI = 34,
+ RDC_PDAP_MIPI_CSI = 35,
+ RDC_PDAP_USB1 = 36,
+ RDC_PDAP_PWM1 = 38,
+ RDC_PDAP_PWM2 = 39,
+ RDC_PDAP_PWM3 = 40,
+ RDC_PDAP_PWM4 = 41,
+ RDC_PDAP_System_Counter_RD = 42,
+ RDC_PDAP_System_Counter_CMP = 43,
+ RDC_PDAP_System_Counter_CTRL = 44,
+ RDC_PDAP_GPT6 = 46,
+ RDC_PDAP_GPT5 = 47,
+ RDC_PDAP_GPT4 = 48,
+ RDC_PDAP_TZASC = 56,
+ RDC_PDAP_PERFMON1 = 60,
+ RDC_PDAP_PERFMON2 = 61,
+ RDC_PDAP_PLATFORM_CTRL = 62,
+ RDC_PDAP_QoSC = 63,
+ RDC_PDAP_I2C1 = 66,
+ RDC_PDAP_I2C2 = 67,
+ RDC_PDAP_I2C3 = 68,
+ RDC_PDAP_I2C4 = 69,
+ RDC_PDAP_UART4 = 70,
+ RDC_PDAP_MU_A = 74,
+ RDC_PDAP_MU_B = 75,
+ RDC_PDAP_SEMAPHORE_HS = 76,
+ RDC_PDAP_SAI2 = 79,
+ RDC_PDAP_SAI3 = 80,
+ RDC_PDAP_SAI5 = 82,
+ RDC_PDAP_SAI6 = 83,
+ RDC_PDAP_uSDHC1 = 84,
+ RDC_PDAP_uSDHC2 = 85,
+ RDC_PDAP_uSDHC3 = 86,
+ RDC_PDAP_SAI7 = 87,
+ RDC_PDAP_SPBA2 = 90,
+ RDC_PDAP_QSPI = 91,
+ RDC_PDAP_SDMA1 = 93,
+ RDC_PDAP_ENET1 = 94,
+ RDC_PDAP_SPDIF1 = 97,
+ RDC_PDAP_eCSPI1 = 98,
+ RDC_PDAP_eCSPI2 = 99,
+ RDC_PDAP_eCSPI3 = 100,
+ RDC_PDAP_MICFIL = 101,
+ RDC_PDAP_UART1 = 102,
+ RDC_PDAP_UART3 = 104,
+ RDC_PDAP_UART2 = 105,
+ RDC_PDAP_ASRC = 107,
+ RDC_PDAP_SPBA1 = 111,
+ RDC_PDAP_CAAM = 114,
+};
+
+enum csu_csl_idx {
+ CSU_CSL_GPIO1 = 0,
+ CSU_CSL_GPIO2 = 1,
+ CSU_CSL_GPIO3 = 2,
+ CSU_CSL_GPIO4 = 3,
+ CSU_CSL_GPIO5 = 4,
+ CSU_CSL_ANA_TSENSOR = 6,
+ CSU_CSL_ANA_OSC = 7,
+ CSU_CSL_WDOG1 = 8,
+ CSU_CSL_WDOG2 = 9,
+ CSU_CSL_WDOG3 = 10,
+ CSU_CSL_SDMA2 = 12,
+ CSU_CSL_GPT1 = 13,
+ CSU_CSL_GPT2 = 14,
+ CSU_CSL_GPT3 = 15,
+ CSU_CSL_ROMCP = 17,
+ CSU_CSL_LCDIF = 18,
+ CSU_CSL_IOMUXC = 19,
+ CSU_CSL_IOMUXC_GPR = 20,
+ CSU_CSL_OCOTP_CTRL = 21,
+ CSU_CSL_ANA_PLL = 22,
+ CSU_CSL_SNVS_HP = 23,
+ CSU_CSL_CCM = 24,
+ CSU_CSL_SRC = 25,
+ CSU_CSL_GPC = 26,
+ CSU_CSL_SEMAPHORE1 = 27,
+ CSU_CSL_SEMAPHORE2 = 28,
+ CSU_CSL_RDC = 29,
+ CSU_CSL_CSU = 30,
+ CSU_CSL_DC_MST0 = 32,
+ CSU_CSL_DC_MST1 = 33,
+ CSU_CSL_DC_MST2 = 34,
+ CSU_CSL_DC_MST3 = 35,
+ CSU_CSL_PWM1 = 38,
+ CSU_CSL_PWM2 = 39,
+ CSU_CSL_PWM3 = 40,
+ CSU_CSL_PWM4 = 41,
+ CSU_CSL_System_Counter_RD = 42,
+ CSU_CSL_System_Counter_CMP = 43,
+ CSU_CSL_System_Counter_CTRL = 44,
+ CSU_CSL_GPT6 = 46,
+ CSU_CSL_GPT5 = 47,
+ CSU_CSL_GPT4 = 48,
+ CSU_CSL_TZASC = 56,
+ CSU_CSL_MTR = 59,
+ CSU_CSL_PERFMON1 = 60,
+ CSU_CSL_PERFMON2 = 61,
+ CSU_CSL_PLATFORM_CTRL = 62,
+ CSU_CSL_QoSC = 63,
+ CSU_CSL_MIPI_PHY = 64,
+ CSU_CSL_MIPI_DSI = 65,
+ CSU_CSL_I2C1 = 66,
+ CSU_CSL_I2C2 = 67,
+ CSU_CSL_I2C3 = 68,
+ CSU_CSL_I2C4 = 69,
+ CSU_CSL_UART4 = 70,
+ CSU_CSL_MIPI_CSI1 = 71,
+ CSU_CSL_MIPI_CSI_PHY1 = 72,
+ CSU_CSL_CSI1 = 73,
+ CSU_CSL_MU_A = 74,
+ CSU_CSL_MU_B = 75,
+ CSU_CSL_SEMAPHORE_HS = 76,
+ CSU_CSL_SAI1 = 78,
+ CSU_CSL_SAI6 = 80,
+ CSU_CSL_SAI5 = 81,
+ CSU_CSL_SAI4 = 82,
+ CSU_CSL_uSDHC1 = 84,
+ CSU_CSL_uSDHC2 = 85,
+ CSU_CSL_MIPI_CSI2 = 86,
+ CSU_CSL_MIPI_CSI_PHY2 = 87,
+ CSU_CSL_CSI2 = 88,
+ CSU_CSL_SPBA2 = 90,
+ CSU_CSL_QSPI = 91,
+ CSU_CSL_SDMA1 = 93,
+ CSU_CSL_ENET1 = 94,
+ CSU_CSL_SPDIF1 = 97,
+ CSU_CSL_eCSPI1 = 98,
+ CSU_CSL_eCSPI2 = 99,
+ CSU_CSL_eCSPI3 = 100,
+ CSU_CSL_UART1 = 102,
+ CSU_CSL_UART3 = 104,
+ CSU_CSL_UART2 = 105,
+ CSU_CSL_SPDIF2 = 106,
+ CSU_CSL_SAI2 = 107,
+ CSU_CSL_SAI3 = 108,
+ CSU_CSL_SPBA1 = 111,
+ CSU_CSL_CAAM = 114,
+ CSU_CSL_OCRAM = 118,
+ CSU_CSL_OCRAM_S = 119,
+};
+
+#endif /* IMX_SEC_DEF_H */
diff --git a/plat/imx/imx8m/imx8mn/include/platform_def.h b/plat/imx/imx8m/imx8mn/include/platform_def.h
new file mode 100644
index 0000000..c75e250
--- /dev/null
+++ b/plat/imx/imx8m/imx8mn/include/platform_def.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2020-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/common_def.h>
+
+#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 U(0x0)
+#define PLATFORM_MAX_CPU_PER_CLUSTER U(4)
+#define PLATFORM_CLUSTER_COUNT U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT U(4)
+#define PLATFORM_CLUSTER1_CORE_COUNT U(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 PLAT_PRI_BITS U(3)
+#define PLAT_SDEI_CRITICAL_PRI 0x10
+#define PLAT_SDEI_NORMAL_PRI 0x20
+#define PLAT_SDEI_SGI_PRIVATE U(9)
+
+#define BL31_BASE U(0x960000)
+#define BL31_SIZE SZ_128K
+#define BL31_LIMIT (BL31_BASE + BL31_SIZE)
+
+/* non-secure uboot base */
+#define PLAT_NS_IMAGE_OFFSET U(0x40200000)
+
+#define BL32_FDT_OVERLAY_ADDR (PLAT_NS_IMAGE_OFFSET + 0x3000000)
+
+/* GICv3 base address */
+#define PLAT_GICD_BASE U(0x38800000)
+#define PLAT_GICR_BASE U(0x38880000)
+
+#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 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_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(0x3000000)
+#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_DDR_IPS_SIZE U(0x1800000)
+#define IMX_ROM_BASE U(0x0)
+#define IMX_ROM_SIZE U(0x40000)
+#define IMX_NS_OCRAM_BASE U(0x900000)
+#define IMX_NS_OCRAM_SIZE U(0x60000)
+#define IMX_CAAM_RAM_BASE U(0x100000)
+#define IMX_CAAM_RAM_SIZE U(0x10000)
+#define IMX_DRAM_BASE U(0x40000000)
+#define IMX_DRAM_SIZE U(0xc0000000)
+
+#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_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 DRAM_PLL_CTRL (IMX_ANAMIX_BASE + 0x50)
+
+#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 SAVED_DRAM_TIMING_BASE OCRAM_S_BASE
+
+#define COUNTER_FREQUENCY 8000000 /* 8MHz */
+
+#define IMX_WDOG_B_RESET
+
+#define GIC_MAP MAP_REGION_FLAT(IMX_GIC_BASE, IMX_GIC_SIZE, MT_DEVICE | MT_RW)
+#define AIPS_MAP MAP_REGION_FLAT(IMX_AIPS_BASE, IMX_AIPS_SIZE, MT_DEVICE | MT_RW) /* AIPS map */
+#define OCRAM_S_MAP MAP_REGION_FLAT(OCRAM_S_BASE, OCRAM_S_SIZE, MT_DEVICE | MT_RW) /* OCRAM_S */
+#define DDRC_MAP MAP_REGION_FLAT(IMX_DDRPHY_BASE, IMX_DDR_IPS_SIZE, MT_DEVICE | MT_RW) /* DDRMIX */
+#define CAAM_RAM_MAP MAP_REGION_FLAT(IMX_CAAM_RAM_BASE, IMX_CAAM_RAM_SIZE, MT_MEMORY | MT_RW) /* CAMM RAM */
+#define NS_OCRAM_MAP MAP_REGION_FLAT(IMX_NS_OCRAM_BASE, IMX_NS_OCRAM_SIZE, MT_MEMORY | MT_RW) /* NS OCRAM */
+#define ROM_MAP MAP_REGION_FLAT(IMX_ROM_BASE, IMX_ROM_SIZE, MT_MEMORY | MT_RO) /* ROM code */
+
+/*
+ * Note: DRAM region is mapped with entire size available and uses MT_RW
+ * attributes.
+ * See details in docs/plat/imx8m.rst "High Assurance Boot (HABv4)" section
+ * for explanation of this mapping scheme.
+ */
+#define DRAM_MAP MAP_REGION_FLAT(IMX_DRAM_BASE, IMX_DRAM_SIZE, MT_MEMORY | MT_RW | MT_NS) /* DRAM */
+
+#endif /* platform_def.h */
diff --git a/plat/imx/imx8m/imx8mn/platform.mk b/plat/imx/imx8m/imx8mn/platform.mk
new file mode 100644
index 0000000..1c0ad4f
--- /dev/null
+++ b/plat/imx/imx8m/imx8mn/platform.mk
@@ -0,0 +1,77 @@
+#
+# Copyright 2019-2022 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT_INCLUDES := -Iplat/imx/common/include \
+ -Iplat/imx/imx8m/include \
+ -Iplat/imx/imx8m/imx8mn/include
+# Translation tables library
+include lib/xlat_tables_v2/xlat_tables.mk
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+IMX_DRAM_SOURCES := plat/imx/imx8m/ddr/dram.c \
+ plat/imx/imx8m/ddr/clock.c \
+ plat/imx/imx8m/ddr/dram_retention.c \
+ plat/imx/imx8m/ddr/ddr4_dvfs.c \
+ plat/imx/imx8m/ddr/lpddr4_dvfs.c
+
+
+IMX_GIC_SOURCES := ${GICV3_SOURCES} \
+ 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_hab.c \
+ plat/imx/imx8m/imx_aipstz.c \
+ plat/imx/imx8m/imx_rdc.c \
+ plat/imx/imx8m/imx8m_caam.c \
+ plat/imx/imx8m/imx8m_csu.c \
+ plat/imx/imx8m/imx8m_psci_common.c \
+ plat/imx/imx8m/imx8mn/imx8mn_bl31_setup.c \
+ plat/imx/imx8m/imx8mn/imx8mn_psci.c \
+ plat/imx/imx8m/imx8mn/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/cpus/aarch64/cortex_a53.S \
+ drivers/arm/tzc/tzc380.c \
+ drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ ${IMX_DRAM_SOURCES} \
+ ${IMX_GIC_SOURCES} \
+ ${XLAT_TABLES_LIB_SRCS}
+
+ENABLE_PIE := 1
+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
+
+BL32_BASE ?= 0xbe000000
+$(eval $(call add_define,BL32_BASE))
+
+BL32_SIZE ?= 0x2000000
+$(eval $(call add_define,BL32_SIZE))
+
+IMX_BOOT_UART_BASE ?= 0x30890000
+$(eval $(call add_define,IMX_BOOT_UART_BASE))
+
+EL3_EXCEPTION_HANDLING := $(SDEI_SUPPORT)
+ifeq (${SDEI_SUPPORT}, 1)
+BL31_SOURCES += plat/imx/common/imx_ehf.c \
+ plat/imx/common/imx_sdei.c
+endif
+
+ifeq (${SPD},trusty)
+ BL31_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC=1
+endif
diff --git a/plat/imx/imx8m/imx8mp/gpc.c b/plat/imx/imx8m/imx8mp/gpc.c
new file mode 100644
index 0000000..452e788
--- /dev/null
+++ b/plat/imx/imx8m/imx8mp/gpc.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright 2019-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <lib/smccc.h>
+#include <services/std_svc.h>
+
+#include <gpc.h>
+#include <imx_aipstz.h>
+#include <imx_sip_svc.h>
+#include <platform_def.h>
+
+#define CCGR(x) (0x4000 + (x) * 0x10)
+#define IMR_NUM U(5)
+
+struct imx_noc_setting {
+ uint32_t domain_id;
+ uint32_t start;
+ uint32_t end;
+ uint32_t prioriy;
+ uint32_t mode;
+ uint32_t socket_qos_en;
+};
+
+enum clk_type {
+ CCM_ROOT_SLICE,
+ CCM_CCGR,
+};
+
+struct clk_setting {
+ uint32_t offset;
+ uint32_t val;
+ enum clk_type type;
+};
+
+enum pu_domain_id {
+ /* hsio ss */
+ HSIOMIX,
+ PCIE_PHY,
+ USB1_PHY,
+ USB2_PHY,
+ MLMIX,
+ AUDIOMIX,
+ /* gpu ss */
+ GPUMIX,
+ GPU2D,
+ GPU3D,
+ /* vpu ss */
+ VPUMIX,
+ VPU_G1,
+ VPU_G2,
+ VPU_H1,
+ /* media ss */
+ MEDIAMIX,
+ MEDIAMIX_ISPDWP,
+ MIPI_PHY1,
+ MIPI_PHY2,
+ /* HDMI ss */
+ HDMIMIX,
+ HDMI_PHY,
+ DDRMIX,
+ MAX_DOMAINS,
+};
+
+/* PU domain, add some hole to minimize the uboot change */
+static struct imx_pwr_domain pu_domains[MAX_DOMAINS] = {
+ [MIPI_PHY1] = IMX_PD_DOMAIN(MIPI_PHY1, false),
+ [PCIE_PHY] = IMX_PD_DOMAIN(PCIE_PHY, false),
+ [USB1_PHY] = IMX_PD_DOMAIN(USB1_PHY, true),
+ [USB2_PHY] = IMX_PD_DOMAIN(USB2_PHY, true),
+ [MLMIX] = IMX_MIX_DOMAIN(MLMIX, false),
+ [AUDIOMIX] = IMX_MIX_DOMAIN(AUDIOMIX, false),
+ [GPU2D] = IMX_PD_DOMAIN(GPU2D, false),
+ [GPUMIX] = IMX_MIX_DOMAIN(GPUMIX, false),
+ [VPUMIX] = IMX_MIX_DOMAIN(VPUMIX, false),
+ [GPU3D] = IMX_PD_DOMAIN(GPU3D, false),
+ [MEDIAMIX] = IMX_MIX_DOMAIN(MEDIAMIX, false),
+ [VPU_G1] = IMX_PD_DOMAIN(VPU_G1, false),
+ [VPU_G2] = IMX_PD_DOMAIN(VPU_G2, false),
+ [VPU_H1] = IMX_PD_DOMAIN(VPU_H1, false),
+ [HDMIMIX] = IMX_MIX_DOMAIN(HDMIMIX, false),
+ [HDMI_PHY] = IMX_PD_DOMAIN(HDMI_PHY, false),
+ [MIPI_PHY2] = IMX_PD_DOMAIN(MIPI_PHY2, false),
+ [HSIOMIX] = IMX_MIX_DOMAIN(HSIOMIX, false),
+ [MEDIAMIX_ISPDWP] = IMX_PD_DOMAIN(MEDIAMIX_ISPDWP, false),
+};
+
+static struct imx_noc_setting noc_setting[] = {
+ {MLMIX, 0x180, 0x180, 0x80000303, 0x0, 0x0},
+ {AUDIOMIX, 0x200, 0x200, 0x80000303, 0x0, 0x0},
+ {AUDIOMIX, 0x280, 0x480, 0x80000404, 0x0, 0x0},
+ {GPUMIX, 0x500, 0x580, 0x80000303, 0x0, 0x0},
+ {HDMIMIX, 0x600, 0x680, 0x80000202, 0x0, 0x1},
+ {HDMIMIX, 0x700, 0x700, 0x80000505, 0x0, 0x0},
+ {HSIOMIX, 0x780, 0x900, 0x80000303, 0x0, 0x0},
+ {MEDIAMIX, 0x980, 0xb80, 0x80000202, 0x0, 0x1},
+ {MEDIAMIX_ISPDWP, 0xc00, 0xd00, 0x80000505, 0x0, 0x0},
+ {VPU_G1, 0xd80, 0xd80, 0x80000303, 0x0, 0x0},
+ {VPU_G2, 0xe00, 0xe00, 0x80000303, 0x0, 0x0},
+ {VPU_H1, 0xe80, 0xe80, 0x80000303, 0x0, 0x0}
+};
+
+static struct clk_setting hsiomix_clk[] = {
+ { 0x8380, 0x0, CCM_ROOT_SLICE },
+ { 0x44d0, 0x0, CCM_CCGR },
+ { 0x45c0, 0x0, CCM_CCGR },
+};
+
+static struct aipstz_cfg aipstz5[] = {
+ {IMX_AIPSTZ5, 0x77777777, 0x77777777, .opacr = {0x0, 0x0, 0x0, 0x0, 0x0}, },
+ {0},
+};
+
+static unsigned int pu_domain_status;
+
+static void imx_noc_qos(unsigned int domain_id)
+{
+ unsigned int i;
+ uint32_t hurry;
+
+ if (domain_id == HDMIMIX) {
+ mmio_write_32(IMX_HDMI_CTL_BASE + TX_CONTROL1, 0x22018);
+ mmio_write_32(IMX_HDMI_CTL_BASE + TX_CONTROL1, 0x22010);
+
+ /* set GPR to make lcdif read hurry level 0x7 */
+ hurry = mmio_read_32(IMX_HDMI_CTL_BASE + TX_CONTROL0);
+ hurry |= 0x00077000;
+ mmio_write_32(IMX_HDMI_CTL_BASE + TX_CONTROL0, hurry);
+ }
+
+ if (domain_id == MEDIAMIX) {
+ /* handle mediamix special */
+ mmio_write_32(IMX_MEDIAMIX_CTL_BASE + RSTn_CSR, 0x1FFFFFF);
+ mmio_write_32(IMX_MEDIAMIX_CTL_BASE + CLK_EN_CSR, 0x1FFFFFF);
+ mmio_write_32(IMX_MEDIAMIX_CTL_BASE + RST_DIV, 0x40030000);
+
+ /* set GPR to make lcdif read hurry level 0x7 */
+ hurry = mmio_read_32(IMX_MEDIAMIX_CTL_BASE + LCDIF_ARCACHE_CTRL);
+ hurry |= 0xfc00;
+ mmio_write_32(IMX_MEDIAMIX_CTL_BASE + LCDIF_ARCACHE_CTRL, hurry);
+ /* set GPR to make isi write hurry level 0x7 */
+ hurry = mmio_read_32(IMX_MEDIAMIX_CTL_BASE + ISI_CACHE_CTRL);
+ hurry |= 0x1ff00000;
+ mmio_write_32(IMX_MEDIAMIX_CTL_BASE + ISI_CACHE_CTRL, hurry);
+ }
+
+ /* set MIX NoC */
+ for (i = 0; i < ARRAY_SIZE(noc_setting); i++) {
+ if (noc_setting[i].domain_id == domain_id) {
+ udelay(50);
+ uint32_t offset = noc_setting[i].start;
+
+ while (offset <= noc_setting[i].end) {
+ mmio_write_32(IMX_NOC_BASE + offset + 0x8, noc_setting[i].prioriy);
+ mmio_write_32(IMX_NOC_BASE + offset + 0xc, noc_setting[i].mode);
+ mmio_write_32(IMX_NOC_BASE + offset + 0x18, noc_setting[i].socket_qos_en);
+ offset += 0x80;
+ }
+ }
+ }
+}
+
+void imx_gpc_pm_domain_enable(uint32_t domain_id, bool on)
+{
+ struct imx_pwr_domain *pwr_domain = &pu_domains[domain_id];
+ unsigned int i;
+
+ /* validate the domain id */
+ if (domain_id >= MAX_DOMAINS) {
+ return;
+ }
+
+ if (domain_id == HSIOMIX) {
+ for (i = 0; i < ARRAY_SIZE(hsiomix_clk); i++) {
+ hsiomix_clk[i].val = mmio_read_32(IMX_CCM_BASE + hsiomix_clk[i].offset);
+ mmio_setbits_32(IMX_CCM_BASE + hsiomix_clk[i].offset,
+ hsiomix_clk[i].type == CCM_ROOT_SLICE ? BIT(28) : 0x3);
+ }
+ }
+
+ if (on) {
+ if (pwr_domain->need_sync) {
+ pu_domain_status |= (1 << domain_id);
+ }
+
+ if (domain_id == HDMIMIX) {
+ /* assert the reset */
+ mmio_write_32(IMX_HDMI_CTL_BASE + RTX_RESET_CTL0, 0x0);
+ /* enable all th function clock */
+ mmio_write_32(IMX_HDMI_CTL_BASE + RTX_CLK_CTL0, 0xFFFFFFFF);
+ mmio_write_32(IMX_HDMI_CTL_BASE + RTX_CLK_CTL1, 0x7ffff87e);
+ }
+
+ /* clear the PGC bit */
+ mmio_clrbits_32(IMX_GPC_BASE + pwr_domain->pgc_offset, 0x1);
+
+ /* power up the domain */
+ mmio_setbits_32(IMX_GPC_BASE + PU_PGC_UP_TRG, pwr_domain->pwr_req);
+
+ /* wait for power request done */
+ while (mmio_read_32(IMX_GPC_BASE + PU_PGC_UP_TRG) & pwr_domain->pwr_req)
+ ;
+
+ if (domain_id == HDMIMIX) {
+ /* wait for memory repair done for HDMIMIX */
+ while (!(mmio_read_32(IMX_SRC_BASE + 0x94) & BIT(8)))
+ ;
+ /* disable all the function clock */
+ mmio_write_32(IMX_HDMI_CTL_BASE + RTX_CLK_CTL0, 0x0);
+ mmio_write_32(IMX_HDMI_CTL_BASE + RTX_CLK_CTL1, 0x0);
+ /* deassert the reset */
+ mmio_write_32(IMX_HDMI_CTL_BASE + RTX_RESET_CTL0, 0xffffffff);
+ /* enable all the clock again */
+ mmio_write_32(IMX_HDMI_CTL_BASE + RTX_CLK_CTL0, 0xFFFFFFFF);
+ mmio_write_32(IMX_HDMI_CTL_BASE + RTX_CLK_CTL1, 0x7ffff87e);
+ }
+
+ if (domain_id == HSIOMIX) {
+ /* enable HSIOMIX clock */
+ mmio_write_32(IMX_HSIOMIX_CTL_BASE, 0x2);
+ }
+
+ /* handle the ADB400 sync */
+ if (pwr_domain->need_sync) {
+ /* clear adb power down request */
+ mmio_setbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, pwr_domain->adb400_sync);
+
+ /* wait for adb power request ack */
+ while (!(mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & pwr_domain->adb400_ack))
+ ;
+ }
+
+ imx_noc_qos(domain_id);
+
+ /* AIPS5 config is lost when audiomix is off, so need to re-init it */
+ if (domain_id == AUDIOMIX) {
+ imx_aipstz_init(aipstz5);
+ }
+ } else {
+ if (pwr_domain->always_on) {
+ return;
+ }
+
+ if (pwr_domain->need_sync) {
+ pu_domain_status &= ~(1 << domain_id);
+ }
+
+ /* handle the ADB400 sync */
+ if (pwr_domain->need_sync) {
+ /* set adb power down request */
+ mmio_clrbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, pwr_domain->adb400_sync);
+
+ /* wait for adb power request ack */
+ while ((mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & pwr_domain->adb400_ack))
+ ;
+ }
+
+ /* set the PGC bit */
+ mmio_setbits_32(IMX_GPC_BASE + pwr_domain->pgc_offset, 0x1);
+
+ /*
+ * leave the G1, G2, H1 power domain on until VPUMIX power off,
+ * otherwise system will hang due to VPUMIX ACK
+ */
+ if (domain_id == VPU_H1 || domain_id == VPU_G1 || domain_id == VPU_G2) {
+ return;
+ }
+
+ if (domain_id == VPUMIX) {
+ mmio_write_32(IMX_GPC_BASE + PU_PGC_DN_TRG, VPU_G1_PWR_REQ |
+ VPU_G2_PWR_REQ | VPU_H1_PWR_REQ);
+
+ while (mmio_read_32(IMX_GPC_BASE + PU_PGC_DN_TRG) & (VPU_G1_PWR_REQ |
+ VPU_G2_PWR_REQ | VPU_H1_PWR_REQ))
+ ;
+ }
+
+ /* power down the domain */
+ mmio_setbits_32(IMX_GPC_BASE + PU_PGC_DN_TRG, pwr_domain->pwr_req);
+
+ /* wait for power request done */
+ while (mmio_read_32(IMX_GPC_BASE + PU_PGC_DN_TRG) & pwr_domain->pwr_req)
+ ;
+
+ if (domain_id == HDMIMIX) {
+ /* disable all the clocks of HDMIMIX */
+ mmio_write_32(IMX_HDMI_CTL_BASE + 0x40, 0x0);
+ mmio_write_32(IMX_HDMI_CTL_BASE + 0x50, 0x0);
+ }
+ }
+
+ if (domain_id == HSIOMIX) {
+ for (i = 0; i < ARRAY_SIZE(hsiomix_clk); i++) {
+ mmio_write_32(IMX_CCM_BASE + hsiomix_clk[i].offset, hsiomix_clk[i].val);
+ }
+ }
+}
+
+void imx_gpc_init(void)
+{
+ uint32_t val;
+ unsigned int i;
+
+ /* mask all the wakeup irq by default */
+ for (i = 0; i < IMR_NUM; 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 |= CORE_WKUP_FROM_GIC;
+ /* clear the MASTER0 LPM handshake */
+ val &= ~MASTER0_LPM_HSK;
+ 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, 0x3fffff);
+
+ /*
+ * 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, 0x401);
+ mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(1) + 0x4, 0x401);
+ mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(2) + 0x4, 0x401);
+ mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(3) + 0x4, 0x401);
+ mmio_write_32(IMX_GPC_BASE + PLAT_PGC_PCR + 0x4, 0x401);
+ mmio_write_32(IMX_GPC_BASE + PGC_SCU_TIMING,
+ (0x59 << TMC_TMR_SHIFT) | 0x5B | (0x2 << TRC1_TMC_SHIFT));
+
+ /* 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/stop mode */
+ val |= SLPCR_A53_FASTWUP_WAIT_MODE;
+ val |= SLPCR_A53_FASTWUP_STOP_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 */
+ for (i = 0; i < 101; i++) {
+ mmio_write_32(IMX_CCM_BASE + CCGR(i), 0x3);
+ }
+
+ for (i = 0; i < 20; i++) {
+ imx_gpc_pm_domain_enable(i, true);
+ }
+}
diff --git a/plat/imx/imx8m/imx8mp/imx8mp_bl2_el3_setup.c b/plat/imx/imx8m/imx8mp/imx8mp_bl2_el3_setup.c
new file mode 100644
index 0000000..08cbeeb
--- /dev/null
+++ b/plat/imx/imx8m/imx8mp/imx8mp_bl2_el3_setup.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <context.h>
+#include <drivers/arm/tzc380.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/mmc.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <lib/optee_utils.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <imx8m_caam.h>
+#include "imx8mp_private.h"
+#include <imx_aipstz.h>
+#include <imx_rdc.h>
+#include <imx_uart.h>
+#include <plat/common/platform.h>
+#include <plat_imx8.h>
+#include <platform_def.h>
+
+
+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},
+};
+
+void bl2_el3_early_platform_setup(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3)
+{
+ static console_t console;
+ unsigned int i;
+
+ /* Enable CSU NS access permission */
+ for (i = 0U; i < 64; i++) {
+ mmio_write_32(IMX_CSU_BASE + i * 4, 0x00ff00ff);
+ }
+
+ imx_aipstz_init(aipstz);
+
+ console_imx_uart_register(IMX_BOOT_UART_BASE, IMX_BOOT_UART_CLK_IN_HZ,
+ IMX_CONSOLE_BAUDRATE, &console);
+
+ generic_delay_timer_init();
+
+ /* select the CKIL source to 32K OSC */
+ mmio_write_32(IMX_ANAMIX_BASE + ANAMIX_MISC_CTL, 0x1);
+
+ /* Open handles to a FIP image */
+ plat_imx_io_setup();
+}
+
+void bl2_el3_plat_arch_setup(void)
+{
+}
+
+void bl2_platform_setup(void)
+{
+}
+
+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 *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");
+ }
+
+ break;
+ default:
+ /* Do nothing in default case */
+ break;
+ }
+
+ return err;
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+ return COUNTER_FREQUENCY;
+}
+
+void bl2_plat_runtime_setup(void)
+{
+ return;
+}
diff --git a/plat/imx/imx8m/imx8mp/imx8mp_bl2_mem_params_desc.c b/plat/imx/imx8m/imx8mp/imx8mp_bl2_mem_params_desc.c
new file mode 100644
index 0000000..f2f6808
--- /dev/null
+++ b/plat/imx/imx8m/imx8mp/imx8mp_bl2_mem_params_desc.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+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.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 = INVALID_IMAGE_ID,
+ },
+ {
+ .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_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 = BL32_BASE,
+ .image_info.image_max_size = BL32_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 = PLAT_NS_IMAGE_OFFSET,
+
+ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+ VERSION_2, image_info_t,
+ IMAGE_ATTRIB_SKIP_LOADING),
+ # else
+ .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 = PLAT_NS_IMAGE_SIZE,
+ # endif /* PRELOADED_BL33_BASE */
+
+ .next_handoff_image_id = INVALID_IMAGE_ID,
+ }
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs);
diff --git a/plat/imx/imx8m/imx8mp/imx8mp_bl31_setup.c b/plat/imx/imx8m/imx8mp/imx8mp_bl31_setup.c
new file mode 100644
index 0000000..4c31fa2
--- /dev/null
+++ b/plat/imx/imx8m/imx8mp/imx8mp_bl31_setup.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2020-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <drivers/arm/tzc380.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include <dram.h>
+#include <gpc.h>
+#include <imx_aipstz.h>
+#include <imx_uart.h>
+#include <imx_rdc.h>
+#include <imx8m_caam.h>
+#include <imx8m_csu.h>
+#include <platform_def.h>
+#include <plat_imx8.h>
+
+#define TRUSTY_PARAMS_LEN_BYTES (4096*2)
+
+static const mmap_region_t imx_mmap[] = {
+ GIC_MAP, AIPS_MAP, OCRAM_S_MAP, DDRC_MAP,
+ NOC_MAP, CAAM_RAM_MAP, NS_OCRAM_MAP,
+ ROM_MAP, DRAM_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(RDC_MDA_M7, DID1),
+
+ /* peripherals domain permission */
+ RDC_PDAPn(RDC_PDAP_UART2, D0R | D0W),
+
+ /* memory region */
+
+ /* Sentinel */
+ {0},
+};
+
+static const struct imx_csu_cfg csu_cfg[] = {
+ /* peripherals csl setting */
+ CSU_CSLx(CSU_CSL_OCRAM, CSU_SEC_LEVEL_2, UNLOCKED),
+ CSU_CSLx(CSU_CSL_OCRAM_S, CSU_SEC_LEVEL_2, UNLOCKED),
+
+ /* master HP0~1 */
+
+ /* SA setting */
+
+ /* HP control setting */
+
+ /* 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;
+}
+
+static 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.mx8mp.
+ */
+
+ /* 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_t console;
+ unsigned int val;
+ unsigned 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);
+
+ imx_csu_init(csu_cfg);
+
+ /* config the ocram memory range for secure access */
+ mmio_write_32(IMX_IOMUX_GPR_BASE + 0x2c, 0x4E1);
+ val = mmio_read_32(IMX_IOMUX_GPR_BASE + 0x2c);
+ mmio_write_32(IMX_IOMUX_GPR_BASE + 0x2c, val | 0x3DFF0000);
+
+ 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_FLAG_BOOT);
+
+ imx8m_caam_init();
+
+ /*
+ * 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);
+
+#if defined(SPD_opteed) || defined(SPD_trusty)
+ /* 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 = 0;
+
+ /* Pass TEE base and size to bl33 */
+ bl33_image_ep_info.args.arg1 = BL32_BASE;
+ bl33_image_ep_info.args.arg2 = BL32_SIZE;
+
+#ifdef SPD_trusty
+ bl32_image_ep_info.args.arg0 = BL32_SIZE;
+ bl32_image_ep_info.args.arg1 = BL32_BASE;
+#else
+ /* Make sure memory is clean */
+ mmio_write_32(BL32_FDT_OVERLAY_ADDR, 0);
+ bl33_image_ep_info.args.arg3 = BL32_FDT_OVERLAY_ADDR;
+ bl32_image_ep_info.args.arg3 = BL32_FDT_OVERLAY_ADDR;
+#endif
+#endif
+
+ bl31_tzc380_setup();
+}
+
+#define MAP_BL31_TOTAL \
+ MAP_REGION_FLAT(BL31_START, BL31_SIZE, MT_MEMORY | MT_RW | MT_SECURE)
+#define MAP_BL31_RO \
+ MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, MT_MEMORY | MT_RO | MT_SECURE)
+#define MAP_COHERENT_MEM \
+ MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+#define MAP_BL32_TOTAL \
+ MAP_REGION_FLAT(BL32_BASE, BL32_SIZE, MT_MEMORY | MT_RW)
+
+void bl31_plat_arch_setup(void)
+{
+ const mmap_region_t bl_regions[] = {
+ MAP_BL31_TOTAL,
+ MAP_BL31_RO,
+#if USE_COHERENT_MEM
+ MAP_COHERENT_MEM,
+#endif
+ /* Map TEE memory */
+ MAP_BL32_TOTAL,
+ {0}
+ };
+
+ setup_page_tables(bl_regions, imx_mmap);
+ 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);
+
+ /* Init the dram info */
+ dram_info_init(SAVED_DRAM_TIMING_BASE);
+
+ 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;
+}
+
+#ifdef SPD_trusty
+void plat_trusty_set_boot_args(aapcs64_params_t *args)
+{
+ args->arg0 = BL32_SIZE;
+ args->arg1 = BL32_BASE;
+ args->arg2 = TRUSTY_PARAMS_LEN_BYTES;
+}
+#endif
diff --git a/plat/imx/imx8m/imx8mp/imx8mp_psci.c b/plat/imx/imx8m/imx8mp/imx8mp_psci.c
new file mode 100644
index 0000000..bc7b246
--- /dev/null
+++ b/plat/imx/imx8m/imx8mp/imx8mp_psci.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <gpc.h>
+#include <imx8m_psci.h>
+#include <plat_imx8.h>
+
+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;
+}
diff --git a/plat/imx/imx8m/imx8mp/imx8mp_rotpk.S b/plat/imx/imx8m/imx8mp/imx8mp_rotpk.S
new file mode 100644
index 0000000..a4c7ce1
--- /dev/null
+++ b/plat/imx/imx8m/imx8mp/imx8mp_rotpk.S
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+ .global imx8mp_rotpk_hash
+ .global imx8mp_rotpk_hash_end
+imx8mp_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
+imx8mp_rotpk_hash_end:
diff --git a/plat/imx/imx8m/imx8mp/imx8mp_trusted_boot.c b/plat/imx/imx8m/imx8mp/imx8mp_trusted_boot.c
new file mode 100644
index 0000000..5d1a6c2
--- /dev/null
+++ b/plat/imx/imx8m/imx8mp/imx8mp_trusted_boot.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+extern char imx8mp_rotpk_hash[], imx8mp_rotpk_hash_end[];
+
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+ unsigned int *flags)
+{
+ *key_ptr = imx8mp_rotpk_hash;
+ *key_len = imx8mp_rotpk_hash_end - imx8mp_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);
+}
diff --git a/plat/imx/imx8m/imx8mp/include/gpc_reg.h b/plat/imx/imx8m/imx8mp/include/gpc_reg.h
new file mode 100644
index 0000000..7909937
--- /dev/null
+++ b/plat/imx/imx8m/imx8mp/include/gpc_reg.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GPC_REG_H
+#define GPC_REG_H
+
+#define LPCR_A53_BSC 0x0
+#define LPCR_A53_BSC2 0x180
+#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 0x44
+#define IMR1_CORE2_A53 0x194
+#define IMR1_CORE3_A53 0x1A8
+#define IMR1_CORE0_M4 0x58
+
+#define SLT0_CFG 0x200
+#define GPC_PU_PWRHSK 0x190
+#define PGC_CPU_0_1_MAPPING 0x1CC
+#define CPU_PGC_UP_TRG 0xD0
+#define PU_PGC_UP_TRG 0xD8
+#define CPU_PGC_DN_TRG 0xDC
+#define PU_PGC_DN_TRG 0xE4
+#define LPS_CPU1 0xEC
+
+#define A53_CORE0_PGC 0x800
+#define A53_PLAT_PGC 0x900
+#define PLAT_PGC_PCR 0x900
+#define NOC_PGC_PCR 0xa40
+#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 MASTER1_LPM_HSK BIT(7)
+#define MASTER2_LPM_HSK BIT(8)
+
+#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(30)
+#define A53_DUMMY_PUP_ACK BIT(31)
+#define A53_PLAT_PDN_ACK BIT(8)
+#define A53_PLAT_PUP_ACK BIT(9)
+
+#define NOC_PDN_SLT_CTRL BIT(12)
+#define NOC_PUP_SLT_CTRL BIT(13)
+#define NOC_PGC_PDN_ACK BIT(12)
+#define NOC_PGC_PUP_ACK BIT(13)
+
+#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)
+
+#define TMR_TCD2_SHIFT 0
+#define TMC_TMR_SHIFT 10
+#define TRC1_TMC_SHIFT 20
+
+#define MIPI_PHY1_PWR_REQ BIT(0)
+#define PCIE_PHY_PWR_REQ BIT(1)
+#define USB1_PHY_PWR_REQ BIT(2)
+#define USB2_PHY_PWR_REQ BIT(3)
+#define MLMIX_PWR_REQ BIT(4)
+#define AUDIOMIX_PWR_REQ BIT(5)
+#define GPU2D_PWR_REQ BIT(6)
+#define GPUMIX_PWR_REQ BIT(7)
+#define VPUMIX_PWR_REQ BIT(8)
+#define GPU3D_PWR_REQ BIT(9)
+#define MEDIAMIX_PWR_REQ BIT(10)
+#define VPU_G1_PWR_REQ BIT(11)
+#define VPU_G2_PWR_REQ BIT(12)
+#define VPU_H1_PWR_REQ BIT(13)
+#define HDMIMIX_PWR_REQ BIT(14)
+#define HDMI_PHY_PWR_REQ BIT(15)
+#define MIPI_PHY2_PWR_REQ BIT(16)
+#define HSIOMIX_PWR_REQ BIT(17)
+#define MEDIAMIX_ISPDWP_PWR_REQ BIT(18)
+#define DDRMIX_PWR_REQ BIT(19)
+
+#define AUDIOMIX_ADB400_SYNC (BIT(4) | BIT(15))
+#define MLMIX_ADB400_SYNC (BIT(7) | BIT(8))
+#define GPUMIX_ADB400_SYNC BIT(9)
+#define VPUMIX_ADB400_SYNC BIT(10)
+#define DDRMIX_ADB400_SYNC BIT(11)
+#define HSIOMIX_ADB400_SYNC BIT(12)
+#define HDMIMIX_ADB400_SYNC BIT(13)
+#define MEDIAMIX_ADB400_SYNC BIT(14)
+
+#define AUDIOMIX_ADB400_ACK (BIT(20) | BIT(31))
+#define MLMIX_ADB400_ACK (BIT(23) | BIT(24))
+#define GPUMIX_ADB400_ACK BIT(25)
+#define VPUMIX_ADB400_ACK BIT(26)
+#define DDRMIX_ADB400_ACK BIT(27)
+#define HSIOMIX_ADB400_ACK BIT(28)
+#define HDMIMIX_ADB400_ACK BIT(29)
+#define MEDIAMIX_ADB400_ACK BIT(30)
+
+#define MIPI_PHY1_PGC 0xb00
+#define PCIE_PHY_PGC 0xb40
+#define USB1_PHY_PGC 0xb80
+#define USB2_PHY_PGC 0xbc0
+#define MLMIX_PGC 0xc00
+#define AUDIOMIX_PGC 0xc40
+#define GPU2D_PGC 0xc80
+#define GPUMIX_PGC 0xcc0
+#define VPUMIX_PGC 0xd00
+#define GPU3D_PGC 0xd40
+#define MEDIAMIX_PGC 0xd80
+#define VPU_G1_PGC 0xdc0
+#define VPU_G2_PGC 0xe00
+#define VPU_H1_PGC 0xe40
+#define HDMIMIX_PGC 0xe80
+#define HDMI_PHY_PGC 0xec0
+#define MIPI_PHY2_PGC 0xf00
+#define HSIOMIX_PGC 0xf40
+#define MEDIAMIX_ISPDWP_PGC 0xf80
+#define DDRMIX_PGC 0xfc0
+
+#define IRQ_IMR_NUM U(5)
+
+#endif /* GPC_REG_H */
diff --git a/plat/imx/imx8m/imx8mp/include/imx8mp_private.h b/plat/imx/imx8m/imx8mp/include/imx8mp_private.h
new file mode 100644
index 0000000..0a02334
--- /dev/null
+++ b/plat/imx/imx8m/imx8mp/include/imx8mp_private.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX8MP_PRIVATE_H
+#define IMX8MP_PRIVATE_H
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+void plat_imx_io_setup(void);
+
+#endif /* IMX8MP_PRIVATE_H */
diff --git a/plat/imx/imx8m/imx8mp/include/imx_sec_def.h b/plat/imx/imx8m/imx8mp/include/imx_sec_def.h
new file mode 100644
index 0000000..ba248b5
--- /dev/null
+++ b/plat/imx/imx8m/imx8mp/include/imx_sec_def.h
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2020-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_SEC_DEF_H
+#define IMX_SEC_DEF_H
+
+/* RDC MDA index */
+enum rdc_mda_idx {
+ RDC_MDA_A53 = 0,
+ RDC_MDA_M7 = 1,
+ RDC_MDA_PCIE_CTRL1 = 2,
+ RDC_MDA_SDMA3p = 3,
+ RDC_MDA_SDMA3b = 4,
+ RDC_MDA_LCDIF = 5,
+ RDC_MDA_ISI = 6,
+ RDC_MDA_NPU = 7,
+ RDC_MDA_Coresight = 8,
+ RDC_MDA_DAP = 9,
+ RDC_MDA_CAAM = 10,
+ RDC_MDA_SDMA1p = 11,
+ RDC_MDA_SDMA1b = 12,
+ RDC_MDA_APBHDMA = 13,
+ RDC_MDA_RAWNAND = 14,
+ RDC_MDA_uSDHC1 = 15,
+ RDC_MDA_uSDHC2 = 16,
+ RDC_MDA_uSDHC3 = 17,
+ RDC_MDA_AUDIO_PROCESSOR = 18,
+ RDC_MDA_USB1 = 19,
+ RDC_MDA_USB2 = 20,
+ RDC_MDA_TESTPORT = 21,
+ RDC_MDA_ENET1_TX = 22,
+ RDC_MDA_ENET1_RX = 23,
+ RDC_MDA_SDMA2 = 24,
+ RDC_MDA_SDMA3_to_SPBA2 = 25,
+ RDC_MDA_SDMA1_to_SPBA1 = 26,
+ RDC_MDA_LCDIF2 = 27,
+ RDC_MDA_HDMI_TX = 28,
+ RDC_MDA_ENET2 = 29,
+ RDC_MDA_GPU3D = 30,
+ RDC_MDA_GPU2D = 31,
+ RDC_MDA_VPU_G1 = 32,
+ RDC_MDA_VPU_G2 = 33,
+ RDC_MDA_VPU_VC8000E = 34,
+ RDC_MDA_AUDIO_EDMA = 35,
+ RDC_MDA_ISP1 = 36,
+ RDC_MDA_ISP2 = 37,
+ RDC_MDA_DEWARP = 38,
+ RDC_MDA_GIC500 = 39,
+};
+
+/* RDC Peripherals index */
+enum rdc_pdap_idx {
+ RDC_PDAP_GPIO1 = 0,
+ RDC_PDAP_GPIO2 = 1,
+ RDC_PDAP_GPIO3 = 2,
+ RDC_PDAP_GPIO4 = 3,
+ RDC_PDAP_GPIO5 = 4,
+ RDC_PDAP_MU_2_A = 5,
+ RDC_PDAP_ANA_TSENSOR = 6,
+ RDC_PDAP_ANA_OSC = 7,
+ RDC_PDAP_WDOG1 = 8,
+ RDC_PDAP_WDOG2 = 9,
+ RDC_PDAP_WDOG3 = 10,
+ RDC_PDAP_GPT1 = 13,
+ RDC_PDAP_GPT2 = 14,
+ RDC_PDAP_GPT3 = 15,
+ RDC_PDAP_MU_2_B = 16,
+ RDC_PDAP_ROMCP = 17,
+ RDC_PDAP_MU_3_A = 18,
+ RDC_PDAP_IOMUXC = 19,
+ RDC_PDAP_IOMUXC_GPR = 20,
+ RDC_PDAP_OCOTP_CTRL = 21,
+ RDC_PDAP_ANA_PLL = 22,
+ RDC_PDAP_SNVS_HP = 23,
+ RDC_PDAP_CCM = 24,
+ RDC_PDAP_SRC = 25,
+ RDC_PDAP_GPC = 26,
+ RDC_PDAP_SEMAPHORE1 = 27,
+ RDC_PDAP_SEMAPHORE2 = 28,
+ RDC_PDAP_RDC = 29,
+ RDC_PDAP_CSU = 30,
+ RDC_PDAP_MU_3_B = 31,
+ RDC_PDAP_ISI = 32,
+ RDC_PDAP_ISP0 = 33,
+ RDC_PDAP_ISP1 = 34,
+ RDC_PDAP_IPS_Dewarp = 35,
+ RDC_PDAP_MIPI_CSI0 = 36,
+ RDC_PDAP_HSIOMIX_BLK_CTL = 37,
+ RDC_PDAP_PWM1 = 38,
+ RDC_PDAP_PWM2 = 39,
+ RDC_PDAP_PWM3 = 40,
+ RDC_PDAP_PWM4 = 41,
+ RDC_PDAP_System_Counter_RD = 42,
+ RDC_PDAP_System_Counter_CMP = 43,
+ RDC_PDAP_System_Counter_CTRL = 44,
+ RDC_PDAP_I2C5 = 45,
+ RDC_PDAP_GPT6 = 46,
+ RDC_PDAP_GPT5 = 47,
+ RDC_PDAP_GPT4 = 48,
+ RDC_PDAP_MIPI_CSI1 = 49,
+ RDC_PDAP_MIPI_DSI0 = 50,
+ RDC_PDAP_MEDIAMIX_BLK_CTL = 51,
+ RDC_PDAP_LCDIF1 = 52,
+ RDC_PDAP_eDMA_Management_Page = 53,
+ RDC_PDAP_eDMA_Channels_15_0 = 54,
+ RDC_PDAP_eDMA_Channels_31_16 = 55,
+ RDC_PDAP_TZASC = 56,
+ RDC_PDAP_I2C6 = 57,
+ RDC_PDAP_CAAM = 58,
+ RDC_PDAP_LCDIF2 = 59,
+ RDC_PDAP_PERFMON1 = 60,
+ RDC_PDAP_PERFMON2 = 61,
+ RDC_PDAP_NOC_BLK_CTL = 62,
+ RDC_PDAP_QoSC = 63,
+ RDC_PDAP_LVDS0 = 64,
+ RDC_PDAP_LVDS1 = 65,
+ RDC_PDAP_I2C1 = 66,
+ RDC_PDAP_I2C2 = 67,
+ RDC_PDAP_I2C3 = 68,
+ RDC_PDAP_I2C4 = 69,
+ RDC_PDAP_UART4 = 70,
+ RDC_PDAP_HDMI_TX = 71,
+ RDC_PDAP_IRQ_STEER_Audio_Processor = 72,
+ RDC_PDAP_SDMA2 = 73,
+ RDC_PDAP_MU_1_A = 74,
+ RDC_PDAP_MU_1_B = 75,
+ RDC_PDAP_SEMAPHORE_HS = 76,
+ RDC_PDAP_SAI1 = 78,
+ RDC_PDAP_SAI2 = 79,
+ RDC_PDAP_SAI3 = 80,
+ RDC_PDAP_CAN_FD1 = 81,
+ RDC_PDAP_SAI5 = 82,
+ RDC_PDAP_SAI6 = 83,
+ RDC_PDAP_uSDHC1 = 84,
+ RDC_PDAP_uSDHC2 = 85,
+ RDC_PDAP_uSDHC3 = 86,
+ RDC_PDAP_PCIE_PHY1 = 87,
+ RDC_PDAP_HDMI_TX_AUDLNK_MSTR = 88,
+ RDC_PDAP_CAN_FD2 = 89,
+ RDC_PDAP_SPBA2 = 90,
+ RDC_PDAP_QSPI = 91,
+ RDC_PDAP_AUDIO_BLK_CTRL = 92,
+ RDC_PDAP_SDMA1 = 93,
+ RDC_PDAP_ENET1 = 94,
+ RDC_PDAP_ENET2_TSN = 95,
+ RDC_PDAP_ASRC = 97,
+ RDC_PDAP_eCSPI1 = 98,
+ RDC_PDAP_eCSPI2 = 99,
+ RDC_PDAP_eCSPI3 = 100,
+ RDC_PDAP_SAI7 = 101,
+ RDC_PDAP_UART1 = 102,
+ RDC_PDAP_UART3 = 104,
+ RDC_PDAP_UART2 = 105,
+ RDC_PDAP_PDM_MICFIL = 106,
+ RDC_PDAP_AUDIO_XCVR_RX_eARC = 107,
+ RDC_PDAP_SDMA3 = 109,
+ RDC_PDAP_SPBA1 = 111,
+};
+
+enum csu_csl_idx {
+ CSU_CSL_GPIO1 = 0,
+ CSU_CSL_GPIO2 = 1,
+ CSU_CSL_GPIO3 = 2,
+ CSU_CSL_GPIO4 = 3,
+ CSU_CSL_GPIO5 = 4,
+ CSU_CSL_MU_2_A = 5,
+ CSU_CSL_ANA_TSENSOR = 6,
+ CSU_CSL_ANA_OSC = 7,
+ CSU_CSL_WDOG1 = 8,
+ CSU_CSL_WDOG2 = 9,
+ CSU_CSL_WDOG3 = 10,
+ CSU_CSL_GPT1 = 13,
+ CSU_CSL_GPT2 = 14,
+ CSU_CSL_GPT3 = 15,
+ CSU_CSL_MU_2_B = 16,
+ CSU_CSL_ROMCP = 17,
+ CSU_CSL_MU_3_A = 18,
+ CSU_CSL_IOMUXC = 19,
+ CSU_CSL_IOMUXC_GPR = 20,
+ CSU_CSL_OCOTP_CTRL = 21,
+ CSU_CSL_ANA_PLL = 22,
+ CSU_CSL_SNVS_HP = 23,
+ CSU_CSL_CCM = 24,
+ CSU_CSL_SRC = 25,
+ CSU_CSL_GPC = 26,
+ CSU_CSL_SEMAPHORE1 = 27,
+ CSU_CSL_SEMAPHORE2 = 28,
+ CSU_CSL_RDC = 29,
+ CSU_CSL_CSU = 30,
+ CSU_CSL_MU_3_B = 31,
+ CSU_CSL_ISI = 32,
+ CSU_CSL_ISP0 = 33,
+ CSU_CSL_ISP1 = 34,
+ CSU_CSL_IPS_Dewarp = 35,
+ CSU_CSL_MIPI_CSI0 = 36,
+ CSU_CSL_HSIOMIX_BLK_CTL = 37,
+ CSU_CSL_PWM1 = 38,
+ CSU_CSL_PWM2 = 39,
+ CSU_CSL_PWM3 = 40,
+ CSU_CSL_PWM4 = 41,
+ CSU_CSL_System_Counter_RD = 42,
+ CSU_CSL_System_Counter_CMP = 43,
+ CSU_CSL_System_Counter_CTRL = 44,
+ CSU_CSL_I2C5 = 45,
+ CSU_CSL_GPT6 = 46,
+ CSU_CSL_GPT5 = 47,
+ CSU_CSL_GPT4 = 48,
+ CSU_CSL_MIPI_CSI1 = 49,
+ CSU_CSL_MIPI_DSI0 = 50,
+ CSU_CSL_MEDIAMIX_BLK_CTL = 51,
+ CSU_CSL_LCDIF1 = 52,
+ CSU_CSL_eDMA_Management_Page = 53,
+ CSU_CSL_eDMA_Channels_15_0 = 54,
+ CSU_CSL_eDMA_Channels_31_16 = 55,
+ CSU_CSL_TZASC = 56,
+ CSU_CSL_I2C6 = 57,
+ CSU_CSL_CAAM = 58,
+ CSU_CSL_LCDIF2 = 59,
+ CSU_CSL_PERFMON1 = 60,
+ CSU_CSL_PERFMON2 = 61,
+ CSU_CSL_NOC_BLK_CTL = 62,
+ CSU_CSL_QoSC = 63,
+ CSU_CSL_LVDS0 = 64,
+ CSU_CSL_LVDS1 = 65,
+ CSU_CSL_I2C1 = 66,
+ CSU_CSL_I2C2 = 67,
+ CSU_CSL_I2C3 = 68,
+ CSU_CSL_I2C4 = 69,
+ CSU_CSL_UART4 = 70,
+ CSU_CSL_HDMI_TX = 71,
+ CSU_CSL_IRQ_STEER_Audio_Processor = 72,
+ CSU_CSL_SDMA2 = 73,
+ CSU_CSL_MU_1_A = 74,
+ CSU_CSL_MU_1_B = 75,
+ CSU_CSL_SEMAPHORE_HS = 76,
+ CSU_CSL_SAI1 = 78,
+ CSU_CSL_SAI2 = 79,
+ CSU_CSL_SAI3 = 80,
+ CSU_CSL_CAN_FD1 = 81,
+ CSU_CSL_SAI5 = 82,
+ CSU_CSL_SAI6 = 83,
+ CSU_CSL_uSDHC1 = 84,
+ CSU_CSL_uSDHC2 = 85,
+ CSU_CSL_uSDHC3 = 86,
+ CSU_CSL_PCIE_PHY1 = 87,
+ CSU_CSL_HDMI_TX_AUDLNK_MSTR = 88,
+ CSU_CSL_CAN_FD2 = 89,
+ CSU_CSL_SPBA2 = 90,
+ CSU_CSL_QSPI = 91,
+ CSU_CSL_AUDIO_BLK_CTRL = 92,
+ CSU_CSL_SDMA1 = 93,
+ CSU_CSL_ENET1 = 94,
+ CSU_CSL_ENET2_TSN = 95,
+ CSU_CSL_ASRC = 97,
+ CSU_CSL_eCSPI1 = 98,
+ CSU_CSL_eCSPI2 = 99,
+ CSU_CSL_eCSPI3 = 100,
+ CSU_CSL_SAI7 = 101,
+ CSU_CSL_UART1 = 102,
+ CSU_CSL_UART3 = 104,
+ CSU_CSL_UART2 = 105,
+ CSU_CSL_PDM_MICFIL = 106,
+ CSU_CSL_AUDIO_XCVR_RX_eARC = 107,
+ CSU_CSL_SDMA3 = 109,
+ CSU_CSL_SPBA1 = 111,
+ CSU_CSL_OCRAM_A = 113,
+ CSU_CSL_OCRAM = 118,
+ CSU_CSL_OCRAM_S = 119,
+};
+
+#endif /* IMX_SEC_DEF_H */
diff --git a/plat/imx/imx8m/imx8mp/include/platform_def.h b/plat/imx/imx8m/imx8mp/include/platform_def.h
new file mode 100644
index 0000000..14cb709
--- /dev/null
+++ b/plat/imx/imx8m/imx8mp/include/platform_def.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2020-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/common_def.h>
+
+#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 U(0x0)
+#define PLATFORM_MAX_CPU_PER_CLUSTER U(4)
+#define PLATFORM_CLUSTER_COUNT U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT U(4)
+#define PLATFORM_CLUSTER1_CORE_COUNT U(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)
+
+#if defined(NEED_BL2)
+#define BL2_BASE U(0x970000)
+#define BL2_SIZE SZ_128K
+#define BL2_LIMIT (BL2_BASE + BL2_SIZE)
+#define BL31_BASE U(0x950000)
+#define IMX_FIP_BASE U(0x40310000)
+#define IMX_FIP_SIZE U(0x000300000)
+#define IMX_FIP_LIMIT U(FIP_BASE + FIP_SIZE)
+
+/* Define FIP image location on eMMC */
+#define IMX_FIP_MMC_BASE U(0x100000)
+
+#define PLAT_IMX8MP_BOOT_MMC_BASE U(0x30B50000) /* SD */
+#else
+#define BL31_BASE U(0x970000)
+#endif
+
+#define BL31_SIZE SZ_128K
+#define BL31_LIMIT (BL31_BASE + BL31_SIZE)
+
+#define PLAT_PRI_BITS U(3)
+#define PLAT_SDEI_CRITICAL_PRI 0x10
+#define PLAT_SDEI_NORMAL_PRI 0x20
+#define PLAT_SDEI_SGI_PRIVATE U(9)
+
+/* non-secure uboot base */
+#define PLAT_NS_IMAGE_OFFSET U(0x40200000)
+#define PLAT_NS_IMAGE_SIZE U(0x00200000)
+
+#define BL32_FDT_OVERLAY_ADDR (PLAT_NS_IMAGE_OFFSET + 0x3000000)
+
+/* GICv3 base address */
+#define PLAT_GICD_BASE U(0x38800000)
+#define PLAT_GICR_BASE U(0x38880000)
+
+#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 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_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_AIPSTZ5 U(0x30df0000)
+
+#define IMX_AIPS_BASE U(0x30000000)
+#define IMX_AIPS_SIZE U(0x3000000)
+#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_NOC_SIZE U(0x100000)
+#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_DDR_IPS_SIZE U(0x1800000)
+#define IMX_ROM_BASE U(0x0)
+#define IMX_ROM_SIZE U(0x40000)
+#define IMX_NS_OCRAM_BASE U(0x900000)
+#define IMX_NS_OCRAM_SIZE U(0x60000)
+#define IMX_CAAM_RAM_BASE U(0x100000)
+#define IMX_CAAM_RAM_SIZE U(0x10000)
+#define IMX_DRAM_BASE U(0x40000000)
+#define IMX_DRAM_SIZE U(0xc0000000)
+
+#define IMX_GIC_BASE PLAT_GICD_BASE
+#define IMX_GIC_SIZE U(0x200000)
+
+#define IMX_HSIOMIX_CTL_BASE U(0x32f10000)
+#define IMX_HDMI_CTL_BASE U(0x32fc0000)
+#define RTX_RESET_CTL0 U(0x20)
+#define RTX_CLK_CTL0 U(0x40)
+#define RTX_CLK_CTL1 U(0x50)
+#define TX_CONTROL0 U(0x200)
+#define TX_CONTROL1 U(0x220)
+
+#define IMX_MEDIAMIX_CTL_BASE U(0x32ec0000)
+#define RSTn_CSR U(0x0)
+#define CLK_EN_CSR U(0x4)
+#define RST_DIV U(0x8)
+#define LCDIF_ARCACHE_CTRL U(0x4c)
+#define ISI_CACHE_CTRL U(0x50)
+
+#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 DRAM_PLL_CTRL (IMX_ANAMIX_BASE + 0x50)
+
+#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 SAVED_DRAM_TIMING_BASE OCRAM_S_BASE
+
+#define COUNTER_FREQUENCY 8000000 /* 8MHz */
+
+#define IMX_WDOG_B_RESET
+
+#define MAX_IO_HANDLES 3U
+#define MAX_IO_DEVICES 2U
+#define MAX_IO_BLOCK_DEVICES 1U
+
+#define GIC_MAP MAP_REGION_FLAT(IMX_GIC_BASE, IMX_GIC_SIZE, MT_DEVICE | MT_RW)
+#define AIPS_MAP MAP_REGION_FLAT(IMX_AIPS_BASE, IMX_AIPS_SIZE, MT_DEVICE | MT_RW) /* AIPS map */
+#define OCRAM_S_MAP MAP_REGION_FLAT(OCRAM_S_BASE, OCRAM_S_SIZE, MT_MEMORY | MT_RW) /* OCRAM_S */
+#define DDRC_MAP MAP_REGION_FLAT(IMX_DDRPHY_BASE, IMX_DDR_IPS_SIZE, MT_DEVICE | MT_RW) /* DDRMIX */
+#define NOC_MAP MAP_REGION_FLAT(IMX_NOC_BASE, IMX_NOC_SIZE, MT_DEVICE | MT_RW) /* NOC QoS */
+#define CAAM_RAM_MAP MAP_REGION_FLAT(IMX_CAAM_RAM_BASE, IMX_CAAM_RAM_SIZE, MT_MEMORY | MT_RW) /* CAMM RAM */
+#define NS_OCRAM_MAP MAP_REGION_FLAT(IMX_NS_OCRAM_BASE, IMX_NS_OCRAM_SIZE, MT_MEMORY | MT_RW) /* NS OCRAM */
+#define ROM_MAP MAP_REGION_FLAT(IMX_ROM_BASE, IMX_ROM_SIZE, MT_MEMORY | MT_RO) /* ROM code */
+
+/*
+ * Note: DRAM region is mapped with entire size available and uses MT_RW
+ * attributes.
+ * See details in docs/plat/imx8m.rst "High Assurance Boot (HABv4)" section
+ * for explanation of this mapping scheme.
+ */
+#define DRAM_MAP MAP_REGION_FLAT(IMX_DRAM_BASE, IMX_DRAM_SIZE, MT_MEMORY | MT_RW | MT_NS) /* DRAM */
+
+#endif /* platform_def.h */
diff --git a/plat/imx/imx8m/imx8mp/platform.mk b/plat/imx/imx8m/imx8mp/platform.mk
new file mode 100644
index 0000000..5414c0a
--- /dev/null
+++ b/plat/imx/imx8m/imx8mp/platform.mk
@@ -0,0 +1,168 @@
+#
+# Copyright 2019-2022 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT_INCLUDES := -Iplat/imx/common/include \
+ -Iplat/imx/imx8m/include \
+ -Iplat/imx/imx8m/imx8mp/include \
+ -Idrivers/imx/usdhc \
+ -Iinclude/common/tbbr
+# Translation tables library
+include lib/xlat_tables_v2/xlat_tables.mk
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+IMX_DRAM_SOURCES := plat/imx/imx8m/ddr/dram.c \
+ plat/imx/imx8m/ddr/clock.c \
+ plat/imx/imx8m/ddr/dram_retention.c \
+ plat/imx/imx8m/ddr/ddr4_dvfs.c \
+ plat/imx/imx8m/ddr/lpddr4_dvfs.c
+
+IMX_GIC_SOURCES := ${GICV3_SOURCES} \
+ 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_hab.c \
+ plat/imx/imx8m/imx_aipstz.c \
+ plat/imx/imx8m/imx_rdc.c \
+ plat/imx/imx8m/imx8m_caam.c \
+ plat/imx/imx8m/imx8m_csu.c \
+ plat/imx/imx8m/imx8m_psci_common.c \
+ plat/imx/imx8m/imx8mp/imx8mp_bl31_setup.c \
+ plat/imx/imx8m/imx8mp/imx8mp_psci.c \
+ plat/imx/imx8m/imx8mp/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/cpus/aarch64/cortex_a53.S \
+ drivers/arm/tzc/tzc380.c \
+ drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ ${IMX_DRAM_SOURCES} \
+ ${IMX_GIC_SOURCES} \
+ ${XLAT_TABLES_LIB_SRCS}
+
+ifeq (${NEED_BL2},yes)
+BL2_SOURCES += common/desc_image_load.c \
+ plat/imx/common/imx8_helpers.S \
+ plat/imx/common/imx_uart_console.S \
+ plat/imx/imx8m/imx8mp/imx8mp_bl2_el3_setup.c \
+ plat/imx/imx8m/imx8mp/gpc.c \
+ plat/imx/imx8m/imx_aipstz.c \
+ plat/imx/imx8m/imx_rdc.c \
+ plat/imx/imx8m/imx8m_caam.c \
+ plat/common/plat_psci_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 \
+ ${PLAT_GIC_SOURCES} \
+ ${PLAT_DRAM_SOURCES} \
+ ${XLAT_TABLES_LIB_SRCS} \
+ 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/usdhc/imx_usdhc.c \
+ plat/imx/imx8m/imx8mp/imx8mp_bl2_mem_params_desc.c \
+ plat/imx/common/imx_io_storage.c \
+ plat/imx/imx8m/imx8m_image_load.c \
+ lib/optee/optee_utils.c
+endif
+
+# Add the build options to pack BLx images and kernel device tree
+# in the FIP if the platform requires.
+ifneq ($(BL2),)
+RESET_TO_BL31 := 0
+$(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
+
+ifeq (${NEED_BL2},yes)
+$(eval $(call add_define,NEED_BL2))
+LOAD_IMAGE_V2 := 1
+# Non-TF Boot ROM
+BL2_AT_EL3 := 1
+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_common.c \
+ drivers/auth/tbbr/tbbr_cot_bl2.c
+
+BL2_SOURCES += ${AUTH_SOURCES} \
+ plat/common/tbbr/plat_tbbr.c \
+ plat/imx/imx8m/imx8mp/imx8mp_trusted_boot.c \
+ plat/imx/imx8m/imx8mp/imx8mp_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/imx8mp_rotpk.o: $(ROTPK_HASH)
+
+certificates: $(ROT_KEY)
+
+$(ROT_KEY): | $(BUILD_PLAT)
+ @echo " OPENSSL $@"
+ @if [ ! -f $(ROT_KEY) ]; then \
+ ${OPENSSL_BIN_PATH}/openssl genrsa 2048 > $@ 2>/dev/null; \
+ fi
+
+$(ROTPK_HASH): $(ROT_KEY)
+ @echo " OPENSSL $@"
+ $(Q)${OPENSSL_BIN_PATH}/openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+ ${OPENSSL_BIN_PATH}/openssl dgst -sha256 -binary > $@ 2>/dev/null
+endif
+
+ENABLE_PIE := 1
+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
+
+BL32_BASE ?= 0x56000000
+$(eval $(call add_define,BL32_BASE))
+
+BL32_SIZE ?= 0x2000000
+$(eval $(call add_define,BL32_SIZE))
+
+IMX_BOOT_UART_BASE ?= 0x30890000
+$(eval $(call add_define,IMX_BOOT_UART_BASE))
+
+EL3_EXCEPTION_HANDLING := $(SDEI_SUPPORT)
+ifeq (${SDEI_SUPPORT}, 1)
+BL31_SOURCES += plat/imx/common/imx_ehf.c \
+ plat/imx/common/imx_sdei.c
+endif
+
+ifeq (${SPD},trusty)
+ BL31_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC=1
+endif
diff --git a/plat/imx/imx8m/imx8mq/gpc.c b/plat/imx/imx8m/imx8mq/gpc.c
new file mode 100644
index 0000000..fa83324
--- /dev/null
+++ b/plat/imx/imx8m/imx8mq/gpc.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <platform_def.h>
+#include <services/std_svc.h>
+
+#include <gpc.h>
+
+/* use wfi power down the core */
+void imx_set_cpu_pwr_off(unsigned int core_id)
+{
+ bakery_lock_get(&gpc_lock);
+
+ /* 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)));
+
+ bakery_lock_release(&gpc_lock);
+
+ /* 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)
+{
+ bakery_lock_get(&gpc_lock);
+
+ 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);
+ }
+
+ bakery_lock_release(&gpc_lock);
+}
+
+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);
+
+ /*
+ * for USB OTG, the limitation are:
+ * 1. before system clock config, the IPG clock run at 12.5MHz, delay time
+ * should be longer than 82us.
+ * 2. after system clock config, ipg clock run at 66.5MHz, delay time
+ * be longer that 15.3 us.
+ * Add 100us to make sure the USB OTG SRC is clear safely.
+ */
+ udelay(100);
+}
diff --git a/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c b/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c
new file mode 100644
index 0000000..59c3779
--- /dev/null
+++ b/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <drivers/arm/tzc380.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include <gpc.h>
+#include <imx_aipstz.h>
+#include <imx_uart.h>
+#include <imx8m_caam.h>
+#include <plat_imx8.h>
+
+#define TRUSTY_PARAMS_LEN_BYTES (4096*2)
+
+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);
+
+#if DEBUG_CONSOLE
+ static console_t console;
+
+ console_imx_uart_register(IMX_BOOT_UART_BASE, IMX_BOOT_UART_CLK_IN_HZ,
+ IMX_CONSOLE_BAUDRATE, &console);
+#endif
+
+ imx8m_caam_init();
+
+ /*
+ * 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);
+
+#if defined(SPD_opteed) || defined(SPD_trusty)
+ /* 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 = 0;
+
+ /* Pass TEE base and size to bl33 */
+ bl33_image_ep_info.args.arg1 = BL32_BASE;
+ bl33_image_ep_info.args.arg2 = BL32_SIZE;
+
+#ifdef SPD_trusty
+ bl32_image_ep_info.args.arg0 = BL32_SIZE;
+ bl32_image_ep_info.args.arg1 = BL32_BASE;
+#else
+ /* Make sure memory is clean */
+ mmio_write_32(BL32_FDT_OVERLAY_ADDR, 0);
+ bl33_image_ep_info.args.arg3 = BL32_FDT_OVERLAY_ADDR;
+ bl32_image_ep_info.args.arg3 = BL32_FDT_OVERLAY_ADDR;
+#endif
+#endif
+
+ 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);
+
+ /* Map TEE memory */
+ mmap_add_region(BL32_BASE, BL32_BASE, BL32_SIZE, MT_MEMORY | MT_RW);
+
+ 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;
+}
+
+#ifdef SPD_trusty
+void plat_trusty_set_boot_args(aapcs64_params_t *args)
+{
+ args->arg0 = BL32_SIZE;
+ args->arg1 = BL32_BASE;
+ args->arg2 = TRUSTY_PARAMS_LEN_BYTES;
+}
+#endif
diff --git a/plat/imx/imx8m/imx8mq/imx8mq_psci.c b/plat/imx/imx8m/imx8mq/imx8mq_psci.c
new file mode 100644
index 0000000..662017d
--- /dev/null
+++ b/plat/imx/imx8m/imx8mq/imx8mq_psci.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <gpc.h>
+#include <imx8m_psci.h>
+#include <plat_imx8.h>
+
+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_reset2 = imx_system_reset2,
+ .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;
+}
diff --git a/plat/imx/imx8m/imx8mq/include/gpc_reg.h b/plat/imx/imx8m/imx8mq/include/gpc_reg.h
new file mode 100644
index 0000000..f171bd9
--- /dev/null
+++ b/plat/imx/imx8m/imx8mq/include/gpc_reg.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GPC_REG_H
+#define GPC_REG_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 LPS_CPU1 0x114
+#define A53_CORE0_PGC 0x800
+#define A53_PLAT_PGC 0x900
+#define PLAT_PGC_PCR 0x900
+#define NOC_PGC_PCR 0xa40
+#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 MASTER1_LPM_HSK BIT(7)
+#define MASTER2_LPM_HSK BIT(8)
+
+#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 NOC_PDN_SLT_CTRL BIT(10)
+#define NOC_PUP_SLT_CTRL BIT(11)
+#define NOC_PGC_PDN_ACK BIT(3)
+#define NOC_PGC_PUP_ACK BIT(19)
+
+#define DDRMIX_PWR_REQ BIT(5)
+#define DDRMIX_ADB400_SYNC BIT(1)
+#define DDRMIX_ADB400_ACK BIT(18)
+#define DDRMIX_PGC 0xd40
+
+#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)
+
+#define IRQ_IMR_NUM U(4)
+
+#endif /* GPC_REG_H */
diff --git a/plat/imx/imx8m/imx8mq/include/imx_sec_def.h b/plat/imx/imx8m/imx8mq/include/imx_sec_def.h
new file mode 100644
index 0000000..0f77141
--- /dev/null
+++ b/plat/imx/imx8m/imx8mq/include/imx_sec_def.h
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2020-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_SEC_DEF_H
+#define IMX_SEC_DEF_H
+
+/* RDC MDA index */
+enum rdc_mda_idx {
+ RDC_MDA_A53 = 0,
+ RDC_MDA_M4 = 1,
+ RDC_MDA_PCIE_CTRL1 = 2,
+ RDC_MDA_PCIE_CTRL2 = 3,
+ RDC_MDA_VPU_DEC = 4,
+ RDC_MDA_LCDIF = 5,
+ RDC_MDA_CSI1 = 6,
+ RDC_MDA_CSI2 = 7,
+ RDC_MDA_Coresight = 8,
+ RDC_MDA_DAP = 9,
+ RDC_MDA_CAAM = 10,
+ RDC_MDA_SDMAp = 11,
+ RDC_MDA_SDMAb = 12,
+ RDC_MDA_APBHDMA = 13,
+ RDC_MDA_RAWNAND = 14,
+ RDC_MDA_uSDHC1 = 15,
+ RDC_MDA_uSDHC2 = 16,
+ RDC_MDA_DCSS = 17,
+ RDC_MDA_GPU = 18,
+ RDC_MDA_USB1 = 19,
+ RDC_MDA_USB2 = 20,
+ RDC_MDA_TESTPORT = 21,
+ RDC_MDA_ENET1_TX = 22,
+ RDC_MDA_ENET1_RX = 23,
+ RDC_MDA_SDMA2 = 24,
+ RDC_MDA_SDMA1 = 26,
+};
+
+/* RDC Peripherals index */
+enum rdc_pdap_idx {
+ RDC_PDAP_GPIO1 = 0,
+ RDC_PDAP_GPIO2 = 1,
+ RDC_PDAP_GPIO3 = 2,
+ RDC_PDAP_GPIO4 = 3,
+ RDC_PDAP_GPIO5 = 4,
+ RDC_PDAP_ANA_TSENSOR = 6,
+ RDC_PDAP_ANA_OSC = 7,
+ RDC_PDAP_WDOG1 = 8,
+ RDC_PDAP_WDOG2 = 9,
+ RDC_PDAP_WDOG3 = 10,
+ RDC_PDAP_SDMA2 = 12,
+ RDC_PDAP_GPT1 = 13,
+ RDC_PDAP_GPT2 = 14,
+ RDC_PDAP_GPT3 = 15,
+ RDC_PDAP_ROMCP = 17,
+ RDC_PDAP_LCDIF = 18,
+ RDC_PDAP_IOMUXC = 19,
+ RDC_PDAP_IOMUXC_GPR = 20,
+ RDC_PDAP_OCOTP_CTRL = 21,
+ RDC_PDAP_ANATOP_PLL = 22,
+ RDC_PDAP_SNVS_HP = 23,
+ RDC_PDAP_CCM = 24,
+ RDC_PDAP_SRC = 25,
+ RDC_PDAP_GPC = 26,
+ RDC_PDAP_SEMAPHORE1 = 27,
+ RDC_PDAP_SEMAPHORE2 = 28,
+ RDC_PDAP_RDC = 29,
+ RDC_PDAP_CSU = 30,
+ RDC_PDAP_MST0 = 32,
+ RDC_PDAP_MST1 = 33,
+ RDC_PDAP_MST2 = 34,
+ RDC_PDAP_MST3 = 35,
+ RDC_PDAP_HDMI_SEC = 36,
+ RDC_PDAP_PWM1 = 38,
+ RDC_PDAP_PWM2 = 39,
+ RDC_PDAP_PWM3 = 40,
+ RDC_PDAP_PWM4 = 41,
+ RDC_PDAP_SysCounter_RD = 42,
+ RDC_PDAP_SysCounter_CMP = 43,
+ RDC_PDAP_SysCounter_CTRL = 44,
+ RDC_PDAP_HDMI_CTRL = 45,
+ RDC_PDAP_GPT6 = 46,
+ RDC_PDAP_GPT5 = 47,
+ RDC_PDAP_GPT4 = 48,
+ RDC_PDAP_TZASC = 56,
+ RDC_PDAP_MTR = 59,
+ RDC_PDAP_PERFMON1 = 60,
+ RDC_PDAP_PERFMON2 = 61,
+ RDC_PDAP_PLATFORM_CTRL = 62,
+ RDC_PDAP_QoSC = 63,
+ RDC_PDAP_MIPI_PHY = 64,
+ RDC_PDAP_MIPI_DSI = 65,
+ RDC_PDAP_I2C1 = 66,
+ RDC_PDAP_I2C2 = 67,
+ RDC_PDAP_I2C3 = 68,
+ RDC_PDAP_I2C4 = 69,
+ RDC_PDAP_UART4 = 70,
+ RDC_PDAP_MIPI_CSI1 = 71,
+ RDC_PDAP_MIPI_CSI_PHY1 = 72,
+ RDC_PDAP_CSI1 = 73,
+ RDC_PDAP_MU_A = 74,
+ RDC_PDAP_MU_B = 75,
+ RDC_PDAP_SEMAPHORE_HS = 76,
+ RDC_PDAP_SAI1 = 78,
+ RDC_PDAP_SAI6 = 80,
+ RDC_PDAP_SAI5 = 81,
+ RDC_PDAP_SAI4 = 82,
+ RDC_PDAP_USDHC1 = 84,
+ RDC_PDAP_USDHC2 = 85,
+ RDC_PDAP_MIPI_CSI2 = 86,
+ RDC_PDAP_MIPI_CSI_PHY2 = 87,
+ RDC_PDAP_CSI2 = 88,
+ RDC_PDAP_QSPI = 91,
+ RDC_PDAP_SDMA1 = 93,
+ RDC_PDAP_ENET1 = 94,
+ RDC_PDAP_SPDIF1 = 97,
+ RDC_PDAP_ECSPI1 = 98,
+ RDC_PDAP_ECSPI2 = 99,
+ RDC_PDAP_ECSPI3 = 100,
+ RDC_PDAP_UART1 = 102,
+ RDC_PDAP_UART3 = 104,
+ RDC_PDAP_UART2 = 105,
+ RDC_PDAP_SPDIF2 = 106,
+ RDC_PDAP_SAI2 = 107,
+ RDC_PDAP_SAI3 = 108,
+ RDC_PDAP_SPBA1 = 111,
+ RDC_PDAP_CAAM = 114,
+ RDC_PDAP_DDRC_SEC = 115,
+ RDC_PDAP_GIC_EXSC = 116,
+ RDC_PDAP_USB_EXSC = 117,
+ RDC_PDAP_OCRAM_TZ = 118,
+ RDC_PDAP_OCRAM_S_TZ = 119,
+ RDC_PDAP_VPU_SEC = 120,
+ RDC_PDAP_DAP_EXSC = 121,
+ RDC_PDAP_ROMCP_SEC = 122,
+ RDC_PDAP_APBHDMA_SEC = 123,
+ RDC_PDAP_M4_SEC = 124,
+ RDC_PDAP_QSPI_SEC = 125,
+ RDC_PDAP_GPU_EXSC = 126,
+ RDC_PDAP_PCIE = 127,
+};
+
+enum csu_csl_idx {
+ CSU_CSL_GPIO1 = 0,
+ CSU_CSL_GPIO2 = 1,
+ CSU_CSL_GPIO3 = 2,
+ CSU_CSL_GPIO4 = 3,
+ CSU_CSL_GPIO5 = 4,
+ CSU_CSL_ANA_TSENSOR = 6,
+ CSU_CSL_ANA_OSC = 7,
+ CSU_CSL_WDOG1 = 8,
+ CSU_CSL_WDOG2 = 9,
+ CSU_CSL_WDOG3 = 10,
+ CSU_CSL_SDMA2 = 12,
+ CSU_CSL_GPT1 = 13,
+ CSU_CSL_GPT2 = 14,
+ CSU_CSL_GPT3 = 15,
+ CSU_CSL_ROMCP = 17,
+ CSU_CSL_LCDIF = 18,
+ CSU_CSL_IOMUXC = 19,
+ CSU_CSL_IOMUXC_GPR = 20,
+ CSU_CSL_OCOTP_CTRL = 21,
+ CSU_CSL_ANATOP_PLL = 22,
+ CSU_CSL_SNVS_HP = 23,
+ CSU_CSL_CCM = 24,
+ CSU_CSL_SRC = 25,
+ CSU_CSL_GPC = 26,
+ CSU_CSL_SEMAPHORE1 = 27,
+ CSU_CSL_SEMAPHORE2 = 28,
+ CSU_CSL_RDC = 29,
+ CSU_CSL_CSU = 30,
+ CSU_CSL_MST0 = 32,
+ CSU_CSL_MST1 = 33,
+ CSU_CSL_MST2 = 34,
+ CSU_CSL_MST3 = 35,
+ CSU_CSL_HDMI_SEC = 36,
+ CSU_CSL_PWM1 = 38,
+ CSU_CSL_PWM2 = 39,
+ CSU_CSL_PWM3 = 40,
+ CSU_CSL_PWM4 = 41,
+ CSU_CSL_SysCounter_RD = 42,
+ CSU_CSL_SysCounter_CMP = 43,
+ CSU_CSL_SysCounter_CTRL = 44,
+ CSU_CSL_HDMI_CTRL = 45,
+ CSU_CSL_GPT6 = 46,
+ CSU_CSL_GPT5 = 47,
+ CSU_CSL_GPT4 = 48,
+ CSU_CSL_TZASC = 56,
+ CSU_CSL_MTR = 59,
+ CSU_CSL_PERFMON1 = 60,
+ CSU_CSL_PERFMON2 = 61,
+ CSU_CSL_PLATFORM_CTRL = 62,
+ CSU_CSL_QoSC = 63,
+ CSU_CSL_MIPI_PHY = 64,
+ CSU_CSL_MIPI_DSI = 65,
+ CSU_CSL_I2C1 = 66,
+ CSU_CSL_I2C2 = 67,
+ CSU_CSL_I2C3 = 68,
+ CSU_CSL_I2C4 = 69,
+ CSU_CSL_UART4 = 70,
+ CSU_CSL_MIPI_CSI1 = 71,
+ CSU_CSL_MIPI_CSI_PHY1 = 72,
+ CSU_CSL_CSI1 = 73,
+ CSU_CSL_MU_A = 74,
+ CSU_CSL_MU_B = 75,
+ CSU_CSL_SEMAPHORE_HS = 76,
+ CSU_CSL_SAI1 = 78,
+ CSU_CSL_SAI6 = 80,
+ CSU_CSL_SAI5 = 81,
+ CSU_CSL_SAI4 = 82,
+ CSU_CSL_USDHC1 = 84,
+ CSU_CSL_USDHC2 = 85,
+ CSU_CSL_MIPI_CSI2 = 86,
+ CSU_CSL_MIPI_CSI_PHY2 = 87,
+ CSU_CSL_CSI2 = 88,
+ CSU_CSL_QSPI = 91,
+ CSU_CSL_SDMA1 = 93,
+ CSU_CSL_ENET1 = 94,
+ CSU_CSL_SPDIF1 = 97,
+ CSU_CSL_ECSPI1 = 98,
+ CSU_CSL_ECSPI2 = 99,
+ CSU_CSL_ECSPI3 = 100,
+ CSU_CSL_UART1 = 102,
+ CSU_CSL_UART3 = 104,
+ CSU_CSL_UART2 = 105,
+ CSU_CSL_SPDIF2 = 106,
+ CSU_CSL_SAI2 = 107,
+ CSU_CSL_SAI3 = 108,
+ CSU_CSL_SPBA1 = 111,
+ CSU_CSL_MOD_EN3 = 112,
+ CSU_CSL_MOD_EN0 = 113,
+ CSU_CSL_CAAM = 114,
+ CSU_CSL_DDRC_SEC = 115,
+ CSU_CSL_GIC_EXSC = 116,
+ CSU_CSL_USB_EXSC = 117,
+ CSU_CSL_OCRAM_TZ = 118,
+ CSU_CSL_OCRAM_S_TZ = 119,
+ CSU_CSL_VPU_SEC = 120,
+ CSU_CSL_DAP_EXSC = 121,
+ CSU_CSL_ROMCP_SEC = 122,
+ CSU_CSL_APBHDMA_SEC = 123,
+ CSU_CSL_M4_SEC = 124,
+ CSU_CSL_QSPI_SEC = 125,
+ CSU_CSL_GPU_EXSC = 126,
+ CSU_CSL_PCIE = 127,
+};
+
+#endif /* IMX_SEC_DEF_H */
diff --git a/plat/imx/imx8m/imx8mq/include/platform_def.h b/plat/imx/imx8m/imx8mq/include/platform_def.h
new file mode 100644
index 0000000..1dd22d9
--- /dev/null
+++ b/plat/imx/imx8m/imx8mq/include/platform_def.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2018-2022, 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 U(0x0)
+#define PLATFORM_MAX_CPU_PER_CLUSTER U(4)
+#define PLATFORM_CLUSTER_COUNT U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT U(4)
+#define PLATFORM_CLUSTER1_CORE_COUNT U(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)
+
+/* non-secure uboot base */
+#define PLAT_NS_IMAGE_OFFSET U(0x40200000)
+#define BL32_FDT_OVERLAY_ADDR (PLAT_NS_IMAGE_OFFSET + 0x3000000)
+
+/* 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)
+
+#ifdef SPD_trusty
+#define MAX_XLAT_TABLES 5
+#define MAX_MMAP_REGIONS 15
+#else
+#define MAX_XLAT_TABLES 4
+#define MAX_MMAP_REGIONS 14
+#endif
+
+#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 SRC_GPR10_OFFSET U(0x98)
+#define SRC_GPR10_PERSIST_SECONDARY_BOOT BIT(30)
+
+#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 8333333 /* 25MHz / 3 */
+
+#define DEBUG_CONSOLE 0
+#define IMX_WDOG_B_RESET
diff --git a/plat/imx/imx8m/imx8mq/platform.mk b/plat/imx/imx8m/imx8mq/platform.mk
new file mode 100644
index 0000000..7b6df92
--- /dev/null
+++ b/plat/imx/imx8m/imx8mq/platform.mk
@@ -0,0 +1,57 @@
+#
+# Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Translation tables library
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_INCLUDES := -Iplat/imx/common/include \
+ -Iplat/imx/imx8m/include \
+ -Iplat/imx/imx8m/imx8mq/include
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+IMX_GIC_SOURCES := ${GICV3_SOURCES} \
+ 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/cpus/aarch64/cortex_a53.S \
+ drivers/arm/tzc/tzc380.c \
+ drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ ${XLAT_TABLES_LIB_SRCS} \
+ ${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
+
+BL32_BASE ?= 0xfe000000
+$(eval $(call add_define,BL32_BASE))
+
+BL32_SIZE ?= 0x2000000
+$(eval $(call add_define,BL32_SIZE))
+
+ifeq (${SPD},trusty)
+ BL31_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC=1
+endif
diff --git a/plat/imx/imx8m/imx_aipstz.c b/plat/imx/imx8m/imx_aipstz.c
new file mode 100644
index 0000000..ecf8b1d
--- /dev/null
+++ b/plat/imx/imx8m/imx_aipstz.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include <imx_aipstz.h>
+
+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++;
+ }
+}
diff --git a/plat/imx/imx8m/imx_hab.c b/plat/imx/imx8m/imx_hab.c
new file mode 100644
index 0000000..222046f
--- /dev/null
+++ b/plat/imx/imx8m/imx_hab.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2017-2020 NXP
+ * Copyright 2022 Leica Geosystems AG
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/runtime_svc.h>
+#include <imx_sip_svc.h>
+
+#define HAB_CID_ATF U(2) /* TF-A Caller ID */
+
+/* HAB Status definitions */
+enum hab_status {
+ HAB_STS_ANY = 0x00, /* Match any status in report_event() */
+ HAB_FAILURE = 0x33, /* Operation failed */
+ HAB_WARNING = 0x69, /* Operation completed with warning */
+ HAB_SUCCESS = 0xf0 /* Operation completed successfully */
+};
+
+/* HAB Configuration definitions */
+enum hab_config {
+ HAB_CFG_RETURN = 0x33, /* Field Return IC */
+ HAB_CFG_OPEN = 0xf0, /* Non-secure IC */
+ HAB_CFG_CLOSED = 0xcc /* Secure IC */
+};
+
+/* HAB State definitions */
+enum hab_state {
+ HAB_STATE_INITIAL = 0x33, /* Initializing state (transitory) */
+ HAB_STATE_CHECK = 0x55, /* Check state (non-secure) */
+ HAB_STATE_NONSECURE = 0x66, /* Non-secure state */
+ HAB_STATE_TRUSTED = 0x99, /* Trusted state */
+ HAB_STATE_SECURE = 0xaa, /* Secure state */
+ HAB_STATE_FAIL_SOFT = 0xcc, /* Soft fail state */
+ HAB_STATE_FAIL_HARD = 0xff, /* Hard fail state (terminal) */
+ HAB_STATE_NONE = 0xf0 /* No security state machine */
+};
+
+/* HAB Verification Target definitions */
+enum hab_target {
+ HAB_TGT_MEMORY = 0x0f, /* Check memory allowed list */
+ HAB_TGT_PERIPHERAL = 0xf0, /* Check peripheral allowed list */
+ HAB_TGT_ANY = 0x55 /* Check memory & peripheral allowed list */
+};
+
+/* Authenticate Image Loader Callback prototype */
+typedef enum hab_status hab_loader_callback_f_t(void **, size_t *, const void *);
+
+/*
+ * HAB Rom VectorTable (RVT) structure.
+ * This table provides function pointers into the HAB library in ROM for
+ * use by post-ROM boot sequence components.
+ * Functions are ordered in the structure below based on the offsets in ROM
+ * image, and shall not be changed!
+ * Details on API allocation offsets and function description could be
+ * found in following documents from NXP:
+ * - High Assurance Boot Version 4 Application Programming Interface
+ * Reference Manual (available in CST package)
+ * - HABv4 RVT Guidelines and Recommendations (AN12263)
+ */
+struct hab_rvt_api {
+ uint64_t hdr;
+ enum hab_status (*entry)(void);
+ enum hab_status (*exit)(void);
+ enum hab_status (*check_target)(enum hab_target type, const void *start, size_t bytes);
+ void* (*authenticate_image)(uint8_t cid, long ivt_offset, void **start,
+ size_t *bytes, hab_loader_callback_f_t loader);
+ enum hab_status (*run_dcd)(const uint8_t *dcd);
+ enum hab_status (*run_csf)(const uint8_t *csf, uint8_t cid, uint32_t srkmask);
+ enum hab_status (*assert)(long type, const void *data, uint32_t count);
+ enum hab_status (*report_event)(enum hab_status status, uint32_t index,
+ uint8_t *event, size_t *bytes);
+ enum hab_status (*report_status)(enum hab_config *config, enum hab_state *state);
+ void (*failsafe)(void);
+ void* (*authenticate_image_no_dcd)(uint8_t cid, long ivt_offset, void **start,
+ size_t *bytes, hab_loader_callback_f_t loader);
+ uint32_t (*get_version)(void);
+ enum hab_status (*authenticate_container)(uint8_t cid, long ivt_offset, void **start,
+ size_t *bytes, hab_loader_callback_f_t loader, uint32_t srkmask, int skip_dcd);
+};
+
+struct hab_rvt_api *g_hab_rvt_api = (struct hab_rvt_api *)HAB_RVT_BASE;
+
+/*******************************************************************************
+ * Handler for servicing HAB SMC calls
+ ******************************************************************************/
+int imx_hab_handler(uint32_t smc_fid,
+ u_register_t x1,
+ u_register_t x2,
+ u_register_t x3,
+ u_register_t x4)
+{
+ switch (x1) {
+ case IMX_SIP_HAB_ENTRY:
+ return g_hab_rvt_api->entry();
+ case IMX_SIP_HAB_EXIT:
+ return g_hab_rvt_api->exit();
+ case IMX_SIP_HAB_CHECK_TARGET:
+ return g_hab_rvt_api->check_target((enum hab_target)x2,
+ (const void *)x3, (size_t)x4);
+ case IMX_SIP_HAB_AUTH_IMG:
+ return (unsigned long)g_hab_rvt_api->authenticate_image(HAB_CID_ATF,
+ x2, (void **)x3, (size_t *)x4, NULL);
+ case IMX_SIP_HAB_REPORT_EVENT:
+ return g_hab_rvt_api->report_event(HAB_FAILURE,
+ (uint32_t)x2, (uint8_t *)x3, (size_t *)x4);
+ case IMX_SIP_HAB_REPORT_STATUS:
+ return g_hab_rvt_api->report_status((enum hab_config *)x2,
+ (enum hab_state *)x3);
+ case IMX_SIP_HAB_FAILSAFE:
+ g_hab_rvt_api->failsafe();
+ break;
+ case IMX_SIP_HAB_AUTH_IMG_NO_DCD:
+ return (unsigned long)g_hab_rvt_api->authenticate_image_no_dcd(
+ HAB_CID_ATF, x2, (void **)x3, (size_t *)x4, NULL);
+ case IMX_SIP_HAB_GET_VERSION:
+ return g_hab_rvt_api->get_version();
+ default:
+ return SMC_UNK;
+ };
+
+ return SMC_OK;
+}
diff --git a/plat/imx/imx8m/imx_rdc.c b/plat/imx/imx8m/imx_rdc.c
new file mode 100644
index 0000000..85de191
--- /dev/null
+++ b/plat/imx/imx8m/imx_rdc.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019, NXP. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include <imx_rdc.h>
+
+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++;
+ }
+}
diff --git a/plat/imx/imx8m/include/ddrc.h b/plat/imx/imx8m/include/ddrc.h
new file mode 100644
index 0000000..55af3ff
--- /dev/null
+++ b/plat/imx/imx8m/include/ddrc.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2019-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_DDRC_H
+#define IMX_DDRC_H
+
+#define DDRC_IPS_BASE_ADDR(X) (0x3d400000 + ((X) * 0x2000000))
+#define DDRC_DDR_SS_GPR0 0x3d000000
+
+/* DWC ddr umctl2 REGs offset*/
+/**********************/
+#define DDRC_MSTR(X) (DDRC_IPS_BASE_ADDR(X) + 0x00)
+#define DDRC_STAT(X) (DDRC_IPS_BASE_ADDR(X) + 0x04)
+#define DDRC_MSTR1(X) (DDRC_IPS_BASE_ADDR(X) + 0x08)
+#define DDRC_MRCTRL0(X) (DDRC_IPS_BASE_ADDR(X) + 0x10)
+#define DDRC_MRCTRL1(X) (DDRC_IPS_BASE_ADDR(X) + 0x14)
+#define DDRC_MRSTAT(X) (DDRC_IPS_BASE_ADDR(X) + 0x18)
+#define DDRC_MRCTRL2(X) (DDRC_IPS_BASE_ADDR(X) + 0x1c)
+#define DDRC_DERATEEN(X) (DDRC_IPS_BASE_ADDR(X) + 0x20)
+#define DDRC_DERATEINT(X) (DDRC_IPS_BASE_ADDR(X) + 0x24)
+#define DDRC_MSTR2(X) (DDRC_IPS_BASE_ADDR(X) + 0x28)
+#define DDRC_PWRCTL(X) (DDRC_IPS_BASE_ADDR(X) + 0x30)
+#define DDRC_PWRTMG(X) (DDRC_IPS_BASE_ADDR(X) + 0x34)
+#define DDRC_HWLPCTL(X) (DDRC_IPS_BASE_ADDR(X) + 0x38)
+#define DDRC_HWFFCCTL(X) (DDRC_IPS_BASE_ADDR(X) + 0x3c)
+#define DDRC_HWFFCSTAT(X) (DDRC_IPS_BASE_ADDR(X) + 0x40)
+#define DDRC_RFSHCTL0(X) (DDRC_IPS_BASE_ADDR(X) + 0x50)
+#define DDRC_RFSHCTL1(X) (DDRC_IPS_BASE_ADDR(X) + 0x54)
+#define DDRC_RFSHCTL2(X) (DDRC_IPS_BASE_ADDR(X) + 0x58)
+#define DDRC_RFSHCTL3(X) (DDRC_IPS_BASE_ADDR(X) + 0x60)
+#define DDRC_RFSHTMG(X) (DDRC_IPS_BASE_ADDR(X) + 0x64)
+#define DDRC_ECCCFG0(X) (DDRC_IPS_BASE_ADDR(X) + 0x70)
+#define DDRC_ECCCFG1(X) (DDRC_IPS_BASE_ADDR(X) + 0x74)
+#define DDRC_ECCSTAT(X) (DDRC_IPS_BASE_ADDR(X) + 0x78)
+#define DDRC_ECCCLR(X) (DDRC_IPS_BASE_ADDR(X) + 0x7c)
+#define DDRC_ECCERRCNT(X) (DDRC_IPS_BASE_ADDR(X) + 0x80)
+#define DDRC_ECCCADDR0(X) (DDRC_IPS_BASE_ADDR(X) + 0x84)
+#define DDRC_ECCCADDR1(X) (DDRC_IPS_BASE_ADDR(X) + 0x88)
+#define DDRC_ECCCSYN0(X) (DDRC_IPS_BASE_ADDR(X) + 0x8c)
+#define DDRC_ECCCSYN1(X) (DDRC_IPS_BASE_ADDR(X) + 0x90)
+#define DDRC_ECCCSYN2(X) (DDRC_IPS_BASE_ADDR(X) + 0x94)
+#define DDRC_ECCBITMASK0(X) (DDRC_IPS_BASE_ADDR(X) + 0x98)
+#define DDRC_ECCBITMASK1(X) (DDRC_IPS_BASE_ADDR(X) + 0x9c)
+#define DDRC_ECCBITMASK2(X) (DDRC_IPS_BASE_ADDR(X) + 0xa0)
+#define DDRC_ECCUADDR0(X) (DDRC_IPS_BASE_ADDR(X) + 0xa4)
+#define DDRC_ECCUADDR1(X) (DDRC_IPS_BASE_ADDR(X) + 0xa8)
+#define DDRC_ECCUSYN0(X) (DDRC_IPS_BASE_ADDR(X) + 0xac)
+#define DDRC_ECCUSYN1(X) (DDRC_IPS_BASE_ADDR(X) + 0xb0)
+#define DDRC_ECCUSYN2(X) (DDRC_IPS_BASE_ADDR(X) + 0xb4)
+#define DDRC_ECCPOISONADDR0(X) (DDRC_IPS_BASE_ADDR(X) + 0xb8)
+#define DDRC_ECCPOISONADDR1(X) (DDRC_IPS_BASE_ADDR(X) + 0xbc)
+#define DDRC_CRCPARCTL0(X) (DDRC_IPS_BASE_ADDR(X) + 0xc0)
+#define DDRC_CRCPARCTL1(X) (DDRC_IPS_BASE_ADDR(X) + 0xc4)
+#define DDRC_CRCPARCTL2(X) (DDRC_IPS_BASE_ADDR(X) + 0xc8)
+#define DDRC_CRCPARSTAT(X) (DDRC_IPS_BASE_ADDR(X) + 0xcc)
+#define DDRC_INIT0(X) (DDRC_IPS_BASE_ADDR(X) + 0xd0)
+#define DDRC_INIT1(X) (DDRC_IPS_BASE_ADDR(X) + 0xd4)
+#define DDRC_INIT2(X) (DDRC_IPS_BASE_ADDR(X) + 0xd8)
+#define DDRC_INIT3(X) (DDRC_IPS_BASE_ADDR(X) + 0xdc)
+#define DDRC_INIT4(X) (DDRC_IPS_BASE_ADDR(X) + 0xe0)
+#define DDRC_INIT5(X) (DDRC_IPS_BASE_ADDR(X) + 0xe4)
+#define DDRC_INIT6(X) (DDRC_IPS_BASE_ADDR(X) + 0xe8)
+#define DDRC_INIT7(X) (DDRC_IPS_BASE_ADDR(X) + 0xec)
+#define DDRC_DIMMCTL(X) (DDRC_IPS_BASE_ADDR(X) + 0xf0)
+#define DDRC_RANKCTL(X) (DDRC_IPS_BASE_ADDR(X) + 0xf4)
+#define DDRC_DRAMTMG0(X) (DDRC_IPS_BASE_ADDR(X) + 0x100)
+#define DDRC_DRAMTMG1(X) (DDRC_IPS_BASE_ADDR(X) + 0x104)
+#define DDRC_DRAMTMG2(X) (DDRC_IPS_BASE_ADDR(X) + 0x108)
+#define DDRC_DRAMTMG3(X) (DDRC_IPS_BASE_ADDR(X) + 0x10c)
+#define DDRC_DRAMTMG4(X) (DDRC_IPS_BASE_ADDR(X) + 0x110)
+#define DDRC_DRAMTMG5(X) (DDRC_IPS_BASE_ADDR(X) + 0x114)
+#define DDRC_DRAMTMG6(X) (DDRC_IPS_BASE_ADDR(X) + 0x118)
+#define DDRC_DRAMTMG7(X) (DDRC_IPS_BASE_ADDR(X) + 0x11c)
+#define DDRC_DRAMTMG8(X) (DDRC_IPS_BASE_ADDR(X) + 0x120)
+#define DDRC_DRAMTMG9(X) (DDRC_IPS_BASE_ADDR(X) + 0x124)
+#define DDRC_DRAMTMG10(X) (DDRC_IPS_BASE_ADDR(X) + 0x128)
+#define DDRC_DRAMTMG11(X) (DDRC_IPS_BASE_ADDR(X) + 0x12c)
+#define DDRC_DRAMTMG12(X) (DDRC_IPS_BASE_ADDR(X) + 0x130)
+#define DDRC_DRAMTMG13(X) (DDRC_IPS_BASE_ADDR(X) + 0x134)
+#define DDRC_DRAMTMG14(X) (DDRC_IPS_BASE_ADDR(X) + 0x138)
+#define DDRC_DRAMTMG15(X) (DDRC_IPS_BASE_ADDR(X) + 0x13C)
+#define DDRC_DRAMTMG16(X) (DDRC_IPS_BASE_ADDR(X) + 0x140)
+#define DDRC_DRAMTMG17(X) (DDRC_IPS_BASE_ADDR(X) + 0x144)
+
+#define DDRC_ZQCTL0(X) (DDRC_IPS_BASE_ADDR(X) + 0x180)
+#define DDRC_ZQCTL1(X) (DDRC_IPS_BASE_ADDR(X) + 0x184)
+#define DDRC_ZQCTL2(X) (DDRC_IPS_BASE_ADDR(X) + 0x188)
+#define DDRC_ZQSTAT(X) (DDRC_IPS_BASE_ADDR(X) + 0x18c)
+#define DDRC_DFITMG0(X) (DDRC_IPS_BASE_ADDR(X) + 0x190)
+#define DDRC_DFITMG1(X) (DDRC_IPS_BASE_ADDR(X) + 0x194)
+#define DDRC_DFILPCFG0(X) (DDRC_IPS_BASE_ADDR(X) + 0x198)
+#define DDRC_DFILPCFG1(X) (DDRC_IPS_BASE_ADDR(X) + 0x19c)
+#define DDRC_DFIUPD0(X) (DDRC_IPS_BASE_ADDR(X) + 0x1a0)
+#define DDRC_DFIUPD1(X) (DDRC_IPS_BASE_ADDR(X) + 0x1a4)
+#define DDRC_DFIUPD2(X) (DDRC_IPS_BASE_ADDR(X) + 0x1a8)
+#define DDRC_DFIMISC(X) (DDRC_IPS_BASE_ADDR(X) + 0x1b0)
+#define DDRC_DFITMG2(X) (DDRC_IPS_BASE_ADDR(X) + 0x1b4)
+#define DDRC_DFITMG3(X) (DDRC_IPS_BASE_ADDR(X) + 0x1b8)
+#define DDRC_DFISTAT(X) (DDRC_IPS_BASE_ADDR(X) + 0x1bc)
+
+#define DDRC_DBICTL(X) (DDRC_IPS_BASE_ADDR(X) + 0x1c0)
+#define DDRC_DFIPHYMSTR(X) (DDRC_IPS_BASE_ADDR(X) + 0x1c4)
+#define DDRC_TRAINCTL0(X) (DDRC_IPS_BASE_ADDR(X) + 0x1d0)
+#define DDRC_TRAINCTL1(X) (DDRC_IPS_BASE_ADDR(X) + 0x1d4)
+#define DDRC_TRAINCTL2(X) (DDRC_IPS_BASE_ADDR(X) + 0x1d8)
+#define DDRC_TRAINSTAT(X) (DDRC_IPS_BASE_ADDR(X) + 0x1dc)
+#define DDRC_ADDRMAP0(X) (DDRC_IPS_BASE_ADDR(X) + 0x200)
+#define DDRC_ADDRMAP1(X) (DDRC_IPS_BASE_ADDR(X) + 0x204)
+#define DDRC_ADDRMAP2(X) (DDRC_IPS_BASE_ADDR(X) + 0x208)
+#define DDRC_ADDRMAP3(X) (DDRC_IPS_BASE_ADDR(X) + 0x20c)
+#define DDRC_ADDRMAP4(X) (DDRC_IPS_BASE_ADDR(X) + 0x210)
+#define DDRC_ADDRMAP5(X) (DDRC_IPS_BASE_ADDR(X) + 0x214)
+#define DDRC_ADDRMAP6(X) (DDRC_IPS_BASE_ADDR(X) + 0x218)
+#define DDRC_ADDRMAP7(X) (DDRC_IPS_BASE_ADDR(X) + 0x21c)
+#define DDRC_ADDRMAP8(X) (DDRC_IPS_BASE_ADDR(X) + 0x220)
+#define DDRC_ADDRMAP9(X) (DDRC_IPS_BASE_ADDR(X) + 0x224)
+#define DDRC_ADDRMAP10(X) (DDRC_IPS_BASE_ADDR(X) + 0x228)
+#define DDRC_ADDRMAP11(X) (DDRC_IPS_BASE_ADDR(X) + 0x22c)
+
+#define DDRC_ODTCFG(X) (DDRC_IPS_BASE_ADDR(X) + 0x240)
+#define DDRC_ODTMAP(X) (DDRC_IPS_BASE_ADDR(X) + 0x244)
+#define DDRC_SCHED(X) (DDRC_IPS_BASE_ADDR(X) + 0x250)
+#define DDRC_SCHED1(X) (DDRC_IPS_BASE_ADDR(X) + 0x254)
+#define DDRC_PERFHPR1(X) (DDRC_IPS_BASE_ADDR(X) + 0x25c)
+#define DDRC_PERFLPR1(X) (DDRC_IPS_BASE_ADDR(X) + 0x264)
+#define DDRC_PERFWR1(X) (DDRC_IPS_BASE_ADDR(X) + 0x26c)
+#define DDRC_PERFVPR1(X) (DDRC_IPS_BASE_ADDR(X) + 0x274)
+
+#define DDRC_PERFVPW1(X) (DDRC_IPS_BASE_ADDR(X) + 0x278)
+
+#define DDRC_DQMAP0(X) (DDRC_IPS_BASE_ADDR(X) + 0x280)
+#define DDRC_DQMAP1(X) (DDRC_IPS_BASE_ADDR(X) + 0x284)
+#define DDRC_DQMAP2(X) (DDRC_IPS_BASE_ADDR(X) + 0x288)
+#define DDRC_DQMAP3(X) (DDRC_IPS_BASE_ADDR(X) + 0x28c)
+#define DDRC_DQMAP4(X) (DDRC_IPS_BASE_ADDR(X) + 0x290)
+#define DDRC_DQMAP5(X) (DDRC_IPS_BASE_ADDR(X) + 0x294)
+#define DDRC_DBG0(X) (DDRC_IPS_BASE_ADDR(X) + 0x300)
+#define DDRC_DBG1(X) (DDRC_IPS_BASE_ADDR(X) + 0x304)
+#define DDRC_DBGCAM(X) (DDRC_IPS_BASE_ADDR(X) + 0x308)
+#define DDRC_DBGCMD(X) (DDRC_IPS_BASE_ADDR(X) + 0x30c)
+#define DDRC_DBGSTAT(X) (DDRC_IPS_BASE_ADDR(X) + 0x310)
+
+#define DDRC_SWCTL(X) (DDRC_IPS_BASE_ADDR(X) + 0x320)
+#define DDRC_SWSTAT(X) (DDRC_IPS_BASE_ADDR(X) + 0x324)
+#define DDRC_OCPARCFG0(X) (DDRC_IPS_BASE_ADDR(X) + 0x330)
+#define DDRC_OCPARCFG1(X) (DDRC_IPS_BASE_ADDR(X) + 0x334)
+#define DDRC_OCPARCFG2(X) (DDRC_IPS_BASE_ADDR(X) + 0x338)
+#define DDRC_OCPARCFG3(X) (DDRC_IPS_BASE_ADDR(X) + 0x33c)
+#define DDRC_OCPARSTAT0(X) (DDRC_IPS_BASE_ADDR(X) + 0x340)
+#define DDRC_OCPARSTAT1(X) (DDRC_IPS_BASE_ADDR(X) + 0x344)
+#define DDRC_OCPARWLOG0(X) (DDRC_IPS_BASE_ADDR(X) + 0x348)
+#define DDRC_OCPARWLOG1(X) (DDRC_IPS_BASE_ADDR(X) + 0x34c)
+#define DDRC_OCPARWLOG2(X) (DDRC_IPS_BASE_ADDR(X) + 0x350)
+#define DDRC_OCPARAWLOG0(X) (DDRC_IPS_BASE_ADDR(X) + 0x354)
+#define DDRC_OCPARAWLOG1(X) (DDRC_IPS_BASE_ADDR(X) + 0x358)
+#define DDRC_OCPARRLOG0(X) (DDRC_IPS_BASE_ADDR(X) + 0x35c)
+#define DDRC_OCPARRLOG1(X) (DDRC_IPS_BASE_ADDR(X) + 0x360)
+#define DDRC_OCPARARLOG0(X) (DDRC_IPS_BASE_ADDR(X) + 0x364)
+#define DDRC_OCPARARLOG1(X) (DDRC_IPS_BASE_ADDR(X) + 0x368)
+#define DDRC_POISONCFG(X) (DDRC_IPS_BASE_ADDR(X) + 0x36C)
+#define DDRC_POISONSTAT(X) (DDRC_IPS_BASE_ADDR(X) + 0x370)
+#define DDRC_ADVECCINDEX(X) (DDRC_IPS_BASE_ADDR(X) + 0x3)
+#define DDRC_ADVECCSTAT(X) (DDRC_IPS_BASE_ADDR(X) + 0x3)
+#define DDRC_ECCPOISONPAT0(X) (DDRC_IPS_BASE_ADDR(X) + 0x3)
+#define DDRC_ECCPOISONPAT1(X) (DDRC_IPS_BASE_ADDR(X) + 0x3)
+#define DDRC_ECCPOISONPAT2(X) (DDRC_IPS_BASE_ADDR(X) + 0x3)
+#define DDRC_HIFCTL(X) (DDRC_IPS_BASE_ADDR(X) + 0x3)
+
+#define DDRC_PSTAT(X) (DDRC_IPS_BASE_ADDR(X) + 0x3fc)
+#define DDRC_PCCFG(X) (DDRC_IPS_BASE_ADDR(X) + 0x400)
+#define DDRC_PCFGR_0(X) (DDRC_IPS_BASE_ADDR(X) + 0x404)
+#define DDRC_PCFGR_1(X) (DDRC_IPS_BASE_ADDR(X) + 1 * 0xb0 + 0x404)
+#define DDRC_PCFGR_2(X) (DDRC_IPS_BASE_ADDR(X) + 2 * 0xb0 + 0x404)
+#define DDRC_PCFGR_3(X) (DDRC_IPS_BASE_ADDR(X) + 3 * 0xb0 + 0x404)
+#define DDRC_PCFGW_0(X) (DDRC_IPS_BASE_ADDR(X) + 0x408)
+#define DDRC_PCFGW_1(X) (DDRC_IPS_BASE_ADDR(X) + 1 * 0xb0 + 0x408)
+#define DDRC_PCFGW_2(X) (DDRC_IPS_BASE_ADDR(X) + 2 * 0xb0 + 0x408)
+#define DDRC_PCFGW_3(X) (DDRC_IPS_BASE_ADDR(X) + 3 * 0xb0 + 0x408)
+#define DDRC_PCFGC_0(X) (DDRC_IPS_BASE_ADDR(X) + 0x40c)
+#define DDRC_PCFGIDMASKCH(X) (DDRC_IPS_BASE_ADDR(X) + 0x410)
+#define DDRC_PCFGIDVALUECH(X) (DDRC_IPS_BASE_ADDR(X) + 0x414)
+#define DDRC_PCTRL_0(X) (DDRC_IPS_BASE_ADDR(X) + 0x490)
+#define DDRC_PCTRL_1(X) (DDRC_IPS_BASE_ADDR(X) + 0x490 + 1 * 0xb0)
+#define DDRC_PCTRL_2(X) (DDRC_IPS_BASE_ADDR(X) + 0x490 + 2 * 0xb0)
+#define DDRC_PCTRL_3(X) (DDRC_IPS_BASE_ADDR(X) + 0x490 + 3 * 0xb0)
+#define DDRC_PCFGQOS0_0(X) (DDRC_IPS_BASE_ADDR(X) + 0x494)
+#define DDRC_PCFGQOS1_0(X) (DDRC_IPS_BASE_ADDR(X) + 0x498)
+#define DDRC_PCFGWQOS0_0(X) (DDRC_IPS_BASE_ADDR(X) + 0x49c)
+#define DDRC_PCFGWQOS1_0(X) (DDRC_IPS_BASE_ADDR(X) + 0x4a0)
+#define DDRC_SARBASE0(X) (DDRC_IPS_BASE_ADDR(X) + 0xf04)
+#define DDRC_SARSIZE0(X) (DDRC_IPS_BASE_ADDR(X) + 0xf08)
+#define DDRC_SBRCTL(X) (DDRC_IPS_BASE_ADDR(X) + 0xf24)
+#define DDRC_SBRSTAT(X) (DDRC_IPS_BASE_ADDR(X) + 0xf28)
+#define DDRC_SBRWDATA0(X) (DDRC_IPS_BASE_ADDR(X) + 0xf2c)
+#define DDRC_SBRWDATA1(X) (DDRC_IPS_BASE_ADDR(X) + 0xf30)
+#define DDRC_PDCH(X) (DDRC_IPS_BASE_ADDR(X) + 0xf34)
+
+/* SHADOW registers */
+#define DDRC_FREQ1_DERATEEN(X) (DDRC_IPS_BASE_ADDR(X) + 0x2020)
+#define DDRC_FREQ1_DERATEINT(X) (DDRC_IPS_BASE_ADDR(X) + 0x2024)
+#define DDRC_FREQ1_RFSHCTL0(X) (DDRC_IPS_BASE_ADDR(X) + 0x2050)
+#define DDRC_FREQ1_RFSHTMG(X) (DDRC_IPS_BASE_ADDR(X) + 0x2064)
+#define DDRC_FREQ1_INIT3(X) (DDRC_IPS_BASE_ADDR(X) + 0x20dc)
+#define DDRC_FREQ1_INIT4(X) (DDRC_IPS_BASE_ADDR(X) + 0x20e0)
+#define DDRC_FREQ1_INIT6(X) (DDRC_IPS_BASE_ADDR(X) + 0x20e8)
+#define DDRC_FREQ1_INIT7(X) (DDRC_IPS_BASE_ADDR(X) + 0x20ec)
+#define DDRC_FREQ1_DRAMTMG0(X) (DDRC_IPS_BASE_ADDR(X) + 0x2100)
+#define DDRC_FREQ1_DRAMTMG1(X) (DDRC_IPS_BASE_ADDR(X) + 0x2104)
+#define DDRC_FREQ1_DRAMTMG2(X) (DDRC_IPS_BASE_ADDR(X) + 0x2108)
+#define DDRC_FREQ1_DRAMTMG3(X) (DDRC_IPS_BASE_ADDR(X) + 0x210c)
+#define DDRC_FREQ1_DRAMTMG4(X) (DDRC_IPS_BASE_ADDR(X) + 0x2110)
+#define DDRC_FREQ1_DRAMTMG5(X) (DDRC_IPS_BASE_ADDR(X) + 0x2114)
+#define DDRC_FREQ1_DRAMTMG6(X) (DDRC_IPS_BASE_ADDR(X) + 0x2118)
+#define DDRC_FREQ1_DRAMTMG7(X) (DDRC_IPS_BASE_ADDR(X) + 0x211c)
+#define DDRC_FREQ1_DRAMTMG8(X) (DDRC_IPS_BASE_ADDR(X) + 0x2120)
+#define DDRC_FREQ1_DRAMTMG9(X) (DDRC_IPS_BASE_ADDR(X) + 0x2124)
+#define DDRC_FREQ1_DRAMTMG10(X) (DDRC_IPS_BASE_ADDR(X) + 0x2128)
+#define DDRC_FREQ1_DRAMTMG11(X) (DDRC_IPS_BASE_ADDR(X) + 0x212c)
+#define DDRC_FREQ1_DRAMTMG12(X) (DDRC_IPS_BASE_ADDR(X) + 0x2130)
+#define DDRC_FREQ1_DRAMTMG13(X) (DDRC_IPS_BASE_ADDR(X) + 0x2134)
+#define DDRC_FREQ1_DRAMTMG14(X) (DDRC_IPS_BASE_ADDR(X) + 0x2138)
+#define DDRC_FREQ1_DRAMTMG15(X) (DDRC_IPS_BASE_ADDR(X) + 0x213C)
+#define DDRC_FREQ1_DRAMTMG16(X) (DDRC_IPS_BASE_ADDR(X) + 0x2140)
+#define DDRC_FREQ1_DRAMTMG17(X) (DDRC_IPS_BASE_ADDR(X) + 0x2144)
+#define DDRC_FREQ1_ZQCTL0(X) (DDRC_IPS_BASE_ADDR(X) + 0x2180)
+#define DDRC_FREQ1_DFITMG0(X) (DDRC_IPS_BASE_ADDR(X) + 0x2190)
+#define DDRC_FREQ1_DFITMG1(X) (DDRC_IPS_BASE_ADDR(X) + 0x2194)
+#define DDRC_FREQ1_DFITMG2(X) (DDRC_IPS_BASE_ADDR(X) + 0x21b4)
+#define DDRC_FREQ1_DFITMG3(X) (DDRC_IPS_BASE_ADDR(X) + 0x21b8)
+#define DDRC_FREQ1_ODTCFG(X) (DDRC_IPS_BASE_ADDR(X) + 0x2240)
+
+#define DDRC_FREQ2_DERATEEN(X) (DDRC_IPS_BASE_ADDR(X) + 0x3020)
+#define DDRC_FREQ2_DERATEINT(X) (DDRC_IPS_BASE_ADDR(X) + 0x3024)
+#define DDRC_FREQ2_RFSHCTL0(X) (DDRC_IPS_BASE_ADDR(X) + 0x3050)
+#define DDRC_FREQ2_RFSHTMG(X) (DDRC_IPS_BASE_ADDR(X) + 0x3064)
+#define DDRC_FREQ2_INIT3(X) (DDRC_IPS_BASE_ADDR(X) + 0x30dc)
+#define DDRC_FREQ2_INIT4(X) (DDRC_IPS_BASE_ADDR(X) + 0x30e0)
+#define DDRC_FREQ2_INIT6(X) (DDRC_IPS_BASE_ADDR(X) + 0x30e8)
+#define DDRC_FREQ2_INIT7(X) (DDRC_IPS_BASE_ADDR(X) + 0x30ec)
+#define DDRC_FREQ2_DRAMTMG0(X) (DDRC_IPS_BASE_ADDR(X) + 0x3100)
+#define DDRC_FREQ2_DRAMTMG1(X) (DDRC_IPS_BASE_ADDR(X) + 0x3104)
+#define DDRC_FREQ2_DRAMTMG2(X) (DDRC_IPS_BASE_ADDR(X) + 0x3108)
+#define DDRC_FREQ2_DRAMTMG3(X) (DDRC_IPS_BASE_ADDR(X) + 0x310c)
+#define DDRC_FREQ2_DRAMTMG4(X) (DDRC_IPS_BASE_ADDR(X) + 0x3110)
+#define DDRC_FREQ2_DRAMTMG5(X) (DDRC_IPS_BASE_ADDR(X) + 0x3114)
+#define DDRC_FREQ2_DRAMTMG6(X) (DDRC_IPS_BASE_ADDR(X) + 0x3118)
+#define DDRC_FREQ2_DRAMTMG7(X) (DDRC_IPS_BASE_ADDR(X) + 0x311c)
+#define DDRC_FREQ2_DRAMTMG8(X) (DDRC_IPS_BASE_ADDR(X) + 0x3120)
+#define DDRC_FREQ2_DRAMTMG9(X) (DDRC_IPS_BASE_ADDR(X) + 0x3124)
+#define DDRC_FREQ2_DRAMTMG10(X) (DDRC_IPS_BASE_ADDR(X) + 0x3128)
+#define DDRC_FREQ2_DRAMTMG11(X) (DDRC_IPS_BASE_ADDR(X) + 0x312c)
+#define DDRC_FREQ2_DRAMTMG12(X) (DDRC_IPS_BASE_ADDR(X) + 0x3130)
+#define DDRC_FREQ2_DRAMTMG13(X) (DDRC_IPS_BASE_ADDR(X) + 0x3134)
+#define DDRC_FREQ2_DRAMTMG14(X) (DDRC_IPS_BASE_ADDR(X) + 0x3138)
+#define DDRC_FREQ2_DRAMTMG15(X) (DDRC_IPS_BASE_ADDR(X) + 0x313C)
+#define DDRC_FREQ2_DRAMTMG16(X) (DDRC_IPS_BASE_ADDR(X) + 0x3140)
+#define DDRC_FREQ2_DRAMTMG17(X) (DDRC_IPS_BASE_ADDR(X) + 0x3144)
+#define DDRC_FREQ2_ZQCTL0(X) (DDRC_IPS_BASE_ADDR(X) + 0x3180)
+#define DDRC_FREQ2_DFITMG0(X) (DDRC_IPS_BASE_ADDR(X) + 0x3190)
+#define DDRC_FREQ2_DFITMG1(X) (DDRC_IPS_BASE_ADDR(X) + 0x3194)
+#define DDRC_FREQ2_DFITMG2(X) (DDRC_IPS_BASE_ADDR(X) + 0x31b4)
+#define DDRC_FREQ2_DFITMG3(X) (DDRC_IPS_BASE_ADDR(X) + 0x31b8)
+#define DDRC_FREQ2_ODTCFG(X) (DDRC_IPS_BASE_ADDR(X) + 0x3240)
+
+#define DDRC_FREQ3_DERATEEN(X) (DDRC_IPS_BASE_ADDR(X) + 0x4020)
+#define DDRC_FREQ3_DERATEINT(X) (DDRC_IPS_BASE_ADDR(X) + 0x4024)
+#define DDRC_FREQ3_RFSHCTL0(X) (DDRC_IPS_BASE_ADDR(X) + 0x4050)
+#define DDRC_FREQ3_RFSHTMG(X) (DDRC_IPS_BASE_ADDR(X) + 0x4064)
+#define DDRC_FREQ3_INIT3(X) (DDRC_IPS_BASE_ADDR(X) + 0x40dc)
+#define DDRC_FREQ3_INIT4(X) (DDRC_IPS_BASE_ADDR(X) + 0x40e0)
+#define DDRC_FREQ3_INIT6(X) (DDRC_IPS_BASE_ADDR(X) + 0x40e8)
+#define DDRC_FREQ3_INIT7(X) (DDRC_IPS_BASE_ADDR(X) + 0x40ec)
+#define DDRC_FREQ3_DRAMTMG0(X) (DDRC_IPS_BASE_ADDR(X) + 0x4100)
+#define DDRC_FREQ3_DRAMTMG1(X) (DDRC_IPS_BASE_ADDR(X) + 0x4104)
+#define DDRC_FREQ3_DRAMTMG2(X) (DDRC_IPS_BASE_ADDR(X) + 0x4108)
+#define DDRC_FREQ3_DRAMTMG3(X) (DDRC_IPS_BASE_ADDR(X) + 0x410c)
+#define DDRC_FREQ3_DRAMTMG4(X) (DDRC_IPS_BASE_ADDR(X) + 0x4110)
+#define DDRC_FREQ3_DRAMTMG5(X) (DDRC_IPS_BASE_ADDR(X) + 0x4114)
+#define DDRC_FREQ3_DRAMTMG6(X) (DDRC_IPS_BASE_ADDR(X) + 0x4118)
+#define DDRC_FREQ3_DRAMTMG7(X) (DDRC_IPS_BASE_ADDR(X) + 0x411c)
+#define DDRC_FREQ3_DRAMTMG8(X) (DDRC_IPS_BASE_ADDR(X) + 0x4120)
+#define DDRC_FREQ3_DRAMTMG9(X) (DDRC_IPS_BASE_ADDR(X) + 0x4124)
+#define DDRC_FREQ3_DRAMTMG10(X) (DDRC_IPS_BASE_ADDR(X) + 0x4128)
+#define DDRC_FREQ3_DRAMTMG11(X) (DDRC_IPS_BASE_ADDR(X) + 0x412c)
+#define DDRC_FREQ3_DRAMTMG12(X) (DDRC_IPS_BASE_ADDR(X) + 0x4130)
+#define DDRC_FREQ3_DRAMTMG13(X) (DDRC_IPS_BASE_ADDR(X) + 0x4134)
+#define DDRC_FREQ3_DRAMTMG14(X) (DDRC_IPS_BASE_ADDR(X) + 0x4138)
+#define DDRC_FREQ3_DRAMTMG15(X) (DDRC_IPS_BASE_ADDR(X) + 0x413C)
+#define DDRC_FREQ3_DRAMTMG16(X) (DDRC_IPS_BASE_ADDR(X) + 0x4140)
+
+#define DDRC_FREQ3_ZQCTL0(X) (DDRC_IPS_BASE_ADDR(X) + 0x4180)
+#define DDRC_FREQ3_DFITMG0(X) (DDRC_IPS_BASE_ADDR(X) + 0x4190)
+#define DDRC_FREQ3_DFITMG1(X) (DDRC_IPS_BASE_ADDR(X) + 0x4194)
+#define DDRC_FREQ3_DFITMG2(X) (DDRC_IPS_BASE_ADDR(X) + 0x41b4)
+#define DDRC_FREQ3_DFITMG3(X) (DDRC_IPS_BASE_ADDR(X) + 0x41b8)
+#define DDRC_FREQ3_ODTCFG(X) (DDRC_IPS_BASE_ADDR(X) + 0x4240)
+#define DDRC_DFITMG0_SHADOW(X) (DDRC_IPS_BASE_ADDR(X) + 0x2190)
+#define DDRC_DFITMG1_SHADOW(X) (DDRC_IPS_BASE_ADDR(X) + 0x2194)
+#define DDRC_DFITMG2_SHADOW(X) (DDRC_IPS_BASE_ADDR(X) + 0x21b4)
+#define DDRC_DFITMG3_SHADOW(X) (DDRC_IPS_BASE_ADDR(X) + 0x21b8)
+#define DDRC_ODTCFG_SHADOW(X) (DDRC_IPS_BASE_ADDR(X) + 0x2240)
+
+#define DRC_PERF_MON_BASE_ADDR(X) (0x3d800000 + ((X) * 0x2000000))
+#define DRC_PERF_MON_CNT0_CTL(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x0)
+#define DRC_PERF_MON_CNT1_CTL(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x4)
+#define DRC_PERF_MON_CNT2_CTL(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x8)
+#define DRC_PERF_MON_CNT3_CTL(X) (DRC_PERF_MON_BASE_ADDR(X) + 0xC)
+#define DRC_PERF_MON_CNT0_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x20)
+#define DRC_PERF_MON_CNT1_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x24)
+#define DRC_PERF_MON_CNT2_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x28)
+#define DRC_PERF_MON_CNT3_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x2C)
+#define DRC_PERF_MON_DPCR_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x30)
+#define DRC_PERF_MON_MRR0_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x40)
+#define DRC_PERF_MON_MRR1_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x44)
+#define DRC_PERF_MON_MRR2_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x48)
+#define DRC_PERF_MON_MRR3_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x4C)
+#define DRC_PERF_MON_MRR4_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x50)
+#define DRC_PERF_MON_MRR5_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x54)
+#define DRC_PERF_MON_MRR6_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x58)
+#define DRC_PERF_MON_MRR7_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x5C)
+#define DRC_PERF_MON_MRR8_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x60)
+#define DRC_PERF_MON_MRR9_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x64)
+#define DRC_PERF_MON_MRR10_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x68)
+#define DRC_PERF_MON_MRR11_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x6C)
+#define DRC_PERF_MON_MRR12_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x70)
+#define DRC_PERF_MON_MRR13_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x74)
+#define DRC_PERF_MON_MRR14_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x78)
+#define DRC_PERF_MON_MRR15_DAT(X) (DRC_PERF_MON_BASE_ADDR(X) + 0x7C)
+
+#define dwc_ddrphy_apb_rd(addr) mmio_read_32(IMX_DDRPHY_BASE + 4 * (addr))
+#define dwc_ddrphy_apb_wr(addr, val) mmio_write_32(IMX_DDRPHY_BASE + 4 * (addr), val)
+
+#endif /*IMX_DDRC_H */
diff --git a/plat/imx/imx8m/include/dram.h b/plat/imx/imx8m/include/dram.h
new file mode 100644
index 0000000..ad11a27
--- /dev/null
+++ b/plat/imx/imx8m/include/dram.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2019-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRAM_H
+#define DRAM_H
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <lib/utils_def.h>
+
+#include <ddrc.h>
+#include <platform_def.h>
+
+#define DDRC_LPDDR4 BIT(5)
+#define DDRC_DDR4 BIT(4)
+#define DDRC_DDR3L BIT(0)
+#define DDR_TYPE_MASK U(0x3f)
+#define ACTIVE_RANK_MASK U(0x3)
+
+/* reg & config param */
+struct dram_cfg_param {
+ unsigned int reg;
+ unsigned int val;
+};
+
+struct dram_timing_info {
+ /* umctl2 config */
+ struct dram_cfg_param *ddrc_cfg;
+ unsigned int ddrc_cfg_num;
+ /* ddrphy config */
+ struct dram_cfg_param *ddrphy_cfg;
+ unsigned int ddrphy_cfg_num;
+ /* ddr fsp train info */
+ struct dram_fsp_msg *fsp_msg;
+ unsigned int fsp_msg_num;
+ /* ddr phy trained CSR */
+ struct dram_cfg_param *ddrphy_trained_csr;
+ unsigned int ddrphy_trained_csr_num;
+ /* ddr phy PIE */
+ struct dram_cfg_param *ddrphy_pie;
+ unsigned int ddrphy_pie_num;
+ /* initialized fsp table */
+ unsigned int fsp_table[4];
+};
+
+struct dram_info {
+ int dram_type;
+ unsigned int num_rank;
+ uint32_t num_fsp;
+ int current_fsp;
+ int boot_fsp;
+ bool bypass_mode;
+ struct dram_timing_info *timing_info;
+ /* mr, emr, emr2, emr3, mr11, mr12, mr22, mr14 */
+ uint32_t mr_table[3][8];
+};
+
+extern struct dram_info dram_info;
+
+void dram_info_init(unsigned long dram_timing_base);
+void dram_umctl2_init(struct dram_timing_info *timing);
+void dram_phy_init(struct dram_timing_info *timing);
+
+/* dram retention */
+void dram_enter_retention(void);
+void dram_exit_retention(void);
+
+void dram_clock_switch(unsigned int target_drate, bool bypass_mode);
+
+/* dram frequency change */
+void lpddr4_swffc(struct dram_info *info, unsigned int init_fsp, unsigned int fsp_index);
+void ddr4_swffc(struct dram_info *dram_info, unsigned int pstate);
+
+#endif /* DRAM_H */
diff --git a/plat/imx/imx8m/include/gpc.h b/plat/imx/imx8m/include/gpc.h
new file mode 100644
index 0000000..a41030e
--- /dev/null
+++ b/plat/imx/imx8m/include/gpc.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX8M_GPC_H
+#define IMX8M_GPC_H
+
+#include <gpc_reg.h>
+
+/* 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 CORE_WKUP_FROM_GIC (IRQ_SRC_C0 | IRQ_SRC_C1 | IRQ_SRC_C2 | IRQ_SRC_C3)
+#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 IMR_MASK_ALL 0xffffffff
+
+#define IMX_PD_DOMAIN(name, on) \
+ { \
+ .pwr_req = name##_PWR_REQ, \
+ .pgc_offset = name##_PGC, \
+ .need_sync = false, \
+ .always_on = (on), \
+ }
+
+#define IMX_MIX_DOMAIN(name, on) \
+ { \
+ .pwr_req = name##_PWR_REQ, \
+ .pgc_offset = name##_PGC, \
+ .adb400_sync = name##_ADB400_SYNC, \
+ .adb400_ack = name##_ADB400_ACK, \
+ .need_sync = true, \
+ .always_on = (on), \
+ }
+
+struct imx_pwr_domain {
+ uint32_t pwr_req;
+ uint32_t adb400_sync;
+ uint32_t adb400_ack;
+ uint32_t pgc_offset;
+ bool need_sync;
+ bool always_on;
+};
+
+DECLARE_BAKERY_LOCK(gpc_lock);
+
+/* 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);
+void imx_anamix_override(bool enter);
+void imx_gpc_pm_domain_enable(uint32_t domain_id, bool on);
+
+#endif /*IMX8M_GPC_H */
diff --git a/plat/imx/imx8m/include/imx8m_caam.h b/plat/imx/imx8m/include/imx8m_caam.h
new file mode 100644
index 0000000..84725b1
--- /dev/null
+++ b/plat/imx/imx8m/include/imx8m_caam.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019, NXP. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX8M_CAAM_H
+#define IMX8M_CAAM_H
+
+#include <lib/utils_def.h>
+
+#include <platform_def.h>
+
+#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 */
diff --git a/plat/imx/imx8m/include/imx8m_csu.h b/plat/imx/imx8m/include/imx8m_csu.h
new file mode 100644
index 0000000..dc634ed
--- /dev/null
+++ b/plat/imx/imx8m/include/imx8m_csu.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_CSU_H
+#define IMX_CSU_H
+
+#include <lib/utils_def.h>
+
+#include <platform_def.h>
+
+#define CSU_SEC_LEVEL_0 0xff
+#define CSU_SEC_LEVEL_1 0xbb
+#define CSU_SEC_LEVEL_2 0x3f
+#define CSU_SEC_LEVEL_3 0x3b
+#define CSU_SEC_LEVEL_4 0x33
+#define CSU_SEC_LEVEL_5 0x22
+#define CSU_SEC_LEVEL_6 0x03
+#define CSU_SEC_LEVEL_7 0x0
+
+#define LOCKED 0x1
+#define UNLOCKED 0x0
+
+#define CSLx_REG(x) (IMX_CSU_BASE + ((x) / 2) * 4)
+#define CSLx_LOCK(x) ((0x1 << (((x) % 2) * 16 + 8)))
+#define CSLx_CFG(x, n) ((x) << (((n) % 2) * 16))
+
+#define CSU_HP_REG(x) (IMX_CSU_BASE + ((x) / 16) * 4 + 0x200)
+#define CSU_HP_LOCK(x) ((0x1 << (((x) % 16) * 2 + 1)))
+#define CSU_HP_CFG(x, n) ((x) << (((n) % 16) * 2))
+
+#define CSU_SA_REG(x) (IMX_CSU_BASE + 0x218)
+#define CSU_SA_LOCK(x) ((0x1 << (((x) % 16) * 2 + 1)))
+#define CSU_SA_CFG(x, n) ((x) << (((n) % 16) * 2))
+
+#define CSU_HPCONTROL_REG(x) (IMX_CSU_BASE + (((x) / 16) * 4) + 0x358)
+#define CSU_HPCONTROL_LOCK(x) ((0x1 << (((x) % 16) * 2 + 1)))
+#define CSU_HPCONTROL_CFG(x, n) ((x) << (((n) % 16) * 2))
+
+enum csu_cfg_type {
+ CSU_INVALID,
+ CSU_CSL,
+ CSU_HP,
+ CSU_SA,
+ CSU_HPCONTROL,
+};
+
+struct imx_csu_cfg {
+ enum csu_cfg_type type;
+ uint16_t idx;
+ uint16_t lock : 1;
+ uint16_t csl_level : 8;
+ uint16_t hp : 1;
+ uint16_t sa : 1;
+ uint16_t hpctrl : 1;
+};
+
+#define CSU_CSLx(i, level, lk) \
+ {CSU_CSL, .idx = (i), .csl_level = (level), .lock = (lk),}
+
+#define CSU_HPx(i, val, lk) \
+ {CSU_HP, .idx = (i), .hp = (val), .lock = (lk), }
+
+#define CSU_SA(i, val, lk) \
+ {CSU_SA, .idx = (i), .sa = (val), .lock = (lk), }
+
+#define CSU_HPCTRL(i, val, lk) \
+ {CSU_HPCONTROL, .idx = (i), .hpctrl = (val), .lock = (lk), }
+
+void imx_csu_init(const struct imx_csu_cfg *csu_cfg);
+
+#endif /* IMX_CSU_H */
diff --git a/plat/imx/imx8m/include/imx8m_measured_boot.h b/plat/imx/imx8m/include/imx8m_measured_boot.h
new file mode 100644
index 0000000..2ec0c46
--- /dev/null
+++ b/plat/imx/imx8m/include/imx8m_measured_boot.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2022, Linaro
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX8M_MEASURED_BOOT_H
+#define IMX8M_MEASURED_BOOT_H
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+
+int imx8m_set_nt_fw_info(size_t log_size, uintptr_t *ns_log_addr);
+
+#endif /* IMX8M_MEASURED_BOOT_H */
diff --git a/plat/imx/imx8m/include/imx8m_psci.h b/plat/imx/imx8m/include/imx8m_psci.h
new file mode 100644
index 0000000..7d14d11
--- /dev/null
+++ b/plat/imx/imx8m/include/imx8m_psci.h
@@ -0,0 +1,24 @@
+/*
+ * 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);
+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 __dead2 imx_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state);
+int imx_system_reset2(int is_vendor, int reset_type, u_register_t cookie);
+
+#endif /* IMX8M_PSCI_H */
diff --git a/plat/imx/imx8m/include/imx_aipstz.h b/plat/imx/imx8m/include/imx_aipstz.h
new file mode 100644
index 0000000..7616862
--- /dev/null
+++ b/plat/imx/imx8m/include/imx_aipstz.h
@@ -0,0 +1,27 @@
+/*
+ * 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 <lib/utils_def.h>
+
+#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 */
diff --git a/plat/imx/imx8m/include/imx_rdc.h b/plat/imx/imx8m/include/imx_rdc.h
new file mode 100644
index 0000000..a6e10a7
--- /dev/null
+++ b/plat/imx/imx8m/include/imx_rdc.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2019-2022 NXP. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_RDC_H
+#define IMX_RDC_H
+
+#include <lib/utils_def.h>
+
+#include <imx_sec_def.h>
+#include <platform_def.h>
+
+#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) * 0x10)
+#define MREAn(x) (IMX_RDC_BASE + 0x804 + (x) * 0x10)
+#define MRCn(x) (IMX_RDC_BASE + 0x808 + (x) * 0x10)
+
+#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 */
+
diff --git a/plat/imx/imx8qm/imx8qm_bl31_setup.c b/plat/imx/imx8qm/imx8qm_bl31_setup.c
new file mode 100644
index 0000000..68eb534
--- /dev/null
+++ b/plat/imx/imx8qm/imx8qm_bl31_setup.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <context.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/console.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include <imx8qm_pads.h>
+#include <imx8_iomux.h>
+#include <imx8_lpuart.h>
+#include <plat_imx8.h>
+#include <sci/sci.h>
+#include <sec_rsrc.h>
+
+static const unsigned long BL31_COHERENT_RAM_START = BL_COHERENT_RAM_BASE;
+static const unsigned long BL31_COHERENT_RAM_END = BL_COHERENT_RAM_END;
+static const unsigned long BL31_RO_START = BL_CODE_BASE;
+static const unsigned long BL31_RO_END = BL_CODE_END;
+static const unsigned long BL31_RW_END = BL_END;
+
+IMPORT_SYM(unsigned long, __RW_START__, BL31_RW_START);
+
+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))
+
+#if defined(IMX_USE_UART0)
+#define IMX_RES_UART SC_R_UART_0
+#define IMX_PAD_UART_RX SC_P_UART0_RX
+#define IMX_PAD_UART_TX SC_P_UART0_TX
+#define IMX_PAD_UART_RTS_B SC_P_UART0_RTS_B
+#define IMX_PAD_UART_CTS_B SC_P_UART0_CTS_B
+#elif defined(IMX_USE_UART1)
+#define IMX_RES_UART SC_R_UART_1
+#define IMX_PAD_UART_RX SC_P_UART1_RX
+#define IMX_PAD_UART_TX SC_P_UART1_TX
+#define IMX_PAD_UART_RTS_B SC_P_UART1_RTS_B
+#define IMX_PAD_UART_CTS_B SC_P_UART1_CTS_B
+#else
+#error "Provide proper UART number in IMX_DEBUG_UART"
+#endif
+
+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, IMX_RES_UART, 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%" PRIx64 " -- 0x%" PRIx64 "\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%" PRIx64 " -- 0x%" PRIx64 ", \
+ 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%" PRIx64 " -- 0x%" PRIx64 "\n",
+ (sc_faddr_t)BL31_LIMIT, end);
+ err = sc_rm_assign_memreg(ipc_handle, os_part, mr);
+ if (err)
+ ERROR("Memreg assign failed, 0x%" PRIx64 " -- 0x%" PRIx64 "\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%" PRIx64 " -- 0x%" PRIx64 "\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%" PRIx64 " -- 0x%" PRIx64 "\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_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, IMX_RES_UART,
+ SC_PM_PW_MODE_ON);
+ sc_pm_clock_rate_t rate = 80000000;
+ sc_pm_set_clock_rate(ipc_handle, IMX_RES_UART, 2, &rate);
+ sc_pm_clock_enable(ipc_handle, IMX_RES_UART, 2, true, false);
+
+ /* configure UART pads */
+ sc_pad_set(ipc_handle, IMX_PAD_UART_RX, UART_PAD_CTRL);
+ sc_pad_set(ipc_handle, IMX_PAD_UART_TX, UART_PAD_CTRL);
+ sc_pad_set(ipc_handle, IMX_PAD_UART_RTS_B, UART_PAD_CTRL);
+ sc_pad_set(ipc_handle, IMX_PAD_UART_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;
+}
diff --git a/plat/imx/imx8qm/imx8qm_psci.c b/plat/imx/imx8qm/imx8qm_psci.c
new file mode 100644
index 0000000..bdba37c
--- /dev/null
+++ b/plat/imx/imx8qm/imx8qm_psci.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <plat_imx8.h>
+#include <sci/sci.h>
+
+#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;
+}
diff --git a/plat/imx/imx8qm/include/platform_def.h b/plat/imx/imx8qm/include/platform_def.h
new file mode 100644
index 0000000..671c77f
--- /dev/null
+++ b/plat/imx/imx8qm/include/platform_def.h
@@ -0,0 +1,79 @@
+/*
+ * 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 <lib/utils_def.h>
+
+#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 U(0x0)
+#define PLATFORM_MAX_CPU_PER_CLUSTER U(4)
+#define PLATFORM_CLUSTER_COUNT U(2)
+#define PLATFORM_CLUSTER0_CORE_COUNT U(4)
+#define PLATFORM_CLUSTER1_CORE_COUNT U(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
+
+/* UART */
+#if defined(IMX_USE_UART0)
+#define IMX_BOOT_UART_BASE 0x5a060000
+#elif defined(IMX_USE_UART1)
+#define IMX_BOOT_UART_BASE 0x5a070000
+#else
+#error "Provide proper UART number in IMX_DEBUG_UART"
+#endif
+
+#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_A53 DEBUG_CONSOLE
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/imx/imx8qm/include/sec_rsrc.h b/plat/imx/imx8qm/include/sec_rsrc.h
new file mode 100644
index 0000000..d16d051
--- /dev/null
+++ b/plat/imx/imx8qm/include/sec_rsrc.h
@@ -0,0 +1,32 @@
+/*
+ * 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
+};
diff --git a/plat/imx/imx8qm/platform.mk b/plat/imx/imx8qm/platform.mk
new file mode 100644
index 0000000..c57edbe
--- /dev/null
+++ b/plat/imx/imx8qm/platform.mk
@@ -0,0 +1,50 @@
+#
+# Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Translation tables library
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_INCLUDES := -Iplat/imx/imx8qm/include \
+ -Iplat/imx/common/include \
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+IMX_GIC_SOURCES := ${GICV3_SOURCES} \
+ 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/cpus/aarch64/cortex_a53.S \
+ lib/cpus/aarch64/cortex_a72.S \
+ drivers/arm/cci/cci.c \
+ ${XLAT_TABLES_LIB_SRCS} \
+ ${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
+
+IMX_DEBUG_UART ?= 0
+$(eval $(call add_define,IMX_USE_UART${IMX_DEBUG_UART}))
+
+DEBUG_CONSOLE ?= 0
+$(eval $(call add_define,DEBUG_CONSOLE))
diff --git a/plat/imx/imx8qx/imx8qx_bl31_setup.c b/plat/imx/imx8qx/imx8qx_bl31_setup.c
new file mode 100644
index 0000000..1da8d29
--- /dev/null
+++ b/plat/imx/imx8qx/imx8qx_bl31_setup.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <drivers/arm/cci.h>
+#include <drivers/console.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include <imx8qx_pads.h>
+#include <imx8_iomux.h>
+#include <imx8_lpuart.h>
+#include <plat_imx8.h>
+#include <sci/sci.h>
+#include <sec_rsrc.h>
+
+static const unsigned long BL31_COHERENT_RAM_START = BL_COHERENT_RAM_BASE;
+static const unsigned long BL31_COHERENT_RAM_END = BL_COHERENT_RAM_END;
+static const unsigned long BL31_RO_START = BL_CODE_BASE;
+static const unsigned long BL31_RO_END = BL_CODE_END;
+static const unsigned long BL31_RW_END = BL_END;
+
+IMPORT_SYM(unsigned long, __RW_START__, BL31_RW_START);
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+/* Default configuration for i.MX8QM/QXP MEK */
+#if defined(IMX_USE_UART0)
+#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))
+#define IMX_RES_UART SC_R_UART_0
+#define IMX_PAD_UART_RX SC_P_UART0_RX
+#define IMX_PAD_UART_TX SC_P_UART0_TX
+
+/*
+ * On Toradex Colibri i.MX8QXP UART3 on the FLEXCAN2.
+ * Use custom pad control for this
+ */
+#elif defined(IMX_USE_UART3)
+/*
+ * FLEXCAN2_RX/TX pads are muxed to ADMA_UART3_RX/TX,
+ * For ref:
+ * 000b - ADMA_FLEXCAN2_RX
+ * 001b - ADMA_SAI3_RXD
+ * 010b - ADMA_UART3_RX
+ * 011b - ADMA_SAI1_RXFS
+ * 100b - LSIO_GPIO1_IO19
+ */
+#define UART_PAD_CTRL (PADRING_IFMUX_EN_MASK | PADRING_GP_EN_MASK | \
+ (SC_PAD_CONFIG_OUT_IN << PADRING_CONFIG_SHIFT) | \
+ (2U << PADRING_IFMUX_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))
+#define IMX_RES_UART SC_R_UART_3
+#define IMX_PAD_UART_RX SC_P_FLEXCAN2_RX
+#define IMX_PAD_UART_TX SC_P_FLEXCAN2_TX
+#else
+#error "Provide proper UART configuration in IMX_DEBUG_UART"
+#endif
+
+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, IMX_RES_UART, 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%" PRIx64 " -- 0x%" PRIx64 "\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%" PRIx64 " -- 0x%" PRIx64 ", \
+ 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%" PRIx64 " -- 0x%" PRIx64 "\n",
+ (sc_faddr_t)BL31_LIMIT, end);
+ err = sc_rm_assign_memreg(ipc_handle, os_part, mr);
+ if (err)
+ ERROR("Memreg assign failed, 0x%" PRIx64 " -- 0x%" PRIx64 "\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%" PRIx64 " -- 0x%" PRIx64 "\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%" PRIx64 " -- 0x%" PRIx64 "\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_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, IMX_RES_UART,
+ SC_PM_PW_MODE_ON);
+ sc_pm_clock_rate_t rate = 80000000;
+ sc_pm_set_clock_rate(ipc_handle, IMX_RES_UART, 2, &rate);
+ sc_pm_clock_enable(ipc_handle, IMX_RES_UART, 2, true, false);
+
+ /* Configure UART pads */
+ sc_pad_set(ipc_handle, IMX_PAD_UART_RX, UART_PAD_CTRL);
+ sc_pad_set(ipc_handle, IMX_PAD_UART_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;
+}
diff --git a/plat/imx/imx8qx/imx8qx_psci.c b/plat/imx/imx8qx/imx8qx_psci.c
new file mode 100644
index 0000000..aab3a2d
--- /dev/null
+++ b/plat/imx/imx8qx/imx8qx_psci.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <plat_imx8.h>
+#include <sci/sci.h>
+
+#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;
+}
diff --git a/plat/imx/imx8qx/include/platform_def.h b/plat/imx/imx8qx/include/platform_def.h
new file mode 100644
index 0000000..b880e1b
--- /dev/null
+++ b/plat/imx/imx8qx/include/platform_def.h
@@ -0,0 +1,68 @@
+/*
+ * 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 <lib/utils_def.h>
+
+#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 U(0x0)
+#define PLATFORM_MAX_CPU_PER_CLUSTER U(4)
+#define PLATFORM_CLUSTER_COUNT U(1)
+#define PLATFORM_CORE_COUNT U(4)
+#define PLATFORM_CLUSTER0_CORE_COUNT U(4)
+#define PLATFORM_CLUSTER1_CORE_COUNT U(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
+
+#if defined(IMX_USE_UART0)
+#define IMX_BOOT_UART_BASE 0x5a060000
+#elif defined(IMX_USE_UART3)
+#define IMX_BOOT_UART_BASE 0x5a090000
+#else
+#error "Provide proper UART configuration in IMX_DEBUG_UART"
+#endif
+
+#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_A35 DEBUG_CONSOLE
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/imx/imx8qx/include/sec_rsrc.h b/plat/imx/imx8qx/include/sec_rsrc.h
new file mode 100644
index 0000000..b7fe0e8
--- /dev/null
+++ b/plat/imx/imx8qx/include/sec_rsrc.h
@@ -0,0 +1,25 @@
+/*
+ * 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
+};
diff --git a/plat/imx/imx8qx/platform.mk b/plat/imx/imx8qx/platform.mk
new file mode 100644
index 0000000..85b5f3d
--- /dev/null
+++ b/plat/imx/imx8qx/platform.mk
@@ -0,0 +1,42 @@
+#
+# Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Translation tables library
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_INCLUDES := -Iplat/imx/imx8qx/include \
+ -Iplat/imx/common/include \
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+IMX_GIC_SOURCES := ${GICV3_SOURCES} \
+ 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/cpus/aarch64/cortex_a35.S \
+ ${XLAT_TABLES_LIB_SRCS} \
+ ${IMX_GIC_SOURCES} \
+
+include plat/imx/common/sci/sci_api.mk
+
+USE_COHERENT_MEM := 1
+RESET_TO_BL31 := 1
+
+IMX_DEBUG_UART ?= 0
+$(eval $(call add_define,IMX_USE_UART${IMX_DEBUG_UART}))
+
+DEBUG_CONSOLE ?= 0
+$(eval $(call add_define,DEBUG_CONSOLE))
diff --git a/plat/intel/soc/agilex/bl2_plat_setup.c b/plat/intel/soc/agilex/bl2_plat_setup.c
new file mode 100644
index 0000000..211a7b7
--- /dev/null
+++ b/plat/intel/soc/agilex/bl2_plat_setup.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/synopsys/dw_mmc.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+#include "agilex_mmc.h"
+#include "agilex_clock_manager.h"
+#include "agilex_memory_controller.h"
+#include "agilex_pinmux.h"
+#include "ccu/ncore_ccu.h"
+#include "qspi/cadence_qspi.h"
+#include "socfpga_emac.h"
+#include "socfpga_f2sdram_manager.h"
+#include "socfpga_handoff.h"
+#include "socfpga_mailbox.h"
+#include "socfpga_private.h"
+#include "socfpga_reset_manager.h"
+#include "socfpga_system_manager.h"
+#include "wdt/watchdog.h"
+
+static struct mmc_device_info mmc_info;
+
+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 = 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_t console;
+ handoff reverse_handoff_ptr;
+
+ generic_delay_timer_init();
+
+ if (socfpga_get_handoff(&reverse_handoff_ptr))
+ return;
+ config_pinmux(&reverse_handoff_ptr);
+ 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_INTEL_UART_BASE, get_uart_clk(),
+ PLAT_BAUDRATE, &console);
+
+ socfpga_delay_timer_init();
+ init_ncore_ccu();
+ socfpga_emac_init();
+ init_hard_memory_controller();
+ mailbox_init();
+ agx_mmc_init();
+
+ if (!intel_mailbox_is_fpga_not_ready()) {
+ socfpga_bridges_enable(SOC2FPGA_MASK | LWHPS2FPGA_MASK |
+ FPGA2SOC_MASK);
+ }
+}
+
+
+void bl2_el3_plat_arch_setup(void)
+{
+
+ 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());
+
+ mmc_info.mmc_dev_type = MMC_IS_SD;
+ mmc_info.ocr_voltage = OCR_3_3_3_4 | OCR_3_2_3_3;
+
+ /* Request ownership and direct access to QSPI */
+ mailbox_hps_qspi_enable();
+
+ switch (boot_source) {
+ case BOOT_SOURCE_SDMMC:
+ dw_mmc_init(&params, &mmc_info);
+ socfpga_io_setup(boot_source);
+ break;
+
+ case BOOT_SOURCE_QSPI:
+ 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);
+
+ assert(bl_mem_params);
+
+ 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)
+{
+}
+
diff --git a/plat/intel/soc/agilex/bl31_plat_setup.c b/plat/intel/soc/agilex/bl31_plat_setup.c
new file mode 100644
index 0000000..b1b9514
--- /dev/null
+++ b/plat/intel/soc/agilex/bl31_plat_setup.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/bl_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+#include "ccu/ncore_ccu.h"
+#include "socfpga_mailbox.h"
+#include "socfpga_private.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_t console;
+
+ mmio_write_64(PLAT_SEC_ENTRY, PLAT_SEC_WARM_ENTRY);
+
+ console_16550_register(PLAT_INTEL_UART_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);
+
+ /*
+ * Copy BL32 (if populated by BL31) and BL33 entry point information.
+ * They are stored in Secure RAM, in BL31's address space.
+ */
+
+ if (params_from_bl2->h.type == PARAM_BL_PARAMS &&
+ params_from_bl2->h.version >= VERSION_2) {
+
+ 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;
+ }
+ } else {
+ struct socfpga_bl31_params *arg_from_bl2 =
+ (struct socfpga_bl31_params *) from_bl2;
+
+ assert(arg_from_bl2->h.type == PARAM_BL31);
+ assert(arg_from_bl2->h.version >= VERSION_1);
+
+ bl32_image_ep_info = *arg_from_bl2->bl32_ep_info;
+ bl33_image_ep_info = *arg_from_bl2->bl33_ep_info;
+ }
+ SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+}
+
+static const interrupt_prop_t s10_interrupt_props[] = {
+ PLAT_INTEL_SOCFPGA_G1S_IRQ_PROPS(GICV2_INTR_GROUP0),
+ PLAT_INTEL_SOCFPGA_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_SOCFPGA_GICD_BASE,
+ .gicc_base = PLAT_INTEL_SOCFPGA_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)
+{
+ socfpga_delay_timer_init();
+
+ /* Initialize the gic cpu and distributor interfaces */
+ gicv2_driver_init(&plat_gicv2_gic_data);
+ gicv2_distif_init();
+ gicv2_pcpu_distif_init();
+ gicv2_cpuif_enable();
+
+ /* Signal secondary CPUs to jump to BL31 (BL2 = U-boot SPL) */
+ mmio_write_64(PLAT_CPU_RELEASE_ADDR,
+ (uint64_t)plat_secondary_cpus_bl31_entry);
+
+ mailbox_hps_stage_notify(HPS_EXECUTION_STATE_SSBL);
+
+ ncore_enable_ocram_firewall();
+}
+
+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);
+}
+
diff --git a/plat/intel/soc/agilex/include/agilex_clock_manager.h b/plat/intel/soc/agilex/include/agilex_clock_manager.h
new file mode 100644
index 0000000..f39d475
--- /dev/null
+++ b/plat/intel/soc/agilex/include/agilex_clock_manager.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CLOCKMANAGER_H
+#define CLOCKMANAGER_H
+
+#include "socfpga_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_EN_SDMMCCLK BIT(5)
+#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
diff --git a/plat/intel/soc/agilex/include/agilex_memory_controller.h b/plat/intel/soc/agilex/include/agilex_memory_controller.h
new file mode 100644
index 0000000..3746d92
--- /dev/null
+++ b/plat/intel/soc/agilex/include/agilex_memory_controller.h
@@ -0,0 +1,163 @@
+/*
+ * 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_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
diff --git a/plat/intel/soc/agilex/include/agilex_mmc.h b/plat/intel/soc/agilex/include/agilex_mmc.h
new file mode 100644
index 0000000..00f4ca5
--- /dev/null
+++ b/plat/intel/soc/agilex/include/agilex_mmc.h
@@ -0,0 +1,7 @@
+/*
+ * Copyright (c) 2020, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+void agx_mmc_init(void);
diff --git a/plat/intel/soc/agilex/include/agilex_pinmux.h b/plat/intel/soc/agilex/include/agilex_pinmux.h
new file mode 100644
index 0000000..fe01062
--- /dev/null
+++ b/plat/intel/soc/agilex/include/agilex_pinmux.h
@@ -0,0 +1,20 @@
+/*
+ * 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 "socfpga_handoff.h"
+
+void config_pinmux(handoff *handoff);
+
+#endif
+
diff --git a/plat/intel/soc/agilex/include/socfpga_plat_def.h b/plat/intel/soc/agilex/include/socfpga_plat_def.h
new file mode 100644
index 0000000..b216ab1
--- /dev/null
+++ b/plat/intel/soc/agilex/include/socfpga_plat_def.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_SOCFPGA_DEF_H
+#define PLAT_SOCFPGA_DEF_H
+
+#include <platform_def.h>
+
+/* Platform Setting */
+#define PLATFORM_MODEL PLAT_SOCFPGA_AGILEX
+#define BOOT_SOURCE BOOT_SOURCE_SDMMC
+
+/* FPGA config helpers */
+#define INTEL_SIP_SMC_FPGA_CONFIG_ADDR 0x400000
+#define INTEL_SIP_SMC_FPGA_CONFIG_SIZE 0x2000000
+
+/* Register Mapping */
+#define SOCFPGA_CCU_NOC_REG_BASE 0xf7000000
+#define SOCFPGA_F2SDRAMMGR_REG_BASE U(0xf8024000)
+
+#define SOCFPGA_MMC_REG_BASE 0xff808000
+
+#define SOCFPGA_RSTMGR_REG_BASE 0xffd11000
+#define SOCFPGA_SYSMGR_REG_BASE 0xffd12000
+
+#define SOCFPGA_L4_PER_SCR_REG_BASE 0xffd21000
+#define SOCFPGA_L4_SYS_SCR_REG_BASE 0xffd21100
+#define SOCFPGA_SOC2FPGA_SCR_REG_BASE 0xffd21200
+#define SOCFPGA_LWSOC2FPGA_SCR_REG_BASE 0xffd21300
+
+/* Platform specific system counter */
+#define PLAT_SYS_COUNTER_FREQ_IN_MHZ get_cpu_clk()
+
+uint32_t get_cpu_clk(void);
+
+#endif /* PLAT_SOCFPGA_DEF_H */
diff --git a/plat/intel/soc/agilex/platform.mk b/plat/intel/soc/agilex/platform.mk
new file mode 100644
index 0000000..a1e58fc
--- /dev/null
+++ b/plat/intel/soc/agilex/platform.mk
@@ -0,0 +1,83 @@
+#
+# Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2019-2022, 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/
+
+# Include GICv2 driver files
+include drivers/arm/gic/v2/gicv2.mk
+AGX_GICv2_SOURCES := \
+ ${GICV2_SOURCES} \
+ plat/common/plat_gicv2.c
+
+
+PLAT_BL_COMMON_SOURCES := \
+ ${AGX_GICv2_SOURCES} \
+ 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/intel/soc/common/aarch64/platform_common.c \
+ plat/intel/soc/common/aarch64/plat_helpers.S \
+ plat/intel/soc/common/drivers/ccu/ncore_ccu.c \
+ plat/intel/soc/common/socfpga_delay_timer.c
+
+BL2_SOURCES += \
+ common/desc_image_load.c \
+ drivers/mmc/mmc.c \
+ drivers/intel/soc/stratix10/io/s10_memmap_qspi.c \
+ drivers/io/io_storage.c \
+ drivers/io/io_block.c \
+ drivers/io/io_fip.c \
+ drivers/partition/partition.c \
+ drivers/partition/gpt.c \
+ drivers/synopsys/emmc/dw_mmc.c \
+ lib/cpus/aarch64/cortex_a53.S \
+ plat/intel/soc/agilex/bl2_plat_setup.c \
+ plat/intel/soc/agilex/soc/agilex_clock_manager.c \
+ plat/intel/soc/agilex/soc/agilex_memory_controller.c \
+ plat/intel/soc/agilex/soc/agilex_mmc.c \
+ plat/intel/soc/agilex/soc/agilex_pinmux.c \
+ plat/intel/soc/common/bl2_plat_mem_params_desc.c \
+ plat/intel/soc/common/socfpga_image_load.c \
+ plat/intel/soc/common/socfpga_storage.c \
+ plat/intel/soc/common/soc/socfpga_emac.c \
+ plat/intel/soc/common/soc/socfpga_firewall.c \
+ plat/intel/soc/common/soc/socfpga_handoff.c \
+ plat/intel/soc/common/soc/socfpga_mailbox.c \
+ plat/intel/soc/common/soc/socfpga_reset_manager.c \
+ plat/intel/soc/common/drivers/qspi/cadence_qspi.c \
+ plat/intel/soc/common/drivers/wdt/watchdog.c
+
+include lib/zlib/zlib.mk
+PLAT_INCLUDES += -Ilib/zlib
+BL2_SOURCES += $(ZLIB_SOURCES)
+
+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/intel/soc/agilex/bl31_plat_setup.c \
+ plat/intel/soc/agilex/soc/agilex_clock_manager.c \
+ plat/intel/soc/common/socfpga_psci.c \
+ plat/intel/soc/common/socfpga_sip_svc.c \
+ plat/intel/soc/common/socfpga_sip_svc_v2.c \
+ plat/intel/soc/common/socfpga_topology.c \
+ plat/intel/soc/common/sip/socfpga_sip_ecc.c \
+ plat/intel/soc/common/sip/socfpga_sip_fcs.c \
+ plat/intel/soc/common/soc/socfpga_mailbox.c \
+ plat/intel/soc/common/soc/socfpga_reset_manager.c
+
+PROGRAMMABLE_RESET_ADDRESS := 0
+BL2_AT_EL3 := 1
+BL2_INV_DCACHE := 0
+MULTI_CONSOLE_API := 1
+USE_COHERENT_MEM := 1
diff --git a/plat/intel/soc/agilex/soc/agilex_clock_manager.c b/plat/intel/soc/agilex/soc/agilex_clock_manager.c
new file mode 100644
index 0000000..76b9937
--- /dev/null
+++ b/plat/intel/soc/agilex/soc/agilex_clock_manager.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <errno.h>
+#include <lib/mmio.h>
+
+#include "agilex_clock_manager.h"
+#include "socfpga_handoff.h"
+#include "socfpga_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 data)
+{
+ uint32_t val = 0;
+ uint32_t count = 0;
+ uint32_t req_status = 0;
+
+ val = (CLKMGR_MEM_WR | CLKMGR_MEM_REQ |
+ (data << 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 rdata;
+}
+
+void config_clkmgr_handoff(handoff *hoff_ptr)
+{
+ uint32_t mdiv, mscnt, hscnt;
+ uint32_t drefclk_div, refclk_div, rdata;
+
+ /* Set clock maanger into boot mode before running configuration */
+ mmio_setbits_32(CLKMGR_OFFSET + CLKMGR_CTRL,
+ CLKMGR_CTRL_BOOTMODE_SET_MSK);
+ /* 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);
+
+ drefclk_div = CLKMGR_PLLGLOB_DREFCLKDIV(
+ hoff_ptr->main_pll_pllglob);
+ refclk_div = CLKMGR_PLLGLOB_REFCLKDIV(
+ hoff_ptr->main_pll_pllglob);
+
+ mscnt = 100 / (mdiv * BIT(drefclk_div));
+ if (!mscnt)
+ mscnt = 1;
+ hscnt = (mdiv * mscnt * BIT(drefclk_div) / refclk_div) - 4;
+
+ mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB,
+ hoff_ptr->main_pll_pllglob &
+ ~CLKMGR_PLLGLOB_RST_SET_MSK);
+ mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_FDBCK,
+ hoff_ptr->main_pll_fdbck);
+ 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_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);
+ mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_NOCDIV,
+ hoff_ptr->main_pll_nocdiv);
+
+ /* Setup peripheral PLL dividers */
+ mdiv = CLKMGR_PLLM_MDIV(hoff_ptr->per_pll_pllm);
+
+ drefclk_div = CLKMGR_PLLGLOB_DREFCLKDIV(
+ hoff_ptr->per_pll_pllglob);
+ refclk_div = CLKMGR_PLLGLOB_REFCLKDIV(
+ hoff_ptr->per_pll_pllglob);
+
+
+ mscnt = 100 / (mdiv * BIT(drefclk_div));
+ if (!mscnt)
+ mscnt = 1;
+ hscnt = (mdiv * mscnt * BIT(drefclk_div) / refclk_div) - 4;
+
+ mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLGLOB,
+ hoff_ptr->per_pll_pllglob &
+ ~CLKMGR_PLLGLOB_RST_SET_MSK);
+ mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_FDBCK,
+ hoff_ptr->per_pll_fdbck);
+
+ 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_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);
+ mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_EMACCTL,
+ hoff_ptr->per_pll_emacctl);
+ mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_GPIODIV,
+ hoff_ptr->per_pll_gpiodiv);
+
+ /* 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);
+
+ rdata = pll_source_sync_read(CLKMGR_MAINPLL +
+ CLKMGR_MAINPLL_MEM);
+ pll_source_sync_config(CLKMGR_MAINPLL + CLKMGR_MAINPLL_MEM,
+ rdata | 0x80);
+
+ rdata = pll_source_sync_read(CLKMGR_PERPLL + CLKMGR_PERPLL_MEM);
+ pll_source_sync_config(CLKMGR_PERPLL + CLKMGR_PERPLL_MEM,
+ rdata | 0x80);
+
+ wait_pll_lock();
+
+ /*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_clrbits_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(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_1),
+ hoff_ptr->hps_osc_clk_h);
+ mmio_write_32(SOCFPGA_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 = SOCFPGA_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 = SOCFPGA_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;
+}
+
+/* Get cpu freq clock */
+uint32_t get_cpu_clk(void)
+{
+ uint32_t cpu_clk;
+
+ cpu_clk = get_l3_clk()/PLAT_SYS_COUNTER_CONVERT_TO_MHZ;
+
+ return cpu_clk;
+}
diff --git a/plat/intel/soc/agilex/soc/agilex_memory_controller.c b/plat/intel/soc/agilex/soc/agilex_memory_controller.c
new file mode 100644
index 0000000..2aabe87
--- /dev/null
+++ b/plat/intel/soc/agilex/soc/agilex_memory_controller.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <platform_def.h>
+
+#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 1000
+#define CLEAR_EMIF_TIMEOUT 1000
+
+#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;
+ udelay(500);
+ } 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");
+ }
+}
diff --git a/plat/intel/soc/agilex/soc/agilex_mmc.c b/plat/intel/soc/agilex/soc/agilex_mmc.c
new file mode 100644
index 0000000..e05d92a
--- /dev/null
+++ b/plat/intel/soc/agilex/soc/agilex_mmc.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2020, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <lib/mmio.h>
+
+#include "socfpga_system_manager.h"
+#include "agilex_clock_manager.h"
+
+void agx_mmc_init(void)
+{
+ mmio_clrbits_32(CLKMGR_PERPLL + CLKMGR_PERPLL_EN,
+ CLKMGR_PERPLL_EN_SDMMCCLK);
+ mmio_write_32(SOCFPGA_SYSMGR(SDMMC),
+ SYSMGR_SDMMC_SMPLSEL(0) | SYSMGR_SDMMC_DRVSEL(3));
+ mmio_setbits_32(CLKMGR_PERPLL + CLKMGR_PERPLL_EN,
+ CLKMGR_PERPLL_EN_SDMMCCLK);
+}
diff --git a/plat/intel/soc/agilex/soc/agilex_pinmux.c b/plat/intel/soc/agilex/soc/agilex_pinmux.c
new file mode 100644
index 0000000..0b908cf
--- /dev/null
+++ b/plat/intel/soc/agilex/soc/agilex_pinmux.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include "agilex_pinmux.h"
+#include "socfpga_system_manager.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_fpgaintf_mod(void)
+{
+ mmio_write_32(SOCFPGA_SYSMGR(FPGAINTF_EN_2), 1<<8);
+}
+
+
+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]);
+ }
+
+ config_fpgaintf_mod();
+}
+
diff --git a/plat/intel/soc/common/aarch64/plat_helpers.S b/plat/intel/soc/common/aarch64/plat_helpers.S
new file mode 100644
index 0000000..213fd3c
--- /dev/null
+++ b/plat/intel/soc/common/aarch64/plat_helpers.S
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cpu_macros.S>
+#include <platform_def.h>
+#include <el3_common_macros.S>
+
+ .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_secondary_cpus_bl31_entry
+
+ .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 warm_reset_req
+ str xzr, [x4]
+ bl plat_is_my_cpu_primary
+ cbz x0, cpu_in_wfi
+ mov_imm x1, PLAT_SEC_ENTRY
+ str xzr, [x1]
+ mrs x1, rmr_el3
+ orr x1, x1, #0x02
+ msr rmr_el3, x1
+ isb
+ dsb sy
+cpu_in_wfi:
+ wfi
+ b cpu_in_wfi
+endfunc warm_reset_req
+
+func plat_get_my_entrypoint
+ ldr x4, =L2_RESET_DONE_REG
+ ldr x5, [x4]
+ ldr x1, =L2_RESET_DONE_STATUS
+ cmp x1, x5
+ b.eq warm_reset_req
+ 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, CRASH_CONSOLE_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, CRASH_CONSOLE_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
+
+func plat_secondary_cpus_bl31_entry
+ el3_entrypoint_common \
+ _init_sctlr=0 \
+ _warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \
+ _secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \
+ _init_memory=1 \
+ _init_c_runtime=1 \
+ _exception_vectors=runtime_exceptions \
+ _pie_fixup_size=BL31_LIMIT - BL31_BASE
+endfunc plat_secondary_cpus_bl31_entry
diff --git a/plat/intel/soc/common/aarch64/platform_common.c b/plat/intel/soc/common/aarch64/platform_common.c
new file mode 100644
index 0000000..b79a63c
--- /dev/null
+++ b/plat/intel/soc/common/aarch64/platform_common.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <platform_def.h>
+#include <plat/common/platform.h>
+
+#include "socfpga_private.h"
+
+
+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;
+}
+
diff --git a/plat/intel/soc/common/bl2_plat_mem_params_desc.c b/plat/intel/soc/common/bl2_plat_mem_params_desc.c
new file mode 100644
index 0000000..187c53a
--- /dev/null
+++ b/plat/intel/soc/common/bl2_plat_mem_params_desc.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <platform_def.h>
+#include <plat/common/platform.h>
+
+
+/*******************************************************************************
+ * 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)
diff --git a/plat/intel/soc/common/drivers/ccu/ncore_ccu.c b/plat/intel/soc/common/drivers/ccu/ncore_ccu.c
new file mode 100644
index 0000000..d9a238e
--- /dev/null
+++ b/plat/intel/soc/common/drivers/ccu/ncore_ccu.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/debug.h>
+#include <errno.h>
+#include <lib/mmio.h>
+
+#include "ncore_ccu.h"
+
+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++) {
+ for (sf = 0; sf < subsystem_id.num_snoop_filter; sf++) {
+ dir_sf_mtn = DIRECTORY_UNIT(dir, NCORE_DIRUSFMCR);
+ dir_sf_en = DIRECTORY_UNIT(dir, NCORE_DIRUSFER);
+
+ /* Initialize All Entries */
+ mmio_write_32(dir_sf_mtn, SNOOP_FILTER_ID(dir));
+
+ /* Poll Active Bit */
+ ret = poll_active_bit(dir);
+ if (ret != 0) {
+ ERROR("Timeout during active bit polling");
+ return -ETIMEDOUT;
+ }
+
+ /* Snoope Filter Enable */
+ mmio_setbits_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++) {
+ for (ca = 0; ca < subsystem_id.num_coh_agent; ca++) {
+ ca_snoop_en = DIRECTORY_UNIT(ca, NCORE_DIRUCASER0);
+ 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);
+}
+
+void ncore_enable_ocram_firewall(void)
+{
+ mmio_setbits_32(COH_CPU0_BYPASS_REG(NCORE_FW_OCRAM_BLK_CGF1),
+ OCRAM_PRIVILEGED_MASK | OCRAM_SECURE_MASK);
+ mmio_setbits_32(COH_CPU0_BYPASS_REG(NCORE_FW_OCRAM_BLK_CGF2),
+ OCRAM_PRIVILEGED_MASK | OCRAM_SECURE_MASK);
+ mmio_setbits_32(COH_CPU0_BYPASS_REG(NCORE_FW_OCRAM_BLK_CGF3),
+ OCRAM_PRIVILEGED_MASK | OCRAM_SECURE_MASK);
+ mmio_setbits_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;
+}
diff --git a/plat/intel/soc/common/drivers/ccu/ncore_ccu.h b/plat/intel/soc/common/drivers/ccu/ncore_ccu.h
new file mode 100644
index 0000000..3f662ff
--- /dev/null
+++ b/plat/intel/soc/common/drivers/ccu/ncore_ccu.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2019-2022, 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);
+void ncore_enable_ocram_firewall(void);
+
+#endif
diff --git a/plat/intel/soc/common/drivers/qspi/cadence_qspi.c b/plat/intel/soc/common/drivers/qspi/cadence_qspi.c
new file mode 100644
index 0000000..cecf560
--- /dev/null
+++ b/plat/intel/soc/common/drivers/qspi/cadence_qspi.c
@@ -0,0 +1,822 @@
+/*
+ * 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 <assert.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <string.h>
+#include <drivers/delay_timer.h>
+#include <drivers/console.h>
+
+#include "cadence_qspi.h"
+
+#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)) {
+ 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)) {
+ 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);
+}
+
diff --git a/plat/intel/soc/common/drivers/qspi/cadence_qspi.h b/plat/intel/soc/common/drivers/qspi/cadence_qspi.h
new file mode 100644
index 0000000..cfef585
--- /dev/null
+++ b/plat/intel/soc/common/drivers/qspi/cadence_qspi.h
@@ -0,0 +1,178 @@
+/*
+ * 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
+
diff --git a/plat/intel/soc/common/drivers/wdt/watchdog.c b/plat/intel/soc/common/drivers/wdt/watchdog.c
new file mode 100644
index 0000000..651189b
--- /dev/null
+++ b/plat/intel/soc/common/drivers/wdt/watchdog.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#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);
+}
diff --git a/plat/intel/soc/common/drivers/wdt/watchdog.h b/plat/intel/soc/common/drivers/wdt/watchdog.h
new file mode 100644
index 0000000..2c72463
--- /dev/null
+++ b/plat/intel/soc/common/drivers/wdt/watchdog.h
@@ -0,0 +1,39 @@
+/*
+ * 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
diff --git a/plat/intel/soc/common/include/plat_macros.S b/plat/intel/soc/common/include/plat_macros.S
new file mode 100644
index 0000000..43db9a2
--- /dev/null
+++ b/plat/intel/soc/common/include/plat_macros.S
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <platform_def.h>
+
+ /* ---------------------------------------------
+ * 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 */
diff --git a/plat/intel/soc/common/include/platform_def.h b/plat/intel/soc/common/include/platform_def.h
new file mode 100644
index 0000000..2b3f144
--- /dev/null
+++ b/plat/intel/soc/common/include/platform_def.h
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <common/interrupt_props.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <plat/common/common_def.h>
+
+/* Platform Type */
+#define PLAT_SOCFPGA_STRATIX10 1
+#define PLAT_SOCFPGA_AGILEX 2
+#define PLAT_SOCFPGA_N5X 3
+#define PLAT_SOCFPGA_EMULATOR 0
+
+/* sysmgr.boot_scratch_cold4 & 5 used for CPU release address for SPL */
+#define PLAT_CPU_RELEASE_ADDR 0xffd12210
+
+/*
+ * sysmgr.boot_scratch_cold6 & 7 (64bit) are used to indicate L2 reset
+ * is done and HPS should trigger warm reset via RMR_EL3.
+ */
+#define L2_RESET_DONE_REG 0xFFD12218
+
+/* Magic word to indicate L2 reset is completed */
+#define L2_RESET_DONE_STATUS 0x1228E5E7
+
+/* Define next boot image name and offset */
+#define PLAT_NS_IMAGE_OFFSET 0x10000000
+#define PLAT_HANDOFF_OFFSET 0xFFE3F000
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH aarch64
+
+/* SoCFPGA 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 U(1)
+#define PLATFORM_CLUSTER_COUNT U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT U(4)
+#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 U(4)
+
+/* Interrupt related constant */
+
+#define INTEL_SOCFPGA_IRQ_SEC_PHY_TIMER 29
+
+#define INTEL_SOCFPGA_IRQ_SEC_SGI_0 8
+#define INTEL_SOCFPGA_IRQ_SEC_SGI_1 9
+#define INTEL_SOCFPGA_IRQ_SEC_SGI_2 10
+#define INTEL_SOCFPGA_IRQ_SEC_SGI_3 11
+#define INTEL_SOCFPGA_IRQ_SEC_SGI_4 12
+#define INTEL_SOCFPGA_IRQ_SEC_SGI_5 13
+#define INTEL_SOCFPGA_IRQ_SEC_SGI_6 14
+#define INTEL_SOCFPGA_IRQ_SEC_SGI_7 15
+
+#define TSP_IRQ_SEC_PHY_TIMER INTEL_SOCFPGA_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 (0x1000)
+#define BL31_LIMIT (0x81000)
+
+#define BL_DATA_LIMIT PLAT_HANDOFF_OFFSET
+
+#define PLAT_CPUID_RELEASE (BL_DATA_LIMIT - 16)
+#define PLAT_SEC_ENTRY (BL_DATA_LIMIT - 8)
+
+#define PLAT_SEC_WARM_ENTRY 0
+
+/*******************************************************************************
+ * 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_INTEL_UART_BASE PLAT_UART0_BASE
+
+#if PLAT_SOCFPGA_EMULATOR
+#define PLAT_BAUDRATE (4800)
+#define PLAT_UART_CLOCK (76800)
+#else
+#define PLAT_BAUDRATE (115200)
+#define PLAT_UART_CLOCK (100000000)
+#endif
+
+/*******************************************************************************
+ * PHY related constants
+ ******************************************************************************/
+
+#define EMAC0_PHY_MODE PHY_INTERFACE_MODE_RGMII
+#define EMAC1_PHY_MODE PHY_INTERFACE_MODE_RGMII
+#define EMAC2_PHY_MODE PHY_INTERFACE_MODE_RGMII
+
+/*******************************************************************************
+ * System counter frequency related constants
+ ******************************************************************************/
+#define PLAT_SYS_COUNTER_FREQ_IN_TICKS (400000000)
+#define PLAT_SYS_COUNTER_CONVERT_TO_MHZ (1000000)
+
+#define PLAT_INTEL_SOCFPGA_GICD_BASE PLAT_GICD_BASE
+#define PLAT_INTEL_SOCFPGA_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_SOCFPGA_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(INTEL_SOCFPGA_IRQ_SEC_PHY_TIMER, \
+ GIC_HIGHEST_SEC_PRIORITY, grp, GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(INTEL_SOCFPGA_IRQ_SEC_SGI_0, \
+ GIC_HIGHEST_SEC_PRIORITY, grp, GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(INTEL_SOCFPGA_IRQ_SEC_SGI_1, \
+ GIC_HIGHEST_SEC_PRIORITY, grp, GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(INTEL_SOCFPGA_IRQ_SEC_SGI_2, \
+ GIC_HIGHEST_SEC_PRIORITY, grp, GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(INTEL_SOCFPGA_IRQ_SEC_SGI_3, \
+ GIC_HIGHEST_SEC_PRIORITY, grp, GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(INTEL_SOCFPGA_IRQ_SEC_SGI_4, \
+ GIC_HIGHEST_SEC_PRIORITY, grp, GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(INTEL_SOCFPGA_IRQ_SEC_SGI_5, \
+ GIC_HIGHEST_SEC_PRIORITY, grp, GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(INTEL_SOCFPGA_IRQ_SEC_SGI_6, \
+ GIC_HIGHEST_SEC_PRIORITY, grp, GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(INTEL_SOCFPGA_IRQ_SEC_SGI_7, \
+ GIC_HIGHEST_SEC_PRIORITY, grp, GIC_INTR_CFG_EDGE)
+
+#define PLAT_INTEL_SOCFPGA_G0_IRQ_PROPS(grp)
+
+#define MAX_IO_HANDLES 4
+#define MAX_IO_DEVICES 4
+#define MAX_IO_BLOCK_DEVICES 2
+
+#ifndef __ASSEMBLER__
+struct socfpga_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;
+};
+#endif
+
+#endif /* PLATFORM_DEF_H */
+
diff --git a/plat/intel/soc/common/include/socfpga_emac.h b/plat/intel/soc/common/include/socfpga_emac.h
new file mode 100644
index 0000000..5b98006
--- /dev/null
+++ b/plat/intel/soc/common/include/socfpga_emac.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2020, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOCFPGA_EMAC_H
+#define SOCFPGA_EMAC_H
+
+/* EMAC PHY Mode */
+
+#define PHY_INTERFACE_MODE_GMII_MII 0
+#define PHY_INTERFACE_MODE_RGMII 1
+#define PHY_INTERFACE_MODE_RMII 2
+#define PHY_INTERFACE_MODE_RESET 3
+
+/* Mask Definitions */
+
+#define PHY_INTF_SEL_MSK 0x3
+#define FPGAINTF_EN_3_EMAC_MSK(x) (1 << (x * 8))
+
+void socfpga_emac_init(void);
+
+#endif /* SOCFPGA_EMAC_H */
diff --git a/plat/intel/soc/common/include/socfpga_f2sdram_manager.h b/plat/intel/soc/common/include/socfpga_f2sdram_manager.h
new file mode 100644
index 0000000..82bb6cb
--- /dev/null
+++ b/plat/intel/soc/common/include/socfpga_f2sdram_manager.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOCFPGA_F2SDRAMMANAGER_H
+#define SOCFPGA_F2SDRAMMANAGER_H
+
+#include "socfpga_plat_def.h"
+
+/* FPGA2SDRAM Register Map */
+#define SOCFPGA_F2SDRAMMGR_SIDEBANDMGR_FLAGINSTATUS0 0x14
+#define SOCFPGA_F2SDRAMMGR_SIDEBANDMGR_FLAGOUTCLR0 0x54
+#define SOCFPGA_F2SDRAMMGR_SIDEBANDMGR_FLAGOUTSET0 0x50
+
+#define FLAGOUTSETCLR_F2SDRAM0_ENABLE (BIT(1))
+#define FLAGOUTSETCLR_F2SDRAM1_ENABLE (BIT(4))
+#define FLAGOUTSETCLR_F2SDRAM2_ENABLE (BIT(7))
+
+#define FLAGOUTSETCLR_F2SDRAM0_IDLEREQ (BIT(0))
+#define FLAGOUTSETCLR_F2SDRAM1_IDLEREQ (BIT(3))
+#define FLAGOUTSETCLR_F2SDRAM2_IDLEREQ (BIT(6))
+#define FLAGINTSTATUS_F2SDRAM0_IDLEACK (BIT(1))
+#define FLAGINTSTATUS_F2SDRAM1_IDLEACK (BIT(5))
+#define FLAGINTSTATUS_F2SDRAM2_IDLEACK (BIT(9))
+#define FLAGOUTSETCLR_F2SDRAM0_FORCE_DRAIN (BIT(2))
+#define FLAGOUTSETCLR_F2SDRAM1_FORCE_DRAIN (BIT(5))
+#define FLAGOUTSETCLR_F2SDRAM2_FORCE_DRAIN (BIT(8))
+
+#define FLAGINTSTATUS_F2SOC_RESPEMPTY (BIT(3))
+#define FLAGINTSTATUS_F2SDRAM0_RESPEMPTY (BIT(3))
+#define FLAGINTSTATUS_F2SDRAM1_RESPEMPTY (BIT(7))
+#define FLAGINTSTATUS_F2SDRAM2_RESPEMPTY (BIT(11))
+
+#define SOCFPGA_F2SDRAMMGR(_reg) (SOCFPGA_F2SDRAMMGR_REG_BASE \
+ + (SOCFPGA_F2SDRAMMGR_##_reg))
+
+#endif /* SOCFPGA_F2SDRAMMGR_H */
diff --git a/plat/intel/soc/common/include/socfpga_fcs.h b/plat/intel/soc/common/include/socfpga_fcs.h
new file mode 100644
index 0000000..893551d
--- /dev/null
+++ b/plat/intel/soc/common/include/socfpga_fcs.h
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2020-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOCFPGA_FCS_H
+#define SOCFPGA_FCS_H
+
+/* FCS Definitions */
+
+#define FCS_RANDOM_WORD_SIZE 8U
+#define FCS_PROV_DATA_WORD_SIZE 44U
+#define FCS_SHA384_WORD_SIZE 12U
+
+#define FCS_RANDOM_BYTE_SIZE (FCS_RANDOM_WORD_SIZE * 4U)
+#define FCS_RANDOM_EXT_MAX_WORD_SIZE 1020U
+#define FCS_PROV_DATA_BYTE_SIZE (FCS_PROV_DATA_WORD_SIZE * 4U)
+#define FCS_SHA384_BYTE_SIZE (FCS_SHA384_WORD_SIZE * 4U)
+
+#define FCS_RANDOM_EXT_OFFSET 3
+
+#define FCS_MODE_DECRYPT 0x0
+#define FCS_MODE_ENCRYPT 0x1
+#define FCS_ENCRYPTION_DATA_0 0x10100
+#define FCS_DECRYPTION_DATA_0 0x10102
+#define FCS_OWNER_ID_OFFSET 0xC
+#define FCS_CRYPTION_CRYPTO_HEADER 0x07000000
+#define FCS_CRYPTION_RESP_WORD_SIZE 4U
+#define FCS_CRYPTION_RESP_SIZE_OFFSET 3U
+
+#define PSGSIGMA_TEARDOWN_MAGIC 0xB852E2A4
+#define PSGSIGMA_SESSION_ID_ONE 0x1
+#define PSGSIGMA_UNKNOWN_SESSION 0xFFFFFFFF
+
+#define RESERVED_AS_ZERO 0x0
+/* FCS Single cert */
+
+#define FCS_BIG_CNTR_SEL 0x1
+
+#define FCS_SVN_CNTR_0_SEL 0x2
+#define FCS_SVN_CNTR_1_SEL 0x3
+#define FCS_SVN_CNTR_2_SEL 0x4
+#define FCS_SVN_CNTR_3_SEL 0x5
+
+#define FCS_BIG_CNTR_VAL_MAX 495U
+#define FCS_SVN_CNTR_VAL_MAX 64U
+
+/* FCS Attestation Cert Request Parameter */
+
+#define FCS_ATTEST_FIRMWARE_CERT 0x01
+#define FCS_ATTEST_DEV_ID_SELF_SIGN_CERT 0x02
+#define FCS_ATTEST_DEV_ID_ENROLL_CERT 0x04
+#define FCS_ATTEST_ENROLL_SELF_SIGN_CERT 0x08
+#define FCS_ATTEST_ALIAS_CERT 0x10
+#define FCS_ATTEST_CERT_MAX_REQ_PARAM 0xFF
+
+/* FCS Crypto Service */
+
+#define FCS_CS_KEY_OBJ_MAX_WORD_SIZE 88U
+#define FCS_CS_KEY_INFO_MAX_WORD_SIZE 36U
+#define FCS_CS_KEY_RESP_STATUS_MASK 0xFF
+#define FCS_CS_KEY_RESP_STATUS_OFFSET 16U
+
+#define FCS_CS_FIELD_SIZE_MASK 0xFFFF
+#define FCS_CS_FIELD_FLAG_OFFSET 24
+#define FCS_CS_FIELD_FLAG_INIT BIT(0)
+#define FCS_CS_FIELD_FLAG_UPDATE BIT(1)
+#define FCS_CS_FIELD_FLAG_FINALIZE BIT(2)
+
+#define FCS_AES_MAX_DATA_SIZE 0x10000000 /* 256 MB */
+#define FCS_AES_MIN_DATA_SIZE 0x20 /* 32 Byte */
+#define FCS_AES_CMD_MAX_WORD_SIZE 15U
+
+#define FCS_GET_DIGEST_CMD_MAX_WORD_SIZE 7U
+#define FCS_GET_DIGEST_RESP_MAX_WORD_SIZE 19U
+#define FCS_MAC_VERIFY_CMD_MAX_WORD_SIZE 23U
+#define FCS_MAC_VERIFY_RESP_MAX_WORD_SIZE 4U
+#define FCS_SHA_HMAC_CRYPTO_PARAM_SIZE_OFFSET 8U
+
+#define FCS_ECDSA_GET_PUBKEY_MAX_WORD_SIZE 5U
+#define FCS_ECDSA_SHA2_DATA_SIGN_CMD_MAX_WORD_SIZE 7U
+#define FCS_ECDSA_SHA2_DATA_SIG_VERIFY_CMD_MAX_WORD_SIZE 43U
+#define FCS_ECDSA_HASH_SIGN_CMD_MAX_WORD_SIZE 17U
+#define FCS_ECDSA_HASH_SIG_VERIFY_CMD_MAX_WORD_SIZE 52U
+#define FCS_ECDH_REQUEST_CMD_MAX_WORD_SIZE 29U
+/* FCS Payload Structure */
+typedef struct fcs_rng_payload_t {
+ uint32_t session_id;
+ uint32_t context_id;
+ uint32_t crypto_header;
+ uint32_t size;
+} fcs_rng_payload;
+
+typedef struct fcs_encrypt_payload_t {
+ uint32_t first_word;
+ uint32_t src_addr;
+ uint32_t src_size;
+ uint32_t dst_addr;
+ uint32_t dst_size;
+} fcs_encrypt_payload;
+
+typedef struct fcs_decrypt_payload_t {
+ uint32_t first_word;
+ uint32_t owner_id[2];
+ uint32_t src_addr;
+ uint32_t src_size;
+ uint32_t dst_addr;
+ uint32_t dst_size;
+} fcs_decrypt_payload;
+
+typedef struct fcs_encrypt_ext_payload_t {
+ uint32_t session_id;
+ uint32_t context_id;
+ uint32_t crypto_header;
+ uint32_t src_addr;
+ uint32_t src_size;
+ uint32_t dst_addr;
+ uint32_t dst_size;
+} fcs_encrypt_ext_payload;
+
+typedef struct fcs_decrypt_ext_payload_t {
+ uint32_t session_id;
+ uint32_t context_id;
+ uint32_t crypto_header;
+ uint32_t owner_id[2];
+ uint32_t src_addr;
+ uint32_t src_size;
+ uint32_t dst_addr;
+ uint32_t dst_size;
+} fcs_decrypt_ext_payload;
+
+typedef struct psgsigma_teardown_msg_t {
+ uint32_t reserved_word;
+ uint32_t magic_word;
+ uint32_t session_id;
+} psgsigma_teardown_msg;
+
+typedef struct fcs_cntr_set_preauth_payload_t {
+ uint32_t first_word;
+ uint32_t counter_value;
+} fcs_cntr_set_preauth_payload;
+
+typedef struct fcs_cs_key_payload_t {
+ uint32_t session_id;
+ uint32_t reserved0;
+ uint32_t reserved1;
+ uint32_t key_id;
+} fcs_cs_key_payload;
+
+typedef struct fcs_crypto_service_data_t {
+ uint32_t session_id;
+ uint32_t context_id;
+ uint32_t key_id;
+ uint32_t crypto_param_size;
+ uint64_t crypto_param;
+ uint8_t is_updated;
+} fcs_crypto_service_data;
+
+typedef struct fcs_crypto_service_aes_data_t {
+ uint32_t session_id;
+ uint32_t context_id;
+ uint32_t param_size;
+ uint32_t key_id;
+ uint32_t crypto_param[7];
+ uint8_t is_updated;
+} fcs_crypto_service_aes_data;
+
+/* Functions Definitions */
+
+uint32_t intel_fcs_random_number_gen(uint64_t addr, uint64_t *ret_size,
+ uint32_t *mbox_error);
+int intel_fcs_random_number_gen_ext(uint32_t session_id, uint32_t context_id,
+ uint32_t size, uint32_t *send_id);
+uint32_t intel_fcs_send_cert(uint64_t addr, uint64_t size,
+ uint32_t *send_id);
+uint32_t intel_fcs_get_provision_data(uint32_t *send_id);
+uint32_t intel_fcs_cntr_set_preauth(uint8_t counter_type,
+ int32_t counter_value,
+ uint32_t test_bit,
+ uint32_t *mbox_error);
+uint32_t intel_fcs_encryption(uint32_t src_addr, uint32_t src_size,
+ uint32_t dst_addr, uint32_t dst_size,
+ uint32_t *send_id);
+
+uint32_t intel_fcs_decryption(uint32_t src_addr, uint32_t src_size,
+ uint32_t dst_addr, uint32_t dst_size,
+ uint32_t *send_id);
+
+int intel_fcs_encryption_ext(uint32_t session_id, uint32_t context_id,
+ uint32_t src_addr, uint32_t src_size,
+ uint32_t dst_addr, uint32_t *dst_size,
+ uint32_t *mbox_error);
+int intel_fcs_decryption_ext(uint32_t sesion_id, uint32_t context_id,
+ uint32_t src_addr, uint32_t src_size,
+ uint32_t dst_addr, uint32_t *dst_size,
+ uint32_t *mbox_error);
+
+int intel_fcs_sigma_teardown(uint32_t session_id, uint32_t *mbox_error);
+int intel_fcs_chip_id(uint32_t *id_low, uint32_t *id_high, uint32_t *mbox_error);
+int intel_fcs_attestation_subkey(uint64_t src_addr, uint32_t src_size,
+ uint64_t dst_addr, uint32_t *dst_size,
+ uint32_t *mbox_error);
+int intel_fcs_get_measurement(uint64_t src_addr, uint32_t src_size,
+ uint64_t dst_addr, uint32_t *dst_size,
+ uint32_t *mbox_error);
+uint32_t intel_fcs_get_rom_patch_sha384(uint64_t addr, uint64_t *ret_size,
+ uint32_t *mbox_error);
+
+int intel_fcs_create_cert_on_reload(uint32_t cert_request,
+ uint32_t *mbox_error);
+int intel_fcs_get_attestation_cert(uint32_t cert_request, uint64_t dst_addr,
+ uint32_t *dst_size, uint32_t *mbox_error);
+
+int intel_fcs_open_crypto_service_session(uint32_t *session_id,
+ uint32_t *mbox_error);
+int intel_fcs_close_crypto_service_session(uint32_t session_id,
+ uint32_t *mbox_error);
+
+int intel_fcs_import_crypto_service_key(uint64_t src_addr, uint32_t src_size,
+ uint32_t *mbox_error);
+int intel_fcs_export_crypto_service_key(uint32_t session_id, uint32_t key_id,
+ uint64_t dst_addr, uint32_t *dst_size,
+ uint32_t *mbox_error);
+int intel_fcs_remove_crypto_service_key(uint32_t session_id, uint32_t key_id,
+ uint32_t *mbox_error);
+int intel_fcs_get_crypto_service_key_info(uint32_t session_id, uint32_t key_id,
+ uint64_t dst_addr, uint32_t *dst_size,
+ uint32_t *mbox_error);
+
+int intel_fcs_get_digest_init(uint32_t session_id, uint32_t context_id,
+ uint32_t key_id, uint32_t param_size,
+ uint64_t param_data, uint32_t *mbox_error);
+int intel_fcs_get_digest_update_finalize(uint32_t session_id, uint32_t context_id,
+ uint32_t src_addr, uint32_t src_size,
+ uint64_t dst_addr, uint32_t *dst_size,
+ uint8_t is_finalised, uint32_t *mbox_error);
+
+int intel_fcs_mac_verify_init(uint32_t session_id, uint32_t context_id,
+ uint32_t key_id, uint32_t param_size,
+ uint64_t param_data, uint32_t *mbox_error);
+int intel_fcs_mac_verify_update_finalize(uint32_t session_id, uint32_t context_id,
+ uint32_t src_addr, uint32_t src_size,
+ uint64_t dst_addr, uint32_t *dst_size,
+ uint32_t data_size, uint8_t is_finalised,
+ uint32_t *mbox_error);
+
+int intel_fcs_ecdsa_hash_sign_init(uint32_t session_id, uint32_t context_id,
+ uint32_t key_id, uint32_t param_size,
+ uint64_t param_data, uint32_t *mbox_error);
+int intel_fcs_ecdsa_hash_sign_finalize(uint32_t session_id, uint32_t context_id,
+ uint32_t src_addr, uint32_t src_size,
+ uint64_t dst_addr, uint32_t *dst_size,
+ uint32_t *mbox_error);
+
+int intel_fcs_ecdsa_hash_sig_verify_init(uint32_t session_id, uint32_t context_id,
+ uint32_t key_id, uint32_t param_size,
+ uint64_t param_data, uint32_t *mbox_error);
+int intel_fcs_ecdsa_hash_sig_verify_finalize(uint32_t session_id, uint32_t context_id,
+ uint32_t src_addr, uint32_t src_size,
+ uint64_t dst_addr, uint32_t *dst_size,
+ uint32_t *mbox_error);
+
+int intel_fcs_ecdsa_sha2_data_sign_init(uint32_t session_id,
+ uint32_t context_id, uint32_t key_id,
+ uint32_t param_size, uint64_t param_data,
+ uint32_t *mbox_error);
+int intel_fcs_ecdsa_sha2_data_sign_update_finalize(uint32_t session_id,
+ uint32_t context_id, uint32_t src_addr,
+ uint32_t src_size, uint64_t dst_addr,
+ uint32_t *dst_size, uint8_t is_finalised,
+ uint32_t *mbox_error);
+
+int intel_fcs_ecdsa_sha2_data_sig_verify_init(uint32_t session_id,
+ uint32_t context_id, uint32_t key_id,
+ uint32_t param_size, uint64_t param_data,
+ uint32_t *mbox_error);
+int intel_fcs_ecdsa_sha2_data_sig_verify_update_finalize(uint32_t session_id,
+ uint32_t context_id, uint32_t src_addr,
+ uint32_t src_size, uint64_t dst_addr,
+ uint32_t *dst_size, uint32_t data_size,
+ uint8_t is_finalised, uint32_t *mbox_error);
+
+int intel_fcs_ecdsa_get_pubkey_init(uint32_t session_id, uint32_t context_id,
+ uint32_t key_id, uint32_t param_size,
+ uint64_t param_data, uint32_t *mbox_error);
+int intel_fcs_ecdsa_get_pubkey_finalize(uint32_t session_id, uint32_t context_id,
+ uint64_t dst_addr, uint32_t *dst_size,
+ uint32_t *mbox_error);
+
+int intel_fcs_ecdh_request_init(uint32_t session_id, uint32_t context_id,
+ uint32_t key_id, uint32_t param_size,
+ uint64_t param_data, uint32_t *mbox_error);
+int intel_fcs_ecdh_request_finalize(uint32_t session_id, uint32_t context_id,
+ uint32_t src_addr, uint32_t src_size,
+ uint64_t dst_addr, uint32_t *dst_size,
+ uint32_t *mbox_error);
+
+int intel_fcs_aes_crypt_init(uint32_t session_id, uint32_t context_id,
+ uint32_t key_id, uint64_t param_addr,
+ uint32_t param_size, uint32_t *mbox_error);
+int intel_fcs_aes_crypt_update_finalize(uint32_t session_id,
+ uint32_t context_id, uint64_t src_addr,
+ uint32_t src_size, uint64_t dst_addr,
+ uint32_t dst_size, uint8_t is_finalised,
+ uint32_t *send_id);
+
+#endif /* SOCFPGA_FCS_H */
diff --git a/plat/intel/soc/common/include/socfpga_handoff.h b/plat/intel/soc/common/include/socfpga_handoff.h
new file mode 100644
index 0000000..ba0f7f3
--- /dev/null
+++ b/plat/intel/soc/common/include/socfpga_handoff.h
@@ -0,0 +1,135 @@
+/*
+ * 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 */
+
+#include <socfpga_plat_def.h>
+
+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 */
+
+#if PLATFORM_MODEL == PLAT_SOCFPGA_STRATIX10
+ 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;
+#elif PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX
+ 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];
+#endif
+ /* misc configuration */
+ uint32_t misc_magic;
+ uint32_t misc_length;
+ uint32_t _pad_0x618_0x620[2];
+} handoff;
+
+int verify_handoff_image(handoff *hoff_ptr, handoff *reverse_hoff_ptr);
+int socfpga_get_handoff(handoff *hoff_ptr);
+
+#endif
+
+
diff --git a/plat/intel/soc/common/include/socfpga_mailbox.h b/plat/intel/soc/common/include/socfpga_mailbox.h
new file mode 100644
index 0000000..1f4b2a4
--- /dev/null
+++ b/plat/intel/soc/common/include/socfpga_mailbox.h
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOCFPGA_MBOX_H
+#define SOCFPGA_MBOX_H
+
+#include <lib/utils_def.h>
+
+
+#define MBOX_OFFSET 0xffa30000
+
+#define MBOX_ATF_CLIENT_ID 0x1U
+#define MBOX_MAX_JOB_ID 0xFU
+#define MBOX_MAX_IND_JOB_ID (MBOX_MAX_JOB_ID - 1U)
+#define MBOX_JOB_ID MBOX_MAX_JOB_ID
+#define MBOX_TEST_BIT BIT(31)
+
+/* Mailbox Shared Memory Register Map */
+#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
+
+/* Mailbox SDM doorbell */
+#define MBOX_DOORBELL_TO_SDM 0x400
+#define MBOX_DOORBELL_FROM_SDM 0x480
+
+
+/* Mailbox commands */
+
+#define MBOX_CMD_NOOP 0x00
+#define MBOX_CMD_SYNC 0x01
+#define MBOX_CMD_RESTART 0x02
+#define MBOX_CMD_CANCEL 0x03
+#define MBOX_CMD_VAB_SRC_CERT 0x0B
+#define MBOX_CMD_GET_IDCODE 0x10
+#define MBOX_CMD_GET_USERCODE 0x13
+#define MBOX_CMD_GET_CHIPID 0x12
+#define MBOX_CMD_REBOOT_HPS 0x47
+
+/* Reconfiguration Commands */
+#define MBOX_CONFIG_STATUS 0x04
+#define MBOX_RECONFIG 0x06
+#define MBOX_RECONFIG_DATA 0x08
+#define MBOX_RECONFIG_STATUS 0x09
+
+/* HWMON Commands */
+#define MBOX_HWMON_READVOLT 0x18
+#define MBOX_HWMON_READTEMP 0x19
+
+
+/* QSPI Commands */
+#define MBOX_CMD_QSPI_OPEN 0x32
+#define MBOX_CMD_QSPI_CLOSE 0x33
+#define MBOX_CMD_QSPI_SET_CS 0x34
+#define MBOX_CMD_QSPI_DIRECT 0x3B
+
+/* RSU Commands */
+#define MBOX_GET_SUBPARTITION_TABLE 0x5A
+#define MBOX_RSU_STATUS 0x5B
+#define MBOX_RSU_UPDATE 0x5C
+#define MBOX_HPS_STAGE_NOTIFY 0x5D
+
+/* FCS Command */
+#define MBOX_FCS_GET_PROVISION 0x7B
+#define MBOX_FCS_CNTR_SET_PREAUTH 0x7C
+#define MBOX_FCS_ENCRYPT_REQ 0x7E
+#define MBOX_FCS_DECRYPT_REQ 0x7F
+#define MBOX_FCS_RANDOM_GEN 0x80
+#define MBOX_FCS_AES_CRYPT_REQ 0x81
+#define MBOX_FCS_GET_DIGEST_REQ 0x82
+#define MBOX_FCS_MAC_VERIFY_REQ 0x83
+#define MBOX_FCS_ECDSA_HASH_SIGN_REQ 0x84
+#define MBOX_FCS_ECDSA_SHA2_DATA_SIGN_REQ 0x85
+#define MBOX_FCS_ECDSA_HASH_SIG_VERIFY 0x86
+#define MBOX_FCS_ECDSA_SHA2_DATA_SIGN_VERIFY 0x87
+#define MBOX_FCS_ECDSA_GET_PUBKEY 0x88
+#define MBOX_FCS_ECDH_REQUEST 0x89
+#define MBOX_FCS_OPEN_CS_SESSION 0xA0
+#define MBOX_FCS_CLOSE_CS_SESSION 0xA1
+#define MBOX_FCS_IMPORT_CS_KEY 0xA5
+#define MBOX_FCS_EXPORT_CS_KEY 0xA6
+#define MBOX_FCS_REMOVE_CS_KEY 0xA7
+#define MBOX_FCS_GET_CS_KEY_INFO 0xA8
+
+/* PSG SIGMA Commands */
+#define MBOX_PSG_SIGMA_TEARDOWN 0xD5
+
+/* Attestation Commands */
+#define MBOX_CREATE_CERT_ON_RELOAD 0x180
+#define MBOX_GET_ATTESTATION_CERT 0x181
+#define MBOX_ATTESTATION_SUBKEY 0x182
+#define MBOX_GET_MEASUREMENT 0x183
+
+/* Miscellaneous commands */
+#define MBOX_GET_ROM_PATCH_SHA384 0x1B0
+
+/* Mailbox Definitions */
+
+#define CMD_DIRECT 0
+#define CMD_INDIRECT 1
+#define CMD_CASUAL 0
+#define CMD_URGENT 1
+
+#define MBOX_WORD_BYTE 4U
+#define MBOX_RESP_BUFFER_SIZE 16
+#define MBOX_CMD_BUFFER_SIZE 32
+#define MBOX_INC_HEADER_MAX_WORD_SIZE 1024U
+
+/* Execution states for HPS_STAGE_NOTIFY */
+#define HPS_EXECUTION_STATE_FSBL 0
+#define HPS_EXECUTION_STATE_SSBL 1
+#define HPS_EXECUTION_STATE_OS 2
+
+/* Status Response */
+#define MBOX_RET_OK 0
+#define MBOX_RET_ERROR -1
+#define MBOX_NO_RESPONSE -2
+#define MBOX_WRONG_ID -3
+#define MBOX_BUFFER_FULL -4
+#define MBOX_BUSY -5
+#define MBOX_TIMEOUT -2047
+
+/* Reconfig Status Response */
+#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_IDLE 0x00000000
+#define MBOX_CFGSTAT_STATE_CONFIG 0x10000000
+#define MBOX_CFGSTAT_STATE_FAILACK 0x08000000
+#define MBOX_CFGSTAT_STATE_ERROR_INVALID 0xf0000001
+#define MBOX_CFGSTAT_STATE_ERROR_CORRUPT 0xf0000002
+#define MBOX_CFGSTAT_STATE_ERROR_AUTH 0xf0000003
+#define MBOX_CFGSTAT_STATE_ERROR_CORE_IO 0xf0000004
+#define MBOX_CFGSTAT_STATE_ERROR_HARDWARE 0xf0000005
+#define MBOX_CFGSTAT_STATE_ERROR_FAKE 0xf0000006
+#define MBOX_CFGSTAT_STATE_ERROR_BOOT_INFO 0xf0000007
+#define MBOX_CFGSTAT_STATE_ERROR_QSPI_ERROR 0xf0000008
+
+
+/* Mailbox Macros */
+
+#define MBOX_ENTRY_TO_ADDR(_buf, ptr) (MBOX_OFFSET + (MBOX_##_buf##_BUFFER) \
+ + MBOX_WORD_BYTE * (ptr))
+
+/* 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_ERR(BUFFER) ((BUFFER) & 0x000007ff)
+#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_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(val) ((val) << 11)
+#define MBOX_CMD_MASK(header) ((header) & 0x7ff)
+
+/* Mailbox payload */
+#define MBOX_DATA_MAX_LEN 0x3ff
+#define MBOX_PAYLOAD_FLAG_BUSY BIT(0)
+
+/* RSU Macros */
+#define RSU_VERSION_ACMF BIT(8)
+#define RSU_VERSION_ACMF_MASK 0xff00
+
+/* Config Status Macros */
+#define CONFIG_STATUS_WORD_SIZE 16U
+#define CONFIG_STATUS_FW_VER_OFFSET 1
+#define CONFIG_STATUS_FW_VER_MASK 0x00FFFFFF
+
+/* Data structure */
+
+typedef struct mailbox_payload {
+ uint32_t header;
+ uint32_t data[MBOX_DATA_MAX_LEN];
+} mailbox_payload_t;
+
+typedef struct mailbox_container {
+ uint32_t flag;
+ uint32_t index;
+ mailbox_payload_t *payload;
+} mailbox_container_t;
+
+/* Mailbox Function Definitions */
+
+void mailbox_set_int(uint32_t interrupt_input);
+int mailbox_init(void);
+void mailbox_set_qspi_close(void);
+void mailbox_hps_qspi_enable(void);
+
+int mailbox_send_cmd(uint32_t job_id, uint32_t cmd, uint32_t *args,
+ unsigned int len, uint32_t urgent, uint32_t *response,
+ unsigned int *resp_len);
+int mailbox_send_cmd_async(uint32_t *job_id, uint32_t cmd, uint32_t *args,
+ unsigned int len, unsigned int indirect);
+int mailbox_send_cmd_async_ext(uint32_t header_cmd, uint32_t *args,
+ unsigned int len);
+int mailbox_read_response(uint32_t *job_id, uint32_t *response,
+ unsigned int *resp_len);
+int mailbox_read_response_async(uint32_t *job_id, uint32_t *header,
+ uint32_t *response, unsigned int *resp_len,
+ uint8_t ignore_client_id);
+int iterate_resp(uint32_t mbox_resp_len, uint32_t *resp_buf,
+ unsigned int *resp_len);
+
+void mailbox_reset_cold(void);
+void mailbox_clear_response(void);
+
+int intel_mailbox_get_config_status(uint32_t cmd, bool init_done);
+int intel_mailbox_is_fpga_not_ready(void);
+
+int mailbox_rsu_get_spt_offset(uint32_t *resp_buf, uint32_t resp_buf_len);
+int mailbox_rsu_status(uint32_t *resp_buf, uint32_t resp_buf_len);
+int mailbox_rsu_update(uint32_t *flash_offset);
+int mailbox_hps_stage_notify(uint32_t execution_stage);
+int mailbox_hwmon_readtemp(uint32_t chan, uint32_t *resp_buf);
+int mailbox_hwmon_readvolt(uint32_t chan, uint32_t *resp_buf);
+
+#endif /* SOCFPGA_MBOX_H */
diff --git a/plat/intel/soc/common/include/socfpga_noc.h b/plat/intel/soc/common/include/socfpga_noc.h
new file mode 100644
index 0000000..e3c0f73
--- /dev/null
+++ b/plat/intel/soc/common/include/socfpga_noc.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2020-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOCFPGA_NOC_H
+#define SOCFPGA_NOC_H
+
+/* Macros */
+#define SCR_AXI_AP_MASK BIT(24)
+#define SCR_FPGA2SOC_MASK BIT(16)
+#define SCR_MPU_MASK BIT(0)
+#define DISABLE_L4_FIREWALL (SCR_AXI_AP_MASK | SCR_FPGA2SOC_MASK \
+ | SCR_MPU_MASK)
+#define DISABLE_BRIDGE_FIREWALL 0x0ffe0101
+
+#define SOCFPGA_CCU_NOC(_ctrl, _dev) (SOCFPGA_CCU_NOC_REG_BASE \
+ + (SOCFPGA_CCU_NOC_##_ctrl##_##_dev))
+
+#define SOCFPGA_L4_PER_SCR(_reg) (SOCFPGA_L4_PER_SCR_REG_BASE \
+ + (SOCFPGA_NOC_FW_L4_PER_SCR_##_reg))
+
+#define SOCFPGA_L4_SYS_SCR(_reg) (SOCFPGA_L4_SYS_SCR_REG_BASE \
+ + (SOCFPGA_NOC_FW_L4_SYS_SCR_##_reg))
+
+/* L3 Interconnect Register Map */
+#define SOCFPGA_NOC_FW_L4_PER_SCR_NAND_REGISTER 0x0000
+#define SOCFPGA_NOC_FW_L4_PER_SCR_NAND_DATA 0x0004
+#define SOCFPGA_NOC_FW_L4_PER_SCR_USB0_REGISTER 0x000c
+#define SOCFPGA_NOC_FW_L4_PER_SCR_USB1_REGISTER 0x0010
+#define SOCFPGA_NOC_FW_L4_PER_SCR_SPI_MASTER0 0x001c
+#define SOCFPGA_NOC_FW_L4_PER_SCR_SPI_MASTER1 0x0020
+#define SOCFPGA_NOC_FW_L4_PER_SCR_SPI_SLAVE0 0x0024
+#define SOCFPGA_NOC_FW_L4_PER_SCR_SPI_SLAVE1 0x0028
+#define SOCFPGA_NOC_FW_L4_PER_SCR_EMAC0 0x002c
+#define SOCFPGA_NOC_FW_L4_PER_SCR_EMAC1 0x0030
+#define SOCFPGA_NOC_FW_L4_PER_SCR_EMAC2 0x0034
+#define SOCFPGA_NOC_FW_L4_PER_SCR_SDMMC 0x0040
+#define SOCFPGA_NOC_FW_L4_PER_SCR_GPIO0 0x0044
+#define SOCFPGA_NOC_FW_L4_PER_SCR_GPIO1 0x0048
+#define SOCFPGA_NOC_FW_L4_PER_SCR_I2C0 0x0050
+#define SOCFPGA_NOC_FW_L4_PER_SCR_I2C1 0x0054
+#define SOCFPGA_NOC_FW_L4_PER_SCR_I2C2 0x0058
+#define SOCFPGA_NOC_FW_L4_PER_SCR_I2C3 0x005c
+#define SOCFPGA_NOC_FW_L4_PER_SCR_I2C4 0x0060
+#define SOCFPGA_NOC_FW_L4_PER_SCR_SP_TIMER0 0x0064
+#define SOCFPGA_NOC_FW_L4_PER_SCR_SP_TIMER1 0x0068
+#define SOCFPGA_NOC_FW_L4_PER_SCR_UART0 0x006c
+#define SOCFPGA_NOC_FW_L4_PER_SCR_UART1 0x0070
+
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_DMA_ECC 0x0008
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_EMAC0RX_ECC 0x000c
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_EMAC0TX_ECC 0x0010
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_EMAC1RX_ECC 0x0014
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_EMAC1TX_ECC 0x0018
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_EMAC2RX_ECC 0x001c
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_EMAC2TX_ECC 0x0020
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_NAND_ECC 0x002c
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_NAND_READ_ECC 0x0030
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_NAND_WRITE_ECC 0x0034
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_OCRAM_ECC 0x0038
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_SDMMC_ECC 0x0040
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_USB0_ECC 0x0044
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_USB1_ECC 0x0048
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_CLK_MGR 0x004c
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_IO_MGR 0x0054
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_RST_MGR 0x0058
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_SYS_MGR 0x005c
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_OSC0_TIMER 0x0060
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_OSC1_TIMER 0x0064
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_WATCHDOG0 0x0068
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_WATCHDOG1 0x006c
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_WATCHDOG2 0x0070
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_WATCHDOG3 0x0074
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_DAP 0x0078
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_L4_NOC_PROBES 0x0090
+#define SOCFPGA_NOC_FW_L4_SYS_SCR_L4_NOC_QOS 0x0094
+
+/* CCU NOC Register Map */
+
+#define SOCFPGA_CCU_NOC_CPU0_RAM0 0x04688
+#define SOCFPGA_CCU_NOC_IOM_RAM0 0x18628
+
+#define SOCFPGA_CCU_NOC_ADMASK_P_MASK BIT(0)
+#define SOCFPGA_CCU_NOC_ADMASK_NS_MASK BIT(1)
+
+/* Function Definitions */
+
+void enable_ns_peripheral_access(void);
+void enable_ns_bridge_access(void);
+void enable_ns_ocram_access(void);
+void enable_ocram_firewall(void);
+
+#endif
diff --git a/plat/intel/soc/common/include/socfpga_private.h b/plat/intel/soc/common/include/socfpga_private.h
new file mode 100644
index 0000000..9d389e3
--- /dev/null
+++ b/plat/intel/soc/common/include/socfpga_private.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOCFPGA_PRIVATE_H
+#define SOCFPGA_PRIVATE_H
+
+#include "socfpga_plat_def.h"
+
+#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 = SOCFPGA_MMC_REG_BASE \
+ }
+
+typedef enum {
+ BOOT_SOURCE_FPGA = 0,
+ BOOT_SOURCE_SDMMC,
+ BOOT_SOURCE_NAND,
+ BOOT_SOURCE_RSVD,
+ BOOT_SOURCE_QSPI
+} boot_source_type;
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+
+void enable_nonsecure_access(void);
+
+void socfpga_io_setup(int boot_source);
+
+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);
+
+void socfpga_delay_timer_init_args(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);
+
+void plat_secondary_cpus_bl31_entry(void);
+
+#endif /* SOCFPGA_PRIVATE_H */
diff --git a/plat/intel/soc/common/include/socfpga_reset_manager.h b/plat/intel/soc/common/include/socfpga_reset_manager.h
new file mode 100644
index 0000000..cce16ab
--- /dev/null
+++ b/plat/intel/soc/common/include/socfpga_reset_manager.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOCFPGA_RESETMANAGER_H
+#define SOCFPGA_RESETMANAGER_H
+
+#include "socfpga_plat_def.h"
+
+#define SOCFPGA_BRIDGE_ENABLE BIT(0)
+#define SOCFPGA_BRIDGE_HAS_MASK BIT(1)
+
+#define SOC2FPGA_MASK (1<<0)
+#define LWHPS2FPGA_MASK (1<<1)
+#define FPGA2SOC_MASK (1<<2)
+#define F2SDRAM0_MASK (1<<3)
+#define F2SDRAM1_MASK (1<<4)
+#define F2SDRAM2_MASK (1<<5)
+
+/* Register Mapping */
+
+#define SOCFPGA_RSTMGR_STAT 0x000
+#define SOCFPGA_RSTMGR_HDSKEN 0x010
+#define SOCFPGA_RSTMGR_HDSKREQ 0x014
+#define SOCFPGA_RSTMGR_HDSKACK 0x018
+#define SOCFPGA_RSTMGR_MPUMODRST 0x020
+#define SOCFPGA_RSTMGR_PER0MODRST 0x024
+#define SOCFPGA_RSTMGR_PER1MODRST 0x028
+#define SOCFPGA_RSTMGR_BRGMODRST 0x02c
+#define SOCFPGA_RSTMGR_COLDMODRST 0x034
+#define SOCFPGA_RSTMGR_HDSKTIMEOUT 0x064
+
+/* Field Mapping */
+
+#define RSTMGR_PER0MODRST_EMAC0 0x00000001
+#define RSTMGR_PER0MODRST_EMAC1 0x00000002
+#define RSTMGR_PER0MODRST_EMAC2 0x00000004
+#define RSTMGR_PER0MODRST_USB0 0x00000008
+#define RSTMGR_PER0MODRST_USB1 0x00000010
+#define RSTMGR_PER0MODRST_NAND 0x00000020
+#define RSTMGR_PER0MODRST_SDMMC 0x00000080
+#define RSTMGR_PER0MODRST_EMAC0OCP 0x00000100
+#define RSTMGR_PER0MODRST_EMAC1OCP 0x00000200
+#define RSTMGR_PER0MODRST_EMAC2OCP 0x00000400
+#define RSTMGR_PER0MODRST_USB0OCP 0x00000800
+#define RSTMGR_PER0MODRST_USB1OCP 0x00001000
+#define RSTMGR_PER0MODRST_NANDOCP 0x00002000
+#define RSTMGR_PER0MODRST_SDMMCOCP 0x00008000
+#define RSTMGR_PER0MODRST_DMA 0x00010000
+#define RSTMGR_PER0MODRST_SPIM0 0x00020000
+#define RSTMGR_PER0MODRST_SPIM1 0x00040000
+#define RSTMGR_PER0MODRST_SPIS0 0x00080000
+#define RSTMGR_PER0MODRST_SPIS1 0x00100000
+#define RSTMGR_PER0MODRST_DMAOCP 0x00200000
+#define RSTMGR_PER0MODRST_EMACPTP 0x00400000
+#define RSTMGR_PER0MODRST_DMAIF0 0x01000000
+#define RSTMGR_PER0MODRST_DMAIF1 0x02000000
+#define RSTMGR_PER0MODRST_DMAIF2 0x04000000
+#define RSTMGR_PER0MODRST_DMAIF3 0x08000000
+#define RSTMGR_PER0MODRST_DMAIF4 0x10000000
+#define RSTMGR_PER0MODRST_DMAIF5 0x20000000
+#define RSTMGR_PER0MODRST_DMAIF6 0x40000000
+#define RSTMGR_PER0MODRST_DMAIF7 0x80000000
+
+#define RSTMGR_PER1MODRST_WATCHDOG0 0x00000001
+#define RSTMGR_PER1MODRST_WATCHDOG1 0x00000002
+#define RSTMGR_PER1MODRST_WATCHDOG2 0x00000004
+#define RSTMGR_PER1MODRST_WATCHDOG3 0x00000008
+#define RSTMGR_PER1MODRST_L4SYSTIMER0 0x00000010
+#define RSTMGR_PER1MODRST_L4SYSTIMER1 0x00000020
+#define RSTMGR_PER1MODRST_SPTIMER0 0x00000040
+#define RSTMGR_PER1MODRST_SPTIMER1 0x00000080
+#define RSTMGR_PER1MODRST_I2C0 0x00000100
+#define RSTMGR_PER1MODRST_I2C1 0x00000200
+#define RSTMGR_PER1MODRST_I2C2 0x00000400
+#define RSTMGR_PER1MODRST_I2C3 0x00000800
+#define RSTMGR_PER1MODRST_I2C4 0x00001000
+#define RSTMGR_PER1MODRST_UART0 0x00010000
+#define RSTMGR_PER1MODRST_UART1 0x00020000
+#define RSTMGR_PER1MODRST_GPIO0 0x01000000
+#define RSTMGR_PER1MODRST_GPIO1 0x02000000
+
+#define RSTMGR_HDSKEN_FPGAHSEN 0x00000004
+#define RSTMGR_HDSKEN_ETRSTALLEN 0x00000008
+#define RSTMGR_HDSKEN_L2FLUSHEN 0x00000100
+#define RSTMGR_HDSKEN_L3NOC_DBG 0x00010000
+#define RSTMGR_HDSKEN_DEBUG_L3NOC 0x00020000
+#define RSTMGR_HDSKEN_SDRSELFREFEN 0x00000001
+
+#define RSTMGR_HDSKEQ_FPGAHSREQ 0x4
+
+#define RSTMGR_BRGMODRST_SOC2FPGA 0x1
+#define RSTMGR_BRGMODRST_LWHPS2FPGA 0x2
+#define RSTMGR_BRGMODRST_FPGA2SOC 0x4
+#define RSTMGR_BRGMODRST_F2SSDRAM0 0x8
+#define RSTMGR_BRGMODRST_F2SSDRAM1 0x10
+#define RSTMGR_BRGMODRST_F2SSDRAM2 0x20
+#define RSTMGR_BRGMODRST_MPFE 0x40
+#define RSTMGR_BRGMODRST_DDRSCH 0x40
+
+#define RSTMGR_HDSKREQ_FPGAHSREQ (BIT(2))
+#define RSTMGR_HDSKACK_FPGAHSACK_MASK (BIT(2))
+
+/* Definitions */
+
+#define RSTMGR_L2_MODRST 0x0100
+#define RSTMGR_HDSKEN_SET 0x010D
+
+/* Macros */
+
+#define SOCFPGA_RSTMGR(_reg) (SOCFPGA_RSTMGR_REG_BASE \
+ + (SOCFPGA_RSTMGR_##_reg))
+#define RSTMGR_FIELD(_reg, _field) (RSTMGR_##_reg##MODRST_##_field)
+
+/* Function Declarations */
+
+void deassert_peripheral_reset(void);
+void config_hps_hs_before_warm_reset(void);
+
+int socfpga_bridges_enable(uint32_t mask);
+int socfpga_bridges_disable(uint32_t mask);
+
+#endif /* SOCFPGA_RESETMANAGER_H */
diff --git a/plat/intel/soc/common/include/socfpga_sip_svc.h b/plat/intel/soc/common/include/socfpga_sip_svc.h
new file mode 100644
index 0000000..0803eb5
--- /dev/null
+++ b/plat/intel/soc/common/include/socfpga_sip_svc.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOCFPGA_SIP_SVC_H
+#define SOCFPGA_SIP_SVC_H
+
+
+/* SiP status response */
+#define INTEL_SIP_SMC_STATUS_OK 0
+#define INTEL_SIP_SMC_STATUS_BUSY 0x1
+#define INTEL_SIP_SMC_STATUS_REJECTED 0x2
+#define INTEL_SIP_SMC_STATUS_NO_RESPONSE 0x3
+#define INTEL_SIP_SMC_STATUS_ERROR 0x4
+#define INTEL_SIP_SMC_RSU_ERROR 0x7
+
+/* SiP mailbox error code */
+#define GENERIC_RESPONSE_ERROR 0x3FF
+
+/* SiP V2 command code range */
+#define INTEL_SIP_SMC_CMD_MASK 0xFFFF
+#define INTEL_SIP_SMC_CMD_V2_RANGE_BEGIN 0x400
+#define INTEL_SIP_SMC_CMD_V2_RANGE_END 0x4FF
+
+/* SiP V2 protocol header */
+#define INTEL_SIP_SMC_HEADER_JOB_ID_MASK 0xF
+#define INTEL_SIP_SMC_HEADER_JOB_ID_OFFSET 0U
+#define INTEL_SIP_SMC_HEADER_CID_MASK 0xF
+#define INTEL_SIP_SMC_HEADER_CID_OFFSET 4U
+#define INTEL_SIP_SMC_HEADER_VERSION_MASK 0xF
+#define INTEL_SIP_SMC_HEADER_VERSION_OFFSET 60U
+
+/* SMC SiP service function identifier for version 1 */
+
+/* FPGA Reconfig */
+#define INTEL_SIP_SMC_FPGA_CONFIG_START 0xC2000001
+#define INTEL_SIP_SMC_FPGA_CONFIG_WRITE 0x42000002
+#define INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE 0xC2000003
+#define INTEL_SIP_SMC_FPGA_CONFIG_ISDONE 0xC2000004
+#define INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM 0xC2000005
+
+/* FPGA Bitstream Flag */
+#define FLAG_PARTIAL_CONFIG BIT(0)
+#define FLAG_AUTHENTICATION BIT(1)
+#define CONFIG_TEST_FLAG(_flag, _type) (((flag) & FLAG_##_type) \
+ == FLAG_##_type)
+
+/* Secure Register Access */
+#define INTEL_SIP_SMC_REG_READ 0xC2000007
+#define INTEL_SIP_SMC_REG_WRITE 0xC2000008
+#define INTEL_SIP_SMC_REG_UPDATE 0xC2000009
+
+/* Remote System Update */
+#define INTEL_SIP_SMC_RSU_STATUS 0xC200000B
+#define INTEL_SIP_SMC_RSU_UPDATE 0xC200000C
+#define INTEL_SIP_SMC_RSU_NOTIFY 0xC200000E
+#define INTEL_SIP_SMC_RSU_RETRY_COUNTER 0xC200000F
+#define INTEL_SIP_SMC_RSU_DCMF_VERSION 0xC2000010
+#define INTEL_SIP_SMC_RSU_COPY_DCMF_VERSION 0xC2000011
+#define INTEL_SIP_SMC_RSU_MAX_RETRY 0xC2000012
+#define INTEL_SIP_SMC_RSU_COPY_MAX_RETRY 0xC2000013
+#define INTEL_SIP_SMC_RSU_DCMF_STATUS 0xC2000014
+#define INTEL_SIP_SMC_RSU_COPY_DCMF_STATUS 0xC2000015
+
+/* Hardware monitor */
+#define INTEL_SIP_SMC_HWMON_READTEMP 0xC2000020
+#define INTEL_SIP_SMC_HWMON_READVOLT 0xC2000021
+#define TEMP_CHANNEL_MAX (1 << 15)
+#define VOLT_CHANNEL_MAX (1 << 15)
+
+/* ECC */
+#define INTEL_SIP_SMC_ECC_DBE 0xC200000D
+
+/* Generic Command */
+#define INTEL_SIP_SMC_SERVICE_COMPLETED 0xC200001E
+#define INTEL_SIP_SMC_FIRMWARE_VERSION 0xC200001F
+#define INTEL_SIP_SMC_HPS_SET_BRIDGES 0xC2000032
+#define INTEL_SIP_SMC_GET_ROM_PATCH_SHA384 0xC2000040
+
+#define SERVICE_COMPLETED_MODE_ASYNC 0x00004F4E
+
+/* Mailbox Command */
+#define INTEL_SIP_SMC_MBOX_SEND_CMD 0xC200003C
+#define INTEL_SIP_SMC_GET_USERCODE 0xC200003D
+
+/* FPGA Crypto Services */
+#define INTEL_SIP_SMC_FCS_RANDOM_NUMBER 0xC200005A
+#define INTEL_SIP_SMC_FCS_RANDOM_NUMBER_EXT 0x4200008F
+#define INTEL_SIP_SMC_FCS_CRYPTION 0x4200005B
+#define INTEL_SIP_SMC_FCS_CRYPTION_EXT 0xC2000090
+#define INTEL_SIP_SMC_FCS_SERVICE_REQUEST 0x4200005C
+#define INTEL_SIP_SMC_FCS_SEND_CERTIFICATE 0x4200005D
+#define INTEL_SIP_SMC_FCS_GET_PROVISION_DATA 0x4200005E
+#define INTEL_SIP_SMC_FCS_CNTR_SET_PREAUTH 0xC200005F
+#define INTEL_SIP_SMC_FCS_PSGSIGMA_TEARDOWN 0xC2000064
+#define INTEL_SIP_SMC_FCS_CHIP_ID 0xC2000065
+#define INTEL_SIP_SMC_FCS_ATTESTATION_SUBKEY 0xC2000066
+#define INTEL_SIP_SMC_FCS_ATTESTATION_MEASUREMENTS 0xC2000067
+#define INTEL_SIP_SMC_FCS_GET_ATTESTATION_CERT 0xC2000068
+#define INTEL_SIP_SMC_FCS_CREATE_CERT_ON_RELOAD 0xC2000069
+#define INTEL_SIP_SMC_FCS_OPEN_CS_SESSION 0xC200006E
+#define INTEL_SIP_SMC_FCS_CLOSE_CS_SESSION 0xC200006F
+#define INTEL_SIP_SMC_FCS_IMPORT_CS_KEY 0x42000070
+#define INTEL_SIP_SMC_FCS_EXPORT_CS_KEY 0xC2000071
+#define INTEL_SIP_SMC_FCS_REMOVE_CS_KEY 0xC2000072
+#define INTEL_SIP_SMC_FCS_GET_CS_KEY_INFO 0xC2000073
+#define INTEL_SIP_SMC_FCS_AES_CRYPT_INIT 0xC2000074
+#define INTEL_SIP_SMC_FCS_AES_CRYPT_UPDATE 0x42000075
+#define INTEL_SIP_SMC_FCS_AES_CRYPT_FINALIZE 0x42000076
+#define INTEL_SIP_SMC_FCS_GET_DIGEST_INIT 0xC2000077
+#define INTEL_SIP_SMC_FCS_GET_DIGEST_UPDATE 0xC2000078
+#define INTEL_SIP_SMC_FCS_GET_DIGEST_FINALIZE 0xC2000079
+#define INTEL_SIP_SMC_FCS_MAC_VERIFY_INIT 0xC200007A
+#define INTEL_SIP_SMC_FCS_MAC_VERIFY_UPDATE 0xC200007B
+#define INTEL_SIP_SMC_FCS_MAC_VERIFY_FINALIZE 0xC200007C
+#define INTEL_SIP_SMC_FCS_ECDSA_HASH_SIGN_INIT 0xC200007D
+#define INTEL_SIP_SMC_FCS_ECDSA_HASH_SIGN_FINALIZE 0xC200007F
+#define INTEL_SIP_SMC_FCS_ECDSA_SHA2_DATA_SIGN_INIT 0xC2000080
+#define INTEL_SIP_SMC_FCS_ECDSA_SHA2_DATA_SIGN_UPDATE 0xC2000081
+#define INTEL_SIP_SMC_FCS_ECDSA_SHA2_DATA_SIGN_FINALIZE 0xC2000082
+#define INTEL_SIP_SMC_FCS_ECDSA_HASH_SIG_VERIFY_INIT 0xC2000083
+#define INTEL_SIP_SMC_FCS_ECDSA_HASH_SIG_VERIFY_FINALIZE 0xC2000085
+#define INTEL_SIP_SMC_FCS_ECDSA_SHA2_DATA_SIG_VERIFY_INIT 0xC2000086
+#define INTEL_SIP_SMC_FCS_ECDSA_SHA2_DATA_SIG_VERIFY_UPDATE 0xC2000087
+#define INTEL_SIP_SMC_FCS_ECDSA_SHA2_DATA_SIG_VERIFY_FINALIZE 0xC2000088
+#define INTEL_SIP_SMC_FCS_ECDSA_GET_PUBKEY_INIT 0xC2000089
+#define INTEL_SIP_SMC_FCS_ECDSA_GET_PUBKEY_FINALIZE 0xC200008B
+#define INTEL_SIP_SMC_FCS_ECDH_REQUEST_INIT 0xC200008C
+#define INTEL_SIP_SMC_FCS_ECDH_REQUEST_FINALIZE 0xC200008E
+
+#define INTEL_SIP_SMC_FCS_SHA_MODE_MASK 0xF
+#define INTEL_SIP_SMC_FCS_DIGEST_SIZE_MASK 0xF
+#define INTEL_SIP_SMC_FCS_DIGEST_SIZE_OFFSET 4U
+#define INTEL_SIP_SMC_FCS_ECC_ALGO_MASK 0xF
+
+/* ECC DBE */
+#define WARM_RESET_WFI_FLAG BIT(31)
+#define SYSMGR_ECC_DBE_COLD_RST_MASK (SYSMGR_ECC_OCRAM_MASK |\
+ SYSMGR_ECC_DDR0_MASK |\
+ SYSMGR_ECC_DDR1_MASK)
+
+/* Non-mailbox SMC Call */
+#define INTEL_SIP_SMC_SVC_VERSION 0xC2000200
+
+/**
+ * SMC SiP service function identifier for version 2
+ * Command code from 0x400 ~ 0x4FF
+ */
+
+/* V2: Non-mailbox function identifier */
+#define INTEL_SIP_SMC_V2_GET_SVC_VERSION 0xC2000400
+#define INTEL_SIP_SMC_V2_REG_READ 0xC2000401
+#define INTEL_SIP_SMC_V2_REG_WRITE 0xC2000402
+#define INTEL_SIP_SMC_V2_REG_UPDATE 0xC2000403
+#define INTEL_SIP_SMC_V2_HPS_SET_BRIDGES 0xC2000404
+
+/* V2: Mailbox function identifier */
+#define INTEL_SIP_SMC_V2_MAILBOX_SEND_COMMAND 0xC2000420
+#define INTEL_SIP_SMC_V2_MAILBOX_POLL_RESPONSE 0xC2000421
+
+/* 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 1
+#define SIP_SVC_VERSION_MINOR 0
+
+
+/* Structure Definitions */
+struct fpga_config_info {
+ uint32_t addr;
+ int size;
+ int size_written;
+ uint32_t write_requested;
+ int subblocks_sent;
+ int block_number;
+};
+
+typedef enum {
+ NO_REQUEST = 0,
+ RECONFIGURATION,
+ BITSTREAM_AUTH
+} config_type;
+
+/* Function Definitions */
+bool is_size_4_bytes_aligned(uint32_t size);
+bool is_address_in_ddr_range(uint64_t addr, uint64_t size);
+
+/* ECC DBE */
+bool cold_reset_for_ecc_dbe(void);
+uint32_t intel_ecc_dbe_notification(uint64_t dbe_value);
+
+/* Secure register access */
+uint32_t intel_secure_reg_read(uint64_t reg_addr, uint32_t *retval);
+uint32_t intel_secure_reg_write(uint64_t reg_addr, uint32_t val,
+ uint32_t *retval);
+uint32_t intel_secure_reg_update(uint64_t reg_addr, uint32_t mask,
+ uint32_t val, uint32_t *retval);
+
+/* Miscellaneous HPS services */
+uint32_t intel_hps_set_bridges(uint64_t enable, uint64_t mask);
+
+/* SiP Service handler for version 2 */
+uintptr_t sip_smc_handler_v2(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);
+
+#endif /* SOCFPGA_SIP_SVC_H */
diff --git a/plat/intel/soc/common/include/socfpga_system_manager.h b/plat/intel/soc/common/include/socfpga_system_manager.h
new file mode 100644
index 0000000..7f67313
--- /dev/null
+++ b/plat/intel/soc/common/include/socfpga_system_manager.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOCFPGA_SYSTEMMANAGER_H
+#define SOCFPGA_SYSTEMMANAGER_H
+
+#include "socfpga_plat_def.h"
+
+/* System Manager Register Map */
+
+#define SOCFPGA_SYSMGR_SDMMC 0x28
+
+#define SOCFPGA_SYSMGR_FPGAINTF_EN_2 0x6c
+
+#define SOCFPGA_SYSMGR_EMAC_0 0x44
+#define SOCFPGA_SYSMGR_EMAC_1 0x48
+#define SOCFPGA_SYSMGR_EMAC_2 0x4c
+#define SOCFPGA_SYSMGR_FPGAINTF_EN_3 0x70
+
+#define SOCFPGA_SYSMGR_NOC_TIMEOUT 0xc0
+#define SOCFPGA_SYSMGR_NOC_IDLEREQ_SET 0xc4
+#define SOCFPGA_SYSMGR_NOC_IDLEREQ_CLR 0xc8
+#define SOCFPGA_SYSMGR_NOC_IDLEREQ_VAL 0xcc
+#define SOCFPGA_SYSMGR_NOC_IDLEACK 0xd0
+#define SOCFPGA_SYSMGR_NOC_IDLESTATUS 0xd4
+
+#define SOCFPGA_SYSMGR_BOOT_SCRATCH_COLD_0 0x200
+#define SOCFPGA_SYSMGR_BOOT_SCRATCH_COLD_1 0x204
+#define SOCFPGA_SYSMGR_BOOT_SCRATCH_COLD_2 0x208
+#define SOCFPGA_SYSMGR_BOOT_SCRATCH_COLD_8 0x220
+#define SOCFPGA_SYSMGR_BOOT_SCRATCH_COLD_9 0x224
+
+/* Field Masking */
+
+#define SYSMGR_SDMMC_DRVSEL(x) (((x) & 0x7) << 0)
+#define SYSMGR_SDMMC_SMPLSEL(x) (((x) & 0x7) << 4)
+
+#define IDLE_DATA_LWSOC2FPGA BIT(4)
+#define IDLE_DATA_SOC2FPGA BIT(0)
+#define IDLE_DATA_MASK (IDLE_DATA_LWSOC2FPGA | IDLE_DATA_SOC2FPGA)
+
+#define SYSMGR_ECC_OCRAM_MASK BIT(1)
+#define SYSMGR_ECC_DDR0_MASK BIT(16)
+#define SYSMGR_ECC_DDR1_MASK BIT(17)
+
+/* Macros */
+
+#define SOCFPGA_SYSMGR(_reg) (SOCFPGA_SYSMGR_REG_BASE \
+ + (SOCFPGA_SYSMGR_##_reg))
+
+#endif /* SOCFPGA_SYSTEMMANAGER_H */
diff --git a/plat/intel/soc/common/sip/socfpga_sip_ecc.c b/plat/intel/soc/common/sip/socfpga_sip_ecc.c
new file mode 100644
index 0000000..c4e06a6
--- /dev/null
+++ b/plat/intel/soc/common/sip/socfpga_sip_ecc.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
+ */
+
+#include <assert.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+#include <tools_share/uuid.h>
+
+#include "socfpga_fcs.h"
+#include "socfpga_mailbox.h"
+#include "socfpga_reset_manager.h"
+#include "socfpga_sip_svc.h"
+#include "socfpga_system_manager.h"
+
+uint32_t intel_ecc_dbe_notification(uint64_t dbe_value)
+{
+ dbe_value &= WARM_RESET_WFI_FLAG;
+
+ /* Trap CPUs in WFI if warm reset flag is set */
+ if (dbe_value > 0) {
+ while (1) {
+ wfi();
+ }
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+bool cold_reset_for_ecc_dbe(void)
+{
+ uint32_t dbe_int_status;
+
+ dbe_int_status = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8));
+
+ /* Trigger cold reset only for error in critical memory (DDR/OCRAM) */
+ dbe_int_status &= SYSMGR_ECC_DBE_COLD_RST_MASK;
+
+ if (dbe_int_status > 0) {
+ return true;
+ }
+
+ return false;
+}
diff --git a/plat/intel/soc/common/sip/socfpga_sip_fcs.c b/plat/intel/soc/common/sip/socfpga_sip_fcs.c
new file mode 100644
index 0000000..facee0f
--- /dev/null
+++ b/plat/intel/soc/common/sip/socfpga_sip_fcs.c
@@ -0,0 +1,1739 @@
+/*
+ * Copyright (c) 2020-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+
+#include "socfpga_fcs.h"
+#include "socfpga_mailbox.h"
+#include "socfpga_sip_svc.h"
+
+/* FCS static variables */
+static fcs_crypto_service_aes_data fcs_aes_init_payload;
+static fcs_crypto_service_data fcs_sha_get_digest_param;
+static fcs_crypto_service_data fcs_sha_mac_verify_param;
+static fcs_crypto_service_data fcs_ecdsa_hash_sign_param;
+static fcs_crypto_service_data fcs_ecdsa_hash_sig_verify_param;
+static fcs_crypto_service_data fcs_sha2_data_sign_param;
+static fcs_crypto_service_data fcs_sha2_data_sig_verify_param;
+static fcs_crypto_service_data fcs_ecdsa_get_pubkey_param;
+static fcs_crypto_service_data fcs_ecdh_request_param;
+
+bool is_size_4_bytes_aligned(uint32_t size)
+{
+ if ((size % MBOX_WORD_BYTE) != 0U) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+static bool is_8_bytes_aligned(uint32_t data)
+{
+ if ((data % (MBOX_WORD_BYTE * 2U)) != 0U) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+static bool is_32_bytes_aligned(uint32_t data)
+{
+ if ((data % (8U * MBOX_WORD_BYTE)) != 0U) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+static int intel_fcs_crypto_service_init(uint32_t session_id,
+ uint32_t context_id, uint32_t key_id,
+ uint32_t param_size, uint64_t param_data,
+ fcs_crypto_service_data *data_addr,
+ uint32_t *mbox_error)
+{
+ if (mbox_error == NULL) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (param_size != 4) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ memset(data_addr, 0, sizeof(fcs_crypto_service_data));
+
+ data_addr->session_id = session_id;
+ data_addr->context_id = context_id;
+ data_addr->key_id = key_id;
+ data_addr->crypto_param_size = param_size;
+ data_addr->crypto_param = param_data;
+
+ data_addr->is_updated = 0;
+
+ *mbox_error = 0;
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+uint32_t intel_fcs_random_number_gen(uint64_t addr, uint64_t *ret_size,
+ uint32_t *mbox_error)
+{
+ int status;
+ unsigned int i;
+ unsigned int resp_len = FCS_RANDOM_WORD_SIZE;
+ uint32_t random_data[FCS_RANDOM_WORD_SIZE] = {0U};
+
+ if (!is_address_in_ddr_range(addr, FCS_RANDOM_BYTE_SIZE)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_FCS_RANDOM_GEN, NULL, 0U,
+ CMD_CASUAL, random_data, &resp_len);
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ if (resp_len != FCS_RANDOM_WORD_SIZE) {
+ *mbox_error = GENERIC_RESPONSE_ERROR;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *ret_size = FCS_RANDOM_BYTE_SIZE;
+
+ for (i = 0U; i < FCS_RANDOM_WORD_SIZE; i++) {
+ mmio_write_32(addr, random_data[i]);
+ addr += MBOX_WORD_BYTE;
+ }
+
+ flush_dcache_range(addr - *ret_size, *ret_size);
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_random_number_gen_ext(uint32_t session_id, uint32_t context_id,
+ uint32_t size, uint32_t *send_id)
+{
+ int status;
+ uint32_t payload_size;
+ uint32_t crypto_header;
+
+ if (size > (FCS_RANDOM_EXT_MAX_WORD_SIZE *
+ MBOX_WORD_BYTE) || size == 0U) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_size_4_bytes_aligned(size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ crypto_header = (FCS_CS_FIELD_FLAG_INIT | FCS_CS_FIELD_FLAG_FINALIZE) <<
+ FCS_CS_FIELD_FLAG_OFFSET;
+
+ fcs_rng_payload payload = {
+ session_id,
+ context_id,
+ crypto_header,
+ size
+ };
+
+ payload_size = sizeof(payload) / MBOX_WORD_BYTE;
+
+ status = mailbox_send_cmd_async(send_id, MBOX_FCS_RANDOM_GEN,
+ (uint32_t *) &payload, payload_size,
+ CMD_INDIRECT);
+
+ if (status < 0) {
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+uint32_t intel_fcs_send_cert(uint64_t addr, uint64_t size,
+ uint32_t *send_id)
+{
+ int status;
+
+ if (!is_address_in_ddr_range(addr, size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_size_4_bytes_aligned(size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ status = mailbox_send_cmd_async(send_id, MBOX_CMD_VAB_SRC_CERT,
+ (uint32_t *)addr, size / MBOX_WORD_BYTE,
+ CMD_DIRECT);
+
+ flush_dcache_range(addr, size);
+
+ if (status < 0) {
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+uint32_t intel_fcs_get_provision_data(uint32_t *send_id)
+{
+ int status;
+
+ status = mailbox_send_cmd_async(send_id, MBOX_FCS_GET_PROVISION,
+ NULL, 0U, CMD_DIRECT);
+
+ if (status < 0) {
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+uint32_t intel_fcs_cntr_set_preauth(uint8_t counter_type, int32_t counter_value,
+ uint32_t test_bit, uint32_t *mbox_error)
+{
+ int status;
+ uint32_t first_word;
+ uint32_t payload_size;
+
+ if ((test_bit != MBOX_TEST_BIT) &&
+ (test_bit != 0)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if ((counter_type < FCS_BIG_CNTR_SEL) ||
+ (counter_type > FCS_SVN_CNTR_3_SEL)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if ((counter_type == FCS_BIG_CNTR_SEL) &&
+ (counter_value > FCS_BIG_CNTR_VAL_MAX)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if ((counter_type >= FCS_SVN_CNTR_0_SEL) &&
+ (counter_type <= FCS_SVN_CNTR_3_SEL) &&
+ (counter_value > FCS_SVN_CNTR_VAL_MAX)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ first_word = test_bit | counter_type;
+ fcs_cntr_set_preauth_payload payload = {
+ first_word,
+ counter_value
+ };
+
+ payload_size = sizeof(payload) / MBOX_WORD_BYTE;
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_FCS_CNTR_SET_PREAUTH,
+ (uint32_t *) &payload, payload_size,
+ CMD_CASUAL, NULL, NULL);
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+uint32_t intel_fcs_encryption(uint32_t src_addr, uint32_t src_size,
+ uint32_t dst_addr, uint32_t dst_size, uint32_t *send_id)
+{
+ int status;
+ uint32_t load_size;
+
+ fcs_encrypt_payload payload = {
+ FCS_ENCRYPTION_DATA_0,
+ src_addr,
+ src_size,
+ dst_addr,
+ dst_size };
+ load_size = sizeof(payload) / MBOX_WORD_BYTE;
+
+ if (!is_address_in_ddr_range(src_addr, src_size) ||
+ !is_address_in_ddr_range(dst_addr, dst_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_size_4_bytes_aligned(src_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ status = mailbox_send_cmd_async(send_id, MBOX_FCS_ENCRYPT_REQ,
+ (uint32_t *) &payload, load_size,
+ CMD_INDIRECT);
+ inv_dcache_range(dst_addr, dst_size);
+
+ if (status < 0) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+uint32_t intel_fcs_decryption(uint32_t src_addr, uint32_t src_size,
+ uint32_t dst_addr, uint32_t dst_size, uint32_t *send_id)
+{
+ int status;
+ uint32_t load_size;
+ uintptr_t id_offset;
+
+ id_offset = src_addr + FCS_OWNER_ID_OFFSET;
+ fcs_decrypt_payload payload = {
+ FCS_DECRYPTION_DATA_0,
+ {mmio_read_32(id_offset),
+ mmio_read_32(id_offset + MBOX_WORD_BYTE)},
+ src_addr,
+ src_size,
+ dst_addr,
+ dst_size };
+ load_size = sizeof(payload) / MBOX_WORD_BYTE;
+
+ if (!is_address_in_ddr_range(src_addr, src_size) ||
+ !is_address_in_ddr_range(dst_addr, dst_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_size_4_bytes_aligned(src_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ status = mailbox_send_cmd_async(send_id, MBOX_FCS_DECRYPT_REQ,
+ (uint32_t *) &payload, load_size,
+ CMD_INDIRECT);
+ inv_dcache_range(dst_addr, dst_size);
+
+ if (status < 0) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_encryption_ext(uint32_t session_id, uint32_t context_id,
+ uint32_t src_addr, uint32_t src_size,
+ uint32_t dst_addr, uint32_t *dst_size, uint32_t *mbox_error)
+{
+ int status;
+ uint32_t payload_size;
+ uint32_t resp_len = FCS_CRYPTION_RESP_WORD_SIZE;
+ uint32_t resp_data[FCS_CRYPTION_RESP_WORD_SIZE] = {0U};
+
+ if ((dst_size == NULL) || (mbox_error == NULL)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_address_in_ddr_range(src_addr, src_size) ||
+ !is_address_in_ddr_range(dst_addr, *dst_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_size_4_bytes_aligned(src_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ fcs_encrypt_ext_payload payload = {
+ session_id,
+ context_id,
+ FCS_CRYPTION_CRYPTO_HEADER,
+ src_addr,
+ src_size,
+ dst_addr,
+ *dst_size
+ };
+
+ payload_size = sizeof(payload) / MBOX_WORD_BYTE;
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_FCS_ENCRYPT_REQ,
+ (uint32_t *) &payload, payload_size,
+ CMD_CASUAL, resp_data, &resp_len);
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ if (resp_len != FCS_CRYPTION_RESP_WORD_SIZE) {
+ *mbox_error = MBOX_RET_ERROR;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *dst_size = resp_data[FCS_CRYPTION_RESP_SIZE_OFFSET];
+ inv_dcache_range(dst_addr, *dst_size);
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_decryption_ext(uint32_t session_id, uint32_t context_id,
+ uint32_t src_addr, uint32_t src_size,
+ uint32_t dst_addr, uint32_t *dst_size, uint32_t *mbox_error)
+{
+ int status;
+ uintptr_t id_offset;
+ uint32_t payload_size;
+ uint32_t resp_len = FCS_CRYPTION_RESP_WORD_SIZE;
+ uint32_t resp_data[FCS_CRYPTION_RESP_WORD_SIZE] = {0U};
+
+ if ((dst_size == NULL) || (mbox_error == NULL)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_address_in_ddr_range(src_addr, src_size) ||
+ !is_address_in_ddr_range(dst_addr, *dst_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_size_4_bytes_aligned(src_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ id_offset = src_addr + FCS_OWNER_ID_OFFSET;
+ fcs_decrypt_ext_payload payload = {
+ session_id,
+ context_id,
+ FCS_CRYPTION_CRYPTO_HEADER,
+ {mmio_read_32(id_offset),
+ mmio_read_32(id_offset + MBOX_WORD_BYTE)},
+ src_addr,
+ src_size,
+ dst_addr,
+ *dst_size
+ };
+
+ payload_size = sizeof(payload) / MBOX_WORD_BYTE;
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_FCS_DECRYPT_REQ,
+ (uint32_t *) &payload, payload_size,
+ CMD_CASUAL, resp_data, &resp_len);
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ if (resp_len != FCS_CRYPTION_RESP_WORD_SIZE) {
+ *mbox_error = MBOX_RET_ERROR;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *dst_size = resp_data[FCS_CRYPTION_RESP_SIZE_OFFSET];
+ inv_dcache_range(dst_addr, *dst_size);
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_sigma_teardown(uint32_t session_id, uint32_t *mbox_error)
+{
+ int status;
+
+ if ((session_id != PSGSIGMA_SESSION_ID_ONE) &&
+ (session_id != PSGSIGMA_UNKNOWN_SESSION)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ psgsigma_teardown_msg message = {
+ RESERVED_AS_ZERO,
+ PSGSIGMA_TEARDOWN_MAGIC,
+ session_id
+ };
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_PSG_SIGMA_TEARDOWN,
+ (uint32_t *) &message, sizeof(message) / MBOX_WORD_BYTE,
+ CMD_CASUAL, NULL, NULL);
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_chip_id(uint32_t *id_low, uint32_t *id_high, uint32_t *mbox_error)
+{
+ int status;
+ uint32_t load_size;
+ uint32_t chip_id[2];
+
+ load_size = sizeof(chip_id) / MBOX_WORD_BYTE;
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_GET_CHIPID, NULL,
+ 0U, CMD_CASUAL, (uint32_t *) chip_id, &load_size);
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *id_low = chip_id[0];
+ *id_high = chip_id[1];
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_attestation_subkey(uint64_t src_addr, uint32_t src_size,
+ uint64_t dst_addr, uint32_t *dst_size, uint32_t *mbox_error)
+{
+ int status;
+ uint32_t send_size = src_size / MBOX_WORD_BYTE;
+ uint32_t ret_size = *dst_size / MBOX_WORD_BYTE;
+
+
+ if (!is_address_in_ddr_range(src_addr, src_size) ||
+ !is_address_in_ddr_range(dst_addr, *dst_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_ATTESTATION_SUBKEY,
+ (uint32_t *) src_addr, send_size, CMD_CASUAL,
+ (uint32_t *) dst_addr, &ret_size);
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *dst_size = ret_size * MBOX_WORD_BYTE;
+ flush_dcache_range(dst_addr, *dst_size);
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_get_measurement(uint64_t src_addr, uint32_t src_size,
+ uint64_t dst_addr, uint32_t *dst_size, uint32_t *mbox_error)
+{
+ int status;
+ uint32_t send_size = src_size / MBOX_WORD_BYTE;
+ uint32_t ret_size = *dst_size / MBOX_WORD_BYTE;
+
+ if (!is_address_in_ddr_range(src_addr, src_size) ||
+ !is_address_in_ddr_range(dst_addr, *dst_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_GET_MEASUREMENT,
+ (uint32_t *) src_addr, send_size, CMD_CASUAL,
+ (uint32_t *) dst_addr, &ret_size);
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *dst_size = ret_size * MBOX_WORD_BYTE;
+ flush_dcache_range(dst_addr, *dst_size);
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+uint32_t intel_fcs_get_rom_patch_sha384(uint64_t addr, uint64_t *ret_size,
+ uint32_t *mbox_error)
+{
+ int status;
+ unsigned int resp_len = FCS_SHA384_WORD_SIZE;
+
+ if (!is_address_in_ddr_range(addr, FCS_SHA384_BYTE_SIZE)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_GET_ROM_PATCH_SHA384, NULL, 0U,
+ CMD_CASUAL, (uint32_t *) addr, &resp_len);
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ if (resp_len != FCS_SHA384_WORD_SIZE) {
+ *mbox_error = GENERIC_RESPONSE_ERROR;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *ret_size = FCS_SHA384_BYTE_SIZE;
+
+ flush_dcache_range(addr, *ret_size);
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_get_attestation_cert(uint32_t cert_request, uint64_t dst_addr,
+ uint32_t *dst_size, uint32_t *mbox_error)
+{
+ int status;
+ uint32_t ret_size = *dst_size / MBOX_WORD_BYTE;
+
+ if (mbox_error == NULL) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (cert_request < FCS_ATTEST_FIRMWARE_CERT ||
+ cert_request > FCS_ATTEST_CERT_MAX_REQ_PARAM) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_address_in_ddr_range(dst_addr, *dst_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_GET_ATTESTATION_CERT,
+ (uint32_t *) &cert_request, 1U, CMD_CASUAL,
+ (uint32_t *) dst_addr, &ret_size);
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *dst_size = ret_size * MBOX_WORD_BYTE;
+ flush_dcache_range(dst_addr, *dst_size);
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_create_cert_on_reload(uint32_t cert_request,
+ uint32_t *mbox_error)
+{
+ int status;
+
+ if (mbox_error == NULL) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (cert_request < FCS_ATTEST_FIRMWARE_CERT ||
+ cert_request > FCS_ATTEST_CERT_MAX_REQ_PARAM) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_CREATE_CERT_ON_RELOAD,
+ (uint32_t *) &cert_request, 1U, CMD_CASUAL,
+ NULL, NULL);
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_open_crypto_service_session(uint32_t *session_id,
+ uint32_t *mbox_error)
+{
+ int status;
+ uint32_t resp_len = 1U;
+
+ if ((session_id == NULL) || (mbox_error == NULL)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_FCS_OPEN_CS_SESSION,
+ NULL, 0U, CMD_CASUAL, session_id, &resp_len);
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_close_crypto_service_session(uint32_t session_id,
+ uint32_t *mbox_error)
+{
+ int status;
+
+ if (mbox_error == NULL) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_FCS_CLOSE_CS_SESSION,
+ &session_id, 1U, CMD_CASUAL, NULL, NULL);
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_import_crypto_service_key(uint64_t src_addr, uint32_t src_size,
+ uint32_t *send_id)
+{
+ int status;
+
+ if (src_size > (FCS_CS_KEY_OBJ_MAX_WORD_SIZE *
+ MBOX_WORD_BYTE)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_address_in_ddr_range(src_addr, src_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ status = mailbox_send_cmd_async(send_id, MBOX_FCS_IMPORT_CS_KEY,
+ (uint32_t *)src_addr, src_size / MBOX_WORD_BYTE,
+ CMD_INDIRECT);
+
+ if (status < 0) {
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_export_crypto_service_key(uint32_t session_id, uint32_t key_id,
+ uint64_t dst_addr, uint32_t *dst_size,
+ uint32_t *mbox_error)
+{
+ int status;
+ uint32_t i;
+ uint32_t payload_size;
+ uint32_t resp_len = FCS_CS_KEY_OBJ_MAX_WORD_SIZE;
+ uint32_t resp_data[FCS_CS_KEY_OBJ_MAX_WORD_SIZE] = {0U};
+ uint32_t op_status = 0U;
+
+ if ((dst_size == NULL) || (mbox_error == NULL)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_address_in_ddr_range(dst_addr, *dst_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ fcs_cs_key_payload payload = {
+ session_id,
+ RESERVED_AS_ZERO,
+ RESERVED_AS_ZERO,
+ key_id
+ };
+
+ payload_size = sizeof(payload) / MBOX_WORD_BYTE;
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_FCS_EXPORT_CS_KEY,
+ (uint32_t *) &payload, payload_size,
+ CMD_CASUAL, resp_data, &resp_len);
+
+ if (resp_len > 0) {
+ op_status = resp_data[0] & FCS_CS_KEY_RESP_STATUS_MASK;
+ }
+
+ if (status < 0) {
+ *mbox_error = (-status) | (op_status << FCS_CS_KEY_RESP_STATUS_OFFSET);
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ if (resp_len > 1) {
+
+ /* Export key object is start at second response data */
+ *dst_size = (resp_len - 1) * MBOX_WORD_BYTE;
+
+ for (i = 1U; i < resp_len; i++) {
+ mmio_write_32(dst_addr, resp_data[i]);
+ dst_addr += MBOX_WORD_BYTE;
+ }
+
+ flush_dcache_range(dst_addr - *dst_size, *dst_size);
+
+ } else {
+
+ /* Unexpected response, missing key object in response */
+ *mbox_error = MBOX_RET_ERROR;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_remove_crypto_service_key(uint32_t session_id, uint32_t key_id,
+ uint32_t *mbox_error)
+{
+ int status;
+ uint32_t payload_size;
+ uint32_t resp_len = 1U;
+ uint32_t resp_data = 0U;
+ uint32_t op_status = 0U;
+
+ if (mbox_error == NULL) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ fcs_cs_key_payload payload = {
+ session_id,
+ RESERVED_AS_ZERO,
+ RESERVED_AS_ZERO,
+ key_id
+ };
+
+ payload_size = sizeof(payload) / MBOX_WORD_BYTE;
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_FCS_REMOVE_CS_KEY,
+ (uint32_t *) &payload, payload_size,
+ CMD_CASUAL, &resp_data, &resp_len);
+
+ if (resp_len > 0) {
+ op_status = resp_data & FCS_CS_KEY_RESP_STATUS_MASK;
+ }
+
+ if (status < 0) {
+ *mbox_error = (-status) | (op_status << FCS_CS_KEY_RESP_STATUS_OFFSET);
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_get_crypto_service_key_info(uint32_t session_id, uint32_t key_id,
+ uint64_t dst_addr, uint32_t *dst_size,
+ uint32_t *mbox_error)
+{
+ int status;
+ uint32_t payload_size;
+ uint32_t resp_len = FCS_CS_KEY_INFO_MAX_WORD_SIZE;
+ uint32_t op_status = 0U;
+
+ if ((dst_size == NULL) || (mbox_error == NULL)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_address_in_ddr_range(dst_addr, *dst_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ fcs_cs_key_payload payload = {
+ session_id,
+ RESERVED_AS_ZERO,
+ RESERVED_AS_ZERO,
+ key_id
+ };
+
+ payload_size = sizeof(payload) / MBOX_WORD_BYTE;
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_FCS_GET_CS_KEY_INFO,
+ (uint32_t *) &payload, payload_size,
+ CMD_CASUAL, (uint32_t *) dst_addr, &resp_len);
+
+ if (resp_len > 0) {
+ op_status = mmio_read_32(dst_addr) &
+ FCS_CS_KEY_RESP_STATUS_MASK;
+ }
+
+ if (status < 0) {
+ *mbox_error = (-status) | (op_status << FCS_CS_KEY_RESP_STATUS_OFFSET);
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *dst_size = resp_len * MBOX_WORD_BYTE;
+ flush_dcache_range(dst_addr, *dst_size);
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_get_digest_init(uint32_t session_id, uint32_t context_id,
+ uint32_t key_id, uint32_t param_size,
+ uint64_t param_data, uint32_t *mbox_error)
+{
+ return intel_fcs_crypto_service_init(session_id, context_id,
+ key_id, param_size, param_data,
+ (void *) &fcs_sha_get_digest_param,
+ mbox_error);
+}
+
+int intel_fcs_get_digest_update_finalize(uint32_t session_id,
+ uint32_t context_id, uint32_t src_addr,
+ uint32_t src_size, uint64_t dst_addr,
+ uint32_t *dst_size, uint8_t is_finalised,
+ uint32_t *mbox_error)
+{
+ int status;
+ uint32_t i;
+ uint32_t flag;
+ uint32_t crypto_header;
+ uint32_t resp_len;
+ uint32_t payload[FCS_GET_DIGEST_CMD_MAX_WORD_SIZE] = {0U};
+
+ if (dst_size == NULL || mbox_error == NULL) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (fcs_sha_get_digest_param.session_id != session_id ||
+ fcs_sha_get_digest_param.context_id != context_id) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ /* Source data must be 8 bytes aligned */
+ if (!is_8_bytes_aligned(src_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_address_in_ddr_range(src_addr, src_size) ||
+ !is_address_in_ddr_range(dst_addr, *dst_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ resp_len = *dst_size / MBOX_WORD_BYTE;
+
+ /* Prepare crypto header */
+ flag = 0;
+
+ if (fcs_sha_get_digest_param.is_updated) {
+ fcs_sha_get_digest_param.crypto_param_size = 0;
+ } else {
+ flag |= FCS_CS_FIELD_FLAG_INIT;
+ }
+
+ if (is_finalised != 0U) {
+ flag |= FCS_CS_FIELD_FLAG_FINALIZE;
+ } else {
+ flag |= FCS_CS_FIELD_FLAG_UPDATE;
+ fcs_sha_get_digest_param.is_updated = 1;
+ }
+
+ crypto_header = ((flag << FCS_CS_FIELD_FLAG_OFFSET) |
+ (fcs_sha_get_digest_param.crypto_param_size &
+ FCS_CS_FIELD_SIZE_MASK));
+
+ /* Prepare command payload */
+ i = 0;
+ payload[i] = fcs_sha_get_digest_param.session_id;
+ i++;
+ payload[i] = fcs_sha_get_digest_param.context_id;
+ i++;
+ payload[i] = crypto_header;
+ i++;
+
+ if ((crypto_header >> FCS_CS_FIELD_FLAG_OFFSET) &
+ FCS_CS_FIELD_FLAG_INIT) {
+ payload[i] = fcs_sha_get_digest_param.key_id;
+ i++;
+ /* Crypto parameters */
+ payload[i] = fcs_sha_get_digest_param.crypto_param
+ & INTEL_SIP_SMC_FCS_SHA_MODE_MASK;
+ payload[i] |= ((fcs_sha_get_digest_param.crypto_param
+ >> INTEL_SIP_SMC_FCS_DIGEST_SIZE_OFFSET)
+ & INTEL_SIP_SMC_FCS_DIGEST_SIZE_MASK)
+ << FCS_SHA_HMAC_CRYPTO_PARAM_SIZE_OFFSET;
+ i++;
+ }
+ /* Data source address and size */
+ payload[i] = src_addr;
+ i++;
+ payload[i] = src_size;
+ i++;
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_FCS_GET_DIGEST_REQ,
+ payload, i, CMD_CASUAL,
+ (uint32_t *) dst_addr, &resp_len);
+
+ if (is_finalised != 0U) {
+ memset((void *)&fcs_sha_get_digest_param, 0,
+ sizeof(fcs_crypto_service_data));
+ }
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *dst_size = resp_len * MBOX_WORD_BYTE;
+ flush_dcache_range(dst_addr, *dst_size);
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_mac_verify_init(uint32_t session_id, uint32_t context_id,
+ uint32_t key_id, uint32_t param_size,
+ uint64_t param_data, uint32_t *mbox_error)
+{
+ return intel_fcs_crypto_service_init(session_id, context_id,
+ key_id, param_size, param_data,
+ (void *) &fcs_sha_mac_verify_param,
+ mbox_error);
+}
+
+int intel_fcs_mac_verify_update_finalize(uint32_t session_id,
+ uint32_t context_id, uint32_t src_addr,
+ uint32_t src_size, uint64_t dst_addr,
+ uint32_t *dst_size, uint32_t data_size,
+ uint8_t is_finalised, uint32_t *mbox_error)
+{
+ int status;
+ uint32_t i;
+ uint32_t flag;
+ uint32_t crypto_header;
+ uint32_t resp_len;
+ uint32_t payload[FCS_MAC_VERIFY_CMD_MAX_WORD_SIZE] = {0U};
+ uintptr_t mac_offset;
+
+ if (dst_size == NULL || mbox_error == NULL) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (fcs_sha_mac_verify_param.session_id != session_id ||
+ fcs_sha_mac_verify_param.context_id != context_id) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (data_size > src_size) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_size_4_bytes_aligned(src_size) ||
+ !is_8_bytes_aligned(data_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_address_in_ddr_range(src_addr, src_size) ||
+ !is_address_in_ddr_range(dst_addr, *dst_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ resp_len = *dst_size / MBOX_WORD_BYTE;
+
+ /* Prepare crypto header */
+ flag = 0;
+
+ if (fcs_sha_mac_verify_param.is_updated) {
+ fcs_sha_mac_verify_param.crypto_param_size = 0;
+ } else {
+ flag |= FCS_CS_FIELD_FLAG_INIT;
+ }
+
+ if (is_finalised) {
+ flag |= FCS_CS_FIELD_FLAG_FINALIZE;
+ } else {
+ flag |= FCS_CS_FIELD_FLAG_UPDATE;
+ fcs_sha_mac_verify_param.is_updated = 1;
+ }
+
+ crypto_header = ((flag << FCS_CS_FIELD_FLAG_OFFSET) |
+ (fcs_sha_mac_verify_param.crypto_param_size &
+ FCS_CS_FIELD_SIZE_MASK));
+
+ /* Prepare command payload */
+ i = 0;
+ payload[i] = fcs_sha_mac_verify_param.session_id;
+ i++;
+ payload[i] = fcs_sha_mac_verify_param.context_id;
+ i++;
+ payload[i] = crypto_header;
+ i++;
+
+ if ((crypto_header >> FCS_CS_FIELD_FLAG_OFFSET) &
+ FCS_CS_FIELD_FLAG_INIT) {
+ payload[i] = fcs_sha_mac_verify_param.key_id;
+ i++;
+ /* Crypto parameters */
+ payload[i] = ((fcs_sha_mac_verify_param.crypto_param
+ >> INTEL_SIP_SMC_FCS_DIGEST_SIZE_OFFSET)
+ & INTEL_SIP_SMC_FCS_DIGEST_SIZE_MASK)
+ << FCS_SHA_HMAC_CRYPTO_PARAM_SIZE_OFFSET;
+ i++;
+ }
+ /* Data source address and size */
+ payload[i] = src_addr;
+ i++;
+ payload[i] = data_size;
+ i++;
+
+ if ((crypto_header >> FCS_CS_FIELD_FLAG_OFFSET) &
+ FCS_CS_FIELD_FLAG_FINALIZE) {
+ /* Copy mac data to command */
+ mac_offset = src_addr + data_size;
+ memcpy((uint8_t *) &payload[i], (uint8_t *) mac_offset,
+ src_size - data_size);
+
+ i += (src_size - data_size) / MBOX_WORD_BYTE;
+ }
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_FCS_MAC_VERIFY_REQ,
+ payload, i, CMD_CASUAL,
+ (uint32_t *) dst_addr, &resp_len);
+
+ if (is_finalised) {
+ memset((void *)&fcs_sha_mac_verify_param, 0,
+ sizeof(fcs_crypto_service_data));
+ }
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *dst_size = resp_len * MBOX_WORD_BYTE;
+ flush_dcache_range(dst_addr, *dst_size);
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_ecdsa_hash_sign_init(uint32_t session_id, uint32_t context_id,
+ uint32_t key_id, uint32_t param_size,
+ uint64_t param_data, uint32_t *mbox_error)
+{
+ return intel_fcs_crypto_service_init(session_id, context_id,
+ key_id, param_size, param_data,
+ (void *) &fcs_ecdsa_hash_sign_param,
+ mbox_error);
+}
+
+int intel_fcs_ecdsa_hash_sign_finalize(uint32_t session_id, uint32_t context_id,
+ uint32_t src_addr, uint32_t src_size,
+ uint64_t dst_addr, uint32_t *dst_size,
+ uint32_t *mbox_error)
+{
+ int status;
+ uint32_t i;
+ uint32_t payload[FCS_ECDSA_HASH_SIGN_CMD_MAX_WORD_SIZE] = {0U};
+ uint32_t resp_len;
+ uintptr_t hash_data_addr;
+
+ if ((dst_size == NULL) || (mbox_error == NULL)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (fcs_ecdsa_hash_sign_param.session_id != session_id ||
+ fcs_ecdsa_hash_sign_param.context_id != context_id) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_address_in_ddr_range(src_addr, src_size) ||
+ !is_address_in_ddr_range(dst_addr, *dst_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ resp_len = *dst_size / MBOX_WORD_BYTE;
+
+ /* Prepare command payload */
+ /* Crypto header */
+ i = 0;
+ payload[i] = fcs_ecdsa_hash_sign_param.session_id;
+ i++;
+ payload[i] = fcs_ecdsa_hash_sign_param.context_id;
+
+ i++;
+ payload[i] = fcs_ecdsa_hash_sign_param.crypto_param_size
+ & FCS_CS_FIELD_SIZE_MASK;
+ payload[i] |= (FCS_CS_FIELD_FLAG_INIT | FCS_CS_FIELD_FLAG_UPDATE
+ | FCS_CS_FIELD_FLAG_FINALIZE)
+ << FCS_CS_FIELD_FLAG_OFFSET;
+ i++;
+ payload[i] = fcs_ecdsa_hash_sign_param.key_id;
+
+ /* Crypto parameters */
+ i++;
+ payload[i] = fcs_ecdsa_hash_sign_param.crypto_param
+ & INTEL_SIP_SMC_FCS_ECC_ALGO_MASK;
+
+ /* Hash Data */
+ i++;
+ hash_data_addr = src_addr;
+ memcpy((uint8_t *) &payload[i], (uint8_t *) hash_data_addr,
+ src_size);
+
+ i += src_size / MBOX_WORD_BYTE;
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_FCS_ECDSA_HASH_SIGN_REQ,
+ payload, i, CMD_CASUAL, (uint32_t *) dst_addr,
+ &resp_len);
+
+ memset((void *) &fcs_ecdsa_hash_sign_param,
+ 0, sizeof(fcs_crypto_service_data));
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *dst_size = resp_len * MBOX_WORD_BYTE;
+ flush_dcache_range(dst_addr, *dst_size);
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_ecdsa_hash_sig_verify_init(uint32_t session_id, uint32_t context_id,
+ uint32_t key_id, uint32_t param_size,
+ uint64_t param_data, uint32_t *mbox_error)
+{
+ return intel_fcs_crypto_service_init(session_id, context_id,
+ key_id, param_size, param_data,
+ (void *) &fcs_ecdsa_hash_sig_verify_param,
+ mbox_error);
+}
+
+int intel_fcs_ecdsa_hash_sig_verify_finalize(uint32_t session_id, uint32_t context_id,
+ uint32_t src_addr, uint32_t src_size,
+ uint64_t dst_addr, uint32_t *dst_size,
+ uint32_t *mbox_error)
+{
+ int status;
+ uint32_t i = 0;
+ uint32_t payload[FCS_ECDSA_HASH_SIG_VERIFY_CMD_MAX_WORD_SIZE] = {0U};
+ uint32_t resp_len;
+ uintptr_t hash_sig_pubkey_addr;
+
+ if ((dst_size == NULL) || (mbox_error == NULL)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (fcs_ecdsa_hash_sig_verify_param.session_id != session_id ||
+ fcs_ecdsa_hash_sig_verify_param.context_id != context_id) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_address_in_ddr_range(src_addr, src_size) ||
+ !is_address_in_ddr_range(dst_addr, *dst_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ resp_len = *dst_size / MBOX_WORD_BYTE;
+
+ /* Prepare command payload */
+ /* Crypto header */
+ i = 0;
+ payload[i] = fcs_ecdsa_hash_sig_verify_param.session_id;
+
+ i++;
+ payload[i] = fcs_ecdsa_hash_sig_verify_param.context_id;
+
+ i++;
+ payload[i] = fcs_ecdsa_hash_sig_verify_param.crypto_param_size
+ & FCS_CS_FIELD_SIZE_MASK;
+ payload[i] |= (FCS_CS_FIELD_FLAG_INIT | FCS_CS_FIELD_FLAG_UPDATE
+ | FCS_CS_FIELD_FLAG_FINALIZE)
+ << FCS_CS_FIELD_FLAG_OFFSET;
+
+ i++;
+ payload[i] = fcs_ecdsa_hash_sig_verify_param.key_id;
+
+ /* Crypto parameters */
+ i++;
+ payload[i] = fcs_ecdsa_hash_sig_verify_param.crypto_param
+ & INTEL_SIP_SMC_FCS_ECC_ALGO_MASK;
+
+ /* Hash Data Word, Signature Data Word and Public Key Data word */
+ i++;
+ hash_sig_pubkey_addr = src_addr;
+ memcpy((uint8_t *) &payload[i],
+ (uint8_t *) hash_sig_pubkey_addr, src_size);
+
+ i += (src_size / MBOX_WORD_BYTE);
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_FCS_ECDSA_HASH_SIG_VERIFY,
+ payload, i, CMD_CASUAL, (uint32_t *) dst_addr,
+ &resp_len);
+
+ memset((void *)&fcs_ecdsa_hash_sig_verify_param,
+ 0, sizeof(fcs_crypto_service_data));
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *dst_size = resp_len * MBOX_WORD_BYTE;
+ flush_dcache_range(dst_addr, *dst_size);
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_ecdsa_sha2_data_sign_init(uint32_t session_id,
+ uint32_t context_id, uint32_t key_id,
+ uint32_t param_size, uint64_t param_data,
+ uint32_t *mbox_error)
+{
+ return intel_fcs_crypto_service_init(session_id, context_id,
+ key_id, param_size, param_data,
+ (void *) &fcs_sha2_data_sign_param,
+ mbox_error);
+}
+
+int intel_fcs_ecdsa_sha2_data_sign_update_finalize(uint32_t session_id,
+ uint32_t context_id, uint32_t src_addr,
+ uint32_t src_size, uint64_t dst_addr,
+ uint32_t *dst_size, uint8_t is_finalised,
+ uint32_t *mbox_error)
+{
+ int status;
+ int i;
+ uint32_t flag;
+ uint32_t crypto_header;
+ uint32_t payload[FCS_ECDSA_SHA2_DATA_SIGN_CMD_MAX_WORD_SIZE] = {0U};
+ uint32_t resp_len;
+
+ if ((dst_size == NULL) || (mbox_error == NULL)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (fcs_sha2_data_sign_param.session_id != session_id ||
+ fcs_sha2_data_sign_param.context_id != context_id) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ /* Source data must be 8 bytes aligned */
+ if (!is_8_bytes_aligned(src_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_address_in_ddr_range(src_addr, src_size) ||
+ !is_address_in_ddr_range(dst_addr, *dst_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ resp_len = *dst_size / MBOX_WORD_BYTE;
+
+ /* Prepare crypto header */
+ flag = 0;
+ if (fcs_sha2_data_sign_param.is_updated) {
+ fcs_sha2_data_sign_param.crypto_param_size = 0;
+ } else {
+ flag |= FCS_CS_FIELD_FLAG_INIT;
+ }
+
+ if (is_finalised != 0U) {
+ flag |= FCS_CS_FIELD_FLAG_FINALIZE;
+ } else {
+ flag |= FCS_CS_FIELD_FLAG_UPDATE;
+ fcs_sha2_data_sign_param.is_updated = 1;
+ }
+ crypto_header = (flag << FCS_CS_FIELD_FLAG_OFFSET) |
+ fcs_sha2_data_sign_param.crypto_param_size;
+
+ /* Prepare command payload */
+ i = 0;
+ payload[i] = fcs_sha2_data_sign_param.session_id;
+ i++;
+ payload[i] = fcs_sha2_data_sign_param.context_id;
+ i++;
+ payload[i] = crypto_header;
+ i++;
+
+ if ((crypto_header >> FCS_CS_FIELD_FLAG_OFFSET) &
+ FCS_CS_FIELD_FLAG_INIT) {
+ payload[i] = fcs_sha2_data_sign_param.key_id;
+ /* Crypto parameters */
+ i++;
+ payload[i] = fcs_sha2_data_sign_param.crypto_param
+ & INTEL_SIP_SMC_FCS_ECC_ALGO_MASK;
+ i++;
+ }
+
+ /* Data source address and size */
+ payload[i] = src_addr;
+ i++;
+ payload[i] = src_size;
+ i++;
+ status = mailbox_send_cmd(MBOX_JOB_ID,
+ MBOX_FCS_ECDSA_SHA2_DATA_SIGN_REQ, payload,
+ i, CMD_CASUAL, (uint32_t *) dst_addr,
+ &resp_len);
+
+ if (is_finalised != 0U) {
+ memset((void *)&fcs_sha2_data_sign_param, 0,
+ sizeof(fcs_crypto_service_data));
+ }
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *dst_size = resp_len * MBOX_WORD_BYTE;
+ flush_dcache_range(dst_addr, *dst_size);
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_ecdsa_sha2_data_sig_verify_init(uint32_t session_id,
+ uint32_t context_id, uint32_t key_id,
+ uint32_t param_size, uint64_t param_data,
+ uint32_t *mbox_error)
+{
+ return intel_fcs_crypto_service_init(session_id, context_id,
+ key_id, param_size, param_data,
+ (void *) &fcs_sha2_data_sig_verify_param,
+ mbox_error);
+}
+
+int intel_fcs_ecdsa_sha2_data_sig_verify_update_finalize(uint32_t session_id,
+ uint32_t context_id, uint32_t src_addr,
+ uint32_t src_size, uint64_t dst_addr,
+ uint32_t *dst_size, uint32_t data_size,
+ uint8_t is_finalised, uint32_t *mbox_error)
+{
+ int status;
+ uint32_t i;
+ uint32_t flag;
+ uint32_t crypto_header;
+ uint32_t payload[FCS_ECDSA_SHA2_DATA_SIG_VERIFY_CMD_MAX_WORD_SIZE] = {0U};
+ uint32_t resp_len;
+ uintptr_t sig_pubkey_offset;
+
+ if ((dst_size == NULL) || (mbox_error == NULL)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (fcs_sha2_data_sig_verify_param.session_id != session_id ||
+ fcs_sha2_data_sig_verify_param.context_id != context_id) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_size_4_bytes_aligned(src_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_8_bytes_aligned(data_size) ||
+ !is_8_bytes_aligned(src_addr)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_address_in_ddr_range(src_addr, src_size) ||
+ !is_address_in_ddr_range(dst_addr, *dst_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ resp_len = *dst_size / MBOX_WORD_BYTE;
+
+ /* Prepare crypto header */
+ flag = 0;
+ if (fcs_sha2_data_sig_verify_param.is_updated)
+ fcs_sha2_data_sig_verify_param.crypto_param_size = 0;
+ else
+ flag |= FCS_CS_FIELD_FLAG_INIT;
+
+ if (is_finalised != 0U)
+ flag |= FCS_CS_FIELD_FLAG_FINALIZE;
+ else {
+ flag |= FCS_CS_FIELD_FLAG_UPDATE;
+ fcs_sha2_data_sig_verify_param.is_updated = 1;
+ }
+ crypto_header = (flag << FCS_CS_FIELD_FLAG_OFFSET) |
+ fcs_sha2_data_sig_verify_param.crypto_param_size;
+
+ /* Prepare command payload */
+ i = 0;
+ payload[i] = fcs_sha2_data_sig_verify_param.session_id;
+ i++;
+ payload[i] = fcs_sha2_data_sig_verify_param.context_id;
+ i++;
+ payload[i] = crypto_header;
+ i++;
+
+ if ((crypto_header >> FCS_CS_FIELD_FLAG_OFFSET) &
+ FCS_CS_FIELD_FLAG_INIT) {
+ payload[i] = fcs_sha2_data_sig_verify_param.key_id;
+ i++;
+ /* Crypto parameters */
+ payload[i] = fcs_sha2_data_sig_verify_param.crypto_param
+ & INTEL_SIP_SMC_FCS_ECC_ALGO_MASK;
+ i++;
+ }
+
+ /* Data source address and size */
+ payload[i] = src_addr;
+ i++;
+ payload[i] = data_size;
+ i++;
+
+ if ((crypto_header >> FCS_CS_FIELD_FLAG_OFFSET) &
+ FCS_CS_FIELD_FLAG_FINALIZE) {
+ /* Signature + Public Key Data */
+ sig_pubkey_offset = src_addr + data_size;
+ memcpy((uint8_t *) &payload[i], (uint8_t *) sig_pubkey_offset,
+ src_size - data_size);
+
+ i += (src_size - data_size) / MBOX_WORD_BYTE;
+ }
+
+ status = mailbox_send_cmd(MBOX_JOB_ID,
+ MBOX_FCS_ECDSA_SHA2_DATA_SIGN_VERIFY, payload, i,
+ CMD_CASUAL, (uint32_t *) dst_addr, &resp_len);
+
+ if (is_finalised != 0U) {
+ memset((void *) &fcs_sha2_data_sig_verify_param, 0,
+ sizeof(fcs_crypto_service_data));
+ }
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *dst_size = resp_len * MBOX_WORD_BYTE;
+ flush_dcache_range(dst_addr, *dst_size);
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_ecdsa_get_pubkey_init(uint32_t session_id, uint32_t context_id,
+ uint32_t key_id, uint32_t param_size,
+ uint64_t param_data, uint32_t *mbox_error)
+{
+ return intel_fcs_crypto_service_init(session_id, context_id,
+ key_id, param_size, param_data,
+ (void *) &fcs_ecdsa_get_pubkey_param,
+ mbox_error);
+}
+
+int intel_fcs_ecdsa_get_pubkey_finalize(uint32_t session_id, uint32_t context_id,
+ uint64_t dst_addr, uint32_t *dst_size,
+ uint32_t *mbox_error)
+{
+ int status;
+ int i;
+ uint32_t crypto_header;
+ uint32_t ret_size;
+ uint32_t payload[FCS_ECDSA_GET_PUBKEY_MAX_WORD_SIZE] = {0U};
+
+ if ((dst_size == NULL) || (mbox_error == NULL)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (fcs_ecdsa_get_pubkey_param.session_id != session_id ||
+ fcs_ecdsa_get_pubkey_param.context_id != context_id) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ ret_size = *dst_size / MBOX_WORD_BYTE;
+
+ crypto_header = ((FCS_CS_FIELD_FLAG_INIT |
+ FCS_CS_FIELD_FLAG_UPDATE |
+ FCS_CS_FIELD_FLAG_FINALIZE) <<
+ FCS_CS_FIELD_FLAG_OFFSET) |
+ fcs_ecdsa_get_pubkey_param.crypto_param_size;
+ i = 0;
+ /* Prepare command payload */
+ payload[i] = session_id;
+ i++;
+ payload[i] = context_id;
+ i++;
+ payload[i] = crypto_header;
+ i++;
+ payload[i] = fcs_ecdsa_get_pubkey_param.key_id;
+ i++;
+ payload[i] = (uint32_t) fcs_ecdsa_get_pubkey_param.crypto_param &
+ INTEL_SIP_SMC_FCS_ECC_ALGO_MASK;
+ i++;
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_FCS_ECDSA_GET_PUBKEY,
+ payload, i, CMD_CASUAL,
+ (uint32_t *) dst_addr, &ret_size);
+
+ memset((void *) &fcs_ecdsa_get_pubkey_param, 0,
+ sizeof(fcs_crypto_service_data));
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *dst_size = ret_size * MBOX_WORD_BYTE;
+ flush_dcache_range(dst_addr, *dst_size);
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_ecdh_request_init(uint32_t session_id, uint32_t context_id,
+ uint32_t key_id, uint32_t param_size,
+ uint64_t param_data, uint32_t *mbox_error)
+{
+ return intel_fcs_crypto_service_init(session_id, context_id,
+ key_id, param_size, param_data,
+ (void *) &fcs_ecdh_request_param,
+ mbox_error);
+}
+
+int intel_fcs_ecdh_request_finalize(uint32_t session_id, uint32_t context_id,
+ uint32_t src_addr, uint32_t src_size,
+ uint64_t dst_addr, uint32_t *dst_size,
+ uint32_t *mbox_error)
+{
+ int status;
+ uint32_t i;
+ uint32_t payload[FCS_ECDH_REQUEST_CMD_MAX_WORD_SIZE] = {0U};
+ uint32_t resp_len;
+ uintptr_t pubkey;
+
+ if ((dst_size == NULL) || (mbox_error == NULL)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (fcs_ecdh_request_param.session_id != session_id ||
+ fcs_ecdh_request_param.context_id != context_id) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_address_in_ddr_range(src_addr, src_size) ||
+ !is_address_in_ddr_range(dst_addr, *dst_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ resp_len = *dst_size / MBOX_WORD_BYTE;
+
+ /* Prepare command payload */
+ i = 0;
+ /* Crypto header */
+ payload[i] = fcs_ecdh_request_param.session_id;
+ i++;
+ payload[i] = fcs_ecdh_request_param.context_id;
+ i++;
+ payload[i] = fcs_ecdh_request_param.crypto_param_size
+ & FCS_CS_FIELD_SIZE_MASK;
+ payload[i] |= (FCS_CS_FIELD_FLAG_INIT | FCS_CS_FIELD_FLAG_UPDATE
+ | FCS_CS_FIELD_FLAG_FINALIZE)
+ << FCS_CS_FIELD_FLAG_OFFSET;
+ i++;
+ payload[i] = fcs_ecdh_request_param.key_id;
+ i++;
+ /* Crypto parameters */
+ payload[i] = fcs_ecdh_request_param.crypto_param
+ & INTEL_SIP_SMC_FCS_ECC_ALGO_MASK;
+ i++;
+ /* Public key data */
+ pubkey = src_addr;
+ memcpy((uint8_t *) &payload[i], (uint8_t *) pubkey, src_size);
+ i += src_size / MBOX_WORD_BYTE;
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_FCS_ECDH_REQUEST,
+ payload, i, CMD_CASUAL, (uint32_t *) dst_addr,
+ &resp_len);
+
+ memset((void *)&fcs_ecdh_request_param, 0,
+ sizeof(fcs_crypto_service_data));
+
+ if (status < 0) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *dst_size = resp_len * MBOX_WORD_BYTE;
+ flush_dcache_range(dst_addr, *dst_size);
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_aes_crypt_init(uint32_t session_id, uint32_t context_id,
+ uint32_t key_id, uint64_t param_addr,
+ uint32_t param_size, uint32_t *mbox_error)
+{
+ if (mbox_error == NULL) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ memset((void *)&fcs_aes_init_payload, 0U, sizeof(fcs_aes_init_payload));
+
+ fcs_aes_init_payload.session_id = session_id;
+ fcs_aes_init_payload.context_id = context_id;
+ fcs_aes_init_payload.param_size = param_size;
+ fcs_aes_init_payload.key_id = key_id;
+
+ memcpy((uint8_t *) fcs_aes_init_payload.crypto_param,
+ (uint8_t *) param_addr, param_size);
+
+ fcs_aes_init_payload.is_updated = 0;
+
+ *mbox_error = 0;
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+int intel_fcs_aes_crypt_update_finalize(uint32_t session_id,
+ uint32_t context_id, uint64_t src_addr,
+ uint32_t src_size, uint64_t dst_addr,
+ uint32_t dst_size, uint8_t is_finalised,
+ uint32_t *send_id)
+{
+ int status;
+ int i;
+ uint32_t flag;
+ uint32_t crypto_header;
+ uint32_t fcs_aes_crypt_payload[FCS_AES_CMD_MAX_WORD_SIZE];
+
+ if (fcs_aes_init_payload.session_id != session_id ||
+ fcs_aes_init_payload.context_id != context_id) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if ((!is_8_bytes_aligned(src_addr)) ||
+ (!is_32_bytes_aligned(src_size)) ||
+ (!is_address_in_ddr_range(src_addr, src_size))) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if ((!is_8_bytes_aligned(dst_addr)) ||
+ (!is_32_bytes_aligned(dst_size))) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if ((dst_size > FCS_AES_MAX_DATA_SIZE ||
+ dst_size < FCS_AES_MIN_DATA_SIZE) ||
+ (src_size > FCS_AES_MAX_DATA_SIZE ||
+ src_size < FCS_AES_MIN_DATA_SIZE)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ /* Prepare crypto header*/
+ flag = 0;
+ if (fcs_aes_init_payload.is_updated) {
+ fcs_aes_init_payload.param_size = 0;
+ } else {
+ flag |= FCS_CS_FIELD_FLAG_INIT;
+ }
+
+ if (is_finalised != 0U) {
+ flag |= FCS_CS_FIELD_FLAG_FINALIZE;
+ } else {
+ flag |= FCS_CS_FIELD_FLAG_UPDATE;
+ fcs_aes_init_payload.is_updated = 1;
+ }
+ crypto_header = (flag << FCS_CS_FIELD_FLAG_OFFSET) |
+ fcs_aes_init_payload.param_size;
+
+ i = 0U;
+ fcs_aes_crypt_payload[i] = session_id;
+ i++;
+ fcs_aes_crypt_payload[i] = context_id;
+ i++;
+ fcs_aes_crypt_payload[i] = crypto_header;
+ i++;
+
+ if ((crypto_header >> FCS_CS_FIELD_FLAG_OFFSET) &
+ FCS_CS_FIELD_FLAG_INIT) {
+ fcs_aes_crypt_payload[i] = fcs_aes_init_payload.key_id;
+ i++;
+
+ memcpy((uint8_t *) &fcs_aes_crypt_payload[i],
+ (uint8_t *) fcs_aes_init_payload.crypto_param,
+ fcs_aes_init_payload.param_size);
+
+ i += fcs_aes_init_payload.param_size / MBOX_WORD_BYTE;
+ }
+
+ fcs_aes_crypt_payload[i] = (uint32_t) src_addr;
+ i++;
+ fcs_aes_crypt_payload[i] = src_size;
+ i++;
+ fcs_aes_crypt_payload[i] = (uint32_t) dst_addr;
+ i++;
+ fcs_aes_crypt_payload[i] = dst_size;
+ i++;
+
+ status = mailbox_send_cmd_async(send_id, MBOX_FCS_AES_CRYPT_REQ,
+ fcs_aes_crypt_payload, i,
+ CMD_INDIRECT);
+
+ if (is_finalised != 0U) {
+ memset((void *)&fcs_aes_init_payload, 0,
+ sizeof(fcs_aes_init_payload));
+ }
+
+ if (status < 0U) {
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
diff --git a/plat/intel/soc/common/soc/socfpga_emac.c b/plat/intel/soc/common/soc/socfpga_emac.c
new file mode 100644
index 0000000..cacfd53
--- /dev/null
+++ b/plat/intel/soc/common/soc/socfpga_emac.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#include "socfpga_emac.h"
+#include "socfpga_reset_manager.h"
+#include "socfpga_system_manager.h"
+
+void socfpga_emac_init(void)
+{
+ mmio_setbits_32(SOCFPGA_RSTMGR(PER0MODRST),
+ RSTMGR_PER0MODRST_EMAC0 |
+ RSTMGR_PER0MODRST_EMAC1 |
+ RSTMGR_PER0MODRST_EMAC2);
+
+ mmio_clrsetbits_32(SOCFPGA_SYSMGR(EMAC_0),
+ PHY_INTF_SEL_MSK, EMAC0_PHY_MODE);
+ mmio_clrsetbits_32(SOCFPGA_SYSMGR(EMAC_1),
+ PHY_INTF_SEL_MSK, EMAC1_PHY_MODE);
+ mmio_clrsetbits_32(SOCFPGA_SYSMGR(EMAC_2),
+ PHY_INTF_SEL_MSK, EMAC2_PHY_MODE);
+
+ mmio_clrbits_32(SOCFPGA_SYSMGR(FPGAINTF_EN_3),
+ FPGAINTF_EN_3_EMAC_MSK(0) |
+ FPGAINTF_EN_3_EMAC_MSK(1) |
+ FPGAINTF_EN_3_EMAC_MSK(2));
+
+ mmio_clrbits_32(SOCFPGA_RSTMGR(PER0MODRST),
+ RSTMGR_PER0MODRST_EMAC0 |
+ RSTMGR_PER0MODRST_EMAC1 |
+ RSTMGR_PER0MODRST_EMAC2);
+}
+
diff --git a/plat/intel/soc/common/soc/socfpga_firewall.c b/plat/intel/soc/common/soc/socfpga_firewall.c
new file mode 100644
index 0000000..515784b
--- /dev/null
+++ b/plat/intel/soc/common/soc/socfpga_firewall.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include "socfpga_noc.h"
+#include "socfpga_plat_def.h"
+#include "socfpga_system_manager.h"
+
+void enable_nonsecure_access(void)
+{
+ enable_ns_peripheral_access();
+ enable_ns_bridge_access();
+}
+
+void enable_ns_peripheral_access(void)
+{
+ mmio_write_32(SOCFPGA_L4_PER_SCR(NAND_REGISTER), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_PER_SCR(NAND_DATA), DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(NAND_ECC), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(NAND_READ_ECC), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(NAND_WRITE_ECC),
+ DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_PER_SCR(USB0_REGISTER), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_PER_SCR(USB1_REGISTER), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(USB0_ECC), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(USB1_ECC), DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_PER_SCR(SPI_MASTER0), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_PER_SCR(SPI_MASTER1), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_PER_SCR(SPI_SLAVE0), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_PER_SCR(SPI_SLAVE1), DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_PER_SCR(EMAC0), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_PER_SCR(EMAC1), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_PER_SCR(EMAC2), DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(EMAC0RX_ECC), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(EMAC0TX_ECC), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(EMAC1RX_ECC), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(EMAC1TX_ECC), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(EMAC2RX_ECC), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(EMAC2TX_ECC), DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_PER_SCR(SDMMC), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(SDMMC_ECC), DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_PER_SCR(GPIO0), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_PER_SCR(GPIO1), DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_PER_SCR(I2C0), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_PER_SCR(I2C1), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_PER_SCR(I2C2), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_PER_SCR(I2C3), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_PER_SCR(I2C4), DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_PER_SCR(SP_TIMER1), DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_PER_SCR(UART0), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_PER_SCR(UART1), DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(DMA_ECC), DISABLE_L4_FIREWALL);
+
+
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(OCRAM_ECC), DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(CLK_MGR), DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(IO_MGR), DISABLE_L4_FIREWALL);
+
+
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(RST_MGR), DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(SYS_MGR), DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(OSC0_TIMER), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(OSC1_TIMER), DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(WATCHDOG0), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(WATCHDOG1), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(WATCHDOG2), DISABLE_L4_FIREWALL);
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(WATCHDOG3), DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(DAP), DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(L4_NOC_PROBES), DISABLE_L4_FIREWALL);
+
+ mmio_write_32(SOCFPGA_L4_SYS_SCR(L4_NOC_QOS), DISABLE_L4_FIREWALL);
+
+#if PLATFORM_MODEL == PLAT_SOCFPGA_STRATIX10
+ enable_ns_ocram_access();
+ mmio_write_32(SOCFPGA_SYSMGR(SDMMC), SYSMGR_SDMMC_DRVSEL(3));
+#endif
+
+}
+
+void enable_ns_ocram_access(void)
+{
+ mmio_clrbits_32(SOCFPGA_CCU_NOC(CPU0, RAM0),
+ SOCFPGA_CCU_NOC_ADMASK_P_MASK | SOCFPGA_CCU_NOC_ADMASK_NS_MASK);
+ mmio_clrbits_32(SOCFPGA_CCU_NOC(IOM, RAM0),
+ SOCFPGA_CCU_NOC_ADMASK_P_MASK | SOCFPGA_CCU_NOC_ADMASK_NS_MASK);
+}
+
+void enable_ns_bridge_access(void)
+{
+ mmio_write_32(SOCFPGA_SOC2FPGA_SCR_REG_BASE, DISABLE_BRIDGE_FIREWALL);
+ mmio_write_32(SOCFPGA_LWSOC2FPGA_SCR_REG_BASE, DISABLE_BRIDGE_FIREWALL);
+}
+
+void enable_ocram_firewall(void)
+{
+ mmio_setbits_32(SOCFPGA_CCU_NOC(CPU0, RAM0),
+ SOCFPGA_CCU_NOC_ADMASK_P_MASK | SOCFPGA_CCU_NOC_ADMASK_NS_MASK);
+ mmio_setbits_32(SOCFPGA_CCU_NOC(IOM, RAM0),
+ SOCFPGA_CCU_NOC_ADMASK_P_MASK | SOCFPGA_CCU_NOC_ADMASK_NS_MASK);
+}
diff --git a/plat/intel/soc/common/soc/socfpga_handoff.c b/plat/intel/soc/common/soc/socfpga_handoff.c
new file mode 100644
index 0000000..4bb3a96
--- /dev/null
+++ b/plat/intel/soc/common/soc/socfpga_handoff.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include "socfpga_handoff.h"
+
+#define SWAP_UINT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | \
+ (((x) & 0x0000FF00) << 8) | ((x) << 24))
+
+int socfpga_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;
+}
diff --git a/plat/intel/soc/common/soc/socfpga_mailbox.c b/plat/intel/soc/common/soc/socfpga_mailbox.c
new file mode 100644
index 0000000..79817e6
--- /dev/null
+++ b/plat/intel/soc/common/soc/socfpga_mailbox.c
@@ -0,0 +1,647 @@
+/*
+ * Copyright (c) 2020-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+
+#include "socfpga_mailbox.h"
+#include "socfpga_sip_svc.h"
+
+static mailbox_payload_t mailbox_resp_payload;
+static mailbox_container_t mailbox_resp_ctr = {0, 0, &mailbox_resp_payload};
+
+static bool is_mailbox_cmdbuf_full(uint32_t cin)
+{
+ uint32_t cout = mmio_read_32(MBOX_OFFSET + MBOX_COUT);
+
+ return (((cin + 1U) % MBOX_CMD_BUFFER_SIZE) == cout);
+}
+
+static bool is_mailbox_cmdbuf_empty(uint32_t cin)
+{
+ uint32_t cout = mmio_read_32(MBOX_OFFSET + MBOX_COUT);
+
+ return (((cout + 1U) % MBOX_CMD_BUFFER_SIZE) == cin);
+}
+
+static int wait_for_mailbox_cmdbuf_empty(uint32_t cin)
+{
+ unsigned int timeout = 200U;
+
+ do {
+ if (is_mailbox_cmdbuf_empty(cin)) {
+ break;
+ }
+ mdelay(10U);
+ } while (--timeout != 0U);
+
+ if (timeout == 0U) {
+ return MBOX_TIMEOUT;
+ }
+
+ return MBOX_RET_OK;
+}
+
+static int write_mailbox_cmd_buffer(uint32_t *cin, uint32_t cout,
+ uint32_t data,
+ bool *is_doorbell_triggered)
+{
+ unsigned int timeout = 100U;
+
+ do {
+ if (is_mailbox_cmdbuf_full(*cin)) {
+ if (!(*is_doorbell_triggered)) {
+ mmio_write_32(MBOX_OFFSET +
+ MBOX_DOORBELL_TO_SDM, 1U);
+ *is_doorbell_triggered = true;
+ }
+ mdelay(10U);
+ } else {
+ mmio_write_32(MBOX_ENTRY_TO_ADDR(CMD, (*cin)++), data);
+ *cin %= MBOX_CMD_BUFFER_SIZE;
+ mmio_write_32(MBOX_OFFSET + MBOX_CIN, *cin);
+ break;
+ }
+ } while (--timeout != 0U);
+
+ if (timeout == 0U) {
+ return MBOX_TIMEOUT;
+ }
+
+ if (*is_doorbell_triggered) {
+ int ret = wait_for_mailbox_cmdbuf_empty(*cin);
+ return ret;
+ }
+
+ return MBOX_RET_OK;
+}
+
+static int fill_mailbox_circular_buffer(uint32_t header_cmd, uint32_t *args,
+ unsigned int len)
+{
+ uint32_t sdm_read_offset, cmd_free_offset;
+ unsigned int i;
+ int ret;
+ bool is_doorbell_triggered = false;
+
+ cmd_free_offset = mmio_read_32(MBOX_OFFSET + MBOX_CIN);
+ sdm_read_offset = mmio_read_32(MBOX_OFFSET + MBOX_COUT);
+
+ ret = write_mailbox_cmd_buffer(&cmd_free_offset, sdm_read_offset,
+ header_cmd, &is_doorbell_triggered);
+ if (ret != 0) {
+ goto restart_mailbox;
+ }
+
+ for (i = 0U; i < len; i++) {
+ is_doorbell_triggered = false;
+ ret = write_mailbox_cmd_buffer(&cmd_free_offset,
+ sdm_read_offset, args[i],
+ &is_doorbell_triggered);
+ if (ret != 0) {
+ goto restart_mailbox;
+ }
+ }
+
+ mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1U);
+
+ return MBOX_RET_OK;
+
+restart_mailbox:
+ /*
+ * Attempt to restart mailbox if the driver not able to write
+ * into mailbox command buffer
+ */
+ if (MBOX_CMD_MASK(header_cmd) != MBOX_CMD_RESTART) {
+ INFO("Mailbox timed out: Attempting mailbox reset\n");
+ ret = mailbox_init();
+
+ if (ret == MBOX_TIMEOUT) {
+ INFO("Error: Mailbox fail to restart\n");
+ }
+ }
+
+ return MBOX_TIMEOUT;
+}
+
+int mailbox_read_response(unsigned int *job_id, uint32_t *response,
+ unsigned int *resp_len)
+{
+ uint32_t rin;
+ uint32_t rout;
+ uint32_t resp_data;
+ unsigned int ret_resp_len;
+
+ if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) == 1U) {
+ mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0U);
+ }
+
+ rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
+ rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
+
+ if (rout != rin) {
+ resp_data = mmio_read_32(MBOX_ENTRY_TO_ADDR(RESP, (rout)++));
+
+ rout %= MBOX_RESP_BUFFER_SIZE;
+ mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
+
+
+ if (MBOX_RESP_CLIENT_ID(resp_data) != MBOX_ATF_CLIENT_ID) {
+ return MBOX_WRONG_ID;
+ }
+
+ *job_id = MBOX_RESP_JOB_ID(resp_data);
+
+ ret_resp_len = MBOX_RESP_LEN(resp_data);
+
+ if (iterate_resp(ret_resp_len, response, resp_len)
+ != MBOX_RET_OK) {
+ return MBOX_TIMEOUT;
+ }
+
+ if (MBOX_RESP_ERR(resp_data) > 0U) {
+ INFO("Error in response: %x\n", resp_data);
+ return -MBOX_RESP_ERR(resp_data);
+ }
+
+ return MBOX_RET_OK;
+ }
+ return MBOX_NO_RESPONSE;
+}
+
+int mailbox_read_response_async(unsigned int *job_id, uint32_t *header,
+ uint32_t *response, unsigned int *resp_len,
+ uint8_t ignore_client_id)
+{
+ uint32_t rin;
+ uint32_t rout;
+ uint32_t resp_data;
+ uint32_t ret_resp_len = 0;
+ uint8_t is_done = 0;
+
+ if ((mailbox_resp_ctr.flag & MBOX_PAYLOAD_FLAG_BUSY) != 0) {
+ ret_resp_len = MBOX_RESP_LEN(
+ mailbox_resp_ctr.payload->header) -
+ mailbox_resp_ctr.index;
+ }
+
+ if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) == 1U) {
+ mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0U);
+ }
+
+ rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
+ rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
+
+ while (rout != rin && !is_done) {
+
+ resp_data = mmio_read_32(MBOX_ENTRY_TO_ADDR(RESP, (rout)++));
+
+ rout %= MBOX_RESP_BUFFER_SIZE;
+ mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
+ rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
+
+ if ((mailbox_resp_ctr.flag & MBOX_PAYLOAD_FLAG_BUSY) != 0) {
+ mailbox_resp_ctr.payload->data[mailbox_resp_ctr.index] = resp_data;
+ mailbox_resp_ctr.index++;
+ ret_resp_len--;
+ } else {
+ if (!ignore_client_id) {
+ if (MBOX_RESP_CLIENT_ID(resp_data) != MBOX_ATF_CLIENT_ID) {
+ *resp_len = 0;
+ return MBOX_WRONG_ID;
+ }
+ }
+
+ *job_id = MBOX_RESP_JOB_ID(resp_data);
+ ret_resp_len = MBOX_RESP_LEN(resp_data);
+ mailbox_resp_ctr.payload->header = resp_data;
+ mailbox_resp_ctr.flag |= MBOX_PAYLOAD_FLAG_BUSY;
+ }
+
+ if (ret_resp_len == 0) {
+ is_done = 1;
+ }
+ }
+
+ if (is_done != 0) {
+
+ /* copy header data to input address if applicable */
+ if (header != 0) {
+ *header = mailbox_resp_ctr.payload->header;
+ }
+
+ /* copy response data to input buffer if applicable */
+ ret_resp_len = MBOX_RESP_LEN(mailbox_resp_ctr.payload->header);
+ if ((ret_resp_len > 0) && (response != NULL) && (resp_len != NULL)) {
+ if (*resp_len > ret_resp_len) {
+ *resp_len = ret_resp_len;
+ }
+
+ memcpy((uint8_t *) response,
+ (uint8_t *) mailbox_resp_ctr.payload->data,
+ *resp_len * MBOX_WORD_BYTE);
+ }
+
+ /* reset async response param */
+ mailbox_resp_ctr.index = 0;
+ mailbox_resp_ctr.flag = 0;
+
+ if (MBOX_RESP_ERR(mailbox_resp_ctr.payload->header) > 0U) {
+ INFO("Error in async response: %x\n",
+ mailbox_resp_ctr.payload->header);
+ return -MBOX_RESP_ERR(mailbox_resp_ctr.payload->header);
+ }
+
+ return MBOX_RET_OK;
+ }
+
+ *resp_len = 0;
+ return (mailbox_resp_ctr.flag & MBOX_PAYLOAD_FLAG_BUSY) ? MBOX_BUSY : MBOX_NO_RESPONSE;
+}
+
+int mailbox_poll_response(uint32_t job_id, uint32_t urgent, uint32_t *response,
+ unsigned int *resp_len)
+{
+ unsigned int timeout = 40U;
+ unsigned int sdm_loop = 255U;
+ unsigned int ret_resp_len;
+ uint32_t rin;
+ uint32_t rout;
+ uint32_t resp_data;
+
+ while (sdm_loop != 0U) {
+
+ do {
+ if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM)
+ == 1U) {
+ break;
+ }
+ mdelay(10U);
+ } while (--timeout != 0U);
+
+ if (timeout == 0U) {
+ break;
+ }
+
+ mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0U);
+
+ if ((urgent & 1U) != 0U) {
+ mdelay(5U);
+ if ((mmio_read_32(MBOX_OFFSET + MBOX_STATUS) &
+ MBOX_STATUS_UA_MASK) ^
+ (urgent & MBOX_STATUS_UA_MASK)) {
+ mmio_write_32(MBOX_OFFSET + MBOX_URG, 0U);
+ return MBOX_RET_OK;
+ }
+
+ mmio_write_32(MBOX_OFFSET + MBOX_URG, 0U);
+ INFO("Error: Mailbox did not get UA");
+ return MBOX_RET_ERROR;
+ }
+
+ rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
+ rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
+
+ while (rout != rin) {
+ resp_data = mmio_read_32(MBOX_ENTRY_TO_ADDR(RESP,
+ (rout)++));
+
+ rout %= MBOX_RESP_BUFFER_SIZE;
+ mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
+
+ if (MBOX_RESP_CLIENT_ID(resp_data) != MBOX_ATF_CLIENT_ID
+ || MBOX_RESP_JOB_ID(resp_data) != job_id) {
+ continue;
+ }
+
+ ret_resp_len = MBOX_RESP_LEN(resp_data);
+
+ if (iterate_resp(ret_resp_len, response, resp_len)
+ != MBOX_RET_OK) {
+ return MBOX_TIMEOUT;
+ }
+
+ if (MBOX_RESP_ERR(resp_data) > 0U) {
+ INFO("Error in response: %x\n", resp_data);
+ return -MBOX_RESP_ERR(resp_data);
+ }
+
+ return MBOX_RET_OK;
+ }
+
+ sdm_loop--;
+ }
+
+ INFO("Timed out waiting for SDM\n");
+ return MBOX_TIMEOUT;
+}
+
+int iterate_resp(uint32_t mbox_resp_len, uint32_t *resp_buf,
+ unsigned int *resp_len)
+{
+ unsigned int timeout, total_resp_len = 0U;
+ uint32_t resp_data;
+ uint32_t rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
+ uint32_t rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
+
+ while (mbox_resp_len > 0U) {
+ timeout = 100U;
+ mbox_resp_len--;
+ resp_data = mmio_read_32(MBOX_ENTRY_TO_ADDR(RESP, (rout)++));
+
+ if ((resp_buf != NULL) && (resp_len != NULL)
+ && (*resp_len != 0U)) {
+ *(resp_buf + total_resp_len)
+ = resp_data;
+ *resp_len = *resp_len - 1;
+ total_resp_len++;
+ }
+ rout %= MBOX_RESP_BUFFER_SIZE;
+ mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
+
+ do {
+ rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
+ if (rout == rin) {
+ mdelay(10U);
+ } else {
+ break;
+ }
+ timeout--;
+ } while ((mbox_resp_len > 0U) && (timeout != 0U));
+
+ if (timeout == 0U) {
+ INFO("Timed out waiting for SDM\n");
+ return MBOX_TIMEOUT;
+ }
+ }
+
+ if (resp_len)
+ *resp_len = total_resp_len;
+
+ return MBOX_RET_OK;
+}
+
+int mailbox_send_cmd_async_ext(uint32_t header_cmd, uint32_t *args,
+ unsigned int len)
+{
+ return fill_mailbox_circular_buffer(header_cmd, args, len);
+}
+
+int mailbox_send_cmd_async(uint32_t *job_id, uint32_t cmd, uint32_t *args,
+ unsigned int len, unsigned int indirect)
+{
+ int status;
+
+ status = 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(indirect) |
+ cmd, args, len);
+ if (status < 0) {
+ return status;
+ }
+
+ *job_id = (*job_id + 1U) % MBOX_MAX_IND_JOB_ID;
+
+ return MBOX_RET_OK;
+}
+
+int mailbox_send_cmd(uint32_t job_id, uint32_t cmd, uint32_t *args,
+ unsigned int len, uint32_t urgent, uint32_t *response,
+ unsigned int *resp_len)
+{
+ int status = 0;
+
+ if (urgent != 0U) {
+ urgent |= mmio_read_32(MBOX_OFFSET + MBOX_STATUS) &
+ MBOX_STATUS_UA_MASK;
+ mmio_write_32(MBOX_OFFSET + MBOX_URG, cmd);
+ mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1U);
+ }
+
+ else {
+ status = fill_mailbox_circular_buffer(
+ MBOX_CLIENT_ID_CMD(MBOX_ATF_CLIENT_ID) |
+ MBOX_JOB_ID_CMD(job_id) |
+ MBOX_CMD_LEN_CMD(len) |
+ cmd, args, len);
+ }
+
+ if (status != 0) {
+ return status;
+ }
+
+ status = mailbox_poll_response(job_id, urgent, response, resp_len);
+
+ return status;
+}
+
+void mailbox_clear_response(void)
+{
+ mmio_write_32(MBOX_OFFSET + MBOX_ROUT,
+ mmio_read_32(MBOX_OFFSET + MBOX_RIN));
+}
+
+void mailbox_set_int(uint32_t 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, NULL, 0U,
+ CMD_CASUAL, NULL, NULL);
+}
+
+void mailbox_set_qspi_direct(void)
+{
+ mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_DIRECT, NULL, 0U,
+ CMD_CASUAL, NULL, NULL);
+}
+
+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, NULL, 0U,
+ CMD_CASUAL, NULL, NULL);
+}
+
+void mailbox_qspi_set_cs(uint32_t device_select)
+{
+ uint32_t cs_setting;
+
+ /* QSPI device select settings at 31:28 */
+ cs_setting = (device_select << 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,
+ 1U, CMD_CASUAL, NULL, NULL);
+}
+
+void mailbox_hps_qspi_enable(void)
+{
+ mailbox_set_qspi_open();
+ mailbox_set_qspi_direct();
+}
+
+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, NULL, 0U,
+ CMD_CASUAL, NULL, NULL);
+}
+
+int mailbox_rsu_get_spt_offset(uint32_t *resp_buf, unsigned int resp_buf_len)
+{
+ return mailbox_send_cmd(MBOX_JOB_ID, MBOX_GET_SUBPARTITION_TABLE,
+ NULL, 0U, CMD_CASUAL, resp_buf,
+ &resp_buf_len);
+}
+
+struct rsu_status_info {
+ uint64_t current_image;
+ uint64_t fail_image;
+ uint32_t state;
+ uint32_t version;
+ uint32_t error_location;
+ uint32_t error_details;
+ uint32_t retry_counter;
+};
+
+int mailbox_rsu_status(uint32_t *resp_buf, unsigned int resp_buf_len)
+{
+ int ret;
+ struct rsu_status_info *info = (struct rsu_status_info *)resp_buf;
+
+ info->retry_counter = ~0U;
+
+ ret = mailbox_send_cmd(MBOX_JOB_ID, MBOX_RSU_STATUS, NULL, 0U,
+ CMD_CASUAL, resp_buf,
+ &resp_buf_len);
+
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (info->retry_counter != ~0U) {
+ if ((info->version & RSU_VERSION_ACMF_MASK) == 0U) {
+ info->version |= RSU_VERSION_ACMF;
+ }
+ }
+
+ return ret;
+}
+
+int mailbox_rsu_update(uint32_t *flash_offset)
+{
+ return mailbox_send_cmd(MBOX_JOB_ID, MBOX_RSU_UPDATE,
+ flash_offset, 2U,
+ CMD_CASUAL, NULL, NULL);
+}
+
+int mailbox_hps_stage_notify(uint32_t execution_stage)
+{
+ return mailbox_send_cmd(MBOX_JOB_ID, MBOX_HPS_STAGE_NOTIFY,
+ &execution_stage, 1U, CMD_CASUAL,
+ NULL, NULL);
+}
+
+int mailbox_init(void)
+{
+ int status;
+
+ mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE |
+ MBOX_INT_FLAG_UAE);
+ mmio_write_32(MBOX_OFFSET + MBOX_URG, 0U);
+ mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0U);
+
+ status = mailbox_send_cmd(0U, MBOX_CMD_RESTART, NULL, 0U,
+ CMD_URGENT, NULL, NULL);
+
+ if (status != 0) {
+ return status;
+ }
+
+ mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE |
+ MBOX_INT_FLAG_UAE);
+
+ return MBOX_RET_OK;
+}
+
+int intel_mailbox_get_config_status(uint32_t cmd, bool init_done)
+{
+ int status;
+ uint32_t res, response[6];
+ unsigned int resp_len = ARRAY_SIZE(response);
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, cmd, NULL, 0U, CMD_CASUAL,
+ response, &resp_len);
+
+ if (status < 0) {
+ return status;
+ }
+
+ res = response[RECONFIG_STATUS_STATE];
+ if ((res != 0U) && (res != MBOX_CFGSTAT_STATE_CONFIG)) {
+ return res;
+ }
+
+ res = response[RECONFIG_STATUS_PIN_STATUS];
+ if ((res & PIN_STATUS_NSTATUS) == 0U) {
+ return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
+ }
+
+ res = response[RECONFIG_STATUS_SOFTFUNC_STATUS];
+ if ((res & SOFTFUNC_STATUS_SEU_ERROR) != 0U) {
+ return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
+ }
+
+ if ((res & SOFTFUNC_STATUS_CONF_DONE) == 0U) {
+ return MBOX_CFGSTAT_STATE_CONFIG;
+ }
+
+ if (init_done && (res & SOFTFUNC_STATUS_INIT_DONE) == 0U) {
+ return MBOX_CFGSTAT_STATE_CONFIG;
+ }
+
+ return MBOX_RET_OK;
+}
+
+int intel_mailbox_is_fpga_not_ready(void)
+{
+ int ret = intel_mailbox_get_config_status(MBOX_RECONFIG_STATUS, true);
+
+ if ((ret != MBOX_RET_OK) && (ret != MBOX_CFGSTAT_STATE_CONFIG)) {
+ ret = intel_mailbox_get_config_status(MBOX_CONFIG_STATUS,
+ false);
+ }
+
+ return ret;
+}
+
+int mailbox_hwmon_readtemp(uint32_t chan, uint32_t *resp_buf)
+{
+ unsigned int resp_len = sizeof(resp_buf);
+
+ return mailbox_send_cmd(MBOX_JOB_ID, MBOX_HWMON_READTEMP, &chan, 1U,
+ CMD_CASUAL, resp_buf,
+ &resp_len);
+
+}
+
+int mailbox_hwmon_readvolt(uint32_t chan, uint32_t *resp_buf)
+{
+ unsigned int resp_len = sizeof(resp_buf);
+
+ return mailbox_send_cmd(MBOX_JOB_ID, MBOX_HWMON_READVOLT, &chan, 1U,
+ CMD_CASUAL, resp_buf,
+ &resp_len);
+}
diff --git a/plat/intel/soc/common/soc/socfpga_reset_manager.c b/plat/intel/soc/common/soc/socfpga_reset_manager.c
new file mode 100644
index 0000000..bb4efab
--- /dev/null
+++ b/plat/intel/soc/common/soc/socfpga_reset_manager.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include "socfpga_f2sdram_manager.h"
+#include "socfpga_mailbox.h"
+#include "socfpga_reset_manager.h"
+#include "socfpga_system_manager.h"
+
+
+void deassert_peripheral_reset(void)
+{
+ mmio_clrbits_32(SOCFPGA_RSTMGR(PER1MODRST),
+ RSTMGR_FIELD(PER1, WATCHDOG0) |
+ RSTMGR_FIELD(PER1, WATCHDOG1) |
+ RSTMGR_FIELD(PER1, WATCHDOG2) |
+ RSTMGR_FIELD(PER1, WATCHDOG3) |
+ RSTMGR_FIELD(PER1, L4SYSTIMER0) |
+ RSTMGR_FIELD(PER1, L4SYSTIMER1) |
+ RSTMGR_FIELD(PER1, SPTIMER0) |
+ RSTMGR_FIELD(PER1, SPTIMER1) |
+ RSTMGR_FIELD(PER1, I2C0) |
+ RSTMGR_FIELD(PER1, I2C1) |
+ RSTMGR_FIELD(PER1, I2C2) |
+ RSTMGR_FIELD(PER1, I2C3) |
+ RSTMGR_FIELD(PER1, I2C4) |
+ RSTMGR_FIELD(PER1, UART0) |
+ RSTMGR_FIELD(PER1, UART1) |
+ RSTMGR_FIELD(PER1, GPIO0) |
+ RSTMGR_FIELD(PER1, GPIO1));
+
+ mmio_clrbits_32(SOCFPGA_RSTMGR(PER0MODRST),
+ RSTMGR_FIELD(PER0, EMAC0OCP) |
+ RSTMGR_FIELD(PER0, EMAC1OCP) |
+ RSTMGR_FIELD(PER0, EMAC2OCP) |
+ RSTMGR_FIELD(PER0, USB0OCP) |
+ RSTMGR_FIELD(PER0, USB1OCP) |
+ RSTMGR_FIELD(PER0, NANDOCP) |
+ RSTMGR_FIELD(PER0, SDMMCOCP) |
+ RSTMGR_FIELD(PER0, DMAOCP));
+
+ mmio_clrbits_32(SOCFPGA_RSTMGR(PER0MODRST),
+ RSTMGR_FIELD(PER0, EMAC0) |
+ RSTMGR_FIELD(PER0, EMAC1) |
+ RSTMGR_FIELD(PER0, EMAC2) |
+ RSTMGR_FIELD(PER0, USB0) |
+ RSTMGR_FIELD(PER0, USB1) |
+ RSTMGR_FIELD(PER0, NAND) |
+ RSTMGR_FIELD(PER0, SDMMC) |
+ RSTMGR_FIELD(PER0, DMA) |
+ RSTMGR_FIELD(PER0, SPIM0) |
+ RSTMGR_FIELD(PER0, SPIM1) |
+ RSTMGR_FIELD(PER0, SPIS0) |
+ RSTMGR_FIELD(PER0, SPIS1) |
+ RSTMGR_FIELD(PER0, EMACPTP) |
+ RSTMGR_FIELD(PER0, DMAIF0) |
+ RSTMGR_FIELD(PER0, DMAIF1) |
+ RSTMGR_FIELD(PER0, DMAIF2) |
+ RSTMGR_FIELD(PER0, DMAIF3) |
+ RSTMGR_FIELD(PER0, DMAIF4) |
+ RSTMGR_FIELD(PER0, DMAIF5) |
+ RSTMGR_FIELD(PER0, DMAIF6) |
+ RSTMGR_FIELD(PER0, DMAIF7));
+
+#if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX
+ mmio_clrbits_32(SOCFPGA_RSTMGR(BRGMODRST),
+ RSTMGR_FIELD(BRG, MPFE));
+#endif
+}
+
+void config_hps_hs_before_warm_reset(void)
+{
+ uint32_t or_mask = 0;
+
+ or_mask |= RSTMGR_HDSKEN_SDRSELFREFEN;
+ or_mask |= RSTMGR_HDSKEN_FPGAHSEN;
+ or_mask |= RSTMGR_HDSKEN_ETRSTALLEN;
+ or_mask |= RSTMGR_HDSKEN_L2FLUSHEN;
+ or_mask |= RSTMGR_HDSKEN_L3NOC_DBG;
+ or_mask |= RSTMGR_HDSKEN_DEBUG_L3NOC;
+
+ mmio_setbits_32(SOCFPGA_RSTMGR(HDSKEN), or_mask);
+}
+
+static int poll_idle_status(uint32_t addr, uint32_t mask, uint32_t match)
+{
+ int time_out = 300;
+
+ while (time_out--) {
+ if ((mmio_read_32(addr) & mask) == match) {
+ return 0;
+ }
+ udelay(1000);
+ }
+ return -ETIMEDOUT;
+}
+
+static void socfpga_s2f_bridge_mask(uint32_t mask,
+ uint32_t *brg_mask,
+ uint32_t *noc_mask)
+{
+ *brg_mask = 0;
+ *noc_mask = 0;
+
+ if ((mask & SOC2FPGA_MASK) != 0U) {
+ *brg_mask |= RSTMGR_FIELD(BRG, SOC2FPGA);
+ *noc_mask |= IDLE_DATA_SOC2FPGA;
+ }
+
+ if ((mask & LWHPS2FPGA_MASK) != 0U) {
+ *brg_mask |= RSTMGR_FIELD(BRG, LWHPS2FPGA);
+ *noc_mask |= IDLE_DATA_LWSOC2FPGA;
+ }
+}
+
+static void socfpga_f2s_bridge_mask(uint32_t mask,
+ uint32_t *brg_mask,
+ uint32_t *f2s_idlereq,
+ uint32_t *f2s_force_drain,
+ uint32_t *f2s_en,
+ uint32_t *f2s_idleack,
+ uint32_t *f2s_respempty)
+{
+ *brg_mask = 0;
+ *f2s_idlereq = 0;
+ *f2s_force_drain = 0;
+ *f2s_en = 0;
+ *f2s_idleack = 0;
+ *f2s_respempty = 0;
+
+#if PLATFORM_MODEL == PLAT_SOCFPGA_STRATIX10
+ if ((mask & FPGA2SOC_MASK) != 0U) {
+ *brg_mask |= RSTMGR_FIELD(BRG, FPGA2SOC);
+ }
+ if ((mask & F2SDRAM0_MASK) != 0U) {
+ *brg_mask |= RSTMGR_FIELD(BRG, F2SSDRAM0);
+ *f2s_idlereq |= FLAGOUTSETCLR_F2SDRAM0_IDLEREQ;
+ *f2s_force_drain |= FLAGOUTSETCLR_F2SDRAM0_FORCE_DRAIN;
+ *f2s_en |= FLAGOUTSETCLR_F2SDRAM0_ENABLE;
+ *f2s_idleack |= FLAGINTSTATUS_F2SDRAM0_IDLEACK;
+ *f2s_respempty |= FLAGINTSTATUS_F2SDRAM0_RESPEMPTY;
+ }
+ if ((mask & F2SDRAM1_MASK) != 0U) {
+ *brg_mask |= RSTMGR_FIELD(BRG, F2SSDRAM1);
+ *f2s_idlereq |= FLAGOUTSETCLR_F2SDRAM1_IDLEREQ;
+ *f2s_force_drain |= FLAGOUTSETCLR_F2SDRAM1_FORCE_DRAIN;
+ *f2s_en |= FLAGOUTSETCLR_F2SDRAM1_ENABLE;
+ *f2s_idleack |= FLAGINTSTATUS_F2SDRAM1_IDLEACK;
+ *f2s_respempty |= FLAGINTSTATUS_F2SDRAM1_RESPEMPTY;
+ }
+ if ((mask & F2SDRAM2_MASK) != 0U) {
+ *brg_mask |= RSTMGR_FIELD(BRG, F2SSDRAM2);
+ *f2s_idlereq |= FLAGOUTSETCLR_F2SDRAM2_IDLEREQ;
+ *f2s_force_drain |= FLAGOUTSETCLR_F2SDRAM2_FORCE_DRAIN;
+ *f2s_en |= FLAGOUTSETCLR_F2SDRAM2_ENABLE;
+ *f2s_idleack |= FLAGINTSTATUS_F2SDRAM2_IDLEACK;
+ *f2s_respempty |= FLAGINTSTATUS_F2SDRAM2_RESPEMPTY;
+ }
+#else
+ if ((mask & FPGA2SOC_MASK) != 0U) {
+ *brg_mask |= RSTMGR_FIELD(BRG, FPGA2SOC);
+ *f2s_idlereq |= FLAGOUTSETCLR_F2SDRAM0_IDLEREQ;
+ *f2s_force_drain |= FLAGOUTSETCLR_F2SDRAM0_FORCE_DRAIN;
+ *f2s_en |= FLAGOUTSETCLR_F2SDRAM0_ENABLE;
+ *f2s_idleack |= FLAGINTSTATUS_F2SDRAM0_IDLEACK;
+ *f2s_respempty |= FLAGINTSTATUS_F2SDRAM0_RESPEMPTY;
+ }
+#endif
+}
+
+int socfpga_bridges_enable(uint32_t mask)
+{
+ int ret = 0;
+ uint32_t brg_mask = 0;
+ uint32_t noc_mask = 0;
+ uint32_t f2s_idlereq = 0;
+ uint32_t f2s_force_drain = 0;
+ uint32_t f2s_en = 0;
+ uint32_t f2s_idleack = 0;
+ uint32_t f2s_respempty = 0;
+
+ /* Enable s2f bridge */
+ socfpga_s2f_bridge_mask(mask, &brg_mask, &noc_mask);
+ if (brg_mask != 0U) {
+ /* Clear idle request */
+ mmio_setbits_32(SOCFPGA_SYSMGR(NOC_IDLEREQ_CLR),
+ noc_mask);
+
+ /* De-assert all bridges */
+ mmio_clrbits_32(SOCFPGA_RSTMGR(BRGMODRST), brg_mask);
+
+ /* Wait until idle ack becomes 0 */
+ ret = poll_idle_status(SOCFPGA_SYSMGR(NOC_IDLEACK),
+ noc_mask, 0);
+ if (ret < 0) {
+ ERROR("S2F bridge enable: "
+ "Timeout waiting for idle ack\n");
+ }
+ }
+
+ /* Enable f2s bridge */
+ socfpga_f2s_bridge_mask(mask, &brg_mask, &f2s_idlereq,
+ &f2s_force_drain, &f2s_en,
+ &f2s_idleack, &f2s_respempty);
+ if (brg_mask != 0U) {
+ mmio_clrbits_32(SOCFPGA_RSTMGR(BRGMODRST), brg_mask);
+
+ mmio_clrbits_32(SOCFPGA_F2SDRAMMGR(SIDEBANDMGR_FLAGOUTSET0),
+ f2s_idlereq);
+
+ ret = poll_idle_status(SOCFPGA_F2SDRAMMGR(
+ SIDEBANDMGR_FLAGINSTATUS0), f2s_idleack, 0);
+ if (ret < 0) {
+ ERROR("F2S bridge enable: "
+ "Timeout waiting for idle ack");
+ }
+
+ mmio_clrbits_32(SOCFPGA_F2SDRAMMGR(SIDEBANDMGR_FLAGOUTSET0),
+ f2s_force_drain);
+ udelay(5);
+
+ mmio_setbits_32(SOCFPGA_F2SDRAMMGR(SIDEBANDMGR_FLAGOUTSET0),
+ f2s_en);
+ udelay(5);
+ }
+
+ return ret;
+}
+
+int socfpga_bridges_disable(uint32_t mask)
+{
+ int ret = 0;
+ int timeout = 300;
+ uint32_t brg_mask = 0;
+ uint32_t noc_mask = 0;
+ uint32_t f2s_idlereq = 0;
+ uint32_t f2s_force_drain = 0;
+ uint32_t f2s_en = 0;
+ uint32_t f2s_idleack = 0;
+ uint32_t f2s_respempty = 0;
+
+ /* Disable s2f bridge */
+ socfpga_s2f_bridge_mask(mask, &brg_mask, &noc_mask);
+ if (brg_mask != 0U) {
+ mmio_setbits_32(SOCFPGA_SYSMGR(NOC_IDLEREQ_SET),
+ noc_mask);
+
+ mmio_write_32(SOCFPGA_SYSMGR(NOC_TIMEOUT), 1);
+
+ ret = poll_idle_status(SOCFPGA_SYSMGR(NOC_IDLEACK),
+ noc_mask, noc_mask);
+ if (ret < 0) {
+ ERROR("S2F Bridge disable: "
+ "Timeout waiting for idle ack\n");
+ }
+
+ ret = poll_idle_status(SOCFPGA_SYSMGR(NOC_IDLESTATUS),
+ noc_mask, noc_mask);
+ if (ret < 0) {
+ ERROR("S2F Bridge disable: "
+ "Timeout waiting for idle status\n");
+ }
+
+ mmio_setbits_32(SOCFPGA_RSTMGR(BRGMODRST), brg_mask);
+
+ mmio_write_32(SOCFPGA_SYSMGR(NOC_TIMEOUT), 0);
+ }
+
+ /* Disable f2s bridge */
+ socfpga_f2s_bridge_mask(mask, &brg_mask, &f2s_idlereq,
+ &f2s_force_drain, &f2s_en,
+ &f2s_idleack, &f2s_respempty);
+ if (brg_mask != 0U) {
+ mmio_setbits_32(SOCFPGA_RSTMGR(HDSKEN),
+ RSTMGR_HDSKEN_FPGAHSEN);
+
+ mmio_setbits_32(SOCFPGA_RSTMGR(HDSKREQ),
+ RSTMGR_HDSKREQ_FPGAHSREQ);
+
+ poll_idle_status(SOCFPGA_RSTMGR(HDSKACK),
+ RSTMGR_HDSKACK_FPGAHSACK_MASK,
+ RSTMGR_HDSKACK_FPGAHSACK_MASK);
+
+ mmio_clrbits_32(SOCFPGA_F2SDRAMMGR(SIDEBANDMGR_FLAGOUTSET0),
+ f2s_en);
+ udelay(5);
+
+ mmio_setbits_32(SOCFPGA_F2SDRAMMGR(SIDEBANDMGR_FLAGOUTSET0),
+ f2s_force_drain);
+ udelay(5);
+
+ do {
+ /* Read response queue status to ensure it is empty */
+ uint32_t idle_status;
+
+ idle_status = mmio_read_32(SOCFPGA_F2SDRAMMGR(
+ SIDEBANDMGR_FLAGINSTATUS0));
+ if ((idle_status & f2s_respempty) != 0U) {
+ idle_status = mmio_read_32(SOCFPGA_F2SDRAMMGR(
+ SIDEBANDMGR_FLAGINSTATUS0));
+ if ((idle_status & f2s_respempty) != 0U) {
+ break;
+ }
+ }
+ udelay(1000);
+ } while (timeout-- > 0);
+
+#if PLATFORM_MODEL == PLAT_SOCFPGA_STRATIX10
+ /* Software must never write a 0x1 to FPGA2SOC_MASK bit */
+ mmio_setbits_32(SOCFPGA_RSTMGR(BRGMODRST),
+ brg_mask & ~RSTMGR_FIELD(BRG, FPGA2SOC));
+#else
+ mmio_setbits_32(SOCFPGA_RSTMGR(BRGMODRST),
+ brg_mask);
+#endif
+ mmio_clrbits_32(SOCFPGA_RSTMGR(HDSKREQ),
+ RSTMGR_HDSKEQ_FPGAHSREQ);
+
+ mmio_setbits_32(SOCFPGA_F2SDRAMMGR(SIDEBANDMGR_FLAGOUTCLR0),
+ f2s_idlereq);
+ }
+
+ return ret;
+}
diff --git a/plat/intel/soc/common/socfpga_delay_timer.c b/plat/intel/soc/common/socfpga_delay_timer.c
new file mode 100644
index 0000000..dcd51e2
--- /dev/null
+++ b/plat/intel/soc/common/socfpga_delay_timer.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <arch_helpers.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include "socfpga_plat_def.h"
+
+#define SOCFPGA_GLOBAL_TIMER 0xffd01000
+#define SOCFPGA_GLOBAL_TIMER_EN 0x3
+
+static timer_ops_t plat_timer_ops;
+/********************************************************************
+ * 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());
+}
+
+void socfpga_delay_timer_init_args(void)
+{
+ plat_timer_ops.get_timer_value = socfpga_get_timer_value;
+ plat_timer_ops.clk_mult = 1;
+ plat_timer_ops.clk_div = PLAT_SYS_COUNTER_FREQ_IN_MHZ;
+
+ timer_init(&plat_timer_ops);
+
+}
+
+void socfpga_delay_timer_init(void)
+{
+ socfpga_delay_timer_init_args();
+ mmio_write_32(SOCFPGA_GLOBAL_TIMER, SOCFPGA_GLOBAL_TIMER_EN);
+
+ asm volatile("msr cntp_ctl_el0, %0" : : "r" (SOCFPGA_GLOBAL_TIMER_EN));
+ asm volatile("msr cntp_tval_el0, %0" : : "r" (~0));
+
+}
diff --git a/plat/intel/soc/common/socfpga_image_load.c b/plat/intel/soc/common/socfpga_image_load.c
new file mode 100644
index 0000000..a5c3279
--- /dev/null
+++ b/plat/intel/soc/common/socfpga_image_load.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/desc_image_load.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)
+{
+ unsigned int count;
+ unsigned int img_id = 0U;
+ unsigned int link_index = 0U;
+ bl_params_node_t *bl_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;
+
+ /* Clean next_params_info in BL image node */
+ for (count = 0U; count < bl_mem_params_desc_num; count++) {
+
+ desc_ptr = &bl_mem_params_desc_ptr[link_index];
+ bl_exec_node = &desc_ptr->params_node_mem;
+ bl_exec_node->next_params_info = NULL;
+
+ /* 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);
+ }
+
+ return get_next_bl_params_from_mem_params_desc();
+}
diff --git a/plat/intel/soc/common/socfpga_psci.c b/plat/intel/soc/common/socfpga_psci.c
new file mode 100644
index 0000000..5fd6559
--- /dev/null
+++ b/plat/intel/soc/common/socfpga_psci.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include "socfpga_mailbox.h"
+#include "socfpga_plat_def.h"
+#include "socfpga_reset_manager.h"
+#include "socfpga_sip_svc.h"
+
+
+/*******************************************************************************
+ * 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;
+
+ mmio_write_64(PLAT_CPUID_RELEASE, cpu_id);
+
+ /* release core reset */
+ mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 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(SOCFPGA_RSTMGR(MPUMODRST), 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(SOCFPGA_RSTMGR(MPUMODRST), 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();
+}
+
+extern uint64_t intel_rsu_update_address;
+
+static void __dead2 socfpga_system_reset(void)
+{
+ uint32_t addr_buf[2];
+
+ memcpy(addr_buf, &intel_rsu_update_address,
+ sizeof(intel_rsu_update_address));
+
+ if (intel_rsu_update_address)
+ mailbox_rsu_update(addr_buf);
+ else
+ mailbox_reset_cold();
+
+ while (1)
+ wfi();
+}
+
+static int socfpga_system_reset2(int is_vendor, int reset_type,
+ u_register_t cookie)
+{
+ if (cold_reset_for_ecc_dbe()) {
+ mailbox_reset_cold();
+ }
+ /* disable cpuif */
+ gicv2_cpuif_disable();
+
+ /* Store magic number */
+ mmio_write_32(L2_RESET_DONE_REG, L2_RESET_DONE_STATUS);
+
+ /* Increase timeout */
+ mmio_write_32(SOCFPGA_RSTMGR(HDSKTIMEOUT), 0xffffff);
+
+ /* Enable handshakes */
+ mmio_setbits_32(SOCFPGA_RSTMGR(HDSKEN), RSTMGR_HDSKEN_SET);
+
+ /* Reset L2 module */
+ mmio_setbits_32(SOCFPGA_RSTMGR(COLDMODRST), 0x100);
+
+ while (1)
+ wfi();
+
+ /* Should not reach here */
+ return 0;
+}
+
+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,
+ .system_reset2 = socfpga_system_reset2,
+ .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.*/
+ mmio_write_64(PLAT_SEC_ENTRY, sec_entrypoint);
+ *psci_ops = &socfpga_psci_pm_ops;
+
+ return 0;
+}
diff --git a/plat/intel/soc/common/socfpga_sip_svc.c b/plat/intel/soc/common/socfpga_sip_svc.c
new file mode 100644
index 0000000..f079349
--- /dev/null
+++ b/plat/intel/soc/common/socfpga_sip_svc.c
@@ -0,0 +1,1131 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+#include <tools_share/uuid.h>
+
+#include "socfpga_fcs.h"
+#include "socfpga_mailbox.h"
+#include "socfpga_reset_manager.h"
+#include "socfpga_sip_svc.h"
+
+
+/* Total buffer the driver can hold */
+#define FPGA_CONFIG_BUFFER_SIZE 4
+
+static config_type request_type = NO_REQUEST;
+static int current_block, current_buffer;
+static int read_block, max_blocks;
+static uint32_t send_id, rcv_id;
+static uint32_t bytes_per_block, blocks_submitted;
+static bool bridge_disable;
+
+/* RSU static variables */
+static uint32_t rsu_dcmf_ver[4] = {0};
+static uint16_t rsu_dcmf_stat[4] = {0};
+static uint32_t rsu_max_retry;
+
+/* SiP Service UUID */
+DEFINE_SVC_UUID2(intl_svc_uid,
+ 0xa85273b0, 0xe85a, 0x4862, 0xa6, 0x2a,
+ 0xfa, 0x88, 0x88, 0x17, 0x68, 0x81);
+
+static 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 int intel_fpga_sdm_write_buffer(struct fpga_config_info *buffer)
+{
+ uint32_t args[3];
+
+ while (max_blocks > 0 && buffer->size > buffer->size_written) {
+ args[0] = (1<<8);
+ args[1] = buffer->addr + buffer->size_written;
+ if (buffer->size - buffer->size_written <= bytes_per_block) {
+ args[2] = buffer->size - buffer->size_written;
+ current_buffer++;
+ current_buffer %= FPGA_CONFIG_BUFFER_SIZE;
+ } else {
+ args[2] = bytes_per_block;
+ }
+
+ buffer->size_written += args[2];
+ mailbox_send_cmd_async(&send_id, MBOX_RECONFIG_DATA, args,
+ 3U, CMD_INDIRECT);
+
+ buffer->subblocks_sent++;
+ max_blocks--;
+ }
+
+ return !max_blocks;
+}
+
+static int intel_fpga_sdm_write_all(void)
+{
+ for (int i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) {
+ if (intel_fpga_sdm_write_buffer(
+ &fpga_config_buffers[current_buffer])) {
+ break;
+ }
+ }
+ return 0;
+}
+
+static uint32_t intel_mailbox_fpga_config_isdone(void)
+{
+ uint32_t ret;
+
+ switch (request_type) {
+ case RECONFIGURATION:
+ ret = intel_mailbox_get_config_status(MBOX_RECONFIG_STATUS,
+ true);
+ break;
+ case BITSTREAM_AUTH:
+ ret = intel_mailbox_get_config_status(MBOX_RECONFIG_STATUS,
+ false);
+ break;
+ default:
+ ret = intel_mailbox_get_config_status(MBOX_CONFIG_STATUS,
+ false);
+ break;
+ }
+
+ if (ret != 0U) {
+ if (ret == MBOX_CFGSTAT_STATE_CONFIG) {
+ return INTEL_SIP_SMC_STATUS_BUSY;
+ } else {
+ request_type = NO_REQUEST;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+ }
+
+ if (bridge_disable != 0U) {
+ socfpga_bridges_enable(~0); /* Enable bridge */
+ bridge_disable = false;
+ }
+ request_type = NO_REQUEST;
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+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;
+}
+
+static int intel_fpga_config_completed_write(uint32_t *completed_addr,
+ uint32_t *count, uint32_t *job_id)
+{
+ uint32_t resp[5];
+ unsigned int resp_len = ARRAY_SIZE(resp);
+ int status = INTEL_SIP_SMC_STATUS_OK;
+ int all_completed = 1;
+ *count = 0;
+
+ while (*count < 3) {
+
+ status = mailbox_read_response(job_id,
+ resp, &resp_len);
+
+ if (status < 0) {
+ break;
+ }
+
+ max_blocks++;
+
+ if (mark_last_buffer_xfer_completed(
+ &completed_addr[*count]) == 0) {
+ *count = *count + 1;
+ } else {
+ break;
+ }
+ }
+
+ if (*count <= 0) {
+ if (status != MBOX_NO_RESPONSE &&
+ status != MBOX_TIMEOUT && resp_len != 0) {
+ mailbox_clear_response();
+ request_type = NO_REQUEST;
+ 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;
+}
+
+static int intel_fpga_config_start(uint32_t flag)
+{
+ uint32_t argument = 0x1;
+ uint32_t response[3];
+ int status = 0;
+ unsigned int size = 0;
+ unsigned int resp_len = ARRAY_SIZE(response);
+
+ request_type = RECONFIGURATION;
+
+ if (!CONFIG_TEST_FLAG(flag, PARTIAL_CONFIG)) {
+ bridge_disable = true;
+ }
+
+ if (CONFIG_TEST_FLAG(flag, AUTHENTICATION)) {
+ size = 1;
+ bridge_disable = false;
+ request_type = BITSTREAM_AUTH;
+ }
+
+ mailbox_clear_response();
+
+ mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_CANCEL, NULL, 0U,
+ CMD_CASUAL, NULL, NULL);
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_RECONFIG, &argument, size,
+ CMD_CASUAL, response, &resp_len);
+
+ if (status < 0) {
+ bridge_disable = false;
+ request_type = NO_REQUEST;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ 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;
+ read_block = 0;
+ current_buffer = 0;
+
+ /* Disable bridge on full reconfiguration */
+ if (bridge_disable) {
+ socfpga_bridges_disable(~0);
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+static bool is_fpga_config_buffer_full(void)
+{
+ for (int i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) {
+ if (!fpga_config_buffers[i].write_requested) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool is_address_in_ddr_range(uint64_t addr, uint64_t size)
+{
+ if (!addr && !size) {
+ return true;
+ }
+ if (size > (UINT64_MAX - addr)) {
+ return false;
+ }
+ if (addr < BL31_LIMIT) {
+ return false;
+ }
+ if (addr + size > DRAM_BASE + DRAM_SIZE) {
+ return false;
+ }
+
+ return true;
+}
+
+static uint32_t intel_fpga_config_write(uint64_t mem, uint64_t size)
+{
+ int i;
+
+ intel_fpga_sdm_write_all();
+
+ if (!is_address_in_ddr_range(mem, size) ||
+ is_fpga_config_buffer_full()) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ for (i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) {
+ int j = (i + current_buffer) % FPGA_CONFIG_BUFFER_SIZE;
+
+ if (!fpga_config_buffers[j].write_requested) {
+ fpga_config_buffers[j].addr = mem;
+ fpga_config_buffers[j].size = size;
+ fpga_config_buffers[j].size_written = 0;
+ fpga_config_buffers[j].write_requested = 1;
+ fpga_config_buffers[j].block_number =
+ blocks_submitted++;
+ fpga_config_buffers[j].subblocks_sent = 0;
+ break;
+ }
+ }
+
+ if (is_fpga_config_buffer_full()) {
+ return INTEL_SIP_SMC_STATUS_BUSY;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+static int is_out_of_sec_range(uint64_t reg_addr)
+{
+#if DEBUG
+ return 0;
+#endif
+
+ switch (reg_addr) {
+ case(0xF8011100): /* ECCCTRL1 */
+ case(0xF8011104): /* ECCCTRL2 */
+ case(0xF8011110): /* ERRINTEN */
+ case(0xF8011114): /* ERRINTENS */
+ case(0xF8011118): /* ERRINTENR */
+ case(0xF801111C): /* INTMODE */
+ case(0xF8011120): /* INTSTAT */
+ case(0xF8011124): /* DIAGINTTEST */
+ case(0xF801112C): /* DERRADDRA */
+ case(0xFFD12028): /* SDMMCGRP_CTRL */
+ case(0xFFD12044): /* EMAC0 */
+ case(0xFFD12048): /* EMAC1 */
+ case(0xFFD1204C): /* EMAC2 */
+ case(0xFFD12090): /* ECC_INT_MASK_VALUE */
+ case(0xFFD12094): /* ECC_INT_MASK_SET */
+ case(0xFFD12098): /* ECC_INT_MASK_CLEAR */
+ case(0xFFD1209C): /* ECC_INTSTATUS_SERR */
+ case(0xFFD120A0): /* ECC_INTSTATUS_DERR */
+ case(0xFFD120C0): /* NOC_TIMEOUT */
+ case(0xFFD120C4): /* NOC_IDLEREQ_SET */
+ case(0xFFD120C8): /* NOC_IDLEREQ_CLR */
+ case(0xFFD120D0): /* NOC_IDLEACK */
+ case(0xFFD120D4): /* NOC_IDLESTATUS */
+ case(0xFFD12200): /* BOOT_SCRATCH_COLD0 */
+ case(0xFFD12204): /* BOOT_SCRATCH_COLD1 */
+ case(0xFFD12220): /* BOOT_SCRATCH_COLD8 */
+ case(0xFFD12224): /* BOOT_SCRATCH_COLD9 */
+ return 0;
+
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+/* Secure register access */
+uint32_t intel_secure_reg_read(uint64_t reg_addr, uint32_t *retval)
+{
+ if (is_out_of_sec_range(reg_addr)) {
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *retval = mmio_read_32(reg_addr);
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+uint32_t intel_secure_reg_write(uint64_t reg_addr, uint32_t val,
+ uint32_t *retval)
+{
+ if (is_out_of_sec_range(reg_addr)) {
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ mmio_write_32(reg_addr, val);
+
+ return intel_secure_reg_read(reg_addr, retval);
+}
+
+uint32_t intel_secure_reg_update(uint64_t reg_addr, uint32_t mask,
+ uint32_t val, uint32_t *retval)
+{
+ if (!intel_secure_reg_read(reg_addr, retval)) {
+ *retval &= ~mask;
+ *retval |= val & mask;
+ return intel_secure_reg_write(reg_addr, *retval, retval);
+ }
+
+ return INTEL_SIP_SMC_STATUS_ERROR;
+}
+
+/* Intel Remote System Update (RSU) services */
+uint64_t intel_rsu_update_address;
+
+static uint32_t intel_rsu_status(uint64_t *respbuf, unsigned int respbuf_sz)
+{
+ if (mailbox_rsu_status((uint32_t *)respbuf, respbuf_sz) < 0) {
+ return INTEL_SIP_SMC_RSU_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+static uint32_t intel_rsu_update(uint64_t update_address)
+{
+ intel_rsu_update_address = update_address;
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+static uint32_t intel_rsu_notify(uint32_t execution_stage)
+{
+ if (mailbox_hps_stage_notify(execution_stage) < 0) {
+ return INTEL_SIP_SMC_RSU_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+static uint32_t intel_rsu_retry_counter(uint32_t *respbuf, uint32_t respbuf_sz,
+ uint32_t *ret_stat)
+{
+ if (mailbox_rsu_status((uint32_t *)respbuf, respbuf_sz) < 0) {
+ return INTEL_SIP_SMC_RSU_ERROR;
+ }
+
+ *ret_stat = respbuf[8];
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+static uint32_t intel_rsu_copy_dcmf_version(uint64_t dcmf_ver_1_0,
+ uint64_t dcmf_ver_3_2)
+{
+ rsu_dcmf_ver[0] = dcmf_ver_1_0;
+ rsu_dcmf_ver[1] = dcmf_ver_1_0 >> 32;
+ rsu_dcmf_ver[2] = dcmf_ver_3_2;
+ rsu_dcmf_ver[3] = dcmf_ver_3_2 >> 32;
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+static uint32_t intel_rsu_copy_dcmf_status(uint64_t dcmf_stat)
+{
+ rsu_dcmf_stat[0] = 0xFFFF & (dcmf_stat >> (0 * 16));
+ rsu_dcmf_stat[1] = 0xFFFF & (dcmf_stat >> (1 * 16));
+ rsu_dcmf_stat[2] = 0xFFFF & (dcmf_stat >> (2 * 16));
+ rsu_dcmf_stat[3] = 0xFFFF & (dcmf_stat >> (3 * 16));
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+/* Intel HWMON services */
+static uint32_t intel_hwmon_readtemp(uint32_t chan, uint32_t *retval)
+{
+ if (chan > TEMP_CHANNEL_MAX) {
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ if (mailbox_hwmon_readtemp(chan, retval) < 0) {
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+static uint32_t intel_hwmon_readvolt(uint32_t chan, uint32_t *retval)
+{
+ if (chan > VOLT_CHANNEL_MAX) {
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ if (mailbox_hwmon_readvolt(chan, retval) < 0) {
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+/* Mailbox services */
+static uint32_t intel_smc_fw_version(uint32_t *fw_version)
+{
+ int status;
+ unsigned int resp_len = CONFIG_STATUS_WORD_SIZE;
+ uint32_t resp_data[CONFIG_STATUS_WORD_SIZE] = {0U};
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_CONFIG_STATUS, NULL, 0U,
+ CMD_CASUAL, resp_data, &resp_len);
+
+ if (status < 0) {
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ if (resp_len <= CONFIG_STATUS_FW_VER_OFFSET) {
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *fw_version = resp_data[CONFIG_STATUS_FW_VER_OFFSET] & CONFIG_STATUS_FW_VER_MASK;
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+static uint32_t intel_mbox_send_cmd(uint32_t cmd, uint32_t *args,
+ unsigned int len, uint32_t urgent, uint64_t response,
+ unsigned int resp_len, int *mbox_status,
+ unsigned int *len_in_resp)
+{
+ *len_in_resp = 0;
+ *mbox_status = GENERIC_RESPONSE_ERROR;
+
+ if (!is_address_in_ddr_range((uint64_t)args, sizeof(uint32_t) * len)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ int status = mailbox_send_cmd(MBOX_JOB_ID, cmd, args, len, urgent,
+ (uint32_t *) response, &resp_len);
+
+ if (status < 0) {
+ *mbox_status = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ *mbox_status = 0;
+ *len_in_resp = resp_len;
+
+ flush_dcache_range(response, resp_len * MBOX_WORD_BYTE);
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+static int intel_smc_get_usercode(uint32_t *user_code)
+{
+ int status;
+ unsigned int resp_len = sizeof(user_code) / MBOX_WORD_BYTE;
+
+ status = mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_GET_USERCODE, NULL,
+ 0U, CMD_CASUAL, user_code, &resp_len);
+
+ if (status < 0) {
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+uint32_t intel_smc_service_completed(uint64_t addr, uint32_t size,
+ uint32_t mode, uint32_t *job_id,
+ uint32_t *ret_size, uint32_t *mbox_error)
+{
+ int status = 0;
+ uint32_t resp_len = size / MBOX_WORD_BYTE;
+
+ if (resp_len > MBOX_DATA_MAX_LEN) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_address_in_ddr_range(addr, size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (mode == SERVICE_COMPLETED_MODE_ASYNC) {
+ status = mailbox_read_response_async(job_id,
+ NULL, (uint32_t *) addr, &resp_len, 0);
+ } else {
+ status = mailbox_read_response(job_id,
+ (uint32_t *) addr, &resp_len);
+
+ if (status == MBOX_NO_RESPONSE) {
+ status = MBOX_BUSY;
+ }
+ }
+
+ if (status == MBOX_NO_RESPONSE) {
+ return INTEL_SIP_SMC_STATUS_NO_RESPONSE;
+ }
+
+ if (status == MBOX_BUSY) {
+ return INTEL_SIP_SMC_STATUS_BUSY;
+ }
+
+ *ret_size = resp_len * MBOX_WORD_BYTE;
+ flush_dcache_range(addr, *ret_size);
+
+ if (status != MBOX_RET_OK) {
+ *mbox_error = -status;
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+/* Miscellaneous HPS services */
+uint32_t intel_hps_set_bridges(uint64_t enable, uint64_t mask)
+{
+ int status = 0;
+
+ if ((enable & SOCFPGA_BRIDGE_ENABLE) != 0U) {
+ if ((enable & SOCFPGA_BRIDGE_HAS_MASK) != 0U) {
+ status = socfpga_bridges_enable((uint32_t)mask);
+ } else {
+ status = socfpga_bridges_enable(~0);
+ }
+ } else {
+ if ((enable & SOCFPGA_BRIDGE_HAS_MASK) != 0U) {
+ status = socfpga_bridges_disable((uint32_t)mask);
+ } else {
+ status = socfpga_bridges_disable(~0);
+ }
+ }
+
+ if (status < 0) {
+ return INTEL_SIP_SMC_STATUS_ERROR;
+ }
+
+ return INTEL_SIP_SMC_STATUS_OK;
+}
+
+/*
+ * This function is responsible for handling all SiP calls from the NS world
+ */
+
+uintptr_t sip_smc_handler_v1(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 retval = 0, completed_addr[3];
+ uint32_t retval2 = 0;
+ uint32_t mbox_error = 0;
+ uint64_t retval64, rsu_respbuf[9];
+ int status = INTEL_SIP_SMC_STATUS_OK;
+ int mbox_status;
+ unsigned int len_in_resp;
+ u_register_t x5, x6, x7;
+
+ switch (smc_fid) {
+ case SIP_SVC_UID:
+ /* Return UID to the caller */
+ SMC_UUID_RET(handle, intl_svc_uid);
+
+ case INTEL_SIP_SMC_FPGA_CONFIG_ISDONE:
+ status = intel_mailbox_fpga_config_isdone();
+ SMC_RET4(handle, status, 0, 0, 0);
+
+ 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);
+
+ case INTEL_SIP_SMC_FPGA_CONFIG_START:
+ status = intel_fpga_config_start(x1);
+ SMC_RET4(handle, status, 0, 0, 0);
+
+ case INTEL_SIP_SMC_FPGA_CONFIG_WRITE:
+ status = intel_fpga_config_write(x1, x2);
+ SMC_RET4(handle, status, 0, 0, 0);
+
+ case INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE:
+ status = intel_fpga_config_completed_write(completed_addr,
+ &retval, &rcv_id);
+ switch (retval) {
+ case 1:
+ SMC_RET4(handle, INTEL_SIP_SMC_STATUS_OK,
+ completed_addr[0], 0, 0);
+
+ case 2:
+ SMC_RET4(handle, INTEL_SIP_SMC_STATUS_OK,
+ completed_addr[0],
+ completed_addr[1], 0);
+
+ case 3:
+ SMC_RET4(handle, INTEL_SIP_SMC_STATUS_OK,
+ completed_addr[0],
+ completed_addr[1],
+ completed_addr[2]);
+
+ case 0:
+ SMC_RET4(handle, status, 0, 0, 0);
+
+ default:
+ mailbox_clear_response();
+ SMC_RET1(handle, INTEL_SIP_SMC_STATUS_ERROR);
+ }
+
+ case INTEL_SIP_SMC_REG_READ:
+ status = intel_secure_reg_read(x1, &retval);
+ SMC_RET3(handle, status, retval, x1);
+
+ case INTEL_SIP_SMC_REG_WRITE:
+ status = intel_secure_reg_write(x1, (uint32_t)x2, &retval);
+ SMC_RET3(handle, status, retval, x1);
+
+ case INTEL_SIP_SMC_REG_UPDATE:
+ status = intel_secure_reg_update(x1, (uint32_t)x2,
+ (uint32_t)x3, &retval);
+ SMC_RET3(handle, status, retval, x1);
+
+ case INTEL_SIP_SMC_RSU_STATUS:
+ status = intel_rsu_status(rsu_respbuf,
+ ARRAY_SIZE(rsu_respbuf));
+ if (status) {
+ SMC_RET1(handle, status);
+ } else {
+ SMC_RET4(handle, rsu_respbuf[0], rsu_respbuf[1],
+ rsu_respbuf[2], rsu_respbuf[3]);
+ }
+
+ case INTEL_SIP_SMC_RSU_UPDATE:
+ status = intel_rsu_update(x1);
+ SMC_RET1(handle, status);
+
+ case INTEL_SIP_SMC_RSU_NOTIFY:
+ status = intel_rsu_notify(x1);
+ SMC_RET1(handle, status);
+
+ case INTEL_SIP_SMC_RSU_RETRY_COUNTER:
+ status = intel_rsu_retry_counter((uint32_t *)rsu_respbuf,
+ ARRAY_SIZE(rsu_respbuf), &retval);
+ if (status) {
+ SMC_RET1(handle, status);
+ } else {
+ SMC_RET2(handle, status, retval);
+ }
+
+ case INTEL_SIP_SMC_RSU_DCMF_VERSION:
+ SMC_RET3(handle, INTEL_SIP_SMC_STATUS_OK,
+ ((uint64_t)rsu_dcmf_ver[1] << 32) | rsu_dcmf_ver[0],
+ ((uint64_t)rsu_dcmf_ver[3] << 32) | rsu_dcmf_ver[2]);
+
+ case INTEL_SIP_SMC_RSU_COPY_DCMF_VERSION:
+ status = intel_rsu_copy_dcmf_version(x1, x2);
+ SMC_RET1(handle, status);
+
+ case INTEL_SIP_SMC_RSU_DCMF_STATUS:
+ SMC_RET2(handle, INTEL_SIP_SMC_STATUS_OK,
+ ((uint64_t)rsu_dcmf_stat[3] << 48) |
+ ((uint64_t)rsu_dcmf_stat[2] << 32) |
+ ((uint64_t)rsu_dcmf_stat[1] << 16) |
+ rsu_dcmf_stat[0]);
+
+ case INTEL_SIP_SMC_RSU_COPY_DCMF_STATUS:
+ status = intel_rsu_copy_dcmf_status(x1);
+ SMC_RET1(handle, status);
+
+ case INTEL_SIP_SMC_RSU_MAX_RETRY:
+ SMC_RET2(handle, INTEL_SIP_SMC_STATUS_OK, rsu_max_retry);
+
+ case INTEL_SIP_SMC_RSU_COPY_MAX_RETRY:
+ rsu_max_retry = x1;
+ SMC_RET1(handle, INTEL_SIP_SMC_STATUS_OK);
+
+ case INTEL_SIP_SMC_ECC_DBE:
+ status = intel_ecc_dbe_notification(x1);
+ SMC_RET1(handle, status);
+
+ case INTEL_SIP_SMC_SERVICE_COMPLETED:
+ status = intel_smc_service_completed(x1, x2, x3, &rcv_id,
+ &len_in_resp, &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x1, len_in_resp);
+
+ case INTEL_SIP_SMC_FIRMWARE_VERSION:
+ status = intel_smc_fw_version(&retval);
+ SMC_RET2(handle, status, retval);
+
+ case INTEL_SIP_SMC_MBOX_SEND_CMD:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+ status = intel_mbox_send_cmd(x1, (uint32_t *)x2, x3, x4, x5, x6,
+ &mbox_status, &len_in_resp);
+ SMC_RET3(handle, status, mbox_status, len_in_resp);
+
+ case INTEL_SIP_SMC_GET_USERCODE:
+ status = intel_smc_get_usercode(&retval);
+ SMC_RET2(handle, status, retval);
+
+ case INTEL_SIP_SMC_FCS_CRYPTION:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+
+ if (x1 == FCS_MODE_DECRYPT) {
+ status = intel_fcs_decryption(x2, x3, x4, x5, &send_id);
+ } else if (x1 == FCS_MODE_ENCRYPT) {
+ status = intel_fcs_encryption(x2, x3, x4, x5, &send_id);
+ } else {
+ status = INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ SMC_RET3(handle, status, x4, x5);
+
+ case INTEL_SIP_SMC_FCS_CRYPTION_EXT:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+ x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
+
+ if (x3 == FCS_MODE_DECRYPT) {
+ status = intel_fcs_decryption_ext(x1, x2, x4, x5, x6,
+ (uint32_t *) &x7, &mbox_error);
+ } else if (x3 == FCS_MODE_ENCRYPT) {
+ status = intel_fcs_encryption_ext(x1, x2, x4, x5, x6,
+ (uint32_t *) &x7, &mbox_error);
+ } else {
+ status = INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ SMC_RET4(handle, status, mbox_error, x6, x7);
+
+ case INTEL_SIP_SMC_FCS_RANDOM_NUMBER:
+ status = intel_fcs_random_number_gen(x1, &retval64,
+ &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x1, retval64);
+
+ case INTEL_SIP_SMC_FCS_RANDOM_NUMBER_EXT:
+ status = intel_fcs_random_number_gen_ext(x1, x2, x3,
+ &send_id);
+ SMC_RET1(handle, status);
+
+ case INTEL_SIP_SMC_FCS_SEND_CERTIFICATE:
+ status = intel_fcs_send_cert(x1, x2, &send_id);
+ SMC_RET1(handle, status);
+
+ case INTEL_SIP_SMC_FCS_GET_PROVISION_DATA:
+ status = intel_fcs_get_provision_data(&send_id);
+ SMC_RET1(handle, status);
+
+ case INTEL_SIP_SMC_FCS_CNTR_SET_PREAUTH:
+ status = intel_fcs_cntr_set_preauth(x1, x2, x3,
+ &mbox_error);
+ SMC_RET2(handle, status, mbox_error);
+
+ case INTEL_SIP_SMC_HPS_SET_BRIDGES:
+ status = intel_hps_set_bridges(x1, x2);
+ SMC_RET1(handle, status);
+
+ case INTEL_SIP_SMC_HWMON_READTEMP:
+ status = intel_hwmon_readtemp(x1, &retval);
+ SMC_RET2(handle, status, retval);
+
+ case INTEL_SIP_SMC_HWMON_READVOLT:
+ status = intel_hwmon_readvolt(x1, &retval);
+ SMC_RET2(handle, status, retval);
+
+ case INTEL_SIP_SMC_FCS_PSGSIGMA_TEARDOWN:
+ status = intel_fcs_sigma_teardown(x1, &mbox_error);
+ SMC_RET2(handle, status, mbox_error);
+
+ case INTEL_SIP_SMC_FCS_CHIP_ID:
+ status = intel_fcs_chip_id(&retval, &retval2, &mbox_error);
+ SMC_RET4(handle, status, mbox_error, retval, retval2);
+
+ case INTEL_SIP_SMC_FCS_ATTESTATION_SUBKEY:
+ status = intel_fcs_attestation_subkey(x1, x2, x3,
+ (uint32_t *) &x4, &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x3, x4);
+
+ case INTEL_SIP_SMC_FCS_ATTESTATION_MEASUREMENTS:
+ status = intel_fcs_get_measurement(x1, x2, x3,
+ (uint32_t *) &x4, &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x3, x4);
+
+ case INTEL_SIP_SMC_FCS_GET_ATTESTATION_CERT:
+ status = intel_fcs_get_attestation_cert(x1, x2,
+ (uint32_t *) &x3, &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x2, x3);
+
+ case INTEL_SIP_SMC_FCS_CREATE_CERT_ON_RELOAD:
+ status = intel_fcs_create_cert_on_reload(x1, &mbox_error);
+ SMC_RET2(handle, status, mbox_error);
+
+ case INTEL_SIP_SMC_FCS_OPEN_CS_SESSION:
+ status = intel_fcs_open_crypto_service_session(&retval, &mbox_error);
+ SMC_RET3(handle, status, mbox_error, retval);
+
+ case INTEL_SIP_SMC_FCS_CLOSE_CS_SESSION:
+ status = intel_fcs_close_crypto_service_session(x1, &mbox_error);
+ SMC_RET2(handle, status, mbox_error);
+
+ case INTEL_SIP_SMC_FCS_IMPORT_CS_KEY:
+ status = intel_fcs_import_crypto_service_key(x1, x2, &send_id);
+ SMC_RET1(handle, status);
+
+ case INTEL_SIP_SMC_FCS_EXPORT_CS_KEY:
+ status = intel_fcs_export_crypto_service_key(x1, x2, x3,
+ (uint32_t *) &x4, &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x3, x4);
+
+ case INTEL_SIP_SMC_FCS_REMOVE_CS_KEY:
+ status = intel_fcs_remove_crypto_service_key(x1, x2,
+ &mbox_error);
+ SMC_RET2(handle, status, mbox_error);
+
+ case INTEL_SIP_SMC_FCS_GET_CS_KEY_INFO:
+ status = intel_fcs_get_crypto_service_key_info(x1, x2, x3,
+ (uint32_t *) &x4, &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x3, x4);
+
+ case INTEL_SIP_SMC_FCS_GET_DIGEST_INIT:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ status = intel_fcs_get_digest_init(x1, x2, x3,
+ x4, x5, &mbox_error);
+ SMC_RET2(handle, status, mbox_error);
+
+ case INTEL_SIP_SMC_FCS_GET_DIGEST_UPDATE:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+ status = intel_fcs_get_digest_update_finalize(x1, x2, x3,
+ x4, x5, (uint32_t *) &x6, false,
+ &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x5, x6);
+
+ case INTEL_SIP_SMC_FCS_GET_DIGEST_FINALIZE:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+ status = intel_fcs_get_digest_update_finalize(x1, x2, x3,
+ x4, x5, (uint32_t *) &x6, true,
+ &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x5, x6);
+
+ case INTEL_SIP_SMC_FCS_MAC_VERIFY_INIT:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ status = intel_fcs_mac_verify_init(x1, x2, x3,
+ x4, x5, &mbox_error);
+ SMC_RET2(handle, status, mbox_error);
+
+ case INTEL_SIP_SMC_FCS_MAC_VERIFY_UPDATE:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+ x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
+ status = intel_fcs_mac_verify_update_finalize(x1, x2, x3,
+ x4, x5, (uint32_t *) &x6, x7,
+ false, &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x5, x6);
+
+ case INTEL_SIP_SMC_FCS_MAC_VERIFY_FINALIZE:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+ x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
+ status = intel_fcs_mac_verify_update_finalize(x1, x2, x3,
+ x4, x5, (uint32_t *) &x6, x7,
+ true, &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x5, x6);
+
+ case INTEL_SIP_SMC_FCS_ECDSA_SHA2_DATA_SIGN_INIT:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ status = intel_fcs_ecdsa_sha2_data_sign_init(x1, x2, x3,
+ x4, x5, &mbox_error);
+ SMC_RET2(handle, status, mbox_error);
+
+ case INTEL_SIP_SMC_FCS_ECDSA_SHA2_DATA_SIGN_UPDATE:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+ status = intel_fcs_ecdsa_sha2_data_sign_update_finalize(x1, x2,
+ x3, x4, x5, (uint32_t *) &x6, false,
+ &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x5, x6);
+
+ case INTEL_SIP_SMC_FCS_ECDSA_SHA2_DATA_SIGN_FINALIZE:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+ status = intel_fcs_ecdsa_sha2_data_sign_update_finalize(x1, x2,
+ x3, x4, x5, (uint32_t *) &x6, true,
+ &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x5, x6);
+
+ case INTEL_SIP_SMC_FCS_ECDSA_HASH_SIGN_INIT:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ status = intel_fcs_ecdsa_hash_sign_init(x1, x2, x3,
+ x4, x5, &mbox_error);
+ SMC_RET2(handle, status, mbox_error);
+
+ case INTEL_SIP_SMC_FCS_ECDSA_HASH_SIGN_FINALIZE:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+ status = intel_fcs_ecdsa_hash_sign_finalize(x1, x2, x3,
+ x4, x5, (uint32_t *) &x6, &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x5, x6);
+
+ case INTEL_SIP_SMC_FCS_ECDSA_HASH_SIG_VERIFY_INIT:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ status = intel_fcs_ecdsa_hash_sig_verify_init(x1, x2, x3,
+ x4, x5, &mbox_error);
+ SMC_RET2(handle, status, mbox_error);
+
+ case INTEL_SIP_SMC_FCS_ECDSA_HASH_SIG_VERIFY_FINALIZE:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+ status = intel_fcs_ecdsa_hash_sig_verify_finalize(x1, x2, x3,
+ x4, x5, (uint32_t *) &x6, &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x5, x6);
+
+ case INTEL_SIP_SMC_FCS_ECDSA_SHA2_DATA_SIG_VERIFY_INIT:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ status = intel_fcs_ecdsa_sha2_data_sig_verify_init(x1, x2, x3,
+ x4, x5, &mbox_error);
+ SMC_RET2(handle, status, mbox_error);
+
+ case INTEL_SIP_SMC_FCS_ECDSA_SHA2_DATA_SIG_VERIFY_UPDATE:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+ x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
+ status = intel_fcs_ecdsa_sha2_data_sig_verify_update_finalize(
+ x1, x2, x3, x4, x5, (uint32_t *) &x6,
+ x7, false, &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x5, x6);
+
+ case INTEL_SIP_SMC_FCS_ECDSA_SHA2_DATA_SIG_VERIFY_FINALIZE:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+ x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
+ status = intel_fcs_ecdsa_sha2_data_sig_verify_update_finalize(
+ x1, x2, x3, x4, x5, (uint32_t *) &x6,
+ x7, true, &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x5, x6);
+
+ case INTEL_SIP_SMC_FCS_ECDSA_GET_PUBKEY_INIT:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ status = intel_fcs_ecdsa_get_pubkey_init(x1, x2, x3,
+ x4, x5, &mbox_error);
+ SMC_RET2(handle, status, mbox_error);
+
+ case INTEL_SIP_SMC_FCS_ECDSA_GET_PUBKEY_FINALIZE:
+ status = intel_fcs_ecdsa_get_pubkey_finalize(x1, x2, x3,
+ (uint32_t *) &x4, &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x3, x4);
+
+ case INTEL_SIP_SMC_FCS_ECDH_REQUEST_INIT:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ status = intel_fcs_ecdh_request_init(x1, x2, x3,
+ x4, x5, &mbox_error);
+ SMC_RET2(handle, status, mbox_error);
+
+ case INTEL_SIP_SMC_FCS_ECDH_REQUEST_FINALIZE:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+ status = intel_fcs_ecdh_request_finalize(x1, x2, x3,
+ x4, x5, (uint32_t *) &x6, &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x5, x6);
+
+ case INTEL_SIP_SMC_FCS_AES_CRYPT_INIT:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ status = intel_fcs_aes_crypt_init(x1, x2, x3, x4, x5,
+ &mbox_error);
+ SMC_RET2(handle, status, mbox_error);
+
+ case INTEL_SIP_SMC_FCS_AES_CRYPT_UPDATE:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+ status = intel_fcs_aes_crypt_update_finalize(x1, x2, x3, x4,
+ x5, x6, false, &send_id);
+ SMC_RET1(handle, status);
+
+ case INTEL_SIP_SMC_FCS_AES_CRYPT_FINALIZE:
+ x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+ x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+ status = intel_fcs_aes_crypt_update_finalize(x1, x2, x3, x4,
+ x5, x6, true, &send_id);
+ SMC_RET1(handle, status);
+
+ case INTEL_SIP_SMC_GET_ROM_PATCH_SHA384:
+ status = intel_fcs_get_rom_patch_sha384(x1, &retval64,
+ &mbox_error);
+ SMC_RET4(handle, status, mbox_error, x1, retval64);
+
+ case INTEL_SIP_SMC_SVC_VERSION:
+ SMC_RET3(handle, INTEL_SIP_SMC_STATUS_OK,
+ SIP_SVC_VERSION_MAJOR,
+ SIP_SVC_VERSION_MINOR);
+
+ default:
+ return socfpga_sip_handler(smc_fid, x1, x2, x3, x4,
+ cookie, handle, flags);
+ }
+}
+
+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 cmd = smc_fid & INTEL_SIP_SMC_CMD_MASK;
+
+ if (cmd >= INTEL_SIP_SMC_CMD_V2_RANGE_BEGIN &&
+ cmd <= INTEL_SIP_SMC_CMD_V2_RANGE_END) {
+ return sip_smc_handler_v2(smc_fid, x1, x2, x3, x4,
+ cookie, handle, flags);
+ } else {
+ return sip_smc_handler_v1(smc_fid, x1, x2, x3, x4,
+ cookie, handle, flags);
+ }
+}
+
+DECLARE_RT_SVC(
+ socfpga_sip_svc,
+ OEN_SIP_START,
+ OEN_SIP_END,
+ SMC_TYPE_FAST,
+ NULL,
+ sip_smc_handler
+);
+
+DECLARE_RT_SVC(
+ socfpga_sip_svc_std,
+ OEN_SIP_START,
+ OEN_SIP_END,
+ SMC_TYPE_YIELD,
+ NULL,
+ sip_smc_handler
+);
diff --git a/plat/intel/soc/common/socfpga_sip_svc_v2.c b/plat/intel/soc/common/socfpga_sip_svc_v2.c
new file mode 100644
index 0000000..791c714
--- /dev/null
+++ b/plat/intel/soc/common/socfpga_sip_svc_v2.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+
+#include "socfpga_mailbox.h"
+#include "socfpga_sip_svc.h"
+
+static uint32_t intel_v2_mbox_send_cmd(uint32_t req_header,
+ uint32_t *data, uint32_t data_size)
+{
+ uint32_t value;
+ uint32_t len;
+
+ if ((data == NULL) || (data_size == 0)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (data_size > (MBOX_INC_HEADER_MAX_WORD_SIZE * MBOX_WORD_BYTE)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_size_4_bytes_aligned(data_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ /* Make sure client id align in SMC SiP V2 header and mailbox header */
+ value = (req_header >> INTEL_SIP_SMC_HEADER_CID_OFFSET) &
+ INTEL_SIP_SMC_HEADER_CID_MASK;
+
+ if (value != MBOX_RESP_CLIENT_ID(data[0])) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ /* Make sure job id align in SMC SiP V2 header and mailbox header */
+ value = (req_header >> INTEL_SIP_SMC_HEADER_JOB_ID_OFFSET) &
+ INTEL_SIP_SMC_HEADER_JOB_ID_MASK;
+
+ if (value != MBOX_RESP_JOB_ID(data[0])) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ /*
+ * Make sure data length align in SMC SiP V2 header and
+ * mailbox header
+ */
+ len = (data_size / MBOX_WORD_BYTE) - 1;
+
+ if (len != MBOX_RESP_LEN(data[0])) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ return mailbox_send_cmd_async_ext(data[0], &data[1], len);
+}
+
+static uint32_t intel_v2_mbox_poll_resp(uint64_t req_header,
+ uint32_t *data, uint32_t *data_size,
+ uint64_t *resp_header)
+{
+ int status = 0;
+ uint32_t resp_len;
+ uint32_t job_id = 0;
+ uint32_t client_id = 0;
+ uint32_t version;
+
+ if ((data == NULL) || (data_size == NULL) || (resp_header == NULL)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ if (!is_size_4_bytes_aligned(*data_size)) {
+ return INTEL_SIP_SMC_STATUS_REJECTED;
+ }
+
+ resp_len = (*data_size / MBOX_WORD_BYTE) - 1;
+ status = mailbox_read_response_async(&job_id, &data[0], &data[1],
+ &resp_len, 1);
+
+ if (status == MBOX_BUSY) {
+ status = INTEL_SIP_SMC_STATUS_BUSY;
+ } else if (status == MBOX_NO_RESPONSE) {
+ status = INTEL_SIP_SMC_STATUS_NO_RESPONSE;
+ } else {
+ *data_size = 0;
+
+ if (resp_len > 0) {
+ /*
+ * Fill in the final response length,
+ * the length include both mailbox header and payload
+ */
+ *data_size = (resp_len + 1) * MBOX_WORD_BYTE;
+
+ /* Extract the client id from mailbox header */
+ client_id = MBOX_RESP_CLIENT_ID(data[0]);
+ }
+
+ /*
+ * Extract SMC SiP V2 protocol version from
+ * SMC request header
+ */
+ version = (req_header >> INTEL_SIP_SMC_HEADER_VERSION_OFFSET) &
+ INTEL_SIP_SMC_HEADER_VERSION_MASK;
+
+ /* Fill in SMC SiP V2 protocol response header */
+ *resp_header = 0;
+ *resp_header |= (((uint64_t)job_id) &
+ INTEL_SIP_SMC_HEADER_JOB_ID_MASK) <<
+ INTEL_SIP_SMC_HEADER_JOB_ID_OFFSET;
+ *resp_header |= (((uint64_t)client_id) &
+ INTEL_SIP_SMC_HEADER_CID_MASK) <<
+ INTEL_SIP_SMC_HEADER_CID_OFFSET;
+ *resp_header |= (((uint64_t)version) &
+ INTEL_SIP_SMC_HEADER_VERSION_MASK) <<
+ INTEL_SIP_SMC_HEADER_VERSION_OFFSET;
+ }
+
+ return status;
+}
+
+uintptr_t sip_smc_handler_v2(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 retval = 0;
+ uint64_t retval64 = 0;
+ int status = INTEL_SIP_SMC_STATUS_OK;
+
+ switch (smc_fid) {
+ case INTEL_SIP_SMC_V2_GET_SVC_VERSION:
+ SMC_RET4(handle, INTEL_SIP_SMC_STATUS_OK, x1,
+ SIP_SVC_VERSION_MAJOR,
+ SIP_SVC_VERSION_MINOR);
+
+ case INTEL_SIP_SMC_V2_REG_READ:
+ status = intel_secure_reg_read(x2, &retval);
+ SMC_RET4(handle, status, x1, retval, x2);
+
+ case INTEL_SIP_SMC_V2_REG_WRITE:
+ status = intel_secure_reg_write(x2, (uint32_t)x3, &retval);
+ SMC_RET4(handle, status, x1, retval, x2);
+
+ case INTEL_SIP_SMC_V2_REG_UPDATE:
+ status = intel_secure_reg_update(x2, (uint32_t)x3,
+ (uint32_t)x4, &retval);
+ SMC_RET4(handle, status, x1, retval, x2);
+
+ case INTEL_SIP_SMC_V2_HPS_SET_BRIDGES:
+ status = intel_hps_set_bridges(x2, x3);
+ SMC_RET2(handle, status, x1);
+
+ case INTEL_SIP_SMC_V2_MAILBOX_SEND_COMMAND:
+ status = intel_v2_mbox_send_cmd(x1, (uint32_t *)x2, x3);
+ SMC_RET2(handle, status, x1);
+
+ case INTEL_SIP_SMC_V2_MAILBOX_POLL_RESPONSE:
+ status = intel_v2_mbox_poll_resp(x1, (uint32_t *)x2,
+ (uint32_t *) &x3, &retval64);
+ SMC_RET4(handle, status, retval64, x2, x3);
+
+ default:
+ ERROR("%s: unhandled SMC V2 (0x%x)\n", __func__, smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+ }
+}
diff --git a/plat/intel/soc/common/socfpga_storage.c b/plat/intel/soc/common/socfpga_storage.c
new file mode 100644
index 0000000..a2f2c18
--- /dev/null
+++ b/plat/intel/soc/common/socfpga_storage.c
@@ -0,0 +1,193 @@
+/*
+ * 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 <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/mmc.h>
+#include <drivers/partition/partition.h>
+#include <lib/mmio.h>
+#include <tools_share/firmware_image_package.h>
+
+#include "socfpga_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 = &register_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 = &register_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;
+}
diff --git a/plat/intel/soc/common/socfpga_topology.c b/plat/intel/soc/common/socfpga_topology.c
new file mode 100644
index 0000000..ca1a91e
--- /dev/null
+++ b/plat/intel/soc/common/socfpga_topology.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <platform_def.h>
+#include <lib/psci/psci.h>
+
+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));
+}
+
diff --git a/plat/intel/soc/n5x/bl31_plat_setup.c b/plat/intel/soc/n5x/bl31_plat_setup.c
new file mode 100644
index 0000000..5ca1a71
--- /dev/null
+++ b/plat/intel/soc/n5x/bl31_plat_setup.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2020-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+#include "ccu/ncore_ccu.h"
+#include "socfpga_mailbox.h"
+#include "socfpga_private.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_t console;
+
+ mmio_write_64(PLAT_SEC_ENTRY, 0);
+
+ console_16550_register(PLAT_INTEL_UART_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);
+
+ /*
+ * Copy BL32 (if populated by BL31) and BL33 entry point information.
+ * They are stored in Secure RAM, in BL31's address space.
+ */
+
+ if (params_from_bl2->h.type == PARAM_BL_PARAMS &&
+ params_from_bl2->h.version >= VERSION_2) {
+
+ bl_params_node_t *bl_params = params_from_bl2->head;
+
+ while (bl_params != NULL) {
+ if (bl_params->image_id == BL33_IMAGE_ID)
+ bl33_image_ep_info = *bl_params->ep_info;
+
+ bl_params = bl_params->next_params_info;
+ }
+ } else {
+ struct socfpga_bl31_params *arg_from_bl2 =
+ (struct socfpga_bl31_params *) from_bl2;
+
+ assert(arg_from_bl2->h.type == PARAM_BL31);
+ assert(arg_from_bl2->h.version >= VERSION_1);
+
+ bl32_image_ep_info = *arg_from_bl2->bl32_ep_info;
+ bl33_image_ep_info = *arg_from_bl2->bl33_ep_info;
+ }
+ SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+}
+
+static const interrupt_prop_t s10_interrupt_props[] = {
+ PLAT_INTEL_SOCFPGA_G1S_IRQ_PROPS(GICV2_INTR_GROUP0),
+ PLAT_INTEL_SOCFPGA_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_SOCFPGA_GICD_BASE,
+ .gicc_base = PLAT_INTEL_SOCFPGA_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)
+{
+ socfpga_delay_timer_init();
+
+ /* Initialize the gic cpu and distributor interfaces */
+ gicv2_driver_init(&plat_gicv2_gic_data);
+ gicv2_distif_init();
+ gicv2_pcpu_distif_init();
+ gicv2_cpuif_enable();
+
+ /* Signal secondary CPUs to jump to BL31 (BL2 = U-boot SPL) */
+ mmio_write_64(PLAT_CPU_RELEASE_ADDR,
+ (uint64_t)plat_secondary_cpus_bl31_entry);
+
+ mailbox_hps_stage_notify(HPS_EXECUTION_STATE_SSBL);
+
+ ncore_enable_ocram_firewall();
+}
+
+const mmap_region_t plat_dm_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_dm_mmap);
+ enable_mmu_el3(0);
+}
diff --git a/plat/intel/soc/n5x/include/socfpga_plat_def.h b/plat/intel/soc/n5x/include/socfpga_plat_def.h
new file mode 100644
index 0000000..4c36f91
--- /dev/null
+++ b/plat/intel/soc/n5x/include/socfpga_plat_def.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_SOCFPGA_DEF_H
+#define PLAT_SOCFPGA_DEF_H
+
+#include <platform_def.h>
+
+/* Platform Setting */
+#define PLATFORM_MODEL PLAT_SOCFPGA_N5X
+#define BOOT_SOURCE BOOT_SOURCE_SDMMC
+
+/* FPGA config helpers */
+#define INTEL_SIP_SMC_FPGA_CONFIG_ADDR 0x400000
+#define INTEL_SIP_SMC_FPGA_CONFIG_SIZE 0x2000000
+
+/* Register Mapping */
+#define SOCFPGA_CCU_NOC_REG_BASE U(0xf7000000)
+#define SOCFPGA_F2SDRAMMGR_REG_BASE U(0xf8024000)
+
+#define SOCFPGA_MMC_REG_BASE U(0xff808000)
+
+#define SOCFPGA_RSTMGR_REG_BASE U(0xffd11000)
+#define SOCFPGA_SYSMGR_REG_BASE U(0xffd12000)
+
+#define SOCFPGA_L4_PER_SCR_REG_BASE U(0xffd21000)
+#define SOCFPGA_L4_SYS_SCR_REG_BASE U(0xffd21100)
+#define SOCFPGA_SOC2FPGA_SCR_REG_BASE U(0xffd21200)
+#define SOCFPGA_LWSOC2FPGA_SCR_REG_BASE U(0xffd21300)
+
+/* Platform specific system counter */
+/*
+ * In N5X the clk init is done in Uboot SPL.
+ * BL31 shall bypass the clk init and only provides other APIs.
+ */
+#define PLAT_SYS_COUNTER_FREQ_IN_MHZ (400)
+
+#endif /* PLAT_SOCFPGA_DEF_H */
diff --git a/plat/intel/soc/n5x/platform.mk b/plat/intel/soc/n5x/platform.mk
new file mode 100644
index 0000000..be1ad8c
--- /dev/null
+++ b/plat/intel/soc/n5x/platform.mk
@@ -0,0 +1,52 @@
+#
+# Copyright (c) 2020-2022, Intel Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT_INCLUDES := \
+ -Iplat/intel/soc/n5x/include/ \
+ -Iplat/intel/soc/common/drivers/ \
+ -Iplat/intel/soc/common/include/
+
+# Include GICv2 driver files
+include drivers/arm/gic/v2/gicv2.mk
+DM_GICv2_SOURCES := \
+ ${GICV2_SOURCES} \
+ plat/common/plat_gicv2.c
+
+
+PLAT_BL_COMMON_SOURCES := \
+ ${DM_GICv2_SOURCES} \
+ 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/intel/soc/common/aarch64/platform_common.c \
+ plat/intel/soc/common/aarch64/plat_helpers.S \
+ plat/intel/soc/common/socfpga_delay_timer.c \
+ plat/intel/soc/common/drivers/ccu/ncore_ccu.c
+
+BL2_SOURCES +=
+
+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/intel/soc/n5x/bl31_plat_setup.c \
+ plat/intel/soc/common/socfpga_psci.c \
+ plat/intel/soc/common/socfpga_sip_svc.c \
+ plat/intel/soc/common/socfpga_sip_svc_v2.c \
+ plat/intel/soc/common/socfpga_topology.c \
+ plat/intel/soc/common/sip/socfpga_sip_ecc.c \
+ plat/intel/soc/common/sip/socfpga_sip_fcs.c \
+ plat/intel/soc/common/soc/socfpga_mailbox.c \
+ plat/intel/soc/common/soc/socfpga_reset_manager.c
+
+PROGRAMMABLE_RESET_ADDRESS := 0
+BL2_AT_EL3 := 1
+BL2_INV_DCACHE := 0
+MULTI_CONSOLE_API := 1
+USE_COHERENT_MEM := 1
diff --git a/plat/intel/soc/stratix10/bl2_plat_setup.c b/plat/intel/soc/stratix10/bl2_plat_setup.c
new file mode 100644
index 0000000..73e3216
--- /dev/null
+++ b/plat/intel/soc/stratix10/bl2_plat_setup.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/synopsys/dw_mmc.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+#include "qspi/cadence_qspi.h"
+#include "socfpga_emac.h"
+#include "socfpga_f2sdram_manager.h"
+#include "socfpga_handoff.h"
+#include "socfpga_mailbox.h"
+#include "socfpga_private.h"
+#include "socfpga_reset_manager.h"
+#include "socfpga_system_manager.h"
+#include "s10_clock_manager.h"
+#include "s10_memory_controller.h"
+#include "s10_mmc.h"
+#include "s10_pinmux.h"
+#include "wdt/watchdog.h"
+
+static struct mmc_device_info mmc_info;
+
+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 = 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_t console;
+ handoff reverse_handoff_ptr;
+
+ generic_delay_timer_init();
+
+ if (socfpga_get_handoff(&reverse_handoff_ptr))
+ return;
+ config_pinmux(&reverse_handoff_ptr);
+
+ 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_INTEL_UART_BASE, get_uart_clk(),
+ PLAT_BAUDRATE, &console);
+
+ socfpga_emac_init();
+ socfpga_delay_timer_init();
+ init_hard_memory_controller();
+ mailbox_init();
+ s10_mmc_init();
+
+ if (!intel_mailbox_is_fpga_not_ready()) {
+ socfpga_bridges_enable(SOC2FPGA_MASK | LWHPS2FPGA_MASK |
+ FPGA2SOC_MASK | F2SDRAM0_MASK | F2SDRAM1_MASK |
+ F2SDRAM2_MASK);
+ }
+}
+
+
+void bl2_el3_plat_arch_setup(void)
+{
+
+ 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());
+
+ mmc_info.mmc_dev_type = MMC_IS_SD;
+ mmc_info.ocr_voltage = OCR_3_3_3_4 | OCR_3_2_3_3;
+
+ /* Request ownership and direct access to QSPI */
+ mailbox_hps_qspi_enable();
+
+ switch (boot_source) {
+ case BOOT_SOURCE_SDMMC:
+ dw_mmc_init(&params, &mmc_info);
+ socfpga_io_setup(boot_source);
+ break;
+
+ case BOOT_SOURCE_QSPI:
+ 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);
+
+ assert(bl_mem_params);
+
+ 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)
+{
+}
+
diff --git a/plat/intel/soc/stratix10/bl31_plat_setup.c b/plat/intel/soc/stratix10/bl31_plat_setup.c
new file mode 100644
index 0000000..be0fae5
--- /dev/null
+++ b/plat/intel/soc/stratix10/bl31_plat_setup.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/bl_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include "socfpga_mailbox.h"
+#include "socfpga_noc.h"
+#include "socfpga_private.h"
+#include "socfpga_reset_manager.h"
+#include "socfpga_system_manager.h"
+#include "s10_memory_controller.h"
+#include "s10_pinmux.h"
+#include "s10_clock_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_t console;
+
+ mmio_write_64(PLAT_SEC_ENTRY, PLAT_SEC_WARM_ENTRY);
+
+ console_16550_register(PLAT_INTEL_UART_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);
+
+ /*
+ * Copy BL32 (if populated by BL31) and BL33 entry point information.
+ * They are stored in Secure RAM, in BL31's address space.
+ */
+
+ if (params_from_bl2->h.type == PARAM_BL_PARAMS &&
+ params_from_bl2->h.version >= VERSION_2) {
+
+ 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;
+ }
+ } else {
+ struct socfpga_bl31_params *arg_from_bl2 =
+ (struct socfpga_bl31_params *) from_bl2;
+
+ assert(arg_from_bl2->h.type == PARAM_BL31);
+ assert(arg_from_bl2->h.version >= VERSION_1);
+
+ bl32_image_ep_info = *arg_from_bl2->bl32_ep_info;
+ bl33_image_ep_info = *arg_from_bl2->bl33_ep_info;
+ }
+ SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+}
+
+static const interrupt_prop_t s10_interrupt_props[] = {
+ PLAT_INTEL_SOCFPGA_G1S_IRQ_PROPS(GICV2_INTR_GROUP0),
+ PLAT_INTEL_SOCFPGA_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_SOCFPGA_GICD_BASE,
+ .gicc_base = PLAT_INTEL_SOCFPGA_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)
+{
+ socfpga_delay_timer_init();
+
+ /* Initialize the gic cpu and distributor interfaces */
+ gicv2_driver_init(&plat_gicv2_gic_data);
+ gicv2_distif_init();
+ gicv2_pcpu_distif_init();
+ gicv2_cpuif_enable();
+
+ /* Signal secondary CPUs to jump to BL31 (BL2 = U-boot SPL) */
+ mmio_write_64(PLAT_CPU_RELEASE_ADDR,
+ (uint64_t)plat_secondary_cpus_bl31_entry);
+
+ mailbox_hps_stage_notify(HPS_EXECUTION_STATE_SSBL);
+
+ enable_ocram_firewall();
+}
+
+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);
+}
+
diff --git a/plat/intel/soc/stratix10/include/s10_clock_manager.h b/plat/intel/soc/stratix10/include/s10_clock_manager.h
new file mode 100644
index 0000000..cf57df3
--- /dev/null
+++ b/plat/intel/soc/stratix10/include/s10_clock_manager.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CLOCKMANAGER_H__
+#define __CLOCKMANAGER_H__
+
+#include "socfpga_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_EN_SDMMCCLK BIT(5)
+#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);
+uint32_t get_l3_clk(uint32_t ref_clk);
+uint32_t get_ref_clk(uint32_t pllglob);
+
+#endif
diff --git a/plat/intel/soc/stratix10/include/s10_memory_controller.h b/plat/intel/soc/stratix10/include/s10_memory_controller.h
new file mode 100644
index 0000000..155b279
--- /dev/null
+++ b/plat/intel/soc/stratix10/include/s10_memory_controller.h
@@ -0,0 +1,160 @@
+/*
+ * 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_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
diff --git a/plat/intel/soc/stratix10/include/s10_mmc.h b/plat/intel/soc/stratix10/include/s10_mmc.h
new file mode 100644
index 0000000..99f86f5
--- /dev/null
+++ b/plat/intel/soc/stratix10/include/s10_mmc.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __S10_MMC_H__
+#define __S10_MMC_H__
+
+void s10_mmc_init(void);
+
+#endif /* S10_MMC_H */
diff --git a/plat/intel/soc/stratix10/include/s10_pinmux.h b/plat/intel/soc/stratix10/include/s10_pinmux.h
new file mode 100644
index 0000000..82367d7
--- /dev/null
+++ b/plat/intel/soc/stratix10/include/s10_pinmux.h
@@ -0,0 +1,20 @@
+/*
+ * 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 "socfpga_handoff.h"
+
+void config_pinmux(handoff *handoff);
+
+#endif
+
diff --git a/plat/intel/soc/stratix10/include/socfpga_plat_def.h b/plat/intel/soc/stratix10/include/socfpga_plat_def.h
new file mode 100644
index 0000000..516cc75
--- /dev/null
+++ b/plat/intel/soc/stratix10/include/socfpga_plat_def.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_SOCFPGA_DEF_H
+#define PLAT_SOCFPGA_DEF_H
+
+#include <platform_def.h>
+
+/* Platform Setting */
+#define PLATFORM_MODEL PLAT_SOCFPGA_STRATIX10
+#define BOOT_SOURCE BOOT_SOURCE_SDMMC
+
+/* FPGA config helpers */
+#define INTEL_SIP_SMC_FPGA_CONFIG_ADDR 0x400000
+#define INTEL_SIP_SMC_FPGA_CONFIG_SIZE 0x1000000
+
+/* Register Mapping */
+#define SOCFPGA_CCU_NOC_REG_BASE 0xf7000000
+#define SOCFPGA_F2SDRAMMGR_REG_BASE U(0xf8024000)
+
+#define SOCFPGA_MMC_REG_BASE 0xff808000
+
+#define SOCFPGA_RSTMGR_REG_BASE 0xffd11000
+#define SOCFPGA_SYSMGR_REG_BASE 0xffd12000
+
+#define SOCFPGA_L4_PER_SCR_REG_BASE 0xffd21000
+#define SOCFPGA_L4_SYS_SCR_REG_BASE 0xffd21100
+#define SOCFPGA_SOC2FPGA_SCR_REG_BASE 0xffd21200
+#define SOCFPGA_LWSOC2FPGA_SCR_REG_BASE 0xffd21300
+
+/* Platform specific system counter */
+#define PLAT_SYS_COUNTER_FREQ_IN_MHZ get_cpu_clk()
+
+uint32_t get_cpu_clk(void);
+
+#endif /* PLATSOCFPGA_DEF_H */
+
diff --git a/plat/intel/soc/stratix10/platform.mk b/plat/intel/soc/stratix10/platform.mk
new file mode 100644
index 0000000..b7eb4bd
--- /dev/null
+++ b/plat/intel/soc/stratix10/platform.mk
@@ -0,0 +1,80 @@
+#
+# Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2019-2022, Intel Corporation. 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/
+
+# Include GICv2 driver files
+include drivers/arm/gic/v2/gicv2.mk
+AGX_GICv2_SOURCES := \
+ ${GICV2_SOURCES} \
+ plat/common/plat_gicv2.c
+
+
+PLAT_BL_COMMON_SOURCES := \
+ ${AGX_GICv2_SOURCES} \
+ 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/intel/soc/common/aarch64/platform_common.c \
+ plat/intel/soc/common/aarch64/plat_helpers.S \
+ plat/intel/soc/common/socfpga_delay_timer.c \
+ plat/intel/soc/common/soc/socfpga_firewall.c
+
+BL2_SOURCES += \
+ common/desc_image_load.c \
+ drivers/mmc/mmc.c \
+ drivers/intel/soc/stratix10/io/s10_memmap_qspi.c \
+ drivers/io/io_storage.c \
+ drivers/io/io_block.c \
+ drivers/io/io_fip.c \
+ drivers/partition/partition.c \
+ drivers/partition/gpt.c \
+ drivers/synopsys/emmc/dw_mmc.c \
+ lib/cpus/aarch64/cortex_a53.S \
+ plat/intel/soc/stratix10/bl2_plat_setup.c \
+ plat/intel/soc/stratix10/soc/s10_clock_manager.c \
+ plat/intel/soc/stratix10/soc/s10_memory_controller.c \
+ plat/intel/soc/stratix10/soc/s10_mmc.c \
+ plat/intel/soc/stratix10/soc/s10_pinmux.c \
+ plat/intel/soc/common/bl2_plat_mem_params_desc.c \
+ plat/intel/soc/common/socfpga_image_load.c \
+ plat/intel/soc/common/socfpga_storage.c \
+ plat/intel/soc/common/soc/socfpga_emac.c \
+ plat/intel/soc/common/soc/socfpga_handoff.c \
+ plat/intel/soc/common/soc/socfpga_mailbox.c \
+ plat/intel/soc/common/soc/socfpga_reset_manager.c \
+ plat/intel/soc/common/drivers/qspi/cadence_qspi.c \
+ plat/intel/soc/common/drivers/wdt/watchdog.c
+
+include lib/zlib/zlib.mk
+PLAT_INCLUDES += -Ilib/zlib
+BL2_SOURCES += $(ZLIB_SOURCES)
+
+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/intel/soc/stratix10/soc/s10_clock_manager.c \
+ plat/intel/soc/stratix10/bl31_plat_setup.c \
+ plat/intel/soc/common/socfpga_psci.c \
+ plat/intel/soc/common/socfpga_sip_svc.c \
+ plat/intel/soc/common/socfpga_sip_svc_v2.c \
+ plat/intel/soc/common/socfpga_topology.c \
+ plat/intel/soc/common/sip/socfpga_sip_ecc.c \
+ plat/intel/soc/common/sip/socfpga_sip_fcs.c \
+ plat/intel/soc/common/soc/socfpga_mailbox.c \
+ plat/intel/soc/common/soc/socfpga_reset_manager.c
+
+PROGRAMMABLE_RESET_ADDRESS := 0
+BL2_AT_EL3 := 1
+USE_COHERENT_MEM := 1
diff --git a/plat/intel/soc/stratix10/soc/s10_clock_manager.c b/plat/intel/soc/stratix10/soc/s10_clock_manager.c
new file mode 100644
index 0000000..30009f7
--- /dev/null
+++ b/plat/intel/soc/stratix10/soc/s10_clock_manager.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2019-2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#include "s10_clock_manager.h"
+#include "socfpga_handoff.h"
+#include "socfpga_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(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_1),
+ hoff_ptr->hps_osc_clk_h);
+ mmio_write_32(SOCFPGA_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 = SOCFPGA_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 = SOCFPGA_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;
+}
+
+/* Get cpu freq clock */
+uint32_t get_cpu_clk(void)
+{
+ uint32_t data32, ref_clk, cpu_clk;
+
+ data32 = mmio_read_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_PLLGLOB);
+ ref_clk = get_ref_clk(data32);
+
+ cpu_clk = get_l3_clk(ref_clk)/PLAT_SYS_COUNTER_CONVERT_TO_MHZ;
+
+ return cpu_clk;
+}
diff --git a/plat/intel/soc/stratix10/soc/s10_memory_controller.c b/plat/intel/soc/stratix10/soc/s10_memory_controller.c
new file mode 100644
index 0000000..ac756ab
--- /dev/null
+++ b/plat/intel/soc/stratix10/soc/s10_memory_controller.c
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <platform_def.h>
+#include <string.h>
+
+#include "s10_memory_controller.h"
+#include "socfpga_reset_manager.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 1000
+#define CLEAR_EMIF_TIMEOUT 1000
+
+#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(500);
+ } 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(SOCFPGA_RSTMGR(BRGMODRST), RSTMGR_FIELD(BRG, 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");
+ }
+}
+
diff --git a/plat/intel/soc/stratix10/soc/s10_mmc.c b/plat/intel/soc/stratix10/soc/s10_mmc.c
new file mode 100644
index 0000000..333bdd6
--- /dev/null
+++ b/plat/intel/soc/stratix10/soc/s10_mmc.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2022, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <lib/mmio.h>
+
+#include "s10_clock_manager.h"
+#include "socfpga_system_manager.h"
+
+void s10_mmc_init(void)
+{
+ mmio_clrbits_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_EN,
+ ALT_CLKMGR_PERPLL_EN_SDMMCCLK);
+ mmio_write_32(SOCFPGA_SYSMGR(SDMMC),
+ SYSMGR_SDMMC_SMPLSEL(2) | SYSMGR_SDMMC_DRVSEL(3));
+ mmio_setbits_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_EN,
+ ALT_CLKMGR_PERPLL_EN_SDMMCCLK);
+}
diff --git a/plat/intel/soc/stratix10/soc/s10_pinmux.c b/plat/intel/soc/stratix10/soc/s10_pinmux.c
new file mode 100644
index 0000000..7fb4711
--- /dev/null
+++ b/plat/intel/soc/stratix10/soc/s10_pinmux.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#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]);
+ }
+
+}
+
diff --git a/plat/marvell/armada/a3k/a3700/board/pm_src.c b/plat/marvell/armada/a3k/a3700/board/pm_src.c
new file mode 100644
index 0000000..247f73b
--- /dev/null
+++ b/plat/marvell/armada/a3k/a3700/board/pm_src.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <a3700_pm.h>
+#include <plat_marvell.h>
+
+/* This struct provides the PM wake up src configuration for A3720 Development Board */
+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;
+}
+
diff --git a/plat/marvell/armada/a3k/a3700/mvebu_def.h b/plat/marvell/armada/a3k/a3700/mvebu_def.h
new file mode 100644
index 0000000..dad1085
--- /dev/null
+++ b/plat/marvell/armada/a3k/a3700/mvebu_def.h
@@ -0,0 +1,13 @@
+/*
+ * 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 <a3700_plat_def.h>
+
+#endif /* MVEBU_DEF_H */
diff --git a/plat/marvell/armada/a3k/a3700/plat_bl31_setup.c b/plat/marvell/armada/a3k/a3700/plat_bl31_setup.c
new file mode 100644
index 0000000..6862a86
--- /dev/null
+++ b/plat/marvell/armada/a3k/a3700/plat_bl31_setup.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+#include <dram_win.h>
+#include <io_addr_dec.h>
+#include <marvell_plat_priv.h>
+#include <plat_marvell.h>
+
+/* 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;
+ }
+}
diff --git a/plat/marvell/armada/a3k/a3700/platform.mk b/plat/marvell/armada/a3k/a3700/platform.mk
new file mode 100644
index 0000000..050af41
--- /dev/null
+++ b/plat/marvell/armada/a3k/a3700/platform.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+include plat/marvell/armada/a3k/common/a3700_common.mk
+
+include plat/marvell/armada/common/marvell_common.mk
diff --git a/plat/marvell/armada/a3k/common/a3700_common.mk b/plat/marvell/armada/a3k/common/a3700_common.mk
new file mode 100644
index 0000000..b9c28de
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/a3700_common.mk
@@ -0,0 +1,247 @@
+#
+# Copyright (C) 2018-2021 Marvell International Ltd.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+MARVELL_PLAT_BASE := plat/marvell/armada
+MARVELL_PLAT_INCLUDE_BASE := include/plat/marvell/armada
+PLAT_FAMILY := a3k
+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
+ERRATA_A53_1530924 := 1
+
+include plat/marvell/marvell.mk
+
+#*********** A3700 *************
+
+# GICV3
+$(eval $(call add_define,CONFIG_GICV3))
+
+# CCI-400
+$(eval $(call add_define,USE_CCI))
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+MARVELL_GIC_SOURCES := ${GICV3_SOURCES} \
+ plat/common/plat_gicv3.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 \
+ $(PLAT_COMMON_BASE)/aarch64/a3700_clock.S \
+ $(MARVELL_DRV_BASE)/uart/a3700_console.S
+
+BL1_SOURCES += $(PLAT_COMMON_BASE)/aarch64/plat_helpers.S \
+ lib/cpus/aarch64/cortex_a53.S
+
+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_cci.c \
+ $(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_FAMILY_BASE)/$(PLAT)/plat_bl31_setup.c \
+ $(MARVELL_COMMON_BASE)/marvell_cci.c \
+ $(MARVELL_COMMON_BASE)/marvell_ddr_info.c \
+ $(MARVELL_COMMON_BASE)/marvell_gicv3.c \
+ $(MARVELL_GIC_SOURCES) \
+ drivers/arm/cci/cci.c \
+ $(PLAT_COMMON_BASE)/a3700_sip_svc.c \
+ $(MARVELL_DRV)
+
+ifeq ($(HANDLE_EA_EL3_FIRST_NS),1)
+BL31_SOURCES += $(PLAT_COMMON_BASE)/a3700_ea.c
+endif
+
+ifeq ($(CM3_SYSTEM_RESET),1)
+BL31_SOURCES += $(PLAT_COMMON_BASE)/cm3_system_reset.c
+endif
+
+ifeq ($(A3720_DB_PM_WAKEUP_SRC),1)
+BL31_SOURCES += $(PLAT_FAMILY_BASE)/$(PLAT)/board/pm_src.c
+endif
+
+ifdef WTP
+
+# Do not remove! Following checks are required to ensure correct TF-A builds, removing these checks leads to broken TF-A builds
+$(if $(wildcard $(value WTP)/*),,$(error "'WTP=$(value WTP)' was specified, but '$(value WTP)' directory does not exist"))
+$(if $(shell git -C $(value WTP) rev-parse --show-cdup 2>&1),$(error "'WTP=$(value WTP)' was specified, but '$(value WTP)' does not contain valid A3700-utils-marvell git repository"))
+
+TBB := $(WTP)/wtptp/src/TBB_Linux/release/TBB_linux
+
+BUILD_UART := uart-images
+UART_IMAGE := $(BUILD_UART).tgz.bin
+
+ifeq ($(MARVELL_SECURE_BOOT),1)
+TIM_CFG := $(BUILD_PLAT)/atf-tim.txt
+TIM_UART_CFG := $(BUILD_PLAT)/$(BUILD_UART)/atf-tim.txt
+IMAGESPATH := $(WTP)/tim/trusted
+TIMN_CFG := $(BUILD_PLAT)/atf-timN.txt
+TIMN_UART_CFG := $(BUILD_PLAT)/$(BUILD_UART)/atf-timN.txt
+TIMN_SIG := $(IMAGESPATH)/timnsign.txt
+TIM2IMGARGS := -i $(TIM_CFG) -n $(TIMN_CFG)
+TIMN_UART_IMAGE := $$(grep "Image Filename:" -m 1 $(TIMN_UART_CFG) | cut -c 17-)
+else #MARVELL_SECURE_BOOT
+TIM_CFG := $(BUILD_PLAT)/atf-ntim.txt
+TIM_UART_CFG := $(BUILD_PLAT)/$(BUILD_UART)/atf-ntim.txt
+IMAGESPATH := $(WTP)/tim/untrusted
+TIM2IMGARGS := -i $(TIM_CFG)
+endif #MARVELL_SECURE_BOOT
+
+TIM_UART_IMAGE := $$(grep "Image Filename:" -m 1 $(TIM_UART_CFG) | cut -c 17-)
+
+TIMBUILD := $(WTP)/script/buildtim.sh
+TIM2IMG := $(WTP)/script/tim2img.pl
+TIMDDRTOOL := $(WTP)/tim/ddr/ddr_tool
+
+$(TIMBUILD): $(TIMDDRTOOL)
+
+# 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 := $(WTP)/wtmi/fuse/build/fuse.bin
+
+# WTMI_MULTI_IMG is composed of CM3 RTOS image (WTMI_IMG)
+# and sys-init image.
+WTMI_MULTI_IMG := $(WTP)/wtmi/build/wtmi.bin
+
+WTMI_ENC_IMG := wtmi-enc.bin
+
+SRCPATH := $(dir $(BL33))
+
+CLOCKSPRESET ?= CPU_800_DDR_800
+
+DDR_TOPOLOGY ?= 0
+
+BOOTDEV ?= SPINOR
+PARTNUM ?= 0
+
+TIMBLDARGS := $(MARVELL_SECURE_BOOT) $(BOOTDEV) $(IMAGESPATH) $(WTP) $(CLOCKSPRESET) \
+ $(DDR_TOPOLOGY) $(PARTNUM) $(DEBUG) $(TIM_CFG) $(TIMN_CFG) $(TIMN_SIG) 1
+TIMBLDUARTARGS := $(MARVELL_SECURE_BOOT) UART $(IMAGESPATH) $(WTP) $(CLOCKSPRESET) \
+ $(DDR_TOPOLOGY) 0 0 $(TIM_UART_CFG) $(TIMN_UART_CFG) $(TIMN_SIG) 0
+
+UART_IMAGES := $(BUILD_UART)/$(TIM_UART_IMAGE)
+ifeq ($(MARVELL_SECURE_BOOT),1)
+UART_IMAGES += $(BUILD_UART)/$(TIMN_UART_IMAGE)
+endif
+UART_IMAGES += $(BUILD_UART)/wtmi_h.bin $(BUILD_UART)/boot-image_h.bin
+
+CRYPTOPP_LIBDIR ?= $(CRYPTOPP_PATH)
+CRYPTOPP_INCDIR ?= $(CRYPTOPP_PATH)
+
+$(TBB): FORCE
+# Do not remove! Following checks are required to ensure correct TF-A builds, removing these checks leads to broken TF-A builds
+ $(if $(CRYPTOPP_LIBDIR),,$(error "Platform '$(PLAT)' for WTP image tool requires CRYPTOPP_PATH or CRYPTOPP_LIBDIR. Please set CRYPTOPP_PATH or CRYPTOPP_LIBDIR to point to the right directory"))
+ $(if $(CRYPTOPP_INCDIR),,$(error "Platform '$(PLAT)' for WTP image tool requires CRYPTOPP_PATH or CRYPTOPP_INCDIR. Please set CRYPTOPP_PATH or CRYPTOPP_INCDIR to point to the right directory"))
+ $(if $(wildcard $(CRYPTOPP_LIBDIR)/*),,$(error "Either 'CRYPTOPP_PATH' or 'CRYPTOPP_LIB' was set to '$(CRYPTOPP_LIBDIR)', but '$(CRYPTOPP_LIBDIR)' does not exist"))
+ $(if $(wildcard $(CRYPTOPP_INCDIR)/*),,$(error "Either 'CRYPTOPP_PATH' or 'CRYPTOPP_INCDIR' was set to '$(CRYPTOPP_INCDIR)', but '$(CRYPTOPP_INCDIR)' does not exist"))
+ifdef CRYPTOPP_PATH
+ $(Q)$(MAKE) --no-print-directory -C $(CRYPTOPP_PATH) -f GNUmakefile
+endif
+ $(Q)$(MAKE) --no-print-directory -C $(WTP)/wtptp/src/TBB_Linux -f TBB_linux.mak LIBDIR=$(CRYPTOPP_LIBDIR) INCDIR=$(CRYPTOPP_INCDIR)
+
+$(WTMI_MULTI_IMG): FORCE
+ $(Q)$(MAKE) --no-print-directory -C $(WTP) WTMI_IMG=$(WTMI_IMG) DDR_TOPOLOGY=$(DDR_TOPOLOGY) CLOCKSPRESET=$(CLOCKSPRESET) WTMI
+
+$(BUILD_PLAT)/wtmi.bin: $(WTMI_MULTI_IMG)
+ $(Q)cp -a $(WTMI_MULTI_IMG) $(BUILD_PLAT)/wtmi.bin
+
+$(TIMDDRTOOL): FORCE
+# Do not remove! Following checks are required to ensure correct TF-A builds, removing these checks leads to broken TF-A builds
+ $(if $(value MV_DDR_PATH),,$(error "Platform '${PLAT}' for ddr tool requires MV_DDR_PATH. Please set MV_DDR_PATH to point to the right directory"))
+ $(if $(wildcard $(value MV_DDR_PATH)/*),,$(error "'MV_DDR_PATH=$(value MV_DDR_PATH)' was specified, but '$(value MV_DDR_PATH)' directory does not exist"))
+ $(if $(shell git -C $(value MV_DDR_PATH) rev-parse --show-cdup 2>&1),$(error "'MV_DDR_PATH=$(value MV_DDR_PATH)' was specified, but '$(value MV_DDR_PATH)' does not contain valid mv-ddr-marvell git repository"))
+ $(Q)$(MAKE) --no-print-directory -C $(WTP) MV_DDR_PATH=$(MV_DDR_PATH) DDR_TOPOLOGY=$(DDR_TOPOLOGY) mv_ddr
+
+$(BUILD_PLAT)/$(UART_IMAGE): $(BUILD_PLAT)/$(BOOT_IMAGE) $(BUILD_PLAT)/wtmi.bin $(TBB) $(TIMBUILD) $(TIMDDRTOOL)
+ @$(ECHO_BLANK_LINE)
+ @echo "Building uart images"
+ $(Q)mkdir -p $(BUILD_PLAT)/$(BUILD_UART)
+ $(Q)cp -a $(BUILD_PLAT)/wtmi.bin $(BUILD_PLAT)/$(BUILD_UART)/wtmi.bin
+ $(Q)cp -a $(BUILD_PLAT)/$(BOOT_IMAGE) $(BUILD_PLAT)/$(BUILD_UART)/$(BOOT_IMAGE)
+ $(Q)cd $(BUILD_PLAT)/$(BUILD_UART) && $(TIMBUILD) $(TIMBLDUARTARGS)
+ $(Q)sed -i 's|WTMI_IMG|wtmi.bin|1' $(TIM_UART_CFG)
+ $(Q)sed -i 's|BOOT_IMAGE|$(BOOT_IMAGE)|1' $(TIM_UART_CFG)
+ifeq ($(MARVELL_SECURE_BOOT),1)
+ $(Q)sed -i 's|WTMI_IMG|wtmi.bin|1' $(TIMN_UART_CFG)
+ $(Q)sed -i 's|BOOT_IMAGE|$(BOOT_IMAGE)|1' $(TIMN_UART_CFG)
+endif
+ $(Q)cd $(BUILD_PLAT)/$(BUILD_UART) && $(TBB) -r $(TIM_UART_CFG) -v -D
+ifeq ($(MARVELL_SECURE_BOOT),1)
+ $(Q)cd $(BUILD_PLAT)/$(BUILD_UART) && $(TBB) -r $(TIMN_UART_CFG)
+endif
+ $(Q)tar czf $(BUILD_PLAT)/$(UART_IMAGE) -C $(BUILD_PLAT) $(UART_IMAGES)
+ @$(ECHO_BLANK_LINE)
+ @echo "Built $@ successfully"
+ @$(ECHO_BLANK_LINE)
+
+$(BUILD_PLAT)/$(FLASH_IMAGE): $(BUILD_PLAT)/$(BOOT_IMAGE) $(BUILD_PLAT)/wtmi.bin $(TBB) $(TIMBUILD) $(TIMDDRTOOL) $(TIM2IMG)
+ @$(ECHO_BLANK_LINE)
+ @echo "Building flash image"
+ $(Q)cd $(BUILD_PLAT) && $(TIMBUILD) $(TIMBLDARGS)
+ $(Q)sed -i 's|WTMI_IMG|wtmi.bin|1' $(TIM_CFG)
+ $(Q)sed -i 's|BOOT_IMAGE|$(BOOT_IMAGE)|1' $(TIM_CFG)
+ifeq ($(MARVELL_SECURE_BOOT),1)
+ $(Q)sed -i 's|WTMI_IMG|wtmi.bin|1' $(TIMN_CFG)
+ $(Q)sed -i 's|BOOT_IMAGE|$(BOOT_IMAGE)|1' $(TIMN_CFG)
+ @$(ECHO_BLANK_LINE)
+ @echo "=======================================================";
+ @echo " Secure boot. Encrypting wtmi and boot-image";
+ @echo "=======================================================";
+ @$(ECHO_BLANK_LINE)
+ $(Q)cp $(BUILD_PLAT)/wtmi.bin $(BUILD_PLAT)/wtmi-align.bin
+ $(Q)truncate -s %16 $(BUILD_PLAT)/wtmi-align.bin
+ $(Q)${OPENSSL_BIN_PATH}/openssl enc -aes-256-cbc -e -in $(BUILD_PLAT)/wtmi-align.bin \
+ -out $(BUILD_PLAT)/$(WTMI_ENC_IMG) \
+ -K `cat $(IMAGESPATH)/aes-256.txt` -nosalt \
+ -iv `cat $(IMAGESPATH)/iv.txt` -p
+ $(Q)truncate -s %16 $(BUILD_PLAT)/$(BOOT_IMAGE);
+ $(Q)${OPENSSL_BIN_PATH}/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
+ $(Q)cd $(BUILD_PLAT) && $(TBB) -r $(TIM_CFG) -v -D
+ifeq ($(MARVELL_SECURE_BOOT),1)
+ $(Q)cd $(BUILD_PLAT) && $(TBB) -r $(TIMN_CFG)
+ $(Q)sed -i 's|wtmi.bin|$(WTMI_ENC_IMG)|1' $(TIMN_CFG)
+ $(Q)sed -i 's|$(BOOT_IMAGE)|$(BOOT_ENC_IMAGE)|1' $(TIMN_CFG)
+endif
+ $(Q)cd $(BUILD_PLAT) && $(TIM2IMG) $(TIM2IMGARGS) -o $(BUILD_PLAT)/$(FLASH_IMAGE)
+ @$(ECHO_BLANK_LINE)
+ @echo "Built $@ successfully"
+ @$(ECHO_BLANK_LINE)
+
+clean realclean distclean: mrvl_clean
+
+.PHONY: mrvl_clean
+mrvl_clean:
+ -$(Q)$(MAKE) --no-print-directory -C $(WTP) MV_DDR_PATH=$(MV_DDR_PATH) clean
+ -$(Q)$(MAKE) --no-print-directory -C $(WTP)/wtptp/src/TBB_Linux -f TBB_linux.mak clean
+ifdef CRYPTOPP_PATH
+ -$(Q)$(MAKE) --no-print-directory -C $(CRYPTOPP_PATH) -f GNUmakefile clean
+endif
+
+else # WTP
+
+$(BUILD_PLAT)/$(UART_IMAGE) $(BUILD_PLAT)/$(FLASH_IMAGE):
+ $(error "Platform '${PLAT}' for target '$@' requires WTP. Please set WTP to point to the right directory")
+
+endif # WTP
+
+.PHONY: mrvl_uart
+mrvl_uart: $(BUILD_PLAT)/$(UART_IMAGE)
diff --git a/plat/marvell/armada/a3k/common/a3700_ea.c b/plat/marvell/armada/a3k/common/a3700_ea.c
new file mode 100644
index 0000000..5696b5c
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/a3700_ea.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 Repk repk@triplefau.lt
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <inttypes.h>
+#include <stdint.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <arch_helpers.h>
+#include <plat/common/platform.h>
+#include <bl31/ea_handle.h>
+
+#define A53_SERR_INT_AXI_SLVERR_ON_EXTERNAL_ACCESS 0xbf000002
+
+/*
+ * This source file with custom plat_ea_handler function is compiled only when
+ * building TF-A with compile option HANDLE_EA_EL3_FIRST_NS=1
+ */
+void plat_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
+ void *handle, uint64_t flags)
+{
+ unsigned int level = (unsigned int)GET_EL(read_spsr_el3());
+
+ /*
+ * Asynchronous External Abort with syndrome 0xbf000002 on Cortex A53
+ * core means SError interrupt caused by AXI SLVERR on external access.
+ *
+ * In most cases this indicates a bug in U-Boot or Linux kernel driver
+ * pci-aardvark.c which implements access to A3700 PCIe config space.
+ * Driver does not wait for PCIe PIO transfer completion and try to
+ * start a new PCIe PIO transfer while previous has not finished yet.
+ * A3700 PCIe controller in this case sends SLVERR via AXI which results
+ * in a fatal Asynchronous SError interrupt on Cortex A53 CPU.
+ *
+ * Following patches fix that bug in U-Boot and Linux kernel drivers:
+ * https://source.denx.de/u-boot/u-boot/-/commit/eccbd4ad8e4e182638eafbfb87ac139c04f24a01
+ * https://git.kernel.org/stable/c/f18139966d072dab8e4398c95ce955a9742e04f7
+ *
+ * As a hacky workaround for unpatched U-Boot and Linux kernel drivers
+ * ignore all asynchronous aborts with that syndrome value received on
+ * CPU from level lower than EL3.
+ *
+ * Because these aborts are delivered on CPU asynchronously, they are
+ * imprecise and we cannot check the real reason of abort and neither
+ * who and why sent this abort. We expect that on A3700 it is always
+ * PCIe controller.
+ *
+ * Hence ignoring all aborts with this syndrome value is just a giant
+ * hack that we need only because of bugs in old U-Boot and Linux kernel
+ * versions and because it was decided that TF-A would implement this
+ * hack for U-Boot and Linux kernel it in this way. New patched U-Boot
+ * and kernel versions do not need it anymore.
+ *
+ * Links to discussion about this workaround:
+ * https://lore.kernel.org/linux-pci/20190316161243.29517-1-repk@triplefau.lt/
+ * https://lore.kernel.org/linux-pci/971be151d24312cc533989a64bd454b4@www.loen.fr/
+ * https://review.trustedfirmware.org/c/TF-A/trusted-firmware-a/+/1541
+ */
+ if (level < MODE_EL3 && ea_reason == ERROR_EA_ASYNC &&
+ syndrome == A53_SERR_INT_AXI_SLVERR_ON_EXTERNAL_ACCESS) {
+ ERROR_NL();
+ ERROR("Ignoring Asynchronous External Abort with"
+ " syndrome 0x%" PRIx64 " received on 0x%lx from %s\n",
+ syndrome, read_mpidr_el1(), get_el_str(level));
+ ERROR("SError interrupt: AXI SLVERR on external access\n");
+ ERROR("This indicates a bug in pci-aardvark.c driver\n");
+ ERROR("Please update U-Boot/Linux to the latest version\n");
+ ERROR_NL();
+ console_flush();
+ return;
+ }
+
+ plat_default_ea_handler(ea_reason, syndrome, cookie, handle, flags);
+}
diff --git a/plat/marvell/armada/a3k/common/a3700_sip_svc.c b/plat/marvell/armada/a3k/common/a3700_sip_svc.c
new file mode 100644
index 0000000..e8ac5fc
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/a3700_sip_svc.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/smccc.h>
+
+#include <marvell_plat_priv.h>
+#include <plat_marvell.h>
+
+#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
+);
diff --git a/plat/marvell/armada/a3k/common/aarch64/a3700_clock.S b/plat/marvell/armada/a3k/common/aarch64/a3700_clock.S
new file mode 100644
index 0000000..f79516f
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/aarch64/a3700_clock.S
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <asm_macros.S>
+#include <platform_def.h>
+
+/*
+ * 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)
+
+ /* -----------------------------------------------------
+ * uint32_t get_ref_clk (void);
+ *
+ * returns reference clock in MHz (25 or 40)
+ * -----------------------------------------------------
+ */
+.globl get_ref_clk
+func get_ref_clk
+ mov_imm x0, MVEBU_TEST_PIN_LATCH_N
+ ldr w0, [x0]
+ tst w0, #MVEBU_XTAL_MODE_MASK
+ bne 40
+ mov w0, #25
+ ret
+40:
+ mov w0, #40
+ ret
+endfunc get_ref_clk
diff --git a/plat/marvell/armada/a3k/common/aarch64/a3700_common.c b/plat/marvell/armada/a3k/common/aarch64/a3700_common.c
new file mode 100644
index 0000000..6351285
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/aarch64/a3700_common.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+#include <plat_marvell.h>
+
+/* 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;
diff --git a/plat/marvell/armada/a3k/common/aarch64/plat_helpers.S b/plat/marvell/armada/a3k/common/aarch64/plat_helpers.S
new file mode 100644
index 0000000..90d76f0
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/aarch64/plat_helpers.S
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/marvell/armada/a3k/common/cm3_system_reset.c b/plat/marvell/armada/a3k/common/cm3_system_reset.c
new file mode 100644
index 0000000..f105d59
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/cm3_system_reset.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 Marek Behun, CZ.NIC
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <stdbool.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <mvebu_def.h>
+
+/* Cortex-M3 Secure Processor Mailbox Registers */
+#define MVEBU_RWTM_PARAM0_REG (MVEBU_RWTM_REG_BASE)
+#define MVEBU_RWTM_CMD_REG (MVEBU_RWTM_REG_BASE + 0x40)
+#define MVEBU_RWTM_HOST_INT_RESET_REG (MVEBU_RWTM_REG_BASE + 0xC8)
+#define MVEBU_RWTM_HOST_INT_MASK_REG (MVEBU_RWTM_REG_BASE + 0xCC)
+#define MVEBU_RWTM_HOST_INT_SP_COMPLETE BIT(0)
+
+#define MVEBU_RWTM_REBOOT_CMD 0x0009
+#define MVEBU_RWTM_REBOOT_MAGIC 0xDEADBEEF
+
+static inline bool rwtm_completed(void)
+{
+ return (mmio_read_32(MVEBU_RWTM_HOST_INT_RESET_REG) &
+ MVEBU_RWTM_HOST_INT_SP_COMPLETE) != 0;
+}
+
+static bool rwtm_wait(int ms)
+{
+ while (ms && !rwtm_completed()) {
+ mdelay(1);
+ --ms;
+ }
+
+ return rwtm_completed();
+}
+
+void cm3_system_reset(void)
+{
+ int tries = 5;
+
+ for (; tries > 0; --tries) {
+ mmio_clrbits_32(MVEBU_RWTM_HOST_INT_RESET_REG,
+ MVEBU_RWTM_HOST_INT_SP_COMPLETE);
+
+ mmio_write_32(MVEBU_RWTM_PARAM0_REG, MVEBU_RWTM_REBOOT_MAGIC);
+ mmio_write_32(MVEBU_RWTM_CMD_REG, MVEBU_RWTM_REBOOT_CMD);
+
+ if (rwtm_wait(10)) {
+ break;
+ }
+
+ mdelay(100);
+ }
+
+ /* If we reach here, the command is not implemented. */
+ WARN("System reset command not implemented in WTMI firmware!\n");
+}
diff --git a/plat/marvell/armada/a3k/common/dram_win.c b/plat/marvell/armada/a3k/common/dram_win.c
new file mode 100644
index 0000000..9d7b3a9
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/dram_win.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2018-2021 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <string.h>
+
+#include <lib/mmio.h>
+
+#include <dram_win.h>
+#include <marvell_plat_priv.h>
+#include <mvebu.h>
+#include <plat_marvell.h>
+
+/* 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 of DRAM; to better utilize address space (for maximization of
+ * DRAM usage), we will use the configuration of CPU windows below:
+ * - Internal Regs and Boot ROM windows are kept as default;
+ * - CCI-400 is moved from its default address to another address
+ * (this is actually done even if DRAM size is not more than 2 GB,
+ * because the firmware is compiled with that address as a
+ * constant);
+ * - PCIe window is moved to another address;
+ * - Use 4 CPU decode windows for DRAM, which cover 3.75GB DRAM;
+ * DDR window 0 is configured in tim header with 2G B size, no need
+ * to configure it again here;
+ *
+ * 0xFFFFFFFF ---> +-----------------------+
+ * | Boot ROM | 1 MB
+ * | AP Boot ROM - 16 KB: |
+ * | 0xFFFF0000-0xFFFF4000 |
+ * 0xFFF00000 ---> +-----------------------+
+ * : :
+ * 0xFE010000 ---> +-----------------------+
+ * | CCI Regs | 64 KB
+ * 0xFE000000 ---> +-----------------------+
+ * : :
+ * 0xFA000000 ---> +-----------------------+
+ * | PCIE | 128 MB
+ * 0xF2000000 ---> +-----------------------+
+ * | DDR window 3 | 512 MB
+ * 0xD2000000 ---> +-----------------------+
+ * | Internal Regs | 32 MB
+ * 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,
+ 0xd2000000,
+ 0x20000000,
+ 0xd2000000},
+ {CPU_WIN_ENABLED,
+ CPU_WIN_TARGET_PCIE,
+ 0xf2000000,
+ 0x08000000,
+ 0xf2000000},
+ },
+};
+
+/*
+ * 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 <Base> 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]);
+}
+
diff --git a/plat/marvell/armada/a3k/common/include/a3700_plat_def.h b/plat/marvell/armada/a3k/common/include/a3700_plat_def.h
new file mode 100644
index 0000000..4d45e15
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/include/a3700_plat_def.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2018-2021 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef A3700_PLAT_DEF_H
+#define A3700_PLAT_DEF_H
+
+#include <marvell_def.h>
+
+
+#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 base address
+ * This address is absolute, not relative to MVEBU_REGS_BASE.
+ * This is not the default CCI base address (that would be 0xD8000000).
+ * Rather we remap CCI to this address to better utilize the address space.
+ * (The remapping is done in plat/marvell/armada/a3k/common/plat_cci.c)
+ */
+#define MVEBU_CCI_BASE 0xFE000000
+
+/*****************************************************************************
+ * North and south bridge reset registers
+ *****************************************************************************
+ */
+#define MVEBU_NB_RESET_REG (MVEBU_REGS_BASE + 0x12400)
+#define MVEBU_NB_RESET_I2C1_N (1 << 0)
+#define MVEBU_NB_RESET_1WIRE_N (1 << 1)
+#define MVEBU_NB_RESET_SPI_N (1 << 2)
+#define MVEBU_NB_RESET_UART_N (1 << 3)
+#define MVEBU_NB_RESET_XTL_N (1 << 4)
+#define MVEBU_NB_RESET_I2C2_N (1 << 5)
+#define MVEBU_NB_RESET_UART2_N (1 << 6)
+#define MVEBU_NB_RESET_AVS_N (1 << 7)
+#define MVEBU_NB_RESET_DDR_N (1 << 10)
+#define MVEBU_NB_RESET_SETM_N (1 << 11)
+#define MVEBU_NB_RESET_DMA_N (1 << 12)
+#define MVEBU_NB_RESET_TSECM_N (1 << 13)
+#define MVEBU_NB_RESET_SDIO_N (1 << 14)
+#define MVEBU_NB_RESET_SATA_N (1 << 15)
+#define MVEBU_NB_RESET_PWRMGT_N (1 << 16)
+#define MVEBU_NB_RESET_OTP_N (1 << 17)
+#define MVEBU_NB_RESET_EIP_N (1 << 18)
+#define MVEBU_SB_RESET_REG (MVEBU_REGS_BASE + 0x18600)
+#define MVEBU_SB_RESET_MCIPHY (1 << 1)
+#define MVEBU_SB_RESET_SDIO_N (1 << 2)
+#define MVEBU_SB_RESET_PCIE_N (1 << 3)
+#define MVEBU_SB_RESET_GBE1_N (1 << 4)
+#define MVEBU_SB_RESET_GBE0_N (1 << 5)
+#define MVEBU_SB_RESET_USB2PHY (1 << 6)
+#define MVEBU_SB_RESET_USB2HPHY (1 << 7)
+#define MVEBU_SB_RESET_MCI_N (1 << 8)
+#define MVEBU_SB_RESET_PWRMGT_N (1 << 9)
+#define MVEBU_SB_RESET_EBM_N (1 << 10)
+#define MVEBU_SB_RESET_OTP_N (1 << 11)
+
+/*****************************************************************************
+ * 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)
+
+/*****************************************************************************
+ * Cortex-M3 Secure Processor Mailbox constants
+ *****************************************************************************
+ */
+#define MVEBU_RWTM_REG_BASE (MVEBU_REGS_BASE + 0xB0000)
+
+#endif /* A3700_PLAT_DEF_H */
diff --git a/plat/marvell/armada/a3k/common/include/a3700_pm.h b/plat/marvell/armada/a3k/common/include/a3700_pm.h
new file mode 100644
index 0000000..44dbb9f
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/include/a3700_pm.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016-2020 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef A3700_PM_H
+#define A3700_PM_H
+
+#include <stdint.h>
+
+/* 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);
+
+void cm3_system_reset(void);
+
+#endif /* A3700_PM_H */
diff --git a/plat/marvell/armada/a3k/common/include/ddr_info.h b/plat/marvell/armada/a3k/common/include/ddr_info.h
new file mode 100644
index 0000000..254f78c
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/include/ddr_info.h
@@ -0,0 +1,14 @@
+/*
+ * 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 */
diff --git a/plat/marvell/armada/a3k/common/include/dram_win.h b/plat/marvell/armada/a3k/common/include/dram_win.h
new file mode 100644
index 0000000..26a0137
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/include/dram_win.h
@@ -0,0 +1,18 @@
+/*
+ * 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 <common/bl_common.h>
+
+#include <io_addr_dec.h>
+
+void dram_win_map_build(struct dram_win_map *win_map);
+void cpu_wins_init(void);
+
+#endif /* DRAM_WIN_H */
diff --git a/plat/marvell/armada/a3k/common/include/io_addr_dec.h b/plat/marvell/armada/a3k/common/include/io_addr_dec.h
new file mode 100644
index 0000000..42ef30b
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/include/io_addr_dec.h
@@ -0,0 +1,66 @@
+/*
+ * 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 <stdint.h>
+
+/* 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 */
diff --git a/plat/marvell/armada/a3k/common/include/plat_macros.S b/plat/marvell/armada/a3k/common/include/plat_macros.S
new file mode 100644
index 0000000..f689b4f
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/include/plat_macros.S
@@ -0,0 +1,26 @@
+/*
+ * 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 <marvell_macros.S>
+
+/* ---------------------------------------------
+ * 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 */
diff --git a/plat/marvell/armada/a3k/common/include/platform_def.h b/plat/marvell/armada/a3k/common/include/platform_def.h
new file mode 100644
index 0000000..f19d96b
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/include/platform_def.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2016-2021 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#ifndef __ASSEMBLER__
+#include <stdio.h>
+#endif /* __ASSEMBLER__ */
+
+#include <board_marvell_def.h>
+#include <mvebu_def.h>
+
+/*
+ * 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
+ */
+
+/*
+ * Since BL33 is loaded by BL2 (and validated by BL31) to DRAM offset 0,
+ * it is allowed to load/copy images to 'NULL' pointers
+ */
+#if defined(IMAGE_BL2) || defined(IMAGE_BL31)
+#define PLAT_ALLOW_ZERO_ADDR_COPY
+#endif
+
+#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 U(2)
+/* DRAM[2MB..66MB] is used as Trusted ROM */
+#define PLAT_MARVELL_TRUSTED_ROM_BASE PLAT_MARVELL_ATF_LOAD_ADDR
+/* 4 MB for FIP image */
+#define PLAT_MARVELL_TRUSTED_ROM_SIZE 0x00400000
+/* Reserve 12M for SCP (Secure PayLoad) Trusted RAM
+ * OP-TEE SHMEM follows this region
+ */
+#define PLAT_MARVELL_TRUSTED_RAM_BASE 0x04400000
+#define PLAT_MARVELL_TRUSTED_RAM_SIZE 0x00C00000 /* 12 MB DRAM */
+
+/*
+ * 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_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_UART_BASE (MVEBU_REGS_BASE + 0x12000)
+
+/* 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_SHARED_RAM_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)
+
+#define CPU_DEC_CCI_BASE_REG (MVEBU_CPU_DEC_WIN_REG_BASE + 0xe0)
+
+/* Securities */
+#define IRQ_SEC_OS_TICK_INT MARVELL_IRQ_SEC_PHY_TIMER
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/marvell/armada/a3k/common/io_addr_dec.c b/plat/marvell/armada/a3k/common/io_addr_dec.c
new file mode 100644
index 0000000..fea7f81
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/io_addr_dec.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2016 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <io_addr_dec.h>
+#include <plat_marvell.h>
+
+#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) remap(0x%x)\n",
+ 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)),
+ (win_id < dec_win->max_remap) ?
+ mmio_read_32(MVEBU_DEC_WIN_REMAP_REG(dec_win->dec_reg_base,
+ win_id, dec_win->win_offset)) : 0);
+}
+
+/* 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)"
+ " win_attr(%x) max_dram_win(%d) max_remap(%d)"
+ " win_offset(%d)\n", io_dec_win->dec_reg_base,
+ io_dec_win->win_attr, io_dec_win->max_dram_win,
+ io_dec_win->max_remap, io_dec_win->win_offset);
+ }
+
+ return 0;
+}
diff --git a/plat/marvell/armada/a3k/common/marvell_plat_config.c b/plat/marvell/armada/a3k/common/marvell_plat_config.c
new file mode 100644
index 0000000..3bf3d96
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/marvell_plat_config.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <common/bl_common.h>
+
+#include <io_addr_dec.h>
+#include <mvebu_def.h>
+
+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;
+}
+
diff --git a/plat/marvell/armada/a3k/common/plat_cci.c b/plat/marvell/armada/a3k/common/plat_cci.c
new file mode 100644
index 0000000..56f091f
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/plat_cci.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 Marek Behun <marek.behun@nic.cz>
+ *
+ * Based on plat/marvell/armada/common/marvell_cci.c
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <drivers/arm/cci.h>
+#include <lib/mmio.h>
+
+#include <plat_marvell.h>
+
+static const int cci_map[] = {
+ PLAT_MARVELL_CCI_CLUSTER0_SL_IFACE_IX,
+ PLAT_MARVELL_CCI_CLUSTER1_SL_IFACE_IX
+};
+
+/*
+ * This redefines the weak definition in
+ * plat/marvell/armada/common/marvell_cci.c
+ */
+void plat_marvell_interconnect_init(void)
+{
+ /*
+ * To better utilize the address space, we remap CCI base address from
+ * the default (0xD8000000) to MVEBU_CCI_BASE.
+ * This has to be done here, rather than in cpu_wins_init(), because
+ * cpu_wins_init() is called later.
+ */
+ mmio_write_32(CPU_DEC_CCI_BASE_REG, MVEBU_CCI_BASE >> 20);
+
+ cci_init(PLAT_MARVELL_CCI_BASE, cci_map, ARRAY_SIZE(cci_map));
+}
diff --git a/plat/marvell/armada/a3k/common/plat_pm.c b/plat/marvell/armada/a3k/common/plat_pm.c
new file mode 100644
index 0000000..e2d15ab
--- /dev/null
+++ b/plat/marvell/armada/a3k/common/plat_pm.c
@@ -0,0 +1,822 @@
+/*
+ * Copyright (C) 2018-2020 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <common/debug.h>
+#ifdef USE_CCI
+#include <drivers/arm/cci.h>
+#endif
+#include <lib/psci/psci.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <a3700_pm.h>
+#include <arch_helpers.h>
+#include <armada_common.h>
+#include <dram_win.h>
+#include <io_addr_dec.h>
+#include <mvebu.h>
+#include <mvebu_def.h>
+#include <marvell_plat_priv.h>
+#include <plat_marvell.h>
+
+/* 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;
+}
+
+#pragma weak mv_wake_up_src_config_get
+struct pm_wake_up_src_config *mv_wake_up_src_config_get(void)
+{
+ static struct pm_wake_up_src_config wake_up_src_cfg = {};
+ return &wake_up_src_cfg;
+}
+
+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();
+}
+
+#pragma weak cm3_system_reset
+void cm3_system_reset(void)
+{
+}
+
+/*****************************************************************************
+ * 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
+
+ /* Use Cortex-M3 secure coprocessor for system reset */
+ cm3_system_reset();
+
+ /* 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
+};
diff --git a/plat/marvell/armada/a8k/a70x0/board/dram_port.c b/plat/marvell/armada/a8k/a70x0/board/dram_port.c
new file mode 100644
index 0000000..355770b
--- /dev/null
+++ b/plat/marvell/armada/a8k/a70x0/board/dram_port.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#include <mv_ddr_if.h>
+#include <plat_marvell.h>
+
+/*
+ * 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 */
+ NOT_COMBINED, /* ddr twin-die combined*/
+ { {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;
+}
diff --git a/plat/marvell/armada/a8k/a70x0/board/marvell_plat_config.c b/plat/marvell/armada/a8k/a70x0/board/marvell_plat_config.c
new file mode 100644
index 0000000..a409261
--- /dev/null
+++ b/plat/marvell/armada/a8k/a70x0/board/marvell_plat_config.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <armada_common.h>
+
+/*
+ * If bootrom is currently at BLE there's no need to include the memory
+ * maps structure at this point
+ */
+#include <mvebu_def.h>
+#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
+#if LLC_SRAM
+ /* This entry is prepared for OP-TEE OS that enables the LLC SRAM
+ * and changes the window target to SRAM_TID.
+ */
+ {PLAT_MARVELL_LLC_SRAM_BASE, PLAT_MARVELL_LLC_SRAM_SIZE, DRAM_0_TID},
+#endif
+ {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
diff --git a/plat/marvell/armada/a8k/a70x0/mvebu_def.h b/plat/marvell/armada/a8k/a70x0/mvebu_def.h
new file mode 100644
index 0000000..72bca12
--- /dev/null
+++ b/plat/marvell/armada/a8k/a70x0/mvebu_def.h
@@ -0,0 +1,15 @@
+/*
+ * 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 <a8k_plat_def.h>
+
+#define CP_COUNT 1 /* A70x0 has single CP0 */
+
+#endif /* MVEBU_DEF_H */
diff --git a/plat/marvell/armada/a8k/a70x0/platform.mk b/plat/marvell/armada/a8k/a70x0/platform.mk
new file mode 100644
index 0000000..39eb712
--- /dev/null
+++ b/plat/marvell/armada/a8k/a70x0/platform.mk
@@ -0,0 +1,20 @@
+#
+# 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
+
+BOARD_DIR := $(shell dirname $(lastword $(MAKEFILE_LIST)))
+include plat/marvell/armada/a8k/common/a8k_common.mk
+
+include plat/marvell/armada/common/marvell_common.mk
diff --git a/plat/marvell/armada/a8k/a70x0_amc/board/dram_port.c b/plat/marvell/armada/a8k/a70x0_amc/board/dram_port.c
new file mode 100644
index 0000000..9c8c97e
--- /dev/null
+++ b/plat/marvell/armada/a8k/a70x0_amc/board/dram_port.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#include <mv_ddr_if.h>
+#include <plat_marvell.h>
+
+/*
+ * 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 */
+ NOT_COMBINED, /* ddr twin-die combined*/
+ { {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;
+}
diff --git a/plat/marvell/armada/a8k/a70x0_amc/board/marvell_plat_config.c b/plat/marvell/armada/a8k/a70x0_amc/board/marvell_plat_config.c
new file mode 100644
index 0000000..3b68e91
--- /dev/null
+++ b/plat/marvell/armada/a8k/a70x0_amc/board/marvell_plat_config.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <armada_common.h>
+
+/*
+ * If bootrom is currently at BLE there's no need to include the memory
+ * maps structure at this point
+ */
+#include <mvebu_def.h>
+#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
+#if LLC_SRAM
+ /* This entry is prepared for OP-TEE OS that enables the LLC SRAM
+ * and changes the window target to SRAM_TID.
+ */
+ {PLAT_MARVELL_LLC_SRAM_BASE, PLAT_MARVELL_LLC_SRAM_SIZE, DRAM_0_TID},
+#endif
+ {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
diff --git a/plat/marvell/armada/a8k/a70x0_amc/mvebu_def.h b/plat/marvell/armada/a8k/a70x0_amc/mvebu_def.h
new file mode 100644
index 0000000..cedf323
--- /dev/null
+++ b/plat/marvell/armada/a8k/a70x0_amc/mvebu_def.h
@@ -0,0 +1,31 @@
+/*
+ * 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 <a8k_plat_def.h>
+
+#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 */
diff --git a/plat/marvell/armada/a8k/a70x0_amc/platform.mk b/plat/marvell/armada/a8k/a70x0_amc/platform.mk
new file mode 100644
index 0000000..39eb712
--- /dev/null
+++ b/plat/marvell/armada/a8k/a70x0_amc/platform.mk
@@ -0,0 +1,20 @@
+#
+# 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
+
+BOARD_DIR := $(shell dirname $(lastword $(MAKEFILE_LIST)))
+include plat/marvell/armada/a8k/common/a8k_common.mk
+
+include plat/marvell/armada/common/marvell_common.mk
diff --git a/plat/marvell/armada/a8k/a70x0_mochabin/board/dram_port.c b/plat/marvell/armada/a8k/a70x0_mochabin/board/dram_port.c
new file mode 100644
index 0000000..68d335b
--- /dev/null
+++ b/plat/marvell/armada/a8k/a70x0_mochabin/board/dram_port.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2021 Sartura Ltd.
+ * Copyright (C) 2021 Globalscale technologies, Inc.
+ * Copyright (C) 2021 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#include <mv_ddr_if.h>
+#include <plat_marvell.h>
+
+/*
+ * 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
+ */
+#if DDR_TOPOLOGY == 0
+static struct mv_ddr_topology_map board_topology_map_2g = {
+/* 1CS 4Gb x4 devices of Samsung K4A4G085WF */
+ DEBUG_LEVEL_ERROR,
+ 0x1, /* active interfaces */
+ /* cs_mask, mirror, dqs_swap, ck_swap X subphys */
+ { { { {0x1, 0x2, 0, 0},
+ {0x1, 0x2, 0, 0},
+ {0x1, 0x2, 0, 0},
+ {0x1, 0x2, 0, 0},
+ {0x1, 0x2, 0, 0},
+ {0x1, 0x2, 0, 0},
+ {0x1, 0x2, 0, 0},
+ {0x1, 0x2, 0, 0},
+ {0x1, 0x2, 0, 0} },
+ SPEED_BIN_DDR_2400R, /* 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 */
+ BUS_MASK_32BIT, /* subphys mask */
+ MV_DDR_CFG_DEFAULT, /* ddr configuration data source */
+ NOT_COMBINED, /* ddr twin-die combined*/
+ { {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 */
+ },
+ }
+};
+#endif
+
+#if DDR_TOPOLOGY == 1
+static struct mv_ddr_topology_map board_topology_map_4g = {
+/* 1CS 8Gb x4 devices of Samsung K4A8G085WC-BCTD */
+ DEBUG_LEVEL_ERROR,
+ 0x1, /* active interfaces */
+ /* cs_mask, mirror, dqs_swap, ck_swap X subphys */
+ { { { {0x1, 0x2, 0, 0},
+ {0x1, 0x2, 0, 0},
+ {0x1, 0x2, 0, 0},
+ {0x1, 0x2, 0, 0},
+ {0x1, 0x2, 0, 0},
+ {0x1, 0x2, 0, 0},
+ {0x1, 0x2, 0, 0},
+ {0x1, 0x2, 0, 0},
+ {0x1, 0x2, 0, 0} },
+ SPEED_BIN_DDR_2400R, /* 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 */
+ BUS_MASK_32BIT, /* subphys mask */
+ MV_DDR_CFG_DEFAULT, /* ddr configuration data source */
+ NOT_COMBINED, /* ddr twin-die combined*/
+ { {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 */
+ },
+ }
+};
+#endif
+
+#if DDR_TOPOLOGY == 2
+static struct mv_ddr_topology_map board_topology_map_8g = {
+/* 2CS 8Gb x8 devices of Micron MT40A1G8WE-083E IT */
+ 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_2400R, /* 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 */
+ BUS_MASK_32BIT, /* subphys mask */
+ MV_DDR_CFG_DEFAULT, /* ddr configuration data source */
+ NOT_COMBINED, /* ddr twin-die combined*/
+ { {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 */
+ },
+ }
+};
+#endif
+
+struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
+{
+/* a70x0_mochabin board supports 3 DDR4 models (2G/1CS, 4G/1CS, 8G/2CS) */
+#if DDR_TOPOLOGY == 0
+ return &board_topology_map_2g;
+#elif DDR_TOPOLOGY == 1
+ return &board_topology_map_4g;
+#elif DDR_TOPOLOGY == 2
+ return &board_topology_map_8g;
+#else
+ #error "Unknown DDR topology"
+#endif
+}
diff --git a/plat/marvell/armada/a8k/a70x0_mochabin/board/marvell_plat_config.c b/plat/marvell/armada/a8k/a70x0_mochabin/board/marvell_plat_config.c
new file mode 100644
index 0000000..1ed6323
--- /dev/null
+++ b/plat/marvell/armada/a8k/a70x0_mochabin/board/marvell_plat_config.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2021 Sartura Ltd.
+ * Copyright (C) 2021 Globalscale technologies, Inc.
+ * Copyright (C) 2021 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <armada_common.h>
+
+/*
+ * If bootrom is currently at BLE there's no need to include the memory
+ * maps structure at this point
+ */
+#include <mvebu_def.h>
+#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
+#if LLC_SRAM
+ /* This entry is prepared for OP-TEE OS that enables the LLC SRAM
+ * and changes the window target to SRAM_TID.
+ */
+ {PLAT_MARVELL_LLC_SRAM_BASE, PLAT_MARVELL_LLC_SRAM_SIZE, DRAM_0_TID},
+#endif
+ {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
+void *plat_marvell_get_skip_image_data(void)
+{
+ /* No recovery button on a70x0_mochabin board */
+ return NULL;
+}
+#endif
+#endif
diff --git a/plat/marvell/armada/a8k/a70x0_mochabin/board/phy-porting-layer.h b/plat/marvell/armada/a8k/a70x0_mochabin/board/phy-porting-layer.h
new file mode 100644
index 0000000..ab76c31
--- /dev/null
+++ b/plat/marvell/armada/a8k/a70x0_mochabin/board/phy-porting-layer.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2021 Sartura Ltd.
+ * Copyright (C) 2021 Globalscale technologies, Inc.
+ * Copyright (C) 2021 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 */
+ { 0 }, /* Comphy2 */
+ { 0 }, /* Comphy3 */
+ { .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf, .align90 = 0x60,
+ .g1_dfe_res = 0x1, .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 }, /* Comphy4 */
+ { 0 }, /* Comphy5 */
+ },
+ },
+};
+
+static const struct sata_params
+ sata_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
+ /* AP0 */
+ {
+ /* CP 0 */
+ {
+ { 0 }, /* Comphy0 */
+ { 0 }, /* Comphy1 */
+ { .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,
+ .polarity_invert = COMPHY_POLARITY_NO_INVERT,
+ .valid = 0x1
+ }, /* 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,
+ .polarity_invert = COMPHY_POLARITY_NO_INVERT,
+ .valid = 0x1
+ }, /* Comphy3 */
+ { 0 }, /* Comphy4 */
+ { 0 }, /* Comphy5 */
+ },
+ },
+};
+
+static const struct usb_params
+ usb_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
+ [0 ... AP_NUM-1][0 ... CP_NUM-1][0 ... MAX_LANE_NR-1] = {
+ .polarity_invert = COMPHY_POLARITY_NO_INVERT
+ },
+};
+
+#endif /* __PHY_PORTING_LAYER_H */
diff --git a/plat/marvell/armada/a8k/a70x0_mochabin/mvebu_def.h b/plat/marvell/armada/a8k/a70x0_mochabin/mvebu_def.h
new file mode 100644
index 0000000..768f735
--- /dev/null
+++ b/plat/marvell/armada/a8k/a70x0_mochabin/mvebu_def.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2021 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MVEBU_DEF_H
+#define MVEBU_DEF_H
+
+#include <a8k_plat_def.h>
+
+#define CP_COUNT 1 /* A70x0 has single CP0 */
+
+#endif /* MVEBU_DEF_H */
diff --git a/plat/marvell/armada/a8k/a70x0_mochabin/platform.mk b/plat/marvell/armada/a8k/a70x0_mochabin/platform.mk
new file mode 100644
index 0000000..2495591
--- /dev/null
+++ b/plat/marvell/armada/a8k/a70x0_mochabin/platform.mk
@@ -0,0 +1,20 @@
+#
+# Copyright (C) 2021 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
+
+BOARD_DIR := $(shell dirname $(lastword $(MAKEFILE_LIST)))
+include plat/marvell/armada/a8k/common/a8k_common.mk
+
+include plat/marvell/armada/common/marvell_common.mk
diff --git a/plat/marvell/armada/a8k/a80x0/board/dram_port.c b/plat/marvell/armada/a8k/a80x0/board/dram_port.c
new file mode 100644
index 0000000..47bc0a8
--- /dev/null
+++ b/plat/marvell/armada/a8k/a80x0/board/dram_port.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/mentor/mi2cv.h>
+#include <lib/mmio.h>
+
+#include <mv_ddr_if.h>
+#include <mvebu_def.h>
+#include <plat_marvell.h>
+
+#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 */
+#if DDR32
+ MV_DDR_32BIT_ECC_PUP8_BUS_MASK, /* subphys mask */
+#else
+ MV_DDR_64BIT_ECC_PUP8_BUS_MASK, /* subphys mask */
+#endif
+ MV_DDR_CFG_SPD, /* ddr configuration data source */
+ NOT_COMBINED, /* ddr twin-die combined*/
+ { {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, 0);
+
+ /* read data from spd */
+ i2c_read(I2C_SPD_ADDR, 0x0, 1, tm->spd_data.all_bytes,
+ sizeof(tm->spd_data.all_bytes));
+ }
+}
diff --git a/plat/marvell/armada/a8k/a80x0/board/marvell_plat_config.c b/plat/marvell/armada/a8k/a80x0/board/marvell_plat_config.c
new file mode 100644
index 0000000..4ccda14
--- /dev/null
+++ b/plat/marvell/armada/a8k/a80x0/board/marvell_plat_config.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <armada_common.h>
+
+/*
+ * If bootrom is currently at BLE there's no need to include the memory
+ * maps structure at this point
+ */
+#include <mvebu_def.h>
+#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
+#if LLC_SRAM
+ /* This entry is prepared for OP-TEE OS that enables the LLC SRAM
+ * and changes the window target to SRAM_TID.
+ */
+ {PLAT_MARVELL_LLC_SRAM_BASE, PLAT_MARVELL_LLC_SRAM_SIZE, DRAM_0_TID},
+#endif
+ {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
diff --git a/plat/marvell/armada/a8k/a80x0/board/phy-porting-layer.h b/plat/marvell/armada/a8k/a80x0/board/phy-porting-layer.h
new file mode 100644
index 0000000..afa3be1
--- /dev/null
+++ b/plat/marvell/armada/a8k/a80x0/board/phy-porting-layer.h
@@ -0,0 +1,192 @@
+/*
+ * 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,
+ .polarity_invert = COMPHY_POLARITY_NO_INVERT,
+ .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,
+ .polarity_invert = COMPHY_POLARITY_NO_INVERT,
+ .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,
+ .polarity_invert = COMPHY_POLARITY_NO_INVERT,
+ .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,
+ .polarity_invert = COMPHY_POLARITY_NO_INVERT,
+ .valid = 0x1
+ }, /* Comphy3 */
+ { 0 }, /* Comphy4 */
+ { 0 }, /* Comphy5 */
+
+ },
+ },
+};
+
+static const struct usb_params
+ usb_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
+ [0 ... AP_NUM-1][0 ... CP_NUM-1][0 ... MAX_LANE_NR-1] = {
+ .polarity_invert = COMPHY_POLARITY_NO_INVERT
+ },
+};
+#endif /* PHY_PORTING_LAYER_H */
diff --git a/plat/marvell/armada/a8k/a80x0/mvebu_def.h b/plat/marvell/armada/a8k/a80x0/mvebu_def.h
new file mode 100644
index 0000000..3fa119a
--- /dev/null
+++ b/plat/marvell/armada/a8k/a80x0/mvebu_def.h
@@ -0,0 +1,17 @@
+/*
+ * 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 <a8k_plat_def.h>
+
+#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 */
diff --git a/plat/marvell/armada/a8k/a80x0/platform.mk b/plat/marvell/armada/a8k/a80x0/platform.mk
new file mode 100644
index 0000000..115dd4a
--- /dev/null
+++ b/plat/marvell/armada/a8k/a80x0/platform.mk
@@ -0,0 +1,20 @@
+#
+# 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
+
+BOARD_DIR := $(shell dirname $(lastword $(MAKEFILE_LIST)))
+include plat/marvell/armada/a8k/common/a8k_common.mk
+
+include plat/marvell/armada/common/marvell_common.mk
diff --git a/plat/marvell/armada/a8k/a80x0_mcbin/board/dram_port.c b/plat/marvell/armada/a8k/a80x0_mcbin/board/dram_port.c
new file mode 100644
index 0000000..85c931c
--- /dev/null
+++ b/plat/marvell/armada/a8k/a80x0_mcbin/board/dram_port.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/mentor/mi2cv.h>
+#include <lib/mmio.h>
+
+#include <mv_ddr_if.h>
+#include <mvebu_def.h>
+#include <plat_marvell.h>
+
+#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 */
+ NOT_COMBINED, /* ddr twin-die combined*/
+ { {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, 0);
+ /* read data from spd */
+ i2c_read(I2C_SPD_ADDR, 0x0, 1, tm->spd_data.all_bytes,
+ sizeof(tm->spd_data.all_bytes));
+ }
+}
diff --git a/plat/marvell/armada/a8k/a80x0_mcbin/board/marvell_plat_config.c b/plat/marvell/armada/a8k/a80x0_mcbin/board/marvell_plat_config.c
new file mode 100644
index 0000000..75a1b0c
--- /dev/null
+++ b/plat/marvell/armada/a8k/a80x0_mcbin/board/marvell_plat_config.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+
+/*
+ * If bootrom is currently at BLE there's no need to include the memory
+ * maps structure at this point
+ */
+#include <mvebu_def.h>
+#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-2 and SPI1_CS0 (RUNIT) on CP1*/
+ {0x00000000f9000000, 0x4000000, 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
+#if LLC_SRAM
+ /* This entry is prepared for OP-TEE OS that enables the LLC SRAM
+ * and changes the window target to SRAM_TID.
+ */
+ {PLAT_MARVELL_LLC_SRAM_BASE, PLAT_MARVELL_LLC_SRAM_SIZE, DRAM_0_TID},
+#endif
+ {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;
+}
diff --git a/plat/marvell/armada/a8k/a80x0_mcbin/mvebu_def.h b/plat/marvell/armada/a8k/a80x0_mcbin/mvebu_def.h
new file mode 100644
index 0000000..3fa119a
--- /dev/null
+++ b/plat/marvell/armada/a8k/a80x0_mcbin/mvebu_def.h
@@ -0,0 +1,17 @@
+/*
+ * 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 <a8k_plat_def.h>
+
+#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 */
diff --git a/plat/marvell/armada/a8k/a80x0_mcbin/platform.mk b/plat/marvell/armada/a8k/a80x0_mcbin/platform.mk
new file mode 100644
index 0000000..115dd4a
--- /dev/null
+++ b/plat/marvell/armada/a8k/a80x0_mcbin/platform.mk
@@ -0,0 +1,20 @@
+#
+# 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
+
+BOARD_DIR := $(shell dirname $(lastword $(MAKEFILE_LIST)))
+include plat/marvell/armada/a8k/common/a8k_common.mk
+
+include plat/marvell/armada/common/marvell_common.mk
diff --git a/plat/marvell/armada/a8k/a80x0_puzzle/board/dram_port.c b/plat/marvell/armada/a8k/a80x0_puzzle/board/dram_port.c
new file mode 100644
index 0000000..1d8e9d2
--- /dev/null
+++ b/plat/marvell/armada/a8k/a80x0_puzzle/board/dram_port.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/mentor/mi2cv.h>
+#include <lib/mmio.h>
+
+#include <mv_ddr_if.h>
+#include <mvebu_def.h>
+#include <plat_marvell.h>
+
+#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 = {
+ /* 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 */
+ NOT_COMBINED, /* ddr twin-die combined*/
+ { {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;
+
+ /* configure ap mmps 4, 5 to I2C */
+ reg = MVEBU_AP_MPP_CTRL0_7_REG;
+
+ val = mmio_read_32(reg);
+ val &= ~((MVEBU_MPP_CTRL_MASK << MVEBU_AP_MPP_CTRL4_OFFS) |
+ (MVEBU_MPP_CTRL_MASK << MVEBU_AP_MPP_CTRL5_OFFS));
+ val |= ((MVEBU_AP_MPP_CTRL4_I2C0_SDA_ENA << MVEBU_AP_MPP_CTRL4_OFFS) |
+ (MVEBU_AP_MPP_CTRL5_I2C0_SCK_ENA << MVEBU_AP_MPP_CTRL5_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 MVEBU_AP_I2C_BASE I2C bus */
+ i2c_init((void *)MVEBU_AP_I2C_BASE);
+ /* select SPD memory page 0 to access DRAM configuration */
+ i2c_write(I2C_SPD_P0_ADDR, 0x0, 1, tm->spd_data.all_bytes, 0);
+ /* read data from spd */
+ i2c_read(I2C_SPD_ADDR, 0x0, 1, tm->spd_data.all_bytes,
+ sizeof(tm->spd_data.all_bytes));
+ }
+}
diff --git a/plat/marvell/armada/a8k/a80x0_puzzle/board/marvell_plat_config.c b/plat/marvell/armada/a8k/a80x0_puzzle/board/marvell_plat_config.c
new file mode 100644
index 0000000..0edc977
--- /dev/null
+++ b/plat/marvell/armada/a8k/a80x0_puzzle/board/marvell_plat_config.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+
+/*
+ * If bootrom is currently at BLE there's no need to include the memory
+ * maps structure at this point
+ */
+#include <mvebu_def.h>
+#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
+#if LLC_SRAM
+ {PLAT_MARVELL_LLC_SRAM_BASE, PLAT_MARVELL_LLC_SRAM_SIZE, SRAM_TID},
+#endif
+ {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;
+}
diff --git a/plat/marvell/armada/a8k/a80x0_puzzle/board/system_power.c b/plat/marvell/armada/a8k/a80x0_puzzle/board/system_power.c
new file mode 100644
index 0000000..eb00874
--- /dev/null
+++ b/plat/marvell/armada/a8k/a80x0_puzzle/board/system_power.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2020 Sartura Ltd.
+ * Author: Luka Kovacic <luka.kovacic@sartura.hr>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <armada_common.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <drivers/console.h>
+#include <plat_marvell.h>
+
+/*****************************************************************************
+ * Platform specific power off functions
+ * Power off PSU / Send command to power management MCU / ...
+ *****************************************************************************
+ */
+
+unsigned char add_xor_checksum(unsigned char *buf, unsigned char xor_len)
+{
+ unsigned char xor_sum = 0;
+ unsigned int i;
+
+ for (i = 0; i < xor_len; i++)
+ xor_sum ^= buf[i];
+
+ return xor_sum;
+}
+
+int system_power_off(void)
+{
+ static console_t console;
+
+ /* WT61P803 MCU system_off_now command */
+ unsigned char system_off_now[4] = { '@', 'C', '0' };
+ int i, len;
+
+ len = sizeof(system_off_now);
+ system_off_now[len - 1] = add_xor_checksum(system_off_now, len);
+
+ console_16550_register(PLAT_MARVELL_UART_BASE + 0x100,
+ PLAT_MARVELL_UART_CLK_IN_HZ, 115200, &console);
+
+ /* Send system_off_now to console */
+ for (i = 0; i < len; i++) {
+ console.putc(system_off_now[i], &console);
+ udelay(1000);
+ }
+
+ console.flush(&console);
+ (void)console_unregister(&console);
+
+ mdelay(100);
+
+ return 0;
+}
diff --git a/plat/marvell/armada/a8k/a80x0_puzzle/mvebu_def.h b/plat/marvell/armada/a8k/a80x0_puzzle/mvebu_def.h
new file mode 100644
index 0000000..3fa119a
--- /dev/null
+++ b/plat/marvell/armada/a8k/a80x0_puzzle/mvebu_def.h
@@ -0,0 +1,17 @@
+/*
+ * 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 <a8k_plat_def.h>
+
+#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 */
diff --git a/plat/marvell/armada/a8k/a80x0_puzzle/platform.mk b/plat/marvell/armada/a8k/a80x0_puzzle/platform.mk
new file mode 100644
index 0000000..3378d53
--- /dev/null
+++ b/plat/marvell/armada/a8k/a80x0_puzzle/platform.mk
@@ -0,0 +1,20 @@
+#
+# 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
+
+BOARD_DIR := $(shell dirname $(lastword $(MAKEFILE_LIST)))
+include plat/marvell/armada/a8k/common/a8k_common.mk
+
+include plat/marvell/armada/common/marvell_common.mk
diff --git a/plat/marvell/armada/a8k/common/a8k_common.mk b/plat/marvell/armada/a8k/common/a8k_common.mk
new file mode 100644
index 0000000..4d8a87f
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/a8k_common.mk
@@ -0,0 +1,192 @@
+#
+# Copyright (C) 2016 - 2020 Marvell International Ltd.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# https://spdx.org/licenses
+
+PLAT_FAMILY := a8k
+PLAT_INCLUDE_BASE := include/plat/marvell/armada/$(PLAT_FAMILY)
+PLAT_COMMON_BASE := plat/marvell/armada/a8k/common
+MARVELL_DRV_BASE := drivers/marvell
+MARVELL_COMMON_BASE := plat/marvell/armada/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
+$(eval $(call add_define,MSS_SUPPORT))
+
+# Disable EL3 cache for power management
+BL31_CACHE_DISABLE := 0
+$(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
+
+include plat/marvell/marvell.mk
+include tools/marvell/doimage/doimage.mk
+
+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
+
+ROM_BIN_EXT ?= $(BUILD_PLAT)/ble.bin
+DOIMAGE_FLAGS += -b $(ROM_BIN_EXT) $(NAND_DOIMAGE_FLAGS) $(DOIMAGE_SEC_FLAGS)
+
+# Check whether to build system_power.c for the platform
+ifneq ("$(wildcard $(BOARD_DIR)/board/system_power.c)","")
+SYSTEM_POWER_SUPPORT = 1
+else
+SYSTEM_POWER_SUPPORT = 0
+endif
+
+# This define specifies DDR type for BLE
+$(eval $(call add_define,CONFIG_DDR4))
+
+# This define specifies DDR topology for BLE
+DDR_TOPOLOGY ?= 0
+$(eval $(call add_define,DDR_TOPOLOGY))
+
+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$(BOARD_DIR) \
+ -I$(BOARD_DIR)/board \
+ -I$(CURDIR)/drivers/marvell \
+ -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
+
+ifndef BLE_PORTING_SOURCES
+BLE_PORTING_SOURCES := $(BOARD_DIR)/board/dram_port.c \
+ $(BOARD_DIR)/board/marvell_plat_config.c
+endif
+
+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 \
+ $(MARVELL_DRV_BASE)/secure_dfx_access/armada_thermal.c \
+ $(MARVELL_DRV_BASE)/secure_dfx_access/misc_dfx.c \
+ $(MARVELL_DRV_BASE)/ddr_phy_access.c \
+ drivers/rambus/trng_ip_76.c
+
+ifeq (${MSS_SUPPORT}, 1)
+MARVELL_DRV += $(MARVELL_DRV_BASE)/mg_conf_cm3/mg_conf_cm3.c
+endif
+
+ifndef BL31_PORTING_SOURCES
+BL31_PORTING_SOURCES := $(BOARD_DIR)/board/marvell_plat_config.c
+endif
+
+ifeq ($(SYSTEM_POWER_SUPPORT),1)
+BL31_PORTING_SOURCES += $(BOARD_DIR)/board/system_power.c
+endif
+
+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
+
+
+ifeq (${MSS_SUPPORT}, 1)
+# 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
+endif
+
+# BLE (ROM context execution code, AKA binary extension)
+BLE_PATH ?= $(PLAT_COMMON_BASE)/ble
+
+include ${BLE_PATH}/ble.mk
+$(eval $(call MAKE_BL,ble))
+
+clean realclean distclean: mrvl_clean
+
+.PHONY: mrvl_clean
+mrvl_clean:
+ @echo " Doimage CLEAN"
+ ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${DOIMAGEPATH} clean
+
+${DOIMAGETOOL}: FORCE
+ @$(DOIMAGE_LIBS_CHECK)
+ ${Q}${MAKE} --no-print-directory -C ${DOIMAGEPATH}
+
+${BUILD_PLAT}/${FLASH_IMAGE}: ${ROM_BIN_EXT} ${BUILD_PLAT}/${BOOT_IMAGE} ${DOIMAGETOOL}
+ @${ECHO_BLANK_LINE}
+ @echo "Building flash image"
+ ${Q}${DOIMAGETOOL} ${DOIMAGE_FLAGS} ${BUILD_PLAT}/${BOOT_IMAGE} ${BUILD_PLAT}/${FLASH_IMAGE}
+ @${ECHO_BLANK_LINE}
+ @echo "Built $@ successfully"
+ @${ECHO_BLANK_LINE}
diff --git a/plat/marvell/armada/a8k/common/aarch64/a8k_common.c b/plat/marvell/armada/a8k/common/aarch64/a8k_common.c
new file mode 100644
index 0000000..4332a76
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/aarch64/a8k_common.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <plat_marvell.h>
+
+
+/* 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_SECURE_RAM,
+ MAP_DEVICE0,
+ {0}
+};
+#endif
+#if IMAGE_BL2
+const mmap_region_t plat_marvell_mmap[] = {
+ MARVELL_MAP_SECURE_RAM,
+ MAP_DEVICE0,
+ MARVELL_MAP_DRAM,
+#ifdef SPD_opteed
+ MARVELL_MAP_OPTEE_CORE_MEM,
+ MARVELL_OPTEE_PAGEABLE_LOAD_MEM,
+#endif
+ {0}
+};
+#endif
+
+#if IMAGE_BL2U
+const mmap_region_t plat_marvell_mmap[] = {
+ MARVELL_MAP_SECURE_RAM,
+ 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_SECURE_RAM,
+ MAP_DEVICE0,
+ MARVELL_MAP_DRAM,
+ {0}
+};
+#endif
+#if IMAGE_BL32
+const mmap_region_t plat_marvell_mmap[] = {
+ MARVELL_MAP_SECURE_RAM,
+ MAP_DEVICE0,
+ {0}
+};
+#endif
+
+MARVELL_CASSERT_MMAP;
diff --git a/plat/marvell/armada/a8k/common/aarch64/plat_arch_config.c b/plat/marvell/armada/a8k/common/aarch64/plat_arch_config.c
new file mode 100644
index 0000000..d576514
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/aarch64/plat_arch_config.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/marvell/cache_llc.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#define CCU_HTC_ASET (MVEBU_CCU_BASE(MVEBU_AP0) + 0x264)
+#define MVEBU_IO_AFFINITY (0xF00)
+#define MVEBU_SF_REG (MVEBU_REGS_BASE + 0x40)
+#define MVEBU_SF_EN BIT(8)
+#define MVEBU_DFX_REG(cluster_id) (MVEBU_REGS_BASE + 0x6F82A0 + \
+ (cluster_id) * 0x4)
+#define MVEBU_DFX_CLK_EN_POS 0x3
+#define MVEBU_DFX_CL0_CLK_OFFS 16
+#define MVEBU_DFX_CL0_CLK_MASK (0xF << MVEBU_DFX_CL0_CLK_OFFS)
+#define MVEBU_DFX_CL1_CLK_OFFS 8
+#define MVEBU_DFX_CL1_CLK_MASK (0xF << MVEBU_DFX_CL1_CLK_OFFS)
+
+#ifdef MVEBU_SOC_AP807
+static void plat_enable_snoop_filter(void)
+{
+ int cpu_id = plat_my_core_pos();
+
+ /* Snoop filter needs to be enabled once per cluster */
+ if (cpu_id % 2)
+ return;
+
+ mmio_setbits_32(MVEBU_SF_REG, MVEBU_SF_EN);
+}
+#endif
+
+#ifndef MVEBU_SOC_AP807
+static void plat_config_dfx_clock(void)
+{
+ int cluster_id = plat_my_core_pos();
+ uint32_t val;
+
+ /* DFX clock needs to be configured once per cluster */
+ if ((cluster_id % PLAT_MAX_CPUS_PER_CLUSTER) != 0) {
+ return;
+ }
+
+ val = mmio_read_32(MVEBU_DFX_REG(cluster_id / PLAT_MAX_CPUS_PER_CLUSTER));
+ if (cluster_id == 0) {
+ val &= ~MVEBU_DFX_CL0_CLK_MASK;
+ val |= (MVEBU_DFX_CLK_EN_POS << MVEBU_DFX_CL0_CLK_OFFS);
+ } else {
+ val &= ~MVEBU_DFX_CL1_CLK_MASK;
+ val |= (MVEBU_DFX_CLK_EN_POS << MVEBU_DFX_CL1_CLK_OFFS);
+ }
+ mmio_write_32(MVEBU_DFX_REG(cluster_id / PLAT_MAX_CPUS_PER_CLUSTER), val);
+}
+#endif
+
+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();
+
+#ifdef MVEBU_SOC_AP807
+ plat_enable_snoop_filter();
+#else
+ plat_config_dfx_clock();
+#endif
+}
diff --git a/plat/marvell/armada/a8k/common/aarch64/plat_helpers.S b/plat/marvell/armada/a8k/common/aarch64/plat_helpers.S
new file mode 100644
index 0000000..fadc4c2
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/aarch64/plat_helpers.S
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <asm_macros.S>
+#include <platform_def.h>
+#include <marvell_pm.h>
+
+ .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
diff --git a/plat/marvell/armada/a8k/common/ble/ble.ld.S b/plat/marvell/armada/a8k/common/ble/ble.ld.S
new file mode 100644
index 0000000..d7a0592
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/ble/ble.ld.S
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <platform_def.h>
+
+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);
+}
diff --git a/plat/marvell/armada/a8k/common/ble/ble.mk b/plat/marvell/armada/a8k/common/ble/ble.mk
new file mode 100644
index 0000000..160e98f
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/ble/ble.mk
@@ -0,0 +1,35 @@
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# https://spdx.org/licenses
+
+MV_DDR_LIB = $(BUILD_PLAT)/ble/mv_ddr_lib.a
+LIBC_LIB = $(BUILD_PLAT)/lib/libc.a
+BLE_LIBS = $(MV_DDR_LIB) $(LIBC_LIB)
+PLAT_MARVELL = plat/marvell/armada
+
+BLE_SOURCES += $(BLE_PATH)/ble_main.c \
+ $(BLE_PATH)/ble_mem.S \
+ drivers/delay_timer/delay_timer.c \
+ drivers/marvell/iob.c \
+ $(PLAT_MARVELL)/common/aarch64/marvell_helpers.S \
+ $(PLAT_MARVELL)/common/plat_delay_timer.c \
+ $(PLAT_MARVELL)/common/marvell_console.c
+
+MV_DDR_INCLUDES := -I$(CURDIR)/include \
+ -I$(CURDIR)/include/arch/aarch64 \
+ -I$(CURDIR)/include/lib/libc \
+ -I$(CURDIR)/include/lib/libc/aarch64
+
+BLE_LINKERFILE := $(BLE_PATH)/ble.ld.S
+
+BLE_OBJS := $(addprefix $(BUILD_PLAT)/ble/,$(call SOURCES_TO_OBJS,$(BLE_SOURCES)))
+$(BLE_OBJS): PLAT_INCLUDES += -I$(MV_DDR_PATH)
+$(BLE_OBJS): $(MV_DDR_LIB)
+
+$(MV_DDR_LIB): FORCE
+# Do not remove! Following checks are required to ensure correct TF-A builds, removing these checks leads to broken TF-A builds
+ $(if $(value MV_DDR_PATH),,$(error "Platform '$(PLAT)' for BLE requires MV_DDR_PATH. Please set MV_DDR_PATH to point to the right directory"))
+ $(if $(wildcard $(value MV_DDR_PATH)/*),,$(error "'MV_DDR_PATH=$(value MV_DDR_PATH)' was specified, but '$(value MV_DDR_PATH)' directory does not exist"))
+ $(if $(shell git -C $(value MV_DDR_PATH) rev-parse --show-cdup 2>&1),$(error "'MV_DDR_PATH=$(value MV_DDR_PATH)' was specified, but '$(value MV_DDR_PATH)' does not contain valid mv-ddr-marvell git repository"))
+ @+make -C $(MV_DDR_PATH) --no-print-directory PLAT_INCLUDES="$(MV_DDR_INCLUDES)" PLATFORM=$(PLAT) ARCH=AARCH64 OBJ_DIR=$(BUILD_PLAT)/ble
diff --git a/plat/marvell/armada/a8k/common/ble/ble_main.c b/plat/marvell/armada/a8k/common/ble/ble_main.c
new file mode 100644
index 0000000..5b3acec
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/ble/ble_main.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+
+#include <marvell_plat_priv.h>
+#include <marvell_pm.h>
+#include <plat_marvell.h>
+
+#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;
+}
diff --git a/plat/marvell/armada/a8k/common/ble/ble_mem.S b/plat/marvell/armada/a8k/common/ble/ble_mem.S
new file mode 100644
index 0000000..a48d546
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/ble/ble_mem.S
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <asm_macros.S>
+#include <marvell_def.h>
+#include <platform_def.h>
+
+#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
diff --git a/plat/marvell/armada/a8k/common/include/a8k_plat_def.h b/plat/marvell/armada/a8k/common/include/a8k_plat_def.h
new file mode 100644
index 0000000..3a0fd4b
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/include/a8k_plat_def.h
@@ -0,0 +1,195 @@
+/*
+ * 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 <marvell_def.h>
+
+#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_GEN_MGMT_BASE (MVEBU_RFU_BASE + 0x8000)
+#define MVEBU_AP_EXT_TSEN_BASE (MVEBU_AP_GEN_MGMT_BASE + 0x84)
+
+#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 */
diff --git a/plat/marvell/armada/a8k/common/include/ddr_info.h b/plat/marvell/armada/a8k/common/include/ddr_info.h
new file mode 100644
index 0000000..e19036a
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/include/ddr_info.h
@@ -0,0 +1,9 @@
+/*
+ * 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
diff --git a/plat/marvell/armada/a8k/common/include/mentor_i2c_plat.h b/plat/marvell/armada/a8k/common/include/mentor_i2c_plat.h
new file mode 100644
index 0000000..e03c448
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/include/mentor_i2c_plat.h
@@ -0,0 +1,33 @@
+/*
+ * 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 */
diff --git a/plat/marvell/armada/a8k/common/include/plat_macros.S b/plat/marvell/armada/a8k/common/include/plat_macros.S
new file mode 100644
index 0000000..8faccf0
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/include/plat_macros.S
@@ -0,0 +1,20 @@
+/*
+ * 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 <marvell_macros.S>
+
+/*
+ * Required platform porting macros
+ * (Provided by included headers)
+ */
+.macro plat_crash_print_regs
+.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/marvell/armada/a8k/common/include/platform_def.h b/plat/marvell/armada/a8k/common/include/platform_def.h
new file mode 100644
index 0000000..45860ba
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/include/platform_def.h
@@ -0,0 +1,196 @@
+/*
+ * 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 <stdio.h>
+#endif /* __ASSEMBLER__ */
+
+#include <common/interrupt_props.h>
+#include <drivers/arm/gic_common.h>
+
+#include <board_marvell_def.h>
+#include <mvebu_def.h>
+
+/*
+ * 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 U(2)
+#define PLAT_MARVELL_CLUSTER_CORE_COUNT U(2)
+
+#define PLAT_MARVELL_CORE_COUNT (PLAT_MARVELL_CLUSTER_COUNT * \
+ PLAT_MARVELL_CLUSTER_CORE_COUNT)
+
+#define PLAT_MAX_CPUS_PER_CLUSTER PLAT_MARVELL_CLUSTER_CORE_COUNT
+
+/* Part of DRAM that is used as Trusted ROM */
+#define PLAT_MARVELL_TRUSTED_ROM_BASE PLAT_MARVELL_ATF_LOAD_ADDR
+/* 4 MB for FIP image */
+#define PLAT_MARVELL_TRUSTED_ROM_SIZE 0x00400000
+/* Reserve 12MB for SCP (Secure PayLoad) Trusted RAM
+ * OP-TEE 4MB SHMEM follows this region
+ */
+#define PLAT_MARVELL_TRUSTED_RAM_BASE 0x04400000
+#define PLAT_MARVELL_TRUSTED_RAM_SIZE 0x00C00000 /* 12 MB DRAM */
+
+#define PLAT_MARVELL_LLC_SRAM_BASE 0x05400000
+#define PLAT_MARVELL_LLC_SRAM_SIZE 0x00100000 /* 1 MB SRAM */
+
+/*
+ * 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_UART_BASE (MVEBU_REGS_BASE + 0x512000)
+#define PLAT_MARVELL_UART_CLK_IN_HZ 200000000
+
+/* 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_SHARED_RAM_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 MVEBU_PMU_IRQ_WA
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/marvell/armada/a8k/common/mss/mss_a8k.mk b/plat/marvell/armada/a8k/common/mss/mss_a8k.mk
new file mode 100644
index 0000000..315fc87
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/mss/mss_a8k.mk
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+PLAT_MARVELL := plat/marvell/armada
+A8K_MSS_SOURCE := $(PLAT_MARVELL)/a8k/common/mss
+
+BL2_SOURCES += $(A8K_MSS_SOURCE)/mss_bl2_setup.c \
+ $(MARVELL_MOCHI_DRV)
+
+BL31_SOURCES += $(A8K_MSS_SOURCE)/mss_pm_ipc.c \
+ $(A8K_MSS_SOURCE)/mss_bl31_setup.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
diff --git a/plat/marvell/armada/a8k/common/mss/mss_bl2_setup.c b/plat/marvell/armada/a8k/common/mss/mss_bl2_setup.c
new file mode 100644
index 0000000..dee2d5b
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/mss/mss_bl2_setup.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/marvell/ccu.h>
+#include <drivers/marvell/mochi/ap_setup.h>
+#include <drivers/marvell/mochi/cp110_setup.h>
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+#include <marvell_plat_priv.h> /* timer functionality */
+#include "mss_defs.h"
+#include "mss_scp_bootloader.h"
+
+/* 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, cp;
+
+ 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;
+ (win_id < MVEBU_CCU_MAX_WINS) && (cfg_idx < cfg_num); win_id++) {
+ /* Skip already enabled CCU windows */
+ if (ccu_is_win_enabled(MVEBU_AP0, win_id))
+ continue;
+ /* Enable required CCU windows */
+ ccu_win_check(&ccu_mem_map[cfg_idx]);
+ ccu_enable_win(MVEBU_AP0, &ccu_mem_map[cfg_idx], win_id);
+ cfg_idx++;
+ }
+
+ /* Config address for each cp other than cp0 */
+ for (cp = 1; cp < CP_COUNT; cp++)
+ update_cp110_default_win(cp);
+
+ /* There is need to configure IO_WIN windows again to overwrite
+ * temporary configuration done during update_cp110_default_win
+ */
+ init_io_win(MVEBU_AP0);
+
+ /* Open AMB bridge required for MG access */
+ for (cp = 0; cp < CP_COUNT; cp++)
+ cp110_amb_init(MVEBU_CP_REGS_BASE(cp));
+
+ 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) + MSS_CP_REGS_OFFSET;
+}
+
+uintptr_t bl2_plat_get_cp_mss_sram(int ap_idx, int cp_idx)
+{
+ return MVEBU_CP_REGS_BASE(cp_idx) + MSS_CP_SRAM_OFFSET;
+}
+
+uintptr_t bl2_plat_get_ap_mss_regs(int ap_idx)
+{
+ return MVEBU_REGS_BASE + MSS_AP_REGS_OFFSET;
+}
+
+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 if (revision == MVEBU_CN9130_DEV_ID)
+ return CP_COUNT;
+ 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));
+}
diff --git a/plat/marvell/armada/a8k/common/mss/mss_bl31_setup.c b/plat/marvell/armada/a8k/common/mss/mss_bl31_setup.c
new file mode 100644
index 0000000..52a8929
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/mss/mss_bl31_setup.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+
+#include "mss_defs.h"
+
+void mss_start_cp_cm3(int cp)
+{
+ uint32_t magic;
+ uintptr_t sram = MVEBU_CP_REGS_BASE(cp) + MSS_CP_SRAM_OFFSET;
+ uintptr_t regs = MVEBU_CP_REGS_BASE(cp) + MSS_CP_REGS_OFFSET;
+
+ magic = mmio_read_32(sram);
+
+ /* Make sure the FW was loaded */
+ if (magic != MSS_FW_READY_MAGIC) {
+ return;
+ }
+
+ NOTICE("Starting CP%d MSS CPU\n", cp);
+ /* remove the magic */
+ mmio_write_32(sram, 0);
+ /* Release M3 from reset */
+ mmio_write_32(MSS_M3_RSTCR(regs),
+ (MSS_M3_RSTCR_RST_OFF << MSS_M3_RSTCR_RST_OFFSET));
+}
diff --git a/plat/marvell/armada/a8k/common/mss/mss_defs.h b/plat/marvell/armada/a8k/common/mss/mss_defs.h
new file mode 100644
index 0000000..6956461
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/mss/mss_defs.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MSS_DEFS_H
+#define MSS_DEFS_H
+
+#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_FW_READY_MAGIC 0x46575144 /* FWRD */
+
+#define MSS_AP_REGS_OFFSET 0x00580000
+#define MSS_CP_SRAM_OFFSET 0x00220000
+#define MSS_CP_REGS_OFFSET 0x00280000
+
+void mss_start_cp_cm3(int cp);
+
+#endif /* MSS_DEFS_H */
diff --git a/plat/marvell/armada/a8k/common/mss/mss_pm_ipc.c b/plat/marvell/armada/a8k/common/mss/mss_pm_ipc.c
new file mode 100644
index 0000000..a070583
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/mss/mss_pm_ipc.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <string.h>
+
+#include <common/debug.h>
+#include <lib/psci/psci.h>
+#include <lib/mmio.h>
+
+#include <mss_pm_ipc.h>
+
+/*
+ * 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;
+}
diff --git a/plat/marvell/armada/a8k/common/mss/mss_pm_ipc.h b/plat/marvell/armada/a8k/common/mss/mss_pm_ipc.h
new file mode 100644
index 0000000..1dfa9fa
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/mss/mss_pm_ipc.h
@@ -0,0 +1,35 @@
+/*
+ * 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 <mss_ipc_drv.h>
+
+/* 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 */
diff --git a/plat/marvell/armada/a8k/common/plat_bl1_setup.c b/plat/marvell/armada/a8k/common/plat_bl1_setup.c
new file mode 100644
index 0000000..f9521c8
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/plat_bl1_setup.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <lib/mmio.h>
+
+#include <plat_marvell.h>
+
+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);
+}
diff --git a/plat/marvell/armada/a8k/common/plat_bl31_setup.c b/plat/marvell/armada/a8k/common/plat_bl31_setup.c
new file mode 100644
index 0000000..db85cce
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/plat_bl31_setup.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <common/debug.h>
+#include <drivers/marvell/mci.h>
+#include <drivers/marvell/mochi/ap_setup.h>
+#include <drivers/marvell/mochi/cp110_setup.h>
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+#include <marvell_plat_priv.h>
+#include <marvell_pm.h>
+#include <mc_trustzone/mc_trustzone.h>
+#include <plat_marvell.h>
+#if MSS_SUPPORT
+#include <mss_ipc_drv.h>
+#include <mss_mem.h>
+#include <mss_defs.h>
+#endif
+
+/* 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);
+}
+
+#if MSS_SUPPORT
+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);
+}
+#endif
+
+_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++) {
+ cp110_init(MVEBU_CP_REGS_BASE(cp),
+ STREAM_ID_BASE + (cp * MAX_STREAM_ID_PER_CP));
+
+ marvell_bl31_mpp_init(cp);
+
+#if MSS_SUPPORT
+ /* Release CP MSS CPU from reset once the CP init is done */
+ mss_start_cp_cm3(cp);
+#endif
+ }
+
+ for (cp = 1; cp < CP_COUNT; cp++)
+ mci_link_tune(cp - 1);
+
+#if MSS_SUPPORT
+ /* 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();
+#endif
+ /* Configure GPIO */
+ marvell_gpio_config();
+
+ marvell_bl31_security_setup();
+}
diff --git a/plat/marvell/armada/a8k/common/plat_ble_setup.c b/plat/marvell/armada/a8k/common/plat_ble_setup.c
new file mode 100644
index 0000000..9c5ee15
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/plat_ble_setup.c
@@ -0,0 +1,765 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <common/debug.h>
+#include <drivers/marvell/ap807_clocks_init.h>
+#include <drivers/marvell/aro.h>
+#include <drivers/marvell/ccu.h>
+#include <drivers/marvell/io_win.h>
+#include <drivers/marvell/mochi/ap_setup.h>
+#include <drivers/marvell/mochi/cp110_setup.h>
+
+#include <armada_common.h>
+#include <efuse_def.h>
+#include <mv_ddr_if.h>
+#include <mvebu_def.h>
+#include <plat_marvell.h>
+
+/* 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_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 is 0.88V for 2GHz clock on CN913x devices */
+#define AVS_AP807_CLK_VALUE ((0x80UL << 24) | \
+ (0x2dc << 13) | \
+ (0x2dc << 3) | \
+ (0x1 << AVS_SOFT_RESET_OFFSET) | \
+ (0x1 << AVS_ENABLE_OFFSET))
+
+/*
+ * - 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)
+ */
+/* Offsets for 2 efuse 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_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
+ #define EFUSE_AP_LD0_SWREV_OFFS 50 /* LD0[115:113] */
+#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 18 /* LD0[91:81] */
+ #define EFUSE_AP_LD0_SVC2_OFFS 29 /* LD0[102:92] */
+ #define EFUSE_AP_LD0_SVC3_OFFS 40 /* LD0[113:103] */
+ #define EFUSE_AP_LD0_WP_MASK 0x7FF /* 10 data,1 parity */
+ #define EFUSE_AP_LD0_SWREV_OFFS 51 /* LD0[116:114] */
+#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) {
+
+ avs_val = AVS_AP807_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;
+ uint8_t avs_data_bits, min_sw_ver, svc_fields;
+ unsigned int ap_type;
+
+ /* Get test EERPOM data */
+ 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_MASK;
+ mmio_write_32(MVEBU_AP_EFUSE_SRV_CTRL_REG, reg_val);
+
+ /* Obtain the value of LD0[125:63] */
+ efuse = mmio_read_32(MVEBU_AP_LDX_125_95_EFUSE_OFFS);
+ efuse <<= 32;
+ efuse |= mmio_read_32(MVEBU_AP_LDX_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]);
+ avs_data_bits = 7;
+ min_sw_ver = 2; /* parity check from sw revision 2 */
+ svc_fields = 4;
+ } else {
+ INFO("SVC: Efuse WP: [0]=0x%x, [1]=0x%x, [2]=0x%x\n",
+ svc[0], svc[1], svc[2]);
+ avs_data_bits = 10;
+ min_sw_ver = 1; /* parity check required from sw revision 1 */
+ svc_fields = 3;
+ }
+
+ /* Validate parity of SVC workpoint values */
+ for (i = 0; i < svc_fields; i++) {
+ uint8_t parity, bit;
+ perr[i] = 0;
+
+ for (bit = 1, parity = (svc[i] & 1); bit < avs_data_bits; bit++)
+ parity ^= (svc[i] >> bit) & 1;
+
+ /* From SW version 1 or 2 (AP806/AP807), check parity */
+ if ((sw_ver >= min_sw_ver) &&
+ (parity != ((svc[i] >> avs_data_bits) & 1)))
+ perr[i] = 1; /* register the error */
+ }
+
+ single_cluster = mmio_read_32(MVEBU_AP_LDX_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_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 {
+#if MARVELL_SVC_TEST
+ reg_val = mmio_read_32(AVS_EN_CTRL_REG);
+ avs_workpoint = (reg_val &
+ AVS_VDD_LOW_LIMIT_MASK) >>
+ AVS_LOW_VDD_LIMIT_OFFSET;
+ NOTICE("7040 1600Mhz, avs = 0x%x\n",
+ avs_workpoint);
+#else
+ NOTICE("SVC: AVS work point not changed\n");
+ return;
+#endif
+ }
+ 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 if (device_id == MVEBU_CN9130_DEV_ID) {
+ NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n",
+ "CN913x", freq_pidi_mode);
+ switch (freq_pidi_mode) {
+ case CPU_2200_DDR_1200_RCLK_1200:
+ if (perr[0])
+ goto perror;
+ avs_workpoint = svc[0];
+ break;
+ case CPU_2000_DDR_1200_RCLK_1200:
+ if (perr[1])
+ goto perror;
+ avs_workpoint = svc[1];
+ break;
+ case CPU_1600_DDR_1200_RCLK_1200:
+ if (perr[2])
+ goto perror;
+ avs_workpoint = svc[2];
+ break;
+ default:
+ ERROR("SVC: Unsupported Frequency 0x%x\n",
+ freq_pidi_mode);
+ return;
+
+ }
+ } else {
+ ERROR("SVC: Unsupported Device ID 0x%x\n", device_id);
+ return;
+ }
+
+ /* Set AVS control if needed */
+ if (avs_workpoint == 0) {
+ ERROR("SVC: You are using a frequency setup which is\n");
+ ERROR("Not supported by this device\n");
+ ERROR("This may result in malfunction of the device\n");
+ return;
+ }
+
+ /* Remove parity bit */
+ if (ap_type != CHIP_ID_AP807)
+ avs_workpoint &= 0x7F;
+ else
+ avs_workpoint &= 0x3FF;
+
+ /* 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, cp;
+ 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));
+
+ /* Config address for each cp other than cp0 */
+ for (cp = 1; cp < CP_COUNT; cp++)
+ update_cp110_default_win(cp);
+
+ /* 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;
+}
diff --git a/plat/marvell/armada/a8k/common/plat_pm.c b/plat/marvell/armada/a8k/common/plat_pm.c
new file mode 100644
index 0000000..9ea9276
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/plat_pm.c
@@ -0,0 +1,853 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <drivers/marvell/cache_llc.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <armada_common.h>
+#include <marvell_pm.h>
+#if MSS_SUPPORT
+#include <mss_pm_ipc.h>
+#endif
+#include <plat_marvell.h>
+#include <plat_pm_trace.h>
+
+#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 MSS_SUPPORT
+ 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
+#endif
+ {
+ /* 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 MSS_SUPPORT
+ 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__);
+ }
+#endif
+}
+
+/* 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 MSS_SUPPORT
+ 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
+#endif
+ {
+ 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
+ *****************************************************************************
+ */
+
+/* Set a weak stub for platforms that don't configure system power off */
+#pragma weak system_power_off
+int system_power_off(void)
+{
+ return 0;
+}
+
+static void __dead2 a8k_system_off(void)
+{
+ /* Call the platform specific system power off function */
+ system_power_off();
+
+ /* board doesn't have a system off implementation */
+ 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
+};
diff --git a/plat/marvell/armada/a8k/common/plat_pm_trace.c b/plat/marvell/armada/a8k/common/plat_pm_trace.c
new file mode 100644
index 0000000..e02a893
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/plat_pm_trace.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#if MSS_SUPPORT
+#include <mss_mem.h>
+
+#ifdef PM_TRACE_ENABLE
+#include <plat_pm_trace.h>
+
+/* 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 */
+#endif /* MSS_SUPPORT */
diff --git a/plat/marvell/armada/a8k/common/plat_thermal.c b/plat/marvell/armada/a8k/common/plat_thermal.c
new file mode 100644
index 0000000..a2fc0d0
--- /dev/null
+++ b/plat/marvell/armada/a8k/common/plat_thermal.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/marvell/thermal.h>
+#include <lib/mmio.h>
+
+#include <mvebu_def.h>
+
+#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;
+}
diff --git a/plat/marvell/armada/common/aarch64/marvell_bl2_mem_params_desc.c b/plat/marvell/armada/common/aarch64/marvell_bl2_mem_params_desc.c
new file mode 100644
index 0000000..6c55858
--- /dev/null
+++ b/plat/marvell/armada/common/aarch64/marvell_bl2_mem_params_desc.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <marvell_def.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * 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,
+ },
+
+ /*
+ * 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 = MARVELL_OPTEE_PAGEABLE_LOAD_BASE,
+ .image_info.image_max_size = MARVELL_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 = 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)
diff --git a/plat/marvell/armada/common/aarch64/marvell_common.c b/plat/marvell/armada/common/aarch64/marvell_common.c
new file mode 100644
index 0000000..21a62d4
--- /dev/null
+++ b/plat/marvell/armada/common/aarch64/marvell_common.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <plat_marvell.h>
+
+/* 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;
+}
+
diff --git a/plat/marvell/armada/common/aarch64/marvell_helpers.S b/plat/marvell/armada/common/aarch64/marvell_helpers.S
new file mode 100644
index 0000000..3038ec0
--- /dev/null
+++ b/plat/marvell/armada/common/aarch64/marvell_helpers.S
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2020, ARM Limited. All rights reserved.
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <asm_macros.S>
+#include <cortex_a72.h>
+#ifndef PLAT_a3700
+#include <drivers/marvell/ccu.h>
+#include <drivers/marvell/cache_llc.h>
+#endif
+#include <marvell_def.h>
+#include <platform_def.h>
+
+ .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
+#ifdef PLAT_a3700
+ mov x1, x30
+ bl get_ref_clk
+ mov x30, x1
+ mov_imm x1, 1000000
+ mul x1, x0, x1
+#else
+ mov_imm x1, PLAT_MARVELL_UART_CLK_IN_HZ
+#endif
+ mov_imm x0, PLAT_MARVELL_UART_BASE
+ 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_UART_BASE
+#ifdef PLAT_a3700
+
+ b console_a3700_core_putc
+#else
+ b console_16550_core_putc
+#endif
+endfunc plat_crash_console_putc
+
+ /* ---------------------------------------------
+ * void plat_crash_console_flush()
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * Out : void.
+ * Clobber list : r0
+ * ---------------------------------------------
+ */
+func plat_crash_console_flush
+ mov_imm x0, PLAT_MARVELL_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_LLC_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
diff --git a/plat/marvell/armada/common/marvell_bl1_setup.c b/plat/marvell/armada/common/marvell_bl1_setup.c
new file mode 100644
index 0000000..7b7cef3
--- /dev/null
+++ b/plat/marvell/armada/common/marvell_bl1_setup.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <platform_def.h>
+
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/sp805.h>
+#include <drivers/console.h>
+#include <plat/common/platform.h>
+
+#include <plat_marvell.h>
+
+/* 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
+}
diff --git a/plat/marvell/armada/common/marvell_bl2_setup.c b/plat/marvell/armada/common/marvell_bl2_setup.c
new file mode 100644
index 0000000..3dfa82e
--- /dev/null
+++ b/plat/marvell/armada/common/marvell_bl2_setup.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/console.h>
+#include <lib/utils.h>
+
+#ifdef SPD_opteed
+#include <optee_utils.h>
+#endif
+#include <marvell_def.h>
+#include <plat_marvell.h>
+
+/* 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);
+
+#ifdef SPD_opteed
+ bl_mem_params_node_t *pager_mem_params = NULL;
+ bl_mem_params_node_t *paged_mem_params = NULL;
+#endif /* SPD_opteed */
+ assert(bl_mem_params);
+
+ 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 /* SPD_opteed */
+ bl_mem_params->ep_info.spsr = marvell_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 = 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);
+}
+
diff --git a/plat/marvell/armada/common/marvell_bl31_setup.c b/plat/marvell/armada/common/marvell_bl31_setup.c
new file mode 100644
index 0000000..26ba906
--- /dev/null
+++ b/plat/marvell/armada/common/marvell_bl31_setup.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#ifdef USE_CCI
+#include <drivers/arm/cci.h>
+#endif
+#include <drivers/console.h>
+#include <plat/common/platform.h>
+
+#include <marvell_def.h>
+#include <marvell_plat_priv.h>
+#include <plat_marvell.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;
+
+/* 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;
+}
diff --git a/plat/marvell/armada/common/marvell_cci.c b/plat/marvell/armada/common/marvell_cci.c
new file mode 100644
index 0000000..80351ae
--- /dev/null
+++ b/plat/marvell/armada/common/marvell_cci.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <drivers/arm/cci.h>
+
+#include <plat_marvell.h>
+
+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()));
+}
diff --git a/plat/marvell/armada/common/marvell_common.mk b/plat/marvell/armada/common/marvell_common.mk
new file mode 100644
index 0000000..f0e6edf
--- /dev/null
+++ b/plat/marvell/armada/common/marvell_common.mk
@@ -0,0 +1,99 @@
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# https://spdx.org/licenses
+
+MARVELL_PLAT_BASE := plat/marvell/armada
+MARVELL_PLAT_INCLUDE_BASE := include/plat/marvell/armada
+
+SEPARATE_CODE_AND_RODATA := 1
+
+# flag to switch from PLL to ARO
+ARO_ENABLE := 0
+$(eval $(call add_define,ARO_ENABLE))
+
+# Convert LLC to secure SRAM
+LLC_SRAM := 0
+$(eval $(call add_define,LLC_SRAM))
+
+# 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
+
+ifeq (${SPD},opteed)
+PLAT_INCLUDES += -Iinclude/lib
+BL2_SOURCES += lib/optee/optee_utils.c
+endif
+
+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))
+
+# 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
+
+# MSS (SCP) build
+ifeq (${MSS_SUPPORT}, 1)
+include $(MARVELL_PLAT_BASE)/common/mss/mss_common.mk
+endif
+
+$(BUILD_PLAT)/$(BOOT_IMAGE): $(BUILD_PLAT)/bl1.bin $(BUILD_PLAT)/$(FIP_NAME)
+ $(if $(shell find $(BUILD_PLAT)/bl1.bin -type f -size +128k),$(error "Image '$(BUILD_PLAT)/bl1.bin' is bigger than 128kB"))
+ @cp $(BUILD_PLAT)/bl1.bin $(BUILD_PLAT)/$(BOOT_IMAGE) || { rm -f $(BUILD_PLAT)/$(BOOT_IMAGE); false; }
+ @truncate -s %128K $(BUILD_PLAT)/$(BOOT_IMAGE) || { rm -f $(BUILD_PLAT)/$(BOOT_IMAGE); false; }
+ @cat $(BUILD_PLAT)/$(FIP_NAME) >> $(BUILD_PLAT)/$(BOOT_IMAGE) || { rm -f $(BUILD_PLAT)/$(BOOT_IMAGE); false; }
+ @truncate -s %4 $(BUILD_PLAT)/$(BOOT_IMAGE) || { rm -f $(BUILD_PLAT)/$(BOOT_IMAGE); false; }
+ @$(ECHO_BLANK_LINE)
+ @echo "Built $@ successfully"
+ @$(ECHO_BLANK_LINE)
+
+.PHONY: mrvl_bootimage
+mrvl_bootimage: $(BUILD_PLAT)/$(BOOT_IMAGE)
+
+.PHONY: mrvl_flash
+mrvl_flash: $(BUILD_PLAT)/$(FLASH_IMAGE)
diff --git a/plat/marvell/armada/common/marvell_console.c b/plat/marvell/armada/common/marvell_console.c
new file mode 100644
index 0000000..ef54bff
--- /dev/null
+++ b/plat/marvell/armada/common/marvell_console.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/console.h>
+
+#include <plat_marvell.h>
+
+#ifdef PLAT_a3700
+#include <drivers/marvell/uart/a3700_console.h>
+#define PLAT_MARVELL_UART_CLK_IN_HZ (get_ref_clk() * 1000000)
+#define console_marvell_register console_a3700_register
+#else
+#include <drivers/ti/uart/uart_16550.h>
+#define console_marvell_register console_16550_register
+#endif
+
+static console_t marvell_boot_console;
+static console_t marvell_runtime_console;
+
+/*******************************************************************************
+ * Functions that set up the console
+ ******************************************************************************/
+
+/* Initialize the console to provide early debug support */
+void marvell_console_boot_init(void)
+{
+ int rc =
+ console_marvell_register(PLAT_MARVELL_UART_BASE,
+ PLAT_MARVELL_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_FLAG_BOOT);
+}
+
+void marvell_console_boot_end(void)
+{
+ console_flush();
+
+ (void)console_unregister(&marvell_boot_console);
+}
+
+/* Initialize the runtime console */
+void marvell_console_runtime_init(void)
+{
+ int rc =
+ console_marvell_register(PLAT_MARVELL_UART_BASE,
+ PLAT_MARVELL_UART_CLK_IN_HZ,
+ MARVELL_CONSOLE_BAUDRATE,
+ &marvell_runtime_console);
+ if (rc == 0)
+ panic();
+
+ console_set_scope(&marvell_runtime_console, CONSOLE_FLAG_RUNTIME);
+}
+
+void marvell_console_runtime_end(void)
+{
+ console_flush();
+
+ (void)console_unregister(&marvell_runtime_console);
+}
diff --git a/plat/marvell/armada/common/marvell_ddr_info.c b/plat/marvell/armada/common/marvell_ddr_info.c
new file mode 100644
index 0000000..7340996
--- /dev/null
+++ b/plat/marvell/armada/common/marvell_ddr_info.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <ddr_info.h>
+
+#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;
+}
diff --git a/plat/marvell/armada/common/marvell_gicv2.c b/plat/marvell/armada/common/marvell_gicv2.c
new file mode 100644
index 0000000..2505c9f
--- /dev/null
+++ b/plat/marvell/armada/common/marvell_gicv2.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <platform_def.h>
+
+#include <bl31/interrupt_mgmt.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <plat_marvell.h>
+
+/*
+ * 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();
+}
diff --git a/plat/marvell/armada/common/marvell_gicv3.c b/plat/marvell/armada/common/marvell_gicv3.c
new file mode 100644
index 0000000..0bd5545
--- /dev/null
+++ b/plat/marvell/armada/common/marvell_gicv3.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <plat/common/platform.h>
+
+#include <marvell_def.h>
+#include <plat_marvell.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_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);
+}
diff --git a/plat/marvell/armada/common/marvell_image_load.c b/plat/marvell/armada/common/marvell_image_load.c
new file mode 100644
index 0000000..be16b08
--- /dev/null
+++ b/plat/marvell/armada/common/marvell_image_load.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.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();
+}
diff --git a/plat/marvell/armada/common/marvell_io_storage.c b/plat/marvell/armada/common/marvell_io_storage.c
new file mode 100644
index 0000000..2627ba4
--- /dev/null
+++ b/plat/marvell/armada/common/marvell_io_storage.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <tools_share/firmware_image_package.h>
+
+/* 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 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 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
+ },
+ [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
+ },
+};
+
+
+/* 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;
+}
diff --git a/plat/marvell/armada/common/marvell_pm.c b/plat/marvell/armada/common/marvell_pm.c
new file mode 100644
index 0000000..3c675b2
--- /dev/null
+++ b/plat/marvell/armada/common/marvell_pm.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <lib/psci/psci.h>
+
+#include <marvell_pm.h>
+
+/* 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;
+}
diff --git a/plat/marvell/armada/common/marvell_topology.c b/plat/marvell/armada/common/marvell_topology.c
new file mode 100644
index 0000000..a40ff6f
--- /dev/null
+++ b/plat/marvell/armada/common/marvell_topology.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <plat_marvell.h>
+
+/* 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);
+}
diff --git a/plat/marvell/armada/common/mrvl_sip_svc.c b/plat/marvell/armada/common/mrvl_sip_svc.c
new file mode 100644
index 0000000..c4c5c0e
--- /dev/null
+++ b/plat/marvell/armada/common/mrvl_sip_svc.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <drivers/marvell/cache_llc.h>
+#include <drivers/marvell/mochi/ap_setup.h>
+#include <drivers/rambus/trng_ip_76.h>
+#include <lib/smccc.h>
+
+#include <marvell_plat_priv.h>
+#include <plat_marvell.h>
+
+#include "comphy/phy-comphy-cp110.h"
+#include "secure_dfx_access/dfx.h"
+#include "ddr_phy_access.h"
+#include <stdbool.h>
+
+/* #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 MV_SIP_DFX 0x82000014
+#define MV_SIP_DDR_PHY_WRITE 0x82000015
+#define MV_SIP_DDR_PHY_READ 0x82000016
+
+/* TRNG */
+#define MV_SIP_RNG_64 0xC200FF11
+
+#define MAX_LANE_NR 6
+#define MVEBU_COMPHY_OFFSET 0x441000
+#define MVEBU_CP_BASE_MASK (~0xffffff)
+
+/* Common PHY register */
+#define COMPHY_TRX_TRAIN_CTRL_REG_0_OFFS 0x120a2c
+
+/* 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, read, x5 = x1;
+ 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);
+ }
+
+ x5 = x1 + COMPHY_TRX_TRAIN_CTRL_REG_0_OFFS;
+ 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, x5);
+ 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
+ case MV_SIP_DFX:
+ if (x1 >= MV_SIP_DFX_THERMAL_INIT &&
+ x1 <= MV_SIP_DFX_THERMAL_SEL_CHANNEL) {
+ ret = mvebu_dfx_thermal_handle(x1, &read, x2, x3);
+ SMC_RET2(handle, ret, read);
+ }
+ if (x1 >= MV_SIP_DFX_SREAD && x1 <= MV_SIP_DFX_SWRITE) {
+ ret = mvebu_dfx_misc_handle(x1, &read, x2, x3);
+ SMC_RET2(handle, ret, read);
+ }
+
+ SMC_RET1(handle, SMC_UNK);
+ case MV_SIP_DDR_PHY_WRITE:
+ ret = mvebu_ddr_phy_write(x1, x2);
+ SMC_RET1(handle, ret);
+ case MV_SIP_DDR_PHY_READ:
+ read = 0;
+ ret = mvebu_ddr_phy_read(x1, (uint16_t *)&read);
+ SMC_RET2(handle, ret, read);
+ case MV_SIP_RNG_64:
+ if ((x1 % 2 + 1) > sizeof(read)/4) {
+ ERROR("%s: Maximum %ld random bytes per SMC call\n",
+ __func__, sizeof(read));
+ SMC_RET1(handle, SMC_UNK);
+ }
+ ret = eip76_rng_get_random((uint8_t *)&read, 4 * (x1 % 2 + 1));
+ SMC_RET2(handle, ret, read);
+ 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
+);
diff --git a/plat/marvell/armada/common/mss/mss_common.mk b/plat/marvell/armada/common/mss/mss_common.mk
new file mode 100644
index 0000000..4ab4359
--- /dev/null
+++ b/plat/marvell/armada/common/mss/mss_common.mk
@@ -0,0 +1,20 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+
+PLAT_MARVELL := plat/marvell/armada
+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) \
+ $(BOARD_DIR)/board/marvell_plat_config.c
+
+BL31_SOURCES += $(MSS_SOURCE)/mss_ipc_drv.c
+
+PLAT_INCLUDES += -I$(MSS_SOURCE)
diff --git a/plat/marvell/armada/common/mss/mss_ipc_drv.c b/plat/marvell/armada/common/mss/mss_ipc_drv.c
new file mode 100644
index 0000000..70ccfa5
--- /dev/null
+++ b/plat/marvell/armada/common/mss/mss_ipc_drv.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <string.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <plat_marvell.h>
+#include <mss_ipc_drv.h>
+
+#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;
+}
diff --git a/plat/marvell/armada/common/mss/mss_ipc_drv.h b/plat/marvell/armada/common/mss/mss_ipc_drv.h
new file mode 100644
index 0000000..bcb4b2d
--- /dev/null
+++ b/plat/marvell/armada/common/mss/mss_ipc_drv.h
@@ -0,0 +1,120 @@
+/*
+ * 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 <lib/psci/psci.h>
+
+#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 */
diff --git a/plat/marvell/armada/common/mss/mss_mem.h b/plat/marvell/armada/common/mss/mss_mem.h
new file mode 100644
index 0000000..5d68ac7
--- /dev/null
+++ b/plat/marvell/armada/common/mss/mss_mem.h
@@ -0,0 +1,60 @@
+/*
+ * 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 */
diff --git a/plat/marvell/armada/common/mss/mss_scp_bl2_format.h b/plat/marvell/armada/common/mss/mss_scp_bl2_format.h
new file mode 100644
index 0000000..90913b0
--- /dev/null
+++ b/plat/marvell/armada/common/mss/mss_scp_bl2_format.h
@@ -0,0 +1,45 @@
+/*
+ * 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 8
+#define FILE_MAGIC 0xddd01ff
+#define HEADER_VERSION 0x1
+
+#define MSS_IDRAM_SIZE 0x10000 /* 64KB */
+#define MSS_SRAM_SIZE 0x8000 /* 32KB */
+
+/* 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,
+ MG_CP2,
+};
+
+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 */
diff --git a/plat/marvell/armada/common/mss/mss_scp_bootloader.c b/plat/marvell/armada/common/mss/mss_scp_bootloader.c
new file mode 100644
index 0000000..fbede1b
--- /dev/null
+++ b/plat/marvell/armada/common/mss/mss_scp_bootloader.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <mg_conf_cm3/mg_conf_cm3.h>
+#include <lib/mmio.h>
+
+#include <plat_pm_trace.h>
+#include <mss_scp_bootloader.h>
+#include <mss_ipc_drv.h>
+#include <mss_mem.h>
+#include <mss_defs.h>
+#include <mss_scp_bl2_format.h>
+
+#define MSS_DMA_TIMEOUT 1000
+#define MSS_EXTERNAL_SPACE 0x50000000
+#define MSS_EXTERNAL_ADDR_MASK 0xfffffff
+#define MSS_INTERNAL_SPACE 0x40000000
+#define MSS_INTERNAL_ADDR_MASK 0x00ffffff
+
+#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_iram_dma_load(uint32_t src_addr, uint32_t size,
+ uintptr_t mss_regs)
+{
+ uint32_t i, loop_num, timeout;
+
+ /* load image to MSS RAM using DMA */
+ loop_num = (size / DMA_SIZE) + !!(size % DMA_SIZE);
+ for (i = 0; i < loop_num; i++) {
+ /* write source address */
+ mmio_write_32(MSS_DMA_SRCBR(mss_regs),
+ src_addr + (i * DMA_SIZE));
+ /* write destination address */
+ mmio_write_32(MSS_DMA_DSTBR(mss_regs), (i * DMA_SIZE));
+ /* make sure DMA data is ready before triggering it */
+ dsb();
+ /* 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 > 0U) {
+ 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("\nMSS DMA failed (timeout)\n");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int mss_image_load(uint32_t src_addr, uint32_t size,
+ uintptr_t mss_regs, uintptr_t sram)
+{
+ uint32_t chunks = 1; /* !sram case */
+ uint32_t chunk_num;
+ int ret;
+
+ /* 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;
+ }
+
+ /* The CPx MSS DMA cannot access DRAM directly in secure boot mode
+ * Copy the MSS FW image to MSS SRAM by the CPU first, then run
+ * MSS DMA for SRAM to IRAM copy
+ */
+ if (sram != 0) {
+ chunks = size / MSS_SRAM_SIZE + !!(size % MSS_SRAM_SIZE);
+ }
+
+ NOTICE("%s Loading MSS FW from addr. 0x%x Size 0x%x to MSS at 0x%lx\n",
+ sram == 0 ? "" : "SECURELY", src_addr, size, mss_regs);
+ for (chunk_num = 0; chunk_num < chunks; chunk_num++) {
+ size_t chunk_size = size;
+ uint32_t img_src = MSS_EXTERNAL_SPACE | /* no SRAM */
+ (src_addr & MSS_EXTERNAL_ADDR_MASK);
+
+ if (sram != 0) {
+ uintptr_t chunk_source =
+ src_addr + MSS_SRAM_SIZE * chunk_num;
+
+ if (chunk_num != (size / MSS_SRAM_SIZE)) {
+ chunk_size = MSS_SRAM_SIZE;
+ } else {
+ chunk_size = size % MSS_SRAM_SIZE;
+ }
+
+ if (chunk_size == 0) {
+ break;
+ }
+
+ VERBOSE("Chunk %d -> SRAM 0x%lx from 0x%lx SZ 0x%lx\n",
+ chunk_num, sram, chunk_source, chunk_size);
+ memcpy((void *)sram, (void *)chunk_source, chunk_size);
+ dsb();
+ img_src = MSS_INTERNAL_SPACE |
+ (sram & MSS_INTERNAL_ADDR_MASK);
+ }
+
+ ret = mss_iram_dma_load(img_src, chunk_size, mss_regs);
+ if (ret != 0) {
+ ERROR("MSS FW chunk %d load failed\n", chunk_num);
+ return ret;
+ }
+ }
+
+ bl2_plat_configure_mss_windows(mss_regs);
+
+ if (sram != 0) {
+ /* Wipe the MSS SRAM after using it as copy buffer */
+ memset((void *)sram, 0, MSS_SRAM_SIZE);
+ NOTICE("CP MSS startup is postponed\n");
+ /* FW loaded, but CPU startup postponed until final CP setup */
+ mmio_write_32(sram, MSS_FW_READY_MAGIC);
+ dsb();
+ } else {
+ /* 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), 0);
+ 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),
+ bl2_plat_get_cp_mss_sram(
+ ap_idx, cp_index));
+ if (ret != 0) {
+ ERROR("SCP Image load failed\n");
+ return -1;
+ }
+ }
+ break;
+ case MG_CP0:
+ case MG_CP1:
+ case MG_CP2:
+ cp_index = cm3_type - MG_CP0;
+ if (bl2_plat_get_cp_count(0) <= cp_index) {
+ NOTICE("Skipping MG CP%d related image\n",
+ cp_index);
+ break;
+ }
+ NOTICE("Load image to CP%d MG\n", cp_index);
+ ret = mg_image_load(single_img, image_size, cp_index);
+ if (ret != 0) {
+ ERROR("SCP Image load failed\n");
+ return -1;
+ }
+ 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 too 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;
+}
diff --git a/plat/marvell/armada/common/mss/mss_scp_bootloader.h b/plat/marvell/armada/common/mss/mss_scp_bootloader.h
new file mode 100644
index 0000000..d65354a
--- /dev/null
+++ b/plat/marvell/armada/common/mss/mss_scp_bootloader.h
@@ -0,0 +1,20 @@
+/*
+ * 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_cp_mss_sram(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 */
diff --git a/plat/marvell/armada/common/plat_delay_timer.c b/plat/marvell/armada/common/plat_delay_timer.c
new file mode 100644
index 0000000..2539752
--- /dev/null
+++ b/plat/marvell/armada/common/plat_delay_timer.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <drivers/delay_timer.h>
+
+#include <mvebu_def.h>
+
+#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);
+}
diff --git a/plat/marvell/marvell.mk b/plat/marvell/marvell.mk
new file mode 100644
index 0000000..b6a2b99
--- /dev/null
+++ b/plat/marvell/marvell.mk
@@ -0,0 +1,21 @@
+# 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))
+
+# Set board to work with DDR 32bit
+DDR32 := 0
+$(eval $(call add_define,DDR32))
diff --git a/plat/marvell/octeontx/otx2/t91/t9130/board/dram_port.c b/plat/marvell/octeontx/otx2/t91/t9130/board/dram_port.c
new file mode 100644
index 0000000..82ce07b
--- /dev/null
+++ b/plat/marvell/octeontx/otx2/t91/t9130/board/dram_port.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/mentor/mi2cv.h>
+#include <lib/mmio.h>
+
+#include <mv_ddr_if.h>
+#include <mvebu_def.h>
+#include <plat_marvell.h>
+
+#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
+ */
+struct mv_ddr_iface dram_iface_ap0 = {
+ .ap_base = MVEBU_REGS_BASE_AP(0),
+ .state = MV_DDR_IFACE_NRDY,
+ .validation = MV_DDR_MEMORY_CHECK,
+ .sscg = SSCG_EN,
+ .id = 0,
+ .iface_base_addr = 0,
+ .tm = {
+ DEBUG_LEVEL_ERROR,
+ 0x1, /* active interfaces */
+ /* cs_mask, mirror, dqs_swap, ck_swap X subphys */
+ { { { {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},
+ {0x1, 0x0, 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 */
+#if DDR32
+ MV_DDR_32BIT_ECC_PUP8_BUS_MASK, /* subphys mask */
+#else
+ MV_DDR_64BIT_ECC_PUP8_BUS_MASK, /* subphys mask */
+#endif
+ MV_DDR_CFG_SPD, /* ddr configuration data src */
+ NOT_COMBINED, /* ddr twin-die combined*/
+ { {0} }, /* raw spd data */
+ {0}, /* timing parameters */
+ { /* electrical configuration */
+ { /* memory electrical configuration */
+ MV_DDR_RTT_NOM_PARK_RZQ_DISABLE, /* rtt_nom */
+ { /* rtt_park 1cs */
+ MV_DDR_RTT_NOM_PARK_RZQ_DIV4,
+ /* rtt_park 2cs */
+ MV_DDR_RTT_NOM_PARK_RZQ_DIV1
+ },
+ { /* rtt_wr 1cs */
+ MV_DDR_RTT_WR_DYN_ODT_OFF,
+ /* rtt_wr 2cs */
+ MV_DDR_RTT_WR_RZQ_DIV2
+ },
+ 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 */
+ },
+ },
+ },
+};
+
+/* Pointer to the first DRAM interface in the system */
+struct mv_ddr_iface *ptr_iface = &dram_iface_ap0;
+
+struct mv_ddr_iface *mv_ddr_iface_get(void)
+{
+ /* Return current ddr interface */
+ return ptr_iface;
+}
+
+struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
+{
+ /* Return the board topology as defined in the board code */
+ return &ptr_iface->tm;
+}
+
+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, 0);
+
+ /* read data from spd */
+ i2c_read(I2C_SPD_ADDR, 0x0, 1, tm->spd_data.all_bytes,
+ sizeof(tm->spd_data.all_bytes));
+ }
+}
diff --git a/plat/marvell/octeontx/otx2/t91/t9130/board/marvell_plat_config.c b/plat/marvell/octeontx/otx2/t91/t9130/board/marvell_plat_config.c
new file mode 100644
index 0000000..fbacf54
--- /dev/null
+++ b/plat/marvell/octeontx/otx2/t91/t9130/board/marvell_plat_config.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <armada_common.h>
+#include <mvebu_def.h>
+
+/*
+ * If bootrom is currently at BLE there's no need to include the memory
+ * maps structure at this point
+ */
+#ifndef IMAGE_BLE
+
+/*****************************************************************************
+ * AMB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win amb_memory_map_cp0[] = {
+ /* CP0 SPI1 CS0 Direct Mode access */
+ {0xe800, 0x2000000, AMB_SPI1_CS0_ID},
+};
+
+int marvell_get_amb_memory_map(struct addr_map_win **win, uint32_t *size,
+ uintptr_t base)
+{
+ switch (base) {
+ case MVEBU_CP_REGS_BASE(0):
+ *win = amb_memory_map_cp0;
+ *size = ARRAY_SIZE(amb_memory_map_cp0);
+ return 0;
+ case MVEBU_CP_REGS_BASE(1):
+ case MVEBU_CP_REGS_BASE(2):
+ default:
+ *size = 0;
+ *win = 0;
+ return 1;
+ }
+}
+#endif
+
+/*****************************************************************************
+ * IO WIN Configuration
+ *****************************************************************************
+ */
+struct addr_map_win io_win_memory_map[] = {
+#if (CP_COUNT > 1)
+ /* SB (MCi0) internal regs */
+ {0x00000000f4000000, 0x2000000, MCI_0_TID},
+#if (CP_COUNT > 2)
+ /* SB (MCi1) internal regs */
+ {0x00000000f6000000, 0x2000000, MCI_1_TID},
+#endif
+#endif
+#ifndef IMAGE_BLE
+ /* SB (MCi0) PCIe0-2 on CP1 */
+ {0x00000000e2000000, 0x3000000, MCI_0_TID},
+ /* SB (MCi1) PCIe0-2 on CP2 */
+ {0x00000000e5000000, 0x3000000, MCI_1_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
+};
+
+/* Global Control Register - window default target */
+uint32_t marvell_get_io_win_gcr_target(int ap_index)
+{
+ /*
+ * PIDI == iMCIP AP to SB internal MoChi connection.
+ * In other words CP0
+ */
+ 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[] = {
+ /* SPI1_CS0 (RUNIT) window */
+ {0x00000000e8000000, 0x2000000, RUNIT_TID},
+ /* PEX2_X1 window */
+ {0x00000000e1000000, 0x1000000, PEX2_TID},
+ /* PEX1_X1 window */
+ {0x00000000e0000000, 0x1000000, PEX1_TID},
+ /* PEX0_X4 window */
+ {0x00000000c0000000, 0x20000000, PEX0_TID},
+};
+
+struct addr_map_win iob_memory_map_cp1[] = {
+
+ /* PEX2_X1 window */
+ {0x00000000e4000000, 0x1000000, PEX2_TID},
+ /* PEX1_X1 window */
+ {0x00000000e3000000, 0x1000000, PEX1_TID},
+ /* PEX0_X4 window */
+ {0x00000000e2000000, 0x1000000, PEX0_TID},
+};
+
+struct addr_map_win iob_memory_map_cp2[] = {
+
+ /* PEX2_X1 window */
+ {0x00000000e7000000, 0x1000000, PEX2_TID},
+ /* PEX1_X1 window */
+ {0x00000000e6000000, 0x1000000, PEX1_TID},
+ /* PEX0_X4 window */
+ {0x00000000e5000000, 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;
+ case MVEBU_CP_REGS_BASE(2):
+ *win = iob_memory_map_cp2;
+ *size = ARRAY_SIZE(iob_memory_map_cp2);
+ return 0;
+ default:
+ *size = 0;
+ *win = 0;
+ return 1;
+ }
+}
+#endif
+
+/*****************************************************************************
+ * CCU Configuration
+ *****************************************************************************
+ */
+struct addr_map_win ccu_memory_map[] = { /* IO window */
+#ifdef IMAGE_BLE
+ {0x00000000f2000000, 0x6000000, IO_0_TID}, /* IO window */
+#else
+#if LLC_SRAM
+ {PLAT_MARVELL_LLC_SRAM_BASE, PLAT_MARVELL_LLC_SRAM_SIZE, DRAM_0_TID},
+#endif
+ {0x00000000f2000000, 0xe000000, IO_0_TID}, /* IO window */
+ {0x00000000c0000000, 0x30000000, IO_0_TID}, /* IO window */
+ {0x0000002000000000, 0x70e000000, IO_0_TID}, /* IO for CV-OS */
+#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
+ *****************************************************************************
+ */
+void *plat_get_skip_image_data(void)
+{
+ /* No recovery button on CN-9130 board? */
+ return NULL;
+}
+#endif
diff --git a/plat/marvell/octeontx/otx2/t91/t9130/board/phy-porting-layer.h b/plat/marvell/octeontx/otx2/t91/t9130/board/phy-porting-layer.h
new file mode 100644
index 0000000..6b55407
--- /dev/null
+++ b/plat/marvell/octeontx/otx2/t91/t9130/board/phy-porting-layer.h
@@ -0,0 +1,145 @@
+/*
+ * 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
+#define XFI_PARAMS static const struct xfi_params
+
+
+XFI_PARAMS xfi_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
+ /* AP0 */
+ {
+ /* CP 0 */
+ {
+ { 0 }, /* Comphy0 not relevant*/
+ { 0 }, /* Comphy1 not relevant*/
+ { .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 }, /* Comphy2 */
+ { 0 }, /* Comphy3 not relevant*/
+ { .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 }, /* Comphy4 */
+ { 0 }, /* Comphy5 not relevant*/
+ },
+#if CP_NUM > 1
+ /* CP 1 */
+ {
+ { 0 }, /* Comphy0 not relevant*/
+ { 0 }, /* Comphy1 not relevant*/
+ { .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 }, /* Comphy2 */
+ { 0 }, /* Comphy3 not relevant*/
+ /* different from defaults */
+ { .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf,
+ .align90 = 0x5f,
+ .g1_dfe_res = 0x2, .g1_amp = 0xc,
+ .g1_emph = 0x5,
+ .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}, /* Comphy4 */
+ { 0 }, /* Comphy5 not relevant*/
+ },
+#if CP_NUM > 2
+ /* CP 2 */
+ {
+ { 0 }, /* Comphy0 not relevant*/
+ { 0 }, /* Comphy1 not relevant*/
+ { .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 }, /* Comphy2 */
+ { 0 }, /* Comphy3 not relevant*/
+ { .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 }, /* Comphy4 */
+ { 0 }, /* Comphy5 not relevant*/
+ },
+#endif
+#endif
+ },
+};
+
+#define SATA_PARAMS static const struct sata_params
+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,
+ .polarity_invert = COMPHY_POLARITY_NO_INVERT,
+ .valid = 0x1
+ },
+};
+
+static const struct usb_params
+ usb_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
+ [0 ... AP_NUM-1][0 ... CP_NUM-1][0 ... MAX_LANE_NR-1] = {
+ .polarity_invert = COMPHY_POLARITY_NO_INVERT
+ },
+};
+#endif /* __PHY_PORTING_LAYER_H */
diff --git a/plat/marvell/octeontx/otx2/t91/t9130/mvebu_def.h b/plat/marvell/octeontx/otx2/t91/t9130/mvebu_def.h
new file mode 100644
index 0000000..490be73
--- /dev/null
+++ b/plat/marvell/octeontx/otx2/t91/t9130/mvebu_def.h
@@ -0,0 +1,25 @@
+/*
+ * 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 <a8k_plat_def.h>
+
+/*
+ * CN-9130 has single CP0 inside the package and 2 additional one
+ * from MoChi interface. In case of db-9130-modular board the MCI interface
+ * is routed to:
+ * - on-board CP115 (MCI0)
+ * - extension board CP115 (MCI1)
+ */
+#define CP_COUNT CP_NUM
+#define MVEBU_SOC_AP807 1
+#define I2C_SPD_ADDR 0x53 /* Access SPD data */
+#define I2C_SPD_P0_ADDR 0x36 /* Select SPD data page 0 */
+
+#endif /* __MVEBU_DEF_H__ */
diff --git a/plat/marvell/octeontx/otx2/t91/t9130/platform.mk b/plat/marvell/octeontx/otx2/t91/t9130/platform.mk
new file mode 100644
index 0000000..1e2716d
--- /dev/null
+++ b/plat/marvell/octeontx/otx2/t91/t9130/platform.mk
@@ -0,0 +1,20 @@
+#
+# 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/ap807_setup.c
+
+BOARD_DIR := $(shell dirname $(lastword $(MAKEFILE_LIST)))
+include plat/marvell/armada/a8k/common/a8k_common.mk
+
+include plat/marvell/armada/common/marvell_common.mk
diff --git a/plat/marvell/octeontx/otx2/t91/t9130_cex7_eval/board/marvell_plat_config.c b/plat/marvell/octeontx/otx2/t91/t9130_cex7_eval/board/marvell_plat_config.c
new file mode 100644
index 0000000..5bae8eb
--- /dev/null
+++ b/plat/marvell/octeontx/otx2/t91/t9130_cex7_eval/board/marvell_plat_config.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ * Copyright (C) 2021 Semihalf.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <armada_common.h>
+#include <mvebu_def.h>
+
+/*
+ * If bootrom is currently at BLE there's no need to include the memory
+ * maps structure at this point
+ */
+#ifndef IMAGE_BLE
+
+/*****************************************************************************
+ * AMB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win amb_memory_map_cp0[] = {
+ /* CP0 SPI1 CS0 Direct Mode access */
+ {0xef00, 0x1000000, AMB_SPI1_CS0_ID},
+};
+
+struct addr_map_win amb_memory_map_cp1[] = {
+ /* CP1 SPI1 CS0 Direct Mode access */
+ {0xe800, 0x1000000, AMB_SPI1_CS0_ID},
+};
+
+int marvell_get_amb_memory_map(struct addr_map_win **win, uint32_t *size,
+ uintptr_t base)
+{
+ switch (base) {
+ case MVEBU_CP_REGS_BASE(0):
+ *win = amb_memory_map_cp0;
+ *size = ARRAY_SIZE(amb_memory_map_cp0);
+ return 0;
+ case MVEBU_CP_REGS_BASE(1):
+ *win = amb_memory_map_cp1;
+ *size = ARRAY_SIZE(amb_memory_map_cp1);
+ return 0;
+ case MVEBU_CP_REGS_BASE(2):
+ default:
+ *size = 0;
+ *win = 0;
+ return 1;
+ }
+}
+#endif
+
+/*****************************************************************************
+ * IO WIN Configuration
+ *****************************************************************************
+ */
+struct addr_map_win io_win_memory_map[] = {
+#if (CP_COUNT > 1)
+ /* SB (MCi0) internal regs */
+ {0x00000000f4000000, 0x2000000, MCI_0_TID},
+ /* SB (MCi0) PCIe0-2 on CP1 */
+ {0x00000000e2000000, 0x7000000, MCI_0_TID},
+ /*
+ * Due to lack of sufficient number of IO windows registers,
+ * below CP1 PCIE configuration must be performed in the
+ * later firmware stages. It should replace the MCI 0 indirect
+ * window, which becomes no longer needed.
+ */
+ /* {0x0000000890000000, 0x30000000, MCI_0_TID}, */
+#if (CP_COUNT > 2)
+ /* SB (MCi1) internal regs */
+ {0x00000000f6000000, 0x2000000, MCI_1_TID},
+ /* SB (MCi1) PCIe0-2 on CP2 */
+ {0x00000000e9000000, 0x6000000, MCI_1_TID},
+ /*
+ * Due to lack of sufficient number of IO windows registers,
+ * below CP2 PCIE configuration must be performed in the
+ * later firmware stages. It should replace the MCI 1 indirect
+ * window, which becomes no longer needed.
+ */
+ /* {0x00000008c0000000, 0x30000000, MCI_1_TID}, */
+#endif
+#endif
+#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
+};
+
+/* Global Control Register - window default target */
+uint32_t marvell_get_io_win_gcr_target(int ap_index)
+{
+ /*
+ * PIDI == iMCIP AP to SB internal MoChi connection.
+ * In other words CP0
+ */
+ 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[] = {
+ /* SPI1_CS0 (RUNIT) window */
+ {0x00000000ef000000, 0x1000000, RUNIT_TID},
+ /* PEX2_X1 window */
+ {0x00000000e1000000, 0x1000000, PEX2_TID},
+ /* PEX1_X1 window */
+ {0x00000000e0000000, 0x1000000, PEX1_TID},
+ /* PEX0_X4 window */
+ {0x00000000c0000000, 0x20000000, PEX0_TID},
+ {0x0000000800000000, 0x90000000, PEX0_TID},
+};
+
+struct addr_map_win iob_memory_map_cp1[] = {
+ /* SPI1_CS0 (RUNIT) window */
+ {0x00000000e8000000, 0x1000000, RUNIT_TID},
+ /* PEX2_X1 window */
+ {0x00000000e6000000, 0x2000000, PEX2_TID},
+ {0x00000008b0000000, 0x10000000, PEX2_TID},
+ /* PEX1_X1 window */
+ {0x00000000e4000000, 0x2000000, PEX1_TID},
+ {0x00000008a0000000, 0x10000000, PEX1_TID},
+ /* PEX0_X2 window */
+ {0x00000000e2000000, 0x2000000, PEX0_TID},
+ {0x0000000890000000, 0x10000000, PEX0_TID},
+};
+
+struct addr_map_win iob_memory_map_cp2[] = {
+
+ /* PEX2_X1 window */
+ {0x00000000ed000000, 0x2000000, PEX2_TID},
+ {0x00000008e0000000, 0x10000000, PEX2_TID},
+ /* PEX1_X1 window */
+ {0x00000000eb000000, 0x2000000, PEX1_TID},
+ {0x00000008d0000000, 0x10000000, PEX1_TID},
+ /* PEX0_X1 window */
+ {0x00000000e9000000, 0x2000000, PEX0_TID},
+ {0x00000008c0000000, 0x10000000, 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;
+ case MVEBU_CP_REGS_BASE(2):
+ *win = iob_memory_map_cp2;
+ *size = ARRAY_SIZE(iob_memory_map_cp2);
+ return 0;
+ default:
+ *size = 0;
+ *win = 0;
+ return 1;
+ }
+}
+#endif
+
+/*****************************************************************************
+ * CCU Configuration
+ *****************************************************************************
+ */
+struct addr_map_win ccu_memory_map[] = { /* IO window */
+#ifdef IMAGE_BLE
+ {0x00000000f2000000, 0x6000000, IO_0_TID}, /* IO window */
+#else
+#if LLC_SRAM
+ {PLAT_MARVELL_LLC_SRAM_BASE, PLAT_MARVELL_LLC_SRAM_SIZE, DRAM_0_TID},
+#endif
+ {0x00000000f2000000, 0xe000000, IO_0_TID}, /* IO window */
+ {0x00000000c0000000, 0x30000000, IO_0_TID}, /* IO window */
+ {0x0000000800000000, 0x100000000, IO_0_TID}, /* IO window */
+ {0x0000002000000000, 0x70e000000, IO_0_TID}, /* IO for CV-OS */
+#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
+ *****************************************************************************
+ */
+void *plat_get_skip_image_data(void)
+{
+ /* No recovery button on CN-9130 board? */
+ return NULL;
+}
+#endif
diff --git a/plat/marvell/octeontx/otx2/t91/t9130_cex7_eval/platform.mk b/plat/marvell/octeontx/otx2/t91/t9130_cex7_eval/platform.mk
new file mode 100644
index 0000000..ee55455
--- /dev/null
+++ b/plat/marvell/octeontx/otx2/t91/t9130_cex7_eval/platform.mk
@@ -0,0 +1,33 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+# Copyright (C) 2021 Semihalf.
+#
+# 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/ap807_setup.c
+
+BOARD_DIR := $(shell dirname $(lastword $(MAKEFILE_LIST)))
+
+#
+# CN913X CEx7 Evaluation Board shares the DRAM connectivity
+# and SerDes settings with the CN913X DB - reuse relevant
+# board-specific files.
+#
+T9130_DIR := $(BOARD_DIR)/../t9130
+PLAT_INCLUDES := -I$(T9130_DIR) \
+ -I$(T9130_DIR)/board
+BLE_PORTING_SOURCES := $(T9130_DIR)/board/dram_port.c \
+ $(BOARD_DIR)/board/marvell_plat_config.c
+
+include plat/marvell/armada/a8k/common/a8k_common.mk
+
+include plat/marvell/armada/common/marvell_common.mk
diff --git a/plat/mediatek/build_helpers/conditional_eval_options.mk b/plat/mediatek/build_helpers/conditional_eval_options.mk
new file mode 100644
index 0000000..6bb3b4e
--- /dev/null
+++ b/plat/mediatek/build_helpers/conditional_eval_options.mk
@@ -0,0 +1,51 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Conditional makefile variable assignment
+
+# Options depend on BUILD_TYPE variable
+ifeq ($(BUILD_TYPE),release)
+MTK_DEBUGSYS_LOCK := 1
+MTK_GET_PERM_DIS := 1
+ERRATA_KLEIN_2218950 := 0
+ERRATA_KLEIN_2184257 := 0
+ERRATA_KLEIN_BOOKER := 0
+ERRATA_MTH_BOOKER := 0
+ERRATA_MTHELP_BOOKER := 0
+CRASH_REPORTING := 1
+CONFIG_MTK_BL31_RAMDUMP := 0
+endif
+
+ifeq ($(BUILD_TYPE),debug)
+MTK_PTP3_PROC_DEBUG := 1
+MTK_SRAMRC_DEBUG := 1
+MTK_IOMMU_DEBUG := 1
+MTK_DCM_DEBUG := 1
+MTK_EMI_MPU_DEBUG := 1
+endif
+
+ifeq (${SPD},none)
+SPD_NONE:=1
+$(eval $(call add_define,SPD_NONE))
+endif
+
+# TEE OS config
+ifeq ($(SPD), tbase)
+CONFIG_TBASE := y
+endif
+
+# MICROTRUST OS config
+ifeq ($(SPD), teeid)
+CONFIG_MICROTRUST_TEEI := y
+endif
+
+ifeq (${CONFIG_ARCH_ARM_V8_2},y)
+ARCH_VERSION := armv8_2
+endif
+
+ifeq (${CONFIG_ARCH_ARM_V9},y)
+ARCH_VERSION := armv9
+endif
diff --git a/plat/mediatek/build_helpers/mtk_build_helpers.mk b/plat/mediatek/build_helpers/mtk_build_helpers.mk
new file mode 100644
index 0000000..fc3876e
--- /dev/null
+++ b/plat/mediatek/build_helpers/mtk_build_helpers.mk
@@ -0,0 +1,142 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Get local directory path
+define GET_LOCAL_DIR
+$(patsubst %/,%,$(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))))
+endef
+
+# Clear module source variable
+define CLEAR_LOCAL_SRCS
+$(eval $(1) :=)
+endef
+
+define EXPAND_SUB_MAKEFILE
+include $(S)
+endef
+
+# Expand sub rules.mk
+define INCLUDE_MAKEFILE
+$(eval MODULES_SUB_MAKEFILE := $(patsubst %,%/rules.mk,$(1)))
+$(foreach S,$(MODULES_SUB_MAKEFILE),$(eval $(EXPAND_SUB_MAKEFILE)))
+endef
+
+# Determine option variable is defined or not then define it
+define add_defined_option
+ifdef $(1)
+ifeq ($(findstring $(value $(1)), $(uppercase_table)),)
+DEFINES += -D$(1)$(if $(value $(1)),=$(value $(1)),)
+else
+ifeq ($(strip $(value $(1))),y)
+DEFINES += -D$(1)$(if $(value $(1)),=1,)
+endif
+endif
+endif
+endef
+
+define EXPAND_RULES_MAKEFILE
+LOCAL_SRCS-y :=
+MODULE :=
+SUB_RULES-y :=
+include $(S)
+endef
+
+# INCLUDE_MODULES macro expand included modules rules.mk
+# Arguments:
+# $(1) = MODULES variables
+define INCLUDE_MODULES
+$(eval MODULES_TEMP := $(1))
+$(eval MODULES_MAKEFILE := $(patsubst %,%/rules.mk,$(MODULES_TEMP)))
+$(foreach S,$(MODULES_MAKEFILE),$(eval $(EXPAND_RULES_MAKEFILE)))
+endef
+
+# MAKE_LOCALS expand module source file variable to BL${BL}_SOURCES
+# Arguments:
+# $(1) = source file
+# $(2) = BL stage (1, 2, 2u, 31, 32)
+define MAKE_LOCALS
+$(eval $(call uppercase,$(2))_SOURCES += $(1))
+endef
+
+# MAKE_LINKERFILE change linker script source file name to
+# target linker script
+# $(1) = linker script source file
+# $(2) = BL stage
+define MAKE_LINKERFILE
+$(eval EXTRA_GENERATED_LINKER_SCRIPT += $(BUILD_PLAT)/$(2)/$(patsubst %.ld.S,%.ld,$(notdir $(1))))
+endef
+
+# MAKE_LINKERFILE_ITER call MAKE_LINKERFILE iteratively
+# $(1) = linker script source file
+# $(2) = BL stage
+define MAKE_LINKERFILE_ITER
+$(eval $(foreach link_src,$(1),$(call MAKE_LINKERFILE,$(link_src),$(2))))
+endef
+
+# MAKE_LD_ITER generate the linker scripts using the C preprocessor iteratively
+# $(1) = output linker script
+# $(2) = input template
+# $(3) = BL stage (1, 2, 2u, 31, 32)
+define MAKE_LD_ITER
+$(eval index_list=$(shell seq $(words $(1))))
+$(eval $(foreach i, $(index_list), \
+$(call MAKE_LD,$(word $(i), $(1)), $(word $(i), $(2)),$(3))))
+endef
+
+# MAKE_MODULE reference MAKE_OBJS.
+# Create module folder under out/bl$(BL)/$(module)
+# Arguments:
+# $(1) = module name
+# $(2) = source file
+# $(3) = BL stage
+define MAKE_MODULE
+ $(eval MODULE := $(strip $(1)))
+ $(eval BUILD_DIR := ${BUILD_PLAT}/${3})
+ $(eval SOURCES := $(2))
+ $(eval OBJS_TEMP := $(addprefix $(BUILD_DIR)/$(MODULE)/,$(call SOURCES_TO_OBJS,$(SOURCES))))
+ $(eval MODULE_OBJS += $(OBJS_TEMP))
+ # 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_TEMP} ${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)))
+
+$(eval $(foreach objd,${OBJ_DIRS},$(call MAKE_PREREQ_DIR,${objd},${BUILD_DIR})))
+${3}_dirs: | ${OBJ_DIRS}
+
+$(eval $(call MAKE_OBJS,$(BUILD_DIR)/$(MODULE),$(SOURCES),${3}))
+
+libraries: $(OBJS_TEMP)
+endef
+
+# Include MTK configuration files
+
+# MTK makefile variables
+ifeq (${COREBOOT},1)
+MTK_COMMON_CFG := $(MTK_PLAT)/common/coreboot_config.mk
+else
+MTK_COMMON_CFG := $(MTK_PLAT)/common/common_config.mk
+endif
+MTK_PLAT := plat/mediatek
+MTK_PLAT_SOC := ${MTK_PLAT}/${MTK_SOC}
+MTK_PLAT_CFG := $(MTK_PLAT_SOC)/plat_config.mk
+MTK_PROJECT_CFG := $(MTK_PLAT)/project/$(PLAT)/project_config.mk
+MTK_OPTIONS := $(MTK_PLAT)/build_helpers/options.mk
+MTK_COND_EVAL := $(MTK_PLAT)/build_helpers/conditional_eval_options.mk
+
+# Indicate which BL should be built in command line
+ifeq (${NEED_BL32},yes)
+MTK_BL := bl32
+else
+MTK_BL := bl31
+endif
+# Include common, platform, board level config
+include $(MTK_COMMON_CFG)
+include $(MTK_PLAT_CFG)
+-include $(MTK_PROJECT_CFG)
+include $(MTK_COND_EVAL)
+include $(MTK_OPTIONS)
diff --git a/plat/mediatek/build_helpers/mtk_build_helpers_epilogue.mk b/plat/mediatek/build_helpers/mtk_build_helpers_epilogue.mk
new file mode 100644
index 0000000..22a546c
--- /dev/null
+++ b/plat/mediatek/build_helpers/mtk_build_helpers_epilogue.mk
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Expand include modules
+$(eval $(call INCLUDE_MODULES,$(MODULES-y)))
+
+# Make next section align to page size
+ifneq ($(MTK_EXTRA_LINKERFILE),)
+$(eval $(call MAKE_LINKERFILE_ITER,$(MTK_LINKERFILE_SOURCE),bl31))
+
+# EXTRA_GENERATED_LINKER_SCRIPT is a global variable of derived linker
+# script list(from MTK_LINKERFILE_SOURCE) after MAKE_LINKERFILE_ITER
+# function call
+EXTRA_LINKERFILE += ${EXTRA_GENERATED_LINKER_SCRIPT}
+
+# Expand derived linker script as build target
+$(eval $(call MAKE_LD_ITER, $(EXTRA_GENERATED_LINKER_SCRIPT),$(MTK_LINKERFILE_SOURCE),bl31))
+
+# mtk_align.ld MUST BE THE LAST LINKER SCRIPT!
+EXTRA_LINKERFILE += ${MTK_PLAT}/include/mtk_align.ld
+
+# bl31.ld should depend on EXTRA_LINKERFILE
+$(eval ${BUILD_PLAT}/bl31/bl31.ld: ${EXTRA_LINKERFILE})
+EXTRA_LINKERFILE := $(addprefix -T,$(EXTRA_LINKERFILE))
+else
+EXTRA_LINKERFILE :=
+endif
diff --git a/plat/mediatek/build_helpers/options.mk b/plat/mediatek/build_helpers/options.mk
new file mode 100644
index 0000000..0279648
--- /dev/null
+++ b/plat/mediatek/build_helpers/options.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# call add_defined_option to evaluate MTK defined value
+$(eval $(call add_defined_option,MTK_SIP_KERNEL_BOOT_ENABLE))
+$(eval $(call add_defined_option,PLAT_EXTRA_RODATA_INCLUDES))
+$(eval $(call add_defined_option,MTK_EXTRA_LINKERFILE))
+$(eval $(call add_defined_option,MTK_BL31_AS_BL2))
+$(eval $(call add_defined_option,MTK_BL33_IS_64BIT))
+$(eval $(call add_defined_option,PLAT_XLAT_TABLES_DYNAMIC))
+$(eval $(call add_defined_option,MTK_ADAPTED))
+$(eval $(call add_defined_option,MTK_PUBEVENT_ENABLE))
+$(eval $(call add_defined_option,MTK_SOC))
+$(eval $(call add_defined_option,UART_CLOCK))
+$(eval $(call add_defined_option,UART_BAUDRATE))
+$(eval $(call add_defined_option,CONFIG_MTK_MCUSYS))
+$(eval $(call add_defined_option,CONFIG_MTK_PM_SUPPORT))
+$(eval $(call add_defined_option,CONFIG_MTK_CPU_PM_SUPPORT))
+$(eval $(call add_defined_option,CONFIG_MTK_SMP_EN))
+$(eval $(call add_defined_option,CONFIG_MTK_CPU_SUSPEND_EN))
+$(eval $(call add_defined_option,CONFIG_MTK_PM_ARCH))
+$(eval $(call add_defined_option,CONFIG_MTK_CPU_PM_ARCH))
diff --git a/plat/mediatek/common/common_config.mk b/plat/mediatek/common/common_config.mk
new file mode 100644
index 0000000..851eb2c
--- /dev/null
+++ b/plat/mediatek/common/common_config.mk
@@ -0,0 +1,34 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# indicate the reset vector address can be programmed
+PROGRAMMABLE_RESET_ADDRESS := 1
+MULTI_CONSOLE_API := 1
+COLD_BOOT_SINGLE_CPU := 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 := 0
+PLAT_XLAT_TABLES_DYNAMIC := 1
+# enable this definition to print irq dump status in tf-a
+GIC_DEBUG := 0
+# Enable stack protector.
+# Allowed values are "all", "strong", "default" and "none"
+ENABLE_STACK_PROTECTOR := strong
+# AMU, Kernel will access amuserenr_el0 if PE supported
+# Firmware _must_ implement AMU support
+ENABLE_AMU := 1
+VENDOR_EXTEND_PUBEVENT_ENABLE := 1
+
+# MTK define options
+MTK_BL33_IS_64BIT := 0
+MTK_ADAPTED := 1
+
+# MTK module config
+CONFIG_MTK_INTERRUPT := y
+CONFIG_MTK_UART := y
+
+# UART baudrate
+UART_BAUDRATE := 921600
diff --git a/plat/mediatek/common/coreboot_config.mk b/plat/mediatek/common/coreboot_config.mk
new file mode 100644
index 0000000..59d18e8
--- /dev/null
+++ b/plat/mediatek/common/coreboot_config.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# indicate the reset vector address can be programmed
+PROGRAMMABLE_RESET_ADDRESS := 1
+COLD_BOOT_SINGLE_CPU := 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 := 0
+PLAT_XLAT_TABLES_DYNAMIC := 1
+
+VENDOR_EXTEND_PUBEVENT_ENABLE := 1
diff --git a/plat/mediatek/common/lpm/mt_lp_rm.c b/plat/mediatek/common/lpm/mt_lp_rm.c
new file mode 100644
index 0000000..0bafc66
--- /dev/null
+++ b/plat/mediatek/common/lpm/mt_lp_rm.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mt_lp_rm.h>
+#include <stddef.h>
+
+struct platform_mt_resource_manager {
+ unsigned int count;
+ struct mt_resource_manager *plat_rm;
+};
+
+static struct platform_mt_resource_manager plat_mt_rm;
+
+int mt_lp_rm_register(struct mt_resource_manager *rm)
+{
+ unsigned int i;
+ struct mt_resource_constraint *const *rc;
+
+ if ((rm == NULL) || (rm->consts == NULL) ||
+ (plat_mt_rm.plat_rm != NULL)) {
+ return MT_RM_STATUS_BAD;
+ }
+
+ for (i = 0U, rc = rm->consts; *rc != NULL; i++, rc++) {
+ if ((*rc)->init != NULL) {
+ (*rc)->init();
+ }
+ }
+
+ plat_mt_rm.plat_rm = rm;
+ plat_mt_rm.count = i;
+
+ return MT_RM_STATUS_OK;
+}
+
+int mt_lp_rm_reset_constraint(int idx, unsigned int cpuid, int stateid)
+{
+ struct mt_resource_constraint const *rc = NULL;
+
+ if ((plat_mt_rm.plat_rm == NULL) || (idx < 0) ||
+ (idx >= plat_mt_rm.count)) {
+ return MT_RM_STATUS_BAD;
+ }
+
+ rc = plat_mt_rm.plat_rm->consts[idx];
+
+ if ((rc == NULL) || (rc->reset == NULL)) {
+ return MT_RM_STATUS_BAD;
+ }
+
+ return rc->reset(cpuid, stateid);
+}
+
+int mt_lp_rm_find_and_run_constraint(int idx, unsigned int cpuid,
+ int stateid, void *priv)
+{
+ int i, res = MT_RM_STATUS_BAD;
+ struct mt_resource_constraint *const *rc;
+ struct mt_resource_manager *rm = plat_mt_rm.plat_rm;
+
+ if ((rm == NULL) || (idx < 0) || (idx >= plat_mt_rm.count)) {
+ return res;
+ }
+
+ /* If subsys clk/mtcmos is on, add block-resource-off flag */
+ if (rm->update != NULL) {
+ res = rm->update(rm->consts, stateid, priv);
+ if (res != 0) {
+ return res;
+ }
+ }
+
+ for (i = idx, rc = (rm->consts + idx); *rc != NULL; i++, rc++) {
+ if (((*rc)->is_valid != NULL) &&
+ ((*rc)->is_valid(cpuid, stateid))) {
+ if (((*rc)->run != NULL) &&
+ ((*rc)->run(cpuid, stateid) == 0)) {
+ res = i;
+ break;
+ }
+ }
+ }
+
+ return res;
+}
+
+int mt_lp_rm_do_update(int stateid, int type, void const *p)
+{
+ int res = MT_RM_STATUS_BAD;
+ struct mt_resource_constraint *const *rc;
+ struct mt_resource_manager *rm = plat_mt_rm.plat_rm;
+
+ if (rm == NULL) {
+ return res;
+ }
+
+ for (rc = rm->consts; *rc != NULL; rc++) {
+ if ((*rc)->update != NULL) {
+ res = (*rc)->update(stateid, type, p);
+ if (res != MT_RM_STATUS_OK) {
+ break;
+ }
+ }
+ }
+
+ return res;
+}
diff --git a/plat/mediatek/common/lpm/mt_lp_rm.h b/plat/mediatek/common/lpm/mt_lp_rm.h
new file mode 100644
index 0000000..e93dac3
--- /dev/null
+++ b/plat/mediatek/common/lpm/mt_lp_rm.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_LP_RM_H
+#define MT_LP_RM_H
+
+#include <stdbool.h>
+
+#define MT_RM_STATUS_OK 0
+#define MT_RM_STATUS_BAD -1
+
+enum PLAT_MT_LPM_RC_TYPE {
+ PLAT_RC_UPDATE_CONDITION,
+ PLAT_RC_UPDATE_REMAIN_IRQS
+};
+
+struct mt_resource_constraint {
+ int level;
+ int (*init)(void);
+ bool (*is_valid)(unsigned int cpu, int stateid);
+ int (*update)(int stateid, int type, const void *p);
+ int (*run)(unsigned int cpu, int stateid);
+ int (*reset)(unsigned int cpu, int stateid);
+ unsigned int (*allow)(int stateid);
+};
+
+struct mt_resource_manager {
+ int (*update)(struct mt_resource_constraint **con,
+ int stateid, void *priv);
+ struct mt_resource_constraint **consts;
+};
+
+extern int mt_lp_rm_register(struct mt_resource_manager *rm);
+extern int mt_lp_rm_find_and_run_constraint(int idx, unsigned int cpuid,
+ int stateid, void *priv);
+extern int mt_lp_rm_reset_constraint(int constraint_id, unsigned int cpuid,
+ int stateid);
+extern int mt_lp_rm_do_update(int stateid, int type, void const *p);
+#endif /* MT_LP_RM_H */
diff --git a/plat/mediatek/common/lpm/rules.mk b/plat/mediatek/common/lpm/rules.mk
new file mode 100644
index 0000000..87a212a
--- /dev/null
+++ b/plat/mediatek/common/lpm/rules.mk
@@ -0,0 +1,14 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := lpm
+LOCAL_SRCS-y := $(LOCAL_DIR)/mt_lp_rm.c
+
+PLAT_INCLUDES += -I${LOCAL_DIR}
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/common/mtk_bl31_setup.c b/plat/mediatek/common/mtk_bl31_setup.c
new file mode 100644
index 0000000..7c9db8b
--- /dev/null
+++ b/plat/mediatek/common/mtk_bl31_setup.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <arch.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/generic_delay_timer.h>
+#if XLAT_TABLES_LIB_V2 && PLAT_XLAT_TABLES_DYNAMIC
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#endif
+#include <plat/common/platform.h>
+
+#if COREBOOT
+#include <common/desc_image_load.h>
+
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/coreboot.h>
+#include <plat_params.h>
+#endif
+
+/* MTK headers */
+#if MTK_SIP_KERNEL_BOOT_ENABLE
+#include <cold_boot.h>
+#endif
+#include <lib/mtk_init/mtk_init.h>
+#include <mtk_mmap_pool.h>
+
+IMPORT_SYM(uintptr_t, __RW_START__, RW_START);
+IMPORT_SYM(uintptr_t, __DATA_START__, DATA_START);
+
+#if COREBOOT
+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;
+ }
+}
+#else
+#ifndef MTK_BL31_AS_BL2
+static struct mtk_bl31_fw_config bl31_fw_config;
+#else
+struct mtk_bl31_fw_config bl31_fw_config;
+#endif
+/* In order to be accessed after MMU enable */
+static struct mtk_bl_param_t bl_param_clone;
+
+void *get_mtk_bl31_fw_config(int index)
+{
+ void *arg = NULL;
+
+ switch (index) {
+ case BOOT_ARG_FROM_BL2:
+ arg = bl31_fw_config.from_bl2;
+ break;
+ case BOOT_ARG_SOC_FW_CONFIG:
+ arg = bl31_fw_config.soc_fw_config;
+ break;
+ case BOOT_ARG_HW_CONFIG:
+ arg = bl31_fw_config.hw_config;
+ break;
+ case BOOT_ARG_RESERVED:
+ arg = bl31_fw_config.reserved;
+ break;
+ default:
+ WARN("Fail to get boot arg, index:%d", index);
+ break;
+ }
+ return arg;
+}
+#endif
+/*****************************************************************************
+ * 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 bl31_early_platform_setup2(u_register_t from_bl2,
+ u_register_t soc_fw_config,
+ u_register_t hw_config, u_register_t plat_params_from_bl2)
+
+{
+#if COREBOOT
+ static console_t console;
+
+ params_early_setup(soc_fw_config);
+ if (coreboot_serial.type) {
+ console_16550_register(coreboot_serial.baseaddr,
+ coreboot_serial.input_hertz,
+ coreboot_serial.baud,
+ &console);
+ }
+ bl31_params_parse_helper(from_bl2, &bl32_ep_info, &bl33_ep_info);
+#else
+ struct mtk_bl_param_t *p_mtk_bl_param = (struct mtk_bl_param_t *)from_bl2;
+
+ if (p_mtk_bl_param == NULL) {
+ ERROR("from_bl2 should not be NULL\n");
+ panic();
+ }
+ memcpy(&bl_param_clone, p_mtk_bl_param, sizeof(struct mtk_bl_param_t));
+ bl31_fw_config.from_bl2 = (void *)&bl_param_clone;
+ bl31_fw_config.soc_fw_config = (void *)soc_fw_config;
+ bl31_fw_config.hw_config = (void *)hw_config;
+ bl31_fw_config.reserved = (void *)plat_params_from_bl2;
+#endif
+
+ INFO("MTK BL31 start\n");
+ /* Init delay function */
+ generic_delay_timer_init();
+ /* Initialize module initcall */
+ mtk_init_one_level(MTK_INIT_LVL_EARLY_PLAT);
+}
+
+void bl31_plat_arch_setup(void)
+{
+ const mmap_region_t bl_regions[] = {
+ MAP_BL_RO,
+ MAP_BL_RW,
+#if USE_COHERENT_MEM
+ MAP_BL_COHERENT_RAM,
+#endif
+ {0},
+ };
+
+ mtk_xlat_init(bl_regions);
+ /* Initialize module initcall */
+ mtk_init_one_level(MTK_INIT_LVL_ARCH);
+}
+
+/*****************************************************************************
+ * Perform any BL31 platform setup common to ARM standard platforms
+ ******************************************************************************/
+
+void bl31_platform_setup(void)
+{
+ mtk_init_one_level(MTK_INIT_LVL_PLAT_SETUP_0);
+ mtk_init_one_level(MTK_INIT_LVL_PLAT_SETUP_1);
+}
+
+/*******************************************************************************
+ * Operations before cold CPU leave BL31.
+ * Switch console to runtime state.
+ ******************************************************************************/
+void bl31_plat_runtime_setup(void)
+{
+ mtk_init_one_level(MTK_INIT_LVL_PLAT_RUNTIME);
+ console_switch_state(CONSOLE_FLAG_RUNTIME);
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+ return SYS_COUNTER_FREQ_IN_HZ;
+}
diff --git a/plat/mediatek/common/mtk_plat_common.c b/plat/mediatek/common/mtk_plat_common.c
new file mode 100644
index 0000000..76f74a9
--- /dev/null
+++ b/plat/mediatek/common/mtk_plat_common.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <lib/smccc.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.h>
+#include <services/arm_arch_svc.h>
+
+#include <mtk_plat_common.h>
+#include <mtk_sip_svc.h>
+#include <plat_private.h>
+
+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 (GET_SMC_CC(smc_fid) == SMC_64) {
+ *px1 = *px1 & SMC32_PARAM_MASK;
+ *px2 = *px2 & SMC32_PARAM_MASK;
+ *px3 = *px3 & SMC32_PARAM_MASK;
+ *px4 = *px4 & SMC32_PARAM_MASK;
+ }
+}
+
+/*****************************************************************************
+ * plat_is_smccc_feature_available() - This function checks whether SMCCC
+ * feature is availabile for platform.
+ * @fid: SMCCC function id
+ *
+ * Return SMC_OK if SMCCC feature is available and SMC_ARCH_CALL_NOT_SUPPORTED
+ * otherwise.
+ *****************************************************************************/
+int32_t plat_is_smccc_feature_available(u_register_t fid)
+{
+ switch (fid) {
+ case SMCCC_ARCH_SOC_ID:
+ return SMC_ARCH_CALL_SUCCESS;
+ default:
+ return SMC_ARCH_CALL_NOT_SUPPORTED;
+ }
+}
+
+int32_t plat_get_soc_version(void)
+{
+ uint32_t manfid = SOC_ID_SET_JEP_106(JEDEC_MTK_BKID, JEDEC_MTK_MFID);
+
+ return (int32_t)(manfid | (SOC_CHIP_ID & SOC_ID_IMPL_DEF_MASK));
+}
+
+int32_t plat_get_soc_revision(void)
+{
+ return 0;
+}
diff --git a/plat/mediatek/common/mtk_plat_common.h b/plat/mediatek/common/mtk_plat_common.h
new file mode 100644
index 0000000..4c14b9d
--- /dev/null
+++ b/plat/mediatek/common/mtk_plat_common.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef MTK_PLAT_COMMON_H
+#define MTK_PLAT_COMMON_H
+
+#include <stdint.h>
+
+#include <common/bl_common.h>
+#include <common/param_header.h>
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+#define SMC32_PARAM_MASK (0xFFFFFFFF)
+
+#define JEDEC_MTK_BKID U(4)
+#define JEDEC_MTK_MFID U(0x26)
+
+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 */
diff --git a/plat/mediatek/common/mtk_sip_svc.c b/plat/mediatek/common/mtk_sip_svc.c
new file mode 100644
index 0000000..dab0d45
--- /dev/null
+++ b/plat/mediatek/common/mtk_sip_svc.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <tools_share/uuid.h>
+
+#include <mtk_plat_common.h>
+#include <mtk_sip_svc.h>
+#include <plat_sip_calls.h>
+
+/* 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
+);
diff --git a/plat/mediatek/common/mtk_smc_handlers.c b/plat/mediatek/common/mtk_smc_handlers.c
new file mode 100644
index 0000000..51a960f
--- /dev/null
+++ b/plat/mediatek/common/mtk_smc_handlers.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#if MTK_SIP_KERNEL_BOOT_ENABLE
+#include <cold_boot.h>
+#endif
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mtk_init/mtk_init.h>
+#include <mtk_sip_svc.h>
+
+#define SMC_HANDLER_DEBUG(...) VERBOSE(__VA_ARGS__)
+#define SMC_HANDLER_DEBUG_NOT_IMP_MSG "%s[0x%x] smc handler not implemented\n"
+#define SMC_HANDLER_DEBUG_START_MSG "%s[0x%x] smc handler start, smc desc. index:%d\n"
+#define SMC_HANDLER_DEBUG_END_MSG "%s[0x%x] smc handler end\n"
+
+/*
+ * These macros below are used to identify SIP calls from Kernel,
+ * Hypervisor, or 2ndBootloader
+ */
+#define SIP_FID_ORI_MASK (0xc000)
+#define SIP_FID_ORI_SHIFT (14)
+#define SIP_FID_KERNEL (0x0)
+#define SIP_FID_KERNEL_VIA_GZ (0x1)
+#define SIP_FID_GZ (0x2)
+
+#define GET_SMC_ORI(_fid) (((_fid) & SIP_FID_ORI_MASK) >> SIP_FID_ORI_SHIFT)
+#define GET_SMC_ORI_NUM(_fid) ((_fid) & ~(SIP_FID_ORI_MASK))
+
+#define is_from_nsel2(_ori) (_ori == SIP_FID_GZ)
+#define is_from_bl33(_ori) \
+ ((_ori != SIP_FID_GZ) && (is_el1_2nd_bootloader() == 1))
+#define is_from_nsel1(_ori) \
+ (((_ori == SIP_FID_KERNEL) || \
+ (_ori == SIP_FID_KERNEL_VIA_GZ)) && \
+ (is_el1_2nd_bootloader() == 0))
+
+#define is_smc_forbidden(_ori) (_ori == SIP_FID_KERNEL_VIA_GZ)
+
+#define MASK_32_BIT (0xffffffffU)
+#define SMC_ID_EXPAND_AS_SMC_OPERATION(_smc_id, _smc_num) \
+ case _smc_id##_AARCH32: \
+ { \
+ x1 = x1 & MASK_32_BIT; \
+ x2 = x2 & MASK_32_BIT; \
+ x3 = x3 & MASK_32_BIT; \
+ x4 = x4 & MASK_32_BIT; \
+ } \
+ case _smc_id##_AARCH64: \
+ { \
+ if (_smc_id##_descriptor_index < 0) { \
+ SMC_HANDLER_DEBUG(SMC_HANDLER_DEBUG_NOT_IMP_MSG, #_smc_id, smc_id); \
+ break; \
+ } \
+ if (_smc_id##_descriptor_index >= smc_id_descriptor_max) { \
+ SMC_HANDLER_DEBUG("smc descriptor index[%d] exceed max[%d]\n", \
+ _smc_id##_descriptor_index, smc_id_descriptor_max); \
+ break; \
+ } \
+ SMC_HANDLER_DEBUG(SMC_HANDLER_DEBUG_START_MSG, #_smc_id, smc_id, \
+ _smc_id##_descriptor_index); \
+ ret = smc_handler_pool[_smc_id##_descriptor_index].smc_handler(x1,\
+ x2, x3, x4, handle, &smc_ret); \
+ SMC_HANDLER_DEBUG(SMC_HANDLER_DEBUG_END_MSG, #_smc_id, smc_id); \
+ break; \
+ }
+
+#define SMC_ID_EXPAND_AS_DESCRIPTOR_INDEX(_smc_id, _smc_num) \
+ short _smc_id##_descriptor_index __section("mtk_plat_ro") = -1;
+
+MTK_SIP_SMC_FROM_BL33_TABLE(SMC_ID_EXPAND_AS_DESCRIPTOR_INDEX);
+MTK_SIP_SMC_FROM_NS_EL1_TABLE(SMC_ID_EXPAND_AS_DESCRIPTOR_INDEX);
+
+IMPORT_SYM(uintptr_t, __MTK_SMC_POOL_START__, MTK_SMC_POOL_START);
+IMPORT_SYM(uintptr_t, __MTK_SMC_POOL_END_UNALIGNED__, MTK_SMC_POOL_END_UNALIGNED);
+
+static const struct smc_descriptor *smc_handler_pool;
+static short smc_id_descriptor_max;
+
+#if !MTK_SIP_KERNEL_BOOT_ENABLE
+/*
+ * If there is no SMC request needs to be served in 2nd bootloader,
+ * disable the service path inherently.
+ */
+bool is_el1_2nd_bootloader(void)
+{
+ return false;
+}
+#endif
+
+static void print_smc_descriptor(const struct smc_descriptor pool[])
+{
+ const struct smc_descriptor *p_smc_desc;
+
+ INFO("print smc descriptor pool\n");
+ for (p_smc_desc = &pool[0];
+ (char *)p_smc_desc < (char *)MTK_SMC_POOL_END_UNALIGNED;
+ p_smc_desc++) {
+ INFO("descriptor name:%s\n", p_smc_desc->smc_name);
+ INFO("descriptor index:%d\n", *p_smc_desc->smc_descriptor_index);
+ INFO("smc id 32:0x%x, smc id 64:0x%x\n",
+ p_smc_desc->smc_id_aarch32, p_smc_desc->smc_id_aarch64);
+ }
+}
+
+static int mtk_smc_handler_init(void)
+{
+ const struct smc_descriptor *iter;
+ short index_cnt;
+ int ret = 0;
+
+ smc_handler_pool = (const struct smc_descriptor *)MTK_SMC_POOL_START;
+ /* Designate descriptor index point to smc_handler_pool */
+ for (index_cnt = 0, iter = &smc_handler_pool[0];
+ (char *)iter < (char *)MTK_SMC_POOL_END_UNALIGNED;
+ iter++, index_cnt++) {
+ if (index_cnt < 0) {
+ SMC_HANDLER_DEBUG("smc handler pool index overflow!\n");
+ ret = -EPERM;
+ assert(0);
+ break;
+ }
+ *(iter->smc_descriptor_index) = index_cnt;
+ }
+ smc_id_descriptor_max = index_cnt;
+ print_smc_descriptor(smc_handler_pool);
+ return ret;
+}
+MTK_EARLY_PLAT_INIT(mtk_smc_handler_init);
+
+/* This function handles Mediatek defined SiP Calls from Bootloader */
+static uintptr_t mtk_smc_handler_bl33(uint32_t smc_id,
+ u_register_t x1,
+ u_register_t x2,
+ u_register_t x3,
+ u_register_t x4,
+ void *cookie,
+ void *handle,
+ u_register_t flags)
+{
+ uintptr_t ret = MTK_SIP_E_SUCCESS;
+ struct smccc_res smc_ret = {0};
+
+ switch (smc_id) {
+ MTK_SIP_SMC_FROM_BL33_TABLE(SMC_ID_EXPAND_AS_SMC_OPERATION);
+ default:
+ INFO("BL33 SMC ID:0x%x not supported\n", smc_id);
+ ret = SMC_UNK;
+ break;
+ }
+ SMC_RET4(handle, ret, smc_ret.a1, smc_ret.a2, smc_ret.a3);
+}
+
+/* This function handles Mediatek defined SiP Calls from Kernel */
+static uintptr_t mtk_smc_handler_nsel1(uint32_t smc_id,
+ u_register_t x1,
+ u_register_t x2,
+ u_register_t x3,
+ u_register_t x4,
+ void *cookie,
+ void *handle,
+ u_register_t flags)
+{
+ uintptr_t ret = MTK_SIP_E_SUCCESS;
+ struct smccc_res smc_ret = {0};
+
+ switch (smc_id) {
+ MTK_SIP_SMC_FROM_NS_EL1_TABLE(SMC_ID_EXPAND_AS_SMC_OPERATION);
+ default:
+ INFO("NSEL1 SMC ID:0x%x not supported\n", smc_id);
+ ret = SMC_UNK;
+ break;
+ }
+ SMC_RET4(handle, ret, smc_ret.a1, smc_ret.a2, smc_ret.a3);
+}
+
+static uintptr_t mtk_smc_handler(uint32_t smc_id,
+ u_register_t x1,
+ u_register_t x2,
+ u_register_t x3,
+ u_register_t x4,
+ void *cookie,
+ void *handle,
+ u_register_t flags)
+{
+ uintptr_t ret = SMC_UNK;
+ uint32_t ns;
+ uint32_t smc_ori;
+ uint32_t smc_num;
+
+ /* Get SMC Originator bit 14.15 */
+ smc_ori = GET_SMC_ORI(smc_id);
+ /* Get SMC Number. Clean bit 14.15 */
+ smc_num = GET_SMC_ORI_NUM(smc_id);
+
+ /* Determine which security state this SMC originated from */
+ ns = is_caller_non_secure(flags);
+
+ if (ns && is_smc_forbidden(smc_ori)) {
+ ERROR("%s: Forbidden SMC call (0x%x)\n", __func__, smc_id);
+ SMC_RET1(handle, ret);
+ }
+
+ if (!ns) {
+ /* SiP SMC service secure world's call */
+ INFO("Secure SMC ID:0x%x not supported\n", smc_id);
+ SMC_RET1(handle, ret);
+ }
+ if (is_from_bl33(smc_ori)) {
+ /* SiP SMC service secure bootloader's call */
+ return mtk_smc_handler_bl33(smc_num, x1, x2, x3, x4,
+ cookie, handle, flags);
+ } else if (is_from_nsel1(smc_ori)) {
+ /* SiP SMC service kernel's call */
+ return mtk_smc_handler_nsel1(smc_num, x1, x2, x3, x4,
+ cookie, handle, flags);
+ }
+ INFO("SMC ID:0x%x not supported\n", smc_id);
+ SMC_RET1(handle, ret);
+}
+
+/* Define a runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+ mtk_smc_handler,
+ OEN_SIP_START,
+ OEN_SIP_END,
+ SMC_TYPE_FAST,
+ NULL,
+ mtk_smc_handler
+);
diff --git a/plat/mediatek/common/params_setup.c b/plat/mediatek/common/params_setup.c
new file mode 100644
index 0000000..a9df13e
--- /dev/null
+++ b/plat/mediatek/common/params_setup.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/bl_aux_params/bl_aux_params.h>
+#include <common/debug.h>
+#include <plat_params.h>
+#include <string.h>
+
+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);
+}
+
diff --git a/plat/mediatek/common/plat_params.h b/plat/mediatek/common/plat_params.h
new file mode 100644
index 0000000..828c3dc
--- /dev/null
+++ b/plat/mediatek/common/plat_params.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PARAMS_H
+#define PLAT_PARAMS_H
+
+#include <stdint.h>
+
+#include <export/plat/mediatek/common/plat_params_exp.h>
+
+struct bl_aux_gpio_info *plat_get_mtk_gpio_reset(void);
+void params_early_setup(u_register_t plat_param_from_bl2);
+
+#endif
diff --git a/plat/mediatek/common/rules.mk b/plat/mediatek/common/rules.mk
new file mode 100644
index 0000000..6acc731
--- /dev/null
+++ b/plat/mediatek/common/rules.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := mtk_common
+
+LOCAL_SRCS-y := ${LOCAL_DIR}/mtk_bl31_setup.c
+LOCAL_SRCS-y += ${LOCAL_DIR}/mtk_smc_handlers.c
+LOCAL_SRCS-$(MTK_SIP_KERNEL_BOOT_ENABLE) += ${LOCAL_DIR}/cold_boot.c
+
+$(eval $(call MAKE_LOCALS,$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/audio/audio.c b/plat/mediatek/drivers/audio/audio.c
new file mode 100644
index 0000000..285c565
--- /dev/null
+++ b/plat/mediatek/drivers/audio/audio.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+
+#include <common/debug.h>
+
+#include <audio.h>
+
+#include <mtk_sip_svc.h>
+
+#define MODULE_TAG "[AUDIO]"
+
+static u_register_t audio_smc_handler(u_register_t x1, u_register_t x2,
+ u_register_t x3, u_register_t x4,
+ void *handle, struct smccc_res *smccc_ret)
+{
+ uint32_t request_ops;
+ int ret;
+
+ request_ops = (uint32_t)x1;
+
+ switch (request_ops) {
+ case MTK_AUDIO_SMC_OP_DOMAIN_SIDEBANDS:
+ ret = set_audio_domain_sidebands();
+ break;
+ default:
+ ERROR("%s: %s: Unsupported request_ops %x\n",
+ MODULE_TAG, __func__, request_ops);
+ ret = -EIO;
+ break;
+ }
+
+ VERBOSE("%s: %s, request_ops = %x, ret = %d\n",
+ MODULE_TAG, __func__, request_ops, ret);
+ return ret;
+}
+/* Register SiP SMC service */
+DECLARE_SMC_HANDLER(MTK_SIP_AUDIO_CONTROL, audio_smc_handler);
diff --git a/plat/mediatek/drivers/audio/audio.h b/plat/mediatek/drivers/audio/audio.h
new file mode 100644
index 0000000..1598a92
--- /dev/null
+++ b/plat/mediatek/drivers/audio/audio.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AUDIO_H
+#define AUDIO_H
+
+#include <stdint.h>
+#include <lib/mmio.h>
+
+enum mtk_audio_smc_call_op {
+ MTK_AUDIO_SMC_OP_INIT = 0,
+ MTK_AUDIO_SMC_OP_DRAM_REQUEST,
+ MTK_AUDIO_SMC_OP_DRAM_RELEASE,
+ MTK_AUDIO_SMC_OP_SRAM_REQUEST,
+ MTK_AUDIO_SMC_OP_SRAM_RELEASE,
+ MTK_AUDIO_SMC_OP_ADSP_REQUEST,
+ MTK_AUDIO_SMC_OP_ADSP_RELEASE,
+ MTK_AUDIO_SMC_OP_DOMAIN_SIDEBANDS,
+ MTK_AUDIO_SMC_OP_BTCVSD_WRITE,
+ MTK_AUDIO_SMC_OP_BTCVSD_UPDATE_CTRL_CLEAR,
+ MTK_AUDIO_SMC_OP_BTCVSD_UPDATE_CTRL_UNDERFLOW,
+ MTK_AUDIO_SMC_OP_NUM,
+};
+
+int32_t set_audio_domain_sidebands(void);
+
+#endif /* AUDIO_H */
diff --git a/plat/mediatek/drivers/audio/mt8188/audio_domain.c b/plat/mediatek/drivers/audio/mt8188/audio_domain.c
new file mode 100644
index 0000000..cbafd19
--- /dev/null
+++ b/plat/mediatek/drivers/audio/mt8188/audio_domain.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2022, Mediatek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <common/debug.h>
+
+#include <audio.h>
+#include <mt_audio_private.h>
+#include <mtk_mmap_pool.h>
+#include <platform_def.h>
+#include <spm_reg.h>
+
+#define MODULE_TAG "[AUDIO_DOMAIN]"
+
+int32_t set_audio_domain_sidebands(void)
+{
+ uint32_t val = mmio_read_32(PWR_STATUS);
+
+ if ((val & BIT(SPM_PWR_STATUS_AUDIO_BIT)) == 0) {
+ ERROR("%s: %s, pwr_status=0x%x, w/o [%d]AUDIO!\n",
+ MODULE_TAG, __func__, val, SPM_PWR_STATUS_AUDIO_BIT);
+ return -EIO;
+ }
+
+ mmio_write_32(AFE_SE_SECURE_CON, 0x0);
+
+ mmio_write_32(AFE_SECURE_SIDEBAND0, 0x0);
+ mmio_write_32(AFE_SECURE_SIDEBAND1, 0x0);
+ mmio_write_32(AFE_SECURE_SIDEBAND2, 0x0);
+ mmio_write_32(AFE_SECURE_SIDEBAND3, 0x0);
+
+ VERBOSE("%s: %s, SE_SECURE_CON=0x%x, SIDEBAND0/1/2/3=0x%x/0x%x/0x%x/0x%x\n",
+ MODULE_TAG, __func__,
+ mmio_read_32(AFE_SE_SECURE_CON),
+ mmio_read_32(AFE_SECURE_SIDEBAND0),
+ mmio_read_32(AFE_SECURE_SIDEBAND1),
+ mmio_read_32(AFE_SECURE_SIDEBAND2),
+ mmio_read_32(AFE_SECURE_SIDEBAND3));
+
+ return 0;
+}
diff --git a/plat/mediatek/drivers/audio/mt8188/mt_audio_private.h b/plat/mediatek/drivers/audio/mt8188/mt_audio_private.h
new file mode 100644
index 0000000..bcb1abc
--- /dev/null
+++ b/plat/mediatek/drivers/audio/mt8188/mt_audio_private.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_AUDIO_PRIVATE_H
+#define MT_AUDIO_PRIVATE_H
+
+#include <platform_def.h>
+
+#define AFE_SE_SECURE_CON (AUDIO_BASE + 0x17a8)
+#define AFE_SECURE_SIDEBAND0 (AUDIO_BASE + 0x1908)
+#define AFE_SECURE_SIDEBAND1 (AUDIO_BASE + 0x190c)
+#define AFE_SECURE_SIDEBAND2 (AUDIO_BASE + 0x1910)
+#define AFE_SECURE_SIDEBAND3 (AUDIO_BASE + 0x1914)
+
+#define SPM_PWR_STATUS_AUDIO_BIT (6)
+
+#endif /* MT_AUDIO_PRIVATE_H */
diff --git a/plat/mediatek/drivers/audio/mt8188/rules.mk b/plat/mediatek/drivers/audio/mt8188/rules.mk
new file mode 100644
index 0000000..82acbfc
--- /dev/null
+++ b/plat/mediatek/drivers/audio/mt8188/rules.mk
@@ -0,0 +1,13 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := audio_${MTK_SOC}
+
+LOCAL_SRCS-y := ${LOCAL_DIR}/audio_domain.c
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/audio/rules.mk b/plat/mediatek/drivers/audio/rules.mk
new file mode 100644
index 0000000..8538a64
--- /dev/null
+++ b/plat/mediatek/drivers/audio/rules.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := audio
+
+LOCAL_SRCS-y := ${LOCAL_DIR}/audio.c
+
+PLAT_INCLUDES += -I${LOCAL_DIR}
+PLAT_INCLUDES += -I${LOCAL_DIR}/$(MTK_SOC)
+
+SUB_RULES-y:= ${LOCAL_DIR}/${MTK_SOC}
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
+$(eval $(call INCLUDE_MAKEFILE,$(SUB_RULES-y)))
diff --git a/plat/mediatek/drivers/cirq/mt_cirq.c b/plat/mediatek/drivers/cirq/mt_cirq.c
new file mode 100644
index 0000000..60534a2
--- /dev/null
+++ b/plat/mediatek/drivers/cirq/mt_cirq.c
@@ -0,0 +1,549 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/mmio.h>
+
+#include <mt_cirq.h>
+#include <mt_gic_v3.h>
+
+static struct cirq_events cirq_all_events = {
+ .spi_start = CIRQ_SPI_START,
+};
+static uint32_t already_cloned;
+/*
+ * mt_irq_mask_restore: restore all interrupts
+ * @mask: pointer to struct mtk_irq_mask for storing the original mask value.
+ * Return 0 for success; return negative values for failure.
+ * (This is ONLY used for the idle current measurement by the factory mode.)
+ */
+int mt_irq_mask_restore(struct mtk_irq_mask *mask)
+{
+ if (mask == NULL) {
+ return -1;
+ }
+ if (mask->header != IRQ_MASK_HEADER) {
+ return -1;
+ }
+ if (mask->footer != IRQ_MASK_FOOTER) {
+ return -1;
+ }
+
+ mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x4),
+ mask->mask1);
+ mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x8),
+ mask->mask2);
+ mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0xc),
+ mask->mask3);
+ mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x10),
+ mask->mask4);
+ mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x14),
+ mask->mask5);
+ mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x18),
+ mask->mask6);
+ mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x1c),
+ mask->mask7);
+ mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x20),
+ mask->mask8);
+ mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x24),
+ mask->mask9);
+ mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x28),
+ mask->mask10);
+ mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x2c),
+ mask->mask11);
+ mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x30),
+ mask->mask12);
+ /* make sure dist changes happen */
+ dsb();
+
+ return 0;
+}
+
+/*
+ * mt_irq_mask_all: disable all interrupts
+ * @mask: pointer to struct mtk_irq_mask for storing the original mask value.
+ * Return 0 for success; return negative values for failure.
+ * (This is ONLY used for the idle current measurement by the factory mode.)
+ */
+int mt_irq_mask_all(struct mtk_irq_mask *mask)
+{
+ if (mask != NULL) {
+ /* for SPI */
+ mask->mask1 = mmio_read_32((BASE_GICD_BASE +
+ GICD_ISENABLER + 0x4));
+ mask->mask2 = mmio_read_32((BASE_GICD_BASE +
+ GICD_ISENABLER + 0x8));
+ mask->mask3 = mmio_read_32((BASE_GICD_BASE +
+ GICD_ISENABLER + 0xc));
+ mask->mask4 = mmio_read_32((BASE_GICD_BASE +
+ GICD_ISENABLER + 0x10));
+ mask->mask5 = mmio_read_32((BASE_GICD_BASE +
+ GICD_ISENABLER + 0x14));
+ mask->mask6 = mmio_read_32((BASE_GICD_BASE +
+ GICD_ISENABLER + 0x18));
+ mask->mask7 = mmio_read_32((BASE_GICD_BASE +
+ GICD_ISENABLER + 0x1c));
+ mask->mask8 = mmio_read_32((BASE_GICD_BASE +
+ GICD_ISENABLER + 0x20));
+ mask->mask9 = mmio_read_32((BASE_GICD_BASE +
+ GICD_ISENABLER + 0x24));
+ mask->mask10 = mmio_read_32((BASE_GICD_BASE +
+ GICD_ISENABLER + 0x28));
+ mask->mask11 = mmio_read_32((BASE_GICD_BASE +
+ GICD_ISENABLER + 0x2c));
+ mask->mask12 = mmio_read_32((BASE_GICD_BASE +
+ GICD_ISENABLER + 0x30));
+
+ /* for SPI */
+ mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x4),
+ 0xFFFFFFFF);
+ mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x8),
+ 0xFFFFFFFF);
+ mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0xC),
+ 0xFFFFFFFF);
+ mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x10),
+ 0xFFFFFFFF);
+ mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x14),
+ 0xFFFFFFFF);
+ mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x18),
+ 0xFFFFFFFF);
+ mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x1C),
+ 0xFFFFFFFF);
+ mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x20),
+ 0xFFFFFFFF);
+ mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x24),
+ 0xFFFFFFFF);
+ mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x28),
+ 0xFFFFFFFF);
+ mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x2c),
+ 0xFFFFFFFF);
+ mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x30),
+ 0xFFFFFFFF);
+ /* make sure distributor changes happen */
+ dsb();
+
+ mask->header = IRQ_MASK_HEADER;
+ mask->footer = IRQ_MASK_FOOTER;
+
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+static uint32_t mt_irq_get_pol(uint32_t irq)
+{
+#ifdef CIRQ_WITH_POLARITY
+ uint32_t reg;
+ uint32_t base = INT_POL_CTL0;
+
+ if (irq < 32U) {
+ return 0;
+ }
+
+ reg = ((irq - 32U) / 32U);
+
+ return mmio_read_32(base + reg * 4U);
+#else
+ return 0;
+#endif
+}
+
+unsigned int mt_irq_get_sens(unsigned int irq)
+{
+ unsigned int config;
+
+ /*
+ * 2'b10 edge
+ * 2'b01 level
+ */
+ config = mmio_read_32(MT_GIC_BASE + GICD_ICFGR + (irq / 16U) * 4U);
+ config = (config >> (irq % 16U) * 2U) & 0x3;
+
+ return config;
+}
+
+static void collect_all_wakeup_events(void)
+{
+ unsigned int i;
+ uint32_t gic_irq;
+ uint32_t cirq;
+ uint32_t cirq_reg;
+ uint32_t cirq_offset;
+ uint32_t mask;
+ uint32_t pol_mask;
+ uint32_t irq_offset;
+ uint32_t irq_mask;
+
+ if ((cirq_all_events.wakeup_events == NULL) ||
+ cirq_all_events.num_of_events == 0U) {
+ return;
+ }
+
+ for (i = 0U; i < cirq_all_events.num_of_events; i++) {
+ if (cirq_all_events.wakeup_events[i] > 0U) {
+ gic_irq = cirq_all_events.wakeup_events[i];
+ cirq = gic_irq - cirq_all_events.spi_start - 32U;
+ cirq_reg = cirq / 32U;
+ cirq_offset = cirq % 32U;
+ mask = 0x1 << cirq_offset;
+ irq_offset = gic_irq % 32U;
+ irq_mask = 0x1 << irq_offset;
+ /*
+ * CIRQ default masks all
+ */
+ cirq_all_events.table[cirq_reg].mask |= mask;
+ /*
+ * CIRQ default pol is low
+ */
+ pol_mask = mt_irq_get_pol(
+ cirq_all_events.wakeup_events[i])
+ & irq_mask;
+ /*
+ * 0 means rising
+ */
+ if (pol_mask == 0U) {
+ cirq_all_events.table[cirq_reg].pol |= mask;
+ }
+ /*
+ * CIRQ could monitor edge/level trigger
+ * cirq register (0: edge, 1: level)
+ */
+ if (mt_irq_get_sens(cirq_all_events.wakeup_events[i])
+ == SENS_EDGE) {
+ cirq_all_events.table[cirq_reg].sen |= mask;
+ }
+
+ cirq_all_events.table[cirq_reg].used = 1U;
+ cirq_all_events.table[cirq_reg].reg_num = cirq_reg;
+ }
+ }
+}
+
+/*
+ * mt_cirq_set_pol: Set the polarity for the specified SYS_CIRQ number.
+ * @cirq_num: the SYS_CIRQ number to set
+ * @pol: polarity to set
+ * @return:
+ * 0: set pol success
+ * -1: cirq num is out of range
+ */
+#ifdef CIRQ_WITH_POLARITY
+static int mt_cirq_set_pol(uint32_t cirq_num, uint32_t pol)
+{
+ uint32_t base;
+ uint32_t bit = 1U << (cirq_num % 32U);
+
+ if (cirq_num >= CIRQ_IRQ_NUM) {
+ return -1;
+ }
+
+ if (pol == MT_CIRQ_POL_NEG) {
+ base = (cirq_num / 32U) * 4U + CIRQ_POL_CLR_BASE;
+ } else if (pol == MT_CIRQ_POL_POS) {
+ base = (cirq_num / 32U) * 4U + CIRQ_POL_SET_BASE;
+ } else {
+ return -1;
+ }
+
+ mmio_write_32(base, bit);
+ return 0;
+}
+#endif
+
+/*
+ * mt_cirq_mask: Mask the specified SYS_CIRQ.
+ * @cirq_num: the SYS_CIRQ number to mask
+ * @return:
+ * 0: mask success
+ * -1: cirq num is out of range
+ */
+static int mt_cirq_mask(uint32_t cirq_num)
+{
+ uint32_t bit = 1U << (cirq_num % 32U);
+
+ if (cirq_num >= CIRQ_IRQ_NUM) {
+ return -1;
+ }
+
+ mmio_write_32((cirq_num / 32U) * 4U + CIRQ_MASK_SET_BASE, bit);
+
+ return 0;
+}
+
+/*
+ * mt_cirq_unmask: Unmask the specified SYS_CIRQ.
+ * @cirq_num: the SYS_CIRQ number to unmask
+ * @return:
+ * 0: umask success
+ * -1: cirq num is out of range
+ */
+static int mt_cirq_unmask(uint32_t cirq_num)
+{
+ uint32_t bit = 1U << (cirq_num % 32U);
+
+ if (cirq_num >= CIRQ_IRQ_NUM) {
+ return -1;
+ }
+
+ mmio_write_32((cirq_num / 32U) * 4U + CIRQ_MASK_CLR_BASE, bit);
+
+ return 0;
+}
+
+uint32_t mt_irq_get_en(uint32_t irq)
+{
+ uint32_t addr, st, val;
+
+ addr = BASE_GICD_BASE + GICD_ISENABLER + (irq / 32U) * 4U;
+ st = mmio_read_32(addr);
+
+ val = (st >> (irq % 32U)) & 1U;
+
+ return val;
+}
+
+static void __cirq_fast_clone(void)
+{
+ struct cirq_reg *reg;
+ unsigned int i;
+
+ for (i = 0U; i < CIRQ_REG_NUM ; ++i) {
+ uint32_t cirq_bit;
+
+ reg = &cirq_all_events.table[i];
+
+ if (reg->used == 0U) {
+ continue;
+ }
+
+ mmio_write_32(CIRQ_SENS_CLR_BASE + (reg->reg_num * 4U),
+ reg->sen);
+
+ for (cirq_bit = 0U; cirq_bit < 32U; ++cirq_bit) {
+ uint32_t val, cirq_id;
+ uint32_t gic_id;
+#ifdef CIRQ_WITH_POLARITY
+ uint32_t gic_bit, pol;
+#endif
+ uint32_t en;
+
+ val = ((1U << cirq_bit) & reg->mask);
+
+ if (val == 0U) {
+ continue;
+ }
+
+ cirq_id = (reg->reg_num << 5U) + cirq_bit;
+ gic_id = CIRQ_TO_IRQ_NUM(cirq_id);
+#ifdef CIRQ_WITH_POLARITY
+ gic_bit = (0x1U << ((gic_id - 32U) % 32U));
+ pol = mt_irq_get_pol(gic_id) & gic_bit;
+ if (pol != 0U) {
+ mt_cirq_set_pol(cirq_id, MT_CIRQ_POL_NEG);
+ } else {
+ mt_cirq_set_pol(cirq_id, MT_CIRQ_POL_POS);
+ }
+#endif
+ en = mt_irq_get_en(gic_id);
+ if (en == 1U) {
+ mt_cirq_unmask(cirq_id);
+ } else {
+ mt_cirq_mask(cirq_id);
+ }
+ }
+ }
+}
+
+static void cirq_fast_clone(void)
+{
+ if (already_cloned == 0U) {
+ collect_all_wakeup_events();
+ already_cloned = 1U;
+ }
+ __cirq_fast_clone();
+}
+
+void set_wakeup_sources(uint32_t *list, uint32_t num_of_events)
+{
+ cirq_all_events.num_of_events = num_of_events;
+ cirq_all_events.wakeup_events = list;
+}
+/*
+ * mt_cirq_clone_gic: Copy the setting from GIC to SYS_CIRQ
+ */
+void mt_cirq_clone_gic(void)
+{
+ cirq_fast_clone();
+}
+
+uint32_t mt_irq_get_pending_vec(uint32_t start_irq)
+{
+ uint32_t base = 0U;
+ uint32_t pending_vec = 0U;
+ uint32_t reg = start_irq / 32U;
+ uint32_t LSB_num, MSB_num;
+ uint32_t LSB_vec, MSB_vec;
+
+ base = BASE_GICD_BASE;
+
+ /* if start_irq is not aligned 32, do some assembling */
+ MSB_num = start_irq % 32U;
+ if (MSB_num != 0U) {
+ LSB_num = 32U - MSB_num;
+ LSB_vec = mmio_read_32(base + GICD_ISPENDR +
+ reg * 4U) >> MSB_num;
+ MSB_vec = mmio_read_32(base + GICD_ISPENDR +
+ (reg + 1U) * 4U) << LSB_num;
+ pending_vec = MSB_vec | LSB_vec;
+ } else {
+ pending_vec = mmio_read_32(base + GICD_ISPENDR + reg * 4);
+ }
+
+ return pending_vec;
+}
+
+static int mt_cirq_get_mask_vec(unsigned int i)
+{
+ return mmio_read_32((i * 4U) + CIRQ_MASK_BASE);
+}
+
+/*
+ * mt_cirq_ack_all: Ack all the interrupt on SYS_CIRQ
+ */
+void mt_cirq_ack_all(void)
+{
+ uint32_t ack_vec, pend_vec, mask_vec;
+ unsigned int i;
+
+ for (i = 0; i < CIRQ_CTRL_REG_NUM; i++) {
+ /*
+ * if a irq is pending & not masked, don't ack it
+ * , since cirq start irq might not be 32 aligned with gic,
+ * need an exotic API to get proper vector of pending irq
+ */
+ pend_vec = mt_irq_get_pending_vec(CIRQ_SPI_START
+ + (i + 1U) * 32U);
+ mask_vec = mt_cirq_get_mask_vec(i);
+ /* those should be acked are: "not (pending & not masked)",
+ */
+ ack_vec = (~pend_vec) | mask_vec;
+ mmio_write_32(CIRQ_ACK_BASE + (i * 4U), ack_vec);
+ }
+
+ /*
+ * make sure all cirq setting take effect
+ * before doing other things
+ */
+ dsb();
+}
+/*
+ * mt_cirq_enable: Enable SYS_CIRQ
+ */
+void mt_cirq_enable(void)
+{
+ uint32_t st;
+
+ /* level only */
+ mt_cirq_ack_all();
+
+ st = mmio_read_32(CIRQ_CON);
+ /*
+ * CIRQ could monitor edge/level trigger
+ */
+ st |= (CIRQ_CON_EN << CIRQ_CON_EN_BITS);
+
+ mmio_write_32(CIRQ_CON, (st & CIRQ_CON_BITS_MASK));
+}
+
+/*
+ * mt_cirq_disable: Disable SYS_CIRQ
+ */
+void mt_cirq_disable(void)
+{
+ uint32_t st;
+
+ st = mmio_read_32(CIRQ_CON);
+ st &= ~(CIRQ_CON_EN << CIRQ_CON_EN_BITS);
+ mmio_write_32(CIRQ_CON, (st & CIRQ_CON_BITS_MASK));
+}
+
+void mt_irq_unmask_for_sleep_ex(uint32_t irq)
+{
+ uint32_t mask;
+
+ mask = 1U << (irq % 32U);
+
+ mmio_write_32(BASE_GICD_BASE + GICD_ISENABLER +
+ ((irq / 32U) * 4U), mask);
+}
+
+void mt_cirq_mask_all(void)
+{
+ unsigned int i;
+
+ for (i = 0U; i < CIRQ_CTRL_REG_NUM; i++) {
+ mmio_write_32(CIRQ_MASK_SET_BASE + (i * 4U), 0xFFFFFFFF);
+ }
+ dsb();
+}
+
+static void cirq_fast_sw_flush(void)
+{
+ struct cirq_reg *reg;
+ unsigned int i;
+
+ for (i = 0U; i < CIRQ_REG_NUM ; ++i) {
+ uint32_t cirq_bit;
+
+ reg = &cirq_all_events.table[i];
+
+ if (reg->used == 0U) {
+ continue;
+ }
+
+ reg->pending = mmio_read_32(CIRQ_STA_BASE +
+ (reg->reg_num << 2U));
+ reg->pending &= reg->mask;
+
+ for (cirq_bit = 0U; cirq_bit < 32U; ++cirq_bit) {
+ uint32_t val, cirq_id;
+
+ val = (1U << cirq_bit) & reg->pending;
+ if (val == 0U) {
+ continue;
+ }
+
+ cirq_id = (reg->reg_num << 5U) + cirq_bit;
+ mt_irq_set_pending(CIRQ_TO_IRQ_NUM(cirq_id));
+ if (CIRQ_TO_IRQ_NUM(cirq_id) == MD_WDT_IRQ_BIT_ID) {
+ INFO("Set MD_WDT_IRQ pending in %s\n",
+ __func__);
+ }
+ }
+ }
+}
+
+/*
+ * mt_cirq_disable: Flush interrupt from SYS_CIRQ to GIC
+ */
+void mt_cirq_flush(void)
+{
+ cirq_fast_sw_flush();
+ mt_cirq_mask_all();
+ mt_cirq_ack_all();
+}
+
+void mt_cirq_sw_reset(void)
+{
+ uint32_t st;
+
+ st = mmio_read_32(CIRQ_CON);
+ st |= (CIRQ_SW_RESET << CIRQ_CON_SW_RST_BITS);
+ mmio_write_32(CIRQ_CON, st);
+}
diff --git a/plat/mediatek/drivers/cirq/mt_cirq.h b/plat/mediatek/drivers/cirq/mt_cirq.h
new file mode 100644
index 0000000..cb96295
--- /dev/null
+++ b/plat/mediatek/drivers/cirq/mt_cirq.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MT_CIRQ_H
+#define PLAT_MT_CIRQ_H
+
+#include <stdint.h>
+#include <platform_def.h>
+
+enum {
+ IRQ_MASK_HEADER = 0xF1F1F1F1,
+ IRQ_MASK_FOOTER = 0xF2F2F2F2
+};
+
+struct mtk_irq_mask {
+ uint32_t header; /* for error checking */
+ uint32_t mask0;
+ uint32_t mask1;
+ uint32_t mask2;
+ uint32_t mask3;
+ uint32_t mask4;
+ uint32_t mask5;
+ uint32_t mask6;
+ uint32_t mask7;
+ uint32_t mask8;
+ uint32_t mask9;
+ uint32_t mask10;
+ uint32_t mask11;
+ uint32_t mask12;
+ uint32_t footer; /* for error checking */
+};
+
+/*
+ * Define hardware register
+ */
+#define CIRQ_STA_BASE (SYS_CIRQ_BASE + U(0x000))
+#define CIRQ_ACK_BASE (SYS_CIRQ_BASE + U(0x080))
+#define CIRQ_MASK_BASE (SYS_CIRQ_BASE + U(0x100))
+#define CIRQ_MASK_SET_BASE (SYS_CIRQ_BASE + U(0x180))
+#define CIRQ_MASK_CLR_BASE (SYS_CIRQ_BASE + U(0x200))
+#define CIRQ_SENS_BASE (SYS_CIRQ_BASE + U(0x280))
+#define CIRQ_SENS_SET_BASE (SYS_CIRQ_BASE + U(0x300))
+#define CIRQ_SENS_CLR_BASE (SYS_CIRQ_BASE + U(0x380))
+#define CIRQ_POL_BASE (SYS_CIRQ_BASE + U(0x400))
+#define CIRQ_POL_SET_BASE (SYS_CIRQ_BASE + U(0x480))
+#define CIRQ_POL_CLR_BASE (SYS_CIRQ_BASE + U(0x500))
+#define CIRQ_CON (SYS_CIRQ_BASE + U(0x600))
+
+/*
+ * Register placement
+ */
+#define CIRQ_CON_EN_BITS U(0)
+#define CIRQ_CON_EDGE_ONLY_BITS U(1)
+#define CIRQ_CON_FLUSH_BITS U(2)
+#define CIRQ_CON_SW_RST_BITS U(20)
+#define CIRQ_CON_EVENT_BITS U(31)
+#define CIRQ_CON_BITS_MASK U(0x7)
+
+/*
+ * Register setting
+ */
+#define CIRQ_CON_EN U(0x1)
+#define CIRQ_CON_EDGE_ONLY U(0x1)
+#define CIRQ_CON_FLUSH U(0x1)
+#define CIRQ_SW_RESET U(0x1)
+
+/*
+ * Define constant
+ */
+#define CIRQ_CTRL_REG_NUM ((CIRQ_IRQ_NUM + 31U) / 32U)
+
+#define MT_CIRQ_POL_NEG U(0)
+#define MT_CIRQ_POL_POS U(1)
+
+#define IRQ_TO_CIRQ_NUM(irq) ((irq) - (32U + CIRQ_SPI_START))
+#define CIRQ_TO_IRQ_NUM(cirq) ((cirq) + (32U + CIRQ_SPI_START))
+
+/* GIC sensitive */
+#define SENS_EDGE U(0x2)
+#define SENS_LEVEL U(0x1)
+
+
+/*
+ * Define function prototypes.
+ */
+int mt_cirq_test(void);
+void mt_cirq_dump_reg(void);
+int mt_irq_mask_restore(struct mtk_irq_mask *mask);
+int mt_irq_mask_all(struct mtk_irq_mask *mask);
+void mt_cirq_clone_gic(void);
+void mt_cirq_enable(void);
+void mt_cirq_flush(void);
+void mt_cirq_disable(void);
+void mt_irq_unmask_for_sleep_ex(uint32_t irq);
+void set_wakeup_sources(uint32_t *list, uint32_t num_of_events);
+void mt_cirq_sw_reset(void);
+
+struct cirq_reg {
+ uint32_t reg_num;
+ uint32_t used;
+ uint32_t mask;
+ uint32_t pol;
+ uint32_t sen;
+ uint32_t pending;
+ uint32_t the_link;
+};
+
+struct cirq_events {
+ uint32_t num_reg;
+ uint32_t spi_start;
+ uint32_t num_of_events;
+ uint32_t *wakeup_events;
+ struct cirq_reg table[CIRQ_REG_NUM];
+ uint32_t dist_base;
+ uint32_t cirq_base;
+ uint32_t used_reg_head;
+};
+
+#endif /* PLAT_MT_CIRQ_H */
diff --git a/plat/mediatek/drivers/cirq/rules.mk b/plat/mediatek/drivers/cirq/rules.mk
new file mode 100644
index 0000000..710eae0
--- /dev/null
+++ b/plat/mediatek/drivers/cirq/rules.mk
@@ -0,0 +1,14 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := cirq
+LOCAL_SRCS-y := $(LOCAL_DIR)/mt_cirq.c
+
+PLAT_INCLUDES += -I${LOCAL_DIR}
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm.c b/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm.c
new file mode 100644
index 0000000..313ad47
--- /dev/null
+++ b/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <lib/spinlock.h>
+
+#include <lib/mtk_init/mtk_init.h>
+#include <lib/pm/mtk_pm.h>
+#include "mt_cpu_pm.h"
+#include "mt_cpu_pm_cpc.h"
+#include "mt_cpu_pm_mbox.h"
+#include <mt_lp_rm.h>
+#include "mt_smp.h"
+#include <mtk_mmap_pool.h>
+#include <platform_def.h>
+
+/*
+ * The locker must use the bakery locker when cache turns off.
+ * Using spin_lock will gain better performance.
+ */
+#ifdef MT_CPU_PM_USING_BAKERY_LOCK
+DEFINE_BAKERY_LOCK(mt_cpu_pm_lock);
+#define plat_cpu_pm_lock_init() bakery_lock_init(&mt_cpu_pm_lock)
+#define plat_cpu_pm_lock() bakery_lock_get(&mt_cpu_pm_lock)
+#define plat_cpu_pm_unlock() bakery_lock_release(&mt_cpu_pm_lock)
+#else
+spinlock_t mt_cpu_pm_lock;
+#define plat_cpu_pm_lock_init()
+#define plat_cpu_pm_lock() spin_lock(&mt_cpu_pm_lock)
+#define plat_cpu_pm_unlock() spin_unlock(&mt_cpu_pm_lock)
+#endif
+
+enum mt_pwr_node {
+ MT_PWR_NONMCUSYS = 0,
+ MT_PWR_MCUSYS_PDN,
+ MT_PWR_SUSPEND,
+ MT_PWR_SYSTEM_MEM,
+ MT_PWR_SYSTEM_PLL,
+ MT_PWR_SYSTEM_BUS,
+ MT_PWR_MAX,
+};
+
+#define CPU_PM_DEPD_INIT BIT(0)
+#define CPU_PM_DEPD_READY BIT(1)
+#define CPU_PM_PLAT_READY BIT(2)
+
+#ifdef CPU_PM_TINYSYS_SUPPORT
+#define CPU_PM_INIT_READY (CPU_PM_DEPD_INIT | CPU_PM_DEPD_READY)
+#define CPU_PM_LP_READY (CPU_PM_INIT_READY | CPU_PM_PLAT_READY)
+#else
+#define CPU_PM_LP_READY (CPU_PM_PLAT_READY)
+#endif
+
+#if CONFIG_MTK_PM_SUPPORT
+
+#if CONFIG_MTK_CPU_SUSPEND_EN || CONFIG_MTK_SMP_EN
+static void cpupm_cpu_resume_common(const struct mtk_cpupm_pwrstate *state)
+{
+ CPU_PM_ASSERT(state != NULL);
+ mtk_cpc_core_on_hint_clr(state->info.cpuid);
+}
+#endif
+
+#if CONFIG_MTK_SMP_EN
+static int cpupm_cpu_pwr_on_prepare(unsigned int cpu, uintptr_t entry)
+{
+ struct cpu_pwr_ctrl pwr_ctrl;
+
+ PER_CPU_PWR_CTRL(pwr_ctrl, cpu);
+ mt_smp_core_bootup_address_set(&pwr_ctrl, entry);
+ mt_smp_core_init_arch(0, cpu, 1, &pwr_ctrl);
+
+ return mt_smp_power_core_on(cpu, &pwr_ctrl);
+}
+
+static void cpupm_cpu_resume_smp(const struct mtk_cpupm_pwrstate *state)
+{
+ CPU_PM_ASSERT(state != NULL);
+
+ plat_cpu_pm_lock();
+ mmio_clrbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG,
+ GIC_WAKEUP_IGNORE(state->info.cpuid));
+ plat_cpu_pm_unlock();
+ cpupm_cpu_resume_common(state);
+}
+
+static void cpupm_cpu_suspend_smp(const struct mtk_cpupm_pwrstate *state)
+{
+ struct cpu_pwr_ctrl pwr_ctrl;
+
+ CPU_PM_ASSERT(state != NULL);
+
+ PER_CPU_PWR_CTRL(pwr_ctrl, state->info.cpuid);
+ mt_smp_power_core_off(&pwr_ctrl);
+ mmio_setbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG,
+ GIC_WAKEUP_IGNORE(state->info.cpuid));
+}
+
+static void cpupm_smp_init(unsigned int cpu, uintptr_t sec_entrypoint)
+{
+ unsigned int reg;
+ struct mtk_cpupm_pwrstate state = {
+ .info = {
+ .cpuid = cpu,
+ .mode = MTK_CPU_PM_SMP,
+ },
+ .pwr = {
+ .afflv = 0,
+ .state_id = 0,
+ },
+ };
+
+ reg = mmio_read_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG);
+ if ((reg & CPC_MCUSYS_CPC_RESET_PWR_ON_EN) != 0) {
+ INFO("[%s:%d][CPU_PM] reset pwr on is enabled then clear it!\n",
+ __func__, __LINE__);
+ mmio_clrbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG, CPC_MCUSYS_CPC_RESET_PWR_ON_EN);
+ }
+
+ cpupm_cpu_pwr_on_prepare(cpu, sec_entrypoint);
+ cpupm_cpu_resume_smp(&state);
+}
+
+static struct mtk_cpu_smp_ops cpcv3_2_cpu_smp = {
+ .init = cpupm_smp_init,
+ .cpu_pwr_on_prepare = cpupm_cpu_pwr_on_prepare,
+ .cpu_on = cpupm_cpu_resume_smp,
+ .cpu_off = cpupm_cpu_suspend_smp,
+};
+
+#endif /* CONFIG_MTK_SMP_EN */
+
+#if CONFIG_MTK_CPU_SUSPEND_EN
+#define CPUPM_READY_MS (40000)
+#define CPUPM_ARCH_TIME_MS(ms) (ms * 1000 * SYS_COUNTER_FREQ_IN_MHZ)
+#define CPUPM_BOOTUP_TIME_THR CPUPM_ARCH_TIME_MS(CPUPM_READY_MS)
+
+static int mt_pwr_nodes[MT_PWR_MAX];
+static int plat_mt_lp_cpu_rc;
+static unsigned int cpu_pm_status;
+static unsigned int plat_prev_stateid;
+
+static int mcusys_prepare_suspend(const struct mtk_cpupm_pwrstate *state)
+{
+ unsigned int stateid = state->pwr.state_id;
+
+ if (mtk_cpc_mcusys_off_prepare() != CPC_SUCCESS) {
+ goto mt_pwr_mcusysoff_break;
+ }
+
+ if (!IS_PLAT_SUSPEND_ID(stateid)) {
+ if (mt_pwr_nodes[MT_PWR_SYSTEM_MEM] != 0) {
+ stateid = MT_PLAT_PWR_STATE_SYSTEM_MEM;
+ } else if (mt_pwr_nodes[MT_PWR_SYSTEM_PLL] != 0) {
+ stateid = MT_PLAT_PWR_STATE_SYSTEM_PLL;
+ } else if (mt_pwr_nodes[MT_PWR_SYSTEM_BUS] != 0) {
+ stateid = MT_PLAT_PWR_STATE_SYSTEM_BUS;
+ } else if (mt_pwr_nodes[MT_PWR_SUSPEND] != 0) {
+ stateid = MT_PLAT_PWR_STATE_SUSPEND;
+ } else {
+ stateid = MT_PLAT_PWR_STATE_MCUSYS;
+ }
+ }
+
+ plat_prev_stateid = stateid;
+ plat_mt_lp_cpu_rc = mt_lp_rm_find_and_run_constraint(0, state->info.cpuid, stateid, NULL);
+
+ if (plat_mt_lp_cpu_rc < 0) {
+ goto mt_pwr_mcusysoff_reflect;
+ }
+
+#ifdef CPU_PM_TINYSYS_SUPPORT
+ mtk_set_cpu_pm_preffered_cpu(state->info.cpuid);
+#endif
+ return MTK_CPUPM_E_OK;
+
+mt_pwr_mcusysoff_reflect:
+ mtk_cpc_mcusys_off_reflect();
+mt_pwr_mcusysoff_break:
+ plat_mt_lp_cpu_rc = -1;
+
+ return MTK_CPUPM_E_FAIL;
+}
+
+static int mcusys_prepare_resume(const struct mtk_cpupm_pwrstate *state)
+{
+ if (plat_mt_lp_cpu_rc < 0) {
+ return MTK_CPUPM_E_FAIL;
+ }
+
+ mt_lp_rm_reset_constraint(plat_mt_lp_cpu_rc, state->info.cpuid, plat_prev_stateid);
+ mtk_cpc_mcusys_off_reflect();
+ return MTK_CPUPM_E_OK;
+}
+
+static unsigned int cpupm_do_pstate_off(const mtk_pstate_type psci_state,
+ const struct mtk_cpupm_pwrstate *state)
+{
+ unsigned int pstate = MT_CPUPM_PWR_DOMAIN_CORE;
+
+ if (!state || (state->pwr.afflv > PLAT_MAX_PWR_LVL)) {
+ CPU_PM_ASSERT(0);
+ }
+
+ switch (state->pwr.state_id) {
+ case MT_PLAT_PWR_STATE_SYSTEM_MEM:
+ mt_pwr_nodes[MT_PWR_SYSTEM_MEM] += 1;
+ break;
+ case MT_PLAT_PWR_STATE_SYSTEM_PLL:
+ mt_pwr_nodes[MT_PWR_SYSTEM_PLL] += 1;
+ break;
+ case MT_PLAT_PWR_STATE_SYSTEM_BUS:
+ mt_pwr_nodes[MT_PWR_SYSTEM_BUS] += 1;
+ break;
+ case MT_PLAT_PWR_STATE_SUSPEND:
+ mt_pwr_nodes[MT_PWR_SUSPEND] += 1;
+ break;
+ default:
+ if (!IS_MT_PLAT_PWR_STATE_MCUSYS(state->pwr.state_id) &&
+ !IS_PLAT_SYSTEM_SUSPEND(state->pwr.afflv)) {
+ plat_cpu_pm_lock();
+ mt_pwr_nodes[MT_PWR_NONMCUSYS] += 1;
+ flush_dcache_range((uintptr_t)&mt_pwr_nodes[MT_PWR_NONMCUSYS],
+ sizeof(mt_pwr_nodes[MT_PWR_NONMCUSYS]));
+ plat_cpu_pm_unlock();
+ }
+ break;
+ }
+
+ if ((mt_pwr_nodes[MT_PWR_NONMCUSYS] == 0) && IS_PLAT_MCUSYSOFF_AFFLV(state->pwr.afflv)) {
+ /* Prepare to power down mcusys */
+ if (mcusys_prepare_suspend(state) == MTK_CPUPM_E_OK) {
+ mt_pwr_nodes[MT_PWR_MCUSYS_PDN] += 1;
+ flush_dcache_range((uintptr_t)&mt_pwr_nodes[MT_PWR_MCUSYS_PDN],
+ sizeof(mt_pwr_nodes[MT_PWR_MCUSYS_PDN]));
+ pstate |= (MT_CPUPM_PWR_DOMAIN_MCUSYS | MT_CPUPM_PWR_DOMAIN_CLUSTER);
+ }
+ }
+
+ if (state->pwr.afflv >= PLAT_MT_CPU_SUSPEND_CLUSTER) {
+ pstate |= MT_CPUPM_PWR_DOMAIN_CLUSTER;
+ }
+
+ if (psci_get_pstate_pwrlvl(psci_state) >= PLAT_MT_CPU_SUSPEND_CLUSTER) {
+ pstate |= MT_CPUPM_PWR_DOMAIN_PERCORE_DSU;
+ }
+
+ return pstate;
+}
+
+static unsigned int cpupm_do_pstate_on(const mtk_pstate_type psci_state,
+ const struct mtk_cpupm_pwrstate *state)
+{
+ unsigned int pstate = MT_CPUPM_PWR_DOMAIN_CORE;
+
+ CPU_PM_ASSERT(state != NULL);
+
+ if (state->pwr.afflv > PLAT_MAX_PWR_LVL) {
+ CPU_PM_ASSERT(0);
+ }
+
+ if (mt_pwr_nodes[MT_PWR_MCUSYS_PDN] != 0) {
+ mt_pwr_nodes[MT_PWR_MCUSYS_PDN] = 0;
+ flush_dcache_range((uintptr_t)&mt_pwr_nodes[MT_PWR_MCUSYS_PDN],
+ sizeof(mt_pwr_nodes[MT_PWR_MCUSYS_PDN]));
+ pstate |= (MT_CPUPM_PWR_DOMAIN_MCUSYS | MT_CPUPM_PWR_DOMAIN_CLUSTER);
+ mcusys_prepare_resume(state);
+ }
+
+ if (state->pwr.afflv >= PLAT_MT_CPU_SUSPEND_CLUSTER) {
+ pstate |= MT_CPUPM_PWR_DOMAIN_CLUSTER;
+ }
+
+ switch (state->pwr.state_id) {
+ case MT_PLAT_PWR_STATE_SYSTEM_MEM:
+ mt_pwr_nodes[MT_PWR_SYSTEM_MEM] -= 1;
+ CPU_PM_ASSERT(mt_pwr_nodes[MT_PWR_SYSTEM_MEM] >= 0);
+ break;
+ case MT_PLAT_PWR_STATE_SYSTEM_PLL:
+ mt_pwr_nodes[MT_PWR_SYSTEM_PLL] -= 1;
+ CPU_PM_ASSERT(mt_pwr_nodes[MT_PWR_SYSTEM_PLL] >= 0);
+ break;
+ case MT_PLAT_PWR_STATE_SYSTEM_BUS:
+ mt_pwr_nodes[MT_PWR_SYSTEM_BUS] -= 1;
+ CPU_PM_ASSERT(mt_pwr_nodes[MT_PWR_SYSTEM_BUS] >= 0);
+ break;
+ case MT_PLAT_PWR_STATE_SUSPEND:
+ mt_pwr_nodes[MT_PWR_SUSPEND] -= 1;
+ CPU_PM_ASSERT(mt_pwr_nodes[MT_PWR_SUSPEND] >= 0);
+ break;
+ default:
+ if (!IS_MT_PLAT_PWR_STATE_MCUSYS(state->pwr.state_id) &&
+ !IS_PLAT_SYSTEM_SUSPEND(state->pwr.afflv)) {
+ plat_cpu_pm_lock();
+ mt_pwr_nodes[MT_PWR_NONMCUSYS] -= 1;
+ flush_dcache_range((uintptr_t)&mt_pwr_nodes[MT_PWR_NONMCUSYS],
+ sizeof(mt_pwr_nodes[MT_PWR_NONMCUSYS]));
+ plat_cpu_pm_unlock();
+ }
+ break;
+ }
+
+ if (IS_PLAT_SYSTEM_SUSPEND(state->pwr.afflv) ||
+ (IS_PLAT_SYSTEM_RETENTION(state->pwr.afflv) && (mt_pwr_nodes[MT_PWR_SUSPEND] > 0))) {
+ mtk_cpc_time_sync();
+ }
+
+ if (mt_pwr_nodes[MT_PWR_NONMCUSYS] < 0) {
+ CPU_PM_ASSERT(0);
+ }
+
+ pstate |= MT_CPUPM_PWR_DOMAIN_PERCORE_DSU;
+
+ return pstate;
+}
+
+static void cpupm_cpu_resume(const struct mtk_cpupm_pwrstate *state)
+{
+ cpupm_cpu_resume_common(state);
+}
+
+static void cpupm_mcusys_resume(const struct mtk_cpupm_pwrstate *state)
+{
+ assert(state != NULL);
+}
+
+static void cpupm_mcusys_suspend(const struct mtk_cpupm_pwrstate *state)
+{
+ assert(state != NULL);
+}
+
+static unsigned int cpupm_get_pstate(enum mt_cpupm_pwr_domain domain,
+ const mtk_pstate_type psci_state,
+ const struct mtk_cpupm_pwrstate *state)
+{
+ unsigned int pstate = 0;
+
+ if (state == NULL) {
+ return 0;
+ }
+
+ if (state->info.mode == MTK_CPU_PM_SMP) {
+ pstate = MT_CPUPM_PWR_DOMAIN_CORE;
+ } else {
+ if (domain == CPUPM_PWR_OFF) {
+ pstate = cpupm_do_pstate_off(psci_state, state);
+ } else if (domain == CPUPM_PWR_ON) {
+ pstate = cpupm_do_pstate_on(psci_state, state);
+ } else {
+ INFO("[%s:%d][CPU_PM] unknown pwr domain :%d\n",
+ __func__, __LINE__, domain);
+ assert(0);
+ }
+ }
+ return pstate;
+}
+
+static int cpupm_init(void)
+{
+ int ret = MTK_CPUPM_E_OK;
+
+#ifdef CPU_PM_TINYSYS_SUPPORT
+ int status;
+
+ if ((cpu_pm_status & CPU_PM_INIT_READY) == CPU_PM_INIT_READY) {
+ return MTK_CPUPM_E_OK;
+ }
+
+ if (!(cpu_pm_status & CPU_PM_DEPD_INIT)) {
+ status = mtk_lp_depd_condition(CPUPM_MBOX_WAIT_DEV_INIT);
+ if (status == 0) {
+ plat_cpu_pm_lock();
+ cpu_pm_status |= CPU_PM_DEPD_INIT;
+ plat_cpu_pm_unlock();
+ }
+ }
+
+ if ((cpu_pm_status & CPU_PM_DEPD_INIT) && !(cpu_pm_status & CPU_PM_DEPD_READY)) {
+ status = mtk_lp_depd_condition(CPUPM_MBOX_WAIT_TASK_READY);
+ if (status == 0) {
+ plat_cpu_pm_lock();
+ cpu_pm_status |= CPU_PM_DEPD_READY;
+ plat_cpu_pm_unlock();
+ }
+ }
+
+ ret = ((cpu_pm_status & CPU_PM_INIT_READY) == CPU_PM_INIT_READY) ?
+ MTK_CPUPM_E_OK : MTK_CPUPM_E_FAIL;
+#endif
+ return ret;
+}
+
+static int cpupm_pwr_state_valid(unsigned int afflv, unsigned int state)
+{
+ if (cpu_pm_status == CPU_PM_LP_READY) {
+ return MTK_CPUPM_E_OK;
+ }
+
+ if (cpupm_init() != MTK_CPUPM_E_OK) {
+ return MTK_CPUPM_E_FAIL;
+ }
+
+ if (read_cntpct_el0() >= (uint64_t)CPUPM_BOOTUP_TIME_THR) {
+ plat_cpu_pm_lock();
+ cpu_pm_status |= CPU_PM_PLAT_READY;
+ plat_cpu_pm_unlock();
+ }
+
+ if (!IS_PLAT_SYSTEM_SUSPEND(afflv) && (cpu_pm_status & CPU_PM_PLAT_READY) == 0) {
+ return MTK_CPUPM_E_FAIL;
+ }
+
+ return MTK_CPUPM_E_OK;
+}
+
+static struct mtk_cpu_pm_ops cpcv3_2_mcdi = {
+ .get_pstate = cpupm_get_pstate,
+ .pwr_state_valid = cpupm_pwr_state_valid,
+ .cpu_resume = cpupm_cpu_resume,
+ .mcusys_suspend = cpupm_mcusys_suspend,
+ .mcusys_resume = cpupm_mcusys_resume,
+};
+#endif /* CONFIG_MTK_CPU_SUSPEND_EN */
+
+#endif /* CONFIG_MTK_PM_SUPPORT */
+
+/*
+ * Depend on mtk pm methodology, the psci op init must
+ * be invoked after cpu pm to avoid initialization fail.
+ */
+int mt_plat_cpu_pm_init(void)
+{
+ plat_cpu_pm_lock_init();
+
+ mtk_cpc_init();
+#if CONFIG_MTK_PM_SUPPORT
+
+#if CONFIG_MTK_CPU_SUSPEND_EN
+ register_cpu_pm_ops(CPU_PM_FN, &cpcv3_2_mcdi);
+#endif /* CONFIG_MTK_CPU_SUSPEND_EN */
+
+#if CONFIG_MTK_SMP_EN
+ register_cpu_smp_ops(CPU_PM_FN, &cpcv3_2_cpu_smp);
+#endif /* CONFIG_MTK_SMP_EN */
+
+#endif /* CONFIG_MTK_PM_SUPPORT */
+
+ INFO("[%s:%d] - CPU PM INIT finished\n", __func__, __LINE__);
+ return 0;
+}
+MTK_ARCH_INIT(mt_plat_cpu_pm_init);
+
+static const mmap_region_t cpu_pm_mmap[] MTK_MMAP_SECTION = {
+#ifdef CPU_PM_TINYSYS_SUPPORT
+#if CONFIG_MTK_PM_SUPPORT && CONFIG_MTK_CPU_SUSPEND_EN
+ MAP_REGION_FLAT(CPU_EB_TCM_BASE, CPU_EB_TCM_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+#endif
+#endif
+ {0}
+};
+DECLARE_MTK_MMAP_REGIONS(cpu_pm_mmap);
diff --git a/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm.h b/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm.h
new file mode 100644
index 0000000..4d99df1
--- /dev/null
+++ b/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_CPU_PM_H
+#define MT_CPU_PM_H
+
+#include <assert.h>
+#include <mcucfg.h>
+#include <platform_def.h>
+
+/*
+ * After ARM v8.2, the cache will turn off automatically when powering down CPU. Therefore, there
+ * is no doubt to use the spin_lock here.
+ */
+#if !HW_ASSISTED_COHERENCY
+#define MT_CPU_PM_USING_BAKERY_LOCK
+#endif
+
+#define CPU_PM_FN (MTK_CPUPM_FN_CPUPM_GET_PWR_STATE | \
+ MTK_CPUPM_FN_PWR_STATE_VALID | \
+ MTK_CPUPM_FN_PWR_ON_CORE_PREPARE | \
+ MTK_CPUPM_FN_RESUME_CORE | \
+ MTK_CPUPM_FN_SUSPEND_MCUSYS | \
+ MTK_CPUPM_FN_RESUME_MCUSYS | \
+ MTK_CPUPM_FN_SMP_INIT | \
+ MTK_CPUPM_FN_SMP_CORE_ON | \
+ MTK_CPUPM_FN_SMP_CORE_OFF)
+
+#define CPU_PM_ASSERT(_cond) ({ \
+ if (!(_cond)) { \
+ INFO("[%s:%d] - %s\n", __func__, __LINE__, #_cond); \
+ panic(); \
+ } })
+
+#define CPC_PWR_MASK_MCUSYS_MP0 (0xC001)
+
+#define PER_CPU_PWR_DATA(ctrl, cluster, core) \
+ do { \
+ ctrl.rvbaraddr_l = CORE_RVBRADDR_##cluster##_##core##_L; \
+ ctrl.arch_addr = MCUCFG_MP0_CLUSTER_CFG5; \
+ ctrl.pwpr = SPM_MP##cluster##_CPU##core##_PWR_CON; \
+ } while (0)
+
+#define PER_CPU_PWR_CTRL(ctrl, cpu) ({ \
+ switch (cpu) { \
+ case 0: \
+ PER_CPU_PWR_DATA(ctrl, 0, 0); \
+ break; \
+ case 1: \
+ PER_CPU_PWR_DATA(ctrl, 0, 1); \
+ break; \
+ case 2: \
+ PER_CPU_PWR_DATA(ctrl, 0, 2); \
+ break; \
+ case 3: \
+ PER_CPU_PWR_DATA(ctrl, 0, 3); \
+ break; \
+ case 4: \
+ PER_CPU_PWR_DATA(ctrl, 0, 4); \
+ break; \
+ case 5: \
+ PER_CPU_PWR_DATA(ctrl, 0, 5); \
+ break; \
+ case 6: \
+ PER_CPU_PWR_DATA(ctrl, 0, 6); \
+ break; \
+ case 7: \
+ PER_CPU_PWR_DATA(ctrl, 0, 7); \
+ break; \
+ default: \
+ assert(0); \
+ break; \
+ } })
+
+
+/* MCUSYS DREQ BIG VPROC ISO control */
+#define DREQ20_BIG_VPROC_ISO (MCUCFG_BASE + 0xad8c)
+
+/* Definition about bootup address for each core CORE_RVBRADDR_clusterid_cpuid */
+#define CORE_RVBRADDR_0_0_L (MCUCFG_BASE + 0xc900)
+#define CORE_RVBRADDR_0_1_L (MCUCFG_BASE + 0xc908)
+#define CORE_RVBRADDR_0_2_L (MCUCFG_BASE + 0xc910)
+#define CORE_RVBRADDR_0_3_L (MCUCFG_BASE + 0xc918)
+#define CORE_RVBRADDR_0_4_L (MCUCFG_BASE + 0xc920)
+#define CORE_RVBRADDR_0_5_L (MCUCFG_BASE + 0xc928)
+#define CORE_RVBRADDR_0_6_L (MCUCFG_BASE + 0xc930)
+#define CORE_RVBRADDR_0_7_L (MCUCFG_BASE + 0xc938)
+#define MCUCFG_MP0_CLUSTER_CFG5 (MCUCFG_BASE + 0xc8e4)
+
+struct cpu_pwr_ctrl {
+ unsigned int rvbaraddr_l;
+ unsigned int arch_addr;
+ unsigned int pwpr;
+};
+
+#define MCUSYS_STATUS_PDN BIT(0)
+#define MCUSYS_STATUS_CPUSYS_PROTECT BIT(8)
+#define MCUSYS_STATUS_MCUSYS_PROTECT BIT(9)
+
+/* cpu_pm function ID */
+enum mt_cpu_pm_user_id {
+ MCUSYS_STATUS,
+ CPC_COMMAND,
+};
+
+/* cpu_pm lp function ID */
+enum mt_cpu_pm_lp_smc_id {
+ LP_CPC_COMMAND,
+ IRQS_REMAIN_ALLOC,
+ IRQS_REMAIN_CTRL,
+ IRQS_REMAIN_IRQ,
+ IRQS_REMAIN_WAKEUP_CAT,
+ IRQS_REMAIN_WAKEUP_SRC,
+};
+
+#endif /* MT_CPU_PM_H */
diff --git a/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm_cpc.c b/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm_cpc.c
new file mode 100644
index 0000000..4cc2203
--- /dev/null
+++ b/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm_cpc.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <drivers/delay_timer.h>
+
+#include "mt_cpu_pm.h"
+#include "mt_cpu_pm_cpc.h"
+#include "mt_smp.h"
+#include <mt_timer.h>
+
+struct mtk_cpc_dev {
+ int auto_off;
+ unsigned int auto_thres_tick;
+};
+
+static struct mtk_cpc_dev cpc;
+
+static int mtk_cpc_last_core_prot(int prot_req, int resp_reg, int resp_ofs)
+{
+ unsigned int staus;
+ unsigned int retry = 0;
+
+ while (retry < RETRY_CNT_MAX) {
+ retry++;
+
+ mmio_write_32(CPC_MCUSYS_LAST_CORE_REQ, prot_req);
+
+ udelay(1);
+
+ staus = (mmio_read_32(resp_reg) >> resp_ofs) & CPC_PROT_RESP_MASK;
+
+ if (staus == PROT_SUCCESS) {
+ return CPC_SUCCESS;
+ } else if (staus == PROT_GIVEUP) {
+ return CPC_ERR_FAIL;
+ }
+ }
+
+ return CPC_ERR_TIMEOUT;
+}
+
+static int mtk_cpu_pm_mcusys_prot_aquire(void)
+{
+ return mtk_cpc_last_core_prot(MCUSYS_PROT_SET, CPC_MCUSYS_LAST_CORE_RESP, MCUSYS_RESP_OFS);
+}
+
+static void mtk_cpu_pm_mcusys_prot_release(void)
+{
+ mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, MCUSYS_PROT_CLR);
+}
+
+int mtk_cpu_pm_cluster_prot_aquire(void)
+{
+ return mtk_cpc_last_core_prot(CPUSYS_PROT_SET, CPC_MCUSYS_MP_LAST_CORE_RESP,
+ CPUSYS_RESP_OFS);
+}
+
+void mtk_cpu_pm_cluster_prot_release(void)
+{
+ mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, CPUSYS_PROT_CLR);
+}
+
+static void mtk_cpc_cluster_cnt_backup(void)
+{
+ /* single cluster */
+ uint32_t backup_cnt = mmio_read_32(CPC_CLUSTER_CNT_BACKUP);
+ uint32_t curr_cnt = mmio_read_32(CPC_MCUSYS_CLUSTER_COUNTER);
+
+ if ((curr_cnt & 0x7fff) == 0) {
+ curr_cnt = (curr_cnt >> 16) & 0x7fff;
+ } else {
+ curr_cnt = curr_cnt & 0x7fff;
+ }
+
+ mmio_write_32(CPC_CLUSTER_CNT_BACKUP, backup_cnt + curr_cnt);
+ mmio_write_32(CPC_MCUSYS_CLUSTER_COUNTER_CLR, 0x3);
+}
+
+static inline void mtk_cpc_mcusys_off_enable(bool enable)
+{
+ mmio_write_32(CPC_MCUSYS_PWR_CTRL, enable ? 1 : 0);
+}
+
+void mtk_cpc_mcusys_off_reflect(void)
+{
+ mtk_cpc_mcusys_off_enable(false);
+ mtk_cpu_pm_mcusys_prot_release();
+}
+
+int mtk_cpc_mcusys_off_prepare(void)
+{
+ if (mtk_cpu_pm_mcusys_prot_aquire() != CPC_SUCCESS) {
+ return CPC_ERR_FAIL;
+ }
+
+ mtk_cpc_cluster_cnt_backup();
+ mtk_cpc_mcusys_off_enable(true);
+
+ return CPC_SUCCESS;
+}
+
+void mtk_cpc_core_on_hint_set(int cpu)
+{
+ mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_SET, BIT(cpu));
+}
+
+void mtk_cpc_core_on_hint_clr(int cpu)
+{
+ mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_CLR, BIT(cpu));
+}
+
+static void mtk_cpc_dump_timestamp(void)
+{
+ unsigned int id;
+
+ for (id = 0; id < CPC_TRACE_ID_NUM; id++) {
+ mmio_write_32(CPC_MCUSYS_TRACE_SEL, id);
+
+ memcpy((void *)(uintptr_t)CPC_TRACE_SRAM(id),
+ (const void *)(uintptr_t)CPC_MCUSYS_TRACE_DATA,
+ CPC_TRACE_SIZE);
+ }
+}
+
+void mtk_cpc_time_sync(void)
+{
+ uint64_t kt;
+ uint32_t systime_l, systime_h;
+
+ kt = sched_clock();
+ systime_l = mmio_read_32(CNTSYS_L_REG);
+ systime_h = mmio_read_32(CNTSYS_H_REG);
+
+ /* sync kernel timer to cpc */
+ mmio_write_32(CPC_MCUSYS_CPC_KERNEL_TIME_L_BASE, (uint32_t)kt);
+ mmio_write_32(CPC_MCUSYS_CPC_KERNEL_TIME_H_BASE, (uint32_t)(kt >> 32));
+
+ /* sync system timer to cpc */
+ mmio_write_32(CPC_MCUSYS_CPC_SYSTEM_TIME_L_BASE, systime_l);
+ mmio_write_32(CPC_MCUSYS_CPC_SYSTEM_TIME_H_BASE, systime_h);
+}
+
+static void mtk_cpc_config(unsigned int cfg, unsigned int data)
+{
+ switch (cfg) {
+ case CPC_SMC_CONFIG_PROF:
+ if (data) {
+ mmio_setbits_32(CPC_MCUSYS_CPC_DBG_SETTING, CPC_PROF_EN);
+ } else {
+ mmio_clrbits_32(CPC_MCUSYS_CPC_DBG_SETTING, CPC_PROF_EN);
+ }
+ break;
+ case CPC_SMC_CONFIG_AUTO_OFF:
+ if (data) {
+ mmio_setbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG, CPC_AUTO_OFF_EN);
+ cpc.auto_off = 1;
+ } else {
+ mmio_setbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG, CPC_AUTO_OFF_EN);
+ cpc.auto_off = 0;
+ }
+ break;
+ case CPC_SMC_CONFIG_AUTO_OFF_THRES:
+ cpc.auto_thres_tick = US_TO_TICKS(data);
+ mmio_write_32(CPC_MCUSYS_CPC_OFF_THRES, cpc.auto_thres_tick);
+ break;
+ case CPC_SMC_CONFIG_CNT_CLR:
+ mmio_write_32(CPC_MCUSYS_CLUSTER_COUNTER_CLR, 0x3);
+ break;
+ case CPC_SMC_CONFIG_TIME_SYNC:
+ mtk_cpc_time_sync();
+ break;
+ default:
+ break;
+ }
+}
+
+static unsigned int mtk_cpc_read_config(unsigned int cfg)
+{
+ unsigned int res = 0;
+
+ switch (cfg) {
+ case CPC_SMC_CONFIG_PROF:
+ res = (mmio_read_32(CPC_MCUSYS_CPC_DBG_SETTING) & CPC_PROF_EN) ? 1 : 0;
+ break;
+ case CPC_SMC_CONFIG_AUTO_OFF:
+ res = cpc.auto_off;
+ break;
+ case CPC_SMC_CONFIG_AUTO_OFF_THRES:
+ res = TICKS_TO_US(cpc.auto_thres_tick);
+ break;
+ case CPC_SMC_CONFIG_CNT_CLR:
+ default:
+ break;
+ }
+
+ return res;
+}
+
+uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2)
+{
+ uint64_t res = 0;
+
+ switch (act) {
+ case CPC_SMC_EVENT_CPC_CONFIG:
+ mtk_cpc_config((unsigned int)arg1, (unsigned int)arg2);
+ break;
+ case CPC_SMC_EVENT_READ_CONFIG:
+ res = mtk_cpc_read_config((unsigned int)arg1);
+ break;
+ case CPC_SMC_EVENT_GIC_DPG_SET:
+ /* isolated_status = x2; */
+ default:
+ break;
+ }
+
+ return res;
+}
+
+uint64_t mtk_cpc_trace_dump(uint64_t act, uint64_t arg1, uint64_t arg2)
+{
+ switch (act) {
+ case CPC_SMC_EVENT_DUMP_TRACE_DATA:
+ mtk_cpc_dump_timestamp();
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+void mtk_cpc_init(void)
+{
+#if CONFIG_MTK_SMP_EN
+ mt_smp_init();
+#endif
+ mmio_setbits_32(CPC_MCUSYS_CPC_DBG_SETTING, (CPC_DBG_EN | CPC_CALC_EN));
+
+ cpc.auto_off = 1;
+ mmio_setbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG, (CPC_OFF_PRE_EN |
+ ((cpc.auto_off > 0) ? CPC_AUTO_OFF_EN : 0)));
+
+ mtk_cpc_config(CPC_SMC_CONFIG_AUTO_OFF_THRES, 8000);
+
+ /* enable CPC */
+ mmio_setbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG, CPC_CTRL_ENABLE);
+ mmio_setbits_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG, SSPM_CORE_PWR_ON_EN);
+}
diff --git a/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm_cpc.h b/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm_cpc.h
new file mode 100644
index 0000000..3004f41
--- /dev/null
+++ b/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm_cpc.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_CPU_PM_CPC_H
+#define MT_CPU_PM_CPC_H
+
+#include <lib/mmio.h>
+
+#include <mcucfg.h>
+#include <platform_def.h>
+
+#define NEED_CPUSYS_PROT_WORKAROUND (1)
+
+/* system sram registers */
+#define CPUIDLE_SRAM_REG(r) (CPU_IDLE_SRAM_BASE + (r))
+
+/* db dump */
+#define CPC_TRACE_SIZE (0x20)
+#define CPC_TRACE_ID_NUM (10)
+#define CPC_TRACE_SRAM(id) (CPUIDLE_SRAM_REG(0x10) + (id) * CPC_TRACE_SIZE)
+
+/* buckup off count */
+#define CPC_CLUSTER_CNT_BACKUP CPUIDLE_SRAM_REG(0x1f0)
+#define CPC_MCUSYS_CNT CPUIDLE_SRAM_REG(0x1f4)
+
+/* CPC_MCUSYS_CPC_FLOW_CTRL_CFG (0xA814): debug setting */
+#define CPC_PWR_ON_SEQ_DIS BIT(1)
+#define CPC_PWR_ON_PRIORITY BIT(2)
+#define CPC_AUTO_OFF_EN BIT(5)
+#define CPC_DORMANT_WAIT_EN BIT(14)
+#define CPC_CTRL_EN BIT(16)
+#define CPC_OFF_PRE_EN BIT(29)
+
+/* CPC_MCUSYS_LAST_CORE_REQ (0xA818) : last core protection */
+#define CPUSYS_PROT_SET BIT(0)
+#define MCUSYS_PROT_SET BIT(8)
+#define CPUSYS_PROT_CLR BIT(8)
+#define MCUSYS_PROT_CLR BIT(9)
+
+#define CPC_PROT_RESP_MASK (0x3)
+#define CPUSYS_RESP_OFS (16)
+#define MCUSYS_RESP_OFS (30)
+
+#define RETRY_CNT_MAX (1000)
+
+#define PROT_RETRY (0)
+#define PROT_SUCCESS (1)
+#define PROT_GIVEUP (2)
+
+/* CPC_MCUSYS_CPC_DBG_SETTING (0xAB00): debug setting */
+#define CPC_PROF_EN BIT(0)
+#define CPC_DBG_EN BIT(1)
+#define CPC_FREEZE BIT(2)
+#define CPC_CALC_EN BIT(3)
+
+enum mcusys_cpc_lastcore_prot_status {
+ CPC_SUCCESS = 0,
+ CPC_ERR_FAIL,
+ CPC_ERR_TIMEOUT,
+ NF_CPC_ERR,
+};
+
+enum mcusys_cpc_smc_events {
+ CPC_SMC_EVENT_DUMP_TRACE_DATA,
+ CPC_SMC_EVENT_GIC_DPG_SET,
+ CPC_SMC_EVENT_CPC_CONFIG,
+ CPC_SMC_EVENT_READ_CONFIG,
+ NF_CPC_SMC_EVENT,
+};
+
+enum mcusys_cpc_smc_config {
+ CPC_SMC_CONFIG_PROF,
+ CPC_SMC_CONFIG_AUTO_OFF,
+ CPC_SMC_CONFIG_AUTO_OFF_THRES,
+ CPC_SMC_CONFIG_CNT_CLR,
+ CPC_SMC_CONFIG_TIME_SYNC,
+ NF_CPC_SMC_CONFIG,
+};
+
+#define US_TO_TICKS(us) ((us) * 13)
+#define TICKS_TO_US(tick) ((tick) / 13)
+
+int mtk_cpu_pm_cluster_prot_aquire(void);
+void mtk_cpu_pm_cluster_prot_release(void);
+
+void mtk_cpc_mcusys_off_reflect(void);
+int mtk_cpc_mcusys_off_prepare(void);
+
+void mtk_cpc_core_on_hint_set(int cpu);
+void mtk_cpc_core_on_hint_clr(int cpu);
+void mtk_cpc_time_sync(void);
+
+uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2);
+uint64_t mtk_cpc_trace_dump(uint64_t act, uint64_t arg1, uint64_t arg2);
+void mtk_cpc_init(void);
+
+#endif /* MT_CPU_PM_CPC_H */
diff --git a/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm_mbox.c b/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm_mbox.c
new file mode 100644
index 0000000..4d67e7b
--- /dev/null
+++ b/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm_mbox.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <lib/mmio.h>
+
+#include "mt_cpu_pm_mbox.h"
+#include <platform_def.h>
+
+#ifdef __GNUC__
+#define MCDI_LIKELY(x) __builtin_expect(!!(x), 1)
+#define MCDI_UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+#define MCDI_LIKELY(x) (x)
+#define MCDI_UNLIKELY(x) (x)
+#endif
+
+#define MCUPM_MBOX_3_BASE (CPU_EB_TCM_BASE + CPU_EB_MBOX3_OFFSET)
+#define MCUPM_MBOX_WRITE(id, val) mmio_write_32(MCUPM_MBOX_3_BASE + 4 * (id), val)
+#define MCUPM_MBOX_READ(id) mmio_read_32(MCUPM_MBOX_3_BASE + 4 * (id))
+
+void mtk_set_mcupm_pll_mode(unsigned int mode)
+{
+ if (mode < NF_MCUPM_ARMPLL_MODE) {
+ MCUPM_MBOX_WRITE(MCUPM_MBOX_ARMPLL_MODE, mode);
+ }
+}
+
+int mtk_get_mcupm_pll_mode(void)
+{
+ return MCUPM_MBOX_READ(MCUPM_MBOX_ARMPLL_MODE);
+}
+
+void mtk_set_mcupm_buck_mode(unsigned int mode)
+{
+ if (mode < NF_MCUPM_BUCK_MODE) {
+ MCUPM_MBOX_WRITE(MCUPM_MBOX_BUCK_MODE, mode);
+ }
+}
+
+int mtk_get_mcupm_buck_mode(void)
+{
+ return MCUPM_MBOX_READ(MCUPM_MBOX_BUCK_MODE);
+}
+
+void mtk_set_cpu_pm_preffered_cpu(unsigned int cpuid)
+{
+ return MCUPM_MBOX_WRITE(MCUPM_MBOX_WAKEUP_CPU, cpuid);
+}
+
+unsigned int mtk_get_cpu_pm_preffered_cpu(void)
+{
+ return MCUPM_MBOX_READ(MCUPM_MBOX_WAKEUP_CPU);
+}
+
+static int mtk_wait_mbox_init_done(void)
+{
+ int status = MCUPM_MBOX_READ(MCUPM_MBOX_TASK_STA);
+
+ if (status != MCUPM_TASK_INIT) {
+ return status;
+ }
+
+ mtk_set_mcupm_pll_mode(MCUPM_ARMPLL_OFF);
+ mtk_set_mcupm_buck_mode(MCUPM_BUCK_OFF_MODE);
+
+ MCUPM_MBOX_WRITE(MCUPM_MBOX_PWR_CTRL_EN, (MCUPM_MCUSYS_CTRL | MCUPM_CM_CTRL |
+ MCUPM_BUCK_CTRL | MCUPM_ARMPLL_CTRL));
+
+ return status;
+}
+
+int mtk_lp_depd_condition(enum cpupm_mbox_depd_type type)
+{
+ int status;
+
+ if (type == CPUPM_MBOX_WAIT_DEV_INIT) {
+ status = mtk_wait_mbox_init_done();
+ if (MCDI_UNLIKELY(status != MCUPM_TASK_INIT)) {
+ return -ENXIO;
+ }
+ MCUPM_MBOX_WRITE(MCUPM_MBOX_AP_READY, 1);
+ } else if (type == CPUPM_MBOX_WAIT_TASK_READY) {
+ status = MCUPM_MBOX_READ(MCUPM_MBOX_TASK_STA);
+ if (MCDI_UNLIKELY((status != MCUPM_TASK_WAIT) &&
+ (status != MCUPM_TASK_INIT_FINISH))) {
+ return -ENXIO;
+ }
+ }
+ return 0;
+}
diff --git a/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm_mbox.h b/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm_mbox.h
new file mode 100644
index 0000000..72be6bd
--- /dev/null
+++ b/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_cpu_pm_mbox.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_CPU_PM_MBOX_H
+#define MT_CPU_PM_MBOX_H
+
+#include <lib/utils_def.h>
+
+/* MCUPM Mbox */
+/* AP Write */
+#define MCUPM_MBOX_AP_READY (0)
+#define MCUPM_MBOX_RESERVED_1 (1)
+#define MCUPM_MBOX_RESERVED_2 (2)
+#define MCUPM_MBOX_RESERVED_3 (3)
+#define MCUPM_MBOX_PWR_CTRL_EN (4)
+#define MCUPM_MBOX_L3_CACHE_MODE (5)
+#define MCUPM_MBOX_BUCK_MODE (6)
+#define MCUPM_MBOX_ARMPLL_MODE (7)
+/* AP Read */
+#define MCUPM_MBOX_TASK_STA (8)
+#define MCUPM_MBOX_RESERVED_9 (9)
+#define MCUPM_MBOX_RESERVED_10 (10)
+#define MCUPM_MBOX_RESERVED_11 (11)
+#define MCUPM_MBOX_WAKEUP_CPU (12)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_PWR_CTRL_EN (4) */
+#define MCUPM_MCUSYS_CTRL BIT(0)
+#define MCUPM_BUCK_CTRL BIT(1)
+#define MCUPM_ARMPLL_CTRL BIT(2)
+#define MCUPM_CM_CTRL BIT(3)
+#define MCUPM_PWR_CTRL_MASK (BIT(3) - 1)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_L3_CACHE_MODE (5) */
+#define MCUPM_L3_OFF_MODE (0) /* default */
+#define MCUPM_L3_DORMANT_MODE (1)
+#define NF_MCUPM_L3_MODE (2)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_BUCK_MODE (6) */
+#define MCUPM_BUCK_NORMAL_MODE (0) /* default */
+#define MCUPM_BUCK_LP_MODE (1)
+#define MCUPM_BUCK_OFF_MODE (2)
+#define NF_MCUPM_BUCK_MODE (3)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_ARMPLL_MODE (7) */
+#define MCUPM_ARMPLL_ON (0) /* default */
+#define MCUPM_ARMPLL_GATING (1)
+#define MCUPM_ARMPLL_OFF (2)
+#define NF_MCUPM_ARMPLL_MODE (3)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_TASK_STA (9) */
+#define MCUPM_TASK_UNINIT (0)
+#define MCUPM_TASK_INIT (1)
+#define MCUPM_TASK_INIT_FINISH (2)
+#define MCUPM_TASK_WAIT (3)
+#define MCUPM_TASK_RUN (4)
+#define MCUPM_TASK_PAUSE (5)
+
+
+void mtk_set_mcupm_pll_mode(unsigned int mode);
+int mtk_get_mcupm_pll_mode(void);
+
+void mtk_set_mcupm_buck_mode(unsigned int mode);
+int mtk_get_mcupm_buck_mode(void);
+
+void mtk_set_cpu_pm_preffered_cpu(unsigned int cpuid);
+unsigned int mtk_get_cpu_pm_preffered_cpu(void);
+
+enum cpupm_mbox_depd_type {
+ CPUPM_MBOX_WAIT_DEV_INIT,
+ CPUPM_MBOX_WAIT_TASK_READY,
+};
+
+int mtk_lp_depd_condition(enum cpupm_mbox_depd_type type);
+
+#endif /* MT_CPU_PM_MBOX_H */
diff --git a/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_smp.c b/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_smp.c
new file mode 100644
index 0000000..a1d9c31
--- /dev/null
+++ b/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_smp.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <plat/common/platform.h>
+
+#include <lib/pm/mtk_pm.h>
+#include <mcucfg.h>
+#include "mt_cpu_pm.h"
+#include "mt_smp.h"
+
+static inline int is_core_power_status_on(unsigned int cpuid)
+{
+ return !!(mmio_read_32(CPU_PWR_STATUS) & BIT(cpuid));
+}
+
+void mt_smp_core_init_arch(unsigned int cluster, unsigned int cpu, int arm64,
+ struct cpu_pwr_ctrl *pwr_ctrl)
+{
+ CPU_PM_ASSERT(cluster == 0);
+ CPU_PM_ASSERT(pwr_ctrl != NULL);
+
+ /* aa64naa32 in bits[16:23] */
+ if (arm64 != 0) {
+ mmio_setbits_32(pwr_ctrl->arch_addr, 1 << (16 + cpu));
+ } else {
+ mmio_clrbits_32(pwr_ctrl->arch_addr, 1 << (16 + cpu));
+ }
+}
+
+void mt_smp_core_bootup_address_set(struct cpu_pwr_ctrl *pwr_ctrl, uintptr_t entry)
+{
+ CPU_PM_ASSERT(pwr_ctrl != NULL);
+
+ /* Set bootup address */
+ mmio_write_32(pwr_ctrl->rvbaraddr_l, entry);
+}
+
+int mt_smp_power_core_on(unsigned int cpu_id, struct cpu_pwr_ctrl *pwr_ctrl)
+{
+ unsigned int val = is_core_power_status_on(cpu_id);
+
+ CPU_PM_ASSERT(pwr_ctrl);
+
+ mmio_clrbits_32(pwr_ctrl->pwpr, RESETPWRON_CONFIG);
+ if (val == 0) {
+ /*
+ * Set to 0 after BIG VPROC bulk powered on (configure in MCUPM) and
+ * before big core power-on sequence.
+ */
+ if (cpu_id >= PLAT_CPU_PM_B_BUCK_ISO_ID) {
+ mmio_write_32(DREQ20_BIG_VPROC_ISO, 0);
+ }
+
+ mmio_setbits_32(pwr_ctrl->pwpr, PWR_RST_B);
+ dsbsy();
+
+ /* set mp0_spmc_pwr_on_cpuX = 1 */
+ mmio_setbits_32(pwr_ctrl->pwpr, PWR_ON);
+
+ val = 0;
+ while (is_core_power_status_on(cpu_id) == 0) {
+ DO_SMP_CORE_ON_WAIT_TIMEOUT(val);
+ mmio_clrbits_32(pwr_ctrl->pwpr, PWR_ON);
+ mmio_setbits_32(pwr_ctrl->pwpr, PWR_ON);
+ }
+ } else {
+ INFO("[%s:%d] - core_%u haven been power on\n", __func__, __LINE__, cpu_id);
+ }
+
+ return MTK_CPUPM_E_OK;
+}
+
+int mt_smp_power_core_off(struct cpu_pwr_ctrl *pwr_ctrl)
+{
+ /* set mp0_spmc_pwr_on_cpuX = 1 */
+ mmio_clrbits_32(pwr_ctrl->pwpr, PWR_ON);
+ return MTK_CPUPM_E_OK;
+}
+
+void mt_smp_init(void)
+{
+ /* clear RESETPWRON_CONFIG of mcusys/cluster/core0 */
+ mmio_clrbits_32(SPM_MCUSYS_PWR_CON, RESETPWRON_CONFIG);
+ mmio_clrbits_32(SPM_MP0_CPUTOP_PWR_CON, RESETPWRON_CONFIG);
+}
diff --git a/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_smp.h b/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_smp.h
new file mode 100644
index 0000000..4c2f8d2
--- /dev/null
+++ b/plat/mediatek/drivers/cpu_pm/cpcv3_2/mt_smp.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SMP_H
+#define MT_SMP_H
+
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#define CPU_PWR_STATUS (MCUCFG_BASE + 0xA840)
+
+#define SMP_CORE_TIMEOUT_MAX (50000)
+#define DO_SMP_CORE_ON_WAIT_TIMEOUT(k_cnt) ({ \
+ CPU_PM_ASSERT(k_cnt < SMP_CORE_TIMEOUT_MAX); \
+ k_cnt++; udelay(1); })
+
+void mt_smp_core_init_arch(unsigned int cluster, unsigned int cpu, int arm64,
+ struct cpu_pwr_ctrl *pwr_ctrl);
+void mt_smp_core_bootup_address_set(struct cpu_pwr_ctrl *pwr_ctrl, uintptr_t entry);
+int mt_smp_power_core_on(unsigned int cpu_id, struct cpu_pwr_ctrl *pwr_ctrl);
+int mt_smp_power_core_off(struct cpu_pwr_ctrl *pwr_ctrl);
+void mt_smp_init(void);
+
+#endif /* MT_SMP_H */
diff --git a/plat/mediatek/drivers/cpu_pm/cpcv3_2/rules.mk b/plat/mediatek/drivers/cpu_pm/cpcv3_2/rules.mk
new file mode 100644
index 0000000..858cf38
--- /dev/null
+++ b/plat/mediatek/drivers/cpu_pm/cpcv3_2/rules.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := cpcv${CONFIG_MTK_CPU_PM_ARCH}
+
+LOCAL_SRCS-y := ${LOCAL_DIR}/mt_cpu_pm.c ${LOCAL_DIR}/mt_cpu_pm_cpc.c
+
+LOCAL_SRCS-$(CPU_PM_TINYSYS_SUPPORT) += ${LOCAL_DIR}/mt_cpu_pm_mbox.c
+LOCAL_SRCS-$(CONFIG_MTK_SMP_EN) += ${LOCAL_DIR}/mt_smp.c
+
+$(eval $(call add_defined_option,CPU_PM_TINYSYS_SUPPORT))
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
+
diff --git a/plat/mediatek/drivers/cpu_pm/rules.mk b/plat/mediatek/drivers/cpu_pm/rules.mk
new file mode 100644
index 0000000..8df4f21
--- /dev/null
+++ b/plat/mediatek/drivers/cpu_pm/rules.mk
@@ -0,0 +1,13 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := cpu_pm
+
+SUB_RULES-${CONFIG_MTK_CPU_PM_SUPPORT} := $(LOCAL_DIR)/cpcv${CONFIG_MTK_CPU_PM_ARCH}
+
+$(eval $(call INCLUDE_MAKEFILE,$(SUB_RULES-y)))
diff --git a/plat/mediatek/drivers/dcm/mt8188/mtk_dcm_utils.c b/plat/mediatek/drivers/dcm/mt8188/mtk_dcm_utils.c
new file mode 100644
index 0000000..c054de9
--- /dev/null
+++ b/plat/mediatek/drivers/dcm/mt8188/mtk_dcm_utils.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <mtk_dcm_utils.h>
+
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_MASK BIT(17)
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_MASK (BIT(15) | BIT(16) | BIT(17) | \
+ BIT(18) | BIT(21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG2_MASK (BIT(15) | BIT(16) | BIT(17) | BIT(18))
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_ON BIT(17)
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_ON (BIT(15) | BIT(16) | BIT(17) | \
+ BIT(18) | BIT(21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG2_ON (BIT(15) | BIT(16) | BIT(17) | BIT(18))
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_OFF (0x0 << 17)
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_OFF ((0x0 << 15) | (0x0 << 16) | \
+ (0x0 << 17) | (0x0 << 18) | \
+ (0x0 << 21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG2_OFF ((0x0 << 15) | (0x0 << 16) | \
+ (0x0 << 17) | (0x0 << 18))
+
+bool dcm_mp_cpusys_top_adb_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= dcm_check_state(MP_CPUSYS_TOP_MP_ADB_DCM_CFG0,
+ MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG0_ON);
+ ret &= dcm_check_state(MP_CPUSYS_TOP_MP_ADB_DCM_CFG4,
+ MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG1_ON);
+ ret &= dcm_check_state(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+ MP_CPUSYS_TOP_ADB_DCM_REG2_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG2_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_adb_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_adb_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG0,
+ MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG0_ON);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG4,
+ MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG1_ON);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+ MP_CPUSYS_TOP_ADB_DCM_REG2_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG2_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_adb_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG0,
+ MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG0_OFF);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG4,
+ MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG1_OFF);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+ MP_CPUSYS_TOP_ADB_DCM_REG2_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG2_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_APB_DCM_REG0_MASK BIT(5)
+#define MP_CPUSYS_TOP_APB_DCM_REG1_MASK BIT(8)
+#define MP_CPUSYS_TOP_APB_DCM_REG2_MASK BIT(16)
+#define MP_CPUSYS_TOP_APB_DCM_REG0_ON BIT(5)
+#define MP_CPUSYS_TOP_APB_DCM_REG1_ON BIT(8)
+#define MP_CPUSYS_TOP_APB_DCM_REG2_ON BIT(16)
+#define MP_CPUSYS_TOP_APB_DCM_REG0_OFF (0x0 << 5)
+#define MP_CPUSYS_TOP_APB_DCM_REG1_OFF (0x0 << 8)
+#define MP_CPUSYS_TOP_APB_DCM_REG2_OFF (0x0 << 16)
+
+bool dcm_mp_cpusys_top_apb_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= dcm_check_state(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG0_ON);
+ ret &= dcm_check_state(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG1_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG1_ON);
+ ret &= dcm_check_state(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG2_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG2_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_apb_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_apb_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG0_ON);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG1_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG1_ON);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG2_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG2_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_apb_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG0_OFF);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG1_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG1_OFF);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG2_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG2_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK (BIT(11) | BIT(24) | BIT(25))
+#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON (BIT(11) | BIT(24) | BIT(25))
+#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_OFF ((0x0 << 11) | \
+ (0x0 << 24) | \
+ (0x0 << 25))
+
+bool dcm_mp_cpusys_top_bus_pll_div_dcm_is_on(void)
+{
+ return dcm_check_state(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON);
+}
+
+void dcm_mp_cpusys_top_bus_pll_div_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_bus_pll_div_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_bus_pll_div_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK BIT(0)
+#define MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON BIT(0)
+#define MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_OFF (0x0 << 0)
+
+bool dcm_mp_cpusys_top_core_stall_dcm_is_on(void)
+{
+ return dcm_check_state(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON);
+}
+
+void dcm_mp_cpusys_top_core_stall_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_core_stall_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_core_stall_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK (0xffff << 0)
+#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON (0xffff << 0)
+#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_OFF (0x0 << 0)
+
+bool dcm_mp_cpusys_top_cpubiu_dcm_is_on(void)
+{
+ return dcm_check_state(MP_CPUSYS_TOP_MCSIC_DCM0,
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON);
+}
+
+void dcm_mp_cpusys_top_cpubiu_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpubiu_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCSIC_DCM0,
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpubiu_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCSIC_DCM0,
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK (BIT(24) | BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON (BIT(24) | BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_OFF ((0x0 << 24) | (0x0 << 25))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on(void)
+{
+ return dcm_check_state(MP_CPUSYS_TOP_CPU_PLLDIV_CFG0,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON);
+}
+
+void dcm_mp_cpusys_top_cpu_pll_div_0_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_0_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG0,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_0_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG0,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK (BIT(24) | BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON (BIT(24) | BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_OFF ((0x0 << 24) | (0x0 << 25))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on(void)
+{
+ return dcm_check_state(MP_CPUSYS_TOP_CPU_PLLDIV_CFG1,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON);
+}
+
+void dcm_mp_cpusys_top_cpu_pll_div_1_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_1_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG1,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_1_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG1,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK BIT(4)
+#define MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON BIT(4)
+#define MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_OFF (0x0 << 4)
+
+bool dcm_mp_cpusys_top_fcm_stall_dcm_is_on(void)
+{
+ return dcm_check_state(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON);
+}
+
+void dcm_mp_cpusys_top_fcm_stall_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_fcm_stall_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_fcm_stall_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK BIT(31)
+#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON BIT(31)
+#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_OFF (0x0U << 31)
+
+bool dcm_mp_cpusys_top_last_cor_idle_dcm_is_on(void)
+{
+ return dcm_check_state(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON);
+}
+
+void dcm_mp_cpusys_top_last_cor_idle_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_last_cor_idle_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_last_cor_idle_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_MASK (BIT(1) | BIT(4))
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_ON (BIT(1) | BIT(4))
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_OFF ((0x0 << 1) | (0x0 << 4))
+
+bool dcm_mp_cpusys_top_misc_dcm_is_on(void)
+{
+ return dcm_check_state(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_MISC_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_MISC_DCM_REG0_ON);
+}
+
+void dcm_mp_cpusys_top_misc_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_misc_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_MISC_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_MISC_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_misc_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_MISC_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_MISC_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK BIT(3)
+#define MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_ON BIT(3)
+#define MP_CPUSYS_TOP_MP0_QDCM_REG1_ON (BIT(0) | BIT(1) | BIT(2) | BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_OFF ((0x0 << 3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG1_OFF ((0x0 << 0) | (0x0 << 1) | \
+ (0x0 << 2) | (0x0 << 3))
+
+bool dcm_mp_cpusys_top_mp0_qdcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= dcm_check_state(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_ON);
+ ret &= dcm_check_state(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+ MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK,
+ MP_CPUSYS_TOP_MP0_QDCM_REG1_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_mp0_qdcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_mp0_qdcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_ON);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+ MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK,
+ MP_CPUSYS_TOP_MP0_QDCM_REG1_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_mp0_qdcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_OFF);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+ MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK,
+ MP_CPUSYS_TOP_MP0_QDCM_REG1_OFF);
+ }
+}
+
+#define CPCCFG_REG_EMI_WFIFO_REG0_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
+#define CPCCFG_REG_EMI_WFIFO_REG0_ON (BIT(0) | BIT(1) | BIT(2) | BIT(3))
+#define CPCCFG_REG_EMI_WFIFO_REG0_OFF ((0x0 << 0) | (0x0 << 1) | \
+ (0x0 << 2) | (0x0 << 3))
+
+bool dcm_cpccfg_reg_emi_wfifo_is_on(void)
+{
+ return dcm_check_state(CPCCFG_REG_EMI_WFIFO,
+ CPCCFG_REG_EMI_WFIFO_REG0_MASK,
+ CPCCFG_REG_EMI_WFIFO_REG0_ON);
+}
+
+void dcm_cpccfg_reg_emi_wfifo(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'cpccfg_reg_emi_wfifo'" */
+ mmio_clrsetbits_32(CPCCFG_REG_EMI_WFIFO,
+ CPCCFG_REG_EMI_WFIFO_REG0_MASK,
+ CPCCFG_REG_EMI_WFIFO_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'cpccfg_reg_emi_wfifo'" */
+ mmio_clrsetbits_32(CPCCFG_REG_EMI_WFIFO,
+ CPCCFG_REG_EMI_WFIFO_REG0_MASK,
+ CPCCFG_REG_EMI_WFIFO_REG0_OFF);
+ }
+}
diff --git a/plat/mediatek/drivers/dcm/mt8188/mtk_dcm_utils.h b/plat/mediatek/drivers/dcm/mt8188/mtk_dcm_utils.h
new file mode 100644
index 0000000..5d758dd
--- /dev/null
+++ b/plat/mediatek/drivers/dcm/mt8188/mtk_dcm_utils.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_DCM_UTILS_H
+#define MTK_DCM_UTILS_H
+
+#include <stdbool.h>
+
+#include <mtk_dcm.h>
+#include <platform_def.h>
+
+/* Base */
+#define MP_CPUSYS_TOP_BASE (MCUCFG_BASE + 0x8000)
+#define CPCCFG_REG_BASE (MCUCFG_BASE + 0xA800)
+
+/* Register Definition */
+#define CPCCFG_REG_EMI_WFIFO (CPCCFG_REG_BASE + 0x100)
+#define MP_CPUSYS_TOP_CPU_PLLDIV_CFG0 (MP_CPUSYS_TOP_BASE + 0x22a0)
+#define MP_CPUSYS_TOP_CPU_PLLDIV_CFG1 (MP_CPUSYS_TOP_BASE + 0x22a4)
+#define MP_CPUSYS_TOP_BUS_PLLDIV_CFG (MP_CPUSYS_TOP_BASE + 0x22e0)
+#define MP_CPUSYS_TOP_MCSIC_DCM0 (MP_CPUSYS_TOP_BASE + 0x2440)
+#define MP_CPUSYS_TOP_MP_ADB_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x2500)
+#define MP_CPUSYS_TOP_MP_ADB_DCM_CFG4 (MP_CPUSYS_TOP_BASE + 0x2510)
+#define MP_CPUSYS_TOP_MP_MISC_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x2518)
+#define MP_CPUSYS_TOP_MCUSYS_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x25c0)
+#define MP_CPUSYS_TOP_MP0_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x4880)
+#define MP_CPUSYS_TOP_MP0_DCM_CFG7 (MP_CPUSYS_TOP_BASE + 0x489c)
+
+/* MP_CPUSYS_TOP */
+bool dcm_mp_cpusys_top_adb_dcm_is_on(void);
+void dcm_mp_cpusys_top_adb_dcm(bool on);
+bool dcm_mp_cpusys_top_apb_dcm_is_on(void);
+void dcm_mp_cpusys_top_apb_dcm(bool on);
+bool dcm_mp_cpusys_top_bus_pll_div_dcm_is_on(void);
+void dcm_mp_cpusys_top_bus_pll_div_dcm(bool on);
+bool dcm_mp_cpusys_top_core_stall_dcm_is_on(void);
+void dcm_mp_cpusys_top_core_stall_dcm(bool on);
+bool dcm_mp_cpusys_top_cpubiu_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpubiu_dcm(bool on);
+bool dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpu_pll_div_0_dcm(bool on);
+bool dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpu_pll_div_1_dcm(bool on);
+bool dcm_mp_cpusys_top_fcm_stall_dcm_is_on(void);
+void dcm_mp_cpusys_top_fcm_stall_dcm(bool on);
+bool dcm_mp_cpusys_top_last_cor_idle_dcm_is_on(void);
+void dcm_mp_cpusys_top_last_cor_idle_dcm(bool on);
+bool dcm_mp_cpusys_top_misc_dcm_is_on(void);
+void dcm_mp_cpusys_top_misc_dcm(bool on);
+bool dcm_mp_cpusys_top_mp0_qdcm_is_on(void);
+void dcm_mp_cpusys_top_mp0_qdcm(bool on);
+/* CPCCFG_REG */
+bool dcm_cpccfg_reg_emi_wfifo_is_on(void);
+void dcm_cpccfg_reg_emi_wfifo(bool on);
+
+#endif
diff --git a/plat/mediatek/drivers/dcm/mtk_dcm.c b/plat/mediatek/drivers/dcm/mtk_dcm.c
new file mode 100644
index 0000000..ca79a20
--- /dev/null
+++ b/plat/mediatek/drivers/dcm/mtk_dcm.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/mtk_init/mtk_init.h>
+#include <mtk_dcm.h>
+#include <mtk_dcm_utils.h>
+
+static void dcm_armcore(bool mode)
+{
+ dcm_mp_cpusys_top_bus_pll_div_dcm(mode);
+ dcm_mp_cpusys_top_cpu_pll_div_0_dcm(mode);
+ dcm_mp_cpusys_top_cpu_pll_div_1_dcm(mode);
+}
+
+static void dcm_mcusys(bool on)
+{
+ dcm_mp_cpusys_top_adb_dcm(on);
+ dcm_mp_cpusys_top_apb_dcm(on);
+ dcm_mp_cpusys_top_cpubiu_dcm(on);
+ dcm_mp_cpusys_top_misc_dcm(on);
+ dcm_mp_cpusys_top_mp0_qdcm(on);
+
+ /* CPCCFG_REG */
+ dcm_cpccfg_reg_emi_wfifo(on);
+ dcm_mp_cpusys_top_last_cor_idle_dcm(on);
+}
+
+static void dcm_stall(bool on)
+{
+ dcm_mp_cpusys_top_core_stall_dcm(on);
+ dcm_mp_cpusys_top_fcm_stall_dcm(on);
+}
+
+static bool check_dcm_state(void)
+{
+ bool ret = true;
+
+ ret &= dcm_mp_cpusys_top_bus_pll_div_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on();
+
+ ret &= dcm_mp_cpusys_top_adb_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_apb_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_cpubiu_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_misc_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_mp0_qdcm_is_on();
+ ret &= dcm_cpccfg_reg_emi_wfifo_is_on();
+ ret &= dcm_mp_cpusys_top_last_cor_idle_dcm_is_on();
+
+ ret &= dcm_mp_cpusys_top_core_stall_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_fcm_stall_dcm_is_on();
+
+ return ret;
+}
+
+bool dcm_check_state(uintptr_t addr, unsigned int mask, unsigned int compare)
+{
+ return ((mmio_read_32(addr) & mask) == compare);
+}
+
+int dcm_set_init(void)
+{
+ int ret;
+
+ dcm_armcore(true);
+ dcm_mcusys(true);
+ dcm_stall(true);
+
+ if (check_dcm_state() == false) {
+ ERROR("Failed to set default dcm on!!\n");
+ ret = -1;
+ } else {
+ INFO("%s, dcm pass\n", __func__);
+ ret = 0;
+ }
+
+ return ret;
+}
+MTK_PLAT_SETUP_0_INIT(dcm_set_init);
diff --git a/plat/mediatek/drivers/dcm/mtk_dcm.h b/plat/mediatek/drivers/dcm/mtk_dcm.h
new file mode 100644
index 0000000..05f8d45
--- /dev/null
+++ b/plat/mediatek/drivers/dcm/mtk_dcm.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_DCM_H
+#define MTK_DCM_H
+
+#include <stdbool.h>
+
+bool dcm_check_state(uintptr_t addr, unsigned int mask, unsigned int compare);
+int dcm_set_init(void);
+
+#endif /* #ifndef MTK_DCM_H */
diff --git a/plat/mediatek/drivers/dcm/rules.mk b/plat/mediatek/drivers/dcm/rules.mk
new file mode 100644
index 0000000..a8ee05e
--- /dev/null
+++ b/plat/mediatek/drivers/dcm/rules.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := mtk_dcm
+
+LOCAL_SRCS-y := ${LOCAL_DIR}/mtk_dcm.c
+LOCAL_SRCS-y += ${LOCAL_DIR}/${MTK_SOC}/mtk_dcm_utils.c
+
+PLAT_INCLUDES += -I${LOCAL_DIR}
+PLAT_INCLUDES += -I${LOCAL_DIR}/${MTK_SOC}
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/dfd/dfd.c b/plat/mediatek/drivers/dfd/dfd.c
new file mode 100644
index 0000000..5770d50
--- /dev/null
+++ b/plat/mediatek/drivers/dfd/dfd.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <dfd.h>
+#include <mtk_sip_svc.h>
+#include <plat_dfd.h>
+
+static u_register_t dfd_smc_dispatcher(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3,
+ void *handle, struct smccc_res *smccc_ret)
+{
+ int ret = MTK_SIP_E_SUCCESS;
+
+ switch (arg0) {
+ case PLAT_MTK_DFD_SETUP_MAGIC:
+ INFO("[%s] DFD setup call from kernel\n", __func__);
+ dfd_setup(arg1, arg2, arg3);
+ break;
+ case PLAT_MTK_DFD_READ_MAGIC:
+ /* only allow to access DFD register base + 0x200 */
+ if (arg1 <= 0x200) {
+ ret = mmio_read_32(MISC1_CFG_BASE + arg1);
+ }
+ break;
+ case PLAT_MTK_DFD_WRITE_MAGIC:
+ /* only allow to access DFD register base + 0x200 */
+ if (arg1 <= 0x200) {
+ sync_writel(MISC1_CFG_BASE + arg1, arg2);
+ }
+ break;
+ default:
+ ret = MTK_SIP_E_INVALID_PARAM;
+ break;
+ }
+
+ return ret;
+}
+DECLARE_SMC_HANDLER(MTK_SIP_KERNEL_DFD, dfd_smc_dispatcher);
diff --git a/plat/mediatek/drivers/dfd/dfd.h b/plat/mediatek/drivers/dfd/dfd.h
new file mode 100644
index 0000000..c088bd0
--- /dev/null
+++ b/plat/mediatek/drivers/dfd/dfd.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DFD_H
+#define DFD_H
+
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+
+void dfd_resume(void);
+void dfd_setup(uint64_t base_addr, uint64_t chain_length, uint64_t cache_dump);
+
+#endif /* DFD_H */
diff --git a/plat/mediatek/drivers/dfd/mt8188/plat_dfd.c b/plat/mediatek/drivers/dfd/mt8188/plat_dfd.c
new file mode 100644
index 0000000..1aa68f5
--- /dev/null
+++ b/plat/mediatek/drivers/dfd/mt8188/plat_dfd.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <dfd.h>
+#include <plat_dfd.h>
+
+static uint64_t dfd_cache_dump;
+static bool dfd_enabled;
+static uint64_t dfd_base_addr;
+static uint64_t dfd_chain_length;
+
+void dfd_setup(uint64_t base_addr, uint64_t chain_length, uint64_t cache_dump)
+{
+ mmio_write_32(MTK_DRM_LATCH_CTL1, MTK_DRM_LATCH_CTL1_VAL);
+ mmio_write_32(MTK_DRM_LATCH_CTL2, MTK_DRM_LATCH_CTL2_VAL);
+ mmio_write_32(MTK_WDT_LATCH_CTL2, MTK_WDT_LATCH_CTL2_VAL);
+
+ mmio_clrbits_32(DFD_O_INTRF_MCU_PWR_CTL_MASK, BIT(2));
+ mmio_setbits_32(DFD_V50_GROUP_0_63_DIFF, 0x1);
+ sync_writel(DFD_INTERNAL_CTL, 0x5);
+ mmio_setbits_32(DFD_INTERNAL_CTL, BIT(13));
+ mmio_setbits_32(DFD_INTERNAL_CTL, 0x1F << 3);
+ mmio_setbits_32(DFD_INTERNAL_CTL, 0x3 << 9);
+ mmio_setbits_32(DFD_INTERNAL_CTL, 0x3 << 19);
+
+ mmio_write_32(DFD_INTERNAL_PWR_ON, 0xB);
+ mmio_write_32(DFD_CHAIN_LENGTH0, chain_length);
+ mmio_write_32(DFD_INTERNAL_SHIFT_CLK_RATIO, 0x0);
+ mmio_write_32(DFD_INTERNAL_TEST_SO_OVER_64, 0x1);
+
+ mmio_write_32(DFD_TEST_SI_0, 0x0);
+ mmio_write_32(DFD_TEST_SI_1, 0x0);
+ mmio_write_32(DFD_TEST_SI_2, 0x0);
+ mmio_write_32(DFD_TEST_SI_3, 0x0);
+
+ sync_writel(DFD_POWER_CTL, 0xF9);
+ sync_writel(DFD_READ_ADDR, DFD_READ_ADDR_VAL);
+ sync_writel(DFD_V30_CTL, 0xD);
+
+ mmio_write_32(DFD_O_SET_BASEADDR_REG, base_addr >> 24);
+ mmio_write_32(DFD_O_REG_0, 0);
+
+ /* setup global variables for suspend and resume */
+ dfd_enabled = true;
+ dfd_base_addr = base_addr;
+ dfd_chain_length = chain_length;
+ dfd_cache_dump = cache_dump;
+
+ if ((cache_dump & DFD_CACHE_DUMP_ENABLE) != 0UL) {
+ mmio_write_32(MTK_DRM_LATCH_CTL2, MTK_DRM_LATCH_CTL2_CACHE_VAL);
+ sync_writel(DFD_V35_ENABLE, 0x1);
+ sync_writel(DFD_V35_TAP_NUMBER, 0xB);
+ sync_writel(DFD_V35_TAP_EN, DFD_V35_TAP_EN_VAL);
+ sync_writel(DFD_V35_SEQ0_0, DFD_V35_SEQ0_0_VAL);
+
+ /* Cache dump only mode */
+ sync_writel(DFD_V35_CTL, 0x1);
+ mmio_write_32(DFD_INTERNAL_NUM_OF_TEST_SO_GROUP, 0xF);
+ mmio_write_32(DFD_CHAIN_LENGTH0, DFD_CHAIN_LENGTH_VAL);
+ mmio_write_32(DFD_CHAIN_LENGTH1, DFD_CHAIN_LENGTH_VAL);
+ mmio_write_32(DFD_CHAIN_LENGTH2, DFD_CHAIN_LENGTH_VAL);
+ mmio_write_32(DFD_CHAIN_LENGTH3, DFD_CHAIN_LENGTH_VAL);
+
+ if ((cache_dump & DFD_PARITY_ERR_TRIGGER) != 0UL) {
+ sync_writel(DFD_HW_TRIGGER_MASK, 0xC);
+ mmio_setbits_32(DFD_INTERNAL_CTL, 0x1 << 4);
+ }
+ }
+ dsbsy();
+}
+
+void dfd_resume(void)
+{
+ if (dfd_enabled == true) {
+ dfd_setup(dfd_base_addr, dfd_chain_length, dfd_cache_dump);
+ }
+}
diff --git a/plat/mediatek/drivers/dfd/mt8188/plat_dfd.h b/plat/mediatek/drivers/dfd/mt8188/plat_dfd.h
new file mode 100644
index 0000000..5b98024
--- /dev/null
+++ b/plat/mediatek/drivers/dfd/mt8188/plat_dfd.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_DFD_H
+#define PLAT_DFD_H
+
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#define sync_writel(addr, val) do { mmio_write_32((addr), (val)); dsbsy(); } while (0)
+
+#define PLAT_MTK_DFD_SETUP_MAGIC (0x99716150)
+#define PLAT_MTK_DFD_READ_MAGIC (0x99716151)
+#define PLAT_MTK_DFD_WRITE_MAGIC (0x99716152)
+
+#define MTK_DRM_LATCH_CTL1 (DRM_BASE + 0x40)
+#define MTK_DRM_LATCH_CTL2 (DRM_BASE + 0x44)
+
+#define MTK_WDT_BASE (RGU_BASE)
+#define MTK_WDT_INTERVAL (MTK_WDT_BASE + 0x10)
+#define MTK_WDT_LATCH_CTL2 (MTK_WDT_BASE + 0x48)
+
+#define MCU_BIU_BASE (MCUCFG_BASE)
+#define MISC1_CFG_BASE (MCU_BIU_BASE + 0xE040)
+#define DFD_INTERNAL_CTL (MISC1_CFG_BASE + 0x00)
+#define DFD_INTERNAL_PWR_ON (MISC1_CFG_BASE + 0x08)
+#define DFD_CHAIN_LENGTH0 (MISC1_CFG_BASE + 0x0C)
+#define DFD_INTERNAL_SHIFT_CLK_RATIO (MISC1_CFG_BASE + 0x10)
+#define DFD_CHAIN_LENGTH1 (MISC1_CFG_BASE + 0x1C)
+#define DFD_CHAIN_LENGTH2 (MISC1_CFG_BASE + 0x20)
+#define DFD_CHAIN_LENGTH3 (MISC1_CFG_BASE + 0x24)
+#define DFD_INTERNAL_TEST_SO_0 (MISC1_CFG_BASE + 0x28)
+#define DFD_INTERNAL_NUM_OF_TEST_SO_GROUP (MISC1_CFG_BASE + 0x30)
+#define DFD_INTERNAL_TEST_SO_OVER_64 (MISC1_CFG_BASE + 0x34)
+#define DFD_INTERNAL_SW_NS_TRIGGER (MISC1_CFG_BASE + 0x3c)
+#define DFD_V30_CTL (MISC1_CFG_BASE + 0x48)
+#define DFD_V30_BASE_ADDR (MISC1_CFG_BASE + 0x4C)
+#define DFD_POWER_CTL (MISC1_CFG_BASE + 0x50)
+#define DFD_TEST_SI_0 (MISC1_CFG_BASE + 0x58)
+#define DFD_TEST_SI_1 (MISC1_CFG_BASE + 0x5C)
+#define DFD_CLEAN_STATUS (MISC1_CFG_BASE + 0x60)
+#define DFD_TEST_SI_2 (MISC1_CFG_BASE + 0x1D8)
+#define DFD_TEST_SI_3 (MISC1_CFG_BASE + 0x1DC)
+#define DFD_READ_ADDR (MISC1_CFG_BASE + 0x1E8)
+#define DFD_HW_TRIGGER_MASK (MISC1_CFG_BASE + 0xBC)
+
+#define DFD_V35_ENABLE (MCU_BIU_BASE + 0xE0A8)
+#define DFD_V35_TAP_NUMBER (MCU_BIU_BASE + 0xE0AC)
+#define DFD_V35_TAP_EN (MCU_BIU_BASE + 0xE0B0)
+#define DFD_V35_CTL (MCU_BIU_BASE + 0xE0B4)
+#define DFD_V35_SEQ0_0 (MCU_BIU_BASE + 0xE0C0)
+#define DFD_V35_SEQ0_1 (MCU_BIU_BASE + 0xE0C4)
+#define DFD_V50_GROUP_0_63_DIFF (MCU_BIU_BASE + 0xE2AC)
+
+#define DFD_O_PROTECT_EN_REG (0x10001220)
+#define DFD_O_INTRF_MCU_PWR_CTL_MASK (0x10001A3C)
+#define DFD_O_SET_BASEADDR_REG (0x10043000)
+#define DFD_O_REG_0 (0x10001390)
+
+#define DFD_CACHE_DUMP_ENABLE (1U)
+#define DFD_PARITY_ERR_TRIGGER (2U)
+
+#define DFD_V35_TAP_EN_VAL (0x43FF)
+#define DFD_V35_SEQ0_0_VAL (0x63668820)
+#define DFD_READ_ADDR_VAL (0x40000008)
+#define DFD_CHAIN_LENGTH_VAL (0xFFFFFFFF)
+
+#define MTK_WDT_LATCH_CTL2_VAL (0x9507FFFF)
+#define MTK_WDT_INTERVAL_VAL (0x6600000A)
+#define MTK_DRM_LATCH_CTL2_VAL (0x950607D0)
+#define MTK_DRM_LATCH_CTL2_CACHE_VAL (0x95065DC0)
+
+#define MTK_DRM_LATCH_CTL1_VAL (0x95000013)
+
+#endif /* PLAT_DFD_H */
diff --git a/plat/mediatek/drivers/dfd/rules.mk b/plat/mediatek/drivers/dfd/rules.mk
new file mode 100644
index 0000000..60fbc88
--- /dev/null
+++ b/plat/mediatek/drivers/dfd/rules.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := mtk_dfd
+
+LOCAL_SRCS-y := ${LOCAL_DIR}/dfd.c
+LOCAL_SRCS-y += ${LOCAL_DIR}/$(MTK_SOC)/plat_dfd.c
+
+PLAT_INCLUDES += -I${LOCAL_DIR}
+PLAT_INCLUDES += -I${LOCAL_DIR}/$(MTK_SOC)
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/dp/mt_dp.c b/plat/mediatek/drivers/dp/mt_dp.c
new file mode 100644
index 0000000..8aa246f
--- /dev/null
+++ b/plat/mediatek/drivers/dp/mt_dp.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <inttypes.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mt_dp.h>
+#include <mtk_sip_svc.h>
+#include <platform_def.h>
+
+static uint32_t dp_write_sec_reg(uint32_t is_edp, uint32_t offset,
+ uint32_t value, uint32_t mask)
+{
+ uint32_t reg = (is_edp != 0U) ? EDP_SEC_BASE : DP_SEC_BASE;
+
+ mmio_clrsetbits_32(reg + offset, mask, value);
+
+ return mmio_read_32(reg + offset);
+}
+
+int32_t dp_secure_handler(uint64_t cmd, uint64_t para, uint32_t *val)
+{
+ int32_t ret = 0L;
+ uint32_t is_edp = 0UL;
+ uint32_t regval = 0UL;
+ uint32_t regmsk = 0UL;
+ uint32_t fldmask = 0UL;
+
+ if ((cmd > DP_ATF_CMD_COUNT) || (val == NULL)) {
+ INFO("dp_secure_handler error cmd 0x%" PRIx64 "\n", cmd);
+ return MTK_SIP_E_INVALID_PARAM;
+ }
+
+ switch (cmd) {
+ case DP_ATF_DP_VIDEO_UNMUTE:
+ INFO("[%s] DP_ATF_DP_VIDEO_UNMUTE\n", __func__);
+ is_edp = DP_ATF_TYPE_DP;
+ ret = MTK_SIP_E_SUCCESS;
+ break;
+ case DP_ATF_EDP_VIDEO_UNMUTE:
+ INFO("[%s] DP_ATF_EDP_VIDEO_UNMUTE\n", __func__);
+ is_edp = DP_ATF_TYPE_EDP;
+ ret = MTK_SIP_E_SUCCESS;
+ break;
+ default:
+ ret = MTK_SIP_E_INVALID_PARAM;
+ break;
+ }
+
+ if (ret == MTK_SIP_E_SUCCESS) {
+ regmsk = (VIDEO_MUTE_SEL_SECURE_FLDMASK |
+ VIDEO_MUTE_SW_SECURE_FLDMASK);
+ if (para > 0U) {
+ fldmask = VIDEO_MUTE_SW_SECURE_FLDMASK;
+ } else {
+ fldmask = 0;
+ }
+
+ regval = (VIDEO_MUTE_SEL_SECURE_FLDMASK | fldmask);
+ *val = dp_write_sec_reg(is_edp, DP_TX_SECURE_REG11,
+ regval, regmsk);
+ }
+
+ return ret;
+}
+
+u_register_t mtk_dp_sip_handler(u_register_t x1, u_register_t x2,
+ u_register_t x3, u_register_t x4,
+ void *handle, struct smccc_res *smccc_ret)
+{
+ uint32_t ret_val;
+
+ return dp_secure_handler(x1, x2, &ret_val);
+}
+DECLARE_SMC_HANDLER(MTK_SIP_DP_CONTROL, mtk_dp_sip_handler);
diff --git a/plat/mediatek/drivers/dp/mt_dp.h b/plat/mediatek/drivers/dp/mt_dp.h
new file mode 100644
index 0000000..d5dad29
--- /dev/null
+++ b/plat/mediatek/drivers/dp/mt_dp.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_DP_H
+#define MT_DP_H
+
+#define DP_TX_SECURE_REG11 (0x2c)
+
+#define VIDEO_MUTE_SEL_SECURE_FLDMASK (0x10)
+#define VIDEO_MUTE_SW_SECURE_FLDMASK (0x8)
+
+enum DP_ATF_HW_TYPE {
+ DP_ATF_TYPE_DP = 0,
+ DP_ATF_TYPE_EDP = 1
+};
+
+enum DP_ATF_CMD {
+ DP_ATF_DP_VIDEO_UNMUTE = 0x20,
+ DP_ATF_EDP_VIDEO_UNMUTE,
+ DP_ATF_CMD_COUNT
+};
+
+int32_t dp_secure_handler(uint64_t cmd, uint64_t para, uint32_t *val);
+
+#endif
diff --git a/plat/mediatek/drivers/dp/rules.mk b/plat/mediatek/drivers/dp/rules.mk
new file mode 100644
index 0000000..786d514
--- /dev/null
+++ b/plat/mediatek/drivers/dp/rules.mk
@@ -0,0 +1,14 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := dp
+LOCAL_SRCS-y := $(LOCAL_DIR)/mt_dp.c
+
+PLAT_INCLUDES += -I${LOCAL_DIR}
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/emi_mpu/emi_mpu.h b/plat/mediatek/drivers/emi_mpu/emi_mpu.h
new file mode 100644
index 0000000..66a369e
--- /dev/null
+++ b/plat/mediatek/drivers/emi_mpu/emi_mpu.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EMI_MPU_H
+#define EMI_MPU_H
+
+#include <emi_mpu_priv.h>
+#include <platform_def.h>
+
+#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 LOCK (1)
+#define UNLOCK (0)
+
+#if (EMI_MPU_DGROUP_NUM == 1)
+#define SET_ACCESS_PERMISSION(apc_ary, lock, d7, d6, d5, d4, d3, d2, d1, d0) \
+do { \
+ apc_ary[1] = 0; \
+ apc_ary[0] = \
+ (((unsigned int) d7) << 21) | (((unsigned int) d6) << 18) | \
+ (((unsigned int) d5) << 15) | (((unsigned int) d4) << 12) | \
+ (((unsigned int) d3) << 9) | (((unsigned int) d2) << 6) | \
+ (((unsigned int) d1) << 3) | ((unsigned int) d0) | \
+ ((unsigned int) lock << 31); \
+} while (0)
+#elif (EMI_MPU_DGROUP_NUM == 2)
+#define SET_ACCESS_PERMISSION(apc_ary, lock, d15, d14, d13, d12, d11, d10, \
+ d9, d8, d7, d6, d5, d4, d3, d2, d1, d0) \
+do { \
+ apc_ary[1] = \
+ (((unsigned int) d15) << 21) | (((unsigned int) d14) << 18) | \
+ (((unsigned int) d13) << 15) | (((unsigned int) d12) << 12) | \
+ (((unsigned int) d11) << 9) | (((unsigned int) d10) << 6) | \
+ (((unsigned int) d9) << 3) | ((unsigned int) d8); \
+ apc_ary[0] = \
+ (((unsigned int) d7) << 21) | (((unsigned int) d6) << 18) | \
+ (((unsigned int) d5) << 15) | (((unsigned int) d4) << 12) | \
+ (((unsigned int) d3) << 9) | (((unsigned int) d2) << 6) | \
+ (((unsigned int) d1) << 3) | ((unsigned int) d0) | \
+ ((unsigned int) lock << 31); \
+} while (0)
+#endif
+
+struct emi_region_info_t {
+ unsigned long long start;
+ unsigned long long end;
+ unsigned int region;
+ unsigned int apc[EMI_MPU_DGROUP_NUM];
+};
+
+int emi_mpu_init(void);
+int emi_mpu_set_protection(struct emi_region_info_t *region_info);
+void set_emi_mpu_regions(void);
+
+#endif
diff --git a/plat/mediatek/drivers/emi_mpu/emi_mpu_common.c b/plat/mediatek/drivers/emi_mpu/emi_mpu_common.c
new file mode 100644
index 0000000..27b2b07
--- /dev/null
+++ b/plat/mediatek/drivers/emi_mpu/emi_mpu_common.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <emi_mpu.h>
+#include <lib/mtk_init/mtk_init.h>
+
+#if ENABLE_EMI_MPU_SW_LOCK
+static unsigned char region_lock_state[EMI_MPU_REGION_NUM];
+#endif
+
+#define EMI_MPU_START_MASK (0x00FFFFFF)
+#define EMI_MPU_END_MASK (0x00FFFFFF)
+#define EMI_MPU_APC_SW_LOCK_MASK (0x00FFFFFF)
+#define EMI_MPU_APC_HW_LOCK_MASK (0x80FFFFFF)
+
+static int _emi_mpu_set_protection(unsigned int start, unsigned int end,
+ unsigned int apc)
+{
+ unsigned int dgroup;
+ unsigned int region;
+
+ region = (start >> 24) & 0xFF;
+ start &= EMI_MPU_START_MASK;
+ dgroup = (end >> 24) & 0xFF;
+ end &= EMI_MPU_END_MASK;
+
+ if ((region >= EMI_MPU_REGION_NUM) || (dgroup > EMI_MPU_DGROUP_NUM)) {
+ WARN("invalid region, domain\n");
+ return -1;
+ }
+
+#if ENABLE_EMI_MPU_SW_LOCK
+ if (region_lock_state[region] == 1) {
+ WARN("invalid region\n");
+ return -1;
+ }
+
+ if ((dgroup == 0) && ((apc >> 31) & 0x1)) {
+ region_lock_state[region] = 1;
+ }
+
+ apc &= EMI_MPU_APC_SW_LOCK_MASK;
+#else
+ apc &= EMI_MPU_APC_HW_LOCK_MASK;
+#endif
+
+ if ((start >= DRAM_OFFSET) && (end >= start)) {
+ start -= DRAM_OFFSET;
+ end -= DRAM_OFFSET;
+ } else {
+ WARN("invalid range\n");
+ return -1;
+ }
+
+ mmio_write_32(EMI_MPU_SA(region), start);
+ mmio_write_32(EMI_MPU_EA(region), end);
+ mmio_write_32(EMI_MPU_APC(region, dgroup), apc);
+
+#if defined(SUB_EMI_MPU_BASE)
+ mmio_write_32(SUB_EMI_MPU_SA(region), start);
+ mmio_write_32(SUB_EMI_MPU_EA(region), end);
+ mmio_write_32(SUB_EMI_MPU_APC(region, dgroup), apc);
+#endif
+ return 0;
+}
+
+static void dump_emi_mpu_regions(void)
+{
+ int region, i;
+
+ /* Only dump 8 regions(max: EMI_MPU_REGION_NUM --> 32) */
+ for (region = 0; region < 8; ++region) {
+ INFO("region %d:\n", region);
+ INFO("\tsa: 0x%x, ea: 0x%x\n",
+ mmio_read_32(EMI_MPU_SA(region)), mmio_read_32(EMI_MPU_EA(region)));
+
+ for (i = 0; i < EMI_MPU_DGROUP_NUM; ++i) {
+ INFO("\tapc%d: 0x%x\n", i, mmio_read_32(EMI_MPU_APC(region, i)));
+ }
+ }
+}
+
+int emi_mpu_set_protection(struct emi_region_info_t *region_info)
+{
+ unsigned int start, end;
+ int i;
+
+ if (region_info->region >= EMI_MPU_REGION_NUM) {
+ WARN("invalid region\n");
+ return -1;
+ }
+
+ start = (unsigned int)(region_info->start >> EMI_MPU_ALIGN_BITS) |
+ (region_info->region << 24);
+
+ for (i = EMI_MPU_DGROUP_NUM - 1; i >= 0; i--) {
+ end = (unsigned int)(region_info->end >> EMI_MPU_ALIGN_BITS) | (i << 24);
+
+ if (_emi_mpu_set_protection(start, end, region_info->apc[i]) < 0) {
+ WARN("Failed to set emi mpu protection(%d, %d, %d)\n",
+ start, end, region_info->apc[i]);
+ }
+ }
+
+ return 0;
+}
+
+int emi_mpu_init(void)
+{
+ INFO("[%s] emi mpu initialization\n", __func__);
+
+ set_emi_mpu_regions();
+ dump_emi_mpu_regions();
+
+ return 0;
+}
+MTK_PLAT_SETUP_0_INIT(emi_mpu_init);
diff --git a/plat/mediatek/drivers/emi_mpu/mt8188/emi_mpu.c b/plat/mediatek/drivers/emi_mpu/mt8188/emi_mpu.c
new file mode 100644
index 0000000..558533d
--- /dev/null
+++ b/plat/mediatek/drivers/emi_mpu/mt8188/emi_mpu.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <emi_mpu.h>
+
+void set_emi_mpu_regions(void)
+{
+ /* TODO: set emi mpu region */
+ INFO("%s, emi mpu is not setting currently\n", __func__);
+}
diff --git a/plat/mediatek/drivers/emi_mpu/mt8188/emi_mpu_priv.h b/plat/mediatek/drivers/emi_mpu/mt8188/emi_mpu_priv.h
new file mode 100644
index 0000000..1ee7397
--- /dev/null
+++ b/plat/mediatek/drivers/emi_mpu/mt8188/emi_mpu_priv.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EMI_MPU_PRIV_H
+#define EMI_MPU_PRIV_H
+
+#define ENABLE_EMI_MPU_SW_LOCK (1)
+
+#define EMI_MPU_CTRL (EMI_MPU_BASE + 0x000)
+#define EMI_MPU_DBG (EMI_MPU_BASE + 0x004)
+#define EMI_MPU_SA0 (EMI_MPU_BASE + 0x100)
+#define EMI_MPU_EA0 (EMI_MPU_BASE + 0x200)
+#define EMI_MPU_SA(region) (EMI_MPU_SA0 + (region * 4))
+#define EMI_MPU_EA(region) (EMI_MPU_EA0 + (region * 4))
+#define EMI_MPU_APC0 (EMI_MPU_BASE + 0x300)
+#define EMI_MPU_APC(region, dgroup) (EMI_MPU_APC0 + (region * 4) + (dgroup * 0x100))
+#define EMI_MPU_CTRL_D0 (EMI_MPU_BASE + 0x800)
+#define EMI_MPU_CTRL_D(domain) (EMI_MPU_CTRL_D0 + (domain * 4))
+#define EMI_RG_MASK_D0 (EMI_MPU_BASE + 0x900)
+#define EMI_RG_MASK_D(domain) (EMI_RG_MASK_D0 + (domain * 4))
+
+#define SUB_EMI_MPU_CTRL (SUB_EMI_MPU_BASE + 0x000)
+#define SUB_EMI_MPU_DBG (SUB_EMI_MPU_BASE + 0x004)
+#define SUB_EMI_MPU_SA0 (SUB_EMI_MPU_BASE + 0x100)
+#define SUB_EMI_MPU_EA0 (SUB_EMI_MPU_BASE + 0x200)
+#define SUB_EMI_MPU_SA(region) (SUB_EMI_MPU_SA0 + (region * 4))
+#define SUB_EMI_MPU_EA(region) (SUB_EMI_MPU_EA0 + (region * 4))
+#define SUB_EMI_MPU_APC0 (SUB_EMI_MPU_BASE + 0x300)
+#define SUB_EMI_MPU_APC(region, dgroup) (SUB_EMI_MPU_APC0 + (region * 4) + (dgroup * 0x100))
+#define SUB_EMI_MPU_CTRL_D0 (SUB_EMI_MPU_BASE + 0x800)
+#define SUB_EMI_MPU_CTRL_D(domain) (SUB_EMI_MPU_CTRL_D0 + (domain * 4))
+#define SUB_EMI_RG_MASK_D0 (SUB_EMI_MPU_BASE + 0x900)
+#define SUB_EMI_RG_MASK_D(domain) (SUB_EMI_RG_MASK_D0 + (domain * 4))
+
+#define EMI_MPU_DOMAIN_NUM (16)
+#define EMI_MPU_REGION_NUM (32)
+#define EMI_MPU_ALIGN_BITS (16)
+#define DRAM_OFFSET (0x40000000 >> EMI_MPU_ALIGN_BITS)
+
+#define EMI_MPU_DGROUP_NUM (EMI_MPU_DOMAIN_NUM / 8)
+
+#endif
diff --git a/plat/mediatek/drivers/emi_mpu/rules.mk b/plat/mediatek/drivers/emi_mpu/rules.mk
new file mode 100644
index 0000000..ed3d777
--- /dev/null
+++ b/plat/mediatek/drivers/emi_mpu/rules.mk
@@ -0,0 +1,16 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := emi_mpu
+LOCAL_SRCS-y := $(LOCAL_DIR)/emi_mpu_common.c
+LOCAL_SRCS-y += ${LOCAL_DIR}/${MTK_SOC}/emi_mpu.c
+
+PLAT_INCLUDES += -I${LOCAL_DIR}
+PLAT_INCLUDES += -I${LOCAL_DIR}/${MTK_SOC}
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/gic600/mt_gic_v3.c b/plat/mediatek/drivers/gic600/mt_gic_v3.c
new file mode 100644
index 0000000..cca5d0a
--- /dev/null
+++ b/plat/mediatek/drivers/gic600/mt_gic_v3.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "../drivers/arm/gic/v3/gicv3_private.h"
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/mtk_init/mtk_init.h>
+#include <mt_gic_v3.h>
+#include <mtk_plat_common.h>
+#include <plat/common/platform.h>
+#include <plat_private.h>
+#include <platform_def.h>
+
+#define SGI_MASK 0xffff
+
+uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+static uint32_t rdist_has_saved[PLATFORM_CORE_COUNT];
+
+/* we save and restore the GICv3 context on system suspend */
+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,
+};
+
+struct gic_chip_data {
+ /* All cores share the same configuration */
+ unsigned int saved_group;
+ unsigned int saved_enable;
+ unsigned int saved_conf0;
+ unsigned int saved_conf1;
+ unsigned int saved_grpmod;
+ /* Per-core sgi */
+ unsigned int saved_sgi[PLATFORM_CORE_COUNT];
+};
+
+static struct gic_chip_data gic_data;
+
+void mt_gic_driver_init(void)
+{
+ gicv3_driver_init(&mt_gicv3_data);
+}
+
+void mt_gic_set_pending(uint32_t irq)
+{
+ gicv3_set_interrupt_pending(irq, plat_my_core_pos());
+}
+
+void mt_gic_distif_save(void)
+{
+ gicv3_distif_save(&dist_ctx);
+}
+
+void mt_gic_distif_restore(void)
+{
+ gicv3_distif_init_restore(&dist_ctx);
+}
+
+void mt_gic_rdistif_init(void)
+{
+ unsigned int proc_num;
+ unsigned int index;
+ uintptr_t gicr_base;
+
+ proc_num = plat_my_core_pos();
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+
+ /* set all SGI/PPI as non-secure GROUP1 by default */
+ mmio_write_32(gicr_base + GICR_IGROUPR0, ~0U);
+ mmio_write_32(gicr_base + GICR_IGRPMODR0, 0x0);
+
+ /* setup the default PPI/SGI priorities */
+ for (index = 0; index < TOTAL_PCPU_INTR_NUM; index += 4U)
+ gicr_write_ipriorityr(gicr_base, index,
+ GICD_IPRIORITYR_DEF_VAL);
+}
+
+void mt_gic_rdistif_save(void)
+{
+ unsigned int proc_num;
+ uintptr_t gicr_base;
+
+ proc_num = plat_my_core_pos();
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+
+ gic_data.saved_group = mmio_read_32(gicr_base + GICR_IGROUPR0);
+ gic_data.saved_enable = mmio_read_32(gicr_base + GICR_ISENABLER0);
+ gic_data.saved_conf0 = mmio_read_32(gicr_base + GICR_ICFGR0);
+ gic_data.saved_conf1 = mmio_read_32(gicr_base + GICR_ICFGR1);
+ gic_data.saved_grpmod = mmio_read_32(gicr_base + GICR_IGRPMODR0);
+
+ rdist_has_saved[proc_num] = 1;
+}
+
+void mt_gic_rdistif_restore(void)
+{
+ unsigned int proc_num;
+ uintptr_t gicr_base;
+
+ proc_num = plat_my_core_pos();
+ if (rdist_has_saved[proc_num] == 1) {
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+ mmio_write_32(gicr_base + GICR_IGROUPR0, gic_data.saved_group);
+ mmio_write_32(gicr_base + GICR_ISENABLER0,
+ gic_data.saved_enable);
+ mmio_write_32(gicr_base + GICR_ICFGR0, gic_data.saved_conf0);
+ mmio_write_32(gicr_base + GICR_ICFGR1, gic_data.saved_conf1);
+ mmio_write_32(gicr_base + GICR_IGRPMODR0,
+ gic_data.saved_grpmod);
+ }
+}
+
+void mt_gic_rdistif_restore_all(void)
+{
+ unsigned int proc_num;
+ uintptr_t gicr_base;
+
+ for (proc_num = 0; proc_num < PLATFORM_CORE_COUNT; proc_num++) {
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+ mmio_write_32(gicr_base + GICR_IGROUPR0, gic_data.saved_group);
+ mmio_write_32(gicr_base + GICR_ISENABLER0,
+ gic_data.saved_enable);
+ mmio_write_32(gicr_base + GICR_ICFGR0, gic_data.saved_conf0);
+ mmio_write_32(gicr_base + GICR_ICFGR1, gic_data.saved_conf1);
+ mmio_write_32(gicr_base + GICR_IGRPMODR0,
+ gic_data.saved_grpmod);
+ }
+}
+
+void gic_sgi_save_all(void)
+{
+ unsigned int proc_num;
+ uintptr_t gicr_base;
+
+ for (proc_num = 0; proc_num < PLATFORM_CORE_COUNT; proc_num++) {
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+ gic_data.saved_sgi[proc_num] =
+ mmio_read_32(gicr_base + GICR_ISPENDR0) & SGI_MASK;
+ }
+}
+
+void gic_sgi_restore_all(void)
+{
+ unsigned int proc_num;
+ uintptr_t gicr_base;
+
+ for (proc_num = 0; proc_num < PLATFORM_CORE_COUNT; proc_num++) {
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+ mmio_write_32(gicr_base + GICR_ICPENDR0, SGI_MASK);
+ mmio_write_32(gicr_base + GICR_ISPENDR0,
+ gic_data.saved_sgi[proc_num] & SGI_MASK);
+ }
+}
+
+void mt_gic_init(void)
+{
+ gicv3_distif_init();
+ gicv3_rdistif_init(plat_my_core_pos());
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+uint32_t mt_irq_get_pending(uint32_t irq)
+{
+ uint32_t val;
+
+ val = mmio_read_32(BASE_GICD_BASE + GICD_ISPENDR +
+ irq / 32 * 4);
+ val = (val >> (irq % 32)) & 1U;
+ return val;
+}
+
+
+void mt_irq_set_pending(uint32_t irq)
+{
+ uint32_t bit = 1U << (irq % 32);
+
+ mmio_write_32(BASE_GICD_BASE + GICD_ISPENDR +
+ irq / 32 * 4, bit);
+}
+
+int mt_gic_one_init(void)
+{
+ INFO("[%s] GIC initialization\n", __func__);
+
+ /* Initialize the GIC driver, CPU and distributor interfaces */
+ mt_gic_driver_init();
+ mt_gic_init();
+
+ return 0;
+}
+MTK_PLAT_SETUP_0_INIT(mt_gic_one_init);
diff --git a/plat/mediatek/drivers/gic600/mt_gic_v3.h b/plat/mediatek/drivers/gic600/mt_gic_v3.h
new file mode 100644
index 0000000..31513ef
--- /dev/null
+++ b/plat/mediatek/drivers/gic600/mt_gic_v3.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_GIC_V3_H
+#define MT_GIC_V3_H
+
+#include <drivers/arm/gicv3.h>
+#include <lib/mmio.h>
+
+void mt_gic_driver_init(void);
+void mt_gic_init(void);
+void mt_gic_set_pending(uint32_t irq);
+void mt_gic_distif_save(void);
+void mt_gic_distif_restore(void);
+void mt_gic_rdistif_init(void);
+void mt_gic_rdistif_save(void);
+void mt_gic_rdistif_restore(void);
+void mt_gic_rdistif_restore_all(void);
+void gic_sgi_save_all(void);
+void gic_sgi_restore_all(void);
+uint32_t mt_irq_get_pending(uint32_t irq);
+void mt_irq_set_pending(uint32_t irq);
+int mt_gic_one_init(void);
+
+#endif /* MT_GIC_V3_H */
diff --git a/plat/mediatek/drivers/gic600/rules.mk b/plat/mediatek/drivers/gic600/rules.mk
new file mode 100644
index 0000000..3070591
--- /dev/null
+++ b/plat/mediatek/drivers/gic600/rules.mk
@@ -0,0 +1,14 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := gic600
+LOCAL_SRCS-y := $(LOCAL_DIR)/mt_gic_v3.c
+
+PLAT_INCLUDES += -I${LOCAL_DIR}
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/gpio/mt8188/mtgpio.c b/plat/mediatek/drivers/gpio/mt8188/mtgpio.c
new file mode 100644
index 0000000..9e9fc5d
--- /dev/null
+++ b/plat/mediatek/drivers/gpio/mt8188/mtgpio.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <mtgpio.h>
+#include <platform_def.h>
+
+uintptr_t mt_gpio_find_reg_addr(uint32_t pin)
+{
+ uintptr_t reg_addr = 0U;
+ struct mt_pin_info gpio_info;
+
+ assert(pin < MAX_GPIO_PIN);
+
+ gpio_info = mt_pin_infos[pin];
+
+ switch (gpio_info.base & 0x0f) {
+ case 0:
+ reg_addr = IOCFG_RM_BASE;
+ break;
+ case 1:
+ reg_addr = IOCFG_LT_BASE;
+ break;
+ case 2:
+ reg_addr = IOCFG_LM_BASE;
+ break;
+ case 3:
+ reg_addr = IOCFG_RT_BASE;
+ break;
+ default:
+ break;
+ }
+
+ return reg_addr;
+}
diff --git a/plat/mediatek/drivers/gpio/mt8188/mtgpio.h b/plat/mediatek/drivers/gpio/mt8188/mtgpio.h
new file mode 100644
index 0000000..32a4608
--- /dev/null
+++ b/plat/mediatek/drivers/gpio/mt8188/mtgpio.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_GPIO_H
+#define MT_GPIO_H
+
+#include <mtgpio_common.h>
+
+/* 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,
+ MT_GPIO_BASE_MAX
+} GPIO_PIN;
+
+static const struct mt_pin_info mt_pin_infos[] = {
+ PIN(0, 0, 6, 0x30, 0xb0),
+ PIN(1, 0, 7, 0x30, 0xb0),
+ PIN(2, 0, 8, 0x30, 0xb0),
+ PIN(3, 0, 9, 0x30, 0xb0),
+ PIN(4, 0, 10, 0x30, 0xb0),
+ PIN(5, 0, 11, 0x30, 0xb0),
+ PIN(6, 0, 12, 0x30, 0xb0),
+ PIN(7, 0, 13, 0x30, 0xb0),
+ PIN(8, 0, 14, 0x30, 0xb0),
+ PIN(9, 0, 15, 0x30, 0xb0),
+ PIN(10, 0, 16, 0x30, 0xb0),
+ PIN(11, 0, 17, 0x30, 0xb0),
+ PIN(12, 0, 12, 0x31, 0xa0),
+ PIN(13, 0, 13, 0x31, 0xa0),
+ PIN(14, 0, 14, 0x31, 0xa0),
+ PIN(15, 0, 15, 0x31, 0xa0),
+ PIN(16, 0, 1, 0x22, 0x50),
+ PIN(17, 0, 2, 0x22, 0x50),
+ PIN(18, 0, 3, 0x23, 0x60),
+ PIN(19, 0, 4, 0x23, 0x60),
+ PIN(20, 0, 5, 0x23, 0x60),
+ PIN(21, 0, 6, 0x23, 0x60),
+ PIN(22, 0, 0, 0x23, 0x60),
+ PIN(23, 0, 1, 0x23, 0x60),
+ PIN(24, 0, 2, 0x23, 0x60),
+ PIN(25, 0, 3, 0x30, 0xb0),
+ PIN(26, 0, 2, 0x30, 0xb0),
+ PIN(27, 0, 5, 0x30, 0xb0),
+ PIN(28, 0, 4, 0x30, 0xb0),
+ PIN(29, 0, 0, 0x30, 0xb0),
+ PIN(30, 0, 1, 0x30, 0xb0),
+ PIN(31, 0, 11, 0x30, 0xc0),
+ PIN(32, 0, 10, 0x30, 0xc0),
+ PIN(33, 0, 13, 0x30, 0xc0),
+ PIN(34, 0, 12, 0x30, 0xc0),
+ PIN(35, 0, 15, 0x30, 0xc0),
+ PIN(36, 0, 14, 0x30, 0xc0),
+ PIN(37, 0, 21, 0x30, 0xb0),
+ PIN(38, 0, 18, 0x30, 0xb0),
+ PIN(39, 0, 19, 0x30, 0xb0),
+ PIN(40, 0, 20, 0x30, 0xb0),
+ PIN(41, 0, 22, 0x30, 0xb0),
+ PIN(42, 1, 12, 0x31, 0xc0),
+ PIN(43, 1, 13, 0x31, 0xc0),
+ PIN(44, 1, 14, 0x31, 0xc0),
+ PIN(45, 1, 15, 0x31, 0xc0),
+ PIN(46, 0, 0, 0x22, 0x50),
+ PIN(47, 0, 25, 0x30, 0xb0),
+ PIN(48, 0, 24, 0x30, 0xb0),
+ PIN(49, 0, 23, 0x30, 0xb0),
+ PIN(50, 0, 5, 0x22, 0x50),
+ PIN(51, 0, 4, 0x22, 0x50),
+ PIN(52, 0, 3, 0x22, 0x50),
+ PIN(53, 0, 6, 0x22, 0x50),
+ PIN(54, 0, 7, 0x22, 0x50),
+ PIN(55, 0, 26, 0x30, 0xb0),
+ PIN(56, 0, 29, 0x30, 0xb0),
+ PIN(57, 0, 6, 0x31, 0xb0),
+ PIN(58, 0, 9, 0x31, 0xb0),
+ PIN(59, 0, 27, 0x30, 0xb0),
+ PIN(60, 0, 30, 0x30, 0xb0),
+ PIN(61, 0, 28, 0x30, 0xb0),
+ PIN(62, 0, 31, 0x30, 0xb0),
+ PIN(63, 0, 7, 0x31, 0xb0),
+ PIN(64, 0, 10, 0x31, 0xb0),
+ PIN(65, 0, 7, 0x23, 0x60),
+ PIN(66, 0, 9, 0x23, 0x60),
+ PIN(67, 0, 8, 0x23, 0x60),
+ PIN(68, 0, 10, 0x23, 0x60),
+ PIN(69, 0, 1, 0x30, 0xc0),
+ PIN(70, 0, 0, 0x30, 0xc0),
+ PIN(71, 0, 5, 0x30, 0xc0),
+ PIN(72, 0, 4, 0x30, 0xc0),
+ PIN(73, 0, 2, 0x30, 0xc0),
+ PIN(74, 0, 3, 0x30, 0xc0),
+ PIN(75, 0, 7, 0x30, 0xc0),
+ PIN(76, 0, 6, 0x30, 0xc0),
+ PIN(77, 0, 9, 0x30, 0xc0),
+ PIN(78, 0, 8, 0x30, 0xc0),
+ PIN(79, 0, 12, 0x23, 0x60),
+ PIN(80, 0, 11, 0x23, 0x60),
+ PIN(81, 0, 14, 0x23, 0x60),
+ PIN(82, 0, 13, 0x23, 0x60),
+ PIN(83, 0, 16, 0x31, 0xb0),
+ PIN(84, 0, 15, 0x31, 0xb0),
+ PIN(85, 0, 17, 0x31, 0xb0),
+ PIN(86, 0, 19, 0x31, 0xb0),
+ PIN(87, 0, 18, 0x31, 0xb0),
+ PIN(88, 0, 20, 0x31, 0xb0),
+ PIN(89, 0, 22, 0x31, 0xb0),
+ PIN(90, 0, 21, 0x31, 0xb0),
+ PIN(91, 0, 23, 0x31, 0xb0),
+ PIN(92, 0, 3, 0x31, 0xb0),
+ PIN(93, 0, 2, 0x31, 0xb0),
+ PIN(94, 0, 5, 0x31, 0xb0),
+ PIN(95, 0, 4, 0x31, 0xb0),
+ PIN(96, 0, 31, 0x31, 0xa0),
+ PIN(97, 0, 0, 0x31, 0xb0),
+ PIN(98, 0, 8, 0x31, 0xb0),
+ PIN(99, 0, 30, 0x31, 0xa0),
+ PIN(100, 0, 1, 0x31, 0xb0),
+ PIN(101, 0, 0, 0x31, 0xa0),
+ PIN(102, 0, 5, 0x31, 0xa0),
+ PIN(103, 0, 3, 0x31, 0xa0),
+ PIN(104, 0, 4, 0x31, 0xa0),
+ PIN(105, 0, 1, 0x31, 0xa0),
+ PIN(106, 0, 2, 0x31, 0xa0),
+ PIN(107, 0, 21, 0x31, 0xa0),
+ PIN(108, 0, 16, 0x31, 0xa0),
+ PIN(109, 0, 22, 0x31, 0xa0),
+ PIN(110, 0, 17, 0x31, 0xa0),
+ PIN(111, 0, 18, 0x31, 0xa0),
+ PIN(112, 0, 19, 0x31, 0xa0),
+ PIN(113, 0, 20, 0x31, 0xa0),
+ PIN(114, 0, 28, 0x31, 0xa0),
+ PIN(115, 0, 23, 0x31, 0xa0),
+ PIN(116, 0, 29, 0x31, 0xa0),
+ PIN(117, 0, 24, 0x31, 0xa0),
+ PIN(118, 0, 25, 0x31, 0xa0),
+ PIN(119, 0, 26, 0x31, 0xa0),
+ PIN(120, 0, 27, 0x31, 0xa0),
+ PIN(121, 0, 8, 0x22, 0x50),
+ PIN(122, 0, 11, 0x22, 0x50),
+ PIN(123, 0, 10, 0x22, 0x50),
+ PIN(124, 0, 9, 0x22, 0x50),
+ PIN(125, 0, 6, 0x31, 0xa0),
+ PIN(126, 0, 7, 0x31, 0xa0),
+ PIN(127, 0, 8, 0x31, 0xa0),
+ PIN(128, 0, 9, 0x31, 0xa0),
+ PIN(129, 0, 10, 0x31, 0xa0),
+ PIN(130, 0, 11, 0x31, 0xa0),
+ PIN(131, 1, 1, 0x30, 0xd0),
+ PIN(132, 1, 2, 0x30, 0xd0),
+ PIN(133, 1, 9, 0x30, 0xd0),
+ PIN(134, 1, 10, 0x30, 0xd0),
+ PIN(135, 1, 11, 0x30, 0xd0),
+ PIN(136, 1, 12, 0x30, 0xd0),
+ PIN(137, 1, 13, 0x30, 0xd0),
+ PIN(138, 1, 14, 0x30, 0xd0),
+ PIN(139, 1, 15, 0x30, 0xd0),
+ PIN(140, 1, 16, 0x30, 0xd0),
+ PIN(141, 1, 3, 0x30, 0xd0),
+ PIN(142, 1, 4, 0x30, 0xd0),
+ PIN(143, 1, 5, 0x30, 0xd0),
+ PIN(144, 1, 6, 0x30, 0xd0),
+ PIN(145, 1, 7, 0x30, 0xd0),
+ PIN(146, 1, 8, 0x30, 0xd0),
+ PIN(147, 1, 18, 0x30, 0xd0),
+ PIN(148, 1, 19, 0x30, 0xd0),
+ PIN(149, 1, 17, 0x30, 0xd0),
+ PIN(150, 1, 0, 0x30, 0xd0),
+ PIN(151, 1, 9, 0x31, 0xc0),
+ PIN(152, 1, 8, 0x31, 0xc0),
+ PIN(153, 1, 7, 0x31, 0xc0),
+ PIN(154, 1, 6, 0x31, 0xc0),
+ PIN(155, 1, 11, 0x31, 0xc0),
+ PIN(156, 1, 1, 0x31, 0xc0),
+ PIN(157, 1, 0, 0x31, 0xc0),
+ PIN(158, 1, 5, 0x31, 0xc0),
+ PIN(159, 1, 4, 0x31, 0xc0),
+ PIN(160, 1, 3, 0x31, 0xc0),
+ PIN(161, 1, 2, 0x31, 0xc0),
+ PIN(162, 1, 10, 0x31, 0xc0),
+ PIN(163, 1, 1, 0x23, 0x70),
+ PIN(164, 1, 0, 0x23, 0x70),
+ PIN(165, 1, 2, 0x23, 0x70),
+ PIN(166, 1, 3, 0x23, 0x70),
+ PIN(167, 1, 4, 0x23, 0x70),
+ PIN(168, 1, 5, 0x23, 0x70),
+ PIN(169, 1, 1, 0x22, 0x60),
+ PIN(170, 1, 0, 0x22, 0x60),
+ PIN(171, 1, 2, 0x22, 0x60),
+ PIN(172, 1, 3, 0x22, 0x60),
+ PIN(173, 1, 4, 0x22, 0x60),
+ PIN(174, 1, 5, 0x22, 0x60),
+ PIN(175, 0, 11, 0x31, 0xb0),
+ PIN(176, 0, 12, 0x31, 0xb0),
+};
+
+#endif /* MT_GPIO_H */
diff --git a/plat/mediatek/drivers/gpio/mtgpio_common.c b/plat/mediatek/drivers/gpio/mtgpio_common.c
new file mode 100644
index 0000000..bad0190
--- /dev/null
+++ b/plat/mediatek/drivers/gpio/mtgpio_common.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/gpio.h>
+#include <lib/mmio.h>
+#include <lib/mtk_init/mtk_init.h>
+#include <mtgpio.h>
+#include <platform_def.h>
+
+/******************************************************************************
+ *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
+
+static void mt_set_gpio_dir_chip(uint32_t pin, int dir)
+{
+ uint32_t pos, bit;
+
+ assert(pin < MAX_GPIO_PIN);
+ assert(dir < MT_GPIO_DIR_MAX);
+
+ pos = pin / MAX_GPIO_REG_BITS;
+ bit = pin % MAX_GPIO_REG_BITS;
+
+ if (dir == MT_GPIO_DIR_IN) {
+ mmio_write_32(DIR_BASE + 0x10U * pos + CLR, 1U << bit);
+ } else {
+ mmio_write_32(DIR_BASE + 0x10U * pos + SET, 1U << bit);
+ }
+}
+
+static 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 + 0x10U * pos);
+ return (((reg & (1U << bit)) != 0U) ? MT_GPIO_DIR_OUT : MT_GPIO_DIR_IN);
+}
+
+static void mt_set_gpio_out_chip(uint32_t pin, int output)
+{
+ uint32_t pos, bit;
+
+ assert(pin < MAX_GPIO_PIN);
+ assert(output < MT_GPIO_OUT_MAX);
+
+ pos = pin / MAX_GPIO_REG_BITS;
+ bit = pin % MAX_GPIO_REG_BITS;
+
+ if (output == MT_GPIO_OUT_ZERO) {
+ mmio_write_32(DOUT_BASE + 0x10U * pos + CLR, 1U << bit);
+ } else {
+ mmio_write_32(DOUT_BASE + 0x10U * pos + SET, 1U << bit);
+ }
+}
+
+static 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 + 0x10U * pos);
+ return (((reg & (1U << bit)) != 0U) ? 1 : 0);
+}
+
+static void mt_gpio_set_spec_pull_pupd(uint32_t pin, int enable,
+ int select)
+{
+ uintptr_t reg1;
+ uintptr_t reg2;
+ struct mt_pin_info gpio_info;
+
+ gpio_info = mt_pin_infos[pin];
+ uint32_t bit = gpio_info.bit;
+
+ reg1 = mt_gpio_find_reg_addr(pin) + gpio_info.offset;
+ reg2 = reg1 + (gpio_info.base & 0xf0);
+ if (enable == MT_GPIO_PULL_ENABLE) {
+ mmio_write_32(reg2 + SET, (1U << bit));
+ if (select == MT_GPIO_PULL_DOWN) {
+ mmio_write_32(reg1 + SET, (1U << bit));
+ } else {
+ mmio_write_32(reg1 + CLR, (1U << bit));
+ }
+ } else {
+ mmio_write_32(reg2 + CLR, (1U << bit));
+ mmio_write_32((reg2 + 0x010U) + CLR, (1U << bit));
+ }
+}
+
+static void mt_gpio_set_pull_pu_pd(uint32_t pin, int enable,
+ int select)
+{
+ uintptr_t reg1;
+ uintptr_t reg2;
+ struct mt_pin_info gpio_info;
+
+ gpio_info = mt_pin_infos[pin];
+ uint32_t bit = gpio_info.bit;
+
+ reg1 = mt_gpio_find_reg_addr(pin) + gpio_info.offset;
+ reg2 = reg1 - (gpio_info.base & 0xf0);
+
+ if (enable == MT_GPIO_PULL_ENABLE) {
+ if (select == MT_GPIO_PULL_DOWN) {
+ mmio_write_32(reg1 + CLR, (1U << bit));
+ mmio_write_32(reg2 + SET, (1U << bit));
+ } else {
+ mmio_write_32(reg2 + CLR, (1U << bit));
+ mmio_write_32(reg1 + SET, (1U << bit));
+ }
+ } else {
+ mmio_write_32(reg1 + CLR, (1U << bit));
+ mmio_write_32(reg2 + CLR, (1U << bit));
+ }
+}
+
+static void mt_gpio_set_pull_chip(uint32_t pin, int enable,
+ int select)
+{
+ struct mt_pin_info gpio_info;
+
+ gpio_info = mt_pin_infos[pin];
+ if (gpio_info.flag) {
+ mt_gpio_set_spec_pull_pupd(pin, enable, select);
+ } else {
+ mt_gpio_set_pull_pu_pd(pin, enable, select);
+ }
+}
+
+static int mt_gpio_get_spec_pull_pupd(uint32_t pin)
+{
+ uintptr_t reg1;
+ uintptr_t reg2;
+ uint32_t r0;
+ uint32_t r1;
+
+ struct mt_pin_info gpio_info;
+
+ gpio_info = mt_pin_infos[pin];
+ uint32_t bit = gpio_info.bit;
+
+ reg1 = mt_gpio_find_reg_addr(pin) + gpio_info.offset;
+ reg2 = reg1 + (gpio_info.base & 0xf0);
+
+ r0 = (mmio_read_32(reg2) >> bit) & 1U;
+ r1 = (mmio_read_32(reg2 + 0x010) >> bit) & 1U;
+ if (r0 == 0U && r1 == 0U) {
+ return MT_GPIO_PULL_NONE;
+ } else {
+ if (mmio_read_32(reg1) & (1U << bit)) {
+ return MT_GPIO_PULL_DOWN;
+ } else {
+ return MT_GPIO_PULL_UP;
+ }
+ }
+}
+
+static int mt_gpio_get_pull_pu_pd(uint32_t pin)
+{
+ uintptr_t reg1;
+ uintptr_t reg2;
+ uint32_t pu;
+ uint32_t pd;
+
+ struct mt_pin_info gpio_info;
+
+ gpio_info = mt_pin_infos[pin];
+ uint32_t bit = gpio_info.bit;
+
+ reg1 = mt_gpio_find_reg_addr(pin) + gpio_info.offset;
+ reg2 = reg1 - (gpio_info.base & 0xf0);
+ pu = (mmio_read_32(reg1) >> bit) & 1U;
+ pd = (mmio_read_32(reg2) >> bit) & 1U;
+ if (pu == 1U) {
+ return MT_GPIO_PULL_UP;
+ } else if (pd == 1U) {
+ return MT_GPIO_PULL_DOWN;
+ } else {
+ return MT_GPIO_PULL_NONE;
+ }
+}
+
+static int mt_gpio_get_pull_chip(uint32_t pin)
+{
+ struct mt_pin_info gpio_info;
+
+ gpio_info = mt_pin_infos[pin];
+ if (gpio_info.flag) {
+ return mt_gpio_get_spec_pull_pupd(pin);
+ } else {
+ return mt_gpio_get_pull_pu_pd(pin);
+ }
+}
+
+static void mt_set_gpio_pull_select_chip(uint32_t pin, int sel)
+{
+ assert(pin < MAX_GPIO_PIN);
+
+ if (sel == MT_GPIO_PULL_NONE) {
+ mt_gpio_set_pull_chip(pin, MT_GPIO_PULL_DISABLE, MT_GPIO_PULL_DOWN);
+ } else if (sel == MT_GPIO_PULL_UP) {
+ mt_gpio_set_pull_chip(pin, MT_GPIO_PULL_ENABLE, MT_GPIO_PULL_UP);
+ } else if (sel == MT_GPIO_PULL_DOWN) {
+ mt_gpio_set_pull_chip(pin, MT_GPIO_PULL_ENABLE, MT_GPIO_PULL_DOWN);
+ }
+}
+
+/* get pull-up or pull-down, regardless of resistor value */
+static int mt_get_gpio_pull_select_chip(uint32_t pin)
+{
+ assert(pin < MAX_GPIO_PIN);
+
+ return mt_gpio_get_pull_chip(pin);
+}
+
+static void mt_set_gpio_dir(int gpio, int direction)
+{
+ mt_set_gpio_dir_chip((uint32_t)gpio, direction);
+}
+
+static int mt_get_gpio_dir(int gpio)
+{
+ uint32_t pin;
+
+ pin = (uint32_t)gpio;
+ return mt_get_gpio_dir_chip(pin);
+}
+
+static void mt_set_gpio_pull(int gpio, int pull)
+{
+ uint32_t pin;
+
+ pin = (uint32_t)gpio;
+ mt_set_gpio_pull_select_chip(pin, pull);
+}
+
+static int mt_get_gpio_pull(int gpio)
+{
+ uint32_t pin;
+
+ pin = (uint32_t)gpio;
+ return mt_get_gpio_pull_select_chip(pin);
+}
+
+static void mt_set_gpio_out(int gpio, int value)
+{
+ uint32_t pin;
+
+ pin = (uint32_t)gpio;
+ mt_set_gpio_out_chip(pin, value);
+}
+
+static int mt_get_gpio_in(int gpio)
+{
+ uint32_t pin;
+
+ pin = (uint32_t)gpio;
+ return mt_get_gpio_in_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,
+};
+
+int mt_gpio_init(void)
+{
+ gpio_init(&mtgpio_ops);
+
+ return 0;
+}
+MTK_PLAT_SETUP_0_INIT(mt_gpio_init);
diff --git a/plat/mediatek/drivers/gpio/mtgpio_common.h b/plat/mediatek/drivers/gpio/mtgpio_common.h
new file mode 100644
index 0000000..d6b858c
--- /dev/null
+++ b/plat/mediatek/drivers/gpio/mtgpio_common.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_GPIO_COMMON_H
+#define MT_GPIO_COMMON_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <plat/common/common_def.h>
+
+/* Error Code No. */
+#define RSUCCESS 0
+#define ERACCESS 1
+#define ERINVAL 2
+#define ERWRAPPER 3
+#define MAX_GPIO_PIN MT_GPIO_BASE_MAX
+
+/* 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 {
+ MT_GPIO_DIR_UNSUPPORTED = -1,
+ MT_GPIO_DIR_OUT = 0,
+ MT_GPIO_DIR_IN = 1,
+ MT_GPIO_DIR_MAX,
+ MT_GPIO_DIR_DEFAULT = MT_GPIO_DIR_IN,
+} GPIO_DIR;
+
+/* GPIO PULL ENABLE*/
+typedef enum {
+ MT_GPIO_PULL_EN_UNSUPPORTED = -1,
+ MT_GPIO_PULL_DISABLE = 0,
+ MT_GPIO_PULL_ENABLE = 1,
+ MT_GPIO_PULL_ENABLE_R0 = 2,
+ MT_GPIO_PULL_ENABLE_R1 = 3,
+ MT_GPIO_PULL_ENABLE_R0R1 = 4,
+
+ MT_GPIO_PULL_EN_MAX,
+ MT_GPIO_PULL_EN_DEFAULT = MT_GPIO_PULL_ENABLE,
+} GPIO_PULL_EN;
+
+/* GPIO PULL-UP/PULL-DOWN*/
+typedef enum {
+ MT_GPIO_PULL_UNSUPPORTED = -1,
+ MT_GPIO_PULL_NONE = 0,
+ MT_GPIO_PULL_UP = 1,
+ MT_GPIO_PULL_DOWN = 2,
+ MT_GPIO_PULL_MAX,
+ MT_GPIO_PULL_DEFAULT = MT_GPIO_PULL_DOWN
+} GPIO_PULL;
+
+/* GPIO OUTPUT */
+typedef enum {
+ MT_GPIO_OUT_UNSUPPORTED = -1,
+ MT_GPIO_OUT_ZERO = 0,
+ MT_GPIO_OUT_ONE = 1,
+
+ MT_GPIO_OUT_MAX,
+ MT_GPIO_OUT_DEFAULT = MT_GPIO_OUT_ZERO,
+ MT_GPIO_DATA_OUT_DEFAULT = MT_GPIO_OUT_ZERO, /*compatible with DCT*/
+} GPIO_OUT;
+
+/* GPIO INPUT */
+typedef enum {
+ MT_GPIO_IN_UNSUPPORTED = -1,
+ MT_GPIO_IN_ZERO = 0,
+ MT_GPIO_IN_ONE = 1,
+
+ MT_GPIO_IN_MAX,
+} GPIO_IN;
+
+#define PIN(_id, _flag, _bit, _base, _offset) { \
+ .id = _id, \
+ .flag = _flag, \
+ .bit = _bit, \
+ .base = _base, \
+ .offset = _offset, \
+ }
+
+struct mt_pin_info {
+ uint8_t id;
+ uint8_t flag;
+ uint8_t bit;
+ uint16_t base;
+ uint16_t offset;
+};
+
+int mt_gpio_init(void);
+uintptr_t mt_gpio_find_reg_addr(uint32_t pin);
+#endif /* MT_GPIO_COMMON_H */
diff --git a/plat/mediatek/drivers/gpio/rules.mk b/plat/mediatek/drivers/gpio/rules.mk
new file mode 100644
index 0000000..78061a8
--- /dev/null
+++ b/plat/mediatek/drivers/gpio/rules.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := gpio
+
+LOCAL_SRCS-y := drivers/gpio/gpio.c
+LOCAL_SRCS-y += ${LOCAL_DIR}/mtgpio_common.c
+LOCAL_SRCS-y += ${LOCAL_DIR}/${MTK_SOC}/mtgpio.c
+
+PLAT_INCLUDES += -I${LOCAL_DIR}
+PLAT_INCLUDES += -I${LOCAL_DIR}/${MTK_SOC}
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/iommu/mt8188/mtk_iommu_plat.c b/plat/mediatek/drivers/iommu/mt8188/mtk_iommu_plat.c
new file mode 100644
index 0000000..1d6863f
--- /dev/null
+++ b/plat/mediatek/drivers/iommu/mt8188/mtk_iommu_plat.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mtk_iommu_plat.h>
+#include <mtk_mmap_pool.h>
+#include <platform_def.h>
+
+/* mm iommu */
+#define SMI_L0_ID (0)
+#define SMI_L1_ID (1)
+#define SMI_L2_ID (2)
+#define SMI_L3_ID (3)
+#define SMI_L4_ID (4)
+#define SMI_L5_ID (5)
+#define SMI_L6_ID (6)
+#define SMI_L7_ID (7)
+#define SMI_L9_ID (8)
+#define SMI_L10_ID (9)
+#define SMI_L11A_ID (10)
+#define SMI_L11B_ID (11)
+#define SMI_L11C_ID (12)
+#define SMI_L12_ID (13)
+#define SMI_L13_ID (14)
+#define SMI_L14_ID (15)
+#define SMI_L15_ID (16)
+#define SMI_L16A_ID (17)
+#define SMI_L16B_ID (18)
+#define SMI_L17A_ID (19)
+#define SMI_L17B_ID (20)
+#define SMI_L19_ID (21)
+#define SMI_L21_ID (22)
+#define SMI_L23_ID (23)
+#define SMI_L27_ID (24)
+#define SMI_L28_ID (25)
+
+/* infra iommu */
+#define PERI_MST_PROT (0x710)
+#define PERICFG_AO_IOMMU_1 (0x714)
+#define MMU_DEV_PCIE_0 (0)
+#define IFR_CFG_GROUP_NUM (1)
+
+static struct mtk_smi_larb_config mt8188_larb_cfg[SMI_LARB_NUM] = {
+ [SMI_L0_ID] = LARB_CFG_ENTRY(SMI_LARB_0_BASE, 7, 0),
+ [SMI_L1_ID] = LARB_CFG_ENTRY(SMI_LARB_1_BASE, 7, 0),
+ [SMI_L2_ID] = LARB_CFG_ENTRY(SMI_LARB_2_BASE, 5, 0),
+ [SMI_L3_ID] = LARB_CFG_ENTRY(SMI_LARB_3_BASE, 7, 0),
+ [SMI_L4_ID] = LARB_CFG_ENTRY(SMI_LARB_4_BASE, 7, 0),
+ [SMI_L5_ID] = LARB_CFG_ENTRY(SMI_LARB_5_BASE, 8, 0),
+ [SMI_L6_ID] = LARB_CFG_ENTRY(SMI_LARB_6_BASE, 4, 0),
+ [SMI_L7_ID] = LARB_CFG_ENTRY(SMI_LARB_7_BASE, 3, 0),
+ [SMI_L9_ID] = LARB_CFG_ENTRY(SMI_LARB_9_BASE, 25, 0),
+ [SMI_L10_ID] = LARB_CFG_ENTRY(SMI_LARB_10_BASE, 20, 0),
+ [SMI_L11A_ID] = LARB_CFG_ENTRY(SMI_LARB_11A_BASE, 30, 0),
+ [SMI_L11B_ID] = LARB_CFG_ENTRY(SMI_LARB_11B_BASE, 30, 0),
+ [SMI_L11C_ID] = LARB_CFG_ENTRY(SMI_LARB_11C_BASE, 30, 0),
+ [SMI_L12_ID] = LARB_CFG_ENTRY(SMI_LARB_12_BASE, 16, 0),
+ [SMI_L13_ID] = LARB_CFG_ENTRY(SMI_LARB_13_BASE, 24, 0),
+ [SMI_L14_ID] = LARB_CFG_ENTRY(SMI_LARB_14_BASE, 23, 0),
+ [SMI_L15_ID] = LARB_CFG_ENTRY(SMI_LARB_15_BASE, 19, 0),
+ [SMI_L16A_ID] = LARB_CFG_ENTRY(SMI_LARB_16A_BASE, 17, 0),
+ [SMI_L16B_ID] = LARB_CFG_ENTRY(SMI_LARB_16B_BASE, 17, 0),
+ [SMI_L17A_ID] = LARB_CFG_ENTRY(SMI_LARB_17A_BASE, 7, 0),
+ [SMI_L17B_ID] = LARB_CFG_ENTRY(SMI_LARB_17B_BASE, 7, 0),
+ /* venc nbm ports (5/6/11/15/16/17) to sram */
+ [SMI_L19_ID] = LARB_CFG_ENTRY_WITH_PATH(SMI_LARB_19_BASE, 27, 0, 0x38860),
+ [SMI_L21_ID] = LARB_CFG_ENTRY(SMI_LARB_21_BASE, 11, 0),
+ [SMI_L23_ID] = LARB_CFG_ENTRY(SMI_LARB_23_BASE, 9, 0),
+ [SMI_L27_ID] = LARB_CFG_ENTRY(SMI_LARB_27_BASE, 4, 0),
+ [SMI_L28_ID] = LARB_CFG_ENTRY(SMI_LARB_28_BASE, 0, 0),
+};
+
+static bool is_protected;
+
+static uint32_t mt8188_ifr_mst_cfg_base[IFR_CFG_GROUP_NUM] = {
+ PERICFG_AO_BASE,
+};
+static uint32_t mt8188_ifr_mst_cfg_offs[IFR_CFG_GROUP_NUM] = {
+ PERICFG_AO_IOMMU_1,
+};
+static struct mtk_ifr_mst_config mt8188_ifr_mst_cfg[MMU_DEV_NUM] = {
+ [MMU_DEV_PCIE_0] = IFR_MST_CFG_ENTRY(0, 18),
+};
+
+struct mtk_smi_larb_config *g_larb_cfg = &mt8188_larb_cfg[0];
+struct mtk_ifr_mst_config *g_ifr_mst_cfg = &mt8188_ifr_mst_cfg[0];
+uint32_t *g_ifr_mst_cfg_base = &mt8188_ifr_mst_cfg_base[0];
+uint32_t *g_ifr_mst_cfg_offs = &mt8188_ifr_mst_cfg_offs[0];
+
+/* Protect infra iommu enable setting registers as secure access. */
+void mtk_infra_iommu_enable_protect(void)
+{
+ if (!is_protected) {
+ mmio_write_32(PERICFG_AO_BASE + PERI_MST_PROT, 0xffffffff);
+ is_protected = true;
+ }
+}
diff --git a/plat/mediatek/drivers/iommu/mt8188/mtk_iommu_plat.h b/plat/mediatek/drivers/iommu/mt8188/mtk_iommu_plat.h
new file mode 100644
index 0000000..a59e0c7
--- /dev/null
+++ b/plat/mediatek/drivers/iommu/mt8188/mtk_iommu_plat.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IOMMU_PLAT_H
+#define IOMMU_PLAT_H
+
+#include <mtk_iommu_priv.h>
+
+/* mm iommu */
+#define SMI_LARB_NUM (26)
+extern struct mtk_smi_larb_config *g_larb_cfg;
+
+/* infra iommu */
+#define MMU_DEV_NUM (1)
+extern struct mtk_ifr_mst_config *g_ifr_mst_cfg;
+extern uint32_t *g_ifr_mst_cfg_base;
+extern uint32_t *g_ifr_mst_cfg_offs;
+
+extern void mtk_infra_iommu_enable_protect(void);
+
+#endif /* IOMMU_PLAT_H */
diff --git a/plat/mediatek/drivers/iommu/mtk_iommu_priv.h b/plat/mediatek/drivers/iommu/mtk_iommu_priv.h
new file mode 100644
index 0000000..3404d31
--- /dev/null
+++ b/plat/mediatek/drivers/iommu/mtk_iommu_priv.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IOMMU_PRIV_H
+#define IOMMU_PRIV_H
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mtk_sip_svc.h>
+
+#define LARB_CFG_ENTRY(bs, p_nr, dom) \
+ { .base = (bs), .port_nr = (p_nr), \
+ .dom_id = (dom), .to_sram = 0, }
+
+#define LARB_CFG_ENTRY_WITH_PATH(bs, p_nr, dom, sram) \
+ { .base = (bs), .port_nr = (p_nr), \
+ .dom_id = (dom), .to_sram = (sram), }
+
+#define IFR_MST_CFG_ENTRY(idx, bit) \
+ { .cfg_addr_idx = (idx), .r_mmu_en_bit = (bit), }
+
+enum IOMMU_ATF_CMD {
+ IOMMU_ATF_CMD_CONFIG_SMI_LARB, /* For mm master to enable iommu */
+ IOMMU_ATF_CMD_CONFIG_INFRA_IOMMU, /* For infra master to enable iommu */
+ IOMMU_ATF_CMD_COUNT,
+};
+
+struct mtk_smi_larb_config {
+ uint32_t base;
+ uint32_t port_nr;
+ uint32_t dom_id;
+ uint32_t to_sram;
+ uint32_t sec_en_msk;
+};
+
+struct mtk_ifr_mst_config {
+ uint8_t cfg_addr_idx;
+ uint8_t r_mmu_en_bit;
+};
+
+#endif /* IOMMU_PRIV_H */
diff --git a/plat/mediatek/drivers/iommu/mtk_iommu_smc.c b/plat/mediatek/drivers/iommu/mtk_iommu_smc.c
new file mode 100644
index 0000000..9762d0b
--- /dev/null
+++ b/plat/mediatek/drivers/iommu/mtk_iommu_smc.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <mtk_iommu_plat.h>
+
+/* defination */
+/* smi larb */
+#define SMI_LARB_NON_SEC_CON(port) (0x380 + ((port) << 2))
+#define PATH_SEL_MASK (0xf0000) /* to sram (INT) */
+#define SMI_LARB_SEC_CON_INT(port) (0xf00 + ((port) << 2))
+#define SMI_LARB_SEC_CON(port) (0xf80 + ((port) << 2))
+#define MMU_MASK BIT(0)
+#define MMU_EN(en) ((!!(en)) << 0)
+#define SEC_MASK BIT(1)
+#define SEC_EN(en) ((!!(en)) << 1)
+#define DOMAIN_MASK (0x1f << 4)
+#define SMI_MMU_EN(port) (0x1 << (port))
+
+/* infra master */
+#define IFR_CFG_MMU_EN_MSK(r_bit) (0x3 << (r_bit))
+
+/* smi larb configure */
+/*
+ * If multimedia security config is enabled, the SMI config register must be
+ * configurated in security world.
+ * And the SRAM path is also configurated here to enhance security.
+ */
+static void mtk_smi_larb_port_config_to_sram(
+ const struct mtk_smi_larb_config *larb,
+ uint32_t port_id)
+{
+ mmio_clrbits_32(larb->base + SMI_LARB_SEC_CON_INT(port_id),
+ MMU_MASK | SEC_MASK | DOMAIN_MASK);
+
+ mmio_setbits_32(larb->base + SMI_LARB_NON_SEC_CON(port_id),
+ PATH_SEL_MASK);
+}
+
+static void mtk_smi_port_config(const struct mtk_smi_larb_config *larb,
+ uint32_t port_id, uint8_t mmu_en, uint8_t sec_en)
+{
+ mmio_clrsetbits_32(larb->base + SMI_LARB_SEC_CON(port_id),
+ MMU_MASK | SEC_MASK | DOMAIN_MASK,
+ MMU_EN(mmu_en) | SEC_EN(sec_en));
+}
+
+static int mtk_smi_larb_port_config_sec(uint32_t larb_id, uint32_t mmu_en_msk)
+{
+ uint32_t port_id, port_nr;
+ const struct mtk_smi_larb_config *larb;
+ uint32_t to_sram;
+ uint8_t mmu_en;
+
+ if (larb_id >= SMI_LARB_NUM) {
+ return MTK_SIP_E_INVALID_PARAM;
+ }
+
+ larb = &g_larb_cfg[larb_id];
+ port_nr = larb->port_nr;
+ to_sram = larb->to_sram;
+
+ for (port_id = 0; port_id < port_nr; port_id++) {
+ if ((to_sram & BIT(port_id)) > 0U) {
+ mtk_smi_larb_port_config_to_sram(larb, port_id);
+ continue;
+ }
+ mmu_en = !!(mmu_en_msk & SMI_MMU_EN(port_id));
+ mtk_smi_port_config(larb, port_id, mmu_en, 0);
+ }
+
+ return MTK_SIP_E_SUCCESS;
+}
+
+static int mtk_infra_master_config_sec(uint32_t dev_id, uint32_t enable)
+{
+ const struct mtk_ifr_mst_config *ifr_cfg;
+ uint32_t reg_addr;
+
+ mtk_infra_iommu_enable_protect();
+
+ if (dev_id >= MMU_DEV_NUM) {
+ return MTK_SIP_E_NOT_SUPPORTED;
+ }
+
+ ifr_cfg = &g_ifr_mst_cfg[dev_id];
+ reg_addr = g_ifr_mst_cfg_base[(ifr_cfg->cfg_addr_idx)] +
+ g_ifr_mst_cfg_offs[(ifr_cfg->cfg_addr_idx)];
+
+ if (enable > 0U) {
+ mmio_setbits_32(reg_addr, IFR_CFG_MMU_EN_MSK(ifr_cfg->r_mmu_en_bit));
+ } else {
+ mmio_clrbits_32(reg_addr, IFR_CFG_MMU_EN_MSK(ifr_cfg->r_mmu_en_bit));
+ }
+
+ return MTK_SIP_E_SUCCESS;
+}
+
+static u_register_t mtk_iommu_handler(u_register_t x1, u_register_t x2,
+ u_register_t x3, u_register_t x4,
+ void *handle, struct smccc_res *smccc_ret)
+{
+ uint32_t cmd_id = x1, mdl_id = x2, val = x3;
+ int ret = MTK_SIP_E_NOT_SUPPORTED;
+
+ (void)x4;
+ (void)handle;
+
+ switch (cmd_id) {
+ case IOMMU_ATF_CMD_CONFIG_SMI_LARB:
+ ret = mtk_smi_larb_port_config_sec(mdl_id, val);
+ break;
+ case IOMMU_ATF_CMD_CONFIG_INFRA_IOMMU:
+ ret = mtk_infra_master_config_sec(mdl_id, val);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+DECLARE_SMC_HANDLER(MTK_SIP_IOMMU_CONTROL, mtk_iommu_handler);
diff --git a/plat/mediatek/drivers/iommu/rules.mk b/plat/mediatek/drivers/iommu/rules.mk
new file mode 100644
index 0000000..5490f41
--- /dev/null
+++ b/plat/mediatek/drivers/iommu/rules.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := mtk_iommu
+
+LOCAL_SRCS-y := ${LOCAL_DIR}/mtk_iommu_smc.c
+LOCAL_SRCS-y += ${LOCAL_DIR}/${MTK_SOC}/mtk_iommu_plat.c
+
+PLAT_INCLUDES += -I${LOCAL_DIR}
+PLAT_INCLUDES += -I${LOCAL_DIR}/${MTK_SOC}
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/mcusys/mcusys.c b/plat/mediatek/drivers/mcusys/mcusys.c
new file mode 100644
index 0000000..63edb23
--- /dev/null
+++ b/plat/mediatek/drivers/mcusys/mcusys.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <mtk_mmap_pool.h>
+#include <platform_def.h>
+
+static const mmap_region_t mcusys_mmap[] MTK_MMAP_SECTION = {
+ MAP_REGION_FLAT(MCUCFG_BASE, MCUCFG_REG_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+ {0}
+};
+DECLARE_MTK_MMAP_REGIONS(mcusys_mmap);
diff --git a/plat/mediatek/drivers/mcusys/rules.mk b/plat/mediatek/drivers/mcusys/rules.mk
new file mode 100644
index 0000000..5438998
--- /dev/null
+++ b/plat/mediatek/drivers/mcusys/rules.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := mcusys
+
+PLAT_INCLUDES += -I$(LOCAL_DIR)/$(MCUSYS_VERSION)
+
+LOCAL_SRCS-y := $(LOCAL_DIR)/mcusys.c
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/mcusys/v1/mcucfg.h b/plat/mediatek/drivers/mcusys/v1/mcucfg.h
new file mode 100644
index 0000000..7aced5a
--- /dev/null
+++ b/plat/mediatek/drivers/mcusys/v1/mcucfg.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MCUCFG_V1_H
+#define MCUCFG_V1_H
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+#endif /*__ASSEMBLER__*/
+
+#include <platform_def.h>
+
+#define MP2_MISC_CONFIG_BOOT_ADDR_L(cpu) (MCUCFG_BASE + 0x2290 + ((cpu) * 8))
+#define MP2_MISC_CONFIG_BOOT_ADDR_H(cpu) (MCUCFG_BASE + 0x2294 + ((cpu) * 8))
+
+#define MP2_CPUCFG (MCUCFG_BASE + 0x2208)
+
+#define MP0_CPUTOP_SPMC_CTL (MCUCFG_BASE + 0x788)
+#define MP1_CPUTOP_SPMC_CTL (MCUCFG_BASE + 0x78C)
+#define MP1_CPUTOP_SPMC_SRAM_CTL (MCUCFG_BASE + 0x790)
+
+#define CPUSYSx_CPUx_SPMC_CTL(cluster, cpu) (MCUCFG_BASE + 0x1C30 + \
+ (cluster) * 0x2000 + (cpu) * 4)
+
+#define CPUSYS0_CPU0_SPMC_CTL (MCUCFG_BASE + 0x1C30)
+#define CPUSYS0_CPU1_SPMC_CTL (MCUCFG_BASE + 0x1C34)
+#define CPUSYS0_CPU2_SPMC_CTL (MCUCFG_BASE + 0x1C38)
+#define CPUSYS0_CPU3_SPMC_CTL (MCUCFG_BASE + 0x1C3C)
+
+#define CPUSYS1_CPU0_SPMC_CTL (MCUCFG_BASE + 0x3C30)
+#define CPUSYS1_CPU1_SPMC_CTL (MCUCFG_BASE + 0x3C34)
+#define CPUSYS1_CPU2_SPMC_CTL (MCUCFG_BASE + 0x3C38)
+#define CPUSYS1_CPU3_SPMC_CTL (MCUCFG_BASE + 0x3C3C)
+
+/* CPC related registers */
+#define CPC_MCUSYS_CPC_OFF_THRES (MCUCFG_BASE + 0xA714)
+#define CPC_MCUSYS_PWR_CTRL (MCUCFG_BASE + 0xA804)
+#define CPC_MCUSYS_CPC_FLOW_CTRL_CFG (MCUCFG_BASE + 0xA814)
+#define CPC_MCUSYS_LAST_CORE_REQ (MCUCFG_BASE + 0xA818)
+#define CPC_MCUSYS_MP_LAST_CORE_RESP (MCUCFG_BASE + 0xA81C)
+#define CPC_MCUSYS_LAST_CORE_RESP (MCUCFG_BASE + 0xA824)
+#define CPC_MCUSYS_PWR_ON_MASK (MCUCFG_BASE + 0xA828)
+#define CPC_SPMC_PWR_STATUS (MCUCFG_BASE + 0xA840)
+#define CPC_MCUSYS_CPU_ON_SW_HINT_SET (MCUCFG_BASE + 0xA8A8)
+#define CPC_MCUSYS_CPU_ON_SW_HINT_CLR (MCUCFG_BASE + 0xA8AC)
+#define CPC_MCUSYS_CPC_DBG_SETTING (MCUCFG_BASE + 0xAB00)
+#define CPC_MCUSYS_CPC_KERNEL_TIME_L_BASE (MCUCFG_BASE + 0xAB04)
+#define CPC_MCUSYS_CPC_KERNEL_TIME_H_BASE (MCUCFG_BASE + 0xAB08)
+#define CPC_MCUSYS_CPC_SYSTEM_TIME_L_BASE (MCUCFG_BASE + 0xAB0C)
+#define CPC_MCUSYS_CPC_SYSTEM_TIME_H_BASE (MCUCFG_BASE + 0xAB10)
+#define CPC_MCUSYS_TRACE_SEL (MCUCFG_BASE + 0xAB14)
+#define CPC_MCUSYS_TRACE_DATA (MCUCFG_BASE + 0xAB20)
+#define CPC_MCUSYS_CLUSTER_COUNTER (MCUCFG_BASE + 0xAB70)
+#define CPC_MCUSYS_CLUSTER_COUNTER_CLR (MCUCFG_BASE + 0xAB74)
+
+/* CPC_MCUSYS_CPC_FLOW_CTRL_CFG bit control */
+#define CPC_CTRL_ENABLE BIT(16)
+#define SSPM_CORE_PWR_ON_EN BIT(7) /* for cpu-hotplug */
+#define SSPM_ALL_PWR_CTRL_EN BIT(13) /* for cpu-hotplug */
+#define GIC_WAKEUP_IGNORE(cpu) BIT(21 + cpu)
+
+#define CPC_MCUSYS_CPC_RESET_ON_KEEP_ON BIT(17)
+#define CPC_MCUSYS_CPC_RESET_PWR_ON_EN BIT(20)
+
+/* SPMC related registers */
+#define SPM_MCUSYS_PWR_CON (MCUCFG_BASE + 0xD200)
+#define SPM_MP0_CPUTOP_PWR_CON (MCUCFG_BASE + 0xD204)
+#define SPM_MP0_CPU0_PWR_CON (MCUCFG_BASE + 0xD208)
+#define SPM_MP0_CPU1_PWR_CON (MCUCFG_BASE + 0xD20C)
+#define SPM_MP0_CPU2_PWR_CON (MCUCFG_BASE + 0xD210)
+#define SPM_MP0_CPU3_PWR_CON (MCUCFG_BASE + 0xD214)
+#define SPM_MP0_CPU4_PWR_CON (MCUCFG_BASE + 0xD218)
+#define SPM_MP0_CPU5_PWR_CON (MCUCFG_BASE + 0xD21C)
+#define SPM_MP0_CPU6_PWR_CON (MCUCFG_BASE + 0xD220)
+#define SPM_MP0_CPU7_PWR_CON (MCUCFG_BASE + 0xD224)
+
+/* bit fields of SPM_*_PWR_CON */
+#define PWR_ON_ACK BIT(31)
+#define VPROC_EXT_OFF BIT(7)
+#define DORMANT_EN BIT(6)
+#define RESETPWRON_CONFIG BIT(5)
+#define PWR_CLK_DIS BIT(4)
+#define PWR_ON BIT(2)
+#define PWR_RST_B BIT(0)
+
+#define SPARK2LDO (MCUCFG_BASE + 0x2700)
+/* APB Module mcucfg */
+#define MP0_CA7_CACHE_CONFIG (MCUCFG_BASE + 0x000)
+#define MP0_AXI_CONFIG (MCUCFG_BASE + 0x02C)
+#define MP0_MISC_CONFIG0 (MCUCFG_BASE + 0x030)
+#define MP0_MISC_CONFIG1 (MCUCFG_BASE + 0x034)
+#define MP0_MISC_CONFIG2 (MCUCFG_BASE + 0x038)
+#define MP0_MISC_CONFIG_BOOT_ADDR(cpu) (MCUCFG_BASE + 0x038 + ((cpu) * 8))
+#define MP0_MISC_CONFIG3 (MCUCFG_BASE + 0x03C)
+#define MP0_MISC_CONFIG9 (MCUCFG_BASE + 0x054)
+#define MP0_CA7_MISC_CONFIG (MCUCFG_BASE + 0x064)
+
+#define MP0_RW_RSVD0 (MCUCFG_BASE + 0x06C)
+#define MP1_CA7_CACHE_CONFIG (MCUCFG_BASE + 0x200)
+#define MP1_AXI_CONFIG (MCUCFG_BASE + 0x22C)
+#define MP1_MISC_CONFIG0 (MCUCFG_BASE + 0x230)
+#define MP1_MISC_CONFIG1 (MCUCFG_BASE + 0x234)
+#define MP1_MISC_CONFIG2 (MCUCFG_BASE + 0x238)
+#define MP1_MISC_CONFIG_BOOT_ADDR(cpu) (MCUCFG_BASE + 0x238 + ((cpu) * 8))
+#define MP1_MISC_CONFIG3 (MCUCFG_BASE + 0x23C)
+#define MP1_MISC_CONFIG9 (MCUCFG_BASE + 0x254)
+#define MP1_CA7_MISC_CONFIG (MCUCFG_BASE + 0x264)
+
+#define CCI_ADB400_DCM_CONFIG (MCUCFG_BASE + 0x740)
+#define SYNC_DCM_CONFIG (MCUCFG_BASE + 0x744)
+
+#define MP0_CLUSTER_CFG0 (MCUCFG_BASE + 0xC8D0)
+
+#define MP0_SPMC (MCUCFG_BASE + 0x788)
+#define MP1_SPMC (MCUCFG_BASE + 0x78C)
+#define MP2_AXI_CONFIG (MCUCFG_BASE + 0x220C)
+#define MP2_AXI_CONFIG_ACINACTM BIT(0)
+#define MP2_AXI_CONFIG_AINACTS BIT(4)
+
+#define MPx_AXI_CONFIG_ACINACTM BIT(4)
+#define MPx_AXI_CONFIG_AINACTS BIT(5)
+
+#define MPx_CA7_MISC_CONFIG_standbywfil2 BIT(28)
+
+#define MP0_CPU0_STANDBYWFE BIT(20)
+#define MP0_CPU1_STANDBYWFE BIT(21)
+#define MP0_CPU2_STANDBYWFE BIT(22)
+#define MP0_CPU3_STANDBYWFE BIT(23)
+
+#define MP1_CPU0_STANDBYWFE BIT(20)
+#define MP1_CPU1_STANDBYWFE BIT(21)
+#define MP1_CPU2_STANDBYWFE BIT(22)
+#define MP1_CPU3_STANDBYWFE BIT(23)
+
+#define CPUSYS0_SPARKVRETCNTRL (MCUCFG_BASE+0x1c00)
+#define CPUSYS0_SPARKEN (MCUCFG_BASE+0x1c04)
+#define CPUSYS0_AMUXSEL (MCUCFG_BASE+0x1c08)
+#define CPUSYS1_SPARKVRETCNTRL (MCUCFG_BASE+0x3c00)
+#define CPUSYS1_SPARKEN (MCUCFG_BASE+0x3c04)
+#define CPUSYS1_AMUXSEL (MCUCFG_BASE+0x3c08)
+
+#define MP2_PWR_RST_CTL (MCUCFG_BASE + 0x2008)
+#define MP2_PTP3_CPUTOP_SPMC0 (MCUCFG_BASE + 0x22A0)
+#define MP2_PTP3_CPUTOP_SPMC1 (MCUCFG_BASE + 0x22A4)
+
+#define MP2_COQ (MCUCFG_BASE + 0x22BC)
+#define MP2_COQ_SW_DIS BIT(0)
+
+#define MP2_CA15M_MON_SEL (MCUCFG_BASE + 0x2400)
+#define MP2_CA15M_MON_L (MCUCFG_BASE + 0x2404)
+
+#define CPUSYS2_CPU0_SPMC_CTL (MCUCFG_BASE + 0x2430)
+#define CPUSYS2_CPU1_SPMC_CTL (MCUCFG_BASE + 0x2438)
+#define CPUSYS2_CPU0_SPMC_STA (MCUCFG_BASE + 0x2434)
+#define CPUSYS2_CPU1_SPMC_STA (MCUCFG_BASE + 0x243C)
+
+#define MP0_CA7L_DBG_PWR_CTRL (MCUCFG_BASE + 0x068)
+#define MP1_CA7L_DBG_PWR_CTRL (MCUCFG_BASE + 0x268)
+#define BIG_DBG_PWR_CTRL (MCUCFG_BASE + 0x75C)
+
+#define MP2_SW_RST_B BIT(0)
+#define MP2_TOPAON_APB_MASK BIT(1)
+#define B_SW_HOT_PLUG_RESET BIT(30)
+#define B_SW_PD_OFFSET (18)
+#define B_SW_PD (0x3F << B_SW_PD_OFFSET)
+
+#define B_SW_SRAM_SLEEPB_OFFSET (12)
+#define B_SW_SRAM_SLEEPB (0x3F << B_SW_SRAM_SLEEPB_OFFSET)
+
+#define B_SW_SRAM_ISOINTB BIT(9)
+#define B_SW_ISO BIT(8)
+#define B_SW_LOGIC_PDB BIT(7)
+#define B_SW_LOGIC_PRE2_PDB BIT(6)
+#define B_SW_LOGIC_PRE1_PDB BIT(5)
+#define B_SW_FSM_OVERRIDE BIT(4)
+#define B_SW_PWR_ON BIT(3)
+#define B_SW_PWR_ON_OVERRIDE_EN BIT(2)
+
+#define B_FSM_STATE_OUT_OFFSET (6)
+#define B_FSM_STATE_OUT_MASK (0x1F << B_FSM_STATE_OUT_OFFSET)
+#define B_SW_LOGIC_PDBO_ALL_OFF_ACK BIT(5)
+#define B_SW_LOGIC_PDBO_ALL_ON_ACK BIT(4)
+#define B_SW_LOGIC_PRE2_PDBO_ALL_ON_ACK BIT(3)
+#define B_SW_LOGIC_PRE1_PDBO_ALL_ON_ACK BIT(2)
+
+
+#define B_FSM_OFF (0U << B_FSM_STATE_OUT_OFFSET)
+#define B_FSM_ON (1U << B_FSM_STATE_OUT_OFFSET)
+#define B_FSM_RET (2U << B_FSM_STATE_OUT_OFFSET)
+
+#ifndef __ASSEMBLER__
+/* cpu boot mode */
+enum mp0_coucfg_64bit_ctrl {
+ MP0_CPUCFG_64BIT_SHIFT = 12,
+ MP1_CPUCFG_64BIT_SHIFT = 28,
+ MP0_CPUCFG_64BIT = 0xfu << MP0_CPUCFG_64BIT_SHIFT,
+ MP1_CPUCFG_64BIT = 0xfu << MP1_CPUCFG_64BIT_SHIFT,
+};
+
+enum mp1_dis_rgu0_ctrl {
+ 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_ctrl {
+ MP1_AINACTS_SHIFT = 4,
+ MP1_AINACTS = 1U << MP1_AINACTS_SHIFT,
+};
+
+enum mp1_sw_cg_gen {
+ MP1_SW_CG_GEN_SHIFT = 12,
+ MP1_SW_CG_GEN = 1U << MP1_SW_CG_GEN_SHIFT,
+};
+
+enum mp1_l2rstdisable {
+ MP1_L2RSTDISABLE_SHIFT = 14,
+ MP1_L2RSTDISABLE = 1U << MP1_L2RSTDISABLE_SHIFT,
+};
+#endif /*__ASSEMBLER__*/
+
+#endif /* MCUCFG_V1_H */
diff --git a/plat/mediatek/drivers/msdc/mt8186/mt_msdc_priv.h b/plat/mediatek/drivers/msdc/mt8186/mt_msdc_priv.h
new file mode 100644
index 0000000..b3337ca
--- /dev/null
+++ b/plat/mediatek/drivers/msdc/mt8186/mt_msdc_priv.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_MSDC_PRIV_H
+#define MT_MSDC_PRIV_H
+
+#define MSDC_CQHCI_CFG 0x808
+#define MSDC_CQHCI_CRYPTO_ENABLE BIT(1)
+
+#endif
diff --git a/plat/mediatek/drivers/msdc/mt_msdc.c b/plat/mediatek/drivers/msdc/mt_msdc.c
new file mode 100644
index 0000000..ccf440f
--- /dev/null
+++ b/plat/mediatek/drivers/msdc/mt_msdc.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mt_msdc.h>
+#include <platform_def.h>
+
+uint64_t msdc_smc_dispatcher(uint64_t arg0, uint64_t arg1,
+ uint64_t arg2, uint64_t arg3)
+{
+ INFO("[%s] msdc setup call from kernel\n", __func__);
+ mmio_setbits_32(MSDC0_BASE + MSDC_CQHCI_CFG, MSDC_CQHCI_CRYPTO_ENABLE);
+
+ return 0L;
+}
diff --git a/plat/mediatek/drivers/msdc/mt_msdc.h b/plat/mediatek/drivers/msdc/mt_msdc.h
new file mode 100644
index 0000000..1c500c2
--- /dev/null
+++ b/plat/mediatek/drivers/msdc/mt_msdc.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_MSDC_H
+#define MT_MSDC_H
+
+#include <mt_msdc_priv.h>
+
+uint64_t msdc_smc_dispatcher(uint64_t arg0, uint64_t arg1,
+ uint64_t arg2, uint64_t arg3);
+
+#endif
diff --git a/plat/mediatek/drivers/pmic/pmic.c b/plat/mediatek/drivers/pmic/pmic.c
new file mode 100644
index 0000000..a11ad9a
--- /dev/null
+++ b/plat/mediatek/drivers/pmic/pmic.c
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <pmic.h>
+#include <pmic_wrap_init.h>
+
+void pmic_power_off(void)
+{
+ pwrap_write(PMIC_PWRHOLD, 0x0);
+}
diff --git a/plat/mediatek/drivers/pmic/pmic.h b/plat/mediatek/drivers/pmic/pmic.h
new file mode 100644
index 0000000..6c10f65
--- /dev/null
+++ b/plat/mediatek/drivers/pmic/pmic.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMIC_H
+#define PMIC_H
+
+#define PMIC_PWRHOLD (0xa08)
+
+/* external API */
+void pmic_power_off(void);
+
+#endif /* PMIC_H */
diff --git a/plat/mediatek/drivers/pmic/rules.mk b/plat/mediatek/drivers/pmic/rules.mk
new file mode 100644
index 0000000..e408b03
--- /dev/null
+++ b/plat/mediatek/drivers/pmic/rules.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := pmic
+
+LOCAL_SRCS-y += ${LOCAL_DIR}/pmic.c
+
+PLAT_INCLUDES += -I${LOCAL_DIR}/
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/pmic_wrap/mt8188/pmic_wrap_init.h b/plat/mediatek/drivers/pmic_wrap/mt8188/pmic_wrap_init.h
new file mode 100644
index 0000000..9027daf
--- /dev/null
+++ b/plat/mediatek/drivers/pmic_wrap/mt8188/pmic_wrap_init.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMIC_WRAP_INIT_H
+#define PMIC_WRAP_INIT_H
+
+#include <stdint.h>
+
+#include "platform_def.h"
+#include <pmic_wrap_init_common.h>
+
+static struct mt8188_pmic_wrap_regs *const mtk_pwrap = (void *)PMIC_WRAP_BASE;
+
+/* PMIC_WRAP registers */
+struct mt8188_pmic_wrap_regs {
+ uint32_t init_done;
+ uint32_t reserved[543];
+ uint32_t wacs2_cmd;
+ uint32_t wacs2_wdata;
+ uint32_t reserved1[3];
+ uint32_t wacs2_rdata;
+ uint32_t reserved2[3];
+ uint32_t wacs2_vldclr;
+ uint32_t wacs2_sta;
+};
+
+#endif /* PMIC_WRAP_INIT_H */
diff --git a/plat/mediatek/drivers/pmic_wrap/pmic_wrap_init.c b/plat/mediatek/drivers/pmic_wrap/pmic_wrap_init.c
new file mode 100644
index 0000000..0ee1c64
--- /dev/null
+++ b/plat/mediatek/drivers/pmic_wrap/pmic_wrap_init.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2019-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+#include <pmic_wrap_init.h>
+
+/* 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,
+ &reg_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);
+}
diff --git a/plat/mediatek/drivers/pmic_wrap/pmic_wrap_init_common.h b/plat/mediatek/drivers/pmic_wrap/pmic_wrap_init_common.h
new file mode 100644
index 0000000..4ba1f5c
--- /dev/null
+++ b/plat/mediatek/drivers/pmic_wrap/pmic_wrap_init_common.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMIC_WRAP_INIT_COMMON_H
+#define PMIC_WRAP_INIT_COMMON_H
+
+#include <stdint.h>
+
+#include "platform_def.h"
+
+/* external API */
+int32_t pwrap_read(uint32_t adr, uint32_t *rdata);
+int32_t pwrap_write(uint32_t adr, uint32_t wdata);
+
+#define GET_WACS_FSM(x) ((x >> 1) & 0x7)
+
+/* macro for SWINF_FSM */
+#define SWINF_FSM_IDLE (0x00)
+#define SWINF_FSM_REQ (0x02)
+#define SWINF_FSM_WFDLE (0x04)
+#define SWINF_FSM_WFVLDCLR (0x06)
+#define SWINF_INIT_DONE (0x01)
+
+/* timeout setting */
+#define PWRAP_READ_US (1000)
+#define PWRAP_WAIT_IDLE_US (1000)
+
+/* error information flag */
+enum pwrap_errno {
+ 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_COMMON_H */
diff --git a/plat/mediatek/drivers/pmic_wrap/pmic_wrap_init_v2.c b/plat/mediatek/drivers/pmic_wrap/pmic_wrap_init_v2.c
new file mode 100644
index 0000000..80f55de
--- /dev/null
+++ b/plat/mediatek/drivers/pmic_wrap/pmic_wrap_init_v2.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include "platform_def.h"
+#include "pmic_wrap_init.h"
+
+/* pmic wrap module wait_idle and read polling interval (in microseconds) */
+enum pwrap_polling_interval {
+ WAIT_IDLE_POLLING_DELAY_US = 1,
+ READ_POLLING_DELAY_US = 2
+};
+
+static uint32_t pwrap_check_idle(void *wacs_register, uint32_t timeout_us)
+{
+ uint32_t reg_rdata = 0U, retry;
+
+ retry = (timeout_us + WAIT_IDLE_POLLING_DELAY_US) /
+ WAIT_IDLE_POLLING_DELAY_US;
+ while (retry != 0) {
+ 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 (GET_WACS_FSM(reg_rdata)) {
+ case SWINF_FSM_WFVLDCLR:
+ mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_vldclr, 0x1);
+ INFO("WACS_FSM = SWINF_FSM_WFVLDCLR\n");
+ break;
+ case SWINF_FSM_WFDLE:
+ INFO("WACS_FSM = SWINF_FSM_WFDLE\n");
+ break;
+ case SWINF_FSM_REQ:
+ INFO("WACS_FSM = SWINF_FSM_REQ\n");
+ break;
+ case SWINF_FSM_IDLE:
+ goto done;
+ default:
+ break;
+ }
+ retry--;
+ };
+
+done:
+ if (retry == 0) {
+ /* timeout */
+ return E_PWR_WAIT_IDLE_TIMEOUT;
+ }
+
+ return 0U;
+}
+
+static uint32_t pwrap_check_vldclr(void *wacs_register, uint32_t timeout_us)
+{
+ uint32_t reg_rdata = 0U, retry;
+
+ retry = (timeout_us + READ_POLLING_DELAY_US) / READ_POLLING_DELAY_US;
+ while (retry != 0) {
+ udelay(READ_POLLING_DELAY_US);
+ reg_rdata = mmio_read_32((uintptr_t)wacs_register);
+ if (GET_WACS_FSM(reg_rdata) == SWINF_FSM_WFVLDCLR) {
+ break;
+ }
+ retry--;
+ };
+
+ if (retry == 0) {
+ /* timeout */
+ return E_PWR_WAIT_IDLE_TIMEOUT;
+ }
+
+ return 0U;
+}
+
+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, return_value;
+
+ if (init_check != 0) {
+ if ((mmio_read_32((uintptr_t)&mtk_pwrap->init_done) & 0x1) == 0) {
+ ERROR("initialization isn't finished\n");
+ return E_PWR_NOT_INIT_DONE;
+ }
+ }
+
+ /* Wait for Software Interface FSM state to be IDLE. */
+ return_value = pwrap_check_idle(&mtk_pwrap->wacs2_sta,
+ PWRAP_WAIT_IDLE_US);
+ if (return_value != 0) {
+ return return_value;
+ }
+
+ /* Set the write data */
+ if (write == 1) {
+ /* Set the write data. */
+ mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_wdata, wdata);
+ }
+
+ /* Send the command. */
+ mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_cmd, (write << 29) | adr);
+
+ if (write == 0) {
+ /*
+ * Wait for Software Interface FSM state to be WFVLDCLR,
+ * read the data and clear the valid flag.
+ */
+ return_value = pwrap_check_vldclr(&mtk_pwrap->wacs2_sta,
+ PWRAP_READ_US);
+ if (return_value != 0) {
+ return return_value;
+ }
+
+ if (rdata == NULL) {
+ return E_PWR_INVALID_ARG;
+ }
+
+ reg_rdata = mmio_read_32((uintptr_t)&mtk_pwrap->wacs2_rdata);
+ *rdata = reg_rdata;
+ mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_vldclr, 0x1);
+ }
+
+ 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);
+}
diff --git a/plat/mediatek/drivers/pmic_wrap/rules.mk b/plat/mediatek/drivers/pmic_wrap/rules.mk
new file mode 100644
index 0000000..9ba44a6
--- /dev/null
+++ b/plat/mediatek/drivers/pmic_wrap/rules.mk
@@ -0,0 +1,20 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := pmic_wrap
+
+ifeq (${USE_PMIC_WRAP_INIT_V2}, 1)
+LOCAL_SRCS-y += ${LOCAL_DIR}/pmic_wrap_init_v2.c
+else
+LOCAL_SRCS-y += ${LOCAL_DIR}/pmic_wrap_init.c
+endif
+
+PLAT_INCLUDES += -I${LOCAL_DIR}/
+PLAT_INCLUDES += -I${LOCAL_DIR}/${MTK_SOC}
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/ptp3/mt8188/ptp3_plat.h b/plat/mediatek/drivers/ptp3/mt8188/ptp3_plat.h
new file mode 100644
index 0000000..aa7d7ca
--- /dev/null
+++ b/plat/mediatek/drivers/ptp3/mt8188/ptp3_plat.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PTP3_PLAT_H
+#define PTP3_PLAT_H
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <ptp3_common.h>
+
+/* CPU Info */
+#define NR_PTP3_CFG_CPU U(8)
+#define PTP3_CFG_CPU_START_ID_L U(0)
+#define PTP3_CFG_CPU_START_ID_B U(6)
+#define PTP3_CFG_CPU_END_ID U(7)
+
+#define NR_PTP3_CFG1_DATA U(2)
+#define PTP3_CFG1_MASK (0x3000)
+
+#define NR_PTP3_CFG2_DATA U(5)
+
+#define PTP3_CFG3_MASK1 (0x1180)
+#define PTP3_CFG3_MASK2 (0x35C0)
+#define PTP3_CFG3_MASK3 (0x3DC0)
+
+
+/* Central control */
+static unsigned int ptp3_cfg1[NR_PTP3_CFG1_DATA][NR_PTP3_CFG] = {
+ {0x0C53A2A0, 0x1000},
+ {0x0C53A2A4, 0x1000}
+};
+
+static unsigned int ptp3_cfg2[NR_PTP3_CFG2_DATA][NR_PTP3_CFG] = {
+ {0x0C530404, 0x3A1000},
+ {0x0C530428, 0x13E0408},
+ {0x0C530434, 0xB22800},
+ {0x0C53043C, 0x750},
+ {0x0C530440, 0x0222c4cc}
+};
+
+static unsigned int ptp3_cfg3[NR_PTP3_CFG] = {0x0C530400, 0xC00};
+static unsigned int ptp3_cfg3_ext[NR_PTP3_CFG] = {0x0C530400, 0xC00};
+
+#endif /* PTP3_PLAT_H */
diff --git a/plat/mediatek/drivers/ptp3/ptp3_common.c b/plat/mediatek/drivers/ptp3/ptp3_common.c
new file mode 100644
index 0000000..6846852
--- /dev/null
+++ b/plat/mediatek/drivers/ptp3/ptp3_common.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#if MTK_PUBEVENT_ENABLE
+#include <lib/pm/mtk_pm.h>
+#endif
+#include <ptp3_plat.h>
+
+#define PTP3_CORE_OFT(core) (0x800 * (core))
+
+static void ptp3_init(unsigned int core)
+{
+ unsigned int i, addr, value;
+
+ if (core < PTP3_CFG_CPU_START_ID_B) {
+ mmio_clrsetbits_32(ptp3_cfg1[0][PTP3_CFG_ADDR], PTP3_CFG1_MASK,
+ ptp3_cfg1[0][PTP3_CFG_VALUE]);
+ } else {
+ mmio_clrsetbits_32(ptp3_cfg1[1][PTP3_CFG_ADDR], PTP3_CFG1_MASK,
+ ptp3_cfg1[1][PTP3_CFG_VALUE]);
+ }
+
+ if (core < PTP3_CFG_CPU_START_ID_B) {
+ for (i = 0; i < NR_PTP3_CFG2_DATA; i++) {
+ addr = ptp3_cfg2[i][PTP3_CFG_ADDR] + PTP3_CORE_OFT(core);
+ value = ptp3_cfg2[i][PTP3_CFG_VALUE];
+
+ mmio_write_32(addr, value);
+ }
+ } else {
+ for (i = 0; i < NR_PTP3_CFG2_DATA; i++) {
+ addr = ptp3_cfg2[i][PTP3_CFG_ADDR] + PTP3_CORE_OFT(core);
+
+ if (i == 2) {
+ value = ptp3_cfg2[i][PTP3_CFG_VALUE] + 0x5E0;
+ } else {
+ value = ptp3_cfg2[i][PTP3_CFG_VALUE];
+ }
+ mmio_write_32(addr, value);
+ }
+ }
+
+ if (core < PTP3_CFG_CPU_START_ID_B) {
+ addr = ptp3_cfg3[PTP3_CFG_ADDR] + PTP3_CORE_OFT(core);
+ value = ptp3_cfg3[PTP3_CFG_VALUE];
+ } else {
+ addr = ptp3_cfg3_ext[PTP3_CFG_ADDR] + PTP3_CORE_OFT(core);
+ value = ptp3_cfg3_ext[PTP3_CFG_VALUE];
+ }
+ mmio_write_32(addr, value & PTP3_CFG3_MASK1);
+ mmio_write_32(addr, value & PTP3_CFG3_MASK2);
+ mmio_write_32(addr, value & PTP3_CFG3_MASK3);
+}
+
+static void pdp_proc_arm_write(unsigned int pdp_n)
+{
+ unsigned long v = 0;
+
+ dsb();
+ __asm__ volatile ("mrs %0, S3_6_C15_C2_0" : "=r" (v));
+ v |= (UL(0x0) << 52);
+ v |= (UL(0x1) << 53);
+ v |= (UL(0x0) << 54);
+ v |= (UL(0x0) << 48);
+ v |= (UL(0x1) << 49);
+ __asm__ volatile ("msr S3_6_C15_C2_0, %0" : : "r" (v));
+ dsb();
+}
+
+static void pdp_init(unsigned int pdp_cpu)
+{
+ if ((pdp_cpu >= PTP3_CFG_CPU_START_ID_B) && (pdp_cpu < NR_PTP3_CFG_CPU)) {
+ pdp_proc_arm_write(pdp_cpu);
+ }
+}
+
+void ptp3_core_init(unsigned int core)
+{
+ ptp3_init(core);
+ pdp_init(core);
+}
+
+void ptp3_core_deinit(unsigned int core)
+{
+ /* TBD */
+}
+
+#if MTK_PUBEVENT_ENABLE
+/* Handle for power on domain */
+void *ptp3_handle_pwr_on_event(const void *arg)
+{
+ if (arg != NULL) {
+ struct mt_cpupm_event_data *data = (struct mt_cpupm_event_data *)arg;
+
+ if ((data->pwr_domain & MT_CPUPM_PWR_DOMAIN_CORE) > 0) {
+ ptp3_core_init(data->cpuid);
+ }
+ }
+ return (void *)arg;
+}
+MT_CPUPM_SUBCRIBE_EVENT_PWR_ON(ptp3_handle_pwr_on_event);
+
+/* Handle for power off domain */
+void *ptp3_handle_pwr_off_event(const void *arg)
+{
+ if (arg != NULL) {
+ struct mt_cpupm_event_data *data = (struct mt_cpupm_event_data *)arg;
+
+ if ((data->pwr_domain & MT_CPUPM_PWR_DOMAIN_CORE) > 0) {
+ ptp3_core_deinit(data->cpuid);
+ }
+ }
+ return (void *)arg;
+}
+MT_CPUPM_SUBCRIBE_EVENT_PWR_OFF(ptp3_handle_pwr_off_event);
+#else
+#pragma message "PSCI hint not enable"
+#endif
diff --git a/plat/mediatek/drivers/ptp3/ptp3_common.h b/plat/mediatek/drivers/ptp3/ptp3_common.h
new file mode 100644
index 0000000..83ce62b
--- /dev/null
+++ b/plat/mediatek/drivers/ptp3/ptp3_common.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PTP3_COMMON_H
+#define PTP3_COMMON_H
+
+/* config enum */
+enum PTP3_CFG {
+ PTP3_CFG_ADDR,
+ PTP3_CFG_VALUE,
+ NR_PTP3_CFG,
+};
+
+/* prototype */
+void ptp3_core_init(unsigned int core);
+void ptp3_core_deinit(unsigned int core);
+
+#endif /* PTP3_COMMON_H */
diff --git a/plat/mediatek/drivers/ptp3/rules.mk b/plat/mediatek/drivers/ptp3/rules.mk
new file mode 100644
index 0000000..81d79d2
--- /dev/null
+++ b/plat/mediatek/drivers/ptp3/rules.mk
@@ -0,0 +1,16 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := mtk_ptp3
+
+LOCAL_SRCS-y := ${LOCAL_DIR}/ptp3_common.c
+
+PLAT_INCLUDES += -I${LOCAL_DIR}
+PLAT_INCLUDES += -I${LOCAL_DIR}/$(MTK_SOC)
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/rtc/mt8188/rtc.h b/plat/mediatek/drivers/rtc/mt8188/rtc.h
new file mode 100644
index 0000000..734e89f
--- /dev/null
+++ b/plat/mediatek/drivers/rtc/mt8188/rtc.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RTC_H
+#define RTC_H
+
+#include <rtc_mt6359p.h>
+
+#endif /* RTC_H */
diff --git a/plat/mediatek/drivers/rtc/rtc_common.c b/plat/mediatek/drivers/rtc/rtc_common.c
new file mode 100644
index 0000000..4efddff
--- /dev/null
+++ b/plat/mediatek/drivers/rtc/rtc_common.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2019-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+
+#include <pmic_wrap_init.h>
+#include <rtc.h>
+
+/* 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;
+}
+
diff --git a/plat/mediatek/drivers/rtc/rtc_mt6359p.c b/plat/mediatek/drivers/rtc/rtc_mt6359p.c
new file mode 100644
index 0000000..3bf4337
--- /dev/null
+++ b/plat/mediatek/drivers/rtc/rtc_mt6359p.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <rtc.h>
+
+
+static void RTC_Config_Interface(uint32_t addr, uint16_t data,
+ uint16_t mask, uint16_t shift)
+{
+ uint16_t pmic_reg;
+
+ pmic_reg = RTC_Read(addr);
+
+ pmic_reg &= ~(mask << shift);
+ pmic_reg |= (data << shift);
+
+ RTC_Write(addr, pmic_reg);
+}
+
+static int32_t 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);
+
+ return RTC_Write_Trigger();
+}
+
+static int32_t rtc_enable_k_eosc(void)
+{
+ uint16_t alm_dow, alm_sec;
+ int16_t ret;
+
+ /* Turning on eosc cali mode clock */
+ RTC_Config_Interface(PMIC_RG_SCK_TOP_CKPDN_CON0_CLR, 1,
+ PMIC_RG_RTC_EOSC32_CK_PDN_MASK,
+ PMIC_RG_RTC_EOSC32_CK_PDN_SHIFT);
+
+ alm_sec = RTC_Read(RTC_AL_SEC) & (~RTC_LPD_OPT_MASK);
+ RTC_Write(RTC_AL_SEC, alm_sec);
+ ret = RTC_Write_Trigger();
+ if (ret == 0) {
+ return 0;
+ }
+
+ RTC_Write(RTC_CON, RTC_LPD_EN);
+ ret = RTC_Write_Trigger();
+ if (ret == 0) {
+ return 0;
+ }
+
+ RTC_Write(RTC_CON, RTC_LPD_RST);
+ ret = RTC_Write_Trigger();
+ if (ret == 0) {
+ return 0;
+ }
+
+ RTC_Write(RTC_CON, RTC_LPD_EN);
+ ret = RTC_Write_Trigger();
+ if (ret == 0) {
+ return 0;
+ }
+
+ RTC_Write(RTC_POWERKEY1, RTC_POWERKEY1_KEY);
+ RTC_Write(RTC_POWERKEY2, RTC_POWERKEY2_KEY);
+ ret = RTC_Write_Trigger();
+ if (ret == 0) {
+ return 0;
+ }
+
+ /* set RTC EOSC calibration period = 8sec */
+ alm_dow = (RTC_Read(RTC_AL_DOW) & (~RTC_RG_EOSC_CALI_TD_MASK)) |
+ RTC_RG_EOSC_CALI_TD_8SEC;
+ RTC_Write(RTC_AL_DOW, alm_dow);
+ ret = RTC_Write_Trigger();
+ if (ret == 0) {
+ return 0;
+ }
+
+ RTC_Write(RTC_BBPU,
+ RTC_Read(RTC_BBPU) | RTC_BBPU_KEY | RTC_BBPU_RELOAD);
+ ret = RTC_Write_Trigger();
+ if (ret == 0) {
+ return 0;
+ }
+
+ /* Enable K EOSC mode :use solution1 of eosc cali to fix mt6359p 32K*/
+ 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)));
+ ret = RTC_Write_Trigger();
+ if (ret == 0) {
+ return 0;
+ }
+
+ INFO("[RTC] RTC_enable_k_eosc\n");
+
+ return 1;
+}
+
+void rtc_power_off_sequence(void)
+{
+ uint16_t bbpu;
+ int16_t ret;
+
+ ret = rtc_disable_2sec_reboot();
+ if (ret == 0) {
+ return;
+ }
+
+ ret = rtc_enable_k_eosc();
+ if (ret == 0) {
+ return;
+ }
+
+ bbpu = RTC_BBPU_KEY | RTC_BBPU_PWREN;
+
+ if (Writeif_unlock() != 0) {
+ RTC_Write(RTC_BBPU,
+ bbpu | RTC_BBPU_RESET_ALARM | RTC_BBPU_RESET_SPAR);
+ RTC_Write(RTC_AL_MASK, RTC_AL_MASK_DOW);
+ ret = RTC_Write_Trigger();
+ if (ret == 0) {
+ return;
+ }
+ mdelay(1);
+
+ bbpu = RTC_Read(RTC_BBPU);
+
+ if (((bbpu & RTC_BBPU_RESET_ALARM) > 0) ||
+ ((bbpu & RTC_BBPU_RESET_SPAR) > 0)) {
+ INFO("[RTC] timeout\n");
+ }
+
+ bbpu = RTC_Read(RTC_BBPU) | RTC_BBPU_KEY | RTC_BBPU_RELOAD;
+ RTC_Write(RTC_BBPU, bbpu);
+ ret = RTC_Write_Trigger();
+ if (ret == 0) {
+ return;
+ }
+ }
+}
diff --git a/plat/mediatek/drivers/rtc/rtc_mt6359p.h b/plat/mediatek/drivers/rtc/rtc_mt6359p.h
new file mode 100644
index 0000000..199f152
--- /dev/null
+++ b/plat/mediatek/drivers/rtc/rtc_mt6359p.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RTC_MT6359P_H
+#define RTC_MT6359P_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_POWERKEY1 = 0x05B0,
+ RTC_POWERKEY2 = 0x05B2
+};
+
+enum {
+ RTC_POWERKEY1_KEY = 0xA357,
+ RTC_POWERKEY2_KEY = 0x67D2
+};
+
+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_LPD_EN = 0x0406,
+ RTC_LPD_RST = 0x040E
+};
+
+enum {
+ RTC_LPD_OPT_XOSC_AND_EOSC_LPD = 0U << 13,
+ RTC_LPD_OPT_EOSC_LPD = 1U << 13,
+ RTC_LPD_OPT_XOSC_LPD = 2U << 13,
+ RTC_LPD_OPT_F32K_CK_ALIVE = 3U << 13,
+};
+
+#define RTC_LPD_OPT_MASK (3U << 13)
+
+enum {
+ RTC_PROT_UNLOCK1 = 0x586A,
+ RTC_PROT_UNLOCK2 = 0x9136
+};
+
+enum {
+ RTC_BBPU_PWREN = 1U << 0,
+ RTC_BBPU_SPAR_SW = 1U << 1,
+ RTC_BBPU_RESET_SPAR = 1U << 2,
+ RTC_BBPU_RESET_ALARM = 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
+};
+
+enum {
+ RTC_RG_EOSC_CALI_TD_1SEC = 3 << 5,
+ RTC_RG_EOSC_CALI_TD_2SEC = 4 << 5,
+ RTC_RG_EOSC_CALI_TD_4SEC = 5 << 5,
+ RTC_RG_EOSC_CALI_TD_8SEC = 6 << 5,
+ RTC_RG_EOSC_CALI_TD_16SEC = 7 << 5,
+ RTC_RG_EOSC_CALI_TD_MASK = 7 << 5
+};
+
+/* PMIC TOP Register Definition */
+enum {
+ PMIC_RG_TOP_CON = 0x0020,
+ 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 = 0x0514,
+ PMIC_RG_SCK_TOP_CKPDN_CON0_SET = 0x0516,
+ PMIC_RG_SCK_TOP_CKPDN_CON0_CLR = 0x0518,
+ PMIC_RG_EOSC_CALI_CON0 = 0x53A
+};
+
+enum {
+ PMIC_EOSC_CALI_START_ADDR = 0x53A
+};
+
+enum {
+ PMIC_EOSC_CALI_START_MASK = 0x1,
+ PMIC_EOSC_CALI_START_SHIFT = 0
+};
+
+/* PMIC DCXO Register Definition */
+enum {
+ PMIC_RG_DCXO_CW00 = 0x0788,
+ PMIC_RG_DCXO_CW02 = 0x0790,
+ PMIC_RG_DCXO_CW08 = 0x079C,
+ PMIC_RG_DCXO_CW09 = 0x079E,
+ PMIC_RG_DCXO_CW09_CLR = 0x07A2,
+ PMIC_RG_DCXO_CW10 = 0x07A4,
+ PMIC_RG_DCXO_CW12 = 0x07A8,
+ PMIC_RG_DCXO_CW13 = 0x07AA,
+ PMIC_RG_DCXO_CW15 = 0x07AE,
+ PMIC_RG_DCXO_CW19 = 0x07B6,
+};
+
+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_MT6359P_H */
diff --git a/plat/mediatek/drivers/rtc/rules.mk b/plat/mediatek/drivers/rtc/rules.mk
new file mode 100644
index 0000000..2398f8a
--- /dev/null
+++ b/plat/mediatek/drivers/rtc/rules.mk
@@ -0,0 +1,20 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := rtc
+
+LOCAL_SRCS-y := ${LOCAL_DIR}/rtc_common.c
+
+ifeq (${USE_RTC_MT6359P}, 1)
+LOCAL_SRCS-y += ${LOCAL_DIR}/rtc_mt6359p.c
+PLAT_INCLUDES += -I${LOCAL_DIR}
+endif
+
+PLAT_INCLUDES += -I${LOCAL_DIR}/${MTK_SOC}
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/timer/mt_timer.c b/plat/mediatek/drivers/timer/mt_timer.c
new file mode 100644
index 0000000..11e4572
--- /dev/null
+++ b/plat/mediatek/drivers/timer/mt_timer.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/mtk_init/mtk_init.h>
+#include <mt_timer.h>
+#include <platform_def.h>
+
+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;
+ uint64_t rel_base;
+
+ rel_base = read_cntpct_el0() - atf_time_base;
+ cval = ((rel_base * 1000U) / SYS_COUNTER_FREQ_IN_MHZ)
+ - normal_time_base;
+ return cval;
+}
+
+int mt_systimer_init(void)
+{
+ INFO("[%s] systimer initialization\n", __func__);
+
+ /* Enable access in NS mode */
+ mmio_write_32(CNTWACR_REG, CNT_WRITE_ACCESS_CTL_MASK);
+ mmio_write_32(CNTRACR_REG, CNT_READ_ACCESS_CTL_MASK);
+
+ return 0;
+}
+MTK_PLAT_SETUP_0_INIT(mt_systimer_init);
diff --git a/plat/mediatek/drivers/timer/mt_timer.h b/plat/mediatek/drivers/timer/mt_timer.h
new file mode 100644
index 0000000..1c08f90
--- /dev/null
+++ b/plat/mediatek/drivers/timer/mt_timer.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_TIMER_H
+#define MT_TIMER_H
+
+#define SYSTIMER_BASE (0x10017000)
+#define CNTCR_REG (SYSTIMER_BASE + 0x0)
+#define CNTSR_REG (SYSTIMER_BASE + 0x4)
+#define CNTSYS_L_REG (SYSTIMER_BASE + 0x8)
+#define CNTSYS_H_REG (SYSTIMER_BASE + 0xc)
+#define CNTWACR_REG (SYSTIMER_BASE + 0x10)
+#define CNTRACR_REG (SYSTIMER_BASE + 0x14)
+
+#define TIEO_EN (1 << 3)
+#define COMP_15_EN (1 << 10)
+#define COMP_20_EN (1 << 11)
+#define COMP_25_EN (1 << 12)
+
+#define COMP_FEATURE_MASK (COMP_15_EN | COMP_20_EN | COMP_25_EN | TIEO_EN)
+#define COMP_15_MASK (COMP_15_EN)
+#define COMP_20_MASK (COMP_20_EN | TIEO_EN)
+#define COMP_25_MASK (COMP_20_EN | COMP_25_EN)
+
+#define CNT_WRITE_ACCESS_CTL_MASK (0x3FFFFF0U)
+#define CNT_READ_ACCESS_CTL_MASK (0x3FFFFFFU)
+
+void sched_clock_init(uint64_t normal_base, uint64_t atf_base);
+uint64_t sched_clock(void);
+int mt_systimer_init(void);
+
+#endif /* MT_TIMER_H */
diff --git a/plat/mediatek/drivers/timer/rules.mk b/plat/mediatek/drivers/timer/rules.mk
new file mode 100644
index 0000000..005cf45
--- /dev/null
+++ b/plat/mediatek/drivers/timer/rules.mk
@@ -0,0 +1,14 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := timer
+LOCAL_SRCS-y := $(LOCAL_DIR)/mt_timer.c
+
+PLAT_INCLUDES += -I${LOCAL_DIR}
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/uart/8250_console.S b/plat/mediatek/drivers/uart/8250_console.S
new file mode 100644
index 0000000..66f998d
--- /dev/null
+++ b/plat/mediatek/drivers/uart/8250_console.S
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <asm_macros.S>
+#include <uart8250.h>
+
+ .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
+
+ /* ---------------------------------------------
+ * void 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 : void.
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func console_core_flush
+ /* Placeholder */
+ ret
+endfunc console_core_flush
diff --git a/plat/mediatek/drivers/uart/uart.c b/plat/mediatek/drivers/uart/uart.c
new file mode 100644
index 0000000..fdaa793
--- /dev/null
+++ b/plat/mediatek/drivers/uart/uart.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <uart.h>
+
+static struct mt_uart uart_save_addr[DRV_SUPPORT_UART_PORTS];
+
+static const uint32_t 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 == 1) {
+ mmio_write_32(UART_CLOCK_GATE_CLR, UART0_CLOCK_GATE_BIT);
+ } else {
+ mmio_write_32(UART_CLOCK_GATE_SET, UART0_CLOCK_GATE_BIT);
+ }
+}
+
+uint32_t mt_console_uart_cg_status(void)
+{
+ return mmio_read_32(UART_CLOCK_GATE_STA) & UART0_CLOCK_GATE_BIT;
+}
diff --git a/plat/mediatek/drivers/uart/uart.h b/plat/mediatek/drivers/uart/uart.h
new file mode 100644
index 0000000..2ca74fa
--- /dev/null
+++ b/plat/mediatek/drivers/uart/uart.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef UART_H
+#define UART_H
+
+#include <platform_def.h>
+
+/* 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 {
+ uint32_t dll;
+ uint32_t dlh;
+ uint32_t ier;
+ uint32_t lcr;
+ uint32_t mcr;
+ uint32_t fcr;
+ uint32_t lsr;
+ uint32_t scr;
+ uint32_t efr;
+ uint32_t highspeed;
+ uint32_t sample_count;
+ uint32_t sample_point;
+ uint32_t fracdiv_l;
+ uint32_t fracdiv_m;
+ uint32_t escape_en;
+ uint32_t guard;
+ uint32_t 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);
+uint32_t mt_console_uart_cg_status(void);
+
+#endif /* __UART_H__ */
diff --git a/plat/mediatek/drivers/uart/uart8250.h b/plat/mediatek/drivers/uart/uart8250.h
new file mode 100644
index 0000000..f0541d6
--- /dev/null
+++ b/plat/mediatek/drivers/uart/uart8250.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015-2022, 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 */
diff --git a/plat/mediatek/helpers/armv8_2/arch_helpers.S b/plat/mediatek/helpers/armv8_2/arch_helpers.S
new file mode 100644
index 0000000..02d8d53
--- /dev/null
+++ b/plat/mediatek/helpers/armv8_2/arch_helpers.S
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2022, Mediatek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cpu_macros.S>
+#if CONFIG_MTK_MCUSYS
+#include <mcucfg.h>
+#endif
+#include <platform_def.h>
+ /*
+ * Declare as weak function so that can be
+ * overwritten by platform helpers
+ */
+ .weak platform_mem_init
+ .weak plat_core_pos_by_mpidr
+ .weak plat_my_core_pos
+ .weak plat_mediatek_calc_core_pos
+ .global plat_mpidr_by_core_pos
+ .global plat_reset_handler
+
+ /* -----------------------------------------------------
+ * unsigned long plat_mpidr_by_core_pos(uint32_t cpuid)
+ * This function calcuate mpidr by cpu pos if cpu
+ * topology is linear.
+ *
+ * Clobbers: x0-x1
+ * -----------------------------------------------------
+ */
+func plat_mpidr_by_core_pos
+ lsl x0, x0, #MPIDR_AFF1_SHIFT
+ mrs x1, mpidr_el1
+ and x1, x1, #MPIDR_MT_MASK
+ orr x0, x0, x1
+ ret
+endfunc plat_mpidr_by_core_pos
+
+ /* -----------------------------------------------------
+ * 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_mediatek_calc_core_pos
+endfunc plat_my_core_pos
+
+ /* -----------------------------------------------------
+ * int plat_mediatek_calc_core_pos(u_register_t mpidr);
+ *
+ * In ARMv8.2, AFF2 is cluster id, AFF1 is core id and
+ * AFF0 is thread id. There is only one cluster in ARMv8.2
+ * and one thread in current implementation.
+ *
+ * With this function: CorePos = CoreID (AFF1)
+ * we do it with x0 = (x0 >> 8) & 0xff
+ * -----------------------------------------------------
+ */
+func plat_mediatek_calc_core_pos
+ b plat_core_pos_by_mpidr
+endfunc plat_mediatek_calc_core_pos
+
+ /* ------------------------------------------------------
+ * int32_t plat_core_pos_by_mpidr(u_register_t 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.
+ *
+ * Clobbers: x0-x1
+ * ------------------------------------------------------
+ */
+func plat_core_pos_by_mpidr
+ mov x1, #MPIDR_AFFLVL_MASK
+ and x0, x1, x0, lsr #MPIDR_AFF1_SHIFT
+ ret
+endfunc plat_core_pos_by_mpidr
+
+ /* --------------------------------------------------------
+ * 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
+
+func plat_reset_handler
+#if CONFIG_MTK_MCUSYS
+ mov x10, x30
+ bl plat_my_core_pos
+ mov x30, x10
+ mov w1, #0x1
+ lsl w1, w1, w0
+ ldr x0, =CPC_MCUSYS_CPU_ON_SW_HINT_SET
+ str w1, [x0]
+ dsb sy
+#endif
+
+#if CONFIG_MTK_ECC
+ mov x10, x30
+ /* enable sequence of ecc for cpus */
+ bl disable_core_ecc
+ bl ft_ecc_clear_per_core
+ bl enable_core_ecc
+ mov x30, x10
+#endif
+
+ ret
+endfunc plat_reset_handler
diff --git a/plat/mediatek/helpers/rules.mk b/plat/mediatek/helpers/rules.mk
new file mode 100644
index 0000000..ae8068e
--- /dev/null
+++ b/plat/mediatek/helpers/rules.mk
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := helpers
+LOCAL_SRCS-y += $(LOCAL_DIR)/$(ARCH_VERSION)/arch_helpers.S
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/include/armv8_2/arch_def.h b/plat/mediatek/include/armv8_2/arch_def.h
new file mode 100644
index 0000000..61f818f
--- /dev/null
+++ b/plat/mediatek/include/armv8_2/arch_def.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022, Mediatek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARCH_DEF_H
+#define ARCH_DEF_H
+
+/* Topology constants */
+#define PLAT_MAX_PWR_LVL (2)
+#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 (8)
+#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER (8)
+#define PLATFORM_NUM_AFFS (PLATFORM_SYSTEM_COUNT + \
+ PLATFORM_CLUSTER_COUNT + \
+ PLATFORM_CORE_COUNT)
+
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+/* Cachline size */
+#define CACHE_WRITEBACK_SHIFT (6)
+#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
+
+#endif /* ARCH_DEF_H */
+
diff --git a/plat/mediatek/include/lib/mtk_init/mtk_init.h b/plat/mediatek/include/lib/mtk_init/mtk_init.h
new file mode 100644
index 0000000..6f23a9b
--- /dev/null
+++ b/plat/mediatek/include/lib/mtk_init/mtk_init.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_INIT_H
+#define MTK_INIT_H
+
+#include <cdefs.h>
+#include <lib/mtk_init/mtk_init_def.h>
+
+#define INIT_CALL_EXPAND_AS_ENUMERATION(_section_enum, _section_name, _level) \
+ _section_enum = _level,
+
+#define EXPAND_AS_LINK_SECTION(_section_enum, _section_name, _level) \
+ __##_section_enum##_START__ = .; \
+ KEEP(*(_section_name##_level));
+
+#define EXPAND_AS_EXTERN(_section_enum, _section_name, _level) \
+ extern struct initcall __##_section_enum##_START__[];
+
+#define EXPAND_AS_SYMBOL_ARR(_section_enum, _section_name, _level) \
+ __##_section_enum##_START__,
+
+#define DECLARE_MTK_INITCALL(_fn, _level) \
+ const struct initcall _mtk_initcall_##_fn \
+ __used \
+ __aligned(sizeof(void *)) \
+ __section(".mtk_plat_initcall_"#_level) \
+ = { \
+ .name = #_fn, \
+ .fn = _fn \
+ }
+
+/* initcall helpers */
+#define MTK_EARLY_PLAT_INIT(_fn) DECLARE_MTK_INITCALL(_fn, 0)
+#define MTK_ARCH_INIT(_fn) DECLARE_MTK_INITCALL(_fn, 1)
+#define MTK_PLAT_SETUP_0_INIT(_fn) DECLARE_MTK_INITCALL(_fn, 2)
+#define MTK_PLAT_SETUP_1_INIT(_fn) DECLARE_MTK_INITCALL(_fn, 3)
+#define MTK_PLAT_RUNTIME_INIT(_fn) DECLARE_MTK_INITCALL(_fn, 4)
+#define MTK_PLAT_BL33_DEFER_INIT(_fn) DECLARE_MTK_INITCALL(_fn, 5)
+
+#ifndef __ASSEMBLER__
+struct initcall {
+ const char *name;
+ int (*fn)(void);
+};
+
+enum {
+ INIT_CALL_TABLE(INIT_CALL_EXPAND_AS_ENUMERATION)
+ MTK_INIT_LVL_MAX
+};
+
+void mtk_init_one_level(unsigned int level);
+#endif
+
+#endif /* MTK_INIT_H */
diff --git a/plat/mediatek/include/lib/mtk_init/mtk_init_def.h b/plat/mediatek/include/lib/mtk_init/mtk_init_def.h
new file mode 100644
index 0000000..8aae41d
--- /dev/null
+++ b/plat/mediatek/include/lib/mtk_init/mtk_init_def.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_INIT_DEF_H
+#define MTK_INIT_DEF_H
+
+/*
+ * Define init call sections here. _func is for 2nd level expansion, init
+ * section enum, and init section name.
+ */
+#define INIT_CALL_TABLE(_func) \
+ _func(MTK_INIT_LVL_EARLY_PLAT, .mtk_plat_initcall_, 0) \
+ _func(MTK_INIT_LVL_ARCH, .mtk_plat_initcall_, 1) \
+ _func(MTK_INIT_LVL_PLAT_SETUP_0, .mtk_plat_initcall_, 2) \
+ _func(MTK_INIT_LVL_PLAT_SETUP_1, .mtk_plat_initcall_, 3) \
+ _func(MTK_INIT_LVL_PLAT_RUNTIME, .mtk_plat_initcall_, 4) \
+ _func(MTK_INIT_LVL_BL33_DEFER, .mtk_plat_initcall_, 5)
+
+#endif /* MTK_INIT_DEF_H */
diff --git a/plat/mediatek/include/mtk_mmap_pool.h b/plat/mediatek/include/mtk_mmap_pool.h
new file mode 100644
index 0000000..99d1bff
--- /dev/null
+++ b/plat/mediatek/include/mtk_mmap_pool.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_MMAP_POOL_H
+#define MTK_MMAP_POOL_H
+
+#include <cdefs.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+
+struct mtk_mmap_descriptor {
+ const char *mmap_name;
+ const mmap_region_t *mmap_ptr;
+ const uint32_t mmap_size;
+};
+
+#define MTK_MMAP_SECTION \
+ __used \
+ __aligned(sizeof(void *)) \
+ __section(".mtk_mmap_lists")
+
+#define DECLARE_MTK_MMAP_REGIONS(_mmap_array) \
+ static const struct mtk_mmap_descriptor _mtk_mmap_descriptor_##_mmap_array \
+ __used \
+ __aligned(sizeof(void *)) \
+ __section(".mtk_mmap_pool") \
+ = { \
+ .mmap_name = #_mmap_array, \
+ .mmap_ptr = _mmap_array, \
+ .mmap_size = ARRAY_SIZE(_mmap_array) \
+ }
+
+#define MAP_BL_RW MAP_REGION_FLAT( \
+ DATA_START, \
+ BL_END - DATA_START, \
+ MT_MEMORY | MT_RW | MT_SECURE)
+
+#if SEPARATE_CODE_AND_RODATA
+#define 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 MAP_BL_RO MAP_REGION_FLAT(BL_CODE_BASE, \
+ BL_CODE_END - BL_CODE_BASE, \
+ MT_CODE | MT_SECURE)
+#endif
+
+void mtk_xlat_init(const mmap_region_t *bl_regions);
+
+#endif /* MTK_MMAP_POOL_H */
diff --git a/plat/mediatek/include/mtk_sip_def.h b/plat/mediatek/include/mtk_sip_def.h
new file mode 100644
index 0000000..2039017
--- /dev/null
+++ b/plat/mediatek/include/mtk_sip_def.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_SIP_DEF_H
+#define MTK_SIP_DEF_H
+
+/* Define SiP SMC ID here */
+#define MTK_SIP_SMC_FROM_NS_EL1_TABLE(_func) \
+ _func(MTK_SIP_KERNEL_TIME_SYNC, 0x202) \
+ _func(MTK_SIP_KERNEL_DFD, 0x205) \
+ _func(MTK_SIP_KERNEL_MSDC, 0x273) \
+ _func(MTK_SIP_VCORE_CONTROL, 0x506) \
+ _func(MTK_SIP_IOMMU_CONTROL, 0x514) \
+ _func(MTK_SIP_AUDIO_CONTROL, 0x517) \
+ _func(MTK_SIP_APUSYS_CONTROL, 0x51E) \
+ _func(MTK_SIP_DP_CONTROL, 0x523) \
+ _func(MTK_SIP_KERNEL_GIC_OP, 0x526)
+
+#define MTK_SIP_SMC_FROM_BL33_TABLE(_func) \
+ _func(MTK_SIP_KERNEL_BOOT, 0x115)
+
+#endif /* MTK_SIP_DEF_H */
diff --git a/plat/mediatek/include/mtk_sip_svc.h b/plat/mediatek/include/mtk_sip_svc.h
new file mode 100644
index 0000000..ce51048
--- /dev/null
+++ b/plat/mediatek/include/mtk_sip_svc.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_SIP_SVC_H
+#define MTK_SIP_SVC_H
+
+#include <stdint.h>
+#include <lib/smccc.h>
+#include <mtk_sip_def.h>
+
+/* SMC function IDs for SiP Service queries */
+#define SIP_SVC_CALL_COUNT U(0x8200ff00)
+#define SIP_SVC_UID U(0x8200ff01)
+/* 0x8200ff02 is reserved */
+#define SIP_SVC_VERSION U(0x8200ff03)
+
+/* MediaTek SiP Service Calls version numbers */
+#define MTK_SIP_SVC_VERSION_MAJOR U(0x0)
+#define MTK_SIP_SVC_VERSION_MINOR U(0x1)
+
+/* Number of MediaTek SiP Calls implemented */
+#define MTK_COMMON_SIP_NUM_CALLS U(4)
+
+/* MediaTek SiP Service Calls function IDs */
+#define MTK_SIP_SET_AUTHORIZED_SECURE_REG U(0x82000001)
+
+#define SMC_ID_EXPAND_AS_ENUM(_smc_id, _smc_num) \
+ _smc_id##_AARCH32 = ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT) | \
+ ((0) << FUNCID_CC_SHIFT) | \
+ (OEN_SIP_START << FUNCID_OEN_SHIFT) | \
+ ((_smc_num) << FUNCID_NUM_SHIFT)), \
+ _smc_id##_AARCH64 = ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT) | \
+ ((1) << FUNCID_CC_SHIFT) | \
+ (OEN_SIP_START << FUNCID_OEN_SHIFT) | \
+ ((_smc_num) << FUNCID_NUM_SHIFT)),
+
+#define SMC_ID_EXPAND_AS_EXTERN_SMC_INDEX(_smc_id, _smc_num) \
+ extern short _smc_id##_descriptor_index;
+
+/* Bind SMC handler with SMC ID */
+#define DECLARE_SMC_HANDLER(_smc_id, _smc_handler) \
+ const struct smc_descriptor _smc_id##_descriptor \
+ __used \
+ __aligned(sizeof(void *)) \
+ __section(".mtk_smc_descriptor_pool") = { \
+ .smc_handler = _smc_handler, \
+ .smc_name = #_smc_id, \
+ .smc_id_aarch32 = _smc_id##_AARCH32, \
+ .smc_id_aarch64 = _smc_id##_AARCH64, \
+ .smc_descriptor_index = &_smc_id##_descriptor_index \
+ }
+
+MTK_SIP_SMC_FROM_BL33_TABLE(SMC_ID_EXPAND_AS_EXTERN_SMC_INDEX);
+MTK_SIP_SMC_FROM_NS_EL1_TABLE(SMC_ID_EXPAND_AS_EXTERN_SMC_INDEX);
+
+/* Expand SiP SMC ID table as enum */
+enum {
+ MTK_SIP_SMC_FROM_BL33_TABLE(SMC_ID_EXPAND_AS_ENUM)
+ MTK_SIP_SMC_FROM_NS_EL1_TABLE(SMC_ID_EXPAND_AS_ENUM)
+ MTK_SIP_SMC_MAX_NUMBER
+};
+
+/* 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,
+};
+
+struct smccc_res {
+ uint64_t a1;
+ uint64_t a2;
+ uint64_t a3;
+};
+
+typedef uintptr_t (*smc_handler_t)(u_register_t,
+ u_register_t,
+ u_register_t,
+ u_register_t,
+ void *,
+ struct smccc_res *);
+
+struct smc_descriptor {
+ smc_handler_t smc_handler;
+ const uint32_t smc_id_aarch32;
+ const uint32_t smc_id_aarch64;
+ const char *smc_name;
+ short *const smc_descriptor_index;
+};
+
+/*
+ * 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 */
diff --git a/plat/mediatek/include/plat.ld.rodata.inc b/plat/mediatek/include/plat.ld.rodata.inc
new file mode 100644
index 0000000..06ad491
--- /dev/null
+++ b/plat/mediatek/include/plat.ld.rodata.inc
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_LD_RODATA_INC
+#define PLAT_LD_RODATA_INC
+
+#include <lib/mtk_init/mtk_init.h>
+ . = ALIGN(32);
+ INIT_CALL_TABLE(EXPAND_AS_LINK_SECTION);
+ __MTK_PLAT_INITCALL_END__ = .;
+ . = ALIGN(32);
+ __MTK_MMAP_POINTER_POOL_START__ = .;
+ KEEP(*(.mtk_mmap_pool))
+ __MTK_MMAP_POINTER_POOL_END_UNALIGNED__ = .;
+ . = ALIGN(8);
+ __MTK_MMAP_POOL_START__ = .;
+ KEEP(*(.mtk_mmap_lists))
+ __MTK_MMAP_POOL_END_UNALIGNED__ = .;
+ . = ALIGN(32);
+ __MTK_SMC_POOL_START__ = .;
+ KEEP(*(.mtk_smc_descriptor_pool))
+ __MTK_SMC_POOL_END_UNALIGNED__ = .;
+ . = ALIGN(8);
+#include <vendor_pubsub_events.h>
+ *(mtk_plat_ro)
+
+#endif /* PLAT_LD_RODATA_INC */
diff --git a/plat/mediatek/include/vendor_pubsub_events.h b/plat/mediatek/include/vendor_pubsub_events.h
new file mode 100644
index 0000000..cb8d878
--- /dev/null
+++ b/plat/mediatek/include/vendor_pubsub_events.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef VENDOR_PUBSUB_EVENTS_H
+#define VENDOR_PUBSUB_EVENTS_H
+
+#include <lib/el3_runtime/pubsub.h>
+
+REGISTER_PUBSUB_EVENT(lpm_publish_event);
+REGISTER_PUBSUB_EVENT(suspend_publish_event);
+REGISTER_PUBSUB_EVENT(mt_cpupm_publish_pwr_on);
+REGISTER_PUBSUB_EVENT(mt_cpupm_publish_pwr_off);
+REGISTER_PUBSUB_EVENT(mt_cpupm_publish_afflv_pwr_on);
+REGISTER_PUBSUB_EVENT(mt_cpupm_publish_afflv_pwr_off);
+REGISTER_PUBSUB_EVENT(publish_check_wakeup_irq);
+REGISTER_PUBSUB_EVENT(watchdog_timeout);
+
+#endif /* VENDOR_PUBSUB_EVENTS_H */
diff --git a/plat/mediatek/lib/mtk_init/mtk_init.c b/plat/mediatek/lib/mtk_init/mtk_init.c
new file mode 100644
index 0000000..2289659
--- /dev/null
+++ b/plat/mediatek/lib/mtk_init/mtk_init.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/utils_def.h>
+#include <lib/mtk_init/mtk_init.h>
+
+INIT_CALL_TABLE(EXPAND_AS_EXTERN);
+extern struct initcall __MTK_PLAT_INITCALL_END__[];
+
+struct initcall *initcall_list[] = {
+ INIT_CALL_TABLE(EXPAND_AS_SYMBOL_ARR)
+ __MTK_PLAT_INITCALL_END__
+};
+
+void mtk_init_one_level(uint32_t level)
+{
+ const struct initcall *entry;
+ int error;
+
+ if (level >= MTK_INIT_LVL_MAX) {
+ ERROR("invalid level:%u\n", level);
+ panic();
+ }
+
+ INFO("init calling level:%u\n", level);
+ for (entry = initcall_list[level];
+ (entry != NULL) && (entry < initcall_list[level + 1]);
+ entry++) {
+ INFO("calling %s\n", entry->name);
+ error = entry->fn();
+ if (error != 0) {
+ ERROR("init %s fail, errno:%d\n", entry->name, error);
+ }
+ }
+}
diff --git a/plat/mediatek/lib/mtk_init/mtk_mmap_init.c b/plat/mediatek/lib/mtk_init/mtk_mmap_init.c
new file mode 100644
index 0000000..e3dada0
--- /dev/null
+++ b/plat/mediatek/lib/mtk_init/mtk_mmap_init.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+#include <mtk_mmap_pool.h>
+
+IMPORT_SYM(uintptr_t, __MTK_MMAP_POINTER_POOL_START__, MTK_MMAP_POINTER_POOL_START);
+IMPORT_SYM(uintptr_t, __MTK_MMAP_POINTER_POOL_END_UNALIGNED__, MTK_MMAP_POINTER_POOL_END_UNALIGNED);
+IMPORT_SYM(uintptr_t, __RW_START__, RW_START);
+IMPORT_SYM(uintptr_t, __DATA_START__, DATA_START);
+
+#define MAP_MTK_SECTIONS MAP_REGION_FLAT(RW_START, \
+ DATA_START - RW_START, \
+ MT_MEMORY | MT_RO | MT_SECURE)
+
+
+static void print_mmap(const mmap_region_t *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++;
+ }
+}
+
+void mtk_xlat_init(const mmap_region_t *bl_regions)
+{
+ struct mtk_mmap_descriptor *iter;
+ const mmap_region_t *regions = bl_regions;
+
+ print_mmap(regions);
+ mmap_add(bl_regions);
+ if (MTK_MMAP_POINTER_POOL_START != MTK_MMAP_POINTER_POOL_END_UNALIGNED) {
+ for (iter = (struct mtk_mmap_descriptor *)MTK_MMAP_POINTER_POOL_START;
+ (char *)iter < (char *)MTK_MMAP_POINTER_POOL_END_UNALIGNED;
+ iter++) {
+ regions = iter->mmap_ptr;
+ INFO("mmap_name: %s\n", iter->mmap_name);
+ INFO("mmap_size: 0x%x\n", iter->mmap_size);
+ print_mmap(regions);
+ mmap_add(regions);
+ }
+ }
+ init_xlat_tables();
+ enable_mmu_el3(0);
+}
diff --git a/plat/mediatek/lib/mtk_init/rules.mk b/plat/mediatek/lib/mtk_init/rules.mk
new file mode 100644
index 0000000..cc6ca95
--- /dev/null
+++ b/plat/mediatek/lib/mtk_init/rules.mk
@@ -0,0 +1,14 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := mtk_init
+
+LOCAL_SRCS-y := $(LOCAL_DIR)/mtk_init.c
+LOCAL_SRCS-y += $(LOCAL_DIR)/mtk_mmap_init.c
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/lib/pm/armv8_2/pwr_ctrl.c b/plat/mediatek/lib/pm/armv8_2/pwr_ctrl.c
new file mode 100644
index 0000000..447234a
--- /dev/null
+++ b/plat/mediatek/lib/pm/armv8_2/pwr_ctrl.c
@@ -0,0 +1,543 @@
+/*
+ * Copyright (c) 2022, Mediatek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/psci/psci.h>
+#include <lib/utils.h>
+#ifdef MTK_PUBEVENT_ENABLE
+#include <vendor_pubsub_events.h>
+#endif
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#include <dfd.h>
+#include <lib/mtk_init/mtk_init.h>
+#include <lib/pm/mtk_pm.h>
+#include <mt_gic_v3.h>
+#include <platform_def.h>
+
+#define IS_AFFLV_PUBEVENT(_pstate) \
+ ((_pstate & (MT_CPUPM_PWR_DOMAIN_MCUSYS | MT_CPUPM_PWR_DOMAIN_CLUSTER)) != 0)
+
+#ifdef MTK_PUBEVENT_ENABLE
+#define MT_CPUPM_EVENT_PWR_ON(x) ({ \
+ PUBLISH_EVENT_ARG(mt_cpupm_publish_pwr_on, (const void *)(x)); })
+
+#define MT_CPUPM_EVENT_PWR_OFF(x) ({ \
+ PUBLISH_EVENT_ARG(mt_cpupm_publish_pwr_off, (const void *)(x)); })
+
+#define MT_CPUPM_EVENT_AFFLV_PWR_ON(x) ({ \
+ PUBLISH_EVENT_ARG(mt_cpupm_publish_afflv_pwr_on, (const void *)(x)); })
+
+#define MT_CPUPM_EVENT_AFFLV_PWR_OFF(x) ({ \
+ PUBLISH_EVENT_ARG(mt_cpupm_publish_afflv_pwr_off, (const void *)(x)); })
+
+#else
+#define MT_CPUPM_EVENT_PWR_ON(x) ({ (void)x; })
+#define MT_CPUPM_EVENT_PWR_OFF(x) ({ (void)x; })
+#define MT_CPUPM_EVENT_AFFLV_PWR_ON(x) ({ (void)x; })
+#define MT_CPUPM_EVENT_AFFLV_PWR_OFF(x) ({ (void)x; })
+#endif
+
+/*
+ * The cpu require to cluster power stattus
+ * [0] : The cpu require cluster power down
+ * [1] : The cpu require cluster power on
+ */
+#define coordinate_cluster(onoff) write_clusterpwrdn_el1(onoff)
+#define coordinate_cluster_pwron() coordinate_cluster(1)
+#define coordinate_cluster_pwroff() coordinate_cluster(0)
+
+/* defaultly disable all functions */
+#define MTK_CPUPM_FN_MASK_DEFAULT (0)
+
+struct mtk_cpu_pwr_ctrl {
+ unsigned int fn_mask;
+ struct mtk_cpu_pm_ops *ops;
+ struct mtk_cpu_smp_ops *smp;
+};
+
+static struct mtk_cpu_pwr_ctrl mtk_cpu_pwr = {
+ .fn_mask = MTK_CPUPM_FN_MASK_DEFAULT,
+ .ops = NULL,
+};
+
+#define IS_CPUIDLE_FN_ENABLE(x) ((mtk_cpu_pwr.ops != NULL) && ((mtk_cpu_pwr.fn_mask & x) != 0))
+#define IS_CPUSMP_FN_ENABLE(x) ((mtk_cpu_pwr.smp != NULL) && ((mtk_cpu_pwr.fn_mask & x) != 0))
+
+/* per-cpu power state */
+static unsigned int armv8_2_power_state[PLATFORM_CORE_COUNT];
+
+#define armv8_2_get_pwr_stateid(cpu) psci_get_pstate_id(armv8_2_power_state[cpu])
+
+static unsigned int get_mediatek_pstate(unsigned int domain, unsigned int psci_state,
+ struct mtk_cpupm_pwrstate *state)
+{
+ if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_CPUPM_GET_PWR_STATE)) {
+ return mtk_cpu_pwr.ops->get_pstate(domain, psci_state, state);
+ }
+
+ return 0;
+}
+
+unsigned int armv8_2_get_pwr_afflv(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;
+}
+
+/* MediaTek mcusys power on control interface */
+static void armv8_2_mcusys_pwr_on_common(const struct mtk_cpupm_pwrstate *state)
+{
+ gicv3_distif_init();
+ mt_gic_distif_restore();
+ gic_sgi_restore_all();
+
+ dfd_resume();
+
+ /* Add code here that behavior before system enter mcusys'on */
+ if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_RESUME_MCUSYS)) {
+ mtk_cpu_pwr.ops->mcusys_resume(state);
+ }
+}
+
+/* MediaTek mcusys power down control interface */
+static void armv8_2_mcusys_pwr_dwn_common(const struct mtk_cpupm_pwrstate *state)
+{
+ mt_gic_distif_save();
+ gic_sgi_save_all();
+
+ /* Add code here that behaves before entering mcusys off */
+ if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_SUSPEND_MCUSYS)) {
+ mtk_cpu_pwr.ops->mcusys_suspend(state);
+ }
+}
+
+/* MediaTek Cluster power on control interface */
+static void armv8_2_cluster_pwr_on_common(const struct mtk_cpupm_pwrstate *state)
+{
+ /* Add code here that behavior before system enter cluster'on */
+#if defined(MTK_CM_MGR) && !defined(MTK_FPGA_EARLY_PORTING)
+ /* init cpu stall counter */
+ init_cpu_stall_counter_all();
+#endif
+
+ if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_RESUME_CLUSTER)) {
+ mtk_cpu_pwr.ops->cluster_resume(state);
+ }
+}
+
+/* MediaTek Cluster power down control interface */
+static void armv8_2_cluster_pwr_dwn_common(const struct mtk_cpupm_pwrstate *state)
+{
+ if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_SUSPEND_CLUSTER)) {
+ mtk_cpu_pwr.ops->cluster_suspend(state);
+ }
+}
+
+/* MediaTek CPU power on control interface */
+static void armv8_2_cpu_pwr_on_common(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
+{
+ coordinate_cluster_pwron();
+
+ gicv3_rdistif_init(plat_my_core_pos());
+ gicv3_cpuif_enable(plat_my_core_pos());
+
+ /* If MCUSYS has been powered down then restore GIC redistributor for all CPUs. */
+ if (IS_PLAT_SYSTEM_RETENTION(state->pwr.afflv)) {
+ mt_gic_rdistif_restore_all();
+ } else {
+ mt_gic_rdistif_restore();
+ }
+}
+
+/* MediaTek CPU power down control interface */
+static void armv8_2_cpu_pwr_dwn_common(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
+{
+ if ((pstate & MT_CPUPM_PWR_DOMAIN_PERCORE_DSU) != 0) {
+ coordinate_cluster_pwroff();
+ }
+
+ mt_gic_rdistif_save();
+ gicv3_cpuif_disable(plat_my_core_pos());
+ gicv3_rdistif_off(plat_my_core_pos());
+}
+
+static void armv8_2_cpu_pwr_resume(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
+{
+ armv8_2_cpu_pwr_on_common(state, pstate);
+ if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_RESUME_CORE)) {
+ mtk_cpu_pwr.ops->cpu_resume(state);
+ }
+}
+
+static void armv8_2_cpu_pwr_suspend(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
+{
+ if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_SUSPEND_CORE)) {
+ mtk_cpu_pwr.ops->cpu_suspend(state);
+ }
+ armv8_2_cpu_pwr_dwn_common(state, pstate);
+}
+
+static void armv8_2_cpu_pwr_on(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
+{
+ armv8_2_cpu_pwr_on_common(state, pstate);
+
+ if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_SMP_CORE_ON)) {
+ mtk_cpu_pwr.smp->cpu_on(state);
+ }
+}
+
+static void armv8_2_cpu_pwr_off(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
+{
+ if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_SMP_CORE_OFF)) {
+ mtk_cpu_pwr.smp->cpu_off(state);
+ }
+ armv8_2_cpu_pwr_dwn_common(state, pstate);
+}
+
+/* MediaTek PSCI power domain */
+static int armv8_2_power_domain_on(u_register_t mpidr)
+{
+ int ret = PSCI_E_SUCCESS;
+ int cpu = plat_core_pos_by_mpidr(mpidr);
+ uintptr_t entry = plat_pm_get_warm_entry();
+
+ if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_PWR_ON_CORE_PREPARE)) {
+ if (mtk_cpu_pwr.smp->cpu_pwr_on_prepare(cpu, entry) != 0) {
+ ret = PSCI_E_DENIED;
+ }
+ }
+ INFO("CPU %u power domain prepare on\n", cpu);
+ return ret;
+}
+
+/* MediaTek PSCI power domain */
+static void armv8_2_power_domain_on_finish(const psci_power_state_t *state)
+{
+ struct mt_cpupm_event_data nb;
+ unsigned int pstate = (MT_CPUPM_PWR_DOMAIN_CORE | MT_CPUPM_PWR_DOMAIN_PERCORE_DSU);
+ struct mtk_cpupm_pwrstate pm_state = {
+ .info = {
+ .cpuid = plat_my_core_pos(),
+ .mode = MTK_CPU_PM_SMP,
+ },
+ .pwr = {
+ .afflv = armv8_2_get_pwr_afflv(state),
+ .state_id = 0x0,
+ },
+ };
+
+ armv8_2_cpu_pwr_on(&pm_state, pstate);
+
+ nb.cpuid = pm_state.info.cpuid;
+ nb.pwr_domain = pstate;
+ MT_CPUPM_EVENT_PWR_ON(&nb);
+
+ INFO("CPU %u power domain on finished\n", pm_state.info.cpuid);
+}
+
+/* MediaTek PSCI power domain */
+static void armv8_2_power_domain_off(const psci_power_state_t *state)
+{
+ struct mt_cpupm_event_data nb;
+ unsigned int pstate = (MT_CPUPM_PWR_DOMAIN_CORE | MT_CPUPM_PWR_DOMAIN_PERCORE_DSU);
+ struct mtk_cpupm_pwrstate pm_state = {
+ .info = {
+ .cpuid = plat_my_core_pos(),
+ .mode = MTK_CPU_PM_SMP,
+ },
+ .pwr = {
+ .afflv = armv8_2_get_pwr_afflv(state),
+ .state_id = 0x0,
+ },
+ };
+ armv8_2_cpu_pwr_off(&pm_state, pstate);
+
+ nb.cpuid = pm_state.info.cpuid;
+ nb.pwr_domain = pstate;
+ MT_CPUPM_EVENT_PWR_OFF(&nb);
+
+ INFO("CPU %u power domain off\n", pm_state.info.cpuid);
+}
+
+/* MediaTek PSCI power domain */
+static void armv8_2_power_domain_suspend(const psci_power_state_t *state)
+{
+ unsigned int pstate = 0;
+ struct mt_cpupm_event_data nb;
+ struct mtk_cpupm_pwrstate pm_state = {
+ .info = {
+ .cpuid = plat_my_core_pos(),
+ .mode = MTK_CPU_PM_CPUIDLE,
+ },
+ };
+
+ pm_state.pwr.state_id = armv8_2_get_pwr_stateid(pm_state.info.cpuid);
+ pm_state.pwr.afflv = armv8_2_get_pwr_afflv(state);
+ pm_state.pwr.raw = state;
+
+ pstate = get_mediatek_pstate(CPUPM_PWR_OFF,
+ armv8_2_power_state[pm_state.info.cpuid], &pm_state);
+
+ armv8_2_cpu_pwr_suspend(&pm_state, pstate);
+
+ if ((pstate & MT_CPUPM_PWR_DOMAIN_CLUSTER) != 0) {
+ armv8_2_cluster_pwr_dwn_common(&pm_state);
+ }
+
+ if ((pstate & MT_CPUPM_PWR_DOMAIN_MCUSYS) != 0) {
+ armv8_2_mcusys_pwr_dwn_common(&pm_state);
+ }
+
+ nb.cpuid = pm_state.info.cpuid;
+ nb.pwr_domain = pstate;
+ MT_CPUPM_EVENT_PWR_OFF(&nb);
+
+ if (IS_AFFLV_PUBEVENT(pstate)) {
+ MT_CPUPM_EVENT_AFFLV_PWR_OFF(&nb);
+ }
+}
+
+/* MediaTek PSCI power domain */
+static void armv8_2_power_domain_suspend_finish(const psci_power_state_t *state)
+{
+ unsigned int pstate = 0;
+ struct mt_cpupm_event_data nb;
+ struct mtk_cpupm_pwrstate pm_state = {
+ .info = {
+ .cpuid = plat_my_core_pos(),
+ .mode = MTK_CPU_PM_CPUIDLE,
+ },
+ };
+
+ pm_state.pwr.state_id = armv8_2_get_pwr_stateid(pm_state.info.cpuid);
+ pm_state.pwr.afflv = armv8_2_get_pwr_afflv(state);
+ pm_state.pwr.raw = state;
+
+ pstate = get_mediatek_pstate(CPUPM_PWR_ON,
+ armv8_2_power_state[pm_state.info.cpuid], &pm_state);
+
+ if ((pstate & MT_CPUPM_PWR_DOMAIN_MCUSYS) != 0) {
+ armv8_2_mcusys_pwr_on_common(&pm_state);
+ }
+
+ if ((pstate & MT_CPUPM_PWR_DOMAIN_CLUSTER) != 0) {
+ armv8_2_cluster_pwr_on_common(&pm_state);
+ }
+
+ armv8_2_cpu_pwr_resume(&pm_state, pstate);
+
+ nb.cpuid = pm_state.info.cpuid;
+ nb.pwr_domain = pstate;
+ MT_CPUPM_EVENT_PWR_ON(&nb);
+
+ if (IS_AFFLV_PUBEVENT(pstate)) {
+ MT_CPUPM_EVENT_AFFLV_PWR_ON(&nb);
+ }
+}
+
+/* MediaTek PSCI power domain */
+static int armv8_2_validate_power_state(unsigned int power_state, psci_power_state_t *req_state)
+{
+ unsigned int i;
+ unsigned int pstate = psci_get_pstate_type(power_state);
+ unsigned int aff_lvl = psci_get_pstate_pwrlvl(power_state);
+ unsigned int my_core_pos = plat_my_core_pos();
+
+ if (mtk_cpu_pwr.ops == NULL) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_PWR_STATE_VALID)) {
+ if (mtk_cpu_pwr.ops->pwr_state_valid(aff_lvl, pstate) != 0) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+ }
+
+ if (pstate == PSTATE_TYPE_STANDBY) {
+ req_state->pwr_domain_state[0] = PLAT_MAX_RET_STATE;
+ } else {
+ for (i = PSCI_CPU_PWR_LVL; i <= aff_lvl; i++) {
+ req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+ }
+ }
+ armv8_2_power_state[my_core_pos] = power_state;
+
+ return PSCI_E_SUCCESS;
+}
+
+/* MediaTek PSCI power domain */
+#if CONFIG_MTK_SUPPORT_SYSTEM_SUSPEND
+static void armv8_2_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+ unsigned int i;
+ int ret;
+ unsigned int power_state;
+ unsigned int my_core_pos = plat_my_core_pos();
+
+ ret = mtk_cpu_pwr.ops->pwr_state_valid(PLAT_MAX_PWR_LVL,
+ PSTATE_TYPE_POWERDOWN);
+
+ if (ret != MTK_CPUPM_E_OK) {
+ /* Avoid suspend due to platform is not ready. */
+ req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] =
+ PLAT_MAX_RET_STATE;
+ for (i = PSCI_CPU_PWR_LVL + 1; i <= PLAT_MAX_PWR_LVL; i++) {
+ req_state->pwr_domain_state[i] = PSCI_LOCAL_STATE_RUN;
+ }
+
+ power_state = psci_make_powerstate(0, PSTATE_TYPE_STANDBY, PSCI_CPU_PWR_LVL);
+ } else {
+ for (i = PSCI_CPU_PWR_LVL; i <= PLAT_MAX_PWR_LVL; i++) {
+ req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+ }
+
+ power_state = psci_make_powerstate(MT_PLAT_PWR_STATE_SUSPEND,
+ PSTATE_TYPE_POWERDOWN, PLAT_MAX_PWR_LVL);
+ }
+
+ armv8_2_power_state[my_core_pos] = power_state;
+ flush_dcache_range((uintptr_t)&armv8_2_power_state[my_core_pos],
+ sizeof(armv8_2_power_state[my_core_pos]));
+}
+#endif
+static void armv8_2_pm_smp_init(unsigned int cpu_id, uintptr_t entry_point)
+{
+ if (entry_point == 0) {
+ ERROR("%s, warm_entry_point is null\n", __func__);
+ panic();
+ }
+ if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_SMP_INIT)) {
+ mtk_cpu_pwr.smp->init(cpu_id, entry_point);
+ }
+ INFO("[%s:%d] - Initialize finished\n", __func__, __LINE__);
+}
+
+static struct plat_pm_pwr_ctrl armv8_2_pwr_ops = {
+ .pwr_domain_suspend = armv8_2_power_domain_suspend,
+ .pwr_domain_suspend_finish = armv8_2_power_domain_suspend_finish,
+ .validate_power_state = armv8_2_validate_power_state,
+#if CONFIG_MTK_SUPPORT_SYSTEM_SUSPEND
+ .get_sys_suspend_power_state = armv8_2_get_sys_suspend_power_state,
+#endif
+};
+
+struct plat_pm_smp_ctrl armv8_2_smp_ops = {
+ .init = armv8_2_pm_smp_init,
+ .pwr_domain_on = armv8_2_power_domain_on,
+ .pwr_domain_off = armv8_2_power_domain_off,
+ .pwr_domain_on_finish = armv8_2_power_domain_on_finish,
+};
+
+#define ISSUE_CPU_PM_REG_FAIL(_success) ({ _success = false; assert(0); })
+
+#define CPM_PM_FN_CHECK(_fns, _ops, _id, _func, _result, _flag) ({ \
+ if ((_fns & _id)) { \
+ if (_ops->_func) \
+ _flag |= _id; \
+ else { \
+ ISSUE_CPU_PM_REG_FAIL(_result); \
+ } \
+ } })
+
+int register_cpu_pm_ops(unsigned int fn_flags, struct mtk_cpu_pm_ops *ops)
+{
+ bool success = true;
+ unsigned int fns = 0;
+
+ if ((ops == NULL) || (mtk_cpu_pwr.ops != NULL)) {
+ ERROR("[%s:%d] register cpu_pm fail !!\n", __FILE__, __LINE__);
+ return MTK_CPUPM_E_ERR;
+ }
+
+ CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_RESUME_CORE,
+ cpu_resume, success, fns);
+
+ CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SUSPEND_CORE,
+ cpu_suspend, success, fns);
+
+ CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_RESUME_CLUSTER,
+ cluster_resume, success, fns);
+
+ CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SUSPEND_CLUSTER,
+ cluster_suspend, success, fns);
+
+ CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_RESUME_MCUSYS,
+ mcusys_resume, success, fns);
+
+ CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SUSPEND_MCUSYS,
+ mcusys_suspend, success, fns);
+
+ CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_CPUPM_GET_PWR_STATE,
+ get_pstate, success, fns);
+
+ CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_PWR_STATE_VALID,
+ pwr_state_valid, success, fns);
+
+ CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_INIT,
+ init, success, fns);
+
+ if (success) {
+ mtk_cpu_pwr.ops = ops;
+ mtk_cpu_pwr.fn_mask |= fns;
+ plat_pm_ops_setup_pwr(&armv8_2_pwr_ops);
+ INFO("[%s:%d] CPU pwr ops register success, support:0x%x\n",
+ __func__, __LINE__, fns);
+ } else {
+ ERROR("[%s:%d] register cpu_pm ops fail !, fn:0x%x\n",
+ __func__, __LINE__, fn_flags);
+ assert(0);
+ }
+ return MTK_CPUPM_E_OK;
+}
+
+int register_cpu_smp_ops(unsigned int fn_flags, struct mtk_cpu_smp_ops *ops)
+{
+ bool success = true;
+ unsigned int fns = 0;
+
+ if ((ops == NULL) || (mtk_cpu_pwr.smp != NULL)) {
+ ERROR("[%s:%d] register cpu_smp fail !!\n", __FILE__, __LINE__);
+ return MTK_CPUPM_E_ERR;
+ }
+
+ CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SMP_INIT,
+ init, success, fns);
+
+ CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_PWR_ON_CORE_PREPARE,
+ cpu_pwr_on_prepare, success, fns);
+
+ CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SMP_CORE_ON,
+ cpu_on, success, fns);
+
+ CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SMP_CORE_OFF,
+ cpu_off, success, fns);
+
+ if (success == true) {
+ mtk_cpu_pwr.smp = ops;
+ mtk_cpu_pwr.fn_mask |= fns;
+ plat_pm_ops_setup_smp(&armv8_2_smp_ops);
+ INFO("[%s:%d] CPU smp ops register success, support:0x%x\n",
+ __func__, __LINE__, fns);
+ } else {
+ ERROR("[%s:%d] register cpu_smp ops fail !, fn:0x%x\n",
+ __func__, __LINE__, fn_flags);
+ assert(0);
+ }
+ return MTK_CPUPM_E_OK;
+}
diff --git a/plat/mediatek/lib/pm/armv8_2/rules.mk b/plat/mediatek/lib/pm/armv8_2/rules.mk
new file mode 100644
index 0000000..0e065c5
--- /dev/null
+++ b/plat/mediatek/lib/pm/armv8_2/rules.mk
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := armv${CONFIG_MTK_PM_ARCH}
+LOCAL_SRCS-y := ${LOCAL_DIR}/pwr_ctrl.c
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/lib/pm/mtk_pm.c b/plat/mediatek/lib/pm/mtk_pm.c
new file mode 100644
index 0000000..3dbeb51
--- /dev/null
+++ b/plat/mediatek/lib/pm/mtk_pm.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <plat/common/platform.h>
+#include <lib/pm/mtk_pm.h>
+
+#define MTK_PM_ST_SMP_READY BIT(0)
+#define MTK_PM_ST_PWR_READY BIT(1)
+#define MTK_PM_ST_RESET_READY BIT(2)
+
+static uintptr_t mtk_secure_entrypoint;
+static plat_init_func mtk_plat_smp_init;
+static plat_psci_ops_t mtk_pm_ops;
+static unsigned int mtk_pm_status;
+
+uintptr_t plat_pm_get_warm_entry(void)
+{
+ return mtk_secure_entrypoint;
+}
+
+int plat_pm_ops_setup_pwr(struct plat_pm_pwr_ctrl *ops)
+{
+ if (!ops) {
+ return MTK_CPUPM_E_FAIL;
+ }
+
+#if CONFIG_MTK_CPU_SUSPEND_EN
+ if (!mtk_pm_ops.pwr_domain_suspend) {
+ mtk_pm_ops.pwr_domain_suspend = ops->pwr_domain_suspend;
+ }
+
+ if (!mtk_pm_ops.pwr_domain_suspend_finish) {
+ mtk_pm_ops.pwr_domain_suspend_finish = ops->pwr_domain_suspend_finish;
+ }
+
+ if (!mtk_pm_ops.validate_power_state) {
+ mtk_pm_ops.validate_power_state = ops->validate_power_state;
+ }
+
+ if (!mtk_pm_ops.get_sys_suspend_power_state) {
+ mtk_pm_ops.get_sys_suspend_power_state = ops->get_sys_suspend_power_state;
+ }
+
+ mtk_pm_status |= MTK_PM_ST_PWR_READY;
+#endif
+ return MTK_CPUPM_E_OK;
+}
+
+int plat_pm_ops_setup_smp(struct plat_pm_smp_ctrl *ops)
+{
+ if (!ops) {
+ return MTK_CPUPM_E_FAIL;
+ }
+
+#if CONFIG_MTK_SMP_EN
+ if (!mtk_pm_ops.pwr_domain_on) {
+ mtk_pm_ops.pwr_domain_on = ops->pwr_domain_on;
+ }
+
+ if (!mtk_pm_ops.pwr_domain_on_finish) {
+ mtk_pm_ops.pwr_domain_on_finish = ops->pwr_domain_on_finish;
+ }
+
+ if (!mtk_pm_ops.pwr_domain_off) {
+ mtk_pm_ops.pwr_domain_off = ops->pwr_domain_off;
+ }
+
+ if (!mtk_plat_smp_init) {
+ mtk_plat_smp_init = ops->init;
+ }
+
+ mtk_pm_status |= MTK_PM_ST_SMP_READY;
+#endif
+ return MTK_CPUPM_E_OK;
+}
+
+int plat_pm_ops_setup_reset(struct plat_pm_reset_ctrl *ops)
+{
+ if (!ops) {
+ return MTK_CPUPM_E_FAIL;
+ }
+
+ if (!mtk_pm_ops.system_off) {
+ mtk_pm_ops.system_off = ops->system_off;
+ }
+
+ if (!mtk_pm_ops.system_reset) {
+ mtk_pm_ops.system_reset = ops->system_reset;
+ }
+
+ if (!mtk_pm_ops.system_reset2) {
+ mtk_pm_ops.system_reset2 = ops->system_reset2;
+ }
+
+ mtk_pm_status |= MTK_PM_ST_RESET_READY;
+
+ return MTK_CPUPM_E_OK;
+}
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const plat_psci_ops_t **psci_ops)
+{
+ *psci_ops = &mtk_pm_ops;
+ mtk_secure_entrypoint = sec_entrypoint;
+
+ if (mtk_plat_smp_init) {
+ unsigned int cpu_id = plat_my_core_pos();
+
+ mtk_plat_smp_init(cpu_id, mtk_secure_entrypoint);
+ }
+ INFO("%s, smp:(%d), pwr_ctrl:(%d), system_reset:(%d)\n", __func__,
+ !!(mtk_pm_status & MTK_PM_ST_SMP_READY),
+ !!(mtk_pm_status & MTK_PM_ST_PWR_READY),
+ !!(mtk_pm_status & MTK_PM_ST_RESET_READY));
+ return 0;
+}
diff --git a/plat/mediatek/lib/pm/mtk_pm.h b/plat/mediatek/lib/pm/mtk_pm.h
new file mode 100644
index 0000000..4a29439
--- /dev/null
+++ b/plat/mediatek/lib/pm/mtk_pm.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2022, Mediatek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_PM_H
+#define MTK_PM_H
+#include <lib/psci/psci.h>
+
+#if MTK_PUBEVENT_ENABLE
+#include <vendor_pubsub_events.h>
+#endif
+
+#define MTK_CPUPM_E_OK (0)
+#define MTK_CPUPM_E_UNKNOWN (-1)
+#define MTK_CPUPM_E_ERR (-2)
+#define MTK_CPUPM_E_FAIL (-3)
+#define MTK_CPUPM_E_NOT_SUPPORT (-4)
+
+
+#define MTK_CPUPM_FN_PWR_LOCK_AQUIRE BIT(0)
+#define MTK_CPUPM_FN_INIT BIT(1)
+#define MTK_CPUPM_FN_PWR_STATE_VALID BIT(2)
+#define MTK_CPUPM_FN_PWR_ON_CORE_PREPARE BIT(3)
+#define MTK_CPUPM_FN_SUSPEND_CORE BIT(4)
+#define MTK_CPUPM_FN_RESUME_CORE BIT(5)
+#define MTK_CPUPM_FN_SUSPEND_CLUSTER BIT(6)
+#define MTK_CPUPM_FN_RESUME_CLUSTER BIT(7)
+#define MTK_CPUPM_FN_SUSPEND_MCUSYS BIT(8)
+#define MTK_CPUPM_FN_RESUME_MCUSYS BIT(9)
+#define MTK_CPUPM_FN_CPUPM_GET_PWR_STATE BIT(10)
+#define MTK_CPUPM_FN_SMP_INIT BIT(11)
+#define MTK_CPUPM_FN_SMP_CORE_ON BIT(12)
+#define MTK_CPUPM_FN_SMP_CORE_OFF BIT(13)
+
+enum mtk_cpupm_pstate {
+ MTK_CPUPM_CORE_ON,
+ MTK_CPUPM_CORE_OFF,
+ MTK_CPUPM_CORE_SUSPEND,
+ MTK_CPUPM_CORE_RESUME,
+ MTK_CPUPM_CLUSTER_SUSPEND,
+ MTK_CPUPM_CLUSTER_RESUME,
+ MTK_CPUPM_MCUSYS_SUSPEND,
+ MTK_CPUPM_MCUSYS_RESUME,
+};
+
+enum mtk_cpu_pm_mode {
+ MTK_CPU_PM_CPUIDLE,
+ MTK_CPU_PM_SMP,
+};
+
+#define MT_IRQ_REMAIN_MAX (32)
+#define MT_IRQ_REMAIN_CAT_LOG BIT(31)
+
+struct mt_irqremain {
+ unsigned int count;
+ unsigned int irqs[MT_IRQ_REMAIN_MAX];
+ unsigned int wakeupsrc_cat[MT_IRQ_REMAIN_MAX];
+ unsigned int wakeupsrc[MT_IRQ_REMAIN_MAX];
+};
+
+typedef void (*plat_init_func)(unsigned int, uintptr_t);
+
+struct plat_pm_smp_ctrl {
+ plat_init_func init;
+ int (*pwr_domain_on)(u_register_t mpidr);
+ void (*pwr_domain_off)(const psci_power_state_t *target_state);
+ void (*pwr_domain_on_finish)(const psci_power_state_t *target_state);
+};
+
+struct plat_pm_pwr_ctrl {
+ void (*pwr_domain_suspend)(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);
+ int (*validate_power_state)(unsigned int power_state, psci_power_state_t *req_state);
+ void (*get_sys_suspend_power_state)(psci_power_state_t *req_state);
+};
+
+struct plat_pm_reset_ctrl {
+ __dead2 void (*system_off)();
+ __dead2 void (*system_reset)();
+ int (*system_reset2)(int is_vendor, int reset_type, u_register_t cookie);
+};
+
+struct mtk_cpu_pm_info {
+ unsigned int cpuid;
+ unsigned int mode;
+};
+
+struct mtk_cpu_pm_state {
+ unsigned int afflv;
+ unsigned int state_id;
+ const psci_power_state_t *raw;
+};
+
+struct mtk_cpupm_pwrstate {
+ struct mtk_cpu_pm_info info;
+ struct mtk_cpu_pm_state pwr;
+};
+
+struct mtk_cpu_smp_ops {
+ void (*init)(unsigned int cpu, uintptr_t sec_entrypoint);
+ int (*cpu_pwr_on_prepare)(unsigned int cpu, uintptr_t entry);
+ void (*cpu_on)(const struct mtk_cpupm_pwrstate *state);
+ void (*cpu_off)(const struct mtk_cpupm_pwrstate *state);
+ int (*invoke)(unsigned int funcID, void *priv);
+};
+
+#define MT_CPUPM_PWR_DOMAIN_CORE BIT(0)
+#define MT_CPUPM_PWR_DOMAIN_PERCORE_DSU BIT(1)
+#define MT_CPUPM_PWR_DOMAIN_PERCORE_DSU_MEM BIT(2)
+#define MT_CPUPM_PWR_DOMAIN_CLUSTER BIT(3)
+#define MT_CPUPM_PWR_DOMAIN_MCUSYS BIT(4)
+#define MT_CPUPM_PWR_DOMAIN_SUSPEND BIT(5)
+
+enum mt_cpupm_pwr_domain {
+ CPUPM_PWR_ON,
+ CPUPM_PWR_OFF,
+};
+
+typedef unsigned int mtk_pstate_type;
+
+struct mtk_cpu_pm_ops {
+ void (*init)(unsigned int cpu, uintptr_t sec_entrypoint);
+ unsigned int (*get_pstate)(enum mt_cpupm_pwr_domain domain,
+ const mtk_pstate_type psci_state,
+ const struct mtk_cpupm_pwrstate *state);
+ int (*pwr_state_valid)(unsigned int afflv, unsigned int state);
+ void (*cpu_suspend)(const struct mtk_cpupm_pwrstate *state);
+ void (*cpu_resume)(const struct mtk_cpupm_pwrstate *state);
+ void (*cluster_suspend)(const struct mtk_cpupm_pwrstate *state);
+ void (*cluster_resume)(const struct mtk_cpupm_pwrstate *state);
+ void (*mcusys_suspend)(const struct mtk_cpupm_pwrstate *state);
+ void (*mcusys_resume)(const struct mtk_cpupm_pwrstate *state);
+ int (*invoke)(unsigned int funcID, void *priv);
+};
+
+int register_cpu_pm_ops(unsigned int fn_flags, struct mtk_cpu_pm_ops *ops);
+int register_cpu_smp_ops(unsigned int fn_flags, struct mtk_cpu_smp_ops *ops);
+
+struct mt_cpupm_event_data {
+ unsigned int cpuid;
+ unsigned int pwr_domain;
+};
+
+/* Extension event for platform driver */
+#if MTK_PUBEVENT_ENABLE
+/* [PUB_EVENT] Core power on */
+#define MT_CPUPM_SUBCRIBE_EVENT_PWR_ON(_fn) \
+ SUBSCRIBE_TO_EVENT(mt_cpupm_publish_pwr_on, _fn)
+
+/* [PUB_EVENT] Core power off */
+#define MT_CPUPM_SUBCRIBE_EVENT_PWR_OFF(_fn) \
+ SUBSCRIBE_TO_EVENT(mt_cpupm_publish_pwr_off, _fn)
+
+/* [PUB_EVENT] Cluster power on */
+#define MT_CPUPM_SUBCRIBE_CLUSTER_PWR_ON(_fn) \
+ SUBSCRIBE_TO_EVENT(mt_cpupm_publish_afflv_pwr_on, _fn)
+
+/* [PUB_EVENT] Cluster power off */
+#define MT_CPUPM_SUBCRIBE_CLUSTER_PWR_OFF(_fn) \
+ SUBSCRIBE_TO_EVENT(mt_cpupm_publish_afflv_pwr_off, _fn)
+
+/* [PUB_EVENT] Mcusys power on */
+#define MT_CPUPM_SUBCRIBE_MCUSYS_PWR_ON(_fn) \
+ SUBSCRIBE_TO_EVENT(mt_cpupm_publish_afflv_pwr_on, _fn)
+
+/* [PUB_EVENT] Mcusys power off */
+#define MT_CPUPM_SUBCRIBE_MCUSYS_PWR_OFF(_fn) \
+ SUBSCRIBE_TO_EVENT(mt_cpupm_publish_afflv_pwr_off, _fn)
+
+#else
+#define MT_CPUPM_SUBCRIBE_EVENT_PWR_ON(_fn)
+#define MT_CPUPM_SUBCRIBE_EVENT_PWR_OFF(_fn)
+#define MT_CPUPM_SUBCRIBE_CLUSTER_PWR_ON(_fn)
+#define MT_CPUPM_SUBCRIBE_CLUSTER_PWR_OFF(_fn)
+#define MT_CPUPM_SUBCRIBE_MCUSYS_PWR_ON(_fn)
+#define MT_CPUPM_SUBCRIBE_MCUSYS_PWR_OFF(_fn)
+#endif
+
+/*
+ * Definition c-state power domain.
+ * bit[7:4] (main state id):
+ * - 1: Cluster.
+ * - 2: Mcusys.
+ * - 3: Memory.
+ * - 4: System pll.
+ * - 5: System bus.
+ * - 6: SoC 26m/DCXO.
+ * - 7: Vcore buck.
+ * - 15: Suspend.
+ * bit[3:0] (reserved for state_id extension):
+ * - 4: CPU buck.
+ */
+#define MT_PLAT_PWR_STATE_CLUSTER (0x0010)
+#define MT_PLAT_PWR_STATE_MCUSYS (0x0020)
+#define MT_PLAT_PWR_STATE_MCUSYS_BUCK (0x0024)
+#define MT_PLAT_PWR_STATE_SYSTEM_MEM (0x0030)
+#define MT_PLAT_PWR_STATE_SYSTEM_PLL (0x0040)
+#define MT_PLAT_PWR_STATE_SYSTEM_BUS (0x0050)
+#define MT_PLAT_PWR_STATE_SUSPEND (0x00f0)
+
+#define IS_MT_PLAT_PWR_STATE(state, target_state) ((state & target_state) == target_state)
+#define IS_MT_PLAT_PWR_STATE_MCUSYS(state) IS_MT_PLAT_PWR_STATE(state, MT_PLAT_PWR_STATE_MCUSYS)
+
+#define PLAT_MT_SYSTEM_SUSPEND PLAT_MAX_OFF_STATE
+#define PLAT_MT_CPU_SUSPEND_CLUSTER PLAT_MAX_RET_STATE
+#define PLAT_MT_CPU_SUSPEND_MCUSYS PLAT_MAX_RET_STATE
+
+#define IS_PLAT_SYSTEM_SUSPEND(aff) (aff == PLAT_MT_SYSTEM_SUSPEND)
+#define IS_PLAT_SYSTEM_RETENTION(aff) (aff >= PLAT_MAX_RET_STATE)
+
+#define IS_PLAT_SUSPEND_ID(stateid) (stateid == MT_PLAT_PWR_STATE_SUSPEND)
+
+#define IS_PLAT_MCUSYSOFF_AFFLV(afflv) (afflv >= PLAT_MT_CPU_SUSPEND_MCUSYS)
+
+int plat_pm_ops_setup_pwr(struct plat_pm_pwr_ctrl *ops);
+int plat_pm_ops_setup_reset(struct plat_pm_reset_ctrl *ops);
+int plat_pm_ops_setup_smp(struct plat_pm_smp_ctrl *ops);
+uintptr_t plat_pm_get_warm_entry(void);
+
+#endif
diff --git a/plat/mediatek/lib/pm/rules.mk b/plat/mediatek/lib/pm/rules.mk
new file mode 100644
index 0000000..29265c4
--- /dev/null
+++ b/plat/mediatek/lib/pm/rules.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := pm
+
+LOCAL_SRCS-y := ${LOCAL_DIR}/mtk_pm.c
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
+
+SUB_RULES-$(CONFIG_MTK_PM_SUPPORT) := $(LOCAL_DIR)/armv${CONFIG_MTK_PM_ARCH}
+$(eval $(call INCLUDE_MAKEFILE,$(SUB_RULES-y)))
diff --git a/plat/mediatek/lib/system_reset/reset_cros.c b/plat/mediatek/lib/system_reset/reset_cros.c
new file mode 100644
index 0000000..40e68ba
--- /dev/null
+++ b/plat/mediatek/lib/system_reset/reset_cros.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/gpio.h>
+#include <lib/mtk_init/mtk_init.h>
+#include <lib/pm/mtk_pm.h>
+#include <plat_params.h>
+#include <pmic.h>
+#include <rtc.h>
+
+static void __dead2 mtk_system_reset_cros(void)
+{
+ struct bl_aux_gpio_info *gpio_reset = plat_get_mtk_gpio_reset();
+
+ INFO("MTK System Reset\n");
+
+ gpio_set_value(gpio_reset->index, gpio_reset->polarity);
+
+ wfi();
+ ERROR("MTK System Reset: operation not handled.\n");
+ panic();
+}
+
+static void __dead2 mtk_system_off_cros(void)
+{
+ INFO("MTK System Off\n");
+
+ rtc_power_off_sequence();
+ pmic_power_off();
+
+ wfi();
+ ERROR("MTK System Off: operation not handled.\n");
+ panic();
+}
+
+static struct plat_pm_reset_ctrl lib_reset_ctrl = {
+ .system_off = mtk_system_off_cros,
+ .system_reset = mtk_system_reset_cros,
+ .system_reset2 = NULL,
+};
+
+static int lib_reset_ctrl_init(void)
+{
+ INFO("Reset init\n");
+
+ plat_pm_ops_setup_reset(&lib_reset_ctrl);
+
+ return 0;
+}
+MTK_ARCH_INIT(lib_reset_ctrl_init);
diff --git a/plat/mediatek/lib/system_reset/rules.mk b/plat/mediatek/lib/system_reset/rules.mk
new file mode 100644
index 0000000..4f20663
--- /dev/null
+++ b/plat/mediatek/lib/system_reset/rules.mk
@@ -0,0 +1,14 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := system_reset
+
+LOCAL_SRCS-y := ${LOCAL_DIR}/reset_cros.c
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/mt8173/aarch64/plat_helpers.S b/plat/mediatek/mt8173/aarch64/plat_helpers.S
new file mode 100644
index 0000000..095dfc5
--- /dev/null
+++ b/plat/mediatek/mt8173/aarch64/plat_helpers.S
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <mt8173_def.h>
+
+ .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
diff --git a/plat/mediatek/mt8173/aarch64/platform_common.c b/plat/mediatek/mt8173/aarch64/platform_common.c
new file mode 100644
index 0000000..a2dbe3e
--- /dev/null
+++ b/plat/mediatek/mt8173/aarch64/platform_common.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+#include <mt8173_def.h>
+
+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()));
+}
diff --git a/plat/mediatek/mt8173/bl31_plat_setup.c b/plat/mediatek/mt8173/bl31_plat_setup.c
new file mode 100644
index 0000000..bd7d0b0
--- /dev/null
+++ b/plat/mediatek/mt8173/bl31_plat_setup.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/mmio.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/common_def.h>
+#include <plat/common/platform.h>
+
+#include <mcucfg.h>
+#include <mtcmos.h>
+#include <mtk_plat_common.h>
+#include <plat_private.h>
+#include <spm.h>
+
+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_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);
+}
+
diff --git a/plat/mediatek/mt8173/drivers/crypt/crypt.c b/plat/mediatek/mt8173/drivers/crypt/crypt.c
new file mode 100644
index 0000000..bfb3082
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/crypt/crypt.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <mt8173_def.h>
+#include <mtk_sip_svc.h>
+
+#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;
+}
diff --git a/plat/mediatek/mt8173/drivers/crypt/crypt.h b/plat/mediatek/mt8173/drivers/crypt/crypt.h
new file mode 100644
index 0000000..1a691a6
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/crypt/crypt.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef CRYPT_H
+#define CRYPT_H
+
+#include <stdint.h>
+
+/* 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 */
diff --git a/plat/mediatek/mt8173/drivers/mtcmos/mtcmos.c b/plat/mediatek/mt8173/drivers/mtcmos/mtcmos.c
new file mode 100644
index 0000000..452ac22
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/mtcmos/mtcmos.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <mt8173_def.h>
+#include <mtcmos.h>
+#include <spm.h>
+#include <spm_mcdi.h>
+
+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;
+}
diff --git a/plat/mediatek/mt8173/drivers/mtcmos/mtcmos.h b/plat/mediatek/mt8173/drivers/mtcmos/mtcmos.h
new file mode 100644
index 0000000..1e58027
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/mtcmos/mtcmos.h
@@ -0,0 +1,18 @@
+/*
+ * 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 */
diff --git a/plat/mediatek/mt8173/drivers/pmic/pmic_wrap_init.h b/plat/mediatek/mt8173/drivers/pmic/pmic_wrap_init.h
new file mode 100644
index 0000000..0dffc23
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/pmic/pmic_wrap_init.h
@@ -0,0 +1,169 @@
+/*
+ * 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 <platform_def.h>
+
+/* 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 */
diff --git a/plat/mediatek/mt8173/drivers/rtc/rtc.c b/plat/mediatek/mt8173/drivers/rtc/rtc.c
new file mode 100644
index 0000000..587886c
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/rtc/rtc.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/debug.h>
+
+#include <mt8173_def.h>
+#include <rtc.h>
+
+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);
+ }
+}
diff --git a/plat/mediatek/mt8173/drivers/rtc/rtc.h b/plat/mediatek/mt8173/drivers/rtc/rtc.h
new file mode 100644
index 0000000..f60a4c1
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/rtc/rtc.h
@@ -0,0 +1,60 @@
+/*
+ * 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 */
diff --git a/plat/mediatek/mt8173/drivers/spm/spm.c b/plat/mediatek/mt8173/drivers/spm/spm.c
new file mode 100644
index 0000000..1caab3b
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/spm/spm.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include <mt8173_def.h>
+#include <spm.h>
+#include <spm_suspend.h>
+
+/*
+ * 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();
+}
diff --git a/plat/mediatek/mt8173/drivers/spm/spm.h b/plat/mediatek/mt8173/drivers/spm/spm.h
new file mode 100644
index 0000000..0c05410
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/spm/spm.h
@@ -0,0 +1,335 @@
+/*
+ * 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);
+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 */
diff --git a/plat/mediatek/mt8173/drivers/spm/spm_hotplug.c b/plat/mediatek/mt8173/drivers/spm/spm_hotplug.c
new file mode 100644
index 0000000..b2b9ada
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/spm/spm_hotplug.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <lib/mmio.h>
+#include <mt8173_def.h>
+#include <plat/common/platform.h>
+
+#include <spm.h>
+#include <spm_hotplug.h>
+#include <spm_mcdi.h>
+
+/*
+ * 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();
+}
diff --git a/plat/mediatek/mt8173/drivers/spm/spm_hotplug.h b/plat/mediatek/mt8173/drivers/spm/spm_hotplug.h
new file mode 100644
index 0000000..00849a2
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/spm/spm_hotplug.h
@@ -0,0 +1,13 @@
+/*
+ * 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 */
diff --git a/plat/mediatek/mt8173/drivers/spm/spm_mcdi.c b/plat/mediatek/mt8173/drivers/spm/spm_mcdi.c
new file mode 100644
index 0000000..ea5f2bb
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/spm/spm_mcdi.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <mt8173_def.h>
+#include <spm.h>
+#include <spm_hotplug.h>
+#include <spm_mcdi.h>
+
+/*
+ * 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();
+}
diff --git a/plat/mediatek/mt8173/drivers/spm/spm_mcdi.h b/plat/mediatek/mt8173/drivers/spm/spm_mcdi.h
new file mode 100644
index 0000000..7f3f96e
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/spm/spm_mcdi.h
@@ -0,0 +1,14 @@
+/*
+ * 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 */
diff --git a/plat/mediatek/mt8173/drivers/spm/spm_suspend.c b/plat/mediatek/mt8173/drivers/spm/spm_suspend.c
new file mode 100644
index 0000000..838455d
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/spm/spm_suspend.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include <mt8173_def.h>
+#include <spm.h>
+#include <spm_suspend.h>
+
+/*
+ * 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 flags_spm)
+{
+ struct pwr_ctrl *pwrctrl;
+
+ pwrctrl = &spm_ctrl;
+
+ set_pwrctrl_pcm_flags(pwrctrl, flags_spm);
+
+ 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);
+}
diff --git a/plat/mediatek/mt8173/drivers/spm/spm_suspend.h b/plat/mediatek/mt8173/drivers/spm/spm_suspend.h
new file mode 100644
index 0000000..b00faa9
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/spm/spm_suspend.h
@@ -0,0 +1,16 @@
+/*
+ * 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*/
diff --git a/plat/mediatek/mt8173/drivers/timer/mt_cpuxgpt.c b/plat/mediatek/mt8173/drivers/timer/mt_cpuxgpt.c
new file mode 100644
index 0000000..174a24d
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/timer/mt_cpuxgpt.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+
+#include <mcucfg.h>
+#include <mt8173_def.h>
+#include <mt_cpuxgpt.h>
+
+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));
+}
diff --git a/plat/mediatek/mt8173/drivers/timer/mt_cpuxgpt.h b/plat/mediatek/mt8173/drivers/timer/mt_cpuxgpt.h
new file mode 100644
index 0000000..8c0fe83
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/timer/mt_cpuxgpt.h
@@ -0,0 +1,16 @@
+/*
+ * 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 */
diff --git a/plat/mediatek/mt8173/drivers/wdt/wdt.c b/plat/mediatek/mt8173/drivers/wdt/wdt.c
new file mode 100644
index 0000000..40f57ee
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/wdt/wdt.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2020, Google LLC. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mt8173_def.h>
+#include <plat_sip_calls.h>
+#include <lib/psci/psci.h>
+#include <smccc_helpers.h>
+#include <wdt.h>
+
+#define WDT_BASE (RGU_BASE + 0)
+#define WDT_MODE (WDT_BASE + 0x00)
+#define WDT_LENGTH (WDT_BASE + 0x04)
+#define WDT_RESTART (WDT_BASE + 0x08)
+#define WDT_SWRST (WDT_BASE + 0x14)
+
+#define WDT_MODE_DUAL_MODE 0x40
+#define WDT_MODE_IRQ 0x8
+#define WDT_MODE_KEY 0x22000000
+#define WDT_MODE_EXTEN 0x4
+#define WDT_MODE_EN 0x1
+#define WDT_LENGTH_KEY 0x8
+#define WDT_RESTART_KEY 0x1971
+#define WDT_SWRST_KEY 0x1209
+
+
+#define WDT_MIN_TIMEOUT 1
+#define WDT_MAX_TIMEOUT 31
+
+enum smcwd_call {
+ SMCWD_INFO = 0,
+ SMCWD_SET_TIMEOUT = 1,
+ SMCWD_ENABLE = 2,
+ SMCWD_PET = 3,
+};
+
+static int wdt_enabled_before_suspend;
+
+/*
+ * We expect the WDT registers to be correctly initialized by BL2 firmware
+ * (which may be board specific), so we do not reinitialize them here.
+ */
+
+void wdt_trigger_reset(void)
+{
+ mmio_write_32(WDT_SWRST, WDT_SWRST_KEY);
+}
+
+void wdt_pet(void)
+{
+ mmio_write_32(WDT_RESTART, WDT_RESTART_KEY);
+}
+
+int wdt_set_timeout(uint32_t timeout)
+{
+ /* One tick here equals 512 32KHz ticks. 512 / 32000 * 125 / 2 = 1 */
+ uint32_t ticks = timeout * 125 / 2;
+
+ if (timeout < WDT_MIN_TIMEOUT || timeout > WDT_MAX_TIMEOUT)
+ return PSCI_E_INVALID_PARAMS;
+
+ mmio_write_32(WDT_LENGTH, ticks << 5 | WDT_LENGTH_KEY);
+
+ return PSCI_E_SUCCESS;
+}
+
+void wdt_set_enable(int enable)
+{
+ if (enable)
+ wdt_pet();
+ mmio_clrsetbits_32(WDT_MODE, WDT_MODE_EN,
+ WDT_MODE_KEY | (enable ? WDT_MODE_EN : 0));
+}
+
+void wdt_suspend(void)
+{
+ wdt_enabled_before_suspend = mmio_read_32(WDT_MODE) & WDT_MODE_EN;
+ if (wdt_enabled_before_suspend)
+ wdt_set_enable(0);
+}
+
+void wdt_resume(void)
+{
+ if (wdt_enabled_before_suspend)
+ wdt_set_enable(1);
+}
+
+uint64_t wdt_smc_handler(uint32_t x1,
+ uint32_t x2,
+ void *handle)
+{
+ int ret;
+
+ switch (x1) {
+ case SMCWD_INFO:
+ SMC_RET3(handle, PSCI_E_SUCCESS,
+ WDT_MIN_TIMEOUT, WDT_MAX_TIMEOUT);
+ case SMCWD_SET_TIMEOUT:
+ ret = wdt_set_timeout(x2);
+ SMC_RET1(handle, ret);
+ case SMCWD_ENABLE:
+ wdt_set_enable(x2 > 0);
+ SMC_RET1(handle, PSCI_E_SUCCESS);
+ case SMCWD_PET:
+ wdt_pet();
+ SMC_RET1(handle, PSCI_E_SUCCESS);
+ default:
+ ERROR("Unimplemented SMCWD call (%d)\n", x1);
+ SMC_RET1(handle, PSCI_E_NOT_SUPPORTED);
+ }
+}
diff --git a/plat/mediatek/mt8173/drivers/wdt/wdt.h b/plat/mediatek/mt8173/drivers/wdt/wdt.h
new file mode 100644
index 0000000..7262a57
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/wdt/wdt.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2020, Google LLC. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef WDT_H
+#define WDT_H
+
+#include "stdint.h"
+
+void wdt_pet(void);
+void wdt_resume(void);
+void wdt_set_enable(int enable);
+int wdt_set_timeout(uint32_t timeout);
+uint64_t wdt_smc_handler(uint32_t x1, uint32_t x2, void *handle);
+void wdt_suspend(void);
+void wdt_trigger_reset(void);
+
+#endif /* WDT_H */
diff --git a/plat/mediatek/mt8173/include/mcucfg.h b/plat/mediatek/mt8173/include/mcucfg.h
new file mode 100644
index 0000000..dedbc08
--- /dev/null
+++ b/plat/mediatek/mt8173/include/mcucfg.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef MCUCFG_H
+#define MCUCFG_H
+
+#include <stdint.h>
+
+#include <mt8173_def.h>
+
+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 */
diff --git a/plat/mediatek/mt8173/include/mt8173_def.h b/plat/mediatek/mt8173/include/mt8173_def.h
new file mode 100644
index 0000000..378b4da
--- /dev/null
+++ b/plat/mediatek/mt8173/include/mt8173_def.h
@@ -0,0 +1,140 @@
+/*
+ * 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
+
+/* 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 */
diff --git a/plat/mediatek/mt8173/include/plat_macros.S b/plat/mediatek/mt8173/include/plat_macros.S
new file mode 100644
index 0000000..ac9fb16
--- /dev/null
+++ b/plat/mediatek/mt8173/include/plat_macros.S
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <mt8173_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"
+
+.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
diff --git a/plat/mediatek/mt8173/include/plat_private.h b/plat/mediatek/mt8173/include/plat_private.h
new file mode 100644
index 0000000..cd92d34
--- /dev/null
+++ b/plat/mediatek/mt8173/include/plat_private.h
@@ -0,0 +1,27 @@
+/*
+ * 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 */
diff --git a/plat/mediatek/mt8173/include/plat_sip_calls.h b/plat/mediatek/mt8173/include/plat_sip_calls.h
new file mode 100644
index 0000000..ce9951a
--- /dev/null
+++ b/plat/mediatek/mt8173/include/plat_sip_calls.h
@@ -0,0 +1,23 @@
+/*
+ * 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 7
+
+#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
+#define MTK_SIP_SMC_WATCHDOG 0x82003D06
+
+#endif /* PLAT_SIP_CALLS_H */
diff --git a/plat/mediatek/mt8173/include/platform_def.h b/plat/mediatek/mt8173/include/platform_def.h
new file mode 100644
index 0000000..d340422
--- /dev/null
+++ b/plat/mediatek/mt8173/include/platform_def.h
@@ -0,0 +1,141 @@
+/*
+ * 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 <common/interrupt_props.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/utils_def.h>
+
+#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 U(1)
+#define PLATFORM_CLUSTER_COUNT U(2)
+#define PLATFORM_CLUSTER0_CORE_COUNT U(4)
+#define PLATFORM_CLUSTER1_CORE_COUNT U(2)
+#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER1_CORE_COUNT + \
+ PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER U(4)
+#define PLATFORM_NUM_AFFS (PLATFORM_SYSTEM_COUNT + \
+ PLATFORM_CLUSTER_COUNT + \
+ PLATFORM_CORE_COUNT)
+
+#define SOC_CHIP_ID U(0x8173)
+
+/*******************************************************************************
+ * 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 */
diff --git a/plat/mediatek/mt8173/include/power_tracer.h b/plat/mediatek/mt8173/include/power_tracer.h
new file mode 100644
index 0000000..195366d
--- /dev/null
+++ b/plat/mediatek/mt8173/include/power_tracer.h
@@ -0,0 +1,19 @@
+/*
+ * 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 */
diff --git a/plat/mediatek/mt8173/include/scu.h b/plat/mediatek/mt8173/include/scu.h
new file mode 100644
index 0000000..b1e9424
--- /dev/null
+++ b/plat/mediatek/mt8173/include/scu.h
@@ -0,0 +1,13 @@
+/*
+ * 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 */
diff --git a/plat/mediatek/mt8173/plat_mt_gic.c b/plat/mediatek/mt8173/plat_mt_gic.c
new file mode 100644
index 0000000..80b9010
--- /dev/null
+++ b/plat/mediatek/mt8173/plat_mt_gic.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <lib/utils.h>
+
+#include <mt8173_def.h>
+
+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));
+}
diff --git a/plat/mediatek/mt8173/plat_pm.c b/plat/mediatek/mt8173/plat_pm.c
new file mode 100644
index 0000000..e72a343
--- /dev/null
+++ b/plat/mediatek/mt8173/plat_pm.c
@@ -0,0 +1,603 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+
+#include <mcucfg.h>
+#include <mt8173_def.h>
+#include <mt_cpuxgpt.h> /* generic_timer_backup() */
+#include <plat_private.h>
+#include <power_tracer.h>
+#include <rtc.h>
+#include <scu.h>
+#include <spm_hotplug.h>
+#include <spm_mcdi.h>
+#include <spm_suspend.h>
+#include <wdt.h>
+
+#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)
+{
+ u_register_t 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) {
+ wdt_suspend();
+ 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);
+ wdt_resume();
+ }
+
+ /* 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");
+
+ wdt_trigger_reset();
+
+ 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;
+}
diff --git a/plat/mediatek/mt8173/plat_sip_calls.c b/plat/mediatek/mt8173/plat_sip_calls.c
new file mode 100644
index 0000000..da9b91d
--- /dev/null
+++ b/plat/mediatek/mt8173/plat_sip_calls.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+
+#include <crypt.h>
+#include <mtcmos.h>
+#include <mtk_sip_svc.h>
+#include <plat_sip_calls.h>
+#include <wdt.h>
+
+/* 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);
+
+ case MTK_SIP_SMC_WATCHDOG:
+ return wdt_smc_handler(x1, x2, handle);
+
+ default:
+ ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+ break;
+ }
+
+ SMC_RET1(handle, SMC_UNK);
+}
diff --git a/plat/mediatek/mt8173/plat_topology.c b/plat/mediatek/mt8173/plat_topology.c
new file mode 100644
index 0000000..23e7d2d
--- /dev/null
+++ b/plat/mediatek/mt8173/plat_topology.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <lib/psci/psci.h>
+
+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));
+}
diff --git a/plat/mediatek/mt8173/platform.mk b/plat/mediatek/mt8173/platform.mk
new file mode 100644
index 0000000..6bf1aa7
--- /dev/null
+++ b/plat/mediatek/mt8173/platform.mk
@@ -0,0 +1,75 @@
+#
+# Copyright (c) 2015-2022, 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/ \
+ -I${MTK_PLAT}/include/ \
+ -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}/drivers/wdt/ \
+ -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/mtk_plat_common.c \
+ ${MTK_PLAT}/common/mtk_sip_svc.c \
+ ${MTK_PLAT}/drivers/pmic_wrap/pmic_wrap_init.c \
+ ${MTK_PLAT}/drivers/rtc/rtc_common.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}/drivers/wdt/wdt.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
diff --git a/plat/mediatek/mt8173/power_tracer.c b/plat/mediatek/mt8173/power_tracer.c
new file mode 100644
index 0000000..d1fcf9f
--- /dev/null
+++ b/plat/mediatek/mt8173/power_tracer.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <common/debug.h>
+
+#include <power_tracer.h>
+
+#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;
+ }
+}
diff --git a/plat/mediatek/mt8173/scu.c b/plat/mediatek/mt8173/scu.c
new file mode 100644
index 0000000..2524d72
--- /dev/null
+++ b/plat/mediatek/mt8173/scu.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <lib/mmio.h>
+
+#include <mcucfg.h>
+
+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);
+}
diff --git a/plat/mediatek/mt8183/aarch64/plat_helpers.S b/plat/mediatek/mt8183/aarch64/plat_helpers.S
new file mode 100644
index 0000000..5c39633
--- /dev/null
+++ b/plat/mediatek/mt8183/aarch64/plat_helpers.S
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/mediatek/mt8183/aarch64/platform_common.c b/plat/mediatek/mt8183/aarch64/platform_common.c
new file mode 100644
index 0000000..31d1339
--- /dev/null
+++ b/plat/mediatek/mt8183/aarch64/platform_common.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <mcsi/mcsi.h>
+#include <platform_def.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+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();
+}
diff --git a/plat/mediatek/mt8183/bl31_plat_setup.c b/plat/mediatek/mt8183/bl31_plat_setup.c
new file mode 100644
index 0000000..7dac8a4
--- /dev/null
+++ b/plat/mediatek/mt8183/bl31_plat_setup.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2019, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <devapc.h>
+#include <emi_mpu.h>
+#include <plat/common/common_def.h>
+#include <drivers/console.h>
+#include <common/debug.h>
+#include <drivers/generic_delay_timer.h>
+#include <mcucfg.h>
+#include <mt_gic_v3.h>
+#include <mt_timer.h>
+#include <lib/coreboot.h>
+#include <lib/mmio.h>
+#include <mtk_mcdi.h>
+#include <mtk_plat_common.h>
+#include <mtspmc.h>
+#include <plat_debug.h>
+#include <plat_params.h>
+#include <plat_private.h>
+#include <platform_def.h>
+#include <scu.h>
+#include <spm.h>
+#include <drivers/ti/uart/uart_16550.h>
+
+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_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();
+
+ mt_systimer_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);
+}
diff --git a/plat/mediatek/mt8183/drivers/devapc/devapc.c b/plat/mediatek/mt8183/drivers/devapc/devapc.c
new file mode 100644
index 0000000..9d76aa5
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/devapc/devapc.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <devapc.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+
+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();
+}
+
diff --git a/plat/mediatek/mt8183/drivers/devapc/devapc.h b/plat/mediatek/mt8183/drivers/devapc/devapc.h
new file mode 100644
index 0000000..042a8ff
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/devapc/devapc.h
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DEVAPC_H
+#define DEVAPC_H
+
+#include <stdint.h>
+
+#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 */
+
diff --git a/plat/mediatek/mt8183/drivers/emi_mpu/emi_mpu.c b/plat/mediatek/mt8183/drivers/emi_mpu/emi_mpu.c
new file mode 100644
index 0000000..56d2ce2
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/emi_mpu/emi_mpu.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <emi_mpu.h>
+
+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, 0xFFFFFFFFUL, 3,
+ (FORBIDDEN << 3 | FORBIDDEN << 6));
+ emi_mpu_set_region_protection(0x100000000UL, 0x23FFFFFFFUL, 4,
+ (FORBIDDEN << 3 | FORBIDDEN << 6));
+ dump_emi_mpu_regions();
+}
+
diff --git a/plat/mediatek/mt8183/drivers/emi_mpu/emi_mpu.h b/plat/mediatek/mt8183/drivers/emi_mpu/emi_mpu.h
new file mode 100644
index 0000000..b67ea56
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/emi_mpu/emi_mpu.h
@@ -0,0 +1,106 @@
+/*
+ * 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 <platform_def.h>
+
+#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 */
diff --git a/plat/mediatek/mt8183/drivers/gpio/mtgpio.c b/plat/mediatek/mt8183/drivers/gpio/mtgpio.c
new file mode 100644
index 0000000..61aaeef
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/gpio/mtgpio.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2019, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <gpio/mtgpio.h>
+#include <gpio/mtgpio_cfg.h>
+#include <drivers/gpio.h>
+#include <mcucfg.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+#include <spm.h>
+#include <stdbool.h>
+
+/******************************************************************************
+ *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,
+};
diff --git a/plat/mediatek/mt8183/drivers/gpio/mtgpio.h b/plat/mediatek/mt8183/drivers/gpio/mtgpio.h
new file mode 100644
index 0000000..9461c54
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/gpio/mtgpio.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2019, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_GPIO_H
+#define MT_GPIO_H
+
+#include <stdint.h>
+#include <plat/common/common_def.h>
+
+/* 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 */
diff --git a/plat/mediatek/mt8183/drivers/gpio/mtgpio_cfg.h b/plat/mediatek/mt8183/drivers/gpio/mtgpio_cfg.h
new file mode 100644
index 0000000..4e1fd2b
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/gpio/mtgpio_cfg.h
@@ -0,0 +1,208 @@
+/*
+ * 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 <stdint.h>
+#include <plat/common/common_def.h>
+
+#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 */
diff --git a/plat/mediatek/mt8183/drivers/mcdi/mtk_mcdi.c b/plat/mediatek/mt8183/drivers/mcdi/mtk_mcdi.c
new file mode 100644
index 0000000..29eebcb
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/mcdi/mtk_mcdi.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <sspm_reg.h>
+#include <mtk_mcdi.h>
+
+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 */
+}
diff --git a/plat/mediatek/mt8183/drivers/mcdi/mtk_mcdi.h b/plat/mediatek/mt8183/drivers/mcdi/mtk_mcdi.h
new file mode 100644
index 0000000..9a40df1
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/mcdi/mtk_mcdi.h
@@ -0,0 +1,34 @@
+/*
+ * 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 <stdbool.h>
+
+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__ */
diff --git a/plat/mediatek/mt8183/drivers/mcsi/mcsi.c b/plat/mediatek/mt8183/drivers/mcsi/mcsi.c
new file mode 100644
index 0000000..cbe7f0a
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/mcsi/mcsi.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <scu.h>
+#include <mcucfg.h>
+#include <drivers/delay_timer.h>
+#include <mcsi/mcsi.h>
+
+#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;
+}
diff --git a/plat/mediatek/mt8183/drivers/mcsi/mcsi.h b/plat/mediatek/mt8183/drivers/mcsi/mcsi.h
new file mode 100644
index 0000000..863e7da
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/mcsi/mcsi.h
@@ -0,0 +1,116 @@
+/*
+ * 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 <plat/common/common_def.h>
+#include <stdint.h>
+
+/* 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 */
diff --git a/plat/mediatek/mt8183/drivers/pmic/pmic.c b/plat/mediatek/mt8183/drivers/pmic/pmic.c
new file mode 100644
index 0000000..b0f898e
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/pmic/pmic.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <pmic_wrap_init.h>
+#include <pmic.h>
+
+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);
+}
diff --git a/plat/mediatek/mt8183/drivers/pmic/pmic.h b/plat/mediatek/mt8183/drivers/pmic/pmic.h
new file mode 100644
index 0000000..f19f9f6
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/pmic/pmic.h
@@ -0,0 +1,30 @@
+/*
+ * 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 */
diff --git a/plat/mediatek/mt8183/drivers/pmic/pmic_wrap_init.h b/plat/mediatek/mt8183/drivers/pmic/pmic_wrap_init.h
new file mode 100644
index 0000000..679c5e4
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/pmic/pmic_wrap_init.h
@@ -0,0 +1,94 @@
+/*
+ * 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 <platform_def.h>
+#include <stdint.h>
+
+/* 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 */
diff --git a/plat/mediatek/mt8183/drivers/rtc/rtc.c b/plat/mediatek/mt8183/drivers/rtc/rtc.c
new file mode 100644
index 0000000..a821c1b
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/rtc/rtc.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2019, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <rtc.h>
+
+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));
+ }
+}
diff --git a/plat/mediatek/mt8183/drivers/rtc/rtc.h b/plat/mediatek/mt8183/drivers/rtc/rtc.h
new file mode 100644
index 0000000..66686b4
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/rtc/rtc.h
@@ -0,0 +1,147 @@
+/*
+ * 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 */
diff --git a/plat/mediatek/mt8183/drivers/spm/spm.c b/plat/mediatek/mt8183/drivers/spm/spm.c
new file mode 100644
index 0000000..d6d2344
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/spm/spm.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <lib/bakery_lock.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <spm.h>
+#include <spm_pmic_wrap.h>
+
+DEFINE_BAKERY_LOCK(spm_lock);
+
+/* SPM_DVS_LEVEL */
+#define SPM_VMODEM_LEVEL_MASK (0xff << 16)
+#define SPM_VMODEM_LEVEL (1U << 18)
+#define SPM_VCORE_LEVEL_MASK (0xff)
+#define SPM_VCORE_LEVEL (1U << 1)
+
+/* CLK_SCP_CFG_0 */
+#define SPM_CK_OFF_CONTROL (0x3FF)
+
+/* CLK_SCP_CFG_1 */
+#define SPM_AXI_26M_SEL (0x1)
+
+/* AP_PLL_CON3 */
+#define SPM_PLL_CONTROL (0x7FAAAAF)
+
+/* AP_PLL_CON4 */
+#define SPM_PLL_OUT_OFF_CONTROL (0xFA0A)
+
+/* AP_PLL_CON6 */
+#define PLL_DLY (0x20000)
+
+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);
+
+ /* Set Vmodem / Vcore DVS init level */
+ mmio_clrsetbits_32(SPM_DVS_LEVEL,
+ SPM_VMODEM_LEVEL_MASK | SPM_VCORE_LEVEL_MASK,
+ SPM_VMODEM_LEVEL | SPM_VCORE_LEVEL);
+
+ /* switch ck_off/axi_26m control to SPM */
+ mmio_setbits_32(CLK_SCP_CFG_0, SPM_CK_OFF_CONTROL);
+ mmio_setbits_32(CLK_SCP_CFG_1, SPM_AXI_26M_SEL);
+
+ /* switch PLL/CLKSQ control to SPM */
+ mmio_clrbits_32(AP_PLL_CON3, SPM_PLL_CONTROL);
+ mmio_clrbits_32(AP_PLL_CON4, SPM_PLL_OUT_OFF_CONTROL);
+ mmio_clrbits_32(AP_PLL_CON6, PLL_DLY);
+
+ NOTICE("%s() end\n", __func__);
+}
diff --git a/plat/mediatek/mt8183/drivers/spm/spm.h b/plat/mediatek/mt8183/drivers/spm/spm.h
new file mode 100644
index 0000000..b2e83dc
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/spm/spm.h
@@ -0,0 +1,2552 @@
+/*
+ * 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 */
diff --git a/plat/mediatek/mt8183/drivers/spm/spm_pmic_wrap.c b/plat/mediatek/mt8183/drivers/spm/spm_pmic_wrap.c
new file mode 100644
index 0000000..ce85272
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/spm/spm_pmic_wrap.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+#include <spm.h>
+#include <spm_pmic_wrap.h>
+#include <lib/libc/string.h>
+
+#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;
+}
+
diff --git a/plat/mediatek/mt8183/drivers/spm/spm_pmic_wrap.h b/plat/mediatek/mt8183/drivers/spm/spm_pmic_wrap.h
new file mode 100644
index 0000000..194d347
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/spm/spm_pmic_wrap.h
@@ -0,0 +1,50 @@
+/*
+ * 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 */
+
diff --git a/plat/mediatek/mt8183/drivers/spm/spm_suspend.c b/plat/mediatek/mt8183/drivers/spm/spm_suspend.c
new file mode 100644
index 0000000..b9ac19f
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/spm/spm_suspend.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <mt_gic_v3.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+#include <pmic.h>
+#include <spm.h>
+#include <uart.h>
+
+#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);
+}
diff --git a/plat/mediatek/mt8183/drivers/spm/spm_suspend.h b/plat/mediatek/mt8183/drivers/spm/spm_suspend.h
new file mode 100644
index 0000000..e127c2e
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/spm/spm_suspend.h
@@ -0,0 +1,13 @@
+/*
+ * 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__*/
diff --git a/plat/mediatek/mt8183/drivers/spmc/mtspmc.c b/plat/mediatek/mt8183/drivers/spmc/mtspmc.c
new file mode 100644
index 0000000..ac8e1b4
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/spmc/mtspmc.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2019, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <arch_helpers.h>
+#include <cortex_a53.h>
+#include <cortex_a73.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+#include <mcucfg.h>
+#include <spm.h>
+#include <drivers/delay_timer.h>
+#include <mtspmc.h>
+
+#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<n>_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);
+}
diff --git a/plat/mediatek/mt8183/drivers/spmc/mtspmc.h b/plat/mediatek/mt8183/drivers/spmc/mtspmc.h
new file mode 100644
index 0000000..4cf3bcf
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/spmc/mtspmc.h
@@ -0,0 +1,42 @@
+/*
+ * 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 */
diff --git a/plat/mediatek/mt8183/drivers/spmc/mtspmc_private.h b/plat/mediatek/mt8183/drivers/spmc/mtspmc_private.h
new file mode 100644
index 0000000..2228e63
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/spmc/mtspmc_private.h
@@ -0,0 +1,233 @@
+/*
+ * 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 */
diff --git a/plat/mediatek/mt8183/drivers/sspm/sspm.c b/plat/mediatek/mt8183/drivers/sspm/sspm.c
new file mode 100644
index 0000000..6e76124
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/sspm/sspm.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <sspm.h>
+
+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) / sizeof(uint32_t))
+ && count) {
+ mdelay(100);
+ count--;
+ }
+
+ return (ipi_data == 1) ? 0 : -1;
+}
diff --git a/plat/mediatek/mt8183/drivers/sspm/sspm.h b/plat/mediatek/mt8183/drivers/sspm/sspm.h
new file mode 100644
index 0000000..2c2cc10
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/sspm/sspm.h
@@ -0,0 +1,32 @@
+/*
+ * 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__ */
diff --git a/plat/mediatek/mt8183/drivers/timer/mt_timer.c b/plat/mediatek/mt8183/drivers/timer/mt_timer.c
new file mode 100644
index 0000000..0da4815
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/timer/mt_timer.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mcucfg.h>
+#include <mt_timer.h>
+#include <platform_def.h>
+
+static void enable_systimer_compensation(void)
+{
+ unsigned int reg;
+
+ reg = mmio_read_32(CNTCR_REG);
+ reg &= ~COMP_15_EN;
+ reg |= COMP_20_EN;
+ mmio_write_32(CNTCR_REG, reg);
+
+ NOTICE("[systimer] CNTCR_REG(0x%x)\n", mmio_read_32(CNTCR_REG));
+}
+
+void mt_systimer_init(void)
+{
+ /* systimer is default on, so we only enable systimer compensation */
+ enable_systimer_compensation();
+}
diff --git a/plat/mediatek/mt8183/drivers/timer/mt_timer.h b/plat/mediatek/mt8183/drivers/timer/mt_timer.h
new file mode 100644
index 0000000..0b8edc5
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/timer/mt_timer.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_TIMER_H
+#define MT_TIMER_H
+
+
+#define SYSTIMER_BASE (0x10017000)
+#define CNTCR_REG (SYSTIMER_BASE + 0x0)
+#define CNTSR_REG (SYSTIMER_BASE + 0x4)
+
+#define COMP_15_EN (1 << 10)
+#define COMP_20_EN (1 << 11)
+
+void mt_systimer_init(void);
+
+#endif /* MT_TIMER_H */
diff --git a/plat/mediatek/mt8183/include/mcucfg.h b/plat/mediatek/mt8183/include/mcucfg.h
new file mode 100644
index 0000000..6b03818
--- /dev/null
+++ b/plat/mediatek/mt8183/include/mcucfg.h
@@ -0,0 +1,568 @@
+/*
+ * 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 <platform_def.h>
+#include <stdint.h>
+
+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 */
diff --git a/plat/mediatek/mt8183/include/mt_gic_v3.h b/plat/mediatek/mt8183/include/mt_gic_v3.h
new file mode 100644
index 0000000..b6fc29b
--- /dev/null
+++ b/plat/mediatek/mt8183/include/mt_gic_v3.h
@@ -0,0 +1,34 @@
+/*
+ * 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 <lib/mmio.h>
+
+#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)
+
+#define NR_INT_POL_CTL 20
+
+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_rdistif_init(void);
+void mt_gic_distif_save(void);
+void mt_gic_distif_restore(void);
+void mt_gic_rdistif_save(void);
+void mt_gic_rdistif_restore(void);
+void mt_gic_sync_dcm_enable(void);
+void mt_gic_sync_dcm_disable(void);
+
+#endif /* MT_GIC_V3_H */
diff --git a/plat/mediatek/mt8183/include/plat_dcm.h b/plat/mediatek/mt8183/include/plat_dcm.h
new file mode 100644
index 0000000..afa9b63
--- /dev/null
+++ b/plat/mediatek/mt8183/include/plat_dcm.h
@@ -0,0 +1,53 @@
+/*
+ * 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 */ \ No newline at end of file
diff --git a/plat/mediatek/mt8183/include/plat_debug.h b/plat/mediatek/mt8183/include/plat_debug.h
new file mode 100644
index 0000000..c9d73cc
--- /dev/null
+++ b/plat/mediatek/mt8183/include/plat_debug.h
@@ -0,0 +1,34 @@
+/*
+ * 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 */
diff --git a/plat/mediatek/mt8183/include/plat_macros.S b/plat/mediatek/mt8183/include/plat_macros.S
new file mode 100644
index 0000000..cac7769
--- /dev/null
+++ b/plat/mediatek/mt8183/include/plat_macros.S
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <platform_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"
+
+.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
diff --git a/plat/mediatek/mt8183/include/plat_private.h b/plat/mediatek/mt8183/include/plat_private.h
new file mode 100644
index 0000000..0853934
--- /dev/null
+++ b/plat/mediatek/mt8183/include/plat_private.h
@@ -0,0 +1,28 @@
+/*
+ * 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 */
diff --git a/plat/mediatek/mt8183/include/platform_def.h b/plat/mediatek/mt8183/include/platform_def.h
new file mode 100644
index 0000000..25ccfbc
--- /dev/null
+++ b/plat/mediatek/mt8183/include/platform_def.h
@@ -0,0 +1,321 @@
+/*
+ * 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 <arch.h>
+#include <drivers/arm/gic_common.h>
+
+#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 TOPCKGEN_BASE (IO_PHYS + 0x0)
+#define CLK_SCP_CFG_0 (TOPCKGEN_BASE + 0x200)
+#define CLK_SCP_CFG_1 (TOPCKGEN_BASE + 0x204)
+
+#define APMIXEDSYS (IO_PHYS + 0xC000)
+#define AP_PLL_CON3 (APMIXEDSYS + 0xC)
+#define AP_PLL_CON4 (APMIXEDSYS + 0x10)
+#define AP_PLL_CON6 (APMIXEDSYS + 0x18)
+#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 U(1)
+#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 PLATFORM_NUM_AFFS (PLATFORM_SYSTEM_COUNT + \
+ PLATFORM_CLUSTER_COUNT + \
+ PLATFORM_CORE_COUNT)
+
+#define SOC_CHIP_ID U(0x8183)
+
+/*******************************************************************************
+ * 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 */
diff --git a/plat/mediatek/mt8183/include/power_tracer.h b/plat/mediatek/mt8183/include/power_tracer.h
new file mode 100644
index 0000000..c93be64
--- /dev/null
+++ b/plat/mediatek/mt8183/include/power_tracer.h
@@ -0,0 +1,20 @@
+/*
+ * 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 */
+
diff --git a/plat/mediatek/mt8183/include/scu.h b/plat/mediatek/mt8183/include/scu.h
new file mode 100644
index 0000000..96b80c5
--- /dev/null
+++ b/plat/mediatek/mt8183/include/scu.h
@@ -0,0 +1,13 @@
+/*
+ * 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 */
diff --git a/plat/mediatek/mt8183/include/sspm_reg.h b/plat/mediatek/mt8183/include/sspm_reg.h
new file mode 100644
index 0000000..3f1ac86
--- /dev/null
+++ b/plat/mediatek/mt8183/include/sspm_reg.h
@@ -0,0 +1,41 @@
+/*
+ * 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__ */
diff --git a/plat/mediatek/mt8183/plat_dcm.c b/plat/mediatek/mt8183/plat_dcm.c
new file mode 100644
index 0000000..8ee77f1
--- /dev/null
+++ b/plat/mediatek/mt8183/plat_dcm.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2019, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <lib/bakery_lock.h>
+#include <drivers/console.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <plat_dcm.h>
+#include <plat_private.h>
+#include <plat_dcm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <mtk_plat_common.h>
+
+#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();
+}
diff --git a/plat/mediatek/mt8183/plat_debug.c b/plat/mediatek/mt8183/plat_debug.c
new file mode 100644
index 0000000..2f0b67d
--- /dev/null
+++ b/plat/mediatek/mt8183/plat_debug.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <plat_debug.h>
+#include <platform_def.h>
+#include <spm.h>
+
+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);
+}
diff --git a/plat/mediatek/mt8183/plat_mt_gic.c b/plat/mediatek/mt8183/plat_mt_gic.c
new file mode 100644
index 0000000..35792b2
--- /dev/null
+++ b/plat/mediatek/mt8183/plat_mt_gic.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2019, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv3.h>
+#include <bl31/interrupt_mgmt.h>
+#include <mt_gic_v3.h>
+#include <mtk_plat_common.h>
+#include "../drivers/arm/gic/v3/gicv3_private.h"
+#include "plat_private.h"
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <stdint.h>
+#include <stdio.h>
+
+uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+static uint32_t rdist_has_saved[PLATFORM_CORE_COUNT];
+
+/* we save and restore the GICv3 context on system suspend */
+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,
+};
+
+struct gic_chip_data {
+ unsigned int saved_group;
+ unsigned int saved_enable;
+ unsigned int saved_conf0;
+ unsigned int saved_conf1;
+ unsigned int saved_grpmod;
+};
+
+static struct gic_chip_data gic_data;
+
+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_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_rdistif_init(void)
+{
+ unsigned int proc_num;
+ unsigned int index;
+ uintptr_t gicr_base;
+
+ proc_num = plat_my_core_pos();
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+
+ /* set all SGI/PPI as non-secure GROUP1 by default */
+ mmio_write_32(gicr_base + GICR_IGROUPR0, ~0U);
+ mmio_write_32(gicr_base + GICR_IGRPMODR0, 0x0);
+
+ /* setup the default PPI/SGI priorities */
+ for (index = 0; index < TOTAL_PCPU_INTR_NUM; index += 4U)
+ gicr_write_ipriorityr(gicr_base, index,
+ GICD_IPRIORITYR_DEF_VAL);
+}
+
+void mt_gic_distif_save(void)
+{
+ gicv3_distif_save(&dist_ctx);
+}
+
+void mt_gic_distif_restore(void)
+{
+ gicv3_distif_init_restore(&dist_ctx);
+}
+
+void mt_gic_rdistif_save(void)
+{
+ unsigned int proc_num;
+ uintptr_t gicr_base;
+
+ proc_num = plat_my_core_pos();
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+
+ gic_data.saved_group = mmio_read_32(gicr_base + GICR_IGROUPR0);
+ gic_data.saved_enable = mmio_read_32(gicr_base + GICR_ISENABLER0);
+ gic_data.saved_conf0 = mmio_read_32(gicr_base + GICR_ICFGR0);
+ gic_data.saved_conf1 = mmio_read_32(gicr_base + GICR_ICFGR1);
+ gic_data.saved_grpmod = mmio_read_32(gicr_base + GICR_IGRPMODR0);
+
+ rdist_has_saved[proc_num] = 1;
+}
+
+void mt_gic_rdistif_restore(void)
+{
+ unsigned int proc_num;
+ uintptr_t gicr_base;
+
+ proc_num = plat_my_core_pos();
+ if (rdist_has_saved[proc_num] == 1) {
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+ mmio_write_32(gicr_base + GICR_IGROUPR0, gic_data.saved_group);
+ mmio_write_32(gicr_base + GICR_ISENABLER0, gic_data.saved_enable);
+ mmio_write_32(gicr_base + GICR_ICFGR0, gic_data.saved_conf0);
+ mmio_write_32(gicr_base + GICR_ICFGR1, gic_data.saved_conf1);
+ mmio_write_32(gicr_base + GICR_IGRPMODR0, gic_data.saved_grpmod);
+ }
+}
+
+void mt_gic_sync_dcm_enable(void)
+{
+ mmio_clrsetbits_32(GIC_SYNC_DCM, GIC_SYNC_DCM_MASK, GIC_SYNC_DCM_ON);
+}
+
+void mt_gic_sync_dcm_disable(void)
+{
+ mmio_clrsetbits_32(GIC_SYNC_DCM, GIC_SYNC_DCM_MASK, GIC_SYNC_DCM_OFF);
+}
+
+void mt_gic_init(void)
+{
+ gicv3_distif_init();
+ gicv3_cpuif_enable(plat_my_core_pos());
+ mt_gic_rdistif_init();
+
+ clear_sec_pol_ctl_en();
+}
diff --git a/plat/mediatek/mt8183/plat_pm.c b/plat/mediatek/mt8183/plat_pm.c
new file mode 100644
index 0000000..6094a17
--- /dev/null
+++ b/plat/mediatek/mt8183/plat_pm.c
@@ -0,0 +1,589 @@
+/*
+ * Copyright (c) 2019-2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* common headers */
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <errno.h>
+
+/* mediatek platform specific headers */
+#include <platform_def.h>
+#include <scu.h>
+#include <mt_gic_v3.h>
+#include <mtk_mcdi.h>
+#include <mtk_plat_common.h>
+#include <mtgpio.h>
+#include <mtspmc.h>
+#include <plat_dcm.h>
+#include <plat_debug.h>
+#include <plat_params.h>
+#include <plat_private.h>
+#include <power_tracer.h>
+#include <pmic.h>
+#include <spm.h>
+#include <spm_suspend.h>
+#include <sspm.h>
+#include <rtc.h>
+
+/* 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_cpu_pwrdwn_common(void)
+{
+ /* Prevent interrupts from spuriously waking up this cpu */
+ mt_gic_rdistif_save();
+ mt_gic_cpuif_disable();
+}
+
+static void plat_cpu_pwron_common(void)
+{
+ /* Enable the gic cpu interface */
+ mt_gic_cpuif_enable();
+ mt_gic_rdistif_init();
+ mt_gic_rdistif_restore();
+}
+
+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)
+{
+ u_register_t 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);
+ int clst_pwr = spm_get_cluster_powerstate(cluster);
+ unsigned int i;
+
+ mcdi_ctrl_before_hotplug_on(cluster, cpu);
+ hotplug_ctrl_cluster_on(cluster, cpu);
+
+ if (clst_pwr == 0) {
+ /* init cpu reset arch as AARCH64 of cluster */
+ for (i = 0; i < PLATFORM_MAX_CPUS_PER_CLUSTER; i++) {
+ mcucfg_init_archstate(cluster, i, 1);
+ mcucfg_set_bootaddr(cluster, i, 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));
+
+ plat_cpu_pwrdwn_common();
+
+ 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);
+
+ plat_cpu_pwron_common();
+
+ 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);
+
+ plat_cpu_pwrdwn_common();
+
+ 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))
+ ;
+
+ mt_gic_distif_save();
+ } 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_distif_restore();
+ mt_gic_rdistif_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();
+ } else {
+ plat_cpu_pwron_common();
+ }
+
+ 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)
+{
+ unsigned int i;
+
+ *psci_ops = &plat_plat_pm_ops;
+ secure_entrypoint = sec_entrypoint;
+
+ /* Init cpu reset arch as AARCH64 of cluster 0 */
+ for (i = 0; i < PLATFORM_MAX_CPUS_PER_CLUSTER; i++) {
+ mcucfg_init_archstate(0, i, 1);
+ mcucfg_set_bootaddr(0, i, secure_entrypoint);
+ }
+
+ if (!check_mcdi_ctl_stat()) {
+ HP_SSPM_CTRL = false;
+ MCDI_SSPM = false;
+ }
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8183/plat_topology.c b/plat/mediatek/mt8183/plat_topology.c
new file mode 100644
index 0000000..7b1dd03
--- /dev/null
+++ b/plat/mediatek/mt8183/plat_topology.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <platform_def.h>
+#include <lib/psci/psci.h>
+
+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));
+}
diff --git a/plat/mediatek/mt8183/platform.mk b/plat/mediatek/mt8183/platform.mk
new file mode 100644
index 0000000..a737d24
--- /dev/null
+++ b/plat/mediatek/mt8183/platform.mk
@@ -0,0 +1,90 @@
+#
+# Copyright (c) 2019-2022, 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}/drivers/uart/ \
+ -I${MTK_PLAT}/include/ \
+ -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/timer/ \
+ -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}/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
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+BL31_SOURCES += common/desc_image_load.c \
+ drivers/arm/cci/cci.c \
+ ${GICV3_SOURCES} \
+ 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/params_setup.c \
+ ${MTK_PLAT}/drivers/pmic_wrap/pmic_wrap_init.c \
+ ${MTK_PLAT}/drivers/rtc/rtc_common.c \
+ ${MTK_PLAT}/drivers/uart/uart.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/timer/mt_timer.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
+
diff --git a/plat/mediatek/mt8183/scu.c b/plat/mediatek/mt8183/scu.c
new file mode 100644
index 0000000..c4f1c3f
--- /dev/null
+++ b/plat/mediatek/mt8183/scu.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mcucfg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+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);
+}
diff --git a/plat/mediatek/mt8186/aarch64/plat_helpers.S b/plat/mediatek/mt8186/aarch64/plat_helpers.S
new file mode 100644
index 0000000..35b293f
--- /dev/null
+++ b/plat/mediatek/mt8186/aarch64/plat_helpers.S
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .globl plat_is_my_cpu_primary
+ .globl plat_my_core_pos
+ .globl plat_mediatek_calc_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)
+ * This function uses the plat_mediatek_calc_core_pos()
+ * definition to get the index of the calling CPU.
+ * -----------------------------------------------------
+ */
+func plat_my_core_pos
+ mrs x0, mpidr_el1
+ b plat_mediatek_calc_core_pos
+endfunc plat_my_core_pos
+
+ /* -----------------------------------------------------
+ * unsigned int plat_mediatek_calc_core_pos(u_register_t mpidr);
+ *
+ * With this function: CorePos = CoreID (AFF1)
+ * we do it with x0 = (x0 >> 8) & 0xff
+ * -----------------------------------------------------
+ */
+func plat_mediatek_calc_core_pos
+ mov x1, #MPIDR_AFFLVL_MASK
+ and x0, x1, x0, lsr #MPIDR_AFF1_SHIFT
+ ret
+endfunc plat_mediatek_calc_core_pos
diff --git a/plat/mediatek/mt8186/aarch64/platform_common.c b/plat/mediatek/mt8186/aarch64/platform_common.c
new file mode 100644
index 0000000..021cab7
--- /dev/null
+++ b/plat/mediatek/mt8186/aarch64/platform_common.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <platform_def.h>
+
+/* Table of regions to map using the MMU. */
+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_RNG2_BASE, MTK_DEV_RNG2_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(MTK_MCDI_SRAM_BASE, MTK_MCDI_SRAM_MAP_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)
+{
+ mmap_add_region(total_base, total_base, total_size,
+ MT_RW_DATA | MT_SECURE);
+ mmap_add_region(ro_start, ro_start, ro_limit - ro_start,
+ MT_CODE | 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;
+}
diff --git a/plat/mediatek/mt8186/bl31_plat_setup.c b/plat/mediatek/mt8186/bl31_plat_setup.c
new file mode 100644
index 0000000..5fc6b6e
--- /dev/null
+++ b/plat/mediatek/mt8186/bl31_plat_setup.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* System Includes */
+#include <assert.h>
+
+/* Project Includes */
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/coreboot.h>
+
+/* Platform Includes */
+#include <emi_mpu.h>
+#include <mt_gic_v3.h>
+#include <mt_spm.h>
+#include <mt_timer.h>
+#include <mtgpio.h>
+#include <mtk_dcm.h>
+#include <plat_params.h>
+#include <plat_private.h>
+
+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;
+ }
+}
+
+/*******************************************************************************
+ * 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_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
+
+ INFO("MT8186 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)
+{
+ dcm_set_default();
+
+ /* Initialize the GIC driver, CPU and distributor interfaces */
+ mt_gic_driver_init();
+ mt_gic_init();
+
+ mt_gpio_init();
+ mt_systimer_init();
+ generic_delay_timer_init();
+ spm_boot_init();
+
+ emi_mpu_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_configure_mmu_el3(BL31_START,
+ BL31_END - BL31_START,
+ BL_CODE_BASE,
+ BL_CODE_END);
+}
diff --git a/plat/mediatek/mt8186/drivers/dcm/mtk_dcm.c b/plat/mediatek/mt8186/drivers/dcm/mtk_dcm.c
new file mode 100644
index 0000000..5dde5c5
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/dcm/mtk_dcm.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <mtk_dcm.h>
+#include <mtk_dcm_utils.h>
+
+static void dcm_armcore(bool mode)
+{
+ dcm_mp_cpusys_top_bus_pll_div_dcm(mode);
+ dcm_mp_cpusys_top_cpu_pll_div_0_dcm(mode);
+ dcm_mp_cpusys_top_cpu_pll_div_1_dcm(mode);
+}
+
+static void dcm_mcusys(bool on)
+{
+ dcm_mp_cpusys_top_adb_dcm(on);
+ dcm_mp_cpusys_top_apb_dcm(on);
+ dcm_mp_cpusys_top_cpubiu_dcm(on);
+ dcm_mp_cpusys_top_cpubiu_dbg_cg(on);
+ dcm_mp_cpusys_top_misc_dcm(on);
+ dcm_mp_cpusys_top_mp0_qdcm(on);
+ dcm_cpccfg_reg_emi_wfifo(on);
+ dcm_mp_cpusys_top_last_cor_idle_dcm(on);
+}
+
+static void dcm_stall(bool on)
+{
+ dcm_mp_cpusys_top_core_stall_dcm(on);
+ dcm_mp_cpusys_top_fcm_stall_dcm(on);
+}
+
+static bool check_dcm_state(void)
+{
+ bool ret = true;
+
+ ret &= dcm_mp_cpusys_top_bus_pll_div_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on();
+
+ ret &= dcm_mp_cpusys_top_adb_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_apb_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_cpubiu_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_cpubiu_dbg_cg_is_on();
+ ret &= dcm_mp_cpusys_top_misc_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_mp0_qdcm_is_on();
+ ret &= dcm_cpccfg_reg_emi_wfifo_is_on();
+ ret &= dcm_mp_cpusys_top_last_cor_idle_dcm_is_on();
+
+ ret &= dcm_mp_cpusys_top_core_stall_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_fcm_stall_dcm_is_on();
+
+ return ret;
+}
+
+void dcm_set_default(void)
+{
+ dcm_armcore(true);
+ dcm_mcusys(true);
+ dcm_stall(true);
+
+ INFO("%s: %d", __func__, check_dcm_state());
+}
diff --git a/plat/mediatek/mt8186/drivers/dcm/mtk_dcm.h b/plat/mediatek/mt8186/drivers/dcm/mtk_dcm.h
new file mode 100644
index 0000000..6abcff4
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/dcm/mtk_dcm.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_DCM_H
+#define MTK_DCM_H
+
+#include <stdbool.h>
+
+void dcm_set_default(void);
+
+#endif /* #ifndef MTK_DCM_H */
diff --git a/plat/mediatek/mt8186/drivers/dcm/mtk_dcm_utils.c b/plat/mediatek/mt8186/drivers/dcm/mtk_dcm_utils.c
new file mode 100644
index 0000000..ae0e964
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/dcm/mtk_dcm_utils.c
@@ -0,0 +1,490 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <mtk_dcm_utils.h>
+
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_MASK (BIT(16) | \
+ BIT(17) | \
+ BIT(18) | \
+ BIT(21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_MASK (BIT(16) | \
+ BIT(17) | \
+ BIT(18))
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_ON (BIT(16) | \
+ BIT(17) | \
+ BIT(18) | \
+ BIT(21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_ON (BIT(16) | \
+ BIT(17) | \
+ BIT(18))
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_OFF ((0x0 << 16) | \
+ (0x0 << 17) | \
+ (0x0 << 18) | \
+ (0x0 << 21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_OFF ((0x0 << 16) | \
+ (0x0 << 17) | \
+ (0x0 << 18))
+
+bool dcm_mp_cpusys_top_adb_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG4) &
+ MP_CPUSYS_TOP_ADB_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_ADB_DCM_REG0_ON);
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0) &
+ MP_CPUSYS_TOP_ADB_DCM_REG1_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_ADB_DCM_REG1_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_adb_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_adb_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG4,
+ MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG0_ON);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+ MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG1_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_adb_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG4,
+ MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG0_OFF);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+ MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG1_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_APB_DCM_REG0_MASK (BIT(5))
+#define MP_CPUSYS_TOP_APB_DCM_REG1_MASK (BIT(8))
+#define MP_CPUSYS_TOP_APB_DCM_REG2_MASK (BIT(16))
+#define MP_CPUSYS_TOP_APB_DCM_REG0_ON (BIT(5))
+#define MP_CPUSYS_TOP_APB_DCM_REG1_ON (BIT(8))
+#define MP_CPUSYS_TOP_APB_DCM_REG2_ON (BIT(16))
+#define MP_CPUSYS_TOP_APB_DCM_REG0_OFF ((0x0 << 5))
+#define MP_CPUSYS_TOP_APB_DCM_REG1_OFF ((0x0 << 8))
+#define MP_CPUSYS_TOP_APB_DCM_REG2_OFF ((0x0 << 16))
+
+bool dcm_mp_cpusys_top_apb_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0) &
+ MP_CPUSYS_TOP_APB_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_APB_DCM_REG0_ON);
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0) &
+ MP_CPUSYS_TOP_APB_DCM_REG1_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_APB_DCM_REG1_ON);
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP0_DCM_CFG0) &
+ MP_CPUSYS_TOP_APB_DCM_REG2_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_APB_DCM_REG2_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_apb_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_apb_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG0_ON);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG1_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG1_ON);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG2_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG2_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_apb_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG0_OFF);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG1_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG1_OFF);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG2_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG2_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK (BIT(11) | \
+ BIT(24) | \
+ BIT(25))
+#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON (BIT(11) | \
+ BIT(24) | \
+ BIT(25))
+#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_OFF ((0x0 << 11) | \
+ (0x0 << 24) | \
+ (0x0 << 25))
+
+bool dcm_mp_cpusys_top_bus_pll_div_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG) &
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_bus_pll_div_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_bus_pll_div_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_bus_pll_div_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK (BIT(0))
+#define MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON (BIT(0))
+#define MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_OFF ((0x0 << 0))
+
+bool dcm_mp_cpusys_top_core_stall_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP0_DCM_CFG7) &
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_core_stall_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_core_stall_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_core_stall_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CPUBIU_DBG_CG_REG0_MASK (BIT(0))
+#define MP_CPUSYS_TOP_CPUBIU_DBG_CG_REG0_ON ((0x0 << 0))
+#define MP_CPUSYS_TOP_CPUBIU_DBG_CG_REG0_OFF (BIT(0))
+
+bool dcm_mp_cpusys_top_cpubiu_dbg_cg_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MCSI_CFG2) &
+ MP_CPUSYS_TOP_CPUBIU_DBG_CG_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_CPUBIU_DBG_CG_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_cpubiu_dbg_cg(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpubiu_dbg_cg'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCSI_CFG2,
+ MP_CPUSYS_TOP_CPUBIU_DBG_CG_REG0_MASK,
+ MP_CPUSYS_TOP_CPUBIU_DBG_CG_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpubiu_dbg_cg'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCSI_CFG2,
+ MP_CPUSYS_TOP_CPUBIU_DBG_CG_REG0_MASK,
+ MP_CPUSYS_TOP_CPUBIU_DBG_CG_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK ((0xffff << 0))
+#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON ((0xffff << 0))
+#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_OFF ((0x0 << 0))
+
+bool dcm_mp_cpusys_top_cpubiu_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MCSIC_DCM0) &
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_cpubiu_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpubiu_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCSIC_DCM0,
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpubiu_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCSIC_DCM0,
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK (BIT(11) | \
+ BIT(24) | \
+ BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON (BIT(11) | \
+ BIT(24) | \
+ BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_OFF ((0x0 << 11) | \
+ (0x0 << 24) | \
+ (0x0 << 25))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG0) &
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_cpu_pll_div_0_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_0_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG0,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_0_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG0,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK (BIT(11) | \
+ BIT(24) | \
+ BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON (BIT(11) | \
+ BIT(24) | \
+ BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_OFF ((0x0 << 11) | \
+ (0x0 << 24) | \
+ (0x0 << 25))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG1) &
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_cpu_pll_div_1_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_1_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG1,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_1_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG1,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK (BIT(4))
+#define MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON (BIT(4))
+#define MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_OFF ((0x0 << 4))
+
+bool dcm_mp_cpusys_top_fcm_stall_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP0_DCM_CFG7) &
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_fcm_stall_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_fcm_stall_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_fcm_stall_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK (BIT(31))
+#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON (BIT(31))
+#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_OFF ((0x0 << 31))
+
+bool dcm_mp_cpusys_top_last_cor_idle_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG) &
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_last_cor_idle_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_last_cor_idle_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_last_cor_idle_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_MASK (BIT(0) | \
+ BIT(1) | \
+ BIT(2) | \
+ BIT(3) | \
+ BIT(4))
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_ON (BIT(0) | \
+ BIT(1) | \
+ BIT(2) | \
+ BIT(3) | \
+ BIT(4))
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_OFF ((0x0 << 0) | \
+ (0x0 << 1) | \
+ (0x0 << 2) | \
+ (0x0 << 3) | \
+ (0x0 << 4))
+
+bool dcm_mp_cpusys_top_misc_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0) &
+ MP_CPUSYS_TOP_MISC_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_MISC_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_misc_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_misc_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_MISC_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_MISC_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_misc_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_MISC_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_MISC_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK (BIT(0) | \
+ BIT(1) | \
+ BIT(2) | \
+ BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_ON (BIT(0) | \
+ BIT(1) | \
+ BIT(2) | \
+ BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_OFF ((0x0 << 0) | \
+ (0x0 << 1) | \
+ (0x0 << 2) | \
+ (0x0 << 3))
+
+bool dcm_mp_cpusys_top_mp0_qdcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP0_DCM_CFG0) &
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_MP0_QDCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_mp0_qdcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_mp0_qdcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_mp0_qdcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_OFF);
+ }
+}
+
+#define CPCCFG_REG_EMI_WFIFO_REG0_MASK (BIT(0) | BIT(2))
+#define CPCCFG_REG_EMI_WFIFO_REG0_ON (BIT(0) | BIT(2))
+#define CPCCFG_REG_EMI_WFIFO_REG0_OFF ((0x0 << 0) | (0x0 << 2))
+
+bool dcm_cpccfg_reg_emi_wfifo_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(CPCCFG_REG_EMI_WFIFO) &
+ CPCCFG_REG_EMI_WFIFO_REG0_MASK) ==
+ (unsigned int) CPCCFG_REG_EMI_WFIFO_REG0_ON);
+
+ return ret;
+}
+
+void dcm_cpccfg_reg_emi_wfifo(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'cpccfg_reg_emi_wfifo'" */
+ mmio_clrsetbits_32(CPCCFG_REG_EMI_WFIFO,
+ CPCCFG_REG_EMI_WFIFO_REG0_MASK,
+ CPCCFG_REG_EMI_WFIFO_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'cpccfg_reg_emi_wfifo'" */
+ mmio_clrsetbits_32(CPCCFG_REG_EMI_WFIFO,
+ CPCCFG_REG_EMI_WFIFO_REG0_MASK,
+ CPCCFG_REG_EMI_WFIFO_REG0_OFF);
+ }
+}
+
diff --git a/plat/mediatek/mt8186/drivers/dcm/mtk_dcm_utils.h b/plat/mediatek/mt8186/drivers/dcm/mtk_dcm_utils.h
new file mode 100644
index 0000000..ba76594
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/dcm/mtk_dcm_utils.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_DCM_UTILS_H
+#define MTK_DCM_UTILS_H
+
+#include <stdbool.h>
+
+#include <mtk_dcm.h>
+#include <platform_def.h>
+
+/* Base */
+#define MP_CPUSYS_TOP_BASE 0xc538000
+#define CPCCFG_REG_BASE 0xc53a800
+
+/* Register Definition */
+#define CPCCFG_REG_EMI_WFIFO (CPCCFG_REG_BASE + 0x100)
+#define MP_CPUSYS_TOP_BUS_PLLDIV_CFG (MP_CPUSYS_TOP_BASE + 0x22e0)
+#define MP_CPUSYS_TOP_CPU_PLLDIV_CFG0 (MP_CPUSYS_TOP_BASE + 0x22a0)
+#define MP_CPUSYS_TOP_CPU_PLLDIV_CFG1 (MP_CPUSYS_TOP_BASE + 0x22a4)
+#define MP_CPUSYS_TOP_MCSIC_DCM0 (MP_CPUSYS_TOP_BASE + 0x2440)
+#define MP_CPUSYS_TOP_MCSI_CFG2 (MP_CPUSYS_TOP_BASE + 0x2418)
+#define MP_CPUSYS_TOP_MCUSYS_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x25c0)
+#define MP_CPUSYS_TOP_MP0_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x4880)
+#define MP_CPUSYS_TOP_MP0_DCM_CFG7 (MP_CPUSYS_TOP_BASE + 0x489c)
+#define MP_CPUSYS_TOP_MP_ADB_DCM_CFG4 (MP_CPUSYS_TOP_BASE + 0x2510)
+#define MP_CPUSYS_TOP_MP_MISC_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x2518)
+
+bool dcm_mp_cpusys_top_adb_dcm_is_on(void);
+void dcm_mp_cpusys_top_adb_dcm(bool on);
+bool dcm_mp_cpusys_top_apb_dcm_is_on(void);
+void dcm_mp_cpusys_top_apb_dcm(bool on);
+bool dcm_mp_cpusys_top_bus_pll_div_dcm_is_on(void);
+void dcm_mp_cpusys_top_bus_pll_div_dcm(bool on);
+bool dcm_mp_cpusys_top_core_stall_dcm_is_on(void);
+void dcm_mp_cpusys_top_core_stall_dcm(bool on);
+bool dcm_mp_cpusys_top_cpubiu_dbg_cg_is_on(void);
+void dcm_mp_cpusys_top_cpubiu_dbg_cg(bool on);
+bool dcm_mp_cpusys_top_cpubiu_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpubiu_dcm(bool on);
+bool dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpu_pll_div_0_dcm(bool on);
+bool dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpu_pll_div_1_dcm(bool on);
+bool dcm_mp_cpusys_top_fcm_stall_dcm_is_on(void);
+void dcm_mp_cpusys_top_fcm_stall_dcm(bool on);
+bool dcm_mp_cpusys_top_last_cor_idle_dcm_is_on(void);
+void dcm_mp_cpusys_top_last_cor_idle_dcm(bool on);
+bool dcm_mp_cpusys_top_misc_dcm_is_on(void);
+void dcm_mp_cpusys_top_misc_dcm(bool on);
+bool dcm_mp_cpusys_top_mp0_qdcm_is_on(void);
+void dcm_mp_cpusys_top_mp0_qdcm(bool on);
+bool dcm_cpccfg_reg_emi_wfifo_is_on(void);
+void dcm_cpccfg_reg_emi_wfifo(bool on);
+#endif
diff --git a/plat/mediatek/mt8186/drivers/dfd/plat_dfd.c b/plat/mediatek/mt8186/drivers/dfd/plat_dfd.c
new file mode 100644
index 0000000..ade0837
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/dfd/plat_dfd.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mtk_sip_svc.h>
+#include <plat_dfd.h>
+
+static bool dfd_enabled;
+static uint64_t dfd_base_addr;
+static uint64_t dfd_chain_length;
+static uint64_t dfd_cache_dump;
+
+static void dfd_setup(uint64_t base_addr, uint64_t chain_length,
+ uint64_t cache_dump)
+{
+ mmio_write_32(MCUSYS_DFD_MAP, base_addr >> 24);
+ mmio_write_32(WDT_DEBUG_CTL, WDT_DEBUG_CTL_VAL_0);
+
+ sync_writel(DFD_INTERNAL_CTL, (BIT(0) | BIT(2)));
+
+ mmio_setbits_32(DFD_INTERNAL_CTL, BIT(13));
+ mmio_setbits_32(DFD_INTERNAL_CTL, BIT(3));
+ mmio_setbits_32(DFD_INTERNAL_CTL, (BIT(19) | BIT(20)));
+ mmio_write_32(DFD_INTERNAL_PWR_ON, (BIT(0) | BIT(1) | BIT(3)));
+ mmio_write_32(DFD_CHAIN_LENGTH0, chain_length);
+ mmio_write_32(DFD_INTERNAL_SHIFT_CLK_RATIO, 0);
+ mmio_write_32(DFD_INTERNAL_TEST_SO_0, DFD_INTERNAL_TEST_SO_0_VAL);
+ mmio_write_32(DFD_INTERNAL_NUM_OF_TEST_SO_GROUP, 1);
+
+ mmio_write_32(DFD_TEST_SI_0, DFD_TEST_SI_0_VAL);
+ mmio_write_32(DFD_TEST_SI_1, DFD_TEST_SI_1_VAL);
+
+ sync_writel(DFD_V30_CTL, 1);
+
+ mmio_write_32(DFD_V30_BASE_ADDR, (base_addr & 0xFFF00000));
+
+ /* setup global variables for suspend and resume */
+ dfd_enabled = true;
+ dfd_base_addr = base_addr;
+ dfd_chain_length = chain_length;
+ dfd_cache_dump = cache_dump;
+
+ if ((cache_dump & DFD_CACHE_DUMP_ENABLE) != 0UL) {
+ mmio_write_32(WDT_DEBUG_CTL, WDT_DEBUG_CTL_VAL_1);
+ sync_writel(DFD_V35_ENALBE, 1);
+ sync_writel(DFD_V35_TAP_NUMBER, DFD_V35_TAP_NUMBER_VAL);
+ sync_writel(DFD_V35_TAP_EN, DFD_V35_TAP_EN_VAL);
+ sync_writel(DFD_V35_SEQ0_0, DFD_V35_SEQ0_0_VAL);
+
+ if (cache_dump & DFD_PARITY_ERR_TRIGGER) {
+ sync_writel(DFD_HW_TRIGGER_MASK, DFD_HW_TRIGGER_MASK_VAL);
+ mmio_setbits_32(DFD_INTERNAL_CTL, BIT(4));
+ }
+ }
+ dsbsy();
+}
+
+void dfd_resume(void)
+{
+ if (dfd_enabled == true) {
+ dfd_setup(dfd_base_addr, dfd_chain_length, dfd_cache_dump);
+ }
+}
+
+uint64_t dfd_smc_dispatcher(uint64_t arg0, uint64_t arg1,
+ uint64_t arg2, uint64_t arg3)
+{
+ uint64_t ret = 0L;
+
+ switch (arg0) {
+ case PLAT_MTK_DFD_SETUP_MAGIC:
+ INFO("[%s] DFD setup call from kernel\n", __func__);
+ dfd_setup(arg1, arg2, arg3);
+ break;
+ case PLAT_MTK_DFD_READ_MAGIC:
+ /* only allow to access DFD register base + 0x200 */
+ if (arg1 <= 0x200) {
+ ret = mmio_read_32(MISC1_CFG_BASE + arg1);
+ }
+ break;
+ case PLAT_MTK_DFD_WRITE_MAGIC:
+ /* only allow to access DFD register base + 0x200 */
+ if (arg1 <= 0x200) {
+ sync_writel(MISC1_CFG_BASE + arg1, arg2);
+ }
+ break;
+ default:
+ ret = MTK_SIP_E_INVALID_PARAM;
+ break;
+ }
+
+ return ret;
+}
diff --git a/plat/mediatek/mt8186/drivers/dfd/plat_dfd.h b/plat/mediatek/mt8186/drivers/dfd/plat_dfd.h
new file mode 100644
index 0000000..1901ec9
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/dfd/plat_dfd.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_DFD_H
+#define PLAT_DFD_H
+
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#define sync_writel(addr, val) do { mmio_write_32((addr), (val)); \
+ dsbsy(); \
+ } while (0)
+
+#define PLAT_MTK_DFD_SETUP_MAGIC (0x99716150)
+#define PLAT_MTK_DFD_READ_MAGIC (0x99716151)
+#define PLAT_MTK_DFD_WRITE_MAGIC (0x99716152)
+
+#define MCU_BIU_BASE (MCUCFG_BASE)
+#define MISC1_CFG_BASE (MCU_BIU_BASE + 0xA040)
+
+#define DFD_INTERNAL_CTL (MISC1_CFG_BASE + 0x00)
+#define DFD_INTERNAL_PWR_ON (MISC1_CFG_BASE + 0x08)
+#define DFD_CHAIN_LENGTH0 (MISC1_CFG_BASE + 0x0C)
+#define DFD_INTERNAL_SHIFT_CLK_RATIO (MISC1_CFG_BASE + 0x10)
+#define DFD_INTERNAL_TEST_SO_0 (MISC1_CFG_BASE + 0x28)
+#define DFD_INTERNAL_NUM_OF_TEST_SO_GROUP (MISC1_CFG_BASE + 0x30)
+#define DFD_V30_CTL (MISC1_CFG_BASE + 0x48)
+#define DFD_V30_BASE_ADDR (MISC1_CFG_BASE + 0x4C)
+#define DFD_TEST_SI_0 (MISC1_CFG_BASE + 0x58)
+#define DFD_TEST_SI_1 (MISC1_CFG_BASE + 0x5C)
+#define DFD_HW_TRIGGER_MASK (MISC1_CFG_BASE + 0xBC)
+
+#define DFD_V35_ENALBE (MCU_BIU_BASE + 0xA0A8)
+#define DFD_V35_TAP_NUMBER (MCU_BIU_BASE + 0xA0AC)
+#define DFD_V35_TAP_EN (MCU_BIU_BASE + 0xA0B0)
+#define DFD_V35_SEQ0_0 (MCU_BIU_BASE + 0xA0C0)
+#define DFD_V35_SEQ0_1 (MCU_BIU_BASE + 0xA0C4)
+
+#define DFD_CACHE_DUMP_ENABLE (1U)
+#define DFD_PARITY_ERR_TRIGGER (2U)
+
+#define MCUSYS_DFD_MAP (0x10001390)
+#define WDT_DEBUG_CTL (0x10007048)
+
+#define WDT_DEBUG_CTL_VAL_0 (0x950603A0)
+#define DFD_INTERNAL_TEST_SO_0_VAL (0x3B)
+#define DFD_TEST_SI_0_VAL (0x108)
+#define DFD_TEST_SI_1_VAL (0x20200000)
+
+#define WDT_DEBUG_CTL_VAL_1 (0x95063E80)
+#define DFD_V35_TAP_NUMBER_VAL (0xA)
+#define DFD_V35_TAP_EN_VAL (0x3FF)
+#define DFD_V35_SEQ0_0_VAL (0x63668820)
+#define DFD_HW_TRIGGER_MASK_VAL (0xC)
+
+void dfd_resume(void);
+uint64_t dfd_smc_dispatcher(uint64_t arg0, uint64_t arg1,
+ uint64_t arg2, uint64_t arg3);
+
+#endif /* PLAT_DFD_H */
diff --git a/plat/mediatek/mt8186/drivers/emi_mpu/emi_mpu.c b/plat/mediatek/mt8186/drivers/emi_mpu/emi_mpu.c
new file mode 100644
index 0000000..1133c86
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/emi_mpu/emi_mpu.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <emi_mpu.h>
+
+#if ENABLE_EMI_MPU_SW_LOCK
+static unsigned char region_lock_state[EMI_MPU_REGION_NUM];
+#endif
+
+#define EMI_MPU_START_MASK (0x00FFFFFF)
+#define EMI_MPU_END_MASK (0x00FFFFFF)
+#define EMI_MPU_APC_SW_LOCK_MASK (0x00FFFFFF)
+#define EMI_MPU_APC_HW_LOCK_MASK (0x80FFFFFF)
+
+static int _emi_mpu_set_protection(unsigned int start, unsigned int end,
+ unsigned int apc)
+{
+ unsigned int dgroup;
+ unsigned int region;
+
+ region = (start >> 24) & 0xFF;
+ start &= EMI_MPU_START_MASK;
+ dgroup = (end >> 24) & 0xFF;
+ end &= EMI_MPU_END_MASK;
+
+ if ((region >= EMI_MPU_REGION_NUM) || (dgroup > EMI_MPU_DGROUP_NUM)) {
+ WARN("invalid region, domain\n");
+ return -1;
+ }
+
+#if ENABLE_EMI_MPU_SW_LOCK
+ if (region_lock_state[region] == 1) {
+ WARN("invalid region\n");
+ return -1;
+ }
+
+ if ((dgroup == 0U) && ((apc >> 31) & 0x1)) {
+ region_lock_state[region] = 1;
+ }
+
+ apc &= EMI_MPU_APC_SW_LOCK_MASK;
+#else
+ apc &= EMI_MPU_APC_HW_LOCK_MASK;
+#endif
+
+ if ((start >= DRAM_OFFSET) && (end >= start)) {
+ start -= DRAM_OFFSET;
+ end -= DRAM_OFFSET;
+ } else {
+ WARN("invalid range\n");
+ return -1;
+ }
+
+ mmio_write_32(EMI_MPU_SA(region), start);
+ mmio_write_32(EMI_MPU_EA(region), end);
+ mmio_write_32(EMI_MPU_APC(region, dgroup), apc);
+
+#if defined(SUB_EMI_MPU_BASE)
+ mmio_write_32(SUB_EMI_MPU_SA(region), start);
+ mmio_write_32(SUB_EMI_MPU_EA(region), end);
+ mmio_write_32(SUB_EMI_MPU_APC(region, dgroup), apc);
+#endif
+ return 0;
+}
+
+int emi_mpu_set_protection(struct emi_region_info_t *region_info)
+{
+ unsigned int start, end;
+ int i;
+
+ if (region_info->region >= EMI_MPU_REGION_NUM) {
+ WARN("invalid region\n");
+ return -1;
+ }
+
+ start = (unsigned int)(region_info->start >> EMI_MPU_ALIGN_BITS) |
+ (region_info->region << 24);
+
+ for (i = EMI_MPU_DGROUP_NUM - 1; i >= 0; i--) {
+ end = (unsigned int)(region_info->end >> EMI_MPU_ALIGN_BITS) | (i << 24);
+
+ if (_emi_mpu_set_protection(start, end, region_info->apc[i]) < 0) {
+ WARN("failed to set emi mpu protection(%d, %d, %d)\n",
+ start, end, region_info->apc[i]);
+ }
+ }
+
+ return 0;
+}
+
+void emi_mpu_init(void)
+{
+ struct emi_region_info_t region_info;
+
+ /* SCP DRAM */
+ region_info.start = 0x50000000ULL;
+ region_info.end = 0x5109FFFFULL;
+ region_info.region = 2;
+ SET_ACCESS_PERMISSION(region_info.apc, 1,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION);
+ emi_mpu_set_protection(&region_info);
+
+ /* DSP protect address */
+ region_info.start = 0x60000000ULL; /* dram base addr */
+ region_info.end = 0x610FFFFFULL;
+ region_info.region = 3;
+ SET_ACCESS_PERMISSION(region_info.apc, 1,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, NO_PROTECTION, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION);
+ emi_mpu_set_protection(&region_info);
+
+ /* Forbidden All */
+ region_info.start = 0x40000000ULL; /* dram base addr */
+ region_info.end = 0x1FFFF0000ULL;
+ region_info.region = 4;
+ SET_ACCESS_PERMISSION(region_info.apc, 1,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION);
+ emi_mpu_set_protection(&region_info);
+}
diff --git a/plat/mediatek/mt8186/drivers/emi_mpu/emi_mpu.h b/plat/mediatek/mt8186/drivers/emi_mpu/emi_mpu.h
new file mode 100644
index 0000000..415146e
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/emi_mpu/emi_mpu.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EMI_MPU_H
+#define EMI_MPU_H
+
+#include <platform_def.h>
+
+#define ENABLE_EMI_MPU_SW_LOCK 1
+
+#define EMI_MPU_CTRL (EMI_MPU_BASE + 0x000)
+#define EMI_MPU_DBG (EMI_MPU_BASE + 0x004)
+#define EMI_MPU_SA0 (EMI_MPU_BASE + 0x100)
+#define EMI_MPU_EA0 (EMI_MPU_BASE + 0x200)
+#define EMI_MPU_SA(region) (EMI_MPU_SA0 + (region * 4))
+#define EMI_MPU_EA(region) (EMI_MPU_EA0 + (region * 4))
+#define EMI_MPU_APC0 (EMI_MPU_BASE + 0x300)
+#define EMI_MPU_APC(region, dgroup) (EMI_MPU_APC0 + (region * 4) + (dgroup * 0x100))
+#define EMI_MPU_CTRL_D0 (EMI_MPU_BASE + 0x800)
+#define EMI_MPU_CTRL_D(domain) (EMI_MPU_CTRL_D0 + (domain * 4))
+#define EMI_RG_MASK_D0 (EMI_MPU_BASE + 0x900)
+#define EMI_RG_MASK_D(domain) (EMI_RG_MASK_D0 + (domain * 4))
+#define EMI_MPU_START (0x000)
+#define EMI_MPU_END (0x93C)
+
+#define SUB_EMI_MPU_CTRL (SUB_EMI_MPU_BASE + 0x000)
+#define SUB_EMI_MPU_DBG (SUB_EMI_MPU_BASE + 0x004)
+#define SUB_EMI_MPU_SA0 (SUB_EMI_MPU_BASE + 0x100)
+#define SUB_EMI_MPU_EA0 (SUB_EMI_MPU_BASE + 0x200)
+#define SUB_EMI_MPU_SA(region) (SUB_EMI_MPU_SA0 + (region * 4))
+#define SUB_EMI_MPU_EA(region) (SUB_EMI_MPU_EA0 + (region * 4))
+#define SUB_EMI_MPU_APC0 (SUB_EMI_MPU_BASE + 0x300)
+#define SUB_EMI_MPU_APC(region, dgroup) (SUB_EMI_MPU_APC0 + (region * 4) + (dgroup * 0x100))
+#define SUB_EMI_MPU_CTRL_D0 (SUB_EMI_MPU_BASE + 0x800)
+#define SUB_EMI_MPU_CTRL_D(domain) (SUB_EMI_MPU_CTRL_D0 + (domain * 4))
+#define SUB_EMI_RG_MASK_D0 (SUB_EMI_MPU_BASE + 0x900)
+#define SUB_EMI_RG_MASK_D(domain) (SUB_EMI_RG_MASK_D0 + (domain * 4))
+
+#define EMI_MPU_DOMAIN_NUM (16)
+#define EMI_MPU_REGION_NUM (32)
+#define EMI_MPU_ALIGN_BITS (16)
+#define DRAM_OFFSET (0x40000000 >> EMI_MPU_ALIGN_BITS)
+
+#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 LOCK 1
+#define UNLOCK 0
+
+#define EMI_MPU_DGROUP_NUM (EMI_MPU_DOMAIN_NUM / 8)
+
+#if (EMI_MPU_DGROUP_NUM == 1)
+#define SET_ACCESS_PERMISSION(apc_ary, lock, d7, d6, d5, d4, d3, d2, d1, d0) \
+do { \
+ apc_ary[1] = 0; \
+ apc_ary[0] = \
+ (((unsigned int) d7) << 21) | (((unsigned int) d6) << 18) | \
+ (((unsigned int) d5) << 15) | (((unsigned int) d4) << 12) | \
+ (((unsigned int) d3) << 9) | (((unsigned int) d2) << 6) | \
+ (((unsigned int) d1) << 3) | ((unsigned int) d0) | \
+ ((unsigned int) lock << 31); \
+} while (0)
+#elif (EMI_MPU_DGROUP_NUM == 2)
+#define SET_ACCESS_PERMISSION(apc_ary, lock, d15, d14, d13, d12, d11, d10, \
+ d9, d8, d7, d6, d5, d4, d3, d2, d1, d0) \
+do { \
+ apc_ary[1] = \
+ (((unsigned int) d15) << 21) | (((unsigned int) d14) << 18) | \
+ (((unsigned int) d13) << 15) | (((unsigned int) d12) << 12) | \
+ (((unsigned int) d11) << 9) | (((unsigned int) d10) << 6) | \
+ (((unsigned int) d9) << 3) | ((unsigned int) d8); \
+ apc_ary[0] = \
+ (((unsigned int) d7) << 21) | (((unsigned int) d6) << 18) | \
+ (((unsigned int) d5) << 15) | (((unsigned int) d4) << 12) | \
+ (((unsigned int) d3) << 9) | (((unsigned int) d2) << 6) | \
+ (((unsigned int) d1) << 3) | ((unsigned int) d0) | \
+ ((unsigned int) lock << 31); \
+} while (0)
+#endif
+
+struct emi_region_info_t {
+ unsigned long long start;
+ unsigned long long end;
+ unsigned int region;
+ unsigned int apc[EMI_MPU_DGROUP_NUM];
+};
+
+void emi_mpu_init(void);
+
+#endif
diff --git a/plat/mediatek/mt8186/drivers/gpio/mtgpio.c b/plat/mediatek/mt8186/drivers/gpio/mtgpio.c
new file mode 100644
index 0000000..134476a
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/gpio/mtgpio.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <mtgpio.h>
+#include <platform_def.h>
+
+uintptr_t mt_gpio_find_reg_addr(uint32_t pin)
+{
+ uintptr_t reg_addr = 0U;
+ struct mt_pin_info gpio_info;
+
+ assert(pin < MAX_GPIO_PIN);
+
+ gpio_info = mt_pin_infos[pin];
+
+ switch (gpio_info.base & 0x0f) {
+ case 0:
+ reg_addr = IOCFG_LT_BASE;
+ break;
+ case 1:
+ reg_addr = IOCFG_LM_BASE;
+ break;
+ case 2:
+ reg_addr = IOCFG_LB_BASE;
+ break;
+ case 3:
+ reg_addr = IOCFG_BL_BASE;
+ break;
+ case 4:
+ reg_addr = IOCFG_RB_BASE;
+ break;
+ case 5:
+ reg_addr = IOCFG_RT_BASE;
+ break;
+ default:
+ break;
+ }
+
+ return reg_addr;
+}
diff --git a/plat/mediatek/mt8186/drivers/gpio/mtgpio.h b/plat/mediatek/mt8186/drivers/gpio/mtgpio.h
new file mode 100644
index 0000000..4430a58
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/gpio/mtgpio.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_GPIO_H
+#define MT_GPIO_H
+
+#include <mtgpio_common.h>
+
+/* 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, GPIO180, GPIO181, GPIO182,
+ GPIO183, GPIO184,
+ MT_GPIO_BASE_MAX
+} GPIO_PIN;
+
+static const struct mt_pin_info mt_pin_infos[] = {
+ PIN(0, 0, 13, 0x16, 0x40),
+ PIN(1, 0, 14, 0x16, 0x40),
+ PIN(2, 0, 17, 0x16, 0x40),
+ PIN(3, 0, 18, 0x16, 0x40),
+ PIN(4, 0, 19, 0x16, 0x40),
+ PIN(5, 0, 20, 0x16, 0x40),
+ PIN(6, 0, 19, 0x24, 0x40),
+ PIN(7, 0, 20, 0x24, 0x40),
+ PIN(8, 0, 21, 0x24, 0x40),
+ PIN(9, 0, 22, 0x24, 0x40),
+ PIN(10, 0, 16, 0x24, 0x40),
+ PIN(11, 0, 17, 0x24, 0x40),
+ PIN(12, 0, 18, 0x24, 0x40),
+ PIN(13, 0, 0, 0x23, 0x60),
+ PIN(14, 0, 1, 0x23, 0x60),
+ PIN(15, 0, 15, 0x16, 0x40),
+ PIN(16, 0, 16, 0x16, 0x40),
+ PIN(17, 0, 9, 0x25, 0x70),
+ PIN(18, 0, 10, 0x25, 0x70),
+ PIN(19, 0, 3, 0x25, 0x70),
+ PIN(20, 0, 6, 0x25, 0x70),
+ PIN(21, 0, 4, 0x25, 0x70),
+ PIN(22, 0, 7, 0x25, 0x70),
+ PIN(23, 0, 5, 0x25, 0x70),
+ PIN(24, 0, 8, 0x25, 0x70),
+ PIN(25, 0, 18, 0x25, 0x70),
+ PIN(26, 0, 15, 0x25, 0x70),
+ PIN(27, 0, 17, 0x25, 0x70),
+ PIN(28, 0, 16, 0x25, 0x70),
+ PIN(29, 0, 0, 0x16, 0x40),
+ PIN(30, 0, 1, 0x16, 0x40),
+ PIN(31, 0, 2, 0x16, 0x40),
+ PIN(32, 0, 25, 0x12, 0x50),
+ PIN(33, 0, 27, 0x12, 0x50),
+ PIN(34, 0, 26, 0x12, 0x50),
+ PIN(35, 0, 28, 0x12, 0x50),
+ PIN(36, 0, 9, 0x12, 0x50),
+ PIN(37, 0, 10, 0x12, 0x50),
+ PIN(38, 0, 12, 0x12, 0x50),
+ PIN(39, 0, 11, 0x12, 0x50),
+ PIN(40, 0, 13, 0x12, 0x50),
+ PIN(41, 0, 14, 0x12, 0x50),
+ PIN(42, 0, 16, 0x12, 0x50),
+ PIN(43, 0, 15, 0x12, 0x50),
+ PIN(44, 0, 28, 0x25, 0x70),
+ PIN(45, 0, 29, 0x25, 0x70),
+ PIN(46, 0, 31, 0x25, 0x70),
+ PIN(47, 0, 30, 0x25, 0x70),
+ PIN(48, 0, 17, 0x12, 0x50),
+ PIN(49, 0, 18, 0x12, 0x50),
+ PIN(50, 0, 20, 0x12, 0x50),
+ PIN(51, 0, 19, 0x12, 0x50),
+ PIN(52, 0, 12, 0x23, 0x60),
+ PIN(53, 0, 13, 0x23, 0x60),
+ PIN(54, 0, 15, 0x23, 0x60),
+ PIN(55, 0, 14, 0x23, 0x60),
+ PIN(56, 0, 12, 0x25, 0x70),
+ PIN(57, 0, 11, 0x25, 0x70),
+ PIN(58, 0, 13, 0x25, 0x70),
+ PIN(59, 0, 14, 0x25, 0x70),
+ PIN(60, 0, 21, 0x23, 0x60),
+ PIN(61, 0, 16, 0x23, 0x60),
+ PIN(62, 0, 22, 0x23, 0x60),
+ PIN(63, 0, 17, 0x23, 0x60),
+ PIN(64, 0, 18, 0x23, 0x60),
+ PIN(65, 0, 19, 0x23, 0x60),
+ PIN(66, 0, 20, 0x23, 0x60),
+ PIN(67, 1, 10, 0x21, 0x70),
+ PIN(68, 1, 0, 0x21, 0x70),
+ PIN(69, 1, 1, 0x21, 0x70),
+ PIN(70, 1, 11, 0x21, 0x70),
+ PIN(71, 1, 2, 0x21, 0x70),
+ PIN(72, 1, 3, 0x21, 0x70),
+ PIN(73, 1, 4, 0x21, 0x70),
+ PIN(74, 1, 5, 0x21, 0x70),
+ PIN(75, 1, 6, 0x21, 0x70),
+ PIN(76, 1, 7, 0x21, 0x70),
+ PIN(77, 1, 8, 0x21, 0x70),
+ PIN(78, 1, 9, 0x21, 0x70),
+ PIN(79, 1, 0, 0x25, 0x80),
+ PIN(80, 1, 1, 0x25, 0x80),
+ PIN(81, 1, 2, 0x25, 0x80),
+ PIN(82, 1, 3, 0x25, 0x80),
+ PIN(83, 0, 3, 0x16, 0x40),
+ PIN(84, 1, 0, 0x23, 0x70),
+ PIN(85, 1, 1, 0x23, 0x70),
+ PIN(86, 1, 2, 0x23, 0x70),
+ PIN(87, 1, 3, 0x23, 0x70),
+ PIN(88, 1, 4, 0x23, 0x70),
+ PIN(89, 1, 5, 0x23, 0x70),
+ PIN(90, 0, 2, 0x23, 0x60),
+ PIN(91, 0, 23, 0x23, 0x60),
+ PIN(92, 0, 25, 0x23, 0x60),
+ PIN(93, 0, 3, 0x23, 0x60),
+ PIN(94, 0, 24, 0x23, 0x60),
+ PIN(95, 0, 26, 0x23, 0x60),
+ PIN(96, 0, 1, 0x12, 0x50),
+ PIN(97, 0, 0, 0x12, 0x50),
+ PIN(98, 0, 2, 0x12, 0x50),
+ PIN(99, 0, 14, 0x24, 0x40),
+ PIN(100, 0, 15, 0x24, 0x40),
+ PIN(101, 0, 13, 0x24, 0x40),
+ PIN(102, 0, 12, 0x24, 0x40),
+ PIN(103, 0, 0, 0x24, 0x40),
+ PIN(104, 0, 1, 0x24, 0x40),
+ PIN(105, 0, 4, 0x24, 0x40),
+ PIN(106, 0, 5, 0x24, 0x40),
+ PIN(107, 0, 6, 0x24, 0x40),
+ PIN(108, 0, 7, 0x24, 0x40),
+ PIN(109, 0, 8, 0x24, 0x40),
+ PIN(110, 0, 9, 0x24, 0x40),
+ PIN(111, 0, 10, 0x24, 0x40),
+ PIN(112, 0, 11, 0x24, 0x40),
+ PIN(113, 0, 2, 0x24, 0x40),
+ PIN(114, 0, 3, 0x24, 0x40),
+ PIN(115, 0, 4, 0x23, 0x60),
+ PIN(116, 0, 7, 0x23, 0x60),
+ PIN(117, 0, 5, 0x23, 0x60),
+ PIN(118, 0, 6, 0x23, 0x60),
+ PIN(119, 0, 22, 0x25, 0x70),
+ PIN(120, 0, 19, 0x25, 0x70),
+ PIN(121, 0, 20, 0x25, 0x70),
+ PIN(122, 0, 21, 0x25, 0x70),
+ PIN(123, 0, 23, 0x25, 0x70),
+ PIN(124, 0, 0, 0x25, 0x70),
+ PIN(125, 0, 1, 0x25, 0x70),
+ PIN(126, 0, 2, 0x25, 0x70),
+ PIN(127, 0, 8, 0x23, 0x60),
+ PIN(128, 0, 10, 0x23, 0x60),
+ PIN(129, 0, 24, 0x25, 0x70),
+ PIN(130, 0, 26, 0x25, 0x70),
+ PIN(131, 0, 25, 0x25, 0x70),
+ PIN(132, 0, 27, 0x25, 0x70),
+ PIN(133, 0, 9, 0x21, 0x60),
+ PIN(134, 0, 12, 0x21, 0x60),
+ PIN(135, 0, 21, 0x16, 0x40),
+ PIN(136, 0, 24, 0x16, 0x40),
+ PIN(137, 0, 10, 0x21, 0x60),
+ PIN(138, 0, 13, 0x21, 0x60),
+ PIN(139, 0, 7, 0x12, 0x50),
+ PIN(140, 0, 8, 0x12, 0x50),
+ PIN(141, 0, 9, 0x23, 0x60),
+ PIN(142, 0, 11, 0x23, 0x60),
+ PIN(143, 0, 22, 0x16, 0x40),
+ PIN(144, 0, 25, 0x16, 0x40),
+ PIN(145, 0, 23, 0x16, 0x40),
+ PIN(146, 0, 26, 0x16, 0x40),
+ PIN(147, 0, 23, 0x24, 0x40),
+ PIN(148, 0, 24, 0x24, 0x40),
+ PIN(149, 0, 25, 0x24, 0x40),
+ PIN(150, 0, 26, 0x24, 0x40),
+ PIN(151, 0, 27, 0x24, 0x40),
+ PIN(152, 0, 28, 0x24, 0x40),
+ PIN(153, 0, 29, 0x24, 0x40),
+ PIN(154, 0, 30, 0x24, 0x40),
+ PIN(155, 0, 31, 0x24, 0x40),
+ PIN(156, 0, 0, 0x24, 0x50),
+ PIN(157, 0, 4, 0x12, 0x50),
+ PIN(158, 0, 3, 0x12, 0x50),
+ PIN(159, 0, 6, 0x12, 0x50),
+ PIN(160, 0, 5, 0x12, 0x50),
+ PIN(161, 0, 23, 0x12, 0x50),
+ PIN(162, 0, 24, 0x12, 0x50),
+ PIN(163, 0, 11, 0x21, 0x60),
+ PIN(164, 0, 8, 0x21, 0x60),
+ PIN(165, 0, 16, 0x21, 0x60),
+ PIN(166, 0, 1, 0x21, 0x60),
+ PIN(167, 0, 7, 0x21, 0x60),
+ PIN(168, 0, 4, 0x21, 0x60),
+ PIN(169, 0, 5, 0x21, 0x60),
+ PIN(170, 0, 0, 0x21, 0x60),
+ PIN(171, 0, 6, 0x21, 0x60),
+ PIN(172, 0, 2, 0x21, 0x60),
+ PIN(173, 0, 3, 0x21, 0x60),
+ PIN(174, 0, 7, 0x16, 0x40),
+ PIN(175, 0, 8, 0x16, 0x40),
+ PIN(176, 0, 4, 0x16, 0x40),
+ PIN(177, 0, 5, 0x16, 0x40),
+ PIN(178, 0, 6, 0x16, 0x40),
+ PIN(179, 0, 9, 0x16, 0x40),
+ PIN(180, 0, 10, 0x16, 0x40),
+ PIN(181, 0, 11, 0x16, 0x40),
+ PIN(182, 0, 12, 0x16, 0x40),
+ PIN(183, 0, 21, 0x12, 0x50),
+ PIN(184, 0, 22, 0x12, 0x50),
+};
+
+#endif /* MT_GPIO_H */
diff --git a/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.c b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.c
new file mode 100644
index 0000000..8c012e7
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <lib/psci/psci.h>
+#include <lib/spinlock.h>
+
+#include <mt_cpu_pm_cpc.h>
+#include <mt_lp_irqremain.h>
+#include <mt_lp_rm.h>
+#include <mt_mcdi.h>
+#include <plat_mtk_lpm.h>
+#include <plat_pm.h>
+
+DEFINE_SYSREG_RW_FUNCS(dbgprcr_el1);
+
+static int plat_mt_lp_cpu_rc;
+
+static int pwr_state_prompt(unsigned int cpu, const psci_power_state_t *state)
+{
+ return 0;
+}
+
+static int pwr_state_reflect(unsigned int cpu, const psci_power_state_t *state)
+{
+ mtk_cpc_core_on_hint_clr(cpu);
+
+ if (IS_SYSTEM_SUSPEND_STATE(state)) {
+ mtk_cpc_time_sync();
+ }
+
+ return 0;
+}
+
+static int pwr_cpu_pwron(unsigned int cpu, const psci_power_state_t *state)
+{
+ return 0;
+}
+
+static int pwr_cpu_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
+{
+ /* clear DBGPRCR.CORENPDRQ to allow CPU power down */
+ write_dbgprcr_el1(0ULL);
+
+ return 0;
+}
+
+static int pwr_cluster_pwron(unsigned int cpu, const psci_power_state_t *state)
+{
+ return 0;
+}
+
+static int pwr_cluster_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
+{
+ return 0;
+}
+
+static int pwr_mcusys_pwron(unsigned int cpu, const psci_power_state_t *state)
+{
+ if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) {
+ return -1;
+ }
+
+ mtk_cpc_mcusys_off_reflect();
+
+ return 0;
+}
+
+static int pwr_mcusys_pwron_finished(unsigned int cpu,
+ const psci_power_state_t *state)
+{
+ int state_id = state->pwr_domain_state[MTK_AFFLVL_MCUSYS];
+
+ if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) {
+ return -1;
+ }
+
+ mt_lp_rm_reset_constraint(plat_mt_lp_cpu_rc, cpu, state_id);
+ mt_lp_irqremain_release();
+
+ return 0;
+}
+
+static int pwr_mcusys_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
+{
+ int state_id = state->pwr_domain_state[MTK_AFFLVL_MCUSYS];
+
+ if (!IS_MCUSYS_OFF_STATE(state)) {
+ goto mt_pwr_mcusysoff_break;
+ }
+
+ if (mcdi_try_init() != 0) { /* not ready to process mcusys-off */
+ goto mt_pwr_mcusysoff_break;
+ }
+
+ if (mtk_cpc_mcusys_off_prepare() != CPC_SUCCESS) {
+ goto mt_pwr_mcusysoff_break;
+ }
+
+ plat_mt_lp_cpu_rc =
+ mt_lp_rm_find_and_run_constraint(0, cpu, state_id, NULL);
+
+ if (plat_mt_lp_cpu_rc < 0) {
+ goto mt_pwr_mcusysoff_reflect;
+ }
+
+ mt_lp_irqremain_aquire();
+
+ return 0;
+
+mt_pwr_mcusysoff_reflect:
+ mtk_cpc_mcusys_off_reflect();
+
+mt_pwr_mcusysoff_break:
+ plat_mt_lp_cpu_rc = -1;
+
+ return -1;
+}
+
+static const struct mt_lpm_tz plat_pm = {
+ .pwr_prompt = pwr_state_prompt,
+ .pwr_reflect = pwr_state_reflect,
+ .pwr_cpu_on = pwr_cpu_pwron,
+ .pwr_cpu_dwn = pwr_cpu_pwrdwn,
+ .pwr_cluster_on = pwr_cluster_pwron,
+ .pwr_cluster_dwn = pwr_cluster_pwrdwn,
+ .pwr_mcusys_dwn = pwr_mcusys_pwrdwn,
+ .pwr_mcusys_on = pwr_mcusys_pwron,
+ .pwr_mcusys_on_finished = pwr_mcusys_pwron_finished
+};
+
+const struct mt_lpm_tz *mt_plat_cpu_pm_init(void)
+{
+ mtk_cpc_init();
+
+ if (mcdi_try_init() == 0) {
+ INFO("MCDI init done.\n");
+ }
+
+ mt_lp_irqremain_init();
+
+ return &plat_pm;
+}
diff --git a/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.h b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.h
new file mode 100644
index 0000000..83a7a53
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __MT_CPU_PM_H__
+#define __MT_CPU_PM_H__
+
+#define MCUSYS_STATUS_PDN (1 << 0UL)
+#define MCUSYS_STATUS_CPUSYS_PROTECT (1 << 8UL)
+#define MCUSYS_STATUS_MCUSYS_PROTECT (1 << 9UL)
+
+/* cpu_pm function ID*/
+enum mt_cpu_pm_user_id {
+ MCUSYS_STATUS,
+ CPC_COMMAND,
+ IRQ_REMAIN_LIST_ALLOC,
+ IRQ_REMAIN_IRQ_ADD,
+ IRQ_REMAIN_IRQ_SUBMIT,
+ MBOX_INFO,
+};
+
+/* cpu_pm lp function ID */
+enum mt_cpu_pm_lp_smc_id {
+ LP_CPC_COMMAND,
+ IRQS_REMAIN_ALLOC,
+ IRQS_REMAIN_CTRL,
+ IRQS_REMAIN_IRQ,
+ IRQS_REMAIN_WAKEUP_CAT,
+ IRQS_REMAIN_WAKEUP_SRC,
+};
+
+#endif
diff --git a/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_cpc.c b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_cpc.c
new file mode 100644
index 0000000..2b0f071
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_cpc.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <drivers/delay_timer.h>
+
+#include <mt_cpu_pm_cpc.h>
+#include <mt_timer.h>
+
+struct mtk_cpc_dev {
+ int auto_off;
+ unsigned int auto_thres_tick;
+};
+
+static struct mtk_cpc_dev cpc;
+
+static int mtk_cpc_last_core_prot(uint32_t prot_req,
+ uint32_t resp_reg, uint32_t resp_ofs)
+{
+ uint32_t sta, retry;
+
+ retry = 0U;
+
+ while (retry++ < RETRY_CNT_MAX) {
+
+ mmio_write_32(CPC_MCUSYS_LAST_CORE_REQ, prot_req);
+
+ udelay(1U);
+
+ sta = (mmio_read_32(resp_reg) >> resp_ofs) & CPC_PROT_RESP_MASK;
+
+ if (sta == PROT_SUCCESS) {
+ return CPC_SUCCESS;
+ } else if (sta == PROT_GIVEUP) {
+ return CPC_ERR_FAIL;
+ }
+ }
+
+ return CPC_ERR_TIMEOUT;
+}
+
+int mtk_cpu_pm_mcusys_prot_aquire(void)
+{
+ return mtk_cpc_last_core_prot(
+ MCUSYS_PROT_SET,
+ CPC_MCUSYS_LAST_CORE_RESP,
+ MCUSYS_RESP_OFS);
+}
+
+void mtk_cpu_pm_mcusys_prot_release(void)
+{
+ mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, MCUSYS_PROT_CLR);
+}
+
+int mtk_cpu_pm_cluster_prot_aquire(unsigned int cluster)
+{
+ return mtk_cpc_last_core_prot(
+ CPUSYS_PROT_SET,
+ CPC_MCUSYS_MP_LAST_CORE_RESP,
+ CPUSYS_RESP_OFS);
+}
+
+void mtk_cpu_pm_cluster_prot_release(unsigned int cluster)
+{
+ mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, CPUSYS_PROT_CLR);
+}
+
+static void mtk_cpc_cluster_cnt_backup(void)
+{
+ uint32_t backup_cnt;
+ uint32_t curr_cnt;
+ uint32_t cnt_mask = GENMASK(14, 0);
+ uint32_t clr_mask = GENMASK(1, 0);
+
+ /* Single Cluster */
+ backup_cnt = mmio_read_32(CPC_CLUSTER_CNT_BACKUP);
+ curr_cnt = mmio_read_32(CPC_MCUSYS_CLUSTER_COUNTER);
+
+ /* Get off count if dormant count is 0 */
+ if ((curr_cnt & cnt_mask) == 0U) {
+ curr_cnt = (curr_cnt >> 16) & cnt_mask;
+ } else {
+ curr_cnt = curr_cnt & cnt_mask;
+ }
+
+ mmio_write_32(CPC_CLUSTER_CNT_BACKUP, backup_cnt + curr_cnt);
+ mmio_write_32(CPC_MCUSYS_CLUSTER_COUNTER_CLR, clr_mask);
+}
+
+static inline void mtk_cpc_mcusys_off_en(void)
+{
+ mmio_write_32(CPC_MCUSYS_PWR_CTRL, 1U);
+}
+
+static inline void mtk_cpc_mcusys_off_dis(void)
+{
+ mmio_write_32(CPC_MCUSYS_PWR_CTRL, 0U);
+}
+
+void mtk_cpc_mcusys_off_reflect(void)
+{
+ mtk_cpc_mcusys_off_dis();
+ mtk_cpu_pm_mcusys_prot_release();
+}
+
+int mtk_cpc_mcusys_off_prepare(void)
+{
+ if (mtk_cpu_pm_mcusys_prot_aquire() != CPC_SUCCESS) {
+ return CPC_ERR_FAIL;
+ }
+
+ mtk_cpc_cluster_cnt_backup();
+ mtk_cpc_mcusys_off_en();
+
+ return CPC_SUCCESS;
+}
+
+void mtk_cpc_core_on_hint_set(unsigned int cpu)
+{
+ mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_SET, BIT(cpu));
+}
+
+void mtk_cpc_core_on_hint_clr(unsigned int cpu)
+{
+ mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_CLR, BIT(cpu));
+}
+
+static void mtk_cpc_dump_timestamp(void)
+{
+ uint32_t id;
+
+ for (id = 0U; id < CPC_TRACE_ID_NUM; id++) {
+ mmio_write_32(CPC_MCUSYS_TRACE_SEL, id);
+
+ memcpy((void *)(uintptr_t)CPC_TRACE_SRAM(id),
+ (const void *)(uintptr_t)CPC_MCUSYS_TRACE_DATA,
+ CPC_TRACE_SIZE);
+ }
+}
+
+void mtk_cpc_time_sync(void)
+{
+ uint64_t kt;
+ uint32_t systime_l, systime_h;
+
+ kt = sched_clock();
+ systime_l = mmio_read_32(CNTSYS_L_REG);
+ systime_h = mmio_read_32(CNTSYS_H_REG);
+
+ /* sync kernel timer to cpc */
+ mmio_write_32(CPC_MCUSYS_CPC_KERNEL_TIME_L_BASE, (uint32_t)kt);
+ mmio_write_32(CPC_MCUSYS_CPC_KERNEL_TIME_H_BASE, (uint32_t)(kt >> 32));
+ /* sync system timer to cpc */
+ mmio_write_32(CPC_MCUSYS_CPC_SYSTEM_TIME_L_BASE, systime_l);
+ mmio_write_32(CPC_MCUSYS_CPC_SYSTEM_TIME_H_BASE, systime_h);
+}
+
+static void mtk_cpc_config(uint32_t cfg, uint32_t data)
+{
+ uint32_t val;
+ uint32_t reg = 0U;
+
+ switch (cfg) {
+ case CPC_SMC_CONFIG_PROF:
+ reg = CPC_MCUSYS_CPC_DBG_SETTING;
+ val = mmio_read_32(reg);
+ val = (data != 0U) ? (val | CPC_PROF_EN) : (val & ~CPC_PROF_EN);
+ break;
+ case CPC_SMC_CONFIG_AUTO_OFF:
+ reg = CPC_MCUSYS_CPC_FLOW_CTRL_CFG;
+ val = mmio_read_32(reg);
+ if (data != 0U) {
+ val |= CPC_AUTO_OFF_EN;
+ cpc.auto_off = 1;
+ } else {
+ val &= ~CPC_AUTO_OFF_EN;
+ cpc.auto_off = 0;
+ }
+ break;
+ case CPC_SMC_CONFIG_AUTO_OFF_THRES:
+ reg = CPC_MCUSYS_CPC_OFF_THRES;
+ cpc.auto_thres_tick = us_to_ticks(data);
+ val = cpc.auto_thres_tick;
+ break;
+ case CPC_SMC_CONFIG_CNT_CLR:
+ reg = CPC_MCUSYS_CLUSTER_COUNTER_CLR;
+ val = GENMASK(1, 0); /* clr_mask */
+ break;
+ case CPC_SMC_CONFIG_TIME_SYNC:
+ mtk_cpc_time_sync();
+ break;
+ default:
+ break;
+ }
+
+ if (reg != 0U) {
+ mmio_write_32(reg, val);
+ }
+}
+
+static uint32_t mtk_cpc_read_config(uint32_t cfg)
+{
+ uint32_t res = 0U;
+
+ switch (cfg) {
+ case CPC_SMC_CONFIG_PROF:
+ res = (mmio_read_32(CPC_MCUSYS_CPC_DBG_SETTING) & CPC_PROF_EN) ?
+ 1U : 0U;
+ break;
+ case CPC_SMC_CONFIG_AUTO_OFF:
+ res = cpc.auto_off;
+ break;
+ case CPC_SMC_CONFIG_AUTO_OFF_THRES:
+ res = ticks_to_us(cpc.auto_thres_tick);
+ break;
+ case CPC_SMC_CONFIG_CNT_CLR:
+ break;
+ default:
+ break;
+ }
+
+ return res;
+}
+
+uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2)
+{
+ uint64_t res = 0ULL;
+
+ switch (act) {
+ case CPC_SMC_EVENT_DUMP_TRACE_DATA:
+ mtk_cpc_dump_timestamp();
+ break;
+ case CPC_SMC_EVENT_GIC_DPG_SET:
+ /* isolated_status = x2; */
+ break;
+ case CPC_SMC_EVENT_CPC_CONFIG:
+ mtk_cpc_config((uint32_t)arg1, (uint32_t)arg2);
+ break;
+ case CPC_SMC_EVENT_READ_CONFIG:
+ res = mtk_cpc_read_config((uint32_t)arg1);
+ break;
+ default:
+ break;
+ }
+
+ return res;
+}
+
+void mtk_cpc_init(void)
+{
+ mmio_write_32(CPC_MCUSYS_CPC_DBG_SETTING,
+ mmio_read_32(CPC_MCUSYS_CPC_DBG_SETTING)
+ | CPC_DBG_EN
+ | CPC_CALC_EN);
+
+ cpc.auto_off = 1;
+ cpc.auto_thres_tick = us_to_ticks(8000);
+
+ mmio_write_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG,
+ mmio_read_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG)
+ | CPC_OFF_PRE_EN
+ | (cpc.auto_off ? CPC_AUTO_OFF_EN : 0U));
+
+ mmio_write_32(CPC_MCUSYS_CPC_OFF_THRES, cpc.auto_thres_tick);
+}
diff --git a/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_cpc.h b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_cpc.h
new file mode 100644
index 0000000..488b1d1
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_cpc.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_CPU_PM_CPC_H
+#define MT_CPU_PM_CPC_H
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <mcucfg.h>
+#include <platform_def.h>
+
+#define NEED_CPUSYS_PROT_WORKAROUND 1
+
+/* system sram registers */
+#define CPUIDLE_SRAM_REG(r) (0x11B000 + (r))
+
+/* db dump */
+#define CPC_TRACE_SIZE U(0x20)
+#define CPC_TRACE_ID_NUM U(10)
+#define CPC_TRACE_SRAM(id) (CPUIDLE_SRAM_REG(0x10) + (id) * CPC_TRACE_SIZE)
+
+/* buckup off count */
+#define CPC_CLUSTER_CNT_BACKUP CPUIDLE_SRAM_REG(0x1F0)
+#define CPC_MCUSYS_CNT CPUIDLE_SRAM_REG(0x1F4)
+
+/* CPC_MCUSYS_CPC_FLOW_CTRL_CFG(0xA814): debug setting */
+#define CPC_PWR_ON_SEQ_DIS BIT(1)
+#define CPC_PWR_ON_PRIORITY BIT(2)
+#define CPC_AUTO_OFF_EN BIT(5)
+#define CPC_DORMANT_WAIT_EN BIT(14)
+#define CPC_CTRL_EN BIT(16)
+#define CPC_OFF_PRE_EN BIT(29)
+
+/* CPC_MCUSYS_LAST_CORE_REQ(0xA818) : last core protection */
+#define CPUSYS_PROT_SET BIT(0)
+#define MCUSYS_PROT_SET BIT(8)
+#define CPUSYS_PROT_CLR BIT(8)
+#define MCUSYS_PROT_CLR BIT(9)
+
+#define CPC_PROT_RESP_MASK U(0x3)
+#define CPUSYS_RESP_OFS U(16)
+#define MCUSYS_RESP_OFS U(30)
+
+#define cpusys_resp(r) (((r) >> CPUSYS_RESP_OFS) & CPC_PROT_RESP_MASK)
+#define mcusys_resp(r) (((r) >> MCUSYS_RESP_OFS) & CPC_PROT_RESP_MASK)
+
+#define RETRY_CNT_MAX U(1000)
+
+#define PROT_RETRY U(0)
+#define PROT_SUCCESS U(1)
+#define PROT_GIVEUP U(2)
+
+/* CPC_MCUSYS_CPC_DBG_SETTING(0xAB00): debug setting */
+#define CPC_PROF_EN BIT(0)
+#define CPC_DBG_EN BIT(1)
+#define CPC_FREEZE BIT(2)
+#define CPC_CALC_EN BIT(3)
+
+enum {
+ CPC_SUCCESS = 0U,
+ CPC_ERR_FAIL = 1U,
+ CPC_ERR_TIMEOUT = 2U,
+ NF_CPC_ERR = 3U,
+};
+
+enum {
+ CPC_SMC_EVENT_DUMP_TRACE_DATA = 0U,
+ CPC_SMC_EVENT_GIC_DPG_SET = 1U,
+ CPC_SMC_EVENT_CPC_CONFIG = 2U,
+ CPC_SMC_EVENT_READ_CONFIG = 3U,
+ NF_CPC_SMC_EVENT = 4U,
+};
+
+enum {
+ CPC_SMC_CONFIG_PROF = 0U,
+ CPC_SMC_CONFIG_AUTO_OFF = 1U,
+ CPC_SMC_CONFIG_AUTO_OFF_THRES = 2U,
+ CPC_SMC_CONFIG_CNT_CLR = 3U,
+ CPC_SMC_CONFIG_TIME_SYNC = 4U,
+ NF_CPC_SMC_CONFIG = 5U,
+};
+
+#define us_to_ticks(us) ((us) * 13)
+#define ticks_to_us(tick) ((tick) / 13)
+
+int mtk_cpu_pm_cluster_prot_aquire(unsigned int cluster);
+void mtk_cpu_pm_cluster_prot_release(unsigned int cluster);
+
+void mtk_cpc_mcusys_off_reflect(void);
+int mtk_cpc_mcusys_off_prepare(void);
+
+void mtk_cpc_core_on_hint_set(unsigned int cpu);
+void mtk_cpc_core_on_hint_clr(unsigned int cpu);
+void mtk_cpc_time_sync(void);
+
+uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2);
+void mtk_cpc_init(void);
+
+#endif /* MT_CPU_PM_CPC_H */
diff --git a/plat/mediatek/mt8186/drivers/mcdi/mt_lp_irqremain.c b/plat/mediatek/mt8186/drivers/mcdi/mt_lp_irqremain.c
new file mode 100644
index 0000000..b5a0284
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/mcdi/mt_lp_irqremain.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mt_cirq.h>
+#include <mt_lp_irqremain.h>
+#include <mt_lp_rm.h>
+#include <plat_mtk_lpm.h>
+
+#define KEYPAD_IRQ_ID U(138)
+#define KEYPAD_WAKESRC (0x4U)
+
+static struct mt_irqremain remain_irqs;
+
+int mt_lp_irqremain_submit(void)
+{
+ int ret = 0;
+
+ if (remain_irqs.count == 0) {
+ ret = -1;
+ } else {
+ set_wakeup_sources(remain_irqs.irqs, remain_irqs.count);
+ mt_lp_rm_do_update(-1, PLAT_RC_UPDATE_REMAIN_IRQS, &remain_irqs);
+ }
+
+ return ret;
+}
+
+int mt_lp_irqremain_aquire(void)
+{
+ int ret = 0;
+
+ if (remain_irqs.count == 0) {
+ ret = -1;
+ } else {
+ mt_cirq_sw_reset();
+ mt_cirq_clone_gic();
+ mt_cirq_enable();
+ }
+
+ return ret;
+}
+
+int mt_lp_irqremain_release(void)
+{
+ int ret = 0;
+
+ if (remain_irqs.count == 0) {
+ ret = -1;
+ } else {
+ mt_cirq_flush();
+ mt_cirq_disable();
+ }
+
+ return ret;
+}
+
+void mt_lp_irqremain_init(void)
+{
+ uint32_t idx;
+
+ remain_irqs.count = 0U;
+
+ /*edge keypad*/
+ idx = remain_irqs.count;
+ remain_irqs.irqs[idx] = KEYPAD_IRQ_ID;
+ remain_irqs.wakeupsrc_cat[idx] = 0U;
+ remain_irqs.wakeupsrc[idx] = KEYPAD_WAKESRC;
+ remain_irqs.count++;
+
+ mt_lp_irqremain_submit();
+}
diff --git a/plat/mediatek/mt8186/drivers/mcdi/mt_lp_irqremain.h b/plat/mediatek/mt8186/drivers/mcdi/mt_lp_irqremain.h
new file mode 100644
index 0000000..c313438
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/mcdi/mt_lp_irqremain.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_LP_IRQREMAIN_H
+#define MT_LP_IRQREMAIN_H
+
+extern int mt_lp_irqremain_submit(void);
+extern int mt_lp_irqremain_aquire(void);
+extern int mt_lp_irqremain_release(void);
+extern void mt_lp_irqremain_init(void);
+
+#endif /* MT_LP_IRQREMAIN_H */
diff --git a/plat/mediatek/mt8186/drivers/mcdi/mt_mcdi.c b/plat/mediatek/mt8186/drivers/mcdi/mt_mcdi.c
new file mode 100644
index 0000000..0103612
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/mcdi/mt_mcdi.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cdefs.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <mt_mcdi.h>
+
+/* Read/Write */
+#define APMCU_MCUPM_MBOX_AP_READY U(0)
+#define APMCU_MCUPM_MBOX_RESERVED_1 U(1)
+#define APMCU_MCUPM_MBOX_RESERVED_2 U(2)
+#define APMCU_MCUPM_MBOX_RESERVED_3 U(3)
+#define APMCU_MCUPM_MBOX_PWR_CTRL_EN U(4)
+#define APMCU_MCUPM_MBOX_L3_CACHE_MODE U(5)
+#define APMCU_MCUPM_MBOX_BUCK_MODE U(6)
+#define APMCU_MCUPM_MBOX_ARMPLL_MODE U(7)
+/* Read only */
+#define APMCU_MCUPM_MBOX_TASK_STA U(8)
+#define APMCU_MCUPM_MBOX_RESERVED_9 U(9)
+#define APMCU_MCUPM_MBOX_RESERVED_10 U(10)
+#define APMCU_MCUPM_MBOX_RESERVED_11 U(11)
+
+/* CPC mode - Read/Write */
+#define APMCU_MCUPM_MBOX_WAKEUP_CPU U(12)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_PWR_CTRL_EN */
+#define MCUPM_MCUSYS_CTRL BIT(0)
+#define MCUPM_BUCK_CTRL BIT(1)
+#define MCUPM_ARMPLL_CTRL BIT(2)
+#define MCUPM_CM_CTRL BIT(3)
+#define MCUPM_PWR_CTRL_MASK GENMASK(3, 0)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_BUCK_MODE */
+#define MCUPM_BUCK_NORMAL_MODE U(0) /* default */
+#define MCUPM_BUCK_LP_MODE U(1)
+#define MCUPM_BUCK_OFF_MODE U(2)
+#define NF_MCUPM_BUCK_MODE U(3)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_ARMPLL_MODE */
+#define MCUPM_ARMPLL_ON U(0) /* default */
+#define MCUPM_ARMPLL_GATING U(1)
+#define MCUPM_ARMPLL_OFF U(2)
+#define NF_MCUPM_ARMPLL_MODE U(3)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_TASK_STA */
+#define MCUPM_TASK_UNINIT U(0)
+#define MCUPM_TASK_INIT U(1)
+#define MCUPM_TASK_INIT_FINISH U(2)
+#define MCUPM_TASK_WAIT U(3)
+#define MCUPM_TASK_RUN U(4)
+#define MCUPM_TASK_PAUSE U(5)
+
+#define SSPM_MBOX_3_BASE U(0x10420000)
+
+#define MCDI_NOT_INIT U(0)
+#define MCDI_INIT_1 U(1)
+#define MCDI_INIT_2 U(2)
+#define MCDI_INIT_DONE U(3)
+
+static int mcdi_init_status __section("tzfw_coherent_mem");
+
+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);
+}
+
+static void mtk_mcupm_pwr_ctrl_setting(uint32_t dev)
+{
+ mcdi_mbox_write(APMCU_MCUPM_MBOX_PWR_CTRL_EN, dev);
+}
+
+static void mtk_set_mcupm_pll_mode(uint32_t mode)
+{
+ if (mode < NF_MCUPM_ARMPLL_MODE) {
+ mcdi_mbox_write(APMCU_MCUPM_MBOX_ARMPLL_MODE, mode);
+ }
+}
+
+static void mtk_set_mcupm_buck_mode(uint32_t mode)
+{
+ if (mode < NF_MCUPM_BUCK_MODE) {
+ mcdi_mbox_write(APMCU_MCUPM_MBOX_BUCK_MODE, mode);
+ }
+}
+
+static int mtk_mcupm_is_ready(void)
+{
+ unsigned int sta = mcdi_mbox_read(APMCU_MCUPM_MBOX_TASK_STA);
+
+ return ((sta == MCUPM_TASK_WAIT) || (sta == MCUPM_TASK_INIT_FINISH));
+}
+
+static int mcdi_init_1(void)
+{
+ unsigned int sta = mcdi_mbox_read(APMCU_MCUPM_MBOX_TASK_STA);
+
+ if (sta != MCUPM_TASK_INIT) {
+ return -1;
+ }
+
+ mtk_set_mcupm_pll_mode(MCUPM_ARMPLL_OFF);
+ mtk_set_mcupm_buck_mode(MCUPM_BUCK_OFF_MODE);
+
+ mtk_mcupm_pwr_ctrl_setting(
+ MCUPM_MCUSYS_CTRL |
+ MCUPM_BUCK_CTRL |
+ MCUPM_ARMPLL_CTRL);
+
+ mcdi_mbox_write(APMCU_MCUPM_MBOX_AP_READY, 1);
+
+ return 0;
+}
+
+static int mcdi_init_2(void)
+{
+ return mtk_mcupm_is_ready() ? 0 : -1;
+}
+
+int mcdi_try_init(void)
+{
+ if (mcdi_init_status == MCDI_INIT_DONE) {
+ return 0;
+ }
+
+ if (mcdi_init_status == MCDI_NOT_INIT) {
+ mcdi_init_status = MCDI_INIT_1;
+ }
+
+ if (mcdi_init_status == MCDI_INIT_1 && mcdi_init_1() == 0) {
+ mcdi_init_status = MCDI_INIT_2;
+ }
+
+ if (mcdi_init_status == MCDI_INIT_2 && mcdi_init_2() == 0) {
+ mcdi_init_status = MCDI_INIT_DONE;
+ }
+
+ INFO("mcdi ready for mcusys-off-idle and system suspend\n");
+
+ return (mcdi_init_status == MCDI_INIT_DONE) ? 0 : mcdi_init_status;
+}
diff --git a/plat/mediatek/mt8186/drivers/mcdi/mt_mcdi.h b/plat/mediatek/mt8186/drivers/mcdi/mt_mcdi.h
new file mode 100644
index 0000000..0e6444a
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/mcdi/mt_mcdi.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_MCDI_H
+#define MT_MCDI_H
+
+int mcdi_try_init(void);
+
+#endif /* MT_MCDI_H */
diff --git a/plat/mediatek/mt8186/drivers/pmic/pmic.c b/plat/mediatek/mt8186/drivers/pmic/pmic.c
new file mode 100644
index 0000000..4f7ab13
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/pmic/pmic.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <pmic.h>
+#include <pmic_wrap_init.h>
+
+uint32_t pmic_get_hwcid(void)
+{
+ uint32_t val = 0;
+
+ pwrap_read(PMIC_RG_HWCID_ADDR, &val);
+
+ return val;
+}
+
+void pmic_power_off(void)
+{
+ pwrap_write(PMIC_PWRHOLD, 0x0);
+}
diff --git a/plat/mediatek/mt8186/drivers/pmic/pmic.h b/plat/mediatek/mt8186/drivers/pmic/pmic.h
new file mode 100644
index 0000000..91ccb19
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/pmic/pmic.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMIC_H
+#define PMIC_H
+
+#include <stdint.h>
+
+#define PMIC_RG_HWCID_ADDR 0x8
+#define PMIC_PWRHOLD 0xa08
+
+/* external API */
+uint32_t pmic_get_hwcid(void);
+void pmic_power_off(void);
+
+#endif /* PMIC_H */
diff --git a/plat/mediatek/mt8186/drivers/pmic/pmic_wrap_init.h b/plat/mediatek/mt8186/drivers/pmic/pmic_wrap_init.h
new file mode 100644
index 0000000..e8cbf7e
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/pmic/pmic_wrap_init.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2021-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMIC_WRAP_INIT_H
+#define PMIC_WRAP_INIT_H
+
+#include <stdint.h>
+
+#include "platform_def.h"
+#include <pmic_wrap_init_common.h>
+
+static struct mt8186_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 mt8186_pmic_wrap_regs {
+ uint32_t unused[776];
+ uint32_t wacs2_cmd;
+ uint32_t wacs2_rdata;
+ uint32_t wacs2_vldclr;
+};
+
+enum {
+ RDATA_WACS_RDATA_SHIFT = 0,
+ RDATA_WACS_FSM_SHIFT = 16,
+ RDATA_WACS_REQ_SHIFT = 19,
+ RDATA_SYNC_IDLE_SHIFT = 20,
+ RDATA_INIT_DONE_SHIFT = 22,
+ RDATA_SYS_IDLE_SHIFT = 23,
+};
+
+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
+};
+
+#endif /* PMIC_WRAP_INIT_H */
diff --git a/plat/mediatek/mt8186/drivers/rtc/rtc.c b/plat/mediatek/mt8186/drivers/rtc/rtc.c
new file mode 100644
index 0000000..4fcf58e
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/rtc/rtc.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <rtc.h>
+
+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));
+ }
+}
diff --git a/plat/mediatek/mt8186/drivers/rtc/rtc.h b/plat/mediatek/mt8186/drivers/rtc/rtc.h
new file mode 100644
index 0000000..b48dbb9
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/rtc/rtc.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RTC_H
+#define RTC_H
+
+#define PMIC_RG_SRCLKEN_IN0_HW_MODE_MASK (1U)
+#define PMIC_RG_SRCLKEN_IN0_HW_MODE_SHIFT (1U)
+#define PMIC_RG_SRCLKEN_IN1_HW_MODE_MASK (1U)
+#define PMIC_RG_SRCLKEN_IN1_HW_MODE_SHIFT (3U)
+#define PMIC_RG_RTC_EOSC32_CK_PDN_MASK (1U)
+#define PMIC_RG_RTC_EOSC32_CK_PDN_SHIFT (2U)
+#define PMIC_RG_EOSC_CALI_TD_MASK (7U)
+#define PMIC_RG_EOSC_CALI_TD_SHIFT (5U)
+#define PMIC_RG_XO_EN32K_MAN_MASK (1U)
+#define PMIC_RG_XO_EN32K_MAN_SHIFT (0U)
+
+/* 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
+};
+
+/* 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 */
diff --git a/plat/mediatek/mt8186/drivers/spm/build.mk b/plat/mediatek/mt8186/drivers/spm/build.mk
new file mode 100644
index 0000000..72a2b6b
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/build.mk
@@ -0,0 +1,78 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Enable or disable spm feature
+MT_SPM_FEATURE_SUPPORT=yes
+
+# Enable or disable cirq restore
+MT_SPM_CIRQ_FEATURE_SUPPORT=yes
+
+# sspm notifier support
+MT_SPM_SSPM_NOTIFIER_SUPPORT=yes
+
+CUR_SPM_FOLDER = ${MTK_PLAT_SOC}/drivers/spm
+
+# spm common files
+PLAT_SPM_SOURCE_FILES_COMMON += \
+ ${CUR_SPM_FOLDER}/mt_spm.c \
+ ${CUR_SPM_FOLDER}/mt_spm_internal.c \
+ ${CUR_SPM_FOLDER}/mt_spm_pmic_wrap.c \
+ ${CUR_SPM_FOLDER}/mt_spm_vcorefs.c \
+ ${CUR_SPM_FOLDER}/mt_spm_conservation.c \
+ ${CUR_SPM_FOLDER}/mt_spm_extern.c
+
+# spm platform dependcy files
+PLAT_SPM_SOURCE_FILES += \
+ ${CUR_SPM_FOLDER}/constraints/mt_spm_rc_syspll.c \
+ ${CUR_SPM_FOLDER}/constraints/mt_spm_rc_bus26m.c \
+ ${CUR_SPM_FOLDER}/constraints/mt_spm_rc_cpu_buck_ldo.c \
+ ${CUR_SPM_FOLDER}/constraints/mt_spm_rc_dram.c \
+ ${CUR_SPM_FOLDER}/mt_spm_cond.c \
+ ${CUR_SPM_FOLDER}/mt_spm_suspend.c \
+ ${CUR_SPM_FOLDER}/mt_spm_idle.c
+
+ifeq (${MT_SPM_FEATURE_SUPPORT}, no)
+PLAT_SPM_DEBUG_CFLAGS += -DATF_PLAT_SPM_UNSUPPORT
+
+BL31_MT_LPM_PLAT_SPM_SOURCE_FILES += ${PLAT_SPM_SOURCE_FILES_COMMON}
+else
+BL31_MT_LPM_PLAT_SPM_SOURCE_FILES += \
+ ${PLAT_SPM_SOURCE_FILES_COMMON} \
+ ${PLAT_SPM_SOURCE_FILES}
+endif
+
+ifeq (${MT_SPM_CIRQ_FEATURE_SUPPORT}, no)
+PLAT_SPM_DEBUG_CFLAGS += -DATF_PLAT_CIRQ_UNSUPPORT
+endif
+
+ifeq (${MT_SPM_SSPM_NOTIFIER_SUPPORT}, no)
+PLAT_SPM_DEBUG_CFLAGS += -DATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+else
+BL31_MT_LPM_PLAT_SPM_SOURCE_FILES += ${CUR_SPM_FOLDER}/notifier/mt_spm_sspm_notifier.c
+endif
+
+ifeq (${MTK_VOLTAGE_BIN_VCORE}, yes)
+PLAT_SPM_DEBUG_CFLAGS += -DATF_VOLTAGE_BIN_VCORE_SUPPORT
+endif
+
+ifeq ($(MTK_SPM_EXTENSION_CONFIG), pmic6362)
+MTK_SPM_EXTENSION_PMIC_CONTROL := 6362
+$(eval $(call add_define,MTK_SPM_EXTENSION_PMIC_CONTROL))
+endif
+
+$(info --------------------------------------)
+$(info SPM build flags: ${PLAT_SPM_DEBUG_CFLAGS})
+$(info SPM build files: ${BL31_MT_LPM_PLAT_SPM_SOURCE_FILES})
+$(info --------------------------------------)
+
+# Common makefile for platform.mk
+PLAT_INCLUDES += \
+ ${PLAT_SPM_DEBUG_CFLAGS} \
+ -I${CUR_SPM_FOLDER}/ \
+ -I${CUR_SPM_FOLDER}/constraints/ \
+ -I${CUR_SPM_FOLDER}/notifier/
+
+PLAT_BL_COMMON_SOURCES += ${BL31_MT_LPM_PLAT_SPM_SOURCE_FILES}
diff --git a/plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_bus26m.c b/plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_bus26m.c
new file mode 100644
index 0000000..dd2aee8
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_bus26m.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#ifndef ATF_PLAT_CIRQ_UNSUPPORT
+#include <mt_gic_v3.h>
+#endif
+
+#include <mt_lp_rm.h>
+#include <mt_spm.h>
+#include <mt_spm_cond.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_constraint.h>
+#include <mt_spm_idle.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_notifier.h>
+#include <mt_spm_pmic_wrap.h>
+#include <mt_spm_rc_internal.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_suspend.h>
+
+#ifndef ATF_PLAT_CIRQ_UNSUPPORT
+#include <mt_cirq.h>
+#endif
+
+#include <plat_mtk_lpm.h>
+#include <plat_pm.h>
+
+#define CONSTRAINT_BUS26M_ALLOW \
+ (MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF | \
+ MT_RM_CONSTRAINT_ALLOW_DRAM_S0 | \
+ MT_RM_CONSTRAINT_ALLOW_DRAM_S1 | \
+ MT_RM_CONSTRAINT_ALLOW_VCORE_LP | \
+ MT_RM_CONSTRAINT_ALLOW_LVTS_STATE | \
+ MT_RM_CONSTRAINT_ALLOW_BUS26M_OFF)
+
+#define CONSTRAINT_BUS26M_PCM_FLAG \
+ (SPM_FLAG_DISABLE_INFRA_PDN | \
+ SPM_FLAG_DISABLE_VCORE_DVS | \
+ SPM_FLAG_DISABLE_VCORE_DFS | \
+ SPM_FLAG_SRAM_SLEEP_CTRL | \
+ SPM_FLAG_ENABLE_TIA_WORKAROUND | \
+ SPM_FLAG_ENABLE_LVTS_WORKAROUND | \
+ SPM_FLAG_KEEP_CSYSPWRACK_HIGH)
+
+#define CONSTRAINT_BUS26M_PCM_FLAG1 (0U)
+#define CONSTRAINT_BUS26M_RESOURCE_REQ (0U)
+
+static unsigned int bus26m_ext_opand;
+static struct mt_irqremain *refer2remain_irq;
+static struct mt_spm_cond_tables cond_bus26m = {
+ .name = "bus26m",
+ .table_cg = {
+ 0x0385E03C, /* MTCMOS1 */
+ 0x003F0100, /* INFRA0 */
+ 0x0A040802, /* INFRA1 */
+ 0x06017E51, /* INFRA2 */
+ 0x08000000, /* INFRA3 */
+ 0x00000000, /* INFRA4 */
+ 0x00000000, /* INFRA5 */
+ 0x03720820, /* MMSYS0 */
+ 0x00000000, /* MMSYS1 */
+ 0x00000000, /* MMSYS2 */
+ 0x00015151, /* MMSYS3 */
+ },
+ .table_pll = (PLL_BIT_UNIVPLL | PLL_BIT_MFGPLL |
+ PLL_BIT_MSDCPLL | PLL_BIT_TVDPLL |
+ PLL_BIT_MMPLL),
+};
+
+static struct mt_spm_cond_tables cond_bus26m_res = {
+ .table_cg = {0U},
+ .table_pll = 0U,
+};
+
+static struct constraint_status status = {
+ .id = MT_RM_CONSTRAINT_ID_BUS26M,
+ .valid = (MT_SPM_RC_VALID_SW | MT_SPM_RC_VALID_COND_LATCH),
+ .cond_block = 0U,
+ .enter_cnt = 0U,
+ .cond_res = &cond_bus26m_res,
+};
+
+/*
+ * Cirq will take the place of gic when gic is off.
+ * However, cirq cannot work if 26m clk is turned off when system idle/suspend.
+ * Therefore, we need to set irq pending for specific wakeup source.
+ */
+#ifdef ATF_PLAT_CIRQ_UNSUPPORT
+#define do_irqs_delivery()
+#else
+static void mt_spm_irq_remain_dump(struct mt_irqremain *irqs,
+ unsigned int irq_index,
+ struct wake_status *wakeup)
+{
+ INFO("[SPM] r12 = 0x%08x(0x%08x), flag = 0x%08x 0x%08x 0x%08x\n",
+ wakeup->tr.comm.r12, wakeup->md32pcm_wakeup_sta,
+ wakeup->tr.comm.debug_flag, wakeup->tr.comm.b_sw_flag0,
+ wakeup->tr.comm.b_sw_flag1);
+
+ INFO("irq:%u(0x%08x) set pending\n",
+ irqs->wakeupsrc[irq_index], irqs->irqs[irq_index]);
+}
+
+static void do_irqs_delivery(void)
+{
+ unsigned int idx;
+ int res = 0;
+ struct wake_status *wakeup = NULL;
+ struct mt_irqremain *irqs = refer2remain_irq;
+
+ res = spm_conservation_get_result(&wakeup);
+
+ if ((res != 0) && (irqs == NULL)) {
+ return;
+ }
+
+ for (idx = 0; idx < irqs->count; ++idx) {
+ if (((wakeup->tr.comm.r12 & irqs->wakeupsrc[idx]) != 0U) ||
+ ((wakeup->raw_sta & irqs->wakeupsrc[idx]) != 0U)) {
+ if ((irqs->wakeupsrc_cat[idx] & MT_IRQ_REMAIN_CAT_LOG) != 0U) {
+ mt_spm_irq_remain_dump(irqs, idx, wakeup);
+ }
+
+ mt_irq_set_pending(irqs->irqs[idx]);
+ }
+ }
+}
+#endif
+
+static void spm_bus26m_conduct(struct spm_lp_scen *spm_lp, unsigned int *resource_req)
+{
+ spm_lp->pwrctrl->pcm_flags = (uint32_t)CONSTRAINT_BUS26M_PCM_FLAG;
+ spm_lp->pwrctrl->pcm_flags1 = (uint32_t)CONSTRAINT_BUS26M_PCM_FLAG1;
+ *resource_req |= CONSTRAINT_BUS26M_RESOURCE_REQ;
+}
+
+bool spm_is_valid_rc_bus26m(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+ (void)state_id;
+
+ return ((status.cond_block == 0U) && IS_MT_RM_RC_READY(status.valid));
+}
+
+int spm_update_rc_bus26m(int state_id, int type, const void *val)
+{
+ const struct mt_spm_cond_tables *tlb;
+ const struct mt_spm_cond_tables *tlb_check;
+ int res = MT_RM_STATUS_OK;
+
+ if (val == NULL) {
+ res = MT_RM_STATUS_BAD;
+ } else {
+ if (type == PLAT_RC_UPDATE_CONDITION) {
+ tlb = (const struct mt_spm_cond_tables *)val;
+ tlb_check = (const struct mt_spm_cond_tables *)&cond_bus26m;
+
+ status.cond_block =
+ mt_spm_cond_check(state_id, tlb, tlb_check,
+ ((status.valid &
+ MT_SPM_RC_VALID_COND_LATCH) != 0U) ?
+ (&cond_bus26m_res) : (NULL));
+ } else if (type == PLAT_RC_UPDATE_REMAIN_IRQS) {
+ refer2remain_irq = (struct mt_irqremain *)val;
+ } else {
+ res = MT_RM_STATUS_BAD;
+ }
+ }
+
+ return res;
+}
+
+unsigned int spm_allow_rc_bus26m(int state_id)
+{
+ (void)state_id;
+
+ return CONSTRAINT_BUS26M_ALLOW;
+}
+
+int spm_run_rc_bus26m(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+
+ unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+
+#ifdef ATF_VOLTAGE_BIN_VCORE_SUPPORT
+#define SUSPEND_VB_MAGIC (0x5642)
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_SUSPEND_VCORE_VOLTAGE,
+ ((SUSPEND_VB_MAGIC << 16) |
+ spm_get_suspend_vcore_voltage_idx()));
+ }
+#endif
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_ENTER, CONSTRAINT_BUS26M_ALLOW |
+ (IS_PLAT_SUSPEND_ID(state_id) ?
+ (MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND) : (0U)));
+#endif
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_enter(state_id,
+ (MT_SPM_EX_OP_CLR_26M_RECORD |
+ MT_SPM_EX_OP_SET_WDT |
+ MT_SPM_EX_OP_HW_S1_DETECT |
+ bus26m_ext_opand),
+ CONSTRAINT_BUS26M_RESOURCE_REQ);
+ } else {
+ mt_spm_idle_generic_enter(state_id, ext_op, spm_bus26m_conduct);
+ }
+
+ return 0;
+}
+
+int spm_reset_rc_bus26m(unsigned int cpu, int state_id)
+{
+ unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
+
+ (void)cpu;
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_LEAVE, 0U);
+#endif
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ ext_op |= (bus26m_ext_opand | MT_SPM_EX_OP_SET_WDT);
+ mt_spm_suspend_resume(state_id, ext_op, NULL);
+ bus26m_ext_opand = 0U;
+ } else {
+ mt_spm_idle_generic_resume(state_id, ext_op, NULL, NULL);
+ status.enter_cnt++;
+ }
+
+ do_irqs_delivery();
+ return 0;
+}
diff --git a/plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_cpu_buck_ldo.c b/plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_cpu_buck_ldo.c
new file mode 100644
index 0000000..c47cf1f
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_cpu_buck_ldo.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <mt_spm.h>
+#include <mt_spm_cond.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_constraint.h>
+#include <mt_spm_idle.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_notifier.h>
+#include <mt_spm_rc_internal.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_suspend.h>
+#include <plat_mtk_lpm.h>
+#include <plat_pm.h>
+
+#define CONSTRAINT_CPU_BUCK_PCM_FLAG \
+ (SPM_FLAG_DISABLE_INFRA_PDN | \
+ SPM_FLAG_DISABLE_VCORE_DVS | \
+ SPM_FLAG_DISABLE_VCORE_DFS | \
+ SPM_FLAG_SRAM_SLEEP_CTRL | \
+ SPM_FLAG_KEEP_CSYSPWRACK_HIGH)
+
+#define CONSTRAINT_CPU_BUCK_PCM_FLAG1 (0U)
+
+#define CONSTRAINT_CPU_BUCK_RESOURCE_REQ \
+ (MT_SPM_DRAM_S1 | \
+ MT_SPM_DRAM_S0 | \
+ MT_SPM_SYSPLL | \
+ MT_SPM_INFRA | \
+ MT_SPM_26M | \
+ MT_SPM_XO_FPM)
+
+static unsigned int cpubuckldo_status = MT_SPM_RC_VALID_SW;
+static unsigned int cpubuckldo_enter_cnt;
+
+static void spm_cpu_bcuk_ldo_conduct(struct spm_lp_scen *spm_lp,
+ unsigned int *resource_req)
+{
+ spm_lp->pwrctrl->pcm_flags = (uint32_t)CONSTRAINT_CPU_BUCK_PCM_FLAG;
+ spm_lp->pwrctrl->pcm_flags1 = (uint32_t)CONSTRAINT_CPU_BUCK_PCM_FLAG1;
+ *resource_req |= CONSTRAINT_CPU_BUCK_RESOURCE_REQ;
+}
+
+bool spm_is_valid_rc_cpu_buck_ldo(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+ (void)state_id;
+
+ return IS_MT_RM_RC_READY(cpubuckldo_status);
+}
+
+unsigned int spm_allow_rc_cpu_buck_ldo(int state_id)
+{
+ (void)state_id;
+
+ return MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF;
+}
+
+int spm_run_rc_cpu_buck_ldo(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+ unsigned int ext_op = 0U;
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_ENTER,
+ (IS_PLAT_SUSPEND_ID(state_id) ?
+ (MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND) : (0U)));
+#endif
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_enter(state_id,
+ MT_SPM_EX_OP_SET_WDT,
+ CONSTRAINT_CPU_BUCK_RESOURCE_REQ);
+ } else {
+ mt_spm_idle_generic_enter(state_id, ext_op,
+ spm_cpu_bcuk_ldo_conduct);
+ }
+
+ cpubuckldo_enter_cnt++;
+
+ return 0;
+}
+
+int spm_reset_rc_cpu_buck_ldo(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+ unsigned int ext_op = 0U;
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_LEAVE, 0U);
+#endif
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_resume(state_id, MT_SPM_EX_OP_SET_WDT, NULL);
+ } else {
+ mt_spm_idle_generic_resume(state_id, ext_op, NULL, NULL);
+ }
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_dram.c b/plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_dram.c
new file mode 100644
index 0000000..b281734
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_dram.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <mt_lp_rm.h>
+#include <mt_spm.h>
+#include <mt_spm_cond.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_constraint.h>
+#include <mt_spm_idle.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_notifier.h>
+#include <mt_spm_rc_internal.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_suspend.h>
+#include <plat_mtk_lpm.h>
+#include <plat_pm.h>
+
+#define CONSTRAINT_DRAM_ALLOW \
+ (MT_RM_CONSTRAINT_ALLOW_DRAM_S0 | \
+ MT_RM_CONSTRAINT_ALLOW_DRAM_S1 | \
+ MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF)
+
+#define CONSTRAINT_DRAM_PCM_FLAG \
+ (SPM_FLAG_DISABLE_INFRA_PDN | \
+ SPM_FLAG_DISABLE_VCORE_DVS | \
+ SPM_FLAG_DISABLE_VCORE_DFS | \
+ SPM_FLAG_SRAM_SLEEP_CTRL | \
+ SPM_FLAG_KEEP_CSYSPWRACK_HIGH)
+
+#define CONSTRAINT_DRAM_PCM_FLAG1 (0U)
+
+#define CONSTRAINT_DRAM_RESOURCE_REQ \
+ (MT_SPM_SYSPLL | \
+ MT_SPM_INFRA | \
+ MT_SPM_26M)
+
+static struct mt_spm_cond_tables cond_dram = {
+ .name = "dram",
+ .table_cg = {
+ 0x0385E03C, /* MTCMOS1 */
+ 0x003F0100, /* INFRA0 */
+ 0x08040802, /* INFRA1 */
+ 0x06015641, /* INFRA2 */
+ 0x00000000, /* INFRA3 */
+ 0x00000000, /* INFRA4 */
+ 0x00000000, /* INFRA5 */
+ 0x02300020, /* MMSYS0 */
+ 0x00000000, /* MMSYS1 */
+ 0x00000000, /* MMSYS2 */
+ 0x00015111, /* MMSYS3 */
+ },
+ .table_pll = 0U,
+};
+
+static struct mt_spm_cond_tables cond_dram_res = {
+ .table_cg = {0U},
+ .table_pll = 0U,
+};
+
+static struct constraint_status status = {
+ .id = MT_RM_CONSTRAINT_ID_DRAM,
+ .valid = (MT_SPM_RC_VALID_SW |
+ MT_SPM_RC_VALID_COND_LATCH |
+ MT_SPM_RC_VALID_XSOC_BBLPM),
+ .cond_block = 0U,
+ .enter_cnt = 0U,
+ .cond_res = &cond_dram_res,
+};
+
+static void spm_dram_conduct(struct spm_lp_scen *spm_lp,
+ unsigned int *resource_req)
+{
+ spm_lp->pwrctrl->pcm_flags = (uint32_t)CONSTRAINT_DRAM_PCM_FLAG;
+ spm_lp->pwrctrl->pcm_flags1 = (uint32_t)CONSTRAINT_DRAM_PCM_FLAG1;
+ *resource_req |= CONSTRAINT_DRAM_RESOURCE_REQ;
+}
+
+bool spm_is_valid_rc_dram(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+ (void)state_id;
+
+ return ((status.cond_block == 0U) && IS_MT_RM_RC_READY(status.valid));
+}
+
+int spm_update_rc_dram(int state_id, int type, const void *val)
+{
+ const struct mt_spm_cond_tables *tlb;
+ const struct mt_spm_cond_tables *tlb_check;
+ int res = MT_RM_STATUS_OK;
+
+ if (val == NULL) {
+ res = MT_RM_STATUS_BAD;
+ } else {
+ if (type == PLAT_RC_UPDATE_CONDITION) {
+ tlb = (const struct mt_spm_cond_tables *)val;
+ tlb_check = (const struct mt_spm_cond_tables *)&cond_dram;
+ status.cond_block =
+ mt_spm_cond_check(state_id, tlb, tlb_check,
+ ((status.valid &
+ MT_SPM_RC_VALID_COND_LATCH) != 0U) ?
+ (&cond_dram_res) : (NULL));
+ } else {
+ res = MT_RM_STATUS_BAD;
+ }
+ }
+
+ return res;
+}
+
+unsigned int spm_allow_rc_dram(int state_id)
+{
+ (void)state_id;
+
+ return CONSTRAINT_DRAM_ALLOW;
+}
+
+int spm_run_rc_dram(unsigned int cpu, int state_id)
+{
+ unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
+ unsigned int allows = CONSTRAINT_DRAM_ALLOW;
+
+ (void)cpu;
+
+ if (IS_MT_SPM_RC_BBLPM_MODE(status.valid)) {
+#ifdef MT_SPM_USING_SRCLKEN_RC
+ ext_op |= MT_SPM_EX_OP_SRCLKEN_RC_BBLPM;
+#else
+ allows |= MT_RM_CONSTRAINT_ALLOW_BBLPM;
+#endif
+ }
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_ENTER, allows | (IS_PLAT_SUSPEND_ID(state_id) ?
+ (MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND) : (0U)));
+#else
+ (void)allows;
+#endif
+
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_enter(state_id,
+ (MT_SPM_EX_OP_SET_WDT | MT_SPM_EX_OP_HW_S1_DETECT),
+ CONSTRAINT_DRAM_RESOURCE_REQ);
+ } else {
+ mt_spm_idle_generic_enter(state_id, ext_op, spm_dram_conduct);
+ }
+
+ return 0;
+}
+
+int spm_reset_rc_dram(unsigned int cpu, int state_id)
+{
+ unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
+ unsigned int allows = CONSTRAINT_DRAM_ALLOW;
+
+ (void)cpu;
+
+ if (IS_MT_SPM_RC_BBLPM_MODE(status.valid)) {
+#ifdef MT_SPM_USING_SRCLKEN_RC
+ ext_op |= MT_SPM_EX_OP_SRCLKEN_RC_BBLPM;
+#else
+ allows |= MT_RM_CONSTRAINT_ALLOW_BBLPM;
+#endif
+ }
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_LEAVE, allows);
+#else
+ (void)allows;
+#endif
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_resume(state_id,
+ (MT_SPM_EX_OP_SET_WDT | MT_SPM_EX_OP_HW_S1_DETECT),
+ NULL);
+ } else {
+ mt_spm_idle_generic_resume(state_id, ext_op, NULL, NULL);
+ status.enter_cnt++;
+ }
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_internal.h b/plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_internal.h
new file mode 100644
index 0000000..dfacba9
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_internal.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_RC_INTERNAL_H
+#define MT_SPM_RC_INTERNAL_H
+
+#include <stdbool.h>
+
+#define SPM_SRAM_SLEEP_DEFAULT_FLAG (SPM_FLAG_DISABLE_DRAMC_MCU_SRAM_SLEEP)
+
+#define SPM_FLAG_SRAM_SLEEP_CTRL \
+ (SPM_FLAG_DISABLE_SSPM_SRAM_SLEEP | \
+ SPM_FLAG_DISABLE_DRAMC_MCU_SRAM_SLEEP | \
+ SPM_FLAG_DISABLE_SYSRAM_SLEEP | \
+ SPM_FLAG_DISABLE_MCUPM_SRAM_SLEEP | \
+ SPM_FLAG_DISABLE_SRAM_EVENT)
+
+/* cpu buck/ldo constraint function */
+bool spm_is_valid_rc_cpu_buck_ldo(unsigned int cpu, int state_id);
+unsigned int spm_allow_rc_cpu_buck_ldo(int state_id);
+int spm_run_rc_cpu_buck_ldo(unsigned int cpu, int state_id);
+int spm_reset_rc_cpu_buck_ldo(unsigned int cpu, int state_id);
+
+/* spm resource dram constraint function */
+bool spm_is_valid_rc_dram(unsigned int cpu, int state_id);
+int spm_update_rc_dram(int state_id, int type, const void *val);
+unsigned int spm_allow_rc_dram(int state_id);
+int spm_run_rc_dram(unsigned int cpu, int state_id);
+int spm_reset_rc_dram(unsigned int cpu, int state_id);
+
+/* spm resource syspll constraint function */
+bool spm_is_valid_rc_syspll(unsigned int cpu, int state_id);
+int spm_update_rc_syspll(int state_id, int type, const void *val);
+unsigned int spm_allow_rc_syspll(int state_id);
+int spm_run_rc_syspll(unsigned int cpu, int state_id);
+int spm_reset_rc_syspll(unsigned int cpu, int state_id);
+
+/* spm resource bus26m constraint function */
+bool spm_is_valid_rc_bus26m(unsigned int cpu, int state_id);
+int spm_update_rc_bus26m(int state_id, int type, const void *val);
+unsigned int spm_allow_rc_bus26m(int state_id);
+int spm_run_rc_bus26m(unsigned int cpu, int state_id);
+int spm_reset_rc_bus26m(unsigned int cpu, int state_id);
+
+#endif /* MT_SPM_RC_INTERNAL_H */
diff --git a/plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_syspll.c b/plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_syspll.c
new file mode 100644
index 0000000..4977de1
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/constraints/mt_spm_rc_syspll.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <mt_lp_rm.h>
+#include <mt_spm.h>
+#include <mt_spm_cond.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_constraint.h>
+#include <mt_spm_idle.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_notifier.h>
+#include <mt_spm_rc_internal.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_suspend.h>
+#include <plat_mtk_lpm.h>
+#include <plat_pm.h>
+
+#define CONSTRAINT_SYSPLL_ALLOW \
+ (MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF | \
+ MT_RM_CONSTRAINT_ALLOW_DRAM_S0 | \
+ MT_RM_CONSTRAINT_ALLOW_DRAM_S1 | \
+ MT_RM_CONSTRAINT_ALLOW_VCORE_LP)
+
+#if (MTK_SPM_EXTENSION_PMIC_CONTROL == 6362)
+#define SPM_FLAG_EXTRA_PMIC_CONTROL (SPM_FLAG_ENABLE_6362_CTRL)
+#else
+#define SPM_FLAG_EXTRA_PMIC_CONTROL (SPM_FLAG_ENABLE_6315_CTRL)
+#endif
+
+#define CONSTRAINT_SYSPLL_PCM_FLAG \
+ (SPM_FLAG_DISABLE_INFRA_PDN | \
+ SPM_FLAG_DISABLE_VCORE_DVS | \
+ SPM_FLAG_DISABLE_VCORE_DFS | \
+ SPM_FLAG_USE_SRCCLKENO2 | \
+ SPM_FLAG_SRAM_SLEEP_CTRL | \
+ SPM_FLAG_KEEP_CSYSPWRACK_HIGH | \
+ SPM_FLAG_USE_SRCCLKENO2)
+
+#define CONSTRAINT_SYSPLL_PCM_FLAG1 (0U)
+#define CONSTRAINT_SYSPLL_RESOURCE_REQ (MT_SPM_26M)
+
+static struct mt_spm_cond_tables cond_syspll = {
+ .name = "syspll",
+ .table_cg = {
+ 0x0385E03C, /* MTCMOS1 */
+ 0x003F0100, /* INFRA0 */
+ 0x08040802, /* INFRA1 */
+ 0x06015641, /* INFRA2 */
+ 0x00000000, /* INFRA3 */
+ 0x00000000, /* INFRA4 */
+ 0x00000000, /* INFRA5 */
+ 0x03720820, /* MMSYS0 */
+ 0x00000000, /* MMSYS1 */
+ 0x00000000, /* MMSYS2 */
+ 0x00015151, /* MMSYS3 */
+ },
+ .table_pll = 0U,
+};
+
+static struct mt_spm_cond_tables cond_syspll_res = {
+ .table_cg = {0U},
+ .table_pll = 0U,
+};
+
+static struct constraint_status status = {
+ .id = MT_RM_CONSTRAINT_ID_SYSPLL,
+ .valid = (MT_SPM_RC_VALID_SW |
+ MT_SPM_RC_VALID_COND_LATCH |
+ MT_SPM_RC_VALID_XSOC_BBLPM),
+ .cond_block = 0U,
+ .enter_cnt = 0U,
+ .cond_res = &cond_syspll_res,
+};
+
+static void spm_syspll_conduct(struct spm_lp_scen *spm_lp,
+ unsigned int *resource_req)
+{
+ spm_lp->pwrctrl->pcm_flags = (uint32_t)CONSTRAINT_SYSPLL_PCM_FLAG;
+ spm_lp->pwrctrl->pcm_flags1 = (uint32_t)CONSTRAINT_SYSPLL_PCM_FLAG1;
+
+ *resource_req |= CONSTRAINT_SYSPLL_RESOURCE_REQ;
+}
+
+bool spm_is_valid_rc_syspll(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+ (void)state_id;
+
+ return ((status.cond_block == 0U) && IS_MT_RM_RC_READY(status.valid));
+}
+
+int spm_update_rc_syspll(int state_id, int type, const void *val)
+{
+ const struct mt_spm_cond_tables *tlb;
+ const struct mt_spm_cond_tables *tlb_check;
+ int res = MT_RM_STATUS_OK;
+
+ if (val == NULL) {
+ res = MT_RM_STATUS_BAD;
+ } else {
+ if (type == PLAT_RC_UPDATE_CONDITION) {
+ tlb = (const struct mt_spm_cond_tables *)val;
+ tlb_check = (const struct mt_spm_cond_tables *)&cond_syspll;
+
+ status.cond_block =
+ mt_spm_cond_check(state_id, tlb, tlb_check,
+ ((status.valid &
+ MT_SPM_RC_VALID_COND_LATCH) != 0U) ?
+ (&cond_syspll_res) : (NULL));
+ } else {
+ res = MT_RM_STATUS_BAD;
+ }
+ }
+
+ return res;
+}
+
+unsigned int spm_allow_rc_syspll(int state_id)
+{
+ (void)state_id;
+
+ return CONSTRAINT_SYSPLL_ALLOW;
+}
+
+int spm_run_rc_syspll(unsigned int cpu, int state_id)
+{
+ unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
+ unsigned int allows = CONSTRAINT_SYSPLL_ALLOW;
+
+ (void)cpu;
+
+ if (IS_MT_SPM_RC_BBLPM_MODE(status.valid)) {
+#ifdef MT_SPM_USING_SRCLKEN_RC
+ ext_op |= MT_SPM_EX_OP_SRCLKEN_RC_BBLPM;
+#else
+ allows |= MT_RM_CONSTRAINT_ALLOW_BBLPM;
+#endif
+ }
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_ENTER, allows | (IS_PLAT_SUSPEND_ID(state_id) ?
+ (MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND) : (0U)));
+#else
+ (void)allows;
+#endif
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_enter(state_id,
+ (MT_SPM_EX_OP_SET_WDT |
+ MT_SPM_EX_OP_HW_S1_DETECT |
+ MT_SPM_EX_OP_SET_SUSPEND_MODE),
+ CONSTRAINT_SYSPLL_RESOURCE_REQ);
+ } else {
+ mt_spm_idle_generic_enter(state_id, ext_op, spm_syspll_conduct);
+ }
+
+ return 0;
+}
+
+int spm_reset_rc_syspll(unsigned int cpu, int state_id)
+{
+ unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
+ unsigned int allows = CONSTRAINT_SYSPLL_ALLOW;
+
+ (void)cpu;
+
+ if (IS_MT_SPM_RC_BBLPM_MODE(status.valid)) {
+#ifdef MT_SPM_USING_SRCLKEN_RC
+ ext_op |= MT_SPM_EX_OP_SRCLKEN_RC_BBLPM;
+#else
+ allows |= MT_RM_CONSTRAINT_ALLOW_BBLPM;
+#endif
+ }
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_LEAVE, allows);
+#else
+ (void)allows;
+#endif
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_resume(state_id,
+ (MT_SPM_EX_OP_SET_SUSPEND_MODE |
+ MT_SPM_EX_OP_SET_WDT |
+ MT_SPM_EX_OP_HW_S1_DETECT),
+ NULL);
+ } else {
+ mt_spm_idle_generic_resume(state_id, ext_op, NULL, NULL);
+ status.enter_cnt++;
+ }
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm.c b/plat/mediatek/mt8186/drivers/spm/mt_spm.c
new file mode 100644
index 0000000..8ad50e2
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <common/debug.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <mt_lp_rm.h>
+#include <mt_spm.h>
+#include <mt_spm_cond.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_constraint.h>
+#include "mt_spm_extern.h"
+#include <mt_spm_idle.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_pmic_wrap.h>
+#include <mt_spm_rc_internal.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_suspend.h>
+#include <mtk_plat_common.h>
+#include <plat_mtk_lpm.h>
+#include <plat_pm.h>
+#include <platform_def.h>
+#include <sleep_def.h>
+
+#ifdef MT_SPM_USING_BAKERY_LOCK
+DEFINE_BAKERY_LOCK(spm_lock);
+#define plat_spm_lock_init() bakery_lock_init(&spm_lock)
+#else
+spinlock_t spm_lock;
+#define plat_spm_lock_init()
+#endif
+
+/* CLK_SCP_CFG_0 */
+#define CLK_SCP_CFG_0 (TOPCKGEN_BASE + 0x200)
+#define SPM_CK_CONTROL_EN (0x3FF)
+
+/* CLK_SCP_CFG_1 */
+#define CLK_SCP_CFG_1 (TOPCKGEN_BASE + 0x210)
+#define CLK_SCP_CFG_1_MASK (0x100C)
+#define CLK_SCP_CFG_1_SPM (0x3)
+
+#define MT_SPM_EX_OP_TIME_CHECK BIT(10)
+
+struct mt_resource_constraint plat_constraint_bus26m = {
+ .is_valid = spm_is_valid_rc_bus26m,
+ .update = spm_update_rc_bus26m,
+ .allow = spm_allow_rc_bus26m,
+ .run = spm_run_rc_bus26m,
+ .reset = spm_reset_rc_bus26m,
+};
+
+struct mt_resource_constraint plat_constraint_syspll = {
+ .is_valid = spm_is_valid_rc_syspll,
+ .update = spm_update_rc_syspll,
+ .allow = spm_allow_rc_syspll,
+ .run = spm_run_rc_syspll,
+ .reset = spm_reset_rc_syspll,
+};
+
+struct mt_resource_constraint plat_constraint_dram = {
+ .is_valid = spm_is_valid_rc_dram,
+ .update = spm_update_rc_dram,
+ .allow = spm_allow_rc_dram,
+ .run = spm_run_rc_dram,
+ .reset = spm_reset_rc_dram,
+};
+
+/* Maybe remove when the spm won't cpu power control aymore */
+struct mt_resource_constraint plat_constraint_cpu = {
+ .is_valid = spm_is_valid_rc_cpu_buck_ldo,
+ .update = NULL,
+ .allow = spm_allow_rc_cpu_buck_ldo,
+ .run = spm_run_rc_cpu_buck_ldo,
+ .reset = spm_reset_rc_cpu_buck_ldo,
+};
+
+struct mt_resource_constraint *plat_constraints[] = {
+ &plat_constraint_bus26m,
+ &plat_constraint_syspll,
+ &plat_constraint_dram,
+ &plat_constraint_cpu,
+ NULL,
+};
+
+struct mt_resource_manager plat_mt8186_rm = {
+ .update = mt_spm_cond_update,
+ .consts = plat_constraints,
+};
+
+void spm_boot_init(void)
+{
+ NOTICE("MT8186 %s\n", __func__);
+
+ /* switch ck_off/axi_26m control to SPM */
+ mmio_setbits_32(CLK_SCP_CFG_0, SPM_CK_CONTROL_EN);
+ mmio_clrsetbits_32(CLK_SCP_CFG_1, CLK_SCP_CFG_1_MASK, CLK_SCP_CFG_1_SPM);
+
+ plat_spm_lock_init();
+ mt_spm_pmic_wrap_set_phase(PMIC_WRAP_PHASE_ALLINONE);
+ mt_lp_rm_register(&plat_mt8186_rm);
+ mt_spm_idle_generic_init();
+ mt_spm_suspend_init();
+ spm_extern_initialize();
+}
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm.h b/plat/mediatek/mt8186/drivers/spm/mt_spm.h
new file mode 100644
index 0000000..0e21b5e
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_H
+#define MT_SPM_H
+
+#include <lib/bakery_lock.h>
+#include <lib/spinlock.h>
+#include <plat_mtk_lpm.h>
+
+/*
+ * ARM v8.2, the cache will turn off automatically when cpu
+ * power down. Therefore, there is no doubt to use the spin_lock here.
+ */
+#if !HW_ASSISTED_COHERENCY
+#define MT_SPM_USING_BAKERY_LOCK
+#endif
+
+#ifdef MT_SPM_USING_BAKERY_LOCK
+DECLARE_BAKERY_LOCK(spm_lock);
+#define plat_spm_lock() bakery_lock_get(&spm_lock)
+#define plat_spm_unlock() bakery_lock_release(&spm_lock)
+#else
+extern spinlock_t spm_lock;
+#define plat_spm_lock() spin_lock(&spm_lock)
+#define plat_spm_unlock() spin_unlock(&spm_lock)
+#endif
+
+#define MT_SPM_USING_SRCLKEN_RC
+
+/* spm extern operand definition */
+#define MT_SPM_EX_OP_CLR_26M_RECORD BIT(0)
+#define MT_SPM_EX_OP_SET_WDT BIT(1)
+#define MT_SPM_EX_OP_NON_GENERIC_RESOURCE_REQ BIT(2)
+#define MT_SPM_EX_OP_SET_SUSPEND_MODE BIT(3)
+#define MT_SPM_EX_OP_SET_IS_ADSP BIT(4)
+#define MT_SPM_EX_OP_SRCLKEN_RC_BBLPM BIT(5)
+#define MT_SPM_EX_OP_HW_S1_DETECT BIT(6)
+#define MT_SPM_EX_OP_TRACE_LP BIT(7)
+#define MT_SPM_EX_OP_TRACE_SUSPEND BIT(8)
+#define MT_SPM_EX_OP_TRACE_TIMESTAMP_EN BIT(9)
+#define MT_SPM_EX_OP_TIME_CHECK BIT(10)
+#define MT_SPM_EX_OP_TIME_OBS BIT(11)
+
+typedef enum {
+ WR_NONE = 0,
+ WR_UART_BUSY = 1,
+ WR_ABORT = 2,
+ WR_PCM_TIMER = 3,
+ WR_WAKE_SRC = 4,
+ WR_DVFSRC = 5,
+ WR_TWAM = 6,
+ WR_PMSR = 7,
+ WR_SPM_ACK_CHK = 8,
+ WR_UNKNOWN = 9,
+} wake_reason_t;
+
+/* for suspend vol. bin settings */
+enum MT_PLAT_SUSPEND_VCORE {
+ SPM_SUSPEND_VCORE_5500 = 0,
+ SPM_SUSPEND_VCORE_5250 = 1,
+ SPM_SUSPEND_VCORE_5000 = 2,
+};
+
+extern void spm_boot_init(void);
+
+static inline void spm_lock_get(void)
+{
+ plat_spm_lock();
+}
+
+static inline void spm_lock_release(void)
+{
+ plat_spm_unlock();
+}
+
+unsigned int spm_get_suspend_vcore_voltage_idx(void);
+
+#endif /* MT_SPM_H */
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_cond.c b/plat/mediatek/mt8186/drivers/spm/mt_spm_cond.c
new file mode 100644
index 0000000..a420e16
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_cond.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mt_spm_cond.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_constraint.h>
+#include <plat_mtk_lpm.h>
+#include <plat_pm.h>
+#include <platform_def.h>
+
+#define MT_LP_TZ_INFRA_REG(ofs) (INFRACFG_AO_BASE + ofs)
+#define MT_LP_TZ_MM_REG(ofs) (MMSYS_BASE + ofs)
+#define MT_LP_TZ_MDP_REG(ofs) (MDPSYS_BASE + ofs)
+#define MT_LP_TZ_SPM_REG(ofs) (SPM_BASE + ofs)
+#define MT_LP_TZ_TOPCK_REG(ofs) (TOPCKGEN_BASE + ofs)
+#define MT_LP_TZ_APMIXEDSYS(ofs) (APMIXEDSYS + ofs)
+
+#define SPM_PWR_STATUS MT_LP_TZ_SPM_REG(0x016C)
+#define SPM_PWR_STATUS_2ND MT_LP_TZ_SPM_REG(0x0170)
+#define INFRA_SW_CG0 MT_LP_TZ_INFRA_REG(0x0090)
+#define INFRA_SW_CG1 MT_LP_TZ_INFRA_REG(0x0094)
+#define INFRA_SW_CG2 MT_LP_TZ_INFRA_REG(0x00AC)
+#define INFRA_SW_CG3 MT_LP_TZ_INFRA_REG(0x00C8)
+#define INFRA_SW_CG4 MT_LP_TZ_INFRA_REG(0x00E8)
+#define INFRA_SW_CG5 MT_LP_TZ_INFRA_REG(0x00D8)
+#define MMSYS_CG_CON0 MT_LP_TZ_MM_REG(0x100)
+#define MMSYS_CG_CON1 MT_LP_TZ_MM_REG(0x110)
+#define MMSYS_CG_CON2 MT_LP_TZ_MM_REG(0x1A0)
+#define MMSYS_CG_CON3 MT_LP_TZ_MDP_REG(0x100)
+
+/* Check clkmux registers */
+#define CLK_CFG(id) MT_LP_TZ_TOPCK_REG(0xe0 + id * 0x10)
+#define CLK_CHECK BIT(31)
+
+enum {
+ CLKMUX_DISP = 0,
+ CLKMUX_MDP = 1,
+ CLKMUX_IMG1 = 2,
+ CLKMUX_IMG2 = 3,
+ NF_CLKMUX = 4,
+};
+
+static bool is_clkmux_pdn(unsigned int clkmux_id)
+{
+ unsigned int reg, val, idx;
+ bool ret = false;
+
+ if (clkmux_id & CLK_CHECK) {
+ clkmux_id = (clkmux_id & ~CLK_CHECK);
+ reg = clkmux_id / 4U;
+ val = mmio_read_32(CLK_CFG(reg));
+ idx = clkmux_id % 4U;
+ ret = (((val >> (idx * 8U)) & 0x80) != 0U);
+ }
+
+ return ret;
+}
+
+static struct mt_spm_cond_tables spm_cond_t;
+
+struct idle_cond_info {
+ unsigned int subsys_mask;
+ uintptr_t addr;
+ bool bit_flip;
+ unsigned int clkmux_id;
+};
+
+#define IDLE_CG(mask, addr, bitflip, clkmux) \
+ {mask, (uintptr_t)addr, bitflip, clkmux}
+
+static struct idle_cond_info idle_cg_info[PLAT_SPM_COND_MAX] = {
+ IDLE_CG(0xffffffff, SPM_PWR_STATUS, false, 0U),
+ IDLE_CG(0x00000200, INFRA_SW_CG0, true, 0U),
+ IDLE_CG(0x00000200, INFRA_SW_CG1, true, 0U),
+ IDLE_CG(0x00000200, INFRA_SW_CG2, true, 0U),
+ IDLE_CG(0x00000200, INFRA_SW_CG3, true, 0U),
+ IDLE_CG(0x00000200, INFRA_SW_CG4, true, 0U),
+ IDLE_CG(0x00000200, INFRA_SW_CG5, true, 0U),
+ IDLE_CG(0x00200000, MMSYS_CG_CON0, true, (CLK_CHECK | CLKMUX_DISP)),
+ IDLE_CG(0x00200000, MMSYS_CG_CON1, true, (CLK_CHECK | CLKMUX_DISP)),
+ IDLE_CG(0x00200000, MMSYS_CG_CON2, true, (CLK_CHECK | CLKMUX_DISP)),
+ IDLE_CG(0x00200000, MMSYS_CG_CON3, true, (CLK_CHECK | CLKMUX_MDP)),
+};
+
+/* Check pll idle condition */
+#define PLL_MFGPLL MT_LP_TZ_APMIXEDSYS(0x314)
+#define PLL_MMPLL MT_LP_TZ_APMIXEDSYS(0x254)
+#define PLL_UNIVPLL MT_LP_TZ_APMIXEDSYS(0x324)
+#define PLL_MSDCPLL MT_LP_TZ_APMIXEDSYS(0x38c)
+#define PLL_TVDPLL MT_LP_TZ_APMIXEDSYS(0x264)
+
+unsigned int mt_spm_cond_check(int state_id,
+ const struct mt_spm_cond_tables *src,
+ const struct mt_spm_cond_tables *dest,
+ struct mt_spm_cond_tables *res)
+{
+ unsigned int blocked = 0U;
+ unsigned int i;
+ bool is_system_suspend = IS_PLAT_SUSPEND_ID(state_id);
+
+ if ((src == NULL) || (dest == NULL)) {
+ blocked = SPM_COND_CHECK_FAIL;
+ } else {
+ for (i = 0U; i < PLAT_SPM_COND_MAX; i++) {
+ if (res != NULL) {
+ res->table_cg[i] = (src->table_cg[i] & dest->table_cg[i]);
+ if (is_system_suspend && ((res->table_cg[i]) != 0U)) {
+ INFO("suspend: %s block[%u](0x%lx) = 0x%08x\n",
+ dest->name, i, idle_cg_info[i].addr,
+ res->table_cg[i]);
+ }
+
+ if ((res->table_cg[i]) != 0U) {
+ blocked |= BIT(i);
+ }
+ } else if ((src->table_cg[i] & dest->table_cg[i]) != 0U) {
+ blocked |= BIT(i);
+ break;
+ }
+ }
+
+ if (res != NULL) {
+ res->table_pll = (src->table_pll & dest->table_pll);
+
+ if (res->table_pll != 0U) {
+ blocked |= (res->table_pll << SPM_COND_BLOCKED_PLL_IDX) |
+ SPM_COND_CHECK_BLOCKED_PLL;
+ }
+ } else if ((src->table_pll & dest->table_pll) != 0U) {
+ blocked |= SPM_COND_CHECK_BLOCKED_PLL;
+ }
+
+ if (is_system_suspend && ((blocked) != 0U)) {
+ INFO("suspend: %s total blocked = 0x%08x\n", dest->name, blocked);
+ }
+ }
+
+ return blocked;
+}
+
+#define IS_MT_SPM_PWR_OFF(mask) \
+ (((mmio_read_32(SPM_PWR_STATUS) & mask) == 0U) && \
+ ((mmio_read_32(SPM_PWR_STATUS_2ND) & mask) == 0U))
+
+int mt_spm_cond_update(struct mt_resource_constraint **con, int stateid, void *priv)
+{
+ int res;
+ uint32_t i;
+ struct mt_resource_constraint *const *rc;
+
+ /* read all cg state */
+ for (i = 0U; i < PLAT_SPM_COND_MAX; i++) {
+ spm_cond_t.table_cg[i] = 0U;
+
+ /* check mtcmos, if off set idle_value and clk to 0 disable */
+ if (IS_MT_SPM_PWR_OFF(idle_cg_info[i].subsys_mask)) {
+ continue;
+ }
+
+ /* check clkmux */
+ if (is_clkmux_pdn(idle_cg_info[i].clkmux_id)) {
+ continue;
+ }
+
+ spm_cond_t.table_cg[i] = idle_cg_info[i].bit_flip ?
+ ~mmio_read_32(idle_cg_info[i].addr) :
+ mmio_read_32(idle_cg_info[i].addr);
+ }
+
+ spm_cond_t.table_pll = 0U;
+ if ((mmio_read_32(PLL_MFGPLL) & 0x1) != 0U) {
+ spm_cond_t.table_pll |= PLL_BIT_MFGPLL;
+ }
+
+ if ((mmio_read_32(PLL_MMPLL) & 0x1) != 0U) {
+ spm_cond_t.table_pll |= PLL_BIT_MMPLL;
+ }
+
+ if ((mmio_read_32(PLL_UNIVPLL) & 0x1) != 0U) {
+ spm_cond_t.table_pll |= PLL_BIT_UNIVPLL;
+ }
+
+ if ((mmio_read_32(PLL_MSDCPLL) & 0x1) != 0U) {
+ spm_cond_t.table_pll |= PLL_BIT_MSDCPLL;
+ }
+
+ if ((mmio_read_32(PLL_TVDPLL) & 0x1) != 0U) {
+ spm_cond_t.table_pll |= PLL_BIT_TVDPLL;
+ }
+
+ spm_cond_t.priv = priv;
+
+ for (rc = con; *rc != NULL; rc++) {
+ if (((*rc)->update) == NULL) {
+ continue;
+ }
+
+ res = (*rc)->update(stateid, PLAT_RC_UPDATE_CONDITION,
+ (void const *)&spm_cond_t);
+ if (res != MT_RM_STATUS_OK) {
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_cond.h b/plat/mediatek/mt8186/drivers/spm/mt_spm_cond.h
new file mode 100644
index 0000000..24c39ba
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_cond.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_CONDIT_H
+#define MT_SPM_CONDIT_H
+
+#include <mt_lp_rm.h>
+
+enum PLAT_SPM_COND {
+ PLAT_SPM_COND_MTCMOS1 = 0,
+ PLAT_SPM_COND_CG_INFRA_0 = 1,
+ PLAT_SPM_COND_CG_INFRA_1 = 2,
+ PLAT_SPM_COND_CG_INFRA_2 = 3,
+ PLAT_SPM_COND_CG_INFRA_3 = 4,
+ PLAT_SPM_COND_CG_INFRA_4 = 5,
+ PLAT_SPM_COND_CG_INFRA_5 = 6,
+ PLAT_SPM_COND_CG_MMSYS_0 = 7,
+ PLAT_SPM_COND_CG_MMSYS_1 = 8,
+ PLAT_SPM_COND_CG_MMSYS_2 = 9,
+ PLAT_SPM_COND_CG_MMSYS_3 = 10,
+ PLAT_SPM_COND_MAX = 11,
+};
+
+#define PLL_BIT_UNIVPLL BIT(0)
+#define PLL_BIT_MFGPLL BIT(1)
+#define PLL_BIT_MSDCPLL BIT(2)
+#define PLL_BIT_TVDPLL BIT(3)
+#define PLL_BIT_MMPLL BIT(4)
+
+/*
+ * Definition about SPM_COND_CHECK_BLOCKED
+ * bit [00 ~ 15]: cg blocking index
+ * bit [16 ~ 29]: pll blocking index
+ * bit [30] : pll blocking information
+ * bit [31] : idle condition check fail
+ */
+#define SPM_COND_BLOCKED_CG_IDX U(0)
+#define SPM_COND_BLOCKED_PLL_IDX U(16)
+#define SPM_COND_CHECK_BLOCKED_PLL BIT(30)
+#define SPM_COND_CHECK_FAIL BIT(31)
+
+struct mt_spm_cond_tables {
+ char *name;
+ unsigned int table_cg[PLAT_SPM_COND_MAX];
+ unsigned int table_pll;
+ void *priv;
+};
+
+extern unsigned int mt_spm_cond_check(int state_id,
+ const struct mt_spm_cond_tables *src,
+ const struct mt_spm_cond_tables *dest,
+ struct mt_spm_cond_tables *res);
+
+extern int mt_spm_cond_update(struct mt_resource_constraint **con,
+ int stateid, void *priv);
+
+#endif /* MT_SPM_CONDIT_H */
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_conservation.c b/plat/mediatek/mt8186/drivers/spm/mt_spm_conservation.c
new file mode 100644
index 0000000..a6ea977
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_conservation.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <mt_spm.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_vcorefs.h>
+#include <plat_mtk_lpm.h>
+#include <plat_pm.h>
+#include <platform_def.h>
+
+#define MT_RESUMETIME_THRESHOLD_MAX (5U) /*ms*/
+#define IS_RESUME_OVERTIME(delta) (delta > MT_RESUMETIME_THRESHOLD_MAX)
+
+static struct wake_status spm_wakesta; /* record last wakesta */
+
+static int go_to_spm_before_wfi(int state_id, unsigned int ext_opand,
+ struct spm_lp_scen *spm_lp,
+ unsigned int resource_req)
+{
+ int ret = 0;
+ struct pwr_ctrl *pwrctrl;
+ uint32_t cpu = plat_my_core_pos();
+
+ pwrctrl = spm_lp->pwrctrl;
+
+ __spm_set_cpu_status(cpu);
+ __spm_set_power_control(pwrctrl);
+ __spm_set_wakeup_event(pwrctrl);
+ __spm_sync_vcore_dvfs_power_control(pwrctrl, __spm_vcorefs.pwrctrl);
+ __spm_set_pcm_flags(pwrctrl);
+
+ __spm_src_req_update(pwrctrl, resource_req);
+
+ if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) {
+ __spm_set_pcm_wdt(1);
+ }
+
+ if ((ext_opand & MT_SPM_EX_OP_SRCLKEN_RC_BBLPM) != 0U) {
+ __spm_xo_soc_bblpm(1);
+ }
+
+ if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) {
+ spm_hw_s1_state_monitor_resume();
+ }
+
+ /* Disable auto resume by PCM in system suspend stage */
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ __spm_disable_pcm_timer();
+ __spm_set_pcm_wdt(0);
+ }
+
+ __spm_send_cpu_wakeup_event();
+
+ INFO("cpu%d: wakesrc = 0x%x, settle = 0x%x, sec = %u\n",
+ cpu, pwrctrl->wake_src, mmio_read_32(SPM_CLK_SETTLE),
+ (mmio_read_32(PCM_TIMER_VAL) / 32768));
+ INFO("sw_flag = 0x%x 0x%x, req = 0x%x, pwr = 0x%x 0x%x\n",
+ pwrctrl->pcm_flags, pwrctrl->pcm_flags1,
+ mmio_read_32(SPM_SRC_REQ), mmio_read_32(PWR_STATUS),
+ mmio_read_32(PWR_STATUS_2ND));
+
+ return ret;
+}
+
+static void go_to_spm_after_wfi(int state_id, unsigned int ext_opand,
+ struct spm_lp_scen *spm_lp,
+ struct wake_status **status)
+{
+ unsigned int ext_status = 0U;
+
+ spm_wakesta.tr.comm.resumetime = 0;
+ spm_wakesta.tr.comm.times_h = spm_wakesta.tr.comm.times_l = 0;
+
+ /* system watchdog will be resumed at kernel stage */
+ if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) {
+ __spm_set_pcm_wdt(0);
+ }
+
+ if ((ext_opand & MT_SPM_EX_OP_SRCLKEN_RC_BBLPM) != 0U) {
+ __spm_xo_soc_bblpm(0);
+ }
+
+ if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) {
+ spm_hw_s1_state_monitor_pause(&ext_status);
+ }
+
+ __spm_ext_int_wakeup_req_clr();
+
+ __spm_get_wakeup_status(&spm_wakesta, ext_status);
+
+ if (status != NULL) {
+ *status = &spm_wakesta;
+ }
+
+ __spm_clean_after_wakeup();
+
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ __spm_output_wake_reason(state_id, &spm_wakesta);
+ }
+
+}
+
+int spm_conservation(int state_id, unsigned int ext_opand,
+ struct spm_lp_scen *spm_lp, unsigned int resource_req)
+{
+ int ret = 0;
+
+ if (spm_lp == NULL) {
+ ret = -1;
+ } else {
+ spm_lock_get();
+ go_to_spm_before_wfi(state_id, ext_opand, spm_lp, resource_req);
+ spm_lock_release();
+ }
+
+ return ret;
+}
+
+void spm_conservation_finish(int state_id, unsigned int ext_opand,
+ struct spm_lp_scen *spm_lp,
+ struct wake_status **status)
+{
+ spm_lock_get();
+ go_to_spm_after_wfi(state_id, ext_opand, spm_lp, status);
+ spm_lock_release();
+}
+
+int spm_conservation_get_result(struct wake_status **res)
+{
+ int ret = 0;
+
+ if (res == NULL) {
+ ret = -1;
+ } else {
+ *res = &spm_wakesta;
+ }
+ return ret;
+}
+
+#define GPIO_BANK (GPIO_BASE + 0x6F0)
+#define TRAP_UFS_FIRST BIT(11) /* bit 11, 0: UFS, 1: eMMC */
+
+void spm_conservation_pwrctrl_init(struct pwr_ctrl *pwrctrl)
+{
+ if (pwrctrl != NULL) {
+ /* For ufs, emmc storage type */
+ if ((mmio_read_32(GPIO_BANK) & TRAP_UFS_FIRST) != 0U) {
+ /* If eMMC is used, mask UFS req */
+ pwrctrl->reg_ufs_srcclkena_mask_b = 0;
+ pwrctrl->reg_ufs_infra_req_mask_b = 0;
+ pwrctrl->reg_ufs_apsrc_req_mask_b = 0;
+ pwrctrl->reg_ufs_vrf18_req_mask_b = 0;
+ pwrctrl->reg_ufs_ddren_req_mask_b = 0;
+ }
+ }
+}
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_conservation.h b/plat/mediatek/mt8186/drivers/spm/mt_spm_conservation.h
new file mode 100644
index 0000000..e7ef346
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_conservation.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_CONSERVATION_H
+#define MT_SPM_CONSERVATION_H
+
+#include <mt_spm_internal.h>
+
+extern int spm_conservation(int state_id, unsigned int ext_opand,
+ struct spm_lp_scen *spm_lp,
+ unsigned int resource_req);
+extern void spm_conservation_finish(int state_id, unsigned int ext_opand,
+ struct spm_lp_scen *spm_lp,
+ struct wake_status **status);
+extern int spm_conservation_get_result(struct wake_status **res);
+extern void spm_conservation_pwrctrl_init(struct pwr_ctrl *pwrctrl);
+
+#endif /* MT_SPM_CONSERVATION_H */
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_constraint.h b/plat/mediatek/mt8186/drivers/spm/mt_spm_constraint.h
new file mode 100644
index 0000000..53be3b6
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_constraint.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_CONSTRAINT_H
+#define MT_SPM_CONSTRAINT_H
+
+#include <mt_lp_rm.h>
+
+#define MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF BIT(0)
+#define MT_RM_CONSTRAINT_ALLOW_DRAM_S0 BIT(1)
+#define MT_RM_CONSTRAINT_ALLOW_DRAM_S1 BIT(2)
+#define MT_RM_CONSTRAINT_ALLOW_VCORE_LP BIT(3)
+#define MT_RM_CONSTRAINT_ALLOW_INFRA_PDN BIT(4)
+#define MT_RM_CONSTRAINT_ALLOW_BUS26M_OFF BIT(5)
+#define MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND BIT(6)
+#define MT_RM_CONSTRAINT_ALLOW_BBLPM BIT(7)
+#define MT_RM_CONSTRAINT_ALLOW_XO_UFS BIT(8)
+#define MT_RM_CONSTRAINT_ALLOW_GPS_STATE BIT(9)
+#define MT_RM_CONSTRAINT_ALLOW_LVTS_STATE BIT(10)
+
+#define MT_SPM_RC_INVALID (0x0)
+#define MT_SPM_RC_VALID_SW BIT(0)
+#define MT_SPM_RC_VALID_FW BIT(1)
+#define MT_SPM_RC_VALID_RESIDNECY BIT(2)
+#define MT_SPM_RC_VALID_COND_CHECK BIT(3)
+#define MT_SPM_RC_VALID_COND_LATCH BIT(4)
+#define MT_SPM_RC_VALID_UFS_H8 BIT(5)
+#define MT_SPM_RC_VALID_FLIGHTMODE BIT(6)
+#define MT_SPM_RC_VALID_XSOC_BBLPM BIT(7)
+#define MT_SPM_RC_VALID_TRACE_EVENT BIT(8)
+
+#define MT_SPM_RC_VALID (MT_SPM_RC_VALID_SW)
+
+#define IS_MT_RM_RC_READY(status) \
+ ((status & MT_SPM_RC_VALID) == MT_SPM_RC_VALID)
+
+#define MT_SPM_RC_BBLPM_MODE \
+ (MT_SPM_RC_VALID_UFS_H8 | \
+ MT_SPM_RC_VALID_FLIGHTMODE | \
+ MT_SPM_RC_VALID_XSOC_BBLPM)
+
+#define IS_MT_SPM_RC_BBLPM_MODE(st) \
+ ((st & (MT_SPM_RC_BBLPM_MODE)) == MT_SPM_RC_BBLPM_MODE)
+
+struct constraint_status {
+ uint16_t id;
+ uint16_t valid;
+ uint32_t cond_block;
+ uint32_t enter_cnt;
+ struct mt_spm_cond_tables *cond_res;
+};
+
+enum MT_SPM_RM_RC_TYPE {
+ MT_RM_CONSTRAINT_ID_BUS26M = 0U,
+ MT_RM_CONSTRAINT_ID_SYSPLL = 1U,
+ MT_RM_CONSTRAINT_ID_DRAM = 2U,
+ MT_RM_CONSTRAINT_ID_CPU_BUCK_LDO = 3U,
+ MT_RM_CONSTRAINT_ID_ALL = 4U,
+};
+
+#endif /* MT_SPM_CONSTRAINT_H */
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_extern.c b/plat/mediatek/mt8186/drivers/spm/mt_spm_extern.c
new file mode 100644
index 0000000..608d9f9
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_extern.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) since 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#define INFRA_AO_RES_CTRL_MASK (INFRACFG_AO_BASE + 0xB8)
+#define INFRA_AO_RES_CTRL_MASK_EMI_IDLE BIT(18)
+#define INFRA_AO_RES_CTRL_MASK_MPU_IDLE BIT(15)
+
+void spm_extern_initialize(void)
+{
+ unsigned int val;
+
+ val = mmio_read_32(INFRA_AO_RES_CTRL_MASK);
+
+ val |= (INFRA_AO_RES_CTRL_MASK_EMI_IDLE | INFRA_AO_RES_CTRL_MASK_MPU_IDLE);
+ mmio_write_32(INFRA_AO_RES_CTRL_MASK, val);
+}
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_extern.h b/plat/mediatek/mt8186/drivers/spm/mt_spm_extern.h
new file mode 100644
index 0000000..5bcbaff
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_extern.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) since 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_EXTERN_H
+#define MT_SPM_EXTERN_H
+
+void spm_extern_initialize(void);
+
+#endif
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_idle.c b/plat/mediatek/mt8186/drivers/spm/mt_spm_idle.c
new file mode 100644
index 0000000..04776c8
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_idle.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mt_spm.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_idle.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <plat_pm.h>
+
+#define __WAKE_SRC_FOR_SUSPEND_COMMON__ \
+ (R12_PCM_TIMER | \
+ R12_KP_IRQ_B | \
+ R12_APWDT_EVENT_B | \
+ R12_APXGPT1_EVENT_B | \
+ R12_CONN2AP_SPM_WAKEUP_B | \
+ R12_EINT_EVENT_B | \
+ R12_CONN_WDT_IRQ_B | \
+ R12_SSPM2SPM_WAKEUP_B | \
+ R12_SCP2SPM_WAKEUP_B | \
+ R12_ADSP2SPM_WAKEUP_B | \
+ R12_USBX_CDSC_B | \
+ R12_USBX_POWERDWN_B | \
+ R12_SYS_TIMER_EVENT_B | \
+ R12_EINT_EVENT_SECURE_B | \
+ R12_AFE_IRQ_MCU_B | \
+ R12_SYS_CIRQ_IRQ_B | \
+ R12_NNA_WAKEUP | \
+ R12_SEJ_EVENT_B | \
+ R12_REG_CPU_WAKEUP)
+
+#if defined(CFG_MICROTRUST_TEE_SUPPORT)
+#define WAKE_SRC_FOR_SUSPEND (__WAKE_SRC_FOR_SUSPEND_COMMON__)
+#else
+#define WAKE_SRC_FOR_SUSPEND \
+ (__WAKE_SRC_FOR_SUSPEND_COMMON__ | \
+ R12_SEJ_EVENT_B)
+#endif
+
+static struct pwr_ctrl idle_spm_pwr = {
+ .timer_val = 0x28000,
+ .wake_src = WAKE_SRC_FOR_SUSPEND,
+ /* Auto-gen Start */
+
+ /* SPM_AP_STANDBY_CON */
+ .reg_wfi_op = 0,
+ .reg_wfi_type = 0,
+ .reg_mp0_cputop_idle_mask = 0,
+ .reg_mp1_cputop_idle_mask = 0,
+ .reg_mcusys_idle_mask = 0,
+ .reg_md_apsrc_1_sel = 0,
+ .reg_md_apsrc_0_sel = 0,
+ .reg_conn_apsrc_sel = 0,
+
+ /* SPM_SRC6_MASK */
+ .reg_ccif_event_infra_req_mask_b = 0,
+ .reg_ccif_event_apsrc_req_mask_b = 0,
+
+ /* SPM_SRC_REQ */
+ .reg_spm_apsrc_req = 0,
+ .reg_spm_f26m_req = 0,
+ .reg_spm_infra_req = 0,
+ .reg_spm_vrf18_req = 0,
+ .reg_spm_ddren_req = 0,
+ .reg_spm_dvfs_req = 0,
+ .reg_spm_sw_mailbox_req = 0,
+ .reg_spm_sspm_mailbox_req = 0,
+ .reg_spm_adsp_mailbox_req = 0,
+ .reg_spm_scp_mailbox_req = 0,
+
+ /* SPM_SRC_MASK */
+ .reg_md_0_srcclkena_mask_b = 0,
+ .reg_md_0_infra_req_mask_b = 0,
+ .reg_md_0_apsrc_req_mask_b = 0,
+ .reg_md_0_vrf18_req_mask_b = 0,
+ .reg_md_0_ddren_req_mask_b = 0,
+ .reg_md_1_srcclkena_mask_b = 0,
+ .reg_md_1_infra_req_mask_b = 0,
+ .reg_md_1_apsrc_req_mask_b = 0,
+ .reg_md_1_vrf18_req_mask_b = 0,
+ .reg_md_1_ddren_req_mask_b = 0,
+ .reg_conn_srcclkena_mask_b = 1,
+ .reg_conn_srcclkenb_mask_b = 0,
+ .reg_conn_infra_req_mask_b = 1,
+ .reg_conn_apsrc_req_mask_b = 1,
+ .reg_conn_vrf18_req_mask_b = 1,
+ .reg_conn_ddren_req_mask_b = 1,
+ .reg_conn_vfe28_mask_b = 0,
+ .reg_srcclkeni_srcclkena_mask_b = 1,
+ .reg_srcclkeni_infra_req_mask_b = 1,
+ .reg_infrasys_apsrc_req_mask_b = 0,
+ .reg_infrasys_ddren_req_mask_b = 1,
+ .reg_sspm_srcclkena_mask_b = 1,
+ .reg_sspm_infra_req_mask_b = 1,
+ .reg_sspm_apsrc_req_mask_b = 1,
+ .reg_sspm_vrf18_req_mask_b = 1,
+ .reg_sspm_ddren_req_mask_b = 1,
+
+ /* SPM_SRC2_MASK */
+ .reg_scp_srcclkena_mask_b = 1,
+ .reg_scp_infra_req_mask_b = 1,
+ .reg_scp_apsrc_req_mask_b = 1,
+ .reg_scp_vrf18_req_mask_b = 1,
+ .reg_scp_ddren_req_mask_b = 1,
+ .reg_audio_dsp_srcclkena_mask_b = 1,
+ .reg_audio_dsp_infra_req_mask_b = 1,
+ .reg_audio_dsp_apsrc_req_mask_b = 1,
+ .reg_audio_dsp_vrf18_req_mask_b = 1,
+ .reg_audio_dsp_ddren_req_mask_b = 1,
+ .reg_ufs_srcclkena_mask_b = 1,
+ .reg_ufs_infra_req_mask_b = 1,
+ .reg_ufs_apsrc_req_mask_b = 1,
+ .reg_ufs_vrf18_req_mask_b = 1,
+ .reg_ufs_ddren_req_mask_b = 1,
+ .reg_disp0_apsrc_req_mask_b = 1,
+ .reg_disp0_ddren_req_mask_b = 1,
+ .reg_disp1_apsrc_req_mask_b = 1,
+ .reg_disp1_ddren_req_mask_b = 1,
+ .reg_gce_infra_req_mask_b = 1,
+ .reg_gce_apsrc_req_mask_b = 1,
+ .reg_gce_vrf18_req_mask_b = 1,
+ .reg_gce_ddren_req_mask_b = 1,
+ .reg_apu_srcclkena_mask_b = 0,
+ .reg_apu_infra_req_mask_b = 0,
+ .reg_apu_apsrc_req_mask_b = 0,
+ .reg_apu_vrf18_req_mask_b = 0,
+ .reg_apu_ddren_req_mask_b = 0,
+ .reg_cg_check_srcclkena_mask_b = 0,
+ .reg_cg_check_apsrc_req_mask_b = 0,
+ .reg_cg_check_vrf18_req_mask_b = 0,
+ .reg_cg_check_ddren_req_mask_b = 0,
+
+ /* SPM_SRC3_MASK */
+ .reg_dvfsrc_event_trigger_mask_b = 1,
+ .reg_sw2spm_wakeup_mask_b = 0,
+ .reg_adsp2spm_wakeup_mask_b = 0,
+ .reg_sspm2spm_wakeup_mask_b = 0,
+ .reg_scp2spm_wakeup_mask_b = 0,
+ .reg_csyspwrup_ack_mask = 1,
+ .reg_spm_reserved_srcclkena_mask_b = 0,
+ .reg_spm_reserved_infra_req_mask_b = 0,
+ .reg_spm_reserved_apsrc_req_mask_b = 0,
+ .reg_spm_reserved_vrf18_req_mask_b = 0,
+ .reg_spm_reserved_ddren_req_mask_b = 0,
+ .reg_mcupm_srcclkena_mask_b = 0,
+ .reg_mcupm_infra_req_mask_b = 0,
+ .reg_mcupm_apsrc_req_mask_b = 0,
+ .reg_mcupm_vrf18_req_mask_b = 0,
+ .reg_mcupm_ddren_req_mask_b = 0,
+ .reg_msdc0_srcclkena_mask_b = 1,
+ .reg_msdc0_infra_req_mask_b = 1,
+ .reg_msdc0_apsrc_req_mask_b = 1,
+ .reg_msdc0_vrf18_req_mask_b = 1,
+ .reg_msdc0_ddren_req_mask_b = 1,
+ .reg_msdc1_srcclkena_mask_b = 1,
+ .reg_msdc1_infra_req_mask_b = 1,
+ .reg_msdc1_apsrc_req_mask_b = 1,
+ .reg_msdc1_vrf18_req_mask_b = 1,
+ .reg_msdc1_ddren_req_mask_b = 1,
+
+ /* SPM_SRC4_MASK */
+ .reg_ccif_event_srcclkena_mask_b = 0,
+ .reg_bak_psri_srcclkena_mask_b = 0,
+ .reg_bak_psri_infra_req_mask_b = 0,
+ .reg_bak_psri_apsrc_req_mask_b = 0,
+ .reg_bak_psri_vrf18_req_mask_b = 0,
+ .reg_bak_psri_ddren_req_mask_b = 0,
+ .reg_dramc_md32_infra_req_mask_b = 0,
+ .reg_dramc_md32_vrf18_req_mask_b = 0,
+ .reg_conn_srcclkenb2pwrap_mask_b = 0,
+ .reg_dramc_md32_apsrc_req_mask_b = 0,
+
+ /* SPM_SRC5_MASK */
+ .reg_mcusys_merge_apsrc_req_mask_b = 0x83,
+ .reg_mcusys_merge_ddren_req_mask_b = 0x83,
+ .reg_afe_srcclkena_mask_b = 1,
+ .reg_afe_infra_req_mask_b = 1,
+ .reg_afe_apsrc_req_mask_b = 1,
+ .reg_afe_vrf18_req_mask_b = 1,
+ .reg_afe_ddren_req_mask_b = 1,
+ .reg_msdc2_srcclkena_mask_b = 0,
+ .reg_msdc2_infra_req_mask_b = 0,
+ .reg_msdc2_apsrc_req_mask_b = 0,
+ .reg_msdc2_vrf18_req_mask_b = 0,
+ .reg_msdc2_ddren_req_mask_b = 0,
+
+ /* SPM_WAKEUP_EVENT_MASK */
+ .reg_wakeup_event_mask = 0xE1283203,
+
+ /* SPM_WAKEUP_EVENT_EXT_MASK */
+ .reg_ext_wakeup_event_mask = 0xFFFFFFFF,
+
+ /* SPM_SRC7_MASK */
+ .reg_pcie_srcclkena_mask_b = 0,
+ .reg_pcie_infra_req_mask_b = 0,
+ .reg_pcie_apsrc_req_mask_b = 0,
+ .reg_pcie_vrf18_req_mask_b = 0,
+ .reg_pcie_ddren_req_mask_b = 0,
+ .reg_dpmaif_srcclkena_mask_b = 1,
+ .reg_dpmaif_infra_req_mask_b = 1,
+ .reg_dpmaif_apsrc_req_mask_b = 1,
+ .reg_dpmaif_vrf18_req_mask_b = 1,
+ .reg_dpmaif_ddren_req_mask_b = 1,
+
+ /* Auto-gen End */
+};
+
+struct spm_lp_scen idle_spm_lp = {
+ .pwrctrl = &idle_spm_pwr,
+};
+
+int mt_spm_idle_generic_enter(int state_id, unsigned int ext_opand,
+ spm_idle_conduct fn)
+{
+ unsigned int src_req = 0U;
+
+ if (fn != NULL) {
+ fn(&idle_spm_lp, &src_req);
+ }
+
+ return spm_conservation(state_id, ext_opand, &idle_spm_lp, src_req);
+}
+void mt_spm_idle_generic_resume(int state_id, unsigned int ext_opand,
+ struct wake_status **status,
+ spm_idle_conduct_restore fn)
+{
+ ext_opand |= (MT_SPM_EX_OP_TIME_CHECK | MT_SPM_EX_OP_TIME_OBS);
+ spm_conservation_finish(state_id, ext_opand, &idle_spm_lp, status);
+}
+
+void mt_spm_idle_generic_init(void)
+{
+ spm_conservation_pwrctrl_init(idle_spm_lp.pwrctrl);
+}
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_idle.h b/plat/mediatek/mt8186/drivers/spm/mt_spm_idle.h
new file mode 100644
index 0000000..7196190
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_idle.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_IDLE_H
+#define MT_SPM_IDLE_H
+
+typedef void (*spm_idle_conduct)(struct spm_lp_scen *spm_lp, unsigned int *resource_req);
+
+typedef int (*spm_idle_conduct_restore)(int state_id,
+ struct spm_lp_scen *spm_lp,
+ struct wake_status *status);
+
+int mt_spm_idle_generic_enter(int state_id, unsigned int ext_opand, spm_idle_conduct fn);
+
+void mt_spm_idle_generic_resume(int state_id, unsigned int ext_opand,
+ struct wake_status **status,
+ spm_idle_conduct_restore fn);
+
+void mt_spm_idle_generic_init(void);
+
+#endif /* MT_SPM_IDLE_H */
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_internal.c b/plat/mediatek/mt8186/drivers/spm/mt_spm_internal.c
new file mode 100644
index 0000000..f228961
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_internal.c
@@ -0,0 +1,623 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <mt_spm.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <plat_pm.h>
+#include <platform_def.h>
+
+/* Define and Declare */
+#define ROOT_CORE_ADDR_OFFSET (0x20000000)
+#define SPM_WAKEUP_EVENT_MASK_CLEAN_MASK (0xefffffff)
+#define SPM_INIT_DONE_US (20)
+
+static unsigned int mt_spm_bblpm_cnt;
+
+const char *wakeup_src_str[32] = {
+ [0] = "R12_PCM_TIMER",
+ [1] = "R12_RESERVED_DEBUG_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_SC_SSPM2SPM_WAKEUP_B",
+ [11] = "R12_SC_SCP2SPM_WAKEUP_B",
+ [12] = "R12_SC_ADSP2SPM_WAKEUP_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_AP2AP_PEER_WAKEUPEVENT_B",
+ [27] = "R12_SEJ_EVENT_B",
+ [28] = "R12_SPM_CPU_WAKEUPEVENT_B",
+ [29] = "R12_APUSYS",
+ [30] = "R12_PCIE_BRIDGE_IRQ",
+ [31] = "R12_PCIE_IRQ",
+};
+
+/* Function and API */
+wake_reason_t __spm_output_wake_reason(int state_id, const struct wake_status *wakesta)
+{
+ uint32_t i, bk_vtcxo_dur, spm_26m_off_pct = 0U;
+ wake_reason_t wr = WR_UNKNOWN;
+
+ if (wakesta != NULL) {
+ if (wakesta->abort != 0U) {
+ ERROR("spmfw flow is aborted: 0x%x, timer_out = %u\n",
+ wakesta->abort, wakesta->timer_out);
+ } else {
+ for (i = 0U; i < 32U; i++) {
+ if ((wakesta->r12 & BIT(i)) != 0U) {
+ INFO("wake up by %s, timer_out = %u\n",
+ wakeup_src_str[i], wakesta->timer_out);
+ wr = WR_WAKE_SRC;
+ break;
+ }
+ }
+ }
+
+ INFO("r12 = 0x%x, r12_ext = 0x%x, r13 = 0x%x, debug_flag = 0x%x 0x%x\n",
+ wakesta->r12, wakesta->r12_ext, wakesta->r13, wakesta->debug_flag,
+ wakesta->debug_flag1);
+ INFO("raw_sta = 0x%x 0x%x 0x%x, idle_sta = 0x%x, cg_check_sta = 0x%x\n",
+ wakesta->raw_sta, wakesta->md32pcm_wakeup_sta,
+ wakesta->md32pcm_event_sta, wakesta->idle_sta,
+ wakesta->cg_check_sta);
+ INFO("req_sta = 0x%x 0x%x 0x%x 0x%x 0x%x, isr = 0x%x\n",
+ wakesta->req_sta0, wakesta->req_sta1, wakesta->req_sta2,
+ wakesta->req_sta3, wakesta->req_sta4, wakesta->isr);
+ INFO("rt_req_sta0 = 0x%x, rt_req_sta1 = 0x%x, rt_req_sta2 = 0x%x\n",
+ wakesta->rt_req_sta0, wakesta->rt_req_sta1, wakesta->rt_req_sta2);
+ INFO("rt_req_sta3 = 0x%x, dram_sw_con_3 = 0x%x, raw_ext_sta = 0x%x\n",
+ wakesta->rt_req_sta3, wakesta->rt_req_sta4, wakesta->raw_ext_sta);
+ INFO("wake_misc = 0x%x, pcm_flag = 0x%x 0x%x 0x%x 0x%x, req = 0x%x\n",
+ wakesta->wake_misc, wakesta->sw_flag0, wakesta->sw_flag1,
+ wakesta->b_sw_flag0, wakesta->b_sw_flag1, wakesta->src_req);
+ INFO("clk_settle = 0x%x, wlk_cntcv_l = 0x%x, wlk_cntcv_h = 0x%x\n",
+ wakesta->clk_settle, mmio_read_32(SYS_TIMER_VALUE_L),
+ mmio_read_32(SYS_TIMER_VALUE_H));
+
+ if (wakesta->timer_out != 0U) {
+ bk_vtcxo_dur = mmio_read_32(SPM_BK_VTCXO_DUR);
+ spm_26m_off_pct = (100 * bk_vtcxo_dur) / wakesta->timer_out;
+ INFO("spm_26m_off_pct = %u\n", spm_26m_off_pct);
+ }
+ }
+
+ return wr;
+}
+
+void __spm_set_cpu_status(unsigned int cpu)
+{
+ uint32_t root_core_addr;
+
+ if (cpu < 8U) {
+ mmio_write_32(ROOT_CPUTOP_ADDR, BIT(cpu));
+
+ root_core_addr = SPM_CPU0_PWR_CON + (cpu * 0x4);
+ root_core_addr += ROOT_CORE_ADDR_OFFSET;
+ mmio_write_32(ROOT_CORE_ADDR, root_core_addr);
+
+ /* Notify SSPM that preferred cpu wakeup */
+ mmio_write_32(MCUPM_MBOX_WAKEUP_CPU, cpu);
+ } else {
+ ERROR("%s: error cpu number %d\n", __func__, cpu);
+ }
+}
+
+void __spm_src_req_update(const struct pwr_ctrl *pwrctrl,
+ unsigned int resource_usage)
+{
+ uint8_t apsrc_req = ((resource_usage & MT_SPM_DRAM_S0) != 0U) ?
+ 1 : pwrctrl->reg_spm_apsrc_req;
+ uint8_t ddr_en_req = ((resource_usage & MT_SPM_DRAM_S1) != 0U) ?
+ 1 : pwrctrl->reg_spm_ddren_req;
+ uint8_t vrf18_req = ((resource_usage & MT_SPM_SYSPLL) != 0U) ?
+ 1 : pwrctrl->reg_spm_vrf18_req;
+ uint8_t infra_req = ((resource_usage & MT_SPM_INFRA) != 0U) ?
+ 1 : pwrctrl->reg_spm_infra_req;
+ uint8_t f26m_req = ((resource_usage & (MT_SPM_26M | MT_SPM_XO_FPM)) != 0U) ?
+ 1 : pwrctrl->reg_spm_f26m_req;
+
+ /*
+ * if SPM_FLAG_SSPM_INFRA_SLEEP_MODE set,
+ * clear sspm_srclkena_mask_b and sspm_infra_mask_b
+ */
+ uint8_t reg_sspm_srcclkena_mask_b =
+ (pwrctrl->pcm_flags & SPM_FLAG_SSPM_INFRA_SLEEP_MODE)
+ ? 0U : pwrctrl->reg_sspm_srcclkena_mask_b;
+
+ uint8_t reg_sspm_infra_req_mask_b =
+ (pwrctrl->pcm_flags & SPM_FLAG_SSPM_INFRA_SLEEP_MODE)
+ ? 0 : pwrctrl->reg_sspm_infra_req_mask_b;
+
+ /* SPM_SRC_REQ */
+ mmio_write_32(SPM_SRC_REQ,
+ ((apsrc_req & 0x1) << 0) |
+ ((f26m_req & 0x1) << 1) |
+ ((infra_req & 0x1) << 3) |
+ ((vrf18_req & 0x1) << 4) |
+ ((ddr_en_req & 0x1) << 7) |
+ ((pwrctrl->reg_spm_dvfs_req & 0x1) << 8) |
+ ((pwrctrl->reg_spm_sw_mailbox_req & 0x1) << 9) |
+ ((pwrctrl->reg_spm_sspm_mailbox_req & 0x1) << 10) |
+ ((pwrctrl->reg_spm_adsp_mailbox_req & 0x1) << 11) |
+ ((pwrctrl->reg_spm_scp_mailbox_req & 0x1) << 12));
+
+ /* SPM_SRC_MASK */
+ mmio_write_32(SPM_SRC_MASK,
+ ((pwrctrl->reg_md_0_srcclkena_mask_b & 0x1) << 0) |
+ ((pwrctrl->reg_md_0_infra_req_mask_b & 0x1) << 1) |
+ ((pwrctrl->reg_md_0_apsrc_req_mask_b & 0x1) << 2) |
+ ((pwrctrl->reg_md_0_vrf18_req_mask_b & 0x1) << 3) |
+ ((pwrctrl->reg_md_0_ddren_req_mask_b & 0x1) << 4) |
+ ((pwrctrl->reg_md_1_srcclkena_mask_b & 0x1) << 5) |
+ ((pwrctrl->reg_md_1_infra_req_mask_b & 0x1) << 6) |
+ ((pwrctrl->reg_md_1_apsrc_req_mask_b & 0x1) << 7) |
+ ((pwrctrl->reg_md_1_vrf18_req_mask_b & 0x1) << 8) |
+ ((pwrctrl->reg_md_1_ddren_req_mask_b & 0x1) << 9) |
+ ((pwrctrl->reg_conn_srcclkena_mask_b & 0x1) << 10) |
+ ((pwrctrl->reg_conn_srcclkenb_mask_b & 0x1) << 11) |
+ ((pwrctrl->reg_conn_infra_req_mask_b & 0x1) << 12) |
+ ((pwrctrl->reg_conn_apsrc_req_mask_b & 0x1) << 13) |
+ ((pwrctrl->reg_conn_vrf18_req_mask_b & 0x1) << 14) |
+ ((pwrctrl->reg_conn_ddren_req_mask_b & 0x1) << 15) |
+ ((pwrctrl->reg_conn_vfe28_mask_b & 0x1) << 16) |
+ ((pwrctrl->reg_srcclkeni_srcclkena_mask_b & 0x7) << 17) |
+ ((pwrctrl->reg_srcclkeni_infra_req_mask_b & 0x7) << 20) |
+ ((pwrctrl->reg_infrasys_apsrc_req_mask_b & 0x1) << 25) |
+ ((pwrctrl->reg_infrasys_ddren_req_mask_b & 0x1) << 26) |
+ ((reg_sspm_srcclkena_mask_b & 0x1) << 27) |
+ ((reg_sspm_infra_req_mask_b & 0x1) << 28) |
+ ((pwrctrl->reg_sspm_apsrc_req_mask_b & 0x1) << 29) |
+ ((pwrctrl->reg_sspm_vrf18_req_mask_b & 0x1) << 30) |
+ ((pwrctrl->reg_sspm_ddren_req_mask_b & 0x1) << 31));
+}
+
+void __spm_set_power_control(const struct pwr_ctrl *pwrctrl)
+{
+ /* Auto-gen Start */
+
+ /* SPM_AP_STANDBY_CON */
+ mmio_write_32(SPM_AP_STANDBY_CON,
+ ((pwrctrl->reg_wfi_op & 0x1) << 0) |
+ ((pwrctrl->reg_wfi_type & 0x1) << 1) |
+ ((pwrctrl->reg_mp0_cputop_idle_mask & 0x1) << 2) |
+ ((pwrctrl->reg_mp1_cputop_idle_mask & 0x1) << 3) |
+ ((pwrctrl->reg_mcusys_idle_mask & 0x1) << 4) |
+ ((pwrctrl->reg_md_apsrc_1_sel & 0x1) << 25) |
+ ((pwrctrl->reg_md_apsrc_0_sel & 0x1) << 26) |
+ ((pwrctrl->reg_conn_apsrc_sel & 0x1) << 29));
+
+ /* SPM_SRC6_MASK */
+ mmio_write_32(SPM_SRC6_MASK,
+ ((pwrctrl->reg_ccif_event_infra_req_mask_b & 0xffff) << 0) |
+ ((pwrctrl->reg_ccif_event_apsrc_req_mask_b & 0xffff) << 16));
+
+ /* SPM_SRC_REQ */
+ mmio_write_32(SPM_SRC_REQ,
+ ((pwrctrl->reg_spm_apsrc_req & 0x1) << 0) |
+ ((pwrctrl->reg_spm_f26m_req & 0x1) << 1) |
+ ((pwrctrl->reg_spm_infra_req & 0x1) << 3) |
+ ((pwrctrl->reg_spm_vrf18_req & 0x1) << 4) |
+ ((pwrctrl->reg_spm_ddren_req & 0x1) << 7) |
+ ((pwrctrl->reg_spm_dvfs_req & 0x1) << 8) |
+ ((pwrctrl->reg_spm_sw_mailbox_req & 0x1) << 9) |
+ ((pwrctrl->reg_spm_sspm_mailbox_req & 0x1) << 10) |
+ ((pwrctrl->reg_spm_adsp_mailbox_req & 0x1) << 11) |
+ ((pwrctrl->reg_spm_scp_mailbox_req & 0x1) << 12));
+
+ /* SPM_SRC_MASK */
+ mmio_write_32(SPM_SRC_MASK,
+ ((pwrctrl->reg_md_0_srcclkena_mask_b & 0x1) << 0) |
+ ((pwrctrl->reg_md_0_infra_req_mask_b & 0x1) << 1) |
+ ((pwrctrl->reg_md_0_apsrc_req_mask_b & 0x1) << 2) |
+ ((pwrctrl->reg_md_0_vrf18_req_mask_b & 0x1) << 3) |
+ ((pwrctrl->reg_md_0_ddren_req_mask_b & 0x1) << 4) |
+ ((pwrctrl->reg_md_1_srcclkena_mask_b & 0x1) << 5) |
+ ((pwrctrl->reg_md_1_infra_req_mask_b & 0x1) << 6) |
+ ((pwrctrl->reg_md_1_apsrc_req_mask_b & 0x1) << 7) |
+ ((pwrctrl->reg_md_1_vrf18_req_mask_b & 0x1) << 8) |
+ ((pwrctrl->reg_md_1_ddren_req_mask_b & 0x1) << 9) |
+ ((pwrctrl->reg_conn_srcclkena_mask_b & 0x1) << 10) |
+ ((pwrctrl->reg_conn_srcclkenb_mask_b & 0x1) << 11) |
+ ((pwrctrl->reg_conn_infra_req_mask_b & 0x1) << 12) |
+ ((pwrctrl->reg_conn_apsrc_req_mask_b & 0x1) << 13) |
+ ((pwrctrl->reg_conn_vrf18_req_mask_b & 0x1) << 14) |
+ ((pwrctrl->reg_conn_ddren_req_mask_b & 0x1) << 15) |
+ ((pwrctrl->reg_conn_vfe28_mask_b & 0x1) << 16) |
+ ((pwrctrl->reg_srcclkeni_srcclkena_mask_b & 0x7) << 17) |
+ ((pwrctrl->reg_srcclkeni_infra_req_mask_b & 0x7) << 20) |
+ ((pwrctrl->reg_infrasys_apsrc_req_mask_b & 0x1) << 25) |
+ ((pwrctrl->reg_infrasys_ddren_req_mask_b & 0x1) << 26) |
+ ((pwrctrl->reg_sspm_srcclkena_mask_b & 0x1) << 27) |
+ ((pwrctrl->reg_sspm_infra_req_mask_b & 0x1) << 28) |
+ ((pwrctrl->reg_sspm_apsrc_req_mask_b & 0x1) << 29) |
+ ((pwrctrl->reg_sspm_vrf18_req_mask_b & 0x1) << 30) |
+ ((pwrctrl->reg_sspm_ddren_req_mask_b & 0x1) << 31));
+
+ /* SPM_SRC2_MASK */
+ mmio_write_32(SPM_SRC2_MASK,
+ ((pwrctrl->reg_scp_srcclkena_mask_b & 0x1) << 0) |
+ ((pwrctrl->reg_scp_infra_req_mask_b & 0x1) << 1) |
+ ((pwrctrl->reg_scp_apsrc_req_mask_b & 0x1) << 2) |
+ ((pwrctrl->reg_scp_vrf18_req_mask_b & 0x1) << 3) |
+ ((pwrctrl->reg_scp_ddren_req_mask_b & 0x1) << 4) |
+ ((pwrctrl->reg_audio_dsp_srcclkena_mask_b & 0x1) << 5) |
+ ((pwrctrl->reg_audio_dsp_infra_req_mask_b & 0x1) << 6) |
+ ((pwrctrl->reg_audio_dsp_apsrc_req_mask_b & 0x1) << 7) |
+ ((pwrctrl->reg_audio_dsp_vrf18_req_mask_b & 0x1) << 8) |
+ ((pwrctrl->reg_audio_dsp_ddren_req_mask_b & 0x1) << 9) |
+ ((pwrctrl->reg_ufs_srcclkena_mask_b & 0x1) << 10) |
+ ((pwrctrl->reg_ufs_infra_req_mask_b & 0x1) << 11) |
+ ((pwrctrl->reg_ufs_apsrc_req_mask_b & 0x1) << 12) |
+ ((pwrctrl->reg_ufs_vrf18_req_mask_b & 0x1) << 13) |
+ ((pwrctrl->reg_ufs_ddren_req_mask_b & 0x1) << 14) |
+ ((pwrctrl->reg_disp0_apsrc_req_mask_b & 0x1) << 15) |
+ ((pwrctrl->reg_disp0_ddren_req_mask_b & 0x1) << 16) |
+ ((pwrctrl->reg_disp1_apsrc_req_mask_b & 0x1) << 17) |
+ ((pwrctrl->reg_disp1_ddren_req_mask_b & 0x1) << 18) |
+ ((pwrctrl->reg_gce_infra_req_mask_b & 0x1) << 19) |
+ ((pwrctrl->reg_gce_apsrc_req_mask_b & 0x1) << 20) |
+ ((pwrctrl->reg_gce_vrf18_req_mask_b & 0x1) << 21) |
+ ((pwrctrl->reg_gce_ddren_req_mask_b & 0x1) << 22) |
+ ((pwrctrl->reg_apu_srcclkena_mask_b & 0x1) << 23) |
+ ((pwrctrl->reg_apu_infra_req_mask_b & 0x1) << 24) |
+ ((pwrctrl->reg_apu_apsrc_req_mask_b & 0x1) << 25) |
+ ((pwrctrl->reg_apu_vrf18_req_mask_b & 0x1) << 26) |
+ ((pwrctrl->reg_apu_ddren_req_mask_b & 0x1) << 27) |
+ ((pwrctrl->reg_cg_check_srcclkena_mask_b & 0x1) << 28) |
+ ((pwrctrl->reg_cg_check_apsrc_req_mask_b & 0x1) << 29) |
+ ((pwrctrl->reg_cg_check_vrf18_req_mask_b & 0x1) << 30) |
+ ((pwrctrl->reg_cg_check_ddren_req_mask_b & 0x1) << 31));
+
+ /* SPM_SRC3_MASK */
+ mmio_write_32(SPM_SRC3_MASK,
+ ((pwrctrl->reg_dvfsrc_event_trigger_mask_b & 0x1) << 0) |
+ ((pwrctrl->reg_sw2spm_wakeup_mask_b & 0xf) << 1) |
+ ((pwrctrl->reg_adsp2spm_wakeup_mask_b & 0x1) << 5) |
+ ((pwrctrl->reg_sspm2spm_wakeup_mask_b & 0xf) << 6) |
+ ((pwrctrl->reg_scp2spm_wakeup_mask_b & 0x1) << 10) |
+ ((pwrctrl->reg_csyspwrup_ack_mask & 0x1) << 11) |
+ ((pwrctrl->reg_spm_reserved_srcclkena_mask_b & 0x1) << 12) |
+ ((pwrctrl->reg_spm_reserved_infra_req_mask_b & 0x1) << 13) |
+ ((pwrctrl->reg_spm_reserved_apsrc_req_mask_b & 0x1) << 14) |
+ ((pwrctrl->reg_spm_reserved_vrf18_req_mask_b & 0x1) << 15) |
+ ((pwrctrl->reg_spm_reserved_ddren_req_mask_b & 0x1) << 16) |
+ ((pwrctrl->reg_mcupm_srcclkena_mask_b & 0x1) << 17) |
+ ((pwrctrl->reg_mcupm_infra_req_mask_b & 0x1) << 18) |
+ ((pwrctrl->reg_mcupm_apsrc_req_mask_b & 0x1) << 19) |
+ ((pwrctrl->reg_mcupm_vrf18_req_mask_b & 0x1) << 20) |
+ ((pwrctrl->reg_mcupm_ddren_req_mask_b & 0x1) << 21) |
+ ((pwrctrl->reg_msdc0_srcclkena_mask_b & 0x1) << 22) |
+ ((pwrctrl->reg_msdc0_infra_req_mask_b & 0x1) << 23) |
+ ((pwrctrl->reg_msdc0_apsrc_req_mask_b & 0x1) << 24) |
+ ((pwrctrl->reg_msdc0_vrf18_req_mask_b & 0x1) << 25) |
+ ((pwrctrl->reg_msdc0_ddren_req_mask_b & 0x1) << 26) |
+ ((pwrctrl->reg_msdc1_srcclkena_mask_b & 0x1) << 27) |
+ ((pwrctrl->reg_msdc1_infra_req_mask_b & 0x1) << 28) |
+ ((pwrctrl->reg_msdc1_apsrc_req_mask_b & 0x1) << 29) |
+ ((pwrctrl->reg_msdc1_vrf18_req_mask_b & 0x1) << 30) |
+ ((pwrctrl->reg_msdc1_ddren_req_mask_b & 0x1) << 31));
+
+ /* SPM_SRC4_MASK */
+ mmio_write_32(SPM_SRC4_MASK,
+ ((pwrctrl->reg_ccif_event_srcclkena_mask_b & 0xffff) << 0) |
+ ((pwrctrl->reg_bak_psri_srcclkena_mask_b & 0x1) << 16) |
+ ((pwrctrl->reg_bak_psri_infra_req_mask_b & 0x1) << 17) |
+ ((pwrctrl->reg_bak_psri_apsrc_req_mask_b & 0x1) << 18) |
+ ((pwrctrl->reg_bak_psri_vrf18_req_mask_b & 0x1) << 19) |
+ ((pwrctrl->reg_bak_psri_ddren_req_mask_b & 0x1) << 20) |
+ ((pwrctrl->reg_dramc_md32_infra_req_mask_b & 0x3) << 21) |
+ ((pwrctrl->reg_dramc_md32_vrf18_req_mask_b & 0x3) << 23) |
+ ((pwrctrl->reg_conn_srcclkenb2pwrap_mask_b & 0x1) << 25) |
+ ((pwrctrl->reg_dramc_md32_apsrc_req_mask_b & 0x3) << 26));
+
+ /* SPM_SRC5_MASK */
+ mmio_write_32(SPM_SRC5_MASK,
+ ((pwrctrl->reg_mcusys_merge_apsrc_req_mask_b & 0x1ff) << 0) |
+ ((pwrctrl->reg_mcusys_merge_ddren_req_mask_b & 0x1ff) << 9) |
+ ((pwrctrl->reg_afe_srcclkena_mask_b & 0x1) << 18) |
+ ((pwrctrl->reg_afe_infra_req_mask_b & 0x1) << 19) |
+ ((pwrctrl->reg_afe_apsrc_req_mask_b & 0x1) << 20) |
+ ((pwrctrl->reg_afe_vrf18_req_mask_b & 0x1) << 21) |
+ ((pwrctrl->reg_afe_ddren_req_mask_b & 0x1) << 22) |
+ ((pwrctrl->reg_msdc2_srcclkena_mask_b & 0x1) << 23) |
+ ((pwrctrl->reg_msdc2_infra_req_mask_b & 0x1) << 24) |
+ ((pwrctrl->reg_msdc2_apsrc_req_mask_b & 0x1) << 25) |
+ ((pwrctrl->reg_msdc2_vrf18_req_mask_b & 0x1) << 26) |
+ ((pwrctrl->reg_msdc2_ddren_req_mask_b & 0x1) << 27));
+
+ /* SPM_WAKEUP_EVENT_MASK */
+ mmio_write_32(SPM_WAKEUP_EVENT_MASK,
+ ((pwrctrl->reg_wakeup_event_mask & 0xffffffff) << 0));
+
+ /* SPM_WAKEUP_EVENT_EXT_MASK */
+ mmio_write_32(SPM_WAKEUP_EVENT_EXT_MASK,
+ ((pwrctrl->reg_ext_wakeup_event_mask & 0xffffffff) << 0));
+
+ /* SPM_SRC7_MASK */
+ mmio_write_32(SPM_SRC7_MASK,
+ ((pwrctrl->reg_pcie_srcclkena_mask_b & 0x1) << 0) |
+ ((pwrctrl->reg_pcie_infra_req_mask_b & 0x1) << 1) |
+ ((pwrctrl->reg_pcie_apsrc_req_mask_b & 0x1) << 2) |
+ ((pwrctrl->reg_pcie_vrf18_req_mask_b & 0x1) << 3) |
+ ((pwrctrl->reg_pcie_ddren_req_mask_b & 0x1) << 4) |
+ ((pwrctrl->reg_dpmaif_srcclkena_mask_b & 0x1) << 5) |
+ ((pwrctrl->reg_dpmaif_infra_req_mask_b & 0x1) << 6) |
+ ((pwrctrl->reg_dpmaif_apsrc_req_mask_b & 0x1) << 7) |
+ ((pwrctrl->reg_dpmaif_vrf18_req_mask_b & 0x1) << 8) |
+ ((pwrctrl->reg_dpmaif_ddren_req_mask_b & 0x1) << 9));
+ /* Auto-gen End */
+}
+
+void __spm_disable_pcm_timer(void)
+{
+ mmio_clrsetbits_32(PCM_CON1, RG_PCM_TIMER_EN_LSB, SPM_REGWR_CFG_KEY);
+}
+
+
+void __spm_set_wakeup_event(const struct pwr_ctrl *pwrctrl)
+{
+ uint32_t val, mask;
+
+ /* toggle event counter clear */
+ mmio_setbits_32(PCM_CON1,
+ SPM_REGWR_CFG_KEY | REG_SPM_EVENT_COUNTER_CLR_LSB);
+
+ /* toggle for reset SYS TIMER start point */
+ mmio_setbits_32(SYS_TIMER_CON, SYS_TIMER_START_EN_LSB);
+
+ if (pwrctrl->timer_val_cust == 0U) {
+ val = pwrctrl->timer_val ? (pwrctrl->timer_val) : (PCM_TIMER_MAX);
+ } else {
+ val = pwrctrl->timer_val_cust;
+ }
+
+ mmio_write_32(PCM_TIMER_VAL, val);
+ mmio_setbits_32(PCM_CON1, (SPM_REGWR_CFG_KEY | RG_PCM_TIMER_EN_LSB));
+
+ /* unmask AP wakeup source */
+ if (pwrctrl->wake_src_cust == 0U) {
+ mask = pwrctrl->wake_src;
+ } else {
+ mask = pwrctrl->wake_src_cust;
+ }
+
+ if (pwrctrl->reg_csyspwrup_ack_mask != 0U) {
+ mask &= ~R12_CSYSPWREQ_B;
+ }
+
+ mmio_write_32(SPM_WAKEUP_EVENT_MASK, ~mask);
+
+ /* unmask SPM ISR (keep TWAM setting) */
+ mmio_setbits_32(SPM_IRQ_MASK, ISRM_RET_IRQ_AUX);
+
+ /* toggle event counter clear */
+ mmio_clrsetbits_32(PCM_CON1, REG_SPM_EVENT_COUNTER_CLR_LSB,
+ SPM_REGWR_CFG_KEY);
+ /* toggle for reset SYS TIMER start point */
+ mmio_clrbits_32(SYS_TIMER_CON, SYS_TIMER_START_EN_LSB);
+}
+
+void __spm_set_pcm_flags(struct pwr_ctrl *pwrctrl)
+{
+ /* set PCM flags and data */
+ if (pwrctrl->pcm_flags_cust_clr != 0U) {
+ pwrctrl->pcm_flags &= ~pwrctrl->pcm_flags_cust_clr;
+ }
+
+ if (pwrctrl->pcm_flags_cust_set != 0U) {
+ pwrctrl->pcm_flags |= pwrctrl->pcm_flags_cust_set;
+ }
+
+ if (pwrctrl->pcm_flags1_cust_clr != 0U) {
+ pwrctrl->pcm_flags1 &= ~pwrctrl->pcm_flags1_cust_clr;
+ }
+
+ if (pwrctrl->pcm_flags1_cust_set != 0U) {
+ pwrctrl->pcm_flags1 |= pwrctrl->pcm_flags1_cust_set;
+ }
+
+ mmio_write_32(SPM_SW_FLAG_0, pwrctrl->pcm_flags);
+
+ mmio_write_32(SPM_SW_FLAG_1, pwrctrl->pcm_flags1);
+
+ mmio_write_32(SPM_SW_RSV_7, pwrctrl->pcm_flags);
+
+ mmio_write_32(SPM_SW_RSV_8, pwrctrl->pcm_flags1);
+}
+
+void __spm_get_wakeup_status(struct wake_status *wakesta,
+ unsigned int ext_status)
+{
+ wakesta->tr.comm.r12 = mmio_read_32(SPM_BK_WAKE_EVENT);
+ wakesta->tr.comm.timer_out = mmio_read_32(SPM_BK_PCM_TIMER);
+ wakesta->tr.comm.r13 = mmio_read_32(PCM_REG13_DATA);
+ wakesta->tr.comm.req_sta0 = mmio_read_32(SRC_REQ_STA_0);
+ wakesta->tr.comm.req_sta1 = mmio_read_32(SRC_REQ_STA_1);
+ wakesta->tr.comm.req_sta2 = mmio_read_32(SRC_REQ_STA_2);
+ wakesta->tr.comm.req_sta3 = mmio_read_32(SRC_REQ_STA_3);
+ wakesta->tr.comm.req_sta4 = mmio_read_32(SRC_REQ_STA_4);
+
+ wakesta->tr.comm.debug_flag = mmio_read_32(PCM_WDT_LATCH_SPARE_0);
+ wakesta->tr.comm.debug_flag1 = mmio_read_32(PCM_WDT_LATCH_SPARE_1);
+
+ if ((ext_status & SPM_INTERNAL_STATUS_HW_S1) != 0U) {
+ wakesta->tr.comm.debug_flag |= (SPM_DBG_DEBUG_IDX_DDREN_WAKE |
+ SPM_DBG_DEBUG_IDX_DDREN_SLEEP);
+ mmio_write_32(PCM_WDT_LATCH_SPARE_0, wakesta->tr.comm.debug_flag);
+ }
+
+ wakesta->tr.comm.b_sw_flag0 = mmio_read_32(SPM_SW_RSV_7);
+ wakesta->tr.comm.b_sw_flag1 = mmio_read_32(SPM_SW_RSV_8);
+
+ /* record below spm info for debug */
+ wakesta->r12 = mmio_read_32(SPM_BK_WAKE_EVENT);
+ wakesta->r12_ext = mmio_read_32(SPM_WAKEUP_STA);
+ wakesta->raw_sta = mmio_read_32(SPM_WAKEUP_STA);
+ wakesta->raw_ext_sta = mmio_read_32(SPM_WAKEUP_EXT_STA);
+ wakesta->md32pcm_wakeup_sta = mmio_read_32(MD32PCM_WAKEUP_STA);
+ wakesta->md32pcm_event_sta = mmio_read_32(MD32PCM_EVENT_STA);
+ wakesta->src_req = mmio_read_32(SPM_SRC_REQ);
+
+ /* backup of SPM_WAKEUP_MISC */
+ wakesta->wake_misc = mmio_read_32(SPM_BK_WAKE_MISC);
+
+ /* get sleep time, backup of PCM_TIMER_OUT */
+ wakesta->timer_out = mmio_read_32(SPM_BK_PCM_TIMER);
+
+ /* get other SYS and co-clock status */
+ wakesta->r13 = mmio_read_32(PCM_REG13_DATA);
+ wakesta->idle_sta = mmio_read_32(SUBSYS_IDLE_STA);
+ wakesta->req_sta0 = mmio_read_32(SRC_REQ_STA_0);
+ wakesta->req_sta1 = mmio_read_32(SRC_REQ_STA_1);
+ wakesta->req_sta2 = mmio_read_32(SRC_REQ_STA_2);
+ wakesta->req_sta3 = mmio_read_32(SRC_REQ_STA_3);
+ wakesta->req_sta4 = mmio_read_32(SRC_REQ_STA_4);
+
+ /* get HW CG check status */
+ wakesta->cg_check_sta = mmio_read_32(SPM_CG_CHECK_STA);
+
+ /* get debug flag for PCM execution check */
+ wakesta->debug_flag = mmio_read_32(PCM_WDT_LATCH_SPARE_0);
+ wakesta->debug_flag1 = mmio_read_32(PCM_WDT_LATCH_SPARE_1);
+
+ /* get backup SW flag status */
+ wakesta->b_sw_flag0 = mmio_read_32(SPM_SW_RSV_7);
+ wakesta->b_sw_flag1 = mmio_read_32(SPM_SW_RSV_8);
+
+ wakesta->rt_req_sta0 = mmio_read_32(SPM_SW_RSV_2);
+ wakesta->rt_req_sta1 = mmio_read_32(SPM_SW_RSV_3);
+ wakesta->rt_req_sta2 = mmio_read_32(SPM_SW_RSV_4);
+ wakesta->rt_req_sta3 = mmio_read_32(SPM_SW_RSV_5);
+ wakesta->rt_req_sta4 = mmio_read_32(SPM_SW_RSV_6);
+
+ /* get ISR status */
+ wakesta->isr = mmio_read_32(SPM_IRQ_STA);
+
+ /* get SW flag status */
+ wakesta->sw_flag0 = mmio_read_32(SPM_SW_FLAG_0);
+ wakesta->sw_flag1 = mmio_read_32(SPM_SW_FLAG_1);
+
+ /* get CLK SETTLE */
+ wakesta->clk_settle = mmio_read_32(SPM_CLK_SETTLE);
+
+ /* check abort */
+ wakesta->abort = ((wakesta->debug_flag & DEBUG_ABORT_MASK) |
+ (wakesta->debug_flag1 & DEBUG_ABORT_MASK_1));
+}
+
+void __spm_clean_after_wakeup(void)
+{
+ mmio_write_32(SPM_BK_WAKE_EVENT,
+ (mmio_read_32(SPM_WAKEUP_STA) |
+ mmio_read_32(SPM_BK_WAKE_EVENT)));
+ mmio_write_32(SPM_CPU_WAKEUP_EVENT, 0U);
+
+ /*
+ * clean wakeup event raw status (for edge trigger event)
+ * bit[28] for cpu wake up event
+ */
+ mmio_write_32(SPM_WAKEUP_EVENT_MASK, SPM_WAKEUP_EVENT_MASK_CLEAN_MASK);
+
+ /* clean ISR status (except TWAM) */
+ 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_set_pcm_wdt(int en)
+{
+ mmio_clrsetbits_32(PCM_CON1, RG_PCM_WDT_EN_LSB,
+ SPM_REGWR_CFG_KEY);
+
+ if (en == 1) {
+ mmio_clrsetbits_32(PCM_CON1, RG_PCM_WDT_WAKE_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 | RG_PCM_WDT_EN_LSB);
+ }
+}
+
+void __spm_send_cpu_wakeup_event(void)
+{
+ /* SPM will clear SPM_CPU_WAKEUP_EVENT */
+ mmio_write_32(SPM_CPU_WAKEUP_EVENT, 1);
+}
+
+void __spm_ext_int_wakeup_req_clr(void)
+{
+ unsigned int reg = mmio_read_32(SPM_MD32_IRQ) & (~(0x1U << 0));
+
+ mmio_write_32(EXT_INT_WAKEUP_REQ_CLR, mmio_read_32(ROOT_CPUTOP_ADDR));
+
+ /* Clear spm2mcupm wakeup interrupt status */
+ mmio_write_32(SPM_MD32_IRQ, reg);
+}
+
+void __spm_xo_soc_bblpm(int en)
+{
+ if (en == 1) {
+ mmio_clrsetbits_32(RC_M00_SRCLKEN_CFG,
+ RC_SW_SRCCLKEN_FPM, RC_SW_SRCCLKEN_RC);
+ assert(mt_spm_bblpm_cnt == 0);
+ mt_spm_bblpm_cnt += 1;
+ } else {
+ mmio_clrsetbits_32(RC_M00_SRCLKEN_CFG,
+ RC_SW_SRCCLKEN_RC, RC_SW_SRCCLKEN_FPM);
+ mt_spm_bblpm_cnt -= 1;
+ }
+}
+
+void __spm_hw_s1_state_monitor(int en, unsigned int *status)
+{
+ unsigned int reg = mmio_read_32(SPM_ACK_CHK_CON_3);
+
+ if (en == 1) {
+ reg = mmio_read_32(SPM_ACK_CHK_CON_3);
+ reg &= ~SPM_ACK_CHK_3_CON_CLR_ALL;
+ mmio_write_32(SPM_ACK_CHK_CON_3, reg);
+ reg |= SPM_ACK_CHK_3_CON_EN;
+ mmio_write_32(SPM_ACK_CHK_CON_3, reg);
+ } else {
+ if (((reg & SPM_ACK_CHK_3_CON_RESULT) != 0U) &&
+ (status != NULL)) {
+ *status |= SPM_INTERNAL_STATUS_HW_S1;
+ }
+
+ mmio_clrsetbits_32(SPM_ACK_CHK_CON_3, SPM_ACK_CHK_3_CON_EN,
+ SPM_ACK_CHK_3_CON_HW_MODE_TRIG |
+ SPM_ACK_CHK_3_CON_CLR_ALL);
+ }
+}
+
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_internal.h b/plat/mediatek/mt8186/drivers/spm/mt_spm_internal.h
new file mode 100644
index 0000000..8cf2062
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_internal.h
@@ -0,0 +1,620 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_INTERNAL
+#define MT_SPM_INTERNAL
+
+#include "mt_spm.h"
+
+/* Config and Parameter */
+#define POWER_ON_VAL0_DEF (0x0000F100)
+#define POWER_ON_VAL1_DEF (0x80015860)
+#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 BIT(0)
+#define PCM_PWRIO_EN_R7 BIT(7)
+#define PCM_RF_SYNC_R0 BIT(16)
+#define PCM_RF_SYNC_R6 BIT(22)
+#define PCM_RF_SYNC_R7 BIT(23)
+
+/* SPM_SWINT */
+#define PCM_SW_INT0 BIT(0)
+#define PCM_SW_INT1 BIT(1)
+#define PCM_SW_INT2 BIT(2)
+#define PCM_SW_INT3 BIT(3)
+#define PCM_SW_INT4 BIT(4)
+#define PCM_SW_INT5 BIT(5)
+#define PCM_SW_INT6 BIT(6)
+#define PCM_SW_INT7 BIT(7)
+#define PCM_SW_INT8 BIT(8)
+#define PCM_SW_INT9 BIT(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_AP_STANDBY_CON */
+#define WFI_OP_AND (1U)
+#define WFI_OP_OR (0U)
+
+/* 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 BIT(2)
+#define ISRS_PCM_RETURN BIT(3)
+#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_GIC_WAKEUP (0x3FF)
+#define WAKE_MISC_DVFSRC_IRQ DVFSRC_IRQ_LSB
+#define WAKE_MISC_REG_CPU_WAKEUP SPM_WAKEUP_MISC_REG_CPU_WAKEUP_LSB
+#define WAKE_MISC_PCM_TIMER_EVENT PCM_TIMER_EVENT_LSB
+#define WAKE_MISC_PMIC_OUT_B ((1U << 19) | (1U << 20))
+#define WAKE_MISC_TWAM_IRQ_B TWAM_IRQ_B_LSB
+#define WAKE_MISC_SPM_ACK_CHK_WAKEUP_0 SPM_ACK_CHK_WAKEUP_0_LSB
+#define WAKE_MISC_SPM_ACK_CHK_WAKEUP_1 SPM_ACK_CHK_WAKEUP_1_LSB
+#define WAKE_MISC_SPM_ACK_CHK_WAKEUP_2 SPM_ACK_CHK_WAKEUP_2_LSB
+#define WAKE_MISC_SPM_ACK_CHK_WAKEUP_3 SPM_ACK_CHK_WAKEUP_3_LSB
+#define WAKE_MISC_SPM_ACK_CHK_WAKEUP_ALL SPM_ACK_CHK_WAKEUP_ALL_LSB
+#define WAKE_MISC_PMIC_IRQ_ACK PMIC_IRQ_ACK_LSB
+#define WAKE_MISC_PMIC_SCP_IRQ PMIC_SCP_IRQ_LSB
+
+/* ABORT MASK for DEBUG FOORTPRINT */
+#define DEBUG_ABORT_MASK \
+ (SPM_DBG_DEBUG_IDX_DRAM_SREF_ABORT_IN_APSRC | \
+ SPM_DBG_DEBUG_IDX_DRAM_SREF_ABORT_IN_DDREN)
+
+#define DEBUG_ABORT_MASK_1 \
+ (SPM_DBG1_DEBUG_IDX_VRCXO_SLEEP_ABORT | \
+ SPM_DBG1_DEBUG_IDX_PWRAP_SLEEP_ACK_LOW_ABORT | \
+ SPM_DBG1_DEBUG_IDX_PWRAP_SLEEP_ACK_HIGH_ABORT | \
+ SPM_DBG1_DEBUG_IDX_EMI_SLP_IDLE_ABORT | \
+ SPM_DBG1_DEBUG_IDX_SCP_SLP_ACK_LOW_ABORT | \
+ SPM_DBG1_DEBUG_IDX_SCP_SLP_ACK_HIGH_ABORT | \
+ SPM_DBG1_DEBUG_IDX_SPM_DVFS_CMD_RDY_ABORT)
+
+#define MCUPM_MBOX_WAKEUP_CPU (0x0C55FD10)
+
+struct pwr_ctrl {
+ uint32_t pcm_flags;
+ uint32_t pcm_flags_cust;
+ uint32_t pcm_flags_cust_set;
+ uint32_t pcm_flags_cust_clr;
+ uint32_t pcm_flags1;
+ uint32_t pcm_flags1_cust;
+ uint32_t pcm_flags1_cust_set;
+ uint32_t pcm_flags1_cust_clr;
+ uint32_t timer_val;
+ uint32_t timer_val_cust;
+ uint32_t timer_val_ramp_en;
+ uint32_t timer_val_ramp_en_sec;
+ uint32_t wake_src;
+ uint32_t wake_src_cust;
+ uint32_t wakelock_timer_val;
+ uint8_t wdt_disable;
+
+ /* Auto-gen Start */
+
+ /* SPM_AP_STANDBY_CON */
+ uint8_t reg_wfi_op;
+ uint8_t reg_wfi_type;
+ uint8_t reg_mp0_cputop_idle_mask;
+ uint8_t reg_mp1_cputop_idle_mask;
+ uint8_t reg_mcusys_idle_mask;
+ uint8_t reg_md_apsrc_1_sel;
+ uint8_t reg_md_apsrc_0_sel;
+ uint8_t reg_conn_apsrc_sel;
+
+ /* SPM_SRC6_MASK */
+ uint32_t reg_ccif_event_infra_req_mask_b;
+ uint32_t reg_ccif_event_apsrc_req_mask_b;
+
+ /* SPM_SRC_REQ */
+ uint8_t reg_spm_apsrc_req;
+ uint8_t reg_spm_f26m_req;
+ uint8_t reg_spm_infra_req;
+ uint8_t reg_spm_vrf18_req;
+ uint8_t reg_spm_ddren_req;
+ uint8_t reg_spm_dvfs_req;
+ uint8_t reg_spm_sw_mailbox_req;
+ uint8_t reg_spm_sspm_mailbox_req;
+ uint8_t reg_spm_adsp_mailbox_req;
+ uint8_t reg_spm_scp_mailbox_req;
+
+ /* SPM_SRC_MASK */
+ uint8_t reg_md_0_srcclkena_mask_b;
+ uint8_t reg_md_0_infra_req_mask_b;
+ uint8_t reg_md_0_apsrc_req_mask_b;
+ uint8_t reg_md_0_vrf18_req_mask_b;
+ uint8_t reg_md_0_ddren_req_mask_b;
+ uint8_t reg_md_1_srcclkena_mask_b;
+ uint8_t reg_md_1_infra_req_mask_b;
+ uint8_t reg_md_1_apsrc_req_mask_b;
+ uint8_t reg_md_1_vrf18_req_mask_b;
+ uint8_t reg_md_1_ddren_req_mask_b;
+ uint8_t reg_conn_srcclkena_mask_b;
+ uint8_t reg_conn_srcclkenb_mask_b;
+ uint8_t reg_conn_infra_req_mask_b;
+ uint8_t reg_conn_apsrc_req_mask_b;
+ uint8_t reg_conn_vrf18_req_mask_b;
+ uint8_t reg_conn_ddren_req_mask_b;
+ uint8_t reg_conn_vfe28_mask_b;
+ uint8_t reg_srcclkeni_srcclkena_mask_b;
+ uint8_t reg_srcclkeni_infra_req_mask_b;
+ uint8_t reg_infrasys_apsrc_req_mask_b;
+ uint8_t reg_infrasys_ddren_req_mask_b;
+ uint8_t reg_sspm_srcclkena_mask_b;
+ uint8_t reg_sspm_infra_req_mask_b;
+ uint8_t reg_sspm_apsrc_req_mask_b;
+ uint8_t reg_sspm_vrf18_req_mask_b;
+ uint8_t reg_sspm_ddren_req_mask_b;
+
+ /* SPM_SRC2_MASK */
+ uint8_t reg_scp_srcclkena_mask_b;
+ uint8_t reg_scp_infra_req_mask_b;
+ uint8_t reg_scp_apsrc_req_mask_b;
+ uint8_t reg_scp_vrf18_req_mask_b;
+ uint8_t reg_scp_ddren_req_mask_b;
+ uint8_t reg_audio_dsp_srcclkena_mask_b;
+ uint8_t reg_audio_dsp_infra_req_mask_b;
+ uint8_t reg_audio_dsp_apsrc_req_mask_b;
+ uint8_t reg_audio_dsp_vrf18_req_mask_b;
+ uint8_t reg_audio_dsp_ddren_req_mask_b;
+ uint8_t reg_ufs_srcclkena_mask_b;
+ uint8_t reg_ufs_infra_req_mask_b;
+ uint8_t reg_ufs_apsrc_req_mask_b;
+ uint8_t reg_ufs_vrf18_req_mask_b;
+ uint8_t reg_ufs_ddren_req_mask_b;
+ uint8_t reg_disp0_apsrc_req_mask_b;
+ uint8_t reg_disp0_ddren_req_mask_b;
+ uint8_t reg_disp1_apsrc_req_mask_b;
+ uint8_t reg_disp1_ddren_req_mask_b;
+ uint8_t reg_gce_infra_req_mask_b;
+ uint8_t reg_gce_apsrc_req_mask_b;
+ uint8_t reg_gce_vrf18_req_mask_b;
+ uint8_t reg_gce_ddren_req_mask_b;
+ uint8_t reg_apu_srcclkena_mask_b;
+ uint8_t reg_apu_infra_req_mask_b;
+ uint8_t reg_apu_apsrc_req_mask_b;
+ uint8_t reg_apu_vrf18_req_mask_b;
+ uint8_t reg_apu_ddren_req_mask_b;
+ uint8_t reg_cg_check_srcclkena_mask_b;
+ uint8_t reg_cg_check_apsrc_req_mask_b;
+ uint8_t reg_cg_check_vrf18_req_mask_b;
+ uint8_t reg_cg_check_ddren_req_mask_b;
+
+ /* SPM_SRC3_MASK */
+ uint8_t reg_dvfsrc_event_trigger_mask_b;
+ uint8_t reg_sw2spm_wakeup_mask_b;
+ uint8_t reg_adsp2spm_wakeup_mask_b;
+ uint8_t reg_sspm2spm_wakeup_mask_b;
+ uint8_t reg_scp2spm_wakeup_mask_b;
+ uint8_t reg_csyspwrup_ack_mask;
+ uint8_t reg_spm_reserved_srcclkena_mask_b;
+ uint8_t reg_spm_reserved_infra_req_mask_b;
+ uint8_t reg_spm_reserved_apsrc_req_mask_b;
+ uint8_t reg_spm_reserved_vrf18_req_mask_b;
+ uint8_t reg_spm_reserved_ddren_req_mask_b;
+ uint8_t reg_mcupm_srcclkena_mask_b;
+ uint8_t reg_mcupm_infra_req_mask_b;
+ uint8_t reg_mcupm_apsrc_req_mask_b;
+ uint8_t reg_mcupm_vrf18_req_mask_b;
+ uint8_t reg_mcupm_ddren_req_mask_b;
+ uint8_t reg_msdc0_srcclkena_mask_b;
+ uint8_t reg_msdc0_infra_req_mask_b;
+ uint8_t reg_msdc0_apsrc_req_mask_b;
+ uint8_t reg_msdc0_vrf18_req_mask_b;
+ uint8_t reg_msdc0_ddren_req_mask_b;
+ uint8_t reg_msdc1_srcclkena_mask_b;
+ uint8_t reg_msdc1_infra_req_mask_b;
+ uint8_t reg_msdc1_apsrc_req_mask_b;
+ uint8_t reg_msdc1_vrf18_req_mask_b;
+ uint8_t reg_msdc1_ddren_req_mask_b;
+
+ /* SPM_SRC4_MASK */
+ uint32_t reg_ccif_event_srcclkena_mask_b;
+ uint8_t reg_bak_psri_srcclkena_mask_b;
+ uint8_t reg_bak_psri_infra_req_mask_b;
+ uint8_t reg_bak_psri_apsrc_req_mask_b;
+ uint8_t reg_bak_psri_vrf18_req_mask_b;
+ uint8_t reg_bak_psri_ddren_req_mask_b;
+ uint8_t reg_dramc_md32_infra_req_mask_b;
+ uint8_t reg_dramc_md32_vrf18_req_mask_b;
+ uint8_t reg_conn_srcclkenb2pwrap_mask_b;
+ uint8_t reg_dramc_md32_apsrc_req_mask_b;
+
+ /* SPM_SRC5_MASK */
+ uint32_t reg_mcusys_merge_apsrc_req_mask_b;
+ uint32_t reg_mcusys_merge_ddren_req_mask_b;
+ uint8_t reg_afe_srcclkena_mask_b;
+ uint8_t reg_afe_infra_req_mask_b;
+ uint8_t reg_afe_apsrc_req_mask_b;
+ uint8_t reg_afe_vrf18_req_mask_b;
+ uint8_t reg_afe_ddren_req_mask_b;
+ uint8_t reg_msdc2_srcclkena_mask_b;
+ uint8_t reg_msdc2_infra_req_mask_b;
+ uint8_t reg_msdc2_apsrc_req_mask_b;
+ uint8_t reg_msdc2_vrf18_req_mask_b;
+ uint8_t reg_msdc2_ddren_req_mask_b;
+
+ /* SPM_WAKEUP_EVENT_MASK */
+ uint32_t reg_wakeup_event_mask;
+
+ /* SPM_WAKEUP_EVENT_EXT_MASK */
+ uint32_t reg_ext_wakeup_event_mask;
+
+ /* SPM_SRC7_MASK */
+ uint8_t reg_pcie_srcclkena_mask_b;
+ uint8_t reg_pcie_infra_req_mask_b;
+ uint8_t reg_pcie_apsrc_req_mask_b;
+ uint8_t reg_pcie_vrf18_req_mask_b;
+ uint8_t reg_pcie_ddren_req_mask_b;
+ uint8_t reg_dpmaif_srcclkena_mask_b;
+ uint8_t reg_dpmaif_infra_req_mask_b;
+ uint8_t reg_dpmaif_apsrc_req_mask_b;
+ uint8_t reg_dpmaif_vrf18_req_mask_b;
+ uint8_t reg_dpmaif_ddren_req_mask_b;
+
+ /* Auto-gen End */
+};
+
+/* code gen by spm_pwr_ctrl_atf.pl, need struct pwr_ctrl */
+enum pwr_ctrl_enum {
+ PW_PCM_FLAGS,
+ PW_PCM_FLAGS_CUST,
+ PW_PCM_FLAGS_CUST_SET,
+ PW_PCM_FLAGS_CUST_CLR,
+ PW_PCM_FLAGS1,
+ PW_PCM_FLAGS1_CUST,
+ PW_PCM_FLAGS1_CUST_SET,
+ PW_PCM_FLAGS1_CUST_CLR,
+ PW_TIMER_VAL,
+ PW_TIMER_VAL_CUST,
+ PW_TIMER_VAL_RAMP_EN,
+ PW_TIMER_VAL_RAMP_EN_SEC,
+ PW_WAKE_SRC,
+ PW_WAKE_SRC_CUST,
+ PW_WAKELOCK_TIMER_VAL,
+ PW_WDT_DISABLE,
+
+ /* SPM_AP_STANDBY_CON */
+ PW_REG_WFI_OP,
+ PW_REG_WFI_TYPE,
+ PW_REG_MP0_CPUTOP_IDLE_MASK,
+ PW_REG_MP1_CPUTOP_IDLE_MASK,
+ PW_REG_MCUSYS_IDLE_MASK,
+ PW_REG_MD_APSRC_1_SEL,
+ PW_REG_MD_APSRC_0_SEL,
+ PW_REG_CONN_APSRC_SEL,
+
+ /* SPM_SRC6_MASK */
+ PW_REG_CCIF_EVENT_INFRA_REQ_MASK_B,
+ PW_REG_CCIF_EVENT_APSRC_REQ_MASK_B,
+
+ /* SPM_WAKEUP_EVENT_SENS */
+ PW_REG_WAKEUP_EVENT_SENS,
+
+ /* SPM_SRC_REQ */
+ PW_REG_SPM_APSRC_REQ,
+ PW_REG_SPM_F26M_REQ,
+ PW_REG_SPM_INFRA_REQ,
+ PW_REG_SPM_VRF18_REQ,
+ PW_REG_SPM_DDREN_REQ,
+ PW_REG_SPM_DVFS_REQ,
+ PW_REG_SPM_SW_MAILBOX_REQ,
+ PW_REG_SPM_SSPM_MAILBOX_REQ,
+ PW_REG_SPM_ADSP_MAILBOX_REQ,
+ PW_REG_SPM_SCP_MAILBOX_REQ,
+
+ /* SPM_SRC_MASK */
+ PW_REG_MD_0_SRCCLKENA_MASK_B,
+ PW_REG_MD_0_INFRA_REQ_MASK_B,
+ PW_REG_MD_0_APSRC_REQ_MASK_B,
+ PW_REG_MD_0_VRF18_REQ_MASK_B,
+ PW_REG_MD_0_DDREN_REQ_MASK_B,
+ PW_REG_MD_1_SRCCLKENA_MASK_B,
+ PW_REG_MD_1_INFRA_REQ_MASK_B,
+ PW_REG_MD_1_APSRC_REQ_MASK_B,
+ PW_REG_MD_1_VRF18_REQ_MASK_B,
+ PW_REG_MD_1_DDREN_REQ_MASK_B,
+ PW_REG_CONN_SRCCLKENA_MASK_B,
+ PW_REG_CONN_SRCCLKENB_MASK_B,
+ PW_REG_CONN_INFRA_REQ_MASK_B,
+ PW_REG_CONN_APSRC_REQ_MASK_B,
+ PW_REG_CONN_VRF18_REQ_MASK_B,
+ PW_REG_CONN_DDREN_REQ_MASK_B,
+ PW_REG_CONN_VFE28_MASK_B,
+ PW_REG_SRCCLKENI_SRCCLKENA_MASK_B,
+ PW_REG_SRCCLKENI_INFRA_REQ_MASK_B,
+ PW_REG_INFRASYS_APSRC_REQ_MASK_B,
+ PW_REG_INFRASYS_DDREN_REQ_MASK_B,
+ PW_REG_SSPM_SRCCLKENA_MASK_B,
+ PW_REG_SSPM_INFRA_REQ_MASK_B,
+ PW_REG_SSPM_APSRC_REQ_MASK_B,
+ PW_REG_SSPM_VRF18_REQ_MASK_B,
+ PW_REG_SSPM_DDREN_REQ_MASK_B,
+
+ /* SPM_SRC2_MASK */
+ PW_REG_SCP_SRCCLKENA_MASK_B,
+ PW_REG_SCP_INFRA_REQ_MASK_B,
+ PW_REG_SCP_APSRC_REQ_MASK_B,
+ PW_REG_SCP_VRF18_REQ_MASK_B,
+ PW_REG_SCP_DDREN_REQ_MASK_B,
+ PW_REG_AUDIO_DSP_SRCCLKENA_MASK_B,
+ PW_REG_AUDIO_DSP_INFRA_REQ_MASK_B,
+ PW_REG_AUDIO_DSP_APSRC_REQ_MASK_B,
+ PW_REG_AUDIO_DSP_VRF18_REQ_MASK_B,
+ PW_REG_AUDIO_DSP_DDREN_REQ_MASK_B,
+ PW_REG_UFS_SRCCLKENA_MASK_B,
+ PW_REG_UFS_INFRA_REQ_MASK_B,
+ PW_REG_UFS_APSRC_REQ_MASK_B,
+ PW_REG_UFS_VRF18_REQ_MASK_B,
+ PW_REG_UFS_DDREN_REQ_MASK_B,
+ PW_REG_DISP0_APSRC_REQ_MASK_B,
+ PW_REG_DISP0_DDREN_REQ_MASK_B,
+ PW_REG_DISP1_APSRC_REQ_MASK_B,
+ PW_REG_DISP1_DDREN_REQ_MASK_B,
+ PW_REG_GCE_INFRA_REQ_MASK_B,
+ PW_REG_GCE_APSRC_REQ_MASK_B,
+ PW_REG_GCE_VRF18_REQ_MASK_B,
+ PW_REG_GCE_DDREN_REQ_MASK_B,
+ PW_REG_APU_SRCCLKENA_MASK_B,
+ PW_REG_APU_INFRA_REQ_MASK_B,
+ PW_REG_APU_APSRC_REQ_MASK_B,
+ PW_REG_APU_VRF18_REQ_MASK_B,
+ PW_REG_APU_DDREN_REQ_MASK_B,
+ PW_REG_CG_CHECK_SRCCLKENA_MASK_B,
+ PW_REG_CG_CHECK_APSRC_REQ_MASK_B,
+ PW_REG_CG_CHECK_VRF18_REQ_MASK_B,
+ PW_REG_CG_CHECK_DDREN_REQ_MASK_B,
+
+ /* SPM_SRC3_MASK */
+ PW_REG_DVFSRC_EVENT_TRIGGER_MASK_B,
+ PW_REG_SW2SPM_WAKEUP_MASK_B,
+ PW_REG_ADSP2SPM_WAKEUP_MASK_B,
+ PW_REG_SSPM2SPM_WAKEUP_MASK_B,
+ PW_REG_SCP2SPM_WAKEUP_MASK_B,
+ PW_REG_CSYSPWRUP_ACK_MASK,
+ PW_REG_SPM_RESERVED_SRCCLKENA_MASK_B,
+ PW_REG_SPM_RESERVED_INFRA_REQ_MASK_B,
+ PW_REG_SPM_RESERVED_APSRC_REQ_MASK_B,
+ PW_REG_SPM_RESERVED_VRF18_REQ_MASK_B,
+ PW_REG_SPM_RESERVED_DDREN_REQ_MASK_B,
+ PW_REG_MCUPM_SRCCLKENA_MASK_B,
+ PW_REG_MCUPM_INFRA_REQ_MASK_B,
+ PW_REG_MCUPM_APSRC_REQ_MASK_B,
+ PW_REG_MCUPM_VRF18_REQ_MASK_B,
+ PW_REG_MCUPM_DDREN_REQ_MASK_B,
+ PW_REG_MSDC0_SRCCLKENA_MASK_B,
+ PW_REG_MSDC0_INFRA_REQ_MASK_B,
+ PW_REG_MSDC0_APSRC_REQ_MASK_B,
+ PW_REG_MSDC0_VRF18_REQ_MASK_B,
+ PW_REG_MSDC0_DDREN_REQ_MASK_B,
+ PW_REG_MSDC1_SRCCLKENA_MASK_B,
+ PW_REG_MSDC1_INFRA_REQ_MASK_B,
+ PW_REG_MSDC1_APSRC_REQ_MASK_B,
+ PW_REG_MSDC1_VRF18_REQ_MASK_B,
+ PW_REG_MSDC1_DDREN_REQ_MASK_B,
+
+ /* SPM_SRC4_MASK */
+ PW_REG_CCIF_EVENT_SRCCLKENA_MASK_B,
+ PW_REG_BAK_PSRI_SRCCLKENA_MASK_B,
+ PW_REG_BAK_PSRI_INFRA_REQ_MASK_B,
+ PW_REG_BAK_PSRI_APSRC_REQ_MASK_B,
+ PW_REG_BAK_PSRI_VRF18_REQ_MASK_B,
+ PW_REG_BAK_PSRI_DDREN_REQ_MASK_B,
+ PW_REG_DRAMC_MD32_INFRA_REQ_MASK_B,
+ PW_REG_DRAMC_MD32_VRF18_REQ_MASK_B,
+ PW_REG_CONN_SRCCLKENB2PWRAP_MASK_B,
+ PW_REG_DRAMC_MD32_APSRC_REQ_MASK_B,
+
+ /* SPM_SRC5_MASK */
+ PW_REG_MCUSYS_MERGE_APSRC_REQ_MASK_B,
+ PW_REG_MCUSYS_MERGE_DDREN_REQ_MASK_B,
+ PW_REG_AFE_SRCCLKENA_MASK_B,
+ PW_REG_AFE_INFRA_REQ_MASK_B,
+ PW_REG_AFE_APSRC_REQ_MASK_B,
+ PW_REG_AFE_VRF18_REQ_MASK_B,
+ PW_REG_AFE_DDREN_REQ_MASK_B,
+ PW_REG_MSDC2_SRCCLKENA_MASK_B,
+ PW_REG_MSDC2_INFRA_REQ_MASK_B,
+ PW_REG_MSDC2_APSRC_REQ_MASK_B,
+ PW_REG_MSDC2_VRF18_REQ_MASK_B,
+ PW_REG_MSDC2_DDREN_REQ_MASK_B,
+
+ /* SPM_WAKEUP_EVENT_MASK */
+ PW_REG_WAKEUP_EVENT_MASK,
+
+ /* SPM_WAKEUP_EVENT_EXT_MASK */
+ PW_REG_EXT_WAKEUP_EVENT_MASK,
+
+ /* SPM_SRC7_MASK */
+ PW_REG_PCIE_SRCCLKENA_MASK_B,
+ PW_REG_PCIE_INFRA_REQ_MASK_B,
+ PW_REG_PCIE_APSRC_REQ_MASK_B,
+ PW_REG_PCIE_VRF18_REQ_MASK_B,
+ PW_REG_PCIE_DDREN_REQ_MASK_B,
+ PW_REG_DPMAIF_SRCCLKENA_MASK_B,
+ PW_REG_DPMAIF_INFRA_REQ_MASK_B,
+ PW_REG_DPMAIF_APSRC_REQ_MASK_B,
+ PW_REG_DPMAIF_VRF18_REQ_MASK_B,
+ PW_REG_DPMAIF_DDREN_REQ_MASK_B,
+
+ PW_MAX_COUNT,
+};
+
+/*
+ * ACK HW MODE SETTING
+ * 0: trigger(1)
+ * 1: trigger(0)
+ * 2: trigger(1) and target(0)
+ * 3: trigger(0) and target(1)
+ * 4: trigger(1) and target(1)
+ * 5: trigger(0) and target(0)
+ */
+#define TRIG_H_TAR_L (2U)
+#define TRIG_L_TAR_H (3U)
+#define TRIG_H_TAR_H (4U)
+#define TRIG_L_TAR_L (5U)
+
+#define SPM_INTERNAL_STATUS_HW_S1 (1U << 0)
+#define SPM_ACK_CHK_3_SEL_HW_S1 (0x00350098)
+#define SPM_ACK_CHK_3_HW_S1_CNT (1U)
+#define SPM_ACK_CHK_3_CON_HW_MODE_TRIG (TRIG_L_TAR_H << 9u)
+#define SPM_ACK_CHK_3_CON_EN (0x110)
+#define SPM_ACK_CHK_3_CON_CLR_ALL (0x2)
+#define SPM_ACK_CHK_3_CON_RESULT (0x8000)
+
+struct wake_status_trace_comm {
+ uint32_t debug_flag; /* PCM_WDT_LATCH_SPARE_0 */
+ uint32_t debug_flag1; /* PCM_WDT_LATCH_SPARE_1 */
+ uint32_t timer_out; /* SPM_SW_RSV_6*/
+ uint32_t b_sw_flag0; /* SPM_SW_RSV_7 */
+ uint32_t b_sw_flag1; /* SPM_SW_RSV_7 */
+ uint32_t r12; /* SPM_SW_RSV_0 */
+ uint32_t r13; /* PCM_REG13_DATA */
+ uint32_t req_sta0; /* SRC_REQ_STA_0 */
+ uint32_t req_sta1; /* SRC_REQ_STA_1 */
+ uint32_t req_sta2; /* SRC_REQ_STA_2 */
+ uint32_t req_sta3; /* SRC_REQ_STA_3 */
+ uint32_t req_sta4; /* SRC_REQ_STA_4 */
+ uint32_t raw_sta; /* SPM_WAKEUP_STA */
+ uint32_t times_h; /* timestamp high bits */
+ uint32_t times_l; /* timestamp low bits */
+ uint32_t resumetime; /* timestamp low bits */
+};
+
+struct wake_status_trace {
+ struct wake_status_trace_comm comm;
+};
+
+struct wake_status {
+ struct wake_status_trace tr;
+ uint32_t r12; /* SPM_BK_WAKE_EVENT */
+ uint32_t r12_ext; /* SPM_WAKEUP_EXT_STA */
+ uint32_t raw_sta; /* SPM_WAKEUP_STA */
+ uint32_t raw_ext_sta; /* SPM_WAKEUP_EXT_STA */
+ uint32_t md32pcm_wakeup_sta; /* MD32CPM_WAKEUP_STA */
+ uint32_t md32pcm_event_sta; /* MD32PCM_EVENT_STA */
+ uint32_t wake_misc; /* SPM_BK_WAKE_MISC */
+ uint32_t timer_out; /* SPM_BK_PCM_TIMER */
+ uint32_t r13; /* PCM_REG13_DATA */
+ uint32_t idle_sta; /* SUBSYS_IDLE_STA */
+ uint32_t req_sta0; /* SRC_REQ_STA_0 */
+ uint32_t req_sta1; /* SRC_REQ_STA_1 */
+ uint32_t req_sta2; /* SRC_REQ_STA_2 */
+ uint32_t req_sta3; /* SRC_REQ_STA_3 */
+ uint32_t req_sta4; /* SRC_REQ_STA_4 */
+ uint32_t cg_check_sta; /* SPM_CG_CHECK_STA */
+ uint32_t debug_flag; /* PCM_WDT_LATCH_SPARE_0 */
+ uint32_t debug_flag1; /* PCM_WDT_LATCH_SPARE_1 */
+ uint32_t b_sw_flag0; /* SPM_SW_RSV_7 */
+ uint32_t b_sw_flag1; /* SPM_SW_RSV_8 */
+ uint32_t isr; /* SPM_IRQ_STA */
+ uint32_t sw_flag0; /* SPM_SW_FLAG_0 */
+ uint32_t sw_flag1; /* SPM_SW_FLAG_1 */
+ uint32_t clk_settle; /* SPM_CLK_SETTLE */
+ uint32_t src_req; /* SPM_SRC_REQ */
+ uint32_t log_index;
+ uint32_t abort;
+ uint32_t rt_req_sta0; /* SPM_SW_RSV_2 */
+ uint32_t rt_req_sta1; /* SPM_SW_RSV_3 */
+ uint32_t rt_req_sta2; /* SPM_SW_RSV_4 */
+ uint32_t rt_req_sta3; /* SPM_SW_RSV_5 */
+ uint32_t rt_req_sta4; /* SPM_SW_RSV_6 */
+ uint32_t mcupm_req_sta;
+};
+
+struct spm_lp_scen {
+ struct pcm_desc *pcmdesc;
+ struct pwr_ctrl *pwrctrl;
+};
+
+extern struct spm_lp_scen __spm_vcorefs;
+
+extern void __spm_set_cpu_status(unsigned int cpu);
+extern void __spm_reset_and_init_pcm(const struct pcm_desc *pcmdesc);
+extern void __spm_kick_im_to_fetch(const struct pcm_desc *pcmdesc);
+extern void __spm_init_pcm_register(void);
+extern void __spm_src_req_update(const struct pwr_ctrl *pwrctrl,
+ unsigned int resource_usage);
+extern void __spm_set_power_control(const struct pwr_ctrl *pwrctrl);
+extern void __spm_disable_pcm_timer(void);
+extern void __spm_set_wakeup_event(const struct pwr_ctrl *pwrctrl);
+extern void __spm_kick_pcm_to_run(struct pwr_ctrl *pwrctrl);
+extern void __spm_set_pcm_flags(struct pwr_ctrl *pwrctrl);
+extern void __spm_send_cpu_wakeup_event(void);
+
+extern void __spm_get_wakeup_status(struct wake_status *wakesta,
+ unsigned int ext_status);
+extern void __spm_clean_after_wakeup(void);
+extern wake_reason_t __spm_output_wake_reason(int state_id,
+ const struct wake_status *wakesta);
+extern void __spm_sync_vcore_dvfs_power_control(struct pwr_ctrl *dest_pwr_ctrl,
+ const struct pwr_ctrl *src_pwr_ctrl);
+extern void __spm_set_pcm_wdt(int en);
+extern uint32_t _spm_get_wake_period(int pwake_time, wake_reason_t last_wr);
+extern void __spm_set_fw_resume_option(struct pwr_ctrl *pwrctrl);
+extern void __spm_ext_int_wakeup_req_clr(void);
+extern void __spm_xo_soc_bblpm(int en);
+
+static inline void set_pwrctrl_pcm_flags(struct pwr_ctrl *pwrctrl,
+ uint32_t flags)
+{
+ if (pwrctrl->pcm_flags_cust == 0U) {
+ pwrctrl->pcm_flags = flags;
+ } else {
+ pwrctrl->pcm_flags = pwrctrl->pcm_flags_cust;
+ }
+}
+
+static inline void set_pwrctrl_pcm_flags1(struct pwr_ctrl *pwrctrl,
+ uint32_t flags)
+{
+ if (pwrctrl->pcm_flags1_cust == 0U) {
+ pwrctrl->pcm_flags1 = flags;
+ } else {
+ pwrctrl->pcm_flags1 = pwrctrl->pcm_flags1_cust;
+ }
+}
+
+extern void __spm_hw_s1_state_monitor(int en, unsigned int *status);
+
+static inline void spm_hw_s1_state_monitor_resume(void)
+{
+ __spm_hw_s1_state_monitor(1, NULL);
+}
+
+static inline void spm_hw_s1_state_monitor_pause(unsigned int *status)
+{
+ __spm_hw_s1_state_monitor(0, status);
+}
+
+#endif /* MT_SPM_INTERNAL_H */
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_pmic_wrap.c b/plat/mediatek/mt8186/drivers/spm/mt_spm_pmic_wrap.c
new file mode 100644
index 0000000..c0000ed
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_pmic_wrap.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mt_spm.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_pmic_wrap.h>
+#include <mt_spm_reg.h>
+#include <plat_pm.h>
+#include <platform_def.h>
+#include <pmic.h>
+
+/* PMIC_WRAP MT6359 */
+#define NR_PMIC_WRAP_CMD (NR_IDX_ALL)
+#define SPM_DATA_SHIFT (16U)
+
+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];
+};
+
+struct set_vsram {
+ unsigned long cmd_addr;
+ unsigned long cmd_wdata;
+};
+
+/* MT6366 */
+#define VOLT_TO_PMIC_VAL_66(volt) (((volt) - 50000 + 625 - 1) / 625)
+#define BUCK_VCORE_ELR0_66 (0x14AA)
+#define TOP_SPI_CON0_66 (0x44C)
+
+static struct pmic_wrap_setting pw66 = {
+ .phase = NR_PMIC_WRAP_PHASE, /* invalid setting for init */
+ .addr = { {0UL, 0UL} },
+ .set[PMIC_WRAP_PHASE_ALLINONE] = {
+ ._[CMD_0] = { BUCK_VCORE_ELR0_66, VOLT_TO_PMIC_VAL_66(80000), },
+ ._[CMD_1] = { BUCK_VCORE_ELR0_66, VOLT_TO_PMIC_VAL_66(80000), },
+ ._[CMD_2] = { BUCK_VCORE_ELR0_66, VOLT_TO_PMIC_VAL_66(80000), },
+ ._[CMD_3] = { BUCK_VCORE_ELR0_66, VOLT_TO_PMIC_VAL_66(80000), },
+ ._[CMD_4] = { BUCK_VCORE_ELR0_66, VOLT_TO_PMIC_VAL_66(80000), },
+ ._[CMD_5] = { TOP_SPI_CON0_66, 0x1, },
+ ._[CMD_6] = { TOP_SPI_CON0_66, 0x0, },
+ .nr_idx = NR_IDX_ALL,
+ },
+};
+
+/* MT6357 */
+#define VOLT_TO_PMIC_VAL_57(volt) (((volt) - 51875 + 625 - 1) / 625)
+#define BUCK_VCORE_ELR0_57 (0x152A)
+#define TOP_SPI_CON0_57 (0x448)
+
+static struct pmic_wrap_setting pw57 = {
+ .phase = NR_PMIC_WRAP_PHASE, /* invalid setting for init */
+ .addr = { {0UL, 0UL} },
+ .set[PMIC_WRAP_PHASE_ALLINONE] = {
+ ._[CMD_0] = { BUCK_VCORE_ELR0_57, VOLT_TO_PMIC_VAL_57(80000), },
+ ._[CMD_1] = { BUCK_VCORE_ELR0_57, VOLT_TO_PMIC_VAL_57(75000), },
+ ._[CMD_2] = { BUCK_VCORE_ELR0_57, VOLT_TO_PMIC_VAL_57(70000), },
+ ._[CMD_3] = { BUCK_VCORE_ELR0_57, VOLT_TO_PMIC_VAL_57(65000), },
+ ._[CMD_4] = { BUCK_VCORE_ELR0_57, VOLT_TO_PMIC_VAL_57(62500), },
+ ._[CMD_5] = { TOP_SPI_CON0_57, 0x1, },
+ ._[CMD_6] = { TOP_SPI_CON0_57, 0x0, },
+ .nr_idx = NR_IDX_ALL,
+ },
+};
+
+static struct pmic_wrap_setting *pw;
+
+#define IS_PMIC_57() ((pmic_get_hwcid() >> 8) == 0x57)
+
+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, },
+ };
+
+ if (IS_PMIC_57()) {
+ pw = &pw57;
+ } else {
+ pw = &pw66;
+ }
+
+ 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) {
+ if (pw == NULL || pw->addr[0].cmd_addr == 0) {
+ _mt_spm_pmic_table_init();
+ }
+
+ if (pw->phase != phase) {
+ pw->phase = phase;
+
+ mmio_write_32(POWERON_CONFIG_EN, SPM_REGWR_CFG_KEY | 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 (pw == NULL || 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);
+ 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)
+{
+ uint64_t ret = 0UL;
+
+ if ((phase < NR_PMIC_WRAP_PHASE) &&
+ (pw != NULL && idx < pw->set[phase].nr_idx)) {
+ ret = pw->set[phase]._[idx].cmd_wdata;
+ }
+
+ return ret;
+}
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_pmic_wrap.h b/plat/mediatek/mt8186/drivers/spm/mt_spm_pmic_wrap.h
new file mode 100644
index 0000000..219b8d3
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_pmic_wrap.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/****************************************************************
+ * Auto generated by DE, please DO NOT modify this file directly.
+ *****************************************************************/
+#ifndef MT_SPM_PMIC_WRAP_H
+#define MT_SPM_PMIC_WRAP_H
+
+enum pmic_wrap_phase_id {
+ PMIC_WRAP_PHASE_ALLINONE = 0U,
+ NR_PMIC_WRAP_PHASE = 1U,
+};
+
+/* IDX mapping, PMIC_WRAP_PHASE_ALLINONE */
+enum {
+ CMD_0 = 0U, /* 0x0 */
+ CMD_1 = 1U, /* 0x1 */
+ CMD_2 = 2U, /* 0x2 */
+ CMD_3 = 3U, /* 0x3 */
+ CMD_4 = 4U, /* 0x4 */
+ CMD_5 = 5U, /* 0x5 */
+ CMD_6 = 6U, /* 0x6 */
+ CMD_7 = 7U, /* 0x7 */
+ CMD_8 = 8U, /* 0x8 */
+ NR_IDX_ALL = 9U,
+};
+
+/* APIs */
+extern void mt_spm_pmic_wrap_set_phase(enum pmic_wrap_phase_id phase);
+extern void mt_spm_pmic_wrap_set_cmd(enum pmic_wrap_phase_id phase,
+ uint32_t idx, uint32_t cmd_wdata);
+extern uint64_t mt_spm_pmic_wrap_get_cmd(enum pmic_wrap_phase_id phase,
+ uint32_t idx);
+
+#endif /* MT_SPM_PMIC_WRAP_H */
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_reg.h b/plat/mediatek/mt8186/drivers/spm/mt_spm_reg.h
new file mode 100644
index 0000000..f85ee3b
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_reg.h
@@ -0,0 +1,2957 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_REG
+#define MT_SPM_REG
+
+#include "pcm_def.h"
+#include <platform_def.h>
+#include "sleep_def.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 SPM_POWER_ON_VAL2 (SPM_BASE + 0x020)
+#define SPM_POWER_ON_VAL3 (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 SPM_SW_RST_CON (SPM_BASE + 0x040)
+#define SPM_SW_RST_CON_SET (SPM_BASE + 0x044)
+#define SPM_SW_RST_CON_CLR (SPM_BASE + 0x048)
+#define SPM_SRC6_MASK (SPM_BASE + 0x04C)
+#define MD32_CLK_CON (SPM_BASE + 0x084)
+#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_WAKEUP_EVENT_SENS (SPM_BASE + 0x0A0)
+#define SPM_WAKEUP_EVENT_CLEAR (SPM_BASE + 0x0A4)
+#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_SRC3_MASK (SPM_BASE + 0x0C4)
+#define SPM_SRC4_MASK (SPM_BASE + 0x0C8)
+#define SPM_SRC5_MASK (SPM_BASE + 0x0CC)
+#define SPM_WAKEUP_EVENT_MASK (SPM_BASE + 0x0D0)
+#define SPM_WAKEUP_EVENT_EXT_MASK (SPM_BASE + 0x0D4)
+#define SPM_SRC7_MASK (SPM_BASE + 0x0D8)
+#define SCP_CLK_CON (SPM_BASE + 0x0DC)
+#define PCM_DEBUG_CON (SPM_BASE + 0x0E0)
+#define DDREN_DBC_CON (SPM_BASE + 0x0E8)
+#define SPM_RESOURCE_ACK_CON4 (SPM_BASE + 0x0EC)
+#define SPM_RESOURCE_ACK_CON0 (SPM_BASE + 0x0F0)
+#define SPM_RESOURCE_ACK_CON1 (SPM_BASE + 0x0F4)
+#define SPM_RESOURCE_ACK_CON2 (SPM_BASE + 0x0F8)
+#define SPM_RESOURCE_ACK_CON3 (SPM_BASE + 0x0FC)
+#define PCM_REG0_DATA (SPM_BASE + 0x100)
+#define PCM_REG2_DATA (SPM_BASE + 0x104)
+#define PCM_REG6_DATA (SPM_BASE + 0x108)
+#define PCM_REG7_DATA (SPM_BASE + 0x10C)
+#define PCM_REG13_DATA (SPM_BASE + 0x110)
+#define SRC_REQ_STA_0 (SPM_BASE + 0x114)
+#define SRC_REQ_STA_1 (SPM_BASE + 0x118)
+#define SRC_REQ_STA_2 (SPM_BASE + 0x11C)
+#define PCM_TIMER_OUT (SPM_BASE + 0x120)
+#define PCM_WDT_OUT (SPM_BASE + 0x124)
+#define SPM_IRQ_STA (SPM_BASE + 0x128)
+#define SRC_REQ_STA_4 (SPM_BASE + 0x12C)
+#define MD32PCM_WAKEUP_STA (SPM_BASE + 0x130)
+#define MD32PCM_EVENT_STA (SPM_BASE + 0x134)
+#define SPM_WAKEUP_STA (SPM_BASE + 0x138)
+#define SPM_WAKEUP_EXT_STA (SPM_BASE + 0x13C)
+#define SPM_WAKEUP_MISC (SPM_BASE + 0x140)
+#define MM_DVFS_HALT (SPM_BASE + 0x144)
+#define BUS_PROTECT_RDY (SPM_BASE + 0x150)
+#define BUS_PROTECT1_RDY (SPM_BASE + 0x154)
+#define BUS_PROTECT2_RDY (SPM_BASE + 0x158)
+#define BUS_PROTECT3_RDY (SPM_BASE + 0x15C)
+#define SUBSYS_IDLE_STA (SPM_BASE + 0x160)
+#define PCM_STA (SPM_BASE + 0x164)
+#define SRC_REQ_STA_3 (SPM_BASE + 0x168)
+#define PWR_STATUS (SPM_BASE + 0x16C)
+#define PWR_STATUS_2ND (SPM_BASE + 0x170)
+#define CPU_PWR_STATUS (SPM_BASE + 0x174)
+#define OTHER_PWR_STATUS (SPM_BASE + 0x178)
+#define SPM_VTCXO_EVENT_COUNT_STA (SPM_BASE + 0x17C)
+#define SPM_INFRA_EVENT_COUNT_STA (SPM_BASE + 0x180)
+#define SPM_VRF18_EVENT_COUNT_STA (SPM_BASE + 0x184)
+#define SPM_APSRC_EVENT_COUNT_STA (SPM_BASE + 0x188)
+#define SPM_DDREN_EVENT_COUNT_STA (SPM_BASE + 0x18C)
+#define MD32PCM_STA (SPM_BASE + 0x190)
+#define MD32PCM_PC (SPM_BASE + 0x194)
+#define DVFSRC_EVENT_STA (SPM_BASE + 0x1A4)
+#define BUS_PROTECT4_RDY (SPM_BASE + 0x1A8)
+#define BUS_PROTECT5_RDY (SPM_BASE + 0x1AC)
+#define BUS_PROTECT6_RDY (SPM_BASE + 0x1B0)
+#define BUS_PROTECT7_RDY (SPM_BASE + 0x1B4)
+#define BUS_PROTECT8_RDY (SPM_BASE + 0x1B8)
+#define SPM_TWAM_LAST_STA0 (SPM_BASE + 0x1D0)
+#define SPM_TWAM_LAST_STA1 (SPM_BASE + 0x1D4)
+#define SPM_TWAM_LAST_STA2 (SPM_BASE + 0x1D8)
+#define SPM_TWAM_LAST_STA3 (SPM_BASE + 0x1DC)
+#define SPM_TWAM_CURR_STA0 (SPM_BASE + 0x1E0)
+#define SPM_TWAM_CURR_STA1 (SPM_BASE + 0x1E4)
+#define SPM_TWAM_CURR_STA2 (SPM_BASE + 0x1E8)
+#define SPM_TWAM_CURR_STA3 (SPM_BASE + 0x1EC)
+#define SPM_TWAM_TIMER_OUT (SPM_BASE + 0x1F0)
+#define SPM_CG_CHECK_STA (SPM_BASE + 0x1F4)
+#define SPM_DVFS_STA (SPM_BASE + 0x1F8)
+#define SPM_DVFS_OPP_STA (SPM_BASE + 0x1FC)
+#define SPM_MCUSYS_PWR_CON (SPM_BASE + 0x200)
+#define SPM_CPUTOP_PWR_CON (SPM_BASE + 0x204)
+#define SPM_CPU0_PWR_CON (SPM_BASE + 0x208)
+#define SPM_CPU1_PWR_CON (SPM_BASE + 0x20C)
+#define SPM_CPU2_PWR_CON (SPM_BASE + 0x210)
+#define SPM_CPU3_PWR_CON (SPM_BASE + 0x214)
+#define SPM_CPU4_PWR_CON (SPM_BASE + 0x218)
+#define SPM_CPU5_PWR_CON (SPM_BASE + 0x21C)
+#define SPM_CPU6_PWR_CON (SPM_BASE + 0x220)
+#define SPM_CPU7_PWR_CON (SPM_BASE + 0x224)
+#define ARMPLL_CLK_CON (SPM_BASE + 0x22C)
+#define MCUSYS_IDLE_STA (SPM_BASE + 0x230)
+#define GIC_WAKEUP_STA (SPM_BASE + 0x234)
+#define CPU_SPARE_CON (SPM_BASE + 0x238)
+#define CPU_SPARE_CON_SET (SPM_BASE + 0x23C)
+#define CPU_SPARE_CON_CLR (SPM_BASE + 0x240)
+#define ARMPLL_CLK_SEL (SPM_BASE + 0x244)
+#define EXT_INT_WAKEUP_REQ (SPM_BASE + 0x248)
+#define EXT_INT_WAKEUP_REQ_SET (SPM_BASE + 0x24C)
+#define EXT_INT_WAKEUP_REQ_CLR (SPM_BASE + 0x250)
+#define CPU_IRQ_MASK (SPM_BASE + 0x260)
+#define CPU_IRQ_MASK_SET (SPM_BASE + 0x264)
+#define CPU_IRQ_MASK_CLR (SPM_BASE + 0x268)
+#define CPU_WFI_EN (SPM_BASE + 0x280)
+#define CPU_WFI_EN_SET (SPM_BASE + 0x284)
+#define CPU_WFI_EN_CLR (SPM_BASE + 0x288)
+#define ROOT_CPUTOP_ADDR (SPM_BASE + 0x2A0)
+#define ROOT_CORE_ADDR (SPM_BASE + 0x2A4)
+#define SPM2SW_MAILBOX_0 (SPM_BASE + 0x2D0)
+#define SPM2SW_MAILBOX_1 (SPM_BASE + 0x2D4)
+#define SPM2SW_MAILBOX_2 (SPM_BASE + 0x2D8)
+#define SPM2SW_MAILBOX_3 (SPM_BASE + 0x2DC)
+#define SW2SPM_WAKEUP (SPM_BASE + 0x2E0)
+#define SW2SPM_WAKEUP_SET (SPM_BASE + 0x2E4)
+#define SW2SPM_WAKEUP_CLR (SPM_BASE + 0x2E8)
+#define SW2SPM_MAILBOX_0 (SPM_BASE + 0x2EC)
+#define SW2SPM_MAILBOX_1 (SPM_BASE + 0x2F0)
+#define SW2SPM_MAILBOX_2 (SPM_BASE + 0x2F4)
+#define SW2SPM_MAILBOX_3 (SPM_BASE + 0x2F8)
+#define SW2SPM_CFG (SPM_BASE + 0x2FC)
+#define MD1_PWR_CON (SPM_BASE + 0x300)
+#define CONN_PWR_CON (SPM_BASE + 0x304)
+#define MFG0_PWR_CON (SPM_BASE + 0x308)
+#define MFG1_PWR_CON (SPM_BASE + 0x30C)
+#define MFG2_PWR_CON (SPM_BASE + 0x310)
+#define MFG3_PWR_CON (SPM_BASE + 0x314)
+#define MFG4_PWR_CON (SPM_BASE + 0x318)
+#define MFG5_PWR_CON (SPM_BASE + 0x31C)
+#define MFG6_PWR_CON (SPM_BASE + 0x320)
+#define IFR_PWR_CON (SPM_BASE + 0x324)
+#define IFR_SUB_PWR_CON (SPM_BASE + 0x328)
+#define DPY_PWR_CON (SPM_BASE + 0x32C)
+#define DRAMC_MD32_PWR_CON (SPM_BASE + 0x330)
+#define ISP_PWR_CON (SPM_BASE + 0x334)
+#define ISP2_PWR_CON (SPM_BASE + 0x338)
+#define IPE_PWR_CON (SPM_BASE + 0x33C)
+#define VDE_PWR_CON (SPM_BASE + 0x340)
+#define VDE2_PWR_CON (SPM_BASE + 0x344)
+#define VEN_PWR_CON (SPM_BASE + 0x348)
+#define VEN_CORE1_PWR_CON (SPM_BASE + 0x34C)
+#define MDP_PWR_CON (SPM_BASE + 0x350)
+#define DIS_PWR_CON (SPM_BASE + 0x354)
+#define AUDIO_PWR_CON (SPM_BASE + 0x358)
+#define CAM_PWR_CON (SPM_BASE + 0x35C)
+#define CAM_RAWA_PWR_CON (SPM_BASE + 0x360)
+#define CAM_RAWB_PWR_CON (SPM_BASE + 0x364)
+#define CAM_RAWC_PWR_CON (SPM_BASE + 0x368)
+#define SYSRAM_CON (SPM_BASE + 0x36C)
+#define SYSROM_CON (SPM_BASE + 0x370)
+#define SSPM_SRAM_CON (SPM_BASE + 0x374)
+#define SCP_SRAM_CON (SPM_BASE + 0x378)
+#define DPY_SHU_SRAM_CON (SPM_BASE + 0x37C)
+#define UFS_SRAM_CON (SPM_BASE + 0x380)
+#define DEVAPC_IFR_SRAM_CON (SPM_BASE + 0x384)
+#define DEVAPC_SUBIFR_SRAM_CON (SPM_BASE + 0x388)
+#define DEVAPC_ACP_SRAM_CON (SPM_BASE + 0x38C)
+#define USB_SRAM_CON (SPM_BASE + 0x390)
+#define DUMMY_SRAM_CON (SPM_BASE + 0x394)
+#define MD_EXT_BUCK_ISO_CON (SPM_BASE + 0x398)
+#define EXT_BUCK_ISO (SPM_BASE + 0x39C)
+#define DXCC_SRAM_CON (SPM_BASE + 0x3A0)
+#define MSDC_PWR_CON (SPM_BASE + 0x3A4)
+#define DEBUGTOP_SRAM_CON (SPM_BASE + 0x3A8)
+#define DP_TX_PWR_CON (SPM_BASE + 0x3AC)
+#define DPMAIF_SRAM_CON (SPM_BASE + 0x3B0)
+#define DPY_SHU2_SRAM_CON (SPM_BASE + 0x3B4)
+#define DRAMC_MCU2_SRAM_CON (SPM_BASE + 0x3B8)
+#define DRAMC_MCU_SRAM_CON (SPM_BASE + 0x3BC)
+#define MCUPM_PWR_CON (SPM_BASE + 0x3C0)
+#define DPY2_PWR_CON (SPM_BASE + 0x3C4)
+#define SPM_SRAM_CON (SPM_BASE + 0x3C8)
+#define PERI_PWR_CON (SPM_BASE + 0x3D0)
+#define NNA0_PWR_CON (SPM_BASE + 0x3D4)
+#define NNA1_PWR_CON (SPM_BASE + 0x3D8)
+#define NNA2_PWR_CON (SPM_BASE + 0x3DC)
+#define NNA_PWR_CON (SPM_BASE + 0x3E0)
+#define ADSP_PWR_CON (SPM_BASE + 0x3E4)
+#define DPY_SRAM_CON (SPM_BASE + 0x3E8)
+#define SPM_MEM_CK_SEL (SPM_BASE + 0x400)
+#define SPM_BUS_PROTECT_MASK_B (SPM_BASE + 0x404)
+#define SPM_BUS_PROTECT1_MASK_B (SPM_BASE + 0x408)
+#define SPM_BUS_PROTECT2_MASK_B (SPM_BASE + 0x40C)
+#define SPM_BUS_PROTECT3_MASK_B (SPM_BASE + 0x410)
+#define SPM_BUS_PROTECT4_MASK_B (SPM_BASE + 0x414)
+#define SPM_EMI_BW_MODE (SPM_BASE + 0x418)
+#define AP2MD_PEER_WAKEUP (SPM_BASE + 0x41C)
+#define ULPOSC_CON (SPM_BASE + 0x420)
+#define SPM2MM_CON (SPM_BASE + 0x424)
+#define SPM_BUS_PROTECT5_MASK_B (SPM_BASE + 0x428)
+#define SPM2MCUPM_CON (SPM_BASE + 0x42C)
+#define AP_MDSRC_REQ (SPM_BASE + 0x430)
+#define SPM2EMI_ENTER_ULPM (SPM_BASE + 0x434)
+#define SPM2MD_DVFS_CON (SPM_BASE + 0x438)
+#define MD2SPM_DVFS_CON (SPM_BASE + 0x43C)
+#define SPM_BUS_PROTECT6_MASK_B (SPM_BASE + 0x440)
+#define SPM_BUS_PROTECT7_MASK_B (SPM_BASE + 0x444)
+#define SPM_BUS_PROTECT8_MASK_B (SPM_BASE + 0x448)
+#define SPM_PLL_CON (SPM_BASE + 0x44C)
+#define RC_SPM_CTRL (SPM_BASE + 0x450)
+#define SPM_DRAM_MCU_SW_CON_0 (SPM_BASE + 0x454)
+#define SPM_DRAM_MCU_SW_CON_1 (SPM_BASE + 0x458)
+#define SPM_DRAM_MCU_SW_CON_2 (SPM_BASE + 0x45C)
+#define SPM_DRAM_MCU_SW_CON_3 (SPM_BASE + 0x460)
+#define SPM_DRAM_MCU_SW_CON_4 (SPM_BASE + 0x464)
+#define SPM_DRAM_MCU_STA_0 (SPM_BASE + 0x468)
+#define SPM_DRAM_MCU_STA_1 (SPM_BASE + 0x46C)
+#define SPM_DRAM_MCU_STA_2 (SPM_BASE + 0x470)
+#define SPM_DRAM_MCU_SW_SEL_0 (SPM_BASE + 0x474)
+#define RELAY_DVFS_LEVEL (SPM_BASE + 0x478)
+#define DRAMC_DPY_CLK_SW_CON_0 (SPM_BASE + 0x480)
+#define DRAMC_DPY_CLK_SW_CON_1 (SPM_BASE + 0x484)
+#define DRAMC_DPY_CLK_SW_CON_2 (SPM_BASE + 0x488)
+#define DRAMC_DPY_CLK_SW_CON_3 (SPM_BASE + 0x48C)
+#define DRAMC_DPY_CLK_SW_SEL_0 (SPM_BASE + 0x490)
+#define DRAMC_DPY_CLK_SW_SEL_1 (SPM_BASE + 0x494)
+#define DRAMC_DPY_CLK_SW_SEL_2 (SPM_BASE + 0x498)
+#define DRAMC_DPY_CLK_SW_SEL_3 (SPM_BASE + 0x49C)
+#define DRAMC_DPY_CLK_SPM_CON (SPM_BASE + 0x4A0)
+#define SPM_DVFS_LEVEL (SPM_BASE + 0x4A4)
+#define SPM_CIRQ_CON (SPM_BASE + 0x4A8)
+#define SPM_DVFS_MISC (SPM_BASE + 0x4AC)
+#define RG_MODULE_SW_CG_0_MASK_REQ_0 (SPM_BASE + 0x4B4)
+#define RG_MODULE_SW_CG_0_MASK_REQ_1 (SPM_BASE + 0x4B8)
+#define RG_MODULE_SW_CG_0_MASK_REQ_2 (SPM_BASE + 0x4BC)
+#define RG_MODULE_SW_CG_1_MASK_REQ_0 (SPM_BASE + 0x4C0)
+#define RG_MODULE_SW_CG_1_MASK_REQ_1 (SPM_BASE + 0x4C4)
+#define RG_MODULE_SW_CG_1_MASK_REQ_2 (SPM_BASE + 0x4C8)
+#define RG_MODULE_SW_CG_2_MASK_REQ_0 (SPM_BASE + 0x4CC)
+#define RG_MODULE_SW_CG_2_MASK_REQ_1 (SPM_BASE + 0x4D0)
+#define RG_MODULE_SW_CG_2_MASK_REQ_2 (SPM_BASE + 0x4D4)
+#define RG_MODULE_SW_CG_3_MASK_REQ_0 (SPM_BASE + 0x4D8)
+#define RG_MODULE_SW_CG_3_MASK_REQ_1 (SPM_BASE + 0x4DC)
+#define RG_MODULE_SW_CG_3_MASK_REQ_2 (SPM_BASE + 0x4E0)
+#define PWR_STATUS_MASK_REQ_0 (SPM_BASE + 0x4E4)
+#define PWR_STATUS_MASK_REQ_1 (SPM_BASE + 0x4E8)
+#define PWR_STATUS_MASK_REQ_2 (SPM_BASE + 0x4EC)
+#define SPM_CG_CHECK_CON (SPM_BASE + 0x4F0)
+#define SPM_SRC_RDY_STA (SPM_BASE + 0x4F4)
+#define SPM_DVS_DFS_LEVEL (SPM_BASE + 0x4F8)
+#define SPM_FORCE_DVFS (SPM_BASE + 0x4FC)
+#define RC_M00_SRCLKEN_CFG (SPM_BASE + 0x520)
+#define SPM_SW_FLAG_0 (SPM_BASE + 0x600)
+#define SPM_SW_DEBUG_0 (SPM_BASE + 0x604)
+#define SPM_SW_FLAG_1 (SPM_BASE + 0x608)
+#define SPM_SW_DEBUG_1 (SPM_BASE + 0x60C)
+#define SPM_SW_RSV_0 (SPM_BASE + 0x610)
+#define SPM_SW_RSV_1 (SPM_BASE + 0x614)
+#define SPM_SW_RSV_2 (SPM_BASE + 0x618)
+#define SPM_SW_RSV_3 (SPM_BASE + 0x61C)
+#define SPM_SW_RSV_4 (SPM_BASE + 0x620)
+#define SPM_SW_RSV_5 (SPM_BASE + 0x624)
+#define SPM_SW_RSV_6 (SPM_BASE + 0x628)
+#define SPM_SW_RSV_7 (SPM_BASE + 0x62C)
+#define SPM_SW_RSV_8 (SPM_BASE + 0x630)
+#define SPM_BK_WAKE_EVENT (SPM_BASE + 0x634)
+#define SPM_BK_VTCXO_DUR (SPM_BASE + 0x638)
+#define SPM_BK_WAKE_MISC (SPM_BASE + 0x63C)
+#define SPM_BK_PCM_TIMER (SPM_BASE + 0x640)
+#define SPM_RSV_CON_0 (SPM_BASE + 0x650)
+#define SPM_RSV_CON_1 (SPM_BASE + 0x654)
+#define SPM_RSV_STA_0 (SPM_BASE + 0x658)
+#define SPM_RSV_STA_1 (SPM_BASE + 0x65C)
+#define SPM_SPARE_CON (SPM_BASE + 0x660)
+#define SPM_SPARE_CON_SET (SPM_BASE + 0x664)
+#define SPM_SPARE_CON_CLR (SPM_BASE + 0x668)
+#define SPM_CROSS_WAKE_M00_REQ (SPM_BASE + 0x66C)
+#define SPM_CROSS_WAKE_M01_REQ (SPM_BASE + 0x670)
+#define SPM_CROSS_WAKE_M02_REQ (SPM_BASE + 0x674)
+#define SPM_CROSS_WAKE_M03_REQ (SPM_BASE + 0x678)
+#define SCP_VCORE_LEVEL (SPM_BASE + 0x67C)
+#define SC_MM_CK_SEL_CON (SPM_BASE + 0x680)
+#define SPARE_ACK_MASK (SPM_BASE + 0x684)
+#define SPM_SPARE_FUNCTION (SPM_BASE + 0x688)
+#define SPM_DV_CON_0 (SPM_BASE + 0x68C)
+#define SPM_DV_CON_1 (SPM_BASE + 0x690)
+#define SPM_DV_STA (SPM_BASE + 0x694)
+#define CONN_XOWCN_DEBUG_EN (SPM_BASE + 0x698)
+#define SPM_SEMA_M0 (SPM_BASE + 0x69C)
+#define SPM_SEMA_M1 (SPM_BASE + 0x6A0)
+#define SPM_SEMA_M2 (SPM_BASE + 0x6A4)
+#define SPM_SEMA_M3 (SPM_BASE + 0x6A8)
+#define SPM_SEMA_M4 (SPM_BASE + 0x6AC)
+#define SPM_SEMA_M5 (SPM_BASE + 0x6B0)
+#define SPM_SEMA_M6 (SPM_BASE + 0x6B4)
+#define SPM_SEMA_M7 (SPM_BASE + 0x6B8)
+#define SPM2ADSP_MAILBOX (SPM_BASE + 0x6BC)
+#define ADSP2SPM_MAILBOX (SPM_BASE + 0x6C0)
+#define SPM_ADSP_IRQ (SPM_BASE + 0x6C4)
+#define SPM_MD32_IRQ (SPM_BASE + 0x6C8)
+#define SPM2PMCU_MAILBOX_0 (SPM_BASE + 0x6CC)
+#define SPM2PMCU_MAILBOX_1 (SPM_BASE + 0x6D0)
+#define SPM2PMCU_MAILBOX_2 (SPM_BASE + 0x6D4)
+#define SPM2PMCU_MAILBOX_3 (SPM_BASE + 0x6D8)
+#define PMCU2SPM_MAILBOX_0 (SPM_BASE + 0x6DC)
+#define PMCU2SPM_MAILBOX_1 (SPM_BASE + 0x6E0)
+#define PMCU2SPM_MAILBOX_2 (SPM_BASE + 0x6E4)
+#define PMCU2SPM_MAILBOX_3 (SPM_BASE + 0x6E8)
+#define UFS_PSRI_SW (SPM_BASE + 0x6EC)
+#define UFS_PSRI_SW_SET (SPM_BASE + 0x6F0)
+#define UFS_PSRI_SW_CLR (SPM_BASE + 0x6F4)
+#define SPM_AP_SEMA (SPM_BASE + 0x6F8)
+#define SPM_SPM_SEMA (SPM_BASE + 0x6FC)
+#define SPM_DVFS_CON (SPM_BASE + 0x700)
+#define SPM_DVFS_CON_STA (SPM_BASE + 0x704)
+#define SPM_PMIC_SPMI_CON (SPM_BASE + 0x708)
+#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 SPM_DVFS_CMD16 (SPM_BASE + 0x750)
+#define SPM_DVFS_CMD17 (SPM_BASE + 0x754)
+#define SPM_DVFS_CMD18 (SPM_BASE + 0x758)
+#define SPM_DVFS_CMD19 (SPM_BASE + 0x75C)
+#define SPM_DVFS_CMD20 (SPM_BASE + 0x760)
+#define SPM_DVFS_CMD21 (SPM_BASE + 0x764)
+#define SPM_DVFS_CMD22 (SPM_BASE + 0x768)
+#define SPM_DVFS_CMD23 (SPM_BASE + 0x76C)
+#define SYS_TIMER_VALUE_L (SPM_BASE + 0x770)
+#define SYS_TIMER_VALUE_H (SPM_BASE + 0x774)
+#define SYS_TIMER_START_L (SPM_BASE + 0x778)
+#define SYS_TIMER_START_H (SPM_BASE + 0x77C)
+#define SYS_TIMER_LATCH_L_00 (SPM_BASE + 0x780)
+#define SYS_TIMER_LATCH_H_00 (SPM_BASE + 0x784)
+#define SYS_TIMER_LATCH_L_01 (SPM_BASE + 0x788)
+#define SYS_TIMER_LATCH_H_01 (SPM_BASE + 0x78C)
+#define SYS_TIMER_LATCH_L_02 (SPM_BASE + 0x790)
+#define SYS_TIMER_LATCH_H_02 (SPM_BASE + 0x794)
+#define SYS_TIMER_LATCH_L_03 (SPM_BASE + 0x798)
+#define SYS_TIMER_LATCH_H_03 (SPM_BASE + 0x79C)
+#define SYS_TIMER_LATCH_L_04 (SPM_BASE + 0x7A0)
+#define SYS_TIMER_LATCH_H_04 (SPM_BASE + 0x7A4)
+#define SYS_TIMER_LATCH_L_05 (SPM_BASE + 0x7A8)
+#define SYS_TIMER_LATCH_H_05 (SPM_BASE + 0x7AC)
+#define SYS_TIMER_LATCH_L_06 (SPM_BASE + 0x7B0)
+#define SYS_TIMER_LATCH_H_06 (SPM_BASE + 0x7B4)
+#define SYS_TIMER_LATCH_L_07 (SPM_BASE + 0x7B8)
+#define SYS_TIMER_LATCH_H_07 (SPM_BASE + 0x7BC)
+#define SYS_TIMER_LATCH_L_08 (SPM_BASE + 0x7C0)
+#define SYS_TIMER_LATCH_H_08 (SPM_BASE + 0x7C4)
+#define SYS_TIMER_LATCH_L_09 (SPM_BASE + 0x7C8)
+#define SYS_TIMER_LATCH_H_09 (SPM_BASE + 0x7CC)
+#define SYS_TIMER_LATCH_L_10 (SPM_BASE + 0x7D0)
+#define SYS_TIMER_LATCH_H_10 (SPM_BASE + 0x7D4)
+#define SYS_TIMER_LATCH_L_11 (SPM_BASE + 0x7D8)
+#define SYS_TIMER_LATCH_H_11 (SPM_BASE + 0x7DC)
+#define SYS_TIMER_LATCH_L_12 (SPM_BASE + 0x7E0)
+#define SYS_TIMER_LATCH_H_12 (SPM_BASE + 0x7E4)
+#define SYS_TIMER_LATCH_L_13 (SPM_BASE + 0x7E8)
+#define SYS_TIMER_LATCH_H_13 (SPM_BASE + 0x7EC)
+#define SYS_TIMER_LATCH_L_14 (SPM_BASE + 0x7F0)
+#define SYS_TIMER_LATCH_H_14 (SPM_BASE + 0x7F4)
+#define SYS_TIMER_LATCH_L_15 (SPM_BASE + 0x7F8)
+#define SYS_TIMER_LATCH_H_15 (SPM_BASE + 0x7FC)
+#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 PCM_WDT_LATCH_10 (SPM_BASE + 0x828)
+#define PCM_WDT_LATCH_11 (SPM_BASE + 0x82C)
+#define PCM_WDT_LATCH_12 (SPM_BASE + 0x830)
+#define PCM_WDT_LATCH_13 (SPM_BASE + 0x834)
+#define PCM_WDT_LATCH_14 (SPM_BASE + 0x838)
+#define PCM_WDT_LATCH_15 (SPM_BASE + 0x83C)
+#define PCM_WDT_LATCH_16 (SPM_BASE + 0x840)
+#define PCM_WDT_LATCH_17 (SPM_BASE + 0x844)
+#define PCM_WDT_LATCH_18 (SPM_BASE + 0x848)
+#define PCM_WDT_LATCH_SPARE_0 (SPM_BASE + 0x84C)
+#define PCM_WDT_LATCH_SPARE_1 (SPM_BASE + 0x850)
+#define PCM_WDT_LATCH_SPARE_2 (SPM_BASE + 0x854)
+#define PCM_WDT_LATCH_CONN_0 (SPM_BASE + 0x870)
+#define PCM_WDT_LATCH_CONN_1 (SPM_BASE + 0x874)
+#define PCM_WDT_LATCH_CONN_2 (SPM_BASE + 0x878)
+#define DRAMC_GATING_ERR_LATCH_CH0_0 (SPM_BASE + 0x8A0)
+#define DRAMC_GATING_ERR_LATCH_CH0_1 (SPM_BASE + 0x8A4)
+#define DRAMC_GATING_ERR_LATCH_CH0_2 (SPM_BASE + 0x8A8)
+#define DRAMC_GATING_ERR_LATCH_CH0_3 (SPM_BASE + 0x8AC)
+#define DRAMC_GATING_ERR_LATCH_CH0_4 (SPM_BASE + 0x8B0)
+#define DRAMC_GATING_ERR_LATCH_CH0_5 (SPM_BASE + 0x8B4)
+#define DRAMC_GATING_ERR_LATCH_CH0_6 (SPM_BASE + 0x8B8)
+#define DRAMC_GATING_ERR_LATCH_SPARE_0 (SPM_BASE + 0x8F4)
+#define SPM_ACK_CHK_CON_0 (SPM_BASE + 0x900)
+#define SPM_ACK_CHK_PC_0 (SPM_BASE + 0x904)
+#define SPM_ACK_CHK_SEL_0 (SPM_BASE + 0x908)
+#define SPM_ACK_CHK_TIMER_0 (SPM_BASE + 0x90C)
+#define SPM_ACK_CHK_STA_0 (SPM_BASE + 0x910)
+#define SPM_ACK_CHK_SWINT_0 (SPM_BASE + 0x914)
+#define SPM_ACK_CHK_CON_1 (SPM_BASE + 0x918)
+#define SPM_ACK_CHK_PC_1 (SPM_BASE + 0x91C)
+#define SPM_ACK_CHK_SEL_1 (SPM_BASE + 0x920)
+#define SPM_ACK_CHK_TIMER_1 (SPM_BASE + 0x924)
+#define SPM_ACK_CHK_STA_1 (SPM_BASE + 0x928)
+#define SPM_ACK_CHK_SWINT_1 (SPM_BASE + 0x92C)
+#define SPM_ACK_CHK_CON_2 (SPM_BASE + 0x930)
+#define SPM_ACK_CHK_PC_2 (SPM_BASE + 0x934)
+#define SPM_ACK_CHK_SEL_2 (SPM_BASE + 0x938)
+#define SPM_ACK_CHK_TIMER_2 (SPM_BASE + 0x93C)
+#define SPM_ACK_CHK_STA_2 (SPM_BASE + 0x940)
+#define SPM_ACK_CHK_SWINT_2 (SPM_BASE + 0x944)
+#define SPM_ACK_CHK_CON_3 (SPM_BASE + 0x948)
+#define SPM_ACK_CHK_PC_3 (SPM_BASE + 0x94C)
+#define SPM_ACK_CHK_SEL_3 (SPM_BASE + 0x950)
+#define SPM_ACK_CHK_TIMER_3 (SPM_BASE + 0x954)
+#define SPM_ACK_CHK_STA_3 (SPM_BASE + 0x958)
+#define SPM_ACK_CHK_SWINT_3 (SPM_BASE + 0x95C)
+#define SPM_COUNTER_0 (SPM_BASE + 0x960)
+#define SPM_COUNTER_1 (SPM_BASE + 0x964)
+#define SPM_COUNTER_2 (SPM_BASE + 0x968)
+#define SYS_TIMER_CON (SPM_BASE + 0x96C)
+#define SPM_TWAM_CON (SPM_BASE + 0x970)
+#define SPM_TWAM_WINDOW_LEN (SPM_BASE + 0x974)
+#define SPM_TWAM_IDLE_SEL (SPM_BASE + 0x978)
+#define SPM_TWAM_EVENT_CLEAR (SPM_BASE + 0x97C)
+#define OPP0_TABLE (SPM_BASE + 0x980)
+#define OPP1_TABLE (SPM_BASE + 0x984)
+#define OPP2_TABLE (SPM_BASE + 0x988)
+#define OPP3_TABLE (SPM_BASE + 0x98C)
+#define OPP4_TABLE (SPM_BASE + 0x990)
+#define OPP5_TABLE (SPM_BASE + 0x994)
+#define OPP6_TABLE (SPM_BASE + 0x998)
+#define OPP7_TABLE (SPM_BASE + 0x99C)
+#define OPP8_TABLE (SPM_BASE + 0x9A0)
+#define OPP9_TABLE (SPM_BASE + 0x9A4)
+#define OPP10_TABLE (SPM_BASE + 0x9A8)
+#define OPP11_TABLE (SPM_BASE + 0x9AC)
+#define OPP12_TABLE (SPM_BASE + 0x9B0)
+#define OPP13_TABLE (SPM_BASE + 0x9B4)
+#define OPP14_TABLE (SPM_BASE + 0x9B8)
+#define OPP15_TABLE (SPM_BASE + 0x9BC)
+#define OPP16_TABLE (SPM_BASE + 0x9C0)
+#define OPP17_TABLE (SPM_BASE + 0x9C4)
+#define SHU0_ARRAY (SPM_BASE + 0x9C8)
+#define SHU1_ARRAY (SPM_BASE + 0x9CC)
+#define SHU2_ARRAY (SPM_BASE + 0x9D0)
+#define SHU3_ARRAY (SPM_BASE + 0x9D4)
+#define SHU4_ARRAY (SPM_BASE + 0x9D8)
+#define SHU5_ARRAY (SPM_BASE + 0x9DC)
+#define SHU6_ARRAY (SPM_BASE + 0x9E0)
+#define SHU7_ARRAY (SPM_BASE + 0x9E4)
+#define SHU8_ARRAY (SPM_BASE + 0x9E8)
+#define SHU9_ARRAY (SPM_BASE + 0x9EC)
+
+/* POWERON_CONFIG_EN (0x10006000 + 0x000) */
+#define BCLK_CG_EN_LSB (1U << 0) /* 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 REG_SRCCLKEN0_CTL_LSB (1U << 0) /* 2b */
+#define REG_SRCCLKEN1_CTL_LSB (1U << 2) /* 2b */
+#define RC_SW_SRCCLKEN_RC (1U << 3) /* 1b */
+#define RC_SW_SRCCLKEN_FPM (1U << 4) /* 1b */
+#define SYS_SETTLE_SEL_LSB (1U << 4) /* 1b */
+#define REG_SPM_LOCK_INFRA_DCM_LSB (1U << 5) /* 1b */
+#define REG_SRCCLKEN_MASK_LSB (1U << 6) /* 3b */
+#define REG_MD1_C32RM_EN_LSB (1U << 9) /* 1b */
+#define REG_MD2_C32RM_EN_LSB (1U << 10) /* 1b */
+#define REG_CLKSQ0_SEL_CTRL_LSB (1U << 11) /* 1b */
+#define REG_CLKSQ1_SEL_CTRL_LSB (1U << 12) /* 1b */
+#define REG_SRCCLKEN0_EN_LSB (1U << 13) /* 1b */
+#define REG_SRCCLKEN1_EN_LSB (1U << 14) /* 1b */
+#define SCP_DCM_EN_LSB (1U << 15) /* 1b */
+#define REG_SYSCLK0_SRC_MASK_B_LSB (1U << 16) /* 8b */
+#define REG_SYSCLK1_SRC_MASK_B_LSB (1U << 24) /* 8b */
+
+/* SPM_CLK_SETTLE (0x10006000 + 0x010) */
+#define SYSCLK_SETTLE_LSB (1U << 0) /* 28b */
+
+/* SPM_AP_STANDBY_CON (0x10006000 + 0x014) */
+#define REG_WFI_OP_LSB (1U << 0) /* 1b */
+#define REG_WFI_TYPE_LSB (1U << 1) /* 1b */
+#define REG_MP0_CPUTOP_IDLE_MASK_LSB (1U << 2) /* 1b */
+#define REG_MP1_CPUTOP_IDLE_MASK_LSB (1U << 3) /* 1b */
+#define REG_MCUSYS_IDLE_MASK_LSB (1U << 4) /* 1b */
+#define REG_MD_APSRC_1_SEL_LSB (1U << 25) /* 1b */
+#define REG_MD_APSRC_0_SEL_LSB (1U << 26) /* 1b */
+#define REG_CONN_APSRC_SEL_LSB (1U << 29) /* 1b */
+
+/* PCM_CON0 (0x10006000 + 0x018) */
+#define PCM_CK_EN_LSB (1U << 2) /* 1b */
+#define RG_EN_IM_SLEEP_DVS_LSB (1U << 3) /* 1b */
+#define PCM_CK_FROM_CKSYS_LSB (1U << 4) /* 1b */
+#define PCM_SW_RESET_LSB (1U << 15) /* 1b */
+#define PCM_CON0_PROJECT_CODE_LSB (1U << 16) /* 16b */
+
+/* PCM_CON1 (0x10006000 + 0x01C) */
+#define REG_IM_SLEEP_EN_LSB (1U << 1) /* 1b */
+#define REG_SPM_SRAM_CTRL_MUX_LSB (1U << 2) /* 1b */
+#define RG_AHBMIF_APBEN_LSB (1U << 3) /* 1b */
+#define RG_PCM_TIMER_EN_LSB (1U << 5) /* 1b */
+#define REG_SPM_EVENT_COUNTER_CLR_LSB (1U << 6) /* 1b */
+#define RG_DIS_MIF_PROT_LSB (1U << 7) /* 1b */
+#define RG_PCM_WDT_EN_LSB (1U << 8) /* 1b */
+#define RG_PCM_WDT_WAKE_LSB (1U << 9) /* 1b */
+#define SPM_LEAVE_SUSPEND_MERGE_MASK_LSB (1U << 10) /* 1b */
+#define REG_SRCCLKEN_FAST_RESP_LSB (1U << 13) /* 1b */
+#define REG_MD32_APB_INTERNAL_EN_LSB (1U << 14) /* 1b */
+#define RG_PCM_IRQ_MSK_LSB (1U << 15) /* 1b */
+#define PCM_CON1_PROJECT_CODE_LSB (1U << 16) /* 16b */
+
+/* SPM_POWER_ON_VAL2 (0x10006000 + 0x020) */
+#define POWER_ON_VAL2_LSB (1U << 0) /* 32b */
+
+/* SPM_POWER_ON_VAL3 (0x10006000 + 0x024) */
+#define POWER_ON_VAL3_LSB (1U << 0) /* 32b */
+
+/* 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 RG_RF_SYNC_EN_LSB (1U << 16) /* 8b */
+
+/* PCM_TIMER_VAL (0x10006000 + 0x030) */
+#define REG_PCM_TIMER_VAL_LSB (1U << 0) /* 32b */
+
+/* PCM_WDT_VAL (0x10006000 + 0x034) */
+#define RG_PCM_WDT_VAL_LSB (1U << 0) /* 32b */
+
+/* SPM_SW_RST_CON (0x10006000 + 0x040) */
+#define SPM_SW_RST_CON_LSB (1U << 0) /* 16b */
+#define SPM_SW_RST_CON_PROJECT_CODE_LSB (1U << 16) /* 16b */
+
+/* SPM_SW_RST_CON_SET (0x10006000 + 0x044) */
+#define SPM_SW_RST_CON_SET_LSB (1U << 0) /* 16b */
+#define SPM_SW_RST_CON_SET_PROJECT_CODE_LSB (1U << 16) /* 16b */
+
+/* SPM_SW_RST_CON_CLR (0x10006000 + 0x048) */
+#define SPM_SW_RST_CON_CLR_LSB (1U << 0) /* 16b */
+#define SPM_SW_RST_CON_CLR_PROJECT_CODE_LSB (1U << 16) /* 16b */
+
+/* SPM_SRC6_MASK (0x10006000 + 0x04C) */
+#define REG_CCIF_EVENT_INFRA_REQ_MASK_B_LSB (1U << 0) /* 16b */
+#define REG_CCIF_EVENT_APSRC_REQ_MASK_B_LSB (1U << 16) /* 16b */
+
+/* MD32_CLK_CON (0x10006000 + 0x084) */
+#define REG_MD32_26M_CK_SEL_LSB (1U << 0) /* 1b */
+#define REG_MD32_DCM_EN_LSB (1U << 1) /* 1b */
+
+/* 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) /* 32b */
+
+/* SPM_SWINT_SET (0x10006000 + 0x090) */
+#define SPM_SWINT_SET_LSB (1U << 0) /* 32b */
+
+/* SPM_SWINT_CLR (0x10006000 + 0x094) */
+#define SPM_SWINT_CLR_LSB (1U << 0) /* 32b */
+
+/* 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_WAKEUP_EVENT_SENS (0x10006000 + 0x0A0) */
+#define REG_WAKEUP_EVENT_SENS_LSB (1U << 0) /* 32b */
+
+/* SPM_WAKEUP_EVENT_CLEAR (0x10006000 + 0x0A4) */
+#define REG_WAKEUP_EVENT_CLR_LSB (1U << 0) /* 32b */
+
+/* SPM_SCP_IRQ (0x10006000 + 0x0AC) */
+#define SC_SPM2SCP_WAKEUP_LSB (1U << 0) /* 1b */
+#define SC_SCP2SPM_WAKEUP_LSB (1U << 4) /* 1b */
+
+/* SPM_CPU_WAKEUP_EVENT (0x10006000 + 0x0B0) */
+#define REG_CPU_WAKEUP_LSB (1U << 0) /* 1b */
+
+/* SPM_IRQ_MASK (0x10006000 + 0x0B4) */
+#define REG_SPM_IRQ_MASK_LSB (1U << 0) /* 32b */
+
+/* SPM_SRC_REQ (0x10006000 + 0x0B8) */
+#define REG_SPM_APSRC_REQ_LSB (1U << 0) /* 1b */
+#define REG_SPM_F26M_REQ_LSB (1U << 1) /* 1b */
+#define REG_SPM_INFRA_REQ_LSB (1U << 3) /* 1b */
+#define REG_SPM_VRF18_REQ_LSB (1U << 4) /* 1b */
+#define REG_SPM_DDREN_REQ_LSB (1U << 7) /* 1b */
+#define REG_SPM_DVFS_REQ_LSB (1U << 8) /* 1b */
+#define REG_SPM_SW_MAILBOX_REQ_LSB (1U << 9) /* 1b */
+#define REG_SPM_SSPM_MAILBOX_REQ_LSB (1U << 10) /* 1b */
+#define REG_SPM_ADSP_MAILBOX_REQ_LSB (1U << 11) /* 1b */
+#define REG_SPM_SCP_MAILBOX_REQ_LSB (1U << 12) /* 1b */
+
+/* SPM_SRC_MASK (0x10006000 + 0x0BC) */
+#define REG_MD_0_SRCCLKENA_MASK_B_LSB (1U << 0) /* 1b */
+#define REG_MD_0_INFRA_REQ_MASK_B_LSB (1U << 1) /* 1b */
+#define REG_MD_0_APSRC_REQ_MASK_B_LSB (1U << 2) /* 1b */
+#define REG_MD_0_VRF18_REQ_MASK_B_LSB (1U << 3) /* 1b */
+#define REG_MD_0_DDREN_REQ_MASK_B_LSB (1U << 4) /* 1b */
+#define REG_MD_1_SRCCLKENA_MASK_B_LSB (1U << 5) /* 1b */
+#define REG_MD_1_INFRA_REQ_MASK_B_LSB (1U << 6) /* 1b */
+#define REG_MD_1_APSRC_REQ_MASK_B_LSB (1U << 7) /* 1b */
+#define REG_MD_1_VRF18_REQ_MASK_B_LSB (1U << 8) /* 1b */
+#define REG_MD_1_DDREN_REQ_MASK_B_LSB (1U << 9) /* 1b */
+#define REG_CONN_SRCCLKENA_MASK_B_LSB (1U << 10) /* 1b */
+#define REG_CONN_SRCCLKENB_MASK_B_LSB (1U << 11) /* 1b */
+#define REG_CONN_INFRA_REQ_MASK_B_LSB (1U << 12) /* 1b */
+#define REG_CONN_APSRC_REQ_MASK_B_LSB (1U << 13) /* 1b */
+#define REG_CONN_VRF18_REQ_MASK_B_LSB (1U << 14) /* 1b */
+#define REG_CONN_DDREN_REQ_MASK_B_LSB (1U << 15) /* 1b */
+#define REG_CONN_VFE28_MASK_B_LSB (1U << 16) /* 1b */
+#define REG_SRCCLKENI_SRCCLKENA_MASK_B_LSB (1U << 17) /* 3b */
+#define REG_SRCCLKENI_INFRA_REQ_MASK_B_LSB (1U << 20) /* 3b */
+#define REG_INFRASYS_APSRC_REQ_MASK_B_LSB (1U << 25) /* 1b */
+#define REG_INFRASYS_DDREN_REQ_MASK_B_LSB (1U << 26) /* 1b */
+#define REG_SSPM_SRCCLKENA_MASK_B_LSB (1U << 27) /* 1b */
+#define REG_SSPM_INFRA_REQ_MASK_B_LSB (1U << 28) /* 1b */
+#define REG_SSPM_APSRC_REQ_MASK_B_LSB (1U << 29) /* 1b */
+#define REG_SSPM_VRF18_REQ_MASK_B_LSB (1U << 30) /* 1b */
+#define REG_SSPM_DDREN_REQ_MASK_B_LSB (1U << 31) /* 1b */
+
+/* SPM_SRC2_MASK (0x10006000 + 0x0C0) */
+#define REG_SCP_SRCCLKENA_MASK_B_LSB (1U << 0) /* 1b */
+#define REG_SCP_INFRA_REQ_MASK_B_LSB (1U << 1) /* 1b */
+#define REG_SCP_APSRC_REQ_MASK_B_LSB (1U << 2) /* 1b */
+#define REG_SCP_VRF18_REQ_MASK_B_LSB (1U << 3) /* 1b */
+#define REG_SCP_DDREN_REQ_MASK_B_LSB (1U << 4) /* 1b */
+#define REG_AUDIO_DSP_SRCCLKENA_MASK_B_LSB (1U << 5) /* 1b */
+#define REG_AUDIO_DSP_INFRA_REQ_MASK_B_LSB (1U << 6) /* 1b */
+#define REG_AUDIO_DSP_APSRC_REQ_MASK_B_LSB (1U << 7) /* 1b */
+#define REG_AUDIO_DSP_VRF18_REQ_MASK_B_LSB (1U << 8) /* 1b */
+#define REG_AUDIO_DSP_DDREN_REQ_MASK_B_LSB (1U << 9) /* 1b */
+#define REG_UFS_SRCCLKENA_MASK_B_LSB (1U << 10) /* 1b */
+#define REG_UFS_INFRA_REQ_MASK_B_LSB (1U << 11) /* 1b */
+#define REG_UFS_APSRC_REQ_MASK_B_LSB (1U << 12) /* 1b */
+#define REG_UFS_VRF18_REQ_MASK_B_LSB (1U << 13) /* 1b */
+#define REG_UFS_DDREN_REQ_MASK_B_LSB (1U << 14) /* 1b */
+#define REG_DISP0_APSRC_REQ_MASK_B_LSB (1U << 15) /* 1b */
+#define REG_DISP0_DDREN_REQ_MASK_B_LSB (1U << 16) /* 1b */
+#define REG_DISP1_APSRC_REQ_MASK_B_LSB (1U << 17) /* 1b */
+#define REG_DISP1_DDREN_REQ_MASK_B_LSB (1U << 18) /* 1b */
+#define REG_GCE_INFRA_REQ_MASK_B_LSB (1U << 19) /* 1b */
+#define REG_GCE_APSRC_REQ_MASK_B_LSB (1U << 20) /* 1b */
+#define REG_GCE_VRF18_REQ_MASK_B_LSB (1U << 21) /* 1b */
+#define REG_GCE_DDREN_REQ_MASK_B_LSB (1U << 22) /* 1b */
+#define REG_APU_SRCCLKENA_MASK_B_LSB (1U << 23) /* 1b */
+#define REG_APU_INFRA_REQ_MASK_B_LSB (1U << 24) /* 1b */
+#define REG_APU_APSRC_REQ_MASK_B_LSB (1U << 25) /* 1b */
+#define REG_APU_VRF18_REQ_MASK_B_LSB (1U << 26) /* 1b */
+#define REG_APU_DDREN_REQ_MASK_B_LSB (1U << 27) /* 1b */
+#define REG_CG_CHECK_SRCCLKENA_MASK_B_LSB (1U << 28) /* 1b */
+#define REG_CG_CHECK_APSRC_REQ_MASK_B_LSB (1U << 29) /* 1b */
+#define REG_CG_CHECK_VRF18_REQ_MASK_B_LSB (1U << 30) /* 1b */
+#define REG_CG_CHECK_DDREN_REQ_MASK_B_LSB (1U << 31) /* 1b */
+
+/* SPM_SRC3_MASK (0x10006000 + 0x0C4) */
+#define REG_DVFSRC_EVENT_TRIGGER_MASK_B_LSB (1U << 0) /* 1b */
+#define REG_SW2SPM_WAKEUP_MASK_B_LSB (1U << 1) /* 4b */
+#define REG_ADSP2SPM_WAKEUP_MASK_B_LSB (1U << 5) /* 1b */
+#define REG_SSPM2SPM_WAKEUP_MASK_B_LSB (1U << 6) /* 4b */
+#define REG_SCP2SPM_WAKEUP_MASK_B_LSB (1U << 10) /* 1b */
+#define REG_CSYSPWRUP_ACK_MASK_LSB (1U << 11) /* 1b */
+#define REG_SPM_RESERVED_SRCCLKENA_MASK_B_LSB (1U << 12) /* 1b */
+#define REG_SPM_RESERVED_INFRA_REQ_MASK_B_LSB (1U << 13) /* 1b */
+#define REG_SPM_RESERVED_APSRC_REQ_MASK_B_LSB (1U << 14) /* 1b */
+#define REG_SPM_RESERVED_VRF18_REQ_MASK_B_LSB (1U << 15) /* 1b */
+#define REG_SPM_RESERVED_DDREN_REQ_MASK_B_LSB (1U << 16) /* 1b */
+#define REG_MCUPM_SRCCLKENA_MASK_B_LSB (1U << 17) /* 1b */
+#define REG_MCUPM_INFRA_REQ_MASK_B_LSB (1U << 18) /* 1b */
+#define REG_MCUPM_APSRC_REQ_MASK_B_LSB (1U << 19) /* 1b */
+#define REG_MCUPM_VRF18_REQ_MASK_B_LSB (1U << 20) /* 1b */
+#define REG_MCUPM_DDREN_REQ_MASK_B_LSB (1U << 21) /* 1b */
+#define REG_MSDC0_SRCCLKENA_MASK_B_LSB (1U << 22) /* 1b */
+#define REG_MSDC0_INFRA_REQ_MASK_B_LSB (1U << 23) /* 1b */
+#define REG_MSDC0_APSRC_REQ_MASK_B_LSB (1U << 24) /* 1b */
+#define REG_MSDC0_VRF18_REQ_MASK_B_LSB (1U << 25) /* 1b */
+#define REG_MSDC0_DDREN_REQ_MASK_B_LSB (1U << 26) /* 1b */
+#define REG_MSDC1_SRCCLKENA_MASK_B_LSB (1U << 27) /* 1b */
+#define REG_MSDC1_INFRA_REQ_MASK_B_LSB (1U << 28) /* 1b */
+#define REG_MSDC1_APSRC_REQ_MASK_B_LSB (1U << 29) /* 1b */
+#define REG_MSDC1_VRF18_REQ_MASK_B_LSB (1U << 30) /* 1b */
+#define REG_MSDC1_DDREN_REQ_MASK_B_LSB (1U << 31) /* 1b */
+
+/* SPM_SRC4_MASK (0x10006000 + 0x0C8) */
+#define REG_CCIF_EVENT_SRCCLKENA_MASK_B_LSB (1U << 0) /* 16b */
+#define REG_BAK_PSRI_SRCCLKENA_MASK_B_LSB (1U << 16) /* 1b */
+#define REG_BAK_PSRI_INFRA_REQ_MASK_B_LSB (1U << 17) /* 1b */
+#define REG_BAK_PSRI_APSRC_REQ_MASK_B_LSB (1U << 18) /* 1b */
+#define REG_BAK_PSRI_VRF18_REQ_MASK_B_LSB (1U << 19) /* 1b */
+#define REG_BAK_PSRI_DDREN_REQ_MASK_B_LSB (1U << 20) /* 1b */
+#define REG_DRAMC_MD32_INFRA_REQ_MASK_B_LSB (1U << 21) /* 2b */
+#define REG_DRAMC_MD32_VRF18_REQ_MASK_B_LSB (1U << 23) /* 2b */
+#define REG_CONN_SRCCLKENB2PWRAP_MASK_B_LSB (1U << 25) /* 1b */
+#define REG_DRAMC_MD32_APSRC_REQ_MASK_B_LSB (1U << 26) /* 2b */
+
+/* SPM_SRC5_MASK (0x10006000 + 0x0CC) */
+#define REG_MCUSYS_MERGE_APSRC_REQ_MASK_B_LSB (1U << 0) /* 9b */
+#define REG_MCUSYS_MERGE_DDREN_REQ_MASK_B_LSB (1U << 9) /* 9b */
+#define REG_AFE_SRCCLKENA_MASK_B_LSB (1U << 18) /* 1b */
+#define REG_AFE_INFRA_REQ_MASK_B_LSB (1U << 19) /* 1b */
+#define REG_AFE_APSRC_REQ_MASK_B_LSB (1U << 20) /* 1b */
+#define REG_AFE_VRF18_REQ_MASK_B_LSB (1U << 21) /* 1b */
+#define REG_AFE_DDREN_REQ_MASK_B_LSB (1U << 22) /* 1b */
+#define REG_MSDC2_SRCCLKENA_MASK_B_LSB (1U << 23) /* 1b */
+#define REG_MSDC2_INFRA_REQ_MASK_B_LSB (1U << 24) /* 1b */
+#define REG_MSDC2_APSRC_REQ_MASK_B_LSB (1U << 25) /* 1b */
+#define REG_MSDC2_VRF18_REQ_MASK_B_LSB (1U << 26) /* 1b */
+#define REG_MSDC2_DDREN_REQ_MASK_B_LSB (1U << 27) /* 1b */
+/* SPM_WAKEUP_EVENT_MASK (0x10006000 + 0x0D0) */
+#define REG_WAKEUP_EVENT_MASK_LSB (1U << 0) /* 32b */
+
+/* SPM_WAKEUP_EVENT_EXT_MASK (0x10006000 + 0x0D4) */
+#define REG_EXT_WAKEUP_EVENT_MASK_LSB (1U << 0) /* 32b */
+
+/* SPM_SRC7_MASK (0x10006000 + 0x0D8) */
+#define REG_PCIE_SRCCLKENA_MASK_B_LSB (1U << 0) /* 1b */
+#define REG_PCIE_INFRA_REQ_MASK_B_LSB (1U << 1) /* 1b */
+#define REG_PCIE_APSRC_REQ_MASK_B_LSB (1U << 2) /* 1b */
+#define REG_PCIE_VRF18_REQ_MASK_B_LSB (1U << 3) /* 1b */
+#define REG_PCIE_DDREN_REQ_MASK_B_LSB (1U << 4) /* 1b */
+#define REG_DPMAIF_SRCCLKENA_MASK_B_LSB (1U << 5) /* 1b */
+#define REG_DPMAIF_INFRA_REQ_MASK_B_LSB (1U << 6) /* 1b */
+#define REG_DPMAIF_APSRC_REQ_MASK_B_LSB (1U << 7) /* 1b */
+#define REG_DPMAIF_VRF18_REQ_MASK_B_LSB (1U << 8) /* 1b */
+#define REG_DPMAIF_DDREN_REQ_MASK_B_LSB (1U << 9) /* 1b */
+
+/* SCP_CLK_CON (0x10006000 + 0x0DC) */
+#define REG_SCP_26M_CK_SEL_LSB (1U << 0) /* 1b */
+#define REG_SCP_DCM_EN_LSB (1U << 1) /* 1b */
+#define SCP_SECURE_VREQ_MASK_LSB (1U << 2) /* 1b */
+#define SCP_SLP_REQ_LSB (1U << 3) /* 1b */
+#define SCP_SLP_ACK_LSB (1U << 4) /* 1b */
+
+/* PCM_DEBUG_CON (0x10006000 + 0x0E0) */
+#define PCM_DEBUG_OUT_ENABLE_LSB (1U << 0) /* 1b */
+
+/* DDREN_DBC_CON (0x10006000 + 0x0E8) */
+#define REG_DDREN_DBC_LEN_LSB (1U << 0) /* 10b */
+#define REG_DDREN_DBC_EN_LSB (1U << 16) /* 1b */
+
+/* SPM_RESOURCE_ACK_CON4 (0x10006000 + 0x0EC) */
+#define REG_DPMAIF_SRCCLKENA_ACK_MASK_LSB (1U << 0) /* 1b */
+#define REG_DPMAIF_INFRA_ACK_MASK_LSB (1U << 1) /* 1b */
+#define REG_DPMAIF_APSRC_ACK_MASK_LSB (1U << 2) /* 1b */
+#define REG_DPMAIF_VRF18_ACK_MASK_LSB (1U << 3) /* 1b */
+#define REG_DPMAIF_DDREN_ACK_MASK_LSB (1U << 4) /* 1b */
+
+/* SPM_RESOURCE_ACK_CON0 (0x10006000 + 0x0F0) */
+#define REG_MD_0_SRCCLKENA_ACK_MASK_LSB (1U << 0) /* 1b */
+#define REG_MD_0_INFRA_ACK_MASK_LSB (1U << 1) /* 1b */
+#define REG_MD_0_APSRC_ACK_MASK_LSB (1U << 2) /* 1b */
+#define REG_MD_0_VRF18_ACK_MASK_LSB (1U << 3) /* 1b */
+#define REG_MD_0_DDREN_ACK_MASK_LSB (1U << 4) /* 1b */
+#define REG_MD_1_SRCCLKENA_ACK_MASK_LSB (1U << 5) /* 1b */
+#define REG_MD_1_INFRA_ACK_MASK_LSB (1U << 6) /* 1b */
+#define REG_MD_1_APSRC_ACK_MASK_LSB (1U << 7) /* 1b */
+#define REG_MD_1_VRF18_ACK_MASK_LSB (1U << 8) /* 1b */
+#define REG_MD_1_DDREN_ACK_MASK_LSB (1U << 9) /* 1b */
+#define REG_CONN_SRCCLKENA_ACK_MASK_LSB (1U << 10) /* 1b */
+#define REG_CONN_INFRA_ACK_MASK_LSB (1U << 11) /* 1b */
+#define REG_CONN_APSRC_ACK_MASK_LSB (1U << 12) /* 1b */
+#define REG_CONN_VRF18_ACK_MASK_LSB (1U << 13) /* 1b */
+#define REG_CONN_DDREN_ACK_MASK_LSB (1U << 14) /* 1b */
+#define REG_SSPM_SRCCLKENA_ACK_MASK_LSB (1U << 15) /* 1b */
+#define REG_SSPM_INFRA_ACK_MASK_LSB (1U << 16) /* 1b */
+#define REG_SSPM_APSRC_ACK_MASK_LSB (1U << 17) /* 1b */
+#define REG_SSPM_VRF18_ACK_MASK_LSB (1U << 18) /* 1b */
+#define REG_SSPM_DDREN_ACK_MASK_LSB (1U << 19) /* 1b */
+#define REG_SCP_SRCCLKENA_ACK_MASK_LSB (1U << 20) /* 1b */
+#define REG_SCP_INFRA_ACK_MASK_LSB (1U << 21) /* 1b */
+#define REG_SCP_APSRC_ACK_MASK_LSB (1U << 22) /* 1b */
+#define REG_SCP_VRF18_ACK_MASK_LSB (1U << 23) /* 1b */
+#define REG_SCP_DDREN_ACK_MASK_LSB (1U << 24) /* 1b */
+#define REG_AUDIO_DSP_SRCCLKENA_ACK_MASK_LSB (1U << 25) /* 1b */
+#define REG_AUDIO_DSP_INFRA_ACK_MASK_LSB (1U << 26) /* 1b */
+#define REG_AUDIO_DSP_APSRC_ACK_MASK_LSB (1U << 27) /* 1b */
+#define REG_AUDIO_DSP_VRF18_ACK_MASK_LSB (1U << 28) /* 1b */
+#define REG_AUDIO_DSP_DDREN_ACK_MASK_LSB (1U << 29) /* 1b */
+#define REG_DISP0_DDREN_ACK_MASK_LSB (1U << 30) /* 1b */
+#define REG_DISP1_APSRC_ACK_MASK_LSB (1U << 31) /* 1b */
+
+/* SPM_RESOURCE_ACK_CON1 (0x10006000 + 0x0F4) */
+#define REG_UFS_SRCCLKENA_ACK_MASK_LSB (1U << 0) /* 1b */
+#define REG_UFS_INFRA_ACK_MASK_LSB (1U << 1) /* 1b */
+#define REG_UFS_APSRC_ACK_MASK_LSB (1U << 2) /* 1b */
+#define REG_UFS_VRF18_ACK_MASK_LSB (1U << 3) /* 1b */
+#define REG_UFS_DDREN_ACK_MASK_LSB (1U << 4) /* 1b */
+#define REG_APU_SRCCLKENA_ACK_MASK_LSB (1U << 5) /* 1b */
+#define REG_APU_INFRA_ACK_MASK_LSB (1U << 6) /* 1b */
+#define REG_APU_APSRC_ACK_MASK_LSB (1U << 7) /* 1b */
+#define REG_APU_VRF18_ACK_MASK_LSB (1U << 8) /* 1b */
+#define REG_APU_DDREN_ACK_MASK_LSB (1U << 9) /* 1b */
+#define REG_MCUPM_SRCCLKENA_ACK_MASK_LSB (1U << 10) /* 1b */
+#define REG_MCUPM_INFRA_ACK_MASK_LSB (1U << 11) /* 1b */
+#define REG_MCUPM_APSRC_ACK_MASK_LSB (1U << 12) /* 1b */
+#define REG_MCUPM_VRF18_ACK_MASK_LSB (1U << 13) /* 1b */
+#define REG_MCUPM_DDREN_ACK_MASK_LSB (1U << 14) /* 1b */
+#define REG_MSDC0_SRCCLKENA_ACK_MASK_LSB (1U << 15) /* 1b */
+#define REG_MSDC0_INFRA_ACK_MASK_LSB (1U << 16) /* 1b */
+#define REG_MSDC0_APSRC_ACK_MASK_LSB (1U << 17) /* 1b */
+#define REG_MSDC0_VRF18_ACK_MASK_LSB (1U << 18) /* 1b */
+#define REG_MSDC0_DDREN_ACK_MASK_LSB (1U << 19) /* 1b */
+#define REG_MSDC1_SRCCLKENA_ACK_MASK_LSB (1U << 20) /* 1b */
+#define REG_MSDC1_INFRA_ACK_MASK_LSB (1U << 21) /* 1b */
+#define REG_MSDC1_APSRC_ACK_MASK_LSB (1U << 22) /* 1b */
+#define REG_MSDC1_VRF18_ACK_MASK_LSB (1U << 23) /* 1b */
+#define REG_MSDC1_DDREN_ACK_MASK_LSB (1U << 24) /* 1b */
+#define REG_DISP0_APSRC_ACK_MASK_LSB (1U << 25) /* 1b */
+#define REG_DISP1_DDREN_ACK_MASK_LSB (1U << 26) /* 1b */
+#define REG_GCE_INFRA_ACK_MASK_LSB (1U << 27) /* 1b */
+#define REG_GCE_APSRC_ACK_MASK_LSB (1U << 28) /* 1b */
+#define REG_GCE_VRF18_ACK_MASK_LSB (1U << 29) /* 1b */
+#define REG_GCE_DDREN_ACK_MASK_LSB (1U << 30) /* 1b */
+
+/* SPM_RESOURCE_ACK_CON2 (0x10006000 + 0x0F8) */
+#define SPM_SRCCLKENA_ACK_WAIT_CYCLE_LSB (1U << 0) /* 8b */
+#define SPM_INFRA_ACK_WAIT_CYCLE_LSB (1U << 8) /* 8b */
+#define SPM_APSRC_ACK_WAIT_CYCLE_LSB (1U << 16) /* 8b */
+#define SPM_VRF18_ACK_WAIT_CYCLE_LSB (1U << 24) /* 8b */
+
+/* SPM_RESOURCE_ACK_CON3 (0x10006000 + 0x0FC) */
+#define SPM_DDREN_ACK_WAIT_CYCLE_LSB (1U << 0) /* 8b */
+#define REG_BAK_PSRI_SRCCLKENA_ACK_MASK_LSB (1U << 8) /* 1b */
+#define REG_BAK_PSRI_INFRA_ACK_MASK_LSB (1U << 9) /* 1b */
+#define REG_BAK_PSRI_APSRC_ACK_MASK_LSB (1U << 10) /* 1b */
+#define REG_BAK_PSRI_VRF18_ACK_MASK_LSB (1U << 11) /* 1b */
+#define REG_BAK_PSRI_DDREN_ACK_MASK_LSB (1U << 12) /* 1b */
+#define REG_AFE_SRCCLKENA_ACK_MASK_LSB (1U << 13) /* 1b */
+#define REG_AFE_INFRA_ACK_MASK_LSB (1U << 14) /* 1b */
+#define REG_AFE_APSRC_ACK_MASK_LSB (1U << 15) /* 1b */
+#define REG_AFE_VRF18_ACK_MASK_LSB (1U << 16) /* 1b */
+#define REG_AFE_DDREN_ACK_MASK_LSB (1U << 17) /* 1b */
+#define REG_MSDC2_SRCCLKENA_ACK_MASK_LSB (1U << 18) /* 1b */
+#define REG_MSDC2_INFRA_ACK_MASK_LSB (1U << 19) /* 1b */
+#define REG_MSDC2_APSRC_ACK_MASK_LSB (1U << 20) /* 1b */
+#define REG_MSDC2_VRF18_ACK_MASK_LSB (1U << 21) /* 1b */
+#define REG_MSDC2_DDREN_ACK_MASK_LSB (1U << 22) /* 1b */
+#define REG_PCIE_SRCCLKENA_ACK_MASK_LSB (1U << 23) /* 1b */
+#define REG_PCIE_INFRA_ACK_MASK_LSB (1U << 24) /* 1b */
+#define REG_PCIE_APSRC_ACK_MASK_LSB (1U << 25) /* 1b */
+#define REG_PCIE_VRF18_ACK_MASK_LSB (1U << 26) /* 1b */
+#define REG_PCIE_DDREN_ACK_MASK_LSB (1U << 27) /* 1b */
+
+/* PCM_REG0_DATA (0x10006000 + 0x100) */
+#define PCM_REG0_RF_LSB (1U << 0) /* 32b */
+
+/* PCM_REG2_DATA (0x10006000 + 0x104) */
+#define PCM_REG2_RF_LSB (1U << 0) /* 32b */
+
+/* PCM_REG6_DATA (0x10006000 + 0x108) */
+#define PCM_REG6_RF_LSB (1U << 0) /* 32b */
+
+/* PCM_REG7_DATA (0x10006000 + 0x10C) */
+#define PCM_REG7_RF_LSB (1U << 0) /* 32b */
+
+/* PCM_REG13_DATA (0x10006000 + 0x110) */
+#define PCM_REG13_RF_LSB (1U << 0) /* 32b */
+
+/* SRC_REQ_STA_0 (0x10006000 + 0x114) */
+#define MD_0_SRCCLKENA_LSB (1U << 0) /* 1b */
+#define MD_0_INFRA_REQ_LSB (1U << 1) /* 1b */
+#define MD_0_APSRC_REQ_LSB (1U << 2) /* 1b */
+#define MD_0_VRF18_REQ_LSB (1U << 4) /* 1b */
+#define MD_0_DDREN_REQ_LSB (1U << 5) /* 1b */
+#define MD_1_SRCCLKENA_LSB (1U << 6) /* 1b */
+#define MD_1_INFRA_REQ_LSB (1U << 7) /* 1b */
+#define MD_1_APSRC_REQ_LSB (1U << 8) /* 1b */
+#define MD_1_VRF18_REQ_LSB (1U << 10) /* 1b */
+#define MD_1_DDREN_REQ_LSB (1U << 11) /* 1b */
+#define CONN_SRCCLKENA_LSB (1U << 12) /* 1b */
+#define CONN_SRCCLKENB_LSB (1U << 13) /* 1b */
+#define CONN_INFRA_REQ_LSB (1U << 14) /* 1b */
+#define CONN_APSRC_REQ_LSB (1U << 15) /* 1b */
+#define CONN_VRF18_REQ_LSB (1U << 16) /* 1b */
+#define CONN_DDREN_REQ_LSB (1U << 17) /* 1b */
+#define SRCCLKENI_LSB (1U << 18) /* 3b */
+#define SSPM_SRCCLKENA_LSB (1U << 21) /* 1b */
+#define SSPM_INFRA_REQ_LSB (1U << 22) /* 1b */
+#define SSPM_APSRC_REQ_LSB (1U << 23) /* 1b */
+#define SSPM_VRF18_REQ_LSB (1U << 24) /* 1b */
+#define SSPM_DDREN_REQ_LSB (1U << 25) /* 1b */
+#define DISP0_APSRC_REQ_LSB (1U << 26) /* 1b */
+#define DISP0_DDREN_REQ_LSB (1U << 27) /* 1b */
+#define DISP1_APSRC_REQ_LSB (1U << 28) /* 1b */
+#define DISP1_DDREN_REQ_LSB (1U << 29) /* 1b */
+#define DVFSRC_EVENT_TRIGGER_LSB (1U << 30) /* 1b */
+
+/* SRC_REQ_STA_1 (0x10006000 + 0x118) */
+#define SCP_SRCCLKENA_LSB (1U << 0) /* 1b */
+#define SCP_INFRA_REQ_LSB (1U << 1) /* 1b */
+#define SCP_APSRC_REQ_LSB (1U << 2) /* 1b */
+#define SCP_VRF18_REQ_LSB (1U << 3) /* 1b */
+#define SCP_DDREN_REQ_LSB (1U << 4) /* 1b */
+#define AUDIO_DSP_SRCCLKENA_LSB (1U << 5) /* 1b */
+#define AUDIO_DSP_INFRA_REQ_LSB (1U << 6) /* 1b */
+#define AUDIO_DSP_APSRC_REQ_LSB (1U << 7) /* 1b */
+#define AUDIO_DSP_VRF18_REQ_LSB (1U << 8) /* 1b */
+#define AUDIO_DSP_DDREN_REQ_LSB (1U << 9) /* 1b */
+#define UFS_SRCCLKENA_LSB (1U << 10) /* 1b */
+#define UFS_INFRA_REQ_LSB (1U << 11) /* 1b */
+#define UFS_APSRC_REQ_LSB (1U << 12) /* 1b */
+#define UFS_VRF18_REQ_LSB (1U << 13) /* 1b */
+#define UFS_DDREN_REQ_LSB (1U << 14) /* 1b */
+#define GCE_INFRA_REQ_LSB (1U << 15) /* 1b */
+#define GCE_APSRC_REQ_LSB (1U << 16) /* 1b */
+#define GCE_VRF18_REQ_LSB (1U << 17) /* 1b */
+#define GCE_DDREN_REQ_LSB (1U << 18) /* 1b */
+#define INFRASYS_APSRC_REQ_LSB (1U << 19) /* 1b */
+#define INFRASYS_DDREN_REQ_LSB (1U << 20) /* 1b */
+#define MSDC0_SRCCLKENA_LSB (1U << 21) /* 1b */
+#define MSDC0_INFRA_REQ_LSB (1U << 22) /* 1b */
+#define MSDC0_APSRC_REQ_LSB (1U << 23) /* 1b */
+#define MSDC0_VRF18_REQ_LSB (1U << 24) /* 1b */
+#define MSDC0_DDREN_REQ_LSB (1U << 25) /* 1b */
+#define MSDC1_SRCCLKENA_LSB (1U << 26) /* 1b */
+#define MSDC1_INFRA_REQ_LSB (1U << 27) /* 1b */
+#define MSDC1_APSRC_REQ_LSB (1U << 28) /* 1b */
+#define MSDC1_VRF18_REQ_LSB (1U << 29) /* 1b */
+#define MSDC1_DDREN_REQ_LSB (1U << 30) /* 1b */
+
+/* SRC_REQ_STA_2 (0x10006000 + 0x11C) */
+#define MCUSYS_MERGE_DDR_EN_LSB (1U << 0) /* 9b */
+#define EMI_SELF_REFRESH_CH_LSB (1U << 9) /* 2b */
+#define SW2SPM_WAKEUP_LSB (1U << 11) /* 4b */
+#define SC_ADSP2SPM_WAKEUP_LSB (1U << 15) /* 1b */
+#define SC_SSPM2SPM_WAKEUP_LSB (1U << 16) /* 4b */
+#define SRC_REQ_STA_2_SC_SCP2SPM_WAKEUP_LSB (1U << 20) /* 1b */
+#define SPM_RESERVED_SRCCLKENA_LSB (1U << 21) /* 1b */
+#define SPM_RESERVED_INFRA_REQ_LSB (1U << 22) /* 1b */
+#define SPM_RESERVED_APSRC_REQ_LSB (1U << 23) /* 1b */
+#define SPM_RESERVED_VRF18_REQ_LSB (1U << 24) /* 1b */
+#define SPM_RESERVED_DDREN_REQ_LSB (1U << 25) /* 1b */
+#define MCUPM_SRCCLKENA_LSB (1U << 26) /* 1b */
+#define MCUPM_INFRA_REQ_LSB (1U << 27) /* 1b */
+#define MCUPM_APSRC_REQ_LSB (1U << 28) /* 1b */
+#define MCUPM_VRF18_REQ_LSB (1U << 29) /* 1b */
+#define MCUPM_DDREN_REQ_LSB (1U << 30) /* 1b */
+
+/* PCM_TIMER_OUT (0x10006000 + 0x120) */
+#define PCM_TIMER_LSB (1U << 0) /* 32b */
+
+/* PCM_WDT_OUT (0x10006000 + 0x124) */
+#define PCM_WDT_TIMER_VAL_OUT_LSB (1U << 0) /* 32b */
+
+/* SPM_IRQ_STA (0x10006000 + 0x128) */
+#define TWAM_IRQ_LSB (1U << 2) /* 1b */
+#define PCM_IRQ_LSB (1U << 3) /* 1b */
+
+/* SRC_REQ_STA_4 (0x10006000 + 0x12C) */
+#define APU_SRCCLKENA_LSB (1U << 0) /* 1b */
+#define APU_INFRA_REQ_LSB (1U << 1) /* 1b */
+#define APU_APSRC_REQ_LSB (1U << 2) /* 1b */
+#define APU_VRF18_REQ_LSB (1U << 3) /* 1b */
+#define APU_DDREN_REQ_LSB (1U << 4) /* 1b */
+#define BAK_PSRI_SRCCLKENA_LSB (1U << 5) /* 1b */
+#define BAK_PSRI_INFRA_REQ_LSB (1U << 6) /* 1b */
+#define BAK_PSRI_APSRC_REQ_LSB (1U << 7) /* 1b */
+#define BAK_PSRI_VRF18_REQ_LSB (1U << 8) /* 1b */
+#define BAK_PSRI_DDREN_REQ_LSB (1U << 9) /* 1b */
+#define MSDC2_SRCCLKENA_LSB (1U << 10) /* 1b */
+#define MSDC2_INFRA_REQ_LSB (1U << 11) /* 1b */
+#define MSDC2_APSRC_REQ_LSB (1U << 12) /* 1b */
+#define MSDC2_VRF18_REQ_LSB (1U << 13) /* 1b */
+#define MSDC2_DDREN_REQ_LSB (1U << 14) /* 1b */
+#define PCIE_SRCCLKENA_LSB (1U << 15) /* 1b */
+#define PCIE_INFRA_REQ_LSB (1U << 16) /* 1b */
+#define PCIE_APSRC_REQ_LSB (1U << 17) /* 1b */
+#define PCIE_VRF18_REQ_LSB (1U << 18) /* 1b */
+#define PCIE_DDREN_REQ_LSB (1U << 19) /* 1b */
+#define DPMAIF_SRCCLKENA_LSB (1U << 20) /* 1b */
+#define DPMAIF_INFRA_REQ_LSB (1U << 21) /* 1b */
+#define DPMAIF_APSRC_REQ_LSB (1U << 22) /* 1b */
+#define DPMAIF_VRF18_REQ_LSB (1U << 23) /* 1b */
+#define DPMAIF_DDREN_REQ_LSB (1U << 24) /* 1b */
+#define AFE_SRCCLKENA_LSB (1U << 25) /* 1b */
+#define AFE_INFRA_REQ_LSB (1U << 26) /* 1b */
+#define AFE_APSRC_REQ_LSB (1U << 27) /* 1b */
+#define AFE_VRF18_REQ_LSB (1U << 28) /* 1b */
+#define AFE_DDREN_REQ_LSB (1U << 29) /* 1b */
+
+/* MD32PCM_WAKEUP_STA (0x10006000 + 0x130) */
+#define MD32PCM_WAKEUP_STA_LSB (1U << 0) /* 32b */
+
+/* MD32PCM_EVENT_STA (0x10006000 + 0x134) */
+#define MD32PCM_EVENT_STA_LSB (1U << 0) /* 32b */
+
+/* SPM_WAKEUP_STA (0x10006000 + 0x138) */
+#define SPM_WAKEUP_EVENT_L_LSB (1U << 0) /* 32b */
+
+/* SPM_WAKEUP_EXT_STA (0x10006000 + 0x13C) */
+#define EXT_WAKEUP_EVENT_LSB (1U << 0) /* 32b */
+
+/* SPM_WAKEUP_MISC (0x10006000 + 0x140) */
+#define GIC_WAKEUP_LSB (1U << 0) /* 10b */
+#define DVFSRC_IRQ_LSB (1U << 16) /* 1b */
+#define SPM_WAKEUP_MISC_REG_CPU_WAKEUP_LSB (1U << 17) /* 1b */
+#define PCM_TIMER_EVENT_LSB (1U << 18) /* 1b */
+#define PMIC_EINT_OUT_B_LSB (1U << 19) /* 2b */
+#define TWAM_IRQ_B_LSB (1U << 21) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_0_LSB (1U << 25) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_1_LSB (1U << 26) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_2_LSB (1U << 27) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_3_LSB (1U << 28) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_ALL_LSB (1U << 29) /* 1b */
+#define PMIC_IRQ_ACK_LSB (1U << 30) /* 1b */
+#define PMIC_SCP_IRQ_LSB (1U << 31) /* 1b */
+
+/* MM_DVFS_HALT (0x10006000 + 0x144) */
+#define MM_DVFS_HALT_LSB (1U << 0) /* 5b */
+
+/* BUS_PROTECT_RDY (0x10006000 + 0x150) */
+#define PROTECT_READY_LSB (1U << 0) /* 32b */
+
+/* BUS_PROTECT1_RDY (0x10006000 + 0x154) */
+#define PROTECT1_READY_LSB (1U << 0) /* 32b */
+
+/* BUS_PROTECT2_RDY (0x10006000 + 0x158) */
+#define PROTECT2_READY_LSB (1U << 0) /* 32b */
+/* BUS_PROTECT3_RDY (0x10006000 + 0x15C) */
+
+#define PROTECT3_READY_LSB (1U << 0) /* 32b */
+/* SUBSYS_IDLE_STA (0x10006000 + 0x160) */
+#define SUBSYS_IDLE_SIGNALS_LSB (1U << 0) /* 32b */
+/* PCM_STA (0x10006000 + 0x164) */
+
+#define PCM_CK_SEL_O_LSB (1U << 0) /* 4b */
+#define EXT_SRC_STA_LSB (1U << 4) /* 3b */
+
+/* SRC_REQ_STA_3 (0x10006000 + 0x168) */
+#define CCIF_EVENT_STATE_LSB (1U << 0) /* 1b */
+#define F26M_STATE_LSB (1U << 16) /* 1b */
+#define INFRA_STATE_LSB (1U << 17) /* 1b */
+#define APSRC_STATE_LSB (1U << 18) /* 1b */
+#define VRF18_STATE_LSB (1U << 19) /* 1b */
+#define DDREN_STATE_LSB (1U << 20) /* 1b */
+#define DVFS_STATE_LSB (1U << 21) /* 1b */
+#define SW_MAILBOX_STATE_LSB (1U << 22) /* 1b */
+#define SSPM_MAILBOX_STATE_LSB (1U << 23) /* 1b */
+#define ADSP_MAILBOX_STATE_LSB (1U << 24) /* 1b */
+#define SCP_MAILBOX_STATE_LSB (1U << 25) /* 1b */
+
+/* PWR_STATUS (0x10006000 + 0x16C) */
+#define PWR_STATUS_LSB (1U << 0) /* 32b */
+
+/* PWR_STATUS_2ND (0x10006000 + 0x170) */
+#define PWR_STATUS_2ND_LSB (1U << 0) /* 32b */
+
+/* CPU_PWR_STATUS (0x10006000 + 0x174) */
+#define MP0_SPMC_PWR_ON_ACK_CPU0_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU1_LSB (1U << 1) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU2_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU3_LSB (1U << 3) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU4_LSB (1U << 4) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU5_LSB (1U << 5) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU6_LSB (1U << 6) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU7_LSB (1U << 7) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPUTOP_LSB (1U << 8) /* 1b */
+#define MCUSYS_SPMC_PWR_ON_ACK_LSB (1U << 9) /* 1b */
+
+/* OTHER_PWR_STATUSi (0x10006000 + 0x178) */
+#define OTHER_PWR_STATUS_LSB (1U << 0) /* 32b */
+
+/* SPM_VTCXO_EVENT_COUNT_STA (0x10006000 + 0x17C) */
+#define SPM_SRCCLKENA_SLEEP_COUNT_LSB (1U << 0) /* 16b */
+#define SPM_SRCCLKENA_WAKE_COUNT_LSB (1U << 16) /* 16b */
+
+/* SPM_INFRA_EVENT_COUNT_STA (0x10006000 + 0x180) */
+#define SPM_INFRA_SLEEP_COUNT_LSB (1U << 0) /* 16b */
+#define SPM_INFRA_WAKE_COUNT_LSB (1U << 16) /* 16b */
+
+/* SPM_VRF18_EVENT_COUNT_STA (0x10006000 + 0x184) */
+#define SPM_VRF18_SLEEP_COUNT_LSB (1U << 0) /* 16b */
+#define SPM_VRF18_WAKE_COUNT_LSB (1U << 16) /* 16b */
+
+/* SPM_APSRC_EVENT_COUNT_STA (0x10006000 + 0x188) */
+#define SPM_APSRC_SLEEP_COUNT_LSB (1U << 0) /* 16b */
+#define SPM_APSRC_WAKE_COUNT_LSB (1U << 16) /* 16b */
+
+/* SPM_DDREN_EVENT_COUNT_STA (0x10006000 + 0x18C) */
+#define SPM_DDREN_SLEEP_COUNT_LSB (1U << 0) /* 16b */
+#define SPM_DDREN_WAKE_COUNT_LSB (1U << 16) /* 16b */
+
+/* MD32PCM_STA (0x10006000 + 0x190) */
+#define MD32PCM_HALT_LSB (1U << 0) /* 1b */
+#define MD32PCM_GATED_LSB (1U << 1) /* 1b */
+
+/* MD32PCM_PC (0x10006000 + 0x194) */
+#define MON_PC_LSB (1U << 0) /* 32b */
+
+/* DVFSRC_EVENT_STA (0x10006000 + 0x1A4) */
+#define DVFSRC_EVENT_LSB (1U << 0) /* 32b */
+
+/* BUS_PROTECT4_RDY (0x10006000 + 0x1A8) */
+#define PROTECT4_READY_LSB (1U << 0) /* 32b */
+
+/* BUS_PROTECT5_RDY (0x10006000 + 0x1AC) */
+#define PROTECT5_READY_LSB (1U << 0) /* 32b */
+
+/* BUS_PROTECT6_RDY (0x10006000 + 0x1B0) */
+#define PROTECT6_READY_LSB (1U << 0) /* 32b */
+
+/* BUS_PROTECT7_RDY (0x10006000 + 0x1B4) */
+#define PROTECT7_READY_LSB (1U << 0) /* 32b */
+
+/* BUS_PROTECT8_RDY (0x10006000 + 0x1B8) */
+#define PROTECT8_READY_LSB (1U << 0) /* 32b */
+
+/* SPM_TWAM_LAST_STA0 (0x10006000 + 0x1D0) */
+#define LAST_IDLE_CNT_0_LSB (1U << 0) /* 32b */
+
+/* SPM_TWAM_LAST_STA1 (0x10006000 + 0x1D4) */
+#define LAST_IDLE_CNT_1_LSB (1U << 0) /* 32b */
+
+/* SPM_TWAM_LAST_STA2 (0x10006000 + 0x1D8) */
+#define LAST_IDLE_CNT_2_LSB (1U << 0) /* 32b */
+
+/* SPM_TWAM_LAST_STA3 (0x10006000 + 0x1DC) */
+#define LAST_IDLE_CNT_3_LSB (1U << 0) /* 32b */
+
+/* SPM_TWAM_CURR_STA0 (0x10006000 + 0x1E0) */
+#define CURRENT_IDLE_CNT_0_LSB (1U << 0) /* 32b */
+
+/* SPM_TWAM_CURR_STA1 (0x10006000 + 0x1E4) */
+#define CURRENT_IDLE_CNT_1_LSB (1U << 0) /* 32b */
+
+/* SPM_TWAM_CURR_STA2 (0x10006000 + 0x1E8) */
+#define CURRENT_IDLE_CNT_2_LSB (1U << 0) /* 32b */
+
+/* SPM_TWAM_CURR_STA3 (0x10006000 + 0x1EC) */
+#define CURRENT_IDLE_CNT_3_LSB (1U << 0) /* 32b */
+
+/* SPM_TWAM_TIMER_OUT (0x10006000 + 0x1F0) */
+#define TWAM_TIMER_LSB (1U << 0) /* 32b */
+
+/* SPM_CG_CHECK_STA (0x10006000 + 0x1F4) */
+#define SPM_CG_CHECK_SLEEP_REQ_0_LSB (1U << 0) /* 1b */
+#define SPM_CG_CHECK_SLEEP_REQ_1_LSB (1U << 1) /* 1b */
+#define SPM_CG_CHECK_SLEEP_REQ_2_LSB (1U << 2) /* 1b */
+
+/* SPM_DVFS_STA (0x10006000 + 0x1F8) */
+#define TARGET_DVFS_LEVEL_LSB (1U << 0) /* 32b */
+
+/* SPM_DVFS_OPP_STA (0x10006000 + 0x1FC) */
+#define TARGET_DVFS_OPP_LSB (1U << 0) /* 5b */
+#define CURRENT_DVFS_OPP_LSB (1U << 5) /* 5b */
+#define RELAY_DVFS_OPP_LSB (1U << 10) /* 5b */
+
+/* SPM_MCUSYS_PWR_CON (0x10006000 + 0x200) */
+#define MCUSYS_SPMC_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MCUSYS_SPMC_PWR_ON_LSB (1U << 2) /* 1b */
+#define MCUSYS_SPMC_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MCUSYS_SPMC_RESETPWRON_CONFIG_LSB (1U << 5) /* 1b */
+#define MCUSYS_SPMC_DORMANT_EN_LSB (1U << 6) /* 1b */
+#define MCUSYS_VPROC_EXT_OFF_LSB (1U << 7) /* 1b */
+#define SPM_MCUSYS_PWR_CON_MCUSYS_SPMC_PWR_ON_ACK_LSB (1U << 31) /* 1b */
+
+/* SPM_CPUTOP_PWR_CON (0x10006000 + 0x204) */
+#define MP0_SPMC_PWR_RST_B_CPUTOP_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPUTOP_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_PWR_CLK_DIS_CPUTOP_LSB (1U << 4) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPUTOP_LSB (1U << 5) /* 1b */
+#define MP0_SPMC_DORMANT_EN_CPUTOP_LSB (1U << 6) /* 1b */
+#define MP0_VPROC_EXT_OFF_LSB (1U << 7) /* 1b */
+#define MP0_VSRAM_EXT_OFF_LSB (1U << 8) /* 1b */
+#define SPM_CPUTOP_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPUTOP_LSB (1U << 31) /* 1b */
+/* SPM_CPU0_PWR_CON (0x10006000 + 0x208) */
+#define MP0_SPMC_PWR_RST_B_CPU0_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU0_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU0_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU0_LSB (1U << 7) /* 1b */
+#define SPM_CPU0_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU0_LSB (1U << 31) /* 1b */
+
+/* SPM_CPU1_PWR_CON (0x10006000 + 0x20C) */
+#define MP0_SPMC_PWR_RST_B_CPU1_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU1_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU1_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU1_LSB (1U << 7) /* 1b */
+#define SPM_CPU1_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU1_LSB (1U << 31) /* 1b */
+
+/* SPM_CPU2_PWR_CON (0x10006000 + 0x210) */
+#define MP0_SPMC_PWR_RST_B_CPU2_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU2_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU2_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU2_LSB (1U << 7) /* 1b */
+#define SPM_CPU2_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU2_LSB (1U << 31) /* 1b */
+
+/* SPM_CPU3_PWR_CON (0x10006000 + 0x214) */
+#define MP0_SPMC_PWR_RST_B_CPU3_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU3_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU3_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU3_LSB (1U << 7) /* 1b */
+#define SPM_CPU3_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU3_LSB (1U << 31) /* 1b */
+
+/* SPM_CPU4_PWR_CON (0x10006000 + 0x218) */
+#define MP0_SPMC_PWR_RST_B_CPU4_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU4_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU4_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU4_LSB (1U << 7) /* 1b */
+#define SPM_CPU4_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU4_LSB (1U << 31) /* 1b */
+
+/* SPM_CPU5_PWR_CON (0x10006000 + 0x21C) */
+#define MP0_SPMC_PWR_RST_B_CPU5_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU5_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU5_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU5_LSB (1U << 7) /* 1b */
+#define SPM_CPU5_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU5_LSB (1U << 31) /* 1b */
+
+/* SPM_CPU6_PWR_CON (0x10006000 + 0x220) */
+#define MP0_SPMC_PWR_RST_B_CPU6_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU6_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU6_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU6_LSB (1U << 7) /* 1b */
+#define SPM_CPU6_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU6_LSB (1U << 31) /* 1b */
+
+/* SPM_CPU7_PWR_CON (0x10006000 + 0x224) */
+#define MP0_SPMC_PWR_RST_B_CPU7_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU7_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU7_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU7_LSB (1U << 7) /* 1b */
+#define SPM_CPU7_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU7_LSB (1U << 31) /* 1b */
+
+/* ARMPLL_CLK_CON (0x10006000 + 0x22C) */
+#define SC_ARM_FHC_PAUSE_LSB (1U << 0) /* 6b */
+#define SC_ARM_CK_OFF_LSB (1U << 6) /* 6b */
+#define SC_ARMPLL_OFF_LSB (1U << 12) /* 1b */
+#define SC_ARMBPLL_OFF_LSB (1U << 13) /* 1b */
+#define SC_ARMBPLL1_OFF_LSB (1U << 14) /* 1b */
+#define SC_ARMBPLL2_OFF_LSB (1U << 15) /* 1b */
+#define SC_ARMBPLL3_OFF_LSB (1U << 16) /* 1b */
+#define SC_CCIPLL_CKOFF_LSB (1U << 17) /* 1b */
+#define SC_ARMDDS_OFF_LSB (1U << 18) /* 1b */
+#define SC_ARMBPLL_S_OFF_LSB (1U << 19) /* 1b */
+#define SC_ARMBPLL1_S_OFF_LSB (1U << 20) /* 1b */
+#define SC_ARMBPLL2_S_OFF_LSB (1U << 21) /* 1b */
+#define SC_ARMBPLL3_S_OFF_LSB (1U << 22) /* 1b */
+#define SC_CCIPLL_PWROFF_LSB (1U << 23) /* 1b */
+#define SC_ARMPLLOUT_OFF_LSB (1U << 24) /* 1b */
+#define SC_ARMBPLLOUT_OFF_LSB (1U << 25) /* 1b */
+#define SC_ARMBPLLOUT1_OFF_LSB (1U << 26) /* 1b */
+#define SC_ARMBPLLOUT2_OFF_LSB (1U << 27) /* 1b */
+#define SC_ARMBPLLOUT3_OFF_LSB (1U << 28) /* 1b */
+#define SC_CCIPLL_OUT_OFF_LSB (1U << 29) /* 1b */
+
+/* MCUSYS_IDLE_STA (0x10006000 + 0x230) */
+#define ARMBUS_IDLE_TO_26M_LSB (1U << 0) /* 1b */
+#define MP0_CLUSTER_IDLE_TO_PWR_OFF_LSB (1U << 1) /* 1b */
+#define MCUSYS_DDR_EN_0_LSB (1U << 2) /* 1b */
+#define MCUSYS_DDR_EN_1_LSB (1U << 3) /* 1b */
+#define MCUSYS_DDR_EN_2_LSB (1U << 4) /* 1b */
+#define MCUSYS_DDR_EN_3_LSB (1U << 5) /* 1b */
+#define MCUSYS_DDR_EN_4_LSB (1U << 6) /* 1b */
+#define MCUSYS_DDR_EN_5_LSB (1U << 7) /* 1b */
+#define MCUSYS_DDR_EN_6_LSB (1U << 8) /* 1b */
+#define MCUSYS_DDR_EN_7_LSB (1U << 9) /* 1b */
+#define MP0_CPU_IDLE_TO_PWR_OFF_LSB (1U << 16) /* 8b */
+#define WFI_AF_SEL_LSB (1U << 24) /* 8b */
+
+/* GIC_WAKEUP_STA (0x10006000 + 0x234) */
+#define GIC_WAKEUP_STA_GIC_WAKEUP_LSB (1U << 10) /* 10b */
+
+/* CPU_SPARE_CON (0x10006000 + 0x238) */
+#define CPU_SPARE_CON_LSB (1U << 0) /* 32b */
+
+/* CPU_SPARE_CON_SET (0x10006000 + 0x23C) */
+#define CPU_SPARE_CON_SET_LSB (1U << 0) /* 32b */
+
+/* CPU_SPARE_CON_CLR (0x10006000 + 0x240) */
+#define CPU_SPARE_CON_CLR_LSB (1U << 0) /* 32b */
+
+/* ARMPLL_CLK_SEL (0x10006000 + 0x244) */
+#define ARMPLL_CLK_SEL_LSB (1U << 0) /* 15b */
+
+/* EXT_INT_WAKEUP_REQ (0x10006000 + 0x248) */
+#define EXT_INT_WAKEUP_REQ_LSB (1U << 0) /* 10b */
+
+/* EXT_INT_WAKEUP_REQ_SET (0x10006000 + 0x24C) */
+#define EXT_INT_WAKEUP_REQ_SET_LSB (1U << 0) /* 10b */
+
+/* EXT_INT_WAKEUP_REQ_CLR (0x10006000 + 0x250) */
+#define EXT_INT_WAKEUP_REQ_CLR_LSB (1U << 0) /* 10b */
+
+/* CPU_IRQ_MASK (0x10006000 + 0x260) */
+#define CPU_IRQ_MASK_LSB (1U << 0) /* 8b */
+
+/* CPU_IRQ_MASK_SET (0x10006000 + 0x264) */
+#define CPU_IRQ_MASK_SET_LSB (1U << 0) /* 8b */
+
+/* CPU_IRQ_MASK_CLR (0x10006000 + 0x268) */
+#define CPU_IRQ_MASK_CLR_LSB (1U << 0) /* 8b */
+
+/* CPU_WFI_EN (0x10006000 + 0x280) */
+#define CPU_WFI_EN_LSB (1U << 0) /* 8b */
+
+/* CPU_WFI_EN_SET (0x10006000 + 0x284) */
+#define CPU_WFI_EN_SET_LSB (1U << 0) /* 8b */
+
+/* CPU_WFI_EN_CLR (0x10006000 + 0x288) */
+#define CPU_WFI_EN_CLR_LSB (1U << 0) /* 8b */
+
+/* ROOT_CPUTOP_ADDR (0x10006000 + 0x2A0) */
+#define ROOT_CPUTOP_ADDR_LSB (1U << 0) /* 32b */
+
+/* ROOT_CORE_ADDR (0x10006000 + 0x2A4) */
+#define ROOT_CORE_ADDR_LSB (1U << 0) /* 32b */
+
+/* SPM2SW_MAILBOX_0 (0x10006000 + 0x2D0) */
+#define SPM2SW_MAILBOX_0_LSB (1U << 0) /* 32b */
+
+/* SPM2SW_MAILBOX_1 (0x10006000 + 0x2D4) */
+#define SPM2SW_MAILBOX_1_LSB (1U << 0) /* 32b */
+
+/* SPM2SW_MAILBOX_2 (0x10006000 + 0x2D8) */
+#define SPM2SW_MAILBOX_2_LSB (1U << 0) /* 32b */
+
+/* SPM2SW_MAILBOX_3 (0x10006000 + 0x2DC) */
+#define SPM2SW_MAILBOX_3_LSB (1U << 0) /* 32b */
+
+/* SW2SPM_WAKEUP (0x10006000 + 0x2E0) */
+#define SW2SPM_WAKEUP_SW2SPM_WAKEUP_LSB (1U << 0) /* 4b */
+
+/* SW2SPM_WAKEUP_SET (0x10006000 + 0x2E4) */
+#define SW2SPM_WAKEUP_SET_LSB (1U << 0) /* 4b */
+
+/* SW2SPM_WAKEUP_CLR (0x10006000 + 0x2E8) */
+#define SW2SPM_WAKEUP_CLR_LSB (1U << 0) /* 4b */
+
+/* SW2SPM_MAILBOX_0 (0x10006000 + 0x2EC) */
+#define SW2SPM_MAILBOX_0_LSB (1U << 0) /* 32b */
+
+/* SW2SPM_MAILBOX_1 (0x10006000 + 0x2F0) */
+#define SW2SPM_MAILBOX_1_LSB (1U << 0) /* 32b */
+
+/* SW2SPM_MAILBOX_2 (0x10006000 + 0x2F4) */
+#define SW2SPM_MAILBOX_2_LSB (1U << 0) /* 32b */
+
+/* SW2SPM_MAILBOX_3 (0x10006000 + 0x2F8) */
+#define SW2SPM_MAILBOX_3_LSB (1U << 0) /* 32b */
+
+/* SW2SPM_CFG (0x10006000 + 0x2FC) */
+#define SWU2SPM_INT_MASK_B_LSB (1U << 0) /* 4b */
+
+/* MD1_PWR_CON (0x10006000 + 0x300) */
+#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 */
+#define SC_MD1_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* CONN_PWR_CON (0x10006000 + 0x304) */
+#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 */
+
+/* MFG0_PWR_CON (0x10006000 + 0x308) */
+#define MFG0_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG0_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG0_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG0_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG0_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG0_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG0_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* MFG1_PWR_CON (0x10006000 + 0x30C) */
+#define MFG1_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG1_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG1_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG1_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG1_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG1_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG1_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* MFG2_PWR_CON (0x10006000 + 0x310) */
+#define MFG2_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG2_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG2_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG2_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG2_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG2_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG2_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* MFG3_PWR_CON (0x10006000 + 0x314) */
+#define MFG3_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG3_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG3_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG3_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG3_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG3_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG3_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* MFG4_PWR_CON (0x10006000 + 0x318) */
+#define MFG4_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG4_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG4_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG4_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG4_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG4_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG4_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* MFG5_PWR_CON (0x10006000 + 0x31C) */
+#define MFG5_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG5_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG5_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG5_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG5_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG5_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG5_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* MFG6_PWR_CON (0x10006000 + 0x320) */
+#define MFG6_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG6_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG6_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG6_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG6_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG6_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG6_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* IFR_PWR_CON (0x10006000 + 0x324) */
+#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) /* 1b */
+#define SC_IFR_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* IFR_SUB_PWR_CON (0x10006000 + 0x328) */
+#define IFR_SUB_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define IFR_SUB_PWR_ISO_LSB (1U << 1) /* 1b */
+#define IFR_SUB_PWR_ON_LSB (1U << 2) /* 1b */
+#define IFR_SUB_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define IFR_SUB_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define IFR_SUB_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_IFR_SUB_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* DPY_PWR_CON (0x10006000 + 0x32C) */
+#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 */
+
+/* DRAMC_MD32_PWR_CON (0x10006000 + 0x330) */
+#define DRAMC_MD32_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define DRAMC_MD32_PWR_ISO_LSB (1U << 1) /* 1b */
+#define DRAMC_MD32_PWR_ON_LSB (1U << 2) /* 1b */
+#define DRAMC_MD32_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define DRAMC_MD32_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define DRAMC_MD32_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_DRAMC_MD32_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* ISP_PWR_CON (0x10006000 + 0x334) */
+#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) /* 1b */
+#define SC_ISP_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* ISP2_PWR_CON (0x10006000 + 0x338) */
+#define ISP2_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define ISP2_PWR_ISO_LSB (1U << 1) /* 1b */
+#define ISP2_PWR_ON_LSB (1U << 2) /* 1b */
+#define ISP2_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define ISP2_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define ISP2_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_ISP2_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* IPE_PWR_CON (0x10006000 + 0x33C) */
+#define IPE_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define IPE_PWR_ISO_LSB (1U << 1) /* 1b */
+#define IPE_PWR_ON_LSB (1U << 2) /* 1b */
+#define IPE_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define IPE_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define IPE_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_IPE_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* VDE_PWR_CON (0x10006000 + 0x340) */
+#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) /* 1b */
+#define SC_VDE_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* VDE2_PWR_CON (0x10006000 + 0x344) */
+#define VDE2_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define VDE2_PWR_ISO_LSB (1U << 1) /* 1b */
+#define VDE2_PWR_ON_LSB (1U << 2) /* 1b */
+#define VDE2_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define VDE2_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define VDE2_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_VDE2_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* VEN_PWR_CON (0x10006000 + 0x348) */
+#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) /* 1b */
+#define SC_VEN_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* VEN_CORE1_PWR_CON (0x10006000 + 0x34C) */
+#define VEN_CORE1_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define VEN_CORE1_PWR_ISO_LSB (1U << 1) /* 1b */
+#define VEN_CORE1_PWR_ON_LSB (1U << 2) /* 1b */
+#define VEN_CORE1_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define VEN_CORE1_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define VEN_CORE1_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_VEN_CORE1_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* MDP_PWR_CON (0x10006000 + 0x350) */
+#define MDP_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MDP_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MDP_PWR_ON_LSB (1U << 2) /* 1b */
+#define MDP_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MDP_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MDP_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MDP_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* DIS_PWR_CON (0x10006000 + 0x354) */
+#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) /* 1b */
+#define SC_DIS_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* AUDIO_PWR_CON (0x10006000 + 0x358) */
+#define AUDIO_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define AUDIO_PWR_ISO_LSB (1U << 1) /* 1b */
+#define AUDIO_PWR_ON_LSB (1U << 2) /* 1b */
+#define AUDIO_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define AUDIO_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define AUDIO_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_AUDIO_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* CAM_PWR_CON (0x10006000 + 0x35C) */
+#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) /* 1b */
+#define SC_CAM_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* CAM_RAWA_PWR_CON (0x10006000 + 0x360) */
+#define CAM_RAWA_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define CAM_RAWA_PWR_ISO_LSB (1U << 1) /* 1b */
+#define CAM_RAWA_PWR_ON_LSB (1U << 2) /* 1b */
+#define CAM_RAWA_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define CAM_RAWA_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define CAM_RAWA_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_CAM_RAWA_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* CAM_RAWB_PWR_CON (0x10006000 + 0x364) */
+#define CAM_RAWB_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define CAM_RAWB_PWR_ISO_LSB (1U << 1) /* 1b */
+#define CAM_RAWB_PWR_ON_LSB (1U << 2) /* 1b */
+#define CAM_RAWB_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define CAM_RAWB_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define CAM_RAWB_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_CAM_RAWB_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* CAM_RAWC_PWR_CON (0x10006000 + 0x368) */
+#define CAM_RAWC_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define CAM_RAWC_PWR_ISO_LSB (1U << 1) /* 1b */
+#define CAM_RAWC_PWR_ON_LSB (1U << 2) /* 1b */
+#define CAM_RAWC_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define CAM_RAWC_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define CAM_RAWC_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_CAM_RAWC_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* SYSRAM_CON (0x10006000 + 0x36C) */
+#define SYSRAM_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define SYSRAM_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define SYSRAM_SRAM_SLEEP_B_LSB (1U << 4) /* 4b */
+#define SYSRAM_SRAM_PDN_LSB (1U << 16) /* 4b */
+
+/* SYSROM_CON (0x10006000 + 0x370) */
+#define SYSROM_SRAM_PDN_LSB (1U << 0) /* 8b */
+
+/* SSPM_SRAM_CON (0x10006000 + 0x374) */
+#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 + 0x378) */
+#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 */
+
+/* DPY_SHU_SRAM_CON (0x10006000 + 0x37C) */
+#define DPY_SHU_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DPY_SHU_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DPY_SHU_SRAM_SLEEP_B_LSB (1U << 4) /* 2b */
+#define DPY_SHU_SRAM_PDN_LSB (1U << 16) /* 2b */
+
+/* UFS_SRAM_CON (0x10006000 + 0x380) */
+#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) /* 8b */
+#define UFS_SRAM_PDN_LSB (1U << 16) /* 8b */
+
+/* DEVAPC_IFR_SRAM_CON (0x10006000 + 0x384) */
+#define DEVAPC_IFR_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DEVAPC_IFR_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DEVAPC_IFR_SRAM_SLEEP_B_LSB (1U << 4) /* 6b */
+#define DEVAPC_IFR_SRAM_PDN_LSB (1U << 16) /* 6b */
+
+/* DEVAPC_SUBIFR_SRAM_CON (0x10006000 + 0x388) */
+#define DEVAPC_SUBIFR_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DEVAPC_SUBIFR_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DEVAPC_SUBIFR_SRAM_SLEEP_B_LSB (1U << 4) /* 12b */
+#define DEVAPC_SUBIFR_SRAM_PDN_LSB (1U << 16) /* 12b */
+
+/* DEVAPC_ACP_SRAM_CON (0x10006000 + 0x38C) */
+#define DEVAPC_ACP_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DEVAPC_ACP_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DEVAPC_ACP_SRAM_SLEEP_B_LSB (1U << 4) /* 12b */
+#define DEVAPC_ACP_SRAM_PDN_LSB (1U << 16) /* 12b */
+
+/* USB_SRAM_CON (0x10006000 + 0x390) */
+#define USB_SRAM_PDN_LSB (1U << 0) /* 9b */
+
+/* DUMMY_SRAM_CONi (0x10006000 + 0x394) */
+#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) /* 12b */
+#define DUMMY_SRAM_PDN_LSB (1U << 16) /* 12b */
+
+/* MD_EXT_BUCK_ISO_CON (0x10006000 + 0x398) */
+#define VMODEM_EXT_BUCK_ISO_LSB (1U << 0) /* 1b */
+#define VMD_EXT_BUCK_ISO_LSB (1U << 1) /* 1b */
+
+/* EXT_BUCK_ISO (0x10006000 + 0x39C) */
+#define VIMVO_EXT_BUCK_ISO_LSB (1U << 0) /* 1b */
+#define GPU_EXT_BUCK_ISO_LSB (1U << 1) /* 1b */
+#define ADSP_EXT_BUCK_ISO_LSB (1U << 2) /* 1b */
+#define IPU_EXT_BUCK_ISO_LSB (1U << 5) /* 3b */
+
+/* DXCC_SRAM_CON (0x10006000 + 0x3A0) */
+#define DXCC_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DXCC_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DXCC_SRAM_SLEEP_B_LSB (1U << 4) /* 8b */
+#define DXCC_SRAM_PDN_LSB (1U << 16) /* 8b */
+
+/* MSDC_PWR_CON (0x10006000 + 0x3A4) */
+#define MSDC_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MSDC_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MSDC_PWR_ON_LSB (1U << 2) /* 1b */
+#define MSDC_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MSDC_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MSDC_SRAM_CKISO_LSB (1U << 5) /* 1b */
+#define MSDC_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */
+#define MSDC_SRAM_PDN_LSB (1U << 8) /* 5b */
+#define MSDC_SRAM_SLEEP_B_LSB (1U << 13) /* 5b */
+#define SC_MSDC_SRAM_PDN_ACK_LSB (1U << 18) /* 5b */
+#define SC_MSDC_SRAM_SLEEP_B_ACK_LSB (1U << 23) /* 5b */
+
+/* DEBUGTOP_SRAM_CON (0x10006000 + 0x3A8) */
+#define DEBUGTOP_SRAM_PDN_LSB (1U << 0) /* 1b */
+
+/* DP_TX_PWR_CON (0x10006000 + 0x3AC) */
+#define DP_TX_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define DP_TX_PWR_ISO_LSB (1U << 1) /* 1b */
+#define DP_TX_PWR_ON_LSB (1U << 2) /* 1b */
+#define DP_TX_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define DP_TX_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define DP_TX_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_DP_TX_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* DPMAIF_SRAM_CON (0x10006000 + 0x3B0) */
+#define DPMAIF_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DPMAIF_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DPMAIF_SRAM_SLEEP_B_LSB (1U << 4) /* 1b */
+#define DPMAIF_SRAM_PDN_LSB (1U << 16) /* 1b */
+
+/* DPY_SHU2_SRAM_CON (0x10006000 + 0x3B4) */
+#define DPY_SHU2_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DPY_SHU2_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DPY_SHU2_SRAM_SLEEP_B_LSB (1U << 4) /* 12b */
+#define DPY_SHU2_SRAM_PDN_LSB (1U << 16) /* 12b */
+
+/* DRAMC_MCU2_SRAM_CON (0x10006000 + 0x3B8) */
+#define DRAMC_MCU2_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DRAMC_MCU2_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DRAMC_MCU2_SRAM_SLEEP_B_LSB (1U << 4) /* 12b */
+#define DRAMC_MCU2_SRAM_PDN_LSB (1U << 16) /* 12b */
+
+/* DRAMC_MCU_SRAM_CON (0x10006000 + 0x3BC) */
+#define DRAMC_MCU_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DRAMC_MCU_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DRAMC_MCU_SRAM_SLEEP_B_LSB (1U << 4) /* 12b */
+#define DRAMC_MCU_SRAM_PDN_LSB (1U << 16) /* 12b */
+
+/* MCUPM_PWR_CON (0x10006000 + 0x3C0) */
+#define MCUPM_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MCUPM_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MCUPM_PWR_ON_LSB (1U << 2) /* 1b */
+#define MCUPM_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MCUPM_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MCUPM_SRAM_CKISO_LSB (1U << 5) /* 1b */
+#define MCUPM_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */
+#define MCUPM_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define MCUPM_SRAM_SLEEP_B_LSB (1U << 9) /* 1b */
+#define SC_MCUPM_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+#define SC_MCUPM_SRAM_SLEEP_B_ACK_LSB (1U << 13) /* 1b */
+#define MCUPM_WFI_LSB (1U << 14) /* 1b */
+
+/* DPY2_PWR_CON (0x10006000 + 0x3C4) */
+#define DPY2_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define DPY2_PWR_ISO_LSB (1U << 1) /* 1b */
+#define DPY2_PWR_ON_LSB (1U << 2) /* 1b */
+#define DPY2_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define DPY2_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define DPY2_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_DPY2_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* SPM_SRAM_CON (0x10006000 + 0x3C8) */
+#define SPM_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define REG_SPM_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define REG_SPM_SRAM_SLEEP_B_LSB (1U << 4) /* 2b */
+#define SPM_SRAM_PDN_LSB (1U << 16) /* 2b */
+
+/* PERI_PWR_CON (0x10006000 + 0x3D0) */
+#define PERI_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define PERI_PWR_ISO_LSB (1U << 1) /* 1b */
+#define PERI_PWR_ON_LSB (1U << 2) /* 1b */
+#define PERI_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define PERI_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define PERI_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_PERI_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* NNA0_PWR_CON (0x10006000 + 0x3D4) */
+#define NNA0_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define NNA0_PWR_ISO_LSB (1U << 1) /* 1b */
+#define NNA0_PWR_ON_LSB (1U << 2) /* 1b */
+#define NNA0_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define NNA0_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define NNA0_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_NNA0_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* NNA1_PWR_CON (0x10006000 + 0x3D8) */
+#define NNA1_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define NNA1_PWR_ISO_LSB (1U << 1) /* 1b */
+#define NNA1_PWR_ON_LSB (1U << 2) /* 1b */
+#define NNA1_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define NNA1_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define NNA1_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_NNA1_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* NNA2_PWR_CON (0x10006000 + 0x3DC) */
+#define NNA2_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define NNA2_PWR_ISO_LSB (1U << 1) /* 1b */
+#define NNA2_PWR_ON_LSB (1U << 2) /* 1b */
+#define NNA2_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define NNA2_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define NNA2_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_NNA2_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* NNA_PWR_CON (0x10006000 + 0x3E0) */
+#define NNA_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define NNA_PWR_ISO_LSB (1U << 1) /* 1b */
+#define NNA_PWR_ON_LSB (1U << 2) /* 1b */
+#define NNA_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define NNA_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define NNA_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_NNA_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+
+/* ADSP_PWR_CON (0x10006000 + 0x3E4) */
+#define ADSP_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define ADSP_PWR_ISO_LSB (1U << 1) /* 1b */
+#define ADSP_PWR_ON_LSB (1U << 2) /* 1b */
+#define ADSP_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define ADSP_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define ADSP_SRAM_CKISO_LSB (1U << 5) /* 1b */
+#define ADSP_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */
+#define ADSP_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define ADSP_SRAM_SLEEP_B_LSB (1U << 9) /* 1b */
+#define SC_ADSP_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+#define SC_ADSP_SRAM_SLEEP_B_ACK_LSB (1U << 13) /* 1b */
+
+/* DPY_SRAM_CON (0x10006000 + 0x3E8) */
+#define DPY_SRAM_PDN_LSB (1U << 16) /* 4b */
+#define SC_DPY_SRAM_PDN_ACK_LSB (1U << 24) /* 4b */
+
+/* SPM_MEM_CK_SEL (0x10006000 + 0x400) */
+#define SC_MEM_CK_SEL_LSB (1U << 0) /* 1b */
+#define SPM2CKSYS_MEM_CK_MUX_UPDATE_LSB (1U << 1) /* 1b */
+
+/* SPM_BUS_PROTECT_MASK_B (0x10006000 + 0X404) */
+#define SPM_BUS_PROTECT_MASK_B_LSB (1U << 0) /* 32b */
+
+/* SPM_BUS_PROTECT1_MASK_B (0x10006000 + 0x408) */
+#define SPM_BUS_PROTECT1_MASK_B_LSB (1U << 0) /* 32b */
+
+/* SPM_BUS_PROTECT2_MASK_B (0x10006000 + 0x40C) */
+#define SPM_BUS_PROTECT2_MASK_B_LSB (1U << 0) /* 32b */
+
+/* SPM_BUS_PROTECT3_MASK_B (0x10006000 + 0x410) */
+#define SPM_BUS_PROTECT3_MASK_B_LSB (1U << 0) /* 32b */
+
+/* SPM_BUS_PROTECT4_MASK_B (0x10006000 + 0x414) */
+#define SPM_BUS_PROTECT4_MASK_B_LSB (1U << 0) /* 32b */
+
+/* SPM_EMI_BW_MODE (0x10006000 + 0x418) */
+#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 */
+#define SPM_S1_MODE_CH_LSB (1U << 16) /* 2b */
+
+/* AP2MD_PEER_WAKEUP (0x10006000 + 0x41C) */
+#define AP2MD_PEER_WAKEUP_LSB (1U << 0) /* 1b */
+
+/* ULPOSC_CON (0x10006000 + 0x420) */
+#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 + 0x424) */
+#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_D2T_LSB (1U << 16) /* 1b */
+#define MM2SPM_DBL_OSTD_ACT_ACK_D2T_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 */
+
+/* SPM_BUS_PROTECT5_MASK_B (0x10006000 + 0x428) */
+#define SPM_BUS_PROTECT5_MASK_B_LSB (1U << 0) /* 32b */
+
+/* SPM2MCUPM_CON (0x10006000 + 0x42C) */
+#define SPM2MCUPM_SW_RST_B_LSB (1U << 0) /* 1b */
+#define SPM2MCUPM_SW_INT_LSB (1U << 1) /* 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 */
+
+/* SPM2EMI_ENTER_ULPM (0x10006000 + 0x434) */
+#define SPM2EMI_ENTER_ULPM_LSB (1U << 0) /* 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 */
+
+/* SPM_BUS_PROTECT6_MASK_B (0x10006000 + 0X440) */
+#define SPM_BUS_PROTECT6_MASK_B_LSB (1U << 0) /* 32b */
+
+/* SPM_BUS_PROTECT7_MASK_B (0x10006000 + 0x444) */
+#define SPM_BUS_PROTECT7_MASK_B_LSB (1U << 0) /* 32b */
+
+/* SPM_BUS_PROTECT8_MASK_B (0x10006000 + 0x448) */
+#define SPM_BUS_PROTECT8_MASK_B_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_SPAREPLLOUT_OFF_LSB (1U << 2) /* 2b */
+#define SC_MAINPLL_OFF_LSB (1U << 4) /* 1b */
+#define SC_UNIPLL_OFF_LSB (1U << 5) /* 1b */
+#define SC_SPAREPLL_OFF_LSB (1U << 6) /* 2b */
+#define SC_MAINPLL_S_OFF_LSB (1U << 8) /* 1b */
+#define SC_UNIPLL_S_OFF_LSB (1U << 9) /* 1b */
+#define SC_SPAREPLL_S_OFF_LSB (1U << 10) /* 2b */
+#define SC_SPARE_CK_OFF_LSB (1U << 12) /* 4b */
+#define SC_SMI_CK_OFF_LSB (1U << 16) /* 1b */
+#define SC_MD32K_CK_OFF_LSB (1U << 17) /* 1b */
+#define SC_CKSQ1_OFF_LSB (1U << 18) /* 1b */
+#define SC_AXI_MEM_CK_OFF_LSB (1U << 19) /* 1b */
+#define SC_CLK_BACKUP_LSB (1U << 20) /* 12b */
+
+/* RC_SPM_CTRL (0x10006000 + 0x450) */
+#define SPM_AP_26M_RDY_LSB (1U << 0) /* 1b */
+#define SPM2RC_DMY_CTRL_LSB (1U << 2) /* 6b */
+#define RC2SPM_SRCCLKENO_0_ACK_LSB (1U << 16) /* 1b */
+
+/* SPM_DRAM_MCU_SW_CON_0 (0x10006000 + 0x454) */
+#define SW_DDR_PST_REQ_LSB (1U << 0) /* 2b */
+#define SW_DDR_PST_ABORT_REQ_LSB (1U << 2) /* 2b */
+
+/* SPM_DRAM_MCU_SW_CON_1 (0x10006000 + 0x458) */
+#define SW_DDR_PST_CH0_LSB (1U << 0) /* 32b */
+
+/* SPM_DRAM_MCU_SW_CON_2 (0x10006000 + 0x45C) */
+#define SW_DDR_PST_CH1_LSB (1U << 0) /* 32b */
+
+/* SPM_DRAM_MCU_SW_CON_3 (0x10006000 + 0x460) */
+#define SW_DDR_RESERVED_CH0_LSB (1U << 0) /* 32b */
+
+/* SPM_DRAM_MCU_SW_CON_4 (0x10006000 + 0x464) */
+#define SW_DDR_RESERVED_CH1_LSB (1U << 0) /* 32b */
+
+/* SPM_DRAM_MCU_STA_0 (0x10006000 + 0x468) */
+#define SC_DDR_PST_ACK_LSB (1U << 0) /* 2b */
+#define SC_DDR_PST_ABORT_ACK_LSB (1U << 2) /* 2b */
+
+/* SPM_DRAM_MCU_STA_1 (0x10006000 + 0x46C) */
+#define SC_DDR_CUR_PST_STA_CH0_LSB (1U << 0) /* 32b */
+
+/* SPM_DRAM_MCU_STA_2 (0x10006000 + 0x470) */
+#define SC_DDR_CUR_PST_STA_CH1_LSB (1U << 0) /* 32b */
+
+/* SPM_DRAM_MCU_SW_SEL_0 (0x10006000 + 0x474) */
+#define SW_DDR_PST_REQ_SEL_LSB (1U << 0) /* 2b */
+#define SW_DDR_PST_SEL_LSB (1U << 2) /* 2b */
+#define SW_DDR_PST_ABORT_REQ_SEL_LSB (1U << 4) /* 2b */
+#define SW_DDR_RESERVED_SEL_LSB (1U << 6) /* 2b */
+#define SW_DDR_PST_ACK_SEL_LSB (1U << 8) /* 2b */
+#define SW_DDR_PST_ABORT_ACK_SEL_LSB (1U << 10) /* 2b */
+
+/* RELAY_DVFS_LEVEL (0x10006000 + 0x478) */
+#define RELAY_DVFS_LEVEL_LSB (1U << 0) /* 32b */
+
+/* DRAMC_DPY_CLK_SW_CON_0 (0x10006000 + 0x480) */
+#define SW_PHYPLL_EN_LSB (1U << 0) /* 2b */
+#define SW_DPY_VREF_EN_LSB (1U << 2) /* 2b */
+#define SW_DPY_DLL_CK_EN_LSB (1U << 4) /* 2b */
+#define SW_DPY_DLL_EN_LSB (1U << 6) /* 2b */
+#define SW_DPY_2ND_DLL_EN_LSB (1U << 8) /* 2b */
+#define SW_MEM_CK_OFF_LSB (1U << 10) /* 2b */
+#define SW_DMSUS_OFF_LSB (1U << 12) /* 2b */
+#define SW_DPY_MODE_SW_LSB (1U << 14) /* 2b */
+#define SW_EMI_CLK_OFF_LSB (1U << 16) /* 2b */
+#define SW_DDRPHY_FB_CK_EN_LSB (1U << 18) /* 2b */
+#define SW_DR_GATE_RETRY_EN_LSB (1U << 20) /* 2b */
+#define SW_DPHY_PRECAL_UP_LSB (1U << 24) /* 2b */
+#define SW_DPY_BCLK_ENABLE_LSB (1U << 26) /* 2b */
+#define SW_TX_TRACKING_DIS_LSB (1U << 28) /* 2b */
+#define SW_DPHY_RXDLY_TRACKING_EN_LSB (1U << 30) /* 2b */
+
+/* DRAMC_DPY_CLK_SW_CON_1 (0x10006000 + 0x484) */
+#define SW_SHU_RESTORE_LSB (1U << 0) /* 2b */
+#define SW_DMYRD_MOD_LSB (1U << 2) /* 2b */
+#define SW_DMYRD_INTV_LSB (1U << 4) /* 2b */
+#define SW_DMYRD_EN_LSB (1U << 6) /* 2b */
+#define SW_DRS_DIS_REQ_LSB (1U << 8) /* 2b */
+#define SW_DR_SRAM_LOAD_LSB (1U << 10) /* 2b */
+#define SW_DR_SRAM_RESTORE_LSB (1U << 12) /* 2b */
+#define SW_DR_SHU_LEVEL_SRAM_LATCH_LSB (1U << 14) /* 2b */
+#define SW_TX_TRACK_RETRY_EN_LSB (1U << 16) /* 2b */
+#define SW_DPY_MIDPI_EN_LSB (1U << 18) /* 2b */
+#define SW_DPY_PI_RESETB_EN_LSB (1U << 20) /* 2b */
+#define SW_DPY_MCK8X_EN_LSB (1U << 22) /* 2b */
+#define SW_DR_SHU_LEVEL_SRAM_CH0_LSB (1U << 24) /* 4b */
+#define SW_DR_SHU_LEVEL_SRAM_CH1_LSB (1U << 28) /* 4b */
+
+/* DRAMC_DPY_CLK_SW_CON_2 (0x10006000 + 0x488) */
+#define SW_DR_SHU_LEVEL_LSB (1U << 0) /* 2b */
+#define SW_DR_SHU_EN_LSB (1U << 2) /* 1b */
+#define SW_DR_SHORT_QUEUE_LSB (1U << 3) /* 1b */
+#define SW_PHYPLL_MODE_SW_LSB (1U << 4) /* 1b */
+#define SW_PHYPLL2_MODE_SW_LSB (1U << 5) /* 1b */
+#define SW_PHYPLL_SHU_EN_LSB (1U << 6) /* 1b */
+#define SW_PHYPLL2_SHU_EN_LSB (1U << 7) /* 1b */
+#define SW_DR_RESERVED_0_LSB (1U << 24) /* 2b */
+#define SW_DR_RESERVED_1_LSB (1U << 26) /* 2b */
+#define SW_DR_RESERVED_2_LSB (1U << 28) /* 2b */
+#define SW_DR_RESERVED_3_LSB (1U << 30) /* 2b */
+
+/* DRAMC_DPY_CLK_SW_CON_3 (0x10006000 + 0x48C) */
+#define SC_DR_SHU_EN_ACK_LSB (1U << 0) /* 4b */
+#define SC_EMI_CLK_OFF_ACK_LSB (1U << 4) /* 4b */
+#define SC_DR_SHORT_QUEUE_ACK_LSB (1U << 8) /* 4b */
+#define SC_DRAMC_DFS_STA_LSB (1U << 12) /* 4b */
+#define SC_DRS_DIS_ACK_LSB (1U << 16) /* 4b */
+#define SC_DR_SRAM_LOAD_ACK_LSB (1U << 20) /* 4b */
+#define SC_DR_SRAM_PLL_LOAD_ACK_LSB (1U << 24) /* 4b */
+#define SC_DR_SRAM_RESTORE_ACK_LSB (1U << 28) /* 4b */
+
+/* DRAMC_DPY_CLK_SW_SEL_0 (0x10006000 + 0x490) */
+#define SW_PHYPLL_EN_SEL_LSB (1U << 0) /* 2b */
+#define SW_DPY_VREF_EN_SEL_LSB (1U << 2) /* 2b */
+#define SW_DPY_DLL_CK_EN_SEL_LSB (1U << 4) /* 2b */
+#define SW_DPY_DLL_EN_SEL_LSB (1U << 6) /* 2b */
+#define SW_DPY_2ND_DLL_EN_SEL_LSB (1U << 8) /* 2b */
+#define SW_MEM_CK_OFF_SEL_LSB (1U << 10) /* 2b */
+#define SW_DMSUS_OFF_SEL_LSB (1U << 12) /* 2b */
+#define SW_DPY_MODE_SW_SEL_LSB (1U << 14) /* 2b */
+#define SW_EMI_CLK_OFF_SEL_LSB (1U << 16) /* 2b */
+#define SW_DDRPHY_FB_CK_EN_SEL_LSB (1U << 18) /* 2b */
+#define SW_DR_GATE_RETRY_EN_SEL_LSB (1U << 20) /* 2b */
+#define SW_DPHY_PRECAL_UP_SEL_LSB (1U << 24) /* 2b */
+#define SW_DPY_BCLK_ENABLE_SEL_LSB (1U << 26) /* 2b */
+#define SW_TX_TRACKING_DIS_SEL_LSB (1U << 28) /* 2b */
+#define SW_DPHY_RXDLY_TRACKING_EN_SEL_LSB (1U << 30) /* 2b */
+
+/* DRAMC_DPY_CLK_SW_SEL_1 (0x10006000 + 0x494) */
+#define SW_SHU_RESTORE_SEL_LSB (1U << 0) /* 2b */
+#define SW_DMYRD_MOD_SEL_LSB (1U << 2) /* 2b */
+#define SW_DMYRD_INTV_SEL_LSB (1U << 4) /* 2b */
+#define SW_DMYRD_EN_SEL_LSB (1U << 6) /* 2b */
+#define SW_DRS_DIS_REQ_SEL_LSB (1U << 8) /* 2b */
+#define SW_DR_SRAM_LOAD_SEL_LSB (1U << 10) /* 2b */
+#define SW_DR_SRAM_RESTORE_SEL_LSB (1U << 12) /* 2b */
+#define SW_DR_SHU_LEVEL_SRAM_LATCH_SEL_LSB (1U << 14) /* 2b */
+#define SW_TX_TRACK_RETRY_EN_SEL_LSB (1U << 16) /* 2b */
+#define SW_DPY_MIDPI_EN_SEL_LSB (1U << 18) /* 2b */
+#define SW_DPY_PI_RESETB_EN_SEL_LSB (1U << 20) /* 2b */
+#define SW_DPY_MCK8X_EN_SEL_LSB (1U << 22) /* 2b */
+#define SW_DR_SHU_LEVEL_SRAM_SEL_LSB (1U << 24) /* 2b */
+
+/* DRAMC_DPY_CLK_SW_SEL_2 (0x10006000 + 0x498) */
+#define SW_DR_SHU_LEVEL_SEL_LSB (1U << 0) /* 1b */
+#define SW_DR_SHU_EN_SEL_LSB (1U << 2) /* 1b */
+#define SW_DR_SHORT_QUEUE_SEL_LSB (1U << 3) /* 1b */
+#define SW_PHYPLL_MODE_SW_SEL_LSB (1U << 4) /* 1b */
+#define SW_PHYPLL2_MODE_SW_SEL_LSB (1U << 5) /* 1b */
+#define SW_PHYPLL_SHU_EN_SEL_LSB (1U << 6) /* 1b */
+#define SW_PHYPLL2_SHU_EN_SEL_LSB (1U << 7) /* 1b */
+#define SW_DR_RESERVED_0_SEL_LSB (1U << 24) /* 2b */
+#define SW_DR_RESERVED_1_SEL_LSB (1U << 26) /* 2b */
+#define SW_DR_RESERVED_2_SEL_LSB (1U << 28) /* 2b */
+#define SW_DR_RESERVED_3_SEL_LSB (1U << 30) /* 2b */
+
+/* DRAMC_DPY_CLK_SW_SEL_3 (0x10006000 + 0x49C) */
+#define SC_DR_SHU_EN_ACK_SEL_LSB (1U << 0) /* 4b */
+#define SC_EMI_CLK_OFF_ACK_SEL_LSB (1U << 4) /* 4b */
+#define SC_DR_SHORT_QUEUE_ACK_SEL_LSB (1U << 8) /* 4b */
+#define SC_DRAMC_DFS_STA_SEL_LSB (1U << 12) /* 4b */
+#define SC_DRS_DIS_ACK_SEL_LSB (1U << 16) /* 4b */
+#define SC_DR_SRAM_LOAD_ACK_SEL_LSB (1U << 20) /* 4b */
+#define SC_DR_SRAM_PLL_LOAD_ACK_SEL_LSB (1U << 24) /* 4b */
+#define SC_DR_SRAM_RESTORE_ACK_SEL_LSB (1U << 28) /* 4b */
+
+/* DRAMC_DPY_CLK_SPM_CON (0x10006000 + 0x4A0) */
+#define SC_DMYRD_EN_MOD_SEL_PCM_LSB (1U << 0) /* 1b */
+#define SC_DMYRD_INTV_SEL_PCM_LSB (1U << 1) /* 1b */
+#define SC_DMYRD_EN_PCM_LSB (1U << 2) /* 1b */
+#define SC_DRS_DIS_REQ_PCM_LSB (1U << 3) /* 1b */
+#define SC_DR_SHU_LEVEL_SRAM_PCM_LSB (1U << 4) /* 4b */
+#define SC_DR_GATE_RETRY_EN_PCM_LSB (1U << 8) /* 1b */
+#define SC_DR_SHORT_QUEUE_PCM_LSB (1U << 9) /* 1b */
+#define SC_DPY_MIDPI_EN_PCM_LSB (1U << 10) /* 1b */
+#define SC_DPY_PI_RESETB_EN_PCM_LSB (1U << 11) /* 1b */
+#define SC_DPY_MCK8X_EN_PCM_LSB (1U << 12) /* 1b */
+#define SC_DR_RESERVED_0_PCM_LSB (1U << 13) /* 1b */
+#define SC_DR_RESERVED_1_PCM_LSB (1U << 14) /* 1b */
+#define SC_DR_RESERVED_2_PCM_LSB (1U << 15) /* 1b */
+#define SC_DR_RESERVED_3_PCM_LSB (1U << 16) /* 1b */
+#define SC_DMDRAMCSHU_ACK_ALL_LSB (1U << 24) /* 1b */
+#define SC_EMI_CLK_OFF_ACK_ALL_LSB (1U << 25) /* 1b */
+#define SC_DR_SHORT_QUEUE_ACK_ALL_LSB (1U << 26) /* 1b */
+#define SC_DRAMC_DFS_STA_ALL_LSB (1U << 27) /* 1b */
+#define SC_DRS_DIS_ACK_ALL_LSB (1U << 28) /* 1b */
+#define SC_DR_SRAM_LOAD_ACK_ALL_LSB (1U << 29) /* 1b */
+#define SC_DR_SRAM_PLL_LOAD_ACK_ALL_LSB (1U << 30) /* 1b */
+#define SC_DR_SRAM_RESTORE_ACK_ALL_LSB (1U << 31) /* 1b */
+
+/* SPM_DVFS_LEVEL (0x10006000 + 0x4A4) */
+#define SPM_DVFS_LEVEL_LSB (1U << 0) /* 32b */
+
+/* SPM_CIRQ_CON (0x10006000 + 0x4A8) */
+#define CIRQ_CLK_SEL_LSB (1U << 0) /* 1b */
+
+/* SPM_DVFS_MISC (0x10006000 + 0x4AC) */
+#define MSDC_DVFS_REQUEST_LSB (1U << 0) /* 1b */
+#define SPM2EMI_SLP_PROT_EN_LSB (1U << 1) /* 1b */
+#define SPM_DVFS_FORCE_ENABLE_LSB (1U << 2) /* 1b */
+#define FORCE_DVFS_WAKE_LSB (1U << 3) /* 1b */
+#define SPM_DVFSRC_ENABLE_LSB (1U << 4) /* 1b */
+#define SPM_DVFS_DONE_LSB (1U << 5) /* 1b */
+#define DVFSRC_IRQ_WAKEUP_EVENT_MASK_LSB (1U << 6) /* 1b */
+#define SPM2RC_EVENT_ABORT_LSB (1U << 7) /* 1b */
+#define EMI_SLP_IDLE_LSB (1U << 14) /* 1b */
+#define SDIO_READY_TO_SPM_LSB (1U << 15) /* 1b */
+
+/* RG_MODULE_SW_CG_0_MASK_REQ_0 (0x10006000 + 0x4B4) */
+#define RG_MODULE_SW_CG_0_MASK_REQ_0_LSB (1U << 0) /* 32b */
+
+/* RG_MODULE_SW_CG_0_MASK_REQ_1 (0x10006000 + 0x4B8) */
+#define RG_MODULE_SW_CG_0_MASK_REQ_1_LSB (1U << 0) /* 32b */
+
+/* RG_MODULE_SW_CG_0_MASK_REQ_2 (0x10006000 + 0x4BC) */
+#define RG_MODULE_SW_CG_0_MASK_REQ_2_LSB (1U << 0) /* 32b */
+
+/* RG_MODULE_SW_CG_1_MASK_REQ_0 (0x10006000 + 0x4C0) */
+#define RG_MODULE_SW_CG_1_MASK_REQ_0_LSB (1U << 0) /* 32b */
+
+/* RG_MODULE_SW_CG_1_MASK_REQ_1 (0x10006000 + 0x4C4) */
+#define RG_MODULE_SW_CG_1_MASK_REQ_1_LSB (1U << 0) /* 32b */
+
+/* RG_MODULE_SW_CG_1_MASK_REQ_2 (0x10006000 + 0x4C8) */
+#define RG_MODULE_SW_CG_1_MASK_REQ_2_LSB (1U << 0) /* 32b */
+
+/* RG_MODULE_SW_CG_2_MASK_REQ_0 (0x10006000 + 0x4CC) */
+#define RG_MODULE_SW_CG_2_MASK_REQ_0_LSB (1U << 0) /* 32b */
+
+/* RG_MODULE_SW_CG_2_MASK_REQ_1 (0x10006000 + 0x4D0) */
+#define RG_MODULE_SW_CG_2_MASK_REQ_1_LSB (1U << 0) /* 32b */
+
+/* RG_MODULE_SW_CG_2_MASK_REQ_2 (0x10006000 + 0x4D4) */
+#define RG_MODULE_SW_CG_2_MASK_REQ_2_LSB (1U << 0) /* 32b */
+
+/* RG_MODULE_SW_CG_3_MASK_REQ_0 (0x10006000 + 0x4D8) */
+#define RG_MODULE_SW_CG_3_MASK_REQ_0_LSB (1U << 0) /* 32b */
+
+/* RG_MODULE_SW_CG_3_MASK_REQ_1 (0x10006000 + 0x4DC) */
+#define RG_MODULE_SW_CG_3_MASK_REQ_1_LSB (1U << 0) /* 32b */
+
+/* RG_MODULE_SW_CG_3_MASK_REQ_2 (0x10006000 + 0x4E0) */
+#define RG_MODULE_SW_CG_3_MASK_REQ_2_LSB (1U << 0) /* 32b */
+
+/* PWR_STATUS_MASK_REQ_0 (0x10006000 + 0x4E4) */
+#define PWR_STATUS_MASK_REQ_0_LSB (1U << 0) /* 32b */
+
+/* PWR_STATUS_MASK_REQ_1 (0x10006000 + 0x4E8) */
+#define PWR_STATUS_MASK_REQ_1_LSB (1U << 0) /* 32b */
+
+/* PWR_STATUS_MASK_REQ_2 (0x10006000 + 0x4EC) */
+#define PWR_STATUS_MASK_REQ_2_LSB (1U << 0) /* 32b */
+
+/* SPM_CG_CHECK_CON (0x10006000 + 0x4F0) */
+#define APMIXEDSYS_BUSY_MASK_REQ_0_LSB (1U << 0) /* 5b */
+#define APMIXEDSYS_BUSY_MASK_REQ_1_LSB (1U << 8) /* 5b */
+#define APMIXEDSYS_BUSY_MASK_REQ_2_LSB (1U << 16) /* 5b */
+#define AUDIOSYS_BUSY_MASK_REQ_0_LSB (1U << 24) /* 1b */
+#define AUDIOSYS_BUSY_MASK_REQ_1_LSB (1U << 25) /* 1b */
+#define AUDIOSYS_BUSY_MASK_REQ_2_LSB (1U << 26) /* 1b */
+#define SSUSB_BUSY_MASK_REQ_0_LSB (1U << 27) /* 1b */
+#define SSUSB_BUSY_MASK_REQ_1_LSB (1U << 28) /* 1b */
+#define SSUSB_BUSY_MASK_REQ_2_LSB (1U << 29) /* 1b */
+
+/* SPM_SRC_RDY_STA (0x10006000 + 0x4F4) */
+#define SPM_INFRA_INTERNAL_ACK_LSB (1U << 0) /* 1b */
+#define SPM_VRF18_INTERNAL_ACK_LSB (1U << 1) /* 1b */
+
+/* SPM_DVS_DFS_LEVEL (0x10006000 + 0x4F8) */
+#define SPM_DFS_LEVEL_LSB (1U << 0) /* 16b */
+#define SPM_DVS_LEVEL_LSB (1U << 16) /* 16b */
+
+/* SPM_FORCE_DVFS (0x10006000 + 0x4FC) */
+#define FORCE_DVFS_LEVEL_LSB (1U << 0) /* 32b */
+
+/* SPM_SW_FLAG_0 (0x10006000 + 0x600) */
+#define SPM_SW_FLAG_LSB (1U << 0) /* 32b */
+
+/* SPM_SW_DEBUG_0 (0x10006000 + 0x604) */
+#define SPM_SW_DEBUG_0_LSB (1U << 0) /* 32b */
+
+/* SPM_SW_FLAG_1 (0x10006000 + 0x608) */
+#define SPM_SW_FLAG_1_LSB (1U << 0) /* 32b */
+
+/* SPM_SW_DEBUG_1 (0x10006000 + 0x60C) */
+#define SPM_SW_DEBUG_1_LSB (1U << 0) /* 32b */
+
+/* SPM_SW_RSV_0 (0x10006000 + 0x610) */
+#define SPM_SW_RSV_0_LSB (1U << 0) /* 32b */
+
+/* SPM_SW_RSV_1 (0x10006000 + 0x614) */
+#define SPM_SW_RSV_1_LSB (1U << 0) /* 32b */
+
+/* SPM_SW_RSV_2 (0x10006000 + 0x618) */
+#define SPM_SW_RSV_2_LSB (1U << 0) /* 32b */
+
+/* SPM_SW_RSV_3 (0x10006000 + 0x61C) */
+#define SPM_SW_RSV_3_LSB (1U << 0) /* 32b */
+
+/* SPM_SW_RSV_4 (0x10006000 + 0x620) */
+#define SPM_SW_RSV_4_LSB (1U << 0) /* 32b */
+
+/* SPM_SW_RSV_5 (0x10006000 + 0x624) */
+#define SPM_SW_RSV_5_LSB (1U << 0) /* 32b */
+
+/* SPM_SW_RSV_6 (0x10006000 + 0x628) */
+#define SPM_SW_RSV_6_LSB (1U << 0) /* 32b */
+
+/* SPM_SW_RSV_7 (0x10006000 + 0x62C) */
+#define SPM_SW_RSV_7_LSB (1U << 0) /* 32b */
+
+/* SPM_SW_RSV_8 (0x10006000 + 0x630) */
+#define SPM_SW_RSV_8_LSB (1U << 0) /* 32b */
+
+/* SPM_BK_WAKE_EVENT (0x10006000 + 0x634) */
+#define SPM_BK_WAKE_EVENT_LSB (1U << 0) /* 32b */
+
+/* SPM_BK_VTCXO_DUR (0x10006000 + 0x638) */
+#define SPM_BK_VTCXO_DUR_LSB (1U << 0) /* 32b */
+
+/* SPM_BK_WAKE_MISC (0x10006000 + 0x63C) */
+#define SPM_BK_WAKE_MISC_LSB (1U << 0) /* 32b */
+
+/* SPM_BK_PCM_TIMER (0x10006000 + 0x640) */
+#define SPM_BK_PCM_TIMER_LSB (1U << 0) /* 32b */
+
+/* SPM_RSV_CON_0 (0x10006000 + 0x650) */
+#define SPM_RSV_CON_0_LSB (1U << 0) /* 32b */
+
+/* SPM_RSV_CON_1 (0x10006000 + 0x654) */
+#define SPM_RSV_CON_1_LSB (1U << 0) /* 32b */
+
+/* SPM_RSV_STA_0 (0x10006000 + 0x658) */
+#define SPM_RSV_STA_0_LSB (1U << 0) /* 32b */
+
+/* SPM_RSV_STA_1 (0x10006000 + 0x65C) */
+#define SPM_RSV_STA_1_LSB (1U << 0) /* 32b */
+
+/* SPM_SPARE_CON (0x10006000 + 0x660) */
+#define SPM_SPARE_CON_LSB (1U << 0) /* 32b */
+
+/* SPM_SPARE_CON_SET (0x10006000 + 0x664) */
+#define SPM_SPARE_CON_SET_LSB (1U << 0) /* 32b */
+
+/* SPM_SPARE_CON_CLR (0x10006000 + 0x668) */
+#define SPM_SPARE_CON_CLR_LSB (1U << 0) /* 32b */
+
+/* SPM_CROSS_WAKE_M00_REQ (0x10006000 + 0x66C) */
+#define SPM_CROSS_WAKE_M00_REQ_LSB (1U << 0) /* 4b */
+#define SPM_CROSS_WAKE_M00_CHK_LSB (1U << 4) /* 4b */
+
+/* SPM_CROSS_WAKE_M01_REQ (0x10006000 + 0x670) */
+#define SPM_CROSS_WAKE_M01_REQ_LSB (1U << 0) /* 4b */
+#define SPM_CROSS_WAKE_M01_CHK_LSB (1U << 4) /* 4b */
+
+/* SPM_CROSS_WAKE_M02_REQ (0x10006000 + 0x674) */
+#define SPM_CROSS_WAKE_M02_REQ_LSB (1U << 0) /* 4b */
+#define SPM_CROSS_WAKE_M02_CHK_LSB (1U << 4) /* 4b */
+
+/* SPM_CROSS_WAKE_M03_REQ (0x10006000 + 0x678) */
+#define SPM_CROSS_WAKE_M03_REQ_LSB (1U << 0) /* 4b */
+#define SPM_CROSS_WAKE_M03_CHK_LSB (1U << 4) /* 4b */
+
+/* SCP_VCORE_LEVEL (0x10006000 + 0x67C) */
+#define SCP_VCORE_LEVEL_LSB (1U << 0) /* 16b */
+
+/* SC_MM_CK_SEL_CON (0x10006000 + 0x680) */
+#define SC_MM_CK_SEL_LSB (1U << 0) /* 4b */
+#define SC_MM_CK_SEL_EN_LSB (1U << 4) /* 1b */
+
+/* SPARE_ACK_MASK (0x10006000 + 0x684) */
+#define SPARE_ACK_MASK_B_LSB (1U << 0) /* 32b */
+
+/* SPM_SPARE_FUNCTION (0x10006000 + 0x688) */
+#define SPM_SPARE_FUNCTION_LSB (1U << 0) /* 32b */
+
+/* SPM_DV_CON_0 (0x10006000 + 0x68C) */
+#define SPM_DV_CON_0_LSB (1U << 0) /* 32b */
+
+/* SPM_DV_CON_1 (0x10006000 + 0x690) */
+#define SPM_DV_CON_1_LSB (1U << 0) /* 32b */
+
+/* SPM_DV_STA (0x10006000 + 0x694) */
+#define SPM_DV_STA_LSB (1U << 0) /* 32b */
+
+/* CONN_XOWCN_DEBUG_EN (0x10006000 + 0x698) */
+#define CONN_XOWCN_DEBUG_EN_LSB (1U << 0) /* 1b */
+
+/* SPM_SEMA_M0 (0x10006000 + 0x69C) */
+#define SPM_SEMA_M0_LSB (1U << 0) /* 8b */
+
+/* SPM_SEMA_M1 (0x10006000 + 0x6A0) */
+#define SPM_SEMA_M1_LSB (1U << 0) /* 8b */
+
+/* SPM_SEMA_M2 (0x10006000 + 0x6A4) */
+#define SPM_SEMA_M2_LSB (1U << 0) /* 8b */
+
+/* SPM_SEMA_M3 (0x10006000 + 0x6A8) */
+#define SPM_SEMA_M3_LSB (1U << 0) /* 8b */
+
+/* SPM_SEMA_M4 (0x10006000 + 0x6AC) */
+#define SPM_SEMA_M4_LSB (1U << 0) /* 8b */
+
+/* SPM_SEMA_M5 (0x10006000 + 0x6B0) */
+#define SPM_SEMA_M5_LSB (1U << 0) /* 8b */
+
+/* SPM_SEMA_M6 (0x10006000 + 0x6B4) */
+#define SPM_SEMA_M6_LSB (1U << 0) /* 8b */
+
+/* SPM_SEMA_M7 (0x10006000 + 0x6B8) */
+#define SPM_SEMA_M7_LSB (1U << 0) /* 8b */
+
+/* SPM2ADSP_MAILBOXi (0x10006000 + 0x6BC) */
+#define SPM2ADSP_MAILBOX_LSB (1U << 0) /* 32b */
+
+/* ADSP2SPM_MAILBOX (0x10006000 + 0x6C0) */
+#define ADSP2SPM_MAILBOX_LSB (1U << 0) /* 32b */
+
+/* SPM_ADSP_IRQ (0x10006000 + 0x6C4) */
+#define SC_SPM2ADSP_WAKEUP_LSB (1U << 0) /* 1b */
+#define SPM_ADSP_IRQ_SC_ADSP2SPM_WAKEUP_LSB (1U << 4) /* 1b */
+
+/* SPM_MD32_IRQ (0x10006000 + 0x6C8) */
+#define SC_SPM2SSPM_WAKEUP_LSB (1U << 0) /* 4b */
+#define SPM_MD32_IRQ_SC_SSPM2SPM_WAKEUP_LSB (1U << 4) /* 4b */
+
+/* SPM2PMCU_MAILBOX_0 (0x10006000 + 0x6CC) */
+#define SPM2PMCU_MAILBOX_0_LSB (1U << 0) /* 32b */
+
+/* SPM2PMCU_MAILBOX_1 (0x10006000 + 0x6D0) */
+#define SPM2PMCU_MAILBOX_1_LSB (1U << 0) /* 32b */
+
+/* SPM2PMCU_MAILBOX_2 (0x10006000 + 0x6D4) */
+#define SPM2PMCU_MAILBOX_2_LSB (1U << 0) /* 32b */
+
+/* SPM2PMCU_MAILBOX_3 (0x10006000 + 0x6D8) */
+#define SPM2PMCU_MAILBOX_3_LSB (1U << 0) /* 32b */
+
+/* PMCU2SPM_MAILBOX_0 (0x10006000 + 0x6DC) */
+#define PMCU2SPM_MAILBOX_0_LSB (1U << 0) /* 32b */
+
+/* PMCU2SPM_MAILBOX_1 (0x10006000 + 0x6E0) */
+#define PMCU2SPM_MAILBOX_1_LSB (1U << 0) /* 32b */
+
+/* PMCU2SPM_MAILBOX_2 (0x10006000 + 0x6E4) */
+#define PMCU2SPM_MAILBOX_2_LSB (1U << 0) /* 32b */
+
+/* PMCU2SPM_MAILBOX_3 (0x10006000 + 0x6E8) */
+#define PMCU2SPM_MAILBOX_3_LSB (1U << 0) /* 32b */
+
+/* UFS_PSRI_SW (0x10006000 + 0x6EC) */
+#define UFS_PSRI_SW_LSB (1U << 0) /* 1b */
+
+/* UFS_PSRI_SW_SET (0x10006000 + 0x6F0) */
+#define UFS_PSRI_SW_SET_LSB (1U << 0) /* 1b */
+
+/* UFS_PSRI_SW_CLR (0x10006000 + 0x6F4) */
+#define UFS_PSRI_SW_CLR_LSB (1U << 0) /* 1b */
+
+/* SPM_AP_SEMA (0x10006000 + 0x6F8) */
+#define SPM_AP_SEMA_LSB (1U << 0) /* 1b */
+
+/* SPM_SPM_SEMA (0x10006000 + 0x6FC) */
+#define SPM_SPM_SEMA_LSB (1U << 0) /* 1b */
+
+/* SPM_DVFS_CON (0x10006000 + 0x700) */
+#define SPM_DVFS_CON_LSB (1U << 0) /* 32b */
+
+/* SPM_DVFS_CON_STA (0x10006000 + 0x704) */
+#define SPM_DVFS_CON_STA_LSB (1U << 0) /* 32b */
+
+/* SPM_PMIC_SPMI_CON (0x10006000 + 0x708) */
+#define SPM_PMIC_SPMI_CMD_LSB (1U << 0) /* 2b */
+#define SPM_PMIC_SPMI_SLAVEID_LSB (1U << 2) /* 4b */
+#define SPM_PMIC_SPMI_PMIFID_LSB (1U << 6) /* 1b */
+#define SPM_PMIC_SPMI_DBCNT_LSB (1U << 7) /* 1b */
+
+/* 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 */
+
+/* SPM_DVFS_CMD16i (0x10006000 + 0x750) */
+#define SPM_DVFS_CMD16_LSB (1U << 0) /* 32b */
+
+/* SPM_DVFS_CMD17 (0x10006000 + 0x754) */
+#define SPM_DVFS_CMD17_LSB (1U << 0) /* 32b */
+
+/* SPM_DVFS_CMD18 (0x10006000 + 0x758) */
+#define SPM_DVFS_CMD18_LSB (1U << 0) /* 32b */
+
+/* SPM_DVFS_CMD19 (0x10006000 + 0x75C) */
+#define SPM_DVFS_CMD19_LSB (1U << 0) /* 32b */
+
+/* SPM_DVFS_CMD20 (0x10006000 + 0x760) */
+#define SPM_DVFS_CMD20_LSB (1U << 0) /* 32b */
+
+/* SPM_DVFS_CMD21 (0x10006000 + 0x764) */
+#define SPM_DVFS_CMD21_LSB (1U << 0) /* 32b */
+
+/* SPM_DVFS_CMD22 (0x10006000 + 0x768) */
+#define SPM_DVFS_CMD22_LSB (1U << 0) /* 32b */
+
+/* SPM_DVFS_CMD23 (0x10006000 + 0x76C) */
+#define SPM_DVFS_CMD23_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_VALUE_L (0x10006000 + 0x770) */
+#define SYS_TIMER_VALUE_L_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_VALUE_H (0x10006000 + 0x774) */
+#define SYS_TIMER_VALUE_H_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_START_L (0x10006000 + 0x778) */
+#define SYS_TIMER_START_L_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_START_H (0x10006000 + 0x77C) */
+#define SYS_TIMER_START_H_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_L_00 (0x10006000 + 0x780) */
+#define SYS_TIMER_LATCH_L_00_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_H_00 (0x10006000 + 0x784) */
+#define SYS_TIMER_LATCH_H_00_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_L_01 (0x10006000 + 0x788) */
+#define SYS_TIMER_LATCH_L_01_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_H_01 (0x10006000 + 0x78C) */
+#define SYS_TIMER_LATCH_H_01_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_L_02 (0x10006000 + 0x790) */
+#define SYS_TIMER_LATCH_L_02_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_H_02 (0x10006000 + 0x794) */
+#define SYS_TIMER_LATCH_H_02_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_L_03 (0x10006000 + 0x798) */
+#define SYS_TIMER_LATCH_L_03_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_H_03 (0x10006000 + 0x79C) */
+#define SYS_TIMER_LATCH_H_03_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_L_04 (0x10006000 + 0x7A0) */
+#define SYS_TIMER_LATCH_L_04_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_H_04 (0x10006000 + 0x7A4) */
+#define SYS_TIMER_LATCH_H_04_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_L_05 (0x10006000 + 0x7A8) */
+#define SYS_TIMER_LATCH_L_05_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_H_05 (0x10006000 + 0x7AC) */
+#define SYS_TIMER_LATCH_H_05_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_L_06 (0x10006000 + 0x7B0) */
+#define SYS_TIMER_LATCH_L_06_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_H_06 (0x10006000 + 0x7B4) */
+#define SYS_TIMER_LATCH_H_06_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_L_07 (0x10006000 + 0x7B8) */
+#define SYS_TIMER_LATCH_L_07_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_H_07 (0x10006000 + 0x7BC) */
+#define SYS_TIMER_LATCH_H_07_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_L_08 (0x10006000 + 0x7C0) */
+#define SYS_TIMER_LATCH_L_08_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_H_08 (0x10006000 + 0x7C4) */
+#define SYS_TIMER_LATCH_H_08_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_L_09 (0x10006000 + 0x7C8) */
+#define SYS_TIMER_LATCH_L_09_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_H_09 (0x10006000 + 0x7CC) */
+#define SYS_TIMER_LATCH_H_09_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_L_10 (0x10006000 + 0x7D0) */
+#define SYS_TIMER_LATCH_L_10_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_H_10 (0x10006000 + 0x7D4) */
+#define SYS_TIMER_LATCH_H_10_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_L_11 (0x10006000 + 0x7D8) */
+#define SYS_TIMER_LATCH_L_11_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_H_11 (0x10006000 + 0x7DC) */
+#define SYS_TIMER_LATCH_H_11_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_L_12 (0x10006000 + 0x7E0) */
+#define SYS_TIMER_LATCH_L_12_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_H_12 (0x10006000 + 0x7E4) */
+#define SYS_TIMER_LATCH_H_12_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_L_13 (0x10006000 + 0x7E8) */
+#define SYS_TIMER_LATCH_L_13_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_H_13 (0x10006000 + 0x7EC) */
+#define SYS_TIMER_LATCH_H_13_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_L_14 (0x10006000 + 0x7F0) */
+#define SYS_TIMER_LATCH_L_14_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_H_14 (0x10006000 + 0x7F4) */
+#define SYS_TIMER_LATCH_H_14_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_L_15 (0x10006000 + 0x7F8) */
+#define SYS_TIMER_LATCH_L_15_LSB (1U << 0) /* 32b */
+
+/* SYS_TIMER_LATCH_H_15 (0x10006000 + 0x7FC) */
+#define SYS_TIMER_LATCH_H_15_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 */
+
+/* PCM_WDT_LATCH_10 (0x10006000 + 0x828) */
+#define PCM_WDT_LATCH_10_LSB (1U << 0) /* 32b */
+
+/* PCM_WDT_LATCH_11 (0x10006000 + 0x82C) */
+#define PCM_WDT_LATCH_11_LSB (1U << 0) /* 32b */
+
+/* PCM_WDT_LATCH_12 (0x10006000 + 0x830) */
+#define PCM_WDT_LATCH_12_LSB (1U << 0) /* 32b */
+
+/* PCM_WDT_LATCH_13 (0x10006000 + 0x834) */
+#define PCM_WDT_LATCH_13_LSB (1U << 0) /* 32b */
+
+/* PCM_WDT_LATCH_14 (0x10006000 + 0x838) */
+#define PCM_WDT_LATCH_14_LSB (1U << 0) /* 32b */
+
+/* PCM_WDT_LATCH_15 (0x10006000 + 0x83C) */
+#define PCM_WDT_LATCH_15_LSB (1U << 0) /* 32b */
+
+/* PCM_WDT_LATCH_16 (0x10006000 + 0x840) */
+#define PCM_WDT_LATCH_16_LSB (1U << 0) /* 32b */
+
+/* PCM_WDT_LATCH_17 (0x10006000 + 0x844) */
+#define PCM_WDT_LATCH_17_LSB (1U << 0) /* 32b */
+
+/* PCM_WDT_LATCH_18 (0x10006000 + 0x848) */
+#define PCM_WDT_LATCH_18_LSB (1U << 0) /* 32b */
+
+/* PCM_WDT_LATCH_SPARE_0 (0x10006000 + 0x84C) */
+#define PCM_WDT_LATCH_SPARE_0_LSB (1U << 0) /* 32b */
+
+/* PCM_WDT_LATCH_SPARE_1 (0x10006000 + 0x850) */
+#define PCM_WDT_LATCH_SPARE_1_LSB (1U << 0) /* 32b */
+
+/* PCM_WDT_LATCH_SPARE_2 (0x10006000 + 0x854) */
+#define PCM_WDT_LATCH_SPARE_2_LSB (1U << 0) /* 32b */
+
+/* PCM_WDT_LATCH_CONN_0 (0x10006000 + 0x870) */
+#define PCM_WDT_LATCH_CONN_0_LSB (1U << 0) /* 32b */
+
+/* PCM_WDT_LATCH_CONN_1 (0x10006000 + 0x874) */
+#define PCM_WDT_LATCH_CONN_1_LSB (1U << 0) /* 32b */
+
+/* PCM_WDT_LATCH_CONN_2 (0x10006000 + 0x878) */
+#define PCM_WDT_LATCH_CONN_2_LSB (1U << 0) /* 32b */
+
+/* DRAMC_GATING_ERR_LATCH_CH0_0 (0x10006000 + 0x8A0) */
+#define DRAMC_GATING_ERR_LATCH_CH0_0_LSB (1U << 0) /* 32b */
+
+/* DRAMC_GATING_ERR_LATCH_CH0_1 (0x10006000 + 0x8A4) */
+#define DRAMC_GATING_ERR_LATCH_CH0_1_LSB (1U << 0) /* 32b */
+
+/* DRAMC_GATING_ERR_LATCH_CH0_2 (0x10006000 + 0x8A8) */
+#define DRAMC_GATING_ERR_LATCH_CH0_2_LSB (1U << 0) /* 32b */
+
+/* DRAMC_GATING_ERR_LATCH_CH0_3 (0x10006000 + 0x8AC) */
+#define DRAMC_GATING_ERR_LATCH_CH0_3_LSB (1U << 0) /* 32b */
+
+/* DRAMC_GATING_ERR_LATCH_CH0_4 (0x10006000 + 0x8B0) */
+#define DRAMC_GATING_ERR_LATCH_CH0_4_LSB (1U << 0) /* 32b */
+
+/* DRAMC_GATING_ERR_LATCH_CH0_5 (0x10006000 + 0x8B4) */
+#define DRAMC_GATING_ERR_LATCH_CH0_5_LSB (1U << 0) /* 32b */
+
+/* DRAMC_GATING_ERR_LATCH_CH0_6 (0x10006000 + 0x8B8) */
+#define DRAMC_GATING_ERR_LATCH_CH0_6_LSB (1U << 0) /* 32b */
+
+/* DRAMC_GATING_ERR_LATCH_SPARE_0 (0x10006000 + 0x8F4) */
+#define DRAMC_GATING_ERR_LATCH_SPARE_0_LSB (1U << 0) /* 32b */
+
+/* SPM_ACK_CHK_CON_0 (0x10006000 + 0x900) */
+#define SPM_ACK_CHK_SW_EN_0_LSB (1U << 0) /* 1b */
+#define SPM_ACK_CHK_CLR_ALL_0_LSB (1U << 1) /* 1b */
+#define SPM_ACK_CHK_CLR_TIMER_0_LSB (1U << 2) /* 1b */
+#define SPM_ACK_CHK_CLR_IRQ_0_LSB (1U << 3) /* 1b */
+#define SPM_ACK_CHK_STA_EN_0_LSB (1U << 4) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_EN_0_LSB (1U << 5) /* 1b */
+#define SPM_ACK_CHK_WDT_EN_0_LSB (1U << 6) /* 1b */
+#define SPM_ACK_CHK_LOCK_PC_TRACE_EN_0_LSB (1U << 7) /* 1b */
+#define SPM_ACK_CHK_HW_EN_0_LSB (1U << 8) /* 1b */
+#define SPM_ACK_CHK_HW_MODE_0_LSB (1U << 9) /* 3b */
+#define SPM_ACK_CHK_FAIL_0_LSB (1U << 15) /* 1b */
+
+/* SPM_ACK_CHK_PC_0 (0x10006000 + 0x904) */
+#define SPM_ACK_CHK_HW_TRIG_PC_VAL_0_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_HW_TARG_PC_VAL_0_LSB (1U << 16) /* 16b */
+
+/* SPM_ACK_CHK_SEL_0 (0x10006000 + 0x908) */
+#define SPM_ACK_CHK_HW_TRIG_SIGNAL_SEL_0_LSB (1U << 0) /* 5b */
+#define SPM_ACK_CHK_HW_TRIG_GROUP_SEL_0_LSB (1U << 5) /* 3b */
+#define SPM_ACK_CHK_HW_TARG_SIGNAL_SEL_0_LSB (1U << 16) /* 5b */
+#define SPM_ACK_CHK_HW_TARG_GROUP_SEL_0_LSB (1U << 21) /* 3b */
+
+/* SPM_ACK_CHK_TIMER_0 (0x10006000 + 0x90C) */
+#define SPM_ACK_CHK_TIMER_VAL_0_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_TIMER_0_LSB (1U << 16) /* 16b */
+
+/* SPM_ACK_CHK_STA_0 (0x10006000 + 0x910) */
+#define SPM_ACK_CHK_STA_0_LSB (1U << 0) /* 32b */
+
+/* SPM_ACK_CHK_SWINT_0 (0x10006000 + 0x914) */
+#define SPM_ACK_CHK_SWINT_EN_0_LSB (1U << 0) /* 32b */
+
+/* SPM_ACK_CHK_CON_1 (0x10006000 + 0x918) */
+#define SPM_ACK_CHK_SW_EN_1_LSB (1U << 0) /* 1b */
+#define SPM_ACK_CHK_CLR_ALL_1_LSB (1U << 1) /* 1b */
+#define SPM_ACK_CHK_CLR_TIMER_1_LSB (1U << 2) /* 1b */
+#define SPM_ACK_CHK_CLR_IRQ_1_LSB (1U << 3) /* 1b */
+#define SPM_ACK_CHK_STA_EN_1_LSB (1U << 4) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_EN_1_LSB (1U << 5) /* 1b */
+#define SPM_ACK_CHK_WDT_EN_1_LSB (1U << 6) /* 1b */
+#define SPM_ACK_CHK_LOCK_PC_TRACE_EN_1_LSB (1U << 7) /* 1b */
+#define SPM_ACK_CHK_HW_EN_1_LSB (1U << 8) /* 1b */
+#define SPM_ACK_CHK_HW_MODE_1_LSB (1U << 9) /* 3b */
+#define SPM_ACK_CHK_FAIL_1_LSB (1U << 15) /* 1b */
+
+/* SPM_ACK_CHK_PC_1 (0x10006000 + 0x91C) */
+#define SPM_ACK_CHK_HW_TRIG_PC_VAL_1_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_HW_TARG_PC_VAL_1_LSB (1U << 16) /* 16b */
+
+/* SPM_ACK_CHK_SEL_1 (0x10006000 + 0x920) */
+#define SPM_ACK_CHK_HW_TRIG_SIGNAL_SEL_1_LSB (1U << 0) /* 5b */
+#define SPM_ACK_CHK_HW_TRIG_GROUP_SEL_1_LSB (1U << 5) /* 3b */
+#define SPM_ACK_CHK_HW_TARG_SIGNAL_SEL_1_LSB (1U << 16) /* 5b */
+#define SPM_ACK_CHK_HW_TARG_GROUP_SEL_1_LSB (1U << 21) /* 3b */
+
+/* SPM_ACK_CHK_TIMER_1 (0x10006000 + 0x924) */
+#define SPM_ACK_CHK_TIMER_VAL_1_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_TIMER_1_LSB (1U << 16) /* 16b */
+
+/* SPM_ACK_CHK_STA_1 (0x10006000 + 0x928) */
+#define SPM_ACK_CHK_STA_1_LSB (1U << 0) /* 32b */
+
+/* SPM_ACK_CHK_SWINT_1 (0x10006000 + 0x92C) */
+#define SPM_ACK_CHK_SWINT_EN_1_LSB (1U << 0) /* 32b */
+
+/* SPM_ACK_CHK_CON_2 (0x10006000 + 0x930) */
+#define SPM_ACK_CHK_SW_EN_2_LSB (1U << 0) /* 1b */
+#define SPM_ACK_CHK_CLR_ALL_2_LSB (1U << 1) /* 1b */
+#define SPM_ACK_CHK_CLR_TIMER_2_LSB (1U << 2) /* 1b */
+#define SPM_ACK_CHK_CLR_IRQ_2_LSB (1U << 3) /* 1b */
+#define SPM_ACK_CHK_STA_EN_2_LSB (1U << 4) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_EN_2_LSB (1U << 5) /* 1b */
+#define SPM_ACK_CHK_WDT_EN_2_LSB (1U << 6) /* 1b */
+#define SPM_ACK_CHK_LOCK_PC_TRACE_EN_2_LSB (1U << 7) /* 1b */
+#define SPM_ACK_CHK_HW_EN_2_LSB (1U << 8) /* 1b */
+#define SPM_ACK_CHK_HW_MODE_2_LSB (1U << 9) /* 3b */
+#define SPM_ACK_CHK_FAIL_2_LSB (1U << 15) /* 1b */
+
+/* SPM_ACK_CHK_PC_2 (0x10006000 + 0x934) */
+#define SPM_ACK_CHK_HW_TRIG_PC_VAL_2_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_HW_TARG_PC_VAL_2_LSB (1U << 16) /* 16b */
+
+/* SPM_ACK_CHK_SEL_2 (0x10006000 + 0x938) */
+#define SPM_ACK_CHK_HW_TRIG_SIGNAL_SEL_2_LSB (1U << 0) /* 5b */
+#define SPM_ACK_CHK_HW_TRIG_GROUP_SEL_2_LSB (1U << 5) /* 3b */
+#define SPM_ACK_CHK_HW_TARG_SIGNAL_SEL_2_LSB (1U << 16) /* 5b */
+#define SPM_ACK_CHK_HW_TARG_GROUP_SEL_2_LSB (1U << 21) /* 3b */
+
+/* SPM_ACK_CHK_TIMER_2 (0x10006000 + 0x93C) */
+#define SPM_ACK_CHK_TIMER_VAL_2_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_TIMER_2_LSB (1U << 16) /* 16b */
+
+/* SPM_ACK_CHK_STA_2 (0x10006000 + 0x940) */
+#define SPM_ACK_CHK_STA_2_LSB (1U << 0) /* 32b */
+
+/* SPM_ACK_CHK_SWINT_2 (0x10006000 + 0x944) */
+#define SPM_ACK_CHK_SWINT_EN_2_LSB (1U << 0) /* 32b */
+
+/* SPM_ACK_CHK_CON_3 (0x10006000 + 0x948) */
+#define SPM_ACK_CHK_SW_EN_3_LSB (1U << 0) /* 1b */
+#define SPM_ACK_CHK_CLR_ALL_3_LSB (1U << 1) /* 1b */
+#define SPM_ACK_CHK_CLR_TIMER_3_LSB (1U << 2) /* 1b */
+#define SPM_ACK_CHK_CLR_IRQ_3_LSB (1U << 3) /* 1b */
+#define SPM_ACK_CHK_STA_EN_3_LSB (1U << 4) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_EN_3_LSB (1U << 5) /* 1b */
+#define SPM_ACK_CHK_WDT_EN_3_LSB (1U << 6) /* 1b */
+#define SPM_ACK_CHK_LOCK_PC_TRACE_EN_3_LSB (1U << 7) /* 1b */
+#define SPM_ACK_CHK_HW_EN_3_LSB (1U << 8) /* 1b */
+#define SPM_ACK_CHK_HW_MODE_3_LSB (1U << 9) /* 3b */
+#define SPM_ACK_CHK_FAIL_3_LSB (1U << 15) /* 1b */
+
+/* SPM_ACK_CHK_PC_3 (0x10006000 + 0x94C) */
+#define SPM_ACK_CHK_HW_TRIG_PC_VAL_3_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_HW_TARG_PC_VAL_3_LSB (1U << 16) /* 16b */
+
+/* SPM_ACK_CHK_SEL_3 (0x10006000 + 0x950) */
+#define SPM_ACK_CHK_HW_TRIG_SIGNAL_SEL_3_LSB (1U << 0) /* 5b */
+#define SPM_ACK_CHK_HW_TRIG_GROUP_SEL_3_LSB (1U << 5) /* 3b */
+#define SPM_ACK_CHK_HW_TARG_SIGNAL_SEL_3_LSB (1U << 16) /* 5b */
+#define SPM_ACK_CHK_HW_TARG_GROUP_SEL_3_LSB (1U << 21) /* 3b */
+
+/* SPM_ACK_CHK_TIMER_3 (0x10006000 + 0x954) */
+#define SPM_ACK_CHK_TIMER_VAL_3_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_TIMER_3_LSB (1U << 16) /* 16b */
+
+/* SPM_ACK_CHK_STA_3 (0x10006000 + 0x958) */
+#define SPM_ACK_CHK_STA_3_LSB (1U << 0) /* 32b */
+
+/* SPM_ACK_CHK_SWINT_3 (0x10006000 + 0x95C) */
+#define SPM_ACK_CHK_SWINT_EN_3_LSB (1U << 0) /* 32b */
+
+/* SPM_COUNTER_0 (0x10006000 + 0x960) */
+#define SPM_COUNTER_VAL_0_LSB (1U << 0) /* 14b */
+#define SPM_COUNTER_OUT_0_LSB (1U << 14) /* 14b */
+#define SPM_COUNTER_EN_0_LSB (1U << 28) /* 1b */
+#define SPM_COUNTER_CLR_0_LSB (1U << 29) /* 1b */
+#define SPM_COUNTER_TIMEOUT_0_LSB (1U << 30) /* 1b */
+#define SPM_COUNTER_WAKEUP_EN_0_LSB (1U << 31) /* 1b */
+
+/* SPM_COUNTER_1 (0x10006000 + 0x964) */
+#define SPM_COUNTER_VAL_1_LSB (1U << 0) /* 14b */
+#define SPM_COUNTER_OUT_1_LSB (1U << 14) /* 14b */
+#define SPM_COUNTER_EN_1_LSB (1U << 28) /* 1b */
+#define SPM_COUNTER_CLR_1_LSB (1U << 29) /* 1b */
+#define SPM_COUNTER_TIMEOUT_1_LSB (1U << 30) /* 1b */
+#define SPM_COUNTER_WAKEUP_EN_1_LSB (1U << 31) /* 1b */
+
+/* SPM_COUNTER_2 (0x10006000 + 0x968) */
+#define SPM_COUNTER_VAL_2_LSB (1U << 0) /* 14b */
+#define SPM_COUNTER_OUT_2_LSB (1U << 14) /* 14b */
+#define SPM_COUNTER_EN_2_LSB (1U << 28) /* 1b */
+#define SPM_COUNTER_CLR_2_LSB (1U << 29) /* 1b */
+#define SPM_COUNTER_TIMEOUT_2_LSB (1U << 30) /* 1b */
+#define SPM_COUNTER_WAKEUP_EN_2_LSB (1U << 31) /* 1b */
+
+/* SYS_TIMER_CON (0x10006000 + 0x96C) */
+#define SYS_TIMER_START_EN_LSB (1U << 0) /* 1b */
+#define SYS_TIMER_LATCH_EN_LSB (1U << 1) /* 1b */
+#define SYS_TIMER_ID_LSB (1U << 8) /* 8b */
+#define SYS_TIMER_VALID_LSB (1U << 31) /* 1b */
+
+/* SPM_TWAM_CON (0x10006000 + 0x970) */
+#define REG_TWAM_ENABLE_LSB (1U << 0) /* 1b */
+#define REG_TWAM_SPEED_MODE_EN_LSB (1U << 1) /* 1b */
+#define REG_TWAM_SW_RST_LSB (1U << 2) /* 1b */
+#define REG_TWAM_IRQ_MASK_LSB (1U << 3) /* 1b */
+#define REG_TWAM_MON_TYPE_0_LSB (1U << 4) /* 2b */
+#define REG_TWAM_MON_TYPE_1_LSB (1U << 6) /* 2b */
+#define REG_TWAM_MON_TYPE_2_LSB (1U << 8) /* 2b */
+#define REG_TWAM_MON_TYPE_3_LSB (1U << 10) /* 2b */
+
+/* SPM_TWAM_WINDOW_LEN (0x10006000 + 0x974) */
+#define REG_TWAM_WINDOW_LEN_LSB (1U << 0) /* 32b */
+
+/* SPM_TWAM_IDLE_SEL (0x10006000 + 0x978) */
+#define REG_TWAM_SIG_SEL_0_LSB (1U << 0) /* 7b */
+#define REG_TWAM_SIG_SEL_1_LSB (1U << 8) /* 7b */
+#define REG_TWAM_SIG_SEL_2_LSB (1U << 16) /* 7b */
+#define REG_TWAM_SIG_SEL_3_LSB (1U << 24) /* 7b */
+
+/* SPM_TWAM_EVENT_CLEAR (0x10006000 + 0x97C) */
+#define SPM_TWAM_EVENT_CLEAR_LSB (1U << 0) /* 1b */
+
+/* OPP0_TABLE (0x10006000 + 0x980) */
+#define OPP0_TABLE_LSB (1U << 0) /* 32b */
+
+/* OPP1_TABLE (0x10006000 + 0x984) */
+#define OPP1_TABLE_LSB (1U << 0) /* 32b */
+
+/* OPP2_TABLE (0x10006000 + 0x988) */
+#define OPP2_TABLE_LSB (1U << 0) /* 32b */
+
+/* OPP3_TABLE (0x10006000 + 0x98C) */
+#define OPP3_TABLE_LSB (1U << 0) /* 32b */
+
+/* OPP4_TABLE (0x10006000 + 0x990) */
+#define OPP4_TABLE_LSB (1U << 0) /* 32b */
+
+/* OPP5_TABLE (0x10006000 + 0x994) */
+#define OPP5_TABLE_LSB (1U << 0) /* 32b */
+
+/* OPP6_TABLE (0x10006000 + 0x998) */
+#define OPP6_TABLE_LSB (1U << 0) /* 32b */
+
+/* OPP7_TABLE (0x10006000 + 0x99C) */
+#define OPP7_TABLE_LSB (1U << 0) /* 32b */
+
+/* OPP8_TABLE (0x10006000 + 0x9A0) */
+#define OPP8_TABLE_LSB (1U << 0) /* 32b */
+
+/* OPP9_TABLE (0x10006000 + 0x9A4) */
+#define OPP9_TABLE_LSB (1U << 0) /* 32b */
+
+/* OPP10_TABLE (0x10006000 + 0x9A8) */
+#define OPP10_TABLE_LSB (1U << 0) /* 32b */
+
+/* OPP11_TABLE (0x10006000 + 0x9AC) */
+#define OPP11_TABLE_LSB (1U << 0) /* 32b */
+
+/* OPP12_TABLE (0x10006000 + 0x9B0) */
+#define OPP12_TABLE_LSB (1U << 0) /* 32b */
+
+/* OPP13_TABLE (0x10006000 + 0x9B4) */
+#define OPP13_TABLE_LSB (1U << 0) /* 32b */
+
+/* OPP14_TABLE (0x10006000 + 0x9B8) */
+#define OPP14_TABLE_LSB (1U << 0) /* 32b */
+
+/* OPP15_TABLE (0x10006000 + 0x9BC) */
+#define OPP15_TABLE_LSB (1U << 0) /* 32b */
+
+/* OPP16_TABLE (0x10006000 + 0x9C0) */
+#define OPP16_TABLE_LSB (1U << 0) /* 32b */
+
+/* OPP17_TABLE (0x10006000 + 0x9C4) */
+#define OPP17_TABLE_LSB (1U << 0) /* 32b */
+
+/* SHU0_ARRAY (0x10006000 + 0x9C8) */
+#define SHU0_ARRAY_LSB (1U << 0) /* 32b */
+
+/* SHU1_ARRAY (0x10006000 + 0x9CC) */
+#define SHU1_ARRAY_LSB (1U << 0) /* 32b */
+
+/* SHU2_ARRAY (0x10006000 + 0x9D0) */
+#define SHU2_ARRAY_LSB (1U << 0) /* 32b */
+
+/* SHU3_ARRAY (0x10006000 + 0x9D4) */
+#define SHU3_ARRAY_LSB (1U << 0) /* 32b */
+
+/* SHU4_ARRAY (0x10006000 + 0x9D8) */
+#define SHU4_ARRAY_LSB (1U << 0) /* 32b */
+
+/* SHU5_ARRAY (0x10006000 + 0x9DC) */
+#define SHU5_ARRAY_LSB (1U << 0) /* 32b */
+
+/* SHU6_ARRAY (0x10006000 + 0x9E0) */
+#define SHU6_ARRAY_LSB (1U << 0) /* 32b */
+
+/* SHU7_ARRAY (0x10006000 + 0x9E4) */
+#define SHU7_ARRAY_LSB (1U << 0) /* 32b */
+
+/* SHU8_ARRAY (0x10006000 + 0x9E8) */
+#define SHU8_ARRAY_LSB (1U << 0) /* 32b */
+
+/* SHU9_ARRAY (0x10006000 + 0x9EC) */
+#define SHU9_ARRAY_LSB (1U << 0) /* 32b */
+
+#define SPM_PROJECT_CODE (0xb16)
+#define SPM_REGWR_CFG_KEY (SPM_PROJECT_CODE << 16)
+
+#endif /* MT_SPM_REG */
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_resource_req.h b/plat/mediatek/mt8186/drivers/spm/mt_spm_resource_req.h
new file mode 100644
index 0000000..d370daf
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_resource_req.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_RESOURCE_REQ_H
+#define MT_SPM_RESOURCE_REQ_H
+
+/* SPM resource request internal bit */
+#define MT_SPM_BIT_XO_FPM 0U
+#define MT_SPM_BIT_26M 1U
+#define MT_SPM_BIT_INFRA 2U
+#define MT_SPM_BIT_SYSPLL 3U
+#define MT_SPM_BIT_DRAM_S0 4U
+#define MT_SPM_BIT_DRAM_S1 5U
+
+/* SPM resource request internal bit_mask */
+#define MT_SPM_XO_FPM BIT(MT_SPM_BIT_XO_FPM)
+#define MT_SPM_26M BIT(MT_SPM_BIT_26M)
+#define MT_SPM_INFRA BIT(MT_SPM_BIT_INFRA)
+#define MT_SPM_SYSPLL BIT(MT_SPM_BIT_SYSPLL)
+#define MT_SPM_DRAM_S0 BIT(MT_SPM_BIT_DRAM_S0)
+#define MT_SPM_DRAM_S1 BIT(MT_SPM_BIT_DRAM_S1)
+
+#endif /* MT_SPM_RESOURCE_REQ_H */
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_suspend.c b/plat/mediatek/mt8186/drivers/spm/mt_spm_suspend.c
new file mode 100644
index 0000000..df533a6
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_suspend.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mt_spm.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_rc_internal.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_suspend.h>
+#include <plat_pm.h>
+#include <uart.h>
+
+#define SPM_SUSPEND_SLEEP_PCM_FLAG \
+ (SPM_FLAG_DISABLE_INFRA_PDN | \
+ SPM_FLAG_DISABLE_VCORE_DVS | \
+ SPM_FLAG_DISABLE_VCORE_DFS | \
+ SPM_FLAG_USE_SRCCLKENO2)
+
+#define SPM_SUSPEND_SLEEP_PCM_FLAG1 (0U)
+
+#define SPM_SUSPEND_PCM_FLAG \
+ (SPM_FLAG_DISABLE_VCORE_DVS | \
+ SPM_FLAG_DISABLE_VCORE_DFS)
+
+#define SPM_SUSPEND_PCM_FLAG1 (0U)
+
+#define __WAKE_SRC_FOR_SUSPEND_COMMON__ \
+ (R12_PCM_TIMER | \
+ R12_KP_IRQ_B | \
+ R12_APWDT_EVENT_B | \
+ R12_CONN2AP_SPM_WAKEUP_B | \
+ R12_EINT_EVENT_B | \
+ R12_CONN_WDT_IRQ_B | \
+ R12_SSPM2SPM_WAKEUP_B | \
+ R12_SCP2SPM_WAKEUP_B | \
+ R12_ADSP2SPM_WAKEUP_B | \
+ R12_USBX_CDSC_B | \
+ R12_USBX_POWERDWN_B | \
+ R12_SYS_TIMER_EVENT_B | \
+ R12_EINT_EVENT_SECURE_B | \
+ R12_SYS_CIRQ_IRQ_B | \
+ R12_NNA_WAKEUP | \
+ R12_REG_CPU_WAKEUP)
+
+#if defined(CFG_MICROTRUST_TEE_SUPPORT)
+#define WAKE_SRC_FOR_SUSPEND (__WAKE_SRC_FOR_SUSPEND_COMMON__)
+#else
+#define WAKE_SRC_FOR_SUSPEND \
+ (__WAKE_SRC_FOR_SUSPEND_COMMON__ | \
+ R12_SEJ_EVENT_B)
+#endif
+
+static struct pwr_ctrl suspend_ctrl = {
+ .wake_src = WAKE_SRC_FOR_SUSPEND,
+
+ /* Auto-gen Start */
+
+ /* SPM_AP_STANDBY_CON */
+ .reg_wfi_op = 0,
+ .reg_wfi_type = 0,
+ .reg_mp0_cputop_idle_mask = 0,
+ .reg_mp1_cputop_idle_mask = 0,
+ .reg_mcusys_idle_mask = 0,
+ .reg_md_apsrc_1_sel = 0,
+ .reg_md_apsrc_0_sel = 0,
+ .reg_conn_apsrc_sel = 0,
+
+ /* SPM_SRC6_MASK */
+ .reg_ccif_event_infra_req_mask_b = 0,
+ .reg_ccif_event_apsrc_req_mask_b = 0,
+
+ /* SPM_SRC_REQ */
+ .reg_spm_apsrc_req = 0,
+ .reg_spm_f26m_req = 0,
+ .reg_spm_infra_req = 0,
+ .reg_spm_vrf18_req = 0,
+ .reg_spm_ddren_req = 0,
+ .reg_spm_dvfs_req = 0,
+ .reg_spm_sw_mailbox_req = 0,
+ .reg_spm_sspm_mailbox_req = 0,
+ .reg_spm_adsp_mailbox_req = 0,
+ .reg_spm_scp_mailbox_req = 0,
+
+ /* SPM_SRC_MASK */
+ .reg_md_0_srcclkena_mask_b = 0,
+ .reg_md_0_infra_req_mask_b = 0,
+ .reg_md_0_apsrc_req_mask_b = 0,
+ .reg_md_0_vrf18_req_mask_b = 0,
+ .reg_md_0_ddren_req_mask_b = 0,
+ .reg_md_1_srcclkena_mask_b = 0,
+ .reg_md_1_infra_req_mask_b = 0,
+ .reg_md_1_apsrc_req_mask_b = 0,
+ .reg_md_1_vrf18_req_mask_b = 0,
+ .reg_md_1_ddren_req_mask_b = 0,
+ .reg_conn_srcclkena_mask_b = 1,
+ .reg_conn_srcclkenb_mask_b = 0,
+ .reg_conn_infra_req_mask_b = 1,
+ .reg_conn_apsrc_req_mask_b = 1,
+ .reg_conn_vrf18_req_mask_b = 1,
+ .reg_conn_ddren_req_mask_b = 1,
+ .reg_conn_vfe28_mask_b = 0,
+ .reg_srcclkeni_srcclkena_mask_b = 1,
+ .reg_srcclkeni_infra_req_mask_b = 1,
+ .reg_infrasys_apsrc_req_mask_b = 0,
+ .reg_infrasys_ddren_req_mask_b = 1,
+ .reg_sspm_srcclkena_mask_b = 1,
+ .reg_sspm_infra_req_mask_b = 1,
+ .reg_sspm_apsrc_req_mask_b = 1,
+ .reg_sspm_vrf18_req_mask_b = 1,
+ .reg_sspm_ddren_req_mask_b = 1,
+
+ /* SPM_SRC2_MASK */
+ .reg_scp_srcclkena_mask_b = 1,
+ .reg_scp_infra_req_mask_b = 1,
+ .reg_scp_apsrc_req_mask_b = 1,
+ .reg_scp_vrf18_req_mask_b = 1,
+ .reg_scp_ddren_req_mask_b = 1,
+ .reg_audio_dsp_srcclkena_mask_b = 1,
+ .reg_audio_dsp_infra_req_mask_b = 1,
+ .reg_audio_dsp_apsrc_req_mask_b = 1,
+ .reg_audio_dsp_vrf18_req_mask_b = 1,
+ .reg_audio_dsp_ddren_req_mask_b = 1,
+ .reg_ufs_srcclkena_mask_b = 1,
+ .reg_ufs_infra_req_mask_b = 1,
+ .reg_ufs_apsrc_req_mask_b = 1,
+ .reg_ufs_vrf18_req_mask_b = 1,
+ .reg_ufs_ddren_req_mask_b = 1,
+ .reg_disp0_apsrc_req_mask_b = 1,
+ .reg_disp0_ddren_req_mask_b = 1,
+ .reg_disp1_apsrc_req_mask_b = 1,
+ .reg_disp1_ddren_req_mask_b = 1,
+ .reg_gce_infra_req_mask_b = 1,
+ .reg_gce_apsrc_req_mask_b = 1,
+ .reg_gce_vrf18_req_mask_b = 1,
+ .reg_gce_ddren_req_mask_b = 1,
+ .reg_apu_srcclkena_mask_b = 0,
+ .reg_apu_infra_req_mask_b = 0,
+ .reg_apu_apsrc_req_mask_b = 0,
+ .reg_apu_vrf18_req_mask_b = 0,
+ .reg_apu_ddren_req_mask_b = 0,
+ .reg_cg_check_srcclkena_mask_b = 0,
+ .reg_cg_check_apsrc_req_mask_b = 0,
+ .reg_cg_check_vrf18_req_mask_b = 0,
+ .reg_cg_check_ddren_req_mask_b = 0,
+
+ /* SPM_SRC3_MASK */
+ .reg_dvfsrc_event_trigger_mask_b = 1,
+ .reg_sw2spm_wakeup_mask_b = 0,
+ .reg_adsp2spm_wakeup_mask_b = 0,
+ .reg_sspm2spm_wakeup_mask_b = 0,
+ .reg_scp2spm_wakeup_mask_b = 0,
+ .reg_csyspwrup_ack_mask = 1,
+ .reg_spm_reserved_srcclkena_mask_b = 0,
+ .reg_spm_reserved_infra_req_mask_b = 0,
+ .reg_spm_reserved_apsrc_req_mask_b = 0,
+ .reg_spm_reserved_vrf18_req_mask_b = 0,
+ .reg_spm_reserved_ddren_req_mask_b = 0,
+ .reg_mcupm_srcclkena_mask_b = 0,
+ .reg_mcupm_infra_req_mask_b = 0,
+ .reg_mcupm_apsrc_req_mask_b = 0,
+ .reg_mcupm_vrf18_req_mask_b = 0,
+ .reg_mcupm_ddren_req_mask_b = 0,
+ .reg_msdc0_srcclkena_mask_b = 1,
+ .reg_msdc0_infra_req_mask_b = 1,
+ .reg_msdc0_apsrc_req_mask_b = 1,
+ .reg_msdc0_vrf18_req_mask_b = 1,
+ .reg_msdc0_ddren_req_mask_b = 1,
+ .reg_msdc1_srcclkena_mask_b = 1,
+ .reg_msdc1_infra_req_mask_b = 1,
+ .reg_msdc1_apsrc_req_mask_b = 1,
+ .reg_msdc1_vrf18_req_mask_b = 1,
+ .reg_msdc1_ddren_req_mask_b = 1,
+
+ /* SPM_SRC4_MASK */
+ .reg_ccif_event_srcclkena_mask_b = 0,
+ .reg_bak_psri_srcclkena_mask_b = 0,
+ .reg_bak_psri_infra_req_mask_b = 0,
+ .reg_bak_psri_apsrc_req_mask_b = 0,
+ .reg_bak_psri_vrf18_req_mask_b = 0,
+ .reg_bak_psri_ddren_req_mask_b = 0,
+ .reg_dramc_md32_infra_req_mask_b = 0,
+ .reg_dramc_md32_vrf18_req_mask_b = 0,
+ .reg_conn_srcclkenb2pwrap_mask_b = 0,
+ .reg_dramc_md32_apsrc_req_mask_b = 0,
+
+ /* SPM_SRC5_MASK */
+ .reg_mcusys_merge_apsrc_req_mask_b = 0x83,
+ .reg_mcusys_merge_ddren_req_mask_b = 0x83,
+ .reg_afe_srcclkena_mask_b = 1,
+ .reg_afe_infra_req_mask_b = 1,
+ .reg_afe_apsrc_req_mask_b = 1,
+ .reg_afe_vrf18_req_mask_b = 1,
+ .reg_afe_ddren_req_mask_b = 1,
+ .reg_msdc2_srcclkena_mask_b = 0,
+ .reg_msdc2_infra_req_mask_b = 0,
+ .reg_msdc2_apsrc_req_mask_b = 0,
+ .reg_msdc2_vrf18_req_mask_b = 0,
+ .reg_msdc2_ddren_req_mask_b = 0,
+
+ /* SPM_WAKEUP_EVENT_MASK */
+ .reg_wakeup_event_mask = 0x1383213,
+
+ /* SPM_WAKEUP_EVENT_EXT_MASK */
+ .reg_ext_wakeup_event_mask = 0xFFFFFFFF,
+
+ /* SPM_SRC7_MASK */
+ .reg_pcie_srcclkena_mask_b = 0,
+ .reg_pcie_infra_req_mask_b = 0,
+ .reg_pcie_apsrc_req_mask_b = 0,
+ .reg_pcie_vrf18_req_mask_b = 0,
+ .reg_pcie_ddren_req_mask_b = 0,
+ .reg_dpmaif_srcclkena_mask_b = 1,
+ .reg_dpmaif_infra_req_mask_b = 1,
+ .reg_dpmaif_apsrc_req_mask_b = 1,
+ .reg_dpmaif_vrf18_req_mask_b = 1,
+ .reg_dpmaif_ddren_req_mask_b = 1,
+
+ /* Auto-gen End */
+
+ /*sw flag setting */
+ .pcm_flags = SPM_SUSPEND_PCM_FLAG,
+ .pcm_flags1 = SPM_SUSPEND_PCM_FLAG1,
+};
+
+struct spm_lp_scen __spm_suspend = {
+ .pwrctrl = &suspend_ctrl,
+};
+
+int mt_spm_suspend_mode_set(int mode)
+{
+ if (mode == MT_SPM_SUSPEND_SLEEP) {
+ suspend_ctrl.pcm_flags = SPM_SUSPEND_SLEEP_PCM_FLAG;
+ suspend_ctrl.pcm_flags1 = SPM_SUSPEND_SLEEP_PCM_FLAG1;
+ } else {
+ suspend_ctrl.pcm_flags = SPM_SUSPEND_PCM_FLAG;
+ suspend_ctrl.pcm_flags1 = SPM_SUSPEND_PCM_FLAG1;
+ }
+
+ return 0;
+}
+
+int mt_spm_suspend_enter(int state_id, unsigned int ext_opand,
+ unsigned int resource_req)
+{
+ /* If FMAudio / ADSP is active, change to sleep suspend mode */
+ if ((ext_opand & MT_SPM_EX_OP_SET_SUSPEND_MODE) != 0U) {
+ mt_spm_suspend_mode_set(MT_SPM_SUSPEND_SLEEP);
+ }
+
+ /* Notify MCUPM that device is going suspend flow */
+ mmio_write_32(MCUPM_MBOX_OFFSET_PDN, MCUPM_POWER_DOWN);
+
+ /* Notify UART to sleep */
+ mt_uart_save();
+
+ return spm_conservation(state_id, ext_opand,
+ &__spm_suspend, resource_req);
+}
+
+void mt_spm_suspend_resume(int state_id, unsigned int ext_opand,
+ struct wake_status **status)
+{
+ spm_conservation_finish(state_id, ext_opand, &__spm_suspend, status);
+
+ /* Notify UART to wakeup */
+ mt_uart_restore();
+
+ /* Notify MCUPM that device leave suspend */
+ mmio_write_32(MCUPM_MBOX_OFFSET_PDN, 0);
+
+ /* If FMAudio / ADSP is active, change back to suspend mode */
+ if ((ext_opand & MT_SPM_EX_OP_SET_SUSPEND_MODE) != 0U) {
+ mt_spm_suspend_mode_set(MT_SPM_SUSPEND_SYSTEM_PDN);
+ }
+}
+
+void mt_spm_suspend_init(void)
+{
+ spm_conservation_pwrctrl_init(__spm_suspend.pwrctrl);
+}
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_suspend.h b/plat/mediatek/mt8186/drivers/spm/mt_spm_suspend.h
new file mode 100644
index 0000000..f7c066a
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_suspend.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#ifndef MT_SPM_SUSPEDN_H
+#define MT_SPM_SUSPEDN_H
+
+#include <mt_spm_internal.h>
+
+#define MCUPM_MBOX_OFFSET_PDN (0x0C55FDA8)
+#define MCUPM_POWER_DOWN (0x4D50444E)
+
+enum MT_SPM_SUSPEND_MODE {
+ MT_SPM_SUSPEND_SYSTEM_PDN = 0U,
+ MT_SPM_SUSPEND_SLEEP = 1U,
+};
+
+extern int mt_spm_suspend_mode_set(int mode);
+extern int mt_spm_suspend_enter(int state_id, unsigned int ext_opand,
+ unsigned int reosuce_req);
+extern void mt_spm_suspend_resume(int state_id, unsigned int ext_opand,
+ struct wake_status **status);
+extern void mt_spm_suspend_init(void);
+
+#endif /* MT_SPM_SUSPEND_H */
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_vcorefs.c b/plat/mediatek/mt8186/drivers/spm/mt_spm_vcorefs.c
new file mode 100644
index 0000000..fb51e69
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_vcorefs.c
@@ -0,0 +1,533 @@
+/*
+ * Copyright(C)2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+#include <mt_spm.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_pmic_wrap.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_vcorefs.h>
+#include <mtk_sip_svc.h>
+#include <plat_pm.h>
+#include <platform_def.h>
+#include <pmic.h>
+
+#define VCORE_CT_ENABLE BIT(5)
+#define VCORE_DRM_ENABLE BIT(31)
+#define VCORE_PTPOD_SHIFT (8)
+#define VCORE_POWER_SHIFT (2)
+
+#define VCORE_MAX_OPP (3)
+#define DRAM_MAX_OPP (6)
+
+#define SW_REQ5_INIT_VAL (6U << 12)
+#define V_VMODE_SHIFT (0)
+#define VCORE_HV (105)
+#define VCORE_LV (95)
+#define PMIC_STEP_UV (6250)
+
+static int vcore_opp_0_uv = 800000;
+static int vcore_opp_1_uv = 700000;
+static int vcore_opp_2_uv = 650000;
+
+static struct pwr_ctrl vcorefs_ctrl = {
+ .wake_src = R12_REG_CPU_WAKEUP,
+
+ /* default VCORE DVFS is disabled */
+ .pcm_flags = (SPM_FLAG_RUN_COMMON_SCENARIO |
+ SPM_FLAG_DISABLE_VCORE_DVS |
+ SPM_FLAG_DISABLE_VCORE_DFS),
+
+ /* Auto-gen Start */
+
+ /* SPM_AP_STANDBY_CON */
+ .reg_wfi_op = 0,
+ .reg_wfi_type = 0,
+ .reg_mp0_cputop_idle_mask = 0,
+ .reg_mp1_cputop_idle_mask = 0,
+ .reg_mcusys_idle_mask = 0,
+ .reg_md_apsrc_1_sel = 0,
+ .reg_md_apsrc_0_sel = 0,
+ .reg_conn_apsrc_sel = 0,
+
+ /* SPM_SRC6_MASK */
+ .reg_ccif_event_infra_req_mask_b = 0xFFFF,
+ .reg_ccif_event_apsrc_req_mask_b = 0xFFFF,
+
+ /* SPM_SRC_REQ */
+ .reg_spm_apsrc_req = 1,
+ .reg_spm_f26m_req = 1,
+ .reg_spm_infra_req = 1,
+ .reg_spm_vrf18_req = 1,
+ .reg_spm_ddren_req = 1,
+ .reg_spm_dvfs_req = 0,
+ .reg_spm_sw_mailbox_req = 0,
+ .reg_spm_sspm_mailbox_req = 0,
+ .reg_spm_adsp_mailbox_req = 0,
+ .reg_spm_scp_mailbox_req = 0,
+
+ /* SPM_SRC_MASK */
+ .reg_md_0_srcclkena_mask_b = 1,
+ .reg_md_0_infra_req_mask_b = 1,
+ .reg_md_0_apsrc_req_mask_b = 1,
+ .reg_md_0_vrf18_req_mask_b = 1,
+ .reg_md_0_ddren_req_mask_b = 1,
+ .reg_md_1_srcclkena_mask_b = 0,
+ .reg_md_1_infra_req_mask_b = 0,
+ .reg_md_1_apsrc_req_mask_b = 0,
+ .reg_md_1_vrf18_req_mask_b = 0,
+ .reg_md_1_ddren_req_mask_b = 0,
+ .reg_conn_srcclkena_mask_b = 1,
+ .reg_conn_srcclkenb_mask_b = 0,
+ .reg_conn_infra_req_mask_b = 1,
+ .reg_conn_apsrc_req_mask_b = 1,
+ .reg_conn_vrf18_req_mask_b = 1,
+ .reg_conn_ddren_req_mask_b = 1,
+ .reg_conn_vfe28_mask_b = 0,
+ .reg_srcclkeni_srcclkena_mask_b = 1,
+ .reg_srcclkeni_infra_req_mask_b = 1,
+ .reg_infrasys_apsrc_req_mask_b = 0,
+ .reg_infrasys_ddren_req_mask_b = 1,
+ .reg_sspm_srcclkena_mask_b = 1,
+ .reg_sspm_infra_req_mask_b = 1,
+ .reg_sspm_apsrc_req_mask_b = 1,
+ .reg_sspm_vrf18_req_mask_b = 1,
+ .reg_sspm_ddren_req_mask_b = 1,
+
+ /* SPM_SRC2_MASK */
+ .reg_scp_srcclkena_mask_b = 1,
+ .reg_scp_infra_req_mask_b = 1,
+ .reg_scp_apsrc_req_mask_b = 1,
+ .reg_scp_vrf18_req_mask_b = 1,
+ .reg_scp_ddren_req_mask_b = 1,
+ .reg_audio_dsp_srcclkena_mask_b = 1,
+ .reg_audio_dsp_infra_req_mask_b = 1,
+ .reg_audio_dsp_apsrc_req_mask_b = 1,
+ .reg_audio_dsp_vrf18_req_mask_b = 1,
+ .reg_audio_dsp_ddren_req_mask_b = 1,
+ .reg_ufs_srcclkena_mask_b = 1,
+ .reg_ufs_infra_req_mask_b = 1,
+ .reg_ufs_apsrc_req_mask_b = 1,
+ .reg_ufs_vrf18_req_mask_b = 1,
+ .reg_ufs_ddren_req_mask_b = 1,
+ .reg_disp0_apsrc_req_mask_b = 1,
+ .reg_disp0_ddren_req_mask_b = 1,
+ .reg_disp1_apsrc_req_mask_b = 1,
+ .reg_disp1_ddren_req_mask_b = 1,
+ .reg_gce_infra_req_mask_b = 1,
+ .reg_gce_apsrc_req_mask_b = 1,
+ .reg_gce_vrf18_req_mask_b = 1,
+ .reg_gce_ddren_req_mask_b = 1,
+ .reg_apu_srcclkena_mask_b = 0,
+ .reg_apu_infra_req_mask_b = 0,
+ .reg_apu_apsrc_req_mask_b = 0,
+ .reg_apu_vrf18_req_mask_b = 0,
+ .reg_apu_ddren_req_mask_b = 0,
+ .reg_cg_check_srcclkena_mask_b = 0,
+ .reg_cg_check_apsrc_req_mask_b = 0,
+ .reg_cg_check_vrf18_req_mask_b = 0,
+ .reg_cg_check_ddren_req_mask_b = 0,
+
+ /* SPM_SRC3_MASK */
+ .reg_dvfsrc_event_trigger_mask_b = 1,
+ .reg_sw2spm_wakeup_mask_b = 0,
+ .reg_adsp2spm_wakeup_mask_b = 0,
+ .reg_sspm2spm_wakeup_mask_b = 0,
+ .reg_scp2spm_wakeup_mask_b = 0,
+ .reg_csyspwrup_ack_mask = 1,
+ .reg_spm_reserved_srcclkena_mask_b = 0,
+ .reg_spm_reserved_infra_req_mask_b = 0,
+ .reg_spm_reserved_apsrc_req_mask_b = 0,
+ .reg_spm_reserved_vrf18_req_mask_b = 0,
+ .reg_spm_reserved_ddren_req_mask_b = 0,
+ .reg_mcupm_srcclkena_mask_b = 1,
+ .reg_mcupm_infra_req_mask_b = 1,
+ .reg_mcupm_apsrc_req_mask_b = 1,
+ .reg_mcupm_vrf18_req_mask_b = 1,
+ .reg_mcupm_ddren_req_mask_b = 1,
+ .reg_msdc0_srcclkena_mask_b = 1,
+ .reg_msdc0_infra_req_mask_b = 1,
+ .reg_msdc0_apsrc_req_mask_b = 1,
+ .reg_msdc0_vrf18_req_mask_b = 1,
+ .reg_msdc0_ddren_req_mask_b = 1,
+ .reg_msdc1_srcclkena_mask_b = 1,
+ .reg_msdc1_infra_req_mask_b = 1,
+ .reg_msdc1_apsrc_req_mask_b = 1,
+ .reg_msdc1_vrf18_req_mask_b = 1,
+ .reg_msdc1_ddren_req_mask_b = 1,
+
+ /* SPM_SRC4_MASK */
+ .reg_ccif_event_srcclkena_mask_b = 0x3FF,
+ .reg_bak_psri_srcclkena_mask_b = 0,
+ .reg_bak_psri_infra_req_mask_b = 0,
+ .reg_bak_psri_apsrc_req_mask_b = 0,
+ .reg_bak_psri_vrf18_req_mask_b = 0,
+ .reg_bak_psri_ddren_req_mask_b = 0,
+ .reg_dramc_md32_infra_req_mask_b = 1,
+ .reg_dramc_md32_vrf18_req_mask_b = 0,
+ .reg_conn_srcclkenb2pwrap_mask_b = 0,
+ .reg_dramc_md32_apsrc_req_mask_b = 0,
+
+ /* SPM_SRC5_MASK */
+ .reg_mcusys_merge_apsrc_req_mask_b = 0x14,
+ .reg_mcusys_merge_ddren_req_mask_b = 0x14,
+ .reg_afe_srcclkena_mask_b = 0,
+ .reg_afe_infra_req_mask_b = 0,
+ .reg_afe_apsrc_req_mask_b = 0,
+ .reg_afe_vrf18_req_mask_b = 0,
+ .reg_afe_ddren_req_mask_b = 0,
+ .reg_msdc2_srcclkena_mask_b = 0,
+ .reg_msdc2_infra_req_mask_b = 0,
+ .reg_msdc2_apsrc_req_mask_b = 0,
+ .reg_msdc2_vrf18_req_mask_b = 0,
+ .reg_msdc2_ddren_req_mask_b = 0,
+
+ /* SPM_WAKEUP_EVENT_MASK */
+ .reg_wakeup_event_mask = 0xEFFFFFFF,
+
+ /* SPM_WAKEUP_EVENT_EXT_MASK */
+ .reg_ext_wakeup_event_mask = 0xFFFFFFFF,
+
+ /* SPM_SRC7_MASK */
+ .reg_pcie_srcclkena_mask_b = 1,
+ .reg_pcie_infra_req_mask_b = 1,
+ .reg_pcie_apsrc_req_mask_b = 1,
+ .reg_pcie_vrf18_req_mask_b = 1,
+ .reg_pcie_ddren_req_mask_b = 1,
+ .reg_dpmaif_srcclkena_mask_b = 1,
+ .reg_dpmaif_infra_req_mask_b = 1,
+ .reg_dpmaif_apsrc_req_mask_b = 1,
+ .reg_dpmaif_vrf18_req_mask_b = 1,
+ .reg_dpmaif_ddren_req_mask_b = 1,
+
+ /* Auto-gen End */
+};
+
+struct spm_lp_scen __spm_vcorefs = {
+ .pwrctrl = &vcorefs_ctrl,
+};
+
+static struct reg_config dvfsrc_init_configs[] = {
+ {DVFSRC_HRT_REQ_UNIT, 0x0000001E},
+ {DVFSRC_DEBOUNCE_TIME, 0x00001965},
+ {DVFSRC_TIMEOUT_NEXTREQ, 0x00000015},
+ {DVFSRC_VCORE_REQUEST4, 0x22211100},
+ {DVFSRC_DDR_QOS0, 0x00000019},
+ {DVFSRC_DDR_QOS1, 0x00000026},
+ {DVFSRC_DDR_QOS2, 0x00000033},
+ {DVFSRC_DDR_QOS3, 0x0000004C},
+ {DVFSRC_DDR_QOS4, 0x00000066},
+ {DVFSRC_DDR_QOS5, 0x00000077},
+ {DVFSRC_DDR_QOS6, 0x00770077},
+ {DVFSRC_LEVEL_LABEL_0_1, 0x40225032},
+ {DVFSRC_LEVEL_LABEL_2_3, 0x20223012},
+ {DVFSRC_LEVEL_LABEL_4_5, 0x40211012},
+ {DVFSRC_LEVEL_LABEL_6_7, 0x20213011},
+ {DVFSRC_LEVEL_LABEL_8_9, 0x30101011},
+ {DVFSRC_LEVEL_LABEL_10_11, 0x10102000},
+ {DVFSRC_LEVEL_LABEL_12_13, 0x00000000},
+ {DVFSRC_LEVEL_LABEL_14_15, 0x00000000},
+ {DVFSRC_LEVEL_LABEL_16_17, 0x00000000},
+ {DVFSRC_LEVEL_LABEL_18_19, 0x00000000},
+ {DVFSRC_LEVEL_LABEL_20_21, 0x00000000},
+ {DVFSRC_LEVEL_MASK, 0x00000000},
+ {DVFSRC_MD_LATENCY_IMPROVE, 0x00000020},
+ {DVFSRC_HRT_BW_BASE, 0x00000004},
+ {DVSFRC_HRT_REQ_MD_URG, 0x000D50D5},
+ {DVFSRC_HRT_REQ_MD_BW_0, 0x00200802},
+ {DVFSRC_HRT_REQ_MD_BW_1, 0x00200802},
+ {DVFSRC_HRT_REQ_MD_BW_2, 0x00200800},
+ {DVFSRC_HRT_REQ_MD_BW_3, 0x00400802},
+ {DVFSRC_HRT_REQ_MD_BW_4, 0x00601404},
+ {DVFSRC_HRT_REQ_MD_BW_5, 0x00D02C09},
+ {DVFSRC_HRT_REQ_MD_BW_6, 0x00000012},
+ {DVFSRC_HRT_REQ_MD_BW_7, 0x00000024},
+ {DVFSRC_HRT_REQ_MD_BW_8, 0x00000000},
+ {DVFSRC_HRT_REQ_MD_BW_9, 0x00000000},
+ {DVFSRC_HRT_REQ_MD_BW_10, 0x00035400},
+ {DVFSRC_HRT1_REQ_MD_BW_0, 0x04B12C4B},
+ {DVFSRC_HRT1_REQ_MD_BW_1, 0x04B12C4B},
+ {DVFSRC_HRT1_REQ_MD_BW_2, 0x04B12C00},
+ {DVFSRC_HRT1_REQ_MD_BW_3, 0x04B12C4B},
+ {DVFSRC_HRT1_REQ_MD_BW_4, 0x04B12C4B},
+ {DVFSRC_HRT1_REQ_MD_BW_5, 0x04B12C4B},
+ {DVFSRC_HRT1_REQ_MD_BW_6, 0x0000004B},
+ {DVFSRC_HRT1_REQ_MD_BW_7, 0x0000005C},
+ {DVFSRC_HRT1_REQ_MD_BW_8, 0x00000000},
+ {DVFSRC_HRT1_REQ_MD_BW_9, 0x00000000},
+ {DVFSRC_HRT1_REQ_MD_BW_10, 0x00035400},
+ {DVFSRC_95MD_SCEN_BW0_T, 0x22222220},
+ {DVFSRC_95MD_SCEN_BW1_T, 0x22222222},
+ {DVFSRC_95MD_SCEN_BW2_T, 0x22222222},
+ {DVFSRC_95MD_SCEN_BW3_T, 0x52222222},
+ {DVFSRC_95MD_SCEN_BW4, 0x00000005},
+ {DVFSRC_RSRV_5, 0x00000001},
+#ifdef DVFSRC_1600_FLOOR
+ {DVFSRC_DDR_REQUEST, 0x00000022},
+#else
+ {DVFSRC_DDR_REQUEST, 0x00000021},
+#endif
+ {DVFSRC_DDR_REQUEST3, 0x00554300},
+ {DVFSRC_DDR_ADD_REQUEST, 0x55543210},
+#ifdef DVFSRC_1600_FLOOR
+ {DVFSRC_DDR_REQUEST5, 0x54322000},
+#else
+ {DVFSRC_DDR_REQUEST5, 0x54321000},
+#endif
+ {DVFSRC_DDR_REQUEST6, 0x53143130},
+ {DVFSRC_DDR_REQUEST7, 0x55000000},
+ {DVFSRC_DDR_REQUEST8, 0x05000000},
+ {DVFSRC_EMI_MON_DEBOUNCE_TIME, 0x4C2D0000},
+ {DVFSRC_EMI_ADD_REQUEST, 0x55543210},
+ {DVFSRC_VCORE_USER_REQ, 0x00010A29},
+ {DVFSRC_HRT_HIGH, 0x0E100960},
+ {DVFSRC_HRT_HIGH_1, 0x1AD21700},
+ {DVFSRC_HRT_HIGH_2, 0x314C2306},
+ {DVFSRC_HRT_HIGH_3, 0x314C314C},
+ {DVFSRC_HRT_LOW, 0x0E0F095F},
+ {DVFSRC_HRT_LOW_1, 0x1AD116FF},
+ {DVFSRC_HRT_LOW_2, 0x314B2305},
+ {DVFSRC_HRT_LOW_3, 0x314B314B},
+#ifdef DVFSRC_1600_FLOOR
+ {DVFSRC_HRT_REQUEST, 0x55554322},
+#else
+ {DVFSRC_HRT_REQUEST, 0x55554321},
+#endif
+ {DVFSRC_BASIC_CONTROL_3, 0x0000000E},
+ {DVFSRC_INT_EN, 0x00000002},
+ {DVFSRC_QOS_EN, 0x001e407C},
+ {DVFSRC_CURRENT_FORCE, 0x00000001},
+ {DVFSRC_BASIC_CONTROL, 0x0180004B},
+ {DVFSRC_BASIC_CONTROL, 0X0180404B},
+ {DVFSRC_BASIC_CONTROL, 0X0180014B},
+ {DVFSRC_CURRENT_FORCE, 0x00000000},
+};
+
+#define IS_PMIC_57() ((pmic_get_hwcid() >> 8) == 0x57)
+
+static inline unsigned int vcore_base_uv(void)
+{
+ static unsigned int vb;
+
+ if (vb == 0) {
+ vb = IS_PMIC_57() ? 518750 : 500000;
+ }
+
+ return vb;
+}
+
+#define _VCORE_STEP_UV (6250)
+
+#define __vcore_uv_to_pmic(uv) /* pmic >= uv */ \
+ ((((uv) - vcore_base_uv()) + (_VCORE_STEP_UV - 1)) / _VCORE_STEP_UV)
+
+static int devinfo_table[] = {
+ 3539, 492, 1038, 106, 231, 17, 46, 2179,
+ 4, 481, 1014, 103, 225, 17, 45, 2129,
+ 3, 516, 1087, 111, 242, 19, 49, 2282,
+ 4, 504, 1063, 108, 236, 18, 47, 2230,
+ 4, 448, 946, 96, 210, 15, 41, 1986,
+ 2, 438, 924, 93, 205, 14, 40, 1941,
+ 2, 470, 991, 101, 220, 16, 43, 2080,
+ 3, 459, 968, 98, 215, 16, 42, 2033,
+ 3, 594, 1250, 129, 279, 23, 57, 2621,
+ 6, 580, 1221, 126, 273, 22, 56, 2561,
+ 6, 622, 1309, 136, 293, 24, 60, 2745,
+ 7, 608, 1279, 132, 286, 23, 59, 2683,
+ 6, 541, 1139, 117, 254, 20, 51, 2390,
+ 5, 528, 1113, 114, 248, 19, 50, 2335,
+ 4, 566, 1193, 123, 266, 21, 54, 2503,
+ 5, 553, 1166, 120, 260, 21, 53, 2446,
+ 5, 338, 715, 70, 157, 9, 29, 1505,
+ 3153, 330, 699, 69, 153, 9, 28, 1470,
+ 3081, 354, 750, 74, 165, 10, 31, 1576,
+ 3302, 346, 732, 72, 161, 10, 30, 1540,
+ 3227, 307, 652, 63, 142, 8, 26, 1371,
+ 2875, 300, 637, 62, 139, 7, 25, 1340,
+ 2809, 322, 683, 67, 149, 8, 27, 1436,
+ 3011, 315, 667, 65, 146, 8, 26, 1404,
+ 2942, 408, 862, 86, 191, 13, 37, 1811,
+ 1, 398, 842, 84, 186, 12, 36, 1769,
+ 1, 428, 903, 91, 200, 14, 39, 1896,
+ 2, 418, 882, 89, 195, 13, 38, 1853,
+ 2, 371, 785, 78, 173, 11, 33, 1651,
+ 3458, 363, 767, 76, 169, 10, 32, 1613,
+ 3379, 389, 823, 82, 182, 12, 35, 1729,
+ 1, 380, 804, 80, 177, 11, 34, 1689,
+};
+
+static void spm_vcorefs_pwarp_cmd(uint64_t cmd, uint64_t val)
+{
+ if (cmd < NR_IDX_ALL) {
+ mt_spm_pmic_wrap_set_cmd(PMIC_WRAP_PHASE_ALLINONE, cmd, val);
+ } else {
+ INFO("cmd out of range!\n");
+ }
+}
+
+void spm_dvfsfw_init(uint64_t boot_up_opp, uint64_t dram_issue)
+{
+ mmio_write_32(OPP0_TABLE, 0xFFFF0000);
+ mmio_write_32(OPP1_TABLE, 0xFFFF0100);
+ mmio_write_32(OPP2_TABLE, 0xFFFF0300);
+ mmio_write_32(OPP3_TABLE, 0xFFFF0500);
+ mmio_write_32(OPP4_TABLE, 0xFFFF0700);
+ mmio_write_32(OPP5_TABLE, 0xFFFF0202);
+ mmio_write_32(OPP6_TABLE, 0xFFFF0302);
+ mmio_write_32(OPP7_TABLE, 0xFFFF0502);
+ mmio_write_32(OPP8_TABLE, 0xFFFF0702);
+ mmio_write_32(OPP9_TABLE, 0xFFFF0403);
+ mmio_write_32(OPP10_TABLE, 0xFFFF0603);
+ mmio_write_32(OPP11_TABLE, 0xFFFF0803);
+ mmio_write_32(OPP12_TABLE, 0xFFFF0903);
+ mmio_write_32(OPP13_TABLE, 0xFFFFFFFF);
+ mmio_write_32(OPP14_TABLE, 0xFFFFFFFF);
+ mmio_write_32(OPP15_TABLE, 0xFFFFFFFF);
+ mmio_write_32(OPP16_TABLE, 0xFFFFFFFF);
+ mmio_write_32(OPP17_TABLE, 0xFFFFFFFF);
+ mmio_write_32(SHU0_ARRAY, 0xFFFFFF00);
+ mmio_write_32(SHU1_ARRAY, 0xFFFFEE01);
+ mmio_write_32(SHU2_ARRAY, 0xFF05EEFF);
+ mmio_write_32(SHU3_ARRAY, 0xFF06EE02);
+ mmio_write_32(SHU4_ARRAY, 0x0906FFFF);
+ mmio_write_32(SHU5_ARRAY, 0xFF07EE03);
+ mmio_write_32(SHU6_ARRAY, 0x0A07FFFF);
+ mmio_write_32(SHU7_ARRAY, 0xFF08EE04);
+ mmio_write_32(SHU8_ARRAY, 0x0B08FFFF);
+ mmio_write_32(SHU9_ARRAY, 0x0CFFFFFF);
+
+ mmio_clrsetbits_32(SPM_DVFS_MISC, SPM_DVFS_FORCE_ENABLE_LSB,
+ SPM_DVFSRC_ENABLE_LSB);
+
+ mmio_write_32(SPM_DVFS_LEVEL, 0x00000001);
+ mmio_write_32(SPM_DVS_DFS_LEVEL, 0x00010001);
+}
+
+void __spm_sync_vcore_dvfs_power_control(struct pwr_ctrl *dest_pwr_ctrl,
+ const struct pwr_ctrl *src_pwr_ctrl)
+{
+ uint32_t dvfs_mask = SPM_FLAG_DISABLE_VCORE_DVS |
+ SPM_FLAG_DISABLE_VCORE_DFS |
+ SPM_FLAG_ENABLE_VOLTAGE_BIN;
+
+ dest_pwr_ctrl->pcm_flags = (dest_pwr_ctrl->pcm_flags & (~dvfs_mask)) |
+ (src_pwr_ctrl->pcm_flags & dvfs_mask);
+
+ if (dest_pwr_ctrl->pcm_flags_cust > 0U) {
+ dest_pwr_ctrl->pcm_flags_cust =
+ ((dest_pwr_ctrl->pcm_flags_cust) & (~dvfs_mask)) |
+ ((src_pwr_ctrl->pcm_flags) & (dvfs_mask));
+ }
+}
+
+static void spm_go_to_vcorefs(void)
+{
+ __spm_set_power_control(__spm_vcorefs.pwrctrl);
+ __spm_set_wakeup_event(__spm_vcorefs.pwrctrl);
+ __spm_set_pcm_flags(__spm_vcorefs.pwrctrl);
+ __spm_send_cpu_wakeup_event();
+}
+
+static void dvfsrc_init(void)
+{
+ uint32_t i;
+
+ for (i = 0U; i < ARRAY_SIZE(dvfsrc_init_configs); i++) {
+ mmio_write_32(dvfsrc_init_configs[i].offset,
+ dvfsrc_init_configs[i].val);
+ }
+}
+
+static void spm_vcorefs_vcore_setting(uint64_t flag)
+{
+ int idx, ptpod, rsv4;
+ int power = 0;
+
+ switch (flag) {
+ case 1: /*HV*/
+ vcore_opp_0_uv = 840000;
+ vcore_opp_1_uv = 725000;
+ vcore_opp_2_uv = 682500;
+ break;
+ case 2: /*LV*/
+ vcore_opp_0_uv = 760000;
+ vcore_opp_1_uv = 665000;
+ vcore_opp_2_uv = 617500;
+ break;
+ default:
+ break;
+ }
+
+ rsv4 = mmio_read_32(DVFSRC_RSRV_4);
+ ptpod = (rsv4 >> VCORE_PTPOD_SHIFT) & 0xF;
+ idx = (rsv4 >> VCORE_POWER_SHIFT) & 0xFF;
+
+ if (idx != 0) {
+ power = (int)devinfo_table[idx];
+ }
+
+ if (power > 0 && power <= 40) {
+ idx = ptpod & 0xF;
+ if (idx == 1) {
+ vcore_opp_2_uv = 700000;
+ } else if (idx > 1 && idx < 10) {
+ vcore_opp_2_uv = 675000;
+ }
+ }
+
+ spm_vcorefs_pwarp_cmd(3, __vcore_uv_to_pmic(vcore_opp_2_uv));
+ spm_vcorefs_pwarp_cmd(2, __vcore_uv_to_pmic(vcore_opp_1_uv));
+ spm_vcorefs_pwarp_cmd(0, __vcore_uv_to_pmic(vcore_opp_0_uv));
+}
+
+uint64_t spm_vcorefs_args(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t *x4)
+{
+ uint64_t cmd = x1;
+ uint64_t spm_flags;
+
+ switch (cmd) {
+ case VCOREFS_SMC_CMD_INIT:
+ /* vcore_dvfs init + kick */
+ mmio_write_32(DVFSRC_SW_REQ5, SW_REQ5_INIT_VAL);
+ spm_dvfsfw_init(0ULL, 0ULL);
+ spm_vcorefs_vcore_setting(x3 & 0xF);
+ spm_flags = SPM_FLAG_RUN_COMMON_SCENARIO;
+ if ((x2 & 0x1) > 0U) {
+ spm_flags |= SPM_FLAG_DISABLE_VCORE_DVS;
+ }
+
+ if ((x2 & 0x2) > 0U) {
+ spm_flags |= SPM_FLAG_DISABLE_VCORE_DFS;
+ }
+
+ if ((mmio_read_32(DVFSRC_RSRV_4) & VCORE_CT_ENABLE) > 0U) {
+ spm_flags |= SPM_FLAG_ENABLE_VOLTAGE_BIN;
+ }
+
+ set_pwrctrl_pcm_flags(__spm_vcorefs.pwrctrl, spm_flags);
+ spm_go_to_vcorefs();
+ dvfsrc_init();
+
+ *x4 = 0U;
+ mmio_write_32(DVFSRC_SW_REQ5, 0U);
+ break;
+ case VCOREFS_SMC_CMD_KICK:
+ mmio_write_32(DVFSRC_SW_REQ5, 0U);
+ break;
+ default:
+ break;
+ }
+
+ return 0ULL;
+}
diff --git a/plat/mediatek/mt8186/drivers/spm/mt_spm_vcorefs.h b/plat/mediatek/mt8186/drivers/spm/mt_spm_vcorefs.h
new file mode 100644
index 0000000..4fe1b12
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/mt_spm_vcorefs.h
@@ -0,0 +1,316 @@
+/*
+ * Copyright(C)2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_VCOREFS_H
+#define MT_SPM_VCOREFS_H
+
+uint64_t spm_vcorefs_args(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t *x4);
+
+enum vcorefs_smc_cmd {
+ VCOREFS_SMC_CMD_0 = 0U,
+ VCOREFS_SMC_CMD_1 = 1U,
+ VCOREFS_SMC_CMD_2 = 2U,
+ VCOREFS_SMC_CMD_3 = 3U,
+ VCOREFS_SMC_CMD_4 = 4U,
+ /* check spmfw status */
+ VCOREFS_SMC_CMD_5 = 5U,
+
+ /* get spmfw type */
+ VCOREFS_SMC_CMD_6 = 6U,
+
+ /* get spm reg status */
+ VCOREFS_SMC_CMD_7 = 7U,
+
+ NUM_VCOREFS_SMC_CMD = 8U,
+};
+
+enum vcorefs_smc_cmd_new {
+ VCOREFS_SMC_CMD_INIT = 0U,
+ VCOREFS_SMC_CMD_KICK = 1U,
+ VCOREFS_SMC_CMD_OPP_TYPE = 2U,
+ VCOREFS_SMC_CMD_FW_TYPE = 3U,
+ VCOREFS_SMC_CMD_GET_UV = 4U,
+ VCOREFS_SMC_CMD_GET_FREQ = 5U,
+ VCOREFS_SMC_CMD_GET_NUM_V = 6U,
+ VCOREFS_SMC_CMD_GET_NUM_F = 7U,
+ VCOREFS_SMC_CMD_FB_ACTION = 8U,
+ /*chip specific setting */
+ VCOREFS_SMC_CMD_SET_FREQ = 16U,
+ VCOREFS_SMC_CMD_SET_EFUSE = 17U,
+ VCOREFS_SMC_CMD_GET_EFUSE = 18U,
+ VCOREFS_SMC_CMD_DVFS_HOPPING = 19U,
+ VCOREFS_SMC_CMD_DVFS_HOPPING_STATE = 20U,
+};
+
+enum dvfsrc_channel {
+ DVFSRC_CHANNEL_1 = 1U,
+ DVFSRC_CHANNEL_2 = 2U,
+ DVFSRC_CHANNEL_3 = 3U,
+ DVFSRC_CHANNEL_4 = 4U,
+ NUM_DVFSRC_CHANNEL = 5U,
+};
+
+struct reg_config {
+ uint32_t offset;
+ uint32_t val;
+};
+
+#define DVFSRC_BASIC_CONTROL (DVFSRC_BASE + 0x0)
+#define DVFSRC_SW_REQ1 (DVFSRC_BASE + 0x4)
+#define DVFSRC_SW_REQ2 (DVFSRC_BASE + 0x8)
+#define DVFSRC_SW_REQ3 (DVFSRC_BASE + 0xC)
+#define DVFSRC_SW_REQ4 (DVFSRC_BASE + 0x10)
+#define DVFSRC_SW_REQ5 (DVFSRC_BASE + 0x14)
+#define DVFSRC_SW_REQ6 (DVFSRC_BASE + 0x18)
+#define DVFSRC_SW_REQ7 (DVFSRC_BASE + 0x1C)
+#define DVFSRC_SW_REQ8 (DVFSRC_BASE + 0x20)
+#define DVFSRC_EMI_REQUEST (DVFSRC_BASE + 0x24)
+#define DVFSRC_EMI_REQUEST2 (DVFSRC_BASE + 0x28)
+#define DVFSRC_EMI_REQUEST3 (DVFSRC_BASE + 0x2C)
+#define DVFSRC_EMI_REQUEST4 (DVFSRC_BASE + 0x30)
+#define DVFSRC_EMI_REQUEST5 (DVFSRC_BASE + 0x34)
+#define DVFSRC_EMI_REQUEST6 (DVFSRC_BASE + 0x38)
+#define DVFSRC_EMI_HRT (DVFSRC_BASE + 0x3C)
+#define DVFSRC_EMI_HRT2 (DVFSRC_BASE + 0x40)
+#define DVFSRC_EMI_HRT3 (DVFSRC_BASE + 0x44)
+#define DVFSRC_EMI_QOS0 (DVFSRC_BASE + 0x48)
+#define DVFSRC_EMI_QOS1 (DVFSRC_BASE + 0x4C)
+#define DVFSRC_EMI_QOS2 (DVFSRC_BASE + 0x50)
+#define DVFSRC_EMI_MD2SPM0 (DVFSRC_BASE + 0x54)
+#define DVFSRC_EMI_MD2SPM1 (DVFSRC_BASE + 0x58)
+#define DVFSRC_EMI_MD2SPM2 (DVFSRC_BASE + 0x5C)
+#define DVFSRC_EMI_MD2SPM0_T (DVFSRC_BASE + 0x60)
+#define DVFSRC_EMI_MD2SPM1_T (DVFSRC_BASE + 0x64)
+#define DVFSRC_EMI_MD2SPM2_T (DVFSRC_BASE + 0x68)
+#define DVFSRC_VCORE_REQUEST (DVFSRC_BASE + 0x6C)
+#define DVFSRC_VCORE_REQUEST2 (DVFSRC_BASE + 0x70)
+#define DVFSRC_VCORE_REQUEST3 (DVFSRC_BASE + 0x74)
+#define DVFSRC_VCORE_REQUEST4 (DVFSRC_BASE + 0x78)
+#define DVFSRC_VCORE_HRT (DVFSRC_BASE + 0x7C)
+#define DVFSRC_VCORE_HRT2 (DVFSRC_BASE + 0x80)
+#define DVFSRC_VCORE_HRT3 (DVFSRC_BASE + 0x84)
+#define DVFSRC_VCORE_QOS0 (DVFSRC_BASE + 0x88)
+#define DVFSRC_VCORE_QOS1 (DVFSRC_BASE + 0x8C)
+#define DVFSRC_VCORE_QOS2 (DVFSRC_BASE + 0x90)
+#define DVFSRC_VCORE_MD2SPM0 (DVFSRC_BASE + 0x94)
+#define DVFSRC_VCORE_MD2SPM1 (DVFSRC_BASE + 0x98)
+#define DVFSRC_VCORE_MD2SPM2 (DVFSRC_BASE + 0x9C)
+#define DVFSRC_VCORE_MD2SPM0_T (DVFSRC_BASE + 0xA0)
+#define DVFSRC_VCORE_MD2SPM1_T (DVFSRC_BASE + 0xA4)
+#define DVFSRC_VCORE_MD2SPM2_T (DVFSRC_BASE + 0xA8)
+#define DVFSRC_MD_VSRAM_REMAP (DVFSRC_BASE + 0xBC)
+#define DVFSRC_HALT_SW_CONTROL (DVFSRC_BASE + 0xC0)
+#define DVFSRC_INT (DVFSRC_BASE + 0xC4)
+#define DVFSRC_INT_EN (DVFSRC_BASE + 0xC8)
+#define DVFSRC_INT_CLR (DVFSRC_BASE + 0xCC)
+#define DVFSRC_BW_MON_WINDOW (DVFSRC_BASE + 0xD0)
+#define DVFSRC_BW_MON_THRES_1 (DVFSRC_BASE + 0xD4)
+#define DVFSRC_BW_MON_THRES_2 (DVFSRC_BASE + 0xD8)
+#define DVFSRC_MD_TURBO (DVFSRC_BASE + 0xDC)
+#define DVFSRC_VCORE_USER_REQ (DVFSRC_BASE + 0xE4)
+#define DVFSRC_DEBOUNCE_FOUR (DVFSRC_BASE + 0xF0)
+#define DVFSRC_DEBOUNCE_RISE_FALL (DVFSRC_BASE + 0xF4)
+#define DVFSRC_TIMEOUT_NEXTREQ (DVFSRC_BASE + 0xF8)
+#define DVFSRC_LEVEL_LABEL_0_1 (DVFSRC_BASE + 0x100)
+#define DVFSRC_LEVEL_LABEL_2_3 (DVFSRC_BASE + 0x104)
+#define DVFSRC_LEVEL_LABEL_4_5 (DVFSRC_BASE + 0x108)
+#define DVFSRC_LEVEL_LABEL_6_7 (DVFSRC_BASE + 0x10C)
+#define DVFSRC_LEVEL_LABEL_8_9 (DVFSRC_BASE + 0x110)
+#define DVFSRC_LEVEL_LABEL_10_11 (DVFSRC_BASE + 0x114)
+#define DVFSRC_LEVEL_LABEL_12_13 (DVFSRC_BASE + 0x118)
+#define DVFSRC_LEVEL_LABEL_14_15 (DVFSRC_BASE + 0x11C)
+#define DVFSRC_MM_BW_0 (DVFSRC_BASE + 0x200)
+#define DVFSRC_MM_BW_1 (DVFSRC_BASE + 0x204)
+#define DVFSRC_MM_BW_2 (DVFSRC_BASE + 0x208)
+#define DVFSRC_MM_BW_3 (DVFSRC_BASE + 0x20C)
+#define DVFSRC_MM_BW_4 (DVFSRC_BASE + 0x210)
+#define DVFSRC_MM_BW_5 (DVFSRC_BASE + 0x214)
+#define DVFSRC_MM_BW_6 (DVFSRC_BASE + 0x218)
+#define DVFSRC_MM_BW_7 (DVFSRC_BASE + 0x21C)
+#define DVFSRC_MM_BW_8 (DVFSRC_BASE + 0x220)
+#define DVFSRC_MM_BW_9 (DVFSRC_BASE + 0x224)
+#define DVFSRC_MM_BW_10 (DVFSRC_BASE + 0x228)
+#define DVFSRC_MM_BW_11 (DVFSRC_BASE + 0x22C)
+#define DVFSRC_MM_BW_12 (DVFSRC_BASE + 0x230)
+#define DVFSRC_MM_BW_13 (DVFSRC_BASE + 0x234)
+#define DVFSRC_MM_BW_14 (DVFSRC_BASE + 0x238)
+#define DVFSRC_MM_BW_15 (DVFSRC_BASE + 0x23C)
+#define DVFSRC_MD_BW_0 (DVFSRC_BASE + 0x240)
+#define DVFSRC_MD_BW_1 (DVFSRC_BASE + 0x244)
+#define DVFSRC_MD_BW_2 (DVFSRC_BASE + 0x248)
+#define DVFSRC_MD_BW_3 (DVFSRC_BASE + 0x24C)
+#define DVFSRC_MD_BW_4 (DVFSRC_BASE + 0x250)
+#define DVFSRC_MD_BW_5 (DVFSRC_BASE + 0x254)
+#define DVFSRC_MD_BW_6 (DVFSRC_BASE + 0x258)
+#define DVFSRC_MD_BW_7 (DVFSRC_BASE + 0x25C)
+#define DVFSRC_SW_BW_0 (DVFSRC_BASE + 0x260)
+#define DVFSRC_SW_BW_1 (DVFSRC_BASE + 0x264)
+#define DVFSRC_SW_BW_2 (DVFSRC_BASE + 0x268)
+#define DVFSRC_SW_BW_3 (DVFSRC_BASE + 0x26C)
+#define DVFSRC_SW_BW_4 (DVFSRC_BASE + 0x270)
+#define DVFSRC_SW_BW_5 (DVFSRC_BASE + 0x274)
+#define DVFSRC_SW_BW_6 (DVFSRC_BASE + 0x278)
+#define DVFSRC_QOS_EN (DVFSRC_BASE + 0x280)
+#define DVFSRC_MD_BW_URG (DVFSRC_BASE + 0x284)
+#define DVFSRC_ISP_HRT (DVFSRC_BASE + 0x290)
+#define DVFSRC_HRT_BW_BASE (DVFSRC_BASE + 0x294)
+#define DVFSRC_SEC_SW_REQ (DVFSRC_BASE + 0x304)
+#define DVFSRC_EMI_MON_DEBOUNCE_TIME (DVFSRC_BASE + 0x308)
+#define DVFSRC_MD_LATENCY_IMPROVE (DVFSRC_BASE + 0x30C)
+#define DVFSRC_BASIC_CONTROL_3 (DVFSRC_BASE + 0x310)
+#define DVFSRC_DEBOUNCE_TIME (DVFSRC_BASE + 0x314)
+#define DVFSRC_LEVEL_MASK (DVFSRC_BASE + 0x318)
+#define DVFSRC_95MD_SCEN_EMI0 (DVFSRC_BASE + 0x500)
+#define DVFSRC_95MD_SCEN_EMI1 (DVFSRC_BASE + 0x504)
+#define DVFSRC_95MD_SCEN_EMI2 (DVFSRC_BASE + 0x508)
+#define DVFSRC_95MD_SCEN_EMI3 (DVFSRC_BASE + 0x50C)
+#define DVFSRC_95MD_SCEN_EMI0_T (DVFSRC_BASE + 0x510)
+#define DVFSRC_95MD_SCEN_EMI1_T (DVFSRC_BASE + 0x514)
+#define DVFSRC_95MD_SCEN_EMI2_T (DVFSRC_BASE + 0x518)
+#define DVFSRC_95MD_SCEN_EMI3_T (DVFSRC_BASE + 0x51C)
+#define DVFSRC_95MD_SCEN_EMI4 (DVFSRC_BASE + 0x520)
+#define DVFSRC_95MD_SCEN_BW0 (DVFSRC_BASE + 0x524)
+#define DVFSRC_95MD_SCEN_BW1 (DVFSRC_BASE + 0x528)
+#define DVFSRC_95MD_SCEN_BW2 (DVFSRC_BASE + 0x52C)
+#define DVFSRC_95MD_SCEN_BW3 (DVFSRC_BASE + 0x530)
+#define DVFSRC_95MD_SCEN_BW0_T (DVFSRC_BASE + 0x534)
+#define DVFSRC_95MD_SCEN_BW1_T (DVFSRC_BASE + 0x538)
+#define DVFSRC_95MD_SCEN_BW2_T (DVFSRC_BASE + 0x53C)
+#define DVFSRC_95MD_SCEN_BW3_T (DVFSRC_BASE + 0x540)
+#define DVFSRC_95MD_SCEN_BW4 (DVFSRC_BASE + 0x544)
+#define DVFSRC_MD_LEVEL_SW_REG (DVFSRC_BASE + 0x548)
+#define DVFSRC_RSRV_0 (DVFSRC_BASE + 0x600)
+#define DVFSRC_RSRV_1 (DVFSRC_BASE + 0x604)
+#define DVFSRC_RSRV_2 (DVFSRC_BASE + 0x608)
+#define DVFSRC_RSRV_3 (DVFSRC_BASE + 0x60C)
+#define DVFSRC_RSRV_4 (DVFSRC_BASE + 0x610)
+#define DVFSRC_RSRV_5 (DVFSRC_BASE + 0x614)
+#define DVFSRC_SPM_RESEND (DVFSRC_BASE + 0x630)
+#define DVFSRC_DEBUG_STA_0 (DVFSRC_BASE + 0x700)
+#define DVFSRC_DEBUG_STA_1 (DVFSRC_BASE + 0x704)
+#define DVFSRC_DEBUG_STA_2 (DVFSRC_BASE + 0x708)
+#define DVFSRC_DEBUG_STA_3 (DVFSRC_BASE + 0x70C)
+#define DVFSRC_DEBUG_STA_4 (DVFSRC_BASE + 0x710)
+#define DVFSRC_EMI_REQUEST7 (DVFSRC_BASE + 0x800)
+#define DVFSRC_EMI_HRT_1 (DVFSRC_BASE + 0x804)
+#define DVFSRC_EMI_HRT2_1 (DVFSRC_BASE + 0x808)
+#define DVFSRC_EMI_HRT3_1 (DVFSRC_BASE + 0x80C)
+#define DVFSRC_EMI_QOS3 (DVFSRC_BASE + 0x810)
+#define DVFSRC_EMI_QOS4 (DVFSRC_BASE + 0x814)
+#define DVFSRC_DDR_REQUEST (DVFSRC_BASE + 0xA00)
+#define DVFSRC_DDR_REQUEST2 (DVFSRC_BASE + 0xA04)
+#define DVFSRC_DDR_REQUEST3 (DVFSRC_BASE + 0xA08)
+#define DVFSRC_DDR_REQUEST4 (DVFSRC_BASE + 0xA0C)
+#define DVFSRC_DDR_REQUEST5 (DVFSRC_BASE + 0xA10)
+#define DVFSRC_DDR_REQUEST6 (DVFSRC_BASE + 0xA14)
+#define DVFSRC_DDR_REQUEST7 (DVFSRC_BASE + 0xA18)
+#define DVFSRC_DDR_HRT (DVFSRC_BASE + 0xA1C)
+#define DVFSRC_DDR_HRT2 (DVFSRC_BASE + 0xA20)
+#define DVFSRC_DDR_HRT3 (DVFSRC_BASE + 0xA24)
+#define DVFSRC_DDR_HRT_1 (DVFSRC_BASE + 0xA28)
+#define DVFSRC_DDR_HRT2_1 (DVFSRC_BASE + 0xA2C)
+#define DVFSRC_DDR_HRT3_1 (DVFSRC_BASE + 0xA30)
+#define DVFSRC_DDR_QOS0 (DVFSRC_BASE + 0xA34)
+#define DVFSRC_DDR_QOS1 (DVFSRC_BASE + 0xA38)
+#define DVFSRC_DDR_QOS2 (DVFSRC_BASE + 0xA3C)
+#define DVFSRC_DDR_QOS3 (DVFSRC_BASE + 0xA40)
+#define DVFSRC_DDR_QOS4 (DVFSRC_BASE + 0xA44)
+#define DVFSRC_DDR_MD2SPM0 (DVFSRC_BASE + 0xA48)
+#define DVFSRC_DDR_MD2SPM1 (DVFSRC_BASE + 0xA4C)
+#define DVFSRC_DDR_MD2SPM2 (DVFSRC_BASE + 0xA50)
+#define DVFSRC_DDR_MD2SPM0_T (DVFSRC_BASE + 0xA54)
+#define DVFSRC_DDR_MD2SPM1_T (DVFSRC_BASE + 0xA58)
+#define DVFSRC_DDR_MD2SPM2_T (DVFSRC_BASE + 0xA5C)
+#define DVFSRC_HRT_REQ_UNIT (DVFSRC_BASE + 0xA60)
+#define DVSFRC_HRT_REQ_MD_URG (DVFSRC_BASE + 0xA64)
+#define DVFSRC_HRT_REQ_MD_BW_0 (DVFSRC_BASE + 0xA68)
+#define DVFSRC_HRT_REQ_MD_BW_1 (DVFSRC_BASE + 0xA6C)
+#define DVFSRC_HRT_REQ_MD_BW_2 (DVFSRC_BASE + 0xA70)
+#define DVFSRC_HRT_REQ_MD_BW_3 (DVFSRC_BASE + 0xA74)
+#define DVFSRC_HRT_REQ_MD_BW_4 (DVFSRC_BASE + 0xA78)
+#define DVFSRC_HRT_REQ_MD_BW_5 (DVFSRC_BASE + 0xA7C)
+#define DVFSRC_HRT_REQ_MD_BW_6 (DVFSRC_BASE + 0xA80)
+#define DVFSRC_HRT_REQ_MD_BW_7 (DVFSRC_BASE + 0xA84)
+#define DVFSRC_HRT1_REQ_MD_BW_0 (DVFSRC_BASE + 0xA88)
+#define DVFSRC_HRT1_REQ_MD_BW_1 (DVFSRC_BASE + 0xA8C)
+#define DVFSRC_HRT1_REQ_MD_BW_2 (DVFSRC_BASE + 0xA90)
+#define DVFSRC_HRT1_REQ_MD_BW_3 (DVFSRC_BASE + 0xA94)
+#define DVFSRC_HRT1_REQ_MD_BW_4 (DVFSRC_BASE + 0xA98)
+#define DVFSRC_HRT1_REQ_MD_BW_5 (DVFSRC_BASE + 0xA9C)
+#define DVFSRC_HRT1_REQ_MD_BW_6 (DVFSRC_BASE + 0xAA0)
+#define DVFSRC_HRT1_REQ_MD_BW_7 (DVFSRC_BASE + 0xAA4)
+#define DVFSRC_HRT_REQ_MD_BW_8 (DVFSRC_BASE + 0xAA8)
+#define DVFSRC_HRT_REQ_MD_BW_9 (DVFSRC_BASE + 0xAAC)
+#define DVFSRC_HRT_REQ_MD_BW_10 (DVFSRC_BASE + 0xAB0)
+#define DVFSRC_HRT1_REQ_MD_BW_8 (DVFSRC_BASE + 0xAB4)
+#define DVFSRC_HRT1_REQ_MD_BW_9 (DVFSRC_BASE + 0xAB8)
+#define DVFSRC_HRT1_REQ_MD_BW_10 (DVFSRC_BASE + 0xABC)
+#define DVFSRC_HRT_REQ_BW_SW_REG (DVFSRC_BASE + 0xAC0)
+#define DVFSRC_HRT_REQUEST (DVFSRC_BASE + 0xAC4)
+#define DVFSRC_HRT_HIGH_2 (DVFSRC_BASE + 0xAC8)
+#define DVFSRC_HRT_HIGH_1 (DVFSRC_BASE + 0xACC)
+#define DVFSRC_HRT_HIGH (DVFSRC_BASE + 0xAD0)
+#define DVFSRC_HRT_LOW_2 (DVFSRC_BASE + 0xAD4)
+#define DVFSRC_HRT_LOW_1 (DVFSRC_BASE + 0xAD8)
+#define DVFSRC_HRT_LOW (DVFSRC_BASE + 0xADC)
+#define DVFSRC_DDR_ADD_REQUEST (DVFSRC_BASE + 0xAE0)
+#define DVFSRC_LAST (DVFSRC_BASE + 0xAE4)
+#define DVFSRC_LAST_L (DVFSRC_BASE + 0xAE8)
+#define DVFSRC_MD_SCENARIO (DVFSRC_BASE + 0xAEC)
+#define DVFSRC_RECORD_0_0 (DVFSRC_BASE + 0xAF0)
+#define DVFSRC_RECORD_0_1 (DVFSRC_BASE + 0xAF4)
+#define DVFSRC_RECORD_0_2 (DVFSRC_BASE + 0xAF8)
+#define DVFSRC_RECORD_0_3 (DVFSRC_BASE + 0xAFC)
+#define DVFSRC_RECORD_0_4 (DVFSRC_BASE + 0xB00)
+#define DVFSRC_RECORD_0_5 (DVFSRC_BASE + 0xB04)
+#define DVFSRC_RECORD_0_6 (DVFSRC_BASE + 0xB08)
+#define DVFSRC_RECORD_0_7 (DVFSRC_BASE + 0xB0C)
+#define DVFSRC_RECORD_0_L_0 (DVFSRC_BASE + 0xBF0)
+#define DVFSRC_RECORD_0_L_1 (DVFSRC_BASE + 0xBF4)
+#define DVFSRC_RECORD_0_L_2 (DVFSRC_BASE + 0xBF8)
+#define DVFSRC_RECORD_0_L_3 (DVFSRC_BASE + 0xBFC)
+#define DVFSRC_RECORD_0_L_4 (DVFSRC_BASE + 0xC00)
+#define DVFSRC_RECORD_0_L_5 (DVFSRC_BASE + 0xC04)
+#define DVFSRC_RECORD_0_L_6 (DVFSRC_BASE + 0xC08)
+#define DVFSRC_RECORD_0_L_7 (DVFSRC_BASE + 0xC0C)
+#define DVFSRC_EMI_REQUEST8 (DVFSRC_BASE + 0xCF0)
+#define DVFSRC_DDR_REQUEST8 (DVFSRC_BASE + 0xCF4)
+#define DVFSRC_EMI_HRT_2 (DVFSRC_BASE + 0xCF8)
+#define DVFSRC_EMI_HRT2_2 (DVFSRC_BASE + 0xCFC)
+#define DVFSRC_EMI_HRT3_2 (DVFSRC_BASE + 0xD00)
+#define DVFSRC_EMI_QOS5 (DVFSRC_BASE + 0xD04)
+#define DVFSRC_EMI_QOS6 (DVFSRC_BASE + 0xD08)
+#define DVFSRC_DDR_HRT_2 (DVFSRC_BASE + 0xD0C)
+#define DVFSRC_DDR_HRT2_2 (DVFSRC_BASE + 0xD10)
+#define DVFSRC_DDR_HRT3_2 (DVFSRC_BASE + 0xD14)
+#define DVFSRC_DDR_QOS5 (DVFSRC_BASE + 0xD18)
+#define DVFSRC_DDR_QOS6 (DVFSRC_BASE + 0xD1C)
+#define DVFSRC_VCORE_REQUEST5 (DVFSRC_BASE + 0xD20)
+#define DVFSRC_VCORE_HRT_1 (DVFSRC_BASE + 0xD24)
+#define DVFSRC_VCORE_HRT2_1 (DVFSRC_BASE + 0xD28)
+#define DVFSRC_VCORE_HRT3_1 (DVFSRC_BASE + 0xD2C)
+#define DVFSRC_VCORE_QOS3 (DVFSRC_BASE + 0xD30)
+#define DVFSRC_VCORE_QOS4 (DVFSRC_BASE + 0xD34)
+#define DVFSRC_HRT_HIGH_3 (DVFSRC_BASE + 0xD38)
+#define DVFSRC_HRT_LOW_3 (DVFSRC_BASE + 0xD3C)
+#define DVFSRC_BASIC_CONTROL_2 (DVFSRC_BASE + 0xD40)
+#define DVFSRC_CURRENT_LEVEL (DVFSRC_BASE + 0xD44)
+#define DVFSRC_TARGET_LEVEL (DVFSRC_BASE + 0xD48)
+#define DVFSRC_LEVEL_LABEL_16_17 (DVFSRC_BASE + 0xD4C)
+#define DVFSRC_LEVEL_LABEL_18_19 (DVFSRC_BASE + 0xD50)
+#define DVFSRC_LEVEL_LABEL_20_21 (DVFSRC_BASE + 0xD54)
+#define DVFSRC_LEVEL_LABEL_22_23 (DVFSRC_BASE + 0xD58)
+#define DVFSRC_LEVEL_LABEL_24_25 (DVFSRC_BASE + 0xD5C)
+#define DVFSRC_LEVEL_LABEL_26_27 (DVFSRC_BASE + 0xD60)
+#define DVFSRC_LEVEL_LABEL_28_29 (DVFSRC_BASE + 0xD64)
+#define DVFSRC_LEVEL_LABEL_30_31 (DVFSRC_BASE + 0xD68)
+#define DVFSRC_CURRENT_FORCE (DVFSRC_BASE + 0xD6C)
+#define DVFSRC_TARGET_FORCE (DVFSRC_BASE + 0xD70)
+#define DVFSRC_EMI_ADD_REQUEST (DVFSRC_BASE + 0xD74)
+
+#define VCORE_VB_EFUSE (0x11C105E8)
+
+#endif /* MT_SPM_VCOREFS_H */
diff --git a/plat/mediatek/mt8186/drivers/spm/notifier/mt_spm_notifier.h b/plat/mediatek/mt8186/drivers/spm/notifier/mt_spm_notifier.h
new file mode 100644
index 0000000..89aa163
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/notifier/mt_spm_notifier.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_SSPM_NOTIFIER_H
+#define MT_SPM_SSPM_NOTIFIER_H
+
+enum MT_SPM_SSPM_NOTIFY_ID {
+ MT_SPM_NOTIFY_LP_ENTER = 0U,
+ MT_SPM_NOTIFY_LP_LEAVE = 1U,
+ MT_SPM_NOTIFY_SUSPEND_VCORE_VOLTAGE = 2U,
+};
+
+int mt_spm_sspm_notify(int type, unsigned int lp_mode);
+
+static inline int mt_spm_sspm_notify_u32(int type, unsigned int lp_mode)
+{
+ return mt_spm_sspm_notify(type, lp_mode);
+}
+
+#endif /* MT_SPM_SSPM_NOTIFIER_H */
diff --git a/plat/mediatek/mt8186/drivers/spm/notifier/mt_spm_sspm_intc.h b/plat/mediatek/mt8186/drivers/spm/notifier/mt_spm_sspm_intc.h
new file mode 100644
index 0000000..0b85c60
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/notifier/mt_spm_sspm_intc.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_SSPM_INTC_H
+#define MT_SPM_SSPM_INTC_H
+
+#include <mt_spm_reg.h>
+
+#define MT_SPM_SSPM_INTC_SEL_0 (0x10)
+#define MT_SPM_SSPM_INTC_SEL_1 (0x20)
+#define MT_SPM_SSPM_INTC_SEL_2 (0x40)
+#define MT_SPM_SSPM_INTC_SEL_3 (0x80)
+
+#define MT_SPM_SSPM_INTC_TRIGGER(id, sg) \
+ (((0x10 << id) | (sg << id)) & 0xff)
+
+#define MT_SPM_SSPM_INTC0_HIGH MT_SPM_SSPM_INTC_TRIGGER(0, 1)
+#define MT_SPM_SSPM_INTC0_LOW MT_SPM_SSPM_INTC_TRIGGER(0, 0)
+#define MT_SPM_SSPM_INTC1_HIGH MT_SPM_SSPM_INTC_TRIGGER(1, 1)
+#define MT_SPM_SSPM_INTC1_LOW MT_SPM_SSPM_INTC_TRIGGER(1, 0)
+#define MT_SPM_SSPM_INTC2_HIGH MT_SPM_SSPM_INTC_TRIGGER(2, 1)
+#define MT_SPM_SSPM_INTC2_LOW MT_SPM_SSPM_INTC_TRIGGER(2, 0)
+#define MT_SPM_SSPM_INTC3_HIGH MT_SPM_SSPM_INTC_TRIGGER(3, 1)
+#define MT_SPM_SSPM_INTC3_LOW MT_SPM_SSPM_INTC_TRIGGER(3, 0)
+
+/*
+ * mt8186 use cpc pbi as notify.
+ * Therefore, it won't need be notified by spm driver.
+ */
+#define DO_SPM_SSPM_LP_SUSPEND()
+#define DO_SPM_SSPM_LP_RESUME()
+
+#endif /* MT_SPM_SSPM_INTC_H */
diff --git a/plat/mediatek/mt8186/drivers/spm/notifier/mt_spm_sspm_notifier.c b/plat/mediatek/mt8186/drivers/spm/notifier/mt_spm_sspm_notifier.c
new file mode 100644
index 0000000..20ef011
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/notifier/mt_spm_sspm_notifier.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <lib/mmio.h>
+
+#include <mt_spm_notifier.h>
+#include <mt_spm_sspm_intc.h>
+#include <sspm_reg.h>
+
+#define MT_SPM_SSPM_MBOX_OFF(x) (SSPM_MBOX_BASE + x)
+#define MT_SPM_MBOX(slot) MT_SPM_SSPM_MBOX_OFF((slot << 2UL))
+
+#define SSPM_MBOX_SPM_LP_LOOKUP1 MT_SPM_MBOX(0)
+#define SSPM_MBOX_SPM_LP_LOOKUP2 MT_SPM_MBOX(1)
+#define SSPM_MBOX_SPM_LP1 MT_SPM_MBOX(2)
+#define SSPM_MBOX_SPM_LP2 MT_SPM_MBOX(3)
+
+int mt_spm_sspm_notify(int type, unsigned int lp_mode)
+{
+ switch (type) {
+ case MT_SPM_NOTIFY_LP_ENTER:
+ mmio_write_32(SSPM_MBOX_SPM_LP1, lp_mode);
+ DO_SPM_SSPM_LP_SUSPEND();
+ break;
+ case MT_SPM_NOTIFY_LP_LEAVE:
+ mmio_write_32(SSPM_MBOX_SPM_LP1, lp_mode);
+ DO_SPM_SSPM_LP_RESUME();
+ break;
+ case MT_SPM_NOTIFY_SUSPEND_VCORE_VOLTAGE:
+ mmio_write_32(SSPM_MBOX_SPM_LP2, lp_mode);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8186/drivers/spm/pcm_def.h b/plat/mediatek/mt8186/drivers/spm/pcm_def.h
new file mode 100644
index 0000000..eb2db33
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/pcm_def.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PCM_DEF_H
+#define PCM_DEF_H
+
+/*
+ * Auto generated by DE, please DO NOT modify this file directly.
+ */
+
+/* --- R0 Define --- */
+#define R0_SC_26M_CK_OFF (1U << 0)
+#define R0_SC_TX_TRACK_RETRY_EN (1U << 1)
+#define R0_SC_MEM_CK_OFF (1U << 2)
+#define R0_SC_AXI_CK_OFF (1U << 3)
+#define R0_SC_DR_SRAM_LOAD (1U << 4)
+#define R0_SC_MD26M_CK_OFF (1U << 5)
+#define R0_SC_DPY_MODE_SW (1U << 6)
+#define R0_SC_DMSUS_OFF (1U << 7)
+#define R0_SC_DPY_2ND_DLL_EN (1U << 8)
+#define R0_SC_DR_SRAM_RESTORE (1U << 9)
+#define R0_SC_MPLLOUT_OFF (1U << 10)
+#define R0_SC_TX_TRACKING_DIS (1U << 11)
+#define R0_SC_DPY_DLL_EN (1U << 12)
+#define R0_SC_DPY_DLL_CK_EN (1U << 13)
+#define R0_SC_DPY_VREF_EN (1U << 14)
+#define R0_SC_PHYPLL_EN (1U << 15)
+#define R0_SC_DDRPHY_FB_CK_EN (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_DR_SHU_LEVEL_SRAM_LATCH (1U << 21)
+#define R0_SC_DR_SHU_EN (1U << 22)
+#define R0_SC_DPHY_PRECAL_UP (1U << 23)
+#define R0_SC_MPLL_S_OFF (1U << 24)
+#define R0_SC_DPHY_RXDLY_TRACKING_EN (1U << 25)
+#define R0_SC_PHYPLL_SHU_EN (1U << 26)
+#define R0_SC_PHYPLL2_SHU_EN (1U << 27)
+#define R0_SC_PHYPLL_MODE_SW (1U << 28)
+#define R0_SC_PHYPLL2_MODE_SW (1U << 29)
+#define R0_SC_DR0_SHU_LEVEL (1U << 30)
+#define R0_SC_DR1_SHU_LEVEL (1U << 31)
+/* --- R7 Define --- */
+#define R7_PWRAP_SLEEP_REQ (1U << 0)
+#define R7_EMI_CLK_OFF_REQ_PCM (1U << 1)
+#define R7_PCM_BUS_PROTECT_REQ (1U << 2)
+#define R7_SPM_CK_UPDATE (1U << 3)
+#define R7_SPM_CK_SEL0 (1U << 4)
+#define R7_SPM_CK_SEL1 (1U << 5)
+#define R7_SPM_LEAVE_DEEPIDLE_REQ (1U << 6)
+#define R7_SC_FHC_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_SPM_LEAVE_SUSPEND_REQ (1U << 11)
+#define R7_CSYSPWRUPACK (1U << 12)
+#define R7_PCM_IM_SLP_EN (1U << 13)
+#define R7_SRCCLKENO0 (1U << 14)
+#define R7_FORCE_DDR_EN_WAKE (1U << 15)
+#define R7_SPM_APSRC_INTERNAL_ACK (1U << 16)
+#define R7_CPU_SYS_TIMER_CLK_SEL (1U << 17)
+#define R7_SC_AXI_DCM_DIS (1U << 18)
+#define R7_SC_FHC_PAUSE_MEM (1U << 19)
+#define R7_SC_FHC_PAUSE_MAIN (1U << 20)
+#define R7_SRCCLKENO1 (1U << 21)
+#define R7_PCM_WDT_KICK_P (1U << 22)
+#define R7_SPM2EMI_S1_MODE_ASYNC (1U << 23)
+#define R7_SC_DDR_PST_REQ_PCM (1U << 24)
+#define R7_SC_DDR_PST_ABORT_REQ_PCM (1U << 25)
+#define R7_PMIC_IRQ_REQ_EN (1U << 26)
+#define R7_FORCE_F26M_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_SPM_DDR_EN_INTERNAL_ACK (1U << 31)
+/* --- R12 Define --- */
+#define R12_PCM_TIMER (1U << 0)
+#define R12_TWAM_IRQ_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_SSPM2SPM_WAKEUP_B (1U << 10)
+#define R12_SCP2SPM_WAKEUP_B (1U << 11)
+#define R12_ADSP2SPM_WAKEUP_B (1U << 12)
+#define R12_PCM_WDT_WAKEUP_B (1U << 13)
+#define R12_USBX_CDSC_B (1U << 14)
+#define R12_USBX_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_NNA_WAKEUP (1U << 25)
+#define R12_CLDMA_EVENT_B (1U << 26)
+#define R12_SEJ_EVENT_B (1U << 27)
+#define R12_REG_CPU_WAKEUP (1U << 28)
+#define R12_CPU_IRQOUT (1U << 29)
+#define R12_CPU_WFI (1U << 30)
+#define R12_MCUSYS_IDLE (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_WAKE (1U << 8)
+#define R12EXT_DDREN_WAKE (1U << 9)
+#define R12EXT_DDREN_SLEEP (1U << 10)
+#define R12EXT_MCU_PM_WFI (1U << 11)
+#define R12EXT_SSPM_IDLE (1U << 12)
+#define R12EXT_CONN_SRCCLKENB (1U << 13)
+#define R12EXT_DRAMC_MD32_WFI_MERGE (1U << 14)
+#define R12EXT_SW_MAILBOX_WAKE (1U << 15)
+#define R12EXT_SSPM_MAILBOX_WAKE (1U << 16)
+#define R12EXT_ADSP_MAILBOX_WAKE (1U << 17)
+#define R12EXT_SCP_MAILBOX_WAKE (1U << 18)
+#define R12EXT_SPM_LEAVE_SUSPEND_ACK (1U << 19)
+#define R12EXT_SPM_LEAVE_DEEPIDLE_ACK (1U << 20)
+#define R12EXT_BIT21 (1U << 21)
+#define R12EXT_BIT22 (1U << 22)
+#define R12EXT_BIT23 (1U << 23)
+#define R12EXT_BIT24 (1U << 24)
+#define R12EXT_BIT25 (1U << 25)
+#define R12EXT_BIT26 (1U << 26)
+#define R12EXT_BIT27 (1U << 27)
+#define R12EXT_BIT28 (1U << 28)
+#define R12EXT_BIT29 (1U << 29)
+#define R12EXT_BIT30 (1U << 30)
+#define R12EXT_BIT31 (1U << 31)
+/* --- R13 Define --- */
+#define R13_SRCCLKENI0 (1U << 0)
+#define R13_SRCCLKENI1 (1U << 1)
+#define R13_MD_0_SRCCLKENA (1U << 2)
+#define R13_MD_0_APSRC_REQ (1U << 3)
+#define R13_CONN_DDREN (1U << 4)
+#define R13_MD_1_SRCCLKENA (1U << 5)
+#define R13_SSPM_SRCCLKENA (1U << 6)
+#define R13_SSPM_APSRC_REQ (1U << 7)
+#define R13_MD_1_STATE (1U << 8)
+#define R13_RC_SRCCLKENO_ACK (1U << 9)
+#define R13_MM_STATE (1U << 10)
+#define R13_SSPM_STATE (1U << 11)
+#define R13_MD_0_DDREN (1U << 12)
+#define R13_CONN_STATE (1U << 13)
+#define R13_CONN_SRCCLKENA (1U << 14)
+#define R13_CONN_APSRC_REQ (1U << 15)
+#define R13_SC_DDR_PST_ACK_ALL (1U << 16)
+#define R13_SC_DDR_PST_ABORT_ACK_ALL (1U << 17)
+#define R13_SCP_STATE (1U << 18)
+#define R13_CSYSPWRUPREQ (1U << 19)
+#define R13_PWRAP_SLEEP_ACK (1U << 20)
+#define R13_SC_EMI_CLK_OFF_ACK_ALL (1U << 21)
+#define R13_AUDIO_DSP_STATE (1U << 22)
+#define R13_SC_DMDRAMCSHU_ACK_ALL (1U << 23)
+#define R13_CONN_SRCCLKENB (1U << 24)
+#define R13_SC_DR_SRAM_LOAD_ACK_ALL (1U << 25)
+#define R13_SUBSYS_IDLE_SIGNALS0 (1U << 26)
+#define R13_DVFS_STATE (1U << 27)
+#define R13_SC_DR_SRAM_PLL_LOAD_ACK_ALL (1U << 28)
+#define R13_SC_DR_SRAM_RESTORE_ACK_ALL (1U << 29)
+#define R13_MD_0_VRF18_REQ (1U << 30)
+#define R13_DDR_EN_STATE (1U << 31)
+
+#endif /* PCM_DEF_H */
diff --git a/plat/mediatek/mt8186/drivers/spm/sleep_def.h b/plat/mediatek/mt8186/drivers/spm/sleep_def.h
new file mode 100644
index 0000000..d007939
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spm/sleep_def.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SLEEP_DEF_H
+#define SLEEP_DEF_H
+
+/*
+ * Auto generated by DE, please DO NOT modify this file directly.
+ */
+
+/* --- SPM Flag Define --- */
+#define SPM_FLAG_DISABLE_CPU_PDN (1U << 0)
+#define SPM_FLAG_DISABLE_INFRA_PDN (1U << 1)
+#define SPM_FLAG_DISABLE_DDRPHY_PDN (1U << 2)
+#define SPM_FLAG_DISABLE_VCORE_DVS (1U << 3)
+#define SPM_FLAG_DISABLE_VCORE_DFS (1U << 4)
+#define SPM_FLAG_DISABLE_COMMON_SCENARIO (1U << 5)
+#define SPM_FLAG_DISABLE_BUS_CLK_OFF (1U << 6)
+#define SPM_FLAG_DISABLE_ARMPLL_OFF (1U << 7)
+#define SPM_FLAG_KEEP_CSYSPWRACK_HIGH (1U << 8)
+#define SPM_FLAG_ENABLE_LVTS_WORKAROUND (1U << 9)
+#define SPM_FLAG_RUN_COMMON_SCENARIO (1U << 10)
+#define SPM_FLAG_SSPM_INFRA_SLEEP_MODE (1U << 11)
+#define SPM_FLAG_ENABLE_SPM_DBG_WDT_DUMP (1U << 12)
+#define SPM_FLAG_USE_SRCCLKENO2 (1U << 13)
+#define SPM_FLAG_RESERVED_BIT14 (1U << 14)
+#define SPM_FLAG_ENABLE_TIA_WORKAROUND (1U << 15)
+#define SPM_FLAG_DISABLE_SYSRAM_SLEEP (1U << 16)
+#define SPM_FLAG_DISABLE_SSPM_SRAM_SLEEP (1U << 17)
+#define SPM_FLAG_DISABLE_MCUPM_SRAM_SLEEP (1U << 18)
+#define SPM_FLAG_RESERVED_BIT19 (1U << 19)
+#define SPM_FLAG_ENABLE_VOLTAGE_BIN (1U << 20)
+#define SPM_FLAG_RESERVED_BIT21 (1U << 21)
+#define SPM_FLAG_DISABLE_DRAMC_MCU_SRAM_SLEEP (1U << 22)
+#define SPM_FLAG_DISABLE_SRAM_EVENT (1U << 23)
+#define SPM_FLAG_RESERVED_BIT24 (1U << 24)
+#define SPM_FLAG_RESERVED_BIT25 (1U << 25)
+#define SPM_FLAG_RESERVED_BIT26 (1U << 26)
+#define SPM_FLAG_DDREN_STATE (1U << 27)
+#define SPM_FLAG_VTCXO_STATE (1U << 28)
+#define SPM_FLAG_INFRA_STATE (1U << 29)
+#define SPM_FLAG_VRF18_STATE (1U << 30)
+#define SPM_FLAG_APSRC_STATE (1U << 31)
+#define SPM_FLAG_SYSTEM_POWER_STATE (1U << 28)
+/* --- SPM Flag1 Define --- */
+#define SPM_FLAG1_DISABLE_AXI_BUS_TO_26M (1U << 0)
+#define SPM_FLAG1_DISABLE_SYSPLL_OFF (1U << 1)
+#define SPM_FLAG1_DISABLE_PWRAP_CLK_SWITCH (1U << 2)
+#define SPM_FLAG1_DISABLE_ULPOSC_OFF (1U << 3)
+#define SPM_FLAG1_FW_SET_ULPOSC_ON (1U << 4)
+#define SPM_FLAG1_RESERVED_BIT5 (1U << 5)
+#define SPM_FLAG1_ENABLE_REKICK (1U << 6)
+#define SPM_FLAG1_RESERVED_BIT7 (1U << 7)
+#define SPM_FLAG1_RESERVED_BIT8 (1U << 8)
+#define SPM_FLAG1_RESERVED_BIT9 (1U << 9)
+#define SPM_FLAG1_DISABLE_SRCLKEN_LOW (1U << 10)
+#define SPM_FLAG1_DISABLE_SCP_CLK_SWITCH (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_RESERVED_BIT15 (1U << 15)
+#define SPM_FLAG1_RESERVED_BIT16 (1U << 16)
+#define SPM_FLAG1_RESERVED_BIT17 (1U << 17)
+#define SPM_FLAG1_RESERVED_BIT18 (1U << 18)
+#define SPM_FLAG1_RESERVED_BIT19 (1U << 19)
+#define SPM_FLAG1_DISABLE_DEVAPC_SRAM_SLEEP (1U << 20)
+#define SPM_FLAG1_RESERVED_BIT21 (1U << 21)
+#define SPM_FLAG1_RESERVED_BIT22 (1U << 22)
+#define SPM_FLAG1_RESERVED_BIT23 (1U << 23)
+#define SPM_FLAG1_DISABLE_SCP_VREQ_MASK_CONTROL (1U << 24)
+#define SPM_FLAG1_RESERVED_BIT25 (1U << 25)
+#define SPM_FLAG1_RESERVED_BIT26 (1U << 26)
+#define SPM_FLAG1_RESERVED_BIT27 (1U << 27)
+#define SPM_FLAG1_RESERVED_BIT28 (1U << 28)
+#define SPM_FLAG1_RESERVED_BIT29 (1U << 29)
+#define SPM_FLAG1_RESERVED_BIT30 (1U << 30)
+#define SPM_FLAG1_ENABLE_MCUPM_OFF (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_DRAM_SREF_ABORT_IN_APSRC (1U << 10)
+#define SPM_DBG_DEBUG_IDX_MCUPM_SRAM_STATE (1U << 11)
+#define SPM_DBG_DEBUG_IDX_SSPM_SRAM_STATE (1U << 12)
+#define SPM_DBG_DEBUG_IDX_DRAM_SREF_ABORT_IN_DDREN (1U << 13)
+#define SPM_DBG_DEBUG_IDX_DRAMC_MCU_SRAM_STATE (1U << 14)
+#define SPM_DBG_DEBUG_IDX_SYSRAM_SLP (1U << 15)
+#define SPM_DBG_DEBUG_IDX_SYSRAM_ON (1U << 16)
+#define SPM_DBG_DEBUG_IDX_MCUPM_SRAM_SLP (1U << 17)
+#define SPM_DBG_DEBUG_IDX_MCUPM_SRAM_ON (1U << 18)
+#define SPM_DBG_DEBUG_IDX_SSPM_SRAM_SLP (1U << 19)
+#define SPM_DBG_DEBUG_IDX_SSPM_SRAM_ON (1U << 20)
+#define SPM_DBG_DEBUG_IDX_DRAMC_MCU_SRAM_SLP (1U << 21)
+#define SPM_DBG_DEBUG_IDX_DRAMC_MCU_SRAM_ON (1U << 22)
+#define SPM_DBG_DEBUG_IDX_APSRC_SLEEP_ABORT (1U << 23)
+#define SPM_DBG_DEBUG_IDX_SPM_GO_WAKEUP_NOW (1U << 27)
+#define SPM_DBG_DEBUG_IDX_VTCXO_STATE (1U << 28)
+#define SPM_DBG_DEBUG_IDX_INFRA_STATE (1U << 29)
+#define SPM_DBG_DEBUG_IDX_VRR18_STATE (1U << 30)
+#define SPM_DBG_DEBUG_IDX_APSRC_STATE (1U << 31)
+/* --- SPM DEBUG1 Define --- */
+#define SPM_DBG1_DEBUG_IDX_CURRENT_IS_LP (1U << 0)
+#define SPM_DBG1_DEBUG_IDX_VCORE_DVFS_START (1U << 1)
+#define SPM_DBG1_DEBUG_IDX_SYSPLL_OFF (1U << 2)
+#define SPM_DBG1_DEBUG_IDX_SYSPLL_ON (1U << 3)
+#define SPM_DBG1_DEBUG_IDX_CURRENT_IS_VCORE_DVFS (1U << 4)
+#define SPM_DBG1_DEBUG_IDX_INFRA_MTCMOS_OFF (1U << 5)
+#define SPM_DBG1_DEBUG_IDX_INFRA_MTCMOS_ON (1U << 6)
+#define SPM_DBG1_DEBUG_IDX_VRCXO_SLEEP_ABORT (1U << 7)
+#define SPM_DBG1_RESERVED_BIT8 (1U << 8)
+#define SPM_DBG1_DEBUG_IDX_PWRAP_CLK_TO_ULPOSC (1U << 11)
+#define SPM_DBG1_DEBUG_IDX_PWRAP_CLK_TO_26M (1U << 12)
+#define SPM_DBG1_DEBUG_IDX_SCP_CLK_TO_32K (1U << 13)
+#define SPM_DBG1_DEBUG_IDX_SCP_CLK_TO_26M (1U << 14)
+#define SPM_DBG1_DEBUG_IDX_BUS_CLK_OFF (1U << 15)
+#define SPM_DBG1_DEBUG_IDX_BUS_CLK_ON (1U << 16)
+#define SPM_DBG1_DEBUG_IDX_SRCLKEN2_LOW (1U << 17)
+#define SPM_DBG1_DEBUG_IDX_SRCLKEN2_HIGH (1U << 18)
+#define SPM_DBG1_DEBUG_IDX_MCUPM_WAKE_IRQ (1U << 19)
+#define SPM_DBG1_DEBUG_IDX_ULPOSC_IS_OFF_BUT_SHOULD_ON (1U << 20)
+#define SPM_DBG1_DEBUG_IDX_PWRAP_SLEEP_ACK_LOW_ABORT (1U << 23)
+#define SPM_DBG1_DEBUG_IDX_PWRAP_SLEEP_ACK_HIGH_ABORT (1U << 24)
+#define SPM_DBG1_DEBUG_IDX_EMI_SLP_IDLE_ABORT (1U << 25)
+#define SPM_DBG1_DEBUG_IDX_SCP_SLP_ACK_LOW_ABORT (1U << 26)
+#define SPM_DBG1_DEBUG_IDX_SCP_SLP_ACK_HIGH_ABORT (1U << 27)
+#define SPM_DBG1_DEBUG_IDX_SPM_DVFS_CMD_RDY_ABORT (1U << 28)
+#define SPM_DBG1_DEBUG_IDX_SPM_TIMER_RST_DVFS (1U << 29)
+#define SPM_DBG1_DEBUG_IDX_SPM_DISABLE_DDREN_EVENT (1U << 30)
+#define MCUPM_RESTORE (1U << 31)
+
+/* Macro and Inline */
+#define is_cpu_pdn(flags) (((flags) & SPM_FLAG_DISABLE_CPU_PDN) == 0U)
+#define is_infra_pdn(flags) (((flags) & SPM_FLAG_DISABLE_INFRA_PDN) == 0U)
+#define is_ddrphy_pdn(flags) (((flags) & SPM_FLAG_DISABLE_DDRPHY_PDN) == 0U)
+
+#endif /* SLEEP_DEF_H */
diff --git a/plat/mediatek/mt8186/drivers/spmc/mtspmc.c b/plat/mediatek/mt8186/drivers/spmc/mtspmc.c
new file mode 100644
index 0000000..91ef096
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spmc/mtspmc.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <mcucfg.h>
+#include <mtspmc.h>
+#include <mtspmc_private.h>
+#include <plat/common/platform.h>
+
+void mcucfg_disable_gic_wakeup(unsigned int cluster, unsigned int cpu)
+{
+ mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(cpu));
+}
+
+void mcucfg_enable_gic_wakeup(unsigned int cluster, unsigned int cpu)
+{
+ mmio_clrbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(cpu));
+ /* Clear cpu's cpc sw hint */
+ mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_CLR, BIT(cpu));
+}
+
+void mcucfg_set_bootaddr(unsigned int cluster, unsigned int cpu, uintptr_t bootaddr)
+{
+ assert(cluster == 0U);
+
+ mmio_write_32(per_cpu(cluster, cpu, MCUCFG_BOOTADDR), bootaddr);
+}
+
+uintptr_t mcucfg_get_bootaddr(unsigned int cluster, unsigned int cpu)
+{
+ assert(cluster == 0U);
+
+ return (uintptr_t)mmio_read_32(per_cpu(cluster, cpu, MCUCFG_BOOTADDR));
+}
+
+void mcucfg_init_archstate(unsigned int cluster, unsigned int cpu, bool arm64)
+{
+ uint32_t reg;
+
+ assert(cluster == 0U);
+
+ reg = per_cluster(cluster, MCUCFG_INITARCH);
+
+ if (arm64) {
+ mmio_setbits_32(reg, MCUCFG_INITARCH_CPU_BIT(cpu));
+ } else {
+ mmio_clrbits_32(reg, MCUCFG_INITARCH_CPU_BIT(cpu));
+ }
+}
+
+/*
+ * Return subsystem's power state.
+ *
+ * @mask: mask to SPM_CPU_PWR_STATUS to query the power state
+ * of one subsystem.
+ * RETURNS:
+ * 0 (the subsys was powered off)
+ * 1 (the subsys was powered on)
+ */
+bool spm_get_powerstate(uint32_t mask)
+{
+ return (mmio_read_32(SPM_CPU_PWR_STATUS) & mask);
+}
+
+bool spm_get_cluster_powerstate(unsigned int cluster)
+{
+ assert(cluster == 0U);
+
+ return spm_get_powerstate(MP0_CPUTOP);
+}
+
+bool spm_get_cpu_powerstate(unsigned int cluster, unsigned int cpu)
+{
+ uint32_t mask = BIT(cpu);
+
+ assert(cluster == 0U);
+
+ return spm_get_powerstate(mask);
+}
+
+int spmc_init(void)
+{
+ unsigned int cpu = plat_my_core_pos();
+
+
+ INFO("SPM: enable CPC mode\n");
+
+ mmio_write_32(SPM_POWERON_CONFIG_EN, PROJECT_CODE | BCLK_CG_EN);
+
+ mmio_setbits_32(per_cpu(0, 1, SPM_CPU_PWR), PWR_RST_B);
+ mmio_setbits_32(per_cpu(0, 2, SPM_CPU_PWR), PWR_RST_B);
+ mmio_setbits_32(per_cpu(0, 3, SPM_CPU_PWR), PWR_RST_B);
+ mmio_setbits_32(per_cpu(0, 4, SPM_CPU_PWR), PWR_RST_B);
+ mmio_setbits_32(per_cpu(0, 5, SPM_CPU_PWR), PWR_RST_B);
+ mmio_setbits_32(per_cpu(0, 6, SPM_CPU_PWR), PWR_RST_B);
+ mmio_setbits_32(per_cpu(0, 7, SPM_CPU_PWR), PWR_RST_B);
+
+ mmio_clrbits_32(SPM_MCUSYS_PWR_CON, RESETPWRON_CONFIG);
+ mmio_clrbits_32(SPM_MP0_CPUTOP_PWR_CON, RESETPWRON_CONFIG);
+ mmio_clrbits_32(per_cpu(0, 0, SPM_CPU_PWR), RESETPWRON_CONFIG);
+
+ mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, CPC_CTRL_ENABLE);
+
+ /* Clear bootup cpu's cpc sw hint */
+ mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_CLR, BIT(cpu));
+
+ 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(unsigned int cluster, unsigned int cpu)
+{
+ /* info CPC that CPU hotplug on */
+ mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, SSPM_ALL_PWR_CTRL_EN);
+
+ /* Set mp0_spmc_pwr_on_cpuX = 1 */
+ mmio_setbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWR_ON);
+
+ /* wait for power on ack */
+ while (!spm_get_cpu_powerstate(cluster, cpu))
+ ;
+
+ /* info CPC that CPU hotplug off */
+ mmio_clrbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, SSPM_ALL_PWR_CTRL_EN);
+}
+
+/*
+ * 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(unsigned int cluster, unsigned int cpu)
+{
+ /* Set mp0_spmc_pwr_on_cpuX = 0 */
+ mmio_clrbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWR_ON);
+}
+
+/*
+ * Power off a cluster with specified index
+ *
+ * @cluster: the cluster index which to be powered off
+ */
+void spm_poweroff_cluster(unsigned int cluster)
+{
+ /* No need to power on/off cluster on single cluster platform */
+ assert(false);
+}
+
+/*
+ * Power on a cluster with specified index
+ *
+ * @cluster: the cluster index which to be powered on
+ */
+void spm_poweron_cluster(unsigned int cluster)
+{
+ /* No need to power on/off cluster on single cluster platform */
+ assert(false);
+}
diff --git a/plat/mediatek/mt8186/drivers/spmc/mtspmc.h b/plat/mediatek/mt8186/drivers/spmc/mtspmc.h
new file mode 100644
index 0000000..768599b
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spmc/mtspmc.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTSPMC_H
+#define MTSPMC_H
+
+#include <stdint.h>
+
+int spmc_init(void);
+
+void spm_poweron_cpu(unsigned int cluster, unsigned int cpu);
+void spm_poweroff_cpu(unsigned int cluster, unsigned int cpu);
+
+void spm_poweroff_cluster(unsigned int cluster);
+void spm_poweron_cluster(unsigned int cluster);
+
+bool spm_get_cpu_powerstate(unsigned int cluster, unsigned int cpu);
+bool spm_get_cluster_powerstate(unsigned int cluster);
+bool spm_get_powerstate(uint32_t mask);
+
+void mcucfg_init_archstate(unsigned int cluster, unsigned int cpu, bool arm64);
+void mcucfg_set_bootaddr(unsigned int cluster, unsigned int cpu, uintptr_t bootaddr);
+uintptr_t mcucfg_get_bootaddr(unsigned int cluster, unsigned int cpu);
+
+void mcucfg_disable_gic_wakeup(unsigned int cluster, unsigned int cpu);
+void mcucfg_enable_gic_wakeup(unsigned int cluster, unsigned int cpu);
+
+#endif /* MTSPMC_H */
diff --git a/plat/mediatek/mt8186/drivers/spmc/mtspmc_private.h b/plat/mediatek/mt8186/drivers/spmc/mtspmc_private.h
new file mode 100644
index 0000000..472b54c
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spmc/mtspmc_private.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTSPMC_PRIVATE_H
+#define MTSPMC_PRIVATE_H
+
+#include <lib/utils_def.h>
+#include <platform_def.h>
+
+unsigned long read_cpuectlr(void);
+void write_cpuectlr(unsigned long cpuectlr);
+
+unsigned long read_cpupwrctlr_el1(void);
+void write_cpupwrctlr_el1(unsigned long cpuectlr);
+
+/* per_cpu/cluster helper */
+struct per_cpu_reg {
+ unsigned int cluster_addr;
+ unsigned 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)
+
+#define SPM_REG(ofs) (uint32_t)(SPM_BASE + (ofs))
+#define MCUCFG_REG(ofs) (uint32_t)(MCUCFG_BASE + (ofs))
+#define INFRACFG_AO_REG(ofs) (uint32_t)(INFRACFG_AO_BASE + (ofs))
+
+/* SPMC related registers */
+#define SPM_POWERON_CONFIG_EN SPM_REG(0x000)
+/* bit-fields of SPM_POWERON_CONFIG_EN */
+#define PROJECT_CODE (U(0xb16) << 16)
+#define BCLK_CG_EN BIT(0)
+
+#define SPM_PWR_STATUS SPM_REG(0x16c)
+#define SPM_PWR_STATUS_2ND SPM_REG(0x170)
+#define SPM_CPU_PWR_STATUS SPM_REG(0x174)
+
+/* bit-fields of SPM_PWR_STATUS */
+#define MD BIT(0)
+#define CONN BIT(1)
+#define DDRPHY BIT(2)
+#define DISP BIT(3)
+#define MFG BIT(4)
+#define ISP BIT(5)
+#define INFRA BIT(6)
+#define VDEC BIT(7)
+#define MP0_CPUTOP BIT(8)
+#define MP0_CPU0 BIT(9)
+#define MP0_CPU1 BIT(10)
+#define MP0_CPU2 BIT(11)
+#define MP0_CPU3 BIT(12)
+#define MCUSYS BIT(14)
+#define MP0_CPU4 BIT(15)
+#define MP0_CPU5 BIT(16)
+#define MP0_CPU6 BIT(17)
+#define MP0_CPU7 BIT(18)
+#define VEN BIT(21)
+
+/* SPMC related registers */
+#define SPM_MCUSYS_PWR_CON SPM_REG(0x200)
+#define SPM_MP0_CPUTOP_PWR_CON SPM_REG(0x204)
+#define SPM_MP0_CPU0_PWR_CON SPM_REG(0x208)
+#define SPM_MP0_CPU1_PWR_CON SPM_REG(0x20c)
+#define SPM_MP0_CPU2_PWR_CON SPM_REG(0x210)
+#define SPM_MP0_CPU3_PWR_CON SPM_REG(0x214)
+#define SPM_MP0_CPU4_PWR_CON SPM_REG(0x218)
+#define SPM_MP0_CPU5_PWR_CON SPM_REG(0x21c)
+#define SPM_MP0_CPU6_PWR_CON SPM_REG(0x220)
+#define SPM_MP0_CPU7_PWR_CON SPM_REG(0x224)
+
+/* bit-fields of SPM_*_PWR_CON */
+#define PWR_ON_ACK BIT(31)
+#define VPROC_EXT_OFF BIT(7)
+#define DORMANT_EN BIT(6)
+#define RESETPWRON_CONFIG BIT(5)
+#define PWR_CLK_DIS BIT(4)
+#define PWR_ON BIT(2)
+#define PWR_RST_B BIT(0)
+
+/* per_cpu registers for SPM_MP0_CPU_PWR_CON */
+static const struct per_cpu_reg SPM_CPU_PWR[] = {
+ { .cluster_addr = SPM_MP0_CPU0_PWR_CON, .cpu_stride = 2U }
+};
+
+/* per_cluster registers for SPM_MP0_CPUTOP_PWR_CON */
+static const struct per_cpu_reg SPM_CLUSTER_PWR[] = {
+ { .cluster_addr = SPM_MP0_CPUTOP_PWR_CON, .cpu_stride = 0U }
+};
+
+/* MCUCFG related registers */
+#define MCUCFG_MP0_CLUSTER_CFG5 MCUCFG_REG(0xc8e4)
+/* reset vectors */
+#define MCUCFG_MP0_CLUSTER_CFG8 MCUCFG_REG(0xc900)
+#define MCUCFG_MP0_CLUSTER_CFG10 MCUCFG_REG(0xc908)
+#define MCUCFG_MP0_CLUSTER_CFG12 MCUCFG_REG(0xc910)
+#define MCUCFG_MP0_CLUSTER_CFG14 MCUCFG_REG(0xc918)
+#define MCUCFG_MP0_CLUSTER_CFG16 MCUCFG_REG(0xc920)
+#define MCUCFG_MP0_CLUSTER_CFG18 MCUCFG_REG(0xc928)
+#define MCUCFG_MP0_CLUSTER_CFG20 MCUCFG_REG(0xc930)
+#define MCUCFG_MP0_CLUSTER_CFG22 MCUCFG_REG(0xc938)
+
+/* per_cpu registers for MCUCFG_MP0_CLUSTER_CFG */
+static const struct per_cpu_reg MCUCFG_BOOTADDR[] = {
+ { .cluster_addr = MCUCFG_MP0_CLUSTER_CFG8, .cpu_stride = 3U }
+};
+
+/* per_cpu registers for MCUCFG_MP0_CLUSTER_CFG5 */
+static const struct per_cpu_reg MCUCFG_INITARCH[] = {
+ { .cluster_addr = MCUCFG_MP0_CLUSTER_CFG5, .cpu_stride = 0U }
+};
+
+#define MCUCFG_INITARCH_CPU_BIT(cpu) BIT(16U + cpu)
+/* CPC control */
+#define MCUCFG_CPC_FLOW_CTRL_CFG MCUCFG_REG(0xa814)
+#define MCUCFG_CPC_SPMC_PWR_STATUS MCUCFG_REG(0xa840)
+
+/* bit-fields of CPC_FLOW_CTRL_CFG */
+#define CPC_CTRL_ENABLE BIT(16)
+#define SSPM_ALL_PWR_CTRL_EN BIT(13) /* for cpu-hotplug */
+#define GIC_WAKEUP_IGNORE(cpu) BIT(21 + cpu)
+
+/* bit-fields of CPC_SPMC_PWR_STATUS */
+#define CORE_SPMC_PWR_ON_ACK GENMASK(11, 0)
+
+/* APB module infracfg_ao */
+#define INFRA_TOPAXI_PROTECTEN INFRACFG_AO_REG(0x0220)
+#define INFRA_TOPAXI_PROTECTEN_STA0 INFRACFG_AO_REG(0x0224)
+#define INFRA_TOPAXI_PROTECTEN_STA1 INFRACFG_AO_REG(0x0228)
+#define INFRA_TOPAXI_PROTECTEN_SET INFRACFG_AO_REG(0x02a0)
+#define INFRA_TOPAXI_PROTECTEN_CLR INFRACFG_AO_REG(0x02a4)
+#define INFRA_TOPAXI_PROTECTEN_1 INFRACFG_AO_REG(0x0250)
+#define INFRA_TOPAXI_PROTECTEN_STA0_1 INFRACFG_AO_REG(0x0254)
+#define INFRA_TOPAXI_PROTECTEN_STA1_1 INFRACFG_AO_REG(0x0258)
+#define INFRA_TOPAXI_PROTECTEN_1_SET INFRACFG_AO_REG(0x02a8)
+#define INFRA_TOPAXI_PROTECTEN_1_CLR INFRACFG_AO_REG(0x02ac)
+
+/* bit-fields of INFRA_TOPAXI_PROTECTEN */
+#define MP0_SPMC_PROT_STEP1_0_MASK BIT(12)
+#define MP0_SPMC_PROT_STEP1_1_MASK (BIT(26) | BIT(12))
+
+/* SPARK */
+#define VOLTAGE_04 U(0x40)
+#define VOLTAGE_05 U(0x60)
+
+#define PTP3_CPU0_SPMC_SW_CFG MCUCFG_REG(0x200)
+#define CPU0_ILDO_CONTROL5 MCUCFG_REG(0x334)
+#define CPU0_ILDO_CONTROL8 MCUCFG_REG(0x340)
+
+/* bit-fields of CPU0_ILDO_CONTROL5 */
+#define ILDO_RET_VOSEL GENMASK(7, 0)
+
+/* bit-fields of PTP3_CPU_SPMC_SW_CFG */
+#define SW_SPARK_EN BIT(0)
+
+/* bit-fields of CPU0_ILDO_CONTROL8 */
+#define ILDO_BYPASS_B BIT(0)
+
+static const struct per_cpu_reg MCUCFG_SPARK[] = {
+ { .cluster_addr = PTP3_CPU0_SPMC_SW_CFG, .cpu_stride = 11U }
+};
+
+static const struct per_cpu_reg ILDO_CONTROL5[] = {
+ { .cluster_addr = CPU0_ILDO_CONTROL5, .cpu_stride = 11U }
+};
+
+static const struct per_cpu_reg ILDO_CONTROL8[] = {
+ { .cluster_addr = CPU0_ILDO_CONTROL8, .cpu_stride = 11U }
+};
+
+#endif /* MTSPMC_PRIVATE_H */
diff --git a/plat/mediatek/mt8186/include/mcucfg.h b/plat/mediatek/mt8186/include/mcucfg.h
new file mode 100644
index 0000000..78a01a8
--- /dev/null
+++ b/plat/mediatek/mt8186/include/mcucfg.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MCUCFG_H
+#define MCUCFG_H
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+#endif /* __ASSEMBLER__ */
+
+#include <platform_def.h>
+
+#define MCUCFG_REG(ofs) (uint32_t)(MCUCFG_BASE + (ofs))
+
+#define MP2_MISC_CONFIG_BOOT_ADDR_L(cpu) (MCUCFG_REG(0x2290) + ((cpu) * 8))
+#define MP2_MISC_CONFIG_BOOT_ADDR_H(cpu) (MCUCFG_REG(0x2294) + ((cpu) * 8))
+
+#define MP2_CPUCFG MCUCFG_REG(0x2208)
+
+#define MP2_CPU0_STANDBYWFE BIT(4)
+#define MP2_CPU1_STANDBYWFE BIT(5)
+
+#define MP0_CPUTOP_SPMC_CTL MCUCFG_REG(0x788)
+#define MP1_CPUTOP_SPMC_CTL MCUCFG_REG(0x78C)
+#define MP1_CPUTOP_SPMC_SRAM_CTL MCUCFG_REG(0x790)
+
+#define sw_spark_en BIT(0)
+#define sw_no_wait_for_q_channel BIT(1)
+#define sw_fsm_override BIT(2)
+#define sw_logic_pre1_pdb BIT(3)
+#define sw_logic_pre2_pdb BIT(4)
+#define sw_logic_pdb BIT(5)
+#define sw_iso BIT(6)
+#define sw_sram_sleepb (U(0x3F) << 7)
+#define sw_sram_isointb BIT(13)
+#define sw_clk_dis BIT(14)
+#define sw_ckiso BIT(15)
+#define sw_pd (U(0x3F) << 16)
+#define sw_hot_plug_reset BIT(22)
+#define sw_pwr_on_override_en BIT(23)
+#define sw_pwr_on BIT(24)
+#define sw_coq_dis BIT(25)
+#define logic_pdbo_all_off_ack BIT(26)
+#define logic_pdbo_all_on_ack BIT(27)
+#define logic_pre2_pdbo_all_on_ack BIT(28)
+#define logic_pre1_pdbo_all_on_ack BIT(29)
+
+
+#define CPUSYSx_CPUx_SPMC_CTL(cluster, cpu) \
+ (MCUCFG_REG(0x1c30) + cluster * 0x2000 + cpu * 4)
+
+#define CPUSYS0_CPU0_SPMC_CTL MCUCFG_REG(0x1c30)
+#define CPUSYS0_CPU1_SPMC_CTL MCUCFG_REG(0x1c34)
+#define CPUSYS0_CPU2_SPMC_CTL MCUCFG_REG(0x1c38)
+#define CPUSYS0_CPU3_SPMC_CTL MCUCFG_REG(0x1c3C)
+
+#define CPUSYS1_CPU0_SPMC_CTL MCUCFG_REG(0x3c30)
+#define CPUSYS1_CPU1_SPMC_CTL MCUCFG_REG(0x3c34)
+#define CPUSYS1_CPU2_SPMC_CTL MCUCFG_REG(0x3c38)
+#define CPUSYS1_CPU3_SPMC_CTL MCUCFG_REG(0x3c3C)
+
+#define cpu_sw_spark_en BIT(0)
+#define cpu_sw_no_wait_for_q_channel BIT(1)
+#define cpu_sw_fsm_override BIT(2)
+#define cpu_sw_logic_pre1_pdb BIT(3)
+#define cpu_sw_logic_pre2_pdb BIT(4)
+#define cpu_sw_logic_pdb BIT(5)
+#define cpu_sw_iso BIT(6)
+#define cpu_sw_sram_sleepb BIT(7)
+#define cpu_sw_sram_isointb BIT(8)
+#define cpu_sw_clk_dis BIT(9)
+#define cpu_sw_ckiso BIT(10)
+#define cpu_sw_pd (U(0x1F) << 11)
+#define cpu_sw_hot_plug_reset BIT(16)
+#define cpu_sw_powr_on_override_en BIT(17)
+#define cpu_sw_pwr_on BIT(18)
+#define cpu_spark2ldo_allswoff BIT(19)
+#define cpu_pdbo_all_on_ack BIT(20)
+#define cpu_pre2_pdbo_allon_ack BIT(21)
+#define cpu_pre1_pdbo_allon_ack BIT(22)
+
+/* CPC related registers */
+#define CPC_MCUSYS_CPC_OFF_THRES MCUCFG_REG(0xa714)
+#define CPC_MCUSYS_PWR_CTRL MCUCFG_REG(0xa804)
+#define CPC_MCUSYS_CPC_FLOW_CTRL_CFG MCUCFG_REG(0xa814)
+#define CPC_MCUSYS_LAST_CORE_REQ MCUCFG_REG(0xa818)
+#define CPC_MCUSYS_MP_LAST_CORE_RESP MCUCFG_REG(0xa81c)
+#define CPC_MCUSYS_LAST_CORE_RESP MCUCFG_REG(0xa824)
+#define CPC_MCUSYS_PWR_ON_MASK MCUCFG_REG(0xa828)
+#define CPC_MCUSYS_CPU_ON_SW_HINT_SET MCUCFG_REG(0xa8a8)
+#define CPC_MCUSYS_CPU_ON_SW_HINT_CLR MCUCFG_REG(0xa8ac)
+#define CPC_MCUSYS_CPC_DBG_SETTING MCUCFG_REG(0xab00)
+#define CPC_MCUSYS_CPC_KERNEL_TIME_L_BASE MCUCFG_REG(0xab04)
+#define CPC_MCUSYS_CPC_KERNEL_TIME_H_BASE MCUCFG_REG(0xab08)
+#define CPC_MCUSYS_CPC_SYSTEM_TIME_L_BASE MCUCFG_REG(0xab0c)
+#define CPC_MCUSYS_CPC_SYSTEM_TIME_H_BASE MCUCFG_REG(0xab10)
+#define CPC_MCUSYS_TRACE_SEL MCUCFG_REG(0xab14)
+#define CPC_MCUSYS_TRACE_DATA MCUCFG_REG(0xab20)
+#define CPC_MCUSYS_CLUSTER_COUNTER MCUCFG_REG(0xab70)
+#define CPC_MCUSYS_CLUSTER_COUNTER_CLR MCUCFG_REG(0xab74)
+#define SPARK2LDO MCUCFG_REG(0x2700)
+/* APB module mcucfg */
+#define MP0_CA7_CACHE_CONFIG MCUCFG_REG(0x000)
+#define MP0_AXI_CONFIG MCUCFG_REG(0x02C)
+#define MP0_MISC_CONFIG0 MCUCFG_REG(0x030)
+#define MP0_MISC_CONFIG1 MCUCFG_REG(0x034)
+#define MP0_MISC_CONFIG2 MCUCFG_REG(0x038)
+#define MP0_MISC_CONFIG_BOOT_ADDR(cpu) (MP0_MISC_CONFIG2 + ((cpu) * 8))
+#define MP0_MISC_CONFIG3 MCUCFG_REG(0x03C)
+#define MP0_MISC_CONFIG9 MCUCFG_REG(0x054)
+#define MP0_CA7_MISC_CONFIG MCUCFG_REG(0x064)
+
+#define MP0_RW_RSVD0 MCUCFG_REG(0x06C)
+
+
+#define MP1_CA7_CACHE_CONFIG MCUCFG_REG(0x200)
+#define MP1_AXI_CONFIG MCUCFG_REG(0x22C)
+#define MP1_MISC_CONFIG0 MCUCFG_REG(0x230)
+#define MP1_MISC_CONFIG1 MCUCFG_REG(0x234)
+#define MP1_MISC_CONFIG2 MCUCFG_REG(0x238)
+#define MP1_MISC_CONFIG_BOOT_ADDR(cpu) (MP1_MISC_CONFIG2 + ((cpu) * 8))
+#define MP1_MISC_CONFIG3 MCUCFG_REG(0x23C)
+#define MP1_MISC_CONFIG9 MCUCFG_REG(0x254)
+#define MP1_CA7_MISC_CONFIG MCUCFG_REG(0x264)
+
+#define CCI_ADB400_DCM_CONFIG MCUCFG_REG(0x740)
+#define SYNC_DCM_CONFIG MCUCFG_REG(0x744)
+
+#define MP0_CLUSTER_CFG0 MCUCFG_REG(0xC8D0)
+
+#define MP0_SPMC MCUCFG_REG(0x788)
+#define MP1_SPMC MCUCFG_REG(0x78C)
+#define MP2_AXI_CONFIG MCUCFG_REG(0x220C)
+#define MP2_AXI_CONFIG_ACINACTM BIT(0)
+#define MP2_AXI_CONFIG_AINACTS BIT(4)
+
+#define MPx_AXI_CONFIG_ACINACTM BIT(4)
+#define MPx_AXI_CONFIG_AINACTS BIT(5)
+#define MPx_CA7_MISC_CONFIG_standbywfil2 BIT(28)
+
+#define MP0_CPU0_STANDBYWFE BIT(20)
+#define MP0_CPU1_STANDBYWFE BIT(21)
+#define MP0_CPU2_STANDBYWFE BIT(22)
+#define MP0_CPU3_STANDBYWFE BIT(23)
+
+#define MP1_CPU0_STANDBYWFE BIT(20)
+#define MP1_CPU1_STANDBYWFE BIT(21)
+#define MP1_CPU2_STANDBYWFE BIT(22)
+#define MP1_CPU3_STANDBYWFE BIT(23)
+
+#define CPUSYS0_SPARKVRETCNTRL MCUCFG_REG(0x1c00)
+#define CPUSYS0_SPARKEN MCUCFG_REG(0x1c04)
+#define CPUSYS0_AMUXSEL MCUCFG_REG(0x1c08)
+#define CPUSYS1_SPARKVRETCNTRL MCUCFG_REG(0x3c00)
+#define CPUSYS1_SPARKEN MCUCFG_REG(0x3c04)
+#define CPUSYS1_AMUXSEL MCUCFG_REG(0x3c08)
+
+#define MP2_PWR_RST_CTL MCUCFG_REG(0x2008)
+#define MP2_PTP3_CPUTOP_SPMC0 MCUCFG_REG(0x22A0)
+#define MP2_PTP3_CPUTOP_SPMC1 MCUCFG_REG(0x22A4)
+
+#define MP2_COQ MCUCFG_REG(0x22BC)
+#define MP2_COQ_SW_DIS BIT(0)
+
+#define MP2_CA15M_MON_SEL MCUCFG_REG(0x2400)
+#define MP2_CA15M_MON_L MCUCFG_REG(0x2404)
+
+#define CPUSYS2_CPU0_SPMC_CTL MCUCFG_REG(0x2430)
+#define CPUSYS2_CPU1_SPMC_CTL MCUCFG_REG(0x2438)
+#define CPUSYS2_CPU0_SPMC_STA MCUCFG_REG(0x2434)
+#define CPUSYS2_CPU1_SPMC_STA MCUCFG_REG(0x243C)
+
+#define MP0_CA7L_DBG_PWR_CTRL MCUCFG_REG(0x068)
+#define MP1_CA7L_DBG_PWR_CTRL MCUCFG_REG(0x268)
+#define BIG_DBG_PWR_CTRL MCUCFG_REG(0x75C)
+
+#define MP2_SW_RST_B BIT(0)
+#define MP2_TOPAON_APB_MASK BIT(1)
+
+#define B_SW_HOT_PLUG_RESET BIT(30)
+
+#define B_SW_PD_OFFSET (18U)
+#define B_SW_PD (U(0x3f) << B_SW_PD_OFFSET)
+
+#define B_SW_SRAM_SLEEPB_OFFSET (12U)
+#define B_SW_SRAM_SLEEPB (U(0x3f) << B_SW_SRAM_SLEEPB_OFFSET)
+
+#define B_SW_SRAM_ISOINTB BIT(9)
+#define B_SW_ISO BIT(8)
+#define B_SW_LOGIC_PDB BIT(7)
+#define B_SW_LOGIC_PRE2_PDB BIT(6)
+#define B_SW_LOGIC_PRE1_PDB BIT(5)
+#define B_SW_FSM_OVERRIDE BIT(4)
+#define B_SW_PWR_ON BIT(3)
+#define B_SW_PWR_ON_OVERRIDE_EN BIT(2)
+
+#define B_FSM_STATE_OUT_OFFSET (6U)
+#define B_FSM_STATE_OUT_MASK (U(0x1f) << B_FSM_STATE_OUT_OFFSET)
+#define B_SW_LOGIC_PDBO_ALL_OFF_ACK BIT(5)
+#define B_SW_LOGIC_PDBO_ALL_ON_ACK BIT(4)
+#define B_SW_LOGIC_PRE2_PDBO_ALL_ON_ACK BIT(3)
+#define B_SW_LOGIC_PRE1_PDBO_ALL_ON_ACK BIT(2)
+
+#define B_FSM_OFF (0U << B_FSM_STATE_OUT_OFFSET)
+#define B_FSM_ON (1U << B_FSM_STATE_OUT_OFFSET)
+#define B_FSM_RET (2U << B_FSM_STATE_OUT_OFFSET)
+
+#ifndef __ASSEMBLER__
+/* cpu boot mode */
+enum {
+ MP0_CPUCFG_64BIT_SHIFT = 12U,
+ MP1_CPUCFG_64BIT_SHIFT = 28U,
+ MP0_CPUCFG_64BIT = U(0xf) << MP0_CPUCFG_64BIT_SHIFT,
+ MP1_CPUCFG_64BIT = U(0xf) << MP1_CPUCFG_64BIT_SHIFT
+};
+
+enum {
+ MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT = 0U,
+ MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT = 4U,
+ MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT = 8U,
+ MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT = 12U,
+ MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT = 16U,
+
+ MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK =
+ U(0xf) << MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT,
+ MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK =
+ U(0xf) << MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT,
+ MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK =
+ U(0xf) << MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT,
+ MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK =
+ U(0xf) << MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT,
+ MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK =
+ U(0xf) << MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT
+};
+
+enum {
+ MP1_AINACTS_SHIFT = 4U,
+ MP1_AINACTS = 1U << MP1_AINACTS_SHIFT
+};
+
+enum {
+ MP1_SW_CG_GEN_SHIFT = 12U,
+ MP1_SW_CG_GEN = 1U << MP1_SW_CG_GEN_SHIFT
+};
+
+enum {
+ MP1_L2RSTDISABLE_SHIFT = 14U,
+ MP1_L2RSTDISABLE = 1U << MP1_L2RSTDISABLE_SHIFT
+};
+#endif /* __ASSEMBLER__ */
+
+#endif /* MCUCFG_H */
diff --git a/plat/mediatek/mt8186/include/mt_spm_resource_req.h b/plat/mediatek/mt8186/include/mt_spm_resource_req.h
new file mode 100644
index 0000000..9761e79
--- /dev/null
+++ b/plat/mediatek/mt8186/include/mt_spm_resource_req.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_RESOURCE_REQ_H
+#define MT_SPM_RESOURCE_REQ_H
+
+/* SPM resource request internal bit */
+#define MT_SPM_BIT_XO_FPM (0U)
+#define MT_SPM_BIT_26M (1U)
+#define MT_SPM_BIT_INFRA (2U)
+#define MT_SPM_BIT_SYSPLL (3U)
+#define MT_SPM_BIT_DRAM_S0 (4U)
+#define MT_SPM_BIT_DRAM_S1 (5U)
+
+/* SPM resource request internal bit_mask */
+#define MT_SPM_XO_FPM BIT(MT_SPM_BIT_XO_FPM)
+#define MT_SPM_26M BIT(MT_SPM_BIT_26M)
+#define MT_SPM_INFRA BIT(MT_SPM_BIT_INFRA)
+#define MT_SPM_SYSPLL BIT(MT_SPM_BIT_SYSPLL)
+#define MT_SPM_DRAM_S0 BIT(MT_SPM_BIT_DRAM_S0)
+#define MT_SPM_DRAM_S1 BIT(MT_SPM_BIT_DRAM_S1)
+
+char spm_resource_req(unsigned int user, unsigned int req_mask);
+
+#define IS_PLAT_SUSPEND_ID(stateid)\
+ ((stateid == MT_PLAT_PWR_STATE_SUSPEND2IDLE)\
+ || (stateid == MT_PLAT_PWR_STATE_SYSTEM_SUSPEND))
+
+#endif /* MT_SPM_RESOURCE_REQ_H */
diff --git a/plat/mediatek/mt8186/include/plat_helpers.h b/plat/mediatek/mt8186/include/plat_helpers.h
new file mode 100644
index 0000000..ebc9fa0
--- /dev/null
+++ b/plat/mediatek/mt8186/include/plat_helpers.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLAT_HELPERS_H__
+#define __PLAT_HELPERS_H__
+
+unsigned int plat_mediatek_calc_core_pos(u_register_t mpidr);
+
+#endif /* __PLAT_HELPERS_H__ */
diff --git a/plat/mediatek/mt8186/include/plat_macros.S b/plat/mediatek/mt8186/include/plat_macros.S
new file mode 100644
index 0000000..39727ea
--- /dev/null
+++ b/plat/mediatek/mt8186/include/plat_macros.S
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <platform_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"
+
+.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.
+ * Clobbers: x0 - x10, x26, x27, sp
+ * ---------------------------------------------
+ */
+ .macro plat_crash_print_regs
+ /* TODO: leave implementation to GIC owner */
+ .endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/mediatek/mt8186/include/plat_mtk_lpm.h b/plat/mediatek/mt8186/include/plat_mtk_lpm.h
new file mode 100644
index 0000000..12ea9d7
--- /dev/null
+++ b/plat/mediatek/mt8186/include/plat_mtk_lpm.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MTK_LPM_H
+#define PLAT_MTK_LPM_H
+
+#include <lib/psci/psci.h>
+#include <lib/utils_def.h>
+
+#define MT_IRQ_REMAIN_MAX U(32)
+#define MT_IRQ_REMAIN_CAT_LOG BIT(31)
+
+struct mt_irqremain {
+ unsigned int count;
+ unsigned int irqs[MT_IRQ_REMAIN_MAX];
+ unsigned int wakeupsrc_cat[MT_IRQ_REMAIN_MAX];
+ unsigned int wakeupsrc[MT_IRQ_REMAIN_MAX];
+};
+
+#define PLAT_RC_STATUS_READY BIT(0)
+#define PLAT_RC_STATUS_FEATURE_EN BIT(1)
+#define PLAT_RC_STATUS_UART_NONSLEEP BIT(31)
+
+struct mt_lpm_tz {
+ int (*pwr_prompt)(unsigned int cpu, const psci_power_state_t *state);
+ int (*pwr_reflect)(unsigned int cpu, const psci_power_state_t *state);
+
+ int (*pwr_cpu_on)(unsigned int cpu, const psci_power_state_t *state);
+ int (*pwr_cpu_dwn)(unsigned int cpu, const psci_power_state_t *state);
+
+ int (*pwr_cluster_on)(unsigned int cpu,
+ const psci_power_state_t *state);
+ int (*pwr_cluster_dwn)(unsigned int cpu,
+ const psci_power_state_t *state);
+
+ int (*pwr_mcusys_on)(unsigned int cpu, const psci_power_state_t *state);
+ int (*pwr_mcusys_on_finished)(unsigned int cpu,
+ const psci_power_state_t *state);
+ int (*pwr_mcusys_dwn)(unsigned int cpu,
+ const psci_power_state_t *state);
+};
+
+const struct mt_lpm_tz *mt_plat_cpu_pm_init(void);
+int plat_mt_pm_register(struct mt_lpm_tz *mt_pm);
+
+#endif /* PLAT_MTK_LPM_H */
diff --git a/plat/mediatek/mt8186/include/plat_pm.h b/plat/mediatek/mt8186/include/plat_pm.h
new file mode 100644
index 0000000..ec70e4b
--- /dev/null
+++ b/plat/mediatek/mt8186/include/plat_pm.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PM_H
+#define PLAT_PM_H
+
+#include <lib/utils_def.h>
+
+#ifndef __ASSEMBLY__
+extern uintptr_t mtk_suspend_footprint_addr;
+extern uintptr_t mtk_suspend_timestamp_addr;
+
+#define MT_PLAT_PWR_STATE_CPU U(1)
+#define MT_PLAT_PWR_STATE_CLUSTER U(2)
+#define MT_PLAT_PWR_STATE_MCUSYS U(3)
+#define MT_PLAT_PWR_STATE_SUSPEND2IDLE U(8)
+#define MT_PLAT_PWR_STATE_SYSTEM_SUSPEND U(9)
+
+#define MTK_LOCAL_STATE_RUN U(0)
+#define MTK_LOCAL_STATE_RET U(1)
+#define MTK_LOCAL_STATE_OFF U(2)
+
+#define MTK_AFFLVL_CPU U(0)
+#define MTK_AFFLVL_CLUSTER U(1)
+#define MTK_AFFLVL_MCUSYS U(2)
+#define MTK_AFFLVL_SYSTEM U(3)
+
+void mtk_suspend_footprint_log(int idx);
+void mtk_suspend_timestamp_log(int idx);
+
+int mt_cluster_ops(int cputop_mpx, int mode, int state);
+int mt_core_ops(int cpux, int state);
+
+#define IS_CLUSTER_OFF_STATE(s) \
+ is_local_state_off(s->pwr_domain_state[MTK_AFFLVL_CLUSTER])
+#define IS_MCUSYS_OFF_STATE(s) \
+ is_local_state_off(s->pwr_domain_state[MTK_AFFLVL_MCUSYS])
+#define IS_SYSTEM_SUSPEND_STATE(s) \
+ is_local_state_off(s->pwr_domain_state[MTK_AFFLVL_SYSTEM])
+
+/* SMC secure magic number */
+#define SPM_LP_SMC_MAGIC (0xDAF10000)
+
+#define IS_SPM_LP_SMC(_type, _id) (_id == (SPM_LP_SMC_MAGIC | _type))
+
+enum mtk_suspend_mode {
+ MTK_MCDI_MODE = 1U,
+ MTK_IDLEDRAM_MODE = 2U,
+ MTK_IDLESYSPLL_MODE = 3U,
+ MTK_IDLEBUS26M_MODE = 4U,
+ MTK_SUSPEND_MODE = 5U,
+};
+#endif
+
+enum mt8169_idle_model {
+ IDLE_MODEL_START = 0U,
+ IDLE_MODEL_RESOURCE_HEAD = IDLE_MODEL_START,
+ IDLE_MODEL_BUS26M = IDLE_MODEL_RESOURCE_HEAD,
+ IDLE_MODEL_SYSPLL = 1U,
+ IDLE_MODEL_DRAM = 2U,
+ IDLE_MODEL_NUM = 3U,
+};
+
+#define footprint_addr(cpu) (mtk_suspend_footprint_addr + (cpu << 2))
+#define timestamp_addr(cpu, idx) (mtk_suspend_timestamp_addr + \
+ ((cpu * MTK_SUSPEND_TIMESTAMP_MAX + idx) << 3))
+
+#define MTK_SUSPEND_FOOTPRINT_ENTER_CPUIDLE (0U)
+#define MTK_SUSPEND_FOOTPRINT_BEFORE_ATF (1U)
+#define MTK_SUSPEND_FOOTPRINT_ENTER_ATF (2U)
+#define MTK_SUSPEND_FOOTPRINT_RESERVE_P1 (3U)
+#define MTK_SUSPEND_FOOTPRINT_RESERVE_P2 (4U)
+#define MTK_SUSPEND_FOOTPRINT_ENTER_SPM_SUSPEND (5U)
+#define MTK_SUSPEND_FOOTPRINT_LEAVE_SPM_SUSPEND (6U)
+#define MTK_SUSPEND_FOOTPRINT_BEFORE_WFI (7U)
+#define MTK_SUSPEND_FOOTPRINT_AFTER_WFI (8U)
+#define MTK_SUSPEND_FOOTPRINT_BEFORE_MMU (9U)
+#define MTK_SUSPEND_FOOTPRINT_AFTER_MMU (10U)
+#define MTK_SUSPEND_FOOTPRINT_ENTER_SPM_SUSPEND_FINISH (11U)
+#define MTK_SUSPEND_FOOTPRINT_LEAVE_SPM_SUSPEND_FINISH (12U)
+#define MTK_SUSPEND_FOOTPRINT_LEAVE_ATF (13U)
+#define MTK_SUSPEND_FOOTPRINT_AFTER_ATF (14U)
+#define MTK_SUSPEND_FOOTPRINT_LEAVE_CPUIDLE (15U)
+
+#define MTK_SUSPEND_TIMESTAMP_ENTER_CPUIDLE (0U)
+#define MTK_SUSPEND_TIMESTAMP_BEFORE_ATF (1U)
+#define MTK_SUSPEND_TIMESTAMP_ENTER_ATF (2U)
+#define MTK_SUSPEND_TIMESTAMP_BEFORE_L2_FLUSH (3U)
+#define MTK_SUSPEND_TIMESTAMP_AFTER_L2_FLUSH (4U)
+#define MTK_SUSPEND_TIMESTAMP_ENTER_SPM_SUSPEND (5U)
+#define MTK_SUSPEND_TIMESTAMP_LEAVE_SPM_SUSPEND (6U)
+#define MTK_SUSPEND_TIMESTAMP_GIC_P1 (7U)
+#define MTK_SUSPEND_TIMESTAMP_GIC_P2 (8U)
+#define MTK_SUSPEND_TIMESTAMP_BEFORE_WFI (9U)
+#define MTK_SUSPEND_TIMESTAMP_AFTER_WFI (10U)
+#define MTK_SUSPEND_TIMESTAMP_RESERVE_P1 (11U)
+#define MTK_SUSPEND_TIMESTAMP_RESERVE_P2 (12U)
+#define MTK_SUSPEND_TIMESTAMP_GIC_P3 (13U)
+#define MTK_SUSPEND_TIMESTAMP_GIC_P4 (14U)
+#define MTK_SUSPEND_TIMESTAMP_ENTER_SPM_SUSPEND_FINISH (15U)
+#define MTK_SUSPEND_TIMESTAMP_LEAVE_SPM_SUSPEND_FINISH (16U)
+#define MTK_SUSPEND_TIMESTAMP_LEAVE_ATF (17U)
+#define MTK_SUSPEND_TIMESTAMP_AFTER_ATF (18U)
+#define MTK_SUSPEND_TIMESTAMP_LEAVE_CPUIDLE (19U)
+#define MTK_SUSPEND_TIMESTAMP_MAX (20U)
+
+/*
+ * definition platform power state menas.
+ * PLAT_MT_SYSTEM_SUSPEND - system suspend pwr level
+ * PLAT_MT_CPU_SUSPEND_CLUSTER - cluster off pwr level
+ */
+#define PLAT_MT_SYSTEM_SUSPEND PLAT_MAX_OFF_STATE
+#define PLAT_MT_CPU_SUSPEND_CLUSTER PLAT_MAX_RET_STATE
+
+#define IS_PLAT_SYSTEM_SUSPEND(aff) (aff == PLAT_MT_SYSTEM_SUSPEND)
+#define IS_PLAT_SYSTEM_RETENTION(aff) (aff >= PLAT_MAX_RET_STATE)
+
+#define IS_PLAT_SUSPEND2IDLE_ID(stateid)\
+ (stateid == MT_PLAT_PWR_STATE_SUSPEND2IDLE)
+
+#define IS_PLAT_SUSPEND_ID(stateid) \
+ ((stateid == MT_PLAT_PWR_STATE_SUSPEND2IDLE) \
+ || (stateid == MT_PLAT_PWR_STATE_SYSTEM_SUSPEND))
+
+#endif /* PLAT_PM_H */
diff --git a/plat/mediatek/mt8186/include/plat_private.h b/plat/mediatek/mt8186/include/plat_private.h
new file mode 100644
index 0000000..7ef2b85
--- /dev/null
+++ b/plat/mediatek/mt8186/include/plat_private.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2021, 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);
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/mediatek/mt8186/include/plat_sip_calls.h b/plat/mediatek/mt8186/include/plat_sip_calls.h
new file mode 100644
index 0000000..f5c15e3
--- /dev/null
+++ b/plat/mediatek/mt8186/include/plat_sip_calls.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021-2022, MediaTek Inc. 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)
+
+#endif /* PLAT_SIP_CALLS_H */
diff --git a/plat/mediatek/mt8186/include/plat_uart.h b/plat/mediatek/mt8186/include/plat_uart.h
new file mode 100644
index 0000000..f0fb442
--- /dev/null
+++ b/plat/mediatek/mt8186/include/plat_uart.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLAT_UART_H__
+#define __PLAT_UART_H__
+
+/* UART error code */
+#define UART_DONE U(0)
+#define UART_PM_ERROR U(1)
+
+/* UART HW information */
+#ifndef HW_SUPPORT_UART_PORTS
+#define HW_SUPPORT_UART_PORTS (2U) /* the UART PORTs current HW have */
+#endif
+#define MTK_UART_SEND_SLEEP_REQ (1U) /* Request uart to sleep */
+#define MTK_UART_SLEEP_ACK_IDLE (1U) /* uart in idle state */
+#define MTK_UART_WAIT_ACK_TIMES (50U)
+
+#define UART_BASE0 (0x11002000)
+#define UART_BASE1 (0x11003000)
+
+#endif /* __PLAT_UART_H__ */
diff --git a/plat/mediatek/mt8186/include/platform_def.h b/plat/mediatek/mt8186/include/platform_def.h
new file mode 100644
index 0000000..850ce2f
--- /dev/null
+++ b/plat/mediatek/mt8186/include/platform_def.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#define PLAT_PRIMARY_CPU (0x0)
+
+#define MT_GIC_BASE (0x0C000000)
+#define MCUCFG_BASE (0x0C530000)
+#define IO_PHYS (0x10000000)
+
+/* Aggregate of all devices for MMU mapping */
+#define MTK_DEV_RNG0_BASE IO_PHYS
+#define MTK_DEV_RNG0_SIZE (0x10000000)
+#define MTK_DEV_RNG2_BASE MT_GIC_BASE
+#define MTK_DEV_RNG2_SIZE (0x600000)
+#define MTK_MCDI_SRAM_BASE (0x11B000)
+#define MTK_MCDI_SRAM_MAP_SIZE (0x1000)
+
+#define TOPCKGEN_BASE (IO_PHYS + 0x00000000)
+#define INFRACFG_AO_BASE (IO_PHYS + 0x00001000)
+#define SPM_BASE (IO_PHYS + 0x00006000)
+#define APMIXEDSYS (IO_PHYS + 0x0000C000)
+#define SSPM_MCDI_SHARE_SRAM (IO_PHYS + 0x00420000)
+#define SSPM_CFGREG_BASE (IO_PHYS + 0x00440000) /* SSPM view: 0x30040000 */
+#define SSPM_MBOX_BASE (IO_PHYS + 0x00480000)
+#define PERICFG_AO_BASE (IO_PHYS + 0x01003000)
+#define VPPSYS0_BASE (IO_PHYS + 0x04000000)
+#define VPPSYS1_BASE (IO_PHYS + 0x04f00000)
+#define VDOSYS0_BASE (IO_PHYS + 0x0C01A000)
+#define VDOSYS1_BASE (IO_PHYS + 0x0C100000)
+
+/*******************************************************************************
+ * GPIO related constants
+ ******************************************************************************/
+#define TOPCKGEN_BASE (IO_PHYS + 0x00000000)
+#define INFRACFG_AO_BASE (IO_PHYS + 0x00001000)
+#define GPIO_BASE (IO_PHYS + 0x00005000)
+#define SPM_BASE (IO_PHYS + 0x00006000)
+#define IOCFG_LT_BASE (IO_PHYS + 0x00002000)
+#define IOCFG_LM_BASE (IO_PHYS + 0x00002200)
+#define IOCFG_LB_BASE (IO_PHYS + 0x00002400)
+#define IOCFG_BL_BASE (IO_PHYS + 0x00002600)
+#define IOCFG_RB_BASE (IO_PHYS + 0x00002A00)
+#define IOCFG_RT_BASE (IO_PHYS + 0x00002C00)
+#define APMIXEDSYS (IO_PHYS + 0x0000C000)
+#define DVFSRC_BASE (IO_PHYS + 0x00012000)
+#define MMSYS_BASE (IO_PHYS + 0x04000000)
+#define MDPSYS_BASE (IO_PHYS + 0x0B000000)
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define UART0_BASE (IO_PHYS + 0x01002000)
+#define UART1_BASE (IO_PHYS + 0x01003000)
+
+#define UART_BAUDRATE (115200)
+
+/*******************************************************************************
+ * PWRAP related constants
+ ******************************************************************************/
+#define PMIC_WRAP_BASE (IO_PHYS + 0x0000D000)
+
+/*******************************************************************************
+ * EMI MPU related constants
+ ******************************************************************************/
+#define EMI_MPU_BASE (IO_PHYS + 0x0021B000)
+
+/*******************************************************************************
+ * MSDC related constants
+ ******************************************************************************/
+#define MSDC0_BASE (IO_PHYS + 0x01230000)
+
+/*******************************************************************************
+ * GIC-600 & interrupt handling related constants
+ ******************************************************************************/
+/* Base MTK_platform compatible GIC memory map */
+#define BASE_GICD_BASE MT_GIC_BASE
+#define MT_GIC_RDIST_BASE (MT_GIC_BASE + 0x40000)
+
+#define SYS_CIRQ_BASE (IO_PHYS + 0x204000)
+#define CIRQ_REG_NUM (11)
+#define CIRQ_IRQ_NUM (326)
+#define CIRQ_SPI_START (64)
+#define MD_WDT_IRQ_BIT_ID (107)
+/*******************************************************************************
+ * System counter frequency related constants
+ ******************************************************************************/
+#define SYS_COUNTER_FREQ_IN_TICKS (13000000)
+#define SYS_COUNTER_FREQ_IN_MHZ (13)
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH aarch64
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+#define PLATFORM_STACK_SIZE 0x800
+
+#define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n"
+
+#define PLAT_MAX_PWR_LVL U(3)
+#define PLAT_MAX_RET_STATE U(1)
+#define PLAT_MAX_OFF_STATE U(9)
+
+#define PLATFORM_SYSTEM_COUNT U(1)
+#define PLATFORM_MCUSYS_COUNT U(1)
+#define PLATFORM_CLUSTER_COUNT U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT U(8)
+#define PLATFORM_CLUSTER1_CORE_COUNT U(0)
+
+#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER U(8)
+
+#define SOC_CHIP_ID U(0x8186)
+
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+#define TZRAM_BASE (0x54600000)
+#define TZRAM_SIZE (0x00030000)
+
+/*******************************************************************************
+ * 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)
+
+/*******************************************************************************
+ * 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 BIT(CACHE_WRITEBACK_SHIFT)
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/mediatek/mt8186/include/sspm_reg.h b/plat/mediatek/mt8186/include/sspm_reg.h
new file mode 100644
index 0000000..40b71ac
--- /dev/null
+++ b/plat/mediatek/mt8186/include/sspm_reg.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __SSPM_REG_H__
+#define __SSPM_REG_H__
+
+#include "platform_def.h"
+
+#define SSPM_CFGREG_ADDR(ofs) (SSPM_CFGREG_BASE + (ofs))
+
+#define SSPM_HW_SEM SSPM_CFGREG_ADDR(0x0048)
+#define SSPM_ACAO_INT_SET SSPM_CFGREG_ADDR(0x00D8)
+#define SSPM_ACAO_INT_CLR SSPM_CFGREG_ADDR(0x00DC)
+
+#define STANDBYWFI_EN(n) (1 << (n + 8))
+#define GIC_IRQOUT_EN(n) (1 << (n + 0))
+
+#endif /* __SSPM_REG_H__ */
diff --git a/plat/mediatek/mt8186/plat_pm.c b/plat/mediatek/mt8186/plat_pm.c
new file mode 100644
index 0000000..e125c99
--- /dev/null
+++ b/plat/mediatek/mt8186/plat_pm.c
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/gpio.h>
+#include <lib/psci/psci.h>
+
+#include <mt_gic_v3.h>
+#include <mtspmc.h>
+#include <plat/common/platform.h>
+#include <plat_dfd.h>
+#include <plat_mtk_lpm.h>
+#include <plat_params.h>
+#include <plat_pm.h>
+#include <pmic.h>
+#include <rtc.h>
+
+/*
+ * Cluster state request:
+ * [0] : The CPU requires cluster power down
+ * [1] : The CPU requires cluster power on
+ */
+#define coordinate_cluster(onoff) write_clusterpwrdn_el1(onoff)
+#define coordinate_cluster_pwron() coordinate_cluster(1)
+#define coordinate_cluster_pwroff() coordinate_cluster(0)
+
+/* platform secure entry point */
+static uintptr_t secure_entrypoint;
+/* per-CPU power state */
+static unsigned int plat_power_state[PLATFORM_CORE_COUNT];
+
+/* platform CPU power domain - ops */
+static const struct mt_lpm_tz *plat_mt_pm;
+
+static inline int plat_mt_pm_invoke(int (*func)(unsigned int cpu,
+ const psci_power_state_t *state),
+ int cpu, const psci_power_state_t *state)
+{
+ int ret = -1;
+
+ if (func != NULL) {
+ ret = func(cpu, state);
+ }
+ return ret;
+}
+
+/*
+ * Common MTK_platform operations to power on/off a
+ * CPU in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
+ */
+static void plat_cpu_pwrdwn_common(unsigned int cpu,
+ const psci_power_state_t *state, unsigned int req_pstate)
+{
+ assert(cpu == plat_my_core_pos());
+ assert(plat_mt_pm != NULL);
+
+ (void)plat_mt_pm_invoke(plat_mt_pm->pwr_cpu_dwn, cpu, state);
+
+ if ((psci_get_pstate_pwrlvl(req_pstate) >= MTK_AFFLVL_CLUSTER) ||
+ (req_pstate == 0U)) { /* hotplug off */
+ coordinate_cluster_pwroff();
+ }
+
+ /* Prevent interrupts from spuriously waking up this CPU */
+ mt_gic_rdistif_save();
+ gicv3_cpuif_disable(cpu);
+ gicv3_rdistif_off(cpu);
+}
+
+static void plat_cpu_pwron_common(unsigned int cpu,
+ const psci_power_state_t *state, unsigned int req_pstate)
+{
+ assert(cpu == plat_my_core_pos());
+ assert(plat_mt_pm != NULL);
+
+ (void)plat_mt_pm_invoke(plat_mt_pm->pwr_cpu_on, cpu, state);
+
+ coordinate_cluster_pwron();
+
+ /*
+ * If mcusys does power down before then restore
+ * all CPUs' GIC Redistributors
+ */
+ if (IS_MCUSYS_OFF_STATE(state)) {
+ mt_gic_rdistif_restore_all();
+ } else {
+ gicv3_rdistif_on(cpu);
+ gicv3_cpuif_enable(cpu);
+ mt_gic_rdistif_init();
+ mt_gic_rdistif_restore();
+ }
+}
+
+/*
+ * Common MTK_platform operations to power on/off a
+ * cluster in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
+ */
+static void plat_cluster_pwrdwn_common(unsigned int cpu,
+ const psci_power_state_t *state, unsigned int req_pstate)
+{
+ assert(cpu == plat_my_core_pos());
+ assert(plat_mt_pm != NULL);
+
+ if (plat_mt_pm_invoke(plat_mt_pm->pwr_cluster_dwn, cpu, state) != 0) {
+ coordinate_cluster_pwron();
+
+ /*
+ * TODO:
+ * Return on fail and add a 'return' here before
+ * adding any code following the if-block.
+ */
+ }
+}
+
+static void plat_cluster_pwron_common(unsigned int cpu,
+ const psci_power_state_t *state, unsigned int req_pstate)
+{
+ assert(cpu == plat_my_core_pos());
+ assert(plat_mt_pm != NULL);
+
+ if (plat_mt_pm_invoke(plat_mt_pm->pwr_cluster_on, cpu, state) != 0) {
+ /*
+ * TODO:
+ * return on fail and add a 'return' here before
+ * adding any code following the if-block.
+ */
+ }
+}
+
+/*
+ * Common MTK_platform operations to power on/off a
+ * mcusys in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
+ */
+static void plat_mcusys_pwrdwn_common(unsigned int cpu,
+ const psci_power_state_t *state, unsigned int req_pstate)
+{
+ assert(cpu == plat_my_core_pos());
+ assert(plat_mt_pm != NULL);
+
+ if (plat_mt_pm_invoke(plat_mt_pm->pwr_mcusys_dwn, cpu, state) != 0) {
+ return; /* return on fail */
+ }
+
+ mt_gic_distif_save();
+ gic_sgi_save_all();
+}
+
+static void plat_mcusys_pwron_common(unsigned int cpu,
+ const psci_power_state_t *state, unsigned int req_pstate)
+{
+ assert(cpu == plat_my_core_pos());
+ assert(plat_mt_pm != NULL);
+
+ if (plat_mt_pm_invoke(plat_mt_pm->pwr_mcusys_on, cpu, state) != 0) {
+ /* return on fail */
+ return;
+ }
+
+ mt_gic_init();
+ mt_gic_distif_restore();
+ gic_sgi_restore_all();
+
+ dfd_resume();
+
+ (void)plat_mt_pm_invoke(plat_mt_pm->pwr_mcusys_on_finished, cpu, state);
+}
+
+/* plat_psci_ops implementation */
+static void plat_cpu_standby(plat_local_state_t cpu_state)
+{
+ uint64_t scr;
+
+ scr = read_scr_el3();
+ write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
+
+ isb();
+ dsb();
+ wfi();
+
+ write_scr_el3(scr);
+}
+
+static int plat_power_domain_on(u_register_t mpidr)
+{
+ unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+ unsigned int cluster = 0U;
+
+ if (cpu >= PLATFORM_CORE_COUNT) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ if (!spm_get_cluster_powerstate(cluster)) {
+ spm_poweron_cluster(cluster);
+ }
+
+ /* init CPU reset arch as AARCH64 */
+ mcucfg_init_archstate(cluster, cpu, true);
+ mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint);
+ spm_poweron_cpu(cluster, cpu);
+
+ return PSCI_E_SUCCESS;
+}
+
+static void plat_power_domain_on_finish(const psci_power_state_t *state)
+{
+ unsigned long mpidr = read_mpidr_el1();
+ unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+
+ assert(cpu < PLATFORM_CORE_COUNT);
+
+ /* Allow IRQs to wakeup this core in IDLE flow */
+ mcucfg_enable_gic_wakeup(0U, cpu);
+
+ if (IS_CLUSTER_OFF_STATE(state)) {
+ plat_cluster_pwron_common(cpu, state, 0U);
+ }
+
+ plat_cpu_pwron_common(cpu, state, 0U);
+}
+
+static void plat_power_domain_off(const psci_power_state_t *state)
+{
+ unsigned long mpidr = read_mpidr_el1();
+ unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+
+ assert(cpu < PLATFORM_CORE_COUNT);
+
+ plat_cpu_pwrdwn_common(cpu, state, 0U);
+ spm_poweroff_cpu(0U, cpu);
+
+ /* prevent unintended IRQs from waking up the hot-unplugged core */
+ mcucfg_disable_gic_wakeup(0U, cpu);
+
+ if (IS_CLUSTER_OFF_STATE(state)) {
+ plat_cluster_pwrdwn_common(cpu, state, 0U);
+ }
+}
+
+static void plat_power_domain_suspend(const psci_power_state_t *state)
+{
+ unsigned int cpu = plat_my_core_pos();
+
+ assert(cpu < PLATFORM_CORE_COUNT);
+ assert(plat_mt_pm != NULL);
+
+ (void)plat_mt_pm_invoke(plat_mt_pm->pwr_prompt, cpu, state);
+
+ /* Perform the common CPU specific operations */
+ plat_cpu_pwrdwn_common(cpu, state, plat_power_state[cpu]);
+
+ if (IS_CLUSTER_OFF_STATE(state)) {
+ /* Perform the common cluster specific operations */
+ plat_cluster_pwrdwn_common(cpu, state, plat_power_state[cpu]);
+ }
+
+ if (IS_MCUSYS_OFF_STATE(state)) {
+ /* Perform the common mcusys specific operations */
+ plat_mcusys_pwrdwn_common(cpu, state, plat_power_state[cpu]);
+ }
+}
+
+static void plat_power_domain_suspend_finish(const psci_power_state_t *state)
+{
+ unsigned int cpu = plat_my_core_pos();
+
+ assert(cpu < PLATFORM_CORE_COUNT);
+ assert(plat_mt_pm != NULL);
+
+ if (IS_MCUSYS_OFF_STATE(state)) {
+ /* Perform the common mcusys specific operations */
+ plat_mcusys_pwron_common(cpu, state, plat_power_state[cpu]);
+ }
+
+ if (IS_CLUSTER_OFF_STATE(state)) {
+ /* Perform the common cluster specific operations */
+ plat_cluster_pwron_common(cpu, state, plat_power_state[cpu]);
+ }
+
+ /* Perform the common CPU specific operations */
+ plat_cpu_pwron_common(cpu, state, plat_power_state[cpu]);
+
+ (void)plat_mt_pm_invoke(plat_mt_pm->pwr_reflect, cpu, state);
+}
+
+static int plat_validate_power_state(unsigned int power_state,
+ psci_power_state_t *req_state)
+{
+ unsigned int pstate = psci_get_pstate_type(power_state);
+ unsigned int aff_lvl = psci_get_pstate_pwrlvl(power_state);
+ unsigned int cpu = plat_my_core_pos();
+
+ if (aff_lvl > PLAT_MAX_PWR_LVL) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ if (pstate == PSTATE_TYPE_STANDBY) {
+ req_state->pwr_domain_state[0] = PLAT_MAX_RET_STATE;
+ } else {
+ unsigned int i;
+ unsigned int pstate_id = psci_get_pstate_id(power_state);
+ plat_local_state_t s = MTK_LOCAL_STATE_OFF;
+
+ /* Use pstate_id to be power domain state */
+ if (pstate_id > s) {
+ s = (plat_local_state_t)pstate_id;
+ }
+
+ for (i = 0U; i <= aff_lvl; i++) {
+ req_state->pwr_domain_state[i] = s;
+ }
+ }
+
+ plat_power_state[cpu] = power_state;
+ return PSCI_E_SUCCESS;
+}
+
+static void plat_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+ unsigned int lv;
+ unsigned int cpu = plat_my_core_pos();
+
+ for (lv = PSCI_CPU_PWR_LVL; lv <= PLAT_MAX_PWR_LVL; lv++) {
+ req_state->pwr_domain_state[lv] = PLAT_MAX_OFF_STATE;
+ }
+
+ plat_power_state[cpu] =
+ psci_make_powerstate(
+ MT_PLAT_PWR_STATE_SYSTEM_SUSPEND,
+ PSTATE_TYPE_POWERDOWN, PLAT_MAX_PWR_LVL);
+
+ flush_dcache_range((uintptr_t)
+ &plat_power_state[cpu],
+ sizeof(plat_power_state[cpu]));
+}
+
+/*******************************************************************************
+ * MTK handlers to shutdown/reboot the system
+ ******************************************************************************/
+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");
+
+ gpio_set_value(gpio_reset->index, gpio_reset->polarity);
+
+ wfi();
+ ERROR("MTK System Reset: operation not handled.\n");
+ panic();
+}
+
+static void __dead2 plat_mtk_system_off(void)
+{
+ INFO("MTK System Off\n");
+
+ rtc_power_off_sequence();
+ pmic_power_off();
+
+ wfi();
+ ERROR("MTK System Off: operation not handled.\n");
+ panic();
+}
+
+static const plat_psci_ops_t plat_psci_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,
+ .validate_power_state = plat_validate_power_state,
+ .get_sys_suspend_power_state = plat_get_sys_suspend_power_state,
+ .system_off = plat_mtk_system_off,
+ .system_reset = plat_mtk_system_reset,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const plat_psci_ops_t **psci_ops)
+{
+ *psci_ops = &plat_psci_ops;
+ secure_entrypoint = sec_entrypoint;
+
+ /*
+ * init the warm reset config for boot CPU
+ * reset arch as AARCH64
+ * reset addr as function bl31_warm_entrypoint()
+ */
+ mcucfg_init_archstate(0U, 0U, true);
+ mcucfg_set_bootaddr(0U, 0U, secure_entrypoint);
+
+ spmc_init();
+ plat_mt_pm = mt_plat_cpu_pm_init();
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8186/plat_sip_calls.c b/plat/mediatek/mt8186/plat_sip_calls.c
new file mode 100644
index 0000000..0e9c270
--- /dev/null
+++ b/plat/mediatek/mt8186/plat_sip_calls.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2021-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+#include <mt_msdc.h>
+#include <mt_spm_vcorefs.h>
+#include <mtk_sip_svc.h>
+#include <plat_dfd.h>
+#include "plat_sip_calls.h"
+
+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)
+{
+ uint64_t ret;
+
+ switch (smc_fid) {
+ case MTK_SIP_VCORE_CONTROL_AARCH32:
+ case MTK_SIP_VCORE_CONTROL_AARCH64:
+ ret = spm_vcorefs_args(x1, x2, x3, (uint64_t *)&x4);
+ SMC_RET2(handle, ret, x4);
+ break;
+ case MTK_SIP_KERNEL_DFD_AARCH32:
+ case MTK_SIP_KERNEL_DFD_AARCH64:
+ ret = dfd_smc_dispatcher(x1, x2, x3, x4);
+ SMC_RET1(handle, ret);
+ break;
+ case MTK_SIP_KERNEL_MSDC_AARCH32:
+ case MTK_SIP_KERNEL_MSDC_AARCH64:
+ ret = msdc_smc_dispatcher(x1, x2, x3, x4);
+ SMC_RET1(handle, ret);
+ break;
+ default:
+ ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+ break;
+ }
+
+ SMC_RET1(handle, SMC_UNK);
+}
diff --git a/plat/mediatek/mt8186/plat_topology.c b/plat/mediatek/mt8186/plat_topology.c
new file mode 100644
index 0000000..bc95c64
--- /dev/null
+++ b/plat/mediatek/mt8186/plat_topology.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/psci/psci.h>
+
+#include <plat_helpers.h>
+#include <platform_def.h>
+
+const unsigned char mtk_power_domain_tree_desc[] = {
+ /* Number of root nodes */
+ PLATFORM_SYSTEM_COUNT,
+ /* Number of children for the root node */
+ PLATFORM_MCUSYS_COUNT,
+ /* Number of children for the mcusys node */
+ PLATFORM_CLUSTER_COUNT,
+ /* Number of children for the first cluster node */
+ PLATFORM_CLUSTER0_CORE_COUNT,
+};
+
+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;
+
+ if ((read_mpidr() & MPIDR_MT_MASK) != 0) {
+ /* ARMv8.2 arch */
+ if ((mpidr & (MPIDR_AFFLVL_MASK << MPIDR_AFF0_SHIFT)) != 0) {
+ return -1;
+ }
+ return plat_mediatek_calc_core_pos(mpidr);
+ }
+
+ mpidr &= MPIDR_AFFINITY_MASK;
+
+ if ((mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) != 0) {
+ 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 * 8));
+}
diff --git a/plat/mediatek/mt8186/platform.mk b/plat/mediatek/mt8186/platform.mk
new file mode 100644
index 0000000..68f4a1f
--- /dev/null
+++ b/plat/mediatek/mt8186/platform.mk
@@ -0,0 +1,110 @@
+#
+# Copyright (c) 2021-2022, 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}/common/lpm \
+ -I${MTK_PLAT}/drivers/cirq/ \
+ -I${MTK_PLAT}/drivers/gic600/ \
+ -I${MTK_PLAT}/drivers/gpio/ \
+ -I${MTK_PLAT}/drivers/msdc/ \
+ -I${MTK_PLAT}/drivers/msdc/${PLAT} \
+ -I${MTK_PLAT}/drivers/pmic_wrap/ \
+ -I${MTK_PLAT}/drivers/timer/ \
+ -I${MTK_PLAT}/drivers/uart/ \
+ -I${MTK_PLAT}/include/ \
+ -I${MTK_PLAT_SOC}/drivers/spm/ \
+ -I${MTK_PLAT_SOC}/drivers/dcm/ \
+ -I${MTK_PLAT_SOC}/drivers/dfd/ \
+ -I${MTK_PLAT_SOC}/drivers/emi_mpu/ \
+ -I${MTK_PLAT_SOC}/drivers/gpio/ \
+ -I${MTK_PLAT_SOC}/drivers/mcdi/ \
+ -I${MTK_PLAT_SOC}/drivers/pmic/ \
+ -I${MTK_PLAT_SOC}/drivers/rtc/ \
+ -I${MTK_PLAT_SOC}/drivers/spmc/ \
+ -I${MTK_PLAT_SOC}/include/
+
+GICV3_SUPPORT_GIC600 := 1
+include drivers/arm/gic/v3/gicv3.mk
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_BL_COMMON_SOURCES := ${GICV3_SOURCES} \
+ ${XLAT_TABLES_LIB_SRCS} \
+ plat/common/aarch64/crash_console_helpers.S \
+ plat/common/plat_psci_common.c
+
+
+BL31_SOURCES += common/desc_image_load.c \
+ drivers/delay_timer/delay_timer.c \
+ drivers/gpio/gpio.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ drivers/ti/uart/aarch64/16550_console.S \
+ lib/bl_aux_params/bl_aux_params.c \
+ lib/cpus/aarch64/cortex_a55.S \
+ lib/cpus/aarch64/cortex_a76.S \
+ plat/common/plat_gicv3.c \
+ ${MTK_PLAT}/common/mtk_plat_common.c \
+ ${MTK_PLAT}/common/mtk_sip_svc.c \
+ ${MTK_PLAT}/common/params_setup.c \
+ ${MTK_PLAT}/common/lpm/mt_lp_rm.c \
+ ${MTK_PLAT}/drivers/cirq/mt_cirq.c \
+ ${MTK_PLAT}/drivers/gic600/mt_gic_v3.c \
+ ${MTK_PLAT}/drivers/gpio/mtgpio_common.c \
+ ${MTK_PLAT}/drivers/msdc/mt_msdc.c \
+ ${MTK_PLAT}/drivers/pmic_wrap/pmic_wrap_init.c \
+ ${MTK_PLAT}/drivers/rtc/rtc_common.c \
+ ${MTK_PLAT}/drivers/timer/mt_timer.c \
+ ${MTK_PLAT}/drivers/uart/uart.c \
+ ${MTK_PLAT_SOC}/aarch64/platform_common.c \
+ ${MTK_PLAT_SOC}/aarch64/plat_helpers.S \
+ ${MTK_PLAT_SOC}/bl31_plat_setup.c \
+ ${MTK_PLAT_SOC}/drivers/dcm/mtk_dcm.c \
+ ${MTK_PLAT_SOC}/drivers/dcm/mtk_dcm_utils.c \
+ ${MTK_PLAT_SOC}/drivers/dfd/plat_dfd.c \
+ ${MTK_PLAT_SOC}/drivers/emi_mpu/emi_mpu.c \
+ ${MTK_PLAT_SOC}/drivers/gpio/mtgpio.c \
+ ${MTK_PLAT_SOC}/drivers/mcdi/mt_cpu_pm.c \
+ ${MTK_PLAT_SOC}/drivers/mcdi/mt_cpu_pm_cpc.c \
+ ${MTK_PLAT_SOC}/drivers/mcdi/mt_mcdi.c \
+ ${MTK_PLAT_SOC}/drivers/mcdi/mt_lp_irqremain.c \
+ ${MTK_PLAT_SOC}/drivers/pmic/pmic.c \
+ ${MTK_PLAT_SOC}/drivers/rtc/rtc.c \
+ ${MTK_PLAT_SOC}/drivers/spmc/mtspmc.c \
+ ${MTK_PLAT_SOC}/plat_pm.c \
+ ${MTK_PLAT_SOC}/plat_sip_calls.c \
+ ${MTK_PLAT_SOC}/plat_topology.c
+
+# Build SPM drivers
+include ${MTK_PLAT_SOC}/drivers/spm/build.mk
+
+# Configs for A76 and A55
+HW_ASSISTED_COHERENCY := 1
+USE_COHERENT_MEM := 0
+CTX_INCLUDE_AARCH32_REGS := 0
+ERRATA_A55_1530923 := 1
+ERRATA_A55_1221012 := 1
+
+ERRATA_A76_1257314 := 1
+ERRATA_A76_1262606 := 1
+ERRATA_A76_1262888 := 1
+ERRATA_A76_1275112 := 1
+ERRATA_A76_1286807 := 1
+ERRATA_A76_1791580 := 1
+ERRATA_A76_1165522 := 1
+ERRATA_A76_1868343 := 1
+ERRATA_A76_1946160 := 1
+
+# indicate the reset vector address can be programmed
+PROGRAMMABLE_RESET_ADDRESS := 1
+
+COLD_BOOT_SINGLE_CPU := 1
+
+MACH_MT8186 := 1
+$(eval $(call add_define,MACH_MT8186))
+
+include lib/coreboot/coreboot.mk
diff --git a/plat/mediatek/mt8188/include/plat_helpers.h b/plat/mediatek/mt8188/include/plat_helpers.h
new file mode 100644
index 0000000..eb78623
--- /dev/null
+++ b/plat/mediatek/mt8188/include/plat_helpers.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_HELPERS_H
+#define PLAT_HELPERS_H
+
+unsigned int plat_mediatek_calc_core_pos(u_register_t mpidr);
+
+#endif /* PLAT_HELPERS_H */
diff --git a/plat/mediatek/mt8188/include/plat_macros.S b/plat/mediatek/mt8188/include/plat_macros.S
new file mode 100644
index 0000000..a6e05a9
--- /dev/null
+++ b/plat/mediatek/mt8188/include/plat_macros.S
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <platform_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"
+
+.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.
+ * Clobbers: x0 - x10, x26, x27, sp
+ * ---------------------------------------------
+ */
+ .macro plat_crash_print_regs
+ /* TODO: leave implementation to GIC owner */
+ .endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/mediatek/mt8188/include/plat_private.h b/plat/mediatek/mt8188/include/plat_private.h
new file mode 100644
index 0000000..4d4ac85
--- /dev/null
+++ b/plat/mediatek/mt8188/include/plat_private.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2022, 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);
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/mediatek/mt8188/include/platform_def.h b/plat/mediatek/mt8188/include/platform_def.h
new file mode 100644
index 0000000..156a7e2
--- /dev/null
+++ b/plat/mediatek/mt8188/include/platform_def.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch_def.h>
+
+#define PLAT_PRIMARY_CPU (0x0)
+
+#define MT_GIC_BASE (0x0C000000)
+#define MCUCFG_BASE (0x0C530000)
+#define MCUCFG_REG_SIZE (0x10000)
+#define IO_PHYS (0x10000000)
+
+/* Aggregate of all devices for MMU mapping */
+#define MTK_DEV_RNG0_BASE (MT_GIC_BASE)
+#define MTK_DEV_RNG0_SIZE (0x600000)
+#define MTK_DEV_RNG1_BASE (IO_PHYS)
+#define MTK_DEV_RNG1_SIZE (0x10000000)
+
+/*******************************************************************************
+ * AUDIO related constants
+ ******************************************************************************/
+#define AUDIO_BASE (IO_PHYS + 0x00b10000)
+
+/*******************************************************************************
+ * SPM related constants
+ ******************************************************************************/
+#define SPM_BASE (IO_PHYS + 0x00006000)
+
+/*******************************************************************************
+ * GPIO related constants
+ ******************************************************************************/
+#define GPIO_BASE (IO_PHYS + 0x00005000)
+#define RGU_BASE (IO_PHYS + 0x00007000)
+#define DRM_BASE (IO_PHYS + 0x0000D000)
+#define IOCFG_RM_BASE (IO_PHYS + 0x01C00000)
+#define IOCFG_LT_BASE (IO_PHYS + 0x01E10000)
+#define IOCFG_LM_BASE (IO_PHYS + 0x01E20000)
+#define IOCFG_RT_BASE (IO_PHYS + 0x01EA0000)
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define UART0_BASE (IO_PHYS + 0x01002000)
+#define UART_BAUDRATE (115200)
+
+/*******************************************************************************
+ * PMIC related constants
+ ******************************************************************************/
+#define PMIC_WRAP_BASE (IO_PHYS + 0x00024000)
+
+/*******************************************************************************
+ * Infra IOMMU related constants
+ ******************************************************************************/
+#define PERICFG_AO_BASE (IO_PHYS + 0x01003000)
+#define PERICFG_AO_REG_SIZE (0x1000)
+
+/*******************************************************************************
+ * GIC-600 & interrupt handling related constants
+ ******************************************************************************/
+/* Base MTK_platform compatible GIC memory map */
+#define BASE_GICD_BASE (MT_GIC_BASE)
+#define MT_GIC_RDIST_BASE (MT_GIC_BASE + 0x40000)
+
+/*******************************************************************************
+ * CIRQ related constants
+ ******************************************************************************/
+#define SYS_CIRQ_BASE (IO_PHYS + 0x204000)
+#define MD_WDT_IRQ_BIT_ID (141)
+#define CIRQ_IRQ_NUM (730)
+#define CIRQ_REG_NUM (23)
+#define CIRQ_SPI_START (96)
+
+/*******************************************************************************
+ * MM IOMMU & SMI related constants
+ ******************************************************************************/
+#define SMI_LARB_0_BASE (IO_PHYS + 0x0c022000)
+#define SMI_LARB_1_BASE (IO_PHYS + 0x0c023000)
+#define SMI_LARB_2_BASE (IO_PHYS + 0x0c102000)
+#define SMI_LARB_3_BASE (IO_PHYS + 0x0c103000)
+#define SMI_LARB_4_BASE (IO_PHYS + 0x04013000)
+#define SMI_LARB_5_BASE (IO_PHYS + 0x04f02000)
+#define SMI_LARB_6_BASE (IO_PHYS + 0x04f03000)
+#define SMI_LARB_7_BASE (IO_PHYS + 0x04e04000)
+#define SMI_LARB_9_BASE (IO_PHYS + 0x05001000)
+#define SMI_LARB_10_BASE (IO_PHYS + 0x05120000)
+#define SMI_LARB_11A_BASE (IO_PHYS + 0x05230000)
+#define SMI_LARB_11B_BASE (IO_PHYS + 0x05530000)
+#define SMI_LARB_11C_BASE (IO_PHYS + 0x05630000)
+#define SMI_LARB_12_BASE (IO_PHYS + 0x05340000)
+#define SMI_LARB_13_BASE (IO_PHYS + 0x06001000)
+#define SMI_LARB_14_BASE (IO_PHYS + 0x06002000)
+#define SMI_LARB_15_BASE (IO_PHYS + 0x05140000)
+#define SMI_LARB_16A_BASE (IO_PHYS + 0x06008000)
+#define SMI_LARB_16B_BASE (IO_PHYS + 0x0600a000)
+#define SMI_LARB_17A_BASE (IO_PHYS + 0x06009000)
+#define SMI_LARB_17B_BASE (IO_PHYS + 0x0600b000)
+#define SMI_LARB_19_BASE (IO_PHYS + 0x0a010000)
+#define SMI_LARB_21_BASE (IO_PHYS + 0x0802e000)
+#define SMI_LARB_23_BASE (IO_PHYS + 0x0800d000)
+#define SMI_LARB_27_BASE (IO_PHYS + 0x07201000)
+#define SMI_LARB_28_BASE (IO_PHYS + 0x00000000)
+#define SMI_LARB_REG_RNG_SIZE (0x1000)
+
+/*******************************************************************************
+ * DP related constants
+ ******************************************************************************/
+#define EDP_SEC_BASE (IO_PHYS + 0x0C504000)
+#define DP_SEC_BASE (IO_PHYS + 0x0C604000)
+#define EDP_SEC_SIZE (0x1000)
+#define DP_SEC_SIZE (0x1000)
+
+/*******************************************************************************
+ * EMI MPU related constants
+ *******************************************************************************/
+#define EMI_MPU_BASE (IO_PHYS + 0x00226000)
+#define SUB_EMI_MPU_BASE (IO_PHYS + 0x00225000)
+
+/*******************************************************************************
+ * System counter frequency related constants
+ ******************************************************************************/
+#define SYS_COUNTER_FREQ_IN_HZ (13000000)
+#define SYS_COUNTER_FREQ_IN_MHZ (13)
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH aarch64
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+#define PLATFORM_STACK_SIZE (0x800)
+#define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n"
+#define SOC_CHIP_ID U(0x8188)
+
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+#define TZRAM_BASE (0x54600000)
+#define TZRAM_SIZE (0x00030000)
+
+/*******************************************************************************
+ * 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)
+
+/*******************************************************************************
+ * 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)
+
+/*******************************************************************************
+ * CPU_EB TCM handling related constants
+ ******************************************************************************/
+#define CPU_EB_TCM_BASE (0x0C550000)
+#define CPU_EB_TCM_SIZE (0x10000)
+#define CPU_EB_MBOX3_OFFSET (0xFCE0)
+
+/*******************************************************************************
+ * CPU PM definitions
+ *******************************************************************************/
+#define PLAT_CPU_PM_B_BUCK_ISO_ID (6)
+#define PLAT_CPU_PM_ILDO_ID (6)
+#define CPU_IDLE_SRAM_BASE (0x11B000)
+#define CPU_IDLE_SRAM_SIZE (0x1000)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/mediatek/mt8188/include/spm_reg.h b/plat/mediatek/mt8188/include/spm_reg.h
new file mode 100644
index 0000000..e20f1aa
--- /dev/null
+++ b/plat/mediatek/mt8188/include/spm_reg.h
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2022, Mediatek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPM_REG_H
+#define SPM_REG_H
+
+#include <platform_def.h>
+
+/* Register_SPM_CFG */
+#define MD32PCM_CFG_BASE (SPM_BASE + 0xA00)
+#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 SPM_POWER_ON_VAL2 (SPM_BASE + 0x020)
+#define SPM_POWER_ON_VAL3 (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 SPM_SW_RST_CON (SPM_BASE + 0x040)
+#define SPM_SW_RST_CON_SET (SPM_BASE + 0x044)
+#define SPM_SW_RST_CON_CLR (SPM_BASE + 0x048)
+#define SPM_ARBITER_EN (SPM_BASE + 0x050)
+#define SCPSYS_CLK_CON (SPM_BASE + 0x054)
+#define SPM_SRAM_RSV_CON (SPM_BASE + 0x058)
+#define SPM_SWINT (SPM_BASE + 0x05C)
+#define SPM_SWINT_SET (SPM_BASE + 0x060)
+#define SPM_SWINT_CLR (SPM_BASE + 0x064)
+#define SPM_SCP_MAILBOX (SPM_BASE + 0x068)
+#define SCP_SPM_MAILBOX (SPM_BASE + 0x06C)
+#define SPM_SCP_IRQ (SPM_BASE + 0x070)
+#define SPM_CPU_WAKEUP_EVENT (SPM_BASE + 0x074)
+#define SPM_IRQ_MASK (SPM_BASE + 0x078)
+#define SPM_SRC_REQ (SPM_BASE + 0x080)
+#define SPM_SRC_MASK (SPM_BASE + 0x084)
+#define SPM_SRC2_MASK (SPM_BASE + 0x088)
+#define SPM_SRC3_MASK (SPM_BASE + 0x090)
+#define SPM_SRC4_MASK (SPM_BASE + 0x094)
+#define SPM_WAKEUP_EVENT_MASK2 (SPM_BASE + 0x098)
+#define SPM_WAKEUP_EVENT_MASK (SPM_BASE + 0x09C)
+#define SPM_WAKEUP_EVENT_SENS (SPM_BASE + 0x0A0)
+#define SPM_WAKEUP_EVENT_CLEAR (SPM_BASE + 0x0A4)
+#define SPM_WAKEUP_EVENT_EXT_MASK (SPM_BASE + 0x0A8)
+#define SCP_CLK_CON (SPM_BASE + 0x0AC)
+#define PCM_DEBUG_CON (SPM_BASE + 0x0B0)
+#define DDREN_DBC_CON (SPM_BASE + 0x0B4)
+#define SPM_RESOURCE_ACK_CON0 (SPM_BASE + 0x0B8)
+#define SPM_RESOURCE_ACK_CON1 (SPM_BASE + 0x0BC)
+#define SPM_RESOURCE_ACK_CON2 (SPM_BASE + 0x0C0)
+#define SPM_RESOURCE_ACK_CON3 (SPM_BASE + 0x0C4)
+#define SPM_RESOURCE_ACK_CON4 (SPM_BASE + 0x0C8)
+#define SPM_SRAM_CON (SPM_BASE + 0x0CC)
+#define PCM_REG0_DATA (SPM_BASE + 0x100)
+#define PCM_REG2_DATA (SPM_BASE + 0x104)
+#define PCM_REG6_DATA (SPM_BASE + 0x108)
+#define PCM_REG7_DATA (SPM_BASE + 0x10C)
+#define PCM_REG13_DATA (SPM_BASE + 0x110)
+#define SRC_REQ_STA_0 (SPM_BASE + 0x114)
+#define SRC_REQ_STA_1 (SPM_BASE + 0x118)
+#define SRC_REQ_STA_2 (SPM_BASE + 0x120)
+#define SRC_REQ_STA_3 (SPM_BASE + 0x124)
+#define SRC_REQ_STA_4 (SPM_BASE + 0x128)
+#define PCM_TIMER_OUT (SPM_BASE + 0x130)
+#define PCM_WDT_OUT (SPM_BASE + 0x134)
+#define SPM_IRQ_STA (SPM_BASE + 0x138)
+#define MD32PCM_WAKEUP_STA (SPM_BASE + 0x13C)
+#define MD32PCM_EVENT_STA (SPM_BASE + 0x140)
+#define SPM_WAKEUP_STA (SPM_BASE + 0x144)
+#define SPM_WAKEUP_EXT_STA (SPM_BASE + 0x148)
+#define SPM_WAKEUP_MISC (SPM_BASE + 0x14C)
+#define MM_DVFS_HALT (SPM_BASE + 0x150)
+#define SUBSYS_IDLE_STA (SPM_BASE + 0x164)
+#define PCM_STA (SPM_BASE + 0x168)
+#define PWR_STATUS (SPM_BASE + 0x16C)
+#define PWR_STATUS_2ND (SPM_BASE + 0x170)
+#define CPU_PWR_STATUS (SPM_BASE + 0x174)
+#define CPU_PWR_STATUS_2ND (SPM_BASE + 0x178)
+#define SPM_VTCXO_EVENT_COUNT_STA (SPM_BASE + 0x17C)
+#define SPM_INFRA_EVENT_COUNT_STA (SPM_BASE + 0x180)
+#define SPM_VRF18_EVENT_COUNT_STA (SPM_BASE + 0x184)
+#define SPM_APSRC_EVENT_COUNT_STA (SPM_BASE + 0x188)
+#define SPM_DDREN_EVENT_COUNT_STA (SPM_BASE + 0x18C)
+#define MD32PCM_STA (SPM_BASE + 0x190)
+#define MD32PCM_PC (SPM_BASE + 0x194)
+#define OTHER_PWR_STATUS (SPM_BASE + 0x198)
+#define DVFSRC_EVENT_STA (SPM_BASE + 0x19C)
+#define BUS_PROTECT_RDY (SPM_BASE + 0x1A0)
+#define BUS_PROTECT1_RDY (SPM_BASE + 0x1A4)
+#define BUS_PROTECT2_RDY (SPM_BASE + 0x1A8)
+#define BUS_PROTECT3_RDY (SPM_BASE + 0x1AC)
+#define BUS_PROTECT4_RDY (SPM_BASE + 0x1B0)
+#define BUS_PROTECT5_RDY (SPM_BASE + 0x1B4)
+#define BUS_PROTECT6_RDY (SPM_BASE + 0x1B8)
+#define BUS_PROTECT7_RDY (SPM_BASE + 0x1BC)
+#define BUS_PROTECT8_RDY (SPM_BASE + 0x1C0)
+#define BUS_PROTECT9_RDY (SPM_BASE + 0x1C4)
+#define SPM_TWAM_LAST_STA0 (SPM_BASE + 0x1D0)
+#define SPM_TWAM_LAST_STA1 (SPM_BASE + 0x1D4)
+#define SPM_TWAM_LAST_STA2 (SPM_BASE + 0x1D8)
+#define SPM_TWAM_LAST_STA3 (SPM_BASE + 0x1DC)
+#define SPM_TWAM_CURR_STA0 (SPM_BASE + 0x1E0)
+#define SPM_TWAM_CURR_STA1 (SPM_BASE + 0x1E4)
+#define SPM_TWAM_CURR_STA2 (SPM_BASE + 0x1E8)
+#define SPM_TWAM_CURR_STA3 (SPM_BASE + 0x1EC)
+#define SPM_TWAM_TIMER_OUT (SPM_BASE + 0x1F0)
+#define SPM_CG_CHECK_STA (SPM_BASE + 0x1F4)
+#define SPM_DVFS_STA (SPM_BASE + 0x1F8)
+#define SPM_DVFS_OPP_STA (SPM_BASE + 0x1FC)
+#define CPUEB_PWR_CON (SPM_BASE + 0x200)
+#define SPM_MCUSYS_PWR_CON (SPM_BASE + 0x204)
+#define SPM_CPUTOP_PWR_CON (SPM_BASE + 0x208)
+#define SPM_CPU0_PWR_CON (SPM_BASE + 0x20C)
+#define SPM_CPU1_PWR_CON (SPM_BASE + 0x210)
+#define SPM_CPU2_PWR_CON (SPM_BASE + 0x214)
+#define SPM_CPU3_PWR_CON (SPM_BASE + 0x218)
+#define SPM_CPU4_PWR_CON (SPM_BASE + 0x21C)
+#define SPM_CPU5_PWR_CON (SPM_BASE + 0x220)
+#define SPM_CPU6_PWR_CON (SPM_BASE + 0x224)
+#define SPM_CPU7_PWR_CON (SPM_BASE + 0x228)
+#define ARMPLL_CLK_CON (SPM_BASE + 0x22C)
+#define MCUSYS_IDLE_STA (SPM_BASE + 0x230)
+#define GIC_WAKEUP_STA (SPM_BASE + 0x234)
+#define CPU_SPARE_CON (SPM_BASE + 0x238)
+#define CPU_SPARE_CON_SET (SPM_BASE + 0x23C)
+#define CPU_SPARE_CON_CLR (SPM_BASE + 0x240)
+#define ARMPLL_CLK_SEL (SPM_BASE + 0x244)
+#define EXT_INT_WAKEUP_REQ (SPM_BASE + 0x248)
+#define EXT_INT_WAKEUP_REQ_SET (SPM_BASE + 0x24C)
+#define EXT_INT_WAKEUP_REQ_CLR (SPM_BASE + 0x250)
+#define CPU_IRQ_MASK (SPM_BASE + 0x260)
+#define CPU_IRQ_MASK_SET (SPM_BASE + 0x264)
+#define CPU_IRQ_MASK_CLR (SPM_BASE + 0x268)
+#define CPU_WFI_EN (SPM_BASE + 0x280)
+#define CPU_WFI_EN_SET (SPM_BASE + 0x284)
+#define CPU_WFI_EN_CLR (SPM_BASE + 0x288)
+#define SYSRAM_CON (SPM_BASE + 0x290)
+#define SYSROM_CON (SPM_BASE + 0x294)
+#define ROOT_CPUTOP_ADDR (SPM_BASE + 0x2A0)
+#define ROOT_CORE_ADDR (SPM_BASE + 0x2A4)
+#define SPM2SW_MAILBOX_0 (SPM_BASE + 0x2D0)
+#define SPM2SW_MAILBOX_1 (SPM_BASE + 0x2D4)
+#define SPM2SW_MAILBOX_2 (SPM_BASE + 0x2D8)
+#define SPM2SW_MAILBOX_3 (SPM_BASE + 0x2DC)
+#define SW2SPM_INT (SPM_BASE + 0x2E0)
+#define SW2SPM_INT_SET (SPM_BASE + 0x2E4)
+#define SW2SPM_INT_CLR (SPM_BASE + 0x2E8)
+#define SW2SPM_MAILBOX_0 (SPM_BASE + 0x2EC)
+#define SW2SPM_MAILBOX_1 (SPM_BASE + 0x2F0)
+#define SW2SPM_MAILBOX_2 (SPM_BASE + 0x2F4)
+#define SW2SPM_MAILBOX_3 (SPM_BASE + 0x2F8)
+#define SW2SPM_CFG (SPM_BASE + 0x2FC)
+#define MFG0_PWR_CON (SPM_BASE + 0x300)
+#define MFG1_PWR_CON (SPM_BASE + 0x304)
+#define MFG2_PWR_CON (SPM_BASE + 0x308)
+#define MFG3_PWR_CON (SPM_BASE + 0x30C)
+#define MFG4_PWR_CON (SPM_BASE + 0x310)
+#define MFG5_PWR_CON (SPM_BASE + 0x314)
+#define IFR_PWR_CON (SPM_BASE + 0x318)
+#define IFR_SUB_PWR_CON (SPM_BASE + 0x31C)
+#define PERI_PWR_CON (SPM_BASE + 0x320)
+#define PEXTP_MAC_TOP_P0_PWR_CON (SPM_BASE + 0x324)
+#define PEXTP_PHY_TOP_PWR_CON (SPM_BASE + 0x328)
+#define APHY_N_PWR_CON (SPM_BASE + 0x32C)
+#define APHY_S_PWR_CON (SPM_BASE + 0x330)
+#define ETHER_PWR_CON (SPM_BASE + 0x338)
+#define DPY0_PWR_CON (SPM_BASE + 0x33C)
+#define DPY1_PWR_CON (SPM_BASE + 0x340)
+#define DPM0_PWR_CON (SPM_BASE + 0x344)
+#define DPM1_PWR_CON (SPM_BASE + 0x348)
+#define AUDIO_PWR_CON (SPM_BASE + 0x34C)
+#define AUDIO_ASRC_PWR_CON (SPM_BASE + 0x350)
+#define ADSP_PWR_CON (SPM_BASE + 0x354)
+#define ADSP_INFRA_PWR_CON (SPM_BASE + 0x358)
+#define ADSP_AO_PWR_CON (SPM_BASE + 0x35C)
+#define VPPSYS0_PWR_CON (SPM_BASE + 0x360)
+#define VPPSYS1_PWR_CON (SPM_BASE + 0x364)
+#define VDOSYS0_PWR_CON (SPM_BASE + 0x368)
+#define VDOSYS1_PWR_CON (SPM_BASE + 0x36C)
+#define WPESYS_PWR_CON (SPM_BASE + 0x370)
+#define DP_TX_PWR_CON (SPM_BASE + 0x374)
+#define EDP_TX_PWR_CON (SPM_BASE + 0x378)
+#define HDMI_TX_PWR_CON (SPM_BASE + 0x37C)
+#define VDE0_PWR_CON (SPM_BASE + 0x380)
+#define VDE1_PWR_CON (SPM_BASE + 0x384)
+#define VDE2_PWR_CON (SPM_BASE + 0x388)
+#define VEN_PWR_CON (SPM_BASE + 0x38C)
+#define VEN_CORE1_PWR_CON (SPM_BASE + 0x390)
+#define CAM_MAIN_PWR_CON (SPM_BASE + 0x394)
+#define CAM_SUBA_PWR_CON (SPM_BASE + 0x398)
+#define CAM_SUBB_PWR_CON (SPM_BASE + 0x39C)
+#define CAM_VCORE_PWR_CON (SPM_BASE + 0x3A0)
+#define IMG_VCORE_PWR_CON (SPM_BASE + 0x3A4)
+#define IMG_MAIN_PWR_CON (SPM_BASE + 0x3A8)
+#define IMG_DIP_PWR_CON (SPM_BASE + 0x3AC)
+#define IMG_IPE_PWR_CON (SPM_BASE + 0x3B0)
+#define NNA0_PWR_CON (SPM_BASE + 0x3B4)
+#define NNA1_PWR_CON (SPM_BASE + 0x3B8)
+#define IPNNA_PWR_CON (SPM_BASE + 0x3C0)
+#define CSI_RX_TOP_PWR_CON (SPM_BASE + 0x3C4)
+#define SSPM_SRAM_CON (SPM_BASE + 0x3CC)
+#define SCP_SRAM_CON (SPM_BASE + 0x3D0)
+#define DEVAPC_IFR_SRAM_CON (SPM_BASE + 0x3D8)
+#define DEVAPC_SUBIFR_SRAM_CON (SPM_BASE + 0x3DC)
+#define DEVAPC_ACP_SRAM_CON (SPM_BASE + 0x3E0)
+#define USB_SRAM_CON (SPM_BASE + 0x3E4)
+#define DUMMY_SRAM_CON (SPM_BASE + 0x3E8)
+#define EXT_BUCK_ISO (SPM_BASE + 0x3EC)
+#define MSDC_SRAM_CON (SPM_BASE + 0x3F0)
+#define DEBUGTOP_SRAM_CON (SPM_BASE + 0x3F4)
+#define DPMAIF_SRAM_CON (SPM_BASE + 0x3F8)
+#define GCPU_SRAM_CON (SPM_BASE + 0x3FC)
+#define SPM_MEM_CK_SEL (SPM_BASE + 0x400)
+#define SPM_BUS_PROTECT_MASK_B (SPM_BASE + 0x404)
+#define SPM_BUS_PROTECT1_MASK_B (SPM_BASE + 0x408)
+#define SPM_BUS_PROTECT2_MASK_B (SPM_BASE + 0x40C)
+#define SPM_BUS_PROTECT3_MASK_B (SPM_BASE + 0x410)
+#define SPM_BUS_PROTECT4_MASK_B (SPM_BASE + 0x414)
+#define SPM_BUS_PROTECT5_MASK_B (SPM_BASE + 0x418)
+#define SPM_BUS_PROTECT6_MASK_B (SPM_BASE + 0x41C)
+#define SPM_BUS_PROTECT7_MASK_B (SPM_BASE + 0x420)
+#define SPM_BUS_PROTECT8_MASK_B (SPM_BASE + 0x424)
+#define SPM_BUS_PROTECT9_MASK_B (SPM_BASE + 0x428)
+#define SPM_EMI_BW_MODE (SPM_BASE + 0x42C)
+#define SPM2MM_CON (SPM_BASE + 0x434)
+#define SPM2CPUEB_CON (SPM_BASE + 0x438)
+#define AP_MDSRC_REQ (SPM_BASE + 0x43C)
+#define SPM2EMI_ENTER_ULPM (SPM_BASE + 0x440)
+#define SPM_PLL_CON (SPM_BASE + 0x444)
+#define RC_SPM_CTRL (SPM_BASE + 0x448)
+#define SPM_DRAM_MCU_SW_CON_0 (SPM_BASE + 0x44C)
+#define SPM_DRAM_MCU_SW_CON_1 (SPM_BASE + 0x450)
+#define SPM_DRAM_MCU_SW_CON_2 (SPM_BASE + 0x454)
+#define SPM_DRAM_MCU_SW_CON_3 (SPM_BASE + 0x458)
+#define SPM_DRAM_MCU_SW_CON_4 (SPM_BASE + 0x45C)
+#define SPM_DRAM_MCU_STA_0 (SPM_BASE + 0x460)
+#define SPM_DRAM_MCU_STA_1 (SPM_BASE + 0x464)
+#define SPM_DRAM_MCU_STA_2 (SPM_BASE + 0x468)
+#define SPM_DRAM_MCU_SW_SEL_0 (SPM_BASE + 0x46C)
+#define RELAY_DVFS_LEVEL (SPM_BASE + 0x470)
+#define DRAMC_DPY_CLK_SW_CON_0 (SPM_BASE + 0x474)
+#define DRAMC_DPY_CLK_SW_CON_1 (SPM_BASE + 0x478)
+#define DRAMC_DPY_CLK_SW_CON_2 (SPM_BASE + 0x47C)
+#define DRAMC_DPY_CLK_SW_CON_3 (SPM_BASE + 0x480)
+#define DRAMC_DPY_CLK_SW_SEL_0 (SPM_BASE + 0x484)
+#define DRAMC_DPY_CLK_SW_SEL_1 (SPM_BASE + 0x488)
+#define DRAMC_DPY_CLK_SW_SEL_2 (SPM_BASE + 0x48C)
+#define DRAMC_DPY_CLK_SW_SEL_3 (SPM_BASE + 0x490)
+#define DRAMC_DPY_CLK_SPM_CON (SPM_BASE + 0x494)
+#define SPM_DVFS_LEVEL (SPM_BASE + 0x498)
+#define SPM_CIRQ_CON (SPM_BASE + 0x49C)
+#define SPM_DVFS_MISC (SPM_BASE + 0x4A0)
+#define RG_MODULE_SW_CG_0_MASK_REQ_0 (SPM_BASE + 0x4A4)
+#define RG_MODULE_SW_CG_0_MASK_REQ_1 (SPM_BASE + 0x4A8)
+#define RG_MODULE_SW_CG_0_MASK_REQ_2 (SPM_BASE + 0x4AC)
+#define RG_MODULE_SW_CG_1_MASK_REQ_0 (SPM_BASE + 0x4B0)
+#define RG_MODULE_SW_CG_1_MASK_REQ_1 (SPM_BASE + 0x4B4)
+#define RG_MODULE_SW_CG_1_MASK_REQ_2 (SPM_BASE + 0x4B8)
+#define RG_MODULE_SW_CG_2_MASK_REQ_0 (SPM_BASE + 0x4BC)
+#define RG_MODULE_SW_CG_2_MASK_REQ_1 (SPM_BASE + 0x4C0)
+#define RG_MODULE_SW_CG_2_MASK_REQ_2 (SPM_BASE + 0x4C4)
+#define RG_MODULE_SW_CG_3_MASK_REQ_0 (SPM_BASE + 0x4C8)
+#define RG_MODULE_SW_CG_3_MASK_REQ_1 (SPM_BASE + 0x4CC)
+#define RG_MODULE_SW_CG_3_MASK_REQ_2 (SPM_BASE + 0x4D0)
+#define PWR_STATUS_MASK_REQ_0 (SPM_BASE + 0x4D4)
+#define PWR_STATUS_MASK_REQ_1 (SPM_BASE + 0x4D8)
+#define PWR_STATUS_MASK_REQ_2 (SPM_BASE + 0x4DC)
+#define SPM_CG_CHECK_CON (SPM_BASE + 0x4E0)
+#define SPM_SRC_RDY_STA (SPM_BASE + 0x4E4)
+#define SPM_DVS_DFS_LEVEL (SPM_BASE + 0x4E8)
+#define SPM_FORCE_DVFS (SPM_BASE + 0x4EC)
+#define DRAMC_MCU_SRAM_CON (SPM_BASE + 0x4F0)
+#define DRAMC_MCU2_SRAM_CON (SPM_BASE + 0x4F4)
+#define DPY_SHU_SRAM_CON (SPM_BASE + 0x4F8)
+#define DPY_SHU2_SRAM_CON (SPM_BASE + 0x4FC)
+#define SPM_DPM_P2P_STA (SPM_BASE + 0x514)
+#define SPM_DPM_P2P_CON (SPM_BASE + 0x518)
+#define SPM_SW_FLAG_0 (SPM_BASE + 0x600)
+#define SPM_SW_DEBUG_0 (SPM_BASE + 0x604)
+#define SPM_SW_FLAG_1 (SPM_BASE + 0x608)
+#define SPM_SW_DEBUG_1 (SPM_BASE + 0x60C)
+#define SPM_SW_RSV_0 (SPM_BASE + 0x610)
+#define SPM_SW_RSV_1 (SPM_BASE + 0x614)
+#define SPM_SW_RSV_2 (SPM_BASE + 0x618)
+#define SPM_SW_RSV_3 (SPM_BASE + 0x61C)
+#define SPM_SW_RSV_4 (SPM_BASE + 0x620)
+#define SPM_SW_RSV_5 (SPM_BASE + 0x624)
+#define SPM_SW_RSV_6 (SPM_BASE + 0x628)
+#define SPM_SW_RSV_7 (SPM_BASE + 0x62C)
+#define SPM_SW_RSV_8 (SPM_BASE + 0x630)
+#define SPM_BK_WAKE_EVENT (SPM_BASE + 0x634)
+#define SPM_BK_VTCXO_DUR (SPM_BASE + 0x638)
+#define SPM_BK_WAKE_MISC (SPM_BASE + 0x63C)
+#define SPM_BK_PCM_TIMER (SPM_BASE + 0x640)
+#define ULPOSC_CON (SPM_BASE + 0x644)
+#define SPM_RSV_CON_0 (SPM_BASE + 0x650)
+#define SPM_RSV_CON_1 (SPM_BASE + 0x654)
+#define SPM_RSV_STA_0 (SPM_BASE + 0x658)
+#define SPM_RSV_STA_1 (SPM_BASE + 0x65C)
+#define SPM_SPARE_CON (SPM_BASE + 0x660)
+#define SPM_SPARE_CON_SET (SPM_BASE + 0x664)
+#define SPM_SPARE_CON_CLR (SPM_BASE + 0x668)
+#define SPM_CROSS_WAKE_M00_REQ (SPM_BASE + 0x66C)
+#define SPM_CROSS_WAKE_M01_REQ (SPM_BASE + 0x670)
+#define SPM_CROSS_WAKE_M02_REQ (SPM_BASE + 0x674)
+#define SPM_CROSS_WAKE_M03_REQ (SPM_BASE + 0x678)
+#define SCP_VCORE_LEVEL (SPM_BASE + 0x67C)
+#define SC_MM_CK_SEL_CON (SPM_BASE + 0x680)
+#define SPARE_ACK_MASK (SPM_BASE + 0x684)
+#define SPM_DV_CON_0 (SPM_BASE + 0x68C)
+#define SPM_DV_CON_1 (SPM_BASE + 0x690)
+#define SPM_DV_STA (SPM_BASE + 0x694)
+#define CONN_XOWCN_DEBUG_EN (SPM_BASE + 0x698)
+#define SPM_SEMA_M0 (SPM_BASE + 0x69C)
+#define SPM_SEMA_M1 (SPM_BASE + 0x6A0)
+#define SPM_SEMA_M2 (SPM_BASE + 0x6A4)
+#define SPM_SEMA_M3 (SPM_BASE + 0x6A8)
+#define SPM_SEMA_M4 (SPM_BASE + 0x6AC)
+#define SPM_SEMA_M5 (SPM_BASE + 0x6B0)
+#define SPM_SEMA_M6 (SPM_BASE + 0x6B4)
+#define SPM_SEMA_M7 (SPM_BASE + 0x6B8)
+#define SPM2ADSP_MAILBOX (SPM_BASE + 0x6BC)
+#define ADSP2SPM_MAILBOX (SPM_BASE + 0x6C0)
+#define SPM_ADSP_IRQ (SPM_BASE + 0x6C4)
+#define SPM_MD32_IRQ (SPM_BASE + 0x6C8)
+#define SPM2PMCU_MAILBOX_0 (SPM_BASE + 0x6CC)
+#define SPM2PMCU_MAILBOX_1 (SPM_BASE + 0x6D0)
+#define SPM2PMCU_MAILBOX_2 (SPM_BASE + 0x6D4)
+#define SPM2PMCU_MAILBOX_3 (SPM_BASE + 0x6D8)
+#define PMCU2SPM_MAILBOX_0 (SPM_BASE + 0x6DC)
+#define PMCU2SPM_MAILBOX_1 (SPM_BASE + 0x6E0)
+#define PMCU2SPM_MAILBOX_2 (SPM_BASE + 0x6E4)
+#define PMCU2SPM_MAILBOX_3 (SPM_BASE + 0x6E8)
+#define SPM_AP_SEMA (SPM_BASE + 0x6F8)
+#define SPM_SPM_SEMA (SPM_BASE + 0x6FC)
+#define SPM_DVFS_CON (SPM_BASE + 0x700)
+#define SPM_DVFS_CON_STA (SPM_BASE + 0x704)
+#define SPM_PMIC_SPMI_CON (SPM_BASE + 0x708)
+#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 SPM_DVFS_CMD16 (SPM_BASE + 0x750)
+#define SPM_DVFS_CMD17 (SPM_BASE + 0x754)
+#define SPM_DVFS_CMD18 (SPM_BASE + 0x758)
+#define SPM_DVFS_CMD19 (SPM_BASE + 0x75C)
+#define SPM_DVFS_CMD20 (SPM_BASE + 0x760)
+#define SPM_DVFS_CMD21 (SPM_BASE + 0x764)
+#define SPM_DVFS_CMD22 (SPM_BASE + 0x768)
+#define SPM_DVFS_CMD23 (SPM_BASE + 0x76C)
+#define SYS_TIMER_VALUE_L (SPM_BASE + 0x770)
+#define SYS_TIMER_VALUE_H (SPM_BASE + 0x774)
+#define SYS_TIMER_START_L (SPM_BASE + 0x778)
+#define SYS_TIMER_START_H (SPM_BASE + 0x77C)
+#define SYS_TIMER_LATCH_L_00 (SPM_BASE + 0x780)
+#define SYS_TIMER_LATCH_H_00 (SPM_BASE + 0x784)
+#define SYS_TIMER_LATCH_L_01 (SPM_BASE + 0x788)
+#define SYS_TIMER_LATCH_H_01 (SPM_BASE + 0x78C)
+#define SYS_TIMER_LATCH_L_02 (SPM_BASE + 0x790)
+#define SYS_TIMER_LATCH_H_02 (SPM_BASE + 0x794)
+#define SYS_TIMER_LATCH_L_03 (SPM_BASE + 0x798)
+#define SYS_TIMER_LATCH_H_03 (SPM_BASE + 0x79C)
+#define SYS_TIMER_LATCH_L_04 (SPM_BASE + 0x7A0)
+#define SYS_TIMER_LATCH_H_04 (SPM_BASE + 0x7A4)
+#define SYS_TIMER_LATCH_L_05 (SPM_BASE + 0x7A8)
+#define SYS_TIMER_LATCH_H_05 (SPM_BASE + 0x7AC)
+#define SYS_TIMER_LATCH_L_06 (SPM_BASE + 0x7B0)
+#define SYS_TIMER_LATCH_H_06 (SPM_BASE + 0x7B4)
+#define SYS_TIMER_LATCH_L_07 (SPM_BASE + 0x7B8)
+#define SYS_TIMER_LATCH_H_07 (SPM_BASE + 0x7BC)
+#define SYS_TIMER_LATCH_L_08 (SPM_BASE + 0x7C0)
+#define SYS_TIMER_LATCH_H_08 (SPM_BASE + 0x7C4)
+#define SYS_TIMER_LATCH_L_09 (SPM_BASE + 0x7C8)
+#define SYS_TIMER_LATCH_H_09 (SPM_BASE + 0x7CC)
+#define SYS_TIMER_LATCH_L_10 (SPM_BASE + 0x7D0)
+#define SYS_TIMER_LATCH_H_10 (SPM_BASE + 0x7D4)
+#define SYS_TIMER_LATCH_L_11 (SPM_BASE + 0x7D8)
+#define SYS_TIMER_LATCH_H_11 (SPM_BASE + 0x7DC)
+#define SYS_TIMER_LATCH_L_12 (SPM_BASE + 0x7E0)
+#define SYS_TIMER_LATCH_H_12 (SPM_BASE + 0x7E4)
+#define SYS_TIMER_LATCH_L_13 (SPM_BASE + 0x7E8)
+#define SYS_TIMER_LATCH_H_13 (SPM_BASE + 0x7EC)
+#define SYS_TIMER_LATCH_L_14 (SPM_BASE + 0x7F0)
+#define SYS_TIMER_LATCH_H_14 (SPM_BASE + 0x7F4)
+#define SYS_TIMER_LATCH_L_15 (SPM_BASE + 0x7F8)
+#define SYS_TIMER_LATCH_H_15 (SPM_BASE + 0x7FC)
+#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 PCM_WDT_LATCH_10 (SPM_BASE + 0x828)
+#define PCM_WDT_LATCH_11 (SPM_BASE + 0x82C)
+#define PCM_WDT_LATCH_12 (SPM_BASE + 0x830)
+#define PCM_WDT_LATCH_13 (SPM_BASE + 0x834)
+#define PCM_WDT_LATCH_14 (SPM_BASE + 0x838)
+#define PCM_WDT_LATCH_15 (SPM_BASE + 0x83C)
+#define PCM_WDT_LATCH_16 (SPM_BASE + 0x840)
+#define PCM_WDT_LATCH_17 (SPM_BASE + 0x844)
+#define PCM_WDT_LATCH_18 (SPM_BASE + 0x848)
+#define PCM_WDT_LATCH_SPARE_0 (SPM_BASE + 0x84C)
+#define PCM_WDT_LATCH_SPARE_1 (SPM_BASE + 0x850)
+#define PCM_WDT_LATCH_SPARE_2 (SPM_BASE + 0x854)
+#define DRAMC_GATING_ERR_LATCH_CH0_0 (SPM_BASE + 0x8A0)
+#define DRAMC_GATING_ERR_LATCH_CH0_1 (SPM_BASE + 0x8A4)
+#define DRAMC_GATING_ERR_LATCH_CH0_2 (SPM_BASE + 0x8A8)
+#define DRAMC_GATING_ERR_LATCH_CH0_3 (SPM_BASE + 0x8AC)
+#define DRAMC_GATING_ERR_LATCH_CH0_4 (SPM_BASE + 0x8B0)
+#define DRAMC_GATING_ERR_LATCH_CH0_5 (SPM_BASE + 0x8B4)
+#define DRAMC_GATING_ERR_LATCH_SPARE_0 (SPM_BASE + 0x8F4)
+#define SPM_ACK_CHK_CON_0 (SPM_BASE + 0x900)
+#define SPM_ACK_CHK_PC_0 (SPM_BASE + 0x904)
+#define SPM_ACK_CHK_SEL_0 (SPM_BASE + 0x908)
+#define SPM_ACK_CHK_TIMER_0 (SPM_BASE + 0x90C)
+#define SPM_ACK_CHK_STA_0 (SPM_BASE + 0x910)
+#define SPM_ACK_CHK_SWINT_0 (SPM_BASE + 0x914)
+#define SPM_ACK_CHK_CON_1 (SPM_BASE + 0x920)
+#define SPM_ACK_CHK_PC_1 (SPM_BASE + 0x924)
+#define SPM_ACK_CHK_SEL_1 (SPM_BASE + 0x928)
+#define SPM_ACK_CHK_TIMER_1 (SPM_BASE + 0x92C)
+#define SPM_ACK_CHK_STA_1 (SPM_BASE + 0x930)
+#define SPM_ACK_CHK_SWINT_1 (SPM_BASE + 0x934)
+#define SPM_ACK_CHK_CON_2 (SPM_BASE + 0x940)
+#define SPM_ACK_CHK_PC_2 (SPM_BASE + 0x944)
+#define SPM_ACK_CHK_SEL_2 (SPM_BASE + 0x948)
+#define SPM_ACK_CHK_TIMER_2 (SPM_BASE + 0x94C)
+#define SPM_ACK_CHK_STA_2 (SPM_BASE + 0x950)
+#define SPM_ACK_CHK_SWINT_2 (SPM_BASE + 0x954)
+#define SPM_ACK_CHK_CON_3 (SPM_BASE + 0x960)
+#define SPM_ACK_CHK_PC_3 (SPM_BASE + 0x964)
+#define SPM_ACK_CHK_SEL_3 (SPM_BASE + 0x968)
+#define SPM_ACK_CHK_TIMER_3 (SPM_BASE + 0x96C)
+#define SPM_ACK_CHK_STA_3 (SPM_BASE + 0x970)
+#define SPM_ACK_CHK_SWINT_3 (SPM_BASE + 0x974)
+#define SPM_COUNTER_0 (SPM_BASE + 0x978)
+#define SPM_COUNTER_1 (SPM_BASE + 0x97C)
+#define SPM_COUNTER_2 (SPM_BASE + 0x980)
+#define SYS_TIMER_CON (SPM_BASE + 0x98C)
+#define SPM_TWAM_CON (SPM_BASE + 0x990)
+#define SPM_TWAM_WINDOW_LEN (SPM_BASE + 0x994)
+#define SPM_TWAM_IDLE_SEL (SPM_BASE + 0x998)
+#define SPM_TWAM_EVENT_CLEAR (SPM_BASE + 0x99C)
+#define PMSR_LAST_DAT (SPM_BASE + 0xF00)
+#define PMSR_LAST_CNT (SPM_BASE + 0xF04)
+#define PMSR_LAST_ACK (SPM_BASE + 0xF08)
+#define SPM_PMSR_SEL_CON0 (SPM_BASE + 0xF10)
+#define SPM_PMSR_SEL_CON1 (SPM_BASE + 0xF14)
+#define SPM_PMSR_SEL_CON2 (SPM_BASE + 0xF18)
+#define SPM_PMSR_SEL_CON3 (SPM_BASE + 0xF1C)
+#define SPM_PMSR_SEL_CON4 (SPM_BASE + 0xF20)
+#define SPM_PMSR_SEL_CON5 (SPM_BASE + 0xF24)
+#define SPM_PMSR_SEL_CON6 (SPM_BASE + 0xF28)
+#define SPM_PMSR_SEL_CON7 (SPM_BASE + 0xF2C)
+#define SPM_PMSR_SEL_CON8 (SPM_BASE + 0xF30)
+#define SPM_PMSR_SEL_CON9 (SPM_BASE + 0xF34)
+#define SPM_PMSR_SEL_CON10 (SPM_BASE + 0xF3C)
+#define SPM_PMSR_SEL_CON11 (SPM_BASE + 0xF40)
+#define SPM_PMSR_TIEMR_STA0 (SPM_BASE + 0xFB8)
+#define SPM_PMSR_TIEMR_STA1 (SPM_BASE + 0xFBC)
+#define SPM_PMSR_TIEMR_STA2 (SPM_BASE + 0xFC0)
+#define SPM_PMSR_GENERAL_CON0 (SPM_BASE + 0xFC4)
+#define SPM_PMSR_GENERAL_CON1 (SPM_BASE + 0xFC8)
+#define SPM_PMSR_GENERAL_CON2 (SPM_BASE + 0xFCC)
+#define SPM_PMSR_GENERAL_CON3 (SPM_BASE + 0xFD0)
+#define SPM_PMSR_GENERAL_CON4 (SPM_BASE + 0xFD4)
+#define SPM_PMSR_GENERAL_CON5 (SPM_BASE + 0xFD8)
+#define SPM_PMSR_SW_RESET (SPM_BASE + 0xFDC)
+#define SPM_PMSR_MON_CON0 (SPM_BASE + 0xFE0)
+#define SPM_PMSR_MON_CON1 (SPM_BASE + 0xFE4)
+#define SPM_PMSR_MON_CON2 (SPM_BASE + 0xFE8)
+#define SPM_PMSR_LEN_CON0 (SPM_BASE + 0xFEC)
+#define SPM_PMSR_LEN_CON1 (SPM_BASE + 0xFF0)
+#define SPM_PMSR_LEN_CON2 (SPM_BASE + 0xFF4)
+
+#endif /* SPM_REG_H */
diff --git a/plat/mediatek/mt8188/plat_config.mk b/plat/mediatek/mt8188/plat_config.mk
new file mode 100644
index 0000000..137318e
--- /dev/null
+++ b/plat/mediatek/mt8188/plat_config.mk
@@ -0,0 +1,48 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Separate text code and read only data
+SEPARATE_CODE_AND_RODATA := 1
+# ARMv8.2 and above need enable HW assist coherence
+HW_ASSISTED_COHERENCY := 1
+# No need coherency memory because of HW assistency
+USE_COHERENT_MEM := 0
+# GIC600
+GICV3_SUPPORT_GIC600 := 1
+#
+# MTK options
+#
+PLAT_EXTRA_RODATA_INCLUDES := 1
+USE_PMIC_WRAP_INIT_V2 := 1
+USE_RTC_MT6359P := 1
+
+# Configs for A78 and A55
+CTX_INCLUDE_AARCH32_REGS := 0
+ERRATA_A55_1530923 := 1
+ERRATA_A55_1221012 := 1
+ERRATA_A78_1688305 := 1
+ERRATA_A78_1941498 := 1
+ERRATA_A78_1951500 := 1
+ERRATA_A78_1821534 := 1
+ERRATA_A78_2132060 := 1
+ERRATA_A78_2242635 := 1
+ERRATA_A78_2376745 := 1
+ERRATA_A78_2395406 := 1
+
+CONFIG_ARCH_ARM_V8_2 := y
+CONFIG_MTK_MCUSYS := y
+MCUSYS_VERSION := v1
+CONFIG_MTK_PM_SUPPORT := y
+CONFIG_MTK_PM_ARCH := 8_2
+CONFIG_MTK_CPU_PM_SUPPORT := y
+CONFIG_MTK_CPU_PM_ARCH := 3_2
+CONFIG_MTK_SMP_EN := y
+CONFIG_MTK_CPU_SUSPEND_EN := y
+CPU_PM_TINYSYS_SUPPORT := y
+MTK_PUBEVENT_ENABLE := y
+
+MACH_MT8188 := 1
+$(eval $(call add_define,MACH_MT8188))
diff --git a/plat/mediatek/mt8188/plat_mmap.c b/plat/mediatek/mt8188/plat_mmap.c
new file mode 100644
index 0000000..a611d22
--- /dev/null
+++ b/plat/mediatek/mt8188/plat_mmap.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <mtk_mmap_pool.h>
+#include <platform_def.h>
+
+static const mmap_region_t plat_mmap[] = {
+ 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(CPU_IDLE_SRAM_BASE, CPU_IDLE_SRAM_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ { 0 }
+};
+DECLARE_MTK_MMAP_REGIONS(plat_mmap);
diff --git a/plat/mediatek/mt8188/platform.mk b/plat/mediatek/mt8188/platform.mk
new file mode 100644
index 0000000..b6a17aa
--- /dev/null
+++ b/plat/mediatek/mt8188/platform.mk
@@ -0,0 +1,65 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+MTK_PLAT := plat/mediatek
+MTK_PLAT_SOC := ${MTK_PLAT}/${PLAT}
+MTK_SOC := ${PLAT}
+
+include plat/mediatek/build_helpers/mtk_build_helpers.mk
+include drivers/arm/gic/v3/gicv3.mk
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_INCLUDES := -I${MTK_PLAT}/common \
+ -I${MTK_PLAT}/include \
+ -I${MTK_PLAT}/include/${ARCH_VERSION} \
+ -I${MTK_PLAT} \
+ -I${MTK_PLAT_SOC}/include \
+ -Idrivers/arm/gic \
+
+MODULES-y += $(MTK_PLAT)/common
+MODULES-y += $(MTK_PLAT)/common/lpm
+MODULES-y += $(MTK_PLAT)/lib/mtk_init
+MODULES-y += $(MTK_PLAT)/lib/pm
+MODULES-y += $(MTK_PLAT)/lib/system_reset
+MODULES-y += $(MTK_PLAT)/drivers/audio
+MODULES-y += $(MTK_PLAT)/drivers/cirq
+MODULES-y += $(MTK_PLAT)/drivers/cpu_pm
+MODULES-y += $(MTK_PLAT)/drivers/dcm
+MODULES-y += $(MTK_PLAT)/drivers/dfd
+MODULES-y += $(MTK_PLAT)/drivers/dp
+MODULES-y += $(MTK_PLAT)/drivers/emi_mpu
+MODULES-y += $(MTK_PLAT)/drivers/gic600
+MODULES-y += $(MTK_PLAT)/drivers/gpio
+MODULES-y += $(MTK_PLAT)/drivers/iommu
+MODULES-y += $(MTK_PLAT)/drivers/mcusys
+MODULES-y += $(MTK_PLAT)/drivers/pmic
+MODULES-y += $(MTK_PLAT)/drivers/pmic_wrap
+MODULES-y += $(MTK_PLAT)/drivers/ptp3
+MODULES-y += $(MTK_PLAT)/drivers/rtc
+MODULES-y += $(MTK_PLAT)/drivers/timer
+MODULES-y += $(MTK_PLAT)/helpers
+MODULES-y += $(MTK_PLAT)/topology
+
+PLAT_BL_COMMON_SOURCES := common/desc_image_load.c \
+ drivers/ti/uart/aarch64/16550_console.S \
+ lib/bl_aux_params/bl_aux_params.c
+
+BL31_SOURCES += drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ lib/cpus/aarch64/cortex_a55.S \
+ lib/cpus/aarch64/cortex_a78.S \
+ ${GICV3_SOURCES} \
+ ${XLAT_TABLES_LIB_SRCS} \
+ plat/common/plat_gicv3.c \
+ plat/common/plat_psci_common.c \
+ plat/common/aarch64/crash_console_helpers.S \
+ ${MTK_PLAT}/common/mtk_plat_common.c \
+ ${MTK_PLAT}/common/params_setup.c \
+ $(MTK_PLAT)/$(MTK_SOC)/plat_mmap.c
+
+include plat/mediatek/build_helpers/mtk_build_helpers_epilogue.mk
+
+include lib/coreboot/coreboot.mk
diff --git a/plat/mediatek/mt8192/aarch64/plat_helpers.S b/plat/mediatek/mt8192/aarch64/plat_helpers.S
new file mode 100644
index 0000000..99274de
--- /dev/null
+++ b/plat/mediatek/mt8192/aarch64/plat_helpers.S
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .globl plat_is_my_cpu_primary
+ .globl plat_my_core_pos
+ .globl plat_mediatek_calc_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)
+ * This function uses the plat_mediatek_calc_core_pos()
+ * definition to get the index of the calling CPU.
+ * -----------------------------------------------------
+ */
+func plat_my_core_pos
+ mrs x0, mpidr_el1
+ b plat_mediatek_calc_core_pos
+endfunc plat_my_core_pos
+
+ /* -----------------------------------------------------
+ * unsigned int plat_mediatek_calc_core_pos(u_register_t mpidr);
+ *
+ * In ARMv8.2, AFF2 is cluster id, AFF1 is core id and
+ * AFF0 is thread id. There is only one cluster in ARMv8.2
+ * and one thread in current implementation.
+ *
+ * With this function: CorePos = CoreID (AFF1)
+ * we do it with x0 = (x0 >> 8) & 0xff
+ * -----------------------------------------------------
+ */
+func plat_mediatek_calc_core_pos
+ mov x1, #MPIDR_AFFLVL_MASK
+ and x0, x1, x0, lsr #MPIDR_AFF1_SHIFT
+ ret
+endfunc plat_mediatek_calc_core_pos
diff --git a/plat/mediatek/mt8192/aarch64/platform_common.c b/plat/mediatek/mt8192/aarch64/platform_common.c
new file mode 100644
index 0000000..fc98871
--- /dev/null
+++ b/plat/mediatek/mt8192/aarch64/platform_common.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Project Includes */
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+/* Platform Includes */
+#include <platform_def.h>
+
+/* Table of regions to map using the MMU. */
+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(MTK_DEV_RNG2_BASE, MTK_DEV_RNG2_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(MTK_MCDI_SRAM_BASE, MTK_MCDI_SRAM_MAP_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(APUSYS_SCTRL_REVISER_BASE, APUSYS_SCTRL_REVISER_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(APUSYS_APU_S_S_4_BASE, APUSYS_APU_S_S_4_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(APUSYS_APC_AO_WRAPPER_BASE, APUSYS_APC_AO_WRAPPER_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(APUSYS_NOC_DAPC_AO_BASE, APUSYS_NOC_DAPC_AO_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)
+{
+ mmap_add_region(total_base, total_base, total_size,
+ MT_RW_DATA | MT_SECURE);
+ mmap_add_region(ro_start, ro_start, ro_limit - ro_start,
+ MT_CODE | 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;
+}
diff --git a/plat/mediatek/mt8192/bl31_plat_setup.c b/plat/mediatek/mt8192/bl31_plat_setup.c
new file mode 100644
index 0000000..c3cb9a5
--- /dev/null
+++ b/plat/mediatek/mt8192/bl31_plat_setup.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* System Includes */
+#include <assert.h>
+
+/* Project Includes */
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/coreboot.h>
+
+/* Platform Includes */
+#include <devapc/devapc.h>
+#include <emi_mpu/emi_mpu.h>
+#include <gpio/mtgpio.h>
+#include <mt_gic_v3.h>
+#include <mt_spm.h>
+#include <mt_timer.h>
+#include <mtk_dcm.h>
+#include <plat_params.h>
+#include <plat_private.h>
+
+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;
+ }
+}
+
+/*******************************************************************************
+ * 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_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("MT8192 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)
+{
+ /* Set dcm on */
+ if (!dcm_set_default()) {
+ ERROR("Failed to set default dcm on!!\n");
+ }
+
+ /* MPU Init */
+ emi_mpu_init();
+
+ /* DAPC Init */
+ devapc_init();
+
+ /* Initialize the GIC driver, CPU and distributor interfaces */
+ mt_gic_driver_init();
+ mt_gic_init();
+
+ mt_gpio_init();
+ mt_systimer_init();
+ generic_delay_timer_init();
+ 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_configure_mmu_el3(BL31_START,
+ BL31_END - BL31_START,
+ BL_CODE_BASE,
+ BL_CODE_END);
+}
diff --git a/plat/mediatek/mt8192/drivers/apusys/mtk_apusys.c b/plat/mediatek/mt8192/drivers/apusys/mtk_apusys.c
new file mode 100644
index 0000000..782aa5f
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/apusys/mtk_apusys.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <mtk_apusys.h>
+#include <plat/common/platform.h>
+
+uint64_t apusys_kernel_ctrl(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4,
+ uint32_t *ret1)
+{
+ uint32_t request_ops;
+
+ request_ops = (uint32_t)x1;
+ INFO("[APUSYS] ops=0x%x\n", request_ops);
+
+ switch (request_ops) {
+ case MTK_SIP_APU_START_MCU:
+ /* setup addr[33:32] in reviser */
+ mmio_write_32(REVISER_SECUREFW_CTXT, 0U);
+ mmio_write_32(REVISER_USDRFW_CTXT, 0U);
+
+ /* setup secure sideband */
+ mmio_write_32(AO_SEC_FW,
+ (SEC_FW_NON_SECURE << SEC_FW_SHIFT_NS) |
+ (0U << SEC_FW_DOMAIN_SHIFT));
+
+ /* setup boot address */
+ mmio_write_32(AO_MD32_BOOT_CTRL, 0U);
+
+ /* setup pre-define region */
+ mmio_write_32(AO_MD32_PRE_DEFINE,
+ (PRE_DEFINE_CACHE_TCM << PRE_DEFINE_SHIFT_0G) |
+ (PRE_DEFINE_CACHE << PRE_DEFINE_SHIFT_1G) |
+ (PRE_DEFINE_CACHE << PRE_DEFINE_SHIFT_2G) |
+ (PRE_DEFINE_CACHE << PRE_DEFINE_SHIFT_3G));
+
+ /* release runstall */
+ mmio_write_32(AO_MD32_SYS_CTRL, SYS_CTRL_RUN);
+
+ INFO("[APUSYS] reviser_ctxt=%x,%x\n",
+ mmio_read_32(REVISER_SECUREFW_CTXT),
+ mmio_read_32(REVISER_USDRFW_CTXT));
+ INFO("[APUSYS]fw=0x%08x,boot=0x%08x,def=0x%08x,sys=0x%08x\n",
+ mmio_read_32(AO_SEC_FW),
+ mmio_read_32(AO_MD32_BOOT_CTRL),
+ mmio_read_32(AO_MD32_PRE_DEFINE),
+ mmio_read_32(AO_MD32_SYS_CTRL));
+ break;
+ case MTK_SIP_APU_STOP_MCU:
+ /* hold runstall */
+ mmio_write_32(AO_MD32_SYS_CTRL, SYS_CTRL_STALL);
+
+ INFO("[APUSYS] md32_boot_ctrl=0x%08x,runstall=0x%08x\n",
+ mmio_read_32(AO_MD32_BOOT_CTRL),
+ mmio_read_32(AO_MD32_SYS_CTRL));
+ break;
+ default:
+ ERROR("%s, unknown request_ops = %x\n", __func__, request_ops);
+ break;
+ }
+
+ return 0UL;
+}
diff --git a/plat/mediatek/mt8192/drivers/apusys/mtk_apusys.h b/plat/mediatek/mt8192/drivers/apusys/mtk_apusys.h
new file mode 100644
index 0000000..95fac4a
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/apusys/mtk_apusys.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __MTK_APUSYS_H__
+#define __MTK_APUSYS_H__
+
+#include <stdint.h>
+
+/* setup the SMC command ops */
+#define MTK_SIP_APU_START_MCU 0x00U
+#define MTK_SIP_APU_STOP_MCU 0x01U
+
+/* AO Register */
+#define AO_MD32_PRE_DEFINE (APUSYS_APU_S_S_4_BASE + 0x00)
+#define AO_MD32_BOOT_CTRL (APUSYS_APU_S_S_4_BASE + 0x04)
+#define AO_MD32_SYS_CTRL (APUSYS_APU_S_S_4_BASE + 0x08)
+#define AO_SEC_FW (APUSYS_APU_S_S_4_BASE + 0x10)
+
+#define PRE_DEFINE_CACHE_TCM 0x3U
+#define PRE_DEFINE_CACHE 0x2U
+#define PRE_DEFINE_SHIFT_0G 0U
+#define PRE_DEFINE_SHIFT_1G 2U
+#define PRE_DEFINE_SHIFT_2G 4U
+#define PRE_DEFINE_SHIFT_3G 6U
+
+#define SEC_FW_NON_SECURE 1U
+#define SEC_FW_SHIFT_NS 4U
+#define SEC_FW_DOMAIN_SHIFT 0U
+
+#define SYS_CTRL_RUN 0U
+#define SYS_CTRL_STALL 1U
+
+/* Reviser Register */
+#define REVISER_SECUREFW_CTXT (APUSYS_SCTRL_REVISER_BASE + 0x300)
+#define REVISER_USDRFW_CTXT (APUSYS_SCTRL_REVISER_BASE + 0x304)
+
+uint64_t apusys_kernel_ctrl(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4,
+ uint32_t *ret1);
+#endif /* __MTK_APUSYS_H__ */
diff --git a/plat/mediatek/mt8192/drivers/apusys/mtk_apusys_apc.c b/plat/mediatek/mt8192/drivers/apusys/mtk_apusys_apc.c
new file mode 100644
index 0000000..245d512
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/apusys/mtk_apusys_apc.c
@@ -0,0 +1,571 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <mtk_apusys_apc.h>
+#include <mtk_apusys_apc_def.h>
+#include <mtk_plat_common.h>
+#include <platform_def.h>
+
+static const struct APC_DOM_16 APUSYS_NOC_DAPC_AO[] = {
+/* 0~3 */
+APUSYS_APC_AO_ATTR("slv07-0",
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION),
+APUSYS_APC_AO_ATTR("slv07-1",
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION),
+APUSYS_APC_AO_ATTR("slv07-2",
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION),
+APUSYS_APC_AO_ATTR("slv07-3",
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION),
+
+/* 16~18 */
+APUSYS_APC_AO_ATTR("slv01-0",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("slv01-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("slv01-2",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 19~21 */
+APUSYS_APC_AO_ATTR("slv00-0",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("slv00-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("slv00-2",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 22~26 */
+APUSYS_APC_AO_ATTR("slv02-0",
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION),
+APUSYS_APC_AO_ATTR("slv02-1",
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION),
+APUSYS_APC_AO_ATTR("slv02-2",
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION),
+APUSYS_APC_AO_ATTR("slv02-3",
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION),
+APUSYS_APC_AO_ATTR("slv02-4",
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION,
+ NO_PROTECTION, NO_PROTECTION, NO_PROTECTION, NO_PROTECTION),
+};
+
+static int32_t set_slave_noc_dapc(uint32_t slave,
+ enum APUSYS_APC_DOMAIN_ID domain_id,
+ enum APUSYS_APC_PERM_TYPE perm)
+{
+ uint32_t apc_register_index;
+ uint32_t apc_set_index;
+ uintptr_t base;
+ uint32_t clr_bit;
+ uint32_t set_bit;
+ int32_t ret;
+
+ if (perm >= PERM_NUM) {
+ ERROR("[NOC_DAPC] perm type:0x%x is not supported!\n", perm);
+ ret = APUSYS_APC_ERR_PERMISSION_NOT_SUPPORTED;
+ goto exit;
+ }
+
+ apc_register_index = slave / APUSYS_NOC_DAPC_AO_SLAVE_NUM_IN_1_DOM;
+ apc_set_index = slave % APUSYS_NOC_DAPC_AO_SLAVE_NUM_IN_1_DOM;
+
+ clr_bit = 0xFFFFFFFF ^ (0x3U << (apc_set_index * 2));
+ set_bit = perm << (apc_set_index * 2);
+
+ if ((slave < APUSYS_NOC_DAPC_AO_SLAVE_NUM) &&
+ (domain_id < APUSYS_NOC_DAPC_AO_DOM_NUM)) {
+ base = APUSYS_NOC_DAPC_AO_BASE +
+ (domain_id * 0x40) + (apc_register_index * 4);
+ apuapc_writel(apuapc_readl(base) & clr_bit, base);
+ apuapc_writel(apuapc_readl(base) | set_bit, base);
+ ret = APUSYS_APC_OK;
+ } else {
+ ERROR("[NOC_DAPC] %s: %s, %s:0x%x, %s:0x%x\n",
+ __func__, "out of boundary",
+ "slave", slave,
+ "domain_id", domain_id);
+ ret = APUSYS_APC_ERR_OUT_OF_BOUNDARY;
+ }
+
+exit:
+ return ret;
+}
+
+static void dump_apusys_noc_dapc(void)
+{
+ uint32_t reg_num;
+ uint32_t d, i;
+
+ reg_num = APUSYS_NOC_DAPC_AO_SLAVE_NUM /
+ APUSYS_NOC_DAPC_AO_SLAVE_NUM_IN_1_DOM;
+ for (d = 0U; d < APUSYS_NOC_DAPC_AO_DOM_NUM; d++) {
+ for (i = 0U; i <= reg_num; i++) {
+ INFO("[NOCDAPC] D%d_APC_%d: 0x%x\n", d, i,
+ apuapc_readl(APUSYS_NOC_DAPC_AO_BASE +
+ (d * 0x40) + (i * 4)));
+ }
+ }
+
+ INFO("[NOCDAPC] APC_CON: 0x%x\n", apuapc_readl(APUSYS_NOC_DAPC_CON));
+}
+
+static const struct APC_DOM_16 APUSYS_AO_Devices[] = {
+
+/* 0 */
+APUSYS_APC_AO_ATTR("apusys_ao-0",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apusys_ao-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apusys_ao-2",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apusys_ao-3",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apusys_ao-4",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apusys_ao-5",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("md32_apb_s-0",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("md32_apb_s-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("md32_apb_s-2",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("md32_debug_apb",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 10 */
+APUSYS_APC_AO_ATTR("apu_conn_config",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apu_sctrl_reviser",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apu_sema_stimer",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apu_emi_config",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apu_adl",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apu_edma_lite0",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apu_edma_lite1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apu_edma0",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apu_edma0",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apu_dapc_ao",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 20 */
+APUSYS_APC_AO_ATTR("apu_dapc",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("infra_bcrm",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apb_dbg_ctl",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("noc_dapc",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apu_noc_bcrm",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apu_noc_config",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("vpu_core0_config-0",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("vpu_core0_config-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("vpu_core1_config-0",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("vpu_core1_config-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 30 */
+APUSYS_APC_AO_ATTR("mdla0_apb-0",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("mdla0_apb-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("mdla0_apb-2",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("mdla0_apb-3",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apu_iommu0_r0",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apu_iommu0_r1",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apu_iommu0_r2",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apu_iommu0_r3",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apu_iommu0_r4",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("apu_rsi2_config",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 40 */
+APUSYS_APC_AO_ATTR("apu_ssc2_config",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("vp6_core0_debug_apb",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+APUSYS_APC_AO_ATTR("vp6_core1_debug_apb",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+};
+
+static int32_t set_slave_apc(uint32_t slave,
+ enum APUSYS_APC_DOMAIN_ID domain_id,
+ enum APUSYS_APC_PERM_TYPE perm)
+{
+ uint32_t apc_register_index;
+ uint32_t apc_set_index;
+ uintptr_t base;
+ uint32_t clr_bit;
+ uint32_t set_bit;
+ int32_t ret;
+
+ if (perm >= PERM_NUM) {
+ ERROR("[APUAPC] perm type:0x%x is not supported!\n", perm);
+ ret = APUSYS_APC_ERR_PERMISSION_NOT_SUPPORTED;
+ goto exit;
+ }
+
+ apc_register_index = slave / APUSYS_APC_SYS0_AO_SLAVE_NUM_IN_1_DOM;
+ apc_set_index = slave % APUSYS_APC_SYS0_AO_SLAVE_NUM_IN_1_DOM;
+
+ clr_bit = 0xFFFFFFFF ^ (0x3U << (apc_set_index * 2));
+ set_bit = perm << (apc_set_index * 2);
+
+ if ((slave < APUSYS_APC_SYS0_AO_SLAVE_NUM) &&
+ (domain_id < APUSYS_APC_SYS0_AO_DOM_NUM)) {
+ base = APUSYS_APC_AO_BASE +
+ (domain_id * 0x40) + (apc_register_index * 4);
+ apuapc_writel(apuapc_readl(base) & clr_bit, base);
+ apuapc_writel(apuapc_readl(base) | set_bit, base);
+ ret = APUSYS_APC_OK;
+ } else {
+ ERROR("[APUAPC] %s: %s, %s:0x%x, %s:0x%x\n",
+ __func__, "out of boundary",
+ "slave", slave,
+ "domain_id", domain_id);
+ ret = APUSYS_APC_ERR_OUT_OF_BOUNDARY;
+ }
+
+exit:
+ return ret;
+}
+
+static void dump_apusys_ao_apc(void)
+{
+ uint32_t reg_num;
+ uint32_t d, i;
+
+ reg_num = APUSYS_APC_SYS0_AO_SLAVE_NUM /
+ APUSYS_APC_SYS0_AO_SLAVE_NUM_IN_1_DOM;
+ for (d = 0U; d < APUSYS_APC_SYS0_AO_DOM_NUM; d++) {
+ for (i = 0U; i <= reg_num; i++) {
+ INFO("[APUAPC] D%d_APC_%d: 0x%x\n", d, i,
+ apuapc_readl(APUSYS_APC_AO_BASE +
+ (d * 0x40) + (i * 4)));
+ }
+ }
+ INFO("[APUAPC] APC_CON: 0x%x\n", apuapc_readl(APUSYS_APC_CON));
+}
+
+static int32_t set_apusys_noc_dapc(void)
+{
+ int32_t ret = 0;
+ uint32_t i;
+ uint32_t index;
+
+ for (i = 0U; i < ARRAY_SIZE(APUSYS_NOC_DAPC_AO); i++) {
+ if (i < APUSYS_NOC_DAPC_GAP_BOUNDARY) {
+ index = i;
+ } else {
+ index = i + APUSYS_NOC_DAPC_JUMP_GAP;
+ }
+ ret += set_slave_noc_dapc(index, DOMAIN_0,
+ APUSYS_NOC_DAPC_AO[i].d0_permission);
+ ret += set_slave_noc_dapc(index, DOMAIN_1,
+ APUSYS_NOC_DAPC_AO[i].d1_permission);
+ ret += set_slave_noc_dapc(index, DOMAIN_2,
+ APUSYS_NOC_DAPC_AO[i].d2_permission);
+ ret += set_slave_noc_dapc(index, DOMAIN_3,
+ APUSYS_NOC_DAPC_AO[i].d3_permission);
+ ret += set_slave_noc_dapc(index, DOMAIN_4,
+ APUSYS_NOC_DAPC_AO[i].d4_permission);
+ ret += set_slave_noc_dapc(index, DOMAIN_5,
+ APUSYS_NOC_DAPC_AO[i].d5_permission);
+ ret += set_slave_noc_dapc(index, DOMAIN_6,
+ APUSYS_NOC_DAPC_AO[i].d6_permission);
+ ret += set_slave_noc_dapc(index, DOMAIN_7,
+ APUSYS_NOC_DAPC_AO[i].d7_permission);
+ ret += set_slave_noc_dapc(index, DOMAIN_8,
+ APUSYS_NOC_DAPC_AO[i].d8_permission);
+ ret += set_slave_noc_dapc(index, DOMAIN_9,
+ APUSYS_NOC_DAPC_AO[i].d9_permission);
+ ret += set_slave_noc_dapc(index, DOMAIN_10,
+ APUSYS_NOC_DAPC_AO[i].d10_permission);
+ ret += set_slave_noc_dapc(index, DOMAIN_11,
+ APUSYS_NOC_DAPC_AO[i].d11_permission);
+ ret += set_slave_noc_dapc(index, DOMAIN_12,
+ APUSYS_NOC_DAPC_AO[i].d12_permission);
+ ret += set_slave_noc_dapc(index, DOMAIN_13,
+ APUSYS_NOC_DAPC_AO[i].d13_permission);
+ ret += set_slave_noc_dapc(index, DOMAIN_14,
+ APUSYS_NOC_DAPC_AO[i].d14_permission);
+ ret += set_slave_noc_dapc(index, DOMAIN_15,
+ APUSYS_NOC_DAPC_AO[i].d15_permission);
+ }
+
+ return ret;
+}
+
+static int32_t set_apusys_ao_apc(void)
+{
+ int32_t ret = 0;
+ uint32_t i;
+
+ for (i = 0U; i < ARRAY_SIZE(APUSYS_AO_Devices); i++) {
+ ret += set_slave_apc(i, DOMAIN_0,
+ APUSYS_AO_Devices[i].d0_permission);
+ ret += set_slave_apc(i, DOMAIN_1,
+ APUSYS_AO_Devices[i].d1_permission);
+ ret += set_slave_apc(i, DOMAIN_2,
+ APUSYS_AO_Devices[i].d2_permission);
+ ret += set_slave_apc(i, DOMAIN_3,
+ APUSYS_AO_Devices[i].d3_permission);
+ ret += set_slave_apc(i, DOMAIN_4,
+ APUSYS_AO_Devices[i].d4_permission);
+ ret += set_slave_apc(i, DOMAIN_5,
+ APUSYS_AO_Devices[i].d5_permission);
+ ret += set_slave_apc(i, DOMAIN_6,
+ APUSYS_AO_Devices[i].d6_permission);
+ ret += set_slave_apc(i, DOMAIN_7,
+ APUSYS_AO_Devices[i].d7_permission);
+ ret += set_slave_apc(i, DOMAIN_8,
+ APUSYS_AO_Devices[i].d8_permission);
+ ret += set_slave_apc(i, DOMAIN_9,
+ APUSYS_AO_Devices[i].d9_permission);
+ ret += set_slave_apc(i, DOMAIN_10,
+ APUSYS_AO_Devices[i].d10_permission);
+ ret += set_slave_apc(i, DOMAIN_11,
+ APUSYS_AO_Devices[i].d11_permission);
+ ret += set_slave_apc(i, DOMAIN_12,
+ APUSYS_AO_Devices[i].d12_permission);
+ ret += set_slave_apc(i, DOMAIN_13,
+ APUSYS_AO_Devices[i].d13_permission);
+ ret += set_slave_apc(i, DOMAIN_14,
+ APUSYS_AO_Devices[i].d14_permission);
+ ret += set_slave_apc(i, DOMAIN_15,
+ APUSYS_AO_Devices[i].d15_permission);
+ }
+
+ return ret;
+}
+
+static void set_apusys_apc_lock(void)
+{
+ uint32_t set_bit = 1U << APUSYS_APC_SYS0_LOCK_BIT_APU_SCTRL_REVISER;
+
+ /* Lock apu_sctrl_reviser */
+ set_bit = set_bit | (1U << APUSYS_APC_SYS0_LOCK_BIT_APUSYS_AO_5);
+ apuapc_writel(set_bit, APUSYS_SYS0_APC_LOCK_0);
+}
+
+void set_apusys_apc(void)
+{
+ int32_t ret = 0;
+
+ /* Check violation status */
+ INFO("[APUAPC] vio %d\n", apuapc_readl(APUSYS_APC_CON) & 0x80000000);
+
+ /* Initial Permission */
+ ret = set_apusys_ao_apc();
+ INFO("[APUAPC] %s - %s!\n", "set_apusys_ao_apc",
+ ret ? "FAILED" : "SUCCESS");
+
+ /* Lock */
+ set_apusys_apc_lock();
+
+ /* Initial NoC Permission */
+ ret = set_apusys_noc_dapc();
+ INFO("[APUAPC] %s - %s!\n", "set_apusys_noc_dapc",
+ ret ? "FAILED" : "SUCCESS");
+
+ /* Dump Permission */
+ dump_apusys_ao_apc();
+ dump_apusys_noc_dapc();
+
+ INFO("[APUAPC] %s done\n", __func__);
+}
diff --git a/plat/mediatek/mt8192/drivers/apusys/mtk_apusys_apc.h b/plat/mediatek/mt8192/drivers/apusys/mtk_apusys_apc.h
new file mode 100644
index 0000000..ff7a9fa
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/apusys/mtk_apusys_apc.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __MTK_APUSYS_APC_H__
+#define __MTK_APUSYS_APC_H__
+
+void set_apusys_apc(void);
+
+#endif /* __MTK_APUSYS_APC_H__ */
diff --git a/plat/mediatek/mt8192/drivers/apusys/mtk_apusys_apc_def.h b/plat/mediatek/mt8192/drivers/apusys/mtk_apusys_apc_def.h
new file mode 100644
index 0000000..b392d6a
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/apusys/mtk_apusys_apc_def.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __MTK_APUSYS_APC_DEF_H__
+#define __MTK_APUSYS_APC_DEF_H__
+
+#include <lib/mmio.h>
+
+enum APUSYS_APC_ERR_STATUS {
+ APUSYS_APC_OK = 0x0,
+
+ APUSYS_APC_ERR_GENERIC = 0x1000,
+ APUSYS_APC_ERR_INVALID_CMD = 0x1001,
+ APUSYS_APC_ERR_SLAVE_TYPE_NOT_SUPPORTED = 0x1002,
+ APUSYS_APC_ERR_SLAVE_IDX_NOT_SUPPORTED = 0x1003,
+ APUSYS_APC_ERR_DOMAIN_NOT_SUPPORTED = 0x1004,
+ APUSYS_APC_ERR_PERMISSION_NOT_SUPPORTED = 0x1005,
+ APUSYS_APC_ERR_OUT_OF_BOUNDARY = 0x1006,
+ APUSYS_APC_ERR_REQ_TYPE_NOT_SUPPORTED = 0x1007,
+};
+
+enum APUSYS_APC_PERM_TYPE {
+ NO_PROTECTION = 0U,
+ SEC_RW_ONLY = 1U,
+ SEC_RW_NS_R = 2U,
+ FORBIDDEN = 3U,
+ PERM_NUM = 4U,
+};
+
+enum APUSYS_APC_DOMAIN_ID {
+ DOMAIN_0 = 0U,
+ DOMAIN_1 = 1U,
+ DOMAIN_2 = 2U,
+ DOMAIN_3 = 3U,
+ DOMAIN_4 = 4U,
+ DOMAIN_5 = 5U,
+ DOMAIN_6 = 6U,
+ DOMAIN_7 = 7U,
+ DOMAIN_8 = 8U,
+ DOMAIN_9 = 9U,
+ DOMAIN_10 = 10U,
+ DOMAIN_11 = 11U,
+ DOMAIN_12 = 12U,
+ DOMAIN_13 = 13U,
+ DOMAIN_14 = 14U,
+ DOMAIN_15 = 15U,
+};
+
+struct APC_DOM_16 {
+ unsigned char d0_permission;
+ unsigned char d1_permission;
+ unsigned char d2_permission;
+ unsigned char d3_permission;
+ unsigned char d4_permission;
+ unsigned char d5_permission;
+ unsigned char d6_permission;
+ unsigned char d7_permission;
+ unsigned char d8_permission;
+ unsigned char d9_permission;
+ unsigned char d10_permission;
+ unsigned char d11_permission;
+ unsigned char d12_permission;
+ unsigned char d13_permission;
+ unsigned char d14_permission;
+ unsigned char d15_permission;
+};
+
+#define APUSYS_APC_AO_ATTR(DEV_NAME, PERM_ATTR0, PERM_ATTR1, \
+ PERM_ATTR2, PERM_ATTR3, PERM_ATTR4, PERM_ATTR5, \
+ PERM_ATTR6, PERM_ATTR7, PERM_ATTR8, PERM_ATTR9, \
+ PERM_ATTR10, PERM_ATTR11, PERM_ATTR12, PERM_ATTR13, \
+ PERM_ATTR14, PERM_ATTR15) \
+ {(unsigned char)PERM_ATTR0, (unsigned char)PERM_ATTR1, \
+ (unsigned char)PERM_ATTR2, (unsigned char)PERM_ATTR3, \
+ (unsigned char)PERM_ATTR4, (unsigned char)PERM_ATTR5, \
+ (unsigned char)PERM_ATTR6, (unsigned char)PERM_ATTR7, \
+ (unsigned char)PERM_ATTR8, (unsigned char)PERM_ATTR9, \
+ (unsigned char)PERM_ATTR10, (unsigned char)PERM_ATTR11, \
+ (unsigned char)PERM_ATTR12, (unsigned char)PERM_ATTR13, \
+ (unsigned char)PERM_ATTR14, (unsigned char)PERM_ATTR15}
+
+#define apuapc_writel(VAL, REG) mmio_write_32((uintptr_t)REG, VAL)
+#define apuapc_readl(REG) mmio_read_32((uintptr_t)REG)
+
+/* APUSYS APC AO Registers */
+#define APUSYS_APC_AO_BASE APUSYS_APC_AO_WRAPPER_BASE
+#define APUSYS_APC_CON (APUSYS_APC_AO_BASE + 0x00F00)
+#define APUSYS_SYS0_APC_LOCK_0 (APUSYS_APC_AO_BASE + 0x00700)
+
+/* APUSYS NOC_DPAC_AO Registers */
+#define APUSYS_NOC_DAPC_CON (APUSYS_NOC_DAPC_AO_BASE + 0x00F00)
+
+#define APUSYS_NOC_DAPC_GAP_BOUNDARY 4U
+#define APUSYS_NOC_DAPC_JUMP_GAP 12U
+
+#define APUSYS_APC_SYS0_AO_SLAVE_NUM_IN_1_DOM 16U
+#define APUSYS_APC_SYS0_AO_DOM_NUM 16U
+#define APUSYS_APC_SYS0_AO_SLAVE_NUM 59U
+
+#define APUSYS_APC_SYS0_LOCK_BIT_APU_SCTRL_REVISER 11U
+#define APUSYS_APC_SYS0_LOCK_BIT_APUSYS_AO_5 5U
+
+#define APUSYS_NOC_DAPC_AO_SLAVE_NUM_IN_1_DOM 16U
+#define APUSYS_NOC_DAPC_AO_DOM_NUM 16U
+#define APUSYS_NOC_DAPC_AO_SLAVE_NUM 27U
+
+#endif /* __MTK_APUSYS_APC_DEF_H__ */
diff --git a/plat/mediatek/mt8192/drivers/dcm/mtk_dcm.c b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm.c
new file mode 100644
index 0000000..dd8bf4e
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mtk_dcm.h>
+#include <mtk_dcm_utils.h>
+
+static void dcm_armcore(bool mode)
+{
+ dcm_mp_cpusys_top_bus_pll_div_dcm(mode);
+ dcm_mp_cpusys_top_cpu_pll_div_0_dcm(mode);
+ dcm_mp_cpusys_top_cpu_pll_div_1_dcm(mode);
+}
+
+static void dcm_mcusys(bool on)
+{
+ dcm_mp_cpusys_top_adb_dcm(on);
+ dcm_mp_cpusys_top_apb_dcm(on);
+ dcm_mp_cpusys_top_cpubiu_dcm(on);
+ dcm_mp_cpusys_top_misc_dcm(on);
+ dcm_mp_cpusys_top_mp0_qdcm(on);
+ dcm_cpccfg_reg_emi_wfifo(on);
+ dcm_mp_cpusys_top_last_cor_idle_dcm(on);
+}
+
+static void dcm_stall(bool on)
+{
+ dcm_mp_cpusys_top_core_stall_dcm(on);
+ dcm_mp_cpusys_top_fcm_stall_dcm(on);
+}
+
+static bool check_dcm_state(void)
+{
+ bool ret = true;
+
+ ret &= dcm_mp_cpusys_top_bus_pll_div_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on();
+
+ ret &= dcm_mp_cpusys_top_adb_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_apb_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_cpubiu_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_misc_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_mp0_qdcm_is_on();
+ ret &= dcm_cpccfg_reg_emi_wfifo_is_on();
+ ret &= dcm_mp_cpusys_top_last_cor_idle_dcm_is_on();
+
+ ret &= dcm_mp_cpusys_top_core_stall_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_fcm_stall_dcm_is_on();
+
+ return ret;
+}
+
+bool dcm_set_default(void)
+{
+ dcm_armcore(true);
+ dcm_mcusys(true);
+ dcm_stall(true);
+
+ return check_dcm_state();
+}
diff --git a/plat/mediatek/mt8192/drivers/dcm/mtk_dcm.h b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm.h
new file mode 100644
index 0000000..ee98d0e
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_DCM_H
+#define MTK_DCM_H
+
+#include <stdbool.h>
+
+bool dcm_set_default(void);
+
+#endif /* #ifndef MTK_DCM_H */
diff --git a/plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.c b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.c
new file mode 100644
index 0000000..15a700c
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.c
@@ -0,0 +1,562 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <mtk_dcm_utils.h>
+
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_MASK (BIT(17))
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_MASK (BIT(15) | \
+ BIT(16) | \
+ BIT(17) | \
+ BIT(18) | \
+ BIT(21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG2_MASK (BIT(15) | \
+ BIT(16) | \
+ BIT(17) | \
+ BIT(18))
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_ON (BIT(17))
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_ON (BIT(15) | \
+ BIT(16) | \
+ BIT(17) | \
+ BIT(18) | \
+ BIT(21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG2_ON (BIT(15) | \
+ BIT(16) | \
+ BIT(17) | \
+ BIT(18))
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_OFF ((0x0 << 17))
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_OFF ((0x0 << 15) | \
+ (0x0 << 16) | \
+ (0x0 << 17) | \
+ (0x0 << 18) | \
+ (0x0 << 21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG2_OFF ((0x0 << 15) | \
+ (0x0 << 16) | \
+ (0x0 << 17) | \
+ (0x0 << 18))
+
+bool dcm_mp_cpusys_top_adb_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_ADB_DCM_CFG0) &
+ MP_CPUSYS_TOP_ADB_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_ADB_DCM_REG0_ON);
+ ret &= ((mmio_read_32(MP_ADB_DCM_CFG4) &
+ MP_CPUSYS_TOP_ADB_DCM_REG1_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_ADB_DCM_REG1_ON);
+ ret &= ((mmio_read_32(MCUSYS_DCM_CFG0) &
+ MP_CPUSYS_TOP_ADB_DCM_REG2_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_ADB_DCM_REG2_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_adb_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_adb_dcm'" */
+ mmio_clrsetbits_32(MP_ADB_DCM_CFG0,
+ MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG0_ON);
+ mmio_clrsetbits_32(MP_ADB_DCM_CFG4,
+ MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG1_ON);
+ mmio_clrsetbits_32(MCUSYS_DCM_CFG0,
+ MP_CPUSYS_TOP_ADB_DCM_REG2_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG2_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_adb_dcm'" */
+ mmio_clrsetbits_32(MP_ADB_DCM_CFG0,
+ MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG0_OFF);
+ mmio_clrsetbits_32(MP_ADB_DCM_CFG4,
+ MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG1_OFF);
+ mmio_clrsetbits_32(MCUSYS_DCM_CFG0,
+ MP_CPUSYS_TOP_ADB_DCM_REG2_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG2_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_APB_DCM_REG0_MASK (BIT(5))
+#define MP_CPUSYS_TOP_APB_DCM_REG1_MASK (BIT(8))
+#define MP_CPUSYS_TOP_APB_DCM_REG2_MASK (BIT(16))
+#define MP_CPUSYS_TOP_APB_DCM_REG0_ON (BIT(5))
+#define MP_CPUSYS_TOP_APB_DCM_REG1_ON (BIT(8))
+#define MP_CPUSYS_TOP_APB_DCM_REG2_ON (BIT(16))
+#define MP_CPUSYS_TOP_APB_DCM_REG0_OFF ((0x0 << 5))
+#define MP_CPUSYS_TOP_APB_DCM_REG1_OFF ((0x0 << 8))
+#define MP_CPUSYS_TOP_APB_DCM_REG2_OFF ((0x0 << 16))
+
+bool dcm_mp_cpusys_top_apb_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_MISC_DCM_CFG0) &
+ MP_CPUSYS_TOP_APB_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_APB_DCM_REG0_ON);
+ ret &= ((mmio_read_32(MCUSYS_DCM_CFG0) &
+ MP_CPUSYS_TOP_APB_DCM_REG1_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_APB_DCM_REG1_ON);
+ ret &= ((mmio_read_32(MP0_DCM_CFG0) &
+ MP_CPUSYS_TOP_APB_DCM_REG2_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_APB_DCM_REG2_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_apb_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_apb_dcm'" */
+ mmio_clrsetbits_32(MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG0_ON);
+ mmio_clrsetbits_32(MCUSYS_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG1_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG1_ON);
+ mmio_clrsetbits_32(MP0_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG2_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG2_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_apb_dcm'" */
+ mmio_clrsetbits_32(MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG0_OFF);
+ mmio_clrsetbits_32(MCUSYS_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG1_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG1_OFF);
+ mmio_clrsetbits_32(MP0_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG2_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG2_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK (BIT(11))
+#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON (BIT(11))
+#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_OFF ((0x0 << 11))
+
+bool dcm_mp_cpusys_top_bus_pll_div_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(BUS_PLLDIV_CFG) &
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_bus_pll_div_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_bus_pll_div_dcm'" */
+ mmio_clrsetbits_32(BUS_PLLDIV_CFG,
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_bus_pll_div_dcm'" */
+ mmio_clrsetbits_32(BUS_PLLDIV_CFG,
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK (BIT(0))
+#define MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON (BIT(0))
+#define MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_OFF ((0x0 << 0))
+
+bool dcm_mp_cpusys_top_core_stall_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP0_DCM_CFG7) &
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_core_stall_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_core_stall_dcm'" */
+ mmio_clrsetbits_32(MP0_DCM_CFG7,
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_core_stall_dcm'" */
+ mmio_clrsetbits_32(MP0_DCM_CFG7,
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK ((0xffff << 0))
+#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON ((0xffff << 0))
+#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_OFF ((0x0 << 0))
+
+bool dcm_mp_cpusys_top_cpubiu_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MCSI_DCM0) &
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_cpubiu_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpubiu_dcm'" */
+ mmio_clrsetbits_32(MCSI_DCM0,
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpubiu_dcm'" */
+ mmio_clrsetbits_32(MCSI_DCM0,
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK (BIT(11))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON (BIT(11))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_OFF ((0x0 << 11))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(CPU_PLLDIV_CFG0) &
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_cpu_pll_div_0_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_0_dcm'" */
+ mmio_clrsetbits_32(CPU_PLLDIV_CFG0,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_0_dcm'" */
+ mmio_clrsetbits_32(CPU_PLLDIV_CFG0,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK (BIT(11))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON (BIT(11))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_OFF ((0x0 << 11))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(CPU_PLLDIV_CFG1) &
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_cpu_pll_div_1_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_1_dcm'" */
+ mmio_clrsetbits_32(CPU_PLLDIV_CFG1,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_1_dcm'" */
+ mmio_clrsetbits_32(CPU_PLLDIV_CFG1,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_MASK (BIT(11))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_ON (BIT(11))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_OFF ((0x0 << 11))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_2_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(CPU_PLLDIV_CFG2) &
+ MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_cpu_pll_div_2_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_2_dcm'" */
+ mmio_clrsetbits_32(CPU_PLLDIV_CFG2,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_2_dcm'" */
+ mmio_clrsetbits_32(CPU_PLLDIV_CFG2,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_MASK (BIT(11))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_ON (BIT(11))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_OFF ((0x0 << 11))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_3_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(CPU_PLLDIV_CFG3) &
+ MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_cpu_pll_div_3_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_3_dcm'" */
+ mmio_clrsetbits_32(CPU_PLLDIV_CFG3,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_3_dcm'" */
+ mmio_clrsetbits_32(CPU_PLLDIV_CFG3,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_MASK (BIT(11))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_ON (BIT(11))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_OFF ((0x0 << 11))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_4_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(CPU_PLLDIV_CFG4) &
+ MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_cpu_pll_div_4_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_4_dcm'" */
+ mmio_clrsetbits_32(CPU_PLLDIV_CFG4,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_4_dcm'" */
+ mmio_clrsetbits_32(CPU_PLLDIV_CFG4,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK (BIT(4))
+#define MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON (BIT(4))
+#define MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_OFF ((0x0 << 4))
+
+bool dcm_mp_cpusys_top_fcm_stall_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP0_DCM_CFG7) &
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_fcm_stall_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_fcm_stall_dcm'" */
+ mmio_clrsetbits_32(MP0_DCM_CFG7,
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_fcm_stall_dcm'" */
+ mmio_clrsetbits_32(MP0_DCM_CFG7,
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK ((0x1U << 31))
+#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON ((0x1U << 31))
+#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_OFF ((0x0U << 31))
+
+bool dcm_mp_cpusys_top_last_cor_idle_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(BUS_PLLDIV_CFG) &
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_last_cor_idle_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_last_cor_idle_dcm'" */
+ mmio_clrsetbits_32(BUS_PLLDIV_CFG,
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_last_cor_idle_dcm'" */
+ mmio_clrsetbits_32(BUS_PLLDIV_CFG,
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_MASK (BIT(1) | \
+ BIT(4))
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_ON (BIT(1) | \
+ BIT(4))
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_OFF ((0x0 << 1) | \
+ (0x0 << 4))
+
+bool dcm_mp_cpusys_top_misc_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_MISC_DCM_CFG0) &
+ MP_CPUSYS_TOP_MISC_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_MISC_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_misc_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_misc_dcm'" */
+ mmio_clrsetbits_32(MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_MISC_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_MISC_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_misc_dcm'" */
+ mmio_clrsetbits_32(MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_MISC_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_MISC_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK (BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK (BIT(0) | \
+ BIT(1) | \
+ BIT(2) | \
+ BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_ON (BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG1_ON (BIT(0) | \
+ BIT(1) | \
+ BIT(2) | \
+ BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_OFF ((0x0 << 3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG1_OFF ((0x0 << 0) | \
+ (0x0 << 1) | \
+ (0x0 << 2) | \
+ (0x0 << 3))
+
+bool dcm_mp_cpusys_top_mp0_qdcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_MISC_DCM_CFG0) &
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_MP0_QDCM_REG0_ON);
+ ret &= ((mmio_read_32(MP0_DCM_CFG0) &
+ MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_MP0_QDCM_REG1_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_mp0_qdcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_mp0_qdcm'" */
+ mmio_clrsetbits_32(MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_ON);
+ mmio_clrsetbits_32(MP0_DCM_CFG0,
+ MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK,
+ MP_CPUSYS_TOP_MP0_QDCM_REG1_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_mp0_qdcm'" */
+ mmio_clrsetbits_32(MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_OFF);
+ mmio_clrsetbits_32(MP0_DCM_CFG0,
+ MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK,
+ MP_CPUSYS_TOP_MP0_QDCM_REG1_OFF);
+ }
+}
+
+#define CPCCFG_REG_EMI_WFIFO_REG0_MASK (BIT(0) | \
+ BIT(1) | \
+ BIT(2) | \
+ BIT(3))
+#define CPCCFG_REG_EMI_WFIFO_REG0_ON (BIT(0) | \
+ BIT(1) | \
+ BIT(2) | \
+ BIT(3))
+#define CPCCFG_REG_EMI_WFIFO_REG0_OFF ((0x0 << 0) | \
+ (0x0 << 1) | \
+ (0x0 << 2) | \
+ (0x0 << 3))
+
+bool dcm_cpccfg_reg_emi_wfifo_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(EMI_WFIFO) &
+ CPCCFG_REG_EMI_WFIFO_REG0_MASK) ==
+ (unsigned int) CPCCFG_REG_EMI_WFIFO_REG0_ON);
+
+ return ret;
+}
+
+void dcm_cpccfg_reg_emi_wfifo(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'cpccfg_reg_emi_wfifo'" */
+ mmio_clrsetbits_32(EMI_WFIFO,
+ CPCCFG_REG_EMI_WFIFO_REG0_MASK,
+ CPCCFG_REG_EMI_WFIFO_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'cpccfg_reg_emi_wfifo'" */
+ mmio_clrsetbits_32(EMI_WFIFO,
+ CPCCFG_REG_EMI_WFIFO_REG0_MASK,
+ CPCCFG_REG_EMI_WFIFO_REG0_OFF);
+ }
+}
+
diff --git a/plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.h b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.h
new file mode 100644
index 0000000..1cf7834
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_DCM_UTILS_H
+#define MTK_DCM_UTILS_H
+
+#include <stdbool.h>
+
+#include <mtk_dcm.h>
+#include <platform_def.h>
+
+/* Base */
+#define MP_CPUSYS_TOP_BASE (MCUCFG_BASE + 0x8000)
+#define CPCCFG_REG_BASE (MCUCFG_BASE + 0xA800)
+
+/* Register Definition */
+#define CPU_PLLDIV_CFG0 (MP_CPUSYS_TOP_BASE + 0x22a0)
+#define CPU_PLLDIV_CFG1 (MP_CPUSYS_TOP_BASE + 0x22a4)
+#define CPU_PLLDIV_CFG2 (MP_CPUSYS_TOP_BASE + 0x22a8)
+#define CPU_PLLDIV_CFG3 (MP_CPUSYS_TOP_BASE + 0x22ac)
+#define CPU_PLLDIV_CFG4 (MP_CPUSYS_TOP_BASE + 0x22b0)
+#define BUS_PLLDIV_CFG (MP_CPUSYS_TOP_BASE + 0x22e0)
+#define MCSI_DCM0 (MP_CPUSYS_TOP_BASE + 0x2440)
+#define MP_ADB_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x2500)
+#define MP_ADB_DCM_CFG4 (MP_CPUSYS_TOP_BASE + 0x2510)
+#define MP_MISC_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x2518)
+#define MCUSYS_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x25c0)
+#define EMI_WFIFO (CPCCFG_REG_BASE + 0x100)
+#define MP0_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x4880)
+#define MP0_DCM_CFG7 (MP_CPUSYS_TOP_BASE + 0x489c)
+
+/* MP_CPUSYS_TOP */
+bool dcm_mp_cpusys_top_adb_dcm_is_on(void);
+void dcm_mp_cpusys_top_adb_dcm(bool on);
+bool dcm_mp_cpusys_top_apb_dcm_is_on(void);
+void dcm_mp_cpusys_top_apb_dcm(bool on);
+bool dcm_mp_cpusys_top_bus_pll_div_dcm_is_on(void);
+void dcm_mp_cpusys_top_bus_pll_div_dcm(bool on);
+bool dcm_mp_cpusys_top_core_stall_dcm_is_on(void);
+void dcm_mp_cpusys_top_core_stall_dcm(bool on);
+bool dcm_mp_cpusys_top_cpubiu_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpubiu_dcm(bool on);
+bool dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpu_pll_div_0_dcm(bool on);
+bool dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpu_pll_div_1_dcm(bool on);
+bool dcm_mp_cpusys_top_cpu_pll_div_2_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpu_pll_div_2_dcm(bool on);
+bool dcm_mp_cpusys_top_cpu_pll_div_3_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpu_pll_div_3_dcm(bool on);
+bool dcm_mp_cpusys_top_cpu_pll_div_4_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpu_pll_div_4_dcm(bool on);
+bool dcm_mp_cpusys_top_fcm_stall_dcm_is_on(void);
+void dcm_mp_cpusys_top_fcm_stall_dcm(bool on);
+bool dcm_mp_cpusys_top_last_cor_idle_dcm_is_on(void);
+void dcm_mp_cpusys_top_last_cor_idle_dcm(bool on);
+bool dcm_mp_cpusys_top_misc_dcm_is_on(void);
+void dcm_mp_cpusys_top_misc_dcm(bool on);
+bool dcm_mp_cpusys_top_mp0_qdcm_is_on(void);
+void dcm_mp_cpusys_top_mp0_qdcm(bool on);
+/* CPCCFG_REG */
+bool dcm_cpccfg_reg_emi_wfifo_is_on(void);
+void dcm_cpccfg_reg_emi_wfifo(bool on);
+
+#endif
diff --git a/plat/mediatek/mt8192/drivers/devapc/devapc.c b/plat/mediatek/mt8192/drivers/devapc/devapc.c
new file mode 100644
index 0000000..b11f272
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/devapc/devapc.c
@@ -0,0 +1,2847 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+
+#include <devapc.h>
+#include <mtk_apusys_apc.h>
+
+/* Infra_ao */
+static const struct APC_INFRA_PERI_DOM_16 INFRA_AO_SYS0_Devices[] = {
+
+/* 0 */
+DAPC_INFRA_AO_SYS0_ATTR("MFG_S_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("MFG_S_S-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("MFG_S_S-2",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("MFG_S_S-3",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("MFG_S_S-4",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("MFG_S_S-5",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("MFG_S_S-6",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("MFG_S_S-7",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("MFG_S_S-8",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("APU_S_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 10 */
+DAPC_INFRA_AO_SYS0_ATTR("APU_S_S-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("APU_S_S-2",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("APU_S_S-3",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("APU_S_S-4",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("APU_S_S-5",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("MCUSYS_CFGREG_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("MCUSYS_CFGREG_APB_S-1",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("MCUSYS_CFGREG_APB_S-2",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("MCUSYS_CFGREG_APB_S-3",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("MCUSYS_CFGREG_APB_S-4",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 20 */
+DAPC_INFRA_AO_SYS0_ATTR("L3C_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("L3C_S-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS0_ATTR("PCIE_AXI_S",
+ NO_PROTECTION, NO_PROTECTION, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+};
+
+static const struct APC_INFRA_PERI_DOM_4 INFRA_AO_SYS1_Devices[] = {
+
+/* 0 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-2",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-3",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-4",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-5",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-6",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-7",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-8",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-9",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 10 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-10",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-11",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-12",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-13",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-14",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-15",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-16",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-17",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-18",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-19",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 20 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-20",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-21",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-22",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-23",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-24",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-25",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-26",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-27",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-28",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-29",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 30 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-30",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-31",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-32",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-33",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-34",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-35",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-36",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-37",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-38",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-39",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 40 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-100",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-101",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-102",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-103",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-104",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-105",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-106",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-107",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-108",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-109",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 50 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-110",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-111",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-112",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-113",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-114",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-115",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-116",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-117",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-118",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-119",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 60 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-120",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-121",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-122",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-123",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-124",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-125",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-126",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-127",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-128",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-129",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 70 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-130",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-131",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-132",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-133",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-134",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-135",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-136",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-137",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-138",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-139",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 80 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-140",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-141",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-142",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-143",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-200",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, NO_PROTECTION),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-201",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, NO_PROTECTION),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-202",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-203",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, NO_PROTECTION),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-204",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-205",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 90 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-206",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-207",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-300",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-301",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-302",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, NO_PROTECTION),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-303",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-304",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-305",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-306",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-307",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 100 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-400",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-401",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-402",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-403",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-404",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-405",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-406",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-407",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-408",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-409",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 110 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-410",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-411",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-412",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-413",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-414",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-415",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-416",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-417",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-418",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-419",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 120 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-420",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-421",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-422",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-423",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-424",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-425",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-426",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-427",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-428",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-429",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 130 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-430",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-431",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-432",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-433",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-434",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-435",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-436",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-437",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-438",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-439",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 140 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-440",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-441",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-442",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-443",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-444",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-445",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-446",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-447",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-448",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-449",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 150 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-450",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-451",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-452",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-453",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-454",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-455",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-456",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-457",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-458",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-459",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 160 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-460",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-461",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-462",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-463",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-464",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-465",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-466",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-467",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-468",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-469",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 170 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-470",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-471",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-472",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-473",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-474",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-475",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-476",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-477",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-478",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-479",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 180 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-480",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-481",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-482",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-483",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-484",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-485",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-486",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-487",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-488",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-489",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 190 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-490",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-491",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-492",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-493",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-494",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-495",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-496",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-497",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-498",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-499",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 200 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-500",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-501",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-502",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-503",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-504",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-505",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-506",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-507",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-508",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-509",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 210 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-510",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-511",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-512",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-513",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-514",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-515",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-516",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-517",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-518",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-519",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 220 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-520",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-521",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-522",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-523",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-524",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-525",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-526",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-527",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-528",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-529",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 230 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-530",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-531",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-532",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-533",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-534",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-535",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-536",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-537",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-538",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-539",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 240 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-540",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-541",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-542",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-543",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-544",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-545",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-546",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-547",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-548",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-549",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 250 */
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-550",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-551",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-552",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-553",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-554",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS1_ATTR("MM_S_S-555",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+};
+
+static const struct APC_INFRA_PERI_DOM_4 INFRA_AO_SYS2_Devices[] = {
+
+/* 0 */
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-556",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-557",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-558",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-559",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-560",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-561",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-562",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-563",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-564",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-565",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 10 */
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-566",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-567",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-568",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-569",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-570",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-571",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-572",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-573",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-574",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-575",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 20 */
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-576",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-577",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-578",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-579",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-580",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-581",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-582",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-583",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-584",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-585",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 30 */
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-586",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-587",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-588",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-589",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-590",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-591",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-592",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-593",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-594",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-595",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 40 */
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-600",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-601",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-602",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-603",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-604",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-605",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-606",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-607",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-608",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-609",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 50 */
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-610",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-611",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-700",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-701",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-702",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-703",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-704",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-705",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-706",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-707",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 60 */
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-708",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-709",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-710",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-711",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-712",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-713",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-714",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-715",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-716",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_INFRA_AO_SYS2_ATTR("MM_S_S-717",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+};
+
+/* Peri_ao */
+static const struct APC_INFRA_PERI_DOM_16 PERI_AO_SYS0_Devices[] = {
+
+/* 0 */
+DAPC_PERI_AO_SYS0_ATTR("SPM_APB_S",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("SPM_APB_S-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("SPM_APB_S-2",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("SPM_APB_S-3",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("SPM_APB_S-4",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("APMIXEDSYS_APB_S",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, NO_PROTECTION,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("APMIXEDSYS_APB_S-1",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("TOPCKGEN_APB_S",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, NO_PROTECTION,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("INFRACFG_AO_APB_S",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("INFRACFG_AO_MEM_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 10 */
+DAPC_PERI_AO_SYS0_ATTR("PERICFG_AO_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("GPIO_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, NO_PROTECTION,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("TOPRGU_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("RESERVED_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DEVICE_APC_INFRA_AO_APB_S",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("BCRM_INFRA_AO_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DEBUG_CTRL_INFRA_AO_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DEVICE_APC_PERI_AO_APB_S",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("BCRM_PERI_AO_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DEBUG_CTRL_PERI_AO_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 20 */
+DAPC_PERI_AO_SYS0_ATTR("AP_CIRQ_EINT_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("PMIC_WRAP_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DEVICE_APC_AO_MM_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("KP_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("TOP_MISC_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DVFSRC_APB_S",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("MBIST_AO_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DPMAIF_AO_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DEVICE_MPU_AO_APB_S",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("SYS_TIMER_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 30 */
+DAPC_PERI_AO_SYS0_ATTR("MODEM_TEMP_SHARE_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DEVICE_APC_AO_MD_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("PMIF1_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("PMICSPI_MST_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("TIA_APB_S",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("TOPCKGEN_INFRA_CFG_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRM_DEBUG_TOP_APB_S",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("PWR_MD32_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("PWR_MD32_S-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("PWR_MD32_S-2",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 40 */
+DAPC_PERI_AO_SYS0_ATTR("PWR_MD32_S-3",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("PWR_MD32_S-4",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("PWR_MD32_S-5",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("PWR_MD32_S-6",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("PWR_MD32_S-7",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("PWR_MD32_S-8",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("PWR_MD32_S-9",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("PWR_MD32_S-10",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("AUDIO_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("AUDIO_S-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 50 */
+DAPC_PERI_AO_SYS0_ATTR("SSUSB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("SSUSB_S-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("SSUSB_S-2",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("UFS_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("UFS_S-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("UFS_S-2",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("UFS_S-3",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DEBUGSYS_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_MD32_S0_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_MD32_S0_APB_S-1",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 60 */
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_MD32_S1_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_MD32_S1_APB_S-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("NOR_AXI_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("PCIE_AHB_S",
+ NO_PROTECTION, NO_PROTECTION, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH0_TOP0_APB_S",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH0_TOP1_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH0_TOP2_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH0_TOP3_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH0_TOP4_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH0_TOP5_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 70 */
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH0_TOP6_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH1_TOP0_APB_S",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH1_TOP1_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH1_TOP2_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH1_TOP3_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH1_TOP4_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH1_TOP5_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH1_TOP6_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH2_TOP0_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH2_TOP1_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 80 */
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH2_TOP2_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH2_TOP3_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH2_TOP4_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH2_TOP5_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH2_TOP6_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH3_TOP0_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH3_TOP1_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH3_TOP2_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH3_TOP3_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH3_TOP4_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 90 */
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH3_TOP5_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DRAMC_CH3_TOP6_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("CCIF2_AP_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("CCIF2_MD_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("CCIF3_AP_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("CCIF3_MD_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("CCIF4_AP_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("CCIF4_MD_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("INFRA_BUS_TRACE_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("CCIF5_AP_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 100 */
+DAPC_PERI_AO_SYS0_ATTR("CCIF5_MD_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("SSC_INFRA_APB0_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("SSC_INFRA_APB1_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("SSC_INFRA_APB2_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS0_ATTR("DEVICE_MPU_ACP_APB_S",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+};
+
+static const struct APC_INFRA_PERI_DOM_8 PERI_AO_SYS1_Devices[] = {
+
+/* 0 */
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-2",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-3",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-4",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-5",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-6",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-7",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-8",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-9",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 10 */
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-10",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-11",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-12",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-13",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-14",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-15",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-16",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-17",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-18",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-19",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 20 */
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-20",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-21",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("TINSYS_S-22",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-2",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-3",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-4",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-5",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-6",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 30 */
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-7",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-8",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-9",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-10",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-11",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-12",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-13",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-14",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-15",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-16",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 40 */
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-17",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-18",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-19",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-20",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-21",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-22",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-23",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-24",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-25",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-26",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 50 */
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-27",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-28",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-29",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-30",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-31",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-32",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-33",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-34",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-35",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-36",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 60 */
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-37",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-38",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-39",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-40",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-41",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO_SYS1_ATTR("MD_AP_S-42",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+};
+
+static const struct APC_INFRA_PERI_DOM_4 PERI_AO_SYS2_Devices[] = {
+
+/* 0 */
+DAPC_PERI_AO_SYS2_ATTR("CONN_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+};
+
+/* Peri_ao2 */
+static const struct APC_INFRA_PERI_DOM_16 PERI_AO2_SYS0_Devices[] = {
+
+/* 0 */
+DAPC_PERI_AO2_SYS0_ATTR("EFUSE_DEBUG_AO_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("APXGPT_APB_S",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("SEJ_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("AES_TOP0_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("SECURITY_AO_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("DEVICE_APC_PERI_AO2_APB_S",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BCRM_PERI_AO2_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("DEBUG_CTRL_PERI_AO2_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("SPMI_MST_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("DEBUG_CTRL_FMEM_AO_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 10 */
+DAPC_PERI_AO2_SYS0_ATTR("BCRM_FMEM_AO_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("DEVICE_APC_FMEM_AO_APB_S",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("PWM_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("GCE_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("GCE_APB_S-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("GCE_APB_S-2",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("GCE_APB_S-3",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("DPMAIF_PDN_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("DPMAIF_PDN_APB_S-1",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("DPMAIF_PDN_APB_S-2",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 20 */
+DAPC_PERI_AO2_SYS0_ATTR("DPMAIF_PDN_APB_S-3",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_APB0_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_APB1_S",
+ NO_PROTECTION, FORBIDDEN, SEC_RW_NS_R, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_APB2_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_APB3_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_APB4_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_APB5_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_APB6_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_APB7_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_APB8_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 30 */
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_APB9_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_APB10_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_APB11_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_APB12_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_APB13_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_APB14_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_APB15_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_WEST_APB0_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_WEST_APB1_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_WEST_APB2_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 40 */
+DAPC_PERI_AO2_SYS0_ATTR("BND_WEST_APB3_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_WEST_APB4_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_WEST_APB5_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_WEST_APB6_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_WEST_APB7_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_NORTH_APB0_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_NORTH_APB1_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_NORTH_APB2_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_NORTH_APB3_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_NORTH_APB4_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 50 */
+DAPC_PERI_AO2_SYS0_ATTR("BND_NORTH_APB5_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_NORTH_APB6_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_NORTH_APB7_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_NORTH_APB8_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_NORTH_APB9_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_NORTH_APB10_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_NORTH_APB11_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_NORTH_APB12_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_NORTH_APB13_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_NORTH_APB14_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 60 */
+DAPC_PERI_AO2_SYS0_ATTR("BND_NORTH_APB15_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_SOUTH_APB0_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_SOUTH_APB1_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_SOUTH_APB2_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_SOUTH_APB3_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_SOUTH_APB4_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_SOUTH_APB5_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_SOUTH_APB6_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_SOUTH_APB7_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_SOUTH_APB8_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 70 */
+DAPC_PERI_AO2_SYS0_ATTR("BND_SOUTH_APB9_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_SOUTH_APB10_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_SOUTH_APB11_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_SOUTH_APB12_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_SOUTH_APB13_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_SOUTH_APB14_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_SOUTH_APB15_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_NORTH_APB0_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_NORTH_APB1_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_NORTH_APB2_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 80 */
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_NORTH_APB3_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_NORTH_APB4_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_NORTH_APB5_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_NORTH_APB6_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BND_EAST_NORTH_APB7_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("SYS_CIRQ_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("EFUSE_DEBUG_PDN_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("DEVICE_APC_INFRA_PDN_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("DEBUG_TRACKER_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("CCIF0_AP_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 90 */
+DAPC_PERI_AO2_SYS0_ATTR("CCIF0_MD_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("CCIF1_AP_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("CCIF1_MD_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("MBIST_PDN_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("INFRACFG_PDN_APB_S",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("TRNG_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("DX_CC_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("CQ_DMA_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("SRAMROM_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("INFRACFG_MEM_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 100 */
+DAPC_PERI_AO2_SYS0_ATTR("RESERVED_DVFS_PROC_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("SYS_CIRQ1_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("SYS_CIRQ2_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("DEBUG_TRACKER_APB1_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("EMI_APB_S",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("EMI_MPU_APB_S",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("DEVICE_MPU_PDN_APB_S",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("APDMA_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("DEBUG_TRACKER_APB2_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BCRM_INFRA_PDN_APB_S",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 110 */
+DAPC_PERI_AO2_SYS0_ATTR("BCRM_PERI_PDN_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BCRM_PERI_PDN2_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("DEVICE_APC_PERI_PDN_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("DEVICE_APC_PERI_PDN2_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_AO2_SYS0_ATTR("BCRM_FMEM_PDN_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+};
+
+/* Peri_par_ao */
+static const struct APC_INFRA_PERI_DOM_16 PERI_PAR_AO_SYS0_Devices[] = {
+
+/* 0 */
+DAPC_PERI_PAR_AO_SYS0_ATTR("AUXADC_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("UART0_APB_S",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("UART1_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("UART2_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("IIC_P2P_REMAP_APB4_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("SPI0_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("PTP_THERM_CTRL_APB_S",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("BTIF_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("DISP_PWM_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("SPI1_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 10 */
+DAPC_PERI_PAR_AO_SYS0_ATTR("SPI2_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("SPI3_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("IIC_P2P_REMAP_APB0_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("IIC_P2P_REMAP_APB1_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("SPI4_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("SPI5_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("IIC_P2P_REMAP_APB2_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("IIC_P2P_REMAP_APB3_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("SPI6_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("SPI7_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+/* 20 */
+DAPC_PERI_PAR_AO_SYS0_ATTR("BCRM_PERI_PAR_PDN_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("DEVICE_APC_PERI_PAR_PDN_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("PTP_THERM_CTRL2_APB_S",
+ NO_PROTECTION, FORBIDDEN, NO_PROTECTION, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("NOR_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("DEVICE_APC_PERI_PAR_AO_APB_S",
+ SEC_RW_ONLY, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("DEBUG_CTRL_PERI_PAR_AO_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+DAPC_PERI_PAR_AO_SYS0_ATTR("BCRM_PERI_PAR_AO_APB_S",
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN),
+
+};
+
+static void set_module_apc(enum DEVAPC_SLAVE_TYPE slave_type,
+ uint32_t module, enum DOMAIN_ID domain_id,
+ enum DEVAPC_PERM_TYPE perm)
+{
+ uint32_t apc_register_index;
+ uint32_t apc_set_index;
+ uintptr_t base = 0, reg;
+ uint32_t clr_bit;
+ uint32_t set_bit;
+
+ apc_register_index = module / MOD_NO_IN_1_DEVAPC;
+ apc_set_index = module % MOD_NO_IN_1_DEVAPC;
+
+ clr_bit = (0x3U << (apc_set_index * 2));
+ set_bit = (uint32_t)perm << (apc_set_index * 2);
+
+ /* infra_ao */
+ if ((slave_type == SLAVE_TYPE_INFRA_AO_SYS0) &&
+ (module < SLAVE_NUM_INFRA_AO_SYS0) &&
+ (domain_id < (uint32_t)DOM_NUM_INFRA_AO_SYS0)) {
+ base = DEVAPC_INFRA_AO_SYS0_D0_APC_0;
+
+ } else if ((slave_type == SLAVE_TYPE_INFRA_AO_SYS1) &&
+ (module < SLAVE_NUM_INFRA_AO_SYS1) &&
+ (domain_id < (uint32_t)DOM_NUM_INFRA_AO_SYS1)) {
+ base = DEVAPC_INFRA_AO_SYS1_D0_APC_0;
+
+ } else if ((slave_type == SLAVE_TYPE_INFRA_AO_SYS2) &&
+ (module < SLAVE_NUM_INFRA_AO_SYS2) &&
+ (domain_id < (uint32_t)DOM_NUM_INFRA_AO_SYS2)) {
+ base = DEVAPC_INFRA_AO_SYS2_D0_APC_0;
+ /* peri_ao */
+ } else if ((slave_type == SLAVE_TYPE_PERI_AO_SYS0) &&
+ (module < SLAVE_NUM_PERI_AO_SYS0) &&
+ (domain_id < (uint32_t)DOM_NUM_PERI_AO_SYS0)) {
+ base = DEVAPC_PERI_AO_SYS0_D0_APC_0;
+
+ } else if ((slave_type == SLAVE_TYPE_PERI_AO_SYS1) &&
+ (module < SLAVE_NUM_PERI_AO_SYS1) &&
+ (domain_id <= (uint32_t)DOM_NUM_PERI_AO_SYS1)) {
+ base = DEVAPC_PERI_AO_SYS1_D0_APC_0;
+
+ } else if ((slave_type == SLAVE_TYPE_PERI_AO_SYS2) &&
+ (module < SLAVE_NUM_PERI_AO_SYS2) &&
+ (domain_id < (uint32_t)DOM_NUM_PERI_AO_SYS2)) {
+ base = DEVAPC_PERI_AO_SYS2_D0_APC_0;
+ /* peri_ao2 */
+ } else if ((slave_type == SLAVE_TYPE_PERI_AO2_SYS0) &&
+ (module < SLAVE_NUM_PERI_AO2_SYS0) &&
+ (domain_id < (uint32_t)DOM_NUM_PERI_AO2_SYS0)) {
+ base = DEVAPC_PERI_AO2_SYS0_D0_APC_0;
+
+ /* peri_par_ao */
+ } else if ((slave_type == SLAVE_TYPE_PERI_PAR_AO_SYS0) &&
+ (module < SLAVE_NUM_PERI_PAR_AO_SYS0) &&
+ (domain_id < (uint32_t)DOM_NUM_PERI_PAR_AO_SYS0)) {
+ base = DEVAPC_PERI_PAR_AO_SYS0_D0_APC_0;
+
+ } else {
+ ERROR("[DEVAPC] %s: %s, %s:0x%x, %s:0x%x, %s:0x%x\n",
+ __func__, "out of boundary",
+ "slave_type", slave_type,
+ "module", module,
+ "domain_id", domain_id);
+ }
+
+ if (base != 0U) {
+ reg = base + domain_id * 0x40 + apc_register_index * 4;
+ mmio_clrsetbits_32(reg, clr_bit, set_bit);
+ }
+}
+
+static void dump_infra_ao_apc(void)
+{
+ int reg_num;
+ int d, i;
+
+ reg_num = (SLAVE_NUM_INFRA_AO_SYS0 - 1) / MOD_NO_IN_1_DEVAPC;
+ for (d = 0; d < DOM_NUM_INFRA_AO_SYS0; d++) {
+ for (i = 0; i <= reg_num; i++) {
+ INFO("[DEVAPC] (INFRA_AO_SYS0)D%d_APC_%d: 0x%x\n",
+ d, i, devapc_readl(
+ DEVAPC_INFRA_AO_SYS0_D0_APC_0 +
+ d * 0x40 + i * 4)
+ );
+ }
+ }
+
+ reg_num = (SLAVE_NUM_INFRA_AO_SYS1 - 1) / MOD_NO_IN_1_DEVAPC;
+ for (d = 0; d < DOM_NUM_INFRA_AO_SYS1; d++) {
+ for (i = 0; i <= reg_num; i++) {
+ INFO("[DEVAPC] (INFRA_AO_SYS1)D%d_APC_%d: 0x%x\n",
+ d, i, devapc_readl(
+ DEVAPC_INFRA_AO_SYS1_D0_APC_0 +
+ d * 0x40 + i * 4)
+ );
+ }
+ }
+
+ reg_num = (SLAVE_NUM_INFRA_AO_SYS2 - 1) / MOD_NO_IN_1_DEVAPC;
+ for (d = 0; d < DOM_NUM_INFRA_AO_SYS2; d++) {
+ for (i = 0; i <= reg_num; i++) {
+ INFO("[DEVAPC] (INFRA_AO_SYS2)D%d_APC_%d: 0x%x\n",
+ d, i, devapc_readl(
+ DEVAPC_INFRA_AO_SYS2_D0_APC_0 +
+ d * 0x40 + i * 4)
+ );
+ }
+ }
+
+ INFO("[DEVAPC] (INFRA_AO)MAS_SEC_0: 0x%x\n",
+ devapc_readl(DEVAPC_INFRA_AO_MAS_SEC_0));
+}
+
+static void dump_peri_ao_apc(void)
+{
+ int reg_num;
+ int d, i;
+
+ reg_num = (SLAVE_NUM_PERI_AO_SYS0 - 1) / MOD_NO_IN_1_DEVAPC;
+ for (d = 0; d < DOM_NUM_PERI_AO_SYS0; d++) {
+ for (i = 0; i <= reg_num; i++) {
+ INFO("[DEVAPC] (PERI_AO_SYS0)D%d_APC_%d: 0x%x\n",
+ d, i, devapc_readl(
+ DEVAPC_PERI_AO_SYS0_D0_APC_0 +
+ d * 0x40 + i * 4)
+ );
+ }
+ }
+
+ reg_num = (SLAVE_NUM_PERI_AO_SYS1 - 1) / MOD_NO_IN_1_DEVAPC;
+ for (d = 0; d < DOM_NUM_PERI_AO_SYS1; d++) {
+ for (i = 0; i <= reg_num; i++) {
+ INFO("[DEVAPC] (PERI_AO_SYS1)D%d_APC_%d: 0x%x\n",
+ d, i, devapc_readl(
+ DEVAPC_PERI_AO_SYS1_D0_APC_0 +
+ d * 0x40 + i * 4)
+ );
+ }
+ }
+
+ reg_num = (SLAVE_NUM_PERI_AO_SYS2 - 1) / MOD_NO_IN_1_DEVAPC;
+ for (d = 0; d < DOM_NUM_PERI_AO_SYS2; d++) {
+ for (i = 0; i <= reg_num; i++) {
+ INFO("[DEVAPC] (PERI_AO_SYS2)D%d_APC_%d: 0x%x\n",
+ d, i, devapc_readl(
+ DEVAPC_PERI_AO_SYS2_D0_APC_0 +
+ d * 0x40 + i * 4)
+ );
+ }
+ }
+
+ INFO("[DEVAPC] (PERI_AO)MAS_SEC_0: 0x%x\n",
+ devapc_readl(DEVAPC_PERI_AO_MAS_SEC_0));
+}
+
+static void dump_peri_ao2_apc(void)
+{
+ int reg_num;
+ int d, i;
+
+ reg_num = (SLAVE_NUM_PERI_AO2_SYS0 - 1) / MOD_NO_IN_1_DEVAPC;
+ for (d = 0; d < DOM_NUM_PERI_AO2_SYS0; d++) {
+ for (i = 0; i <= reg_num; i++) {
+ INFO("[DEVAPC] (PERI_AO2_SYS0)D%d_APC_%d: 0x%x\n",
+ d, i, devapc_readl(
+ DEVAPC_PERI_AO2_SYS0_D0_APC_0 +
+ d * 0x40 + i * 4)
+ );
+ }
+ }
+}
+
+static void dump_peri_par_ao_apc(void)
+{
+ int reg_num;
+ int d, i;
+
+ reg_num = (SLAVE_NUM_PERI_PAR_AO_SYS0 - 1) / MOD_NO_IN_1_DEVAPC;
+ for (d = 0; d < DOM_NUM_PERI_PAR_AO_SYS0; d++) {
+ for (i = 0; i <= reg_num; i++) {
+ INFO("[DEVAPC] (PERI_PAR_AO_SYS0)D%d_APC_%d: 0x%x\n",
+ d, i, devapc_readl(
+ DEVAPC_PERI_PAR_AO_SYS0_D0_APC_0 +
+ d * 0x40 + i * 4)
+ );
+ }
+ }
+
+ INFO("[DEVAPC] (PERI_PAR_AO)MAS_SEC_0: 0x%x\n",
+ devapc_readl(DEVAPC_PERI_PAR_AO_MAS_SEC_0));
+}
+
+static void set_infra_ao_apc(void)
+{
+ uint32_t infra_ao_size;
+ uint32_t i;
+
+ infra_ao_size = ARRAY_SIZE(INFRA_AO_SYS0_Devices);
+
+ for (i = 0; i < infra_ao_size; i++) {
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS0, i, DOMAIN_0,
+ INFRA_AO_SYS0_Devices[i].d0_permission); /* APMCU */
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS0, i, DOMAIN_1,
+ INFRA_AO_SYS0_Devices[i].d1_permission);
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS0, i, DOMAIN_2,
+ INFRA_AO_SYS0_Devices[i].d2_permission);
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS0, i, DOMAIN_3,
+ INFRA_AO_SYS0_Devices[i].d3_permission);
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS0, i, DOMAIN_4,
+ INFRA_AO_SYS0_Devices[i].d4_permission);
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS0, i, DOMAIN_5,
+ INFRA_AO_SYS0_Devices[i].d5_permission);
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS0, i, DOMAIN_6,
+ INFRA_AO_SYS0_Devices[i].d6_permission);
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS0, i, DOMAIN_7,
+ INFRA_AO_SYS0_Devices[i].d7_permission);
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS0, i, DOMAIN_8,
+ INFRA_AO_SYS0_Devices[i].d8_permission);
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS0, i, DOMAIN_9,
+ INFRA_AO_SYS0_Devices[i].d9_permission);
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS0, i, DOMAIN_10,
+ INFRA_AO_SYS0_Devices[i].d10_permission);
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS0, i, DOMAIN_11,
+ INFRA_AO_SYS0_Devices[i].d11_permission);
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS0, i, DOMAIN_12,
+ INFRA_AO_SYS0_Devices[i].d12_permission);
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS0, i, DOMAIN_13,
+ INFRA_AO_SYS0_Devices[i].d13_permission);
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS0, i, DOMAIN_14,
+ INFRA_AO_SYS0_Devices[i].d14_permission);
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS0, i, DOMAIN_15,
+ INFRA_AO_SYS0_Devices[i].d15_permission);
+ }
+
+ infra_ao_size = ARRAY_SIZE(INFRA_AO_SYS1_Devices);
+
+ for (i = 0; i < infra_ao_size; i++) {
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS1, i, DOMAIN_0,
+ INFRA_AO_SYS1_Devices[i].d0_permission); /* APMCU */
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS1, i, DOMAIN_1,
+ INFRA_AO_SYS1_Devices[i].d1_permission);
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS1, i, DOMAIN_2,
+ INFRA_AO_SYS1_Devices[i].d2_permission);
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS1, i, DOMAIN_3,
+ INFRA_AO_SYS1_Devices[i].d3_permission);
+ }
+
+ infra_ao_size = ARRAY_SIZE(INFRA_AO_SYS2_Devices);
+
+ for (i = 0; i < infra_ao_size; i++) {
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS2, i, DOMAIN_0,
+ INFRA_AO_SYS2_Devices[i].d0_permission); /* APMCU */
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS2, i, DOMAIN_1,
+ INFRA_AO_SYS2_Devices[i].d1_permission);
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS2, i, DOMAIN_2,
+ INFRA_AO_SYS2_Devices[i].d2_permission);
+ set_module_apc(SLAVE_TYPE_INFRA_AO_SYS2, i, DOMAIN_3,
+ INFRA_AO_SYS2_Devices[i].d3_permission);
+ }
+}
+
+static void set_peri_ao_apc(void)
+{
+ uint32_t peri_ao_size;
+ uint32_t i;
+
+ peri_ao_size = ARRAY_SIZE(PERI_AO_SYS0_Devices);
+
+ for (i = 0; i < peri_ao_size; i++) {
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS0, i, DOMAIN_0,
+ PERI_AO_SYS0_Devices[i].d0_permission); /* APMCU */
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS0, i, DOMAIN_1,
+ PERI_AO_SYS0_Devices[i].d1_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS0, i, DOMAIN_2,
+ PERI_AO_SYS0_Devices[i].d2_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS0, i, DOMAIN_3,
+ PERI_AO_SYS0_Devices[i].d3_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS0, i, DOMAIN_4,
+ PERI_AO_SYS0_Devices[i].d4_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS0, i, DOMAIN_5,
+ PERI_AO_SYS0_Devices[i].d5_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS0, i, DOMAIN_6,
+ PERI_AO_SYS0_Devices[i].d6_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS0, i, DOMAIN_7,
+ PERI_AO_SYS0_Devices[i].d7_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS0, i, DOMAIN_8,
+ PERI_AO_SYS0_Devices[i].d8_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS0, i, DOMAIN_9,
+ PERI_AO_SYS0_Devices[i].d9_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS0, i, DOMAIN_10,
+ PERI_AO_SYS0_Devices[i].d10_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS0, i, DOMAIN_11,
+ PERI_AO_SYS0_Devices[i].d11_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS0, i, DOMAIN_12,
+ PERI_AO_SYS0_Devices[i].d12_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS0, i, DOMAIN_13,
+ PERI_AO_SYS0_Devices[i].d13_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS0, i, DOMAIN_14,
+ PERI_AO_SYS0_Devices[i].d14_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS0, i, DOMAIN_15,
+ PERI_AO_SYS0_Devices[i].d15_permission);
+ }
+
+ peri_ao_size = ARRAY_SIZE(PERI_AO_SYS1_Devices);
+
+ for (i = 0; i < peri_ao_size; i++) {
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS1, i, DOMAIN_0,
+ PERI_AO_SYS1_Devices[i].d0_permission); /* APMCU */
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS1, i, DOMAIN_1,
+ PERI_AO_SYS1_Devices[i].d1_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS1, i, DOMAIN_2,
+ PERI_AO_SYS1_Devices[i].d2_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS1, i, DOMAIN_3,
+ PERI_AO_SYS1_Devices[i].d3_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS1, i, DOMAIN_4,
+ PERI_AO_SYS1_Devices[i].d4_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS1, i, DOMAIN_5,
+ PERI_AO_SYS1_Devices[i].d5_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS1, i, DOMAIN_6,
+ PERI_AO_SYS1_Devices[i].d6_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS1, i, DOMAIN_7,
+ PERI_AO_SYS1_Devices[i].d7_permission);
+ }
+
+ peri_ao_size = ARRAY_SIZE(PERI_AO_SYS2_Devices);
+
+ for (i = 0; i < peri_ao_size; i++) {
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS2, i, DOMAIN_0,
+ PERI_AO_SYS2_Devices[i].d0_permission); /* APMCU */
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS2, i, DOMAIN_1,
+ PERI_AO_SYS2_Devices[i].d1_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS2, i, DOMAIN_2,
+ PERI_AO_SYS2_Devices[i].d2_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS2, i, DOMAIN_3,
+ PERI_AO_SYS2_Devices[i].d3_permission);
+ }
+}
+
+static void set_peri_ao2_apc(void)
+{
+ uint32_t peri_ao2_size;
+ uint32_t i;
+
+ peri_ao2_size = ARRAY_SIZE(PERI_AO2_SYS0_Devices);
+
+ for (i = 0; i < peri_ao2_size; i++) {
+ set_module_apc(SLAVE_TYPE_PERI_AO2_SYS0, i, DOMAIN_0,
+ PERI_AO2_SYS0_Devices[i].d0_permission); /* APMCU */
+ set_module_apc(SLAVE_TYPE_PERI_AO2_SYS0, i, DOMAIN_1,
+ PERI_AO2_SYS0_Devices[i].d1_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO2_SYS0, i, DOMAIN_2,
+ PERI_AO2_SYS0_Devices[i].d2_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO2_SYS0, i, DOMAIN_3,
+ PERI_AO2_SYS0_Devices[i].d3_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO2_SYS0, i, DOMAIN_4,
+ PERI_AO2_SYS0_Devices[i].d4_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO2_SYS0, i, DOMAIN_5,
+ PERI_AO2_SYS0_Devices[i].d5_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO2_SYS0, i, DOMAIN_6,
+ PERI_AO2_SYS0_Devices[i].d6_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO2_SYS0, i, DOMAIN_7,
+ PERI_AO2_SYS0_Devices[i].d7_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO2_SYS0, i, DOMAIN_8,
+ PERI_AO2_SYS0_Devices[i].d8_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO2_SYS0, i, DOMAIN_9,
+ PERI_AO2_SYS0_Devices[i].d9_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO2_SYS0, i, DOMAIN_10,
+ PERI_AO2_SYS0_Devices[i].d10_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO2_SYS0, i, DOMAIN_11,
+ PERI_AO2_SYS0_Devices[i].d11_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO2_SYS0, i, DOMAIN_12,
+ PERI_AO2_SYS0_Devices[i].d12_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO2_SYS0, i, DOMAIN_13,
+ PERI_AO2_SYS0_Devices[i].d13_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO2_SYS0, i, DOMAIN_14,
+ PERI_AO2_SYS0_Devices[i].d14_permission);
+ set_module_apc(SLAVE_TYPE_PERI_AO2_SYS0, i, DOMAIN_15,
+ PERI_AO2_SYS0_Devices[i].d15_permission);
+ }
+}
+
+static void set_peri_par_ao_apc(void)
+{
+ uint32_t peri_par_ao_size;
+ uint32_t i;
+
+ peri_par_ao_size = ARRAY_SIZE(PERI_PAR_AO_SYS0_Devices);
+
+ for (i = 0; i < peri_par_ao_size; i++) {
+ set_module_apc(SLAVE_TYPE_PERI_PAR_AO_SYS0, i, DOMAIN_0,
+ PERI_PAR_AO_SYS0_Devices[i].d0_permission); /* APMCU */
+ set_module_apc(SLAVE_TYPE_PERI_PAR_AO_SYS0, i, DOMAIN_1,
+ PERI_PAR_AO_SYS0_Devices[i].d1_permission);
+ set_module_apc(SLAVE_TYPE_PERI_PAR_AO_SYS0, i, DOMAIN_2,
+ PERI_PAR_AO_SYS0_Devices[i].d2_permission);
+ set_module_apc(SLAVE_TYPE_PERI_PAR_AO_SYS0, i, DOMAIN_3,
+ PERI_PAR_AO_SYS0_Devices[i].d3_permission);
+ set_module_apc(SLAVE_TYPE_PERI_PAR_AO_SYS0, i, DOMAIN_4,
+ PERI_PAR_AO_SYS0_Devices[i].d4_permission);
+ set_module_apc(SLAVE_TYPE_PERI_PAR_AO_SYS0, i, DOMAIN_5,
+ PERI_PAR_AO_SYS0_Devices[i].d5_permission);
+ set_module_apc(SLAVE_TYPE_PERI_PAR_AO_SYS0, i, DOMAIN_6,
+ PERI_PAR_AO_SYS0_Devices[i].d6_permission);
+ set_module_apc(SLAVE_TYPE_PERI_PAR_AO_SYS0, i, DOMAIN_7,
+ PERI_PAR_AO_SYS0_Devices[i].d7_permission);
+ set_module_apc(SLAVE_TYPE_PERI_PAR_AO_SYS0, i, DOMAIN_8,
+ PERI_PAR_AO_SYS0_Devices[i].d8_permission);
+ set_module_apc(SLAVE_TYPE_PERI_PAR_AO_SYS0, i, DOMAIN_9,
+ PERI_PAR_AO_SYS0_Devices[i].d9_permission);
+ set_module_apc(SLAVE_TYPE_PERI_PAR_AO_SYS0, i, DOMAIN_10,
+ PERI_PAR_AO_SYS0_Devices[i].d10_permission);
+ set_module_apc(SLAVE_TYPE_PERI_PAR_AO_SYS0, i, DOMAIN_11,
+ PERI_PAR_AO_SYS0_Devices[i].d11_permission);
+ set_module_apc(SLAVE_TYPE_PERI_PAR_AO_SYS0, i, DOMAIN_12,
+ PERI_PAR_AO_SYS0_Devices[i].d12_permission);
+ set_module_apc(SLAVE_TYPE_PERI_PAR_AO_SYS0, i, DOMAIN_13,
+ PERI_PAR_AO_SYS0_Devices[i].d13_permission);
+ set_module_apc(SLAVE_TYPE_PERI_PAR_AO_SYS0, i, DOMAIN_14,
+ PERI_PAR_AO_SYS0_Devices[i].d14_permission);
+ set_module_apc(SLAVE_TYPE_PERI_PAR_AO_SYS0, i, DOMAIN_15,
+ PERI_PAR_AO_SYS0_Devices[i].d15_permission);
+ }
+}
+
+static void set_extra_apc(void)
+{
+#ifdef MTK_DEBUGSYS_LOCK
+ /* Block debugsys to avoid privilege escalation (user load only) */
+ set_module_apc(SLAVE_TYPE_PERI_AO_SYS0, DEVAPC_DEBUGSYS_INDEX,
+ DOMAIN_0, SEC_RW_NS_R);
+#endif
+}
+
+void devapc_init(void)
+{
+ /* Initial Permission */
+ set_infra_ao_apc();
+ set_peri_ao_apc();
+ set_peri_ao2_apc();
+ set_peri_par_ao_apc();
+
+ /* Extra Permission */
+ set_extra_apc();
+
+ /* Dump Permission */
+ dump_infra_ao_apc();
+ dump_peri_ao_apc();
+ dump_peri_ao2_apc();
+ dump_peri_par_ao_apc();
+
+ /* Setup APUSYS Permission */
+ set_apusys_apc();
+
+ INFO("[DEVAPC] %s done\n", __func__);
+}
diff --git a/plat/mediatek/mt8192/drivers/devapc/devapc.h b/plat/mediatek/mt8192/drivers/devapc/devapc.h
new file mode 100644
index 0000000..9033a0f
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/devapc/devapc.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DEVAPC_H
+#define DEVAPC_H
+
+#include <stdint.h>
+#include <platform_def.h>
+
+/******************************************************************************
+ * FUNCTION DEFINITION
+ ******************************************************************************/
+void devapc_init(void);
+
+/******************************************************************************
+ * STRUCTURE DEFINITION
+ ******************************************************************************/
+enum DEVAPC_PERM_TYPE {
+ NO_PROTECTION = 0,
+ SEC_RW_ONLY,
+ SEC_RW_NS_R,
+ FORBIDDEN,
+ PERM_NUM,
+};
+
+enum DOMAIN_ID {
+ 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,
+ DOMAIN_12,
+ DOMAIN_13,
+ DOMAIN_14,
+ DOMAIN_15,
+};
+
+/* Slave Type */
+enum DEVAPC_SLAVE_TYPE_SIMPLE {
+ SLAVE_TYPE_INFRA = 0,
+ SLAVE_TYPE_PERI,
+ SLAVE_TYPE_PERI2,
+ SLAVE_TYPE_PERI_PAR,
+};
+
+enum DEVAPC_SYS_INDEX {
+ DEVAPC_SYS0 = 0,
+ DEVAPC_SYS1,
+ DEVAPC_SYS2,
+};
+
+enum DEVAPC_SLAVE_TYPE {
+ SLAVE_TYPE_INFRA_AO_SYS0 = 0,
+ SLAVE_TYPE_INFRA_AO_SYS1,
+ SLAVE_TYPE_INFRA_AO_SYS2,
+ SLAVE_TYPE_PERI_AO_SYS0,
+ SLAVE_TYPE_PERI_AO_SYS1,
+ SLAVE_TYPE_PERI_AO_SYS2,
+ SLAVE_TYPE_PERI_AO2_SYS0,
+ SLAVE_TYPE_PERI_PAR_AO_SYS0,
+};
+
+/* Slave Num */
+enum DEVAPC_SLAVE_NUM {
+ SLAVE_NUM_INFRA_AO_SYS0 = 23,
+ SLAVE_NUM_INFRA_AO_SYS1 = 256,
+ SLAVE_NUM_INFRA_AO_SYS2 = 70,
+ SLAVE_NUM_PERI_AO_SYS0 = 105,
+ SLAVE_NUM_PERI_AO_SYS1 = 66,
+ SLAVE_NUM_PERI_AO_SYS2 = 1,
+ SLAVE_NUM_PERI_AO2_SYS0 = 115,
+ SLAVE_NUM_PERI_PAR_AO_SYS0 = 27,
+};
+
+enum DEVAPC_SYS_DOM_NUM {
+ DOM_NUM_INFRA_AO_SYS0 = 16,
+ DOM_NUM_INFRA_AO_SYS1 = 4,
+ DOM_NUM_INFRA_AO_SYS2 = 4,
+ DOM_NUM_PERI_AO_SYS0 = 16,
+ DOM_NUM_PERI_AO_SYS1 = 8,
+ DOM_NUM_PERI_AO_SYS2 = 4,
+ DOM_NUM_PERI_AO2_SYS0 = 16,
+ DOM_NUM_PERI_PAR_AO_SYS0 = 16,
+};
+
+enum DEVAPC_CFG_INDEX {
+ DEVAPC_DEBUGSYS_INDEX = 57,
+};
+
+struct APC_INFRA_PERI_DOM_16 {
+ unsigned char d0_permission;
+ unsigned char d1_permission;
+ unsigned char d2_permission;
+ unsigned char d3_permission;
+ unsigned char d4_permission;
+ unsigned char d5_permission;
+ unsigned char d6_permission;
+ unsigned char d7_permission;
+ unsigned char d8_permission;
+ unsigned char d9_permission;
+ unsigned char d10_permission;
+ unsigned char d11_permission;
+ unsigned char d12_permission;
+ unsigned char d13_permission;
+ unsigned char d14_permission;
+ unsigned char d15_permission;
+};
+
+struct APC_INFRA_PERI_DOM_8 {
+ unsigned char d0_permission;
+ unsigned char d1_permission;
+ unsigned char d2_permission;
+ unsigned char d3_permission;
+ unsigned char d4_permission;
+ unsigned char d5_permission;
+ unsigned char d6_permission;
+ unsigned char d7_permission;
+};
+
+struct APC_INFRA_PERI_DOM_4 {
+ unsigned char d0_permission;
+ unsigned char d1_permission;
+ unsigned char d2_permission;
+ unsigned char d3_permission;
+};
+
+#define DAPC_INFRA_AO_SYS0_ATTR(DEV_NAME, PERM_ATTR0, PERM_ATTR1, \
+ PERM_ATTR2, PERM_ATTR3, PERM_ATTR4, PERM_ATTR5, \
+ PERM_ATTR6, PERM_ATTR7, PERM_ATTR8, PERM_ATTR9, \
+ PERM_ATTR10, PERM_ATTR11, PERM_ATTR12, PERM_ATTR13, \
+ PERM_ATTR14, PERM_ATTR15) \
+ {(unsigned char)PERM_ATTR0, (unsigned char)PERM_ATTR1, \
+ (unsigned char)PERM_ATTR2, (unsigned char)PERM_ATTR3, \
+ (unsigned char)PERM_ATTR4, (unsigned char)PERM_ATTR5, \
+ (unsigned char)PERM_ATTR6, (unsigned char)PERM_ATTR7, \
+ (unsigned char)PERM_ATTR8, (unsigned char)PERM_ATTR9, \
+ (unsigned char)PERM_ATTR10, (unsigned char)PERM_ATTR11, \
+ (unsigned char)PERM_ATTR12, (unsigned char)PERM_ATTR13, \
+ (unsigned char)PERM_ATTR14, (unsigned char)PERM_ATTR15}
+
+#define DAPC_INFRA_AO_SYS1_ATTR(DEV_NAME, PERM_ATTR0, PERM_ATTR1, \
+ PERM_ATTR2, PERM_ATTR3) \
+ {(unsigned char)PERM_ATTR0, (unsigned char)PERM_ATTR1, \
+ (unsigned char)PERM_ATTR2, (unsigned char)PERM_ATTR3}
+
+#define DAPC_PERI_AO_SYS1_ATTR(DEV_NAME, PERM_ATTR0, PERM_ATTR1, \
+ PERM_ATTR2, PERM_ATTR3, PERM_ATTR4, PERM_ATTR5, \
+ PERM_ATTR6, PERM_ATTR7) \
+ {(unsigned char)PERM_ATTR0, (unsigned char)PERM_ATTR1, \
+ (unsigned char)PERM_ATTR2, (unsigned char)PERM_ATTR3, \
+ (unsigned char)PERM_ATTR4, (unsigned char)PERM_ATTR5, \
+ (unsigned char)PERM_ATTR6, (unsigned char)PERM_ATTR7}
+
+#define DAPC_INFRA_AO_SYS2_ATTR(...) DAPC_INFRA_AO_SYS1_ATTR(__VA_ARGS__)
+#define DAPC_PERI_AO_SYS0_ATTR(...) DAPC_INFRA_AO_SYS0_ATTR(__VA_ARGS__)
+#define DAPC_PERI_AO_SYS2_ATTR(...) DAPC_INFRA_AO_SYS1_ATTR(__VA_ARGS__)
+#define DAPC_PERI_AO2_SYS0_ATTR(...) DAPC_INFRA_AO_SYS0_ATTR(__VA_ARGS__)
+#define DAPC_PERI_PAR_AO_SYS0_ATTR(...) DAPC_INFRA_AO_SYS0_ATTR(__VA_ARGS__)
+
+/******************************************************************************
+ * UTILITY DEFINITION
+ ******************************************************************************/
+#define devapc_writel(VAL, REG) mmio_write_32((uintptr_t)REG, VAL)
+#define devapc_readl(REG) mmio_read_32((uintptr_t)REG)
+
+/******************************************************************************/
+/* Device APC AO for INFRA AO */
+#define DEVAPC_INFRA_AO_SYS0_D0_APC_0 (DEVAPC_INFRA_AO_BASE + 0x0000)
+#define DEVAPC_INFRA_AO_SYS1_D0_APC_0 (DEVAPC_INFRA_AO_BASE + 0x1000)
+#define DEVAPC_INFRA_AO_SYS2_D0_APC_0 (DEVAPC_INFRA_AO_BASE + 0x2000)
+
+#define DEVAPC_INFRA_AO_MAS_SEC_0 (DEVAPC_INFRA_AO_BASE + 0x0A00)
+
+/******************************************************************************/
+/* Device APC AO for PERI AO */
+#define DEVAPC_PERI_AO_SYS0_D0_APC_0 (DEVAPC_PERI_AO_BASE + 0x0000)
+#define DEVAPC_PERI_AO_SYS1_D0_APC_0 (DEVAPC_PERI_AO_BASE + 0x1000)
+#define DEVAPC_PERI_AO_SYS2_D0_APC_0 (DEVAPC_PERI_AO_BASE + 0x2000)
+
+#define DEVAPC_PERI_AO_MAS_SEC_0 (DEVAPC_PERI_AO_BASE + 0x0A00)
+
+/******************************************************************************/
+/* Device APC AO for PERI AO2 */
+#define DEVAPC_PERI_AO2_SYS0_D0_APC_0 (DEVAPC_PERI_AO2_BASE + 0x0000)
+
+/******************************************************************************/
+/* Device APC AO for PERI PAR AO */
+#define DEVAPC_PERI_PAR_AO_SYS0_D0_APC_0 (DEVAPC_PERI_PAR_AO_BASE + 0x0000)
+
+#define DEVAPC_PERI_PAR_AO_MAS_SEC_0 (DEVAPC_PERI_PAR_AO_BASE + 0x0A00)
+
+/******************************************************************************/
+
+
+/******************************************************************************
+ * Variable DEFINITION
+ ******************************************************************************/
+#define MOD_NO_IN_1_DEVAPC 16
+
+#endif /* DEVAPC_H */
+
diff --git a/plat/mediatek/mt8192/drivers/dfd/plat_dfd.c b/plat/mediatek/mt8192/drivers/dfd/plat_dfd.c
new file mode 100644
index 0000000..69c395e
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/dfd/plat_dfd.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mtk_sip_svc.h>
+#include <plat_dfd.h>
+
+static bool dfd_enabled;
+static uint64_t dfd_base_addr;
+static uint64_t dfd_chain_length;
+static uint64_t dfd_cache_dump;
+
+static void dfd_setup(uint64_t base_addr, uint64_t chain_length,
+ uint64_t cache_dump)
+{
+ /* bit[0]: rg_rw_dfd_internal_dump_en -> 1 */
+ /* bit[2]: rg_rw_dfd_clock_stop_en -> 1 */
+ sync_writel(DFD_INTERNAL_CTL, 0x5);
+
+ /* bit[13]: xreset_b_update_disable */
+ mmio_setbits_32(DFD_INTERNAL_CTL, 0x1 << 13);
+
+ /*
+ * bit[10:3]: DFD trigger selection mask
+ * bit[3]: rg_rw_dfd_trigger_sel[0] = 1(enable wdt trigger)
+ * bit[4]: rg_rw_dfd_trigger_sel[1] = 1(enable HW trigger)
+ * bit[5]: rg_rw_dfd_trigger_sel[2] = 1(enable SW trigger)
+ * bit[6]: rg_rw_dfd_trigger_sel[3] = 1(enable SW non-security trigger)
+ * bit[7]: rg_rw_dfd_trigger_sel[4] = 1(enable timer trigger)
+ */
+ mmio_setbits_32(DFD_INTERNAL_CTL, 0x1 << 3);
+
+ /* bit[20:19]: rg_dfd_armpll_div_mux_sel switch to PLL2 for DFD */
+ mmio_setbits_32(DFD_INTERNAL_CTL, 0x3 << 19);
+
+ /*
+ * bit[0]: rg_rw_dfd_auto_power_on = 1
+ * bit[2:1]: rg_rw_dfd_auto_power_on_dely = 1(10us)
+ * bit[4:2]: rg_rw_dfd_power_on_wait_time = 1(20us)
+ */
+ mmio_write_32(DFD_INTERNAL_PWR_ON, 0xB);
+
+ /* longest scan chain length */
+ mmio_write_32(DFD_CHAIN_LENGTH0, chain_length);
+
+ /* bit[1:0]: rg_rw_dfd_shift_clock_ratio */
+ mmio_write_32(DFD_INTERNAL_SHIFT_CLK_RATIO, 0x0);
+
+ /* rg_dfd_test_so_over_64 */
+ mmio_write_32(DFD_INTERNAL_TEST_SO_OVER_64, 0x1);
+
+ /* DFD3.0 */
+ mmio_write_32(DFD_TEST_SI_0, DFD_TEST_SI_0_CACHE_DIS_VAL);
+ mmio_write_32(DFD_TEST_SI_1, DFD_TEST_SI_1_VAL);
+ mmio_write_32(DFD_TEST_SI_2, DFD_TEST_SI_2_VAL);
+ mmio_write_32(DFD_TEST_SI_3, DFD_TEST_SI_3_VAL);
+
+ /* for iLDO feature */
+ sync_writel(DFD_POWER_CTL, 0xF9);
+
+ /* set base address */
+ mmio_write_32(DFD_O_SET_BASEADDR_REG, base_addr >> 24);
+
+ /*
+ * disable sleep protect of DFD
+ * 10001220[8]: protect_en_reg[8]
+ * 10001a3c[2]: infra_mcu_pwr_ctl_mask[2]
+ */
+ mmio_clrbits_32(DFD_O_PROTECT_EN_REG, 1 << 8);
+ mmio_clrbits_32(DFD_O_INTRF_MCU_PWR_CTL_MASK, 1 << 2);
+
+ /* clean DFD trigger status */
+ sync_writel(DFD_CLEAN_STATUS, 0x1);
+ sync_writel(DFD_CLEAN_STATUS, 0x0);
+
+ /* DFD-3.0 */
+ sync_writel(DFD_V30_CTL, 0x1);
+
+ /* setup global variables for suspend and resume */
+ dfd_enabled = true;
+ dfd_base_addr = base_addr;
+ dfd_chain_length = chain_length;
+ dfd_cache_dump = cache_dump;
+
+ if ((cache_dump & DFD_CACHE_DUMP_ENABLE) != 0UL) {
+ /* DFD3.5 */
+ mmio_write_32(DFD_TEST_SI_0, DFD_TEST_SI_0_CACHE_EN_VAL);
+ sync_writel(DFD_V35_ENALBE, 0x1);
+ sync_writel(DFD_V35_TAP_NUMBER, 0xB);
+ sync_writel(DFD_V35_TAP_EN, DFD_V35_TAP_EN_VAL);
+ sync_writel(DFD_V35_SEQ0_0, DFD_V35_SEQ0_0_VAL);
+
+ if (cache_dump & DFD_PARITY_ERR_TRIGGER) {
+ sync_writel(DFD_HW_TRIGGER_MASK, 0xC);
+ mmio_setbits_32(DFD_INTERNAL_CTL, 0x1 << 4);
+ }
+ }
+ dsbsy();
+}
+
+void dfd_resume(void)
+{
+ if (dfd_enabled == true) {
+ dfd_setup(dfd_base_addr, dfd_chain_length, dfd_cache_dump);
+ }
+}
+
+uint64_t dfd_smc_dispatcher(uint64_t arg0, uint64_t arg1,
+ uint64_t arg2, uint64_t arg3)
+{
+ uint64_t ret = 0L;
+
+ switch (arg0) {
+ case PLAT_MTK_DFD_SETUP_MAGIC:
+ dfd_setup(arg1, arg2, arg3);
+ break;
+ case PLAT_MTK_DFD_READ_MAGIC:
+ /* only allow to access DFD register base + 0x200 */
+ if (arg1 <= 0x200) {
+ ret = mmio_read_32(MISC1_CFG_BASE + arg1);
+ }
+ break;
+ case PLAT_MTK_DFD_WRITE_MAGIC:
+ /* only allow to access DFD register base + 0x200 */
+ if (arg1 <= 0x200) {
+ sync_writel(MISC1_CFG_BASE + arg1, arg2);
+ }
+ break;
+ default:
+ ret = MTK_SIP_E_INVALID_PARAM;
+ break;
+ }
+
+ return ret;
+}
diff --git a/plat/mediatek/mt8192/drivers/dfd/plat_dfd.h b/plat/mediatek/mt8192/drivers/dfd/plat_dfd.h
new file mode 100644
index 0000000..7f0f4b5
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/dfd/plat_dfd.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_DFD_H
+#define PLAT_DFD_H
+
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#define sync_writel(addr, val) do { mmio_write_32((addr), (val)); \
+ dsbsy(); \
+ } while (0)
+
+#define PLAT_MTK_DFD_SETUP_MAGIC (0x99716150)
+#define PLAT_MTK_DFD_READ_MAGIC (0x99716151)
+#define PLAT_MTK_DFD_WRITE_MAGIC (0x99716152)
+
+#define MCU_BIU_BASE (MCUCFG_BASE)
+#define MISC1_CFG_BASE (MCU_BIU_BASE + 0xE040)
+#define DFD_INTERNAL_CTL (MISC1_CFG_BASE + 0x00)
+#define DFD_INTERNAL_PWR_ON (MISC1_CFG_BASE + 0x08)
+#define DFD_CHAIN_LENGTH0 (MISC1_CFG_BASE + 0x0C)
+#define DFD_INTERNAL_SHIFT_CLK_RATIO (MISC1_CFG_BASE + 0x10)
+#define DFD_CHAIN_LENGTH1 (MISC1_CFG_BASE + 0x1C)
+#define DFD_CHAIN_LENGTH2 (MISC1_CFG_BASE + 0x20)
+#define DFD_CHAIN_LENGTH3 (MISC1_CFG_BASE + 0x24)
+#define DFD_INTERNAL_TEST_SO_0 (MISC1_CFG_BASE + 0x28)
+#define DFD_INTERNAL_NUM_OF_TEST_SO_GROUP (MISC1_CFG_BASE + 0x30)
+#define DFD_INTERNAL_TEST_SO_OVER_64 (MISC1_CFG_BASE + 0x34)
+#define DFD_V30_CTL (MISC1_CFG_BASE + 0x48)
+#define DFD_V30_BASE_ADDR (MISC1_CFG_BASE + 0x4C)
+#define DFD_POWER_CTL (MISC1_CFG_BASE + 0x50)
+#define DFD_TEST_SI_0 (MISC1_CFG_BASE + 0x58)
+#define DFD_TEST_SI_1 (MISC1_CFG_BASE + 0x5C)
+#define DFD_CLEAN_STATUS (MISC1_CFG_BASE + 0x60)
+#define DFD_TEST_SI_2 (MISC1_CFG_BASE + 0x1D8)
+#define DFD_TEST_SI_3 (MISC1_CFG_BASE + 0x1DC)
+#define DFD_HW_TRIGGER_MASK (MISC1_CFG_BASE + 0xBC)
+
+#define DFD_V35_ENALBE (MCU_BIU_BASE + 0xE0A8)
+#define DFD_V35_TAP_NUMBER (MCU_BIU_BASE + 0xE0AC)
+#define DFD_V35_TAP_EN (MCU_BIU_BASE + 0xE0B0)
+#define DFD_V35_CTL (MCU_BIU_BASE + 0xE0B4)
+#define DFD_V35_SEQ0_0 (MCU_BIU_BASE + 0xE0C0)
+#define DFD_V35_SEQ0_1 (MCU_BIU_BASE + 0xE0C4)
+
+#define DFD_O_PROTECT_EN_REG (0x10001220)
+#define DFD_O_INTRF_MCU_PWR_CTL_MASK (0x10001A3C)
+#define DFD_O_SET_BASEADDR_REG (0x10043034)
+
+#define DFD_CACHE_DUMP_ENABLE 1U
+#define DFD_PARITY_ERR_TRIGGER 2U
+
+#define DFD_TEST_SI_0_CACHE_DIS_VAL (0x1E000202)
+#define DFD_TEST_SI_0_CACHE_EN_VAL (0x1E000002)
+#define DFD_TEST_SI_1_VAL (0x20408100)
+#define DFD_TEST_SI_2_VAL (0x10101000)
+#define DFD_TEST_SI_3_VAL (0x00000010)
+#define DFD_V35_TAP_EN_VAL (0x43FF)
+#define DFD_V35_SEQ0_0_VAL (0x63668820)
+
+void dfd_resume(void);
+uint64_t dfd_smc_dispatcher(uint64_t arg0, uint64_t arg1,
+ uint64_t arg2, uint64_t arg3);
+
+#endif /* PLAT_DFD_H */
diff --git a/plat/mediatek/mt8192/drivers/emi_mpu/emi_mpu.c b/plat/mediatek/mt8192/drivers/emi_mpu/emi_mpu.c
new file mode 100644
index 0000000..26bed29
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/emi_mpu/emi_mpu.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <emi_mpu.h>
+#include <lib/mmio.h>
+
+/*
+ * emi_mpu_set_region_protection: protect a region.
+ * @start: start address of the region
+ * @end: end address of the region
+ * @access_permission: EMI MPU access permission
+ * Return 0 for success, otherwise negative status code.
+ */
+static int _emi_mpu_set_protection(
+ unsigned long start, unsigned long end,
+ unsigned int apc)
+{
+ unsigned int dgroup;
+ unsigned int region;
+
+ region = (start >> 24) & 0xFF;
+ start &= 0x00FFFFFF;
+ dgroup = (end >> 24) & 0xFF;
+ end &= 0x00FFFFFF;
+
+ if ((region >= EMI_MPU_REGION_NUM) || (dgroup > EMI_MPU_DGROUP_NUM)) {
+ WARN("Region:%u or dgroup:%u is wrong!\n", region, dgroup);
+ return -1;
+ }
+
+ apc &= 0x80FFFFFF;
+
+ if ((start >= DRAM_OFFSET) && (end >= start)) {
+ start -= DRAM_OFFSET;
+ end -= DRAM_OFFSET;
+ } else {
+ WARN("start:0x%lx or end:0x%lx address is wrong!\n",
+ start, end);
+ return -2;
+ }
+
+ mmio_write_32(EMI_MPU_SA(region), start);
+ mmio_write_32(EMI_MPU_EA(region), end);
+ mmio_write_32(EMI_MPU_APC(region, dgroup), apc);
+
+ return 0;
+}
+
+void dump_emi_mpu_regions(void)
+{
+ unsigned long apc[EMI_MPU_DGROUP_NUM], sa, ea;
+
+ int region, i;
+
+ /* Only dump 8 regions(max: EMI_MPU_REGION_NUM --> 32) */
+ for (region = 0; region < 8; ++region) {
+ for (i = 0; i < EMI_MPU_DGROUP_NUM; ++i)
+ apc[i] = mmio_read_32(EMI_MPU_APC(region, i));
+ sa = mmio_read_32(EMI_MPU_SA(region));
+ ea = mmio_read_32(EMI_MPU_EA(region));
+
+ WARN("region %d:\n", region);
+ WARN("\tsa:0x%lx, ea:0x%lx, apc0: 0x%lx apc1: 0x%lx\n",
+ sa, ea, apc[0], apc[1]);
+ }
+}
+
+int emi_mpu_set_protection(struct emi_region_info_t *region_info)
+{
+ unsigned long start, end;
+ int i;
+
+ if (region_info->region >= EMI_MPU_REGION_NUM)
+ return -1;
+
+ start = (unsigned long)(region_info->start >> EMI_MPU_ALIGN_BITS) |
+ (region_info->region << 24);
+
+ for (i = EMI_MPU_DGROUP_NUM - 1; i >= 0; i--) {
+ end = (unsigned long)(region_info->end >> EMI_MPU_ALIGN_BITS) |
+ (i << 24);
+ _emi_mpu_set_protection(start, end, region_info->apc[i]);
+ }
+
+ return 0;
+}
+
+void emi_mpu_init(void)
+{
+ struct emi_region_info_t region_info;
+
+ /* reserve region 0 for future use */
+
+ /* PCI-e protect address(64MB) */
+ region_info.start = 0xC0000000ULL;
+ region_info.end = 0xC3FF0000ULL;
+ region_info.region = 1;
+ SET_ACCESS_PERMISSION(region_info.apc, 1,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, NO_PROT, NO_PROT);
+ emi_mpu_set_protection(&region_info);
+
+ /* SCP protect address */
+ region_info.start = 0x50000000ULL;
+ region_info.end = 0x513F0000ULL;
+ region_info.region = 2;
+ SET_ACCESS_PERMISSION(region_info.apc, 1,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ NO_PROT, FORBIDDEN, FORBIDDEN, NO_PROT);
+ emi_mpu_set_protection(&region_info);
+
+ /* DSP protect address */
+ region_info.start = 0x40000000ULL; /* dram base addr */
+ region_info.end = 0x1FFFF0000ULL;
+ region_info.region = 3;
+ SET_ACCESS_PERMISSION(region_info.apc, 1,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROT);
+ emi_mpu_set_protection(&region_info);
+
+ /* Forbidden All */
+ region_info.start = 0x40000000ULL; /* dram base addr */
+ region_info.end = 0x1FFFF0000ULL;
+ region_info.region = 4;
+ SET_ACCESS_PERMISSION(region_info.apc, 1,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROT);
+ emi_mpu_set_protection(&region_info);
+
+ dump_emi_mpu_regions();
+}
+
diff --git a/plat/mediatek/mt8192/drivers/emi_mpu/emi_mpu.h b/plat/mediatek/mt8192/drivers/emi_mpu/emi_mpu.h
new file mode 100644
index 0000000..0b15431
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/emi_mpu/emi_mpu.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EMI_MPU_H
+#define EMI_MPU_H
+
+#include <platform_def.h>
+
+#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 NO_PROT (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)
+
+#define EMI_MPU_SA0 (EMI_MPU_BASE + 0x100)
+#define EMI_MPU_EA0 (EMI_MPU_BASE + 0x200)
+#define EMI_MPU_SA(region) (EMI_MPU_SA0 + (region) * 4)
+#define EMI_MPU_EA(region) (EMI_MPU_EA0 + (region) * 4)
+
+#define EMI_MPU_APC0 (EMI_MPU_BASE + 0x300)
+#define EMI_MPU_APC(region, dgroup) (EMI_MPU_APC0 + (region) * 4 + \
+ (dgroup) * 0x100)
+
+#define EMI_MPU_CTRL_D0 (EMI_MPU_BASE + 0x800)
+#define EMI_MPU_CTRL_D(domain) (EMI_MPU_CTRL_D0 + domain * 4)
+#define EMI_RG_MASK_D0 (EMI_MPU_BASE + 0x900)
+#define EMI_RG_MASK_D(domain) (EMI_RG_MASK_D0 + domain * 4)
+
+#define EMI_MPU_DOMAIN_NUM 16
+#define EMI_MPU_REGION_NUM 32
+#define EMI_MPU_ALIGN_BITS 16
+#define DRAM_OFFSET (0x40000000 >> EMI_MPU_ALIGN_BITS)
+
+#define EMI_MPU_DGROUP_NUM (EMI_MPU_DOMAIN_NUM / 8)
+
+#if (EMI_MPU_DGROUP_NUM == 1)
+#define SET_ACCESS_PERMISSION(apc_ary, lock, d7, d6, d5, d4, d3, d2, d1, d0) \
+do { \
+ apc_ary[0] = 0; \
+ apc_ary[0] = \
+ (((unsigned int) d7) << 21) | (((unsigned int) d6) << 18) \
+ | (((unsigned int) d5) << 15) | (((unsigned int) d4) << 12) \
+ | (((unsigned int) d3) << 9) | (((unsigned int) d2) << 6) \
+ | (((unsigned int) d1) << 3) | ((unsigned int) d0) \
+ | (((unsigned int) lock) << 31); \
+} while (0)
+#elif (EMI_MPU_DGROUP_NUM == 2)
+#define SET_ACCESS_PERMISSION(apc_ary, lock, d15, d14, d13, d12, d11, d10, \
+ d9, d8, d7, d6, d5, d4, d3, d2, d1, d0) \
+do { \
+ apc_ary[1] = \
+ (((unsigned int) d15) << 21) | (((unsigned int) d14) << 18) \
+ | (((unsigned int) d13) << 15) | (((unsigned int) d12) << 12) \
+ | (((unsigned int) d11) << 9) | (((unsigned int) d10) << 6) \
+ | (((unsigned int) d9) << 3) | ((unsigned int) d8); \
+ apc_ary[0] = \
+ (((unsigned int) d7) << 21) | (((unsigned int) d6) << 18) \
+ | (((unsigned int) d5) << 15) | (((unsigned int) d4) << 12) \
+ | (((unsigned int) d3) << 9) | (((unsigned int) d2) << 6) \
+ | (((unsigned int) d1) << 3) | ((unsigned int) d0) \
+ | (((unsigned int) lock) << 31); \
+} while (0)
+#endif
+
+struct emi_region_info_t {
+ unsigned long long start;
+ unsigned long long end;
+ unsigned int region;
+ unsigned long apc[EMI_MPU_DGROUP_NUM];
+};
+
+void emi_mpu_init(void);
+int emi_mpu_set_protection(struct emi_region_info_t *region_info);
+void dump_emi_mpu_regions(void);
+
+#endif /* __EMI_MPU_H */
diff --git a/plat/mediatek/mt8192/drivers/gpio/mtgpio.c b/plat/mediatek/mt8192/drivers/gpio/mtgpio.c
new file mode 100644
index 0000000..c78332d
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/gpio/mtgpio.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <mtgpio.h>
+#include <platform_def.h>
+
+uintptr_t mt_gpio_find_reg_addr(uint32_t pin)
+{
+ uintptr_t reg_addr = 0U;
+ struct mt_pin_info gpio_info;
+
+ assert(pin < MAX_GPIO_PIN);
+
+ gpio_info = mt_pin_infos[pin];
+
+ switch (gpio_info.base & 0x0f) {
+ case 0:
+ reg_addr = IOCFG_RM_BASE;
+ break;
+ case 1:
+ reg_addr = IOCFG_BM_BASE;
+ break;
+ case 2:
+ reg_addr = IOCFG_BL_BASE;
+ break;
+ case 3:
+ reg_addr = IOCFG_BR_BASE;
+ break;
+ case 4:
+ reg_addr = IOCFG_LM_BASE;
+ break;
+ case 5:
+ reg_addr = IOCFG_LB_BASE;
+ break;
+ case 6:
+ reg_addr = IOCFG_RT_BASE;
+ break;
+ case 7:
+ reg_addr = IOCFG_LT_BASE;
+ break;
+ case 8:
+ reg_addr = IOCFG_TL_BASE;
+ break;
+ default:
+ break;
+ }
+
+ return reg_addr;
+}
diff --git a/plat/mediatek/mt8192/drivers/gpio/mtgpio.h b/plat/mediatek/mt8192/drivers/gpio/mtgpio.h
new file mode 100644
index 0000000..d3aa24d
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/gpio/mtgpio.h
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_GPIO_H
+#define MT_GPIO_H
+
+#include <mtgpio_common.h>
+
+/* 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, GPIO180, GPIO181, GPIO182, GPIO183,
+ GPIO184, GPIO185, GPIO186, GPIO187, GPIO188, GPIO189, GPIO190, GPIO191,
+ GPIO192, GPIO193, GPIO194, GPIO195, GPIO196, GPIO197, GPIO198, GPIO199,
+ GPIO200, GPIO201, GPIO202, GPIO203, GPIO204, GPIO205, GPIO206, GPIO207,
+ GPIO208, GPIO209, GPIO210, GPIO211, GPIO212, GPIO213, GPIO214, GPIO215,
+ GPIO216, GPIO217, GPIO218, GPIO219,
+ MT_GPIO_BASE_MAX
+} GPIO_PIN;
+
+static const struct mt_pin_info mt_pin_infos[] = {
+ PIN(0, 0, 9, 0x23, 0xb0),
+ PIN(1, 0, 10, 0x23, 0xb0),
+ PIN(2, 0, 11, 0x23, 0xb0),
+ PIN(3, 0, 12, 0x23, 0xb0),
+ PIN(4, 0, 13, 0x23, 0xb0),
+ PIN(5, 0, 14, 0x23, 0xb0),
+ PIN(6, 0, 15, 0x23, 0xb0),
+ PIN(7, 0, 16, 0x23, 0xb0),
+ PIN(8, 0, 17, 0x23, 0xb0),
+ PIN(9, 0, 18, 0x23, 0xb0),
+ PIN(10, 1, 0, 0x15, 0x20),
+ PIN(11, 1, 1, 0x15, 0x20),
+ PIN(12, 1, 2, 0x15, 0x20),
+ PIN(13, 1, 3, 0x15, 0x20),
+ PIN(14, 1, 4, 0x15, 0x20),
+ PIN(15, 1, 5, 0x15, 0x20),
+ PIN(16, 0, 2, 0x17, 0x50),
+ PIN(17, 0, 3, 0x17, 0x50),
+ PIN(18, 0, 21, 0x36, 0xa0),
+ PIN(19, 0, 22, 0x36, 0xa0),
+ PIN(20, 0, 23, 0x36, 0xa0),
+ PIN(21, 0, 24, 0x36, 0xa0),
+ PIN(22, 0, 3, 0x21, 0x90),
+ PIN(23, 0, 4, 0x21, 0x90),
+ PIN(24, 0, 5, 0x21, 0x90),
+ PIN(25, 0, 6, 0x21, 0x90),
+ PIN(26, 0, 5, 0x22, 0x80),
+ PIN(27, 0, 6, 0x22, 0x80),
+ PIN(28, 0, 7, 0x22, 0x80),
+ PIN(29, 0, 8, 0x22, 0x80),
+ PIN(30, 0, 9, 0x22, 0x80),
+ PIN(31, 0, 27, 0x22, 0x70),
+ PIN(32, 0, 24, 0x22, 0x70),
+ PIN(33, 0, 26, 0x22, 0x70),
+ PIN(34, 0, 23, 0x22, 0x70),
+ PIN(35, 0, 25, 0x22, 0x70),
+ PIN(36, 0, 20, 0x21, 0x90),
+ PIN(37, 0, 21, 0x21, 0x90),
+ PIN(38, 0, 22, 0x21, 0x90),
+ PIN(39, 0, 23, 0x21, 0x90),
+ PIN(40, 0, 0, 0x17, 0x50),
+ PIN(41, 0, 1, 0x17, 0x50),
+ PIN(42, 0, 4, 0x17, 0x50),
+ PIN(43, 0, 25, 0x36, 0xa0),
+ PIN(44, 0, 26, 0x36, 0xa0),
+ PIN(45, 1, 9, 0x20, 0x60),
+ PIN(46, 1, 11, 0x20, 0x60),
+ PIN(47, 1, 10, 0x20, 0x60),
+ PIN(48, 1, 7, 0x20, 0x60),
+ PIN(49, 1, 8, 0x20, 0x60),
+ PIN(50, 1, 6, 0x20, 0x60),
+ PIN(51, 1, 0, 0x20, 0x60),
+ PIN(52, 1, 1, 0x20, 0x60),
+ PIN(53, 1, 5, 0x20, 0x60),
+ PIN(54, 1, 2, 0x20, 0x60),
+ PIN(55, 1, 4, 0x20, 0x60),
+ PIN(56, 1, 3, 0x20, 0x60),
+ PIN(57, 0, 1, 0x22, 0x80),
+ PIN(58, 0, 2, 0x22, 0x80),
+ PIN(59, 0, 3, 0x22, 0x80),
+ PIN(60, 0, 4, 0x22, 0x80),
+ PIN(61, 0, 28, 0x22, 0x70),
+ PIN(62, 0, 22, 0x22, 0x70),
+ PIN(63, 0, 0, 0x22, 0x70),
+ PIN(64, 0, 1, 0x22, 0x70),
+ PIN(65, 0, 12, 0x22, 0x70),
+ PIN(66, 0, 15, 0x22, 0x70),
+ PIN(67, 0, 16, 0x22, 0x70),
+ PIN(68, 0, 17, 0x22, 0x70),
+ PIN(69, 0, 18, 0x22, 0x70),
+ PIN(70, 0, 19, 0x22, 0x70),
+ PIN(71, 0, 20, 0x22, 0x70),
+ PIN(72, 0, 21, 0x22, 0x70),
+ PIN(73, 0, 2, 0x22, 0x70),
+ PIN(74, 0, 3, 0x22, 0x70),
+ PIN(75, 0, 4, 0x22, 0x70),
+ PIN(76, 0, 5, 0x22, 0x70),
+ PIN(77, 0, 6, 0x22, 0x70),
+ PIN(78, 0, 7, 0x22, 0x70),
+ PIN(79, 0, 8, 0x22, 0x70),
+ PIN(80, 0, 9, 0x22, 0x70),
+ PIN(81, 0, 10, 0x22, 0x70),
+ PIN(82, 0, 11, 0x22, 0x70),
+ PIN(83, 0, 13, 0x22, 0x70),
+ PIN(84, 0, 14, 0x22, 0x70),
+ PIN(85, 0, 31, 0x22, 0x70),
+ PIN(86, 0, 0, 0x22, 0x80),
+ PIN(87, 0, 29, 0x22, 0x70),
+ PIN(88, 0, 30, 0x22, 0x70),
+ PIN(89, 0, 24, 0x21, 0x90),
+ PIN(90, 0, 25, 0x21, 0x90),
+ PIN(91, 0, 0, 0x21, 0x90),
+ PIN(92, 0, 2, 0x21, 0xa0),
+ PIN(93, 0, 4, 0x21, 0xa0),
+ PIN(94, 0, 3, 0x21, 0xa0),
+ PIN(95, 0, 5, 0x21, 0xa0),
+ PIN(96, 0, 31, 0x21, 0x90),
+ PIN(97, 0, 26, 0x21, 0x90),
+ PIN(98, 0, 0, 0x21, 0xa0),
+ PIN(99, 0, 27, 0x21, 0x90),
+ PIN(100, 0, 28, 0x21, 0x90),
+ PIN(101, 0, 29, 0x21, 0x90),
+ PIN(102, 0, 30, 0x21, 0x90),
+ PIN(103, 0, 18, 0x21, 0x90),
+ PIN(104, 0, 17, 0x21, 0x90),
+ PIN(105, 0, 19, 0x21, 0x90),
+ PIN(106, 0, 16, 0x21, 0x90),
+ PIN(107, 0, 1, 0x21, 0x90),
+ PIN(108, 0, 2, 0x21, 0x90),
+ PIN(109, 0, 10, 0x21, 0x90),
+ PIN(110, 0, 7, 0x21, 0x90),
+ PIN(111, 0, 9, 0x21, 0x90),
+ PIN(112, 0, 11, 0x21, 0x90),
+ PIN(113, 0, 8, 0x21, 0x90),
+ PIN(114, 0, 14, 0x21, 0x90),
+ PIN(115, 0, 13, 0x21, 0x90),
+ PIN(116, 0, 15, 0x21, 0x90),
+ PIN(117, 0, 12, 0x21, 0x90),
+ PIN(118, 0, 23, 0x23, 0xb0),
+ PIN(119, 0, 29, 0x23, 0xb0),
+ PIN(120, 0, 28, 0x23, 0xb0),
+ PIN(121, 0, 2, 0x23, 0xc0),
+ PIN(122, 0, 27, 0x23, 0xb0),
+ PIN(123, 0, 1, 0x23, 0xc0),
+ PIN(124, 0, 26, 0x23, 0xb0),
+ PIN(125, 0, 0, 0x23, 0xc0),
+ PIN(126, 0, 19, 0x23, 0xb0),
+ PIN(127, 0, 20, 0x23, 0xb0),
+ PIN(128, 0, 21, 0x23, 0xb0),
+ PIN(129, 0, 22, 0x23, 0xb0),
+ PIN(130, 0, 6, 0x23, 0xb0),
+ PIN(131, 0, 7, 0x23, 0xb0),
+ PIN(132, 0, 8, 0x23, 0xb0),
+ PIN(133, 0, 3, 0x23, 0xb0),
+ PIN(134, 0, 4, 0x23, 0xb0),
+ PIN(135, 0, 5, 0x23, 0xb0),
+ PIN(136, 0, 0, 0x23, 0xb0),
+ PIN(137, 0, 1, 0x23, 0xb0),
+ PIN(138, 0, 2, 0x23, 0xb0),
+ PIN(139, 0, 25, 0x23, 0xb0),
+ PIN(140, 0, 31, 0x23, 0xb0),
+ PIN(141, 0, 24, 0x23, 0xb0),
+ PIN(142, 0, 30, 0x23, 0xb0),
+ PIN(143, 0, 6, 0x20, 0x70),
+ PIN(144, 0, 7, 0x20, 0x70),
+ PIN(145, 0, 8, 0x20, 0x70),
+ PIN(146, 0, 3, 0x20, 0x70),
+ PIN(147, 0, 4, 0x20, 0x70),
+ PIN(148, 0, 5, 0x20, 0x70),
+ PIN(149, 0, 0, 0x20, 0x70),
+ PIN(150, 0, 1, 0x20, 0x70),
+ PIN(151, 0, 2, 0x20, 0x70),
+ PIN(152, 1, 3, 0x36, 0x90),
+ PIN(153, 1, 2, 0x36, 0x90),
+ PIN(154, 1, 0, 0x36, 0x906),
+ PIN(155, 1, 1, 0x36, 0x90),
+ PIN(156, 0, 29, 0x36, 0xa0),
+ PIN(157, 0, 30, 0x36, 0xa0),
+ PIN(158, 0, 31, 0x36, 0xa0),
+ PIN(159, 0, 0, 0x36, 0xb0),
+ PIN(160, 0, 27, 0x36, 0xa04),
+ PIN(161, 0, 28, 0x36, 0xa0),
+ PIN(162, 0, 0, 0x36, 0xa0),
+ PIN(163, 0, 1, 0x36, 0xa0),
+ PIN(164, 0, 2, 0x36, 0xa0),
+ PIN(165, 0, 3, 0x36, 0xa0),
+ PIN(166, 0, 4, 0x36, 0xa0),
+ PIN(167, 0, 5, 0x36, 0xa0),
+ PIN(168, 0, 6, 0x36, 0xa0),
+ PIN(169, 0, 7, 0x36, 0xa0),
+ PIN(170, 0, 8, 0x36, 0xa0),
+ PIN(171, 0, 9, 0x36, 0xa0),
+ PIN(172, 0, 13, 0x36, 0xa0),
+ PIN(173, 0, 14, 0x36, 0xa0),
+ PIN(174, 0, 12, 0x36, 0xa0),
+ PIN(175, 0, 15, 0x36, 0xa0),
+ PIN(176, 0, 10, 0x36, 0xa0),
+ PIN(177, 0, 11, 0x36, 0xa0),
+ PIN(178, 0, 16, 0x36, 0xa0),
+ PIN(179, 0, 17, 0x36, 0xa0),
+ PIN(180, 0, 18, 0x36, 0xa0),
+ PIN(181, 0, 19, 0x36, 0xa0),
+ PIN(182, 0, 20, 0x36, 0xa0),
+ PIN(183, 1, 1, 0x18, 0x30),
+ PIN(184, 1, 2, 0x18, 0x30),
+ PIN(185, 1, 4, 0x18, 0x30),
+ PIN(186, 1, 6, 0x18, 0x30),
+ PIN(187, 1, 8, 0x18, 0x30),
+ PIN(188, 1, 3, 0x18, 0x30),
+ PIN(189, 1, 7, 0x18, 0x30),
+ PIN(190, 1, 9, 0x18, 0x30),
+ PIN(191, 1, 10, 0x18, 0x30),
+ PIN(192, 1, 0, 0x18, 0x30),
+ PIN(193, 1, 5, 0x18, 0x30),
+ PIN(194, 1, 11, 0x18, 0x30),
+ PIN(195, 0, 16, 0x14, 0x50),
+ PIN(196, 0, 6, 0x14, 0x50),
+ PIN(197, 0, 8, 0x14, 0x50),
+ PIN(198, 0, 7, 0x14, 0x50),
+ PIN(199, 0, 3, 0x14, 0x50),
+ PIN(200, 0, 6, 0x17, 0x50),
+ PIN(201, 0, 8, 0x17, 0x50),
+ PIN(202, 0, 15, 0x14, 0x50),
+ PIN(203, 0, 17, 0x14, 0x50),
+ PIN(204, 0, 5, 0x17, 0x50),
+ PIN(205, 0, 7, 0x17, 0x50),
+ PIN(206, 0, 18, 0x14, 0x50),
+ PIN(207, 0, 19, 0x14, 0x50),
+ PIN(208, 0, 20, 0x14, 0x50),
+ PIN(209, 0, 12, 0x14, 0x50),
+ PIN(210, 0, 11, 0x14, 0x50),
+ PIN(211, 0, 13, 0x14, 0x50),
+ PIN(212, 0, 10, 0x14, 0x50),
+ PIN(213, 0, 14, 0x14, 0x50),
+ PIN(214, 0, 0, 0x14, 0x50),
+ PIN(215, 0, 9, 0x14, 0x50),
+ PIN(216, 0, 4, 0x14, 0x50),
+ PIN(217, 0, 5, 0x14, 0x50),
+ PIN(218, 0, 1, 0x14, 0x50),
+ PIN(219, 0, 2, 0x14, 0x50),
+};
+#endif /* MT_GPIO_H */
diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm.c b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm.c
new file mode 100644
index 0000000..b483c36
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <lib/psci/psci.h>
+#include <lib/spinlock.h>
+
+#include <mt_cpu_pm_cpc.h>
+#include <mt_lp_irqremain.h>
+#include <mt_lp_rm.h>
+#include <mt_mcdi.h>
+#include <plat_mtk_lpm.h>
+#include <plat_pm.h>
+
+DEFINE_SYSREG_RW_FUNCS(dbgprcr_el1);
+
+static int plat_mt_lp_cpu_rc;
+
+static int pwr_state_prompt(unsigned int cpu, const psci_power_state_t *state)
+{
+ return 0;
+}
+
+static int pwr_state_reflect(unsigned int cpu, const psci_power_state_t *state)
+{
+ mtk_cpc_core_on_hint_clr(cpu);
+
+ if (IS_SYSTEM_SUSPEND_STATE(state)) {
+ mtk_cpc_time_sync();
+ }
+
+ return 0;
+}
+
+static int pwr_cpu_pwron(unsigned int cpu, const psci_power_state_t *state)
+{
+ return 0;
+}
+
+static int pwr_cpu_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
+{
+ /* clear DBGPRCR.CORENPDRQ to allow CPU power down */
+ write_dbgprcr_el1(0ULL);
+
+ return 0;
+}
+
+static int pwr_cluster_pwron(unsigned int cpu, const psci_power_state_t *state)
+{
+ return 0;
+}
+
+static int pwr_cluster_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
+{
+ return 0;
+}
+
+static int pwr_mcusys_pwron(unsigned int cpu, const psci_power_state_t *state)
+{
+ if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) {
+ return -1;
+ }
+
+ mtk_cpc_mcusys_off_reflect();
+
+ return 0;
+}
+
+static int pwr_mcusys_pwron_finished(unsigned int cpu,
+ const psci_power_state_t *state)
+{
+ int state_id = state->pwr_domain_state[MTK_AFFLVL_MCUSYS];
+
+ if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) {
+ return -1;
+ }
+
+ mt_lp_rm_reset_constraint(plat_mt_lp_cpu_rc, cpu, state_id);
+ mt_lp_irqremain_release();
+
+ return 0;
+}
+
+static int pwr_mcusys_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
+{
+ int state_id = state->pwr_domain_state[MTK_AFFLVL_MCUSYS];
+
+ if (!IS_MCUSYS_OFF_STATE(state)) {
+ goto mt_pwr_mcusysoff_break;
+ }
+
+ if (mcdi_try_init() != 0) {
+ goto mt_pwr_mcusysoff_break;
+ }
+
+ if (mtk_cpc_mcusys_off_prepare() != CPC_SUCCESS) {
+ goto mt_pwr_mcusysoff_break;
+ }
+
+ plat_mt_lp_cpu_rc =
+ mt_lp_rm_find_and_run_constraint(0, cpu, state_id, NULL);
+
+ if (plat_mt_lp_cpu_rc < 0) {
+ goto mt_pwr_mcusysoff_reflect;
+ }
+
+ mt_lp_irqremain_aquire();
+
+ return 0;
+
+mt_pwr_mcusysoff_reflect:
+ mtk_cpc_mcusys_off_reflect();
+
+mt_pwr_mcusysoff_break:
+ plat_mt_lp_cpu_rc = -1;
+
+ return -1;
+}
+
+static const struct mt_lpm_tz plat_pm = {
+ .pwr_prompt = pwr_state_prompt,
+ .pwr_reflect = pwr_state_reflect,
+ .pwr_cpu_on = pwr_cpu_pwron,
+ .pwr_cpu_dwn = pwr_cpu_pwrdwn,
+ .pwr_cluster_on = pwr_cluster_pwron,
+ .pwr_cluster_dwn = pwr_cluster_pwrdwn,
+ .pwr_mcusys_dwn = pwr_mcusys_pwrdwn,
+ .pwr_mcusys_on = pwr_mcusys_pwron,
+ .pwr_mcusys_on_finished = pwr_mcusys_pwron_finished
+};
+
+const struct mt_lpm_tz *mt_plat_cpu_pm_init(void)
+{
+ mtk_cpc_init();
+
+ if (mcdi_try_init() == 0) {
+ INFO("MCDI init done.\n");
+ }
+
+ mt_lp_irqremain_init();
+
+ return &plat_pm;
+}
diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.c b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.c
new file mode 100644
index 0000000..f8c51a1
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <drivers/delay_timer.h>
+
+#include <mt_cpu_pm_cpc.h>
+#include <mt_timer.h>
+
+struct mtk_cpc_dev {
+ int auto_off;
+ unsigned int auto_thres_tick;
+};
+
+static struct mtk_cpc_dev cpc;
+
+static int mtk_cpc_last_core_prot(uint32_t prot_req,
+ uint32_t resp_reg, uint32_t resp_ofs)
+{
+ uint32_t sta, retry;
+
+ retry = 0U;
+
+ while (retry++ < RETRY_CNT_MAX) {
+
+ mmio_write_32(CPC_MCUSYS_LAST_CORE_REQ, prot_req);
+
+ udelay(1U);
+
+ sta = (mmio_read_32(resp_reg) >> resp_ofs) & CPC_PROT_RESP_MASK;
+
+ if (sta == PROT_SUCCESS) {
+ return CPC_SUCCESS;
+ } else if (sta == PROT_GIVEUP) {
+ return CPC_ERR_FAIL;
+ }
+ }
+
+ return CPC_ERR_TIMEOUT;
+}
+
+int mtk_cpu_pm_mcusys_prot_aquire(void)
+{
+ return mtk_cpc_last_core_prot(
+ MCUSYS_PROT_SET,
+ CPC_MCUSYS_LAST_CORE_RESP,
+ MCUSYS_RESP_OFS);
+}
+
+void mtk_cpu_pm_mcusys_prot_release(void)
+{
+ mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, MCUSYS_PROT_CLR);
+}
+
+int mtk_cpu_pm_cluster_prot_aquire(unsigned int cluster)
+{
+ return mtk_cpc_last_core_prot(
+ CPUSYS_PROT_SET,
+ CPC_MCUSYS_MP_LAST_CORE_RESP,
+ CPUSYS_RESP_OFS);
+}
+
+void mtk_cpu_pm_cluster_prot_release(unsigned int cluster)
+{
+ mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, CPUSYS_PROT_CLR);
+}
+
+static void mtk_cpc_cluster_cnt_backup(void)
+{
+ uint32_t backup_cnt;
+ uint32_t curr_cnt;
+ uint32_t cnt_mask = GENMASK(14, 0);
+ uint32_t clr_mask = GENMASK(1, 0);
+
+ /* Single Cluster */
+ backup_cnt = mmio_read_32(CPC_CLUSTER_CNT_BACKUP);
+ curr_cnt = mmio_read_32(CPC_MCUSYS_CLUSTER_COUNTER);
+
+ /* Get off count if dormant count is 0 */
+ if ((curr_cnt & cnt_mask) == 0U) {
+ curr_cnt = (curr_cnt >> 16) & cnt_mask;
+ } else {
+ curr_cnt = curr_cnt & cnt_mask;
+ }
+
+ mmio_write_32(CPC_CLUSTER_CNT_BACKUP, backup_cnt + curr_cnt);
+ mmio_write_32(CPC_MCUSYS_CLUSTER_COUNTER_CLR, clr_mask);
+}
+
+static inline void mtk_cpc_mcusys_off_en(void)
+{
+ mmio_write_32(CPC_MCUSYS_PWR_CTRL, 1U);
+}
+
+static inline void mtk_cpc_mcusys_off_dis(void)
+{
+ mmio_write_32(CPC_MCUSYS_PWR_CTRL, 0U);
+}
+
+void mtk_cpc_mcusys_off_reflect(void)
+{
+ mtk_cpc_mcusys_off_dis();
+ mtk_cpu_pm_mcusys_prot_release();
+}
+
+int mtk_cpc_mcusys_off_prepare(void)
+{
+ if (mtk_cpu_pm_mcusys_prot_aquire() != CPC_SUCCESS) {
+ return CPC_ERR_FAIL;
+ }
+
+ mtk_cpc_cluster_cnt_backup();
+ mtk_cpc_mcusys_off_en();
+
+ return CPC_SUCCESS;
+}
+
+void mtk_cpc_core_on_hint_set(unsigned int cpu)
+{
+ mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_SET, BIT(cpu));
+}
+
+void mtk_cpc_core_on_hint_clr(unsigned int cpu)
+{
+ mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_CLR, BIT(cpu));
+}
+
+static void mtk_cpc_dump_timestamp(void)
+{
+ uint32_t id;
+
+ for (id = 0U; id < CPC_TRACE_ID_NUM; id++) {
+ mmio_write_32(CPC_MCUSYS_TRACE_SEL, id);
+
+ memcpy((void *)(uintptr_t)CPC_TRACE_SRAM(id),
+ (const void *)(uintptr_t)CPC_MCUSYS_TRACE_DATA,
+ CPC_TRACE_SIZE);
+ }
+}
+
+void mtk_cpc_time_sync(void)
+{
+ uint64_t kt;
+ uint32_t systime_l, systime_h;
+
+ kt = sched_clock();
+ systime_l = mmio_read_32(CNTSYS_L_REG);
+ systime_h = mmio_read_32(CNTSYS_H_REG);
+
+ /* sync kernel timer to cpc */
+ mmio_write_32(CPC_MCUSYS_CPC_KERNEL_TIME_L_BASE, (uint32_t)kt);
+ mmio_write_32(CPC_MCUSYS_CPC_KERNEL_TIME_H_BASE, (uint32_t)(kt >> 32));
+ /* sync system timer to cpc */
+ mmio_write_32(CPC_MCUSYS_CPC_SYSTEM_TIME_L_BASE, systime_l);
+ mmio_write_32(CPC_MCUSYS_CPC_SYSTEM_TIME_H_BASE, systime_h);
+}
+
+static void mtk_cpc_config(uint32_t cfg, uint32_t data)
+{
+ uint32_t val;
+ uint32_t reg = 0U;
+
+ switch (cfg) {
+ case CPC_SMC_CONFIG_PROF:
+ reg = CPC_MCUSYS_CPC_DBG_SETTING;
+ val = mmio_read_32(reg);
+ val = (data != 0U) ? (val | CPC_PROF_EN) : (val & ~CPC_PROF_EN);
+ break;
+ case CPC_SMC_CONFIG_AUTO_OFF:
+ reg = CPC_MCUSYS_CPC_FLOW_CTRL_CFG;
+ val = mmio_read_32(reg);
+ if (data != 0U) {
+ val |= CPC_AUTO_OFF_EN;
+ cpc.auto_off = 1;
+ } else {
+ val &= ~CPC_AUTO_OFF_EN;
+ cpc.auto_off = 0;
+ }
+ break;
+ case CPC_SMC_CONFIG_AUTO_OFF_THRES:
+ reg = CPC_MCUSYS_CPC_OFF_THRES;
+ cpc.auto_thres_tick = us_to_ticks(data);
+ val = cpc.auto_thres_tick;
+ break;
+ case CPC_SMC_CONFIG_CNT_CLR:
+ reg = CPC_MCUSYS_CLUSTER_COUNTER_CLR;
+ val = GENMASK(1, 0); /* clr_mask */
+ break;
+ case CPC_SMC_CONFIG_TIME_SYNC:
+ mtk_cpc_time_sync();
+ break;
+ default:
+ break;
+ }
+
+ if (reg != 0U) {
+ mmio_write_32(reg, val);
+ }
+}
+
+static uint32_t mtk_cpc_read_config(uint32_t cfg)
+{
+ uint32_t res = 0U;
+
+ switch (cfg) {
+ case CPC_SMC_CONFIG_PROF:
+ res = (mmio_read_32(CPC_MCUSYS_CPC_DBG_SETTING) & CPC_PROF_EN) ?
+ 1U : 0U;
+ break;
+ case CPC_SMC_CONFIG_AUTO_OFF:
+ res = cpc.auto_off;
+ break;
+ case CPC_SMC_CONFIG_AUTO_OFF_THRES:
+ res = ticks_to_us(cpc.auto_thres_tick);
+ break;
+ case CPC_SMC_CONFIG_CNT_CLR:
+ break;
+ default:
+ break;
+ }
+
+ return res;
+}
+
+uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2)
+{
+ uint64_t res = 0ULL;
+
+ switch (act) {
+ case CPC_SMC_EVENT_DUMP_TRACE_DATA:
+ mtk_cpc_dump_timestamp();
+ break;
+ case CPC_SMC_EVENT_GIC_DPG_SET:
+ /* isolated_status = x2; */
+ break;
+ case CPC_SMC_EVENT_CPC_CONFIG:
+ mtk_cpc_config((uint32_t)arg1, (uint32_t)arg2);
+ break;
+ case CPC_SMC_EVENT_READ_CONFIG:
+ res = mtk_cpc_read_config((uint32_t)arg1);
+ break;
+ default:
+ break;
+ }
+
+ return res;
+}
+
+void mtk_cpc_init(void)
+{
+ mmio_write_32(CPC_MCUSYS_CPC_DBG_SETTING,
+ mmio_read_32(CPC_MCUSYS_CPC_DBG_SETTING)
+ | CPC_DBG_EN
+ | CPC_CALC_EN);
+
+ cpc.auto_off = 1;
+ cpc.auto_thres_tick = us_to_ticks(8000);
+
+ mmio_write_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG,
+ mmio_read_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG)
+ | CPC_OFF_PRE_EN
+ | (cpc.auto_off ? CPC_AUTO_OFF_EN : 0U));
+
+ mmio_write_32(CPC_MCUSYS_CPC_OFF_THRES, cpc.auto_thres_tick);
+}
diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.h b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.h
new file mode 100644
index 0000000..19dd6a2
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_CPU_PM_CPC_H
+#define MT_CPU_PM_CPC_H
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <mcucfg.h>
+#include <platform_def.h>
+
+#define NEED_CPUSYS_PROT_WORKAROUND 1
+
+/* system sram registers */
+#define CPUIDLE_SRAM_REG(r) (uint32_t)(MTK_MCDI_SRAM_BASE + (r))
+
+/* db dump */
+#define CPC_TRACE_SIZE U(0x20)
+#define CPC_TRACE_ID_NUM U(10)
+#define CPC_TRACE_SRAM(id) (CPUIDLE_SRAM_REG(0x10) + (id) * CPC_TRACE_SIZE)
+
+/* buckup off count */
+#define CPC_CLUSTER_CNT_BACKUP CPUIDLE_SRAM_REG(0x1F0)
+#define CPC_MCUSYS_CNT CPUIDLE_SRAM_REG(0x1F4)
+
+/* CPC_MCUSYS_CPC_FLOW_CTRL_CFG(0xA814): debug setting */
+#define CPC_PWR_ON_SEQ_DIS BIT(1)
+#define CPC_PWR_ON_PRIORITY BIT(2)
+#define CPC_AUTO_OFF_EN BIT(5)
+#define CPC_DORMANT_WAIT_EN BIT(14)
+#define CPC_CTRL_EN BIT(16)
+#define CPC_OFF_PRE_EN BIT(29)
+
+/* CPC_MCUSYS_LAST_CORE_REQ(0xA818) : last core protection */
+#define CPUSYS_PROT_SET BIT(0)
+#define MCUSYS_PROT_SET BIT(8)
+#define CPUSYS_PROT_CLR BIT(8)
+#define MCUSYS_PROT_CLR BIT(9)
+
+#define CPC_PROT_RESP_MASK U(0x3)
+#define CPUSYS_RESP_OFS U(16)
+#define MCUSYS_RESP_OFS U(30)
+
+#define cpusys_resp(r) (((r) >> CPUSYS_RESP_OFS) & CPC_PROT_RESP_MASK)
+#define mcusys_resp(r) (((r) >> MCUSYS_RESP_OFS) & CPC_PROT_RESP_MASK)
+
+#define RETRY_CNT_MAX U(1000)
+
+#define PROT_RETRY U(0)
+#define PROT_SUCCESS U(1)
+#define PROT_GIVEUP U(2)
+
+/* CPC_MCUSYS_CPC_DBG_SETTING(0xAB00): debug setting */
+#define CPC_PROF_EN BIT(0)
+#define CPC_DBG_EN BIT(1)
+#define CPC_FREEZE BIT(2)
+#define CPC_CALC_EN BIT(3)
+
+enum {
+ CPC_SUCCESS = 0,
+
+ CPC_ERR_FAIL,
+ CPC_ERR_TIMEOUT,
+
+ NF_CPC_ERR
+};
+
+enum {
+ CPC_SMC_EVENT_DUMP_TRACE_DATA,
+ CPC_SMC_EVENT_GIC_DPG_SET,
+ CPC_SMC_EVENT_CPC_CONFIG,
+ CPC_SMC_EVENT_READ_CONFIG,
+
+ NF_CPC_SMC_EVENT
+};
+
+enum {
+ CPC_SMC_CONFIG_PROF,
+ CPC_SMC_CONFIG_AUTO_OFF,
+ CPC_SMC_CONFIG_AUTO_OFF_THRES,
+ CPC_SMC_CONFIG_CNT_CLR,
+ CPC_SMC_CONFIG_TIME_SYNC,
+
+ NF_CPC_SMC_CONFIG
+};
+
+#define us_to_ticks(us) ((us) * 13)
+#define ticks_to_us(tick) ((tick) / 13)
+
+int mtk_cpu_pm_cluster_prot_aquire(unsigned int cluster);
+void mtk_cpu_pm_cluster_prot_release(unsigned int cluster);
+
+void mtk_cpc_mcusys_off_reflect(void);
+int mtk_cpc_mcusys_off_prepare(void);
+
+void mtk_cpc_core_on_hint_set(unsigned int cpu);
+void mtk_cpc_core_on_hint_clr(unsigned int cpu);
+void mtk_cpc_time_sync(void);
+
+uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2);
+void mtk_cpc_init(void);
+
+#endif /* MT_CPU_PM_CPC_H */
diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_lp_irqremain.c b/plat/mediatek/mt8192/drivers/mcdi/mt_lp_irqremain.c
new file mode 100644
index 0000000..872f4d0
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/mcdi/mt_lp_irqremain.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mt_cirq.h>
+#include <mt_lp_irqremain.h>
+#include <mt_lp_rm.h>
+#include <plat_mtk_lpm.h>
+
+#define EDMA0_IRQ_ID U(448)
+#define MDLA_IRQ_ID U(446)
+#define MALI4_IRQ_ID U(399)
+#define MALI3_IRQ_ID U(398)
+#define MALI2_IRQ_ID U(397)
+#define MALI1_IRQ_ID U(396)
+#define MALI0_IRQ_ID U(395)
+#define VPU_CORE1_IRQ_ID U(453)
+#define VPU_CORE0_IRQ_ID U(452)
+#define MD_WDT_IRQ_ID U(110)
+#define KEYPAD_IRQ_ID U(106)
+
+#define MD_WDT_WAKESRC 0x2000000
+#define KEYPAD_WAKESRC 0x4
+
+static struct mt_irqremain remain_irqs;
+
+int mt_lp_irqremain_submit(void)
+{
+ if (remain_irqs.count == 0) {
+ return -1;
+ }
+
+ set_wakeup_sources(remain_irqs.irqs, remain_irqs.count);
+ mt_lp_rm_do_update(-1, PLAT_RC_UPDATE_REMAIN_IRQS, &remain_irqs);
+
+ return 0;
+}
+
+int mt_lp_irqremain_aquire(void)
+{
+ if (remain_irqs.count == 0) {
+ return -1;
+ }
+
+ mt_cirq_sw_reset();
+ mt_cirq_clone_gic();
+ mt_cirq_enable();
+
+ return 0;
+}
+
+int mt_lp_irqremain_release(void)
+{
+ if (remain_irqs.count == 0) {
+ return -1;
+ }
+
+ mt_cirq_flush();
+ mt_cirq_disable();
+
+ return 0;
+}
+
+void mt_lp_irqremain_init(void)
+{
+ uint32_t idx;
+
+ remain_irqs.count = 0;
+
+ /* level edma0 */
+ idx = remain_irqs.count;
+ remain_irqs.irqs[idx] = EDMA0_IRQ_ID;
+ remain_irqs.wakeupsrc_cat[idx] = 0;
+ remain_irqs.wakeupsrc[idx] = 0;
+ remain_irqs.count++;
+
+ /* level mdla */
+ idx = remain_irqs.count;
+ remain_irqs.irqs[idx] = MDLA_IRQ_ID;
+ remain_irqs.wakeupsrc_cat[idx] = 0;
+ remain_irqs.wakeupsrc[idx] = 0;
+ remain_irqs.count++;
+
+ /* level mali4 */
+ idx = remain_irqs.count;
+ remain_irqs.irqs[idx] = MALI4_IRQ_ID;
+ remain_irqs.wakeupsrc_cat[idx] = 0;
+ remain_irqs.wakeupsrc[idx] = 0;
+ remain_irqs.count++;
+
+ /* level mali3 */
+ idx = remain_irqs.count;
+ remain_irqs.irqs[idx] = MALI3_IRQ_ID;
+ remain_irqs.wakeupsrc_cat[idx] = 0;
+ remain_irqs.wakeupsrc[idx] = 0;
+ remain_irqs.count++;
+
+ /* level mali2 */
+ idx = remain_irqs.count;
+ remain_irqs.irqs[idx] = MALI2_IRQ_ID;
+ remain_irqs.wakeupsrc_cat[idx] = 0;
+ remain_irqs.wakeupsrc[idx] = 0;
+ remain_irqs.count++;
+
+ /* level mali1 */
+ idx = remain_irqs.count;
+ remain_irqs.irqs[idx] = MALI1_IRQ_ID;
+ remain_irqs.wakeupsrc_cat[idx] = 0;
+ remain_irqs.wakeupsrc[idx] = 0;
+ remain_irqs.count++;
+
+ /* level mali0 */
+ idx = remain_irqs.count;
+ remain_irqs.irqs[idx] = MALI0_IRQ_ID;
+ remain_irqs.wakeupsrc_cat[idx] = 0;
+ remain_irqs.wakeupsrc[idx] = 0;
+ remain_irqs.count++;
+
+ /* level vpu core1 */
+ idx = remain_irqs.count;
+ remain_irqs.irqs[idx] = VPU_CORE1_IRQ_ID;
+ remain_irqs.wakeupsrc_cat[idx] = 0;
+ remain_irqs.wakeupsrc[idx] = 0;
+ remain_irqs.count++;
+
+ /* level vpu core0 */
+ idx = remain_irqs.count;
+ remain_irqs.irqs[idx] = VPU_CORE0_IRQ_ID;
+ remain_irqs.wakeupsrc_cat[idx] = 0;
+ remain_irqs.wakeupsrc[idx] = 0;
+ remain_irqs.count++;
+
+ /* edge mdwdt */
+ idx = remain_irqs.count;
+ remain_irqs.irqs[idx] = MD_WDT_IRQ_ID;
+ remain_irqs.wakeupsrc_cat[idx] = 0;
+ remain_irqs.wakeupsrc[idx] = MD_WDT_WAKESRC;
+ remain_irqs.count++;
+
+ /* edge keypad */
+ idx = remain_irqs.count;
+ remain_irqs.irqs[idx] = KEYPAD_IRQ_ID;
+ remain_irqs.wakeupsrc_cat[idx] = 0;
+ remain_irqs.wakeupsrc[idx] = KEYPAD_WAKESRC;
+ remain_irqs.count++;
+
+ mt_lp_irqremain_submit();
+}
diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_lp_irqremain.h b/plat/mediatek/mt8192/drivers/mcdi/mt_lp_irqremain.h
new file mode 100644
index 0000000..cbed967
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/mcdi/mt_lp_irqremain.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_LP_IRQREMAIN_H
+#define MT_LP_IRQREMAIN_H
+
+extern int mt_lp_irqremain_submit(void);
+extern int mt_lp_irqremain_aquire(void);
+extern int mt_lp_irqremain_release(void);
+extern void mt_lp_irqremain_init(void);
+#endif /* MT_LP_IRQREMAIN_H */
diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.c b/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.c
new file mode 100644
index 0000000..1635b67
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cdefs.h>
+#include <common/debug.h>
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <mt_mcdi.h>
+
+/* Read/Write */
+#define APMCU_MCUPM_MBOX_AP_READY U(0)
+#define APMCU_MCUPM_MBOX_RESERVED_1 U(1)
+#define APMCU_MCUPM_MBOX_RESERVED_2 U(2)
+#define APMCU_MCUPM_MBOX_RESERVED_3 U(3)
+#define APMCU_MCUPM_MBOX_PWR_CTRL_EN U(4)
+#define APMCU_MCUPM_MBOX_L3_CACHE_MODE U(5)
+#define APMCU_MCUPM_MBOX_BUCK_MODE U(6)
+#define APMCU_MCUPM_MBOX_ARMPLL_MODE U(7)
+/* Read only */
+#define APMCU_MCUPM_MBOX_TASK_STA U(8)
+#define APMCU_MCUPM_MBOX_RESERVED_9 U(9)
+#define APMCU_MCUPM_MBOX_RESERVED_10 U(10)
+#define APMCU_MCUPM_MBOX_RESERVED_11 U(11)
+
+/* CPC mode - Read/Write */
+#define APMCU_MCUPM_MBOX_WAKEUP_CPU U(12)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_PWR_CTRL_EN */
+#define MCUPM_MCUSYS_CTRL BIT(0)
+#define MCUPM_BUCK_CTRL BIT(1)
+#define MCUPM_ARMPLL_CTRL BIT(2)
+#define MCUPM_CM_CTRL BIT(3)
+#define MCUPM_PWR_CTRL_MASK GENMASK(3, 0)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_BUCK_MODE */
+#define MCUPM_BUCK_NORMAL_MODE U(0) /* default */
+#define MCUPM_BUCK_LP_MODE U(1)
+#define MCUPM_BUCK_OFF_MODE U(2)
+#define NF_MCUPM_BUCK_MODE U(3)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_ARMPLL_MODE */
+#define MCUPM_ARMPLL_ON U(0) /* default */
+#define MCUPM_ARMPLL_GATING U(1)
+#define MCUPM_ARMPLL_OFF U(2)
+#define NF_MCUPM_ARMPLL_MODE U(3)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_TASK_STA */
+#define MCUPM_TASK_UNINIT U(0)
+#define MCUPM_TASK_INIT U(1)
+#define MCUPM_TASK_INIT_FINISH U(2)
+#define MCUPM_TASK_WAIT U(3)
+#define MCUPM_TASK_RUN U(4)
+#define MCUPM_TASK_PAUSE U(5)
+
+#define SSPM_MBOX_3_BASE U(0x0c55fce0)
+
+#define MCDI_NOT_INIT 0
+#define MCDI_INIT_1 1
+#define MCDI_INIT_2 2
+#define MCDI_INIT_DONE 3
+
+static int mcdi_init_status __section("tzfw_coherent_mem");
+
+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);
+}
+
+static void mtk_mcupm_pwr_ctrl_setting(uint32_t dev)
+{
+ mcdi_mbox_write(APMCU_MCUPM_MBOX_PWR_CTRL_EN, dev);
+}
+
+static void mtk_set_mcupm_pll_mode(uint32_t mode)
+{
+ if (mode < NF_MCUPM_ARMPLL_MODE) {
+ mcdi_mbox_write(APMCU_MCUPM_MBOX_ARMPLL_MODE, mode);
+ }
+}
+
+static void mtk_set_mcupm_buck_mode(uint32_t mode)
+{
+ if (mode < NF_MCUPM_BUCK_MODE) {
+ mcdi_mbox_write(APMCU_MCUPM_MBOX_BUCK_MODE, mode);
+ }
+}
+
+static int mtk_mcupm_is_ready(void)
+{
+ unsigned int sta = mcdi_mbox_read(APMCU_MCUPM_MBOX_TASK_STA);
+
+ return (sta == MCUPM_TASK_WAIT) || (sta == MCUPM_TASK_INIT_FINISH);
+}
+
+static int mcdi_init_1(void)
+{
+ unsigned int sta = mcdi_mbox_read(APMCU_MCUPM_MBOX_TASK_STA);
+
+ if (sta != MCUPM_TASK_INIT) {
+ return -1;
+ }
+
+ mtk_set_mcupm_pll_mode(MCUPM_ARMPLL_OFF);
+ mtk_set_mcupm_buck_mode(MCUPM_BUCK_OFF_MODE);
+
+ mtk_mcupm_pwr_ctrl_setting(
+ MCUPM_MCUSYS_CTRL |
+ MCUPM_BUCK_CTRL |
+ MCUPM_ARMPLL_CTRL);
+
+ mcdi_mbox_write(APMCU_MCUPM_MBOX_AP_READY, 1);
+
+ return 0;
+}
+
+static int mcdi_init_2(void)
+{
+ return mtk_mcupm_is_ready() ? 0 : -1;
+}
+
+int mcdi_try_init(void)
+{
+ if (mcdi_init_status == MCDI_INIT_DONE) {
+ return 0;
+ }
+
+ if (mcdi_init_status == MCDI_NOT_INIT) {
+ mcdi_init_status = MCDI_INIT_1;
+ }
+
+ if (mcdi_init_status == MCDI_INIT_1 && mcdi_init_1() == 0) {
+ mcdi_init_status = MCDI_INIT_2;
+ }
+
+ if (mcdi_init_status == MCDI_INIT_2 && mcdi_init_2() == 0) {
+ mcdi_init_status = MCDI_INIT_DONE;
+ }
+
+ INFO("mcdi ready for mcusys-off-idle and system suspend\n");
+
+ return (mcdi_init_status == MCDI_INIT_DONE) ? 0 : mcdi_init_status;
+}
diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.h b/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.h
new file mode 100644
index 0000000..f3545aa
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_MCDI_H
+#define MT_MCDI_H
+
+int mcdi_try_init(void);
+
+#endif /* MT_MCDI_H */
diff --git a/plat/mediatek/mt8192/drivers/pmic/pmic_wrap_init.h b/plat/mediatek/mt8192/drivers/pmic/pmic_wrap_init.h
new file mode 100644
index 0000000..b9ab586
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/pmic/pmic_wrap_init.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMIC_WRAP_INIT_H
+#define PMIC_WRAP_INIT_H
+
+#include <stdint.h>
+
+#include "platform_def.h"
+#include <pmic_wrap_init_common.h>
+
+static struct mt8192_pmic_wrap_regs *const mtk_pwrap = (void *)PMIC_WRAP_BASE;
+
+/* PMIC_WRAP registers */
+struct mt8192_pmic_wrap_regs {
+ uint32_t init_done;
+ uint32_t reserved[799];
+ uint32_t wacs2_cmd;
+ uint32_t wacs2_wdata;
+ uint32_t reserved1[3];
+ uint32_t wacs2_rdata;
+ uint32_t reserved2[3];
+ uint32_t wacs2_vldclr;
+ uint32_t wacs2_sta;
+};
+
+#endif /* PMIC_WRAP_INIT_H */
diff --git a/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_common.h b/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_common.h
new file mode 100644
index 0000000..92c71bc
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_common.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_PTP3_H
+#define MTK_PTP3_H
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+/************************************************
+ * BIT Operation and REG r/w
+ ************************************************/
+#define ptp3_read(addr) mmio_read_32((uintptr_t)addr)
+#define ptp3_write(addr, val) mmio_write_32((uintptr_t)addr, val)
+
+/************************************************
+ * CPU info
+ ************************************************/
+#define NR_PTP3_CFG1_CPU U(8)
+#define PTP3_CFG1_CPU_START_ID U(0)
+#define PTP3_CFG1_MASK 0x00100000
+
+#define NR_PTP3_CFG2_CPU U(4)
+#define PTP3_CFG2_CPU_START_ID U(4)
+
+#define NR_PTP3_CFG3_CPU U(4)
+#define PTP3_CFG3_CPU_START_ID U(4)
+
+/************************************************
+ * config enum
+ ************************************************/
+enum PTP3_CFG {
+ PTP3_CFG_ADDR,
+ PTP3_CFG_VALUE,
+ NR_PTP3_CFG,
+};
+
+/************************************
+ * prototype
+ ************************************/
+/* init trigger for ptp3 feature */
+extern void ptp3_init(unsigned int core);
+extern void ptp3_deinit(unsigned int core);
+
+#endif /* MTK_PTP3_H */
diff --git a/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_main.c b/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_main.c
new file mode 100644
index 0000000..f1d8493
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_main.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved. \
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "mtk_ptp3_common.h"
+
+/************************************************
+ * Central control: turn on sysPi protection
+ ************************************************/
+static unsigned int ptp3_cfg1[NR_PTP3_CFG1_CPU][NR_PTP3_CFG] = {
+ {0x0C530610, 0x110842},
+ {0x0C530E10, 0x110842},
+ {0x0C531610, 0x110842},
+ {0x0C531E10, 0x110842},
+ {0x0C532610, 0x110842},
+ {0x0C532E10, 0x110842},
+ {0x0C533610, 0x110842},
+ {0x0C533E10, 0x110842}
+};
+static unsigned int ptp3_cfg2[NR_PTP3_CFG2_CPU][NR_PTP3_CFG] = {
+ {0x0C53B830, 0x68000},
+ {0x0C53BA30, 0x68000},
+ {0x0C53BC30, 0x68000},
+ {0x0C53BE30, 0x68000}
+};
+static unsigned int ptp3_cfg3[NR_PTP3_CFG3_CPU][NR_PTP3_CFG] = {
+ {0x0C532480, 0x7C607C6},
+ {0x0C532C80, 0x7C607C6},
+ {0x0C533480, 0x7C607C6},
+ {0x0C533C80, 0x7C607C6}
+};
+
+/************************************************
+ * API
+ ************************************************/
+void ptp3_init(unsigned int core)
+{
+ unsigned int _core;
+
+ /* Apply ptp3_cfg1 for core 0 to 7 */
+ if (core < NR_PTP3_CFG1_CPU) {
+ /* update ptp3_cfg1 */
+ ptp3_write(
+ ptp3_cfg1[core][PTP3_CFG_ADDR],
+ ptp3_cfg1[core][PTP3_CFG_VALUE]);
+ }
+
+ /* Apply ptp3_cfg2 for core 4 to 7 */
+ if (core >= PTP3_CFG2_CPU_START_ID) {
+ _core = core - PTP3_CFG2_CPU_START_ID;
+
+ if (_core < NR_PTP3_CFG2_CPU) {
+ /* update ptp3_cfg2 */
+ ptp3_write(
+ ptp3_cfg2[_core][PTP3_CFG_ADDR],
+ ptp3_cfg2[_core][PTP3_CFG_VALUE]);
+ }
+ }
+
+ /* Apply ptp3_cfg3 for core 4 to 7 */
+ if (core >= PTP3_CFG3_CPU_START_ID) {
+ _core = core - PTP3_CFG3_CPU_START_ID;
+
+ if (_core < NR_PTP3_CFG3_CPU) {
+ /* update ptp3_cfg3 */
+ ptp3_write(
+ ptp3_cfg3[_core][PTP3_CFG_ADDR],
+ ptp3_cfg3[_core][PTP3_CFG_VALUE]);
+ }
+ }
+}
+
+void ptp3_deinit(unsigned int core)
+{
+ if (core < NR_PTP3_CFG1_CPU) {
+ /* update ptp3_cfg1 */
+ ptp3_write(
+ ptp3_cfg1[core][PTP3_CFG_ADDR],
+ ptp3_cfg1[core][PTP3_CFG_VALUE] &
+ ~PTP3_CFG1_MASK);
+ }
+}
diff --git a/plat/mediatek/mt8192/drivers/spm/build.mk b/plat/mediatek/mt8192/drivers/spm/build.mk
new file mode 100644
index 0000000..4153603
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/build.mk
@@ -0,0 +1,68 @@
+#
+# Copyright (c) 2020, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Enable or disable spm feature
+MT_SPM_FEATURE_SUPPORT = yes
+
+# Enable or disable cirq restore
+MT_SPM_CIRQ_FEATURE_SUPPORT = yes
+
+# sspm notifier support
+MT_SPM_SSPM_NOTIFIER_SUPPORT = yes
+
+CUR_SPM_FOLDER = ${MTK_PLAT_SOC}/drivers/spm
+
+# spm common files
+PLAT_SPM_SOURCE_FILES_COMMON += \
+ ${CUR_SPM_FOLDER}/mt_spm.c \
+ ${CUR_SPM_FOLDER}/mt_spm_conservation.c \
+ ${CUR_SPM_FOLDER}/mt_spm_internal.c \
+ ${CUR_SPM_FOLDER}/mt_spm_pmic_wrap.c \
+ ${CUR_SPM_FOLDER}/mt_spm_vcorefs.c
+
+# spm platform dependcy files
+PLAT_SPM_SOURCE_FILES += \
+ ${CUR_SPM_FOLDER}/constraints/mt_spm_rc_bus26m.c \
+ ${CUR_SPM_FOLDER}/constraints/mt_spm_rc_cpu_buck_ldo.c \
+ ${CUR_SPM_FOLDER}/constraints/mt_spm_rc_dram.c \
+ ${CUR_SPM_FOLDER}/constraints/mt_spm_rc_syspll.c \
+ ${CUR_SPM_FOLDER}/mt_spm_cond.c \
+ ${CUR_SPM_FOLDER}/mt_spm_suspend.c \
+ ${CUR_SPM_FOLDER}/mt_spm_idle.c
+
+ifeq (${MT_SPM_FEATURE_SUPPORT}, no)
+PLAT_SPM_DEBUG_CFLAGS += -DATF_PLAT_SPM_UNSUPPORT
+BL31_MT_LPM_PLAT_SPM_SOURCE_FILES += ${PLAT_SPM_SOURCE_FILES_COMMON}
+else
+BL31_MT_LPM_PLAT_SPM_SOURCE_FILES += \
+ ${PLAT_SPM_SOURCE_FILES_COMMON} \
+ ${PLAT_SPM_SOURCE_FILES}
+endif
+
+ifeq (${MT_SPM_CIRQ_FEATURE_SUPPORT}, no)
+PLAT_SPM_DEBUG_CFLAGS += -DATF_PLAT_CIRQ_UNSUPPORT
+endif
+
+ifeq (${MT_SPM_SSPM_NOTIFIER_SUPPORT}, no)
+PLAT_SPM_DEBUG_CFLAGS += -DATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+else
+BL31_MT_LPM_PLAT_SPM_SOURCE_FILES += \
+ ${CUR_SPM_FOLDER}/notifier/mt_spm_sspm_notifier.c
+endif
+
+$(info --------------------------------------)
+$(info SPM build flags: ${PLAT_SPM_DEBUG_CFLAGS})
+$(info SPM build files: ${BL31_MT_LPM_PLAT_SPM_SOURCE_FILES})
+$(info --------------------------------------)
+
+# Common makefile for platform.mk
+PLAT_INCLUDES += \
+ ${PLAT_SPM_DEBUG_CFLAGS} \
+ -I${CUR_SPM_FOLDER}/ \
+ -I${CUR_SPM_FOLDER}/constraints/ \
+ -I${CUR_SPM_FOLDER}/notifier/
+
+PLAT_BL_COMMON_SOURCES += ${BL31_MT_LPM_PLAT_SPM_SOURCE_FILES}
diff --git a/plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_bus26m.c b/plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_bus26m.c
new file mode 100644
index 0000000..18c43b1
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_bus26m.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#include <mt_lp_rm.h>
+#include <mt_spm.h>
+#include <mt_spm_cond.h>
+#include <mt_spm_constraint.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_idle.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_notifier.h>
+#include <mt_spm_rc_internal.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_suspend.h>
+#include <plat_pm.h>
+#include <plat_mtk_lpm.h>
+
+#ifndef ATF_PLAT_CIRQ_UNSUPPORT
+#include <mt_cirq.h>
+#include <mt_gic_v3.h>
+#endif
+
+#define CONSTRAINT_BUS26M_ALLOW \
+ (MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF | \
+ MT_RM_CONSTRAINT_ALLOW_DRAM_S0 | \
+ MT_RM_CONSTRAINT_ALLOW_DRAM_S1 | \
+ MT_RM_CONSTRAINT_ALLOW_VCORE_LP | \
+ MT_RM_CONSTRAINT_ALLOW_LVTS_STATE | \
+ MT_RM_CONSTRAINT_ALLOW_BUS26M_OFF)
+
+#define CONSTRAINT_BUS26M_PCM_FLAG \
+ (SPM_FLAG_DISABLE_INFRA_PDN | \
+ SPM_FLAG_DISABLE_VCORE_DVS | \
+ SPM_FLAG_DISABLE_VCORE_DFS | \
+ SPM_FLAG_SRAM_SLEEP_CTRL | \
+ SPM_FLAG_ENABLE_TIA_WORKAROUND | \
+ SPM_FLAG_ENABLE_LVTS_WORKAROUND | \
+ SPM_FLAG_KEEP_CSYSPWRACK_HIGH)
+
+#define CONSTRAINT_BUS26M_PCM_FLAG1 \
+ (SPM_FLAG1_DISABLE_MD26M_CK_OFF)
+
+#define CONSTRAINT_BUS26M_RESOURCE_REQ 0U
+
+static unsigned int bus26m_ext_opand;
+static struct mt_irqremain *refer2remain_irq;
+static struct mt_spm_cond_tables cond_bus26m = {
+ .name = "bus26m",
+ .table_cg = {
+ 0x07CBF1FC, /* MTCMOS1 */
+ 0x0A0D8856, /* INFRA0 */
+ 0x03AF9A00, /* INFRA1 */
+ 0x86000650, /* INFRA2 */
+ 0xC800C000, /* INFRA3 */
+ 0x00000000, /* INFRA4 */
+ 0x4000007C, /* INFRA5 */
+ 0x280E0800, /* MMSYS0 */
+ 0x00000001, /* MMSYS1 */
+ 0x00000000, /* MMSYS2 */
+ },
+ .table_pll = (PLL_BIT_UNIVPLL | PLL_BIT_MFGPLL |
+ PLL_BIT_MSDCPLL | PLL_BIT_TVDPLL |
+ PLL_BIT_MMPLL),
+};
+
+static struct mt_spm_cond_tables cond_bus26m_res = {
+ .table_cg = { 0U },
+ .table_pll = 0U,
+};
+
+static struct constraint_status status = {
+ .id = MT_RM_CONSTRAINT_ID_BUS26M,
+ .valid = (MT_SPM_RC_VALID_SW |
+ MT_SPM_RC_VALID_COND_LATCH),
+ .cond_block = 0U,
+ .enter_cnt = 0U,
+ .cond_res = &cond_bus26m_res,
+};
+
+/*
+ * Cirq will take the place of gic when gic is off.
+ * However, cirq cannot work if 26m clk is turned off when system idle/suspend.
+ * Therefore, we need to set irq pending for specific wakeup source.
+ */
+#ifdef ATF_PLAT_CIRQ_UNSUPPORT
+#define do_irqs_delivery()
+#else
+static void mt_spm_irq_remain_dump(struct mt_irqremain *irqs,
+ unsigned int irq_index,
+ struct wake_status *wakeup)
+{
+ INFO("[SPM] r12 = 0x%08x(0x%08x), flag = 0x%08x 0x%08x 0x%08x\n",
+ wakeup->tr.comm.r12, wakeup->md32pcm_wakeup_sta,
+ wakeup->tr.comm.debug_flag, wakeup->tr.comm.b_sw_flag0,
+ wakeup->tr.comm.b_sw_flag1);
+
+ INFO("irq:%u(0x%08x) set pending\n",
+ irqs->wakeupsrc[irq_index], irqs->irqs[irq_index]);
+}
+
+static void do_irqs_delivery(void)
+{
+ unsigned int idx;
+ int res = 0;
+ struct wake_status *wakeup = NULL;
+ struct mt_irqremain *irqs = refer2remain_irq;
+
+ res = spm_conservation_get_result(&wakeup);
+
+ if ((res != 0) && (irqs == NULL)) {
+ return;
+ }
+
+ for (idx = 0U; idx < irqs->count; ++idx) {
+ if (((wakeup->tr.comm.r12 & irqs->wakeupsrc[idx]) != 0U) ||
+ ((wakeup->raw_sta & irqs->wakeupsrc[idx]) != 0U)) {
+ if ((irqs->wakeupsrc_cat[idx] &
+ MT_IRQ_REMAIN_CAT_LOG) != 0U) {
+ mt_spm_irq_remain_dump(irqs, idx, wakeup);
+ }
+
+ mt_irq_set_pending(irqs->irqs[idx]);
+ }
+ }
+}
+#endif
+
+static void spm_bus26m_conduct(struct spm_lp_scen *spm_lp,
+ unsigned int *resource_req)
+{
+ spm_lp->pwrctrl->pcm_flags = (uint32_t)CONSTRAINT_BUS26M_PCM_FLAG;
+ spm_lp->pwrctrl->pcm_flags1 = (uint32_t)CONSTRAINT_BUS26M_PCM_FLAG1;
+ *resource_req |= CONSTRAINT_BUS26M_RESOURCE_REQ;
+}
+
+bool spm_is_valid_rc_bus26m(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+ (void)state_id;
+
+ return (status.cond_block == 0U) && IS_MT_RM_RC_READY(status.valid);
+}
+
+int spm_update_rc_bus26m(int state_id, int type, const void *val)
+{
+ const struct mt_spm_cond_tables *tlb;
+ const struct mt_spm_cond_tables *tlb_check;
+ int res = MT_RM_STATUS_OK;
+
+ if (val == NULL) {
+ return MT_RM_STATUS_BAD;
+ }
+
+ if (type == PLAT_RC_UPDATE_CONDITION) {
+ tlb = (const struct mt_spm_cond_tables *)val;
+ tlb_check = (const struct mt_spm_cond_tables *)&cond_bus26m;
+
+ status.cond_block =
+ mt_spm_cond_check(state_id, tlb, tlb_check,
+ ((status.valid &
+ MT_SPM_RC_VALID_COND_LATCH) != 0U) ?
+ &cond_bus26m_res : NULL);
+ } else if (type == PLAT_RC_UPDATE_REMAIN_IRQS) {
+ refer2remain_irq = (struct mt_irqremain *)val;
+ } else {
+ res = MT_RM_STATUS_BAD;
+ }
+
+ return res;
+}
+
+unsigned int spm_allow_rc_bus26m(int state_id)
+{
+ (void)state_id;
+
+ return CONSTRAINT_BUS26M_ALLOW;
+}
+
+int spm_run_rc_bus26m(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_ENTER, CONSTRAINT_BUS26M_ALLOW |
+ (IS_PLAT_SUSPEND_ID(state_id) ?
+ MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND : 0U));
+#endif
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_enter(state_id,
+ (MT_SPM_EX_OP_SET_WDT |
+ MT_SPM_EX_OP_HW_S1_DETECT |
+ bus26m_ext_opand),
+ CONSTRAINT_BUS26M_RESOURCE_REQ);
+ } else {
+ mt_spm_idle_generic_enter(state_id, MT_SPM_EX_OP_HW_S1_DETECT,
+ spm_bus26m_conduct);
+ }
+
+ return 0;
+}
+
+int spm_reset_rc_bus26m(unsigned int cpu, int state_id)
+{
+ unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
+
+ (void)cpu;
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_LEAVE, 0U);
+#endif
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ ext_op |= (bus26m_ext_opand | MT_SPM_EX_OP_SET_WDT);
+ mt_spm_suspend_resume(state_id, ext_op, NULL);
+ bus26m_ext_opand = 0U;
+ } else {
+ mt_spm_idle_generic_resume(state_id, ext_op, NULL);
+ status.enter_cnt++;
+ }
+
+ do_irqs_delivery();
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_cpu_buck_ldo.c b/plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_cpu_buck_ldo.c
new file mode 100644
index 0000000..9618f3b
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_cpu_buck_ldo.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#include <mt_spm.h>
+#include <mt_spm_cond.h>
+#include <mt_spm_constraint.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_idle.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_notifier.h>
+#include <mt_spm_rc_internal.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_suspend.h>
+#include <plat_pm.h>
+
+#define CONSTRAINT_CPU_BUCK_PCM_FLAG \
+ (SPM_FLAG_DISABLE_INFRA_PDN | \
+ SPM_FLAG_DISABLE_VCORE_DVS | \
+ SPM_FLAG_DISABLE_VCORE_DFS | \
+ SPM_FLAG_SRAM_SLEEP_CTRL | \
+ SPM_FLAG_KEEP_CSYSPWRACK_HIGH)
+
+#define CONSTRAINT_CPU_BUCK_PCM_FLAG1 0U
+
+#define CONSTRAINT_CPU_BUCK_RESOURCE_REQ \
+ (MT_SPM_DRAM_S1 | \
+ MT_SPM_DRAM_S0 | \
+ MT_SPM_SYSPLL | \
+ MT_SPM_INFRA | \
+ MT_SPM_26M | \
+ MT_SPM_XO_FPM)
+
+
+static unsigned int cpubuckldo_status = MT_SPM_RC_VALID_SW;
+static unsigned int cpubuckldo_enter_cnt;
+
+static void spm_cpu_bcuk_ldo_conduct(struct spm_lp_scen *spm_lp,
+ unsigned int *resource_req)
+{
+ spm_lp->pwrctrl->pcm_flags = (uint32_t)CONSTRAINT_CPU_BUCK_PCM_FLAG;
+ spm_lp->pwrctrl->pcm_flags1 = (uint32_t)CONSTRAINT_CPU_BUCK_PCM_FLAG1;
+ *resource_req |= CONSTRAINT_CPU_BUCK_RESOURCE_REQ;
+}
+
+bool spm_is_valid_rc_cpu_buck_ldo(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+ (void)state_id;
+
+ return IS_MT_RM_RC_READY(cpubuckldo_status);
+}
+
+unsigned int spm_allow_rc_cpu_buck_ldo(int state_id)
+{
+ (void)state_id;
+
+ return MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF;
+}
+
+int spm_run_rc_cpu_buck_ldo(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_ENTER,
+ (IS_PLAT_SUSPEND_ID(state_id) ?
+ MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND : 0U));
+#endif
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_enter(state_id,
+ MT_SPM_EX_OP_SET_WDT,
+ CONSTRAINT_CPU_BUCK_RESOURCE_REQ);
+ } else {
+ mt_spm_idle_generic_enter(state_id, 0U,
+ spm_cpu_bcuk_ldo_conduct);
+ }
+
+ cpubuckldo_enter_cnt++;
+
+ return 0;
+}
+
+int spm_reset_rc_cpu_buck_ldo(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_LEAVE, 0U);
+#endif
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_resume(state_id, MT_SPM_EX_OP_SET_WDT, NULL);
+ } else {
+ mt_spm_idle_generic_resume(state_id, 0U, NULL);
+ }
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_dram.c b/plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_dram.c
new file mode 100644
index 0000000..34293c4
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_dram.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#include <mt_lp_rm.h>
+#include <mt_spm.h>
+#include <mt_spm_cond.h>
+#include <mt_spm_constraint.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_idle.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_notifier.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_rc_internal.h>
+#include <mt_spm_suspend.h>
+#include <plat_pm.h>
+#include <plat_mtk_lpm.h>
+
+#define CONSTRAINT_DRAM_ALLOW \
+ (MT_RM_CONSTRAINT_ALLOW_DRAM_S0 | \
+ MT_RM_CONSTRAINT_ALLOW_DRAM_S1 | \
+ MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF)
+
+#define CONSTRAINT_DRAM_PCM_FLAG \
+ (SPM_FLAG_DISABLE_INFRA_PDN | \
+ SPM_FLAG_DISABLE_VCORE_DVS | \
+ SPM_FLAG_DISABLE_VCORE_DFS | \
+ SPM_FLAG_SRAM_SLEEP_CTRL | \
+ SPM_FLAG_KEEP_CSYSPWRACK_HIGH)
+
+#define CONSTRAINT_DRAM_PCM_FLAG1 0U
+
+#define CONSTRAINT_DRAM_RESOURCE_REQ \
+ (MT_SPM_SYSPLL | \
+ MT_SPM_INFRA | \
+ MT_SPM_26M)
+
+static struct mt_spm_cond_tables cond_dram = {
+ .name = "dram",
+ .table_cg = {
+ 0x078BF1FC, /* MTCMOS1 */
+ 0x080D8856, /* INFRA0 */
+ 0x03AF9A00, /* INFRA1 */
+ 0x86000640, /* INFRA2 */
+ 0xC800C000, /* INFRA3 */
+ 0x00000000, /* INFRA4 */
+ 0x00000000, /* INFRA5 */
+ 0x200C0000, /* MMSYS0 */
+ 0x00000000, /* MMSYS1 */
+ 0x00000000, /* MMSYS2 */
+ },
+ .table_pll = 0U,
+};
+
+static struct mt_spm_cond_tables cond_dram_res = {
+ .table_cg = { 0U },
+ .table_pll = 0U,
+};
+
+static struct constraint_status status = {
+ .id = MT_RM_CONSTRAINT_ID_DRAM,
+ .valid = (MT_SPM_RC_VALID_SW |
+ MT_SPM_RC_VALID_COND_LATCH |
+ MT_SPM_RC_VALID_XSOC_BBLPM),
+ .cond_block = 0U,
+ .enter_cnt = 0U,
+ .cond_res = &cond_dram_res,
+};
+
+static void spm_dram_conduct(struct spm_lp_scen *spm_lp,
+ unsigned int *resource_req)
+{
+ spm_lp->pwrctrl->pcm_flags = (uint32_t)CONSTRAINT_DRAM_PCM_FLAG;
+ spm_lp->pwrctrl->pcm_flags1 = (uint32_t)CONSTRAINT_DRAM_PCM_FLAG1;
+ *resource_req |= CONSTRAINT_DRAM_RESOURCE_REQ;
+}
+
+bool spm_is_valid_rc_dram(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+ (void)state_id;
+
+ return (status.cond_block == 0U) && IS_MT_RM_RC_READY(status.valid);
+}
+
+int spm_update_rc_dram(int state_id, int type, const void *val)
+{
+ const struct mt_spm_cond_tables *tlb;
+ const struct mt_spm_cond_tables *tlb_check;
+ int res = MT_RM_STATUS_OK;
+
+ if (val == NULL) {
+ return MT_RM_STATUS_BAD;
+ }
+
+ if (type == PLAT_RC_UPDATE_CONDITION) {
+ tlb = (const struct mt_spm_cond_tables *)val;
+ tlb_check = (const struct mt_spm_cond_tables *)&cond_dram;
+ status.cond_block =
+ mt_spm_cond_check(state_id, tlb, tlb_check,
+ ((status.valid &
+ MT_SPM_RC_VALID_COND_LATCH) != 0U) ?
+ &cond_dram_res : NULL);
+ } else {
+ res = MT_RM_STATUS_BAD;
+ }
+
+ return res;
+}
+
+unsigned int spm_allow_rc_dram(int state_id)
+{
+ (void)state_id;
+
+ return CONSTRAINT_DRAM_ALLOW;
+}
+
+int spm_run_rc_dram(unsigned int cpu, int state_id)
+{
+ unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
+ unsigned int allows = CONSTRAINT_DRAM_ALLOW;
+
+ (void)cpu;
+
+ if (IS_MT_SPM_RC_BBLPM_MODE(status.valid)) {
+#ifdef MT_SPM_USING_SRCLKEN_RC
+ ext_op |= MT_SPM_EX_OP_SRCLKEN_RC_BBLPM;
+#else
+ allows |= MT_RM_CONSTRAINT_ALLOW_BBLPM;
+#endif
+ }
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_ENTER, allows |
+ (IS_PLAT_SUSPEND_ID(state_id) ?
+ MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND : 0U));
+#else
+ (void)allows;
+#endif
+
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_enter(state_id,
+ (MT_SPM_EX_OP_SET_WDT |
+ MT_SPM_EX_OP_HW_S1_DETECT),
+ CONSTRAINT_DRAM_RESOURCE_REQ);
+ } else {
+ mt_spm_idle_generic_enter(state_id, ext_op, spm_dram_conduct);
+ }
+
+ return 0;
+}
+
+int spm_reset_rc_dram(unsigned int cpu, int state_id)
+{
+ unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
+ unsigned int allows = CONSTRAINT_DRAM_ALLOW;
+
+ (void)cpu;
+
+ if (IS_MT_SPM_RC_BBLPM_MODE(status.valid)) {
+#ifdef MT_SPM_USING_SRCLKEN_RC
+ ext_op |= MT_SPM_EX_OP_SRCLKEN_RC_BBLPM;
+#else
+ allows |= MT_RM_CONSTRAINT_ALLOW_BBLPM;
+#endif
+ }
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_LEAVE, allows);
+#else
+ (void)allows;
+#endif
+
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_resume(state_id,
+ (MT_SPM_EX_OP_SET_WDT |
+ MT_SPM_EX_OP_HW_S1_DETECT),
+ NULL);
+ } else {
+ mt_spm_idle_generic_resume(state_id, ext_op, NULL);
+ status.enter_cnt++;
+ }
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_internal.h b/plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_internal.h
new file mode 100644
index 0000000..aeb778a
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_internal.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_RC_INTERNAL_H
+#define MT_SPM_RC_INTERNAL_H
+
+#include <stdbool.h>
+
+#define SPM_FLAG_SRAM_SLEEP_CTRL \
+ (SPM_FLAG_DISABLE_SSPM_SRAM_SLEEP | \
+ SPM_FLAG_DISABLE_DRAMC_MCU_SRAM_SLEEP | \
+ SPM_FLAG_DISABLE_SYSRAM_SLEEP | \
+ SPM_FLAG_DISABLE_MCUPM_SRAM_SLEEP | \
+ SPM_FLAG_DISABLE_SRAM_EVENT)
+
+/* cpu buck/ldo constraint function */
+bool spm_is_valid_rc_cpu_buck_ldo(unsigned int cpu, int state_id);
+unsigned int spm_allow_rc_cpu_buck_ldo(int state_id);
+int spm_run_rc_cpu_buck_ldo(unsigned int cpu, int state_id);
+int spm_reset_rc_cpu_buck_ldo(unsigned int cpu, int state_id);
+
+/* spm resource dram constraint function */
+bool spm_is_valid_rc_dram(unsigned int cpu, int state_id);
+int spm_update_rc_dram(int state_id, int type, const void *val);
+unsigned int spm_allow_rc_dram(int state_id);
+int spm_run_rc_dram(unsigned int cpu, int state_id);
+int spm_reset_rc_dram(unsigned int cpu, int state_id);
+
+/* spm resource syspll constraint function */
+bool spm_is_valid_rc_syspll(unsigned int cpu, int state_id);
+int spm_update_rc_syspll(int state_id, int type, const void *val);
+unsigned int spm_allow_rc_syspll(int state_id);
+int spm_run_rc_syspll(unsigned int cpu, int state_id);
+int spm_reset_rc_syspll(unsigned int cpu, int state_id);
+
+/* spm resource bus26m constraint function */
+bool spm_is_valid_rc_bus26m(unsigned int cpu, int state_id);
+int spm_update_rc_bus26m(int state_id, int type, const void *val);
+unsigned int spm_allow_rc_bus26m(int state_id);
+int spm_run_rc_bus26m(unsigned int cpu, int state_id);
+int spm_reset_rc_bus26m(unsigned int cpu, int state_id);
+#endif /* MT_SPM_RC_INTERNAL_H */
diff --git a/plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_syspll.c b/plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_syspll.c
new file mode 100644
index 0000000..8d76d63
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/constraints/mt_spm_rc_syspll.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+
+#include <mt_lp_rm.h>
+#include <mt_spm.h>
+#include <mt_spm_cond.h>
+#include <mt_spm_constraint.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_idle.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_notifier.h>
+#include <mt_spm_rc_internal.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_suspend.h>
+#include <plat_pm.h>
+#include <plat_mtk_lpm.h>
+
+#define CONSTRAINT_SYSPLL_ALLOW \
+ (MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF | \
+ MT_RM_CONSTRAINT_ALLOW_DRAM_S0 | \
+ MT_RM_CONSTRAINT_ALLOW_DRAM_S1 | \
+ MT_RM_CONSTRAINT_ALLOW_VCORE_LP)
+
+#define CONSTRAINT_SYSPLL_PCM_FLAG \
+ (SPM_FLAG_DISABLE_INFRA_PDN | \
+ SPM_FLAG_DISABLE_VCORE_DVS | \
+ SPM_FLAG_DISABLE_VCORE_DFS | \
+ SPM_FLAG_SRAM_SLEEP_CTRL | \
+ SPM_FLAG_KEEP_CSYSPWRACK_HIGH | \
+ SPM_FLAG_ENABLE_6315_CTRL | \
+ SPM_FLAG_USE_SRCCLKENO2)
+
+#define CONSTRAINT_SYSPLL_PCM_FLAG1 0U
+#define CONSTRAINT_SYSPLL_RESOURCE_REQ \
+ (MT_SPM_26M)
+
+static struct mt_spm_cond_tables cond_syspll = {
+ .name = "syspll",
+ .table_cg = {
+ 0x078BF1FC, /* MTCMOS1 */
+ 0x080D8856, /* INFRA0 */
+ 0x03AF9A00, /* INFRA1 */
+ 0x86000640, /* INFRA2 */
+ 0xC800C000, /* INFRA3 */
+ 0x00000000, /* INFRA4 */
+ 0x0000007C, /* INFRA5 */
+ 0x280E0800, /* MMSYS0 */
+ 0x00000001, /* MMSYS1 */
+ 0x00000000, /* MMSYS2 */
+ },
+ .table_pll = 0U,
+};
+
+static struct mt_spm_cond_tables cond_syspll_res = {
+ .table_cg = { 0U },
+ .table_pll = 0U,
+};
+
+static struct constraint_status status = {
+ .id = MT_RM_CONSTRAINT_ID_SYSPLL,
+ .valid = (MT_SPM_RC_VALID_SW |
+ MT_SPM_RC_VALID_COND_LATCH |
+ MT_SPM_RC_VALID_XSOC_BBLPM),
+ .cond_block = 0U,
+ .enter_cnt = 0U,
+ .cond_res = &cond_syspll_res,
+};
+
+static void spm_syspll_conduct(struct spm_lp_scen *spm_lp,
+ unsigned int *resource_req)
+{
+ spm_lp->pwrctrl->pcm_flags = (uint32_t)CONSTRAINT_SYSPLL_PCM_FLAG;
+ spm_lp->pwrctrl->pcm_flags1 = (uint32_t)CONSTRAINT_SYSPLL_PCM_FLAG1;
+ *resource_req |= CONSTRAINT_SYSPLL_RESOURCE_REQ;
+}
+
+bool spm_is_valid_rc_syspll(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+ (void)state_id;
+
+ return (status.cond_block == 0U) && IS_MT_RM_RC_READY(status.valid);
+}
+
+int spm_update_rc_syspll(int state_id, int type, const void *val)
+{
+ const struct mt_spm_cond_tables *tlb;
+ const struct mt_spm_cond_tables *tlb_check;
+ int res = MT_RM_STATUS_OK;
+
+ if (val == NULL) {
+ return MT_RM_STATUS_BAD;
+ }
+
+ if (type == PLAT_RC_UPDATE_CONDITION) {
+ tlb = (const struct mt_spm_cond_tables *)val;
+ tlb_check = (const struct mt_spm_cond_tables *)&cond_syspll;
+
+ status.cond_block =
+ mt_spm_cond_check(state_id, tlb, tlb_check,
+ ((status.valid &
+ MT_SPM_RC_VALID_COND_LATCH) != 0U) ?
+ &cond_syspll_res : NULL);
+ } else {
+ res = MT_RM_STATUS_BAD;
+ }
+
+ return res;
+}
+
+unsigned int spm_allow_rc_syspll(int state_id)
+{
+ (void)state_id;
+
+ return CONSTRAINT_SYSPLL_ALLOW;
+}
+
+int spm_run_rc_syspll(unsigned int cpu, int state_id)
+{
+ unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
+ unsigned int allows = CONSTRAINT_SYSPLL_ALLOW;
+
+ (void)cpu;
+
+ if (IS_MT_SPM_RC_BBLPM_MODE(status.valid)) {
+#ifdef MT_SPM_USING_SRCLKEN_RC
+ ext_op |= MT_SPM_EX_OP_SRCLKEN_RC_BBLPM;
+#else
+ allows |= MT_RM_CONSTRAINT_ALLOW_BBLPM;
+#endif
+ }
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_ENTER, allows |
+ (IS_PLAT_SUSPEND_ID(state_id) ?
+ MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND : 0U));
+#else
+ (void)allows;
+#endif
+
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_enter(state_id,
+ (MT_SPM_EX_OP_SET_WDT |
+ MT_SPM_EX_OP_HW_S1_DETECT |
+ MT_SPM_EX_OP_SET_SUSPEND_MODE),
+ CONSTRAINT_SYSPLL_RESOURCE_REQ);
+ } else {
+ mt_spm_idle_generic_enter(state_id, ext_op, spm_syspll_conduct);
+ }
+
+ return 0;
+}
+
+int spm_reset_rc_syspll(unsigned int cpu, int state_id)
+{
+ unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
+ unsigned int allows = CONSTRAINT_SYSPLL_ALLOW;
+
+ (void)cpu;
+
+ if (IS_MT_SPM_RC_BBLPM_MODE(status.valid)) {
+#ifdef MT_SPM_USING_SRCLKEN_RC
+ ext_op |= MT_SPM_EX_OP_SRCLKEN_RC_BBLPM;
+#else
+ allows |= MT_RM_CONSTRAINT_ALLOW_BBLPM;
+#endif
+ }
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_LEAVE, allows);
+#else
+ (void)allows;
+#endif
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_resume(state_id,
+ (MT_SPM_EX_OP_SET_SUSPEND_MODE |
+ MT_SPM_EX_OP_SET_WDT |
+ MT_SPM_EX_OP_HW_S1_DETECT),
+ NULL);
+ } else {
+ mt_spm_idle_generic_resume(state_id, ext_op, NULL);
+ status.enter_cnt++;
+ }
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm.c b/plat/mediatek/mt8192/drivers/spm/mt_spm.c
new file mode 100644
index 0000000..f4505b6
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <common/debug.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <mt_lp_rm.h>
+#include <mt_spm.h>
+#include <mt_spm_cond.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_constraint.h>
+#include <mt_spm_idle.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_pmic_wrap.h>
+#include <mt_spm_rc_internal.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_suspend.h>
+#include <mtk_plat_common.h>
+#include <plat_mtk_lpm.h>
+#include <plat_pm.h>
+#include <platform_def.h>
+#include <sleep_def.h>
+
+#ifdef MT_SPM_USING_BAKERY_LOCK
+DEFINE_BAKERY_LOCK(spm_lock);
+#define plat_spm_lock_init() bakery_lock_init(&spm_lock)
+#else
+spinlock_t spm_lock;
+#define plat_spm_lock_init()
+#endif
+
+/* CLK_SCP_CFG_0 */
+#define CLK_SCP_CFG_0 (TOPCKGEN_BASE + 0x200)
+#define SPM_CK_CONTROL_EN 0x3FF
+
+/* CLK_SCP_CFG_1 */
+#define CLK_SCP_CFG_1 (TOPCKGEN_BASE + 0x210)
+#define CLK_SCP_CFG_1_MASK 0x100C
+#define CLK_SCP_CFG_1_SPM 0x3
+
+struct mt_resource_constraint plat_constraint_bus26m = {
+ .is_valid = spm_is_valid_rc_bus26m,
+ .update = spm_update_rc_bus26m,
+ .allow = spm_allow_rc_bus26m,
+ .run = spm_run_rc_bus26m,
+ .reset = spm_reset_rc_bus26m,
+};
+
+struct mt_resource_constraint plat_constraint_syspll = {
+ .is_valid = spm_is_valid_rc_syspll,
+ .update = spm_update_rc_syspll,
+ .allow = spm_allow_rc_syspll,
+ .run = spm_run_rc_syspll,
+ .reset = spm_reset_rc_syspll,
+};
+
+struct mt_resource_constraint plat_constraint_dram = {
+ .is_valid = spm_is_valid_rc_dram,
+ .update = spm_update_rc_dram,
+ .allow = spm_allow_rc_dram,
+ .run = spm_run_rc_dram,
+ .reset = spm_reset_rc_dram,
+};
+
+struct mt_resource_constraint plat_constraint_cpu = {
+ .is_valid = spm_is_valid_rc_cpu_buck_ldo,
+ .update = NULL,
+ .allow = spm_allow_rc_cpu_buck_ldo,
+ .run = spm_run_rc_cpu_buck_ldo,
+ .reset = spm_reset_rc_cpu_buck_ldo,
+};
+
+struct mt_resource_constraint *plat_constraints[] = {
+ &plat_constraint_bus26m,
+ &plat_constraint_syspll,
+ &plat_constraint_dram,
+ &plat_constraint_cpu,
+ NULL,
+};
+
+struct mt_resource_manager plat_mt8192_rm = {
+ .update = mt_spm_cond_update,
+ .consts = plat_constraints,
+};
+
+void spm_boot_init(void)
+{
+ /* switch ck_off/axi_26m control to SPM */
+ mmio_setbits_32(CLK_SCP_CFG_0, SPM_CK_CONTROL_EN);
+ mmio_clrsetbits_32(CLK_SCP_CFG_1, CLK_SCP_CFG_1_MASK,
+ CLK_SCP_CFG_1_SPM);
+
+ plat_spm_lock_init();
+ mt_spm_pmic_wrap_set_phase(PMIC_WRAP_PHASE_ALLINONE);
+ mt_lp_rm_register(&plat_mt8192_rm);
+ mt_spm_idle_generic_init();
+ mt_spm_suspend_init();
+}
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm.h b/plat/mediatek/mt8192/drivers/spm/mt_spm.h
new file mode 100644
index 0000000..b147fe2
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_H
+#define MT_SPM_H
+
+#include <lib/bakery_lock.h>
+#include <lib/spinlock.h>
+
+#include <plat_mtk_lpm.h>
+
+/*
+ * ARM v8.2, the cache will turn off automatically when cpu
+ * power down. So, there is no doubt to use the spin_lock here
+ */
+#if !HW_ASSISTED_COHERENCY
+#define MT_SPM_USING_BAKERY_LOCK
+#endif
+
+#ifdef MT_SPM_USING_BAKERY_LOCK
+DECLARE_BAKERY_LOCK(spm_lock);
+#define plat_spm_lock() bakery_lock_get(&spm_lock)
+#define plat_spm_unlock() bakery_lock_release(&spm_lock)
+#else
+extern spinlock_t spm_lock;
+#define plat_spm_lock() spin_lock(&spm_lock)
+#define plat_spm_unlock() spin_unlock(&spm_lock)
+#endif
+
+#define MT_SPM_USING_SRCLKEN_RC
+
+/* spm extern operand definition */
+#define MT_SPM_EX_OP_CLR_26M_RECORD (1U << 0)
+#define MT_SPM_EX_OP_SET_WDT (1U << 1)
+#define MT_SPM_EX_OP_NON_GENERIC_RESOURCE_REQ (1U << 2)
+#define MT_SPM_EX_OP_SET_SUSPEND_MODE (1U << 3)
+#define MT_SPM_EX_OP_SET_IS_ADSP (1U << 4)
+#define MT_SPM_EX_OP_SRCLKEN_RC_BBLPM (1U << 5)
+#define MT_SPM_EX_OP_HW_S1_DETECT (1U << 6)
+
+typedef enum {
+ WR_NONE = 0,
+ WR_UART_BUSY = 1,
+ WR_ABORT = 2,
+ WR_PCM_TIMER = 3,
+ WR_WAKE_SRC = 4,
+ WR_DVFSRC = 5,
+ WR_TWAM = 6,
+ WR_PMSR = 7,
+ WR_SPM_ACK_CHK = 8,
+ WR_UNKNOWN = 9,
+} wake_reason_t;
+
+static inline void spm_lock_get(void)
+{
+ plat_spm_lock();
+}
+
+static inline void spm_lock_release(void)
+{
+ plat_spm_unlock();
+}
+
+extern void spm_boot_init(void);
+#endif /* MT_SPM_H */
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm_cond.c b/plat/mediatek/mt8192/drivers/spm/mt_spm_cond.c
new file mode 100644
index 0000000..2d67fdf
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm_cond.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <mt_spm_cond.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_constraint.h>
+#include <plat_mtk_lpm.h>
+#include <plat_pm.h>
+#include <platform_def.h>
+
+#define MT_LP_TZ_INFRA_REG(ofs) (INFRACFG_AO_BASE + ofs)
+#define MT_LP_TZ_MM_REG(ofs) (MMSYS_BASE + ofs)
+#define MT_LP_TZ_SPM_REG(ofs) (SPM_BASE + ofs)
+#define MT_LP_TZ_TOPCK_REG(ofs) (TOPCKGEN_BASE + ofs)
+#define MT_LP_TZ_APMIXEDSYS(ofs) (APMIXEDSYS + ofs)
+
+#define SPM_PWR_STATUS MT_LP_TZ_SPM_REG(0x016C)
+#define SPM_PWR_STATUS_2ND MT_LP_TZ_SPM_REG(0x0170)
+#define INFRA_SW_CG0 MT_LP_TZ_INFRA_REG(0x0094)
+#define INFRA_SW_CG1 MT_LP_TZ_INFRA_REG(0x0090)
+#define INFRA_SW_CG2 MT_LP_TZ_INFRA_REG(0x00AC)
+#define INFRA_SW_CG3 MT_LP_TZ_INFRA_REG(0x00C8)
+#define INFRA_SW_CG4 MT_LP_TZ_INFRA_REG(0x00D8)
+#define INFRA_SW_CG5 MT_LP_TZ_INFRA_REG(0x00E8)
+#define MMSYS_CG_CON0 MT_LP_TZ_MM_REG(0x100)
+#define MMSYS_CG_CON1 MT_LP_TZ_MM_REG(0x110)
+#define MMSYS_CG_CON2 MT_LP_TZ_MM_REG(0x1A0)
+
+/***********************************************************
+ * Check clkmux registers
+ ***********************************************************/
+#define CLK_CFG(id) MT_LP_TZ_TOPCK_REG(0x20 + id * 0x10)
+#define PDN_CHECK BIT(7)
+#define CLK_CHECK BIT(31)
+
+enum {
+ CLKMUX_DISP = 0,
+ CLKMUX_MDP = 1,
+ CLKMUX_IMG1 = 2,
+ CLKMUX_IMG2 = 3,
+ NF_CLKMUX,
+};
+
+static bool is_clkmux_pdn(unsigned int clkmux_id)
+{
+ unsigned int reg, val, idx;
+
+ if ((clkmux_id & CLK_CHECK) != 0U) {
+ clkmux_id = (clkmux_id & ~CLK_CHECK);
+ reg = clkmux_id / 4U;
+ val = mmio_read_32(CLK_CFG(reg));
+ idx = clkmux_id % 4U;
+ val = (val >> (idx * 8U)) & PDN_CHECK;
+ return (val != 0U);
+ }
+
+ return false;
+}
+
+static struct mt_spm_cond_tables spm_cond_t;
+
+struct idle_cond_info {
+ unsigned int subsys_mask;
+ uintptr_t addr;
+ bool bBitflip;
+ unsigned int clkmux_id;
+};
+
+#define IDLE_CG(mask, addr, bitflip, clkmux) \
+ {mask, (uintptr_t)addr, bitflip, clkmux}
+
+static struct idle_cond_info idle_cg_info[PLAT_SPM_COND_MAX] = {
+ IDLE_CG(0xffffffff, SPM_PWR_STATUS, false, 0U),
+ IDLE_CG(0x00000200, INFRA_SW_CG0, true, 0U),
+ IDLE_CG(0x00000200, INFRA_SW_CG1, true, 0U),
+ IDLE_CG(0x00000200, INFRA_SW_CG2, true, 0U),
+ IDLE_CG(0x00000200, INFRA_SW_CG3, true, 0U),
+ IDLE_CG(0x00000200, INFRA_SW_CG4, true, 0U),
+ IDLE_CG(0x00000200, INFRA_SW_CG5, true, 0U),
+ IDLE_CG(0x00100000, MMSYS_CG_CON0, true, (CLK_CHECK | CLKMUX_DISP)),
+ IDLE_CG(0x00100000, MMSYS_CG_CON1, true, (CLK_CHECK | CLKMUX_DISP)),
+ IDLE_CG(0x00100000, MMSYS_CG_CON2, true, (CLK_CHECK | CLKMUX_DISP)),
+};
+
+/***********************************************************
+ * Check pll idle condition
+ ***********************************************************/
+#define PLL_MFGPLL MT_LP_TZ_APMIXEDSYS(0x268)
+#define PLL_MMPLL MT_LP_TZ_APMIXEDSYS(0x360)
+#define PLL_UNIVPLL MT_LP_TZ_APMIXEDSYS(0x308)
+#define PLL_MSDCPLL MT_LP_TZ_APMIXEDSYS(0x350)
+#define PLL_TVDPLL MT_LP_TZ_APMIXEDSYS(0x380)
+
+unsigned int mt_spm_cond_check(int state_id,
+ const struct mt_spm_cond_tables *src,
+ const struct mt_spm_cond_tables *dest,
+ struct mt_spm_cond_tables *res)
+{
+ unsigned int blocked = 0U, i;
+ bool is_system_suspend = IS_PLAT_SUSPEND_ID(state_id);
+
+ if ((src == NULL) || (dest == NULL)) {
+ return SPM_COND_CHECK_FAIL;
+ }
+
+ for (i = 0U; i < PLAT_SPM_COND_MAX; i++) {
+ if (res != NULL) {
+ res->table_cg[i] =
+ (src->table_cg[i] & dest->table_cg[i]);
+
+ if (is_system_suspend && (res->table_cg[i] != 0U)) {
+ INFO("suspend: %s block[%u](0x%lx) = 0x%08x\n",
+ dest->name, i, idle_cg_info[i].addr,
+ res->table_cg[i]);
+ }
+
+ if (res->table_cg[i] != 0U) {
+ blocked |= (1U << i);
+ }
+ } else if ((src->table_cg[i] & dest->table_cg[i]) != 0U) {
+ blocked |= (1U << i);
+ break;
+ }
+ }
+
+ if (res != NULL) {
+ res->table_pll = (src->table_pll & dest->table_pll);
+
+ if (res->table_pll != 0U) {
+ blocked |=
+ (res->table_pll << SPM_COND_BLOCKED_PLL_IDX) |
+ SPM_COND_CHECK_BLOCKED_PLL;
+ }
+ } else if ((src->table_pll & dest->table_pll) != 0U) {
+ blocked |= SPM_COND_CHECK_BLOCKED_PLL;
+ }
+
+ if (is_system_suspend && (blocked != 0U)) {
+ INFO("suspend: %s total blocked = 0x%08x\n",
+ dest->name, blocked);
+ }
+
+ return blocked;
+}
+
+#define IS_MT_SPM_PWR_OFF(mask) \
+ (((mmio_read_32(SPM_PWR_STATUS) & mask) == 0U) && \
+ ((mmio_read_32(SPM_PWR_STATUS_2ND) & mask) == 0U))
+
+int mt_spm_cond_update(struct mt_resource_constraint **con,
+ int stateid, void *priv)
+{
+ int res;
+ uint32_t i;
+ struct mt_resource_constraint *const *rc;
+
+ /* read all cg state */
+ for (i = 0U; i < PLAT_SPM_COND_MAX; i++) {
+ spm_cond_t.table_cg[i] = 0U;
+
+ /* check mtcmos, if off set idle_value and clk to 0 disable */
+ if (IS_MT_SPM_PWR_OFF(idle_cg_info[i].subsys_mask)) {
+ continue;
+ }
+
+ /* check clkmux */
+ if (is_clkmux_pdn(idle_cg_info[i].clkmux_id)) {
+ continue;
+ }
+
+ spm_cond_t.table_cg[i] = idle_cg_info[i].bBitflip ?
+ ~mmio_read_32(idle_cg_info[i].addr) :
+ mmio_read_32(idle_cg_info[i].addr);
+ }
+
+ spm_cond_t.table_pll = 0U;
+ if ((mmio_read_32(PLL_MFGPLL) & 0x1) != 0U) {
+ spm_cond_t.table_pll |= PLL_BIT_MFGPLL;
+ }
+
+ if ((mmio_read_32(PLL_MMPLL) & 0x1) != 0U) {
+ spm_cond_t.table_pll |= PLL_BIT_MMPLL;
+ }
+
+ if ((mmio_read_32(PLL_UNIVPLL) & 0x1) != 0U) {
+ spm_cond_t.table_pll |= PLL_BIT_UNIVPLL;
+ }
+
+ if ((mmio_read_32(PLL_MSDCPLL) & 0x1) != 0U) {
+ spm_cond_t.table_pll |= PLL_BIT_MSDCPLL;
+ }
+
+ if ((mmio_read_32(PLL_TVDPLL) & 0x1) != 0U) {
+ spm_cond_t.table_pll |= PLL_BIT_TVDPLL;
+ }
+
+ spm_cond_t.priv = priv;
+ for (rc = con; *rc != NULL; rc++) {
+ if (((*rc)->update) == NULL) {
+ continue;
+ }
+
+ res = (*rc)->update(stateid, PLAT_RC_UPDATE_CONDITION,
+ (void const *)&spm_cond_t);
+ if (res != MT_RM_STATUS_OK) {
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm_cond.h b/plat/mediatek/mt8192/drivers/spm/mt_spm_cond.h
new file mode 100644
index 0000000..91ebdd9
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm_cond.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_CONDIT_H
+#define MT_SPM_CONDIT_H
+
+#include <mt_lp_rm.h>
+
+enum PLAT_SPM_COND {
+ PLAT_SPM_COND_MTCMOS1 = 0,
+ PLAT_SPM_COND_CG_INFRA_0,
+ PLAT_SPM_COND_CG_INFRA_1,
+ PLAT_SPM_COND_CG_INFRA_2,
+ PLAT_SPM_COND_CG_INFRA_3,
+ PLAT_SPM_COND_CG_INFRA_4,
+ PLAT_SPM_COND_CG_INFRA_5,
+ PLAT_SPM_COND_CG_MMSYS_0,
+ PLAT_SPM_COND_CG_MMSYS_1,
+ PLAT_SPM_COND_CG_MMSYS_2,
+ PLAT_SPM_COND_MAX,
+};
+
+#define PLL_BIT_UNIVPLL BIT(0)
+#define PLL_BIT_MFGPLL BIT(1)
+#define PLL_BIT_MSDCPLL BIT(2)
+#define PLL_BIT_TVDPLL BIT(3)
+#define PLL_BIT_MMPLL BIT(4)
+
+/* Definition about SPM_COND_CHECK_BLOCKED
+ * bit [00 ~ 15]: cg blocking index
+ * bit [16 ~ 29]: pll blocking index
+ * bit [30] : pll blocking information
+ * bit [31] : idle condition check fail
+ */
+#define SPM_COND_BLOCKED_CG_IDX U(0)
+#define SPM_COND_BLOCKED_PLL_IDX U(16)
+#define SPM_COND_CHECK_BLOCKED_PLL BIT(30)
+#define SPM_COND_CHECK_FAIL BIT(31)
+
+struct mt_spm_cond_tables {
+ char *name;
+ unsigned int table_cg[PLAT_SPM_COND_MAX];
+ unsigned int table_pll;
+ void *priv;
+};
+
+extern unsigned int mt_spm_cond_check(int state_id,
+ const struct mt_spm_cond_tables *src,
+ const struct mt_spm_cond_tables *dest,
+ struct mt_spm_cond_tables *res);
+extern int mt_spm_cond_update(struct mt_resource_constraint **con,
+ int stateid, void *priv);
+#endif /* MT_SPM_CONDIT_H */
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm_conservation.c b/plat/mediatek/mt8192/drivers/spm/mt_spm_conservation.c
new file mode 100644
index 0000000..f9e6654
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm_conservation.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <mt_spm.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_vcorefs.h>
+#include <plat_mtk_lpm.h>
+#include <plat_pm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+struct wake_status spm_wakesta; /* record last wakesta */
+
+static int go_to_spm_before_wfi(int state_id, unsigned int ext_opand,
+ struct spm_lp_scen *spm_lp,
+ unsigned int resource_req)
+{
+ int ret = 0;
+ struct pwr_ctrl *pwrctrl;
+ uint32_t cpu = plat_my_core_pos();
+
+ pwrctrl = spm_lp->pwrctrl;
+
+ __spm_set_cpu_status(cpu);
+ __spm_set_power_control(pwrctrl);
+ __spm_set_wakeup_event(pwrctrl);
+ __spm_sync_vcore_dvfs_power_control(pwrctrl, __spm_vcorefs.pwrctrl);
+ __spm_set_pcm_flags(pwrctrl);
+ __spm_src_req_update(pwrctrl, resource_req);
+
+ if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) {
+ __spm_set_pcm_wdt(1);
+ }
+
+ if ((ext_opand & MT_SPM_EX_OP_SRCLKEN_RC_BBLPM) != 0U) {
+ __spm_xo_soc_bblpm(1);
+ }
+
+ if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) {
+ spm_hw_s1_state_monitor_resume();
+ }
+
+ /* Disable auto resume by PCM in system suspend stage */
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ __spm_disable_pcm_timer();
+ __spm_set_pcm_wdt(0);
+ }
+
+ __spm_send_cpu_wakeup_event();
+
+ INFO("cpu%d: wakesrc = 0x%x, settle = 0x%x, sec = %u\n",
+ cpu, pwrctrl->wake_src, mmio_read_32(SPM_CLK_SETTLE),
+ mmio_read_32(PCM_TIMER_VAL) / 32768);
+ INFO("sw_flag = 0x%x 0x%x, req = 0x%x, pwr = 0x%x 0x%x\n",
+ pwrctrl->pcm_flags, pwrctrl->pcm_flags1,
+ mmio_read_32(SPM_SRC_REQ), mmio_read_32(PWR_STATUS),
+ mmio_read_32(PWR_STATUS_2ND));
+
+ return ret;
+}
+
+static void go_to_spm_after_wfi(int state_id, unsigned int ext_opand,
+ struct spm_lp_scen *spm_lp,
+ struct wake_status **status)
+{
+ unsigned int ext_status = 0U;
+
+ /* system watchdog will be resumed at kernel stage */
+ if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) {
+ __spm_set_pcm_wdt(0);
+ }
+
+ if ((ext_opand & MT_SPM_EX_OP_SRCLKEN_RC_BBLPM) != 0U) {
+ __spm_xo_soc_bblpm(0);
+ }
+
+ if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) {
+ spm_hw_s1_state_monitor_pause(&ext_status);
+ }
+
+ __spm_ext_int_wakeup_req_clr();
+ __spm_get_wakeup_status(&spm_wakesta, ext_status);
+
+ if (status != NULL) {
+ *status = &spm_wakesta;
+ }
+
+ __spm_clean_after_wakeup();
+
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ __spm_output_wake_reason(state_id, &spm_wakesta);
+ }
+}
+
+int spm_conservation(int state_id, unsigned int ext_opand,
+ struct spm_lp_scen *spm_lp, unsigned int resource_req)
+{
+ if (spm_lp == NULL) {
+ return -1;
+ }
+
+ spm_lock_get();
+ go_to_spm_before_wfi(state_id, ext_opand, spm_lp, resource_req);
+ spm_lock_release();
+
+ return 0;
+}
+
+void spm_conservation_finish(int state_id, unsigned int ext_opand,
+ struct spm_lp_scen *spm_lp,
+ struct wake_status **status)
+{
+ spm_lock_get();
+ go_to_spm_after_wfi(state_id, ext_opand, spm_lp, status);
+ spm_lock_release();
+}
+
+int spm_conservation_get_result(struct wake_status **res)
+{
+ if (res == NULL) {
+ return -1;
+ }
+
+ *res = &spm_wakesta;
+
+ return 0;
+}
+
+#define GPIO_BANK (GPIO_BASE + 0x6F0)
+#define TRAP_UFS_FIRST BIT(11) /* bit 11, 0: UFS, 1: eMMC */
+
+void spm_conservation_pwrctrl_init(struct pwr_ctrl *pwrctrl)
+{
+ if (pwrctrl == NULL) {
+ return;
+ }
+
+ /* For ufs, emmc storage type */
+ if ((mmio_read_32(GPIO_BANK) & TRAP_UFS_FIRST) != 0U) {
+ /* If eMMC is used, mask UFS req */
+ pwrctrl->reg_ufs_srcclkena_mask_b = 0;
+ pwrctrl->reg_ufs_infra_req_mask_b = 0;
+ pwrctrl->reg_ufs_apsrc_req_mask_b = 0;
+ pwrctrl->reg_ufs_vrf18_req_mask_b = 0;
+ pwrctrl->reg_ufs_ddr_en_mask_b = 0;
+ }
+}
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm_conservation.h b/plat/mediatek/mt8192/drivers/spm/mt_spm_conservation.h
new file mode 100644
index 0000000..c5e97db
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm_conservation.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_CONSERVATION_H
+#define MT_SPM_CONSERVATION_H
+
+#include <mt_spm_internal.h>
+
+extern int spm_conservation(int state_id, unsigned int ext_opand,
+ struct spm_lp_scen *spm_lp,
+ unsigned int resource_req);
+extern void spm_conservation_finish(int state_id, unsigned int ext_opand,
+ struct spm_lp_scen *spm_lp,
+ struct wake_status **status);
+extern int spm_conservation_get_result(struct wake_status **res);
+extern void spm_conservation_pwrctrl_init(struct pwr_ctrl *pwrctrl);
+#endif /* MT_SPM_CONSERVATION_H */
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm_constraint.h b/plat/mediatek/mt8192/drivers/spm/mt_spm_constraint.h
new file mode 100644
index 0000000..a3409f7
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm_constraint.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_CONSTRAINT_H
+#define MT_SPM_CONSTRAINT_H
+
+#include <mt_lp_rm.h>
+
+#define MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF (1U << 0)
+#define MT_RM_CONSTRAINT_ALLOW_DRAM_S0 (1U << 1)
+#define MT_RM_CONSTRAINT_ALLOW_DRAM_S1 (1U << 2)
+#define MT_RM_CONSTRAINT_ALLOW_VCORE_LP (1U << 3)
+#define MT_RM_CONSTRAINT_ALLOW_INFRA_PDN (1U << 4)
+#define MT_RM_CONSTRAINT_ALLOW_BUS26M_OFF (1U << 5)
+#define MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND (1U << 6)
+#define MT_RM_CONSTRAINT_ALLOW_BBLPM (1U << 7)
+#define MT_RM_CONSTRAINT_ALLOW_XO_UFS (1U << 8)
+#define MT_RM_CONSTRAINT_ALLOW_GPS_STATE (1U << 9)
+#define MT_RM_CONSTRAINT_ALLOW_LVTS_STATE (1U << 10)
+
+#define MT_SPM_RC_INVALID 0x0
+#define MT_SPM_RC_VALID_SW (1U << 0)
+#define MT_SPM_RC_VALID_FW (1U << 1)
+#define MT_SPM_RC_VALID_RESIDNECY (1U << 2)
+#define MT_SPM_RC_VALID_COND_CHECK (1U << 3)
+#define MT_SPM_RC_VALID_COND_LATCH (1U << 4)
+#define MT_SPM_RC_VALID_UFS_H8 (1U << 5)
+#define MT_SPM_RC_VALID_FLIGHTMODE (1U << 6)
+#define MT_SPM_RC_VALID_XSOC_BBLPM (1U << 7)
+#define MT_SPM_RC_VALID_TRACE_EVENT (1U << 8)
+
+#define MT_SPM_RC_VALID (MT_SPM_RC_VALID_SW)
+
+#define IS_MT_RM_RC_READY(status) \
+ ((status & MT_SPM_RC_VALID) == MT_SPM_RC_VALID)
+
+#define MT_SPM_RC_BBLPM_MODE \
+ (MT_SPM_RC_VALID_UFS_H8 | \
+ MT_SPM_RC_VALID_FLIGHTMODE | \
+ MT_SPM_RC_VALID_XSOC_BBLPM)
+
+#define IS_MT_SPM_RC_BBLPM_MODE(st) \
+ ((st & (MT_SPM_RC_BBLPM_MODE)) == MT_SPM_RC_BBLPM_MODE)
+
+struct constraint_status {
+ uint16_t id;
+ uint16_t valid;
+ uint32_t cond_block;
+ uint32_t enter_cnt;
+ struct mt_spm_cond_tables *cond_res;
+};
+
+enum MT_SPM_RM_RC_TYPE {
+ MT_RM_CONSTRAINT_ID_BUS26M,
+ MT_RM_CONSTRAINT_ID_SYSPLL,
+ MT_RM_CONSTRAINT_ID_DRAM,
+ MT_RM_CONSTRAINT_ID_CPU_BUCK_LDO,
+ MT_RM_CONSTRAINT_ID_ALL,
+};
+#endif /* MT_SPM_CONSTRAINT_H */
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm_idle.c b/plat/mediatek/mt8192/drivers/spm/mt_spm_idle.c
new file mode 100644
index 0000000..3540ec2
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm_idle.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <mt_spm.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_idle.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <plat_pm.h>
+
+#define __WAKE_SRC_FOR_IDLE_COMMON__ \
+ (R12_PCM_TIMER | \
+ R12_KP_IRQ_B | \
+ R12_APWDT_EVENT_B | \
+ R12_APXGPT1_EVENT_B | \
+ R12_CONN2AP_SPM_WAKEUP_B | \
+ R12_EINT_EVENT_B | \
+ R12_CONN_WDT_IRQ_B | \
+ R12_CCIF0_EVENT_B | \
+ R12_SSPM2SPM_WAKEUP_B | \
+ R12_SCP2SPM_WAKEUP_B | \
+ R12_ADSP2SPM_WAKEUP_B | \
+ R12_USBX_CDSC_B | \
+ R12_USBX_POWERDWN_B | \
+ R12_SYS_TIMER_EVENT_B | \
+ R12_EINT_EVENT_SECURE_B | \
+ R12_CCIF1_EVENT_B | \
+ R12_AFE_IRQ_MCU_B | \
+ R12_SYS_CIRQ_IRQ_B | \
+ R12_MD2AP_PEER_EVENT_B | \
+ R12_MD1_WDT_B | \
+ R12_CLDMA_EVENT_B | \
+ R12_REG_CPU_WAKEUP | \
+ R12_APUSYS_WAKE_HOST_B | \
+ R12_PCIE_BRIDGE_IRQ | \
+ R12_PCIE_IRQ)
+
+#if defined(CFG_MICROTRUST_TEE_SUPPORT)
+#define WAKE_SRC_FOR_IDLE (__WAKE_SRC_FOR_IDLE_COMMON__)
+#else
+#define WAKE_SRC_FOR_IDLE \
+ (__WAKE_SRC_FOR_IDLE_COMMON__ | \
+ R12_SEJ_EVENT_B)
+#endif
+
+static struct pwr_ctrl idle_spm_pwr = {
+ .timer_val = 0x28000,
+ .wake_src = WAKE_SRC_FOR_IDLE,
+
+ /* Auto-gen Start */
+
+ /* SPM_AP_STANDBY_CON */
+ .reg_wfi_op = 0,
+ .reg_wfi_type = 0,
+ .reg_mp0_cputop_idle_mask = 0,
+ .reg_mp1_cputop_idle_mask = 0,
+ .reg_mcusys_idle_mask = 0,
+ .reg_md_apsrc_1_sel = 0,
+ .reg_md_apsrc_0_sel = 0,
+ .reg_conn_apsrc_sel = 0,
+
+ /* SPM_SRC6_MASK */
+ .reg_dpmaif_srcclkena_mask_b = 1,
+ .reg_dpmaif_infra_req_mask_b = 1,
+ .reg_dpmaif_apsrc_req_mask_b = 1,
+ .reg_dpmaif_vrf18_req_mask_b = 1,
+ .reg_dpmaif_ddr_en_mask_b = 1,
+
+ /* SPM_SRC_REQ */
+ .reg_spm_apsrc_req = 1,
+ .reg_spm_f26m_req = 1,
+ .reg_spm_infra_req = 1,
+ .reg_spm_vrf18_req = 1,
+ .reg_spm_ddr_en_req = 1,
+ .reg_spm_dvfs_req = 0,
+ .reg_spm_sw_mailbox_req = 0,
+ .reg_spm_sspm_mailbox_req = 0,
+ .reg_spm_adsp_mailbox_req = 0,
+ .reg_spm_scp_mailbox_req = 0,
+
+ /* SPM_SRC_MASK */
+ .reg_md_srcclkena_0_mask_b = 1,
+ .reg_md_srcclkena2infra_req_0_mask_b = 0,
+ .reg_md_apsrc2infra_req_0_mask_b = 1,
+ .reg_md_apsrc_req_0_mask_b = 1,
+ .reg_md_vrf18_req_0_mask_b = 1,
+ .reg_md_ddr_en_0_mask_b = 1,
+ .reg_md_srcclkena_1_mask_b = 0,
+ .reg_md_srcclkena2infra_req_1_mask_b = 0,
+ .reg_md_apsrc2infra_req_1_mask_b = 0,
+ .reg_md_apsrc_req_1_mask_b = 0,
+ .reg_md_vrf18_req_1_mask_b = 0,
+ .reg_md_ddr_en_1_mask_b = 0,
+ .reg_conn_srcclkena_mask_b = 1,
+ .reg_conn_srcclkenb_mask_b = 0,
+ .reg_conn_infra_req_mask_b = 1,
+ .reg_conn_apsrc_req_mask_b = 1,
+ .reg_conn_vrf18_req_mask_b = 1,
+ .reg_conn_ddr_en_mask_b = 1,
+ .reg_conn_vfe28_mask_b = 0,
+ .reg_srcclkeni0_srcclkena_mask_b = 1,
+ .reg_srcclkeni0_infra_req_mask_b = 1,
+ .reg_srcclkeni1_srcclkena_mask_b = 0,
+ .reg_srcclkeni1_infra_req_mask_b = 0,
+ .reg_srcclkeni2_srcclkena_mask_b = 0,
+ .reg_srcclkeni2_infra_req_mask_b = 0,
+ .reg_infrasys_apsrc_req_mask_b = 0,
+ .reg_infrasys_ddr_en_mask_b = 1,
+ .reg_md32_srcclkena_mask_b = 1,
+ .reg_md32_infra_req_mask_b = 1,
+ .reg_md32_apsrc_req_mask_b = 1,
+ .reg_md32_vrf18_req_mask_b = 1,
+ .reg_md32_ddr_en_mask_b = 1,
+
+ /* SPM_SRC2_MASK */
+ .reg_scp_srcclkena_mask_b = 1,
+ .reg_scp_infra_req_mask_b = 1,
+ .reg_scp_apsrc_req_mask_b = 1,
+ .reg_scp_vrf18_req_mask_b = 1,
+ .reg_scp_ddr_en_mask_b = 1,
+ .reg_audio_dsp_srcclkena_mask_b = 1,
+ .reg_audio_dsp_infra_req_mask_b = 1,
+ .reg_audio_dsp_apsrc_req_mask_b = 1,
+ .reg_audio_dsp_vrf18_req_mask_b = 1,
+ .reg_audio_dsp_ddr_en_mask_b = 1,
+ .reg_ufs_srcclkena_mask_b = 1,
+ .reg_ufs_infra_req_mask_b = 1,
+ .reg_ufs_apsrc_req_mask_b = 1,
+ .reg_ufs_vrf18_req_mask_b = 1,
+ .reg_ufs_ddr_en_mask_b = 1,
+ .reg_disp0_apsrc_req_mask_b = 1,
+ .reg_disp0_ddr_en_mask_b = 1,
+ .reg_disp1_apsrc_req_mask_b = 1,
+ .reg_disp1_ddr_en_mask_b = 1,
+ .reg_gce_infra_req_mask_b = 1,
+ .reg_gce_apsrc_req_mask_b = 1,
+ .reg_gce_vrf18_req_mask_b = 1,
+ .reg_gce_ddr_en_mask_b = 1,
+ .reg_apu_srcclkena_mask_b = 1,
+ .reg_apu_infra_req_mask_b = 1,
+ .reg_apu_apsrc_req_mask_b = 1,
+ .reg_apu_vrf18_req_mask_b = 1,
+ .reg_apu_ddr_en_mask_b = 1,
+ .reg_cg_check_srcclkena_mask_b = 0,
+ .reg_cg_check_apsrc_req_mask_b = 0,
+ .reg_cg_check_vrf18_req_mask_b = 0,
+ .reg_cg_check_ddr_en_mask_b = 0,
+
+ /* SPM_SRC3_MASK */
+ .reg_dvfsrc_event_trigger_mask_b = 1,
+ .reg_sw2spm_int0_mask_b = 0,
+ .reg_sw2spm_int1_mask_b = 0,
+ .reg_sw2spm_int2_mask_b = 0,
+ .reg_sw2spm_int3_mask_b = 0,
+ .reg_sc_adsp2spm_wakeup_mask_b = 0,
+ .reg_sc_sspm2spm_wakeup_mask_b = 0,
+ .reg_sc_scp2spm_wakeup_mask_b = 0,
+ .reg_csyspwrreq_mask = 1,
+ .reg_spm_srcclkena_reserved_mask_b = 0,
+ .reg_spm_infra_req_reserved_mask_b = 0,
+ .reg_spm_apsrc_req_reserved_mask_b = 0,
+ .reg_spm_vrf18_req_reserved_mask_b = 0,
+ .reg_spm_ddr_en_reserved_mask_b = 0,
+ .reg_mcupm_srcclkena_mask_b = 1,
+ .reg_mcupm_infra_req_mask_b = 1,
+ .reg_mcupm_apsrc_req_mask_b = 1,
+ .reg_mcupm_vrf18_req_mask_b = 1,
+ .reg_mcupm_ddr_en_mask_b = 1,
+ .reg_msdc0_srcclkena_mask_b = 1,
+ .reg_msdc0_infra_req_mask_b = 1,
+ .reg_msdc0_apsrc_req_mask_b = 1,
+ .reg_msdc0_vrf18_req_mask_b = 1,
+ .reg_msdc0_ddr_en_mask_b = 1,
+ .reg_msdc1_srcclkena_mask_b = 1,
+ .reg_msdc1_infra_req_mask_b = 1,
+ .reg_msdc1_apsrc_req_mask_b = 1,
+ .reg_msdc1_vrf18_req_mask_b = 1,
+ .reg_msdc1_ddr_en_mask_b = 1,
+
+ /* SPM_SRC4_MASK */
+ .ccif_event_mask_b = 0xFFF,
+ .reg_bak_psri_srcclkena_mask_b = 0,
+ .reg_bak_psri_infra_req_mask_b = 0,
+ .reg_bak_psri_apsrc_req_mask_b = 0,
+ .reg_bak_psri_vrf18_req_mask_b = 0,
+ .reg_bak_psri_ddr_en_mask_b = 0,
+ .reg_dramc0_md32_infra_req_mask_b = 1,
+ .reg_dramc0_md32_vrf18_req_mask_b = 0,
+ .reg_dramc1_md32_infra_req_mask_b = 1,
+ .reg_dramc1_md32_vrf18_req_mask_b = 0,
+ .reg_conn_srcclkenb2pwrap_mask_b = 0,
+ .reg_dramc0_md32_wakeup_mask = 1,
+ .reg_dramc1_md32_wakeup_mask = 1,
+
+ /* SPM_SRC5_MASK */
+ .reg_mcusys_merge_apsrc_req_mask_b = 0x11,
+ .reg_mcusys_merge_ddr_en_mask_b = 0x11,
+ .reg_msdc2_srcclkena_mask_b = 1,
+ .reg_msdc2_infra_req_mask_b = 1,
+ .reg_msdc2_apsrc_req_mask_b = 1,
+ .reg_msdc2_vrf18_req_mask_b = 1,
+ .reg_msdc2_ddr_en_mask_b = 1,
+ .reg_pcie_srcclkena_mask_b = 1,
+ .reg_pcie_infra_req_mask_b = 1,
+ .reg_pcie_apsrc_req_mask_b = 1,
+ .reg_pcie_vrf18_req_mask_b = 1,
+ .reg_pcie_ddr_en_mask_b = 1,
+
+ /* SPM_WAKEUP_EVENT_MASK */
+ .reg_wakeup_event_mask = 0x01282202,
+
+ /* SPM_WAKEUP_EVENT_EXT_MASK */
+ .reg_ext_wakeup_event_mask = 0xFFFFFFFF,
+
+ /* Auto-gen End */
+};
+
+struct spm_lp_scen idle_spm_lp = {
+ .pwrctrl = &idle_spm_pwr,
+};
+
+int mt_spm_idle_generic_enter(int state_id, unsigned int ext_opand,
+ spm_idle_conduct fn)
+{
+ unsigned int src_req = 0;
+
+ if (fn != NULL) {
+ fn(&idle_spm_lp, &src_req);
+ }
+
+ return spm_conservation(state_id, ext_opand, &idle_spm_lp, src_req);
+}
+void mt_spm_idle_generic_resume(int state_id, unsigned int ext_opand,
+ struct wake_status **status)
+{
+ spm_conservation_finish(state_id, ext_opand, &idle_spm_lp, status);
+}
+
+void mt_spm_idle_generic_init(void)
+{
+ spm_conservation_pwrctrl_init(idle_spm_lp.pwrctrl);
+}
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm_idle.h b/plat/mediatek/mt8192/drivers/spm/mt_spm_idle.h
new file mode 100644
index 0000000..3d42cf1
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm_idle.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_IDLE_H
+#define MT_SPM_IDLE_H
+
+typedef void (*spm_idle_conduct)(struct spm_lp_scen *spm_lp,
+ unsigned int *resource_req);
+int mt_spm_idle_generic_enter(int state_id, unsigned int ext_opand,
+ spm_idle_conduct fn);
+void mt_spm_idle_generic_resume(int state_id, unsigned int ext_opand,
+ struct wake_status **status);
+void mt_spm_idle_generic_init(void);
+#endif /* MT_SPM_IDLE_H */
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm_internal.c b/plat/mediatek/mt8192/drivers/spm/mt_spm_internal.c
new file mode 100644
index 0000000..40be027
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm_internal.c
@@ -0,0 +1,588 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <assert.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <mt_spm.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_pmic_wrap.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <platform_def.h>
+#include <plat_pm.h>
+
+/**************************************
+ * Define and Declare
+ **************************************/
+#define ROOT_CORE_ADDR_OFFSET 0x20000000
+#define SPM_WAKEUP_EVENT_MASK_CLEAN_MASK 0xefffffff
+#define SPM_INIT_DONE_US 20
+
+static unsigned int mt_spm_bblpm_cnt;
+
+const char *wakeup_src_str[32] = {
+ [0] = "R12_PCM_TIMER",
+ [1] = "R12_RESERVED_DEBUG_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_SC_SSPM2SPM_WAKEUP_B",
+ [11] = "R12_SC_SCP2SPM_WAKEUP_B",
+ [12] = "R12_SC_ADSP2SPM_WAKEUP_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_AP2AP_PEER_WAKEUPEVENT_B",
+ [27] = "R12_SEJ_EVENT_B",
+ [28] = "R12_SPM_CPU_WAKEUPEVENT_B",
+ [29] = "R12_APUSYS",
+ [30] = "R12_PCIE_BRIDGE_IRQ",
+ [31] = "R12_PCIE_IRQ",
+};
+
+/**************************************
+ * Function and API
+ **************************************/
+
+wake_reason_t __spm_output_wake_reason(int state_id,
+ const struct wake_status *wakesta)
+{
+ uint32_t i, bk_vtcxo_dur, spm_26m_off_pct = 0U;
+ wake_reason_t wr = WR_UNKNOWN;
+
+ if (wakesta == NULL) {
+ return WR_UNKNOWN;
+ }
+
+ if (wakesta->abort != 0U) {
+ ERROR("spmfw flow is aborted: 0x%x, timer_out = %u\n",
+ wakesta->abort, wakesta->timer_out);
+ } else {
+ for (i = 0U; i < 32U; i++) {
+ if ((wakesta->r12 & (1U << i)) != 0U) {
+ INFO("wake up by %s, timer_out = %u\n",
+ wakeup_src_str[i], wakesta->timer_out);
+ wr = WR_WAKE_SRC;
+ break;
+ }
+ }
+ }
+
+ INFO("r12 = 0x%x, r12_ext = 0x%x, r13 = 0x%x, debug_flag = 0x%x 0x%x\n",
+ wakesta->r12, wakesta->r12_ext, wakesta->r13, wakesta->debug_flag,
+ wakesta->debug_flag1);
+ INFO("raw_sta = 0x%x 0x%x 0x%x, idle_sta = 0x%x, cg_check_sta = 0x%x\n",
+ wakesta->raw_sta, wakesta->md32pcm_wakeup_sta,
+ wakesta->md32pcm_event_sta, wakesta->idle_sta,
+ wakesta->cg_check_sta);
+ INFO("req_sta = 0x%x 0x%x 0x%x 0x%x 0x%x, isr = 0x%x\n",
+ wakesta->req_sta0, wakesta->req_sta1, wakesta->req_sta2,
+ wakesta->req_sta3, wakesta->req_sta4, wakesta->isr);
+ INFO("rt_req_sta0 = 0x%x, rt_req_sta1 = 0x%x, rt_req_sta2 = 0x%x\n",
+ wakesta->rt_req_sta0, wakesta->rt_req_sta1, wakesta->rt_req_sta2);
+ INFO("rt_req_sta3 = 0x%x, dram_sw_con_3 = 0x%x, raw_ext_sta = 0x%x\n",
+ wakesta->rt_req_sta3, wakesta->rt_req_sta4, wakesta->raw_ext_sta);
+ INFO("wake_misc = 0x%x, pcm_flag = 0x%x 0x%x 0x%x 0x%x, req = 0x%x\n",
+ wakesta->wake_misc, wakesta->sw_flag0, wakesta->sw_flag1,
+ wakesta->b_sw_flag0, wakesta->b_sw_flag1, wakesta->src_req);
+ INFO("clk_settle = 0x%x, wlk_cntcv_l = 0x%x, wlk_cntcv_h = 0x%x\n",
+ wakesta->clk_settle, mmio_read_32(SYS_TIMER_VALUE_L),
+ mmio_read_32(SYS_TIMER_VALUE_H));
+
+ if (wakesta->timer_out != 0U) {
+ bk_vtcxo_dur = mmio_read_32(SPM_BK_VTCXO_DUR);
+ spm_26m_off_pct = (100 * bk_vtcxo_dur) / wakesta->timer_out;
+ INFO("spm_26m_off_pct = %u\n", spm_26m_off_pct);
+ }
+
+ return wr;
+}
+
+void __spm_set_cpu_status(unsigned int cpu)
+{
+ uint32_t root_core_addr;
+
+ if (cpu < 8U) {
+ mmio_write_32(ROOT_CPUTOP_ADDR, (1U << cpu));
+ root_core_addr = SPM_CPU0_PWR_CON + (cpu * 0x4);
+ root_core_addr += ROOT_CORE_ADDR_OFFSET;
+ mmio_write_32(ROOT_CORE_ADDR, root_core_addr);
+ /* Notify MCUPM that preferred cpu wakeup */
+ mmio_write_32(MCUPM_MBOX_WAKEUP_CPU, cpu);
+ } else {
+ ERROR("%s: error cpu number %d\n", __func__, cpu);
+ }
+}
+
+void __spm_src_req_update(const struct pwr_ctrl *pwrctrl,
+ unsigned int resource_usage)
+{
+ uint8_t apsrc_req = ((resource_usage & MT_SPM_DRAM_S0) != 0U) ?
+ 1 : pwrctrl->reg_spm_apsrc_req;
+ uint8_t ddr_en_req = ((resource_usage & MT_SPM_DRAM_S1) != 0U) ?
+ 1 : pwrctrl->reg_spm_ddr_en_req;
+ uint8_t vrf18_req = ((resource_usage & MT_SPM_SYSPLL) != 0U) ?
+ 1 : pwrctrl->reg_spm_vrf18_req;
+ uint8_t infra_req = ((resource_usage & MT_SPM_INFRA) != 0U) ?
+ 1 : pwrctrl->reg_spm_infra_req;
+ uint8_t f26m_req = ((resource_usage &
+ (MT_SPM_26M | MT_SPM_XO_FPM)) != 0U) ?
+ 1 : pwrctrl->reg_spm_f26m_req;
+
+ mmio_write_32(SPM_SRC_REQ,
+ ((apsrc_req & 0x1) << 0) |
+ ((f26m_req & 0x1) << 1) |
+ ((infra_req & 0x1) << 3) |
+ ((vrf18_req & 0x1) << 4) |
+ ((ddr_en_req & 0x1) << 7) |
+ ((pwrctrl->reg_spm_dvfs_req & 0x1) << 8) |
+ ((pwrctrl->reg_spm_sw_mailbox_req & 0x1) << 9) |
+ ((pwrctrl->reg_spm_sspm_mailbox_req & 0x1) << 10) |
+ ((pwrctrl->reg_spm_adsp_mailbox_req & 0x1) << 11) |
+ ((pwrctrl->reg_spm_scp_mailbox_req & 0x1) << 12));
+}
+
+void __spm_set_power_control(const struct pwr_ctrl *pwrctrl)
+{
+ /* Auto-gen Start */
+
+ /* SPM_AP_STANDBY_CON */
+ mmio_write_32(SPM_AP_STANDBY_CON,
+ ((pwrctrl->reg_wfi_op & 0x1) << 0) |
+ ((pwrctrl->reg_wfi_type & 0x1) << 1) |
+ ((pwrctrl->reg_mp0_cputop_idle_mask & 0x1) << 2) |
+ ((pwrctrl->reg_mp1_cputop_idle_mask & 0x1) << 3) |
+ ((pwrctrl->reg_mcusys_idle_mask & 0x1) << 4) |
+ ((pwrctrl->reg_md_apsrc_1_sel & 0x1) << 25) |
+ ((pwrctrl->reg_md_apsrc_0_sel & 0x1) << 26) |
+ ((pwrctrl->reg_conn_apsrc_sel & 0x1) << 29));
+
+ /* SPM_SRC6_MASK */
+ mmio_write_32(SPM_SRC6_MASK,
+ ((pwrctrl->reg_dpmaif_srcclkena_mask_b & 0x1) << 0) |
+ ((pwrctrl->reg_dpmaif_infra_req_mask_b & 0x1) << 1) |
+ ((pwrctrl->reg_dpmaif_apsrc_req_mask_b & 0x1) << 2) |
+ ((pwrctrl->reg_dpmaif_vrf18_req_mask_b & 0x1) << 3) |
+ ((pwrctrl->reg_dpmaif_ddr_en_mask_b & 0x1) << 4));
+
+ /* SPM_SRC_REQ */
+ mmio_write_32(SPM_SRC_REQ,
+ ((pwrctrl->reg_spm_apsrc_req & 0x1) << 0) |
+ ((pwrctrl->reg_spm_f26m_req & 0x1) << 1) |
+ ((pwrctrl->reg_spm_infra_req & 0x1) << 3) |
+ ((pwrctrl->reg_spm_vrf18_req & 0x1) << 4) |
+ ((pwrctrl->reg_spm_ddr_en_req & 0x1) << 7) |
+ ((pwrctrl->reg_spm_dvfs_req & 0x1) << 8) |
+ ((pwrctrl->reg_spm_sw_mailbox_req & 0x1) << 9) |
+ ((pwrctrl->reg_spm_sspm_mailbox_req & 0x1) << 10) |
+ ((pwrctrl->reg_spm_adsp_mailbox_req & 0x1) << 11) |
+ ((pwrctrl->reg_spm_scp_mailbox_req & 0x1) << 12));
+
+ /* SPM_SRC_MASK */
+ mmio_write_32(SPM_SRC_MASK,
+ ((pwrctrl->reg_md_srcclkena_0_mask_b & 0x1) << 0) |
+ ((pwrctrl->reg_md_srcclkena2infra_req_0_mask_b & 0x1) << 1) |
+ ((pwrctrl->reg_md_apsrc2infra_req_0_mask_b & 0x1) << 2) |
+ ((pwrctrl->reg_md_apsrc_req_0_mask_b & 0x1) << 3) |
+ ((pwrctrl->reg_md_vrf18_req_0_mask_b & 0x1) << 4) |
+ ((pwrctrl->reg_md_ddr_en_0_mask_b & 0x1) << 5) |
+ ((pwrctrl->reg_md_srcclkena_1_mask_b & 0x1) << 6) |
+ ((pwrctrl->reg_md_srcclkena2infra_req_1_mask_b & 0x1) << 7) |
+ ((pwrctrl->reg_md_apsrc2infra_req_1_mask_b & 0x1) << 8) |
+ ((pwrctrl->reg_md_apsrc_req_1_mask_b & 0x1) << 9) |
+ ((pwrctrl->reg_md_vrf18_req_1_mask_b & 0x1) << 10) |
+ ((pwrctrl->reg_md_ddr_en_1_mask_b & 0x1) << 11) |
+ ((pwrctrl->reg_conn_srcclkena_mask_b & 0x1) << 12) |
+ ((pwrctrl->reg_conn_srcclkenb_mask_b & 0x1) << 13) |
+ ((pwrctrl->reg_conn_infra_req_mask_b & 0x1) << 14) |
+ ((pwrctrl->reg_conn_apsrc_req_mask_b & 0x1) << 15) |
+ ((pwrctrl->reg_conn_vrf18_req_mask_b & 0x1) << 16) |
+ ((pwrctrl->reg_conn_ddr_en_mask_b & 0x1) << 17) |
+ ((pwrctrl->reg_conn_vfe28_mask_b & 0x1) << 18) |
+ ((pwrctrl->reg_srcclkeni0_srcclkena_mask_b & 0x1) << 19) |
+ ((pwrctrl->reg_srcclkeni0_infra_req_mask_b & 0x1) << 20) |
+ ((pwrctrl->reg_srcclkeni1_srcclkena_mask_b & 0x1) << 21) |
+ ((pwrctrl->reg_srcclkeni1_infra_req_mask_b & 0x1) << 22) |
+ ((pwrctrl->reg_srcclkeni2_srcclkena_mask_b & 0x1) << 23) |
+ ((pwrctrl->reg_srcclkeni2_infra_req_mask_b & 0x1) << 24) |
+ ((pwrctrl->reg_infrasys_apsrc_req_mask_b & 0x1) << 25) |
+ ((pwrctrl->reg_infrasys_ddr_en_mask_b & 0x1) << 26) |
+ ((pwrctrl->reg_md32_srcclkena_mask_b & 0x1) << 27) |
+ ((pwrctrl->reg_md32_infra_req_mask_b & 0x1) << 28) |
+ ((pwrctrl->reg_md32_apsrc_req_mask_b & 0x1) << 29) |
+ ((pwrctrl->reg_md32_vrf18_req_mask_b & 0x1) << 30) |
+ ((pwrctrl->reg_md32_ddr_en_mask_b & 0x1) << 31));
+
+ /* SPM_SRC2_MASK */
+ mmio_write_32(SPM_SRC2_MASK,
+ ((pwrctrl->reg_scp_srcclkena_mask_b & 0x1) << 0) |
+ ((pwrctrl->reg_scp_infra_req_mask_b & 0x1) << 1) |
+ ((pwrctrl->reg_scp_apsrc_req_mask_b & 0x1) << 2) |
+ ((pwrctrl->reg_scp_vrf18_req_mask_b & 0x1) << 3) |
+ ((pwrctrl->reg_scp_ddr_en_mask_b & 0x1) << 4) |
+ ((pwrctrl->reg_audio_dsp_srcclkena_mask_b & 0x1) << 5) |
+ ((pwrctrl->reg_audio_dsp_infra_req_mask_b & 0x1) << 6) |
+ ((pwrctrl->reg_audio_dsp_apsrc_req_mask_b & 0x1) << 7) |
+ ((pwrctrl->reg_audio_dsp_vrf18_req_mask_b & 0x1) << 8) |
+ ((pwrctrl->reg_audio_dsp_ddr_en_mask_b & 0x1) << 9) |
+ ((pwrctrl->reg_ufs_srcclkena_mask_b & 0x1) << 10) |
+ ((pwrctrl->reg_ufs_infra_req_mask_b & 0x1) << 11) |
+ ((pwrctrl->reg_ufs_apsrc_req_mask_b & 0x1) << 12) |
+ ((pwrctrl->reg_ufs_vrf18_req_mask_b & 0x1) << 13) |
+ ((pwrctrl->reg_ufs_ddr_en_mask_b & 0x1) << 14) |
+ ((pwrctrl->reg_disp0_apsrc_req_mask_b & 0x1) << 15) |
+ ((pwrctrl->reg_disp0_ddr_en_mask_b & 0x1) << 16) |
+ ((pwrctrl->reg_disp1_apsrc_req_mask_b & 0x1) << 17) |
+ ((pwrctrl->reg_disp1_ddr_en_mask_b & 0x1) << 18) |
+ ((pwrctrl->reg_gce_infra_req_mask_b & 0x1) << 19) |
+ ((pwrctrl->reg_gce_apsrc_req_mask_b & 0x1) << 20) |
+ ((pwrctrl->reg_gce_vrf18_req_mask_b & 0x1) << 21) |
+ ((pwrctrl->reg_gce_ddr_en_mask_b & 0x1) << 22) |
+ ((pwrctrl->reg_apu_srcclkena_mask_b & 0x1) << 23) |
+ ((pwrctrl->reg_apu_infra_req_mask_b & 0x1) << 24) |
+ ((pwrctrl->reg_apu_apsrc_req_mask_b & 0x1) << 25) |
+ ((pwrctrl->reg_apu_vrf18_req_mask_b & 0x1) << 26) |
+ ((pwrctrl->reg_apu_ddr_en_mask_b & 0x1) << 27) |
+ ((pwrctrl->reg_cg_check_srcclkena_mask_b & 0x1) << 28) |
+ ((pwrctrl->reg_cg_check_apsrc_req_mask_b & 0x1) << 29) |
+ ((pwrctrl->reg_cg_check_vrf18_req_mask_b & 0x1) << 30) |
+ ((pwrctrl->reg_cg_check_ddr_en_mask_b & 0x1) << 31));
+
+ /* SPM_SRC3_MASK */
+ mmio_write_32(SPM_SRC3_MASK,
+ ((pwrctrl->reg_dvfsrc_event_trigger_mask_b & 0x1) << 0) |
+ ((pwrctrl->reg_sw2spm_int0_mask_b & 0x1) << 1) |
+ ((pwrctrl->reg_sw2spm_int1_mask_b & 0x1) << 2) |
+ ((pwrctrl->reg_sw2spm_int2_mask_b & 0x1) << 3) |
+ ((pwrctrl->reg_sw2spm_int3_mask_b & 0x1) << 4) |
+ ((pwrctrl->reg_sc_adsp2spm_wakeup_mask_b & 0x1) << 5) |
+ ((pwrctrl->reg_sc_sspm2spm_wakeup_mask_b & 0xf) << 6) |
+ ((pwrctrl->reg_sc_scp2spm_wakeup_mask_b & 0x1) << 10) |
+ ((pwrctrl->reg_csyspwrreq_mask & 0x1) << 11) |
+ ((pwrctrl->reg_spm_srcclkena_reserved_mask_b & 0x1) << 12) |
+ ((pwrctrl->reg_spm_infra_req_reserved_mask_b & 0x1) << 13) |
+ ((pwrctrl->reg_spm_apsrc_req_reserved_mask_b & 0x1) << 14) |
+ ((pwrctrl->reg_spm_vrf18_req_reserved_mask_b & 0x1) << 15) |
+ ((pwrctrl->reg_spm_ddr_en_reserved_mask_b & 0x1) << 16) |
+ ((pwrctrl->reg_mcupm_srcclkena_mask_b & 0x1) << 17) |
+ ((pwrctrl->reg_mcupm_infra_req_mask_b & 0x1) << 18) |
+ ((pwrctrl->reg_mcupm_apsrc_req_mask_b & 0x1) << 19) |
+ ((pwrctrl->reg_mcupm_vrf18_req_mask_b & 0x1) << 20) |
+ ((pwrctrl->reg_mcupm_ddr_en_mask_b & 0x1) << 21) |
+ ((pwrctrl->reg_msdc0_srcclkena_mask_b & 0x1) << 22) |
+ ((pwrctrl->reg_msdc0_infra_req_mask_b & 0x1) << 23) |
+ ((pwrctrl->reg_msdc0_apsrc_req_mask_b & 0x1) << 24) |
+ ((pwrctrl->reg_msdc0_vrf18_req_mask_b & 0x1) << 25) |
+ ((pwrctrl->reg_msdc0_ddr_en_mask_b & 0x1) << 26) |
+ ((pwrctrl->reg_msdc1_srcclkena_mask_b & 0x1) << 27) |
+ ((pwrctrl->reg_msdc1_infra_req_mask_b & 0x1) << 28) |
+ ((pwrctrl->reg_msdc1_apsrc_req_mask_b & 0x1) << 29) |
+ ((pwrctrl->reg_msdc1_vrf18_req_mask_b & 0x1) << 30) |
+ ((pwrctrl->reg_msdc1_ddr_en_mask_b & 0x1) << 31));
+
+ /* SPM_SRC4_MASK */
+ mmio_write_32(SPM_SRC4_MASK,
+ ((pwrctrl->ccif_event_mask_b & 0xffff) << 0) |
+ ((pwrctrl->reg_bak_psri_srcclkena_mask_b & 0x1) << 16) |
+ ((pwrctrl->reg_bak_psri_infra_req_mask_b & 0x1) << 17) |
+ ((pwrctrl->reg_bak_psri_apsrc_req_mask_b & 0x1) << 18) |
+ ((pwrctrl->reg_bak_psri_vrf18_req_mask_b & 0x1) << 19) |
+ ((pwrctrl->reg_bak_psri_ddr_en_mask_b & 0x1) << 20) |
+ ((pwrctrl->reg_dramc0_md32_infra_req_mask_b & 0x1) << 21) |
+ ((pwrctrl->reg_dramc0_md32_vrf18_req_mask_b & 0x1) << 22) |
+ ((pwrctrl->reg_dramc1_md32_infra_req_mask_b & 0x1) << 23) |
+ ((pwrctrl->reg_dramc1_md32_vrf18_req_mask_b & 0x1) << 24) |
+ ((pwrctrl->reg_conn_srcclkenb2pwrap_mask_b & 0x1) << 25) |
+ ((pwrctrl->reg_dramc0_md32_wakeup_mask & 0x1) << 26) |
+ ((pwrctrl->reg_dramc1_md32_wakeup_mask & 0x1) << 27));
+
+ /* SPM_SRC5_MASK */
+ mmio_write_32(SPM_SRC5_MASK,
+ ((pwrctrl->reg_mcusys_merge_apsrc_req_mask_b & 0x1ff) << 0) |
+ ((pwrctrl->reg_mcusys_merge_ddr_en_mask_b & 0x1ff) << 9) |
+ ((pwrctrl->reg_msdc2_srcclkena_mask_b & 0x1) << 18) |
+ ((pwrctrl->reg_msdc2_infra_req_mask_b & 0x1) << 19) |
+ ((pwrctrl->reg_msdc2_apsrc_req_mask_b & 0x1) << 20) |
+ ((pwrctrl->reg_msdc2_vrf18_req_mask_b & 0x1) << 21) |
+ ((pwrctrl->reg_msdc2_ddr_en_mask_b & 0x1) << 22) |
+ ((pwrctrl->reg_pcie_srcclkena_mask_b & 0x1) << 23) |
+ ((pwrctrl->reg_pcie_infra_req_mask_b & 0x1) << 24) |
+ ((pwrctrl->reg_pcie_apsrc_req_mask_b & 0x1) << 25) |
+ ((pwrctrl->reg_pcie_vrf18_req_mask_b & 0x1) << 26) |
+ ((pwrctrl->reg_pcie_ddr_en_mask_b & 0x1) << 27));
+
+ /* SPM_WAKEUP_EVENT_MASK */
+ mmio_write_32(SPM_WAKEUP_EVENT_MASK,
+ ((pwrctrl->reg_wakeup_event_mask & 0xffffffff) << 0));
+
+ /* SPM_WAKEUP_EVENT_EXT_MASK */
+ mmio_write_32(SPM_WAKEUP_EVENT_EXT_MASK,
+ ((pwrctrl->reg_ext_wakeup_event_mask & 0xffffffff) << 0));
+
+ /* Auto-gen End */
+}
+
+void __spm_disable_pcm_timer(void)
+{
+ mmio_clrsetbits_32(PCM_CON1, RG_PCM_TIMER_EN_LSB, SPM_REGWR_CFG_KEY);
+}
+
+void __spm_set_wakeup_event(const struct pwr_ctrl *pwrctrl)
+{
+ uint32_t val, mask;
+
+ /* toggle event counter clear */
+ mmio_setbits_32(PCM_CON1,
+ SPM_REGWR_CFG_KEY | SPM_EVENT_COUNTER_CLR_LSB);
+
+ /* toggle for reset SYS TIMER start point */
+ mmio_setbits_32(SYS_TIMER_CON, SYS_TIMER_START_EN_LSB);
+
+ if (pwrctrl->timer_val_cust == 0U) {
+ val = pwrctrl->timer_val;
+ } else {
+ val = pwrctrl->timer_val_cust;
+ }
+
+ mmio_write_32(PCM_TIMER_VAL, val);
+ mmio_setbits_32(PCM_CON1, SPM_REGWR_CFG_KEY | RG_PCM_TIMER_EN_LSB);
+
+ /* unmask AP wakeup source */
+ if (pwrctrl->wake_src_cust == 0U) {
+ mask = pwrctrl->wake_src;
+ } else {
+ mask = pwrctrl->wake_src_cust;
+ }
+
+ if (pwrctrl->reg_csyspwrreq_mask != 0U) {
+ mask &= ~R12_CSYSPWREQ_B;
+ }
+
+ mmio_write_32(SPM_WAKEUP_EVENT_MASK, ~mask);
+
+ /* unmask SPM ISR (keep TWAM setting) */
+ mmio_setbits_32(SPM_IRQ_MASK, ISRM_RET_IRQ_AUX);
+
+ /* toggle event counter clear */
+ mmio_clrsetbits_32(PCM_CON1, SPM_EVENT_COUNTER_CLR_LSB,
+ SPM_REGWR_CFG_KEY);
+ /* toggle for reset SYS TIMER start point */
+ mmio_clrbits_32(SYS_TIMER_CON, SYS_TIMER_START_EN_LSB);
+}
+
+void __spm_set_pcm_flags(struct pwr_ctrl *pwrctrl)
+{
+ /* set PCM flags and data */
+ if (pwrctrl->pcm_flags_cust_clr != 0U) {
+ pwrctrl->pcm_flags &= ~pwrctrl->pcm_flags_cust_clr;
+ }
+
+ if (pwrctrl->pcm_flags_cust_set != 0U) {
+ pwrctrl->pcm_flags |= pwrctrl->pcm_flags_cust_set;
+ }
+
+ if (pwrctrl->pcm_flags1_cust_clr != 0U) {
+ pwrctrl->pcm_flags1 &= ~pwrctrl->pcm_flags1_cust_clr;
+ }
+
+ if (pwrctrl->pcm_flags1_cust_set != 0U) {
+ pwrctrl->pcm_flags1 |= pwrctrl->pcm_flags1_cust_set;
+ }
+
+ mmio_write_32(SPM_SW_FLAG_0, pwrctrl->pcm_flags);
+ mmio_write_32(SPM_SW_FLAG_1, pwrctrl->pcm_flags1);
+ mmio_write_32(SPM_SW_RSV_7, pwrctrl->pcm_flags);
+ mmio_write_32(SPM_SW_RSV_8, pwrctrl->pcm_flags1);
+}
+
+void __spm_get_wakeup_status(struct wake_status *wakesta,
+ unsigned int ext_status)
+{
+ wakesta->tr.comm.r12 = mmio_read_32(SPM_BK_WAKE_EVENT);
+ wakesta->tr.comm.timer_out = mmio_read_32(SPM_BK_PCM_TIMER);
+ wakesta->tr.comm.r13 = mmio_read_32(PCM_REG13_DATA);
+ wakesta->tr.comm.req_sta0 = mmio_read_32(SRC_REQ_STA_0);
+ wakesta->tr.comm.req_sta1 = mmio_read_32(SRC_REQ_STA_1);
+ wakesta->tr.comm.req_sta2 = mmio_read_32(SRC_REQ_STA_2);
+ wakesta->tr.comm.req_sta3 = mmio_read_32(SRC_REQ_STA_3);
+ wakesta->tr.comm.req_sta4 = mmio_read_32(SRC_REQ_STA_4);
+ wakesta->tr.comm.debug_flag = mmio_read_32(PCM_WDT_LATCH_SPARE_0);
+ wakesta->tr.comm.debug_flag1 = mmio_read_32(PCM_WDT_LATCH_SPARE_1);
+
+ if ((ext_status & SPM_INTERNAL_STATUS_HW_S1) != 0U) {
+ wakesta->tr.comm.debug_flag |= (SPM_DBG_DEBUG_IDX_DDREN_WAKE |
+ SPM_DBG_DEBUG_IDX_DDREN_SLEEP);
+ mmio_write_32(PCM_WDT_LATCH_SPARE_0,
+ wakesta->tr.comm.debug_flag);
+ }
+
+ wakesta->tr.comm.b_sw_flag0 = mmio_read_32(SPM_SW_RSV_7);
+ wakesta->tr.comm.b_sw_flag1 = mmio_read_32(SPM_SW_RSV_8);
+
+ /* record below spm info for debug */
+ wakesta->r12 = mmio_read_32(SPM_BK_WAKE_EVENT);
+ wakesta->r12_ext = mmio_read_32(SPM_WAKEUP_STA);
+ wakesta->raw_sta = mmio_read_32(SPM_WAKEUP_STA);
+ wakesta->raw_ext_sta = mmio_read_32(SPM_WAKEUP_EXT_STA);
+ wakesta->md32pcm_wakeup_sta = mmio_read_32(MD32PCM_WAKEUP_STA);
+ wakesta->md32pcm_event_sta = mmio_read_32(MD32PCM_EVENT_STA);
+ wakesta->src_req = mmio_read_32(SPM_SRC_REQ);
+
+ /* backup of SPM_WAKEUP_MISC */
+ wakesta->wake_misc = mmio_read_32(SPM_BK_WAKE_MISC);
+
+ /* get sleep time, backup of PCM_TIMER_OUT */
+ wakesta->timer_out = mmio_read_32(SPM_BK_PCM_TIMER);
+
+ /* get other SYS and co-clock status */
+ wakesta->r13 = mmio_read_32(PCM_REG13_DATA);
+ wakesta->idle_sta = mmio_read_32(SUBSYS_IDLE_STA);
+ wakesta->req_sta0 = mmio_read_32(SRC_REQ_STA_0);
+ wakesta->req_sta1 = mmio_read_32(SRC_REQ_STA_1);
+ wakesta->req_sta2 = mmio_read_32(SRC_REQ_STA_2);
+ wakesta->req_sta3 = mmio_read_32(SRC_REQ_STA_3);
+ wakesta->req_sta4 = mmio_read_32(SRC_REQ_STA_4);
+
+ /* get HW CG check status */
+ wakesta->cg_check_sta = mmio_read_32(SPM_CG_CHECK_STA);
+
+ /* get debug flag for PCM execution check */
+ wakesta->debug_flag = mmio_read_32(PCM_WDT_LATCH_SPARE_0);
+ wakesta->debug_flag1 = mmio_read_32(PCM_WDT_LATCH_SPARE_1);
+
+ /* get backup SW flag status */
+ wakesta->b_sw_flag0 = mmio_read_32(SPM_SW_RSV_7);
+ wakesta->b_sw_flag1 = mmio_read_32(SPM_SW_RSV_8);
+
+ wakesta->rt_req_sta0 = mmio_read_32(SPM_SW_RSV_2);
+ wakesta->rt_req_sta1 = mmio_read_32(SPM_SW_RSV_3);
+ wakesta->rt_req_sta2 = mmio_read_32(SPM_SW_RSV_4);
+ wakesta->rt_req_sta3 = mmio_read_32(SPM_SW_RSV_5);
+ wakesta->rt_req_sta4 = mmio_read_32(SPM_SW_RSV_6);
+
+ /* get ISR status */
+ wakesta->isr = mmio_read_32(SPM_IRQ_STA);
+
+ /* get SW flag status */
+ wakesta->sw_flag0 = mmio_read_32(SPM_SW_FLAG_0);
+ wakesta->sw_flag1 = mmio_read_32(SPM_SW_FLAG_1);
+
+ /* get CLK SETTLE */
+ wakesta->clk_settle = mmio_read_32(SPM_CLK_SETTLE);
+
+ /* check abort */
+ wakesta->abort = (wakesta->debug_flag & DEBUG_ABORT_MASK) |
+ (wakesta->debug_flag1 & DEBUG_ABORT_MASK_1);
+}
+
+void __spm_clean_after_wakeup(void)
+{
+ mmio_write_32(SPM_BK_WAKE_EVENT,
+ mmio_read_32(SPM_WAKEUP_STA) |
+ mmio_read_32(SPM_BK_WAKE_EVENT));
+ mmio_write_32(SPM_CPU_WAKEUP_EVENT, 0);
+
+ /*
+ * clean wakeup event raw status (for edge trigger event)
+ * bit[28] for cpu wake up event
+ */
+ mmio_write_32(SPM_WAKEUP_EVENT_MASK, SPM_WAKEUP_EVENT_MASK_CLEAN_MASK);
+
+ /* clean ISR status (except TWAM) */
+ 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_set_pcm_wdt(int en)
+{
+ mmio_clrsetbits_32(PCM_CON1, RG_PCM_WDT_EN_LSB,
+ SPM_REGWR_CFG_KEY);
+
+ if (en == 1) {
+ mmio_clrsetbits_32(PCM_CON1, RG_PCM_WDT_WAKE_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 | RG_PCM_WDT_EN_LSB);
+ }
+}
+
+void __spm_send_cpu_wakeup_event(void)
+{
+ /* SPM will clear SPM_CPU_WAKEUP_EVENT */
+ mmio_write_32(SPM_CPU_WAKEUP_EVENT, 1);
+}
+
+void __spm_ext_int_wakeup_req_clr(void)
+{
+ mmio_write_32(EXT_INT_WAKEUP_REQ_CLR, mmio_read_32(ROOT_CPUTOP_ADDR));
+
+ /* Clear spm2mcupm wakeup interrupt status */
+ mmio_write_32(SPM2MCUPM_CON, 0);
+}
+
+void __spm_xo_soc_bblpm(int en)
+{
+ if (en == 1) {
+ mmio_clrsetbits_32(RC_M00_SRCLKEN_CFG,
+ RC_SW_SRCLKEN_FPM, RC_SW_SRCLKEN_RC);
+ assert(mt_spm_bblpm_cnt == 0);
+ mt_spm_bblpm_cnt += 1;
+ } else {
+ mmio_clrsetbits_32(RC_M00_SRCLKEN_CFG,
+ RC_SW_SRCLKEN_RC, RC_SW_SRCLKEN_FPM);
+ mt_spm_bblpm_cnt -= 1;
+ }
+}
+
+void __spm_hw_s1_state_monitor(int en, unsigned int *status)
+{
+ unsigned int reg;
+
+ reg = mmio_read_32(SPM_ACK_CHK_CON_3);
+
+ if (en == 1) {
+ reg &= ~SPM_ACK_CHK_3_CON_CLR_ALL;
+ mmio_write_32(SPM_ACK_CHK_CON_3, reg);
+ reg |= SPM_ACK_CHK_3_CON_EN;
+ mmio_write_32(SPM_ACK_CHK_CON_3, reg);
+ } else {
+ if (((reg & SPM_ACK_CHK_3_CON_RESULT) != 0U) &&
+ (status != NULL)) {
+ *status |= SPM_INTERNAL_STATUS_HW_S1;
+ }
+
+ mmio_clrsetbits_32(SPM_ACK_CHK_CON_3, SPM_ACK_CHK_3_CON_EN,
+ SPM_ACK_CHK_3_CON_HW_MODE_TRIG |
+ SPM_ACK_CHK_3_CON_CLR_ALL);
+ }
+}
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm_internal.h b/plat/mediatek/mt8192/drivers/spm/mt_spm_internal.h
new file mode 100644
index 0000000..1d0f783
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm_internal.h
@@ -0,0 +1,637 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_INTERNAL_H
+#define MT_SPM_INTERNAL_H
+
+#include "mt_spm.h"
+
+/**************************************
+ * Config and Parameter
+ **************************************/
+#define POWER_ON_VAL0_DEF 0x0000F100
+#define POWER_ON_VAL1_DEF 0x80015860
+#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_AP_STANDBY_CON */
+#define WFI_OP_AND 1
+#define WFI_OP_OR 0
+
+/* 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 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_GIC_WAKEUP 0x3FF
+#define WAKE_MISC_DVFSRC_IRQ DVFSRC_IRQ_LSB
+#define WAKE_MISC_REG_CPU_WAKEUP SPM_WAKEUP_MISC_REG_CPU_WAKEUP_LSB
+#define WAKE_MISC_PCM_TIMER_EVENT PCM_TIMER_EVENT_LSB
+#define WAKE_MISC_PMIC_OUT_B ((1U << 19) | (1U << 20))
+#define WAKE_MISC_TWAM_IRQ_B TWAM_IRQ_B_LSB
+#define WAKE_MISC_PMSR_IRQ_B_SET0 PMSR_IRQ_B_SET0_LSB
+#define WAKE_MISC_PMSR_IRQ_B_SET1 PMSR_IRQ_B_SET1_LSB
+#define WAKE_MISC_PMSR_IRQ_B_SET2 PMSR_IRQ_B_SET2_LSB
+#define WAKE_MISC_SPM_ACK_CHK_WAKEUP_0 SPM_ACK_CHK_WAKEUP_0_LSB
+#define WAKE_MISC_SPM_ACK_CHK_WAKEUP_1 SPM_ACK_CHK_WAKEUP_1_LSB
+#define WAKE_MISC_SPM_ACK_CHK_WAKEUP_2 SPM_ACK_CHK_WAKEUP_2_LSB
+#define WAKE_MISC_SPM_ACK_CHK_WAKEUP_3 SPM_ACK_CHK_WAKEUP_3_LSB
+#define WAKE_MISC_SPM_ACK_CHK_WAKEUP_ALL SPM_ACK_CHK_WAKEUP_ALL_LSB
+#define WAKE_MISC_PMIC_IRQ_ACK PMIC_IRQ_ACK_LSB
+#define WAKE_MISC_PMIC_SCP_IRQ PMIC_SCP_IRQ_LSB
+
+/* ABORT MASK for DEBUG FOORTPRINT */
+#define DEBUG_ABORT_MASK \
+ (SPM_DBG_DEBUG_IDX_DRAM_SREF_ABORT_IN_APSRC | \
+ SPM_DBG_DEBUG_IDX_DRAM_SREF_ABORT_IN_DDREN)
+
+#define DEBUG_ABORT_MASK_1 \
+ (SPM_DBG1_DEBUG_IDX_VRCXO_SLEEP_ABORT | \
+ SPM_DBG1_DEBUG_IDX_PWRAP_SLEEP_ACK_LOW_ABORT | \
+ SPM_DBG1_DEBUG_IDX_PWRAP_SLEEP_ACK_HIGH_ABORT | \
+ SPM_DBG1_DEBUG_IDX_EMI_SLP_IDLE_ABORT | \
+ SPM_DBG1_DEBUG_IDX_SCP_SLP_ACK_LOW_ABORT | \
+ SPM_DBG1_DEBUG_IDX_SCP_SLP_ACK_HIGH_ABORT | \
+ SPM_DBG1_DEBUG_IDX_SPM_DVFS_CMD_RDY_ABORT)
+
+#define MCUPM_MBOX_WAKEUP_CPU 0x0C55FD10
+
+struct pwr_ctrl {
+ uint32_t pcm_flags;
+ uint32_t pcm_flags_cust;
+ uint32_t pcm_flags_cust_set;
+ uint32_t pcm_flags_cust_clr;
+ uint32_t pcm_flags1;
+ uint32_t pcm_flags1_cust;
+ uint32_t pcm_flags1_cust_set;
+ uint32_t pcm_flags1_cust_clr;
+ uint32_t timer_val;
+ uint32_t timer_val_cust;
+ uint32_t timer_val_ramp_en;
+ uint32_t timer_val_ramp_en_sec;
+ uint32_t wake_src;
+ uint32_t wake_src_cust;
+ uint32_t wakelock_timer_val;
+ uint8_t wdt_disable;
+
+ /* Auto-gen Start */
+
+ /* SPM_CLK_CON */
+ uint8_t reg_srcclken0_ctl;
+ uint8_t reg_srcclken1_ctl;
+ uint8_t reg_spm_lock_infra_dcm;
+ uint8_t reg_srcclken_mask;
+ uint8_t reg_md1_c32rm_en;
+ uint8_t reg_md2_c32rm_en;
+ uint8_t reg_clksq0_sel_ctrl;
+ uint8_t reg_clksq1_sel_ctrl;
+ uint8_t reg_srcclken0_en;
+ uint8_t reg_srcclken1_en;
+ uint32_t reg_sysclk0_src_mask_b;
+ uint32_t reg_sysclk1_src_mask_b;
+
+ /* SPM_AP_STANDBY_CON */
+ uint8_t reg_wfi_op;
+ uint8_t reg_wfi_type;
+ uint8_t reg_mp0_cputop_idle_mask;
+ uint8_t reg_mp1_cputop_idle_mask;
+ uint8_t reg_mcusys_idle_mask;
+ uint8_t reg_md_apsrc_1_sel;
+ uint8_t reg_md_apsrc_0_sel;
+ uint8_t reg_conn_apsrc_sel;
+
+ /* SPM_SRC6_MASK */
+ uint8_t reg_dpmaif_srcclkena_mask_b;
+ uint8_t reg_dpmaif_infra_req_mask_b;
+ uint8_t reg_dpmaif_apsrc_req_mask_b;
+ uint8_t reg_dpmaif_vrf18_req_mask_b;
+ uint8_t reg_dpmaif_ddr_en_mask_b;
+ /* SPM_SRC_REQ */
+ uint8_t reg_spm_apsrc_req;
+ uint8_t reg_spm_f26m_req;
+ uint8_t reg_spm_infra_req;
+ uint8_t reg_spm_vrf18_req;
+ uint8_t reg_spm_ddr_en_req;
+ uint8_t reg_spm_dvfs_req;
+ uint8_t reg_spm_sw_mailbox_req;
+ uint8_t reg_spm_sspm_mailbox_req;
+ uint8_t reg_spm_adsp_mailbox_req;
+ uint8_t reg_spm_scp_mailbox_req;
+
+ /* SPM_SRC_MASK */
+ uint8_t reg_md_srcclkena_0_mask_b;
+ uint8_t reg_md_srcclkena2infra_req_0_mask_b;
+ uint8_t reg_md_apsrc2infra_req_0_mask_b;
+ uint8_t reg_md_apsrc_req_0_mask_b;
+ uint8_t reg_md_vrf18_req_0_mask_b;
+ uint8_t reg_md_ddr_en_0_mask_b;
+ uint8_t reg_md_srcclkena_1_mask_b;
+ uint8_t reg_md_srcclkena2infra_req_1_mask_b;
+ uint8_t reg_md_apsrc2infra_req_1_mask_b;
+ uint8_t reg_md_apsrc_req_1_mask_b;
+ uint8_t reg_md_vrf18_req_1_mask_b;
+ uint8_t reg_md_ddr_en_1_mask_b;
+ uint8_t reg_conn_srcclkena_mask_b;
+ uint8_t reg_conn_srcclkenb_mask_b;
+ uint8_t reg_conn_infra_req_mask_b;
+ uint8_t reg_conn_apsrc_req_mask_b;
+ uint8_t reg_conn_vrf18_req_mask_b;
+ uint8_t reg_conn_ddr_en_mask_b;
+ uint8_t reg_conn_vfe28_mask_b;
+ uint8_t reg_srcclkeni0_srcclkena_mask_b;
+ uint8_t reg_srcclkeni0_infra_req_mask_b;
+ uint8_t reg_srcclkeni1_srcclkena_mask_b;
+ uint8_t reg_srcclkeni1_infra_req_mask_b;
+ uint8_t reg_srcclkeni2_srcclkena_mask_b;
+ uint8_t reg_srcclkeni2_infra_req_mask_b;
+ uint8_t reg_infrasys_apsrc_req_mask_b;
+ uint8_t reg_infrasys_ddr_en_mask_b;
+ uint8_t reg_md32_srcclkena_mask_b;
+ uint8_t reg_md32_infra_req_mask_b;
+ uint8_t reg_md32_apsrc_req_mask_b;
+ uint8_t reg_md32_vrf18_req_mask_b;
+ uint8_t reg_md32_ddr_en_mask_b;
+
+ /* SPM_SRC2_MASK */
+ uint8_t reg_scp_srcclkena_mask_b;
+ uint8_t reg_scp_infra_req_mask_b;
+ uint8_t reg_scp_apsrc_req_mask_b;
+ uint8_t reg_scp_vrf18_req_mask_b;
+ uint8_t reg_scp_ddr_en_mask_b;
+ uint8_t reg_audio_dsp_srcclkena_mask_b;
+ uint8_t reg_audio_dsp_infra_req_mask_b;
+ uint8_t reg_audio_dsp_apsrc_req_mask_b;
+ uint8_t reg_audio_dsp_vrf18_req_mask_b;
+ uint8_t reg_audio_dsp_ddr_en_mask_b;
+ uint8_t reg_ufs_srcclkena_mask_b;
+ uint8_t reg_ufs_infra_req_mask_b;
+ uint8_t reg_ufs_apsrc_req_mask_b;
+ uint8_t reg_ufs_vrf18_req_mask_b;
+ uint8_t reg_ufs_ddr_en_mask_b;
+ uint8_t reg_disp0_apsrc_req_mask_b;
+ uint8_t reg_disp0_ddr_en_mask_b;
+ uint8_t reg_disp1_apsrc_req_mask_b;
+ uint8_t reg_disp1_ddr_en_mask_b;
+ uint8_t reg_gce_infra_req_mask_b;
+ uint8_t reg_gce_apsrc_req_mask_b;
+ uint8_t reg_gce_vrf18_req_mask_b;
+ uint8_t reg_gce_ddr_en_mask_b;
+ uint8_t reg_apu_srcclkena_mask_b;
+ uint8_t reg_apu_infra_req_mask_b;
+ uint8_t reg_apu_apsrc_req_mask_b;
+ uint8_t reg_apu_vrf18_req_mask_b;
+ uint8_t reg_apu_ddr_en_mask_b;
+ uint8_t reg_cg_check_srcclkena_mask_b;
+ uint8_t reg_cg_check_apsrc_req_mask_b;
+ uint8_t reg_cg_check_vrf18_req_mask_b;
+ uint8_t reg_cg_check_ddr_en_mask_b;
+
+ /* SPM_SRC3_MASK */
+ uint8_t reg_dvfsrc_event_trigger_mask_b;
+ uint8_t reg_sw2spm_int0_mask_b;
+ uint8_t reg_sw2spm_int1_mask_b;
+ uint8_t reg_sw2spm_int2_mask_b;
+ uint8_t reg_sw2spm_int3_mask_b;
+ uint8_t reg_sc_adsp2spm_wakeup_mask_b;
+ uint8_t reg_sc_sspm2spm_wakeup_mask_b;
+ uint8_t reg_sc_scp2spm_wakeup_mask_b;
+ uint8_t reg_csyspwrreq_mask;
+ uint8_t reg_spm_srcclkena_reserved_mask_b;
+ uint8_t reg_spm_infra_req_reserved_mask_b;
+ uint8_t reg_spm_apsrc_req_reserved_mask_b;
+ uint8_t reg_spm_vrf18_req_reserved_mask_b;
+ uint8_t reg_spm_ddr_en_reserved_mask_b;
+ uint8_t reg_mcupm_srcclkena_mask_b;
+ uint8_t reg_mcupm_infra_req_mask_b;
+ uint8_t reg_mcupm_apsrc_req_mask_b;
+ uint8_t reg_mcupm_vrf18_req_mask_b;
+ uint8_t reg_mcupm_ddr_en_mask_b;
+ uint8_t reg_msdc0_srcclkena_mask_b;
+ uint8_t reg_msdc0_infra_req_mask_b;
+ uint8_t reg_msdc0_apsrc_req_mask_b;
+ uint8_t reg_msdc0_vrf18_req_mask_b;
+ uint8_t reg_msdc0_ddr_en_mask_b;
+ uint8_t reg_msdc1_srcclkena_mask_b;
+ uint8_t reg_msdc1_infra_req_mask_b;
+ uint8_t reg_msdc1_apsrc_req_mask_b;
+ uint8_t reg_msdc1_vrf18_req_mask_b;
+ uint8_t reg_msdc1_ddr_en_mask_b;
+
+ /* SPM_SRC4_MASK */
+ uint32_t ccif_event_mask_b;
+ uint8_t reg_bak_psri_srcclkena_mask_b;
+ uint8_t reg_bak_psri_infra_req_mask_b;
+ uint8_t reg_bak_psri_apsrc_req_mask_b;
+ uint8_t reg_bak_psri_vrf18_req_mask_b;
+ uint8_t reg_bak_psri_ddr_en_mask_b;
+ uint8_t reg_dramc0_md32_infra_req_mask_b;
+ uint8_t reg_dramc0_md32_vrf18_req_mask_b;
+ uint8_t reg_dramc1_md32_infra_req_mask_b;
+ uint8_t reg_dramc1_md32_vrf18_req_mask_b;
+ uint8_t reg_conn_srcclkenb2pwrap_mask_b;
+ uint8_t reg_dramc0_md32_wakeup_mask;
+ uint8_t reg_dramc1_md32_wakeup_mask;
+
+ /* SPM_SRC5_MASK */
+ uint32_t reg_mcusys_merge_apsrc_req_mask_b;
+ uint32_t reg_mcusys_merge_ddr_en_mask_b;
+ uint8_t reg_msdc2_srcclkena_mask_b;
+ uint8_t reg_msdc2_infra_req_mask_b;
+ uint8_t reg_msdc2_apsrc_req_mask_b;
+ uint8_t reg_msdc2_vrf18_req_mask_b;
+ uint8_t reg_msdc2_ddr_en_mask_b;
+ uint8_t reg_pcie_srcclkena_mask_b;
+ uint8_t reg_pcie_infra_req_mask_b;
+ uint8_t reg_pcie_apsrc_req_mask_b;
+ uint8_t reg_pcie_vrf18_req_mask_b;
+ uint8_t reg_pcie_ddr_en_mask_b;
+
+ /* SPM_WAKEUP_EVENT_MASK */
+ uint32_t reg_wakeup_event_mask;
+
+ /* SPM_WAKEUP_EVENT_EXT_MASK */
+ uint32_t reg_ext_wakeup_event_mask;
+
+ /* Auto-gen End */
+};
+
+/* code gen by spm_pwr_ctrl_atf.pl, need struct pwr_ctrl */
+enum pwr_ctrl_enum {
+ PW_PCM_FLAGS,
+ PW_PCM_FLAGS_CUST,
+ PW_PCM_FLAGS_CUST_SET,
+ PW_PCM_FLAGS_CUST_CLR,
+ PW_PCM_FLAGS1,
+ PW_PCM_FLAGS1_CUST,
+ PW_PCM_FLAGS1_CUST_SET,
+ PW_PCM_FLAGS1_CUST_CLR,
+ PW_TIMER_VAL,
+ PW_TIMER_VAL_CUST,
+ PW_TIMER_VAL_RAMP_EN,
+ PW_TIMER_VAL_RAMP_EN_SEC,
+ PW_WAKE_SRC,
+ PW_WAKE_SRC_CUST,
+ PW_WAKELOCK_TIMER_VAL,
+ PW_WDT_DISABLE,
+
+ /* SPM_CLK_CON */
+ PW_REG_SRCCLKEN0_CTL,
+ PW_REG_SRCCLKEN1_CTL,
+ PW_REG_SPM_LOCK_INFRA_DCM,
+ PW_REG_SRCCLKEN_MASK,
+ PW_REG_MD1_C32RM_EN,
+ PW_REG_MD2_C32RM_EN,
+ PW_REG_CLKSQ0_SEL_CTRL,
+ PW_REG_CLKSQ1_SEL_CTRL,
+ PW_REG_SRCCLKEN0_EN,
+ PW_REG_SRCCLKEN1_EN,
+ PW_REG_SYSCLK0_SRC_MASK_B,
+ PW_REG_SYSCLK1_SRC_MASK_B,
+
+ /* SPM_AP_STANDBY_CON */
+ PW_REG_WFI_OP,
+ PW_REG_WFI_TYPE,
+ PW_REG_MP0_CPUTOP_IDLE_MASK,
+ PW_REG_MP1_CPUTOP_IDLE_MASK,
+ PW_REG_MCUSYS_IDLE_MASK,
+ PW_REG_MD_APSRC_1_SEL,
+ PW_REG_MD_APSRC_0_SEL,
+ PW_REG_CONN_APSRC_SEL,
+
+ /* SPM_SRC6_MASK */
+ PW_REG_DPMAIF_SRCCLKENA_MASK_B,
+ PW_REG_DPMAIF_INFRA_REQ_MASK_B,
+ PW_REG_DPMAIF_APSRC_REQ_MASK_B,
+ PW_REG_DPMAIF_VRF18_REQ_MASK_B,
+ PW_REG_DPMAIF_DDR_EN_MASK_B,
+
+ /* SPM_SRC_REQ */
+ PW_REG_SPM_APSRC_REQ,
+ PW_REG_SPM_F26M_REQ,
+ PW_REG_SPM_INFRA_REQ,
+ PW_REG_SPM_VRF18_REQ,
+ PW_REG_SPM_DDR_EN_REQ,
+ PW_REG_SPM_DVFS_REQ,
+ PW_REG_SPM_SW_MAILBOX_REQ,
+ PW_REG_SPM_SSPM_MAILBOX_REQ,
+ PW_REG_SPM_ADSP_MAILBOX_REQ,
+ PW_REG_SPM_SCP_MAILBOX_REQ,
+
+ /* SPM_SRC_MASK */
+ PW_REG_MD_SRCCLKENA_0_MASK_B,
+ PW_REG_MD_SRCCLKENA2INFRA_REQ_0_MASK_B,
+ PW_REG_MD_APSRC2INFRA_REQ_0_MASK_B,
+ PW_REG_MD_APSRC_REQ_0_MASK_B,
+ PW_REG_MD_VRF18_REQ_0_MASK_B,
+ PW_REG_MD_DDR_EN_0_MASK_B,
+ PW_REG_MD_SRCCLKENA_1_MASK_B,
+ PW_REG_MD_SRCCLKENA2INFRA_REQ_1_MASK_B,
+ PW_REG_MD_APSRC2INFRA_REQ_1_MASK_B,
+ PW_REG_MD_APSRC_REQ_1_MASK_B,
+ PW_REG_MD_VRF18_REQ_1_MASK_B,
+ PW_REG_MD_DDR_EN_1_MASK_B,
+ PW_REG_CONN_SRCCLKENA_MASK_B,
+ PW_REG_CONN_SRCCLKENB_MASK_B,
+ PW_REG_CONN_INFRA_REQ_MASK_B,
+ PW_REG_CONN_APSRC_REQ_MASK_B,
+ PW_REG_CONN_VRF18_REQ_MASK_B,
+ PW_REG_CONN_DDR_EN_MASK_B,
+ PW_REG_CONN_VFE28_MASK_B,
+ PW_REG_SRCCLKENI0_SRCCLKENA_MASK_B,
+ PW_REG_SRCCLKENI0_INFRA_REQ_MASK_B,
+ PW_REG_SRCCLKENI1_SRCCLKENA_MASK_B,
+ PW_REG_SRCCLKENI1_INFRA_REQ_MASK_B,
+ PW_REG_SRCCLKENI2_SRCCLKENA_MASK_B,
+ PW_REG_SRCCLKENI2_INFRA_REQ_MASK_B,
+ PW_REG_INFRASYS_APSRC_REQ_MASK_B,
+ PW_REG_INFRASYS_DDR_EN_MASK_B,
+ PW_REG_MD32_SRCCLKENA_MASK_B,
+ PW_REG_MD32_INFRA_REQ_MASK_B,
+ PW_REG_MD32_APSRC_REQ_MASK_B,
+ PW_REG_MD32_VRF18_REQ_MASK_B,
+ PW_REG_MD32_DDR_EN_MASK_B,
+
+ /* SPM_SRC2_MASK */
+ PW_REG_SCP_SRCCLKENA_MASK_B,
+ PW_REG_SCP_INFRA_REQ_MASK_B,
+ PW_REG_SCP_APSRC_REQ_MASK_B,
+ PW_REG_SCP_VRF18_REQ_MASK_B,
+ PW_REG_SCP_DDR_EN_MASK_B,
+ PW_REG_AUDIO_DSP_SRCCLKENA_MASK_B,
+ PW_REG_AUDIO_DSP_INFRA_REQ_MASK_B,
+ PW_REG_AUDIO_DSP_APSRC_REQ_MASK_B,
+ PW_REG_AUDIO_DSP_VRF18_REQ_MASK_B,
+ PW_REG_AUDIO_DSP_DDR_EN_MASK_B,
+ PW_REG_UFS_SRCCLKENA_MASK_B,
+ PW_REG_UFS_INFRA_REQ_MASK_B,
+ PW_REG_UFS_APSRC_REQ_MASK_B,
+ PW_REG_UFS_VRF18_REQ_MASK_B,
+ PW_REG_UFS_DDR_EN_MASK_B,
+ PW_REG_DISP0_APSRC_REQ_MASK_B,
+ PW_REG_DISP0_DDR_EN_MASK_B,
+ PW_REG_DISP1_APSRC_REQ_MASK_B,
+ PW_REG_DISP1_DDR_EN_MASK_B,
+ PW_REG_GCE_INFRA_REQ_MASK_B,
+ PW_REG_GCE_APSRC_REQ_MASK_B,
+ PW_REG_GCE_VRF18_REQ_MASK_B,
+ PW_REG_GCE_DDR_EN_MASK_B,
+ PW_REG_APU_SRCCLKENA_MASK_B,
+ PW_REG_APU_INFRA_REQ_MASK_B,
+ PW_REG_APU_APSRC_REQ_MASK_B,
+ PW_REG_APU_VRF18_REQ_MASK_B,
+ PW_REG_APU_DDR_EN_MASK_B,
+ PW_REG_CG_CHECK_SRCCLKENA_MASK_B,
+ PW_REG_CG_CHECK_APSRC_REQ_MASK_B,
+ PW_REG_CG_CHECK_VRF18_REQ_MASK_B,
+ PW_REG_CG_CHECK_DDR_EN_MASK_B,
+
+ /* SPM_SRC3_MASK */
+ PW_REG_DVFSRC_EVENT_TRIGGER_MASK_B,
+ PW_REG_SW2SPM_INT0_MASK_B,
+ PW_REG_SW2SPM_INT1_MASK_B,
+ PW_REG_SW2SPM_INT2_MASK_B,
+ PW_REG_SW2SPM_INT3_MASK_B,
+ PW_REG_SC_ADSP2SPM_WAKEUP_MASK_B,
+ PW_REG_SC_SSPM2SPM_WAKEUP_MASK_B,
+ PW_REG_SC_SCP2SPM_WAKEUP_MASK_B,
+ PW_REG_CSYSPWRREQ_MASK,
+ PW_REG_SPM_SRCCLKENA_RESERVED_MASK_B,
+ PW_REG_SPM_INFRA_REQ_RESERVED_MASK_B,
+ PW_REG_SPM_APSRC_REQ_RESERVED_MASK_B,
+ PW_REG_SPM_VRF18_REQ_RESERVED_MASK_B,
+ PW_REG_SPM_DDR_EN_RESERVED_MASK_B,
+ PW_REG_MCUPM_SRCCLKENA_MASK_B,
+ PW_REG_MCUPM_INFRA_REQ_MASK_B,
+ PW_REG_MCUPM_APSRC_REQ_MASK_B,
+ PW_REG_MCUPM_VRF18_REQ_MASK_B,
+ PW_REG_MCUPM_DDR_EN_MASK_B,
+ PW_REG_MSDC0_SRCCLKENA_MASK_B,
+ PW_REG_MSDC0_INFRA_REQ_MASK_B,
+ PW_REG_MSDC0_APSRC_REQ_MASK_B,
+ PW_REG_MSDC0_VRF18_REQ_MASK_B,
+ PW_REG_MSDC0_DDR_EN_MASK_B,
+ PW_REG_MSDC1_SRCCLKENA_MASK_B,
+ PW_REG_MSDC1_INFRA_REQ_MASK_B,
+ PW_REG_MSDC1_APSRC_REQ_MASK_B,
+ PW_REG_MSDC1_VRF18_REQ_MASK_B,
+ PW_REG_MSDC1_DDR_EN_MASK_B,
+
+ /* SPM_SRC4_MASK */
+ PW_CCIF_EVENT_MASK_B,
+ PW_REG_BAK_PSRI_SRCCLKENA_MASK_B,
+ PW_REG_BAK_PSRI_INFRA_REQ_MASK_B,
+ PW_REG_BAK_PSRI_APSRC_REQ_MASK_B,
+ PW_REG_BAK_PSRI_VRF18_REQ_MASK_B,
+ PW_REG_BAK_PSRI_DDR_EN_MASK_B,
+ PW_REG_DRAMC0_MD32_INFRA_REQ_MASK_B,
+ PW_REG_DRAMC0_MD32_VRF18_REQ_MASK_B,
+ PW_REG_DRAMC1_MD32_INFRA_REQ_MASK_B,
+ PW_REG_DRAMC1_MD32_VRF18_REQ_MASK_B,
+ PW_REG_CONN_SRCCLKENB2PWRAP_MASK_B,
+ PW_REG_DRAMC0_MD32_WAKEUP_MASK,
+ PW_REG_DRAMC1_MD32_WAKEUP_MASK,
+
+ /* SPM_SRC5_MASK */
+ PW_REG_MCUSYS_MERGE_APSRC_REQ_MASK_B,
+ PW_REG_MCUSYS_MERGE_DDR_EN_MASK_B,
+ PW_REG_MSDC2_SRCCLKENA_MASK_B,
+ PW_REG_MSDC2_INFRA_REQ_MASK_B,
+ PW_REG_MSDC2_APSRC_REQ_MASK_B,
+ PW_REG_MSDC2_VRF18_REQ_MASK_B,
+ PW_REG_MSDC2_DDR_EN_MASK_B,
+ PW_REG_PCIE_SRCCLKENA_MASK_B,
+ PW_REG_PCIE_INFRA_REQ_MASK_B,
+ PW_REG_PCIE_APSRC_REQ_MASK_B,
+ PW_REG_PCIE_VRF18_REQ_MASK_B,
+ PW_REG_PCIE_DDR_EN_MASK_B,
+
+ /* SPM_WAKEUP_EVENT_MASK */
+ PW_REG_WAKEUP_EVENT_MASK,
+
+ /* SPM_WAKEUP_EVENT_EXT_MASK */
+ PW_REG_EXT_WAKEUP_EVENT_MASK,
+
+ PW_MAX_COUNT,
+};
+
+#define SPM_INTERNAL_STATUS_HW_S1 (1U << 0)
+#define SPM_ACK_CHK_3_SEL_HW_S1 0x00350098
+#define SPM_ACK_CHK_3_HW_S1_CNT 1
+#define SPM_ACK_CHK_3_CON_HW_MODE_TRIG 0x800
+#define SPM_ACK_CHK_3_CON_EN 0x110
+#define SPM_ACK_CHK_3_CON_CLR_ALL 0x2
+#define SPM_ACK_CHK_3_CON_RESULT 0x8000
+
+struct wake_status_trace_comm {
+ uint32_t debug_flag; /* PCM_WDT_LATCH_SPARE_0 */
+ uint32_t debug_flag1; /* PCM_WDT_LATCH_SPARE_1 */
+ uint32_t timer_out; /* SPM_SW_RSV_6*/
+ uint32_t b_sw_flag0; /* SPM_SW_RSV_7 */
+ uint32_t b_sw_flag1; /* SPM_SW_RSV_7 */
+ uint32_t r12; /* SPM_SW_RSV_0 */
+ uint32_t r13; /* PCM_REG13_DATA */
+ uint32_t req_sta0; /* SRC_REQ_STA_0 */
+ uint32_t req_sta1; /* SRC_REQ_STA_1 */
+ uint32_t req_sta2; /* SRC_REQ_STA_2 */
+ uint32_t req_sta3; /* SRC_REQ_STA_3 */
+ uint32_t req_sta4; /* SRC_REQ_STA_4 */
+};
+
+struct wake_status_trace {
+ struct wake_status_trace_comm comm;
+};
+
+struct wake_status {
+ struct wake_status_trace tr;
+ uint32_t r12; /* SPM_BK_WAKE_EVENT */
+ uint32_t r12_ext; /* SPM_WAKEUP_EXT_STA */
+ uint32_t raw_sta; /* SPM_WAKEUP_STA */
+ uint32_t raw_ext_sta; /* SPM_WAKEUP_EXT_STA */
+ uint32_t md32pcm_wakeup_sta; /* MD32CPM_WAKEUP_STA */
+ uint32_t md32pcm_event_sta; /* MD32PCM_EVENT_STA */
+ uint32_t wake_misc; /* SPM_BK_WAKE_MISC */
+ uint32_t timer_out; /* SPM_BK_PCM_TIMER */
+ uint32_t r13; /* PCM_REG13_DATA */
+ uint32_t idle_sta; /* SUBSYS_IDLE_STA */
+ uint32_t req_sta0; /* SRC_REQ_STA_0 */
+ uint32_t req_sta1; /* SRC_REQ_STA_1 */
+ uint32_t req_sta2; /* SRC_REQ_STA_2 */
+ uint32_t req_sta3; /* SRC_REQ_STA_3 */
+ uint32_t req_sta4; /* SRC_REQ_STA_4 */
+ uint32_t cg_check_sta; /* SPM_CG_CHECK_STA */
+ uint32_t debug_flag; /* PCM_WDT_LATCH_SPARE_0 */
+ uint32_t debug_flag1; /* PCM_WDT_LATCH_SPARE_1 */
+ uint32_t b_sw_flag0; /* SPM_SW_RSV_7 */
+ uint32_t b_sw_flag1; /* SPM_SW_RSV_8 */
+ uint32_t isr; /* SPM_IRQ_STA */
+ uint32_t sw_flag0; /* SPM_SW_FLAG_0 */
+ uint32_t sw_flag1; /* SPM_SW_FLAG_1 */
+ uint32_t clk_settle; /* SPM_CLK_SETTLE */
+ uint32_t src_req; /* SPM_SRC_REQ */
+ uint32_t log_index;
+ uint32_t abort;
+ uint32_t rt_req_sta0; /* SPM_SW_RSV_2 */
+ uint32_t rt_req_sta1; /* SPM_SW_RSV_3 */
+ uint32_t rt_req_sta2; /* SPM_SW_RSV_4 */
+ uint32_t rt_req_sta3; /* SPM_SW_RSV_5 */
+ uint32_t rt_req_sta4; /* SPM_SW_RSV_6 */
+ uint32_t mcupm_req_sta;
+};
+
+struct spm_lp_scen {
+ struct pcm_desc *pcmdesc;
+ struct pwr_ctrl *pwrctrl;
+};
+
+extern struct spm_lp_scen __spm_vcorefs;
+extern void __spm_set_cpu_status(unsigned int cpu);
+extern void __spm_reset_and_init_pcm(const struct pcm_desc *pcmdesc);
+extern void __spm_kick_im_to_fetch(const struct pcm_desc *pcmdesc);
+extern void __spm_init_pcm_register(void);
+extern void __spm_src_req_update(const struct pwr_ctrl *pwrctrl,
+ unsigned int resource_usage);
+extern void __spm_set_power_control(const struct pwr_ctrl *pwrctrl);
+extern void __spm_disable_pcm_timer(void);
+extern void __spm_set_wakeup_event(const struct pwr_ctrl *pwrctrl);
+extern void __spm_kick_pcm_to_run(struct pwr_ctrl *pwrctrl);
+extern void __spm_set_pcm_flags(struct pwr_ctrl *pwrctrl);
+extern void __spm_send_cpu_wakeup_event(void);
+extern void __spm_get_wakeup_status(struct wake_status *wakesta,
+ unsigned int ext_status);
+extern void __spm_clean_after_wakeup(void);
+extern wake_reason_t
+__spm_output_wake_reason(int state_id, const struct wake_status *wakesta);
+extern void
+__spm_sync_vcore_dvfs_power_control(struct pwr_ctrl *dest_pwr_ctrl,
+ const struct pwr_ctrl *src_pwr_ctrl);
+extern void __spm_set_pcm_wdt(int en);
+extern uint32_t _spm_get_wake_period(int pwake_time, wake_reason_t last_wr);
+extern void __spm_set_fw_resume_option(struct pwr_ctrl *pwrctrl);
+extern void __spm_ext_int_wakeup_req_clr(void);
+extern void __spm_xo_soc_bblpm(int en);
+
+static inline void set_pwrctrl_pcm_flags(struct pwr_ctrl *pwrctrl,
+ uint32_t flags)
+{
+ if (pwrctrl->pcm_flags_cust == 0U) {
+ pwrctrl->pcm_flags = flags;
+ } else {
+ pwrctrl->pcm_flags = pwrctrl->pcm_flags_cust;
+ }
+}
+
+static inline void set_pwrctrl_pcm_flags1(struct pwr_ctrl *pwrctrl,
+ uint32_t flags)
+{
+ if (pwrctrl->pcm_flags1_cust == 0U) {
+ pwrctrl->pcm_flags1 = flags;
+ } else {
+ pwrctrl->pcm_flags1 = pwrctrl->pcm_flags1_cust;
+ }
+}
+
+extern void __spm_hw_s1_state_monitor(int en, unsigned int *status);
+
+static inline void spm_hw_s1_state_monitor_resume(void)
+{
+ __spm_hw_s1_state_monitor(1, NULL);
+}
+
+static inline void spm_hw_s1_state_monitor_pause(unsigned int *status)
+{
+ __spm_hw_s1_state_monitor(0, status);
+}
+#endif /* MT_SPM_INTERNAL_H */
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm_pmic_wrap.c b/plat/mediatek/mt8192/drivers/spm/mt_spm_pmic_wrap.c
new file mode 100644
index 0000000..4e5f6a0
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm_pmic_wrap.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <mt_spm.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_pmic_wrap.h>
+#include <mt_spm_reg.h>
+#include <plat_pm.h>
+#include <platform_def.h>
+
+/* PMIC_WRAP MT6359 */
+#define VCORE_BASE_UV 40000
+#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 NR_PMIC_WRAP_CMD (NR_IDX_ALL)
+#define SPM_DATA_SHIFT 16
+
+#define BUCK_VGPU11_ELR0 0x15B4
+#define TOP_SPI_CON0 0x0456
+#define BUCK_TOP_CON1 0x1443
+#define TOP_CON 0x0013
+#define TOP_DIG_WPK 0x03a9
+#define TOP_CON_LOCK 0x03a8
+#define TOP_CLK_CON0 0x0134
+
+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, /* invalid setting for init */
+ .addr = { {0UL, 0UL} },
+ .set[PMIC_WRAP_PHASE_ALLINONE] = {
+ ._[CMD_0] = {BUCK_VGPU11_ELR0, VOLT_TO_PMIC_VAL(72500),},
+ ._[CMD_1] = {BUCK_VGPU11_ELR0, VOLT_TO_PMIC_VAL(65000),},
+ ._[CMD_2] = {BUCK_VGPU11_ELR0, VOLT_TO_PMIC_VAL(60000),},
+ ._[CMD_3] = {BUCK_VGPU11_ELR0, VOLT_TO_PMIC_VAL(57500),},
+ ._[CMD_4] = {TOP_SPI_CON0, 0x1,},
+ ._[CMD_5] = {TOP_SPI_CON0, 0x0,},
+ ._[CMD_6] = {BUCK_TOP_CON1, 0x0,},
+ ._[CMD_7] = {BUCK_TOP_CON1, 0xf,},
+ ._[CMD_8] = {TOP_CON, 0x3,},
+ ._[CMD_9] = {TOP_CON, 0x0,},
+ ._[CMD_10] = {TOP_DIG_WPK, 0x63,},
+ ._[CMD_11] = {TOP_CON_LOCK, 0x15,},
+ ._[CMD_12] = {TOP_DIG_WPK, 0x0,},
+ ._[CMD_13] = {TOP_CON_LOCK, 0x0,},
+ ._[CMD_14] = {TOP_CLK_CON0, 0x40,},
+ ._[CMD_15] = {TOP_CLK_CON0, 0x0,},
+ .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,},
+ };
+
+ 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 == 0UL) {
+ _mt_spm_pmic_table_init();
+ }
+
+ pw.phase = phase;
+ mmio_write_32(POWERON_CONFIG_EN, SPM_REGWR_CFG_KEY | BCLK_CG_EN_LSB);
+
+ for (idx = 0U; 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);
+
+ 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 0UL;
+ }
+
+ if (idx >= pw.set[phase].nr_idx) {
+ return 0UL;
+ }
+
+ return pw.set[phase]._[idx].cmd_wdata;
+}
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm_pmic_wrap.h b/plat/mediatek/mt8192/drivers/spm/mt_spm_pmic_wrap.h
new file mode 100644
index 0000000..6e20916
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm_pmic_wrap.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/****************************************************************
+ * Auto generated by DE, please DO NOT modify this file directly.
+ *****************************************************************/
+#ifndef MT_SPM_PMIC_WRAP_H
+#define MT_SPM_PMIC_WRAP_H
+
+enum pmic_wrap_phase_id {
+ PMIC_WRAP_PHASE_ALLINONE,
+ NR_PMIC_WRAP_PHASE,
+};
+
+/* IDX mapping, PMIC_WRAP_PHASE_ALLINONE */
+enum {
+ CMD_0, /* 0x0 */
+ 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 */
+ NR_IDX_ALL,
+};
+
+/* APIs */
+extern void mt_spm_pmic_wrap_set_phase(enum pmic_wrap_phase_id phase);
+extern void mt_spm_pmic_wrap_set_cmd(enum pmic_wrap_phase_id phase,
+ uint32_t idx, uint32_t cmd_wdata);
+extern uint64_t mt_spm_pmic_wrap_get_cmd(enum pmic_wrap_phase_id phase,
+ uint32_t idx);
+#endif /* MT_SPM_PMIC_WRAP_H */
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm_reg.h b/plat/mediatek/mt8192/drivers/spm/mt_spm_reg.h
new file mode 100644
index 0000000..fba011d
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm_reg.h
@@ -0,0 +1,2919 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/****************************************************************
+ * Auto generated by DE, please DO NOT modify this file directly.
+ *****************************************************************/
+#ifndef MT_SPM_REG
+#define MT_SPM_REG
+
+#include "pcm_def.h"
+#include <platform_def.h>
+#include "sleep_def.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 SPM_POWER_ON_VAL2 (SPM_BASE + 0x020)
+#define SPM_POWER_ON_VAL3 (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 SPM_SRC6_MASK (SPM_BASE + 0x038)
+#define SPM_SW_RST_CON (SPM_BASE + 0x040)
+#define SPM_SW_RST_CON_SET (SPM_BASE + 0x044)
+#define SPM_SW_RST_CON_CLR (SPM_BASE + 0x048)
+#define VS1_PSR_MASK_B (SPM_BASE + 0x04C)
+#define VS2_PSR_MASK_B (SPM_BASE + 0x050)
+#define MD32_CLK_CON (SPM_BASE + 0x084)
+#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_SRC3_MASK (SPM_BASE + 0x0C4)
+#define SPM_SRC4_MASK (SPM_BASE + 0x0C8)
+#define SPM_SRC5_MASK (SPM_BASE + 0x0CC)
+#define SPM_WAKEUP_EVENT_MASK (SPM_BASE + 0x0D0)
+#define SPM_WAKEUP_EVENT_EXT_MASK (SPM_BASE + 0x0D4)
+#define SPM_TWAM_EVENT_CLEAR (SPM_BASE + 0x0D8)
+#define SCP_CLK_CON (SPM_BASE + 0x0DC)
+#define PCM_DEBUG_CON (SPM_BASE + 0x0E0)
+#define AHB_BUS_CON (SPM_BASE + 0x0E4)
+#define DDR_EN_DBC_CON0 (SPM_BASE + 0x0E8)
+#define DDR_EN_DBC_CON1 (SPM_BASE + 0x0EC)
+#define SPM_RESOURCE_ACK_CON0 (SPM_BASE + 0x0F0)
+#define SPM_RESOURCE_ACK_CON1 (SPM_BASE + 0x0F4)
+#define SPM_RESOURCE_ACK_CON2 (SPM_BASE + 0x0F8)
+#define SPM_RESOURCE_ACK_CON3 (SPM_BASE + 0x0FC)
+#define PCM_REG0_DATA (SPM_BASE + 0x100)
+#define PCM_REG2_DATA (SPM_BASE + 0x104)
+#define PCM_REG6_DATA (SPM_BASE + 0x108)
+#define PCM_REG7_DATA (SPM_BASE + 0x10C)
+#define PCM_REG13_DATA (SPM_BASE + 0x110)
+#define SRC_REQ_STA_0 (SPM_BASE + 0x114)
+#define SRC_REQ_STA_1 (SPM_BASE + 0x118)
+#define SRC_REQ_STA_2 (SPM_BASE + 0x11C)
+#define PCM_TIMER_OUT (SPM_BASE + 0x120)
+#define PCM_WDT_OUT (SPM_BASE + 0x124)
+#define SPM_IRQ_STA (SPM_BASE + 0x128)
+#define SRC_REQ_STA_4 (SPM_BASE + 0x12C)
+#define MD32PCM_WAKEUP_STA (SPM_BASE + 0x130)
+#define MD32PCM_EVENT_STA (SPM_BASE + 0x134)
+#define SPM_WAKEUP_STA (SPM_BASE + 0x138)
+#define SPM_WAKEUP_EXT_STA (SPM_BASE + 0x13C)
+#define SPM_WAKEUP_MISC (SPM_BASE + 0x140)
+#define MM_DVFS_HALT (SPM_BASE + 0x144)
+#define BUS_PROTECT_RDY (SPM_BASE + 0x150)
+#define BUS_PROTECT1_RDY (SPM_BASE + 0x154)
+#define BUS_PROTECT2_RDY (SPM_BASE + 0x158)
+#define BUS_PROTECT3_RDY (SPM_BASE + 0x15C)
+#define SUBSYS_IDLE_STA (SPM_BASE + 0x160)
+#define PCM_STA (SPM_BASE + 0x164)
+#define SRC_REQ_STA_3 (SPM_BASE + 0x168)
+#define PWR_STATUS (SPM_BASE + 0x16C)
+#define PWR_STATUS_2ND (SPM_BASE + 0x170)
+#define CPU_PWR_STATUS (SPM_BASE + 0x174)
+#define OTHER_PWR_STATUS (SPM_BASE + 0x178)
+#define SPM_VTCXO_EVENT_COUNT_STA (SPM_BASE + 0x17C)
+#define SPM_INFRA_EVENT_COUNT_STA (SPM_BASE + 0x180)
+#define SPM_VRF18_EVENT_COUNT_STA (SPM_BASE + 0x184)
+#define SPM_APSRC_EVENT_COUNT_STA (SPM_BASE + 0x188)
+#define SPM_DDREN_EVENT_COUNT_STA (SPM_BASE + 0x18C)
+#define MD32PCM_STA (SPM_BASE + 0x190)
+#define MD32PCM_PC (SPM_BASE + 0x194)
+#define DVFSRC_EVENT_STA (SPM_BASE + 0x1A4)
+#define BUS_PROTECT4_RDY (SPM_BASE + 0x1A8)
+#define BUS_PROTECT5_RDY (SPM_BASE + 0x1AC)
+#define BUS_PROTECT6_RDY (SPM_BASE + 0x1B0)
+#define BUS_PROTECT7_RDY (SPM_BASE + 0x1B4)
+#define BUS_PROTECT8_RDY (SPM_BASE + 0x1B8)
+#define SPM_TWAM_LAST_STA0 (SPM_BASE + 0x1D0)
+#define SPM_TWAM_LAST_STA1 (SPM_BASE + 0x1D4)
+#define SPM_TWAM_LAST_STA2 (SPM_BASE + 0x1D8)
+#define SPM_TWAM_LAST_STA3 (SPM_BASE + 0x1DC)
+#define SPM_TWAM_CURR_STA0 (SPM_BASE + 0x1E0)
+#define SPM_TWAM_CURR_STA1 (SPM_BASE + 0x1E4)
+#define SPM_TWAM_CURR_STA2 (SPM_BASE + 0x1E8)
+#define SPM_TWAM_CURR_STA3 (SPM_BASE + 0x1EC)
+#define SPM_TWAM_TIMER_OUT (SPM_BASE + 0x1F0)
+#define SPM_CG_CHECK_STA (SPM_BASE + 0x1F4)
+#define SPM_DVFS_STA (SPM_BASE + 0x1F8)
+#define SPM_DVFS_OPP_STA (SPM_BASE + 0x1FC)
+#define SPM_MCUSYS_PWR_CON (SPM_BASE + 0x200)
+#define SPM_CPUTOP_PWR_CON (SPM_BASE + 0x204)
+#define SPM_CPU0_PWR_CON (SPM_BASE + 0x208)
+#define SPM_CPU1_PWR_CON (SPM_BASE + 0x20C)
+#define SPM_CPU2_PWR_CON (SPM_BASE + 0x210)
+#define SPM_CPU3_PWR_CON (SPM_BASE + 0x214)
+#define SPM_CPU4_PWR_CON (SPM_BASE + 0x218)
+#define SPM_CPU5_PWR_CON (SPM_BASE + 0x21C)
+#define SPM_CPU6_PWR_CON (SPM_BASE + 0x220)
+#define SPM_CPU7_PWR_CON (SPM_BASE + 0x224)
+#define ARMPLL_CLK_CON (SPM_BASE + 0x22C)
+#define MCUSYS_IDLE_STA (SPM_BASE + 0x230)
+#define GIC_WAKEUP_STA (SPM_BASE + 0x234)
+#define CPU_SPARE_CON (SPM_BASE + 0x238)
+#define CPU_SPARE_CON_SET (SPM_BASE + 0x23C)
+#define CPU_SPARE_CON_CLR (SPM_BASE + 0x240)
+#define ARMPLL_CLK_SEL (SPM_BASE + 0x244)
+#define EXT_INT_WAKEUP_REQ (SPM_BASE + 0x248)
+#define EXT_INT_WAKEUP_REQ_SET (SPM_BASE + 0x24C)
+#define EXT_INT_WAKEUP_REQ_CLR (SPM_BASE + 0x250)
+#define MP0_CPU0_IRQ_MASK (SPM_BASE + 0x260)
+#define MP0_CPU1_IRQ_MASK (SPM_BASE + 0x264)
+#define MP0_CPU2_IRQ_MASK (SPM_BASE + 0x268)
+#define MP0_CPU3_IRQ_MASK (SPM_BASE + 0x26C)
+#define MP1_CPU0_IRQ_MASK (SPM_BASE + 0x270)
+#define MP1_CPU1_IRQ_MASK (SPM_BASE + 0x274)
+#define MP1_CPU2_IRQ_MASK (SPM_BASE + 0x278)
+#define MP1_CPU3_IRQ_MASK (SPM_BASE + 0x27C)
+#define MP0_CPU0_WFI_EN (SPM_BASE + 0x280)
+#define MP0_CPU1_WFI_EN (SPM_BASE + 0x284)
+#define MP0_CPU2_WFI_EN (SPM_BASE + 0x288)
+#define MP0_CPU3_WFI_EN (SPM_BASE + 0x28C)
+#define MP0_CPU4_WFI_EN (SPM_BASE + 0x290)
+#define MP0_CPU5_WFI_EN (SPM_BASE + 0x294)
+#define MP0_CPU6_WFI_EN (SPM_BASE + 0x298)
+#define MP0_CPU7_WFI_EN (SPM_BASE + 0x29C)
+#define ROOT_CPUTOP_ADDR (SPM_BASE + 0x2A0)
+#define ROOT_CORE_ADDR (SPM_BASE + 0x2A4)
+#define SPM2SW_MAILBOX_0 (SPM_BASE + 0x2D0)
+#define SPM2SW_MAILBOX_1 (SPM_BASE + 0x2D4)
+#define SPM2SW_MAILBOX_2 (SPM_BASE + 0x2D8)
+#define SPM2SW_MAILBOX_3 (SPM_BASE + 0x2DC)
+#define SW2SPM_INT (SPM_BASE + 0x2E0)
+#define SW2SPM_INT_SET (SPM_BASE + 0x2E4)
+#define SW2SPM_INT_CLR (SPM_BASE + 0x2E8)
+#define SW2SPM_MAILBOX_0 (SPM_BASE + 0x2EC)
+#define SW2SPM_MAILBOX_1 (SPM_BASE + 0x2F0)
+#define SW2SPM_MAILBOX_2 (SPM_BASE + 0x2F4)
+#define SW2SPM_MAILBOX_3 (SPM_BASE + 0x2F8)
+#define SW2SPM_CFG (SPM_BASE + 0x2FC)
+#define MD1_PWR_CON (SPM_BASE + 0x300)
+#define CONN_PWR_CON (SPM_BASE + 0x304)
+#define MFG0_PWR_CON (SPM_BASE + 0x308)
+#define MFG1_PWR_CON (SPM_BASE + 0x30C)
+#define MFG2_PWR_CON (SPM_BASE + 0x310)
+#define MFG3_PWR_CON (SPM_BASE + 0x314)
+#define MFG4_PWR_CON (SPM_BASE + 0x318)
+#define MFG5_PWR_CON (SPM_BASE + 0x31C)
+#define MFG6_PWR_CON (SPM_BASE + 0x320)
+#define IFR_PWR_CON (SPM_BASE + 0x324)
+#define IFR_SUB_PWR_CON (SPM_BASE + 0x328)
+#define DPY_PWR_CON (SPM_BASE + 0x32C)
+#define ISP_PWR_CON (SPM_BASE + 0x330)
+#define ISP2_PWR_CON (SPM_BASE + 0x334)
+#define IPE_PWR_CON (SPM_BASE + 0x338)
+#define VDE_PWR_CON (SPM_BASE + 0x33C)
+#define VDE2_PWR_CON (SPM_BASE + 0x340)
+#define VEN_PWR_CON (SPM_BASE + 0x344)
+#define VEN_CORE1_PWR_CON (SPM_BASE + 0x348)
+#define MDP_PWR_CON (SPM_BASE + 0x34C)
+#define DIS_PWR_CON (SPM_BASE + 0x350)
+#define AUDIO_PWR_CON (SPM_BASE + 0x354)
+#define ADSP_PWR_CON (SPM_BASE + 0x358)
+#define CAM_PWR_CON (SPM_BASE + 0x35C)
+#define CAM_RAWA_PWR_CON (SPM_BASE + 0x360)
+#define CAM_RAWB_PWR_CON (SPM_BASE + 0x364)
+#define CAM_RAWC_PWR_CON (SPM_BASE + 0x368)
+#define SYSRAM_CON (SPM_BASE + 0x36C)
+#define SYSROM_CON (SPM_BASE + 0x370)
+#define SSPM_SRAM_CON (SPM_BASE + 0x374)
+#define SCP_SRAM_CON (SPM_BASE + 0x378)
+#define DPY_SHU_SRAM_CON (SPM_BASE + 0x37C)
+#define UFS_SRAM_CON (SPM_BASE + 0x380)
+#define DEVAPC_IFR_SRAM_CON (SPM_BASE + 0x384)
+#define DEVAPC_SUBIFR_SRAM_CON (SPM_BASE + 0x388)
+#define DEVAPC_ACP_SRAM_CON (SPM_BASE + 0x38C)
+#define USB_SRAM_CON (SPM_BASE + 0x390)
+#define DUMMY_SRAM_CON (SPM_BASE + 0x394)
+#define MD_EXT_BUCK_ISO_CON (SPM_BASE + 0x398)
+#define EXT_BUCK_ISO (SPM_BASE + 0x39C)
+#define DXCC_SRAM_CON (SPM_BASE + 0x3A0)
+#define MSDC_SRAM_CON (SPM_BASE + 0x3A4)
+#define DEBUGTOP_SRAM_CON (SPM_BASE + 0x3A8)
+#define DP_TX_PWR_CON (SPM_BASE + 0x3AC)
+#define DPMAIF_SRAM_CON (SPM_BASE + 0x3B0)
+#define DPY_SHU2_SRAM_CON (SPM_BASE + 0x3B4)
+#define DRAMC_MCU2_SRAM_CON (SPM_BASE + 0x3B8)
+#define DRAMC_MCU_SRAM_CON (SPM_BASE + 0x3BC)
+#define MCUPM_SRAM_CON (SPM_BASE + 0x3C0)
+#define DPY2_PWR_CON (SPM_BASE + 0x3C4)
+#define PERI_PWR_CON (SPM_BASE + 0x3C8)
+#define SPM_MEM_CK_SEL (SPM_BASE + 0x400)
+#define SPM_BUS_PROTECT_MASK_B (SPM_BASE + 0x404)
+#define SPM_BUS_PROTECT1_MASK_B (SPM_BASE + 0x408)
+#define SPM_BUS_PROTECT2_MASK_B (SPM_BASE + 0x40C)
+#define SPM_BUS_PROTECT3_MASK_B (SPM_BASE + 0x410)
+#define SPM_BUS_PROTECT4_MASK_B (SPM_BASE + 0x414)
+#define SPM_EMI_BW_MODE (SPM_BASE + 0x418)
+#define AP2MD_PEER_WAKEUP (SPM_BASE + 0x41C)
+#define ULPOSC_CON (SPM_BASE + 0x420)
+#define SPM2MM_CON (SPM_BASE + 0x424)
+#define SPM_BUS_PROTECT5_MASK_B (SPM_BASE + 0x428)
+#define SPM2MCUPM_CON (SPM_BASE + 0x42C)
+#define AP_MDSRC_REQ (SPM_BASE + 0x430)
+#define SPM2EMI_ENTER_ULPM (SPM_BASE + 0x434)
+#define SPM2MD_DVFS_CON (SPM_BASE + 0x438)
+#define MD2SPM_DVFS_CON (SPM_BASE + 0x43C)
+#define SPM_BUS_PROTECT6_MASK_B (SPM_BASE + 0x440)
+#define SPM_BUS_PROTECT7_MASK_B (SPM_BASE + 0x444)
+#define SPM_BUS_PROTECT8_MASK_B (SPM_BASE + 0x448)
+#define SPM_PLL_CON (SPM_BASE + 0x44C)
+#define CPU_DVFS_REQ (SPM_BASE + 0x450)
+#define SPM_DRAM_MCU_SW_CON_0 (SPM_BASE + 0x454)
+#define SPM_DRAM_MCU_SW_CON_1 (SPM_BASE + 0x458)
+#define SPM_DRAM_MCU_SW_CON_2 (SPM_BASE + 0x45C)
+#define SPM_DRAM_MCU_SW_CON_3 (SPM_BASE + 0x460)
+#define SPM_DRAM_MCU_SW_CON_4 (SPM_BASE + 0x464)
+#define SPM_DRAM_MCU_STA_0 (SPM_BASE + 0x468)
+#define SPM_DRAM_MCU_STA_1 (SPM_BASE + 0x46C)
+#define SPM_DRAM_MCU_STA_2 (SPM_BASE + 0x470)
+#define SPM_DRAM_MCU_SW_SEL_0 (SPM_BASE + 0x474)
+#define RELAY_DVFS_LEVEL (SPM_BASE + 0x478)
+#define DRAMC_DPY_CLK_SW_CON_0 (SPM_BASE + 0x480)
+#define DRAMC_DPY_CLK_SW_CON_1 (SPM_BASE + 0x484)
+#define DRAMC_DPY_CLK_SW_CON_2 (SPM_BASE + 0x488)
+#define DRAMC_DPY_CLK_SW_CON_3 (SPM_BASE + 0x48C)
+#define DRAMC_DPY_CLK_SW_SEL_0 (SPM_BASE + 0x490)
+#define DRAMC_DPY_CLK_SW_SEL_1 (SPM_BASE + 0x494)
+#define DRAMC_DPY_CLK_SW_SEL_2 (SPM_BASE + 0x498)
+#define DRAMC_DPY_CLK_SW_SEL_3 (SPM_BASE + 0x49C)
+#define DRAMC_DPY_CLK_SPM_CON (SPM_BASE + 0x4A0)
+#define SPM_DVFS_LEVEL (SPM_BASE + 0x4A4)
+#define SPM_CIRQ_CON (SPM_BASE + 0x4A8)
+#define SPM_DVFS_MISC (SPM_BASE + 0x4AC)
+#define SPM_VS1_VS2_RC_CON (SPM_BASE + 0x4B0)
+#define RG_MODULE_SW_CG_0_MASK_REQ_0 (SPM_BASE + 0x4B4)
+#define RG_MODULE_SW_CG_0_MASK_REQ_1 (SPM_BASE + 0x4B8)
+#define RG_MODULE_SW_CG_0_MASK_REQ_2 (SPM_BASE + 0x4BC)
+#define RG_MODULE_SW_CG_1_MASK_REQ_0 (SPM_BASE + 0x4C0)
+#define RG_MODULE_SW_CG_1_MASK_REQ_1 (SPM_BASE + 0x4C4)
+#define RG_MODULE_SW_CG_1_MASK_REQ_2 (SPM_BASE + 0x4C8)
+#define RG_MODULE_SW_CG_2_MASK_REQ_0 (SPM_BASE + 0x4CC)
+#define RG_MODULE_SW_CG_2_MASK_REQ_1 (SPM_BASE + 0x4D0)
+#define RG_MODULE_SW_CG_2_MASK_REQ_2 (SPM_BASE + 0x4D4)
+#define RG_MODULE_SW_CG_3_MASK_REQ_0 (SPM_BASE + 0x4D8)
+#define RG_MODULE_SW_CG_3_MASK_REQ_1 (SPM_BASE + 0x4DC)
+#define RG_MODULE_SW_CG_3_MASK_REQ_2 (SPM_BASE + 0x4E0)
+#define PWR_STATUS_MASK_REQ_0 (SPM_BASE + 0x4E4)
+#define PWR_STATUS_MASK_REQ_1 (SPM_BASE + 0x4E8)
+#define PWR_STATUS_MASK_REQ_2 (SPM_BASE + 0x4EC)
+#define SPM_CG_CHECK_CON (SPM_BASE + 0x4F0)
+#define SPM_SRC_RDY_STA (SPM_BASE + 0x4F4)
+#define SPM_DVS_DFS_LEVEL (SPM_BASE + 0x4F8)
+#define SPM_FORCE_DVFS (SPM_BASE + 0x4FC)
+#define SRCLKEN_RC_CFG (SPM_BASE + 0x500)
+#define RC_CENTRAL_CFG1 (SPM_BASE + 0x504)
+#define RC_CENTRAL_CFG2 (SPM_BASE + 0x508)
+#define RC_CMD_ARB_CFG (SPM_BASE + 0x50C)
+#define RC_PMIC_RCEN_ADDR (SPM_BASE + 0x510)
+#define RC_PMIC_RCEN_SET_CLR_ADDR (SPM_BASE + 0x514)
+#define RC_DCXO_FPM_CFG (SPM_BASE + 0x518)
+#define RC_CENTRAL_CFG3 (SPM_BASE + 0x51C)
+#define RC_M00_SRCLKEN_CFG (SPM_BASE + 0x520)
+#define RC_M01_SRCLKEN_CFG (SPM_BASE + 0x524)
+#define RC_M02_SRCLKEN_CFG (SPM_BASE + 0x528)
+#define RC_M03_SRCLKEN_CFG (SPM_BASE + 0x52C)
+#define RC_M04_SRCLKEN_CFG (SPM_BASE + 0x530)
+#define RC_M05_SRCLKEN_CFG (SPM_BASE + 0x534)
+#define RC_M06_SRCLKEN_CFG (SPM_BASE + 0x538)
+#define RC_M07_SRCLKEN_CFG (SPM_BASE + 0x53C)
+#define RC_M08_SRCLKEN_CFG (SPM_BASE + 0x540)
+#define RC_M09_SRCLKEN_CFG (SPM_BASE + 0x544)
+#define RC_M10_SRCLKEN_CFG (SPM_BASE + 0x548)
+#define RC_M11_SRCLKEN_CFG (SPM_BASE + 0x54C)
+#define RC_M12_SRCLKEN_CFG (SPM_BASE + 0x550)
+#define RC_SRCLKEN_SW_CON_CFG (SPM_BASE + 0x554)
+#define RC_CENTRAL_CFG4 (SPM_BASE + 0x558)
+#define RC_PROTOCOL_CHK_CFG (SPM_BASE + 0x560)
+#define RC_DEBUG_CFG (SPM_BASE + 0x564)
+#define RC_MISC_0 (SPM_BASE + 0x5B4)
+#define RC_SPM_CTRL (SPM_BASE + 0x5B8)
+#define SUBSYS_INTF_CFG (SPM_BASE + 0x5BC)
+#define PCM_WDT_LATCH_25 (SPM_BASE + 0x5C0)
+#define PCM_WDT_LATCH_26 (SPM_BASE + 0x5C4)
+#define PCM_WDT_LATCH_27 (SPM_BASE + 0x5C8)
+#define PCM_WDT_LATCH_28 (SPM_BASE + 0x5CC)
+#define PCM_WDT_LATCH_29 (SPM_BASE + 0x5D0)
+#define PCM_WDT_LATCH_30 (SPM_BASE + 0x5D4)
+#define PCM_WDT_LATCH_31 (SPM_BASE + 0x5D8)
+#define PCM_WDT_LATCH_32 (SPM_BASE + 0x5DC)
+#define PCM_WDT_LATCH_33 (SPM_BASE + 0x5E0)
+#define PCM_WDT_LATCH_34 (SPM_BASE + 0x5E4)
+#define PCM_WDT_LATCH_35 (SPM_BASE + 0x5EC)
+#define PCM_WDT_LATCH_36 (SPM_BASE + 0x5F0)
+#define PCM_WDT_LATCH_37 (SPM_BASE + 0x5F4)
+#define PCM_WDT_LATCH_38 (SPM_BASE + 0x5F8)
+#define PCM_WDT_LATCH_39 (SPM_BASE + 0x5FC)
+#define SPM_SW_FLAG_0 (SPM_BASE + 0x600)
+#define SPM_SW_DEBUG_0 (SPM_BASE + 0x604)
+#define SPM_SW_FLAG_1 (SPM_BASE + 0x608)
+#define SPM_SW_DEBUG_1 (SPM_BASE + 0x60C)
+#define SPM_SW_RSV_0 (SPM_BASE + 0x610)
+#define SPM_SW_RSV_1 (SPM_BASE + 0x614)
+#define SPM_SW_RSV_2 (SPM_BASE + 0x618)
+#define SPM_SW_RSV_3 (SPM_BASE + 0x61C)
+#define SPM_SW_RSV_4 (SPM_BASE + 0x620)
+#define SPM_SW_RSV_5 (SPM_BASE + 0x624)
+#define SPM_SW_RSV_6 (SPM_BASE + 0x628)
+#define SPM_SW_RSV_7 (SPM_BASE + 0x62C)
+#define SPM_SW_RSV_8 (SPM_BASE + 0x630)
+#define SPM_BK_WAKE_EVENT (SPM_BASE + 0x634)
+#define SPM_BK_VTCXO_DUR (SPM_BASE + 0x638)
+#define SPM_BK_WAKE_MISC (SPM_BASE + 0x63C)
+#define SPM_BK_PCM_TIMER (SPM_BASE + 0x640)
+#define SPM_RSV_CON_0 (SPM_BASE + 0x650)
+#define SPM_RSV_CON_1 (SPM_BASE + 0x654)
+#define SPM_RSV_STA_0 (SPM_BASE + 0x658)
+#define SPM_RSV_STA_1 (SPM_BASE + 0x65C)
+#define SPM_SPARE_CON (SPM_BASE + 0x660)
+#define SPM_SPARE_CON_SET (SPM_BASE + 0x664)
+#define SPM_SPARE_CON_CLR (SPM_BASE + 0x668)
+#define SPM_CROSS_WAKE_M00_REQ (SPM_BASE + 0x66C)
+#define SPM_CROSS_WAKE_M01_REQ (SPM_BASE + 0x670)
+#define SPM_CROSS_WAKE_M02_REQ (SPM_BASE + 0x674)
+#define SPM_CROSS_WAKE_M03_REQ (SPM_BASE + 0x678)
+#define SCP_VCORE_LEVEL (SPM_BASE + 0x67C)
+#define SC_MM_CK_SEL_CON (SPM_BASE + 0x680)
+#define SPARE_ACK_MASK (SPM_BASE + 0x684)
+#define SPM_CROSS_WAKE_M04_REQ (SPM_BASE + 0x688)
+#define SPM_DV_CON_0 (SPM_BASE + 0x68C)
+#define SPM_DV_CON_1 (SPM_BASE + 0x690)
+#define SPM_DV_STA (SPM_BASE + 0x694)
+#define CONN_XOWCN_DEBUG_EN (SPM_BASE + 0x698)
+#define SPM_SEMA_M0 (SPM_BASE + 0x69C)
+#define SPM_SEMA_M1 (SPM_BASE + 0x6A0)
+#define SPM_SEMA_M2 (SPM_BASE + 0x6A4)
+#define SPM_SEMA_M3 (SPM_BASE + 0x6A8)
+#define SPM_SEMA_M4 (SPM_BASE + 0x6AC)
+#define SPM_SEMA_M5 (SPM_BASE + 0x6B0)
+#define SPM_SEMA_M6 (SPM_BASE + 0x6B4)
+#define SPM_SEMA_M7 (SPM_BASE + 0x6B8)
+#define SPM2ADSP_MAILBOX (SPM_BASE + 0x6BC)
+#define ADSP2SPM_MAILBOX (SPM_BASE + 0x6C0)
+#define SPM_ADSP_IRQ (SPM_BASE + 0x6C4)
+#define SPM_MD32_IRQ (SPM_BASE + 0x6C8)
+#define SPM2PMCU_MAILBOX_0 (SPM_BASE + 0x6CC)
+#define SPM2PMCU_MAILBOX_1 (SPM_BASE + 0x6D0)
+#define SPM2PMCU_MAILBOX_2 (SPM_BASE + 0x6D4)
+#define SPM2PMCU_MAILBOX_3 (SPM_BASE + 0x6D8)
+#define PMCU2SPM_MAILBOX_0 (SPM_BASE + 0x6DC)
+#define PMCU2SPM_MAILBOX_1 (SPM_BASE + 0x6E0)
+#define PMCU2SPM_MAILBOX_2 (SPM_BASE + 0x6E4)
+#define PMCU2SPM_MAILBOX_3 (SPM_BASE + 0x6E8)
+#define UFS_PSRI_SW (SPM_BASE + 0x6EC)
+#define UFS_PSRI_SW_SET (SPM_BASE + 0x6F0)
+#define UFS_PSRI_SW_CLR (SPM_BASE + 0x6F4)
+#define SPM_AP_SEMA (SPM_BASE + 0x6F8)
+#define SPM_SPM_SEMA (SPM_BASE + 0x6FC)
+#define SPM_DVFS_CON (SPM_BASE + 0x700)
+#define SPM_DVFS_CON_STA (SPM_BASE + 0x704)
+#define SPM_PMIC_SPMI_CON (SPM_BASE + 0x708)
+#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 SPM_DVFS_CMD16 (SPM_BASE + 0x750)
+#define SPM_DVFS_CMD17 (SPM_BASE + 0x754)
+#define SPM_DVFS_CMD18 (SPM_BASE + 0x758)
+#define SPM_DVFS_CMD19 (SPM_BASE + 0x75C)
+#define SPM_DVFS_CMD20 (SPM_BASE + 0x760)
+#define SPM_DVFS_CMD21 (SPM_BASE + 0x764)
+#define SPM_DVFS_CMD22 (SPM_BASE + 0x768)
+#define SPM_DVFS_CMD23 (SPM_BASE + 0x76C)
+#define SYS_TIMER_VALUE_L (SPM_BASE + 0x770)
+#define SYS_TIMER_VALUE_H (SPM_BASE + 0x774)
+#define SYS_TIMER_START_L (SPM_BASE + 0x778)
+#define SYS_TIMER_START_H (SPM_BASE + 0x77C)
+#define SYS_TIMER_LATCH_L_00 (SPM_BASE + 0x780)
+#define SYS_TIMER_LATCH_H_00 (SPM_BASE + 0x784)
+#define SYS_TIMER_LATCH_L_01 (SPM_BASE + 0x788)
+#define SYS_TIMER_LATCH_H_01 (SPM_BASE + 0x78C)
+#define SYS_TIMER_LATCH_L_02 (SPM_BASE + 0x790)
+#define SYS_TIMER_LATCH_H_02 (SPM_BASE + 0x794)
+#define SYS_TIMER_LATCH_L_03 (SPM_BASE + 0x798)
+#define SYS_TIMER_LATCH_H_03 (SPM_BASE + 0x79C)
+#define SYS_TIMER_LATCH_L_04 (SPM_BASE + 0x7A0)
+#define SYS_TIMER_LATCH_H_04 (SPM_BASE + 0x7A4)
+#define SYS_TIMER_LATCH_L_05 (SPM_BASE + 0x7A8)
+#define SYS_TIMER_LATCH_H_05 (SPM_BASE + 0x7AC)
+#define SYS_TIMER_LATCH_L_06 (SPM_BASE + 0x7B0)
+#define SYS_TIMER_LATCH_H_06 (SPM_BASE + 0x7B4)
+#define SYS_TIMER_LATCH_L_07 (SPM_BASE + 0x7B8)
+#define SYS_TIMER_LATCH_H_07 (SPM_BASE + 0x7BC)
+#define SYS_TIMER_LATCH_L_08 (SPM_BASE + 0x7C0)
+#define SYS_TIMER_LATCH_H_08 (SPM_BASE + 0x7C4)
+#define SYS_TIMER_LATCH_L_09 (SPM_BASE + 0x7C8)
+#define SYS_TIMER_LATCH_H_09 (SPM_BASE + 0x7CC)
+#define SYS_TIMER_LATCH_L_10 (SPM_BASE + 0x7D0)
+#define SYS_TIMER_LATCH_H_10 (SPM_BASE + 0x7D4)
+#define SYS_TIMER_LATCH_L_11 (SPM_BASE + 0x7D8)
+#define SYS_TIMER_LATCH_H_11 (SPM_BASE + 0x7DC)
+#define SYS_TIMER_LATCH_L_12 (SPM_BASE + 0x7E0)
+#define SYS_TIMER_LATCH_H_12 (SPM_BASE + 0x7E4)
+#define SYS_TIMER_LATCH_L_13 (SPM_BASE + 0x7E8)
+#define SYS_TIMER_LATCH_H_13 (SPM_BASE + 0x7EC)
+#define SYS_TIMER_LATCH_L_14 (SPM_BASE + 0x7F0)
+#define SYS_TIMER_LATCH_H_14 (SPM_BASE + 0x7F4)
+#define SYS_TIMER_LATCH_L_15 (SPM_BASE + 0x7F8)
+#define SYS_TIMER_LATCH_H_15 (SPM_BASE + 0x7FC)
+#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 PCM_WDT_LATCH_10 (SPM_BASE + 0x828)
+#define PCM_WDT_LATCH_11 (SPM_BASE + 0x82C)
+#define PCM_WDT_LATCH_12 (SPM_BASE + 0x830)
+#define PCM_WDT_LATCH_13 (SPM_BASE + 0x834)
+#define PCM_WDT_LATCH_14 (SPM_BASE + 0x838)
+#define PCM_WDT_LATCH_15 (SPM_BASE + 0x83C)
+#define PCM_WDT_LATCH_16 (SPM_BASE + 0x840)
+#define PCM_WDT_LATCH_17 (SPM_BASE + 0x844)
+#define PCM_WDT_LATCH_18 (SPM_BASE + 0x848)
+#define PCM_WDT_LATCH_SPARE_0 (SPM_BASE + 0x84C)
+#define PCM_WDT_LATCH_SPARE_1 (SPM_BASE + 0x850)
+#define PCM_WDT_LATCH_SPARE_2 (SPM_BASE + 0x854)
+#define PCM_WDT_LATCH_CONN_0 (SPM_BASE + 0x870)
+#define PCM_WDT_LATCH_CONN_1 (SPM_BASE + 0x874)
+#define PCM_WDT_LATCH_CONN_2 (SPM_BASE + 0x878)
+#define DRAMC_GATING_ERR_LATCH_CH0_0 (SPM_BASE + 0x8A0)
+#define DRAMC_GATING_ERR_LATCH_CH0_1 (SPM_BASE + 0x8A4)
+#define DRAMC_GATING_ERR_LATCH_CH0_2 (SPM_BASE + 0x8A8)
+#define DRAMC_GATING_ERR_LATCH_CH0_3 (SPM_BASE + 0x8AC)
+#define DRAMC_GATING_ERR_LATCH_CH0_4 (SPM_BASE + 0x8B0)
+#define DRAMC_GATING_ERR_LATCH_CH0_5 (SPM_BASE + 0x8B4)
+#define DRAMC_GATING_ERR_LATCH_CH0_6 (SPM_BASE + 0x8B8)
+#define DRAMC_GATING_ERR_LATCH_SPARE_0 (SPM_BASE + 0x8F4)
+#define SPM_ACK_CHK_CON_0 (SPM_BASE + 0x900)
+#define SPM_ACK_CHK_PC_0 (SPM_BASE + 0x904)
+#define SPM_ACK_CHK_SEL_0 (SPM_BASE + 0x908)
+#define SPM_ACK_CHK_TIMER_0 (SPM_BASE + 0x90C)
+#define SPM_ACK_CHK_STA_0 (SPM_BASE + 0x910)
+#define SPM_ACK_CHK_SWINT_0 (SPM_BASE + 0x914)
+#define SPM_ACK_CHK_CON_1 (SPM_BASE + 0x920)
+#define SPM_ACK_CHK_PC_1 (SPM_BASE + 0x924)
+#define SPM_ACK_CHK_SEL_1 (SPM_BASE + 0x928)
+#define SPM_ACK_CHK_TIMER_1 (SPM_BASE + 0x92C)
+#define SPM_ACK_CHK_STA_1 (SPM_BASE + 0x930)
+#define SPM_ACK_CHK_SWINT_1 (SPM_BASE + 0x934)
+#define SPM_ACK_CHK_CON_2 (SPM_BASE + 0x940)
+#define SPM_ACK_CHK_PC_2 (SPM_BASE + 0x944)
+#define SPM_ACK_CHK_SEL_2 (SPM_BASE + 0x948)
+#define SPM_ACK_CHK_TIMER_2 (SPM_BASE + 0x94C)
+#define SPM_ACK_CHK_STA_2 (SPM_BASE + 0x950)
+#define SPM_ACK_CHK_SWINT_2 (SPM_BASE + 0x954)
+#define SPM_ACK_CHK_CON_3 (SPM_BASE + 0x960)
+#define SPM_ACK_CHK_PC_3 (SPM_BASE + 0x964)
+#define SPM_ACK_CHK_SEL_3 (SPM_BASE + 0x968)
+#define SPM_ACK_CHK_TIMER_3 (SPM_BASE + 0x96C)
+#define SPM_ACK_CHK_STA_3 (SPM_BASE + 0x970)
+#define SPM_ACK_CHK_SWINT_3 (SPM_BASE + 0x974)
+#define SPM_COUNTER_0 (SPM_BASE + 0x978)
+#define SPM_COUNTER_1 (SPM_BASE + 0x97C)
+#define SPM_COUNTER_2 (SPM_BASE + 0x980)
+#define SYS_TIMER_CON (SPM_BASE + 0x98C)
+#define RC_FSM_STA_0 (SPM_BASE + 0xE00)
+#define RC_CMD_STA_0 (SPM_BASE + 0xE04)
+#define RC_CMD_STA_1 (SPM_BASE + 0xE08)
+#define RC_SPI_STA_0 (SPM_BASE + 0xE0C)
+#define RC_PI_PO_STA_0 (SPM_BASE + 0xE10)
+#define RC_M00_REQ_STA_0 (SPM_BASE + 0xE14)
+#define RC_M01_REQ_STA_0 (SPM_BASE + 0xE1C)
+#define RC_M02_REQ_STA_0 (SPM_BASE + 0xE20)
+#define RC_M03_REQ_STA_0 (SPM_BASE + 0xE24)
+#define RC_M04_REQ_STA_0 (SPM_BASE + 0xE28)
+#define RC_M05_REQ_STA_0 (SPM_BASE + 0xE2C)
+#define RC_M06_REQ_STA_0 (SPM_BASE + 0xE30)
+#define RC_M07_REQ_STA_0 (SPM_BASE + 0xE34)
+#define RC_M08_REQ_STA_0 (SPM_BASE + 0xE38)
+#define RC_M09_REQ_STA_0 (SPM_BASE + 0xE3C)
+#define RC_M10_REQ_STA_0 (SPM_BASE + 0xE40)
+#define RC_M11_REQ_STA_0 (SPM_BASE + 0xE44)
+#define RC_M12_REQ_STA_0 (SPM_BASE + 0xE48)
+#define RC_DEBUG_STA_0 (SPM_BASE + 0xE4C)
+#define RC_DEBUG_TRACE_0_LSB (SPM_BASE + 0xE50)
+#define RC_DEBUG_TRACE_0_MSB (SPM_BASE + 0xE54)
+#define RC_DEBUG_TRACE_1_LSB (SPM_BASE + 0xE5C)
+#define RC_DEBUG_TRACE_1_MSB (SPM_BASE + 0xE60)
+#define RC_DEBUG_TRACE_2_LSB (SPM_BASE + 0xE64)
+#define RC_DEBUG_TRACE_2_MSB (SPM_BASE + 0xE6C)
+#define RC_DEBUG_TRACE_3_LSB (SPM_BASE + 0xE70)
+#define RC_DEBUG_TRACE_3_MSB (SPM_BASE + 0xE74)
+#define RC_DEBUG_TRACE_4_LSB (SPM_BASE + 0xE78)
+#define RC_DEBUG_TRACE_4_MSB (SPM_BASE + 0xE7C)
+#define RC_DEBUG_TRACE_5_LSB (SPM_BASE + 0xE80)
+#define RC_DEBUG_TRACE_5_MSB (SPM_BASE + 0xE84)
+#define RC_DEBUG_TRACE_6_LSB (SPM_BASE + 0xE88)
+#define RC_DEBUG_TRACE_6_MSB (SPM_BASE + 0xE8C)
+#define RC_DEBUG_TRACE_7_LSB (SPM_BASE + 0xE90)
+#define RC_DEBUG_TRACE_7_MSB (SPM_BASE + 0xE94)
+#define RC_SYS_TIMER_LATCH_0_LSB (SPM_BASE + 0xE98)
+#define RC_SYS_TIMER_LATCH_0_MSB (SPM_BASE + 0xE9C)
+#define RC_SYS_TIMER_LATCH_1_LSB (SPM_BASE + 0xEA0)
+#define RC_SYS_TIMER_LATCH_1_MSB (SPM_BASE + 0xEA4)
+#define RC_SYS_TIMER_LATCH_2_LSB (SPM_BASE + 0xEA8)
+#define RC_SYS_TIMER_LATCH_2_MSB (SPM_BASE + 0xEAC)
+#define RC_SYS_TIMER_LATCH_3_LSB (SPM_BASE + 0xEB0)
+#define RC_SYS_TIMER_LATCH_3_MSB (SPM_BASE + 0xEB4)
+#define RC_SYS_TIMER_LATCH_4_LSB (SPM_BASE + 0xEB8)
+#define RC_SYS_TIMER_LATCH_4_MSB (SPM_BASE + 0xEBC)
+#define RC_SYS_TIMER_LATCH_5_LSB (SPM_BASE + 0xEC0)
+#define RC_SYS_TIMER_LATCH_5_MSB (SPM_BASE + 0xEC4)
+#define RC_SYS_TIMER_LATCH_6_LSB (SPM_BASE + 0xEC8)
+#define RC_SYS_TIMER_LATCH_6_MSB (SPM_BASE + 0xECC)
+#define RC_SYS_TIMER_LATCH_7_LSB (SPM_BASE + 0xED0)
+#define RC_SYS_TIMER_LATCH_7_MSB (SPM_BASE + 0xED4)
+#define PCM_WDT_LATCH_19 (SPM_BASE + 0xED8)
+#define PCM_WDT_LATCH_20 (SPM_BASE + 0xEDC)
+#define PCM_WDT_LATCH_21 (SPM_BASE + 0xEE0)
+#define PCM_WDT_LATCH_22 (SPM_BASE + 0xEE4)
+#define PCM_WDT_LATCH_23 (SPM_BASE + 0xEE8)
+#define PCM_WDT_LATCH_24 (SPM_BASE + 0xEEC)
+#define PMSR_LAST_DAT (SPM_BASE + 0xF00)
+#define PMSR_LAST_CNT (SPM_BASE + 0xF04)
+#define PMSR_LAST_ACK (SPM_BASE + 0xF08)
+#define SPM_PMSR_SEL_CON0 (SPM_BASE + 0xF10)
+#define SPM_PMSR_SEL_CON1 (SPM_BASE + 0xF14)
+#define SPM_PMSR_SEL_CON2 (SPM_BASE + 0xF18)
+#define SPM_PMSR_SEL_CON3 (SPM_BASE + 0xF1C)
+#define SPM_PMSR_SEL_CON4 (SPM_BASE + 0xF20)
+#define SPM_PMSR_SEL_CON5 (SPM_BASE + 0xF24)
+#define SPM_PMSR_SEL_CON6 (SPM_BASE + 0xF28)
+#define SPM_PMSR_SEL_CON7 (SPM_BASE + 0xF2C)
+#define SPM_PMSR_SEL_CON8 (SPM_BASE + 0xF30)
+#define SPM_PMSR_SEL_CON9 (SPM_BASE + 0xF34)
+#define SPM_PMSR_SEL_CON10 (SPM_BASE + 0xF3C)
+#define SPM_PMSR_SEL_CON11 (SPM_BASE + 0xF40)
+#define SPM_PMSR_TIEMR_STA0 (SPM_BASE + 0xFB8)
+#define SPM_PMSR_TIEMR_STA1 (SPM_BASE + 0xFBC)
+#define SPM_PMSR_TIEMR_STA2 (SPM_BASE + 0xFC0)
+#define SPM_PMSR_GENERAL_CON0 (SPM_BASE + 0xFC4)
+#define SPM_PMSR_GENERAL_CON1 (SPM_BASE + 0xFC8)
+#define SPM_PMSR_GENERAL_CON2 (SPM_BASE + 0xFCC)
+#define SPM_PMSR_GENERAL_CON3 (SPM_BASE + 0xFD0)
+#define SPM_PMSR_GENERAL_CON4 (SPM_BASE + 0xFD4)
+#define SPM_PMSR_GENERAL_CON5 (SPM_BASE + 0xFD8)
+#define SPM_PMSR_SW_RESET (SPM_BASE + 0xFDC)
+#define SPM_PMSR_MON_CON0 (SPM_BASE + 0xFE0)
+#define SPM_PMSR_MON_CON1 (SPM_BASE + 0xFE4)
+#define SPM_PMSR_MON_CON2 (SPM_BASE + 0xFE8)
+#define SPM_PMSR_LEN_CON0 (SPM_BASE + 0xFEC)
+#define SPM_PMSR_LEN_CON1 (SPM_BASE + 0xFF0)
+#define SPM_PMSR_LEN_CON2 (SPM_BASE + 0xFF4)
+
+/* POWERON_CONFIG_EN (0x10006000+0x000) */
+#define BCLK_CG_EN_LSB (1U << 0) /* 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 REG_SRCCLKEN0_CTL_LSB (1U << 0) /* 2b */
+#define REG_SRCCLKEN1_CTL_LSB (1U << 2) /* 2b */
+#define SYS_SETTLE_SEL_LSB (1U << 4) /* 1b */
+#define REG_SPM_LOCK_INFRA_DCM_LSB (1U << 5) /* 1b */
+#define REG_SRCCLKEN_MASK_LSB (1U << 6) /* 3b */
+#define REG_MD1_C32RM_EN_LSB (1U << 9) /* 1b */
+#define REG_MD2_C32RM_EN_LSB (1U << 10) /* 1b */
+#define REG_CLKSQ0_SEL_CTRL_LSB (1U << 11) /* 1b */
+#define REG_CLKSQ1_SEL_CTRL_LSB (1U << 12) /* 1b */
+#define REG_SRCCLKEN0_EN_LSB (1U << 13) /* 1b */
+#define REG_SRCCLKEN1_EN_LSB (1U << 14) /* 1b */
+#define SCP_DCM_EN_LSB (1U << 15) /* 1b */
+#define REG_SYSCLK0_SRC_MASK_B_LSB (1U << 16) /* 8b */
+#define REG_SYSCLK1_SRC_MASK_B_LSB (1U << 24) /* 8b */
+/* SPM_CLK_SETTLE (0x10006000+0x010) */
+#define SYSCLK_SETTLE_LSB (1U << 0) /* 28b */
+/* SPM_AP_STANDBY_CON (0x10006000+0x014) */
+#define REG_WFI_OP_LSB (1U << 0) /* 1b */
+#define REG_WFI_TYPE_LSB (1U << 1) /* 1b */
+#define REG_MP0_CPUTOP_IDLE_MASK_LSB (1U << 2) /* 1b */
+#define REG_MP1_CPUTOP_IDLE_MASK_LSB (1U << 3) /* 1b */
+#define REG_MCUSYS_IDLE_MASK_LSB (1U << 4) /* 1b */
+#define REG_MD_APSRC_1_SEL_LSB (1U << 25) /* 1b */
+#define REG_MD_APSRC_0_SEL_LSB (1U << 26) /* 1b */
+#define REG_CONN_APSRC_SEL_LSB (1U << 29) /* 1b */
+/* PCM_CON0 (0x10006000+0x018) */
+#define PCM_CK_EN_LSB (1U << 2) /* 1b */
+#define RG_EN_IM_SLEEP_DVS_LSB (1U << 3) /* 1b */
+#define PCM_CK_FROM_CKSYS_LSB (1U << 4) /* 1b */
+#define PCM_SW_RESET_LSB (1U << 15) /* 1b */
+#define PCM_CON0_PROJECT_CODE_LSB (1U << 16) /* 16b */
+/* PCM_CON1 (0x10006000+0x01C) */
+#define RG_IM_SLAVE_LSB (1U << 0) /* 1b */
+#define RG_IM_SLEEP_LSB (1U << 1) /* 1b */
+#define REG_SPM_SRAM_CTRL_MUX_LSB (1U << 2) /* 1b */
+#define RG_AHBMIF_APBEN_LSB (1U << 3) /* 1b */
+#define RG_IM_PDN_LSB (1U << 4) /* 1b */
+#define RG_PCM_TIMER_EN_LSB (1U << 5) /* 1b */
+#define SPM_EVENT_COUNTER_CLR_LSB (1U << 6) /* 1b */
+#define RG_DIS_MIF_PROT_LSB (1U << 7) /* 1b */
+#define RG_PCM_WDT_EN_LSB (1U << 8) /* 1b */
+#define RG_PCM_WDT_WAKE_LSB (1U << 9) /* 1b */
+#define REG_SPM_SRAM_SLEEP_B_LSB (1U << 10) /* 1b */
+#define REG_SPM_SRAM_ISOINT_B_LSB (1U << 11) /* 1b */
+#define REG_EVENT_LOCK_EN_LSB (1U << 12) /* 1b */
+#define REG_SRCCLKEN_FAST_RESP_LSB (1U << 13) /* 1b */
+#define REG_MD32_APB_INTERNAL_EN_LSB (1U << 14) /* 1b */
+#define RG_PCM_IRQ_MSK_LSB (1U << 15) /* 1b */
+#define PCM_CON1_PROJECT_CODE_LSB (1U << 16) /* 16b */
+/* SPM_POWER_ON_VAL2 (0x10006000+0x020) */
+#define POWER_ON_VAL2_LSB (1U << 0) /* 32b */
+/* SPM_POWER_ON_VAL3 (0x10006000+0x024) */
+#define POWER_ON_VAL3_LSB (1U << 0) /* 32b */
+/* 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 RG_RF_SYNC_EN_LSB (1U << 16) /* 8b */
+/* PCM_TIMER_VAL (0x10006000+0x030) */
+#define REG_PCM_TIMER_VAL_LSB (1U << 0) /* 32b */
+/* PCM_WDT_VAL (0x10006000+0x034) */
+#define RG_PCM_WDT_VAL_LSB (1U << 0) /* 32b */
+/* SPM_SRC6_MASK (0x10006000+0x038) */
+#define REG_DPMAIF_SRCCLKENA_MASK_B_LSB (1U << 0) /* 1b */
+#define REG_DPMAIF_INFRA_REQ_MASK_B_LSB (1U << 1) /* 1b */
+#define REG_DPMAIF_APSRC_REQ_MASK_B_LSB (1U << 2) /* 1b */
+#define REG_DPMAIF_VRF18_REQ_MASK_B_LSB (1U << 3) /* 1b */
+#define REG_DPMAIF_DDR_EN_MASK_B_LSB (1U << 4) /* 1b */
+/* SPM_SW_RST_CON (0x10006000+0x040) */
+#define SPM_SW_RST_CON_LSB (1U << 0) /* 16b */
+#define SPM_SW_RST_CON_PROJECT_CODE_LSB (1U << 16) /* 16b */
+/* SPM_SW_RST_CON_SET (0x10006000+0x044) */
+#define SPM_SW_RST_CON_SET_LSB (1U << 0) /* 16b */
+#define SPM_SW_RST_CON_SET_PROJECT_CODE_LSB (1U << 16) /* 16b */
+/* SPM_SW_RST_CON_CLR (0x10006000+0x048) */
+#define SPM_SW_RST_CON_CLR_LSB (1U << 0) /* 16b */
+#define SPM_SW_RST_CON_CLR_PROJECT_CODE_LSB (1U << 16) /* 16b */
+/* VS1_PSR_MASK_B (0x10006000+0x04C) */
+#define VS1_OPP0_PSR_MASK_B_LSB (1U << 0) /* 8b */
+#define VS1_OPP1_PSR_MASK_B_LSB (1U << 8) /* 8b */
+/* VS2_PSR_MASK_B (0x10006000+0x050) */
+#define VS2_OPP0_PSR_MASK_B_LSB (1U << 0) /* 8b */
+#define VS2_OPP1_PSR_MASK_B_LSB (1U << 8) /* 8b */
+#define VS2_OPP2_PSR_MASK_B_LSB (1U << 16) /* 8b */
+/* MD32_CLK_CON (0x10006000+0x084) */
+#define REG_MD32_26M_CK_SEL_LSB (1U << 0) /* 1b */
+#define REG_MD32_DCM_EN_LSB (1U << 1) /* 1b */
+/* 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) /* 32b */
+/* SPM_SWINT_SET (0x10006000+0x090) */
+#define SPM_SWINT_SET_LSB (1U << 0) /* 32b */
+/* SPM_SWINT_CLR (0x10006000+0x094) */
+#define SPM_SWINT_CLR_LSB (1U << 0) /* 32b */
+/* 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 REG_TWAM_ENABLE_LSB (1U << 0) /* 1b */
+#define REG_TWAM_SPEED_MODE_EN_LSB (1U << 1) /* 1b */
+#define REG_TWAM_SW_RST_LSB (1U << 2) /* 1b */
+#define REG_TWAM_IRQ_MASK_LSB (1U << 3) /* 1b */
+#define REG_TWAM_MON_TYPE_0_LSB (1U << 4) /* 2b */
+#define REG_TWAM_MON_TYPE_1_LSB (1U << 6) /* 2b */
+#define REG_TWAM_MON_TYPE_2_LSB (1U << 8) /* 2b */
+#define REG_TWAM_MON_TYPE_3_LSB (1U << 10) /* 2b */
+/* SPM_TWAM_WINDOW_LEN (0x10006000+0x0A4) */
+#define REG_TWAM_WINDOW_LEN_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_IDLE_SEL (0x10006000+0x0A8) */
+#define REG_TWAM_SIG_SEL_0_LSB (1U << 0) /* 7b */
+#define REG_TWAM_SIG_SEL_1_LSB (1U << 8) /* 7b */
+#define REG_TWAM_SIG_SEL_2_LSB (1U << 16) /* 7b */
+#define REG_TWAM_SIG_SEL_3_LSB (1U << 24) /* 7b */
+/* SPM_SCP_IRQ (0x10006000+0x0AC) */
+#define SC_SPM2SCP_WAKEUP_LSB (1U << 0) /* 1b */
+#define SC_SCP2SPM_WAKEUP_LSB (1U << 4) /* 1b */
+/* SPM_CPU_WAKEUP_EVENT (0x10006000+0x0B0) */
+#define REG_CPU_WAKEUP_LSB (1U << 0) /* 1b */
+/* SPM_IRQ_MASK (0x10006000+0x0B4) */
+#define REG_SPM_IRQ_MASK_LSB (1U << 0) /* 32b */
+/* SPM_SRC_REQ (0x10006000+0x0B8) */
+#define REG_SPM_APSRC_REQ_LSB (1U << 0) /* 1b */
+#define REG_SPM_F26M_REQ_LSB (1U << 1) /* 1b */
+#define REG_SPM_INFRA_REQ_LSB (1U << 3) /* 1b */
+#define REG_SPM_VRF18_REQ_LSB (1U << 4) /* 1b */
+#define REG_SPM_DDR_EN_REQ_LSB (1U << 7) /* 1b */
+#define REG_SPM_DVFS_REQ_LSB (1U << 8) /* 1b */
+#define REG_SPM_SW_MAILBOX_REQ_LSB (1U << 9) /* 1b */
+#define REG_SPM_SSPM_MAILBOX_REQ_LSB (1U << 10) /* 1b */
+#define REG_SPM_ADSP_MAILBOX_REQ_LSB (1U << 11) /* 1b */
+#define REG_SPM_SCP_MAILBOX_REQ_LSB (1U << 12) /* 1b */
+/* SPM_SRC_MASK (0x10006000+0x0BC) */
+#define REG_MD_SRCCLKENA_0_MASK_B_LSB (1U << 0) /* 1b */
+#define REG_MD_SRCCLKENA2INFRA_REQ_0_MASK_B_LSB (1U << 1) /* 1b */
+#define REG_MD_APSRC2INFRA_REQ_0_MASK_B_LSB (1U << 2) /* 1b */
+#define REG_MD_APSRC_REQ_0_MASK_B_LSB (1U << 3) /* 1b */
+#define REG_MD_VRF18_REQ_0_MASK_B_LSB (1U << 4) /* 1b */
+#define REG_MD_DDR_EN_0_MASK_B_LSB (1U << 5) /* 1b */
+#define REG_MD_SRCCLKENA_1_MASK_B_LSB (1U << 6) /* 1b */
+#define REG_MD_SRCCLKENA2INFRA_REQ_1_MASK_B_LSB (1U << 7) /* 1b */
+#define REG_MD_APSRC2INFRA_REQ_1_MASK_B_LSB (1U << 8) /* 1b */
+#define REG_MD_APSRC_REQ_1_MASK_B_LSB (1U << 9) /* 1b */
+#define REG_MD_VRF18_REQ_1_MASK_B_LSB (1U << 10) /* 1b */
+#define REG_MD_DDR_EN_1_MASK_B_LSB (1U << 11) /* 1b */
+#define REG_CONN_SRCCLKENA_MASK_B_LSB (1U << 12) /* 1b */
+#define REG_CONN_SRCCLKENB_MASK_B_LSB (1U << 13) /* 1b */
+#define REG_CONN_INFRA_REQ_MASK_B_LSB (1U << 14) /* 1b */
+#define REG_CONN_APSRC_REQ_MASK_B_LSB (1U << 15) /* 1b */
+#define REG_CONN_VRF18_REQ_MASK_B_LSB (1U << 16) /* 1b */
+#define REG_CONN_DDR_EN_MASK_B_LSB (1U << 17) /* 1b */
+#define REG_CONN_VFE28_MASK_B_LSB (1U << 18) /* 1b */
+#define REG_SRCCLKENI0_SRCCLKENA_MASK_B_LSB (1U << 19) /* 1b */
+#define REG_SRCCLKENI0_INFRA_REQ_MASK_B_LSB (1U << 20) /* 1b */
+#define REG_SRCCLKENI1_SRCCLKENA_MASK_B_LSB (1U << 21) /* 1b */
+#define REG_SRCCLKENI1_INFRA_REQ_MASK_B_LSB (1U << 22) /* 1b */
+#define REG_SRCCLKENI2_SRCCLKENA_MASK_B_LSB (1U << 23) /* 1b */
+#define REG_SRCCLKENI2_INFRA_REQ_MASK_B_LSB (1U << 24) /* 1b */
+#define REG_INFRASYS_APSRC_REQ_MASK_B_LSB (1U << 25) /* 1b */
+#define REG_INFRASYS_DDR_EN_MASK_B_LSB (1U << 26) /* 1b */
+#define REG_MD32_SRCCLKENA_MASK_B_LSB (1U << 27) /* 1b */
+#define REG_MD32_INFRA_REQ_MASK_B_LSB (1U << 28) /* 1b */
+#define REG_MD32_APSRC_REQ_MASK_B_LSB (1U << 29) /* 1b */
+#define REG_MD32_VRF18_REQ_MASK_B_LSB (1U << 30) /* 1b */
+#define REG_MD32_DDR_EN_MASK_B_LSB (1U << 31) /* 1b */
+/* SPM_SRC2_MASK (0x10006000+0x0C0) */
+#define REG_SCP_SRCCLKENA_MASK_B_LSB (1U << 0) /* 1b */
+#define REG_SCP_INFRA_REQ_MASK_B_LSB (1U << 1) /* 1b */
+#define REG_SCP_APSRC_REQ_MASK_B_LSB (1U << 2) /* 1b */
+#define REG_SCP_VRF18_REQ_MASK_B_LSB (1U << 3) /* 1b */
+#define REG_SCP_DDR_EN_MASK_B_LSB (1U << 4) /* 1b */
+#define REG_AUDIO_DSP_SRCCLKENA_MASK_B_LSB (1U << 5) /* 1b */
+#define REG_AUDIO_DSP_INFRA_REQ_MASK_B_LSB (1U << 6) /* 1b */
+#define REG_AUDIO_DSP_APSRC_REQ_MASK_B_LSB (1U << 7) /* 1b */
+#define REG_AUDIO_DSP_VRF18_REQ_MASK_B_LSB (1U << 8) /* 1b */
+#define REG_AUDIO_DSP_DDR_EN_MASK_B_LSB (1U << 9) /* 1b */
+#define REG_UFS_SRCCLKENA_MASK_B_LSB (1U << 10) /* 1b */
+#define REG_UFS_INFRA_REQ_MASK_B_LSB (1U << 11) /* 1b */
+#define REG_UFS_APSRC_REQ_MASK_B_LSB (1U << 12) /* 1b */
+#define REG_UFS_VRF18_REQ_MASK_B_LSB (1U << 13) /* 1b */
+#define REG_UFS_DDR_EN_MASK_B_LSB (1U << 14) /* 1b */
+#define REG_DISP0_APSRC_REQ_MASK_B_LSB (1U << 15) /* 1b */
+#define REG_DISP0_DDR_EN_MASK_B_LSB (1U << 16) /* 1b */
+#define REG_DISP1_APSRC_REQ_MASK_B_LSB (1U << 17) /* 1b */
+#define REG_DISP1_DDR_EN_MASK_B_LSB (1U << 18) /* 1b */
+#define REG_GCE_INFRA_REQ_MASK_B_LSB (1U << 19) /* 1b */
+#define REG_GCE_APSRC_REQ_MASK_B_LSB (1U << 20) /* 1b */
+#define REG_GCE_VRF18_REQ_MASK_B_LSB (1U << 21) /* 1b */
+#define REG_GCE_DDR_EN_MASK_B_LSB (1U << 22) /* 1b */
+#define REG_APU_SRCCLKENA_MASK_B_LSB (1U << 23) /* 1b */
+#define REG_APU_INFRA_REQ_MASK_B_LSB (1U << 24) /* 1b */
+#define REG_APU_APSRC_REQ_MASK_B_LSB (1U << 25) /* 1b */
+#define REG_APU_VRF18_REQ_MASK_B_LSB (1U << 26) /* 1b */
+#define REG_APU_DDR_EN_MASK_B_LSB (1U << 27) /* 1b */
+#define REG_CG_CHECK_SRCCLKENA_MASK_B_LSB (1U << 28) /* 1b */
+#define REG_CG_CHECK_APSRC_REQ_MASK_B_LSB (1U << 29) /* 1b */
+#define REG_CG_CHECK_VRF18_REQ_MASK_B_LSB (1U << 30) /* 1b */
+#define REG_CG_CHECK_DDR_EN_MASK_B_LSB (1U << 31) /* 1b */
+/* SPM_SRC3_MASK (0x10006000+0x0C4) */
+#define REG_DVFSRC_EVENT_TRIGGER_MASK_B_LSB (1U << 0) /* 1b */
+#define REG_SW2SPM_INT0_MASK_B_LSB (1U << 1) /* 1b */
+#define REG_SW2SPM_INT1_MASK_B_LSB (1U << 2) /* 1b */
+#define REG_SW2SPM_INT2_MASK_B_LSB (1U << 3) /* 1b */
+#define REG_SW2SPM_INT3_MASK_B_LSB (1U << 4) /* 1b */
+#define REG_SC_ADSP2SPM_WAKEUP_MASK_B_LSB (1U << 5) /* 1b */
+#define REG_SC_SSPM2SPM_WAKEUP_MASK_B_LSB (1U << 6) /* 4b */
+#define REG_SC_SCP2SPM_WAKEUP_MASK_B_LSB (1U << 10) /* 1b */
+#define REG_CSYSPWRREQ_MASK_LSB (1U << 11) /* 1b */
+#define REG_SPM_SRCCLKENA_RESERVED_MASK_B_LSB (1U << 12) /* 1b */
+#define REG_SPM_INFRA_REQ_RESERVED_MASK_B_LSB (1U << 13) /* 1b */
+#define REG_SPM_APSRC_REQ_RESERVED_MASK_B_LSB (1U << 14) /* 1b */
+#define REG_SPM_VRF18_REQ_RESERVED_MASK_B_LSB (1U << 15) /* 1b */
+#define REG_SPM_DDR_EN_RESERVED_MASK_B_LSB (1U << 16) /* 1b */
+#define REG_MCUPM_SRCCLKENA_MASK_B_LSB (1U << 17) /* 1b */
+#define REG_MCUPM_INFRA_REQ_MASK_B_LSB (1U << 18) /* 1b */
+#define REG_MCUPM_APSRC_REQ_MASK_B_LSB (1U << 19) /* 1b */
+#define REG_MCUPM_VRF18_REQ_MASK_B_LSB (1U << 20) /* 1b */
+#define REG_MCUPM_DDR_EN_MASK_B_LSB (1U << 21) /* 1b */
+#define REG_MSDC0_SRCCLKENA_MASK_B_LSB (1U << 22) /* 1b */
+#define REG_MSDC0_INFRA_REQ_MASK_B_LSB (1U << 23) /* 1b */
+#define REG_MSDC0_APSRC_REQ_MASK_B_LSB (1U << 24) /* 1b */
+#define REG_MSDC0_VRF18_REQ_MASK_B_LSB (1U << 25) /* 1b */
+#define REG_MSDC0_DDR_EN_MASK_B_LSB (1U << 26) /* 1b */
+#define REG_MSDC1_SRCCLKENA_MASK_B_LSB (1U << 27) /* 1b */
+#define REG_MSDC1_INFRA_REQ_MASK_B_LSB (1U << 28) /* 1b */
+#define REG_MSDC1_APSRC_REQ_MASK_B_LSB (1U << 29) /* 1b */
+#define REG_MSDC1_VRF18_REQ_MASK_B_LSB (1U << 30) /* 1b */
+#define REG_MSDC1_DDR_EN_MASK_B_LSB (1U << 31) /* 1b */
+/* SPM_SRC4_MASK (0x10006000+0x0C8) */
+#define CCIF_EVENT_MASK_B_LSB (1U << 0) /* 16b */
+#define REG_BAK_PSRI_SRCCLKENA_MASK_B_LSB (1U << 16) /* 1b */
+#define REG_BAK_PSRI_INFRA_REQ_MASK_B_LSB (1U << 17) /* 1b */
+#define REG_BAK_PSRI_APSRC_REQ_MASK_B_LSB (1U << 18) /* 1b */
+#define REG_BAK_PSRI_VRF18_REQ_MASK_B_LSB (1U << 19) /* 1b */
+#define REG_BAK_PSRI_DDR_EN_MASK_B_LSB (1U << 20) /* 1b */
+#define REG_DRAMC0_MD32_INFRA_REQ_MASK_B_LSB (1U << 21) /* 1b */
+#define REG_DRAMC0_MD32_VRF18_REQ_MASK_B_LSB (1U << 22) /* 1b */
+#define REG_DRAMC1_MD32_INFRA_REQ_MASK_B_LSB (1U << 23) /* 1b */
+#define REG_DRAMC1_MD32_VRF18_REQ_MASK_B_LSB (1U << 24) /* 1b */
+#define REG_CONN_SRCCLKENB2PWRAP_MASK_B_LSB (1U << 25) /* 1b */
+#define REG_DRAMC0_MD32_WAKEUP_MASK_LSB (1U << 26) /* 1b */
+#define REG_DRAMC1_MD32_WAKEUP_MASK_LSB (1U << 27) /* 1b */
+/* SPM_SRC5_MASK (0x10006000+0x0CC) */
+#define REG_MCUSYS_MERGE_APSRC_REQ_MASK_B_LSB (1U << 0) /* 9b */
+#define REG_MCUSYS_MERGE_DDR_EN_MASK_B_LSB (1U << 9) /* 9b */
+#define REG_MSDC2_SRCCLKENA_MASK_B_LSB (1U << 18) /* 1b */
+#define REG_MSDC2_INFRA_REQ_MASK_B_LSB (1U << 19) /* 1b */
+#define REG_MSDC2_APSRC_REQ_MASK_B_LSB (1U << 20) /* 1b */
+#define REG_MSDC2_VRF18_REQ_MASK_B_LSB (1U << 21) /* 1b */
+#define REG_MSDC2_DDR_EN_MASK_B_LSB (1U << 22) /* 1b */
+#define REG_PCIE_SRCCLKENA_MASK_B_LSB (1U << 23) /* 1b */
+#define REG_PCIE_INFRA_REQ_MASK_B_LSB (1U << 24) /* 1b */
+#define REG_PCIE_APSRC_REQ_MASK_B_LSB (1U << 25) /* 1b */
+#define REG_PCIE_VRF18_REQ_MASK_B_LSB (1U << 26) /* 1b */
+#define REG_PCIE_DDR_EN_MASK_B_LSB (1U << 27) /* 1b */
+/* SPM_WAKEUP_EVENT_MASK (0x10006000+0x0D0) */
+#define REG_WAKEUP_EVENT_MASK_LSB (1U << 0) /* 32b */
+/* SPM_WAKEUP_EVENT_EXT_MASK (0x10006000+0x0D4) */
+#define REG_EXT_WAKEUP_EVENT_MASK_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_EVENT_CLEAR (0x10006000+0x0D8) */
+#define SPM_TWAM_EVENT_CLEAR_LSB (1U << 0) /* 1b */
+/* SCP_CLK_CON (0x10006000+0x0DC) */
+#define REG_SCP_26M_CK_SEL_LSB (1U << 0) /* 1b */
+#define REG_SCP_DCM_EN_LSB (1U << 1) /* 1b */
+#define SCP_SECURE_V_REQ_MASK_LSB (1U << 2) /* 1b */
+#define SCP_SLP_REQ_LSB (1U << 3) /* 1b */
+#define SCP_SLP_ACK_LSB (1U << 4) /* 1b */
+/* PCM_DEBUG_CON (0x10006000+0x0E0) */
+#define PCM_DEBUG_OUT_ENABLE_LSB (1U << 0) /* 1b */
+/* AHB_BUS_CON (0x10006000+0x0E4) */
+#define AHB_HADDR_EXT_LSB (1U << 0) /* 2b */
+#define REG_AHB_LOCK_LSB (1U << 8) /* 1b */
+/* DDR_EN_DBC_CON0 (0x10006000+0x0E8) */
+#define REG_ALL_DDR_EN_DBC_LEN_LSB (1U << 0) /* 10b */
+#define REG_MD_DDR_EN_0_DBC_LEN_LSB (1U << 10) /* 10b */
+#define REG_HW_S1_DBC_LEN_LSB (1U << 20) /* 10b */
+/* DDR_EN_DBC_CON1 (0x10006000+0x0EC) */
+#define REG_ALL_DDR_EN_DBC_EN_LSB (1U << 0) /* 1b */
+#define REG_MD_DDR_EN_0_DBC_EN_LSB (1U << 1) /* 1b */
+#define REG_HW_S1_DBC_EN_LSB (1U << 2) /* 1b */
+/* SPM_RESOURCE_ACK_CON0 (0x10006000+0x0F0) */
+#define REG_MD_SRCCLKENA_ACK_0_MASK_LSB (1U << 0) /* 1b */
+#define REG_MD_INFRA_ACK_0_MASK_LSB (1U << 1) /* 1b */
+#define REG_MD_APSRC_ACK_0_MASK_LSB (1U << 2) /* 1b */
+#define REG_MD_VRF18_ACK_0_MASK_LSB (1U << 3) /* 1b */
+#define REG_MD_DDR_EN_ACK_0_MASK_LSB (1U << 4) /* 1b */
+#define REG_MD_SRCCLKENA_ACK_1_MASK_LSB (1U << 5) /* 1b */
+#define REG_MD_INFRA_ACK_1_MASK_LSB (1U << 6) /* 1b */
+#define REG_MD_APSRC_ACK_1_MASK_LSB (1U << 7) /* 1b */
+#define REG_MD_VRF18_ACK_1_MASK_LSB (1U << 8) /* 1b */
+#define REG_MD_DDR_EN_ACK_1_MASK_LSB (1U << 9) /* 1b */
+#define REG_CONN_SRCCLKENA_ACK_MASK_LSB (1U << 10) /* 1b */
+#define REG_CONN_INFRA_ACK_MASK_LSB (1U << 11) /* 1b */
+#define REG_CONN_APSRC_ACK_MASK_LSB (1U << 12) /* 1b */
+#define REG_CONN_VRF18_ACK_MASK_LSB (1U << 13) /* 1b */
+#define REG_CONN_DDR_EN_ACK_MASK_LSB (1U << 14) /* 1b */
+#define REG_MD32_SRCCLKENA_ACK_MASK_LSB (1U << 15) /* 1b */
+#define REG_MD32_INFRA_ACK_MASK_LSB (1U << 16) /* 1b */
+#define REG_MD32_APSRC_ACK_MASK_LSB (1U << 17) /* 1b */
+#define REG_MD32_VRF18_ACK_MASK_LSB (1U << 18) /* 1b */
+#define REG_MD32_DDR_EN_ACK_MASK_LSB (1U << 19) /* 1b */
+#define REG_SCP_SRCCLKENA_ACK_MASK_LSB (1U << 20) /* 1b */
+#define REG_SCP_INFRA_ACK_MASK_LSB (1U << 21) /* 1b */
+#define REG_SCP_APSRC_ACK_MASK_LSB (1U << 22) /* 1b */
+#define REG_SCP_VRF18_ACK_MASK_LSB (1U << 23) /* 1b */
+#define REG_SCP_DDR_EN_ACK_MASK_LSB (1U << 24) /* 1b */
+#define REG_AUDIO_DSP_SRCCLKENA_ACK_MASK_LSB (1U << 25) /* 1b */
+#define REG_AUDIO_DSP_INFRA_ACK_MASK_LSB (1U << 26) /* 1b */
+#define REG_AUDIO_DSP_APSRC_ACK_MASK_LSB (1U << 27) /* 1b */
+#define REG_AUDIO_DSP_VRF18_ACK_MASK_LSB (1U << 28) /* 1b */
+#define REG_AUDIO_DSP_DDR_EN_ACK_MASK_LSB (1U << 29) /* 1b */
+#define REG_DISP0_DDR_EN_ACK_MASK_LSB (1U << 30) /* 1b */
+#define REG_DISP1_APSRC_ACK_MASK_LSB (1U << 31) /* 1b */
+/* SPM_RESOURCE_ACK_CON1 (0x10006000+0x0F4) */
+#define REG_UFS_SRCCLKENA_ACK_MASK_LSB (1U << 0) /* 1b */
+#define REG_UFS_INFRA_ACK_MASK_LSB (1U << 1) /* 1b */
+#define REG_UFS_APSRC_ACK_MASK_LSB (1U << 2) /* 1b */
+#define REG_UFS_VRF18_ACK_MASK_LSB (1U << 3) /* 1b */
+#define REG_UFS_DDR_EN_ACK_MASK_LSB (1U << 4) /* 1b */
+#define REG_APU_SRCCLKENA_ACK_MASK_LSB (1U << 5) /* 1b */
+#define REG_APU_INFRA_ACK_MASK_LSB (1U << 6) /* 1b */
+#define REG_APU_APSRC_ACK_MASK_LSB (1U << 7) /* 1b */
+#define REG_APU_VRF18_ACK_MASK_LSB (1U << 8) /* 1b */
+#define REG_APU_DDR_EN_ACK_MASK_LSB (1U << 9) /* 1b */
+#define REG_MCUPM_SRCCLKENA_ACK_MASK_LSB (1U << 10) /* 1b */
+#define REG_MCUPM_INFRA_ACK_MASK_LSB (1U << 11) /* 1b */
+#define REG_MCUPM_APSRC_ACK_MASK_LSB (1U << 12) /* 1b */
+#define REG_MCUPM_VRF18_ACK_MASK_LSB (1U << 13) /* 1b */
+#define REG_MCUPM_DDR_EN_ACK_MASK_LSB (1U << 14) /* 1b */
+#define REG_MSDC0_SRCCLKENA_ACK_MASK_LSB (1U << 15) /* 1b */
+#define REG_MSDC0_INFRA_ACK_MASK_LSB (1U << 16) /* 1b */
+#define REG_MSDC0_APSRC_ACK_MASK_LSB (1U << 17) /* 1b */
+#define REG_MSDC0_VRF18_ACK_MASK_LSB (1U << 18) /* 1b */
+#define REG_MSDC0_DDR_EN_ACK_MASK_LSB (1U << 19) /* 1b */
+#define REG_MSDC1_SRCCLKENA_ACK_MASK_LSB (1U << 20) /* 1b */
+#define REG_MSDC1_INFRA_ACK_MASK_LSB (1U << 21) /* 1b */
+#define REG_MSDC1_APSRC_ACK_MASK_LSB (1U << 22) /* 1b */
+#define REG_MSDC1_VRF18_ACK_MASK_LSB (1U << 23) /* 1b */
+#define REG_MSDC1_DDR_EN_ACK_MASK_LSB (1U << 24) /* 1b */
+#define REG_DISP0_APSRC_ACK_MASK_LSB (1U << 25) /* 1b */
+#define REG_DISP1_DDR_EN_ACK_MASK_LSB (1U << 26) /* 1b */
+#define REG_GCE_INFRA_ACK_MASK_LSB (1U << 27) /* 1b */
+#define REG_GCE_APSRC_ACK_MASK_LSB (1U << 28) /* 1b */
+#define REG_GCE_VRF18_ACK_MASK_LSB (1U << 29) /* 1b */
+#define REG_GCE_DDR_EN_ACK_MASK_LSB (1U << 30) /* 1b */
+/* SPM_RESOURCE_ACK_CON2 (0x10006000+0x0F8) */
+#define SPM_F26M_ACK_WAIT_CYCLE_LSB (1U << 0) /* 8b */
+#define SPM_INFRA_ACK_WAIT_CYCLE_LSB (1U << 8) /* 8b */
+#define SPM_APSRC_ACK_WAIT_CYCLE_LSB (1U << 16) /* 8b */
+#define SPM_VRF18_ACK_WAIT_CYCLE_LSB (1U << 24) /* 8b */
+/* SPM_RESOURCE_ACK_CON3 (0x10006000+0x0FC) */
+#define SPM_DDR_EN_ACK_WAIT_CYCLE_LSB (1U << 0) /* 8b */
+#define REG_BAK_PSRI_SRCCLKENA_ACK_MASK_LSB (1U << 8) /* 1b */
+#define REG_BAK_PSRI_INFRA_ACK_MASK_LSB (1U << 9) /* 1b */
+#define REG_BAK_PSRI_APSRC_ACK_MASK_LSB (1U << 10) /* 1b */
+#define REG_BAK_PSRI_VRF18_ACK_MASK_LSB (1U << 11) /* 1b */
+#define REG_BAK_PSRI_DDR_EN_ACK_MASK_LSB (1U << 12) /* 1b */
+#define REG_MSDC2_SRCCLKENA_ACK_MASK_LSB (1U << 13) /* 1b */
+#define REG_MSDC2_INFRA_ACK_MASK_LSB (1U << 14) /* 1b */
+#define REG_MSDC2_APSRC_ACK_MASK_LSB (1U << 15) /* 1b */
+#define REG_MSDC2_VRF18_ACK_MASK_LSB (1U << 16) /* 1b */
+#define REG_MSDC2_DDR_EN_ACK_MASK_LSB (1U << 17) /* 1b */
+#define REG_PCIE_SRCCLKENA_ACK_MASK_LSB (1U << 18) /* 1b */
+#define REG_PCIE_INFRA_ACK_MASK_LSB (1U << 19) /* 1b */
+#define REG_PCIE_APSRC_ACK_MASK_LSB (1U << 20) /* 1b */
+#define REG_PCIE_VRF18_ACK_MASK_LSB (1U << 21) /* 1b */
+#define REG_PCIE_DDR_EN_ACK_MASK_LSB (1U << 22) /* 1b */
+#define REG_DPMAIF_SRCCLKENA_ACK_MASK_LSB (1U << 23) /* 1b */
+#define REG_DPMAIF_INFRA_ACK_MASK_LSB (1U << 24) /* 1b */
+#define REG_DPMAIF_APSRC_ACK_MASK_LSB (1U << 25) /* 1b */
+#define REG_DPMAIF_VRF18_ACK_MASK_LSB (1U << 26) /* 1b */
+#define REG_DPMAIF_DDR_EN_ACK_MASK_LSB (1U << 27) /* 1b */
+/* PCM_REG0_DATA (0x10006000+0x100) */
+#define PCM_REG0_RF_LSB (1U << 0) /* 32b */
+/* PCM_REG2_DATA (0x10006000+0x104) */
+#define PCM_REG2_RF_LSB (1U << 0) /* 32b */
+/* PCM_REG6_DATA (0x10006000+0x108) */
+#define PCM_REG6_RF_LSB (1U << 0) /* 32b */
+/* PCM_REG7_DATA (0x10006000+0x10C) */
+#define PCM_REG7_RF_LSB (1U << 0) /* 32b */
+/* PCM_REG13_DATA (0x10006000+0x110) */
+#define PCM_REG13_RF_LSB (1U << 0) /* 32b */
+/* SRC_REQ_STA_0 (0x10006000+0x114) */
+#define MD_SRCCLKENA_0_LSB (1U << 0) /* 1b */
+#define MD_SRCCLKENA2INFRA_REQ_0_LSB (1U << 1) /* 1b */
+#define MD_APSRC2INFRA_REQ_0_LSB (1U << 2) /* 1b */
+#define MD_APSRC_REQ_0_LSB (1U << 3) /* 1b */
+#define MD_VRF18_REQ_0_LSB (1U << 4) /* 1b */
+#define MD_DDR_EN_0_LSB (1U << 5) /* 1b */
+#define MD_SRCCLKENA_1_LSB (1U << 6) /* 1b */
+#define MD_SRCCLKENA2INFRA_REQ_1_LSB (1U << 7) /* 1b */
+#define MD_APSRC2INFRA_REQ_1_LSB (1U << 8) /* 1b */
+#define MD_APSRC_REQ_1_LSB (1U << 9) /* 1b */
+#define MD_VRF18_REQ_1_LSB (1U << 10) /* 1b */
+#define MD_DDR_EN_1_LSB (1U << 11) /* 1b */
+#define CONN_SRCCLKENA_LSB (1U << 12) /* 1b */
+#define CONN_SRCCLKENB_LSB (1U << 13) /* 1b */
+#define CONN_INFRA_REQ_LSB (1U << 14) /* 1b */
+#define CONN_APSRC_REQ_LSB (1U << 15) /* 1b */
+#define CONN_VRF18_REQ_LSB (1U << 16) /* 1b */
+#define CONN_DDR_EN_LSB (1U << 17) /* 1b */
+#define SRCCLKENI_LSB (1U << 18) /* 3b */
+#define MD32_SRCCLKENA_LSB (1U << 21) /* 1b */
+#define MD32_INFRA_REQ_LSB (1U << 22) /* 1b */
+#define MD32_APSRC_REQ_LSB (1U << 23) /* 1b */
+#define MD32_VRF18_REQ_LSB (1U << 24) /* 1b */
+#define MD32_DDR_EN_LSB (1U << 25) /* 1b */
+#define DISP0_APSRC_REQ_LSB (1U << 26) /* 1b */
+#define DISP0_DDR_EN_LSB (1U << 27) /* 1b */
+#define DISP1_APSRC_REQ_LSB (1U << 28) /* 1b */
+#define DISP1_DDR_EN_LSB (1U << 29) /* 1b */
+#define DVFSRC_EVENT_TRIGGER_LSB (1U << 30) /* 1b */
+/* SRC_REQ_STA_1 (0x10006000+0x118) */
+#define SCP_SRCCLKENA_LSB (1U << 0) /* 1b */
+#define SCP_INFRA_REQ_LSB (1U << 1) /* 1b */
+#define SCP_APSRC_REQ_LSB (1U << 2) /* 1b */
+#define SCP_VRF18_REQ_LSB (1U << 3) /* 1b */
+#define SCP_DDR_EN_LSB (1U << 4) /* 1b */
+#define AUDIO_DSP_SRCCLKENA_LSB (1U << 5) /* 1b */
+#define AUDIO_DSP_INFRA_REQ_LSB (1U << 6) /* 1b */
+#define AUDIO_DSP_APSRC_REQ_LSB (1U << 7) /* 1b */
+#define AUDIO_DSP_VRF18_REQ_LSB (1U << 8) /* 1b */
+#define AUDIO_DSP_DDR_EN_LSB (1U << 9) /* 1b */
+#define UFS_SRCCLKENA_LSB (1U << 10) /* 1b */
+#define UFS_INFRA_REQ_LSB (1U << 11) /* 1b */
+#define UFS_APSRC_REQ_LSB (1U << 12) /* 1b */
+#define UFS_VRF18_REQ_LSB (1U << 13) /* 1b */
+#define UFS_DDR_EN_LSB (1U << 14) /* 1b */
+#define GCE_INFRA_REQ_LSB (1U << 15) /* 1b */
+#define GCE_APSRC_REQ_LSB (1U << 16) /* 1b */
+#define GCE_VRF18_REQ_LSB (1U << 17) /* 1b */
+#define GCE_DDR_EN_LSB (1U << 18) /* 1b */
+#define INFRASYS_APSRC_REQ_LSB (1U << 19) /* 1b */
+#define INFRASYS_DDR_EN_LSB (1U << 20) /* 1b */
+#define MSDC0_SRCCLKENA_LSB (1U << 21) /* 1b */
+#define MSDC0_INFRA_REQ_LSB (1U << 22) /* 1b */
+#define MSDC0_APSRC_REQ_LSB (1U << 23) /* 1b */
+#define MSDC0_VRF18_REQ_LSB (1U << 24) /* 1b */
+#define MSDC0_DDR_EN_LSB (1U << 25) /* 1b */
+#define MSDC1_SRCCLKENA_LSB (1U << 26) /* 1b */
+#define MSDC1_INFRA_REQ_LSB (1U << 27) /* 1b */
+#define MSDC1_APSRC_REQ_LSB (1U << 28) /* 1b */
+#define MSDC1_VRF18_REQ_LSB (1U << 29) /* 1b */
+#define MSDC1_DDR_EN_LSB (1U << 30) /* 1b */
+/* SRC_REQ_STA_2 (0x10006000+0x11C) */
+#define MCUSYS_MERGE_DDR_EN_LSB (1U << 0) /* 9b */
+#define EMI_SELF_REFRESH_CH_LSB (1U << 9) /* 2b */
+#define SW2SPM_INT_LSB (1U << 11) /* 4b */
+#define SC_ADSP2SPM_WAKEUP_LSB (1U << 15) /* 1b */
+#define SC_SSPM2SPM_WAKEUP_LSB (1U << 16) /* 4b */
+#define SRC_REQ_STA_2_SC_SCP2SPM_WAKEUP_LSB (1U << 20) /* 1b */
+#define SPM_SRCCLKENA_RESERVED_LSB (1U << 21) /* 1b */
+#define SPM_INFRA_REQ_RESERVED_LSB (1U << 22) /* 1b */
+#define SPM_APSRC_REQ_RESERVED_LSB (1U << 23) /* 1b */
+#define SPM_VRF18_REQ_RESERVED_LSB (1U << 24) /* 1b */
+#define SPM_DDR_EN_RESERVED_LSB (1U << 25) /* 1b */
+#define MCUPM_SRCCLKENA_LSB (1U << 26) /* 1b */
+#define MCUPM_INFRA_REQ_LSB (1U << 27) /* 1b */
+#define MCUPM_APSRC_REQ_LSB (1U << 28) /* 1b */
+#define MCUPM_VRF18_REQ_LSB (1U << 29) /* 1b */
+#define MCUPM_DDR_EN_LSB (1U << 30) /* 1b */
+/* PCM_TIMER_OUT (0x10006000+0x120) */
+#define PCM_TIMER_LSB (1U << 0) /* 32b */
+/* PCM_WDT_OUT (0x10006000+0x124) */
+#define PCM_WDT_TIMER_VAL_OUT_LSB (1U << 0) /* 32b */
+/* SPM_IRQ_STA (0x10006000+0x128) */
+#define TWAM_IRQ_LSB (1U << 2) /* 1b */
+#define PCM_IRQ_LSB (1U << 3) /* 1b */
+/* SRC_REQ_STA_4 (0x10006000+0x12C) */
+#define APU_SRCCLKENA_LSB (1U << 0) /* 1b */
+#define APU_INFRA_REQ_LSB (1U << 1) /* 1b */
+#define APU_APSRC_REQ_LSB (1U << 2) /* 1b */
+#define APU_VRF18_REQ_LSB (1U << 3) /* 1b */
+#define APU_DDR_EN_LSB (1U << 4) /* 1b */
+#define BAK_PSRI_SRCCLKENA_LSB (1U << 5) /* 1b */
+#define BAK_PSRI_INFRA_REQ_LSB (1U << 6) /* 1b */
+#define BAK_PSRI_APSRC_REQ_LSB (1U << 7) /* 1b */
+#define BAK_PSRI_VRF18_REQ_LSB (1U << 8) /* 1b */
+#define BAK_PSRI_DDR_EN_LSB (1U << 9) /* 1b */
+#define MSDC2_SRCCLKENA_LSB (1U << 10) /* 1b */
+#define MSDC2_INFRA_REQ_LSB (1U << 11) /* 1b */
+#define MSDC2_APSRC_REQ_LSB (1U << 12) /* 1b */
+#define MSDC2_VRF18_REQ_LSB (1U << 13) /* 1b */
+#define MSDC2_DDR_EN_LSB (1U << 14) /* 1b */
+#define PCIE_SRCCLKENA_LSB (1U << 15) /* 1b */
+#define PCIE_INFRA_REQ_LSB (1U << 16) /* 1b */
+#define PCIE_APSRC_REQ_LSB (1U << 17) /* 1b */
+#define PCIE_VRF18_REQ_LSB (1U << 18) /* 1b */
+#define PCIE_DDR_EN_LSB (1U << 19) /* 1b */
+#define DPMAIF_SRCCLKENA_LSB (1U << 20) /* 1b */
+#define DPMAIF_INFRA_REQ_LSB (1U << 21) /* 1b */
+#define DPMAIF_APSRC_REQ_LSB (1U << 22) /* 1b */
+#define DPMAIF_VRF18_REQ_LSB (1U << 23) /* 1b */
+#define DPMAIF_DDR_EN_LSB (1U << 24) /* 1b */
+/* MD32PCM_WAKEUP_STA (0x10006000+0x130) */
+#define MD32PCM_WAKEUP_STA_LSB (1U << 0) /* 32b */
+/* MD32PCM_EVENT_STA (0x10006000+0x134) */
+#define MD32PCM_EVENT_STA_LSB (1U << 0) /* 32b */
+/* SPM_WAKEUP_STA (0x10006000+0x138) */
+#define F32K_WAKEUP_EVENT_L_LSB (1U << 0) /* 16b */
+#define ASYN_WAKEUP_EVENT_L_LSB (1U << 16) /* 16b */
+/* SPM_WAKEUP_EXT_STA (0x10006000+0x13C) */
+#define EXT_WAKEUP_EVENT_LSB (1U << 0) /* 32b */
+/* SPM_WAKEUP_MISC (0x10006000+0x140) */
+#define GIC_WAKEUP_LSB (1U << 0) /* 10b */
+#define DVFSRC_IRQ_LSB (1U << 16) /* 1b */
+#define SPM_WAKEUP_MISC_REG_CPU_WAKEUP_LSB (1U << 17) /* 1b */
+#define PCM_TIMER_EVENT_LSB (1U << 18) /* 1b */
+#define PMIC_EINT_OUT_B_LSB (1U << 19) /* 2b */
+#define TWAM_IRQ_B_LSB (1U << 21) /* 1b */
+#define PMSR_IRQ_B_SET0_LSB (1U << 22) /* 1b */
+#define PMSR_IRQ_B_SET1_LSB (1U << 23) /* 1b */
+#define PMSR_IRQ_B_SET2_LSB (1U << 24) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_0_LSB (1U << 25) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_1_LSB (1U << 26) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_2_LSB (1U << 27) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_3_LSB (1U << 28) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_ALL_LSB (1U << 29) /* 1b */
+#define PMIC_IRQ_ACK_LSB (1U << 30) /* 1b */
+#define PMIC_SCP_IRQ_LSB (1U << 31) /* 1b */
+/* MM_DVFS_HALT (0x10006000+0x144) */
+#define MM_DVFS_HALT_LSB (1U << 0) /* 5b */
+/* BUS_PROTECT_RDY (0x10006000+0x150) */
+#define PROTECT_READY_LSB (1U << 0) /* 32b */
+/* BUS_PROTECT1_RDY (0x10006000+0x154) */
+#define PROTECT1_READY_LSB (1U << 0) /* 32b */
+/* BUS_PROTECT2_RDY (0x10006000+0x158) */
+#define PROTECT2_READY_LSB (1U << 0) /* 32b */
+/* BUS_PROTECT3_RDY (0x10006000+0x15C) */
+#define PROTECT3_READY_LSB (1U << 0) /* 32b */
+/* SUBSYS_IDLE_STA (0x10006000+0x160) */
+#define SUBSYS_IDLE_SIGNALS_LSB (1U << 0) /* 32b */
+/* PCM_STA (0x10006000+0x164) */
+#define PCM_CK_SEL_O_LSB (1U << 0) /* 4b */
+#define EXT_SRC_STA_LSB (1U << 4) /* 3b */
+/* SRC_REQ_STA_3 (0x10006000+0x168) */
+#define CCIF_EVENT_RAW_STATUS_LSB (1U << 0) /* 16b */
+#define F26M_STATE_LSB (1U << 16) /* 1b */
+#define INFRA_STATE_LSB (1U << 17) /* 1b */
+#define APSRC_STATE_LSB (1U << 18) /* 1b */
+#define VRF18_STATE_LSB (1U << 19) /* 1b */
+#define DDR_EN_STATE_LSB (1U << 20) /* 1b */
+#define DVFS_STATE_LSB (1U << 21) /* 1b */
+#define SW_MAILBOX_STATE_LSB (1U << 22) /* 1b */
+#define SSPM_MAILBOX_STATE_LSB (1U << 23) /* 1b */
+#define ADSP_MAILBOX_STATE_LSB (1U << 24) /* 1b */
+#define SCP_MAILBOX_STATE_LSB (1U << 25) /* 1b */
+/* PWR_STATUS (0x10006000+0x16C) */
+#define PWR_STATUS_LSB (1U << 0) /* 32b */
+/* PWR_STATUS_2ND (0x10006000+0x170) */
+#define PWR_STATUS_2ND_LSB (1U << 0) /* 32b */
+/* CPU_PWR_STATUS (0x10006000+0x174) */
+#define MP0_SPMC_PWR_ON_ACK_CPU0_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU1_LSB (1U << 1) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU2_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU3_LSB (1U << 3) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU4_LSB (1U << 4) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU5_LSB (1U << 5) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU6_LSB (1U << 6) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU7_LSB (1U << 7) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPUTOP_LSB (1U << 8) /* 1b */
+#define MCUSYS_SPMC_PWR_ON_ACK_LSB (1U << 9) /* 1b */
+/* OTHER_PWR_STATUS (0x10006000+0x178) */
+#define OTHER_PWR_STATUS_LSB (1U << 0) /* 32b */
+/* SPM_VTCXO_EVENT_COUNT_STA (0x10006000+0x17C) */
+#define SPM_VTCXO_SLEEP_COUNT_LSB (1U << 0) /* 16b */
+#define SPM_VTCXO_WAKE_COUNT_LSB (1U << 16) /* 16b */
+/* SPM_INFRA_EVENT_COUNT_STA (0x10006000+0x180) */
+#define SPM_INFRA_SLEEP_COUNT_LSB (1U << 0) /* 16b */
+#define SPM_INFRA_WAKE_COUNT_LSB (1U << 16) /* 16b */
+/* SPM_VRF18_EVENT_COUNT_STA (0x10006000+0x184) */
+#define SPM_VRF18_SLEEP_COUNT_LSB (1U << 0) /* 16b */
+#define SPM_VRF18_WAKE_COUNT_LSB (1U << 16) /* 16b */
+/* SPM_APSRC_EVENT_COUNT_STA (0x10006000+0x188) */
+#define SPM_APSRC_SLEEP_COUNT_LSB (1U << 0) /* 16b */
+#define SPM_APSRC_WAKE_COUNT_LSB (1U << 16) /* 16b */
+/* SPM_DDREN_EVENT_COUNT_STA (0x10006000+0x18C) */
+#define SPM_DDREN_SLEEP_COUNT_LSB (1U << 0) /* 16b */
+#define SPM_DDREN_WAKE_COUNT_LSB (1U << 16) /* 16b */
+/* MD32PCM_STA (0x10006000+0x190) */
+#define MD32PCM_HALT_LSB (1U << 0) /* 1b */
+#define MD32PCM_GATED_LSB (1U << 1) /* 1b */
+/* MD32PCM_PC (0x10006000+0x194) */
+#define MON_PC_LSB (1U << 0) /* 32b */
+/* DVFSRC_EVENT_STA (0x10006000+0x1A4) */
+#define DVFSRC_EVENT_LSB (1U << 0) /* 32b */
+/* BUS_PROTECT4_RDY (0x10006000+0x1A8) */
+#define PROTECT4_READY_LSB (1U << 0) /* 32b */
+/* BUS_PROTECT5_RDY (0x10006000+0x1AC) */
+#define PROTECT5_READY_LSB (1U << 0) /* 32b */
+/* BUS_PROTECT6_RDY (0x10006000+0x1B0) */
+#define PROTECT6_READY_LSB (1U << 0) /* 32b */
+/* BUS_PROTECT7_RDY (0x10006000+0x1B4) */
+#define PROTECT7_READY_LSB (1U << 0) /* 32b */
+/* BUS_PROTECT8_RDY (0x10006000+0x1B8) */
+#define PROTECT8_READY_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_LAST_STA0 (0x10006000+0x1D0) */
+#define LAST_IDLE_CNT_0_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_LAST_STA1 (0x10006000+0x1D4) */
+#define LAST_IDLE_CNT_1_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_LAST_STA2 (0x10006000+0x1D8) */
+#define LAST_IDLE_CNT_2_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_LAST_STA3 (0x10006000+0x1DC) */
+#define LAST_IDLE_CNT_3_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_CURR_STA0 (0x10006000+0x1E0) */
+#define CURRENT_IDLE_CNT_0_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_CURR_STA1 (0x10006000+0x1E4) */
+#define CURRENT_IDLE_CNT_1_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_CURR_STA2 (0x10006000+0x1E8) */
+#define CURRENT_IDLE_CNT_2_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_CURR_STA3 (0x10006000+0x1EC) */
+#define CURRENT_IDLE_CNT_3_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_TIMER_OUT (0x10006000+0x1F0) */
+#define TWAM_TIMER_LSB (1U << 0) /* 32b */
+/* SPM_CG_CHECK_STA (0x10006000+0x1F4) */
+#define SPM_CG_CHECK_SLEEP_REQ_0_LSB (1U << 0) /* 1b */
+#define SPM_CG_CHECK_SLEEP_REQ_1_LSB (1U << 1) /* 1b */
+#define SPM_CG_CHECK_SLEEP_REQ_2_LSB (1U << 2) /* 1b */
+/* SPM_DVFS_STA (0x10006000+0x1F8) */
+#define TARGET_DVFS_LEVEL_LSB (1U << 0) /* 32b */
+/* SPM_DVFS_OPP_STA (0x10006000+0x1FC) */
+#define TARGET_DVFS_OPP_LSB (1U << 0) /* 5b */
+#define CURRENT_DVFS_OPP_LSB (1U << 5) /* 5b */
+#define RELAY_DVFS_OPP_LSB (1U << 10) /* 5b */
+/* SPM_MCUSYS_PWR_CON (0x10006000+0x200) */
+#define MCUSYS_SPMC_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MCUSYS_SPMC_PWR_ON_LSB (1U << 2) /* 1b */
+#define MCUSYS_SPMC_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MCUSYS_SPMC_RESETPWRON_CONFIG_LSB (1U << 5) /* 1b */
+#define MCUSYS_SPMC_DORMANT_EN_LSB (1U << 6) /* 1b */
+#define MCUSYS_VPROC_EXT_OFF_LSB (1U << 7) /* 1b */
+#define SPM_MCUSYS_PWR_CON_MCUSYS_SPMC_PWR_ON_ACK_LSB (1U << 31) /* 1b */
+/* SPM_CPUTOP_PWR_CON (0x10006000+0x204) */
+#define MP0_SPMC_PWR_RST_B_CPUTOP_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPUTOP_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_PWR_CLK_DIS_CPUTOP_LSB (1U << 4) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPUTOP_LSB (1U << 5) /* 1b */
+#define MP0_SPMC_DORMANT_EN_CPUTOP_LSB (1U << 6) /* 1b */
+#define MP0_VPROC_EXT_OFF_LSB (1U << 7) /* 1b */
+#define MP0_VSRAM_EXT_OFF_LSB (1U << 8) /* 1b */
+#define SPM_CPUTOP_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPUTOP_LSB (1U << 31) /* 1b */
+/* SPM_CPU0_PWR_CON (0x10006000+0x208) */
+#define MP0_SPMC_PWR_RST_B_CPU0_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU0_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU0_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU0_LSB (1U << 7) /* 1b */
+#define SPM_CPU0_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU0_LSB (1U << 31) /* 1b */
+/* SPM_CPU1_PWR_CON (0x10006000+0x20C) */
+#define MP0_SPMC_PWR_RST_B_CPU1_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU1_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU1_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU1_LSB (1U << 7) /* 1b */
+#define SPM_CPU1_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU1_LSB (1U << 31) /* 1b */
+/* SPM_CPU2_PWR_CON (0x10006000+0x210) */
+#define MP0_SPMC_PWR_RST_B_CPU2_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU2_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU2_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU2_LSB (1U << 7) /* 1b */
+#define SPM_CPU2_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU2_LSB (1U << 31) /* 1b */
+/* SPM_CPU3_PWR_CON (0x10006000+0x214) */
+#define MP0_SPMC_PWR_RST_B_CPU3_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU3_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU3_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU3_LSB (1U << 7) /* 1b */
+#define SPM_CPU3_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU3_LSB (1U << 31) /* 1b */
+/* SPM_CPU4_PWR_CON (0x10006000+0x218) */
+#define MP0_SPMC_PWR_RST_B_CPU4_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU4_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU4_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU4_LSB (1U << 7) /* 1b */
+#define SPM_CPU4_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU4_LSB (1U << 31) /* 1b */
+/* SPM_CPU5_PWR_CON (0x10006000+0x21C) */
+#define MP0_SPMC_PWR_RST_B_CPU5_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU5_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU5_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU5_LSB (1U << 7) /* 1b */
+#define SPM_CPU5_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU5_LSB (1U << 31) /* 1b */
+/* SPM_CPU6_PWR_CON (0x10006000+0x220) */
+#define MP0_SPMC_PWR_RST_B_CPU6_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU6_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU6_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU6_LSB (1U << 7) /* 1b */
+#define SPM_CPU6_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU6_LSB (1U << 31) /* 1b */
+/* SPM_CPU7_PWR_CON (0x10006000+0x224) */
+#define MP0_SPMC_PWR_RST_B_CPU7_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU7_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU7_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU7_LSB (1U << 7) /* 1b */
+#define SPM_CPU7_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU7_LSB (1U << 31) /* 1b */
+/* ARMPLL_CLK_CON (0x10006000+0x22C) */
+#define SC_ARM_FHC_PAUSE_LSB (1U << 0) /* 6b */
+#define SC_ARM_CK_OFF_LSB (1U << 6) /* 6b */
+#define SC_ARMPLL_OFF_LSB (1U << 12) /* 1b */
+#define SC_ARMBPLL_OFF_LSB (1U << 13) /* 1b */
+#define SC_ARMBPLL1_OFF_LSB (1U << 14) /* 1b */
+#define SC_ARMBPLL2_OFF_LSB (1U << 15) /* 1b */
+#define SC_ARMBPLL3_OFF_LSB (1U << 16) /* 1b */
+#define SC_CCIPLL_CKOFF_LSB (1U << 17) /* 1b */
+#define SC_ARMDDS_OFF_LSB (1U << 18) /* 1b */
+#define SC_ARMBPLL_S_OFF_LSB (1U << 19) /* 1b */
+#define SC_ARMBPLL1_S_OFF_LSB (1U << 20) /* 1b */
+#define SC_ARMBPLL2_S_OFF_LSB (1U << 21) /* 1b */
+#define SC_ARMBPLL3_S_OFF_LSB (1U << 22) /* 1b */
+#define SC_CCIPLL_PWROFF_LSB (1U << 23) /* 1b */
+#define SC_ARMPLLOUT_OFF_LSB (1U << 24) /* 1b */
+#define SC_ARMBPLLOUT_OFF_LSB (1U << 25) /* 1b */
+#define SC_ARMBPLLOUT1_OFF_LSB (1U << 26) /* 1b */
+#define SC_ARMBPLLOUT2_OFF_LSB (1U << 27) /* 1b */
+#define SC_ARMBPLLOUT3_OFF_LSB (1U << 28) /* 1b */
+#define SC_CCIPLL_OUT_OFF_LSB (1U << 29) /* 1b */
+/* MCUSYS_IDLE_STA (0x10006000+0x230) */
+#define ARMBUS_IDLE_TO_26M_LSB (1U << 0) /* 1b */
+#define MP0_CLUSTER_IDLE_TO_PWR_OFF_LSB (1U << 1) /* 1b */
+#define MCUSYS_DDR_EN_0_LSB (1U << 2) /* 1b */
+#define MCUSYS_DDR_EN_1_LSB (1U << 3) /* 1b */
+#define MCUSYS_DDR_EN_2_LSB (1U << 4) /* 1b */
+#define MCUSYS_DDR_EN_3_LSB (1U << 5) /* 1b */
+#define MCUSYS_DDR_EN_4_LSB (1U << 6) /* 1b */
+#define MCUSYS_DDR_EN_5_LSB (1U << 7) /* 1b */
+#define MCUSYS_DDR_EN_6_LSB (1U << 8) /* 1b */
+#define MCUSYS_DDR_EN_7_LSB (1U << 9) /* 1b */
+#define MP0_CPU_IDLE_TO_PWR_OFF_LSB (1U << 16) /* 8b */
+#define WFI_AF_SEL_LSB (1U << 24) /* 8b */
+/* GIC_WAKEUP_STA (0x10006000+0x234) */
+#define GIC_WAKEUP_STA_GIC_WAKEUP_LSB (1U << 10) /* 10b */
+/* CPU_SPARE_CON (0x10006000+0x238) */
+#define CPU_SPARE_CON_LSB (1U << 0) /* 32b */
+/* CPU_SPARE_CON_SET (0x10006000+0x23C) */
+#define CPU_SPARE_CON_SET_LSB (1U << 0) /* 32b */
+/* CPU_SPARE_CON_CLR (0x10006000+0x240) */
+#define CPU_SPARE_CON_CLR_LSB (1U << 0) /* 32b */
+/* ARMPLL_CLK_SEL (0x10006000+0x244) */
+#define ARMPLL_CLK_SEL_LSB (1U << 0) /* 15b */
+/* EXT_INT_WAKEUP_REQ (0x10006000+0x248) */
+#define EXT_INT_WAKEUP_REQ_LSB (1U << 0) /* 10b */
+/* EXT_INT_WAKEUP_REQ_SET (0x10006000+0x24C) */
+#define EXT_INT_WAKEUP_REQ_SET_LSB (1U << 0) /* 10b */
+/* EXT_INT_WAKEUP_REQ_CLR (0x10006000+0x250) */
+#define EXT_INT_WAKEUP_REQ_CLR_LSB (1U << 0) /* 10b */
+/* MP0_CPU0_IRQ_MASK (0x10006000+0x260) */
+#define MP0_CPU0_IRQ_MASK_LSB (1U << 0) /* 1b */
+#define MP0_CPU0_AUX_LSB (1U << 8) /* 11b */
+/* MP0_CPU1_IRQ_MASK (0x10006000+0x264) */
+#define MP0_CPU1_IRQ_MASK_LSB (1U << 0) /* 1b */
+#define MP0_CPU1_AUX_LSB (1U << 8) /* 11b */
+/* MP0_CPU2_IRQ_MASK (0x10006000+0x268) */
+#define MP0_CPU2_IRQ_MASK_LSB (1U << 0) /* 1b */
+#define MP0_CPU2_AUX_LSB (1U << 8) /* 11b */
+/* MP0_CPU3_IRQ_MASK (0x10006000+0x26C) */
+#define MP0_CPU3_IRQ_MASK_LSB (1U << 0) /* 1b */
+#define MP0_CPU3_AUX_LSB (1U << 8) /* 11b */
+/* MP1_CPU0_IRQ_MASK (0x10006000+0x270) */
+#define MP1_CPU0_IRQ_MASK_LSB (1U << 0) /* 1b */
+#define MP1_CPU0_AUX_LSB (1U << 8) /* 11b */
+/* MP1_CPU1_IRQ_MASK (0x10006000+0x274) */
+#define MP1_CPU1_IRQ_MASK_LSB (1U << 0) /* 1b */
+#define MP1_CPU1_AUX_LSB (1U << 8) /* 11b */
+/* MP1_CPU2_IRQ_MASK (0x10006000+0x278) */
+#define MP1_CPU2_IRQ_MASK_LSB (1U << 0) /* 1b */
+#define MP1_CPU2_AUX_LSB (1U << 8) /* 11b */
+/* MP1_CPU3_IRQ_MASK (0x10006000+0x27C) */
+#define MP1_CPU3_IRQ_MASK_LSB (1U << 0) /* 1b */
+#define MP1_CPU3_AUX_LSB (1U << 8) /* 11b */
+/* MP0_CPU0_WFI_EN (0x10006000+0x280) */
+#define MP0_CPU0_WFI_EN_LSB (1U << 0) /* 1b */
+/* MP0_CPU1_WFI_EN (0x10006000+0x284) */
+#define MP0_CPU1_WFI_EN_LSB (1U << 0) /* 1b */
+/* MP0_CPU2_WFI_EN (0x10006000+0x288) */
+#define MP0_CPU2_WFI_EN_LSB (1U << 0) /* 1b */
+/* MP0_CPU3_WFI_EN (0x10006000+0x28C) */
+#define MP0_CPU3_WFI_EN_LSB (1U << 0) /* 1b */
+/* MP0_CPU4_WFI_EN (0x10006000+0x290) */
+#define MP0_CPU4_WFI_EN_LSB (1U << 0) /* 1b */
+/* MP0_CPU5_WFI_EN (0x10006000+0x294) */
+#define MP0_CPU5_WFI_EN_LSB (1U << 0) /* 1b */
+/* MP0_CPU6_WFI_EN (0x10006000+0x298) */
+#define MP0_CPU6_WFI_EN_LSB (1U << 0) /* 1b */
+/* MP0_CPU7_WFI_EN (0x10006000+0x29C) */
+#define MP0_CPU7_WFI_EN_LSB (1U << 0) /* 1b */
+/* ROOT_CPUTOP_ADDR (0x10006000+0x2A0) */
+#define ROOT_CPUTOP_ADDR_LSB (1U << 0) /* 32b */
+/* ROOT_CORE_ADDR (0x10006000+0x2A4) */
+#define ROOT_CORE_ADDR_LSB (1U << 0) /* 32b */
+/* SPM2SW_MAILBOX_0 (0x10006000+0x2D0) */
+#define SPM2SW_MAILBOX_0_LSB (1U << 0) /* 32b */
+/* SPM2SW_MAILBOX_1 (0x10006000+0x2D4) */
+#define SPM2SW_MAILBOX_1_LSB (1U << 0) /* 32b */
+/* SPM2SW_MAILBOX_2 (0x10006000+0x2D8) */
+#define SPM2SW_MAILBOX_2_LSB (1U << 0) /* 32b */
+/* SPM2SW_MAILBOX_3 (0x10006000+0x2DC) */
+#define SPM2SW_MAILBOX_3_LSB (1U << 0) /* 32b */
+/* SW2SPM_INT (0x10006000+0x2E0) */
+#define SW2SPM_INT_SW2SPM_INT_LSB (1U << 0) /* 4b */
+/* SW2SPM_INT_SET (0x10006000+0x2E4) */
+#define SW2SPM_INT_SET_LSB (1U << 0) /* 4b */
+/* SW2SPM_INT_CLR (0x10006000+0x2E8) */
+#define SW2SPM_INT_CLR_LSB (1U << 0) /* 4b */
+/* SW2SPM_MAILBOX_0 (0x10006000+0x2EC) */
+#define SW2SPM_MAILBOX_0_LSB (1U << 0) /* 32b */
+/* SW2SPM_MAILBOX_1 (0x10006000+0x2F0) */
+#define SW2SPM_MAILBOX_1_LSB (1U << 0) /* 32b */
+/* SW2SPM_MAILBOX_2 (0x10006000+0x2F4) */
+#define SW2SPM_MAILBOX_2_LSB (1U << 0) /* 32b */
+/* SW2SPM_MAILBOX_3 (0x10006000+0x2F8) */
+#define SW2SPM_MAILBOX_3_LSB (1U << 0) /* 32b */
+/* SW2SPM_CFG (0x10006000+0x2FC) */
+#define SWU2SPM_INT_MASK_B_LSB (1U << 0) /* 4b */
+/* MD1_PWR_CON (0x10006000+0x300) */
+#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 */
+#define SC_MD1_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* CONN_PWR_CON (0x10006000+0x304) */
+#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 */
+/* MFG0_PWR_CON (0x10006000+0x308) */
+#define MFG0_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG0_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG0_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG0_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG0_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG0_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG0_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* MFG1_PWR_CON (0x10006000+0x30C) */
+#define MFG1_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG1_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG1_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG1_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG1_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG1_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG1_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* MFG2_PWR_CON (0x10006000+0x310) */
+#define MFG2_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG2_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG2_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG2_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG2_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG2_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG2_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* MFG3_PWR_CON (0x10006000+0x314) */
+#define MFG3_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG3_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG3_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG3_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG3_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG3_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG3_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* MFG4_PWR_CON (0x10006000+0x318) */
+#define MFG4_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG4_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG4_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG4_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG4_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG4_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG4_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* MFG5_PWR_CON (0x10006000+0x31C) */
+#define MFG5_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG5_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG5_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG5_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG5_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG5_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG5_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* MFG6_PWR_CON (0x10006000+0x320) */
+#define MFG6_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG6_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG6_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG6_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG6_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG6_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG6_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* IFR_PWR_CON (0x10006000+0x324) */
+#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) /* 1b */
+#define SC_IFR_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* IFR_SUB_PWR_CON (0x10006000+0x328) */
+#define IFR_SUB_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define IFR_SUB_PWR_ISO_LSB (1U << 1) /* 1b */
+#define IFR_SUB_PWR_ON_LSB (1U << 2) /* 1b */
+#define IFR_SUB_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define IFR_SUB_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define IFR_SUB_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_IFR_SUB_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* DPY_PWR_CON (0x10006000+0x32C) */
+#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) /* 1b */
+#define SC_DPY_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* ISP_PWR_CON (0x10006000+0x330) */
+#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) /* 1b */
+#define SC_ISP_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* ISP2_PWR_CON (0x10006000+0x334) */
+#define ISP2_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define ISP2_PWR_ISO_LSB (1U << 1) /* 1b */
+#define ISP2_PWR_ON_LSB (1U << 2) /* 1b */
+#define ISP2_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define ISP2_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define ISP2_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_ISP2_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* IPE_PWR_CON (0x10006000+0x338) */
+#define IPE_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define IPE_PWR_ISO_LSB (1U << 1) /* 1b */
+#define IPE_PWR_ON_LSB (1U << 2) /* 1b */
+#define IPE_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define IPE_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define IPE_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_IPE_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* VDE_PWR_CON (0x10006000+0x33C) */
+#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) /* 1b */
+#define SC_VDE_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* VDE2_PWR_CON (0x10006000+0x340) */
+#define VDE2_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define VDE2_PWR_ISO_LSB (1U << 1) /* 1b */
+#define VDE2_PWR_ON_LSB (1U << 2) /* 1b */
+#define VDE2_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define VDE2_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define VDE2_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_VDE2_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* VEN_PWR_CON (0x10006000+0x344) */
+#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) /* 1b */
+#define SC_VEN_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* VEN_CORE1_PWR_CON (0x10006000+0x348) */
+#define VEN_CORE1_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define VEN_CORE1_PWR_ISO_LSB (1U << 1) /* 1b */
+#define VEN_CORE1_PWR_ON_LSB (1U << 2) /* 1b */
+#define VEN_CORE1_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define VEN_CORE1_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define VEN_CORE1_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_VEN_CORE1_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* MDP_PWR_CON (0x10006000+0x34C) */
+#define MDP_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MDP_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MDP_PWR_ON_LSB (1U << 2) /* 1b */
+#define MDP_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MDP_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MDP_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MDP_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* DIS_PWR_CON (0x10006000+0x350) */
+#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) /* 1b */
+#define SC_DIS_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* AUDIO_PWR_CON (0x10006000+0x354) */
+#define AUDIO_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define AUDIO_PWR_ISO_LSB (1U << 1) /* 1b */
+#define AUDIO_PWR_ON_LSB (1U << 2) /* 1b */
+#define AUDIO_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define AUDIO_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define AUDIO_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_AUDIO_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* ADSP_PWR_CON (0x10006000+0x358) */
+#define ADSP_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define ADSP_PWR_ISO_LSB (1U << 1) /* 1b */
+#define ADSP_PWR_ON_LSB (1U << 2) /* 1b */
+#define ADSP_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define ADSP_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define ADSP_SRAM_CKISO_LSB (1U << 5) /* 1b */
+#define ADSP_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */
+#define ADSP_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define ADSP_SRAM_SLEEP_B_LSB (1U << 9) /* 1b */
+#define SC_ADSP_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+#define SC_ADSP_SRAM_SLEEP_B_ACK_LSB (1U << 13) /* 1b */
+/* CAM_PWR_CON (0x10006000+0x35C) */
+#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) /* 1b */
+#define SC_CAM_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* CAM_RAWA_PWR_CON (0x10006000+0x360) */
+#define CAM_RAWA_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define CAM_RAWA_PWR_ISO_LSB (1U << 1) /* 1b */
+#define CAM_RAWA_PWR_ON_LSB (1U << 2) /* 1b */
+#define CAM_RAWA_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define CAM_RAWA_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define CAM_RAWA_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_CAM_RAWA_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* CAM_RAWB_PWR_CON (0x10006000+0x364) */
+#define CAM_RAWB_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define CAM_RAWB_PWR_ISO_LSB (1U << 1) /* 1b */
+#define CAM_RAWB_PWR_ON_LSB (1U << 2) /* 1b */
+#define CAM_RAWB_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define CAM_RAWB_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define CAM_RAWB_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_CAM_RAWB_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* CAM_RAWC_PWR_CON (0x10006000+0x368) */
+#define CAM_RAWC_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define CAM_RAWC_PWR_ISO_LSB (1U << 1) /* 1b */
+#define CAM_RAWC_PWR_ON_LSB (1U << 2) /* 1b */
+#define CAM_RAWC_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define CAM_RAWC_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define CAM_RAWC_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_CAM_RAWC_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* SYSRAM_CON (0x10006000+0x36C) */
+#define SYSRAM_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define SYSRAM_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define SYSRAM_SRAM_SLEEP_B_LSB (1U << 4) /* 4b */
+#define SYSRAM_SRAM_PDN_LSB (1U << 16) /* 4b */
+/* SYSROM_CON (0x10006000+0x370) */
+#define SYSROM_SRAM_PDN_LSB (1U << 0) /* 6b */
+/* SSPM_SRAM_CON (0x10006000+0x374) */
+#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+0x378) */
+#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 */
+/* DPY_SHU_SRAM_CON (0x10006000+0x37C) */
+#define DPY_SHU_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DPY_SHU_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DPY_SHU_SRAM_SLEEP_B_LSB (1U << 4) /* 2b */
+#define DPY_SHU_SRAM_PDN_LSB (1U << 16) /* 2b */
+/* UFS_SRAM_CON (0x10006000+0x380) */
+#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 */
+/* DEVAPC_IFR_SRAM_CON (0x10006000+0x384) */
+#define DEVAPC_IFR_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DEVAPC_IFR_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DEVAPC_IFR_SRAM_SLEEP_B_LSB (1U << 4) /* 6b */
+#define DEVAPC_IFR_SRAM_PDN_LSB (1U << 16) /* 6b */
+/* DEVAPC_SUBIFR_SRAM_CON (0x10006000+0x388) */
+#define DEVAPC_SUBIFR_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DEVAPC_SUBIFR_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DEVAPC_SUBIFR_SRAM_SLEEP_B_LSB (1U << 4) /* 6b */
+#define DEVAPC_SUBIFR_SRAM_PDN_LSB (1U << 16) /* 6b */
+/* DEVAPC_ACP_SRAM_CON (0x10006000+0x38C) */
+#define DEVAPC_ACP_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DEVAPC_ACP_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DEVAPC_ACP_SRAM_SLEEP_B_LSB (1U << 4) /* 6b */
+#define DEVAPC_ACP_SRAM_PDN_LSB (1U << 16) /* 6b */
+/* USB_SRAM_CON (0x10006000+0x390) */
+#define USB_SRAM_PDN_LSB (1U << 0) /* 7b */
+/* DUMMY_SRAM_CON (0x10006000+0x394) */
+#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+0x398) */
+#define VMODEM_EXT_BUCK_ISO_LSB (1U << 0) /* 1b */
+#define VMD_EXT_BUCK_ISO_LSB (1U << 1) /* 1b */
+/* EXT_BUCK_ISO (0x10006000+0x39C) */
+#define VIMVO_EXT_BUCK_ISO_LSB (1U << 0) /* 1b */
+#define GPU_EXT_BUCK_ISO_LSB (1U << 1) /* 1b */
+#define ADSP_EXT_BUCK_ISO_LSB (1U << 2) /* 1b */
+#define IPU_EXT_BUCK_ISO_LSB (1U << 5) /* 3b */
+/* DXCC_SRAM_CON (0x10006000+0x3A0) */
+#define DXCC_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DXCC_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DXCC_SRAM_SLEEP_B_LSB (1U << 4) /* 1b */
+#define DXCC_SRAM_PDN_LSB (1U << 16) /* 1b */
+/* MSDC_SRAM_CON (0x10006000+0x3A4) */
+#define MSDC_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MSDC_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MSDC_PWR_ON_LSB (1U << 2) /* 1b */
+#define MSDC_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MSDC_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MSDC_SRAM_CKISO_LSB (1U << 5) /* 1b */
+#define MSDC_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */
+#define MSDC_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define MSDC_SRAM_SLEEP_B_LSB (1U << 9) /* 1b */
+#define SC_MSDC_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+#define SC_MSDC_SRAM_SLEEP_B_ACK_LSB (1U << 13) /* 1b */
+/* DEBUGTOP_SRAM_CON (0x10006000+0x3A8) */
+#define DEBUGTOP_SRAM_PDN_LSB (1U << 0) /* 1b */
+/* DP_TX_PWR_CON (0x10006000+0x3AC) */
+#define DP_TX_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define DP_TX_PWR_ISO_LSB (1U << 1) /* 1b */
+#define DP_TX_PWR_ON_LSB (1U << 2) /* 1b */
+#define DP_TX_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define DP_TX_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define DP_TX_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_DP_TX_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* DPMAIF_SRAM_CON (0x10006000+0x3B0) */
+#define DPMAIF_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DPMAIF_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DPMAIF_SRAM_SLEEP_B_LSB (1U << 4) /* 1b */
+#define DPMAIF_SRAM_PDN_LSB (1U << 16) /* 1b */
+/* DPY_SHU2_SRAM_CON (0x10006000+0x3B4) */
+#define DPY_SHU2_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DPY_SHU2_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DPY_SHU2_SRAM_SLEEP_B_LSB (1U << 4) /* 2b */
+#define DPY_SHU2_SRAM_PDN_LSB (1U << 16) /* 2b */
+/* DRAMC_MCU2_SRAM_CON (0x10006000+0x3B8) */
+#define DRAMC_MCU2_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DRAMC_MCU2_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DRAMC_MCU2_SRAM_SLEEP_B_LSB (1U << 4) /* 1b */
+#define DRAMC_MCU2_SRAM_PDN_LSB (1U << 16) /* 1b */
+/* DRAMC_MCU_SRAM_CON (0x10006000+0x3BC) */
+#define DRAMC_MCU_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DRAMC_MCU_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DRAMC_MCU_SRAM_SLEEP_B_LSB (1U << 4) /* 1b */
+#define DRAMC_MCU_SRAM_PDN_LSB (1U << 16) /* 1b */
+/* MCUPM_SRAM_CON (0x10006000+0x3C0) */
+#define MCUPM_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MCUPM_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MCUPM_PWR_ON_LSB (1U << 2) /* 1b */
+#define MCUPM_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MCUPM_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MCUPM_SRAM_CKISO_LSB (1U << 5) /* 1b */
+#define MCUPM_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */
+#define MCUPM_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define MCUPM_SRAM_SLEEP_B_LSB (1U << 9) /* 1b */
+#define SC_MCUPM_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+#define SC_MCUPM_SRAM_SLEEP_B_ACK_LSB (1U << 13) /* 1b */
+/* DPY2_PWR_CON (0x10006000+0x3C4) */
+#define DPY2_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define DPY2_PWR_ISO_LSB (1U << 1) /* 1b */
+#define DPY2_PWR_ON_LSB (1U << 2) /* 1b */
+#define DPY2_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define DPY2_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define DPY2_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_DPY2_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* PERI_PWR_CON (0x10006000+0x3C8) */
+#define PERI_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define PERI_PWR_ISO_LSB (1U << 1) /* 1b */
+#define PERI_PWR_ON_LSB (1U << 2) /* 1b */
+#define PERI_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define PERI_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define PERI_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_PERI_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* SPM_MEM_CK_SEL (0x10006000+0x400) */
+#define SC_MEM_CK_SEL_LSB (1U << 0) /* 1b */
+#define SPM2CKSYS_MEM_CK_MUX_UPDATE_LSB (1U << 1) /* 1b */
+/* SPM_BUS_PROTECT_MASK_B (0x10006000+0X404) */
+#define SPM_BUS_PROTECT_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_BUS_PROTECT1_MASK_B (0x10006000+0x408) */
+#define SPM_BUS_PROTECT1_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_BUS_PROTECT2_MASK_B (0x10006000+0x40C) */
+#define SPM_BUS_PROTECT2_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_BUS_PROTECT3_MASK_B (0x10006000+0x410) */
+#define SPM_BUS_PROTECT3_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_BUS_PROTECT4_MASK_B (0x10006000+0x414) */
+#define SPM_BUS_PROTECT4_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_EMI_BW_MODE (0x10006000+0x418) */
+#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+0x41C) */
+#define AP2MD_PEER_WAKEUP_LSB (1U << 0) /* 1b */
+/* ULPOSC_CON (0x10006000+0x420) */
+#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+0x424) */
+#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_D2T_LSB (1U << 16) /* 1b */
+#define MM2SPM_DBL_OSTD_ACT_ACK_D2T_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 */
+/* SPM_BUS_PROTECT5_MASK_B (0x10006000+0x428) */
+#define SPM_BUS_PROTECT5_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM2MCUPM_CON (0x10006000+0x42C) */
+#define SPM2MCUPM_SW_RST_B_LSB (1U << 0) /* 1b */
+#define SPM2MCUPM_SW_INT_LSB (1U << 1) /* 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 */
+/* SPM2EMI_ENTER_ULPM (0x10006000+0x434) */
+#define SPM2EMI_ENTER_ULPM_LSB (1U << 0) /* 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 */
+/* SPM_BUS_PROTECT6_MASK_B (0x10006000+0X440) */
+#define SPM_BUS_PROTECT6_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_BUS_PROTECT7_MASK_B (0x10006000+0x444) */
+#define SPM_BUS_PROTECT7_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_BUS_PROTECT8_MASK_B (0x10006000+0x448) */
+#define SPM_BUS_PROTECT8_MASK_B_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_MD32K_CK_OFF_LSB (1U << 17) /* 1b */
+#define SC_CKSQ1_OFF_LSB (1U << 18) /* 1b */
+#define SC_AXI_MEM_CK_OFF_LSB (1U << 19) /* 1b */
+/* CPU_DVFS_REQ (0x10006000+0x450) */
+#define CPU_DVFS_REQ_LSB (1U << 0) /* 32b */
+/* SPM_DRAM_MCU_SW_CON_0 (0x10006000+0x454) */
+#define SW_DDR_PST_REQ_LSB (1U << 0) /* 2b */
+#define SW_DDR_PST_ABORT_REQ_LSB (1U << 2) /* 2b */
+/* SPM_DRAM_MCU_SW_CON_1 (0x10006000+0x458) */
+#define SW_DDR_PST_CH0_LSB (1U << 0) /* 32b */
+/* SPM_DRAM_MCU_SW_CON_2 (0x10006000+0x45C) */
+#define SW_DDR_PST_CH1_LSB (1U << 0) /* 32b */
+/* SPM_DRAM_MCU_SW_CON_3 (0x10006000+0x460) */
+#define SW_DDR_RESERVED_CH0_LSB (1U << 0) /* 32b */
+/* SPM_DRAM_MCU_SW_CON_4 (0x10006000+0x464) */
+#define SW_DDR_RESERVED_CH1_LSB (1U << 0) /* 32b */
+/* SPM_DRAM_MCU_STA_0 (0x10006000+0x468) */
+#define SC_DDR_PST_ACK_LSB (1U << 0) /* 2b */
+#define SC_DDR_PST_ABORT_ACK_LSB (1U << 2) /* 2b */
+/* SPM_DRAM_MCU_STA_1 (0x10006000+0x46C) */
+#define SC_DDR_CUR_PST_STA_CH0_LSB (1U << 0) /* 32b */
+/* SPM_DRAM_MCU_STA_2 (0x10006000+0x470) */
+#define SC_DDR_CUR_PST_STA_CH1_LSB (1U << 0) /* 32b */
+/* SPM_DRAM_MCU_SW_SEL_0 (0x10006000+0x474) */
+#define SW_DDR_PST_REQ_SEL_LSB (1U << 0) /* 2b */
+#define SW_DDR_PST_SEL_LSB (1U << 2) /* 2b */
+#define SW_DDR_PST_ABORT_REQ_SEL_LSB (1U << 4) /* 2b */
+#define SW_DDR_RESERVED_SEL_LSB (1U << 6) /* 2b */
+#define SW_DDR_PST_ACK_SEL_LSB (1U << 8) /* 2b */
+#define SW_DDR_PST_ABORT_ACK_SEL_LSB (1U << 10) /* 2b */
+/* RELAY_DVFS_LEVEL (0x10006000+0x478) */
+#define RELAY_DVFS_LEVEL_LSB (1U << 0) /* 32b */
+/* DRAMC_DPY_CLK_SW_CON_0 (0x10006000+0x480) */
+#define SW_PHYPLL_EN_LSB (1U << 0) /* 2b */
+#define SW_DPY_VREF_EN_LSB (1U << 2) /* 2b */
+#define SW_DPY_DLL_CK_EN_LSB (1U << 4) /* 2b */
+#define SW_DPY_DLL_EN_LSB (1U << 6) /* 2b */
+#define SW_DPY_2ND_DLL_EN_LSB (1U << 8) /* 2b */
+#define SW_MEM_CK_OFF_LSB (1U << 10) /* 2b */
+#define SW_DMSUS_OFF_LSB (1U << 12) /* 2b */
+#define SW_DPY_MODE_SW_LSB (1U << 14) /* 2b */
+#define SW_EMI_CLK_OFF_LSB (1U << 16) /* 2b */
+#define SW_DDRPHY_FB_CK_EN_LSB (1U << 18) /* 2b */
+#define SW_DR_GATE_RETRY_EN_LSB (1U << 20) /* 2b */
+#define SW_DPHY_PRECAL_UP_LSB (1U << 24) /* 2b */
+#define SW_DPY_BCLK_ENABLE_LSB (1U << 26) /* 2b */
+#define SW_TX_TRACKING_DIS_LSB (1U << 28) /* 2b */
+#define SW_DPHY_RXDLY_TRACKING_EN_LSB (1U << 30) /* 2b */
+/* DRAMC_DPY_CLK_SW_CON_1 (0x10006000+0x484) */
+#define SW_SHU_RESTORE_LSB (1U << 0) /* 2b */
+#define SW_DMYRD_MOD_LSB (1U << 2) /* 2b */
+#define SW_DMYRD_INTV_LSB (1U << 4) /* 2b */
+#define SW_DMYRD_EN_LSB (1U << 6) /* 2b */
+#define SW_DRS_DIS_REQ_LSB (1U << 8) /* 2b */
+#define SW_DR_SRAM_LOAD_LSB (1U << 10) /* 2b */
+#define SW_DR_SRAM_RESTORE_LSB (1U << 12) /* 2b */
+#define SW_DR_SHU_LEVEL_SRAM_LATCH_LSB (1U << 14) /* 2b */
+#define SW_TX_TRACK_RETRY_EN_LSB (1U << 16) /* 2b */
+#define SW_DPY_MIDPI_EN_LSB (1U << 18) /* 2b */
+#define SW_DPY_PI_RESETB_EN_LSB (1U << 20) /* 2b */
+#define SW_DPY_MCK8X_EN_LSB (1U << 22) /* 2b */
+#define SW_DR_SHU_LEVEL_SRAM_CH0_LSB (1U << 24) /* 4b */
+#define SW_DR_SHU_LEVEL_SRAM_CH1_LSB (1U << 28) /* 4b */
+/* DRAMC_DPY_CLK_SW_CON_2 (0x10006000+0x488) */
+#define SW_DR_SHU_LEVEL_LSB (1U << 0) /* 2b */
+#define SW_DR_SHU_EN_LSB (1U << 2) /* 1b */
+#define SW_DR_SHORT_QUEUE_LSB (1U << 3) /* 1b */
+#define SW_PHYPLL_MODE_SW_LSB (1U << 4) /* 1b */
+#define SW_PHYPLL2_MODE_SW_LSB (1U << 5) /* 1b */
+#define SW_PHYPLL_SHU_EN_LSB (1U << 6) /* 1b */
+#define SW_PHYPLL2_SHU_EN_LSB (1U << 7) /* 1b */
+#define SW_DR_RESERVED_0_LSB (1U << 24) /* 2b */
+#define SW_DR_RESERVED_1_LSB (1U << 26) /* 2b */
+#define SW_DR_RESERVED_2_LSB (1U << 28) /* 2b */
+#define SW_DR_RESERVED_3_LSB (1U << 30) /* 2b */
+/* DRAMC_DPY_CLK_SW_CON_3 (0x10006000+0x48C) */
+#define SC_DR_SHU_EN_ACK_LSB (1U << 0) /* 4b */
+#define SC_EMI_CLK_OFF_ACK_LSB (1U << 4) /* 4b */
+#define SC_DR_SHORT_QUEUE_ACK_LSB (1U << 8) /* 4b */
+#define SC_DRAMC_DFS_STA_LSB (1U << 12) /* 4b */
+#define SC_DRS_DIS_ACK_LSB (1U << 16) /* 4b */
+#define SC_DR_SRAM_LOAD_ACK_LSB (1U << 20) /* 4b */
+#define SC_DR_SRAM_PLL_LOAD_ACK_LSB (1U << 24) /* 4b */
+#define SC_DR_SRAM_RESTORE_ACK_LSB (1U << 28) /* 4b */
+/* DRAMC_DPY_CLK_SW_SEL_0 (0x10006000+0x490) */
+#define SW_PHYPLL_EN_SEL_LSB (1U << 0) /* 2b */
+#define SW_DPY_VREF_EN_SEL_LSB (1U << 2) /* 2b */
+#define SW_DPY_DLL_CK_EN_SEL_LSB (1U << 4) /* 2b */
+#define SW_DPY_DLL_EN_SEL_LSB (1U << 6) /* 2b */
+#define SW_DPY_2ND_DLL_EN_SEL_LSB (1U << 8) /* 2b */
+#define SW_MEM_CK_OFF_SEL_LSB (1U << 10) /* 2b */
+#define SW_DMSUS_OFF_SEL_LSB (1U << 12) /* 2b */
+#define SW_DPY_MODE_SW_SEL_LSB (1U << 14) /* 2b */
+#define SW_EMI_CLK_OFF_SEL_LSB (1U << 16) /* 2b */
+#define SW_DDRPHY_FB_CK_EN_SEL_LSB (1U << 18) /* 2b */
+#define SW_DR_GATE_RETRY_EN_SEL_LSB (1U << 20) /* 2b */
+#define SW_DPHY_PRECAL_UP_SEL_LSB (1U << 24) /* 2b */
+#define SW_DPY_BCLK_ENABLE_SEL_LSB (1U << 26) /* 2b */
+#define SW_TX_TRACKING_DIS_SEL_LSB (1U << 28) /* 2b */
+#define SW_DPHY_RXDLY_TRACKING_EN_SEL_LSB (1U << 30) /* 2b */
+/* DRAMC_DPY_CLK_SW_SEL_1 (0x10006000+0x494) */
+#define SW_SHU_RESTORE_SEL_LSB (1U << 0) /* 2b */
+#define SW_DMYRD_MOD_SEL_LSB (1U << 2) /* 2b */
+#define SW_DMYRD_INTV_SEL_LSB (1U << 4) /* 2b */
+#define SW_DMYRD_EN_SEL_LSB (1U << 6) /* 2b */
+#define SW_DRS_DIS_REQ_SEL_LSB (1U << 8) /* 2b */
+#define SW_DR_SRAM_LOAD_SEL_LSB (1U << 10) /* 2b */
+#define SW_DR_SRAM_RESTORE_SEL_LSB (1U << 12) /* 2b */
+#define SW_DR_SHU_LEVEL_SRAM_LATCH_SEL_LSB (1U << 14) /* 2b */
+#define SW_TX_TRACK_RETRY_EN_SEL_LSB (1U << 16) /* 2b */
+#define SW_DPY_MIDPI_EN_SEL_LSB (1U << 18) /* 2b */
+#define SW_DPY_PI_RESETB_EN_SEL_LSB (1U << 20) /* 2b */
+#define SW_DPY_MCK8X_EN_SEL_LSB (1U << 22) /* 2b */
+#define SW_DR_SHU_LEVEL_SRAM_SEL_LSB (1U << 24) /* 2b */
+/* DRAMC_DPY_CLK_SW_SEL_2 (0x10006000+0x498) */
+#define SW_DR_SHU_LEVEL_SEL_LSB (1U << 0) /* 1b */
+#define SW_DR_SHU_EN_SEL_LSB (1U << 2) /* 1b */
+#define SW_DR_SHORT_QUEUE_SEL_LSB (1U << 3) /* 1b */
+#define SW_PHYPLL_MODE_SW_SEL_LSB (1U << 4) /* 1b */
+#define SW_PHYPLL2_MODE_SW_SEL_LSB (1U << 5) /* 1b */
+#define SW_PHYPLL_SHU_EN_SEL_LSB (1U << 6) /* 1b */
+#define SW_PHYPLL2_SHU_EN_SEL_LSB (1U << 7) /* 1b */
+#define SW_DR_RESERVED_0_SEL_LSB (1U << 24) /* 2b */
+#define SW_DR_RESERVED_1_SEL_LSB (1U << 26) /* 2b */
+#define SW_DR_RESERVED_2_SEL_LSB (1U << 28) /* 2b */
+#define SW_DR_RESERVED_3_SEL_LSB (1U << 30) /* 2b */
+/* DRAMC_DPY_CLK_SW_SEL_3 (0x10006000+0x49C) */
+#define SC_DR_SHU_EN_ACK_SEL_LSB (1U << 0) /* 4b */
+#define SC_EMI_CLK_OFF_ACK_SEL_LSB (1U << 4) /* 4b */
+#define SC_DR_SHORT_QUEUE_ACK_SEL_LSB (1U << 8) /* 4b */
+#define SC_DRAMC_DFS_STA_SEL_LSB (1U << 12) /* 4b */
+#define SC_DRS_DIS_ACK_SEL_LSB (1U << 16) /* 4b */
+#define SC_DR_SRAM_LOAD_ACK_SEL_LSB (1U << 20) /* 4b */
+#define SC_DR_SRAM_PLL_LOAD_ACK_SEL_LSB (1U << 24) /* 4b */
+#define SC_DR_SRAM_RESTORE_ACK_SEL_LSB (1U << 28) /* 4b */
+/* DRAMC_DPY_CLK_SPM_CON (0x10006000+0x4A0) */
+#define SC_DMYRD_EN_MOD_SEL_PCM_LSB (1U << 0) /* 1b */
+#define SC_DMYRD_INTV_SEL_PCM_LSB (1U << 1) /* 1b */
+#define SC_DMYRD_EN_PCM_LSB (1U << 2) /* 1b */
+#define SC_DRS_DIS_REQ_PCM_LSB (1U << 3) /* 1b */
+#define SC_DR_SHU_LEVEL_SRAM_PCM_LSB (1U << 4) /* 4b */
+#define SC_DR_GATE_RETRY_EN_PCM_LSB (1U << 8) /* 1b */
+#define SC_DR_SHORT_QUEUE_PCM_LSB (1U << 9) /* 1b */
+#define SC_DPY_MIDPI_EN_PCM_LSB (1U << 10) /* 1b */
+#define SC_DPY_PI_RESETB_EN_PCM_LSB (1U << 11) /* 1b */
+#define SC_DPY_MCK8X_EN_PCM_LSB (1U << 12) /* 1b */
+#define SC_DR_RESERVED_0_PCM_LSB (1U << 13) /* 1b */
+#define SC_DR_RESERVED_1_PCM_LSB (1U << 14) /* 1b */
+#define SC_DR_RESERVED_2_PCM_LSB (1U << 15) /* 1b */
+#define SC_DR_RESERVED_3_PCM_LSB (1U << 16) /* 1b */
+#define SC_DMDRAMCSHU_ACK_ALL_LSB (1U << 24) /* 1b */
+#define SC_EMI_CLK_OFF_ACK_ALL_LSB (1U << 25) /* 1b */
+#define SC_DR_SHORT_QUEUE_ACK_ALL_LSB (1U << 26) /* 1b */
+#define SC_DRAMC_DFS_STA_ALL_LSB (1U << 27) /* 1b */
+#define SC_DRS_DIS_ACK_ALL_LSB (1U << 28) /* 1b */
+#define SC_DR_SRAM_LOAD_ACK_ALL_LSB (1U << 29) /* 1b */
+#define SC_DR_SRAM_PLL_LOAD_ACK_ALL_LSB (1U << 30) /* 1b */
+#define SC_DR_SRAM_RESTORE_ACK_ALL_LSB (1U << 31) /* 1b */
+/* SPM_DVFS_LEVEL (0x10006000+0x4A4) */
+#define SPM_DVFS_LEVEL_LSB (1U << 0) /* 32b */
+/* SPM_CIRQ_CON (0x10006000+0x4A8) */
+#define CIRQ_CLK_SEL_LSB (1U << 0) /* 1b */
+/* SPM_DVFS_MISC (0x10006000+0x4AC) */
+#define MSDC_DVFS_REQUEST_LSB (1U << 0) /* 1b */
+#define SPM2EMI_SLP_PROT_EN_LSB (1U << 1) /* 1b */
+#define SPM_DVFS_FORCE_ENABLE_LSB (1U << 2) /* 1b */
+#define FORCE_DVFS_WAKE_LSB (1U << 3) /* 1b */
+#define SPM_DVFSRC_ENABLE_LSB (1U << 4) /* 1b */
+#define SPM_DVFS_DONE_LSB (1U << 5) /* 1b */
+#define DVFSRC_IRQ_WAKEUP_EVENT_MASK_LSB (1U << 6) /* 1b */
+#define SPM2RC_EVENT_ABORT_LSB (1U << 7) /* 1b */
+#define EMI_SLP_IDLE_LSB (1U << 14) /* 1b */
+#define SDIO_READY_TO_SPM_LSB (1U << 15) /* 1b */
+/* SPM_VS1_VS2_RC_CON (0x10006000+0x4B0) */
+#define VS1_INIT_LEVEL_LSB (1U << 0) /* 2b */
+#define VS1_INIT_LSB (1U << 2) /* 1b */
+#define VS1_CURR_LEVEL_LSB (1U << 3) /* 2b */
+#define VS1_NEXT_LEVEL_LSB (1U << 5) /* 2b */
+#define VS1_VOTE_LEVEL_LSB (1U << 7) /* 2b */
+#define VS1_TRIGGER_LSB (1U << 9) /* 1b */
+#define VS2_INIT_LEVEL_LSB (1U << 10) /* 3b */
+#define VS2_INIT_LSB (1U << 13) /* 1b */
+#define VS2_CURR_LEVEL_LSB (1U << 14) /* 3b */
+#define VS2_NEXT_LEVEL_LSB (1U << 17) /* 3b */
+#define VS2_VOTE_LEVEL_LSB (1U << 20) /* 3b */
+#define VS2_TRIGGER_LSB (1U << 23) /* 1b */
+#define VS1_FORCE_LSB (1U << 24) /* 1b */
+#define VS2_FORCE_LSB (1U << 25) /* 1b */
+#define VS1_VOTE_LEVEL_FORCE_LSB (1U << 26) /* 2b */
+#define VS2_VOTE_LEVEL_FORCE_LSB (1U << 28) /* 3b */
+/* RG_MODULE_SW_CG_0_MASK_REQ_0 (0x10006000+0x4B4) */
+#define RG_MODULE_SW_CG_0_MASK_REQ_0_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_0_MASK_REQ_1 (0x10006000+0x4B8) */
+#define RG_MODULE_SW_CG_0_MASK_REQ_1_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_0_MASK_REQ_2 (0x10006000+0x4BC) */
+#define RG_MODULE_SW_CG_0_MASK_REQ_2_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_1_MASK_REQ_0 (0x10006000+0x4C0) */
+#define RG_MODULE_SW_CG_1_MASK_REQ_0_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_1_MASK_REQ_1 (0x10006000+0x4C4) */
+#define RG_MODULE_SW_CG_1_MASK_REQ_1_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_1_MASK_REQ_2 (0x10006000+0x4C8) */
+#define RG_MODULE_SW_CG_1_MASK_REQ_2_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_2_MASK_REQ_0 (0x10006000+0x4CC) */
+#define RG_MODULE_SW_CG_2_MASK_REQ_0_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_2_MASK_REQ_1 (0x10006000+0x4D0) */
+#define RG_MODULE_SW_CG_2_MASK_REQ_1_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_2_MASK_REQ_2 (0x10006000+0x4D4) */
+#define RG_MODULE_SW_CG_2_MASK_REQ_2_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_3_MASK_REQ_0 (0x10006000+0x4D8) */
+#define RG_MODULE_SW_CG_3_MASK_REQ_0_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_3_MASK_REQ_1 (0x10006000+0x4DC) */
+#define RG_MODULE_SW_CG_3_MASK_REQ_1_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_3_MASK_REQ_2 (0x10006000+0x4E0) */
+#define RG_MODULE_SW_CG_3_MASK_REQ_2_LSB (1U << 0) /* 32b */
+/* PWR_STATUS_MASK_REQ_0 (0x10006000+0x4E4) */
+#define PWR_STATUS_MASK_REQ_0_LSB (1U << 0) /* 32b */
+/* PWR_STATUS_MASK_REQ_1 (0x10006000+0x4E8) */
+#define PWR_STATUS_MASK_REQ_1_LSB (1U << 0) /* 32b */
+/* PWR_STATUS_MASK_REQ_2 (0x10006000+0x4EC) */
+#define PWR_STATUS_MASK_REQ_2_LSB (1U << 0) /* 32b */
+/* SPM_CG_CHECK_CON (0x10006000+0x4F0) */
+#define APMIXEDSYS_BUSY_MASK_REQ_0_LSB (1U << 0) /* 5b */
+#define APMIXEDSYS_BUSY_MASK_REQ_1_LSB (1U << 8) /* 5b */
+#define APMIXEDSYS_BUSY_MASK_REQ_2_LSB (1U << 16) /* 5b */
+#define AUDIOSYS_BUSY_MASK_REQ_0_LSB (1U << 24) /* 1b */
+#define AUDIOSYS_BUSY_MASK_REQ_1_LSB (1U << 25) /* 1b */
+#define AUDIOSYS_BUSY_MASK_REQ_2_LSB (1U << 26) /* 1b */
+#define SSUSB_BUSY_MASK_REQ_0_LSB (1U << 27) /* 1b */
+#define SSUSB_BUSY_MASK_REQ_1_LSB (1U << 28) /* 1b */
+#define SSUSB_BUSY_MASK_REQ_2_LSB (1U << 29) /* 1b */
+/* SPM_SRC_RDY_STA (0x10006000+0x4F4) */
+#define SPM_INFRA_INTERNAL_ACK_LSB (1U << 0) /* 1b */
+#define SPM_VRF18_INTERNAL_ACK_LSB (1U << 1) /* 1b */
+/* SPM_DVS_DFS_LEVEL (0x10006000+0x4F8) */
+#define SPM_DFS_LEVEL_LSB (1U << 0) /* 16b */
+#define SPM_DVS_LEVEL_LSB (1U << 16) /* 16b */
+/* SPM_FORCE_DVFS (0x10006000+0x4FC) */
+#define FORCE_DVFS_LEVEL_LSB (1U << 0) /* 32b */
+/* SRCLKEN_RC_CFG (0x10006000+0x500) */
+#define SRCLKEN_RC_CFG_LSB (1U << 0) /* 32b */
+/* RC_CENTRAL_CFG1 (0x10006000+0x504) */
+#define RC_CENTRAL_CFG1_LSB (1U << 0) /* 32b */
+/* RC_CENTRAL_CFG2 (0x10006000+0x508) */
+#define RC_CENTRAL_CFG2_LSB (1U << 0) /* 32b */
+/* RC_CMD_ARB_CFG (0x10006000+0x50C) */
+#define RC_CMD_ARB_CFG_LSB (1U << 0) /* 32b */
+/* RC_PMIC_RCEN_ADDR (0x10006000+0x510) */
+#define RC_PMIC_RCEN_ADDR_LSB (1U << 0) /* 16b */
+#define RC_PMIC_RCEN_RESERVE_LSB (1U << 16) /* 16b */
+/* RC_PMIC_RCEN_SET_CLR_ADDR (0x10006000+0x514) */
+#define RC_PMIC_RCEN_SET_ADDR_LSB (1U << 0) /* 16b */
+#define RC_PMIC_RCEN_CLR_ADDR_LSB (1U << 16) /* 16b */
+/* RC_DCXO_FPM_CFG (0x10006000+0x518) */
+#define RC_DCXO_FPM_CFG_LSB (1U << 0) /* 32b */
+/* RC_CENTRAL_CFG3 (0x10006000+0x51C) */
+#define RC_CENTRAL_CFG3_LSB (1U << 0) /* 32b */
+/* RC_M00_SRCLKEN_CFG (0x10006000+0x520) */
+#define RC_M00_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+#define RC_SW_SRCLKEN_RC (1U << 3) /* 1b */
+#define RC_SW_SRCLKEN_FPM (1U << 4) /* 1b */
+/* RC_M01_SRCLKEN_CFG (0x10006000+0x524) */
+#define RC_M01_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M02_SRCLKEN_CFG (0x10006000+0x528) */
+#define RC_M02_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M03_SRCLKEN_CFG (0x10006000+0x52C) */
+#define RC_M03_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M04_SRCLKEN_CFG (0x10006000+0x530) */
+#define RC_M04_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M05_SRCLKEN_CFG (0x10006000+0x534) */
+#define RC_M05_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M06_SRCLKEN_CFG (0x10006000+0x538) */
+#define RC_M06_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M07_SRCLKEN_CFG (0x10006000+0x53C) */
+#define RC_M07_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M08_SRCLKEN_CFG (0x10006000+0x540) */
+#define RC_M08_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M09_SRCLKEN_CFG (0x10006000+0x544) */
+#define RC_M09_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M10_SRCLKEN_CFG (0x10006000+0x548) */
+#define RC_M10_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M11_SRCLKEN_CFG (0x10006000+0x54C) */
+#define RC_M11_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M12_SRCLKEN_CFG (0x10006000+0x550) */
+#define RC_M12_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_SRCLKEN_SW_CON_CFG (0x10006000+0x554) */
+#define RC_SRCLKEN_SW_CON_CFG_LSB (1U << 0) /* 32b */
+/* RC_CENTRAL_CFG4 (0x10006000+0x558) */
+#define RC_CENTRAL_CFG4_LSB (1U << 0) /* 32b */
+/* RC_PROTOCOL_CHK_CFG (0x10006000+0x560) */
+#define RC_PROTOCOL_CHK_CFG_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_CFG (0x10006000+0x564) */
+#define RC_DEBUG_CFG_LSB (1U << 0) /* 32b */
+/* RC_MISC_0 (0x10006000+0x5B4) */
+#define SRCCLKENO_LSB (1U << 0) /* 2b */
+#define PCM_SRCCLKENO_LSB (1U << 3) /* 2b */
+#define RC_VREQ_LSB (1U << 5) /* 1b */
+#define RC_SPM_SRCCLKENO_0_ACK_LSB (1U << 6) /* 1b */
+/* RC_SPM_CTRL (0x10006000+0x5B8) */
+#define SPM_AP_26M_RDY_LSB (1U << 0) /* 1b */
+#define KEEP_RC_SPI_ACTIVE_LSB (1U << 1) /* 1b */
+#define SPM2RC_DMY_CTRL_LSB (1U << 2) /* 6b */
+/* SUBSYS_INTF_CFG (0x10006000+0x5BC) */
+#define SRCLKEN_FPM_MASK_B_LSB (1U << 0) /* 13b */
+#define SRCLKEN_BBLPM_MASK_B_LSB (1U << 16) /* 13b */
+/* PCM_WDT_LATCH_25 (0x10006000+0x5C0) */
+#define PCM_WDT_LATCH_25_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_26 (0x10006000+0x5C4) */
+#define PCM_WDT_LATCH_26_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_27 (0x10006000+0x5C8) */
+#define PCM_WDT_LATCH_27_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_28 (0x10006000+0x5CC) */
+#define PCM_WDT_LATCH_28_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_29 (0x10006000+0x5D0) */
+#define PCM_WDT_LATCH_29_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_30 (0x10006000+0x5D4) */
+#define PCM_WDT_LATCH_30_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_31 (0x10006000+0x5D8) */
+#define PCM_WDT_LATCH_31_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_32 (0x10006000+0x5DC) */
+#define PCM_WDT_LATCH_32_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_33 (0x10006000+0x5E0) */
+#define PCM_WDT_LATCH_33_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_34 (0x10006000+0x5E4) */
+#define PCM_WDT_LATCH_34_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_35 (0x10006000+0x5EC) */
+#define PCM_WDT_LATCH_35_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_36 (0x10006000+0x5F0) */
+#define PCM_WDT_LATCH_36_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_37 (0x10006000+0x5F4) */
+#define PCM_WDT_LATCH_37_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_38 (0x10006000+0x5F8) */
+#define PCM_WDT_LATCH_38_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_39 (0x10006000+0x5FC) */
+#define PCM_WDT_LATCH_39_LSB (1U << 0) /* 32b */
+/* SPM_SW_FLAG_0 (0x10006000+0x600) */
+#define SPM_SW_FLAG_LSB (1U << 0) /* 32b */
+/* SPM_SW_DEBUG_0 (0x10006000+0x604) */
+#define SPM_SW_DEBUG_0_LSB (1U << 0) /* 32b */
+/* SPM_SW_FLAG_1 (0x10006000+0x608) */
+#define SPM_SW_FLAG_1_LSB (1U << 0) /* 32b */
+/* SPM_SW_DEBUG_1 (0x10006000+0x60C) */
+#define SPM_SW_DEBUG_1_LSB (1U << 0) /* 32b */
+/* SPM_SW_RSV_0 (0x10006000+0x610) */
+#define SPM_SW_RSV_0_LSB (1U << 0) /* 32b */
+/* SPM_SW_RSV_1 (0x10006000+0x614) */
+#define SPM_SW_RSV_1_LSB (1U << 0) /* 32b */
+/* SPM_SW_RSV_2 (0x10006000+0x618) */
+#define SPM_SW_RSV_2_LSB (1U << 0) /* 32b */
+/* SPM_SW_RSV_3 (0x10006000+0x61C) */
+#define SPM_SW_RSV_3_LSB (1U << 0) /* 32b */
+/* SPM_SW_RSV_4 (0x10006000+0x620) */
+#define SPM_SW_RSV_4_LSB (1U << 0) /* 32b */
+/* SPM_SW_RSV_5 (0x10006000+0x624) */
+#define SPM_SW_RSV_5_LSB (1U << 0) /* 32b */
+/* SPM_SW_RSV_6 (0x10006000+0x628) */
+#define SPM_SW_RSV_6_LSB (1U << 0) /* 32b */
+/* SPM_SW_RSV_7 (0x10006000+0x62C) */
+#define SPM_SW_RSV_7_LSB (1U << 0) /* 32b */
+/* SPM_SW_RSV_8 (0x10006000+0x630) */
+#define SPM_SW_RSV_8_LSB (1U << 0) /* 32b */
+/* SPM_BK_WAKE_EVENT (0x10006000+0x634) */
+#define SPM_BK_WAKE_EVENT_LSB (1U << 0) /* 32b */
+/* SPM_BK_VTCXO_DUR (0x10006000+0x638) */
+#define SPM_BK_VTCXO_DUR_LSB (1U << 0) /* 32b */
+/* SPM_BK_WAKE_MISC (0x10006000+0x63C) */
+#define SPM_BK_WAKE_MISC_LSB (1U << 0) /* 32b */
+/* SPM_BK_PCM_TIMER (0x10006000+0x640) */
+#define SPM_BK_PCM_TIMER_LSB (1U << 0) /* 32b */
+/* SPM_RSV_CON_0 (0x10006000+0x650) */
+#define SPM_RSV_CON_0_LSB (1U << 0) /* 32b */
+/* SPM_RSV_CON_1 (0x10006000+0x654) */
+#define SPM_RSV_CON_1_LSB (1U << 0) /* 32b */
+/* SPM_RSV_STA_0 (0x10006000+0x658) */
+#define SPM_RSV_STA_0_LSB (1U << 0) /* 32b */
+/* SPM_RSV_STA_1 (0x10006000+0x65C) */
+#define SPM_RSV_STA_1_LSB (1U << 0) /* 32b */
+/* SPM_SPARE_CON (0x10006000+0x660) */
+#define SPM_SPARE_CON_LSB (1U << 0) /* 32b */
+/* SPM_SPARE_CON_SET (0x10006000+0x664) */
+#define SPM_SPARE_CON_SET_LSB (1U << 0) /* 32b */
+/* SPM_SPARE_CON_CLR (0x10006000+0x668) */
+#define SPM_SPARE_CON_CLR_LSB (1U << 0) /* 32b */
+/* SPM_CROSS_WAKE_M00_REQ (0x10006000+0x66C) */
+#define SPM_CROSS_WAKE_M00_REQ_LSB (1U << 0) /* 5b */
+#define SPM_CROSS_WAKE_M00_CHK_LSB (1U << 8) /* 5b */
+/* SPM_CROSS_WAKE_M01_REQ (0x10006000+0x670) */
+#define SPM_CROSS_WAKE_M01_REQ_LSB (1U << 0) /* 5b */
+#define SPM_CROSS_WAKE_M01_CHK_LSB (1U << 8) /* 5b */
+/* SPM_CROSS_WAKE_M02_REQ (0x10006000+0x674) */
+#define SPM_CROSS_WAKE_M02_REQ_LSB (1U << 0) /* 5b */
+#define SPM_CROSS_WAKE_M02_CHK_LSB (1U << 8) /* 5b */
+/* SPM_CROSS_WAKE_M03_REQ (0x10006000+0x678) */
+#define SPM_CROSS_WAKE_M03_REQ_LSB (1U << 0) /* 5b */
+#define SPM_CROSS_WAKE_M03_CHK_LSB (1U << 8) /* 5b */
+/* SCP_VCORE_LEVEL (0x10006000+0x67C) */
+#define SCP_VCORE_LEVEL_LSB (1U << 0) /* 16b */
+/* SC_MM_CK_SEL_CON (0x10006000+0x680) */
+#define SC_MM_CK_SEL_LSB (1U << 0) /* 4b */
+#define SC_MM_CK_SEL_EN_LSB (1U << 4) /* 1b */
+/* SPARE_ACK_MASK (0x10006000+0x684) */
+#define SPARE_ACK_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_CROSS_WAKE_M04_REQ (0x10006000+0x688) */
+#define SPM_CROSS_WAKE_M04_REQ_LSB (1U << 0) /* 5b */
+#define SPM_CROSS_WAKE_M04_CHK_LSB (1U << 8) /* 5b */
+/* SPM_DV_CON_0 (0x10006000+0x68C) */
+#define SPM_DV_CON_0_LSB (1U << 0) /* 32b */
+/* SPM_DV_CON_1 (0x10006000+0x690) */
+#define SPM_DV_CON_1_LSB (1U << 0) /* 32b */
+/* SPM_DV_STA (0x10006000+0x694) */
+#define SPM_DV_STA_LSB (1U << 0) /* 32b */
+/* CONN_XOWCN_DEBUG_EN (0x10006000+0x698) */
+#define CONN_XOWCN_DEBUG_EN_LSB (1U << 0) /* 1b */
+/* SPM_SEMA_M0 (0x10006000+0x69C) */
+#define SPM_SEMA_M0_LSB (1U << 0) /* 8b */
+/* SPM_SEMA_M1 (0x10006000+0x6A0) */
+#define SPM_SEMA_M1_LSB (1U << 0) /* 8b */
+/* SPM_SEMA_M2 (0x10006000+0x6A4) */
+#define SPM_SEMA_M2_LSB (1U << 0) /* 8b */
+/* SPM_SEMA_M3 (0x10006000+0x6A8) */
+#define SPM_SEMA_M3_LSB (1U << 0) /* 8b */
+/* SPM_SEMA_M4 (0x10006000+0x6AC) */
+#define SPM_SEMA_M4_LSB (1U << 0) /* 8b */
+/* SPM_SEMA_M5 (0x10006000+0x6B0) */
+#define SPM_SEMA_M5_LSB (1U << 0) /* 8b */
+/* SPM_SEMA_M6 (0x10006000+0x6B4) */
+#define SPM_SEMA_M6_LSB (1U << 0) /* 8b */
+/* SPM_SEMA_M7 (0x10006000+0x6B8) */
+#define SPM_SEMA_M7_LSB (1U << 0) /* 8b */
+/* SPM2ADSP_MAILBOX (0x10006000+0x6BC) */
+#define SPM2ADSP_MAILBOX_LSB (1U << 0) /* 32b */
+/* ADSP2SPM_MAILBOX (0x10006000+0x6C0) */
+#define ADSP2SPM_MAILBOX_LSB (1U << 0) /* 32b */
+/* SPM_ADSP_IRQ (0x10006000+0x6C4) */
+#define SC_SPM2ADSP_WAKEUP_LSB (1U << 0) /* 1b */
+#define SPM_ADSP_IRQ_SC_ADSP2SPM_WAKEUP_LSB (1U << 4) /* 1b */
+/* SPM_MD32_IRQ (0x10006000+0x6C8) */
+#define SC_SPM2SSPM_WAKEUP_LSB (1U << 0) /* 4b */
+#define SPM_MD32_IRQ_SC_SSPM2SPM_WAKEUP_LSB (1U << 4) /* 4b */
+/* SPM2PMCU_MAILBOX_0 (0x10006000+0x6CC) */
+#define SPM2PMCU_MAILBOX_0_LSB (1U << 0) /* 32b */
+/* SPM2PMCU_MAILBOX_1 (0x10006000+0x6D0) */
+#define SPM2PMCU_MAILBOX_1_LSB (1U << 0) /* 32b */
+/* SPM2PMCU_MAILBOX_2 (0x10006000+0x6D4) */
+#define SPM2PMCU_MAILBOX_2_LSB (1U << 0) /* 32b */
+/* SPM2PMCU_MAILBOX_3 (0x10006000+0x6D8) */
+#define SPM2PMCU_MAILBOX_3_LSB (1U << 0) /* 32b */
+/* PMCU2SPM_MAILBOX_0 (0x10006000+0x6DC) */
+#define PMCU2SPM_MAILBOX_0_LSB (1U << 0) /* 32b */
+/* PMCU2SPM_MAILBOX_1 (0x10006000+0x6E0) */
+#define PMCU2SPM_MAILBOX_1_LSB (1U << 0) /* 32b */
+/* PMCU2SPM_MAILBOX_2 (0x10006000+0x6E4) */
+#define PMCU2SPM_MAILBOX_2_LSB (1U << 0) /* 32b */
+/* PMCU2SPM_MAILBOX_3 (0x10006000+0x6E8) */
+#define PMCU2SPM_MAILBOX_3_LSB (1U << 0) /* 32b */
+/* UFS_PSRI_SW (0x10006000+0x6EC) */
+#define UFS_PSRI_SW_LSB (1U << 0) /* 1b */
+/* UFS_PSRI_SW_SET (0x10006000+0x6F0) */
+#define UFS_PSRI_SW_SET_LSB (1U << 0) /* 1b */
+/* UFS_PSRI_SW_CLR (0x10006000+0x6F4) */
+#define UFS_PSRI_SW_CLR_LSB (1U << 0) /* 1b */
+/* SPM_AP_SEMA (0x10006000+0x6F8) */
+#define SPM_AP_SEMA_LSB (1U << 0) /* 1b */
+/* SPM_SPM_SEMA (0x10006000+0x6FC) */
+#define SPM_SPM_SEMA_LSB (1U << 0) /* 1b */
+/* SPM_DVFS_CON (0x10006000+0x700) */
+#define SPM_DVFS_CON_LSB (1U << 0) /* 32b */
+/* SPM_DVFS_CON_STA (0x10006000+0x704) */
+#define SPM_DVFS_CON_STA_LSB (1U << 0) /* 32b */
+/* SPM_PMIC_SPMI_CON (0x10006000+0x708) */
+#define SPM_PMIC_SPMI_CMD_LSB (1U << 0) /* 2b */
+#define SPM_PMIC_SPMI_SLAVEID_LSB (1U << 2) /* 4b */
+#define SPM_PMIC_SPMI_PMIFID_LSB (1U << 6) /* 1b */
+#define SPM_PMIC_SPMI_DBCNT_LSB (1U << 7) /* 1b */
+/* 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 */
+/* SPM_DVFS_CMD16 (0x10006000+0x750) */
+#define SPM_DVFS_CMD16_LSB (1U << 0) /* 32b */
+/* SPM_DVFS_CMD17 (0x10006000+0x754) */
+#define SPM_DVFS_CMD17_LSB (1U << 0) /* 32b */
+/* SPM_DVFS_CMD18 (0x10006000+0x758) */
+#define SPM_DVFS_CMD18_LSB (1U << 0) /* 32b */
+/* SPM_DVFS_CMD19 (0x10006000+0x75C) */
+#define SPM_DVFS_CMD19_LSB (1U << 0) /* 32b */
+/* SPM_DVFS_CMD20 (0x10006000+0x760) */
+#define SPM_DVFS_CMD20_LSB (1U << 0) /* 32b */
+/* SPM_DVFS_CMD21 (0x10006000+0x764) */
+#define SPM_DVFS_CMD21_LSB (1U << 0) /* 32b */
+/* SPM_DVFS_CMD22 (0x10006000+0x768) */
+#define SPM_DVFS_CMD22_LSB (1U << 0) /* 32b */
+/* SPM_DVFS_CMD23 (0x10006000+0x76C) */
+#define SPM_DVFS_CMD23_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_VALUE_L (0x10006000+0x770) */
+#define SYS_TIMER_VALUE_L_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_VALUE_H (0x10006000+0x774) */
+#define SYS_TIMER_VALUE_H_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_START_L (0x10006000+0x778) */
+#define SYS_TIMER_START_L_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_START_H (0x10006000+0x77C) */
+#define SYS_TIMER_START_H_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_00 (0x10006000+0x780) */
+#define SYS_TIMER_LATCH_L_00_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_00 (0x10006000+0x784) */
+#define SYS_TIMER_LATCH_H_00_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_01 (0x10006000+0x788) */
+#define SYS_TIMER_LATCH_L_01_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_01 (0x10006000+0x78C) */
+#define SYS_TIMER_LATCH_H_01_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_02 (0x10006000+0x790) */
+#define SYS_TIMER_LATCH_L_02_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_02 (0x10006000+0x794) */
+#define SYS_TIMER_LATCH_H_02_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_03 (0x10006000+0x798) */
+#define SYS_TIMER_LATCH_L_03_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_03 (0x10006000+0x79C) */
+#define SYS_TIMER_LATCH_H_03_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_04 (0x10006000+0x7A0) */
+#define SYS_TIMER_LATCH_L_04_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_04 (0x10006000+0x7A4) */
+#define SYS_TIMER_LATCH_H_04_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_05 (0x10006000+0x7A8) */
+#define SYS_TIMER_LATCH_L_05_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_05 (0x10006000+0x7AC) */
+#define SYS_TIMER_LATCH_H_05_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_06 (0x10006000+0x7B0) */
+#define SYS_TIMER_LATCH_L_06_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_06 (0x10006000+0x7B4) */
+#define SYS_TIMER_LATCH_H_06_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_07 (0x10006000+0x7B8) */
+#define SYS_TIMER_LATCH_L_07_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_07 (0x10006000+0x7BC) */
+#define SYS_TIMER_LATCH_H_07_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_08 (0x10006000+0x7C0) */
+#define SYS_TIMER_LATCH_L_08_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_08 (0x10006000+0x7C4) */
+#define SYS_TIMER_LATCH_H_08_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_09 (0x10006000+0x7C8) */
+#define SYS_TIMER_LATCH_L_09_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_09 (0x10006000+0x7CC) */
+#define SYS_TIMER_LATCH_H_09_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_10 (0x10006000+0x7D0) */
+#define SYS_TIMER_LATCH_L_10_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_10 (0x10006000+0x7D4) */
+#define SYS_TIMER_LATCH_H_10_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_11 (0x10006000+0x7D8) */
+#define SYS_TIMER_LATCH_L_11_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_11 (0x10006000+0x7DC) */
+#define SYS_TIMER_LATCH_H_11_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_12 (0x10006000+0x7E0) */
+#define SYS_TIMER_LATCH_L_12_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_12 (0x10006000+0x7E4) */
+#define SYS_TIMER_LATCH_H_12_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_13 (0x10006000+0x7E8) */
+#define SYS_TIMER_LATCH_L_13_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_13 (0x10006000+0x7EC) */
+#define SYS_TIMER_LATCH_H_13_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_14 (0x10006000+0x7F0) */
+#define SYS_TIMER_LATCH_L_14_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_14 (0x10006000+0x7F4) */
+#define SYS_TIMER_LATCH_H_14_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_15 (0x10006000+0x7F8) */
+#define SYS_TIMER_LATCH_L_15_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_15 (0x10006000+0x7FC) */
+#define SYS_TIMER_LATCH_H_15_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 */
+/* PCM_WDT_LATCH_10 (0x10006000+0x828) */
+#define PCM_WDT_LATCH_10_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_11 (0x10006000+0x82C) */
+#define PCM_WDT_LATCH_11_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_12 (0x10006000+0x830) */
+#define PCM_WDT_LATCH_12_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_13 (0x10006000+0x834) */
+#define PCM_WDT_LATCH_13_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_14 (0x10006000+0x838) */
+#define PCM_WDT_LATCH_14_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_15 (0x10006000+0x83C) */
+#define PCM_WDT_LATCH_15_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_16 (0x10006000+0x840) */
+#define PCM_WDT_LATCH_16_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_17 (0x10006000+0x844) */
+#define PCM_WDT_LATCH_17_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_18 (0x10006000+0x848) */
+#define PCM_WDT_LATCH_18_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_SPARE_0 (0x10006000+0x84C) */
+#define PCM_WDT_LATCH_SPARE_0_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_SPARE_1 (0x10006000+0x850) */
+#define PCM_WDT_LATCH_SPARE_1_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_SPARE_2 (0x10006000+0x854) */
+#define PCM_WDT_LATCH_SPARE_2_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_CONN_0 (0x10006000+0x870) */
+#define PCM_WDT_LATCH_CONN_0_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_CONN_1 (0x10006000+0x874) */
+#define PCM_WDT_LATCH_CONN_1_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_CONN_2 (0x10006000+0x878) */
+#define PCM_WDT_LATCH_CONN_2_LSB (1U << 0) /* 32b */
+/* DRAMC_GATING_ERR_LATCH_CH0_0 (0x10006000+0x8A0) */
+#define DRAMC_GATING_ERR_LATCH_CH0_0_LSB (1U << 0) /* 32b */
+/* DRAMC_GATING_ERR_LATCH_CH0_1 (0x10006000+0x8A4) */
+#define DRAMC_GATING_ERR_LATCH_CH0_1_LSB (1U << 0) /* 32b */
+/* DRAMC_GATING_ERR_LATCH_CH0_2 (0x10006000+0x8A8) */
+#define DRAMC_GATING_ERR_LATCH_CH0_2_LSB (1U << 0) /* 32b */
+/* DRAMC_GATING_ERR_LATCH_CH0_3 (0x10006000+0x8AC) */
+#define DRAMC_GATING_ERR_LATCH_CH0_3_LSB (1U << 0) /* 32b */
+/* DRAMC_GATING_ERR_LATCH_CH0_4 (0x10006000+0x8B0) */
+#define DRAMC_GATING_ERR_LATCH_CH0_4_LSB (1U << 0) /* 32b */
+/* DRAMC_GATING_ERR_LATCH_CH0_5 (0x10006000+0x8B4) */
+#define DRAMC_GATING_ERR_LATCH_CH0_5_LSB (1U << 0) /* 32b */
+/* DRAMC_GATING_ERR_LATCH_CH0_6 (0x10006000+0x8B8) */
+#define DRAMC_GATING_ERR_LATCH_CH0_6_LSB (1U << 0) /* 32b */
+/* DRAMC_GATING_ERR_LATCH_SPARE_0 (0x10006000+0x8F4) */
+#define DRAMC_GATING_ERR_LATCH_SPARE_0_LSB (1U << 0) /* 32b */
+/* SPM_ACK_CHK_CON_0 (0x10006000+0x900) */
+#define SPM_ACK_CHK_SW_EN_0_LSB (1U << 0) /* 1b */
+#define SPM_ACK_CHK_CLR_ALL_0_LSB (1U << 1) /* 1b */
+#define SPM_ACK_CHK_CLR_TIMER_0_LSB (1U << 2) /* 1b */
+#define SPM_ACK_CHK_CLR_IRQ_0_LSB (1U << 3) /* 1b */
+#define SPM_ACK_CHK_STA_EN_0_LSB (1U << 4) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_EN_0_LSB (1U << 5) /* 1b */
+#define SPM_ACK_CHK_WDT_EN_0_LSB (1U << 6) /* 1b */
+#define SPM_ACK_CHK_LOCK_PC_TRACE_EN_0_LSB (1U << 7) /* 1b */
+#define SPM_ACK_CHK_HW_EN_0_LSB (1U << 8) /* 1b */
+#define SPM_ACK_CHK_HW_MODE_0_LSB (1U << 9) /* 3b */
+#define SPM_ACK_CHK_FAIL_0_LSB (1U << 15) /* 1b */
+/* SPM_ACK_CHK_PC_0 (0x10006000+0x904) */
+#define SPM_ACK_CHK_HW_TRIG_PC_VAL_0_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_HW_TARG_PC_VAL_0_LSB (1U << 16) /* 16b */
+/* SPM_ACK_CHK_SEL_0 (0x10006000+0x908) */
+#define SPM_ACK_CHK_HW_TRIG_SIGNAL_SEL_0_LSB (1U << 0) /* 5b */
+#define SPM_ACK_CHK_HW_TRIG_GROUP_SEL_0_LSB (1U << 5) /* 3b */
+#define SPM_ACK_CHK_HW_TARG_SIGNAL_SEL_0_LSB (1U << 16) /* 5b */
+#define SPM_ACK_CHK_HW_TARG_GROUP_SEL_0_LSB (1U << 21) /* 3b */
+/* SPM_ACK_CHK_TIMER_0 (0x10006000+0x90C) */
+#define SPM_ACK_CHK_TIMER_VAL_0_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_TIMER_0_LSB (1U << 16) /* 16b */
+/* SPM_ACK_CHK_STA_0 (0x10006000+0x910) */
+#define SPM_ACK_CHK_STA_0_LSB (1U << 0) /* 32b */
+/* SPM_ACK_CHK_SWINT_0 (0x10006000+0x914) */
+#define SPM_ACK_CHK_SWINT_EN_0_LSB (1U << 0) /* 32b */
+/* SPM_ACK_CHK_CON_1 (0x10006000+0x920) */
+#define SPM_ACK_CHK_SW_EN_1_LSB (1U << 0) /* 1b */
+#define SPM_ACK_CHK_CLR_ALL_1_LSB (1U << 1) /* 1b */
+#define SPM_ACK_CHK_CLR_TIMER_1_LSB (1U << 2) /* 1b */
+#define SPM_ACK_CHK_CLR_IRQ_1_LSB (1U << 3) /* 1b */
+#define SPM_ACK_CHK_STA_EN_1_LSB (1U << 4) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_EN_1_LSB (1U << 5) /* 1b */
+#define SPM_ACK_CHK_WDT_EN_1_LSB (1U << 6) /* 1b */
+#define SPM_ACK_CHK_LOCK_PC_TRACE_EN_1_LSB (1U << 7) /* 1b */
+#define SPM_ACK_CHK_HW_EN_1_LSB (1U << 8) /* 1b */
+#define SPM_ACK_CHK_HW_MODE_1_LSB (1U << 9) /* 3b */
+#define SPM_ACK_CHK_FAIL_1_LSB (1U << 15) /* 1b */
+/* SPM_ACK_CHK_PC_1 (0x10006000+0x924) */
+#define SPM_ACK_CHK_HW_TRIG_PC_VAL_1_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_HW_TARG_PC_VAL_1_LSB (1U << 16) /* 16b */
+/* SPM_ACK_CHK_SEL_1 (0x10006000+0x928) */
+#define SPM_ACK_CHK_HW_TRIG_SIGNAL_SEL_1_LSB (1U << 0) /* 5b */
+#define SPM_ACK_CHK_HW_TRIG_GROUP_SEL_1_LSB (1U << 5) /* 3b */
+#define SPM_ACK_CHK_HW_TARG_SIGNAL_SEL_1_LSB (1U << 16) /* 5b */
+#define SPM_ACK_CHK_HW_TARG_GROUP_SEL_1_LSB (1U << 21) /* 3b */
+/* SPM_ACK_CHK_TIMER_1 (0x10006000+0x92C) */
+#define SPM_ACK_CHK_TIMER_VAL_1_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_TIMER_1_LSB (1U << 16) /* 16b */
+/* SPM_ACK_CHK_STA_1 (0x10006000+0x930) */
+#define SPM_ACK_CHK_STA_1_LSB (1U << 0) /* 32b */
+/* SPM_ACK_CHK_SWINT_1 (0x10006000+0x934) */
+#define SPM_ACK_CHK_SWINT_EN_1_LSB (1U << 0) /* 32b */
+/* SPM_ACK_CHK_CON_2 (0x10006000+0x940) */
+#define SPM_ACK_CHK_SW_EN_2_LSB (1U << 0) /* 1b */
+#define SPM_ACK_CHK_CLR_ALL_2_LSB (1U << 1) /* 1b */
+#define SPM_ACK_CHK_CLR_TIMER_2_LSB (1U << 2) /* 1b */
+#define SPM_ACK_CHK_CLR_IRQ_2_LSB (1U << 3) /* 1b */
+#define SPM_ACK_CHK_STA_EN_2_LSB (1U << 4) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_EN_2_LSB (1U << 5) /* 1b */
+#define SPM_ACK_CHK_WDT_EN_2_LSB (1U << 6) /* 1b */
+#define SPM_ACK_CHK_LOCK_PC_TRACE_EN_2_LSB (1U << 7) /* 1b */
+#define SPM_ACK_CHK_HW_EN_2_LSB (1U << 8) /* 1b */
+#define SPM_ACK_CHK_HW_MODE_2_LSB (1U << 9) /* 3b */
+#define SPM_ACK_CHK_FAIL_2_LSB (1U << 15) /* 1b */
+/* SPM_ACK_CHK_PC_2 (0x10006000+0x944) */
+#define SPM_ACK_CHK_HW_TRIG_PC_VAL_2_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_HW_TARG_PC_VAL_2_LSB (1U << 16) /* 16b */
+/* SPM_ACK_CHK_SEL_2 (0x10006000+0x948) */
+#define SPM_ACK_CHK_HW_TRIG_SIGNAL_SEL_2_LSB (1U << 0) /* 5b */
+#define SPM_ACK_CHK_HW_TRIG_GROUP_SEL_2_LSB (1U << 5) /* 3b */
+#define SPM_ACK_CHK_HW_TARG_SIGNAL_SEL_2_LSB (1U << 16) /* 5b */
+#define SPM_ACK_CHK_HW_TARG_GROUP_SEL_2_LSB (1U << 21) /* 3b */
+/* SPM_ACK_CHK_TIMER_2 (0x10006000+0x94C) */
+#define SPM_ACK_CHK_TIMER_VAL_2_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_TIMER_2_LSB (1U << 16) /* 16b */
+/* SPM_ACK_CHK_STA_2 (0x10006000+0x950) */
+#define SPM_ACK_CHK_STA_2_LSB (1U << 0) /* 32b */
+/* SPM_ACK_CHK_SWINT_2 (0x10006000+0x954) */
+#define SPM_ACK_CHK_SWINT_EN_2_LSB (1U << 0) /* 32b */
+/* SPM_ACK_CHK_CON_3 (0x10006000+0x960) */
+#define SPM_ACK_CHK_SW_EN_3_LSB (1U << 0) /* 1b */
+#define SPM_ACK_CHK_CLR_ALL_3_LSB (1U << 1) /* 1b */
+#define SPM_ACK_CHK_CLR_TIMER_3_LSB (1U << 2) /* 1b */
+#define SPM_ACK_CHK_CLR_IRQ_3_LSB (1U << 3) /* 1b */
+#define SPM_ACK_CHK_STA_EN_3_LSB (1U << 4) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_EN_3_LSB (1U << 5) /* 1b */
+#define SPM_ACK_CHK_WDT_EN_3_LSB (1U << 6) /* 1b */
+#define SPM_ACK_CHK_LOCK_PC_TRACE_EN_3_LSB (1U << 7) /* 1b */
+#define SPM_ACK_CHK_HW_EN_3_LSB (1U << 8) /* 1b */
+#define SPM_ACK_CHK_HW_MODE_3_LSB (1U << 9) /* 3b */
+#define SPM_ACK_CHK_FAIL_3_LSB (1U << 15) /* 1b */
+/* SPM_ACK_CHK_PC_3 (0x10006000+0x964) */
+#define SPM_ACK_CHK_HW_TRIG_PC_VAL_3_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_HW_TARG_PC_VAL_3_LSB (1U << 16) /* 16b */
+/* SPM_ACK_CHK_SEL_3 (0x10006000+0x968) */
+#define SPM_ACK_CHK_HW_TRIG_SIGNAL_SEL_3_LSB (1U << 0) /* 5b */
+#define SPM_ACK_CHK_HW_TRIG_GROUP_SEL_3_LSB (1U << 5) /* 3b */
+#define SPM_ACK_CHK_HW_TARG_SIGNAL_SEL_3_LSB (1U << 16) /* 5b */
+#define SPM_ACK_CHK_HW_TARG_GROUP_SEL_3_LSB (1U << 21) /* 3b */
+/* SPM_ACK_CHK_TIMER_3 (0x10006000+0x96C) */
+#define SPM_ACK_CHK_TIMER_VAL_3_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_TIMER_3_LSB (1U << 16) /* 16b */
+/* SPM_ACK_CHK_STA_3 (0x10006000+0x970) */
+#define SPM_ACK_CHK_STA_3_LSB (1U << 0) /* 32b */
+/* SPM_ACK_CHK_SWINT_3 (0x10006000+0x974) */
+#define SPM_ACK_CHK_SWINT_EN_3_LSB (1U << 0) /* 32b */
+/* SPM_COUNTER_0 (0x10006000+0x978) */
+#define SPM_COUNTER_VAL_0_LSB (1U << 0) /* 14b */
+#define SPM_COUNTER_OUT_0_LSB (1U << 14) /* 14b */
+#define SPM_COUNTER_EN_0_LSB (1U << 28) /* 1b */
+#define SPM_COUNTER_CLR_0_LSB (1U << 29) /* 1b */
+#define SPM_COUNTER_TIMEOUT_0_LSB (1U << 30) /* 1b */
+#define SPM_COUNTER_WAKEUP_EN_0_LSB (1U << 31) /* 1b */
+/* SPM_COUNTER_1 (0x10006000+0x97C) */
+#define SPM_COUNTER_VAL_1_LSB (1U << 0) /* 14b */
+#define SPM_COUNTER_OUT_1_LSB (1U << 14) /* 14b */
+#define SPM_COUNTER_EN_1_LSB (1U << 28) /* 1b */
+#define SPM_COUNTER_CLR_1_LSB (1U << 29) /* 1b */
+#define SPM_COUNTER_TIMEOUT_1_LSB (1U << 30) /* 1b */
+#define SPM_COUNTER_WAKEUP_EN_1_LSB (1U << 31) /* 1b */
+/* SPM_COUNTER_2 (0x10006000+0x980) */
+#define SPM_COUNTER_VAL_2_LSB (1U << 0) /* 14b */
+#define SPM_COUNTER_OUT_2_LSB (1U << 14) /* 14b */
+#define SPM_COUNTER_EN_2_LSB (1U << 28) /* 1b */
+#define SPM_COUNTER_CLR_2_LSB (1U << 29) /* 1b */
+#define SPM_COUNTER_TIMEOUT_2_LSB (1U << 30) /* 1b */
+#define SPM_COUNTER_WAKEUP_EN_2_LSB (1U << 31) /* 1b */
+/* SYS_TIMER_CON (0x10006000+0x98C) */
+#define SYS_TIMER_START_EN_LSB (1U << 0) /* 1b */
+#define SYS_TIMER_LATCH_EN_LSB (1U << 1) /* 1b */
+#define SYS_TIMER_ID_LSB (1U << 8) /* 8b */
+#define SYS_TIMER_VALID_LSB (1U << 31) /* 1b */
+/* RC_FSM_STA_0 (0x10006000+0xE00) */
+#define RC_FSM_STA_0_LSB (1U << 0) /* 32b */
+/* RC_CMD_STA_0 (0x10006000+0xE04) */
+#define RC_CMD_STA_0_LSB (1U << 0) /* 32b */
+/* RC_CMD_STA_1 (0x10006000+0xE08) */
+#define RC_CMD_STA_1_LSB (1U << 0) /* 32b */
+/* RC_SPI_STA_0 (0x10006000+0xE0C) */
+#define RC_SPI_STA_0_LSB (1U << 0) /* 32b */
+/* RC_PI_PO_STA_0 (0x10006000+0xE10) */
+#define RC_PI_PO_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M00_REQ_STA_0 (0x10006000+0xE14) */
+#define RC_M00_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M01_REQ_STA_0 (0x10006000+0xE1C) */
+#define RC_M01_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M02_REQ_STA_0 (0x10006000+0xE20) */
+#define RC_M02_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M03_REQ_STA_0 (0x10006000+0xE24) */
+#define RC_M03_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M04_REQ_STA_0 (0x10006000+0xE28) */
+#define RC_M04_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M05_REQ_STA_0 (0x10006000+0xE2C) */
+#define RC_M05_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M06_REQ_STA_0 (0x10006000+0xE30) */
+#define RC_M06_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M07_REQ_STA_0 (0x10006000+0xE34) */
+#define RC_M07_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M08_REQ_STA_0 (0x10006000+0xE38) */
+#define RC_M08_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M09_REQ_STA_0 (0x10006000+0xE3C) */
+#define RC_M09_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M10_REQ_STA_0 (0x10006000+0xE40) */
+#define RC_M10_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M11_REQ_STA_0 (0x10006000+0xE44) */
+#define RC_M11_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M12_REQ_STA_0 (0x10006000+0xE48) */
+#define RC_M12_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_STA_0 (0x10006000+0xE4C) */
+#define RC_DEBUG_STA_0_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_0_LSB (0x10006000+0xE50) */
+#define RO_PMRC_TRACE_00_LSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_0_MSB (0x10006000+0xE54) */
+#define RO_PMRC_TRACE_00_MSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_1_LSB (0x10006000+0xE5C) */
+#define RO_PMRC_TRACE_01_LSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_1_MSB (0x10006000+0xE60) */
+#define RO_PMRC_TRACE_01_MSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_2_LSB (0x10006000+0xE64) */
+#define RO_PMRC_TRACE_02_LSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_2_MSB (0x10006000+0xE6C) */
+#define RO_PMRC_TRACE_02_MSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_3_LSB (0x10006000+0xE70) */
+#define RO_PMRC_TRACE_03_LSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_3_MSB (0x10006000+0xE74) */
+#define RO_PMRC_TRACE_03_MSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_4_LSB (0x10006000+0xE78) */
+#define RO_PMRC_TRACE_04_LSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_4_MSB (0x10006000+0xE7C) */
+#define RO_PMRC_TRACE_04_MSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_5_LSB (0x10006000+0xE80) */
+#define RO_PMRC_TRACE_05_LSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_5_MSB (0x10006000+0xE84) */
+#define RO_PMRC_TRACE_05_MSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_6_LSB (0x10006000+0xE88) */
+#define RO_PMRC_TRACE_06_LSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_6_MSB (0x10006000+0xE8C) */
+#define RO_PMRC_TRACE_06_MSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_7_LSB (0x10006000+0xE90) */
+#define RO_PMRC_TRACE_07_LSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_7_MSB (0x10006000+0xE94) */
+#define RO_PMRC_TRACE_07_MSB_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_0_LSB (0x10006000+0xE98) */
+#define RC_SYS_TIMER_LATCH_L_00_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_0_MSB (0x10006000+0xE9C) */
+#define RC_SYS_TIMER_LATCH_H_00_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_1_LSB (0x10006000+0xEA0) */
+#define RC_SYS_TIMER_LATCH_L_01_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_1_MSB (0x10006000+0xEA4) */
+#define RC_SYS_TIMER_LATCH_H_01_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_2_LSB (0x10006000+0xEA8) */
+#define RC_SYS_TIMER_LATCH_L_02_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_2_MSB (0x10006000+0xEAC) */
+#define RC_SYS_TIMER_LATCH_H_02_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_3_LSB (0x10006000+0xEB0) */
+#define RC_SYS_TIMER_LATCH_L_03_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_3_MSB (0x10006000+0xEB4) */
+#define RC_SYS_TIMER_LATCH_H_03_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_4_LSB (0x10006000+0xEB8) */
+#define RC_SYS_TIMER_LATCH_L_04_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_4_MSB (0x10006000+0xEBC) */
+#define RC_SYS_TIMER_LATCH_H_04_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_5_LSB (0x10006000+0xEC0) */
+#define RC_SYS_TIMER_LATCH_L_05_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_5_MSB (0x10006000+0xEC4) */
+#define RC_SYS_TIMER_LATCH_H_05_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_6_LSB (0x10006000+0xEC8) */
+#define RC_SYS_TIMER_LATCH_L_06_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_6_MSB (0x10006000+0xECC) */
+#define RC_SYS_TIMER_LATCH_H_06_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_7_LSB (0x10006000+0xED0) */
+#define RC_SYS_TIMER_LATCH_L_07_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_7_MSB (0x10006000+0xED4) */
+#define RC_SYS_TIMER_LATCH_H_07_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_19 (0x10006000+0xED8) */
+#define PCM_WDT_LATCH_19_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_20 (0x10006000+0xEDC) */
+#define PCM_WDT_LATCH_20_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_21 (0x10006000+0xEE0) */
+#define PCM_WDT_LATCH_21_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_22 (0x10006000+0xEE4) */
+#define PCM_WDT_LATCH_22_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_23 (0x10006000+0xEE8) */
+#define PCM_WDT_LATCH_23_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_24 (0x10006000+0xEEC) */
+#define PCM_WDT_LATCH_24_LSB (1U << 0) /* 32b */
+/* PMSR_LAST_DAT (0x10006000+0xF00) */
+#define PMSR_LAST_DAT_LSB (1U << 0) /* 32b */
+/* PMSR_LAST_CNT (0x10006000+0xF04) */
+#define PMSR_LAST_CMD_LSB (1U << 0) /* 30b */
+#define PMSR_LAST_REQ_LSB (1U << 30) /* 1b */
+/* PMSR_LAST_ACK (0x10006000+0xF08) */
+#define PMSR_LAST_ACK_LSB (1U << 0) /* 1b */
+/* SPM_PMSR_SEL_CON0 (0x10006000+0xF10) */
+#define REG_PMSR_SIG_SEL_0_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_1_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_2_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_3_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON1 (0x10006000+0xF14) */
+#define REG_PMSR_SIG_SEL_4_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_5_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_6_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_7_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON2 (0x10006000+0xF18) */
+#define REG_PMSR_SIG_SEL_8_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_9_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_10_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_11_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON3 (0x10006000+0xF1C) */
+#define REG_PMSR_SIG_SEL_12_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_13_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_14_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_15_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON4 (0x10006000+0xF20) */
+#define REG_PMSR_SIG_SEL_16_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_17_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_18_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_19_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON5 (0x10006000+0xF24) */
+#define REG_PMSR_SIG_SEL_20_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_21_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_22_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_23_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON6 (0x10006000+0xF28) */
+#define REG_PMSR_SIG_SEL_24_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_25_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_26_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_27_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON7 (0x10006000+0xF2C) */
+#define REG_PMSR_SIG_SEL_28_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_29_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_30_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_31_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON8 (0x10006000+0xF30) */
+#define REG_PMSR_SIG_SEL_32_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_33_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_34_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_35_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON9 (0x10006000+0xF34) */
+#define REG_PMSR_SIG_SEL_36_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_37_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_38_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_39_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON10 (0x10006000+0xF3C) */
+#define REG_PMSR_SIG_SEL_40_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_41_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_42_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_43_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON11 (0x10006000+0xF40) */
+#define REG_PMSR_SIG_SEL_44_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_45_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_46_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_47_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_TIEMR_STA0 (0x10006000+0xFB8) */
+#define PMSR_TIMER_SET0_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_TIEMR_STA1 (0x10006000+0xFBC) */
+#define PMSR_TIMER_SET1_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_TIEMR_STA2 (0x10006000+0xFC0) */
+#define PMSR_TIMER_SET2_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_GENERAL_CON0 (0x10006000+0xFC4) */
+#define PMSR_ENABLE_SET0_LSB (1U << 0) /* 1b */
+#define PMSR_ENABLE_SET1_LSB (1U << 1) /* 1b */
+#define PMSR_ENABLE_SET2_LSB (1U << 2) /* 1b */
+#define PMSR_IRQ_CLR_SET0_LSB (1U << 3) /* 1b */
+#define PMSR_IRQ_CLR_SET1_LSB (1U << 4) /* 1b */
+#define PMSR_IRQ_CLR_SET2_LSB (1U << 5) /* 1b */
+#define PMSR_SPEED_MODE_EN_SET0_LSB (1U << 6) /* 1b */
+#define PMSR_SPEED_MODE_EN_SET1_LSB (1U << 7) /* 1b */
+#define PMSR_SPEED_MODE_EN_SET2_LSB (1U << 8) /* 1b */
+#define PMSR_EVENT_CLR_SET0_LSB (1U << 9) /* 1b */
+#define PMSR_EVENT_CLR_SET1_LSB (1U << 10) /* 1b */
+#define PMSR_EVENT_CLR_SET2_LSB (1U << 11) /* 1b */
+#define REG_PMSR_IRQ_MASK_SET0_LSB (1U << 12) /* 1b */
+#define REG_PMSR_IRQ_MASK_SET1_LSB (1U << 13) /* 1b */
+#define REG_PMSR_IRQ_MASK_SET2_LSB (1U << 14) /* 1b */
+#define REG_PMSR_IRQ_WAKEUP_EVENT_MASK_SET0_LSB (1U << 15) /* 1b */
+#define REG_PMSR_IRQ_WAKEUP_EVENT_MASK_SET1_LSB (1U << 16) /* 1b */
+#define REG_PMSR_IRQ_WAKEUP_EVENT_MASK_SET2_LSB (1U << 17) /* 1b */
+#define PMSR_GEN_SW_RST_EN_LSB (1U << 18) /* 1b */
+#define PMSR_MODULE_ENABLE_LSB (1U << 19) /* 1b */
+#define PMSR_MODE_LSB (1U << 20) /* 2b */
+#define SPM_PMSR_GENERAL_CON0_PMSR_IRQ_B_SET0_LSB (1U << 29) /* 1b */
+#define SPM_PMSR_GENERAL_CON0_PMSR_IRQ_B_SET1_LSB (1U << 30) /* 1b */
+#define SPM_PMSR_GENERAL_CON0_PMSR_IRQ_B_SET2_LSB (1U << 31) /* 1b */
+/* SPM_PMSR_GENERAL_CON1 (0x10006000+0xFC8) */
+#define PMSR_COUNTER_THRES_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_GENERAL_CON2 (0x10006000+0xFCC) */
+#define PMSR_DEBUG_IN_0_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_GENERAL_CON3 (0x10006000+0xFD0) */
+#define PMSR_DEBUG_IN_1_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_GENERAL_CON4 (0x10006000+0xFD4) */
+#define PMSR_DEBUG_IN_2_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_GENERAL_CON5 (0x10006000+0xFD8) */
+#define PMSR_DEBUG_IN_3_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_SW_RESET (0x10006000+0xFDC) */
+#define PMSR_SW_RST_EN_SET0_LSB (1U << 0) /* 1b */
+#define PMSR_SW_RST_EN_SET1_LSB (1U << 1) /* 1b */
+#define PMSR_SW_RST_EN_SET2_LSB (1U << 2) /* 1b */
+/* SPM_PMSR_MON_CON0 (0x10006000+0xFE0) */
+#define REG_PMSR_MON_TYPE_0_LSB (1U << 0) /* 2b */
+#define REG_PMSR_MON_TYPE_1_LSB (1U << 2) /* 2b */
+#define REG_PMSR_MON_TYPE_2_LSB (1U << 4) /* 2b */
+#define REG_PMSR_MON_TYPE_3_LSB (1U << 6) /* 2b */
+#define REG_PMSR_MON_TYPE_4_LSB (1U << 8) /* 2b */
+#define REG_PMSR_MON_TYPE_5_LSB (1U << 10) /* 2b */
+#define REG_PMSR_MON_TYPE_6_LSB (1U << 12) /* 2b */
+#define REG_PMSR_MON_TYPE_7_LSB (1U << 14) /* 2b */
+#define REG_PMSR_MON_TYPE_8_LSB (1U << 16) /* 2b */
+#define REG_PMSR_MON_TYPE_9_LSB (1U << 18) /* 2b */
+#define REG_PMSR_MON_TYPE_10_LSB (1U << 20) /* 2b */
+#define REG_PMSR_MON_TYPE_11_LSB (1U << 22) /* 2b */
+#define REG_PMSR_MON_TYPE_12_LSB (1U << 24) /* 2b */
+#define REG_PMSR_MON_TYPE_13_LSB (1U << 26) /* 2b */
+#define REG_PMSR_MON_TYPE_14_LSB (1U << 28) /* 2b */
+#define REG_PMSR_MON_TYPE_15_LSB (1U << 30) /* 2b */
+/* SPM_PMSR_MON_CON1 (0x10006000+0xFE4) */
+#define REG_PMSR_MON_TYPE_16_LSB (1U << 0) /* 2b */
+#define REG_PMSR_MON_TYPE_17_LSB (1U << 2) /* 2b */
+#define REG_PMSR_MON_TYPE_18_LSB (1U << 4) /* 2b */
+#define REG_PMSR_MON_TYPE_19_LSB (1U << 6) /* 2b */
+#define REG_PMSR_MON_TYPE_20_LSB (1U << 8) /* 2b */
+#define REG_PMSR_MON_TYPE_21_LSB (1U << 10) /* 2b */
+#define REG_PMSR_MON_TYPE_22_LSB (1U << 12) /* 2b */
+#define REG_PMSR_MON_TYPE_23_LSB (1U << 14) /* 2b */
+#define REG_PMSR_MON_TYPE_24_LSB (1U << 16) /* 2b */
+#define REG_PMSR_MON_TYPE_25_LSB (1U << 18) /* 2b */
+#define REG_PMSR_MON_TYPE_26_LSB (1U << 20) /* 2b */
+#define REG_PMSR_MON_TYPE_27_LSB (1U << 22) /* 2b */
+#define REG_PMSR_MON_TYPE_28_LSB (1U << 24) /* 2b */
+#define REG_PMSR_MON_TYPE_29_LSB (1U << 26) /* 2b */
+#define REG_PMSR_MON_TYPE_30_LSB (1U << 28) /* 2b */
+#define REG_PMSR_MON_TYPE_31_LSB (1U << 30) /* 2b */
+/* SPM_PMSR_MON_CON2 (0x10006000+0xFE8) */
+#define REG_PMSR_MON_TYPE_32_LSB (1U << 0) /* 2b */
+#define REG_PMSR_MON_TYPE_33_LSB (1U << 2) /* 2b */
+#define REG_PMSR_MON_TYPE_34_LSB (1U << 4) /* 2b */
+#define REG_PMSR_MON_TYPE_35_LSB (1U << 6) /* 2b */
+#define REG_PMSR_MON_TYPE_36_LSB (1U << 8) /* 2b */
+#define REG_PMSR_MON_TYPE_37_LSB (1U << 10) /* 2b */
+#define REG_PMSR_MON_TYPE_38_LSB (1U << 12) /* 2b */
+#define REG_PMSR_MON_TYPE_39_LSB (1U << 14) /* 2b */
+#define REG_PMSR_MON_TYPE_40_LSB (1U << 16) /* 2b */
+#define REG_PMSR_MON_TYPE_41_LSB (1U << 18) /* 2b */
+#define REG_PMSR_MON_TYPE_42_LSB (1U << 20) /* 2b */
+#define REG_PMSR_MON_TYPE_43_LSB (1U << 22) /* 2b */
+#define REG_PMSR_MON_TYPE_44_LSB (1U << 24) /* 2b */
+#define REG_PMSR_MON_TYPE_45_LSB (1U << 26) /* 2b */
+#define REG_PMSR_MON_TYPE_46_LSB (1U << 28) /* 2b */
+#define REG_PMSR_MON_TYPE_47_LSB (1U << 30) /* 2b */
+/* SPM_PMSR_LEN_CON0 (0x10006000+0xFEC) */
+#define REG_PMSR_WINDOW_LEN_SET0_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_LEN_CON1 (0x10006000+0xFF0) */
+#define REG_PMSR_WINDOW_LEN_SET1_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_LEN_CON2 (0x10006000+0xFF4) */
+#define REG_PMSR_WINDOW_LEN_SET2_LSB (1U << 0) /* 32b */
+
+#define SPM_PROJECT_CODE 0xb16
+#define SPM_REGWR_CFG_KEY (SPM_PROJECT_CODE << 16)
+#endif /* MT_SPM_REG */
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm_resource_req.h b/plat/mediatek/mt8192/drivers/spm/mt_spm_resource_req.h
new file mode 100644
index 0000000..30194eb
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm_resource_req.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_RESOURCE_REQ_H
+#define MT_SPM_RESOURCE_REQ_H
+
+/* SPM resource request internal bit */
+#define MT_SPM_BIT_XO_FPM 0
+#define MT_SPM_BIT_26M 1
+#define MT_SPM_BIT_INFRA 2
+#define MT_SPM_BIT_SYSPLL 3
+#define MT_SPM_BIT_DRAM_S0 4
+#define MT_SPM_BIT_DRAM_S1 5
+
+/* SPM resource request internal bit_mask */
+#define MT_SPM_XO_FPM BIT(MT_SPM_BIT_XO_FPM)
+#define MT_SPM_26M BIT(MT_SPM_BIT_26M)
+#define MT_SPM_INFRA BIT(MT_SPM_BIT_INFRA)
+#define MT_SPM_SYSPLL BIT(MT_SPM_BIT_SYSPLL)
+#define MT_SPM_DRAM_S0 BIT(MT_SPM_BIT_DRAM_S0)
+#define MT_SPM_DRAM_S1 BIT(MT_SPM_BIT_DRAM_S1)
+#endif /* MT_SPM_RESOURCE_REQ_H */
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm_suspend.c b/plat/mediatek/mt8192/drivers/spm/mt_spm_suspend.c
new file mode 100644
index 0000000..3eb73d4
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm_suspend.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mt_spm.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_rc_internal.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_suspend.h>
+#include <plat_pm.h>
+#include <uart.h>
+
+#define SPM_SUSPEND_SLEEP_PCM_FLAG \
+ (SPM_FLAG_DISABLE_INFRA_PDN | \
+ SPM_FLAG_DISABLE_VCORE_DVS | \
+ SPM_FLAG_DISABLE_VCORE_DFS | \
+ SPM_FLAG_KEEP_CSYSPWRACK_HIGH | \
+ SPM_FLAG_USE_SRCCLKENO2 | \
+ SPM_FLAG_ENABLE_MD_MUMTAS | \
+ SPM_FLAG_SRAM_SLEEP_CTRL)
+
+#define SPM_SUSPEND_SLEEP_PCM_FLAG1 \
+ (SPM_FLAG1_DISABLE_MD26M_CK_OFF)
+
+#define SPM_SUSPEND_PCM_FLAG \
+ (SPM_FLAG_DISABLE_VCORE_DVS | \
+ SPM_FLAG_DISABLE_VCORE_DFS | \
+ SPM_FLAG_ENABLE_TIA_WORKAROUND | \
+ SPM_FLAG_ENABLE_MD_MUMTAS | \
+ SPM_FLAG_SRAM_SLEEP_CTRL)
+
+#define SPM_SUSPEND_PCM_FLAG1 \
+ (SPM_FLAG1_DISABLE_MD26M_CK_OFF)
+
+#define __WAKE_SRC_FOR_SUSPEND_COMMON__ \
+ (R12_PCM_TIMER | \
+ R12_KP_IRQ_B | \
+ R12_APWDT_EVENT_B | \
+ R12_APXGPT1_EVENT_B | \
+ R12_CONN2AP_SPM_WAKEUP_B | \
+ R12_EINT_EVENT_B | \
+ R12_CONN_WDT_IRQ_B | \
+ R12_CCIF0_EVENT_B | \
+ R12_SSPM2SPM_WAKEUP_B | \
+ R12_SCP2SPM_WAKEUP_B | \
+ R12_ADSP2SPM_WAKEUP_B | \
+ R12_USBX_CDSC_B | \
+ R12_USBX_POWERDWN_B | \
+ R12_SYS_TIMER_EVENT_B | \
+ R12_EINT_EVENT_SECURE_B | \
+ R12_CCIF1_EVENT_B | \
+ R12_SYS_CIRQ_IRQ_B | \
+ R12_MD2AP_PEER_EVENT_B | \
+ R12_MD1_WDT_B | \
+ R12_CLDMA_EVENT_B | \
+ R12_REG_CPU_WAKEUP | \
+ R12_APUSYS_WAKE_HOST_B | \
+ R12_PCIE_BRIDGE_IRQ | \
+ R12_PCIE_IRQ)
+
+#if defined(CFG_MICROTRUST_TEE_SUPPORT)
+#define WAKE_SRC_FOR_SUSPEND (__WAKE_SRC_FOR_SUSPEND_COMMON__)
+#else
+#define WAKE_SRC_FOR_SUSPEND \
+ (__WAKE_SRC_FOR_SUSPEND_COMMON__ | \
+ R12_SEJ_EVENT_B)
+#endif
+
+static struct pwr_ctrl suspend_ctrl = {
+ .wake_src = WAKE_SRC_FOR_SUSPEND,
+ .pcm_flags = SPM_SUSPEND_PCM_FLAG | SPM_FLAG_DISABLE_INFRA_PDN,
+ .pcm_flags1 = SPM_SUSPEND_PCM_FLAG1,
+
+ /* Auto-gen Start */
+
+ /* SPM_AP_STANDBY_CON */
+ .reg_wfi_op = 0,
+ .reg_wfi_type = 0,
+ .reg_mp0_cputop_idle_mask = 0,
+ .reg_mp1_cputop_idle_mask = 0,
+ .reg_mcusys_idle_mask = 0,
+ .reg_md_apsrc_1_sel = 0,
+ .reg_md_apsrc_0_sel = 0,
+ .reg_conn_apsrc_sel = 0,
+
+ /* SPM_SRC6_MASK */
+ .reg_dpmaif_srcclkena_mask_b = 1,
+ .reg_dpmaif_infra_req_mask_b = 1,
+ .reg_dpmaif_apsrc_req_mask_b = 1,
+ .reg_dpmaif_vrf18_req_mask_b = 1,
+ .reg_dpmaif_ddr_en_mask_b = 1,
+
+ /* SPM_SRC_REQ */
+ .reg_spm_apsrc_req = 0,
+ .reg_spm_f26m_req = 0,
+ .reg_spm_infra_req = 0,
+ .reg_spm_vrf18_req = 0,
+ .reg_spm_ddr_en_req = 0,
+ .reg_spm_dvfs_req = 0,
+ .reg_spm_sw_mailbox_req = 0,
+ .reg_spm_sspm_mailbox_req = 0,
+ .reg_spm_adsp_mailbox_req = 0,
+ .reg_spm_scp_mailbox_req = 0,
+
+ /* SPM_SRC_MASK */
+ .reg_md_srcclkena_0_mask_b = 1,
+ .reg_md_srcclkena2infra_req_0_mask_b = 0,
+ .reg_md_apsrc2infra_req_0_mask_b = 1,
+ .reg_md_apsrc_req_0_mask_b = 1,
+ .reg_md_vrf18_req_0_mask_b = 1,
+ .reg_md_ddr_en_0_mask_b = 1,
+ .reg_md_srcclkena_1_mask_b = 0,
+ .reg_md_srcclkena2infra_req_1_mask_b = 0,
+ .reg_md_apsrc2infra_req_1_mask_b = 0,
+ .reg_md_apsrc_req_1_mask_b = 0,
+ .reg_md_vrf18_req_1_mask_b = 0,
+ .reg_md_ddr_en_1_mask_b = 0,
+ .reg_conn_srcclkena_mask_b = 1,
+ .reg_conn_srcclkenb_mask_b = 0,
+ .reg_conn_infra_req_mask_b = 1,
+ .reg_conn_apsrc_req_mask_b = 1,
+ .reg_conn_vrf18_req_mask_b = 1,
+ .reg_conn_ddr_en_mask_b = 1,
+ .reg_conn_vfe28_mask_b = 0,
+ .reg_srcclkeni0_srcclkena_mask_b = 1,
+ .reg_srcclkeni0_infra_req_mask_b = 1,
+ .reg_srcclkeni1_srcclkena_mask_b = 0,
+ .reg_srcclkeni1_infra_req_mask_b = 0,
+ .reg_srcclkeni2_srcclkena_mask_b = 0,
+ .reg_srcclkeni2_infra_req_mask_b = 0,
+ .reg_infrasys_apsrc_req_mask_b = 0,
+ .reg_infrasys_ddr_en_mask_b = 1,
+ .reg_md32_srcclkena_mask_b = 1,
+ .reg_md32_infra_req_mask_b = 1,
+ .reg_md32_apsrc_req_mask_b = 1,
+ .reg_md32_vrf18_req_mask_b = 1,
+ .reg_md32_ddr_en_mask_b = 1,
+
+ /* SPM_SRC2_MASK */
+ .reg_scp_srcclkena_mask_b = 1,
+ .reg_scp_infra_req_mask_b = 1,
+ .reg_scp_apsrc_req_mask_b = 1,
+ .reg_scp_vrf18_req_mask_b = 1,
+ .reg_scp_ddr_en_mask_b = 1,
+ .reg_audio_dsp_srcclkena_mask_b = 1,
+ .reg_audio_dsp_infra_req_mask_b = 1,
+ .reg_audio_dsp_apsrc_req_mask_b = 1,
+ .reg_audio_dsp_vrf18_req_mask_b = 1,
+ .reg_audio_dsp_ddr_en_mask_b = 1,
+ .reg_ufs_srcclkena_mask_b = 1,
+ .reg_ufs_infra_req_mask_b = 1,
+ .reg_ufs_apsrc_req_mask_b = 1,
+ .reg_ufs_vrf18_req_mask_b = 1,
+ .reg_ufs_ddr_en_mask_b = 1,
+ .reg_disp0_apsrc_req_mask_b = 1,
+ .reg_disp0_ddr_en_mask_b = 1,
+ .reg_disp1_apsrc_req_mask_b = 1,
+ .reg_disp1_ddr_en_mask_b = 1,
+ .reg_gce_infra_req_mask_b = 1,
+ .reg_gce_apsrc_req_mask_b = 1,
+ .reg_gce_vrf18_req_mask_b = 1,
+ .reg_gce_ddr_en_mask_b = 1,
+ .reg_apu_srcclkena_mask_b = 1,
+ .reg_apu_infra_req_mask_b = 1,
+ .reg_apu_apsrc_req_mask_b = 1,
+ .reg_apu_vrf18_req_mask_b = 1,
+ .reg_apu_ddr_en_mask_b = 1,
+ .reg_cg_check_srcclkena_mask_b = 0,
+ .reg_cg_check_apsrc_req_mask_b = 0,
+ .reg_cg_check_vrf18_req_mask_b = 0,
+ .reg_cg_check_ddr_en_mask_b = 0,
+
+ /* SPM_SRC3_MASK */
+ .reg_dvfsrc_event_trigger_mask_b = 1,
+ .reg_sw2spm_int0_mask_b = 0,
+ .reg_sw2spm_int1_mask_b = 0,
+ .reg_sw2spm_int2_mask_b = 0,
+ .reg_sw2spm_int3_mask_b = 0,
+ .reg_sc_adsp2spm_wakeup_mask_b = 0,
+ .reg_sc_sspm2spm_wakeup_mask_b = 0,
+ .reg_sc_scp2spm_wakeup_mask_b = 0,
+ .reg_csyspwrreq_mask = 1,
+ .reg_spm_srcclkena_reserved_mask_b = 0,
+ .reg_spm_infra_req_reserved_mask_b = 0,
+ .reg_spm_apsrc_req_reserved_mask_b = 0,
+ .reg_spm_vrf18_req_reserved_mask_b = 0,
+ .reg_spm_ddr_en_reserved_mask_b = 0,
+ .reg_mcupm_srcclkena_mask_b = 1,
+ .reg_mcupm_infra_req_mask_b = 1,
+ .reg_mcupm_apsrc_req_mask_b = 1,
+ .reg_mcupm_vrf18_req_mask_b = 1,
+ .reg_mcupm_ddr_en_mask_b = 1,
+ .reg_msdc0_srcclkena_mask_b = 1,
+ .reg_msdc0_infra_req_mask_b = 1,
+ .reg_msdc0_apsrc_req_mask_b = 1,
+ .reg_msdc0_vrf18_req_mask_b = 1,
+ .reg_msdc0_ddr_en_mask_b = 1,
+ .reg_msdc1_srcclkena_mask_b = 1,
+ .reg_msdc1_infra_req_mask_b = 1,
+ .reg_msdc1_apsrc_req_mask_b = 1,
+ .reg_msdc1_vrf18_req_mask_b = 1,
+ .reg_msdc1_ddr_en_mask_b = 1,
+
+ /* SPM_SRC4_MASK */
+ .ccif_event_mask_b = 0xFFF,
+ .reg_bak_psri_srcclkena_mask_b = 0,
+ .reg_bak_psri_infra_req_mask_b = 0,
+ .reg_bak_psri_apsrc_req_mask_b = 0,
+ .reg_bak_psri_vrf18_req_mask_b = 0,
+ .reg_bak_psri_ddr_en_mask_b = 0,
+ .reg_dramc0_md32_infra_req_mask_b = 1,
+ .reg_dramc0_md32_vrf18_req_mask_b = 0,
+ .reg_dramc1_md32_infra_req_mask_b = 1,
+ .reg_dramc1_md32_vrf18_req_mask_b = 0,
+ .reg_conn_srcclkenb2pwrap_mask_b = 0,
+ .reg_dramc0_md32_wakeup_mask = 1,
+ .reg_dramc1_md32_wakeup_mask = 1,
+
+ /* SPM_SRC5_MASK */
+ .reg_mcusys_merge_apsrc_req_mask_b = 0x11,
+ .reg_mcusys_merge_ddr_en_mask_b = 0x11,
+ .reg_msdc2_srcclkena_mask_b = 1,
+ .reg_msdc2_infra_req_mask_b = 1,
+ .reg_msdc2_apsrc_req_mask_b = 1,
+ .reg_msdc2_vrf18_req_mask_b = 1,
+ .reg_msdc2_ddr_en_mask_b = 1,
+ .reg_pcie_srcclkena_mask_b = 1,
+ .reg_pcie_infra_req_mask_b = 1,
+ .reg_pcie_apsrc_req_mask_b = 1,
+ .reg_pcie_vrf18_req_mask_b = 1,
+ .reg_pcie_ddr_en_mask_b = 1,
+
+ /* SPM_WAKEUP_EVENT_MASK */
+ .reg_wakeup_event_mask = 0x01382202,
+
+ /* SPM_WAKEUP_EVENT_EXT_MASK */
+ .reg_ext_wakeup_event_mask = 0xFFFFFFFF,
+
+ /* Auto-gen End */
+};
+
+struct spm_lp_scen __spm_suspend = {
+ .pwrctrl = &suspend_ctrl,
+};
+
+int mt_spm_suspend_mode_set(int mode)
+{
+ if (mode == MT_SPM_SUSPEND_SLEEP) {
+ suspend_ctrl.pcm_flags = SPM_SUSPEND_SLEEP_PCM_FLAG;
+ suspend_ctrl.pcm_flags1 = SPM_SUSPEND_SLEEP_PCM_FLAG1;
+ } else {
+ suspend_ctrl.pcm_flags = SPM_SUSPEND_PCM_FLAG;
+ suspend_ctrl.pcm_flags1 = SPM_SUSPEND_PCM_FLAG1;
+ }
+
+ return 0;
+}
+
+int mt_spm_suspend_enter(int state_id, unsigned int ext_opand,
+ unsigned int resource_req)
+{
+ /* If FMAudio / ADSP is active, change to sleep suspend mode */
+ if ((ext_opand & MT_SPM_EX_OP_SET_SUSPEND_MODE) != 0U) {
+ mt_spm_suspend_mode_set(MT_SPM_SUSPEND_SLEEP);
+ }
+
+ /* Notify MCUPM that device is going suspend flow */
+ mmio_write_32(MCUPM_MBOX_OFFSET_PDN, MCUPM_POWER_DOWN);
+
+ /* Notify UART to sleep */
+ mt_uart_save();
+
+ return spm_conservation(state_id, ext_opand,
+ &__spm_suspend, resource_req);
+}
+
+void mt_spm_suspend_resume(int state_id, unsigned int ext_opand,
+ struct wake_status **status)
+{
+ spm_conservation_finish(state_id, ext_opand, &__spm_suspend, status);
+
+ /* Notify UART to wakeup */
+ mt_uart_restore();
+
+ /* Notify MCUPM that device leave suspend */
+ mmio_write_32(MCUPM_MBOX_OFFSET_PDN, 0);
+
+ /* If FMAudio / ADSP is active, change back to suspend mode */
+ if ((ext_opand & MT_SPM_EX_OP_SET_SUSPEND_MODE) != 0U) {
+ mt_spm_suspend_mode_set(MT_SPM_SUSPEND_SYSTEM_PDN);
+ }
+}
+
+void mt_spm_suspend_init(void)
+{
+ spm_conservation_pwrctrl_init(__spm_suspend.pwrctrl);
+}
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm_suspend.h b/plat/mediatek/mt8192/drivers/spm/mt_spm_suspend.h
new file mode 100644
index 0000000..08bbad2
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm_suspend.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_SUSPEND_H
+#define MT_SPM_SUSPEND_H
+
+#include <mt_spm_internal.h>
+
+#define MCUPM_MBOX_OFFSET_PDN 0x0C55FDA8
+#define MCUPM_POWER_DOWN 0x4D50444E
+
+enum MT_SPM_SUSPEND_MODE {
+ MT_SPM_SUSPEND_SYSTEM_PDN,
+ MT_SPM_SUSPEND_SLEEP,
+};
+
+extern int mt_spm_suspend_mode_set(int mode);
+extern int mt_spm_suspend_enter(int state_id, unsigned int ext_opand,
+ unsigned int reosuce_req);
+extern void mt_spm_suspend_resume(int state_id, unsigned int ext_opand,
+ struct wake_status **status);
+extern void mt_spm_suspend_init(void);
+#endif /* MT_SPM_SUSPEND_H */
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm_vcorefs.c b/plat/mediatek/mt8192/drivers/spm/mt_spm_vcorefs.c
new file mode 100644
index 0000000..f74ea80
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm_vcorefs.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright(C)2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <lib/utils_def.h>
+
+#include <mtk_sip_svc.h>
+#include <plat_pm.h>
+#include <platform_def.h>
+
+#include "mt_spm.h"
+#include "mt_spm_internal.h"
+#include "mt_spm_reg.h"
+#include "mt_spm_vcorefs.h"
+#include "mt_spm_pmic_wrap.h"
+
+#define VCORE_CT_ENABLE (1U << 5)
+#define SW_REQ5_INIT_VAL (6U << 12)
+#define V_VMODE_SHIFT 0
+#define VCORE_HV 105
+#define VCORE_LV 95
+#define PMIC_STEP_UV 6250
+
+static const struct reg_config dvfsrc_init_configs[] = {
+ /* Setup opp table */
+ { DVFSRC_LEVEL_LABEL_0_1, 0x50436053 },
+ { DVFSRC_LEVEL_LABEL_2_3, 0x40335042 },
+ { DVFSRC_LEVEL_LABEL_4_5, 0x40314032 },
+ { DVFSRC_LEVEL_LABEL_6_7, 0x30223023 },
+ { DVFSRC_LEVEL_LABEL_8_9, 0x20133021 },
+ { DVFSRC_LEVEL_LABEL_10_11, 0x20112012 },
+ { DVFSRC_LEVEL_LABEL_12_13, 0x10032010 },
+ { DVFSRC_LEVEL_LABEL_14_15, 0x10011002 },
+ { DVFSRC_LEVEL_LABEL_16_17, 0x00131000 },
+ { DVFSRC_LEVEL_LABEL_18_19, 0x00110012 },
+ { DVFSRC_LEVEL_LABEL_20_21, 0x00000010 },
+
+ /* Setup hw emi qos policy */
+ { DVFSRC_DDR_REQUEST, 0x00004321 },
+ { DVFSRC_DDR_REQUEST3, 0x00000065 },
+
+ /* Setup up for PCIe */
+ { DVFSRC_PCIE_VCORE_REQ, 0x0A298001 },
+
+ /* Setup up HRT QOS policy */
+ { DVFSRC_HRT_BW_BASE, 0x00000004 },
+ { DVFSRC_HRT_REQ_UNIT, 0x0000001E },
+ { DVFSRC_HRT_HIGH_3, 0x18A618A6 },
+ { DVFSRC_HRT_HIGH_2, 0x18A61183 },
+ { DVFSRC_HRT_HIGH_1, 0x0D690B80 },
+ { DVFSRC_HRT_HIGH, 0x070804B0 },
+ { DVFSRC_HRT_LOW_3, 0x18A518A5 },
+ { DVFSRC_HRT_LOW_2, 0x18A51182 },
+ { DVFSRC_HRT_LOW_1, 0x0D680B7F },
+ { DVFSRC_HRT_LOW, 0x070704AF },
+ { DVFSRC_HRT_REQUEST, 0x66654321 },
+ /* Setup up SRT QOS policy */
+ { DVFSRC_QOS_EN, 0x0011007C },
+ { DVFSRC_DDR_QOS0, 0x00000019 },
+ { DVFSRC_DDR_QOS1, 0x00000026 },
+ { DVFSRC_DDR_QOS2, 0x00000033 },
+ { DVFSRC_DDR_QOS3, 0x0000003B },
+ { DVFSRC_DDR_QOS4, 0x0000004C },
+ { DVFSRC_DDR_QOS5, 0x00000066 },
+ { DVFSRC_DDR_QOS6, 0x00000066 },
+ { DVFSRC_DDR_REQUEST5, 0x54321000 },
+ { DVFSRC_DDR_REQUEST7, 0x66000000 },
+ /* Setup up hifi request policy */
+ { DVFSRC_DDR_REQUEST6, 0x66543210 },
+ /* Setup up hw request vcore policy */
+ { DVFSRC_VCORE_USER_REQ, 0x00010A29 },
+
+ /* Setup misc*/
+ { DVFSRC_TIMEOUT_NEXTREQ, 0x00000015 },
+ { DVFSRC_RSRV_5, 0x00000001 },
+ { DVFSRC_INT_EN, 0x00000002 },
+ /* Init opp and enable dvfsrc*/
+ { DVFSRC_CURRENT_FORCE, 0x00000001 },
+ { DVFSRC_BASIC_CONTROL, 0x0298444B },
+ { DVFSRC_BASIC_CONTROL, 0x0298054B },
+ { DVFSRC_CURRENT_FORCE, 0x00000000 },
+};
+
+static struct pwr_ctrl vcorefs_ctrl = {
+ .wake_src = R12_REG_CPU_WAKEUP,
+
+ /* default VCORE DVFS is disabled */
+ .pcm_flags = (SPM_FLAG_RUN_COMMON_SCENARIO |
+ SPM_FLAG_DISABLE_VCORE_DVS |
+ SPM_FLAG_DISABLE_VCORE_DFS),
+
+ /* Auto-gen Start */
+
+ /* SPM_AP_STANDBY_CON */
+ .reg_wfi_op = 0,
+ .reg_wfi_type = 0,
+ .reg_mp0_cputop_idle_mask = 0,
+ .reg_mp1_cputop_idle_mask = 0,
+ .reg_mcusys_idle_mask = 0,
+ .reg_md_apsrc_1_sel = 0,
+ .reg_md_apsrc_0_sel = 0,
+ .reg_conn_apsrc_sel = 0,
+
+ /* SPM_SRC_REQ */
+ .reg_spm_apsrc_req = 0,
+ .reg_spm_f26m_req = 0,
+ .reg_spm_infra_req = 0,
+ .reg_spm_vrf18_req = 0,
+ .reg_spm_ddr_en_req = 1,
+ .reg_spm_dvfs_req = 0,
+ .reg_spm_sw_mailbox_req = 0,
+ .reg_spm_sspm_mailbox_req = 0,
+ .reg_spm_adsp_mailbox_req = 0,
+ .reg_spm_scp_mailbox_req = 0,
+
+ /* SPM_SRC6_MASK */
+ .reg_dpmaif_srcclkena_mask_b = 1,
+ .reg_dpmaif_infra_req_mask_b = 1,
+ .reg_dpmaif_apsrc_req_mask_b = 1,
+ .reg_dpmaif_vrf18_req_mask_b = 1,
+ .reg_dpmaif_ddr_en_mask_b = 1,
+
+ /* SPM_SRC_MASK */
+ .reg_md_srcclkena_0_mask_b = 1,
+ .reg_md_srcclkena2infra_req_0_mask_b = 0,
+ .reg_md_apsrc2infra_req_0_mask_b = 1,
+ .reg_md_apsrc_req_0_mask_b = 1,
+ .reg_md_vrf18_req_0_mask_b = 1,
+ .reg_md_ddr_en_0_mask_b = 1,
+ .reg_md_srcclkena_1_mask_b = 0,
+ .reg_md_srcclkena2infra_req_1_mask_b = 0,
+ .reg_md_apsrc2infra_req_1_mask_b = 0,
+ .reg_md_apsrc_req_1_mask_b = 0,
+ .reg_md_vrf18_req_1_mask_b = 0,
+ .reg_md_ddr_en_1_mask_b = 0,
+ .reg_conn_srcclkena_mask_b = 1,
+ .reg_conn_srcclkenb_mask_b = 0,
+ .reg_conn_infra_req_mask_b = 1,
+ .reg_conn_apsrc_req_mask_b = 1,
+ .reg_conn_vrf18_req_mask_b = 1,
+ .reg_conn_ddr_en_mask_b = 1,
+ .reg_conn_vfe28_mask_b = 0,
+ .reg_srcclkeni0_srcclkena_mask_b = 1,
+ .reg_srcclkeni0_infra_req_mask_b = 1,
+ .reg_srcclkeni1_srcclkena_mask_b = 0,
+ .reg_srcclkeni1_infra_req_mask_b = 0,
+ .reg_srcclkeni2_srcclkena_mask_b = 0,
+ .reg_srcclkeni2_infra_req_mask_b = 0,
+ .reg_infrasys_apsrc_req_mask_b = 0,
+ .reg_infrasys_ddr_en_mask_b = 1,
+ .reg_md32_srcclkena_mask_b = 1,
+ .reg_md32_infra_req_mask_b = 1,
+ .reg_md32_apsrc_req_mask_b = 1,
+ .reg_md32_vrf18_req_mask_b = 1,
+ .reg_md32_ddr_en_mask_b = 1,
+
+ /* SPM_SRC2_MASK */
+ .reg_scp_srcclkena_mask_b = 1,
+ .reg_scp_infra_req_mask_b = 1,
+ .reg_scp_apsrc_req_mask_b = 1,
+ .reg_scp_vrf18_req_mask_b = 1,
+ .reg_scp_ddr_en_mask_b = 1,
+ .reg_audio_dsp_srcclkena_mask_b = 1,
+ .reg_audio_dsp_infra_req_mask_b = 1,
+ .reg_audio_dsp_apsrc_req_mask_b = 1,
+ .reg_audio_dsp_vrf18_req_mask_b = 1,
+ .reg_audio_dsp_ddr_en_mask_b = 1,
+ .reg_ufs_srcclkena_mask_b = 1,
+ .reg_ufs_infra_req_mask_b = 1,
+ .reg_ufs_apsrc_req_mask_b = 1,
+ .reg_ufs_vrf18_req_mask_b = 1,
+ .reg_ufs_ddr_en_mask_b = 1,
+ .reg_disp0_apsrc_req_mask_b = 1,
+ .reg_disp0_ddr_en_mask_b = 1,
+ .reg_disp1_apsrc_req_mask_b = 1,
+ .reg_disp1_ddr_en_mask_b = 1,
+ .reg_gce_infra_req_mask_b = 1,
+ .reg_gce_apsrc_req_mask_b = 1,
+ .reg_gce_vrf18_req_mask_b = 1,
+ .reg_gce_ddr_en_mask_b = 1,
+ .reg_apu_srcclkena_mask_b = 1,
+ .reg_apu_infra_req_mask_b = 1,
+ .reg_apu_apsrc_req_mask_b = 1,
+ .reg_apu_vrf18_req_mask_b = 1,
+ .reg_apu_ddr_en_mask_b = 1,
+ .reg_cg_check_srcclkena_mask_b = 0,
+ .reg_cg_check_apsrc_req_mask_b = 0,
+ .reg_cg_check_vrf18_req_mask_b = 0,
+ .reg_cg_check_ddr_en_mask_b = 0,
+
+ /* SPM_SRC3_MASK */
+ .reg_dvfsrc_event_trigger_mask_b = 1,
+ .reg_sw2spm_int0_mask_b = 0,
+ .reg_sw2spm_int1_mask_b = 0,
+ .reg_sw2spm_int2_mask_b = 0,
+ .reg_sw2spm_int3_mask_b = 0,
+ .reg_sc_adsp2spm_wakeup_mask_b = 0,
+ .reg_sc_sspm2spm_wakeup_mask_b = 0,
+ .reg_sc_scp2spm_wakeup_mask_b = 0,
+ .reg_csyspwrreq_mask = 1,
+ .reg_spm_srcclkena_reserved_mask_b = 0,
+ .reg_spm_infra_req_reserved_mask_b = 0,
+ .reg_spm_apsrc_req_reserved_mask_b = 0,
+ .reg_spm_vrf18_req_reserved_mask_b = 0,
+ .reg_spm_ddr_en_reserved_mask_b = 0,
+ .reg_mcupm_srcclkena_mask_b = 1,
+ .reg_mcupm_infra_req_mask_b = 1,
+ .reg_mcupm_apsrc_req_mask_b = 1,
+ .reg_mcupm_vrf18_req_mask_b = 1,
+ .reg_mcupm_ddr_en_mask_b = 1,
+ .reg_msdc0_srcclkena_mask_b = 1,
+ .reg_msdc0_infra_req_mask_b = 1,
+ .reg_msdc0_apsrc_req_mask_b = 1,
+ .reg_msdc0_vrf18_req_mask_b = 1,
+ .reg_msdc0_ddr_en_mask_b = 1,
+ .reg_msdc1_srcclkena_mask_b = 1,
+ .reg_msdc1_infra_req_mask_b = 1,
+ .reg_msdc1_apsrc_req_mask_b = 1,
+ .reg_msdc1_vrf18_req_mask_b = 1,
+ .reg_msdc1_ddr_en_mask_b = 1,
+
+ /* SPM_SRC4_MASK */
+ .ccif_event_mask_b = 0xFFF,
+ .reg_bak_psri_srcclkena_mask_b = 0,
+ .reg_bak_psri_infra_req_mask_b = 0,
+ .reg_bak_psri_apsrc_req_mask_b = 0,
+ .reg_bak_psri_vrf18_req_mask_b = 0,
+ .reg_bak_psri_ddr_en_mask_b = 0,
+ .reg_dramc0_md32_infra_req_mask_b = 1,
+ .reg_dramc0_md32_vrf18_req_mask_b = 0,
+ .reg_dramc1_md32_infra_req_mask_b = 1,
+ .reg_dramc1_md32_vrf18_req_mask_b = 0,
+ .reg_conn_srcclkenb2pwrap_mask_b = 0,
+ .reg_dramc0_md32_wakeup_mask = 1,
+ .reg_dramc1_md32_wakeup_mask = 1,
+
+ /* SPM_SRC5_MASK */
+ .reg_mcusys_merge_apsrc_req_mask_b = 0x11,
+ .reg_mcusys_merge_ddr_en_mask_b = 0x11,
+ .reg_msdc2_srcclkena_mask_b = 1,
+ .reg_msdc2_infra_req_mask_b = 1,
+ .reg_msdc2_apsrc_req_mask_b = 1,
+ .reg_msdc2_vrf18_req_mask_b = 1,
+ .reg_msdc2_ddr_en_mask_b = 1,
+ .reg_pcie_srcclkena_mask_b = 1,
+ .reg_pcie_infra_req_mask_b = 1,
+ .reg_pcie_apsrc_req_mask_b = 1,
+ .reg_pcie_vrf18_req_mask_b = 1,
+ .reg_pcie_ddr_en_mask_b = 1,
+
+ /* SPM_WAKEUP_EVENT_MASK */
+ .reg_wakeup_event_mask = 0xEFFFFFFF,
+
+ /* SPM_WAKEUP_EVENT_EXT_MASK */
+ .reg_ext_wakeup_event_mask = 0xFFFFFFFF,
+
+ /* Auto-gen End */
+};
+
+struct spm_lp_scen __spm_vcorefs = {
+ .pwrctrl = &vcorefs_ctrl,
+};
+
+static void spm_vcorefs_pwarp_cmd(uint64_t cmd, uint64_t val)
+{
+ if (cmd < NR_IDX_ALL) {
+ mt_spm_pmic_wrap_set_cmd(PMIC_WRAP_PHASE_ALLINONE, cmd, val);
+ } else {
+ INFO("cmd out of range!\n");
+ }
+}
+
+void spm_dvfsfw_init(uint64_t boot_up_opp, uint64_t dram_issue)
+{
+ mmio_clrsetbits_32(SPM_DVFS_MISC, SPM_DVFS_FORCE_ENABLE_LSB,
+ SPM_DVFSRC_ENABLE_LSB);
+
+ mmio_write_32(SPM_DVFS_LEVEL, 0x00000001);
+ mmio_write_32(SPM_DVS_DFS_LEVEL, 0x00010001);
+}
+
+void __spm_sync_vcore_dvfs_power_control(struct pwr_ctrl *dest_pwr_ctrl,
+ const struct pwr_ctrl *src_pwr_ctrl)
+{
+ uint32_t dvfs_mask = SPM_FLAG_DISABLE_VCORE_DVS |
+ SPM_FLAG_DISABLE_VCORE_DFS |
+ SPM_FLAG_ENABLE_VOLTAGE_BIN;
+
+ dest_pwr_ctrl->pcm_flags = (dest_pwr_ctrl->pcm_flags & (~dvfs_mask)) |
+ (src_pwr_ctrl->pcm_flags & dvfs_mask);
+
+ if (dest_pwr_ctrl->pcm_flags_cust > 0U) {
+ dest_pwr_ctrl->pcm_flags_cust =
+ (dest_pwr_ctrl->pcm_flags_cust & (~dvfs_mask)) |
+ (src_pwr_ctrl->pcm_flags & dvfs_mask);
+ }
+}
+
+static void spm_go_to_vcorefs(void)
+{
+ __spm_set_power_control(__spm_vcorefs.pwrctrl);
+ __spm_set_wakeup_event(__spm_vcorefs.pwrctrl);
+ __spm_set_pcm_flags(__spm_vcorefs.pwrctrl);
+ __spm_send_cpu_wakeup_event();
+}
+
+static void dvfsrc_init(void)
+{
+ uint32_t i;
+
+ for (i = 0U; i < ARRAY_SIZE(dvfsrc_init_configs); i++) {
+ mmio_write_32(dvfsrc_init_configs[i].offset,
+ dvfsrc_init_configs[i].val);
+ }
+}
+
+static uint32_t spm_vcorefs_get_efuse_data(void)
+{
+ return mmio_read_32(VCORE_VB_EFUSE);
+}
+
+static uint32_t is_rising_need(void)
+{
+ return ((spm_vcorefs_get_efuse_data() & 0xF) == 11U) ? 1U : 0U;
+}
+
+static void spm_vcorefs_vcore_setting(uint64_t flag)
+{
+ uint32_t dvfs_v_mode, dvfsrc_rsrv, i;
+ uint32_t opp_uv[] = {725000U, 650000U, 600000U, 575000U};
+
+ dvfsrc_rsrv = mmio_read_32(DVFSRC_RSRV_4);
+
+ dvfs_v_mode = (dvfsrc_rsrv >> V_VMODE_SHIFT) & 0x3;
+
+ if (is_rising_need() != 0U) {
+ opp_uv[2] = 625000U;
+ opp_uv[3] = 600000U;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(opp_uv); i++) {
+ if (dvfs_v_mode == 3U) {
+ /* LV */
+ opp_uv[i] = round_down((opp_uv[i] * VCORE_LV) / 100U,
+ PMIC_STEP_UV);
+ } else if (dvfs_v_mode == 1U) {
+ /* HV */
+ opp_uv[i] = round_up((opp_uv[i] * VCORE_HV) / 100U,
+ PMIC_STEP_UV);
+ }
+ spm_vcorefs_pwarp_cmd(i, __vcore_uv_to_pmic(opp_uv[i]));
+ }
+}
+
+uint64_t spm_vcorefs_args(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t *x4)
+{
+ uint64_t cmd = x1;
+ uint64_t spm_flags;
+
+ switch (cmd) {
+ case VCOREFS_SMC_CMD_INIT:
+ /* vcore_dvfs init + kick */
+ mmio_write_32(DVFSRC_SW_REQ5, SW_REQ5_INIT_VAL);
+ spm_dvfsfw_init(0ULL, 0ULL);
+ spm_vcorefs_vcore_setting(x3 & 0xF);
+ spm_flags = SPM_FLAG_RUN_COMMON_SCENARIO;
+ if ((x2 & 0x1) > 0U) {
+ spm_flags |= SPM_FLAG_DISABLE_VCORE_DVS;
+ }
+
+ if ((x2 & 0x2) > 0U) {
+ spm_flags |= SPM_FLAG_DISABLE_VCORE_DFS;
+ }
+
+ if ((mmio_read_32(DVFSRC_RSRV_4) & VCORE_CT_ENABLE) > 0U) {
+ spm_flags |= SPM_FLAG_ENABLE_VOLTAGE_BIN;
+ }
+
+ set_pwrctrl_pcm_flags(__spm_vcorefs.pwrctrl, spm_flags);
+ spm_go_to_vcorefs();
+ dvfsrc_init();
+
+ *x4 = 0U;
+ mmio_write_32(DVFSRC_SW_REQ5, 0U);
+ break;
+ case VCOREFS_SMC_CMD_KICK:
+ mmio_write_32(DVFSRC_SW_REQ5, 0U);
+ break;
+ default:
+ break;
+ }
+
+ return 0ULL;
+}
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm_vcorefs.h b/plat/mediatek/mt8192/drivers/spm/mt_spm_vcorefs.h
new file mode 100644
index 0000000..f4e0c48
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/mt_spm_vcorefs.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright(C)2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_VCOREFS_H
+#define MT_SPM_VCOREFS_H
+
+uint64_t spm_vcorefs_args(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t *x4);
+
+enum vcorefs_smc_cmd {
+ VCOREFS_SMC_CMD_0,
+ VCOREFS_SMC_CMD_1,
+ VCOREFS_SMC_CMD_2,
+ VCOREFS_SMC_CMD_3,
+ VCOREFS_SMC_CMD_4,
+ /* check spmfw status */
+ VCOREFS_SMC_CMD_5,
+
+ /* get spmfw type */
+ VCOREFS_SMC_CMD_6,
+
+ /* get spm reg status */
+ VCOREFS_SMC_CMD_7,
+
+ NUM_VCOREFS_SMC_CMD,
+};
+
+enum vcorefs_smc_cmd_new {
+ VCOREFS_SMC_CMD_INIT = 0,
+ VCOREFS_SMC_CMD_KICK = 1,
+};
+
+#define _VCORE_BASE_UV 400000
+#define _VCORE_STEP_UV 6250
+
+/* PMIC */
+#define __vcore_pmic_to_uv(pmic) \
+ (((pmic) * _VCORE_STEP_UV) + _VCORE_BASE_UV)
+
+#define __vcore_uv_to_pmic(uv) /* pmic >= uv */ \
+ ((((uv) - _VCORE_BASE_UV) + (_VCORE_STEP_UV - 1)) / _VCORE_STEP_UV)
+
+struct reg_config {
+ uint32_t offset;
+ uint32_t val;
+};
+
+#define DVFSRC_BASIC_CONTROL (DVFSRC_BASE + 0x0)
+#define DVFSRC_SW_REQ5 (DVFSRC_BASE + 0x14)
+#define DVFSRC_INT_EN (DVFSRC_BASE + 0xC8)
+#define DVFSRC_MD_TURBO (DVFSRC_BASE + 0xDC)
+#define DVFSRC_PCIE_VCORE_REQ (DVFSRC_BASE + 0xE0)
+#define DVFSRC_VCORE_USER_REQ (DVFSRC_BASE + 0xE4)
+#define DVFSRC_TIMEOUT_NEXTREQ (DVFSRC_BASE + 0xF8)
+#define DVFSRC_LEVEL_LABEL_0_1 (DVFSRC_BASE + 0x100)
+#define DVFSRC_LEVEL_LABEL_2_3 (DVFSRC_BASE + 0x104)
+#define DVFSRC_LEVEL_LABEL_4_5 (DVFSRC_BASE + 0x108)
+#define DVFSRC_LEVEL_LABEL_6_7 (DVFSRC_BASE + 0x10C)
+#define DVFSRC_LEVEL_LABEL_8_9 (DVFSRC_BASE + 0x110)
+#define DVFSRC_LEVEL_LABEL_10_11 (DVFSRC_BASE + 0x114)
+#define DVFSRC_LEVEL_LABEL_12_13 (DVFSRC_BASE + 0x118)
+#define DVFSRC_LEVEL_LABEL_14_15 (DVFSRC_BASE + 0x11C)
+#define DVFSRC_QOS_EN (DVFSRC_BASE + 0x280)
+#define DVFSRC_HRT_BW_BASE (DVFSRC_BASE + 0x294)
+#define DVFSRC_RSRV_4 (DVFSRC_BASE + 0x610)
+#define DVFSRC_RSRV_5 (DVFSRC_BASE + 0x614)
+#define DVFSRC_DDR_REQUEST (DVFSRC_BASE + 0xA00)
+#define DVFSRC_DDR_REQUEST2 (DVFSRC_BASE + 0xA04)
+#define DVFSRC_DDR_REQUEST3 (DVFSRC_BASE + 0xA08)
+#define DVFSRC_DDR_REQUEST4 (DVFSRC_BASE + 0xA0C)
+#define DVFSRC_DDR_REQUEST5 (DVFSRC_BASE + 0xA10)
+#define DVFSRC_DDR_REQUEST6 (DVFSRC_BASE + 0xA14)
+#define DVFSRC_DDR_REQUEST7 (DVFSRC_BASE + 0xA18)
+#define DVFSRC_DDR_QOS0 (DVFSRC_BASE + 0xA34)
+#define DVFSRC_DDR_QOS1 (DVFSRC_BASE + 0xA38)
+#define DVFSRC_DDR_QOS2 (DVFSRC_BASE + 0xA3C)
+#define DVFSRC_DDR_QOS3 (DVFSRC_BASE + 0xA40)
+#define DVFSRC_DDR_QOS4 (DVFSRC_BASE + 0xA44)
+#define DVFSRC_HRT_REQ_UNIT (DVFSRC_BASE + 0xA60)
+#define DVFSRC_HRT_REQUEST (DVFSRC_BASE + 0xAC4)
+#define DVFSRC_HRT_HIGH_2 (DVFSRC_BASE + 0xAC8)
+#define DVFSRC_HRT_HIGH_1 (DVFSRC_BASE + 0xACC)
+#define DVFSRC_HRT_HIGH (DVFSRC_BASE + 0xAD0)
+#define DVFSRC_HRT_LOW_2 (DVFSRC_BASE + 0xAD4)
+#define DVFSRC_HRT_LOW_1 (DVFSRC_BASE + 0xAD8)
+#define DVFSRC_HRT_LOW (DVFSRC_BASE + 0xADC)
+#define DVFSRC_DDR_ADD_REQUEST (DVFSRC_BASE + 0xAE0)
+#define DVFSRC_LAST (DVFSRC_BASE + 0xAE4)
+#define DVFSRC_LAST_L (DVFSRC_BASE + 0xAE8)
+#define DVFSRC_MD_SCENARIO (DVFSRC_BASE + 0xAEC)
+#define DVFSRC_RECORD_0_0 (DVFSRC_BASE + 0xAF0)
+#define DVFSRC_RECORD_0_1 (DVFSRC_BASE + 0xAF4)
+#define DVFSRC_RECORD_0_2 (DVFSRC_BASE + 0xAF8)
+#define DVFSRC_RECORD_0_3 (DVFSRC_BASE + 0xAFC)
+#define DVFSRC_RECORD_0_4 (DVFSRC_BASE + 0xB00)
+#define DVFSRC_RECORD_0_5 (DVFSRC_BASE + 0xB04)
+#define DVFSRC_RECORD_0_6 (DVFSRC_BASE + 0xB08)
+#define DVFSRC_RECORD_0_7 (DVFSRC_BASE + 0xB0C)
+#define DVFSRC_RECORD_0_L_0 (DVFSRC_BASE + 0xBF0)
+#define DVFSRC_RECORD_0_L_1 (DVFSRC_BASE + 0xBF4)
+#define DVFSRC_RECORD_0_L_2 (DVFSRC_BASE + 0xBF8)
+#define DVFSRC_RECORD_0_L_3 (DVFSRC_BASE + 0xBFC)
+#define DVFSRC_RECORD_0_L_4 (DVFSRC_BASE + 0xC00)
+#define DVFSRC_RECORD_0_L_5 (DVFSRC_BASE + 0xC04)
+#define DVFSRC_RECORD_0_L_6 (DVFSRC_BASE + 0xC08)
+#define DVFSRC_RECORD_0_L_7 (DVFSRC_BASE + 0xC0C)
+#define DVFSRC_EMI_REQUEST8 (DVFSRC_BASE + 0xCF0)
+#define DVFSRC_DDR_REQUEST8 (DVFSRC_BASE + 0xCF4)
+#define DVFSRC_EMI_HRT_2 (DVFSRC_BASE + 0xCF8)
+#define DVFSRC_EMI_HRT2_2 (DVFSRC_BASE + 0xCFC)
+#define DVFSRC_EMI_HRT3_2 (DVFSRC_BASE + 0xD00)
+#define DVFSRC_EMI_QOS5 (DVFSRC_BASE + 0xD04)
+#define DVFSRC_EMI_QOS6 (DVFSRC_BASE + 0xD08)
+#define DVFSRC_DDR_HRT_2 (DVFSRC_BASE + 0xD0C)
+#define DVFSRC_DDR_HRT2_2 (DVFSRC_BASE + 0xD10)
+#define DVFSRC_DDR_HRT3_2 (DVFSRC_BASE + 0xD14)
+#define DVFSRC_DDR_QOS5 (DVFSRC_BASE + 0xD18)
+#define DVFSRC_DDR_QOS6 (DVFSRC_BASE + 0xD1C)
+#define DVFSRC_HRT_HIGH_3 (DVFSRC_BASE + 0xD38)
+#define DVFSRC_HRT_LOW_3 (DVFSRC_BASE + 0xD3C)
+#define DVFSRC_LEVEL_LABEL_16_17 (DVFSRC_BASE + 0xD4C)
+#define DVFSRC_LEVEL_LABEL_18_19 (DVFSRC_BASE + 0xD50)
+#define DVFSRC_LEVEL_LABEL_20_21 (DVFSRC_BASE + 0xD54)
+#define DVFSRC_LEVEL_LABEL_22_23 (DVFSRC_BASE + 0xD58)
+#define DVFSRC_LEVEL_LABEL_24_25 (DVFSRC_BASE + 0xD5C)
+#define DVFSRC_LEVEL_LABEL_26_27 (DVFSRC_BASE + 0xD60)
+#define DVFSRC_LEVEL_LABEL_28_29 (DVFSRC_BASE + 0xD64)
+#define DVFSRC_LEVEL_LABEL_30_31 (DVFSRC_BASE + 0xD68)
+#define DVFSRC_CURRENT_FORCE (DVFSRC_BASE + 0xD6C)
+
+#define VCORE_VB_EFUSE (0x11C105E8)
+
+#endif /* MT_SPM_VCOREFS_H */
diff --git a/plat/mediatek/mt8192/drivers/spm/notifier/mt_spm_notifier.h b/plat/mediatek/mt8192/drivers/spm/notifier/mt_spm_notifier.h
new file mode 100644
index 0000000..66be7ee
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/notifier/mt_spm_notifier.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_SSPM_NOTIFIER_H
+#define MT_SPM_SSPM_NOTIFIER_H
+
+enum MT_SPM_SSPM_NOTIFY_ID {
+ MT_SPM_NOTIFY_LP_ENTER,
+ MT_SPM_NOTIFY_LP_LEAVE,
+};
+
+int mt_spm_sspm_notify(int type, unsigned int lp_mode);
+
+static inline int mt_spm_sspm_notify_u32(int type, unsigned int lp_mode)
+{
+ return mt_spm_sspm_notify(type, lp_mode);
+}
+#endif /* MT_SPM_SSPM_NOTIFIER_H */
diff --git a/plat/mediatek/mt8192/drivers/spm/notifier/mt_spm_sspm_intc.h b/plat/mediatek/mt8192/drivers/spm/notifier/mt_spm_sspm_intc.h
new file mode 100644
index 0000000..452ae90
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/notifier/mt_spm_sspm_intc.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_SSPM_INTC_H
+#define MT_SPM_SSPM_INTC_H
+
+#include <mt_spm_reg.h>
+
+#define MT_SPM_SSPM_INTC_SEL_0 0x10
+#define MT_SPM_SSPM_INTC_SEL_1 0x20
+#define MT_SPM_SSPM_INTC_SEL_2 0x40
+#define MT_SPM_SSPM_INTC_SEL_3 0x80
+
+#define MT_SPM_SSPM_INTC_TRIGGER(id, sg) \
+ (((0x10 << id) | (sg << id)) & 0xff)
+
+#define MT_SPM_SSPM_INTC0_HIGH MT_SPM_SSPM_INTC_TRIGGER(0, 1)
+#define MT_SPM_SSPM_INTC0_LOW MT_SPM_SSPM_INTC_TRIGGER(0, 0)
+#define MT_SPM_SSPM_INTC1_HIGH MT_SPM_SSPM_INTC_TRIGGER(1, 1)
+#define MT_SPM_SSPM_INTC1_LOW MT_SPM_SSPM_INTC_TRIGGER(1, 0)
+#define MT_SPM_SSPM_INTC2_HIGH MT_SPM_SSPM_INTC_TRIGGER(2, 1)
+#define MT_SPM_SSPM_INTC2_LOW MT_SPM_SSPM_INTC_TRIGGER(2, 0)
+#define MT_SPM_SSPM_INTC3_HIGH MT_SPM_SSPM_INTC_TRIGGER(3, 1)
+#define MT_SPM_SSPM_INTC3_LOW MT_SPM_SSPM_INTC_TRIGGER(3, 0)
+
+#define DO_SPM_SSPM_LP_SUSPEND() \
+ mmio_write_32(SPM_MD32_IRQ, MT_SPM_SSPM_INTC0_HIGH)
+#define DO_SPM_SSPM_LP_RESUME() \
+ mmio_write_32(SPM_MD32_IRQ, MT_SPM_SSPM_INTC0_LOW)
+#endif /* MT_SPM_SSPM_INTC_H */
diff --git a/plat/mediatek/mt8192/drivers/spm/notifier/mt_spm_sspm_notifier.c b/plat/mediatek/mt8192/drivers/spm/notifier/mt_spm_sspm_notifier.c
new file mode 100644
index 0000000..e0ba037
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/notifier/mt_spm_sspm_notifier.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <lib/mmio.h>
+
+#include <mt_spm_notifier.h>
+#include <mt_spm_sspm_intc.h>
+
+#define MT_SPM_SSPM_MBOX_OFF(x) (SSPM_MBOX_BASE + x)
+#define MT_SPM_MBOX(slot) MT_SPM_SSPM_MBOX_OFF((slot << 2UL))
+
+#define SSPM_MBOX_SPM_LP_LOOKUP1 MT_SPM_MBOX(0)
+#define SSPM_MBOX_SPM_LP_LOOKUP2 MT_SPM_MBOX(1)
+#define SSPM_MBOX_SPM_LP1 MT_SPM_MBOX(2)
+#define SSPM_MBOX_SPM_LP2 MT_SPM_MBOX(3)
+
+#define MCUPM_MBOX_OFFSET_LP 0x0C55FDA4
+#define MCUPM_MBOX_ENTER_LP 0x454e0000
+#define MCUPM_MBOX_LEAVE_LP 0x4c450000
+#define MCUPM_MBOX_SLEEP_MASK 0x0000FFFF
+
+int mt_spm_sspm_notify(int type, unsigned int lp_mode)
+{
+ switch (type) {
+ case MT_SPM_NOTIFY_LP_ENTER:
+ mmio_write_32(SSPM_MBOX_SPM_LP1, lp_mode);
+ mmio_write_32(MCUPM_MBOX_OFFSET_LP, MCUPM_MBOX_ENTER_LP |
+ (lp_mode & MCUPM_MBOX_SLEEP_MASK));
+ DO_SPM_SSPM_LP_SUSPEND();
+ break;
+ case MT_SPM_NOTIFY_LP_LEAVE:
+ mmio_write_32(SSPM_MBOX_SPM_LP1, lp_mode);
+ mmio_write_32(MCUPM_MBOX_OFFSET_LP, MCUPM_MBOX_LEAVE_LP |
+ (lp_mode & MCUPM_MBOX_SLEEP_MASK));
+ DO_SPM_SSPM_LP_RESUME();
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8192/drivers/spm/pcm_def.h b/plat/mediatek/mt8192/drivers/spm/pcm_def.h
new file mode 100644
index 0000000..ab46b86
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/pcm_def.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PCM_DEF_H
+#define PCM_DEF_H
+
+/*
+ * Auto generated by DE, please DO NOT modify this file directly.
+ */
+
+/* --- R0 Define --- */
+#define R0_SC_26M_CK_OFF (1U << 0)
+#define R0_SC_TX_TRACK_RETRY_EN (1U << 1)
+#define R0_SC_MEM_CK_OFF (1U << 2)
+#define R0_SC_AXI_CK_OFF (1U << 3)
+#define R0_SC_DR_SRAM_LOAD (1U << 4)
+#define R0_SC_MD26M_CK_OFF (1U << 5)
+#define R0_SC_DPY_MODE_SW (1U << 6)
+#define R0_SC_DMSUS_OFF (1U << 7)
+#define R0_SC_DPY_2ND_DLL_EN (1U << 8)
+#define R0_SC_DR_SRAM_RESTORE (1U << 9)
+#define R0_SC_MPLLOUT_OFF (1U << 10)
+#define R0_SC_TX_TRACKING_DIS (1U << 11)
+#define R0_SC_DPY_DLL_EN (1U << 12)
+#define R0_SC_DPY_DLL_CK_EN (1U << 13)
+#define R0_SC_DPY_VREF_EN (1U << 14)
+#define R0_SC_PHYPLL_EN (1U << 15)
+#define R0_SC_DDRPHY_FB_CK_EN (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_DR_SHU_LEVEL_SRAM_LATCH (1U << 21)
+#define R0_SC_DR_SHU_EN (1U << 22)
+#define R0_SC_DPHY_PRECAL_UP (1U << 23)
+#define R0_SC_MPLL_S_OFF (1U << 24)
+#define R0_SC_DPHY_RXDLY_TRACKING_EN (1U << 25)
+#define R0_SC_PHYPLL_SHU_EN (1U << 26)
+#define R0_SC_PHYPLL2_SHU_EN (1U << 27)
+#define R0_SC_PHYPLL_MODE_SW (1U << 28)
+#define R0_SC_PHYPLL2_MODE_SW (1U << 29)
+#define R0_SC_DR_SHU_LEVEL0 (1U << 30)
+#define R0_SC_DR_SHU_LEVEL1 (1U << 31)
+/* --- R7 Define --- */
+#define R7_PWRAP_SLEEP_REQ (1U << 0)
+#define R7_EMI_CLK_OFF_REQ (1U << 1)
+#define R7_PCM_BUS_PROTECT_REQ (1U << 2)
+#define R7_SPM_CK_UPDATE (1U << 3)
+#define R7_SPM_CK_SEL0 (1U << 4)
+#define R7_SPM_CK_SEL1 (1U << 5)
+#define R7_SPM_LEAVE_DEEPIDLE_REQ (1U << 6)
+#define R7_SC_FHC_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_SPM_LEAVE_SUSPEND_REQ (1U << 11)
+#define R7_CSYSPWRUPACK (1U << 12)
+#define R7_PCM_IM_SLP_EN (1U << 13)
+#define R7_SRCCLKENO0 (1U << 14)
+#define R7_FORCE_DDR_EN_WAKE (1U << 15)
+#define R7_SPM_APSRC_INTERNAL_ACK (1U << 16)
+#define R7_CPU_SYS_TIMER_CLK_SEL (1U << 17)
+#define R7_SC_AXI_DCM_DIS (1U << 18)
+#define R7_SC_FHC_PAUSE_MEM (1U << 19)
+#define R7_SC_FHC_PAUSE_MAIN (1U << 20)
+#define R7_SRCCLKENO1 (1U << 21)
+#define R7_PCM_WDT_KICK_P (1U << 22)
+#define R7_SPM2EMI_S1_MODE_ASYNC (1U << 23)
+#define R7_SC_DDR_PST_REQ_PCM (1U << 24)
+#define R7_SC_DDR_PST_ABORT_REQ_PCM (1U << 25)
+#define R7_PMIC_IRQ_REQ_EN (1U << 26)
+#define R7_FORCE_F26M_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_SPM_DDR_EN_INTERNAL_ACK (1U << 31)
+/* --- R12 Define --- */
+#define R12_PCM_TIMER (1U << 0)
+#define R12_TWAM_IRQ_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_SSPM2SPM_WAKEUP_B (1U << 10)
+#define R12_SCP2SPM_WAKEUP_B (1U << 11)
+#define R12_ADSP2SPM_WAKEUP_B (1U << 12)
+#define R12_PCM_WDT_WAKEUP_B (1U << 13)
+#define R12_USBX_CDSC_B (1U << 14)
+#define R12_USBX_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_EVENT_B (1U << 27)
+#define R12_REG_CPU_WAKEUP (1U << 28)
+#define R12_APUSYS_WAKE_HOST_B (1U << 29)
+#define R12_PCIE_BRIDGE_IRQ (1U << 30)
+#define R12_PCIE_IRQ (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_WAKE (1U << 8)
+#define R12EXT_DDREN_WAKE (1U << 9)
+#define R12EXT_DDREN_SLEEP (1U << 10)
+#define R12EXT_MCU_PM_WFI (1U << 11)
+#define R12EXT_SSPM_IDLE (1U << 12)
+#define R12EXT_CONN_SRCCLKENB (1U << 13)
+#define R12EXT_DRAMC_SSPM_WFI_MERGE (1U << 14)
+#define R12EXT_SW_MAILBOX_WAKE (1U << 15)
+#define R12EXT_SSPM_MAILBOX_WAKE (1U << 16)
+#define R12EXT_ADSP_MAILBOX_WAKE (1U << 17)
+#define R12EXT_SCP_MAILBOX_WAKE (1U << 18)
+#define R12EXT_SPM_LEAVE_SUSPEND_ACK (1U << 19)
+#define R12EXT_SPM_LEAVE_DEEPIDLE_ACK (1U << 20)
+#define R12EXT_VS1_TRIGGER (1U << 21)
+#define R12EXT_VS2_TRIGGER (1U << 22)
+#define R12EXT_COROSS_REQ_APU (1U << 23)
+#define R12EXT_CROSS_REQ_L3 (1U << 24)
+#define R12EXT_DDR_PST_ACK (1U << 25)
+#define R12EXT_BIT26 (1U << 26)
+#define R12EXT_BIT27 (1U << 27)
+#define R12EXT_BIT28 (1U << 28)
+#define R12EXT_BIT29 (1U << 29)
+#define R12EXT_BIT30 (1U << 30)
+#define R12EXT_BIT31 (1U << 31)
+/* --- R13 Define --- */
+#define R13_SRCCLKENI0 (1U << 0)
+#define R13_SRCCLKENI1 (1U << 1)
+#define R13_MD_SRCCLKENA_0 (1U << 2)
+#define R13_MD_APSRC_REQ_0 (1U << 3)
+#define R13_CONN_DDR_EN (1U << 4)
+#define R13_MD_SRCCLKENA_1 (1U << 5)
+#define R13_SSPM_SRCCLKENA (1U << 6)
+#define R13_SSPM_APSRC_REQ (1U << 7)
+#define R13_MD1_STATE (1U << 8)
+#define R13_BIT9 (1U << 9)
+#define R13_MM_STATE (1U << 10)
+#define R13_SSPM_STATE (1U << 11)
+#define R13_MD_DDR_EN_0 (1U << 12)
+#define R13_CONN_STATE (1U << 13)
+#define R13_CONN_SRCCLKENA (1U << 14)
+#define R13_CONN_APSRC_REQ (1U << 15)
+#define R13_SC_DDR_PST_ACK_ALL (1U << 16)
+#define R13_SC_DDR_PST_ABORT_ACK_ALL (1U << 17)
+#define R13_SCP_STATE (1U << 18)
+#define R13_CSYSPWRUPREQ (1U << 19)
+#define R13_PWRAP_SLEEP_ACK (1U << 20)
+#define R13_SC_EMI_CLK_OFF_ACK_ALL (1U << 21)
+#define R13_AUDIO_DSP_STATE (1U << 22)
+#define R13_SC_DMDRAMCSHU_ACK_ALL (1U << 23)
+#define R13_CONN_SRCCLKENB (1U << 24)
+#define R13_SC_DR_SRAM_LOAD_ACK_ALL (1U << 25)
+#define R13_SUBSYS_IDLE_SIGNALS0 (1U << 26)
+#define R13_DVFS_STATE (1U << 27)
+#define R13_SC_DR_SRAM_PLL_LOAD_ACK_ALL (1U << 28)
+#define R13_SC_DR_SRAM_RESTORE_ACK_ALL (1U << 29)
+#define R13_MD_VRF18_REQ_0 (1U << 30)
+#define R13_DDR_EN_STATE (1U << 31)
+#endif /* PCM_DEF_H */
diff --git a/plat/mediatek/mt8192/drivers/spm/sleep_def.h b/plat/mediatek/mt8192/drivers/spm/sleep_def.h
new file mode 100644
index 0000000..6c5cbed
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spm/sleep_def.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SLEEP_DEF_H
+#define SLEEP_DEF_H
+
+/*
+ * Auto generated by DE, please DO NOT modify this file directly.
+ */
+
+/* --- SPM Flag Define --- */
+#define SPM_FLAG_DISABLE_CPU_PDN (1U << 0)
+#define SPM_FLAG_DISABLE_INFRA_PDN (1U << 1)
+#define SPM_FLAG_DISABLE_DDRPHY_PDN (1U << 2)
+#define SPM_FLAG_DISABLE_VCORE_DVS (1U << 3)
+#define SPM_FLAG_DISABLE_VCORE_DFS (1U << 4)
+#define SPM_FLAG_DISABLE_COMMON_SCENARIO (1U << 5)
+#define SPM_FLAG_DISABLE_BUS_CLK_OFF (1U << 6)
+#define SPM_FLAG_DISABLE_ARMPLL_OFF (1U << 7)
+#define SPM_FLAG_KEEP_CSYSPWRACK_HIGH (1U << 8)
+#define SPM_FLAG_ENABLE_LVTS_WORKAROUND (1U << 9)
+#define SPM_FLAG_RUN_COMMON_SCENARIO (1U << 10)
+#define SPM_FLAG_RESERVED_BIT11 (1U << 11)
+#define SPM_FLAG_ENABLE_SPM_DBG_WDT_DUMP (1U << 12)
+#define SPM_FLAG_USE_SRCCLKENO2 (1U << 13)
+#define SPM_FLAG_ENABLE_6315_CTRL (1U << 14)
+#define SPM_FLAG_ENABLE_TIA_WORKAROUND (1U << 15)
+#define SPM_FLAG_DISABLE_SYSRAM_SLEEP (1U << 16)
+#define SPM_FLAG_DISABLE_SSPM_SRAM_SLEEP (1U << 17)
+#define SPM_FLAG_DISABLE_MCUPM_SRAM_SLEEP (1U << 18)
+#define SPM_FLAG_ENABLE_MD_MUMTAS (1U << 19)
+#define SPM_FLAG_ENABLE_VOLTAGE_BIN (1U << 20)
+#define SPM_FLAG_RESERVED_BIT21 (1U << 21)
+#define SPM_FLAG_DISABLE_DRAMC_MCU_SRAM_SLEEP (1U << 22)
+#define SPM_FLAG_DISABLE_SRAM_EVENT (1U << 23)
+#define SPM_FLAG_RESERVED_BIT24 (1U << 24)
+#define SPM_FLAG_RESERVED_BIT25 (1U << 25)
+#define SPM_FLAG_RESERVED_BIT26 (1U << 26)
+#define SPM_FLAG_VTCXO_STATE (1U << 27)
+#define SPM_FLAG_INFRA_STATE (1U << 28)
+#define SPM_FLAG_APSRC_STATE (1U << 29)
+#define SPM_FLAG_VRF18_STATE (1U << 30)
+#define SPM_FLAG_DDREN_STATE (1U << 31)
+/* --- SPM Flag1 Define --- */
+#define SPM_FLAG1_DISABLE_AXI_BUS_TO_26M (1U << 0)
+#define SPM_FLAG1_DISABLE_SYSPLL_OFF (1U << 1)
+#define SPM_FLAG1_DISABLE_PWRAP_CLK_SWITCH (1U << 2)
+#define SPM_FLAG1_DISABLE_ULPOSC_OFF (1U << 3)
+#define SPM_FLAG1_FW_SET_ULPOSC_ON (1U << 4)
+#define SPM_FLAG1_RESERVED_BIT5 (1U << 5)
+#define SPM_FLAG1_ENABLE_REKICK (1U << 6)
+#define SPM_FLAG1_DISABLE_MD26M_CK_OFF (1U << 7)
+#define SPM_FLAG1_RESERVED_BIT8 (1U << 8)
+#define SPM_FLAG1_RESERVED_BIT9 (1U << 9)
+#define SPM_FLAG1_DISABLE_SRCLKEN_LOW (1U << 10)
+#define SPM_FLAG1_DISABLE_SCP_CLK_SWITCH (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_RESERVED_BIT15 (1U << 15)
+#define SPM_FLAG1_RESERVED_BIT16 (1U << 16)
+#define SPM_FLAG1_RESERVED_BIT17 (1U << 17)
+#define SPM_FLAG1_RESERVED_BIT18 (1U << 18)
+#define SPM_FLAG1_RESERVED_BIT19 (1U << 19)
+#define SPM_FLAG1_DISABLE_DEVAPC_SRAM_SLEEP (1U << 20)
+#define SPM_FLAG1_RESERVED_BIT21 (1U << 21)
+#define SPM_FLAG1_ENABLE_VS1_VOTER (1U << 22)
+#define SPM_FLAG1_ENABLE_VS2_VOTER (1U << 23)
+#define SPM_FLAG1_DISABLE_SCP_VREQ_MASK_CONTROL (1U << 24)
+#define SPM_FLAG1_RESERVED_BIT25 (1U << 25)
+#define SPM_FLAG1_RESERVED_BIT26 (1U << 26)
+#define SPM_FLAG1_RESERVED_BIT27 (1U << 27)
+#define SPM_FLAG1_RESERVED_BIT28 (1U << 28)
+#define SPM_FLAG1_RESERVED_BIT29 (1U << 29)
+#define SPM_FLAG1_RESERVED_BIT30 (1U << 30)
+#define SPM_FLAG1_DISABLE_CPUEB_OFF (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_DRAM_SREF_ABORT_IN_APSRC (1U << 10)
+#define SPM_DBG_DEBUG_IDX_MCUPM_SRAM_STATE (1U << 11)
+#define SPM_DBG_DEBUG_IDX_SSPM_SRAM_STATE (1U << 12)
+#define SPM_DBG_DEBUG_IDX_DRAM_SREF_ABORT_IN_DDREN (1U << 13)
+#define SPM_DBG_DEBUG_IDX_DRAMC_MCU_SRAM_STATE (1U << 14)
+#define SPM_DBG_DEBUG_IDX_SYSRAM_SLP (1U << 15)
+#define SPM_DBG_DEBUG_IDX_SYSRAM_ON (1U << 16)
+#define SPM_DBG_DEBUG_IDX_MCUPM_SRAM_SLP (1U << 17)
+#define SPM_DBG_DEBUG_IDX_MCUPM_SRAM_ON (1U << 18)
+#define SPM_DBG_DEBUG_IDX_SSPM_SRAM_SLP (1U << 19)
+#define SPM_DBG_DEBUG_IDX_SSPM_SRAM_ON (1U << 20)
+#define SPM_DBG_DEBUG_IDX_DRAMC_MCU_SRAM_SLP (1U << 21)
+#define SPM_DBG_DEBUG_IDX_DRAMC_MCU_SRAM_ON (1U << 22)
+#define SPM_DBG_DEBUG_IDX_SCP_VCORE_0P575V (1U << 23)
+#define SPM_DBG_DEBUG_IDX_SCP_VCORE_0P600V (1U << 24)
+#define SPM_DBG_DEBUG_IDX_SCP_VCORE_0P650V (1U << 25)
+#define SPM_DBG_DEBUG_IDX_SCP_VCORE_0P725V (1U << 26)
+#define SPM_DBG_DEBUG_IDX_SPM_GO_WAKEUP_NOW (1U << 27)
+#define SPM_DBG_DEBUG_IDX_VTCXO_STATE (1U << 28)
+#define SPM_DBG_DEBUG_IDX_INFRA_STATE (1U << 29)
+#define SPM_DBG_DEBUG_IDX_VRR18_STATE (1U << 30)
+#define SPM_DBG_DEBUG_IDX_APSRC_STATE (1U << 31)
+/* --- SPM DEBUG1 Define --- */
+#define SPM_DBG1_DEBUG_IDX_CURRENT_IS_LP (1U << 0)
+#define SPM_DBG1_DEBUG_IDX_VCORE_DVFS_START (1U << 1)
+#define SPM_DBG1_DEBUG_IDX_SYSPLL_OFF (1U << 2)
+#define SPM_DBG1_DEBUG_IDX_SYSPLL_ON (1U << 3)
+#define SPM_DBG1_DEBUG_IDX_CURRENT_IS_VCORE_DVFS (1U << 4)
+#define SPM_DBG1_DEBUG_IDX_INFRA_MTCMOS_OFF (1U << 5)
+#define SPM_DBG1_DEBUG_IDX_INFRA_MTCMOS_ON (1U << 6)
+#define SPM_DBG1_DEBUG_IDX_VRCXO_SLEEP_ABORT (1U << 7)
+#define SPM_DBG1_RESERVED_BIT8 (1U << 8)
+#define SPM_DBG1_DEBUG_IDX_INFRA_SUB_MTCMOS_OFF (1U << 9)
+#define SPM_DBG1_DEBUG_IDX_INFRA_SUB_MTCMOS_ON (1U << 10)
+#define SPM_DBG1_DEBUG_IDX_PWRAP_CLK_TO_ULPOSC (1U << 11)
+#define SPM_DBG1_DEBUG_IDX_PWRAP_CLK_TO_26M (1U << 12)
+#define SPM_DBG1_DEBUG_IDX_SCP_CLK_TO_32K (1U << 13)
+#define SPM_DBG1_DEBUG_IDX_SCP_CLK_TO_26M (1U << 14)
+#define SPM_DBG1_DEBUG_IDX_BUS_CLK_OFF (1U << 15)
+#define SPM_DBG1_DEBUG_IDX_BUS_CLK_ON (1U << 16)
+#define SPM_DBG1_DEBUG_IDX_SRCLKEN2_LOW (1U << 17)
+#define SPM_DBG1_DEBUG_IDX_SRCLKEN2_HIGH (1U << 18)
+#define SPM_DBG1_RESERVED_BIT19 (1U << 19)
+#define SPM_DBG1_DEBUG_IDX_ULPOSC_IS_OFF_BUT_SHOULD_ON (1U << 20)
+#define SPM_DBG1_DEBUG_IDX_6315_LOW (1U << 21)
+#define SPM_DBG1_DEBUG_IDX_6315_HIGH (1U << 22)
+#define SPM_DBG1_DEBUG_IDX_PWRAP_SLEEP_ACK_LOW_ABORT (1U << 23)
+#define SPM_DBG1_DEBUG_IDX_PWRAP_SLEEP_ACK_HIGH_ABORT (1U << 24)
+#define SPM_DBG1_DEBUG_IDX_EMI_SLP_IDLE_ABORT (1U << 25)
+#define SPM_DBG1_DEBUG_IDX_SCP_SLP_ACK_LOW_ABORT (1U << 26)
+#define SPM_DBG1_DEBUG_IDX_SCP_SLP_ACK_HIGH_ABORT (1U << 27)
+#define SPM_DBG1_DEBUG_IDX_SPM_DVFS_CMD_RDY_ABORT (1U << 28)
+#define SPM_DBG1_RESERVED_BIT29 (1U << 29)
+#define SPM_DBG1_RESERVED_BIT30 (1U << 30)
+#define SPM_DBG1_DEBUG_DISABLE_CPUEB_OFF (1U << 31)
+
+ /* Macro and Inline */
+#define is_cpu_pdn(flags) (((flags) & SPM_FLAG_DISABLE_CPU_PDN) == 0U)
+#define is_infra_pdn(flags) (((flags) & SPM_FLAG_DISABLE_INFRA_PDN) == 0U)
+#define is_ddrphy_pdn(flags) (((flags) & SPM_FLAG_DISABLE_DDRPHY_PDN) == 0U)
+#endif /* SLEEP_DEF_H */
diff --git a/plat/mediatek/mt8192/drivers/spmc/mtspmc.c b/plat/mediatek/mt8192/drivers/spmc/mtspmc.c
new file mode 100644
index 0000000..7ccebd6
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spmc/mtspmc.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <mcucfg.h>
+#include <mtspmc.h>
+#include <mtspmc_private.h>
+
+
+void mcucfg_disable_gic_wakeup(uint32_t cluster, uint32_t cpu)
+{
+ mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(cpu));
+}
+
+void mcucfg_enable_gic_wakeup(uint32_t cluster, uint32_t cpu)
+{
+ mmio_clrbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(cpu));
+}
+
+void mcucfg_set_bootaddr(uint32_t cluster, uint32_t cpu, uintptr_t bootaddr)
+{
+ assert(cluster == 0U);
+
+ mmio_write_32(per_cpu(cluster, cpu, MCUCFG_BOOTADDR), bootaddr);
+}
+
+uintptr_t mcucfg_get_bootaddr(uint32_t cluster, uint32_t cpu)
+{
+ assert(cluster == 0U);
+
+ return (uintptr_t)mmio_read_32(per_cpu(cluster, cpu, MCUCFG_BOOTADDR));
+}
+
+void mcucfg_init_archstate(uint32_t cluster, uint32_t cpu, bool arm64)
+{
+ uint32_t reg;
+
+ assert(cluster == 0U);
+
+ reg = per_cluster(cluster, MCUCFG_INITARCH);
+
+ if (arm64) {
+ mmio_setbits_32(reg, MCUCFG_INITARCH_CPU_BIT(cpu));
+ } else {
+ mmio_clrbits_32(reg, MCUCFG_INITARCH_CPU_BIT(cpu));
+ }
+}
+
+/**
+ * Return subsystem's power state.
+ *
+ * @mask: mask to SPM_CPU_PWR_STATUS to query the power state
+ * of one subsystem.
+ * RETURNS:
+ * 0 (the subsys was powered off)
+ * 1 (the subsys was powered on)
+ */
+bool spm_get_powerstate(uint32_t mask)
+{
+ return (mmio_read_32(SPM_CPU_PWR_STATUS) & mask) != 0U;
+}
+
+bool spm_get_cluster_powerstate(uint32_t cluster)
+{
+ assert(cluster == 0U);
+
+ return spm_get_powerstate(MP0_CPUTOP);
+}
+
+bool spm_get_cpu_powerstate(uint32_t cluster, uint32_t cpu)
+{
+ uint32_t mask = BIT(cpu);
+
+ assert(cluster == 0U);
+
+ return spm_get_powerstate(mask);
+}
+
+int spmc_init(void)
+{
+ INFO("SPM: enable CPC mode\n");
+
+ mmio_write_32(SPM_POWERON_CONFIG_EN, PROJECT_CODE | BCLK_CG_EN);
+
+ mmio_setbits_32(per_cpu(0, 1, SPM_CPU_PWR), PWR_RST_B);
+ mmio_setbits_32(per_cpu(0, 2, SPM_CPU_PWR), PWR_RST_B);
+ mmio_setbits_32(per_cpu(0, 3, SPM_CPU_PWR), PWR_RST_B);
+ mmio_setbits_32(per_cpu(0, 4, SPM_CPU_PWR), PWR_RST_B);
+ mmio_setbits_32(per_cpu(0, 5, SPM_CPU_PWR), PWR_RST_B);
+ mmio_setbits_32(per_cpu(0, 6, SPM_CPU_PWR), PWR_RST_B);
+ mmio_setbits_32(per_cpu(0, 7, SPM_CPU_PWR), PWR_RST_B);
+
+ mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(1));
+ mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(2));
+ mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(3));
+ mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(4));
+ mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(5));
+ mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(6));
+ mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(7));
+
+ mmio_clrbits_32(SPM_MCUSYS_PWR_CON, RESETPWRON_CONFIG);
+ mmio_clrbits_32(SPM_MP0_CPUTOP_PWR_CON, RESETPWRON_CONFIG);
+ mmio_clrbits_32(per_cpu(0, 0, SPM_CPU_PWR), RESETPWRON_CONFIG);
+
+ mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, CPC_CTRL_ENABLE);
+
+ 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(uint32_t cluster, uint32_t cpu)
+{
+ /* set to 0 after BIG VPROC bulk on & before B-core power on seq. */
+ if (cpu >= 4U) {
+ mmio_write_32(DREQ20_BIG_VPROC_ISO, 0U);
+ }
+
+ mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, SSPM_ALL_PWR_CTRL_EN);
+ mmio_setbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWR_ON);
+
+ while (!spm_get_cpu_powerstate(cluster, cpu)) {
+ }
+
+ mmio_clrbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, SSPM_ALL_PWR_CTRL_EN);
+
+ /* Enable Big CPU Last PC */
+ if (cpu >= 4U) {
+ mmio_clrbits_32(LAST_PC_REG(cpu), BIT(3));
+ }
+}
+
+/**
+ * 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(uint32_t cluster, uint32_t cpu)
+{
+ /* Set mp0_spmc_pwr_on_cpuX = 0 */
+ mmio_clrbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWR_ON);
+}
+
+/**
+ * Power off a cluster with specified index
+ *
+ * @cluster: the cluster index which to be powered off
+ */
+void spm_poweroff_cluster(uint32_t cluster)
+{
+ /* No need to power on/off cluster on single cluster platform */
+ assert(false);
+}
+
+/**
+ * Power on a cluster with specified index
+ *
+ * @cluster: the cluster index which to be powered on
+ */
+void spm_poweron_cluster(uint32_t cluster)
+{
+ /* No need to power on/off cluster on single cluster platform */
+ assert(false);
+}
diff --git a/plat/mediatek/mt8192/drivers/spmc/mtspmc.h b/plat/mediatek/mt8192/drivers/spmc/mtspmc.h
new file mode 100644
index 0000000..7ed2e62
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spmc/mtspmc.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTSPMC_H
+#define MTSPMC_H
+
+#include <stdint.h>
+
+int spmc_init(void);
+
+void spm_poweron_cpu(uint32_t cluster, uint32_t cpu);
+void spm_poweroff_cpu(uint32_t cluster, uint32_t cpu);
+
+void spm_poweroff_cluster(uint32_t cluster);
+void spm_poweron_cluster(uint32_t cluster);
+
+bool spm_get_cpu_powerstate(uint32_t cluster, uint32_t cpu);
+bool spm_get_cluster_powerstate(uint32_t cluster);
+bool spm_get_powerstate(uint32_t mask);
+
+void mcucfg_init_archstate(uint32_t cluster, uint32_t cpu, bool arm64);
+void mcucfg_set_bootaddr(uint32_t cluster, uint32_t cpu, uintptr_t bootaddr);
+uintptr_t mcucfg_get_bootaddr(uint32_t cluster, uint32_t cpu);
+
+void mcucfg_disable_gic_wakeup(uint32_t cluster, uint32_t cpu);
+void mcucfg_enable_gic_wakeup(uint32_t cluster, uint32_t cpu);
+
+#endif /* MTSPMC_H */
diff --git a/plat/mediatek/mt8192/drivers/spmc/mtspmc_private.h b/plat/mediatek/mt8192/drivers/spmc/mtspmc_private.h
new file mode 100644
index 0000000..ad78295
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spmc/mtspmc_private.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTSPMC_PRIVATE_H
+#define MTSPMC_PRIVATE_H
+
+#include <lib/utils_def.h>
+#include <platform_def.h>
+
+unsigned long read_cpuectlr(void);
+void write_cpuectlr(unsigned long cpuectlr);
+
+unsigned long read_cpupwrctlr_el1(void);
+void write_cpupwrctlr_el1(unsigned long cpuectlr);
+
+/*
+ * per_cpu/cluster helper
+ */
+struct per_cpu_reg {
+ unsigned int cluster_addr;
+ unsigned 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)
+
+#define SPM_REG(ofs) (uint32_t)(SPM_BASE + (ofs))
+#define MCUCFG_REG(ofs) (uint32_t)(MCUCFG_BASE + (ofs))
+#define INFRACFG_AO_REG(ofs) (uint32_t)(INFRACFG_AO_BASE + (ofs))
+
+/* === SPMC related registers */
+#define SPM_POWERON_CONFIG_EN SPM_REG(0x000)
+/* bit-fields of SPM_POWERON_CONFIG_EN */
+#define PROJECT_CODE (U(0xb16) << 16)
+#define BCLK_CG_EN BIT(0)
+
+#define SPM_PWR_STATUS SPM_REG(0x16c)
+#define SPM_PWR_STATUS_2ND SPM_REG(0x170)
+#define SPM_CPU_PWR_STATUS SPM_REG(0x174)
+
+/* bit-fields of SPM_PWR_STATUS */
+#define MD BIT(0)
+#define CONN BIT(1)
+#define DDRPHY BIT(2)
+#define DISP BIT(3)
+#define MFG BIT(4)
+#define ISP BIT(5)
+#define INFRA BIT(6)
+#define VDEC BIT(7)
+#define MP0_CPUTOP BIT(8)
+#define MP0_CPU0 BIT(9)
+#define MP0_CPU1 BIT(10)
+#define MP0_CPU2 BIT(11)
+#define MP0_CPU3 BIT(12)
+#define MCUSYS BIT(14)
+#define MP0_CPU4 BIT(15)
+#define MP0_CPU5 BIT(16)
+#define MP0_CPU6 BIT(17)
+#define MP0_CPU7 BIT(18)
+#define VEN BIT(21)
+
+/* === SPMC related registers */
+#define SPM_MCUSYS_PWR_CON MCUCFG_REG(0xd200)
+#define SPM_MP0_CPUTOP_PWR_CON MCUCFG_REG(0xd204)
+#define SPM_MP0_CPU0_PWR_CON MCUCFG_REG(0xd208)
+#define SPM_MP0_CPU1_PWR_CON MCUCFG_REG(0xd20c)
+#define SPM_MP0_CPU2_PWR_CON MCUCFG_REG(0xd210)
+#define SPM_MP0_CPU3_PWR_CON MCUCFG_REG(0xd214)
+#define SPM_MP0_CPU4_PWR_CON MCUCFG_REG(0xd218)
+#define SPM_MP0_CPU5_PWR_CON MCUCFG_REG(0xd21c)
+#define SPM_MP0_CPU6_PWR_CON MCUCFG_REG(0xd220)
+#define SPM_MP0_CPU7_PWR_CON MCUCFG_REG(0xd224)
+
+/* bit fields of SPM_*_PWR_CON */
+#define PWR_ON_ACK BIT(31)
+#define VPROC_EXT_OFF BIT(7)
+#define DORMANT_EN BIT(6)
+#define RESETPWRON_CONFIG BIT(5)
+#define PWR_CLK_DIS BIT(4)
+#define PWR_ON BIT(2)
+#define PWR_RST_B BIT(0)
+
+/**** per_cpu registers for SPM_MP0_CPU?_PWR_CON */
+static const struct per_cpu_reg SPM_CPU_PWR[] = {
+ { .cluster_addr = SPM_MP0_CPU0_PWR_CON, .cpu_stride = 2U }
+};
+
+/**** per_cluster registers for SPM_MP0_CPUTOP_PWR_CON */
+static const struct per_cpu_reg SPM_CLUSTER_PWR[] = {
+ { .cluster_addr = SPM_MP0_CPUTOP_PWR_CON, .cpu_stride = 0U }
+};
+
+/* === MCUCFG related registers */
+/* aa64naa32 */
+#define MCUCFG_MP0_CLUSTER_CFG5 MCUCFG_REG(0xc8e4)
+/* reset vectors */
+#define MCUCFG_MP0_CLUSTER_CFG8 MCUCFG_REG(0xc900)
+#define MCUCFG_MP0_CLUSTER_CFG10 MCUCFG_REG(0xc908)
+#define MCUCFG_MP0_CLUSTER_CFG12 MCUCFG_REG(0xc910)
+#define MCUCFG_MP0_CLUSTER_CFG14 MCUCFG_REG(0xc918)
+#define MCUCFG_MP0_CLUSTER_CFG16 MCUCFG_REG(0xc920)
+#define MCUCFG_MP0_CLUSTER_CFG18 MCUCFG_REG(0xc928)
+#define MCUCFG_MP0_CLUSTER_CFG20 MCUCFG_REG(0xc930)
+#define MCUCFG_MP0_CLUSTER_CFG22 MCUCFG_REG(0xc938)
+
+/* MCUSYS DREQ BIG VPROC ISO control */
+#define DREQ20_BIG_VPROC_ISO MCUCFG_REG(0xad8c)
+
+/**** per_cpu registers for MCUCFG_MP0_CLUSTER_CFG? */
+static const struct per_cpu_reg MCUCFG_BOOTADDR[] = {
+ { .cluster_addr = MCUCFG_MP0_CLUSTER_CFG8, .cpu_stride = 3U }
+};
+
+/**** per_cpu registers for MCUCFG_MP0_CLUSTER_CFG5 */
+static const struct per_cpu_reg MCUCFG_INITARCH[] = {
+ { .cluster_addr = MCUCFG_MP0_CLUSTER_CFG5, .cpu_stride = 0U }
+};
+
+#define MCUCFG_INITARCH_CPU_BIT(cpu) BIT(16U + cpu)
+#define LAST_PC_REG(cpu) (MCUCFG_REG(0x308) + (cpu * 0x800))
+
+/* === CPC control */
+#define MCUCFG_CPC_FLOW_CTRL_CFG MCUCFG_REG(0xa814)
+#define MCUCFG_CPC_SPMC_PWR_STATUS MCUCFG_REG(0xa840)
+
+/* bit fields of CPC_FLOW_CTRL_CFG */
+#define CPC_CTRL_ENABLE BIT(16)
+#define SSPM_ALL_PWR_CTRL_EN BIT(13) /* for cpu-hotplug */
+#define GIC_WAKEUP_IGNORE(cpu) BIT(21 + cpu)
+
+/* bit fields of CPC_SPMC_PWR_STATUS */
+#define CORE_SPMC_PWR_ON_ACK GENMASK(15, 0)
+
+/* === APB Module infracfg_ao */
+#define INFRA_TOPAXI_PROTECTEN INFRACFG_AO_REG(0x0220)
+#define INFRA_TOPAXI_PROTECTEN_STA0 INFRACFG_AO_REG(0x0224)
+#define INFRA_TOPAXI_PROTECTEN_STA1 INFRACFG_AO_REG(0x0228)
+#define INFRA_TOPAXI_PROTECTEN_SET INFRACFG_AO_REG(0x02a0)
+#define INFRA_TOPAXI_PROTECTEN_CLR INFRACFG_AO_REG(0x02a4)
+#define INFRA_TOPAXI_PROTECTEN_1 INFRACFG_AO_REG(0x0250)
+#define INFRA_TOPAXI_PROTECTEN_STA0_1 INFRACFG_AO_REG(0x0254)
+#define INFRA_TOPAXI_PROTECTEN_STA1_1 INFRACFG_AO_REG(0x0258)
+#define INFRA_TOPAXI_PROTECTEN_1_SET INFRACFG_AO_REG(0x02a8)
+#define INFRA_TOPAXI_PROTECTEN_1_CLR INFRACFG_AO_REG(0x02ac)
+
+/* bit fields of INFRA_TOPAXI_PROTECTEN */
+#define MP0_SPMC_PROT_STEP1_0_MASK BIT(12)
+#define MP0_SPMC_PROT_STEP1_1_MASK (BIT(26) | BIT(12))
+
+/* === SPARK */
+#define VOLTAGE_04 U(0x40)
+#define VOLTAGE_05 U(0x60)
+
+#define PTP3_CPU0_SPMC_SW_CFG MCUCFG_REG(0x200)
+#define CPU0_ILDO_CONTROL5 MCUCFG_REG(0x334)
+#define CPU0_ILDO_CONTROL8 MCUCFG_REG(0x340)
+
+/* bit fields of CPU0_ILDO_CONTROL5 */
+#define ILDO_RET_VOSEL GENMASK(7, 0)
+
+/* bit fields of PTP3_CPU_SPMC_SW_CFG */
+#define SW_SPARK_EN BIT(0)
+
+/* bit fields of CPU0_ILDO_CONTROL8 */
+#define ILDO_BYPASS_B BIT(0)
+
+static const struct per_cpu_reg MCUCFG_SPARK[] = {
+ { .cluster_addr = PTP3_CPU0_SPMC_SW_CFG, .cpu_stride = 11U }
+};
+
+static const struct per_cpu_reg ILDO_CONTROL5[] = {
+ { .cluster_addr = CPU0_ILDO_CONTROL5, .cpu_stride = 11U }
+};
+
+static const struct per_cpu_reg ILDO_CONTROL8[] = {
+ { .cluster_addr = CPU0_ILDO_CONTROL8, .cpu_stride = 11U }
+};
+
+#endif /* MTSPMC_PRIVATE_H */
diff --git a/plat/mediatek/mt8192/include/mcucfg.h b/plat/mediatek/mt8192/include/mcucfg.h
new file mode 100644
index 0000000..046cf73
--- /dev/null
+++ b/plat/mediatek/mt8192/include/mcucfg.h
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MCUCFG_H
+#define MCUCFG_H
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+#endif /* __ASSEMBLER__ */
+
+#include <platform_def.h>
+
+#define MCUCFG_REG(ofs) (uint32_t)(MCUCFG_BASE + (ofs))
+
+#define MP2_MISC_CONFIG_BOOT_ADDR_L(cpu) (MCUCFG_REG(0x2290) + ((cpu) * 8))
+#define MP2_MISC_CONFIG_BOOT_ADDR_H(cpu) (MCUCFG_REG(0x2294) + ((cpu) * 8))
+
+#define MP2_CPUCFG MCUCFG_REG(0x2208)
+
+#define MP2_CPU0_STANDBYWFE BIT(4)
+#define MP2_CPU1_STANDBYWFE BIT(5)
+
+#define MP0_CPUTOP_SPMC_CTL MCUCFG_REG(0x788)
+#define MP1_CPUTOP_SPMC_CTL MCUCFG_REG(0x78C)
+#define MP1_CPUTOP_SPMC_SRAM_CTL MCUCFG_REG(0x790)
+
+#define sw_spark_en BIT(0)
+#define sw_no_wait_for_q_channel BIT(1)
+#define sw_fsm_override BIT(2)
+#define sw_logic_pre1_pdb BIT(3)
+#define sw_logic_pre2_pdb BIT(4)
+#define sw_logic_pdb BIT(5)
+#define sw_iso BIT(6)
+#define sw_sram_sleepb (U(0x3F) << 7)
+#define sw_sram_isointb BIT(13)
+#define sw_clk_dis BIT(14)
+#define sw_ckiso BIT(15)
+#define sw_pd (U(0x3F) << 16)
+#define sw_hot_plug_reset BIT(22)
+#define sw_pwr_on_override_en BIT(23)
+#define sw_pwr_on BIT(24)
+#define sw_coq_dis BIT(25)
+#define logic_pdbo_all_off_ack BIT(26)
+#define logic_pdbo_all_on_ack BIT(27)
+#define logic_pre2_pdbo_all_on_ack BIT(28)
+#define logic_pre1_pdbo_all_on_ack BIT(29)
+
+
+#define CPUSYSx_CPUx_SPMC_CTL(cluster, cpu) \
+ (MCUCFG_REG(0x1c30) + cluster * 0x2000 + cpu * 4)
+
+#define CPUSYS0_CPU0_SPMC_CTL MCUCFG_REG(0x1c30)
+#define CPUSYS0_CPU1_SPMC_CTL MCUCFG_REG(0x1c34)
+#define CPUSYS0_CPU2_SPMC_CTL MCUCFG_REG(0x1c38)
+#define CPUSYS0_CPU3_SPMC_CTL MCUCFG_REG(0x1c3C)
+
+#define CPUSYS1_CPU0_SPMC_CTL MCUCFG_REG(0x3c30)
+#define CPUSYS1_CPU1_SPMC_CTL MCUCFG_REG(0x3c34)
+#define CPUSYS1_CPU2_SPMC_CTL MCUCFG_REG(0x3c38)
+#define CPUSYS1_CPU3_SPMC_CTL MCUCFG_REG(0x3c3C)
+
+#define cpu_sw_spark_en BIT(0)
+#define cpu_sw_no_wait_for_q_channel BIT(1)
+#define cpu_sw_fsm_override BIT(2)
+#define cpu_sw_logic_pre1_pdb BIT(3)
+#define cpu_sw_logic_pre2_pdb BIT(4)
+#define cpu_sw_logic_pdb BIT(5)
+#define cpu_sw_iso BIT(6)
+#define cpu_sw_sram_sleepb BIT(7)
+#define cpu_sw_sram_isointb BIT(8)
+#define cpu_sw_clk_dis BIT(9)
+#define cpu_sw_ckiso BIT(10)
+#define cpu_sw_pd (U(0x1F) << 11)
+#define cpu_sw_hot_plug_reset BIT(16)
+#define cpu_sw_powr_on_override_en BIT(17)
+#define cpu_sw_pwr_on BIT(18)
+#define cpu_spark2ldo_allswoff BIT(19)
+#define cpu_pdbo_all_on_ack BIT(20)
+#define cpu_pre2_pdbo_allon_ack BIT(21)
+#define cpu_pre1_pdbo_allon_ack BIT(22)
+
+/* CPC related registers */
+#define CPC_MCUSYS_CPC_OFF_THRES MCUCFG_REG(0xa714)
+#define CPC_MCUSYS_PWR_CTRL MCUCFG_REG(0xa804)
+#define CPC_MCUSYS_CPC_FLOW_CTRL_CFG MCUCFG_REG(0xa814)
+#define CPC_MCUSYS_LAST_CORE_REQ MCUCFG_REG(0xa818)
+#define CPC_MCUSYS_MP_LAST_CORE_RESP MCUCFG_REG(0xa81c)
+#define CPC_MCUSYS_LAST_CORE_RESP MCUCFG_REG(0xa824)
+#define CPC_MCUSYS_PWR_ON_MASK MCUCFG_REG(0xa828)
+#define CPC_MCUSYS_CPU_ON_SW_HINT_SET MCUCFG_REG(0xa8a8)
+#define CPC_MCUSYS_CPU_ON_SW_HINT_CLR MCUCFG_REG(0xa8ac)
+#define CPC_MCUSYS_CPC_DBG_SETTING MCUCFG_REG(0xab00)
+#define CPC_MCUSYS_CPC_KERNEL_TIME_L_BASE MCUCFG_REG(0xab04)
+#define CPC_MCUSYS_CPC_KERNEL_TIME_H_BASE MCUCFG_REG(0xab08)
+#define CPC_MCUSYS_CPC_SYSTEM_TIME_L_BASE MCUCFG_REG(0xab0c)
+#define CPC_MCUSYS_CPC_SYSTEM_TIME_H_BASE MCUCFG_REG(0xab10)
+#define CPC_MCUSYS_TRACE_SEL MCUCFG_REG(0xab14)
+#define CPC_MCUSYS_TRACE_DATA MCUCFG_REG(0xab20)
+#define CPC_MCUSYS_CLUSTER_COUNTER MCUCFG_REG(0xab70)
+#define CPC_MCUSYS_CLUSTER_COUNTER_CLR MCUCFG_REG(0xab74)
+
+#define SPARK2LDO MCUCFG_REG(0x2700)
+/* APB Module mcucfg */
+#define MP0_CA7_CACHE_CONFIG MCUCFG_REG(0x000)
+#define MP0_AXI_CONFIG MCUCFG_REG(0x02C)
+#define MP0_MISC_CONFIG0 MCUCFG_REG(0x030)
+#define MP0_MISC_CONFIG1 MCUCFG_REG(0x034)
+#define MP0_MISC_CONFIG2 MCUCFG_REG(0x038)
+#define MP0_MISC_CONFIG_BOOT_ADDR(cpu) (MP0_MISC_CONFIG2 + ((cpu) * 8))
+#define MP0_MISC_CONFIG3 MCUCFG_REG(0x03C)
+#define MP0_MISC_CONFIG9 MCUCFG_REG(0x054)
+#define MP0_CA7_MISC_CONFIG MCUCFG_REG(0x064)
+
+#define MP0_RW_RSVD0 MCUCFG_REG(0x06C)
+
+
+#define MP1_CA7_CACHE_CONFIG MCUCFG_REG(0x200)
+#define MP1_AXI_CONFIG MCUCFG_REG(0x22C)
+#define MP1_MISC_CONFIG0 MCUCFG_REG(0x230)
+#define MP1_MISC_CONFIG1 MCUCFG_REG(0x234)
+#define MP1_MISC_CONFIG2 MCUCFG_REG(0x238)
+#define MP1_MISC_CONFIG_BOOT_ADDR(cpu) (MP1_MISC_CONFIG2 + ((cpu) * 8))
+#define MP1_MISC_CONFIG3 MCUCFG_REG(0x23C)
+#define MP1_MISC_CONFIG9 MCUCFG_REG(0x254)
+#define MP1_CA7_MISC_CONFIG MCUCFG_REG(0x264)
+
+#define CCI_ADB400_DCM_CONFIG MCUCFG_REG(0x740)
+#define SYNC_DCM_CONFIG MCUCFG_REG(0x744)
+
+#define MP0_CLUSTER_CFG0 MCUCFG_REG(0xC8D0)
+
+#define MP0_SPMC MCUCFG_REG(0x788)
+#define MP1_SPMC MCUCFG_REG(0x78C)
+#define MP2_AXI_CONFIG MCUCFG_REG(0x220C)
+#define MP2_AXI_CONFIG_ACINACTM BIT(0)
+#define MP2_AXI_CONFIG_AINACTS BIT(4)
+
+#define MPx_AXI_CONFIG_ACINACTM BIT(4)
+#define MPx_AXI_CONFIG_AINACTS BIT(5)
+
+#define MPx_CA7_MISC_CONFIG_standbywfil2 BIT(28)
+
+#define MP0_CPU0_STANDBYWFE BIT(20)
+#define MP0_CPU1_STANDBYWFE BIT(21)
+#define MP0_CPU2_STANDBYWFE BIT(22)
+#define MP0_CPU3_STANDBYWFE BIT(23)
+
+#define MP1_CPU0_STANDBYWFE BIT(20)
+#define MP1_CPU1_STANDBYWFE BIT(21)
+#define MP1_CPU2_STANDBYWFE BIT(22)
+#define MP1_CPU3_STANDBYWFE BIT(23)
+
+#define CPUSYS0_SPARKVRETCNTRL MCUCFG_REG(0x1c00)
+#define CPUSYS0_SPARKEN MCUCFG_REG(0x1c04)
+#define CPUSYS0_AMUXSEL MCUCFG_REG(0x1c08)
+#define CPUSYS1_SPARKVRETCNTRL MCUCFG_REG(0x3c00)
+#define CPUSYS1_SPARKEN MCUCFG_REG(0x3c04)
+#define CPUSYS1_AMUXSEL MCUCFG_REG(0x3c08)
+
+#define MP2_PWR_RST_CTL MCUCFG_REG(0x2008)
+#define MP2_PTP3_CPUTOP_SPMC0 MCUCFG_REG(0x22A0)
+#define MP2_PTP3_CPUTOP_SPMC1 MCUCFG_REG(0x22A4)
+
+#define MP2_COQ MCUCFG_REG(0x22BC)
+#define MP2_COQ_SW_DIS BIT(0)
+
+#define MP2_CA15M_MON_SEL MCUCFG_REG(0x2400)
+#define MP2_CA15M_MON_L MCUCFG_REG(0x2404)
+
+#define CPUSYS2_CPU0_SPMC_CTL MCUCFG_REG(0x2430)
+#define CPUSYS2_CPU1_SPMC_CTL MCUCFG_REG(0x2438)
+#define CPUSYS2_CPU0_SPMC_STA MCUCFG_REG(0x2434)
+#define CPUSYS2_CPU1_SPMC_STA MCUCFG_REG(0x243C)
+
+#define MP0_CA7L_DBG_PWR_CTRL MCUCFG_REG(0x068)
+#define MP1_CA7L_DBG_PWR_CTRL MCUCFG_REG(0x268)
+#define BIG_DBG_PWR_CTRL MCUCFG_REG(0x75C)
+
+#define MP2_SW_RST_B BIT(0)
+#define MP2_TOPAON_APB_MASK BIT(1)
+
+#define B_SW_HOT_PLUG_RESET BIT(30)
+
+#define B_SW_PD_OFFSET 18U
+#define B_SW_PD (U(0x3f) << B_SW_PD_OFFSET)
+
+#define B_SW_SRAM_SLEEPB_OFFSET 12U
+#define B_SW_SRAM_SLEEPB (U(0x3f) << B_SW_SRAM_SLEEPB_OFFSET)
+
+#define B_SW_SRAM_ISOINTB BIT(9)
+#define B_SW_ISO BIT(8)
+#define B_SW_LOGIC_PDB BIT(7)
+#define B_SW_LOGIC_PRE2_PDB BIT(6)
+#define B_SW_LOGIC_PRE1_PDB BIT(5)
+#define B_SW_FSM_OVERRIDE BIT(4)
+#define B_SW_PWR_ON BIT(3)
+#define B_SW_PWR_ON_OVERRIDE_EN BIT(2)
+
+#define B_FSM_STATE_OUT_OFFSET (6U)
+#define B_FSM_STATE_OUT_MASK (U(0x1f) << B_FSM_STATE_OUT_OFFSET)
+#define B_SW_LOGIC_PDBO_ALL_OFF_ACK BIT(5)
+#define B_SW_LOGIC_PDBO_ALL_ON_ACK BIT(4)
+#define B_SW_LOGIC_PRE2_PDBO_ALL_ON_ACK BIT(3)
+#define B_SW_LOGIC_PRE1_PDBO_ALL_ON_ACK BIT(2)
+
+#define B_FSM_OFF (0U << B_FSM_STATE_OUT_OFFSET)
+#define B_FSM_ON (1U << B_FSM_STATE_OUT_OFFSET)
+#define B_FSM_RET (2U << B_FSM_STATE_OUT_OFFSET)
+
+#ifndef __ASSEMBLER__
+/* cpu boot mode */
+enum {
+ MP0_CPUCFG_64BIT_SHIFT = 12U,
+ MP1_CPUCFG_64BIT_SHIFT = 28U,
+ MP0_CPUCFG_64BIT = U(0xf) << MP0_CPUCFG_64BIT_SHIFT,
+ MP1_CPUCFG_64BIT = U(0xf) << MP1_CPUCFG_64BIT_SHIFT
+};
+
+enum {
+ MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT = 0U,
+ MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT = 4U,
+ MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT = 8U,
+ MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT = 12U,
+ MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT = 16U,
+
+ MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK =
+ U(0xf) << MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT,
+ MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK =
+ U(0xf) << MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT,
+ MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK =
+ U(0xf) << MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT,
+ MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK =
+ U(0xf) << MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT,
+ MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK =
+ U(0xf) << MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT
+};
+
+enum {
+ MP1_AINACTS_SHIFT = 4U,
+ MP1_AINACTS = 1U << MP1_AINACTS_SHIFT
+};
+
+enum {
+ MP1_SW_CG_GEN_SHIFT = 12U,
+ MP1_SW_CG_GEN = 1U << MP1_SW_CG_GEN_SHIFT
+};
+
+enum {
+ MP1_L2RSTDISABLE_SHIFT = 14U,
+ MP1_L2RSTDISABLE = 1U << MP1_L2RSTDISABLE_SHIFT
+};
+#endif /* __ASSEMBLER__ */
+
+#endif /* MCUCFG_H */
diff --git a/plat/mediatek/mt8192/include/plat_helpers.h b/plat/mediatek/mt8192/include/plat_helpers.h
new file mode 100644
index 0000000..9b550ee
--- /dev/null
+++ b/plat/mediatek/mt8192/include/plat_helpers.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLAT_HELPERS_H__
+#define __PLAT_HELPERS_H__
+
+unsigned int plat_mediatek_calc_core_pos(u_register_t mpidr);
+
+#endif /* __PLAT_HELPERS_H__ */
diff --git a/plat/mediatek/mt8192/include/plat_macros.S b/plat/mediatek/mt8192/include/plat_macros.S
new file mode 100644
index 0000000..7d17e36
--- /dev/null
+++ b/plat/mediatek/mt8192/include/plat_macros.S
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <platform_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"
+
+.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.
+ * Clobbers: x0 - x10, x26, x27, sp
+ * ---------------------------------------------
+ */
+ .macro plat_crash_print_regs
+ /* To-do: GIC owner */
+ /* To-do: CCI owner */
+ .endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/mediatek/mt8192/include/plat_mtk_lpm.h b/plat/mediatek/mt8192/include/plat_mtk_lpm.h
new file mode 100644
index 0000000..deaac97
--- /dev/null
+++ b/plat/mediatek/mt8192/include/plat_mtk_lpm.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MTK_LPM_H
+#define PLAT_MTK_LPM_H
+
+#include <lib/psci/psci.h>
+#include <lib/utils_def.h>
+
+#define MT_IRQ_REMAIN_MAX U(32)
+#define MT_IRQ_REMAIN_CAT_LOG BIT(31)
+
+struct mt_irqremain {
+ unsigned int count;
+ unsigned int irqs[MT_IRQ_REMAIN_MAX];
+ unsigned int wakeupsrc_cat[MT_IRQ_REMAIN_MAX];
+ unsigned int wakeupsrc[MT_IRQ_REMAIN_MAX];
+};
+
+#define PLAT_RC_STATUS_READY BIT(0)
+#define PLAT_RC_STATUS_FEATURE_EN BIT(1)
+#define PLAT_RC_STATUS_UART_NONSLEEP BIT(31)
+
+struct mt_lpm_tz {
+ int (*pwr_prompt)(unsigned int cpu, const psci_power_state_t *state);
+ int (*pwr_reflect)(unsigned int cpu, const psci_power_state_t *state);
+
+ int (*pwr_cpu_on)(unsigned int cpu, const psci_power_state_t *state);
+ int (*pwr_cpu_dwn)(unsigned int cpu, const psci_power_state_t *state);
+
+ int (*pwr_cluster_on)(unsigned int cpu,
+ const psci_power_state_t *state);
+ int (*pwr_cluster_dwn)(unsigned int cpu,
+ const psci_power_state_t *state);
+
+ int (*pwr_mcusys_on)(unsigned int cpu, const psci_power_state_t *state);
+ int (*pwr_mcusys_on_finished)(unsigned int cpu,
+ const psci_power_state_t *state);
+ int (*pwr_mcusys_dwn)(unsigned int cpu,
+ const psci_power_state_t *state);
+};
+
+const struct mt_lpm_tz *mt_plat_cpu_pm_init(void);
+
+#endif /* PLAT_MTK_LPM_H */
diff --git a/plat/mediatek/mt8192/include/plat_pm.h b/plat/mediatek/mt8192/include/plat_pm.h
new file mode 100644
index 0000000..a2881ce
--- /dev/null
+++ b/plat/mediatek/mt8192/include/plat_pm.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PM_H
+#define PLAT_PM_H
+
+#include <lib/utils_def.h>
+
+#define MT_PLAT_PWR_STATE_CPU U(1)
+#define MT_PLAT_PWR_STATE_CLUSTER U(2)
+#define MT_PLAT_PWR_STATE_MCUSYS U(3)
+#define MT_PLAT_PWR_STATE_SUSPEND2IDLE U(8)
+#define MT_PLAT_PWR_STATE_SYSTEM_SUSPEND U(9)
+
+#define MTK_LOCAL_STATE_RUN U(0)
+#define MTK_LOCAL_STATE_RET U(1)
+#define MTK_LOCAL_STATE_OFF U(2)
+
+#define MTK_AFFLVL_CPU U(0)
+#define MTK_AFFLVL_CLUSTER U(1)
+#define MTK_AFFLVL_MCUSYS U(2)
+#define MTK_AFFLVL_SYSTEM U(3)
+
+#define IS_CLUSTER_OFF_STATE(s) \
+ is_local_state_off(s->pwr_domain_state[MTK_AFFLVL_CLUSTER])
+#define IS_MCUSYS_OFF_STATE(s) \
+ is_local_state_off(s->pwr_domain_state[MTK_AFFLVL_MCUSYS])
+#define IS_SYSTEM_SUSPEND_STATE(s) \
+ is_local_state_off(s->pwr_domain_state[MTK_AFFLVL_SYSTEM])
+
+#define IS_PLAT_SUSPEND_ID(stateid)\
+ ((stateid == MT_PLAT_PWR_STATE_SUSPEND2IDLE) \
+ || (stateid == MT_PLAT_PWR_STATE_SYSTEM_SUSPEND))
+
+#endif /* PLAT_PM_H */
diff --git a/plat/mediatek/mt8192/include/plat_private.h b/plat/mediatek/mt8192/include/plat_private.h
new file mode 100644
index 0000000..42ca415
--- /dev/null
+++ b/plat/mediatek/mt8192/include/plat_private.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2020, 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);
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/mediatek/mt8192/include/plat_sip_calls.h b/plat/mediatek/mt8192/include/plat_sip_calls.h
new file mode 100644
index 0000000..fdc7bea
--- /dev/null
+++ b/plat/mediatek/mt8192/include/plat_sip_calls.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. 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 (4)
+
+#endif /* PLAT_SIP_CALLS_H */
diff --git a/plat/mediatek/mt8192/include/platform_def.h b/plat/mediatek/mt8192/include/platform_def.h
new file mode 100644
index 0000000..ec377b5
--- /dev/null
+++ b/plat/mediatek/mt8192/include/platform_def.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+
+#define PLAT_PRIMARY_CPU 0x0
+
+#define MT_GIC_BASE 0x0c000000
+#define PLAT_MT_CCI_BASE 0x0c500000
+#define MCUCFG_BASE 0x0c530000
+
+#define IO_PHYS 0x10000000
+
+/* Aggregate of all devices for MMU mapping */
+#define MTK_DEV_RNG0_BASE IO_PHYS
+#define MTK_DEV_RNG0_SIZE 0x10000000
+#define MTK_DEV_RNG1_BASE (IO_PHYS + 0x10000000)
+#define MTK_DEV_RNG1_SIZE 0x10000000
+#define MTK_DEV_RNG2_BASE 0x0c000000
+#define MTK_DEV_RNG2_SIZE 0x600000
+#define MTK_MCDI_SRAM_BASE 0x11B000
+#define MTK_MCDI_SRAM_MAP_SIZE 0x1000
+
+#define APUSYS_BASE 0x19000000
+#define APUSYS_SCTRL_REVISER_BASE 0x19021000
+#define APUSYS_SCTRL_REVISER_SIZE 0x1000
+#define APUSYS_APU_S_S_4_BASE 0x190F2000
+#define APUSYS_APU_S_S_4_SIZE 0x1000
+#define APUSYS_APC_AO_WRAPPER_BASE 0x190F8000
+#define APUSYS_APC_AO_WRAPPER_SIZE 0x1000
+#define APUSYS_NOC_DAPC_AO_BASE 0x190FC000
+#define APUSYS_NOC_DAPC_AO_SIZE 0x1000
+
+#define TOPCKGEN_BASE (IO_PHYS + 0x00000000)
+#define INFRACFG_AO_BASE (IO_PHYS + 0x00001000)
+#define GPIO_BASE (IO_PHYS + 0x00005000)
+#define SPM_BASE (IO_PHYS + 0x00006000)
+#define APMIXEDSYS (IO_PHYS + 0x0000C000)
+#define DVFSRC_BASE (IO_PHYS + 0x00012000)
+#define PMIC_WRAP_BASE (IO_PHYS + 0x00026000)
+#define DEVAPC_INFRA_AO_BASE (IO_PHYS + 0x00030000)
+#define DEVAPC_PERI_AO_BASE (IO_PHYS + 0x00034000)
+#define DEVAPC_PERI_AO2_BASE (IO_PHYS + 0x00038000)
+#define DEVAPC_PERI_PAR_AO_BASE (IO_PHYS + 0x0003C000)
+#define EMI_BASE (IO_PHYS + 0x00219000)
+#define EMI_MPU_BASE (IO_PHYS + 0x00226000)
+#define SSPM_MBOX_BASE (IO_PHYS + 0x00480000)
+#define IOCFG_RM_BASE (IO_PHYS + 0x01C20000)
+#define IOCFG_BM_BASE (IO_PHYS + 0x01D10000)
+#define IOCFG_BL_BASE (IO_PHYS + 0x01D30000)
+#define IOCFG_BR_BASE (IO_PHYS + 0x01D40000)
+#define IOCFG_LM_BASE (IO_PHYS + 0x01E20000)
+#define IOCFG_LB_BASE (IO_PHYS + 0x01E70000)
+#define IOCFG_RT_BASE (IO_PHYS + 0x01EA0000)
+#define IOCFG_LT_BASE (IO_PHYS + 0x01F20000)
+#define IOCFG_TL_BASE (IO_PHYS + 0x01F30000)
+#define MMSYS_BASE (IO_PHYS + 0x04000000)
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define UART0_BASE (IO_PHYS + 0x01002000)
+#define UART1_BASE (IO_PHYS + 0x01003000)
+
+#define UART_BAUDRATE 115200
+
+/*******************************************************************************
+ * System counter frequency related constants
+ ******************************************************************************/
+#define SYS_COUNTER_FREQ_IN_TICKS 13000000
+#define SYS_COUNTER_FREQ_IN_MHZ 13
+
+/*******************************************************************************
+ * GIC-600 & interrupt handling related constants
+ ******************************************************************************/
+
+/* Base MTK_platform compatible GIC memory map */
+#define BASE_GICD_BASE MT_GIC_BASE
+#define MT_GIC_RDIST_BASE (MT_GIC_BASE + 0x40000)
+
+#define SYS_CIRQ_BASE (IO_PHYS + 0x204000)
+#define CIRQ_REG_NUM 14
+#define CIRQ_IRQ_NUM 439
+#define CIRQ_SPI_START 64
+#define MD_WDT_IRQ_BIT_ID 110
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH aarch64
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+#define PLATFORM_STACK_SIZE 0x800
+
+#define PLAT_MAX_PWR_LVL U(3)
+#define PLAT_MAX_RET_STATE U(1)
+#define PLAT_MAX_OFF_STATE U(9)
+
+#define PLATFORM_SYSTEM_COUNT U(1)
+#define PLATFORM_MCUSYS_COUNT U(1)
+#define PLATFORM_CLUSTER_COUNT U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT U(8)
+#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER U(8)
+
+#define SOC_CHIP_ID U(0x8192)
+
+/*******************************************************************************
+ * 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 */
diff --git a/plat/mediatek/mt8192/include/rtc.h b/plat/mediatek/mt8192/include/rtc.h
new file mode 100644
index 0000000..a9c7bc8
--- /dev/null
+++ b/plat/mediatek/mt8192/include/rtc.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RTC_H
+#define RTC_H
+
+#include <rtc_mt6359p.h>
+
+#endif /* RTC_H */
diff --git a/plat/mediatek/mt8192/plat_pm.c b/plat/mediatek/mt8192/plat_pm.c
new file mode 100644
index 0000000..018e418
--- /dev/null
+++ b/plat/mediatek/mt8192/plat_pm.c
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* common headers */
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/gpio.h>
+#include <lib/psci/psci.h>
+
+/* platform specific headers */
+#include <mt_gic_v3.h>
+#include <mtk_ptp3_common.h>
+#include <mtspmc.h>
+#include <plat/common/platform.h>
+#include <plat_dfd.h>
+#include <plat_mtk_lpm.h>
+#include <plat_params.h>
+#include <plat_pm.h>
+#include <pmic.h>
+#include <rtc.h>
+
+/*
+ * Cluster state request:
+ * [0] : The CPU requires cluster power down
+ * [1] : The CPU requires cluster power on
+ */
+#define coordinate_cluster(onoff) write_clusterpwrdn_el1(onoff)
+#define coordinate_cluster_pwron() coordinate_cluster(1)
+#define coordinate_cluster_pwroff() coordinate_cluster(0)
+
+/* platform secure entry point */
+static uintptr_t secure_entrypoint;
+/* per-CPU power state */
+static unsigned int plat_power_state[PLATFORM_CORE_COUNT];
+
+/* platform CPU power domain - ops */
+static const struct mt_lpm_tz *plat_mt_pm;
+
+#define plat_mt_pm_invoke(_name, _cpu, _state) ({ \
+ int ret = -1; \
+ if (plat_mt_pm != NULL && plat_mt_pm->_name != NULL) { \
+ ret = plat_mt_pm->_name(_cpu, _state); \
+ } \
+ ret; })
+
+#define plat_mt_pm_invoke_no_check(_name, _cpu, _state) ({ \
+ if (plat_mt_pm != NULL && plat_mt_pm->_name != NULL) { \
+ (void) plat_mt_pm->_name(_cpu, _state); \
+ } \
+ })
+
+/*
+ * Common MTK_platform operations to power on/off a
+ * CPU in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
+ */
+
+static void plat_cpu_pwrdwn_common(unsigned int cpu,
+ const psci_power_state_t *state, unsigned int req_pstate)
+{
+ assert(cpu == plat_my_core_pos());
+
+ plat_mt_pm_invoke_no_check(pwr_cpu_dwn, cpu, state);
+
+ if ((psci_get_pstate_pwrlvl(req_pstate) >= MTK_AFFLVL_CLUSTER) ||
+ (req_pstate == 0U)) { /* hotplug off */
+ coordinate_cluster_pwroff();
+ }
+
+ /* Prevent interrupts from spuriously waking up this CPU */
+ mt_gic_rdistif_save();
+ gicv3_cpuif_disable(cpu);
+ gicv3_rdistif_off(cpu);
+ /* PTP3 config */
+ ptp3_deinit(cpu);
+}
+
+static void plat_cpu_pwron_common(unsigned int cpu,
+ const psci_power_state_t *state, unsigned int req_pstate)
+{
+ assert(cpu == plat_my_core_pos());
+
+ plat_mt_pm_invoke_no_check(pwr_cpu_on, cpu, state);
+
+ coordinate_cluster_pwron();
+
+ /*
+ * If mcusys does power down before then restore
+ * all CPUs' GIC Redistributors
+ */
+ if (IS_MCUSYS_OFF_STATE(state)) {
+ mt_gic_rdistif_restore_all();
+ } else {
+ gicv3_rdistif_on(cpu);
+ gicv3_cpuif_enable(cpu);
+ mt_gic_rdistif_init();
+ mt_gic_rdistif_restore();
+ }
+
+ /* PTP3 config */
+ ptp3_init(cpu);
+}
+
+/*
+ * Common MTK_platform operations to power on/off a
+ * cluster in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
+ */
+
+static void plat_cluster_pwrdwn_common(unsigned int cpu,
+ const psci_power_state_t *state, unsigned int req_pstate)
+{
+ assert(cpu == plat_my_core_pos());
+
+ if (plat_mt_pm_invoke(pwr_cluster_dwn, cpu, state) != 0) {
+ coordinate_cluster_pwron();
+
+ /* TODO: return on fail.
+ * Add a 'return' here before adding any code following
+ * the if-block.
+ */
+ }
+}
+
+static void plat_cluster_pwron_common(unsigned int cpu,
+ const psci_power_state_t *state, unsigned int req_pstate)
+{
+ assert(cpu == plat_my_core_pos());
+
+ if (plat_mt_pm_invoke(pwr_cluster_on, cpu, state) != 0) {
+ /* TODO: return on fail.
+ * Add a 'return' here before adding any code following
+ * the if-block.
+ */
+ }
+}
+
+/*
+ * Common MTK_platform operations to power on/off a
+ * mcusys in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
+ */
+
+static void plat_mcusys_pwrdwn_common(unsigned int cpu,
+ const psci_power_state_t *state, unsigned int req_pstate)
+{
+ assert(cpu == plat_my_core_pos());
+
+ if (plat_mt_pm_invoke(pwr_mcusys_dwn, cpu, state) != 0) {
+ return; /* return on fail */
+ }
+
+ mt_gic_distif_save();
+ gic_sgi_save_all();
+}
+
+static void plat_mcusys_pwron_common(unsigned int cpu,
+ const psci_power_state_t *state, unsigned int req_pstate)
+{
+ assert(cpu == plat_my_core_pos());
+
+ if (plat_mt_pm_invoke(pwr_mcusys_on, cpu, state) != 0) {
+ return; /* return on fail */
+ }
+
+ mt_gic_init();
+ mt_gic_distif_restore();
+ gic_sgi_restore_all();
+
+ dfd_resume();
+
+ plat_mt_pm_invoke_no_check(pwr_mcusys_on_finished, cpu, state);
+}
+
+/*
+ * plat_psci_ops implementation
+ */
+
+static void plat_cpu_standby(plat_local_state_t cpu_state)
+{
+ uint64_t scr;
+
+ scr = read_scr_el3();
+ write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
+
+ isb();
+ dsb();
+ wfi();
+
+ write_scr_el3(scr);
+}
+
+static int plat_power_domain_on(u_register_t mpidr)
+{
+ unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+ unsigned int cluster = 0U;
+
+ if (cpu >= PLATFORM_CORE_COUNT) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ if (!spm_get_cluster_powerstate(cluster)) {
+ spm_poweron_cluster(cluster);
+ }
+
+ /* init CPU reset arch as AARCH64 */
+ mcucfg_init_archstate(cluster, cpu, true);
+ mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint);
+ spm_poweron_cpu(cluster, cpu);
+
+ return PSCI_E_SUCCESS;
+}
+
+static void plat_power_domain_on_finish(const psci_power_state_t *state)
+{
+ unsigned long mpidr = read_mpidr_el1();
+ unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+
+ assert(cpu < PLATFORM_CORE_COUNT);
+
+ /* Allow IRQs to wakeup this core in IDLE flow */
+ mcucfg_enable_gic_wakeup(0U, cpu);
+
+ if (IS_CLUSTER_OFF_STATE(state)) {
+ plat_cluster_pwron_common(cpu, state, 0U);
+ }
+
+ plat_cpu_pwron_common(cpu, state, 0U);
+}
+
+static void plat_power_domain_off(const psci_power_state_t *state)
+{
+ unsigned long mpidr = read_mpidr_el1();
+ unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+
+ assert(cpu < PLATFORM_CORE_COUNT);
+
+ plat_cpu_pwrdwn_common(cpu, state, 0U);
+ spm_poweroff_cpu(0U, cpu);
+
+ /* prevent unintended IRQs from waking up the hot-unplugged core */
+ mcucfg_disable_gic_wakeup(0U, cpu);
+
+ if (IS_CLUSTER_OFF_STATE(state)) {
+ plat_cluster_pwrdwn_common(cpu, state, 0U);
+ }
+}
+
+static void plat_power_domain_suspend(const psci_power_state_t *state)
+{
+ unsigned int cpu = plat_my_core_pos();
+
+ assert(cpu < PLATFORM_CORE_COUNT);
+
+ plat_mt_pm_invoke_no_check(pwr_prompt, cpu, state);
+
+ /* Perform the common CPU specific operations */
+ plat_cpu_pwrdwn_common(cpu, state, plat_power_state[cpu]);
+
+ if (IS_CLUSTER_OFF_STATE(state)) {
+ /* Perform the common cluster specific operations */
+ plat_cluster_pwrdwn_common(cpu, state, plat_power_state[cpu]);
+ }
+
+ if (IS_MCUSYS_OFF_STATE(state)) {
+ /* Perform the common mcusys specific operations */
+ plat_mcusys_pwrdwn_common(cpu, state, plat_power_state[cpu]);
+ }
+}
+
+static void plat_power_domain_suspend_finish(const psci_power_state_t *state)
+{
+ unsigned int cpu = plat_my_core_pos();
+
+ assert(cpu < PLATFORM_CORE_COUNT);
+
+ if (IS_MCUSYS_OFF_STATE(state)) {
+ /* Perform the common mcusys specific operations */
+ plat_mcusys_pwron_common(cpu, state, plat_power_state[cpu]);
+ }
+
+ if (IS_CLUSTER_OFF_STATE(state)) {
+ /* Perform the common cluster specific operations */
+ plat_cluster_pwron_common(cpu, state, plat_power_state[cpu]);
+ }
+
+ /* Perform the common CPU specific operations */
+ plat_cpu_pwron_common(cpu, state, plat_power_state[cpu]);
+
+ plat_mt_pm_invoke_no_check(pwr_reflect, cpu, state);
+}
+
+static int plat_validate_power_state(unsigned int power_state,
+ psci_power_state_t *req_state)
+{
+ unsigned int pstate = psci_get_pstate_type(power_state);
+ unsigned int aff_lvl = psci_get_pstate_pwrlvl(power_state);
+ unsigned int cpu = plat_my_core_pos();
+
+ if (pstate == PSTATE_TYPE_STANDBY) {
+ req_state->pwr_domain_state[0] = PLAT_MAX_RET_STATE;
+ } else {
+ unsigned int i;
+ unsigned int pstate_id = psci_get_pstate_id(power_state);
+ plat_local_state_t s = MTK_LOCAL_STATE_OFF;
+
+ /* Use pstate_id to be power domain state */
+ if (pstate_id > s) {
+ s = (plat_local_state_t)pstate_id;
+ }
+
+ for (i = 0U; i <= aff_lvl; i++) {
+ req_state->pwr_domain_state[i] = s;
+ }
+ }
+
+ plat_power_state[cpu] = power_state;
+ return PSCI_E_SUCCESS;
+}
+
+static void plat_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+ unsigned int lv;
+ unsigned int cpu = plat_my_core_pos();
+
+ for (lv = PSCI_CPU_PWR_LVL; lv <= PLAT_MAX_PWR_LVL; lv++) {
+ req_state->pwr_domain_state[lv] = PLAT_MAX_OFF_STATE;
+ }
+
+ plat_power_state[cpu] =
+ psci_make_powerstate(
+ MT_PLAT_PWR_STATE_SYSTEM_SUSPEND,
+ PSTATE_TYPE_POWERDOWN, PLAT_MAX_PWR_LVL);
+
+ flush_dcache_range((uintptr_t)
+ &plat_power_state[cpu],
+ sizeof(plat_power_state[cpu]));
+}
+
+static void __dead2 plat_mtk_system_off(void)
+{
+ INFO("MTK System Off\n");
+
+ rtc_power_off_sequence();
+ 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");
+
+ gpio_set_value(gpio_reset->index, gpio_reset->polarity);
+
+ wfi();
+ ERROR("MTK System Reset: operation not handled.\n");
+ panic();
+}
+
+static const plat_psci_ops_t plat_psci_ops = {
+ .system_reset = plat_mtk_system_reset,
+ .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_mtk_system_off,
+ .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_psci_ops;
+ secure_entrypoint = sec_entrypoint;
+
+ /*
+ * init the warm reset config for boot CPU
+ * reset arch as AARCH64
+ * reset addr as function bl31_warm_entrypoint()
+ */
+ mcucfg_init_archstate(0U, 0U, true);
+ mcucfg_set_bootaddr(0U, 0U, secure_entrypoint);
+
+ spmc_init();
+ plat_mt_pm = mt_plat_cpu_pm_init();
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8192/plat_sip_calls.c b/plat/mediatek/mt8192/plat_sip_calls.c
new file mode 100644
index 0000000..0fffed5
--- /dev/null
+++ b/plat/mediatek/mt8192/plat_sip_calls.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <mtk_apusys.h>
+#include <mtk_sip_svc.h>
+#include <mt_spm_vcorefs.h>
+#include <plat_dfd.h>
+#include "plat_sip_calls.h"
+
+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)
+{
+ uint64_t ret;
+ uint32_t rnd_val0 = 0U;
+
+ switch (smc_fid) {
+ case MTK_SIP_VCORE_CONTROL_AARCH32:
+ case MTK_SIP_VCORE_CONTROL_AARCH64:
+ ret = spm_vcorefs_args(x1, x2, x3, (uint64_t *)&x4);
+ SMC_RET2(handle, ret, x4);
+ break;
+ case MTK_SIP_APUSYS_CONTROL_AARCH32:
+ case MTK_SIP_APUSYS_CONTROL_AARCH64:
+ ret = apusys_kernel_ctrl(x1, x2, x3, x4, &rnd_val0);
+ SMC_RET2(handle, ret, rnd_val0);
+ break;
+ case MTK_SIP_KERNEL_DFD_AARCH32:
+ case MTK_SIP_KERNEL_DFD_AARCH64:
+ ret = dfd_smc_dispatcher(x1, x2, x3, x4);
+ SMC_RET1(handle, ret);
+ break;
+ default:
+ ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+ break;
+ }
+
+ SMC_RET1(handle, SMC_UNK);
+}
diff --git a/plat/mediatek/mt8192/plat_topology.c b/plat/mediatek/mt8192/plat_topology.c
new file mode 100644
index 0000000..8c1231a
--- /dev/null
+++ b/plat/mediatek/mt8192/plat_topology.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Project Includes */
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/psci/psci.h>
+
+/* Platform Includes */
+#include <plat_helpers.h>
+#include <platform_def.h>
+
+const unsigned char mtk_power_domain_tree_desc[] = {
+ /* Number of root nodes */
+ PLATFORM_SYSTEM_COUNT,
+ /* Number of children for the root node */
+ PLATFORM_MCUSYS_COUNT,
+ /* Number of children for the mcusys node */
+ PLATFORM_CLUSTER_COUNT,
+ /* Number of children for the first cluster node */
+ PLATFORM_CLUSTER0_CORE_COUNT,
+};
+
+/*******************************************************************************
+ * This function returns the MT8192 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;
+
+ if (read_mpidr() & MPIDR_MT_MASK) {
+ /* ARMv8.2 arch */
+ if (mpidr & (MPIDR_AFFLVL_MASK << MPIDR_AFF0_SHIFT)) {
+ return -1;
+ }
+ return plat_mediatek_calc_core_pos(mpidr);
+ }
+
+ 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 * 8));
+}
diff --git a/plat/mediatek/mt8192/platform.mk b/plat/mediatek/mt8192/platform.mk
new file mode 100644
index 0000000..a19fc45
--- /dev/null
+++ b/plat/mediatek/mt8192/platform.mk
@@ -0,0 +1,103 @@
+#
+# Copyright (c) 2020-2022, 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}/common/lpm/ \
+ -I${MTK_PLAT}/drivers/cirq/ \
+ -I${MTK_PLAT}/drivers/gic600/ \
+ -I${MTK_PLAT}/drivers/gpio/ \
+ -I${MTK_PLAT}/drivers/pmic/ \
+ -I${MTK_PLAT}/drivers/pmic_wrap/ \
+ -I${MTK_PLAT}/drivers/rtc/ \
+ -I${MTK_PLAT}/drivers/timer/ \
+ -I${MTK_PLAT}/drivers/uart/ \
+ -I${MTK_PLAT}/include/ \
+ -I${MTK_PLAT_SOC}/include/ \
+ -I${MTK_PLAT_SOC}/drivers/ \
+ -I${MTK_PLAT_SOC}/drivers/apusys/ \
+ -I${MTK_PLAT_SOC}/drivers/dcm \
+ -I${MTK_PLAT_SOC}/drivers/devapc \
+ -I${MTK_PLAT_SOC}/drivers/dfd \
+ -I${MTK_PLAT_SOC}/drivers/emi_mpu/ \
+ -I${MTK_PLAT_SOC}/drivers/gpio/ \
+ -I${MTK_PLAT_SOC}/drivers/mcdi/ \
+ -I${MTK_PLAT_SOC}/drivers/pmic/ \
+ -I${MTK_PLAT_SOC}/drivers/ptp3/ \
+ -I${MTK_PLAT_SOC}/drivers/spmc/
+
+GICV3_SUPPORT_GIC600 := 1
+include drivers/arm/gic/v3/gicv3.mk
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_BL_COMMON_SOURCES := ${GICV3_SOURCES} \
+ ${XLAT_TABLES_LIB_SRCS} \
+ plat/common/aarch64/crash_console_helpers.S \
+ plat/common/plat_psci_common.c
+
+BL31_SOURCES += common/desc_image_load.c \
+ drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ drivers/ti/uart/aarch64/16550_console.S \
+ drivers/gpio/gpio.c \
+ lib/bl_aux_params/bl_aux_params.c \
+ lib/cpus/aarch64/cortex_a55.S \
+ lib/cpus/aarch64/cortex_a76.S \
+ plat/common/plat_gicv3.c \
+ ${MTK_PLAT}/common/mtk_plat_common.c \
+ ${MTK_PLAT}/common/mtk_sip_svc.c \
+ ${MTK_PLAT}/common/params_setup.c \
+ ${MTK_PLAT}/common/lpm/mt_lp_rm.c \
+ ${MTK_PLAT}/drivers/cirq/mt_cirq.c \
+ ${MTK_PLAT}/drivers/gic600/mt_gic_v3.c \
+ ${MTK_PLAT}/drivers/gpio/mtgpio_common.c \
+ ${MTK_PLAT}/drivers/pmic/pmic.c \
+ ${MTK_PLAT}/drivers/pmic_wrap/pmic_wrap_init_v2.c \
+ ${MTK_PLAT}/drivers/rtc/rtc_common.c \
+ ${MTK_PLAT}/drivers/rtc/rtc_mt6359p.c \
+ ${MTK_PLAT}/drivers/timer/mt_timer.c \
+ ${MTK_PLAT}/drivers/uart/uart.c \
+ ${MTK_PLAT_SOC}/aarch64/platform_common.c \
+ ${MTK_PLAT_SOC}/aarch64/plat_helpers.S \
+ ${MTK_PLAT_SOC}/bl31_plat_setup.c \
+ ${MTK_PLAT_SOC}/plat_pm.c \
+ ${MTK_PLAT_SOC}/plat_topology.c \
+ ${MTK_PLAT_SOC}/plat_sip_calls.c \
+ ${MTK_PLAT_SOC}/drivers/apusys/mtk_apusys.c \
+ ${MTK_PLAT_SOC}/drivers/apusys/mtk_apusys_apc.c \
+ ${MTK_PLAT_SOC}/drivers/dcm/mtk_dcm.c \
+ ${MTK_PLAT_SOC}/drivers/dcm/mtk_dcm_utils.c \
+ ${MTK_PLAT_SOC}/drivers/devapc/devapc.c \
+ ${MTK_PLAT_SOC}/drivers/dfd/plat_dfd.c \
+ ${MTK_PLAT_SOC}/drivers/emi_mpu/emi_mpu.c \
+ ${MTK_PLAT_SOC}/drivers/gpio/mtgpio.c \
+ ${MTK_PLAT_SOC}/drivers/mcdi/mt_cpu_pm.c \
+ ${MTK_PLAT_SOC}/drivers/mcdi/mt_cpu_pm_cpc.c \
+ ${MTK_PLAT_SOC}/drivers/mcdi/mt_lp_irqremain.c \
+ ${MTK_PLAT_SOC}/drivers/mcdi/mt_mcdi.c \
+ ${MTK_PLAT_SOC}/drivers/ptp3/mtk_ptp3_main.c \
+ ${MTK_PLAT_SOC}/drivers/spmc/mtspmc.c
+
+# Build SPM drivers
+include ${MTK_PLAT_SOC}/drivers/spm/build.mk
+
+# Configs for A76 and A55
+HW_ASSISTED_COHERENCY := 1
+USE_COHERENT_MEM := 0
+CTX_INCLUDE_AARCH32_REGS := 0
+
+# indicate the reset vector address can be programmed
+PROGRAMMABLE_RESET_ADDRESS := 1
+
+COLD_BOOT_SINGLE_CPU := 1
+
+MACH_MT8192 := 1
+$(eval $(call add_define,MACH_MT8192))
+
+include lib/coreboot/coreboot.mk
+
diff --git a/plat/mediatek/mt8195/aarch64/plat_helpers.S b/plat/mediatek/mt8195/aarch64/plat_helpers.S
new file mode 100644
index 0000000..a973f4d
--- /dev/null
+++ b/plat/mediatek/mt8195/aarch64/plat_helpers.S
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .globl plat_is_my_cpu_primary
+ .globl plat_my_core_pos
+ .globl plat_mediatek_calc_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)
+ * This function uses the plat_mediatek_calc_core_pos()
+ * definition to get the index of the calling CPU.
+ * -----------------------------------------------------
+ */
+func plat_my_core_pos
+ mrs x0, mpidr_el1
+ b plat_mediatek_calc_core_pos
+endfunc plat_my_core_pos
+
+ /* -----------------------------------------------------
+ * unsigned int plat_mediatek_calc_core_pos(u_register_t mpidr);
+ *
+ * In ARMv8.2, AFF2 is cluster id, AFF1 is core id and
+ * AFF0 is thread id. There is only one cluster in ARMv8.2
+ * and one thread in current implementation.
+ *
+ * With this function: CorePos = CoreID (AFF1)
+ * we do it with x0 = (x0 >> 8) & 0xff
+ * -----------------------------------------------------
+ */
+func plat_mediatek_calc_core_pos
+ mov x1, #MPIDR_AFFLVL_MASK
+ and x0, x1, x0, lsr #MPIDR_AFF1_SHIFT
+ ret
+endfunc plat_mediatek_calc_core_pos
diff --git a/plat/mediatek/mt8195/aarch64/platform_common.c b/plat/mediatek/mt8195/aarch64/platform_common.c
new file mode 100644
index 0000000..1f5c5fa
--- /dev/null
+++ b/plat/mediatek/mt8195/aarch64/platform_common.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <platform_def.h>
+
+/* Table of regions to map using the MMU. */
+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_RNG2_BASE, MTK_DEV_RNG2_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(MTK_MCDI_SRAM_BASE, MTK_MCDI_SRAM_MAP_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(DP_SEC_BASE, DP_SEC_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(EDP_SEC_BASE, EDP_SEC_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(APUSYS_SCTRL_REVISER_BASE, APUSYS_SCTRL_REVISER_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(APUSYS_APU_S_S_4_BASE, APUSYS_APU_S_S_4_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(APUSYS_APU_PLL_BASE, APUSYS_APU_PLL_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(APUSYS_APU_ACC_BASE, APUSYS_APU_ACC_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)
+{
+ mmap_add_region(total_base, total_base, total_size,
+ MT_RW_DATA | MT_SECURE);
+ mmap_add_region(ro_start, ro_start, ro_limit - ro_start,
+ MT_CODE | 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;
+}
diff --git a/plat/mediatek/mt8195/bl31_plat_setup.c b/plat/mediatek/mt8195/bl31_plat_setup.c
new file mode 100644
index 0000000..dff6670
--- /dev/null
+++ b/plat/mediatek/mt8195/bl31_plat_setup.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* System Includes */
+#include <assert.h>
+
+/* Project Includes */
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/coreboot.h>
+
+/* Platform Includes */
+#include <emi_mpu.h>
+#include <mt_gic_v3.h>
+#include <mt_spm.h>
+#include <mt_timer.h>
+#include <mtk_dcm.h>
+#include <mtgpio.h>
+#include <plat_params.h>
+#include <plat_private.h>
+
+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;
+ }
+}
+
+/*******************************************************************************
+ * 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_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("MT8195 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)
+{
+ /* Set dcm on */
+ if (!dcm_set_default()) {
+ ERROR("Failed to set default dcm on!!\n");
+ }
+
+ /* Initialize EMI MPU */
+ emi_mpu_init();
+
+ /* Initialize the GIC driver, CPU and distributor interfaces */
+ mt_gic_driver_init();
+ mt_gic_init();
+
+ mt_gpio_init();
+ mt_systimer_init();
+ generic_delay_timer_init();
+ 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_configure_mmu_el3(BL31_START,
+ BL31_END - BL31_START,
+ BL_CODE_BASE,
+ BL_CODE_END);
+}
diff --git a/plat/mediatek/mt8195/drivers/apusys/apupll.c b/plat/mediatek/mt8195/drivers/apusys/apupll.c
new file mode 100644
index 0000000..0eb8d4a
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/apusys/apupll.c
@@ -0,0 +1,581 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/spinlock.h>
+
+#include <apupwr_clkctl.h>
+#include <apupwr_clkctl_def.h>
+#include <mtk_plat_common.h>
+#include <platform_def.h>
+
+uint32_t mixed_con0_addr[APUPLL_MAX] = {
+ APU_PLL4H_PLL1_CON0,
+ APU_PLL4H_PLL2_CON0,
+ APU_PLL4H_PLL3_CON0,
+ APU_PLL4H_PLL4_CON0,
+};
+
+uint32_t mixed_con1_addr[APUPLL_MAX] = {
+ APU_PLL4H_PLL1_CON1,
+ APU_PLL4H_PLL2_CON1,
+ APU_PLL4H_PLL3_CON1,
+ APU_PLL4H_PLL4_CON1,
+};
+
+uint32_t mixed_con3_addr[APUPLL_MAX] = {
+ APU_PLL4H_PLL1_CON3,
+ APU_PLL4H_PLL2_CON3,
+ APU_PLL4H_PLL3_CON3,
+ APU_PLL4H_PLL4_CON3,
+};
+
+uint32_t fhctl_dds_addr[APUPLL_MAX] = {
+ APU_PLL4H_FHCTL0_DDS,
+ APU_PLL4H_FHCTL1_DDS,
+ APU_PLL4H_FHCTL2_DDS,
+ APU_PLL4H_FHCTL3_DDS,
+};
+
+uint32_t fhctl_dvfs_addr[APUPLL_MAX] = {
+ APU_PLL4H_FHCTL0_DVFS,
+ APU_PLL4H_FHCTL1_DVFS,
+ APU_PLL4H_FHCTL2_DVFS,
+ APU_PLL4H_FHCTL3_DVFS,
+};
+
+uint32_t fhctl_mon_addr[APUPLL_MAX] = {
+ APU_PLL4H_FHCTL0_MON,
+ APU_PLL4H_FHCTL1_MON,
+ APU_PLL4H_FHCTL2_MON,
+ APU_PLL4H_FHCTL3_MON,
+};
+
+uint32_t fhctl_cfg_addr[APUPLL_MAX] = {
+ APU_PLL4H_FHCTL0_CFG,
+ APU_PLL4H_FHCTL1_CFG,
+ APU_PLL4H_FHCTL2_CFG,
+ APU_PLL4H_FHCTL3_CFG,
+};
+
+static spinlock_t apupll_lock;
+static spinlock_t npupll_lock;
+static spinlock_t apupll_1_lock;
+static spinlock_t apupll_2_lock;
+static uint32_t pll_cnt[APUPLL_MAX];
+/**
+ * vd2pllidx() - voltage domain to pll idx.
+ * @domain: the voltage domain for getting pll index.
+ *
+ * Caller will get correspond pll index by different voltage domain.
+ * pll_idx[0] --> APUPLL (MDLA0/1)
+ * pll_idx[1] --> NPUPLL (VPU0/1)
+ * pll_idx[2] --> APUPLL1(CONN)
+ * pll_idx[3] --> APUPLL2(IOMMU)
+ * The longer description may have multiple paragraphs.
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 ~ 3 - return the corresponding pll index
+ * * -EEXIST - cannot find pll idex of the specific voltage domain
+ *
+ */
+static int32_t vd2pllidx(enum dvfs_voltage_domain domain)
+{
+ int32_t ret;
+
+ switch (domain) {
+ case V_VPU0:
+ case V_VPU1:
+ ret = NPUPLL;
+ break;
+ case V_MDLA0:
+ case V_MDLA1:
+ ret = APUPLL;
+ break;
+ case V_TOP_IOMMU:
+ ret = APUPLL2;
+ break;
+ case V_APU_CONN:
+ ret = APUPLL1;
+ break;
+ default:
+ ERROR("%s wrong voltage domain: %d\n", __func__, domain);
+ ret = -EEXIST; /* non-exist */
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pllidx2name() - return names of specific pll index.
+ * @pll_idx: input for specific pll index.
+ *
+ * Given pll index, this function will return name of it.
+ *
+ * Context: Any context.
+ * Return: Names of pll_idx, if found, otherwise will return "NULL"
+ */
+static const char *pllidx2name(int32_t pll_idx)
+{
+ static const char *const names[] = {
+ [APUPLL] = "PLL4H_PLL1",
+ [NPUPLL] = "PLL4H_PLL2",
+ [APUPLL1] = "PLL4H_PLL3",
+ [APUPLL2] = "PLL4H_PLL4",
+ [APUPLL_MAX] = "NULL",
+ };
+
+ if (pll_idx >= APUPLL_MAX) {
+ pll_idx = APUPLL_MAX;
+ }
+
+ return names[pll_idx];
+}
+
+/**
+ * _fhctl_mon_done() - poll whether fhctl HW mode is done.
+ * @pll_idx: input for specific pll index.
+ * @tar_dds: target dds for fhctl_mon to be.
+ *
+ * Given pll index, this function will continue to poll whether fhctl_mon
+ * has reached the expected value within 80us.
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 - OK for fhctl_mon == tar_dds
+ * * -ETIMEDOUT - fhctl_mon not reach tar_dds
+ */
+static int32_t _fhctl_mon_done(uint32_t pll_idx, unsigned long tar_dds)
+{
+ unsigned long mon_dds;
+ uint64_t timeout = timeout_init_us(PLL_READY_TIME_20US);
+ int32_t ret = 0;
+
+ tar_dds &= DDS_MASK;
+ do {
+ mon_dds = apupwr_readl(fhctl_mon_addr[pll_idx]) & DDS_MASK;
+ if (mon_dds == tar_dds) {
+ break;
+ }
+
+ if (timeout_elapsed(timeout)) {
+ ERROR("%s monitor DDS 0x%08lx != expect 0x%08lx\n",
+ pllidx2name(pll_idx), mon_dds, tar_dds);
+ ret = -ETIMEDOUT;
+ break;
+ }
+ } while (mon_dds != tar_dds);
+
+ return ret;
+}
+
+/**
+ * _pll_get_postdiv_reg() - return current post dividor of pll_idx
+ * @pll_idx: input for specific pll index.
+ *
+ * Given pll index, this function will return its current post dividor.
+ *
+ * Context: Any context.
+ * Return: post dividor of current pll_idx.
+ *
+ */
+static uint32_t _pll_get_postdiv_reg(uint32_t pll_idx)
+{
+ int32_t pll_postdiv_reg = 0;
+ uint32_t val;
+
+ val = apupwr_readl(mixed_con1_addr[pll_idx]);
+ pll_postdiv_reg = (val >> POSDIV_SHIFT) & POSDIV_MASK;
+ return pll_postdiv_reg;
+}
+
+/**
+ * _set_postdiv_reg() - set pll_idx's post dividor.
+ * @pll_idx: Which PLL to enable/disable
+ * @post_div: the register value of post dividor to be wrtten.
+ *
+ * Below are lists of post dividor register value and its meaning:
+ * [31] APUPLL_SDM_PCW_CHG
+ * [26:24] APUPLL_POSDIV
+ * [21:0] APUPLL_SDM_PCW (8bit integer + 14bit fraction)
+ * expected freq range ----- divider-------post divider in reg:
+ * >1500M (1500/ 1) -> 1 -> 0(2 to the zero power)
+ * > 750M (1500/ 2) -> 2 -> 1(2 to the 1st power)
+ * > 375M (1500/ 4) -> 4 -> 2(2 to the 2nd power)
+ * > 187.5M (1500/ 8) -> 8 -> 3(2 to the 3rd power)
+ * > 93.75M (1500/16) -> 16 -> 4(2 to the 4th power)
+ *
+ * Context: Any context.
+ */
+static void _set_postdiv_reg(uint32_t pll_idx, uint32_t post_div)
+{
+ apupwr_clrbits(POSDIV_MASK << POSDIV_SHIFT, mixed_con1_addr[pll_idx]);
+ apupwr_setbits((post_div & POSDIV_MASK) << POSDIV_SHIFT,
+ mixed_con1_addr[pll_idx]);
+}
+
+/**
+ * _cal_pll_data() - input freq, calculate correspond post dividor and dds.
+ * @pd: address of output post dividor.
+ * @dds: address of output dds.
+ * @freq: input frequency.
+ *
+ * Given freq, this function will calculate correspond post dividor and dds.
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 - done for calculating post dividor and dds.
+ */
+static int32_t _cal_pll_data(uint32_t *pd, uint32_t *dds, uint32_t freq)
+{
+ uint32_t vco, postdiv_val = 1, postdiv_reg = 0;
+ uint32_t pcw_val;
+
+ vco = freq;
+ postdiv_val = 1;
+ postdiv_reg = 0;
+ while (vco <= FREQ_VCO_MIN) {
+ postdiv_val = postdiv_val << 1;
+ postdiv_reg = postdiv_reg + 1;
+ vco = vco << 1;
+ }
+
+ pcw_val = vco * (1 << PCW_FRACTIONAL_SHIFT);
+ pcw_val = pcw_val / FREQ_FIN;
+
+ if (postdiv_reg == 0) { /* Fvco * 2 with post_divider = 2 */
+ pcw_val = pcw_val * 2;
+ postdiv_val = postdiv_val << 1;
+ postdiv_reg = postdiv_reg + 1;
+ } /* Post divider is 1 is not available */
+ *pd = postdiv_reg;
+ *dds = pcw_val | RG_PLL_SDM_PCW_CHG;
+
+ return 0;
+}
+
+/**
+ * _pll_en() - enable/disable RG_PLL_EN of CON1 for pll[pll_idx]
+ * @pll_idx: Which PLL to enable/disable
+ * @on: 1 -> enable, 0 -> disable.
+ *
+ * This funciton will only change RG_PLL_EN of CON1 for pll[pll_idx].
+ *
+ * Context: Any context.
+ */
+static void _pll_en(uint32_t pll_idx, bool on)
+{
+ if (on) {
+ apupwr_setbits(RG_PLL_EN, mixed_con0_addr[pll_idx]);
+ } else {
+ apupwr_clrbits(RG_PLL_EN, mixed_con0_addr[pll_idx]);
+ }
+}
+
+/**
+ * _pll_pwr() - enable/disable PLL_SDM_PWR_ON of CON3 for pll[pll_idx]
+ * @pll_idx: Which PLL to enable/disable
+ * @on: 1 -> enable, 0 -> disable.
+ *
+ * This funciton will only change PLL_SDM_PWR_ON of CON3 for pll[pll_idx].
+ *
+ * Context: Any context.
+ */
+static void _pll_pwr(uint32_t pll_idx, bool on)
+{
+ if (on) {
+ apupwr_setbits(DA_PLL_SDM_PWR_ON, mixed_con3_addr[pll_idx]);
+ } else {
+ apupwr_clrbits(DA_PLL_SDM_PWR_ON, mixed_con3_addr[pll_idx]);
+ }
+}
+
+/**
+ * _pll_iso() - enable/disable PLL_SDM_ISO_EN of CON3 for pll[pll_idx]
+ * @pll_idx: Which PLL to enable/disable
+ * @enable: 1 -> turn on isolation, 0 -> turn off isolation.
+ *
+ * This funciton will turn on/off pll isolation by
+ * changing PLL_SDM_PWR_ON of CON3 for pll[pll_idx].
+ *
+ * Context: Any context.
+ */
+static void _pll_iso(uint32_t pll_idx, bool enable)
+{
+ if (enable) {
+ apupwr_setbits(DA_PLL_SDM_ISO_EN, mixed_con3_addr[pll_idx]);
+ } else {
+ apupwr_clrbits(DA_PLL_SDM_ISO_EN, mixed_con3_addr[pll_idx]);
+ }
+}
+
+/**
+ * _pll_switch() - entry point to turn whole PLL on/off
+ * @pll_idx: Which PLL to enable/disable
+ * @on: 1 -> enable, 0 -> disable.
+ * @fhctl_en: enable or disable fhctl function
+ *
+ * This is the entry poing for controlling pll and fhctl funciton on/off.
+ * Caller can chose only enable pll instead of fhctl function.
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 - done for enable pll or fhctl as well.
+ */
+static int32_t _pll_switch(uint32_t pll_idx, bool on, bool fhctl_en)
+{
+ int32_t ret = 0;
+
+ if (pll_idx >= APUPLL_MAX) {
+ ERROR("%s wrong pll_idx: %d\n", __func__, pll_idx);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (on) {
+ _pll_pwr(pll_idx, true);
+ udelay(PLL_CMD_READY_TIME_1US);
+ _pll_iso(pll_idx, false);
+ udelay(PLL_CMD_READY_TIME_1US);
+ _pll_en(pll_idx, true);
+ udelay(PLL_READY_TIME_20US);
+ } else {
+ _pll_en(pll_idx, false);
+ _pll_iso(pll_idx, true);
+ _pll_pwr(pll_idx, false);
+ }
+
+err:
+ return ret;
+}
+
+/**
+ * apu_pll_enable() - API for smc function to enable/disable pll
+ * @pll_idx: Which pll to enable/disable.
+ * @enable: 1 -> enable, 0 -> disable.
+ * @fhctl_en: enable or disable fhctl function
+ *
+ * pll_idx[0] --> APUPLL (MDLA0/1)
+ * pll_idx[1] --> NPUPLL (VPU0/1)
+ * pll_idx[2] --> APUPLL1(CONN)
+ * pll_idx[3] --> APUPLL2(IOMMU)
+ * The differences between _pll_switch are:
+ * 1. Atomic update pll reference cnt to protect double enable pll &
+ * close pll during user is not zero.
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 - done for enable pll or fhctl as well.
+ */
+int32_t apu_pll_enable(int32_t pll_idx, bool enable, bool fhctl_en)
+{
+ int32_t ret = 0;
+
+ if (pll_idx >= APUPLL_MAX) {
+ ERROR("%s wrong pll_idx: %d\n", __func__, pll_idx);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (enable) {
+ switch (pll_idx) {
+ case APUPLL:
+ spin_lock(&apupll_lock);
+ if (pll_cnt[APUPLL] == 0) {
+ _pll_switch(pll_idx, enable, fhctl_en);
+ }
+ pll_cnt[APUPLL]++;
+ spin_unlock(&apupll_lock);
+ break;
+ case NPUPLL:
+ spin_lock(&npupll_lock);
+ if (pll_cnt[NPUPLL] == 0) {
+ _pll_switch(pll_idx, enable, fhctl_en);
+ }
+ pll_cnt[NPUPLL]++;
+ spin_unlock(&npupll_lock);
+ break;
+ case APUPLL1:
+ spin_lock(&apupll_1_lock);
+ if (pll_cnt[APUPLL1] == 0) {
+ _pll_switch(pll_idx, enable, fhctl_en);
+ }
+ pll_cnt[APUPLL1]++;
+ spin_unlock(&apupll_1_lock);
+ break;
+ case APUPLL2:
+ spin_lock(&apupll_2_lock);
+ if (pll_cnt[APUPLL2] == 0) {
+ _pll_switch(pll_idx, enable, fhctl_en);
+ }
+ pll_cnt[APUPLL2]++;
+ spin_unlock(&apupll_2_lock);
+ break;
+ default:
+ ERROR("%s invalid pll_idx: %d\n", __func__, pll_idx);
+ ret = -EINVAL;
+ break;
+ }
+ } else {
+ switch (pll_idx) {
+ case APUPLL:
+ spin_lock(&apupll_lock);
+ if (pll_cnt[APUPLL]) {
+ pll_cnt[APUPLL]--;
+ }
+ if (pll_cnt[APUPLL] == 0) {
+ _pll_switch(pll_idx, enable, fhctl_en);
+ }
+ spin_unlock(&apupll_lock);
+ break;
+ case NPUPLL:
+ spin_lock(&npupll_lock);
+ if (pll_cnt[NPUPLL]) {
+ pll_cnt[NPUPLL]--;
+ }
+ if (pll_cnt[NPUPLL] == 0) {
+ _pll_switch(pll_idx, enable, fhctl_en);
+ }
+ spin_unlock(&npupll_lock);
+ break;
+ case APUPLL1:
+ spin_lock(&apupll_1_lock);
+ if (pll_cnt[APUPLL1]) {
+ pll_cnt[APUPLL1]--;
+ }
+ if (pll_cnt[APUPLL1] == 0) {
+ _pll_switch(pll_idx, enable, fhctl_en);
+ }
+ spin_unlock(&apupll_1_lock);
+ break;
+ case APUPLL2:
+ spin_lock(&apupll_2_lock);
+ if (pll_cnt[APUPLL2]) {
+ pll_cnt[APUPLL2]--;
+ }
+ if (pll_cnt[APUPLL2] == 0) {
+ _pll_switch(pll_idx, enable, fhctl_en);
+ }
+ spin_unlock(&apupll_2_lock);
+ break;
+ default:
+ ERROR("%s invalid pll_idx: %d\n", __func__, pll_idx);
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+err:
+ return ret;
+}
+
+/**
+ * anpu_pll_set_rate() - API for smc function to set rate of voltage domain.
+ * @domain: Which pll of correspond voltage domain to change rate.
+ * @mode: which mode to use when set_rate
+ * @freq: which frequency to set.
+ *
+ * For V_VPU0/1, it will only allow 1 of them to modify NPUPLL
+ * such that there will be no race condition happen.
+ *
+ * For V_MDLA0/1, it will only allow 1 of them to modify APUPLL1
+ * such that there will be no race condition happen.
+ *
+ * There are 3 kinds of modes to set pll's rate.
+ * 1. pure sw mode: (CON0_PCW)
+ * fhctl function is off and change rate by programming CON1_PCW.
+ * 2. fhctl sw mode: (FHCTL_SW)
+ * fhctl function is on and change rate by programming fhctl_dds.
+ * (post dividor is still need to program CON1_PCW)
+ * 3. fhctl hw mode: (FHCTL_HW)
+ * fhctl function is on and change rate by programming fhctl_dvfs.
+ * (post dividor is still need to program CON1_PCW)
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 - done for set rate of voltage domain.
+ */
+int32_t anpu_pll_set_rate(enum dvfs_voltage_domain domain,
+ enum pll_set_rate_mode mode, int32_t freq)
+{
+ uint32_t pd, old_pd, dds;
+ int32_t pll_idx, ret = 0;
+
+ pll_idx = vd2pllidx(domain);
+ if (pll_idx < 0) {
+ ret = pll_idx;
+ goto err;
+ }
+
+ _cal_pll_data(&pd, &dds, freq / 1000);
+
+ INFO("%s %s new post_div=%d, target dds=0x%08x(%dMhz) mode = %d\n",
+ __func__, pllidx2name(pll_idx), pd, dds, freq / 1000, mode);
+
+ /* spin_lock for NPULL, since vpu0/1 share npupll */
+ if (domain == V_VPU0 || domain == V_VPU1) {
+ spin_lock(&npupll_lock);
+ }
+
+ /* spin_lock for APUPLL, since mdla0/1 shate apupll */
+ if (domain == V_MDLA0 || domain == V_MDLA1) {
+ spin_lock(&apupll_lock);
+ }
+
+ switch (mode) {
+ case CON0_PCW:
+ pd = RG_PLL_SDM_PCW_CHG |
+ (pd & POSDIV_MASK) << POSDIV_SHIFT | dds;
+ apupwr_writel(pd, mixed_con1_addr[pll_idx]);
+ udelay(PLL_READY_TIME_20US);
+ break;
+ case FHCTL_SW:
+ /* pll con0 disable */
+ _pll_en(pll_idx, false);
+ apupwr_writel(dds, fhctl_dds_addr[pll_idx]);
+ _set_postdiv_reg(pll_idx, pd);
+ apupwr_setbits(PLL_TGL_ORG, fhctl_dds_addr[pll_idx]);
+ udelay(PLL_CMD_READY_TIME_1US);
+ /* pll con0 enable */
+ _pll_en(pll_idx, true);
+ udelay(PLL_READY_TIME_20US);
+ break;
+ case FHCTL_HW:
+ old_pd = _pll_get_postdiv_reg(pll_idx);
+ if (pd > old_pd) {
+ _set_postdiv_reg(pll_idx, pd);
+ apupwr_writel(dds, fhctl_dvfs_addr[pll_idx]);
+ } else {
+ apupwr_writel(dds, fhctl_dvfs_addr[pll_idx]);
+ _set_postdiv_reg(pll_idx, pd);
+ }
+ ret = _fhctl_mon_done(pll_idx, dds);
+ break;
+ default:
+ ERROR("%s input wrong mode: %d\n", __func__, mode);
+ ret = -EINVAL;
+ break;
+ }
+
+ /* spin_lock for NPULL, since vpu0/1 share npupll */
+ if (domain == V_VPU0 || domain == V_VPU1) {
+ spin_unlock(&npupll_lock);
+ }
+
+ /* spin_lock for APUPLL, since mdla0/1 share apupll */
+ if (domain == V_MDLA0 || domain == V_MDLA1) {
+ spin_unlock(&apupll_lock);
+ }
+
+err:
+ return ret;
+}
diff --git a/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.c b/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.c
new file mode 100644
index 0000000..465054d
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+
+#include <apupwr_clkctl.h>
+#include <apupwr_clkctl_def.h>
+#include <mtk_plat_common.h>
+#include <platform_def.h>
+
+/* 8195 use PCW mode to change freq directly */
+enum pll_set_rate_mode PLL_MODE = CON0_PCW;
+
+char *buck_domain_str[APUSYS_BUCK_DOMAIN_NUM] = {
+ "V_VPU0",
+ "V_VPU1",
+ "V_MDLA0",
+ "V_MDLA1",
+ "V_APU_CONN",
+ "V_TOP_IOMMU",
+ "V_VCORE",
+};
+
+uint32_t aacc_set[APUSYS_BUCK_DOMAIN_NUM] = {
+ APU_ACC_CONFG_SET1, APU_ACC_CONFG_SET2,
+ APU_ACC_CONFG_SET4, APU_ACC_CONFG_SET5,
+ APU_ACC_CONFG_SET0, APU_ACC_CONFG_SET7
+};
+
+uint32_t aacc_clr[APUSYS_BUCK_DOMAIN_NUM] = {
+ APU_ACC_CONFG_CLR1, APU_ACC_CONFG_CLR2,
+ APU_ACC_CONFG_CLR4, APU_ACC_CONFG_CLR5,
+ APU_ACC_CONFG_CLR0, APU_ACC_CONFG_CLR7
+};
+
+struct reg_seq {
+ uint32_t address;
+ uint32_t val;
+};
+
+static const struct reg_seq init_acc_cfg[] = {
+ { APU_ACC_CONFG_SET0, BIT(BIT_SEL_APU) },
+ { APU_ACC_CONFG_CLR0, BIT(BIT_CGEN_SOC) },
+ { APU_ACC_CONFG_SET0, BIT(BIT_SEL_APU_DIV2) },
+ { APU_ACC_CONFG_SET7, BIT(BIT_SEL_APU) },
+ { APU_ACC_CONFG_CLR7, BIT(BIT_CGEN_SOC) },
+ { APU_ACC_CONFG_SET7, BIT(BIT_SEL_APU_DIV2) },
+ { APU_ACC_CONFG_SET1, BIT(BIT_SEL_APU) },
+ { APU_ACC_CONFG_CLR1, BIT(BIT_CGEN_SOC) },
+ { APU_ACC_CONFG_SET1, BIT(BIT_SEL_APU_DIV2) },
+ { APU_ACC_CONFG_SET2, BIT(BIT_INVEN_OUT) },
+ { APU_ACC_CONFG_SET2, BIT(BIT_SEL_APU) },
+ { APU_ACC_CONFG_CLR2, BIT(BIT_CGEN_SOC) },
+ { APU_ACC_CONFG_SET2, BIT(BIT_SEL_APU_DIV2) },
+ { APU_ACC_CONFG_SET4, BIT(BIT_SEL_APU) },
+ { APU_ACC_CONFG_CLR4, BIT(BIT_CGEN_SOC) },
+ { APU_ACC_CONFG_SET4, BIT(BIT_SEL_APU_DIV2) },
+ { APU_ACC_CONFG_SET5, BIT(BIT_INVEN_OUT) },
+ { APU_ACC_CONFG_SET5, BIT(BIT_SEL_APU) },
+ { APU_ACC_CONFG_CLR5, BIT(BIT_CGEN_SOC) },
+ { APU_ACC_CONFG_SET5, BIT(BIT_SEL_APU_DIV2) },
+};
+
+int32_t apupwr_smc_acc_init_all(void)
+{
+ int32_t i;
+
+ for (i = 0; i < ARRAY_SIZE(init_acc_cfg); i++) {
+ apupwr_writel(init_acc_cfg[i].val,
+ init_acc_cfg[i].address);
+ }
+
+ /* Deault ACC will raise APU_DIV_2 */
+ apupwr_smc_pll_set_rate(BUCK_VCONN_DOMAIN_DEFAULT_FREQ,
+ true, V_APU_CONN);
+
+ apupwr_smc_pll_set_rate(BUCK_VCONN_DOMAIN_DEFAULT_FREQ,
+ true, V_TOP_IOMMU);
+
+ apupwr_smc_pll_set_rate(BUCK_VVPU_DOMAIN_DEFAULT_FREQ,
+ true, V_VPU0);
+
+ apupwr_smc_pll_set_rate(BUCK_VMDLA_DOMAIN_DEFAULT_FREQ,
+ true, V_MDLA0);
+
+ return 0;
+}
+
+void apupwr_smc_acc_top(bool enable)
+{
+ if (enable) {
+ apupwr_writel(BIT(BIT_CGEN_APU), aacc_set[V_APU_CONN]);
+ apupwr_writel(BIT(BIT_CGEN_APU), aacc_set[V_TOP_IOMMU]);
+ } else {
+ apupwr_writel(BIT(BIT_CGEN_APU), aacc_clr[V_APU_CONN]);
+ apupwr_writel(BIT(BIT_CGEN_APU), aacc_clr[V_TOP_IOMMU]);
+ }
+}
+
+/*
+ * acc_clk_set_parent:ACC MUX select
+ * 0. freq parameters here, only ACC clksrc is valid
+ * 1. Switch between APUPLL <=> Parking (F26M, PARK)
+ * 2. Turn on/off CG_F26M, CG_PARK, CG_SOC, but no CG_APU
+ * 3. Clear APU Div2 while Parking
+ * 4. Only use clksrc of APUPLL while ACC CG_APU is on
+ */
+int32_t apupwr_smc_acc_set_parent(uint32_t freq, uint32_t domain)
+{
+ uint32_t acc_set = 0;
+ uint32_t acc_clr = 0;
+ int32_t ret = 0;
+
+ if (freq > DVFS_FREQ_ACC_APUPLL) {
+ ERROR("%s wrong clksrc: %d\n", __func__, freq);
+ ret = -EIO;
+ goto err;
+ }
+
+ switch (domain) {
+ case V_VPU1:
+ case V_VPU0:
+ case V_MDLA1:
+ case V_MDLA0:
+ case V_APU_CONN:
+ case V_TOP_IOMMU:
+ acc_set = aacc_set[domain];
+ acc_clr = aacc_clr[domain];
+ break;
+ default:
+ ret = -EIO;
+ break;
+ }
+
+ /* Select park source */
+ switch (freq) {
+ case DVFS_FREQ_ACC_PARKING:
+ /* Select park source */
+ apupwr_writel(BIT(BIT_SEL_PARK), acc_set);
+ apupwr_writel(BIT(BIT_SEL_F26M), acc_clr);
+ /* Enable park cg */
+ apupwr_writel(BIT(BIT_CGEN_PARK), acc_set);
+ apupwr_writel(BIT(BIT_CGEN_F26M) | BIT(BIT_CGEN_SOC), acc_clr);
+ /* Select park path */
+ apupwr_writel(BIT(BIT_SEL_APU), acc_clr);
+ /* clear apu div 2 */
+ apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_clr);
+ break;
+
+ case DVFS_FREQ_ACC_APUPLL:
+ /* Select park path */
+ apupwr_writel(BIT(BIT_SEL_APU), acc_set);
+ /* Clear park cg */
+ apupwr_writel(BIT(BIT_CGEN_PARK) | BIT(BIT_CGEN_F26M) |
+ BIT(BIT_CGEN_SOC), acc_clr);
+ break;
+
+ case DVFS_FREQ_ACC_SOC:
+ /* Select park source */
+ apupwr_writel(BIT(BIT_SEL_PARK), acc_clr);
+ apupwr_writel(BIT(BIT_SEL_F26M), acc_clr);
+ /* Enable park cg */
+ apupwr_writel(BIT(BIT_CGEN_SOC), acc_set);
+ apupwr_writel(BIT(BIT_CGEN_F26M) | BIT(BIT_CGEN_PARK), acc_clr);
+ /* Select park path */
+ apupwr_writel(BIT(BIT_SEL_APU), acc_clr);
+ /* clear apu div 2 */
+ apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_clr);
+ break;
+
+ case DVFS_FREQ_ACC_26M:
+ case DVFS_FREQ_NOT_SUPPORT:
+ default:
+ /* Select park source */
+ apupwr_writel(BIT(BIT_SEL_F26M), acc_set);
+ apupwr_writel(BIT(BIT_SEL_PARK), acc_clr);
+ /* Enable park cg */
+ apupwr_writel(BIT(BIT_CGEN_F26M), acc_set);
+ apupwr_writel(BIT(BIT_CGEN_PARK) | BIT(BIT_CGEN_SOC), acc_clr);
+ /* Select park path */
+ apupwr_writel(BIT(BIT_SEL_APU), acc_clr);
+ /* clear apu div 2 */
+ apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_clr);
+ ERROR("[APUPWR] %s wrong ACC clksrc : %d, force assign 26M\n",
+ __func__, freq);
+ break;
+ }
+
+err:
+ return ret;
+}
+
+int32_t apupwr_smc_pll_set_rate(uint32_t freq, bool div2, uint32_t domain)
+{
+ int32_t ret = 0;
+ uint32_t acc_set0 = 0, acc_set1 = 0;
+
+ if (freq > DVFS_FREQ_MAX) {
+ ERROR("%s wrong freq: %d\n", __func__, freq);
+ ret = -EIO;
+ goto err;
+ }
+
+ /*
+ * Switch to Parking src
+ * 1. Need to switch out all ACCs sharing the same apupll
+ */
+ switch (domain) {
+ case V_MDLA0:
+ case V_MDLA1:
+ acc_set0 = APU_ACC_CONFG_SET4;
+ acc_set1 = APU_ACC_CONFG_SET5;
+ ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
+ V_MDLA0);
+ ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
+ V_MDLA1);
+ break;
+ case V_VPU0:
+ case V_VPU1:
+ acc_set0 = APU_ACC_CONFG_SET1;
+ acc_set1 = APU_ACC_CONFG_SET2;
+ ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
+ V_VPU0);
+ ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
+ V_VPU1);
+ break;
+ case V_APU_CONN:
+ acc_set0 = APU_ACC_CONFG_SET0;
+ ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
+ V_APU_CONN);
+ break;
+ case V_TOP_IOMMU:
+ acc_set0 = APU_ACC_CONFG_SET7;
+ ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
+ V_TOP_IOMMU);
+ break;
+ default:
+ ERROR("[APUPWR] %s %d invalid domain (%d)\n",
+ __func__, __LINE__, domain);
+ ret = -EIO;
+ goto err;
+ }
+
+ anpu_pll_set_rate(domain, PLL_MODE, (div2) ? (freq * 2) : freq);
+
+ if (div2) {
+ apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_set0);
+ if (acc_set1) {
+ apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_set1);
+ }
+ }
+
+ /*
+ * Switch back to APUPLL
+ * Only switch back to APUPLL while CG_APU on
+ * And clksrc is not APUPLL
+ */
+ switch (domain) {
+ case V_VPU0:
+ case V_VPU1:
+ if ((apupwr_readl(acc_set0) & BIT(BIT_CGEN_APU)) &&
+ !(apupwr_readl(acc_set0) & BIT(BIT_SEL_APU))) {
+ ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
+ V_VPU0);
+ }
+ if ((apupwr_readl(acc_set1) & BIT(BIT_CGEN_APU)) &&
+ !(apupwr_readl(acc_set1) & BIT(BIT_SEL_APU))) {
+ ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
+ V_VPU1);
+ }
+ break;
+ case V_MDLA0:
+ case V_MDLA1:
+ if ((apupwr_readl(acc_set0) & BIT(BIT_CGEN_APU)) &&
+ !(apupwr_readl(acc_set0) & BIT(BIT_SEL_APU))) {
+ ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
+ V_MDLA0);
+ }
+ if ((apupwr_readl(acc_set1) & BIT(BIT_CGEN_APU)) &&
+ !(apupwr_readl(acc_set1) & BIT(BIT_SEL_APU))) {
+ ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
+ V_MDLA1);
+ }
+ break;
+ case V_APU_CONN:
+ case V_TOP_IOMMU:
+ if ((apupwr_readl(acc_set0) & BIT(BIT_CGEN_APU)) &&
+ !(apupwr_readl(acc_set0) & BIT(BIT_SEL_APU))) {
+ ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
+ domain);
+ }
+ break;
+ default:
+ ERROR("[APUPWR] %s %d invalid domain (%d)\n",
+ __func__, __LINE__, domain);
+ ret = -EIO;
+ break;
+ }
+ INFO("[%s][%d] set domain %d to freq %d\n",
+ __func__, __LINE__, domain, (div2) ? (freq * 2) : freq);
+
+err:
+ return ret;
+}
+
+int32_t apupwr_smc_bulk_pll(bool enable)
+{
+ int32_t ret = 0;
+ int32_t pll_idx;
+
+ if (enable) {
+ for (pll_idx = APUPLL; pll_idx < APUPLL_MAX; pll_idx++) {
+ ret = apu_pll_enable(pll_idx, enable, false);
+ if (ret != 0) {
+ goto err;
+ }
+ }
+ } else {
+ for (pll_idx = APUPLL2; pll_idx >= APUPLL; pll_idx--) {
+ ret = apu_pll_enable(pll_idx, enable, false);
+ if (ret != 0) {
+ goto err;
+ }
+ }
+ }
+
+err:
+ return ret;
+}
+
+void apupwr_smc_bus_prot_cg_on(void)
+{
+ apupwr_clrbits(AO_MD32_MNOC_MASK, APU_CSR_DUMMY_0);
+}
diff --git a/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.h b/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.h
new file mode 100644
index 0000000..3b27c1b
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef APUPWR_CLKCTL_H
+#define APUPWR_CLKCTL_H
+
+#include <arch_helpers.h>
+#include <apupwr_clkctl_def.h>
+
+int32_t apupwr_smc_acc_init_all(void);
+void apupwr_smc_acc_top(bool enable);
+int32_t apupwr_smc_acc_set_parent(uint32_t freq, uint32_t domain);
+int32_t apupwr_smc_pll_set_rate(uint32_t pll, bool div2, uint32_t domain);
+int32_t apupwr_smc_bulk_pll(bool enable);
+void apupwr_smc_bus_prot_cg_on(void);
+
+int32_t apu_pll_enable(int32_t pll_idx, bool enable, bool fhctl_en);
+int32_t anpu_pll_set_rate(enum dvfs_voltage_domain domain,
+ enum pll_set_rate_mode mode, int32_t freq);
+#endif /* APUPWR_CLKCTL_H */
diff --git a/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl_def.h b/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl_def.h
new file mode 100644
index 0000000..6663ad9
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl_def.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef APUPWR_CLKCTL_DEF_H
+#define APUPWR_CLKCTL_DEF_H
+
+#include <lib/mmio.h>
+
+enum dvfs_voltage_domain {
+ V_VPU0 = 0,
+ V_VPU1 = 1,
+ V_MDLA0 = 2,
+ V_MDLA1 = 3,
+ V_APU_CONN = 4,
+ V_TOP_IOMMU = 5,
+ V_VCORE = 6,
+ APUSYS_BUCK_DOMAIN_NUM = 7,
+};
+
+enum dvfs_freq {
+ DVFS_FREQ_NOT_SUPPORT = 0,
+ DVFS_FREQ_ACC_26M = 1,
+ DVFS_FREQ_ACC_PARKING = 2,
+ DVFS_FREQ_ACC_SOC = 3,
+ DVFS_FREQ_ACC_APUPLL = 4,
+ DVFS_FREQ_00_026000_F = 26000,
+ DVFS_FREQ_00_208000_F = 208000,
+ DVFS_FREQ_00_238000_F = 238000,
+ DVFS_FREQ_00_273000_F = 273000,
+ DVFS_FREQ_00_312000_F = 312000,
+ DVFS_FREQ_00_358000_F = 358000,
+ DVFS_FREQ_00_385000_F = 385000,
+ DVFS_FREQ_00_499200_F = 499200,
+ DVFS_FREQ_00_500000_F = 500000,
+ DVFS_FREQ_00_525000_F = 525000,
+ DVFS_FREQ_00_546000_F = 546000,
+ DVFS_FREQ_00_594000_F = 594000,
+ DVFS_FREQ_00_624000_F = 624000,
+ DVFS_FREQ_00_688000_F = 688000,
+ DVFS_FREQ_00_687500_F = 687500,
+ DVFS_FREQ_00_728000_F = 728000,
+ DVFS_FREQ_00_800000_F = 800000,
+ DVFS_FREQ_00_832000_F = 832000,
+ DVFS_FREQ_00_960000_F = 960000,
+ DVFS_FREQ_00_1100000_F = 1100000,
+};
+#define DVFS_FREQ_MAX (DVFS_FREQ_00_1100000_F)
+
+enum pll_set_rate_mode {
+ CON0_PCW = 0,
+ FHCTL_SW = 1,
+ FHCTL_HW = 2,
+ PLL_SET_RATE_MODE_MAX = 3,
+};
+
+enum apupll {
+ APUPLL = 0,
+ NPUPLL = 1,
+ APUPLL1 = 2,
+ APUPLL2 = 3,
+ APUPLL_MAX = 4,
+};
+
+#define BUCK_VVPU_DOMAIN_DEFAULT_FREQ (DVFS_FREQ_00_273000_F)
+#define BUCK_VMDLA_DOMAIN_DEFAULT_FREQ (DVFS_FREQ_00_312000_F)
+#define BUCK_VCONN_DOMAIN_DEFAULT_FREQ (DVFS_FREQ_00_208000_F)
+
+#define apupwr_writel(VAL, REG) mmio_write_32((uintptr_t)REG, VAL)
+#define apupwr_writel_relax(VAL, REG) mmio_write_32_relax((uintptr_t)REG, VAL)
+#define apupwr_readl(REG) mmio_read_32((uintptr_t)REG)
+#define apupwr_clrbits(VAL, REG) mmio_clrbits_32((uintptr_t)REG, VAL)
+#define apupwr_setbits(VAL, REG) mmio_setbits_32((uintptr_t)REG, VAL)
+#define apupwr_clrsetbits(CLR_VAL, SET_VAL, REG) \
+ mmio_clrsetbits_32((uintptr_t)REG, CLR_VAL, SET_VAL)
+
+/* PLL and related register */
+#define APU_PLL_BASE (APUSYS_APU_PLL_BASE)
+#define APU_PLL4H_PLL1_CON0 (APU_PLL_BASE + 0x008)
+#define APU_PLL4H_PLL1_CON1 (APU_PLL_BASE + 0x00C)
+#define APU_PLL4H_PLL1_CON3 (APU_PLL_BASE + 0x014)
+
+#define APU_PLL4H_PLL2_CON0 (APU_PLL_BASE + 0x018)
+#define APU_PLL4H_PLL2_CON1 (APU_PLL_BASE + 0x01C)
+#define APU_PLL4H_PLL2_CON3 (APU_PLL_BASE + 0x024)
+
+#define APU_PLL4H_PLL3_CON0 (APU_PLL_BASE + 0x028)
+#define APU_PLL4H_PLL3_CON1 (APU_PLL_BASE + 0x02C)
+#define APU_PLL4H_PLL3_CON3 (APU_PLL_BASE + 0x034)
+
+#define APU_PLL4H_PLL4_CON0 (APU_PLL_BASE + 0x038)
+#define APU_PLL4H_PLL4_CON1 (APU_PLL_BASE + 0x03C)
+#define APU_PLL4H_PLL4_CON3 (APU_PLL_BASE + 0x044)
+
+#define APU_PLL4H_FHCTL_HP_EN (APU_PLL_BASE + 0x0E00)
+#define APU_PLL4H_FHCTL_UNITSLOPE_EN (APU_PLL_BASE + 0x0E04)
+#define APU_PLL4H_FHCTL_CLK_CON (APU_PLL_BASE + 0x0E08)
+#define APU_PLL4H_FHCTL_RST_CON (APU_PLL_BASE + 0x0E0C)
+#define APU_PLL4H_FHCTL_SLOPE0 (APU_PLL_BASE + 0x0E10)
+#define APU_PLL4H_FHCTL_SLOPE1 (APU_PLL_BASE + 0x0E14)
+#define APU_PLL4H_FHCTL_DSSC_CFG (APU_PLL_BASE + 0x0E18)
+#define APU_PLL4H_FHCTL_DSSC0_CON (APU_PLL_BASE + 0x0E1C)
+#define APU_PLL4H_FHCTL_DSSC1_CON (APU_PLL_BASE + 0x0E20)
+#define APU_PLL4H_FHCTL_DSSC2_CON (APU_PLL_BASE + 0x0E24)
+#define APU_PLL4H_FHCTL_DSSC3_CON (APU_PLL_BASE + 0x0E28)
+#define APU_PLL4H_FHCTL_DSSC4_CON (APU_PLL_BASE + 0x0E2C)
+#define APU_PLL4H_FHCTL_DSSC5_CON (APU_PLL_BASE + 0x0E30)
+#define APU_PLL4H_FHCTL_DSSC6_CON (APU_PLL_BASE + 0x0E34)
+#define APU_PLL4H_FHCTL_DSSC7_CON (APU_PLL_BASE + 0x0E38)
+#define APU_PLL4H_FHCTL0_CFG (APU_PLL_BASE + 0x0E3C)
+#define APU_PLL4H_FHCTL0_UPDNLMT (APU_PLL_BASE + 0x0E40)
+#define APU_PLL4H_FHCTL0_DDS (APU_PLL_BASE + 0x0E44)
+#define APU_PLL4H_FHCTL0_DVFS (APU_PLL_BASE + 0x0E48)
+#define APU_PLL4H_FHCTL0_MON (APU_PLL_BASE + 0x0E4C)
+#define APU_PLL4H_FHCTL1_CFG (APU_PLL_BASE + 0x0E50)
+#define APU_PLL4H_FHCTL1_UPDNLMT (APU_PLL_BASE + 0x0E54)
+#define APU_PLL4H_FHCTL1_DDS (APU_PLL_BASE + 0x0E58)
+#define APU_PLL4H_FHCTL1_DVFS (APU_PLL_BASE + 0x0E5C)
+#define APU_PLL4H_FHCTL1_MON (APU_PLL_BASE + 0x0E60)
+#define APU_PLL4H_FHCTL2_CFG (APU_PLL_BASE + 0x0E64)
+#define APU_PLL4H_FHCTL2_UPDNLMT (APU_PLL_BASE + 0x0E68)
+#define APU_PLL4H_FHCTL2_DDS (APU_PLL_BASE + 0x0E6C)
+#define APU_PLL4H_FHCTL2_DVFS (APU_PLL_BASE + 0x0E70)
+#define APU_PLL4H_FHCTL2_MON (APU_PLL_BASE + 0x0E74)
+#define APU_PLL4H_FHCTL3_CFG (APU_PLL_BASE + 0x0E78)
+#define APU_PLL4H_FHCTL3_UPDNLMT (APU_PLL_BASE + 0x0E7C)
+#define APU_PLL4H_FHCTL3_DDS (APU_PLL_BASE + 0x0E80)
+#define APU_PLL4H_FHCTL3_DVFS (APU_PLL_BASE + 0x0E84)
+#define APU_PLL4H_FHCTL3_MON (APU_PLL_BASE + 0x0E88)
+
+/* PLL4H_PLLx_CON0 */
+#define RG_PLL_EN BIT(0)
+
+/* PLL4H_PLLx_CON1 */
+#define RG_PLL_SDM_PCW_CHG BIT(31)
+#define POSDIV_SHIFT (24U)
+#define POSDIV_MASK (0x7)
+
+/* PLL4H_PLLx_CON3 */
+#define DA_PLL_SDM_PWR_ON BIT(0)
+#define DA_PLL_SDM_ISO_EN BIT(1)
+
+/* FHCTLx_DDS */
+#define DDS_MASK GENMASK_32(21, 0)
+#define PCW_FRACTIONAL_SHIFT 14U
+#define PLL_TGL_ORG BIT(31)
+
+#define PLL_READY_TIME_20US (20U)
+#define PLL_CMD_READY_TIME_1US (1U)
+
+#define FREQ_VCO_MIN (1500U) /* 1500MHz*/
+#define FREQ_FIN (26U) /* 26M*/
+
+/* ACC and related register */
+#define APU_ACC_BASE (APUSYS_APU_ACC_BASE)
+#define APU_ACC_CONFG_SET0 (APU_ACC_BASE + 0x000)
+#define APU_ACC_CONFG_SET1 (APU_ACC_BASE + 0x004)
+#define APU_ACC_CONFG_SET2 (APU_ACC_BASE + 0x008)
+#define APU_ACC_CONFG_SET4 (APU_ACC_BASE + 0x010)
+#define APU_ACC_CONFG_SET5 (APU_ACC_BASE + 0x014)
+#define APU_ACC_CONFG_SET7 (APU_ACC_BASE + 0x01C)
+
+#define APU_ACC_CONFG_CLR0 (APU_ACC_BASE + 0x040)
+#define APU_ACC_CONFG_CLR1 (APU_ACC_BASE + 0x044)
+#define APU_ACC_CONFG_CLR2 (APU_ACC_BASE + 0x048)
+#define APU_ACC_CONFG_CLR4 (APU_ACC_BASE + 0x050)
+#define APU_ACC_CONFG_CLR5 (APU_ACC_BASE + 0x054)
+#define APU_ACC_CONFG_CLR7 (APU_ACC_BASE + 0x05C)
+
+#define APU_ACC_FM_CONFG_SET (APU_ACC_BASE + 0x0C0)
+#define APU_ACC_FM_CONFG_CLR (APU_ACC_BASE + 0x0C4)
+#define APU_ACC_FM_SEL (APU_ACC_BASE + 0x0C8)
+#define APU_ACC_FM_CNT (APU_ACC_BASE + 0x0CC)
+
+/* APU AO control */
+#define APU_AO_CTRL_BASE (APUSYS_APU_S_S_4_BASE)
+#define APU_CSR_DUMMY_0 (APU_AO_CTRL_BASE + 0x24)
+
+#define AO_MD32_MNOC_MASK (BIT(1) | BIT(0))
+
+#define BIT_CGEN_F26M (0)
+#define BIT_CGEN_PARK (1)
+#define BIT_CGEN_SOC (2)
+#define BIT_CGEN_APU (3)
+#define BIT_CGEN_OUT (4)
+#define BIT_SEL_PARK (8)
+#define BIT_SEL_F26M (9)
+#define BIT_SEL_APU_DIV2 (10)
+#define BIT_SEL_APU (11)
+#define BIT_SEL_PARK_SRC_OUT (12)
+#define BIT_INVEN_OUT (15)
+
+#endif /* APUPWR_CLKCTL_DEF_H*/
diff --git a/plat/mediatek/mt8195/drivers/apusys/mtk_apusys.c b/plat/mediatek/mt8195/drivers/apusys/mtk_apusys.c
new file mode 100644
index 0000000..3ed26a1
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/apusys/mtk_apusys.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+
+#include <apupwr_clkctl.h>
+#include <mtk_apusys.h>
+#include <plat/common/platform.h>
+
+int32_t apusys_kernel_ctrl(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4,
+ uint32_t *ret1)
+{
+ int32_t ret = 0L;
+ uint32_t request_ops;
+
+ request_ops = (uint32_t)x1;
+
+ switch (request_ops) {
+ case MTK_SIP_APU_START_MCU:
+ /* setup addr[33:32] in reviser */
+ mmio_write_32(REVISER_SECUREFW_CTXT, 0U);
+ mmio_write_32(REVISER_USDRFW_CTXT, 0U);
+
+ /* setup secure sideband */
+ mmio_write_32(AO_SEC_FW,
+ (SEC_FW_NON_SECURE << SEC_FW_SHIFT_NS) |
+ (0U << SEC_FW_DOMAIN_SHIFT));
+
+ /* setup boot address */
+ mmio_write_32(AO_MD32_BOOT_CTRL, 0U);
+
+ /* setup pre-define region */
+ mmio_write_32(AO_MD32_PRE_DEFINE,
+ (PRE_DEFINE_CACHE_TCM << PRE_DEFINE_SHIFT_0G) |
+ (PRE_DEFINE_CACHE << PRE_DEFINE_SHIFT_1G) |
+ (PRE_DEFINE_CACHE << PRE_DEFINE_SHIFT_2G) |
+ (PRE_DEFINE_CACHE << PRE_DEFINE_SHIFT_3G));
+
+ /* release runstall */
+ mmio_write_32(AO_MD32_SYS_CTRL, SYS_CTRL_RUN);
+
+ INFO("[APUSYS] rev(0x%08x,0x%08x)\n",
+ mmio_read_32(REVISER_SECUREFW_CTXT),
+ mmio_read_32(REVISER_USDRFW_CTXT));
+ INFO("[APUSYS] ao(0x%08x,0x%08x,0x%08x,0x%08x,0x%08x)\n",
+ mmio_read_32(AO_SEC_FW),
+ mmio_read_32(AO_SEC_USR_FW),
+ mmio_read_32(AO_MD32_BOOT_CTRL),
+ mmio_read_32(AO_MD32_PRE_DEFINE),
+ mmio_read_32(AO_MD32_SYS_CTRL));
+ break;
+ case MTK_SIP_APU_STOP_MCU:
+ /* hold runstall */
+ mmio_write_32(AO_MD32_SYS_CTRL, SYS_CTRL_STALL);
+
+ INFO("[APUSYS] md32_boot_ctrl=0x%08x,runstall=0x%08x\n",
+ mmio_read_32(AO_MD32_BOOT_CTRL),
+ mmio_read_32(AO_MD32_SYS_CTRL));
+ break;
+ case MTK_SIP_APUPWR_BUS_PROT_CG_ON:
+ apupwr_smc_bus_prot_cg_on();
+ break;
+ case MTK_SIP_APUPWR_BULK_PLL:
+ ret = apupwr_smc_bulk_pll((bool)x2);
+ break;
+ case MTK_SIP_APUPWR_ACC_INIT_ALL:
+ ret = apupwr_smc_acc_init_all();
+ break;
+ case MTK_SIP_APUPWR_ACC_TOP:
+ apupwr_smc_acc_top((bool)x2);
+ break;
+ default:
+ ERROR("%s, unknown request_ops=0x%x\n", __func__, request_ops);
+ break;
+ }
+
+ return ret;
+}
diff --git a/plat/mediatek/mt8195/drivers/apusys/mtk_apusys.h b/plat/mediatek/mt8195/drivers/apusys/mtk_apusys.h
new file mode 100644
index 0000000..639abd3
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/apusys/mtk_apusys.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_APUSYS_H
+#define MTK_APUSYS_H
+
+#include <stdint.h>
+
+/* setup the SMC command ops */
+#define MTK_SIP_APU_START_MCU (0x00U)
+#define MTK_SIP_APU_STOP_MCU (0x01U)
+#define MTK_SIP_APUPWR_BUS_PROT_CG_ON (0x02U)
+#define MTK_SIP_APUPWR_BULK_PLL (0x03U)
+#define MTK_SIP_APUPWR_ACC_INIT_ALL (0x04U)
+#define MTK_SIP_APUPWR_ACC_TOP (0x05U)
+
+/* AO Register */
+#define AO_MD32_PRE_DEFINE (APUSYS_APU_S_S_4_BASE + 0x00)
+#define AO_MD32_BOOT_CTRL (APUSYS_APU_S_S_4_BASE + 0x04)
+#define AO_MD32_SYS_CTRL (APUSYS_APU_S_S_4_BASE + 0x08)
+#define AO_SEC_FW (APUSYS_APU_S_S_4_BASE + 0x10)
+#define AO_SEC_USR_FW (APUSYS_APU_S_S_4_BASE + 0x14)
+
+#define PRE_DEFINE_CACHE_TCM (0x3U)
+#define PRE_DEFINE_CACHE (0x2U)
+#define PRE_DEFINE_SHIFT_0G (0U)
+#define PRE_DEFINE_SHIFT_1G (2U)
+#define PRE_DEFINE_SHIFT_2G (4U)
+#define PRE_DEFINE_SHIFT_3G (6U)
+
+#define SEC_FW_NON_SECURE (1U)
+#define SEC_FW_SHIFT_NS (4U)
+#define SEC_FW_DOMAIN_SHIFT (0U)
+
+#define SEC_USR_FW_NON_SECURE (1U)
+#define SEC_USR_FW_SHIFT_NS (4U)
+#define SEC_USR_FW_DOMAIN_SHIFT (0U)
+
+#define SYS_CTRL_RUN (0U)
+#define SYS_CTRL_STALL (1U)
+
+/* Reviser Register */
+#define REVISER_SECUREFW_CTXT (APUSYS_SCTRL_REVISER_BASE + 0x100)
+#define REVISER_USDRFW_CTXT (APUSYS_SCTRL_REVISER_BASE + 0x104)
+
+int32_t apusys_kernel_ctrl(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4,
+ uint32_t *ret1);
+#endif /* MTK_APUSYS_H */
diff --git a/plat/mediatek/mt8195/drivers/dcm/mtk_dcm.c b/plat/mediatek/mt8195/drivers/dcm/mtk_dcm.c
new file mode 100644
index 0000000..aed0833
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/dcm/mtk_dcm.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mtk_dcm.h>
+#include <mtk_dcm_utils.h>
+
+static void dcm_armcore(bool mode)
+{
+ dcm_mp_cpusys_top_bus_pll_div_dcm(mode);
+ dcm_mp_cpusys_top_cpu_pll_div_0_dcm(mode);
+ dcm_mp_cpusys_top_cpu_pll_div_1_dcm(mode);
+}
+
+static void dcm_mcusys(bool on)
+{
+ dcm_mp_cpusys_top_adb_dcm(on);
+ dcm_mp_cpusys_top_apb_dcm(on);
+ dcm_mp_cpusys_top_cpubiu_dcm(on);
+ dcm_mp_cpusys_top_misc_dcm(on);
+ dcm_mp_cpusys_top_mp0_qdcm(on);
+ dcm_cpccfg_reg_emi_wfifo(on);
+ dcm_mp_cpusys_top_last_cor_idle_dcm(on);
+}
+
+static void dcm_stall(bool on)
+{
+ dcm_mp_cpusys_top_core_stall_dcm(on);
+ dcm_mp_cpusys_top_fcm_stall_dcm(on);
+}
+
+static bool check_dcm_state(void)
+{
+ bool ret = true;
+
+ ret &= dcm_mp_cpusys_top_bus_pll_div_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on();
+
+ ret &= dcm_mp_cpusys_top_adb_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_apb_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_cpubiu_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_misc_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_mp0_qdcm_is_on();
+ ret &= dcm_cpccfg_reg_emi_wfifo_is_on();
+ ret &= dcm_mp_cpusys_top_last_cor_idle_dcm_is_on();
+
+ ret &= dcm_mp_cpusys_top_core_stall_dcm_is_on();
+ ret &= dcm_mp_cpusys_top_fcm_stall_dcm_is_on();
+
+ return ret;
+}
+
+bool dcm_set_default(void)
+{
+ dcm_armcore(true);
+ dcm_mcusys(true);
+ dcm_stall(true);
+
+ return check_dcm_state();
+}
diff --git a/plat/mediatek/mt8195/drivers/dcm/mtk_dcm.h b/plat/mediatek/mt8195/drivers/dcm/mtk_dcm.h
new file mode 100644
index 0000000..cb65b85
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/dcm/mtk_dcm.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_DCM_H
+#define MTK_DCM_H
+
+#include <stdbool.h>
+
+bool dcm_set_default(void);
+
+#endif /* #ifndef MTK_DCM_H */
diff --git a/plat/mediatek/mt8195/drivers/dcm/mtk_dcm_utils.c b/plat/mediatek/mt8195/drivers/dcm/mtk_dcm_utils.c
new file mode 100644
index 0000000..a1a3720
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/dcm/mtk_dcm_utils.c
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <mtk_dcm_utils.h>
+
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_MASK (BIT(17))
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_MASK (BIT(15) | \
+ BIT(16) | \
+ BIT(17) | \
+ BIT(18) | \
+ BIT(21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG2_MASK (BIT(15) | \
+ BIT(16) | \
+ BIT(17) | \
+ BIT(18))
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_ON (BIT(17))
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_ON (BIT(15) | \
+ BIT(16) | \
+ BIT(17) | \
+ BIT(18) | \
+ BIT(21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG2_ON (BIT(15) | \
+ BIT(16) | \
+ BIT(17) | \
+ BIT(18))
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_OFF ((0x0 << 17))
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_OFF ((0x0 << 15) | \
+ (0x0 << 16) | \
+ (0x0 << 17) | \
+ (0x0 << 18) | \
+ (0x0 << 21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG2_OFF ((0x0 << 15) | \
+ (0x0 << 16) | \
+ (0x0 << 17) | \
+ (0x0 << 18))
+
+bool dcm_mp_cpusys_top_adb_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG0) &
+ MP_CPUSYS_TOP_ADB_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_ADB_DCM_REG0_ON);
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG4) &
+ MP_CPUSYS_TOP_ADB_DCM_REG1_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_ADB_DCM_REG1_ON);
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0) &
+ MP_CPUSYS_TOP_ADB_DCM_REG2_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_ADB_DCM_REG2_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_adb_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_adb_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG0,
+ MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG0_ON);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG4,
+ MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG1_ON);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+ MP_CPUSYS_TOP_ADB_DCM_REG2_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG2_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_adb_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG0,
+ MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG0_OFF);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG4,
+ MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG1_OFF);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+ MP_CPUSYS_TOP_ADB_DCM_REG2_MASK,
+ MP_CPUSYS_TOP_ADB_DCM_REG2_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_APB_DCM_REG0_MASK (BIT(5))
+#define MP_CPUSYS_TOP_APB_DCM_REG1_MASK (BIT(8))
+#define MP_CPUSYS_TOP_APB_DCM_REG2_MASK (BIT(16))
+#define MP_CPUSYS_TOP_APB_DCM_REG0_ON (BIT(5))
+#define MP_CPUSYS_TOP_APB_DCM_REG1_ON (BIT(8))
+#define MP_CPUSYS_TOP_APB_DCM_REG2_ON (BIT(16))
+#define MP_CPUSYS_TOP_APB_DCM_REG0_OFF ((0x0 << 5))
+#define MP_CPUSYS_TOP_APB_DCM_REG1_OFF ((0x0 << 8))
+#define MP_CPUSYS_TOP_APB_DCM_REG2_OFF ((0x0 << 16))
+
+bool dcm_mp_cpusys_top_apb_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0) &
+ MP_CPUSYS_TOP_APB_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_APB_DCM_REG0_ON);
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0) &
+ MP_CPUSYS_TOP_APB_DCM_REG1_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_APB_DCM_REG1_ON);
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP0_DCM_CFG0) &
+ MP_CPUSYS_TOP_APB_DCM_REG2_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_APB_DCM_REG2_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_apb_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_apb_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG0_ON);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG1_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG1_ON);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG2_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG2_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_apb_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG0_OFF);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG1_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG1_OFF);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+ MP_CPUSYS_TOP_APB_DCM_REG2_MASK,
+ MP_CPUSYS_TOP_APB_DCM_REG2_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK (BIT(11) | \
+ BIT(24) | \
+ BIT(25))
+#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON (BIT(11) | \
+ BIT(24) | \
+ BIT(25))
+#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_OFF ((0x0 << 11) | \
+ (0x0 << 24) | \
+ (0x0 << 25))
+
+bool dcm_mp_cpusys_top_bus_pll_div_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG) &
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_bus_pll_div_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_bus_pll_div_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_bus_pll_div_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK (BIT(0))
+#define MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON (BIT(0))
+#define MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_OFF ((0x0 << 0))
+
+bool dcm_mp_cpusys_top_core_stall_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP0_DCM_CFG7) &
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_core_stall_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_core_stall_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_core_stall_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK ((0xffff << 0))
+#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON ((0xffff << 0))
+#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_OFF ((0x0 << 0))
+
+bool dcm_mp_cpusys_top_cpubiu_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MCSIC_DCM0) &
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_cpubiu_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpubiu_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCSIC_DCM0,
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpubiu_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MCSIC_DCM0,
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPUBIU_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK (BIT(24) | \
+ BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON (BIT(24) | \
+ BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_OFF ((0x0 << 24) | \
+ (0x0 << 25))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG0) &
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_cpu_pll_div_0_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_0_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG0,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_0_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG0,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK (BIT(24) | \
+ BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON (BIT(24) | \
+ BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_OFF ((0x0 << 24) | \
+ (0x0 << 25))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG1) &
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_cpu_pll_div_1_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_1_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG1,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_1_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG1,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK (BIT(4))
+#define MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON (BIT(4))
+#define MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_OFF ((0x0 << 4))
+
+bool dcm_mp_cpusys_top_fcm_stall_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP0_DCM_CFG7) &
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_fcm_stall_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_fcm_stall_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_fcm_stall_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK ((0x1U << 31))
+#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON ((0x1U << 31))
+#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_OFF ((0x0U << 31))
+
+bool dcm_mp_cpusys_top_last_cor_idle_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG) &
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_last_cor_idle_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_last_cor_idle_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_last_cor_idle_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_MASK (BIT(1) | \
+ BIT(4))
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_ON (BIT(1) | \
+ BIT(4))
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_OFF ((0x0 << 1) | \
+ (0x0 << 4))
+
+bool dcm_mp_cpusys_top_misc_dcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0) &
+ MP_CPUSYS_TOP_MISC_DCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_MISC_DCM_REG0_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_misc_dcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_misc_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_MISC_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_MISC_DCM_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_misc_dcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_MISC_DCM_REG0_MASK,
+ MP_CPUSYS_TOP_MISC_DCM_REG0_OFF);
+ }
+}
+
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK (BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK (BIT(0) | \
+ BIT(1) | \
+ BIT(2) | \
+ BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_ON (BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG1_ON (BIT(0) | \
+ BIT(1) | \
+ BIT(2) | \
+ BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_OFF ((0x0 << 3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG1_OFF ((0x0 << 0) | \
+ (0x0 << 1) | \
+ (0x0 << 2) | \
+ (0x0 << 3))
+
+bool dcm_mp_cpusys_top_mp0_qdcm_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0) &
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_MP0_QDCM_REG0_ON);
+ ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP0_DCM_CFG0) &
+ MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK) ==
+ (unsigned int) MP_CPUSYS_TOP_MP0_QDCM_REG1_ON);
+
+ return ret;
+}
+
+void dcm_mp_cpusys_top_mp0_qdcm(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'mp_cpusys_top_mp0_qdcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_ON);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+ MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK,
+ MP_CPUSYS_TOP_MP0_QDCM_REG1_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'mp_cpusys_top_mp0_qdcm'" */
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
+ MP_CPUSYS_TOP_MP0_QDCM_REG0_OFF);
+ mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+ MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK,
+ MP_CPUSYS_TOP_MP0_QDCM_REG1_OFF);
+ }
+}
+
+#define CPCCFG_REG_EMI_WFIFO_REG0_MASK (BIT(0) | \
+ BIT(1) | \
+ BIT(2) | \
+ BIT(3))
+#define CPCCFG_REG_EMI_WFIFO_REG0_ON (BIT(0) | \
+ BIT(1) | \
+ BIT(2) | \
+ BIT(3))
+#define CPCCFG_REG_EMI_WFIFO_REG0_OFF ((0x0 << 0) | \
+ (0x0 << 1) | \
+ (0x0 << 2) | \
+ (0x0 << 3))
+
+bool dcm_cpccfg_reg_emi_wfifo_is_on(void)
+{
+ bool ret = true;
+
+ ret &= ((mmio_read_32(CPCCFG_REG_EMI_WFIFO) &
+ CPCCFG_REG_EMI_WFIFO_REG0_MASK) ==
+ (unsigned int) CPCCFG_REG_EMI_WFIFO_REG0_ON);
+
+ return ret;
+}
+
+void dcm_cpccfg_reg_emi_wfifo(bool on)
+{
+ if (on) {
+ /* TINFO = "Turn ON DCM 'cpccfg_reg_emi_wfifo'" */
+ mmio_clrsetbits_32(CPCCFG_REG_EMI_WFIFO,
+ CPCCFG_REG_EMI_WFIFO_REG0_MASK,
+ CPCCFG_REG_EMI_WFIFO_REG0_ON);
+ } else {
+ /* TINFO = "Turn OFF DCM 'cpccfg_reg_emi_wfifo'" */
+ mmio_clrsetbits_32(CPCCFG_REG_EMI_WFIFO,
+ CPCCFG_REG_EMI_WFIFO_REG0_MASK,
+ CPCCFG_REG_EMI_WFIFO_REG0_OFF);
+ }
+}
diff --git a/plat/mediatek/mt8195/drivers/dcm/mtk_dcm_utils.h b/plat/mediatek/mt8195/drivers/dcm/mtk_dcm_utils.h
new file mode 100644
index 0000000..e5743af
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/dcm/mtk_dcm_utils.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_DCM_UTILS_H
+#define MTK_DCM_UTILS_H
+
+#include <stdbool.h>
+
+#include <mtk_dcm.h>
+#include <platform_def.h>
+
+/* Base */
+#define MP_CPUSYS_TOP_BASE (MCUCFG_BASE + 0x8000)
+#define CPCCFG_REG_BASE (MCUCFG_BASE + 0xA800)
+
+/* Register Definition */
+#define MP_CPUSYS_TOP_CPU_PLLDIV_CFG0 (MP_CPUSYS_TOP_BASE + 0x22a0)
+#define MP_CPUSYS_TOP_CPU_PLLDIV_CFG1 (MP_CPUSYS_TOP_BASE + 0x22a4)
+#define MP_CPUSYS_TOP_BUS_PLLDIV_CFG (MP_CPUSYS_TOP_BASE + 0x22e0)
+#define MP_CPUSYS_TOP_MCSIC_DCM0 (MP_CPUSYS_TOP_BASE + 0x2440)
+#define MP_CPUSYS_TOP_MP_ADB_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x2500)
+#define MP_CPUSYS_TOP_MP_ADB_DCM_CFG4 (MP_CPUSYS_TOP_BASE + 0x2510)
+#define MP_CPUSYS_TOP_MP_MISC_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x2518)
+#define MP_CPUSYS_TOP_MCUSYS_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x25c0)
+#define CPCCFG_REG_EMI_WFIFO (CPCCFG_REG_BASE + 0x100)
+#define MP_CPUSYS_TOP_MP0_DCM_CFG0 (MP_CPUSYS_TOP_BASE + 0x4880)
+#define MP_CPUSYS_TOP_MP0_DCM_CFG7 (MP_CPUSYS_TOP_BASE + 0x489c)
+
+/* MP_CPUSYS_TOP */
+bool dcm_mp_cpusys_top_adb_dcm_is_on(void);
+void dcm_mp_cpusys_top_adb_dcm(bool on);
+bool dcm_mp_cpusys_top_apb_dcm_is_on(void);
+void dcm_mp_cpusys_top_apb_dcm(bool on);
+bool dcm_mp_cpusys_top_bus_pll_div_dcm_is_on(void);
+void dcm_mp_cpusys_top_bus_pll_div_dcm(bool on);
+bool dcm_mp_cpusys_top_core_stall_dcm_is_on(void);
+void dcm_mp_cpusys_top_core_stall_dcm(bool on);
+bool dcm_mp_cpusys_top_cpubiu_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpubiu_dcm(bool on);
+bool dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpu_pll_div_0_dcm(bool on);
+bool dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpu_pll_div_1_dcm(bool on);
+bool dcm_mp_cpusys_top_fcm_stall_dcm_is_on(void);
+void dcm_mp_cpusys_top_fcm_stall_dcm(bool on);
+bool dcm_mp_cpusys_top_last_cor_idle_dcm_is_on(void);
+void dcm_mp_cpusys_top_last_cor_idle_dcm(bool on);
+bool dcm_mp_cpusys_top_misc_dcm_is_on(void);
+void dcm_mp_cpusys_top_misc_dcm(bool on);
+bool dcm_mp_cpusys_top_mp0_qdcm_is_on(void);
+void dcm_mp_cpusys_top_mp0_qdcm(bool on);
+/* CPCCFG_REG */
+bool dcm_cpccfg_reg_emi_wfifo_is_on(void);
+void dcm_cpccfg_reg_emi_wfifo(bool on);
+
+#endif
diff --git a/plat/mediatek/mt8195/drivers/dfd/plat_dfd.c b/plat/mediatek/mt8195/drivers/dfd/plat_dfd.c
new file mode 100644
index 0000000..c083318
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/dfd/plat_dfd.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mtk_sip_svc.h>
+#include <plat_dfd.h>
+
+static bool dfd_enabled;
+static uint64_t dfd_base_addr;
+static uint64_t dfd_chain_length;
+static uint64_t dfd_cache_dump;
+
+static void dfd_setup(uint64_t base_addr, uint64_t chain_length,
+ uint64_t cache_dump)
+{
+ mmio_write_32(MTK_WDT_LATCH_CTL2, MTK_WDT_LATCH_CTL2_VAL);
+ mmio_write_32(MTK_WDT_INTERVAL, MTK_WDT_INTERVAL_VAL);
+ mmio_write_32(MTK_DRM_LATCH_CTL2, MTK_DRM_LATCH_CTL2_VAL);
+ mmio_write_32(MTK_DRM_LATCH_CTL1, MTK_DRM_LATCH_CTL1_VAL);
+
+ /* Bit[2] = 0 (default=1), disable dfd apb bus protect_en */
+ mmio_clrbits_32(DFD_O_INTRF_MCU_PWR_CTL_MASK, 0x1 << 2);
+
+ /* Bit[0] : enable?mcusys_vproc?external_off?dfd?trigger -> 1 */
+ mmio_setbits_32(DFD_V50_GROUP_0_63_DIFF, 0x1);
+
+ /* bit[0]: rg_rw_dfd_internal_dump_en -> 1 */
+ /* bit[2]: rg_rw_dfd_clock_stop_en -> 1 */
+ sync_writel(DFD_INTERNAL_CTL, 0x5);
+
+ /* bit[13]: xreset_b_update_disable */
+ mmio_setbits_32(DFD_INTERNAL_CTL, 0x1 << 13);
+
+ /*
+ * bit[10:3]: DFD trigger selection mask
+ * bit[3]: rg_rw_dfd_trigger_sel[0] = 1(enable wdt trigger)
+ * bit[4]: rg_rw_dfd_trigger_sel[1] = 1(enable HW trigger)
+ * bit[5]: rg_rw_dfd_trigger_sel[2] = 1(enable SW trigger)
+ * bit[6]: rg_rw_dfd_trigger_sel[3] = 1(enable SW non-security trigger)
+ * bit[7]: rg_rw_dfd_trigger_sel[4] = 1(enable timer trigger)
+ */
+ mmio_setbits_32(DFD_INTERNAL_CTL, 0x1F << 3);
+
+ /*
+ * bit[9] : rg_rw_dfd_trigger_sel[6] = 1(cpu_eb_sw_dfd_trigger)
+ * bit[10] : rg_rw_dfd_trigger_sel[7] = 1(cpu_eb_wdt_dfd_trigger)
+ */
+ mmio_setbits_32(DFD_INTERNAL_CTL, 0x3 << 9);
+
+ /* bit[20:19]: rg_dfd_armpll_div_mux_sel switch to PLL2 for DFD */
+ mmio_setbits_32(DFD_INTERNAL_CTL, 0x3 << 19);
+
+ /*
+ * bit[0]: rg_rw_dfd_auto_power_on = 1
+ * bit[2:1]: rg_rw_dfd_auto_power_on_dely = 1(10us)
+ * bit[4:2]: rg_rw_dfd_power_on_wait_time = 1(20us)
+ */
+ mmio_write_32(DFD_INTERNAL_PWR_ON, 0xB);
+
+ /* longest scan chain length */
+ mmio_write_32(DFD_CHAIN_LENGTH0, chain_length);
+
+ /* bit[1:0]: rg_rw_dfd_shift_clock_ratio */
+ mmio_write_32(DFD_INTERNAL_SHIFT_CLK_RATIO, 0x0);
+
+ /* rg_dfd_test_so_over_64 */
+ mmio_write_32(DFD_INTERNAL_TEST_SO_OVER_64, 0x1);
+
+ /* DFD3.0 */
+ mmio_write_32(DFD_TEST_SI_0, 0x0);
+ mmio_write_32(DFD_TEST_SI_1, 0x0);
+ mmio_write_32(DFD_TEST_SI_2, 0x0);
+ mmio_write_32(DFD_TEST_SI_3, 0x0);
+
+ /* for iLDO feature */
+ sync_writel(DFD_POWER_CTL, 0xF9);
+
+ /* read offset */
+ sync_writel(DFD_READ_ADDR, DFD_READ_ADDR_VAL);
+
+ /* for DFD-3.0 setup */
+ sync_writel(DFD_V30_CTL, 0xD);
+
+ /* set base address */
+ mmio_write_32(DFD_O_SET_BASEADDR_REG, base_addr >> 24);
+ mmio_write_32(DFD_O_REG_0, 0);
+
+ /* setup global variables for suspend and resume */
+ dfd_enabled = true;
+ dfd_base_addr = base_addr;
+ dfd_chain_length = chain_length;
+ dfd_cache_dump = cache_dump;
+
+ if ((cache_dump & DFD_CACHE_DUMP_ENABLE) != 0UL) {
+ mmio_write_32(MTK_DRM_LATCH_CTL2, MTK_DRM_LATCH_CTL2_CACHE_VAL);
+ sync_writel(DFD_V35_ENABLE, 0x1);
+ sync_writel(DFD_V35_TAP_NUMBER, 0xB);
+ sync_writel(DFD_V35_TAP_EN, DFD_V35_TAP_EN_VAL);
+ sync_writel(DFD_V35_SEQ0_0, DFD_V35_SEQ0_0_VAL);
+
+ /* Cache dump only mode */
+ sync_writel(DFD_V35_CTL, 0x1);
+ mmio_write_32(DFD_INTERNAL_NUM_OF_TEST_SO_GROUP, 0xF);
+ mmio_write_32(DFD_CHAIN_LENGTH0, DFD_CHAIN_LENGTH_VAL);
+ mmio_write_32(DFD_CHAIN_LENGTH1, DFD_CHAIN_LENGTH_VAL);
+ mmio_write_32(DFD_CHAIN_LENGTH2, DFD_CHAIN_LENGTH_VAL);
+ mmio_write_32(DFD_CHAIN_LENGTH3, DFD_CHAIN_LENGTH_VAL);
+
+ if ((cache_dump & DFD_PARITY_ERR_TRIGGER) != 0UL) {
+ sync_writel(DFD_HW_TRIGGER_MASK, 0xC);
+ mmio_setbits_32(DFD_INTERNAL_CTL, 0x1 << 4);
+ }
+ }
+ dsbsy();
+}
+
+void dfd_resume(void)
+{
+ if (dfd_enabled == true) {
+ dfd_setup(dfd_base_addr, dfd_chain_length, dfd_cache_dump);
+ }
+}
+
+uint64_t dfd_smc_dispatcher(uint64_t arg0, uint64_t arg1,
+ uint64_t arg2, uint64_t arg3)
+{
+ uint64_t ret = 0L;
+
+ switch (arg0) {
+ case PLAT_MTK_DFD_SETUP_MAGIC:
+ INFO("[%s] DFD setup call from kernel\n", __func__);
+ dfd_setup(arg1, arg2, arg3);
+ break;
+ case PLAT_MTK_DFD_READ_MAGIC:
+ /* only allow to access DFD register base + 0x200 */
+ if (arg1 <= 0x200) {
+ ret = mmio_read_32(MISC1_CFG_BASE + arg1);
+ }
+ break;
+ case PLAT_MTK_DFD_WRITE_MAGIC:
+ /* only allow to access DFD register base + 0x200 */
+ if (arg1 <= 0x200) {
+ sync_writel(MISC1_CFG_BASE + arg1, arg2);
+ }
+ break;
+ default:
+ ret = MTK_SIP_E_INVALID_PARAM;
+ break;
+ }
+
+ return ret;
+}
diff --git a/plat/mediatek/mt8195/drivers/dfd/plat_dfd.h b/plat/mediatek/mt8195/drivers/dfd/plat_dfd.h
new file mode 100644
index 0000000..2a7e979
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/dfd/plat_dfd.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_DFD_H
+#define PLAT_DFD_H
+
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#define sync_writel(addr, val) do { mmio_write_32((addr), (val)); \
+ dsbsy(); \
+ } while (0)
+
+#define PLAT_MTK_DFD_SETUP_MAGIC (0x99716150)
+#define PLAT_MTK_DFD_READ_MAGIC (0x99716151)
+#define PLAT_MTK_DFD_WRITE_MAGIC (0x99716152)
+
+#define MTK_DRM_LATCH_CTL1 (DRM_BASE + 0x40)
+#define MTK_DRM_LATCH_CTL2 (DRM_BASE + 0x44)
+
+#define MTK_WDT_BASE (RGU_BASE)
+#define MTK_WDT_INTERVAL (MTK_WDT_BASE + 0x10)
+#define MTK_WDT_LATCH_CTL2 (MTK_WDT_BASE + 0x48)
+
+#define MCU_BIU_BASE (MCUCFG_BASE)
+#define MISC1_CFG_BASE (MCU_BIU_BASE + 0xE040)
+#define DFD_INTERNAL_CTL (MISC1_CFG_BASE + 0x00)
+#define DFD_INTERNAL_PWR_ON (MISC1_CFG_BASE + 0x08)
+#define DFD_CHAIN_LENGTH0 (MISC1_CFG_BASE + 0x0C)
+#define DFD_INTERNAL_SHIFT_CLK_RATIO (MISC1_CFG_BASE + 0x10)
+#define DFD_CHAIN_LENGTH1 (MISC1_CFG_BASE + 0x1C)
+#define DFD_CHAIN_LENGTH2 (MISC1_CFG_BASE + 0x20)
+#define DFD_CHAIN_LENGTH3 (MISC1_CFG_BASE + 0x24)
+#define DFD_INTERNAL_TEST_SO_0 (MISC1_CFG_BASE + 0x28)
+#define DFD_INTERNAL_NUM_OF_TEST_SO_GROUP (MISC1_CFG_BASE + 0x30)
+#define DFD_INTERNAL_TEST_SO_OVER_64 (MISC1_CFG_BASE + 0x34)
+#define DFD_INTERNAL_SW_NS_TRIGGER (MISC1_CFG_BASE + 0x3c)
+#define DFD_V30_CTL (MISC1_CFG_BASE + 0x48)
+#define DFD_V30_BASE_ADDR (MISC1_CFG_BASE + 0x4C)
+#define DFD_POWER_CTL (MISC1_CFG_BASE + 0x50)
+#define DFD_TEST_SI_0 (MISC1_CFG_BASE + 0x58)
+#define DFD_TEST_SI_1 (MISC1_CFG_BASE + 0x5C)
+#define DFD_CLEAN_STATUS (MISC1_CFG_BASE + 0x60)
+#define DFD_TEST_SI_2 (MISC1_CFG_BASE + 0x1D8)
+#define DFD_TEST_SI_3 (MISC1_CFG_BASE + 0x1DC)
+#define DFD_READ_ADDR (MISC1_CFG_BASE + 0x1E8)
+#define DFD_HW_TRIGGER_MASK (MISC1_CFG_BASE + 0xBC)
+
+#define DFD_V35_ENABLE (MCU_BIU_BASE + 0xE0A8)
+#define DFD_V35_TAP_NUMBER (MCU_BIU_BASE + 0xE0AC)
+#define DFD_V35_TAP_EN (MCU_BIU_BASE + 0xE0B0)
+#define DFD_V35_CTL (MCU_BIU_BASE + 0xE0B4)
+#define DFD_V35_SEQ0_0 (MCU_BIU_BASE + 0xE0C0)
+#define DFD_V35_SEQ0_1 (MCU_BIU_BASE + 0xE0C4)
+#define DFD_V50_GROUP_0_63_DIFF (MCU_BIU_BASE + 0xE2AC)
+
+#define DFD_O_PROTECT_EN_REG (0x10001220)
+#define DFD_O_INTRF_MCU_PWR_CTL_MASK (0x10001A3C)
+#define DFD_O_SET_BASEADDR_REG (0x10043000)
+#define DFD_O_REG_0 (0x10001390)
+
+#define DFD_CACHE_DUMP_ENABLE 1U
+#define DFD_PARITY_ERR_TRIGGER 2U
+
+#define DFD_V35_TAP_EN_VAL (0x43FF)
+#define DFD_V35_SEQ0_0_VAL (0x63668820)
+#define DFD_READ_ADDR_VAL (0x40000008)
+#define DFD_CHAIN_LENGTH_VAL (0xFFFFFFFF)
+
+#define MTK_WDT_LATCH_CTL2_VAL (0x9507FFFF)
+#define MTK_WDT_INTERVAL_VAL (0x6600000A)
+#define MTK_DRM_LATCH_CTL2_VAL (0x950600C8)
+#define MTK_DRM_LATCH_CTL2_CACHE_VAL (0x95065DC0)
+
+#define MTK_DRM_LATCH_CTL1_VAL (0x95000013)
+
+void dfd_resume(void);
+uint64_t dfd_smc_dispatcher(uint64_t arg0, uint64_t arg1,
+ uint64_t arg2, uint64_t arg3);
+
+#endif /* PLAT_DFD_H */
diff --git a/plat/mediatek/mt8195/drivers/emi_mpu/emi_mpu.c b/plat/mediatek/mt8195/drivers/emi_mpu/emi_mpu.c
new file mode 100644
index 0000000..794e21e
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/emi_mpu/emi_mpu.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <emi_mpu.h>
+
+#if ENABLE_EMI_MPU_SW_LOCK
+static unsigned char region_lock_state[EMI_MPU_REGION_NUM];
+#endif
+
+#define EMI_MPU_START_MASK (0x00FFFFFF)
+#define EMI_MPU_END_MASK (0x00FFFFFF)
+#define EMI_MPU_APC_SW_LOCK_MASK (0x00FFFFFF)
+#define EMI_MPU_APC_HW_LOCK_MASK (0x80FFFFFF)
+
+static int _emi_mpu_set_protection(unsigned int start, unsigned int end,
+ unsigned int apc)
+{
+ unsigned int dgroup;
+ unsigned int region;
+
+ region = (start >> 24) & 0xFF;
+ start &= EMI_MPU_START_MASK;
+ dgroup = (end >> 24) & 0xFF;
+ end &= EMI_MPU_END_MASK;
+
+ if ((region >= EMI_MPU_REGION_NUM) || (dgroup > EMI_MPU_DGROUP_NUM)) {
+ WARN("invalid region, domain\n");
+ return -1;
+ }
+
+#if ENABLE_EMI_MPU_SW_LOCK
+ if (region_lock_state[region] == 1) {
+ WARN("invalid region\n");
+ return -1;
+ }
+
+ if ((dgroup == 0) && ((apc >> 31) & 0x1)) {
+ region_lock_state[region] = 1;
+ }
+
+ apc &= EMI_MPU_APC_SW_LOCK_MASK;
+#else
+ apc &= EMI_MPU_APC_HW_LOCK_MASK;
+#endif
+
+ if ((start >= DRAM_OFFSET) && (end >= start)) {
+ start -= DRAM_OFFSET;
+ end -= DRAM_OFFSET;
+ } else {
+ WARN("invalid range\n");
+ return -1;
+ }
+
+ mmio_write_32(EMI_MPU_SA(region), start);
+ mmio_write_32(EMI_MPU_EA(region), end);
+ mmio_write_32(EMI_MPU_APC(region, dgroup), apc);
+
+#if defined(SUB_EMI_MPU_BASE)
+ mmio_write_32(SUB_EMI_MPU_SA(region), start);
+ mmio_write_32(SUB_EMI_MPU_EA(region), end);
+ mmio_write_32(SUB_EMI_MPU_APC(region, dgroup), apc);
+#endif
+ return 1;
+}
+
+int emi_mpu_set_protection(struct emi_region_info_t *region_info)
+{
+ unsigned int start, end;
+ int i;
+
+ if (region_info->region >= EMI_MPU_REGION_NUM) {
+ WARN("invalid region\n");
+ return -1;
+ }
+
+ start = (unsigned int)(region_info->start >> EMI_MPU_ALIGN_BITS) |
+ (region_info->region << 24);
+
+ for (i = EMI_MPU_DGROUP_NUM - 1; i >= 0; i--) {
+ end = (unsigned int)(region_info->end >> EMI_MPU_ALIGN_BITS) |
+ (i << 24);
+ _emi_mpu_set_protection(start, end, region_info->apc[i]);
+ }
+
+ return 0;
+}
+
+void dump_emi_mpu_regions(void)
+{
+ unsigned long apc[EMI_MPU_DGROUP_NUM], sa, ea;
+
+ int region, i;
+
+ /* Only dump 8 regions(max: EMI_MPU_REGION_NUM --> 32) */
+ for (region = 0; region < 8; ++region) {
+ for (i = 0; i < EMI_MPU_DGROUP_NUM; ++i)
+ apc[i] = mmio_read_32(EMI_MPU_APC(region, i));
+ sa = mmio_read_32(EMI_MPU_SA(region));
+ ea = mmio_read_32(EMI_MPU_EA(region));
+
+ INFO("region %d:\n", region);
+ INFO("\tsa:0x%lx, ea:0x%lx, apc0: 0x%lx apc1: 0x%lx\n",
+ sa, ea, apc[0], apc[1]);
+ }
+}
+
+void emi_mpu_init(void)
+{
+ struct emi_region_info_t region_info;
+
+ /* SCP DRAM */
+ region_info.start = 0x50000000ULL;
+ region_info.end = 0x51400000ULL;
+ region_info.region = 2;
+ SET_ACCESS_PERMISSION(region_info.apc, 1,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ NO_PROTECTION, FORBIDDEN, FORBIDDEN, NO_PROTECTION);
+ emi_mpu_set_protection(&region_info);
+
+ /* DSP protect address */
+ region_info.start = 0x60000000ULL; /* dram base addr */
+ region_info.end = 0x610FFFFFULL;
+ region_info.region = 3;
+ SET_ACCESS_PERMISSION(region_info.apc, 1,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION);
+ emi_mpu_set_protection(&region_info);
+
+ /* Forbidden All */
+ region_info.start = 0x40000000ULL; /* dram base addr */
+ region_info.end = 0x1FFFF0000ULL;
+ region_info.region = 4;
+ SET_ACCESS_PERMISSION(region_info.apc, 1,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+ FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION);
+ emi_mpu_set_protection(&region_info);
+
+ dump_emi_mpu_regions();
+}
diff --git a/plat/mediatek/mt8195/drivers/emi_mpu/emi_mpu.h b/plat/mediatek/mt8195/drivers/emi_mpu/emi_mpu.h
new file mode 100644
index 0000000..415146e
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/emi_mpu/emi_mpu.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EMI_MPU_H
+#define EMI_MPU_H
+
+#include <platform_def.h>
+
+#define ENABLE_EMI_MPU_SW_LOCK 1
+
+#define EMI_MPU_CTRL (EMI_MPU_BASE + 0x000)
+#define EMI_MPU_DBG (EMI_MPU_BASE + 0x004)
+#define EMI_MPU_SA0 (EMI_MPU_BASE + 0x100)
+#define EMI_MPU_EA0 (EMI_MPU_BASE + 0x200)
+#define EMI_MPU_SA(region) (EMI_MPU_SA0 + (region * 4))
+#define EMI_MPU_EA(region) (EMI_MPU_EA0 + (region * 4))
+#define EMI_MPU_APC0 (EMI_MPU_BASE + 0x300)
+#define EMI_MPU_APC(region, dgroup) (EMI_MPU_APC0 + (region * 4) + (dgroup * 0x100))
+#define EMI_MPU_CTRL_D0 (EMI_MPU_BASE + 0x800)
+#define EMI_MPU_CTRL_D(domain) (EMI_MPU_CTRL_D0 + (domain * 4))
+#define EMI_RG_MASK_D0 (EMI_MPU_BASE + 0x900)
+#define EMI_RG_MASK_D(domain) (EMI_RG_MASK_D0 + (domain * 4))
+#define EMI_MPU_START (0x000)
+#define EMI_MPU_END (0x93C)
+
+#define SUB_EMI_MPU_CTRL (SUB_EMI_MPU_BASE + 0x000)
+#define SUB_EMI_MPU_DBG (SUB_EMI_MPU_BASE + 0x004)
+#define SUB_EMI_MPU_SA0 (SUB_EMI_MPU_BASE + 0x100)
+#define SUB_EMI_MPU_EA0 (SUB_EMI_MPU_BASE + 0x200)
+#define SUB_EMI_MPU_SA(region) (SUB_EMI_MPU_SA0 + (region * 4))
+#define SUB_EMI_MPU_EA(region) (SUB_EMI_MPU_EA0 + (region * 4))
+#define SUB_EMI_MPU_APC0 (SUB_EMI_MPU_BASE + 0x300)
+#define SUB_EMI_MPU_APC(region, dgroup) (SUB_EMI_MPU_APC0 + (region * 4) + (dgroup * 0x100))
+#define SUB_EMI_MPU_CTRL_D0 (SUB_EMI_MPU_BASE + 0x800)
+#define SUB_EMI_MPU_CTRL_D(domain) (SUB_EMI_MPU_CTRL_D0 + (domain * 4))
+#define SUB_EMI_RG_MASK_D0 (SUB_EMI_MPU_BASE + 0x900)
+#define SUB_EMI_RG_MASK_D(domain) (SUB_EMI_RG_MASK_D0 + (domain * 4))
+
+#define EMI_MPU_DOMAIN_NUM (16)
+#define EMI_MPU_REGION_NUM (32)
+#define EMI_MPU_ALIGN_BITS (16)
+#define DRAM_OFFSET (0x40000000 >> EMI_MPU_ALIGN_BITS)
+
+#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 LOCK 1
+#define UNLOCK 0
+
+#define EMI_MPU_DGROUP_NUM (EMI_MPU_DOMAIN_NUM / 8)
+
+#if (EMI_MPU_DGROUP_NUM == 1)
+#define SET_ACCESS_PERMISSION(apc_ary, lock, d7, d6, d5, d4, d3, d2, d1, d0) \
+do { \
+ apc_ary[1] = 0; \
+ apc_ary[0] = \
+ (((unsigned int) d7) << 21) | (((unsigned int) d6) << 18) | \
+ (((unsigned int) d5) << 15) | (((unsigned int) d4) << 12) | \
+ (((unsigned int) d3) << 9) | (((unsigned int) d2) << 6) | \
+ (((unsigned int) d1) << 3) | ((unsigned int) d0) | \
+ ((unsigned int) lock << 31); \
+} while (0)
+#elif (EMI_MPU_DGROUP_NUM == 2)
+#define SET_ACCESS_PERMISSION(apc_ary, lock, d15, d14, d13, d12, d11, d10, \
+ d9, d8, d7, d6, d5, d4, d3, d2, d1, d0) \
+do { \
+ apc_ary[1] = \
+ (((unsigned int) d15) << 21) | (((unsigned int) d14) << 18) | \
+ (((unsigned int) d13) << 15) | (((unsigned int) d12) << 12) | \
+ (((unsigned int) d11) << 9) | (((unsigned int) d10) << 6) | \
+ (((unsigned int) d9) << 3) | ((unsigned int) d8); \
+ apc_ary[0] = \
+ (((unsigned int) d7) << 21) | (((unsigned int) d6) << 18) | \
+ (((unsigned int) d5) << 15) | (((unsigned int) d4) << 12) | \
+ (((unsigned int) d3) << 9) | (((unsigned int) d2) << 6) | \
+ (((unsigned int) d1) << 3) | ((unsigned int) d0) | \
+ ((unsigned int) lock << 31); \
+} while (0)
+#endif
+
+struct emi_region_info_t {
+ unsigned long long start;
+ unsigned long long end;
+ unsigned int region;
+ unsigned int apc[EMI_MPU_DGROUP_NUM];
+};
+
+void emi_mpu_init(void);
+
+#endif
diff --git a/plat/mediatek/mt8195/drivers/gpio/mtgpio.c b/plat/mediatek/mt8195/drivers/gpio/mtgpio.c
new file mode 100644
index 0000000..daab84c
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/gpio/mtgpio.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <mtgpio.h>
+#include <platform_def.h>
+
+uintptr_t mt_gpio_find_reg_addr(uint32_t pin)
+{
+ uintptr_t reg_addr = 0U;
+ struct mt_pin_info gpio_info;
+
+ assert(pin < MAX_GPIO_PIN);
+
+ gpio_info = mt_pin_infos[pin];
+
+ switch (gpio_info.base & 0x0f) {
+ case 0:
+ reg_addr = IOCFG_BM_BASE;
+ break;
+ case 1:
+ reg_addr = IOCFG_BL_BASE;
+ break;
+ case 2:
+ reg_addr = IOCFG_BR_BASE;
+ break;
+ case 3:
+ reg_addr = IOCFG_LM_BASE;
+ break;
+ case 4:
+ reg_addr = IOCFG_RB_BASE;
+ break;
+ case 5:
+ reg_addr = IOCFG_TL_BASE;
+ break;
+ default:
+ break;
+ }
+
+ return reg_addr;
+}
diff --git a/plat/mediatek/mt8195/drivers/gpio/mtgpio.h b/plat/mediatek/mt8195/drivers/gpio/mtgpio.h
new file mode 100644
index 0000000..88b4706
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/gpio/mtgpio.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_GPIO_H
+#define MT_GPIO_H
+
+#include <mtgpio_common.h>
+
+/* 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,
+ MT_GPIO_BASE_MAX
+} GPIO_PIN;
+
+static const struct mt_pin_info mt_pin_infos[] = {
+ PIN(0, 1, 0, 0x23, 0x60),
+ PIN(1, 1, 1, 0x23, 0x60),
+ PIN(2, 1, 2, 0x23, 0x60),
+ PIN(3, 1, 3, 0x23, 0x60),
+ PIN(4, 1, 4, 0x23, 0x60),
+ PIN(5, 1, 5, 0x23, 0x60),
+ PIN(6, 0, 6, 0x23, 0x70),
+ PIN(7, 0, 7, 0x23, 0x70),
+ PIN(8, 0, 13, 0x23, 0x70),
+ PIN(9, 0, 8, 0x23, 0x70),
+ PIN(10, 0, 14, 0x23, 0x70),
+ PIN(11, 0, 9, 0x23, 0x70),
+ PIN(12, 0, 15, 0x23, 0x70),
+ PIN(13, 0, 10, 0x23, 0x70),
+ PIN(14, 0, 16, 0x23, 0x70),
+ PIN(15, 0, 11, 0x23, 0x70),
+ PIN(16, 0, 17, 0x23, 0x70),
+ PIN(17, 0, 12, 0x23, 0x70),
+ PIN(18, 0, 5, 0x10, 0x60),
+ PIN(19, 0, 12, 0x10, 0x60),
+ PIN(20, 0, 11, 0x10, 0x60),
+ PIN(21, 0, 10, 0x10, 0x60),
+ PIN(22, 0, 0, 0x10, 0x60),
+ PIN(23, 0, 1, 0x10, 0x60),
+ PIN(24, 0, 2, 0x10, 0x60),
+ PIN(25, 0, 4, 0x10, 0x60),
+ PIN(26, 0, 3, 0x10, 0x60),
+ PIN(27, 0, 6, 0x10, 0x60),
+ PIN(28, 0, 7, 0x10, 0x60),
+ PIN(29, 0, 8, 0x10, 0x60),
+ PIN(30, 0, 9, 0x10, 0x60),
+ PIN(31, 0, 13, 0x21, 0xa0),
+ PIN(32, 0, 12, 0x21, 0xa0),
+ PIN(33, 0, 11, 0x21, 0xa0),
+ PIN(34, 0, 14, 0x21, 0xa0),
+ PIN(35, 0, 15, 0x21, 0xa0),
+ PIN(36, 0, 3, 0x21, 0xb0),
+ PIN(37, 0, 6, 0x21, 0xb0),
+ PIN(38, 0, 4, 0x21, 0xb0),
+ PIN(39, 0, 5, 0x21, 0xb0),
+ PIN(40, 0, 8, 0x21, 0xb0),
+ PIN(41, 0, 7, 0x21, 0xb0),
+ PIN(42, 0, 10, 0x21, 0xb0),
+ PIN(43, 0, 9, 0x21, 0xb0),
+ PIN(44, 0, 20, 0x21, 0xb0),
+ PIN(45, 0, 21, 0x21, 0xb0),
+ PIN(46, 0, 18, 0x21, 0xa0),
+ PIN(47, 0, 16, 0x21, 0xa0),
+ PIN(48, 0, 19, 0x21, 0xa0),
+ PIN(49, 0, 17, 0x21, 0xa0),
+ PIN(50, 0, 25, 0x21, 0xa0),
+ PIN(51, 0, 20, 0x21, 0xa0),
+ PIN(52, 0, 26, 0x21, 0xa0),
+ PIN(53, 0, 21, 0x21, 0xa0),
+ PIN(54, 0, 22, 0x21, 0xa0),
+ PIN(55, 0, 23, 0x21, 0xa0),
+ PIN(56, 0, 24, 0x21, 0xa0),
+ PIN(57, 0, 29, 0x21, 0xa0),
+ PIN(58, 0, 27, 0x21, 0xa0),
+ PIN(59, 0, 30, 0x21, 0xa0),
+ PIN(60, 0, 28, 0x21, 0xa0),
+ PIN(61, 0, 8, 0x21, 0xa0),
+ PIN(62, 0, 7, 0x21, 0xa0),
+ PIN(63, 0, 10, 0x21, 0xa0),
+ PIN(64, 0, 9, 0x21, 0xa0),
+ PIN(65, 0, 1, 0x21, 0xb0),
+ PIN(66, 0, 31, 0x21, 0xa0),
+ PIN(67, 0, 0, 0x21, 0xb0),
+ PIN(68, 0, 2, 0x21, 0xb0),
+ PIN(69, 0, 0, 0x21, 0xa0),
+ PIN(70, 0, 6, 0x21, 0xa0),
+ PIN(71, 0, 4, 0x21, 0xa0),
+ PIN(72, 0, 5, 0x21, 0xa0),
+ PIN(73, 0, 1, 0x21, 0xa0),
+ PIN(74, 0, 2, 0x21, 0xa0),
+ PIN(75, 0, 3, 0x21, 0xa0),
+ PIN(76, 0, 11, 0x21, 0xb0),
+ PIN(77, 1, 1, 0x22, 0x60),
+ PIN(78, 1, 2, 0x22, 0x60),
+ PIN(79, 1, 9, 0x22, 0x60),
+ PIN(80, 1, 10, 0x22, 0x60),
+ PIN(81, 1, 11, 0x22, 0x60),
+ PIN(82, 1, 12, 0x22, 0x60),
+ PIN(83, 1, 13, 0x22, 0x60),
+ PIN(84, 1, 14, 0x22, 0x60),
+ PIN(85, 1, 15, 0x22, 0x60),
+ PIN(86, 1, 16, 0x22, 0x60),
+ PIN(87, 1, 3, 0x22, 0x60),
+ PIN(88, 1, 4, 0x22, 0x60),
+ PIN(89, 1, 5, 0x22, 0x60),
+ PIN(90, 1, 6, 0x22, 0x60),
+ PIN(91, 1, 7, 0x22, 0x60),
+ PIN(92, 1, 8, 0x22, 0x60),
+ PIN(93, 1, 18, 0x22, 0x60),
+ PIN(94, 1, 19, 0x22, 0x60),
+ PIN(95, 1, 17, 0x22, 0x60),
+ PIN(96, 1, 0, 0x22, 0x60),
+ PIN(97, 0, 20, 0x22, 0x70),
+ PIN(98, 0, 28, 0x22, 0x70),
+ PIN(99, 0, 27, 0x22, 0x70),
+ PIN(100, 0, 30, 0x22, 0x70),
+ PIN(101, 0, 29, 0x22, 0x70),
+ PIN(102, 0, 0, 0x22, 0x70),
+ PIN(103, 0, 31, 0x22, 0x70),
+ PIN(104, 1, 25, 0x22, 0x60),
+ PIN(105, 1, 26, 0x22, 0x60),
+ PIN(106, 1, 23, 0x22, 0x60),
+ PIN(107, 1, 24, 0x22, 0x60),
+ PIN(108, 0, 22, 0x22, 0x70),
+ PIN(109, 0, 21, 0x22, 0x70),
+ PIN(110, 1, 1, 0x14, 0x20),
+ PIN(111, 1, 0, 0x14, 0x20),
+ PIN(112, 1, 2, 0x14, 0x20),
+ PIN(113, 1, 3, 0x14, 0x20),
+ PIN(114, 1, 4, 0x14, 0x20),
+ PIN(115, 1, 5, 0x14, 0x20),
+ PIN(116, 1, 9, 0x25, 0x50),
+ PIN(117, 1, 8, 0x25, 0x50),
+ PIN(118, 1, 7, 0x25, 0x50),
+ PIN(119, 1, 6, 0x25, 0x50),
+ PIN(120, 1, 11, 0x25, 0x50),
+ PIN(121, 1, 1, 0x25, 0x50),
+ PIN(122, 1, 0, 0x25, 0x50),
+ PIN(123, 1, 5, 0x25, 0x50),
+ PIN(124, 1, 4, 0x25, 0x50),
+ PIN(125, 1, 3, 0x25, 0x50),
+ PIN(126, 1, 2, 0x25, 0x50),
+ PIN(127, 1, 10, 0x25, 0x50),
+ PIN(128, 0, 3, 0x22, 0x70),
+ PIN(129, 0, 1, 0x22, 0x70),
+ PIN(130, 0, 4, 0x22, 0x70),
+ PIN(131, 0, 2, 0x22, 0x70),
+ PIN(132, 0, 13, 0x25, 0x60),
+ PIN(133, 0, 12, 0x25, 0x60),
+ PIN(134, 0, 15, 0x25, 0x60),
+ PIN(135, 0, 14, 0x25, 0x60),
+ PIN(136, 0, 13, 0x21, 0xb0),
+ PIN(137, 0, 12, 0x21, 0xb0),
+ PIN(138, 0, 15, 0x21, 0xb0),
+ PIN(139, 0, 14, 0x21, 0xb0),
+ PIN(140, 0, 17, 0x21, 0xb0),
+ PIN(141, 0, 16, 0x21, 0xb0),
+ PIN(142, 0, 19, 0x21, 0xb0),
+ PIN(143, 0, 18, 0x21, 0xb0),
+};
+#endif /* MT_GPIO_H */
diff --git a/plat/mediatek/mt8195/drivers/mcdi/mt_cpu_pm.c b/plat/mediatek/mt8195/drivers/mcdi/mt_cpu_pm.c
new file mode 100644
index 0000000..5a80d95
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/mcdi/mt_cpu_pm.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <lib/psci/psci.h>
+#include <lib/spinlock.h>
+
+#include <mt_cpu_pm_cpc.h>
+#include <mt_lp_irqremain.h>
+#include <mt_lp_rm.h>
+#include <mt_mcdi.h>
+#include <plat_mtk_lpm.h>
+#include <plat_pm.h>
+
+DEFINE_SYSREG_RW_FUNCS(dbgprcr_el1);
+
+static int plat_mt_lp_cpu_rc;
+
+static int pwr_state_prompt(unsigned int cpu, const psci_power_state_t *state)
+{
+ return 0;
+}
+
+static int pwr_state_reflect(unsigned int cpu, const psci_power_state_t *state)
+{
+ mtk_cpc_core_on_hint_clr(cpu);
+
+ if (IS_SYSTEM_SUSPEND_STATE(state)) {
+ mtk_cpc_time_sync();
+ }
+
+ return 0;
+}
+
+static int pwr_cpu_pwron(unsigned int cpu, const psci_power_state_t *state)
+{
+ return 0;
+}
+
+static int pwr_cpu_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
+{
+ /* clear DBGPRCR.CORENPDRQ to allow CPU power down */
+ write_dbgprcr_el1(0ULL);
+
+ return 0;
+}
+
+static int pwr_cluster_pwron(unsigned int cpu, const psci_power_state_t *state)
+{
+ return 0;
+}
+
+static int pwr_cluster_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
+{
+ return 0;
+}
+
+static int pwr_mcusys_pwron(unsigned int cpu, const psci_power_state_t *state)
+{
+ if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) {
+ return -1;
+ }
+
+ mtk_cpc_mcusys_off_reflect();
+
+ return 0;
+}
+
+static int pwr_mcusys_pwron_finished(unsigned int cpu,
+ const psci_power_state_t *state)
+{
+ int state_id = state->pwr_domain_state[MTK_AFFLVL_MCUSYS];
+
+ if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) {
+ return -1;
+ }
+
+ mt_lp_rm_reset_constraint(plat_mt_lp_cpu_rc, cpu, state_id);
+ mt_lp_irqremain_release();
+
+ return 0;
+}
+
+static int pwr_mcusys_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
+{
+ int state_id = state->pwr_domain_state[MTK_AFFLVL_MCUSYS];
+
+ if (!IS_MCUSYS_OFF_STATE(state)) {
+ goto mt_pwr_mcusysoff_break;
+ }
+
+ if (mcdi_try_init() != 0) {
+ goto mt_pwr_mcusysoff_break;
+ }
+
+ if (mtk_cpc_mcusys_off_prepare() != CPC_SUCCESS) {
+ goto mt_pwr_mcusysoff_break;
+ }
+
+ plat_mt_lp_cpu_rc =
+ mt_lp_rm_find_and_run_constraint(0, cpu, state_id, NULL);
+
+ if (plat_mt_lp_cpu_rc < 0) {
+ goto mt_pwr_mcusysoff_reflect;
+ }
+
+ mt_lp_irqremain_aquire();
+
+ return 0;
+
+mt_pwr_mcusysoff_reflect:
+ mtk_cpc_mcusys_off_reflect();
+
+mt_pwr_mcusysoff_break:
+
+ plat_mt_lp_cpu_rc = -1;
+
+ return -1;
+}
+
+static const struct mt_lpm_tz plat_pm = {
+ .pwr_prompt = pwr_state_prompt,
+ .pwr_reflect = pwr_state_reflect,
+ .pwr_cpu_on = pwr_cpu_pwron,
+ .pwr_cpu_dwn = pwr_cpu_pwrdwn,
+ .pwr_cluster_on = pwr_cluster_pwron,
+ .pwr_cluster_dwn = pwr_cluster_pwrdwn,
+ .pwr_mcusys_dwn = pwr_mcusys_pwrdwn,
+ .pwr_mcusys_on = pwr_mcusys_pwron,
+ .pwr_mcusys_on_finished = pwr_mcusys_pwron_finished
+};
+
+const struct mt_lpm_tz *mt_plat_cpu_pm_init(void)
+{
+ mtk_cpc_init();
+
+ if (mcdi_try_init() == 0) {
+ INFO("MCDI init done.\n");
+ }
+
+ mt_lp_irqremain_init();
+
+ return &plat_pm;
+}
diff --git a/plat/mediatek/mt8195/drivers/mcdi/mt_cpu_pm_cpc.c b/plat/mediatek/mt8195/drivers/mcdi/mt_cpu_pm_cpc.c
new file mode 100644
index 0000000..f8c51a1
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/mcdi/mt_cpu_pm_cpc.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <drivers/delay_timer.h>
+
+#include <mt_cpu_pm_cpc.h>
+#include <mt_timer.h>
+
+struct mtk_cpc_dev {
+ int auto_off;
+ unsigned int auto_thres_tick;
+};
+
+static struct mtk_cpc_dev cpc;
+
+static int mtk_cpc_last_core_prot(uint32_t prot_req,
+ uint32_t resp_reg, uint32_t resp_ofs)
+{
+ uint32_t sta, retry;
+
+ retry = 0U;
+
+ while (retry++ < RETRY_CNT_MAX) {
+
+ mmio_write_32(CPC_MCUSYS_LAST_CORE_REQ, prot_req);
+
+ udelay(1U);
+
+ sta = (mmio_read_32(resp_reg) >> resp_ofs) & CPC_PROT_RESP_MASK;
+
+ if (sta == PROT_SUCCESS) {
+ return CPC_SUCCESS;
+ } else if (sta == PROT_GIVEUP) {
+ return CPC_ERR_FAIL;
+ }
+ }
+
+ return CPC_ERR_TIMEOUT;
+}
+
+int mtk_cpu_pm_mcusys_prot_aquire(void)
+{
+ return mtk_cpc_last_core_prot(
+ MCUSYS_PROT_SET,
+ CPC_MCUSYS_LAST_CORE_RESP,
+ MCUSYS_RESP_OFS);
+}
+
+void mtk_cpu_pm_mcusys_prot_release(void)
+{
+ mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, MCUSYS_PROT_CLR);
+}
+
+int mtk_cpu_pm_cluster_prot_aquire(unsigned int cluster)
+{
+ return mtk_cpc_last_core_prot(
+ CPUSYS_PROT_SET,
+ CPC_MCUSYS_MP_LAST_CORE_RESP,
+ CPUSYS_RESP_OFS);
+}
+
+void mtk_cpu_pm_cluster_prot_release(unsigned int cluster)
+{
+ mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, CPUSYS_PROT_CLR);
+}
+
+static void mtk_cpc_cluster_cnt_backup(void)
+{
+ uint32_t backup_cnt;
+ uint32_t curr_cnt;
+ uint32_t cnt_mask = GENMASK(14, 0);
+ uint32_t clr_mask = GENMASK(1, 0);
+
+ /* Single Cluster */
+ backup_cnt = mmio_read_32(CPC_CLUSTER_CNT_BACKUP);
+ curr_cnt = mmio_read_32(CPC_MCUSYS_CLUSTER_COUNTER);
+
+ /* Get off count if dormant count is 0 */
+ if ((curr_cnt & cnt_mask) == 0U) {
+ curr_cnt = (curr_cnt >> 16) & cnt_mask;
+ } else {
+ curr_cnt = curr_cnt & cnt_mask;
+ }
+
+ mmio_write_32(CPC_CLUSTER_CNT_BACKUP, backup_cnt + curr_cnt);
+ mmio_write_32(CPC_MCUSYS_CLUSTER_COUNTER_CLR, clr_mask);
+}
+
+static inline void mtk_cpc_mcusys_off_en(void)
+{
+ mmio_write_32(CPC_MCUSYS_PWR_CTRL, 1U);
+}
+
+static inline void mtk_cpc_mcusys_off_dis(void)
+{
+ mmio_write_32(CPC_MCUSYS_PWR_CTRL, 0U);
+}
+
+void mtk_cpc_mcusys_off_reflect(void)
+{
+ mtk_cpc_mcusys_off_dis();
+ mtk_cpu_pm_mcusys_prot_release();
+}
+
+int mtk_cpc_mcusys_off_prepare(void)
+{
+ if (mtk_cpu_pm_mcusys_prot_aquire() != CPC_SUCCESS) {
+ return CPC_ERR_FAIL;
+ }
+
+ mtk_cpc_cluster_cnt_backup();
+ mtk_cpc_mcusys_off_en();
+
+ return CPC_SUCCESS;
+}
+
+void mtk_cpc_core_on_hint_set(unsigned int cpu)
+{
+ mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_SET, BIT(cpu));
+}
+
+void mtk_cpc_core_on_hint_clr(unsigned int cpu)
+{
+ mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_CLR, BIT(cpu));
+}
+
+static void mtk_cpc_dump_timestamp(void)
+{
+ uint32_t id;
+
+ for (id = 0U; id < CPC_TRACE_ID_NUM; id++) {
+ mmio_write_32(CPC_MCUSYS_TRACE_SEL, id);
+
+ memcpy((void *)(uintptr_t)CPC_TRACE_SRAM(id),
+ (const void *)(uintptr_t)CPC_MCUSYS_TRACE_DATA,
+ CPC_TRACE_SIZE);
+ }
+}
+
+void mtk_cpc_time_sync(void)
+{
+ uint64_t kt;
+ uint32_t systime_l, systime_h;
+
+ kt = sched_clock();
+ systime_l = mmio_read_32(CNTSYS_L_REG);
+ systime_h = mmio_read_32(CNTSYS_H_REG);
+
+ /* sync kernel timer to cpc */
+ mmio_write_32(CPC_MCUSYS_CPC_KERNEL_TIME_L_BASE, (uint32_t)kt);
+ mmio_write_32(CPC_MCUSYS_CPC_KERNEL_TIME_H_BASE, (uint32_t)(kt >> 32));
+ /* sync system timer to cpc */
+ mmio_write_32(CPC_MCUSYS_CPC_SYSTEM_TIME_L_BASE, systime_l);
+ mmio_write_32(CPC_MCUSYS_CPC_SYSTEM_TIME_H_BASE, systime_h);
+}
+
+static void mtk_cpc_config(uint32_t cfg, uint32_t data)
+{
+ uint32_t val;
+ uint32_t reg = 0U;
+
+ switch (cfg) {
+ case CPC_SMC_CONFIG_PROF:
+ reg = CPC_MCUSYS_CPC_DBG_SETTING;
+ val = mmio_read_32(reg);
+ val = (data != 0U) ? (val | CPC_PROF_EN) : (val & ~CPC_PROF_EN);
+ break;
+ case CPC_SMC_CONFIG_AUTO_OFF:
+ reg = CPC_MCUSYS_CPC_FLOW_CTRL_CFG;
+ val = mmio_read_32(reg);
+ if (data != 0U) {
+ val |= CPC_AUTO_OFF_EN;
+ cpc.auto_off = 1;
+ } else {
+ val &= ~CPC_AUTO_OFF_EN;
+ cpc.auto_off = 0;
+ }
+ break;
+ case CPC_SMC_CONFIG_AUTO_OFF_THRES:
+ reg = CPC_MCUSYS_CPC_OFF_THRES;
+ cpc.auto_thres_tick = us_to_ticks(data);
+ val = cpc.auto_thres_tick;
+ break;
+ case CPC_SMC_CONFIG_CNT_CLR:
+ reg = CPC_MCUSYS_CLUSTER_COUNTER_CLR;
+ val = GENMASK(1, 0); /* clr_mask */
+ break;
+ case CPC_SMC_CONFIG_TIME_SYNC:
+ mtk_cpc_time_sync();
+ break;
+ default:
+ break;
+ }
+
+ if (reg != 0U) {
+ mmio_write_32(reg, val);
+ }
+}
+
+static uint32_t mtk_cpc_read_config(uint32_t cfg)
+{
+ uint32_t res = 0U;
+
+ switch (cfg) {
+ case CPC_SMC_CONFIG_PROF:
+ res = (mmio_read_32(CPC_MCUSYS_CPC_DBG_SETTING) & CPC_PROF_EN) ?
+ 1U : 0U;
+ break;
+ case CPC_SMC_CONFIG_AUTO_OFF:
+ res = cpc.auto_off;
+ break;
+ case CPC_SMC_CONFIG_AUTO_OFF_THRES:
+ res = ticks_to_us(cpc.auto_thres_tick);
+ break;
+ case CPC_SMC_CONFIG_CNT_CLR:
+ break;
+ default:
+ break;
+ }
+
+ return res;
+}
+
+uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2)
+{
+ uint64_t res = 0ULL;
+
+ switch (act) {
+ case CPC_SMC_EVENT_DUMP_TRACE_DATA:
+ mtk_cpc_dump_timestamp();
+ break;
+ case CPC_SMC_EVENT_GIC_DPG_SET:
+ /* isolated_status = x2; */
+ break;
+ case CPC_SMC_EVENT_CPC_CONFIG:
+ mtk_cpc_config((uint32_t)arg1, (uint32_t)arg2);
+ break;
+ case CPC_SMC_EVENT_READ_CONFIG:
+ res = mtk_cpc_read_config((uint32_t)arg1);
+ break;
+ default:
+ break;
+ }
+
+ return res;
+}
+
+void mtk_cpc_init(void)
+{
+ mmio_write_32(CPC_MCUSYS_CPC_DBG_SETTING,
+ mmio_read_32(CPC_MCUSYS_CPC_DBG_SETTING)
+ | CPC_DBG_EN
+ | CPC_CALC_EN);
+
+ cpc.auto_off = 1;
+ cpc.auto_thres_tick = us_to_ticks(8000);
+
+ mmio_write_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG,
+ mmio_read_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG)
+ | CPC_OFF_PRE_EN
+ | (cpc.auto_off ? CPC_AUTO_OFF_EN : 0U));
+
+ mmio_write_32(CPC_MCUSYS_CPC_OFF_THRES, cpc.auto_thres_tick);
+}
diff --git a/plat/mediatek/mt8195/drivers/mcdi/mt_cpu_pm_cpc.h b/plat/mediatek/mt8195/drivers/mcdi/mt_cpu_pm_cpc.h
new file mode 100644
index 0000000..19dd6a2
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/mcdi/mt_cpu_pm_cpc.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_CPU_PM_CPC_H
+#define MT_CPU_PM_CPC_H
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <mcucfg.h>
+#include <platform_def.h>
+
+#define NEED_CPUSYS_PROT_WORKAROUND 1
+
+/* system sram registers */
+#define CPUIDLE_SRAM_REG(r) (uint32_t)(MTK_MCDI_SRAM_BASE + (r))
+
+/* db dump */
+#define CPC_TRACE_SIZE U(0x20)
+#define CPC_TRACE_ID_NUM U(10)
+#define CPC_TRACE_SRAM(id) (CPUIDLE_SRAM_REG(0x10) + (id) * CPC_TRACE_SIZE)
+
+/* buckup off count */
+#define CPC_CLUSTER_CNT_BACKUP CPUIDLE_SRAM_REG(0x1F0)
+#define CPC_MCUSYS_CNT CPUIDLE_SRAM_REG(0x1F4)
+
+/* CPC_MCUSYS_CPC_FLOW_CTRL_CFG(0xA814): debug setting */
+#define CPC_PWR_ON_SEQ_DIS BIT(1)
+#define CPC_PWR_ON_PRIORITY BIT(2)
+#define CPC_AUTO_OFF_EN BIT(5)
+#define CPC_DORMANT_WAIT_EN BIT(14)
+#define CPC_CTRL_EN BIT(16)
+#define CPC_OFF_PRE_EN BIT(29)
+
+/* CPC_MCUSYS_LAST_CORE_REQ(0xA818) : last core protection */
+#define CPUSYS_PROT_SET BIT(0)
+#define MCUSYS_PROT_SET BIT(8)
+#define CPUSYS_PROT_CLR BIT(8)
+#define MCUSYS_PROT_CLR BIT(9)
+
+#define CPC_PROT_RESP_MASK U(0x3)
+#define CPUSYS_RESP_OFS U(16)
+#define MCUSYS_RESP_OFS U(30)
+
+#define cpusys_resp(r) (((r) >> CPUSYS_RESP_OFS) & CPC_PROT_RESP_MASK)
+#define mcusys_resp(r) (((r) >> MCUSYS_RESP_OFS) & CPC_PROT_RESP_MASK)
+
+#define RETRY_CNT_MAX U(1000)
+
+#define PROT_RETRY U(0)
+#define PROT_SUCCESS U(1)
+#define PROT_GIVEUP U(2)
+
+/* CPC_MCUSYS_CPC_DBG_SETTING(0xAB00): debug setting */
+#define CPC_PROF_EN BIT(0)
+#define CPC_DBG_EN BIT(1)
+#define CPC_FREEZE BIT(2)
+#define CPC_CALC_EN BIT(3)
+
+enum {
+ CPC_SUCCESS = 0,
+
+ CPC_ERR_FAIL,
+ CPC_ERR_TIMEOUT,
+
+ NF_CPC_ERR
+};
+
+enum {
+ CPC_SMC_EVENT_DUMP_TRACE_DATA,
+ CPC_SMC_EVENT_GIC_DPG_SET,
+ CPC_SMC_EVENT_CPC_CONFIG,
+ CPC_SMC_EVENT_READ_CONFIG,
+
+ NF_CPC_SMC_EVENT
+};
+
+enum {
+ CPC_SMC_CONFIG_PROF,
+ CPC_SMC_CONFIG_AUTO_OFF,
+ CPC_SMC_CONFIG_AUTO_OFF_THRES,
+ CPC_SMC_CONFIG_CNT_CLR,
+ CPC_SMC_CONFIG_TIME_SYNC,
+
+ NF_CPC_SMC_CONFIG
+};
+
+#define us_to_ticks(us) ((us) * 13)
+#define ticks_to_us(tick) ((tick) / 13)
+
+int mtk_cpu_pm_cluster_prot_aquire(unsigned int cluster);
+void mtk_cpu_pm_cluster_prot_release(unsigned int cluster);
+
+void mtk_cpc_mcusys_off_reflect(void);
+int mtk_cpc_mcusys_off_prepare(void);
+
+void mtk_cpc_core_on_hint_set(unsigned int cpu);
+void mtk_cpc_core_on_hint_clr(unsigned int cpu);
+void mtk_cpc_time_sync(void);
+
+uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2);
+void mtk_cpc_init(void);
+
+#endif /* MT_CPU_PM_CPC_H */
diff --git a/plat/mediatek/mt8195/drivers/mcdi/mt_lp_irqremain.c b/plat/mediatek/mt8195/drivers/mcdi/mt_lp_irqremain.c
new file mode 100644
index 0000000..f415cb8
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/mcdi/mt_lp_irqremain.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2021-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mt_cirq.h>
+#include <mt_lp_irqremain.h>
+#include <mt_lp_rm.h>
+#include <plat_mtk_lpm.h>
+
+#define KEYPAD_IRQ_ID U(138)
+
+#define KEYPAD_WAKESRC 0x4
+
+static struct mt_irqremain remain_irqs;
+
+int mt_lp_irqremain_submit(void)
+{
+ if (remain_irqs.count == 0) {
+ return -1;
+ }
+
+ set_wakeup_sources(remain_irqs.irqs, remain_irqs.count);
+ mt_lp_rm_do_update(-1, PLAT_RC_UPDATE_REMAIN_IRQS, &remain_irqs);
+
+ return 0;
+}
+
+int mt_lp_irqremain_aquire(void)
+{
+ if (remain_irqs.count == 0) {
+ return -1;
+ }
+
+ mt_cirq_sw_reset();
+ mt_cirq_clone_gic();
+ mt_cirq_enable();
+
+ return 0;
+}
+
+int mt_lp_irqremain_release(void)
+{
+ if (remain_irqs.count == 0) {
+ return -1;
+ }
+
+ mt_cirq_flush();
+ mt_cirq_disable();
+
+ return 0;
+}
+
+void mt_lp_irqremain_init(void)
+{
+ uint32_t idx;
+
+ remain_irqs.count = 0;
+
+ /*edge keypad*/
+ idx = remain_irqs.count;
+ remain_irqs.irqs[idx] = KEYPAD_IRQ_ID;
+ remain_irqs.wakeupsrc_cat[idx] = 0;
+ remain_irqs.wakeupsrc[idx] = KEYPAD_WAKESRC;
+ remain_irqs.count++;
+
+ mt_lp_irqremain_submit();
+}
diff --git a/plat/mediatek/mt8195/drivers/mcdi/mt_lp_irqremain.h b/plat/mediatek/mt8195/drivers/mcdi/mt_lp_irqremain.h
new file mode 100644
index 0000000..b86e17e
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/mcdi/mt_lp_irqremain.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_LP_IRQREMAIN_H
+#define MT_LP_IRQREMAIN_H
+
+extern int mt_lp_irqremain_submit(void);
+extern int mt_lp_irqremain_aquire(void);
+extern int mt_lp_irqremain_release(void);
+extern void mt_lp_irqremain_init(void);
+#endif /* MT_LP_IRQREMAIN_H */
diff --git a/plat/mediatek/mt8195/drivers/mcdi/mt_mcdi.c b/plat/mediatek/mt8195/drivers/mcdi/mt_mcdi.c
new file mode 100644
index 0000000..c14e83b
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/mcdi/mt_mcdi.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cdefs.h>
+#include <common/debug.h>
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <mt_mcdi.h>
+
+/* Read/Write */
+#define APMCU_MCUPM_MBOX_AP_READY U(0)
+#define APMCU_MCUPM_MBOX_RESERVED_1 U(1)
+#define APMCU_MCUPM_MBOX_RESERVED_2 U(2)
+#define APMCU_MCUPM_MBOX_RESERVED_3 U(3)
+#define APMCU_MCUPM_MBOX_PWR_CTRL_EN U(4)
+#define APMCU_MCUPM_MBOX_L3_CACHE_MODE U(5)
+#define APMCU_MCUPM_MBOX_BUCK_MODE U(6)
+#define APMCU_MCUPM_MBOX_ARMPLL_MODE U(7)
+/* Read only */
+#define APMCU_MCUPM_MBOX_TASK_STA U(8)
+#define APMCU_MCUPM_MBOX_RESERVED_9 U(9)
+#define APMCU_MCUPM_MBOX_RESERVED_10 U(10)
+#define APMCU_MCUPM_MBOX_RESERVED_11 U(11)
+
+/* CPC mode - Read/Write */
+#define APMCU_MCUPM_MBOX_WAKEUP_CPU U(12)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_PWR_CTRL_EN */
+#define MCUPM_MCUSYS_CTRL BIT(0)
+#define MCUPM_BUCK_CTRL BIT(1)
+#define MCUPM_ARMPLL_CTRL BIT(2)
+#define MCUPM_CM_CTRL BIT(3)
+#define MCUPM_PWR_CTRL_MASK GENMASK(3, 0)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_BUCK_MODE */
+#define MCUPM_BUCK_NORMAL_MODE U(0) /* default */
+#define MCUPM_BUCK_LP_MODE U(1)
+#define MCUPM_BUCK_OFF_MODE U(2)
+#define NF_MCUPM_BUCK_MODE U(3)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_ARMPLL_MODE */
+#define MCUPM_ARMPLL_ON U(0) /* default */
+#define MCUPM_ARMPLL_GATING U(1)
+#define MCUPM_ARMPLL_OFF U(2)
+#define NF_MCUPM_ARMPLL_MODE U(3)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_TASK_STA */
+#define MCUPM_TASK_UNINIT U(0)
+#define MCUPM_TASK_INIT U(1)
+#define MCUPM_TASK_INIT_FINISH U(2)
+#define MCUPM_TASK_WAIT U(3)
+#define MCUPM_TASK_RUN U(4)
+#define MCUPM_TASK_PAUSE U(5)
+
+#define SSPM_MBOX_3_BASE U(0x0c55fce0)
+
+#define MCDI_NOT_INIT 0
+#define MCDI_INIT_1 1
+#define MCDI_INIT_2 2
+#define MCDI_INIT_DONE 3
+
+static int mcdi_init_status __section("tzfw_coherent_mem");
+
+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);
+}
+
+static void mtk_mcupm_pwr_ctrl_setting(uint32_t dev)
+{
+ mcdi_mbox_write(APMCU_MCUPM_MBOX_PWR_CTRL_EN, dev);
+}
+
+static void mtk_set_mcupm_pll_mode(uint32_t mode)
+{
+ if (mode < NF_MCUPM_ARMPLL_MODE) {
+ mcdi_mbox_write(APMCU_MCUPM_MBOX_ARMPLL_MODE, mode);
+ }
+}
+
+static void mtk_set_mcupm_buck_mode(uint32_t mode)
+{
+ if (mode < NF_MCUPM_BUCK_MODE) {
+ mcdi_mbox_write(APMCU_MCUPM_MBOX_BUCK_MODE, mode);
+ }
+}
+
+static int mtk_mcupm_is_ready(void)
+{
+ unsigned int sta = mcdi_mbox_read(APMCU_MCUPM_MBOX_TASK_STA);
+
+ return (sta == MCUPM_TASK_WAIT) || (sta == MCUPM_TASK_INIT_FINISH);
+}
+
+static int mcdi_init_1(void)
+{
+ unsigned int sta = mcdi_mbox_read(APMCU_MCUPM_MBOX_TASK_STA);
+
+ if (sta != MCUPM_TASK_INIT) {
+ return -1;
+ }
+
+ mtk_set_mcupm_pll_mode(MCUPM_ARMPLL_OFF);
+ mtk_set_mcupm_buck_mode(MCUPM_BUCK_OFF_MODE);
+
+ mtk_mcupm_pwr_ctrl_setting(
+ MCUPM_MCUSYS_CTRL |
+ MCUPM_BUCK_CTRL |
+ MCUPM_ARMPLL_CTRL);
+
+ mcdi_mbox_write(APMCU_MCUPM_MBOX_AP_READY, 1);
+
+ return 0;
+}
+
+static int mcdi_init_2(void)
+{
+ return mtk_mcupm_is_ready() ? 0 : -1;
+}
+
+int mcdi_try_init(void)
+{
+ if (mcdi_init_status == MCDI_INIT_DONE) {
+ return 0;
+ }
+
+ if (mcdi_init_status == MCDI_NOT_INIT) {
+ mcdi_init_status = MCDI_INIT_1;
+ }
+
+ if (mcdi_init_status == MCDI_INIT_1 && mcdi_init_1() == 0) {
+ mcdi_init_status = MCDI_INIT_2;
+ }
+
+ if (mcdi_init_status == MCDI_INIT_2 && mcdi_init_2() == 0) {
+ mcdi_init_status = MCDI_INIT_DONE;
+ }
+
+ INFO("mcdi ready for mcusys-off-idle and system suspend\n");
+
+ return (mcdi_init_status == MCDI_INIT_DONE) ? 0 : mcdi_init_status;
+}
diff --git a/plat/mediatek/mt8195/drivers/mcdi/mt_mcdi.h b/plat/mediatek/mt8195/drivers/mcdi/mt_mcdi.h
new file mode 100644
index 0000000..f3545aa
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/mcdi/mt_mcdi.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_MCDI_H
+#define MT_MCDI_H
+
+int mcdi_try_init(void);
+
+#endif /* MT_MCDI_H */
diff --git a/plat/mediatek/mt8195/drivers/pmic/pmic_wrap_init.h b/plat/mediatek/mt8195/drivers/pmic/pmic_wrap_init.h
new file mode 100644
index 0000000..9e6e74c
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/pmic/pmic_wrap_init.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMIC_WRAP_INIT_H
+#define PMIC_WRAP_INIT_H
+
+#include <stdint.h>
+
+#include "platform_def.h"
+#include <pmic_wrap_init_common.h>
+
+static struct mt8195_pmic_wrap_regs *const mtk_pwrap = (void *)PMIC_WRAP_BASE;
+
+/* PMIC_WRAP registers */
+struct mt8195_pmic_wrap_regs {
+ uint32_t init_done;
+ uint32_t reserved[543];
+ uint32_t wacs2_cmd;
+ uint32_t wacs2_wdata;
+ uint32_t reserved1[3];
+ uint32_t wacs2_rdata;
+ uint32_t reserved2[3];
+ uint32_t wacs2_vldclr;
+ uint32_t wacs2_sta;
+};
+
+#endif /* PMIC_WRAP_INIT_H */
diff --git a/plat/mediatek/mt8195/drivers/ptp3/ptp3_plat.h b/plat/mediatek/mt8195/drivers/ptp3/ptp3_plat.h
new file mode 100644
index 0000000..7d5391c
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/ptp3/ptp3_plat.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2021-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PTP3_PLAT_H
+#define PTP3_PLAT_H
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <ptp3_common.h>
+
+/* CPU info */
+#define NR_PTP3_CFG_CPU U(8)
+#define PTP3_CFG_CPU_START_ID_L U(0)
+#define PTP3_CFG_CPU_START_ID_B U(4)
+#define PTP3_CFG_CPU_END_ID U(7)
+
+#define NR_PTP3_CFG1_DATA U(2)
+#define PTP3_CFG1_MASK 0x3000
+
+#define NR_PTP3_CFG2_DATA U(5)
+
+#define PTP3_CFG3_MASK1 0x1180
+#define PTP3_CFG3_MASK2 0x35C0
+#define PTP3_CFG3_MASK3 0x3DC0
+
+/* Central control */
+static unsigned int ptp3_cfg1[NR_PTP3_CFG1_DATA][NR_PTP3_CFG] = {
+ {0x0C53A2A0, 0x1000},
+ {0x0C53A2A4, 0x1000}
+};
+
+static unsigned int ptp3_cfg2[NR_PTP3_CFG2_DATA][NR_PTP3_CFG] = {
+ {0x0C530404, 0x3A1000},
+ {0x0C530428, 0x13E0408},
+ {0x0C530434, 0xB22800},
+ {0x0C53043C, 0x750},
+ {0x0C530440, 0x0222c4cc}
+};
+
+static unsigned int ptp3_cfg3[NR_PTP3_CFG] = {0x0C530400, 0x2D80};
+static unsigned int ptp3_cfg3_ext[NR_PTP3_CFG] = {0x0C530400, 0xC00};
+
+#endif /* PTP3_PLAT_H */
diff --git a/plat/mediatek/mt8195/drivers/spm/build.mk b/plat/mediatek/mt8195/drivers/spm/build.mk
new file mode 100644
index 0000000..28b2d07
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/build.mk
@@ -0,0 +1,68 @@
+#
+# Copyright (c) 2021, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Enable or disable spm feature
+MT_SPM_FEATURE_SUPPORT = yes
+
+# Enable or disable cirq restore
+MT_SPM_CIRQ_FEATURE_SUPPORT = yes
+
+# sspm notifier support
+MT_SPM_SSPM_NOTIFIER_SUPPORT = yes
+
+CUR_SPM_FOLDER = ${MTK_PLAT_SOC}/drivers/spm
+
+# spm common files
+PLAT_SPM_SOURCE_FILES_COMMON += \
+ ${CUR_SPM_FOLDER}/mt_spm.c \
+ ${CUR_SPM_FOLDER}/mt_spm_conservation.c \
+ ${CUR_SPM_FOLDER}/mt_spm_internal.c \
+ ${CUR_SPM_FOLDER}/mt_spm_pmic_wrap.c
+
+# spm platform dependcy files
+PLAT_SPM_SOURCE_FILES += \
+ ${CUR_SPM_FOLDER}/constraints/mt_spm_rc_bus26m.c \
+ ${CUR_SPM_FOLDER}/constraints/mt_spm_rc_cpu_buck_ldo.c \
+ ${CUR_SPM_FOLDER}/constraints/mt_spm_rc_dram.c \
+ ${CUR_SPM_FOLDER}/constraints/mt_spm_rc_syspll.c \
+ ${CUR_SPM_FOLDER}/mt_spm_cond.c \
+ ${CUR_SPM_FOLDER}/mt_spm_suspend.c \
+ ${CUR_SPM_FOLDER}/mt_spm_idle.c \
+ ${CUR_SPM_FOLDER}/mt_spm_vcorefs.c
+
+ifeq (${MT_SPM_FEATURE_SUPPORT}, no)
+PLAT_SPM_DEBUG_CFLAGS += -DATF_PLAT_SPM_UNSUPPORT
+BL31_MT_LPM_PLAT_SPM_SOURCE_FILES += ${PLAT_SPM_SOURCE_FILES_COMMON}
+else
+BL31_MT_LPM_PLAT_SPM_SOURCE_FILES += \
+ ${PLAT_SPM_SOURCE_FILES_COMMON} \
+ ${PLAT_SPM_SOURCE_FILES}
+endif
+
+ifeq (${MT_SPM_CIRQ_FEATURE_SUPPORT}, no)
+PLAT_SPM_DEBUG_CFLAGS += -DATF_PLAT_CIRQ_UNSUPPORT
+endif
+
+ifeq (${MT_SPM_SSPM_NOTIFIER_SUPPORT}, no)
+PLAT_SPM_DEBUG_CFLAGS += -DATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+else
+BL31_MT_LPM_PLAT_SPM_SOURCE_FILES += \
+ ${CUR_SPM_FOLDER}/notifier/mt_spm_sspm_notifier.c
+endif
+
+$(info --------------------------------------)
+$(info SPM build flags: ${PLAT_SPM_DEBUG_CFLAGS})
+$(info SPM build files: ${BL31_MT_LPM_PLAT_SPM_SOURCE_FILES})
+$(info --------------------------------------)
+
+# Common makefile for platform.mk
+PLAT_INCLUDES += \
+ ${PLAT_SPM_DEBUG_CFLAGS} \
+ -I${CUR_SPM_FOLDER}/ \
+ -I${CUR_SPM_FOLDER}/constraints/ \
+ -I${CUR_SPM_FOLDER}/notifier/
+
+PLAT_BL_COMMON_SOURCES += ${BL31_MT_LPM_PLAT_SPM_SOURCE_FILES}
diff --git a/plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_bus26m.c b/plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_bus26m.c
new file mode 100644
index 0000000..87278d7
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_bus26m.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2021-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#include <mt_lp_rm.h>
+#include <mt_spm.h>
+#include <mt_spm_cond.h>
+#include <mt_spm_constraint.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_idle.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_notifier.h>
+#include <mt_spm_rc_internal.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_suspend.h>
+#include <plat_pm.h>
+#include <plat_mtk_lpm.h>
+
+#ifndef ATF_PLAT_CIRQ_UNSUPPORT
+#include <mt_cirq.h>
+#include <mt_gic_v3.h>
+#endif
+
+#define CONSTRAINT_BUS26M_ALLOW \
+ (MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF | \
+ MT_RM_CONSTRAINT_ALLOW_DRAM_S0 | \
+ MT_RM_CONSTRAINT_ALLOW_DRAM_S1 | \
+ MT_RM_CONSTRAINT_ALLOW_VCORE_LP | \
+ MT_RM_CONSTRAINT_ALLOW_LVTS_STATE | \
+ MT_RM_CONSTRAINT_ALLOW_BUS26M_OFF)
+
+#define CONSTRAINT_BUS26M_PCM_FLAG \
+ (SPM_FLAG_DISABLE_INFRA_PDN | \
+ SPM_FLAG_DISABLE_VCORE_DVS | \
+ SPM_FLAG_DISABLE_VCORE_DFS | \
+ SPM_FLAG_SRAM_SLEEP_CTRL | \
+ SPM_FLAG_ENABLE_TIA_WORKAROUND | \
+ SPM_FLAG_ENABLE_LVTS_WORKAROUND | \
+ SPM_FLAG_KEEP_CSYSPWRACK_HIGH | \
+ SPM_FLAG_DISABLE_DRAMC_MCU_SRAM_SLEEP)
+
+#define CONSTRAINT_BUS26M_PCM_FLAG1 0U
+
+#define CONSTRAINT_BUS26M_RESOURCE_REQ 0U
+
+static unsigned int bus26m_ext_opand;
+static struct mt_irqremain *refer2remain_irq;
+static struct mt_spm_cond_tables cond_bus26m = {
+ .name = "bus26m",
+ .table_cg = {
+ 0xFFFFD408, /* MTCMOS1 */
+ 0x2284C802, /* INFRA0 */
+ 0x27AF8000, /* INFRA1 */
+ 0x86040650, /* INFRA2 */
+ 0x30038020, /* INFRA3 */
+ 0x80000000, /* INFRA4 */
+ 0x00080ABB, /* PERI0 */
+ 0x00004000, /* VPPSYS0_0 */
+ 0x08803000, /* VPPSYS0_1 */
+ 0x00000000, /* VPPSYS0_2 */
+ 0x80005555, /* VPPSYS1_0 */
+ 0x00009008, /* VPPSYS1_1 */
+ 0x60060000, /* VDOSYS0_0 */
+ 0x00000000, /* VDOSYS0_1 */
+ 0x201E01F8, /* VDOSYS1_0 */
+ 0x00800000, /* VDOSYS1_1 */
+ 0x00000000, /* VDOSYS1_2 */
+ 0x00000080, /* I2C */
+ },
+ .table_pll = (PLL_BIT_UNIVPLL |
+ PLL_BIT_MFGPLL |
+ PLL_BIT_MSDCPLL |
+ PLL_BIT_TVDPLL |
+ PLL_BIT_MMPLL),
+};
+
+static struct mt_spm_cond_tables cond_bus26m_res = {
+ .table_cg = { 0U },
+ .table_pll = 0U,
+};
+
+static struct constraint_status status = {
+ .id = MT_RM_CONSTRAINT_ID_BUS26M,
+ .valid = (MT_SPM_RC_VALID_SW |
+ MT_SPM_RC_VALID_COND_LATCH),
+ .cond_block = 0U,
+ .enter_cnt = 0U,
+ .cond_res = &cond_bus26m_res,
+};
+
+/*
+ * Cirq will take the place of gic when gic is off.
+ * However, cirq cannot work if 26m clk is turned off when system idle/suspend.
+ * Therefore, we need to set irq pending for specific wakeup source.
+ */
+#ifdef ATF_PLAT_CIRQ_UNSUPPORT
+#define do_irqs_delivery()
+#else
+static void mt_spm_irq_remain_dump(struct mt_irqremain *irqs,
+ unsigned int irq_index,
+ struct wake_status *wakeup)
+{
+ INFO("[SPM] r12 = 0x%08x(0x%08x), flag = 0x%08x 0x%08x 0x%08x\n",
+ wakeup->tr.comm.r12, wakeup->md32pcm_wakeup_sta,
+ wakeup->tr.comm.debug_flag, wakeup->tr.comm.b_sw_flag0,
+ wakeup->tr.comm.b_sw_flag1);
+
+ INFO("irq:%u(0x%08x) set pending\n",
+ irqs->wakeupsrc[irq_index], irqs->irqs[irq_index]);
+}
+
+static void do_irqs_delivery(void)
+{
+ unsigned int idx;
+ int res = 0;
+ struct wake_status *wakeup = NULL;
+ struct mt_irqremain *irqs = refer2remain_irq;
+
+ res = spm_conservation_get_result(&wakeup);
+
+ if ((res != 0) && (irqs == NULL)) {
+ return;
+ }
+
+ for (idx = 0U; idx < irqs->count; ++idx) {
+ if (((wakeup->tr.comm.r12 & irqs->wakeupsrc[idx]) != 0U) ||
+ ((wakeup->raw_sta & irqs->wakeupsrc[idx]) != 0U)) {
+ if ((irqs->wakeupsrc_cat[idx] &
+ MT_IRQ_REMAIN_CAT_LOG) != 0U) {
+ mt_spm_irq_remain_dump(irqs, idx, wakeup);
+ }
+
+ mt_irq_set_pending(irqs->irqs[idx]);
+ }
+ }
+}
+#endif
+
+static void spm_bus26m_conduct(struct spm_lp_scen *spm_lp,
+ unsigned int *resource_req)
+{
+ spm_lp->pwrctrl->pcm_flags = (uint32_t)CONSTRAINT_BUS26M_PCM_FLAG;
+ spm_lp->pwrctrl->pcm_flags1 = (uint32_t)CONSTRAINT_BUS26M_PCM_FLAG1;
+ *resource_req |= CONSTRAINT_BUS26M_RESOURCE_REQ;
+}
+
+bool spm_is_valid_rc_bus26m(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+ (void)state_id;
+
+ return (status.cond_block == 0U) && IS_MT_RM_RC_READY(status.valid);
+}
+
+int spm_update_rc_bus26m(int state_id, int type, const void *val)
+{
+ const struct mt_spm_cond_tables *tlb;
+ const struct mt_spm_cond_tables *tlb_check;
+ int res = MT_RM_STATUS_OK;
+
+ if (val == NULL) {
+ return MT_RM_STATUS_BAD;
+ }
+
+ if (type == PLAT_RC_UPDATE_CONDITION) {
+ tlb = (const struct mt_spm_cond_tables *)val;
+ tlb_check = (const struct mt_spm_cond_tables *)&cond_bus26m;
+
+ status.cond_block =
+ mt_spm_cond_check(state_id, tlb, tlb_check,
+ ((status.valid &
+ MT_SPM_RC_VALID_COND_LATCH) != 0U) ?
+ &cond_bus26m_res : NULL);
+ } else if (type == PLAT_RC_UPDATE_REMAIN_IRQS) {
+ refer2remain_irq = (struct mt_irqremain *)val;
+ } else {
+ res = MT_RM_STATUS_BAD;
+ }
+
+ return res;
+}
+
+unsigned int spm_allow_rc_bus26m(int state_id)
+{
+ (void)state_id;
+
+ return CONSTRAINT_BUS26M_ALLOW;
+}
+
+int spm_run_rc_bus26m(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_ENTER, CONSTRAINT_BUS26M_ALLOW |
+ (IS_PLAT_SUSPEND_ID(state_id) ?
+ MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND : 0U));
+#endif
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_enter(state_id,
+ (MT_SPM_EX_OP_SET_WDT |
+ MT_SPM_EX_OP_HW_S1_DETECT |
+ MT_SPM_EX_OP_SET_SUSPEND_MODE |
+ bus26m_ext_opand),
+ CONSTRAINT_BUS26M_RESOURCE_REQ);
+ } else {
+ mt_spm_idle_generic_enter(state_id, MT_SPM_EX_OP_HW_S1_DETECT,
+ spm_bus26m_conduct);
+ }
+
+ return 0;
+}
+
+int spm_reset_rc_bus26m(unsigned int cpu, int state_id)
+{
+ unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
+
+ (void)cpu;
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_LEAVE, 0U);
+#endif
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ ext_op |= (bus26m_ext_opand | MT_SPM_EX_OP_SET_WDT);
+ mt_spm_suspend_resume(state_id, ext_op, NULL);
+ bus26m_ext_opand = 0U;
+ } else {
+ mt_spm_idle_generic_resume(state_id, ext_op, NULL);
+ status.enter_cnt++;
+ }
+
+ do_irqs_delivery();
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_cpu_buck_ldo.c b/plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_cpu_buck_ldo.c
new file mode 100644
index 0000000..cf71350
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_cpu_buck_ldo.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#include <mt_spm.h>
+#include <mt_spm_cond.h>
+#include <mt_spm_constraint.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_idle.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_notifier.h>
+#include <mt_spm_rc_internal.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_suspend.h>
+#include <plat_pm.h>
+
+#define CONSTRAINT_CPU_BUCK_PCM_FLAG \
+ (SPM_FLAG_DISABLE_INFRA_PDN | \
+ SPM_FLAG_DISABLE_VCORE_DVS | \
+ SPM_FLAG_DISABLE_VCORE_DFS | \
+ SPM_FLAG_SRAM_SLEEP_CTRL | \
+ SPM_FLAG_DISABLE_DRAMC_MCU_SRAM_SLEEP |\
+ SPM_FLAG_KEEP_CSYSPWRACK_HIGH)
+
+#define CONSTRAINT_CPU_BUCK_PCM_FLAG1 0U
+
+#define CONSTRAINT_CPU_BUCK_RESOURCE_REQ \
+ (MT_SPM_DRAM_S1 | \
+ MT_SPM_DRAM_S0 | \
+ MT_SPM_SYSPLL | \
+ MT_SPM_INFRA | \
+ MT_SPM_26M | \
+ MT_SPM_XO_FPM)
+
+
+static unsigned int cpubuckldo_status = MT_SPM_RC_VALID_SW;
+static unsigned int cpubuckldo_enter_cnt;
+
+static void spm_cpu_bcuk_ldo_conduct(struct spm_lp_scen *spm_lp,
+ unsigned int *resource_req)
+{
+ spm_lp->pwrctrl->pcm_flags = (uint32_t)CONSTRAINT_CPU_BUCK_PCM_FLAG;
+ spm_lp->pwrctrl->pcm_flags1 = (uint32_t)CONSTRAINT_CPU_BUCK_PCM_FLAG1;
+ *resource_req |= CONSTRAINT_CPU_BUCK_RESOURCE_REQ;
+}
+
+bool spm_is_valid_rc_cpu_buck_ldo(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+ (void)state_id;
+
+ return IS_MT_RM_RC_READY(cpubuckldo_status);
+}
+
+unsigned int spm_allow_rc_cpu_buck_ldo(int state_id)
+{
+ (void)state_id;
+
+ return MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF;
+}
+
+int spm_run_rc_cpu_buck_ldo(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_ENTER,
+ (IS_PLAT_SUSPEND_ID(state_id) ?
+ MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND : 0U));
+#endif
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_enter(state_id,
+ MT_SPM_EX_OP_SET_SUSPEND_MODE |
+ MT_SPM_EX_OP_SET_WDT,
+ CONSTRAINT_CPU_BUCK_RESOURCE_REQ);
+ } else {
+ mt_spm_idle_generic_enter(state_id, 0U,
+ spm_cpu_bcuk_ldo_conduct);
+ }
+
+ cpubuckldo_enter_cnt++;
+
+ return 0;
+}
+
+int spm_reset_rc_cpu_buck_ldo(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_LEAVE, 0U);
+#endif
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_resume(state_id, MT_SPM_EX_OP_SET_WDT, NULL);
+ } else {
+ mt_spm_idle_generic_resume(state_id, 0U, NULL);
+ }
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_dram.c b/plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_dram.c
new file mode 100644
index 0000000..bd24ddd
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_dram.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#include <mt_lp_rm.h>
+#include <mt_spm.h>
+#include <mt_spm_cond.h>
+#include <mt_spm_constraint.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_idle.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_notifier.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_rc_internal.h>
+#include <mt_spm_suspend.h>
+#include <plat_pm.h>
+#include <plat_mtk_lpm.h>
+
+#define CONSTRAINT_DRAM_ALLOW \
+ (MT_RM_CONSTRAINT_ALLOW_DRAM_S0 | \
+ MT_RM_CONSTRAINT_ALLOW_DRAM_S1 | \
+ MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF)
+
+#define CONSTRAINT_DRAM_PCM_FLAG \
+ (SPM_FLAG_DISABLE_INFRA_PDN | \
+ SPM_FLAG_DISABLE_VCORE_DVS | \
+ SPM_FLAG_DISABLE_VCORE_DFS | \
+ SPM_FLAG_SRAM_SLEEP_CTRL | \
+ SPM_FLAG_KEEP_CSYSPWRACK_HIGH | \
+ SPM_FLAG_DISABLE_DRAMC_MCU_SRAM_SLEEP)
+
+#define CONSTRAINT_DRAM_PCM_FLAG1 0U
+
+#define CONSTRAINT_DRAM_RESOURCE_REQ \
+ (MT_SPM_SYSPLL | \
+ MT_SPM_INFRA | \
+ MT_SPM_26M)
+
+static struct mt_spm_cond_tables cond_dram = {
+ .name = "dram",
+ .table_cg = {
+ 0xFFFDD008, /* MTCMOS1 */
+ 0x20040802, /* INFRA0 */
+ 0x27AF8000, /* INFRA1 */
+ 0x86040640, /* INFRA2 */
+ 0x00000000, /* INFRA3 */
+ 0x80000000, /* INFRA4 */
+ 0x00000000, /* PERI0 */
+ 0x00004000, /* VPPSYS0_0 */
+ 0x08803000, /* VPPSYS0_1 */
+ 0x00000000, /* VPPSYS0_2 */
+ 0x80005555, /* VPPSYS1_0 */
+ 0x00009008, /* VPPSYS1_1 */
+ 0x60060000, /* VDOSYS0_0 */
+ 0x00000000, /* VDOSYS0_1 */
+ 0x201E01F8, /* VDOSYS1_0 */
+ 0x00800000, /* VDOSYS1_1 */
+ 0x00000000, /* VDOSYS1_2 */
+ 0x00000080, /* I2C */
+ },
+ .table_pll = 0U,
+};
+
+static struct mt_spm_cond_tables cond_dram_res = {
+ .table_cg = { 0U },
+ .table_pll = 0U,
+};
+
+static struct constraint_status status = {
+ .id = MT_RM_CONSTRAINT_ID_DRAM,
+ .valid = (MT_SPM_RC_VALID_SW |
+ MT_SPM_RC_VALID_COND_LATCH |
+ MT_SPM_RC_VALID_XSOC_BBLPM),
+ .cond_block = 0U,
+ .enter_cnt = 0U,
+ .cond_res = &cond_dram_res,
+};
+
+static void spm_dram_conduct(struct spm_lp_scen *spm_lp,
+ unsigned int *resource_req)
+{
+ spm_lp->pwrctrl->pcm_flags = (uint32_t)CONSTRAINT_DRAM_PCM_FLAG;
+ spm_lp->pwrctrl->pcm_flags1 = (uint32_t)CONSTRAINT_DRAM_PCM_FLAG1;
+ *resource_req |= CONSTRAINT_DRAM_RESOURCE_REQ;
+}
+
+bool spm_is_valid_rc_dram(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+ (void)state_id;
+
+ return (status.cond_block == 0U) && IS_MT_RM_RC_READY(status.valid);
+}
+
+int spm_update_rc_dram(int state_id, int type, const void *val)
+{
+ const struct mt_spm_cond_tables *tlb;
+ const struct mt_spm_cond_tables *tlb_check;
+ int res = MT_RM_STATUS_OK;
+
+ if (val == NULL) {
+ return MT_RM_STATUS_BAD;
+ }
+
+ if (type == PLAT_RC_UPDATE_CONDITION) {
+ tlb = (const struct mt_spm_cond_tables *)val;
+ tlb_check = (const struct mt_spm_cond_tables *)&cond_dram;
+ status.cond_block =
+ mt_spm_cond_check(state_id, tlb, tlb_check,
+ ((status.valid &
+ MT_SPM_RC_VALID_COND_LATCH) != 0U) ?
+ &cond_dram_res : NULL);
+ } else {
+ res = MT_RM_STATUS_BAD;
+ }
+
+ return res;
+}
+
+unsigned int spm_allow_rc_dram(int state_id)
+{
+ (void)state_id;
+
+ return CONSTRAINT_DRAM_ALLOW;
+}
+
+int spm_run_rc_dram(unsigned int cpu, int state_id)
+{
+ unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
+ unsigned int allows = CONSTRAINT_DRAM_ALLOW;
+
+ (void)cpu;
+
+ if (IS_MT_SPM_RC_BBLPM_MODE(status.valid)) {
+#ifdef MT_SPM_USING_SRCLKEN_RC
+ ext_op |= MT_SPM_EX_OP_SRCLKEN_RC_BBLPM;
+#else
+ allows |= MT_RM_CONSTRAINT_ALLOW_BBLPM;
+#endif
+ }
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_ENTER, allows |
+ (IS_PLAT_SUSPEND_ID(state_id) ?
+ MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND : 0U));
+#else
+ (void)allows;
+#endif
+
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_enter(state_id,
+ (MT_SPM_EX_OP_SET_WDT |
+ MT_SPM_EX_OP_SET_SUSPEND_MODE |
+ MT_SPM_EX_OP_HW_S1_DETECT),
+ CONSTRAINT_DRAM_RESOURCE_REQ);
+ } else {
+ mt_spm_idle_generic_enter(state_id, ext_op, spm_dram_conduct);
+ }
+
+ return 0;
+}
+
+int spm_reset_rc_dram(unsigned int cpu, int state_id)
+{
+ unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
+ unsigned int allows = CONSTRAINT_DRAM_ALLOW;
+
+ (void)cpu;
+
+ if (IS_MT_SPM_RC_BBLPM_MODE(status.valid)) {
+#ifdef MT_SPM_USING_SRCLKEN_RC
+ ext_op |= MT_SPM_EX_OP_SRCLKEN_RC_BBLPM;
+#else
+ allows |= MT_RM_CONSTRAINT_ALLOW_BBLPM;
+#endif
+ }
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_LEAVE, allows);
+#else
+ (void)allows;
+#endif
+
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_resume(state_id,
+ (MT_SPM_EX_OP_SET_WDT |
+ MT_SPM_EX_OP_HW_S1_DETECT),
+ NULL);
+ } else {
+ mt_spm_idle_generic_resume(state_id, ext_op, NULL);
+ status.enter_cnt++;
+ }
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_internal.h b/plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_internal.h
new file mode 100644
index 0000000..9e74ace
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_internal.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_RC_INTERNAL_H
+#define MT_SPM_RC_INTERNAL_H
+
+#include <stdbool.h>
+
+#define SPM_FLAG_SRAM_SLEEP_CTRL \
+ (SPM_FLAG_DISABLE_SSPM_SRAM_SLEEP | \
+ SPM_FLAG_DISABLE_DRAMC_MCU_SRAM_SLEEP | \
+ SPM_FLAG_DISABLE_SYSRAM_SLEEP)
+
+/* cpu buck/ldo constraint function */
+bool spm_is_valid_rc_cpu_buck_ldo(unsigned int cpu, int state_id);
+unsigned int spm_allow_rc_cpu_buck_ldo(int state_id);
+int spm_run_rc_cpu_buck_ldo(unsigned int cpu, int state_id);
+int spm_reset_rc_cpu_buck_ldo(unsigned int cpu, int state_id);
+
+/* spm resource dram constraint function */
+bool spm_is_valid_rc_dram(unsigned int cpu, int state_id);
+int spm_update_rc_dram(int state_id, int type, const void *val);
+unsigned int spm_allow_rc_dram(int state_id);
+int spm_run_rc_dram(unsigned int cpu, int state_id);
+int spm_reset_rc_dram(unsigned int cpu, int state_id);
+
+/* spm resource syspll constraint function */
+bool spm_is_valid_rc_syspll(unsigned int cpu, int state_id);
+int spm_update_rc_syspll(int state_id, int type, const void *val);
+unsigned int spm_allow_rc_syspll(int state_id);
+int spm_run_rc_syspll(unsigned int cpu, int state_id);
+int spm_reset_rc_syspll(unsigned int cpu, int state_id);
+
+/* spm resource bus26m constraint function */
+bool spm_is_valid_rc_bus26m(unsigned int cpu, int state_id);
+int spm_update_rc_bus26m(int state_id, int type, const void *val);
+unsigned int spm_allow_rc_bus26m(int state_id);
+int spm_run_rc_bus26m(unsigned int cpu, int state_id);
+int spm_reset_rc_bus26m(unsigned int cpu, int state_id);
+#endif /* MT_SPM_RC_INTERNAL_H */
diff --git a/plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_syspll.c b/plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_syspll.c
new file mode 100644
index 0000000..662f85e
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/constraints/mt_spm_rc_syspll.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+
+#include <mt_lp_rm.h>
+#include <mt_spm.h>
+#include <mt_spm_cond.h>
+#include <mt_spm_constraint.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_idle.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_notifier.h>
+#include <mt_spm_rc_internal.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_suspend.h>
+#include <plat_pm.h>
+#include <plat_mtk_lpm.h>
+
+#define CONSTRAINT_SYSPLL_ALLOW \
+ (MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF | \
+ MT_RM_CONSTRAINT_ALLOW_DRAM_S0 | \
+ MT_RM_CONSTRAINT_ALLOW_DRAM_S1 | \
+ MT_RM_CONSTRAINT_ALLOW_VCORE_LP)
+
+#define CONSTRAINT_SYSPLL_PCM_FLAG \
+ (SPM_FLAG_DISABLE_INFRA_PDN | \
+ SPM_FLAG_DISABLE_VCORE_DVS | \
+ SPM_FLAG_DISABLE_VCORE_DFS | \
+ SPM_FLAG_SRAM_SLEEP_CTRL | \
+ SPM_FLAG_KEEP_CSYSPWRACK_HIGH | \
+ SPM_FLAG_ENABLE_6315_CTRL | \
+ SPM_FLAG_DISABLE_DRAMC_MCU_SRAM_SLEEP |\
+ SPM_FLAG_USE_SRCCLKENO2)
+
+#define CONSTRAINT_SYSPLL_PCM_FLAG1 0U
+#define CONSTRAINT_SYSPLL_RESOURCE_REQ (MT_SPM_26M)
+
+static struct mt_spm_cond_tables cond_syspll = {
+ .name = "syspll",
+ .table_cg = {
+ 0xFFFFD008, /* MTCMOS1 */
+ 0x20844802, /* INFRA0 */
+ 0x27AF8000, /* INFRA1 */
+ 0x86040640, /* INFRA2 */
+ 0x30038020, /* INFRA3 */
+ 0x80000000, /* INFRA4 */
+ 0x00080A8B, /* PERI0 */
+ 0x00004000, /* VPPSYS0_0 */
+ 0x08803000, /* VPPSYS0_1 */
+ 0x00000000, /* VPPSYS0_2 */
+ 0x80005555, /* VPPSYS1_0 */
+ 0x00009008, /* VPPSYS1_1 */
+ 0x60060000, /* VDOSYS0_0 */
+ 0x00000000, /* VDOSYS0_1 */
+ 0x201E01F8, /* VDOSYS1_0 */
+ 0x00800000, /* VDOSYS1_1 */
+ 0x00000000, /* VDOSYS1_2 */
+ 0x00000080, /* I2C */
+ },
+ .table_pll = 0U,
+};
+
+static struct mt_spm_cond_tables cond_syspll_res = {
+ .table_cg = { 0U },
+ .table_pll = 0U,
+};
+
+static struct constraint_status status = {
+ .id = MT_RM_CONSTRAINT_ID_SYSPLL,
+ .valid = (MT_SPM_RC_VALID_SW |
+ MT_SPM_RC_VALID_COND_LATCH |
+ MT_SPM_RC_VALID_XSOC_BBLPM),
+ .cond_block = 0U,
+ .enter_cnt = 0U,
+ .cond_res = &cond_syspll_res,
+};
+
+static void spm_syspll_conduct(struct spm_lp_scen *spm_lp,
+ unsigned int *resource_req)
+{
+ spm_lp->pwrctrl->pcm_flags = (uint32_t)CONSTRAINT_SYSPLL_PCM_FLAG;
+ spm_lp->pwrctrl->pcm_flags1 = (uint32_t)CONSTRAINT_SYSPLL_PCM_FLAG1;
+ *resource_req |= CONSTRAINT_SYSPLL_RESOURCE_REQ;
+}
+
+bool spm_is_valid_rc_syspll(unsigned int cpu, int state_id)
+{
+ (void)cpu;
+ (void)state_id;
+
+ return (status.cond_block == 0U) && IS_MT_RM_RC_READY(status.valid);
+}
+
+int spm_update_rc_syspll(int state_id, int type, const void *val)
+{
+ const struct mt_spm_cond_tables *tlb;
+ const struct mt_spm_cond_tables *tlb_check;
+ int res = MT_RM_STATUS_OK;
+
+ if (val == NULL) {
+ return MT_RM_STATUS_BAD;
+ }
+
+ if (type == PLAT_RC_UPDATE_CONDITION) {
+ tlb = (const struct mt_spm_cond_tables *)val;
+ tlb_check = (const struct mt_spm_cond_tables *)&cond_syspll;
+
+ status.cond_block =
+ mt_spm_cond_check(state_id, tlb, tlb_check,
+ ((status.valid &
+ MT_SPM_RC_VALID_COND_LATCH) != 0U) ?
+ &cond_syspll_res : NULL);
+ } else {
+ res = MT_RM_STATUS_BAD;
+ }
+
+ return res;
+}
+
+unsigned int spm_allow_rc_syspll(int state_id)
+{
+ (void)state_id;
+
+ return CONSTRAINT_SYSPLL_ALLOW;
+}
+
+int spm_run_rc_syspll(unsigned int cpu, int state_id)
+{
+ unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
+ unsigned int allows = CONSTRAINT_SYSPLL_ALLOW;
+
+ (void)cpu;
+
+ if (IS_MT_SPM_RC_BBLPM_MODE(status.valid)) {
+#ifdef MT_SPM_USING_SRCLKEN_RC
+ ext_op |= MT_SPM_EX_OP_SRCLKEN_RC_BBLPM;
+#else
+ allows |= MT_RM_CONSTRAINT_ALLOW_BBLPM;
+#endif
+ }
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_ENTER, allows |
+ (IS_PLAT_SUSPEND_ID(state_id) ?
+ MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND : 0U));
+#else
+ (void)allows;
+#endif
+
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_enter(state_id,
+ (MT_SPM_EX_OP_SET_WDT |
+ MT_SPM_EX_OP_HW_S1_DETECT |
+ MT_SPM_EX_OP_SET_SUSPEND_MODE),
+ CONSTRAINT_SYSPLL_RESOURCE_REQ);
+ } else {
+ mt_spm_idle_generic_enter(state_id, ext_op, spm_syspll_conduct);
+ }
+
+ return 0;
+}
+
+int spm_reset_rc_syspll(unsigned int cpu, int state_id)
+{
+ unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
+ unsigned int allows = CONSTRAINT_SYSPLL_ALLOW;
+
+ (void)cpu;
+
+ if (IS_MT_SPM_RC_BBLPM_MODE(status.valid)) {
+#ifdef MT_SPM_USING_SRCLKEN_RC
+ ext_op |= MT_SPM_EX_OP_SRCLKEN_RC_BBLPM;
+#else
+ allows |= MT_RM_CONSTRAINT_ALLOW_BBLPM;
+#endif
+ }
+
+#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
+ mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_LEAVE, allows);
+#else
+ (void)allows;
+#endif
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ mt_spm_suspend_resume(state_id,
+ (MT_SPM_EX_OP_SET_SUSPEND_MODE |
+ MT_SPM_EX_OP_SET_WDT |
+ MT_SPM_EX_OP_HW_S1_DETECT),
+ NULL);
+ } else {
+ mt_spm_idle_generic_resume(state_id, ext_op, NULL);
+ status.enter_cnt++;
+ }
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm.c b/plat/mediatek/mt8195/drivers/spm/mt_spm.c
new file mode 100644
index 0000000..f708bf5
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <common/debug.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <mt_lp_rm.h>
+#include <mt_spm.h>
+#include <mt_spm_cond.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_constraint.h>
+#include <mt_spm_idle.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_pmic_wrap.h>
+#include <mt_spm_rc_internal.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_suspend.h>
+#include <mtk_plat_common.h>
+#include <plat_mtk_lpm.h>
+#include <plat_pm.h>
+#include <platform_def.h>
+#include <sleep_def.h>
+
+#ifdef MT_SPM_USING_BAKERY_LOCK
+DEFINE_BAKERY_LOCK(spm_lock);
+#define plat_spm_lock_init() bakery_lock_init(&spm_lock)
+#else
+spinlock_t spm_lock;
+#define plat_spm_lock_init()
+#endif
+
+/* CLK_SCP_CFG_0 */
+#define CLK_SCP_CFG_0 (TOPCKGEN_BASE + 0x264)
+#define SPM_CK_CONTROL_EN 0x7FF
+
+struct mt_resource_constraint plat_constraint_bus26m = {
+ .is_valid = spm_is_valid_rc_bus26m,
+ .update = spm_update_rc_bus26m,
+ .allow = spm_allow_rc_bus26m,
+ .run = spm_run_rc_bus26m,
+ .reset = spm_reset_rc_bus26m,
+};
+
+struct mt_resource_constraint plat_constraint_syspll = {
+ .is_valid = spm_is_valid_rc_syspll,
+ .update = spm_update_rc_syspll,
+ .allow = spm_allow_rc_syspll,
+ .run = spm_run_rc_syspll,
+ .reset = spm_reset_rc_syspll,
+};
+
+struct mt_resource_constraint plat_constraint_dram = {
+ .is_valid = spm_is_valid_rc_dram,
+ .update = spm_update_rc_dram,
+ .allow = spm_allow_rc_dram,
+ .run = spm_run_rc_dram,
+ .reset = spm_reset_rc_dram,
+};
+
+struct mt_resource_constraint plat_constraint_cpu = {
+ .is_valid = spm_is_valid_rc_cpu_buck_ldo,
+ .update = NULL,
+ .allow = spm_allow_rc_cpu_buck_ldo,
+ .run = spm_run_rc_cpu_buck_ldo,
+ .reset = spm_reset_rc_cpu_buck_ldo,
+};
+
+struct mt_resource_constraint *plat_constraints[] = {
+ &plat_constraint_bus26m,
+ &plat_constraint_syspll,
+ &plat_constraint_dram,
+ &plat_constraint_cpu,
+ NULL,
+};
+
+struct mt_resource_manager plat_mt8195_rm = {
+ .update = mt_spm_cond_update,
+ .consts = plat_constraints,
+};
+
+void spm_boot_init(void)
+{
+ NOTICE("MT8195 %s\n", __func__);
+ /* switch ck_off/axi_26m control to SPM */
+ mmio_setbits_32(CLK_SCP_CFG_0, SPM_CK_CONTROL_EN);
+
+ plat_spm_lock_init();
+ mt_spm_pmic_wrap_set_phase(PMIC_WRAP_PHASE_ALLINONE);
+ mt_lp_rm_register(&plat_mt8195_rm);
+ mt_spm_idle_generic_init();
+ mt_spm_suspend_init();
+}
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm.h b/plat/mediatek/mt8195/drivers/spm/mt_spm.h
new file mode 100644
index 0000000..bc57b61
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_H
+#define MT_SPM_H
+
+#include <lib/bakery_lock.h>
+#include <lib/spinlock.h>
+
+#include <plat_mtk_lpm.h>
+
+/*
+ * ARM v8.2, the cache will turn off automatically when cpu
+ * power down. So, there is no doubt to use the spin_lock here
+ */
+#if !HW_ASSISTED_COHERENCY
+#define MT_SPM_USING_BAKERY_LOCK
+#endif
+
+#ifdef MT_SPM_USING_BAKERY_LOCK
+DECLARE_BAKERY_LOCK(spm_lock);
+#define plat_spm_lock() bakery_lock_get(&spm_lock)
+#define plat_spm_unlock() bakery_lock_release(&spm_lock)
+#else
+extern spinlock_t spm_lock;
+#define plat_spm_lock() spin_lock(&spm_lock)
+#define plat_spm_unlock() spin_unlock(&spm_lock)
+#endif
+
+#define MT_SPM_USING_SRCLKEN_RC
+
+/* spm extern operand definition */
+#define MT_SPM_EX_OP_CLR_26M_RECORD (1U << 0)
+#define MT_SPM_EX_OP_SET_WDT (1U << 1)
+#define MT_SPM_EX_OP_NON_GENERIC_RESOURCE_REQ (1U << 2)
+#define MT_SPM_EX_OP_SET_SUSPEND_MODE (1U << 3)
+#define MT_SPM_EX_OP_SET_IS_ADSP (1U << 4)
+#define MT_SPM_EX_OP_SRCLKEN_RC_BBLPM (1U << 5)
+#define MT_SPM_EX_OP_HW_S1_DETECT (1U << 6)
+
+typedef enum {
+ WR_NONE = 0,
+ WR_UART_BUSY = 1,
+ WR_ABORT = 2,
+ WR_PCM_TIMER = 3,
+ WR_WAKE_SRC = 4,
+ WR_DVFSRC = 5,
+ WR_TWAM = 6,
+ WR_PMSR = 7,
+ WR_SPM_ACK_CHK = 8,
+ WR_UNKNOWN = 9,
+} wake_reason_t;
+
+static inline void spm_lock_get(void)
+{
+ plat_spm_lock();
+}
+
+static inline void spm_lock_release(void)
+{
+ plat_spm_unlock();
+}
+
+extern void spm_boot_init(void);
+#endif /* MT_SPM_H */
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm_cond.c b/plat/mediatek/mt8195/drivers/spm/mt_spm_cond.c
new file mode 100644
index 0000000..c80faf5
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm_cond.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <mt_spm_cond.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_constraint.h>
+#include <plat_mtk_lpm.h>
+#include <plat_pm.h>
+#include <platform_def.h>
+
+#define MT_LP_TZ_INFRA_REG(ofs) (INFRACFG_AO_BASE + ofs)
+#define MT_LP_TZ_SPM_REG(ofs) (SPM_BASE + ofs)
+#define MT_LP_TZ_TOPCK_REG(ofs) (TOPCKGEN_BASE + ofs)
+#define MT_LP_TZ_APMIXEDSYS(ofs) (APMIXEDSYS + ofs)
+#define MT_LP_TZ_VPPSYS0_REG(ofs) (VPPSYS0_BASE + ofs)
+#define MT_LP_TZ_VPPSYS1_REG(ofs) (VPPSYS1_BASE + ofs)
+#define MT_LP_TZ_VDOSYS0_REG(ofs) (VDOSYS0_BASE + ofs)
+#define MT_LP_TZ_VDOSYS1_REG(ofs) (VDOSYS1_BASE + ofs)
+#define MT_LP_TZ_PERI_AO_REG(ofs) (PERICFG_AO_BASE + ofs)
+
+#define SPM_PWR_STATUS MT_LP_TZ_SPM_REG(0x016C)
+#define SPM_PWR_STATUS_2ND MT_LP_TZ_SPM_REG(0x0170)
+#define INFRA_SW_CG0 MT_LP_TZ_INFRA_REG(0x0094)
+#define INFRA_SW_CG1 MT_LP_TZ_INFRA_REG(0x0090)
+#define INFRA_SW_CG2 MT_LP_TZ_INFRA_REG(0x00AC)
+#define INFRA_SW_CG3 MT_LP_TZ_INFRA_REG(0x00C8)
+#define INFRA_SW_CG4 MT_LP_TZ_INFRA_REG(0x00E8)
+#define TOP_SW_I2C_CG MT_LP_TZ_TOPCK_REG(0x00BC)
+#define PERI_SW_CG0 MT_LP_TZ_PERI_AO_REG(0x0018)
+#define VPPSYS0_SW_CG0 MT_LP_TZ_VPPSYS0_REG(0x0020)
+#define VPPSYS0_SW_CG1 MT_LP_TZ_VPPSYS0_REG(0x002C)
+#define VPPSYS0_SW_CG2 MT_LP_TZ_VPPSYS0_REG(0x0038)
+#define VPPSYS1_SW_CG0 MT_LP_TZ_VPPSYS1_REG(0x0100)
+#define VPPSYS1_SW_CG1 MT_LP_TZ_VPPSYS1_REG(0x0110)
+#define VDOSYS0_SW_CG0 MT_LP_TZ_VDOSYS0_REG(0x0100)
+#define VDOSYS0_SW_CG1 MT_LP_TZ_VDOSYS0_REG(0x0110)
+#define VDOSYS1_SW_CG0 MT_LP_TZ_VDOSYS1_REG(0x0100)
+#define VDOSYS1_SW_CG1 MT_LP_TZ_VDOSYS1_REG(0x0120)
+#define VDOSYS1_SW_CG2 MT_LP_TZ_VDOSYS1_REG(0x0130)
+
+/***********************************************************
+ * Check clkmux registers
+ ***********************************************************/
+#define CLK_CFG(id) MT_LP_TZ_TOPCK_REG(0x98 + id * 0x10)
+#define PDN_CHECK BIT(7)
+#define CLK_CHECK BIT(31)
+
+enum {
+ CLKMUX_DISP = 0,
+ NF_CLKMUX,
+};
+
+static bool is_clkmux_pdn(unsigned int clkmux_id)
+{
+ unsigned int reg, val, idx;
+
+ if ((clkmux_id & CLK_CHECK) != 0U) {
+ clkmux_id = (clkmux_id & ~CLK_CHECK);
+ reg = clkmux_id / 4U;
+ val = mmio_read_32(CLK_CFG(reg));
+ idx = clkmux_id % 4U;
+ val = (val >> (idx * 8U)) & PDN_CHECK;
+ return (val != 0U);
+ }
+
+ return false;
+}
+
+static struct mt_spm_cond_tables spm_cond_t;
+
+struct idle_cond_info {
+ unsigned int subsys_mask;
+ uintptr_t addr;
+ bool bBitflip;
+ unsigned int clkmux_id;
+};
+
+#define IDLE_CG(mask, addr, bitflip, clkmux) \
+ {mask, (uintptr_t)addr, bitflip, clkmux}
+
+static struct idle_cond_info idle_cg_info[PLAT_SPM_COND_MAX] = {
+ IDLE_CG(0xffffffff, SPM_PWR_STATUS, false, 0U),
+ IDLE_CG(0xffffffff, INFRA_SW_CG0, true, 0U),
+ IDLE_CG(0xffffffff, INFRA_SW_CG1, true, 0U),
+ IDLE_CG(0xffffffff, INFRA_SW_CG2, true, 0U),
+ IDLE_CG(0xffffffff, INFRA_SW_CG3, true, 0U),
+ IDLE_CG(0xffffffff, INFRA_SW_CG4, true, 0U),
+ IDLE_CG(0xffffffff, PERI_SW_CG0, true, 0U),
+ IDLE_CG(0x00000800, VPPSYS0_SW_CG0, true, (CLK_CHECK|CLKMUX_DISP)),
+ IDLE_CG(0x00000800, VPPSYS0_SW_CG1, true, (CLK_CHECK|CLKMUX_DISP)),
+ IDLE_CG(0x00000800, VPPSYS0_SW_CG2, true, (CLK_CHECK|CLKMUX_DISP)),
+ IDLE_CG(0x00001000, VPPSYS1_SW_CG0, true, (CLK_CHECK|CLKMUX_DISP)),
+ IDLE_CG(0x00001000, VPPSYS1_SW_CG1, true, (CLK_CHECK|CLKMUX_DISP)),
+ IDLE_CG(0x00002000, VDOSYS0_SW_CG0, true, (CLK_CHECK|CLKMUX_DISP)),
+ IDLE_CG(0x00002000, VDOSYS0_SW_CG1, true, (CLK_CHECK|CLKMUX_DISP)),
+ IDLE_CG(0x00004000, VDOSYS1_SW_CG0, true, (CLK_CHECK|CLKMUX_DISP)),
+ IDLE_CG(0x00004000, VDOSYS1_SW_CG1, true, (CLK_CHECK|CLKMUX_DISP)),
+ IDLE_CG(0x00004000, VDOSYS1_SW_CG2, true, (CLK_CHECK|CLKMUX_DISP)),
+ IDLE_CG(0x00000080, TOP_SW_I2C_CG, true, (CLK_CHECK|CLKMUX_DISP)),
+};
+
+/***********************************************************
+ * Check pll idle condition
+ ***********************************************************/
+#define PLL_MFGPLL MT_LP_TZ_APMIXEDSYS(0x340)
+#define PLL_MMPLL MT_LP_TZ_APMIXEDSYS(0x0E0)
+#define PLL_UNIVPLL MT_LP_TZ_APMIXEDSYS(0x1F0)
+#define PLL_MSDCPLL MT_LP_TZ_APMIXEDSYS(0x710)
+#define PLL_TVDPLL MT_LP_TZ_APMIXEDSYS(0x380)
+
+unsigned int mt_spm_cond_check(int state_id,
+ const struct mt_spm_cond_tables *src,
+ const struct mt_spm_cond_tables *dest,
+ struct mt_spm_cond_tables *res)
+{
+ unsigned int blocked = 0U, i;
+ bool is_system_suspend = IS_PLAT_SUSPEND_ID(state_id);
+
+ if ((src == NULL) || (dest == NULL)) {
+ return SPM_COND_CHECK_FAIL;
+ }
+
+ for (i = 0U; i < PLAT_SPM_COND_MAX; i++) {
+ if (res != NULL) {
+ res->table_cg[i] =
+ (src->table_cg[i] & dest->table_cg[i]);
+
+ if (is_system_suspend && (res->table_cg[i] != 0U)) {
+ INFO("suspend: %s block[%u](0x%lx) = 0x%08x\n",
+ dest->name, i, idle_cg_info[i].addr,
+ res->table_cg[i]);
+ }
+
+ if (res->table_cg[i] != 0U) {
+ blocked |= (1U << i);
+ }
+ } else if ((src->table_cg[i] & dest->table_cg[i]) != 0U) {
+ blocked |= (1U << i);
+ break;
+ }
+ }
+
+ if (res != NULL) {
+ res->table_pll = (src->table_pll & dest->table_pll);
+
+ if (res->table_pll != 0U) {
+ blocked |=
+ (res->table_pll << SPM_COND_BLOCKED_PLL_IDX) |
+ SPM_COND_CHECK_BLOCKED_PLL;
+ }
+ } else if ((src->table_pll & dest->table_pll) != 0U) {
+ blocked |= SPM_COND_CHECK_BLOCKED_PLL;
+ }
+
+ if (is_system_suspend && (blocked != 0U)) {
+ INFO("suspend: %s blocked=0x%08x\n", dest->name, blocked);
+ }
+
+ return blocked;
+}
+
+#define IS_MT_SPM_PWR_OFF(mask) \
+ (((mmio_read_32(SPM_PWR_STATUS) & mask) == 0U) && \
+ ((mmio_read_32(SPM_PWR_STATUS_2ND) & mask) == 0U))
+
+int mt_spm_cond_update(struct mt_resource_constraint **con,
+ int stateid, void *priv)
+{
+ int res;
+ uint32_t i;
+ struct mt_resource_constraint *const *rc;
+
+ /* read all cg state */
+ for (i = 0U; i < PLAT_SPM_COND_MAX; i++) {
+ spm_cond_t.table_cg[i] = 0U;
+
+ /* check mtcmos, if off set idle_value and clk to 0 disable */
+ if (IS_MT_SPM_PWR_OFF(idle_cg_info[i].subsys_mask)) {
+ continue;
+ }
+
+ /* check clkmux */
+ if (is_clkmux_pdn(idle_cg_info[i].clkmux_id)) {
+ continue;
+ }
+
+ spm_cond_t.table_cg[i] = idle_cg_info[i].bBitflip ?
+ ~mmio_read_32(idle_cg_info[i].addr) :
+ mmio_read_32(idle_cg_info[i].addr);
+ }
+
+ spm_cond_t.table_pll = 0U;
+ if ((mmio_read_32(PLL_MFGPLL) & 0x200) != 0U) {
+ spm_cond_t.table_pll |= PLL_BIT_MFGPLL;
+ }
+
+ if ((mmio_read_32(PLL_MMPLL) & 0x200) != 0U) {
+ spm_cond_t.table_pll |= PLL_BIT_MMPLL;
+ }
+
+ if ((mmio_read_32(PLL_UNIVPLL) & 0x200) != 0U) {
+ spm_cond_t.table_pll |= PLL_BIT_UNIVPLL;
+ }
+
+ if ((mmio_read_32(PLL_MSDCPLL) & 0x200) != 0U) {
+ spm_cond_t.table_pll |= PLL_BIT_MSDCPLL;
+ }
+
+ if ((mmio_read_32(PLL_TVDPLL) & 0x200) != 0U) {
+ spm_cond_t.table_pll |= PLL_BIT_TVDPLL;
+ }
+
+ spm_cond_t.priv = priv;
+ for (rc = con; *rc != NULL; rc++) {
+ if (((*rc)->update) == NULL) {
+ continue;
+ }
+
+ res = (*rc)->update(stateid, PLAT_RC_UPDATE_CONDITION,
+ (void const *)&spm_cond_t);
+ if (res != MT_RM_STATUS_OK) {
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm_cond.h b/plat/mediatek/mt8195/drivers/spm/mt_spm_cond.h
new file mode 100644
index 0000000..e471b55
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm_cond.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_CONDIT_H
+#define MT_SPM_CONDIT_H
+
+#include <mt_lp_rm.h>
+
+enum PLAT_SPM_COND {
+ PLAT_SPM_COND_MTCMOS1 = 0,
+ PLAT_SPM_COND_CG_INFRA_0,
+ PLAT_SPM_COND_CG_INFRA_1,
+ PLAT_SPM_COND_CG_INFRA_2,
+ PLAT_SPM_COND_CG_INFRA_3,
+ PLAT_SPM_COND_CG_INFRA_4,
+ PLAT_SPM_COND_CG_PERI_SW_0,
+ PLAT_SPM_COND_CG_VPPSYS0_SW_CG_0,
+ PLAT_SPM_COND_CG_VPPSYS0_SW_CG_1,
+ PLAT_SPM_COND_CG_VPPSYS0_SW_CG_2,
+ PLAT_SPM_COND_CG_VPPSYS1_SW_CG_0,
+ PLAT_SPM_COND_CG_VPPSYS1_SW_CG_1,
+ PLAT_SPM_COND_CG_VDOSYS0_SW_CG_0,
+ PLAT_SPM_COND_CG_VDOSYS0_SW_CG_1,
+ PLAT_SPM_COND_CG_VDOSYS1_SW_CG_0,
+ PLAT_SPM_COND_CG_VDOSYS1_SW_CG_1,
+ PLAT_SPM_COND_CG_VDOSYS1_SW_CG_2,
+ PLAT_SPM_COND_CG_I2C_SW_CG,
+ PLAT_SPM_COND_MAX,
+};
+
+enum PLAT_SPM_COND_PLL {
+ PLAT_SPM_COND_PLL_UNIVPLL = 0,
+ PLAT_SPM_COND_PLL_MFGPLL,
+ PLAT_SPM_COND_PLL_MSDCPLL,
+ PLAT_SPM_COND_PLL_TVDPLL,
+ PLAT_SPM_COND_PLL_MMPLL,
+ PLAT_SPM_COND_PLL_MAX,
+};
+
+#define PLL_BIT_MFGPLL BIT(PLAT_SPM_COND_PLL_MFGPLL)
+#define PLL_BIT_MMPLL BIT(PLAT_SPM_COND_PLL_MMPLL)
+#define PLL_BIT_UNIVPLL BIT(PLAT_SPM_COND_PLL_UNIVPLL)
+#define PLL_BIT_MSDCPLL BIT(PLAT_SPM_COND_PLL_MSDCPLL)
+#define PLL_BIT_TVDPLL BIT(PLAT_SPM_COND_PLL_TVDPLL)
+
+/* Definition about SPM_COND_CHECK_BLOCKED
+ * bit [00 ~ 17]: cg blocking index
+ * bit [18 ~ 29]: pll blocking index
+ * bit [30] : pll blocking information
+ * bit [31] : idle condition check fail
+ */
+#define SPM_COND_BLOCKED_CG_IDX U(0)
+#define SPM_COND_BLOCKED_PLL_IDX U(18)
+#define SPM_COND_CHECK_BLOCKED_PLL BIT(30)
+#define SPM_COND_CHECK_FAIL BIT(31)
+
+struct mt_spm_cond_tables {
+ char *name;
+ unsigned int table_cg[PLAT_SPM_COND_MAX];
+ unsigned int table_pll;
+ void *priv;
+};
+
+extern unsigned int mt_spm_cond_check(int state_id,
+ const struct mt_spm_cond_tables *src,
+ const struct mt_spm_cond_tables *dest,
+ struct mt_spm_cond_tables *res);
+extern int mt_spm_cond_update(struct mt_resource_constraint **con,
+ int stateid, void *priv);
+#endif /* MT_SPM_CONDIT_H */
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm_conservation.c b/plat/mediatek/mt8195/drivers/spm/mt_spm_conservation.c
new file mode 100644
index 0000000..7f33408
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm_conservation.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <mt_spm.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_reg.h>
+#include <plat_mtk_lpm.h>
+#include <plat_pm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+struct wake_status spm_wakesta; /* record last wakesta */
+
+static int go_to_spm_before_wfi(int state_id, unsigned int ext_opand,
+ struct spm_lp_scen *spm_lp,
+ unsigned int resource_req)
+{
+ int ret = 0;
+ struct pwr_ctrl *pwrctrl;
+ uint32_t cpu = plat_my_core_pos();
+
+ pwrctrl = spm_lp->pwrctrl;
+
+ __spm_set_cpu_status(cpu);
+ __spm_set_power_control(pwrctrl);
+ __spm_set_wakeup_event(pwrctrl);
+ __spm_set_pcm_flags(pwrctrl);
+ __spm_src_req_update(pwrctrl, resource_req);
+
+ if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) {
+ __spm_set_pcm_wdt(1);
+ }
+
+ if ((ext_opand & MT_SPM_EX_OP_SRCLKEN_RC_BBLPM) != 0U) {
+ __spm_xo_soc_bblpm(1);
+ }
+
+ if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) {
+ spm_hw_s1_state_monitor_resume();
+ }
+
+ /* Disable auto resume by PCM in system suspend stage */
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ __spm_disable_pcm_timer();
+ __spm_set_pcm_wdt(0);
+ }
+
+ __spm_send_cpu_wakeup_event();
+
+ INFO("cpu%d: wakesrc = 0x%x, settle = 0x%x, sec = %u\n",
+ cpu, pwrctrl->wake_src, mmio_read_32(SPM_CLK_SETTLE),
+ mmio_read_32(PCM_TIMER_VAL) / 32768);
+ INFO("sw_flag = 0x%x 0x%x, req = 0x%x, pwr = 0x%x 0x%x\n",
+ pwrctrl->pcm_flags, pwrctrl->pcm_flags1,
+ mmio_read_32(SPM_SRC_REQ), mmio_read_32(PWR_STATUS),
+ mmio_read_32(PWR_STATUS_2ND));
+ INFO("cpu_pwr = 0x%x 0x%x\n", mmio_read_32(CPU_PWR_STATUS),
+ mmio_read_32(CPU_PWR_STATUS_2ND));
+
+ return ret;
+}
+
+static void go_to_spm_after_wfi(int state_id, unsigned int ext_opand,
+ struct spm_lp_scen *spm_lp,
+ struct wake_status **status)
+{
+ unsigned int ext_status = 0U;
+
+ /* system watchdog will be resumed at kernel stage */
+ if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) {
+ __spm_set_pcm_wdt(0);
+ }
+
+ if ((ext_opand & MT_SPM_EX_OP_SRCLKEN_RC_BBLPM) != 0U) {
+ __spm_xo_soc_bblpm(0);
+ }
+
+ if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) {
+ spm_hw_s1_state_monitor_pause(&ext_status);
+ }
+
+ __spm_ext_int_wakeup_req_clr();
+ __spm_get_wakeup_status(&spm_wakesta, ext_status);
+
+ if (status != NULL) {
+ *status = &spm_wakesta;
+ }
+
+ __spm_clean_after_wakeup();
+
+ if (IS_PLAT_SUSPEND_ID(state_id)) {
+ __spm_output_wake_reason(state_id, &spm_wakesta);
+ }
+}
+
+int spm_conservation(int state_id, unsigned int ext_opand,
+ struct spm_lp_scen *spm_lp, unsigned int resource_req)
+{
+ if (spm_lp == NULL) {
+ return -1;
+ }
+
+ spm_lock_get();
+ go_to_spm_before_wfi(state_id, ext_opand, spm_lp, resource_req);
+ spm_lock_release();
+
+ return 0;
+}
+
+void spm_conservation_finish(int state_id, unsigned int ext_opand,
+ struct spm_lp_scen *spm_lp,
+ struct wake_status **status)
+{
+ spm_lock_get();
+ go_to_spm_after_wfi(state_id, ext_opand, spm_lp, status);
+ spm_lock_release();
+}
+
+int spm_conservation_get_result(struct wake_status **res)
+{
+ if (res == NULL) {
+ return -1;
+ }
+
+ *res = &spm_wakesta;
+
+ return 0;
+}
+
+#define GPIO_BANK (GPIO_BASE + 0x6F0)
+#define TRAP_UFS_FIRST BIT(11) /* bit 11, 0: UFS, 1: eMMC */
+
+void spm_conservation_pwrctrl_init(struct pwr_ctrl *pwrctrl)
+{
+ if (pwrctrl == NULL) {
+ return;
+ }
+
+ /* For ufs, emmc storage type */
+ if ((mmio_read_32(GPIO_BANK) & TRAP_UFS_FIRST) != 0U) {
+ /* If eMMC is used, mask UFS req */
+ pwrctrl->reg_ufs_srcclkena_mask_b = 0;
+ pwrctrl->reg_ufs_infra_req_mask_b = 0;
+ pwrctrl->reg_ufs_apsrc_req_mask_b = 0;
+ pwrctrl->reg_ufs_vrf18_req_mask_b = 0;
+ pwrctrl->reg_ufs_ddr_en_mask_b = 0;
+ }
+}
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm_conservation.h b/plat/mediatek/mt8195/drivers/spm/mt_spm_conservation.h
new file mode 100644
index 0000000..aa627e7
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm_conservation.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_CONSERVATION_H
+#define MT_SPM_CONSERVATION_H
+
+#include <mt_spm_internal.h>
+
+extern int spm_conservation(int state_id, unsigned int ext_opand,
+ struct spm_lp_scen *spm_lp,
+ unsigned int resource_req);
+extern void spm_conservation_finish(int state_id, unsigned int ext_opand,
+ struct spm_lp_scen *spm_lp,
+ struct wake_status **status);
+extern int spm_conservation_get_result(struct wake_status **res);
+extern void spm_conservation_pwrctrl_init(struct pwr_ctrl *pwrctrl);
+#endif /* MT_SPM_CONSERVATION_H */
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm_constraint.h b/plat/mediatek/mt8195/drivers/spm/mt_spm_constraint.h
new file mode 100644
index 0000000..944c227
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm_constraint.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_CONSTRAINT_H
+#define MT_SPM_CONSTRAINT_H
+
+#include <mt_lp_rm.h>
+
+#define MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF (1U << 0)
+#define MT_RM_CONSTRAINT_ALLOW_DRAM_S0 (1U << 1)
+#define MT_RM_CONSTRAINT_ALLOW_DRAM_S1 (1U << 2)
+#define MT_RM_CONSTRAINT_ALLOW_VCORE_LP (1U << 3)
+#define MT_RM_CONSTRAINT_ALLOW_INFRA_PDN (1U << 4)
+#define MT_RM_CONSTRAINT_ALLOW_BUS26M_OFF (1U << 5)
+#define MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND (1U << 6)
+#define MT_RM_CONSTRAINT_ALLOW_BBLPM (1U << 7)
+#define MT_RM_CONSTRAINT_ALLOW_XO_UFS (1U << 8)
+#define MT_RM_CONSTRAINT_ALLOW_GPS_STATE (1U << 9)
+#define MT_RM_CONSTRAINT_ALLOW_LVTS_STATE (1U << 10)
+
+#define MT_SPM_RC_INVALID 0x0
+#define MT_SPM_RC_VALID_SW (1U << 0)
+#define MT_SPM_RC_VALID_FW (1U << 1)
+#define MT_SPM_RC_VALID_RESIDNECY (1U << 2)
+#define MT_SPM_RC_VALID_COND_CHECK (1U << 3)
+#define MT_SPM_RC_VALID_COND_LATCH (1U << 4)
+#define MT_SPM_RC_VALID_UFS_H8 (1U << 5)
+#define MT_SPM_RC_VALID_FLIGHTMODE (1U << 6)
+#define MT_SPM_RC_VALID_XSOC_BBLPM (1U << 7)
+#define MT_SPM_RC_VALID_TRACE_EVENT (1U << 8)
+
+#define MT_SPM_RC_VALID (MT_SPM_RC_VALID_SW)
+
+#define IS_MT_RM_RC_READY(status) \
+ ((status & MT_SPM_RC_VALID) == MT_SPM_RC_VALID)
+
+#define MT_SPM_RC_BBLPM_MODE \
+ (MT_SPM_RC_VALID_UFS_H8 | \
+ MT_SPM_RC_VALID_FLIGHTMODE | \
+ MT_SPM_RC_VALID_XSOC_BBLPM)
+
+#define IS_MT_SPM_RC_BBLPM_MODE(st) \
+ ((st & (MT_SPM_RC_BBLPM_MODE)) == MT_SPM_RC_BBLPM_MODE)
+
+struct constraint_status {
+ uint16_t id;
+ uint16_t valid;
+ uint32_t cond_block;
+ uint32_t enter_cnt;
+ struct mt_spm_cond_tables *cond_res;
+};
+
+enum MT_SPM_RM_RC_TYPE {
+ MT_RM_CONSTRAINT_ID_BUS26M,
+ MT_RM_CONSTRAINT_ID_SYSPLL,
+ MT_RM_CONSTRAINT_ID_DRAM,
+ MT_RM_CONSTRAINT_ID_CPU_BUCK_LDO,
+ MT_RM_CONSTRAINT_ID_ALL,
+};
+#endif /* MT_SPM_CONSTRAINT_H */
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm_idle.c b/plat/mediatek/mt8195/drivers/spm/mt_spm_idle.c
new file mode 100644
index 0000000..4bafe95
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm_idle.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <mt_spm.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_idle.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <plat_pm.h>
+
+#define __WAKE_SRC_FOR_IDLE_COMMON__ \
+ (R12_PCM_TIMER | \
+ R12_KP_IRQ_B | \
+ R12_APWDT_EVENT_B | \
+ R12_APXGPT1_EVENT_B | \
+ R12_CONN2AP_SPM_WAKEUP_B | \
+ R12_EINT_EVENT_B | \
+ R12_CONN_WDT_IRQ_B | \
+ R12_CCIF0_EVENT_B | \
+ R12_SSPM2SPM_WAKEUP_B | \
+ R12_SCP2SPM_WAKEUP_B | \
+ R12_ADSP2SPM_WAKEUP_B | \
+ R12_USBX_CDSC_B | \
+ R12_USBX_POWERDWN_B | \
+ R12_SYS_TIMER_EVENT_B | \
+ R12_EINT_EVENT_SECURE_B | \
+ R12_AFE_IRQ_MCU_B | \
+ R12_SYS_CIRQ_IRQ_B | \
+ R12_MD2AP_PEER_EVENT_B | \
+ R12_MD1_WDT_B | \
+ R12_CLDMA_EVENT_B | \
+ R12_REG_CPU_WAKEUP | \
+ R12_APUSYS_WAKE_HOST_B)
+
+#if defined(CFG_MICROTRUST_TEE_SUPPORT)
+#define WAKE_SRC_FOR_IDLE (__WAKE_SRC_FOR_IDLE_COMMON__)
+#else
+#define WAKE_SRC_FOR_IDLE \
+ (__WAKE_SRC_FOR_IDLE_COMMON__ | \
+ R12_SEJ_EVENT_B)
+#endif
+
+static struct pwr_ctrl idle_spm_pwr = {
+ .wake_src = WAKE_SRC_FOR_IDLE,
+
+ /* SPM_AP_STANDBY_CON */
+ /* [0] */
+ .reg_wfi_op = 0,
+ /* [1] */
+ .reg_wfi_type = 0,
+ /* [2] */
+ .reg_mp0_cputop_idle_mask = 0,
+ /* [3] */
+ .reg_mp1_cputop_idle_mask = 0,
+ /* [4] */
+ .reg_mcusys_idle_mask = 0,
+ /* [25] */
+ .reg_md_apsrc_1_sel = 0,
+ /* [26] */
+ .reg_md_apsrc_0_sel = 0,
+ /* [29] */
+ .reg_conn_apsrc_sel = 0,
+
+ /* SPM_SRC_REQ */
+ /* [0] */
+ .reg_spm_apsrc_req = 0,
+ /* [1] */
+ .reg_spm_f26m_req = 1,
+ /* [3] */
+ .reg_spm_infra_req = 1,
+ /* [4] */
+ .reg_spm_vrf18_req = 0,
+ /* [7] FIXME: default disable HW Auto S1 */
+ .reg_spm_ddr_en_req = 1,
+ /* [8] */
+ .reg_spm_dvfs_req = 0,
+ /* [9] */
+ .reg_spm_sw_mailbox_req = 0,
+ /* [10] */
+ .reg_spm_sspm_mailbox_req = 0,
+ /* [11] */
+ .reg_spm_adsp_mailbox_req = 0,
+ /* [12] */
+ .reg_spm_scp_mailbox_req = 0,
+
+
+ /* SPM_SRC_MASK */
+ /* [0] */
+ .reg_sspm_srcclkena_0_mask_b = 1,
+ /* [1] */
+ .reg_sspm_infra_req_0_mask_b = 1,
+ /* [2] */
+ .reg_sspm_apsrc_req_0_mask_b = 1,
+ /* [3] */
+ .reg_sspm_vrf18_req_0_mask_b = 1,
+ /* [4] */
+ .reg_sspm_ddr_en_0_mask_b = 1,
+ /* [5] */
+ .reg_scp_srcclkena_mask_b = 1,
+ /* [6] */
+ .reg_scp_infra_req_mask_b = 1,
+ /* [7] */
+ .reg_scp_apsrc_req_mask_b = 1,
+ /* [8] */
+ .reg_scp_vrf18_req_mask_b = 1,
+ /* [9] */
+ .reg_scp_ddr_en_mask_b = 1,
+ /* [10] */
+ .reg_audio_dsp_srcclkena_mask_b = 1,
+ /* [11] */
+ .reg_audio_dsp_infra_req_mask_b = 1,
+ /* [12] */
+ .reg_audio_dsp_apsrc_req_mask_b = 1,
+ /* [13] */
+ .reg_audio_dsp_vrf18_req_mask_b = 1,
+ /* [14] */
+ .reg_audio_dsp_ddr_en_mask_b = 1,
+ /* [15] */
+ .reg_apu_srcclkena_mask_b = 1,
+ /* [16] */
+ .reg_apu_infra_req_mask_b = 1,
+ /* [17] */
+ .reg_apu_apsrc_req_mask_b = 1,
+ /* [18] */
+ .reg_apu_vrf18_req_mask_b = 1,
+ /* [19] */
+ .reg_apu_ddr_en_mask_b = 1,
+ /* [20] */
+ .reg_cpueb_srcclkena_mask_b = 1,
+ /* [21] */
+ .reg_cpueb_infra_req_mask_b = 1,
+ /* [22] */
+ .reg_cpueb_apsrc_req_mask_b = 1,
+ /* [23] */
+ .reg_cpueb_vrf18_req_mask_b = 1,
+ /* [24] */
+ .reg_cpueb_ddr_en_mask_b = 1,
+ /* [25] */
+ .reg_bak_psri_srcclkena_mask_b = 0,
+ /* [26] */
+ .reg_bak_psri_infra_req_mask_b = 0,
+ /* [27] */
+ .reg_bak_psri_apsrc_req_mask_b = 0,
+ /* [28] */
+ .reg_bak_psri_vrf18_req_mask_b = 0,
+ /* [29] */
+ .reg_bak_psri_ddr_en_mask_b = 0,
+
+ /* SPM_SRC2_MASK */
+ /* [0] */
+ .reg_msdc0_srcclkena_mask_b = 1,
+ /* [1] */
+ .reg_msdc0_infra_req_mask_b = 1,
+ /* [2] */
+ .reg_msdc0_apsrc_req_mask_b = 1,
+ /* [3] */
+ .reg_msdc0_vrf18_req_mask_b = 1,
+ /* [4] */
+ .reg_msdc0_ddr_en_mask_b = 1,
+ /* [5] */
+ .reg_msdc1_srcclkena_mask_b = 1,
+ /* [6] */
+ .reg_msdc1_infra_req_mask_b = 1,
+ /* [7] */
+ .reg_msdc1_apsrc_req_mask_b = 1,
+ /* [8] */
+ .reg_msdc1_vrf18_req_mask_b = 1,
+ /* [9] */
+ .reg_msdc1_ddr_en_mask_b = 1,
+ /* [10] */
+ .reg_msdc2_srcclkena_mask_b = 1,
+ /* [11] */
+ .reg_msdc2_infra_req_mask_b = 1,
+ /* [12] */
+ .reg_msdc2_apsrc_req_mask_b = 1,
+ /* [13] */
+ .reg_msdc2_vrf18_req_mask_b = 1,
+ /* [14] */
+ .reg_msdc2_ddr_en_mask_b = 1,
+ /* [15] */
+ .reg_ufs_srcclkena_mask_b = 1,
+ /* [16] */
+ .reg_ufs_infra_req_mask_b = 1,
+ /* [17] */
+ .reg_ufs_apsrc_req_mask_b = 1,
+ /* [18] */
+ .reg_ufs_vrf18_req_mask_b = 1,
+ /* [19] */
+ .reg_ufs_ddr_en_mask_b = 1,
+ /* [20] */
+ .reg_usb_srcclkena_mask_b = 1,
+ /* [21] */
+ .reg_usb_infra_req_mask_b = 1,
+ /* [22] */
+ .reg_usb_apsrc_req_mask_b = 1,
+ /* [23] */
+ .reg_usb_vrf18_req_mask_b = 1,
+ /* [24] */
+ .reg_usb_ddr_en_mask_b = 1,
+ /* [25] */
+ .reg_pextp_p0_srcclkena_mask_b = 1,
+ /* [26] */
+ .reg_pextp_p0_infra_req_mask_b = 1,
+ /* [27] */
+ .reg_pextp_p0_apsrc_req_mask_b = 1,
+ /* [28] */
+ .reg_pextp_p0_vrf18_req_mask_b = 1,
+ /* [29] */
+ .reg_pextp_p0_ddr_en_mask_b = 1,
+
+ /* SPM_SRC3_MASK */
+ /* [0] */
+ .reg_pextp_p1_srcclkena_mask_b = 1,
+ /* [1] */
+ .reg_pextp_p1_infra_req_mask_b = 1,
+ /* [2] */
+ .reg_pextp_p1_apsrc_req_mask_b = 1,
+ /* [3] */
+ .reg_pextp_p1_vrf18_req_mask_b = 1,
+ /* [4] */
+ .reg_pextp_p1_ddr_en_mask_b = 1,
+ /* [5] */
+ .reg_gce0_infra_req_mask_b = 1,
+ /* [6] */
+ .reg_gce0_apsrc_req_mask_b = 1,
+ /* [7] */
+ .reg_gce0_vrf18_req_mask_b = 1,
+ /* [8] */
+ .reg_gce0_ddr_en_mask_b = 1,
+ /* [9] */
+ .reg_gce1_infra_req_mask_b = 1,
+ /* [10] */
+ .reg_gce1_apsrc_req_mask_b = 1,
+ /* [11] */
+ .reg_gce1_vrf18_req_mask_b = 1,
+ /* [12] */
+ .reg_gce1_ddr_en_mask_b = 1,
+ /* [13] */
+ .reg_spm_srcclkena_reserved_mask_b = 1,
+ /* [14] */
+ .reg_spm_infra_req_reserved_mask_b = 1,
+ /* [15] */
+ .reg_spm_apsrc_req_reserved_mask_b = 1,
+ /* [16] */
+ .reg_spm_vrf18_req_reserved_mask_b = 1,
+ /* [17] */
+ .reg_spm_ddr_en_reserved_mask_b = 1,
+ /* [18] */
+ .reg_disp0_apsrc_req_mask_b = 1,
+ /* [19] */
+ .reg_disp0_ddr_en_mask_b = 1,
+ /* [20] */
+ .reg_disp1_apsrc_req_mask_b = 1,
+ /* [21] */
+ .reg_disp1_ddr_en_mask_b = 1,
+ /* [22] */
+ .reg_disp2_apsrc_req_mask_b = 1,
+ /* [23] */
+ .reg_disp2_ddr_en_mask_b = 1,
+ /* [24] */
+ .reg_disp3_apsrc_req_mask_b = 1,
+ /* [25] */
+ .reg_disp3_ddr_en_mask_b = 1,
+ /* [26] */
+ .reg_infrasys_apsrc_req_mask_b = 0,
+ /* [27] */
+ .reg_infrasys_ddr_en_mask_b = 1,
+
+ /* [28] */
+ .reg_cg_check_srcclkena_mask_b = 1,
+ /* [29] */
+ .reg_cg_check_apsrc_req_mask_b = 1,
+ /* [30] */
+ .reg_cg_check_vrf18_req_mask_b = 1,
+ /* [31] */
+ .reg_cg_check_ddr_en_mask_b = 1,
+
+ /* SPM_SRC4_MASK */
+ /* [8:0] */
+ .reg_mcusys_merge_apsrc_req_mask_b = 0x17,
+ /* [17:9] */
+ .reg_mcusys_merge_ddr_en_mask_b = 0x17,
+ /* [19:18] */
+ .reg_dramc_md32_infra_req_mask_b = 0,
+ /* [21:20] */
+ .reg_dramc_md32_vrf18_req_mask_b = 0,
+ /* [23:22] */
+ .reg_dramc_md32_ddr_en_mask_b = 0,
+ /* [24] */
+ .reg_dvfsrc_event_trigger_mask_b = 1,
+
+ /* SPM_WAKEUP_EVENT_MASK2 */
+ /* [3:0] */
+ .reg_sc_sw2spm_wakeup_mask_b = 0,
+ /* [4] */
+ .reg_sc_adsp2spm_wakeup_mask_b = 0,
+ /* [8:5] */
+ .reg_sc_sspm2spm_wakeup_mask_b = 0,
+ /* [9] */
+ .reg_sc_scp2spm_wakeup_mask_b = 0,
+ /* [10] */
+ .reg_csyspwrup_ack_mask = 0,
+ /* [11] */
+ .reg_csyspwrup_req_mask = 1,
+
+ /* SPM_WAKEUP_EVENT_MASK */
+ /* [31:0] */
+ .reg_wakeup_event_mask = 0xC1282203,
+
+ /* SPM_WAKEUP_EVENT_EXT_MASK */
+ /* [31:0] */
+ .reg_ext_wakeup_event_mask = 0xFFFFFFFF,
+};
+
+struct spm_lp_scen idle_spm_lp = {
+ .pwrctrl = &idle_spm_pwr,
+};
+
+int mt_spm_idle_generic_enter(int state_id, unsigned int ext_opand,
+ spm_idle_conduct fn)
+{
+ unsigned int src_req = 0;
+
+ if (fn != NULL) {
+ fn(&idle_spm_lp, &src_req);
+ }
+
+ return spm_conservation(state_id, ext_opand, &idle_spm_lp, src_req);
+}
+void mt_spm_idle_generic_resume(int state_id, unsigned int ext_opand,
+ struct wake_status **status)
+{
+ spm_conservation_finish(state_id, ext_opand, &idle_spm_lp, status);
+}
+
+void mt_spm_idle_generic_init(void)
+{
+ spm_conservation_pwrctrl_init(idle_spm_lp.pwrctrl);
+}
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm_idle.h b/plat/mediatek/mt8195/drivers/spm/mt_spm_idle.h
new file mode 100644
index 0000000..7f6fb0c
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm_idle.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_IDLE_H
+#define MT_SPM_IDLE_H
+
+typedef void (*spm_idle_conduct)(struct spm_lp_scen *spm_lp,
+ unsigned int *resource_req);
+int mt_spm_idle_generic_enter(int state_id, unsigned int ext_opand,
+ spm_idle_conduct fn);
+void mt_spm_idle_generic_resume(int state_id, unsigned int ext_opand,
+ struct wake_status **status);
+void mt_spm_idle_generic_init(void);
+#endif /* MT_SPM_IDLE_H */
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm_internal.c b/plat/mediatek/mt8195/drivers/spm/mt_spm_internal.c
new file mode 100644
index 0000000..2647d9f
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm_internal.c
@@ -0,0 +1,550 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <assert.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <mt_spm.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_pmic_wrap.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <platform_def.h>
+#include <plat_pm.h>
+
+/**************************************
+ * Define and Declare
+ **************************************/
+#define ROOT_CORE_ADDR_OFFSET 0x20000000
+#define SPM_WAKEUP_EVENT_MASK_CLEAN_MASK 0xefffffff
+#define SPM_INIT_DONE_US 20
+#define SPM_WAKEUP_REASON_MISSING 0xdeaddead
+
+static unsigned int mt_spm_bblpm_cnt;
+
+const char *wakeup_src_str[32] = {
+ [0] = "PCM_TIMER",
+ [1] = "RESERVED_DEBUG_B",
+ [2] = "KEYPAD",
+ [3] = "APWDT",
+ [4] = "APXGPT",
+ [5] = "MSDC",
+ [6] = "EINT",
+ [7] = "IRRX",
+ [8] = "ETHERNET_QOS",
+ [9] = "RESERVE0",
+ [10] = "SSPM",
+ [11] = "SCP",
+ [12] = "ADSP",
+ [13] = "SPM_WDT",
+ [14] = "USB_U2",
+ [15] = "USB_TOP",
+ [16] = "SYS_TIMER",
+ [17] = "EINT_SECURE",
+ [18] = "HDMI",
+ [19] = "RESERVE1",
+ [20] = "AFE",
+ [21] = "THERMAL",
+ [22] = "SYS_CIRQ",
+ [23] = "NNA2INFRA",
+ [24] = "CSYSPWREQ",
+ [25] = "RESERVE2",
+ [26] = "PCIE",
+ [27] = "SEJ",
+ [28] = "SPM_CPU_WAKEUPEVENT",
+ [29] = "APUSYS",
+ [30] = "RESERVE3",
+ [31] = "RESERVE4",
+};
+
+/**************************************
+ * Function and API
+ **************************************/
+
+wake_reason_t __spm_output_wake_reason(int state_id,
+ const struct wake_status *wakesta)
+{
+ uint32_t i, bk_vtcxo_dur, spm_26m_off_pct = 0U;
+ char *spm_26m_sta = NULL;
+ wake_reason_t wr = WR_UNKNOWN;
+
+ if (wakesta == NULL) {
+ return WR_UNKNOWN;
+ }
+
+ spm_26m_sta = ((wakesta->debug_flag & SPM_DBG_DEBUG_IDX_26M_SLEEP) == 0U) ? "on" : "off";
+
+ if (wakesta->abort != 0U) {
+ ERROR("spmfw flow is aborted: 0x%x, timer_out = %u, 26M(%s)\n",
+ wakesta->abort, wakesta->timer_out, spm_26m_sta);
+ } else if (wakesta->r12 == SPM_WAKEUP_REASON_MISSING) {
+ WARN("cannot find wake up reason, timer_out = %u, 26M(%s)\n",
+ wakesta->timer_out, spm_26m_sta);
+ } else {
+ for (i = 0U; i < 32U; i++) {
+ if ((wakesta->r12 & (1U << i)) != 0U) {
+ INFO("wake up by %s, timer_out = %u, 26M(%s)\n",
+ wakeup_src_str[i], wakesta->timer_out, spm_26m_sta);
+ wr = WR_WAKE_SRC;
+ break;
+ }
+ }
+ }
+
+ INFO("r12 = 0x%x, r12_ext = 0x%x, r13 = 0x%x, debug_flag = 0x%x 0x%x\n",
+ wakesta->r12, wakesta->r12_ext, wakesta->r13, wakesta->debug_flag,
+ wakesta->debug_flag1);
+ INFO("raw_sta = 0x%x 0x%x 0x%x, idle_sta = 0x%x, cg_check_sta = 0x%x\n",
+ wakesta->raw_sta, wakesta->md32pcm_wakeup_sta,
+ wakesta->md32pcm_event_sta, wakesta->idle_sta,
+ wakesta->cg_check_sta);
+ INFO("req_sta = 0x%x 0x%x 0x%x 0x%x 0x%x, isr = 0x%x\n",
+ wakesta->req_sta0, wakesta->req_sta1, wakesta->req_sta2,
+ wakesta->req_sta3, wakesta->req_sta4, wakesta->isr);
+ INFO("rt_req_sta0 = 0x%x, rt_req_sta1 = 0x%x, rt_req_sta2 = 0x%x\n",
+ wakesta->rt_req_sta0, wakesta->rt_req_sta1, wakesta->rt_req_sta2);
+ INFO("rt_req_sta3 = 0x%x, dram_sw_con_3 = 0x%x, raw_ext_sta = 0x%x\n",
+ wakesta->rt_req_sta3, wakesta->rt_req_sta4, wakesta->raw_ext_sta);
+ INFO("wake_misc = 0x%x, pcm_flag = 0x%x 0x%x 0x%x 0x%x, req = 0x%x\n",
+ wakesta->wake_misc, wakesta->sw_flag0, wakesta->sw_flag1,
+ wakesta->b_sw_flag0, wakesta->b_sw_flag1, wakesta->src_req);
+ INFO("clk_settle = 0x%x, wlk_cntcv_l = 0x%x, wlk_cntcv_h = 0x%x\n",
+ wakesta->clk_settle, mmio_read_32(SYS_TIMER_VALUE_L),
+ mmio_read_32(SYS_TIMER_VALUE_H));
+
+ if (wakesta->timer_out != 0U) {
+ bk_vtcxo_dur = mmio_read_32(SPM_BK_VTCXO_DUR);
+ spm_26m_off_pct = (100 * bk_vtcxo_dur) / wakesta->timer_out;
+ INFO("spm_26m_off_pct = %u\n", spm_26m_off_pct);
+ }
+
+ return wr;
+}
+
+void __spm_set_cpu_status(unsigned int cpu)
+{
+ uint32_t root_core_addr;
+
+ if (cpu < 8U) {
+ mmio_write_32(ROOT_CPUTOP_ADDR, (1U << cpu));
+ root_core_addr = SPM_CPU0_PWR_CON + (cpu * 0x4);
+ root_core_addr += ROOT_CORE_ADDR_OFFSET;
+ mmio_write_32(ROOT_CORE_ADDR, root_core_addr);
+ /* Notify MCUPM that preferred cpu wakeup */
+ mmio_write_32(MCUPM_MBOX_WAKEUP_CPU, cpu);
+ } else {
+ ERROR("%s: error cpu number %d\n", __func__, cpu);
+ }
+}
+
+void __spm_src_req_update(const struct pwr_ctrl *pwrctrl,
+ unsigned int resource_usage)
+{
+ uint8_t apsrc_req = ((resource_usage & MT_SPM_DRAM_S0) != 0U) ?
+ 1 : pwrctrl->reg_spm_apsrc_req;
+ uint8_t ddr_en_req = ((resource_usage & MT_SPM_DRAM_S1) != 0U) ?
+ 1 : pwrctrl->reg_spm_ddr_en_req;
+ uint8_t vrf18_req = ((resource_usage & MT_SPM_SYSPLL) != 0U) ?
+ 1 : pwrctrl->reg_spm_vrf18_req;
+ uint8_t infra_req = ((resource_usage & MT_SPM_INFRA) != 0U) ?
+ 1 : pwrctrl->reg_spm_infra_req;
+ uint8_t f26m_req = ((resource_usage &
+ (MT_SPM_26M | MT_SPM_XO_FPM)) != 0U) ?
+ 1 : pwrctrl->reg_spm_f26m_req;
+
+ mmio_write_32(SPM_SRC_REQ,
+ ((apsrc_req & 0x1) << 0) |
+ ((f26m_req & 0x1) << 1) |
+ ((infra_req & 0x1) << 3) |
+ ((vrf18_req & 0x1) << 4) |
+ ((ddr_en_req & 0x1) << 7) |
+ ((pwrctrl->reg_spm_dvfs_req & 0x1) << 8) |
+ ((pwrctrl->reg_spm_sw_mailbox_req & 0x1) << 9) |
+ ((pwrctrl->reg_spm_sspm_mailbox_req & 0x1) << 10) |
+ ((pwrctrl->reg_spm_adsp_mailbox_req & 0x1) << 11) |
+ ((pwrctrl->reg_spm_scp_mailbox_req & 0x1) << 12));
+}
+
+void __spm_set_power_control(const struct pwr_ctrl *pwrctrl)
+{
+ /* Auto-gen Start */
+
+ /* SPM_AP_STANDBY_CON */
+ mmio_write_32(SPM_AP_STANDBY_CON,
+ ((pwrctrl->reg_wfi_op & 0x1) << 0) |
+ ((pwrctrl->reg_wfi_type & 0x1) << 1) |
+ ((pwrctrl->reg_mp0_cputop_idle_mask & 0x1) << 2) |
+ ((pwrctrl->reg_mp1_cputop_idle_mask & 0x1) << 3) |
+ ((pwrctrl->reg_mcusys_idle_mask & 0x1) << 4) |
+ ((pwrctrl->reg_md_apsrc_1_sel & 0x1) << 25) |
+ ((pwrctrl->reg_md_apsrc_0_sel & 0x1) << 26) |
+ ((pwrctrl->reg_conn_apsrc_sel & 0x1) << 29));
+
+ /* SPM_SRC_REQ */
+ mmio_write_32(SPM_SRC_REQ,
+ ((pwrctrl->reg_spm_apsrc_req & 0x1) << 0) |
+ ((pwrctrl->reg_spm_f26m_req & 0x1) << 1) |
+ ((pwrctrl->reg_spm_infra_req & 0x1) << 3) |
+ ((pwrctrl->reg_spm_vrf18_req & 0x1) << 4) |
+ ((pwrctrl->reg_spm_ddr_en_req & 0x1) << 7) |
+ ((pwrctrl->reg_spm_dvfs_req & 0x1) << 8) |
+ ((pwrctrl->reg_spm_sw_mailbox_req & 0x1) << 9) |
+ ((pwrctrl->reg_spm_sspm_mailbox_req & 0x1) << 10) |
+ ((pwrctrl->reg_spm_adsp_mailbox_req & 0x1) << 11) |
+ ((pwrctrl->reg_spm_scp_mailbox_req & 0x1) << 12));
+
+ /* SPM_SRC_MASK */
+ mmio_write_32(SPM_SRC_MASK,
+ ((pwrctrl->reg_sspm_srcclkena_0_mask_b & 0x1) << 0) |
+ ((pwrctrl->reg_sspm_infra_req_0_mask_b & 0x1) << 1) |
+ ((pwrctrl->reg_sspm_apsrc_req_0_mask_b & 0x1) << 2) |
+ ((pwrctrl->reg_sspm_vrf18_req_0_mask_b & 0x1) << 3) |
+ ((pwrctrl->reg_sspm_ddr_en_0_mask_b & 0x1) << 4) |
+ ((pwrctrl->reg_scp_srcclkena_mask_b & 0x1) << 5) |
+ ((pwrctrl->reg_scp_infra_req_mask_b & 0x1) << 6) |
+ ((pwrctrl->reg_scp_apsrc_req_mask_b & 0x1) << 7) |
+ ((pwrctrl->reg_scp_vrf18_req_mask_b & 0x1) << 8) |
+ ((pwrctrl->reg_scp_ddr_en_mask_b & 0x1) << 9) |
+ ((pwrctrl->reg_audio_dsp_srcclkena_mask_b & 0x1) << 10) |
+ ((pwrctrl->reg_audio_dsp_infra_req_mask_b & 0x1) << 11) |
+ ((pwrctrl->reg_audio_dsp_apsrc_req_mask_b & 0x1) << 12) |
+ ((pwrctrl->reg_audio_dsp_vrf18_req_mask_b & 0x1) << 13) |
+ ((pwrctrl->reg_audio_dsp_ddr_en_mask_b & 0x1) << 14) |
+ ((pwrctrl->reg_apu_srcclkena_mask_b & 0x1) << 15) |
+ ((pwrctrl->reg_apu_infra_req_mask_b & 0x1) << 16) |
+ ((pwrctrl->reg_apu_apsrc_req_mask_b & 0x1) << 17) |
+ ((pwrctrl->reg_apu_vrf18_req_mask_b & 0x1) << 18) |
+ ((pwrctrl->reg_apu_ddr_en_mask_b & 0x1) << 19) |
+ ((pwrctrl->reg_cpueb_srcclkena_mask_b & 0x1) << 20) |
+ ((pwrctrl->reg_cpueb_infra_req_mask_b & 0x1) << 21) |
+ ((pwrctrl->reg_cpueb_apsrc_req_mask_b & 0x1) << 22) |
+ ((pwrctrl->reg_cpueb_vrf18_req_mask_b & 0x1) << 23) |
+ ((pwrctrl->reg_cpueb_ddr_en_mask_b & 0x1) << 24) |
+ ((pwrctrl->reg_bak_psri_srcclkena_mask_b & 0x1) << 25) |
+ ((pwrctrl->reg_bak_psri_infra_req_mask_b & 0x1) << 26) |
+ ((pwrctrl->reg_bak_psri_apsrc_req_mask_b & 0x1) << 27) |
+ ((pwrctrl->reg_bak_psri_vrf18_req_mask_b & 0x1) << 28) |
+ ((pwrctrl->reg_bak_psri_ddr_en_mask_b & 0x1) << 29));
+
+ /* SPM_SRC2_MASK */
+ mmio_write_32(SPM_SRC2_MASK,
+ ((pwrctrl->reg_msdc0_srcclkena_mask_b & 0x1) << 0) |
+ ((pwrctrl->reg_msdc0_infra_req_mask_b & 0x1) << 1) |
+ ((pwrctrl->reg_msdc0_apsrc_req_mask_b & 0x1) << 2) |
+ ((pwrctrl->reg_msdc0_vrf18_req_mask_b & 0x1) << 3) |
+ ((pwrctrl->reg_msdc0_ddr_en_mask_b & 0x1) << 4) |
+ ((pwrctrl->reg_msdc1_srcclkena_mask_b & 0x1) << 5) |
+ ((pwrctrl->reg_msdc1_infra_req_mask_b & 0x1) << 6) |
+ ((pwrctrl->reg_msdc1_apsrc_req_mask_b & 0x1) << 7) |
+ ((pwrctrl->reg_msdc1_vrf18_req_mask_b & 0x1) << 8) |
+ ((pwrctrl->reg_msdc1_ddr_en_mask_b & 0x1) << 9) |
+ ((pwrctrl->reg_msdc2_srcclkena_mask_b & 0x1) << 10) |
+ ((pwrctrl->reg_msdc2_infra_req_mask_b & 0x1) << 11) |
+ ((pwrctrl->reg_msdc2_apsrc_req_mask_b & 0x1) << 12) |
+ ((pwrctrl->reg_msdc2_vrf18_req_mask_b & 0x1) << 13) |
+ ((pwrctrl->reg_msdc2_ddr_en_mask_b & 0x1) << 14) |
+ ((pwrctrl->reg_ufs_srcclkena_mask_b & 0x1) << 15) |
+ ((pwrctrl->reg_ufs_infra_req_mask_b & 0x1) << 16) |
+ ((pwrctrl->reg_ufs_apsrc_req_mask_b & 0x1) << 17) |
+ ((pwrctrl->reg_ufs_vrf18_req_mask_b & 0x1) << 18) |
+ ((pwrctrl->reg_ufs_ddr_en_mask_b & 0x1) << 19) |
+ ((pwrctrl->reg_usb_srcclkena_mask_b & 0x1) << 20) |
+ ((pwrctrl->reg_usb_infra_req_mask_b & 0x1) << 21) |
+ ((pwrctrl->reg_usb_apsrc_req_mask_b & 0x1) << 22) |
+ ((pwrctrl->reg_usb_vrf18_req_mask_b & 0x1) << 23) |
+ ((pwrctrl->reg_usb_ddr_en_mask_b & 0x1) << 24) |
+ ((pwrctrl->reg_pextp_p0_srcclkena_mask_b & 0x1) << 25) |
+ ((pwrctrl->reg_pextp_p0_infra_req_mask_b & 0x1) << 26) |
+ ((pwrctrl->reg_pextp_p0_apsrc_req_mask_b & 0x1) << 27) |
+ ((pwrctrl->reg_pextp_p0_vrf18_req_mask_b & 0x1) << 28) |
+ ((pwrctrl->reg_pextp_p0_ddr_en_mask_b & 0x1) << 29));
+
+ /* SPM_SRC3_MASK */
+ mmio_write_32(SPM_SRC3_MASK,
+ ((pwrctrl->reg_pextp_p1_srcclkena_mask_b & 0x1) << 0) |
+ ((pwrctrl->reg_pextp_p1_infra_req_mask_b & 0x1) << 1) |
+ ((pwrctrl->reg_pextp_p1_apsrc_req_mask_b & 0x1) << 2) |
+ ((pwrctrl->reg_pextp_p1_vrf18_req_mask_b & 0x1) << 3) |
+ ((pwrctrl->reg_pextp_p1_ddr_en_mask_b & 0x1) << 4) |
+ ((pwrctrl->reg_gce0_infra_req_mask_b & 0x1) << 5) |
+ ((pwrctrl->reg_gce0_apsrc_req_mask_b & 0x1) << 6) |
+ ((pwrctrl->reg_gce0_vrf18_req_mask_b & 0x1) << 7) |
+ ((pwrctrl->reg_gce0_ddr_en_mask_b & 0x1) << 8) |
+ ((pwrctrl->reg_gce1_infra_req_mask_b & 0x1) << 9) |
+ ((pwrctrl->reg_gce1_apsrc_req_mask_b & 0x1) << 10) |
+ ((pwrctrl->reg_gce1_vrf18_req_mask_b & 0x1) << 11) |
+ ((pwrctrl->reg_gce1_ddr_en_mask_b & 0x1) << 12) |
+ ((pwrctrl->reg_spm_srcclkena_reserved_mask_b & 0x1) << 13) |
+ ((pwrctrl->reg_spm_infra_req_reserved_mask_b & 0x1) << 14) |
+ ((pwrctrl->reg_spm_apsrc_req_reserved_mask_b & 0x1) << 15) |
+ ((pwrctrl->reg_spm_vrf18_req_reserved_mask_b & 0x1) << 16) |
+ ((pwrctrl->reg_spm_ddr_en_reserved_mask_b & 0x1) << 17) |
+ ((pwrctrl->reg_disp0_ddr_en_mask_b & 0x1) << 18) |
+ ((pwrctrl->reg_disp0_ddr_en_mask_b & 0x1) << 19) |
+ ((pwrctrl->reg_disp1_apsrc_req_mask_b & 0x1) << 20) |
+ ((pwrctrl->reg_disp1_ddr_en_mask_b & 0x1) << 21) |
+ ((pwrctrl->reg_disp2_apsrc_req_mask_b & 0x1) << 22) |
+ ((pwrctrl->reg_disp2_ddr_en_mask_b & 0x1) << 23) |
+ ((pwrctrl->reg_disp3_apsrc_req_mask_b & 0x1) << 24) |
+ ((pwrctrl->reg_disp3_ddr_en_mask_b & 0x1) << 25) |
+ ((pwrctrl->reg_infrasys_apsrc_req_mask_b & 0x1) << 26) |
+ ((pwrctrl->reg_infrasys_ddr_en_mask_b & 0x1) << 27));
+
+ /* Mask MCUSYS request since SOC HW would check it */
+ mmio_write_32(SPM_SRC4_MASK, 0x1fc0000);
+
+ /* SPM_WAKEUP_EVENT_MASK */
+ mmio_write_32(SPM_WAKEUP_EVENT_MASK,
+ ((pwrctrl->reg_wakeup_event_mask & 0xffffffff) << 0));
+
+ /* SPM_WAKEUP_EVENT_EXT_MASK */
+ mmio_write_32(SPM_WAKEUP_EVENT_EXT_MASK,
+ ((pwrctrl->reg_ext_wakeup_event_mask & 0xffffffff) << 0));
+
+ /* Auto-gen End */
+}
+
+void __spm_disable_pcm_timer(void)
+{
+ mmio_clrsetbits_32(PCM_CON1, RG_PCM_TIMER_EN_LSB, SPM_REGWR_CFG_KEY);
+}
+
+void __spm_set_wakeup_event(const struct pwr_ctrl *pwrctrl)
+{
+ uint32_t val, mask;
+
+ /* toggle event counter clear */
+ mmio_setbits_32(PCM_CON1,
+ SPM_REGWR_CFG_KEY | SPM_EVENT_COUNTER_CLR_LSB);
+
+ /* toggle for reset SYS TIMER start point */
+ mmio_setbits_32(SYS_TIMER_CON, SYS_TIMER_START_EN_LSB);
+
+ if (pwrctrl->timer_val_cust == 0U) {
+ val = pwrctrl->timer_val;
+ } else {
+ val = pwrctrl->timer_val_cust;
+ }
+
+ mmio_write_32(PCM_TIMER_VAL, val);
+ mmio_setbits_32(PCM_CON1, SPM_REGWR_CFG_KEY | RG_PCM_TIMER_EN_LSB);
+
+ /* unmask AP wakeup source */
+ if (pwrctrl->wake_src_cust == 0U) {
+ mask = pwrctrl->wake_src;
+ } else {
+ mask = pwrctrl->wake_src_cust;
+ }
+
+ mmio_write_32(SPM_WAKEUP_EVENT_MASK, ~mask);
+
+ /* unmask SPM ISR (keep TWAM setting) */
+ mmio_setbits_32(SPM_IRQ_MASK, ISRM_RET_IRQ_AUX);
+
+ /* toggle event counter clear */
+ mmio_clrsetbits_32(PCM_CON1, SPM_EVENT_COUNTER_CLR_LSB,
+ SPM_REGWR_CFG_KEY);
+ /* toggle for reset SYS TIMER start point */
+ mmio_clrbits_32(SYS_TIMER_CON, SYS_TIMER_START_EN_LSB);
+}
+
+void __spm_set_pcm_flags(struct pwr_ctrl *pwrctrl)
+{
+ /* set PCM flags and data */
+ if (pwrctrl->pcm_flags_cust_clr != 0U) {
+ pwrctrl->pcm_flags &= ~pwrctrl->pcm_flags_cust_clr;
+ }
+
+ if (pwrctrl->pcm_flags_cust_set != 0U) {
+ pwrctrl->pcm_flags |= pwrctrl->pcm_flags_cust_set;
+ }
+
+ if (pwrctrl->pcm_flags1_cust_clr != 0U) {
+ pwrctrl->pcm_flags1 &= ~pwrctrl->pcm_flags1_cust_clr;
+ }
+
+ if (pwrctrl->pcm_flags1_cust_set != 0U) {
+ pwrctrl->pcm_flags1 |= pwrctrl->pcm_flags1_cust_set;
+ }
+
+ mmio_write_32(SPM_SW_FLAG_0, pwrctrl->pcm_flags);
+ mmio_write_32(SPM_SW_FLAG_1, pwrctrl->pcm_flags1);
+ mmio_write_32(SPM_SW_RSV_7, pwrctrl->pcm_flags);
+ mmio_write_32(SPM_SW_RSV_8, pwrctrl->pcm_flags1);
+}
+
+void __spm_get_wakeup_status(struct wake_status *wakesta,
+ unsigned int ext_status)
+{
+ wakesta->tr.comm.r12 = mmio_read_32(SPM_BK_WAKE_EVENT);
+ wakesta->tr.comm.timer_out = mmio_read_32(SPM_BK_PCM_TIMER);
+ wakesta->tr.comm.r13 = mmio_read_32(PCM_REG13_DATA);
+ wakesta->tr.comm.req_sta0 = mmio_read_32(SRC_REQ_STA_0);
+ wakesta->tr.comm.req_sta1 = mmio_read_32(SRC_REQ_STA_1);
+ wakesta->tr.comm.req_sta2 = mmio_read_32(SRC_REQ_STA_2);
+ wakesta->tr.comm.req_sta3 = mmio_read_32(SRC_REQ_STA_3);
+ wakesta->tr.comm.req_sta4 = mmio_read_32(SRC_REQ_STA_4);
+ wakesta->tr.comm.debug_flag = mmio_read_32(PCM_WDT_LATCH_SPARE_0);
+ wakesta->tr.comm.debug_flag1 = mmio_read_32(PCM_WDT_LATCH_SPARE_1);
+
+ if ((ext_status & SPM_INTERNAL_STATUS_HW_S1) != 0U) {
+ wakesta->tr.comm.debug_flag |= (SPM_DBG_DEBUG_IDX_DDREN_WAKE |
+ SPM_DBG_DEBUG_IDX_DDREN_SLEEP);
+ mmio_write_32(PCM_WDT_LATCH_SPARE_0,
+ wakesta->tr.comm.debug_flag);
+ }
+
+ wakesta->tr.comm.b_sw_flag0 = mmio_read_32(SPM_SW_RSV_7);
+ wakesta->tr.comm.b_sw_flag1 = mmio_read_32(SPM_SW_RSV_8);
+
+ /* record below spm info for debug */
+ wakesta->r12 = mmio_read_32(SPM_BK_WAKE_EVENT);
+ wakesta->r12_ext = mmio_read_32(SPM_WAKEUP_STA);
+ wakesta->raw_sta = mmio_read_32(SPM_WAKEUP_STA);
+ wakesta->raw_ext_sta = mmio_read_32(SPM_WAKEUP_EXT_STA);
+ wakesta->md32pcm_wakeup_sta = mmio_read_32(MD32PCM_WAKEUP_STA);
+ wakesta->md32pcm_event_sta = mmio_read_32(MD32PCM_EVENT_STA);
+ wakesta->src_req = mmio_read_32(SPM_SRC_REQ);
+
+ /* backup of SPM_WAKEUP_MISC */
+ wakesta->wake_misc = mmio_read_32(SPM_BK_WAKE_MISC);
+
+ /* get sleep time, backup of PCM_TIMER_OUT */
+ wakesta->timer_out = mmio_read_32(SPM_BK_PCM_TIMER);
+
+ /* get other SYS and co-clock status */
+ wakesta->r13 = mmio_read_32(PCM_REG13_DATA);
+ wakesta->idle_sta = mmio_read_32(SUBSYS_IDLE_STA);
+ wakesta->req_sta0 = mmio_read_32(SRC_REQ_STA_0);
+ wakesta->req_sta1 = mmio_read_32(SRC_REQ_STA_1);
+ wakesta->req_sta2 = mmio_read_32(SRC_REQ_STA_2);
+ wakesta->req_sta3 = mmio_read_32(SRC_REQ_STA_3);
+ wakesta->req_sta4 = mmio_read_32(SRC_REQ_STA_4);
+
+ /* get HW CG check status */
+ wakesta->cg_check_sta = mmio_read_32(SPM_CG_CHECK_STA);
+
+ /* get debug flag for PCM execution check */
+ wakesta->debug_flag = mmio_read_32(PCM_WDT_LATCH_SPARE_0);
+ wakesta->debug_flag1 = mmio_read_32(PCM_WDT_LATCH_SPARE_1);
+
+ /* get backup SW flag status */
+ wakesta->b_sw_flag0 = mmio_read_32(SPM_SW_RSV_7);
+ wakesta->b_sw_flag1 = mmio_read_32(SPM_SW_RSV_8);
+
+ wakesta->rt_req_sta0 = mmio_read_32(SPM_SW_RSV_2);
+ wakesta->rt_req_sta1 = mmio_read_32(SPM_SW_RSV_3);
+ wakesta->rt_req_sta2 = mmio_read_32(SPM_SW_RSV_4);
+ wakesta->rt_req_sta3 = mmio_read_32(SPM_SW_RSV_5);
+ wakesta->rt_req_sta4 = mmio_read_32(SPM_SW_RSV_6);
+
+ /* get ISR status */
+ wakesta->isr = mmio_read_32(SPM_IRQ_STA);
+
+ /* get SW flag status */
+ wakesta->sw_flag0 = mmio_read_32(SPM_SW_FLAG_0);
+ wakesta->sw_flag1 = mmio_read_32(SPM_SW_FLAG_1);
+
+ /* get CLK SETTLE */
+ wakesta->clk_settle = mmio_read_32(SPM_CLK_SETTLE);
+
+ /* check abort */
+ wakesta->abort = (wakesta->debug_flag & DEBUG_ABORT_MASK) |
+ (wakesta->debug_flag1 & DEBUG_ABORT_MASK_1);
+}
+
+void __spm_clean_after_wakeup(void)
+{
+ mmio_write_32(SPM_BK_WAKE_EVENT,
+ mmio_read_32(SPM_WAKEUP_STA) |
+ mmio_read_32(SPM_BK_WAKE_EVENT));
+ mmio_write_32(SPM_CPU_WAKEUP_EVENT, 0);
+
+ /*
+ * clean wakeup event raw status (for edge trigger event)
+ * bit[28] for cpu wake up event
+ */
+ mmio_write_32(SPM_WAKEUP_EVENT_MASK, SPM_WAKEUP_EVENT_MASK_CLEAN_MASK);
+
+ /* clean ISR status (except TWAM) */
+ 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_set_pcm_wdt(int en)
+{
+ mmio_clrsetbits_32(PCM_CON1, RG_PCM_WDT_EN_LSB,
+ SPM_REGWR_CFG_KEY);
+
+ if (en == 1) {
+ mmio_clrsetbits_32(PCM_CON1, RG_PCM_WDT_WAKE_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 | RG_PCM_WDT_EN_LSB);
+ }
+}
+
+void __spm_send_cpu_wakeup_event(void)
+{
+ /* SPM will clear SPM_CPU_WAKEUP_EVENT */
+ mmio_write_32(SPM_CPU_WAKEUP_EVENT, 1);
+}
+
+void __spm_ext_int_wakeup_req_clr(void)
+{
+ mmio_write_32(EXT_INT_WAKEUP_REQ_CLR, mmio_read_32(ROOT_CPUTOP_ADDR));
+
+ /* Clear spm2mcupm wakeup interrupt status */
+ mmio_write_32(SPM2CPUEB_CON, 0);
+}
+
+void __spm_xo_soc_bblpm(int en)
+{
+ if (en == 1) {
+ mmio_clrsetbits_32(RC_M00_SRCLKEN_CFG,
+ RC_SW_SRCLKEN_FPM, RC_SW_SRCLKEN_RC);
+ assert(mt_spm_bblpm_cnt == 0);
+ mt_spm_bblpm_cnt += 1;
+ } else {
+ mmio_clrsetbits_32(RC_M00_SRCLKEN_CFG,
+ RC_SW_SRCLKEN_RC, RC_SW_SRCLKEN_FPM);
+ mt_spm_bblpm_cnt -= 1;
+ }
+}
+
+void __spm_hw_s1_state_monitor(int en, unsigned int *status)
+{
+ unsigned int reg;
+
+ reg = mmio_read_32(SPM_ACK_CHK_CON_3);
+
+ if (en == 1) {
+ reg &= ~SPM_ACK_CHK_3_CON_CLR_ALL;
+ mmio_write_32(SPM_ACK_CHK_CON_3, reg);
+ reg |= SPM_ACK_CHK_3_CON_EN;
+ mmio_write_32(SPM_ACK_CHK_CON_3, reg);
+ } else {
+ if (((reg & SPM_ACK_CHK_3_CON_RESULT) != 0U) &&
+ (status != NULL)) {
+ *status |= SPM_INTERNAL_STATUS_HW_S1;
+ }
+
+ mmio_clrsetbits_32(SPM_ACK_CHK_CON_3, SPM_ACK_CHK_3_CON_EN,
+ SPM_ACK_CHK_3_CON_HW_MODE_TRIG |
+ SPM_ACK_CHK_3_CON_CLR_ALL);
+ }
+}
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm_internal.h b/plat/mediatek/mt8195/drivers/spm/mt_spm_internal.h
new file mode 100644
index 0000000..5ac7c91
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm_internal.h
@@ -0,0 +1,583 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_INTERNAL_H
+#define MT_SPM_INTERNAL_H
+
+#include "mt_spm.h"
+
+/**************************************
+ * Config and Parameter
+ **************************************/
+#define POWER_ON_VAL0_DEF 0x0000F100
+#define POWER_ON_VAL1_DEF 0x80015860
+#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_AP_STANDBY_CON */
+#define WFI_OP_AND 1
+#define WFI_OP_OR 0
+
+/* 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 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_GIC_WAKEUP 0x3FF
+#define WAKE_MISC_DVFSRC_IRQ DVFSRC_IRQ_LSB
+#define WAKE_MISC_REG_CPU_WAKEUP SPM_WAKEUP_MISC_REG_CPU_WAKEUP_LSB
+#define WAKE_MISC_PCM_TIMER_EVENT PCM_TIMER_EVENT_LSB
+#define WAKE_MISC_PMIC_OUT_B ((1U << 19) | (1U << 20))
+#define WAKE_MISC_TWAM_IRQ_B TWAM_IRQ_B_LSB
+#define WAKE_MISC_PMSR_IRQ_B_SET0 PMSR_IRQ_B_SET0_LSB
+#define WAKE_MISC_PMSR_IRQ_B_SET1 PMSR_IRQ_B_SET1_LSB
+#define WAKE_MISC_PMSR_IRQ_B_SET2 PMSR_IRQ_B_SET2_LSB
+#define WAKE_MISC_SPM_ACK_CHK_WAKEUP_0 SPM_ACK_CHK_WAKEUP_0_LSB
+#define WAKE_MISC_SPM_ACK_CHK_WAKEUP_1 SPM_ACK_CHK_WAKEUP_1_LSB
+#define WAKE_MISC_SPM_ACK_CHK_WAKEUP_2 SPM_ACK_CHK_WAKEUP_2_LSB
+#define WAKE_MISC_SPM_ACK_CHK_WAKEUP_3 SPM_ACK_CHK_WAKEUP_3_LSB
+#define WAKE_MISC_SPM_ACK_CHK_WAKEUP_ALL SPM_ACK_CHK_WAKEUP_ALL_LSB
+#define WAKE_MISC_PMIC_IRQ_ACK PMIC_IRQ_ACK_LSB
+#define WAKE_MISC_PMIC_SCP_IRQ PMIC_SCP_IRQ_LSB
+
+/* ABORT MASK for DEBUG FOORTPRINT */
+#define DEBUG_ABORT_MASK \
+ (SPM_DBG_DEBUG_IDX_DRAM_SREF_ABORT_IN_APSRC | \
+ SPM_DBG_DEBUG_IDX_DRAM_SREF_ABORT_IN_DDREN)
+
+#define DEBUG_ABORT_MASK_1 \
+ (SPM_DBG1_DEBUG_IDX_VRCXO_SLEEP_ABORT | \
+ SPM_DBG1_DEBUG_IDX_PWRAP_SLEEP_ACK_LOW_ABORT | \
+ SPM_DBG1_DEBUG_IDX_PWRAP_SLEEP_ACK_HIGH_ABORT | \
+ SPM_DBG1_DEBUG_IDX_EMI_SLP_IDLE_ABORT | \
+ SPM_DBG1_DEBUG_IDX_SCP_SLP_ACK_LOW_ABORT | \
+ SPM_DBG1_DEBUG_IDX_SCP_SLP_ACK_HIGH_ABORT | \
+ SPM_DBG1_DEBUG_IDX_SPM_DVFS_CMD_RDY_ABORT)
+
+#define MCUPM_MBOX_WAKEUP_CPU 0x0C55FD10
+
+struct pwr_ctrl {
+ uint32_t pcm_flags;
+ uint32_t pcm_flags_cust;
+ uint32_t pcm_flags_cust_set;
+ uint32_t pcm_flags_cust_clr;
+ uint32_t pcm_flags1;
+ uint32_t pcm_flags1_cust;
+ uint32_t pcm_flags1_cust_set;
+ uint32_t pcm_flags1_cust_clr;
+ uint32_t timer_val;
+ uint32_t timer_val_cust;
+ uint32_t timer_val_ramp_en;
+ uint32_t timer_val_ramp_en_sec;
+ uint32_t wake_src;
+ uint32_t wake_src_cust;
+ uint8_t wdt_disable;
+
+ /* SPM_AP_STANDBY_CON */
+ uint8_t reg_wfi_op;
+ uint8_t reg_wfi_type;
+ uint8_t reg_mp0_cputop_idle_mask;
+ uint8_t reg_mp1_cputop_idle_mask;
+ uint8_t reg_mcusys_idle_mask;
+ uint8_t reg_md_apsrc_1_sel;
+ uint8_t reg_md_apsrc_0_sel;
+ uint8_t reg_conn_apsrc_sel;
+
+ /* SPM_SRC_REQ */
+ uint8_t reg_spm_apsrc_req;
+ uint8_t reg_spm_f26m_req;
+ uint8_t reg_spm_infra_req;
+ uint8_t reg_spm_vrf18_req;
+ uint8_t reg_spm_ddr_en_req;
+ uint8_t reg_spm_dvfs_req;
+ uint8_t reg_spm_sw_mailbox_req;
+ uint8_t reg_spm_sspm_mailbox_req;
+ uint8_t reg_spm_adsp_mailbox_req;
+ uint8_t reg_spm_scp_mailbox_req;
+
+ /* SPM_SRC_MASK */
+ uint8_t reg_sspm_srcclkena_0_mask_b;
+ uint8_t reg_sspm_infra_req_0_mask_b;
+ uint8_t reg_sspm_apsrc_req_0_mask_b;
+ uint8_t reg_sspm_vrf18_req_0_mask_b;
+ uint8_t reg_sspm_ddr_en_0_mask_b;
+ uint8_t reg_scp_srcclkena_mask_b;
+ uint8_t reg_scp_infra_req_mask_b;
+ uint8_t reg_scp_apsrc_req_mask_b;
+ uint8_t reg_scp_vrf18_req_mask_b;
+ uint8_t reg_scp_ddr_en_mask_b;
+ uint8_t reg_audio_dsp_srcclkena_mask_b;
+ uint8_t reg_audio_dsp_infra_req_mask_b;
+ uint8_t reg_audio_dsp_apsrc_req_mask_b;
+ uint8_t reg_audio_dsp_vrf18_req_mask_b;
+ uint8_t reg_audio_dsp_ddr_en_mask_b;
+ uint8_t reg_apu_srcclkena_mask_b;
+ uint8_t reg_apu_infra_req_mask_b;
+ uint8_t reg_apu_apsrc_req_mask_b;
+ uint8_t reg_apu_vrf18_req_mask_b;
+ uint8_t reg_apu_ddr_en_mask_b;
+ uint8_t reg_cpueb_srcclkena_mask_b;
+ uint8_t reg_cpueb_infra_req_mask_b;
+ uint8_t reg_cpueb_apsrc_req_mask_b;
+ uint8_t reg_cpueb_vrf18_req_mask_b;
+ uint8_t reg_cpueb_ddr_en_mask_b;
+ uint8_t reg_bak_psri_srcclkena_mask_b;
+ uint8_t reg_bak_psri_infra_req_mask_b;
+ uint8_t reg_bak_psri_apsrc_req_mask_b;
+ uint8_t reg_bak_psri_vrf18_req_mask_b;
+ uint8_t reg_bak_psri_ddr_en_mask_b;
+
+ /* SPM_SRC2_MASK */
+ uint8_t reg_msdc0_srcclkena_mask_b;
+ uint8_t reg_msdc0_infra_req_mask_b;
+ uint8_t reg_msdc0_apsrc_req_mask_b;
+ uint8_t reg_msdc0_vrf18_req_mask_b;
+ uint8_t reg_msdc0_ddr_en_mask_b;
+ uint8_t reg_msdc1_srcclkena_mask_b;
+ uint8_t reg_msdc1_infra_req_mask_b;
+ uint8_t reg_msdc1_apsrc_req_mask_b;
+ uint8_t reg_msdc1_vrf18_req_mask_b;
+ uint8_t reg_msdc1_ddr_en_mask_b;
+ uint8_t reg_msdc2_srcclkena_mask_b;
+ uint8_t reg_msdc2_infra_req_mask_b;
+ uint8_t reg_msdc2_apsrc_req_mask_b;
+ uint8_t reg_msdc2_vrf18_req_mask_b;
+ uint8_t reg_msdc2_ddr_en_mask_b;
+ uint8_t reg_ufs_srcclkena_mask_b;
+ uint8_t reg_ufs_infra_req_mask_b;
+ uint8_t reg_ufs_apsrc_req_mask_b;
+ uint8_t reg_ufs_vrf18_req_mask_b;
+ uint8_t reg_ufs_ddr_en_mask_b;
+ uint8_t reg_usb_srcclkena_mask_b;
+ uint8_t reg_usb_infra_req_mask_b;
+ uint8_t reg_usb_apsrc_req_mask_b;
+ uint8_t reg_usb_vrf18_req_mask_b;
+ uint8_t reg_usb_ddr_en_mask_b;
+ uint8_t reg_pextp_p0_srcclkena_mask_b;
+ uint8_t reg_pextp_p0_infra_req_mask_b;
+ uint8_t reg_pextp_p0_apsrc_req_mask_b;
+ uint8_t reg_pextp_p0_vrf18_req_mask_b;
+ uint8_t reg_pextp_p0_ddr_en_mask_b;
+
+ /* SPM_SRC3_MASK */
+ uint8_t reg_pextp_p1_srcclkena_mask_b;
+ uint8_t reg_pextp_p1_infra_req_mask_b;
+ uint8_t reg_pextp_p1_apsrc_req_mask_b;
+ uint8_t reg_pextp_p1_vrf18_req_mask_b;
+ uint8_t reg_pextp_p1_ddr_en_mask_b;
+ uint8_t reg_gce0_infra_req_mask_b;
+ uint8_t reg_gce0_apsrc_req_mask_b;
+ uint8_t reg_gce0_vrf18_req_mask_b;
+ uint8_t reg_gce0_ddr_en_mask_b;
+ uint8_t reg_gce1_infra_req_mask_b;
+ uint8_t reg_gce1_apsrc_req_mask_b;
+ uint8_t reg_gce1_vrf18_req_mask_b;
+ uint8_t reg_gce1_ddr_en_mask_b;
+ uint8_t reg_spm_srcclkena_reserved_mask_b;
+ uint8_t reg_spm_infra_req_reserved_mask_b;
+ uint8_t reg_spm_apsrc_req_reserved_mask_b;
+ uint8_t reg_spm_vrf18_req_reserved_mask_b;
+ uint8_t reg_spm_ddr_en_reserved_mask_b;
+ uint8_t reg_disp0_apsrc_req_mask_b;
+ uint8_t reg_disp0_ddr_en_mask_b;
+ uint8_t reg_disp1_apsrc_req_mask_b;
+ uint8_t reg_disp1_ddr_en_mask_b;
+ uint8_t reg_disp2_apsrc_req_mask_b;
+ uint8_t reg_disp2_ddr_en_mask_b;
+ uint8_t reg_disp3_apsrc_req_mask_b;
+ uint8_t reg_disp3_ddr_en_mask_b;
+ uint8_t reg_infrasys_apsrc_req_mask_b;
+ uint8_t reg_infrasys_ddr_en_mask_b;
+ uint8_t reg_cg_check_srcclkena_mask_b;
+ uint8_t reg_cg_check_apsrc_req_mask_b;
+ uint8_t reg_cg_check_vrf18_req_mask_b;
+ uint8_t reg_cg_check_ddr_en_mask_b;
+
+ /* SPM_SRC4_MASK */
+ uint32_t reg_mcusys_merge_apsrc_req_mask_b;
+ uint32_t reg_mcusys_merge_ddr_en_mask_b;
+ uint8_t reg_dramc_md32_infra_req_mask_b;
+ uint8_t reg_dramc_md32_vrf18_req_mask_b;
+ uint8_t reg_dramc_md32_ddr_en_mask_b;
+ uint8_t reg_dvfsrc_event_trigger_mask_b;
+
+ /* SPM_WAKEUP_EVENT_MASK2 */
+ uint8_t reg_sc_sw2spm_wakeup_mask_b;
+ uint8_t reg_sc_adsp2spm_wakeup_mask_b;
+ uint8_t reg_sc_sspm2spm_wakeup_mask_b;
+ uint8_t reg_sc_scp2spm_wakeup_mask_b;
+ uint8_t reg_csyspwrup_ack_mask;
+ uint8_t reg_csyspwrup_req_mask;
+
+ /* SPM_WAKEUP_EVENT_MASK */
+ uint32_t reg_wakeup_event_mask;
+
+ /* SPM_WAKEUP_EVENT_EXT_MASK */
+ uint32_t reg_ext_wakeup_event_mask;
+};
+
+/* code gen by spm_pwr_ctrl_atf.pl, need struct pwr_ctrl */
+enum pwr_ctrl_enum {
+ PW_PCM_FLAGS,
+ PW_PCM_FLAGS_CUST,
+ PW_PCM_FLAGS_CUST_SET,
+ PW_PCM_FLAGS_CUST_CLR,
+ PW_PCM_FLAGS1,
+ PW_PCM_FLAGS1_CUST,
+ PW_PCM_FLAGS1_CUST_SET,
+ PW_PCM_FLAGS1_CUST_CLR,
+ PW_TIMER_VAL,
+ PW_TIMER_VAL_CUST,
+ PW_TIMER_VAL_RAMP_EN,
+ PW_TIMER_VAL_RAMP_EN_SEC,
+ PW_WAKE_SRC,
+ PW_WAKE_SRC_CUST,
+ PW_WAKELOCK_TIMER_VAL,
+ PW_WDT_DISABLE,
+
+ /* SPM_CLK_CON */
+ PW_REG_SRCCLKEN0_CTL,
+ PW_REG_SRCCLKEN1_CTL,
+ PW_REG_SPM_LOCK_INFRA_DCM,
+ PW_REG_SRCCLKEN_MASK,
+ PW_REG_MD1_C32RM_EN,
+ PW_REG_MD2_C32RM_EN,
+ PW_REG_CLKSQ0_SEL_CTRL,
+ PW_REG_CLKSQ1_SEL_CTRL,
+ PW_REG_SRCCLKEN0_EN,
+ PW_REG_SRCCLKEN1_EN,
+ PW_REG_SYSCLK0_SRC_MASK_B,
+ PW_REG_SYSCLK1_SRC_MASK_B,
+
+ /* SPM_AP_STANDBY_CON */
+ PW_REG_WFI_OP,
+ PW_REG_WFI_TYPE,
+ PW_REG_MP0_CPUTOP_IDLE_MASK,
+ PW_REG_MP1_CPUTOP_IDLE_MASK,
+ PW_REG_MCUSYS_IDLE_MASK,
+ PW_REG_MD_APSRC_1_SEL,
+ PW_REG_MD_APSRC_0_SEL,
+ PW_REG_CONN_APSRC_SEL,
+
+ /* SPM_SRC_REQ */
+ PW_REG_SPM_APSRC_REQ,
+ PW_REG_SPM_F26M_REQ,
+ PW_REG_SPM_INFRA_REQ,
+ PW_REG_SPM_VRF18_REQ,
+ PW_REG_SPM_DDR_EN_REQ,
+ PW_REG_SPM_DVFS_REQ,
+ PW_REG_SPM_SW_MAILBOX_REQ,
+ PW_REG_SPM_SSPM_MAILBOX_REQ,
+ PW_REG_SPM_ADSP_MAILBOX_REQ,
+ PW_REG_SPM_SCP_MAILBOX_REQ,
+
+ /* SPM_SRC_MASK */
+ PW_REG_MD_SRCCLKENA_0_MASK_B,
+ PW_REG_MD_SRCCLKENA2INFRA_REQ_0_MASK_B,
+ PW_REG_MD_APSRC2INFRA_REQ_0_MASK_B,
+ PW_REG_MD_APSRC_REQ_0_MASK_B,
+ PW_REG_MD_VRF18_REQ_0_MASK_B,
+ PW_REG_MD_DDR_EN_0_MASK_B,
+ PW_REG_MD_SRCCLKENA_1_MASK_B,
+ PW_REG_MD_SRCCLKENA2INFRA_REQ_1_MASK_B,
+ PW_REG_MD_APSRC2INFRA_REQ_1_MASK_B,
+ PW_REG_MD_APSRC_REQ_1_MASK_B,
+ PW_REG_MD_VRF18_REQ_1_MASK_B,
+ PW_REG_MD_DDR_EN_1_MASK_B,
+ PW_REG_CONN_SRCCLKENA_MASK_B,
+ PW_REG_CONN_SRCCLKENB_MASK_B,
+ PW_REG_CONN_INFRA_REQ_MASK_B,
+ PW_REG_CONN_APSRC_REQ_MASK_B,
+ PW_REG_CONN_VRF18_REQ_MASK_B,
+ PW_REG_CONN_DDR_EN_MASK_B,
+ PW_REG_CONN_VFE28_MASK_B,
+ PW_REG_SRCCLKENI0_SRCCLKENA_MASK_B,
+ PW_REG_SRCCLKENI0_INFRA_REQ_MASK_B,
+ PW_REG_SRCCLKENI1_SRCCLKENA_MASK_B,
+ PW_REG_SRCCLKENI1_INFRA_REQ_MASK_B,
+ PW_REG_SRCCLKENI2_SRCCLKENA_MASK_B,
+ PW_REG_SRCCLKENI2_INFRA_REQ_MASK_B,
+ PW_REG_INFRASYS_APSRC_REQ_MASK_B,
+ PW_REG_INFRASYS_DDR_EN_MASK_B,
+ PW_REG_MD32_SRCCLKENA_MASK_B,
+ PW_REG_MD32_INFRA_REQ_MASK_B,
+ PW_REG_MD32_APSRC_REQ_MASK_B,
+ PW_REG_MD32_VRF18_REQ_MASK_B,
+ PW_REG_MD32_DDR_EN_MASK_B,
+
+ /* SPM_SRC2_MASK */
+ PW_REG_SCP_SRCCLKENA_MASK_B,
+ PW_REG_SCP_INFRA_REQ_MASK_B,
+ PW_REG_SCP_APSRC_REQ_MASK_B,
+ PW_REG_SCP_VRF18_REQ_MASK_B,
+ PW_REG_SCP_DDR_EN_MASK_B,
+ PW_REG_AUDIO_DSP_SRCCLKENA_MASK_B,
+ PW_REG_AUDIO_DSP_INFRA_REQ_MASK_B,
+ PW_REG_AUDIO_DSP_APSRC_REQ_MASK_B,
+ PW_REG_AUDIO_DSP_VRF18_REQ_MASK_B,
+ PW_REG_AUDIO_DSP_DDR_EN_MASK_B,
+ PW_REG_UFS_SRCCLKENA_MASK_B,
+ PW_REG_UFS_INFRA_REQ_MASK_B,
+ PW_REG_UFS_APSRC_REQ_MASK_B,
+ PW_REG_UFS_VRF18_REQ_MASK_B,
+ PW_REG_UFS_DDR_EN_MASK_B,
+ PW_REG_DISP0_APSRC_REQ_MASK_B,
+ PW_REG_DISP0_DDR_EN_MASK_B,
+ PW_REG_DISP1_APSRC_REQ_MASK_B,
+ PW_REG_DISP1_DDR_EN_MASK_B,
+ PW_REG_GCE_INFRA_REQ_MASK_B,
+ PW_REG_GCE_APSRC_REQ_MASK_B,
+ PW_REG_GCE_VRF18_REQ_MASK_B,
+ PW_REG_GCE_DDR_EN_MASK_B,
+ PW_REG_APU_SRCCLKENA_MASK_B,
+ PW_REG_APU_INFRA_REQ_MASK_B,
+ PW_REG_APU_APSRC_REQ_MASK_B,
+ PW_REG_APU_VRF18_REQ_MASK_B,
+ PW_REG_APU_DDR_EN_MASK_B,
+ PW_REG_CG_CHECK_SRCCLKENA_MASK_B,
+ PW_REG_CG_CHECK_APSRC_REQ_MASK_B,
+ PW_REG_CG_CHECK_VRF18_REQ_MASK_B,
+ PW_REG_CG_CHECK_DDR_EN_MASK_B,
+
+ /* SPM_SRC3_MASK */
+ PW_REG_DVFSRC_EVENT_TRIGGER_MASK_B,
+ PW_REG_SW2SPM_INT0_MASK_B,
+ PW_REG_SW2SPM_INT1_MASK_B,
+ PW_REG_SW2SPM_INT2_MASK_B,
+ PW_REG_SW2SPM_INT3_MASK_B,
+ PW_REG_SC_ADSP2SPM_WAKEUP_MASK_B,
+ PW_REG_SC_SSPM2SPM_WAKEUP_MASK_B,
+ PW_REG_SC_SCP2SPM_WAKEUP_MASK_B,
+ PW_REG_CSYSPWRREQ_MASK,
+ PW_REG_SPM_SRCCLKENA_RESERVED_MASK_B,
+ PW_REG_SPM_INFRA_REQ_RESERVED_MASK_B,
+ PW_REG_SPM_APSRC_REQ_RESERVED_MASK_B,
+ PW_REG_SPM_VRF18_REQ_RESERVED_MASK_B,
+ PW_REG_SPM_DDR_EN_RESERVED_MASK_B,
+ PW_REG_MCUPM_SRCCLKENA_MASK_B,
+ PW_REG_MCUPM_INFRA_REQ_MASK_B,
+ PW_REG_MCUPM_APSRC_REQ_MASK_B,
+ PW_REG_MCUPM_VRF18_REQ_MASK_B,
+ PW_REG_MCUPM_DDR_EN_MASK_B,
+ PW_REG_MSDC0_SRCCLKENA_MASK_B,
+ PW_REG_MSDC0_INFRA_REQ_MASK_B,
+ PW_REG_MSDC0_APSRC_REQ_MASK_B,
+ PW_REG_MSDC0_VRF18_REQ_MASK_B,
+ PW_REG_MSDC0_DDR_EN_MASK_B,
+ PW_REG_MSDC1_SRCCLKENA_MASK_B,
+ PW_REG_MSDC1_INFRA_REQ_MASK_B,
+ PW_REG_MSDC1_APSRC_REQ_MASK_B,
+ PW_REG_MSDC1_VRF18_REQ_MASK_B,
+ PW_REG_MSDC1_DDR_EN_MASK_B,
+
+ /* SPM_SRC4_MASK */
+ PW_CCIF_EVENT_MASK_B,
+ PW_REG_BAK_PSRI_SRCCLKENA_MASK_B,
+ PW_REG_BAK_PSRI_INFRA_REQ_MASK_B,
+ PW_REG_BAK_PSRI_APSRC_REQ_MASK_B,
+ PW_REG_BAK_PSRI_VRF18_REQ_MASK_B,
+ PW_REG_BAK_PSRI_DDR_EN_MASK_B,
+ PW_REG_DRAMC0_MD32_INFRA_REQ_MASK_B,
+ PW_REG_DRAMC0_MD32_VRF18_REQ_MASK_B,
+ PW_REG_DRAMC1_MD32_INFRA_REQ_MASK_B,
+ PW_REG_DRAMC1_MD32_VRF18_REQ_MASK_B,
+ PW_REG_CONN_SRCCLKENB2PWRAP_MASK_B,
+ PW_REG_DRAMC0_MD32_WAKEUP_MASK,
+ PW_REG_DRAMC1_MD32_WAKEUP_MASK,
+
+ /* SPM_SRC5_MASK */
+ PW_REG_MCUSYS_MERGE_APSRC_REQ_MASK_B,
+ PW_REG_MCUSYS_MERGE_DDR_EN_MASK_B,
+
+ /* SPM_WAKEUP_EVENT_MASK */
+ PW_REG_WAKEUP_EVENT_MASK,
+
+ /* SPM_WAKEUP_EVENT_EXT_MASK */
+ PW_REG_EXT_WAKEUP_EVENT_MASK,
+
+ PW_MAX_COUNT,
+};
+
+#define SPM_INTERNAL_STATUS_HW_S1 (1U << 0)
+#define SPM_ACK_CHK_3_SEL_HW_S1 0x00350098
+#define SPM_ACK_CHK_3_HW_S1_CNT 1
+#define SPM_ACK_CHK_3_CON_HW_MODE_TRIG 0x800
+#define SPM_ACK_CHK_3_CON_EN 0x110
+#define SPM_ACK_CHK_3_CON_CLR_ALL 0x2
+#define SPM_ACK_CHK_3_CON_RESULT 0x8000
+
+struct wake_status_trace_comm {
+ uint32_t debug_flag; /* PCM_WDT_LATCH_SPARE_0 */
+ uint32_t debug_flag1; /* PCM_WDT_LATCH_SPARE_1 */
+ uint32_t timer_out; /* SPM_BK_PCM_TIMER */
+ uint32_t b_sw_flag0; /* SPM_SW_RSV_7 */
+ uint32_t b_sw_flag1; /* SPM_SW_RSV_8 */
+ uint32_t r12; /* SPM_SW_RSV_0 */
+ uint32_t r13; /* PCM_REG13_DATA */
+ uint32_t req_sta0; /* SRC_REQ_STA_0 */
+ uint32_t req_sta1; /* SRC_REQ_STA_1 */
+ uint32_t req_sta2; /* SRC_REQ_STA_2 */
+ uint32_t req_sta3; /* SRC_REQ_STA_3 */
+ uint32_t req_sta4; /* SRC_REQ_STA_4 */
+ uint32_t raw_sta; /* SPM_WAKEUP_STA */
+ uint32_t times_h; /* timestamp high bits */
+ uint32_t times_l; /* timestamp low bits */
+ uint32_t resumetime; /* timestamp low bits */
+};
+
+struct wake_status_trace {
+ struct wake_status_trace_comm comm;
+};
+
+struct wake_status {
+ struct wake_status_trace tr;
+ uint32_t r12; /* SPM_BK_WAKE_EVENT */
+ uint32_t r12_ext; /* SPM_WAKEUP_STA */
+ uint32_t raw_sta; /* SPM_WAKEUP_STA */
+ uint32_t raw_ext_sta; /* SPM_WAKEUP_EXT_STA */
+ uint32_t md32pcm_wakeup_sta; /* MD32PCM_WAKEUP_STA */
+ uint32_t md32pcm_event_sta; /* MD32PCM_EVENT_STA */
+ uint32_t src_req; /* SPM_SRC_REQ */
+ uint32_t wake_misc; /* SPM_BK_WAKE_MISC */
+ uint32_t timer_out; /* SPM_BK_PCM_TIMER */
+ uint32_t r13; /* PCM_REG13_DATA */
+ uint32_t idle_sta; /* SUBSYS_IDLE_STA */
+ uint32_t req_sta0; /* SRC_REQ_STA_0 */
+ uint32_t req_sta1; /* SRC_REQ_STA_1 */
+ uint32_t req_sta2; /* SRC_REQ_STA_2 */
+ uint32_t req_sta3; /* SRC_REQ_STA_3 */
+ uint32_t req_sta4; /* SRC_REQ_STA_4 */
+ uint32_t cg_check_sta; /* SPM_CG_CHECK_STA */
+ uint32_t debug_flag; /* PCM_WDT_LATCH_SPARE_0 */
+ uint32_t debug_flag1; /* PCM_WDT_LATCH_SPARE_1 */
+ uint32_t b_sw_flag0; /* SPM_SW_RSV_7 */
+ uint32_t b_sw_flag1; /* SPM_SW_RSV_8 */
+ uint32_t rt_req_sta0; /* SPM_SW_RSV_2 */
+ uint32_t rt_req_sta1; /* SPM_SW_RSV_3 */
+ uint32_t rt_req_sta2; /* SPM_SW_RSV_4 */
+ uint32_t rt_req_sta3; /* SPM_SW_RSV_5 */
+ uint32_t rt_req_sta4; /* SPM_SW_RSV_6 */
+ uint32_t isr; /* SPM_IRQ_STA */
+ uint32_t sw_flag0; /* SPM_SW_FLAG_0 */
+ uint32_t sw_flag1; /* SPM_SW_FLAG_1 */
+ uint32_t clk_settle; /* SPM_CLK_SETTLE */
+ uint32_t abort;
+};
+
+struct spm_lp_scen {
+ struct pcm_desc *pcmdesc;
+ struct pwr_ctrl *pwrctrl;
+};
+
+extern struct spm_lp_scen __spm_vcorefs;
+extern void __spm_set_cpu_status(unsigned int cpu);
+extern void __spm_reset_and_init_pcm(const struct pcm_desc *pcmdesc);
+extern void __spm_kick_im_to_fetch(const struct pcm_desc *pcmdesc);
+extern void __spm_init_pcm_register(void);
+extern void __spm_src_req_update(const struct pwr_ctrl *pwrctrl,
+ unsigned int resource_usage);
+extern void __spm_set_power_control(const struct pwr_ctrl *pwrctrl);
+extern void __spm_disable_pcm_timer(void);
+extern void __spm_set_wakeup_event(const struct pwr_ctrl *pwrctrl);
+extern void __spm_kick_pcm_to_run(struct pwr_ctrl *pwrctrl);
+extern void __spm_set_pcm_flags(struct pwr_ctrl *pwrctrl);
+extern void __spm_send_cpu_wakeup_event(void);
+extern void __spm_get_wakeup_status(struct wake_status *wakesta,
+ unsigned int ext_status);
+extern void __spm_clean_after_wakeup(void);
+extern wake_reason_t
+__spm_output_wake_reason(int state_id, const struct wake_status *wakesta);
+extern void
+__spm_sync_vcore_dvfs_power_control(struct pwr_ctrl *dest_pwr_ctrl,
+ const struct pwr_ctrl *src_pwr_ctrl);
+extern void __spm_set_pcm_wdt(int en);
+extern uint32_t _spm_get_wake_period(int pwake_time, wake_reason_t last_wr);
+extern void __spm_set_fw_resume_option(struct pwr_ctrl *pwrctrl);
+extern void __spm_ext_int_wakeup_req_clr(void);
+extern void __spm_xo_soc_bblpm(int en);
+
+static inline void set_pwrctrl_pcm_flags(struct pwr_ctrl *pwrctrl,
+ uint32_t flags)
+{
+ if (pwrctrl->pcm_flags_cust == 0U) {
+ pwrctrl->pcm_flags = flags;
+ } else {
+ pwrctrl->pcm_flags = pwrctrl->pcm_flags_cust;
+ }
+}
+
+static inline void set_pwrctrl_pcm_flags1(struct pwr_ctrl *pwrctrl,
+ uint32_t flags)
+{
+ if (pwrctrl->pcm_flags1_cust == 0U) {
+ pwrctrl->pcm_flags1 = flags;
+ } else {
+ pwrctrl->pcm_flags1 = pwrctrl->pcm_flags1_cust;
+ }
+}
+
+extern void __spm_hw_s1_state_monitor(int en, unsigned int *status);
+
+static inline void spm_hw_s1_state_monitor_resume(void)
+{
+ __spm_hw_s1_state_monitor(1, NULL);
+}
+
+static inline void spm_hw_s1_state_monitor_pause(unsigned int *status)
+{
+ __spm_hw_s1_state_monitor(0, status);
+}
+#endif /* MT_SPM_INTERNAL_H */
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm_pmic_wrap.c b/plat/mediatek/mt8195/drivers/spm/mt_spm_pmic_wrap.c
new file mode 100644
index 0000000..9da644c
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm_pmic_wrap.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <mt_spm.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_pmic_wrap.h>
+#include <mt_spm_reg.h>
+#include <plat_pm.h>
+#include <platform_def.h>
+
+/* PMIC_WRAP MT6359 */
+#define VCORE_BASE_UV 40000
+#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 NR_PMIC_WRAP_CMD (NR_IDX_ALL)
+#define SPM_DATA_SHIFT 16
+
+#define BUCK_VGPU11_ELR0 0x15B4
+#define TOP_SPI_CON0 0x0456
+#define BUCK_TOP_CON1 0x1443
+#define TOP_CON 0x0013
+#define TOP_DIG_WPK 0x03a9
+#define TOP_CON_LOCK 0x03a8
+#define TOP_CLK_CON0 0x0134
+
+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, /* invalid setting for init */
+ .addr = { {0UL, 0UL} },
+ .set[PMIC_WRAP_PHASE_ALLINONE] = {
+ ._[CMD_0] = {BUCK_VGPU11_ELR0, VOLT_TO_PMIC_VAL(75000),},
+ ._[CMD_1] = {BUCK_VGPU11_ELR0, VOLT_TO_PMIC_VAL(65000),},
+ ._[CMD_2] = {BUCK_VGPU11_ELR0, VOLT_TO_PMIC_VAL(60000),},
+ ._[CMD_3] = {BUCK_VGPU11_ELR0, VOLT_TO_PMIC_VAL(55000),},
+ ._[CMD_4] = {TOP_SPI_CON0, 0x1,},
+ ._[CMD_5] = {TOP_SPI_CON0, 0x0,},
+ ._[CMD_6] = {BUCK_TOP_CON1, 0x0,},
+ ._[CMD_7] = {BUCK_TOP_CON1, 0xf,},
+ ._[CMD_8] = {TOP_CON, 0x3,},
+ ._[CMD_9] = {TOP_CON, 0x0,},
+ ._[CMD_10] = {TOP_DIG_WPK, 0x63,},
+ ._[CMD_11] = {TOP_CON_LOCK, 0x15,},
+ ._[CMD_12] = {TOP_DIG_WPK, 0x0,},
+ ._[CMD_13] = {TOP_CON_LOCK, 0x0,},
+ ._[CMD_14] = {TOP_CLK_CON0, 0x40,},
+ ._[CMD_15] = {TOP_CLK_CON0, 0x0,},
+ .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,},
+ };
+
+ 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 == 0UL) {
+ _mt_spm_pmic_table_init();
+ }
+
+ pw.phase = phase;
+ mmio_write_32(POWERON_CONFIG_EN, SPM_REGWR_CFG_KEY | BCLK_CG_EN_LSB);
+
+ for (idx = 0U; 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);
+
+ 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 0UL;
+ }
+
+ if (idx >= pw.set[phase].nr_idx) {
+ return 0UL;
+ }
+
+ return pw.set[phase]._[idx].cmd_wdata;
+}
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm_pmic_wrap.h b/plat/mediatek/mt8195/drivers/spm/mt_spm_pmic_wrap.h
new file mode 100644
index 0000000..53fdda2
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm_pmic_wrap.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/****************************************************************
+ * Auto generated by DE, please DO NOT modify this file directly.
+ *****************************************************************/
+#ifndef MT_SPM_PMIC_WRAP_H
+#define MT_SPM_PMIC_WRAP_H
+
+enum pmic_wrap_phase_id {
+ PMIC_WRAP_PHASE_ALLINONE,
+ NR_PMIC_WRAP_PHASE,
+};
+
+/* IDX mapping, PMIC_WRAP_PHASE_ALLINONE */
+enum {
+ CMD_0, /* 0x0 */
+ 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 */
+ NR_IDX_ALL,
+};
+
+/* APIs */
+extern void mt_spm_pmic_wrap_set_phase(enum pmic_wrap_phase_id phase);
+extern void mt_spm_pmic_wrap_set_cmd(enum pmic_wrap_phase_id phase,
+ uint32_t idx, uint32_t cmd_wdata);
+extern uint64_t mt_spm_pmic_wrap_get_cmd(enum pmic_wrap_phase_id phase,
+ uint32_t idx);
+#endif /* MT_SPM_PMIC_WRAP_H */
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm_reg.h b/plat/mediatek/mt8195/drivers/spm/mt_spm_reg.h
new file mode 100644
index 0000000..d8b9b29
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm_reg.h
@@ -0,0 +1,2859 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/****************************************************************
+ * Auto generated by DE, please DO NOT modify this file directly.
+ *****************************************************************/
+
+#ifndef MT_SPM_REG
+#define MT_SPM_REG
+
+#include "sleep_def.h"
+#include <platform_def.h>
+#include "pcm_def.h"
+
+/**************************************
+ * Define and Declare
+ **************************************/
+
+/*******Register_SPM_CFG*************************************************/
+#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 SPM_POWER_ON_VAL2 (SPM_BASE + 0x020)
+#define SPM_POWER_ON_VAL3 (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 SPM_SW_RST_CON (SPM_BASE + 0x040)
+#define SPM_SW_RST_CON_SET (SPM_BASE + 0x044)
+#define SPM_SW_RST_CON_CLR (SPM_BASE + 0x048)
+#define VS1_PSR_MASK_B (SPM_BASE + 0x04C)
+#define SPM_ARBITER_EN (SPM_BASE + 0x050)
+#define SCPSYS_CLK_CON (SPM_BASE + 0x054)
+#define SPM_SRAM_RSV_CON (SPM_BASE + 0x058)
+#define SPM_SWINT (SPM_BASE + 0x05C)
+#define SPM_SWINT_SET (SPM_BASE + 0x060)
+#define SPM_SWINT_CLR (SPM_BASE + 0x064)
+#define SPM_SCP_MAILBOX (SPM_BASE + 0x068)
+#define SCP_SPM_MAILBOX (SPM_BASE + 0x06C)
+#define SPM_SCP_IRQ (SPM_BASE + 0x070)
+#define SPM_CPU_WAKEUP_EVENT (SPM_BASE + 0x074)
+#define SPM_IRQ_MASK (SPM_BASE + 0x078)
+#define SPM_SRC_REQ (SPM_BASE + 0x080)
+#define SPM_SRC_MASK (SPM_BASE + 0x084)
+#define SPM_SRC2_MASK (SPM_BASE + 0x088)
+#define SPM_SRC3_MASK (SPM_BASE + 0x090)
+#define SPM_SRC4_MASK (SPM_BASE + 0x094)
+#define SPM_WAKEUP_EVENT_MASK2 (SPM_BASE + 0x098)
+#define SPM_WAKEUP_EVENT_MASK (SPM_BASE + 0x09C)
+#define SPM_WAKEUP_EVENT_SENS (SPM_BASE + 0x0A0)
+#define SPM_WAKEUP_EVENT_CLEAR (SPM_BASE + 0x0A4)
+#define SPM_WAKEUP_EVENT_EXT_MASK (SPM_BASE + 0x0A8)
+#define SCP_CLK_CON (SPM_BASE + 0x0AC)
+#define PCM_DEBUG_CON (SPM_BASE + 0x0B0)
+#define DDREN_DBC_CON (SPM_BASE + 0x0B4)
+#define SPM_RESOURCE_ACK_CON0 (SPM_BASE + 0x0B8)
+#define SPM_RESOURCE_ACK_CON1 (SPM_BASE + 0x0BC)
+#define SPM_RESOURCE_ACK_CON2 (SPM_BASE + 0x0C0)
+#define SPM_RESOURCE_ACK_CON3 (SPM_BASE + 0x0C4)
+#define SPM_RESOURCE_ACK_CON4 (SPM_BASE + 0x0C8)
+#define SPM_SRAM_CON (SPM_BASE + 0x0CC)
+/*******Register_SPM_STA*************************************************/
+#define PCM_REG0_DATA (SPM_BASE + 0x100)
+#define PCM_REG2_DATA (SPM_BASE + 0x104)
+#define PCM_REG6_DATA (SPM_BASE + 0x108)
+#define PCM_REG7_DATA (SPM_BASE + 0x10C)
+#define PCM_REG13_DATA (SPM_BASE + 0x110)
+#define SRC_REQ_STA_0 (SPM_BASE + 0x114)
+#define SRC_REQ_STA_1 (SPM_BASE + 0x118)
+#define SRC_REQ_STA_2 (SPM_BASE + 0x120)
+#define SRC_REQ_STA_3 (SPM_BASE + 0x124)
+#define SRC_REQ_STA_4 (SPM_BASE + 0x128)
+#define PCM_TIMER_OUT (SPM_BASE + 0x130)
+#define PCM_WDT_OUT (SPM_BASE + 0x134)
+#define SPM_IRQ_STA (SPM_BASE + 0x138)
+#define MD32PCM_WAKEUP_STA (SPM_BASE + 0x13C)
+#define MD32PCM_EVENT_STA (SPM_BASE + 0x140)
+#define SPM_WAKEUP_STA (SPM_BASE + 0x144)
+#define SPM_WAKEUP_EXT_STA (SPM_BASE + 0x148)
+#define SPM_WAKEUP_MISC (SPM_BASE + 0x14C)
+#define MM_DVFS_HALT (SPM_BASE + 0x150)
+#define SUBSYS_IDLE_STA (SPM_BASE + 0x164)
+#define PCM_STA (SPM_BASE + 0x168)
+#define PWR_STATUS (SPM_BASE + 0x16C)
+#define PWR_STATUS_2ND (SPM_BASE + 0x170)
+#define CPU_PWR_STATUS (SPM_BASE + 0x174)
+#define CPU_PWR_STATUS_2ND (SPM_BASE + 0x178)
+#define SPM_VTCXO_EVENT_COUNT_STA (SPM_BASE + 0x17C)
+#define SPM_INFRA_EVENT_COUNT_STA (SPM_BASE + 0x180)
+#define SPM_VRF18_EVENT_COUNT_STA (SPM_BASE + 0x184)
+#define SPM_APSRC_EVENT_COUNT_STA (SPM_BASE + 0x188)
+#define SPM_DDREN_EVENT_COUNT_STA (SPM_BASE + 0x18C)
+#define MD32PCM_STA (SPM_BASE + 0x190)
+#define MD32PCM_PC (SPM_BASE + 0x194)
+#define OTHER_PWR_STATUS (SPM_BASE + 0x198)
+#define DVFSRC_EVENT_STA (SPM_BASE + 0x19C)
+#define BUS_PROTECT_RDY (SPM_BASE + 0x1A0)
+#define BUS_PROTECT1_RDY (SPM_BASE + 0x1A4)
+#define BUS_PROTECT2_RDY (SPM_BASE + 0x1A8)
+#define BUS_PROTECT3_RDY (SPM_BASE + 0x1AC)
+#define BUS_PROTECT4_RDY (SPM_BASE + 0x1B0)
+#define BUS_PROTECT5_RDY (SPM_BASE + 0x1B4)
+#define BUS_PROTECT6_RDY (SPM_BASE + 0x1B8)
+#define BUS_PROTECT7_RDY (SPM_BASE + 0x1BC)
+#define BUS_PROTECT8_RDY (SPM_BASE + 0x1C0)
+#define BUS_PROTECT9_RDY (SPM_BASE + 0x1C4)
+#define SPM_TWAM_LAST_STA0 (SPM_BASE + 0x1D0)
+#define SPM_TWAM_LAST_STA1 (SPM_BASE + 0x1D4)
+#define SPM_TWAM_LAST_STA2 (SPM_BASE + 0x1D8)
+#define SPM_TWAM_LAST_STA3 (SPM_BASE + 0x1DC)
+#define SPM_TWAM_CURR_STA0 (SPM_BASE + 0x1E0)
+#define SPM_TWAM_CURR_STA1 (SPM_BASE + 0x1E4)
+#define SPM_TWAM_CURR_STA2 (SPM_BASE + 0x1E8)
+#define SPM_TWAM_CURR_STA3 (SPM_BASE + 0x1EC)
+#define SPM_TWAM_TIMER_OUT (SPM_BASE + 0x1F0)
+#define SPM_CG_CHECK_STA (SPM_BASE + 0x1F4)
+#define SPM_DVFS_STA (SPM_BASE + 0x1F8)
+#define SPM_DVFS_OPP_STA (SPM_BASE + 0x1FC)
+/*******Register_CPU_MT*************************************************/
+#define CPUEB_PWR_CON (SPM_BASE + 0x200)
+#define SPM_MCUSYS_PWR_CON (SPM_BASE + 0x204)
+#define SPM_CPUTOP_PWR_CON (SPM_BASE + 0x208)
+#define SPM_CPU0_PWR_CON (SPM_BASE + 0x20C)
+#define SPM_CPU1_PWR_CON (SPM_BASE + 0x210)
+#define SPM_CPU2_PWR_CON (SPM_BASE + 0x214)
+#define SPM_CPU3_PWR_CON (SPM_BASE + 0x218)
+#define SPM_CPU4_PWR_CON (SPM_BASE + 0x21C)
+#define SPM_CPU5_PWR_CON (SPM_BASE + 0x220)
+#define SPM_CPU6_PWR_CON (SPM_BASE + 0x224)
+#define SPM_CPU7_PWR_CON (SPM_BASE + 0x228)
+#define ARMPLL_CLK_CON (SPM_BASE + 0x22C)
+#define MCUSYS_IDLE_STA (SPM_BASE + 0x230)
+#define GIC_WAKEUP_STA (SPM_BASE + 0x234)
+#define CPU_SPARE_CON (SPM_BASE + 0x238)
+#define CPU_SPARE_CON_SET (SPM_BASE + 0x23C)
+#define CPU_SPARE_CON_CLR (SPM_BASE + 0x240)
+#define ARMPLL_CLK_SEL (SPM_BASE + 0x244)
+#define EXT_INT_WAKEUP_REQ (SPM_BASE + 0x248)
+#define EXT_INT_WAKEUP_REQ_SET (SPM_BASE + 0x24C)
+#define EXT_INT_WAKEUP_REQ_CLR (SPM_BASE + 0x250)
+#define CPU0_IRQ_MASK (SPM_BASE + 0x260)
+#define CPU_IRQ_MASK_SET (SPM_BASE + 0x264)
+#define CPU_IRQ_MASK_CLR (SPM_BASE + 0x268)
+#define CPU_WFI_EN (SPM_BASE + 0x280)
+#define CPU_WFI_EN_SET (SPM_BASE + 0x284)
+#define CPU_WFI_EN_CLR (SPM_BASE + 0x288)
+#define SYSRAM_CON (SPM_BASE + 0x290)
+#define SYSROM_CON (SPM_BASE + 0x294)
+#define ROOT_CPUTOP_ADDR (SPM_BASE + 0x2A0)
+#define ROOT_CORE_ADDR (SPM_BASE + 0x2A4)
+#define SPM2SW_MAILBOX_0 (SPM_BASE + 0x2D0)
+#define SPM2SW_MAILBOX_1 (SPM_BASE + 0x2D4)
+#define SPM2SW_MAILBOX_2 (SPM_BASE + 0x2D8)
+#define SPM2SW_MAILBOX_3 (SPM_BASE + 0x2DC)
+#define SW2SPM_INT (SPM_BASE + 0x2E0)
+#define SW2SPM_INT_SET (SPM_BASE + 0x2E4)
+#define SW2SPM_INT_CLR (SPM_BASE + 0x2E8)
+#define SW2SPM_MAILBOX_0 (SPM_BASE + 0x2EC)
+#define SW2SPM_MAILBOX_1 (SPM_BASE + 0x2F0)
+#define SW2SPM_MAILBOX_2 (SPM_BASE + 0x2F4)
+#define SW2SPM_MAILBOX_3 (SPM_BASE + 0x2F8)
+#define SW2SPM_CFG (SPM_BASE + 0x2FC)
+/*******Register_NONCPU_MT*************************************************/
+#define MFG0_PWR_CON (SPM_BASE + 0x300)
+#define MFG1_PWR_CON (SPM_BASE + 0x304)
+#define MFG2_PWR_CON (SPM_BASE + 0x308)
+#define MFG3_PWR_CON (SPM_BASE + 0x30C)
+#define MFG4_PWR_CON (SPM_BASE + 0x310)
+#define MFG5_PWR_CON (SPM_BASE + 0x314)
+#define MFG6_PWR_CON (SPM_BASE + 0x318)
+#define IFR_PWR_CON (SPM_BASE + 0x31C)
+#define IFR_SUB_PWR_CON (SPM_BASE + 0x320)
+#define PERI_PWR_CON (SPM_BASE + 0x324)
+#define PEXTP_MAC_TOP_P0_PWR_CON (SPM_BASE + 0x328)
+#define PEXTP_MAC_TOP_P1_PWR_CON (SPM_BASE + 0x32C)
+#define PCIE_PHY_PWR_CON (SPM_BASE + 0x330)
+#define SSUSB_PCIE_PHY_PWR_CON (SPM_BASE + 0x334)
+#define SSUSB_TOP_P1_PWR_CON (SPM_BASE + 0x338)
+#define SSUSB_TOP_P2_PWR_CON (SPM_BASE + 0x33C)
+#define SSUSB_TOP_P3_PWR_CON (SPM_BASE + 0x340)
+#define ETHER_PWR_CON (SPM_BASE + 0x344)
+#define DPY0_PWR_CON (SPM_BASE + 0x348)
+#define DPY1_PWR_CON (SPM_BASE + 0x34C)
+#define DPM0_PWR_CON (SPM_BASE + 0x350)
+#define DPM1_PWR_CON (SPM_BASE + 0x354)
+#define AUDIO_PWR_CON (SPM_BASE + 0x358)
+#define AUDIO_ASRC_PWR_CON (SPM_BASE + 0x35C)
+#define ADSP_PWR_CON (SPM_BASE + 0x360)
+#define VPPSYS0_PWR_CON (SPM_BASE + 0x364)
+#define VPPSYS1_PWR_CON (SPM_BASE + 0x368)
+#define VDOSYS0_PWR_CON (SPM_BASE + 0x36C)
+#define VDOSYS1_PWR_CON (SPM_BASE + 0x370)
+#define WPESYS_PWR_CON (SPM_BASE + 0x374)
+#define DP_TX_PWR_CON (SPM_BASE + 0x378)
+#define EDP_TX_PWR_CON (SPM_BASE + 0x37C)
+#define HDMI_TX_PWR_CON (SPM_BASE + 0x380)
+#define HDMI_RX_PWR_CON (SPM_BASE + 0x384)
+#define VDE0_PWR_CON (SPM_BASE + 0x388)
+#define VDE1_PWR_CON (SPM_BASE + 0x38C)
+#define VDE2_PWR_CON (SPM_BASE + 0x390)
+#define VEN_PWR_CON (SPM_BASE + 0x394)
+#define VEN_CORE1_PWR_CON (SPM_BASE + 0x398)
+#define CAM_PWR_CON (SPM_BASE + 0x39C)
+#define CAM_RAWA_PWR_CON (SPM_BASE + 0x3A0)
+#define CAM_RAWB_PWR_CON (SPM_BASE + 0x3A4)
+#define CAM_RAWC_PWR_CON (SPM_BASE + 0x3A8)
+#define IMG_M_PWR_CON (SPM_BASE + 0x3AC)
+#define IMG_D_PWR_CON (SPM_BASE + 0x3B0)
+#define IPE_PWR_CON (SPM_BASE + 0x3B4)
+#define NNA0_PWR_CON (SPM_BASE + 0x3B8)
+#define NNA1_PWR_CON (SPM_BASE + 0x3BC)
+#define IPNNA_PWR_CON (SPM_BASE + 0x3C0)
+#define CSI_RX_TOP_PWR_CON (SPM_BASE + 0x3C4)
+#define SSPM_SRAM_CON (SPM_BASE + 0x3C4)
+#define SCP_SRAM_CON (SPM_BASE + 0x3D0)
+#define UFS_SRAM_CON (SPM_BASE + 0x3D4)
+#define DEVAPC_IFR_SRAM_CON (SPM_BASE + 0x3D8)
+#define DEVAPC_SUBIFR_SRAM_CON (SPM_BASE + 0x3DC)
+#define DEVAPC_ACP_SRAM_CON (SPM_BASE + 0x3E0)
+#define USB_SRAM_CON (SPM_BASE + 0x3E4)
+#define DUMMY_SRAM_CO (SPM_BASE + 0x3E8)
+#define EXT_BUCK_ISO (SPM_BASE + 0x3EC)
+#define MSDC_SRAM_CON (SPM_BASE + 0x3F0)
+#define DEBUGTOP_SRAM (SPM_BASE + 0x3F4)
+#define DPMAIF_SRAM_C (SPM_BASE + 0x3F8)
+#define GCPU_SRAM_CON (SPM_BASE + 0x3FC)
+/*******Register_DIRC_IF*************************************************/
+#define SPM_MEM_CK_SEL (SPM_BASE + 0x400)
+#define SPM_BUS_PROTECT_MASK_B (SPM_BASE + 0x404)
+#define SPM_BUS_PROTECT1_MASK_B (SPM_BASE + 0x408)
+#define SPM_BUS_PROTECT2_MASK_B (SPM_BASE + 0x40C)
+#define SPM_BUS_PROTECT3_MASK_B (SPM_BASE + 0x410)
+#define SPM_BUS_PROTECT4_MASK_B (SPM_BASE + 0x414)
+#define SPM_BUS_PROTECT5_MASK_B (SPM_BASE + 0x418)
+#define SPM_BUS_PROTECT6_MASK_B (SPM_BASE + 0x41C)
+#define SPM_BUS_PROTECT7_MASK_B (SPM_BASE + 0x420)
+#define SPM_BUS_PROTECT8_MASK_B (SPM_BASE + 0x424)
+#define SPM_BUS_PROTECT9_MASK_B (SPM_BASE + 0x428)
+#define SPM_EMI_BW_MODE (SPM_BASE + 0x42C)
+#define SPM2MM_CON (SPM_BASE + 0x434)
+#define SPM2CPUEB_CON (SPM_BASE + 0x438)
+#define AP_MDSRC_REQ (SPM_BASE + 0x43C)
+#define SPM2EMI_ENTER_ULPM (SPM_BASE + 0x440)
+#define SPM_PLL_CON (SPM_BASE + 0x444)
+#define RC_SPM_CTRL (SPM_BASE + 0x448)
+#define SPM_DRAM_MCU_SW_CON_0 (SPM_BASE + 0x44C)
+#define SPM_DRAM_MCU_SW_CON_1 (SPM_BASE + 0x450)
+#define SPM_DRAM_MCU_SW_CON_2 (SPM_BASE + 0x454)
+#define SPM_DRAM_MCU_SW_CON_3 (SPM_BASE + 0x458)
+#define SPM_DRAM_MCU_SW_CON_4 (SPM_BASE + 0x45C)
+#define SPM_DRAM_MCU_STA_0 (SPM_BASE + 0x460)
+#define SPM_DRAM_MCU_STA_1 (SPM_BASE + 0x464)
+#define SPM_DRAM_MCU_STA_2 (SPM_BASE + 0x468)
+#define SPM_DRAM_MCU_SW_SEL_0 (SPM_BASE + 0x46C)
+#define RELAY_DVFS_LEVEL (SPM_BASE + 0x470)
+#define DRAMC_DPY_CLK_SW_CON_0 (SPM_BASE + 0x474)
+#define DRAMC_DPY_CLK_SW_CON_1 (SPM_BASE + 0x478)
+#define DRAMC_DPY_CLK_SW_CON_2 (SPM_BASE + 0x47C)
+#define DRAMC_DPY_CLK_SW_CON_3 (SPM_BASE + 0x480)
+#define DRAMC_DPY_CLK_SW_SEL_0 (SPM_BASE + 0x484)
+#define DRAMC_DPY_CLK_SW_SEL_1 (SPM_BASE + 0x488)
+#define DRAMC_DPY_CLK_SW_SEL_2 (SPM_BASE + 0x48C)
+#define DRAMC_DPY_CLK_SW_SEL_3 (SPM_BASE + 0x490)
+#define DRAMC_DPY_CLK_SPM_CON (SPM_BASE + 0x494)
+#define SPM_DVFS_LEVEL (SPM_BASE + 0x498)
+#define SPM_CIRQ_CON (SPM_BASE + 0x49C)
+#define SPM_DVFS_MISC (SPM_BASE + 0x4A0)
+#define RG_MODULE_SW_CG_0_MASK_REQ_0 (SPM_BASE + 0x4A4)
+#define RG_MODULE_SW_CG_0_MASK_REQ_1 (SPM_BASE + 0x4A8)
+#define RG_MODULE_SW_CG_0_MASK_REQ_2 (SPM_BASE + 0x4AC)
+#define RG_MODULE_SW_CG_1_MASK_REQ_0 (SPM_BASE + 0x4B0)
+#define RG_MODULE_SW_CG_1_MASK_REQ_1 (SPM_BASE + 0x4B4)
+#define RG_MODULE_SW_CG_1_MASK_REQ_2 (SPM_BASE + 0x4B8)
+#define RG_MODULE_SW_CG_2_MASK_REQ_0 (SPM_BASE + 0x4BC)
+#define RG_MODULE_SW_CG_2_MASK_REQ_1 (SPM_BASE + 0x4C0)
+#define RG_MODULE_SW_CG_2_MASK_REQ_2 (SPM_BASE + 0x4C4)
+#define RG_MODULE_SW_CG_3_MASK_REQ_0 (SPM_BASE + 0x4C8)
+#define RG_MODULE_SW_CG_3_MASK_REQ_1 (SPM_BASE + 0x4CC)
+#define RG_MODULE_SW_CG_3_MASK_REQ_2 (SPM_BASE + 0x4D0)
+#define PWR_STATUS_MASK_REQ_0 (SPM_BASE + 0x4D4)
+#define PWR_STATUS_MASK_REQ_1 (SPM_BASE + 0x4D8)
+#define PWR_STATUS_MASK_REQ_2 (SPM_BASE + 0x4DC)
+#define SPM_CG_CHECK_CON (SPM_BASE + 0x4E0)
+#define SPM_SRC_RDY_STA (SPM_BASE + 0x4E4)
+#define SPM_DVS_DFS_LEVEL (SPM_BASE + 0x4E8)
+#define SPM_FORCE_DVFS (SPM_BASE + 0x4EC)
+#define DRAMC_MCU_SRAM_CON (SPM_BASE + 0x4F0)
+#define DRAMC_MCU2_SRAM_CON (SPM_BASE + 0x4F4)
+#define DPY_SHU_SRAM_CON (SPM_BASE + 0x4F8)
+#define DPY_SHU2_SRAM_CON (SPM_BASE + 0x4FC)
+/*******The Others*************************************************/
+#define SRCLKEN_RC_CFG (SPM_BASE + 0x500)
+#define RC_CENTRAL_CFG1 (SPM_BASE + 0x504)
+#define RC_CENTRAL_CFG2 (SPM_BASE + 0x508)
+#define RC_CMD_ARB_CFG (SPM_BASE + 0x50C)
+#define RC_PMIC_RCEN_ADDR (SPM_BASE + 0x510)
+#define RC_PMIC_RCEN_SET_CLR_ADDR (SPM_BASE + 0x514)
+#define RC_DCXO_FPM_CFG (SPM_BASE + 0x518)
+#define RC_CENTRAL_CFG3 (SPM_BASE + 0x51C)
+#define RC_M00_SRCLKEN_CFG (SPM_BASE + 0x520)
+#define RC_M01_SRCLKEN_CFG (SPM_BASE + 0x524)
+#define RC_M02_SRCLKEN_CFG (SPM_BASE + 0x528)
+#define RC_M03_SRCLKEN_CFG (SPM_BASE + 0x52C)
+#define RC_M04_SRCLKEN_CFG (SPM_BASE + 0x530)
+#define RC_M05_SRCLKEN_CFG (SPM_BASE + 0x534)
+#define RC_M06_SRCLKEN_CFG (SPM_BASE + 0x538)
+#define RC_M07_SRCLKEN_CFG (SPM_BASE + 0x53C)
+#define RC_M08_SRCLKEN_CFG (SPM_BASE + 0x540)
+#define RC_M09_SRCLKEN_CFG (SPM_BASE + 0x544)
+#define RC_M10_SRCLKEN_CFG (SPM_BASE + 0x548)
+#define RC_M11_SRCLKEN_CFG (SPM_BASE + 0x54C)
+#define RC_M12_SRCLKEN_CFG (SPM_BASE + 0x550)
+#define RC_SRCLKEN_SW_CON_CFG (SPM_BASE + 0x554)
+#define RC_CENTRAL_CFG4 (SPM_BASE + 0x558)
+#define RC_PROTOCOL_CHK_CFG (SPM_BASE + 0x560)
+#define RC_DEBUG_CFG (SPM_BASE + 0x564)
+#define RC_MISC_0 (SPM_BASE + 0x5B4)
+
+#define SUBSYS_INTF_CFG (SPM_BASE + 0x5BC)
+#define PCM_WDT_LATCH_25 (SPM_BASE + 0x5C0)
+#define PCM_WDT_LATCH_26 (SPM_BASE + 0x5C4)
+#define PCM_WDT_LATCH_27 (SPM_BASE + 0x5C8)
+#define PCM_WDT_LATCH_28 (SPM_BASE + 0x5CC)
+#define PCM_WDT_LATCH_29 (SPM_BASE + 0x5D0)
+#define PCM_WDT_LATCH_30 (SPM_BASE + 0x5D4)
+#define PCM_WDT_LATCH_31 (SPM_BASE + 0x5D8)
+#define PCM_WDT_LATCH_32 (SPM_BASE + 0x5DC)
+#define PCM_WDT_LATCH_33 (SPM_BASE + 0x5E0)
+#define PCM_WDT_LATCH_34 (SPM_BASE + 0x5E4)
+#define PCM_WDT_LATCH_35 (SPM_BASE + 0x5EC)
+#define PCM_WDT_LATCH_36 (SPM_BASE + 0x5F0)
+#define PCM_WDT_LATCH_37 (SPM_BASE + 0x5F4)
+#define PCM_WDT_LATCH_38 (SPM_BASE + 0x5F8)
+#define PCM_WDT_LATCH_39 (SPM_BASE + 0x5FC)
+/*******Register_RSV*************************************************/
+#define SPM_SW_FLAG_0 (SPM_BASE + 0x600)
+#define SPM_SW_DEBUG_0 (SPM_BASE + 0x604)
+#define SPM_SW_FLAG_1 (SPM_BASE + 0x608)
+#define SPM_SW_DEBUG_1 (SPM_BASE + 0x60C)
+#define SPM_SW_RSV_0 (SPM_BASE + 0x610)
+#define SPM_SW_RSV_1 (SPM_BASE + 0x614)
+#define SPM_SW_RSV_2 (SPM_BASE + 0x618)
+#define SPM_SW_RSV_3 (SPM_BASE + 0x61C)
+#define SPM_SW_RSV_4 (SPM_BASE + 0x620)
+#define SPM_SW_RSV_5 (SPM_BASE + 0x624)
+#define SPM_SW_RSV_6 (SPM_BASE + 0x628)
+#define SPM_SW_RSV_7 (SPM_BASE + 0x62C)
+#define SPM_SW_RSV_8 (SPM_BASE + 0x630)
+#define SPM_BK_WAKE_EVENT (SPM_BASE + 0x634)
+#define SPM_BK_VTCXO_DUR (SPM_BASE + 0x638)
+#define SPM_BK_WAKE_MISC (SPM_BASE + 0x63C)
+#define SPM_BK_PCM_TIMER (SPM_BASE + 0x640)
+#define ULPOSC_CON (SPM_BASE + 0x644)
+#define SPM_RSV_CON_0 (SPM_BASE + 0x650)
+#define SPM_RSV_CON_1 (SPM_BASE + 0x654)
+#define SPM_RSV_STA_0 (SPM_BASE + 0x658)
+#define SPM_RSV_STA_1 (SPM_BASE + 0x65C)
+#define SPM_SPARE_CON (SPM_BASE + 0x660)
+#define SPM_SPARE_CON_SET (SPM_BASE + 0x664)
+#define SPM_SPARE_CON_CLR (SPM_BASE + 0x668)
+#define SPM_CROSS_WAKE_M00_REQ (SPM_BASE + 0x66C)
+#define SPM_CROSS_WAKE_M01_REQ (SPM_BASE + 0x670)
+#define SPM_CROSS_WAKE_M02_REQ (SPM_BASE + 0x674)
+#define SPM_CROSS_WAKE_M03_REQ (SPM_BASE + 0x678)
+#define SCP_VCORE_LEVEL (SPM_BASE + 0x67C)
+#define SC_MM_CK_SEL_CON (SPM_BASE + 0x680)
+#define SPARE_ACK_MASK (SPM_BASE + 0x684)
+#define SPM_DV_CON_0 (SPM_BASE + 0x68C)
+#define SPM_DV_CON_1 (SPM_BASE + 0x690)
+#define SPM_DV_STA (SPM_BASE + 0x694)
+#define CONN_XOWCN_DEBUG_EN (SPM_BASE + 0x698)
+#define SPM_SEMA_M0 (SPM_BASE + 0x69C)
+#define SPM_SEMA_M1 (SPM_BASE + 0x6A0)
+#define SPM_SEMA_M2 (SPM_BASE + 0x6A4)
+#define SPM_SEMA_M3 (SPM_BASE + 0x6A8)
+#define SPM_SEMA_M4 (SPM_BASE + 0x6AC)
+#define SPM_SEMA_M5 (SPM_BASE + 0x6B0)
+#define SPM_SEMA_M6 (SPM_BASE + 0x6B4)
+#define SPM_SEMA_M7 (SPM_BASE + 0x6B8)
+#define SPM2ADSP_MAILBOX (SPM_BASE + 0x6BC)
+#define ADSP2SPM_MAILBOX (SPM_BASE + 0x6C0)
+#define SPM_ADSP_IRQ (SPM_BASE + 0x6C4)
+#define SPM_MD32_IRQ (SPM_BASE + 0x6C8)
+#define SPM2PMCU_MAILBOX_0 (SPM_BASE + 0x6CC)
+#define SPM2PMCU_MAILBOX_1 (SPM_BASE + 0x6D0)
+#define SPM2PMCU_MAILBOX_2 (SPM_BASE + 0x6D4)
+#define SPM2PMCU_MAILBOX_3 (SPM_BASE + 0x6D8)
+#define PMCU2SPM_MAILBOX_0 (SPM_BASE + 0x6DC)
+#define PMCU2SPM_MAILBOX_1 (SPM_BASE + 0x6E0)
+#define PMCU2SPM_MAILBOX_2 (SPM_BASE + 0x6E4)
+#define PMCU2SPM_MAILBOX_3 (SPM_BASE + 0x6E8)
+#define UFS_PSRI_SW (SPM_BASE + 0x6EC)
+#define UFS_PSRI_SW_SET (SPM_BASE + 0x6F0)
+#define UFS_PSRI_SW_CLR (SPM_BASE + 0x6F4)
+#define SPM_AP_SEMA (SPM_BASE + 0x6F8)
+#define SPM_SPM_SEMA (SPM_BASE + 0x6FC)
+/*******Register_DVFS_TAB*************************************************/
+#define SPM_DVFS_CON (SPM_BASE + 0x700)
+#define SPM_DVFS_CON_STA (SPM_BASE + 0x704)
+#define SPM_PMIC_SPMI_CON (SPM_BASE + 0x708)
+#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 SPM_DVFS_CMD16 (SPM_BASE + 0x750)
+#define SPM_DVFS_CMD17 (SPM_BASE + 0x754)
+#define SPM_DVFS_CMD18 (SPM_BASE + 0x758)
+#define SPM_DVFS_CMD19 (SPM_BASE + 0x75C)
+#define SPM_DVFS_CMD20 (SPM_BASE + 0x760)
+#define SPM_DVFS_CMD21 (SPM_BASE + 0x764)
+#define SPM_DVFS_CMD22 (SPM_BASE + 0x768)
+#define SPM_DVFS_CMD23 (SPM_BASE + 0x76C)
+#define SYS_TIMER_VALUE_L (SPM_BASE + 0x770)
+#define SYS_TIMER_VALUE_H (SPM_BASE + 0x774)
+#define SYS_TIMER_START_L (SPM_BASE + 0x778)
+#define SYS_TIMER_START_H (SPM_BASE + 0x77C)
+#define SYS_TIMER_LATCH_L_00 (SPM_BASE + 0x780)
+#define SYS_TIMER_LATCH_H_00 (SPM_BASE + 0x784)
+#define SYS_TIMER_LATCH_L_01 (SPM_BASE + 0x788)
+#define SYS_TIMER_LATCH_H_01 (SPM_BASE + 0x78C)
+#define SYS_TIMER_LATCH_L_02 (SPM_BASE + 0x790)
+#define SYS_TIMER_LATCH_H_02 (SPM_BASE + 0x794)
+#define SYS_TIMER_LATCH_L_03 (SPM_BASE + 0x798)
+#define SYS_TIMER_LATCH_H_03 (SPM_BASE + 0x79C)
+#define SYS_TIMER_LATCH_L_04 (SPM_BASE + 0x7A0)
+#define SYS_TIMER_LATCH_H_04 (SPM_BASE + 0x7A4)
+#define SYS_TIMER_LATCH_L_05 (SPM_BASE + 0x7A8)
+#define SYS_TIMER_LATCH_H_05 (SPM_BASE + 0x7AC)
+#define SYS_TIMER_LATCH_L_06 (SPM_BASE + 0x7B0)
+#define SYS_TIMER_LATCH_H_06 (SPM_BASE + 0x7B4)
+#define SYS_TIMER_LATCH_L_07 (SPM_BASE + 0x7B8)
+#define SYS_TIMER_LATCH_H_07 (SPM_BASE + 0x7BC)
+#define SYS_TIMER_LATCH_L_08 (SPM_BASE + 0x7C0)
+#define SYS_TIMER_LATCH_H_08 (SPM_BASE + 0x7C4)
+#define SYS_TIMER_LATCH_L_09 (SPM_BASE + 0x7C8)
+#define SYS_TIMER_LATCH_H_09 (SPM_BASE + 0x7CC)
+#define SYS_TIMER_LATCH_L_10 (SPM_BASE + 0x7D0)
+#define SYS_TIMER_LATCH_H_10 (SPM_BASE + 0x7D4)
+#define SYS_TIMER_LATCH_L_11 (SPM_BASE + 0x7D8)
+#define SYS_TIMER_LATCH_H_11 (SPM_BASE + 0x7DC)
+#define SYS_TIMER_LATCH_L_12 (SPM_BASE + 0x7E0)
+#define SYS_TIMER_LATCH_H_12 (SPM_BASE + 0x7E4)
+#define SYS_TIMER_LATCH_L_13 (SPM_BASE + 0x7E8)
+#define SYS_TIMER_LATCH_H_13 (SPM_BASE + 0x7EC)
+#define SYS_TIMER_LATCH_L_14 (SPM_BASE + 0x7F0)
+#define SYS_TIMER_LATCH_H_14 (SPM_BASE + 0x7F4)
+#define SYS_TIMER_LATCH_L_15 (SPM_BASE + 0x7F8)
+#define SYS_TIMER_LATCH_H_15 (SPM_BASE + 0x7FC)
+/*******Register_LAT_STA*************************************************/
+#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 PCM_WDT_LATCH_10 (SPM_BASE + 0x828)
+#define PCM_WDT_LATCH_11 (SPM_BASE + 0x82C)
+#define PCM_WDT_LATCH_12 (SPM_BASE + 0x830)
+#define PCM_WDT_LATCH_13 (SPM_BASE + 0x834)
+#define PCM_WDT_LATCH_14 (SPM_BASE + 0x838)
+#define PCM_WDT_LATCH_15 (SPM_BASE + 0x83C)
+#define PCM_WDT_LATCH_16 (SPM_BASE + 0x840)
+#define PCM_WDT_LATCH_17 (SPM_BASE + 0x844)
+#define PCM_WDT_LATCH_18 (SPM_BASE + 0x848)
+#define PCM_WDT_LATCH_SPARE_0 (SPM_BASE + 0x84C)
+#define PCM_WDT_LATCH_SPARE_1 (SPM_BASE + 0x850)
+#define PCM_WDT_LATCH_SPARE_2 (SPM_BASE + 0x854)
+#define PCM_WDT_LATCH_CONN_0 (SPM_BASE + 0x870)
+#define PCM_WDT_LATCH_CONN_1 (SPM_BASE + 0x874)
+#define PCM_WDT_LATCH_CONN_2 (SPM_BASE + 0x878)
+#define DRAMC_GATING_ERR_LATCH_CH0_0 (SPM_BASE + 0x8A0)
+#define DRAMC_GATING_ERR_LATCH_CH0_1 (SPM_BASE + 0x8A4)
+#define DRAMC_GATING_ERR_LATCH_CH0_2 (SPM_BASE + 0x8A8)
+#define DRAMC_GATING_ERR_LATCH_CH0_3 (SPM_BASE + 0x8AC)
+#define DRAMC_GATING_ERR_LATCH_CH0_4 (SPM_BASE + 0x8B0)
+#define DRAMC_GATING_ERR_LATCH_CH0_5 (SPM_BASE + 0x8B4)
+#define DRAMC_GATING_ERR_LATCH_CH0_6 (SPM_BASE + 0x8B8)
+#define DRAMC_GATING_ERR_LATCH_SPARE_0 (SPM_BASE + 0x8F4)
+/*******Register_SPM_ACK_CHK*************************************************/
+#define SPM_ACK_CHK_CON_0 (SPM_BASE + 0x900)
+#define SPM_ACK_CHK_PC_0 (SPM_BASE + 0x904)
+#define SPM_ACK_CHK_SEL_0 (SPM_BASE + 0x908)
+#define SPM_ACK_CHK_TIMER_0 (SPM_BASE + 0x90C)
+#define SPM_ACK_CHK_STA_0 (SPM_BASE + 0x910)
+#define SPM_ACK_CHK_SWINT_0 (SPM_BASE + 0x914)
+#define SPM_ACK_CHK_CON_1 (SPM_BASE + 0x920)
+#define SPM_ACK_CHK_PC_1 (SPM_BASE + 0x924)
+#define SPM_ACK_CHK_SEL_1 (SPM_BASE + 0x928)
+#define SPM_ACK_CHK_TIMER_1 (SPM_BASE + 0x92C)
+#define SPM_ACK_CHK_STA_1 (SPM_BASE + 0x930)
+#define SPM_ACK_CHK_SWINT_1 (SPM_BASE + 0x934)
+#define SPM_ACK_CHK_CON_2 (SPM_BASE + 0x940)
+#define SPM_ACK_CHK_PC_2 (SPM_BASE + 0x944)
+#define SPM_ACK_CHK_SEL_2 (SPM_BASE + 0x948)
+#define SPM_ACK_CHK_TIMER_2 (SPM_BASE + 0x94C)
+#define SPM_ACK_CHK_STA_2 (SPM_BASE + 0x950)
+#define SPM_ACK_CHK_SWINT_2 (SPM_BASE + 0x954)
+#define SPM_ACK_CHK_CON_3 (SPM_BASE + 0x960)
+#define SPM_ACK_CHK_PC_3 (SPM_BASE + 0x964)
+#define SPM_ACK_CHK_SEL_3 (SPM_BASE + 0x968)
+#define SPM_ACK_CHK_TIMER_3 (SPM_BASE + 0x96C)
+#define SPM_ACK_CHK_STA_3 (SPM_BASE + 0x970)
+#define SPM_ACK_CHK_SWINT_3 (SPM_BASE + 0x974)
+#define SPM_COUNTER_0 (SPM_BASE + 0x978)
+#define SPM_COUNTER_1 (SPM_BASE + 0x97C)
+#define SPM_COUNTER_2 (SPM_BASE + 0x980)
+#define SYS_TIMER_CON (SPM_BASE + 0x98C)
+#define SPM_TWAM_CON (SPM_BASE + 0x990)
+#define SPM_TWAM_WINDOW_LEN (SPM_BASE + 0x994)
+#define SPM_TWAM_IDLE_SEL (SPM_BASE + 0x998)
+#define SPM_TWAM_EVENT_CLEAR (SPM_BASE + 0x99C)
+/*******The OTHERS*************************************************/
+#define RC_FSM_STA_0 (SPM_BASE + 0xE00)
+#define RC_CMD_STA_0 (SPM_BASE + 0xE04)
+#define RC_CMD_STA_1 (SPM_BASE + 0xE08)
+#define RC_SPI_STA_0 (SPM_BASE + 0xE0C)
+#define RC_PI_PO_STA_0 (SPM_BASE + 0xE10)
+#define RC_M00_REQ_STA_0 (SPM_BASE + 0xE14)
+#define RC_M01_REQ_STA_0 (SPM_BASE + 0xE1C)
+#define RC_M02_REQ_STA_0 (SPM_BASE + 0xE20)
+#define RC_M03_REQ_STA_0 (SPM_BASE + 0xE24)
+#define RC_M04_REQ_STA_0 (SPM_BASE + 0xE28)
+#define RC_M05_REQ_STA_0 (SPM_BASE + 0xE2C)
+#define RC_M06_REQ_STA_0 (SPM_BASE + 0xE30)
+#define RC_M07_REQ_STA_0 (SPM_BASE + 0xE34)
+#define RC_M08_REQ_STA_0 (SPM_BASE + 0xE38)
+#define RC_M09_REQ_STA_0 (SPM_BASE + 0xE3C)
+#define RC_M10_REQ_STA_0 (SPM_BASE + 0xE40)
+#define RC_M11_REQ_STA_0 (SPM_BASE + 0xE44)
+#define RC_M12_REQ_STA_0 (SPM_BASE + 0xE48)
+#define RC_DEBUG_STA_0 (SPM_BASE + 0xE4C)
+#define RC_DEBUG_TRACE_0_LSB (SPM_BASE + 0xE50)
+#define RC_DEBUG_TRACE_0_MSB (SPM_BASE + 0xE54)
+#define RC_DEBUG_TRACE_1_LSB (SPM_BASE + 0xE5C)
+#define RC_DEBUG_TRACE_1_MSB (SPM_BASE + 0xE60)
+#define RC_DEBUG_TRACE_2_LSB (SPM_BASE + 0xE64)
+#define RC_DEBUG_TRACE_2_MSB (SPM_BASE + 0xE6C)
+#define RC_DEBUG_TRACE_3_LSB (SPM_BASE + 0xE70)
+#define RC_DEBUG_TRACE_3_MSB (SPM_BASE + 0xE74)
+#define RC_DEBUG_TRACE_4_LSB (SPM_BASE + 0xE78)
+#define RC_DEBUG_TRACE_4_MSB (SPM_BASE + 0xE7C)
+#define RC_DEBUG_TRACE_5_LSB (SPM_BASE + 0xE80)
+#define RC_DEBUG_TRACE_5_MSB (SPM_BASE + 0xE84)
+#define RC_DEBUG_TRACE_6_LSB (SPM_BASE + 0xE88)
+#define RC_DEBUG_TRACE_6_MSB (SPM_BASE + 0xE8C)
+#define RC_DEBUG_TRACE_7_LSB (SPM_BASE + 0xE90)
+#define RC_DEBUG_TRACE_7_MSB (SPM_BASE + 0xE94)
+#define RC_SYS_TIMER_LATCH_0_LSB (SPM_BASE + 0xE98)
+#define RC_SYS_TIMER_LATCH_0_MSB (SPM_BASE + 0xE9C)
+#define RC_SYS_TIMER_LATCH_1_LSB (SPM_BASE + 0xEA0)
+#define RC_SYS_TIMER_LATCH_1_MSB (SPM_BASE + 0xEA4)
+#define RC_SYS_TIMER_LATCH_2_LSB (SPM_BASE + 0xEA8)
+#define RC_SYS_TIMER_LATCH_2_MSB (SPM_BASE + 0xEAC)
+#define RC_SYS_TIMER_LATCH_3_LSB (SPM_BASE + 0xEB0)
+#define RC_SYS_TIMER_LATCH_3_MSB (SPM_BASE + 0xEB4)
+#define RC_SYS_TIMER_LATCH_4_LSB (SPM_BASE + 0xEB8)
+#define RC_SYS_TIMER_LATCH_4_MSB (SPM_BASE + 0xEBC)
+#define RC_SYS_TIMER_LATCH_5_LSB (SPM_BASE + 0xEC0)
+#define RC_SYS_TIMER_LATCH_5_MSB (SPM_BASE + 0xEC4)
+#define RC_SYS_TIMER_LATCH_6_LSB (SPM_BASE + 0xEC8)
+#define RC_SYS_TIMER_LATCH_6_MSB (SPM_BASE + 0xECC)
+#define RC_SYS_TIMER_LATCH_7_LSB (SPM_BASE + 0xED0)
+#define RC_SYS_TIMER_LATCH_7_MSB (SPM_BASE + 0xED4)
+#define PCM_WDT_LATCH_19 (SPM_BASE + 0xED8)
+#define PCM_WDT_LATCH_20 (SPM_BASE + 0xEDC)
+#define PCM_WDT_LATCH_21 (SPM_BASE + 0xEE0)
+#define PCM_WDT_LATCH_22 (SPM_BASE + 0xEE4)
+#define PCM_WDT_LATCH_23 (SPM_BASE + 0xEE8)
+#define PCM_WDT_LATCH_24 (SPM_BASE + 0xEEC)
+/*******Register_PMSR*************************************************/
+#define PMSR_LAST_DAT (SPM_BASE + 0xF00)
+#define PMSR_LAST_CNT (SPM_BASE + 0xF04)
+#define PMSR_LAST_ACK (SPM_BASE + 0xF08)
+#define SPM_PMSR_SEL_CON0 (SPM_BASE + 0xF10)
+#define SPM_PMSR_SEL_CON1 (SPM_BASE + 0xF14)
+#define SPM_PMSR_SEL_CON2 (SPM_BASE + 0xF18)
+#define SPM_PMSR_SEL_CON3 (SPM_BASE + 0xF1C)
+#define SPM_PMSR_SEL_CON4 (SPM_BASE + 0xF20)
+#define SPM_PMSR_SEL_CON5 (SPM_BASE + 0xF24)
+#define SPM_PMSR_SEL_CON6 (SPM_BASE + 0xF28)
+#define SPM_PMSR_SEL_CON7 (SPM_BASE + 0xF2C)
+#define SPM_PMSR_SEL_CON8 (SPM_BASE + 0xF30)
+#define SPM_PMSR_SEL_CON9 (SPM_BASE + 0xF34)
+#define SPM_PMSR_SEL_CON10 (SPM_BASE + 0xF3C)
+#define SPM_PMSR_SEL_CON11 (SPM_BASE + 0xF40)
+#define SPM_PMSR_TIEMR_STA0 (SPM_BASE + 0xFB8)
+#define SPM_PMSR_TIEMR_STA1 (SPM_BASE + 0xFBC)
+#define SPM_PMSR_TIEMR_STA2 (SPM_BASE + 0xFC0)
+#define SPM_PMSR_GENERAL_CON0 (SPM_BASE + 0xFC4)
+#define SPM_PMSR_GENERAL_CON1 (SPM_BASE + 0xFC8)
+#define SPM_PMSR_GENERAL_CON2 (SPM_BASE + 0xFCC)
+#define SPM_PMSR_GENERAL_CON3 (SPM_BASE + 0xFD0)
+#define SPM_PMSR_GENERAL_CON4 (SPM_BASE + 0xFD4)
+#define SPM_PMSR_GENERAL_CON5 (SPM_BASE + 0xFD8)
+#define SPM_PMSR_SW_RESET (SPM_BASE + 0xFDC)
+#define SPM_PMSR_MON_CON0 (SPM_BASE + 0xFE0)
+#define SPM_PMSR_MON_CON1 (SPM_BASE + 0xFE4)
+#define SPM_PMSR_MON_CON2 (SPM_BASE + 0xFE8)
+#define SPM_PMSR_LEN_CON0 (SPM_BASE + 0xFEC)
+#define SPM_PMSR_LEN_CON1 (SPM_BASE + 0xFF0)
+#define SPM_PMSR_LEN_CON2 (SPM_BASE + 0xFF4)
+/*******Register End*************************************************/
+
+/* POWERON_CONFIG_EN (0x10006000+0x000) */
+#define BCLK_CG_EN_LSB (1U << 0) /* 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 REG_SRCCLKEN0_CTL_LSB (1U << 0) /* 2b */
+#define REG_SRCCLKEN1_CTL_LSB (1U << 2) /* 2b */
+#define SYS_SETTLE_SEL_LSB (1U << 4) /* 1b */
+#define REG_SPM_LOCK_INFRA_DCM_LSB (1U << 5) /* 1b */
+#define REG_SRCCLKEN_MASK_LSB (1U << 6) /* 3b */
+#define REG_MD1_C32RM_EN_LSB (1U << 9) /* 1b */
+#define REG_MD2_C32RM_EN_LSB (1U << 10) /* 1b */
+#define REG_CLKSQ0_SEL_CTRL_LSB (1U << 11) /* 1b */
+#define REG_CLKSQ1_SEL_CTRL_LSB (1U << 12) /* 1b */
+#define REG_SRCCLKEN0_EN_LSB (1U << 13) /* 1b */
+#define REG_SRCCLKEN1_EN_LSB (1U << 14) /* 1b */
+#define SCP_DCM_EN_LSB (1U << 15) /* 1b */
+#define REG_SYSCLK0_SRC_MASK_B_LSB (1U << 16) /* 8b */
+#define REG_SYSCLK1_SRC_MASK_B_LSB (1U << 24) /* 8b */
+/* SPM_CLK_SETTLE (0x10006000+0x010) */
+#define SYSCLK_SETTLE_LSB (1U << 0) /* 28b */
+/* SPM_AP_STANDBY_CON (0x10006000+0x014) */
+#define REG_WFI_OP_LSB (1U << 0) /* 1b */
+#define REG_WFI_TYPE_LSB (1U << 1) /* 1b */
+#define REG_MP0_CPUTOP_IDLE_MASK_LSB (1U << 2) /* 1b */
+#define REG_MP1_CPUTOP_IDLE_MASK_LSB (1U << 3) /* 1b */
+#define REG_MCUSYS_IDLE_MASK_LSB (1U << 4) /* 1b */
+#define REG_MD_APSRC_1_SEL_LSB (1U << 25) /* 1b */
+#define REG_MD_APSRC_0_SEL_LSB (1U << 26) /* 1b */
+#define REG_CONN_APSRC_SEL_LSB (1U << 29) /* 1b */
+/* PCM_CON0 (0x10006000+0x018) */
+#define PCM_CK_EN_LSB (1U << 2) /* 1b */
+#define RG_EN_IM_SLEEP_DVS_LSB (1U << 3) /* 1b */
+#define PCM_CK_FROM_CKSYS_LSB (1U << 4) /* 1b */
+#define PCM_SW_RESET_LSB (1U << 15) /* 1b */
+#define PCM_CON0_PROJECT_CODE_LSB (1U << 16) /* 16b */
+/* PCM_CON1 (0x10006000+0x01C) */
+#define RG_IM_SLAVE_LSB (1U << 0) /* 1b */
+#define RG_IM_SLEEP_LSB (1U << 1) /* 1b */
+#define REG_SPM_SRAM_CTRL_MUX_LSB (1U << 2) /* 1b */
+#define RG_AHBMIF_APBEN_LSB (1U << 3) /* 1b */
+#define RG_IM_PDN_LSB (1U << 4) /* 1b */
+#define RG_PCM_TIMER_EN_LSB (1U << 5) /* 1b */
+#define SPM_EVENT_COUNTER_CLR_LSB (1U << 6) /* 1b */
+#define RG_DIS_MIF_PROT_LSB (1U << 7) /* 1b */
+#define RG_PCM_WDT_EN_LSB (1U << 8) /* 1b */
+#define RG_PCM_WDT_WAKE_LSB (1U << 9) /* 1b */
+#define REG_SPM_SRAM_SLEEP_B_LSB (1U << 10) /* 1b */
+#define REG_SPM_SRAM_ISOINT_B_LSB (1U << 11) /* 1b */
+#define REG_EVENT_LOCK_EN_LSB (1U << 12) /* 1b */
+#define REG_SRCCLKEN_FAST_RESP_LSB (1U << 13) /* 1b */
+#define REG_MD32_APB_INTERNAL_EN_LSB (1U << 14) /* 1b */
+#define RG_PCM_IRQ_MSK_LSB (1U << 15) /* 1b */
+#define PCM_CON1_PROJECT_CODE_LSB (1U << 16) /* 16b */
+/* SPM_POWER_ON_VAL2 (0x10006000+0x020) */
+#define POWER_ON_VAL2_LSB (1U << 0) /* 32b */
+/* SPM_POWER_ON_VAL3 (0x10006000+0x024) */
+#define POWER_ON_VAL3_LSB (1U << 0) /* 32b */
+/* 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 RG_RF_SYNC_EN_LSB (1U << 16) /* 8b */
+/* PCM_TIMER_VAL (0x10006000+0x030) */
+#define REG_PCM_TIMER_VAL_LSB (1U << 0) /* 32b */
+/* PCM_WDT_VAL (0x10006000+0x034) */
+#define RG_PCM_WDT_VAL_LSB (1U << 0) /* 32b */
+/* SPM_SW_RST_CON (0x10006000+0x040) */
+#define SPM_SW_RST_CON_LSB (1U << 0) /* 16b */
+#define SPM_SW_RST_CON_PROJECT_CODE_LSB (1U << 16) /* 16b */
+/* SPM_SW_RST_CON_SET (0x10006000+0x044) */
+#define SPM_SW_RST_CON_SET_LSB (1U << 0) /* 16b */
+#define SPM_SW_RST_CON_SET_PROJECT_CODE_LSB (1U << 16) /* 16b */
+/* SPM_SW_RST_CON_CLR (0x10006000+0x048) */
+#define SPM_SW_RST_CON_CLR_LSB (1U << 0) /* 16b */
+#define SPM_SW_RST_CON_CLR_PROJECT_CODE_LSB (1U << 16) /* 16b */
+/* VS1_PSR_MASK_B (0x10006000+0x04C) */
+#define VS1_OPP0_PSR_MASK_B_LSB (1U << 0) /* 8b */
+#define VS1_OPP1_PSR_MASK_B_LSB (1U << 8) /* 8b */
+/* VS2_PSR_MASK_B (0x10006000+0x050) */
+#define VS2_OPP0_PSR_MASK_B_LSB (1U << 0) /* 8b */
+#define VS2_OPP1_PSR_MASK_B_LSB (1U << 8) /* 8b */
+#define VS2_OPP2_PSR_MASK_B_LSB (1U << 16) /* 8b */
+/* MD32_CLK_CON (0x10006000+0x084) */
+#define REG_MD32_26M_CK_SEL_LSB (1U << 0) /* 1b */
+#define REG_MD32_DCM_EN_LSB (1U << 1) /* 1b */
+/* 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) /* 32b */
+/* SPM_SWINT_SET (0x10006000+0x090) */
+#define SPM_SWINT_SET_LSB (1U << 0) /* 32b */
+/* SPM_SWINT_CLR (0x10006000+0x094) */
+#define SPM_SWINT_CLR_LSB (1U << 0) /* 32b */
+/* 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 REG_TWAM_ENABLE_LSB (1U << 0) /* 1b */
+#define REG_TWAM_SPEED_MODE_EN_LSB (1U << 1) /* 1b */
+#define REG_TWAM_SW_RST_LSB (1U << 2) /* 1b */
+#define REG_TWAM_IRQ_MASK_LSB (1U << 3) /* 1b */
+#define REG_TWAM_MON_TYPE_0_LSB (1U << 4) /* 2b */
+#define REG_TWAM_MON_TYPE_1_LSB (1U << 6) /* 2b */
+#define REG_TWAM_MON_TYPE_2_LSB (1U << 8) /* 2b */
+#define REG_TWAM_MON_TYPE_3_LSB (1U << 10) /* 2b */
+/* SPM_TWAM_WINDOW_LEN (0x10006000+0x0A4) */
+#define REG_TWAM_WINDOW_LEN_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_IDLE_SEL (0x10006000+0x0A8) */
+#define REG_TWAM_SIG_SEL_0_LSB (1U << 0) /* 7b */
+#define REG_TWAM_SIG_SEL_1_LSB (1U << 8) /* 7b */
+#define REG_TWAM_SIG_SEL_2_LSB (1U << 16) /* 7b */
+#define REG_TWAM_SIG_SEL_3_LSB (1U << 24) /* 7b */
+/* SPM_SCP_IRQ (0x10006000+0x0AC) */
+#define SC_SPM2SCP_WAKEUP_LSB (1U << 0) /* 1b */
+#define SC_SCP2SPM_WAKEUP_LSB (1U << 4) /* 1b */
+/* SPM_CPU_WAKEUP_EVENT (0x10006000+0x0B0) */
+#define REG_CPU_WAKEUP_LSB (1U << 0) /* 1b */
+/* SPM_IRQ_MASK (0x10006000+0x0B4) */
+#define REG_SPM_IRQ_MASK_LSB (1U << 0) /* 32b */
+/* DDR_EN_DBC (0x10006000+0x0B4) */
+#define REG_ALL_DDR_EN_DBC_EN_LSB (1U << 16) /* 1b */
+/* SPM_SRC_REQ (0x10006000+0x0B8) */
+#define REG_SPM_APSRC_REQ_LSB (1U << 0) /* 1b */
+#define REG_SPM_F26M_REQ_LSB (1U << 1) /* 1b */
+#define REG_SPM_INFRA_REQ_LSB (1U << 3) /* 1b */
+#define REG_SPM_VRF18_REQ_LSB (1U << 4) /* 1b */
+#define REG_SPM_DDR_EN_REQ_LSB (1U << 7) /* 1b */
+#define REG_SPM_DVFS_REQ_LSB (1U << 8) /* 1b */
+#define REG_SPM_SW_MAILBOX_REQ_LSB (1U << 9) /* 1b */
+#define REG_SPM_SSPM_MAILBOX_REQ_LSB (1U << 10) /* 1b */
+#define REG_SPM_ADSP_MAILBOX_REQ_LSB (1U << 11) /* 1b */
+#define REG_SPM_SCP_MAILBOX_REQ_LSB (1U << 12) /* 1b */
+/* SPM_SRC_MASK (0x10006000+0x0BC) */
+#define REG_MD_SRCCLKENA_0_MASK_B_LSB (1U << 0) /* 1b */
+#define REG_MD_SRCCLKENA2INFRA_REQ_0_MASK_B_LSB (1U << 1) /* 1b */
+#define REG_MD_APSRC2INFRA_REQ_0_MASK_B_LSB (1U << 2) /* 1b */
+#define REG_MD_APSRC_REQ_0_MASK_B_LSB (1U << 3) /* 1b */
+#define REG_MD_VRF18_REQ_0_MASK_B_LSB (1U << 4) /* 1b */
+#define REG_MD_DDR_EN_0_MASK_B_LSB (1U << 5) /* 1b */
+#define REG_MD_SRCCLKENA_1_MASK_B_LSB (1U << 6) /* 1b */
+#define REG_MD_SRCCLKENA2INFRA_REQ_1_MASK_B_LSB (1U << 7) /* 1b */
+#define REG_MD_APSRC2INFRA_REQ_1_MASK_B_LSB (1U << 8) /* 1b */
+#define REG_MD_APSRC_REQ_1_MASK_B_LSB (1U << 9) /* 1b */
+#define REG_MD_VRF18_REQ_1_MASK_B_LSB (1U << 10) /* 1b */
+#define REG_MD_DDR_EN_1_MASK_B_LSB (1U << 11) /* 1b */
+#define REG_CONN_SRCCLKENA_MASK_B_LSB (1U << 12) /* 1b */
+#define REG_CONN_SRCCLKENB_MASK_B_LSB (1U << 13) /* 1b */
+#define REG_CONN_INFRA_REQ_MASK_B_LSB (1U << 14) /* 1b */
+#define REG_CONN_APSRC_REQ_MASK_B_LSB (1U << 15) /* 1b */
+#define REG_CONN_VRF18_REQ_MASK_B_LSB (1U << 16) /* 1b */
+#define REG_CONN_DDR_EN_MASK_B_LSB (1U << 17) /* 1b */
+#define REG_CONN_VFE28_MASK_B_LSB (1U << 18) /* 1b */
+#define REG_SRCCLKENI0_SRCCLKENA_MASK_B_LSB (1U << 19) /* 1b */
+#define REG_SRCCLKENI0_INFRA_REQ_MASK_B_LSB (1U << 20) /* 1b */
+#define REG_SRCCLKENI1_SRCCLKENA_MASK_B_LSB (1U << 21) /* 1b */
+#define REG_SRCCLKENI1_INFRA_REQ_MASK_B_LSB (1U << 22) /* 1b */
+#define REG_SRCCLKENI2_SRCCLKENA_MASK_B_LSB (1U << 23) /* 1b */
+#define REG_SRCCLKENI2_INFRA_REQ_MASK_B_LSB (1U << 24) /* 1b */
+#define REG_INFRASYS_APSRC_REQ_MASK_B_LSB (1U << 25) /* 1b */
+#define REG_INFRASYS_DDR_EN_MASK_B_LSB (1U << 26) /* 1b */
+#define REG_MD32_SRCCLKENA_MASK_B_LSB (1U << 27) /* 1b */
+#define REG_MD32_INFRA_REQ_MASK_B_LSB (1U << 28) /* 1b */
+#define REG_MD32_APSRC_REQ_MASK_B_LSB (1U << 29) /* 1b */
+#define REG_MD32_VRF18_REQ_MASK_B_LSB (1U << 30) /* 1b */
+#define REG_MD32_DDR_EN_MASK_B_LSB (1U << 31) /* 1b */
+/* SPM_SRC2_MASK (0x10006000+0x0C0) */
+#define REG_SCP_SRCCLKENA_MASK_B_LSB (1U << 0) /* 1b */
+#define REG_SCP_INFRA_REQ_MASK_B_LSB (1U << 1) /* 1b */
+#define REG_SCP_APSRC_REQ_MASK_B_LSB (1U << 2) /* 1b */
+#define REG_SCP_VRF18_REQ_MASK_B_LSB (1U << 3) /* 1b */
+#define REG_SCP_DDR_EN_MASK_B_LSB (1U << 4) /* 1b */
+#define REG_AUDIO_DSP_SRCCLKENA_MASK_B_LSB (1U << 5) /* 1b */
+#define REG_AUDIO_DSP_INFRA_REQ_MASK_B_LSB (1U << 6) /* 1b */
+#define REG_AUDIO_DSP_APSRC_REQ_MASK_B_LSB (1U << 7) /* 1b */
+#define REG_AUDIO_DSP_VRF18_REQ_MASK_B_LSB (1U << 8) /* 1b */
+#define REG_AUDIO_DSP_DDR_EN_MASK_B_LSB (1U << 9) /* 1b */
+#define REG_UFS_SRCCLKENA_MASK_B_LSB (1U << 10) /* 1b */
+#define REG_UFS_INFRA_REQ_MASK_B_LSB (1U << 11) /* 1b */
+#define REG_UFS_APSRC_REQ_MASK_B_LSB (1U << 12) /* 1b */
+#define REG_UFS_VRF18_REQ_MASK_B_LSB (1U << 13) /* 1b */
+#define REG_UFS_DDR_EN_MASK_B_LSB (1U << 14) /* 1b */
+#define REG_DISP0_APSRC_REQ_MASK_B_LSB (1U << 15) /* 1b */
+#define REG_DISP0_DDR_EN_MASK_B_LSB (1U << 16) /* 1b */
+#define REG_DISP1_APSRC_REQ_MASK_B_LSB (1U << 17) /* 1b */
+#define REG_DISP1_DDR_EN_MASK_B_LSB (1U << 18) /* 1b */
+#define REG_GCE_INFRA_REQ_MASK_B_LSB (1U << 19) /* 1b */
+#define REG_GCE_APSRC_REQ_MASK_B_LSB (1U << 20) /* 1b */
+#define REG_GCE_VRF18_REQ_MASK_B_LSB (1U << 21) /* 1b */
+#define REG_GCE_DDR_EN_MASK_B_LSB (1U << 22) /* 1b */
+#define REG_APU_SRCCLKENA_MASK_B_LSB (1U << 23) /* 1b */
+#define REG_APU_INFRA_REQ_MASK_B_LSB (1U << 24) /* 1b */
+#define REG_APU_APSRC_REQ_MASK_B_LSB (1U << 25) /* 1b */
+#define REG_APU_VRF18_REQ_MASK_B_LSB (1U << 26) /* 1b */
+#define REG_APU_DDR_EN_MASK_B_LSB (1U << 27) /* 1b */
+#define REG_CG_CHECK_SRCCLKENA_MASK_B_LSB (1U << 28) /* 1b */
+#define REG_CG_CHECK_APSRC_REQ_MASK_B_LSB (1U << 29) /* 1b */
+#define REG_CG_CHECK_VRF18_REQ_MASK_B_LSB (1U << 30) /* 1b */
+#define REG_CG_CHECK_DDR_EN_MASK_B_LSB (1U << 31) /* 1b */
+/* SPM_SRC3_MASK (0x10006000+0x0C4) */
+#define REG_DVFSRC_EVENT_TRIGGER_MASK_B_LSB (1U << 0) /* 1b */
+#define REG_SW2SPM_INT0_MASK_B_LSB (1U << 1) /* 1b */
+#define REG_SW2SPM_INT1_MASK_B_LSB (1U << 2) /* 1b */
+#define REG_SW2SPM_INT2_MASK_B_LSB (1U << 3) /* 1b */
+#define REG_SW2SPM_INT3_MASK_B_LSB (1U << 4) /* 1b */
+#define REG_SC_ADSP2SPM_WAKEUP_MASK_B_LSB (1U << 5) /* 1b */
+#define REG_SC_SSPM2SPM_WAKEUP_MASK_B_LSB (1U << 6) /* 4b */
+#define REG_SC_SCP2SPM_WAKEUP_MASK_B_LSB (1U << 10) /* 1b */
+#define REG_CSYSPWRREQ_MASK_LSB (1U << 11) /* 1b */
+#define REG_SPM_SRCCLKENA_RESERVED_MASK_B_LSB (1U << 12) /* 1b */
+#define REG_SPM_INFRA_REQ_RESERVED_MASK_B_LSB (1U << 13) /* 1b */
+#define REG_SPM_APSRC_REQ_RESERVED_MASK_B_LSB (1U << 14) /* 1b */
+#define REG_SPM_VRF18_REQ_RESERVED_MASK_B_LSB (1U << 15) /* 1b */
+#define REG_SPM_DDR_EN_RESERVED_MASK_B_LSB (1U << 16) /* 1b */
+#define REG_MCUPM_SRCCLKENA_MASK_B_LSB (1U << 17) /* 1b */
+#define REG_MCUPM_INFRA_REQ_MASK_B_LSB (1U << 18) /* 1b */
+#define REG_MCUPM_APSRC_REQ_MASK_B_LSB (1U << 19) /* 1b */
+#define REG_MCUPM_VRF18_REQ_MASK_B_LSB (1U << 20) /* 1b */
+#define REG_MCUPM_DDR_EN_MASK_B_LSB (1U << 21) /* 1b */
+#define REG_MSDC0_SRCCLKENA_MASK_B_LSB (1U << 22) /* 1b */
+#define REG_MSDC0_INFRA_REQ_MASK_B_LSB (1U << 23) /* 1b */
+#define REG_MSDC0_APSRC_REQ_MASK_B_LSB (1U << 24) /* 1b */
+#define REG_MSDC0_VRF18_REQ_MASK_B_LSB (1U << 25) /* 1b */
+#define REG_MSDC0_DDR_EN_MASK_B_LSB (1U << 26) /* 1b */
+#define REG_MSDC1_SRCCLKENA_MASK_B_LSB (1U << 27) /* 1b */
+#define REG_MSDC1_INFRA_REQ_MASK_B_LSB (1U << 28) /* 1b */
+#define REG_MSDC1_APSRC_REQ_MASK_B_LSB (1U << 29) /* 1b */
+#define REG_MSDC1_VRF18_REQ_MASK_B_LSB (1U << 30) /* 1b */
+#define REG_MSDC1_DDR_EN_MASK_B_LSB (1U << 31) /* 1b */
+/* SPM_SRC4_MASK (0x10006000+0x0C8) */
+#define CCIF_EVENT_MASK_B_LSB (1U << 0) /* 16b */
+#define REG_BAK_PSRI_SRCCLKENA_MASK_B_LSB (1U << 16) /* 1b */
+#define REG_BAK_PSRI_INFRA_REQ_MASK_B_LSB (1U << 17) /* 1b */
+#define REG_BAK_PSRI_APSRC_REQ_MASK_B_LSB (1U << 18) /* 1b */
+#define REG_BAK_PSRI_VRF18_REQ_MASK_B_LSB (1U << 19) /* 1b */
+#define REG_BAK_PSRI_DDR_EN_MASK_B_LSB (1U << 20) /* 1b */
+#define REG_DRAMC0_MD32_INFRA_REQ_MASK_B_LSB (1U << 21) /* 1b */
+#define REG_DRAMC0_MD32_VRF18_REQ_MASK_B_LSB (1U << 22) /* 1b */
+#define REG_DRAMC1_MD32_INFRA_REQ_MASK_B_LSB (1U << 23) /* 1b */
+#define REG_DRAMC1_MD32_VRF18_REQ_MASK_B_LSB (1U << 24) /* 1b */
+#define REG_CONN_SRCCLKENB2PWRAP_MASK_B_LSB (1U << 25) /* 1b */
+#define REG_DRAMC0_MD32_WAKEUP_MASK_LSB (1U << 26) /* 1b */
+#define REG_DRAMC1_MD32_WAKEUP_MASK_LSB (1U << 27) /* 1b */
+/* SPM_SRC5_MASK (0x10006000+0x0CC) */
+#define REG_MCUSYS_MERGE_APSRC_REQ_MASK_B_LSB (1U << 0) /* 9b */
+#define REG_MCUSYS_MERGE_DDR_EN_MASK_B_LSB (1U << 9) /* 9b */
+/* SPM_WAKEUP_EVENT_MASK (0x10006000+0x0D0) */
+#define REG_WAKEUP_EVENT_MASK_LSB (1U << 0) /* 32b */
+/* SPM_WAKEUP_EVENT_EXT_MASK (0x10006000+0x0D4) */
+#define REG_EXT_WAKEUP_EVENT_MASK_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_EVENT_CLEAR (0x10006000+0x0D8) */
+#define SPM_TWAM_EVENT_CLEAR_LSB (1U << 0) /* 1b */
+/* SCP_CLK_CON (0x10006000+0x0DC) */
+#define REG_SCP_26M_CK_SEL_LSB (1U << 0) /* 1b */
+#define REG_SCP_DCM_EN_LSB (1U << 1) /* 1b */
+#define SCP_SECURE_V_REQ_MASK_LSB (1U << 2) /* 1b */
+#define SCP_SLP_REQ_LSB (1U << 3) /* 1b */
+#define SCP_SLP_ACK_LSB (1U << 4) /* 1b */
+/* SPM_RESOURCE_ACK_CON0 (0x10006000+0x0F0) */
+#define REG_MD_SRCCLKENA_ACK_0_MASK_LSB (1U << 0) /* 1b */
+#define REG_MD_INFRA_ACK_0_MASK_LSB (1U << 1) /* 1b */
+#define REG_MD_APSRC_ACK_0_MASK_LSB (1U << 2) /* 1b */
+#define REG_MD_VRF18_ACK_0_MASK_LSB (1U << 3) /* 1b */
+#define REG_MD_DDR_EN_ACK_0_MASK_LSB (1U << 4) /* 1b */
+#define REG_MD_SRCCLKENA_ACK_1_MASK_LSB (1U << 5) /* 1b */
+#define REG_MD_INFRA_ACK_1_MASK_LSB (1U << 6) /* 1b */
+#define REG_MD_APSRC_ACK_1_MASK_LSB (1U << 7) /* 1b */
+#define REG_MD_VRF18_ACK_1_MASK_LSB (1U << 8) /* 1b */
+#define REG_MD_DDR_EN_ACK_1_MASK_LSB (1U << 9) /* 1b */
+#define REG_CONN_SRCCLKENA_ACK_MASK_LSB (1U << 10) /* 1b */
+#define REG_CONN_INFRA_ACK_MASK_LSB (1U << 11) /* 1b */
+#define REG_CONN_APSRC_ACK_MASK_LSB (1U << 12) /* 1b */
+#define REG_CONN_VRF18_ACK_MASK_LSB (1U << 13) /* 1b */
+#define REG_CONN_DDR_EN_ACK_MASK_LSB (1U << 14) /* 1b */
+#define REG_MD32_SRCCLKENA_ACK_MASK_LSB (1U << 15) /* 1b */
+#define REG_MD32_INFRA_ACK_MASK_LSB (1U << 16) /* 1b */
+#define REG_MD32_APSRC_ACK_MASK_LSB (1U << 17) /* 1b */
+#define REG_MD32_VRF18_ACK_MASK_LSB (1U << 18) /* 1b */
+#define REG_MD32_DDR_EN_ACK_MASK_LSB (1U << 19) /* 1b */
+#define REG_SCP_SRCCLKENA_ACK_MASK_LSB (1U << 20) /* 1b */
+#define REG_SCP_INFRA_ACK_MASK_LSB (1U << 21) /* 1b */
+#define REG_SCP_APSRC_ACK_MASK_LSB (1U << 22) /* 1b */
+#define REG_SCP_VRF18_ACK_MASK_LSB (1U << 23) /* 1b */
+#define REG_SCP_DDR_EN_ACK_MASK_LSB (1U << 24) /* 1b */
+#define REG_AUDIO_DSP_SRCCLKENA_ACK_MASK_LSB (1U << 25) /* 1b */
+#define REG_AUDIO_DSP_INFRA_ACK_MASK_LSB (1U << 26) /* 1b */
+#define REG_AUDIO_DSP_APSRC_ACK_MASK_LSB (1U << 27) /* 1b */
+#define REG_AUDIO_DSP_VRF18_ACK_MASK_LSB (1U << 28) /* 1b */
+#define REG_AUDIO_DSP_DDR_EN_ACK_MASK_LSB (1U << 29) /* 1b */
+#define REG_DISP0_DDR_EN_ACK_MASK_LSB (1U << 30) /* 1b */
+#define REG_DISP1_APSRC_ACK_MASK_LSB (1U << 31) /* 1b */
+/* SPM_RESOURCE_ACK_CON1 (0x10006000+0x0F4) */
+#define REG_UFS_SRCCLKENA_ACK_MASK_LSB (1U << 0) /* 1b */
+#define REG_UFS_INFRA_ACK_MASK_LSB (1U << 1) /* 1b */
+#define REG_UFS_APSRC_ACK_MASK_LSB (1U << 2) /* 1b */
+#define REG_UFS_VRF18_ACK_MASK_LSB (1U << 3) /* 1b */
+#define REG_UFS_DDR_EN_ACK_MASK_LSB (1U << 4) /* 1b */
+#define REG_APU_SRCCLKENA_ACK_MASK_LSB (1U << 5) /* 1b */
+#define REG_APU_INFRA_ACK_MASK_LSB (1U << 6) /* 1b */
+#define REG_APU_APSRC_ACK_MASK_LSB (1U << 7) /* 1b */
+#define REG_APU_VRF18_ACK_MASK_LSB (1U << 8) /* 1b */
+#define REG_APU_DDR_EN_ACK_MASK_LSB (1U << 9) /* 1b */
+#define REG_MCUPM_SRCCLKENA_ACK_MASK_LSB (1U << 10) /* 1b */
+#define REG_MCUPM_INFRA_ACK_MASK_LSB (1U << 11) /* 1b */
+#define REG_MCUPM_APSRC_ACK_MASK_LSB (1U << 12) /* 1b */
+#define REG_MCUPM_VRF18_ACK_MASK_LSB (1U << 13) /* 1b */
+#define REG_MCUPM_DDR_EN_ACK_MASK_LSB (1U << 14) /* 1b */
+#define REG_MSDC0_SRCCLKENA_ACK_MASK_LSB (1U << 15) /* 1b */
+#define REG_MSDC0_INFRA_ACK_MASK_LSB (1U << 16) /* 1b */
+#define REG_MSDC0_APSRC_ACK_MASK_LSB (1U << 17) /* 1b */
+#define REG_MSDC0_VRF18_ACK_MASK_LSB (1U << 18) /* 1b */
+#define REG_MSDC0_DDR_EN_ACK_MASK_LSB (1U << 19) /* 1b */
+#define REG_MSDC1_SRCCLKENA_ACK_MASK_LSB (1U << 20) /* 1b */
+#define REG_MSDC1_INFRA_ACK_MASK_LSB (1U << 21) /* 1b */
+#define REG_MSDC1_APSRC_ACK_MASK_LSB (1U << 22) /* 1b */
+#define REG_MSDC1_VRF18_ACK_MASK_LSB (1U << 23) /* 1b */
+#define REG_MSDC1_DDR_EN_ACK_MASK_LSB (1U << 24) /* 1b */
+#define REG_DISP0_APSRC_ACK_MASK_LSB (1U << 25) /* 1b */
+#define REG_DISP1_DDR_EN_ACK_MASK_LSB (1U << 26) /* 1b */
+#define REG_GCE_INFRA_ACK_MASK_LSB (1U << 27) /* 1b */
+#define REG_GCE_APSRC_ACK_MASK_LSB (1U << 28) /* 1b */
+#define REG_GCE_VRF18_ACK_MASK_LSB (1U << 29) /* 1b */
+#define REG_GCE_DDR_EN_ACK_MASK_LSB (1U << 30) /* 1b */
+/* SPM_RESOURCE_ACK_CON2 (0x10006000+0x0F8) */
+#define SPM_F26M_ACK_WAIT_CYCLE_LSB (1U << 0) /* 8b */
+#define SPM_INFRA_ACK_WAIT_CYCLE_LSB (1U << 8) /* 8b */
+#define SPM_APSRC_ACK_WAIT_CYCLE_LSB (1U << 16) /* 8b */
+#define SPM_VRF18_ACK_WAIT_CYCLE_LSB (1U << 24) /* 8b */
+/* SPM_RESOURCE_ACK_CON3 (0x10006000+0x0FC) */
+#define SPM_DDR_EN_ACK_WAIT_CYCLE_LSB (1U << 0) /* 8b */
+#define REG_BAK_PSRI_SRCCLKENA_ACK_MASK_LSB (1U << 8) /* 1b */
+#define REG_BAK_PSRI_INFRA_ACK_MASK_LSB (1U << 9) /* 1b */
+#define REG_BAK_PSRI_APSRC_ACK_MASK_LSB (1U << 10) /* 1b */
+#define REG_BAK_PSRI_VRF18_ACK_MASK_LSB (1U << 11) /* 1b */
+#define REG_BAK_PSRI_DDR_EN_ACK_MASK_LSB (1U << 12) /* 1b */
+/* PCM_REG0_DATA (0x10006000+0x100) */
+#define PCM_REG0_RF_LSB (1U << 0) /* 32b */
+/* PCM_REG2_DATA (0x10006000+0x104) */
+#define PCM_REG2_RF_LSB (1U << 0) /* 32b */
+/* PCM_REG6_DATA (0x10006000+0x108) */
+#define PCM_REG6_RF_LSB (1U << 0) /* 32b */
+/* PCM_REG7_DATA (0x10006000+0x10C) */
+#define PCM_REG7_RF_LSB (1U << 0) /* 32b */
+/* PCM_REG13_DATA (0x10006000+0x110) */
+#define PCM_REG13_RF_LSB (1U << 0) /* 32b */
+/* SRC_REQ_STA_0 (0x10006000+0x114) */
+#define MD_SRCCLKENA_0_LSB (1U << 0) /* 1b */
+#define MD_SRCCLKENA2INFRA_REQ_0_LSB (1U << 1) /* 1b */
+#define MD_APSRC2INFRA_REQ_0_LSB (1U << 2) /* 1b */
+#define MD_APSRC_REQ_0_LSB (1U << 3) /* 1b */
+#define MD_VRF18_REQ_0_LSB (1U << 4) /* 1b */
+#define MD_DDR_EN_0_LSB (1U << 5) /* 1b */
+#define MD_SRCCLKENA_1_LSB (1U << 6) /* 1b */
+#define MD_SRCCLKENA2INFRA_REQ_1_LSB (1U << 7) /* 1b */
+#define MD_APSRC2INFRA_REQ_1_LSB (1U << 8) /* 1b */
+#define MD_APSRC_REQ_1_LSB (1U << 9) /* 1b */
+#define MD_VRF18_REQ_1_LSB (1U << 10) /* 1b */
+#define MD_DDR_EN_1_LSB (1U << 11) /* 1b */
+#define CONN_SRCCLKENA_LSB (1U << 12) /* 1b */
+#define CONN_SRCCLKENB_LSB (1U << 13) /* 1b */
+#define CONN_INFRA_REQ_LSB (1U << 14) /* 1b */
+#define CONN_APSRC_REQ_LSB (1U << 15) /* 1b */
+#define CONN_VRF18_REQ_LSB (1U << 16) /* 1b */
+#define CONN_DDR_EN_LSB (1U << 17) /* 1b */
+#define SRCCLKENI_LSB (1U << 18) /* 3b */
+#define MD32_SRCCLKENA_LSB (1U << 21) /* 1b */
+#define MD32_INFRA_REQ_LSB (1U << 22) /* 1b */
+#define MD32_APSRC_REQ_LSB (1U << 23) /* 1b */
+#define MD32_VRF18_REQ_LSB (1U << 24) /* 1b */
+#define MD32_DDR_EN_LSB (1U << 25) /* 1b */
+#define DISP0_APSRC_REQ_LSB (1U << 26) /* 1b */
+#define DISP0_DDR_EN_LSB (1U << 27) /* 1b */
+#define DISP1_APSRC_REQ_LSB (1U << 28) /* 1b */
+#define DISP1_DDR_EN_LSB (1U << 29) /* 1b */
+#define DVFSRC_EVENT_TRIGGER_LSB (1U << 30) /* 1b */
+/* SRC_REQ_STA_1 (0x10006000+0x118) */
+#define SCP_SRCCLKENA_LSB (1U << 0) /* 1b */
+#define SCP_INFRA_REQ_LSB (1U << 1) /* 1b */
+#define SCP_APSRC_REQ_LSB (1U << 2) /* 1b */
+#define SCP_VRF18_REQ_LSB (1U << 3) /* 1b */
+#define SCP_DDR_EN_LSB (1U << 4) /* 1b */
+#define AUDIO_DSP_SRCCLKENA_LSB (1U << 5) /* 1b */
+#define AUDIO_DSP_INFRA_REQ_LSB (1U << 6) /* 1b */
+#define AUDIO_DSP_APSRC_REQ_LSB (1U << 7) /* 1b */
+#define AUDIO_DSP_VRF18_REQ_LSB (1U << 8) /* 1b */
+#define AUDIO_DSP_DDR_EN_LSB (1U << 9) /* 1b */
+#define UFS_SRCCLKENA_LSB (1U << 10) /* 1b */
+#define UFS_INFRA_REQ_LSB (1U << 11) /* 1b */
+#define UFS_APSRC_REQ_LSB (1U << 12) /* 1b */
+#define UFS_VRF18_REQ_LSB (1U << 13) /* 1b */
+#define UFS_DDR_EN_LSB (1U << 14) /* 1b */
+#define GCE_INFRA_REQ_LSB (1U << 15) /* 1b */
+#define GCE_APSRC_REQ_LSB (1U << 16) /* 1b */
+#define GCE_VRF18_REQ_LSB (1U << 17) /* 1b */
+#define GCE_DDR_EN_LSB (1U << 18) /* 1b */
+#define INFRASYS_APSRC_REQ_LSB (1U << 19) /* 1b */
+#define INFRASYS_DDR_EN_LSB (1U << 20) /* 1b */
+#define MSDC0_SRCCLKENA_LSB (1U << 21) /* 1b */
+#define MSDC0_INFRA_REQ_LSB (1U << 22) /* 1b */
+#define MSDC0_APSRC_REQ_LSB (1U << 23) /* 1b */
+#define MSDC0_VRF18_REQ_LSB (1U << 24) /* 1b */
+#define MSDC0_DDR_EN_LSB (1U << 25) /* 1b */
+#define MSDC1_SRCCLKENA_LSB (1U << 26) /* 1b */
+#define MSDC1_INFRA_REQ_LSB (1U << 27) /* 1b */
+#define MSDC1_APSRC_REQ_LSB (1U << 28) /* 1b */
+#define MSDC1_VRF18_REQ_LSB (1U << 29) /* 1b */
+#define MSDC1_DDR_EN_LSB (1U << 30) /* 1b */
+/* SRC_REQ_STA_2 (0x10006000+0x11C) */
+#define MCUSYS_MERGE_DDR_EN_LSB (1U << 0) /* 9b */
+#define EMI_SELF_REFRESH_CH_LSB (1U << 9) /* 2b */
+#define SW2SPM_INT_LSB (1U << 11) /* 4b */
+#define SC_ADSP2SPM_WAKEUP_LSB (1U << 15) /* 1b */
+#define SC_SSPM2SPM_WAKEUP_LSB (1U << 16) /* 4b */
+#define SRC_REQ_STA_2_SC_SCP2SPM_WAKEUP_LSB (1U << 20) /* 1b */
+#define SPM_SRCCLKENA_RESERVED_LSB (1U << 21) /* 1b */
+#define SPM_INFRA_REQ_RESERVED_LSB (1U << 22) /* 1b */
+#define SPM_APSRC_REQ_RESERVED_LSB (1U << 23) /* 1b */
+#define SPM_VRF18_REQ_RESERVED_LSB (1U << 24) /* 1b */
+#define SPM_DDR_EN_RESERVED_LSB (1U << 25) /* 1b */
+#define MCUPM_SRCCLKENA_LSB (1U << 26) /* 1b */
+#define MCUPM_INFRA_REQ_LSB (1U << 27) /* 1b */
+#define MCUPM_APSRC_REQ_LSB (1U << 28) /* 1b */
+#define MCUPM_VRF18_REQ_LSB (1U << 29) /* 1b */
+#define MCUPM_DDR_EN_LSB (1U << 30) /* 1b */
+/* PCM_TIMER_OUT (0x10006000+0x120) */
+#define PCM_TIMER_LSB (1U << 0) /* 32b */
+/* PCM_WDT_OUT (0x10006000+0x124) */
+#define PCM_WDT_TIMER_VAL_OUT_LSB (1U << 0) /* 32b */
+/* SPM_IRQ_STA (0x10006000+0x128) */
+#define TWAM_IRQ_LSB (1U << 2) /* 1b */
+#define PCM_IRQ_LSB (1U << 3) /* 1b */
+/* SRC_REQ_STA_4 (0x10006000+0x12C) */
+#define APU_SRCCLKENA_LSB (1U << 0) /* 1b */
+#define APU_INFRA_REQ_LSB (1U << 1) /* 1b */
+#define APU_APSRC_REQ_LSB (1U << 2) /* 1b */
+#define APU_VRF18_REQ_LSB (1U << 3) /* 1b */
+#define APU_DDR_EN_LSB (1U << 4) /* 1b */
+#define BAK_PSRI_SRCCLKENA_LSB (1U << 5) /* 1b */
+#define BAK_PSRI_INFRA_REQ_LSB (1U << 6) /* 1b */
+#define BAK_PSRI_APSRC_REQ_LSB (1U << 7) /* 1b */
+#define BAK_PSRI_VRF18_REQ_LSB (1U << 8) /* 1b */
+#define BAK_PSRI_DDR_EN_LSB (1U << 9) /* 1b */
+/* MD32PCM_WAKEUP_STA (0x10006000+0x130) */
+#define MD32PCM_WAKEUP_STA_LSB (1U << 0) /* 32b */
+/* MD32PCM_EVENT_STA (0x10006000+0x134) */
+#define MD32PCM_EVENT_STA_LSB (1U << 0) /* 32b */
+/* SPM_WAKEUP_STA (0x10006000+0x138) */
+#define F32K_WAKEUP_EVENT_L_LSB (1U << 0) /* 16b */
+#define ASYN_WAKEUP_EVENT_L_LSB (1U << 16) /* 16b */
+/* SPM_WAKEUP_EXT_STA (0x10006000+0x13C) */
+#define EXT_WAKEUP_EVENT_LSB (1U << 0) /* 32b */
+/* SPM_WAKEUP_MISC (0x10006000+0x140) */
+#define GIC_WAKEUP_LSB (1U << 0) /* 10b */
+#define DVFSRC_IRQ_LSB (1U << 16) /* 1b */
+#define SPM_WAKEUP_MISC_REG_CPU_WAKEUP_LSB (1U << 17) /* 1b */
+#define PCM_TIMER_EVENT_LSB (1U << 18) /* 1b */
+#define PMIC_EINT_OUT_B_LSB (1U << 19) /* 2b */
+#define TWAM_IRQ_B_LSB (1U << 21) /* 1b */
+#define PMSR_IRQ_B_SET0_LSB (1U << 22) /* 1b */
+#define PMSR_IRQ_B_SET1_LSB (1U << 23) /* 1b */
+#define PMSR_IRQ_B_SET2_LSB (1U << 24) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_0_LSB (1U << 25) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_1_LSB (1U << 26) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_2_LSB (1U << 27) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_3_LSB (1U << 28) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_ALL_LSB (1U << 29) /* 1b */
+#define PMIC_IRQ_ACK_LSB (1U << 30) /* 1b */
+#define PMIC_SCP_IRQ_LSB (1U << 31) /* 1b */
+/* MM_DVFS_HALT (0x10006000+0x144) */
+#define MM_DVFS_HALT_LSB (1U << 0) /* 5b */
+/* BUS_PROTECT_RDY (0x10006000+0x150) */
+#define PROTECT_READY_LSB (1U << 0) /* 32b */
+/* BUS_PROTECT1_RDY (0x10006000+0x154) */
+#define PROTECT1_READY_LSB (1U << 0) /* 32b */
+/* BUS_PROTECT2_RDY (0x10006000+0x158) */
+#define PROTECT2_READY_LSB (1U << 0) /* 32b */
+/* BUS_PROTECT3_RDY (0x10006000+0x15C) */
+#define PROTECT3_READY_LSB (1U << 0) /* 32b */
+/* SUBSYS_IDLE_STA (0x10006000+0x160) */
+#define SUBSYS_IDLE_SIGNALS_LSB (1U << 0) /* 32b */
+/* PCM_STA (0x10006000+0x164) */
+#define PCM_CK_SEL_O_LSB (1U << 0) /* 4b */
+#define EXT_SRC_STA_LSB (1U << 4) /* 3b */
+/* SRC_REQ_STA_3 (0x10006000+0x168) */
+#define CCIF_EVENT_RAW_STATUS_LSB (1U << 0) /* 16b */
+#define F26M_STATE_LSB (1U << 16) /* 1b */
+#define INFRA_STATE_LSB (1U << 17) /* 1b */
+#define APSRC_STATE_LSB (1U << 18) /* 1b */
+#define VRF18_STATE_LSB (1U << 19) /* 1b */
+#define DDR_EN_STATE_LSB (1U << 20) /* 1b */
+#define DVFS_STATE_LSB (1U << 21) /* 1b */
+#define SW_MAILBOX_STATE_LSB (1U << 22) /* 1b */
+#define SSPM_MAILBOX_STATE_LSB (1U << 23) /* 1b */
+#define ADSP_MAILBOX_STATE_LSB (1U << 24) /* 1b */
+#define SCP_MAILBOX_STATE_LSB (1U << 25) /* 1b */
+/* PWR_STATUS (0x10006000+0x16C) */
+#define PWR_STATUS_LSB (1U << 0) /* 32b */
+/* PWR_STATUS_2ND (0x10006000+0x170) */
+#define PWR_STATUS_2ND_LSB (1U << 0) /* 32b */
+/* CPU_PWR_STATUS (0x10006000+0x174) */
+#define MP0_SPMC_PWR_ON_ACK_CPU0_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU1_LSB (1U << 1) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU2_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU3_LSB (1U << 3) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU4_LSB (1U << 4) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU5_LSB (1U << 5) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU6_LSB (1U << 6) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPU7_LSB (1U << 7) /* 1b */
+#define MP0_SPMC_PWR_ON_ACK_CPUTOP_LSB (1U << 8) /* 1b */
+#define MCUSYS_SPMC_PWR_ON_ACK_LSB (1U << 9) /* 1b */
+/* OTHER_PWR_STATUS (0x10006000+0x178) */
+#define OTHER_PWR_STATUS_LSB (1U << 0) /* 32b */
+/* SPM_VTCXO_EVENT_COUNT_STA (0x10006000+0x17C) */
+#define SPM_VTCXO_SLEEP_COUNT_LSB (1U << 0) /* 16b */
+#define SPM_VTCXO_WAKE_COUNT_LSB (1U << 16) /* 16b */
+/* SPM_INFRA_EVENT_COUNT_STA (0x10006000+0x180) */
+#define SPM_INFRA_SLEEP_COUNT_LSB (1U << 0) /* 16b */
+#define SPM_INFRA_WAKE_COUNT_LSB (1U << 16) /* 16b */
+/* SPM_VRF18_EVENT_COUNT_STA (0x10006000+0x184) */
+#define SPM_VRF18_SLEEP_COUNT_LSB (1U << 0) /* 16b */
+#define SPM_VRF18_WAKE_COUNT_LSB (1U << 16) /* 16b */
+/* SPM_APSRC_EVENT_COUNT_STA (0x10006000+0x188) */
+#define SPM_APSRC_SLEEP_COUNT_LSB (1U << 0) /* 16b */
+#define SPM_APSRC_WAKE_COUNT_LSB (1U << 16) /* 16b */
+/* SPM_DDREN_EVENT_COUNT_STA (0x10006000+0x18C) */
+#define SPM_DDREN_SLEEP_COUNT_LSB (1U << 0) /* 16b */
+#define SPM_DDREN_WAKE_COUNT_LSB (1U << 16) /* 16b */
+/* MD32PCM_STA (0x10006000+0x190) */
+#define MD32PCM_HALT_LSB (1U << 0) /* 1b */
+#define MD32PCM_GATED_LSB (1U << 1) /* 1b */
+/* MD32PCM_PC (0x10006000+0x194) */
+#define MON_PC_LSB (1U << 0) /* 32b */
+/* DVFSRC_EVENT_STA (0x10006000+0x1A4) */
+#define DVFSRC_EVENT_LSB (1U << 0) /* 32b */
+/* BUS_PROTECT4_RDY (0x10006000+0x1A8) */
+#define PROTECT4_READY_LSB (1U << 0) /* 32b */
+/* BUS_PROTECT5_RDY (0x10006000+0x1AC) */
+#define PROTECT5_READY_LSB (1U << 0) /* 32b */
+/* BUS_PROTECT6_RDY (0x10006000+0x1B0) */
+#define PROTECT6_READY_LSB (1U << 0) /* 32b */
+/* BUS_PROTECT7_RDY (0x10006000+0x1B4) */
+#define PROTECT7_READY_LSB (1U << 0) /* 32b */
+/* BUS_PROTECT8_RDY (0x10006000+0x1B8) */
+#define PROTECT8_READY_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_LAST_STA0 (0x10006000+0x1D0) */
+#define LAST_IDLE_CNT_0_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_LAST_STA1 (0x10006000+0x1D4) */
+#define LAST_IDLE_CNT_1_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_LAST_STA2 (0x10006000+0x1D8) */
+#define LAST_IDLE_CNT_2_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_LAST_STA3 (0x10006000+0x1DC) */
+#define LAST_IDLE_CNT_3_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_CURR_STA0 (0x10006000+0x1E0) */
+#define CURRENT_IDLE_CNT_0_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_CURR_STA1 (0x10006000+0x1E4) */
+#define CURRENT_IDLE_CNT_1_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_CURR_STA2 (0x10006000+0x1E8) */
+#define CURRENT_IDLE_CNT_2_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_CURR_STA3 (0x10006000+0x1EC) */
+#define CURRENT_IDLE_CNT_3_LSB (1U << 0) /* 32b */
+/* SPM_TWAM_TIMER_OUT (0x10006000+0x1F0) */
+#define TWAM_TIMER_LSB (1U << 0) /* 32b */
+/* SPM_CG_CHECK_STA (0x10006000+0x1F4) */
+#define SPM_CG_CHECK_SLEEP_REQ_0_LSB (1U << 0) /* 1b */
+#define SPM_CG_CHECK_SLEEP_REQ_1_LSB (1U << 1) /* 1b */
+#define SPM_CG_CHECK_SLEEP_REQ_2_LSB (1U << 2) /* 1b */
+/* SPM_DVFS_STA (0x10006000+0x1F8) */
+#define TARGET_DVFS_LEVEL_LSB (1U << 0) /* 32b */
+/* SPM_DVFS_OPP_STA (0x10006000+0x1FC) */
+#define TARGET_DVFS_OPP_LSB (1U << 0) /* 5b */
+#define CURRENT_DVFS_OPP_LSB (1U << 5) /* 5b */
+#define RELAY_DVFS_OPP_LSB (1U << 10) /* 5b */
+/* SPM_MCUSYS_PWR_CON (0x10006000+0x200) */
+#define MCUSYS_SPMC_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MCUSYS_SPMC_PWR_ON_LSB (1U << 2) /* 1b */
+#define MCUSYS_SPMC_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MCUSYS_SPMC_RESETPWRON_CONFIG_LSB (1U << 5) /* 1b */
+#define MCUSYS_SPMC_DORMANT_EN_LSB (1U << 6) /* 1b */
+#define MCUSYS_VPROC_EXT_OFF_LSB (1U << 7) /* 1b */
+#define SPM_MCUSYS_PWR_CON_MCUSYS_SPMC_PWR_ON_ACK_LSB (1U << 31) /* 1b */
+/* SPM_CPUTOP_PWR_CON (0x10006000+0x204) */
+#define MP0_SPMC_PWR_RST_B_CPUTOP_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPUTOP_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_PWR_CLK_DIS_CPUTOP_LSB (1U << 4) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPUTOP_LSB (1U << 5) /* 1b */
+#define MP0_SPMC_DORMANT_EN_CPUTOP_LSB (1U << 6) /* 1b */
+#define MP0_VPROC_EXT_OFF_LSB (1U << 7) /* 1b */
+#define MP0_VSRAM_EXT_OFF_LSB (1U << 8) /* 1b */
+#define SPM_CPUTOP_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPUTOP_LSB (1U << 31) /* 1b */
+/* SPM_CPU0_PWR_CON (0x10006000+0x208) */
+#define MP0_SPMC_PWR_RST_B_CPU0_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU0_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU0_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU0_LSB (1U << 7) /* 1b */
+#define SPM_CPU0_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU0_LSB (1U << 31) /* 1b */
+/* SPM_CPU1_PWR_CON (0x10006000+0x20C) */
+#define MP0_SPMC_PWR_RST_B_CPU1_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU1_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU1_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU1_LSB (1U << 7) /* 1b */
+#define SPM_CPU1_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU1_LSB (1U << 31) /* 1b */
+/* SPM_CPU2_PWR_CON (0x10006000+0x210) */
+#define MP0_SPMC_PWR_RST_B_CPU2_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU2_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU2_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU2_LSB (1U << 7) /* 1b */
+#define SPM_CPU2_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU2_LSB (1U << 31) /* 1b */
+/* SPM_CPU3_PWR_CON (0x10006000+0x214) */
+#define MP0_SPMC_PWR_RST_B_CPU3_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU3_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU3_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU3_LSB (1U << 7) /* 1b */
+#define SPM_CPU3_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU3_LSB (1U << 31) /* 1b */
+/* SPM_CPU4_PWR_CON (0x10006000+0x218) */
+#define MP0_SPMC_PWR_RST_B_CPU4_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU4_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU4_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU4_LSB (1U << 7) /* 1b */
+#define SPM_CPU4_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU4_LSB (1U << 31) /* 1b */
+/* SPM_CPU5_PWR_CON (0x10006000+0x21C) */
+#define MP0_SPMC_PWR_RST_B_CPU5_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU5_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU5_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU5_LSB (1U << 7) /* 1b */
+#define SPM_CPU5_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU5_LSB (1U << 31) /* 1b */
+/* SPM_CPU6_PWR_CON (0x10006000+0x220) */
+#define MP0_SPMC_PWR_RST_B_CPU6_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU6_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU6_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU6_LSB (1U << 7) /* 1b */
+#define SPM_CPU6_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU6_LSB (1U << 31) /* 1b */
+/* SPM_CPU7_PWR_CON (0x10006000+0x224) */
+#define MP0_SPMC_PWR_RST_B_CPU7_LSB (1U << 0) /* 1b */
+#define MP0_SPMC_PWR_ON_CPU7_LSB (1U << 2) /* 1b */
+#define MP0_SPMC_RESETPWRON_CONFIG_CPU7_LSB (1U << 5) /* 1b */
+#define MP0_VPROC_EXT_OFF_CPU7_LSB (1U << 7) /* 1b */
+#define SPM_CPU7_PWR_CON_MP0_SPMC_PWR_ON_ACK_CPU7_LSB (1U << 31) /* 1b */
+/* ARMPLL_CLK_CON (0x10006000+0x22C) */
+#define SC_ARM_FHC_PAUSE_LSB (1U << 0) /* 6b */
+#define SC_ARM_CK_OFF_LSB (1U << 6) /* 6b */
+#define SC_ARMPLL_OFF_LSB (1U << 12) /* 1b */
+#define SC_ARMBPLL_OFF_LSB (1U << 13) /* 1b */
+#define SC_ARMBPLL1_OFF_LSB (1U << 14) /* 1b */
+#define SC_ARMBPLL2_OFF_LSB (1U << 15) /* 1b */
+#define SC_ARMBPLL3_OFF_LSB (1U << 16) /* 1b */
+#define SC_CCIPLL_CKOFF_LSB (1U << 17) /* 1b */
+#define SC_ARMDDS_OFF_LSB (1U << 18) /* 1b */
+#define SC_ARMBPLL_S_OFF_LSB (1U << 19) /* 1b */
+#define SC_ARMBPLL1_S_OFF_LSB (1U << 20) /* 1b */
+#define SC_ARMBPLL2_S_OFF_LSB (1U << 21) /* 1b */
+#define SC_ARMBPLL3_S_OFF_LSB (1U << 22) /* 1b */
+#define SC_CCIPLL_PWROFF_LSB (1U << 23) /* 1b */
+#define SC_ARMPLLOUT_OFF_LSB (1U << 24) /* 1b */
+#define SC_ARMBPLLOUT_OFF_LSB (1U << 25) /* 1b */
+#define SC_ARMBPLLOUT1_OFF_LSB (1U << 26) /* 1b */
+#define SC_ARMBPLLOUT2_OFF_LSB (1U << 27) /* 1b */
+#define SC_ARMBPLLOUT3_OFF_LSB (1U << 28) /* 1b */
+#define SC_CCIPLL_OUT_OFF_LSB (1U << 29) /* 1b */
+/* MCUSYS_IDLE_STA (0x10006000+0x230) */
+#define ARMBUS_IDLE_TO_26M_LSB (1U << 0) /* 1b */
+#define MP0_CLUSTER_IDLE_TO_PWR_OFF_LSB (1U << 1) /* 1b */
+#define MCUSYS_DDR_EN_0_LSB (1U << 2) /* 1b */
+#define MCUSYS_DDR_EN_1_LSB (1U << 3) /* 1b */
+#define MCUSYS_DDR_EN_2_LSB (1U << 4) /* 1b */
+#define MCUSYS_DDR_EN_3_LSB (1U << 5) /* 1b */
+#define MCUSYS_DDR_EN_4_LSB (1U << 6) /* 1b */
+#define MCUSYS_DDR_EN_5_LSB (1U << 7) /* 1b */
+#define MCUSYS_DDR_EN_6_LSB (1U << 8) /* 1b */
+#define MCUSYS_DDR_EN_7_LSB (1U << 9) /* 1b */
+#define MP0_CPU_IDLE_TO_PWR_OFF_LSB (1U << 16) /* 8b */
+#define WFI_AF_SEL_LSB (1U << 24) /* 8b */
+/* GIC_WAKEUP_STA (0x10006000+0x234) */
+#define GIC_WAKEUP_STA_GIC_WAKEUP_LSB (1U << 10) /* 10b */
+/* CPU_SPARE_CON (0x10006000+0x238) */
+#define CPU_SPARE_CON_LSB (1U << 0) /* 32b */
+/* CPU_SPARE_CON_SET (0x10006000+0x23C) */
+#define CPU_SPARE_CON_SET_LSB (1U << 0) /* 32b */
+/* CPU_SPARE_CON_CLR (0x10006000+0x240) */
+#define CPU_SPARE_CON_CLR_LSB (1U << 0) /* 32b */
+/* ARMPLL_CLK_SEL (0x10006000+0x244) */
+#define ARMPLL_CLK_SEL_LSB (1U << 0) /* 15b */
+/* EXT_INT_WAKEUP_REQ (0x10006000+0x248) */
+#define EXT_INT_WAKEUP_REQ_LSB (1U << 0) /* 10b */
+/* EXT_INT_WAKEUP_REQ_SET (0x10006000+0x24C) */
+#define EXT_INT_WAKEUP_REQ_SET_LSB (1U << 0) /* 10b */
+/* EXT_INT_WAKEUP_REQ_CLR (0x10006000+0x250) */
+#define EXT_INT_WAKEUP_REQ_CLR_LSB (1U << 0) /* 10b */
+/* MP0_CPU0_IRQ_MASK (0x10006000+0x260) */
+#define MP0_CPU0_IRQ_MASK_LSB (1U << 0) /* 1b */
+#define MP0_CPU0_AUX_LSB (1U << 8) /* 11b */
+/* MP0_CPU1_IRQ_MASK (0x10006000+0x264) */
+#define MP0_CPU1_IRQ_MASK_LSB (1U << 0) /* 1b */
+#define MP0_CPU1_AUX_LSB (1U << 8) /* 11b */
+/* MP0_CPU2_IRQ_MASK (0x10006000+0x268) */
+#define MP0_CPU2_IRQ_MASK_LSB (1U << 0) /* 1b */
+#define MP0_CPU2_AUX_LSB (1U << 8) /* 11b */
+/* MP0_CPU3_IRQ_MASK (0x10006000+0x26C) */
+#define MP0_CPU3_IRQ_MASK_LSB (1U << 0) /* 1b */
+#define MP0_CPU3_AUX_LSB (1U << 8) /* 11b */
+/* MP1_CPU0_IRQ_MASK (0x10006000+0x270) */
+#define MP1_CPU0_IRQ_MASK_LSB (1U << 0) /* 1b */
+#define MP1_CPU0_AUX_LSB (1U << 8) /* 11b */
+/* MP1_CPU1_IRQ_MASK (0x10006000+0x274) */
+#define MP1_CPU1_IRQ_MASK_LSB (1U << 0) /* 1b */
+#define MP1_CPU1_AUX_LSB (1U << 8) /* 11b */
+/* MP1_CPU2_IRQ_MASK (0x10006000+0x278) */
+#define MP1_CPU2_IRQ_MASK_LSB (1U << 0) /* 1b */
+#define MP1_CPU2_AUX_LSB (1U << 8) /* 11b */
+/* MP1_CPU3_IRQ_MASK (0x10006000+0x27C) */
+#define MP1_CPU3_IRQ_MASK_LSB (1U << 0) /* 1b */
+#define MP1_CPU3_AUX_LSB (1U << 8) /* 11b */
+/* MP0_CPU0_WFI_EN (0x10006000+0x280) */
+#define MP0_CPU0_WFI_EN_LSB (1U << 0) /* 1b */
+/* MP0_CPU1_WFI_EN (0x10006000+0x284) */
+#define MP0_CPU1_WFI_EN_LSB (1U << 0) /* 1b */
+/* MP0_CPU2_WFI_EN (0x10006000+0x288) */
+#define MP0_CPU2_WFI_EN_LSB (1U << 0) /* 1b */
+/* MP0_CPU3_WFI_EN (0x10006000+0x28C) */
+#define MP0_CPU3_WFI_EN_LSB (1U << 0) /* 1b */
+/* MP0_CPU4_WFI_EN (0x10006000+0x290) */
+#define MP0_CPU4_WFI_EN_LSB (1U << 0) /* 1b */
+/* MP0_CPU5_WFI_EN (0x10006000+0x294) */
+#define MP0_CPU5_WFI_EN_LSB (1U << 0) /* 1b */
+/* MP0_CPU6_WFI_EN (0x10006000+0x298) */
+#define MP0_CPU6_WFI_EN_LSB (1U << 0) /* 1b */
+/* MP0_CPU7_WFI_EN (0x10006000+0x29C) */
+#define MP0_CPU7_WFI_EN_LSB (1U << 0) /* 1b */
+/* ROOT_CPUTOP_ADDR (0x10006000+0x2A0) */
+#define ROOT_CPUTOP_ADDR_LSB (1U << 0) /* 32b */
+/* ROOT_CORE_ADDR (0x10006000+0x2A4) */
+#define ROOT_CORE_ADDR_LSB (1U << 0) /* 32b */
+/* SPM2SW_MAILBOX_0 (0x10006000+0x2D0) */
+#define SPM2SW_MAILBOX_0_LSB (1U << 0) /* 32b */
+/* SPM2SW_MAILBOX_1 (0x10006000+0x2D4) */
+#define SPM2SW_MAILBOX_1_LSB (1U << 0) /* 32b */
+/* SPM2SW_MAILBOX_2 (0x10006000+0x2D8) */
+#define SPM2SW_MAILBOX_2_LSB (1U << 0) /* 32b */
+/* SPM2SW_MAILBOX_3 (0x10006000+0x2DC) */
+#define SPM2SW_MAILBOX_3_LSB (1U << 0) /* 32b */
+/* SW2SPM_INT (0x10006000+0x2E0) */
+#define SW2SPM_INT_SW2SPM_INT_LSB (1U << 0) /* 4b */
+/* SW2SPM_INT_SET (0x10006000+0x2E4) */
+#define SW2SPM_INT_SET_LSB (1U << 0) /* 4b */
+/* SW2SPM_INT_CLR (0x10006000+0x2E8) */
+#define SW2SPM_INT_CLR_LSB (1U << 0) /* 4b */
+/* SW2SPM_MAILBOX_0 (0x10006000+0x2EC) */
+#define SW2SPM_MAILBOX_0_LSB (1U << 0) /* 32b */
+/* SW2SPM_MAILBOX_1 (0x10006000+0x2F0) */
+#define SW2SPM_MAILBOX_1_LSB (1U << 0) /* 32b */
+/* SW2SPM_MAILBOX_2 (0x10006000+0x2F4) */
+#define SW2SPM_MAILBOX_2_LSB (1U << 0) /* 32b */
+/* SW2SPM_MAILBOX_3 (0x10006000+0x2F8) */
+#define SW2SPM_MAILBOX_3_LSB (1U << 0) /* 32b */
+/* SW2SPM_CFG (0x10006000+0x2FC) */
+#define SWU2SPM_INT_MASK_B_LSB (1U << 0) /* 4b */
+/* MD1_PWR_CON (0x10006000+0x300) */
+#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 */
+#define SC_MD1_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* CONN_PWR_CON (0x10006000+0x304) */
+#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 */
+/* MFG0_PWR_CON (0x10006000+0x308) */
+#define MFG0_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG0_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG0_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG0_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG0_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG0_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG0_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* MFG1_PWR_CON (0x10006000+0x30C) */
+#define MFG1_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG1_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG1_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG1_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG1_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG1_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG1_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* MFG2_PWR_CON (0x10006000+0x310) */
+#define MFG2_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG2_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG2_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG2_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG2_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG2_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG2_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* MFG3_PWR_CON (0x10006000+0x314) */
+#define MFG3_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG3_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG3_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG3_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG3_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG3_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG3_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* MFG4_PWR_CON (0x10006000+0x318) */
+#define MFG4_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG4_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG4_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG4_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG4_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG4_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG4_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* MFG5_PWR_CON (0x10006000+0x31C) */
+#define MFG5_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG5_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG5_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG5_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG5_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG5_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG5_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* MFG6_PWR_CON (0x10006000+0x320) */
+#define MFG6_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MFG6_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MFG6_PWR_ON_LSB (1U << 2) /* 1b */
+#define MFG6_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MFG6_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MFG6_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MFG6_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* IFR_PWR_CON (0x10006000+0x324) */
+#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) /* 1b */
+#define SC_IFR_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* IFR_SUB_PWR_CON (0x10006000+0x328) */
+#define IFR_SUB_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define IFR_SUB_PWR_ISO_LSB (1U << 1) /* 1b */
+#define IFR_SUB_PWR_ON_LSB (1U << 2) /* 1b */
+#define IFR_SUB_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define IFR_SUB_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define IFR_SUB_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_IFR_SUB_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* DPY_PWR_CON (0x10006000+0x32C) */
+#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) /* 1b */
+#define SC_DPY_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* ISP_PWR_CON (0x10006000+0x330) */
+#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) /* 1b */
+#define SC_ISP_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* ISP2_PWR_CON (0x10006000+0x334) */
+#define ISP2_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define ISP2_PWR_ISO_LSB (1U << 1) /* 1b */
+#define ISP2_PWR_ON_LSB (1U << 2) /* 1b */
+#define ISP2_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define ISP2_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define ISP2_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_ISP2_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* IPE_PWR_CON (0x10006000+0x338) */
+#define IPE_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define IPE_PWR_ISO_LSB (1U << 1) /* 1b */
+#define IPE_PWR_ON_LSB (1U << 2) /* 1b */
+#define IPE_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define IPE_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define IPE_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_IPE_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* VDE_PWR_CON (0x10006000+0x33C) */
+#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) /* 1b */
+#define SC_VDE_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* VDE2_PWR_CON (0x10006000+0x340) */
+#define VDE2_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define VDE2_PWR_ISO_LSB (1U << 1) /* 1b */
+#define VDE2_PWR_ON_LSB (1U << 2) /* 1b */
+#define VDE2_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define VDE2_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define VDE2_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_VDE2_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* VEN_PWR_CON (0x10006000+0x344) */
+#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) /* 1b */
+#define SC_VEN_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* VEN_CORE1_PWR_CON (0x10006000+0x348) */
+#define VEN_CORE1_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define VEN_CORE1_PWR_ISO_LSB (1U << 1) /* 1b */
+#define VEN_CORE1_PWR_ON_LSB (1U << 2) /* 1b */
+#define VEN_CORE1_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define VEN_CORE1_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define VEN_CORE1_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_VEN_CORE1_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* MDP_PWR_CON (0x10006000+0x34C) */
+#define MDP_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define MDP_PWR_ISO_LSB (1U << 1) /* 1b */
+#define MDP_PWR_ON_LSB (1U << 2) /* 1b */
+#define MDP_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define MDP_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define MDP_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_MDP_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* DIS_PWR_CON (0x10006000+0x350) */
+#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) /* 1b */
+#define SC_DIS_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* AUDIO_PWR_CON (0x10006000+0x354) */
+#define AUDIO_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define AUDIO_PWR_ISO_LSB (1U << 1) /* 1b */
+#define AUDIO_PWR_ON_LSB (1U << 2) /* 1b */
+#define AUDIO_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define AUDIO_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define AUDIO_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_AUDIO_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* ADSP_PWR_CON (0x10006000+0x358) */
+#define ADSP_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define ADSP_PWR_ISO_LSB (1U << 1) /* 1b */
+#define ADSP_PWR_ON_LSB (1U << 2) /* 1b */
+#define ADSP_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define ADSP_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define ADSP_SRAM_CKISO_LSB (1U << 5) /* 1b */
+#define ADSP_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */
+#define ADSP_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define ADSP_SRAM_SLEEP_B_LSB (1U << 9) /* 1b */
+#define SC_ADSP_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+#define SC_ADSP_SRAM_SLEEP_B_ACK_LSB (1U << 13) /* 1b */
+/* CAM_PWR_CON (0x10006000+0x35C) */
+#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) /* 1b */
+#define SC_CAM_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* CAM_RAWA_PWR_CON (0x10006000+0x360) */
+#define CAM_RAWA_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define CAM_RAWA_PWR_ISO_LSB (1U << 1) /* 1b */
+#define CAM_RAWA_PWR_ON_LSB (1U << 2) /* 1b */
+#define CAM_RAWA_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define CAM_RAWA_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define CAM_RAWA_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_CAM_RAWA_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* CAM_RAWB_PWR_CON (0x10006000+0x364) */
+#define CAM_RAWB_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define CAM_RAWB_PWR_ISO_LSB (1U << 1) /* 1b */
+#define CAM_RAWB_PWR_ON_LSB (1U << 2) /* 1b */
+#define CAM_RAWB_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define CAM_RAWB_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define CAM_RAWB_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_CAM_RAWB_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* CAM_RAWC_PWR_CON (0x10006000+0x368) */
+#define CAM_RAWC_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define CAM_RAWC_PWR_ISO_LSB (1U << 1) /* 1b */
+#define CAM_RAWC_PWR_ON_LSB (1U << 2) /* 1b */
+#define CAM_RAWC_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define CAM_RAWC_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define CAM_RAWC_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_CAM_RAWC_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* SYSRAM_CON (0x10006000+0x36C) */
+#define SYSRAM_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define SYSRAM_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define SYSRAM_SRAM_SLEEP_B_LSB (1U << 4) /* 4b */
+#define SYSRAM_SRAM_PDN_LSB (1U << 16) /* 4b */
+/* SYSROM_CON (0x10006000+0x370) */
+#define SYSROM_SRAM_PDN_LSB (1U << 0) /* 6b */
+/* SSPM_SRAM_CON (0x10006000+0x374) */
+#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+0x378) */
+#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 */
+/* DPY_SHU_SRAM_CON (0x10006000+0x37C) */
+#define DPY_SHU_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DPY_SHU_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DPY_SHU_SRAM_SLEEP_B_LSB (1U << 4) /* 2b */
+#define DPY_SHU_SRAM_PDN_LSB (1U << 16) /* 2b */
+/* UFS_SRAM_CON (0x10006000+0x380) */
+#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 */
+/* DEVAPC_IFR_SRAM_CON (0x10006000+0x384) */
+#define DEVAPC_IFR_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DEVAPC_IFR_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DEVAPC_IFR_SRAM_SLEEP_B_LSB (1U << 4) /* 6b */
+#define DEVAPC_IFR_SRAM_PDN_LSB (1U << 16) /* 6b */
+/* DEVAPC_SUBIFR_SRAM_CON (0x10006000+0x388) */
+#define DEVAPC_SUBIFR_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DEVAPC_SUBIFR_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DEVAPC_SUBIFR_SRAM_SLEEP_B_LSB (1U << 4) /* 6b */
+#define DEVAPC_SUBIFR_SRAM_PDN_LSB (1U << 16) /* 6b */
+/* DEVAPC_ACP_SRAM_CON (0x10006000+0x38C) */
+#define DEVAPC_ACP_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DEVAPC_ACP_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DEVAPC_ACP_SRAM_SLEEP_B_LSB (1U << 4) /* 6b */
+#define DEVAPC_ACP_SRAM_PDN_LSB (1U << 16) /* 6b */
+/* USB_SRAM_CON (0x10006000+0x390) */
+#define USB_SRAM_PDN_LSB (1U << 0) /* 7b */
+/* DUMMY_SRAM_CON (0x10006000+0x394) */
+#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+0x398) */
+#define VMODEM_EXT_BUCK_ISO_LSB (1U << 0) /* 1b */
+#define VMD_EXT_BUCK_ISO_LSB (1U << 1) /* 1b */
+/* EXT_BUCK_ISO (0x10006000+0x39C) */
+#define VIMVO_EXT_BUCK_ISO_LSB (1U << 0) /* 1b */
+#define GPU_EXT_BUCK_ISO_LSB (1U << 1) /* 1b */
+#define IPU_EXT_BUCK_ISO_LSB (1U << 5) /* 3b */
+/* DXCC_SRAM_CON (0x10006000+0x3A0) */
+#define DXCC_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DXCC_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DXCC_SRAM_SLEEP_B_LSB (1U << 4) /* 1b */
+#define DXCC_SRAM_PDN_LSB (1U << 16) /* 1b */
+/* MSDC_SRAM_CON (0x10006000+0x3A4) */
+#define MSDC_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define MSDC_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define MSDC_SRAM_SLEEP_B_LSB (1U << 4) /* 5b */
+#define MSDC_SRAM_PDN_LSB (1U << 16) /* 5b */
+/* DEBUGTOP_SRAM_CON (0x10006000+0x3A8) */
+#define DEBUGTOP_SRAM_PDN_LSB (1U << 0) /* 1b */
+/* DP_TX_PWR_CON (0x10006000+0x3AC) */
+#define DP_TX_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define DP_TX_PWR_ISO_LSB (1U << 1) /* 1b */
+#define DP_TX_PWR_ON_LSB (1U << 2) /* 1b */
+#define DP_TX_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define DP_TX_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define DP_TX_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_DP_TX_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* DPMAIF_SRAM_CON (0x10006000+0x3B0) */
+#define DPMAIF_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DPMAIF_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DPMAIF_SRAM_SLEEP_B_LSB (1U << 4) /* 1b */
+#define DPMAIF_SRAM_PDN_LSB (1U << 16) /* 1b */
+/* DPY_SHU2_SRAM_CON (0x10006000+0x3B4) */
+#define DPY_SHU2_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DPY_SHU2_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DPY_SHU2_SRAM_SLEEP_B_LSB (1U << 4) /* 2b */
+#define DPY_SHU2_SRAM_PDN_LSB (1U << 16) /* 2b */
+/* DRAMC_MCU2_SRAM_CON (0x10006000+0x3B8) */
+#define DRAMC_MCU2_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DRAMC_MCU2_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DRAMC_MCU2_SRAM_SLEEP_B_LSB (1U << 4) /* 1b */
+#define DRAMC_MCU2_SRAM_PDN_LSB (1U << 16) /* 1b */
+/* DRAMC_MCU_SRAM_CON (0x10006000+0x3BC) */
+#define DRAMC_MCU_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define DRAMC_MCU_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define DRAMC_MCU_SRAM_SLEEP_B_LSB (1U << 4) /* 1b */
+#define DRAMC_MCU_SRAM_PDN_LSB (1U << 16) /* 1b */
+/* MCUPM_SRAM_CON (0x10006000+0x3C0) */
+#define MCUPM_SRAM_CKISO_LSB (1U << 0) /* 1b */
+#define MCUPM_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */
+#define MCUPM_SRAM_SLEEP_B_LSB (1U << 4) /* 8b */
+#define MCUPM_SRAM_PDN_LSB (1U << 16) /* 8b */
+/* DPY2_PWR_CON (0x10006000+0x3C4) */
+#define DPY2_PWR_RST_B_LSB (1U << 0) /* 1b */
+#define DPY2_PWR_ISO_LSB (1U << 1) /* 1b */
+#define DPY2_PWR_ON_LSB (1U << 2) /* 1b */
+#define DPY2_PWR_ON_2ND_LSB (1U << 3) /* 1b */
+#define DPY2_PWR_CLK_DIS_LSB (1U << 4) /* 1b */
+#define DPY2_SRAM_PDN_LSB (1U << 8) /* 1b */
+#define SC_DPY2_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */
+/* SPM_MEM_CK_SEL (0x10006000+0x400) */
+#define SC_MEM_CK_SEL_LSB (1U << 0) /* 1b */
+#define SPM2CKSYS_MEM_CK_MUX_UPDATE_LSB (1U << 1) /* 1b */
+/* SPM_BUS_PROTECT_MASK_B (0x10006000+0X404) */
+#define SPM_BUS_PROTECT_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_BUS_PROTECT1_MASK_B (0x10006000+0x408) */
+#define SPM_BUS_PROTECT1_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_BUS_PROTECT2_MASK_B (0x10006000+0x40C) */
+#define SPM_BUS_PROTECT2_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_BUS_PROTECT3_MASK_B (0x10006000+0x410) */
+#define SPM_BUS_PROTECT3_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_BUS_PROTECT4_MASK_B (0x10006000+0x414) */
+#define SPM_BUS_PROTECT4_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_EMI_BW_MODE (0x10006000+0x418) */
+#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+0x41C) */
+#define AP2MD_PEER_WAKEUP_LSB (1U << 0) /* 1b */
+/* ULPOSC_CON (0x10006000+0x420) */
+#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+0x424) */
+#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_D2T_LSB (1U << 16) /* 1b */
+#define MM2SPM_DBL_OSTD_ACT_ACK_D2T_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 */
+/* SPM_BUS_PROTECT5_MASK_B (0x10006000+0x428) */
+#define SPM_BUS_PROTECT5_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM2MCUPM_CON (0x10006000+0x42C) */
+#define SPM2MCUPM_SW_RST_B_LSB (1U << 0) /* 1b */
+#define SPM2MCUPM_SW_INT_LSB (1U << 1) /* 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 */
+/* SPM2EMI_ENTER_ULPM (0x10006000+0x434) */
+#define SPM2EMI_ENTER_ULPM_LSB (1U << 0) /* 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 */
+/* SPM_BUS_PROTECT6_MASK_B (0x10006000+0X440) */
+#define SPM_BUS_PROTECT6_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_BUS_PROTECT7_MASK_B (0x10006000+0x444) */
+#define SPM_BUS_PROTECT7_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_BUS_PROTECT8_MASK_B (0x10006000+0x448) */
+#define SPM_BUS_PROTECT8_MASK_B_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_MD32K_CK_OFF_LSB (1U << 17) /* 1b */
+#define SC_CKSQ1_OFF_LSB (1U << 18) /* 1b */
+#define SC_AXI_MEM_CK_OFF_LSB (1U << 19) /* 1b */
+/* CPU_DVFS_REQ (0x10006000+0x450) */
+#define CPU_DVFS_REQ_LSB (1U << 0) /* 32b */
+/* SPM_DRAM_MCU_SW_CON_0 (0x10006000+0x454) */
+#define SW_DDR_PST_REQ_LSB (1U << 0) /* 2b */
+#define SW_DDR_PST_ABORT_REQ_LSB (1U << 2) /* 2b */
+/* SPM_DRAM_MCU_SW_CON_1 (0x10006000+0x458) */
+#define SW_DDR_PST_CH0_LSB (1U << 0) /* 32b */
+/* SPM_DRAM_MCU_SW_CON_2 (0x10006000+0x45C) */
+#define SW_DDR_PST_CH1_LSB (1U << 0) /* 32b */
+/* SPM_DRAM_MCU_SW_CON_3 (0x10006000+0x460) */
+#define SW_DDR_RESERVED_CH0_LSB (1U << 0) /* 32b */
+/* SPM_DRAM_MCU_SW_CON_4 (0x10006000+0x464) */
+#define SW_DDR_RESERVED_CH1_LSB (1U << 0) /* 32b */
+/* SPM_DRAM_MCU_STA_0 (0x10006000+0x468) */
+#define SC_DDR_PST_ACK_LSB (1U << 0) /* 2b */
+#define SC_DDR_PST_ABORT_ACK_LSB (1U << 2) /* 2b */
+/* SPM_DRAM_MCU_STA_1 (0x10006000+0x46C) */
+#define SC_DDR_CUR_PST_STA_CH0_LSB (1U << 0) /* 32b */
+/* SPM_DRAM_MCU_STA_2 (0x10006000+0x470) */
+#define SC_DDR_CUR_PST_STA_CH1_LSB (1U << 0) /* 32b */
+/* SPM_DRAM_MCU_SW_SEL_0 (0x10006000+0x474) */
+#define SW_DDR_PST_REQ_SEL_LSB (1U << 0) /* 2b */
+#define SW_DDR_PST_SEL_LSB (1U << 2) /* 2b */
+#define SW_DDR_PST_ABORT_REQ_SEL_LSB (1U << 4) /* 2b */
+#define SW_DDR_RESERVED_SEL_LSB (1U << 6) /* 2b */
+#define SW_DDR_PST_ACK_SEL_LSB (1U << 8) /* 2b */
+#define SW_DDR_PST_ABORT_ACK_SEL_LSB (1U << 10) /* 2b */
+/* RELAY_DVFS_LEVEL (0x10006000+0x478) */
+#define RELAY_DVFS_LEVEL_LSB (1U << 0) /* 32b */
+/* DRAMC_DPY_CLK_SW_CON_0 (0x10006000+0x480) */
+#define SW_PHYPLL_EN_LSB (1U << 0) /* 2b */
+#define SW_DPY_VREF_EN_LSB (1U << 2) /* 2b */
+#define SW_DPY_DLL_CK_EN_LSB (1U << 4) /* 2b */
+#define SW_DPY_DLL_EN_LSB (1U << 6) /* 2b */
+#define SW_DPY_2ND_DLL_EN_LSB (1U << 8) /* 2b */
+#define SW_MEM_CK_OFF_LSB (1U << 10) /* 2b */
+#define SW_DMSUS_OFF_LSB (1U << 12) /* 2b */
+#define SW_DPY_MODE_SW_LSB (1U << 14) /* 2b */
+#define SW_EMI_CLK_OFF_LSB (1U << 16) /* 2b */
+#define SW_DDRPHY_FB_CK_EN_LSB (1U << 18) /* 2b */
+#define SW_DR_GATE_RETRY_EN_LSB (1U << 20) /* 2b */
+#define SW_DPHY_PRECAL_UP_LSB (1U << 24) /* 2b */
+#define SW_DPY_BCLK_ENABLE_LSB (1U << 26) /* 2b */
+#define SW_TX_TRACKING_DIS_LSB (1U << 28) /* 2b */
+#define SW_DPHY_RXDLY_TRACKING_EN_LSB (1U << 30) /* 2b */
+/* DRAMC_DPY_CLK_SW_CON_1 (0x10006000+0x484) */
+#define SW_SHU_RESTORE_LSB (1U << 0) /* 2b */
+#define SW_DMYRD_MOD_LSB (1U << 2) /* 2b */
+#define SW_DMYRD_INTV_LSB (1U << 4) /* 2b */
+#define SW_DMYRD_EN_LSB (1U << 6) /* 2b */
+#define SW_DRS_DIS_REQ_LSB (1U << 8) /* 2b */
+#define SW_DR_SRAM_LOAD_LSB (1U << 10) /* 2b */
+#define SW_DR_SRAM_RESTORE_LSB (1U << 12) /* 2b */
+#define SW_DR_SHU_LEVEL_SRAM_LATCH_LSB (1U << 14) /* 2b */
+#define SW_TX_TRACK_RETRY_EN_LSB (1U << 16) /* 2b */
+#define SW_DPY_MIDPI_EN_LSB (1U << 18) /* 2b */
+#define SW_DPY_PI_RESETB_EN_LSB (1U << 20) /* 2b */
+#define SW_DPY_MCK8X_EN_LSB (1U << 22) /* 2b */
+#define SW_DR_SHU_LEVEL_SRAM_CH0_LSB (1U << 24) /* 4b */
+#define SW_DR_SHU_LEVEL_SRAM_CH1_LSB (1U << 28) /* 4b */
+/* DRAMC_DPY_CLK_SW_CON_2 (0x10006000+0x488) */
+#define SW_DR_SHU_LEVEL_LSB (1U << 0) /* 2b */
+#define SW_DR_SHU_EN_LSB (1U << 2) /* 1b */
+#define SW_DR_SHORT_QUEUE_LSB (1U << 3) /* 1b */
+#define SW_PHYPLL_MODE_SW_LSB (1U << 4) /* 1b */
+#define SW_PHYPLL2_MODE_SW_LSB (1U << 5) /* 1b */
+#define SW_PHYPLL_SHU_EN_LSB (1U << 6) /* 1b */
+#define SW_PHYPLL2_SHU_EN_LSB (1U << 7) /* 1b */
+#define SW_DR_RESERVED_0_LSB (1U << 24) /* 2b */
+#define SW_DR_RESERVED_1_LSB (1U << 26) /* 2b */
+#define SW_DR_RESERVED_2_LSB (1U << 28) /* 2b */
+#define SW_DR_RESERVED_3_LSB (1U << 30) /* 2b */
+/* DRAMC_DPY_CLK_SW_CON_3 (0x10006000+0x48C) */
+#define SC_DR_SHU_EN_ACK_LSB (1U << 0) /* 4b */
+#define SC_EMI_CLK_OFF_ACK_LSB (1U << 4) /* 4b */
+#define SC_DR_SHORT_QUEUE_ACK_LSB (1U << 8) /* 4b */
+#define SC_DRAMC_DFS_STA_LSB (1U << 12) /* 4b */
+#define SC_DRS_DIS_ACK_LSB (1U << 16) /* 4b */
+#define SC_DR_SRAM_LOAD_ACK_LSB (1U << 20) /* 4b */
+#define SC_DR_SRAM_PLL_LOAD_ACK_LSB (1U << 24) /* 4b */
+#define SC_DR_SRAM_RESTORE_ACK_LSB (1U << 28) /* 4b */
+/* DRAMC_DPY_CLK_SW_SEL_0 (0x10006000+0x490) */
+#define SW_PHYPLL_EN_SEL_LSB (1U << 0) /* 2b */
+#define SW_DPY_VREF_EN_SEL_LSB (1U << 2) /* 2b */
+#define SW_DPY_DLL_CK_EN_SEL_LSB (1U << 4) /* 2b */
+#define SW_DPY_DLL_EN_SEL_LSB (1U << 6) /* 2b */
+#define SW_DPY_2ND_DLL_EN_SEL_LSB (1U << 8) /* 2b */
+#define SW_MEM_CK_OFF_SEL_LSB (1U << 10) /* 2b */
+#define SW_DMSUS_OFF_SEL_LSB (1U << 12) /* 2b */
+#define SW_DPY_MODE_SW_SEL_LSB (1U << 14) /* 2b */
+#define SW_EMI_CLK_OFF_SEL_LSB (1U << 16) /* 2b */
+#define SW_DDRPHY_FB_CK_EN_SEL_LSB (1U << 18) /* 2b */
+#define SW_DR_GATE_RETRY_EN_SEL_LSB (1U << 20) /* 2b */
+#define SW_DPHY_PRECAL_UP_SEL_LSB (1U << 24) /* 2b */
+#define SW_DPY_BCLK_ENABLE_SEL_LSB (1U << 26) /* 2b */
+#define SW_TX_TRACKING_DIS_SEL_LSB (1U << 28) /* 2b */
+#define SW_DPHY_RXDLY_TRACKING_EN_SEL_LSB (1U << 30) /* 2b */
+/* DRAMC_DPY_CLK_SW_SEL_1 (0x10006000+0x494) */
+#define SW_SHU_RESTORE_SEL_LSB (1U << 0) /* 2b */
+#define SW_DMYRD_MOD_SEL_LSB (1U << 2) /* 2b */
+#define SW_DMYRD_INTV_SEL_LSB (1U << 4) /* 2b */
+#define SW_DMYRD_EN_SEL_LSB (1U << 6) /* 2b */
+#define SW_DRS_DIS_REQ_SEL_LSB (1U << 8) /* 2b */
+#define SW_DR_SRAM_LOAD_SEL_LSB (1U << 10) /* 2b */
+#define SW_DR_SRAM_RESTORE_SEL_LSB (1U << 12) /* 2b */
+#define SW_DR_SHU_LEVEL_SRAM_LATCH_SEL_LSB (1U << 14) /* 2b */
+#define SW_TX_TRACK_RETRY_EN_SEL_LSB (1U << 16) /* 2b */
+#define SW_DPY_MIDPI_EN_SEL_LSB (1U << 18) /* 2b */
+#define SW_DPY_PI_RESETB_EN_SEL_LSB (1U << 20) /* 2b */
+#define SW_DPY_MCK8X_EN_SEL_LSB (1U << 22) /* 2b */
+#define SW_DR_SHU_LEVEL_SRAM_SEL_LSB (1U << 24) /* 2b */
+/* DRAMC_DPY_CLK_SW_SEL_2 (0x10006000+0x498) */
+#define SW_DR_SHU_LEVEL_SEL_LSB (1U << 0) /* 1b */
+#define SW_DR_SHU_EN_SEL_LSB (1U << 2) /* 1b */
+#define SW_DR_SHORT_QUEUE_SEL_LSB (1U << 3) /* 1b */
+#define SW_PHYPLL_MODE_SW_SEL_LSB (1U << 4) /* 1b */
+#define SW_PHYPLL2_MODE_SW_SEL_LSB (1U << 5) /* 1b */
+#define SW_PHYPLL_SHU_EN_SEL_LSB (1U << 6) /* 1b */
+#define SW_PHYPLL2_SHU_EN_SEL_LSB (1U << 7) /* 1b */
+#define SW_DR_RESERVED_0_SEL_LSB (1U << 24) /* 2b */
+#define SW_DR_RESERVED_1_SEL_LSB (1U << 26) /* 2b */
+#define SW_DR_RESERVED_2_SEL_LSB (1U << 28) /* 2b */
+#define SW_DR_RESERVED_3_SEL_LSB (1U << 30) /* 2b */
+/* DRAMC_DPY_CLK_SW_SEL_3 (0x10006000+0x49C) */
+#define SC_DR_SHU_EN_ACK_SEL_LSB (1U << 0) /* 4b */
+#define SC_EMI_CLK_OFF_ACK_SEL_LSB (1U << 4) /* 4b */
+#define SC_DR_SHORT_QUEUE_ACK_SEL_LSB (1U << 8) /* 4b */
+#define SC_DRAMC_DFS_STA_SEL_LSB (1U << 12) /* 4b */
+#define SC_DRS_DIS_ACK_SEL_LSB (1U << 16) /* 4b */
+#define SC_DR_SRAM_LOAD_ACK_SEL_LSB (1U << 20) /* 4b */
+#define SC_DR_SRAM_PLL_LOAD_ACK_SEL_LSB (1U << 24) /* 4b */
+#define SC_DR_SRAM_RESTORE_ACK_SEL_LSB (1U << 28) /* 4b */
+/* DRAMC_DPY_CLK_SPM_CON (0x10006000+0x4A0) */
+#define SC_DMYRD_EN_MOD_SEL_PCM_LSB (1U << 0) /* 1b */
+#define SC_DMYRD_INTV_SEL_PCM_LSB (1U << 1) /* 1b */
+#define SC_DMYRD_EN_PCM_LSB (1U << 2) /* 1b */
+#define SC_DRS_DIS_REQ_PCM_LSB (1U << 3) /* 1b */
+#define SC_DR_SHU_LEVEL_SRAM_PCM_LSB (1U << 4) /* 4b */
+#define SC_DR_GATE_RETRY_EN_PCM_LSB (1U << 8) /* 1b */
+#define SC_DR_SHORT_QUEUE_PCM_LSB (1U << 9) /* 1b */
+#define SC_DPY_MIDPI_EN_PCM_LSB (1U << 10) /* 1b */
+#define SC_DPY_PI_RESETB_EN_PCM_LSB (1U << 11) /* 1b */
+#define SC_DPY_MCK8X_EN_PCM_LSB (1U << 12) /* 1b */
+#define SC_DR_RESERVED_0_PCM_LSB (1U << 13) /* 1b */
+#define SC_DR_RESERVED_1_PCM_LSB (1U << 14) /* 1b */
+#define SC_DR_RESERVED_2_PCM_LSB (1U << 15) /* 1b */
+#define SC_DR_RESERVED_3_PCM_LSB (1U << 16) /* 1b */
+#define SC_DMDRAMCSHU_ACK_ALL_LSB (1U << 24) /* 1b */
+#define SC_EMI_CLK_OFF_ACK_ALL_LSB (1U << 25) /* 1b */
+#define SC_DR_SHORT_QUEUE_ACK_ALL_LSB (1U << 26) /* 1b */
+#define SC_DRAMC_DFS_STA_ALL_LSB (1U << 27) /* 1b */
+#define SC_DRS_DIS_ACK_ALL_LSB (1U << 28) /* 1b */
+#define SC_DR_SRAM_LOAD_ACK_ALL_LSB (1U << 29) /* 1b */
+#define SC_DR_SRAM_PLL_LOAD_ACK_ALL_LSB (1U << 30) /* 1b */
+#define SC_DR_SRAM_RESTORE_ACK_ALL_LSB (1U << 31) /* 1b */
+/* SPM_DVFS_LEVEL (0x10006000+0x4A4) */
+#define SPM_DVFS_LEVEL_LSB (1U << 0) /* 32b */
+/* SPM_CIRQ_CON (0x10006000+0x4A8) */
+#define CIRQ_CLK_SEL_LSB (1U << 0) /* 1b */
+/* SPM_DVFS_MISC (0x10006000+0x4AC) */
+#define MSDC_DVFS_REQUEST_LSB (1U << 0) /* 1b */
+#define SPM2EMI_SLP_PROT_EN_LSB (1U << 1) /* 1b */
+#define SPM_DVFS_FORCE_ENABLE_LSB (1U << 2) /* 1b */
+#define FORCE_DVFS_WAKE_LSB (1U << 3) /* 1b */
+#define SPM_DVFSRC_ENABLE_LSB (1U << 4) /* 1b */
+#define SPM_DVFS_DONE_LSB (1U << 5) /* 1b */
+#define DVFSRC_IRQ_WAKEUP_EVENT_MASK_LSB (1U << 6) /* 1b */
+#define SPM2RC_EVENT_ABORT_LSB (1U << 7) /* 1b */
+#define EMI_SLP_IDLE_LSB (1U << 14) /* 1b */
+#define SDIO_READY_TO_SPM_LSB (1U << 15) /* 1b */
+/* SPM_VS1_VS2_RC_CON (0x10006000+0x4B0) */
+#define VS1_INIT_LEVEL_LSB (1U << 0) /* 2b */
+#define VS1_INIT_LSB (1U << 2) /* 1b */
+#define VS1_CURR_LEVEL_LSB (1U << 3) /* 2b */
+#define VS1_NEXT_LEVEL_LSB (1U << 5) /* 2b */
+#define VS1_VOTE_LEVEL_LSB (1U << 7) /* 2b */
+#define VS1_TRIGGER_LSB (1U << 9) /* 1b */
+#define VS2_INIT_LEVEL_LSB (1U << 10) /* 3b */
+#define VS2_INIT_LSB (1U << 13) /* 1b */
+#define VS2_CURR_LEVEL_LSB (1U << 14) /* 3b */
+#define VS2_NEXT_LEVEL_LSB (1U << 17) /* 3b */
+#define VS2_VOTE_LEVEL_LSB (1U << 20) /* 3b */
+#define VS2_TRIGGER_LSB (1U << 23) /* 1b */
+#define VS1_FORCE_LSB (1U << 24) /* 1b */
+#define VS2_FORCE_LSB (1U << 25) /* 1b */
+#define VS1_VOTE_LEVEL_FORCE_LSB (1U << 26) /* 2b */
+#define VS2_VOTE_LEVEL_FORCE_LSB (1U << 28) /* 3b */
+/* RG_MODULE_SW_CG_0_MASK_REQ_0 (0x10006000+0x4B4) */
+#define RG_MODULE_SW_CG_0_MASK_REQ_0_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_0_MASK_REQ_1 (0x10006000+0x4B8) */
+#define RG_MODULE_SW_CG_0_MASK_REQ_1_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_0_MASK_REQ_2 (0x10006000+0x4BC) */
+#define RG_MODULE_SW_CG_0_MASK_REQ_2_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_1_MASK_REQ_0 (0x10006000+0x4C0) */
+#define RG_MODULE_SW_CG_1_MASK_REQ_0_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_1_MASK_REQ_1 (0x10006000+0x4C4) */
+#define RG_MODULE_SW_CG_1_MASK_REQ_1_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_1_MASK_REQ_2 (0x10006000+0x4C8) */
+#define RG_MODULE_SW_CG_1_MASK_REQ_2_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_2_MASK_REQ_0 (0x10006000+0x4CC) */
+#define RG_MODULE_SW_CG_2_MASK_REQ_0_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_2_MASK_REQ_1 (0x10006000+0x4D0) */
+#define RG_MODULE_SW_CG_2_MASK_REQ_1_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_2_MASK_REQ_2 (0x10006000+0x4D4) */
+#define RG_MODULE_SW_CG_2_MASK_REQ_2_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_3_MASK_REQ_0 (0x10006000+0x4D8) */
+#define RG_MODULE_SW_CG_3_MASK_REQ_0_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_3_MASK_REQ_1 (0x10006000+0x4DC) */
+#define RG_MODULE_SW_CG_3_MASK_REQ_1_LSB (1U << 0) /* 32b */
+/* RG_MODULE_SW_CG_3_MASK_REQ_2 (0x10006000+0x4E0) */
+#define RG_MODULE_SW_CG_3_MASK_REQ_2_LSB (1U << 0) /* 32b */
+/* PWR_STATUS_MASK_REQ_0 (0x10006000+0x4E4) */
+#define PWR_STATUS_MASK_REQ_0_LSB (1U << 0) /* 32b */
+/* PWR_STATUS_MASK_REQ_1 (0x10006000+0x4E8) */
+#define PWR_STATUS_MASK_REQ_1_LSB (1U << 0) /* 32b */
+/* PWR_STATUS_MASK_REQ_2 (0x10006000+0x4EC) */
+#define PWR_STATUS_MASK_REQ_2_LSB (1U << 0) /* 32b */
+/* SPM_CG_CHECK_CON (0x10006000+0x4F0) */
+#define APMIXEDSYS_BUSY_MASK_REQ_0_LSB (1U << 0) /* 5b */
+#define APMIXEDSYS_BUSY_MASK_REQ_1_LSB (1U << 8) /* 5b */
+#define APMIXEDSYS_BUSY_MASK_REQ_2_LSB (1U << 16) /* 5b */
+#define AUDIOSYS_BUSY_MASK_REQ_0_LSB (1U << 24) /* 1b */
+#define AUDIOSYS_BUSY_MASK_REQ_1_LSB (1U << 25) /* 1b */
+#define AUDIOSYS_BUSY_MASK_REQ_2_LSB (1U << 26) /* 1b */
+#define SSUSB_BUSY_MASK_REQ_0_LSB (1U << 27) /* 1b */
+#define SSUSB_BUSY_MASK_REQ_1_LSB (1U << 28) /* 1b */
+#define SSUSB_BUSY_MASK_REQ_2_LSB (1U << 29) /* 1b */
+/* SPM_SRC_RDY_STA (0x10006000+0x4F4) */
+#define SPM_INFRA_INTERNAL_ACK_LSB (1U << 0) /* 1b */
+#define SPM_VRF18_INTERNAL_ACK_LSB (1U << 1) /* 1b */
+/* SPM_DVS_DFS_LEVEL (0x10006000+0x4F8) */
+#define SPM_DFS_LEVEL_LSB (1U << 0) /* 16b */
+#define SPM_DVS_LEVEL_LSB (1U << 16) /* 16b */
+/* SPM_FORCE_DVFS (0x10006000+0x4FC) */
+#define FORCE_DVFS_LEVEL_LSB (1U << 0) /* 32b */
+/* SRCLKEN_RC_CFG (0x10006000+0x500) */
+#define SRCLKEN_RC_CFG_LSB (1U << 0) /* 32b */
+/* RC_CENTRAL_CFG1 (0x10006000+0x504) */
+#define RC_CENTRAL_CFG1_LSB (1U << 0) /* 32b */
+/* RC_CENTRAL_CFG2 (0x10006000+0x508) */
+#define RC_CENTRAL_CFG2_LSB (1U << 0) /* 32b */
+/* RC_CMD_ARB_CFG (0x10006000+0x50C) */
+#define RC_CMD_ARB_CFG_LSB (1U << 0) /* 32b */
+/* RC_PMIC_RCEN_ADDR (0x10006000+0x510) */
+#define RC_PMIC_RCEN_ADDR_LSB (1U << 0) /* 16b */
+#define RC_PMIC_RCEN_RESERVE_LSB (1U << 16) /* 16b */
+/* RC_PMIC_RCEN_SET_CLR_ADDR (0x10006000+0x514) */
+#define RC_PMIC_RCEN_SET_ADDR_LSB (1U << 0) /* 16b */
+#define RC_PMIC_RCEN_CLR_ADDR_LSB (1U << 16) /* 16b */
+/* RC_DCXO_FPM_CFG (0x10006000+0x518) */
+#define RC_DCXO_FPM_CFG_LSB (1U << 0) /* 32b */
+/* RC_CENTRAL_CFG3 (0x10006000+0x51C) */
+#define RC_CENTRAL_CFG3_LSB (1U << 0) /* 32b */
+/* RC_M00_SRCLKEN_CFG (0x10006000+0x520) */
+#define RC_M00_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+#define RC_SW_SRCLKEN_RC (1U << 3) /* 1b */
+#define RC_SW_SRCLKEN_FPM (1U << 4) /* 1b */
+/* RC_M01_SRCLKEN_CFG (0x10006000+0x524) */
+#define RC_M01_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M02_SRCLKEN_CFG (0x10006000+0x528) */
+#define RC_M02_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M03_SRCLKEN_CFG (0x10006000+0x52C) */
+#define RC_M03_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M04_SRCLKEN_CFG (0x10006000+0x530) */
+#define RC_M04_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M05_SRCLKEN_CFG (0x10006000+0x534) */
+#define RC_M05_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M06_SRCLKEN_CFG (0x10006000+0x538) */
+#define RC_M06_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M07_SRCLKEN_CFG (0x10006000+0x53C) */
+#define RC_M07_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M08_SRCLKEN_CFG (0x10006000+0x540) */
+#define RC_M08_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M09_SRCLKEN_CFG (0x10006000+0x544) */
+#define RC_M09_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M10_SRCLKEN_CFG (0x10006000+0x548) */
+#define RC_M10_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M11_SRCLKEN_CFG (0x10006000+0x54C) */
+#define RC_M11_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_M12_SRCLKEN_CFG (0x10006000+0x550) */
+#define RC_M12_SRCLKEN_CFG_LSB (1U << 0) /* 32b */
+/* RC_SRCLKEN_SW_CON_CFG (0x10006000+0x554) */
+#define RC_SRCLKEN_SW_CON_CFG_LSB (1U << 0) /* 32b */
+/* RC_CENTRAL_CFG4 (0x10006000+0x558) */
+#define RC_CENTRAL_CFG4_LSB (1U << 0) /* 32b */
+/* RC_PROTOCOL_CHK_CFG (0x10006000+0x560) */
+#define RC_PROTOCOL_CHK_CFG_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_CFG (0x10006000+0x564) */
+#define RC_DEBUG_CFG_LSB (1U << 0) /* 32b */
+/* RC_MISC_0 (0x10006000+0x5B4) */
+#define SRCCLKENO_LSB (1U << 0) /* 2b */
+#define PCM_SRCCLKENO_LSB (1U << 3) /* 2b */
+#define RC_VREQ_LSB (1U << 5) /* 1b */
+#define RC_SPM_SRCCLKENO_0_ACK_LSB (1U << 6) /* 1b */
+/* RC_SPM_CTRL (0x10006000+0x448) */
+#define SPM_AP_26M_RDY_LSB (1U << 0) /* 1b */
+#define KEEP_RC_SPI_ACTIVE_LSB (1U << 1) /* 1b */
+#define SPM2RC_DMY_CTRL_LSB (1U << 2) /* 6b */
+/* SUBSYS_INTF_CFG (0x10006000+0x5BC) */
+#define SRCLKEN_FPM_MASK_B_LSB (1U << 0) /* 13b */
+#define SRCLKEN_BBLPM_MASK_B_LSB (1U << 16) /* 13b */
+/* PCM_WDT_LATCH_25 (0x10006000+0x5C0) */
+#define PCM_WDT_LATCH_25_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_26 (0x10006000+0x5C4) */
+#define PCM_WDT_LATCH_26_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_27 (0x10006000+0x5C8) */
+#define PCM_WDT_LATCH_27_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_28 (0x10006000+0x5CC) */
+#define PCM_WDT_LATCH_28_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_29 (0x10006000+0x5D0) */
+#define PCM_WDT_LATCH_29_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_30 (0x10006000+0x5D4) */
+#define PCM_WDT_LATCH_30_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_31 (0x10006000+0x5D8) */
+#define PCM_WDT_LATCH_31_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_32 (0x10006000+0x5DC) */
+#define PCM_WDT_LATCH_32_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_33 (0x10006000+0x5E0) */
+#define PCM_WDT_LATCH_33_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_34 (0x10006000+0x5E4) */
+#define PCM_WDT_LATCH_34_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_35 (0x10006000+0x5EC) */
+#define PCM_WDT_LATCH_35_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_36 (0x10006000+0x5F0) */
+#define PCM_WDT_LATCH_36_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_37 (0x10006000+0x5F4) */
+#define PCM_WDT_LATCH_37_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_38 (0x10006000+0x5F8) */
+#define PCM_WDT_LATCH_38_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_39 (0x10006000+0x5FC) */
+#define PCM_WDT_LATCH_39_LSB (1U << 0) /* 32b */
+/* SPM_SW_FLAG_0 (0x10006000+0x600) */
+#define SPM_SW_FLAG_LSB (1U << 0) /* 32b */
+/* SPM_SW_DEBUG_0 (0x10006000+0x604) */
+#define SPM_SW_DEBUG_0_LSB (1U << 0) /* 32b */
+/* SPM_SW_FLAG_1 (0x10006000+0x608) */
+#define SPM_SW_FLAG_1_LSB (1U << 0) /* 32b */
+/* SPM_SW_DEBUG_1 (0x10006000+0x60C) */
+#define SPM_SW_DEBUG_1_LSB (1U << 0) /* 32b */
+/* SPM_SW_RSV_0 (0x10006000+0x610) */
+#define SPM_SW_RSV_0_LSB (1U << 0) /* 32b */
+/* SPM_SW_RSV_1 (0x10006000+0x614) */
+#define SPM_SW_RSV_1_LSB (1U << 0) /* 32b */
+/* SPM_SW_RSV_2 (0x10006000+0x618) */
+#define SPM_SW_RSV_2_LSB (1U << 0) /* 32b */
+/* SPM_SW_RSV_3 (0x10006000+0x61C) */
+#define SPM_SW_RSV_3_LSB (1U << 0) /* 32b */
+/* SPM_SW_RSV_4 (0x10006000+0x620) */
+#define SPM_SW_RSV_4_LSB (1U << 0) /* 32b */
+/* SPM_SW_RSV_5 (0x10006000+0x624) */
+#define SPM_SW_RSV_5_LSB (1U << 0) /* 32b */
+/* SPM_SW_RSV_6 (0x10006000+0x628) */
+#define SPM_SW_RSV_6_LSB (1U << 0) /* 32b */
+/* SPM_SW_RSV_7 (0x10006000+0x62C) */
+#define SPM_SW_RSV_7_LSB (1U << 0) /* 32b */
+/* SPM_SW_RSV_8 (0x10006000+0x630) */
+#define SPM_SW_RSV_8_LSB (1U << 0) /* 32b */
+/* SPM_BK_WAKE_EVENT (0x10006000+0x634) */
+#define SPM_BK_WAKE_EVENT_LSB (1U << 0) /* 32b */
+/* SPM_BK_VTCXO_DUR (0x10006000+0x638) */
+#define SPM_BK_VTCXO_DUR_LSB (1U << 0) /* 32b */
+/* SPM_BK_WAKE_MISC (0x10006000+0x63C) */
+#define SPM_BK_WAKE_MISC_LSB (1U << 0) /* 32b */
+/* SPM_BK_PCM_TIMER (0x10006000+0x640) */
+#define SPM_BK_PCM_TIMER_LSB (1U << 0) /* 32b */
+/* SPM_RSV_CON_0 (0x10006000+0x650) */
+#define SPM_RSV_CON_0_LSB (1U << 0) /* 32b */
+/* SPM_RSV_CON_1 (0x10006000+0x654) */
+#define SPM_RSV_CON_1_LSB (1U << 0) /* 32b */
+/* SPM_RSV_STA_0 (0x10006000+0x658) */
+#define SPM_RSV_STA_0_LSB (1U << 0) /* 32b */
+/* SPM_RSV_STA_1 (0x10006000+0x65C) */
+#define SPM_RSV_STA_1_LSB (1U << 0) /* 32b */
+/* SPM_SPARE_CON (0x10006000+0x660) */
+#define SPM_SPARE_CON_LSB (1U << 0) /* 32b */
+/* SPM_SPARE_CON_SET (0x10006000+0x664) */
+#define SPM_SPARE_CON_SET_LSB (1U << 0) /* 32b */
+/* SPM_SPARE_CON_CLR (0x10006000+0x668) */
+#define SPM_SPARE_CON_CLR_LSB (1U << 0) /* 32b */
+/* SPM_CROSS_WAKE_M00_REQ (0x10006000+0x66C) */
+#define SPM_CROSS_WAKE_M00_REQ_LSB (1U << 0) /* 4b */
+#define SPM_CROSS_WAKE_M00_CHK_LSB (1U << 4) /* 4b */
+/* SPM_CROSS_WAKE_M01_REQ (0x10006000+0x670) */
+#define SPM_CROSS_WAKE_M01_REQ_LSB (1U << 0) /* 4b */
+#define SPM_CROSS_WAKE_M01_CHK_LSB (1U << 4) /* 4b */
+/* SPM_CROSS_WAKE_M02_REQ (0x10006000+0x674) */
+#define SPM_CROSS_WAKE_M02_REQ_LSB (1U << 0) /* 4b */
+#define SPM_CROSS_WAKE_M02_CHK_LSB (1U << 4) /* 4b */
+/* SPM_CROSS_WAKE_M03_REQ (0x10006000+0x678) */
+#define SPM_CROSS_WAKE_M03_REQ_LSB (1U << 0) /* 4b */
+#define SPM_CROSS_WAKE_M03_CHK_LSB (1U << 4) /* 4b */
+/* SCP_VCORE_LEVEL (0x10006000+0x67C) */
+#define SCP_VCORE_LEVEL_LSB (1U << 0) /* 16b */
+/* SC_MM_CK_SEL_CON (0x10006000+0x680) */
+#define SC_MM_CK_SEL_LSB (1U << 0) /* 4b */
+#define SC_MM_CK_SEL_EN_LSB (1U << 4) /* 1b */
+/* SPARE_ACK_MASK (0x10006000+0x684) */
+#define SPARE_ACK_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_DV_CON_0 (0x10006000+0x68C) */
+#define SPM_DV_CON_0_LSB (1U << 0) /* 32b */
+/* SPM_DV_CON_1 (0x10006000+0x690) */
+#define SPM_DV_CON_1_LSB (1U << 0) /* 32b */
+/* SPM_DV_STA (0x10006000+0x694) */
+#define SPM_DV_STA_LSB (1U << 0) /* 32b */
+/* CONN_XOWCN_DEBUG_EN (0x10006000+0x698) */
+#define CONN_XOWCN_DEBUG_EN_LSB (1U << 0) /* 1b */
+/* SPM_SEMA_M0 (0x10006000+0x69C) */
+#define SPM_SEMA_M0_LSB (1U << 0) /* 8b */
+/* SPM_SEMA_M1 (0x10006000+0x6A0) */
+#define SPM_SEMA_M1_LSB (1U << 0) /* 8b */
+/* SPM_SEMA_M2 (0x10006000+0x6A4) */
+#define SPM_SEMA_M2_LSB (1U << 0) /* 8b */
+/* SPM_SEMA_M3 (0x10006000+0x6A8) */
+#define SPM_SEMA_M3_LSB (1U << 0) /* 8b */
+/* SPM_SEMA_M4 (0x10006000+0x6AC) */
+#define SPM_SEMA_M4_LSB (1U << 0) /* 8b */
+/* SPM_SEMA_M5 (0x10006000+0x6B0) */
+#define SPM_SEMA_M5_LSB (1U << 0) /* 8b */
+/* SPM_SEMA_M6 (0x10006000+0x6B4) */
+#define SPM_SEMA_M6_LSB (1U << 0) /* 8b */
+/* SPM_SEMA_M7 (0x10006000+0x6B8) */
+#define SPM_SEMA_M7_LSB (1U << 0) /* 8b */
+/* SPM2ADSP_MAILBOX (0x10006000+0x6BC) */
+#define SPM2ADSP_MAILBOX_LSB (1U << 0) /* 32b */
+/* ADSP2SPM_MAILBOX (0x10006000+0x6C0) */
+#define ADSP2SPM_MAILBOX_LSB (1U << 0) /* 32b */
+/* SPM_ADSP_IRQ (0x10006000+0x6C4) */
+#define SC_SPM2ADSP_WAKEUP_LSB (1U << 0) /* 1b */
+#define SPM_ADSP_IRQ_SC_ADSP2SPM_WAKEUP_LSB (1U << 4) /* 1b */
+/* SPM_MD32_IRQ (0x10006000+0x6C8) */
+#define SC_SPM2SSPM_WAKEUP_LSB (1U << 0) /* 4b */
+#define SPM_MD32_IRQ_SC_SSPM2SPM_WAKEUP_LSB (1U << 4) /* 4b */
+/* SPM2PMCU_MAILBOX_0 (0x10006000+0x6CC) */
+#define SPM2PMCU_MAILBOX_0_LSB (1U << 0) /* 32b */
+/* SPM2PMCU_MAILBOX_1 (0x10006000+0x6D0) */
+#define SPM2PMCU_MAILBOX_1_LSB (1U << 0) /* 32b */
+/* SPM2PMCU_MAILBOX_2 (0x10006000+0x6D4) */
+#define SPM2PMCU_MAILBOX_2_LSB (1U << 0) /* 32b */
+/* SPM2PMCU_MAILBOX_3 (0x10006000+0x6D8) */
+#define SPM2PMCU_MAILBOX_3_LSB (1U << 0) /* 32b */
+/* PMCU2SPM_MAILBOX_0 (0x10006000+0x6DC) */
+#define PMCU2SPM_MAILBOX_0_LSB (1U << 0) /* 32b */
+/* PMCU2SPM_MAILBOX_1 (0x10006000+0x6E0) */
+#define PMCU2SPM_MAILBOX_1_LSB (1U << 0) /* 32b */
+/* PMCU2SPM_MAILBOX_2 (0x10006000+0x6E4) */
+#define PMCU2SPM_MAILBOX_2_LSB (1U << 0) /* 32b */
+/* PMCU2SPM_MAILBOX_3 (0x10006000+0x6E8) */
+#define PMCU2SPM_MAILBOX_3_LSB (1U << 0) /* 32b */
+/* UFS_PSRI_SW (0x10006000+0x6EC) */
+#define UFS_PSRI_SW_LSB (1U << 0) /* 1b */
+/* UFS_PSRI_SW_SET (0x10006000+0x6F0) */
+#define UFS_PSRI_SW_SET_LSB (1U << 0) /* 1b */
+/* UFS_PSRI_SW_CLR (0x10006000+0x6F4) */
+#define UFS_PSRI_SW_CLR_LSB (1U << 0) /* 1b */
+/* SPM_AP_SEMA (0x10006000+0x6F8) */
+#define SPM_AP_SEMA_LSB (1U << 0) /* 1b */
+/* SPM_SPM_SEMA (0x10006000+0x6FC) */
+#define SPM_SPM_SEMA_LSB (1U << 0) /* 1b */
+/* SPM_DVFS_CON (0x10006000+0x700) */
+#define SPM_DVFS_CON_LSB (1U << 0) /* 32b */
+/* SPM_DVFS_CON_STA (0x10006000+0x704) */
+#define SPM_DVFS_CON_STA_LSB (1U << 0) /* 32b */
+/* SPM_PMIC_SPMI_CON (0x10006000+0x708) */
+#define SPM_PMIC_SPMI_CMD_LSB (1U << 0) /* 2b */
+#define SPM_PMIC_SPMI_SLAVEID_LSB (1U << 2) /* 4b */
+#define SPM_PMIC_SPMI_PMIFID_LSB (1U << 6) /* 1b */
+#define SPM_PMIC_SPMI_DBCNT_LSB (1U << 7) /* 1b */
+/* 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 */
+/* SPM_DVFS_CMD16 (0x10006000+0x750) */
+#define SPM_DVFS_CMD16_LSB (1U << 0) /* 32b */
+/* SPM_DVFS_CMD17 (0x10006000+0x754) */
+#define SPM_DVFS_CMD17_LSB (1U << 0) /* 32b */
+/* SPM_DVFS_CMD18 (0x10006000+0x758) */
+#define SPM_DVFS_CMD18_LSB (1U << 0) /* 32b */
+/* SPM_DVFS_CMD19 (0x10006000+0x75C) */
+#define SPM_DVFS_CMD19_LSB (1U << 0) /* 32b */
+/* SPM_DVFS_CMD20 (0x10006000+0x760) */
+#define SPM_DVFS_CMD20_LSB (1U << 0) /* 32b */
+/* SPM_DVFS_CMD21 (0x10006000+0x764) */
+#define SPM_DVFS_CMD21_LSB (1U << 0) /* 32b */
+/* SPM_DVFS_CMD22 (0x10006000+0x768) */
+#define SPM_DVFS_CMD22_LSB (1U << 0) /* 32b */
+/* SPM_DVFS_CMD23 (0x10006000+0x76C) */
+#define SPM_DVFS_CMD23_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_VALUE_L (0x10006000+0x770) */
+#define SYS_TIMER_VALUE_L_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_VALUE_H (0x10006000+0x774) */
+#define SYS_TIMER_VALUE_H_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_START_L (0x10006000+0x778) */
+#define SYS_TIMER_START_L_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_START_H (0x10006000+0x77C) */
+#define SYS_TIMER_START_H_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_00 (0x10006000+0x780) */
+#define SYS_TIMER_LATCH_L_00_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_00 (0x10006000+0x784) */
+#define SYS_TIMER_LATCH_H_00_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_01 (0x10006000+0x788) */
+#define SYS_TIMER_LATCH_L_01_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_01 (0x10006000+0x78C) */
+#define SYS_TIMER_LATCH_H_01_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_02 (0x10006000+0x790) */
+#define SYS_TIMER_LATCH_L_02_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_02 (0x10006000+0x794) */
+#define SYS_TIMER_LATCH_H_02_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_03 (0x10006000+0x798) */
+#define SYS_TIMER_LATCH_L_03_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_03 (0x10006000+0x79C) */
+#define SYS_TIMER_LATCH_H_03_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_04 (0x10006000+0x7A0) */
+#define SYS_TIMER_LATCH_L_04_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_04 (0x10006000+0x7A4) */
+#define SYS_TIMER_LATCH_H_04_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_05 (0x10006000+0x7A8) */
+#define SYS_TIMER_LATCH_L_05_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_05 (0x10006000+0x7AC) */
+#define SYS_TIMER_LATCH_H_05_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_06 (0x10006000+0x7B0) */
+#define SYS_TIMER_LATCH_L_06_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_06 (0x10006000+0x7B4) */
+#define SYS_TIMER_LATCH_H_06_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_07 (0x10006000+0x7B8) */
+#define SYS_TIMER_LATCH_L_07_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_07 (0x10006000+0x7BC) */
+#define SYS_TIMER_LATCH_H_07_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_08 (0x10006000+0x7C0) */
+#define SYS_TIMER_LATCH_L_08_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_08 (0x10006000+0x7C4) */
+#define SYS_TIMER_LATCH_H_08_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_09 (0x10006000+0x7C8) */
+#define SYS_TIMER_LATCH_L_09_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_09 (0x10006000+0x7CC) */
+#define SYS_TIMER_LATCH_H_09_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_10 (0x10006000+0x7D0) */
+#define SYS_TIMER_LATCH_L_10_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_10 (0x10006000+0x7D4) */
+#define SYS_TIMER_LATCH_H_10_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_11 (0x10006000+0x7D8) */
+#define SYS_TIMER_LATCH_L_11_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_11 (0x10006000+0x7DC) */
+#define SYS_TIMER_LATCH_H_11_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_12 (0x10006000+0x7E0) */
+#define SYS_TIMER_LATCH_L_12_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_12 (0x10006000+0x7E4) */
+#define SYS_TIMER_LATCH_H_12_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_13 (0x10006000+0x7E8) */
+#define SYS_TIMER_LATCH_L_13_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_13 (0x10006000+0x7EC) */
+#define SYS_TIMER_LATCH_H_13_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_14 (0x10006000+0x7F0) */
+#define SYS_TIMER_LATCH_L_14_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_14 (0x10006000+0x7F4) */
+#define SYS_TIMER_LATCH_H_14_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_L_15 (0x10006000+0x7F8) */
+#define SYS_TIMER_LATCH_L_15_LSB (1U << 0) /* 32b */
+/* SYS_TIMER_LATCH_H_15 (0x10006000+0x7FC) */
+#define SYS_TIMER_LATCH_H_15_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 */
+/* PCM_WDT_LATCH_10 (0x10006000+0x828) */
+#define PCM_WDT_LATCH_10_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_11 (0x10006000+0x82C) */
+#define PCM_WDT_LATCH_11_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_12 (0x10006000+0x830) */
+#define PCM_WDT_LATCH_12_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_13 (0x10006000+0x834) */
+#define PCM_WDT_LATCH_13_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_14 (0x10006000+0x838) */
+#define PCM_WDT_LATCH_14_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_15 (0x10006000+0x83C) */
+#define PCM_WDT_LATCH_15_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_16 (0x10006000+0x840) */
+#define PCM_WDT_LATCH_16_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_17 (0x10006000+0x844) */
+#define PCM_WDT_LATCH_17_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_18 (0x10006000+0x848) */
+#define PCM_WDT_LATCH_18_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_SPARE_0 (0x10006000+0x84C) */
+#define PCM_WDT_LATCH_SPARE_0_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_SPARE_1 (0x10006000+0x850) */
+#define PCM_WDT_LATCH_SPARE_1_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_SPARE_2 (0x10006000+0x854) */
+#define PCM_WDT_LATCH_SPARE_2_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_CONN_0 (0x10006000+0x870) */
+#define PCM_WDT_LATCH_CONN_0_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_CONN_1 (0x10006000+0x874) */
+#define PCM_WDT_LATCH_CONN_1_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_CONN_2 (0x10006000+0x878) */
+#define PCM_WDT_LATCH_CONN_2_LSB (1U << 0) /* 32b */
+/* DRAMC_GATING_ERR_LATCH_CH0_0 (0x10006000+0x8A0) */
+#define DRAMC_GATING_ERR_LATCH_CH0_0_LSB (1U << 0) /* 32b */
+/* DRAMC_GATING_ERR_LATCH_CH0_1 (0x10006000+0x8A4) */
+#define DRAMC_GATING_ERR_LATCH_CH0_1_LSB (1U << 0) /* 32b */
+/* DRAMC_GATING_ERR_LATCH_CH0_2 (0x10006000+0x8A8) */
+#define DRAMC_GATING_ERR_LATCH_CH0_2_LSB (1U << 0) /* 32b */
+/* DRAMC_GATING_ERR_LATCH_CH0_3 (0x10006000+0x8AC) */
+#define DRAMC_GATING_ERR_LATCH_CH0_3_LSB (1U << 0) /* 32b */
+/* DRAMC_GATING_ERR_LATCH_CH0_4 (0x10006000+0x8B0) */
+#define DRAMC_GATING_ERR_LATCH_CH0_4_LSB (1U << 0) /* 32b */
+/* DRAMC_GATING_ERR_LATCH_CH0_5 (0x10006000+0x8B4) */
+#define DRAMC_GATING_ERR_LATCH_CH0_5_LSB (1U << 0) /* 32b */
+/* DRAMC_GATING_ERR_LATCH_CH0_6 (0x10006000+0x8B8) */
+#define DRAMC_GATING_ERR_LATCH_CH0_6_LSB (1U << 0) /* 32b */
+/* DRAMC_GATING_ERR_LATCH_SPARE_0 (0x10006000+0x8F4) */
+#define DRAMC_GATING_ERR_LATCH_SPARE_0_LSB (1U << 0) /* 32b */
+/* SPM_ACK_CHK_CON_0 (0x10006000+0x900) */
+#define SPM_ACK_CHK_SW_EN_0_LSB (1U << 0) /* 1b */
+#define SPM_ACK_CHK_CLR_ALL_0_LSB (1U << 1) /* 1b */
+#define SPM_ACK_CHK_CLR_TIMER_0_LSB (1U << 2) /* 1b */
+#define SPM_ACK_CHK_CLR_IRQ_0_LSB (1U << 3) /* 1b */
+#define SPM_ACK_CHK_STA_EN_0_LSB (1U << 4) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_EN_0_LSB (1U << 5) /* 1b */
+#define SPM_ACK_CHK_WDT_EN_0_LSB (1U << 6) /* 1b */
+#define SPM_ACK_CHK_LOCK_PC_TRACE_EN_0_LSB (1U << 7) /* 1b */
+#define SPM_ACK_CHK_HW_EN_0_LSB (1U << 8) /* 1b */
+#define SPM_ACK_CHK_HW_MODE_0_LSB (1U << 9) /* 3b */
+#define SPM_ACK_CHK_FAIL_0_LSB (1U << 15) /* 1b */
+/* SPM_ACK_CHK_PC_0 (0x10006000+0x904) */
+#define SPM_ACK_CHK_HW_TRIG_PC_VAL_0_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_HW_TARG_PC_VAL_0_LSB (1U << 16) /* 16b */
+/* SPM_ACK_CHK_SEL_0 (0x10006000+0x908) */
+#define SPM_ACK_CHK_HW_TRIG_SIGNAL_SEL_0_LSB (1U << 0) /* 5b */
+#define SPM_ACK_CHK_HW_TRIG_GROUP_SEL_0_LSB (1U << 5) /* 3b */
+#define SPM_ACK_CHK_HW_TARG_SIGNAL_SEL_0_LSB (1U << 16) /* 5b */
+#define SPM_ACK_CHK_HW_TARG_GROUP_SEL_0_LSB (1U << 21) /* 3b */
+/* SPM_ACK_CHK_TIMER_0 (0x10006000+0x90C) */
+#define SPM_ACK_CHK_TIMER_VAL_0_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_TIMER_0_LSB (1U << 16) /* 16b */
+/* SPM_ACK_CHK_STA_0 (0x10006000+0x910) */
+#define SPM_ACK_CHK_STA_0_LSB (1U << 0) /* 32b */
+/* SPM_ACK_CHK_SWINT_0 (0x10006000+0x914) */
+#define SPM_ACK_CHK_SWINT_EN_0_LSB (1U << 0) /* 32b */
+/* SPM_ACK_CHK_CON_1 (0x10006000+0x920) */
+#define SPM_ACK_CHK_SW_EN_1_LSB (1U << 0) /* 1b */
+#define SPM_ACK_CHK_CLR_ALL_1_LSB (1U << 1) /* 1b */
+#define SPM_ACK_CHK_CLR_TIMER_1_LSB (1U << 2) /* 1b */
+#define SPM_ACK_CHK_CLR_IRQ_1_LSB (1U << 3) /* 1b */
+#define SPM_ACK_CHK_STA_EN_1_LSB (1U << 4) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_EN_1_LSB (1U << 5) /* 1b */
+#define SPM_ACK_CHK_WDT_EN_1_LSB (1U << 6) /* 1b */
+#define SPM_ACK_CHK_LOCK_PC_TRACE_EN_1_LSB (1U << 7) /* 1b */
+#define SPM_ACK_CHK_HW_EN_1_LSB (1U << 8) /* 1b */
+#define SPM_ACK_CHK_HW_MODE_1_LSB (1U << 9) /* 3b */
+#define SPM_ACK_CHK_FAIL_1_LSB (1U << 15) /* 1b */
+/* SPM_ACK_CHK_PC_1 (0x10006000+0x924) */
+#define SPM_ACK_CHK_HW_TRIG_PC_VAL_1_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_HW_TARG_PC_VAL_1_LSB (1U << 16) /* 16b */
+/* SPM_ACK_CHK_SEL_1 (0x10006000+0x928) */
+#define SPM_ACK_CHK_HW_TRIG_SIGNAL_SEL_1_LSB (1U << 0) /* 5b */
+#define SPM_ACK_CHK_HW_TRIG_GROUP_SEL_1_LSB (1U << 5) /* 3b */
+#define SPM_ACK_CHK_HW_TARG_SIGNAL_SEL_1_LSB (1U << 16) /* 5b */
+#define SPM_ACK_CHK_HW_TARG_GROUP_SEL_1_LSB (1U << 21) /* 3b */
+/* SPM_ACK_CHK_TIMER_1 (0x10006000+0x92C) */
+#define SPM_ACK_CHK_TIMER_VAL_1_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_TIMER_1_LSB (1U << 16) /* 16b */
+/* SPM_ACK_CHK_STA_1 (0x10006000+0x930) */
+#define SPM_ACK_CHK_STA_1_LSB (1U << 0) /* 32b */
+/* SPM_ACK_CHK_SWINT_1 (0x10006000+0x934) */
+#define SPM_ACK_CHK_SWINT_EN_1_LSB (1U << 0) /* 32b */
+/* SPM_ACK_CHK_CON_2 (0x10006000+0x940) */
+#define SPM_ACK_CHK_SW_EN_2_LSB (1U << 0) /* 1b */
+#define SPM_ACK_CHK_CLR_ALL_2_LSB (1U << 1) /* 1b */
+#define SPM_ACK_CHK_CLR_TIMER_2_LSB (1U << 2) /* 1b */
+#define SPM_ACK_CHK_CLR_IRQ_2_LSB (1U << 3) /* 1b */
+#define SPM_ACK_CHK_STA_EN_2_LSB (1U << 4) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_EN_2_LSB (1U << 5) /* 1b */
+#define SPM_ACK_CHK_WDT_EN_2_LSB (1U << 6) /* 1b */
+#define SPM_ACK_CHK_LOCK_PC_TRACE_EN_2_LSB (1U << 7) /* 1b */
+#define SPM_ACK_CHK_HW_EN_2_LSB (1U << 8) /* 1b */
+#define SPM_ACK_CHK_HW_MODE_2_LSB (1U << 9) /* 3b */
+#define SPM_ACK_CHK_FAIL_2_LSB (1U << 15) /* 1b */
+/* SPM_ACK_CHK_PC_2 (0x10006000+0x944) */
+#define SPM_ACK_CHK_HW_TRIG_PC_VAL_2_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_HW_TARG_PC_VAL_2_LSB (1U << 16) /* 16b */
+/* SPM_ACK_CHK_SEL_2 (0x10006000+0x948) */
+#define SPM_ACK_CHK_HW_TRIG_SIGNAL_SEL_2_LSB (1U << 0) /* 5b */
+#define SPM_ACK_CHK_HW_TRIG_GROUP_SEL_2_LSB (1U << 5) /* 3b */
+#define SPM_ACK_CHK_HW_TARG_SIGNAL_SEL_2_LSB (1U << 16) /* 5b */
+#define SPM_ACK_CHK_HW_TARG_GROUP_SEL_2_LSB (1U << 21) /* 3b */
+/* SPM_ACK_CHK_TIMER_2 (0x10006000+0x94C) */
+#define SPM_ACK_CHK_TIMER_VAL_2_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_TIMER_2_LSB (1U << 16) /* 16b */
+/* SPM_ACK_CHK_STA_2 (0x10006000+0x950) */
+#define SPM_ACK_CHK_STA_2_LSB (1U << 0) /* 32b */
+/* SPM_ACK_CHK_SWINT_2 (0x10006000+0x954) */
+#define SPM_ACK_CHK_SWINT_EN_2_LSB (1U << 0) /* 32b */
+/* SPM_ACK_CHK_CON_3 (0x10006000+0x960) */
+#define SPM_ACK_CHK_SW_EN_3_LSB (1U << 0) /* 1b */
+#define SPM_ACK_CHK_CLR_ALL_3_LSB (1U << 1) /* 1b */
+#define SPM_ACK_CHK_CLR_TIMER_3_LSB (1U << 2) /* 1b */
+#define SPM_ACK_CHK_CLR_IRQ_3_LSB (1U << 3) /* 1b */
+#define SPM_ACK_CHK_STA_EN_3_LSB (1U << 4) /* 1b */
+#define SPM_ACK_CHK_WAKEUP_EN_3_LSB (1U << 5) /* 1b */
+#define SPM_ACK_CHK_WDT_EN_3_LSB (1U << 6) /* 1b */
+#define SPM_ACK_CHK_LOCK_PC_TRACE_EN_3_LSB (1U << 7) /* 1b */
+#define SPM_ACK_CHK_HW_EN_3_LSB (1U << 8) /* 1b */
+#define SPM_ACK_CHK_HW_MODE_3_LSB (1U << 9) /* 3b */
+#define SPM_ACK_CHK_FAIL_3_LSB (1U << 15) /* 1b */
+/* SPM_ACK_CHK_PC_3 (0x10006000+0x964) */
+#define SPM_ACK_CHK_HW_TRIG_PC_VAL_3_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_HW_TARG_PC_VAL_3_LSB (1U << 16) /* 16b */
+/* SPM_ACK_CHK_SEL_3 (0x10006000+0x968) */
+#define SPM_ACK_CHK_HW_TRIG_SIGNAL_SEL_3_LSB (1U << 0) /* 5b */
+#define SPM_ACK_CHK_HW_TRIG_GROUP_SEL_3_LSB (1U << 5) /* 3b */
+#define SPM_ACK_CHK_HW_TARG_SIGNAL_SEL_3_LSB (1U << 16) /* 5b */
+#define SPM_ACK_CHK_HW_TARG_GROUP_SEL_3_LSB (1U << 21) /* 3b */
+/* SPM_ACK_CHK_TIMER_3 (0x10006000+0x96C) */
+#define SPM_ACK_CHK_TIMER_VAL_3_LSB (1U << 0) /* 16b */
+#define SPM_ACK_CHK_TIMER_3_LSB (1U << 16) /* 16b */
+/* SPM_ACK_CHK_STA_3 (0x10006000+0x970) */
+#define SPM_ACK_CHK_STA_3_LSB (1U << 0) /* 32b */
+/* SPM_ACK_CHK_SWINT_3 (0x10006000+0x974) */
+#define SPM_ACK_CHK_SWINT_EN_3_LSB (1U << 0) /* 32b */
+/* SPM_COUNTER_0 (0x10006000+0x978) */
+#define SPM_COUNTER_VAL_0_LSB (1U << 0) /* 14b */
+#define SPM_COUNTER_OUT_0_LSB (1U << 14) /* 14b */
+#define SPM_COUNTER_EN_0_LSB (1U << 28) /* 1b */
+#define SPM_COUNTER_CLR_0_LSB (1U << 29) /* 1b */
+#define SPM_COUNTER_TIMEOUT_0_LSB (1U << 30) /* 1b */
+#define SPM_COUNTER_WAKEUP_EN_0_LSB (1U << 31) /* 1b */
+/* SPM_COUNTER_1 (0x10006000+0x97C) */
+#define SPM_COUNTER_VAL_1_LSB (1U << 0) /* 14b */
+#define SPM_COUNTER_OUT_1_LSB (1U << 14) /* 14b */
+#define SPM_COUNTER_EN_1_LSB (1U << 28) /* 1b */
+#define SPM_COUNTER_CLR_1_LSB (1U << 29) /* 1b */
+#define SPM_COUNTER_TIMEOUT_1_LSB (1U << 30) /* 1b */
+#define SPM_COUNTER_WAKEUP_EN_1_LSB (1U << 31) /* 1b */
+/* SPM_COUNTER_2 (0x10006000+0x980) */
+#define SPM_COUNTER_VAL_2_LSB (1U << 0) /* 14b */
+#define SPM_COUNTER_OUT_2_LSB (1U << 14) /* 14b */
+#define SPM_COUNTER_EN_2_LSB (1U << 28) /* 1b */
+#define SPM_COUNTER_CLR_2_LSB (1U << 29) /* 1b */
+#define SPM_COUNTER_TIMEOUT_2_LSB (1U << 30) /* 1b */
+#define SPM_COUNTER_WAKEUP_EN_2_LSB (1U << 31) /* 1b */
+/* SYS_TIMER_CON (0x10006000+0x98C) */
+#define SYS_TIMER_START_EN_LSB (1U << 0) /* 1b */
+#define SYS_TIMER_LATCH_EN_LSB (1U << 1) /* 1b */
+#define SYS_TIMER_ID_LSB (1U << 8) /* 8b */
+#define SYS_TIMER_VALID_LSB (1U << 31) /* 1b */
+/* RC_FSM_STA_0 (0x10006000+0xE00) */
+#define RC_FSM_STA_0_LSB (1U << 0) /* 32b */
+/* RC_CMD_STA_0 (0x10006000+0xE04) */
+#define RC_CMD_STA_0_LSB (1U << 0) /* 32b */
+/* RC_CMD_STA_1 (0x10006000+0xE08) */
+#define RC_CMD_STA_1_LSB (1U << 0) /* 32b */
+/* RC_SPI_STA_0 (0x10006000+0xE0C) */
+#define RC_SPI_STA_0_LSB (1U << 0) /* 32b */
+/* RC_PI_PO_STA_0 (0x10006000+0xE10) */
+#define RC_PI_PO_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M00_REQ_STA_0 (0x10006000+0xE14) */
+#define RC_M00_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M01_REQ_STA_0 (0x10006000+0xE1C) */
+#define RC_M01_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M02_REQ_STA_0 (0x10006000+0xE20) */
+#define RC_M02_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M03_REQ_STA_0 (0x10006000+0xE24) */
+#define RC_M03_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M04_REQ_STA_0 (0x10006000+0xE28) */
+#define RC_M04_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M05_REQ_STA_0 (0x10006000+0xE2C) */
+#define RC_M05_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M06_REQ_STA_0 (0x10006000+0xE30) */
+#define RC_M06_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M07_REQ_STA_0 (0x10006000+0xE34) */
+#define RC_M07_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M08_REQ_STA_0 (0x10006000+0xE38) */
+#define RC_M08_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M09_REQ_STA_0 (0x10006000+0xE3C) */
+#define RC_M09_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M10_REQ_STA_0 (0x10006000+0xE40) */
+#define RC_M10_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M11_REQ_STA_0 (0x10006000+0xE44) */
+#define RC_M11_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_M12_REQ_STA_0 (0x10006000+0xE48) */
+#define RC_M12_REQ_STA_0_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_STA_0 (0x10006000+0xE4C) */
+#define RC_DEBUG_STA_0_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_0_LSB (0x10006000+0xE50) */
+#define RO_PMRC_TRACE_00_LSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_0_MSB (0x10006000+0xE54) */
+#define RO_PMRC_TRACE_00_MSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_1_LSB (0x10006000+0xE5C) */
+#define RO_PMRC_TRACE_01_LSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_1_MSB (0x10006000+0xE60) */
+#define RO_PMRC_TRACE_01_MSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_2_LSB (0x10006000+0xE64) */
+#define RO_PMRC_TRACE_02_LSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_2_MSB (0x10006000+0xE6C) */
+#define RO_PMRC_TRACE_02_MSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_3_LSB (0x10006000+0xE70) */
+#define RO_PMRC_TRACE_03_LSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_3_MSB (0x10006000+0xE74) */
+#define RO_PMRC_TRACE_03_MSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_4_LSB (0x10006000+0xE78) */
+#define RO_PMRC_TRACE_04_LSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_4_MSB (0x10006000+0xE7C) */
+#define RO_PMRC_TRACE_04_MSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_5_LSB (0x10006000+0xE80) */
+#define RO_PMRC_TRACE_05_LSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_5_MSB (0x10006000+0xE84) */
+#define RO_PMRC_TRACE_05_MSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_6_LSB (0x10006000+0xE88) */
+#define RO_PMRC_TRACE_06_LSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_6_MSB (0x10006000+0xE8C) */
+#define RO_PMRC_TRACE_06_MSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_7_LSB (0x10006000+0xE90) */
+#define RO_PMRC_TRACE_07_LSB_LSB (1U << 0) /* 32b */
+/* RC_DEBUG_TRACE_7_MSB (0x10006000+0xE94) */
+#define RO_PMRC_TRACE_07_MSB_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_0_LSB (0x10006000+0xE98) */
+#define RC_SYS_TIMER_LATCH_L_00_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_0_MSB (0x10006000+0xE9C) */
+#define RC_SYS_TIMER_LATCH_H_00_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_1_LSB (0x10006000+0xEA0) */
+#define RC_SYS_TIMER_LATCH_L_01_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_1_MSB (0x10006000+0xEA4) */
+#define RC_SYS_TIMER_LATCH_H_01_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_2_LSB (0x10006000+0xEA8) */
+#define RC_SYS_TIMER_LATCH_L_02_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_2_MSB (0x10006000+0xEAC) */
+#define RC_SYS_TIMER_LATCH_H_02_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_3_LSB (0x10006000+0xEB0) */
+#define RC_SYS_TIMER_LATCH_L_03_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_3_MSB (0x10006000+0xEB4) */
+#define RC_SYS_TIMER_LATCH_H_03_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_4_LSB (0x10006000+0xEB8) */
+#define RC_SYS_TIMER_LATCH_L_04_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_4_MSB (0x10006000+0xEBC) */
+#define RC_SYS_TIMER_LATCH_H_04_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_5_LSB (0x10006000+0xEC0) */
+#define RC_SYS_TIMER_LATCH_L_05_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_5_MSB (0x10006000+0xEC4) */
+#define RC_SYS_TIMER_LATCH_H_05_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_6_LSB (0x10006000+0xEC8) */
+#define RC_SYS_TIMER_LATCH_L_06_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_6_MSB (0x10006000+0xECC) */
+#define RC_SYS_TIMER_LATCH_H_06_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_7_LSB (0x10006000+0xED0) */
+#define RC_SYS_TIMER_LATCH_L_07_LSB (1U << 0) /* 32b */
+/* RC_SYS_TIMER_LATCH_7_MSB (0x10006000+0xED4) */
+#define RC_SYS_TIMER_LATCH_H_07_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_19 (0x10006000+0xED8) */
+#define PCM_WDT_LATCH_19_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_20 (0x10006000+0xEDC) */
+#define PCM_WDT_LATCH_20_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_21 (0x10006000+0xEE0) */
+#define PCM_WDT_LATCH_21_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_22 (0x10006000+0xEE4) */
+#define PCM_WDT_LATCH_22_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_23 (0x10006000+0xEE8) */
+#define PCM_WDT_LATCH_23_LSB (1U << 0) /* 32b */
+/* PCM_WDT_LATCH_24 (0x10006000+0xEEC) */
+#define PCM_WDT_LATCH_24_LSB (1U << 0) /* 32b */
+/* PMSR_LAST_DAT (0x10006000+0xF00) */
+#define PMSR_LAST_DAT_LSB (1U << 0) /* 32b */
+/* PMSR_LAST_CNT (0x10006000+0xF04) */
+#define PMSR_LAST_CMD_LSB (1U << 0) /* 30b */
+#define PMSR_LAST_REQ_LSB (1U << 30) /* 1b */
+/* PMSR_LAST_ACK (0x10006000+0xF08) */
+#define PMSR_LAST_ACK_LSB (1U << 0) /* 1b */
+/* SPM_PMSR_SEL_CON0 (0x10006000+0xF10) */
+#define REG_PMSR_SIG_SEL_0_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_1_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_2_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_3_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON1 (0x10006000+0xF14) */
+#define REG_PMSR_SIG_SEL_4_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_5_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_6_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_7_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON2 (0x10006000+0xF18) */
+#define REG_PMSR_SIG_SEL_8_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_9_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_10_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_11_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON3 (0x10006000+0xF1C) */
+#define REG_PMSR_SIG_SEL_12_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_13_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_14_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_15_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON4 (0x10006000+0xF20) */
+#define REG_PMSR_SIG_SEL_16_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_17_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_18_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_19_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON5 (0x10006000+0xF24) */
+#define REG_PMSR_SIG_SEL_20_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_21_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_22_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_23_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON6 (0x10006000+0xF28) */
+#define REG_PMSR_SIG_SEL_24_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_25_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_26_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_27_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON7 (0x10006000+0xF2C) */
+#define REG_PMSR_SIG_SEL_28_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_29_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_30_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_31_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON8 (0x10006000+0xF30) */
+#define REG_PMSR_SIG_SEL_32_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_33_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_34_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_35_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON9 (0x10006000+0xF34) */
+#define REG_PMSR_SIG_SEL_36_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_37_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_38_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_39_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON10 (0x10006000+0xF3C) */
+#define REG_PMSR_SIG_SEL_40_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_41_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_42_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_43_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_SEL_CON11 (0x10006000+0xF40) */
+#define REG_PMSR_SIG_SEL_44_LSB (1U << 0) /* 8b */
+#define REG_PMSR_SIG_SEL_45_LSB (1U << 8) /* 8b */
+#define REG_PMSR_SIG_SEL_46_LSB (1U << 16) /* 8b */
+#define REG_PMSR_SIG_SEL_47_LSB (1U << 24) /* 8b */
+/* SPM_PMSR_TIEMR_STA0 (0x10006000+0xFB8) */
+#define PMSR_TIMER_SET0_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_TIEMR_STA1 (0x10006000+0xFBC) */
+#define PMSR_TIMER_SET1_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_TIEMR_STA2 (0x10006000+0xFC0) */
+#define PMSR_TIMER_SET2_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_GENERAL_CON0 (0x10006000+0xFC4) */
+#define PMSR_ENABLE_SET0_LSB (1U << 0) /* 1b */
+#define PMSR_ENABLE_SET1_LSB (1U << 1) /* 1b */
+#define PMSR_ENABLE_SET2_LSB (1U << 2) /* 1b */
+#define PMSR_IRQ_CLR_SET0_LSB (1U << 3) /* 1b */
+#define PMSR_IRQ_CLR_SET1_LSB (1U << 4) /* 1b */
+#define PMSR_IRQ_CLR_SET2_LSB (1U << 5) /* 1b */
+#define PMSR_SPEED_MODE_EN_SET0_LSB (1U << 6) /* 1b */
+#define PMSR_SPEED_MODE_EN_SET1_LSB (1U << 7) /* 1b */
+#define PMSR_SPEED_MODE_EN_SET2_LSB (1U << 8) /* 1b */
+#define PMSR_EVENT_CLR_SET0_LSB (1U << 9) /* 1b */
+#define PMSR_EVENT_CLR_SET1_LSB (1U << 10) /* 1b */
+#define PMSR_EVENT_CLR_SET2_LSB (1U << 11) /* 1b */
+#define REG_PMSR_IRQ_MASK_SET0_LSB (1U << 12) /* 1b */
+#define REG_PMSR_IRQ_MASK_SET1_LSB (1U << 13) /* 1b */
+#define REG_PMSR_IRQ_MASK_SET2_LSB (1U << 14) /* 1b */
+#define REG_PMSR_IRQ_WAKEUP_EVENT_MASK_SET0_LSB (1U << 15) /* 1b */
+#define REG_PMSR_IRQ_WAKEUP_EVENT_MASK_SET1_LSB (1U << 16) /* 1b */
+#define REG_PMSR_IRQ_WAKEUP_EVENT_MASK_SET2_LSB (1U << 17) /* 1b */
+#define PMSR_GEN_SW_RST_EN_LSB (1U << 18) /* 1b */
+#define PMSR_MODULE_ENABLE_LSB (1U << 19) /* 1b */
+#define PMSR_MODE_LSB (1U << 20) /* 2b */
+#define SPM_PMSR_GENERAL_CON0_PMSR_IRQ_B_SET0_LSB (1U << 29) /* 1b */
+#define SPM_PMSR_GENERAL_CON0_PMSR_IRQ_B_SET1_LSB (1U << 30) /* 1b */
+#define SPM_PMSR_GENERAL_CON0_PMSR_IRQ_B_SET2_LSB (1U << 31) /* 1b */
+/* SPM_PMSR_GENERAL_CON1 (0x10006000+0xFC8) */
+#define PMSR_COUNTER_THRES_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_GENERAL_CON2 (0x10006000+0xFCC) */
+#define PMSR_DEBUG_IN_0_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_GENERAL_CON3 (0x10006000+0xFD0) */
+#define PMSR_DEBUG_IN_1_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_GENERAL_CON4 (0x10006000+0xFD4) */
+#define PMSR_DEBUG_IN_2_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_GENERAL_CON5 (0x10006000+0xFD8) */
+#define PMSR_DEBUG_IN_3_MASK_B_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_SW_RESET (0x10006000+0xFDC) */
+#define PMSR_SW_RST_EN_SET0_LSB (1U << 0) /* 1b */
+#define PMSR_SW_RST_EN_SET1_LSB (1U << 1) /* 1b */
+#define PMSR_SW_RST_EN_SET2_LSB (1U << 2) /* 1b */
+/* SPM_PMSR_MON_CON0 (0x10006000+0xFE0) */
+#define REG_PMSR_MON_TYPE_0_LSB (1U << 0) /* 2b */
+#define REG_PMSR_MON_TYPE_1_LSB (1U << 2) /* 2b */
+#define REG_PMSR_MON_TYPE_2_LSB (1U << 4) /* 2b */
+#define REG_PMSR_MON_TYPE_3_LSB (1U << 6) /* 2b */
+#define REG_PMSR_MON_TYPE_4_LSB (1U << 8) /* 2b */
+#define REG_PMSR_MON_TYPE_5_LSB (1U << 10) /* 2b */
+#define REG_PMSR_MON_TYPE_6_LSB (1U << 12) /* 2b */
+#define REG_PMSR_MON_TYPE_7_LSB (1U << 14) /* 2b */
+#define REG_PMSR_MON_TYPE_8_LSB (1U << 16) /* 2b */
+#define REG_PMSR_MON_TYPE_9_LSB (1U << 18) /* 2b */
+#define REG_PMSR_MON_TYPE_10_LSB (1U << 20) /* 2b */
+#define REG_PMSR_MON_TYPE_11_LSB (1U << 22) /* 2b */
+#define REG_PMSR_MON_TYPE_12_LSB (1U << 24) /* 2b */
+#define REG_PMSR_MON_TYPE_13_LSB (1U << 26) /* 2b */
+#define REG_PMSR_MON_TYPE_14_LSB (1U << 28) /* 2b */
+#define REG_PMSR_MON_TYPE_15_LSB (1U << 30) /* 2b */
+/* SPM_PMSR_MON_CON1 (0x10006000+0xFE4) */
+#define REG_PMSR_MON_TYPE_16_LSB (1U << 0) /* 2b */
+#define REG_PMSR_MON_TYPE_17_LSB (1U << 2) /* 2b */
+#define REG_PMSR_MON_TYPE_18_LSB (1U << 4) /* 2b */
+#define REG_PMSR_MON_TYPE_19_LSB (1U << 6) /* 2b */
+#define REG_PMSR_MON_TYPE_20_LSB (1U << 8) /* 2b */
+#define REG_PMSR_MON_TYPE_21_LSB (1U << 10) /* 2b */
+#define REG_PMSR_MON_TYPE_22_LSB (1U << 12) /* 2b */
+#define REG_PMSR_MON_TYPE_23_LSB (1U << 14) /* 2b */
+#define REG_PMSR_MON_TYPE_24_LSB (1U << 16) /* 2b */
+#define REG_PMSR_MON_TYPE_25_LSB (1U << 18) /* 2b */
+#define REG_PMSR_MON_TYPE_26_LSB (1U << 20) /* 2b */
+#define REG_PMSR_MON_TYPE_27_LSB (1U << 22) /* 2b */
+#define REG_PMSR_MON_TYPE_28_LSB (1U << 24) /* 2b */
+#define REG_PMSR_MON_TYPE_29_LSB (1U << 26) /* 2b */
+#define REG_PMSR_MON_TYPE_30_LSB (1U << 28) /* 2b */
+#define REG_PMSR_MON_TYPE_31_LSB (1U << 30) /* 2b */
+/* SPM_PMSR_MON_CON2 (0x10006000+0xFE8) */
+#define REG_PMSR_MON_TYPE_32_LSB (1U << 0) /* 2b */
+#define REG_PMSR_MON_TYPE_33_LSB (1U << 2) /* 2b */
+#define REG_PMSR_MON_TYPE_34_LSB (1U << 4) /* 2b */
+#define REG_PMSR_MON_TYPE_35_LSB (1U << 6) /* 2b */
+#define REG_PMSR_MON_TYPE_36_LSB (1U << 8) /* 2b */
+#define REG_PMSR_MON_TYPE_37_LSB (1U << 10) /* 2b */
+#define REG_PMSR_MON_TYPE_38_LSB (1U << 12) /* 2b */
+#define REG_PMSR_MON_TYPE_39_LSB (1U << 14) /* 2b */
+#define REG_PMSR_MON_TYPE_40_LSB (1U << 16) /* 2b */
+#define REG_PMSR_MON_TYPE_41_LSB (1U << 18) /* 2b */
+#define REG_PMSR_MON_TYPE_42_LSB (1U << 20) /* 2b */
+#define REG_PMSR_MON_TYPE_43_LSB (1U << 22) /* 2b */
+#define REG_PMSR_MON_TYPE_44_LSB (1U << 24) /* 2b */
+#define REG_PMSR_MON_TYPE_45_LSB (1U << 26) /* 2b */
+#define REG_PMSR_MON_TYPE_46_LSB (1U << 28) /* 2b */
+#define REG_PMSR_MON_TYPE_47_LSB (1U << 30) /* 2b */
+/* SPM_PMSR_LEN_CON0 (0x10006000+0xFEC) */
+#define REG_PMSR_WINDOW_LEN_SET0_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_LEN_CON1 (0x10006000+0xFF0) */
+#define REG_PMSR_WINDOW_LEN_SET1_LSB (1U << 0) /* 32b */
+/* SPM_PMSR_LEN_CON2 (0x10006000+0xFF4) */
+#define REG_PMSR_WINDOW_LEN_SET2_LSB (1U << 0) /* 32b */
+
+#define SPM_PROJECT_CODE 0xb16
+#define SPM_REGWR_CFG_KEY (SPM_PROJECT_CODE << 16)
+#endif
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm_resource_req.h b/plat/mediatek/mt8195/drivers/spm/mt_spm_resource_req.h
new file mode 100644
index 0000000..26250ba
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm_resource_req.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_RESOURCE_REQ_H
+#define MT_SPM_RESOURCE_REQ_H
+
+/* SPM resource request internal bit */
+#define MT_SPM_BIT_XO_FPM 0
+#define MT_SPM_BIT_26M 1
+#define MT_SPM_BIT_INFRA 2
+#define MT_SPM_BIT_SYSPLL 3
+#define MT_SPM_BIT_DRAM_S0 4
+#define MT_SPM_BIT_DRAM_S1 5
+
+/* SPM resource request internal bit_mask */
+#define MT_SPM_XO_FPM BIT(MT_SPM_BIT_XO_FPM)
+#define MT_SPM_26M BIT(MT_SPM_BIT_26M)
+#define MT_SPM_INFRA BIT(MT_SPM_BIT_INFRA)
+#define MT_SPM_SYSPLL BIT(MT_SPM_BIT_SYSPLL)
+#define MT_SPM_DRAM_S0 BIT(MT_SPM_BIT_DRAM_S0)
+#define MT_SPM_DRAM_S1 BIT(MT_SPM_BIT_DRAM_S1)
+#endif /* MT_SPM_RESOURCE_REQ_H */
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm_suspend.c b/plat/mediatek/mt8195/drivers/spm/mt_spm_suspend.c
new file mode 100644
index 0000000..d018953
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm_suspend.c
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mt_spm.h>
+#include <mt_spm_conservation.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_rc_internal.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_resource_req.h>
+#include <mt_spm_suspend.h>
+#include <plat_pm.h>
+#include <uart.h>
+
+#define SPM_SUSPEND_SLEEP_PCM_FLAG \
+ (SPM_FLAG_DISABLE_INFRA_PDN | \
+ SPM_FLAG_DISABLE_VCORE_DVS | \
+ SPM_FLAG_DISABLE_VCORE_DFS | \
+ SPM_FLAG_KEEP_CSYSPWRACK_HIGH | \
+ SPM_FLAG_DISABLE_DRAMC_MCU_SRAM_SLEEP | \
+ SPM_FLAG_SRAM_SLEEP_CTRL)
+
+#define SPM_SUSPEND_SLEEP_PCM_FLAG1 0
+
+#define SPM_SUSPEND_PCM_FLAG \
+ (SPM_FLAG_DISABLE_VCORE_DVS | \
+ SPM_FLAG_DISABLE_VCORE_DFS | \
+ SPM_FLAG_ENABLE_TIA_WORKAROUND | \
+ SPM_FLAG_DISABLE_DRAMC_MCU_SRAM_SLEEP | \
+ SPM_FLAG_SRAM_SLEEP_CTRL)
+
+#define SPM_SUSPEND_PCM_FLAG1 0
+
+/* Suspend spm power control */
+#define __WAKE_SRC_FOR_SUSPEND_COMMON__ \
+ (R12_PCM_TIMER | \
+ R12_KP_IRQ_B | \
+ R12_APWDT_EVENT_B | \
+ R12_CONN2AP_SPM_WAKEUP_B | \
+ R12_EINT_EVENT_B | \
+ R12_CONN_WDT_IRQ_B | \
+ R12_CCIF0_EVENT_B | \
+ R12_SSPM2SPM_WAKEUP_B | \
+ R12_SCP2SPM_WAKEUP_B | \
+ R12_USBX_CDSC_B | \
+ R12_USBX_POWERDWN_B | \
+ R12_SYS_TIMER_EVENT_B | \
+ R12_EINT_EVENT_SECURE_B | \
+ R12_SYS_CIRQ_IRQ_B | \
+ R12_MD2AP_PEER_EVENT_B | \
+ R12_MD1_WDT_B | \
+ R12_CLDMA_EVENT_B | \
+ R12_REG_CPU_WAKEUP | \
+ R12_APUSYS_WAKE_HOST_B)
+
+#if defined(CFG_MICROTRUST_TEE_SUPPORT)
+#define WAKE_SRC_FOR_SUSPEND (__WAKE_SRC_FOR_SUSPEND_COMMON__)
+#else
+#define WAKE_SRC_FOR_SUSPEND \
+ (__WAKE_SRC_FOR_SUSPEND_COMMON__ | \
+ R12_SEJ_EVENT_B)
+#endif
+
+static struct pwr_ctrl suspend_ctrl = {
+ .wake_src = WAKE_SRC_FOR_SUSPEND,
+
+ /* SPM_AP_STANDBY_CON */
+ /* [0] */
+ .reg_wfi_op = 0,
+ /* [1] */
+ .reg_wfi_type = 0,
+ /* [2] */
+ .reg_mp0_cputop_idle_mask = 0,
+ /* [3] */
+ .reg_mp1_cputop_idle_mask = 0,
+ /* [4] */
+ .reg_mcusys_idle_mask = 0,
+ /* [25] */
+ .reg_md_apsrc_1_sel = 0,
+ /* [26] */
+ .reg_md_apsrc_0_sel = 0,
+ /* [29] */
+ .reg_conn_apsrc_sel = 0,
+
+ /* SPM_SRC_REQ */
+ /* [0] */
+ .reg_spm_apsrc_req = 0,
+ /* [1] */
+ .reg_spm_f26m_req = 0,
+ /* [3] */
+ .reg_spm_infra_req = 0,
+ /* [4] */
+ .reg_spm_vrf18_req = 0,
+ /* [7] FIXME: default disable HW Auto S1*/
+ .reg_spm_ddr_en_req = 1,
+ /* [8] */
+ .reg_spm_dvfs_req = 0,
+ /* [9] */
+ .reg_spm_sw_mailbox_req = 0,
+ /* [10] */
+ .reg_spm_sspm_mailbox_req = 0,
+ /* [11] */
+ .reg_spm_adsp_mailbox_req = 0,
+ /* [12] */
+ .reg_spm_scp_mailbox_req = 0,
+
+ /* SPM_SRC_MASK */
+ /* [0] */
+ .reg_sspm_srcclkena_0_mask_b = 1,
+ /* [1] */
+ .reg_sspm_infra_req_0_mask_b = 1,
+ /* [2] */
+ .reg_sspm_apsrc_req_0_mask_b = 1,
+ /* [3] */
+ .reg_sspm_vrf18_req_0_mask_b = 1,
+ /* [4] */
+ .reg_sspm_ddr_en_0_mask_b = 1,
+ /* [5] */
+ .reg_scp_srcclkena_mask_b = 1,
+ /* [6] */
+ .reg_scp_infra_req_mask_b = 1,
+ /* [7] */
+ .reg_scp_apsrc_req_mask_b = 1,
+ /* [8] */
+ .reg_scp_vrf18_req_mask_b = 1,
+ /* [9] */
+ .reg_scp_ddr_en_mask_b = 1,
+ /* [10] */
+ .reg_audio_dsp_srcclkena_mask_b = 1,
+ /* [11] */
+ .reg_audio_dsp_infra_req_mask_b = 1,
+ /* [12] */
+ .reg_audio_dsp_apsrc_req_mask_b = 1,
+ /* [13] */
+ .reg_audio_dsp_vrf18_req_mask_b = 1,
+ /* [14] */
+ .reg_audio_dsp_ddr_en_mask_b = 1,
+ /* [15] */
+ .reg_apu_srcclkena_mask_b = 1,
+ /* [16] */
+ .reg_apu_infra_req_mask_b = 1,
+ /* [17] */
+ .reg_apu_apsrc_req_mask_b = 1,
+ /* [18] */
+ .reg_apu_vrf18_req_mask_b = 1,
+ /* [19] */
+ .reg_apu_ddr_en_mask_b = 1,
+ /* [20] */
+ .reg_cpueb_srcclkena_mask_b = 1,
+ /* [21] */
+ .reg_cpueb_infra_req_mask_b = 1,
+ /* [22] */
+ .reg_cpueb_apsrc_req_mask_b = 1,
+ /* [23] */
+ .reg_cpueb_vrf18_req_mask_b = 1,
+ /* [24] */
+ .reg_cpueb_ddr_en_mask_b = 1,
+ /* [25] */
+ .reg_bak_psri_srcclkena_mask_b = 0,
+ /* [26] */
+ .reg_bak_psri_infra_req_mask_b = 0,
+ /* [27] */
+ .reg_bak_psri_apsrc_req_mask_b = 0,
+ /* [28] */
+ .reg_bak_psri_vrf18_req_mask_b = 0,
+ /* [29] */
+ .reg_bak_psri_ddr_en_mask_b = 0,
+
+ /* SPM_SRC2_MASK */
+ /* [0] */
+ .reg_msdc0_srcclkena_mask_b = 1,
+ /* [1] */
+ .reg_msdc0_infra_req_mask_b = 1,
+ /* [2] */
+ .reg_msdc0_apsrc_req_mask_b = 1,
+ /* [3] */
+ .reg_msdc0_vrf18_req_mask_b = 1,
+ /* [4] */
+ .reg_msdc0_ddr_en_mask_b = 1,
+ /* [5] */
+ .reg_msdc1_srcclkena_mask_b = 1,
+ /* [6] */
+ .reg_msdc1_infra_req_mask_b = 1,
+ /* [7] */
+ .reg_msdc1_apsrc_req_mask_b = 1,
+ /* [8] */
+ .reg_msdc1_vrf18_req_mask_b = 1,
+ /* [9] */
+ .reg_msdc1_ddr_en_mask_b = 1,
+ /* [10] */
+ .reg_msdc2_srcclkena_mask_b = 1,
+ /* [11] */
+ .reg_msdc2_infra_req_mask_b = 1,
+ /* [12] */
+ .reg_msdc2_apsrc_req_mask_b = 1,
+ /* [13] */
+ .reg_msdc2_vrf18_req_mask_b = 1,
+ /* [14] */
+ .reg_msdc2_ddr_en_mask_b = 1,
+ /* [15] */
+ .reg_ufs_srcclkena_mask_b = 0,
+ /* [16] */
+ .reg_ufs_infra_req_mask_b = 0,
+ /* [17] */
+ .reg_ufs_apsrc_req_mask_b = 0,
+ /* [18] */
+ .reg_ufs_vrf18_req_mask_b = 0,
+ /* [19] */
+ .reg_ufs_ddr_en_mask_b = 0,
+ /* [20] */
+ .reg_usb_srcclkena_mask_b = 1,
+ /* [21] */
+ .reg_usb_infra_req_mask_b = 1,
+ /* [22] */
+ .reg_usb_apsrc_req_mask_b = 1,
+ /* [23] */
+ .reg_usb_vrf18_req_mask_b = 1,
+ /* [24] */
+ .reg_usb_ddr_en_mask_b = 1,
+ /* [25] */
+ .reg_pextp_p0_srcclkena_mask_b = 1,
+ /* [26] */
+ .reg_pextp_p0_infra_req_mask_b = 1,
+ /* [27] */
+ .reg_pextp_p0_apsrc_req_mask_b = 1,
+ /* [28] */
+ .reg_pextp_p0_vrf18_req_mask_b = 1,
+ /* [29] */
+ .reg_pextp_p0_ddr_en_mask_b = 1,
+
+ /* SPM_SRC3_MASK */
+ /* [0] */
+ .reg_pextp_p1_srcclkena_mask_b = 1,
+ /* [1] */
+ .reg_pextp_p1_infra_req_mask_b = 1,
+ /* [2] */
+ .reg_pextp_p1_apsrc_req_mask_b = 1,
+ /* [3] */
+ .reg_pextp_p1_vrf18_req_mask_b = 1,
+ /* [4] */
+ .reg_pextp_p1_ddr_en_mask_b = 1,
+ /* [5] */
+ .reg_gce0_infra_req_mask_b = 1,
+ /* [6] */
+ .reg_gce0_apsrc_req_mask_b = 1,
+ /* [7] */
+ .reg_gce0_vrf18_req_mask_b = 1,
+ /* [8] */
+ .reg_gce0_ddr_en_mask_b = 1,
+ /* [9] */
+ .reg_gce1_infra_req_mask_b = 1,
+ /* [10] */
+ .reg_gce1_apsrc_req_mask_b = 1,
+ /* [11] */
+ .reg_gce1_vrf18_req_mask_b = 1,
+ /* [12] */
+ .reg_gce1_ddr_en_mask_b = 1,
+ /* [13] */
+ .reg_spm_srcclkena_reserved_mask_b = 1,
+ /* [14] */
+ .reg_spm_infra_req_reserved_mask_b = 1,
+ /* [15] */
+ .reg_spm_apsrc_req_reserved_mask_b = 1,
+ /* [16] */
+ .reg_spm_vrf18_req_reserved_mask_b = 1,
+ /* [17] */
+ .reg_spm_ddr_en_reserved_mask_b = 1,
+ /* [18] */
+ .reg_disp0_apsrc_req_mask_b = 1,
+ /* [19] */
+ .reg_disp0_ddr_en_mask_b = 1,
+ /* [20] */
+ .reg_disp1_apsrc_req_mask_b = 1,
+ /* [21] */
+ .reg_disp1_ddr_en_mask_b = 1,
+ /* [22] */
+ .reg_disp2_apsrc_req_mask_b = 1,
+ /* [23] */
+ .reg_disp2_ddr_en_mask_b = 1,
+ /* [24] */
+ .reg_disp3_apsrc_req_mask_b = 1,
+ /* [25] */
+ .reg_disp3_ddr_en_mask_b = 1,
+ /* [26] */
+ .reg_infrasys_apsrc_req_mask_b = 0,
+ /* [27] */
+ .reg_infrasys_ddr_en_mask_b = 1,
+
+ /* [28] */
+ .reg_cg_check_srcclkena_mask_b = 1,
+ /* [29] */
+ .reg_cg_check_apsrc_req_mask_b = 1,
+ /* [30] */
+ .reg_cg_check_vrf18_req_mask_b = 1,
+ /* [31] */
+ .reg_cg_check_ddr_en_mask_b = 1,
+
+ /* SPM_SRC4_MASK */
+ /* [8:0] */
+ .reg_mcusys_merge_apsrc_req_mask_b = 0x17,
+ /* [17:9] */
+ .reg_mcusys_merge_ddr_en_mask_b = 0x17,
+ /* [19:18] */
+ .reg_dramc_md32_infra_req_mask_b = 0,
+ /* [21:20] */
+ .reg_dramc_md32_vrf18_req_mask_b = 0,
+ /* [23:22] */
+ .reg_dramc_md32_ddr_en_mask_b = 0,
+ /* [24] */
+ .reg_dvfsrc_event_trigger_mask_b = 1,
+
+ /* SPM_WAKEUP_EVENT_MASK2 */
+ /* [3:0] */
+ .reg_sc_sw2spm_wakeup_mask_b = 0,
+ /* [4] */
+ .reg_sc_adsp2spm_wakeup_mask_b = 0,
+ /* [8:5] */
+ .reg_sc_sspm2spm_wakeup_mask_b = 0,
+ /* [9] */
+ .reg_sc_scp2spm_wakeup_mask_b = 0,
+ /* [10] */
+ .reg_csyspwrup_ack_mask = 0,
+ /* [11] */
+ .reg_csyspwrup_req_mask = 1,
+
+ /* SPM_WAKEUP_EVENT_MASK */
+ /* [31:0] */
+ .reg_wakeup_event_mask = 0xC1382213,
+
+ /* SPM_WAKEUP_EVENT_EXT_MASK */
+ /* [31:0] */
+ .reg_ext_wakeup_event_mask = 0xFFFFFFFF,
+};
+
+struct spm_lp_scen __spm_suspend = {
+ .pwrctrl = &suspend_ctrl,
+};
+
+int mt_spm_suspend_mode_set(int mode)
+{
+ if (mode == MT_SPM_SUSPEND_SLEEP) {
+ suspend_ctrl.pcm_flags = SPM_SUSPEND_SLEEP_PCM_FLAG;
+ suspend_ctrl.pcm_flags1 = SPM_SUSPEND_SLEEP_PCM_FLAG1;
+ } else {
+ suspend_ctrl.pcm_flags = SPM_SUSPEND_PCM_FLAG;
+ suspend_ctrl.pcm_flags1 = SPM_SUSPEND_PCM_FLAG1;
+ }
+
+ return 0;
+}
+
+int mt_spm_suspend_enter(int state_id, unsigned int ext_opand,
+ unsigned int resource_req)
+{
+ /* If FMAudio / ADSP is active, change to sleep suspend mode */
+ if ((ext_opand & MT_SPM_EX_OP_SET_SUSPEND_MODE) != 0U) {
+ mt_spm_suspend_mode_set(MT_SPM_SUSPEND_SLEEP);
+ }
+
+ /* Notify MCUPM that device is going suspend flow */
+ mmio_write_32(MCUPM_MBOX_OFFSET_PDN, MCUPM_POWER_DOWN);
+
+ /* Notify UART to sleep */
+ mt_uart_save();
+
+ return spm_conservation(state_id, ext_opand,
+ &__spm_suspend, resource_req);
+}
+
+void mt_spm_suspend_resume(int state_id, unsigned int ext_opand,
+ struct wake_status **status)
+{
+ spm_conservation_finish(state_id, ext_opand, &__spm_suspend, status);
+
+ /* Notify UART to wakeup */
+ mt_uart_restore();
+
+ /* Notify MCUPM that device leave suspend */
+ mmio_write_32(MCUPM_MBOX_OFFSET_PDN, 0);
+
+ /* If FMAudio / ADSP is active, change back to suspend mode */
+ if ((ext_opand & MT_SPM_EX_OP_SET_SUSPEND_MODE) != 0U) {
+ mt_spm_suspend_mode_set(MT_SPM_SUSPEND_SYSTEM_PDN);
+ }
+}
+
+void mt_spm_suspend_init(void)
+{
+ spm_conservation_pwrctrl_init(__spm_suspend.pwrctrl);
+}
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm_suspend.h b/plat/mediatek/mt8195/drivers/spm/mt_spm_suspend.h
new file mode 100644
index 0000000..69c5230
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm_suspend.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_SUSPEND_H
+#define MT_SPM_SUSPEND_H
+
+#include <mt_spm_internal.h>
+
+#define MCUPM_MBOX_OFFSET_PDN 0x1031FF88
+#define MCUPM_POWER_DOWN 0x4D50444E
+
+enum MT_SPM_SUSPEND_MODE {
+ MT_SPM_SUSPEND_SYSTEM_PDN,
+ MT_SPM_SUSPEND_SLEEP,
+};
+
+extern int mt_spm_suspend_mode_set(int mode);
+extern int mt_spm_suspend_enter(int state_id, unsigned int ext_opand,
+ unsigned int reosuce_req);
+extern void mt_spm_suspend_resume(int state_id, unsigned int ext_opand,
+ struct wake_status **status);
+extern void mt_spm_suspend_init(void);
+#endif /* MT_SPM_SUSPEND_H */
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm_vcorefs.c b/plat/mediatek/mt8195/drivers/spm/mt_spm_vcorefs.c
new file mode 100644
index 0000000..6a85b5c
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm_vcorefs.c
@@ -0,0 +1,526 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stddef.h>
+#include <string.h>
+#include <common/debug.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <mt_spm.h>
+#include <mt_spm_internal.h>
+#include <mt_spm_pmic_wrap.h>
+#include <mt_spm_reg.h>
+#include <mt_spm_vcorefs.h>
+#include <mtk_plat_common.h>
+#include <mtk_sip_svc.h>
+#include <platform_def.h>
+
+#define VCORE_MAX_OPP 4
+#define DRAM_MAX_OPP 7
+
+static bool spm_dvfs_init_done;
+static bool dvfs_enable_done;
+static int vcore_opp_0_uv = 750000;
+static int vcore_opp_1_uv = 650000;
+static int vcore_opp_2_uv = 600000;
+static int vcore_opp_3_uv = 550000;
+
+static struct reg_config dvfsrc_init_configs[] = {
+ { DVFSRC_HRT_REQ_UNIT, 0x0000001E },
+ { DVFSRC_DEBOUNCE_TIME, 0x19651965 },
+ { DVFSRC_TIMEOUT_NEXTREQ, 0x00000015 },
+ { DVFSRC_LEVEL_MASK, 0x000EE000 },
+ { DVFSRC_DDR_QOS0, 0x00000019 },
+ { DVFSRC_DDR_QOS1, 0x00000026 },
+ { DVFSRC_DDR_QOS2, 0x00000033 },
+ { DVFSRC_DDR_QOS3, 0x0000003B },
+ { DVFSRC_DDR_QOS4, 0x0000004C },
+ { DVFSRC_DDR_QOS5, 0x00000066 },
+ { DVFSRC_DDR_QOS6, 0x00660066 },
+ { DVFSRC_LEVEL_LABEL_0_1, 0x50436053 },
+ { DVFSRC_LEVEL_LABEL_2_3, 0x40335042 },
+ { DVFSRC_LEVEL_LABEL_4_5, 0x40314032 },
+ { DVFSRC_LEVEL_LABEL_6_7, 0x30223023 },
+ { DVFSRC_LEVEL_LABEL_8_9, 0x20133021 },
+ { DVFSRC_LEVEL_LABEL_10_11, 0x20112012 },
+ { DVFSRC_LEVEL_LABEL_12_13, 0x10032010 },
+ { DVFSRC_LEVEL_LABEL_14_15, 0x10011002 },
+ { DVFSRC_LEVEL_LABEL_16_17, 0x00131000 },
+ { DVFSRC_LEVEL_LABEL_18_19, 0x00110012 },
+ { DVFSRC_LEVEL_LABEL_20_21, 0x00000010 },
+ { DVFSRC_MD_LATENCY_IMPROVE, 0x00000040 },
+ { DVFSRC_DDR_REQUEST, 0x00004321 },
+ { DVFSRC_DDR_REQUEST3, 0x00000065 },
+ { DVFSRC_DDR_ADD_REQUEST, 0x66543210 },
+ { DVFSRC_HRT_REQUEST, 0x66654321 },
+ { DVFSRC_DDR_REQUEST5, 0x54321000 },
+ { DVFSRC_DDR_REQUEST7, 0x66000000 },
+ { DVFSRC_VCORE_USER_REQ, 0x00010A29 },
+ { DVFSRC_HRT_HIGH_3, 0x18A618A6 },
+ { DVFSRC_HRT_HIGH_2, 0x18A61183 },
+ { DVFSRC_HRT_HIGH_1, 0x0D690B80 },
+ { DVFSRC_HRT_HIGH, 0x070804B0 },
+ { DVFSRC_HRT_LOW_3, 0x18A518A5 },
+ { DVFSRC_HRT_LOW_2, 0x18A51182 },
+ { DVFSRC_HRT_LOW_1, 0x0D680B7F },
+ { DVFSRC_HRT_LOW, 0x070704AF },
+ { DVFSRC_BASIC_CONTROL_3, 0x00000006 },
+ { DVFSRC_INT_EN, 0x00000002 },
+ { DVFSRC_QOS_EN, 0x0000407C },
+ { DVFSRC_HRT_BW_BASE, 0x00000004 },
+ { DVFSRC_PCIE_VCORE_REQ, 0x65908101 },
+ { DVFSRC_CURRENT_FORCE, 0x00000001 },
+ { DVFSRC_BASIC_CONTROL, 0x6698444B },
+ { DVFSRC_BASIC_CONTROL, 0x6698054B },
+ { DVFSRC_CURRENT_FORCE, 0x00000000 },
+};
+
+static struct pwr_ctrl vcorefs_ctrl = {
+ .wake_src = R12_REG_CPU_WAKEUP,
+
+ /* default VCORE DVFS is disabled */
+ .pcm_flags = (SPM_FLAG_RUN_COMMON_SCENARIO |
+ SPM_FLAG_DISABLE_VCORE_DVS | SPM_FLAG_DISABLE_VCORE_DFS),
+
+ /* SPM_AP_STANDBY_CON */
+ /* [0] */
+ .reg_wfi_op = 0,
+ /* [1] */
+ .reg_wfi_type = 0,
+ /* [2] */
+ .reg_mp0_cputop_idle_mask = 0,
+ /* [3] */
+ .reg_mp1_cputop_idle_mask = 0,
+ /* [4] */
+ .reg_mcusys_idle_mask = 0,
+ /* [25] */
+ .reg_md_apsrc_1_sel = 0,
+ /* [26] */
+ .reg_md_apsrc_0_sel = 0,
+ /* [29] */
+ .reg_conn_apsrc_sel = 0,
+
+ /* SPM_SRC_REQ */
+ /* [0] */
+ .reg_spm_apsrc_req = 0,
+ /* [1] */
+ .reg_spm_f26m_req = 0,
+ /* [3] */
+ .reg_spm_infra_req = 0,
+ /* [4] */
+ .reg_spm_vrf18_req = 0,
+ /* [7] FIXME: default disable HW Auto S1*/
+ .reg_spm_ddr_en_req = 1,
+ /* [8] */
+ .reg_spm_dvfs_req = 0,
+ /* [9] */
+ .reg_spm_sw_mailbox_req = 0,
+ /* [10] */
+ .reg_spm_sspm_mailbox_req = 0,
+ /* [11] */
+ .reg_spm_adsp_mailbox_req = 0,
+ /* [12] */
+ .reg_spm_scp_mailbox_req = 0,
+
+ /* SPM_SRC_MASK */
+ /* [0] */
+ .reg_sspm_srcclkena_0_mask_b = 1,
+ /* [1] */
+ .reg_sspm_infra_req_0_mask_b = 1,
+ /* [2] */
+ .reg_sspm_apsrc_req_0_mask_b = 1,
+ /* [3] */
+ .reg_sspm_vrf18_req_0_mask_b = 1,
+ /* [4] */
+ .reg_sspm_ddr_en_0_mask_b = 1,
+ /* [5] */
+ .reg_scp_srcclkena_mask_b = 1,
+ /* [6] */
+ .reg_scp_infra_req_mask_b = 1,
+ /* [7] */
+ .reg_scp_apsrc_req_mask_b = 1,
+ /* [8] */
+ .reg_scp_vrf18_req_mask_b = 1,
+ /* [9] */
+ .reg_scp_ddr_en_mask_b = 1,
+ /* [10] */
+ .reg_audio_dsp_srcclkena_mask_b = 1,
+ /* [11] */
+ .reg_audio_dsp_infra_req_mask_b = 1,
+ /* [12] */
+ .reg_audio_dsp_apsrc_req_mask_b = 1,
+ /* [13] */
+ .reg_audio_dsp_vrf18_req_mask_b = 1,
+ /* [14] */
+ .reg_audio_dsp_ddr_en_mask_b = 1,
+ /* [15] */
+ .reg_apu_srcclkena_mask_b = 1,
+ /* [16] */
+ .reg_apu_infra_req_mask_b = 1,
+ /* [17] */
+ .reg_apu_apsrc_req_mask_b = 1,
+ /* [18] */
+ .reg_apu_vrf18_req_mask_b = 1,
+ /* [19] */
+ .reg_apu_ddr_en_mask_b = 1,
+ /* [20] */
+ .reg_cpueb_srcclkena_mask_b = 1,
+ /* [21] */
+ .reg_cpueb_infra_req_mask_b = 1,
+ /* [22] */
+ .reg_cpueb_apsrc_req_mask_b = 1,
+ /* [23] */
+ .reg_cpueb_vrf18_req_mask_b = 1,
+ /* [24] */
+ .reg_cpueb_ddr_en_mask_b = 1,
+ /* [25] */
+ .reg_bak_psri_srcclkena_mask_b = 0,
+ /* [26] */
+ .reg_bak_psri_infra_req_mask_b = 0,
+ /* [27] */
+ .reg_bak_psri_apsrc_req_mask_b = 0,
+ /* [28] */
+ .reg_bak_psri_vrf18_req_mask_b = 0,
+ /* [29] */
+ .reg_bak_psri_ddr_en_mask_b = 0,
+
+ /* SPM_SRC2_MASK */
+ /* [0] */
+ .reg_msdc0_srcclkena_mask_b = 1,
+ /* [1] */
+ .reg_msdc0_infra_req_mask_b = 1,
+ /* [2] */
+ .reg_msdc0_apsrc_req_mask_b = 1,
+ /* [3] */
+ .reg_msdc0_vrf18_req_mask_b = 1,
+ /* [4] */
+ .reg_msdc0_ddr_en_mask_b = 1,
+ /* [5] */
+ .reg_msdc1_srcclkena_mask_b = 1,
+ /* [6] */
+ .reg_msdc1_infra_req_mask_b = 1,
+ /* [7] */
+ .reg_msdc1_apsrc_req_mask_b = 1,
+ /* [8] */
+ .reg_msdc1_vrf18_req_mask_b = 1,
+ /* [9] */
+ .reg_msdc1_ddr_en_mask_b = 1,
+ /* [10] */
+ .reg_msdc2_srcclkena_mask_b = 1,
+ /* [11] */
+ .reg_msdc2_infra_req_mask_b = 1,
+ /* [12] */
+ .reg_msdc2_apsrc_req_mask_b = 1,
+ /* [13] */
+ .reg_msdc2_vrf18_req_mask_b = 1,
+ /* [14] */
+ .reg_msdc2_ddr_en_mask_b = 1,
+ /* [15] */
+ .reg_ufs_srcclkena_mask_b = 1,
+ /* [16] */
+ .reg_ufs_infra_req_mask_b = 1,
+ /* [17] */
+ .reg_ufs_apsrc_req_mask_b = 1,
+ /* [18] */
+ .reg_ufs_vrf18_req_mask_b = 1,
+ /* [19] */
+ .reg_ufs_ddr_en_mask_b = 1,
+ /* [20] */
+ .reg_usb_srcclkena_mask_b = 1,
+ /* [21] */
+ .reg_usb_infra_req_mask_b = 1,
+ /* [22] */
+ .reg_usb_apsrc_req_mask_b = 1,
+ /* [23] */
+ .reg_usb_vrf18_req_mask_b = 1,
+ /* [24] */
+ .reg_usb_ddr_en_mask_b = 1,
+ /* [25] */
+ .reg_pextp_p0_srcclkena_mask_b = 1,
+ /* [26] */
+ .reg_pextp_p0_infra_req_mask_b = 1,
+ /* [27] */
+ .reg_pextp_p0_apsrc_req_mask_b = 1,
+ /* [28] */
+ .reg_pextp_p0_vrf18_req_mask_b = 1,
+ /* [29] */
+ .reg_pextp_p0_ddr_en_mask_b = 1,
+
+ /* SPM_SRC3_MASK */
+ /* [0] */
+ .reg_pextp_p1_srcclkena_mask_b = 1,
+ /* [1] */
+ .reg_pextp_p1_infra_req_mask_b = 1,
+ /* [2] */
+ .reg_pextp_p1_apsrc_req_mask_b = 1,
+ /* [3] */
+ .reg_pextp_p1_vrf18_req_mask_b = 1,
+ /* [4] */
+ .reg_pextp_p1_ddr_en_mask_b = 1,
+ /* [5] */
+ .reg_gce0_infra_req_mask_b = 1,
+ /* [6] */
+ .reg_gce0_apsrc_req_mask_b = 1,
+ /* [7] */
+ .reg_gce0_vrf18_req_mask_b = 1,
+ /* [8] */
+ .reg_gce0_ddr_en_mask_b = 1,
+ /* [9] */
+ .reg_gce1_infra_req_mask_b = 1,
+ /* [10] */
+ .reg_gce1_apsrc_req_mask_b = 1,
+ /* [11] */
+ .reg_gce1_vrf18_req_mask_b = 1,
+ /* [12] */
+ .reg_gce1_ddr_en_mask_b = 1,
+ /* [13] */
+ .reg_spm_srcclkena_reserved_mask_b = 1,
+ /* [14] */
+ .reg_spm_infra_req_reserved_mask_b = 1,
+ /* [15] */
+ .reg_spm_apsrc_req_reserved_mask_b = 1,
+ /* [16] */
+ .reg_spm_vrf18_req_reserved_mask_b = 1,
+ /* [17] */
+ .reg_spm_ddr_en_reserved_mask_b = 1,
+ /* [18] */
+ .reg_disp0_apsrc_req_mask_b = 1,
+ /* [19] */
+ .reg_disp0_ddr_en_mask_b = 1,
+ /* [20] */
+ .reg_disp1_apsrc_req_mask_b = 1,
+ /* [21] */
+ .reg_disp1_ddr_en_mask_b = 1,
+ /* [22] */
+ .reg_disp2_apsrc_req_mask_b = 1,
+ /* [23] */
+ .reg_disp2_ddr_en_mask_b = 1,
+ /* [24] */
+ .reg_disp3_apsrc_req_mask_b = 1,
+ /* [25] */
+ .reg_disp3_ddr_en_mask_b = 1,
+ /* [26] */
+ .reg_infrasys_apsrc_req_mask_b = 0,
+ /* [27] */
+ .reg_infrasys_ddr_en_mask_b = 1,
+
+ /* [28] */
+ .reg_cg_check_srcclkena_mask_b = 1,
+ /* [29] */
+ .reg_cg_check_apsrc_req_mask_b = 1,
+ /* [30] */
+ .reg_cg_check_vrf18_req_mask_b = 1,
+ /* [31] */
+ .reg_cg_check_ddr_en_mask_b = 1,
+
+ /* SPM_SRC4_MASK */
+ /* [8:0] */
+ .reg_mcusys_merge_apsrc_req_mask_b = 0x11,
+ /* [17:9] */
+ .reg_mcusys_merge_ddr_en_mask_b = 0x11,
+ /* [19:18] */
+ .reg_dramc_md32_infra_req_mask_b = 0,
+ /* [21:20] */
+ .reg_dramc_md32_vrf18_req_mask_b = 0,
+ /* [23:22] */
+ .reg_dramc_md32_ddr_en_mask_b = 0,
+ /* [24] */
+ .reg_dvfsrc_event_trigger_mask_b = 1,
+
+ /* SPM_WAKEUP_EVENT_MASK2 */
+ /* [3:0] */
+ .reg_sc_sw2spm_wakeup_mask_b = 0,
+ /* [4] */
+ .reg_sc_adsp2spm_wakeup_mask_b = 0,
+ /* [8:5] */
+ .reg_sc_sspm2spm_wakeup_mask_b = 0,
+ /* [9] */
+ .reg_sc_scp2spm_wakeup_mask_b = 0,
+ /* [10] */
+ .reg_csyspwrup_ack_mask = 0,
+ /* [11] */
+ .reg_csyspwrup_req_mask = 1,
+
+ /* SPM_WAKEUP_EVENT_MASK */
+ /* [31:0] */
+ .reg_wakeup_event_mask = 0xEFFFFFFF,
+
+ /* SPM_WAKEUP_EVENT_EXT_MASK */
+ /* [31:0] */
+ .reg_ext_wakeup_event_mask = 0xFFFFFFFF,
+};
+
+struct spm_lp_scen __spm_vcorefs = {
+ .pwrctrl = &vcorefs_ctrl,
+};
+
+static void spm_vcorefs_pwarp_cmd(uint64_t cmd, uint64_t val)
+{
+ if (cmd < NR_IDX_ALL) {
+ mt_spm_pmic_wrap_set_cmd(PMIC_WRAP_PHASE_ALLINONE, cmd, val);
+ } else {
+ INFO("cmd out of range!\n");
+ }
+}
+
+void spm_dvfsfw_init(uint64_t boot_up_opp, uint64_t dram_issue)
+{
+ if (spm_dvfs_init_done == false) {
+ mmio_write_32(SPM_DVFS_MISC, (mmio_read_32(SPM_DVFS_MISC) &
+ ~(SPM_DVFS_FORCE_ENABLE_LSB)) | (SPM_DVFSRC_ENABLE_LSB));
+
+ mmio_write_32(SPM_DVFS_LEVEL, 0x00000001);
+ mmio_write_32(SPM_DVS_DFS_LEVEL, 0x00010001);
+
+ spm_dvfs_init_done = true;
+ }
+}
+
+void __spm_sync_vcore_dvfs_power_control(struct pwr_ctrl *dest_pwr_ctrl,
+ const struct pwr_ctrl *src_pwr_ctrl)
+{
+ uint32_t dvfs_mask = SPM_FLAG_DISABLE_VCORE_DVS |
+ SPM_FLAG_DISABLE_VCORE_DFS |
+ SPM_FLAG_ENABLE_VOLTAGE_BIN;
+
+ dest_pwr_ctrl->pcm_flags = (dest_pwr_ctrl->pcm_flags & (~dvfs_mask)) |
+ (src_pwr_ctrl->pcm_flags & dvfs_mask);
+
+ if (dest_pwr_ctrl->pcm_flags_cust) {
+ dest_pwr_ctrl->pcm_flags_cust = (dest_pwr_ctrl->pcm_flags_cust & (~dvfs_mask)) |
+ (src_pwr_ctrl->pcm_flags & dvfs_mask);
+ }
+}
+
+void spm_go_to_vcorefs(uint64_t spm_flags)
+{
+ __spm_set_power_control(__spm_vcorefs.pwrctrl);
+ __spm_set_wakeup_event(__spm_vcorefs.pwrctrl);
+ __spm_set_pcm_flags(__spm_vcorefs.pwrctrl);
+ __spm_send_cpu_wakeup_event();
+}
+
+uint64_t spm_vcorefs_args(uint64_t x1, uint64_t x2, uint64_t x3)
+{
+ uint64_t ret = 0U;
+ uint64_t cmd = x1;
+ uint64_t spm_flags;
+
+ switch (cmd) {
+ case VCOREFS_SMC_CMD_0:
+ spm_dvfsfw_init(x2, x3);
+ break;
+ case VCOREFS_SMC_CMD_1:
+ spm_flags = SPM_FLAG_RUN_COMMON_SCENARIO;
+ if (x2 & SPM_FLAG_DISABLE_VCORE_DVS)
+ spm_flags |= SPM_FLAG_DISABLE_VCORE_DVS;
+ if (x2 & SPM_FLAG_DISABLE_VCORE_DFS)
+ spm_flags |= SPM_FLAG_DISABLE_VCORE_DFS;
+ spm_go_to_vcorefs(spm_flags);
+ break;
+ case VCOREFS_SMC_CMD_3:
+ spm_vcorefs_pwarp_cmd(x2, x3);
+ break;
+ case VCOREFS_SMC_CMD_2:
+ case VCOREFS_SMC_CMD_4:
+ case VCOREFS_SMC_CMD_5:
+ case VCOREFS_SMC_CMD_7:
+ default:
+ break;
+ }
+ return ret;
+}
+
+static void dvfsrc_init(void)
+{
+ int i;
+ int count = ARRAY_SIZE(dvfsrc_init_configs);
+
+ if (dvfs_enable_done == false) {
+ for (i = 0; i < count; i++) {
+ mmio_write_32(dvfsrc_init_configs[i].offset,
+ dvfsrc_init_configs[i].val);
+ }
+
+ mmio_write_32(DVFSRC_QOS_EN, 0x0011007C);
+
+ dvfs_enable_done = true;
+ }
+}
+
+static void spm_vcorefs_vcore_setting(uint64_t flag)
+{
+ spm_vcorefs_pwarp_cmd(3, __vcore_uv_to_pmic(vcore_opp_3_uv));
+ spm_vcorefs_pwarp_cmd(2, __vcore_uv_to_pmic(vcore_opp_2_uv));
+ spm_vcorefs_pwarp_cmd(1, __vcore_uv_to_pmic(vcore_opp_1_uv));
+ spm_vcorefs_pwarp_cmd(0, __vcore_uv_to_pmic(vcore_opp_0_uv));
+}
+
+int spm_vcorefs_get_vcore(unsigned int gear)
+{
+ int ret_val;
+
+ switch (gear) {
+ case 3:
+ ret_val = vcore_opp_0_uv;
+ break;
+ case 2:
+ ret_val = vcore_opp_1_uv;
+ break;
+ case 1:
+ ret_val = vcore_opp_2_uv;
+ break;
+ case 0:
+ default:
+ ret_val = vcore_opp_3_uv;
+ break;
+ }
+ return ret_val;
+}
+
+uint64_t spm_vcorefs_v2_args(u_register_t x1, u_register_t x2, u_register_t x3, u_register_t *x4)
+{
+ uint64_t ret = 0U;
+ uint64_t cmd = x1;
+ uint64_t spm_flags;
+
+ switch (cmd) {
+ case VCOREFS_SMC_CMD_INIT:
+ /* vcore_dvfs init + kick */
+ spm_dvfsfw_init(0, 0);
+ spm_vcorefs_vcore_setting(x3 & 0xF);
+ spm_flags = SPM_FLAG_RUN_COMMON_SCENARIO;
+ if (x2 & 0x1) {
+ spm_flags |= SPM_FLAG_DISABLE_VCORE_DVS;
+ }
+ if (x2 & 0x2) {
+ spm_flags |= SPM_FLAG_DISABLE_VCORE_DFS;
+ }
+ spm_go_to_vcorefs(spm_flags);
+ dvfsrc_init();
+ *x4 = 0U;
+ break;
+ case VCOREFS_SMC_CMD_OPP_TYPE:
+ /* get dram type */
+ *x4 = 0U;
+ break;
+ case VCOREFS_SMC_CMD_FW_TYPE:
+ *x4 = 0U;
+ break;
+ case VCOREFS_SMC_CMD_GET_UV:
+ *x4 = spm_vcorefs_get_vcore(x2);
+ break;
+ case VCOREFS_SMC_CMD_GET_NUM_V:
+ *x4 = VCORE_MAX_OPP;
+ break;
+ case VCOREFS_SMC_CMD_GET_NUM_F:
+ *x4 = DRAM_MAX_OPP;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/plat/mediatek/mt8195/drivers/spm/mt_spm_vcorefs.h b/plat/mediatek/mt8195/drivers/spm/mt_spm_vcorefs.h
new file mode 100644
index 0000000..b08fcce
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/mt_spm_vcorefs.h
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __MT_SPM_VCOREFS__H__
+#define __MT_SPM_VCOREFS__H__
+
+int spm_vcorefs_get_vcore(unsigned int gear);
+uint64_t spm_vcorefs_v2_args(u_register_t x1, u_register_t x2, u_register_t x3,
+ u_register_t *x4);
+
+enum vcorefs_smc_cmd {
+ VCOREFS_SMC_CMD_0 = 0,
+ VCOREFS_SMC_CMD_1,
+ VCOREFS_SMC_CMD_2,
+ VCOREFS_SMC_CMD_3,
+ VCOREFS_SMC_CMD_4,
+ /* check spmfw status */
+ VCOREFS_SMC_CMD_5,
+
+ /* get spmfw type */
+ VCOREFS_SMC_CMD_6,
+
+ /* get spm reg status */
+ VCOREFS_SMC_CMD_7,
+
+ NUM_VCOREFS_SMC_CMD,
+};
+
+enum vcorefs_smc_cmd_new {
+ VCOREFS_SMC_CMD_INIT = 0,
+ VCOREFS_SMC_CMD_KICK = 1,
+ VCOREFS_SMC_CMD_OPP_TYPE = 2,
+ VCOREFS_SMC_CMD_FW_TYPE = 3,
+ VCOREFS_SMC_CMD_GET_UV = 4,
+ VCOREFS_SMC_CMD_GET_FREQ = 5,
+ VCOREFS_SMC_CMD_GET_NUM_V = 6,
+ VCOREFS_SMC_CMD_GET_NUM_F = 7,
+ VCOREFS_SMC_CMD_FB_ACTION = 8,
+ /*chip specific setting */
+ VCOREFS_SMC_CMD_SET_FREQ = 16,
+ VCOREFS_SMC_CMD_SET_EFUSE = 17,
+ VCOREFS_SMC_CMD_GET_EFUSE = 18,
+ VCOREFS_SMC_CMD_DVFS_HOPPING = 19,
+ VCOREFS_SMC_CMD_DVFS_HOPPING_STATE = 20,
+};
+
+enum dvfsrc_channel {
+ DVFSRC_CHANNEL_1 = 1,
+ DVFSRC_CHANNEL_2,
+ DVFSRC_CHANNEL_3,
+ DVFSRC_CHANNEL_4,
+ NUM_DVFSRC_CHANNEL,
+};
+
+#define _VCORE_BASE_UV 400000
+#define _VCORE_STEP_UV 6250
+
+/* PMIC */
+#define __vcore_pmic_to_uv(pmic) \
+ (((pmic) * _VCORE_STEP_UV) + _VCORE_BASE_UV)
+
+#define __vcore_uv_to_pmic(uv) /* pmic >= uv */ \
+ ((((uv) - _VCORE_BASE_UV) + (_VCORE_STEP_UV - 1)) / _VCORE_STEP_UV)
+
+struct reg_config {
+ uint32_t offset;
+ uint32_t val;
+};
+
+#define DVFSRC_BASIC_CONTROL (DVFSRC_BASE + 0x0)
+#define DVFSRC_SW_REQ1 (DVFSRC_BASE + 0x4)
+#define DVFSRC_SW_REQ2 (DVFSRC_BASE + 0x8)
+#define DVFSRC_SW_REQ3 (DVFSRC_BASE + 0xC)
+#define DVFSRC_SW_REQ4 (DVFSRC_BASE + 0x10)
+#define DVFSRC_SW_REQ5 (DVFSRC_BASE + 0x14)
+#define DVFSRC_SW_REQ6 (DVFSRC_BASE + 0x18)
+#define DVFSRC_SW_REQ7 (DVFSRC_BASE + 0x1C)
+#define DVFSRC_SW_REQ8 (DVFSRC_BASE + 0x20)
+#define DVFSRC_EMI_REQUEST (DVFSRC_BASE + 0x24)
+#define DVFSRC_EMI_REQUEST2 (DVFSRC_BASE + 0x28)
+#define DVFSRC_EMI_REQUEST3 (DVFSRC_BASE + 0x2C)
+#define DVFSRC_EMI_REQUEST4 (DVFSRC_BASE + 0x30)
+#define DVFSRC_EMI_REQUEST5 (DVFSRC_BASE + 0x34)
+#define DVFSRC_EMI_REQUEST6 (DVFSRC_BASE + 0x38)
+#define DVFSRC_EMI_HRT (DVFSRC_BASE + 0x3C)
+#define DVFSRC_EMI_HRT2 (DVFSRC_BASE + 0x40)
+#define DVFSRC_EMI_HRT3 (DVFSRC_BASE + 0x44)
+#define DVFSRC_EMI_QOS0 (DVFSRC_BASE + 0x48)
+#define DVFSRC_EMI_QOS1 (DVFSRC_BASE + 0x4C)
+#define DVFSRC_EMI_QOS2 (DVFSRC_BASE + 0x50)
+#define DVFSRC_EMI_MD2SPM0 (DVFSRC_BASE + 0x54)
+#define DVFSRC_EMI_MD2SPM1 (DVFSRC_BASE + 0x58)
+#define DVFSRC_EMI_MD2SPM2 (DVFSRC_BASE + 0x5C)
+#define DVFSRC_EMI_MD2SPM0_T (DVFSRC_BASE + 0x60)
+#define DVFSRC_EMI_MD2SPM1_T (DVFSRC_BASE + 0x64)
+#define DVFSRC_EMI_MD2SPM2_T (DVFSRC_BASE + 0x68)
+#define DVFSRC_VCORE_REQUEST (DVFSRC_BASE + 0x6C)
+#define DVFSRC_VCORE_REQUEST2 (DVFSRC_BASE + 0x70)
+#define DVFSRC_VCORE_REQUEST3 (DVFSRC_BASE + 0x74)
+#define DVFSRC_VCORE_REQUEST4 (DVFSRC_BASE + 0x78)
+#define DVFSRC_VCORE_HRT (DVFSRC_BASE + 0x7C)
+#define DVFSRC_VCORE_HRT2 (DVFSRC_BASE + 0x80)
+#define DVFSRC_VCORE_HRT3 (DVFSRC_BASE + 0x84)
+#define DVFSRC_VCORE_QOS0 (DVFSRC_BASE + 0x88)
+#define DVFSRC_VCORE_QOS1 (DVFSRC_BASE + 0x8C)
+#define DVFSRC_VCORE_QOS2 (DVFSRC_BASE + 0x90)
+#define DVFSRC_VCORE_MD2SPM0 (DVFSRC_BASE + 0x94)
+#define DVFSRC_VCORE_MD2SPM1 (DVFSRC_BASE + 0x98)
+#define DVFSRC_VCORE_MD2SPM2 (DVFSRC_BASE + 0x9C)
+#define DVFSRC_VCORE_MD2SPM0_T (DVFSRC_BASE + 0xA0)
+#define DVFSRC_VCORE_MD2SPM1_T (DVFSRC_BASE + 0xA4)
+#define DVFSRC_VCORE_MD2SPM2_T (DVFSRC_BASE + 0xA8)
+#define DVFSRC_MD_VSRAM_REMAP (DVFSRC_BASE + 0xBC)
+#define DVFSRC_HALT_SW_CONTROL (DVFSRC_BASE + 0xC0)
+#define DVFSRC_INT (DVFSRC_BASE + 0xC4)
+#define DVFSRC_INT_EN (DVFSRC_BASE + 0xC8)
+#define DVFSRC_INT_CLR (DVFSRC_BASE + 0xCC)
+#define DVFSRC_BW_MON_WINDOW (DVFSRC_BASE + 0xD0)
+#define DVFSRC_BW_MON_THRES_1 (DVFSRC_BASE + 0xD4)
+#define DVFSRC_BW_MON_THRES_2 (DVFSRC_BASE + 0xD8)
+#define DVFSRC_MD_TURBO (DVFSRC_BASE + 0xDC)
+#define DVFSRC_PCIE_VCORE_REQ (DVFSRC_BASE + 0xE0)
+#define DVFSRC_VCORE_USER_REQ (DVFSRC_BASE + 0xE4)
+#define DVFSRC_DEBOUNCE_FOUR (DVFSRC_BASE + 0xF0)
+#define DVFSRC_DEBOUNCE_RISE_FALL (DVFSRC_BASE + 0xF4)
+#define DVFSRC_TIMEOUT_NEXTREQ (DVFSRC_BASE + 0xF8)
+#define DVFSRC_LEVEL_LABEL_0_1 (DVFSRC_BASE + 0x100)
+#define DVFSRC_LEVEL_LABEL_2_3 (DVFSRC_BASE + 0x104)
+#define DVFSRC_LEVEL_LABEL_4_5 (DVFSRC_BASE + 0x108)
+#define DVFSRC_LEVEL_LABEL_6_7 (DVFSRC_BASE + 0x10C)
+#define DVFSRC_LEVEL_LABEL_8_9 (DVFSRC_BASE + 0x110)
+#define DVFSRC_LEVEL_LABEL_10_11 (DVFSRC_BASE + 0x114)
+#define DVFSRC_LEVEL_LABEL_12_13 (DVFSRC_BASE + 0x118)
+#define DVFSRC_LEVEL_LABEL_14_15 (DVFSRC_BASE + 0x11C)
+#define DVFSRC_MM_BW_0 (DVFSRC_BASE + 0x200)
+#define DVFSRC_MM_BW_1 (DVFSRC_BASE + 0x204)
+#define DVFSRC_MM_BW_2 (DVFSRC_BASE + 0x208)
+#define DVFSRC_MM_BW_3 (DVFSRC_BASE + 0x20C)
+#define DVFSRC_MM_BW_4 (DVFSRC_BASE + 0x210)
+#define DVFSRC_MM_BW_5 (DVFSRC_BASE + 0x214)
+#define DVFSRC_MM_BW_6 (DVFSRC_BASE + 0x218)
+#define DVFSRC_MM_BW_7 (DVFSRC_BASE + 0x21C)
+#define DVFSRC_MM_BW_8 (DVFSRC_BASE + 0x220)
+#define DVFSRC_MM_BW_9 (DVFSRC_BASE + 0x224)
+#define DVFSRC_MM_BW_10 (DVFSRC_BASE + 0x228)
+#define DVFSRC_MM_BW_11 (DVFSRC_BASE + 0x22C)
+#define DVFSRC_MM_BW_12 (DVFSRC_BASE + 0x230)
+#define DVFSRC_MM_BW_13 (DVFSRC_BASE + 0x234)
+#define DVFSRC_MM_BW_14 (DVFSRC_BASE + 0x238)
+#define DVFSRC_MM_BW_15 (DVFSRC_BASE + 0x23C)
+#define DVFSRC_MD_BW_0 (DVFSRC_BASE + 0x240)
+#define DVFSRC_MD_BW_1 (DVFSRC_BASE + 0x244)
+#define DVFSRC_MD_BW_2 (DVFSRC_BASE + 0x248)
+#define DVFSRC_MD_BW_3 (DVFSRC_BASE + 0x24C)
+#define DVFSRC_MD_BW_4 (DVFSRC_BASE + 0x250)
+#define DVFSRC_MD_BW_5 (DVFSRC_BASE + 0x254)
+#define DVFSRC_MD_BW_6 (DVFSRC_BASE + 0x258)
+#define DVFSRC_MD_BW_7 (DVFSRC_BASE + 0x25C)
+#define DVFSRC_SW_BW_0 (DVFSRC_BASE + 0x260)
+#define DVFSRC_SW_BW_1 (DVFSRC_BASE + 0x264)
+#define DVFSRC_SW_BW_2 (DVFSRC_BASE + 0x268)
+#define DVFSRC_SW_BW_3 (DVFSRC_BASE + 0x26C)
+#define DVFSRC_SW_BW_4 (DVFSRC_BASE + 0x270)
+#define DVFSRC_SW_BW_5 (DVFSRC_BASE + 0x274)
+#define DVFSRC_SW_BW_6 (DVFSRC_BASE + 0x278)
+#define DVFSRC_QOS_EN (DVFSRC_BASE + 0x280)
+#define DVFSRC_MD_BW_URG (DVFSRC_BASE + 0x284)
+#define DVFSRC_ISP_HRT (DVFSRC_BASE + 0x290)
+#define DVFSRC_HRT_BW_BASE (DVFSRC_BASE + 0x294)
+#define DVFSRC_SEC_SW_REQ (DVFSRC_BASE + 0x304)
+#define DVFSRC_EMI_MON_DEBOUNCE_TIME (DVFSRC_BASE + 0x308)
+#define DVFSRC_MD_LATENCY_IMPROVE (DVFSRC_BASE + 0x30C)
+#define DVFSRC_BASIC_CONTROL_3 (DVFSRC_BASE + 0x310)
+#define DVFSRC_DEBOUNCE_TIME (DVFSRC_BASE + 0x314)
+#define DVFSRC_LEVEL_MASK (DVFSRC_BASE + 0x318)
+#define DVFSRC_DEFAULT_OPP (DVFSRC_BASE + 0x31C)
+#define DVFSRC_95MD_SCEN_EMI0 (DVFSRC_BASE + 0x500)
+#define DVFSRC_95MD_SCEN_EMI1 (DVFSRC_BASE + 0x504)
+#define DVFSRC_95MD_SCEN_EMI2 (DVFSRC_BASE + 0x508)
+#define DVFSRC_95MD_SCEN_EMI3 (DVFSRC_BASE + 0x50C)
+#define DVFSRC_95MD_SCEN_EMI0_T (DVFSRC_BASE + 0x510)
+#define DVFSRC_95MD_SCEN_EMI1_T (DVFSRC_BASE + 0x514)
+#define DVFSRC_95MD_SCEN_EMI2_T (DVFSRC_BASE + 0x518)
+#define DVFSRC_95MD_SCEN_EMI3_T (DVFSRC_BASE + 0x51C)
+#define DVFSRC_95MD_SCEN_EMI4 (DVFSRC_BASE + 0x520)
+#define DVFSRC_95MD_SCEN_BW0 (DVFSRC_BASE + 0x524)
+#define DVFSRC_95MD_SCEN_BW1 (DVFSRC_BASE + 0x528)
+#define DVFSRC_95MD_SCEN_BW2 (DVFSRC_BASE + 0x52C)
+#define DVFSRC_95MD_SCEN_BW3 (DVFSRC_BASE + 0x530)
+#define DVFSRC_95MD_SCEN_BW0_T (DVFSRC_BASE + 0x534)
+#define DVFSRC_95MD_SCEN_BW1_T (DVFSRC_BASE + 0x538)
+#define DVFSRC_95MD_SCEN_BW2_T (DVFSRC_BASE + 0x53C)
+#define DVFSRC_95MD_SCEN_BW3_T (DVFSRC_BASE + 0x540)
+#define DVFSRC_95MD_SCEN_BW4 (DVFSRC_BASE + 0x544)
+#define DVFSRC_MD_LEVEL_SW_REG (DVFSRC_BASE + 0x548)
+#define DVFSRC_RSRV_0 (DVFSRC_BASE + 0x600)
+#define DVFSRC_RSRV_1 (DVFSRC_BASE + 0x604)
+#define DVFSRC_RSRV_2 (DVFSRC_BASE + 0x608)
+#define DVFSRC_RSRV_3 (DVFSRC_BASE + 0x60C)
+#define DVFSRC_RSRV_4 (DVFSRC_BASE + 0x610)
+#define DVFSRC_RSRV_5 (DVFSRC_BASE + 0x614)
+#define DVFSRC_SPM_RESEND (DVFSRC_BASE + 0x630)
+#define DVFSRC_DEBUG_STA_0 (DVFSRC_BASE + 0x700)
+#define DVFSRC_DEBUG_STA_1 (DVFSRC_BASE + 0x704)
+#define DVFSRC_DEBUG_STA_2 (DVFSRC_BASE + 0x708)
+#define DVFSRC_DEBUG_STA_3 (DVFSRC_BASE + 0x70C)
+#define DVFSRC_DEBUG_STA_4 (DVFSRC_BASE + 0x710)
+#define DVFSRC_DEBUG_STA_5 (DVFSRC_BASE + 0x714)
+#define DVFSRC_EMI_REQUEST7 (DVFSRC_BASE + 0x800)
+#define DVFSRC_EMI_HRT_1 (DVFSRC_BASE + 0x804)
+#define DVFSRC_EMI_HRT2_1 (DVFSRC_BASE + 0x808)
+#define DVFSRC_EMI_HRT3_1 (DVFSRC_BASE + 0x80C)
+#define DVFSRC_EMI_QOS3 (DVFSRC_BASE + 0x810)
+#define DVFSRC_EMI_QOS4 (DVFSRC_BASE + 0x814)
+#define DVFSRC_DDR_REQUEST (DVFSRC_BASE + 0xA00)
+#define DVFSRC_DDR_REQUEST2 (DVFSRC_BASE + 0xA04)
+#define DVFSRC_DDR_REQUEST3 (DVFSRC_BASE + 0xA08)
+#define DVFSRC_DDR_REQUEST4 (DVFSRC_BASE + 0xA0C)
+#define DVFSRC_DDR_REQUEST5 (DVFSRC_BASE + 0xA10)
+#define DVFSRC_DDR_REQUEST6 (DVFSRC_BASE + 0xA14)
+#define DVFSRC_DDR_REQUEST7 (DVFSRC_BASE + 0xA18)
+#define DVFSRC_DDR_HRT (DVFSRC_BASE + 0xA1C)
+#define DVFSRC_DDR_HRT2 (DVFSRC_BASE + 0xA20)
+#define DVFSRC_DDR_HRT3 (DVFSRC_BASE + 0xA24)
+#define DVFSRC_DDR_HRT_1 (DVFSRC_BASE + 0xA28)
+#define DVFSRC_DDR_HRT2_1 (DVFSRC_BASE + 0xA2C)
+#define DVFSRC_DDR_HRT3_1 (DVFSRC_BASE + 0xA30)
+#define DVFSRC_DDR_QOS0 (DVFSRC_BASE + 0xA34)
+#define DVFSRC_DDR_QOS1 (DVFSRC_BASE + 0xA38)
+#define DVFSRC_DDR_QOS2 (DVFSRC_BASE + 0xA3C)
+#define DVFSRC_DDR_QOS3 (DVFSRC_BASE + 0xA40)
+#define DVFSRC_DDR_QOS4 (DVFSRC_BASE + 0xA44)
+#define DVFSRC_DDR_MD2SPM0 (DVFSRC_BASE + 0xA48)
+#define DVFSRC_DDR_MD2SPM1 (DVFSRC_BASE + 0xA4C)
+#define DVFSRC_DDR_MD2SPM2 (DVFSRC_BASE + 0xA50)
+#define DVFSRC_DDR_MD2SPM0_T (DVFSRC_BASE + 0xA54)
+#define DVFSRC_DDR_MD2SPM1_T (DVFSRC_BASE + 0xA58)
+#define DVFSRC_DDR_MD2SPM2_T (DVFSRC_BASE + 0xA5C)
+#define DVFSRC_HRT_REQ_UNIT (DVFSRC_BASE + 0xA60)
+#define DVSFRC_HRT_REQ_MD_URG (DVFSRC_BASE + 0xA64)
+#define DVFSRC_HRT_REQ_MD_BW_0 (DVFSRC_BASE + 0xA68)
+#define DVFSRC_HRT_REQ_MD_BW_1 (DVFSRC_BASE + 0xA6C)
+#define DVFSRC_HRT_REQ_MD_BW_2 (DVFSRC_BASE + 0xA70)
+#define DVFSRC_HRT_REQ_MD_BW_3 (DVFSRC_BASE + 0xA74)
+#define DVFSRC_HRT_REQ_MD_BW_4 (DVFSRC_BASE + 0xA78)
+#define DVFSRC_HRT_REQ_MD_BW_5 (DVFSRC_BASE + 0xA7C)
+#define DVFSRC_HRT_REQ_MD_BW_6 (DVFSRC_BASE + 0xA80)
+#define DVFSRC_HRT_REQ_MD_BW_7 (DVFSRC_BASE + 0xA84)
+#define DVFSRC_HRT1_REQ_MD_BW_0 (DVFSRC_BASE + 0xA88)
+#define DVFSRC_HRT1_REQ_MD_BW_1 (DVFSRC_BASE + 0xA8C)
+#define DVFSRC_HRT1_REQ_MD_BW_2 (DVFSRC_BASE + 0xA90)
+#define DVFSRC_HRT1_REQ_MD_BW_3 (DVFSRC_BASE + 0xA94)
+#define DVFSRC_HRT1_REQ_MD_BW_4 (DVFSRC_BASE + 0xA98)
+#define DVFSRC_HRT1_REQ_MD_BW_5 (DVFSRC_BASE + 0xA9C)
+#define DVFSRC_HRT1_REQ_MD_BW_6 (DVFSRC_BASE + 0xAA0)
+#define DVFSRC_HRT1_REQ_MD_BW_7 (DVFSRC_BASE + 0xAA4)
+#define DVFSRC_HRT_REQ_MD_BW_8 (DVFSRC_BASE + 0xAA8)
+#define DVFSRC_HRT_REQ_MD_BW_9 (DVFSRC_BASE + 0xAAC)
+#define DVFSRC_HRT_REQ_MD_BW_10 (DVFSRC_BASE + 0xAB0)
+#define DVFSRC_HRT1_REQ_MD_BW_8 (DVFSRC_BASE + 0xAB4)
+#define DVFSRC_HRT1_REQ_MD_BW_9 (DVFSRC_BASE + 0xAB8)
+#define DVFSRC_HRT1_REQ_MD_BW_10 (DVFSRC_BASE + 0xABC)
+#define DVFSRC_HRT_REQ_BW_SW_REG (DVFSRC_BASE + 0xAC0)
+#define DVFSRC_HRT_REQUEST (DVFSRC_BASE + 0xAC4)
+#define DVFSRC_HRT_HIGH_2 (DVFSRC_BASE + 0xAC8)
+#define DVFSRC_HRT_HIGH_1 (DVFSRC_BASE + 0xACC)
+#define DVFSRC_HRT_HIGH (DVFSRC_BASE + 0xAD0)
+#define DVFSRC_HRT_LOW_2 (DVFSRC_BASE + 0xAD4)
+#define DVFSRC_HRT_LOW_1 (DVFSRC_BASE + 0xAD8)
+#define DVFSRC_HRT_LOW (DVFSRC_BASE + 0xADC)
+#define DVFSRC_DDR_ADD_REQUEST (DVFSRC_BASE + 0xAE0)
+#define DVFSRC_LAST (DVFSRC_BASE + 0xAE4)
+#define DVFSRC_LAST_L (DVFSRC_BASE + 0xAE8)
+#define DVFSRC_MD_SCENARIO (DVFSRC_BASE + 0xAEC)
+#define DVFSRC_RECORD_0_0 (DVFSRC_BASE + 0xAF0)
+#define DVFSRC_RECORD_0_1 (DVFSRC_BASE + 0xAF4)
+#define DVFSRC_RECORD_0_2 (DVFSRC_BASE + 0xAF8)
+#define DVFSRC_RECORD_0_3 (DVFSRC_BASE + 0xAFC)
+#define DVFSRC_RECORD_0_4 (DVFSRC_BASE + 0xB00)
+#define DVFSRC_RECORD_0_5 (DVFSRC_BASE + 0xB04)
+#define DVFSRC_RECORD_0_6 (DVFSRC_BASE + 0xB08)
+#define DVFSRC_RECORD_0_7 (DVFSRC_BASE + 0xB0C)
+#define DVFSRC_RECORD_0_L_0 (DVFSRC_BASE + 0xBF0)
+#define DVFSRC_RECORD_0_L_1 (DVFSRC_BASE + 0xBF4)
+#define DVFSRC_RECORD_0_L_2 (DVFSRC_BASE + 0xBF8)
+#define DVFSRC_RECORD_0_L_3 (DVFSRC_BASE + 0xBFC)
+#define DVFSRC_RECORD_0_L_4 (DVFSRC_BASE + 0xC00)
+#define DVFSRC_RECORD_0_L_5 (DVFSRC_BASE + 0xC04)
+#define DVFSRC_RECORD_0_L_6 (DVFSRC_BASE + 0xC08)
+#define DVFSRC_RECORD_0_L_7 (DVFSRC_BASE + 0xC0C)
+#define DVFSRC_EMI_REQUEST8 (DVFSRC_BASE + 0xCF0)
+#define DVFSRC_DDR_REQUEST8 (DVFSRC_BASE + 0xCF4)
+#define DVFSRC_EMI_HRT_2 (DVFSRC_BASE + 0xCF8)
+#define DVFSRC_EMI_HRT2_2 (DVFSRC_BASE + 0xCFC)
+#define DVFSRC_EMI_HRT3_2 (DVFSRC_BASE + 0xD00)
+#define DVFSRC_EMI_QOS5 (DVFSRC_BASE + 0xD04)
+#define DVFSRC_EMI_QOS6 (DVFSRC_BASE + 0xD08)
+#define DVFSRC_DDR_HRT_2 (DVFSRC_BASE + 0xD0C)
+#define DVFSRC_DDR_HRT2_2 (DVFSRC_BASE + 0xD10)
+#define DVFSRC_DDR_HRT3_2 (DVFSRC_BASE + 0xD14)
+#define DVFSRC_DDR_QOS5 (DVFSRC_BASE + 0xD18)
+#define DVFSRC_DDR_QOS6 (DVFSRC_BASE + 0xD1C)
+#define DVFSRC_VCORE_REQUEST5 (DVFSRC_BASE + 0xD20)
+#define DVFSRC_VCORE_HRT_1 (DVFSRC_BASE + 0xD24)
+#define DVFSRC_VCORE_HRT2_1 (DVFSRC_BASE + 0xD28)
+#define DVFSRC_VCORE_HRT3_1 (DVFSRC_BASE + 0xD2C)
+#define DVFSRC_VCORE_QOS3 (DVFSRC_BASE + 0xD30)
+#define DVFSRC_VCORE_QOS4 (DVFSRC_BASE + 0xD34)
+#define DVFSRC_HRT_HIGH_3 (DVFSRC_BASE + 0xD38)
+#define DVFSRC_HRT_LOW_3 (DVFSRC_BASE + 0xD3C)
+#define DVFSRC_BASIC_CONTROL_2 (DVFSRC_BASE + 0xD40)
+#define DVFSRC_CURRENT_LEVEL (DVFSRC_BASE + 0xD44)
+#define DVFSRC_TARGET_LEVEL (DVFSRC_BASE + 0xD48)
+#define DVFSRC_LEVEL_LABEL_16_17 (DVFSRC_BASE + 0xD4C)
+#define DVFSRC_LEVEL_LABEL_18_19 (DVFSRC_BASE + 0xD50)
+#define DVFSRC_LEVEL_LABEL_20_21 (DVFSRC_BASE + 0xD54)
+#define DVFSRC_LEVEL_LABEL_22_23 (DVFSRC_BASE + 0xD58)
+#define DVFSRC_LEVEL_LABEL_24_25 (DVFSRC_BASE + 0xD5C)
+#define DVFSRC_LEVEL_LABEL_26_27 (DVFSRC_BASE + 0xD60)
+#define DVFSRC_LEVEL_LABEL_28_29 (DVFSRC_BASE + 0xD64)
+#define DVFSRC_LEVEL_LABEL_30_31 (DVFSRC_BASE + 0xD68)
+#define DVFSRC_CURRENT_FORCE (DVFSRC_BASE + 0xD6C)
+#define DVFSRC_TARGET_FORCE (DVFSRC_BASE + 0xD70)
+#define DVFSRC_EMI_ADD_REQUEST (DVFSRC_BASE + 0xD74)
+
+#endif /* __MT_SPM_VCOREFS__H__ */
diff --git a/plat/mediatek/mt8195/drivers/spm/notifier/mt_spm_notifier.h b/plat/mediatek/mt8195/drivers/spm/notifier/mt_spm_notifier.h
new file mode 100644
index 0000000..ee3738d
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/notifier/mt_spm_notifier.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_SSPM_NOTIFIER_H
+#define MT_SPM_SSPM_NOTIFIER_H
+
+enum MT_SPM_SSPM_NOTIFY_ID {
+ MT_SPM_NOTIFY_LP_ENTER,
+ MT_SPM_NOTIFY_LP_LEAVE,
+};
+
+int mt_spm_sspm_notify(int type, unsigned int lp_mode);
+
+static inline int mt_spm_sspm_notify_u32(int type, unsigned int lp_mode)
+{
+ return mt_spm_sspm_notify(type, lp_mode);
+}
+#endif /* MT_SPM_SSPM_NOTIFIER_H */
diff --git a/plat/mediatek/mt8195/drivers/spm/notifier/mt_spm_sspm_intc.h b/plat/mediatek/mt8195/drivers/spm/notifier/mt_spm_sspm_intc.h
new file mode 100644
index 0000000..6847e77
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/notifier/mt_spm_sspm_intc.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_SPM_SSPM_INTC_H
+#define MT_SPM_SSPM_INTC_H
+
+#include <mt_spm_reg.h>
+
+#define MT_SPM_SSPM_INTC_SEL_0 0x10
+#define MT_SPM_SSPM_INTC_SEL_1 0x20
+#define MT_SPM_SSPM_INTC_SEL_2 0x40
+#define MT_SPM_SSPM_INTC_SEL_3 0x80
+
+#define MT_SPM_SSPM_INTC_TRIGGER(id, sg) \
+ (((0x10 << id) | (sg << id)) & 0xff)
+
+#define MT_SPM_SSPM_INTC0_HIGH MT_SPM_SSPM_INTC_TRIGGER(0, 1)
+#define MT_SPM_SSPM_INTC0_LOW MT_SPM_SSPM_INTC_TRIGGER(0, 0)
+#define MT_SPM_SSPM_INTC1_HIGH MT_SPM_SSPM_INTC_TRIGGER(1, 1)
+#define MT_SPM_SSPM_INTC1_LOW MT_SPM_SSPM_INTC_TRIGGER(1, 0)
+#define MT_SPM_SSPM_INTC2_HIGH MT_SPM_SSPM_INTC_TRIGGER(2, 1)
+#define MT_SPM_SSPM_INTC2_LOW MT_SPM_SSPM_INTC_TRIGGER(2, 0)
+#define MT_SPM_SSPM_INTC3_HIGH MT_SPM_SSPM_INTC_TRIGGER(3, 1)
+#define MT_SPM_SSPM_INTC3_LOW MT_SPM_SSPM_INTC_TRIGGER(3, 0)
+
+#define DO_SPM_SSPM_LP_SUSPEND() \
+ mmio_write_32(SPM_MD32_IRQ, MT_SPM_SSPM_INTC0_HIGH)
+#define DO_SPM_SSPM_LP_RESUME() \
+ mmio_write_32(SPM_MD32_IRQ, MT_SPM_SSPM_INTC0_LOW)
+#endif /* MT_SPM_SSPM_INTC_H */
diff --git a/plat/mediatek/mt8195/drivers/spm/notifier/mt_spm_sspm_notifier.c b/plat/mediatek/mt8195/drivers/spm/notifier/mt_spm_sspm_notifier.c
new file mode 100644
index 0000000..a755a38
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/notifier/mt_spm_sspm_notifier.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <lib/mmio.h>
+
+#include <mt_spm_notifier.h>
+#include <mt_spm_sspm_intc.h>
+
+#define MT_SPM_SSPM_MBOX_OFF(x) (SSPM_MBOX_BASE + x)
+#define MT_SPM_MBOX(slot) MT_SPM_SSPM_MBOX_OFF((slot << 2UL))
+
+#define SSPM_MBOX_SPM_LP_LOOKUP1 MT_SPM_MBOX(0)
+#define SSPM_MBOX_SPM_LP_LOOKUP2 MT_SPM_MBOX(1)
+#define SSPM_MBOX_SPM_LP1 MT_SPM_MBOX(2)
+#define SSPM_MBOX_SPM_LP2 MT_SPM_MBOX(3)
+
+int mt_spm_sspm_notify(int type, unsigned int lp_mode)
+{
+ switch (type) {
+ case MT_SPM_NOTIFY_LP_ENTER:
+ mmio_write_32(SSPM_MBOX_SPM_LP1, lp_mode);
+ DO_SPM_SSPM_LP_SUSPEND();
+ break;
+ case MT_SPM_NOTIFY_LP_LEAVE:
+ mmio_write_32(SSPM_MBOX_SPM_LP1, lp_mode);
+ DO_SPM_SSPM_LP_RESUME();
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8195/drivers/spm/pcm_def.h b/plat/mediatek/mt8195/drivers/spm/pcm_def.h
new file mode 100644
index 0000000..fa77b95
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/pcm_def.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PCM_DEF_H
+#define PCM_DEF_H
+
+/*
+ * Auto generated by DE, please DO NOT modify this file directly.
+ */
+
+/* --- R0 Define --- */
+#define R0_SC_26M_CK_OFF (1U << 0)
+#define R0_SC_TX_TRACK_RETRY_EN (1U << 1)
+#define R0_SC_MEM_CK_OFF (1U << 2)
+#define R0_SC_AXI_CK_OFF (1U << 3)
+#define R0_SC_DR_SRAM_LOAD (1U << 4)
+#define R0_SC_MD26M_CK_OFF (1U << 5)
+#define R0_SC_DPY_MODE_SW (1U << 6)
+#define R0_SC_DMSUS_OFF (1U << 7)
+#define R0_SC_DPY_2ND_DLL_EN (1U << 8)
+#define R0_SC_DR_SRAM_RESTORE (1U << 9)
+#define R0_SC_MPLLOUT_OFF (1U << 10)
+#define R0_SC_TX_TRACKING_DIS (1U << 11)
+#define R0_SC_DPY_DLL_EN (1U << 12)
+#define R0_SC_DPY_DLL_CK_EN (1U << 13)
+#define R0_SC_DPY_VREF_EN (1U << 14)
+#define R0_SC_PHYPLL_EN (1U << 15)
+#define R0_SC_DDRPHY_FB_CK_EN (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_DR_SHU_LEVEL_SRAM_LATCH (1U << 21)
+#define R0_SC_DR_SHU_EN (1U << 22)
+#define R0_SC_DPHY_PRECAL_UP (1U << 23)
+#define R0_SC_MPLL_S_OFF (1U << 24)
+#define R0_SC_DPHY_RXDLY_TRACKING_EN (1U << 25)
+#define R0_SC_PHYPLL_SHU_EN (1U << 26)
+#define R0_SC_PHYPLL2_SHU_EN (1U << 27)
+#define R0_SC_PHYPLL_MODE_SW (1U << 28)
+#define R0_SC_PHYPLL2_MODE_SW (1U << 29)
+#define R0_SC_DR_SHU_LEVEL0 (1U << 30)
+#define R0_SC_DR_SHU_LEVEL1 (1U << 31)
+/* --- R7 Define --- */
+#define R7_PWRAP_SLEEP_REQ (1U << 0)
+#define R7_EMI_CLK_OFF_REQ (1U << 1)
+#define R7_PCM_BUS_PROTECT_REQ (1U << 2)
+#define R7_SPM_CK_UPDATE (1U << 3)
+#define R7_SPM_CK_SEL0 (1U << 4)
+#define R7_SPM_CK_SEL1 (1U << 5)
+#define R7_SPM_LEAVE_DEEPIDLE_REQ (1U << 6)
+#define R7_SC_FHC_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_SPM_LEAVE_SUSPEND_REQ (1U << 11)
+#define R7_CSYSPWRUPACK (1U << 12)
+#define R7_PCM_IM_SLP_EN (1U << 13)
+#define R7_SRCCLKENO0 (1U << 14)
+#define R7_FORCE_DDR_EN_WAKE (1U << 15)
+#define R7_SPM_APSRC_INTERNAL_ACK (1U << 16)
+#define R7_CPU_SYS_TIMER_CLK_SEL (1U << 17)
+#define R7_SC_AXI_DCM_DIS (1U << 18)
+#define R7_SC_FHC_PAUSE_MEM (1U << 19)
+#define R7_SC_FHC_PAUSE_MAIN (1U << 20)
+#define R7_SRCCLKENO1 (1U << 21)
+#define R7_PCM_WDT_KICK_P (1U << 22)
+#define R7_SPM2EMI_S1_MODE_ASYNC (1U << 23)
+#define R7_SC_DDR_PST_REQ_PCM (1U << 24)
+#define R7_SC_DDR_PST_ABORT_REQ_PCM (1U << 25)
+#define R7_PMIC_IRQ_REQ_EN (1U << 26)
+#define R7_FORCE_F26M_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_SPM_DDR_EN_INTERNAL_ACK (1U << 31)
+/* --- R12 Define --- */
+#define R12_PCM_TIMER (1U << 0)
+#define R12_TWAM_IRQ_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_SSPM2SPM_WAKEUP_B (1U << 10)
+#define R12_SCP2SPM_WAKEUP_B (1U << 11)
+#define R12_ADSP2SPM_WAKEUP_B (1U << 12)
+#define R12_PCM_WDT_WAKEUP_B (1U << 13)
+#define R12_USBX_CDSC_B (1U << 14)
+#define R12_USBX_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_EVENT_B (1U << 27)
+#define R12_REG_CPU_WAKEUP (1U << 28)
+#define R12_APUSYS_WAKE_HOST_B (1U << 29)
+#define R12_NOT_USED1 (1U << 30)
+#define R12_NOT_USED2 (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_WAKE (1U << 8)
+#define R12EXT_DDREN_WAKE (1U << 9)
+#define R12EXT_DDREN_SLEEP (1U << 10)
+#define R12EXT_MCU_PM_WFI (1U << 11)
+#define R12EXT_SSPM_IDLE (1U << 12)
+#define R12EXT_CONN_SRCCLKENB (1U << 13)
+#define R12EXT_DRAMC_SSPM_WFI_MERGE (1U << 14)
+#define R12EXT_SW_MAILBOX_WAKE (1U << 15)
+#define R12EXT_SSPM_MAILBOX_WAKE (1U << 16)
+#define R12EXT_ADSP_MAILBOX_WAKE (1U << 17)
+#define R12EXT_SCP_MAILBOX_WAKE (1U << 18)
+#define R12EXT_SPM_LEAVE_SUSPEND_ACK (1U << 19)
+#define R12EXT_SPM_LEAVE_DEEPIDLE_ACK (1U << 20)
+#define R12EXT_VS1_TRIGGER (1U << 21)
+#define R12EXT_VS2_TRIGGER (1U << 22)
+#define R12EXT_COROSS_REQ_APU (1U << 23)
+#define R12EXT_CROSS_REQ_L3 (1U << 24)
+#define R12EXT_DDR_PST_ACK (1U << 25)
+#define R12EXT_BIT26 (1U << 26)
+#define R12EXT_BIT27 (1U << 27)
+#define R12EXT_BIT28 (1U << 28)
+#define R12EXT_BIT29 (1U << 29)
+#define R12EXT_BIT30 (1U << 30)
+#define R12EXT_BIT31 (1U << 31)
+/* --- R13 Define --- */
+#define R13_SRCCLKENI0 (1U << 0)
+#define R13_SRCCLKENI1 (1U << 1)
+#define R13_MD_SRCCLKENA_0 (1U << 2)
+#define R13_MD_APSRC_REQ_0 (1U << 3)
+#define R13_CONN_DDR_EN (1U << 4)
+#define R13_MD_SRCCLKENA_1 (1U << 5)
+#define R13_SSPM_SRCCLKENA (1U << 6)
+#define R13_SSPM_APSRC_REQ (1U << 7)
+#define R13_MD1_STATE (1U << 8)
+#define R13_BIT9 (1U << 9)
+#define R13_MM_STATE (1U << 10)
+#define R13_SSPM_STATE (1U << 11)
+#define R13_MD_DDR_EN_0 (1U << 12)
+#define R13_CONN_STATE (1U << 13)
+#define R13_CONN_SRCCLKENA (1U << 14)
+#define R13_CONN_APSRC_REQ (1U << 15)
+#define R13_SC_DDR_PST_ACK_ALL (1U << 16)
+#define R13_SC_DDR_PST_ABORT_ACK_ALL (1U << 17)
+#define R13_SCP_STATE (1U << 18)
+#define R13_CSYSPWRUPREQ (1U << 19)
+#define R13_PWRAP_SLEEP_ACK (1U << 20)
+#define R13_SC_EMI_CLK_OFF_ACK_ALL (1U << 21)
+#define R13_AUDIO_DSP_STATE (1U << 22)
+#define R13_SC_DMDRAMCSHU_ACK_ALL (1U << 23)
+#define R13_CONN_SRCCLKENB (1U << 24)
+#define R13_SC_DR_SRAM_LOAD_ACK_ALL (1U << 25)
+#define R13_SUBSYS_IDLE_SIGNALS0 (1U << 26)
+#define R13_DVFS_STATE (1U << 27)
+#define R13_SC_DR_SRAM_PLL_LOAD_ACK_ALL (1U << 28)
+#define R13_SC_DR_SRAM_RESTORE_ACK_ALL (1U << 29)
+#define R13_MD_VRF18_REQ_0 (1U << 30)
+#define R13_DDR_EN_STATE (1U << 31)
+#endif /* PCM_DEF_H */
diff --git a/plat/mediatek/mt8195/drivers/spm/sleep_def.h b/plat/mediatek/mt8195/drivers/spm/sleep_def.h
new file mode 100644
index 0000000..2639b7e
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spm/sleep_def.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SLEEP_DEF_H
+#define SLEEP_DEF_H
+
+/*
+ * Auto generated by DE, please DO NOT modify this file directly.
+ */
+
+/* --- SPM Flag Define --- */
+#define SPM_FLAG_DISABLE_CPU_PDN (1U << 0)
+#define SPM_FLAG_DISABLE_INFRA_PDN (1U << 1)
+#define SPM_FLAG_DISABLE_DDRPHY_PDN (1U << 2)
+#define SPM_FLAG_DISABLE_VCORE_DVS (1U << 3)
+#define SPM_FLAG_DISABLE_VCORE_DFS (1U << 4)
+#define SPM_FLAG_DISABLE_COMMON_SCENARIO (1U << 5)
+#define SPM_FLAG_DISABLE_BUS_CLK_OFF (1U << 6)
+#define SPM_FLAG_DISABLE_ARMPLL_OFF (1U << 7)
+#define SPM_FLAG_KEEP_CSYSPWRACK_HIGH (1U << 8)
+#define SPM_FLAG_ENABLE_LVTS_WORKAROUND (1U << 9)
+#define SPM_FLAG_RUN_COMMON_SCENARIO (1U << 10)
+#define SPM_FLAG_RESERVED_BIT11 (1U << 11)
+#define SPM_FLAG_ENABLE_SPM_DBG_WDT_DUMP (1U << 12)
+#define SPM_FLAG_USE_SRCCLKENO2 (1U << 13)
+#define SPM_FLAG_ENABLE_6315_CTRL (1U << 14)
+#define SPM_FLAG_ENABLE_TIA_WORKAROUND (1U << 15)
+#define SPM_FLAG_DISABLE_SYSRAM_SLEEP (1U << 16)
+#define SPM_FLAG_DISABLE_SSPM_SRAM_SLEEP (1U << 17)
+#define SPM_FLAG_DISABLE_MCUPM_SRAM_SLEEP (1U << 18)
+#define SPM_FLAG_DISABLE_DRAMC_ISSUE_CMD (1U << 19)
+#define SPM_FLAG_ENABLE_VOLTAGE_BIN (1U << 20)
+#define SPM_FLAG_RESERVED_BIT21 (1U << 21)
+#define SPM_FLAG_DISABLE_DRAMC_MCU_SRAM_SLEEP (1U << 22)
+#define SPM_FLAG_DISABLE_DRAMC_MD32_BACKUP (1U << 23)
+#define SPM_FLAG_RESERVED_BIT24 (1U << 24)
+#define SPM_FLAG_RESERVED_BIT25 (1U << 25)
+#define SPM_FLAG_RESERVED_BIT26 (1U << 26)
+#define SPM_FLAG_VTCXO_STATE (1U << 27)
+#define SPM_FLAG_INFRA_STATE (1U << 28)
+#define SPM_FLAG_APSRC_STATE (1U << 29)
+#define SPM_FLAG_VRF18_STATE (1U << 30)
+#define SPM_FLAG_DDREN_STATE (1U << 31)
+/* --- SPM Flag1 Define --- */
+#define SPM_FLAG1_DISABLE_AXI_BUS_TO_26M (1U << 0)
+#define SPM_FLAG1_DISABLE_SYSPLL_OFF (1U << 1)
+#define SPM_FLAG1_DISABLE_PWRAP_CLK_SWITCH (1U << 2)
+#define SPM_FLAG1_DISABLE_ULPOSC_OFF (1U << 3)
+#define SPM_FLAG1_FW_SET_ULPOSC_ON (1U << 4)
+#define SPM_FLAG1_RESERVED_BIT5 (1U << 5)
+#define SPM_FLAG1_ENABLE_REKICK (1U << 6)
+#define SPM_FLAG1_RESERVED_BIT7 (1U << 7)
+#define SPM_FLAG1_RESERVED_BIT8 (1U << 8)
+#define SPM_FLAG1_RESERVED_BIT9 (1U << 9)
+#define SPM_FLAG1_DISABLE_SRCLKEN_LOW (1U << 10)
+#define SPM_FLAG1_DISABLE_SCP_CLK_SWITCH (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_RESERVED_BIT15 (1U << 15)
+#define SPM_FLAG1_RESERVED_BIT16 (1U << 16)
+#define SPM_FLAG1_RESERVED_BIT17 (1U << 17)
+#define SPM_FLAG1_RESERVED_BIT18 (1U << 18)
+#define SPM_FLAG1_RESERVED_BIT19 (1U << 19)
+#define SPM_FLAG1_DISABLE_DEVAPC_SRAM_SLEEP (1U << 20)
+#define SPM_FLAG1_RESERVED_BIT21 (1U << 21)
+#define SPM_FLAG1_ENABLE_VS1_VOTER (1U << 22)
+#define SPM_FLAG1_ENABLE_VS2_VOTER (1U << 23)
+#define SPM_FLAG1_DISABLE_SCP_VREQ_MASK_CONTROL (1U << 24)
+#define SPM_FLAG1_RESERVED_BIT25 (1U << 25)
+#define SPM_FLAG1_RESERVED_BIT26 (1U << 26)
+#define SPM_FLAG1_RESERVED_BIT27 (1U << 27)
+#define SPM_FLAG1_RESERVED_BIT28 (1U << 28)
+#define SPM_FLAG1_RESERVED_BIT29 (1U << 29)
+#define SPM_FLAG1_RESERVED_BIT30 (1U << 30)
+#define SPM_FLAG1_RESERVED_BIT31 (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_DRAM_SREF_ABORT_IN_APSRC (1U << 10)
+#define SPM_DBG_DEBUG_IDX_MCUPM_SRAM_STATE (1U << 11)
+#define SPM_DBG_DEBUG_IDX_SSPM_SRAM_STATE (1U << 12)
+#define SPM_DBG_DEBUG_IDX_DRAM_SREF_ABORT_IN_DDREN (1U << 13)
+#define SPM_DBG_DEBUG_IDX_DRAMC_MCU_SRAM_STATE (1U << 14)
+#define SPM_DBG_DEBUG_IDX_SYSRAM_SLP (1U << 15)
+#define SPM_DBG_DEBUG_IDX_SYSRAM_ON (1U << 16)
+#define SPM_DBG_DEBUG_IDX_MCUPM_SRAM_SLP (1U << 17)
+#define SPM_DBG_DEBUG_IDX_MCUPM_SRAM_ON (1U << 18)
+#define SPM_DBG_DEBUG_IDX_SSPM_SRAM_SLP (1U << 19)
+#define SPM_DBG_DEBUG_IDX_SSPM_SRAM_ON (1U << 20)
+#define SPM_DBG_DEBUG_IDX_DRAMC_MCU_SRAM_SLP (1U << 21)
+#define SPM_DBG_DEBUG_IDX_DRAMC_MCU_SRAM_ON (1U << 22)
+#define SPM_DBG_DEBUG_IDX_SCP_VCORE_0P575V (1U << 23)
+#define SPM_DBG_DEBUG_IDX_SCP_VCORE_0P600V (1U << 24)
+#define SPM_DBG_DEBUG_IDX_SCP_VCORE_0P650V (1U << 25)
+#define SPM_DBG_DEBUG_IDX_SCP_VCORE_0P725V (1U << 26)
+#define SPM_DBG_DEBUG_IDX_SPM_GO_WAKEUP_NOW (1U << 27)
+#define SPM_DBG_DEBUG_IDX_VTCXO_STATE (1U << 28)
+#define SPM_DBG_DEBUG_IDX_INFRA_STATE (1U << 29)
+#define SPM_DBG_DEBUG_IDX_VRR18_STATE (1U << 30)
+#define SPM_DBG_DEBUG_IDX_APSRC_STATE (1U << 31)
+/* --- SPM DEBUG1 Define --- */
+#define SPM_DBG1_DEBUG_IDX_CURRENT_IS_LP (1U << 0)
+#define SPM_DBG1_DEBUG_IDX_VCORE_DVFS_START (1U << 1)
+#define SPM_DBG1_DEBUG_IDX_SYSPLL_OFF (1U << 2)
+#define SPM_DBG1_DEBUG_IDX_SYSPLL_ON (1U << 3)
+#define SPM_DBG1_DEBUG_IDX_CURRENT_IS_VCORE_DVFS (1U << 4)
+#define SPM_DBG1_DEBUG_IDX_INFRA_MTCMOS_OFF (1U << 5)
+#define SPM_DBG1_DEBUG_IDX_INFRA_MTCMOS_ON (1U << 6)
+#define SPM_DBG1_DEBUG_IDX_VRCXO_SLEEP_ABORT (1U << 7)
+#define SPM_DBG1_RESERVED_BIT8 (1U << 8)
+#define SPM_DBG1_DEBUG_IDX_INFRA_SUB_MTCMOS_OFF (1U << 9)
+#define SPM_DBG1_DEBUG_IDX_INFRA_SUB_MTCMOS_ON (1U << 10)
+#define SPM_DBG1_DEBUG_IDX_PWRAP_CLK_TO_ULPOSC (1U << 11)
+#define SPM_DBG1_DEBUG_IDX_PWRAP_CLK_TO_26M (1U << 12)
+#define SPM_DBG1_DEBUG_IDX_SCP_CLK_TO_32K (1U << 13)
+#define SPM_DBG1_DEBUG_IDX_SCP_CLK_TO_26M (1U << 14)
+#define SPM_DBG1_DEBUG_IDX_BUS_CLK_OFF (1U << 15)
+#define SPM_DBG1_DEBUG_IDX_BUS_CLK_ON (1U << 16)
+#define SPM_DBG1_DEBUG_IDX_SRCLKEN2_LOW (1U << 17)
+#define SPM_DBG1_DEBUG_IDX_SRCLKEN2_HIGH (1U << 18)
+#define SPM_DBG1_RESERVED_BIT19 (1U << 19)
+#define SPM_DBG1_DEBUG_IDX_ULPOSC_IS_OFF_BUT_SHOULD_ON (1U << 20)
+#define SPM_DBG1_DEBUG_IDX_6315_LOW (1U << 21)
+#define SPM_DBG1_DEBUG_IDX_6315_HIGH (1U << 22)
+#define SPM_DBG1_DEBUG_IDX_PWRAP_SLEEP_ACK_LOW_ABORT (1U << 23)
+#define SPM_DBG1_DEBUG_IDX_PWRAP_SLEEP_ACK_HIGH_ABORT (1U << 24)
+#define SPM_DBG1_DEBUG_IDX_EMI_SLP_IDLE_ABORT (1U << 25)
+#define SPM_DBG1_DEBUG_IDX_SCP_SLP_ACK_LOW_ABORT (1U << 26)
+#define SPM_DBG1_DEBUG_IDX_SCP_SLP_ACK_HIGH_ABORT (1U << 27)
+#define SPM_DBG1_DEBUG_IDX_SPM_DVFS_CMD_RDY_ABORT (1U << 28)
+#define SPM_DBG1_RESERVED_BIT29 (1U << 29)
+#define SPM_DBG1_RESERVED_BIT30 (1U << 30)
+#define SPM_DBG1_RESERVED_BIT31 (1U << 31)
+
+ /* Macro and Inline */
+#define is_cpu_pdn(flags) (((flags) & SPM_FLAG_DISABLE_CPU_PDN) == 0U)
+#define is_infra_pdn(flags) (((flags) & SPM_FLAG_DISABLE_INFRA_PDN) == 0U)
+#define is_ddrphy_pdn(flags) (((flags) & SPM_FLAG_DISABLE_DDRPHY_PDN) == 0U)
+#endif /* SLEEP_DEF_H */
diff --git a/plat/mediatek/mt8195/drivers/spmc/mtspmc.c b/plat/mediatek/mt8195/drivers/spmc/mtspmc.c
new file mode 100644
index 0000000..9b332a0
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spmc/mtspmc.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <mcucfg.h>
+#include <mtspmc.h>
+#include <mtspmc_private.h>
+
+
+void mcucfg_disable_gic_wakeup(unsigned int cluster, unsigned int cpu)
+{
+ mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(cpu));
+}
+
+void mcucfg_enable_gic_wakeup(unsigned int cluster, unsigned int cpu)
+{
+ mmio_clrbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(cpu));
+}
+
+void mcucfg_set_bootaddr(unsigned int cluster, unsigned int cpu, uintptr_t bootaddr)
+{
+ assert(cluster == 0U);
+
+ mmio_write_32(per_cpu(cluster, cpu, MCUCFG_BOOTADDR), bootaddr);
+}
+
+uintptr_t mcucfg_get_bootaddr(unsigned int cluster, unsigned int cpu)
+{
+ assert(cluster == 0U);
+
+ return (uintptr_t)mmio_read_32(per_cpu(cluster, cpu, MCUCFG_BOOTADDR));
+}
+
+void mcucfg_init_archstate(unsigned int cluster, unsigned int cpu, bool arm64)
+{
+ uint32_t reg;
+
+ assert(cluster == 0U);
+
+ reg = per_cluster(cluster, MCUCFG_INITARCH);
+
+ if (arm64) {
+ mmio_setbits_32(reg, MCUCFG_INITARCH_CPU_BIT(cpu));
+ } else {
+ mmio_clrbits_32(reg, MCUCFG_INITARCH_CPU_BIT(cpu));
+ }
+}
+
+/**
+ * Return subsystem's power state.
+ *
+ * @mask: mask to MCUCFG_CPC_SPMC_PWR_STATUS to query the power state
+ * of one subsystem.
+ * RETURNS:
+ * 0 (the subsys was powered off)
+ * 1 (the subsys was powered on)
+ */
+bool spm_get_powerstate(uint32_t mask)
+{
+ return (mmio_read_32(MCUCFG_CPC_SPMC_PWR_STATUS) & mask) != 0U;
+}
+
+bool spm_get_cluster_powerstate(unsigned int cluster)
+{
+ assert(cluster == 0U);
+
+ return spm_get_powerstate(BIT(14));
+}
+
+bool spm_get_cpu_powerstate(unsigned int cluster, unsigned int cpu)
+{
+ uint32_t mask = BIT(cpu);
+
+ assert(cluster == 0U);
+
+ return spm_get_powerstate(mask);
+}
+
+int spmc_init(void)
+{
+ INFO("SPM: enable CPC mode\n");
+
+ mmio_write_32(SPM_POWERON_CONFIG_EN, PROJECT_CODE | BCLK_CG_EN);
+
+ mmio_setbits_32(per_cpu(0, 1, SPM_CPU_PWR), PWR_RST_B);
+ mmio_setbits_32(per_cpu(0, 2, SPM_CPU_PWR), PWR_RST_B);
+ mmio_setbits_32(per_cpu(0, 3, SPM_CPU_PWR), PWR_RST_B);
+ mmio_setbits_32(per_cpu(0, 4, SPM_CPU_PWR), PWR_RST_B);
+ mmio_setbits_32(per_cpu(0, 5, SPM_CPU_PWR), PWR_RST_B);
+ mmio_setbits_32(per_cpu(0, 6, SPM_CPU_PWR), PWR_RST_B);
+ mmio_setbits_32(per_cpu(0, 7, SPM_CPU_PWR), PWR_RST_B);
+
+ mmio_clrbits_32(SPM_MCUSYS_PWR_CON, RESETPWRON_CONFIG);
+ mmio_clrbits_32(SPM_MP0_CPUTOP_PWR_CON, RESETPWRON_CONFIG);
+ mmio_clrbits_32(per_cpu(0, 0, SPM_CPU_PWR), RESETPWRON_CONFIG);
+
+ mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, CPC_CTRL_ENABLE);
+ mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, SSPM_CORE_PWR_ON_EN);
+
+ 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(unsigned int cluster, unsigned int cpu)
+{
+ uintptr_t cpu_pwr_con = per_cpu(cluster, cpu, SPM_CPU_PWR);
+
+ /* set to 0 after BIG VPROC bulk on & before B-core power on seq. */
+ if (cpu >= 4U) {
+ mmio_write_32(DREQ20_BIG_VPROC_ISO, 0U);
+ }
+
+ mmio_setbits_32(cpu_pwr_con, PWR_ON);
+
+ while (!spm_get_cpu_powerstate(cluster, cpu)) {
+ mmio_clrbits_32(cpu_pwr_con, PWR_ON);
+ mmio_setbits_32(cpu_pwr_con, PWR_ON);
+ }
+}
+
+/**
+ * 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(unsigned int cluster, unsigned int cpu)
+{
+ /* Set mp0_spmc_pwr_on_cpuX = 0 */
+ mmio_clrbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWR_ON);
+}
+
+/**
+ * Power off a cluster with specified index
+ *
+ * @cluster: the cluster index which to be powered off
+ */
+void spm_poweroff_cluster(unsigned int cluster)
+{
+ /* No need to power on/off cluster on single cluster platform */
+ assert(false);
+}
+
+/**
+ * Power on a cluster with specified index
+ *
+ * @cluster: the cluster index which to be powered on
+ */
+void spm_poweron_cluster(unsigned int cluster)
+{
+ /* No need to power on/off cluster on single cluster platform */
+ assert(false);
+}
diff --git a/plat/mediatek/mt8195/drivers/spmc/mtspmc.h b/plat/mediatek/mt8195/drivers/spmc/mtspmc.h
new file mode 100644
index 0000000..34e93d0
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spmc/mtspmc.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTSPMC_H
+#define MTSPMC_H
+
+#include <stdint.h>
+
+int spmc_init(void);
+
+void spm_poweron_cpu(unsigned int cluster, unsigned int cpu);
+void spm_poweroff_cpu(unsigned int cluster, unsigned int cpu);
+
+void spm_poweroff_cluster(unsigned int cluster);
+void spm_poweron_cluster(unsigned int cluster);
+
+bool spm_get_cpu_powerstate(unsigned int cluster, unsigned int cpu);
+bool spm_get_cluster_powerstate(unsigned int cluster);
+bool spm_get_powerstate(uint32_t mask);
+
+void mcucfg_init_archstate(unsigned int cluster, unsigned int cpu, bool arm64);
+void mcucfg_set_bootaddr(unsigned int cluster, unsigned int cpu, uintptr_t bootaddr);
+uintptr_t mcucfg_get_bootaddr(unsigned int cluster, unsigned int cpu);
+
+void mcucfg_disable_gic_wakeup(unsigned int cluster, unsigned int cpu);
+void mcucfg_enable_gic_wakeup(unsigned int cluster, unsigned int cpu);
+
+#endif /* MTSPMC_H */
diff --git a/plat/mediatek/mt8195/drivers/spmc/mtspmc_private.h b/plat/mediatek/mt8195/drivers/spmc/mtspmc_private.h
new file mode 100644
index 0000000..bf4092e
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/spmc/mtspmc_private.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTSPMC_PRIVATE_H
+#define MTSPMC_PRIVATE_H
+
+#include <lib/utils_def.h>
+#include <platform_def.h>
+
+unsigned long read_cpuectlr(void);
+void write_cpuectlr(unsigned long cpuectlr);
+
+unsigned long read_cpupwrctlr_el1(void);
+void write_cpupwrctlr_el1(unsigned long cpuectlr);
+
+/*
+ * per_cpu/cluster helper
+ */
+struct per_cpu_reg {
+ unsigned int cluster_addr;
+ unsigned 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)
+
+#define SPM_REG(ofs) (uint32_t)(SPM_BASE + (ofs))
+#define MCUCFG_REG(ofs) (uint32_t)(MCUCFG_BASE + (ofs))
+#define INFRACFG_AO_REG(ofs) (uint32_t)(INFRACFG_AO_BASE + (ofs))
+
+/* === SPMC related registers */
+#define SPM_POWERON_CONFIG_EN SPM_REG(0x000)
+/* bit-fields of SPM_POWERON_CONFIG_EN */
+#define PROJECT_CODE (U(0xb16) << 16)
+#define BCLK_CG_EN BIT(0)
+
+#define SPM_PWR_STATUS SPM_REG(0x16c)
+#define SPM_PWR_STATUS_2ND SPM_REG(0x170)
+#define SPM_CPU_PWR_STATUS SPM_REG(0x174)
+
+/* bit-fields of SPM_PWR_STATUS */
+#define MD BIT(0)
+#define CONN BIT(1)
+#define DDRPHY BIT(2)
+#define DISP BIT(3)
+#define MFG BIT(4)
+#define ISP BIT(5)
+#define INFRA BIT(6)
+#define VDEC BIT(7)
+#define MP0_CPUTOP BIT(8)
+#define MP0_CPU0 BIT(9)
+#define MP0_CPU1 BIT(10)
+#define MP0_CPU2 BIT(11)
+#define MP0_CPU3 BIT(12)
+#define MCUSYS BIT(14)
+#define MP0_CPU4 BIT(15)
+#define MP0_CPU5 BIT(16)
+#define MP0_CPU6 BIT(17)
+#define MP0_CPU7 BIT(18)
+#define VEN BIT(21)
+
+/* === SPMC related registers */
+#define SPM_MCUSYS_PWR_CON MCUCFG_REG(0xd200)
+#define SPM_MP0_CPUTOP_PWR_CON MCUCFG_REG(0xd204)
+#define SPM_MP0_CPU0_PWR_CON MCUCFG_REG(0xd208)
+#define SPM_MP0_CPU1_PWR_CON MCUCFG_REG(0xd20c)
+#define SPM_MP0_CPU2_PWR_CON MCUCFG_REG(0xd210)
+#define SPM_MP0_CPU3_PWR_CON MCUCFG_REG(0xd214)
+#define SPM_MP0_CPU4_PWR_CON MCUCFG_REG(0xd218)
+#define SPM_MP0_CPU5_PWR_CON MCUCFG_REG(0xd21c)
+#define SPM_MP0_CPU6_PWR_CON MCUCFG_REG(0xd220)
+#define SPM_MP0_CPU7_PWR_CON MCUCFG_REG(0xd224)
+
+/* bit fields of SPM_*_PWR_CON */
+#define PWR_ON_ACK BIT(31)
+#define VPROC_EXT_OFF BIT(7)
+#define DORMANT_EN BIT(6)
+#define RESETPWRON_CONFIG BIT(5)
+#define PWR_CLK_DIS BIT(4)
+#define PWR_ON BIT(2)
+#define PWR_RST_B BIT(0)
+
+/**** per_cpu registers for SPM_MP0_CPU?_PWR_CON */
+static const struct per_cpu_reg SPM_CPU_PWR[] = {
+ { .cluster_addr = SPM_MP0_CPU0_PWR_CON, .cpu_stride = 2U }
+};
+
+/**** per_cluster registers for SPM_MP0_CPUTOP_PWR_CON */
+static const struct per_cpu_reg SPM_CLUSTER_PWR[] = {
+ { .cluster_addr = SPM_MP0_CPUTOP_PWR_CON, .cpu_stride = 0U }
+};
+
+/* === MCUCFG related registers */
+/* aa64naa32 */
+#define MCUCFG_MP0_CLUSTER_CFG5 MCUCFG_REG(0xc8e4)
+/* reset vectors */
+#define MCUCFG_MP0_CLUSTER_CFG8 MCUCFG_REG(0xc900)
+#define MCUCFG_MP0_CLUSTER_CFG10 MCUCFG_REG(0xc908)
+#define MCUCFG_MP0_CLUSTER_CFG12 MCUCFG_REG(0xc910)
+#define MCUCFG_MP0_CLUSTER_CFG14 MCUCFG_REG(0xc918)
+#define MCUCFG_MP0_CLUSTER_CFG16 MCUCFG_REG(0xc920)
+#define MCUCFG_MP0_CLUSTER_CFG18 MCUCFG_REG(0xc928)
+#define MCUCFG_MP0_CLUSTER_CFG20 MCUCFG_REG(0xc930)
+#define MCUCFG_MP0_CLUSTER_CFG22 MCUCFG_REG(0xc938)
+
+/* MCUSYS DREQ BIG VPROC ISO control */
+#define DREQ20_BIG_VPROC_ISO MCUCFG_REG(0xad8c)
+
+/**** per_cpu registers for MCUCFG_MP0_CLUSTER_CFG? */
+static const struct per_cpu_reg MCUCFG_BOOTADDR[] = {
+ { .cluster_addr = MCUCFG_MP0_CLUSTER_CFG8, .cpu_stride = 3U }
+};
+
+/**** per_cpu registers for MCUCFG_MP0_CLUSTER_CFG5 */
+static const struct per_cpu_reg MCUCFG_INITARCH[] = {
+ { .cluster_addr = MCUCFG_MP0_CLUSTER_CFG5, .cpu_stride = 0U }
+};
+
+#define MCUCFG_INITARCH_CPU_BIT(cpu) BIT(16U + cpu)
+/* === CPC control */
+#define MCUCFG_CPC_FLOW_CTRL_CFG MCUCFG_REG(0xa814)
+#define MCUCFG_CPC_SPMC_PWR_STATUS MCUCFG_REG(0xa840)
+
+/* bit fields of CPC_FLOW_CTRL_CFG */
+#define CPC_CTRL_ENABLE BIT(16)
+#define SSPM_CORE_PWR_ON_EN BIT(7) /* for cpu-hotplug */
+#define SSPM_ALL_PWR_CTRL_EN BIT(13) /* for cpu-hotplug */
+#define GIC_WAKEUP_IGNORE(cpu) BIT(21 + cpu)
+
+/* bit fields of CPC_SPMC_PWR_STATUS */
+#define CORE_SPMC_PWR_ON_ACK GENMASK(11, 0)
+
+/* === APB Module infracfg_ao */
+#define INFRA_TOPAXI_PROTECTEN INFRACFG_AO_REG(0x0220)
+#define INFRA_TOPAXI_PROTECTEN_STA0 INFRACFG_AO_REG(0x0224)
+#define INFRA_TOPAXI_PROTECTEN_STA1 INFRACFG_AO_REG(0x0228)
+#define INFRA_TOPAXI_PROTECTEN_SET INFRACFG_AO_REG(0x02a0)
+#define INFRA_TOPAXI_PROTECTEN_CLR INFRACFG_AO_REG(0x02a4)
+#define INFRA_TOPAXI_PROTECTEN_1 INFRACFG_AO_REG(0x0250)
+#define INFRA_TOPAXI_PROTECTEN_STA0_1 INFRACFG_AO_REG(0x0254)
+#define INFRA_TOPAXI_PROTECTEN_STA1_1 INFRACFG_AO_REG(0x0258)
+#define INFRA_TOPAXI_PROTECTEN_1_SET INFRACFG_AO_REG(0x02a8)
+#define INFRA_TOPAXI_PROTECTEN_1_CLR INFRACFG_AO_REG(0x02ac)
+
+/* bit fields of INFRA_TOPAXI_PROTECTEN */
+#define MP0_SPMC_PROT_STEP1_0_MASK BIT(12)
+#define MP0_SPMC_PROT_STEP1_1_MASK (BIT(26) | BIT(12))
+
+/* === SPARK */
+#define VOLTAGE_04 U(0x40)
+#define VOLTAGE_05 U(0x60)
+
+#define PTP3_CPU0_SPMC_SW_CFG MCUCFG_REG(0x200)
+#define CPU0_ILDO_CONTROL5 MCUCFG_REG(0x334)
+#define CPU0_ILDO_CONTROL8 MCUCFG_REG(0x340)
+
+/* bit fields of CPU0_ILDO_CONTROL5 */
+#define ILDO_RET_VOSEL GENMASK(7, 0)
+
+/* bit fields of PTP3_CPU_SPMC_SW_CFG */
+#define SW_SPARK_EN BIT(0)
+
+/* bit fields of CPU0_ILDO_CONTROL8 */
+#define ILDO_BYPASS_B BIT(0)
+
+static const struct per_cpu_reg MCUCFG_SPARK[] = {
+ { .cluster_addr = PTP3_CPU0_SPMC_SW_CFG, .cpu_stride = 11U }
+};
+
+static const struct per_cpu_reg ILDO_CONTROL5[] = {
+ { .cluster_addr = CPU0_ILDO_CONTROL5, .cpu_stride = 11U }
+};
+
+static const struct per_cpu_reg ILDO_CONTROL8[] = {
+ { .cluster_addr = CPU0_ILDO_CONTROL8, .cpu_stride = 11U }
+};
+
+#endif /* MTSPMC_PRIVATE_H */
diff --git a/plat/mediatek/mt8195/include/mcucfg.h b/plat/mediatek/mt8195/include/mcucfg.h
new file mode 100644
index 0000000..046cf73
--- /dev/null
+++ b/plat/mediatek/mt8195/include/mcucfg.h
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MCUCFG_H
+#define MCUCFG_H
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+#endif /* __ASSEMBLER__ */
+
+#include <platform_def.h>
+
+#define MCUCFG_REG(ofs) (uint32_t)(MCUCFG_BASE + (ofs))
+
+#define MP2_MISC_CONFIG_BOOT_ADDR_L(cpu) (MCUCFG_REG(0x2290) + ((cpu) * 8))
+#define MP2_MISC_CONFIG_BOOT_ADDR_H(cpu) (MCUCFG_REG(0x2294) + ((cpu) * 8))
+
+#define MP2_CPUCFG MCUCFG_REG(0x2208)
+
+#define MP2_CPU0_STANDBYWFE BIT(4)
+#define MP2_CPU1_STANDBYWFE BIT(5)
+
+#define MP0_CPUTOP_SPMC_CTL MCUCFG_REG(0x788)
+#define MP1_CPUTOP_SPMC_CTL MCUCFG_REG(0x78C)
+#define MP1_CPUTOP_SPMC_SRAM_CTL MCUCFG_REG(0x790)
+
+#define sw_spark_en BIT(0)
+#define sw_no_wait_for_q_channel BIT(1)
+#define sw_fsm_override BIT(2)
+#define sw_logic_pre1_pdb BIT(3)
+#define sw_logic_pre2_pdb BIT(4)
+#define sw_logic_pdb BIT(5)
+#define sw_iso BIT(6)
+#define sw_sram_sleepb (U(0x3F) << 7)
+#define sw_sram_isointb BIT(13)
+#define sw_clk_dis BIT(14)
+#define sw_ckiso BIT(15)
+#define sw_pd (U(0x3F) << 16)
+#define sw_hot_plug_reset BIT(22)
+#define sw_pwr_on_override_en BIT(23)
+#define sw_pwr_on BIT(24)
+#define sw_coq_dis BIT(25)
+#define logic_pdbo_all_off_ack BIT(26)
+#define logic_pdbo_all_on_ack BIT(27)
+#define logic_pre2_pdbo_all_on_ack BIT(28)
+#define logic_pre1_pdbo_all_on_ack BIT(29)
+
+
+#define CPUSYSx_CPUx_SPMC_CTL(cluster, cpu) \
+ (MCUCFG_REG(0x1c30) + cluster * 0x2000 + cpu * 4)
+
+#define CPUSYS0_CPU0_SPMC_CTL MCUCFG_REG(0x1c30)
+#define CPUSYS0_CPU1_SPMC_CTL MCUCFG_REG(0x1c34)
+#define CPUSYS0_CPU2_SPMC_CTL MCUCFG_REG(0x1c38)
+#define CPUSYS0_CPU3_SPMC_CTL MCUCFG_REG(0x1c3C)
+
+#define CPUSYS1_CPU0_SPMC_CTL MCUCFG_REG(0x3c30)
+#define CPUSYS1_CPU1_SPMC_CTL MCUCFG_REG(0x3c34)
+#define CPUSYS1_CPU2_SPMC_CTL MCUCFG_REG(0x3c38)
+#define CPUSYS1_CPU3_SPMC_CTL MCUCFG_REG(0x3c3C)
+
+#define cpu_sw_spark_en BIT(0)
+#define cpu_sw_no_wait_for_q_channel BIT(1)
+#define cpu_sw_fsm_override BIT(2)
+#define cpu_sw_logic_pre1_pdb BIT(3)
+#define cpu_sw_logic_pre2_pdb BIT(4)
+#define cpu_sw_logic_pdb BIT(5)
+#define cpu_sw_iso BIT(6)
+#define cpu_sw_sram_sleepb BIT(7)
+#define cpu_sw_sram_isointb BIT(8)
+#define cpu_sw_clk_dis BIT(9)
+#define cpu_sw_ckiso BIT(10)
+#define cpu_sw_pd (U(0x1F) << 11)
+#define cpu_sw_hot_plug_reset BIT(16)
+#define cpu_sw_powr_on_override_en BIT(17)
+#define cpu_sw_pwr_on BIT(18)
+#define cpu_spark2ldo_allswoff BIT(19)
+#define cpu_pdbo_all_on_ack BIT(20)
+#define cpu_pre2_pdbo_allon_ack BIT(21)
+#define cpu_pre1_pdbo_allon_ack BIT(22)
+
+/* CPC related registers */
+#define CPC_MCUSYS_CPC_OFF_THRES MCUCFG_REG(0xa714)
+#define CPC_MCUSYS_PWR_CTRL MCUCFG_REG(0xa804)
+#define CPC_MCUSYS_CPC_FLOW_CTRL_CFG MCUCFG_REG(0xa814)
+#define CPC_MCUSYS_LAST_CORE_REQ MCUCFG_REG(0xa818)
+#define CPC_MCUSYS_MP_LAST_CORE_RESP MCUCFG_REG(0xa81c)
+#define CPC_MCUSYS_LAST_CORE_RESP MCUCFG_REG(0xa824)
+#define CPC_MCUSYS_PWR_ON_MASK MCUCFG_REG(0xa828)
+#define CPC_MCUSYS_CPU_ON_SW_HINT_SET MCUCFG_REG(0xa8a8)
+#define CPC_MCUSYS_CPU_ON_SW_HINT_CLR MCUCFG_REG(0xa8ac)
+#define CPC_MCUSYS_CPC_DBG_SETTING MCUCFG_REG(0xab00)
+#define CPC_MCUSYS_CPC_KERNEL_TIME_L_BASE MCUCFG_REG(0xab04)
+#define CPC_MCUSYS_CPC_KERNEL_TIME_H_BASE MCUCFG_REG(0xab08)
+#define CPC_MCUSYS_CPC_SYSTEM_TIME_L_BASE MCUCFG_REG(0xab0c)
+#define CPC_MCUSYS_CPC_SYSTEM_TIME_H_BASE MCUCFG_REG(0xab10)
+#define CPC_MCUSYS_TRACE_SEL MCUCFG_REG(0xab14)
+#define CPC_MCUSYS_TRACE_DATA MCUCFG_REG(0xab20)
+#define CPC_MCUSYS_CLUSTER_COUNTER MCUCFG_REG(0xab70)
+#define CPC_MCUSYS_CLUSTER_COUNTER_CLR MCUCFG_REG(0xab74)
+
+#define SPARK2LDO MCUCFG_REG(0x2700)
+/* APB Module mcucfg */
+#define MP0_CA7_CACHE_CONFIG MCUCFG_REG(0x000)
+#define MP0_AXI_CONFIG MCUCFG_REG(0x02C)
+#define MP0_MISC_CONFIG0 MCUCFG_REG(0x030)
+#define MP0_MISC_CONFIG1 MCUCFG_REG(0x034)
+#define MP0_MISC_CONFIG2 MCUCFG_REG(0x038)
+#define MP0_MISC_CONFIG_BOOT_ADDR(cpu) (MP0_MISC_CONFIG2 + ((cpu) * 8))
+#define MP0_MISC_CONFIG3 MCUCFG_REG(0x03C)
+#define MP0_MISC_CONFIG9 MCUCFG_REG(0x054)
+#define MP0_CA7_MISC_CONFIG MCUCFG_REG(0x064)
+
+#define MP0_RW_RSVD0 MCUCFG_REG(0x06C)
+
+
+#define MP1_CA7_CACHE_CONFIG MCUCFG_REG(0x200)
+#define MP1_AXI_CONFIG MCUCFG_REG(0x22C)
+#define MP1_MISC_CONFIG0 MCUCFG_REG(0x230)
+#define MP1_MISC_CONFIG1 MCUCFG_REG(0x234)
+#define MP1_MISC_CONFIG2 MCUCFG_REG(0x238)
+#define MP1_MISC_CONFIG_BOOT_ADDR(cpu) (MP1_MISC_CONFIG2 + ((cpu) * 8))
+#define MP1_MISC_CONFIG3 MCUCFG_REG(0x23C)
+#define MP1_MISC_CONFIG9 MCUCFG_REG(0x254)
+#define MP1_CA7_MISC_CONFIG MCUCFG_REG(0x264)
+
+#define CCI_ADB400_DCM_CONFIG MCUCFG_REG(0x740)
+#define SYNC_DCM_CONFIG MCUCFG_REG(0x744)
+
+#define MP0_CLUSTER_CFG0 MCUCFG_REG(0xC8D0)
+
+#define MP0_SPMC MCUCFG_REG(0x788)
+#define MP1_SPMC MCUCFG_REG(0x78C)
+#define MP2_AXI_CONFIG MCUCFG_REG(0x220C)
+#define MP2_AXI_CONFIG_ACINACTM BIT(0)
+#define MP2_AXI_CONFIG_AINACTS BIT(4)
+
+#define MPx_AXI_CONFIG_ACINACTM BIT(4)
+#define MPx_AXI_CONFIG_AINACTS BIT(5)
+
+#define MPx_CA7_MISC_CONFIG_standbywfil2 BIT(28)
+
+#define MP0_CPU0_STANDBYWFE BIT(20)
+#define MP0_CPU1_STANDBYWFE BIT(21)
+#define MP0_CPU2_STANDBYWFE BIT(22)
+#define MP0_CPU3_STANDBYWFE BIT(23)
+
+#define MP1_CPU0_STANDBYWFE BIT(20)
+#define MP1_CPU1_STANDBYWFE BIT(21)
+#define MP1_CPU2_STANDBYWFE BIT(22)
+#define MP1_CPU3_STANDBYWFE BIT(23)
+
+#define CPUSYS0_SPARKVRETCNTRL MCUCFG_REG(0x1c00)
+#define CPUSYS0_SPARKEN MCUCFG_REG(0x1c04)
+#define CPUSYS0_AMUXSEL MCUCFG_REG(0x1c08)
+#define CPUSYS1_SPARKVRETCNTRL MCUCFG_REG(0x3c00)
+#define CPUSYS1_SPARKEN MCUCFG_REG(0x3c04)
+#define CPUSYS1_AMUXSEL MCUCFG_REG(0x3c08)
+
+#define MP2_PWR_RST_CTL MCUCFG_REG(0x2008)
+#define MP2_PTP3_CPUTOP_SPMC0 MCUCFG_REG(0x22A0)
+#define MP2_PTP3_CPUTOP_SPMC1 MCUCFG_REG(0x22A4)
+
+#define MP2_COQ MCUCFG_REG(0x22BC)
+#define MP2_COQ_SW_DIS BIT(0)
+
+#define MP2_CA15M_MON_SEL MCUCFG_REG(0x2400)
+#define MP2_CA15M_MON_L MCUCFG_REG(0x2404)
+
+#define CPUSYS2_CPU0_SPMC_CTL MCUCFG_REG(0x2430)
+#define CPUSYS2_CPU1_SPMC_CTL MCUCFG_REG(0x2438)
+#define CPUSYS2_CPU0_SPMC_STA MCUCFG_REG(0x2434)
+#define CPUSYS2_CPU1_SPMC_STA MCUCFG_REG(0x243C)
+
+#define MP0_CA7L_DBG_PWR_CTRL MCUCFG_REG(0x068)
+#define MP1_CA7L_DBG_PWR_CTRL MCUCFG_REG(0x268)
+#define BIG_DBG_PWR_CTRL MCUCFG_REG(0x75C)
+
+#define MP2_SW_RST_B BIT(0)
+#define MP2_TOPAON_APB_MASK BIT(1)
+
+#define B_SW_HOT_PLUG_RESET BIT(30)
+
+#define B_SW_PD_OFFSET 18U
+#define B_SW_PD (U(0x3f) << B_SW_PD_OFFSET)
+
+#define B_SW_SRAM_SLEEPB_OFFSET 12U
+#define B_SW_SRAM_SLEEPB (U(0x3f) << B_SW_SRAM_SLEEPB_OFFSET)
+
+#define B_SW_SRAM_ISOINTB BIT(9)
+#define B_SW_ISO BIT(8)
+#define B_SW_LOGIC_PDB BIT(7)
+#define B_SW_LOGIC_PRE2_PDB BIT(6)
+#define B_SW_LOGIC_PRE1_PDB BIT(5)
+#define B_SW_FSM_OVERRIDE BIT(4)
+#define B_SW_PWR_ON BIT(3)
+#define B_SW_PWR_ON_OVERRIDE_EN BIT(2)
+
+#define B_FSM_STATE_OUT_OFFSET (6U)
+#define B_FSM_STATE_OUT_MASK (U(0x1f) << B_FSM_STATE_OUT_OFFSET)
+#define B_SW_LOGIC_PDBO_ALL_OFF_ACK BIT(5)
+#define B_SW_LOGIC_PDBO_ALL_ON_ACK BIT(4)
+#define B_SW_LOGIC_PRE2_PDBO_ALL_ON_ACK BIT(3)
+#define B_SW_LOGIC_PRE1_PDBO_ALL_ON_ACK BIT(2)
+
+#define B_FSM_OFF (0U << B_FSM_STATE_OUT_OFFSET)
+#define B_FSM_ON (1U << B_FSM_STATE_OUT_OFFSET)
+#define B_FSM_RET (2U << B_FSM_STATE_OUT_OFFSET)
+
+#ifndef __ASSEMBLER__
+/* cpu boot mode */
+enum {
+ MP0_CPUCFG_64BIT_SHIFT = 12U,
+ MP1_CPUCFG_64BIT_SHIFT = 28U,
+ MP0_CPUCFG_64BIT = U(0xf) << MP0_CPUCFG_64BIT_SHIFT,
+ MP1_CPUCFG_64BIT = U(0xf) << MP1_CPUCFG_64BIT_SHIFT
+};
+
+enum {
+ MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT = 0U,
+ MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT = 4U,
+ MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT = 8U,
+ MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT = 12U,
+ MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT = 16U,
+
+ MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK =
+ U(0xf) << MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT,
+ MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK =
+ U(0xf) << MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT,
+ MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK =
+ U(0xf) << MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT,
+ MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK =
+ U(0xf) << MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT,
+ MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK =
+ U(0xf) << MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT
+};
+
+enum {
+ MP1_AINACTS_SHIFT = 4U,
+ MP1_AINACTS = 1U << MP1_AINACTS_SHIFT
+};
+
+enum {
+ MP1_SW_CG_GEN_SHIFT = 12U,
+ MP1_SW_CG_GEN = 1U << MP1_SW_CG_GEN_SHIFT
+};
+
+enum {
+ MP1_L2RSTDISABLE_SHIFT = 14U,
+ MP1_L2RSTDISABLE = 1U << MP1_L2RSTDISABLE_SHIFT
+};
+#endif /* __ASSEMBLER__ */
+
+#endif /* MCUCFG_H */
diff --git a/plat/mediatek/mt8195/include/plat_helpers.h b/plat/mediatek/mt8195/include/plat_helpers.h
new file mode 100644
index 0000000..ebc9fa0
--- /dev/null
+++ b/plat/mediatek/mt8195/include/plat_helpers.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLAT_HELPERS_H__
+#define __PLAT_HELPERS_H__
+
+unsigned int plat_mediatek_calc_core_pos(u_register_t mpidr);
+
+#endif /* __PLAT_HELPERS_H__ */
diff --git a/plat/mediatek/mt8195/include/plat_macros.S b/plat/mediatek/mt8195/include/plat_macros.S
new file mode 100644
index 0000000..39727ea
--- /dev/null
+++ b/plat/mediatek/mt8195/include/plat_macros.S
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <platform_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"
+
+.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.
+ * Clobbers: x0 - x10, x26, x27, sp
+ * ---------------------------------------------
+ */
+ .macro plat_crash_print_regs
+ /* TODO: leave implementation to GIC owner */
+ .endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/mediatek/mt8195/include/plat_mtk_lpm.h b/plat/mediatek/mt8195/include/plat_mtk_lpm.h
new file mode 100644
index 0000000..347f358
--- /dev/null
+++ b/plat/mediatek/mt8195/include/plat_mtk_lpm.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MTK_LPM_H
+#define PLAT_MTK_LPM_H
+
+#include <lib/psci/psci.h>
+#include <lib/utils_def.h>
+
+#define MT_IRQ_REMAIN_MAX U(32)
+#define MT_IRQ_REMAIN_CAT_LOG BIT(31)
+
+struct mt_irqremain {
+ unsigned int count;
+ unsigned int irqs[MT_IRQ_REMAIN_MAX];
+ unsigned int wakeupsrc_cat[MT_IRQ_REMAIN_MAX];
+ unsigned int wakeupsrc[MT_IRQ_REMAIN_MAX];
+};
+
+#define PLAT_RC_STATUS_READY BIT(0)
+#define PLAT_RC_STATUS_FEATURE_EN BIT(1)
+#define PLAT_RC_STATUS_UART_NONSLEEP BIT(31)
+
+struct mt_lpm_tz {
+ int (*pwr_prompt)(unsigned int cpu, const psci_power_state_t *state);
+ int (*pwr_reflect)(unsigned int cpu, const psci_power_state_t *state);
+
+ int (*pwr_cpu_on)(unsigned int cpu, const psci_power_state_t *state);
+ int (*pwr_cpu_dwn)(unsigned int cpu, const psci_power_state_t *state);
+
+ int (*pwr_cluster_on)(unsigned int cpu,
+ const psci_power_state_t *state);
+ int (*pwr_cluster_dwn)(unsigned int cpu,
+ const psci_power_state_t *state);
+
+ int (*pwr_mcusys_on)(unsigned int cpu, const psci_power_state_t *state);
+ int (*pwr_mcusys_on_finished)(unsigned int cpu,
+ const psci_power_state_t *state);
+ int (*pwr_mcusys_dwn)(unsigned int cpu,
+ const psci_power_state_t *state);
+};
+
+const struct mt_lpm_tz *mt_plat_cpu_pm_init(void);
+
+#endif /* PLAT_MTK_LPM_H */
diff --git a/plat/mediatek/mt8195/include/plat_pm.h b/plat/mediatek/mt8195/include/plat_pm.h
new file mode 100644
index 0000000..a2881ce
--- /dev/null
+++ b/plat/mediatek/mt8195/include/plat_pm.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PM_H
+#define PLAT_PM_H
+
+#include <lib/utils_def.h>
+
+#define MT_PLAT_PWR_STATE_CPU U(1)
+#define MT_PLAT_PWR_STATE_CLUSTER U(2)
+#define MT_PLAT_PWR_STATE_MCUSYS U(3)
+#define MT_PLAT_PWR_STATE_SUSPEND2IDLE U(8)
+#define MT_PLAT_PWR_STATE_SYSTEM_SUSPEND U(9)
+
+#define MTK_LOCAL_STATE_RUN U(0)
+#define MTK_LOCAL_STATE_RET U(1)
+#define MTK_LOCAL_STATE_OFF U(2)
+
+#define MTK_AFFLVL_CPU U(0)
+#define MTK_AFFLVL_CLUSTER U(1)
+#define MTK_AFFLVL_MCUSYS U(2)
+#define MTK_AFFLVL_SYSTEM U(3)
+
+#define IS_CLUSTER_OFF_STATE(s) \
+ is_local_state_off(s->pwr_domain_state[MTK_AFFLVL_CLUSTER])
+#define IS_MCUSYS_OFF_STATE(s) \
+ is_local_state_off(s->pwr_domain_state[MTK_AFFLVL_MCUSYS])
+#define IS_SYSTEM_SUSPEND_STATE(s) \
+ is_local_state_off(s->pwr_domain_state[MTK_AFFLVL_SYSTEM])
+
+#define IS_PLAT_SUSPEND_ID(stateid)\
+ ((stateid == MT_PLAT_PWR_STATE_SUSPEND2IDLE) \
+ || (stateid == MT_PLAT_PWR_STATE_SYSTEM_SUSPEND))
+
+#endif /* PLAT_PM_H */
diff --git a/plat/mediatek/mt8195/include/plat_private.h b/plat/mediatek/mt8195/include/plat_private.h
new file mode 100644
index 0000000..7ef2b85
--- /dev/null
+++ b/plat/mediatek/mt8195/include/plat_private.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2021, 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);
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/mediatek/mt8195/include/plat_sip_calls.h b/plat/mediatek/mt8195/include/plat_sip_calls.h
new file mode 100644
index 0000000..7d1f9fc
--- /dev/null
+++ b/plat/mediatek/mt8195/include/plat_sip_calls.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. 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 (8)
+
+#endif /* PLAT_SIP_CALLS_H */
diff --git a/plat/mediatek/mt8195/include/platform_def.h b/plat/mediatek/mt8195/include/platform_def.h
new file mode 100644
index 0000000..2a2f559
--- /dev/null
+++ b/plat/mediatek/mt8195/include/platform_def.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#define PLAT_PRIMARY_CPU 0x0
+
+#define MT_GIC_BASE (0x0C000000)
+#define MCUCFG_BASE (0x0C530000)
+#define IO_PHYS (0x10000000)
+
+/* Aggregate of all devices for MMU mapping */
+#define MTK_DEV_RNG0_BASE IO_PHYS
+#define MTK_DEV_RNG0_SIZE 0x10000000
+#define MTK_DEV_RNG2_BASE MT_GIC_BASE
+#define MTK_DEV_RNG2_SIZE 0x600000
+#define MTK_MCDI_SRAM_BASE 0x11B000
+#define MTK_MCDI_SRAM_MAP_SIZE 0x1000
+
+#define APUSYS_BASE 0x19000000
+#define APUSYS_SCTRL_REVISER_BASE 0x19021000
+#define APUSYS_SCTRL_REVISER_SIZE 0x1000
+#define APUSYS_APU_S_S_4_BASE 0x190F2000
+#define APUSYS_APU_S_S_4_SIZE 0x1000
+#define APUSYS_APU_PLL_BASE 0x190F3000
+#define APUSYS_APU_PLL_SIZE 0x1000
+#define APUSYS_APU_ACC_BASE 0x190F4000
+#define APUSYS_APU_ACC_SIZE 0x1000
+
+#define TOPCKGEN_BASE (IO_PHYS + 0x00000000)
+#define INFRACFG_AO_BASE (IO_PHYS + 0x00001000)
+#define SPM_BASE (IO_PHYS + 0x00006000)
+#define RGU_BASE (IO_PHYS + 0x00007000)
+#define APMIXEDSYS (IO_PHYS + 0x0000C000)
+#define DRM_BASE (IO_PHYS + 0x0000D000)
+#define SSPM_MBOX_BASE (IO_PHYS + 0x00480000)
+#define PERICFG_AO_BASE (IO_PHYS + 0x01003000)
+#define VPPSYS0_BASE (IO_PHYS + 0x04000000)
+#define VPPSYS1_BASE (IO_PHYS + 0x04f00000)
+#define VDOSYS0_BASE (IO_PHYS + 0x0C01A000)
+#define VDOSYS1_BASE (IO_PHYS + 0x0C100000)
+#define DVFSRC_BASE (IO_PHYS + 0x00012000)
+
+/*******************************************************************************
+ * DP/eDP related constants
+ ******************************************************************************/
+#define EDP_SEC_BASE (IO_PHYS + 0x0C504000)
+#define DP_SEC_BASE (IO_PHYS + 0x0C604000)
+#define EDP_SEC_SIZE 0x1000
+#define DP_SEC_SIZE 0x1000
+
+/*******************************************************************************
+ * GPIO related constants
+ ******************************************************************************/
+#define GPIO_BASE (IO_PHYS + 0x00005000)
+#define IOCFG_BM_BASE (IO_PHYS + 0x01D10000)
+#define IOCFG_BL_BASE (IO_PHYS + 0x01D30000)
+#define IOCFG_BR_BASE (IO_PHYS + 0x01D40000)
+#define IOCFG_LM_BASE (IO_PHYS + 0x01E20000)
+#define IOCFG_RB_BASE (IO_PHYS + 0x01EB0000)
+#define IOCFG_TL_BASE (IO_PHYS + 0x01F40000)
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define UART0_BASE (IO_PHYS + 0x01001100)
+#define UART1_BASE (IO_PHYS + 0x01001200)
+
+#define UART_BAUDRATE 115200
+
+/*******************************************************************************
+ * PMIC related constants
+ ******************************************************************************/
+#define PMIC_WRAP_BASE (IO_PHYS + 0x00024000)
+
+/*******************************************************************************
+ * EMI MPU related constants
+ ******************************************************************************/
+#define EMI_MPU_BASE (IO_PHYS + 0x00226000)
+#define SUB_EMI_MPU_BASE (IO_PHYS + 0x00225000)
+
+/*******************************************************************************
+ * System counter frequency related constants
+ ******************************************************************************/
+#define SYS_COUNTER_FREQ_IN_TICKS 13000000
+#define SYS_COUNTER_FREQ_IN_MHZ 13
+
+/*******************************************************************************
+ * GIC-600 & interrupt handling related constants
+ ******************************************************************************/
+/* Base MTK_platform compatible GIC memory map */
+#define BASE_GICD_BASE MT_GIC_BASE
+#define MT_GIC_RDIST_BASE (MT_GIC_BASE + 0x40000)
+
+#define SYS_CIRQ_BASE (IO_PHYS + 0x204000)
+#define CIRQ_REG_NUM 23
+#define CIRQ_IRQ_NUM 730
+#define CIRQ_SPI_START 96
+#define MD_WDT_IRQ_BIT_ID 141
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH aarch64
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+#define PLATFORM_STACK_SIZE 0x800
+
+#define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n"
+
+#define PLAT_MAX_PWR_LVL U(3)
+#define PLAT_MAX_RET_STATE U(1)
+#define PLAT_MAX_OFF_STATE U(9)
+
+#define PLATFORM_SYSTEM_COUNT U(1)
+#define PLATFORM_MCUSYS_COUNT U(1)
+#define PLATFORM_CLUSTER_COUNT U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT U(8)
+#define PLATFORM_CLUSTER1_CORE_COUNT U(0)
+
+#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER U(8)
+
+#define SOC_CHIP_ID U(0x8195)
+
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+#define TZRAM_BASE 0x54600000
+#define TZRAM_SIZE 0x00030000
+
+/*******************************************************************************
+ * 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)
+
+/*******************************************************************************
+ * 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 */
diff --git a/plat/mediatek/mt8195/include/rtc.h b/plat/mediatek/mt8195/include/rtc.h
new file mode 100644
index 0000000..a9c7bc8
--- /dev/null
+++ b/plat/mediatek/mt8195/include/rtc.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RTC_H
+#define RTC_H
+
+#include <rtc_mt6359p.h>
+
+#endif /* RTC_H */
diff --git a/plat/mediatek/mt8195/plat_pm.c b/plat/mediatek/mt8195/plat_pm.c
new file mode 100644
index 0000000..bd8a3fa
--- /dev/null
+++ b/plat/mediatek/mt8195/plat_pm.c
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 2021-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* common headers */
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/gpio.h>
+#include <lib/psci/psci.h>
+
+/* platform specific headers */
+#include <plat/common/platform.h>
+#include <mt_gic_v3.h>
+#include <mtspmc.h>
+#include <plat_dfd.h>
+#include <plat_mtk_lpm.h>
+#include <plat_params.h>
+#include <plat_pm.h>
+#include <pmic.h>
+#include <ptp3_common.h>
+#include <rtc.h>
+
+/*
+ * Cluster state request:
+ * [0] : The CPU requires cluster power down
+ * [1] : The CPU requires cluster power on
+ */
+#define coordinate_cluster(onoff) write_clusterpwrdn_el1(onoff)
+#define coordinate_cluster_pwron() coordinate_cluster(1)
+#define coordinate_cluster_pwroff() coordinate_cluster(0)
+
+/* platform secure entry point */
+static uintptr_t secure_entrypoint;
+/* per-CPU power state */
+static unsigned int plat_power_state[PLATFORM_CORE_COUNT];
+
+/* platform CPU power domain - ops */
+static const struct mt_lpm_tz *plat_mt_pm;
+
+#define plat_mt_pm_invoke(_name, _cpu, _state) ({ \
+ int ret = -1; \
+ if (plat_mt_pm != NULL && plat_mt_pm->_name != NULL) { \
+ ret = plat_mt_pm->_name(_cpu, _state); \
+ } \
+ ret; })
+
+#define plat_mt_pm_invoke_no_check(_name, _cpu, _state) ({ \
+ if (plat_mt_pm != NULL && plat_mt_pm->_name != NULL) { \
+ (void) plat_mt_pm->_name(_cpu, _state); \
+ } \
+ })
+
+/*
+ * Common MTK_platform operations to power on/off a
+ * CPU in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
+ */
+
+static void plat_cpu_pwrdwn_common(unsigned int cpu,
+ const psci_power_state_t *state, unsigned int req_pstate)
+{
+ assert(cpu == plat_my_core_pos());
+
+ plat_mt_pm_invoke_no_check(pwr_cpu_dwn, cpu, state);
+
+ if ((psci_get_pstate_pwrlvl(req_pstate) >= MTK_AFFLVL_CLUSTER) ||
+ (req_pstate == 0U)) { /* hotplug off */
+ coordinate_cluster_pwroff();
+ }
+
+ /* Prevent interrupts from spuriously waking up this CPU */
+ mt_gic_rdistif_save();
+ gicv3_cpuif_disable(cpu);
+ gicv3_rdistif_off(cpu);
+}
+
+static void plat_cpu_pwron_common(unsigned int cpu,
+ const psci_power_state_t *state, unsigned int req_pstate)
+{
+ assert(cpu == plat_my_core_pos());
+
+ plat_mt_pm_invoke_no_check(pwr_cpu_on, cpu, state);
+
+ coordinate_cluster_pwron();
+
+ /* PTP3 config */
+ ptp3_core_init(cpu);
+
+ /*
+ * If mcusys does power down before then restore
+ * all CPUs' GIC Redistributors
+ */
+ if (IS_MCUSYS_OFF_STATE(state)) {
+ mt_gic_rdistif_restore_all();
+ } else {
+ gicv3_rdistif_on(cpu);
+ gicv3_cpuif_enable(cpu);
+ mt_gic_rdistif_init();
+ mt_gic_rdistif_restore();
+ }
+}
+
+/*
+ * Common MTK_platform operations to power on/off a
+ * cluster in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
+ */
+
+static void plat_cluster_pwrdwn_common(unsigned int cpu,
+ const psci_power_state_t *state, unsigned int req_pstate)
+{
+ assert(cpu == plat_my_core_pos());
+
+ if (plat_mt_pm_invoke(pwr_cluster_dwn, cpu, state) != 0) {
+ coordinate_cluster_pwron();
+
+ /* TODO: return on fail.
+ * Add a 'return' here before adding any code following
+ * the if-block.
+ */
+ }
+}
+
+static void plat_cluster_pwron_common(unsigned int cpu,
+ const psci_power_state_t *state, unsigned int req_pstate)
+{
+ assert(cpu == plat_my_core_pos());
+
+ if (plat_mt_pm_invoke(pwr_cluster_on, cpu, state) != 0) {
+ /* TODO: return on fail.
+ * Add a 'return' here before adding any code following
+ * the if-block.
+ */
+ }
+}
+
+/*
+ * Common MTK_platform operations to power on/off a
+ * mcusys in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
+ */
+
+static void plat_mcusys_pwrdwn_common(unsigned int cpu,
+ const psci_power_state_t *state, unsigned int req_pstate)
+{
+ assert(cpu == plat_my_core_pos());
+
+ if (plat_mt_pm_invoke(pwr_mcusys_dwn, cpu, state) != 0) {
+ return; /* return on fail */
+ }
+
+ mt_gic_distif_save();
+ gic_sgi_save_all();
+}
+
+static void plat_mcusys_pwron_common(unsigned int cpu,
+ const psci_power_state_t *state, unsigned int req_pstate)
+{
+ assert(cpu == plat_my_core_pos());
+
+ if (plat_mt_pm_invoke(pwr_mcusys_on, cpu, state) != 0) {
+ return; /* return on fail */
+ }
+
+ mt_gic_init();
+ mt_gic_distif_restore();
+ gic_sgi_restore_all();
+
+ dfd_resume();
+
+ plat_mt_pm_invoke_no_check(pwr_mcusys_on_finished, cpu, state);
+}
+
+/*
+ * plat_psci_ops implementation
+ */
+
+static void plat_cpu_standby(plat_local_state_t cpu_state)
+{
+ uint64_t scr;
+
+ scr = read_scr_el3();
+ write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
+
+ isb();
+ dsb();
+ wfi();
+
+ write_scr_el3(scr);
+}
+
+static int plat_power_domain_on(u_register_t mpidr)
+{
+ unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+ unsigned int cluster = 0U;
+
+ if (cpu >= PLATFORM_CORE_COUNT) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ if (!spm_get_cluster_powerstate(cluster)) {
+ spm_poweron_cluster(cluster);
+ }
+
+ /* init CPU reset arch as AARCH64 */
+ mcucfg_init_archstate(cluster, cpu, true);
+ mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint);
+ spm_poweron_cpu(cluster, cpu);
+
+ return PSCI_E_SUCCESS;
+}
+
+static void plat_power_domain_on_finish(const psci_power_state_t *state)
+{
+ unsigned long mpidr = read_mpidr_el1();
+ unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+
+ assert(cpu < PLATFORM_CORE_COUNT);
+
+ /* Allow IRQs to wakeup this core in IDLE flow */
+ mcucfg_enable_gic_wakeup(0U, cpu);
+
+ if (IS_CLUSTER_OFF_STATE(state)) {
+ plat_cluster_pwron_common(cpu, state, 0U);
+ }
+
+ plat_cpu_pwron_common(cpu, state, 0U);
+}
+
+static void plat_power_domain_off(const psci_power_state_t *state)
+{
+ unsigned long mpidr = read_mpidr_el1();
+ unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+
+ assert(cpu < PLATFORM_CORE_COUNT);
+
+ plat_cpu_pwrdwn_common(cpu, state, 0U);
+ spm_poweroff_cpu(0U, cpu);
+
+ /* prevent unintended IRQs from waking up the hot-unplugged core */
+ mcucfg_disable_gic_wakeup(0U, cpu);
+
+ if (IS_CLUSTER_OFF_STATE(state)) {
+ plat_cluster_pwrdwn_common(cpu, state, 0U);
+ }
+}
+
+static void plat_power_domain_suspend(const psci_power_state_t *state)
+{
+ unsigned int cpu = plat_my_core_pos();
+
+ assert(cpu < PLATFORM_CORE_COUNT);
+
+ plat_mt_pm_invoke_no_check(pwr_prompt, cpu, state);
+
+ /* Perform the common CPU specific operations */
+ plat_cpu_pwrdwn_common(cpu, state, plat_power_state[cpu]);
+
+ if (IS_CLUSTER_OFF_STATE(state)) {
+ /* Perform the common cluster specific operations */
+ plat_cluster_pwrdwn_common(cpu, state, plat_power_state[cpu]);
+ }
+
+ if (IS_MCUSYS_OFF_STATE(state)) {
+ /* Perform the common mcusys specific operations */
+ plat_mcusys_pwrdwn_common(cpu, state, plat_power_state[cpu]);
+ }
+}
+
+static void plat_power_domain_suspend_finish(const psci_power_state_t *state)
+{
+ unsigned int cpu = plat_my_core_pos();
+
+ assert(cpu < PLATFORM_CORE_COUNT);
+
+ if (IS_MCUSYS_OFF_STATE(state)) {
+ /* Perform the common mcusys specific operations */
+ plat_mcusys_pwron_common(cpu, state, plat_power_state[cpu]);
+ }
+
+ if (IS_CLUSTER_OFF_STATE(state)) {
+ /* Perform the common cluster specific operations */
+ plat_cluster_pwron_common(cpu, state, plat_power_state[cpu]);
+ }
+
+ /* Perform the common CPU specific operations */
+ plat_cpu_pwron_common(cpu, state, plat_power_state[cpu]);
+
+ plat_mt_pm_invoke_no_check(pwr_reflect, cpu, state);
+}
+
+static int plat_validate_power_state(unsigned int power_state,
+ psci_power_state_t *req_state)
+{
+ unsigned int pstate = psci_get_pstate_type(power_state);
+ unsigned int aff_lvl = psci_get_pstate_pwrlvl(power_state);
+ unsigned int cpu = plat_my_core_pos();
+
+ if (aff_lvl > PLAT_MAX_PWR_LVL) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ if (pstate == PSTATE_TYPE_STANDBY) {
+ req_state->pwr_domain_state[0] = PLAT_MAX_RET_STATE;
+ } else {
+ unsigned int i;
+ unsigned int pstate_id = psci_get_pstate_id(power_state);
+ plat_local_state_t s = MTK_LOCAL_STATE_OFF;
+
+ /* Use pstate_id to be power domain state */
+ if (pstate_id > s) {
+ s = (plat_local_state_t)pstate_id;
+ }
+
+ for (i = 0U; i <= aff_lvl; i++) {
+ req_state->pwr_domain_state[i] = s;
+ }
+ }
+
+ plat_power_state[cpu] = power_state;
+ return PSCI_E_SUCCESS;
+}
+
+static void plat_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+ unsigned int lv;
+ unsigned int cpu = plat_my_core_pos();
+
+ for (lv = PSCI_CPU_PWR_LVL; lv <= PLAT_MAX_PWR_LVL; lv++) {
+ req_state->pwr_domain_state[lv] = PLAT_MAX_OFF_STATE;
+ }
+
+ plat_power_state[cpu] =
+ psci_make_powerstate(
+ MT_PLAT_PWR_STATE_SYSTEM_SUSPEND,
+ PSTATE_TYPE_POWERDOWN, PLAT_MAX_PWR_LVL);
+
+ flush_dcache_range((uintptr_t)
+ &plat_power_state[cpu],
+ sizeof(plat_power_state[cpu]));
+}
+
+/*******************************************************************************
+ * MTK handlers to shutdown/reboot the system
+ ******************************************************************************/
+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");
+
+ gpio_set_value(gpio_reset->index, gpio_reset->polarity);
+
+ wfi();
+ ERROR("MTK System Reset: operation not handled.\n");
+ panic();
+}
+
+static void __dead2 plat_mtk_system_off(void)
+{
+ INFO("MTK System Off\n");
+
+ rtc_power_off_sequence();
+ pmic_power_off();
+
+ wfi();
+ ERROR("MTK System Off: operation not handled.\n");
+ panic();
+}
+
+static const plat_psci_ops_t plat_psci_ops = {
+ .system_reset = plat_mtk_system_reset,
+ .system_off = plat_mtk_system_off,
+ .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,
+ .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_psci_ops;
+ secure_entrypoint = sec_entrypoint;
+
+ /*
+ * init the warm reset config for boot CPU
+ * reset arch as AARCH64
+ * reset addr as function bl31_warm_entrypoint()
+ */
+ mcucfg_init_archstate(0U, 0U, true);
+ mcucfg_set_bootaddr(0U, 0U, secure_entrypoint);
+
+ spmc_init();
+ plat_mt_pm = mt_plat_cpu_pm_init();
+
+ return 0;
+}
diff --git a/plat/mediatek/mt8195/plat_sip_calls.c b/plat/mediatek/mt8195/plat_sip_calls.c
new file mode 100644
index 0000000..1cdd622
--- /dev/null
+++ b/plat/mediatek/mt8195/plat_sip_calls.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020-2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <mt_dp.h>
+#include <mt_spm.h>
+#include <mt_spm_vcorefs.h>
+#include <mtk_apusys.h>
+#include <mtk_sip_svc.h>
+#include <plat_dfd.h>
+#include "plat_sip_calls.h"
+
+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)
+{
+ int32_t ret;
+ uint32_t ret_val;
+
+ switch (smc_fid) {
+ case MTK_SIP_DP_CONTROL_AARCH32:
+ case MTK_SIP_DP_CONTROL_AARCH64:
+ ret = dp_secure_handler(x1, x2, &ret_val);
+ SMC_RET2(handle, ret, ret_val);
+ break;
+ case MTK_SIP_VCORE_CONTROL_AARCH32:
+ case MTK_SIP_VCORE_CONTROL_AARCH64:
+ ret = spm_vcorefs_v2_args(x1, x2, x3, &x4);
+ SMC_RET2(handle, ret, x4);
+ break;
+ case MTK_SIP_KERNEL_DFD_AARCH32:
+ case MTK_SIP_KERNEL_DFD_AARCH64:
+ ret = dfd_smc_dispatcher(x1, x2, x3, x4);
+ SMC_RET1(handle, ret);
+ break;
+ case MTK_SIP_APUSYS_CONTROL_AARCH32:
+ case MTK_SIP_APUSYS_CONTROL_AARCH64:
+ ret = apusys_kernel_ctrl(x1, x2, x3, x4, &ret_val);
+ SMC_RET2(handle, ret, ret_val);
+ break;
+ default:
+ ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+ break;
+ }
+
+ SMC_RET1(handle, SMC_UNK);
+}
diff --git a/plat/mediatek/mt8195/plat_topology.c b/plat/mediatek/mt8195/plat_topology.c
new file mode 100644
index 0000000..bc95c64
--- /dev/null
+++ b/plat/mediatek/mt8195/plat_topology.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/psci/psci.h>
+
+#include <plat_helpers.h>
+#include <platform_def.h>
+
+const unsigned char mtk_power_domain_tree_desc[] = {
+ /* Number of root nodes */
+ PLATFORM_SYSTEM_COUNT,
+ /* Number of children for the root node */
+ PLATFORM_MCUSYS_COUNT,
+ /* Number of children for the mcusys node */
+ PLATFORM_CLUSTER_COUNT,
+ /* Number of children for the first cluster node */
+ PLATFORM_CLUSTER0_CORE_COUNT,
+};
+
+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;
+
+ if ((read_mpidr() & MPIDR_MT_MASK) != 0) {
+ /* ARMv8.2 arch */
+ if ((mpidr & (MPIDR_AFFLVL_MASK << MPIDR_AFF0_SHIFT)) != 0) {
+ return -1;
+ }
+ return plat_mediatek_calc_core_pos(mpidr);
+ }
+
+ mpidr &= MPIDR_AFFINITY_MASK;
+
+ if ((mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) != 0) {
+ 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 * 8));
+}
diff --git a/plat/mediatek/mt8195/platform.mk b/plat/mediatek/mt8195/platform.mk
new file mode 100644
index 0000000..07d39cb
--- /dev/null
+++ b/plat/mediatek/mt8195/platform.mk
@@ -0,0 +1,113 @@
+#
+# Copyright (c) 2021-2022, 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}/common/lpm/ \
+ -I${MTK_PLAT}/drivers/cirq/ \
+ -I${MTK_PLAT}/drivers/dp/ \
+ -I${MTK_PLAT}/drivers/gic600/ \
+ -I${MTK_PLAT}/drivers/gpio/ \
+ -I${MTK_PLAT}/drivers/pmic/ \
+ -I${MTK_PLAT}/drivers/pmic_wrap/ \
+ -I${MTK_PLAT}/drivers/ptp3/ \
+ -I${MTK_PLAT}/drivers/rtc/ \
+ -I${MTK_PLAT}/drivers/timer/ \
+ -I${MTK_PLAT}/drivers/uart/ \
+ -I${MTK_PLAT}/include/ \
+ -I${MTK_PLAT_SOC}/drivers/apusys/ \
+ -I${MTK_PLAT_SOC}/drivers/dcm \
+ -I${MTK_PLAT_SOC}/drivers/dfd \
+ -I${MTK_PLAT_SOC}/drivers/emi_mpu/ \
+ -I${MTK_PLAT_SOC}/drivers/gpio/ \
+ -I${MTK_PLAT_SOC}/drivers/mcdi/ \
+ -I${MTK_PLAT_SOC}/drivers/pmic/ \
+ -I${MTK_PLAT_SOC}/drivers/spmc/ \
+ -I${MTK_PLAT_SOC}/drivers/ptp3/ \
+ -I${MTK_PLAT_SOC}/include/
+
+GICV3_SUPPORT_GIC600 := 1
+include drivers/arm/gic/v3/gicv3.mk
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_BL_COMMON_SOURCES := ${GICV3_SOURCES} \
+ ${XLAT_TABLES_LIB_SRCS} \
+ plat/common/aarch64/crash_console_helpers.S \
+ plat/common/plat_psci_common.c
+
+
+BL31_SOURCES += common/desc_image_load.c \
+ drivers/delay_timer/delay_timer.c \
+ drivers/gpio/gpio.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ drivers/ti/uart/aarch64/16550_console.S \
+ lib/bl_aux_params/bl_aux_params.c \
+ lib/cpus/aarch64/cortex_a55.S \
+ lib/cpus/aarch64/cortex_a78.S \
+ plat/common/plat_gicv3.c \
+ ${MTK_PLAT}/common/mtk_plat_common.c \
+ ${MTK_PLAT}/common/mtk_sip_svc.c \
+ ${MTK_PLAT}/common/params_setup.c \
+ ${MTK_PLAT}/common/lpm/mt_lp_rm.c \
+ ${MTK_PLAT}/drivers/cirq/mt_cirq.c \
+ ${MTK_PLAT}/drivers/dp/mt_dp.c \
+ ${MTK_PLAT}/drivers/gic600/mt_gic_v3.c \
+ ${MTK_PLAT}/drivers/gpio/mtgpio_common.c \
+ ${MTK_PLAT}/drivers/pmic/pmic.c \
+ ${MTK_PLAT}/drivers/pmic_wrap/pmic_wrap_init_v2.c \
+ ${MTK_PLAT}/drivers/ptp3/ptp3_common.c \
+ ${MTK_PLAT}/drivers/rtc/rtc_common.c \
+ ${MTK_PLAT}/drivers/rtc/rtc_mt6359p.c \
+ ${MTK_PLAT}/drivers/timer/mt_timer.c \
+ ${MTK_PLAT}/drivers/uart/uart.c \
+ ${MTK_PLAT_SOC}/aarch64/platform_common.c \
+ ${MTK_PLAT_SOC}/aarch64/plat_helpers.S \
+ ${MTK_PLAT_SOC}/bl31_plat_setup.c \
+ ${MTK_PLAT_SOC}/drivers/apusys/apupll.c \
+ ${MTK_PLAT_SOC}/drivers/apusys/apupwr_clkctl.c \
+ ${MTK_PLAT_SOC}/drivers/apusys/mtk_apusys.c \
+ ${MTK_PLAT_SOC}/drivers/dcm/mtk_dcm.c \
+ ${MTK_PLAT_SOC}/drivers/dcm/mtk_dcm_utils.c \
+ ${MTK_PLAT_SOC}/drivers/dfd/plat_dfd.c \
+ ${MTK_PLAT_SOC}/drivers/emi_mpu/emi_mpu.c \
+ ${MTK_PLAT_SOC}/drivers/gpio/mtgpio.c \
+ ${MTK_PLAT_SOC}/drivers/mcdi/mt_cpu_pm.c \
+ ${MTK_PLAT_SOC}/drivers/mcdi/mt_cpu_pm_cpc.c \
+ ${MTK_PLAT_SOC}/drivers/mcdi/mt_mcdi.c \
+ ${MTK_PLAT_SOC}/drivers/mcdi/mt_lp_irqremain.c \
+ ${MTK_PLAT_SOC}/drivers/gpio/mtgpio.c \
+ ${MTK_PLAT_SOC}/drivers/spmc/mtspmc.c \
+ ${MTK_PLAT_SOC}/plat_pm.c \
+ ${MTK_PLAT_SOC}/plat_sip_calls.c \
+ ${MTK_PLAT_SOC}/plat_topology.c
+
+# Build SPM drivers
+include ${MTK_PLAT_SOC}/drivers/spm/build.mk
+
+# Configs for A78 and A55
+HW_ASSISTED_COHERENCY := 1
+USE_COHERENT_MEM := 0
+CTX_INCLUDE_AARCH32_REGS := 0
+ERRATA_A55_1530923 := 1
+
+ERRATA_A78_1688305 := 1
+ERRATA_A78_1941498 := 1
+ERRATA_A78_1951500 := 1
+ERRATA_A78_1821534 := 1
+ERRATA_A78_2132060 := 1
+ERRATA_A78_2242635 := 1
+
+# indicate the reset vector address can be programmed
+PROGRAMMABLE_RESET_ADDRESS := 1
+
+COLD_BOOT_SINGLE_CPU := 1
+
+MACH_MT8195 := 1
+$(eval $(call add_define,MACH_MT8195))
+
+include lib/coreboot/coreboot.mk
diff --git a/plat/mediatek/topology/armv8_2/topology.c b/plat/mediatek/topology/armv8_2/topology.c
new file mode 100644
index 0000000..1627bbd
--- /dev/null
+++ b/plat/mediatek/topology/armv8_2/topology.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022, Mediatek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <lib/psci/psci.h>
+#include <platform_def.h>
+
+#pragma weak plat_get_power_domain_tree_desc
+
+static 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,
+};
+
+/*******************************************************************************
+ * This function returns the default topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ return mtk_power_domain_tree_desc;
+}
diff --git a/plat/mediatek/topology/rules.mk b/plat/mediatek/topology/rules.mk
new file mode 100644
index 0000000..29f15bb
--- /dev/null
+++ b/plat/mediatek/topology/rules.mk
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := topology
+LOCAL_SRCS-y := $(LOCAL_DIR)/$(ARCH_VERSION)/topology.c
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S
new file mode 100644
index 0000000..6c8c4f0
--- /dev/null
+++ b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a57.h>
+#include <cpu_macros.S>
+
+#include <platform_def.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+
+#define MIDR_PN_CORTEX_A57 0xD07
+
+/*******************************************************************************
+ * Implementation defined ACTLR_EL3 bit definitions
+ ******************************************************************************/
+#define ACTLR_ELx_L2ACTLR_BIT (U(1) << 6)
+#define ACTLR_ELx_L2ECTLR_BIT (U(1) << 5)
+#define ACTLR_ELx_L2CTLR_BIT (U(1) << 4)
+#define ACTLR_ELx_CPUECTLR_BIT (U(1) << 1)
+#define ACTLR_ELx_CPUACTLR_BIT (U(1) << 0)
+#define ACTLR_ELx_ENABLE_ALL_ACCESS (ACTLR_ELx_L2ACTLR_BIT | \
+ ACTLR_ELx_L2ECTLR_BIT | \
+ ACTLR_ELx_L2CTLR_BIT | \
+ ACTLR_ELx_CPUECTLR_BIT | \
+ ACTLR_ELx_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
+ .weak plat_core_pos_by_mpidr
+ .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_ELx_ENABLE_ALL_ACCESS
+ orr x0, x0, x1
+ msr actlr_el3, x0
+ mrs x0, actlr_el2
+ mov x1, #ACTLR_ELx_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)
+ * Registers clobbered: x0, x8
+ * ----------------------------------------------------------
+ */
+func plat_my_core_pos
+ mov x8, x30
+ mrs x0, mpidr_el1
+ bl plat_core_pos_by_mpidr
+ ret x8
+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
+
+ /* -----------------------------------------------------
+ * 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
+ adr x2, __RELA_END__
+ sub x2, x2, x18
+_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
+
+ /* ------------------------------------------------------
+ * int32_t plat_core_pos_by_mpidr(u_register_t 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.
+ *
+ * Clobbers: x0-x3
+ * ------------------------------------------------------
+ */
+func plat_core_pos_by_mpidr
+ lsr x1, x0, #MPIDR_AFF0_SHIFT
+ and x1, x1, #MPIDR_AFFLVL_MASK /* core id */
+ lsr x2, x0, #MPIDR_AFF1_SHIFT
+ and x2, x2, #MPIDR_AFFLVL_MASK /* cluster id */
+
+ /* core_id >= PLATFORM_MAX_CPUS_PER_CLUSTER */
+ mov x0, #-1
+ cmp x1, #(PLATFORM_MAX_CPUS_PER_CLUSTER - 1)
+ b.gt 1f
+
+ /* cluster_id >= PLATFORM_CLUSTER_COUNT */
+ cmp x2, #(PLATFORM_CLUSTER_COUNT - 1)
+ b.gt 1f
+
+ /* CorePos = CoreId + (ClusterId * cpus per cluster) */
+ mov x3, #PLATFORM_MAX_CPUS_PER_CLUSTER
+ mul x3, x3, x2
+ add x0, x1, x3
+
+1:
+ ret
+endfunc plat_core_pos_by_mpidr
+
+ /* ----------------------------------------
+ * 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
diff --git a/plat/nvidia/tegra/common/tegra_bl31_setup.c b/plat/nvidia/tegra/common/tegra_bl31_setup.c
new file mode 100644
index 0000000..6a3eae0
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_bl31_setup.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <cortex_a57.h>
+#include <denver.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+
+#include <memctrl.h>
+#include <profiler.h>
+#include <smmu.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+/* length of Trusty's input parameters (in bytes) */
+#define TRUSTY_PARAMS_LEN_BYTES (4096*2)
+
+/*******************************************************************************
+ * Declarations of linker defined symbols which will help us find the layout
+ * of trusted SRAM
+ ******************************************************************************/
+IMPORT_SYM(uint64_t, __RW_START__, BL31_RW_START);
+
+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
+};
+#ifdef SPD_trusty
+static aapcs64_params_t bl32_args;
+#endif
+
+/*******************************************************************************
+ * This variable holds the non-secure image entry address
+ ******************************************************************************/
+extern uint64_t ns_image_entrypoint;
+
+/*******************************************************************************
+ * 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;
+ int32_t ret;
+
+ /*
+ * 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.
+ */
+ 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;
+#ifdef SPD_trusty
+ /* save BL32 boot parameters */
+ memcpy(&bl32_args, &arg_from_bl2->bl32_ep_info->args, sizeof(bl32_args));
+#endif
+ }
+
+ /*
+ * 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();
+ }
+
+ /*
+ * Enable console for the platform
+ */
+ plat_enable_console(plat_params->uart_id);
+
+ /*
+ * 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.
+ */
+ 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();
+
+ /*
+ * 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)
+{
+ /*
+ * arg0 = TZDRAM aperture available for BL32
+ * arg1 = BL32 boot params
+ * arg2 = EKS Blob Length
+ * arg3 = Boot Profiler Carveout Base
+ */
+ args->arg0 = bl32_args.arg0;
+ args->arg1 = bl32_args.arg2;
+
+ /* update EKS size */
+ args->arg2 = bl32_args.arg4;
+
+ /* Profiler Carveout Base */
+ args->arg3 = bl32_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();
+
+ /*
+ * 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)
+{
+ /*
+ * Platform specific runtime setup
+ */
+ plat_runtime_setup();
+
+ /*
+ * 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 = BL_END - BL31_RW_START;
+ uint64_t rodata_start = BL_RO_DATA_BASE;
+ uint64_t rodata_size = BL_RO_DATA_END - BL_RO_DATA_BASE;
+ uint64_t code_base = BL_CODE_BASE;
+ uint64_t code_size = BL_CODE_END - BL_CODE_BASE;
+ const mmap_region_t *plat_mmio_map = NULL;
+ 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);
+
+ /* 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);
+
+ /*
+ * Sanity check the input values
+ */
+ if ((base == 0U) || (size_in_bytes == 0U)) {
+ ERROR("NS address 0x%" PRIx64 " (%" PRId64 " bytes) is invalid\n",
+ base, size_in_bytes);
+ return -EINVAL;
+ }
+
+ /*
+ * 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%" PRIx64 " is out-of-bounds!\n", base);
+ return -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%" PRIx64 " overlaps TZDRAM!\n", base);
+ return -ENOTSUP;
+ }
+
+ /* valid NS address */
+ return 0;
+}
diff --git a/plat/nvidia/tegra/common/tegra_common.mk b/plat/nvidia/tegra/common/tegra_common.mk
new file mode 100644
index 0000000..3791018
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_common.mk
@@ -0,0 +1,59 @@
+#
+# Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2020, NVIDIA Corporation. 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
+
+include lib/xlat_tables_v2/xlat_tables.mk
+PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS}
+
+TEGRA_COMMON := plat/nvidia/tegra/common
+TEGRA_DRIVERS := plat/nvidia/tegra/drivers
+TEGRA_LIBS := plat/nvidia/tegra/lib
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+TEGRA_GICv3_SOURCES := $(GICV3_SOURCES) \
+ plat/common/plat_gicv3.c \
+ ${TEGRA_COMMON}/tegra_gicv3.c
+
+# Include GICv2 driver files
+include drivers/arm/gic/v2/gicv2.mk
+
+TEGRA_GICv2_SOURCES := ${GICV2_SOURCES} \
+ plat/common/plat_gicv2.c \
+ ${TEGRA_COMMON}/tegra_gicv2.c
+
+TEGRA_GICv3_SOURCES := drivers/arm/gic/common/gic_common.c \
+ drivers/arm/gic/v3/arm_gicv3_common.c \
+ drivers/arm/gic/v3/gicv3_main.c \
+ drivers/arm/gic/v3/gicv3_helpers.c \
+ plat/common/plat_gicv3.c \
+ ${TEGRA_COMMON}/tegra_gicv3.c
+
+BL31_SOURCES += drivers/delay_timer/delay_timer.c \
+ drivers/io/io_storage.c \
+ plat/common/aarch64/crash_console_helpers.S \
+ ${TEGRA_LIBS}/debug/profiler.c \
+ ${TEGRA_COMMON}/aarch64/tegra_helpers.S \
+ ${TEGRA_LIBS}/debug/profiler.c \
+ ${TEGRA_COMMON}/tegra_bl31_setup.c \
+ ${TEGRA_COMMON}/tegra_delay_timer.c \
+ ${TEGRA_COMMON}/tegra_fiq_glue.c \
+ ${TEGRA_COMMON}/tegra_io_storage.c \
+ ${TEGRA_COMMON}/tegra_platform.c \
+ ${TEGRA_COMMON}/tegra_pm.c \
+ ${TEGRA_COMMON}/tegra_sip_calls.c \
+ ${TEGRA_COMMON}/tegra_sdei.c
+
+ifneq ($(ENABLE_STACK_PROTECTOR), 0)
+BL31_SOURCES += ${TEGRA_COMMON}/tegra_stack_protector.c
+endif
+ifeq (${EL3_EXCEPTION_HANDLING},1)
+BL31_SOURCES += plat/common/aarch64/plat_ehf.c
+endif
diff --git a/plat/nvidia/tegra/common/tegra_delay_timer.c b/plat/nvidia/tegra/common/tegra_delay_timer.c
new file mode 100644
index 0000000..d9547c4
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_delay_timer.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+
+#include <tegra_def.h>
+#include <tegra_private.h>
+
+static uint32_t tegra_timer_get_value(void)
+{
+ /* enable cntps_tval_el1 timer, mask interrupt */
+ write_cntps_ctl_el1(CNTP_CTL_IMASK_BIT | CNTP_CTL_ENABLE_BIT);
+
+ /*
+ * Generic delay timer implementation expects the timer to be a down
+ * counter. The value is clipped from 64 to 32 bits.
+ */
+ return (uint32_t)(read_cntps_tval_el1());
+}
+
+/*
+ * Initialise the architecture provided counter as the delay timer.
+ */
+void tegra_delay_timer_init(void)
+{
+ static timer_ops_t tegra_timer_ops;
+
+ /* Value in ticks */
+ uint32_t multiplier = MHZ_TICKS_PER_SEC;
+
+ /* Value in ticks per second (Hz) */
+ uint32_t divider = plat_get_syscnt_freq2();
+
+ /* Reduce multiplier and divider by dividing them repeatedly by 10 */
+ while (((multiplier % 10U) == 0U) && ((divider % 10U) == 0U)) {
+ multiplier /= 10U;
+ divider /= 10U;
+ }
+
+ /* enable cntps_tval_el1 timer, mask interrupt */
+ write_cntps_ctl_el1(CNTP_CTL_IMASK_BIT | CNTP_CTL_ENABLE_BIT);
+
+ /* register the timer */
+ tegra_timer_ops.get_timer_value = tegra_timer_get_value;
+ tegra_timer_ops.clk_mult = multiplier;
+ tegra_timer_ops.clk_div = divider;
+ timer_init(&tegra_timer_ops);
+}
diff --git a/plat/nvidia/tegra/common/tegra_fiq_glue.c b/plat/nvidia/tegra/common/tegra_fiq_glue.c
new file mode 100644
index 0000000..5309d98
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_fiq_glue.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <bl31/interrupt_mgmt.h>
+#include <bl31/ehf.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <denver.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+
+#if ENABLE_WDT_LEGACY_FIQ_HANDLING
+#include <flowctrl.h>
+#endif
+#include <tegra_def.h>
+#include <tegra_private.h>
+
+/* Legacy FIQ used by earlier Tegra platforms */
+#define LEGACY_FIQ_PPI_WDT 28U
+
+/*******************************************************************************
+ * 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 int tegra_fiq_interrupt_handler(unsigned int id, unsigned int 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();
+
+ (void)flags;
+ (void)handle;
+ (void)cookie;
+
+ /*
+ * 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 (id == LEGACY_FIQ_PPI_WDT) {
+ tegra_fc_disable_fiq_to_ccplex_routing();
+ }
+#endif
+
+ /*
+ * Mark this interrupt as complete to avoid a FIQ storm.
+ */
+ plat_ic_end_of_interrupt(id);
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Setup handler for FIQ interrupts
+ ******************************************************************************/
+void tegra_fiq_handler_setup(void)
+{
+ /* return if already registered */
+ if (fiq_handler_active == 0U) {
+ /*
+ * Register an interrupt handler for FIQ interrupts generated for
+ * NS interrupt sources
+ */
+ ehf_register_priority_handler(PLAT_TEGRA_WDT_PRIO, tegra_fiq_interrupt_handler);
+
+ /* 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_sysregs_t *el1state_ctx = get_el1_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;
+}
diff --git a/plat/nvidia/tegra/common/tegra_gicv2.c b/plat/nvidia/tegra/common/tegra_gicv2.c
new file mode 100644
index 0000000..012107e
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_gicv2.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#include <tegra_private.h>
+#include <tegra_def.h>
+
+static unsigned int tegra_target_masks[PLATFORM_CORE_COUNT];
+
+/******************************************************************************
+ * 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;
+ tegra_gic_data.target_masks = tegra_target_masks;
+ tegra_gic_data.target_masks_num = ARRAY_SIZE(tegra_target_masks);
+ 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_set_pe_target_mask(plat_my_core_pos());
+ 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_set_pe_target_mask(plat_my_core_pos());
+ gicv2_cpuif_enable();
+}
diff --git a/plat/nvidia/tegra/common/tegra_gicv3.c b/plat/nvidia/tegra/common/tegra_gicv3.c
new file mode 100644
index 0000000..cba2f9b
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_gicv3.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/bl_common.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/utils.h>
+
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <tegra_private.h>
+#include <tegra_def.h>
+
+/* The GICv3 driver only needs to be initialized in EL3 */
+static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static unsigned int plat_tegra_mpidr_to_core_pos(unsigned long mpidr)
+{
+ return (unsigned int)plat_core_pos_by_mpidr(mpidr);
+}
+
+/******************************************************************************
+ * Tegra common helper to setup the GICv3 driver data.
+ *****************************************************************************/
+void tegra_gic_setup(const interrupt_prop_t *interrupt_props,
+ unsigned int interrupt_props_num)
+{
+ /*
+ * Tegra GIC configuration settings
+ */
+ static gicv3_driver_data_t tegra_gic_data;
+
+ /*
+ * Register Tegra GICv3 driver
+ */
+ tegra_gic_data.gicd_base = TEGRA_GICD_BASE;
+ tegra_gic_data.gicr_base = TEGRA_GICR_BASE;
+ tegra_gic_data.rdistif_num = PLATFORM_CORE_COUNT;
+ tegra_gic_data.rdistif_base_addrs = rdistif_base_addrs;
+ tegra_gic_data.mpidr_to_core_pos = plat_tegra_mpidr_to_core_pos;
+ tegra_gic_data.interrupt_props = interrupt_props;
+ tegra_gic_data.interrupt_props_num = interrupt_props_num;
+ gicv3_driver_init(&tegra_gic_data);
+
+ /* initialize the GICD and GICR */
+ tegra_gic_init();
+}
+
+/******************************************************************************
+ * Tegra common helper to initialize the GICv3 only driver.
+ *****************************************************************************/
+void tegra_gic_init(void)
+{
+ gicv3_distif_init();
+ gicv3_rdistif_init(plat_my_core_pos());
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Tegra common helper to disable the GICv3 CPU interface
+ *****************************************************************************/
+void tegra_gic_cpuif_deactivate(void)
+{
+ gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Tegra common helper to initialize the per cpu distributor interface
+ * in GICv3
+ *****************************************************************************/
+void tegra_gic_pcpu_init(void)
+{
+ gicv3_rdistif_init(plat_my_core_pos());
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
diff --git a/plat/nvidia/tegra/common/tegra_io_storage.c b/plat/nvidia/tegra/common/tegra_io_storage.c
new file mode 100644
index 0000000..21641aa
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_io_storage.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <plat/common/platform.h>
+
+/*
+ * 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;
+}
diff --git a/plat/nvidia/tegra/common/tegra_platform.c b/plat/nvidia/tegra/common/tegra_platform.c
new file mode 100644
index 0000000..f3aa3ea
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_platform.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2021, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <lib/mmio.h>
+#include <lib/smccc.h>
+#include <services/arm_arch_svc.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+/*******************************************************************************
+ * 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_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));
+}
+
+bool tegra_chipid_is_t194(void)
+{
+ uint32_t chip_id = (tegra_get_chipid() >> CHIP_ID_SHIFT) & CHIP_ID_MASK;
+
+ return (chip_id == TEGRA_CHIPID_TEGRA19);
+}
+
+/*
+ * 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);
+}
+
+/*
+ * This function returns soc version which mainly consist of below fields
+ *
+ * soc_version[30:24] = JEP-106 continuation code for the SiP
+ * soc_version[23:16] = JEP-106 identification code with parity bit for the SiP
+ * soc_version[0:15] = chip identification
+ */
+int32_t plat_get_soc_version(void)
+{
+ uint32_t chip_id = ((tegra_get_chipid() >> CHIP_ID_SHIFT) & CHIP_ID_MASK);
+ uint32_t manfid = SOC_ID_SET_JEP_106(JEDEC_NVIDIA_BKID, JEDEC_NVIDIA_MFID);
+
+ return (int32_t)(manfid | (chip_id & SOC_ID_IMPL_DEF_MASK));
+}
+
+/*
+ * This function returns soc revision in below format
+ *
+ * soc_revision[8:15] = major version number
+ * soc_revision[0:7] = minor version number
+ */
+int32_t plat_get_soc_revision(void)
+{
+ return (int32_t)(((tegra_get_chipid_major() << 8) | tegra_get_chipid_minor()) &
+ SOC_ID_REV_MASK);
+}
+
+/*****************************************************************************
+ * plat_is_smccc_feature_available() - This function checks whether SMCCC feature
+ * is availabile for the platform or not.
+ * @fid: SMCCC function id
+ *
+ * Return SMC_ARCH_CALL_SUCCESS if SMCCC feature is available and
+ * SMC_ARCH_CALL_NOT_SUPPORTED otherwise.
+ *****************************************************************************/
+int32_t plat_is_smccc_feature_available(u_register_t fid)
+{
+ switch (fid) {
+ case SMCCC_ARCH_SOC_ID:
+ return SMC_ARCH_CALL_SUCCESS;
+ default:
+ return SMC_ARCH_CALL_NOT_SUPPORTED;
+ }
+}
diff --git a/plat/nvidia/tegra/common/tegra_pm.c b/plat/nvidia/tegra/common/tegra_pm.c
new file mode 100644
index 0000000..ec34a85
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_pm.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <drivers/console.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include <memctrl.h>
+#include <pmc.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+extern uint64_t tegra_bl31_phys_base;
+extern uint64_t tegra_sec_entry_point;
+
+/*******************************************************************************
+ * 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 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.
+ ******************************************************************************/
+static 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.
+ ******************************************************************************/
+static 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.
+ ******************************************************************************/
+static void tegra_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ (void)tegra_soc_pwr_domain_off(target_state);
+
+ /* disable GICC */
+ tegra_gic_cpuif_deactivate();
+}
+
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+static void tegra_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+ (void)tegra_soc_pwr_domain_suspend(target_state);
+
+ /* 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.
+ ******************************************************************************/
+static __dead2 void tegra_pwr_domain_power_down_wfi(const psci_power_state_t
+ *target_state)
+{
+ /* call the chip's power down handler */
+ (void)tegra_soc_pwr_domain_power_down_wfi(target_state);
+
+ /* Disable console if we are entering deep sleep. */
+ if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
+ PSTATE_ID_SOC_POWERDN) {
+ INFO("%s: complete. Entering System Suspend...\n", __func__);
+ console_flush();
+ console_switch_state(0);
+ }
+
+ wfi();
+ 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.
+ ******************************************************************************/
+static void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ const plat_params_from_bl2_t *plat_params;
+
+ /*
+ * Check if we are exiting from deep sleep.
+ */
+ if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
+ PSTATE_ID_SOC_POWERDN) {
+
+ /*
+ * On entering System Suspend state, the GIC loses power
+ * completely. Initialize the GIC global distributor and
+ * GIC cpu interfaces.
+ */
+ tegra_gic_init();
+
+ /* 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);
+
+ } else {
+ /*
+ * Initialize the GIC cpu and distributor interfaces
+ */
+ tegra_gic_pcpu_init();
+ }
+
+ /*
+ * 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.
+ ******************************************************************************/
+static 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
+ ******************************************************************************/
+static __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.
+ ******************************************************************************/
+static __dead2 void tegra_system_reset(void)
+{
+ INFO("Restarting system...\n");
+
+ /* per-SoC system reset handler */
+ (void)tegra_soc_prepare_system_reset();
+
+ /* wait for the system to reset */
+ for (;;) {
+ ;
+ }
+}
+
+/*******************************************************************************
+ * Handler called to check the validity of the power state parameter.
+ ******************************************************************************/
+static 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.
+ ******************************************************************************/
+static 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 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);
+
+ /*
+ * Disable System Suspend if the platform does not
+ * support it
+ */
+ if (!plat_supports_system_suspend()) {
+ tegra_plat_psci_ops.get_sys_suspend_power_state = NULL;
+ }
+
+ /*
+ * 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);
+}
diff --git a/plat/nvidia/tegra/common/tegra_sdei.c b/plat/nvidia/tegra/common/tegra_sdei.c
new file mode 100644
index 0000000..9241b81
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_sdei.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* SDEI configuration for Tegra platforms */
+
+#include <platform_def.h>
+
+#include <bl31/ehf.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/utils_def.h>
+#include <services/sdei.h>
+
+/* Private event mappings */
+static sdei_ev_map_t tegra_sdei_private[] = {
+ /* Event 0 definition */
+ SDEI_DEFINE_EVENT_0(TEGRA_SDEI_SGI_PRIVATE),
+
+ /* Dynamic private events */
+ SDEI_PRIVATE_EVENT(TEGRA_SDEI_DP_EVENT_0, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
+ SDEI_PRIVATE_EVENT(TEGRA_SDEI_DP_EVENT_1, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
+ SDEI_PRIVATE_EVENT(TEGRA_SDEI_DP_EVENT_2, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
+
+ /* General purpose explicit events */
+ SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_0, SDEI_MAPF_CRITICAL),
+ SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_1, SDEI_MAPF_CRITICAL),
+ SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_2, SDEI_MAPF_CRITICAL),
+ SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_3, SDEI_MAPF_CRITICAL),
+ SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_4, SDEI_MAPF_CRITICAL),
+ SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_5, SDEI_MAPF_CRITICAL),
+ SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_6, SDEI_MAPF_CRITICAL),
+ SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_7, SDEI_MAPF_CRITICAL),
+ SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_8, SDEI_MAPF_CRITICAL),
+ SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_9, SDEI_MAPF_CRITICAL),
+ SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_10, SDEI_MAPF_CRITICAL),
+ SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_11, SDEI_MAPF_CRITICAL)
+};
+
+/* Shared event mappings */
+static sdei_ev_map_t tegra_sdei_shared[] = {
+ /* Dynamic shared events */
+ SDEI_SHARED_EVENT(TEGRA_SDEI_DS_EVENT_0, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
+ SDEI_SHARED_EVENT(TEGRA_SDEI_DS_EVENT_1, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
+ SDEI_SHARED_EVENT(TEGRA_SDEI_DS_EVENT_2, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC)
+};
+
+void plat_sdei_setup(void)
+{
+ INFO("SDEI platform setup\n");
+}
+
+/* Export Tegra SDEI events */
+REGISTER_SDEI_MAP(tegra_sdei_private, tegra_sdei_shared);
diff --git a/plat/nvidia/tegra/common/tegra_sip_calls.c b/plat/nvidia/tegra/common/tegra_sip_calls.c
new file mode 100644
index 0000000..80a2c4d
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_sip_calls.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+
+#include <memctrl.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+/*******************************************************************************
+ * 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
+
+/*******************************************************************************
+ * 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 whether Video memory resize is enabled */
+ if (mmio_read_32(TEGRA_MC_BASE + MC_VIDEO_PROTECT_REG_CTRL)
+ != MC_VIDEO_PROTECT_WRITE_ACCESS_ENABLED) {
+ ERROR("Video Memory Resize isn't enabled! \n");
+ SMC_RET1(handle, (uint64_t)-ENOTSUP);
+ }
+
+ /*
+ * 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);
+
+ 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)
+);
diff --git a/plat/nvidia/tegra/common/tegra_stack_protector.c b/plat/nvidia/tegra/common/tegra_stack_protector.c
new file mode 100644
index 0000000..f6c459a
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_stack_protector.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+u_register_t plat_get_stack_protector_canary(void)
+{
+ u_register_t seed;
+
+ /*
+ * Ideally, a random number should be returned instead. As the
+ * platform does not have any random number generator, this is
+ * better than nothing, but not really secure.
+ */
+ seed = mmio_read_32(TEGRA_MISC_BASE + HARDWARE_REVISION_OFFSET);
+ seed <<= 32;
+ seed |= mmio_read_32(TEGRA_TMRUS_BASE);
+
+ return seed ^ read_cntpct_el0();
+}
diff --git a/plat/nvidia/tegra/drivers/bpmp/bpmp.c b/plat/nvidia/tegra/drivers/bpmp/bpmp.c
new file mode 100644
index 0000000..d7db604
--- /dev/null
+++ b/plat/nvidia/tegra/drivers/bpmp/bpmp.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bpmp.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <stdbool.h>
+#include <string.h>
+#include <tegra_def.h>
+
+#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");
+ }
+ }
+}
diff --git a/plat/nvidia/tegra/drivers/bpmp_ipc/intf.c b/plat/nvidia/tegra/drivers/bpmp_ipc/intf.c
new file mode 100644
index 0000000..2e90d25
--- /dev/null
+++ b/plat/nvidia/tegra/drivers/bpmp_ipc/intf.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <bpmp_ipc.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <stdbool.h>
+#include <string.h>
+#include <tegra_def.h>
+
+#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__);
+ return -EINVAL;
+ }
+
+ /* 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("%s: wait for slave failed (%d)\n", __func__, ret);
+ return ret;
+ }
+
+ /* retrieve the response frame */
+ if ((size_in <= IVC_DATA_SZ_BYTES) && (p_in != NULL)) {
+
+ 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);
+ }
+ }
+
+ ret = tegra_bpmp_free_master();
+ if (ret < 0) {
+ ERROR("%s: free master failed (%d)\n", __func__, ret);
+ }
+
+ 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, (uint32_t)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, (uint32_t)sizeof(req),
+ NULL, 0);
+ if (ret != 0) {
+ ERROR("%s: failed for module %d with error %d\n", __func__,
+ clk_id, ret);
+ }
+
+ return ret;
+}
diff --git a/plat/nvidia/tegra/drivers/bpmp_ipc/intf.h b/plat/nvidia/tegra/drivers/bpmp_ipc/intf.h
new file mode 100644
index 0000000..d85b906
--- /dev/null
+++ b/plat/nvidia/tegra/drivers/bpmp_ipc/intf.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BPMP_INTF_H
+#define BPMP_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 = U(1),
+ CMD_CLK_SET_RATE = U(2),
+ CMD_CLK_ROUND_RATE = U(3),
+ CMD_CLK_GET_PARENT = U(4),
+ CMD_CLK_SET_PARENT = U(5),
+ CMD_CLK_IS_ENABLED = U(6),
+ CMD_CLK_ENABLE = U(7),
+ CMD_CLK_DISABLE = U(8),
+ CMD_CLK_GET_ALL_INFO = U(14),
+ CMD_CLK_GET_MAX_CLK_ID = U(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 /* BPMP_INTF_H */
diff --git a/plat/nvidia/tegra/drivers/bpmp_ipc/ivc.c b/plat/nvidia/tegra/drivers/bpmp_ipc/ivc.c
new file mode 100644
index 0000000..d964fc0
--- /dev/null
+++ b/plat/nvidia/tegra/drivers/bpmp_ipc/ivc.c
@@ -0,0 +1,654 @@
+/*
+ * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+
+#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 <none>
+ * 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 <none>
+ * EST ACK <none>
+ * 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;
+}
diff --git a/plat/nvidia/tegra/drivers/bpmp_ipc/ivc.h b/plat/nvidia/tegra/drivers/bpmp_ipc/ivc.h
new file mode 100644
index 0000000..1b31821
--- /dev/null
+++ b/plat/nvidia/tegra/drivers/bpmp_ipc/ivc.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017-2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BPMP_IVC_H
+#define BPMP_IVC_H
+
+#include <lib/utils_def.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#define IVC_ALIGN U(64)
+#define IVC_CHHDR_TX_FIELDS U(16)
+#define IVC_CHHDR_RX_FIELDS U(16)
+
+struct ivc_channel_header;
+
+struct ivc {
+ struct ivc_channel_header *rx_channel;
+ struct ivc_channel_header *tx_channel;
+ uint32_t w_pos;
+ uint32_t r_pos;
+ void (*notify)(const struct ivc *);
+ uint32_t nframes;
+ uint32_t frame_size;
+};
+
+/* callback handler for notify on receiving a response */
+typedef void (* ivc_notify_function)(const struct ivc *);
+
+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 /* BPMP_IVC_H */
diff --git a/plat/nvidia/tegra/drivers/flowctrl/flowctrl.c b/plat/nvidia/tegra/drivers/flowctrl/flowctrl.c
new file mode 100644
index 0000000..8f55554
--- /dev/null
+++ b/plat/nvidia/tegra/drivers/flowctrl/flowctrl.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <cortex_a53.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <flowctrl.h>
+#include <lib/utils_def.h>
+#include <pmc.h>
+#include <tegra_def.h>
+
+#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);
+}
diff --git a/plat/nvidia/tegra/drivers/gpcdma/gpcdma.c b/plat/nvidia/tegra/drivers/gpcdma/gpcdma.c
new file mode 100644
index 0000000..d68cdfd
--- /dev/null
+++ b/plat/nvidia/tegra/drivers/gpcdma/gpcdma.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <errno.h>
+#include <gpcdma.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <platform_def.h>
+#include <stdbool.h>
+#include <tegra_def.h>
+
+/* 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);
+}
diff --git a/plat/nvidia/tegra/drivers/memctrl/memctrl_v1.c b/plat/nvidia/tegra/drivers/memctrl/memctrl_v1.c
new file mode 100644
index 0000000..b3dcd2a
--- /dev/null
+++ b/plat/nvidia/tegra/drivers/memctrl/memctrl_v1.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <memctrl.h>
+#include <memctrl_v1.h>
+#include <tegra_def.h>
+
+/* 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);
+}
+
+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 |
+ MT_NON_CACHEABLE); /* 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);
+ }
+}
diff --git a/plat/nvidia/tegra/drivers/memctrl/memctrl_v2.c b/plat/nvidia/tegra/drivers/memctrl/memctrl_v2.c
new file mode 100644
index 0000000..92120b5
--- /dev/null
+++ b/plat/nvidia/tegra/drivers/memctrl/memctrl_v2.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <mce.h>
+#include <memctrl.h>
+#include <memctrl_v2.h>
+#include <smmu.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+/* Video Memory base and size (live values) */
+static uint64_t video_mem_base;
+static uint64_t video_mem_size_mb;
+
+/*
+ * Init Memory controller during boot.
+ */
+void tegra_memctrl_setup(void)
+{
+ INFO("Tegra Memory Controller (v2)\n");
+
+ /* Initialize the System memory management unit */
+ tegra_smmu_init();
+
+ /* allow platforms to program custom memory controller settings */
+ plat_memctrl_setup();
+
+ /*
+ * 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);
+}
+
+/*
+ * Restore Memory Controller settings after "System Suspend"
+ */
+void tegra_memctrl_restore_settings(void)
+{
+ /* restore platform's memory controller settings */
+ plat_memctrl_restore();
+
+ /* video memory carveout region */
+ if (video_mem_base != 0ULL) {
+ tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO,
+ (uint32_t)video_mem_base);
+ assert(tegra_mc_read_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));
+ assert(tegra_mc_read_32(MC_VIDEO_PROTECT_BASE_HI)
+ == (uint32_t)(video_mem_base >> 32));
+ tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB,
+ (uint32_t)video_mem_size_mb);
+ assert(tegra_mc_read_32(MC_VIDEO_PROTECT_SIZE_MB)
+ == (uint32_t)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)
+{
+ ; /* do nothing */
+}
+
+/*
+ * Save MC settings before "System Suspend" to TZDRAM
+ */
+void tegra_mc_save_context(uint64_t mc_ctx_addr)
+{
+ uint32_t i, num_entries = 0;
+ mc_regs_t *mc_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;
+
+ assert((mc_ctx_addr >= tzdram_base) && (mc_ctx_addr <= tzdram_end));
+
+ /* get MC context table */
+ mc_ctx_regs = plat_memctrl_get_sys_suspend_ctx();
+ assert(mc_ctx_regs != NULL);
+
+ /*
+ * mc_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 (mc_ctx_regs[num_entries].reg != 0xFFFFFFFFU) {
+ num_entries++;
+ }
+
+ /* panic if the sizes do not match */
+ if (num_entries != mc_ctx_regs[0].val) {
+ ERROR("MC context size mismatch!");
+ panic();
+ }
+
+ /* save MC register values */
+ for (i = 1U; i < num_entries; i++) {
+ mc_ctx_regs[i].val = mmio_read_32(mc_ctx_regs[i].reg);
+ }
+
+ /* increment by 1 to take care of the last entry */
+ num_entries++;
+
+ /* Save MC config settings */
+ (void)memcpy((void *)mc_ctx_addr, mc_ctx_regs,
+ sizeof(mc_regs_t) * num_entries);
+
+ /* save the MC table address */
+ mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_MC_TABLE_ADDR_LO,
+ (uint32_t)mc_ctx_addr);
+ assert(mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_MC_TABLE_ADDR_LO)
+ == (uint32_t)mc_ctx_addr);
+ mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_MC_TABLE_ADDR_HI,
+ (uint32_t)(mc_ctx_addr >> 32));
+ assert(mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_MC_TABLE_ADDR_HI)
+ == (uint32_t)(mc_ctx_addr >> 32));
+}
+
+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;
+
+ INFO("Cleaning previous Video Memory Carveout\n");
+
+ /*
+ * 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_DEVICE | MT_RW | MT_NS); /* 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);
+
+ ret = mmap_remove_dynamic_region(non_overlap_area_start,
+ non_overlap_area_size);
+ assert(ret == 0);
+}
+
+static void tegra_clear_videomem_nonoverlap(uintptr_t phys_base,
+ unsigned long 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;
+
+ /*
+ * 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
+ */
+ 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);
+ }
+ }
+}
+
+/*
+ * 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)
+{
+ /*
+ * Setup the Memory controller to restrict CPU accesses to the Video
+ * Memory region
+ */
+
+ INFO("Configuring Video Memory Carveout\n");
+
+ if (video_mem_base != 0U) {
+ /*
+ * 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);
+ }
+
+ /* 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);
+
+ /* Redundancy check for Video Protect setting */
+ assert(tegra_mc_read_32(MC_VIDEO_PROTECT_BASE_LO)
+ == (uint32_t)phys_base);
+ assert(tegra_mc_read_32(MC_VIDEO_PROTECT_BASE_HI)
+ == (uint32_t)(phys_base >> 32));
+ assert(tegra_mc_read_32(MC_VIDEO_PROTECT_SIZE_MB)
+ == (size_in_bytes >> 20));
+
+ /*
+ * MCE propagates the VideoMem configuration values across the
+ * CCPLEX.
+ */
+ (void)mce_update_gsc_videomem();
+
+ /* Clear the non-overlapping memory */
+ if (video_mem_base != 0U) {
+ tegra_clear_videomem_nonoverlap(phys_base, size_in_bytes);
+ tegra_unlock_videomem_nonoverlap();
+ }
+
+ /* store new values */
+ video_mem_base = phys_base;
+ video_mem_size_mb = (uint64_t)size_in_bytes >> 20;
+}
+
+/*
+ * 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 */
+}
diff --git a/plat/nvidia/tegra/drivers/pmc/pmc.c b/plat/nvidia/tegra/drivers/pmc/pmc.c
new file mode 100644
index 0000000..6c5a73b
--- /dev/null
+++ b/plat/nvidia/tegra/drivers/pmc/pmc.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <pmc.h>
+#include <tegra_def.h>
+
+#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();
+}
diff --git a/plat/nvidia/tegra/drivers/smmu/smmu.c b/plat/nvidia/tegra/drivers/smmu/smmu.c
new file mode 100644
index 0000000..4189b00
--- /dev/null
+++ b/plat/nvidia/tegra/drivers/smmu/smmu.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+
+#include <smmu.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+extern void memcpy16(void *dest, const void *src, unsigned int length);
+
+#define SMMU_NUM_CONTEXTS 64U
+#define SMMU_CONTEXT_BANK_MAX_IDX 64U
+
+#define MISMATCH_DETECTED 0x55AA55AAU
+
+/*
+ * Init SMMU during boot or "System Suspend" exit
+ */
+void tegra_smmu_init(void)
+{
+ uint32_t val, cb_idx, smmu_id, ctx_base;
+ uint32_t num_smmu_devices = plat_get_num_smmu_devices();
+
+ for (smmu_id = 0U; smmu_id < num_smmu_devices; 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 = 0U; 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);
+ }
+}
+
+/*
+ * Verify SMMU settings have not been altered during boot
+ */
+void tegra_smmu_verify(void)
+{
+ uint32_t cb_idx, ctx_base, smmu_id, val;
+ uint32_t num_smmu_devices = plat_get_num_smmu_devices();
+ uint32_t mismatch = 0U;
+
+ for (smmu_id = 0U; smmu_id < num_smmu_devices; smmu_id++) {
+ /* check PGSIZE_64K bit inr S Aux. Config. Register */
+ val = tegra_smmu_read_32(smmu_id, SMMU_GSR0_SECURE_ACR);
+ if (0U == (val & SMMU_GSR0_PGSIZE_64K)) {
+ ERROR("%s: PGSIZE_64K Mismatch - smmu_id=%d, GSR0_SECURE_ACR=%x\n",
+ __func__, smmu_id, val);
+ mismatch = MISMATCH_DETECTED;
+ }
+
+ /* check CACHE LOCK bit in S Aux. Config. Register */
+ if (0U == (val & SMMU_ACR_CACHE_LOCK_ENABLE_BIT)) {
+ ERROR("%s: CACHE_LOCK Mismatch - smmu_id=%d, GSR0_SECURE_ACR=%x\n",
+ __func__, smmu_id, val);
+ mismatch = MISMATCH_DETECTED;
+ }
+
+ /* check CACHE LOCK bit in NS Aux. Config. Register */
+ val = tegra_smmu_read_32(smmu_id, SMMU_GNSR_ACR);
+ if (0U == (val & SMMU_ACR_CACHE_LOCK_ENABLE_BIT)) {
+ ERROR("%s: Mismatch - smmu_id=%d, GNSR_ACR=%x\n",
+ __func__, smmu_id, val);
+ mismatch = MISMATCH_DETECTED;
+ }
+
+ /* verify TCU prefetch for all contexts is disabled */
+ ctx_base = (SMMU_GSR0_PGSIZE_64K * SMMU_NUM_CONTEXTS) +
+ SMMU_CBn_ACTLR;
+ for (cb_idx = 0U; cb_idx < SMMU_CONTEXT_BANK_MAX_IDX; cb_idx++) {
+ val = tegra_smmu_read_32(smmu_id,
+ ctx_base + (SMMU_GSR0_PGSIZE_64K * cb_idx));
+ if (0U != (val & SMMU_CBn_ACTLR_CPRE_BIT)) {
+ ERROR("%s: Mismatch - smmu_id=%d, cb_idx=%d, GSR0_PGSIZE_64K=%x\n",
+ __func__, smmu_id, cb_idx, val);
+ mismatch = MISMATCH_DETECTED;
+ }
+ }
+ }
+
+ /* Treat configuration mismatch as fatal */
+ if ((mismatch == MISMATCH_DETECTED) && tegra_platform_is_silicon()) {
+ panic();
+ }
+}
diff --git a/plat/nvidia/tegra/drivers/spe/shared_console.S b/plat/nvidia/tegra/drivers/spe/shared_console.S
new file mode 100644
index 0000000..d1b18dd
--- /dev/null
+++ b/plat/nvidia/tegra/drivers/spe/shared_console.S
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console_macros.S>
+
+#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_TIMEOUT 0xC000 /* 50 ms */
+
+ /*
+ * 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
+
+.macro check_if_console_is_ready base, tmp1, tmp2, label
+ /* wait until spe is ready or timeout expires */
+ mrs \tmp2, cntps_tval_el1
+1: ldr \tmp1, [\base]
+ and \tmp1, \tmp1, #CONSOLE_IS_BUSY
+ cbz \tmp1, 2f
+ mrs \tmp1, cntps_tval_el1
+ sub \tmp1, \tmp2, \tmp1
+ cmp \tmp1, #CONSOLE_TIMEOUT
+ b.lt 1b
+ b \label
+2:
+.endm
+
+ /* -------------------------------------------------
+ * int console_spe_register(uintptr_t baseaddr,
+ * uint32_t clock, uint32_t baud,
+ * console_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_t struct
+ * Out: return 1 on success, 0 on error
+ * Clobber list : x0, x1, x2, x6, x7, x14
+ * -------------------------------------------------
+ */
+func console_spe_register
+ /* Check the input base address */
+ cbz x0, register_fail
+
+ /* Dont use clock or baud rate, so ok to overwrite them */
+ check_if_console_is_ready x0, x1, x2, register_fail
+
+ cbz x3, register_fail
+ str x0, [x3, #CONSOLE_T_BASE]
+ 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, x3
+ * --------------------------------------------------------
+ */
+func console_spe_core_putc
+ /* Check the input parameter */
+ cbz x1, putc_error
+
+ /* Prepend '\r' to '\n' */
+ cmp w0, #0xA
+ b.ne not_eol
+
+ check_if_console_is_ready x1, x2, x3, putc_error
+
+ /* spe is ready */
+ mov w2, #0xD /* '\r' */
+ and w2, w2, #0xFF
+ mov w3, #(CONSOLE_RING_DOORBELL | (1 << CONSOLE_NUM_BYTES_SHIFT))
+ orr w2, w2, w3
+ str w2, [x1]
+
+not_eol:
+ check_if_console_is_ready x1, x2, x3, putc_error
+
+ /* spe is ready */
+ mov w2, w0
+ and w2, w2, #0xFF
+ mov w3, #(CONSOLE_RING_DOORBELL | (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_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_BASE]
+ b console_spe_core_putc
+endfunc console_spe_putc
+
+ /* ---------------------------------------------
+ * int console_spe_getc(console_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
+
+ /* -------------------------------------------------
+ * void 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 : void.
+ * Clobber list : x0, x1
+ * -------------------------------------------------
+ */
+func console_spe_core_flush
+#if ENABLE_ASSERTIONS
+ cmp x0, #0
+ ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
+ /* flush console */
+ mov w1, #(CONSOLE_RING_DOORBELL | CONSOLE_FLUSH_DATA_TO_PORT)
+ str w1, [x0]
+ ret
+endfunc console_spe_core_flush
+
+ /* ---------------------------------------------
+ * void console_spe_flush(console_t *console)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * In : x0 - pointer to console_t structure
+ * Out : void.
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func console_spe_flush
+ ldr x0, [x0, #CONSOLE_T_BASE]
+ b console_spe_core_flush
+endfunc console_spe_flush
diff --git a/plat/nvidia/tegra/include/drivers/bpmp.h b/plat/nvidia/tegra/include/drivers/bpmp.h
new file mode 100644
index 0000000..dc3fb6b
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/bpmp.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BPMP_H
+#define BPMP_H
+
+#include <stdint.h>
+
+/* 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 */
diff --git a/plat/nvidia/tegra/include/drivers/bpmp_ipc.h b/plat/nvidia/tegra/include/drivers/bpmp_ipc.h
new file mode 100644
index 0000000..401a07a
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/bpmp_ipc.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BPMP_IPC_H
+#define BPMP_IPC_H
+
+#include <lib/utils_def.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+/**
+ * Currently supported reset identifiers
+ */
+#define TEGRA_RESET_ID_XUSB_PADCTL U(114)
+#define TEGRA_RESET_ID_GPCDMA U(70)
+
+/**
+ * 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 */
diff --git a/plat/nvidia/tegra/include/drivers/flowctrl.h b/plat/nvidia/tegra/include/drivers/flowctrl.h
new file mode 100644
index 0000000..e5ab600
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/flowctrl.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FLOWCTRL_H
+#define FLOWCTRL_H
+
+#include <lib/mmio.h>
+
+#include <stdbool.h>
+
+#include <tegra_def.h>
+
+#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 */
diff --git a/plat/nvidia/tegra/include/drivers/gpcdma.h b/plat/nvidia/tegra/include/drivers/gpcdma.h
new file mode 100644
index 0000000..a59df37
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/gpcdma.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GPCDMA_H
+#define GPCDMA_H
+
+#include <stdint.h>
+
+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 */
diff --git a/plat/nvidia/tegra/include/drivers/mce.h b/plat/nvidia/tegra/include/drivers/mce.h
new file mode 100644
index 0000000..5f1bb4f
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/mce.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MCE_H
+#define MCE_H
+
+#include <lib/mmio.h>
+
+#include <tegra_def.h>
+
+/*******************************************************************************
+ * 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);
+__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 */
diff --git a/plat/nvidia/tegra/include/drivers/memctrl.h b/plat/nvidia/tegra/include/drivers/memctrl.h
new file mode 100644
index 0000000..cc85095
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/memctrl.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. 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_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 */
diff --git a/plat/nvidia/tegra/include/drivers/memctrl_v1.h b/plat/nvidia/tegra/include/drivers/memctrl_v1.h
new file mode 100644
index 0000000..8e9f198
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/memctrl_v1.h
@@ -0,0 +1,57 @@
+/*
+ * 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 <lib/mmio.h>
+
+#include <tegra_def.h>
+
+/* 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 */
diff --git a/plat/nvidia/tegra/include/drivers/memctrl_v2.h b/plat/nvidia/tegra/include/drivers/memctrl_v2.h
new file mode 100644
index 0000000..9af3027
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/memctrl_v2.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MEMCTRL_V2_H
+#define MEMCTRL_V2_H
+
+#include <arch.h>
+
+#include <tegra_def.h>
+
+/*******************************************************************************
+ * 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)
+
+#ifndef __ASSEMBLER__
+
+#include <assert.h>
+
+typedef struct mc_regs {
+ uint32_t reg;
+ uint32_t val;
+} mc_regs_t;
+
+#define mc_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, \
+ }
+
+#endif /* __ASSEMBLER__ */
+
+#ifndef __ASSEMBLER__
+
+#include <lib/mmio.h>
+
+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);
+}
+
+#if defined(TEGRA_MC_STREAMID_BASE)
+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);
+ assert(mmio_read_32(TEGRA_MC_STREAMID_BASE + off) == val);
+}
+#endif
+
+void plat_memctrl_setup(void);
+
+void plat_memctrl_restore(void);
+mc_regs_t *plat_memctrl_get_sys_suspend_ctx(void);
+
+/*******************************************************************************
+ * Handler to save MC settings before "System Suspend" to TZDRAM
+ *
+ * Implemented by Tegra common memctrl_v2 driver under common/drivers/memctrl
+ ******************************************************************************/
+void tegra_mc_save_context(uint64_t mc_ctx_addr);
+
+/*******************************************************************************
+ * 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 */
diff --git a/plat/nvidia/tegra/include/drivers/pmc.h b/plat/nvidia/tegra/include/drivers/pmc.h
new file mode 100644
index 0000000..8752b84
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/pmc.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMC_H
+#define PMC_H
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <stdbool.h>
+
+#include <tegra_def.h>
+
+#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_SCRATCH1 U(0x54)
+#define PMC_CRYPTO_OP_0 U(0xf4)
+#define PMC_TOGGLE_START U(0x100)
+#define PMC_SCRATCH31 U(0x118)
+#define PMC_SCRATCH32 U(0x11C)
+#define PMC_SCRATCH33 U(0x120)
+#define PMC_SCRATCH39 U(0x138)
+#define PMC_SCRATCH40 U(0x13C)
+#define PMC_SCRATCH41 U(0x140)
+#define PMC_SCRATCH42 U(0x144)
+#define PMC_SCRATCH43 U(0x22C)
+#define PMC_SCRATCH44 U(0x230)
+#define PMC_SCRATCH45 U(0x234)
+#define PMC_SCRATCH46 U(0x238)
+#define PMC_SCRATCH47 U(0x23C)
+#define PMC_SCRATCH48 U(0x240)
+#define PMC_SCRATCH50 U(0x248)
+#define PMC_SCRATCH51 U(0x24C)
+#define PMC_TSC_MULT_0 U(0x2B4)
+#define PMC_STICKY_BIT U(0x2C0)
+#define PMC_SECURE_DISABLE2 U(0x2C4)
+#define PMC_SECURE_DISABLE2_WRITE22_ON (U(1) << 28)
+#define PMC_FUSE_CONTROL_0 U(0x450)
+#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_SCRATCH22 U(0x338)
+#define PMC_SECURE_SCRATCH34 U(0x368)
+#define PMC_SECURE_SCRATCH35 U(0x36c)
+#define PMC_SCRATCH56 U(0x600)
+#define PMC_SCRATCH57 U(0x604)
+#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 */
diff --git a/plat/nvidia/tegra/include/drivers/security_engine.h b/plat/nvidia/tegra/include/drivers/security_engine.h
new file mode 100644
index 0000000..5ae6257
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/security_engine.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2020, 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);
+int32_t tegra_se_save_sha256_hash(uint64_t bl31_base, uint32_t src_len_inbyte);
+
+#endif /* SECURITY_ENGINE_H */
diff --git a/plat/nvidia/tegra/include/drivers/smmu.h b/plat/nvidia/tegra/include/drivers/smmu.h
new file mode 100644
index 0000000..1de9af6
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/smmu.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SMMU_H
+#define SMMU_H
+
+#include <lib/mmio.h>
+
+#include <memctrl_v2.h>
+#include <tegra_def.h>
+
+#define SMMU_CBn_ACTLR (0x4U)
+
+/*******************************************************************************
+ * 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 (1ULL << 26U)
+#define SMMU_GSR0_PER (0x20200U)
+
+/*******************************************************************************
+ * SMMU Global Aux. Control Register
+ ******************************************************************************/
+#define SMMU_CBn_ACTLR_CPRE_BIT (1ULL << 1U)
+
+/* SMMU IDs currently supported by the driver */
+enum {
+ TEGRA_SMMU0 = 0U,
+ TEGRA_SMMU1 = 1U,
+ TEGRA_SMMU2 = 2U
+};
+
+static inline 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 inline 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
+}
+
+void tegra_smmu_init(void);
+void tegra_smmu_verify(void);
+uint32_t plat_get_num_smmu_devices(void);
+
+#endif /* SMMU_H */
diff --git a/plat/nvidia/tegra/include/drivers/spe.h b/plat/nvidia/tegra/include/drivers/spe.h
new file mode 100644
index 0000000..e0f8714
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/spe.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPE_H
+#define SPE_H
+
+#include <stdint.h>
+
+#include <drivers/console.h>
+
+/*
+ * Initialize a new spe 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_spe_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
+ console_t *console);
+
+#endif /* SPE_H */
diff --git a/plat/nvidia/tegra/include/drivers/tegra_gic.h b/plat/nvidia/tegra/include/drivers/tegra_gic.h
new file mode 100644
index 0000000..6661dff
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/tegra_gic.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEGRA_GIC_H
+#define TEGRA_GIC_H
+
+#include <common/interrupt_props.h>
+
+/*******************************************************************************
+ * 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 */
diff --git a/plat/nvidia/tegra/include/lib/profiler.h b/plat/nvidia/tegra/include/lib/profiler.h
new file mode 100644
index 0000000..684c872
--- /dev/null
+++ b/plat/nvidia/tegra/include/lib/profiler.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. 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 */
diff --git a/plat/nvidia/tegra/include/plat_macros.S b/plat/nvidia/tegra/include/plat_macros.S
new file mode 100644
index 0000000..2dc3b41
--- /dev/null
+++ b/plat/nvidia/tegra/include/plat_macros.S
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <drivers/arm/gicv2.h>
+#include <tegra_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 BL31.
+ * ---------------------------------------------
+ */
+.macro plat_crash_print_regs
+#ifdef TEGRA_GICC_BASE
+ 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
+#endif
+ /* 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 */
diff --git a/plat/nvidia/tegra/include/platform_def.h b/plat/nvidia/tegra/include/platform_def.h
new file mode 100644
index 0000000..84b3297
--- /dev/null
+++ b/plat/nvidia/tegra/include/platform_def.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <lib/utils_def.h>
+
+#include <tegra_def.h>
+
+/*******************************************************************************
+ * Check and error if SEPARATE_CODE_AND_RODATA is not set to 1
+ ******************************************************************************/
+#if !SEPARATE_CODE_AND_RODATA
+#error "SEPARATE_CODE_AND_RODATA should be set to 1"
+#endif
+
+/*
+ * Platform binary types for linking
+ */
+#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH aarch64
+
+/*
+ * 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 + U(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_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)
+
+/*******************************************************************************
+ * Platforms macros to support SDEI
+ ******************************************************************************/
+#define TEGRA_SDEI_SGI_PRIVATE U(8)
+
+/*******************************************************************************
+ * Platform macros to support exception handling framework
+ ******************************************************************************/
+#define PLAT_PRI_BITS U(3)
+#define PLAT_RAS_PRI U(0x10)
+#define PLAT_SDEI_CRITICAL_PRI U(0x20)
+#define PLAT_SDEI_NORMAL_PRI U(0x30)
+#define PLAT_TEGRA_WDT_PRIO U(0x40)
+
+#define PLAT_EHF_DESC EHF_PRI_DESC(PLAT_PRI_BITS,\
+ PLAT_TEGRA_WDT_PRIO)
+
+/*******************************************************************************
+ * SDEI events
+ ******************************************************************************/
+/* SDEI dynamic private event numbers */
+#define TEGRA_SDEI_DP_EVENT_0 U(100)
+#define TEGRA_SDEI_DP_EVENT_1 U(101)
+#define TEGRA_SDEI_DP_EVENT_2 U(102)
+
+/* SDEI dynamic shared event numbers */
+#define TEGRA_SDEI_DS_EVENT_0 U(200)
+#define TEGRA_SDEI_DS_EVENT_1 U(201)
+#define TEGRA_SDEI_DS_EVENT_2 U(202)
+
+/* SDEI explicit events */
+#define TEGRA_SDEI_EP_EVENT_0 U(300)
+#define TEGRA_SDEI_EP_EVENT_1 U(301)
+#define TEGRA_SDEI_EP_EVENT_2 U(302)
+#define TEGRA_SDEI_EP_EVENT_3 U(303)
+#define TEGRA_SDEI_EP_EVENT_4 U(304)
+#define TEGRA_SDEI_EP_EVENT_5 U(305)
+#define TEGRA_SDEI_EP_EVENT_6 U(306)
+#define TEGRA_SDEI_EP_EVENT_7 U(307)
+#define TEGRA_SDEI_EP_EVENT_8 U(308)
+#define TEGRA_SDEI_EP_EVENT_9 U(309)
+#define TEGRA_SDEI_EP_EVENT_10 U(310)
+#define TEGRA_SDEI_EP_EVENT_11 U(311)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/nvidia/tegra/include/t186/tegra186_private.h b/plat/nvidia/tegra/include/t186/tegra186_private.h
new file mode 100644
index 0000000..4514e14
--- /dev/null
+++ b/plat/nvidia/tegra/include/t186/tegra186_private.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEGRA186_PRIVATE_H
+#define TEGRA186_PRIVATE_H
+
+uint64_t tegra186_get_mc_ctx_size(void);
+
+#endif /* TEGRA186_PRIVATE_H */
diff --git a/plat/nvidia/tegra/include/t186/tegra_def.h b/plat/nvidia/tegra/include/t186/tegra_def.h
new file mode 100644
index 0000000..a971cec
--- /dev/null
+++ b/plat/nvidia/tegra/include/t186/tegra_def.h
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEGRA_DEF_H
+#define TEGRA_DEF_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * Platform BL31 specific defines.
+ ******************************************************************************/
+#define BL31_SIZE U(0x40000)
+
+/*******************************************************************************
+ * 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 */
+
+/*******************************************************************************
+ * Clock identifier for the SE device
+ ******************************************************************************/
+#define TEGRA186_CLK_SE U(103)
+#define TEGRA_CLK_SE TEGRA186_CLK_SE
+
+/*******************************************************************************
+ * 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)
+#define MC_VIDEO_PROTECT_REG_CTRL U(0x650)
+#define MC_VIDEO_PROTECT_WRITE_ACCESS_ENABLED U(3)
+
+/*
+ * 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 HSP doorbell #0 constants
+ ******************************************************************************/
+#define TEGRA_HSP_DBELL_BASE U(0x03C90000)
+#define HSP_DBELL_1_ENABLE U(0x104)
+#define HSP_DBELL_3_TRIGGER U(0x300)
+#define HSP_DBELL_3_ENABLE U(0x304)
+
+/*******************************************************************************
+ * 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_RSV0_HI U(0x654)
+#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 SECURE_SCRATCH_RSV63_LO U(0x848)
+#define SECURE_SCRATCH_RSV63_HI U(0x84C)
+#define SECURE_SCRATCH_RSV64_LO U(0x850)
+#define SECURE_SCRATCH_RSV64_HI U(0x854)
+#define SECURE_SCRATCH_RSV65_LO U(0x858)
+#define SECURE_SCRATCH_RSV65_HI U(0x85c)
+#define SECURE_SCRATCH_RSV66_LO U(0x860)
+#define SECURE_SCRATCH_RSV66_HI U(0x864)
+#define SECURE_SCRATCH_RSV68_LO U(0x870)
+
+#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_MC_TABLE_ADDR_LO SECURE_SCRATCH_RSV11_LO
+#define SCRATCH_MC_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)
+
+/*******************************************************************************
+ * Tegra CCPLEX-BPMP IPC constants
+ ******************************************************************************/
+#define TEGRA_BPMP_IPC_TX_PHYS_BASE U(0x3004C000)
+#define TEGRA_BPMP_IPC_RX_PHYS_BASE U(0x3004D000)
+#define TEGRA_BPMP_IPC_CH_MAP_SIZE U(0x1000) /* 4KB */
+
+/*******************************************************************************
+ * Tegra DRAM memory base address
+ ******************************************************************************/
+#define TEGRA_DRAM_BASE ULL(0x80000000)
+#define TEGRA_DRAM_END ULL(0x27FFFFFFF)
+
+#endif /* TEGRA_DEF_H */
diff --git a/plat/nvidia/tegra/include/t186/tegra_mc_def.h b/plat/nvidia/tegra/include/t186/tegra_mc_def.h
new file mode 100644
index 0000000..fa44772
--- /dev/null
+++ b/plat/nvidia/tegra/include/t186/tegra_mc_def.h
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2017-2020, 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
+
+#ifndef __ASSEMBLER__
+
+/*******************************************************************************
+ * 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;
+ uint32_t override_enable;
+ uint32_t override_client_inputs;
+ uint32_t 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
+
+#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 \
+ }
+
+#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 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) \
+ do { \
+ 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); \
+ } while (0)
+
+#define mc_set_tsa_w_passthrough(client) \
+ do { \
+ 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); \
+ } while (0)
+
+#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); \
+ } while (0)
+
+#define mc_set_txn_override(client, normal_axi_id, so_dev_axi_id, normal_override, so_dev_override) \
+ do { \
+ 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); \
+ } while (0)
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* TEGRA_MC_DEF_H */
diff --git a/plat/nvidia/tegra/include/t194/tegra194_private.h b/plat/nvidia/tegra/include/t194/tegra194_private.h
new file mode 100644
index 0000000..c5a51e9
--- /dev/null
+++ b/plat/nvidia/tegra/include/t194/tegra194_private.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEGRA194_PRIVATE_H
+#define TEGRA194_PRIVATE_H
+
+void tegra194_cpu_reset_handler(void);
+uint64_t tegra194_get_cpu_reset_handler_base(void);
+uint64_t tegra194_get_cpu_reset_handler_size(void);
+uint64_t tegra194_get_mc_ctx_offset(void);
+void tegra194_set_system_suspend_entry(void);
+
+#endif /* TEGRA194_PRIVATE_H */
diff --git a/plat/nvidia/tegra/include/t194/tegra194_ras_private.h b/plat/nvidia/tegra/include/t194/tegra194_ras_private.h
new file mode 100644
index 0000000..336461a
--- /dev/null
+++ b/plat/nvidia/tegra/include/t194/tegra194_ras_private.h
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEGRA194_RAS_PRIVATE
+#define TEGRA194_RAS_PRIVATE
+
+#include <stdint.h>
+
+/* Implementation defined RAS error and corresponding error message */
+struct ras_error {
+ const char *error_msg;
+ /* IERR(bits[15:8]) from ERR<n>STATUS */
+ uint8_t error_code;
+};
+
+/* RAS error node-specific auxiliary data */
+struct ras_aux_data {
+ /* name for current RAS node. */
+ const char *name;
+ /* point to null-terminated ras_error array to convert error code to msg. */
+ const struct ras_error *error_records;
+ /*
+ * function to return an value which needs to be programmed into ERXCTLR_EL1
+ * to enable all specified RAS errors for current node.
+ */
+ uint64_t (*err_ctrl)(void);
+};
+
+/* IFU Uncorrectable RAS ERROR */
+#define IFU_UNCORR_RAS_ERROR_LIST(X)
+
+/* JSR_RET Uncorrectable RAS ERROR */
+#define JSR_RET_UNCORR_RAS_ERROR_LIST(X) \
+ /* Name, ERR_CTRL, IERR, ISA Desc */ \
+ X(JSR_RET, 35, 0x13, "Floating Point Register File Parity Error") \
+ X(JSR_RET, 34, 0x12, "Integer Register File Parity Error") \
+ X(JSR_RET, 33, 0x11, "Garbage Bundle") \
+ X(JSR_RET, 32, 0x10, "Bundle Completion Timeout")
+
+/* JSR_MTS Uncorrectable RAS ERROR */
+#define JSR_MTS_UNCORR_RAS_ERROR_LIST(X) \
+ /* Name, ERR_CTRL, IERR, ISA Desc */ \
+ X(JSR_MTS, 40, 0x28, "CoreSight Access Error") \
+ X(JSR_MTS, 39, 0x27, "Dual Execution Uncorrectable Error") \
+ X(JSR_MTS, 37, 0x25, "CTU MMIO Region") \
+ X(JSR_MTS, 36, 0x24, "MTS MMCRAB Region Access") \
+ X(JSR_MTS, 35, 0x23, "MTS_CARVEOUT Access from ARM SW") \
+ X(JSR_MTS, 34, 0x22, "NAFLL PLL Failure to Lock") \
+ X(JSR_MTS, 32, 0x20, "Internal Uncorrectable MTS Error")
+
+/* LSD_STQ Uncorrectable RAS ERROR */
+#define LSD_STQ_UNCORR_RAS_ERROR_LIST(X) \
+ /* Name, ERR_CTRL, IERR, ISA Desc */ \
+ X(LSD_STQ, 41, 0x39, "Coherent Cache Data Store Multi-Line ECC Error") \
+ X(LSD_STQ, 40, 0x38, "Coherent Cache Data Store Uncorrectable ECC Error") \
+ X(LSD_STQ, 38, 0x36, "Coherent Cache Data Load Uncorrectable ECC Error") \
+ X(LSD_STQ, 33, 0x31, "Coherent Cache Tag Store Parity Error") \
+ X(LSD_STQ, 32, 0x30, "Coherent Cache Tag Load Parity Error")
+
+/* LSD_DCC Uncorrectable RAS ERROR */
+#define LSD_DCC_UNCORR_RAS_ERROR_LIST(X) \
+ /* Name, ERR_CTRL, IERR, ISA Desc */ \
+ X(LSD_DCC, 41, 0x49, "BTU Copy Mini-Cache PPN Multi-Hit Error") \
+ X(LSD_DCC, 39, 0x47, "Coherent Cache Data Uncorrectable ECC Error") \
+ X(LSD_DCC, 37, 0x45, "Version Cache Byte-Enable Parity Error") \
+ X(LSD_DCC, 36, 0x44, "Version Cache Data Uncorrectable ECC Error") \
+ X(LSD_DCC, 33, 0x41, "BTU Copy Coherent Cache PPN Parity Error") \
+ X(LSD_DCC, 32, 0x40, "BTU Copy Coherent Cache VPN Parity Error")
+
+/* LSD_L1HPF Uncorrectable RAS ERROR */
+#define LSD_L1HPF_UNCORR_RAS_ERROR_LIST(X)
+
+/* L2 Uncorrectable RAS ERROR */
+#define L2_UNCORR_RAS_ERROR_LIST(X) \
+ /* Name, ERR_CTRL, IERR, ISA Desc */ \
+ X(L2, 56, 0x68, "URT Timeout") \
+ X(L2, 55, 0x67, "L2 Protocol Violation") \
+ X(L2, 54, 0x66, "SCF to L2 Slave Error Read") \
+ X(L2, 53, 0x65, "SCF to L2 Slave Error Write") \
+ X(L2, 52, 0x64, "SCF to L2 Decode Error Read") \
+ X(L2, 51, 0x63, "SCF to L2 Decode Error Write") \
+ X(L2, 50, 0x62, "SCF to L2 Request Response Interface Parity Errors") \
+ X(L2, 49, 0x61, "SCF to L2 Advance notice interface parity errors") \
+ X(L2, 48, 0x60, "SCF to L2 Filldata Parity Errors") \
+ X(L2, 47, 0x5F, "SCF to L2 UnCorrectable ECC Data Error on interface") \
+ X(L2, 45, 0x5D, "Core 1 to L2 Parity Error") \
+ X(L2, 44, 0x5C, "Core 0 to L2 Parity Error") \
+ X(L2, 43, 0x5B, "L2 Multi-Hit") \
+ X(L2, 42, 0x5A, "L2 URT Tag Parity Error") \
+ X(L2, 41, 0x59, "L2 NTT Tag Parity Error") \
+ X(L2, 40, 0x58, "L2 MLT Tag Parity Error") \
+ X(L2, 39, 0x57, "L2 URD Data") \
+ X(L2, 38, 0x56, "L2 NTP Data") \
+ X(L2, 36, 0x54, "L2 MLC Uncorrectable Clean") \
+ X(L2, 35, 0x53, "L2 URD Uncorrectable Dirty") \
+ X(L2, 34, 0x52, "L2 MLC Uncorrectable Dirty")
+
+/* CLUSTER_CLOCKS Uncorrectable RAS ERROR */
+#define CLUSTER_CLOCKS_UNCORR_RAS_ERROR_LIST(X) \
+ /* Name, ERR_CTRL, IERR, ISA Desc */ \
+ X(CLUSTER_CLOCKS, 32, 0xE4, "Frequency Monitor Error")
+
+/* MMU Uncorrectable RAS ERROR */
+#define MMU_UNCORR_RAS_ERROR_LIST(X)
+
+/* L3 Uncorrectable RAS ERROR */
+#define L3_UNCORR_RAS_ERROR_LIST(X) \
+ /* Name, ERR_CTRL, IERR, ISA Desc */ \
+ X(L3, 43, 0x7B, "SNOC Interface Parity Error") \
+ X(L3, 42, 0x7A, "MCF Interface Parity Error") \
+ X(L3, 41, 0x79, "L3 Tag Parity Error") \
+ X(L3, 40, 0x78, "L3 Dir Parity Error") \
+ X(L3, 39, 0x77, "L3 Uncorrectable ECC Error") \
+ X(L3, 37, 0x75, "Multi-Hit CAM Error") \
+ X(L3, 36, 0x74, "Multi-Hit Tag Error") \
+ X(L3, 35, 0x73, "Unrecognized Command Error") \
+ X(L3, 34, 0x72, "L3 Protocol Error")
+
+/* CCPMU Uncorrectable RAS ERROR */
+#define CCPMU_UNCORR_RAS_ERROR_LIST(X) \
+ /* Name, ERR_CTRL, IERR, ISA Desc */ \
+ X(CCPMU, 40, 0x87, "CoreSight Access Error") \
+ X(CCPMU, 36, 0x84, "MCE Ucode Error") \
+ X(CCPMU, 35, 0x83, "MCE IL1 Parity Error") \
+ X(CCPMU, 34, 0x82, "MCE Timeout Error") \
+ X(CCPMU, 33, 0x81, "CRAB Access Error") \
+ X(CCPMU, 32, 0x80, "MCE Memory Access Error")
+
+/* SCF_IOB Uncorrectable RAS ERROR */
+#define SCF_IOB_UNCORR_RAS_ERROR_LIST(X) \
+ /* Name, ERR_CTRL, IERR, ISA Desc */ \
+ X(SCF_IOB, 41, 0x99, "Request parity error") \
+ X(SCF_IOB, 40, 0x98, "Putdata parity error") \
+ X(SCF_IOB, 39, 0x97, "Uncorrectable ECC on Putdata") \
+ X(SCF_IOB, 38, 0x96, "CBB Interface Error") \
+ X(SCF_IOB, 37, 0x95, "MMCRAB Error") \
+ X(SCF_IOB, 36, 0x94, "IHI Interface Error") \
+ X(SCF_IOB, 35, 0x93, "CRI Error") \
+ X(SCF_IOB, 34, 0x92, "TBX Interface Error") \
+ X(SCF_IOB, 33, 0x91, "EVP Interface Error")
+
+/* SCF_SNOC Uncorrectable RAS ERROR */
+#define SCF_SNOC_UNCORR_RAS_ERROR_LIST(X) \
+ /* Name, ERR_CTRL, IERR, ISA Desc */ \
+ X(SCF_SNOC, 42, 0xAA, "Misc Client Parity Error") \
+ X(SCF_SNOC, 41, 0xA9, "Misc Filldata Parity Error") \
+ X(SCF_SNOC, 40, 0xA8, "Uncorrectable ECC Misc Client") \
+ X(SCF_SNOC, 39, 0xA7, "DVMU Interface Parity Error") \
+ X(SCF_SNOC, 38, 0xA6, "DVMU Interface Timeout Error") \
+ X(SCF_SNOC, 37, 0xA5, "CPE Request Error") \
+ X(SCF_SNOC, 36, 0xA4, "CPE Response Error") \
+ X(SCF_SNOC, 35, 0xA3, "CPE Timeout Error") \
+ X(SCF_SNOC, 34, 0xA2, "Uncorrectable Carveout Error")
+
+/* SCF_CTU Uncorrectable RAS ERROR */
+#define SCF_CTU_UNCORR_RAS_ERROR_LIST(X) \
+ /* Name, ERR_CTRL, IERR, ISA Desc */ \
+ X(SCF_CTU, 39, 0xB7, "Timeout error for TRC_DMA request") \
+ X(SCF_CTU, 38, 0xB6, "Timeout error for CTU Snp") \
+ X(SCF_CTU, 37, 0xB5, "Parity error in CTU TAG RAM") \
+ X(SCF_CTU, 36, 0xB3, "Parity error in CTU DATA RAM") \
+ X(SCF_CTU, 35, 0xB4, "Parity error for Cluster Rsp") \
+ X(SCF_CTU, 34, 0xB2, "Parity error for TRL requests from 9 agents") \
+ X(SCF_CTU, 33, 0xB1, "Parity error for MCF request") \
+ X(SCF_CTU, 32, 0xB0, "TRC DMA fillsnoop parity error")
+
+/* CMU_CLOCKS Uncorrectable RAS ERROR */
+#define CMU_CLOCKS_UNCORR_RAS_ERROR_LIST(X) \
+ /* Name, ERR_CTRL, IERR, ISA Desc */ \
+ X(CMU_CLOCKS, 39, 0xC7, "Cluster 3 frequency monitor error") \
+ X(CMU_CLOCKS, 38, 0xC6, "Cluster 2 frequency monitor error") \
+ X(CMU_CLOCKS, 37, 0xC5, "Cluster 1 frequency monitor error") \
+ X(CMU_CLOCKS, 36, 0xC3, "Cluster 0 frequency monitor error") \
+ X(CMU_CLOCKS, 35, 0xC4, "Voltage error on ADC1 Monitored Logic") \
+ X(CMU_CLOCKS, 34, 0xC2, "Voltage error on ADC0 Monitored Logic") \
+ X(CMU_CLOCKS, 33, 0xC1, "Lookup Table 1 Parity Error") \
+ X(CMU_CLOCKS, 32, 0xC0, "Lookup Table 0 Parity Error")
+
+/*
+ * Define one ras_error entry.
+ *
+ * This macro wille be used to to generate ras_error records for each node
+ * defined by <NODE_NAME>_UNCORR_RAS_ERROR_LIST macro.
+ */
+#define DEFINE_ONE_RAS_ERROR_MSG(unit, ras_bit, ierr, msg) \
+ { \
+ .error_msg = (msg), \
+ .error_code = (ierr) \
+ },
+
+/*
+ * Set one implementation defined bit in ERR<n>CTLR
+ *
+ * This macro will be used to collect all defined ERR_CTRL bits for each node
+ * defined by <NODE_NAME>_UNCORR_RAS_ERROR_LIST macro.
+ */
+#define DEFINE_ENABLE_RAS_BIT(unit, ras_bit, ierr, msg) \
+ do { \
+ val |= (1ULL << ras_bit##U); \
+ } while (0);
+
+/* Represent one RAS node with 0 or more error bits (ERR_CTLR) enabled */
+#define DEFINE_ONE_RAS_NODE(node) \
+static const struct ras_error node##_uncorr_ras_errors[] = { \
+ node##_UNCORR_RAS_ERROR_LIST(DEFINE_ONE_RAS_ERROR_MSG) \
+ { \
+ NULL, \
+ 0U \
+ }, \
+}; \
+static inline uint64_t node##_err_ctrl(void) \
+{ \
+ uint64_t val = 0ULL; \
+ node##_UNCORR_RAS_ERROR_LIST(DEFINE_ENABLE_RAS_BIT) \
+ return val; \
+}
+
+#define DEFINE_ONE_RAS_AUX_DATA(node) \
+ { \
+ .name = #node, \
+ .error_records = node##_uncorr_ras_errors, \
+ .err_ctrl = &node##_err_ctrl \
+ },
+
+#define PER_CORE_RAS_NODE_LIST(X) \
+ X(IFU) \
+ X(JSR_RET) \
+ X(JSR_MTS) \
+ X(LSD_STQ) \
+ X(LSD_DCC) \
+ X(LSD_L1HPF)
+
+#define PER_CORE_RAS_GROUP_NODES PER_CORE_RAS_NODE_LIST(DEFINE_ONE_RAS_AUX_DATA)
+
+#define PER_CLUSTER_RAS_NODE_LIST(X) \
+ X(L2) \
+ X(CLUSTER_CLOCKS) \
+ X(MMU)
+
+#define PER_CLUSTER_RAS_GROUP_NODES PER_CLUSTER_RAS_NODE_LIST(DEFINE_ONE_RAS_AUX_DATA)
+
+#define SCF_L3_BANK_RAS_NODE_LIST(X) X(L3)
+
+/* we have 4 SCF_L3 nodes:3*256 + L3_Bank_ID(0-3) */
+#define SCF_L3_BANK_RAS_GROUP_NODES \
+ SCF_L3_BANK_RAS_NODE_LIST(DEFINE_ONE_RAS_AUX_DATA) \
+ SCF_L3_BANK_RAS_NODE_LIST(DEFINE_ONE_RAS_AUX_DATA) \
+ SCF_L3_BANK_RAS_NODE_LIST(DEFINE_ONE_RAS_AUX_DATA) \
+ SCF_L3_BANK_RAS_NODE_LIST(DEFINE_ONE_RAS_AUX_DATA)
+
+#define CCPLEX_RAS_NODE_LIST(X) \
+ X(CCPMU) \
+ X(SCF_IOB) \
+ X(SCF_SNOC) \
+ X(SCF_CTU) \
+ X(CMU_CLOCKS)
+
+#define CCPLEX_RAS_GROUP_NODES CCPLEX_RAS_NODE_LIST(DEFINE_ONE_RAS_AUX_DATA)
+
+#endif /* TEGRA194_RAS_PRIVATE */
diff --git a/plat/nvidia/tegra/include/t194/tegra_def.h b/plat/nvidia/tegra/include/t194/tegra_def.h
new file mode 100644
index 0000000..abe193f
--- /dev/null
+++ b/plat/nvidia/tegra/include/t194/tegra_def.h
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEGRA_DEF_H
+#define TEGRA_DEF_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * Platform BL31 specific defines.
+ ******************************************************************************/
+#define BL31_SIZE U(0x40000)
+
+/*******************************************************************************
+ * Chip specific cluster and cpu numbers
+ ******************************************************************************/
+#define PLATFORM_CLUSTER_COUNT U(4)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER U(2)
+
+/*******************************************************************************
+ * Chip specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 40)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 40)
+
+/*******************************************************************************
+ * 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)
+
+/*******************************************************************************
+ * Secure IRQ definitions
+ ******************************************************************************/
+#define TEGRA194_MAX_SEC_IRQS U(2)
+#define TEGRA194_TOP_WDT_IRQ U(49)
+#define TEGRA194_AON_WDT_IRQ U(50)
+
+#define TEGRA194_SEC_IRQ_TARGET_MASK U(0xFF) /* 8 Carmel */
+
+/*******************************************************************************
+ * Clock identifier for the SE device
+ ******************************************************************************/
+#define TEGRA194_CLK_SE U(124)
+#define TEGRA_CLK_SE TEGRA194_CLK_SE
+
+/*******************************************************************************
+ * Tegra Miscellanous register constants
+ ******************************************************************************/
+#define TEGRA_MISC_BASE U(0x00100000)
+
+#define HARDWARE_REVISION_OFFSET U(0x4)
+#define MISCREG_EMU_REVID U(0x3160)
+#define BOARD_MASK_BITS U(0xFF)
+#define BOARD_SHIFT_BITS U(24)
+#define MISCREG_PFCFG U(0x200C)
+
+/*******************************************************************************
+ * Tegra General Purpose Centralised DMA constants
+ ******************************************************************************/
+#define TEGRA_GPCDMA_BASE U(0x02610000)
+
+/*******************************************************************************
+ * 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 (U(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)
+
+#define MC_SECURITY_CFG_REG_CTRL_0 U(0x154)
+#define SECURITY_CFG_WRITE_ACCESS_BIT (U(0x1) << 0)
+#define SECURITY_CFG_WRITE_ACCESS_ENABLE U(0x0)
+#define SECURITY_CFG_WRITE_ACCESS_DISABLE U(0x1)
+
+/* 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)
+#define MC_VIDEO_PROTECT_REG_CTRL U(0x650)
+#define MC_VIDEO_PROTECT_WRITE_ACCESS_ENABLED U(3)
+
+/*
+ * 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)
+
+/* Memory Controller Reset Control registers */
+#define MC_CLIENT_HOTRESET_CTRL1_DLAA_FLUSH_ENB (U(1) << 28)
+#define MC_CLIENT_HOTRESET_CTRL1_DLA1A_FLUSH_ENB (U(1) << 29)
+#define MC_CLIENT_HOTRESET_CTRL1_PVA0A_FLUSH_ENB (U(1) << 30)
+#define MC_CLIENT_HOTRESET_CTRL1_PVA1A_FLUSH_ENB (U(1) << 31)
+
+/*******************************************************************************
+ * 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)
+
+/*******************************************************************************
+ * XUSB PADCTL
+ ******************************************************************************/
+#define TEGRA_XUSB_PADCTL_BASE U(0x03520000)
+#define TEGRA_XUSB_PADCTL_SIZE U(0x10000)
+#define XUSB_PADCTL_HOST_AXI_STREAMID_PF_0 U(0x136c)
+#define XUSB_PADCTL_HOST_AXI_STREAMID_VF_0 U(0x1370)
+#define XUSB_PADCTL_HOST_AXI_STREAMID_VF_1 U(0x1374)
+#define XUSB_PADCTL_HOST_AXI_STREAMID_VF_2 U(0x1378)
+#define XUSB_PADCTL_HOST_AXI_STREAMID_VF_3 U(0x137c)
+#define XUSB_PADCTL_DEV_AXI_STREAMID_PF_0 U(0x139c)
+
+/*******************************************************************************
+ * Tegra Fuse Controller related constants
+ ******************************************************************************/
+#define TEGRA_FUSE_BASE U(0x03820000)
+#define OPT_SUBREVISION U(0x248)
+#define SUBREVISION_MASK U(0xF)
+
+/*******************************************************************************
+ * 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 SE0_MUTEX_WATCHDOG_NS_LIMIT U(0x6C)
+#define SE0_AES0_ENTROPY_SRC_AGE_CTRL U(0x2FC)
+#define TEGRA_PKA1_BASE U(0x03AD0000)
+#define SE_PKA1_CTRL_SE_MUTEX_TMOUT_DFTVAL U(0x144)
+#define PKA1_MUTEX_WATCHDOG_NS_LIMIT SE_PKA1_CTRL_SE_MUTEX_TMOUT_DFTVAL
+#define TEGRA_RNG1_BASE U(0x03AE0000)
+#define RNG1_MUTEX_WATCHDOG_NS_LIMIT U(0xFE0)
+
+/*******************************************************************************
+ * Tegra HSP doorbell #0 constants
+ ******************************************************************************/
+#define TEGRA_HSP_DBELL_BASE U(0x03C90000)
+#define HSP_DBELL_1_ENABLE U(0x104)
+#define HSP_DBELL_3_TRIGGER U(0x300)
+#define HSP_DBELL_3_ENABLE U(0x304)
+
+/*******************************************************************************
+ * Tegra hardware synchronization primitives for the SPE engine
+ ******************************************************************************/
+#define TEGRA_AON_HSP_SM_6_7_BASE U(0x0c190000)
+#define TEGRA_CONSOLE_SPE_BASE (TEGRA_AON_HSP_SM_6_7_BASE + U(0x8000))
+
+/*******************************************************************************
+ * Tegra micro-seconds timer constants
+ ******************************************************************************/
+#define TEGRA_TMRUS_BASE U(0x0C2E0000)
+#define TEGRA_TMRUS_SIZE U(0x10000)
+
+/*******************************************************************************
+ * Tegra Power Mgmt Controller constants
+ ******************************************************************************/
+#define TEGRA_PMC_BASE U(0x0C360000)
+
+/*******************************************************************************
+ * Tegra scratch registers constants
+ ******************************************************************************/
+#define TEGRA_SCRATCH_BASE U(0x0C390000)
+#define SECURE_SCRATCH_RSV68_LO U(0x284)
+#define SECURE_SCRATCH_RSV68_HI U(0x288)
+#define SECURE_SCRATCH_RSV69_LO U(0x28C)
+#define SECURE_SCRATCH_RSV69_HI U(0x290)
+#define SECURE_SCRATCH_RSV70_LO U(0x294)
+#define SECURE_SCRATCH_RSV70_HI U(0x298)
+#define SECURE_SCRATCH_RSV71_LO U(0x29C)
+#define SECURE_SCRATCH_RSV71_HI U(0x2A0)
+#define SECURE_SCRATCH_RSV72_LO U(0x2A4)
+#define SECURE_SCRATCH_RSV72_HI U(0x2A8)
+#define SECURE_SCRATCH_RSV75 U(0x2BC)
+#define SECURE_SCRATCH_RSV81_LO U(0x2EC)
+#define SECURE_SCRATCH_RSV81_HI U(0x2F0)
+#define SECURE_SCRATCH_RSV97 U(0x36C)
+#define SECURE_SCRATCH_RSV99_LO U(0x37C)
+#define SECURE_SCRATCH_RSV99_HI U(0x380)
+#define SECURE_SCRATCH_RSV109_LO U(0x3CC)
+#define SECURE_SCRATCH_RSV109_HI U(0x3D0)
+
+#define SCRATCH_BL31_PARAMS_HI_ADDR SECURE_SCRATCH_RSV75
+#define SCRATCH_BL31_PARAMS_HI_ADDR_MASK U(0xFFFF)
+#define SCRATCH_BL31_PARAMS_HI_ADDR_SHIFT U(0)
+#define SCRATCH_BL31_PARAMS_LO_ADDR SECURE_SCRATCH_RSV81_LO
+#define SCRATCH_BL31_PLAT_PARAMS_HI_ADDR SECURE_SCRATCH_RSV75
+#define SCRATCH_BL31_PLAT_PARAMS_HI_ADDR_MASK U(0xFFFF0000)
+#define SCRATCH_BL31_PLAT_PARAMS_HI_ADDR_SHIFT U(16)
+#define SCRATCH_BL31_PLAT_PARAMS_LO_ADDR SECURE_SCRATCH_RSV81_HI
+#define SCRATCH_SECURE_BOOTP_FCFG SECURE_SCRATCH_RSV97
+#define SCRATCH_MC_TABLE_ADDR_LO SECURE_SCRATCH_RSV99_LO
+#define SCRATCH_MC_TABLE_ADDR_HI SECURE_SCRATCH_RSV99_HI
+#define SCRATCH_RESET_VECTOR_LO SECURE_SCRATCH_RSV109_LO
+#define SCRATCH_RESET_VECTOR_HI SECURE_SCRATCH_RSV109_HI
+
+/*******************************************************************************
+ * Tegra Memory Mapped Control Register Access Bus constants
+ ******************************************************************************/
+#define TEGRA_MMCRAB_BASE U(0x0E000000)
+
+/*******************************************************************************
+ * Tegra SMMU Controller constants
+ ******************************************************************************/
+#define TEGRA_SMMU0_BASE U(0x12000000)
+#define TEGRA_SMMU1_BASE U(0x11000000)
+#define TEGRA_SMMU2_BASE U(0x10000000)
+
+/*******************************************************************************
+ * Tegra TZRAM constants
+ ******************************************************************************/
+#define TEGRA_TZRAM_BASE U(0x40000000)
+#define TEGRA_TZRAM_SIZE U(0x40000)
+
+/*******************************************************************************
+ * Tegra CCPLEX-BPMP IPC constants
+ ******************************************************************************/
+#define TEGRA_BPMP_IPC_TX_PHYS_BASE U(0x4004C000)
+#define TEGRA_BPMP_IPC_RX_PHYS_BASE U(0x4004D000)
+#define TEGRA_BPMP_IPC_CH_MAP_SIZE U(0x1000) /* 4KB */
+
+/*******************************************************************************
+ * Tegra Clock and Reset Controller constants
+ ******************************************************************************/
+#define TEGRA_CAR_RESET_BASE U(0x20000000)
+#define TEGRA_GPU_RESET_REG_OFFSET U(0x18)
+#define TEGRA_GPU_RESET_GPU_SET_OFFSET U(0x1C)
+#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 DRAM memory base address
+ ******************************************************************************/
+#define TEGRA_DRAM_BASE ULL(0x80000000)
+#define TEGRA_DRAM_END ULL(0xFFFFFFFFF)
+
+/*******************************************************************************
+ * XUSB STREAMIDs
+ ******************************************************************************/
+#define TEGRA_SID_XUSB_HOST U(0x1b)
+#define TEGRA_SID_XUSB_DEV U(0x1c)
+#define TEGRA_SID_XUSB_VF0 U(0x5d)
+#define TEGRA_SID_XUSB_VF1 U(0x5e)
+#define TEGRA_SID_XUSB_VF2 U(0x5f)
+#define TEGRA_SID_XUSB_VF3 U(0x60)
+
+/*******************************************************************************
+ * SCR addresses and expected settings
+ ******************************************************************************/
+#define SCRATCH_RSV68_SCR U(0x0C398110)
+#define SCRATCH_RSV68_SCR_VAL U(0x38000101)
+#define SCRATCH_RSV71_SCR U(0x0C39811C)
+#define SCRATCH_RSV71_SCR_VAL U(0x38000101)
+#define SCRATCH_RSV72_SCR U(0x0C398120)
+#define SCRATCH_RSV72_SCR_VAL U(0x38000101)
+#define SCRATCH_RSV75_SCR U(0x0C39812C)
+#define SCRATCH_RSV75_SCR_VAL U(0x3A000005)
+#define SCRATCH_RSV81_SCR U(0x0C398144)
+#define SCRATCH_RSV81_SCR_VAL U(0x3A000105)
+#define SCRATCH_RSV97_SCR U(0x0C398184)
+#define SCRATCH_RSV97_SCR_VAL U(0x38000101)
+#define SCRATCH_RSV99_SCR U(0x0C39818C)
+#define SCRATCH_RSV99_SCR_VAL U(0x38000101)
+#define SCRATCH_RSV109_SCR U(0x0C3981B4)
+#define SCRATCH_RSV109_SCR_VAL U(0x38000101)
+#define MISCREG_SCR_SCRTZWELCK U(0x00109000)
+#define MISCREG_SCR_SCRTZWELCK_VAL U(0x30000100)
+
+#endif /* TEGRA_DEF_H */
diff --git a/plat/nvidia/tegra/include/t210/tegra_def.h b/plat/nvidia/tegra/include/t210/tegra_def.h
new file mode 100644
index 0000000..81b25e0
--- /dev/null
+++ b/plat/nvidia/tegra/include/t210/tegra_def.h
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEGRA_DEF_H
+#define TEGRA_DEF_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * Platform BL31 specific defines.
+ ******************************************************************************/
+#define BL31_SIZE U(0x40000)
+
+/*******************************************************************************
+ * 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)
+
+/*******************************************************************************
+ * Counter-timer physical secure timer PPI
+ ******************************************************************************/
+#define TEGRA210_TIMER1_IRQ 32
+
+/*******************************************************************************
+ * 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_CLK_RST_CTL_CLK_SRC_SE U(0x42C)
+#define SE_CLK_SRC_MASK (U(7) << 29)
+#define SE_CLK_SRC_CLK_M (U(6) << 29)
+#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)
+#define MC_VIDEO_PROTECT_REG_CTRL U(0x650)
+#define MC_VIDEO_PROTECT_WRITE_ACCESS_ENABLED U(3)
+
+/* 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)
+
+/*******************************************************************************
+ * Tegra DRAM memory base address
+ ******************************************************************************/
+#define TEGRA_DRAM_BASE ULL(0x80000000)
+#define TEGRA_DRAM_END ULL(0x27FFFFFFF)
+
+#endif /* TEGRA_DEF_H */
diff --git a/plat/nvidia/tegra/include/tegra_platform.h b/plat/nvidia/tegra/include/tegra_platform.h
new file mode 100644
index 0000000..ab51dfe
--- /dev/null
+++ b/plat/nvidia/tegra/include/tegra_platform.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2021, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEGRA_PLATFORM_H
+#define TEGRA_PLATFORM_H
+
+#include <cdefs.h>
+#include <lib/utils_def.h>
+#include <stdbool.h>
+
+/*******************************************************************************
+ * 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)
+#define TEGRA_CHIPID_TEGRA19 U(0x19)
+
+/*******************************************************************************
+ * JEDEC Standard Manufacturer's Identification Code and Bank ID
+ ******************************************************************************/
+#define JEDEC_NVIDIA_MFID U(0x6B)
+#define JEDEC_NVIDIA_BKID U(3)
+
+#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_t186(void);
+bool tegra_chipid_is_t210(void);
+bool tegra_chipid_is_t210_b01(void);
+bool tegra_chipid_is_t194(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 */
diff --git a/plat/nvidia/tegra/include/tegra_private.h b/plat/nvidia/tegra/include/tegra_private.h
new file mode 100644
index 0000000..cc2ad86
--- /dev/null
+++ b/plat/nvidia/tegra/include/tegra_private.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEGRA_PRIVATE_H
+#define TEGRA_PRIVATE_H
+
+#include <platform_def.h>
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/psci/psci.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <tegra_gic.h>
+
+/*******************************************************************************
+ * 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;
+ /* Enable dual execution */
+ uint8_t enable_ccplex_lock_step;
+} 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;
+};
+
+/*******************************************************************************
+* To suppress Coverity MISRA C-2012 Rule 2.2 violations
+*******************************************************************************/
+#define UNUSED_FUNC_NOP() asm("nop")
+
+/* 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);
+void plat_enable_console(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);
+void plat_relocate_bl32_image(const image_info_t *bl32_img_info);
+bool plat_supports_system_suspend(void);
+void plat_runtime_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);
+int32_t 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 */
+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_pwr_domain_suspend_pwrdown_early(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);
+
+/* 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);
+
+/* 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);
+
+#if RAS_EXTENSION
+void tegra194_ras_enable(void);
+void tegra194_ras_corrected_err_clear(uint64_t *cookie);
+#endif
+
+#endif /* TEGRA_PRIVATE_H */
diff --git a/plat/nvidia/tegra/lib/debug/profiler.c b/plat/nvidia/tegra/lib/debug/profiler.c
new file mode 100644
index 0000000..dd76a4e
--- /dev/null
+++ b/plat/nvidia/tegra/lib/debug/profiler.c
@@ -0,0 +1,144 @@
+/*
+ * 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 <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <profiler.h>
+#include <stdbool.h>
+#include <string.h>
+
+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);
+ }
+ }
+}
diff --git a/plat/nvidia/tegra/platform.mk b/plat/nvidia/tegra/platform.mk
new file mode 100644
index 0000000..6ed1cdf
--- /dev/null
+++ b/plat/nvidia/tegra/platform.mk
@@ -0,0 +1,97 @@
+#
+# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2020, NVIDIA Corporation. 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 := 50
+$(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 exception handling at EL3
+EL3_EXCEPTION_HANDLING := 1
+GICV2_G0_FOR_EL3 := 1
+
+# 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
+
+# enable D-cache early during CPU warmboot
+WARMBOOT_ENABLE_DCACHE_EARLY := 1
+
+# remove the standard libc
+OVERRIDE_LIBC := 1
+
+# Flag to enable WDT FIQ interrupt handling for Tegra SoCs
+# prior to Tegra186
+ENABLE_TEGRA_WDT_LEGACY_FIQ_HANDLING ?= 0
+
+# Flag to allow relocation of BL32 image to TZDRAM during boot
+RELOCATE_BL32_IMAGE ?= 0
+
+# Enable stack protection
+ENABLE_STACK_PROTECTOR := strong
+
+# Enable SDEI
+SDEI_SUPPORT := 1
+
+# modify BUILD_PLAT to point to SoC specific build directory
+BUILD_PLAT := ${BUILD_BASE}/${PLAT}/${TARGET_SOC}/${BUILD_TYPE}
+
+include plat/nvidia/tegra/common/tegra_common.mk
+include ${SOC_DIR}/platform_${TARGET_SOC}.mk
+
+$(eval $(call add_define,ENABLE_TEGRA_WDT_LEGACY_FIQ_HANDLING))
+$(eval $(call add_define,RELOCATE_BL32_IMAGE))
+
+# platform cflags (enable signed comparisons, disable stdlib)
+TF_CFLAGS += -nostdlib
+
+# override with necessary libc files for the Tegra platform
+override LIBC_SRCS := $(addprefix lib/libc/, \
+ aarch64/setjmp.S \
+ assert.c \
+ memchr.c \
+ memcmp.c \
+ memcpy.c \
+ memmove.c \
+ memset.c \
+ printf.c \
+ putchar.c \
+ strrchr.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
diff --git a/plat/nvidia/tegra/scat/bl31.scat b/plat/nvidia/tegra/scat/bl31.scat
new file mode 100644
index 0000000..2d6d2b3
--- /dev/null
+++ b/plat/nvidia/tegra/scat/bl31.scat
@@ -0,0 +1,284 @@
+#! armclang -E -x c
+
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#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 <lib/el3_runtime/pubsub_events.h>
+
+ __RODATA_EPILOGUE__ AlignExpr(+0, PAGE_SIZE) FIXED EMPTY 0
+ {
+ /* section delimiter */
+ }
+}
+
+ /* cpu_ops must always be defined */
+ ScatterAssert(ImageLength(__CPU_OPS__) > 0)
+
+#if SPM_MM
+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)
+}
diff --git a/plat/nvidia/tegra/soc/t186/drivers/include/mce_private.h b/plat/nvidia/tegra/soc/t186/drivers/include/mce_private.h
new file mode 100644
index 0000000..203f61a
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/drivers/include/mce_private.h
@@ -0,0 +1,260 @@
+/*
+ * 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 <lib/mmio.h>
+
+#include <tegra_def.h>
+
+/*******************************************************************************
+ * 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 */
diff --git a/plat/nvidia/tegra/soc/t186/drivers/include/t18x_ari.h b/plat/nvidia/tegra/soc/t186/drivers/include/t18x_ari.h
new file mode 100644
index 0000000..ecfb3f4
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/drivers/include/t18x_ari.h
@@ -0,0 +1,437 @@
+/*
+ * 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 */
diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S b/plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S
new file mode 100644
index 0000000..e3591ce
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+ .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
diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c b/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c
new file mode 100644
index 0000000..a57bc11
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c
@@ -0,0 +1,564 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <denver.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <mce_private.h>
+#include <t18x_ari.h>
+
+/*******************************************************************************
+ * 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);
+ }
+}
diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c b/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c
new file mode 100644
index 0000000..aebaceb
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <denver.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+
+#include <mce.h>
+#include <mce_private.h>
+#include <t18x_ari.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+
+/* 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 (%" PRIu64 ")\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 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();
+ }
+ }
+}
diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/nvg.c b/plat/nvidia/tegra/soc/t186/drivers/mce/nvg.c
new file mode 100644
index 0000000..cbc9aa3
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/drivers/mce/nvg.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <denver.h>
+#include <lib/mmio.h>
+
+#include <mce_private.h>
+#include <t18x_ari.h>
+#include <tegra_private.h>
+
+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;
+}
diff --git a/plat/nvidia/tegra/soc/t186/drivers/se/se.c b/plat/nvidia/tegra/soc/t186/drivers/se/se.c
new file mode 100644
index 0000000..25f8cd0
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/drivers/se/se.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <drivers/delay_timer.h>
+#include <errno.h>
+#include <string.h>
+
+#include <bpmp_ipc.h>
+#include <pmc.h>
+#include <security_engine.h>
+#include <tegra_private.h>
+
+#include "se_private.h"
+
+/*******************************************************************************
+ * Constants and Macros
+ ******************************************************************************/
+#define SE0_MAX_BUSY_TIMEOUT_MS U(100) /* 100ms */
+#define BYTES_IN_WORD U(4)
+#define SHA256_MAX_HASH_RESULT U(7)
+#define SHA256_DST_SIZE U(32)
+#define SHA_FIRST_OP U(1)
+#define MAX_SHA_ENGINE_CHUNK_SIZE U(0xFFFFFF)
+#define SHA256_MSG_LENGTH_ONETIME U(0xffff)
+
+/*
+ * 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. SE0_INT_STATUS = SE0_OP_DONE
+ * 2. SE0_STATUS = IDLE
+ * 3. SE0_ERR_STATUS is clean.
+ */
+static int32_t tegra_se_operation_complete(void)
+{
+ uint32_t val = 0U;
+
+ /* Read SE0 interrupt register to ensure H/W operation complete */
+ val = tegra_se_read_32(SE0_INT_STATUS_REG_OFFSET);
+ if (SE0_INT_OP_DONE(val) == SE0_INT_OP_DONE_CLEAR) {
+ ERROR("%s: Engine busy state too many times! val = 0x%x\n",
+ __func__, val);
+ return -ETIMEDOUT;
+ }
+
+ /* Read SE0 status idle to ensure H/W operation complete */
+ val = tegra_se_read_32(SE0_SHA_STATUS_0);
+ if (val != SE0_SHA_STATUS_IDLE) {
+ ERROR("%s: Idle state timeout! val = 0x%x\n", __func__,
+ val);
+ return -ETIMEDOUT;
+ }
+
+ /* Ensure that no errors are thrown during operation */
+ val = tegra_se_read_32(SE0_ERR_STATUS_REG_OFFSET);
+ if (val != SE0_ERR_STATUS_CLEAR) {
+ ERROR("%s: Error during SE operation! val = 0x%x",
+ __func__, val);
+ return -ENOTSUP;
+ }
+
+ return 0;
+}
+
+/*
+ * Security engine primitive normal operations
+ */
+static int32_t tegra_se_start_normal_operation(uint64_t src_addr,
+ uint32_t nbytes, uint32_t last_buf, uint32_t src_len_inbytes)
+{
+ int32_t ret = 0;
+ uint32_t val = 0U;
+ uint32_t src_in_lo;
+ uint32_t src_in_msb;
+ uint32_t src_in_hi;
+
+ if ((src_addr == 0UL) || (nbytes == 0U))
+ return -EINVAL;
+
+ src_in_lo = (uint32_t)src_addr;
+ src_in_msb = ((uint32_t)(src_addr >> 32U) & 0xffU);
+ src_in_hi = ((src_in_msb << SE0_IN_HI_ADDR_HI_0_MSB_SHIFT) |
+ (nbytes & 0xffffffU));
+
+ /* set SRC_IN_ADDR_LO and SRC_IN_ADDR_HI*/
+ tegra_se_write_32(SE0_IN_ADDR, src_in_lo);
+ tegra_se_write_32(SE0_IN_HI_ADDR_HI, src_in_hi);
+
+ val = tegra_se_read_32(SE0_INT_STATUS_REG_OFFSET);
+ if (val > 0U) {
+ tegra_se_write_32(SE0_INT_STATUS_REG_OFFSET, 0x00000U);
+ }
+
+ /* Enable SHA interrupt for SE0 Operation */
+ tegra_se_write_32(SE0_SHA_INT_ENABLE, 0x1aU);
+
+ /* flush to DRAM for SE to use the updated contents */
+ flush_dcache_range(src_addr, src_len_inbytes);
+
+ /* Start SHA256 operation */
+ if (last_buf == 1U) {
+ tegra_se_write_32(SE0_OPERATION_REG_OFFSET, SE0_OP_START |
+ SE0_UNIT_OPERATION_PKT_LASTBUF_FIELD);
+ } else {
+ tegra_se_write_32(SE0_OPERATION_REG_OFFSET, SE0_OP_START);
+ }
+
+ /* Wait for SE-operation to finish */
+ udelay(SE0_MAX_BUSY_TIMEOUT_MS * 100U);
+
+ /* Check SE0 operation status */
+ ret = tegra_se_operation_complete();
+ if (ret != 0) {
+ ERROR("SE operation complete Failed! 0x%x", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int32_t tegra_se_calculate_sha256_hash(uint64_t src_addr,
+ uint32_t src_len_inbyte)
+{
+ uint32_t val, last_buf, i;
+ int32_t ret = 0;
+ uint32_t operations;
+ uint64_t src_len_inbits;
+ uint32_t len_bits_msb;
+ uint32_t len_bits_lsb;
+ uint32_t number_of_operations, max_bytes, bytes_left, remaining_bytes;
+
+ if (src_len_inbyte > MAX_SHA_ENGINE_CHUNK_SIZE) {
+ ERROR("SHA input chunk size too big: 0x%x\n", src_len_inbyte);
+ return -EINVAL;
+ }
+
+ if (src_addr == 0UL) {
+ return -EINVAL;
+ }
+
+ /* number of bytes per operation */
+ max_bytes = SHA256_HASH_SIZE_BYTES * SHA256_MSG_LENGTH_ONETIME;
+
+ src_len_inbits = src_len_inbyte * 8U;
+ len_bits_msb = (uint32_t)(src_len_inbits >> 32U);
+ len_bits_lsb = (uint32_t)(src_len_inbits & 0xFFFFFFFF);
+
+ /* program SE0_CONFIG for SHA256 operation */
+ val = SE0_CONFIG_ENC_ALG_SHA | SE0_CONFIG_ENC_MODE_SHA256 |
+ SE0_CONFIG_DEC_ALG_NOP | SE0_CONFIG_DST_HASHREG;
+ tegra_se_write_32(SE0_SHA_CONFIG, val);
+
+ /* set SE0_SHA_MSG_LENGTH registers */
+ tegra_se_write_32(SE0_SHA_MSG_LENGTH_0, len_bits_lsb);
+ tegra_se_write_32(SE0_SHA_MSG_LEFT_0, len_bits_lsb);
+ tegra_se_write_32(SE0_SHA_MSG_LENGTH_1, len_bits_msb);
+
+ /* zero out unused SE0_SHA_MSG_LENGTH and SE0_SHA_MSG_LEFT */
+ tegra_se_write_32(SE0_SHA_MSG_LENGTH_2, 0U);
+ tegra_se_write_32(SE0_SHA_MSG_LENGTH_3, 0U);
+ tegra_se_write_32(SE0_SHA_MSG_LEFT_1, 0U);
+ tegra_se_write_32(SE0_SHA_MSG_LEFT_2, 0U);
+ tegra_se_write_32(SE0_SHA_MSG_LEFT_3, 0U);
+
+ number_of_operations = src_len_inbyte / max_bytes;
+ remaining_bytes = src_len_inbyte % max_bytes;
+ if (remaining_bytes > 0U) {
+ number_of_operations += 1U;
+ }
+
+ /*
+ * 1. Operations == 1: program SE0_SHA_TASK register to initiate SHA256
+ * hash generation by setting
+ * 1(SE0_SHA_CONFIG_HW_INIT_HASH) to SE0_SHA_TASK
+ * and start SHA256-normal operation.
+ * 2. 1 < Operations < number_of_operations: program SE0_SHA_TASK to
+ * 0(SE0_SHA_CONFIG_HW_INIT_HASH_DISABLE) to load
+ * intermediate SHA256 digest result from
+ * HASH_RESULT register to continue SHA256
+ * generation and start SHA256-normal operation.
+ * 3. Operations == number_of_operations: continue with step 2 and set
+ * max_bytes to bytes_left to process final
+ * hash-result generation and
+ * start SHA256-normal operation.
+ */
+ bytes_left = src_len_inbyte;
+ for (operations = 1U; operations <= number_of_operations;
+ operations++) {
+ if (operations == SHA_FIRST_OP) {
+ val = SE0_SHA_CONFIG_HW_INIT_HASH;
+ } else {
+ /* Load intermediate SHA digest result to
+ * SHA:HASH_RESULT(0..7) to continue the SHA
+ * calculation and tell the SHA engine to use it.
+ */
+ for (i = 0U; (i / BYTES_IN_WORD) <=
+ SHA256_MAX_HASH_RESULT; i += BYTES_IN_WORD) {
+ val = tegra_se_read_32(SE0_SHA_HASH_RESULT_0 +
+ i);
+ tegra_se_write_32(SE0_SHA_HASH_RESULT_0 + i,
+ val);
+ }
+ val = SE0_SHA_CONFIG_HW_INIT_HASH_DISABLE;
+ if (len_bits_lsb <= (max_bytes * 8U)) {
+ len_bits_lsb = (remaining_bytes * 8U);
+ } else {
+ len_bits_lsb -= (max_bytes * 8U);
+ }
+ tegra_se_write_32(SE0_SHA_MSG_LEFT_0, len_bits_lsb);
+ }
+ tegra_se_write_32(SE0_SHA_TASK_CONFIG, val);
+
+ max_bytes = (SHA256_HASH_SIZE_BYTES *
+ SHA256_MSG_LENGTH_ONETIME);
+ if (bytes_left < max_bytes) {
+ max_bytes = bytes_left;
+ last_buf = 1U;
+ } else {
+ bytes_left = bytes_left - max_bytes;
+ last_buf = 0U;
+ }
+ /* start operation */
+ ret = tegra_se_start_normal_operation(src_addr, max_bytes,
+ last_buf, src_len_inbyte);
+ if (ret != 0) {
+ ERROR("Error during SE operation! 0x%x", ret);
+ return -EINVAL;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Handler to generate SHA256 and save SHA256 hash to PMC-Scratch register.
+ */
+int32_t tegra_se_save_sha256_hash(uint64_t bl31_base, uint32_t src_len_inbyte)
+{
+ int32_t ret = 0;
+ uint32_t val = 0U, hash_offset = 0U, scratch_offset = 0U, security;
+
+ /*
+ * Set SE_SOFT_SETTINGS=SE_SECURE to prevent NS process to change SE
+ * registers.
+ */
+ security = tegra_se_read_32(SE0_SECURITY);
+ tegra_se_write_32(SE0_SECURITY, security | SE0_SECURITY_SE_SOFT_SETTING);
+
+ ret = tegra_se_calculate_sha256_hash(bl31_base, src_len_inbyte);
+ if (ret != 0L) {
+ ERROR("%s: SHA256 generation failed\n", __func__);
+ return ret;
+ }
+
+ /*
+ * Reset SE_SECURE to previous value.
+ */
+ tegra_se_write_32(SE0_SECURITY, security);
+
+ /* read SHA256_HASH_RESULT and save to PMC Scratch registers */
+ scratch_offset = SECURE_SCRATCH_TZDRAM_SHA256_HASH_START;
+ while (scratch_offset <= SECURE_SCRATCH_TZDRAM_SHA256_HASH_END) {
+
+ val = tegra_se_read_32(SE0_SHA_HASH_RESULT_0 + hash_offset);
+ mmio_write_32(TEGRA_SCRATCH_BASE + scratch_offset, val);
+
+ hash_offset += BYTES_IN_WORD;
+ scratch_offset += BYTES_IN_WORD;
+ }
+
+ return ret;
+}
+
diff --git a/plat/nvidia/tegra/soc/t186/drivers/se/se_private.h b/plat/nvidia/tegra/soc/t186/drivers/se/se_private.h
new file mode 100644
index 0000000..7aa0dd6
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/drivers/se/se_private.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SE_PRIVATE_H
+#define SE_PRIVATE_H
+
+#include <lib/utils_def.h>
+
+/* SE0 security register */
+#define SE0_SECURITY U(0x18)
+#define SE0_SECURITY_SE_SOFT_SETTING (((uint32_t)1) << 16U)
+
+/* SE0 config register */
+#define SE0_SHA_CONFIG U(0x104)
+#define SE0_SHA_TASK_CONFIG U(0x108)
+#define SE0_SHA_CONFIG_HW_INIT_HASH ((1U) << 0U)
+#define SE0_SHA_CONFIG_HW_INIT_HASH_DISABLE U(0)
+
+#define SE0_CONFIG_ENC_ALG_SHIFT U(12)
+#define SE0_CONFIG_ENC_ALG_SHA \
+ (((uint32_t)3) << SE0_CONFIG_ENC_ALG_SHIFT)
+#define SE0_CONFIG_DEC_ALG_SHIFT U(8)
+#define SE0_CONFIG_DEC_ALG_NOP \
+ (((uint32_t)0) << SE0_CONFIG_DEC_ALG_SHIFT)
+#define SE0_CONFIG_DST_SHIFT U(2)
+#define SE0_CONFIG_DST_HASHREG \
+ (((uint32_t)1) << SE0_CONFIG_DST_SHIFT)
+#define SHA256_HASH_SIZE_BYTES U(256)
+
+#define SE0_CONFIG_ENC_MODE_SHIFT U(24)
+#define SE0_CONFIG_ENC_MODE_SHA256 \
+ (((uint32_t)5) << SE0_CONFIG_ENC_MODE_SHIFT)
+
+/* SHA input message length */
+#define SE0_SHA_MSG_LENGTH_0 U(0x11c)
+#define SE0_SHA_MSG_LENGTH_1 U(0x120)
+#define SE0_SHA_MSG_LENGTH_2 U(0x124)
+#define SE0_SHA_MSG_LENGTH_3 U(0x128)
+
+/* SHA input message left */
+#define SE0_SHA_MSG_LEFT_0 U(0x12c)
+#define SE0_SHA_MSG_LEFT_1 U(0x130)
+#define SE0_SHA_MSG_LEFT_2 U(0x134)
+#define SE0_SHA_MSG_LEFT_3 U(0x138)
+
+/* SE Hash Result */
+#define SE0_SHA_HASH_RESULT_0 U(0x13c)
+
+/* SE OPERATION */
+#define SE0_OPERATION_REG_OFFSET U(0x17c)
+#define SE0_UNIT_OPERATION_PKT_LASTBUF_SHIFT U(16)
+#define SE0_UNIT_OPERATION_PKT_LASTBUF_FIELD \
+ (((uint32_t)0x1) << SE0_UNIT_OPERATION_PKT_LASTBUF_SHIFT)
+#define SE0_OPERATION_SHIFT U(0)
+#define SE0_OP_START \
+ (((uint32_t)0x1) << SE0_OPERATION_SHIFT)
+
+/* SE Interrupt */
+#define SE0_SHA_INT_ENABLE U(0x180)
+
+#define SE0_INT_STATUS_REG_OFFSET U(0x184)
+#define SE0_INT_OP_DONE_SHIFT U(4)
+#define SE0_INT_OP_DONE_CLEAR \
+ (((uint32_t)0) << SE0_INT_OP_DONE_SHIFT)
+#define SE0_INT_OP_DONE(x) \
+ ((x) & (((uint32_t)0x1) << SE0_INT_OP_DONE_SHIFT))
+
+/* SE SHA status */
+#define SE0_SHA_STATUS_0 U(0x188)
+#define SE0_SHA_STATUS_IDLE U(0)
+
+/* SE error status */
+#define SE0_ERR_STATUS_REG_OFFSET U(0x18c)
+#define SE0_ERR_STATUS_CLEAR U(0)
+#define SE0_IN_ADDR U(0x10c)
+#define SE0_IN_HI_ADDR_HI U(0x110)
+#define SE0_IN_HI_ADDR_HI_0_MSB_SHIFT U(24)
+
+/* SE error status */
+#define SECURE_SCRATCH_TZDRAM_SHA256_HASH_START SECURE_SCRATCH_RSV63_LO
+#define SECURE_SCRATCH_TZDRAM_SHA256_HASH_END SECURE_SCRATCH_RSV66_HI
+
+/*******************************************************************************
+ * Inline functions definition
+ ******************************************************************************/
+
+static inline uint32_t tegra_se_read_32(uint32_t offset)
+{
+ return mmio_read_32((uint32_t)(TEGRA_SE0_BASE + offset));
+}
+
+static inline void tegra_se_write_32(uint32_t offset, uint32_t val)
+{
+ mmio_write_32(((uint32_t)(TEGRA_SE0_BASE + offset)), val);
+}
+
+#endif /* SE_PRIVATE_H */
diff --git a/plat/nvidia/tegra/soc/t186/plat_memctrl.c b/plat/nvidia/tegra/soc/t186/plat_memctrl.c
new file mode 100644
index 0000000..81de674
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/plat_memctrl.c
@@ -0,0 +1,700 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/bl_common.h>
+
+#include <mce.h>
+#include <memctrl_v2.h>
+#include <tegra186_private.h>
+#include <tegra_mc_def.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+extern uint64_t tegra_bl31_phys_base;
+
+/*******************************************************************************
+ * Array to hold stream_id override config register offsets
+ ******************************************************************************/
+const static uint32_t tegra186_streamid_override_regs[] = {
+ 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,
+};
+
+/*******************************************************************************
+ * 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, DISABLE),
+ mc_make_sec_cfg(AFIW, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(NVDISPLAYR1, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(XUSB_DEVR, NON_SECURE, OVERRIDE, ENABLE),
+ mc_make_sec_cfg(VICSRD1, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(NVENCSWR, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(TSECSRDB, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(AXISW, SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(SDMMCWAB, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(AONDMAW, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(GPUSWR2, SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(SATAW, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(UFSHCW, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(SDMMCR, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(SCEDMAW, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(UFSHCR, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(SDMMCWAA, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(SESWR, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(MPCORER, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(PTCR, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(BPMPW, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(ETRW, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(GPUSRD, SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(VICSWR, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(SCEDMAR, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(HDAW, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(ISPWA, NON_SECURE, OVERRIDE, ENABLE),
+ mc_make_sec_cfg(EQOSW, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(XUSB_HOSTW, NON_SECURE, OVERRIDE, ENABLE),
+ mc_make_sec_cfg(TSECSWR, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(SDMMCRAA, NON_SECURE, OVERRIDE, DISABLE),
+ 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, DISABLE),
+ 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, DISABLE),
+ 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, DISABLE),
+ mc_make_sec_cfg(NVDISPLAYR, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(BPMPDMAR, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(NVJPGSWR, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(NVDECSRD1, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(TSECSRD, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(NVJPGSRD, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(SDMMCWA, NON_SECURE, OVERRIDE, DISABLE),
+ 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, DISABLE),
+ mc_make_sec_cfg(AONDMAR, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(AONW, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(SDMMCRA, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(HOST1XDMAR, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(EQOSR, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(SATAR, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(BPMPR, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(HDAR, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(SDMMCRAB, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(ETRR, NON_SECURE, OVERRIDE, DISABLE),
+ mc_make_sec_cfg(AONR, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(SESRD, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(NVENCSRD, NON_SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(GPUSWR, SECURE, NO_OVERRIDE, DISABLE),
+ mc_make_sec_cfg(TSECSWRB, NON_SECURE, NO_OVERRIDE, DISABLE),
+ 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)
+{
+ uint32_t i, val;
+
+ /*
+ * 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 < ARRAY_SIZE(tegra186_txn_override_cfgs); i++) {
+ val = tegra_mc_read_32(tegra186_txn_override_cfgs[i].offset);
+ val &= (uint32_t)~MC_TXN_OVERRIDE_CGID_TAG_MASK;
+ tegra_mc_write_32(tegra186_txn_override_cfgs[i].offset,
+ val | tegra186_txn_override_cfgs[i].cgid_tag);
+ }
+ }
+}
+
+
+/*******************************************************************************
+ * Array to hold MC context for Tegra186
+ ******************************************************************************/
+static __attribute__((aligned(16))) mc_regs_t tegra186_mc_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),
+ mc_smmu_bypass_cfg, /* TBU settings */
+ _END_OF_TABLE_,
+};
+
+/*******************************************************************************
+ * Handler to return the pointer to the MC's context struct
+ ******************************************************************************/
+mc_regs_t *plat_memctrl_get_sys_suspend_ctx(void)
+{
+ /* index of _END_OF_TABLE_ */
+ tegra186_mc_context[0].val = (uint32_t)(ARRAY_SIZE(tegra186_mc_context)) - 1U;
+
+ return tegra186_mc_context;
+}
+
+void plat_memctrl_setup(void)
+{
+ uint32_t val;
+ unsigned int i;
+
+ /* Program all the Stream ID overrides */
+ for (i = 0U; i < ARRAY_SIZE(tegra186_streamid_override_regs); i++) {
+ tegra_mc_streamid_write_32(tegra186_streamid_override_regs[i],
+ MC_STREAM_ID_MAX);
+ }
+
+ /* Program the security config settings for all Stream IDs */
+ for (i = 0U; i < ARRAY_SIZE(tegra186_streamid_sec_cfgs); i++) {
+ val = (tegra186_streamid_sec_cfgs[i].override_enable << 16) |
+ (tegra186_streamid_sec_cfgs[i].override_client_inputs << 8) |
+ (tegra186_streamid_sec_cfgs[i].override_client_ns_flag << 0);
+ tegra_mc_streamid_write_32(tegra186_streamid_sec_cfgs[i].offset, val);
+ }
+
+ /*
+ * 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.
+ */
+ tegra186_memctrl_reconfig_mss_clients();
+
+ /* Program overrides for MC transactions */
+ tegra186_memctrl_set_overrides();
+}
+
+/*******************************************************************************
+ * Handler to restore platform specific settings to the memory controller
+ ******************************************************************************/
+void plat_memctrl_restore(void)
+{
+ /*
+ * 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.
+ */
+ tegra186_memctrl_reconfig_mss_clients();
+
+ /* Program overrides for MC transactions */
+ tegra186_memctrl_set_overrides();
+}
+
+/*******************************************************************************
+ * 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();
+}
diff --git a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
new file mode 100644
index 0000000..af4182e
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
@@ -0,0 +1,472 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <cortex_a57.h>
+#include <denver.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include <bpmp_ipc.h>
+#include <mce.h>
+#include <memctrl_v2.h>
+#include <security_engine.h>
+#include <smmu.h>
+#include <t18x_ari.h>
+#include <tegra186_private.h>
+#include <tegra_private.h>
+
+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:
+
+ if (psci_get_pstate_type(power_state) != PSTATE_TYPE_POWERDOWN) {
+ ret = PSCI_E_INVALID_PARAMS;
+ break;
+ }
+
+ /* 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_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)
+{
+ 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 mc_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 MC context to TZDRAM */
+ mc_ctx_base = params_from_bl2->tzdram_base;
+ tegra_mc_save_context((uintptr_t)mc_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);
+
+ } 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;
+ uint64_t src_len_in_bytes = (uint64_t)(((uintptr_t)(&__BL31_END__) -
+ (uintptr_t)BL31_BASE));
+ int32_t ret;
+
+ if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
+ val = params_from_bl2->tzdram_base +
+ tegra186_get_mc_ctx_size();
+
+ /* Initialise communication channel with BPMP */
+ assert(tegra_bpmp_ipc_init() == 0);
+
+ /* Enable SE clock */
+ ret = tegra_bpmp_ipc_enable_clock(TEGRA186_CLK_SE);
+ if (ret != 0) {
+ ERROR("Failed to enable clock\n");
+ return ret;
+ }
+
+ /*
+ * Generate/save SHA256 of ATF during SC7 entry
+ */
+ if (tegra_se_save_sha256_hash(BL31_BASE,
+ (uint32_t)src_len_in_bytes) != 0) {
+ ERROR("Hash calculation failed. Reboot\n");
+ (void)tegra_soc_prepare_system_reset();
+ }
+
+ /*
+ * 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_mc_ctx_size();
+ memcpy16((void *)(uintptr_t)val, (void *)(uintptr_t)BL31_BASE,
+ (uintptr_t)BL31_END - (uintptr_t)BL31_BASE);
+
+ /*
+ * Save code base and size; this would be used by SC7-RF to
+ * verify binary
+ */
+ mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV68_LO,
+ (uint32_t)val);
+ mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV0_HI,
+ (uint32_t)src_len_in_bytes);
+
+ ret = tegra_bpmp_ipc_disable_clock(TEGRA186_CLK_SE);
+ if (ret != 0) {
+ ERROR("Failed to disable clock\n");
+ return ret;
+ }
+ }
+
+ return PSCI_E_SUCCESS;
+}
+
+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_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;
+}
diff --git a/plat/nvidia/tegra/soc/t186/plat_secondary.c b/plat/nvidia/tegra/soc/t186/plat_secondary.c
new file mode 100644
index 0000000..fbb550a
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/plat_secondary.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <mce.h>
+#include <tegra_def.h>
+#include <tegra_private.h>
+
+#define SCRATCH_SECURE_RSV1_SCRATCH_0 0x658U
+#define SCRATCH_SECURE_RSV1_SCRATCH_1 0x65CU
+
+#define CPU_RESET_MODE_AA64 1U
+
+/*******************************************************************************
+ * Setup secondary CPU vectors
+ ******************************************************************************/
+void plat_secondary_setup(void)
+{
+ uint32_t addr_low, addr_high;
+
+ INFO("Setting up secondary CPU boot\n");
+
+ /* TZDRAM base will be used as the "resume" address */
+ addr_low = (uintptr_t)&tegra_secure_entrypoint | CPU_RESET_MODE_AA64;
+ addr_high = (uintptr_t)(((uintptr_t)&tegra_secure_entrypoint >> 32U) & 0x7ffU);
+
+ /* 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);
+}
diff --git a/plat/nvidia/tegra/soc/t186/plat_setup.c b/plat/nvidia/tegra/soc/t186/plat_setup.c
new file mode 100644
index 0000000..d6d090a
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/plat_setup.c
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/ep_info.h>
+#include <common/interrupt_props.h>
+#include <context.h>
+#include <cortex_a57.h>
+#include <denver.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/console.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include <mce.h>
+#include <memctrl.h>
+#include <smmu.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+extern void memcpy16(void *dest, const void *src, unsigned int length);
+
+/*******************************************************************************
+ * 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),
+ MAP_REGION_FLAT(TEGRA_HSP_DBELL_BASE, 0x10000U, /* 64KB */
+ MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_BPMP_IPC_TX_PHYS_BASE, TEGRA_BPMP_IPC_CH_MAP_SIZE, /* 4KB */
+ MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_BPMP_IPC_RX_PHYS_BASE, TEGRA_BPMP_IPC_CH_MAP_SIZE, /* 4KB */
+ 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,
+};
+
+/*******************************************************************************
+ * Enable console corresponding to the console ID
+ ******************************************************************************/
+void plat_enable_console(int32_t id)
+{
+ static console_t uart_console;
+ uint32_t console_clock;
+
+ if ((id > 0) && (id < TEGRA186_MAX_UART_PORTS)) {
+ /*
+ * 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;
+ }
+
+ (void)console_16550_register(tegra186_uart_addresses[id],
+ console_clock,
+ TEGRA_CONSOLE_BAUDRATE,
+ &uart_console);
+ console_set_scope(&uart_console, CONSOLE_FLAG_BOOT |
+ CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH);
+ }
+}
+
+/*******************************************************************************
+ * 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();
+ const struct tegra_bl31_params *arg_from_bl2 = plat_get_bl31_params();
+
+ /* Verify chip id is t186 */
+ assert(tegra_chipid_is_t186());
+
+ /* sanity check MCE firmware compatibility */
+ mce_verify_firmware_version();
+
+ /*
+ * Do initial security configuration to allow DRAM/device access.
+ */
+ tegra_memctrl_tzdram_setup(plat_params->tzdram_base,
+ (uint32_t)plat_params->tzdram_size);
+
+ 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);
+ }
+
+ /*
+ * The previous bootloader might not have placed the BL32 image
+ * inside the TZDRAM. Platform handler to allow relocation of BL32
+ * image to TZDRAM memory. This behavior might change per platform.
+ */
+ plat_relocate_bl32_image(arg_from_bl2->bl32_image_info);
+}
+
+/*******************************************************************************
+ * Handler for late platform setup
+ ******************************************************************************/
+void plat_late_platform_setup(void)
+{
+ ; /* do nothing */
+}
+
+/* Secure IRQs for Tegra186 */
+static const interrupt_prop_t tegra186_interrupt_props[] = {
+ INTR_PROP_DESC(TEGRA_SDEI_SGI_PRIVATE, PLAT_SDEI_CRITICAL_PRI,
+ GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
+ INTR_PROP_DESC(TEGRA186_TOP_WDT_IRQ, PLAT_TEGRA_WDT_PRIO,
+ GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
+ INTR_PROP_DESC(TEGRA186_AON_WDT_IRQ, PLAT_TEGRA_WDT_PRIO,
+ 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;
+}
+
+/*******************************************************************************
+ * Handler to relocate BL32 image to TZDRAM
+ ******************************************************************************/
+void plat_relocate_bl32_image(const image_info_t *bl32_img_info)
+{
+ const plat_params_from_bl2_t *plat_bl31_params = plat_get_bl31_plat_params();
+ const entry_point_info_t *bl32_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
+ uint64_t tzdram_start, tzdram_end, bl32_start, bl32_end;
+
+ if ((bl32_img_info != NULL) && (bl32_ep_info != NULL)) {
+
+ /* Relocate BL32 if it resides outside of the TZDRAM */
+ tzdram_start = plat_bl31_params->tzdram_base;
+ tzdram_end = plat_bl31_params->tzdram_base +
+ plat_bl31_params->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_ep_info->pc > tzdram_start);
+ assert(bl32_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_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);
+ }
+ }
+}
+
+/*******************************************************************************
+ * Handler to indicate support for System Suspend
+ ******************************************************************************/
+bool plat_supports_system_suspend(void)
+{
+ return true;
+}
+/*******************************************************************************
+ * Platform specific runtime setup.
+ ******************************************************************************/
+void 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();
+
+ /*
+ * Verify the integrity of the previously configured SMMU(s)
+ * settings
+ */
+ tegra_smmu_verify();
+}
diff --git a/plat/nvidia/tegra/soc/t186/plat_sip_calls.c b/plat/nvidia/tegra/soc/t186/plat_sip_calls.c
new file mode 100644
index 0000000..4de8a9e
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/plat_sip_calls.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <denver.h>
+#include <lib/el3_runtime/context_mgmt.h>
+
+#include <mce.h>
+#include <memctrl.h>
+#include <t18x_ari.h>
+#include <tegra_private.h>
+
+/*******************************************************************************
+ * 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;
+}
diff --git a/plat/nvidia/tegra/soc/t186/plat_smmu.c b/plat/nvidia/tegra/soc/t186/plat_smmu.c
new file mode 100644
index 0000000..f1bc235
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/plat_smmu.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+
+#include <smmu.h>
+#include <tegra_def.h>
+#include <tegra_mc_def.h>
+
+#define MAX_NUM_SMMU_DEVICES U(1)
+
+/*******************************************************************************
+ * Handler to return the support SMMU devices number
+ ******************************************************************************/
+uint32_t plat_get_num_smmu_devices(void)
+{
+ return MAX_NUM_SMMU_DEVICES;
+}
diff --git a/plat/nvidia/tegra/soc/t186/plat_trampoline.S b/plat/nvidia/tegra/soc/t186/plat_trampoline.S
new file mode 100644
index 0000000..2fc2046
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/plat_trampoline.S
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <memctrl_v2.h>
+#include <plat/common/common_def.h>
+#include <tegra_def.h>
+
+#define TEGRA186_MC_CTX_SIZE 0x93
+
+ .globl tegra186_get_mc_ctx_size
+
+ /*
+ * Tegra186 reset data (offset 0x0 - 0x420)
+ *
+ * 0x000: MC context start
+ * 0x420: MC context end
+ */
+
+ .align 4
+__tegra186_mc_context:
+ .rept TEGRA186_MC_CTX_SIZE
+ .quad 0
+ .endr
+
+ .align 4
+__tegra186_mc_context_end:
+
+/* return the size of the MC context */
+func tegra186_get_mc_ctx_size
+ adr x0, __tegra186_mc_context_end
+ adr x1, __tegra186_mc_context
+ sub x0, x0, x1
+ ret
+endfunc tegra186_get_mc_ctx_size
diff --git a/plat/nvidia/tegra/soc/t186/platform_t186.mk b/plat/nvidia/tegra/soc/t186/platform_t186.mk
new file mode 100644
index 0000000..5275b8e
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/platform_t186.mk
@@ -0,0 +1,77 @@
+#
+# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2020, NVIDIA Corporation. 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 := 0
+
+COLD_BOOT_SINGLE_CPU := 1
+
+RELOCATE_BL32_IMAGE := 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 := 25
+$(eval $(call add_define,MAX_XLAT_TABLES))
+
+MAX_MMAP_REGIONS := 30
+$(eval $(call add_define,MAX_MMAP_REGIONS))
+
+# platform files
+PLAT_INCLUDES += -Iplat/nvidia/tegra/include/t186 \
+ -I${SOC_DIR}/drivers/include
+
+BL31_SOURCES += ${TEGRA_GICv2_SOURCES} \
+ drivers/ti/uart/aarch64/16550_console.S \
+ lib/cpus/aarch64/denver.S \
+ lib/cpus/aarch64/cortex_a57.S \
+ ${TEGRA_DRIVERS}/bpmp_ipc/intf.c \
+ ${TEGRA_DRIVERS}/bpmp_ipc/ivc.c \
+ ${TEGRA_DRIVERS}/gpcdma/gpcdma.c \
+ ${TEGRA_DRIVERS}/memctrl/memctrl_v2.c \
+ ${TEGRA_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)/drivers/se/se.c \
+ ${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
+
+# Enable higher performance Non-cacheable load forwarding
+A57_ENABLE_NONCACHEABLE_LOAD_FWD := 1
diff --git a/plat/nvidia/tegra/soc/t194/drivers/include/mce_private.h b/plat/nvidia/tegra/soc/t194/drivers/include/mce_private.h
new file mode 100644
index 0000000..ef16980
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t194/drivers/include/mce_private.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MCE_PRIVATE_H
+#define MCE_PRIVATE_H
+
+#include <stdbool.h>
+#include <tegra_def.h>
+
+/*******************************************************************************
+ * Macros to prepare CSTATE info request
+ ******************************************************************************/
+/* Description of the parameters for UPDATE_CSTATE_INFO request */
+#define CLUSTER_CSTATE_MASK 0x7U
+#define CLUSTER_CSTATE_SHIFT 0X0U
+#define CLUSTER_CSTATE_UPDATE_BIT (1U << 7)
+#define CCPLEX_CSTATE_MASK 0x7U
+#define CCPLEX_CSTATE_SHIFT 8U
+#define CCPLEX_CSTATE_UPDATE_BIT (1U << 15)
+#define SYSTEM_CSTATE_MASK 0xFU
+#define SYSTEM_CSTATE_SHIFT 16U
+#define SYSTEM_CSTATE_UPDATE_BIT (1U << 23)
+#define CSTATE_WAKE_MASK_UPDATE_BIT (1U << 31)
+#define CSTATE_WAKE_MASK_SHIFT 32U
+#define CSTATE_WAKE_MASK_CLEAR 0xFFFFFFFFU
+
+/*******************************************************************************
+ * Core ID mask (bits 3:0 in the online request)
+ ******************************************************************************/
+#define MCE_CORE_ID_MASK 0xFU
+
+/*******************************************************************************
+ * C-state statistics macros
+ ******************************************************************************/
+#define MCE_STAT_ID_SHIFT 16U
+
+/*******************************************************************************
+ * Security config macros
+ ******************************************************************************/
+#define STRICT_CHECKING_ENABLED_SET (1UL << 0)
+#define STRICT_CHECKING_LOCKED_SET (1UL << 1)
+
+/* declarations for NVG handler functions */
+uint64_t nvg_get_version(void);
+void nvg_set_wake_time(uint32_t wake_time);
+void nvg_update_cstate_info(uint32_t cluster, uint32_t ccplex,
+ uint32_t system, uint32_t wake_mask, uint8_t update_wake_mask);
+int32_t nvg_set_cstate_stat_query_value(uint64_t data);
+uint64_t nvg_get_cstate_stat_query_value(void);
+int32_t nvg_is_sc7_allowed(void);
+int32_t nvg_online_core(uint32_t core);
+int32_t nvg_update_ccplex_gsc(uint32_t gsc_idx);
+int32_t nvg_enter_cstate(uint32_t state, uint32_t wake_time);
+int32_t nvg_roc_clean_cache_trbits(void);
+void nvg_enable_strict_checking_mode(void);
+void nvg_verify_strict_checking_mode(void);
+void nvg_system_shutdown(void);
+void nvg_system_reboot(void);
+void nvg_clear_hsm_corr_status(void);
+
+/* declarations for assembly functions */
+void nvg_set_request_data(uint64_t req, uint64_t data);
+void nvg_set_request(uint64_t req);
+uint64_t nvg_get_result(void);
+uint64_t nvg_cache_clean(void);
+uint64_t nvg_cache_clean_inval(void);
+uint64_t nvg_cache_inval_all(void);
+
+/* MCE helper functions */
+void mce_enable_strict_checking(void);
+void mce_verify_strict_checking(void);
+void mce_system_shutdown(void);
+void mce_system_reboot(void);
+void mce_clear_hsm_corr_status(void);
+
+#endif /* MCE_PRIVATE_H */
diff --git a/plat/nvidia/tegra/soc/t194/drivers/include/se.h b/plat/nvidia/tegra/soc/t194/drivers/include/se.h
new file mode 100644
index 0000000..7de55a7
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t194/drivers/include/se.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SE_H
+#define SE_H
+
+int32_t tegra_se_calculate_save_sha256(uint64_t src_addr,
+ uint32_t src_len_inbyte);
+int32_t tegra_se_suspend(void);
+void tegra_se_resume(void);
+
+#endif /* SE_H */
diff --git a/plat/nvidia/tegra/soc/t194/drivers/include/t194_nvg.h b/plat/nvidia/tegra/soc/t194/drivers/include/t194_nvg.h
new file mode 100644
index 0000000..7a68a43
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t194/drivers/include/t194_nvg.h
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef T194_NVG_H
+#define T194_NVG_H
+
+#include <lib/utils_def.h>
+
+/**
+ * t194_nvg.h - Header for the NVIDIA Generic interface (NVG).
+ * Official documentation for this interface is included as part
+ * of the T194 TRM.
+ */
+
+/**
+ * Current version - Major version increments may break backwards
+ * compatiblity and binary compatibility. Minor version increments
+ * occur when there is only new functionality.
+ */
+enum {
+ TEGRA_NVG_VERSION_MAJOR = U(6),
+ TEGRA_NVG_VERSION_MINOR = U(7)
+};
+
+typedef enum {
+ TEGRA_NVG_CHANNEL_VERSION = U(0),
+ TEGRA_NVG_CHANNEL_POWER_PERF = U(1),
+ TEGRA_NVG_CHANNEL_POWER_MODES = U(2),
+ TEGRA_NVG_CHANNEL_WAKE_TIME = U(3),
+ TEGRA_NVG_CHANNEL_CSTATE_INFO = U(4),
+ TEGRA_NVG_CHANNEL_CROSSOVER_C6_LOWER_BOUND = U(5),
+ TEGRA_NVG_CHANNEL_CROSSOVER_CC6_LOWER_BOUND = U(6),
+ TEGRA_NVG_CHANNEL_CROSSOVER_CG7_LOWER_BOUND = U(8),
+ TEGRA_NVG_CHANNEL_CSTATE_STAT_QUERY_REQUEST = U(10),
+ TEGRA_NVG_CHANNEL_CSTATE_STAT_QUERY_VALUE = U(11),
+ TEGRA_NVG_CHANNEL_NUM_CORES = U(20),
+ TEGRA_NVG_CHANNEL_UNIQUE_LOGICAL_ID = U(21),
+ TEGRA_NVG_CHANNEL_LOGICAL_TO_PHYSICAL_MAPPING = U(22),
+ TEGRA_NVG_CHANNEL_LOGICAL_TO_MPIDR = U(23),
+ TEGRA_NVG_CHANNEL_SHUTDOWN = U(42),
+ TEGRA_NVG_CHANNEL_IS_SC7_ALLOWED = U(43),
+ TEGRA_NVG_CHANNEL_ONLINE_CORE = U(44),
+ TEGRA_NVG_CHANNEL_CC3_CTRL = U(45),
+ TEGRA_NVG_CHANNEL_CCPLEX_CACHE_CONTROL = U(49),
+ TEGRA_NVG_CHANNEL_UPDATE_CCPLEX_GSC = U(50),
+ TEGRA_NVG_CHANNEL_HSM_ERROR_CTRL = U(53),
+ TEGRA_NVG_CHANNEL_SECURITY_CONFIG = U(54),
+ TEGRA_NVG_CHANNEL_DEBUG_CONFIG = U(55),
+ TEGRA_NVG_CHANNEL_DDA_SNOC_MCF = U(56),
+ TEGRA_NVG_CHANNEL_DDA_MCF_ORD1 = U(57),
+ TEGRA_NVG_CHANNEL_DDA_MCF_ORD2 = U(58),
+ TEGRA_NVG_CHANNEL_DDA_MCF_ORD3 = U(59),
+ TEGRA_NVG_CHANNEL_DDA_MCF_ISO = U(60),
+ TEGRA_NVG_CHANNEL_DDA_MCF_SISO = U(61),
+ TEGRA_NVG_CHANNEL_DDA_MCF_NISO = U(62),
+ TEGRA_NVG_CHANNEL_DDA_MCF_NISO_REMOTE = U(63),
+ TEGRA_NVG_CHANNEL_DDA_L3CTRL_ISO = U(64),
+ TEGRA_NVG_CHANNEL_DDA_L3CTRL_SISO = U(65),
+ TEGRA_NVG_CHANNEL_DDA_L3CTRL_NISO = U(66),
+ TEGRA_NVG_CHANNEL_DDA_L3CTRL_NISO_REMOTE = U(67),
+ TEGRA_NVG_CHANNEL_DDA_L3CTRL_L3FILL = U(68),
+ TEGRA_NVG_CHANNEL_DDA_L3CTRL_L3WR = U(69),
+ TEGRA_NVG_CHANNEL_DDA_L3CTRL_RSP_L3RD_DMA = U(70),
+ TEGRA_NVG_CHANNEL_DDA_L3CTRL_RSP_MCFRD_DMA = U(71),
+ TEGRA_NVG_CHANNEL_DDA_L3CTRL_GLOBAL = U(72),
+ TEGRA_NVG_CHANNEL_DDA_L3CTRL_LL = U(73),
+ TEGRA_NVG_CHANNEL_DDA_L3CTRL_L3D = U(74),
+ TEGRA_NVG_CHANNEL_DDA_L3CTRL_FCM_RD = U(75),
+ TEGRA_NVG_CHANNEL_DDA_L3CTRL_FCM_WR = U(76),
+ TEGRA_NVG_CHANNEL_DDA_SNOC_GLOBAL_CTRL = U(77),
+ TEGRA_NVG_CHANNEL_DDA_SNOC_CLIENT_REQ_CTRL = U(78),
+ TEGRA_NVG_CHANNEL_DDA_SNOC_CLIENT_REPLENTISH_CTRL = U(79),
+ TEGRA_NVG_CHANNEL_RT_SAFE_MASK = U(80),
+ TEGRA_NVG_CHANNEL_RT_WINDOW_US = U(81),
+ TEGRA_NVG_CHANNEL_RT_FWD_PROGRESS_US = U(82),
+
+ TEGRA_NVG_CHANNEL_LAST_INDEX
+} tegra_nvg_channel_id_t;
+
+typedef enum {
+ NVG_STAT_QUERY_SC7_ENTRIES = U(1),
+ NVG_STAT_QUERY_CC6_ENTRIES = U(6),
+ NVG_STAT_QUERY_CG7_ENTRIES = U(7),
+ NVG_STAT_QUERY_C6_ENTRIES = U(10),
+ NVG_STAT_QUERY_C7_ENTRIES = U(14),
+ NVG_STAT_QUERY_SC7_RESIDENCY_SUM = U(32),
+ NVG_STAT_QUERY_CC6_RESIDENCY_SUM = U(41),
+ NVG_STAT_QUERY_CG7_RESIDENCY_SUM = U(46),
+ NVG_STAT_QUERY_C6_RESIDENCY_SUM = U(51),
+ NVG_STAT_QUERY_C7_RESIDENCY_SUM = U(56),
+ NVG_STAT_QUERY_SC7_ENTRY_TIME_SUM = U(60),
+ NVG_STAT_QUERY_CC6_ENTRY_TIME_SUM = U(61),
+ NVG_STAT_QUERY_CG7_ENTRY_TIME_SUM = U(62),
+ NVG_STAT_QUERY_C6_ENTRY_TIME_SUM = U(63),
+ NVG_STAT_QUERY_C7_ENTRY_TIME_SUM = U(64),
+ NVG_STAT_QUERY_SC7_EXIT_TIME_SUM = U(70),
+ NVG_STAT_QUERY_CC6_EXIT_TIME_SUM = U(71),
+ NVG_STAT_QUERY_CG7_EXIT_TIME_SUM = U(72),
+ NVG_STAT_QUERY_C6_EXIT_TIME_SUM = U(73),
+ NVG_STAT_QUERY_C7_EXIT_TIME_SUM = U(74),
+ NVG_STAT_QUERY_SC7_ENTRY_LAST = U(80),
+ NVG_STAT_QUERY_CC6_ENTRY_LAST = U(81),
+ NVG_STAT_QUERY_CG7_ENTRY_LAST = U(82),
+ NVG_STAT_QUERY_C6_ENTRY_LAST = U(83),
+ NVG_STAT_QUERY_C7_ENTRY_LAST = U(84),
+ NVG_STAT_QUERY_SC7_EXIT_LAST = U(90),
+ NVG_STAT_QUERY_CC6_EXIT_LAST = U(91),
+ NVG_STAT_QUERY_CG7_EXIT_LAST = U(92),
+ NVG_STAT_QUERY_C6_EXIT_LAST = U(93),
+ NVG_STAT_QUERY_C7_EXIT_LAST = U(94)
+
+} tegra_nvg_stat_query_t;
+
+typedef enum {
+ TEGRA_NVG_CORE_C0 = U(0),
+ TEGRA_NVG_CORE_C1 = U(1),
+ TEGRA_NVG_CORE_C6 = U(6),
+ TEGRA_NVG_CORE_C7 = U(7),
+ TEGRA_NVG_CORE_WARMRSTREQ = U(8)
+} tegra_nvg_core_sleep_state_t;
+
+typedef enum {
+ TEGRA_NVG_SHUTDOWN = U(0),
+ TEGRA_NVG_REBOOT = U(1)
+} tegra_nvg_shutdown_reboot_state_t;
+
+typedef enum {
+ TEGRA_NVG_CLUSTER_CC0 = U(0),
+ TEGRA_NVG_CLUSTER_AUTO_CC1 = U(1),
+ TEGRA_NVG_CLUSTER_CC6 = U(6)
+} tegra_nvg_cluster_sleep_state_t;
+
+typedef enum {
+ TEGRA_NVG_CG_CG0 = U(0),
+ TEGRA_NVG_CG_CG7 = U(7)
+} tegra_nvg_cluster_group_sleep_state_t;
+
+typedef enum {
+ TEGRA_NVG_SYSTEM_SC0 = U(0),
+ TEGRA_NVG_SYSTEM_SC7 = U(7),
+ TEGRA_NVG_SYSTEM_SC8 = U(8)
+} tegra_nvg_system_sleep_state_t;
+
+// ---------------------------------------------------------------------------
+// NVG Data subformats
+// ---------------------------------------------------------------------------
+
+typedef union {
+ uint64_t flat;
+ struct nvg_version_channel_t {
+ uint32_t minor_version : U(32);
+ uint32_t major_version : U(32);
+ } bits;
+} nvg_version_data_t;
+
+typedef union {
+ uint64_t flat;
+ struct {
+ uint32_t perf_per_watt : U(1);
+ uint32_t reserved_31_1 : U(31);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_power_perf_channel_t;
+
+typedef union {
+ uint64_t flat;
+ struct {
+ uint32_t low_battery : U(1);
+ uint32_t reserved_1_1 : U(1);
+ uint32_t battery_save : U(1);
+ uint32_t reserved_31_3 : U(29);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_power_modes_channel_t;
+
+typedef union nvg_channel_1_data_u {
+ uint64_t flat;
+ struct nvg_channel_1_data_s {
+ uint32_t perf_per_watt_mode : U(1);
+ uint32_t reserved_31_1 : U(31);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_channel_1_data_t;
+
+typedef union {
+ uint64_t flat;
+ struct {
+ uint32_t gpu_ways : U(5);
+ uint32_t reserved_7_5 : U(3);
+ uint32_t gpu_only_ways : U(5);
+ uint32_t reserved_31_13 : U(19);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_ccplex_cache_control_channel_t;
+
+typedef union nvg_channel_2_data_u {
+ uint64_t flat;
+ struct nvg_channel_2_data_s {
+ uint32_t reserved_1_0 : U(2);
+ uint32_t battery_saver_mode : U(1);
+ uint32_t reserved_31_3 : U(29);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_channel_2_data_t;
+
+typedef union {
+ uint64_t flat;
+ struct {
+ uint32_t wake_time : U(32);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_wake_time_channel_t;
+
+typedef union {
+ uint64_t flat;
+ struct {
+ uint32_t cluster_state : U(3);
+ uint32_t reserved_6_3 : U(4);
+ uint32_t update_cluster : U(1);
+ uint32_t cg_cstate : U(3);
+ uint32_t reserved_14_11 : U(4);
+ uint32_t update_cg : U(1);
+ uint32_t system_cstate : U(4);
+ uint32_t reserved_22_20 : U(3);
+ uint32_t update_system : U(1);
+ uint32_t reserved_30_24 : U(7);
+ uint32_t update_wake_mask : U(1);
+ union {
+ uint32_t flat : U(32);
+ struct {
+ uint32_t vfiq : U(1);
+ uint32_t virq : U(1);
+ uint32_t fiq : U(1);
+ uint32_t irq : U(1);
+ uint32_t serror : U(1);
+ uint32_t reserved_10_5 : U(6);
+ uint32_t fiqout : U(1);
+ uint32_t irqout : U(1);
+ uint32_t reserved_31_13 : U(19);
+ } carmel;
+ } wake_mask;
+ } bits;
+} nvg_cstate_info_channel_t;
+
+typedef union {
+ uint64_t flat;
+ struct {
+ uint32_t crossover_value : U(32);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_lower_bound_channel_t;
+
+typedef union {
+ uint64_t flat;
+ struct {
+ uint32_t unit_id : U(4);
+ uint32_t reserved_15_4 : U(12);
+ uint32_t stat_id : U(16);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_cstate_stat_query_channel_t;
+
+typedef union {
+ uint64_t flat;
+ struct {
+ uint32_t num_cores : U(4);
+ uint32_t reserved_31_4 : U(28);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_num_cores_channel_t;
+
+typedef union {
+ uint64_t flat;
+ struct {
+ uint32_t unique_core_id : U(3);
+ uint32_t reserved_31_3 : U(29);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_unique_logical_id_channel_t;
+
+typedef union {
+ uint64_t flat;
+ struct {
+ uint32_t lcore0_pcore_id : U(4);
+ uint32_t lcore1_pcore_id : U(4);
+ uint32_t lcore2_pcore_id : U(4);
+ uint32_t lcore3_pcore_id : U(4);
+ uint32_t lcore4_pcore_id : U(4);
+ uint32_t lcore5_pcore_id : U(4);
+ uint32_t lcore6_pcore_id : U(4);
+ uint32_t lcore7_pcore_id : U(4);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_logical_to_physical_mappings_channel_t;
+
+typedef union {
+ uint64_t flat;
+ struct nvg_logical_to_mpidr_channel_write_t {
+ uint32_t lcore_id : U(3);
+ uint32_t reserved_31_3 : U(29);
+ uint32_t reserved_63_32 : U(32);
+ } write;
+ struct nvg_logical_to_mpidr_channel_read_t {
+ uint32_t mpidr : U(32);
+ uint32_t reserved_63_32 : U(32);
+ } read;
+} nvg_logical_to_mpidr_channel_t;
+
+typedef union {
+ uint64_t flat;
+ struct {
+ uint32_t is_sc7_allowed : U(1);
+ uint32_t reserved_31_1 : U(31);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_is_sc7_allowed_channel_t;
+
+typedef union {
+ uint64_t flat;
+ struct {
+ uint32_t core_id : U(4);
+ uint32_t reserved_31_4 : U(28);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_core_online_channel_t;
+
+typedef union {
+ uint64_t flat;
+ struct {
+ uint32_t freq_req : U(9);
+ uint32_t reserved_30_9 : U(22);
+ uint32_t enable : U(1);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_cc3_control_channel_t;
+
+typedef enum {
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_ALL = U(0),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_NVDEC = U(1),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_WPR1 = U(2),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_WPR2 = U(3),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_TSECA = U(4),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_TSECB = U(5),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_BPMP = U(6),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_APE = U(7),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_SPE = U(8),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_SCE = U(9),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_APR = U(10),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_TZRAM = U(11),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_IPC_SE_TSEC = U(12),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_BPMP_TO_RCE = U(13),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_BPMP_TO_MCE = U(14),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_SE_SC7 = U(15),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_BPMP_TO_SPE = U(16),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_RCE = U(17),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_CPU_TZ_TO_BPMP = U(18),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_VM_ENCR1 = U(19),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_CPU_NS_TO_BPMP = U(20),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_OEM_SC7 = U(21),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_IPC_SE_SPE_SCE_BPMP = U(22),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_SC7_RESUME_FW = U(23),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_CAMERA_TASKLIST = U(24),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_XUSB = U(25),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_CV = U(26),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_VM_ENCR2 = U(27),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_HYPERVISOR_SW = U(28),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_SMMU_PAGETABLES = U(29),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_30 = U(30),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_31 = U(31),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_TZ_DRAM = U(32),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_NVLINK = U(33),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_SBS = U(34),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_VPR = U(35),
+ TEGRA_NVG_CHANNEL_UPDATE_GSC_LAST_INDEX
+} tegra_nvg_channel_update_gsc_gsc_enum_t;
+
+typedef union {
+ uint64_t flat;
+ struct {
+ uint32_t gsc_enum : U(16);
+ uint32_t reserved_31_16 : U(16);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_update_ccplex_gsc_channel_t;
+
+typedef union {
+ uint64_t flat;
+ struct nvg_security_config_channel_t {
+ uint32_t strict_checking_enabled : U(1);
+ uint32_t strict_checking_locked : U(1);
+ uint32_t reserved_31_2 : U(30);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_security_config_t;
+
+typedef union {
+ uint64_t flat;
+ struct nvg_shutdown_channel_t {
+ uint32_t reboot : U(1);
+ uint32_t reserved_31_1 : U(31);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_shutdown_t;
+
+typedef union {
+ uint64_t flat;
+ struct nvg_debug_config_channel_t {
+ uint32_t enter_debug_state_on_mca : U(1);
+ uint32_t reserved_31_1 : U(31);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_debug_config_t;
+
+typedef union {
+ uint64_t flat;
+ struct {
+ uint32_t uncorr : U(1);
+ uint32_t corr : U(1);
+ uint32_t reserved_31_2 : U(30);
+ uint32_t reserved_63_32 : U(32);
+ } bits;
+} nvg_hsm_error_ctrl_channel_t;
+
+extern nvg_debug_config_t nvg_debug_config;
+
+#endif /* T194_NVG_H */
diff --git a/plat/nvidia/tegra/soc/t194/drivers/mce/aarch64/nvg_helpers.S b/plat/nvidia/tegra/soc/t194/drivers/mce/aarch64/nvg_helpers.S
new file mode 100644
index 0000000..3c47208
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t194/drivers/mce/aarch64/nvg_helpers.S
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+ .globl nvg_set_request_data
+ .globl nvg_set_request
+ .globl nvg_get_result
+ .globl nvg_cache_clean
+ .globl nvg_cache_clean_inval
+ .globl nvg_cache_inval_all
+
+/* 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
+
+/* uint64_t nvg_cache_clean(void) */
+func nvg_cache_clean
+ mrs x0, s3_0_c15_c3_5
+ ret
+endfunc nvg_cache_clean
+
+/* uint64_t nvg_cache_clean_inval(void) */
+func nvg_cache_clean_inval
+ mrs x0, s3_0_c15_c3_6
+ ret
+endfunc nvg_cache_clean_inval
+
+/* uint64_t nvg_cache_inval_all(void) */
+func nvg_cache_inval_all
+ mrs x0, s3_0_c15_c3_7
+ ret
+endfunc nvg_cache_inval_all \ No newline at end of file
diff --git a/plat/nvidia/tegra/soc/t194/drivers/mce/mce.c b/plat/nvidia/tegra/soc/t194/drivers/mce/mce.c
new file mode 100644
index 0000000..af1c0aa
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t194/drivers/mce/mce.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/bl_common.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <common/debug.h>
+#include <denver.h>
+#include <mce.h>
+#include <mce_private.h>
+#include <platform_def.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <t194_nvg.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+/* Handler to check if MCE firmware is supported */
+static bool mce_firmware_not_supported(void)
+{
+ bool status;
+
+ /* these platforms do not load MCE firmware */
+ status = tegra_platform_is_linsim() || tegra_platform_is_qt() ||
+ tegra_platform_is_virt_dev_kit();
+
+ return status;
+}
+
+/*******************************************************************************
+ * Common handler for all MCE commands
+ ******************************************************************************/
+int32_t mce_command_handler(uint64_t cmd, uint64_t arg0, uint64_t arg1,
+ uint64_t arg2)
+{
+ int32_t ret = 0;
+
+ switch (cmd) {
+ case (uint64_t)MCE_CMD_ENTER_CSTATE:
+ ret = nvg_enter_cstate((uint32_t)arg0, (uint32_t)arg1);
+ if (ret < 0) {
+ ERROR("%s: enter_cstate failed(%d)\n", __func__, ret);
+ }
+
+ break;
+
+ case (uint64_t)MCE_CMD_IS_SC7_ALLOWED:
+ ret = nvg_is_sc7_allowed();
+ if (ret < 0) {
+ ERROR("%s: is_sc7_allowed failed(%d)\n", __func__, ret);
+ }
+
+ break;
+
+ case (uint64_t)MCE_CMD_ONLINE_CORE:
+ ret = nvg_online_core((uint32_t)arg0);
+ if (ret < 0) {
+ ERROR("%s: online_core failed(%d)\n", __func__, ret);
+ }
+
+ break;
+
+ default:
+ ERROR("unknown MCE command (%" PRIu64 ")\n", cmd);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ * Handler to update carveout values for Video Memory Carveout region
+ ******************************************************************************/
+int32_t mce_update_gsc_videomem(void)
+{
+ int32_t ret;
+
+ /*
+ * MCE firmware is not running on simulation platforms.
+ */
+ if (mce_firmware_not_supported()) {
+ ret = -EINVAL;
+ } else {
+ ret = nvg_update_ccplex_gsc((uint32_t)TEGRA_NVG_CHANNEL_UPDATE_GSC_VPR);
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ * Handler to update carveout values for TZDRAM aperture
+ ******************************************************************************/
+int32_t mce_update_gsc_tzdram(void)
+{
+ int32_t ret;
+
+ /*
+ * MCE firmware is not running on simulation platforms.
+ */
+ if (mce_firmware_not_supported()) {
+ ret = -EINVAL;
+ } else {
+ ret = nvg_update_ccplex_gsc((uint32_t)TEGRA_NVG_CHANNEL_UPDATE_GSC_TZ_DRAM);
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ * Handler to issue the UPDATE_CSTATE_INFO request
+ ******************************************************************************/
+void mce_update_cstate_info(const mce_cstate_info_t *cstate)
+{
+ /* issue the UPDATE_CSTATE_INFO request */
+ nvg_update_cstate_info(cstate->cluster, cstate->ccplex, cstate->system,
+ 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)
+{
+ uint64_t version;
+ uint32_t major, minor;
+
+ /*
+ * MCE firmware is not running on simulation platforms.
+ */
+ if (mce_firmware_not_supported()) {
+ return;
+ }
+
+ /*
+ * Read the MCE firmware version and extract the major and minor
+ * version fields
+ */
+ version = nvg_get_version();
+ minor = (uint32_t)version;
+ major = (uint32_t)(version >> 32);
+
+ INFO("MCE Version - HW=%u:%u, SW=%u:%u\n", major, minor,
+ TEGRA_NVG_VERSION_MAJOR, TEGRA_NVG_VERSION_MINOR);
+
+ /*
+ * Verify that the MCE firmware version and the interface header
+ * match
+ */
+ if (major != (uint32_t)TEGRA_NVG_VERSION_MAJOR) {
+ ERROR("MCE major version mismatch\n");
+ panic();
+ }
+
+ if (minor < (uint32_t)TEGRA_NVG_VERSION_MINOR) {
+ ERROR("MCE minor version mismatch\n");
+ panic();
+ }
+}
+
+#if ENABLE_STRICT_CHECKING_MODE
+/*******************************************************************************
+ * Handler to enable the strict checking mode
+ ******************************************************************************/
+void mce_enable_strict_checking(void)
+{
+ uint64_t sctlr = read_sctlr_el3();
+ int32_t ret = 0;
+
+ if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) {
+ /*
+ * Step1: TZ-DRAM and TZRAM should be setup before the MMU is
+ * enabled.
+ *
+ * The common code makes sure that TZDRAM/TZRAM are already
+ * enabled before calling into this handler. If this is not the
+ * case, the following sequence must be executed before moving
+ * on to step 2.
+ *
+ * tlbialle1is();
+ * tlbialle3is();
+ * dsbsy();
+ * isb();
+ *
+ */
+ if ((sctlr & (uint64_t)SCTLR_M_BIT) == (uint64_t)SCTLR_M_BIT) {
+ tlbialle1is();
+ tlbialle3is();
+ dsbsy();
+ isb();
+ }
+
+ /*
+ * Step2: SCF flush - Clean and invalidate caches and clear the
+ * TR-bits
+ */
+ ret = nvg_roc_clean_cache_trbits();
+ if (ret < 0) {
+ ERROR("%s: flush cache_trbits failed(%d)\n", __func__,
+ ret);
+ return;
+ }
+
+ /*
+ * Step3: Issue the SECURITY_CONFIG request to MCE to enable
+ * strict checking mode.
+ */
+ nvg_enable_strict_checking_mode();
+ }
+}
+void mce_verify_strict_checking(void)
+{
+ bool is_silicon = tegra_platform_is_silicon();
+ bool is_fpga = tegra_platform_is_fpga();
+
+ if (is_silicon || is_fpga) {
+ nvg_verify_strict_checking_mode();
+ }
+}
+#endif
+
+/*******************************************************************************
+ * Handler to power down the entire system
+ ******************************************************************************/
+void mce_system_shutdown(void)
+{
+ nvg_system_shutdown();
+}
+
+/*******************************************************************************
+ * Handler to reboot the entire system
+ ******************************************************************************/
+void mce_system_reboot(void)
+{
+ nvg_system_reboot();
+}
+
+/*******************************************************************************
+ * Handler to clear CCPLEX->HSM correctable RAS error signal.
+ ******************************************************************************/
+void mce_clear_hsm_corr_status(void)
+{
+ nvg_clear_hsm_corr_status();
+}
diff --git a/plat/nvidia/tegra/soc/t194/drivers/mce/nvg.c b/plat/nvidia/tegra/soc/t194/drivers/mce/nvg.c
new file mode 100644
index 0000000..f76ab14
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t194/drivers/mce/nvg.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <denver.h>
+#include <lib/mmio.h>
+
+#include <mce_private.h>
+#include <platform_def.h>
+#include <t194_nvg.h>
+#include <tegra_private.h>
+
+#define ID_AFR0_EL1_CACHE_OPS_SHIFT U(12)
+#define ID_AFR0_EL1_CACHE_OPS_MASK U(0xF)
+/*
+ * Reports the major and minor version of this interface.
+ *
+ * NVGDATA[0:31]: SW(R) Minor Version
+ * NVGDATA[32:63]: SW(R) Major Version
+ */
+uint64_t nvg_get_version(void)
+{
+ nvg_set_request((uint64_t)TEGRA_NVG_CHANNEL_VERSION);
+
+ return (uint64_t)nvg_get_result();
+}
+
+/*
+ * Set the expected wake time in TSC ticks for the next low-power state the
+ * core enters.
+ *
+ * NVGDATA[0:31]: SW(RW), WAKE_TIME
+ */
+void nvg_set_wake_time(uint32_t wake_time)
+{
+ /* time (TSC ticks) until the core is expected to get a wake event */
+ nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_WAKE_TIME, (uint64_t)wake_time);
+}
+
+/*
+ * This request allows updating of CLUSTER_CSTATE, CCPLEX_CSTATE and
+ * SYSTEM_CSTATE values.
+ *
+ * NVGDATA[0:2]: SW(RW), CLUSTER_CSTATE
+ * NVGDATA[7]: SW(W), update cluster flag
+ * NVGDATA[8:10]: SW(RW), CG_CSTATE
+ * NVGDATA[15]: SW(W), update ccplex flag
+ * NVGDATA[16:19]: SW(RW), SYSTEM_CSTATE
+ * NVGDATA[23]: SW(W), update system flag
+ * NVGDATA[31]: SW(W), update wake mask flag
+ * NVGDATA[32:63]: SW(RW), WAKE_MASK
+ */
+void nvg_update_cstate_info(uint32_t cluster, uint32_t ccplex,
+ uint32_t system, uint32_t wake_mask, uint8_t update_wake_mask)
+{
+ uint64_t val = 0;
+
+ /* 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) |
+ SYSTEM_CSTATE_UPDATE_BIT;
+ }
+
+ /* update wake mask value? */
+ if (update_wake_mask != 0U) {
+ val |= CSTATE_WAKE_MASK_UPDATE_BIT;
+ }
+
+ /* set the wake mask */
+ val |= ((uint64_t)wake_mask & CSTATE_WAKE_MASK_CLEAR) << CSTATE_WAKE_MASK_SHIFT;
+
+ /* set the updated cstate info */
+ nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_CSTATE_INFO, val);
+}
+
+/*
+ * Return a non-zero value if the CCPLEX is able to enter SC7
+ *
+ * NVGDATA[0]: SW(R), Is allowed result
+ */
+int32_t nvg_is_sc7_allowed(void)
+{
+ /* issue command to check if SC7 is allowed */
+ nvg_set_request((uint64_t)TEGRA_NVG_CHANNEL_IS_SC7_ALLOWED);
+
+ /* 1 = SC7 allowed, 0 = SC7 not allowed */
+ return (int32_t)nvg_get_result();
+}
+
+/*
+ * Wake an offlined logical core. Note that a core is offlined by entering
+ * a C-state where the WAKE_MASK is all 0.
+ *
+ * NVGDATA[0:3]: SW(W) logical core to online
+ */
+int32_t nvg_online_core(uint32_t core)
+{
+ int32_t ret = 0;
+
+ /* sanity check the core ID value */
+ if (core > (uint32_t)PLATFORM_CORE_COUNT) {
+ 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;
+}
+
+/*
+ * MC GSC (General Security Carveout) register values are expected to be
+ * changed by TrustZone ARM code after boot.
+ *
+ * NVGDATA[0:15] SW(R) GSC enun
+ */
+int32_t nvg_update_ccplex_gsc(uint32_t gsc_idx)
+{
+ int32_t ret = 0;
+
+ /* sanity check GSC ID */
+ if (gsc_idx > (uint32_t)TEGRA_NVG_CHANNEL_UPDATE_GSC_VPR) {
+ ERROR("%s: unknown gsc_idx (%u)\n", __func__, gsc_idx);
+ ret = -EINVAL;
+ } else {
+ nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_UPDATE_CCPLEX_GSC,
+ (uint64_t)gsc_idx);
+ }
+
+ return ret;
+}
+
+/*
+ * Cache clean and invalidate, clear TR-bit operation for all CCPLEX caches.
+ */
+int32_t nvg_roc_clean_cache_trbits(void)
+{
+ int32_t ret = 0;
+
+ /* check if cache flush through mts is supported */
+ if (((read_id_afr0_el1() >> ID_AFR0_EL1_CACHE_OPS_SHIFT) &
+ ID_AFR0_EL1_CACHE_OPS_MASK) == 1U) {
+ if (nvg_cache_inval_all() == 0U) {
+ ERROR("%s: failed\n", __func__);
+ ret = -ENODEV;
+ }
+ } else {
+ ret = -ENOTSUP;
+ }
+
+ return ret;
+}
+
+/*
+ * Set the power state for a core
+ */
+int32_t nvg_enter_cstate(uint32_t state, uint32_t wake_time)
+{
+ int32_t ret = 0;
+ uint64_t val = 0ULL;
+
+ /* check for allowed power state */
+ if ((state != (uint32_t)TEGRA_NVG_CORE_C0) &&
+ (state != (uint32_t)TEGRA_NVG_CORE_C1) &&
+ (state != (uint32_t)TEGRA_NVG_CORE_C6) &&
+ (state != (uint32_t)TEGRA_NVG_CORE_C7))
+ {
+ ERROR("%s: unknown cstate (%u)\n", __func__, state);
+ ret = -EINVAL;
+ } else {
+ /* time (TSC ticks) until the core is expected to get a wake event */
+ nvg_set_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;
+}
+
+#if ENABLE_STRICT_CHECKING_MODE
+/*
+ * Enable strict checking mode
+ *
+ * NVGDATA[3] strict_check ON + lock
+ */
+void nvg_enable_strict_checking_mode(void)
+{
+ uint64_t params = (uint64_t)(STRICT_CHECKING_ENABLED_SET |
+ STRICT_CHECKING_LOCKED_SET);
+
+ nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_SECURITY_CONFIG, params);
+}
+
+void nvg_verify_strict_checking_mode(void)
+{
+ uint64_t params = (uint64_t)(STRICT_CHECKING_ENABLED_SET |
+ STRICT_CHECKING_LOCKED_SET);
+
+ nvg_set_request((uint64_t)TEGRA_NVG_CHANNEL_SECURITY_CONFIG);
+ assert(params == (uint64_t)nvg_get_result());
+}
+#endif
+
+/*
+ * Request a reboot
+ *
+ * NVGDATA[0]: reboot command
+ */
+void nvg_system_reboot(void)
+{
+ /* issue command for reboot */
+ nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_SHUTDOWN,
+ (uint64_t)TEGRA_NVG_REBOOT);
+}
+
+/*
+ * Request a shutdown
+ *
+ * NVGDATA[0]: shutdown command
+ */
+void nvg_system_shutdown(void)
+{
+ /* issue command for shutdown */
+ nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_SHUTDOWN,
+ (uint64_t)TEGRA_NVG_SHUTDOWN);
+}
+
+/*
+ * Request to clear CCPLEX->HSM correctable error signal.
+ * NVGDATA[1]: A write of 1 clears the CCPLEX->HSM correctable error signal,
+ * A write of 0 has no effect.
+ */
+void nvg_clear_hsm_corr_status(void)
+{
+ nvg_hsm_error_ctrl_channel_t status = { .bits = { .corr = 1U, }, };
+
+ nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_HSM_ERROR_CTRL, status.flat);
+}
diff --git a/plat/nvidia/tegra/soc/t194/drivers/se/se.c b/plat/nvidia/tegra/soc/t194/drivers/se/se.c
new file mode 100644
index 0000000..31b0e26
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t194/drivers/se/se.c
@@ -0,0 +1,511 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+#include <bpmp_ipc.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <se.h>
+#include <tegra_platform.h>
+
+#include "se_private.h"
+
+/*******************************************************************************
+ * Constants and Macros
+ ******************************************************************************/
+#define ERR_STATUS_SW_CLEAR U(0xFFFFFFFF)
+#define INT_STATUS_SW_CLEAR U(0xFFFFFFFF)
+#define MAX_TIMEOUT_MS U(1000) /* Max. timeout of 1s */
+#define NUM_SE_REGS_TO_SAVE U(4)
+
+#define BYTES_IN_WORD U(4)
+#define SHA256_MAX_HASH_RESULT U(7)
+#define SHA256_DST_SIZE U(32)
+#define SHA_FIRST_OP U(1)
+#define MAX_SHA_ENGINE_CHUNK_SIZE U(0xFFFFFF)
+#define SHA256_MSG_LENGTH_ONETIME U(0xFFFF)
+
+/*******************************************************************************
+ * Data structure and global variables
+ ******************************************************************************/
+static uint32_t se_regs[NUM_SE_REGS_TO_SAVE];
+
+/*
+ * 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_STATUS = IDLE
+ * 2. AHB bus data transfer is complete.
+ * 3. SE_ERR_STATUS is clean.
+ */
+static bool tegra_se_is_operation_complete(void)
+{
+ uint32_t val = 0, timeout = 0, sha_status, aes_status;
+ int32_t ret = 0;
+ bool se_is_busy, txn_has_errors, txn_successful;
+
+ /*
+ * Poll the status register to check if the operation
+ * completed.
+ */
+ do {
+ val = tegra_se_read_32(CTX_SAVE_AUTO_STATUS);
+ se_is_busy = ((val & CTX_SAVE_AUTO_SE_BUSY) != 0U);
+
+ /* sleep until SE finishes */
+ if (se_is_busy) {
+ mdelay(1);
+ timeout++;
+ }
+
+ } while (se_is_busy && (timeout < MAX_TIMEOUT_MS));
+
+ /* any transaction errors? */
+ txn_has_errors = (tegra_se_read_32(SHA_ERR_STATUS) != 0U) ||
+ (tegra_se_read_32(AES0_ERR_STATUS) != 0U);
+
+ /* transaction successful? */
+ sha_status = tegra_se_read_32(SHA_INT_STATUS) & SHA_SE_OP_DONE;
+ aes_status = tegra_se_read_32(AES0_INT_STATUS) & AES0_SE_OP_DONE;
+ txn_successful = (sha_status == SHA_SE_OP_DONE) &&
+ (aes_status == AES0_SE_OP_DONE);
+
+ if ((timeout == MAX_TIMEOUT_MS) || txn_has_errors || !txn_successful) {
+ ERROR("%s: Atomic context save operation failed!\n",
+ __func__);
+ ret = -ECANCELED;
+ }
+
+ return (ret == 0);
+}
+
+/*
+ * Wait for SE engine to be idle and clear any pending interrupts, before
+ * starting the next SE operation.
+ */
+static bool tegra_se_is_ready(void)
+{
+ int32_t ret = 0;
+ uint32_t val = 0, timeout = 0;
+ bool se_is_ready;
+
+ /* Wait for previous operation to finish */
+ do {
+ val = tegra_se_read_32(CTX_SAVE_AUTO_STATUS);
+ se_is_ready = (val == CTX_SAVE_AUTO_SE_READY);
+
+ /* sleep until SE is ready */
+ if (!se_is_ready) {
+ mdelay(1);
+ timeout++;
+ }
+
+ } while (!se_is_ready && (timeout < MAX_TIMEOUT_MS));
+
+ if (timeout == MAX_TIMEOUT_MS) {
+ ERROR("%s: SE is not ready!\n", __func__);
+ ret = -ETIMEDOUT;
+ }
+
+ /* Clear any pending interrupts from previous operation */
+ tegra_se_write_32(AES0_INT_STATUS, INT_STATUS_SW_CLEAR);
+ tegra_se_write_32(AES1_INT_STATUS, INT_STATUS_SW_CLEAR);
+ tegra_se_write_32(RSA_INT_STATUS, INT_STATUS_SW_CLEAR);
+ tegra_se_write_32(SHA_INT_STATUS, INT_STATUS_SW_CLEAR);
+
+ /* Clear error status for each engine seen from current port */
+ tegra_se_write_32(AES0_ERR_STATUS, ERR_STATUS_SW_CLEAR);
+ tegra_se_write_32(AES1_ERR_STATUS, ERR_STATUS_SW_CLEAR);
+ tegra_se_write_32(RSA_ERR_STATUS, ERR_STATUS_SW_CLEAR);
+ tegra_se_write_32(SHA_ERR_STATUS, ERR_STATUS_SW_CLEAR);
+
+ return (ret == 0);
+}
+
+/*
+ * During System Suspend, this handler triggers the hardware context
+ * save operation.
+ */
+static int32_t tegra_se_save_context(void)
+{
+ int32_t ret = -ECANCELED;
+
+ /*
+ * 1. Ensure all SE Driver including RNG1/PKA1 are shut down.
+ * TSEC/R5s are powergated/idle. All tasks on SE1~SE4, RNG1,
+ * PKA1 are wrapped up. SE0 is ready for use.
+ * 2. Clear interrupt/error in SE0 status register.
+ * 3. Scrub SE0 register to avoid false failure for illegal
+ * configuration. Probably not needed, dependent on HW
+ * implementation.
+ * 4. Check SE is ready for HW CTX_SAVE by polling
+ * SE_CTX_SAVE_AUTO_STATUS.SE_READY.
+ *
+ * Steps 1-4 are executed by tegra_se_is_ready().
+ *
+ * 5. Issue context save command.
+ * 6. Check SE is busy with CTX_SAVE, the command in step5 was not
+ * dropped for ongoing traffic in any of SE port/engine.
+ * 7. Poll SE register or wait for SE APB interrupt for task completion
+ * a. Polling: Read SE_CTX_SAVE_AUTO_STATUS.BUSY till it reports IDLE
+ * b. Interrupt: After receiving interrupt from SE APB, read
+ * SE_CTX_SAVE_AUTO_STATUS.BUSY till it reports IDLE.
+ * 8. Check AES0 and SHA ERR_STATUS to ensure no error case.
+ * 9. Check AES0 and SHA INT_STATUS to ensure operation has successfully
+ * completed.
+ *
+ * Steps 6-9 are executed by tegra_se_is_operation_complete().
+ */
+ if (tegra_se_is_ready()) {
+
+ /* Issue context save command */
+ tegra_se_write_32(AES0_OPERATION, SE_OP_CTX_SAVE);
+
+ /* Wait for operation to finish */
+ if (tegra_se_is_operation_complete()) {
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * 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. SE0_INT_STATUS = SE0_OP_DONE
+ * 2. SE0_STATUS = IDLE
+ * 3. SE0_ERR_STATUS is clean.
+ */
+static int32_t tegra_se_sha256_hash_operation_complete(void)
+{
+ uint32_t val = 0U;
+
+ /* Poll the SE interrupt register to ensure H/W operation complete */
+ val = tegra_se_read_32(SE0_INT_STATUS_REG_OFFSET);
+ while (SE0_INT_OP_DONE(val) == SE0_INT_OP_DONE_CLEAR) {
+ val = tegra_se_read_32(SE0_INT_STATUS_REG_OFFSET);
+ if (SE0_INT_OP_DONE(val) != SE0_INT_OP_DONE_CLEAR) {
+ break;
+ }
+ }
+
+ /* Poll the SE status idle to ensure H/W operation complete */
+ val = tegra_se_read_32(SE0_SHA_STATUS_0);
+ while (val != SE0_SHA_STATUS_IDLE) {
+ val = tegra_se_read_32(SE0_SHA_STATUS_0);
+ if (val == SE0_SHA_STATUS_IDLE) {
+ break;
+ }
+ }
+
+ /* Ensure that no errors are thrown during operation */
+ val = tegra_se_read_32(SE0_ERR_STATUS_REG_OFFSET);
+ if (val != 0U) {
+ ERROR("%s: error during SE operation! 0x%x", __func__,
+ val);
+ return -ENOTSUP;
+ }
+
+ return 0;
+}
+
+/*
+ * Security engine primitive normal operations
+ */
+static int32_t tegra_se_start_normal_operation(uint64_t src_addr,
+ uint32_t nbytes, uint32_t last_buf, uint32_t src_len_inbytes)
+{
+ uint32_t val = 0U;
+ uint32_t src_in_lo;
+ uint32_t src_in_msb;
+ uint32_t src_in_hi;
+ int32_t ret = 0;
+
+ if ((src_addr == 0ULL) || (nbytes == 0U))
+ return -EINVAL;
+
+ src_in_lo = (uint32_t)src_addr;
+ src_in_msb = (uint32_t)((src_addr >> 32U) & 0xFFU);
+ src_in_hi = ((src_in_msb << SE0_IN_HI_ADDR_HI_0_MSB_SHIFT) |
+ (nbytes & MAX_SHA_ENGINE_CHUNK_SIZE));
+
+ /* set SRC_IN_ADDR_LO and SRC_IN_ADDR_HI*/
+ tegra_se_write_32(SE0_IN_ADDR, src_in_lo);
+ tegra_se_write_32(SE0_IN_HI_ADDR_HI, src_in_hi);
+
+ val = tegra_se_read_32(SE0_INT_STATUS_REG_OFFSET);
+ if (val > 0U) {
+ tegra_se_write_32(SE0_INT_STATUS_REG_OFFSET, 0x0U);
+ }
+
+ /* Enable SHA interrupt for SE0 Operation */
+ tegra_se_write_32(SE0_SHA_INT_ENABLE, 0x1aU);
+
+ /* flush to DRAM for SE to use the updated contents */
+ flush_dcache_range(src_addr, src_len_inbytes);
+
+ /* Start SHA256 operation */
+ if (last_buf == 1U) {
+ tegra_se_write_32(SE0_OPERATION_REG_OFFSET, SE0_OP_START |
+ SE0_UNIT_OPERATION_PKT_LASTBUF_FIELD);
+ } else {
+ tegra_se_write_32(SE0_OPERATION_REG_OFFSET, SE0_OP_START);
+ }
+
+ return ret;
+}
+
+static int32_t tegra_se_calculate_sha256_hash(uint64_t src_addr,
+ uint32_t src_len_inbyte)
+{
+ uint32_t val, last_buf, i;
+ int32_t ret = 0;
+ uint32_t operations;
+ uint64_t src_len_inbits;
+ uint32_t len_bits_msb;
+ uint32_t len_bits_lsb;
+ uint32_t number_of_operations, max_bytes, bytes_left, remaining_bytes;
+
+ if (src_len_inbyte > MAX_SHA_ENGINE_CHUNK_SIZE) {
+ ERROR("SHA input chunk size too big: 0x%x\n", src_len_inbyte);
+ return -EINVAL;
+ }
+
+ if (src_addr == 0ULL) {
+ return -EINVAL;
+ }
+
+ /* number of bytes per operation */
+ max_bytes = (SHA256_HASH_SIZE_BYTES * SHA256_MSG_LENGTH_ONETIME);
+
+ src_len_inbits = (uint32_t)(src_len_inbyte * 8U);
+ len_bits_msb = (uint32_t)(src_len_inbits >> 32U);
+ len_bits_lsb = (uint32_t)src_len_inbits;
+
+ /* program SE0_CONFIG for SHA256 operation */
+ val = (uint32_t)(SE0_CONFIG_ENC_ALG_SHA | SE0_CONFIG_ENC_MODE_SHA256 |
+ SE0_CONFIG_DEC_ALG_NOP | SE0_CONFIG_DST_HASHREG);
+ tegra_se_write_32(SE0_SHA_CONFIG, val);
+
+ /* set SE0_SHA_MSG_LENGTH registers */
+ tegra_se_write_32(SE0_SHA_MSG_LENGTH_0, len_bits_lsb);
+ tegra_se_write_32(SE0_SHA_MSG_LEFT_0, len_bits_lsb);
+ tegra_se_write_32(SE0_SHA_MSG_LENGTH_1, len_bits_msb);
+
+ /* zero out unused SE0_SHA_MSG_LENGTH and SE0_SHA_MSG_LEFT */
+ tegra_se_write_32(SE0_SHA_MSG_LENGTH_2, 0U);
+ tegra_se_write_32(SE0_SHA_MSG_LENGTH_3, 0U);
+ tegra_se_write_32(SE0_SHA_MSG_LEFT_1, 0U);
+ tegra_se_write_32(SE0_SHA_MSG_LEFT_2, 0U);
+ tegra_se_write_32(SE0_SHA_MSG_LEFT_3, 0U);
+
+ number_of_operations = (src_len_inbyte / max_bytes);
+ remaining_bytes = (src_len_inbyte % max_bytes);
+ if (remaining_bytes > 0U) {
+ number_of_operations += 1U;
+ }
+
+ /*
+ * 1. Operations == 1: program SE0_SHA_TASK register to initiate SHA256
+ * hash generation by setting
+ * 1(SE0_SHA_CONFIG_HW_INIT_HASH) to SE0_SHA_TASK
+ * and start SHA256-normal operation.
+ * 2. 1 < Operations < number_of_operations: program SE0_SHA_TASK to
+ * 0(SE0_SHA_CONFIG_HW_INIT_HASH_DISABLE) to load
+ * intermediate SHA256 digest result from
+ * HASH_RESULT register to continue SHA256
+ * generation and start SHA256-normal operation.
+ * 3. Operations == number_of_operations: continue with step 2 and set
+ * max_bytes to bytes_left to process final
+ * hash-result generation and start SHA256-normal
+ * operation.
+ */
+ bytes_left = src_len_inbyte;
+ for (operations = 1U; operations <= number_of_operations;
+ operations++) {
+ if (operations == SHA_FIRST_OP) {
+ val = SE0_SHA_CONFIG_HW_INIT_HASH;
+ } else {
+ /* Load intermediate SHA digest result to
+ * SHA:HASH_RESULT(0..7) to continue the SHA
+ * calculation and tell the SHA engine to use it.
+ */
+ for (i = 0U; (i / BYTES_IN_WORD) <=
+ SHA256_MAX_HASH_RESULT; i += BYTES_IN_WORD) {
+ val = tegra_se_read_32(SE0_SHA_HASH_RESULT_0 +
+ i);
+ tegra_se_write_32(SE0_SHA_HASH_RESULT_0 + i,
+ val);
+ }
+ val = SE0_SHA_CONFIG_HW_INIT_HASH_DISABLE;
+ if (len_bits_lsb <= (max_bytes * 8U)) {
+ len_bits_lsb = (remaining_bytes * 8U);
+ } else {
+ len_bits_lsb -= (max_bytes * 8U);
+ }
+ tegra_se_write_32(SE0_SHA_MSG_LEFT_0, len_bits_lsb);
+ }
+ tegra_se_write_32(SE0_SHA_TASK_CONFIG, val);
+
+ max_bytes = (SHA256_HASH_SIZE_BYTES *
+ SHA256_MSG_LENGTH_ONETIME);
+ if (bytes_left < max_bytes) {
+ max_bytes = bytes_left;
+ last_buf = 1U;
+ } else {
+ bytes_left = bytes_left - max_bytes;
+ last_buf = 0U;
+ }
+ /* start operation */
+ ret = tegra_se_start_normal_operation(src_addr, max_bytes,
+ last_buf, src_len_inbyte);
+ if (ret != 0) {
+ ERROR("Error during SE operation! 0x%x", ret);
+ return -EINVAL;
+ }
+ }
+
+ return ret;
+}
+
+static int32_t tegra_se_save_sha256_pmc_scratch(void)
+{
+ uint32_t val = 0U, hash_offset = 0U, scratch_offset = 0U;
+ int32_t ret;
+
+ /* Check SE0 operation status */
+ ret = tegra_se_sha256_hash_operation_complete();
+ if (ret != 0) {
+ ERROR("SE operation complete Failed! 0x%x", ret);
+ return ret;
+ }
+
+ for (scratch_offset = SECURE_SCRATCH_TZDRAM_SHA256_HASH_START;
+ scratch_offset <= SECURE_SCRATCH_TZDRAM_SHA256_HASH_END;
+ scratch_offset += BYTES_IN_WORD) {
+ val = tegra_se_read_32(SE0_SHA_HASH_RESULT_0 + hash_offset);
+ mmio_write_32((uint32_t)(TEGRA_SCRATCH_BASE + scratch_offset),
+ val);
+ hash_offset += BYTES_IN_WORD;
+ }
+ return 0;
+}
+
+/*
+ * Handler to generate SHA256 and save HASH-result to pmc-scratch register
+ */
+int32_t tegra_se_calculate_save_sha256(uint64_t src_addr,
+ uint32_t src_len_inbyte)
+{
+ uint32_t security;
+ int32_t val = 0;
+
+ /* Set SE_SOFT_SETTINGS=SE_SECURE to prevent NS process to change SE
+ * registers.
+ */
+ security = tegra_se_read_32(SE0_SECURITY);
+ tegra_se_write_32(SE0_SECURITY, security | SE0_SECURITY_SE_SOFT_SETTING);
+
+ /* Bootrom enable IN_ID bit in SE0_SHA_GSCID_0 register during SC7-exit, causing
+ * SE0 ignores SE0 operation, and therefore failure of 2nd iteration of SC7 cycle.
+ */
+ tegra_se_write_32(SE0_SHA_GSCID_0, 0x0U);
+
+ /* Calculate SHA256 of BL31 */
+ val = tegra_se_calculate_sha256_hash(src_addr, src_len_inbyte);
+ if (val != 0) {
+ ERROR("%s: SHA256 generation failed\n", __func__);
+ return val;
+ }
+
+ /*
+ * Reset SE_SECURE to previous value.
+ */
+ tegra_se_write_32(SE0_SECURITY, security);
+
+ /* copy sha256_dst to PMC Scratch register */
+ val = tegra_se_save_sha256_pmc_scratch();
+ if (val != 0) {
+ ERROR("%s: SE0 status Error.\n", __func__);
+ }
+
+ return val;
+}
+
+/*
+ * Handler to power down the SE hardware blocks - SE, RNG1 and PKA1. This
+ * needs to be called only during System Suspend.
+ */
+int32_t tegra_se_suspend(void)
+{
+ int32_t ret = 0;
+
+ /* initialise communication channel with BPMP */
+ assert(tegra_bpmp_ipc_init() == 0);
+
+ /* Enable SE clock before SE context save */
+ ret = tegra_bpmp_ipc_enable_clock(TEGRA194_CLK_SE);
+ assert(ret == 0);
+
+ /* save SE registers */
+ se_regs[0] = mmio_read_32(TEGRA_SE0_BASE + SE0_MUTEX_WATCHDOG_NS_LIMIT);
+ se_regs[1] = mmio_read_32(TEGRA_SE0_BASE + SE0_AES0_ENTROPY_SRC_AGE_CTRL);
+ se_regs[2] = mmio_read_32(TEGRA_RNG1_BASE + RNG1_MUTEX_WATCHDOG_NS_LIMIT);
+ se_regs[3] = mmio_read_32(TEGRA_PKA1_BASE + PKA1_MUTEX_WATCHDOG_NS_LIMIT);
+
+ /* Save SE context. The BootROM restores it during System Resume */
+ ret = tegra_se_save_context();
+ if (ret != 0) {
+ ERROR("%s: context save failed (%d)\n", __func__, ret);
+ }
+
+ /* Disable SE clock after SE context save */
+ ret = tegra_bpmp_ipc_disable_clock(TEGRA194_CLK_SE);
+ assert(ret == 0);
+
+ return ret;
+}
+
+/*
+ * Handler to power up the SE hardware block(s) during System Resume.
+ */
+void tegra_se_resume(void)
+{
+ int32_t ret = 0;
+
+ /* initialise communication channel with BPMP */
+ assert(tegra_bpmp_ipc_init() == 0);
+
+ /* Enable SE clock before SE context restore */
+ ret = tegra_bpmp_ipc_enable_clock(TEGRA194_CLK_SE);
+ assert(ret == 0);
+
+ /*
+ * When TZ takes over after System Resume, TZ should first reconfigure
+ * SE_MUTEX_WATCHDOG_NS_LIMIT, PKA1_MUTEX_WATCHDOG_NS_LIMIT,
+ * RNG1_MUTEX_WATCHDOG_NS_LIMIT and SE_ENTROPY_SRC_AGE_CTRL before
+ * other operations.
+ */
+ mmio_write_32(TEGRA_SE0_BASE + SE0_MUTEX_WATCHDOG_NS_LIMIT, se_regs[0]);
+ mmio_write_32(TEGRA_SE0_BASE + SE0_AES0_ENTROPY_SRC_AGE_CTRL, se_regs[1]);
+ mmio_write_32(TEGRA_RNG1_BASE + RNG1_MUTEX_WATCHDOG_NS_LIMIT, se_regs[2]);
+ mmio_write_32(TEGRA_PKA1_BASE + PKA1_MUTEX_WATCHDOG_NS_LIMIT, se_regs[3]);
+
+ /* Disable SE clock after SE context restore */
+ ret = tegra_bpmp_ipc_disable_clock(TEGRA194_CLK_SE);
+ assert(ret == 0);
+}
diff --git a/plat/nvidia/tegra/soc/t194/drivers/se/se_private.h b/plat/nvidia/tegra/soc/t194/drivers/se/se_private.h
new file mode 100644
index 0000000..fc118aa
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t194/drivers/se/se_private.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SE_PRIVATE_H
+#define SE_PRIVATE_H
+
+#include <lib/utils_def.h>
+#include <tegra_def.h>
+
+/* SE0 security register */
+#define SE0_SECURITY U(0x18)
+#define SE0_SECURITY_SE_SOFT_SETTING (((uint32_t)1) << 16U)
+
+/* SE0 SHA GSCID register */
+#define SE0_SHA_GSCID_0 U(0x100)
+
+/* SE0 config register */
+#define SE0_SHA_CONFIG U(0x104)
+#define SE0_SHA_TASK_CONFIG U(0x108)
+#define SE0_SHA_CONFIG_HW_INIT_HASH (((uint32_t)1) << 0U)
+#define SE0_SHA_CONFIG_HW_INIT_HASH_DISABLE U(0)
+
+#define SE0_CONFIG_ENC_ALG_SHIFT U(12)
+#define SE0_CONFIG_ENC_ALG_SHA \
+ (((uint32_t)3) << SE0_CONFIG_ENC_ALG_SHIFT)
+#define SE0_CONFIG_DEC_ALG_SHIFT U(8)
+#define SE0_CONFIG_DEC_ALG_NOP \
+ (((uint32_t)0) << SE0_CONFIG_DEC_ALG_SHIFT)
+#define SE0_CONFIG_DST_SHIFT U(2)
+#define SE0_CONFIG_DST_HASHREG \
+ (((uint32_t)1) << SE0_CONFIG_DST_SHIFT)
+#define SHA256_HASH_SIZE_BYTES U(256)
+
+#define SE0_CONFIG_ENC_MODE_SHIFT U(24)
+#define SE0_CONFIG_ENC_MODE_SHA256 \
+ (((uint32_t)5) << SE0_CONFIG_ENC_MODE_SHIFT)
+
+/* SHA input message length */
+#define SE0_IN_ADDR U(0x10c)
+#define SE0_IN_HI_ADDR_HI U(0x110)
+#define SE0_IN_HI_ADDR_HI_0_MSB_SHIFT U(24)
+
+/* SHA input message length */
+#define SE0_SHA_MSG_LENGTH_0 U(0x11c)
+#define SE0_SHA_MSG_LENGTH_1 U(0x120)
+#define SE0_SHA_MSG_LENGTH_2 U(0x124)
+#define SE0_SHA_MSG_LENGTH_3 U(0x128)
+
+/* SHA input message left */
+#define SE0_SHA_MSG_LEFT_0 U(0x12c)
+#define SE0_SHA_MSG_LEFT_1 U(0x130)
+#define SE0_SHA_MSG_LEFT_2 U(0x134)
+#define SE0_SHA_MSG_LEFT_3 U(0x138)
+
+/* SE HASH-RESULT */
+#define SE0_SHA_HASH_RESULT_0 U(0x13c)
+
+/* SE OPERATION */
+#define SE0_OPERATION_REG_OFFSET U(0x17c)
+#define SE0_UNIT_OPERATION_PKT_LASTBUF_SHIFT U(16)
+#define SE0_UNIT_OPERATION_PKT_LASTBUF_FIELD \
+ ((uint32_t)0x1 << SE0_UNIT_OPERATION_PKT_LASTBUF_SHIFT)
+#define SE0_OPERATION_SHIFT U(0)
+#define SE0_OP_START \
+ (((uint32_t)0x1) << SE0_OPERATION_SHIFT)
+
+/* SE Interrupt */
+#define SE0_SHA_INT_ENABLE U(0x180)
+
+#define SE0_INT_STATUS_REG_OFFSET U(0x184)
+#define SE0_INT_OP_DONE_SHIFT U(4)
+#define SE0_INT_OP_DONE_CLEAR \
+ (((uint32_t)0U) << SE0_INT_OP_DONE_SHIFT)
+#define SE0_INT_OP_DONE(x) \
+ ((x) & (((uint32_t)0x1U) << SE0_INT_OP_DONE_SHIFT))
+
+/* SE SHA Status */
+#define SE0_SHA_STATUS_0 U(0x188)
+#define SE0_SHA_STATUS_IDLE U(0)
+
+/* SE error status */
+#define SE0_ERR_STATUS_REG_OFFSET U(0x18c)
+#define SE0_ERR_STATUS_CLEAR U(0)
+
+/* SE error status */
+#define SECURE_SCRATCH_TZDRAM_SHA256_HASH_START SECURE_SCRATCH_RSV68_LO
+#define SECURE_SCRATCH_TZDRAM_SHA256_HASH_END SECURE_SCRATCH_RSV71_HI
+
+/* SE0_INT_ENABLE_0 */
+#define SE0_INT_ENABLE U(0x88)
+#define SE0_DISABLE_ALL_INT U(0x0)
+
+/* SE0_INT_STATUS_0 */
+#define SE0_INT_STATUS U(0x8C)
+#define SE0_CLEAR_ALL_INT_STATUS U(0x3F)
+
+/* SE0_SHA_INT_STATUS_0 */
+#define SHA_INT_STATUS U(0x184)
+#define SHA_SE_OP_DONE (U(1) << 4)
+
+/* SE0_SHA_ERR_STATUS_0 */
+#define SHA_ERR_STATUS U(0x18C)
+
+/* SE0_AES0_INT_STATUS_0 */
+#define AES0_INT_STATUS U(0x2F0)
+#define AES0_SE_OP_DONE (U(1) << 4)
+
+/* SE0_AES0_ERR_STATUS_0 */
+#define AES0_ERR_STATUS U(0x2F8)
+
+/* SE0_AES1_INT_STATUS_0 */
+#define AES1_INT_STATUS U(0x4F0)
+
+/* SE0_AES1_ERR_STATUS_0 */
+#define AES1_ERR_STATUS U(0x4F8)
+
+/* SE0_RSA_INT_STATUS_0 */
+#define RSA_INT_STATUS U(0x758)
+
+/* SE0_RSA_ERR_STATUS_0 */
+#define RSA_ERR_STATUS U(0x760)
+
+/* SE0_AES0_OPERATION_0 */
+#define AES0_OPERATION U(0x238)
+#define OP_MASK_BITS U(0x7)
+#define SE_OP_CTX_SAVE U(0x3)
+
+/* SE0_AES0_CTX_SAVE_CONFIG_0 */
+#define CTX_SAVE_CONFIG U(0x2D4)
+
+/* SE0_AES0_CTX_SAVE_AUTO_STATUS_0 */
+#define CTX_SAVE_AUTO_STATUS U(0x300)
+#define CTX_SAVE_AUTO_SE_READY U(0xFF)
+#define CTX_SAVE_AUTO_SE_BUSY (U(0x1) << 31)
+
+/* SE0_AES0_CTX_SAVE_AUTO_CTRL_0 */
+#define CTX_SAVE_AUTO_CTRL U(0x304)
+#define SE_CTX_SAVE_AUTO_EN (U(0x1) << 0)
+#define SE_CTX_SAVE_AUTO_LOCK_EN (U(0x1) << 1)
+
+/* SE0_AES0_CTX_SAVE_AUTO_START_ADDR_0 */
+#define CTX_SAVE_AUTO_START_ADDR U(0x308)
+
+/* SE0_AES0_CTX_SAVE_AUTO_START_ADDR_HI_0 */
+#define CTX_SAVE_AUTO_START_ADDR_HI U(0x30C)
+
+/*******************************************************************************
+ * Inline functions definition
+ ******************************************************************************/
+
+static inline uint32_t tegra_se_read_32(uint32_t offset)
+{
+ return mmio_read_32((uint32_t)(TEGRA_SE0_BASE + offset));
+}
+
+static inline void tegra_se_write_32(uint32_t offset, uint32_t val)
+{
+ mmio_write_32((uint32_t)(TEGRA_SE0_BASE + offset), val);
+}
+
+#endif /* SE_PRIVATE_H */
diff --git a/plat/nvidia/tegra/soc/t194/plat_memctrl.c b/plat/nvidia/tegra/soc/t194/plat_memctrl.c
new file mode 100644
index 0000000..9ddcacf
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t194/plat_memctrl.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/bl_common.h>
+#include <mce.h>
+#include <memctrl_v2.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+/*******************************************************************************
+ * Array to hold MC context for Tegra194
+ ******************************************************************************/
+static __attribute__((aligned(16))) mc_regs_t tegra194_mc_context[] = {
+ _START_OF_TABLE_,
+ mc_smmu_bypass_cfg, /* TBU settings */
+ _END_OF_TABLE_,
+};
+
+/*******************************************************************************
+ * Handler to return the pointer to the MC's context struct
+ ******************************************************************************/
+mc_regs_t *plat_memctrl_get_sys_suspend_ctx(void)
+{
+ /* index of _END_OF_TABLE_ */
+ tegra194_mc_context[0].val = (uint32_t)ARRAY_SIZE(tegra194_mc_context) - 1U;
+
+ return tegra194_mc_context;
+}
+
+/*******************************************************************************
+ * Handler to restore platform specific settings to the memory controller
+ ******************************************************************************/
+void plat_memctrl_restore(void)
+{
+ UNUSED_FUNC_NOP(); /* do nothing */
+}
+
+/*******************************************************************************
+ * Handler to program platform specific settings to the memory controller
+ ******************************************************************************/
+void plat_memctrl_setup(void)
+{
+ UNUSED_FUNC_NOP(); /* do nothing */
+}
+
+/*******************************************************************************
+ * 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 sec_reg_ctrl = tegra_mc_read_32(MC_SECURITY_CFG_REG_CTRL_0);
+ uint32_t phys_base_lo = (uint32_t)phys_base & 0xFFF00000;
+ uint32_t phys_base_hi = (uint32_t)(phys_base >> 32);
+
+ /*
+ * Check TZDRAM carveout register access status. Setup TZDRAM fence
+ * only if access is enabled.
+ */
+ if ((sec_reg_ctrl & SECURITY_CFG_WRITE_ACCESS_BIT) ==
+ SECURITY_CFG_WRITE_ACCESS_ENABLE) {
+
+ /*
+ * 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_lo);
+ tegra_mc_write_32(MC_SECURITY_CFG3_0, phys_base_hi);
+ tegra_mc_write_32(MC_SECURITY_CFG1_0, (uint32_t)(size_in_bytes >> 20));
+
+ /*
+ * MCE propagates the security configuration values across the
+ * CCPLEX.
+ */
+ (void)mce_update_gsc_tzdram();
+ }
+}
diff --git a/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c
new file mode 100644
index 0000000..41a85ee
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c
@@ -0,0 +1,505 @@
+/*
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <bpmp_ipc.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <drivers/delay_timer.h>
+#include <denver.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/psci/psci.h>
+#include <mce.h>
+#include <mce_private.h>
+#include <memctrl_v2.h>
+#include <plat/common/platform.h>
+#include <se.h>
+#include <smmu.h>
+#include <t194_nvg.h>
+#include <tegra194_private.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+extern uint32_t __tegra194_cpu_reset_handler_data,
+ __tegra194_cpu_reset_handler_end;
+
+/* TZDRAM offset for saving SMMU context */
+#define TEGRA194_SMMU_CTX_OFFSET 16U
+
+/* state id mask */
+#define TEGRA194_STATE_ID_MASK 0xFU
+/* constants to get power state's wake time */
+#define TEGRA194_WAKE_TIME_MASK 0x0FFFFFF0U
+#define TEGRA194_WAKE_TIME_SHIFT 4U
+/* default core wake mask for CPU_SUSPEND */
+#define TEGRA194_CORE_WAKE_MASK 0x180cU
+
+static struct t19x_psci_percpu_data {
+ uint32_t wake_time;
+} __aligned(CACHE_WRITEBACK_GRANULE) t19x_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) &
+ TEGRA194_STATE_ID_MASK;
+ uint32_t cpu = plat_my_core_pos();
+ int32_t ret = PSCI_E_SUCCESS;
+
+ /* save the core wake time (in TSC ticks)*/
+ t19x_percpu_data[cpu].wake_time = (power_state & TEGRA194_WAKE_TIME_MASK)
+ << TEGRA194_WAKE_TIME_SHIFT;
+
+ /*
+ * Clean t19x_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)&t19x_percpu_data[cpu],
+ sizeof(t19x_percpu_data[cpu]));
+
+ /* Sanity check the requested state id */
+ switch (state_id) {
+ case PSTATE_ID_CORE_IDLE:
+
+ if (psci_get_pstate_type(power_state) != PSTATE_TYPE_STANDBY) {
+ ret = PSCI_E_INVALID_PARAMS;
+ break;
+ }
+
+ /* Core idle request */
+ req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
+ req_state->pwr_domain_state[MPIDR_AFFLVL1] = PSCI_LOCAL_STATE_RUN;
+ break;
+
+ default:
+ ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
+ ret = PSCI_E_INVALID_PARAMS;
+ break;
+ }
+
+ return ret;
+}
+
+int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state)
+{
+ uint32_t cpu = plat_my_core_pos();
+ mce_cstate_info_t cstate_info = { 0 };
+
+ /* Program default wake mask */
+ cstate_info.wake_mask = TEGRA194_CORE_WAKE_MASK;
+ cstate_info.update_wake_mask = 1;
+ mce_update_cstate_info(&cstate_info);
+
+ /* Enter CPU idle */
+ (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
+ (uint64_t)TEGRA_NVG_CORE_C6,
+ t19x_percpu_data[cpu].wake_time,
+ 0U);
+
+ return PSCI_E_SUCCESS;
+}
+
+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_afflvl2;
+ plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
+ uint64_t mc_ctx_base;
+ uint32_t val;
+ mce_cstate_info_t sc7_cstate_info = {
+ .cluster = (uint32_t)TEGRA_NVG_CLUSTER_CC6,
+ .ccplex = (uint32_t)TEGRA_NVG_CG_CG7,
+ .system = (uint32_t)TEGRA_NVG_SYSTEM_SC7,
+ .system_state_force = 1U,
+ .update_wake_mask = 1U,
+ };
+ int32_t ret = 0;
+
+ /* get the state ID */
+ pwr_domain_state = target_state->pwr_domain_state;
+ stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
+ TEGRA194_STATE_ID_MASK;
+
+ if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
+
+ /* 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 MC context */
+ mc_ctx_base = params_from_bl2->tzdram_base +
+ tegra194_get_mc_ctx_offset();
+ tegra_mc_save_context((uintptr_t)mc_ctx_base);
+
+ /*
+ * Suspend SE, RNG1 and PKA1 only on silcon and fpga,
+ * since VDK does not support atomic se ctx save
+ */
+ if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) {
+ ret = tegra_se_suspend();
+ assert(ret == 0);
+ }
+
+ /* Prepare for system suspend */
+ mce_update_cstate_info(&sc7_cstate_info);
+
+ do {
+ val = (uint32_t)mce_command_handler(
+ (uint32_t)MCE_CMD_IS_SC7_ALLOWED,
+ (uint32_t)TEGRA_NVG_CORE_C7,
+ MCE_CORE_SLEEP_TIME_INFINITE,
+ 0U);
+ } while (val == 0U);
+
+ /* Instruct the MCE to enter system suspend state */
+ ret = mce_command_handler(
+ (uint64_t)MCE_CMD_ENTER_CSTATE,
+ (uint64_t)TEGRA_NVG_CORE_C7,
+ MCE_CORE_SLEEP_TIME_INFINITE,
+ 0U);
+ assert(ret == 0);
+
+ /* set system suspend state for house-keeping */
+ tegra194_set_system_suspend_entry();
+ }
+
+ return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * Helper function to check if this is the last ON CPU in the cluster
+ ******************************************************************************/
+static bool tegra_last_on_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;
+ plat_local_state_t target = states[core_pos];
+ mce_cstate_info_t cstate_info = { 0 };
+
+ /* CPU off */
+ if (target == PLAT_MAX_OFF_STATE) {
+
+ /* Enable cluster powerdn from last CPU in the cluster */
+ if (tegra_last_on_cpu_in_cluster(states, ncpu)) {
+
+ /* Enable CC6 state and turn off wake mask */
+ cstate_info.cluster = (uint32_t)TEGRA_NVG_CLUSTER_CC6;
+ cstate_info.ccplex = (uint32_t)TEGRA_NVG_CG_CG7;
+ cstate_info.system_state_force = 1;
+ cstate_info.update_wake_mask = 1U;
+ mce_update_cstate_info(&cstate_info);
+
+ } else {
+
+ /* Turn off wake_mask */
+ cstate_info.update_wake_mask = 1U;
+ 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;
+ plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
+ uint8_t stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
+ TEGRA194_STATE_ID_MASK;
+ uint64_t src_len_in_bytes = (uintptr_t)&__BL31_END__ - (uintptr_t)BL31_BASE;
+ uint64_t val;
+ int32_t ret = PSCI_E_SUCCESS;
+
+ if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
+ val = params_from_bl2->tzdram_base +
+ tegra194_get_cpu_reset_handler_size();
+
+ /* initialise communication channel with BPMP */
+ ret = tegra_bpmp_ipc_init();
+ assert(ret == 0);
+
+ /* Enable SE clock before SE context save */
+ ret = tegra_bpmp_ipc_enable_clock(TEGRA194_CLK_SE);
+ assert(ret == 0);
+
+ /*
+ * It is very unlikely that the BL31 image would be
+ * bigger than 2^32 bytes
+ */
+ assert(src_len_in_bytes < UINT32_MAX);
+
+ if (tegra_se_calculate_save_sha256(BL31_BASE,
+ (uint32_t)src_len_in_bytes) != 0) {
+ ERROR("Hash calculation failed. Reboot\n");
+ (void)tegra_soc_prepare_system_reset();
+ }
+
+ /*
+ * 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 +
+ tegra194_get_cpu_reset_handler_size();
+ memcpy((void *)(uintptr_t)val, (void *)(uintptr_t)BL31_BASE,
+ src_len_in_bytes);
+
+ /* Disable SE clock after SE context save */
+ ret = tegra_bpmp_ipc_disable_clock(TEGRA194_CLK_SE);
+ assert(ret == 0);
+ }
+
+ return ret;
+}
+
+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_pwr_domain_on(u_register_t mpidr)
+{
+ uint64_t target_cpu = mpidr & MPIDR_CPU_MASK;
+ uint64_t target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >>
+ MPIDR_AFFINITY_BITS;
+ int32_t ret = 0;
+
+ if (target_cluster > ((uint32_t)PLATFORM_CLUSTER_COUNT - 1U)) {
+ ERROR("%s: unsupported CPU (0x%lx)\n", __func__ , mpidr);
+ return PSCI_E_NOT_PRESENT;
+ }
+
+ /* construct the target CPU # */
+ target_cpu += (target_cluster << 1U);
+
+ ret = mce_command_handler((uint64_t)MCE_CMD_ONLINE_CORE, target_cpu, 0U, 0U);
+ if (ret < 0) {
+ return PSCI_E_DENIED;
+ }
+
+ return PSCI_E_SUCCESS;
+}
+
+int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
+ uint8_t enable_ccplex_lock_step = params_from_bl2->enable_ccplex_lock_step;
+ uint8_t stateid_afflvl2 = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
+ cpu_context_t *ctx = cm_get_context(NON_SECURE);
+ uint64_t actlr_elx;
+
+ /*
+ * 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.
+ */
+ actlr_elx = read_ctx_reg((get_el1_sysregs_ctx(ctx)), (CTX_ACTLR_EL1));
+ actlr_elx &= ~DENVER_CPU_PMSTATE_MASK;
+ actlr_elx |= DENVER_CPU_PMSTATE_C1;
+ write_ctx_reg((get_el1_sysregs_ctx(ctx)), (CTX_ACTLR_EL1), (actlr_elx));
+
+ /*
+ * Check if we are exiting from deep sleep and restore SE
+ * context if we are.
+ */
+ if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
+
+#if ENABLE_STRICT_CHECKING_MODE
+ /*
+ * Enable strict checking after programming the GSC for
+ * enabling TZSRAM and TZDRAM
+ */
+ mce_enable_strict_checking();
+#endif
+
+ /* Init SMMU */
+ tegra_smmu_init();
+
+ /* Resume SE, RNG1 and PKA1 */
+ tegra_se_resume();
+
+ /*
+ * Program XUSB STREAMIDs
+ * ======================
+ * T19x XUSB has support for XUSB virtualization. It will
+ * have one physical function (PF) and four Virtual functions
+ * (VF)
+ *
+ * There were below two SIDs for XUSB until T186.
+ * 1) #define TEGRA_SID_XUSB_HOST 0x1bU
+ * 2) #define TEGRA_SID_XUSB_DEV 0x1cU
+ *
+ * We have below four new SIDs added for VF(s)
+ * 3) #define TEGRA_SID_XUSB_VF0 0x5dU
+ * 4) #define TEGRA_SID_XUSB_VF1 0x5eU
+ * 5) #define TEGRA_SID_XUSB_VF2 0x5fU
+ * 6) #define TEGRA_SID_XUSB_VF3 0x60U
+ *
+ * When virtualization is enabled then we have to disable SID
+ * override and program above SIDs in below newly added SID
+ * registers in XUSB PADCTL MMIO space. These registers are
+ * TZ protected and so need to be done in ATF.
+ *
+ * a) #define XUSB_PADCTL_HOST_AXI_STREAMID_PF_0 (0x136cU)
+ * b) #define XUSB_PADCTL_DEV_AXI_STREAMID_PF_0 (0x139cU)
+ * c) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_0 (0x1370U)
+ * d) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_1 (0x1374U)
+ * e) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_2 (0x1378U)
+ * f) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_3 (0x137cU)
+ *
+ * This change disables SID override and programs XUSB SIDs
+ * in above registers to support both virtualization and
+ * non-virtualization platforms
+ */
+ if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) {
+
+ mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_HOST);
+ assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_PF_0) == TEGRA_SID_XUSB_HOST);
+ mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_VF_0, TEGRA_SID_XUSB_VF0);
+ assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_VF_0) == TEGRA_SID_XUSB_VF0);
+ mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_VF_1, TEGRA_SID_XUSB_VF1);
+ assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_VF_1) == TEGRA_SID_XUSB_VF1);
+ mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_VF_2, TEGRA_SID_XUSB_VF2);
+ assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_VF_2) == TEGRA_SID_XUSB_VF2);
+ mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_VF_3, TEGRA_SID_XUSB_VF3);
+ assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_VF_3) == TEGRA_SID_XUSB_VF3);
+ mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_DEV_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_DEV);
+ assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_DEV_AXI_STREAMID_PF_0) == TEGRA_SID_XUSB_DEV);
+ }
+ }
+
+ /*
+ * Enable dual execution optimized translations for all ELx.
+ */
+ if (enable_ccplex_lock_step != 0U) {
+ actlr_elx = read_actlr_el3();
+ actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL3;
+ write_actlr_el3(actlr_elx);
+
+ actlr_elx = read_actlr_el2();
+ actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL2;
+ write_actlr_el2(actlr_elx);
+
+ actlr_elx = read_actlr_el1();
+ actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL1;
+ write_actlr_el1(actlr_elx);
+ }
+
+ 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) & MIDR_IMPL_MASK;
+ int32_t ret = 0;
+
+ (void)target_state;
+
+ /* Disable Denver's DCO operations */
+ if (impl == DENVER_IMPL) {
+ denver_disable_dco();
+ }
+
+ /* Turn off CPU */
+ ret = mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
+ (uint64_t)TEGRA_NVG_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U);
+ assert(ret == 0);
+
+ return PSCI_E_SUCCESS;
+}
+
+__dead2 void tegra_soc_prepare_system_off(void)
+{
+ /* System power off */
+ mce_system_shutdown();
+
+ wfi();
+
+ /* wait for the system to power down */
+ for (;;) {
+ ;
+ }
+}
+
+int32_t tegra_soc_prepare_system_reset(void)
+{
+ /* System reboot */
+ mce_system_reboot();
+
+ return PSCI_E_SUCCESS;
+}
diff --git a/plat/nvidia/tegra/soc/t194/plat_ras.c b/plat/nvidia/tegra/soc/t194/plat_ras.c
new file mode 100644
index 0000000..02f6158
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t194/plat_ras.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2020-2021, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/bakery_lock.h>
+#include <lib/cassert.h>
+#include <lib/extensions/ras.h>
+#include <lib/utils_def.h>
+#include <services/sdei.h>
+
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <tegra194_ras_private.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+/*
+ * ERR<n>FR bits[63:32], it indicates supported RAS errors which can be enabled
+ * by setting corresponding bits in ERR<n>CTLR
+ */
+#define ERR_FR_EN_BITS_MASK 0xFFFFFFFF00000000ULL
+
+/*
+ * Number of RAS errors will be cleared per 'tegra194_ras_corrected_err_clear'
+ * function call.
+ */
+#define RAS_ERRORS_PER_CALL 8
+
+/*
+ * the max possible RAS node index value.
+ */
+#define RAS_NODE_INDEX_MAX 0x1FFFFFFFU
+
+/* bakery lock for platform RAS handler. */
+static DEFINE_BAKERY_LOCK(ras_handler_lock);
+#define ras_lock() bakery_lock_get(&ras_handler_lock)
+#define ras_unlock() bakery_lock_release(&ras_handler_lock)
+
+/*
+ * Function to handle an External Abort received at EL3.
+ * This function is invoked by RAS framework.
+ */
+static void tegra194_ea_handler(unsigned int ea_reason, uint64_t syndrome,
+ void *cookie, void *handle, uint64_t flags)
+{
+ int32_t ret;
+
+ ras_lock();
+
+ ERROR("MPIDR 0x%lx: exception reason=%u syndrome=0x%" PRIx64 "\n",
+ read_mpidr(), ea_reason, syndrome);
+
+ /* Call RAS EA handler */
+ ret = ras_ea_handler(ea_reason, syndrome, cookie, handle, flags);
+ if (ret != 0) {
+ ERROR("RAS error handled!\n");
+ ret = sdei_dispatch_event(TEGRA_SDEI_EP_EVENT_0 +
+ plat_my_core_pos());
+ if (ret != 0)
+ ERROR("sdei_dispatch_event returned %d\n", ret);
+ } else {
+ ERROR("Not a RAS error!\n");
+ }
+
+ ras_unlock();
+}
+
+/*
+ * Function to enable all supported RAS error report.
+ *
+ * Uncorrected errors are set to report as External abort (SError)
+ * Corrected errors are set to report as interrupt.
+ */
+void tegra194_ras_enable(void)
+{
+ VERBOSE("%s\n", __func__);
+
+ /* skip RAS enablement if not a silicon platform. */
+ if (!tegra_platform_is_silicon()) {
+ return;
+ }
+
+ /*
+ * Iterate for each group(num_idx ERRSELRs starting from idx_start)
+ * use normal for loop instead of for_each_err_record_info to get rid
+ * of MISRA noise..
+ */
+ for (uint32_t i = 0U; i < err_record_mappings.num_err_records; i++) {
+
+ const struct err_record_info *info = &err_record_mappings.err_records[i];
+
+ uint32_t idx_start = info->sysreg.idx_start;
+ uint32_t num_idx = info->sysreg.num_idx;
+ const struct ras_aux_data *aux_data = (const struct ras_aux_data *)info->aux_data;
+
+ assert(aux_data != NULL);
+
+ for (uint32_t j = 0; j < num_idx; j++) {
+
+ /* ERR<n>CTLR register value. */
+ uint64_t err_ctrl = 0ULL;
+ /* all supported errors for this node. */
+ uint64_t err_fr;
+ /* uncorrectable errors */
+ uint64_t uncorr_errs;
+ /* correctable errors */
+ uint64_t corr_errs;
+
+ /*
+ * Catch error if something wrong with the RAS aux data
+ * record table.
+ */
+ assert(aux_data[j].err_ctrl != NULL);
+
+ /*
+ * Write to ERRSELR_EL1 to select the RAS error node.
+ * Always program this at first to select corresponding
+ * RAS node before any other RAS register r/w.
+ */
+ ser_sys_select_record(idx_start + j);
+
+ err_fr = read_erxfr_el1() & ERR_FR_EN_BITS_MASK;
+ uncorr_errs = aux_data[j].err_ctrl();
+ corr_errs = ~uncorr_errs & err_fr;
+
+ /* enable error reporting */
+ ERR_CTLR_ENABLE_FIELD(err_ctrl, ED);
+
+ /* enable SError reporting for uncorrectable errors */
+ if ((uncorr_errs & err_fr) != 0ULL) {
+ ERR_CTLR_ENABLE_FIELD(err_ctrl, UE);
+ }
+
+ /* generate interrupt for corrected errors. */
+ if (corr_errs != 0ULL) {
+ ERR_CTLR_ENABLE_FIELD(err_ctrl, CFI);
+ }
+
+ /* enable the supported errors */
+ err_ctrl |= err_fr;
+
+ VERBOSE("errselr_el1:0x%x, erxfr:0x%" PRIx64 ", err_ctrl:0x%" PRIx64 "\n",
+ idx_start + j, err_fr, err_ctrl);
+
+ /* enable specified errors, or set to 0 if no supported error */
+ write_erxctlr_el1(err_ctrl);
+ }
+ }
+}
+
+/*
+ * Function to clear RAS ERR<n>STATUS for corrected RAS error.
+ *
+ * This function clears number of 'RAS_ERRORS_PER_CALL' RAS errors at most.
+ * 'cookie' - in/out cookie parameter to specify/store last visited RAS
+ * error record index. it is set to '0' to indicate no more RAS
+ * error record to clear.
+ */
+void tegra194_ras_corrected_err_clear(uint64_t *cookie)
+{
+ /*
+ * 'last_node' and 'last_idx' represent last visited RAS node index from
+ * previous function call. they are set to 0 when first smc call is made
+ * or all RAS error are visited by followed multipile smc calls.
+ */
+ union prev_record {
+ struct record {
+ uint32_t last_node;
+ uint32_t last_idx;
+ } rec;
+ uint64_t value;
+ } prev;
+
+ uint64_t clear_ce_status = 0ULL;
+ int32_t nerrs_per_call = RAS_ERRORS_PER_CALL;
+ uint32_t i;
+
+ if (cookie == NULL) {
+ return;
+ }
+
+ prev.value = *cookie;
+
+ if ((prev.rec.last_node >= RAS_NODE_INDEX_MAX) ||
+ (prev.rec.last_idx >= RAS_NODE_INDEX_MAX)) {
+ return;
+ }
+
+ ERR_STATUS_SET_FIELD(clear_ce_status, AV, 0x1UL);
+ ERR_STATUS_SET_FIELD(clear_ce_status, V, 0x1UL);
+ ERR_STATUS_SET_FIELD(clear_ce_status, OF, 0x1UL);
+ ERR_STATUS_SET_FIELD(clear_ce_status, MV, 0x1UL);
+ ERR_STATUS_SET_FIELD(clear_ce_status, CE, 0x3UL);
+
+
+ for (i = prev.rec.last_node; i < err_record_mappings.num_err_records; i++) {
+
+ const struct err_record_info *info = &err_record_mappings.err_records[i];
+ uint32_t idx_start = info->sysreg.idx_start;
+ uint32_t num_idx = info->sysreg.num_idx;
+
+ uint32_t j;
+
+ j = (i == prev.rec.last_node && prev.value != 0UL) ?
+ (prev.rec.last_idx + 1U) : 0U;
+
+ for (; j < num_idx; j++) {
+
+ uint64_t status;
+ uint32_t err_idx = idx_start + j;
+
+ if (err_idx >= RAS_NODE_INDEX_MAX) {
+ return;
+ }
+
+ write_errselr_el1(err_idx);
+ status = read_erxstatus_el1();
+
+ if (ERR_STATUS_GET_FIELD(status, CE) != 0U) {
+ write_erxstatus_el1(clear_ce_status);
+ }
+
+ --nerrs_per_call;
+
+ /* only clear 'nerrs_per_call' errors each time. */
+ if (nerrs_per_call <= 0) {
+ prev.rec.last_idx = j;
+ prev.rec.last_node = i;
+ /* save last visited error record index
+ * into cookie.
+ */
+ *cookie = prev.value;
+
+ return;
+ }
+ }
+ }
+
+ /*
+ * finish if all ras error records are checked or provided index is out
+ * of range.
+ */
+ *cookie = 0ULL;
+ return;
+}
+
+/* Function to probe an error from error record group. */
+static int32_t tegra194_ras_record_probe(const struct err_record_info *info,
+ int *probe_data)
+{
+ /* Skip probing if not a silicon platform */
+ if (!tegra_platform_is_silicon()) {
+ return 0;
+ }
+
+ return ser_probe_sysreg(info->sysreg.idx_start, info->sysreg.num_idx, probe_data);
+}
+
+/* Function to handle error from one given node */
+static int32_t tegra194_ras_node_handler(uint32_t errselr, const char *name,
+ const struct ras_error *errors, uint64_t status)
+{
+ bool found = false;
+ uint32_t ierr = (uint32_t)ERR_STATUS_GET_FIELD(status, IERR);
+ uint32_t serr = (uint32_t)ERR_STATUS_GET_FIELD(status, SERR);
+ uint64_t val = 0;
+
+ /* not a valid error. */
+ if (ERR_STATUS_GET_FIELD(status, V) == 0U) {
+ return 0;
+ }
+
+ ERR_STATUS_SET_FIELD(val, V, 1);
+
+ /* keep the log print same as linux arm64_ras driver. */
+ ERROR("**************************************\n");
+ ERROR("RAS Error in %s, ERRSELR_EL1=0x%x:\n", name, errselr);
+ ERROR("\tStatus = 0x%" PRIx64 "\n", status);
+
+ /* Print uncorrectable errror information. */
+ if (ERR_STATUS_GET_FIELD(status, UE) != 0U) {
+
+ ERR_STATUS_SET_FIELD(val, UE, 1);
+ ERR_STATUS_SET_FIELD(val, UET, 1);
+
+ /* IERR to error message */
+ for (uint32_t i = 0; errors[i].error_msg != NULL; i++) {
+ if (ierr == errors[i].error_code) {
+ ERROR("\tIERR = %s: 0x%x\n",
+ errors[i].error_msg, ierr);
+
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ ERROR("\tUnknown IERR: 0x%x\n", ierr);
+ }
+
+ ERROR("SERR = %s: 0x%x\n", ras_serr_to_str(serr), serr);
+
+ /* Overflow, multiple errors have been detected. */
+ if (ERR_STATUS_GET_FIELD(status, OF) != 0U) {
+ ERROR("\tOverflow (there may be more errors) - "
+ "Uncorrectable\n");
+ ERR_STATUS_SET_FIELD(val, OF, 1);
+ }
+
+ ERROR("\tUncorrectable (this is fatal)\n");
+
+ /* Miscellaneous Register Valid. */
+ if (ERR_STATUS_GET_FIELD(status, MV) != 0U) {
+ ERROR("\tMISC0 = 0x%lx\n", read_erxmisc0_el1());
+ ERROR("\tMISC1 = 0x%lx\n", read_erxmisc1_el1());
+ ERR_STATUS_SET_FIELD(val, MV, 1);
+ }
+
+ /* Address Valid. */
+ if (ERR_STATUS_GET_FIELD(status, AV) != 0U) {
+ ERROR("\tADDR = 0x%lx\n", read_erxaddr_el1());
+ ERR_STATUS_SET_FIELD(val, AV, 1);
+ }
+
+ /* Deferred error */
+ if (ERR_STATUS_GET_FIELD(status, DE) != 0U) {
+ ERROR("\tDeferred error\n");
+ ERR_STATUS_SET_FIELD(val, DE, 1);
+ }
+
+ } else {
+ /* For corrected error, simply clear it. */
+ VERBOSE("corrected RAS error is cleared: ERRSELR_EL1:0x%x, "
+ "IERR:0x%x, SERR:0x%x\n", errselr, ierr, serr);
+ ERR_STATUS_SET_FIELD(val, CE, 1);
+ }
+
+ ERROR("**************************************\n");
+
+ /* Write to clear reported errors. */
+ write_erxstatus_el1(val);
+
+ /* error handled */
+ return 0;
+}
+
+/* Function to handle one error node from an error record group. */
+static int32_t tegra194_ras_record_handler(const struct err_record_info *info,
+ int probe_data, const struct err_handler_data *const data __unused)
+{
+ uint32_t num_idx = info->sysreg.num_idx;
+ uint32_t idx_start = info->sysreg.idx_start;
+ const struct ras_aux_data *aux_data = info->aux_data;
+ const struct ras_error *errors;
+ uint32_t offset;
+ const char *node_name;
+
+ uint64_t status = 0ULL;
+
+ VERBOSE("%s\n", __func__);
+
+ assert(probe_data >= 0);
+ assert((uint32_t)probe_data < num_idx);
+
+ offset = (uint32_t)probe_data;
+ errors = aux_data[offset].error_records;
+ node_name = aux_data[offset].name;
+
+ assert(errors != NULL);
+
+ /* Write to ERRSELR_EL1 to select the error record */
+ ser_sys_select_record(idx_start + offset);
+
+ /* Retrieve status register from the error record */
+ status = read_erxstatus_el1();
+
+ return tegra194_ras_node_handler(idx_start + offset, node_name,
+ errors, status);
+}
+
+
+/* Instantiate RAS nodes */
+PER_CORE_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE)
+PER_CLUSTER_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE)
+SCF_L3_BANK_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE)
+CCPLEX_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE)
+
+/* Instantiate RAS node groups */
+static struct ras_aux_data per_core_ras_group[] = {
+ PER_CORE_RAS_GROUP_NODES
+};
+CASSERT(ARRAY_SIZE(per_core_ras_group) < RAS_NODE_INDEX_MAX,
+ assert_max_per_core_ras_group_size);
+
+static struct ras_aux_data per_cluster_ras_group[] = {
+ PER_CLUSTER_RAS_GROUP_NODES
+};
+CASSERT(ARRAY_SIZE(per_cluster_ras_group) < RAS_NODE_INDEX_MAX,
+ assert_max_per_cluster_ras_group_size);
+
+static struct ras_aux_data scf_l3_ras_group[] = {
+ SCF_L3_BANK_RAS_GROUP_NODES
+};
+CASSERT(ARRAY_SIZE(scf_l3_ras_group) < RAS_NODE_INDEX_MAX,
+ assert_max_scf_l3_ras_group_size);
+
+static struct ras_aux_data ccplex_ras_group[] = {
+ CCPLEX_RAS_GROUP_NODES
+};
+CASSERT(ARRAY_SIZE(ccplex_ras_group) < RAS_NODE_INDEX_MAX,
+ assert_max_ccplex_ras_group_size);
+
+/*
+ * We have same probe and handler for each error record group, use a macro to
+ * simply the record definition.
+ */
+#define ADD_ONE_ERR_GROUP(errselr_start, group) \
+ ERR_RECORD_SYSREG_V1((errselr_start), (uint32_t)ARRAY_SIZE((group)), \
+ &tegra194_ras_record_probe, \
+ &tegra194_ras_record_handler, (group))
+
+/* RAS error record group information */
+static struct err_record_info carmel_ras_records[] = {
+ /*
+ * Per core ras error records
+ * ERRSELR starts from 0*256 + Logical_CPU_ID*16 + 0 to
+ * 0*256 + Logical_CPU_ID*16 + 5 for each group.
+ * 8 cores/groups, 6 * 8 nodes in total.
+ */
+ ADD_ONE_ERR_GROUP(0x000, per_core_ras_group),
+ ADD_ONE_ERR_GROUP(0x010, per_core_ras_group),
+ ADD_ONE_ERR_GROUP(0x020, per_core_ras_group),
+ ADD_ONE_ERR_GROUP(0x030, per_core_ras_group),
+ ADD_ONE_ERR_GROUP(0x040, per_core_ras_group),
+ ADD_ONE_ERR_GROUP(0x050, per_core_ras_group),
+ ADD_ONE_ERR_GROUP(0x060, per_core_ras_group),
+ ADD_ONE_ERR_GROUP(0x070, per_core_ras_group),
+
+ /*
+ * Per cluster ras error records
+ * ERRSELR starts from 2*256 + Logical_Cluster_ID*16 + 0 to
+ * 2*256 + Logical_Cluster_ID*16 + 3.
+ * 4 clusters/groups, 3 * 4 nodes in total.
+ */
+ ADD_ONE_ERR_GROUP(0x200, per_cluster_ras_group),
+ ADD_ONE_ERR_GROUP(0x210, per_cluster_ras_group),
+ ADD_ONE_ERR_GROUP(0x220, per_cluster_ras_group),
+ ADD_ONE_ERR_GROUP(0x230, per_cluster_ras_group),
+
+ /*
+ * SCF L3_Bank ras error records
+ * ERRSELR: 3*256 + L3_Bank_ID, L3_Bank_ID: 0-3
+ * 1 groups, 4 nodes in total.
+ */
+ ADD_ONE_ERR_GROUP(0x300, scf_l3_ras_group),
+
+ /*
+ * CCPLEX ras error records
+ * ERRSELR: 4*256 + Unit_ID, Unit_ID: 0 - 4
+ * 1 groups, 5 nodes in total.
+ */
+ ADD_ONE_ERR_GROUP(0x400, ccplex_ras_group),
+};
+
+CASSERT(ARRAY_SIZE(carmel_ras_records) < RAS_NODE_INDEX_MAX,
+ assert_max_carmel_ras_records_size);
+
+REGISTER_ERR_RECORD_INFO(carmel_ras_records);
+
+/* dummy RAS interrupt */
+static struct ras_interrupt carmel_ras_interrupts[] = {};
+REGISTER_RAS_INTERRUPTS(carmel_ras_interrupts);
+
+/*******************************************************************************
+ * RAS handler for the platform
+ ******************************************************************************/
+void plat_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
+ void *handle, uint64_t flags)
+{
+#if RAS_EXTENSION
+ tegra194_ea_handler(ea_reason, syndrome, cookie, handle, flags);
+#else
+ plat_default_ea_handler(ea_reason, syndrome, cookie, handle, flags);
+#endif
+}
diff --git a/plat/nvidia/tegra/soc/t194/plat_secondary.c b/plat/nvidia/tegra/soc/t194/plat_secondary.c
new file mode 100644
index 0000000..1cb14ad
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t194/plat_secondary.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <mce.h>
+#include <tegra194_private.h>
+#include <tegra_def.h>
+#include <tegra_private.h>
+
+extern uint64_t tegra_bl31_phys_base;
+
+#define MISCREG_AA64_RST_LOW 0x2004U
+#define MISCREG_AA64_RST_HIGH 0x2008U
+
+#define CPU_RESET_MODE_AA64 1U
+
+/*******************************************************************************
+ * Setup secondary CPU vectors
+ ******************************************************************************/
+void plat_secondary_setup(void)
+{
+ uint32_t addr_low, addr_high;
+ plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
+ uint64_t cpu_reset_handler_base, cpu_reset_handler_size, tzdram_addr;
+ uint64_t src_len_bytes = BL_END - tegra_bl31_phys_base;
+
+ INFO("Setting up secondary CPU boot\n");
+
+ tzdram_addr = params_from_bl2->tzdram_base +
+ tegra194_get_cpu_reset_handler_size();
+
+ /*
+ * 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 = tegra194_get_cpu_reset_handler_base();
+ cpu_reset_handler_size = tegra194_get_cpu_reset_handler_size();
+ memcpy((void *)((uintptr_t)params_from_bl2->tzdram_base),
+ (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);
+ assert(mmio_read_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_LOW) == addr_low);
+ mmio_write_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_HIGH, addr_high);
+ assert(mmio_read_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);
+ assert(mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_LO) == addr_low);
+ mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_HI,
+ addr_high);
+ assert(mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_HI) == addr_high);
+ mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV72_LO,
+ (uint32_t)tzdram_addr);
+ assert(mmio_read_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV72_LO) == (uint32_t)tzdram_addr);
+ mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV72_HI,
+ (uint32_t)src_len_bytes);
+ assert(mmio_read_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV72_HI) == (uint32_t)src_len_bytes);
+}
diff --git a/plat/nvidia/tegra/soc/t194/plat_setup.c b/plat/nvidia/tegra/soc/t194/plat_setup.c
new file mode 100644
index 0000000..8f7d1e9
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t194/plat_setup.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/console.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <cortex_a57.h>
+#include <common/debug.h>
+#include <denver.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <bl31/interrupt_mgmt.h>
+#include <mce.h>
+#include <mce_private.h>
+#include <memctrl.h>
+#include <plat/common/platform.h>
+#include <smmu.h>
+#include <spe.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+/* ID for spe-console */
+#define TEGRA_CONSOLE_SPE_ID 0xFE
+
+/*******************************************************************************
+ * Structure to store the SCR addresses and its expected settings.
+ *******************************************************************************
+ */
+typedef struct {
+ uint32_t scr_addr;
+ uint32_t scr_val;
+} scr_settings_t;
+
+static const scr_settings_t t194_scr_settings[] = {
+ { SCRATCH_RSV68_SCR, SCRATCH_RSV68_SCR_VAL },
+ { SCRATCH_RSV71_SCR, SCRATCH_RSV71_SCR_VAL },
+ { SCRATCH_RSV72_SCR, SCRATCH_RSV72_SCR_VAL },
+ { SCRATCH_RSV75_SCR, SCRATCH_RSV75_SCR_VAL },
+ { SCRATCH_RSV81_SCR, SCRATCH_RSV81_SCR_VAL },
+ { SCRATCH_RSV97_SCR, SCRATCH_RSV97_SCR_VAL },
+ { SCRATCH_RSV99_SCR, SCRATCH_RSV99_SCR_VAL },
+ { SCRATCH_RSV109_SCR, SCRATCH_RSV109_SCR_VAL },
+ { MISCREG_SCR_SCRTZWELCK, MISCREG_SCR_SCRTZWELCK_VAL }
+};
+
+/*******************************************************************************
+ * 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,
+ /* No of CPU cores - cluster2 */
+ PLATFORM_MAX_CPUS_PER_CLUSTER,
+ /* No of CPU cores - cluster3 */
+ 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, 0x4000U, /* 16KB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_GPCDMA_BASE, 0x10000U, /* 64KB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_MC_STREAMID_BASE, 0x8000U, /* 32KB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_MC_BASE, 0x8000U, /* 32KB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+#if !ENABLE_CONSOLE_SPE
+ MAP_REGION_FLAT(TEGRA_UARTA_BASE, 0x20000U, /* 128KB - UART A, B*/
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_UARTC_BASE, 0x20000U, /* 128KB - UART C, G */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_UARTD_BASE, 0x30000U, /* 192KB - UART D, E, F */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+#endif
+ MAP_REGION_FLAT(TEGRA_XUSB_PADCTL_BASE, 0x2000U, /* 8KB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_GICD_BASE, 0x1000, /* 4KB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_GICC_BASE, 0x1000, /* 4KB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_SE0_BASE, 0x1000U, /* 4KB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_PKA1_BASE, 0x1000U, /* 4KB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_RNG1_BASE, 0x1000U, /* 4KB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_HSP_DBELL_BASE, 0x1000U, /* 4KB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+#if ENABLE_CONSOLE_SPE
+ MAP_REGION_FLAT(TEGRA_CONSOLE_SPE_BASE, 0x1000U, /* 4KB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+#endif
+ MAP_REGION_FLAT(TEGRA_TMRUS_BASE, TEGRA_TMRUS_SIZE, /* 4KB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_SCRATCH_BASE, 0x1000U, /* 4KB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_SMMU2_BASE, 0x800000U, /* 8MB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_SMMU1_BASE, 0x800000U, /* 8MB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_SMMU0_BASE, 0x800000U, /* 8MB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_BPMP_IPC_TX_PHYS_BASE, 0x10000U, /* 64KB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
+ MAP_REGION_FLAT(TEGRA_CAR_RESET_BASE, 0x10000U, /* 64KB */
+ (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)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;
+}
+
+#if !ENABLE_CONSOLE_SPE
+/*******************************************************************************
+ * Maximum supported UART controllers
+ ******************************************************************************/
+#define TEGRA194_MAX_UART_PORTS 7
+
+/*******************************************************************************
+ * This variable holds the UART port base addresses
+ ******************************************************************************/
+static uint32_t tegra194_uart_addresses[TEGRA194_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
+};
+#endif
+
+/*******************************************************************************
+ * Enable console corresponding to the console ID
+ ******************************************************************************/
+void plat_enable_console(int32_t id)
+{
+ uint32_t console_clock = 0U;
+
+#if ENABLE_CONSOLE_SPE
+ static console_t spe_console;
+
+ if (id == TEGRA_CONSOLE_SPE_ID) {
+ (void)console_spe_register(TEGRA_CONSOLE_SPE_BASE,
+ console_clock,
+ TEGRA_CONSOLE_BAUDRATE,
+ &spe_console);
+ console_set_scope(&spe_console, CONSOLE_FLAG_BOOT |
+ CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH);
+ }
+#else
+ static console_t uart_console;
+
+ if ((id > 0) && (id < TEGRA194_MAX_UART_PORTS)) {
+ /*
+ * 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;
+ }
+
+ (void)console_16550_register(tegra194_uart_addresses[id],
+ console_clock,
+ TEGRA_CONSOLE_BAUDRATE,
+ &uart_console);
+ console_set_scope(&uart_console, CONSOLE_FLAG_BOOT |
+ CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH);
+ }
+#endif
+}
+
+/*******************************************************************************
+ * Verify SCR settings
+ ******************************************************************************/
+static inline bool tegra194_is_scr_valid(void)
+{
+ uint32_t scr_val;
+ bool ret = true;
+
+ for (uint8_t i = 0U; i < ARRAY_SIZE(t194_scr_settings); i++) {
+ scr_val = mmio_read_32((uintptr_t)t194_scr_settings[i].scr_addr);
+ if (scr_val != t194_scr_settings[i].scr_val) {
+ ERROR("Mismatch at SCR addr = 0x%x\n", t194_scr_settings[i].scr_addr);
+ ret = false;
+ }
+ }
+ return ret;
+}
+
+/*******************************************************************************
+ * Handler for early platform setup
+ ******************************************************************************/
+void plat_early_platform_setup(void)
+{
+ const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
+ uint8_t enable_ccplex_lock_step = params_from_bl2->enable_ccplex_lock_step;
+ uint64_t actlr_elx;
+
+ /* Verify chip id is t194 */
+ assert(tegra_chipid_is_t194());
+
+ /* Verify SCR settings */
+ if (tegra_platform_is_silicon()) {
+ assert(tegra194_is_scr_valid());
+ }
+
+ /* sanity check MCE firmware compatibility */
+ mce_verify_firmware_version();
+
+#if RAS_EXTENSION
+ /* Enable Uncorrectable RAS error */
+ tegra194_ras_enable();
+#endif
+
+ /*
+ * Program XUSB STREAMIDs
+ * ======================
+ * T19x XUSB has support for XUSB virtualization. It will have one
+ * physical function (PF) and four Virtual function (VF)
+ *
+ * There were below two SIDs for XUSB until T186.
+ * 1) #define TEGRA_SID_XUSB_HOST 0x1bU
+ * 2) #define TEGRA_SID_XUSB_DEV 0x1cU
+ *
+ * We have below four new SIDs added for VF(s)
+ * 3) #define TEGRA_SID_XUSB_VF0 0x5dU
+ * 4) #define TEGRA_SID_XUSB_VF1 0x5eU
+ * 5) #define TEGRA_SID_XUSB_VF2 0x5fU
+ * 6) #define TEGRA_SID_XUSB_VF3 0x60U
+ *
+ * When virtualization is enabled then we have to disable SID override
+ * and program above SIDs in below newly added SID registers in XUSB
+ * PADCTL MMIO space. These registers are TZ protected and so need to
+ * be done in ATF.
+ * a) #define XUSB_PADCTL_HOST_AXI_STREAMID_PF_0 (0x136cU)
+ * b) #define XUSB_PADCTL_DEV_AXI_STREAMID_PF_0 (0x139cU)
+ * c) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_0 (0x1370U)
+ * d) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_1 (0x1374U)
+ * e) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_2 (0x1378U)
+ * f) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_3 (0x137cU)
+ *
+ * This change disables SID override and programs XUSB SIDs in
+ * above registers to support both virtualization and
+ * non-virtualization platforms
+ */
+ if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) {
+
+ mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_HOST);
+ assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_PF_0) == TEGRA_SID_XUSB_HOST);
+ mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_VF_0, TEGRA_SID_XUSB_VF0);
+ assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_VF_0) == TEGRA_SID_XUSB_VF0);
+ mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_VF_1, TEGRA_SID_XUSB_VF1);
+ assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_VF_1) == TEGRA_SID_XUSB_VF1);
+ mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_VF_2, TEGRA_SID_XUSB_VF2);
+ assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_VF_2) == TEGRA_SID_XUSB_VF2);
+ mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_VF_3, TEGRA_SID_XUSB_VF3);
+ assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_HOST_AXI_STREAMID_VF_3) == TEGRA_SID_XUSB_VF3);
+ mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_DEV_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_DEV);
+ assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
+ XUSB_PADCTL_DEV_AXI_STREAMID_PF_0) == TEGRA_SID_XUSB_DEV);
+ }
+
+ /*
+ * Enable dual execution optimized translations for all ELx.
+ */
+ if (enable_ccplex_lock_step != 0U) {
+ actlr_elx = read_actlr_el3();
+ actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL3;
+ write_actlr_el3(actlr_elx);
+ /* check if the bit is actually set */
+ assert((read_actlr_el3() & DENVER_CPU_ENABLE_DUAL_EXEC_EL3) != 0ULL);
+
+ actlr_elx = read_actlr_el2();
+ actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL2;
+ write_actlr_el2(actlr_elx);
+ /* check if the bit is actually set */
+ assert((read_actlr_el2() & DENVER_CPU_ENABLE_DUAL_EXEC_EL2) != 0ULL);
+
+ actlr_elx = read_actlr_el1();
+ actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL1;
+ write_actlr_el1(actlr_elx);
+ /* check if the bit is actually set */
+ assert((read_actlr_el1() & DENVER_CPU_ENABLE_DUAL_EXEC_EL1) != 0ULL);
+ }
+}
+
+/* Secure IRQs for Tegra194 */
+static const interrupt_prop_t tegra194_interrupt_props[] = {
+ INTR_PROP_DESC(TEGRA_SDEI_SGI_PRIVATE, PLAT_SDEI_CRITICAL_PRI,
+ GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
+ INTR_PROP_DESC(TEGRA194_TOP_WDT_IRQ, PLAT_TEGRA_WDT_PRIO,
+ GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE)
+};
+
+/*******************************************************************************
+ * Initialize the GIC and SGIs
+ ******************************************************************************/
+void plat_gic_setup(void)
+{
+ tegra_gic_setup(tegra194_interrupt_props, ARRAY_SIZE(tegra194_interrupt_props));
+ tegra_gic_init();
+
+ /*
+ * Initialize the FIQ handler
+ */
+ tegra_fiq_handler_setup();
+}
+
+/*******************************************************************************
+ * Return pointer to the BL31 params from previous bootloader
+ ******************************************************************************/
+struct tegra_bl31_params *plat_get_bl31_params(void)
+{
+ uint64_t val;
+
+ val = (mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PARAMS_HI_ADDR) &
+ SCRATCH_BL31_PARAMS_HI_ADDR_MASK) >> SCRATCH_BL31_PARAMS_HI_ADDR_SHIFT;
+ val <<= 32;
+ val |= mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PARAMS_LO_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)
+{
+ uint64_t val;
+
+ val = (mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PLAT_PARAMS_HI_ADDR) &
+ SCRATCH_BL31_PLAT_PARAMS_HI_ADDR_MASK) >> SCRATCH_BL31_PLAT_PARAMS_HI_ADDR_SHIFT;
+ val <<= 32;
+ val |= mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PLAT_PARAMS_LO_ADDR);
+
+ return (plat_params_from_bl2_t *)(uintptr_t)val;
+}
+
+/*******************************************************************************
+ * Handler for late platform setup
+ ******************************************************************************/
+void plat_late_platform_setup(void)
+{
+#if ENABLE_STRICT_CHECKING_MODE
+ /*
+ * Enable strict checking after programming the GSC for
+ * enabling TZSRAM and TZDRAM
+ */
+ mce_enable_strict_checking();
+ mce_verify_strict_checking();
+#endif
+}
+
+/*******************************************************************************
+ * Handler to indicate support for System Suspend
+ ******************************************************************************/
+bool plat_supports_system_suspend(void)
+{
+ return true;
+}
+
+/*******************************************************************************
+ * Platform specific runtime setup.
+ ******************************************************************************/
+void 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();
+
+ /*
+ * Verify the integrity of the previously configured SMMU(s) settings
+ */
+ tegra_smmu_verify();
+}
diff --git a/plat/nvidia/tegra/soc/t194/plat_sip_calls.c b/plat/nvidia/tegra/soc/t194/plat_sip_calls.c
new file mode 100644
index 0000000..1eef559
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t194/plat_sip_calls.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/bl_common.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <common/debug.h>
+#include <errno.h>
+#include <mce.h>
+#include <mce_private.h>
+#include <memctrl.h>
+#include <common/runtime_svc.h>
+#include <tegra_private.h>
+#include <tegra_platform.h>
+#include <smmu.h>
+#include <stdbool.h>
+
+/*******************************************************************************
+ * Tegra194 SiP SMCs
+ ******************************************************************************/
+#define TEGRA_SIP_GET_SMMU_PER 0xC200FF00U
+#define TEGRA_SIP_CLEAR_RAS_CORRECTED_ERRORS 0xC200FF01U
+
+/*******************************************************************************
+ * This function is responsible for handling all T194 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 ret = 0;
+ uint32_t i, smmu_per[6] = {0};
+ uint32_t num_smmu_devices = plat_get_num_smmu_devices();
+ uint64_t per[3] = {0ULL};
+
+ (void)x1;
+ (void)x4;
+ (void)cookie;
+ (void)flags;
+
+ switch (smc_fid) {
+ case TEGRA_SIP_GET_SMMU_PER:
+
+ /* make sure we dont go past the array length */
+ assert(num_smmu_devices <= ARRAY_SIZE(smmu_per));
+
+ /* read all supported SMMU_PER records */
+ for (i = 0U; i < num_smmu_devices; i++) {
+ smmu_per[i] = tegra_smmu_read_32(i, SMMU_GSR0_PER);
+ }
+
+ /* pack results into 3 64bit variables. */
+ per[0] = smmu_per[0] | ((uint64_t)smmu_per[1] << 32U);
+ per[1] = smmu_per[2] | ((uint64_t)smmu_per[3] << 32U);
+ per[2] = smmu_per[4] | ((uint64_t)smmu_per[5] << 32U);
+
+ /* provide the results via X1-X3 CPU registers */
+ write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X1, per[0]);
+ write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X2, per[1]);
+ write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X3, per[2]);
+
+ break;
+
+#if RAS_EXTENSION
+ case TEGRA_SIP_CLEAR_RAS_CORRECTED_ERRORS:
+ {
+ /*
+ * clear all RAS error records for corrected errors at first.
+ * x1 shall be 0 for first SMC call after FHI is asserted.
+ * */
+ uint64_t local_x1 = x1;
+
+ tegra194_ras_corrected_err_clear(&local_x1);
+ if (local_x1 == 0ULL) {
+ /* clear HSM corrected error status after all corrected
+ * RAS errors are cleared.
+ */
+ mce_clear_hsm_corr_status();
+ }
+
+ write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X1, local_x1);
+
+ break;
+ }
+#endif
+
+ default:
+ ret = -ENOTSUP;
+ break;
+ }
+
+ return ret;
+}
diff --git a/plat/nvidia/tegra/soc/t194/plat_smmu.c b/plat/nvidia/tegra/soc/t194/plat_smmu.c
new file mode 100644
index 0000000..310e951
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t194/plat_smmu.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <smmu.h>
+#include <tegra_def.h>
+
+#define BOARD_SYSTEM_FPGA_BASE U(1)
+#define BASE_CONFIG_SMMU_DEVICES U(2)
+#define MAX_NUM_SMMU_DEVICES U(3)
+
+static uint32_t tegra_misc_read_32(uint32_t off)
+{
+ return mmio_read_32((uintptr_t)TEGRA_MISC_BASE + off);
+}
+
+/*******************************************************************************
+ * Handler to return the support SMMU devices number
+ ******************************************************************************/
+uint32_t plat_get_num_smmu_devices(void)
+{
+ uint32_t ret_num = MAX_NUM_SMMU_DEVICES;
+ uint32_t board_revid = ((tegra_misc_read_32(MISCREG_EMU_REVID) >> \
+ BOARD_SHIFT_BITS) & BOARD_MASK_BITS);
+
+ if (board_revid == BOARD_SYSTEM_FPGA_BASE) {
+ ret_num = BASE_CONFIG_SMMU_DEVICES;
+ }
+
+ return ret_num;
+}
diff --git a/plat/nvidia/tegra/soc/t194/plat_trampoline.S b/plat/nvidia/tegra/soc/t194/plat_trampoline.S
new file mode 100644
index 0000000..0ff5407
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t194/plat_trampoline.S
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <plat/common/common_def.h>
+#include <memctrl_v2.h>
+#include <tegra_def.h>
+
+#define TEGRA194_STATE_SYSTEM_SUSPEND 0x5C7
+#define TEGRA194_STATE_SYSTEM_RESUME 0x600D
+#define TEGRA194_MC_CTX_SIZE 0xFB
+
+ .align 4
+ .globl tegra194_cpu_reset_handler
+
+/* CPU reset handler routine */
+func tegra194_cpu_reset_handler
+ /* check if we are exiting system suspend state */
+ adr x0, __tegra194_system_suspend_state
+ ldr x1, [x0]
+ mov x2, #TEGRA194_STATE_SYSTEM_SUSPEND
+ lsl x2, x2, #16
+ add x2, x2, #TEGRA194_STATE_SYSTEM_SUSPEND
+ cmp x1, x2
+ bne boot_cpu
+
+ /* set system resume state */
+ mov x1, #TEGRA194_STATE_SYSTEM_RESUME
+ lsl x1, x1, #16
+ mov x2, #TEGRA194_STATE_SYSTEM_RESUME
+ add x1, x1, x2
+ str x1, [x0]
+ dsb sy
+
+ /* prepare to relocate to TZSRAM */
+ mov x0, #BL31_BASE
+ adr x1, __tegra194_cpu_reset_handler_end
+ adr x2, __tegra194_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
+
+ /*
+ * Synchronization barriers to make sure that memory is flushed out
+ * before we start execution in SysRAM.
+ */
+ dsb sy
+ isb
+
+boot_cpu:
+ adr x0, __tegra194_cpu_reset_handler_data
+ ldr x0, [x0]
+ br x0
+endfunc tegra194_cpu_reset_handler
+
+ /*
+ * Tegra194 reset data (offset 0x0 - 0x2490)
+ *
+ * 0x0000: secure world's entrypoint
+ * 0x0008: BL31 size (RO + RW)
+ * 0x0010: MC context start
+ * 0x2490: MC context end
+ */
+
+ .align 4
+ .type __tegra194_cpu_reset_handler_data, %object
+ .globl __tegra194_cpu_reset_handler_data
+__tegra194_cpu_reset_handler_data:
+ .quad tegra_secure_entrypoint
+ .quad __BL31_END__ - BL31_BASE
+ .globl __tegra194_system_suspend_state
+__tegra194_system_suspend_state:
+ .quad 0
+
+ .align 4
+__tegra194_mc_context:
+ .rept TEGRA194_MC_CTX_SIZE
+ .quad 0
+ .endr
+ .size __tegra194_cpu_reset_handler_data, \
+ . - __tegra194_cpu_reset_handler_data
+
+ .align 4
+ .globl __tegra194_cpu_reset_handler_end
+__tegra194_cpu_reset_handler_end:
+
+ .globl tegra194_get_cpu_reset_handler_size
+ .globl tegra194_get_cpu_reset_handler_base
+ .globl tegra194_get_mc_ctx_offset
+ .globl tegra194_set_system_suspend_entry
+
+/* return size of the CPU reset handler */
+func tegra194_get_cpu_reset_handler_size
+ adr x0, __tegra194_cpu_reset_handler_end
+ adr x1, tegra194_cpu_reset_handler
+ sub x0, x0, x1
+ ret
+endfunc tegra194_get_cpu_reset_handler_size
+
+/* return the start address of the CPU reset handler */
+func tegra194_get_cpu_reset_handler_base
+ adr x0, tegra194_cpu_reset_handler
+ ret
+endfunc tegra194_get_cpu_reset_handler_base
+
+/* return the size of the MC context */
+func tegra194_get_mc_ctx_offset
+ adr x0, __tegra194_mc_context
+ adr x1, tegra194_cpu_reset_handler
+ sub x0, x0, x1
+ ret
+endfunc tegra194_get_mc_ctx_offset
+
+/* set system suspend state before SC7 entry */
+func tegra194_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, __tegra194_system_suspend_state
+ adr x1, tegra194_cpu_reset_handler
+ sub x2, x0, x1 /* offset in TZDRAM */
+ mov x0, #TEGRA194_STATE_SYSTEM_SUSPEND
+ lsl x0, x0, #16
+ add x0, x0, #TEGRA194_STATE_SYSTEM_SUSPEND
+ str x0, [x3, x2] /* set value in TZDRAM */
+ dsb sy
+ ret
+endfunc tegra194_set_system_suspend_entry
diff --git a/plat/nvidia/tegra/soc/t194/platform_t194.mk b/plat/nvidia/tegra/soc/t194/platform_t194.mk
new file mode 100644
index 0000000..631c926
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t194/platform_t194.mk
@@ -0,0 +1,85 @@
+#
+# Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include common/fdt_wrappers.mk
+
+# platform configs
+ENABLE_CONSOLE_SPE := 1
+$(eval $(call add_define,ENABLE_CONSOLE_SPE))
+
+ENABLE_STRICT_CHECKING_MODE := 1
+$(eval $(call add_define,ENABLE_STRICT_CHECKING_MODE))
+
+USE_GPC_DMA := 1
+$(eval $(call add_define,USE_GPC_DMA))
+
+RESET_TO_BL31 := 1
+
+PROGRAMMABLE_RESET_ADDRESS := 1
+
+COLD_BOOT_SINGLE_CPU := 1
+
+# platform settings
+TZDRAM_BASE := 0x40000000
+$(eval $(call add_define,TZDRAM_BASE))
+
+MAX_XLAT_TABLES := 25
+$(eval $(call add_define,MAX_XLAT_TABLES))
+
+MAX_MMAP_REGIONS := 30
+$(eval $(call add_define,MAX_MMAP_REGIONS))
+
+# enable RAS handling
+HANDLE_EA_EL3_FIRST_NS := 1
+RAS_EXTENSION := 1
+
+# platform files
+PLAT_INCLUDES += -Iplat/nvidia/tegra/include/t194 \
+ -I${SOC_DIR}/drivers/include
+
+BL31_SOURCES += ${TEGRA_GICv2_SOURCES} \
+ drivers/ti/uart/aarch64/16550_console.S \
+ lib/cpus/aarch64/denver.S \
+ ${TEGRA_DRIVERS}/bpmp_ipc/intf.c \
+ ${TEGRA_DRIVERS}/bpmp_ipc/ivc.c \
+ ${TEGRA_DRIVERS}/memctrl/memctrl_v2.c \
+ ${TEGRA_DRIVERS}/smmu/smmu.c \
+ ${SOC_DIR}/drivers/mce/mce.c \
+ ${SOC_DIR}/drivers/mce/nvg.c \
+ ${SOC_DIR}/drivers/mce/aarch64/nvg_helpers.S \
+ ${SOC_DIR}/drivers/se/se.c \
+ ${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
+
+ifeq (${USE_GPC_DMA}, 1)
+BL31_SOURCES += ${TEGRA_DRIVERS}/gpcdma/gpcdma.c
+endif
+
+ifeq (${ENABLE_CONSOLE_SPE},1)
+BL31_SOURCES += ${TEGRA_DRIVERS}/spe/shared_console.S
+endif
+
+# RAS sources
+ifeq (${RAS_EXTENSION},1)
+BL31_SOURCES += lib/extensions/ras/std_err_record.c \
+ lib/extensions/ras/ras_common.c \
+ ${SOC_DIR}/plat_ras.c
+endif
+
+# SPM dispatcher
+ifeq (${SPD},spmd)
+include lib/libfdt/libfdt.mk
+# sources to support spmd
+BL31_SOURCES += plat/common/plat_spmd_manifest.c \
+ ${LIBFDT_SRCS}
+
+BL31_SOURCES += ${FDT_WRAPPERS_SOURCES}
+endif
diff --git a/plat/nvidia/tegra/soc/t210/drivers/se/se_private.h b/plat/nvidia/tegra/soc/t210/drivers/se/se_private.h
new file mode 100644
index 0000000..c44b0fc
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t210/drivers/se/se_private.h
@@ -0,0 +1,663 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SE_PRIVATE_H
+#define SE_PRIVATE_H
+
+#include <stdbool.h>
+#include <security_engine.h>
+
+/*
+ * PMC registers
+ */
+
+/* SC7 context save scratch register for T210 */
+#define PMC_SCRATCH43_REG_OFFSET U(0x22C)
+
+/* 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_ENABLE_REG_OFFSET U(0xC)
+#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 */
diff --git a/plat/nvidia/tegra/soc/t210/drivers/se/security_engine.c b/plat/nvidia/tegra/soc/t210/drivers/se/security_engine.c
new file mode 100644
index 0000000..4860858
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t210/drivers/se/security_engine.c
@@ -0,0 +1,1071 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <se_private.h>
+#include <security_engine.h>
+#include <tegra_platform.h>
+
+/*******************************************************************************
+ * 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 for T210 */
+static const uint8_t se_ctx_known_pattern_data[SE_CTX_KNOWN_PATTERN_SIZE] = {
+ /* 128 bit AES block */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
+ };
+
+/* 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 context buffer, 132 blocks */
+static __aligned(64) uint8_t se1_ctx_buf[SE_CTX_DRBG_BUFER_SIZE];
+
+/* 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 *)&se1_ctx_buf
+};
+
+/* SE2 security engine device handle (T210B01 only) */
+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;
+}
+
+/*
+ * 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;
+
+ /* disable SE interrupt to prevent interrupt issued by SE operation */
+ tegra_se_write_32(se_dev, SE_INT_ENABLE_REG_OFFSET, 0U);
+
+ /* 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;
+ /* For T210, First the modulus and then exponent must be
+ * encrypted and saved. This is repeated for SLOT 0
+ * and SLOT 1. Hence the order:
+ * SLOT 0 modulus : RSA_KEY_INDEX : 1
+ * SLOT 0 exponent : RSA_KEY_INDEX : 0
+ * SLOT 1 modulus : RSA_KEY_INDEX : 3
+ * SLOT 1 exponent : RSA_KEY_INDEX : 2
+ */
+ const unsigned int key_index_mod[TEGRA_SE_RSA_KEYSLOT_COUNT][2] = {
+ /* RSA key slot 0 */
+ {SE_RSA_KEY_INDEX_SLOT0_MOD, SE_RSA_KEY_INDEX_SLOT0_EXP},
+ /* RSA key slot 1 */
+ {SE_RSA_KEY_INDEX_SLOT1_MOD, SE_RSA_KEY_INDEX_SLOT1_EXP},
+ };
+
+ 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, support T210 only */
+ mmio_write_32((uint64_t)TEGRA_PMC_BASE + PMC_SCRATCH43_REG_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);
+
+ if (tegra_chipid_is_t210_b01()) {
+ 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);
+
+ /*
+ * Switch SE clock source to CLK_M, to make sure SE clock
+ * is on when saving SE context
+ */
+ mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_RST_CTL_CLK_SRC_SE,
+ SE_CLK_SRC_CLK_M);
+
+ /* 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_chipid_is_t210_b01()) {
+ /* It is T210 B01, Atomic context save se2 and pka1 */
+ INFO("%s: SE2/PKA1 atomic context save\n", __func__);
+ ret = tegra_se_context_save_atomic(&se_dev_2);
+ if (ret != 0) {
+ ERROR("%s: SE2 ctx save failed (%d)\n", __func__, ret);
+ }
+
+ ret = tegra_se_context_save_atomic(&se_dev_1);
+ if (ret != 0) {
+ ERROR("%s: SE1 ctx save failed (%d)\n", __func__, ret);
+ }
+ } else {
+ /* It is T210, SW context save se */
+ INFO("%s: SE1 legacy(SW) context save\n", __func__);
+ ret = tegra_se_context_save_sw(&se_dev_1);
+ if (ret != 0) {
+ ERROR("%s: SE1 ctx save failed (%d)\n", __func__, ret);
+ }
+ }
+
+ 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);
+
+ if (tegra_chipid_is_t210_b01()) {
+ tegra_se_warm_boot_resume(&se_dev_2);
+ }
+}
diff --git a/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c
new file mode 100644
index 0000000..7f73ea5
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c
@@ -0,0 +1,609 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <cortex_a57.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include <bpmp.h>
+#include <flowctrl.h>
+#include <lib/utils.h>
+#include <memctrl.h>
+#include <pmc.h>
+#include <platform_def.h>
+#include <security_engine.h>
+#include <tegra_def.h>
+#include <tegra_private.h>
+#include <tegra_platform.h>
+
+/*
+ * 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;
+}
+
+int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state)
+{
+ (void)cpu_state;
+ return PSCI_E_SUCCESS;
+}
+
+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));
+
+ /* Suspend se/se2 and pka1 for T210 B01 and se for T210 */
+ 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();
+
+ /*
+ * Mark PMC as accessible to the non-secure world
+ * to allow the COP to execute System Suspend
+ * sequence
+ */
+ 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);
+
+ /* 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;
+}
+
+int32_t tegra_soc_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state)
+{
+ return PSCI_E_NOT_SUPPORTED;
+}
+
+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();
+ }
+
+ if (plat_params->sc7entry_fw_base != 0U) {
+ /* sc7entry-fw is part of TZDRAM area */
+ offset = plat_params->tzdram_base - plat_params->sc7entry_fw_base;
+ tegra_memctrl_tzdram_setup(plat_params->sc7entry_fw_base,
+ plat_params->tzdram_size + offset);
+ }
+
+ if (!tegra_chipid_is_t210_b01()) {
+ /* 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();
+ }
+ }
+
+ /*
+ * Mark this CPU as ON in the cpu_powergate_mask[],
+ * so that we use Flow Controller for all subsequent
+ * power ups.
+ */
+ cpu_powergate_mask[plat_my_core_pos()] = 1;
+
+ /*
+ * 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
+ */
+ if (!tegra_chipid_is_t210_b01()) {
+ 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);
+ } 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);
+
+ /*
+ * Program the PMC in order to restart the system.
+ */
+ tegra_pmc_system_reset();
+
+ return PSCI_E_SUCCESS;
+}
+
+__dead2 void tegra_soc_prepare_system_off(void)
+{
+ ERROR("Tegra System Off: operation not handled.\n");
+ panic();
+}
diff --git a/plat/nvidia/tegra/soc/t210/plat_secondary.c b/plat/nvidia/tegra/soc/t210/plat_secondary.c
new file mode 100644
index 0000000..e0242cf
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t210/plat_secondary.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <pmc.h>
+#include <tegra_def.h>
+
+#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();
+}
diff --git a/plat/nvidia/tegra/soc/t210/plat_setup.c b/plat/nvidia/tegra/soc/t210/plat_setup.c
new file mode 100644
index 0000000..68cd38e
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t210/plat_setup.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <cortex_a57.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/console.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <bl31/interrupt_mgmt.h>
+
+#include <bpmp.h>
+#include <flowctrl.h>
+#include <memctrl.h>
+#include <plat/common/platform.h>
+#include <security_engine.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+/* 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,
+};
+
+/*******************************************************************************
+ * Enable console corresponding to the console ID
+ ******************************************************************************/
+void plat_enable_console(int32_t id)
+{
+ static console_t uart_console;
+ uint32_t console_clock;
+
+ if ((id > 0) && (id < TEGRA210_MAX_UART_PORTS)) {
+ /*
+ * 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;
+ }
+
+ (void)console_16550_register(tegra210_uart_addresses[id],
+ console_clock,
+ TEGRA_CONSOLE_BAUDRATE,
+ &uart_console);
+ console_set_scope(&uart_console, CONSOLE_FLAG_BOOT |
+ CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH);
+ }
+}
+
+/*******************************************************************************
+ * Return pointer to the BL31 params from previous bootloader
+ ******************************************************************************/
+struct tegra_bl31_params *plat_get_bl31_params(void)
+{
+ return NULL;
+}
+
+/*******************************************************************************
+ * Return pointer to the BL31 platform params from previous bootloader
+ ******************************************************************************/
+plat_params_from_bl2_t *plat_get_bl31_plat_params(void)
+{
+ return NULL;
+}
+
+/*******************************************************************************
+ * 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;
+
+ /* Verify chip id is t210 */
+ assert(tegra_chipid_is_t210());
+
+ /*
+ * Do initial security configuration to allow DRAM/device access.
+ */
+ tegra_memctrl_tzdram_setup(plat_params->tzdram_base,
+ (uint32_t)plat_params->tzdram_size);
+
+ /* 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 */
+ tegra_se_init();
+}
+
+/* Secure IRQs for Tegra186 */
+static const interrupt_prop_t tegra210_interrupt_props[] = {
+ INTR_PROP_DESC(TEGRA_SDEI_SGI_PRIVATE, PLAT_SDEI_CRITICAL_PRI,
+ GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
+ INTR_PROP_DESC(TEGRA210_TIMER1_IRQ, PLAT_TEGRA_WDT_PRIO,
+ GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
+ INTR_PROP_DESC(TEGRA210_WDT_CPU_LEGACY_FIQ, PLAT_TEGRA_WDT_PRIO,
+ GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
+};
+
+/*******************************************************************************
+ * Handler for late platform setup
+ ******************************************************************************/
+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);
+ }
+
+ if (!tegra_chipid_is_t210_b01()) {
+ /* 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();
+}
+/*******************************************************************************
+ * Handler to indicate support for System Suspend
+ ******************************************************************************/
+bool plat_supports_system_suspend(void)
+{
+ const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
+
+ /*
+ * sc7entry-fw is only supported by Tegra210 SoCs.
+ */
+ if (!tegra_chipid_is_t210_b01() && (plat_params->sc7entry_fw_base != 0U)) {
+ return true;
+ } else if (tegra_chipid_is_t210_b01()) {
+ return true;
+ } else {
+ return false;
+ }
+}
+/*******************************************************************************
+ * Platform specific runtime setup.
+ ******************************************************************************/
+void 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();
+}
diff --git a/plat/nvidia/tegra/soc/t210/plat_sip_calls.c b/plat/nvidia/tegra/soc/t210/plat_sip_calls.c
new file mode 100644
index 0000000..e3484be
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t210/plat_sip_calls.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <inttypes.h>
+#include <stdint.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include <memctrl.h>
+#include <pmc.h>
+#include <tegra_private.h>
+#include <tegra_platform.h>
+#include <tegra_def.h>
+
+/*******************************************************************************
+ * 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);
+
+ if (smc_fid == TEGRA_SIP_PMC_COMMANDS) {
+ /* check the address is within PMC range and is 4byte aligned */
+ if ((x2 >= TEGRA_PMC_SIZE) || (x2 & 0x3))
+ return -EINVAL;
+
+ switch (x2) {
+ /* Black listed PMC registers */
+ case PMC_SCRATCH1:
+ case PMC_SCRATCH31 ... PMC_SCRATCH33:
+ case PMC_SCRATCH40:
+ case PMC_SCRATCH42:
+ case PMC_SCRATCH43 ... PMC_SCRATCH48:
+ case PMC_SCRATCH50 ... PMC_SCRATCH51:
+ case PMC_SCRATCH56 ... PMC_SCRATCH57:
+ /* PMC secure-only registers are not accessible */
+ case PMC_DPD_ENABLE_0:
+ case PMC_FUSE_CONTROL_0:
+ case PMC_CRYPTO_OP_0:
+ case PMC_TSC_MULT_0:
+ case PMC_STICKY_BIT:
+ ERROR("%s: error offset=0x%" PRIx64 "\n", __func__, x2);
+ return -EFAULT;
+ default:
+ /* Valid register */
+ break;
+ }
+
+ /* 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;
+ }
+ } else {
+ return -ENOTSUP;
+ }
+ return 0;
+}
diff --git a/plat/nvidia/tegra/soc/t210/platform_t210.mk b/plat/nvidia/tegra/soc/t210/platform_t210.mk
new file mode 100644
index 0000000..724cfc3
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t210/platform_t210.mk
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2020, NVIDIA Corporation. 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_TEGRA_WDT_LEGACY_FIQ_HANDLING := 1
+
+PLAT_INCLUDES += -Iplat/nvidia/tegra/include/t210 \
+ -I${SOC_DIR}/drivers/se
+
+BL31_SOURCES += ${TEGRA_GICv2_SOURCES} \
+ drivers/ti/uart/aarch64/16550_console.S \
+ lib/cpus/aarch64/cortex_a53.S \
+ lib/cpus/aarch64/cortex_a57.S \
+ ${TEGRA_DRIVERS}/bpmp/bpmp.c \
+ ${TEGRA_DRIVERS}/flowctrl/flowctrl.c \
+ ${TEGRA_DRIVERS}/memctrl/memctrl_v1.c \
+ ${TEGRA_DRIVERS}/pmc/pmc.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_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
+
+# Enable higher performance Non-cacheable load forwarding
+A57_ENABLE_NONCACHEABLE_LOAD_FWD := 1
diff --git a/plat/nxp/common/aarch64/bl31_data.S b/plat/nxp/common/aarch64/bl31_data.S
new file mode 100644
index 0000000..cc91540
--- /dev/null
+++ b/plat/nxp/common/aarch64/bl31_data.S
@@ -0,0 +1,558 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <asm_macros.S>
+
+#include "bl31_data.h"
+#include "plat_psci.h"
+#include "platform_def.h"
+
+.global _getCoreData
+.global _setCoreData
+.global _getCoreState
+.global _setCoreState
+.global _init_global_data
+.global _get_global_data
+.global _set_global_data
+.global _initialize_psci
+.global _init_task_flags
+.global _set_task1_start
+.global _set_task1_done
+
+
+/* Function returns the specified data field value from the specified cpu
+ * core data area
+ * in: x0 = core mask lsb
+ * x1 = data field name/offset
+ * out: x0 = data value
+ * uses x0, x1, x2, [x13, x14, x15]
+ */
+func _getCoreData
+
+ /* generate a 0-based core number from the input mask */
+ clz x2, x0
+ mov x0, #63
+ sub x0, x0, x2
+
+ /* x0 = core number (0-based) */
+ /* x1 = field offset */
+
+ /* determine if this is bootcore or secondary core */
+ cbnz x0, 1f
+
+ /* get base address for bootcore data */
+ ldr x2, =BC_PSCI_BASE
+ add x2, x2, x1
+ b 2f
+
+1: /* get base address for secondary core data */
+
+ /* x0 = core number (0-based) */
+ /* x1 = field offset */
+
+ /* generate number of regions to offset */
+ mov x2, #SEC_REGION_SIZE
+ mul x2, x2, x0
+
+ /* x1 = field offset */
+ /* x2 = region offset */
+
+ /* generate the total offset to data element */
+ sub x1, x2, x1
+
+ /* x1 = total offset to data element */
+
+ /* get the base address */
+ ldr x2, =SECONDARY_TOP
+
+ /* apply offset to base addr */
+ sub x2, x2, x1
+2:
+ /* x2 = data element address */
+
+ dc ivac, x2
+ dsb sy
+ isb
+ /* read data */
+ ldr x0, [x2]
+
+ ret
+endfunc _getCoreData
+
+
+/* Function returns the SoC-specific state of the specified cpu
+ * in: x0 = core mask lsb
+ * out: x0 = data value
+ * uses x0, x1, x2, [x13, x14, x15]
+ */
+func _getCoreState
+
+ mov x1, #CORE_STATE_DATA
+
+ /* generate a 0-based core number from the input mask */
+ clz x2, x0
+ mov x0, #63
+ sub x0, x0, x2
+
+ /* x0 = core number (0-based) */
+ /* x1 = field offset */
+
+ /* determine if this is bootcore or secondary core */
+ cbnz x0, 1f
+
+ /* get base address for bootcore data */
+ ldr x2, =BC_PSCI_BASE
+ add x2, x2, x1
+ b 2f
+
+1: /* get base address for secondary core data */
+
+ /* x0 = core number (0-based) */
+ /* x1 = field offset */
+
+ /* generate number of regions to offset */
+ mov x2, #SEC_REGION_SIZE
+ mul x2, x2, x0
+
+ /* x1 = field offset */
+ /* x2 = region offset */
+
+ /* generate the total offset to data element */
+ sub x1, x2, x1
+
+ /* x1 = total offset to data element */
+
+ /* get the base address */
+ ldr x2, =SECONDARY_TOP
+
+ /* apply offset to base addr */
+ sub x2, x2, x1
+2:
+ /* x2 = data element address */
+
+ dc ivac, x2
+ dsb sy
+ isb
+
+ /* read data */
+ ldr x0, [x2]
+
+ ret
+endfunc _getCoreState
+
+
+/* Function writes the specified data value into the specified cpu
+ * core data area
+ * in: x0 = core mask lsb
+ * x1 = data field offset
+ * x2 = data value to write/store
+ * out: none
+ * uses x0, x1, x2, x3, [x13, x14, x15]
+ */
+func _setCoreData
+ /* x0 = core mask */
+ /* x1 = field offset */
+ /* x2 = data value */
+
+ clz x3, x0
+ mov x0, #63
+ sub x0, x0, x3
+
+ /* x0 = core number (0-based) */
+ /* x1 = field offset */
+ /* x2 = data value */
+
+ /* determine if this is bootcore or secondary core */
+ cbnz x0, 1f
+
+ /* get base address for bootcore data */
+ ldr x3, =BC_PSCI_BASE
+ add x3, x3, x1
+ b 2f
+
+1: /* get base address for secondary core data */
+
+ /* x0 = core number (0-based) */
+ /* x1 = field offset */
+ /* x2 = data value */
+
+ /* generate number of regions to offset */
+ mov x3, #SEC_REGION_SIZE
+ mul x3, x3, x0
+
+ /* x1 = field offset */
+ /* x2 = data value */
+ /* x3 = region offset */
+
+ /* generate the total offset to data element */
+ sub x1, x3, x1
+
+ /* x1 = total offset to data element */
+ /* x2 = data value */
+
+ ldr x3, =SECONDARY_TOP
+
+ /* apply offset to base addr */
+ sub x3, x3, x1
+
+2:
+ /* x2 = data value */
+ /* x3 = data element address */
+
+ str x2, [x3]
+
+ dc cvac, x3
+ dsb sy
+ isb
+ ret
+endfunc _setCoreData
+
+
+/* Function stores the specified core state
+ * in: x0 = core mask lsb
+ * x1 = data value to write/store
+ * out: none
+ * uses x0, x1, x2, x3, [x13, x14, x15]
+ */
+func _setCoreState
+ mov x2, #CORE_STATE_DATA
+
+ clz x3, x0
+ mov x0, #63
+ sub x0, x0, x3
+
+ /* x0 = core number (0-based) */
+ /* x1 = data value */
+ /* x2 = field offset */
+
+ /* determine if this is bootcore or secondary core */
+ cbnz x0, 1f
+
+ /* get base address for bootcore data */
+ ldr x3, =BC_PSCI_BASE
+ add x3, x3, x2
+ b 2f
+
+1: /* get base address for secondary core data */
+
+ /* x0 = core number (0-based) */
+ /* x1 = data value */
+ /* x2 = field offset */
+
+ /* generate number of regions to offset */
+ mov x3, #SEC_REGION_SIZE
+ mul x3, x3, x0
+
+ /* x1 = data value */
+ /* x2 = field offset */
+ /* x3 = region offset */
+
+ /* generate the total offset to data element */
+ sub x2, x3, x2
+
+ /* x1 = data value */
+ /* x2 = total offset to data element */
+
+ ldr x3, =SECONDARY_TOP
+
+ /* apply offset to base addr */
+ sub x3, x3, x2
+
+2:
+ /* x1 = data value */
+ /* x3 = data element address */
+
+ str x1, [x3]
+
+ dc civac, x3
+ dsb sy
+ isb
+ ret
+endfunc _setCoreState
+
+
+/* Function sets the task1 start
+ * in: w0 = value to set flag to
+ * out: none
+ * uses x0, x1
+ */
+func _set_task1_start
+
+ ldr x1, =SMC_TASK1_BASE
+
+ add x1, x1, #TSK_START_OFFSET
+ str w0, [x1]
+ dc cvac, x1
+ dsb sy
+ isb
+ ret
+endfunc _set_task1_start
+
+
+/* Function sets the state of the task 1 done flag
+ * in: w0 = value to set flag to
+ * out: none
+ * uses x0, x1
+ */
+func _set_task1_done
+
+ ldr x1, =SMC_TASK1_BASE
+
+ add x1, x1, #TSK_DONE_OFFSET
+ str w0, [x1]
+ dc cvac, x1
+ dsb sy
+ isb
+ ret
+endfunc _set_task1_done
+
+
+/* Function initializes the smc global data entries
+ * Note: the constant LAST_SMC_GLBL_OFFSET must reference the last entry in the
+ * smc global region
+ * in: none
+ * out: none
+ * uses x0, x1, x2
+ */
+func _init_global_data
+
+ ldr x1, =SMC_GLBL_BASE
+
+ /* x1 = SMC_GLBL_BASE */
+
+ mov x2, #LAST_SMC_GLBL_OFFSET
+ add x2, x2, x1
+1:
+ str xzr, [x1]
+ dc cvac, x1
+ cmp x2, x1
+ add x1, x1, #8
+ b.hi 1b
+
+ dsb sy
+ isb
+ ret
+endfunc _init_global_data
+
+
+/* Function gets the value of the specified global data element
+ * in: x0 = offset of data element
+ * out: x0 = requested data element
+ * uses x0, x1
+ */
+func _get_global_data
+
+ ldr x1, =SMC_GLBL_BASE
+ add x1, x1, x0
+ dc ivac, x1
+ isb
+
+ ldr x0, [x1]
+ ret
+endfunc _get_global_data
+
+
+/* Function sets the value of the specified global data element
+ * in: x0 = offset of data element
+ * x1 = value to write
+ * out: none
+ * uses x0, x1, x2
+ */
+func _set_global_data
+
+ ldr x2, =SMC_GLBL_BASE
+ add x0, x0, x2
+ str x1, [x0]
+ dc cvac, x0
+
+ dsb sy
+ isb
+ ret
+endfunc _set_global_data
+
+
+/* Function initializes the core data areas
+ * only executed by the boot core
+ * in: none
+ * out: none
+ * uses: x0, x1, x2, x3, x4, x5, x6, x7, [x13, x14, x15]
+ */
+func _initialize_psci
+ mov x7, x30
+
+ /* initialize the bootcore psci data */
+ ldr x5, =BC_PSCI_BASE
+ mov x6, #CORE_RELEASED
+
+ str x6, [x5], #8
+ dc cvac, x5
+ str xzr, [x5], #8
+ dc cvac, x5
+ str xzr, [x5], #8
+ dc cvac, x5
+ str xzr, [x5], #8
+ dc cvac, x5
+ str xzr, [x5], #8
+ dc cvac, x5
+ str xzr, [x5], #8
+ dc cvac, x5
+ str xzr, [x5], #8
+ dc cvac, x5
+ str xzr, [x5], #8
+ dc cvac, x5
+ str xzr, [x5], #8
+ dc cvac, x5
+ str xzr, [x5], #8
+ dc cvac, x5
+ str xzr, [x5], #8
+ dc cvac, x5
+ str xzr, [x5], #8
+ dc cvac, x5
+ str xzr, [x5], #8
+ dc cvac, x5
+ str xzr, [x5], #8
+ dc cvac, x5
+ str xzr, [x5], #8
+ dc cvac, x5
+ str xzr, [x5]
+ dc cvac, x5
+ dsb sy
+ isb
+
+ /* see if we have any secondary cores */
+ mov x4, #PLATFORM_CORE_COUNT
+ sub x4, x4, #1
+ cbz x4, 3f
+
+ /* initialize the secondary core's psci data */
+ ldr x5, =SECONDARY_TOP
+ /* core mask lsb for core 1 */
+ mov x3, #2
+ sub x5, x5, #SEC_REGION_SIZE
+
+ /* x3 = core1 mask lsb */
+ /* x4 = number of secondary cores */
+ /* x5 = core1 psci data base address */
+2:
+ /* set core state in x6 */
+ mov x0, x3
+ mov x6, #CORE_IN_RESET
+ bl _soc_ck_disabled
+ cbz x0, 1f
+ mov x6, #CORE_DISABLED
+1:
+ add x2, x5, #CORE_STATE_DATA
+ str x6, [x2]
+ dc cvac, x2
+ add x2, x5, #SPSR_EL3_DATA
+ str xzr, [x2]
+ dc cvac, x2
+ add x2, x5, #CNTXT_ID_DATA
+ str xzr, [x2]
+ dc cvac, x2
+ add x2, x5, #START_ADDR_DATA
+ str xzr, [x2]
+ dc cvac, x2
+ add x2, x5, #LINK_REG_DATA
+ str xzr, [x2]
+ dc cvac, x2
+ add x2, x5, #GICC_CTLR_DATA
+ str xzr, [x2]
+ dc cvac, x2
+ add x2, x5, #ABORT_FLAG_DATA
+ str xzr, [x2]
+ dc cvac, x2
+ add x2, x5, #SCTLR_DATA
+ str xzr, [x2]
+ dc cvac, x2
+ add x2, x5, #CPUECTLR_DATA
+ str xzr, [x2]
+ dc cvac, x2
+ add x2, x5, #AUX_01_DATA
+ str xzr, [x2]
+ dc cvac, x2
+ add x2, x5, #AUX_02_DATA
+ str xzr, [x2]
+ dc cvac, x2
+ add x2, x5, #AUX_03_DATA
+ str xzr, [x2]
+ dc cvac, x2
+ add x2, x5, #AUX_04_DATA
+ str xzr, [x2]
+ dc cvac, x2
+ add x2, x5, #AUX_05_DATA
+ str xzr, [x2]
+ dc cvac, x2
+ add x2, x5, #SCR_EL3_DATA
+ str xzr, [x2]
+ dc cvac, x2
+ add x2, x5, #HCR_EL2_DATA
+ str xzr, [x2]
+ dc cvac, x2
+ dsb sy
+ isb
+
+ sub x4, x4, #1
+ cbz x4, 3f
+
+ /* generate next core mask */
+ lsl x3, x3, #1
+
+ /* decrement base address to next data area */
+ sub x5, x5, #SEC_REGION_SIZE
+ b 2b
+3:
+ mov x30, x7
+ ret
+endfunc _initialize_psci
+
+
+/* Function initializes the soc init task flags
+ * in: none
+ * out: none
+ * uses x0, x1, [x13, x14, x15]
+ */
+func _init_task_flags
+
+ /* get the base address of the first task structure */
+ ldr x0, =SMC_TASK1_BASE
+
+ /* x0 = task1 base address */
+
+ str wzr, [x0, #TSK_START_OFFSET]
+ str wzr, [x0, #TSK_DONE_OFFSET]
+ str wzr, [x0, #TSK_CORE_OFFSET]
+ dc cvac, x0
+
+ /* move to task2 structure */
+ add x0, x0, #SMC_TASK_OFFSET
+
+ str wzr, [x0, #TSK_START_OFFSET]
+ str wzr, [x0, #TSK_DONE_OFFSET]
+ str wzr, [x0, #TSK_CORE_OFFSET]
+ dc cvac, x0
+
+ /* move to task3 structure */
+ add x0, x0, #SMC_TASK_OFFSET
+
+ str wzr, [x0, #TSK_START_OFFSET]
+ str wzr, [x0, #TSK_DONE_OFFSET]
+ str wzr, [x0, #TSK_CORE_OFFSET]
+ dc cvac, x0
+
+ /* move to task4 structure */
+ add x0, x0, #SMC_TASK_OFFSET
+
+ str wzr, [x0, #TSK_START_OFFSET]
+ str wzr, [x0, #TSK_DONE_OFFSET]
+ str wzr, [x0, #TSK_CORE_OFFSET]
+ dc cvac, x0
+
+ dsb sy
+ isb
+ ret
+endfunc _init_task_flags
diff --git a/plat/nxp/common/aarch64/ls_helpers.S b/plat/nxp/common/aarch64/ls_helpers.S
new file mode 100644
index 0000000..311dce1
--- /dev/null
+++ b/plat/nxp/common/aarch64/ls_helpers.S
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <asm_macros.S>
+#include <cortex_a53.h>
+#include <drivers/console.h>
+#include <lib/cpus/aarch64/cortex_a72.h>
+
+#include <platform_def.h>
+
+
+ .globl plat_crash_console_init
+ .globl plat_crash_console_putc
+ .globl plat_crash_console_flush
+ .globl plat_core_pos
+ .globl plat_my_core_pos
+ .globl plat_core_mask
+ .globl plat_my_core_mask
+ .globl plat_core_pos_by_mpidr
+ .globl _disable_ldstr_pfetch_A53
+ .globl _disable_ldstr_pfetch_A72
+ .global _set_smmu_pagesz_64
+
+ /* 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
+ mov x3, x30
+ mov x0, #CONSOLE_FLAG_CRASH
+ bl console_switch_state
+ mov x0, #1
+ ret x3
+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
+
+/* 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.
+ */
+func plat_core_pos_by_mpidr
+
+ b plat_core_pos
+
+endfunc plat_core_pos_by_mpidr
+
+#if (SYMMETRICAL_CLUSTERS)
+/* unsigned int plat_my_core_mask(void)
+ * generate a mask bit for this core
+ */
+func plat_my_core_mask
+ mrs x0, MPIDR_EL1
+ b plat_core_mask
+endfunc plat_my_core_mask
+
+/* unsigned int plat_core_mask(u_register_t mpidr)
+ * generate a lsb-based mask bit for the core specified by mpidr in x0.
+ *
+ * SoC core = ((cluster * cpu_per_cluster) + core)
+ * mask = (1 << SoC core)
+ */
+func plat_core_mask
+ mov w1, wzr
+ mov w2, wzr
+
+ /* extract cluster */
+ bfxil w1, w0, #8, #8
+ /* extract cpu # */
+ bfxil w2, w0, #0, #8
+
+ mov w0, wzr
+
+ /* error checking */
+ cmp w1, #NUMBER_OF_CLUSTERS
+ b.ge 1f
+ cmp w2, #CORES_PER_CLUSTER
+ b.ge 1f
+
+ mov w0, #CORES_PER_CLUSTER
+ mul w1, w1, w0
+ add w1, w1, w2
+ mov w2, #0x1
+ lsl w0, w2, w1
+1:
+ ret
+endfunc plat_core_mask
+
+/*
+ * unsigned int plat_my_core_pos(void)
+ * generate a linear core number for this core
+ */
+func plat_my_core_pos
+ mrs x0, MPIDR_EL1
+ b plat_core_pos
+endfunc plat_my_core_pos
+
+/*
+ * unsigned int plat_core_pos(u_register_t mpidr)
+ * Generate a linear core number for the core specified by mpidr.
+ *
+ * SoC core = ((cluster * cpu_per_cluster) + core)
+ * Returns -1 if mpidr invalid
+ */
+func plat_core_pos
+ mov w1, wzr
+ mov w2, wzr
+ bfxil w1, w0, #8, #8 /* extract cluster */
+ bfxil w2, w0, #0, #8 /* extract cpu # */
+
+ mov w0, #-1
+
+ /* error checking */
+ cmp w1, #NUMBER_OF_CLUSTERS
+ b.ge 1f
+ cmp w2, #CORES_PER_CLUSTER
+ b.ge 1f
+
+ mov w0, #CORES_PER_CLUSTER
+ mul w1, w1, w0
+ add w0, w1, w2
+1:
+ ret
+endfunc plat_core_pos
+
+#endif
+
+/* this function disables the load-store prefetch of the calling core
+ * Note: this function is for A53 cores ONLY
+ * in: none
+ * out: none
+ * uses x0
+ */
+func _disable_ldstr_pfetch_A53
+ mrs x0, CORTEX_A53_CPUACTLR_EL1
+ tst x0, #CORTEX_A53_CPUACTLR_EL1_L1PCTL
+ b.ne 1f
+ b 2f
+
+.align 6
+1:
+ dsb sy
+ isb
+ bic x0, x0, #CORTEX_A53_CPUACTLR_EL1_L1PCTL
+ msr CORTEX_A53_CPUACTLR_EL1, x0
+ isb
+
+2:
+ ret
+endfunc _disable_ldstr_pfetch_A53
+
+
+/* this function disables the load-store prefetch of the calling core
+ * Note: this function is for A72 cores ONLY
+ * in: none
+ * out: none
+ * uses x0
+ */
+func _disable_ldstr_pfetch_A72
+
+ mrs x0, CORTEX_A72_CPUACTLR_EL1
+ tst x0, #CORTEX_A72_CPUACTLR_EL1_DISABLE_L1_DCACHE_HW_PFTCH
+ b.eq 1f
+ b 2f
+
+.align 6
+1:
+ dsb sy
+ isb
+ orr x0, x0, #CORTEX_A72_CPUACTLR_EL1_DISABLE_L1_DCACHE_HW_PFTCH
+ msr CORTEX_A72_CPUACTLR_EL1, x0
+ isb
+
+2:
+ ret
+endfunc _disable_ldstr_pfetch_A72
+
+/*
+ * Function sets the SACR pagesize to 64k
+ */
+func _set_smmu_pagesz_64
+
+ ldr x1, =NXP_SMMU_ADDR
+ ldr w0, [x1, #0x10]
+ orr w0, w0, #1 << 16 /* setting to 64K page */
+ str w0, [x1, #0x10]
+
+ ret
+endfunc _set_smmu_pagesz_64
diff --git a/plat/nxp/common/fip_handler/common/plat_def_fip_uuid.h b/plat/nxp/common/fip_handler/common/plat_def_fip_uuid.h
new file mode 100644
index 0000000..65aef14
--- /dev/null
+++ b/plat/nxp/common/fip_handler/common/plat_def_fip_uuid.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PLAT_DEF_FIP_UUID_H
+#define PLAT_DEF_FIP_UUID_H
+
+/* PHy images configs */
+#define UUID_DDR_IMEM_UDIMM_1D \
+ {{0x5b, 0xdb, 0xe3, 0x83}, {0xd1, 0x9f}, {0xc7, 0x06}, 0xd4, 0x91, {0x76, 0x4f, 0x9d, 0x23, 0x2d, 0x2d} }
+
+#define UUID_DDR_IMEM_UDIMM_2D \
+ {{0xfa, 0x0e, 0xeb, 0x21}, {0xe0, 0x7f}, {0x8e, 0x65}, 0x95, 0xd8, {0x2b, 0x94, 0xf6, 0xb8, 0x28, 0x0a} }
+
+#define UUID_DDR_DMEM_UDIMM_1D \
+ {{0xba, 0xbb, 0xfd, 0x7e}, {0x5b, 0xf0}, {0xeb, 0xb8}, 0xeb, 0x71, {0xb1, 0x85, 0x07, 0xdd, 0xe1, 0x32} }
+
+#define UUID_DDR_DMEM_UDIMM_2D \
+ {{0xb6, 0x99, 0x61, 0xda}, {0xf9, 0x92}, {0x4b, 0x9e}, 0x0c, 0x49, {0x74, 0xa5, 0xe0, 0x5c, 0xbe, 0xc3} }
+
+#define UUID_DDR_IMEM_RDIMM_1D \
+ {{0x42, 0x33, 0x66, 0x52}, {0xd8, 0x94}, {0x4d, 0xc1}, 0x91, 0xcc, {0x26, 0x8f, 0x7a, 0x67, 0xf1, 0xa2} }
+
+#define UUID_DDR_IMEM_RDIMM_2D \
+ {{0x2e, 0x95, 0x73, 0xba}, {0xb5, 0xca}, {0x7c, 0xc7}, 0xef, 0xc9, {0x5e, 0xb0, 0x42, 0xec, 0x08, 0x7a} }
+
+#define UUID_DDR_DMEM_RDIMM_1D \
+ {{0x1c, 0x51, 0x17, 0xed}, {0x30, 0x0d}, {0xae, 0xba}, 0x87, 0x03, {0x1f, 0x37, 0x85, 0xec, 0xe1, 0x44} }
+
+#define UUID_DDR_DMEM_RDIMM_2D \
+ {{0xe9, 0x0a, 0x90, 0x78}, {0x11, 0xd6}, {0x8b, 0xba}, 0x24, 0x35, {0xec, 0x10, 0x75, 0x4f, 0x56, 0xa5} }
+
+#define UUID_DDR_FW_KEY_CERT \
+ {{0xac, 0x4b, 0xb8, 0x9c}, {0x8f, 0xb9}, {0x11, 0xea}, 0xbc, 0x55, {0x02, 0x42, 0xac, 0x12, 0x00, 0x03} }
+
+#define UUID_DDR_UDIMM_FW_CONTENT_CERT \
+ {{0x2c, 0x7f, 0x52, 0x54}, {0x70, 0x92}, {0x48, 0x40}, 0x8c, 0x34, {0x87, 0x4b, 0xbf, 0xbd, 0x9d, 0x89} }
+
+#define UUID_DDR_RDIMM_FW_CONTENT_CERT \
+ {{0x94, 0xc3, 0x63, 0x30}, {0x7c, 0xf7}, {0x4f, 0x1d}, 0xaa, 0xcd, {0xb5, 0x80, 0xb2, 0xc2, 0x40, 0xa5} }
+
+#define UUID_FUSE_PROV \
+ {{0xec, 0x45, 0x90, 0x42}, {0x30, 0x0d}, {0xae, 0xba}, 0x87, 0x03, {0x1f, 0x37, 0x85, 0xec, 0xe1, 0x44} }
+
+#define UUID_FUSE_UP \
+ {{0x89, 0x46, 0xef, 0x78}, {0x11, 0xd6}, {0x8b, 0xba}, 0x24, 0x35, {0xec, 0x10, 0x75, 0x4f, 0x56, 0xa5} }
+
+#endif /* PLAT_DEF_FIP_UUID_H */
diff --git a/plat/nxp/common/fip_handler/common/plat_tbbr_img_def.h b/plat/nxp/common/fip_handler/common/plat_tbbr_img_def.h
new file mode 100644
index 0000000..9856f70
--- /dev/null
+++ b/plat/nxp/common/fip_handler/common/plat_tbbr_img_def.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef NXP_IMG_DEF_H
+#define NXP_IMG_DEF_H
+
+#include <export/common/tbbr/tbbr_img_def_exp.h>
+
+#ifdef CONFIG_DDR_FIP_IMAGE
+/* DDR FIP IMAGE ID */
+#define DDR_FIP_IMAGE_ID MAX_IMG_IDS_WITH_SPMDS
+
+#define DDR_IMEM_UDIMM_1D_IMAGE_ID MAX_IMG_IDS_WITH_SPMDS + 1
+#define DDR_IMEM_UDIMM_2D_IMAGE_ID MAX_IMG_IDS_WITH_SPMDS + 2
+
+#define DDR_DMEM_UDIMM_1D_IMAGE_ID MAX_IMG_IDS_WITH_SPMDS + 3
+#define DDR_DMEM_UDIMM_2D_IMAGE_ID MAX_IMG_IDS_WITH_SPMDS + 4
+
+#define DDR_IMEM_RDIMM_1D_IMAGE_ID MAX_IMG_IDS_WITH_SPMDS + 5
+#define DDR_IMEM_RDIMM_2D_IMAGE_ID MAX_IMG_IDS_WITH_SPMDS + 6
+
+#define DDR_DMEM_RDIMM_1D_IMAGE_ID MAX_IMG_IDS_WITH_SPMDS + 7
+#define DDR_DMEM_RDIMM_2D_IMAGE_ID MAX_IMG_IDS_WITH_SPMDS + 8
+
+#define DDR_FW_KEY_CERT_ID MAX_IMG_IDS_WITH_SPMDS + 9
+#define DDR_UDIMM_FW_CONTENT_CERT_ID MAX_IMG_IDS_WITH_SPMDS + 10
+#define DDR_RDIMM_FW_CONTENT_CERT_ID MAX_IMG_IDS_WITH_SPMDS + 11
+/* Max Images */
+#define MAX_IMG_WITH_DDR_IDS MAX_IMG_IDS_WITH_SPMDS + 12
+#else
+#define MAX_IMG_WITH_DDR_IDS MAX_IMG_IDS_WITH_SPMDS
+#endif
+
+#ifdef POLICY_FUSE_PROVISION
+/* FUSE FIP IMAGE ID */
+#define FUSE_FIP_IMAGE_ID MAX_IMG_WITH_DDR_IDS
+
+#define FUSE_PROV_IMAGE_ID MAX_IMG_WITH_DDR_IDS + 1
+
+#define FUSE_UP_IMAGE_ID MAX_IMG_WITH_DDR_IDS + 2
+
+#define MAX_IMG_WITH_FIMG_IDS MAX_IMG_WITH_DDR_IDS + 3
+#else
+#define MAX_IMG_WITH_FIMG_IDS MAX_IMG_WITH_DDR_IDS
+#endif
+
+#define MAX_NUMBER_IDS MAX_IMG_WITH_FIMG_IDS
+
+#endif /* NXP_IMG_DEF_H */
diff --git a/plat/nxp/common/fip_handler/common/platform_oid.h b/plat/nxp/common/fip_handler/common/platform_oid.h
new file mode 100644
index 0000000..bbd6041
--- /dev/null
+++ b/plat/nxp/common/fip_handler/common/platform_oid.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#define DDR_FW_CONTENT_CERT_PK_OID "1.3.6.1.4.1.4128.2200.1"
+#define DDR_IMEM_UDIMM_1D_HASH_OID "1.3.6.1.4.1.4128.2200.2"
+#define DDR_IMEM_UDIMM_2D_HASH_OID "1.3.6.1.4.1.4128.2200.3"
+#define DDR_DMEM_UDIMM_1D_HASH_OID "1.3.6.1.4.1.4128.2200.4"
+#define DDR_DMEM_UDIMM_2D_HASH_OID "1.3.6.1.4.1.4128.2200.5"
+#define DDR_IMEM_RDIMM_1D_HASH_OID "1.3.6.1.4.1.4128.2200.6"
+#define DDR_IMEM_RDIMM_2D_HASH_OID "1.3.6.1.4.1.4128.2200.7"
+#define DDR_DMEM_RDIMM_1D_HASH_OID "1.3.6.1.4.1.4128.2200.8"
+#define DDR_DMEM_RDIMM_2D_HASH_OID "1.3.6.1.4.1.4128.2200.9"
diff --git a/plat/nxp/common/fip_handler/ddr_fip/ddr_fip_io.mk b/plat/nxp/common/fip_handler/ddr_fip/ddr_fip_io.mk
new file mode 100644
index 0000000..7d673ba
--- /dev/null
+++ b/plat/nxp/common/fip_handler/ddr_fip/ddr_fip_io.mk
@@ -0,0 +1,38 @@
+#
+# Copyright 2020 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-----------------------------------------------------------------------------
+ifeq (${DDR_FIP_IO_STORAGE_ADDED},)
+
+$(eval $(call add_define, PLAT_DEF_FIP_UUID))
+$(eval $(call add_define, PLAT_TBBR_IMG_DEF))
+$(eval $(call SET_NXP_MAKE_FLAG,IMG_LOADR_NEEDED,BL2))
+
+DDR_FIP_IO_STORAGE_ADDED := 1
+$(eval $(call add_define,CONFIG_DDR_FIP_IMAGE))
+
+FIP_HANDLER_PATH := ${PLAT_COMMON_PATH}/fip_handler
+FIP_HANDLER_COMMON_PATH := ${FIP_HANDLER_PATH}/common
+DDR_FIP_IO_STORAGE_PATH := ${FIP_HANDLER_PATH}/ddr_fip
+
+PLAT_INCLUDES += -I${FIP_HANDLER_COMMON_PATH}\
+ -I$(DDR_FIP_IO_STORAGE_PATH)
+
+DDR_FIP_IO_SOURCES += $(DDR_FIP_IO_STORAGE_PATH)/ddr_io_storage.c
+
+$(shell cp tools/nxp/plat_fiptool/plat_fiptool.mk ${PLAT_DIR})
+
+ifeq (${BL_COMM_DDR_FIP_IO_NEEDED},yes)
+BL_COMMON_SOURCES += ${DDR_FIP_IO_SOURCES}
+else
+ifeq (${BL2_DDR_FIP_IO_NEEDED},yes)
+BL2_SOURCES += ${DDR_FIP_IO_SOURCES}
+endif
+ifeq (${BL31_DDR_FIP_IO_NEEDED},yes)
+BL31_SOURCES += ${DDR_FIP_IO_SOURCES}
+endif
+endif
+endif
+#------------------------------------------------
diff --git a/plat/nxp/common/fip_handler/ddr_fip/ddr_io_storage.c b/plat/nxp/common/fip_handler/ddr_fip/ddr_io_storage.c
new file mode 100644
index 0000000..fc3c4a4
--- /dev/null
+++ b/plat/nxp/common/fip_handler/ddr_fip/ddr_io_storage.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <io_block.h>
+#include <io_driver.h>
+#include <io_fip.h>
+#include <io_memmap.h>
+#include <io_storage.h>
+#include <lib/utils.h>
+#include <tools_share/firmware_image_package.h>
+#include "ddr_io_storage.h"
+#include "plat_common.h"
+#include "platform_def.h"
+
+
+/* TBD - Move these defined to the platform_def.h file.
+ * Keeping them for reference here
+ */
+extern uintptr_t backend_dev_handle;
+
+static uint32_t ddr_fip;
+
+static uintptr_t ddr_fip_dev_handle;
+
+static io_block_spec_t ddr_fip_block_spec = {
+ .offset = PLAT_DDR_FIP_OFFSET,
+ .length = PLAT_DDR_FIP_MAX_SIZE
+};
+
+static const io_uuid_spec_t ddr_imem_udimm_1d_uuid_spec = {
+ .uuid = UUID_DDR_IMEM_UDIMM_1D,
+};
+
+static const io_uuid_spec_t ddr_imem_udimm_2d_uuid_spec = {
+ .uuid = UUID_DDR_IMEM_UDIMM_2D,
+};
+
+static const io_uuid_spec_t ddr_dmem_udimm_1d_uuid_spec = {
+ .uuid = UUID_DDR_DMEM_UDIMM_1D,
+};
+
+static const io_uuid_spec_t ddr_dmem_udimm_2d_uuid_spec = {
+ .uuid = UUID_DDR_DMEM_UDIMM_2D,
+};
+
+static const io_uuid_spec_t ddr_imem_rdimm_1d_uuid_spec = {
+ .uuid = UUID_DDR_IMEM_RDIMM_1D,
+};
+
+static const io_uuid_spec_t ddr_imem_rdimm_2d_uuid_spec = {
+ .uuid = UUID_DDR_IMEM_RDIMM_2D,
+};
+
+static const io_uuid_spec_t ddr_dmem_rdimm_1d_uuid_spec = {
+ .uuid = UUID_DDR_DMEM_RDIMM_1D,
+};
+
+static const io_uuid_spec_t ddr_dmem_rdimm_2d_uuid_spec = {
+ .uuid = UUID_DDR_DMEM_RDIMM_2D,
+};
+
+#if TRUSTED_BOARD_BOOT
+static const io_uuid_spec_t ddr_fw_key_cert_uuid_spec = {
+ .uuid = UUID_DDR_FW_KEY_CERT,
+};
+static const io_uuid_spec_t ddr_udimm_fw_cert_uuid_spec = {
+ .uuid = UUID_DDR_UDIMM_FW_CONTENT_CERT,
+};
+static const io_uuid_spec_t ddr_rdimm_fw_cert_uuid_spec = {
+ .uuid = UUID_DDR_RDIMM_FW_CONTENT_CERT,
+};
+#endif
+
+static int open_ddr_fip(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 ddr_policies[] = {
+ [DDR_FIP_IMAGE_ID - DDR_FIP_IMAGE_ID] = {
+ &backend_dev_handle,
+ (uintptr_t)&ddr_fip_block_spec,
+ NULL
+ },
+ [DDR_IMEM_UDIMM_1D_IMAGE_ID - DDR_FIP_IMAGE_ID] = {
+ &ddr_fip_dev_handle,
+ (uintptr_t)&ddr_imem_udimm_1d_uuid_spec,
+ open_ddr_fip
+ },
+ [DDR_IMEM_UDIMM_2D_IMAGE_ID - DDR_FIP_IMAGE_ID] = {
+ &ddr_fip_dev_handle,
+ (uintptr_t)&ddr_imem_udimm_2d_uuid_spec,
+ open_ddr_fip
+ },
+ [DDR_DMEM_UDIMM_1D_IMAGE_ID - DDR_FIP_IMAGE_ID] = {
+ &ddr_fip_dev_handle,
+ (uintptr_t)&ddr_dmem_udimm_1d_uuid_spec,
+ open_ddr_fip
+ },
+ [DDR_DMEM_UDIMM_2D_IMAGE_ID - DDR_FIP_IMAGE_ID] = {
+ &ddr_fip_dev_handle,
+ (uintptr_t)&ddr_dmem_udimm_2d_uuid_spec,
+ open_ddr_fip
+ },
+ [DDR_IMEM_RDIMM_1D_IMAGE_ID - DDR_FIP_IMAGE_ID] = {
+ &ddr_fip_dev_handle,
+ (uintptr_t)&ddr_imem_rdimm_1d_uuid_spec,
+ open_ddr_fip
+ },
+ [DDR_IMEM_RDIMM_2D_IMAGE_ID - DDR_FIP_IMAGE_ID] = {
+ &ddr_fip_dev_handle,
+ (uintptr_t)&ddr_imem_rdimm_2d_uuid_spec,
+ open_ddr_fip
+ },
+ [DDR_DMEM_RDIMM_1D_IMAGE_ID - DDR_FIP_IMAGE_ID] = {
+ &ddr_fip_dev_handle,
+ (uintptr_t)&ddr_dmem_rdimm_1d_uuid_spec,
+ open_ddr_fip
+ },
+ [DDR_DMEM_RDIMM_2D_IMAGE_ID - DDR_FIP_IMAGE_ID] = {
+ &ddr_fip_dev_handle,
+ (uintptr_t)&ddr_dmem_rdimm_2d_uuid_spec,
+ open_ddr_fip
+ },
+#if TRUSTED_BOARD_BOOT
+ [DDR_FW_KEY_CERT_ID - DDR_FIP_IMAGE_ID] = {
+ &ddr_fip_dev_handle,
+ (uintptr_t)&ddr_fw_key_cert_uuid_spec,
+ open_ddr_fip
+ },
+ [DDR_UDIMM_FW_CONTENT_CERT_ID - DDR_FIP_IMAGE_ID] = {
+ &ddr_fip_dev_handle,
+ (uintptr_t)&ddr_udimm_fw_cert_uuid_spec,
+ open_ddr_fip
+ },
+ [DDR_RDIMM_FW_CONTENT_CERT_ID - DDR_FIP_IMAGE_ID] = {
+ &ddr_fip_dev_handle,
+ (uintptr_t)&ddr_rdimm_fw_cert_uuid_spec,
+ open_ddr_fip
+ },
+#endif
+};
+
+static int open_ddr_fip(const uintptr_t spec)
+{
+ int result;
+ uintptr_t local_image_handle;
+
+ /* See if a Firmware Image Package is available */
+ result = io_dev_init(ddr_fip_dev_handle, (uintptr_t)DDR_FIP_IMAGE_ID);
+ if (result == 0) {
+ result = io_open(ddr_fip_dev_handle, spec, &local_image_handle);
+ if (result == 0) {
+ VERBOSE("Using FIP\n");
+ io_close(local_image_handle);
+ }
+ }
+ return result;
+}
+
+/* The image can be one of the DDR PHY images, which can be sleected via DDR
+ * policies
+ */
+int plat_get_ddr_fip_image_source(unsigned int image_id, uintptr_t *dev_handle,
+ uintptr_t *image_spec,
+ int (*check)(const uintptr_t spec))
+{
+ int result = -1;
+ const struct plat_io_policy *policy;
+
+ if (image_id >= (DDR_FIP_IMAGE_ID + ARRAY_SIZE(ddr_policies))) {
+ return result;
+ }
+
+ policy = &ddr_policies[image_id - DDR_FIP_IMAGE_ID];
+ if (image_id == DDR_FIP_IMAGE_ID) {
+ result = check(policy->image_spec);
+ } else {
+ result = policy->check(policy->image_spec);
+ }
+ if (result == 0) {
+ *image_spec = policy->image_spec;
+ *dev_handle = *(policy->dev_handle);
+ }
+ return result;
+}
+
+int ddr_fip_setup(const io_dev_connector_t *fip_dev_con, unsigned int boot_dev)
+{
+ int io_result;
+ size_t ddr_fip_offset = PLAT_DDR_FIP_OFFSET;
+
+ /* Open connections to ddr fip and cache the handles */
+ io_result = io_dev_open(fip_dev_con, (uintptr_t)&ddr_fip,
+ &ddr_fip_dev_handle);
+ assert(io_result == 0);
+
+ switch (boot_dev) {
+#if QSPI_BOOT
+ case BOOT_DEVICE_QSPI:
+ ddr_fip_offset += NXP_QSPI_FLASH_ADDR;
+ break;
+#endif
+#if NOR_BOOT
+ case BOOT_DEVICE_IFC_NOR:
+ ddr_fip_offset += NXP_NOR_FLASH_ADDR;
+ break;
+#endif
+#if FLEXSPI_NOR_BOOT
+ case BOOT_DEVICE_FLEXSPI_NOR:
+ ddr_fip_offset += NXP_FLEXSPI_FLASH_ADDR;
+ break;
+#endif
+ default:
+ break;
+ }
+
+ ddr_fip_block_spec.offset = ddr_fip_offset;
+
+ return io_result;
+}
diff --git a/plat/nxp/common/fip_handler/ddr_fip/ddr_io_storage.h b/plat/nxp/common/fip_handler/ddr_fip/ddr_io_storage.h
new file mode 100644
index 0000000..6df3902
--- /dev/null
+++ b/plat/nxp/common/fip_handler/ddr_fip/ddr_io_storage.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef DDR_IO_STORAGE_H
+#define DDR_IO_STORAGE_H
+
+#include <drivers/io/io_driver.h>
+
+#ifndef PLAT_DDR_FIP_OFFSET
+#define PLAT_DDR_FIP_OFFSET 0x800000
+#endif
+
+#ifndef PLAT_DDR_FIP_MAX_SIZE
+#define PLAT_DDR_FIP_MAX_SIZE 0x32000
+#endif
+
+int ddr_fip_setup(const io_dev_connector_t *fip_dev_con, unsigned int boot_dev);
+int plat_get_ddr_fip_image_source(unsigned int image_id, uintptr_t *dev_handle,
+ uintptr_t *image_spec,
+ int (*check)(const uintptr_t spec));
+
+#endif /* DDR_IO_STORAGE_H */
diff --git a/plat/nxp/common/fip_handler/fuse_fip/fuse.mk b/plat/nxp/common/fip_handler/fuse_fip/fuse.mk
new file mode 100644
index 0000000..d8f5ae6
--- /dev/null
+++ b/plat/nxp/common/fip_handler/fuse_fip/fuse.mk
@@ -0,0 +1,100 @@
+#
+# Copyright 2018-2020 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+
+NEED_FUSE := yes
+
+$(eval $(call add_define, PLAT_DEF_FIP_UUID))
+$(eval $(call add_define, POLICY_FUSE_PROVISION))
+$(eval $(call add_define, PLAT_TBBR_IMG_DEF))
+
+$(eval $(call SET_NXP_MAKE_FLAG,IMG_LOADR_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,SFP_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,GPIO_NEEDED,BL2))
+
+FIP_HANDLER_PATH := ${PLAT_COMMON_PATH}/fip_handler
+FIP_HANDLER_COMMON_PATH := ${FIP_HANDLER_PATH}/common
+
+FUSE_SOURCES := ${FIP_HANDLER_PATH}/fuse_fip/fuse_io_storage.c
+
+PLAT_INCLUDES += -I${FIP_HANDLER_COMMON_PATH}\
+ -I${FIP_HANDLER_PATH}/fuse_fip
+
+FUSE_FIP_NAME := fuse_fip.bin
+
+fip_fuse: ${BUILD_PLAT}/${FUSE_FIP_NAME}
+
+ifeq (${FUSE_PROV_FILE},)
+
+$(shell cp tools/nxp/plat_fiptool/plat_fiptool.mk ${PLAT_DIR})
+
+else
+ifeq (${TRUSTED_BOARD_BOOT},1)
+FUSE_PROV_FILE_SB = $(notdir ${FUSE_PROV_FILE})_prov.sb
+FUSE_FIP_ARGS += --fuse-prov ${BUILD_PLAT}/${FUSE_PROV_FILE_SB}
+FUSE_FIP_DEPS += ${BUILD_PLAT}/${FUSE_PROV_FILE_SB}
+else
+FUSE_FIP_ARGS += --fuse-prov ${FUSE_PROV_FILE}
+FUSE_FIP_DEPS += ${FUSE_PROV_FILE}
+endif
+endif
+
+ifeq (${FUSE_UP_FILE},)
+else
+ifeq (${TRUSTED_BOARD_BOOT},1)
+FUSE_UP_FILE_SB = $(notdir ${FUSE_UP_FILE})_up.sb
+FUSE_FIP_ARGS += --fuse-up ${BUILD_PLAT}/${FUSE_UP_FILE_SB}
+FUSE_FIP_DEPS += ${BUILD_PLAT}/${FUSE_UP_FILE_SB}
+else
+FUSE_FIP_ARGS += --fuse-up ${FUSE_UP_FILE}
+FUSE_FIP_DEPS += ${FUSE_UP_FILE}
+endif
+endif
+
+ifeq (${TRUSTED_BOARD_BOOT},1)
+
+ifeq (${MBEDTLS_DIR},)
+else
+ $(error Error: Trusted Board Boot with X509 certificates not supported with FUSE_PROG build option)
+endif
+
+# Path to CST directory is required to generate the CSF header
+# and prepend it to image before fip image gets generated
+ifeq (${CST_DIR},)
+ $(error Error: CST_DIR not set)
+endif
+
+ifeq (${FUSE_INPUT_FILE},)
+FUSE_INPUT_FILE := $(PLAT_DRIVERS_PATH)/auth/csf_hdr_parser/${CSF_FILE}
+endif
+
+ifeq (${FUSE_PROV_FILE},)
+else
+${BUILD_PLAT}/${FUSE_PROV_FILE_SB}: ${FUSE_PROV_FILE}
+ @echo " Generating CSF Header for $@ $<"
+ $(CST_DIR)/create_hdr_esbc --in $< --out $@ --app_off ${CSF_HDR_SZ} \
+ --app $< ${FUSE_INPUT_FILE}
+endif
+
+ifeq (${FUSE_UP_FILE},)
+else
+${BUILD_PLAT}/${FUSE_UP_FILE_SB}: ${FUSE_UP_FILE}
+ @echo " Generating CSF Header for $@ $<"
+ $(CST_DIR)/create_hdr_esbc --in $< --out $@ --app_off ${CSF_HDR_SZ} \
+ --app $< ${FUSE_INPUT_FILE}
+endif
+
+endif
+
+${BUILD_PLAT}/${FUSE_FIP_NAME}: fiptool ${FUSE_FIP_DEPS}
+ifeq (${FUSE_FIP_DEPS},)
+ $(error "Error: FUSE_PROV_FILE or/and FUSE_UP_FILE needs to point to the right file")
+endif
+ ${FIPTOOL} create ${FUSE_FIP_ARGS} $@
+ ${FIPTOOL} info $@
+ @${ECHO_BLANK_LINE}
+ @echo "Built $@ successfully"
+ @${ECHO_BLANK_LINE}
diff --git a/plat/nxp/common/fip_handler/fuse_fip/fuse_io.h b/plat/nxp/common/fip_handler/fuse_fip/fuse_io.h
new file mode 100644
index 0000000..e8775d0
--- /dev/null
+++ b/plat/nxp/common/fip_handler/fuse_fip/fuse_io.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef FUSE_IO_H
+#define FUSE_IO_H
+
+#include <drivers/io/io_driver.h>
+
+/* Can be overridden from platform_def.h file.
+ */
+#ifndef PLAT_FUSE_FIP_OFFSET
+#define PLAT_FUSE_FIP_OFFSET 0x880000
+#endif
+#ifndef PLAT_FUSE_FIP_MAX_SIZE
+#define PLAT_FUSE_FIP_MAX_SIZE 0x80000
+#endif
+
+int fip_fuse_provisioning(uintptr_t image_buf, uint32_t size);
+int fuse_fip_setup(const io_dev_connector_t *fip_dev_con, unsigned int boot_dev);
+int plat_get_fuse_image_source(unsigned int image_id,
+ uintptr_t *dev_handle,
+ uintptr_t *image_spec,
+ int (*check)(const uintptr_t spec));
+#endif /* FUSE_IO_H */
diff --git a/plat/nxp/common/fip_handler/fuse_fip/fuse_io_storage.c b/plat/nxp/common/fip_handler/fuse_fip/fuse_io_storage.c
new file mode 100644
index 0000000..017ffcf
--- /dev/null
+++ b/plat/nxp/common/fip_handler/fuse_fip/fuse_io_storage.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <dcfg.h>
+#include <drivers/delay_timer.h>
+#include <fuse_prov.h>
+#include <io_block.h>
+#include <io_driver.h>
+#include <io_fip.h>
+#include <io_memmap.h>
+#include <io_storage.h>
+#include <lib/utils.h>
+#include <nxp_gpio.h>
+#include <sfp.h>
+#include <sfp_error_codes.h>
+#include <tools_share/firmware_image_package.h>
+
+#include "fuse_io.h"
+#include <load_img.h>
+#include <plat/common/platform.h>
+#include "plat_common.h"
+#include "platform_def.h"
+
+extern uintptr_t backend_dev_handle;
+
+static uint32_t fuse_fip;
+
+static uintptr_t fuse_fip_dev_handle;
+
+static io_block_spec_t fuse_fip_block_spec = {
+ .offset = PLAT_FUSE_FIP_OFFSET,
+ .length = PLAT_FUSE_FIP_MAX_SIZE
+};
+
+static const io_uuid_spec_t fuse_prov_uuid_spec = {
+ .uuid = UUID_FUSE_PROV,
+};
+
+static const io_uuid_spec_t fuse_up_uuid_spec = {
+ .uuid = UUID_FUSE_UP,
+};
+
+static int open_fuse_fip(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 fuse_policies[] = {
+ [FUSE_FIP_IMAGE_ID - FUSE_FIP_IMAGE_ID] = {
+ &backend_dev_handle,
+ (uintptr_t)&fuse_fip_block_spec,
+ NULL
+ },
+ [FUSE_PROV_IMAGE_ID - FUSE_FIP_IMAGE_ID] = {
+ &fuse_fip_dev_handle,
+ (uintptr_t)&fuse_prov_uuid_spec,
+ open_fuse_fip
+ },
+ [FUSE_UP_IMAGE_ID - FUSE_FIP_IMAGE_ID] = {
+ &fuse_fip_dev_handle,
+ (uintptr_t)&fuse_up_uuid_spec,
+ open_fuse_fip
+ }
+};
+
+static int open_fuse_fip(const uintptr_t spec)
+{
+ int result;
+ uintptr_t local_image_handle;
+
+ /* See if a Firmware Image Package is available */
+ result = io_dev_init(fuse_fip_dev_handle, (uintptr_t)FUSE_FIP_IMAGE_ID);
+ if (result == 0) {
+ result = io_open(fuse_fip_dev_handle,
+ spec,
+ &local_image_handle);
+ if (result == 0) {
+ VERBOSE("Using FIP\n");
+ io_close(local_image_handle);
+ }
+ }
+ return result;
+}
+
+/* The image can be one of the DDR PHY images, which can be sleected via DDR
+ * policies
+ */
+int plat_get_fuse_image_source(unsigned int image_id,
+ uintptr_t *dev_handle,
+ uintptr_t *image_spec,
+ int (*check)(const uintptr_t spec))
+{
+ int result;
+ const struct plat_io_policy *policy;
+
+ assert(image_id < (FUSE_FIP_IMAGE_ID + ARRAY_SIZE(fuse_policies)));
+
+ policy = &fuse_policies[image_id - FUSE_FIP_IMAGE_ID];
+
+ if (image_id == FUSE_FIP_IMAGE_ID) {
+ result = check(policy->image_spec);
+ } else {
+ result = policy->check(policy->image_spec);
+ }
+
+ if (result == 0) {
+ *image_spec = policy->image_spec;
+ *dev_handle = *(policy->dev_handle);
+ }
+ return result;
+}
+
+int fuse_fip_setup(const io_dev_connector_t *fip_dev_con, unsigned int boot_dev)
+{
+ int io_result;
+ size_t fuse_fip_offset = PLAT_FUSE_FIP_OFFSET;
+
+ /* Open connections to fuse fip and cache the handles */
+ io_result = io_dev_open(fip_dev_con, (uintptr_t)&fuse_fip,
+ &fuse_fip_dev_handle);
+
+ assert(io_result == 0);
+
+ switch (boot_dev) {
+#if QSPI_BOOT
+ case BOOT_DEVICE_QSPI:
+ fuse_fip_offset += NXP_QSPI_FLASH_ADDR;
+ break;
+#endif
+#if NOR_BOOT
+ case BOOT_DEVICE_IFC_NOR:
+ fuse_fip_offset += NXP_NOR_FLASH_ADDR;
+ break;
+#endif
+#if FLEXSPI_NOR_BOOT
+ case BOOT_DEVICE_FLEXSPI_NOR:
+ fuse_fip_offset += NXP_FLEXSPI_FLASH_ADDR;
+ break;
+#endif
+ default:
+ break;
+ }
+
+ fuse_fip_block_spec.offset = fuse_fip_offset;
+
+ return io_result;
+}
+
+int fip_fuse_provisioning(uintptr_t image_buf, uint32_t size)
+{
+ uint32_t bit_num;
+ uint32_t *gpio_base_addr = NULL;
+ struct fuse_hdr_t *fuse_hdr = NULL;
+ uint8_t barker[] = {0x68U, 0x39U, 0x27U, 0x81U};
+ int ret = -1;
+
+ if (sfp_check_oem_wp() == 0) {
+ ret = load_img(FUSE_PROV_IMAGE_ID, &image_buf, &size);
+ if (ret != 0) {
+ ERROR("Failed to load FUSE PRIV image\n");
+ assert(ret == 0);
+ }
+ fuse_hdr = (struct fuse_hdr_t *)image_buf;
+
+ /* Check barker code */
+ if (memcmp(fuse_hdr->barker, barker, sizeof(barker)) != 0) {
+ ERROR("FUSE Barker code mismatch.\n");
+ error_handler(ERROR_FUSE_BARKER);
+ return 1;
+ }
+
+ /* Check if GPIO pin to be set for POVDD */
+ if (((fuse_hdr->flags >> FLAG_POVDD_SHIFT) & 0x1) != 0) {
+ gpio_base_addr =
+ select_gpio_n_bitnum(fuse_hdr->povdd_gpio,
+ &bit_num);
+ /*
+ * Add delay so that Efuse gets the power
+ * when GPIO is enabled.
+ */
+ ret = set_gpio_bit(gpio_base_addr, bit_num);
+ mdelay(EFUSE_POWERUP_DELAY_mSec);
+ } else {
+ ret = (board_enable_povdd() == true) ? 0 : PLAT_ERROR_ENABLE_POVDD;
+ }
+ if (ret != 0) {
+ ERROR("Error enabling board POVDD: %d\n", ret);
+ ERROR("Only SFP mirror register will be set.\n");
+ }
+
+ provision_fuses(image_buf, ret == 0);
+
+ /* Check if GPIO pin to be reset for POVDD */
+ if (((fuse_hdr->flags >> FLAG_POVDD_SHIFT) & 0x1) != 0) {
+ if (gpio_base_addr == NULL) {
+ gpio_base_addr =
+ select_gpio_n_bitnum(
+ fuse_hdr->povdd_gpio,
+ &bit_num);
+ }
+ ret = clr_gpio_bit(gpio_base_addr, bit_num);
+ } else {
+ ret = board_disable_povdd() ? 0 : PLAT_ERROR_DISABLE_POVDD;
+ }
+
+ if (ret != 0) {
+ ERROR("Error disabling board POVDD: %d\n", ret);
+ }
+ }
+ return 0;
+}
diff --git a/plat/nxp/common/img_loadr/img_loadr.mk b/plat/nxp/common/img_loadr/img_loadr.mk
new file mode 100644
index 0000000..f64b1fa
--- /dev/null
+++ b/plat/nxp/common/img_loadr/img_loadr.mk
@@ -0,0 +1,21 @@
+#
+# Copyright 2020 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+IMG_LOADR_DRIVERS_PATH := ${PLAT_COMMON_PATH}/img_loadr
+
+IMG_LOADR_SOURCES := $(IMG_LOADR_DRIVERS_PATH)/load_img.c
+PLAT_INCLUDES += -I$(IMG_LOADR_DRIVERS_PATH)
+
+ifeq (${BL_COMM_IMG_LOADR_NEEDED},yes)
+BL_COMMON_SOURCES += ${IMG_LOADR_SOURCES}
+else
+ifeq (${BL2_IMG_LOADR_NEEDED},yes)
+BL2_SOURCES += ${IMG_LOADR_SOURCES}
+endif
+ifeq (${BL31_IMG_LOADR_NEEDED},yes)
+BL31_SOURCES += ${IMG_LOADR_SOURCES}
+endif
+endif
diff --git a/plat/nxp/common/img_loadr/load_img.c b/plat/nxp/common/img_loadr/load_img.c
new file mode 100644
index 0000000..51011e4
--- /dev/null
+++ b/plat/nxp/common/img_loadr/load_img.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include "load_img.h"
+
+/******************************************************************************
+ * This function can be used to load DDR PHY/FUSE Images
+ *
+ * @param [in] image_id Image ID to be loaded
+ *
+ * @param [in,out] image_base Location at which the image should be loaded
+ * In case image is prepended by a CSF header,
+ * image_base is pointer to actual image after
+ * the header
+ *
+ * @param [in,out] image_size User should pass the maximum size of the image
+ * possible.(Buffer size starting from image_base)
+ * Actual size of the image loaded is returned
+ * back.
+ *****************************************************************************/
+int load_img(unsigned int image_id, uintptr_t *image_base,
+ uint32_t *image_size)
+{
+ int err = 0;
+
+ image_desc_t img_info = {
+ .image_id = image_id,
+ SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+ VERSION_2, image_info_t, 0),
+#ifdef CSF_HEADER_PREPENDED
+ .image_info.image_base = *image_base - CSF_HDR_SZ,
+ .image_info.image_max_size = *image_size + CSF_HDR_SZ,
+#else
+ .image_info.image_base = *image_base,
+ .image_info.image_max_size = *image_size,
+#endif
+ };
+
+ /* Create MMU entry for the CSF header */
+#if PLAT_XLAT_TABLES_DYNAMIC
+#ifdef CSF_HEADER_PREPENDED
+ err = mmap_add_dynamic_region(img_info.image_info.image_base,
+ img_info.image_info.image_base,
+ CSF_HDR_SZ,
+ MT_MEMORY | MT_RW | MT_SECURE);
+ if (err != 0) {
+ ERROR("Failed to add dynamic memory region.\n");
+ return err;
+ }
+#endif
+#endif
+
+ VERBOSE("BL2: Loading IMG %d\n", image_id);
+ err = load_auth_image(image_id, &img_info.image_info);
+ if (err != 0) {
+ VERBOSE("Failed to load IMG %d\n", image_id);
+ return err;
+ }
+
+#ifdef CSF_HEADER_PREPENDED
+ *image_base = img_info.image_info.image_base + CSF_HDR_SZ;
+ *image_size = img_info.image_info.image_size - CSF_HDR_SZ;
+#if PLAT_XLAT_TABLES_DYNAMIC
+ mmap_remove_dynamic_region(img_info.image_info.image_base,
+ CSF_HDR_SZ);
+#endif
+#else
+ *image_base = img_info.image_info.image_base;
+ *image_size = img_info.image_info.image_size;
+#endif
+
+ return err;
+}
diff --git a/plat/nxp/common/img_loadr/load_img.h b/plat/nxp/common/img_loadr/load_img.h
new file mode 100644
index 0000000..6f9de32
--- /dev/null
+++ b/plat/nxp/common/img_loadr/load_img.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef LOAD_IMAGE_H
+#define LOAD_IMAGE_H
+
+int load_img(unsigned int image_id, uintptr_t *image_base,
+ uint32_t *image_size);
+
+#endif /* LOAD_IMAGE_H */
diff --git a/plat/nxp/common/include/default/ch_2/soc_default_base_addr.h b/plat/nxp/common/include/default/ch_2/soc_default_base_addr.h
new file mode 100644
index 0000000..6296aef
--- /dev/null
+++ b/plat/nxp/common/include/default/ch_2/soc_default_base_addr.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef SOC_DEFAULT_BASE_ADDR_H
+#define SOC_DEFAULT_BASE_ADDR_H
+
+/* CCSR mmu_def.h */
+#define NXP_CCSR_ADDR 0x01000000
+#define NXP_CCSR_SIZE 0x0F000000
+
+#define NXP_DCSR_ADDR 0x20000000
+#define NXP_DCSR_SIZE 0x4000000
+
+/* Flex-SPI controller address */
+#define NXP_FLEXSPI_ADDR 0x020C0000
+/* QSPI Flash Start address */
+#define NXP_QSPI_FLASH_ADDR 0x40000000
+/* NOR Flash Start address */
+#define NXP_IFC_REGION_ADDR 0x60000000
+#define NXP_NOR_FLASH_ADDR NXP_IFC_REGION_ADDR
+
+/* MMU 500 soc.c*/
+#define NXP_SMMU_ADDR 0x09000000
+
+#define NXP_SNVS_ADDR 0x01E90000
+
+#define NXP_DCFG_ADDR 0x01EE0000
+#define NXP_SFP_ADDR 0x01E80000
+#define NXP_RCPM_ADDR 0x01EE2000
+#define NXP_CSU_ADDR 0x01510000
+#define NXP_IFC_ADDR 0x01530000
+#define NXP_SCFG_ADDR 0x01570000
+#define NXP_DCSR_ADDR 0x20000000
+#define NXP_DCSR_DCFG_ADDR (NXP_DCSR_ADDR + 0x00140000)
+#define NXP_I2C_ADDR 0x02180000
+#define NXP_ESDHC_ADDR 0x01560000
+#define NXP_UART_ADDR 0x021C0500
+#define NXP_UART1_ADDR 0x021C0600
+
+#define NXP_GPIO1_ADDR 0x02300000
+#define NXP_GPIO2_ADDR 0x02310000
+#define NXP_GPIO3_ADDR 0x02320000
+#define NXP_GPIO4_ADDR 0x02330000
+
+#define NXP_WDOG1_NS_ADDR 0x02390000
+#define NXP_WDOG2_NS_ADDR 0x023A0000
+#define NXP_WDOG1_TZ_ADDR 0x023B0000
+#define NXP_WDOG2_TZ_ADDR 0x023C0000
+
+#define NXP_TIMER_STATUS_ADDR 0x023F0000
+
+#define NXP_GICD_4K_ADDR 0x01401000
+#define NXP_GICC_4K_ADDR 0x01402000
+#define NXP_GICD_64K_ADDR 0x01410000
+#define NXP_GICC_64K_ADDR 0x01420000
+
+#define NXP_CAAM_ADDR 0x01700000
+
+#define NXP_TZC_ADDR 0x01500000
+#define NXP_DDR_ADDR 0x01080000
+
+#define NXP_TIMER_ADDR 0x02B00000
+#define NXP_CCI_ADDR 0x01180000
+#define NXP_RESET_ADDR 0x01E60000
+#define NXP_SEC_REGFILE_ADDR 0x01E88000
+#endif /* SOC_DEFAULT_BASE_ADDR_H */
diff --git a/plat/nxp/common/include/default/ch_2/soc_default_helper_macros.h b/plat/nxp/common/include/default/ch_2/soc_default_helper_macros.h
new file mode 100644
index 0000000..928ac05
--- /dev/null
+++ b/plat/nxp/common/include/default/ch_2/soc_default_helper_macros.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef SOC_DEFAULT_HELPER_MACROS_H
+#define SOC_DEFAULT_HELPER_MACROS_H
+
+#ifdef NXP_OCRAM_TZPC_ADDR
+
+/* 0x1: means 4 KB
+ * 0x2: means 8 KB
+ */
+#define TZPC_BLOCK_SIZE 0x1000
+#endif
+
+/* DDR controller offsets and defines */
+#ifdef NXP_DDR_ADDR
+
+#define DDR_CFG_2_OFFSET 0x114
+#define CFG_2_FORCE_REFRESH 0x80000000
+
+#endif /* NXP_DDR_ADDR */
+
+ /* Reset block register offsets */
+#ifdef NXP_RESET_ADDR
+
+/* Register Offset */
+#define RST_RSTCR_OFFSET 0x0
+#define RST_RSTRQMR1_OFFSET 0x10
+#define RST_RSTRQSR1_OFFSET 0x18
+#define BRR_OFFSET 0x60
+
+/* helper macros */
+#define RSTRQSR1_SWRR 0x800
+#define RSTRQMR_RPTOE_MASK (1 << 19)
+
+#endif /* NXP_RESET_ADDR */
+
+/* Secure-Register-File register offsets and bit masks */
+#ifdef NXP_RST_ADDR
+/* Register Offset */
+#define CORE_HOLD_OFFSET 0x140
+#define RSTCNTL_OFFSET 0x180
+
+/* Helper macros */
+#define SW_RST_REQ_INIT 0x1
+#endif
+
+#ifdef NXP_RCPM_ADDR
+/* RCPM Register Offsets */
+#define RCPM_PCPH20SETR_OFFSET 0x0D4
+#define RCPM_PCPH20CLRR_OFFSET 0x0D8
+#define RCPM_POWMGTCSR_OFFSET 0x130
+#define RCPM_IPPDEXPCR0_OFFSET 0x140
+#define RCPM_POWMGTCSR_LPM20_REQ 0x00100000
+
+#define RCPM2_IPSTPCR0_OFFSET 0x8
+#define RCPM2_IPSTPCR1_OFFSET 0xC
+#define RCPM2_IPSTPCR2_OFFSET 0x10
+#define RCPM2_IPSTPCR3_OFFSET 0x14
+#define RCPM2_IPSTPCR4_OFFSET 0x28
+
+#define RCPM2_IPSTPACKR0_OFFSET 0x18
+#define RCPM2_IPSTPACKR1_OFFSET 0x1C
+#define RCPM2_IPSTPACKR2_OFFSET 0x20
+#define RCPM2_IPSTPACKR3_OFFSET 0x24
+#define RCPM2_IPSTPACKR4_OFFSET 0x2C
+#define RCPM2_POWMGTDCR_OFFSET 0x0
+
+/* bitfield masks */
+#define POWMGTDCR_OVRD_EN 0x80000000
+
+#endif /* NXP_RCPM_ADDR */
+
+#define DCFG_SBEESR2_ADDR 0x20140534
+#define DCFG_MBEESR2_ADDR 0x20140544
+/* SBEESR and MBEESR bit mask */
+#define OCRAM_EESR_MASK 0x00000060
+
+#endif /* SOC_DEFAULT_HELPER_MACROS_H */
diff --git a/plat/nxp/common/include/default/ch_3/soc_default_base_addr.h b/plat/nxp/common/include/default/ch_3/soc_default_base_addr.h
new file mode 100644
index 0000000..8d64f04
--- /dev/null
+++ b/plat/nxp/common/include/default/ch_3/soc_default_base_addr.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2021-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef SOC_DEFAULT_BASE_ADDR_H
+#define SOC_DEFAULT_BASE_ADDR_H
+
+/* CCSR mmu_def.h */
+#define NXP_CCSR_ADDR 0x1000000
+#define NXP_CCSR_SIZE 0xF000000
+
+#define NXP_DCSR_ADDR 0x700000000
+#define NXP_DCSR_SIZE 0x40000000
+
+/* Quad SPI Region #1 base address */
+#define NXP_QSPI_FLASH_ADDR 0x20000000
+
+/* IFC Region #1 base address */
+#define NXP_NOR_FLASH_ADDR 0x30000000
+
+/* MMU 500 */
+#define NXP_SMMU_ADDR 0x05000000
+
+#define NXP_SNVS_ADDR 0x01E90000
+
+#define NXP_DCFG_ADDR 0x01E00000
+#define NXP_PMU_CCSR_ADDR 0x01E30000
+#define NXP_PMU_DCSR_ADDR 0x700123000
+#define NXP_PMU_ADDR NXP_PMU_CCSR_ADDR
+#define NXP_SFP_ADDR 0x01E80000
+#define NXP_SCFG_ADDR 0x01FC0000
+#define NXP_I2C_ADDR 0x02000000
+#define NXP_ESDHC_ADDR 0x02140000
+#define NXP_ESDHC2_ADDR 0x02150000
+#ifndef NXP_UART_ADDR
+#define NXP_UART_ADDR 0x021C0500
+#endif
+#ifndef NXP_UART1_ADDR
+#define NXP_UART1_ADDR 0x021C0600
+#endif
+
+#define NXP_GPIO1_ADDR 0x02300000
+#define NXP_GPIO2_ADDR 0x02310000
+#define NXP_GPIO3_ADDR 0x02320000
+#define NXP_GPIO4_ADDR 0x02330000
+
+#define NXP_WDOG1_NS_ADDR 0x02390000
+#define NXP_WDOG2_NS_ADDR 0x023A0000
+#define NXP_WDOG1_TZ_ADDR 0x023B0000
+#define NXP_WDOG2_TZ_ADDR 0x023C0000
+
+#define NXP_TIMER_STATUS_ADDR 0x023F0000
+
+#define NXP_GICD_ADDR 0x06000000
+#define NXP_GICR_ADDR 0x06100000
+#define NXP_GICR_SGI_ADDR 0x06110000
+
+#define NXP_CAAM_ADDR 0x08000000
+
+#define NXP_TZC_ADDR 0x01100000
+#define NXP_TZC2_ADDR 0x01110000
+#define NXP_TZC3_ADDR 0x01120000
+
+#define NXP_RESET_ADDR 0x01E60000
+#define NXP_SEC_REGFILE_ADDR 0x01E88000
+
+#define NXP_RST_ADDR 0x01E88000
+
+/* DDR memory Map */
+#define NXP_DDR_ADDR 0x01080000
+#define NXP_DDR2_ADDR 0x01090000
+#define NXP_DDR3_ADDR 0x08210000
+
+/* QuadSPI base address */
+#define NXP_QSPI_ADDR 0x020C0000
+/* IFC base address */
+#define NXP_IFC_ADDR 0x02240000
+
+/* CCI400 base address */
+#define NXP_CCI_ADDR 0x04090000
+
+/* Global Generic Reference Timer base address */
+#define NXP_TIMER_ADDR 0x023E0000
+
+/* OCRAM TZPC base address */
+#define NXP_OCRAM_TZPC_ADDR 0x02200000
+
+#define NXP_EPU_ADDR 0x700060000
+
+#define NXP_CCN_ADDR 0x04000000
+#define NXP_CCN_HNI_ADDR 0x04080000
+#define NXP_CCN_HN_F_0_ADDR 0x04200000
+#define NXP_CCN_HN_F_1_ADDR 0x04210000
+
+#define TPMWAKEMR0_ADDR 0x700123c50
+
+#endif /* SOC_DEFAULT_BASE_ADDR_H */
diff --git a/plat/nxp/common/include/default/ch_3/soc_default_helper_macros.h b/plat/nxp/common/include/default/ch_3/soc_default_helper_macros.h
new file mode 100644
index 0000000..8e68367
--- /dev/null
+++ b/plat/nxp/common/include/default/ch_3/soc_default_helper_macros.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef SOC_DEFAULT_HELPER_MACROS_H
+#define SOC_DEFAULT_HELPER_MACROS_H
+
+#ifdef NXP_OCRAM_TZPC_ADDR
+#define TZPC_BLOCK_SIZE 0x1000
+#endif
+
+/* Reset block register offsets */
+#ifdef NXP_RESET_ADDR
+
+/* Register Offset */
+#define RST_RSTCR_OFFSET 0x0
+#define RST_RSTRQMR1_OFFSET 0x10
+#define RST_RSTRQSR1_OFFSET 0x18
+#define BRR_OFFSET 0x60
+
+/* helper macros */
+#define RSTRQMR_RPTOE_MASK (1 << 19)
+#endif /* NXP_RESET_ADDR */
+
+#define PCIeRC_RN_I_NODE_ID_OFFSET 0x8
+#define PoS_CONTROL_REG_OFFSET 0x0
+#define POS_EARLY_WR_COMP_EN 0x20
+#define HNI_POS_EN 0x01
+#define POS_TERMINATE_BARRIERS 0x10
+#define SERIALIZE_DEV_nGnRnE_WRITES 0x200
+#define ENABLE_ERR_SIGNAL_TO_MN 0x4
+#define ENABLE_RESERVE_BIT53 0x400
+#define ENABLE_WUO 0x10
+
+#define PORT_S0_CTRL_REG_RNI 0x010
+#define PORT_S1_CTRL_REG_RNI 0x110
+#define PORT_S2_CTRL_REG_RNI 0x210
+#define ENABLE_FORCE_RD_QUO 0x20
+#define QOS_SETTING 0x00FF000C
+
+/* epu register offsets and values */
+#define EPU_EPGCR_OFFSET 0x0
+#define EPU_EPIMCR10_OFFSET 0x128
+#define EPU_EPCTR10_OFFSET 0xa28
+#define EPU_EPCCR10_OFFSET 0x828
+#ifndef EPU_EPCCR10_VAL
+#define EPU_EPCCR10_VAL 0xb2800000
+#endif
+#define EPU_EPIMCR10_VAL 0xba000000
+#define EPU_EPCTR10_VAL 0x0
+#define EPU_EPGCR_VAL (1 << 31)
+
+#ifdef NXP_CCN_ADDR
+#define NXP_CCN_HN_F_1_ADDR 0x04210000
+
+#define CCN_HN_F_SAM_NODEID_MASK 0x7f
+#define CCN_HN_F_SNP_DMN_CTL_OFFSET 0x200
+#define CCN_HN_F_SNP_DMN_CTL_SET_OFFSET 0x210
+#define CCN_HN_F_SNP_DMN_CTL_CLR_OFFSET 0x220
+#define CCN_HN_F_SNP_DMN_CTL_MASK 0x80a00
+#define CCN_HNF_NODE_COUNT 8
+#define CCN_HNF_OFFSET 0x10000
+
+#define SA_AUX_CTRL_REG_OFFSET 0x500
+#define NUM_HNI_NODE 2
+#define CCN_HNI_MEMORY_MAP_SIZE 0x10000
+
+#define PCIeRC_RN_I_NODE_ID_OFFSET 0x8
+#define PoS_CONTROL_REG_OFFSET 0x0
+#define POS_EARLY_WR_COMP_EN 0x20
+#define HNI_POS_EN 0x01
+#define POS_TERMINATE_BARRIERS 0x10
+#define SERIALIZE_DEV_nGnRnE_WRITES 0x200
+#define ENABLE_ERR_SIGNAL_TO_MN 0x4
+#define ENABLE_RESERVE_BIT53 0x400
+#define ENABLE_WUO 0x10
+#endif
+
+/* reset register bit */
+#define RSTRQMR_RPTOE_MASK (1 << 19)
+
+/* secmon register offsets and bitfields */
+#define SECMON_HPCOMR_OFFSET 0x4
+#define SECMON_HPCOMR_NPSWAEN 0x80000000
+
+/* Secure-Register-File register offsets and bit masks */
+#ifdef NXP_RST_ADDR
+/* Register Offset */
+#define CORE_HOLD_OFFSET 0x140
+#endif
+
+#define DCFG_SBEESR2_ADDR 0x00100534
+#define DCFG_MBEESR2_ADDR 0x00100544
+/* SBEESR and MBEESR bit mask */
+#define OCRAM_EESR_MASK 0x00000008
+
+#endif /* SOC_DEFAULT_HELPER_MACROS_H */
diff --git a/plat/nxp/common/include/default/ch_3_2/soc_default_base_addr.h b/plat/nxp/common/include/default/ch_3_2/soc_default_base_addr.h
new file mode 100644
index 0000000..0a4228b
--- /dev/null
+++ b/plat/nxp/common/include/default/ch_3_2/soc_default_base_addr.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef SOC_DEFAULT_BASE_ADDR_H
+#define SOC_DEFAULT_BASE_ADDR_H
+
+/* CCSR mmu_def.h */
+#define NXP_CCSR_ADDR 0x1000000
+#define NXP_CCSR_SIZE 0xF000000
+
+#define NXP_DCSR_ADDR 0x700000000
+#define NXP_DCSR_SIZE 0x40000000
+
+/* Flex-SPI controller address */
+#define NXP_FLEXSPI_ADDR 0x020C0000
+/* Flex-SPI Flash Start address */
+#define NXP_FLEXSPI_FLASH_ADDR 0x20000000
+
+/* MMU 500 soc.c*/
+#define NXP_SMMU_ADDR 0x05000000
+
+/* CCI400 base address */
+#define NXP_CCI_ADDR 0x04090000
+
+#define NXP_SNVS_ADDR 0x01E90000
+
+#define NXP_DCFG_ADDR 0x01E00000
+#define NXP_PMU_CCSR_ADDR 0x01E30000
+#define NXP_PMU_DCSR_ADDR 0x700123000
+#define NXP_PMU_ADDR NXP_PMU_CCSR_ADDR
+#define NXP_SFP_ADDR 0x01E80000
+#define NXP_SCFG_ADDR 0x01FC0000
+#define NXP_I2C_ADDR 0x02000000
+#define NXP_ESDHC_ADDR 0x02140000
+#define NXP_ESDHC2_ADDR 0x02150000
+#define NXP_UART_ADDR 0x021C0000
+#define NXP_UART1_ADDR 0x021D0000
+
+#define NXP_GPIO1_ADDR 0x02300000
+#define NXP_GPIO2_ADDR 0x02310000
+#define NXP_GPIO3_ADDR 0x02320000
+#define NXP_GPIO4_ADDR 0x02330000
+
+#define NXP_WDOG1_NS_ADDR 0x02390000
+#define NXP_WDOG2_NS_ADDR 0x023A0000
+#define NXP_WDOG1_TZ_ADDR 0x023B0000
+#define NXP_WDOG2_TZ_ADDR 0x023C0000
+
+#define NXP_TIMER_STATUS_ADDR 0x023F0000
+
+#define NXP_GICD_ADDR 0x06000000
+#define NXP_GICR_ADDR 0x06200000
+#define NXP_GICR_SGI_ADDR 0x06210000
+
+#define NXP_CAAM_ADDR 0x08000000
+
+#define NXP_TZC_ADDR 0x01100000
+#define NXP_TZC2_ADDR 0x01110000
+#define NXP_TZC3_ADDR 0x01120000
+
+#define NXP_TIMER_ADDR 0x023E0000
+
+#define NXP_RESET_ADDR 0x01E60000
+#define NXP_SEC_REGFILE_ADDR 0x01E88000
+#define NXP_RST_ADDR 0x01E88000
+
+#define TPMWAKEMR0_ADDR 0x700123c50
+#define TZPC_BLOCK_SIZE 0x1000
+
+#define NXP_TZC_ADDR 0x01100000
+#define NXP_TZC2_ADDR 0x01110000
+#define NXP_TZC3_ADDR 0x01120000
+#define NXP_TZC4_ADDR 0x01130000
+#define NXP_DDR_ADDR 0x01080000
+#define NXP_DDR2_ADDR 0x01090000
+
+#define NXP_OCRAM_TZPC_ADDR 0x02200000
+
+#define NXP_CCN_ADDR 0x04000000
+#define NXP_CCN_HNI_ADDR 0x04080000
+#define NXP_CCN_HN_F_0_ADDR 0x04200000
+
+#define NXP_EPU_ADDR 0x700060000
+#endif /* SOC_DEFAULT_BASE_ADDR_H */
diff --git a/plat/nxp/common/include/default/ch_3_2/soc_default_helper_macros.h b/plat/nxp/common/include/default/ch_3_2/soc_default_helper_macros.h
new file mode 100644
index 0000000..1edd28d
--- /dev/null
+++ b/plat/nxp/common/include/default/ch_3_2/soc_default_helper_macros.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef SOC_DEFAULT_HELPER_MACROS_H
+#define SOC_DEFAULT_HELPER_MACROS_H
+
+#ifdef NXP_OCRAM_TZPC_ADDR
+
+/* 0x1: means 4 KB
+ * 0x2: means 8 KB
+ */
+#define TZPC_BLOCK_SIZE 0x1000
+#endif
+
+/* DDR controller offsets and defines */
+#ifdef NXP_DDR_ADDR
+
+#define DDR_CFG_2_OFFSET 0x114
+#define CFG_2_FORCE_REFRESH 0x80000000
+
+#endif /* NXP_DDR_ADDR */
+
+ /* Reset block register offsets */
+#ifdef NXP_RESET_ADDR
+
+/* Register Offset */
+#define RST_RSTCR_OFFSET 0x0
+#define RST_RSTRQMR1_OFFSET 0x10
+#define RST_RSTRQSR1_OFFSET 0x18
+#define BRR_OFFSET 0x60
+
+/* helper macros */
+#define RSTRQSR1_SWRR 0x800
+#define RSTRQMR_RPTOE_MASK (1 << 19)
+
+#endif /* NXP_RESET_ADDR */
+
+/* secmon register offsets and bitfields */
+#define SECMON_HPCOMR_OFFSET 0x4
+#define SECMON_HPCOMR_NPSWAEN 0x80000000
+
+/* Secure-Register-File register offsets and bit masks */
+#ifdef NXP_RST_ADDR
+/* Register Offset */
+#define CORE_HOLD_OFFSET 0x140
+#define RSTCNTL_OFFSET 0x180
+
+/* Helper macros */
+#define SW_RST_REQ_INIT 0x1
+#endif
+
+#ifdef NXP_CCN_ADDR
+#define NXP_CCN_HN_F_1_ADDR 0x04210000
+
+#define CCN_HN_F_SAM_NODEID_MASK 0x7f
+#define CCN_HN_F_SNP_DMN_CTL_OFFSET 0x200
+#define CCN_HN_F_SNP_DMN_CTL_SET_OFFSET 0x210
+#define CCN_HN_F_SNP_DMN_CTL_CLR_OFFSET 0x220
+#define CCN_HN_F_SNP_DMN_CTL_MASK 0x80a00
+#define CCN_HNF_NODE_COUNT 8
+#define CCN_HNF_OFFSET 0x10000
+
+#define SA_AUX_CTRL_REG_OFFSET 0x500
+#define NUM_HNI_NODE 2
+#define CCN_HNI_MEMORY_MAP_SIZE 0x10000
+
+#define PCIeRC_RN_I_NODE_ID_OFFSET 0x8
+#define PoS_CONTROL_REG_OFFSET 0x0
+#define POS_EARLY_WR_COMP_EN 0x20
+#define HNI_POS_EN 0x01
+#define POS_TERMINATE_BARRIERS 0x10
+#define SERIALIZE_DEV_nGnRnE_WRITES 0x200
+#define ENABLE_ERR_SIGNAL_TO_MN 0x4
+#define ENABLE_RESERVE_BIT53 0x400
+#define ENABLE_WUO 0x10
+#endif /* NXP_CCN_ADDR */
+
+#define DCFG_SBEESR2_ADDR 0x00100534
+#define DCFG_MBEESR2_ADDR 0x00100544
+/* SBEESR and MBEESR bit mask */
+#define OCRAM_EESR_MASK 0x00000008
+
+#endif /* SOC_DEFAULT_HELPER_MACROS_H */
diff --git a/plat/nxp/common/include/default/plat_default_def.h b/plat/nxp/common/include/default/plat_default_def.h
new file mode 100644
index 0000000..43320bb
--- /dev/null
+++ b/plat/nxp/common/include/default/plat_default_def.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PLAT_DEFAULT_DEF_H
+#define PLAT_DEFAULT_DEF_H
+
+/*
+ * 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__ */
+
+#define LS_BL31_PLAT_PARAM_VAL 0x0f1e2d3c4b5a6978ULL
+
+/* NXP Platforms have DRAM divided into banks.
+ * DRAM0 Bank: Maximum size of this bank is fixed to 2GB
+ * DRAM1 Bank: Greater than 2GB belongs to bank1 and size of bank1 varies from
+ * one platform to other platform.
+ * DRAMn Bank:
+ *
+ * Except a few, all the platforms have 2GB size as DRAM0 BANK.
+ * Hence common for all the platforms.
+ * For platforms where DRAM0 Size is < 2GB, it is defined in platform_def.h
+ */
+#ifndef PLAT_DEF_DRAM0_SIZE
+#define PLAT_DEF_DRAM0_SIZE 0x80000000 /* 2G */
+#endif
+
+/* This is common for all platforms where: */
+#ifndef NXP_NS_DRAM_ADDR
+#define NXP_NS_DRAM_ADDR NXP_DRAM0_ADDR
+#endif
+
+/* 1 MB is reserved for dma of sd */
+#ifndef NXP_SD_BLOCK_BUF_SIZE
+#define NXP_SD_BLOCK_BUF_SIZE (1 * 1024 * 1024)
+#endif
+
+/* 64MB is reserved for Secure memory */
+#ifndef NXP_SECURE_DRAM_SIZE
+#define NXP_SECURE_DRAM_SIZE (64 * 1024 * 1024)
+#endif
+
+/* 2M Secure EL1 Payload Shared Memory */
+#ifndef NXP_SP_SHRD_DRAM_SIZE
+#define NXP_SP_SHRD_DRAM_SIZE (2 * 1024 * 1024)
+#endif
+
+#ifndef NXP_NS_DRAM_SIZE
+/* Non secure memory */
+#define NXP_NS_DRAM_SIZE (PLAT_DEF_DRAM0_SIZE - \
+ (NXP_SECURE_DRAM_SIZE + NXP_SP_SHRD_DRAM_SIZE))
+#endif
+
+#ifndef NXP_SD_BLOCK_BUF_ADDR
+#define NXP_SD_BLOCK_BUF_ADDR (NXP_NS_DRAM_ADDR)
+#endif
+
+#ifndef NXP_SECURE_DRAM_ADDR
+#ifdef TEST_BL31
+#define NXP_SECURE_DRAM_ADDR 0
+#else
+#define NXP_SECURE_DRAM_ADDR (NXP_NS_DRAM_ADDR + PLAT_DEF_DRAM0_SIZE - \
+ (NXP_SECURE_DRAM_SIZE + NXP_SP_SHRD_DRAM_SIZE))
+#endif
+#endif
+
+#ifndef NXP_SP_SHRD_DRAM_ADDR
+#define NXP_SP_SHRD_DRAM_ADDR (NXP_NS_DRAM_ADDR + PLAT_DEF_DRAM0_SIZE - \
+ NXP_SP_SHRD_DRAM_SIZE)
+#endif
+
+#ifndef BL31_BASE
+/* 2 MB reserved in secure memory for DDR */
+#define BL31_BASE NXP_SECURE_DRAM_ADDR
+#endif
+
+#ifndef BL31_SIZE
+#define BL31_SIZE (0x200000)
+#endif
+
+#ifndef BL31_LIMIT
+#define BL31_LIMIT (BL31_BASE + BL31_SIZE)
+#endif
+
+/* Put BL32 in secure memory */
+#ifndef BL32_BASE
+#define BL32_BASE (NXP_SECURE_DRAM_ADDR + BL31_SIZE)
+#endif
+
+#ifndef BL32_LIMIT
+#define BL32_LIMIT (NXP_SECURE_DRAM_ADDR + \
+ NXP_SECURE_DRAM_SIZE + NXP_SP_SHRD_DRAM_SIZE)
+#endif
+
+/* BL33 memory region */
+/* Hardcoded based on current address in u-boot */
+#ifndef BL33_BASE
+#define BL33_BASE 0x82000000
+#endif
+
+#ifndef BL33_LIMIT
+#define BL33_LIMIT (NXP_NS_DRAM_ADDR + NXP_NS_DRAM_SIZE)
+#endif
+
+/*
+ * FIP image defines - Offset at which FIP Image would be present
+ * Image would include Bl31 , Bl33 and Bl32 (optional)
+ */
+#ifdef POLICY_FUSE_PROVISION
+#ifndef FUSE_BUF
+#define FUSE_BUF ULL(0x81000000)
+#endif
+
+#ifndef FUSE_SZ
+#define FUSE_SZ 0x80000
+#endif
+#endif
+
+#ifndef MAX_FIP_DEVICES
+#define MAX_FIP_DEVICES 2
+#endif
+
+#ifndef PLAT_FIP_OFFSET
+#define PLAT_FIP_OFFSET 0x100000
+#endif
+
+#ifndef PLAT_FIP_MAX_SIZE
+#define PLAT_FIP_MAX_SIZE 0x400000
+#endif
+
+/* Check if this size can be determined from array size */
+#if defined(IMAGE_BL2)
+#ifndef MAX_MMAP_REGIONS
+#define MAX_MMAP_REGIONS 8
+#endif
+#ifndef MAX_XLAT_TABLES
+#define MAX_XLAT_TABLES 6
+#endif
+#elif defined(IMAGE_BL31)
+#ifndef MAX_MMAP_REGIONS
+#define MAX_MMAP_REGIONS 9
+#endif
+#ifndef MAX_XLAT_TABLES
+#define MAX_XLAT_TABLES 9
+#endif
+#elif defined(IMAGE_BL32)
+#ifndef MAX_MMAP_REGIONS
+#define MAX_MMAP_REGIONS 8
+#endif
+#ifndef MAX_XLAT_TABLES
+#define MAX_XLAT_TABLES 9
+#endif
+#endif
+
+/*
+ * ID of the secure physical generic timer interrupt used by the BL32.
+ */
+#ifndef BL32_IRQ_SEC_PHY_TIMER
+#define BL32_IRQ_SEC_PHY_TIMER 29
+#endif
+
+#endif /* PLAT_DEFAULT_DEF_H */
diff --git a/plat/nxp/common/nv_storage/nv_storage.mk b/plat/nxp/common/nv_storage/nv_storage.mk
new file mode 100644
index 0000000..dddba5f
--- /dev/null
+++ b/plat/nxp/common/nv_storage/nv_storage.mk
@@ -0,0 +1,29 @@
+#
+# Copyright 2020 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# NXP Non-Volatile data flag storage used and then cleared by SW on boot-up
+
+$(eval $(call add_define,NXP_NV_SW_MAINT_LAST_EXEC_DATA))
+
+ifeq ($(NXP_COINED_BB),yes)
+$(eval $(call add_define,NXP_COINED_BB))
+# BL2 : To read the reset cause from LP SECMON GPR register
+# BL31: To write the reset cause to LP SECMON GPR register
+$(eval $(call SET_NXP_MAKE_FLAG,SNVS_NEEDED,BL_COMM))
+
+# BL2: DDR training data is stored on Flexspi NOR.
+ifneq (${BOOT_MODE},flexspi_nor)
+$(eval $(call SET_NXP_MAKE_FLAG,XSPI_NEEDED,BL2))
+endif
+
+else
+$(eval $(call add_define_val,DEFAULT_NV_STORAGE_BASE_ADDR,'${BL2_BIN_XSPI_NOR_END_ADDRESS} - 2 * ${NXP_XSPI_NOR_UNIT_SIZE}'))
+$(eval $(call SET_NXP_MAKE_FLAG,XSPI_NEEDED,BL_COMM))
+endif
+
+NV_STORAGE_INCLUDES += -I${PLAT_COMMON_PATH}/nv_storage
+
+NV_STORAGE_SOURCES += ${PLAT_COMMON_PATH}/nv_storage/plat_nv_storage.c
diff --git a/plat/nxp/common/nv_storage/plat_nv_storage.c b/plat/nxp/common/nv_storage/plat_nv_storage.c
new file mode 100644
index 0000000..af3b966
--- /dev/null
+++ b/plat/nxp/common/nv_storage/plat_nv_storage.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <platform_def.h>
+#include <common/debug.h>
+#ifndef NXP_COINED_BB
+#include <flash_info.h>
+#include <fspi.h>
+#include <fspi_api.h>
+#endif
+#include <lib/mmio.h>
+#ifdef NXP_COINED_BB
+#include <snvs.h>
+#else
+#include <xspi_error_codes.h>
+#endif
+
+#include <plat_nv_storage.h>
+
+/*This structure will be a static structure and
+ * will be populated as first step of BL2 booting-up.
+ * fspi_strorage.c . To be located in the fspi driver folder.
+ */
+
+static nv_app_data_t nv_app_data;
+
+int read_nv_app_data(void)
+{
+ int ret = 0;
+
+#ifdef NXP_COINED_BB
+ uint8_t *nv_app_data_array = (uint8_t *) &nv_app_data;
+ uint8_t offset = 0U;
+
+ ret = snvs_read_app_data();
+ do {
+ nv_app_data_array[offset] = snvs_read_app_data_bit(offset);
+ offset++;
+
+ } while (offset < APP_DATA_MAX_OFFSET);
+ snvs_clear_app_data();
+#else
+ uintptr_t nv_base_addr = NV_STORAGE_BASE_ADDR;
+
+ ret = fspi_init(NXP_FLEXSPI_ADDR, NXP_FLEXSPI_FLASH_ADDR);
+
+ if (ret != XSPI_SUCCESS) {
+ ERROR("Failed to initialized driver flexspi-nor.\n");
+ ERROR("exiting warm-reset request.\n");
+ return -ENODEV;
+ }
+
+ xspi_read(nv_base_addr,
+ (uint32_t *)&nv_app_data, sizeof(nv_app_data_t));
+ xspi_sector_erase((uint32_t) nv_base_addr,
+ F_SECTOR_ERASE_SZ);
+#endif
+ return ret;
+}
+
+int wr_nv_app_data(int data_offset,
+ uint8_t *data,
+ int data_size)
+{
+ int ret = 0;
+#ifdef NXP_COINED_BB
+#if !TRUSTED_BOARD_BOOT
+ snvs_disable_zeroize_lp_gpr();
+#endif
+ /* In case LP SecMon General purpose register,
+ * only 1 bit flags can be saved.
+ */
+ if ((data_size > 1) || (*data != DEFAULT_SET_VALUE)) {
+ ERROR("Only binary value is allowed to be written.\n");
+ ERROR("Use flash instead of SNVS GPR as NV location.\n");
+ return -ENODEV;
+ }
+ snvs_write_app_data_bit(data_offset);
+#else
+ uint8_t read_val[sizeof(nv_app_data_t)];
+ uint8_t ready_to_write_val[sizeof(nv_app_data_t)];
+ uintptr_t nv_base_addr = NV_STORAGE_BASE_ADDR;
+
+ assert((nv_base_addr + data_offset + data_size) > (nv_base_addr + F_SECTOR_ERASE_SZ));
+
+ ret = fspi_init(NXP_FLEXSPI_ADDR, NXP_FLEXSPI_FLASH_ADDR);
+
+ if (ret != XSPI_SUCCESS) {
+ ERROR("Failed to initialized driver flexspi-nor.\n");
+ ERROR("exiting warm-reset request.\n");
+ return -ENODEV;
+ }
+
+ ret = xspi_read(nv_base_addr + data_offset, (uint32_t *)read_val, data_size);
+
+ memset(ready_to_write_val, READY_TO_WRITE_VALUE, ARRAY_SIZE(ready_to_write_val));
+
+ if (memcmp(read_val, ready_to_write_val, data_size) == 0) {
+ xspi_write(nv_base_addr + data_offset, data, data_size);
+ }
+#endif
+
+ return ret;
+}
+
+const nv_app_data_t *get_nv_data(void)
+{
+ return (const nv_app_data_t *) &nv_app_data;
+}
diff --git a/plat/nxp/common/nv_storage/plat_nv_storage.h b/plat/nxp/common/nv_storage/plat_nv_storage.h
new file mode 100644
index 0000000..1f5264a
--- /dev/null
+++ b/plat/nxp/common/nv_storage/plat_nv_storage.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PLAT_NV_STRG_H
+#define PLAT_NV_STRG_H
+
+#define DEFAULT_SET_VALUE 0xA1
+#define READY_TO_WRITE_VALUE 0xFF
+
+#ifndef NV_STORAGE_BASE_ADDR
+#define NV_STORAGE_BASE_ADDR DEFAULT_NV_STORAGE_BASE_ADDR
+#endif
+
+typedef struct {
+uint8_t warm_rst_flag;
+uint8_t wdt_rst_flag;
+uint8_t dummy[2];
+} nv_app_data_t;
+
+
+/*below enum and above structure should be in-sync. */
+enum app_data_offset {
+ WARM_RESET_FLAG_OFFSET,
+ WDT_RESET_FLAG_OFFSET,
+ APP_DATA_MAX_OFFSET,
+};
+
+int read_nv_app_data(void);
+
+int wr_nv_app_data(int data_offset,
+ uint8_t *data,
+ int data_size);
+
+const nv_app_data_t *get_nv_data(void);
+
+#endif /* PLAT_NV_STRG_H */
diff --git a/plat/nxp/common/ocram/aarch64/ocram.S b/plat/nxp/common/ocram/aarch64/ocram.S
new file mode 100644
index 0000000..ec53341
--- /dev/null
+++ b/plat/nxp/common/ocram/aarch64/ocram.S
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+#include <soc_default_base_addr.h>
+#include <soc_default_helper_macros.h>
+
+.global ocram_init
+
+/*
+ * void ocram_init(uintptr_t start_addr, size_t size)
+ *
+ * This function will do OCRAM ECC.
+ * OCRAM is initialized with 64-bit writes and then a write
+ * performed to address 0x0010_0534 with the value 0x0000_0008.
+ *
+ * x0: start_addr
+ * x1: size in bytes
+ * Called from C
+ */
+
+func ocram_init
+ /* save the aarch32/64 non-volatile registers */
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+ stp x8, x9, [sp, #-16]!
+ stp x10, x11, [sp, #-16]!
+ stp x12, x13, [sp, #-16]!
+ stp x18, x30, [sp, #-16]!
+
+ /* convert bytes to 64-byte chunks */
+ lsr x1, x1, #6
+1:
+ /* for each location, read and write-back */
+ dc ivac, x0
+ dsb sy
+ ldp x4, x5, [x0]
+ ldp x6, x7, [x0, #16]
+ ldp x8, x9, [x0, #32]
+ ldp x10, x11, [x0, #48]
+ stp x4, x5, [x0]
+ stp x6, x7, [x0, #16]
+ stp x8, x9, [x0, #32]
+ stp x10, x11, [x0, #48]
+ dc cvac, x0
+
+ sub x1, x1, #1
+ cbz x1, 2f
+ add x0, x0, #64
+ b 1b
+2:
+ /* Clear OCRAM ECC status bit in SBEESR2 and MBEESR2 */
+ ldr w1, =OCRAM_EESR_MASK
+ ldr x0, =DCFG_SBEESR2_ADDR
+ str w1, [x0]
+ ldr x0, =DCFG_MBEESR2_ADDR
+ str w1, [x0]
+
+ /* restore the aarch32/64 non-volatile registers */
+ ldp x18, x30, [sp], #16
+ ldp x12, x13, [sp], #16
+ ldp x10, x11, [sp], #16
+ ldp x8, x9, [sp], #16
+ ldp x6, x7, [sp], #16
+ ldp x4, x5, [sp], #16
+ ret
+endfunc ocram_init
diff --git a/plat/nxp/common/ocram/ocram.h b/plat/nxp/common/ocram/ocram.h
new file mode 100644
index 0000000..479de61
--- /dev/null
+++ b/plat/nxp/common/ocram/ocram.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef OCRAM_H
+#define OCRAM_H
+
+void ocram_init(uintptr_t start_addr, size_t size);
+
+#endif /* OCRAM_H */
diff --git a/plat/nxp/common/ocram/ocram.mk b/plat/nxp/common/ocram/ocram.mk
new file mode 100644
index 0000000..c77bd4a
--- /dev/null
+++ b/plat/nxp/common/ocram/ocram.mk
@@ -0,0 +1,14 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+
+PLAT_OCRAM_PATH := $(PLAT_COMMON_PATH)/ocram
+
+OCRAM_SOURCES := ${PLAT_OCRAM_PATH}/$(ARCH)/ocram.S
+
+BL2_SOURCES += ${OCRAM_SOURCES}
+
+PLAT_INCLUDES += -I${PLAT_COMMON_PATH}/ocram
diff --git a/plat/nxp/common/plat_make_helper/plat_build_macros.mk b/plat/nxp/common/plat_make_helper/plat_build_macros.mk
new file mode 100644
index 0000000..bba5e36
--- /dev/null
+++ b/plat/nxp/common/plat_make_helper/plat_build_macros.mk
@@ -0,0 +1,11 @@
+#
+# Copyright (c) 2020, NXP.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+
+define SET_NXP_MAKE_FLAG
+$1 := yes
+$2_$1 := yes
+endef
diff --git a/plat/nxp/common/plat_make_helper/plat_common_def.mk b/plat/nxp/common/plat_make_helper/plat_common_def.mk
new file mode 100644
index 0000000..86dacf8
--- /dev/null
+++ b/plat/nxp/common/plat_make_helper/plat_common_def.mk
@@ -0,0 +1,103 @@
+# Copyright 2020-2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Include build macros, for example: SET_NXP_MAKE_FLAG
+include plat/nxp/common/plat_make_helper/plat_build_macros.mk
+
+# Adding platform specific defines
+
+$(eval $(call add_define_val,BOARD,'"${BOARD}"'))
+
+ifeq (${POVDD_ENABLE},yes)
+$(eval $(call add_define,CONFIG_POVDD_ENABLE))
+endif
+
+ifneq (${FLASH_TYPE},)
+$(eval $(call add_define,CONFIG_${FLASH_TYPE}))
+endif
+
+ifneq (${XSPI_FLASH_SZ},)
+$(eval $(call add_define_val,NXP_FLEXSPI_FLASH_SIZE,${XSPI_FLASH_SZ}))
+endif
+
+ifneq (${QSPI_FLASH_SZ},)
+$(eval $(call add_define_val,NXP_QSPI_FLASH_SIZE,${QSPI_FLASH_SZ}))
+endif
+
+ifneq (${NOR_FLASH_SZ},)
+$(eval $(call add_define_val,NXP_NOR_FLASH_SIZE,${NOR_FLASH_SZ}))
+endif
+
+
+ifneq (${FSPI_ERASE_4K},)
+$(eval $(call add_define_val,CONFIG_FSPI_ERASE_4K,${FSPI_ERASE_4K}))
+endif
+
+ifneq (${NUM_OF_DDRC},)
+$(eval $(call add_define_val,NUM_OF_DDRC,${NUM_OF_DDRC}))
+endif
+
+ifeq (${CONFIG_DDR_NODIMM},1)
+$(eval $(call add_define,CONFIG_DDR_NODIMM))
+DDRC_NUM_DIMM := 1
+endif
+
+ifneq (${DDRC_NUM_DIMM},)
+$(eval $(call add_define_val,DDRC_NUM_DIMM,${DDRC_NUM_DIMM}))
+endif
+
+ifneq (${DDRC_NUM_CS},)
+$(eval $(call add_define_val,DDRC_NUM_CS,${DDRC_NUM_CS}))
+endif
+
+ifeq (${DDR_ADDR_DEC},yes)
+$(eval $(call add_define,CONFIG_DDR_ADDR_DEC))
+endif
+
+ifeq (${DDR_ECC_EN},yes)
+$(eval $(call add_define,CONFIG_DDR_ECC_EN))
+endif
+
+ifeq (${CONFIG_STATIC_DDR},1)
+$(eval $(call add_define,CONFIG_STATIC_DDR))
+endif
+
+# Platform can control the base address for non-volatile storage.
+#$(eval $(call add_define_val,NV_STORAGE_BASE_ADDR,'${BL2_BIN_XSPI_NOR_END_ADDRESS} - 2 * ${NXP_XSPI_NOR_UNIT_SIZE}'))
+
+ifeq (${WARM_BOOT},yes)
+$(eval $(call add_define_val,PHY_TRAINING_REGS_ON_FLASH,'${BL2_BIN_XSPI_NOR_END_ADDRESS} - ${NXP_XSPI_NOR_UNIT_SIZE}'))
+endif
+
+# Selecting Boot Source for the TFA images.
+define add_boot_mode_define
+ ifeq ($(1),qspi)
+ $$(eval $$(call SET_NXP_MAKE_FLAG,QSPI_NEEDED,BL2))
+ $$(eval $$(call add_define,QSPI_BOOT))
+ else ifeq ($(1),sd)
+ $$(eval $$(call SET_NXP_MAKE_FLAG,SD_MMC_NEEDED,BL2))
+ $$(eval $$(call add_define,SD_BOOT))
+ else ifeq ($(1),emmc)
+ $$(eval $$(call SET_NXP_MAKE_FLAG,SD_MMC_NEEDED,BL2))
+ $$(eval $$(call add_define,EMMC_BOOT))
+ else ifeq ($(1),nor)
+ $$(eval $$(call SET_NXP_MAKE_FLAG,IFC_NOR_NEEDED,BL2))
+ $$(eval $$(call add_define,NOR_BOOT))
+ else ifeq ($(1),nand)
+ $$(eval $$(call SET_NXP_MAKE_FLAG,IFC_NAND_NEEDED,BL2))
+ $$(eval $$(call add_define,NAND_BOOT))
+ else ifeq ($(1),flexspi_nor)
+ $$(eval $$(call SET_NXP_MAKE_FLAG,XSPI_NEEDED,BL2))
+ $$(eval $$(call add_define,FLEXSPI_NOR_BOOT))
+ else
+ $$(error $(PLAT) Cannot Support Boot Mode: $(BOOT_MODE))
+ endif
+endef
+
+ifneq (,$(findstring $(BOOT_MODE),$(SUPPORTED_BOOT_MODE)))
+ $(eval $(call add_boot_mode_define,$(strip $(BOOT_MODE))))
+else
+ $(error $(PLAT) Un-supported Boot Mode = $(BOOT_MODE))
+endif
diff --git a/plat/nxp/common/plat_make_helper/soc_common_def.mk b/plat/nxp/common/plat_make_helper/soc_common_def.mk
new file mode 100644
index 0000000..52f2867
--- /dev/null
+++ b/plat/nxp/common/plat_make_helper/soc_common_def.mk
@@ -0,0 +1,117 @@
+# Copyright 2020-2022 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Adding SoC specific defines
+
+ifneq (${CACHE_LINE},)
+$(eval $(call add_define_val,PLATFORM_CACHE_LINE_SHIFT,${CACHE_LINE}))
+$(eval CACHE_WRITEBACK_GRANULE=$(shell echo $$((1 << $(CACHE_LINE)))))
+$(eval $(call add_define_val,CACHE_WRITEBACK_GRANULE,$(CACHE_WRITEBACK_GRANULE)))
+endif
+
+ifneq (${INTERCONNECT},)
+$(eval $(call add_define,NXP_HAS_${INTERCONNECT}))
+ifeq (${INTERCONNECT}, CCI400)
+ICNNCT_ID := 0x420
+$(eval $(call add_define,ICNNCT_ID))
+endif
+endif
+
+ifneq (${CHASSIS},)
+$(eval $(call add_define,CONFIG_CHASSIS_${CHASSIS}))
+endif
+
+ifneq (${PLAT_DDR_PHY},)
+$(eval $(call add_define,NXP_DDR_${PLAT_DDR_PHY}))
+endif
+
+ifneq (${PHYS_SYS},)
+$(eval $(call add_define,CONFIG_PHYS_64BIT))
+endif
+
+ifneq (${CSF_HDR_SZ},)
+$(eval $(call add_define_val,CSF_HDR_SZ,${CSF_HDR_SZ}))
+endif
+
+ifneq (${OCRAM_START_ADDR},)
+$(eval $(call add_define_val,NXP_OCRAM_ADDR,${OCRAM_START_ADDR}))
+endif
+
+ifneq (${OCRAM_SIZE},)
+$(eval $(call add_define_val,NXP_OCRAM_SIZE,${OCRAM_SIZE}))
+endif
+
+ifneq (${NXP_ROM_RSVD},)
+$(eval $(call add_define_val,NXP_ROM_RSVD,${NXP_ROM_RSVD}))
+endif
+
+ifneq (${BL2_BASE},)
+$(eval $(call add_define_val,BL2_BASE,${BL2_BASE}))
+endif
+
+ifeq (${SEC_MEM_NON_COHERENT},yes)
+$(eval $(call add_define,SEC_MEM_NON_COHERENT))
+endif
+
+ifneq (${NXP_ESDHC_ENDIANNESS},)
+$(eval $(call add_define,NXP_ESDHC_${NXP_ESDHC_ENDIANNESS}))
+endif
+
+ifneq (${NXP_SFP_VER},)
+$(eval $(call add_define,NXP_SFP_VER_${NXP_SFP_VER}))
+endif
+
+ifneq (${NXP_SFP_ENDIANNESS},)
+$(eval $(call add_define,NXP_SFP_${NXP_SFP_ENDIANNESS}))
+endif
+
+ifneq (${NXP_GPIO_ENDIANNESS},)
+$(eval $(call add_define,NXP_GPIO_${NXP_GPIO_ENDIANNESS}))
+endif
+
+ifneq (${NXP_SNVS_ENDIANNESS},)
+$(eval $(call add_define,NXP_SNVS_${NXP_SNVS_ENDIANNESS}))
+endif
+
+ifneq (${NXP_GUR_ENDIANNESS},)
+$(eval $(call add_define,NXP_GUR_${NXP_GUR_ENDIANNESS}))
+endif
+
+ifneq (${NXP_FSPI_ENDIANNESS},)
+$(eval $(call add_define,NXP_FSPI_${NXP_FSPI_ENDIANNESS}))
+endif
+
+ifneq (${NXP_SEC_ENDIANNESS},)
+$(eval $(call add_define,NXP_SEC_${NXP_SEC_ENDIANNESS}))
+endif
+
+ifneq (${NXP_DDR_ENDIANNESS},)
+$(eval $(call add_define,NXP_DDR_${NXP_DDR_ENDIANNESS}))
+endif
+
+ifneq (${NXP_QSPI_ENDIANNESS},)
+$(eval $(call add_define,NXP_QSPI_${NXP_QSPI_ENDIANNESS}))
+endif
+
+ifneq (${NXP_SCFG_ENDIANNESS},)
+$(eval $(call add_define,NXP_SCFG_${NXP_SCFG_ENDIANNESS}))
+endif
+
+ifneq (${NXP_IFC_ENDIANNESS},)
+$(eval $(call add_define,NXP_IFC_${NXP_IFC_ENDIANNESS}))
+endif
+
+ifneq (${NXP_DDR_INTLV_256B},)
+$(eval $(call add_define,NXP_DDR_INTLV_256B))
+endif
+
+ifneq (${PLAT_XLAT_TABLES_DYNAMIC},)
+$(eval $(call add_define,PLAT_XLAT_TABLES_DYNAMIC))
+endif
+
+ifeq (${OCRAM_ECC_EN},yes)
+$(eval $(call add_define,CONFIG_OCRAM_ECC_EN))
+include ${PLAT_COMMON_PATH}/ocram/ocram.mk
+endif
diff --git a/plat/nxp/common/psci/aarch64/psci_utils.S b/plat/nxp/common/psci/aarch64/psci_utils.S
new file mode 100644
index 0000000..ec69aea
--- /dev/null
+++ b/plat/nxp/common/psci/aarch64/psci_utils.S
@@ -0,0 +1,1155 @@
+
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <asm_macros.S>
+#include <assert_macros.S>
+
+#include <lib/psci/psci.h>
+
+#include <bl31_data.h>
+#include <plat_psci.h>
+
+
+#define RESET_RETRY_CNT 800
+#define PSCI_ABORT_CNT 100
+
+#if (SOC_CORE_RELEASE)
+
+.global _psci_cpu_on
+
+/*
+ * int _psci_cpu_on(u_register_t core_mask)
+ * x0 = target cpu core mask
+ *
+ * Called from C, so save the non-volatile regs
+ * save these as pairs of registers to maintain the
+ * required 16-byte alignment on the stack
+ *
+ */
+
+func _psci_cpu_on
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+ stp x8, x9, [sp, #-16]!
+ stp x10, x11, [sp, #-16]!
+ stp x12, x13, [sp, #-16]!
+ stp x14, x15, [sp, #-16]!
+ stp x16, x17, [sp, #-16]!
+ stp x18, x30, [sp, #-16]!
+
+ mov x6, x0
+
+ /* x0 = core mask (lsb)
+ * x6 = core mask (lsb)
+ */
+
+ /* check if core disabled */
+ bl _soc_ck_disabled /* 0-2 */
+ cbnz w0, psci_disabled
+
+ /* check core data area to see if core cannot be turned on
+ * read the core state
+ */
+ mov x0, x6
+ bl _getCoreState /* 0-5 */
+ mov x9, x0
+
+ /* x6 = core mask (lsb)
+ * x9 = core state (from data area)
+ */
+
+ cmp x9, #CORE_DISABLED
+ mov x0, #PSCI_E_DISABLED
+ b.eq cpu_on_done
+
+ cmp x9, #CORE_PENDING
+ mov x0, #PSCI_E_ON_PENDING
+ b.eq cpu_on_done
+
+ cmp x9, #CORE_RELEASED
+ mov x0, #PSCI_E_ALREADY_ON
+ b.eq cpu_on_done
+
+8:
+ /* x6 = core mask (lsb)
+ * x9 = core state (from data area)
+ */
+
+ cmp x9, #CORE_WFE
+ b.eq core_in_wfe
+ cmp x9, #CORE_IN_RESET
+ b.eq core_in_reset
+ cmp x9, #CORE_OFF
+ b.eq core_is_off
+ cmp x9, #CORE_OFF_PENDING
+
+ /* if state == CORE_OFF_PENDING, set abort */
+ mov x0, x6
+ mov x1, #ABORT_FLAG_DATA
+ mov x2, #CORE_ABORT_OP
+ bl _setCoreData /* 0-3, [13-15] */
+
+ ldr x3, =PSCI_ABORT_CNT
+7:
+ /* watch for abort to take effect */
+ mov x0, x6
+ bl _getCoreState /* 0-5 */
+ cmp x0, #CORE_OFF
+ b.eq core_is_off
+ cmp x0, #CORE_PENDING
+ mov x0, #PSCI_E_SUCCESS
+ b.eq cpu_on_done
+
+ /* loop til finished */
+ sub x3, x3, #1
+ cbnz x3, 7b
+
+ /* if we didn't see either CORE_OFF or CORE_PENDING, then this
+ * core is in CORE_OFF_PENDING - exit with success, as the core will
+ * respond to the abort request
+ */
+ mov x0, #PSCI_E_SUCCESS
+ b cpu_on_done
+
+/* this is where we start up a core out of reset */
+core_in_reset:
+ /* see if the soc-specific module supports this op */
+ ldr x7, =SOC_CORE_RELEASE
+ cbnz x7, 3f
+
+ mov x0, #PSCI_E_NOT_SUPPORTED
+ b cpu_on_done
+
+ /* x6 = core mask (lsb) */
+3:
+ /* set core state in data area */
+ mov x0, x6
+ mov x1, #CORE_PENDING
+ bl _setCoreState /* 0-3, [13-15] */
+
+ /* release the core from reset */
+ mov x0, x6
+ bl _soc_core_release /* 0-3 */
+ mov x0, #PSCI_E_SUCCESS
+ b cpu_on_done
+
+ /* Start up the core that has been powered-down via CPU_OFF
+ */
+core_is_off:
+ /* see if the soc-specific module supports this op
+ */
+ ldr x7, =SOC_CORE_RESTART
+ cbnz x7, 2f
+
+ mov x0, #PSCI_E_NOT_SUPPORTED
+ b cpu_on_done
+
+ /* x6 = core mask (lsb) */
+2:
+ /* set core state in data area */
+ mov x0, x6
+ mov x1, #CORE_WAKEUP
+ bl _setCoreState /* 0-3, [13-15] */
+
+ /* put the core back into service */
+ mov x0, x6
+#if (SOC_CORE_RESTART)
+ bl _soc_core_restart /* 0-5 */
+#endif
+ mov x0, #PSCI_E_SUCCESS
+ b cpu_on_done
+
+/* this is where we release a core that is being held in wfe */
+core_in_wfe:
+ /* x6 = core mask (lsb) */
+
+ /* set core state in data area */
+ mov x0, x6
+ mov x1, #CORE_PENDING
+ bl _setCoreState /* 0-3, [13-15] */
+ dsb sy
+ isb
+
+ /* put the core back into service */
+ sev
+ sev
+ isb
+ mov x0, #PSCI_E_SUCCESS
+
+cpu_on_done:
+ /* restore the aarch32/64 non-volatile registers */
+ ldp x18, x30, [sp], #16
+ ldp x16, x17, [sp], #16
+ ldp x14, x15, [sp], #16
+ ldp x12, x13, [sp], #16
+ ldp x10, x11, [sp], #16
+ ldp x8, x9, [sp], #16
+ ldp x6, x7, [sp], #16
+ ldp x4, x5, [sp], #16
+ b psci_completed
+endfunc _psci_cpu_on
+
+#endif
+
+
+#if (SOC_CORE_OFF)
+
+.global _psci_cpu_prep_off
+.global _psci_cpu_off_wfi
+
+/*
+ * void _psci_cpu_prep_off(u_register_t core_mask)
+ * this function performs the SoC-specific programming prior
+ * to shutting the core down
+ * x0 = core_mask
+ *
+ * called from C, so save the non-volatile regs
+ * save these as pairs of registers to maintain the
+ * required 16-byte alignment on the stack
+ */
+
+func _psci_cpu_prep_off
+
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+ stp x8, x9, [sp, #-16]!
+ stp x10, x11, [sp, #-16]!
+ stp x12, x13, [sp, #-16]!
+ stp x14, x15, [sp, #-16]!
+ stp x16, x17, [sp, #-16]!
+ stp x18, x30, [sp, #-16]!
+
+ mov x10, x0 /* x10 = core_mask */
+
+ /* the core does not return from cpu_off, so no need
+ * to save/restore non-volatile registers
+ */
+
+ /* mask interrupts by setting DAIF[7:4] to 'b1111 */
+ msr DAIFSet, #0xF
+
+ /* read cpuectlr and save current value */
+ mrs x4, CPUECTLR_EL1
+ mov x1, #CPUECTLR_DATA
+ mov x2, x4
+ mov x0, x10
+ bl _setCoreData
+
+ /* remove the core from coherency */
+ bic x4, x4, #CPUECTLR_SMPEN_MASK
+ msr CPUECTLR_EL1, x4
+
+ /* save scr_el3 */
+ mov x0, x10
+ mrs x4, SCR_EL3
+ mov x2, x4
+ mov x1, #SCR_EL3_DATA
+ bl _setCoreData
+
+ /* x4 = scr_el3 */
+
+ /* secure SGI (FIQ) taken to EL3, set SCR_EL3[FIQ] */
+ orr x4, x4, #SCR_FIQ_MASK
+ msr scr_el3, x4
+
+ /* x10 = core_mask */
+
+ /* prep the core for shutdown */
+ mov x0, x10
+ bl _soc_core_prep_off
+
+ /* restore the aarch32/64 non-volatile registers */
+ ldp x18, x30, [sp], #16
+ ldp x16, x17, [sp], #16
+ ldp x14, x15, [sp], #16
+ ldp x12, x13, [sp], #16
+ ldp x10, x11, [sp], #16
+ ldp x8, x9, [sp], #16
+ ldp x6, x7, [sp], #16
+ ldp x4, x5, [sp], #16
+ b psci_completed
+endfunc _psci_cpu_prep_off
+
+/*
+ * void _psci_cpu_off_wfi(u_register_t core_mask, u_register_t resume_addr)
+ * - this function shuts down the core
+ * - this function does not return!!
+ */
+
+func _psci_cpu_off_wfi
+ /* save the wakeup address */
+ mov x29, x1
+
+ /* x0 = core_mask */
+
+ /* shutdown the core */
+ bl _soc_core_entr_off
+
+ /* branch to resume execution */
+ br x29
+endfunc _psci_cpu_off_wfi
+
+#endif
+
+
+#if (SOC_CORE_RESTART)
+
+.global _psci_wakeup
+
+/*
+ * void _psci_wakeup(u_register_t core_mask)
+ * this function performs the SoC-specific programming
+ * after a core wakes up from OFF
+ * x0 = core mask
+ *
+ * called from C, so save the non-volatile regs
+ * save these as pairs of registers to maintain the
+ * required 16-byte alignment on the stack
+ */
+
+func _psci_wakeup
+
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+ stp x8, x9, [sp, #-16]!
+ stp x10, x11, [sp, #-16]!
+ stp x12, x13, [sp, #-16]!
+ stp x14, x15, [sp, #-16]!
+ stp x16, x17, [sp, #-16]!
+ stp x18, x30, [sp, #-16]!
+
+ mov x4, x0 /* x4 = core mask */
+
+ /* restore scr_el3 */
+ mov x0, x4
+ mov x1, #SCR_EL3_DATA
+ bl _getCoreData
+ /* x0 = saved scr_el3 */
+ msr SCR_EL3, x0
+
+ /* x4 = core mask */
+
+ /* restore CPUECTLR */
+ mov x0, x4
+ mov x1, #CPUECTLR_DATA
+ bl _getCoreData
+ orr x0, x0, #CPUECTLR_SMPEN_MASK
+ msr CPUECTLR_EL1, x0
+
+ /* x4 = core mask */
+
+ /* start the core back up */
+ mov x0, x4
+ bl _soc_core_exit_off
+
+ /* restore the aarch32/64 non-volatile registers
+ */
+ ldp x18, x30, [sp], #16
+ ldp x16, x17, [sp], #16
+ ldp x14, x15, [sp], #16
+ ldp x12, x13, [sp], #16
+ ldp x10, x11, [sp], #16
+ ldp x8, x9, [sp], #16
+ ldp x6, x7, [sp], #16
+ ldp x4, x5, [sp], #16
+ b psci_completed
+endfunc _psci_wakeup
+
+#endif
+
+
+#if (SOC_SYSTEM_RESET)
+
+.global _psci_system_reset
+
+func _psci_system_reset
+
+ /* system reset is mandatory
+ * system reset is soc-specific
+ * Note: under no circumstances do we return from this call
+ */
+ bl _soc_sys_reset
+endfunc _psci_system_reset
+
+#endif
+
+
+#if (SOC_SYSTEM_OFF)
+
+.global _psci_system_off
+
+func _psci_system_off
+
+ /* system off is mandatory
+ * system off is soc-specific
+ * Note: under no circumstances do we return from this call */
+ b _soc_sys_off
+endfunc _psci_system_off
+
+#endif
+
+
+#if (SOC_CORE_STANDBY)
+
+.global _psci_core_entr_stdby
+.global _psci_core_prep_stdby
+.global _psci_core_exit_stdby
+
+/*
+ * void _psci_core_entr_stdby(u_register_t core_mask) - this
+ * is the fast-path for simple core standby
+ */
+
+func _psci_core_entr_stdby
+ stp x4, x5, [sp, #-16]!
+ stp x6, x30, [sp, #-16]!
+
+ mov x5, x0 /* x5 = core mask */
+
+ /* save scr_el3 */
+ mov x0, x5
+ mrs x4, SCR_EL3
+ mov x2, x4
+ mov x1, #SCR_EL3_DATA
+ bl _setCoreData
+
+ /* x4 = SCR_EL3
+ * x5 = core mask
+ */
+
+ /* allow interrupts @ EL3 */
+ orr x4, x4, #(SCR_IRQ_MASK | SCR_FIQ_MASK)
+ msr SCR_EL3, x4
+
+ /* x5 = core mask */
+
+ /* put the core into standby */
+ mov x0, x5
+ bl _soc_core_entr_stdby
+
+ /* restore scr_el3 */
+ mov x0, x5
+ mov x1, #SCR_EL3_DATA
+ bl _getCoreData
+ /* x0 = saved scr_el3 */
+ msr SCR_EL3, x0
+
+ ldp x6, x30, [sp], #16
+ ldp x4, x5, [sp], #16
+ isb
+ ret
+endfunc _psci_core_entr_stdby
+
+/*
+ * void _psci_core_prep_stdby(u_register_t core_mask) - this
+ * sets up the core to enter standby state thru the normal path
+ */
+
+func _psci_core_prep_stdby
+ stp x4, x5, [sp, #-16]!
+ stp x6, x30, [sp, #-16]!
+
+ mov x5, x0
+
+ /* x5 = core mask */
+
+ /* save scr_el3 */
+ mov x0, x5
+ mrs x4, SCR_EL3
+ mov x2, x4
+ mov x1, #SCR_EL3_DATA
+ bl _setCoreData
+
+ /* allow interrupts @ EL3 */
+ orr x4, x4, #(SCR_IRQ_MASK | SCR_FIQ_MASK)
+ msr SCR_EL3, x4
+
+ /* x5 = core mask */
+
+ /* call for any SoC-specific programming */
+ mov x0, x5
+ bl _soc_core_prep_stdby
+
+ ldp x6, x30, [sp], #16
+ ldp x4, x5, [sp], #16
+ isb
+ ret
+endfunc _psci_core_prep_stdby
+
+/*
+ * void _psci_core_exit_stdby(u_register_t core_mask) - this
+ * exits the core from standby state thru the normal path
+ */
+
+func _psci_core_exit_stdby
+ stp x4, x5, [sp, #-16]!
+ stp x6, x30, [sp, #-16]!
+
+ mov x5, x0
+
+ /* x5 = core mask */
+
+ /* restore scr_el3 */
+ mov x0, x5
+ mov x1, #SCR_EL3_DATA
+ bl _getCoreData
+ /* x0 = saved scr_el3 */
+ msr SCR_EL3, x0
+
+ /* x5 = core mask */
+
+ /* perform any SoC-specific programming after standby state */
+ mov x0, x5
+ bl _soc_core_exit_stdby
+
+ ldp x6, x30, [sp], #16
+ ldp x4, x5, [sp], #16
+ isb
+ ret
+endfunc _psci_core_exit_stdby
+
+#endif
+
+
+#if (SOC_CORE_PWR_DWN)
+
+.global _psci_core_prep_pwrdn
+.global _psci_cpu_pwrdn_wfi
+.global _psci_core_exit_pwrdn
+
+/*
+ * void _psci_core_prep_pwrdn_(u_register_t core_mask)
+ * this function prepares the core for power-down
+ * x0 = core mask
+ *
+ * called from C, so save the non-volatile regs
+ * save these as pairs of registers to maintain the
+ * required 16-byte alignment on the stack
+ */
+
+func _psci_core_prep_pwrdn
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+ stp x8, x9, [sp, #-16]!
+ stp x10, x11, [sp, #-16]!
+ stp x12, x13, [sp, #-16]!
+ stp x14, x15, [sp, #-16]!
+ stp x16, x17, [sp, #-16]!
+ stp x18, x30, [sp, #-16]!
+
+ mov x6, x0
+
+ /* x6 = core mask */
+
+ /* mask interrupts by setting DAIF[7:4] to 'b1111 */
+ msr DAIFSet, #0xF
+
+ /* save scr_el3 */
+ mov x0, x6
+ mrs x4, SCR_EL3
+ mov x2, x4
+ mov x1, #SCR_EL3_DATA
+ bl _setCoreData
+
+ /* allow interrupts @ EL3 */
+ orr x4, x4, #(SCR_IRQ_MASK | SCR_FIQ_MASK)
+ msr SCR_EL3, x4
+
+ /* save cpuectlr */
+ mov x0, x6
+ mov x1, #CPUECTLR_DATA
+ mrs x2, CPUECTLR_EL1
+ bl _setCoreData
+
+ /* x6 = core mask */
+
+ /* SoC-specific programming for power-down */
+ mov x0, x6
+ bl _soc_core_prep_pwrdn
+
+ /* restore the aarch32/64 non-volatile registers
+ */
+ ldp x18, x30, [sp], #16
+ ldp x16, x17, [sp], #16
+ ldp x14, x15, [sp], #16
+ ldp x12, x13, [sp], #16
+ ldp x10, x11, [sp], #16
+ ldp x8, x9, [sp], #16
+ ldp x6, x7, [sp], #16
+ ldp x4, x5, [sp], #16
+ b psci_completed
+endfunc _psci_core_prep_pwrdn
+
+/*
+ * void _psci_cpu_pwrdn_wfi(u_register_t core_mask, u_register_t resume_addr)
+ * this function powers down the core
+ */
+
+func _psci_cpu_pwrdn_wfi
+ /* save the wakeup address */
+ mov x29, x1
+
+ /* x0 = core mask */
+
+ /* shutdown the core */
+ bl _soc_core_entr_pwrdn
+
+ /* branch to resume execution */
+ br x29
+endfunc _psci_cpu_pwrdn_wfi
+
+/*
+ * void _psci_core_exit_pwrdn_(u_register_t core_mask)
+ * this function cleans up after a core power-down
+ * x0 = core mask
+ *
+ * called from C, so save the non-volatile regs
+ * save these as pairs of registers to maintain the
+ * required 16-byte alignment on the stack
+ */
+
+func _psci_core_exit_pwrdn
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+ stp x8, x9, [sp, #-16]!
+ stp x10, x11, [sp, #-16]!
+ stp x12, x13, [sp, #-16]!
+ stp x14, x15, [sp, #-16]!
+ stp x16, x17, [sp, #-16]!
+ stp x18, x30, [sp, #-16]!
+
+ mov x5, x0 /* x5 = core mask */
+
+ /* restore scr_el3 */
+ mov x0, x5
+ mov x1, #SCR_EL3_DATA
+ bl _getCoreData
+ /* x0 = saved scr_el3 */
+ msr SCR_EL3, x0
+
+ /* x5 = core mask */
+
+ /* restore cpuectlr */
+ mov x0, x5
+ mov x1, #CPUECTLR_DATA
+ bl _getCoreData
+ /* make sure smp is set */
+ orr x0, x0, #CPUECTLR_SMPEN_MASK
+ msr CPUECTLR_EL1, x0
+
+ /* x5 = core mask */
+
+ /* SoC-specific cleanup */
+ mov x0, x5
+ bl _soc_core_exit_pwrdn
+
+ /* restore the aarch32/64 non-volatile registers
+ */
+ ldp x18, x30, [sp], #16
+ ldp x16, x17, [sp], #16
+ ldp x14, x15, [sp], #16
+ ldp x12, x13, [sp], #16
+ ldp x10, x11, [sp], #16
+ ldp x8, x9, [sp], #16
+ ldp x6, x7, [sp], #16
+ ldp x4, x5, [sp], #16
+ b psci_completed
+endfunc _psci_core_exit_pwrdn
+
+#endif
+
+#if (SOC_CLUSTER_STANDBY)
+
+.global _psci_clstr_prep_stdby
+.global _psci_clstr_exit_stdby
+
+/*
+ * void _psci_clstr_prep_stdby(u_register_t core_mask) - this
+ * sets up the clstr to enter standby state thru the normal path
+ */
+
+func _psci_clstr_prep_stdby
+ stp x4, x5, [sp, #-16]!
+ stp x6, x30, [sp, #-16]!
+
+ mov x5, x0
+
+ /* x5 = core mask */
+
+ /* save scr_el3 */
+ mov x0, x5
+ mrs x4, SCR_EL3
+ mov x2, x4
+ mov x1, #SCR_EL3_DATA
+ bl _setCoreData
+
+ /* allow interrupts @ EL3 */
+ orr x4, x4, #(SCR_IRQ_MASK | SCR_FIQ_MASK)
+ msr SCR_EL3, x4
+
+ /* x5 = core mask */
+
+ /* call for any SoC-specific programming */
+ mov x0, x5
+ bl _soc_clstr_prep_stdby
+
+ ldp x6, x30, [sp], #16
+ ldp x4, x5, [sp], #16
+ isb
+ ret
+endfunc _psci_clstr_prep_stdby
+
+/*
+ * void _psci_clstr_exit_stdby(u_register_t core_mask) - this
+ * exits the clstr from standby state thru the normal path
+ */
+
+func _psci_clstr_exit_stdby
+ stp x4, x5, [sp, #-16]!
+ stp x6, x30, [sp, #-16]!
+
+ mov x5, x0 /* x5 = core mask */
+
+ /* restore scr_el3 */
+ mov x0, x5
+ mov x1, #SCR_EL3_DATA
+ bl _getCoreData
+ /* x0 = saved scr_el3 */
+ msr SCR_EL3, x0
+
+ /* x5 = core mask */
+
+ /* perform any SoC-specific programming after standby state */
+ mov x0, x5
+ bl _soc_clstr_exit_stdby
+
+ ldp x6, x30, [sp], #16
+ ldp x4, x5, [sp], #16
+ isb
+ ret
+endfunc _psci_clstr_exit_stdby
+
+#endif
+
+#if (SOC_CLUSTER_PWR_DWN)
+
+.global _psci_clstr_prep_pwrdn
+.global _psci_clstr_exit_pwrdn
+
+/*
+ * void _psci_clstr_prep_pwrdn_(u_register_t core_mask)
+ * this function prepares the cluster+core for power-down
+ * x0 = core mask
+ *
+ * called from C, so save the non-volatile regs
+ * save these as pairs of registers to maintain the
+ * required 16-byte alignment on the stack
+ */
+
+func _psci_clstr_prep_pwrdn
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+ stp x8, x9, [sp, #-16]!
+ stp x10, x11, [sp, #-16]!
+ stp x12, x13, [sp, #-16]!
+ stp x14, x15, [sp, #-16]!
+ stp x16, x17, [sp, #-16]!
+ stp x18, x30, [sp, #-16]!
+
+ mov x6, x0 /* x6 = core mask */
+
+ /* mask interrupts by setting DAIF[7:4] to 'b1111 */
+ msr DAIFSet, #0xF
+
+ /* save scr_el3 */
+ mov x0, x6
+ mrs x4, SCR_EL3
+ mov x2, x4
+ mov x1, #SCR_EL3_DATA
+ bl _setCoreData
+
+ /* allow interrupts @ EL3 */
+ orr x4, x4, #(SCR_IRQ_MASK | SCR_FIQ_MASK)
+ msr SCR_EL3, x4
+
+ /* save cpuectlr */
+ mov x0, x6
+ mov x1, #CPUECTLR_DATA
+ mrs x2, CPUECTLR_EL1
+ mov x4, x2
+ bl _setCoreData
+
+ /* remove core from coherency */
+ bic x4, x4, #CPUECTLR_SMPEN_MASK
+ msr CPUECTLR_EL1, x4
+
+ /* x6 = core mask */
+
+ /* SoC-specific programming for power-down */
+ mov x0, x6
+ bl _soc_clstr_prep_pwrdn
+
+ /* restore the aarch32/64 non-volatile registers
+ */
+ ldp x18, x30, [sp], #16
+ ldp x16, x17, [sp], #16
+ ldp x14, x15, [sp], #16
+ ldp x12, x13, [sp], #16
+ ldp x10, x11, [sp], #16
+ ldp x8, x9, [sp], #16
+ ldp x6, x7, [sp], #16
+ ldp x4, x5, [sp], #16
+ b psci_completed
+endfunc _psci_clstr_prep_pwrdn
+
+/*
+ * void _psci_clstr_exit_pwrdn_(u_register_t core_mask)
+ * this function cleans up after a cluster power-down
+ * x0 = core mask
+ *
+ * called from C, so save the non-volatile regs
+ * save these as pairs of registers to maintain the
+ * required 16-byte alignment on the stack
+ */
+
+func _psci_clstr_exit_pwrdn
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+ stp x8, x9, [sp, #-16]!
+ stp x10, x11, [sp, #-16]!
+ stp x12, x13, [sp, #-16]!
+ stp x14, x15, [sp, #-16]!
+ stp x16, x17, [sp, #-16]!
+ stp x18, x30, [sp, #-16]!
+
+ mov x4, x0 /* x4 = core mask */
+
+ /* restore scr_el3 */
+ mov x0, x4
+ mov x1, #SCR_EL3_DATA
+ bl _getCoreData
+ /* x0 = saved scr_el3 */
+ msr SCR_EL3, x0
+
+ /* x4 = core mask */
+
+ /* restore cpuectlr */
+ mov x0, x4
+ mov x1, #CPUECTLR_DATA
+ bl _getCoreData
+ /* make sure smp is set */
+ orr x0, x0, #CPUECTLR_SMPEN_MASK
+ msr CPUECTLR_EL1, x0
+
+ /* x4 = core mask */
+
+ /* SoC-specific cleanup */
+ mov x0, x4
+ bl _soc_clstr_exit_pwrdn
+
+ /* restore the aarch32/64 non-volatile registers
+ */
+ ldp x18, x30, [sp], #16
+ ldp x16, x17, [sp], #16
+ ldp x14, x15, [sp], #16
+ ldp x12, x13, [sp], #16
+ ldp x10, x11, [sp], #16
+ ldp x8, x9, [sp], #16
+ ldp x6, x7, [sp], #16
+ ldp x4, x5, [sp], #16
+ b psci_completed
+endfunc _psci_clstr_exit_pwrdn
+
+#endif
+
+#if (SOC_SYSTEM_STANDBY)
+
+.global _psci_sys_prep_stdby
+.global _psci_sys_exit_stdby
+
+/*
+ * void _psci_sys_prep_stdby(u_register_t core_mask) - this
+ * sets up the system to enter standby state thru the normal path
+ */
+
+func _psci_sys_prep_stdby
+ stp x4, x5, [sp, #-16]!
+ stp x6, x30, [sp, #-16]!
+
+ mov x5, x0 /* x5 = core mask */
+
+ /* save scr_el3 */
+ mov x0, x5
+ mrs x4, SCR_EL3
+ mov x2, x4
+ mov x1, #SCR_EL3_DATA
+ bl _setCoreData
+
+ /* allow interrupts @ EL3 */
+ orr x4, x4, #(SCR_IRQ_MASK | SCR_FIQ_MASK)
+ msr SCR_EL3, x4
+
+ /* x5 = core mask */
+
+ /* call for any SoC-specific programming */
+ mov x0, x5
+ bl _soc_sys_prep_stdby
+
+ ldp x6, x30, [sp], #16
+ ldp x4, x5, [sp], #16
+ isb
+ ret
+endfunc _psci_sys_prep_stdby
+
+/*
+ * void _psci_sys_exit_stdby(u_register_t core_mask) - this
+ * exits the system from standby state thru the normal path
+ */
+
+func _psci_sys_exit_stdby
+ stp x4, x5, [sp, #-16]!
+ stp x6, x30, [sp, #-16]!
+
+ mov x5, x0
+
+ /* x5 = core mask */
+
+ /* restore scr_el3 */
+ mov x0, x5
+ mov x1, #SCR_EL3_DATA
+ bl _getCoreData
+ /* x0 = saved scr_el3 */
+ msr SCR_EL3, x0
+
+ /* x5 = core mask */
+
+ /* perform any SoC-specific programming after standby state */
+ mov x0, x5
+ bl _soc_sys_exit_stdby
+
+ ldp x6, x30, [sp], #16
+ ldp x4, x5, [sp], #16
+ isb
+ ret
+endfunc _psci_sys_exit_stdby
+
+#endif
+
+#if (SOC_SYSTEM_PWR_DWN)
+
+.global _psci_sys_prep_pwrdn
+.global _psci_sys_pwrdn_wfi
+.global _psci_sys_exit_pwrdn
+
+/*
+ * void _psci_sys_prep_pwrdn_(u_register_t core_mask)
+ * this function prepares the system+core for power-down
+ * x0 = core mask
+ *
+ * called from C, so save the non-volatile regs
+ * save these as pairs of registers to maintain the
+ * required 16-byte alignment on the stack
+ */
+
+func _psci_sys_prep_pwrdn
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+ stp x8, x9, [sp, #-16]!
+ stp x10, x11, [sp, #-16]!
+ stp x12, x13, [sp, #-16]!
+ stp x14, x15, [sp, #-16]!
+ stp x16, x17, [sp, #-16]!
+ stp x18, x30, [sp, #-16]!
+
+ mov x6, x0 /* x6 = core mask */
+
+ /* mask interrupts by setting DAIF[7:4] to 'b1111 */
+ msr DAIFSet, #0xF
+
+ /* save scr_el3 */
+ mov x0, x6
+ mrs x4, SCR_EL3
+ mov x2, x4
+ mov x1, #SCR_EL3_DATA
+ bl _setCoreData
+
+ /* allow interrupts @ EL3 */
+ orr x4, x4, #(SCR_IRQ_MASK | SCR_FIQ_MASK)
+ msr SCR_EL3, x4
+
+ /* save cpuectlr */
+ mov x0, x6
+ mov x1, #CPUECTLR_DATA
+ mrs x2, CPUECTLR_EL1
+ mov x4, x2
+ bl _setCoreData
+
+ /* remove core from coherency */
+ bic x4, x4, #CPUECTLR_SMPEN_MASK
+ msr CPUECTLR_EL1, x4
+
+ /* x6 = core mask */
+
+ /* SoC-specific programming for power-down */
+ mov x0, x6
+ bl _soc_sys_prep_pwrdn
+
+ /* restore the aarch32/64 non-volatile registers
+ */
+ ldp x18, x30, [sp], #16
+ ldp x16, x17, [sp], #16
+ ldp x14, x15, [sp], #16
+ ldp x12, x13, [sp], #16
+ ldp x10, x11, [sp], #16
+ ldp x8, x9, [sp], #16
+ ldp x6, x7, [sp], #16
+ ldp x4, x5, [sp], #16
+ b psci_completed
+endfunc _psci_sys_prep_pwrdn
+
+
+/*
+ * void _psci_sys_pwrdn_wfi(u_register_t core_mask, u_register_t resume_addr)
+ * this function powers down the system
+ */
+
+func _psci_sys_pwrdn_wfi
+ /* save the wakeup address */
+ mov x29, x1
+
+ /* x0 = core mask */
+
+ /* shutdown the system */
+ bl _soc_sys_pwrdn_wfi
+
+ /* branch to resume execution */
+ br x29
+endfunc _psci_sys_pwrdn_wfi
+
+/*
+ * void _psci_sys_exit_pwrdn_(u_register_t core_mask)
+ * this function cleans up after a system power-down
+ * x0 = core mask
+ *
+ * Called from C, so save the non-volatile regs
+ * save these as pairs of registers to maintain the
+ * required 16-byte alignment on the stack
+ */
+
+func _psci_sys_exit_pwrdn
+
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+ stp x8, x9, [sp, #-16]!
+ stp x10, x11, [sp, #-16]!
+ stp x12, x13, [sp, #-16]!
+ stp x14, x15, [sp, #-16]!
+ stp x16, x17, [sp, #-16]!
+ stp x18, x30, [sp, #-16]!
+
+ mov x4, x0 /* x4 = core mask */
+
+ /* restore scr_el3 */
+ mov x0, x4
+ mov x1, #SCR_EL3_DATA
+ bl _getCoreData
+
+ /* x0 = saved scr_el3 */
+ msr SCR_EL3, x0
+
+ /* x4 = core mask */
+
+ /* restore cpuectlr */
+ mov x0, x4
+ mov x1, #CPUECTLR_DATA
+ bl _getCoreData
+
+ /* make sure smp is set */
+ orr x0, x0, #CPUECTLR_SMPEN_MASK
+ msr CPUECTLR_EL1, x0
+
+ /* x4 = core mask */
+
+ /* SoC-specific cleanup */
+ mov x0, x4
+ bl _soc_sys_exit_pwrdn
+
+ /* restore the aarch32/64 non-volatile registers
+ */
+ ldp x18, x30, [sp], #16
+ ldp x16, x17, [sp], #16
+ ldp x14, x15, [sp], #16
+ ldp x12, x13, [sp], #16
+ ldp x10, x11, [sp], #16
+ ldp x8, x9, [sp], #16
+ ldp x6, x7, [sp], #16
+ ldp x4, x5, [sp], #16
+ b psci_completed
+endfunc _psci_sys_exit_pwrdn
+
+#endif
+
+
+/* psci std returns */
+func psci_disabled
+ ldr w0, =PSCI_E_DISABLED
+ b psci_completed
+endfunc psci_disabled
+
+
+func psci_not_present
+ ldr w0, =PSCI_E_NOT_PRESENT
+ b psci_completed
+endfunc psci_not_present
+
+
+func psci_on_pending
+ ldr w0, =PSCI_E_ON_PENDING
+ b psci_completed
+endfunc psci_on_pending
+
+
+func psci_already_on
+ ldr w0, =PSCI_E_ALREADY_ON
+ b psci_completed
+endfunc psci_already_on
+
+
+func psci_failure
+ ldr w0, =PSCI_E_INTERN_FAIL
+ b psci_completed
+endfunc psci_failure
+
+
+func psci_unimplemented
+ ldr w0, =PSCI_E_NOT_SUPPORTED
+ b psci_completed
+endfunc psci_unimplemented
+
+
+func psci_denied
+ ldr w0, =PSCI_E_DENIED
+ b psci_completed
+endfunc psci_denied
+
+
+func psci_invalid
+ ldr w0, =PSCI_E_INVALID_PARAMS
+ b psci_completed
+endfunc psci_invalid
+
+
+func psci_success
+ mov x0, #PSCI_E_SUCCESS
+endfunc psci_success
+
+
+func psci_completed
+ /* x0 = status code */
+ ret
+endfunc psci_completed
diff --git a/plat/nxp/common/psci/include/plat_psci.h b/plat/nxp/common/psci/include/plat_psci.h
new file mode 100644
index 0000000..7fc48fb
--- /dev/null
+++ b/plat/nxp/common/psci/include/plat_psci.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PLAT_PSCI_H
+#define PLAT_PSCI_H
+#include <cortex_a53.h>
+#include <cortex_a72.h>
+
+ /* core abort current op */
+#define CORE_ABORT_OP 0x1
+
+ /* psci power levels - these are actually affinity levels
+ * in the psci_power_state_t array
+ */
+#define PLAT_CORE_LVL PSCI_CPU_PWR_LVL
+#define PLAT_CLSTR_LVL U(1)
+#define PLAT_SYS_LVL U(2)
+#define PLAT_MAX_LVL PLAT_SYS_LVL
+
+ /* core state */
+ /* OFF states 0x0 - 0xF */
+#define CORE_IN_RESET 0x0
+#define CORE_DISABLED 0x1
+#define CORE_OFF 0x2
+#define CORE_STANDBY 0x3
+#define CORE_PWR_DOWN 0x4
+#define CORE_WFE 0x6
+#define CORE_WFI 0x7
+#define CORE_LAST 0x8
+#define CORE_OFF_PENDING 0x9
+#define CORE_WORKING_INIT 0xA
+#define SYS_OFF_PENDING 0xB
+#define SYS_OFF 0xC
+
+ /* ON states 0x10 - 0x1F */
+#define CORE_PENDING 0x10
+#define CORE_RELEASED 0x11
+#define CORE_WAKEUP 0x12
+ /* highest off state */
+#define CORE_OFF_MAX 0xF
+ /* lowest on state */
+#define CORE_ON_MIN CORE_PENDING
+
+#define DAIF_SET_MASK 0x3C0
+#define SCTLR_I_C_M_MASK 0x00001005
+#define SCTLR_C_MASK 0x00000004
+#define SCTLR_I_MASK 0x00001000
+#define CPUACTLR_L1PCTL_MASK 0x0000E000
+#define DCSR_RCPM2_BASE 0x20170000
+#define CPUECTLR_SMPEN_MASK 0x40
+#define CPUECTLR_SMPEN_EN 0x40
+#define CPUECTLR_RET_MASK 0x7
+#define CPUECTLR_RET_SET 0x2
+#define CPUECTLR_TIMER_MASK 0x7
+#define CPUECTLR_TIMER_8TICKS 0x2
+#define CPUECTLR_TIMER_2TICKS 0x1
+#define SCR_IRQ_MASK 0x2
+#define SCR_FIQ_MASK 0x4
+
+/* pwr mgmt features supported in the soc-specific code:
+ * value == 0x0, the soc code does not support this feature
+ * value != 0x0, the soc code supports this feature
+ */
+#ifndef SOC_CORE_RELEASE
+#define SOC_CORE_RELEASE 0x1
+#endif
+
+#ifndef SOC_CORE_RESTART
+#define SOC_CORE_RESTART 0x1
+#endif
+
+#ifndef SOC_CORE_OFF
+#define SOC_CORE_OFF 0x1
+#endif
+
+#ifndef SOC_CORE_STANDBY
+#define SOC_CORE_STANDBY 0x1
+#endif
+
+#ifndef SOC_CORE_PWR_DWN
+#define SOC_CORE_PWR_DWN 0x1
+#endif
+
+#ifndef SOC_CLUSTER_STANDBY
+#define SOC_CLUSTER_STANDBY 0x1
+#endif
+
+#ifndef SOC_CLUSTER_PWR_DWN
+#define SOC_CLUSTER_PWR_DWN 0x1
+#endif
+
+#ifndef SOC_SYSTEM_STANDBY
+#define SOC_SYSTEM_STANDBY 0x1
+#endif
+
+#ifndef SOC_SYSTEM_PWR_DWN
+#define SOC_SYSTEM_PWR_DWN 0x1
+#endif
+
+#ifndef SOC_SYSTEM_OFF
+#define SOC_SYSTEM_OFF 0x1
+#endif
+
+#ifndef SOC_SYSTEM_RESET
+#define SOC_SYSTEM_RESET 0x1
+#endif
+
+#ifndef SOC_SYSTEM_RESET2
+#define SOC_SYSTEM_RESET2 0x1
+#endif
+
+#ifndef __ASSEMBLER__
+
+void __dead2 _psci_system_reset(void);
+void __dead2 _psci_system_off(void);
+int _psci_cpu_on(u_register_t core_mask);
+void _psci_cpu_prep_off(u_register_t core_mask);
+void __dead2 _psci_cpu_off_wfi(u_register_t core_mask,
+ u_register_t wakeup_address);
+void __dead2 _psci_cpu_pwrdn_wfi(u_register_t core_mask,
+ u_register_t wakeup_address);
+void __dead2 _psci_sys_pwrdn_wfi(u_register_t core_mask,
+ u_register_t wakeup_address);
+void _psci_wakeup(u_register_t core_mask);
+void _psci_core_entr_stdby(u_register_t core_mask);
+void _psci_core_prep_stdby(u_register_t core_mask);
+void _psci_core_exit_stdby(u_register_t core_mask);
+void _psci_core_prep_pwrdn(u_register_t core_mask);
+void _psci_core_exit_pwrdn(u_register_t core_mask);
+void _psci_clstr_prep_stdby(u_register_t core_mask);
+void _psci_clstr_exit_stdby(u_register_t core_mask);
+void _psci_clstr_prep_pwrdn(u_register_t core_mask);
+void _psci_clstr_exit_pwrdn(u_register_t core_mask);
+void _psci_sys_prep_stdby(u_register_t core_mask);
+void _psci_sys_exit_stdby(u_register_t core_mask);
+void _psci_sys_prep_pwrdn(u_register_t core_mask);
+void _psci_sys_exit_pwrdn(u_register_t core_mask);
+
+#endif
+
+#endif /* __PLAT_PSCI_H__ */
diff --git a/plat/nxp/common/psci/plat_psci.c b/plat/nxp/common/psci/plat_psci.c
new file mode 100644
index 0000000..9281e97
--- /dev/null
+++ b/plat/nxp/common/psci/plat_psci.c
@@ -0,0 +1,475 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <common/debug.h>
+
+#include <plat_gic.h>
+#include <plat_common.h>
+#include <plat_psci.h>
+#ifdef NXP_WARM_BOOT
+#include <plat_warm_rst.h>
+#endif
+
+#include <platform_def.h>
+
+#if (SOC_CORE_OFF || SOC_CORE_PWR_DWN)
+static void __dead2 _no_return_wfi(void)
+{
+_bl31_dead_wfi:
+ wfi();
+ goto _bl31_dead_wfi;
+}
+#endif
+
+#if (SOC_CORE_RELEASE || SOC_CORE_PWR_DWN)
+ /* the entry for core warm boot */
+static uintptr_t warmboot_entry = (uintptr_t) NULL;
+#endif
+
+#if (SOC_CORE_RELEASE)
+static int _pwr_domain_on(u_register_t mpidr)
+{
+ int core_pos = plat_core_pos(mpidr);
+ int rc = PSCI_E_INVALID_PARAMS;
+ u_register_t core_mask;
+
+ if (core_pos >= 0 && core_pos < PLATFORM_CORE_COUNT) {
+
+ _soc_set_start_addr(warmboot_entry);
+
+ dsb();
+ isb();
+
+ core_mask = (1 << core_pos);
+ rc = _psci_cpu_on(core_mask);
+ }
+
+ return (rc);
+}
+#endif
+
+#if (SOC_CORE_OFF)
+static void _pwr_domain_off(const psci_power_state_t *target_state)
+{
+ u_register_t core_mask = plat_my_core_mask();
+ u_register_t core_state = _getCoreState(core_mask);
+
+ /* set core state in internal data */
+ core_state = CORE_OFF_PENDING;
+ _setCoreState(core_mask, core_state);
+
+ _psci_cpu_prep_off(core_mask);
+}
+#endif
+
+#if (SOC_CORE_OFF || SOC_CORE_PWR_DWN)
+static void __dead2 _pwr_down_wfi(const psci_power_state_t *target_state)
+{
+ u_register_t core_mask = plat_my_core_mask();
+ u_register_t core_state = _getCoreState(core_mask);
+
+ switch (core_state) {
+#if (SOC_CORE_OFF)
+ case CORE_OFF_PENDING:
+ /* set core state in internal data */
+ core_state = CORE_OFF;
+ _setCoreState(core_mask, core_state);
+
+ /* turn the core off */
+ _psci_cpu_off_wfi(core_mask, warmboot_entry);
+ break;
+#endif
+#if (SOC_CORE_PWR_DWN)
+ case CORE_PWR_DOWN:
+ /* power-down the core */
+ _psci_cpu_pwrdn_wfi(core_mask, warmboot_entry);
+ break;
+#endif
+#if (SOC_SYSTEM_PWR_DWN)
+ case SYS_OFF_PENDING:
+ /* set core state in internal data */
+ core_state = SYS_OFF;
+ _setCoreState(core_mask, core_state);
+
+ /* power-down the system */
+ _psci_sys_pwrdn_wfi(core_mask, warmboot_entry);
+ break;
+#endif
+ default:
+ _no_return_wfi();
+ break;
+ }
+}
+#endif
+
+#if (SOC_CORE_RELEASE || SOC_CORE_RESTART)
+static void _pwr_domain_wakeup(const psci_power_state_t *target_state)
+{
+ u_register_t core_mask = plat_my_core_mask();
+ u_register_t core_state = _getCoreState(core_mask);
+
+ switch (core_state) {
+ case CORE_PENDING: /* this core is coming out of reset */
+
+ /* soc per cpu setup */
+ soc_init_percpu();
+
+ /* gic per cpu setup */
+ plat_gic_pcpu_init();
+
+ /* set core state in internal data */
+ core_state = CORE_RELEASED;
+ _setCoreState(core_mask, core_state);
+ break;
+
+#if (SOC_CORE_RESTART)
+ case CORE_WAKEUP:
+
+ /* this core is waking up from OFF */
+ _psci_wakeup(core_mask);
+
+ /* set core state in internal data */
+ core_state = CORE_RELEASED;
+ _setCoreState(core_mask, core_state);
+
+ break;
+#endif
+ }
+}
+#endif
+
+#if (SOC_CORE_STANDBY)
+static void _pwr_cpu_standby(plat_local_state_t cpu_state)
+{
+ u_register_t core_mask = plat_my_core_mask();
+ u_register_t core_state;
+
+ if (cpu_state == PLAT_MAX_RET_STATE) {
+
+ /* set core state to standby */
+ core_state = CORE_STANDBY;
+ _setCoreState(core_mask, core_state);
+
+ _psci_core_entr_stdby(core_mask);
+
+ /* when we are here, the core is waking up
+ * set core state to released
+ */
+ core_state = CORE_RELEASED;
+ _setCoreState(core_mask, core_state);
+ }
+}
+#endif
+
+#if (SOC_CORE_PWR_DWN)
+static void _pwr_suspend(const psci_power_state_t *state)
+{
+
+ u_register_t core_mask = plat_my_core_mask();
+ u_register_t core_state;
+
+ if (state->pwr_domain_state[PLAT_MAX_LVL] == PLAT_MAX_OFF_STATE) {
+#if (SOC_SYSTEM_PWR_DWN)
+ _psci_sys_prep_pwrdn(core_mask);
+
+ /* set core state */
+ core_state = SYS_OFF_PENDING;
+ _setCoreState(core_mask, core_state);
+#endif
+ } else if (state->pwr_domain_state[PLAT_MAX_LVL]
+ == PLAT_MAX_RET_STATE) {
+#if (SOC_SYSTEM_STANDBY)
+ _psci_sys_prep_stdby(core_mask);
+
+ /* set core state */
+ core_state = CORE_STANDBY;
+ _setCoreState(core_mask, core_state);
+#endif
+ }
+
+ else if (state->pwr_domain_state[PLAT_CLSTR_LVL] ==
+ PLAT_MAX_OFF_STATE) {
+#if (SOC_CLUSTER_PWR_DWN)
+ _psci_clstr_prep_pwrdn(core_mask);
+
+ /* set core state */
+ core_state = CORE_PWR_DOWN;
+ _setCoreState(core_mask, core_state);
+#endif
+ }
+
+ else if (state->pwr_domain_state[PLAT_CLSTR_LVL] ==
+ PLAT_MAX_RET_STATE) {
+#if (SOC_CLUSTER_STANDBY)
+ _psci_clstr_prep_stdby(core_mask);
+
+ /* set core state */
+ core_state = CORE_STANDBY;
+ _setCoreState(core_mask, core_state);
+#endif
+ }
+
+ else if (state->pwr_domain_state[PLAT_CORE_LVL] == PLAT_MAX_OFF_STATE) {
+#if (SOC_CORE_PWR_DWN)
+ /* prep the core for power-down */
+ _psci_core_prep_pwrdn(core_mask);
+
+ /* set core state */
+ core_state = CORE_PWR_DOWN;
+ _setCoreState(core_mask, core_state);
+#endif
+ }
+
+ else if (state->pwr_domain_state[PLAT_CORE_LVL] == PLAT_MAX_RET_STATE) {
+#if (SOC_CORE_STANDBY)
+ _psci_core_prep_stdby(core_mask);
+
+ /* set core state */
+ core_state = CORE_STANDBY;
+ _setCoreState(core_mask, core_state);
+#endif
+ }
+
+}
+#endif
+
+#if (SOC_CORE_PWR_DWN)
+static void _pwr_suspend_finish(const psci_power_state_t *state)
+{
+
+ u_register_t core_mask = plat_my_core_mask();
+ u_register_t core_state;
+
+
+ if (state->pwr_domain_state[PLAT_MAX_LVL] == PLAT_MAX_OFF_STATE) {
+#if (SOC_SYSTEM_PWR_DWN)
+ _psci_sys_exit_pwrdn(core_mask);
+
+ /* when we are here, the core is back up
+ * set core state to released
+ */
+ core_state = CORE_RELEASED;
+ _setCoreState(core_mask, core_state);
+#endif
+ } else if (state->pwr_domain_state[PLAT_MAX_LVL]
+ == PLAT_MAX_RET_STATE) {
+#if (SOC_SYSTEM_STANDBY)
+ _psci_sys_exit_stdby(core_mask);
+
+ /* when we are here, the core is waking up
+ * set core state to released
+ */
+ core_state = CORE_RELEASED;
+ _setCoreState(core_mask, core_state);
+#endif
+ }
+
+ else if (state->pwr_domain_state[PLAT_CLSTR_LVL] ==
+ PLAT_MAX_OFF_STATE) {
+#if (SOC_CLUSTER_PWR_DWN)
+ _psci_clstr_exit_pwrdn(core_mask);
+
+ /* when we are here, the core is waking up
+ * set core state to released
+ */
+ core_state = CORE_RELEASED;
+ _setCoreState(core_mask, core_state);
+#endif
+ }
+
+ else if (state->pwr_domain_state[PLAT_CLSTR_LVL] ==
+ PLAT_MAX_RET_STATE) {
+#if (SOC_CLUSTER_STANDBY)
+ _psci_clstr_exit_stdby(core_mask);
+
+ /* when we are here, the core is waking up
+ * set core state to released
+ */
+ core_state = CORE_RELEASED;
+ _setCoreState(core_mask, core_state);
+#endif
+ }
+
+ else if (state->pwr_domain_state[PLAT_CORE_LVL] == PLAT_MAX_OFF_STATE) {
+#if (SOC_CORE_PWR_DWN)
+ _psci_core_exit_pwrdn(core_mask);
+
+ /* when we are here, the core is back up
+ * set core state to released
+ */
+ core_state = CORE_RELEASED;
+ _setCoreState(core_mask, core_state);
+#endif
+ }
+
+ else if (state->pwr_domain_state[PLAT_CORE_LVL] == PLAT_MAX_RET_STATE) {
+#if (SOC_CORE_STANDBY)
+ _psci_core_exit_stdby(core_mask);
+
+ /* when we are here, the core is waking up
+ * set core state to released
+ */
+ core_state = CORE_RELEASED;
+ _setCoreState(core_mask, core_state);
+#endif
+ }
+
+}
+#endif
+
+#if (SOC_CORE_STANDBY || SOC_CORE_PWR_DWN)
+
+#define PWR_STATE_TYPE_MASK 0x00010000
+#define PWR_STATE_TYPE_STNDBY 0x0
+#define PWR_STATE_TYPE_PWRDWN 0x00010000
+#define PWR_STATE_LVL_MASK 0x03000000
+#define PWR_STATE_LVL_CORE 0x0
+#define PWR_STATE_LVL_CLSTR 0x01000000
+#define PWR_STATE_LVL_SYS 0x02000000
+#define PWR_STATE_LVL_MAX 0x03000000
+
+ /* turns a requested power state into a target power state
+ * based on SoC capabilities
+ */
+static int _pwr_state_validate(uint32_t pwr_state,
+ psci_power_state_t *state)
+{
+ int stat = PSCI_E_INVALID_PARAMS;
+ int pwrdn = (pwr_state & PWR_STATE_TYPE_MASK);
+ int lvl = (pwr_state & PWR_STATE_LVL_MASK);
+
+ switch (lvl) {
+ case PWR_STATE_LVL_MAX:
+ if (pwrdn && SOC_SYSTEM_PWR_DWN)
+ state->pwr_domain_state[PLAT_MAX_LVL] =
+ PLAT_MAX_OFF_STATE;
+ else if (SOC_SYSTEM_STANDBY)
+ state->pwr_domain_state[PLAT_MAX_LVL] =
+ PLAT_MAX_RET_STATE;
+ /* intentional fall-thru condition */
+ case PWR_STATE_LVL_SYS:
+ if (pwrdn && SOC_SYSTEM_PWR_DWN)
+ state->pwr_domain_state[PLAT_SYS_LVL] =
+ PLAT_MAX_OFF_STATE;
+ else if (SOC_SYSTEM_STANDBY)
+ state->pwr_domain_state[PLAT_SYS_LVL] =
+ PLAT_MAX_RET_STATE;
+ /* intentional fall-thru condition */
+ case PWR_STATE_LVL_CLSTR:
+ if (pwrdn && SOC_CLUSTER_PWR_DWN)
+ state->pwr_domain_state[PLAT_CLSTR_LVL] =
+ PLAT_MAX_OFF_STATE;
+ else if (SOC_CLUSTER_STANDBY)
+ state->pwr_domain_state[PLAT_CLSTR_LVL] =
+ PLAT_MAX_RET_STATE;
+ /* intentional fall-thru condition */
+ case PWR_STATE_LVL_CORE:
+ stat = PSCI_E_SUCCESS;
+
+ if (pwrdn && SOC_CORE_PWR_DWN)
+ state->pwr_domain_state[PLAT_CORE_LVL] =
+ PLAT_MAX_OFF_STATE;
+ else if (SOC_CORE_STANDBY)
+ state->pwr_domain_state[PLAT_CORE_LVL] =
+ PLAT_MAX_RET_STATE;
+ break;
+ }
+ return (stat);
+}
+
+#endif
+
+#if (SOC_SYSTEM_PWR_DWN)
+static void _pwr_state_sys_suspend(psci_power_state_t *req_state)
+{
+
+ /* if we need to have per-SoC settings, then we need to
+ * extend this by calling into psci_utils.S and from there
+ * on down to the SoC.S files
+ */
+
+ req_state->pwr_domain_state[PLAT_MAX_LVL] = PLAT_MAX_OFF_STATE;
+ req_state->pwr_domain_state[PLAT_SYS_LVL] = PLAT_MAX_OFF_STATE;
+ req_state->pwr_domain_state[PLAT_CLSTR_LVL] = PLAT_MAX_OFF_STATE;
+ req_state->pwr_domain_state[PLAT_CORE_LVL] = PLAT_MAX_OFF_STATE;
+
+}
+#endif
+
+#if defined(NXP_WARM_BOOT) && (SOC_SYSTEM_RESET2)
+static int psci_system_reset2(int is_vendor,
+ int reset_type,
+ u_register_t cookie)
+{
+ int ret = 0;
+
+ INFO("Executing the sequence of warm reset.\n");
+ ret = prep_n_execute_warm_reset();
+
+ return ret;
+}
+#endif
+
+static plat_psci_ops_t _psci_pm_ops = {
+#if (SOC_SYSTEM_OFF)
+ .system_off = _psci_system_off,
+#endif
+#if (SOC_SYSTEM_RESET)
+ .system_reset = _psci_system_reset,
+#endif
+#if defined(NXP_WARM_BOOT) && (SOC_SYSTEM_RESET2)
+ .system_reset2 = psci_system_reset2,
+#endif
+#if (SOC_CORE_RELEASE || SOC_CORE_RESTART)
+ /* core released or restarted */
+ .pwr_domain_on_finish = _pwr_domain_wakeup,
+#endif
+#if (SOC_CORE_OFF)
+ /* core shutting down */
+ .pwr_domain_off = _pwr_domain_off,
+#endif
+#if (SOC_CORE_OFF || SOC_CORE_PWR_DWN)
+ .pwr_domain_pwr_down_wfi = _pwr_down_wfi,
+#endif
+#if (SOC_CORE_STANDBY || SOC_CORE_PWR_DWN)
+ /* cpu_suspend */
+ .validate_power_state = _pwr_state_validate,
+#if (SOC_CORE_STANDBY)
+ .cpu_standby = _pwr_cpu_standby,
+#endif
+#if (SOC_CORE_PWR_DWN)
+ .pwr_domain_suspend = _pwr_suspend,
+ .pwr_domain_suspend_finish = _pwr_suspend_finish,
+#endif
+#endif
+#if (SOC_SYSTEM_PWR_DWN)
+ .get_sys_suspend_power_state = _pwr_state_sys_suspend,
+#endif
+#if (SOC_CORE_RELEASE)
+ /* core executing psci_cpu_on */
+ .pwr_domain_on = _pwr_domain_on
+#endif
+};
+
+#if (SOC_CORE_RELEASE || SOC_CORE_PWR_DWN)
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const plat_psci_ops_t **psci_ops)
+{
+ warmboot_entry = sec_entrypoint;
+ *psci_ops = &_psci_pm_ops;
+ return 0;
+}
+
+#else
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const plat_psci_ops_t **psci_ops)
+{
+ *psci_ops = &_psci_pm_ops;
+ return 0;
+}
+#endif
diff --git a/plat/nxp/common/psci/psci.mk b/plat/nxp/common/psci/psci.mk
new file mode 100644
index 0000000..a2791c2
--- /dev/null
+++ b/plat/nxp/common/psci/psci.mk
@@ -0,0 +1,35 @@
+#
+# Copyright 2018-2020 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+#------------------------------------------------------------------------------
+#
+# Select the PSCI files
+#
+# -----------------------------------------------------------------------------
+
+ifeq (${ADD_PSCI},)
+
+ADD_PSCI := 1
+PLAT_PSCI_PATH := $(PLAT_COMMON_PATH)/psci
+
+PSCI_SOURCES := ${PLAT_PSCI_PATH}/plat_psci.c \
+ ${PLAT_PSCI_PATH}/$(ARCH)/psci_utils.S \
+ plat/common/plat_psci_common.c
+
+PLAT_INCLUDES += -I${PLAT_PSCI_PATH}/include
+
+ifeq (${BL_COMM_PSCI_NEEDED},yes)
+BL_COMMON_SOURCES += ${PSCI_SOURCES}
+else
+ifeq (${BL2_PSCI_NEEDED},yes)
+BL2_SOURCES += ${PSCI_SOURCES}
+endif
+ifeq (${BL31_PSCI_NEEDED},yes)
+BL31_SOURCES += ${PSCI_SOURCES}
+endif
+endif
+endif
+# -----------------------------------------------------------------------------
diff --git a/plat/nxp/common/setup/aarch64/ls_bl2_mem_params_desc.c b/plat/nxp/common/setup/aarch64/ls_bl2_mem_params_desc.c
new file mode 100644
index 0000000..7463d47
--- /dev/null
+++ b/plat/nxp/common/setup/aarch64/ls_bl2_mem_params_desc.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#ifdef CSF_HEADER_PREPENDED
+#include <csf_hdr.h>
+#endif
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+/*******************************************************************************
+ * 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 = LS_BL31_PLAT_PARAM_VAL,
+#endif
+
+ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+ VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP),
+#ifdef CSF_HEADER_PREPENDED
+ .image_info.image_base = BL31_BASE - CSF_HDR_SZ,
+ .image_info.image_max_size = (BL31_LIMIT - BL31_BASE) +
+ CSF_HDR_SZ,
+#else
+ .image_info.image_base = BL31_BASE,
+ .image_info.image_max_size = (BL31_LIMIT - BL31_BASE),
+#endif
+
+# ifdef NXP_LOAD_BL32
+ .next_handoff_image_id = BL32_IMAGE_ID,
+# else
+ .next_handoff_image_id = BL33_IMAGE_ID,
+# endif
+ },
+# ifdef NXP_LOAD_BL32
+ /* 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),
+#ifdef CSF_HEADER_PREPENDED
+ .image_info.image_base = BL32_BASE - CSF_HDR_SZ,
+ .image_info.image_max_size = (BL32_LIMIT - BL32_BASE) +
+ CSF_HDR_SZ,
+#else
+ .image_info.image_base = BL32_BASE,
+ .image_info.image_max_size = (BL32_LIMIT - BL32_BASE),
+#endif
+ .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),
+ .ep_info.pc = BL33_BASE,
+
+ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+ VERSION_2, image_info_t, 0),
+#ifdef CSF_HEADER_PREPENDED
+ .image_info.image_base = BL33_BASE - CSF_HDR_SZ,
+ .image_info.image_max_size = (BL33_LIMIT - BL33_BASE) +
+ CSF_HDR_SZ,
+#else
+ .image_info.image_base = BL33_BASE,
+ .image_info.image_max_size = BL33_LIMIT - BL33_BASE,
+#endif
+ .ep_info.spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS),
+
+ .next_handoff_image_id = INVALID_IMAGE_ID,
+ }
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
diff --git a/plat/nxp/common/setup/common.mk b/plat/nxp/common/setup/common.mk
new file mode 100644
index 0000000..1fcf1d0
--- /dev/null
+++ b/plat/nxp/common/setup/common.mk
@@ -0,0 +1,105 @@
+#
+# Copyright 2018-2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+
+###############################################################################
+# Flow begins in BL2 at EL3 mode
+BL2_AT_EL3 := 1
+
+# Though one core is powered up by default, there are
+# platform specific ways to release more than one core
+COLD_BOOT_SINGLE_CPU := 0
+
+PROGRAMMABLE_RESET_ADDRESS := 1
+
+USE_COHERENT_MEM := 0
+
+# Use generic OID definition (tbbr_oid.h)
+USE_TBBR_DEFS := 1
+
+PLAT_XLAT_TABLES_DYNAMIC := 0
+
+ENABLE_SVE_FOR_NS := 0
+
+ENABLE_STACK_PROTECTOR := 0
+
+ERROR_DEPRECATED := 0
+
+LS_DISABLE_TRUSTED_WDOG := 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
+
+# Enable new version of image loading on ARM platforms
+LOAD_IMAGE_V2 := 1
+
+RCW := ""
+
+ifneq (${SPD},none)
+$(eval $(call add_define, NXP_LOAD_BL32))
+endif
+
+###############################################################################
+
+PLAT_TOOL_PATH := tools/nxp
+CREATE_PBL_TOOL_PATH := ${PLAT_TOOL_PATH}/create_pbl
+PLAT_SETUP_PATH := ${PLAT_PATH}/common/setup
+
+PLAT_INCLUDES += -I${PLAT_SETUP_PATH}/include \
+ -Iinclude/plat/arm/common \
+ -Iinclude/drivers/arm \
+ -Iinclude/lib \
+ -Iinclude/drivers/io \
+ -Ilib/psci
+
+# Required without TBBR.
+# To include the defines for DDR PHY Images.
+PLAT_INCLUDES += -Iinclude/common/tbbr
+
+include ${PLAT_SETUP_PATH}/core.mk
+PLAT_BL_COMMON_SOURCES += ${CPU_LIBS} \
+ plat/nxp/common/setup/ls_err.c \
+ plat/nxp/common/setup/ls_common.c
+
+ifneq (${ENABLE_STACK_PROTECTOR},0)
+PLAT_BL_COMMON_SOURCES += ${PLAT_SETUP_PATH}/ls_stack_protector.c
+endif
+
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS}
+
+BL2_SOURCES += drivers/io/io_fip.c \
+ drivers/io/io_memmap.c \
+ drivers/io/io_storage.c \
+ common/desc_image_load.c \
+ plat/nxp/common/setup/ls_image_load.c \
+ plat/nxp/common/setup/ls_io_storage.c \
+ plat/nxp/common/setup/ls_bl2_el3_setup.c \
+ plat/nxp/common/setup/${ARCH}/ls_bl2_mem_params_desc.c
+
+BL31_SOURCES += plat/nxp/common/setup/ls_bl31_setup.c \
+
+ifeq (${LS_EL3_INTERRUPT_HANDLER}, yes)
+$(eval $(call add_define, LS_EL3_INTERRUPT_HANDLER))
+BL31_SOURCES += plat/nxp/common/setup/ls_interrupt_mgmt.c
+endif
+
+ifeq (${TEST_BL31}, 1)
+BL31_SOURCES += ${TEST_SOURCES}
+endif
+
+# Verify build config
+# -------------------
+
+ifneq (${LOAD_IMAGE_V2}, 1)
+ $(error Error: Layerscape needs LOAD_IMAGE_V2=1)
+else
+$(eval $(call add_define,LOAD_IMAGE_V2))
+endif
+
+include $(CREATE_PBL_TOOL_PATH)/create_pbl.mk
diff --git a/plat/nxp/common/setup/core.mk b/plat/nxp/common/setup/core.mk
new file mode 100644
index 0000000..82ce30e
--- /dev/null
+++ b/plat/nxp/common/setup/core.mk
@@ -0,0 +1,22 @@
+# Copyright 2018-2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+#------------------------------------------------------------------------------
+#
+# Select the CORE files
+#
+# -----------------------------------------------------------------------------
+
+CPU_LIBS := lib/cpus/${ARCH}/aem_generic.S
+
+ifeq (,$(filter $(CORE_TYPE),a53 a72))
+$(error "CORE_TYPE not specified or incorrect")
+else
+UPPER_CORE_TYPE=$(shell echo $(CORE_TYPE) | tr a-z A-Z)
+$(eval $(call add_define_val,CPUECTLR_EL1,CORTEX_$(UPPER_CORE_TYPE)_ECTLR_EL1))
+CPU_LIBS += lib/cpus/${ARCH}/cortex_$(CORE_TYPE).S
+endif
+
+# -----------------------------------------------------------------------------
diff --git a/plat/nxp/common/setup/include/bl31_data.h b/plat/nxp/common/setup/include/bl31_data.h
new file mode 100644
index 0000000..dd20d43
--- /dev/null
+++ b/plat/nxp/common/setup/include/bl31_data.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef BL31_DATA_H
+#define BL31_DATA_H
+
+#define SECURE_DATA_BASE NXP_OCRAM_ADDR
+#define SECURE_DATA_SIZE NXP_OCRAM_SIZE
+#define SECURE_DATA_TOP (SECURE_DATA_BASE + SECURE_DATA_SIZE)
+#define SMC_REGION_SIZE 0x80
+#define SMC_GLBL_BASE (SECURE_DATA_TOP - SMC_REGION_SIZE)
+#define BC_PSCI_DATA_SIZE 0xC0
+#define BC_PSCI_BASE (SMC_GLBL_BASE - BC_PSCI_DATA_SIZE)
+#define SECONDARY_TOP BC_PSCI_BASE
+
+#define SEC_PSCI_DATA_SIZE 0xC0
+#define SEC_REGION_SIZE SEC_PSCI_DATA_SIZE
+
+/* SMC global data */
+#define BOOTLOC_OFFSET 0x0
+#define BOOT_SVCS_OSET 0x8
+
+/* offset to prefetch disable mask */
+#define PREFETCH_DIS_OFFSET 0x10
+/* must reference last smc global entry */
+#define LAST_SMC_GLBL_OFFSET 0x18
+
+#define SMC_TASK_OFFSET 0xC
+#define TSK_START_OFFSET 0x0
+#define TSK_DONE_OFFSET 0x4
+#define TSK_CORE_OFFSET 0x8
+#define SMC_TASK1_BASE (SMC_GLBL_BASE + 32)
+#define SMC_TASK2_BASE (SMC_TASK1_BASE + SMC_TASK_OFFSET)
+#define SMC_TASK3_BASE (SMC_TASK2_BASE + SMC_TASK_OFFSET)
+#define SMC_TASK4_BASE (SMC_TASK3_BASE + SMC_TASK_OFFSET)
+
+/* psci data area offsets */
+#define CORE_STATE_DATA 0x0
+#define SPSR_EL3_DATA 0x8
+#define CNTXT_ID_DATA 0x10
+#define START_ADDR_DATA 0x18
+#define LINK_REG_DATA 0x20
+#define GICC_CTLR_DATA 0x28
+#define ABORT_FLAG_DATA 0x30
+#define SCTLR_DATA 0x38
+#define CPUECTLR_DATA 0x40
+#define AUX_01_DATA 0x48 /* usage defined per SoC */
+#define AUX_02_DATA 0x50 /* usage defined per SoC */
+#define AUX_03_DATA 0x58 /* usage defined per SoC */
+#define AUX_04_DATA 0x60 /* usage defined per SoC */
+#define AUX_05_DATA 0x68 /* usage defined per SoC */
+#define AUX_06_DATA 0x70 /* usage defined per SoC */
+#define AUX_07_DATA 0x78 /* usage defined per SoC */
+#define SCR_EL3_DATA 0x80
+#define HCR_EL2_DATA 0x88
+
+#endif /* BL31_DATA_H */
diff --git a/plat/nxp/common/setup/include/ls_interrupt_mgmt.h b/plat/nxp/common/setup/include/ls_interrupt_mgmt.h
new file mode 100644
index 0000000..7dbddfb
--- /dev/null
+++ b/plat/nxp/common/setup/include/ls_interrupt_mgmt.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef LS_EL3_INTRPT_MGMT_H
+#define LS_EL3_INTRPT_MGMT_H
+
+#include <bl31/interrupt_mgmt.h>
+
+#define MAX_INTR_EL3 128
+
+/*
+ * Register handler to specific GIC entrance
+ * for INTR_TYPE_EL3 type of interrupt
+ */
+int request_intr_type_el3(uint32_t id, interrupt_type_handler_t handler);
+
+void ls_el3_interrupt_config(void);
+
+#endif /* LS_EL3_INTRPT_MGMT_H */
diff --git a/plat/nxp/common/setup/include/mmu_def.h b/plat/nxp/common/setup/include/mmu_def.h
new file mode 100644
index 0000000..2a7771b
--- /dev/null
+++ b/plat/nxp/common/setup/include/mmu_def.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef MMU_MAP_DEF_H
+#define MMU_MAP_DEF_H
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#include <platform_def.h>
+
+
+#define LS_MAP_CCSR MAP_REGION_FLAT(NXP_CCSR_ADDR, \
+ NXP_CCSR_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+#ifdef NXP_DCSR_ADDR
+#define LS_MAP_DCSR MAP_REGION_FLAT(NXP_DCSR_ADDR, \
+ NXP_DCSR_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+#endif
+
+#define LS_MAP_CONSOLE MAP_REGION_FLAT(NXP_DUART1_ADDR, \
+ NXP_DUART_SIZE, \
+ MT_DEVICE | MT_RW | MT_NS)
+
+#define LS_MAP_OCRAM MAP_REGION_FLAT(NXP_OCRAM_ADDR, \
+ NXP_OCRAM_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+#endif /* MMU_MAP_DEF_H */
diff --git a/plat/nxp/common/setup/include/plat_common.h b/plat/nxp/common/setup/include/plat_common.h
new file mode 100644
index 0000000..e13f45c
--- /dev/null
+++ b/plat/nxp/common/setup/include/plat_common.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PLAT_COMMON_H
+#define PLAT_COMMON_H
+
+#include <stdbool.h>
+
+#include <dcfg.h>
+#include <lib/el3_runtime/cpu_data.h>
+
+#include <platform_def.h>
+
+#ifdef IMAGE_BL31
+
+#define BL31_END (uintptr_t)(&__BL31_END__)
+
+/*******************************************************************************
+ * This structure represents the superset of information that can be passed to
+ * BL31 e.g. while passing control to it from BL2. The BL32 parameters will be
+ * populated only if BL2 detects its presence. A pointer to a structure of this
+ * type should be passed in X0 to BL31's cold boot entrypoint.
+ *
+ * Use of this structure and the X0 parameter is not mandatory: the BL31
+ * platform code can use other mechanisms to provide the necessary information
+ * about BL32 and BL33 to the common and SPD code.
+ *
+ * BL31 image information is mandatory if this structure is used. If either of
+ * the optional BL32 and BL33 image information is not provided, this is
+ * indicated by the respective image_info pointers being zero.
+ ******************************************************************************/
+typedef struct 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;
+} bl31_params_t;
+
+/* BL3 utility functions */
+void ls_bl31_early_platform_setup(void *from_bl2,
+ void *plat_params_from_bl2);
+/* LS Helper functions */
+unsigned int plat_my_core_mask(void);
+unsigned int plat_core_mask(u_register_t mpidr);
+unsigned int plat_core_pos(u_register_t mpidr);
+//unsigned int plat_my_core_pos(void);
+
+/* BL31 Data API(s) */
+void _init_global_data(void);
+void _initialize_psci(void);
+uint32_t _getCoreState(u_register_t core_mask);
+void _setCoreState(u_register_t core_mask, u_register_t core_state);
+
+/* SoC defined structure and API(s) */
+void soc_runtime_setup(void);
+void soc_init(void);
+void soc_platform_setup(void);
+void soc_early_platform_setup2(void);
+#endif /* IMAGE_BL31 */
+
+#ifdef IMAGE_BL2
+void soc_early_init(void);
+void soc_mem_access(void);
+void soc_preload_setup(void);
+void soc_bl2_prepare_exit(void);
+
+/* IO storage utility functions */
+int plat_io_setup(void);
+int open_backend(const uintptr_t spec);
+
+void ls_bl2_plat_arch_setup(void);
+void ls_bl2_el3_plat_arch_setup(void);
+
+enum boot_device {
+ BOOT_DEVICE_IFC_NOR,
+ BOOT_DEVICE_IFC_NAND,
+ BOOT_DEVICE_QSPI,
+ BOOT_DEVICE_EMMC,
+ BOOT_DEVICE_SDHC2_EMMC,
+ BOOT_DEVICE_FLEXSPI_NOR,
+ BOOT_DEVICE_FLEXSPI_NAND,
+ BOOT_DEVICE_NONE
+};
+
+enum boot_device get_boot_dev(void);
+
+/* DDR Related functions */
+#if DDR_INIT
+#ifdef NXP_WARM_BOOT
+long long init_ddr(uint32_t wrm_bt_flg);
+#else
+long long init_ddr(void);
+#endif
+#endif
+
+/* Board specific weak functions */
+bool board_enable_povdd(void);
+bool board_disable_povdd(void);
+
+void mmap_add_ddr_region_dynamically(void);
+#endif /* IMAGE_BL2 */
+
+typedef struct {
+ uint64_t addr;
+ uint64_t size;
+} region_info_t;
+
+typedef struct {
+ uint64_t num_dram_regions;
+ int64_t total_dram_size;
+ region_info_t region[NUM_DRAM_REGIONS];
+} dram_regions_info_t;
+
+dram_regions_info_t *get_dram_regions_info(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
+);
+
+#define SOC_NAME_MAX_LEN (20)
+
+/* Structure to define SoC personality */
+struct soc_type {
+ char name[SOC_NAME_MAX_LEN];
+ uint32_t version;
+ uint8_t num_clusters;
+ uint8_t cores_per_cluster;
+};
+void get_cluster_info(const struct soc_type *soc_list, uint8_t ps_count,
+ uint8_t *num_clusters, uint8_t *cores_per_cluster);
+
+#define SOC_ENTRY(n, v, ncl, nc) { \
+ .name = #n, \
+ .version = SVR_##v, \
+ .num_clusters = (ncl), \
+ .cores_per_cluster = (nc)}
+
+#endif /* PLAT_COMMON_H */
diff --git a/plat/nxp/common/setup/include/plat_macros.S b/plat/nxp/common/setup/include/plat_macros.S
new file mode 100644
index 0000000..69a3b08
--- /dev/null
+++ b/plat/nxp/common/setup/include/plat_macros.S
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * 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 */
diff --git a/plat/nxp/common/setup/ls_bl2_el3_setup.c b/plat/nxp/common/setup/ls_bl2_el3_setup.c
new file mode 100644
index 0000000..a4cbaef
--- /dev/null
+++ b/plat/nxp/common/setup/ls_bl2_el3_setup.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+
+#include <common/desc_image_load.h>
+#include <dcfg.h>
+#ifdef POLICY_FUSE_PROVISION
+#include <fuse_io.h>
+#endif
+#include <mmu_def.h>
+#include <plat_common.h>
+#ifdef NXP_NV_SW_MAINT_LAST_EXEC_DATA
+#include <plat_nv_storage.h>
+#endif
+
+#pragma weak bl2_el3_early_platform_setup
+#pragma weak bl2_el3_plat_arch_setup
+#pragma weak bl2_el3_plat_prepare_exit
+
+static dram_regions_info_t dram_regions_info = {0};
+
+/*******************************************************************************
+ * Return the pointer to the 'dram_regions_info structure of the DRAM.
+ * This structure is populated after init_ddr().
+ ******************************************************************************/
+dram_regions_info_t *get_dram_regions_info(void)
+{
+ return &dram_regions_info;
+}
+
+#ifdef DDR_INIT
+static void populate_dram_regions_info(void)
+{
+ long long dram_remain_size = dram_regions_info.total_dram_size;
+ uint8_t reg_id = 0U;
+
+ dram_regions_info.region[reg_id].addr = NXP_DRAM0_ADDR;
+ dram_regions_info.region[reg_id].size =
+ dram_remain_size > NXP_DRAM0_MAX_SIZE ?
+ NXP_DRAM0_MAX_SIZE : dram_remain_size;
+
+ if (dram_regions_info.region[reg_id].size != NXP_DRAM0_SIZE) {
+ ERROR("Incorrect DRAM0 size is defined in platform_def.h\n");
+ }
+
+ dram_remain_size -= dram_regions_info.region[reg_id].size;
+ dram_regions_info.region[reg_id].size -= (NXP_SECURE_DRAM_SIZE
+ + NXP_SP_SHRD_DRAM_SIZE);
+
+ assert(dram_regions_info.region[reg_id].size > 0);
+
+ /* Reducing total dram size by 66MB */
+ dram_regions_info.total_dram_size -= (NXP_SECURE_DRAM_SIZE
+ + NXP_SP_SHRD_DRAM_SIZE);
+
+#if defined(NXP_DRAM1_ADDR) && defined(NXP_DRAM1_MAX_SIZE)
+ if (dram_remain_size > 0) {
+ reg_id++;
+ dram_regions_info.region[reg_id].addr = NXP_DRAM1_ADDR;
+ dram_regions_info.region[reg_id].size =
+ dram_remain_size > NXP_DRAM1_MAX_SIZE ?
+ NXP_DRAM1_MAX_SIZE : dram_remain_size;
+ dram_remain_size -= dram_regions_info.region[reg_id].size;
+ }
+#endif
+#if defined(NXP_DRAM2_ADDR) && defined(NXP_DRAM2_MAX_SIZE)
+ if (dram_remain_size > 0) {
+ reg_id++;
+ dram_regions_info.region[reg_id].addr = NXP_DRAM1_ADDR;
+ dram_regions_info.region[reg_id].size =
+ dram_remain_size > NXP_DRAM1_MAX_SIZE ?
+ NXP_DRAM1_MAX_SIZE : dram_remain_size;
+ dram_remain_size -= dram_regions_info.region[reg_id].size;
+ }
+#endif
+ reg_id++;
+ dram_regions_info.num_dram_regions = reg_id;
+}
+#endif
+
+#ifdef IMAGE_BL32
+/*******************************************************************************
+ * Gets SPSR for BL32 entry
+ ******************************************************************************/
+static 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 0U;
+}
+#endif
+
+/*******************************************************************************
+ * Gets SPSR for BL33 entry
+ ******************************************************************************/
+#ifndef AARCH32
+static 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
+ ******************************************************************************/
+static 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 /* AARCH32 */
+
+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)
+{
+ /*
+ * SoC specific early init
+ * Any errata handling or SoC specific early initialization can
+ * be done here
+ * Set Counter Base Frequency in CNTFID0 and in cntfrq_el0.
+ * Initialize the interconnect.
+ * Enable coherency for primary CPU cluster
+ */
+ soc_early_init();
+
+ /* Initialise the IO layer and register platform IO devices */
+ plat_io_setup();
+
+ if (dram_regions_info.total_dram_size > 0) {
+ populate_dram_regions_info();
+ }
+
+#ifdef NXP_NV_SW_MAINT_LAST_EXEC_DATA
+ read_nv_app_data();
+#if DEBUG
+ const nv_app_data_t *nv_app_data = get_nv_data();
+
+ INFO("Value of warm_reset flag = 0x%x\n", nv_app_data->warm_rst_flag);
+ INFO("Value of WDT flag = 0x%x\n", nv_app_data->wdt_rst_flag);
+#endif
+#endif
+}
+
+/*******************************************************************************
+ * 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_el3_plat_arch_setup(void)
+{
+ unsigned int flags = 0U;
+ /* Initialise the IO layer and register platform IO devices */
+ ls_setup_page_tables(
+#if SEPARATE_BL2_NOLOAD_REGION
+ BL2_START,
+ BL2_LIMIT - BL2_START,
+#else
+ BL2_BASE,
+ (unsigned long)(&__BL2_END__) - BL2_BASE,
+#endif
+ 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 ((dram_regions_info.region[0].addr == 0)
+ && (dram_regions_info.total_dram_size == 0)) {
+ flags = XLAT_TABLE_NC;
+ }
+
+#ifdef AARCH32
+ enable_mmu_secure(0);
+#else
+ enable_mmu_el3(flags);
+#endif
+}
+
+void bl2_el3_plat_arch_setup(void)
+{
+ ls_bl2_el3_plat_arch_setup();
+}
+
+void bl2_platform_setup(void)
+{
+ /*
+ * Perform platform setup before loading the image.
+ */
+}
+
+/* Handling image information by platform. */
+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) {
+ case BL31_IMAGE_ID:
+ bl_mem_params->ep_info.args.arg3 =
+ (u_register_t) &dram_regions_info;
+
+ /* Pass the value of PORSR1 register in Argument 4 */
+ bl_mem_params->ep_info.args.arg4 =
+ (u_register_t)read_reg_porsr1();
+ flush_dcache_range((uintptr_t)&dram_regions_info,
+ sizeof(dram_regions_info));
+ break;
+#if defined(AARCH64) && defined(IMAGE_BL32)
+ 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);
+}
+
+void bl2_el3_plat_prepare_exit(void)
+{
+ return soc_bl2_prepare_exit();
+}
+
+/* Called to do the dynamic initialization required
+ * before loading the next image.
+ */
+void bl2_plat_preload_setup(void)
+{
+
+ soc_preload_setup();
+
+#ifdef DDR_INIT
+ if (dram_regions_info.total_dram_size <= 0) {
+ ERROR("Asserting as the DDR is not initialized yet.");
+ assert(false);
+ }
+#endif
+
+ if ((dram_regions_info.region[0].addr == 0)
+ && (dram_regions_info.total_dram_size > 0)) {
+ populate_dram_regions_info();
+#ifdef PLAT_XLAT_TABLES_DYNAMIC
+ mmap_add_ddr_region_dynamically();
+#endif
+ }
+
+ /* setup the memory region access permissions */
+ soc_mem_access();
+
+#ifdef POLICY_FUSE_PROVISION
+ fip_fuse_provisioning((uintptr_t)FUSE_BUF, FUSE_SZ);
+#endif
+}
diff --git a/plat/nxp/common/setup/ls_bl31_setup.c b/plat/nxp/common/setup/ls_bl31_setup.c
new file mode 100644
index 0000000..bd0ab4f
--- /dev/null
+++ b/plat/nxp/common/setup/ls_bl31_setup.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+#ifdef LS_EL3_INTERRUPT_HANDLER
+#include <ls_interrupt_mgmt.h>
+#endif
+#include <mmu_def.h>
+#include <plat_common.h>
+
+/*
+ * Placeholder variables for copying the arguments that have been passed to
+ * BL31 from BL2.
+ */
+#ifdef TEST_BL31
+#define SPSR_FOR_EL2H 0x3C9
+#define SPSR_FOR_EL1H 0x3C5
+#else
+static entry_point_info_t bl31_image_ep_info;
+#endif
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+static dram_regions_info_t dram_regions_info = {0};
+static uint64_t rcw_porsr1;
+
+/* Return the pointer to the 'dram_regions_info structure of the DRAM.
+ * This structure is populated after init_ddr().
+ */
+dram_regions_info_t *get_dram_regions_info(void)
+{
+ return &dram_regions_info;
+}
+
+/* Return the RCW.PORSR1 value which was passed in from BL2
+ */
+uint64_t bl31_get_porsr1(void)
+{
+ return rcw_porsr1;
+}
+
+/*
+ * Return 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;
+
+#ifdef TEST_BL31
+ next_image_info->pc = _get_test_entry();
+ next_image_info->spsr = SPSR_FOR_EL2H;
+ next_image_info->h.attr = NON_SECURE;
+#endif
+
+ if (next_image_info->pc != 0U) {
+ return next_image_info;
+ } else {
+ return NULL;
+ }
+}
+
+/*
+ * Perform any BL31 early platform setup common to NXP platforms.
+ * - 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, in order to fetch latest data.
+ */
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3)
+{
+#ifndef TEST_BL31
+ int i = 0;
+ void *from_bl2 = (void *)arg0;
+#endif
+ soc_early_platform_setup2();
+
+#ifdef TEST_BL31
+ dram_regions_info.num_dram_regions = 2;
+ dram_regions_info.total_dram_size = 0x100000000;
+ dram_regions_info.region[0].addr = 0x80000000;
+ dram_regions_info.region[0].size = 0x80000000;
+ dram_regions_info.region[1].addr = 0x880000000;
+ dram_regions_info.region[1].size = 0x80000000;
+
+ bl33_image_ep_info.pc = _get_test_entry();
+#else
+ /*
+ * 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 == BL31_IMAGE_ID) {
+ bl31_image_ep_info = *bl_params->ep_info;
+ dram_regions_info_t *loc_dram_regions_info =
+ (dram_regions_info_t *) bl31_image_ep_info.args.arg3;
+
+ dram_regions_info.num_dram_regions =
+ loc_dram_regions_info->num_dram_regions;
+ dram_regions_info.total_dram_size =
+ loc_dram_regions_info->total_dram_size;
+ VERBOSE("Number of DRAM Regions = %" PRIx64 "\n",
+ dram_regions_info.num_dram_regions);
+
+ for (i = 0; i < dram_regions_info.num_dram_regions;
+ i++) {
+ dram_regions_info.region[i].addr =
+ loc_dram_regions_info->region[i].addr;
+ dram_regions_info.region[i].size =
+ loc_dram_regions_info->region[i].size;
+ VERBOSE("DRAM%d Size = %" PRIx64 "\n", i,
+ dram_regions_info.region[i].size);
+ }
+ rcw_porsr1 = bl31_image_ep_info.args.arg4;
+ }
+
+ 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 /* TEST_BL31 */
+
+ if (bl33_image_ep_info.pc == 0) {
+ panic();
+ }
+
+ /*
+ * perform basic initialization on the soc
+ */
+ soc_init();
+}
+
+/*******************************************************************************
+ * Perform any BL31 platform setup common to ARM standard platforms
+ ******************************************************************************/
+void bl31_platform_setup(void)
+{
+ NOTICE("Welcome to %s BL31 Phase\n", BOARD);
+ soc_platform_setup();
+
+ /* Console logs gone missing as part going to
+ * EL1 for initilizing Bl32 if present.
+ * console flush is necessary to avoid it.
+ */
+ (void)console_flush();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+#ifdef LS_EL3_INTERRUPT_HANDLER
+ ls_el3_interrupt_config();
+#endif
+ soc_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 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);
+}
diff --git a/plat/nxp/common/setup/ls_common.c b/plat/nxp/common/setup/ls_common.c
new file mode 100644
index 0000000..28d6b72
--- /dev/null
+++ b/plat/nxp/common/setup/ls_common.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <mmu_def.h>
+#include <plat/common/platform.h>
+
+#include "plat_common.h"
+#include "platform_def.h"
+
+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 arm_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_BL2
+const mmap_region_t plat_ls_mmap[] = {
+ LS_MAP_CCSR,
+ {0}
+};
+#endif
+
+#ifdef IMAGE_BL31
+const mmap_region_t plat_ls_mmap[] = {
+ LS_MAP_CCSR,
+#ifdef NXP_DCSR_ADDR
+ LS_MAP_DCSR,
+#endif
+ LS_MAP_OCRAM,
+ {0}
+};
+#endif
+#ifdef IMAGE_BL32
+const mmap_region_t plat_ls_mmap[] = {
+ LS_MAP_CCSR,
+ LS_MAP_BL32_SEC_MEM,
+ {0}
+};
+#endif
+
+/* Weak definitions may be overridden in specific NXP SoC */
+#pragma weak plat_get_ns_image_entrypoint
+#pragma weak plat_ls_get_mmap
+
+#if defined(IMAGE_BL31) || !defined(CONFIG_DDR_FIP_IMAGE)
+static void mmap_add_ddr_regions_statically(void)
+{
+ int i = 0;
+ dram_regions_info_t *info_dram_regions = get_dram_regions_info();
+ /* MMU map for Non-Secure DRAM Regions */
+ VERBOSE("DRAM Region %d: %p - %p\n", i,
+ (void *) info_dram_regions->region[i].addr,
+ (void *) (info_dram_regions->region[i].addr
+ + info_dram_regions->region[i].size
+ - 1));
+ mmap_add_region(info_dram_regions->region[i].addr,
+ info_dram_regions->region[i].addr,
+ info_dram_regions->region[i].size,
+ MT_MEMORY | MT_RW | MT_NS);
+
+ /* MMU map for Secure DDR Region on DRAM-0 */
+ if (info_dram_regions->region[i].size >
+ (NXP_SECURE_DRAM_SIZE + NXP_SP_SHRD_DRAM_SIZE)) {
+ VERBOSE("Secure DRAM Region %d: %p - %p\n", i,
+ (void *) (info_dram_regions->region[i].addr
+ + info_dram_regions->region[i].size),
+ (void *) (info_dram_regions->region[i].addr
+ + info_dram_regions->region[i].size
+ + NXP_SECURE_DRAM_SIZE
+ + NXP_SP_SHRD_DRAM_SIZE
+ - 1));
+ mmap_add_region((info_dram_regions->region[i].addr
+ + info_dram_regions->region[i].size),
+ (info_dram_regions->region[i].addr
+ + info_dram_regions->region[i].size),
+ (NXP_SECURE_DRAM_SIZE + NXP_SP_SHRD_DRAM_SIZE),
+ MT_MEMORY | MT_RW | MT_SECURE);
+ }
+
+#ifdef IMAGE_BL31
+ for (i = 1; i < info_dram_regions->num_dram_regions; i++) {
+ if (info_dram_regions->region[i].size == 0)
+ break;
+ VERBOSE("DRAM Region %d: %p - %p\n", i,
+ (void *) info_dram_regions->region[i].addr,
+ (void *) (info_dram_regions->region[i].addr
+ + info_dram_regions->region[i].size
+ - 1));
+ mmap_add_region(info_dram_regions->region[i].addr,
+ info_dram_regions->region[i].addr,
+ info_dram_regions->region[i].size,
+ MT_MEMORY | MT_RW | MT_NS);
+ }
+#endif
+}
+#endif
+
+#if defined(PLAT_XLAT_TABLES_DYNAMIC)
+void mmap_add_ddr_region_dynamically(void)
+{
+ int ret, i = 0;
+
+ dram_regions_info_t *info_dram_regions = get_dram_regions_info();
+ /* MMU map for Non-Secure DRAM Regions */
+ VERBOSE("DRAM Region %d: %p - %p\n", i,
+ (void *) info_dram_regions->region[i].addr,
+ (void *) (info_dram_regions->region[i].addr
+ + info_dram_regions->region[i].size
+ - 1));
+ ret = mmap_add_dynamic_region(info_dram_regions->region[i].addr,
+ info_dram_regions->region[i].addr,
+ info_dram_regions->region[i].size,
+ MT_MEMORY | MT_RW | MT_NS);
+ if (ret != 0) {
+ ERROR("Failed to add dynamic memory region\n");
+ panic();
+ }
+
+ /* MMU map for Secure DDR Region on DRAM-0 */
+ if (info_dram_regions->region[i].size >
+ (NXP_SECURE_DRAM_SIZE + NXP_SP_SHRD_DRAM_SIZE)) {
+ VERBOSE("Secure DRAM Region %d: %p - %p\n", i,
+ (void *) (info_dram_regions->region[i].addr
+ + info_dram_regions->region[i].size),
+ (void *) (info_dram_regions->region[i].addr
+ + info_dram_regions->region[i].size
+ + NXP_SECURE_DRAM_SIZE
+ + NXP_SP_SHRD_DRAM_SIZE
+ - 1));
+ ret = mmap_add_dynamic_region((info_dram_regions->region[i].addr
+ + info_dram_regions->region[i].size),
+ (info_dram_regions->region[i].addr
+ + info_dram_regions->region[i].size),
+ (NXP_SECURE_DRAM_SIZE + NXP_SP_SHRD_DRAM_SIZE),
+ MT_MEMORY | MT_RW | MT_SECURE);
+ if (ret != 0) {
+ ERROR("Failed to add dynamic memory region\n");
+ panic();
+ }
+ }
+
+#ifdef IMAGE_BL31
+ for (i = 1; i < info_dram_regions->num_dram_regions; i++) {
+ if (info_dram_regions->region[i].size == 0) {
+ break;
+ }
+ VERBOSE("DRAM Region %d: %p - %p\n", i,
+ (void *) info_dram_regions->region[i].addr,
+ (void *) (info_dram_regions->region[i].addr
+ + info_dram_regions->region[i].size
+ - 1));
+ ret = mmap_add_dynamic_region(info_dram_regions->region[i].addr,
+ info_dram_regions->region[i].addr,
+ info_dram_regions->region[i].size,
+ MT_MEMORY | MT_RW | MT_NS);
+ if (ret != 0) {
+ ERROR("Failed to add dynamic memory region\n");
+ panic();
+ }
+ }
+#endif
+}
+#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
+ )
+{
+ /*
+ * Map the Trusted SRAM with appropriate memory attributes.
+ * Subsequent mappings will adjust the attributes for specific regions.
+ */
+ VERBOSE("Memory 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_ls_get_mmap());
+
+
+#if defined(IMAGE_BL31) || !defined(CONFIG_DDR_FIP_IMAGE)
+ mmap_add_ddr_regions_statically();
+#endif
+
+ /* Create the page tables to reflect the above mappings */
+ init_xlat_tables();
+}
+
+/*******************************************************************************
+ * Returns NXP platform specific memory map regions.
+ ******************************************************************************/
+const mmap_region_t *plat_ls_get_mmap(void)
+{
+ return plat_ls_mmap;
+}
+
+/*
+ * This function get the number of clusters and cores count per cluster
+ * in the SoC.
+ */
+void get_cluster_info(const struct soc_type *soc_list, uint8_t ps_count,
+ uint8_t *num_clusters, uint8_t *cores_per_cluster)
+{
+ const soc_info_t *soc_info = get_soc_info();
+ *num_clusters = NUMBER_OF_CLUSTERS;
+ *cores_per_cluster = CORES_PER_CLUSTER;
+ unsigned int i;
+
+ for (i = 0U; i < ps_count; i++) {
+ if (soc_list[i].version == soc_info->svr_reg.bf_ver.version) {
+ *num_clusters = soc_list[i].num_clusters;
+ *cores_per_cluster = soc_list[i].cores_per_cluster;
+ break;
+ }
+ }
+
+ VERBOSE("NUM of cluster = 0x%x, Cores per cluster = 0x%x\n",
+ *num_clusters, *cores_per_cluster);
+}
diff --git a/plat/nxp/common/setup/ls_err.c b/plat/nxp/common/setup/ls_err.c
new file mode 100644
index 0000000..845cd15
--- /dev/null
+++ b/plat/nxp/common/setup/ls_err.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#if TRUSTED_BOARD_BOOT
+#include <dcfg.h>
+#include <snvs.h>
+#endif
+
+#include "plat_common.h"
+
+/*
+ * Error handler
+ */
+void plat_error_handler(int err)
+{
+#if TRUSTED_BOARD_BOOT
+ uint32_t mode;
+ bool sb = check_boot_mode_secure(&mode);
+#endif
+
+ switch (err) {
+ case -ENOENT:
+ case -EAUTH:
+ printf("Authentication failure\n");
+#if TRUSTED_BOARD_BOOT
+ /* For SB production mode i.e ITS = 1 */
+ if (sb == true) {
+ if (mode == 1U) {
+ transition_snvs_soft_fail();
+ } else {
+ transition_snvs_non_secure();
+ }
+ }
+#endif
+ break;
+ default:
+ /* Unexpected error */
+ break;
+ }
+
+ /* Loop until the watchdog resets the system */
+ for (;;)
+ wfi();
+}
diff --git a/plat/nxp/common/setup/ls_image_load.c b/plat/nxp/common/setup/ls_image_load.c
new file mode 100644
index 0000000..259ab31
--- /dev/null
+++ b/plat/nxp/common/setup/ls_image_load.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <common/desc_image_load.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();
+}
diff --git a/plat/nxp/common/setup/ls_interrupt_mgmt.c b/plat/nxp/common/setup/ls_interrupt_mgmt.c
new file mode 100644
index 0000000..a81cb2b
--- /dev/null
+++ b/plat/nxp/common/setup/ls_interrupt_mgmt.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <bl31/interrupt_mgmt.h>
+#include <common/debug.h>
+#include <ls_interrupt_mgmt.h>
+#include <plat/common/platform.h>
+
+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] != NULL) {
+ return -EALREADY;
+ }
+
+ type_el3_interrupt_table[id] = handler;
+
+ return 0;
+}
+
+static uint64_t ls_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();
+
+ INFO("Interrupt recvd is %d\n", intr_id);
+
+ handler = type_el3_interrupt_table[intr_id];
+ if (handler != NULL) {
+ handler(intr_id, flags, handle, cookie);
+ }
+
+ /*
+ * Mark this interrupt as complete to avoid a interrupt storm.
+ */
+ plat_ic_end_of_interrupt(intr_id);
+
+ return 0U;
+}
+
+void ls_el3_interrupt_config(void)
+{
+ uint64_t flags = 0U;
+ uint64_t rc;
+
+ set_interrupt_rm_flag(flags, NON_SECURE);
+ rc = register_interrupt_type_handler(INTR_TYPE_EL3,
+ ls_el3_interrupt_handler, flags);
+ if (rc != 0U) {
+ panic();
+ }
+}
diff --git a/plat/nxp/common/setup/ls_io_storage.c b/plat/nxp/common/setup/ls_io_storage.c
new file mode 100644
index 0000000..7f01e72
--- /dev/null
+++ b/plat/nxp/common/setup/ls_io_storage.c
@@ -0,0 +1,556 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <endian.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#ifdef FLEXSPI_NOR_BOOT
+#include <flexspi_nor.h>
+#endif
+#if defined(NAND_BOOT)
+#include <ifc_nand.h>
+#endif
+#if defined(NOR_BOOT)
+#include <ifc_nor.h>
+#endif
+#if defined(QSPI_BOOT)
+#include <qspi.h>
+#endif
+#if defined(SD_BOOT) || defined(EMMC_BOOT)
+#include <sd_mmc.h>
+#endif
+#include <tools_share/firmware_image_package.h>
+
+#ifdef CONFIG_DDR_FIP_IMAGE
+#include <ddr_io_storage.h>
+#endif
+#ifdef POLICY_FUSE_PROVISION
+#include <fuse_io.h>
+#endif
+#include "plat_common.h"
+#include "platform_def.h"
+
+uint32_t fip_device;
+/* IO devices */
+uintptr_t backend_dev_handle;
+
+static const io_dev_connector_t *fip_dev_con;
+static uintptr_t fip_dev_handle;
+static const io_dev_connector_t *backend_dev_con;
+
+static io_block_spec_t fip_block_spec = {
+ .offset = PLAT_FIP_OFFSET,
+ .length = PLAT_FIP_MAX_SIZE
+};
+
+static const io_uuid_spec_t bl2_uuid_spec = {
+ .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+};
+
+static const io_uuid_spec_t fuse_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 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,
+};
+
+#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 fuse_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 fuse_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);
+
+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] = {
+ &backend_dev_handle,
+ (uintptr_t)&fip_block_spec,
+ open_backend
+ },
+ [BL2_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&bl2_uuid_spec,
+ open_fip
+ },
+ [SCP_BL2_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&fuse_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
+ },
+ [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
+ },
+#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)&fuse_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)&fuse_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_io_setup
+
+/*
+ * Return an IO device handle and specification which can be used to access
+ */
+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;
+}
+
+
+int open_backend(const uintptr_t spec)
+{
+ int result;
+ uintptr_t local_image_handle;
+
+ result = io_dev_init(backend_dev_handle, (uintptr_t)NULL);
+ if (result == 0) {
+ result = io_open(backend_dev_handle, spec, &local_image_handle);
+ if (result == 0) {
+ io_close(local_image_handle);
+ }
+ }
+ return result;
+}
+
+#if defined(SD_BOOT) || defined(EMMC_BOOT) || defined(NAND_BOOT)
+static int plat_io_block_setup(size_t fip_offset, uintptr_t block_dev_spec)
+{
+ int io_result;
+
+ fip_block_spec.offset = fip_offset;
+
+ io_result = register_io_dev_block(&backend_dev_con);
+ assert(io_result == 0);
+
+ /* Open connections to devices and cache the handles */
+ io_result = io_dev_open(backend_dev_con, block_dev_spec,
+ &backend_dev_handle);
+ assert(io_result == 0);
+
+ return io_result;
+}
+#endif
+
+#if defined(FLEXSPI_NOR_BOOT) || defined(QSPI_BOOT) || defined(NOR_BOOT)
+static int plat_io_memmap_setup(size_t fip_offset)
+{
+ int io_result;
+
+ fip_block_spec.offset = fip_offset;
+
+ io_result = register_io_dev_memmap(&backend_dev_con);
+ assert(io_result == 0);
+
+ /* Open connections to devices and cache the handles */
+ io_result = io_dev_open(backend_dev_con, (uintptr_t)NULL,
+ &backend_dev_handle);
+ assert(io_result == 0);
+
+ return io_result;
+}
+#endif
+
+static int ls_io_fip_setup(unsigned int boot_dev)
+{
+ int io_result;
+
+ io_result = register_io_dev_fip(&fip_dev_con);
+ assert(io_result == 0);
+
+ /* Open connections to devices and cache the handles */
+ io_result = io_dev_open(fip_dev_con, (uintptr_t)&fip_device,
+ &fip_dev_handle);
+ assert(io_result == 0);
+
+#ifdef CONFIG_DDR_FIP_IMAGE
+ /* Open connection to DDR FIP image if available */
+ io_result = ddr_fip_setup(fip_dev_con, boot_dev);
+
+ assert(io_result == 0);
+#endif
+
+#ifdef POLICY_FUSE_PROVISION
+ /* Open connection to FUSE FIP image if available */
+ io_result = fuse_fip_setup(fip_dev_con, boot_dev);
+
+ assert(io_result == 0);
+#endif
+
+ return io_result;
+}
+
+int ls_qspi_io_setup(void)
+{
+#ifdef QSPI_BOOT
+ qspi_io_setup(NXP_QSPI_FLASH_ADDR,
+ NXP_QSPI_FLASH_SIZE,
+ PLAT_FIP_OFFSET);
+ return plat_io_memmap_setup(NXP_QSPI_FLASH_ADDR + PLAT_FIP_OFFSET);
+#else
+ ERROR("QSPI driver not present. Check your BUILD\n");
+
+ /* Should never reach here */
+ assert(false);
+ return -1;
+#endif
+}
+
+int emmc_sdhc2_io_setup(void)
+{
+#if defined(EMMC_BOOT) && defined(NXP_ESDHC2_ADDR)
+ uintptr_t block_dev_spec;
+ int ret;
+
+ ret = sd_emmc_init(&block_dev_spec,
+ NXP_ESDHC2_ADDR,
+ NXP_SD_BLOCK_BUF_ADDR,
+ NXP_SD_BLOCK_BUF_SIZE,
+ false);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return plat_io_block_setup(PLAT_FIP_OFFSET, block_dev_spec);
+#else
+ ERROR("EMMC driver not present. Check your BUILD\n");
+
+ /* Should never reach here */
+ assert(false);
+ return -1;
+#endif
+}
+
+int emmc_io_setup(void)
+{
+/* On the platforms which only has one ESDHC controller,
+ * eMMC-boot will use the first ESDHC controller.
+ */
+#if defined(SD_BOOT) || defined(EMMC_BOOT)
+ uintptr_t block_dev_spec;
+ int ret;
+
+ ret = sd_emmc_init(&block_dev_spec,
+ NXP_ESDHC_ADDR,
+ NXP_SD_BLOCK_BUF_ADDR,
+ NXP_SD_BLOCK_BUF_SIZE,
+ true);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return plat_io_block_setup(PLAT_FIP_OFFSET, block_dev_spec);
+#else
+ ERROR("SD driver not present. Check your BUILD\n");
+
+ /* Should never reach here */
+ assert(false);
+ return -1;
+#endif
+}
+
+int ifc_nor_io_setup(void)
+{
+#if defined(NOR_BOOT)
+ int ret;
+
+ ret = ifc_nor_init(NXP_NOR_FLASH_ADDR,
+ NXP_NOR_FLASH_SIZE);
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ return plat_io_memmap_setup(NXP_NOR_FLASH_ADDR + PLAT_FIP_OFFSET);
+#else
+ ERROR("NOR driver not present. Check your BUILD\n");
+
+ /* Should never reach here */
+ assert(false);
+ return -1;
+#endif
+}
+
+int ifc_nand_io_setup(void)
+{
+#if defined(NAND_BOOT)
+ uintptr_t block_dev_spec;
+ int ret;
+
+ ret = ifc_nand_init(&block_dev_spec,
+ NXP_IFC_REGION_ADDR,
+ NXP_IFC_ADDR,
+ NXP_IFC_SRAM_BUFFER_SIZE,
+ NXP_SD_BLOCK_BUF_ADDR,
+ NXP_SD_BLOCK_BUF_SIZE);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return plat_io_block_setup(PLAT_FIP_OFFSET, block_dev_spec);
+#else
+
+ ERROR("NAND driver not present. Check your BUILD\n");
+
+ /* Should never reach here */
+ assert(false);
+ return -1;
+#endif
+}
+
+int ls_flexspi_nor_io_setup(void)
+{
+#ifdef FLEXSPI_NOR_BOOT
+ int ret = 0;
+
+ ret = flexspi_nor_io_setup(NXP_FLEXSPI_FLASH_ADDR,
+ NXP_FLEXSPI_FLASH_SIZE,
+ NXP_FLEXSPI_ADDR);
+
+ if (ret != 0) {
+ ERROR("FlexSPI NOR driver initialization error.\n");
+ /* Should never reach here */
+ assert(0);
+ panic();
+ return -1;
+ }
+
+ return plat_io_memmap_setup(NXP_FLEXSPI_FLASH_ADDR + PLAT_FIP_OFFSET);
+#else
+ ERROR("FlexSPI NOR driver not present. Check your BUILD\n");
+
+ /* Should never reach here */
+ assert(false);
+ return -1;
+#endif
+}
+
+static int (* const ls_io_setup_table[])(void) = {
+ [BOOT_DEVICE_IFC_NOR] = ifc_nor_io_setup,
+ [BOOT_DEVICE_IFC_NAND] = ifc_nand_io_setup,
+ [BOOT_DEVICE_QSPI] = ls_qspi_io_setup,
+ [BOOT_DEVICE_EMMC] = emmc_io_setup,
+ [BOOT_DEVICE_SDHC2_EMMC] = emmc_sdhc2_io_setup,
+ [BOOT_DEVICE_FLEXSPI_NOR] = ls_flexspi_nor_io_setup,
+ [BOOT_DEVICE_FLEXSPI_NAND] = ls_flexspi_nor_io_setup,
+};
+
+
+int plat_io_setup(void)
+{
+ int (*io_setup)(void);
+ unsigned int boot_dev = BOOT_DEVICE_NONE;
+ int ret;
+
+ boot_dev = get_boot_dev();
+ if (boot_dev == BOOT_DEVICE_NONE) {
+ ERROR("Boot Device detection failed, Check RCW_SRC\n");
+ return -EINVAL;
+ }
+
+ io_setup = ls_io_setup_table[boot_dev];
+ ret = io_setup();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = ls_io_fip_setup(boot_dev);
+ if (ret != 0) {
+ return ret;
+ }
+
+ 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 = -1;
+ const struct plat_io_policy *policy;
+
+ if (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);
+ }
+ }
+#ifdef CONFIG_DDR_FIP_IMAGE
+ else {
+ VERBOSE("Trying alternative IO\n");
+ result = plat_get_ddr_fip_image_source(image_id, dev_handle,
+ image_spec, open_backend);
+ }
+#endif
+#ifdef POLICY_FUSE_PROVISION
+ if (result != 0) {
+ VERBOSE("Trying FUSE IO\n");
+ result = plat_get_fuse_image_source(image_id, dev_handle,
+ image_spec, open_backend);
+ }
+#endif
+
+ return result;
+}
diff --git a/plat/nxp/common/setup/ls_stack_protector.c b/plat/nxp/common/setup/ls_stack_protector.c
new file mode 100644
index 0000000..ab78f88
--- /dev/null
+++ b/plat/nxp/common/setup/ls_stack_protector.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+
+#include <plat/common/platform.h>
+
+#define RANDOM_CANARY_VALUE ((u_register_t) 3288484550995823360ULL)
+
+u_register_t plat_get_stack_protector_canary(void)
+{
+ /*
+ * TBD: Generate Random Number from NXP CAAM Block.
+ */
+ return RANDOM_CANARY_VALUE ^ read_cntpct_el0();
+}
diff --git a/plat/nxp/common/sip_svc/aarch64/sipsvc.S b/plat/nxp/common/sip_svc/aarch64/sipsvc.S
new file mode 100644
index 0000000..6a47cbf
--- /dev/null
+++ b/plat/nxp/common/sip_svc/aarch64/sipsvc.S
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <asm_macros.S>
+#include <bl31_data.h>
+
+.global el2_2_aarch32
+.global prefetch_disable
+
+#define SPSR_EL3_M4 0x10
+#define SPSR_EL_MASK 0xC
+#define SPSR_EL2 0x8
+#define SCR_EL3_4_EL2_AARCH32 0x131
+#define SPSR32_EL2_LE 0x1DA
+
+#define MIDR_PARTNUM_START 4
+#define MIDR_PARTNUM_WIDTH 12
+#define MIDR_PARTNUM_A53 0xD03
+#define MIDR_PARTNUM_A57 0xD07
+#define MIDR_PARTNUM_A72 0xD08
+
+/*
+ * uint64_t el2_2_aarch32(u_register_t smc_id,
+ * u_register_t start_addr,
+ * u_register_t parm1,
+ * u_register_t parm2)
+ * this function allows changing the execution width of EL2 from Aarch64
+ * to Aarch32
+ * Note: MUST be called from EL2 @ Aarch64
+ * in: x0 = smc function id
+ * x1 = start address for EL2 @ Aarch32
+ * x2 = first parameter to pass to EL2 @ Aarch32
+ * x3 = second parameter to pass to EL2 @ Aarch32
+ * out: x0 = 0, on success
+ * x0 = -1, on failure
+ * uses x0, x1, x2, x3
+ */
+func el2_2_aarch32
+
+ /* check that caller is EL2 @ Aarch64 - err return if not */
+ mrs x0, spsr_el3
+ /* see if we were called from Aarch32 */
+ tst x0, #SPSR_EL3_M4
+ b.ne 2f
+
+ /* see if we were called from EL2 */
+ and x0, x0, SPSR_EL_MASK
+ cmp x0, SPSR_EL2
+ b.ne 2f
+
+ /* set ELR_EL3 */
+ msr elr_el3, x1
+
+ /* set scr_el3 */
+ mov x0, #SCR_EL3_4_EL2_AARCH32
+ msr scr_el3, x0
+
+ /* set sctlr_el2 */
+ ldr x1, =SCTLR_EL2_RES1
+ msr sctlr_el2, x1
+
+ /* set spsr_el3 */
+ ldr x0, =SPSR32_EL2_LE
+ msr spsr_el3, x0
+
+ /* x2 = parm 1
+ * x3 = parm2
+ */
+
+ /* set the parameters to be passed-thru to EL2 @ Aarch32 */
+ mov x1, x2
+ mov x2, x3
+
+ /* x1 = parm 1
+ * x2 = parm2
+ */
+
+ mov x0, xzr
+ /* invalidate the icache */
+ ic iallu
+ dsb sy
+ isb
+ b 1f
+2:
+ /* error return */
+ mvn x0, xzr
+ ret
+1:
+ eret
+endfunc el2_2_aarch32
+
+/*
+ * int prefetch_disable(u_register_t smc_id, u_register_t mask)
+ * this function marks cores which need to have the prefetch disabled -
+ * secondary cores have prefetch disabled when they are released from reset -
+ * the bootcore has prefetch disabled when this call is made
+ * in: x0 = function id
+ * x1 = core mask, where bit[0]=core0, bit[1]=core1, etc
+ * if a bit in the mask is set, then prefetch is disabled for that
+ * core
+ * out: x0 = SMC_SUCCESS
+ */
+func prefetch_disable
+ stp x4, x30, [sp, #-16]!
+
+ mov x3, x1
+
+ /* x1 = core prefetch disable mask */
+ /* x3 = core prefetch disable mask */
+
+ /* store the mask */
+ mov x0, #PREFETCH_DIS_OFFSET
+ bl _set_global_data
+
+ /* x3 = core prefetch disable mask */
+
+ /* see if we need to disable prefetch on THIS core */
+ bl plat_my_core_mask
+
+ /* x0 = core mask lsb */
+ /* x3 = core prefetch disable mask */
+
+ tst x3, x0
+ b.eq 1f
+
+ /* read midr_el1 */
+ mrs x1, midr_el1
+
+ /* x1 = midr_el1 */
+
+ mov x0, xzr
+ bfxil x0, x1, #MIDR_PARTNUM_START, #MIDR_PARTNUM_WIDTH
+
+ /* x0 = part number (a53, a57, a72, etc) */
+
+ /* branch on cpu-specific */
+ cmp x0, #MIDR_PARTNUM_A57
+ b.eq 1f
+ cmp x0, #MIDR_PARTNUM_A72
+ b.ne 1f
+
+ bl _disable_ldstr_pfetch_A72
+ b 1f
+1:
+ ldp x4, x30, [sp], #16
+ mov x0, xzr
+ ret
+endfunc prefetch_disable
diff --git a/plat/nxp/common/sip_svc/include/sipsvc.h b/plat/nxp/common/sip_svc/include/sipsvc.h
new file mode 100644
index 0000000..d9e61e9
--- /dev/null
+++ b/plat/nxp/common/sip_svc/include/sipsvc.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef SIPSVC_H
+#define SIPSVC_H
+
+#include <stdint.h>
+
+#define SMC_FUNC_MASK 0x0000ffff
+#define SMC32_PARAM_MASK 0xffffffff
+
+/* SMC function IDs for SiP Service queries */
+#define SIP_SVC_CALL_COUNT 0xff00
+#define SIP_SVC_UID 0xff01
+#define SIP_SVC_VERSION 0xff03
+#define SIP_SVC_PRNG 0xff10
+#define SIP_SVC_RNG 0xff11
+#define SIP_SVC_MEM_BANK 0xff12
+#define SIP_SVC_PREFETCH_DIS 0xff13
+#define SIP_SVC_HUK 0xff14
+#define SIP_SVC_ALLOW_L1L2_ERR 0xff15
+#define SIP_SVC_ALLOW_L2_CLR 0xff16
+#define SIP_SVC_2_AARCH32 0xff17
+#define SIP_SVC_PORSR1 0xff18
+
+/* Layerscape SiP Service Calls version numbers */
+#define LS_SIP_SVC_VERSION_MAJOR 0x0
+#define LS_SIP_SVC_VERSION_MINOR 0x1
+
+/* Number of Layerscape SiP Calls implemented */
+#define LS_COMMON_SIP_NUM_CALLS 10
+
+/* Parameter Type Constants */
+#define SIP_PARAM_TYPE_NONE 0x0
+#define SIP_PARAM_TYPE_VALUE_INPUT 0x1
+#define SIP_PARAM_TYPE_VALUE_OUTPUT 0x2
+#define SIP_PARAM_TYPE_VALUE_INOUT 0x3
+#define SIP_PARAM_TYPE_MEMREF_INPUT 0x5
+#define SIP_PARAM_TYPE_MEMREF_OUTPUT 0x6
+#define SIP_PARAM_TYPE_MEMREF_INOUT 0x7
+
+#define SIP_PARAM_TYPE_MASK 0xF
+
+/*
+ * The macro SIP_PARAM_TYPES can be used to construct a value that you can
+ * compare against an incoming paramTypes to check the type of all the
+ * parameters in one comparison.
+ */
+#define SIP_PARAM_TYPES(t0, t1, t2, t3) \
+ ((t0) | ((t1) << 4) | ((t2) << 8) | ((t3) << 12))
+
+/*
+ * The macro SIP_PARAM_TYPE_GET can be used to extract the type of a given
+ * parameter from paramTypes if you need more fine-grained type checking.
+ */
+#define SIP_PARAM_TYPE_GET(t, i) ((((uint32_t)(t)) >> ((i) * 4)) & 0xF)
+
+/*
+ * The macro SIP_PARAM_TYPE_SET can be used to load the type of a given
+ * parameter from paramTypes without specifying all types (SIP_PARAM_TYPES)
+ */
+#define SIP_PARAM_TYPE_SET(t, i) (((uint32_t)(t) & 0xF) << ((i) * 4))
+
+#define SIP_SVC_RNG_PARAMS (SIP_PARAM_TYPE_VALUE_INPUT, \
+ SIP_PARAM_TYPE_MEMREF_OUTPUT, \
+ SIP_PARAM_TYPE_NONE, \
+ SIP_PARAM_TYPE_NONE)
+
+/* Layerscape SiP Calls error code */
+enum {
+ LS_SIP_SUCCESS = 0,
+ LS_SIP_INVALID_PARAM = -1,
+ LS_SIP_NOT_SUPPORTED = -2,
+};
+
+#endif /* SIPSVC_H */
diff --git a/plat/nxp/common/sip_svc/sip_svc.c b/plat/nxp/common/sip_svc/sip_svc.c
new file mode 100644
index 0000000..1c8668e
--- /dev/null
+++ b/plat/nxp/common/sip_svc/sip_svc.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <caam.h>
+#include <common/runtime_svc.h>
+#include <dcfg.h>
+#include <lib/mmio.h>
+#include <tools_share/uuid.h>
+
+#include <plat_common.h>
+#include <sipsvc.h>
+
+/* Layerscape SiP Service UUID */
+DEFINE_SVC_UUID2(nxp_sip_svc_uid,
+ 0x871de4ef, 0xedfc, 0x4209, 0xa4, 0x23,
+ 0x8d, 0x23, 0x75, 0x9d, 0x3b, 0x9f);
+
+#pragma weak nxp_plat_sip_handler
+static uintptr_t nxp_plat_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)
+{
+ ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+}
+
+uint64_t el2_2_aarch32(u_register_t smc_id, u_register_t start_addr,
+ u_register_t parm1, u_register_t parm2);
+
+uint64_t prefetch_disable(u_register_t smc_id, u_register_t mask);
+uint64_t bl31_get_porsr1(void);
+
+static 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 (GET_SMC_CC(smc_fid) == SMC_32) {
+ *px1 = *px1 & SMC32_PARAM_MASK;
+ *px2 = *px2 & SMC32_PARAM_MASK;
+ *px3 = *px3 & SMC32_PARAM_MASK;
+ *px4 = *px4 & SMC32_PARAM_MASK;
+ }
+}
+
+/* This function handles Layerscape defined SiP Calls */
+static uintptr_t nxp_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)
+{
+ uint32_t ns;
+ uint64_t ret;
+ dram_regions_info_t *info_dram_regions;
+
+ /* 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 == 0) {
+ /* SiP SMC service secure world's call */
+ ;
+ } else {
+ /* SiP SMC service normal world's call */
+ ;
+ }
+
+ switch (smc_fid & SMC_FUNC_MASK) {
+ case SIP_SVC_RNG:
+ if (is_sec_enabled() == false) {
+ NOTICE("SEC is disabled.\n");
+ SMC_RET1(handle, SMC_UNK);
+ }
+
+ /* Return zero on failure */
+ ret = get_random((int)x1);
+ if (ret != 0) {
+ SMC_RET2(handle, SMC_OK, ret);
+ } else {
+ SMC_RET1(handle, SMC_UNK);
+ }
+ /* break is not required as SMC_RETx return */
+ case SIP_SVC_HUK:
+ if (is_sec_enabled() == false) {
+ NOTICE("SEC is disabled.\n");
+ SMC_RET1(handle, SMC_UNK);
+ }
+ ret = get_hw_unq_key_blob_hw((uint8_t *) x1, (uint32_t) x2);
+
+ if (ret == SMC_OK) {
+ SMC_RET1(handle, SMC_OK);
+ } else {
+ SMC_RET1(handle, SMC_UNK);
+ }
+ /* break is not required as SMC_RETx return */
+ case SIP_SVC_MEM_BANK:
+ VERBOSE("Handling SMC SIP_SVC_MEM_BANK.\n");
+ info_dram_regions = get_dram_regions_info();
+
+ if (x1 == -1) {
+ SMC_RET2(handle, SMC_OK,
+ info_dram_regions->total_dram_size);
+ } else if (x1 >= info_dram_regions->num_dram_regions) {
+ SMC_RET1(handle, SMC_UNK);
+ } else {
+ SMC_RET3(handle, SMC_OK,
+ info_dram_regions->region[x1].addr,
+ info_dram_regions->region[x1].size);
+ }
+ /* break is not required as SMC_RETx return */
+ case SIP_SVC_PREFETCH_DIS:
+ VERBOSE("In SIP_SVC_PREFETCH_DIS call\n");
+ ret = prefetch_disable(smc_fid, x1);
+ if (ret == SMC_OK) {
+ SMC_RET1(handle, SMC_OK);
+ } else {
+ SMC_RET1(handle, SMC_UNK);
+ }
+ /* break is not required as SMC_RETx return */
+ case SIP_SVC_2_AARCH32:
+ ret = el2_2_aarch32(smc_fid, x1, x2, x3);
+
+ /* In success case, control should not reach here. */
+ NOTICE("SMC: SIP_SVC_2_AARCH32 Failed.\n");
+ SMC_RET1(handle, SMC_UNK);
+ /* break is not required as SMC_RETx return */
+ case SIP_SVC_PORSR1:
+ ret = bl31_get_porsr1();
+ SMC_RET2(handle, SMC_OK, ret);
+ /* break is not required as SMC_RETx return */
+ default:
+ return nxp_plat_sip_handler(smc_fid, x1, x2, x3, x4,
+ cookie, handle, flags);
+ }
+}
+
+/* This function is responsible for handling all SiP calls */
+static uintptr_t sip_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)
+{
+ switch (smc_fid & SMC_FUNC_MASK) {
+ case SIP_SVC_CALL_COUNT:
+ /* Return the number of Layerscape SiP Service Calls. */
+ SMC_RET1(handle, LS_COMMON_SIP_NUM_CALLS);
+ break;
+ case SIP_SVC_UID:
+ /* Return UID to the caller */
+ SMC_UUID_RET(handle, nxp_sip_svc_uid);
+ break;
+ case SIP_SVC_VERSION:
+ /* Return the version of current implementation */
+ SMC_RET2(handle, LS_SIP_SVC_VERSION_MAJOR,
+ LS_SIP_SVC_VERSION_MINOR);
+ break;
+ default:
+ return nxp_sip_handler(smc_fid, x1, x2, x3, x4,
+ cookie, handle, flags);
+ }
+}
+
+/* Define a runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+ nxp_sip_svc,
+ OEN_SIP_START,
+ OEN_SIP_END,
+ SMC_TYPE_FAST,
+ NULL,
+ sip_smc_handler
+);
diff --git a/plat/nxp/common/sip_svc/sipsvc.mk b/plat/nxp/common/sip_svc/sipsvc.mk
new file mode 100644
index 0000000..c3a57de
--- /dev/null
+++ b/plat/nxp/common/sip_svc/sipsvc.mk
@@ -0,0 +1,35 @@
+#
+# Copyright 2018-2020 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+#------------------------------------------------------------------------------
+#
+# Select the SIP SVC files
+#
+# -----------------------------------------------------------------------------
+
+ifeq (${ADD_SIPSVC},)
+
+ADD_SIPSVC := 1
+
+PLAT_SIPSVC_PATH := $(PLAT_COMMON_PATH)/sip_svc
+
+SIPSVC_SOURCES := ${PLAT_SIPSVC_PATH}/sip_svc.c \
+ ${PLAT_SIPSVC_PATH}/$(ARCH)/sipsvc.S
+
+PLAT_INCLUDES += -I${PLAT_SIPSVC_PATH}/include
+
+ifeq (${BL_COMM_SIPSVC_NEEDED},yes)
+BL_COMMON_SOURCES += ${SIPSVC_SOURCES}
+else
+ifeq (${BL2_SIPSVC_NEEDED},yes)
+BL2_SOURCES += ${SIPSVC_SOURCES}
+endif
+ifeq (${BL31_SIPSVC_NEEDED},yes)
+BL31_SOURCES += ${SIPSVC_SOURCES}
+endif
+endif
+endif
+# -----------------------------------------------------------------------------
diff --git a/plat/nxp/common/soc_errata/errata.c b/plat/nxp/common/soc_errata/errata.c
new file mode 100644
index 0000000..55ef604
--- /dev/null
+++ b/plat/nxp/common/soc_errata/errata.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2021-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <common/debug.h>
+
+#include "errata_list.h"
+
+void soc_errata(void)
+{
+#ifdef ERRATA_SOC_A050426
+ INFO("SoC workaround for Errata A050426 was applied\n");
+ erratum_a050426();
+#endif
+#ifdef ERRATA_SOC_A008850
+ INFO("SoC workaround for Errata A008850 Early-Phase was applied\n");
+ erratum_a008850_early();
+#endif
+#if ERRATA_SOC_A009660
+ INFO("SoC workaround for Errata A009660 was applied\n");
+ erratum_a009660();
+#endif
+#if ERRATA_SOC_A010539
+ INFO("SoC workaround for Errata A010539 was applied\n");
+ erratum_a010539();
+#endif
+
+ /*
+ * The following DDR Erratas workaround are implemented in DDR driver,
+ * but print information here.
+ */
+#if ERRATA_DDR_A011396
+ INFO("SoC workaround for DDR Errata A011396 was applied\n");
+#endif
+#if ERRATA_DDR_A050450
+ INFO("SoC workaround for DDR Errata A050450 was applied\n");
+#endif
+#if ERRATA_DDR_A050958
+ INFO("SoC workaround for DDR Errata A050958 was applied\n");
+#endif
+#if ERRATA_DDR_A008511
+ INFO("SoC workaround for DDR Errata A008511 was applied\n");
+#endif
+#if ERRATA_DDR_A009803
+ INFO("SoC workaround for DDR Errata A009803 was applied\n");
+#endif
+#if ERRATA_DDR_A009942
+ INFO("SoC workaround for DDR Errata A009942 was applied\n");
+#endif
+#if ERRATA_DDR_A010165
+ INFO("SoC workaround for DDR Errata A010165 was applied\n");
+#endif
+#if ERRATA_DDR_A009663
+ INFO("SoC workaround for DDR Errata A009663 was applied\n");
+#endif
+}
diff --git a/plat/nxp/common/soc_errata/errata.h b/plat/nxp/common/soc_errata/errata.h
new file mode 100644
index 0000000..ab67995
--- /dev/null
+++ b/plat/nxp/common/soc_errata/errata.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2020-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef ERRATA_H
+#define ERRATA_H
+
+#include "errata_list.h"
+
+void soc_errata(void);
+
+#endif /* ERRATA_H */
diff --git a/plat/nxp/common/soc_errata/errata.mk b/plat/nxp/common/soc_errata/errata.mk
new file mode 100644
index 0000000..3deef3d
--- /dev/null
+++ b/plat/nxp/common/soc_errata/errata.mk
@@ -0,0 +1,26 @@
+#
+# Copyright 2021-2022 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Platform Errata Build flags.
+# These should be enabled by the platform if the erratum workaround needs to be
+# applied.
+
+ERRATA := \
+ ERRATA_SOC_A050426 \
+ ERRATA_SOC_A008850 \
+ ERRATA_SOC_A009660 \
+ ERRATA_SOC_A010539
+
+define enable_errata
+ $(1) ?= 0
+ ifeq ($$($(1)),1)
+ $$(eval $$(call add_define,$(1)))
+ BL2_SOURCES += $(PLAT_COMMON_PATH)/soc_errata/errata_a$(shell echo $(1)|awk -F '_A' '{print $$NF}').c
+ endif
+endef
+
+$(foreach e,$(ERRATA),$(eval $(call enable_errata,$(strip $(e)))))
+
+BL2_SOURCES += $(PLAT_COMMON_PATH)/soc_errata/errata.c
diff --git a/plat/nxp/common/soc_errata/errata_a008850.c b/plat/nxp/common/soc_errata/errata_a008850.c
new file mode 100644
index 0000000..e8c0f64
--- /dev/null
+++ b/plat/nxp/common/soc_errata/errata_a008850.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <cci.h>
+#include <common/debug.h>
+#include <ls_interconnect.h>
+#include <mmio.h>
+
+#include <platform_def.h>
+
+void erratum_a008850_early(void)
+{
+ /* part 1 of 2 */
+ uintptr_t cci_base = NXP_CCI_ADDR;
+ uint32_t val = mmio_read_32(cci_base + CTRL_OVERRIDE_REG);
+
+ /* enabling forced barrier termination on CCI400 */
+ mmio_write_32(cci_base + CTRL_OVERRIDE_REG,
+ (val | CCI_TERMINATE_BARRIER_TX));
+
+}
+
+void erratum_a008850_post(void)
+{
+ /* part 2 of 2 */
+ uintptr_t cci_base = NXP_CCI_ADDR;
+ uint32_t val = mmio_read_32(cci_base + CTRL_OVERRIDE_REG);
+
+ /* Clear the BARRIER_TX bit */
+ val = val & ~(CCI_TERMINATE_BARRIER_TX);
+
+ /*
+ * Disable barrier termination on CCI400, allowing
+ * barriers to propagate across CCI
+ */
+ mmio_write_32(cci_base + CTRL_OVERRIDE_REG, val);
+
+ INFO("SoC workaround for Errata A008850 Post-Phase was applied\n");
+}
diff --git a/plat/nxp/common/soc_errata/errata_a009660.c b/plat/nxp/common/soc_errata/errata_a009660.c
new file mode 100644
index 0000000..d31a4d7
--- /dev/null
+++ b/plat/nxp/common/soc_errata/errata_a009660.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <mmio.h>
+#include <soc_default_base_addr.h>
+
+void erratum_a009660(void)
+{
+ mmio_write_32(NXP_SCFG_ADDR + 0x20c, 0x63b20042);
+}
diff --git a/plat/nxp/common/soc_errata/errata_a010539.c b/plat/nxp/common/soc_errata/errata_a010539.c
new file mode 100644
index 0000000..3dcbdc8
--- /dev/null
+++ b/plat/nxp/common/soc_errata/errata_a010539.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <mmio.h>
+
+#include <plat_common.h>
+
+void erratum_a010539(void)
+{
+ if (get_boot_dev() == BOOT_DEVICE_QSPI) {
+ unsigned int *porsr1 = (void *)(NXP_DCFG_ADDR +
+ DCFG_PORSR1_OFFSET);
+ uint32_t val;
+
+ val = (gur_in32(porsr1) & ~PORSR1_RCW_MASK);
+ mmio_write_32((uint32_t)(NXP_DCSR_DCFG_ADDR +
+ DCFG_DCSR_PORCR1_OFFSET), htobe32(val));
+ /* Erratum need to set '1' to all bits for reserved SCFG register 0x1a8 */
+ mmio_write_32((uint32_t)(NXP_SCFG_ADDR + 0x1a8),
+ htobe32(0xffffffff));
+ }
+}
diff --git a/plat/nxp/common/soc_errata/errata_a050426.c b/plat/nxp/common/soc_errata/errata_a050426.c
new file mode 100644
index 0000000..ba4f71f
--- /dev/null
+++ b/plat/nxp/common/soc_errata/errata_a050426.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2021-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <common/debug.h>
+#include <mmio.h>
+
+void erratum_a050426(void)
+{
+ uint32_t i, val3, val4;
+
+ /*
+ * Part of this Errata is implemented in RCW and SCRATCHRW5
+ * register is updated to hold Errata number.
+ * Validate whether RCW has already included required changes
+ */
+ if (mmio_read_32(0x01e00210) != 0x00050426) {
+ ERROR("%s: Invalid RCW : ERR050426 not implemented\n", __func__);
+ }
+
+ /* Enable BIST to access Internal memory locations */
+ val3 = mmio_read_32(0x700117E60);
+ mmio_write_32(0x700117E60, (val3 | 0x80000001));
+ val4 = mmio_read_32(0x700117E90);
+ mmio_write_32(0x700117E90, (val4 & 0xFFDFFFFF));
+
+ /* wriop Internal Memory.*/
+ for (i = 0U; i < 4U; i++) {
+ mmio_write_32(0x706312000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706312400 + (i * 4), 0x55555555);
+ mmio_write_32(0x706312800 + (i * 4), 0x55555555);
+ mmio_write_32(0x706314000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706314400 + (i * 4), 0x55555555);
+ mmio_write_32(0x706314800 + (i * 4), 0x55555555);
+ mmio_write_32(0x706314c00 + (i * 4), 0x55555555);
+ }
+ for (i = 0U; i < 3U; i++) {
+ mmio_write_32(0x706316000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706320000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706320400 + (i * 4), 0x55555555);
+ }
+ for (i = 0U; i < 2U; i++) {
+ mmio_write_32(0x70640a000 + (i * 4), 0x55555555);
+ }
+ for (i = 0U; i < 3U; i++) {
+ mmio_write_32(0x706518000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706519000 + (i * 4), 0x55555555);
+ }
+ for (i = 0U; i < 4U; i++) {
+ mmio_write_32(0x706522000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706522800 + (i * 4), 0x55555555);
+ mmio_write_32(0x706523000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706523800 + (i * 4), 0x55555555);
+ mmio_write_32(0x706524000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706524800 + (i * 4), 0x55555555);
+ mmio_write_32(0x706608000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706608800 + (i * 4), 0x55555555);
+ mmio_write_32(0x706609000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706609800 + (i * 4), 0x55555555);
+ mmio_write_32(0x70660a000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70660a800 + (i * 4), 0x55555555);
+ mmio_write_32(0x70660b000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70660b800 + (i * 4), 0x55555555);
+ }
+ for (i = 0U; i < 3U; i++) {
+ mmio_write_32(0x70660c000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70660c800 + (i * 4), 0x55555555);
+ }
+ for (i = 0U; i < 2U; i++) {
+ mmio_write_32(0x706718000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706718800 + (i * 4), 0x55555555);
+ }
+ mmio_write_32(0x706b0a000, 0x55555555);
+
+ for (i = 0U; i < 4U; i++) {
+ mmio_write_32(0x706b0e000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706b0e800 + (i * 4), 0x55555555);
+ }
+ for (i = 0U; i < 2U; i++) {
+ mmio_write_32(0x706b10000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706b10400 + (i * 4), 0x55555555);
+ }
+ for (i = 0U; i < 4U; i++) {
+ mmio_write_32(0x706b14000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706b14800 + (i * 4), 0x55555555);
+ mmio_write_32(0x706b15000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706b15800 + (i * 4), 0x55555555);
+ }
+ mmio_write_32(0x706e12000, 0x55555555);
+
+ for (i = 0U; i < 4U; i++) {
+ mmio_write_32(0x706e14000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706e14800 + (i * 4), 0x55555555);
+ }
+ for (i = 0U; i < 2U; i++) {
+ mmio_write_32(0x706e16000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706e16400 + (i * 4), 0x55555555);
+ }
+ for (i = 0U; i < 3U; i++) {
+ mmio_write_32(0x706e1a000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706e1a800 + (i * 4), 0x55555555);
+ mmio_write_32(0x706e1b000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706e1b800 + (i * 4), 0x55555555);
+ mmio_write_32(0x706e1c000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706e1c800 + (i * 4), 0x55555555);
+ mmio_write_32(0x706e1e000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706e1e800 + (i * 4), 0x55555555);
+ mmio_write_32(0x706e1f000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706e1f800 + (i * 4), 0x55555555);
+ mmio_write_32(0x706e20000 + (i * 4), 0x55555555);
+ mmio_write_32(0x706e20800 + (i * 4), 0x55555555);
+ }
+ for (i = 0U; i < 4U; i++) {
+ mmio_write_32(0x707108000 + (i * 4), 0x55555555);
+ mmio_write_32(0x707109000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70710a000 + (i * 4), 0x55555555);
+ }
+ for (i = 0U; i < 2U; i++) {
+ mmio_write_32(0x70711c000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70711c800 + (i * 4), 0x55555555);
+ mmio_write_32(0x70711d000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70711d800 + (i * 4), 0x55555555);
+ mmio_write_32(0x70711e000 + (i * 4), 0x55555555);
+ }
+ for (i = 0U; i < 4U; i++) {
+ mmio_write_32(0x707120000 + (i * 4), 0x55555555);
+ mmio_write_32(0x707121000 + (i * 4), 0x55555555);
+ }
+ for (i = 0U; i < 3U; i++) {
+ mmio_write_32(0x707122000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70725a000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70725b000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70725c000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70725e000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70725e400 + (i * 4), 0x55555555);
+ mmio_write_32(0x70725e800 + (i * 4), 0x55555555);
+ mmio_write_32(0x70725ec00 + (i * 4), 0x55555555);
+ mmio_write_32(0x70725f000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70725f400 + (i * 4), 0x55555555);
+ mmio_write_32(0x707340000 + (i * 4), 0x55555555);
+ mmio_write_32(0x707346000 + (i * 4), 0x55555555);
+ mmio_write_32(0x707484000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70748a000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70748b000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70748c000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70748d000 + (i * 4), 0x55555555);
+ }
+
+ /* EDMA Internal Memory.*/
+ for (i = 0U; i < 5U; i++) {
+ mmio_write_32(0x70a208000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70a208800 + (i * 4), 0x55555555);
+ mmio_write_32(0x70a209000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70a209800 + (i * 4), 0x55555555);
+ }
+
+ /* QDMA Internal Memory.*/
+ for (i = 0U; i < 5U; i++) {
+ mmio_write_32(0x70b008000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b00c000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b010000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b014000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b018000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b018400 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b01a000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b01a400 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b01c000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b01d000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b01e000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b01e800 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b01f000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b01f800 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b020000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b020400 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b020800 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b020c00 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b022000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b022400 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b024000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b024800 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b025000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b025800 + (i * 4), 0x55555555);
+ }
+ for (i = 0U; i < 4U; i++) {
+ mmio_write_32(0x70b026000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b026200 + (i * 4), 0x55555555);
+ }
+ for (i = 0U; i < 5U; i++) {
+ mmio_write_32(0x70b028000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b028800 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b029000 + (i * 4), 0x55555555);
+ mmio_write_32(0x70b029800 + (i * 4), 0x55555555);
+ }
+
+ /* Disable BIST */
+ mmio_write_32(0x700117E60, val3);
+ mmio_write_32(0x700117E90, val4);
+}
diff --git a/plat/nxp/common/soc_errata/errata_list.h b/plat/nxp/common/soc_errata/errata_list.h
new file mode 100644
index 0000000..f6741e2
--- /dev/null
+++ b/plat/nxp/common/soc_errata/errata_list.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2021-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef ERRATA_LIST_H
+#define ERRATA_LIST_H
+
+#ifdef ERRATA_SOC_A050426
+void erratum_a050426(void);
+#endif
+
+#ifdef ERRATA_SOC_A008850
+void erratum_a008850_early(void);
+void erratum_a008850_post(void);
+#endif
+
+#ifdef ERRATA_SOC_A009660
+void erratum_a009660(void);
+#endif
+
+#ifdef ERRATA_SOC_A010539
+void erratum_a010539(void);
+#endif
+
+#endif /* ERRATA_LIST_H */
diff --git a/plat/nxp/common/tbbr/csf_tbbr.c b/plat/nxp/common/tbbr/csf_tbbr.c
new file mode 100644
index 0000000..8f38f3e
--- /dev/null
+++ b/plat/nxp/common/tbbr/csf_tbbr.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ *
+ */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <csf_hdr.h>
+#include <dcfg.h>
+#include <drivers/auth/crypto_mod.h>
+#include <snvs.h>
+
+#include <plat/common/platform.h>
+#include "plat_common.h"
+
+extern bool rotpk_not_dpld;
+extern uint8_t rotpk_hash_table[MAX_KEY_ENTRIES][SHA256_BYTES];
+extern uint32_t num_rotpk_hash_entries;
+
+/*
+ * In case of secure boot, return ptr of rotpk_hash table in key_ptr and
+ * number of hashes in key_len
+ */
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+ unsigned int *flags)
+{
+ uint32_t mode = 0U;
+ *flags = ROTPK_NOT_DEPLOYED;
+
+ /* ROTPK hash table must be available for secure boot */
+ if (rotpk_not_dpld == true) {
+ if (check_boot_mode_secure(&mode) == true) {
+ /* Production mode, don;t continue further */
+ if (mode == 1U) {
+ return -EAUTH;
+ }
+
+ /* For development mode, rotpk flag false
+ * indicates that SRK hash comparison might
+ * have failed. This is not fatal error.
+ * Continue in this case but transition SNVS
+ * to non-secure state
+ */
+ transition_snvs_non_secure();
+ return 0;
+ } else {
+ return 0;
+ }
+ }
+
+ /*
+ * We return the complete hash table and number of entries in
+ * table for NXP platform specific implementation.
+ * Here hash is always assume as SHA-256
+ */
+ *key_ptr = rotpk_hash_table;
+ *key_len = num_rotpk_hash_entries;
+ *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 = 0U;
+
+ return 0;
+}
+
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+ return 0;
+}
diff --git a/plat/nxp/common/tbbr/nxp_rotpk.S b/plat/nxp/common/tbbr/nxp_rotpk.S
new file mode 100644
index 0000000..8e084d1
--- /dev/null
+++ b/plat/nxp/common/tbbr/nxp_rotpk.S
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ *
+ */
+
+#ifndef _CSF_HDR_H_
+
+ .global nxp_rotpk_hash
+ .global nxp_rotpk_hash_end
+ .section .rodata.nxp_rotpk_hash, "a"
+nxp_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
+nxp_rotpk_hash_end:
+#endif
diff --git a/plat/nxp/common/tbbr/tbbr.mk b/plat/nxp/common/tbbr/tbbr.mk
new file mode 100644
index 0000000..4aac9d6
--- /dev/null
+++ b/plat/nxp/common/tbbr/tbbr.mk
@@ -0,0 +1,162 @@
+#
+# Copyright 2020-2022 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# For TRUSTED_BOARD_BOOT platforms need to include this makefile
+# Following definations are to be provided by platform.mk file or
+# by user - BL33_INPUT_FILE, BL32_INPUT_FILE, BL31_INPUT_FILE
+
+ifeq ($(CHASSIS), 2)
+include $(PLAT_DRIVERS_PATH)/csu/csu.mk
+CSF_FILE := input_blx_ch${CHASSIS}
+BL2_CSF_FILE := input_bl2_ch${CHASSIS}
+else
+ifeq ($(CHASSIS), 3)
+CSF_FILE := input_blx_ch${CHASSIS}
+BL2_CSF_FILE := input_bl2_ch${CHASSIS}
+PBI_CSF_FILE := input_pbi_ch${CHASSIS}
+$(eval $(call add_define, CSF_HDR_CH3))
+else
+ifeq ($(CHASSIS), 3_2)
+CSF_FILE := input_blx_ch3
+BL2_CSF_FILE := input_bl2_ch${CHASSIS}
+PBI_CSF_FILE := input_pbi_ch${CHASSIS}
+$(eval $(call add_define, CSF_HDR_CH3))
+else
+ $(error -> CHASSIS not set!)
+endif
+endif
+endif
+
+PLAT_AUTH_PATH := $(PLAT_DRIVERS_PATH)/auth
+
+
+ifeq (${BL2_INPUT_FILE},)
+ BL2_INPUT_FILE := $(PLAT_AUTH_PATH)/csf_hdr_parser/${BL2_CSF_FILE}
+endif
+
+ifeq (${PBI_INPUT_FILE},)
+ PBI_INPUT_FILE := $(PLAT_AUTH_PATH)/csf_hdr_parser/${PBI_CSF_FILE}
+endif
+
+# If MBEDTLS_DIR is not specified, use CSF Header option
+ifeq (${MBEDTLS_DIR},)
+ # Generic image processing filters to prepend CSF header
+ ifeq (${BL33_INPUT_FILE},)
+ BL33_INPUT_FILE := $(PLAT_AUTH_PATH)/csf_hdr_parser/${CSF_FILE}
+ endif
+
+ ifeq (${BL31_INPUT_FILE},)
+ BL31_INPUT_FILE := $(PLAT_AUTH_PATH)/csf_hdr_parser/${CSF_FILE}
+ endif
+
+ ifeq (${BL32_INPUT_FILE},)
+ BL32_INPUT_FILE := $(PLAT_AUTH_PATH)/csf_hdr_parser/${CSF_FILE}
+ endif
+
+ ifeq (${FUSE_INPUT_FILE},)
+ FUSE_INPUT_FILE := $(PLAT_AUTH_PATH)/csf_hdr_parser/${CSF_FILE}
+ endif
+
+ PLAT_INCLUDES += -I$(PLAT_DRIVERS_PATH)/sfp
+ PLAT_TBBR_SOURCES += $(PLAT_AUTH_PATH)/csf_hdr_parser/cot.c \
+ $(PLAT_COMMON_PATH)/tbbr/csf_tbbr.c
+ # IMG PARSER here is CSF header parser
+ include $(PLAT_DRIVERS_PATH)/auth/csf_hdr_parser/csf_hdr.mk
+ PLAT_TBBR_SOURCES += $(CSF_HDR_SOURCES)
+
+ SCP_BL2_PRE_TOOL_FILTER := CST_SCP_BL2
+ BL31_PRE_TOOL_FILTER := CST_BL31
+ BL32_PRE_TOOL_FILTER := CST_BL32
+ BL33_PRE_TOOL_FILTER := CST_BL33
+else
+
+ ifeq (${DISABLE_FUSE_WRITE}, 1)
+ $(eval $(call add_define,DISABLE_FUSE_WRITE))
+ endif
+
+ # For Mbedtls currently crypto is not supported via CAAM
+ # enable it when that support is there
+ CAAM_INTEG := 0
+ KEY_ALG := rsa
+ KEY_SIZE := 2048
+
+ $(eval $(call add_define,MBEDTLS_X509))
+ ifeq (${PLAT_DDR_PHY},PHY_GEN2)
+ $(eval $(call add_define,PLAT_DEF_OID))
+ endif
+ include drivers/auth/mbedtls/mbedtls_x509.mk
+
+
+ PLAT_TBBR_SOURCES += $(PLAT_AUTH_PATH)/tbbr/tbbr_cot.c \
+ $(PLAT_COMMON_PATH)/tbbr/nxp_rotpk.S \
+ $(PLAT_COMMON_PATH)/tbbr/x509_tbbr.c
+
+ #ROTPK key is embedded in BL2 image
+ ifeq (${ROT_KEY},)
+ ROT_KEY = $(BUILD_PLAT)/rot_key.pem
+ endif
+
+ ifeq (${SAVE_KEYS},1)
+
+ ifeq (${TRUSTED_WORLD_KEY},)
+ TRUSTED_WORLD_KEY = ${BUILD_PLAT}/trusted.pem
+ endif
+
+ ifeq (${NON_TRUSTED_WORLD_KEY},)
+ NON_TRUSTED_WORLD_KEY = ${BUILD_PLAT}/non-trusted.pem
+ endif
+
+ ifeq (${BL31_KEY},)
+ BL31_KEY = ${BUILD_PLAT}/soc.pem
+ endif
+
+ ifeq (${BL32_KEY},)
+ BL32_KEY = ${BUILD_PLAT}/trusted_os.pem
+ endif
+
+ ifeq (${BL33_KEY},)
+ BL33_KEY = ${BUILD_PLAT}/non-trusted_os.pem
+ endif
+
+ endif
+
+ ROTPK_HASH = $(BUILD_PLAT)/rotpk_sha256.bin
+
+ $(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"'))
+
+ $(BUILD_PLAT)/bl2/nxp_rotpk.o: $(ROTPK_HASH)
+
+ certificates: $(ROT_KEY)
+ $(ROT_KEY): | $(BUILD_PLAT)
+ @echo " OPENSSL $@"
+ @if [ ! -f $(ROT_KEY) ]; then \
+ ${OPENSSL_BIN_PATH}/openssl genrsa 2048 > $@ 2>/dev/null; \
+ fi
+
+ $(ROTPK_HASH): $(ROT_KEY)
+ @echo " OPENSSL $@"
+ $(Q)${OPENSSL_BIN_PATH}/openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+ ${OPENSSL_BIN_PATH}/openssl dgst -sha256 -binary > $@ 2>/dev/null
+
+endif #MBEDTLS_DIR
+
+PLAT_INCLUDES += -Iinclude/common/tbbr
+
+# Generic files for authentication framework
+TBBR_SOURCES += drivers/auth/auth_mod.c \
+ drivers/auth/crypto_mod.c \
+ drivers/auth/img_parser_mod.c \
+ plat/common/tbbr/plat_tbbr.c \
+ ${PLAT_TBBR_SOURCES}
+
+# If CAAM_INTEG is not defined (would be scenario with MBED TLS)
+# include mbedtls_crypto
+ifeq (${CAAM_INTEG},0)
+ include drivers/auth/mbedtls/mbedtls_crypto.mk
+else
+ include $(PLAT_DRIVERS_PATH)/crypto/caam/src/auth/auth.mk
+ TBBR_SOURCES += ${AUTH_SOURCES}
+endif
diff --git a/plat/nxp/common/tbbr/x509_tbbr.c b/plat/nxp/common/tbbr/x509_tbbr.c
new file mode 100644
index 0000000..ec87674
--- /dev/null
+++ b/plat/nxp/common/tbbr/x509_tbbr.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <lib/cassert.h>
+#include <sfp.h>
+#include <tools_share/tbbr_oid.h>
+
+#include <plat/common/platform.h>
+#include "plat_common.h"
+
+extern char nxp_rotpk_hash[], nxp_rotpk_hash_end[];
+
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+ unsigned int *flags)
+{
+ *key_ptr = nxp_rotpk_hash;
+ *key_len = nxp_rotpk_hash_end - nxp_rotpk_hash;
+ *flags = ROTPK_IS_HASH;
+
+ return 0;
+}
+
+int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
+{
+ const char *oid;
+ uint32_t uid_num;
+ uint32_t val = 0U;
+
+ assert(cookie != NULL);
+ assert(nv_ctr != NULL);
+
+ oid = (const char *)cookie;
+ if (strcmp(oid, TRUSTED_FW_NVCOUNTER_OID) == 0) {
+ uid_num = 3U;
+ } else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) {
+ uid_num = 4U;
+ } else {
+ return 1;
+ }
+
+ val = sfp_read_oem_uid(uid_num);
+
+ INFO("SFP Value read is %x from UID %d\n", val, uid_num);
+ if (val == 0U) {
+ *nv_ctr = 0U;
+ } else {
+ *nv_ctr = (32U - __builtin_clz(val));
+ }
+
+ INFO("NV Counter value for UID %d is %d\n", uid_num, *nv_ctr);
+ return 0;
+
+}
+
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+ const char *oid;
+ uint32_t uid_num, sfp_val;
+
+ assert(cookie != NULL);
+
+ /* Counter values upto 32 are supported */
+ if (nv_ctr > 32U) {
+ return 1;
+ }
+
+ oid = (const char *)cookie;
+ if (strcmp(oid, TRUSTED_FW_NVCOUNTER_OID) == 0) {
+ uid_num = 3U;
+ } else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) {
+ uid_num = 4U;
+ } else {
+ return 1;
+ }
+ sfp_val = (1U << (nv_ctr - 1));
+
+ if (sfp_write_oem_uid(uid_num, sfp_val) == 1) {
+ /* Enable POVDD on board */
+ if (board_enable_povdd()) {
+ sfp_program_fuses();
+ }
+
+ /* Disable POVDD on board */
+ board_disable_povdd();
+ } else {
+ ERROR("Invalid OEM UID sent.\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+ return get_mbedtls_heap_helper(heap_addr, heap_size);
+}
diff --git a/plat/nxp/common/warm_reset/plat_warm_reset.c b/plat/nxp/common/warm_reset/plat_warm_reset.c
new file mode 100644
index 0000000..966a73c
--- /dev/null
+++ b/plat/nxp/common/warm_reset/plat_warm_reset.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <ddr.h>
+#ifndef NXP_COINED_BB
+#include <flash_info.h>
+#include <fspi.h>
+#include <fspi_api.h>
+#endif
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#ifdef NXP_COINED_BB
+#include <snvs.h>
+#endif
+
+#include <plat_nv_storage.h>
+#include "plat_warm_rst.h"
+#include "platform_def.h"
+
+#if defined(IMAGE_BL2)
+
+uint32_t is_warm_boot(void)
+{
+ uint32_t ret = mmio_read_32(NXP_RESET_ADDR + RST_RSTRQSR1_OFFSET)
+ & ~(RSTRQSR1_SWRR);
+
+ const nv_app_data_t *nv_app_data = get_nv_data();
+
+ if (ret == 0U) {
+ INFO("Not a SW(Warm) triggered reset.\n");
+ return 0U;
+ }
+
+ ret = (nv_app_data->warm_rst_flag == WARM_BOOT_SUCCESS) ? 1 : 0;
+
+ if (ret != 0U) {
+ INFO("Warm Reset was triggered..\n");
+ } else {
+ INFO("Warm Reset was not triggered..\n");
+ }
+
+ return ret;
+}
+
+#endif
+
+#if defined(IMAGE_BL31)
+int prep_n_execute_warm_reset(void)
+{
+#ifdef NXP_COINED_BB
+#if !TRUSTED_BOARD_BOOT
+ snvs_disable_zeroize_lp_gpr();
+#endif
+#else
+ int ret;
+ uint8_t warm_reset = WARM_BOOT_SUCCESS;
+
+ ret = fspi_init(NXP_FLEXSPI_ADDR, NXP_FLEXSPI_FLASH_ADDR);
+
+ if (ret != 0) {
+ ERROR("Failed to initialized driver flexspi-nor.\n");
+ ERROR("exiting warm-reset request.\n");
+ return PSCI_E_INTERN_FAIL;
+ }
+
+ /* Sector starting from NV_STORAGE_BASE_ADDR is already
+ * erased for writing.
+ */
+
+#if (ERLY_WRM_RST_FLG_FLSH_UPDT)
+ ret = xspi_write((uint32_t)NV_STORAGE_BASE_ADDR,
+ &warm_reset,
+ sizeof(warm_reset));
+#else
+ /* Preparation for writing the Warm reset flag. */
+ ret = xspi_wren((uint32_t)NV_STORAGE_BASE_ADDR);
+
+ /* IP Control Register0 - SF Address to be read */
+ fspi_out32((NXP_FLEXSPI_ADDR + FSPI_IPCR0),
+ (uint32_t) NV_STORAGE_BASE_ADDR);
+
+ while ((fspi_in32(NXP_FLEXSPI_ADDR + FSPI_INTR) &
+ FSPI_INTR_IPTXWE_MASK) == 0) {
+ ;
+ }
+ /* Write TX FIFO Data Register */
+ fspi_out32(NXP_FLEXSPI_ADDR + FSPI_TFDR, (uint32_t) warm_reset);
+
+ fspi_out32(NXP_FLEXSPI_ADDR + FSPI_INTR, FSPI_INTR_IPTXWE);
+
+ /* IP Control Register1 - SEQID_WRITE operation, Size = 1 Byte */
+ fspi_out32(NXP_FLEXSPI_ADDR + FSPI_IPCR1,
+ (uint32_t)(FSPI_WRITE_SEQ_ID << FSPI_IPCR1_ISEQID_SHIFT) |
+ (uint16_t) sizeof(warm_reset));
+
+ /* Trigger XSPI-IP-Write cmd only if:
+ * - Putting DDR in-self refresh mode is successfully.
+ * to complete the writing of the warm-reset flag
+ * to flash.
+ *
+ * This code is as part of assembly.
+ */
+#endif
+#endif
+ INFO("Doing DDR Self refresh.\n");
+ _soc_sys_warm_reset();
+
+ /* Expected behaviour is to do the power cycle */
+ while (1 != 0)
+ ;
+
+ return -1;
+}
+#endif
diff --git a/plat/nxp/common/warm_reset/plat_warm_rst.h b/plat/nxp/common/warm_reset/plat_warm_rst.h
new file mode 100644
index 0000000..e0c39c5
--- /dev/null
+++ b/plat/nxp/common/warm_reset/plat_warm_rst.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PLAT_WARM_RST_H
+#define PLAT_WARM_RST_H
+
+#ifndef NXP_COINED_BB
+#define ERLY_WRM_RST_FLG_FLSH_UPDT 0
+#endif
+
+#ifndef __ASSEMBLER__
+
+#if defined(IMAGE_BL2)
+uint32_t is_warm_boot(void);
+#endif
+
+#if defined(IMAGE_BL31)
+int prep_n_execute_warm_reset(void);
+int _soc_sys_warm_reset(void);
+#endif
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* PLAT_WARM_RST_H */
diff --git a/plat/nxp/common/warm_reset/warm_reset.mk b/plat/nxp/common/warm_reset/warm_reset.mk
new file mode 100644
index 0000000..236004f
--- /dev/null
+++ b/plat/nxp/common/warm_reset/warm_reset.mk
@@ -0,0 +1,20 @@
+#
+# Copyright 2020 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-----------------------------------------------------------------------------
+ifeq (${WARM_RST_ADDED},)
+
+WARM_RST_ADDED := 1
+NXP_NV_SW_MAINT_LAST_EXEC_DATA := yes
+
+$(eval $(call add_define,NXP_WARM_BOOT))
+
+
+WARM_RST_INCLUDES += -I${PLAT_COMMON_PATH}/warm_reset
+WARM_RST_BL31_SOURCES += ${PLAT_SOC_PATH}/$(ARCH)/${SOC}_warm_rst.S
+
+WARM_RST_BL_COMM_SOURCES += ${PLAT_COMMON_PATH}/warm_reset/plat_warm_reset.c
+
+endif
diff --git a/plat/nxp/soc-ls1028a/aarch64/ls1028a.S b/plat/nxp/soc-ls1028a/aarch64/ls1028a.S
new file mode 100644
index 0000000..404c39e
--- /dev/null
+++ b/plat/nxp/soc-ls1028a/aarch64/ls1028a.S
@@ -0,0 +1,1387 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+ .section .text, "ax"
+
+#include <asm_macros.S>
+
+#include <lib/psci/psci.h>
+#include <nxp_timer.h>
+#include <plat_gic.h>
+#include <pmu.h>
+
+#include <bl31_data.h>
+#include <plat_psci.h>
+#include <platform_def.h>
+
+ .global soc_init_lowlevel
+ .global soc_init_percpu
+ .global _set_platform_security
+ .global _soc_set_start_addr
+
+ .global _soc_core_release
+ .global _soc_ck_disabled
+ .global _soc_core_restart
+ .global _soc_core_prep_off
+ .global _soc_core_entr_off
+ .global _soc_core_exit_off
+ .global _soc_sys_reset
+ .global _soc_sys_off
+ .global _soc_core_prep_stdby
+ .global _soc_core_entr_stdby
+ .global _soc_core_exit_stdby
+ .global _soc_core_prep_pwrdn
+ .global _soc_core_entr_pwrdn
+ .global _soc_core_exit_pwrdn
+ .global _soc_clstr_prep_stdby
+ .global _soc_clstr_exit_stdby
+ .global _soc_clstr_prep_pwrdn
+ .global _soc_clstr_exit_pwrdn
+ .global _soc_sys_prep_stdby
+ .global _soc_sys_exit_stdby
+ .global _soc_sys_prep_pwrdn
+ .global _soc_sys_pwrdn_wfi
+ .global _soc_sys_exit_pwrdn
+
+ .equ TZPCDECPROT_0_SET_BASE, 0x02200804
+ .equ TZPCDECPROT_1_SET_BASE, 0x02200810
+ .equ TZPCDECPROT_2_SET_BASE, 0x0220081C
+
+ .equ TZASC_REGION_ATTRIBUTES_0_0, 0x01100110
+
+/*
+ * This function initialize the soc.
+ * in: void
+ * out: void
+ * uses x0 - x11
+ */
+func soc_init_lowlevel
+ /*
+ * Called from C, so save the non-volatile regs
+ * save these as pairs of registers to maintain the
+ * required 16-byte alignment on the stack
+ */
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+ stp x8, x9, [sp, #-16]!
+ stp x10, x11, [sp, #-16]!
+ stp x12, x13, [sp, #-16]!
+ stp x18, x30, [sp, #-16]!
+
+ /*
+ * Make sure the personality has been established by releasing cores
+ * that are marked "to-be-disabled" from reset
+ */
+ bl release_disabled /* 0-8 */
+
+ /* Set SCRATCHRW7 to 0x0 */
+ ldr x0, =DCFG_SCRATCHRW7_OFFSET
+ mov x1, xzr
+ bl _write_reg_dcfg
+
+ /* Restore the aarch32/64 non-volatile registers */
+ ldp x18, x30, [sp], #16
+ ldp x12, x13, [sp], #16
+ ldp x10, x11, [sp], #16
+ ldp x8, x9, [sp], #16
+ ldp x6, x7, [sp], #16
+ ldp x4, x5, [sp], #16
+ ret
+endfunc soc_init_lowlevel
+
+/*
+ * void soc_init_percpu(void)
+ *
+ * This function performs any soc-specific initialization that is needed on
+ * a per-core basis
+ * in: none
+ * out: none
+ * uses x0 - x3
+ */
+func soc_init_percpu
+ stp x4, x30, [sp, #-16]!
+
+ bl plat_my_core_mask
+ mov x2, x0
+
+ /* x2 = core mask */
+
+ /* see if this core is marked for prefetch disable */
+ mov x0, #PREFETCH_DIS_OFFSET
+ bl _get_global_data /* 0-1 */
+ tst x0, x2
+ b.eq 1f
+ bl _disable_ldstr_pfetch_A72 /* 0 */
+1:
+ mov x0, #NXP_PMU_ADDR
+ bl enable_timer_base_to_cluster
+
+ ldp x4, x30, [sp], #16
+ ret
+endfunc soc_init_percpu
+
+/*
+ * This function determines if a core is disabled via COREDISABLEDSR
+ * in: w0 = core_mask_lsb
+ * out: w0 = 0, core not disabled
+ * w0 != 0, core disabled
+ * uses x0, x1
+ */
+func _soc_ck_disabled
+ /* get base addr of dcfg block */
+ ldr x1, =NXP_DCFG_ADDR
+
+ /* read COREDISABLEDSR */
+ ldr w1, [x1, #DCFG_COREDISABLEDSR_OFFSET]
+
+ /* test core bit */
+ and w0, w1, w0
+
+ ret
+endfunc _soc_ck_disabled
+
+/*
+ * This function sets the security mechanisms in the SoC to implement the
+ * Platform Security Policy
+ */
+func _set_platform_security
+ mov x3, x30
+
+#if (!SUPPRESS_TZC)
+ /* initialize the tzpc */
+ bl init_tzpc
+#endif
+
+#if (!SUPPRESS_SEC)
+ /* initialize secmon */
+ bl initSecMon
+#endif
+
+ mov x30, x3
+ ret
+endfunc _set_platform_security
+
+/*
+ * Part of CPU_ON
+ *
+ * This function releases a secondary core from reset
+ * in: x0 = core_mask_lsb
+ * out: none
+ * uses: x0 - x3
+ */
+_soc_core_release:
+ mov x3, x30
+
+ /*
+ * Write to CORE_HOLD to tell the bootrom that we want this core
+ * to run
+ */
+ ldr x1, =NXP_SEC_REGFILE_ADDR
+ str w0, [x1, #CORE_HOLD_OFFSET]
+
+ /* Read-modify-write BRRL to release core */
+ mov x1, #NXP_RESET_ADDR
+ ldr w2, [x1, #BRR_OFFSET]
+ orr w2, w2, w0
+ str w2, [x1, #BRR_OFFSET]
+ dsb sy
+ isb
+
+ /* Send event */
+ sev
+ isb
+
+ mov x30, x3
+ ret
+
+/*
+ * This function writes a 64-bit address to bootlocptrh/l
+ * in: x0, 64-bit address to write to BOOTLOCPTRL/H
+ * uses x0, x1, x2
+ */
+func _soc_set_start_addr
+ /* Get the 64-bit base address of the dcfg block */
+ ldr x2, =NXP_DCFG_ADDR
+
+ /* Write the 32-bit BOOTLOCPTRL register */
+ mov x1, x0
+ str w1, [x2, #DCFG_BOOTLOCPTRL_OFFSET]
+
+ /* Write the 32-bit BOOTLOCPTRH register */
+ lsr x1, x0, #32
+ str w1, [x2, #DCFG_BOOTLOCPTRH_OFFSET]
+ ret
+endfunc _soc_set_start_addr
+
+/*
+ * Part of CPU_ON
+ *
+ * This function restarts a core shutdown via _soc_core_entr_off
+ * in: x0 = core mask lsb (of the target cpu)
+ * out: x0 == 0, on success
+ * x0 != 0, on failure
+ * uses x0 - x6
+ */
+_soc_core_restart:
+ mov x6, x30
+ mov x4, x0
+
+ /* pgm GICD_CTLR - enable secure grp0 */
+ mov x5, #NXP_GICD_ADDR
+ ldr w2, [x5, #GICD_CTLR_OFFSET]
+ orr w2, w2, #GICD_CTLR_EN_GRP_0
+ str w2, [x5, #GICD_CTLR_OFFSET]
+ dsb sy
+ isb
+
+ /* Poll on RWP til write completes */
+4:
+ ldr w2, [x5, #GICD_CTLR_OFFSET]
+ tst w2, #GICD_CTLR_RWP
+ b.ne 4b
+
+ /*
+ * x4 = core mask lsb
+ * x5 = gicd base addr
+ */
+
+ mov x0, x4
+ bl get_mpidr_value
+
+ /* Generate target list bit */
+ and x1, x0, #MPIDR_AFFINITY0_MASK
+ mov x2, #1
+ lsl x2, x2, x1
+
+ /* Get the affinity1 field */
+ and x1, x0, #MPIDR_AFFINITY1_MASK
+ lsl x1, x1, #8
+ orr x2, x2, x1
+
+ /* Insert the INTID for SGI15 */
+ orr x2, x2, #ICC_SGI0R_EL1_INTID
+
+ /* Fire the SGI */
+ msr ICC_SGI0R_EL1, x2
+ dsb sy
+ isb
+
+ /* Load '0' on success */
+ mov x0, xzr
+
+ mov x30, x6
+ ret
+
+/*
+ * Part of CPU_OFF
+ *
+ * This function programs SoC & GIC registers in preparation for shutting down
+ * the core
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0 - x7
+ */
+_soc_core_prep_off:
+ mov x8, x30
+ mov x7, x0
+
+ /* x7 = core mask lsb */
+
+ mrs x1, CPUECTLR_EL1
+
+ /* Set smp and disable L2 snoops in cpuectlr */
+ orr x1, x1, #CPUECTLR_SMPEN_EN
+ orr x1, x1, #CPUECTLR_DISABLE_TWALK_PREFETCH
+ bic x1, x1, #CPUECTLR_INS_PREFETCH_MASK
+ bic x1, x1, #CPUECTLR_DAT_PREFETCH_MASK
+
+ /* Set retention control in cpuectlr */
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ orr x1, x1, #CPUECTLR_TIMER_2TICKS
+ msr CPUECTLR_EL1, x1
+
+ /* Get redistributor rd base addr for this core */
+ mov x0, x7
+ bl get_gic_rd_base
+ mov x6, x0
+
+ /* Get redistributor sgi base addr for this core */
+ mov x0, x7
+ bl get_gic_sgi_base
+ mov x5, x0
+
+ /*
+ * x5 = gicr sgi base addr
+ * x6 = gicr rd base addr
+ * x7 = core mask lsb
+ */
+
+ /* Disable SGI 15 at redistributor - GICR_ICENABLER0 */
+ mov w3, #GICR_ICENABLER0_SGI15
+ str w3, [x5, #GICR_ICENABLER0_OFFSET]
+2:
+ /* Poll on rwp bit in GICR_CTLR */
+ ldr w4, [x6, #GICR_CTLR_OFFSET]
+ tst w4, #GICR_CTLR_RWP
+ b.ne 2b
+
+ /* Disable GRP1 interrupts at cpu interface */
+ msr ICC_IGRPEN1_EL3, xzr
+
+ /* Disable GRP0 ints at cpu interface */
+ msr ICC_IGRPEN0_EL1, xzr
+
+ /* Program the redistributor - poll on GICR_CTLR.RWP as needed */
+
+ /* Define SGI 15 as Grp0 - GICR_IGROUPR0 */
+ ldr w4, [x5, #GICR_IGROUPR0_OFFSET]
+ bic w4, w4, #GICR_IGROUPR0_SGI15
+ str w4, [x5, #GICR_IGROUPR0_OFFSET]
+
+ /* Define SGI 15 as Grp0 - GICR_IGRPMODR0 */
+ ldr w3, [x5, #GICR_IGRPMODR0_OFFSET]
+ bic w3, w3, #GICR_IGRPMODR0_SGI15
+ str w3, [x5, #GICR_IGRPMODR0_OFFSET]
+
+ /* Set priority of SGI 15 to highest (0x0) - GICR_IPRIORITYR3 */
+ ldr w4, [x5, #GICR_IPRIORITYR3_OFFSET]
+ bic w4, w4, #GICR_IPRIORITYR3_SGI15_MASK
+ str w4, [x5, #GICR_IPRIORITYR3_OFFSET]
+
+ /* Enable SGI 15 at redistributor - GICR_ISENABLER0 */
+ mov w3, #GICR_ISENABLER0_SGI15
+ str w3, [x5, #GICR_ISENABLER0_OFFSET]
+ dsb sy
+ isb
+3:
+ /* Poll on rwp bit in GICR_CTLR */
+ ldr w4, [x6, #GICR_CTLR_OFFSET]
+ tst w4, #GICR_CTLR_RWP
+ b.ne 3b
+
+ /* Quiesce the debug interfaces */
+ mrs x3, osdlr_el1
+ orr x3, x3, #OSDLR_EL1_DLK_LOCK
+ msr osdlr_el1, x3
+ isb
+
+ /* Enable grp0 ints */
+ mov x3, #ICC_IGRPEN0_EL1_EN
+ msr ICC_IGRPEN0_EL1, x3
+
+ /*
+ * x5 = gicr sgi base addr
+ * x6 = gicr rd base addr
+ * x7 = core mask lsb
+ */
+
+ /* Clear any pending interrupts */
+ mvn w1, wzr
+ str w1, [x5, #GICR_ICPENDR0_OFFSET]
+
+ /* Make sure system counter is enabled */
+ ldr x3, =NXP_TIMER_ADDR
+ ldr w0, [x3, #SYS_COUNTER_CNTCR_OFFSET]
+ tst w0, #SYS_COUNTER_CNTCR_EN
+ b.ne 4f
+ orr w0, w0, #SYS_COUNTER_CNTCR_EN
+ str w0, [x3, #SYS_COUNTER_CNTCR_OFFSET]
+4:
+ /* Enable the core timer and mask timer interrupt */
+ mov x1, #CNTP_CTL_EL0_EN
+ orr x1, x1, #CNTP_CTL_EL0_IMASK
+ msr cntp_ctl_el0, x1
+
+ isb
+ mov x30, x8
+ ret
+
+/*
+ * Part of CPU_OFF
+ *
+ * This function performs the final steps to shutdown the core
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0 - x5
+ */
+_soc_core_entr_off:
+ mov x5, x30
+ mov x4, x0
+
+ /* x4 = core mask */
+1:
+ /* Enter low-power state by executing wfi */
+ wfi
+
+ /* See if SGI15 woke us up */
+ mrs x2, ICC_IAR0_EL1
+ mov x3, #ICC_IAR0_EL1_SGI15
+ cmp x2, x3
+ b.ne 1b
+
+ /* Deactivate the int */
+ msr ICC_EOIR0_EL1, x2
+
+ /* x4 = core mask */
+2:
+ /* Check if core has been turned on */
+ mov x0, x4
+ bl _getCoreState
+
+ /* x0 = core state */
+
+ cmp x0, #CORE_WAKEUP
+ b.ne 1b
+
+ /* If we get here, then we have exited the wfi */
+ mov x30, x5
+ ret
+
+/*
+ * Part of CPU_OFF
+ *
+ * This function starts the process of starting a core back up
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6
+ */
+_soc_core_exit_off:
+ mov x6, x30
+ mov x5, x0
+
+ /* Disable forwarding of GRP0 ints at cpu interface */
+ msr ICC_IGRPEN0_EL1, xzr
+
+ /* Get redistributor sgi base addr for this core */
+ mov x0, x5
+ bl get_gic_sgi_base
+ mov x4, x0
+
+ /* x4 = gicr sgi base addr */
+ /* x5 = core mask */
+
+ /* Disable SGI 15 at redistributor - GICR_ICENABLER0 */
+ mov w1, #GICR_ICENABLER0_SGI15
+ str w1, [x4, #GICR_ICENABLER0_OFFSET]
+
+ /* Get redistributor rd base addr for this core */
+ mov x0, x5
+ bl get_gic_rd_base
+ mov x4, x0
+
+ /* x4 = gicr rd base addr */
+2:
+ /* Poll on rwp bit in GICR_CTLR */
+ ldr w2, [x4, #GICR_CTLR_OFFSET]
+ tst w2, #GICR_CTLR_RWP
+ b.ne 2b
+
+ /* x4 = gicr rd base addr */
+
+ /* Unlock the debug interfaces */
+ mrs x3, osdlr_el1
+ bic x3, x3, #OSDLR_EL1_DLK_LOCK
+ msr osdlr_el1, x3
+ isb
+
+ dsb sy
+ isb
+ mov x30, x6
+ ret
+
+/*
+ * This function requests a reset of the entire SOC
+ * in: none
+ * out: none
+ * uses: x0, x1, x2, x3, x4, x5, x6
+ */
+_soc_sys_reset:
+ mov x3, x30
+
+ /* Make sure the mask is cleared in the reset request mask register */
+ mov x0, #RST_RSTRQMR1_OFFSET
+ mov w1, wzr
+ bl _write_reg_reset
+
+ /* Set the reset request */
+ mov x4, #RST_RSTCR_OFFSET
+ mov x0, x4
+ mov w1, #RSTCR_RESET_REQ
+ bl _write_reg_reset
+
+ /* x4 = RST_RSTCR_OFFSET */
+
+ /*
+ * Just in case this address range is mapped as cacheable,
+ * flush the write out of the dcaches
+ */
+ mov x2, #NXP_RESET_ADDR
+ add x2, x2, x4
+ dc cvac, x2
+ dsb st
+ isb
+
+ /* This function does not return */
+1:
+ wfi
+ b 1b
+
+/*
+ * Part of SYSTEM_OFF
+ *
+ * This function turns off the SoC clocks
+ * Note: this function is not intended to return, and the only allowable
+ * recovery is POR
+ * in: none
+ * out: none
+ * uses x0, x1, x2, x3
+ */
+_soc_sys_off:
+ /*
+ * Disable sec, spi and flexspi
+ * TBD - Check if eNETC needs to be disabled
+ */
+ ldr x2, =NXP_DCFG_ADDR
+ ldr x0, =DCFG_DEVDISR1_OFFSET
+ ldr w1, =DCFG_DEVDISR1_SEC
+ str w1, [x2, x0]
+ ldr x0, =DCFG_DEVDISR4_OFFSET
+ ldr w1, =DCFG_DEVDISR4_SPI_QSPI
+ str w1, [x2, x0]
+
+ /* Set TPMWAKEMR0 */
+ ldr x0, =TPMWAKEMR0_ADDR
+ mov w1, #0x1
+ str w1, [x0]
+
+ /* Disable icache, dcache, mmu @ EL1 */
+ mov x1, #SCTLR_I_C_M_MASK
+ mrs x0, sctlr_el1
+ bic x0, x0, x1
+ msr sctlr_el1, x0
+
+ /* Disable L2 prefetches */
+ mrs x0, CPUECTLR_EL1
+ orr x0, x0, #CPUECTLR_SMPEN_EN
+ bic x0, x0, #CPUECTLR_TIMER_MASK
+ orr x0, x0, #CPUECTLR_TIMER_2TICKS
+ msr CPUECTLR_EL1, x0
+ dsb sy
+ isb
+
+ /* Disable CCI snoop domain */
+ ldr x0, =NXP_CCI_ADDR
+ mov w1, #0x1
+ str w1, [x0]
+
+ bl get_pmu_idle_core_mask
+
+ /* x3 = pmu base addr */
+ mov x3, #NXP_PMU_ADDR
+4:
+ ldr w1, [x3, #PMU_PCPW20SR_OFFSET]
+ cmp w1, w0
+ b.ne 4b
+
+ bl get_pmu_idle_cluster_mask
+ mov x3, #NXP_PMU_ADDR
+ str w0, [x3, #PMU_CLAINACTSETR_OFFSET]
+
+ bl get_pmu_idle_core_mask
+ mov x3, #NXP_PMU_ADDR
+1:
+ ldr w1, [x3, #PMU_PCPW20SR_OFFSET]
+ cmp w1, w0
+ b.ne 1b
+
+ bl get_pmu_flush_cluster_mask
+ mov x3, #NXP_PMU_ADDR
+ str w0, [x3, #PMU_CLL2FLUSHSETR_OFFSET]
+2:
+ ldr w1, [x3, #PMU_CLL2FLUSHSR_OFFSET]
+ cmp w1, w0
+ b.ne 2b
+
+ str w0, [x3, #PMU_CLSL2FLUSHCLRR_OFFSET]
+
+ str w0, [x3, #PMU_CLSINACTSETR_OFFSET]
+
+ mov x2, #DAIF_SET_MASK
+ mrs x1, spsr_el1
+ orr x1, x1, x2
+ msr spsr_el1, x1
+
+ mrs x1, spsr_el2
+ orr x1, x1, x2
+ msr spsr_el2, x1
+
+ /* Force the debug interface to be quiescent */
+ mrs x0, osdlr_el1
+ orr x0, x0, #0x1
+ msr osdlr_el1, x0
+
+ /* Invalidate all TLB entries at all 3 exception levels */
+ tlbi alle1
+ tlbi alle2
+ tlbi alle3
+
+ /* x3 = pmu base addr */
+
+ /* Request lpm20 */
+ ldr x0, =PMU_POWMGTCSR_OFFSET
+ ldr w1, =PMU_POWMGTCSR_VAL
+ str w1, [x3, x0]
+ isb
+ dsb sy
+5:
+ wfe
+ b.eq 5b
+
+/*
+ * Part of CPU_SUSPEND
+ *
+ * This function performs SoC-specific programming prior to standby
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+_soc_core_prep_stdby:
+ /* Clear CPUECTLR_EL1[2:0] */
+ mrs x1, CPUECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ msr CPUECTLR_EL1, x1
+
+ ret
+
+/*
+ * Part of CPU_SUSPEND
+ *
+ * This function puts the calling core into standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0
+ */
+_soc_core_entr_stdby:
+ /* X0 = core mask lsb */
+ dsb sy
+ isb
+ wfi
+
+ ret
+
+/*
+ * Part of CPU_SUSPEND
+ *
+ * This function performs any SoC-specific cleanup after standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+_soc_core_exit_stdby:
+ ret
+
+/*
+ * Part of CPU_SUSPEND
+ *
+ * This function performs SoC-specific programming prior to power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2
+ */
+_soc_core_prep_pwrdn:
+ /* Make sure system counter is enabled */
+ ldr x2, =NXP_TIMER_ADDR
+ ldr w0, [x2, #SYS_COUNTER_CNTCR_OFFSET]
+ tst w0, #SYS_COUNTER_CNTCR_EN
+ b.ne 1f
+ orr w0, w0, #SYS_COUNTER_CNTCR_EN
+ str w0, [x2, #SYS_COUNTER_CNTCR_OFFSET]
+1:
+ /*
+ * Enable dynamic retention control (CPUECTLR[2:0])
+ * Set the SMPEN bit (CPUECTLR[6])
+ */
+ mrs x1, CPUECTLR_EL1
+ bic x1, x1, #CPUECTLR_RET_MASK
+ orr x1, x1, #CPUECTLR_TIMER_2TICKS
+ orr x1, x1, #CPUECTLR_SMPEN_EN
+ msr CPUECTLR_EL1, x1
+
+ isb
+ ret
+
+/*
+ * Part of CPU_SUSPEND
+ *
+ * This function puts the calling core into a power-down state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0
+ */
+_soc_core_entr_pwrdn:
+ /* X0 = core mask lsb */
+ dsb sy
+ isb
+ wfi
+
+ ret
+
+/*
+ * Part of CPU_SUSPEND
+ *
+ * This function performs any SoC-specific cleanup after power-down state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+_soc_core_exit_pwrdn:
+ ret
+
+/*
+ * Part of CPU_SUSPEND
+ *
+ * This function performs SoC-specific programming prior to standby
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+_soc_clstr_prep_stdby:
+ /* Clear CPUECTLR_EL1[2:0] */
+ mrs x1, CPUECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ msr CPUECTLR_EL1, x1
+
+ ret
+
+/*
+ * Part of CPU_SUSPEND
+ *
+ * This function performs any SoC-specific cleanup after standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+_soc_clstr_exit_stdby:
+ ret
+
+/*
+ * Part of CPU_SUSPEND
+ *
+ * This function performs SoC-specific programming prior to power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2
+ */
+_soc_clstr_prep_pwrdn:
+ /* Make sure system counter is enabled */
+ ldr x2, =NXP_TIMER_ADDR
+ ldr w0, [x2, #SYS_COUNTER_CNTCR_OFFSET]
+ tst w0, #SYS_COUNTER_CNTCR_EN
+ b.ne 1f
+ orr w0, w0, #SYS_COUNTER_CNTCR_EN
+ str w0, [x2, #SYS_COUNTER_CNTCR_OFFSET]
+1:
+ /*
+ * Enable dynamic retention control (CPUECTLR[2:0])
+ * Set the SMPEN bit (CPUECTLR[6])
+ */
+ mrs x1, CPUECTLR_EL1
+ bic x1, x1, #CPUECTLR_RET_MASK
+ orr x1, x1, #CPUECTLR_TIMER_2TICKS
+ orr x1, x1, #CPUECTLR_SMPEN_EN
+ msr CPUECTLR_EL1, x1
+
+ isb
+ ret
+
+/*
+ * Part of CPU_SUSPEND
+ *
+ * This function performs any SoC-specific cleanup after power-down state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+_soc_clstr_exit_pwrdn:
+ ret
+
+/*
+ * Part of CPU_SUSPEND
+ *
+ * This function performs SoC-specific programming prior to standby
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+_soc_sys_prep_stdby:
+ /* Clear CPUECTLR_EL1[2:0] */
+ mrs x1, CPUECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ msr CPUECTLR_EL1, x1
+
+ ret
+
+/*
+ * Part of CPU_SUSPEND
+ *
+ * This function performs any SoC-specific cleanup after standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+_soc_sys_exit_stdby:
+ ret
+
+/*
+ * Part of CPU_SUSPEND
+ *
+ * This function performs SoC-specific programming prior to
+ * suspend-to-power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4
+ */
+_soc_sys_prep_pwrdn:
+ /* Set retention control */
+ mrs x0, CPUECTLR_EL1
+ bic x0, x0, #CPUECTLR_TIMER_MASK
+ orr x0, x0, #CPUECTLR_TIMER_2TICKS
+ orr x0, x0, #CPUECTLR_SMPEN_EN
+ msr CPUECTLR_EL1, x0
+ dsb sy
+ isb
+ ret
+
+/*
+ * Part of CPU_SUSPEND
+ *
+ * This function puts the calling core, and potentially the soc, into a
+ * low-power state
+ * in: x0 = core mask lsb
+ * out: x0 = 0, success
+ * x0 < 0, failure
+ * uses x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x13, x14, x15,
+ * x16, x17, x18
+ */
+_soc_sys_pwrdn_wfi:
+ mov x18, x30
+
+ mov x3, #NXP_PMU_ADDR
+
+ /* x3 = pmu base addr */
+
+ /* Backup epu registers to stack */
+ ldr x2, =NXP_EPU_ADDR
+ ldr w4, [x2, #EPU_EPIMCR10_OFFSET]
+ ldr w5, [x2, #EPU_EPCCR10_OFFSET]
+ ldr w6, [x2, #EPU_EPCTR10_OFFSET]
+ ldr w7, [x2, #EPU_EPGCR_OFFSET]
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+
+ /*
+ * x2 = epu base addr
+ * x3 = pmu base addr
+ */
+
+ /* Set up EPU event to receive the wake signal from PMU */
+ mov w4, #EPU_EPIMCR10_VAL
+ mov w5, #EPU_EPCCR10_VAL
+ mov w6, #EPU_EPCTR10_VAL
+ mov w7, #EPU_EPGCR_VAL
+ str w4, [x2, #EPU_EPIMCR10_OFFSET]
+ str w5, [x2, #EPU_EPCCR10_OFFSET]
+ str w6, [x2, #EPU_EPCTR10_OFFSET]
+ str w7, [x2, #EPU_EPGCR_OFFSET]
+
+ ldr x2, =NXP_GICD_ADDR
+
+ /*
+ * x2 = gicd base addr
+ * x3 = pmu base addr
+ */
+
+ /* Backup flextimer/mmc/usb interrupt router */
+ ldr x0, =GICD_IROUTER60_OFFSET
+ ldr x1, =GICD_IROUTER76_OFFSET
+ ldr w4, [x2, x0]
+ ldr w5, [x2, x1]
+ ldr x0, =GICD_IROUTER112_OFFSET
+ ldr x1, =GICD_IROUTER113_OFFSET
+ ldr w6, [x2, x0]
+ ldr w7, [x2, x1]
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+
+ /*
+ * x2 = gicd base addr
+ * x3 = pmu base addr
+ * x0 = GICD_IROUTER112_OFFSET
+ * x1 = GICD_IROUTER113_OFFSET
+ */
+
+ /* Re-route interrupt to cluster 1 */
+ ldr w4, =GICD_IROUTER_VALUE
+ str w4, [x2, x0]
+ str w4, [x2, x1]
+ ldr x0, =GICD_IROUTER60_OFFSET
+ ldr x1, =GICD_IROUTER76_OFFSET
+ str w4, [x2, x0]
+ str w4, [x2, x1]
+ dsb sy
+ isb
+
+ /* x3 = pmu base addr */
+
+ /* Disable sec, Check for eNETC, spi and qspi */
+ ldr x2, =NXP_DCFG_ADDR
+ ldr x0, =DCFG_DEVDISR1_OFFSET
+ ldr w1, =DCFG_DEVDISR1_SEC
+ str w1, [x2, x0]
+
+ ldr x0, =DCFG_DEVDISR4_OFFSET
+ ldr w1, =DCFG_DEVDISR4_SPI_QSPI
+ str w1, [x2, x0]
+
+ /* x3 = pmu base addr */
+
+ /* Set TPMWAKEMR0 */
+ ldr x0, =TPMWAKEMR0_ADDR
+ mov w1, #0x1
+ str w1, [x0]
+
+ /* Disable CCI snoop domain */
+ ldr x0, =NXP_CCI_ADDR
+ mov w1, #0x1
+ str w1, [x0]
+
+ /* Setup retention control */
+ mrs x0, CPUECTLR_EL1
+ orr x0, x0, #CPUECTLR_SMPEN_EN
+ orr x0, x0, #CPUECTLR_TIMER_2TICKS
+ msr CPUECTLR_EL1, x0
+ dsb sy
+ isb
+
+ bl get_pmu_idle_core_mask
+ mov x3, #NXP_PMU_ADDR
+8:
+ ldr w1, [x3, #PMU_PCPW20SR_OFFSET]
+ cmp w1, w0
+ b.ne 8b
+
+ /* x3 = NXP_PMU_ADDR */
+ /* 1 cluster SoC */
+
+ bl get_pmu_idle_cluster_mask
+ mov x3, #NXP_PMU_ADDR
+
+ str w0, [x3, #PMU_CLAINACTSETR_OFFSET]
+
+ bl get_pmu_idle_core_mask
+ /* x3 = NXP_PMU_ADDR */
+ mov x3, #NXP_PMU_ADDR
+1:
+ ldr w1, [x3, #PMU_PCPW20SR_OFFSET]
+ cmp w1, w0
+ b.ne 1b
+
+ /* x3 = NXP_PMU_ADDR */
+ bl get_pmu_flush_cluster_mask
+ mov x3, #NXP_PMU_ADDR
+
+ str w0, [x3, #PMU_CLL2FLUSHSETR_OFFSET]
+
+ /* x3 = NXP_PMU_ADDR */
+2:
+ ldr w1, [x3, #PMU_CLL2FLUSHSR_OFFSET]
+ cmp w1, w0
+ b.ne 2b
+
+ /* x3 = NXP_PMU_ADDR */
+
+ str w0, [x3, #PMU_CLSL2FLUSHCLRR_OFFSET]
+
+ str w0, [x3, #PMU_CLSINACTSETR_OFFSET]
+
+ /* Force the debug interface to be quiescent */
+ mrs x0, osdlr_el1
+ orr x0, x0, #0x1
+ msr osdlr_el1, x0
+
+ /*
+ * Enable the WakeRequest signal
+ * x3 is cpu mask starting from cpu1 to cpu0
+ */
+ bl get_tot_num_cores
+ sub x0, x0, #1
+ mov x3, #0x1
+ lsl x3, x3, x0
+2:
+ mov x0, x3
+ bl get_gic_rd_base // 0-2
+ ldr w1, [x0, #GICR_WAKER_OFFSET]
+ orr w1, w1, #GICR_WAKER_SLEEP_BIT
+ str w1, [x0, #GICR_WAKER_OFFSET]
+1:
+ ldr w1, [x0, #GICR_WAKER_OFFSET]
+ cmp w1, #GICR_WAKER_ASLEEP
+ b.ne 1b
+
+ lsr x3, x3, #1
+ cbnz x3, 2b
+
+ /* Invalidate all TLB entries at all 3 exception levels */
+ tlbi alle1
+ tlbi alle2
+ tlbi alle3
+
+ /* Request lpm20 */
+ mov x3, #NXP_PMU_ADDR
+ ldr x0, =PMU_POWMGTCSR_OFFSET
+ ldr w1, =PMU_POWMGTCSR_VAL
+ str w1, [x3, x0]
+
+ ldr x5, =NXP_EPU_ADDR
+4:
+ wfe
+ ldr w1, [x5, #EPU_EPCTR10_OFFSET]
+ cmp w1, #0
+ b.eq 4b
+
+ /* x3 = NXP_PMU_ADDR */
+
+ bl get_pmu_idle_cluster_mask
+ mov x3, NXP_PMU_ADDR
+
+ /* Re-enable the GPP ACP */
+ str w0, [x3, #PMU_CLAINACTCLRR_OFFSET]
+ str w0, [x3, #PMU_CLSINACTCLRR_OFFSET]
+
+ /* x3 = NXP_PMU_ADDR */
+3:
+ ldr w1, [x3, #PMU_CLAINACTSETR_OFFSET]
+ cbnz w1, 3b
+4:
+ ldr w1, [x3, #PMU_CLSINACTSETR_OFFSET]
+ cbnz w1, 4b
+
+ /*
+ * Enable the WakeRequest signal on cpu 0-1
+ * x3 is cpu mask starting from cpu1
+ */
+ bl get_tot_num_cores
+ sub x0, x0, #1
+ mov x3, #0x1
+ lsl x3, x3, x0
+2:
+ mov x0, x3
+ bl get_gic_rd_base // 0-2
+ ldr w1, [x0, #GICR_WAKER_OFFSET]
+ bic w1, w1, #GICR_WAKER_SLEEP_BIT
+ str w1, [x0, #GICR_WAKER_OFFSET]
+1:
+ ldr w1, [x0, #GICR_WAKER_OFFSET]
+ cbnz w1, 1b
+
+ lsr x3, x3, #1
+ cbnz x3, 2b
+
+ /* Enable CCI snoop domain */
+ ldr x0, =NXP_CCI_ADDR
+ str wzr, [x0]
+ dsb sy
+ isb
+
+ ldr x3, =NXP_EPU_ADDR
+
+ /* x3 = epu base addr */
+
+ /* Enable sec, enetc, spi and qspi */
+ ldr x2, =NXP_DCFG_ADDR
+ str wzr, [x2, #DCFG_DEVDISR1_OFFSET]
+ str wzr, [x2, #DCFG_DEVDISR2_OFFSET]
+ str wzr, [x2, #DCFG_DEVDISR4_OFFSET]
+
+ /* Restore flextimer/mmc/usb interrupt router */
+ ldr x3, =NXP_GICD_ADDR
+ ldp x0, x2, [sp], #16
+ ldr x1, =GICD_IROUTER113_OFFSET
+ str w2, [x3, x1]
+ ldr x1, =GICD_IROUTER112_OFFSET
+ str w0, [x3, x1]
+ ldp x0, x2, [sp], #16
+ ldr x1, =GICD_IROUTER76_OFFSET
+ str w2, [x3, x1]
+ ldr x1, =GICD_IROUTER60_OFFSET
+ str w0, [x3, x1]
+
+ /* Restore EPU registers */
+ ldr x3, =NXP_EPU_ADDR
+ ldp x0, x2, [sp], #16
+ str w2, [x3, #EPU_EPGCR_OFFSET]
+ str w0, [x3, #EPU_EPCTR10_OFFSET]
+ ldp x2, x1, [sp], #16
+ str w1, [x3, #EPU_EPCCR10_OFFSET]
+ str w2, [x3, #EPU_EPIMCR10_OFFSET]
+
+ dsb sy
+ isb
+ mov x30, x18
+ ret
+
+/*
+ * Part of CPU_SUSPEND
+ *
+ * This function performs any SoC-specific cleanup after power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+_soc_sys_exit_pwrdn:
+ /* Enable stack alignment checking */
+ mrs x1, SCTLR_EL1
+ orr x1, x1, #0x4
+ msr SCTLR_EL1, x1
+
+ /* Enable debug interface */
+ mrs x1, osdlr_el1
+ bic x1, x1, #OSDLR_EL1_DLK_LOCK
+ msr osdlr_el1, x1
+
+ /* Enable i-cache */
+ mrs x1, SCTLR_EL3
+ orr x1, x1, #SCTLR_I_MASK
+ msr SCTLR_EL3, x1
+
+ isb
+ ret
+
+/*
+ * This function setc up the TrustZone Address Space Controller (TZASC)
+ * in: none
+ * out: none
+ * uses x0, x1
+ */
+init_tzpc:
+ /* Set Non Secure access for all devices protected via TZPC */
+ ldr x1, =TZPCDECPROT_0_SET_BASE /* decode Protection-0 Set Reg */
+ mov w0, #0xFF /* set decode region to NS, Bits[7:0] */
+ str w0, [x1]
+
+ ldr x1, =TZPCDECPROT_1_SET_BASE /* decode Protection-1 Set Reg */
+ mov w0, #0xFF /* set decode region to NS, Bits[7:0] */
+ str w0, [x1]
+
+ ldr x1, =TZPCDECPROT_2_SET_BASE /* decode Protection-2 Set Reg */
+ mov w0, #0xFF /* set decode region to NS, Bits[7:0] */
+ str w0, [x1]
+
+ /* entire SRAM as NS */
+ ldr x1, =NXP_OCRAM_TZPC_ADDR /* secure RAM region size Reg */
+ mov w0, #0x00000000 /* 0x00000000 = no secure region */
+ str w0, [x1]
+
+ ret
+
+/*
+ * This function performs any needed initialization on SecMon for
+ * boot services
+ */
+initSecMon:
+ /* Read the register hpcomr */
+ ldr x1, =NXP_SNVS_ADDR
+ ldr w0, [x1, #SECMON_HPCOMR_OFFSET]
+ /* Turn off secure access for the privileged registers */
+ orr w0, w0, #SECMON_HPCOMR_NPSWAEN
+ /* Write back */
+ str w0, [x1, #SECMON_HPCOMR_OFFSET]
+
+ ret
+
+/*
+ * This function checks to see if cores which are to be disabled have been
+ * released from reset - if not, it releases them
+ * in: none
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6, x7, x8
+ */
+release_disabled:
+ stp x18, x30, [sp, #-16]!
+
+ /*
+ * Get the number of cpus on this device
+ * Calling the below c function.
+ * No need to Callee saved registers x9-x15,
+ * as these registers are not used by the callee
+ * prior to calling the below C-routine.
+ */
+ bl get_tot_num_cores
+ mov x6, x0
+
+ /* Read COREDISABLESR */
+ mov x0, #NXP_DCFG_ADDR
+ ldr w4, [x0, #DCFG_COREDISABLEDSR_OFFSET]
+
+ mov x0, #NXP_RESET_ADDR
+ ldr w5, [x0, #BRR_OFFSET]
+
+ /* Load the core mask for the first core */
+ mov x7, #1
+
+ /*
+ * x4 = COREDISABLESR
+ * x5 = BRR
+ * x6 = loop count
+ * x7 = core mask bit
+ */
+2:
+ /* Check if the core is to be disabled */
+ tst x4, x7
+ b.eq 1f
+
+ /* See if disabled cores have already been released from reset */
+ tst x5, x7
+ b.ne 1f
+
+ /* If core has not been released, then release it (0-3) */
+ mov x0, x7
+ bl _soc_core_release
+
+ /* Record the core state in the data area (0-3) */
+ mov x0, x7
+ mov x1, #CORE_DISABLED
+ bl _setCoreState
+1:
+ /* Decrement the counter */
+ subs x6, x6, #1
+ b.le 3f
+ /* Shift the core mask to the next core */
+ lsl x7, x7, #1
+ /* Continue */
+ b 2b
+3:
+ ldp x18, x30, [sp], #16
+ ret
+
+/*
+ * Write a register in the DCFG block
+ * in: x0 = offset
+ * in: w1 = value to write
+ * uses x0, x1, x2
+ */
+_write_reg_dcfg:
+ ldr x2, =NXP_DCFG_ADDR
+ str w1, [x2, x0]
+ ret
+
+/*
+ * Read a register in the DCFG block
+ * in: x0 = offset
+ * out: w0 = value read
+ * uses x0, x1, x2
+ */
+_read_reg_dcfg:
+ ldr x2, =NXP_DCFG_ADDR
+ ldr w1, [x2, x0]
+ mov w0, w1
+ ret
+
+/*
+ * This function returns an mpidr value for a core, given a core_mask_lsb
+ * in: x0 = core mask lsb
+ * out: x0 = affinity2:affinity1:affinity0, where affinity is 8-bits
+ * uses x0, x1
+ */
+get_mpidr_value:
+ /* Convert a core mask to an SoC core number */
+ clz w0, w0
+ mov w1, #31
+ sub w0, w1, w0
+
+ /* Get the mpidr core number from the SoC core number */
+ mov w1, wzr
+ tst x0, #1
+ b.eq 1f
+ orr w1, w1, #1
+1:
+ /* Extract the cluster number */
+ lsr w0, w0, #1
+ orr w0, w1, w0, lsl #8
+
+ ret
+
+/*
+ * This function returns the redistributor base address for the core specified
+ * in x1
+ * in: x0 - core mask lsb of specified core
+ * out: x0 = redistributor rd base address for specified core
+ * uses x0, x1, x2
+ */
+get_gic_rd_base:
+ /* Get the 0-based core number */
+ clz w1, w0
+ mov w2, #0x20
+ sub w2, w2, w1
+ sub w2, w2, #1
+
+ /* x2 = core number / loop counter */
+ ldr x0, =NXP_GICR_ADDR
+ mov x1, #GIC_RD_OFFSET
+2:
+ cbz x2, 1f
+ add x0, x0, x1
+ sub x2, x2, #1
+ b 2b
+1:
+ ret
+
+/*
+ * This function returns the redistributor base address for the core specified
+ * in x1
+ * in: x0 - core mask lsb of specified core
+ * out: x0 = redistributor sgi base address for specified core
+ * uses x0, x1, x2
+ */
+get_gic_sgi_base:
+ /* Get the 0-based core number */
+ clz w1, w0
+ mov w2, #0x20
+ sub w2, w2, w1
+ sub w2, w2, #1
+
+ /* x2 = core number / loop counter */
+ ldr x0, =NXP_GICR_SGI_ADDR
+ mov x1, #GIC_SGI_OFFSET
+2:
+ cbz x2, 1f
+ add x0, x0, x1
+ sub x2, x2, #1
+ b 2b
+1:
+ ret
+
+/*
+ * Write a register in the RESET block
+ * in: x0 = offset
+ * in: w1 = value to write
+ * uses x0, x1, x2
+ */
+_write_reg_reset:
+ ldr x2, =NXP_RESET_ADDR
+ str w1, [x2, x0]
+ ret
+
+/*
+ * Read a register in the RESET block
+ * in: x0 = offset
+ * out: w0 = value read
+ * uses x0, x1
+ */
+_read_reg_reset:
+ ldr x1, =NXP_RESET_ADDR
+ ldr w0, [x1, x0]
+ ret
diff --git a/plat/nxp/soc-ls1028a/aarch64/ls1028a_helpers.S b/plat/nxp/soc-ls1028a/aarch64/ls1028a_helpers.S
new file mode 100644
index 0000000..ec67529
--- /dev/null
+++ b/plat/nxp/soc-ls1028a/aarch64/ls1028a_helpers.S
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+#include <platform_def.h>
+
+.globl plat_secondary_cold_boot_setup
+.globl plat_is_my_cpu_primary
+.globl plat_reset_handler
+.globl platform_mem_init
+
+func platform_mem1_init
+ ret
+endfunc platform_mem1_init
+
+func platform_mem_init
+ ret
+endfunc platform_mem_init
+
+func apply_platform_errata
+ ret
+endfunc apply_platform_errata
+
+func plat_reset_handler
+ mov x29, x30
+ bl apply_platform_errata
+
+#if defined(IMAGE_BL31)
+ ldr x0, =POLICY_SMMU_PAGESZ_64K
+ cbz x0, 1f
+ /* Set the SMMU page size in the sACR register */
+ bl _set_smmu_pagesz_64
+#endif
+1:
+ mov x30, x29
+ ret
+endfunc 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 e.g
+ * mark the cpu's presence, mechanism to place it in a
+ * holding pen etc.
+ */
+func plat_secondary_cold_boot_setup
+ /* ls1028a does not do cold boot for secondary CPU */
+cb_panic:
+ b cb_panic
+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
+ mrs x0, mpidr_el1
+ and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+ cmp x0, 0x0
+ cset w0, eq
+ ret
+endfunc plat_is_my_cpu_primary
diff --git a/plat/nxp/soc-ls1028a/include/soc.h b/plat/nxp/soc-ls1028a/include/soc.h
new file mode 100644
index 0000000..b1d044a
--- /dev/null
+++ b/plat/nxp/soc-ls1028a/include/soc.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOC_H
+#define SOC_H
+
+/* Chassis specific defines - common across SoC's of a particular platform */
+#include <dcfg_lsch3.h>
+#include <soc_default_base_addr.h>
+#include <soc_default_helper_macros.h>
+
+/*
+ * SVR Definition of LS1028A
+ * (not include major and minor rev)
+ * These info is listed in Table B-6. DCFG differences
+ * between LS1028A and LS1027A of LS1028ARM(Reference Manual)
+ */
+#define SVR_LS1017AN 0x870B25
+#define SVR_LS1017AE 0x870B24
+#define SVR_LS1018AN 0x870B21
+#define SVR_LS1018AE 0x870B20
+#define SVR_LS1027AN 0x870B05
+#define SVR_LS1027AE 0x870B04
+#define SVR_LS1028AN 0x870B01
+#define SVR_LS1028AE 0x870B00
+
+/* Number of cores in platform */
+#define PLATFORM_CORE_COUNT 2
+#define NUMBER_OF_CLUSTERS 1
+#define CORES_PER_CLUSTER 2
+
+/* Set to 0 if the clusters are not symmetrical */
+#define SYMMETRICAL_CLUSTERS 1
+
+#define NUM_DRAM_REGIONS 3
+
+#define NXP_DRAM0_ADDR 0x80000000
+#define NXP_DRAM0_MAX_SIZE 0x80000000 /* 2GB */
+
+#define NXP_DRAM1_ADDR 0x2080000000
+#define NXP_DRAM1_MAX_SIZE 0x1F80000000 /* 126G */
+
+#define NXP_DRAM2_ADDR 0x6000000000
+#define NXP_DRAM2_MAX_SIZE 0x2000000000 /* 128G */
+
+/* DRAM0 Size defined in platform_def.h */
+#define NXP_DRAM0_SIZE PLAT_DEF_DRAM0_SIZE
+
+/* CCSR space memory Map */
+#undef NXP_UART_ADDR
+#define NXP_UART_ADDR 0x021C0500
+
+#undef NXP_UART1_ADDR
+#define NXP_UART1_ADDR 0x021C0600
+
+#undef NXP_WDOG1_TZ_ADDR
+#define NXP_WDOG1_TZ_ADDR 0x023C0000
+
+#undef NXP_GICR_ADDR
+#define NXP_GICR_ADDR 0x06040000
+
+#undef NXP_GICR_SGI_ADDR
+#define NXP_GICR_SGI_ADDR 0x06050000
+
+/* EPU register offsets and values */
+#define EPU_EPGCR_OFFSET 0x0
+#define EPU_EPIMCR10_OFFSET 0x128
+#define EPU_EPCTR10_OFFSET 0xa28
+#define EPU_EPCCR10_OFFSET 0x828
+#define EPU_EPCCR10_VAL 0xb2800000
+#define EPU_EPIMCR10_VAL 0xba000000
+#define EPU_EPCTR10_VAL 0x0
+#define EPU_EPGCR_VAL (1 << 31)
+
+/* PORSR1 */
+#define PORSR1_RCW_MASK 0x07800000
+#define PORSR1_RCW_SHIFT 23
+
+#define SDHC1_VAL 0x8
+#define SDHC2_VAL 0x9
+#define I2C1_VAL 0xa
+#define FLEXSPI_NAND2K_VAL 0xc
+#define FLEXSPI_NAND4K_VAL 0xd
+#define FLEXSPI_NOR 0xf
+
+/*
+ * Required LS standard platform porting definitions
+ * for CCI-400
+ */
+#define NXP_CCI_CLUSTER0_SL_IFACE_IX 4
+
+/* Defines required for using XLAT tables from ARM common code */
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 40)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 40)
+
+/* Clock Divisors */
+#define NXP_PLATFORM_CLK_DIVIDER 1
+#define NXP_UART_CLK_DIVIDER 2
+
+/* dcfg register offsets and values */
+#define DCFG_DEVDISR2_ENETC (1 << 31)
+
+#define MPIDR_AFFINITY0_MASK 0x00FF
+#define MPIDR_AFFINITY1_MASK 0xFF00
+#define CPUECTLR_DISABLE_TWALK_PREFETCH 0x4000000000
+#define CPUECTLR_INS_PREFETCH_MASK 0x1800000000
+#define CPUECTLR_DAT_PREFETCH_MASK 0x0300000000
+#define OSDLR_EL1_DLK_LOCK 0x1
+#define CNTP_CTL_EL0_EN 0x1
+#define CNTP_CTL_EL0_IMASK 0x2
+
+#define SYSTEM_PWR_DOMAINS 1
+#define PLAT_NUM_PWR_DOMAINS (PLATFORM_CORE_COUNT + \
+ NUMBER_OF_CLUSTERS + \
+ SYSTEM_PWR_DOMAINS)
+
+/* Power state coordination occurs at the system level */
+#define PLAT_PD_COORD_LVL MPIDR_AFFLVL2
+#define PLAT_MAX_PWR_LVL PLAT_PD_COORD_LVL
+
+/* Local power state for power domains in Run state */
+#define LS_LOCAL_STATE_RUN PSCI_LOCAL_STATE_RUN
+
+/* define retention state */
+#define PLAT_MAX_RET_STATE (PSCI_LOCAL_STATE_RUN + 1)
+#define LS_LOCAL_STATE_RET PLAT_MAX_RET_STATE
+
+/* define power-down state */
+#define PLAT_MAX_OFF_STATE (PLAT_MAX_RET_STATE + 1)
+#define LS_LOCAL_STATE_OFF PLAT_MAX_OFF_STATE
+
+/* One cache line needed for bakery locks on ARM platforms */
+#define PLAT_PERCPU_BAKERY_LOCK_SIZE (1 * CACHE_WRITEBACK_GRANULE)
+
+#ifndef __ASSEMBLER__
+/* CCI slave interfaces */
+static const int cci_map[] = {
+ NXP_CCI_CLUSTER0_SL_IFACE_IX,
+};
+void soc_init_lowlevel(void);
+void soc_init_percpu(void);
+void _soc_set_start_addr(unsigned long addr);
+void _set_platform_security(void);
+#endif
+
+#endif /* SOC_H */
diff --git a/plat/nxp/soc-ls1028a/ls1028ardb/ddr_init.c b/plat/nxp/soc-ls1028a/ls1028ardb/ddr_init.c
new file mode 100644
index 0000000..d82be51
--- /dev/null
+++ b/plat/nxp/soc-ls1028a/ls1028ardb/ddr_init.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <string.h>
+
+#include <common/debug.h>
+#include <ddr.h>
+#include <lib/utils.h>
+
+#include <platform_def.h>
+
+#ifdef CONFIG_STATIC_DDR
+const struct ddr_cfg_regs static_1600 = {
+ .cs[0].config = U(0x80040422),
+ .cs[0].bnds = U(0xFF),
+ .sdram_cfg[0] = U(0xE50C0004),
+ .sdram_cfg[1] = U(0x401100),
+ .timing_cfg[0] = U(0x91550018),
+ .timing_cfg[1] = U(0xBAB40C42),
+ .timing_cfg[2] = U(0x48C111),
+ .timing_cfg[3] = U(0x1111000),
+ .timing_cfg[4] = U(0x2),
+ .timing_cfg[5] = U(0x3401400),
+ .timing_cfg[7] = U(0x23300000),
+ .timing_cfg[8] = U(0x2114600),
+ .sdram_mode[0] = U(0x3010210),
+ .sdram_mode[9] = U(0x4000000),
+ .sdram_mode[8] = U(0x500),
+ .sdram_mode[2] = U(0x10210),
+ .sdram_mode[10] = U(0x400),
+ .sdram_mode[11] = U(0x4000000),
+ .sdram_mode[4] = U(0x10210),
+ .sdram_mode[12] = U(0x400),
+ .sdram_mode[13] = U(0x4000000),
+ .sdram_mode[6] = U(0x10210),
+ .sdram_mode[14] = U(0x400),
+ .sdram_mode[15] = U(0x4000000),
+ .interval = U(0x18600618),
+ .data_init = U(0xdeadbeef),
+ .zq_cntl = U(0x8A090705),
+ .clk_cntl = U(0x2000000),
+ .cdr[0] = U(0x80040000),
+ .cdr[1] = U(0xA181),
+ .wrlvl_cntl[0] = U(0x8675F605),
+ .wrlvl_cntl[1] = U(0x6070700),
+ .wrlvl_cntl[2] = U(0x0000008),
+ .dq_map[0] = U(0x5b65b658),
+ .dq_map[1] = U(0xd96d8000),
+ .dq_map[2] = U(0),
+ .dq_map[3] = U(0x1600000),
+ .debug[28] = U(0x00700046),
+};
+
+unsigned long long board_static_ddr(struct ddr_info *priv)
+{
+ memcpy(&priv->ddr_reg, &static_1600, sizeof(static_1600));
+ return ULL(0x100000000);
+}
+
+#else
+
+static const struct rc_timing rcz[] = {
+ {1600, 8, 5},
+ {}
+};
+
+static const struct board_timing ram[] = {
+ {0x1f, rcz, 0x1020200, 0x00000003},
+};
+
+int ddr_board_options(struct ddr_info *priv)
+{
+ int ret;
+ struct memctl_opt *popts = &priv->opt;
+
+ ret = cal_board_params(priv, ram, ARRAY_SIZE(ram));
+ if (ret != 0) {
+ return ret;
+ }
+
+ popts->bstopre = U(0x40); /* precharge value */
+ popts->half_strength_drive_en = 1;
+ popts->cpo_sample = U(0x46);
+ popts->ddr_cdr1 = DDR_CDR1_DHC_EN |
+ DDR_CDR1_ODT(DDR_CDR_ODT_80ohm);
+ popts->ddr_cdr2 = DDR_CDR2_ODT(DDR_CDR_ODT_80ohm) |
+ DDR_CDR2_VREF_OVRD(70); /* Vref = 70% */
+
+ popts->addr_hash = 1; /* address hashing */
+ return 0;
+}
+
+/* DDR model number: MT40A1G8SA-075:E */
+struct dimm_params ddr_raw_timing = {
+ .n_ranks = U(1),
+ .rank_density = ULL(4294967296),
+ .capacity = ULL(4294967296),
+ .primary_sdram_width = U(32),
+ .ec_sdram_width = U(4),
+ .rdimm = U(0),
+ .mirrored_dimm = U(0),
+ .n_row_addr = U(16),
+ .n_col_addr = U(10),
+ .bank_group_bits = U(2),
+ .edc_config = U(2),
+ .burst_lengths_bitmask = U(0x0c),
+ .tckmin_x_ps = 750,
+ .tckmax_ps = 1900,
+ .caslat_x = U(0x0001FFE00),
+ .taa_ps = 13500,
+ .trcd_ps = 13500,
+ .trp_ps = 13500,
+ .tras_ps = 32000,
+ .trc_ps = 45500,
+ .twr_ps = 15000,
+ .trfc1_ps = 350000,
+ .trfc2_ps = 260000,
+ .trfc4_ps = 160000,
+ .tfaw_ps = 21000,
+ .trrds_ps = 3000,
+ .trrdl_ps = 4900,
+ .tccdl_ps = 5000,
+ .refresh_rate_ps = U(7800000),
+ .dq_mapping[0] = U(0x16),
+ .dq_mapping[1] = U(0x36),
+ .dq_mapping[2] = U(0x16),
+ .dq_mapping[3] = U(0x36),
+ .dq_mapping[4] = U(0x16),
+ .dq_mapping[5] = U(0x36),
+ .dq_mapping[6] = U(0x16),
+ .dq_mapping[7] = U(0x36),
+ .dq_mapping[8] = U(0x16),
+ .dq_mapping[9] = U(0x0),
+ .dq_mapping[10] = U(0x0),
+ .dq_mapping[11] = U(0x0),
+ .dq_mapping[12] = U(0x0),
+ .dq_mapping[13] = U(0x0),
+ .dq_mapping[14] = U(0x0),
+ .dq_mapping[15] = U(0x0),
+ .dq_mapping[16] = U(0x0),
+ .dq_mapping[17] = U(0x0),
+ .dq_mapping_ors = U(0),
+ .rc = U(0x1f),
+};
+
+int ddr_get_ddr_params(struct dimm_params *pdimm,
+ struct ddr_conf *conf)
+{
+ static const char dimm_model[] = "Fixed DDR on board";
+
+ conf->dimm_in_use[0] = 1;
+ memcpy(pdimm, &ddr_raw_timing, sizeof(struct dimm_params));
+ memcpy(pdimm->mpart, dimm_model, sizeof(dimm_model) - 1);
+
+ return 1;
+}
+#endif
+
+int64_t init_ddr(void)
+{
+ struct ddr_info info;
+ struct sysinfo sys;
+ int64_t dram_size;
+
+ zeromem(&sys, sizeof(sys));
+ get_clocks(&sys);
+ debug("platform clock %lu\n", sys.freq_platform);
+ debug("DDR PLL1 %lu\n", sys.freq_ddr_pll0);
+
+ zeromem(&info, sizeof(struct ddr_info));
+ info.num_ctlrs = 1;
+ info.dimm_on_ctlr = 1;
+ info.clk = get_ddr_freq(&sys, 0);
+ info.ddr[0] = (void *)NXP_DDR_ADDR;
+
+ dram_size = dram_init(&info);
+
+ if (dram_size < 0) {
+ ERROR("DDR init failed.\n");
+ }
+
+ return dram_size;
+}
diff --git a/plat/nxp/soc-ls1028a/ls1028ardb/plat_def.h b/plat/nxp/soc-ls1028a/ls1028ardb/plat_def.h
new file mode 100644
index 0000000..63c0219
--- /dev/null
+++ b/plat/nxp/soc-ls1028a/ls1028ardb/plat_def.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_DEF_H
+#define PLAT_DEF_H
+
+#include <arch.h>
+#include <cortex_a72.h>
+/*
+ * Required without TBBR.
+ * To include the defines for DDR PHY
+ * Images.
+ */
+#include <tbbr_img_def.h>
+
+#include <policy.h>
+#include <soc.h>
+
+
+#define NXP_SYSCLK_FREQ 100000000
+#define NXP_DDRCLK_FREQ 100000000
+
+/* UART related definition */
+#define NXP_CONSOLE_ADDR NXP_UART_ADDR
+#define NXP_CONSOLE_BAUDRATE 115200
+
+#define NXP_SPD_EEPROM0 0x51
+
+/* Size of cacheable stacks */
+#if defined(IMAGE_BL2)
+#if defined(TRUSTED_BOARD_BOOT)
+#define PLATFORM_STACK_SIZE 0x2000
+#else
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+#elif defined(IMAGE_BL31)
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+
+/* SD block buffer */
+#define NXP_SD_BLOCK_BUF_SIZE (0xC000)
+
+#ifdef SD_BOOT
+#define BL2_LIMIT (NXP_OCRAM_ADDR + NXP_OCRAM_SIZE \
+ - NXP_SD_BLOCK_BUF_SIZE)
+#else
+#define BL2_LIMIT (NXP_OCRAM_ADDR + NXP_OCRAM_SIZE)
+#endif
+#define BL2_TEXT_LIMIT (BL2_LIMIT)
+
+/* IO defines as needed by IO driver framework */
+#define MAX_IO_DEVICES 4
+#define MAX_IO_BLOCK_DEVICES 1
+#define MAX_IO_HANDLES 4
+
+#define BL31_WDOG_SEC 89
+
+/*
+ * 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_LS_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(BL32_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE)
+
+/* SGI 15 and Secure watchdog interrupts assigned to Group 0 */
+#define PLAT_LS_G0_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(BL31_WDOG_SEC, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(15, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL)
+#endif /* PLAT_DEF_H */
diff --git a/plat/nxp/soc-ls1028a/ls1028ardb/platform.c b/plat/nxp/soc-ls1028a/ls1028ardb/platform.c
new file mode 100644
index 0000000..65d508c
--- /dev/null
+++ b/plat/nxp/soc-ls1028a/ls1028ardb/platform.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_common.h>
+
+#pragma weak board_enable_povdd
+#pragma weak board_disable_povdd
+
+bool board_enable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool board_disable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
diff --git a/plat/nxp/soc-ls1028a/ls1028ardb/platform.mk b/plat/nxp/soc-ls1028a/ls1028ardb/platform.mk
new file mode 100644
index 0000000..c455000
--- /dev/null
+++ b/plat/nxp/soc-ls1028a/ls1028ardb/platform.mk
@@ -0,0 +1,33 @@
+#
+# Copyright 2020-2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Board-specific build parameters
+BOOT_MODE ?= flexspi_nor
+BOARD := ls1028ardb
+POVDD_ENABLE := no
+WARM_BOOT := no
+
+# DDR build parameters
+NUM_OF_DDRC := 1
+CONFIG_DDR_NODIMM := 1
+DDR_ECC_EN := yes
+
+# On-board flash
+FLASH_TYPE := MT35XU02G
+XSPI_FLASH_SZ := 0x10000000
+
+BL2_SOURCES += ${BOARD_PATH}/ddr_init.c \
+ ${BOARD_PATH}/platform.c
+
+SUPPORTED_BOOT_MODE := flexspi_nor \
+ sd \
+ emmc
+
+# Add platform board build info
+include plat/nxp/common/plat_make_helper/plat_common_def.mk
+
+# Add SoC build info
+include plat/nxp/soc-ls1028a/soc.mk
diff --git a/plat/nxp/soc-ls1028a/ls1028ardb/platform_def.h b/plat/nxp/soc-ls1028a/ls1028ardb/platform_def.h
new file mode 100644
index 0000000..bbad293
--- /dev/null
+++ b/plat/nxp/soc-ls1028a/ls1028ardb/platform_def.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <plat_def.h>
+#include <plat_default_def.h>
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/nxp/soc-ls1028a/ls1028ardb/policy.h b/plat/nxp/soc-ls1028a/ls1028ardb/policy.h
new file mode 100644
index 0000000..67a8b45
--- /dev/null
+++ b/plat/nxp/soc-ls1028a/ls1028ardb/policy.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2020-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef POLICY_H
+#define POLICY_H
+
+/*
+ * Set this to 0x0 to leave the default SMMU page size in sACR
+ * Set this to 0x1 to change the SMMU page size to 64K
+ */
+#define POLICY_SMMU_PAGESZ_64K 0x1
+
+#endif /* POLICY_H */
diff --git a/plat/nxp/soc-ls1028a/soc.c b/plat/nxp/soc-ls1028a/soc.c
new file mode 100644
index 0000000..2fb353f
--- /dev/null
+++ b/plat/nxp/soc-ls1028a/soc.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <endian.h>
+
+#include <arch.h>
+#include <caam.h>
+#include <cassert.h>
+#include <cci.h>
+#include <common/debug.h>
+#include <dcfg.h>
+#include <i2c.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <ls_interconnect.h>
+#include <mmio.h>
+#ifdef POLICY_FUSE_PROVISION
+#include <nxp_gpio.h>
+#endif
+#if TRUSTED_BOARD_BOOT
+#include <nxp_smmu.h>
+#endif
+#include <nxp_timer.h>
+#include <plat_console.h>
+#include <plat_gic.h>
+#include <plat_tzc400.h>
+#include <pmu.h>
+#include <scfg.h>
+#if defined(NXP_SFP_ENABLED)
+#include <sfp.h>
+#endif
+
+#include <errata.h>
+#ifdef CONFIG_OCRAM_ECC_EN
+#include <ocram.h>
+#endif
+#include "plat_common.h"
+#include "platform_def.h"
+#include "soc.h"
+
+static dcfg_init_info_t dcfg_init_data = {
+ .g_nxp_dcfg_addr = NXP_DCFG_ADDR,
+ .nxp_sysclk_freq = NXP_SYSCLK_FREQ,
+ .nxp_ddrclk_freq = NXP_DDRCLK_FREQ,
+ .nxp_plat_clk_divider = NXP_PLATFORM_CLK_DIVIDER,
+};
+
+static struct soc_type soc_list[] = {
+ SOC_ENTRY(LS1017AN, LS1017AN, 1, 1),
+ SOC_ENTRY(LS1017AE, LS1017AE, 1, 1),
+ SOC_ENTRY(LS1018AN, LS1018AN, 1, 1),
+ SOC_ENTRY(LS1018AE, LS1018AE, 1, 1),
+ SOC_ENTRY(LS1027AN, LS1027AN, 1, 2),
+ SOC_ENTRY(LS1027AE, LS1027AE, 1, 2),
+ SOC_ENTRY(LS1028AN, LS1028AN, 1, 2),
+ SOC_ENTRY(LS1028AE, LS1028AE, 1, 2),
+};
+
+CASSERT(NUMBER_OF_CLUSTERS && NUMBER_OF_CLUSTERS <= 256,
+ assert_invalid_ls1028a_cluster_count);
+
+/*
+ * Function returns the base counter frequency
+ * after reading the first entry at CNTFID0 (0x20 offset).
+ *
+ * Function is used by:
+ * 1. ARM common code for PSCI management.
+ * 2. ARM Generic Timer init.
+ *
+ */
+unsigned int plat_get_syscnt_freq2(void)
+{
+ unsigned int counter_base_frequency;
+ /*
+ * Below register specifies the base frequency of the system counter.
+ * As per NXP Board Manuals:
+ * The system counter always works with SYS_REF_CLK/4 frequency clock.
+ */
+ counter_base_frequency = mmio_read_32(NXP_TIMER_ADDR + CNTFID_OFF);
+
+ return counter_base_frequency;
+}
+
+#ifdef IMAGE_BL2
+
+#ifdef POLICY_FUSE_PROVISION
+static gpio_init_info_t gpio_init_data = {
+ .gpio1_base_addr = NXP_GPIO1_ADDR,
+ .gpio2_base_addr = NXP_GPIO2_ADDR,
+ .gpio3_base_addr = NXP_GPIO3_ADDR,
+};
+#endif
+
+void soc_preload_setup(void)
+{
+}
+
+void soc_early_init(void)
+{
+ uint8_t num_clusters, cores_per_cluster;
+
+#ifdef CONFIG_OCRAM_ECC_EN
+ ocram_init(NXP_OCRAM_ADDR, NXP_OCRAM_SIZE);
+#endif
+ dcfg_init(&dcfg_init_data);
+ enable_timer_base_to_cluster(NXP_PMU_ADDR);
+ enable_core_tb(NXP_PMU_ADDR);
+ dram_regions_info_t *dram_regions_info = get_dram_regions_info();
+
+#ifdef POLICY_FUSE_PROVISION
+ gpio_init(&gpio_init_data);
+ sec_init(NXP_CAAM_ADDR);
+#endif
+
+#if LOG_LEVEL > 0
+ /* Initialize the console to provide early debug support */
+ plat_console_init(NXP_CONSOLE_ADDR,
+ NXP_UART_CLK_DIVIDER, NXP_CONSOLE_BAUDRATE);
+#endif
+ enum boot_device dev = get_boot_dev();
+ /*
+ * Mark the buffer for SD in OCRAM as non secure.
+ * The buffer is assumed to be at end of OCRAM for
+ * the logic below to calculate TZPC programming
+ */
+ if (dev == BOOT_DEVICE_EMMC || dev == BOOT_DEVICE_SDHC2_EMMC) {
+ /*
+ * Calculate the region in OCRAM which is secure
+ * The buffer for SD needs to be marked non-secure
+ * to allow SD to do DMA operations on it
+ */
+ uint32_t secure_region = (NXP_OCRAM_SIZE - NXP_SD_BLOCK_BUF_SIZE);
+ uint32_t mask = secure_region/TZPC_BLOCK_SIZE;
+
+ mmio_write_32(NXP_OCRAM_TZPC_ADDR, mask);
+
+ /* Add the entry for buffer in MMU Table */
+ mmap_add_region(NXP_SD_BLOCK_BUF_ADDR, NXP_SD_BLOCK_BUF_ADDR,
+ NXP_SD_BLOCK_BUF_SIZE, MT_DEVICE | MT_RW | MT_NS);
+ }
+
+#if TRUSTED_BOARD_BOOT
+ uint32_t mode;
+
+ sfp_init(NXP_SFP_ADDR);
+
+ /*
+ * For secure boot disable SMMU.
+ * Later when platform security policy comes in picture,
+ * this might get modified based on the policy
+ */
+ if (check_boot_mode_secure(&mode) == true) {
+ bypass_smmu(NXP_SMMU_ADDR);
+ }
+
+ /*
+ * For Mbedtls currently crypto is not supported via CAAM
+ * enable it when that support is there. In tbbr.mk
+ * the CAAM_INTEG is set as 0.
+ */
+#ifndef MBEDTLS_X509
+ /* Initialize the crypto accelerator if enabled */
+ if (is_sec_enabled()) {
+ sec_init(NXP_CAAM_ADDR);
+ } else {
+ INFO("SEC is disabled.\n");
+ }
+#endif
+#endif
+
+ /* Set eDDRTQ for DDR performance */
+ scfg_setbits32((void *)(NXP_SCFG_ADDR + 0x210), 0x1f1f1f1f);
+
+ soc_errata();
+
+ /*
+ * Initialize Interconnect for this cluster during cold boot.
+ * No need for locks as no other CPU is active.
+ */
+ cci_init(NXP_CCI_ADDR, cci_map, ARRAY_SIZE(cci_map));
+
+ /*
+ * Enable Interconnect coherency for the primary CPU's cluster.
+ */
+ get_cluster_info(soc_list, ARRAY_SIZE(soc_list), &num_clusters, &cores_per_cluster);
+ plat_ls_interconnect_enter_coherency(num_clusters);
+
+ delay_timer_init(NXP_TIMER_ADDR);
+ i2c_init(NXP_I2C_ADDR);
+ dram_regions_info->total_dram_size = init_ddr();
+}
+
+void soc_bl2_prepare_exit(void)
+{
+#if defined(NXP_SFP_ENABLED) && defined(DISABLE_FUSE_WRITE)
+ set_sfp_wr_disable();
+#endif
+}
+
+/*
+ * This function returns the boot device based on RCW_SRC
+ */
+enum boot_device get_boot_dev(void)
+{
+ enum boot_device src = BOOT_DEVICE_NONE;
+ uint32_t porsr1;
+ uint32_t rcw_src;
+
+ porsr1 = read_reg_porsr1();
+
+ rcw_src = (porsr1 & PORSR1_RCW_MASK) >> PORSR1_RCW_SHIFT;
+ switch (rcw_src) {
+ case FLEXSPI_NOR:
+ src = BOOT_DEVICE_FLEXSPI_NOR;
+ INFO("RCW BOOT SRC is FLEXSPI NOR\n");
+ break;
+ case FLEXSPI_NAND2K_VAL:
+ case FLEXSPI_NAND4K_VAL:
+ INFO("RCW BOOT SRC is FLEXSPI NAND\n");
+ src = BOOT_DEVICE_FLEXSPI_NAND;
+ break;
+ case SDHC1_VAL:
+ src = BOOT_DEVICE_EMMC;
+ INFO("RCW BOOT SRC is SD\n");
+ break;
+ case SDHC2_VAL:
+ src = BOOT_DEVICE_SDHC2_EMMC;
+ INFO("RCW BOOT SRC is EMMC\n");
+ break;
+ default:
+ break;
+ }
+
+ return src;
+}
+
+/*
+ * This function sets up access permissions on memory regions
+ ****************************************************************************/
+void soc_mem_access(void)
+{
+ dram_regions_info_t *info_dram_regions = get_dram_regions_info();
+ struct tzc400_reg tzc400_reg_list[MAX_NUM_TZC_REGION];
+ int dram_idx = 0;
+ /* index 0 is reserved for region-0 */
+ int index = 1;
+
+ for (dram_idx = 0; dram_idx < info_dram_regions->num_dram_regions;
+ dram_idx++) {
+ if (info_dram_regions->region[dram_idx].size == 0) {
+ ERROR("DDR init failure, or");
+ ERROR("DRAM regions not populated correctly.\n");
+ break;
+ }
+
+ index = populate_tzc400_reg_list(tzc400_reg_list,
+ dram_idx, index,
+ info_dram_regions->region[dram_idx].addr,
+ info_dram_regions->region[dram_idx].size,
+ NXP_SECURE_DRAM_SIZE, NXP_SP_SHRD_DRAM_SIZE);
+ }
+
+ mem_access_setup(NXP_TZC_ADDR, index, tzc400_reg_list);
+}
+
+#else
+
+static unsigned char _power_domain_tree_desc[NUMBER_OF_CLUSTERS + 2];
+/*
+ * This function dynamically constructs the topology according to
+ * SoC Flavor and returns it.
+ */
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ uint8_t num_clusters, cores_per_cluster;
+ unsigned int i;
+
+ get_cluster_info(soc_list, ARRAY_SIZE(soc_list), &num_clusters, &cores_per_cluster);
+ /*
+ * The highest level is the system level. The next level is constituted
+ * by clusters and then cores in clusters.
+ */
+ _power_domain_tree_desc[0] = 1;
+ _power_domain_tree_desc[1] = num_clusters;
+
+ for (i = 0; i < _power_domain_tree_desc[1]; i++)
+ _power_domain_tree_desc[i + 2] = cores_per_cluster;
+
+ return _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)
+{
+ uint8_t num_clusters, cores_per_cluster;
+
+ get_cluster_info(soc_list, ARRAY_SIZE(soc_list), &num_clusters, &cores_per_cluster);
+ return num_clusters;
+}
+
+void soc_early_platform_setup2(void)
+{
+ dcfg_init(&dcfg_init_data);
+ /* Initialize system level generic timer for Socs */
+ delay_timer_init(NXP_TIMER_ADDR);
+
+#if LOG_LEVEL > 0
+ /* Initialize the console to provide early debug support */
+ plat_console_init(NXP_CONSOLE_ADDR,
+ NXP_UART_CLK_DIVIDER, NXP_CONSOLE_BAUDRATE);
+#endif
+}
+
+void soc_platform_setup(void)
+{
+ /* Initialize the GIC driver, cpu and distributor interfaces */
+ static uintptr_t target_mask_array[PLATFORM_CORE_COUNT];
+ static interrupt_prop_t ls_interrupt_props[] = {
+ PLAT_LS_G1S_IRQ_PROPS(INTR_GROUP1S),
+ PLAT_LS_G0_IRQ_PROPS(INTR_GROUP0)
+ };
+
+ plat_ls_gic_driver_init(NXP_GICD_ADDR, NXP_GICR_ADDR,
+ PLATFORM_CORE_COUNT,
+ ls_interrupt_props,
+ ARRAY_SIZE(ls_interrupt_props),
+ target_mask_array,
+ plat_core_pos);
+
+ plat_ls_gic_init();
+ enable_init_timer();
+}
+
+/* This function initializes the soc from the BL31 module */
+void soc_init(void)
+{
+ uint8_t num_clusters, cores_per_cluster;
+
+ get_cluster_info(soc_list, ARRAY_SIZE(soc_list), &num_clusters, &cores_per_cluster);
+
+ /* Low-level init of the soc */
+ soc_init_lowlevel();
+ _init_global_data();
+ soc_init_percpu();
+ _initialize_psci();
+
+ /*
+ * Initialize Interconnect for this cluster during cold boot.
+ * No need for locks as no other CPU is active.
+ */
+ cci_init(NXP_CCI_ADDR, cci_map, ARRAY_SIZE(cci_map));
+
+ /* Enable Interconnect coherency for the primary CPU's cluster. */
+ plat_ls_interconnect_enter_coherency(num_clusters);
+
+ /* Set platform security policies */
+ _set_platform_security();
+
+ /* Init SEC Engine which will be used by SiP */
+ if (is_sec_enabled()) {
+ sec_init(NXP_CAAM_ADDR);
+ } else {
+ INFO("SEC is disabled.\n");
+ }
+}
+
+#ifdef NXP_WDOG_RESTART
+static uint64_t wdog_interrupt_handler(uint32_t id, uint32_t flags,
+ void *handle, void *cookie)
+{
+ uint8_t data = WDOG_RESET_FLAG;
+
+ wr_nv_app_data(WDT_RESET_FLAG_OFFSET,
+ (uint8_t *)&data, sizeof(data));
+
+ mmio_write_32(NXP_RST_ADDR + RSTCNTL_OFFSET, SW_RST_REQ_INIT);
+
+ return 0;
+}
+#endif
+
+void soc_runtime_setup(void)
+{
+#ifdef NXP_WDOG_RESTART
+ request_intr_type_el3(BL31_NS_WDOG_WS1, wdog_interrupt_handler);
+#endif
+}
+
+/* This function returns the total number of cores in the SoC. */
+unsigned int get_tot_num_cores(void)
+{
+ uint8_t num_clusters, cores_per_cluster;
+
+ get_cluster_info(soc_list, ARRAY_SIZE(soc_list), &num_clusters, &cores_per_cluster);
+ return (num_clusters * cores_per_cluster);
+}
+
+/* This function returns the PMU IDLE Cluster mask. */
+unsigned int get_pmu_idle_cluster_mask(void)
+{
+ uint8_t num_clusters, cores_per_cluster;
+
+ get_cluster_info(soc_list, ARRAY_SIZE(soc_list), &num_clusters, &cores_per_cluster);
+ return ((1 << num_clusters) - 2);
+}
+
+/* This function returns the PMU Flush Cluster mask. */
+unsigned int get_pmu_flush_cluster_mask(void)
+{
+ uint8_t num_clusters, cores_per_cluster;
+
+ get_cluster_info(soc_list, ARRAY_SIZE(soc_list), &num_clusters, &cores_per_cluster);
+ return ((1 << num_clusters) - 2);
+}
+
+/* This function returns the PMU idle core mask. */
+unsigned int get_pmu_idle_core_mask(void)
+{
+ return ((1 << get_tot_num_cores()) - 2);
+}
+
+/* Function to return the SoC SYS CLK */
+unsigned int get_sys_clk(void)
+{
+ return NXP_SYSCLK_FREQ;
+}
+#endif
diff --git a/plat/nxp/soc-ls1028a/soc.def b/plat/nxp/soc-ls1028a/soc.def
new file mode 100644
index 0000000..c23c1bb
--- /dev/null
+++ b/plat/nxp/soc-ls1028a/soc.def
@@ -0,0 +1,97 @@
+#
+# Copyright 2018-2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+#------------------------------------------------------------------------------
+#
+# This file contains the basic architecture definitions that drive the build
+#
+# -----------------------------------------------------------------------------
+
+CORE_TYPE := a72
+
+CACHE_LINE := 6
+
+# Set to GIC400 or GIC500
+GIC := GIC500
+
+# Set to CCI400 or CCN504 or CCN508
+INTERCONNECT := CCI400
+
+# Layerscape chassis level - set to 3=LSCH3 or 2=LSCH2
+CHASSIS := 3_2
+
+# TZC used is TZC380 or TZC400
+TZC_ID := TZC400
+
+# CONSOLE is NS16550 or PL011
+CONSOLE := NS16550
+
+# DDR PHY generation to be used
+PLAT_DDR_PHY := PHY_GEN1
+
+PHYS_SYS := 64
+
+# Max Size of CSF header. Required to define BL2 TEXT LIMIT in soc.def
+# Input to CST create_hdr_esbc tool
+CSF_HDR_SZ := 0x3000
+
+# In IMAGE_BL2, compile time flag for handling Cache coherency
+# with CAAM for BL2 running from OCRAM
+SEC_MEM_NON_COHERENT := yes
+
+# OCRAM MAP for BL2
+# Before BL2
+# 0x18000000 - 0x18009fff -> Used by ROM code
+# 0x1800a000 - 0x1800dfff -> CSF header for BL2
+# For FlexSFlexSPI boot
+# 0x1800e000 - 0x18040000 -> Reserved for BL2 binary
+# For SD boot
+# 0x1800e000 - 0x18030000 -> Reserved for BL2 binary
+# 0x18030000 - 0x18040000 -> Reserved for SD buffer
+OCRAM_START_ADDR := 0x18000000
+OCRAM_SIZE := 0x40000
+
+# Area of OCRAM reserved by ROM code
+NXP_ROM_RSVD := 0xa000
+
+# Location of BL2 on OCRAM
+BL2_BASE_ADDR := $(shell echo $$(( $(OCRAM_START_ADDR) + $(NXP_ROM_RSVD) + $(CSF_HDR_SZ) )))
+
+# Covert to HEX to be used by create_pbl.mk
+BL2_BASE := $(shell echo "0x"$$(echo "obase=16; ${BL2_BASE_ADDR}" | bc))
+
+# BL2_HDR_LOC is at (BL2_BASE + NXP_ROM_RSVD)
+# This value BL2_HDR_LOC + CSF_HDR_SZ should not
+# overalp with BL2_BASE
+# Input to CST create_hdr_isbc tool
+BL2_HDR_LOC := 0x1800A000
+
+# SoC ERRATAS to be enabled
+ERRATA_SOC_A008850 := 1
+
+ERRATA_DDR_A009803 := 1
+ERRATA_DDR_A009942 := 1
+ERRATA_DDR_A010165 := 1
+
+# Enable dynamic memory mapping
+PLAT_XLAT_TABLES_DYNAMIC := 1
+
+# Define Endianness of each module
+NXP_GUR_ENDIANNESS := LE
+NXP_DDR_ENDIANNESS := LE
+NXP_SEC_ENDIANNESS := LE
+NXP_SFP_ENDIANNESS := LE
+NXP_SNVS_ENDIANNESS := LE
+NXP_ESDHC_ENDIANNESS := LE
+NXP_QSPI_ENDIANNESS := LE
+NXP_FSPI_ENDIANNESS := LE
+NXP_SCFG_ENDIANNESS := LE
+NXP_GPIO_ENDIANNESS := LE
+
+NXP_SFP_VER := 3_4
+
+# OCRAM ECC Enabled
+OCRAM_ECC_EN := yes
diff --git a/plat/nxp/soc-ls1028a/soc.mk b/plat/nxp/soc-ls1028a/soc.mk
new file mode 100644
index 0000000..92d8e98
--- /dev/null
+++ b/plat/nxp/soc-ls1028a/soc.mk
@@ -0,0 +1,113 @@
+#
+# Copyright 2020-2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# SoC-specific build parameters
+SOC := ls1028a
+PLAT_PATH := plat/nxp
+PLAT_COMMON_PATH := plat/nxp/common
+PLAT_DRIVERS_PATH := drivers/nxp
+PLAT_SOC_PATH := ${PLAT_PATH}/soc-${SOC}
+BOARD_PATH := ${PLAT_SOC_PATH}/${BOARD}
+
+# Get SoC-specific definitions
+include ${PLAT_SOC_PATH}/soc.def
+include ${PLAT_COMMON_PATH}/plat_make_helper/soc_common_def.mk
+include ${PLAT_COMMON_PATH}/plat_make_helper/plat_build_macros.mk
+
+ifeq (${TRUSTED_BOARD_BOOT},1)
+$(eval $(call SET_NXP_MAKE_FLAG,SMMU_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,SFP_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,SNVS_NEEDED,BL2))
+SECURE_BOOT := yes
+endif
+$(eval $(call SET_NXP_MAKE_FLAG,CRYPTO_NEEDED,BL_COMM))
+
+$(eval $(call SET_NXP_MAKE_FLAG,DCFG_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,TIMER_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,INTERCONNECT_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,GIC_NEEDED,BL31))
+$(eval $(call SET_NXP_MAKE_FLAG,CONSOLE_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,PMU_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,DDR_DRIVER_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,TZASC_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,I2C_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,IMG_LOADR_NEEDED,BL2))
+
+# Selecting PSCI & SIP_SVC support
+$(eval $(call SET_NXP_MAKE_FLAG,PSCI_NEEDED,BL31))
+$(eval $(call SET_NXP_MAKE_FLAG,SIPSVC_NEEDED,BL31))
+
+PLAT_INCLUDES += -I${PLAT_COMMON_PATH}/include/default\
+ -I${BOARD_PATH}\
+ -I${PLAT_COMMON_PATH}/include/default/ch_${CHASSIS}\
+ -I${PLAT_SOC_PATH}/include\
+ -I${PLAT_COMMON_PATH}/soc_errata
+
+ifeq (${SECURE_BOOT},yes)
+include ${PLAT_COMMON_PATH}/tbbr/tbbr.mk
+endif
+
+ifeq ($(WARM_BOOT),yes)
+include ${PLAT_COMMON_PATH}/warm_reset/warm_reset.mk
+endif
+
+ifeq (${NXP_NV_SW_MAINT_LAST_EXEC_DATA}, yes)
+include ${PLAT_COMMON_PATH}/nv_storage/nv_storage.mk
+endif
+
+ifeq (${PSCI_NEEDED}, yes)
+include ${PLAT_COMMON_PATH}/psci/psci.mk
+endif
+
+ifeq (${SIPSVC_NEEDED}, yes)
+include ${PLAT_COMMON_PATH}/sip_svc/sipsvc.mk
+endif
+
+ifeq (${DDR_FIP_IO_NEEDED}, yes)
+include ${PLAT_COMMON_PATH}/fip_handler/ddr_fip/ddr_fip_io.mk
+endif
+
+# For fuse-fip & fuse-programming
+ifeq (${FUSE_PROG}, 1)
+include ${PLAT_COMMON_PATH}/fip_handler/fuse_fip/fuse.mk
+endif
+
+ifeq (${IMG_LOADR_NEEDED},yes)
+include $(PLAT_COMMON_PATH)/img_loadr/img_loadr.mk
+endif
+
+# Adding source files for the above selected drivers.
+include ${PLAT_DRIVERS_PATH}/drivers.mk
+
+# Adding SoC specific files
+include ${PLAT_COMMON_PATH}/soc_errata/errata.mk
+
+PLAT_INCLUDES += ${NV_STORAGE_INCLUDES}\
+ ${WARM_RST_INCLUDES}
+
+BL31_SOURCES += ${PLAT_SOC_PATH}/$(ARCH)/${SOC}.S\
+ ${WARM_RST_BL31_SOURCES}\
+ ${PSCI_SOURCES}\
+ ${SIPSVC_SOURCES}\
+ ${PLAT_COMMON_PATH}/$(ARCH)/bl31_data.S
+
+PLAT_BL_COMMON_SOURCES += ${PLAT_COMMON_PATH}/$(ARCH)/ls_helpers.S\
+ ${PLAT_SOC_PATH}/aarch64/${SOC}_helpers.S\
+ ${NV_STORAGE_SOURCES}\
+ ${WARM_RST_BL_COMM_SOURCES}\
+ ${PLAT_SOC_PATH}/soc.c
+
+ifeq (${TEST_BL31}, 1)
+BL31_SOURCES += ${PLAT_SOC_PATH}/$(ARCH)/bootmain64.S \
+ ${PLAT_SOC_PATH}/$(ARCH)/nonboot64.S
+endif
+
+BL2_SOURCES += ${DDR_CNTLR_SOURCES}\
+ ${TBBR_SOURCES}\
+ ${FUSE_SOURCES}
+
+# Adding TFA setup files
+include ${PLAT_PATH}/common/setup/common.mk
diff --git a/plat/nxp/soc-ls1043a/aarch64/ls1043a.S b/plat/nxp/soc-ls1043a/aarch64/ls1043a.S
new file mode 100644
index 0000000..a1baf79
--- /dev/null
+++ b/plat/nxp/soc-ls1043a/aarch64/ls1043a.S
@@ -0,0 +1,1637 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <cortex_a53.h>
+#include <dcfg_lsch2.h>
+#include <plat_gic.h>
+#include <scfg.h>
+
+#include <bl31_data.h>
+#include <plat_psci.h>
+#include <platform_def.h>
+
+/* the BASE address for these offsets is AUX_01_DATA in the */
+/* bootcore's psci data region */
+#define DEVDISR2_MASK_OFFSET 0x0 /* references AUX_01_DATA */
+#define DEVDISR5_MASK_OFFSET 0x8 /* references AUX_02_DATA */
+#define CPUACTLR_DATA_OFFSET 0x10 /* references AUX_03_DATA */
+/* the BASE address for these offsets is AUX_04_DATA in the */
+/* bootcore's psci data region */
+#define GICD_BASE_ADDR_OFFSET 0x0 /* references AUX_04_DATA */
+#define GICC_BASE_ADDR_OFFSET 0x8 /* references AUX_05_DATA */
+
+#define DAIF_DATA AUX_06_DATA /* references AUX_06_DATA */
+
+#define IPSTPACK_RETRY_CNT 0x10000
+#define DDR_SLEEP_RETRY_CNT 0x10000
+#define CPUACTLR_EL1 S3_1_C15_C2_0
+#define DDR_SDRAM_CFG_2_FRCSR 0x80000000
+#define DDR_SDRAM_CFG_2_OFFSET 0x114
+#define DDR_TIMING_CFG_4_OFFSET 0x160
+#define DDR_CNTRL_BASE_ADDR 0x01080000
+
+#define DLL_LOCK_MASK 0x3
+#define DLL_LOCK_VALUE 0x2
+
+#define ERROR_DDR_SLEEP -1
+#define ERROR_DDR_WAKE -2
+#define ERROR_NO_QUIESCE -3
+
+#define CORE_RESTARTABLE 0
+#define CORE_NOT_RESTARTABLE 1
+
+#define RESET_RETRY_CNT 800
+
+.global soc_init_lowlevel
+.global soc_init_percpu
+.global _soc_core_release
+.global _soc_core_restart
+.global _soc_ck_disabled
+.global _soc_sys_reset
+.global _soc_sys_off
+.global _getGICD_BaseAddr
+.global _getGICC_BaseAddr
+.global _soc_set_start_addr
+.global _soc_core_prep_off
+.global _soc_core_entr_off
+.global _soc_core_exit_off
+.global _soc_core_prep_stdby
+.global _soc_core_entr_stdby
+.global _soc_core_exit_stdby
+.global _soc_core_prep_pwrdn
+.global _soc_core_entr_pwrdn
+.global _soc_core_exit_pwrdn
+.global _soc_clstr_prep_stdby
+.global _soc_clstr_exit_stdby
+.global _soc_clstr_prep_pwrdn
+.global _soc_clstr_exit_pwrdn
+.global _soc_sys_prep_stdby
+.global _soc_sys_exit_stdby
+.global _soc_sys_prep_pwrdn
+.global _soc_sys_pwrdn_wfi
+.global _soc_sys_exit_pwrdn
+
+/*
+ * This function initialize the soc.
+ * in: void
+ * out: void
+ */
+func soc_init_lowlevel
+ ret
+endfunc soc_init_lowlevel
+
+/*
+ * void soc_init_percpu(void)
+ * this function performs any soc-specific initialization that is needed on
+ * a per-core basis
+ * in: none
+ * out: none
+ * uses x0, x1, x2, x3
+ */
+func soc_init_percpu
+ mov x3, x30
+
+ bl plat_my_core_mask
+ mov x2, x0
+
+ /* see if this core is marked for prefetch disable */
+ mov x0, #PREFETCH_DIS_OFFSET
+ bl _get_global_data /* 0-1 */
+ tst x0, x2
+ b.eq 1f
+ bl _disable_ldstr_pfetch_A53 /* 0 */
+1:
+ mov x30, x3
+ ret
+endfunc soc_init_percpu
+
+/*
+ * part of CPU_ON
+ * this function releases a secondary core from reset
+ * in: x0 = core_mask_lsb
+ * out: none
+ * uses: x0, x1, x2, x3
+ */
+_soc_core_release:
+
+#if (TEST_BL31)
+ mov w2, w0
+ CoreMaskMsb w2, w3
+ /* x2 = core mask msb */
+#else
+ mov x2, x0
+#endif
+ /* write COREBCR */
+ ldr x1, =NXP_SCFG_ADDR
+ rev w3, w2
+ str w3, [x1, #SCFG_COREBCR_OFFSET]
+ isb
+
+ /* read-modify-write BRR */
+ mov x1, #NXP_DCFG_ADDR
+ ldr w2, [x1, #DCFG_BRR_OFFSET]
+ rev w3, w2
+ orr w3, w3, w0
+ rev w2, w3
+ str w2, [x1, #DCFG_BRR_OFFSET]
+ isb
+
+ /* send event */
+ sev
+ isb
+ ret
+
+
+/*
+ * part of CPU_ON
+ * this function restarts a core shutdown via _soc_core_entr_off
+ * in: x0 = core mask lsb (of the target cpu)
+ * out: x0 == 0, on success
+ * x0 != 0, on failure
+ * uses x0 ~ x5
+ */
+_soc_core_restart:
+ mov x5, x30
+ mov x3, x0
+
+ /* x3 = core mask lsb */
+ bl _getGICD_BaseAddr
+ mov x4, x0
+
+ /* x4 = GICD_BASE_ADDR */
+ /* enable forwarding of group 0 interrupts by setting GICD_CTLR[0] = 1 */
+ ldr w1, [x4, #GICD_CTLR_OFFSET]
+ orr w1, w1, #GICD_CTLR_EN_GRP0
+ str w1, [x4, #GICD_CTLR_OFFSET]
+ dsb sy
+ isb
+
+ /*
+ * fire SGI by writing to GICD_SGIR the following values:
+ * [25:24] = 0x0 (forward interrupt to the CPU interfaces specified in CPUTargetList field)
+ * [23:16] = core mask lsb[7:0] (forward interrupt to target cpu)
+ * [15] = 0 (forward SGI only if it is configured as group 0 interrupt)
+ * [3:0] = 0xF (interrupt ID = 15)
+ */
+ lsl w1, w3, #16
+ orr w1, w1, #0xF
+ str w1, [x4, #GICD_SGIR_OFFSET]
+ dsb sy
+ isb
+
+ /* load '0' on success */
+ mov x0, xzr
+
+ mov x30, x5
+ ret
+
+/*
+ * this function determines if a core is disabled via COREDISR
+ * in: w0 = core_mask_lsb
+ * out: w0 = 0, core not disabled
+ * w0 != 0, core disabled
+ * uses x0, x1, x2
+ */
+_soc_ck_disabled:
+
+ /* get base addr of dcfg block */
+ ldr x1, =NXP_DCFG_ADDR
+
+ /* read COREDISR */
+ ldr w1, [x1, #DCFG_COREDISR_OFFSET]
+ rev w2, w1
+
+ /* test core bit */
+ and w0, w2, w0
+ ret
+
+/*
+ * this function resets the system via SoC-specific methods
+ * in: none
+ * out: none
+ * uses x0, x1, x2, x3
+ */
+_soc_sys_reset:
+
+ ldr x2, =NXP_DCFG_ADDR
+
+ /* make sure the mask is cleared in the reset request mask register */
+ mov w1, wzr
+ str w1, [x2, #DCFG_RSTRQMR1_OFFSET]
+
+ /* x2 = NXP_DCFG_ADDR */
+
+ /* set the reset request */
+ ldr w1, =RSTCR_RESET_REQ
+ ldr x3, =DCFG_RSTCR_OFFSET
+ rev w0, w1
+ str w0, [x2, x3]
+
+ /* x2 = NXP_DCFG_ADDR */
+ /* x3 = DCFG_RSTCR_OFFSET */
+
+ /* just in case this address range is mapped as cacheable,
+ * flush the write out of the dcaches */
+ add x3, x2, x3
+ dc cvac, x3
+ dsb st
+ isb
+
+ /* Note: this function does not return */
+1:
+ wfi
+ b 1b
+
+
+/*
+ * part of SYSTEM_OFF
+ * this function turns off the SoC clocks
+ * Note: this function is not intended to return, and the only allowable
+ * recovery is POR
+ * in: none
+ * out: none
+ * uses x0 ~ x8
+ */
+_soc_sys_off:
+
+ /* mask interrupts at the core */
+ mrs x1, DAIF
+ mov x0, #DAIF_SET_MASK
+ orr x0, x1, x0
+ msr DAIF, x0
+
+ /* disable icache, dcache, mmu @ EL1 */
+ mov x1, #SCTLR_I_C_M_MASK
+ mrs x0, sctlr_el1
+ bic x0, x0, x1
+ msr sctlr_el1, x0
+
+ /* disable dcache for EL3 */
+ mrs x1, SCTLR_EL3
+ bic x1, x1, #SCTLR_C_MASK
+ /* make sure icache is enabled */
+ orr x1, x1, #SCTLR_I_MASK
+ msr SCTLR_EL3, x1
+ isb
+
+ /* set WFIL2_EN in SCFG_COREPMCR */
+ ldr x0, =SCFG_COREPMCR_OFFSET
+ ldr x1, =COREPMCR_WFIL2
+ bl write_reg_scfg
+
+ /* set OVRD_EN in RCPM2_POWMGTDCR */
+ ldr x0, =RCPM2_POWMGTDCR_OFFSET
+ ldr x1, =POWMGTDCR_OVRD_EN
+ bl write_reg_rcpm2
+
+ /* read IPPDEXPCR0 @ RCPM_IPPDEXPCR0 */
+ ldr x0, =RCPM_IPPDEXPCR0_OFFSET
+ bl read_reg_rcpm
+ mov x7, x0
+
+ /* build an override mask for IPSTPCR4/IPSTPACK4/DEVDISR5 */
+ mov x5, xzr
+ ldr x6, =IPPDEXPCR_MASK2
+ and x6, x6, x7
+ cbz x6, 1f
+
+ /* x5 = override mask
+ * x6 = IPPDEXPCR bits for DEVDISR5
+ * x7 = IPPDEXPCR */
+
+ /* get the overrides */
+ orr x4, x5, #DEVDISR5_I2C_1
+ tst x6, #IPPDEXPCR_I2C1
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR5_LPUART1
+ tst x6, #IPPDEXPCR_LPUART1
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR5_FLX_TMR
+ tst x6, #IPPDEXPCR_FLX_TMR1
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR5_OCRAM1
+ tst x6, #IPPDEXPCR_OCRAM1
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR5_GPIO
+ tst x6, #IPPDEXPCR_GPIO1
+ csel x5, x5, x4, EQ
+1:
+ /* store the DEVDISR5 override mask */
+ ldr x2, =BC_PSCI_BASE
+ add x2, x2, #AUX_01_DATA
+ str w5, [x2, #DEVDISR5_MASK_OFFSET]
+
+ /* build an override mask for IPSTPCR1/IPSTPACK1/DEVDISR2 */
+ mov x5, xzr
+ ldr x6, =IPPDEXPCR_MASK1
+ and x6, x6, x7
+ cbz x6, 2f
+
+ /* x5 = override mask */
+ /* x6 = IPPDEXPCR bits for DEVDISR2 */
+
+ /* get the overrides */
+ orr x4, x5, #DEVDISR2_FMAN1_MAC1
+ tst x6, #IPPDEXPCR_MAC1_1
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR2_FMAN1_MAC2
+ tst x6, #IPPDEXPCR_MAC1_2
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR2_FMAN1_MAC3
+ tst x6, #IPPDEXPCR_MAC1_3
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR2_FMAN1_MAC4
+ tst x6, #IPPDEXPCR_MAC1_4
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR2_FMAN1_MAC5
+ tst x6, #IPPDEXPCR_MAC1_5
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR2_FMAN1_MAC6
+ tst x6, #IPPDEXPCR_MAC1_6
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR2_FMAN1_MAC9
+ tst x6, #IPPDEXPCR_MAC1_9
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR2_FMAN1
+ tst x6, #IPPDEXPCR_FM1
+ csel x5, x5, x4, EQ
+
+2:
+ /* store the DEVDISR2 override mask */
+ ldr x2, =BC_PSCI_BASE
+ add x2, x2, #AUX_01_DATA
+ str w5, [x2, #DEVDISR2_MASK_OFFSET]
+
+ /* x5 = DEVDISR2 override mask */
+
+ /* write IPSTPCR0 - no overrides */
+ ldr x0, =RCPM2_IPSTPCR0_OFFSET
+ ldr x1, =IPSTPCR0_VALUE
+ bl write_reg_rcpm2
+
+ /* x5 = DEVDISR2 override mask */
+
+ /* write IPSTPCR1 - overrides possible */
+ ldr x0, =RCPM2_IPSTPCR1_OFFSET
+ ldr x1, =IPSTPCR1_VALUE
+ bic x1, x1, x5
+ bl write_reg_rcpm2
+
+ /* write IPSTPCR2 - no overrides */
+ ldr x0, =RCPM2_IPSTPCR2_OFFSET
+ ldr x1, =IPSTPCR2_VALUE
+ bl write_reg_rcpm2
+
+ /* write IPSTPCR3 - no overrides */
+ ldr x0, =RCPM2_IPSTPCR3_OFFSET
+ ldr x1, =IPSTPCR3_VALUE
+ bl write_reg_rcpm2
+
+ /* write IPSTPCR4 - overrides possible */
+ ldr x2, =BC_PSCI_BASE
+ add x2, x2, #AUX_01_DATA
+ ldr w6, [x2, #DEVDISR5_MASK_OFFSET]
+ ldr x0, =RCPM2_IPSTPCR4_OFFSET
+ ldr x1, =IPSTPCR4_VALUE
+ bic x1, x1, x6
+ bl write_reg_rcpm2
+
+ /* x5 = DEVDISR2 override mask */
+ /* x6 = DEVDISR5 override mask */
+
+ /* poll on IPSTPACK0 */
+ ldr x3, =RCPM2_IPSTPACKR0_OFFSET
+ ldr x4, =IPSTPCR0_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+3:
+ mov x0, x3
+ bl read_reg_rcpm2
+ cmp x0, x4
+ b.eq 14f
+ sub x7, x7, #1
+ cbnz x7, 3b
+
+14:
+ /* poll on IPSTPACK1 */
+ ldr x3, =IPSTPCR1_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+ bic x4, x3, x5
+ ldr x3, =RCPM2_IPSTPACKR1_OFFSET
+4:
+ mov x0, x3
+ bl read_reg_rcpm2
+ cmp x0, x4
+ b.eq 15f
+ sub x7, x7, #1
+ cbnz x7, 4b
+
+15:
+ /* poll on IPSTPACK2 */
+ ldr x3, =RCPM2_IPSTPACKR2_OFFSET
+ ldr x4, =IPSTPCR2_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+5:
+ mov x0, x3
+ bl read_reg_rcpm2
+ cmp x0, x4
+ b.eq 16f
+ sub x7, x7, #1
+ cbnz x7, 5b
+
+16:
+ /* poll on IPSTPACK3 */
+ ldr x3, =RCPM2_IPSTPACKR3_OFFSET
+ ldr x4, =IPSTPCR3_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+6:
+ mov x0, x3
+ bl read_reg_rcpm2
+ cmp x0, x4
+ b.eq 17f
+ sub x7, x7, #1
+ cbnz x7, 6b
+
+17:
+ /* poll on IPSTPACK4 */
+ ldr x3, =IPSTPCR4_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+ bic x4, x3, x6
+ ldr x3, =RCPM2_IPSTPACKR4_OFFSET
+7:
+ mov x0, x3
+ bl read_reg_rcpm2
+ cmp x0, x4
+ b.eq 18f
+ sub x7, x7, #1
+ cbnz x7, 7b
+
+18:
+ ldr x7, =BC_PSCI_BASE
+ add x7, x7, #AUX_01_DATA
+
+ /* x5 = DEVDISR2 override mask
+ * x6 = DEVDISR5 override mask
+ * x7 = [soc_data_area] */
+
+ /* DEVDISR1 - load new value */
+ mov x0, #DCFG_DEVDISR1_OFFSET
+ bl read_reg_dcfg
+ mov x0, #DCFG_DEVDISR1_OFFSET
+ ldr x1, =DEVDISR1_VALUE
+ bl write_reg_dcfg
+
+ /* DEVDISR2 - load new value */
+ mov x0, #DCFG_DEVDISR2_OFFSET
+ bl read_reg_dcfg
+ mov x0, #DCFG_DEVDISR2_OFFSET
+ ldr x1, =DEVDISR2_VALUE
+ bic x1, x1, x5
+ bl write_reg_dcfg
+
+ /* x6 = DEVDISR5 override mask */
+ /* x7 = [soc_data_area] */
+
+ /* DEVDISR3 - load new value */
+ mov x0, #DCFG_DEVDISR3_OFFSET
+ bl read_reg_dcfg
+ mov x0, #DCFG_DEVDISR3_OFFSET
+ ldr x1, =DEVDISR3_VALUE
+ bl write_reg_dcfg
+
+ /* DEVDISR4 - load new value */
+ mov x0, #DCFG_DEVDISR4_OFFSET
+ bl read_reg_dcfg
+ mov x0, #DCFG_DEVDISR4_OFFSET
+ ldr x1, =DEVDISR4_VALUE
+ bl write_reg_dcfg
+
+ /* DEVDISR5 - load new value */
+ mov x0, #DCFG_DEVDISR5_OFFSET
+ bl read_reg_dcfg
+ mov x0, #DCFG_DEVDISR5_OFFSET
+ ldr x1, =DEVDISR5_VALUE
+ bic x1, x1, x6
+ bl write_reg_dcfg
+
+ /* x7 = [soc_data_area] */
+
+ /* disable data prefetch */
+ mrs x0, CPUACTLR_EL1
+ bic x0, x0, #CPUACTLR_L1PCTL_MASK
+ msr CPUACTLR_EL1, x0
+
+ /* x6 = DEVDISR5 override mask */
+
+ /* setup registers for cache-only execution */
+ ldr x5, =IPSTPCR4_VALUE
+ bic x5, x5, x6
+ mov x6, #DDR_CNTRL_BASE_ADDR
+ mov x7, #DCSR_RCPM2_BASE
+ mov x8, #NXP_DCFG_ADDR
+ dsb sy
+ isb
+
+ /* set the DLL_LOCK cycle count */
+ ldr w1, [x6, #DDR_TIMING_CFG_4_OFFSET]
+ rev w2, w1
+ bic w2, w2, #DLL_LOCK_MASK
+ orr w2, w2, #DLL_LOCK_VALUE
+ rev w1, w2
+ str w1, [x6, #DDR_TIMING_CFG_4_OFFSET]
+
+ /* x5 = ipstpcr4 (IPSTPCR4_VALUE bic DEVDISR5_MASK)
+ * x6 = DDR_CNTRL_BASE_ADDR
+ * x7 = DCSR_RCPM2_BASE
+ * x8 = NXP_DCFG_ADDR */
+
+ /* enter the cache-only sequence - there is no return */
+ b final_shutdown
+
+
+/*
+ * part of CPU_OFF
+ * this function programs SoC & GIC registers in preparation for shutting down
+ * the core
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0 ~ x7
+ */
+_soc_core_prep_off:
+ mov x7, x30
+ mov x6, x0
+
+ /* make sure the smpen bit is set */
+ mrs x2, CORTEX_A53_ECTLR_EL1
+ orr x2, x2, #CPUECTLR_SMPEN_MASK
+ msr CORTEX_A53_ECTLR_EL1, x2
+ isb
+
+ /* configure the cpu interface */
+
+ /* disable signaling of ints */
+ bl _getGICC_BaseAddr // 0-1
+ mov x4, x0
+
+ ldr w3, [x4, #GICC_CTLR_OFFSET]
+ bic w3, w3, #GICC_CTLR_EN_GRP0
+ bic w3, w3, #GICC_CTLR_EN_GRP1
+ str w3, [x4, #GICC_CTLR_OFFSET]
+ dsb sy
+ isb
+
+ /*
+ * x3 = GICC_CTRL
+ * x4 = GICC_BASE_ADDR
+ * x6 = core mask
+ */
+
+ /* set the priority filter */
+ ldr w2, [x4, #GICC_PMR_OFFSET]
+ orr w2, w2, #GICC_PMR_FILTER
+ str w2, [x4, #GICC_PMR_OFFSET]
+
+ /* setup GICC_CTLR */
+ bic w3, w3, #GICC_CTLR_ACKCTL_MASK
+ orr w3, w3, #GICC_CTLR_FIQ_EN_MASK
+ orr w3, w3, #GICC_CTLR_EOImodeS_MASK
+ orr w3, w3, #GICC_CTLR_CBPR_MASK
+ str w3, [x4, #GICC_CTLR_OFFSET]
+
+ /* x3 = GICC_CTRL */
+ /* x4 = GICC_BASE_ADDR */
+
+ /* setup the banked-per-core GICD registers */
+ bl _getGICD_BaseAddr
+
+ /*
+ * x0 = GICD_BASE_ADDR
+ * x3 = GICC_CTRL
+ * x4 = GICC_BASE_ADDR
+ * x6 = core mask
+ */
+
+ /* define SGI15 as Grp0 */
+ ldr w2, [x0, #GICD_IGROUPR0_OFFSET]
+ bic w2, w2, #GICD_IGROUP0_SGI15
+ str w2, [x0, #GICD_IGROUPR0_OFFSET]
+
+ /* set priority of SGI 15 to highest... */
+ ldr w2, [x0, #GICD_IPRIORITYR3_OFFSET]
+ bic w2, w2, #GICD_IPRIORITY_SGI15_MASK
+ str w2, [x0, #GICD_IPRIORITYR3_OFFSET]
+
+ /* enable SGI 15 */
+ ldr w2, [x0, #GICD_ISENABLER0_OFFSET]
+ orr w2, w2, #GICD_ISENABLE0_SGI15
+ str w2, [x0, #GICD_ISENABLER0_OFFSET]
+
+ /* enable the cpu interface */
+ orr w3, w3, #GICC_CTLR_EN_GRP0
+ str w3, [x4, #GICC_CTLR_OFFSET]
+
+ /* x0 = GICD_BASE_ADDR
+ * x6 = core mask */
+
+ /* clear any pending SGIs */
+ add x0, x0, #GICD_CPENDSGIR3_OFFSET
+ ldr x2, =GICD_CPENDSGIR_CLR_MASK
+ str w2, [x0]
+
+ dsb sy
+ isb
+ mov x30, x7
+ ret
+
+/*
+ * part of CPU_OFF
+ * this function performs the final steps to shutdown the core
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0 ~ x5
+ */
+_soc_core_entr_off:
+ mov x5, x30
+ mov x4, x0
+
+ bl _getGICD_BaseAddr
+ mov x3, x0
+
+ /* x3 = GICD_BASE_ADDR */
+ /* x4 = core mask (lsb) */
+
+3:
+ /* enter low-power state by executing wfi */
+ wfi
+
+ /* x3 = GICD_BASE_ADDR */
+ /* x4 = core mask (lsb) */
+
+ /* see if we got hit by SGI 15 */
+ add x0, x3, #GICD_SPENDSGIR3_OFFSET
+ ldr w2, [x0]
+ and w2, w2, #GICD_SPENDSGIR3_SGI15_MASK
+ cbz w2, 4f
+
+ /* clear the pending SGI */
+ ldr x2, =GICD_CPENDSGIR_CLR_MASK
+ add x0, x3, #GICD_CPENDSGIR3_OFFSET
+ str w2, [x0]
+4:
+ /* check if core has been turned on */
+ mov x0, x4
+ bl _getCoreState
+
+ /* x0 = core state */
+ cmp x0, #CORE_WAKEUP
+ b.ne 3b
+
+ /* if we get here, then we have exited the wfi */
+ dsb sy
+ isb
+ mov x30, x5
+ ret
+
+/*
+ * part of CPU_OFF
+ * this function starts the process of starting a core back up
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0 ~ x5
+ */
+_soc_core_exit_off:
+ mov x5, x30
+ mov x4, x0
+
+ /* x4 = core mask */
+
+ bl _getGICC_BaseAddr
+ mov x2, x0
+
+ /* read GICC_IAR */
+ ldr w0, [x2, #GICC_IAR_OFFSET]
+
+ /* write GICC_EIOR - signal end-of-interrupt */
+ str w0, [x2, #GICC_EOIR_OFFSET]
+
+ /* write GICC_DIR - disable interrupt */
+ str w0, [x2, #GICC_DIR_OFFSET]
+
+ /* x2 = GICC_BASE_ADDR */
+
+ /* disable signaling of grp0 ints */
+ ldr w1, [x2, #GICC_CTLR_OFFSET]
+ bic w1, w1, #GICC_CTLR_EN_GRP0
+ str w1, [x2, #GICC_CTLR_OFFSET]
+
+ dsb sy
+ isb
+ mov x30, x5
+ ret
+
+/*
+ * this function loads a 64-bit execution address of the core in the soc registers
+ * BOOTLOCPTRL/H
+ * in: x0, 64-bit address to write to BOOTLOCPTRL/H
+ * uses x0, x1, x2, x3
+ */
+_soc_set_start_addr:
+ /* get the 64-bit base address of the scfg block */
+ ldr x2, =NXP_SCFG_ADDR
+
+ /* write the 32-bit BOOTLOCPTRL register (offset 0x604 in the scfg block) */
+ mov x1, x0
+ rev w3, w1
+ str w3, [x2, #SCFG_BOOTLOCPTRL_OFFSET]
+
+ /* write the 32-bit BOOTLOCPTRH register (offset 0x600 in the scfg block) */
+ lsr x1, x0, #32
+ rev w3, w1
+ str w3, [x2, #SCFG_BOOTLOCPTRH_OFFSET]
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function puts the calling core into standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0
+ */
+_soc_core_entr_stdby:
+ dsb sy
+ isb
+ wfi
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to standby
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+_soc_core_prep_stdby:
+ /* clear CORTEX_A53_ECTLR_EL1[2:0] */
+ mrs x1, CORTEX_A53_ECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ msr CORTEX_A53_ECTLR_EL1, x1
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs any SoC-specific cleanup after standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+_soc_core_exit_stdby:
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+_soc_core_prep_pwrdn:
+ /* make sure the smp bit is set */
+ mrs x1, CORTEX_A53_ECTLR_EL1
+ orr x1, x1, #CPUECTLR_SMPEN_MASK
+ msr CORTEX_A53_ECTLR_EL1, x1
+ isb
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function puts the calling core into a power-down state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0
+ */
+_soc_core_entr_pwrdn:
+ dsb sy
+ isb
+ wfi
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs any SoC-specific cleanup after power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+_soc_core_exit_pwrdn:
+ ret
+
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to standby
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+_soc_clstr_prep_stdby:
+ /* clear CORTEX_A53_ECTLR_EL1[2:0] */
+ mrs x1, CORTEX_A53_ECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ msr CORTEX_A53_ECTLR_EL1, x1
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs any SoC-specific cleanup after standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+_soc_clstr_exit_stdby:
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+_soc_clstr_prep_pwrdn:
+ /* make sure the smp bit is set */
+ mrs x1, CORTEX_A53_ECTLR_EL1
+ orr x1, x1, #CPUECTLR_SMPEN_MASK
+ msr CORTEX_A53_ECTLR_EL1, x1
+ isb
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs any SoC-specific cleanup after power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+_soc_clstr_exit_pwrdn:
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to standby
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+_soc_sys_prep_stdby:
+ /* clear CORTEX_A53_ECTLR_EL1[2:0] */
+ mrs x1, CORTEX_A53_ECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ msr CORTEX_A53_ECTLR_EL1, x1
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs any SoC-specific cleanup after standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+_soc_sys_exit_stdby:
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to
+ * suspend-to-power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4
+ */
+_soc_sys_prep_pwrdn:
+ mov x4, x30
+ /* make sure the smp bit is set */
+ mrs x1, CORTEX_A53_ECTLR_EL1
+ orr x1, x1, #CPUECTLR_SMPEN_MASK
+ msr CORTEX_A53_ECTLR_EL1, x1
+ isb
+
+ /* set WFIL2_EN in SCFG_COREPMCR */
+ ldr x0, =SCFG_COREPMCR_OFFSET
+ ldr x1, =COREPMCR_WFIL2
+ bl write_reg_scfg // 0-3
+
+ /* set OVRD_EN in RCPM2_POWMGTDCR */
+ ldr x0, =RCPM2_POWMGTDCR_OFFSET
+ ldr x1, =POWMGTDCR_OVRD_EN
+ bl write_reg_rcpm2 // 0-3
+
+ mov x30, x4
+ ret
+/*
+ * part of CPU_SUSPEND
+ * this function puts the calling core, and potentially the soc, into a
+ * low-power state
+ * in: x0 = core mask lsb
+ * out: x0 = 0, success
+ * x0 < 0, failure
+ * uses x0 ~ x9
+ */
+_soc_sys_pwrdn_wfi:
+ mov x18, x30
+
+ /* read IPPDEXPCR0 @ RCPM_IPPDEXPCR0 */
+ ldr x0, =RCPM_IPPDEXPCR0_OFFSET
+ bl read_reg_rcpm
+ mov x7, x0
+
+ /* build an override mask for IPSTPCR4/IPSTPACK4/DEVDISR5 */
+ mov x5, xzr
+ ldr x6, =IPPDEXPCR_MASK2
+ and x6, x6, x7
+ cbz x6, 1f
+
+ /* x5 = override mask
+ * x6 = IPPDEXPCR bits for DEVDISR5
+ * x7 = IPPDEXPCR */
+
+ /* get the overrides */
+ orr x4, x5, #DEVDISR5_I2C_1
+ tst x6, #IPPDEXPCR_I2C1
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR5_LPUART1
+ tst x6, #IPPDEXPCR_LPUART1
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR5_FLX_TMR
+ tst x6, #IPPDEXPCR_FLX_TMR1
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR5_OCRAM1
+ tst x6, #IPPDEXPCR_OCRAM1
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR5_GPIO
+ tst x6, #IPPDEXPCR_GPIO1
+ csel x5, x5, x4, EQ
+1:
+ /* store the DEVDISR5 override mask */
+ ldr x2, =BC_PSCI_BASE
+ add x2, x2, #AUX_01_DATA
+ str w5, [x2, #DEVDISR5_MASK_OFFSET]
+
+ /* build an override mask for IPSTPCR1/IPSTPACK1/DEVDISR2 */
+ mov x5, xzr
+ ldr x6, =IPPDEXPCR_MASK1
+ and x6, x6, x7
+ cbz x6, 2f
+
+ /* x5 = override mask */
+ /* x6 = IPPDEXPCR bits for DEVDISR2 */
+
+ /* get the overrides */
+ orr x4, x5, #DEVDISR2_FMAN1_MAC1
+ tst x6, #IPPDEXPCR_MAC1_1
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR2_FMAN1_MAC2
+ tst x6, #IPPDEXPCR_MAC1_2
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR2_FMAN1_MAC3
+ tst x6, #IPPDEXPCR_MAC1_3
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR2_FMAN1_MAC4
+ tst x6, #IPPDEXPCR_MAC1_4
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR2_FMAN1_MAC5
+ tst x6, #IPPDEXPCR_MAC1_5
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR2_FMAN1_MAC6
+ tst x6, #IPPDEXPCR_MAC1_6
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR2_FMAN1_MAC9
+ tst x6, #IPPDEXPCR_MAC1_9
+ csel x5, x5, x4, EQ
+
+ orr x4, x5, #DEVDISR2_FMAN1
+ tst x6, #IPPDEXPCR_FM1
+ csel x5, x5, x4, EQ
+
+2:
+ /* store the DEVDISR2 override mask */
+ ldr x2, =BC_PSCI_BASE
+ add x2, x2, #AUX_01_DATA
+ str w5, [x2, #DEVDISR2_MASK_OFFSET]
+
+ /* x5 = DEVDISR2 override mask */
+
+ /* write IPSTPCR0 - no overrides */
+ ldr x0, =RCPM2_IPSTPCR0_OFFSET
+ ldr x1, =IPSTPCR0_VALUE
+ bl write_reg_rcpm2
+
+ /* x5 = DEVDISR2 override mask */
+
+ /* write IPSTPCR1 - overrides possible */
+ ldr x0, =RCPM2_IPSTPCR1_OFFSET
+ ldr x1, =IPSTPCR1_VALUE
+ bic x1, x1, x5
+ bl write_reg_rcpm2
+
+ /* write IPSTPCR2 - no overrides */
+ ldr x0, =RCPM2_IPSTPCR2_OFFSET
+ ldr x1, =IPSTPCR2_VALUE
+ bl write_reg_rcpm2
+
+ /* write IPSTPCR3 - no overrides */
+ ldr x0, =RCPM2_IPSTPCR3_OFFSET
+ ldr x1, =IPSTPCR3_VALUE
+ bl write_reg_rcpm2
+
+ /* write IPSTPCR4 - overrides possible */
+ ldr x2, =BC_PSCI_BASE
+ add x2, x2, #AUX_01_DATA
+ ldr w6, [x2, #DEVDISR5_MASK_OFFSET]
+ ldr x0, =RCPM2_IPSTPCR4_OFFSET
+ ldr x1, =IPSTPCR4_VALUE
+ bic x1, x1, x6
+ bl write_reg_rcpm2
+
+ /* x5 = DEVDISR2 override mask */
+ /* x6 = DEVDISR5 override mask */
+
+ /* poll on IPSTPACK0 */
+ ldr x3, =RCPM2_IPSTPACKR0_OFFSET
+ ldr x4, =IPSTPCR0_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+3:
+ mov x0, x3
+ bl read_reg_rcpm2
+ cmp x0, x4
+ b.eq 14f
+ sub x7, x7, #1
+ cbnz x7, 3b
+
+14:
+ /* poll on IPSTPACK1 */
+ ldr x3, =IPSTPCR1_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+ bic x4, x3, x5
+ ldr x3, =RCPM2_IPSTPACKR1_OFFSET
+4:
+ mov x0, x3
+ bl read_reg_rcpm2
+ cmp x0, x4
+ b.eq 15f
+ sub x7, x7, #1
+ cbnz x7, 4b
+
+15:
+ /* poll on IPSTPACK2 */
+ ldr x3, =RCPM2_IPSTPACKR2_OFFSET
+ ldr x4, =IPSTPCR2_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+5:
+ mov x0, x3
+ bl read_reg_rcpm2
+ cmp x0, x4
+ b.eq 16f
+ sub x7, x7, #1
+ cbnz x7, 5b
+
+16:
+ /* poll on IPSTPACK3 */
+ ldr x3, =RCPM2_IPSTPACKR3_OFFSET
+ ldr x4, =IPSTPCR3_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+6:
+ mov x0, x3
+ bl read_reg_rcpm2
+ cmp x0, x4
+ b.eq 17f
+ sub x7, x7, #1
+ cbnz x7, 6b
+
+17:
+ /* poll on IPSTPACK4 */
+ ldr x3, =IPSTPCR4_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+ bic x4, x3, x6
+ ldr x3, =RCPM2_IPSTPACKR4_OFFSET
+7:
+ mov x0, x3
+ bl read_reg_rcpm2
+ cmp x0, x4
+ b.eq 18f
+ sub x7, x7, #1
+ cbnz x7, 7b
+
+18:
+ ldr x7, =BC_PSCI_BASE
+ add x7, x7, #AUX_01_DATA
+
+ /* x5 = DEVDISR2 override mask
+ * x6 = DEVDISR5 override mask
+ * x7 = [soc_data_area] */
+
+ /* save DEVDISR1 and load new value */
+ mov x0, #DCFG_DEVDISR1_OFFSET
+ bl read_reg_dcfg
+ mov w13, w0
+ mov x0, #DCFG_DEVDISR1_OFFSET
+ ldr x1, =DEVDISR1_VALUE
+ bl write_reg_dcfg
+
+ /* save DEVDISR2 and load new value */
+ mov x0, #DCFG_DEVDISR2_OFFSET
+ bl read_reg_dcfg
+ mov w14, w0
+ mov x0, #DCFG_DEVDISR2_OFFSET
+ ldr x1, =DEVDISR2_VALUE
+ bic x1, x1, x5
+ bl write_reg_dcfg
+
+ /* x6 = DEVDISR5 override mask */
+ /* x7 = [soc_data_area] */
+
+ /* save DEVDISR3 and load new value */
+ mov x0, #DCFG_DEVDISR3_OFFSET
+ bl read_reg_dcfg
+ mov w15, w0
+ mov x0, #DCFG_DEVDISR3_OFFSET
+ ldr x1, =DEVDISR3_VALUE
+ bl write_reg_dcfg
+
+ /* save DEVDISR4 and load new value */
+ mov x0, #DCFG_DEVDISR4_OFFSET
+ bl read_reg_dcfg
+ mov w16, w0
+ mov x0, #DCFG_DEVDISR4_OFFSET
+ ldr x1, =DEVDISR4_VALUE
+ bl write_reg_dcfg
+
+ /* save DEVDISR5 and load new value */
+ mov x0, #DCFG_DEVDISR5_OFFSET
+ bl read_reg_dcfg
+ mov w17, w0
+ mov x0, #DCFG_DEVDISR5_OFFSET
+ ldr x1, =DEVDISR5_VALUE
+ bic x1, x1, x6
+ bl write_reg_dcfg
+
+ /* x7 = [soc_data_area] */
+
+ /* save cpuactlr and disable data prefetch */
+ mrs x0, CPUACTLR_EL1
+ str w0, [x7, #CPUACTLR_DATA_OFFSET]
+ bic x0, x0, #CPUACTLR_L1PCTL_MASK
+ msr CPUACTLR_EL1, x0
+
+ /* x6 = DEVDISR5 override mask */
+
+ /* setup registers for cache-only execution */
+ ldr x5, =IPSTPCR4_VALUE
+ bic x5, x5, x6
+ mov x6, #DDR_CNTRL_BASE_ADDR
+ mov x7, #DCSR_RCPM2_BASE
+ mov x8, #NXP_DCFG_ADDR
+ dsb sy
+ isb
+
+ /* set the DLL_LOCK cycle count */
+ ldr w1, [x6, #DDR_TIMING_CFG_4_OFFSET]
+ rev w2, w1
+ bic w2, w2, #DLL_LOCK_MASK
+ orr w2, w2, #DLL_LOCK_VALUE
+ rev w1, w2
+ str w1, [x6, #DDR_TIMING_CFG_4_OFFSET]
+
+ /*
+ * x5 = ipstpcr4 (IPSTPCR4_VALUE bic DEVDISR5_MASK)
+ * x6 = DDR_CNTRL_BASE_ADDR
+ * x7 = DCSR_RCPM2_BASE
+ * x8 = NXP_DCFG_ADDR
+ * w13 = DEVDISR1 saved value
+ * w14 = DEVDISR2 saved value
+ * w15 = DEVDISR3 saved value
+ * w16 = DEVDISR4 saved value
+ * w17 = DEVDISR5 saved value
+ */
+
+ /* enter the cache-only sequence */
+ mov x9, #CORE_RESTARTABLE
+ bl final_pwrdown
+
+ /* when we are here, the core has come out of wfi and the SoC is back up */
+
+ mov x30, x18
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs any SoC-specific cleanup after power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+_soc_sys_exit_pwrdn:
+ /* clear POWMGTDCR */
+ mov x1, #DCSR_RCPM2_BASE
+ str wzr, [x1, #RCPM2_POWMGTDCR_OFFSET]
+
+ /* clear WFIL2_EN in SCFG_COREPMCR */
+ mov x1, #NXP_SCFG_ADDR
+ str wzr, [x1, #SCFG_COREPMCR_OFFSET]
+
+ ret
+
+/*
+ * write a register in the SCFG block
+ * in: x0 = offset
+ * in: w1 = value to write
+ * uses x0, x1, x2, x3
+ */
+write_reg_scfg:
+ ldr x2, =NXP_SCFG_ADDR
+ /* swap for BE */
+ rev w3, w1
+ str w3, [x2, x0]
+ ret
+/*
+ * read a register in the SCFG block
+ * in: x0 = offset
+ * out: w0 = value read
+ * uses x0, x1, x2
+ */
+read_reg_scfg:
+ ldr x2, =NXP_SCFG_ADDR
+ ldr w1, [x2, x0]
+ /* swap for BE */
+ rev w0, w1
+ ret
+
+/*
+ * write a register in the DCFG block
+ * in: x0 = offset
+ * in: w1 = value to write
+ * uses x0, x1, x2, x3
+ */
+write_reg_dcfg:
+ ldr x2, =NXP_DCFG_ADDR
+ /* swap for BE */
+ rev w3, w1
+ str w3, [x2, x0]
+ ret
+
+/*
+ * read a register in the DCFG block
+ * in: x0 = offset
+ * out: w0 = value read
+ * uses x0, x1, x2
+ */
+read_reg_dcfg:
+ ldr x2, =NXP_DCFG_ADDR
+ ldr w1, [x2, x0]
+ /* swap for BE */
+ rev w0, w1
+ ret
+
+/*
+ * write a register in the RCPM block
+ * in: x0 = offset
+ * in: w1 = value to write
+ * uses x0, x1, x2, x3
+ */
+write_reg_rcpm:
+ ldr x2, =NXP_RCPM_ADDR
+ /* swap for BE */
+ rev w3, w1
+ str w3, [x2, x0]
+ ret
+
+/*
+ * read a register in the RCPM block
+ * in: x0 = offset
+ * out: w0 = value read
+ * uses x0, x1, x2
+ */
+read_reg_rcpm:
+ ldr x2, =NXP_RCPM_ADDR
+ ldr w1, [x2, x0]
+ /* swap for BE */
+ rev w0, w1
+ ret
+
+/*
+ * write a register in the DCSR-RCPM2 block
+ * in: x0 = offset
+ * in: w1 = value to write
+ * uses x0, x1, x2, x3
+ */
+write_reg_rcpm2:
+ ldr x2, =DCSR_RCPM2_BASE
+ /* swap for BE */
+ rev w3, w1
+ str w3, [x2, x0]
+ ret
+
+/*
+ * read a register in the DCSR-RCPM2 block
+ * in: x0 = offset
+ * out: w0 = value read
+ * uses x0, x1, x2
+ */
+read_reg_rcpm2:
+ ldr x2, =DCSR_RCPM2_BASE
+ ldr w1, [x2, x0]
+ /* swap for BE */
+ rev w0, w1
+ ret
+
+/*
+ * this function returns the base address of the gic distributor
+ * in: none
+ * out: x0 = base address of gic distributor
+ * uses x0, x1
+ */
+_getGICD_BaseAddr:
+ /* read SVR and get the SoC version */
+ mov x0, #NXP_DCFG_ADDR
+ ldr w1, [x0, #DCFG_SVR_OFFSET]
+ rev w0, w1
+
+ /* x0 = svr */
+ and w0, w0, #SVR_MIN_VER_MASK
+ cmp w0, #SVR_MINOR_VER_0
+ b.ne 8f
+
+ /* load the gic base addresses for rev 1.0 parts */
+ ldr x0, =NXP_GICD_4K_ADDR
+ b 10f
+8:
+ /* for rev 1.1 and later parts, the GIC base addresses */
+ /* can be at 4k or 64k offsets */
+
+ /* read the scfg reg GIC400_ADDR_ALIGN */
+ mov x0, #NXP_SCFG_ADDR
+ ldr w1, [x0, #SCFG_GIC400_ADDR_ALIGN_OFFSET]
+ rev w0, w1
+
+ /* x0 = GIC400_ADDR_ALIGN value */
+ and x0, x0, #SCFG_GIC400_ADDR_ALIGN_4KMODE_MASK
+ mov x1, #SCFG_GIC400_ADDR_ALIGN_4KMODE_EN
+ cmp x0, x1
+ b.ne 9f
+
+ /* load the base addresses for 4k offsets */
+ ldr x0, =NXP_GICD_4K_ADDR
+ b 10f
+9:
+ /* load the base address for 64k offsets */
+ ldr x0, =NXP_GICD_64K_ADDR
+10:
+ ret
+
+/*
+ * this function returns the base address of the gic distributor
+ * in: none
+ * out: x0 = base address of gic controller
+ * uses x0, x1
+ */
+_getGICC_BaseAddr:
+ /* read SVR and get the SoC version */
+ mov x0, #NXP_DCFG_ADDR
+ ldr w1, [x0, #DCFG_SVR_OFFSET]
+ rev w0, w1
+
+ /* x0 = svr */
+ and w0, w0, #SVR_MIN_VER_MASK
+ cmp w0, #SVR_MINOR_VER_0
+ b.ne 8f
+
+ /* load the gic base addresses for rev 1.0 parts */
+ ldr x0, =NXP_GICC_4K_ADDR
+ b 10f
+8:
+ /* for rev 1.1 and later parts, the GIC base addresses */
+ /* can be at 4k or 64k offsets */
+
+ /* read the scfg reg GIC400_ADDR_ALIGN */
+ mov x0, #NXP_SCFG_ADDR
+ ldr w1, [x0, #SCFG_GIC400_ADDR_ALIGN_OFFSET]
+ rev w0, w1
+
+ /* x0 = GIC400_ADDR_ALIGN value */
+ and x0, x0, #SCFG_GIC400_ADDR_ALIGN_4KMODE_MASK
+ mov x1, #SCFG_GIC400_ADDR_ALIGN_4KMODE_EN
+ cmp x0, x1
+ b.ne 9f
+
+ /* load the base addresses for 4k offsets */
+ ldr x0, =NXP_GICC_4K_ADDR
+ b 10f
+9:
+ /* load the base address for 64k offsets */
+ ldr x0, =NXP_GICC_64K_ADDR
+10:
+ ret
+
+/*
+ * this function will pwrdown ddr and the final core - it will do this
+ * by loading itself into the icache and then executing from there
+ * in: x5 = ipstpcr4 (IPSTPCR4_VALUE bic DEVDISR5_MASK)
+ * x6 = DDR_CNTRL_BASE_ADDR
+ * x7 = DCSR_RCPM2_BASE
+ * x8 = NXP_DCFG_ADDR
+ * x9 = 0, restartable
+ * = 1, non-restartable
+ * w13 = DEVDISR1 saved value
+ * w14 = DEVDISR2 saved value
+ * w15 = DEVDISR3 saved value
+ * w16 = DEVDISR4 saved value
+ * w17 = DEVDISR5 saved value
+ * out: none
+ * uses x0 ~ x9
+ */
+
+/* 4Kb aligned */
+.align 12
+final_pwrdown:
+ mov x0, xzr
+ b touch_line_0
+start_line_0:
+ mov x0, #1
+ mov x2, #DDR_SDRAM_CFG_2_FRCSR /* put ddr in self refresh - start */
+ ldr w3, [x6, #DDR_SDRAM_CFG_2_OFFSET]
+ rev w4, w3
+ orr w4, w4, w2
+ rev w3, w4
+ str w3, [x6, #DDR_SDRAM_CFG_2_OFFSET] /* put ddr in self refresh - end */
+ orr w3, w5, #DEVDISR5_MEM /* quiesce ddr clocks - start */
+ rev w4, w3
+ str w4, [x7, #RCPM2_IPSTPCR4_OFFSET] /* quiesce ddr clocks - end */
+
+ mov w3, #DEVDISR5_MEM
+ rev w3, w3 /* polling mask */
+ mov x2, #DDR_SLEEP_RETRY_CNT /* poll on ipstpack4 - start */
+touch_line_0:
+ cbz x0, touch_line_1
+
+start_line_1:
+ ldr w1, [x7, #RCPM2_IPSTPACKR4_OFFSET]
+ tst w1, w3
+ b.ne 1f
+ subs x2, x2, #1
+ b.gt start_line_1 /* poll on ipstpack4 - end */
+
+ /* if we get here, we have a timeout err */
+ rev w4, w5
+ str w4, [x7, #RCPM2_IPSTPCR4_OFFSET] /* re-enable ddr clks interface */
+ mov x0, #ERROR_DDR_SLEEP /* load error code */
+ b 2f
+1:
+ str w4, [x8, #DCFG_DEVDISR5_OFFSET] /* disable ddr cntrlr clk in devdisr5 */
+5:
+ wfi /* stop the final core */
+
+ cbnz x9, 5b /* if non-restartable, keep in wfi */
+ rev w4, w5
+ str w4, [x8, #DCFG_DEVDISR5_OFFSET] /* re-enable ddr in devdisr5 */
+ str w4, [x7, #RCPM2_IPSTPCR4_OFFSET] /* re-enable ddr clk in ipstpcr4 */
+touch_line_1:
+ cbz x0, touch_line_2
+
+start_line_2:
+ ldr w1, [x7, #RCPM2_IPSTPACKR4_OFFSET] /* poll on ipstpack4 - start */
+ tst w1, w3
+ b.eq 2f
+ nop
+ b start_line_2 /* poll on ipstpack4 - end */
+2:
+ mov x2, #DDR_SDRAM_CFG_2_FRCSR /* take ddr out-of self refresh - start */
+ ldr w3, [x6, #DDR_SDRAM_CFG_2_OFFSET]
+ rev w4, w3
+ bic w4, w4, w2
+ rev w3, w4
+ mov x1, #DDR_SLEEP_RETRY_CNT /* wait for ddr cntrlr clock - start */
+3:
+ subs x1, x1, #1
+ b.gt 3b /* wait for ddr cntrlr clock - end */
+ str w3, [x6, #DDR_SDRAM_CFG_2_OFFSET] /* take ddr out-of self refresh - end */
+ rev w1, w17
+touch_line_2:
+ cbz x0, touch_line_3
+
+start_line_3:
+ str w1, [x8, #DCFG_DEVDISR5_OFFSET] /* reset devdisr5 */
+ rev w1, w16
+ str w1, [x8, #DCFG_DEVDISR4_OFFSET] /* reset devdisr4 */
+ rev w1, w15
+ str w1, [x8, #DCFG_DEVDISR3_OFFSET] /* reset devdisr3 */
+ rev w1, w14
+ str w1, [x8, #DCFG_DEVDISR2_OFFSET] /* reset devdisr2 */
+ rev w1, w13
+ str w1, [x8, #DCFG_DEVDISR1_OFFSET] /* reset devdisr1 */
+ str wzr, [x7, #RCPM2_IPSTPCR4_OFFSET] /* reset ipstpcr4 */
+ str wzr, [x7, #RCPM2_IPSTPCR3_OFFSET] /* reset ipstpcr3 */
+ str wzr, [x7, #RCPM2_IPSTPCR2_OFFSET] /* reset ipstpcr2 */
+ str wzr, [x7, #RCPM2_IPSTPCR1_OFFSET] /* reset ipstpcr1 */
+ str wzr, [x7, #RCPM2_IPSTPCR0_OFFSET] /* reset ipstpcr0 */
+ b continue_restart
+touch_line_3:
+ cbz x0, start_line_0
+
+/* execute here after ddr is back up */
+continue_restart:
+ /*
+ * if x0 = 1, all is well
+ * if x0 < 1, we had an error
+ */
+ cmp x0, #1
+ b.ne 4f
+ mov x0, #0
+4:
+ ret
+
+/*
+ * Note: there is no return from this function
+ * this function will shutdown ddr and the final core - it will do this
+ * by loading itself into the icache and then executing from there
+ * in: x5 = ipstpcr4 (IPSTPCR4_VALUE bic DEVDISR5_MASK)
+ * x6 = DDR_CNTRL_BASE_ADDR
+ * x7 = DCSR_RCPM2_BASE
+ * x8 = NXP_DCFG_ADDR
+ * out: none
+ * uses x0 ~ x8
+ */
+
+/* 4Kb aligned */
+.align 12
+final_shutdown:
+
+ mov x0, xzr
+ b touch_line0
+start_line0:
+ mov x0, #1
+ mov x2, #DDR_SDRAM_CFG_2_FRCSR /* put ddr in self refresh - start */
+ ldr w3, [x6, #DDR_SDRAM_CFG_2_OFFSET]
+ rev w4, w3
+ orr w4, w4, w2
+ rev w3, w4
+ str w3, [x6, #DDR_SDRAM_CFG_2_OFFSET] /* put ddr in self refresh - end */
+ orr w3, w5, #DEVDISR5_MEM /* quiesce ddr clocks - start */
+ rev w4, w3
+ str w4, [x7, #RCPM2_IPSTPCR4_OFFSET] /* quiesce ddr clocks - end */
+
+ mov w3, #DEVDISR5_MEM
+ rev w3, w3 /* polling mask */
+ mov x2, #DDR_SLEEP_RETRY_CNT /* poll on ipstpack4 - start */
+touch_line0:
+ cbz x0, touch_line1
+
+start_line1:
+ ldr w1, [x7, #RCPM2_IPSTPACKR4_OFFSET]
+ tst w1, w3
+ b.ne 1f
+ subs x2, x2, #1
+ b.gt start_line1 /* poll on ipstpack4 - end */
+ nop
+ nop
+ nop
+ nop
+1:
+ str w4, [x8, #DCFG_DEVDISR5_OFFSET] /* disable ddr cntrlr clk in devdisr5 */
+5:
+ wfi /* stop the final core */
+ b 5b /* stay here until POR */
+ nop
+ nop
+ nop
+touch_line1:
+ cbz x0, start_line0
diff --git a/plat/nxp/soc-ls1043a/aarch64/ls1043a_helpers.S b/plat/nxp/soc-ls1043a/aarch64/ls1043a_helpers.S
new file mode 100644
index 0000000..bc88886
--- /dev/null
+++ b/plat/nxp/soc-ls1043a/aarch64/ls1043a_helpers.S
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+#include <platform_def.h>
+
+ .globl plat_secondary_cold_boot_setup
+ .globl plat_is_my_cpu_primary
+ .globl plat_reset_handler
+ .globl platform_mem_init
+
+func platform_mem1_init
+ ret
+endfunc platform_mem1_init
+
+func platform_mem_init
+ ret
+endfunc platform_mem_init
+
+func apply_platform_errata
+ ret
+endfunc apply_platform_errata
+
+func plat_reset_handler
+ mov x29, x30
+ bl apply_platform_errata
+
+#if defined(IMAGE_BL31)
+ ldr x0, =POLICY_SMMU_PAGESZ_64K
+ cbz x0, 1f
+ /* Set the SMMU page size in the sACR register */
+ bl _set_smmu_pagesz_64
+#endif
+1:
+ mov x30, x29
+ ret
+endfunc 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 e.g
+ * mark the cpu's presence, mechanism to place it in a
+ * holding pen etc.
+ */
+func plat_secondary_cold_boot_setup
+ /* ls1043a does not do cold boot for secondary CPU */
+cb_panic:
+ b cb_panic
+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
+ mrs x0, mpidr_el1
+ and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+ cmp x0, 0x0
+ cset w0, eq
+ ret
+endfunc plat_is_my_cpu_primary
diff --git a/plat/nxp/soc-ls1043a/include/ns_access.h b/plat/nxp/soc-ls1043a/include/ns_access.h
new file mode 100644
index 0000000..423c454
--- /dev/null
+++ b/plat/nxp/soc-ls1043a/include/ns_access.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2015, 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018, 2020-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NS_ACCESS_H
+#define NS_ACCESS_H
+
+#include <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,
+};
+
+struct csu_ns_dev_st 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_S_SUP_RW},
+ {CSU_CSLX_GIC, CSU_ALL_RW},
+ {CSU_CSLX_PCIE1, CSU_ALL_RW},
+ {CSU_CSLX_OCRAM2, CSU_S_SUP_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 */
diff --git a/plat/nxp/soc-ls1043a/include/soc.h b/plat/nxp/soc-ls1043a/include/soc.h
new file mode 100644
index 0000000..e018102
--- /dev/null
+++ b/plat/nxp/soc-ls1043a/include/soc.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2017-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOC_H
+#define SOC_H
+
+/* Chassis specific defines - common across SoC's of a particular platform */
+#include "dcfg_lsch2.h"
+#include "soc_default_base_addr.h"
+#include "soc_default_helper_macros.h"
+
+/* DDR Regions Info */
+#define NUM_DRAM_REGIONS 3
+#define NXP_DRAM0_ADDR 0x80000000
+#define NXP_DRAM0_MAX_SIZE 0x80000000 /* 2 GB */
+
+#define NXP_DRAM1_ADDR 0x880000000
+#define NXP_DRAM1_MAX_SIZE 0x780000000 /* 30 GB */
+
+#define NXP_DRAM2_ADDR 0x8800000000
+#define NXP_DRAM2_MAX_SIZE 0x7800000000 /* 480 GB */
+/* DRAM0 Size defined in platform_def.h */
+#define NXP_DRAM0_SIZE PLAT_DEF_DRAM0_SIZE
+
+/*
+ * P23: 23 x 23 package
+ * A: without security
+ * AE: with security
+ * SVR Definition (not include major and minor rev)
+ */
+#define SVR_LS1023A 0x879209
+#define SVR_LS1023AE 0x879208
+#define SVR_LS1023A_P23 0x87920B
+#define SVR_LS1023AE_P23 0x87920A
+#define SVR_LS1043A 0x879201
+#define SVR_LS1043AE 0x879200
+#define SVR_LS1043A_P23 0x879203
+#define SVR_LS1043AE_P23 0x879202
+
+/* Number of cores in platform */
+#define PLATFORM_CORE_COUNT 4
+#define NUMBER_OF_CLUSTERS 1
+#define CORES_PER_CLUSTER 4
+
+/* set to 0 if the clusters are not symmetrical */
+#define SYMMETRICAL_CLUSTERS 1
+
+/*
+ * Required LS standard platform porting definitions
+ * for CCI-400
+ */
+#define NXP_CCI_CLUSTER0_SL_IFACE_IX 4
+
+/* ls1043 version info for GIC configuration */
+#define REV1_0 0x10
+#define REV1_1 0x11
+#define GIC_ADDR_BIT 31
+
+/* Errata */
+#define NXP_ERRATUM_A009663
+#define NXP_ERRATUM_A009942
+
+#define NUM_OF_DDRC 1
+
+/* Defines required for using XLAT tables from ARM common code */
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 40)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 40)
+
+/* Clock Divisors */
+#define NXP_PLATFORM_CLK_DIVIDER 1
+#define NXP_UART_CLK_DIVIDER 1
+
+/*
+ * Set this switch to 1 if you need to keep the debug block
+ * clocked during system power-down.
+ */
+#define DEBUG_ACTIVE 0
+
+#define IPPDEXPCR_MAC1_1 0x80000000 // DEVDISR2_FMAN1_MAC1
+#define IPPDEXPCR_MAC1_2 0x40000000 // DEVDISR2_FMAN1_MAC2
+#define IPPDEXPCR_MAC1_3 0x20000000 // DEVDISR2_FMAN1_MAC3
+#define IPPDEXPCR_MAC1_4 0x10000000 // DEVDISR2_FMAN1_MAC4
+#define IPPDEXPCR_MAC1_5 0x08000000 // DEVDISR2_FMAN1_MAC5
+#define IPPDEXPCR_MAC1_6 0x04000000 // DEVDISR2_FMAN1_MAC6
+#define IPPDEXPCR_MAC1_9 0x00800000 // DEVDISR2_FMAN1_MAC9
+#define IPPDEXPCR_I2C1 0x00080000 // DEVDISR5_I2C_1
+#define IPPDEXPCR_LPUART1 0x00040000 // DEVDISR5_LPUART1
+#define IPPDEXPCR_FLX_TMR1 0x00020000 // DEVDISR5_FLX_TMR
+#define IPPDEXPCR_OCRAM1 0x00010000 // DEVDISR5_OCRAM1
+#define IPPDEXPCR_GPIO1 0x00000040 // DEVDISR5_GPIO
+#define IPPDEXPCR_FM1 0x00000008 // DEVDISR2_FMAN1
+
+#define IPPDEXPCR_MASK1 0xFC800008 // overrides for DEVDISR2
+#define IPPDEXPCR_MASK2 0x000F0040 // overriddes for DEVDISR5
+
+#define IPSTPCR0_VALUE 0xA000C201
+#define IPSTPCR1_VALUE 0x00000080
+#define IPSTPCR2_VALUE 0x000C0000
+#define IPSTPCR3_VALUE 0x38000000
+#if (DEBUG_ACTIVE)
+ #define IPSTPCR4_VALUE 0x10833BFC
+#else
+ #define IPSTPCR4_VALUE 0x10A33BFC
+#endif
+
+#define DEVDISR1_QE 0x00000001
+#define DEVDISR1_SEC 0x00000200
+#define DEVDISR1_USB1 0x00004000
+#define DEVDISR1_SATA 0x00008000
+#define DEVDISR1_USB2 0x00010000
+#define DEVDISR1_USB3 0x00020000
+#define DEVDISR1_DMA2 0x00400000
+#define DEVDISR1_DMA1 0x00800000
+#define DEVDISR1_ESDHC 0x20000000
+#define DEVDISR1_PBL 0x80000000
+
+#define DEVDISR2_FMAN1 0x00000080
+#define DEVDISR2_FMAN1_MAC9 0x00800000
+#define DEVDISR2_FMAN1_MAC6 0x04000000
+#define DEVDISR2_FMAN1_MAC5 0x08000000
+#define DEVDISR2_FMAN1_MAC4 0x10000000
+#define DEVDISR2_FMAN1_MAC3 0x20000000
+#define DEVDISR2_FMAN1_MAC2 0x40000000
+#define DEVDISR2_FMAN1_MAC1 0x80000000
+
+#define DEVDISR3_BMAN 0x00040000
+#define DEVDISR3_QMAN 0x00080000
+#define DEVDISR3_PEX3 0x20000000
+#define DEVDISR3_PEX2 0x40000000
+#define DEVDISR3_PEX1 0x80000000
+
+#define DEVDISR4_QSPI 0x08000000
+#define DEVDISR4_DUART2 0x10000000
+#define DEVDISR4_DUART1 0x20000000
+
+#define DEVDISR5_ICMMU 0x00000001
+#define DEVDISR5_I2C_1 0x00000002
+#define DEVDISR5_I2C_2 0x00000004
+#define DEVDISR5_I2C_3 0x00000008
+#define DEVDISR5_I2C_4 0x00000010
+#define DEVDISR5_WDG_5 0x00000020
+#define DEVDISR5_WDG_4 0x00000040
+#define DEVDISR5_WDG_3 0x00000080
+#define DEVDISR5_DSPI1 0x00000100
+#define DEVDISR5_WDG_2 0x00000200
+#define DEVDISR5_FLX_TMR 0x00000400
+#define DEVDISR5_WDG_1 0x00000800
+#define DEVDISR5_LPUART6 0x00001000
+#define DEVDISR5_LPUART5 0x00002000
+#define DEVDISR5_LPUART3 0x00008000
+#define DEVDISR5_LPUART2 0x00010000
+#define DEVDISR5_LPUART1 0x00020000
+#define DEVDISR5_DBG 0x00200000
+#define DEVDISR5_GPIO 0x00400000
+#define DEVDISR5_IFC 0x00800000
+#define DEVDISR5_OCRAM2 0x01000000
+#define DEVDISR5_OCRAM1 0x02000000
+#define DEVDISR5_LPUART4 0x10000000
+#define DEVDISR5_DDR 0x80000000
+#define DEVDISR5_MEM 0x80000000
+
+#define DEVDISR1_VALUE 0xA0C3C201
+#define DEVDISR2_VALUE 0xCC0C0080
+#define DEVDISR3_VALUE 0xE00C0000
+#define DEVDISR4_VALUE 0x38000000
+#if (DEBUG_ACTIVE)
+ #define DEVDISR5_VALUE 0x10833BFC
+#else
+ #define DEVDISR5_VALUE 0x10A33BFC
+#endif
+
+/*
+ * PWR mgmt features supported in the soc-specific code:
+ * value == 0x0 the soc code does not support this feature
+ * value != 0x0 the soc code supports this feature
+ */
+#define SOC_CORE_RELEASE 0x1
+#define SOC_CORE_RESTART 0x1
+#define SOC_CORE_OFF 0x1
+#define SOC_CORE_STANDBY 0x1
+#define SOC_CORE_PWR_DWN 0x1
+#define SOC_CLUSTER_STANDBY 0x1
+#define SOC_CLUSTER_PWR_DWN 0x1
+#define SOC_SYSTEM_STANDBY 0x1
+#define SOC_SYSTEM_PWR_DWN 0x1
+#define SOC_SYSTEM_OFF 0x1
+#define SOC_SYSTEM_RESET 0x1
+
+/* PSCI-specific defines */
+#define SYSTEM_PWR_DOMAINS 1
+#define PLAT_NUM_PWR_DOMAINS (PLATFORM_CORE_COUNT + \
+ NUMBER_OF_CLUSTERS + \
+ SYSTEM_PWR_DOMAINS)
+
+/* Power state coordination occurs at the system level */
+#define PLAT_PD_COORD_LVL MPIDR_AFFLVL2
+#define PLAT_MAX_PWR_LVL PLAT_PD_COORD_LVL
+
+/* Local power state for power domains in Run state */
+#define LS_LOCAL_STATE_RUN PSCI_LOCAL_STATE_RUN
+
+/* define retention state */
+#define PLAT_MAX_RET_STATE (PSCI_LOCAL_STATE_RUN + 1)
+#define LS_LOCAL_STATE_RET PLAT_MAX_RET_STATE
+
+/* define power-down state */
+#define PLAT_MAX_OFF_STATE (PLAT_MAX_RET_STATE + 1)
+#define LS_LOCAL_STATE_OFF PLAT_MAX_OFF_STATE
+
+/*
+ * 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.
+ * CACHE_WRITEBACK_GRANULE is defined in soc.def
+ */
+
+/* One cache line needed for bakery locks on ARM platforms */
+#define PLAT_PERCPU_BAKERY_LOCK_SIZE (1 * CACHE_WRITEBACK_GRANULE)
+
+#ifndef __ASSEMBLER__
+/* CCI slave interfaces */
+static const int cci_map[] = {
+ NXP_CCI_CLUSTER0_SL_IFACE_IX,
+};
+void soc_init_lowlevel(void);
+void soc_init_percpu(void);
+void _soc_set_start_addr(unsigned long addr);
+
+#endif
+
+#endif /* SOC_H */
diff --git a/plat/nxp/soc-ls1043a/ls1043ardb/ddr_init.c b/plat/nxp/soc-ls1043a/ls1043ardb/ddr_init.c
new file mode 100644
index 0000000..28e2dab
--- /dev/null
+++ b/plat/nxp/soc-ls1043a/ls1043ardb/ddr_init.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <common/debug.h>
+#include <ddr.h>
+#include <lib/utils.h>
+
+#include <errata.h>
+#include <platform_def.h>
+
+#ifdef CONFIG_STATIC_DDR
+const struct ddr_cfg_regs static_1600 = {
+ .cs[0].config = U(0x80040322),
+ .cs[0].bnds = U(0x7F),
+ .sdram_cfg[0] = U(0xC50C0000),
+ .sdram_cfg[1] = U(0x401100),
+ .timing_cfg[0] = U(0x91550018),
+ .timing_cfg[1] = U(0xBBB48C42),
+ .timing_cfg[2] = U(0x48C111),
+ .timing_cfg[3] = U(0x10C1000),
+ .timing_cfg[4] = U(0x2),
+ .timing_cfg[5] = U(0x3401400),
+ .timing_cfg[7] = U(0x13300000),
+ .timing_cfg[8] = U(0x2115600),
+ .sdram_mode[0] = U(0x3010210),
+ .sdram_mode[9] = U(0x4000000),
+ .sdram_mode[8] = U(0x500),
+ .sdram_mode[2] = U(0x10210),
+ .sdram_mode[10] = U(0x400),
+ .sdram_mode[11] = U(0x4000000),
+ .sdram_mode[4] = U(0x10210),
+ .sdram_mode[12] = U(0x400),
+ .sdram_mode[13] = U(0x4000000),
+ .sdram_mode[6] = U(0x10210),
+ .sdram_mode[14] = U(0x400),
+ .sdram_mode[15] = U(0x4000000),
+ .interval = U(0x18600618),
+ .zq_cntl = U(0x8A090705),
+ .clk_cntl = U(0x3000000),
+ .cdr[0] = U(0x80040000),
+ .cdr[1] = U(0xA181),
+ .wrlvl_cntl[0] = U(0x8675F607),
+ .wrlvl_cntl[1] = U(0x7090807,
+ .wrlvl_cntl[2] = U(0x7070707),
+ .debug[28] = U(0x00700046),
+};
+
+uint64_t board_static_ddr(struct ddr_info *priv)
+{
+ memcpy(&priv->ddr_reg, &static_1600, sizeof(static_1600));
+
+ return ULL(0x80000000);
+}
+
+#else
+static const struct rc_timing rcz[] = {
+ {1600, 12, 7},
+ {}
+};
+
+static const struct board_timing ram[] = {
+ {0x1f, rcz, 0x00020100, 0},
+};
+
+int ddr_board_options(struct ddr_info *priv)
+{
+ int ret;
+ struct memctl_opt *popts = &priv->opt;
+
+ ret = cal_board_params(priv, ram, ARRAY_SIZE(ram));
+ if (ret)
+ return ret;
+
+ popts->cpo_sample = U(0x46);
+ popts->ddr_cdr1 = DDR_CDR1_DHC_EN |
+ DDR_CDR1_ODT(DDR_CDR_ODT_80ohm);
+ popts->ddr_cdr2 = DDR_CDR2_ODT(DDR_CDR_ODT_80ohm) |
+ DDR_CDR2_VREF_OVRD(70); /* Vref = 70% */
+
+ return 0;
+}
+
+/* DDR model number: MT40A1G8SA-062E:R */
+struct dimm_params ddr_raw_timing = {
+ .n_ranks = U(1),
+ .rank_density = ULL(2147483648),
+ .capacity = ULL(2147483648),
+ .primary_sdram_width = U(32),
+ .ec_sdram_width = U(4),
+ .rdimm = U(0),
+ .mirrored_dimm = U(0),
+ .n_row_addr = U(16),
+ .n_col_addr = U(10),
+ .bank_group_bits = U(2),
+ .edc_config = U(2),
+ .burst_lengths_bitmask = U(0x0c),
+ .tckmin_x_ps = 625,
+ .tckmax_ps = 2200,
+ .caslat_x = U(0x0001FFE00),
+ .taa_ps = 13500,
+ .trcd_ps = 13500,
+ .trp_ps = 13500,
+ .tras_ps = 32000,
+ .trc_ps = 45500,
+ .twr_ps = 15000,
+ .trfc1_ps = 350000,
+ .trfc2_ps = 260000,
+ .trfc4_ps = 160000,
+ .tfaw_ps = 21000,
+ .trrds_ps = 3000,
+ .trrdl_ps = 4900,
+ .tccdl_ps = 5000,
+ .refresh_rate_ps = U(7800000),
+ .rc = U(0x1f),
+};
+
+int ddr_get_ddr_params(struct dimm_params *pdimm,
+ struct ddr_conf *conf)
+{
+ static const char dimm_model[] = "Fixed DDR on board";
+
+ conf->dimm_in_use[0] = 1;
+ memcpy(pdimm, &ddr_raw_timing, sizeof(struct dimm_params));
+ memcpy(pdimm->mpart, dimm_model, sizeof(dimm_model) - 1);
+
+ return 1;
+}
+#endif
+
+int64_t init_ddr(void)
+{
+ struct ddr_info info;
+ struct sysinfo sys;
+ int64_t dram_size;
+
+ zeromem(&sys, sizeof(sys));
+ get_clocks(&sys);
+ debug("platform clock %lu\n", sys.freq_platform);
+ debug("DDR PLL1 %lu\n", sys.freq_ddr_pll0);
+ debug("DDR PLL2 %lu\n", sys.freq_ddr_pll1);
+
+ zeromem(&info, sizeof(struct ddr_info));
+ info.num_ctlrs = 1;
+ info.dimm_on_ctlr = 1;
+ info.clk = get_ddr_freq(&sys, 0);
+ info.ddr[0] = (void *)NXP_DDR_ADDR;
+
+ dram_size = dram_init(&info);
+
+ if (dram_size < 0) {
+ ERROR("DDR init failed\n");
+ }
+
+#ifdef ERRATA_SOC_A008850
+ erratum_a008850_post();
+#endif
+ return dram_size;
+}
diff --git a/plat/nxp/soc-ls1043a/ls1043ardb/plat_def.h b/plat/nxp/soc-ls1043a/ls1043ardb/plat_def.h
new file mode 100644
index 0000000..249f457
--- /dev/null
+++ b/plat/nxp/soc-ls1043a/ls1043ardb/plat_def.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_DEF_H
+#define PLAT_DEF_H
+
+#include <arch.h>
+/*
+ * Required without TBBR.
+ * To include the defines for DDR PHY Images.
+ */
+#include <tbbr_img_def.h>
+
+#include "policy.h"
+#include <soc.h>
+
+#define NXP_SPD_EEPROM0 0x51
+
+#define NXP_SYSCLK_FREQ 100000000
+#define NXP_DDRCLK_FREQ 100000000
+
+/* UART related definition */
+#define NXP_CONSOLE_ADDR NXP_UART_ADDR
+#define NXP_CONSOLE_BAUDRATE 115200
+
+/* Size of cacheable stacks */
+#if defined(IMAGE_BL2)
+#if defined(TRUSTED_BOARD_BOOT)
+#define PLATFORM_STACK_SIZE 0x2000
+#else
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+#elif defined(IMAGE_BL31)
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+
+/* SD block buffer */
+#define NXP_SD_BLOCK_BUF_SIZE (0x00100000)
+#define NXP_SD_BLOCK_BUF_ADDR ULL(0x80000000)
+
+#define BL2_LIMIT (NXP_OCRAM_ADDR + NXP_OCRAM_SIZE)
+
+/* IO defines as needed by IO driver framework */
+#define MAX_IO_DEVICES 3
+#define MAX_IO_BLOCK_DEVICES 1
+#define MAX_IO_HANDLES 4
+
+/*
+ * FIP image defines - Offset at which FIP Image would be present
+ * Image would include Bl31 , Bl33 and Bl32 (optional)
+ */
+#ifdef POLICY_FUSE_PROVISION
+#define MAX_FIP_DEVICES 2
+#endif
+
+#ifndef MAX_FIP_DEVICES
+#define MAX_FIP_DEVICES 1
+#endif
+
+/*
+ * ID of the secure physical generic timer interrupt used by the BL32.
+ */
+#define BL32_IRQ_SEC_PHY_TIMER 29
+
+/*
+ * 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_LS_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(BL32_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL)
+
+#define PLAT_LS_G0_IRQ_PROPS(grp)
+
+#endif /* PLAT_DEF_H */
diff --git a/plat/nxp/soc-ls1043a/ls1043ardb/platform.c b/plat/nxp/soc-ls1043a/ls1043ardb/platform.c
new file mode 100644
index 0000000..65d508c
--- /dev/null
+++ b/plat/nxp/soc-ls1043a/ls1043ardb/platform.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_common.h>
+
+#pragma weak board_enable_povdd
+#pragma weak board_disable_povdd
+
+bool board_enable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool board_disable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
diff --git a/plat/nxp/soc-ls1043a/ls1043ardb/platform.mk b/plat/nxp/soc-ls1043a/ls1043ardb/platform.mk
new file mode 100644
index 0000000..5d23356
--- /dev/null
+++ b/plat/nxp/soc-ls1043a/ls1043ardb/platform.mk
@@ -0,0 +1,40 @@
+#
+# Copyright 2018-2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# board-specific build parameters
+
+BOOT_MODE ?= nor
+BOARD := ls1043ardb
+POVDD_ENABLE := no
+
+# DDR Compilation Configs
+CONFIG_DDR_NODIMM := 1
+NUM_OF_DDRC := 1
+DDRC_NUM_DIMM := 0
+DDRC_NUM_CS := 4
+DDR_ECC_EN := no
+CONFIG_STATIC_DDR := 0
+
+# On-Board Flash Details
+# 128MB IFC NOR Flash
+NOR_FLASH_SZ := 0x8000000
+
+# Platform specific features.
+WARM_BOOT := no
+
+# Adding Platform files build files
+BL2_SOURCES += ${BOARD_PATH}/ddr_init.c\
+ ${BOARD_PATH}/platform.c
+
+SUPPORTED_BOOT_MODE := nor \
+ sd \
+ nand
+
+# Adding platform board build info
+include plat/nxp/common/plat_make_helper/plat_common_def.mk
+
+# Adding SoC build info
+include plat/nxp/soc-ls1043a/soc.mk
diff --git a/plat/nxp/soc-ls1043a/ls1043ardb/platform_def.h b/plat/nxp/soc-ls1043a/ls1043ardb/platform_def.h
new file mode 100644
index 0000000..4721a32
--- /dev/null
+++ b/plat/nxp/soc-ls1043a/ls1043ardb/platform_def.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <plat_def.h>
+#include <plat_default_def.h>
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/nxp/soc-ls1043a/ls1043ardb/policy.h b/plat/nxp/soc-ls1043a/ls1043ardb/policy.h
new file mode 100644
index 0000000..843b5e2
--- /dev/null
+++ b/plat/nxp/soc-ls1043a/ls1043ardb/policy.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef POLICY_H
+#define POLICY_H
+
+/*
+ * Set this to 0x0 to leave the default SMMU page size in sACR
+ * Set this to 0x1 to change the SMMU page size to 64K
+ */
+#define POLICY_SMMU_PAGESZ_64K 0x1
+
+#endif /* POLICY_H */
diff --git a/plat/nxp/soc-ls1043a/soc.c b/plat/nxp/soc-ls1043a/soc.c
new file mode 100644
index 0000000..7badf8c
--- /dev/null
+++ b/plat/nxp/soc-ls1043a/soc.c
@@ -0,0 +1,435 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <caam.h>
+#include <cassert.h>
+#include <cci.h>
+#include <common/debug.h>
+#include <dcfg.h>
+#ifdef I2C_INIT
+#include <i2c.h>
+#endif
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <ls_interconnect.h>
+#ifdef POLICY_FUSE_PROVISION
+#include <nxp_gpio.h>
+#endif
+#if TRUSTED_BOARD_BOOT
+#include <nxp_smmu.h>
+#endif
+#include <nxp_timer.h>
+#include <plat_console.h>
+#include <plat_gic.h>
+#include <plat_tzc380.h>
+#include <scfg.h>
+#if defined(NXP_SFP_ENABLED)
+#include <sfp.h>
+#endif
+
+#include <errata.h>
+#include <ns_access.h>
+#ifdef CONFIG_OCRAM_ECC_EN
+#include <ocram.h>
+#endif
+#include <plat_common.h>
+#include <platform_def.h>
+#include <soc.h>
+
+static dcfg_init_info_t dcfg_init_data = {
+ .g_nxp_dcfg_addr = NXP_DCFG_ADDR,
+ .nxp_sysclk_freq = NXP_SYSCLK_FREQ,
+ .nxp_ddrclk_freq = NXP_DDRCLK_FREQ,
+ .nxp_plat_clk_divider = NXP_PLATFORM_CLK_DIVIDER,
+ };
+
+
+/* Function to return the SoC SYS CLK */
+unsigned int get_sys_clk(void)
+{
+ return NXP_SYSCLK_FREQ;
+}
+
+/*
+ * Function returns the base counter frequency
+ * after reading the first entry at CNTFID0 (0x20 offset).
+ *
+ * Function is used by:
+ * 1. ARM common code for PSCI management.
+ * 2. ARM Generic Timer init.
+ *
+ */
+unsigned int plat_get_syscnt_freq2(void)
+{
+ unsigned int counter_base_frequency;
+
+ counter_base_frequency = get_sys_clk()/4;
+
+ return counter_base_frequency;
+}
+
+#ifdef IMAGE_BL2
+
+static struct soc_type soc_list[] = {
+ SOC_ENTRY(LS1023A, LS1023A, 1, 2),
+ SOC_ENTRY(LS1023AE, LS1023AE, 1, 2),
+ SOC_ENTRY(LS1023A_P23, LS1023A_P23, 1, 2),
+ SOC_ENTRY(LS1023AE_P23, LS1023AE_P23, 1, 2),
+ SOC_ENTRY(LS1043A, LS1043A, 1, 4),
+ SOC_ENTRY(LS1043AE, LS1043AE, 1, 4),
+ SOC_ENTRY(LS1043A_P23, LS1043A_P23, 1, 4),
+ SOC_ENTRY(LS1043AE_P23, LS1043AE_P23, 1, 4),
+};
+
+#ifdef POLICY_FUSE_PROVISION
+static gpio_init_info_t gpio_init_data = {
+ .gpio1_base_addr = NXP_GPIO1_ADDR,
+ .gpio2_base_addr = NXP_GPIO2_ADDR,
+ .gpio3_base_addr = NXP_GPIO3_ADDR,
+ .gpio4_base_addr = NXP_GPIO4_ADDR,
+};
+#endif
+
+/*
+ * Function to set the base counter frequency at
+ * the first entry of the Frequency Mode Table,
+ * at CNTFID0 (0x20 offset).
+ *
+ * Set the value of the pirmary core register cntfrq_el0.
+ */
+static void set_base_freq_CNTFID0(void)
+{
+ /*
+ * Below register specifies the base frequency of the system counter.
+ * As per NXP Board Manuals:
+ * The system counter always works with SYS_REF_CLK/4 frequency clock.
+ *
+ */
+ unsigned int counter_base_frequency = get_sys_clk()/4;
+
+ /*
+ * Setting the frequency in the Frequency modes table.
+ *
+ * Note: The value for ls1046ardb board at this offset
+ * is not RW as stated. This offset have the
+ * fixed value of 100000400 Hz.
+ *
+ * The below code line has no effect.
+ * Keeping it for other platforms where it has effect.
+ */
+ mmio_write_32(NXP_TIMER_ADDR + CNTFID_OFF, counter_base_frequency);
+
+ write_cntfrq_el0(counter_base_frequency);
+}
+
+void soc_preload_setup(void)
+{
+
+}
+
+/*******************************************************************************
+ * This function implements soc specific erratas
+ * This is called before DDR is initialized or MMU is enabled
+ ******************************************************************************/
+void soc_early_init(void)
+{
+ uint8_t num_clusters, cores_per_cluster;
+ dram_regions_info_t *dram_regions_info = get_dram_regions_info();
+
+#ifdef CONFIG_OCRAM_ECC_EN
+ ocram_init(NXP_OCRAM_ADDR, NXP_OCRAM_SIZE);
+#endif
+ dcfg_init(&dcfg_init_data);
+#ifdef POLICY_FUSE_PROVISION
+ gpio_init(&gpio_init_data);
+ sec_init(NXP_CAAM_ADDR);
+#endif
+#if LOG_LEVEL > 0
+ /* Initialize the console to provide early debug support */
+
+ plat_console_init(NXP_CONSOLE_ADDR,
+ NXP_UART_CLK_DIVIDER, NXP_CONSOLE_BAUDRATE);
+#endif
+ set_base_freq_CNTFID0();
+
+ /* Enable snooping on SEC read and write transactions */
+ scfg_setbits32((void *)(NXP_SCFG_ADDR + SCFG_SNPCNFGCR_OFFSET),
+ SCFG_SNPCNFGCR_SECRDSNP | SCFG_SNPCNFGCR_SECWRSNP);
+
+ /*
+ * Initialize Interconnect for this cluster during cold boot.
+ * No need for locks as no other CPU is active.
+ */
+ cci_init(NXP_CCI_ADDR, cci_map, ARRAY_SIZE(cci_map));
+
+ /*
+ * Enable Interconnect coherency for the primary CPU's cluster.
+ */
+ get_cluster_info(soc_list, ARRAY_SIZE(soc_list), &num_clusters, &cores_per_cluster);
+ plat_ls_interconnect_enter_coherency(num_clusters);
+
+#if TRUSTED_BOARD_BOOT
+ uint32_t mode;
+
+ sfp_init(NXP_SFP_ADDR);
+ /*
+ * For secure boot disable SMMU.
+ * Later when platform security policy comes in picture,
+ * this might get modified based on the policy
+ */
+ if (check_boot_mode_secure(&mode) == true) {
+ bypass_smmu(NXP_SMMU_ADDR);
+ }
+
+ /*
+ * For Mbedtls currently crypto is not supported via CAAM
+ * enable it when that support is there. In tbbr.mk
+ * the CAAM_INTEG is set as 0.
+ */
+
+#ifndef MBEDTLS_X509
+ /* Initialize the crypto accelerator if enabled */
+ if (is_sec_enabled() == false) {
+ INFO("SEC is disabled.\n");
+ } else {
+ sec_init(NXP_CAAM_ADDR);
+ }
+#endif
+#elif defined(POLICY_FUSE_PROVISION)
+ gpio_init(&gpio_init_data);
+ sfp_init(NXP_SFP_ADDR);
+ sec_init(NXP_CAAM_ADDR);
+#endif
+
+ soc_errata();
+
+ /*
+ * Initialize system level generic timer for Layerscape Socs.
+ */
+ delay_timer_init(NXP_TIMER_ADDR);
+
+#ifdef DDR_INIT
+ i2c_init(NXP_I2C_ADDR);
+ dram_regions_info->total_dram_size = init_ddr();
+#endif
+}
+
+void soc_bl2_prepare_exit(void)
+{
+#if defined(NXP_SFP_ENABLED) && defined(DISABLE_FUSE_WRITE)
+ set_sfp_wr_disable();
+#endif
+}
+
+/*****************************************************************************
+ * This function returns the boot device based on RCW_SRC
+ ****************************************************************************/
+enum boot_device get_boot_dev(void)
+{
+ enum boot_device src = BOOT_DEVICE_NONE;
+ uint32_t porsr1;
+ uint32_t rcw_src, val;
+
+ porsr1 = read_reg_porsr1();
+
+ rcw_src = (porsr1 & PORSR1_RCW_MASK) >> PORSR1_RCW_SHIFT;
+
+ val = rcw_src & RCW_SRC_NAND_MASK;
+
+ if (val == RCW_SRC_NAND_VAL) {
+ val = rcw_src & NAND_RESERVED_MASK;
+ if ((val != NAND_RESERVED_1) && (val != NAND_RESERVED_2)) {
+ src = BOOT_DEVICE_IFC_NAND;
+ INFO("RCW BOOT SRC is IFC NAND\n");
+ }
+ } else {
+ /* RCW SRC NOR */
+ val = rcw_src & RCW_SRC_NOR_MASK;
+ if (val == NOR_8B_VAL || val == NOR_16B_VAL) {
+ src = BOOT_DEVICE_IFC_NOR;
+ INFO("RCW BOOT SRC is IFC NOR\n");
+ } else {
+ switch (rcw_src) {
+ case QSPI_VAL1:
+ case QSPI_VAL2:
+ src = BOOT_DEVICE_QSPI;
+ INFO("RCW BOOT SRC is QSPI\n");
+ break;
+ case SD_VAL:
+ src = BOOT_DEVICE_EMMC;
+ INFO("RCW BOOT SRC is SD/EMMC\n");
+ break;
+ default:
+ src = BOOT_DEVICE_NONE;
+ }
+ }
+ }
+
+ return src;
+}
+
+/* This function sets up access permissions on memory regions */
+void soc_mem_access(void)
+{
+ struct tzc380_reg tzc380_reg_list[MAX_NUM_TZC_REGION];
+ int dram_idx, index = 0U;
+ dram_regions_info_t *info_dram_regions = get_dram_regions_info();
+
+ for (dram_idx = 0U; dram_idx < info_dram_regions->num_dram_regions;
+ dram_idx++) {
+ if (info_dram_regions->region[dram_idx].size == 0) {
+ ERROR("DDR init failure, or");
+ ERROR("DRAM regions not populated correctly.\n");
+ break;
+ }
+
+ index = populate_tzc380_reg_list(tzc380_reg_list,
+ dram_idx, index,
+ info_dram_regions->region[dram_idx].addr,
+ info_dram_regions->region[dram_idx].size,
+ NXP_SECURE_DRAM_SIZE, NXP_SP_SHRD_DRAM_SIZE);
+ }
+
+ mem_access_setup(NXP_TZC_ADDR, index, tzc380_reg_list);
+
+ /* Configure CSU secure access register to disable TZASC bypass mux */
+ mmio_write_32((uintptr_t)(NXP_CSU_ADDR +
+ CSU_SEC_ACCESS_REG_OFFSET),
+ bswap32(TZASC_BYPASS_MUX_DISABLE));
+}
+
+
+#else
+const unsigned char _power_domain_tree_desc[] = {1, 1, 4};
+
+CASSERT(NUMBER_OF_CLUSTERS && NUMBER_OF_CLUSTERS <= 256,
+ assert_invalid_ls1043_cluster_count);
+
+/* This function returns the SoC topology */
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+
+ return _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 CORES_PER_CLUSTER;
+}
+
+void soc_early_platform_setup2(void)
+{
+ dcfg_init(&dcfg_init_data);
+ /* Initialize system level generic timer for Socs */
+ delay_timer_init(NXP_TIMER_ADDR);
+
+#if LOG_LEVEL > 0
+ /* Initialize the console to provide early debug support */
+ plat_console_init(NXP_CONSOLE_ADDR,
+ NXP_UART_CLK_DIVIDER, NXP_CONSOLE_BAUDRATE);
+#endif
+}
+
+/*
+ * 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 *)(NXP_DCFG_ADDR + DCFG_SVR_OFFSET);
+ uint32_t *gic_align = (uint32_t *)(NXP_SCFG_ADDR +
+ SCFG_GIC400_ADDR_ALIGN_OFFSET);
+ uint32_t val;
+
+ val = be32toh(mmio_read_32((uintptr_t)ccsr_svr));
+
+ if ((val & 0xff) == REV1_1) {
+ val = be32toh(mmio_read_32((uintptr_t)gic_align));
+ if (val & (1L << GIC_ADDR_BIT)) {
+ *gicc_base = NXP_GICC_4K_ADDR;
+ *gicd_base = NXP_GICD_4K_ADDR;
+ } else {
+ *gicc_base = NXP_GICC_64K_ADDR;
+ *gicd_base = NXP_GICD_64K_ADDR;
+ }
+ } else {
+ *gicc_base = NXP_GICC_4K_ADDR;
+ *gicd_base = NXP_GICD_4K_ADDR;
+ }
+}
+
+void soc_platform_setup(void)
+{
+ /* Initialize the GIC driver, cpu and distributor interfaces */
+ static uint32_t target_mask_array[PLATFORM_CORE_COUNT];
+ /*
+ * On a GICv2 system, the Group 1 secure interrupts are treated
+ * as Group 0 interrupts.
+ */
+ static interrupt_prop_t ls_interrupt_props[] = {
+ PLAT_LS_G1S_IRQ_PROPS(GICV2_INTR_GROUP0),
+ PLAT_LS_G0_IRQ_PROPS(GICV2_INTR_GROUP0)
+ };
+ static uint32_t gicc_base, gicd_base;
+
+ get_gic_offset(&gicc_base, &gicd_base);
+ plat_ls_gic_driver_init(gicd_base, gicc_base,
+ PLATFORM_CORE_COUNT,
+ ls_interrupt_props,
+ ARRAY_SIZE(ls_interrupt_props),
+ target_mask_array);
+
+ plat_ls_gic_init();
+ enable_init_timer();
+}
+
+/* This function initializes the soc from the BL31 module */
+void soc_init(void)
+{
+ /* low-level init of the soc */
+ soc_init_lowlevel();
+ _init_global_data();
+ soc_init_percpu();
+ _initialize_psci();
+
+ /*
+ * Initialize the interconnect during cold boot.
+ * No need for locks as no other CPU is active.
+ */
+ cci_init(NXP_CCI_ADDR, cci_map, ARRAY_SIZE(cci_map));
+
+ /*
+ * Enable coherency in interconnect for the primary CPU's cluster.
+ * Earlier bootloader stages might already do this but we can't
+ * assume so. No harm in executing this code twice.
+ */
+ cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
+
+ /* Init CSU to enable non-secure access to peripherals */
+ enable_layerscape_ns_access(ns_dev, ARRAY_SIZE(ns_dev), NXP_CSU_ADDR);
+
+ /* Initialize the crypto accelerator if enabled */
+ if (is_sec_enabled() == false) {
+ INFO("SEC is disabled.\n");
+ } else {
+ sec_init(NXP_CAAM_ADDR);
+ }
+}
+
+void soc_runtime_setup(void)
+{
+
+}
+#endif
diff --git a/plat/nxp/soc-ls1043a/soc.def b/plat/nxp/soc-ls1043a/soc.def
new file mode 100644
index 0000000..b174bd6
--- /dev/null
+++ b/plat/nxp/soc-ls1043a/soc.def
@@ -0,0 +1,107 @@
+#
+# Copyright 2017-2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+#------------------------------------------------------------------------------
+#
+# This file contains the basic architecture definitions that drive the build
+#
+# -----------------------------------------------------------------------------
+
+CORE_TYPE := a53
+
+CACHE_LINE := 6
+
+# set to GIC400 or GIC500
+GIC := GIC400
+
+# set to CCI400 or CCN504 or CCN508
+INTERCONNECT := CCI400
+
+# indicate layerscape chassis level - set to 3=LSCH3 or 2=LSCH2
+CHASSIS := 2
+
+# TZC IP Details TZC used is TZC380 or TZC400
+TZC_ID := TZC380
+
+# CONSOLE Details available is NS16550 or PL011
+CONSOLE := NS16550
+
+# Select the DDR PHY generation to be used
+PLAT_DDR_PHY := PHY_GEN1
+
+PHYS_SYS := 64
+
+# ddr controller - set to MMDC or NXP
+DDRCNTLR := NXP
+
+# ddr phy - set to NXP or SNPS
+DDRPHY := NXP
+
+# Area of OCRAM reserved by ROM code
+NXP_ROM_RSVD := 0x5900
+
+# Max Size of CSF header. Required to define BL2 TEXT LIMIT in soc.def
+# Input to CST create_hdr_esbc tool
+CSF_HDR_SZ := 0x3000
+
+# In IMAGE_BL2, compile time flag for handling Cache coherency
+# with CAAM for BL2 running from OCRAM
+SEC_MEM_NON_COHERENT := yes
+
+# OCRAM MAP
+OCRAM_START_ADDR := 0x10000000
+OCRAM_SIZE := 0x20000
+
+# BL2 binary is placed at start of OCRAM.
+# Also used by create_pbl.mk.
+BL2_BASE := 0x10000000
+
+# After BL2 bin, OCRAM is used by ROM Code:
+# (OCRAM_START_ADDR + BL2_BIN_SIZE) -> (NXP_ROM_RSVD - 1)
+
+# After ROM Code, OCRAM is used by CSF header.
+# (OCRAM_START_ADDR + BL2_TEXT_LIMIT + NXP_ROM_RSVD) -> (CSF_HDR_SZ - 1)
+
+# BL2_HDR_LOC has to be (OCRAM_START_ADDR + OCRAM_SIZE - NXP_ROM_RSVD - CSF_HDR_SZ)
+# This value should be greater than BL2_TEXT_LIMIT
+# Input to CST create_hdr_isbc tool
+BL2_HDR_LOC_HDR ?= $(shell echo $$(( $(OCRAM_START_ADDR) + $(OCRAM_SIZE) - $(NXP_ROM_RSVD) - $(CSF_HDR_SZ))))
+# Covert to HEX to be used by create_pbl.mk
+BL2_HDR_LOC := $$(echo "obase=16; ${BL2_HDR_LOC_HDR}" | bc)
+
+# Core Errata
+ERRATA_A53_855873 := 1
+ERRATA_A53_1530924 := 1
+
+# SoC ERRATAS to be enabled
+ERRATA_SOC_A008850 := 1
+ERRATA_SOC_A010539 := 1
+ERRATA_SOC_A009660 := 1
+
+# DDR Errata
+ERRATA_DDR_A009663 := 1
+ERRATA_DDR_A009942 := 1
+
+# enable dynamic memory mapping
+PLAT_XLAT_TABLES_DYNAMIC := 1
+
+# Define Endianness of each module
+NXP_GUR_ENDIANNESS := BE
+NXP_DDR_ENDIANNESS := BE
+NXP_SEC_ENDIANNESS := BE
+NXP_SFP_ENDIANNESS := BE
+NXP_SNVS_ENDIANNESS := BE
+NXP_ESDHC_ENDIANNESS := BE
+NXP_QSPI_ENDIANNESS := BE
+NXP_FSPI_ENDIANNESS := BE
+NXP_SCFG_ENDIANNESS := BE
+NXP_GPIO_ENDIANNESS := BE
+NXP_IFC_ENDIANNESS := BE
+
+NXP_SFP_VER := 3_2
+
+# OCRAM ECC Enabled
+OCRAM_ECC_EN := yes
diff --git a/plat/nxp/soc-ls1043a/soc.mk b/plat/nxp/soc-ls1043a/soc.mk
new file mode 100644
index 0000000..b6ce14e
--- /dev/null
+++ b/plat/nxp/soc-ls1043a/soc.mk
@@ -0,0 +1,114 @@
+#
+# Copyright 2018-2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# SoC-specific build parameters
+SOC := ls1043a
+PLAT_PATH := plat/nxp
+PLAT_COMMON_PATH := plat/nxp/common
+PLAT_DRIVERS_PATH := drivers/nxp
+PLAT_SOC_PATH := ${PLAT_PATH}/soc-${SOC}
+BOARD_PATH := ${PLAT_SOC_PATH}/${BOARD}
+
+# get SoC-specific defnitions
+include ${PLAT_SOC_PATH}/soc.def
+include ${PLAT_COMMON_PATH}/plat_make_helper/soc_common_def.mk
+include ${PLAT_COMMON_PATH}/plat_make_helper/plat_build_macros.mk
+
+# For Security Features
+DISABLE_FUSE_WRITE := 1
+ifeq (${TRUSTED_BOARD_BOOT}, 1)
+$(eval $(call SET_NXP_MAKE_FLAG,SMMU_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,SFP_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,SNVS_NEEDED,BL2))
+SECURE_BOOT := yes
+endif
+$(eval $(call SET_NXP_MAKE_FLAG,CRYPTO_NEEDED,BL_COMM))
+
+# Selecting Drivers for SoC
+$(eval $(call SET_NXP_MAKE_FLAG,DCFG_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,CSU_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,TIMER_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,INTERCONNECT_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,GIC_NEEDED,BL31))
+$(eval $(call SET_NXP_MAKE_FLAG,CONSOLE_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,PMU_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,DDR_DRIVER_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,TZASC_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,I2C_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,IMG_LOADR_NEEDED,BL2))
+
+# Selecting PSCI & SIP_SVC support
+$(eval $(call SET_NXP_MAKE_FLAG,PSCI_NEEDED,BL31))
+$(eval $(call SET_NXP_MAKE_FLAG,SIPSVC_NEEDED,BL31))
+
+# Source File Addition
+PLAT_INCLUDES += -I${PLAT_COMMON_PATH}/include/default\
+ -I${BOARD_PATH}\
+ -I${PLAT_COMMON_PATH}/include/default/ch_${CHASSIS}\
+ -I${PLAT_SOC_PATH}/include\
+ -I${PLAT_COMMON_PATH}/soc_errata
+
+ifeq (${SECURE_BOOT},yes)
+include ${PLAT_COMMON_PATH}/tbbr/tbbr.mk
+endif
+
+ifeq ($(WARM_BOOT),yes)
+include ${PLAT_COMMON_PATH}/warm_reset/warm_reset.mk
+endif
+
+ifeq (${NXP_NV_SW_MAINT_LAST_EXEC_DATA}, yes)
+include ${PLAT_COMMON_PATH}/nv_storage/nv_storage.mk
+endif
+
+ifeq (${PSCI_NEEDED}, yes)
+include ${PLAT_COMMON_PATH}/psci/psci.mk
+endif
+
+ifeq (${SIPSVC_NEEDED}, yes)
+include ${PLAT_COMMON_PATH}/sip_svc/sipsvc.mk
+endif
+
+# for fuse-fip & fuse-programming
+ifeq (${FUSE_PROG}, 1)
+include ${PLAT_COMMON_PATH}/fip_handler/fuse_fip/fuse.mk
+endif
+
+ifeq (${IMG_LOADR_NEEDED},yes)
+include $(PLAT_COMMON_PATH)/img_loadr/img_loadr.mk
+endif
+
+# Adding source files for the above selected drivers.
+include ${PLAT_DRIVERS_PATH}/drivers.mk
+
+# Adding SoC specific files
+include ${PLAT_COMMON_PATH}/soc_errata/errata.mk
+
+PLAT_INCLUDES += ${NV_STORAGE_INCLUDES}\
+ ${WARM_RST_INCLUDES}
+
+BL31_SOURCES += ${PLAT_SOC_PATH}/$(ARCH)/${SOC}.S\
+ ${WARM_RST_BL31_SOURCES}\
+ ${PSCI_SOURCES}\
+ ${SIPSVC_SOURCES}\
+ ${PLAT_COMMON_PATH}/$(ARCH)/bl31_data.S
+
+PLAT_BL_COMMON_SOURCES += ${PLAT_COMMON_PATH}/$(ARCH)/ls_helpers.S\
+ ${PLAT_SOC_PATH}/aarch64/${SOC}_helpers.S\
+ ${NV_STORAGE_SOURCES}\
+ ${WARM_RST_BL_COMM_SOURCES}\
+ ${PLAT_SOC_PATH}/soc.c
+
+ifeq (${TEST_BL31}, 1)
+BL31_SOURCES += ${PLAT_SOC_PATH}/$(ARCH)/bootmain64.S\
+ ${PLAT_SOC_PATH}/$(ARCH)/nonboot64.S
+endif
+
+BL2_SOURCES += ${DDR_CNTLR_SOURCES}\
+ ${TBBR_SOURCES}\
+ ${FUSE_SOURCES}
+
+# Adding TFA setup files
+include ${PLAT_PATH}/common/setup/common.mk
diff --git a/plat/nxp/soc-ls1046a/aarch64/ls1046a.S b/plat/nxp/soc-ls1046a/aarch64/ls1046a.S
new file mode 100644
index 0000000..daa0542
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/aarch64/ls1046a.S
@@ -0,0 +1,937 @@
+/*
+ * Copyright 2020-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <asm_macros.S>
+#include <dcfg_lsch2.h>
+#include <nxp_timer.h>
+#include <plat_gic.h>
+#include <scfg.h>
+
+#include <bl31_data.h>
+#include <plat_psci.h>
+#include <platform_def.h>
+
+#define DAIF_DATA AUX_01_DATA
+#define TIMER_CNTRL_DATA AUX_02_DATA
+
+.global soc_init_lowlevel
+.global soc_init_percpu
+.global _soc_core_release
+.global _soc_core_restart
+.global _soc_ck_disabled
+.global _soc_sys_reset
+.global _soc_sys_off
+.global _soc_set_start_addr
+.global _getGICC_BaseAddr
+.global _getGICD_BaseAddr
+.global _soc_core_prep_off
+.global _soc_core_entr_off
+.global _soc_core_exit_off
+.global _soc_core_prep_stdby
+.global _soc_core_entr_stdby
+.global _soc_core_exit_stdby
+.global _soc_core_prep_pwrdn
+.global _soc_core_entr_pwrdn
+.global _soc_core_exit_pwrdn
+.global _soc_clstr_prep_stdby
+.global _soc_clstr_exit_stdby
+.global _soc_clstr_prep_pwrdn
+.global _soc_clstr_exit_pwrdn
+.global _soc_sys_prep_stdby
+.global _soc_sys_exit_stdby
+.global _soc_sys_prep_pwrdn
+.global _soc_sys_pwrdn_wfi
+.global _soc_sys_exit_pwrdn
+
+
+/* This function initialize the soc
+ * in: void
+ * out: void
+ */
+func soc_init_lowlevel
+ ret
+endfunc soc_init_lowlevel
+
+
+/* void soc_init_percpu(void)
+ * this function performs any soc-specific initialization that is needed on
+ * a per-core basis
+ * in: none
+ * out: none
+ * uses x0, x1, x2, x3
+ */
+func soc_init_percpu
+ mov x3, x30
+
+ bl plat_my_core_mask
+ mov x2, x0
+
+ /* see if this core is marked for prefetch disable */
+ mov x0, #PREFETCH_DIS_OFFSET
+ bl _get_global_data /* 0-1 */
+ tst x0, x2
+ b.eq 1f
+ bl _disable_ldstr_pfetch_A72 /* 0 */
+1:
+ mov x30, x3
+ ret
+endfunc soc_init_percpu
+
+/* part of CPU_ON
+ * this function releases a secondary core from reset
+ * in: x0 = core_mask_lsb
+ * out: none
+ * uses: x0, x1, x2, x3
+ */
+func _soc_core_release
+
+#if (TEST_BL31)
+ rbit w2, w0
+ /* x2 = core mask msb */
+#else
+ mov x2, x0
+#endif
+ /* write COREBCR */
+ mov x1, #NXP_SCFG_ADDR
+ rev w3, w2
+ str w3, [x1, #SCFG_COREBCR_OFFSET]
+ isb
+
+ /* read-modify-write BRR */
+ mov x1, #NXP_DCFG_ADDR
+ ldr w2, [x1, #DCFG_BRR_OFFSET]
+ rev w3, w2
+ orr w3, w3, w0
+ rev w2, w3
+ str w2, [x1, #DCFG_BRR_OFFSET]
+ isb
+
+ /* send event */
+ sev
+ isb
+ ret
+endfunc _soc_core_release
+
+
+/* part of CPU_ON
+ * this function restarts a core shutdown via _soc_core_entr_off
+ * in: x0 = core mask lsb (of the target cpu)
+ * out: x0 == 0, on success
+ * x0 != 0, on failure
+ * uses x0, x1, x2, x3, x4, x5
+ */
+func _soc_core_restart
+ mov x5, x30
+ mov x3, x0
+
+ /*
+ * unset ph20 request in RCPM_PCPH20CLEARR
+ * this is an lsb-0 register
+ */
+ ldr x1, =NXP_RCPM_ADDR
+ rev w2, w3
+ str w2, [x1, #RCPM_PCPH20CLRR_OFFSET]
+ dsb sy
+ isb
+
+ bl _getGICD_BaseAddr
+ mov x4, x0
+
+ /* enable forwarding of group 0 interrupts by setting GICD_CTLR[0] = 1 */
+ ldr w1, [x4, #GICD_CTLR_OFFSET]
+ orr w1, w1, #GICD_CTLR_EN_GRP0
+ str w1, [x4, #GICD_CTLR_OFFSET]
+ dsb sy
+ isb
+
+
+ /*
+ * fire SGI by writing to GICD_SGIR the following values:
+ * [25:24] = 0x0 (forward interrupt to the CPU interfaces
+ * specified in CPUTargetList field)
+ * [23:16] = core mask lsb[7:0] (forward interrupt to target cpu)
+ * [15] = 0 (forward SGI only if it is configured as group 0 interrupt)
+ * [3:0] = 0xF (interrupt ID = 15)
+ */
+ lsl w1, w3, #16
+ orr w1, w1, #0xF
+ str w1, [x4, #GICD_SGIR_OFFSET]
+ dsb sy
+ isb
+
+ /* load '0' on success */
+ mov x0, xzr
+
+ mov x30, x5
+ ret
+endfunc _soc_core_restart
+
+/*
+ * This function determines if a core is disabled via COREDISR
+ * in: w0 = core_mask_lsb
+ * out: w0 = 0, core not disabled
+ * w0 != 0, core disabled
+ * uses x0, x1, x2
+ */
+func _soc_ck_disabled
+ /* get base addr of dcfg block */
+ mov x1, #NXP_DCFG_ADDR
+
+ /* read COREDISR */
+ ldr w1, [x1, #DCFG_COREDISR_OFFSET]
+ rev w2, w1
+
+ /* test core bit */
+ and w0, w2, w0
+ ret
+endfunc _soc_ck_disabled
+
+/*
+ *This function resets the system via SoC-specific methods
+ * in: none
+ * out: none
+ * uses x0, x1, x2, x3
+ */
+func _soc_sys_reset
+ ldr x2, =NXP_DCFG_ADDR
+
+ /* make sure the mask is cleared in the reset request mask register */
+ mov w1, wzr
+ str w1, [x2, #DCFG_RSTRQMR1_OFFSET]
+
+ /* set the reset request */
+ ldr w1, =RSTCR_RESET_REQ
+ ldr x3, =DCFG_RSTCR_OFFSET
+ rev w0, w1
+ str w0, [x2, x3]
+
+ /*
+ * just in case this address range is mapped as cacheable,
+ * flush the write out of the dcaches
+ */
+ add x3, x2, x3
+ dc cvac, x3
+ dsb st
+ isb
+
+ /* Note: this function does not return */
+1:
+ wfi
+ b 1b
+endfunc _soc_sys_reset
+
+/*
+ * Part of SYSTEM_OFF
+ * this function turns off the SoC clocks
+ * Note: this function is not intended to return, and the only allowable
+ * recovery is POR
+ * in: none
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6, x7, x8, x9
+ */
+func _soc_sys_off
+
+ /* mask interrupts at the core */
+ mrs x1, DAIF
+ mov x0, #DAIF_SET_MASK
+ orr x0, x1, x0
+ msr DAIF, x0
+
+ /* disable icache, dcache, mmu @ EL1 */
+ mov x1, #SCTLR_I_C_M_MASK
+ mrs x0, sctlr_el1
+ bic x0, x0, x1
+ msr sctlr_el1, x0
+
+ /* disable dcache for EL3 */
+ mrs x1, SCTLR_EL3
+ bic x1, x1, #SCTLR_C_MASK
+ /* make sure icache is enabled */
+ orr x1, x1, #SCTLR_I_MASK
+ msr SCTLR_EL3, x1
+ isb
+
+ /* Enable dynamic retention ctrl (CPUECTLR[2:0]) and SMP (CPUECTLR[6]) */
+ mrs x0, CORTEX_A72_ECTLR_EL1
+ orr x0, x0, #CPUECTLR_TIMER_8TICKS
+ orr x0, x0, #CPUECTLR_SMPEN_EN
+ msr CORTEX_A72_ECTLR_EL1, x0
+
+ /* set WFIL2EN in SCFG_CLUSTERPMCR */
+ ldr x0, =SCFG_COREPMCR_OFFSET
+ ldr x1, =COREPMCR_WFIL2
+ bl write_reg_scfg
+
+ /* request LPM20 */
+ mov x0, #RCPM_POWMGTCSR_OFFSET
+ bl read_reg_rcpm
+ orr x1, x0, #RCPM_POWMGTCSR_LPM20_REQ
+ mov x0, #RCPM_POWMGTCSR_OFFSET
+ bl write_reg_rcpm
+
+ dsb sy
+ isb
+1:
+ wfi
+ b 1b
+endfunc _soc_sys_off
+
+/*
+ * Write a register in the RCPM block
+ * in: x0 = offset
+ * in: w1 = value to write
+ * uses x0, x1, x2, x3
+ */
+func write_reg_rcpm
+ ldr x2, =NXP_RCPM_ADDR
+ /* swap for BE */
+ rev w3, w1
+ str w3, [x2, x0]
+ ret
+endfunc write_reg_rcpm
+
+/*
+ * Read a register in the RCPM block
+ * in: x0 = offset
+ * out: w0 = value read
+ * uses x0, x1, x2
+ */
+func read_reg_rcpm
+ ldr x2, =NXP_RCPM_ADDR
+ ldr w1, [x2, x0]
+ /* swap for BE */
+ rev w0, w1
+ ret
+endfunc read_reg_rcpm
+
+/*
+ * Write a register in the SCFG block
+ * in: x0 = offset
+ * in: w1 = value to write
+ * uses x0, x1, x2, x3
+ */
+func write_reg_scfg
+ mov x2, #NXP_SCFG_ADDR
+ /* swap for BE */
+ rev w3, w1
+ str w3, [x2, x0]
+ ret
+endfunc write_reg_scfg
+
+/*
+ * Read a register in the SCFG block
+ * in: x0 = offset
+ * out: w0 = value read
+ * uses x0, x1, x2
+ */
+func read_reg_scfg
+ mov x2, #NXP_SCFG_ADDR
+ ldr w1, [x2, x0]
+ /* swap for BE */
+ rev w0, w1
+ ret
+endfunc read_reg_scfg
+
+/*
+ * Part of CPU_OFF
+ * this function programs SoC & GIC registers in preparation for shutting down
+ * the core
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6, x7
+ */
+func _soc_core_prep_off
+ mov x7, x30
+ mov x6, x0
+
+ /* Set retention control in CPUECTLR make sure smpen bit is set */
+ mrs x4, CORTEX_A72_ECTLR_EL1
+ bic x4, x4, #CPUECTLR_RET_MASK
+ orr x4, x4, #CPUECTLR_TIMER_8TICKS
+ orr x4, x4, #CPUECTLR_SMPEN_EN
+ msr CORTEX_A72_ECTLR_EL1, x4
+
+ /* save timer control current value */
+ mov x5, #NXP_TIMER_ADDR
+ ldr w4, [x5, #SYS_COUNTER_CNTCR_OFFSET]
+ mov w2, w4
+ mov x0, x6
+ mov x1, #TIMER_CNTRL_DATA
+ bl _setCoreData
+
+ /* enable the timer */
+ orr w4, w4, #CNTCR_EN_MASK
+ str w4, [x5, #SYS_COUNTER_CNTCR_OFFSET]
+
+ bl _getGICC_BaseAddr
+ mov x5, x0
+
+ /* disable signaling of ints */
+ ldr w3, [x5, #GICC_CTLR_OFFSET]
+ bic w3, w3, #GICC_CTLR_EN_GRP0
+ bic w3, w3, #GICC_CTLR_EN_GRP1
+ str w3, [x5, #GICC_CTLR_OFFSET]
+ dsb sy
+ isb
+
+
+ /*
+ * set retention control in SCFG_RETREQCR
+ * Note: this register is msb 0
+ */
+ ldr x4, =SCFG_RETREQCR_OFFSET
+ mov x0, x4
+ bl read_reg_scfg
+ rbit w1, w6
+ orr w1, w0, w1
+ mov x0, x4
+ bl write_reg_scfg
+
+ /* set the priority filter */
+ ldr w2, [x5, #GICC_PMR_OFFSET]
+ orr w2, w2, #GICC_PMR_FILTER
+ str w2, [x5, #GICC_PMR_OFFSET]
+
+ /* setup GICC_CTLR */
+ bic w3, w3, #GICC_CTLR_ACKCTL_MASK
+ orr w3, w3, #GICC_CTLR_FIQ_EN_MASK
+ orr w3, w3, #GICC_CTLR_EOImodeS_MASK
+ orr w3, w3, #GICC_CTLR_CBPR_MASK
+ str w3, [x5, #GICC_CTLR_OFFSET]
+
+ /* setup the banked-per-core GICD registers */
+ bl _getGICD_BaseAddr
+ mov x5, x0
+
+ /* define SGI15 as Grp0 */
+ ldr w2, [x5, #GICD_IGROUPR0_OFFSET]
+ bic w2, w2, #GICD_IGROUP0_SGI15
+ str w2, [x5, #GICD_IGROUPR0_OFFSET]
+
+ /* set priority of SGI 15 to highest... */
+ ldr w2, [x5, #GICD_IPRIORITYR3_OFFSET]
+ bic w2, w2, #GICD_IPRIORITY_SGI15_MASK
+ str w2, [x5, #GICD_IPRIORITYR3_OFFSET]
+
+ /* enable SGI 15 */
+ ldr w2, [x5, #GICD_ISENABLER0_OFFSET]
+ orr w2, w2, #GICD_ISENABLE0_SGI15
+ str w2, [x5, #GICD_ISENABLER0_OFFSET]
+
+ /* enable the cpu interface */
+ bl _getGICC_BaseAddr
+ mov x2, x0
+ orr w3, w3, #GICC_CTLR_EN_GRP0
+ str w3, [x2, #GICC_CTLR_OFFSET]
+
+
+ /* clear any pending SGIs */
+ ldr x2, =GICD_CPENDSGIR_CLR_MASK
+ add x0, x5, #GICD_CPENDSGIR3_OFFSET
+ str w2, [x0]
+
+ /*
+ * Set the PC_PH20_REQ bit in RCPM_PCPH20SETR
+ * this is an lsb-0 register
+ */
+ mov x1, x6
+ mov x0, #RCPM_PCPH20SETR_OFFSET
+ bl write_reg_rcpm
+
+ dsb sy
+ isb
+ mov x30, x7
+ ret
+endfunc _soc_core_prep_off
+
+/*
+ * Part of CPU_OFF
+ * this function performs the final steps to shutdown the core
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5
+ */
+func _soc_core_entr_off
+ mov x5, x30
+ mov x4, x0
+
+ bl _getGICD_BaseAddr
+ mov x3, x0
+
+3:
+ /* enter low-power state by executing wfi */
+ wfi
+
+ /* see if we got hit by SGI 15 */
+ add x0, x3, #GICD_SPENDSGIR3_OFFSET
+ ldr w2, [x0]
+ and w2, w2, #GICD_SPENDSGIR3_SGI15_MASK
+ cbz w2, 4f
+
+ /* clear the pending SGI */
+ ldr x2, =GICD_CPENDSGIR_CLR_MASK
+ add x0, x3, #GICD_CPENDSGIR3_OFFSET
+ str w2, [x0]
+4:
+ /* check if core has been turned on */
+ mov x0, x4
+ bl _getCoreState
+
+ cmp x0, #CORE_WAKEUP
+ b.ne 3b
+
+ /* if we get here, then we have exited the wfi */
+ dsb sy
+ isb
+ mov x30, x5
+ ret
+endfunc _soc_core_entr_off
+
+/*
+ * Part of CPU_OFF
+ * this function starts the process of starting a core back up
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6
+ */
+func _soc_core_exit_off
+ mov x6, x30
+ mov x5, x0
+
+ /*
+ * Clear ph20 request in RCPM_PCPH20CLRR - no need
+ * to do that here, it has been done in _soc_core_restart
+ */
+ bl _getGICC_BaseAddr
+ mov x1, x0
+
+ /* read GICC_IAR */
+ ldr w0, [x1, #GICC_IAR_OFFSET]
+
+ /* write GICC_EIOR - signal end-of-interrupt */
+ str w0, [x1, #GICC_EOIR_OFFSET]
+
+ /* write GICC_DIR - disable interrupt */
+ str w0, [x1, #GICC_DIR_OFFSET]
+
+ /* disable signaling of grp0 ints */
+ ldr w3, [x1, #GICC_CTLR_OFFSET]
+ bic w3, w3, #GICC_CTLR_EN_GRP0
+ str w3, [x1, #GICC_CTLR_OFFSET]
+
+ /*
+ * Unset retention request in SCFG_RETREQCR
+ * Note: this register is msb-0
+ */
+ ldr x4, =SCFG_RETREQCR_OFFSET
+ mov x0, x4
+ bl read_reg_scfg
+ rbit w1, w5
+ bic w1, w0, w1
+ mov x0, x4
+ bl write_reg_scfg
+
+ /* restore timer ctrl */
+ mov x0, x5
+ mov x1, #TIMER_CNTRL_DATA
+ bl _getCoreData
+ /* w0 = timer ctrl saved value */
+ mov x2, #NXP_TIMER_ADDR
+ str w0, [x2, #SYS_COUNTER_CNTCR_OFFSET]
+
+ dsb sy
+ isb
+ mov x30, x6
+ ret
+endfunc _soc_core_exit_off
+
+/*
+ * Function loads a 64-bit execution address of the core in the soc registers
+ * BOOTLOCPTRL/H
+ * in: x0, 64-bit address to write to BOOTLOCPTRL/H
+ * uses x0, x1, x2, x3
+ */
+func _soc_set_start_addr
+ /* get the 64-bit base address of the scfg block */
+ ldr x2, =NXP_SCFG_ADDR
+
+ /* write the 32-bit BOOTLOCPTRL register */
+ mov x1, x0
+ rev w3, w1
+ str w3, [x2, #SCFG_BOOTLOCPTRL_OFFSET]
+
+ /* write the 32-bit BOOTLOCPTRH register */
+ lsr x1, x0, #32
+ rev w3, w1
+ str w3, [x2, #SCFG_BOOTLOCPTRH_OFFSET]
+ ret
+endfunc _soc_set_start_addr
+
+/*
+ * This function returns the base address of the gic distributor
+ * in: none
+ * out: x0 = base address of gic distributor
+ * uses x0
+ */
+func _getGICD_BaseAddr
+#if (TEST_BL31)
+ /* defect in simulator - gic base addresses are on 4Kb boundary */
+ ldr x0, =NXP_GICD_4K_ADDR
+#else
+ ldr x0, =NXP_GICD_64K_ADDR
+#endif
+ ret
+endfunc _getGICD_BaseAddr
+
+/*
+ * This function returns the base address of the gic controller
+ * in: none
+ * out: x0 = base address of gic controller
+ * uses x0
+ */
+func _getGICC_BaseAddr
+#if (TEST_BL31)
+ /* defect in simulator - gic base addresses are on 4Kb boundary */
+ ldr x0, =NXP_GICC_4K_ADDR
+#else
+ ldr x0, =NXP_GICC_64K_ADDR
+#endif
+ ret
+endfunc _getGICC_BaseAddr
+
+/*
+ * Part of CPU_SUSPEND
+ * this function puts the calling core into standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0
+ */
+func _soc_core_entr_stdby
+ dsb sy
+ isb
+ wfi
+
+ ret
+endfunc _soc_core_entr_stdby
+
+
+/*
+ * Part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to standby
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+func _soc_core_prep_stdby
+ /* clear CORTEX_A72_ECTLR_EL1[2:0] */
+ mrs x1, CORTEX_A72_ECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ msr CORTEX_A72_ECTLR_EL1, x1
+
+ ret
+endfunc _soc_core_prep_stdby
+
+/*
+ * Part of CPU_SUSPEND
+ * this function performs any SoC-specific cleanup after standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+func _soc_core_exit_stdby
+ ret
+endfunc _soc_core_exit_stdby
+
+/*
+ * Part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5
+ */
+func _soc_core_prep_pwrdn
+ mov x5, x30
+ mov x4, x0
+
+ /* enable CPU retention + set smp */
+ mrs x1, CORTEX_A72_ECTLR_EL1
+ orr x1, x1, #0x1
+ orr x1, x1, #CPUECTLR_SMPEN_MASK
+ msr CORTEX_A72_ECTLR_EL1, x1
+
+ /*
+ * set the retention request in SCFG_RETREQCR
+ * this is an msb-0 register
+ */
+ ldr x3, =SCFG_RETREQCR_OFFSET
+ mov x0, x3
+ bl read_reg_scfg
+ rbit w1, w4
+ orr w1, w0, w1
+ mov x0, x3
+ bl write_reg_scfg
+
+ /*
+ * Set the PC_PH20_REQ bit in RCPM_PCPH20SETR
+ * this is an lsb-0 register
+ */
+ mov x1, x4
+ mov x0, #RCPM_PCPH20SETR_OFFSET
+ bl write_reg_rcpm
+
+ mov x30, x5
+ ret
+endfunc _soc_core_prep_pwrdn
+
+/*
+ * Part of CPU_SUSPEND
+ * this function puts the calling core into a power-down state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0
+ */
+func _soc_core_entr_pwrdn
+ dsb sy
+ isb
+ wfi
+
+ ret
+endfunc _soc_core_entr_pwrdn
+
+/*
+ * Part of CPU_SUSPEND
+ * this function cleans up after a core exits power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5
+ */
+func _soc_core_exit_pwrdn
+ mov x5, x30
+ mov x4, x0
+
+ /*
+ * Set the PC_PH20_REQ bit in RCPM_PCPH20CLRR
+ * this is an lsb-0 register
+ */
+ mov x1, x4
+ mov x0, #RCPM_PCPH20CLRR_OFFSET
+ bl write_reg_rcpm
+
+ /*
+ * Unset the retention request in SCFG_RETREQCR
+ * this is an msb-0 register
+ */
+ ldr x3, =SCFG_RETREQCR_OFFSET
+ mov x0, x3
+ bl read_reg_scfg
+ rbit w1, w4
+ bic w1, w0, w1
+ mov x0, x3
+ bl write_reg_scfg
+
+ mov x30, x5
+ ret
+endfunc _soc_core_exit_pwrdn
+
+/*
+ * Part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to standby
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+func _soc_clstr_prep_stdby
+ /* clear CORTEX_A72_ECTLR_EL1[2:0] */
+ mrs x1, CORTEX_A72_ECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ msr CORTEX_A72_ECTLR_EL1, x1
+
+ ret
+endfunc _soc_clstr_prep_stdby
+
+/*
+ * Part of CPU_SUSPEND
+ * this function performs any SoC-specific cleanup after standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+func _soc_clstr_exit_stdby
+ ret
+endfunc _soc_clstr_exit_stdby
+
+/*
+ * Part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5
+ */
+func _soc_clstr_prep_pwrdn
+ mov x5, x30
+ mov x4, x0
+
+ /* enable CPU retention + set smp */
+ mrs x1, CORTEX_A72_ECTLR_EL1
+ orr x1, x1, #0x1
+ orr x1, x1, #CPUECTLR_SMPEN_MASK
+ msr CORTEX_A72_ECTLR_EL1, x1
+
+ /*
+ * Set the retention request in SCFG_RETREQCR
+ * this is an msb-0 register.
+ */
+ ldr x3, =SCFG_RETREQCR_OFFSET
+ mov x0, x3
+ bl read_reg_scfg
+ rbit w1, w4
+ orr w1, w0, w1
+ mov x0, x3
+ bl write_reg_scfg
+
+ /*
+ * Set the PC_PH20_REQ bit in RCPM_PCPH20SETR
+ * this is an lsb-0 register.
+ */
+ mov x1, x4
+ mov x0, #RCPM_PCPH20SETR_OFFSET
+ bl write_reg_rcpm
+
+ mov x30, x5
+ ret
+endfunc _soc_clstr_prep_pwrdn
+
+/*
+ * Part of CPU_SUSPEND
+ * this function cleans up after a core exits power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5
+ */
+func _soc_clstr_exit_pwrdn
+ mov x5, x30
+ mov x4, x0
+
+ /*
+ * Set the PC_PH20_REQ bit in RCPM_PCPH20CLRR
+ * this is an lsb-0 register.
+ */
+ mov x1, x4
+ mov x0, #RCPM_PCPH20CLRR_OFFSET
+ bl write_reg_rcpm
+
+ /*
+ * Unset the retention request in SCFG_RETREQCR
+ * this is an msb-0 register.
+ */
+ ldr x3, =SCFG_RETREQCR_OFFSET
+ mov x0, x3
+ bl read_reg_scfg
+ rbit w1, w4
+ bic w1, w0, w1
+ mov x0, x3
+ bl write_reg_scfg
+
+ mov x30, x5
+ ret
+endfunc _soc_clstr_exit_pwrdn
+
+/*
+ * Part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to standby
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+func _soc_sys_prep_stdby
+ /* clear CORTEX_A72_ECTLR_EL1[2:0] */
+ mrs x1, CORTEX_A72_ECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ msr CORTEX_A72_ECTLR_EL1, x1
+
+ ret
+endfunc _soc_sys_prep_stdby
+
+/* Part of CPU_SUSPEND
+ * this function performs any SoC-specific cleanup after standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+func _soc_sys_exit_stdby
+ ret
+endfunc _soc_sys_exit_stdby
+
+/*
+ * Part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to
+ * suspend-to-power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4
+ */
+func _soc_sys_prep_pwrdn
+ mov x4, x30
+
+ /* Enable dynamic retention contrl (CPUECTLR[2:0]) and SMP (CPUECTLR[6]) */
+ mrs x0, CORTEX_A72_ECTLR_EL1
+ bic x0, x0, #CPUECTLR_TIMER_MASK
+ orr x0, x0, #CPUECTLR_TIMER_8TICKS
+ orr x0, x0, #CPUECTLR_SMPEN_EN
+ msr CORTEX_A72_ECTLR_EL1, x0
+
+ /* Set WFIL2EN in SCFG_CLUSTERPMCR */
+ ldr x0, =SCFG_COREPMCR_OFFSET
+ ldr x1, =COREPMCR_WFIL2
+ bl write_reg_scfg
+
+ isb
+ mov x30, x4
+ ret
+endfunc _soc_sys_prep_pwrdn
+
+/*
+ * Part of CPU_SUSPEND
+ * this function puts the calling core, and potentially the soc, into a
+ * low-power state
+ * in: x0 = core mask lsb
+ * out: x0 = 0, success
+ * x0 < 0, failure
+ * uses x0, x1, x2, x3, x4
+ */
+func _soc_sys_pwrdn_wfi
+ mov x4, x30
+
+ /* request LPM20 */
+ mov x0, #RCPM_POWMGTCSR_OFFSET
+ bl read_reg_rcpm
+ orr x1, x0, #RCPM_POWMGTCSR_LPM20_REQ
+ mov x0, #RCPM_POWMGTCSR_OFFSET
+ bl write_reg_rcpm
+
+ dsb sy
+ isb
+ wfi
+
+ mov x30, x4
+ ret
+endfunc _soc_sys_pwrdn_wfi
+
+/*
+ * Part of CPU_SUSPEND
+ * this function performs any SoC-specific cleanup after power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+func _soc_sys_exit_pwrdn
+ /* clear WFIL2_EN in SCFG_COREPMCR */
+ mov x1, #NXP_SCFG_ADDR
+ str wzr, [x1, #SCFG_COREPMCR_OFFSET]
+
+ ret
+endfunc _soc_sys_exit_pwrdn
diff --git a/plat/nxp/soc-ls1046a/aarch64/ls1046a_helpers.S b/plat/nxp/soc-ls1046a/aarch64/ls1046a_helpers.S
new file mode 100644
index 0000000..d2a48ea
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/aarch64/ls1046a_helpers.S
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+#include <platform_def.h>
+
+ .globl plat_secondary_cold_boot_setup
+ .globl plat_is_my_cpu_primary
+ .globl plat_reset_handler
+ .globl platform_mem_init
+
+func platform_mem1_init
+ ret
+endfunc platform_mem1_init
+
+func platform_mem_init
+ ret
+endfunc platform_mem_init
+
+func l2_mem_init
+ /* Initialize the L2 RAM latency */
+ mrs x1, S3_1_c11_c0_2
+ mov x0, #0x1C7
+ /* Clear L2 Tag RAM latency and L2 Data RAM latency */
+ bic x1, x1, x0
+ /* Set L2 data ram latency bits [2:0] */
+ orr x1, x1, #0x2
+ /* set L2 tag ram latency bits [8:6] */
+ orr x1, x1, #0x80
+ msr S3_1_c11_c0_2, x1
+ isb
+ ret
+endfunc l2_mem_init
+
+func apply_platform_errata
+ ret
+endfunc apply_platform_errata
+
+func plat_reset_handler
+ mov x29, x30
+#if (defined(IMAGE_BL2) && BL2_AT_EL3)
+ bl l2_mem_init
+#endif
+ bl apply_platform_errata
+
+#if defined(IMAGE_BL31)
+ ldr x0, =POLICY_SMMU_PAGESZ_64K
+ cbz x0, 1f
+ /* Set the SMMU page size in the SACR register */
+ bl _set_smmu_pagesz_64
+#endif
+1:
+ /*
+ * May be cntfrq_el0 needs to be assigned
+ * the value COUNTER_FREQUENCY
+ */
+ mov x30, x29
+ ret
+endfunc 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 e.g
+ * mark the cpu's presence, mechanism to place it in a
+ * holding pen etc.
+ */
+func plat_secondary_cold_boot_setup
+ /* ls1046a does not do cold boot for secondary CPU */
+cb_panic:
+ b cb_panic
+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
+ mrs x0, mpidr_el1
+ and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+ cmp x0, 0x0
+ cset w0, eq
+ ret
+endfunc plat_is_my_cpu_primary
diff --git a/plat/nxp/soc-ls1046a/include/ns_access.h b/plat/nxp/soc-ls1046a/include/ns_access.h
new file mode 100644
index 0000000..25c1964
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/include/ns_access.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2017-2018, 2020-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NS_ACCESS_H
+#define NS_ACCESS_H
+
+#include <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,
+};
+
+struct csu_ns_dev_st 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_S_SUP_RW},
+ {CSU_CSLX_GIC, CSU_ALL_RW},
+ {CSU_CSLX_PCIE1, CSU_ALL_RW},
+ {CSU_CSLX_OCRAM2, CSU_S_SUP_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 */
diff --git a/plat/nxp/soc-ls1046a/include/soc.h b/plat/nxp/soc-ls1046a/include/soc.h
new file mode 100644
index 0000000..67810c3
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/include/soc.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef SOC_H
+#define SOC_H
+
+/* Chassis specific defines - common across SoC's of a particular platform */
+#include <dcfg_lsch2.h>
+
+#include <soc_default_base_addr.h>
+#include <soc_default_helper_macros.h>
+
+/* DDR Regions Info */
+#define NUM_DRAM_REGIONS U(3)
+#define NXP_DRAM0_ADDR ULL(0x80000000)
+#define NXP_DRAM0_MAX_SIZE ULL(0x80000000) /* 2 GB */
+
+#define NXP_DRAM1_ADDR ULL(0x880000000)
+#define NXP_DRAM1_MAX_SIZE ULL(0x780000000) /* 30 GB */
+
+#define NXP_DRAM2_ADDR ULL(0x8800000000)
+#define NXP_DRAM2_MAX_SIZE ULL(0x7800000000) /* 480 GB */
+
+/*DRAM0 Size defined in platform_def.h */
+#define NXP_DRAM0_SIZE PLAT_DEF_DRAM0_SIZE
+
+/*
+ * SVR Definition (not include major and minor rev)
+ * A: without security
+ * AE: with security
+ */
+#define SVR_LS1026A 0x870709
+#define SVR_LS1026AE 0x870708
+#define SVR_LS1046A 0x870701
+#define SVR_LS1046AE 0x870700
+
+/* Number of cores in platform */
+/* Used by common code for array initialization */
+#define NUMBER_OF_CLUSTERS U(1)
+#define CORES_PER_CLUSTER U(4)
+#define PLATFORM_CORE_COUNT (NUMBER_OF_CLUSTERS * CORES_PER_CLUSTER)
+
+/*
+ * Required LS standard platform porting definitions
+ * for CCI-400
+ */
+#define NXP_CCI_CLUSTER0_SL_IFACE_IX 4
+
+
+/* Defines required for using XLAT tables from ARM common code */
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 40)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 40)
+
+/* Clock Divisors */
+#define NXP_PLATFORM_CLK_DIVIDER U(1)
+#define NXP_UART_CLK_DIVIDER U(2)
+
+/* set to 0 if the clusters are not symmetrical */
+#define SYMMETRICAL_CLUSTERS U(1)
+
+ /*
+ * set this switch to 1 if you need to keep the debug block
+ * clocked during system power-down
+ */
+#define DEBUG_ACTIVE 0
+
+ /*
+ * pwr mgmt features supported in the soc-specific code:
+ * value == 0x0 the soc code does not support this feature
+ * value != 0x0 the soc code supports this feature
+ */
+#define SOC_CORE_RELEASE 0x1
+#define SOC_CORE_RESTART 0x1
+#define SOC_CORE_OFF 0x1
+#define SOC_CORE_STANDBY 0x1
+#define SOC_CORE_PWR_DWN 0x1
+#define SOC_CLUSTER_STANDBY 0x1
+#define SOC_CLUSTER_PWR_DWN 0x1
+#define SOC_SYSTEM_STANDBY 0x1
+#define SOC_SYSTEM_PWR_DWN 0x1
+#define SOC_SYSTEM_OFF 0x1
+#define SOC_SYSTEM_RESET 0x1
+
+/* Start: Macros used by lib/psci files */
+#define SYSTEM_PWR_DOMAINS 1
+#define PLAT_NUM_PWR_DOMAINS (PLATFORM_CORE_COUNT + \
+ NUMBER_OF_CLUSTERS + \
+ SYSTEM_PWR_DOMAINS)
+
+/* Power state coordination occurs at the system level */
+#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2
+
+/* define retention state */
+#define PLAT_MAX_RET_STATE (PSCI_LOCAL_STATE_RUN + 1)
+
+/* define power-down state */
+#define PLAT_MAX_OFF_STATE (PLAT_MAX_RET_STATE + 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.
+ *
+ * CACHE_WRITEBACK_GRANULE is defined in soc.def
+ */
+
+ /* One cache line needed for bakery locks on ARM platforms */
+#define PLAT_PERCPU_BAKERY_LOCK_SIZE (1 * CACHE_WRITEBACK_GRANULE)
+
+#ifndef __ASSEMBLER__
+/* CCI slave interfaces */
+static const int cci_map[] = {
+ NXP_CCI_CLUSTER0_SL_IFACE_IX,
+};
+
+void soc_init_lowlevel(void);
+void soc_init_percpu(void);
+void _soc_set_start_addr(unsigned long addr);
+#endif
+
+#endif /* SOC_H */
diff --git a/plat/nxp/soc-ls1046a/ls1046afrwy/ddr_init.c b/plat/nxp/soc-ls1046a/ls1046afrwy/ddr_init.c
new file mode 100644
index 0000000..3d561c7
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/ls1046afrwy/ddr_init.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <ddr.h>
+#include <lib/utils.h>
+
+#include <errata.h>
+#include <platform_def.h>
+
+#ifdef CONFIG_STATIC_DDR
+const struct ddr_cfg_regs static_1600 = {
+ .cs[0].config = U(0x80010412),
+ .cs[0].bnds = U(0x7F),
+ .sdram_cfg[0] = U(0xE50C0008),
+ .sdram_cfg[1] = U(0x00401010),
+ .sdram_cfg[2] = U(0x1),
+ .timing_cfg[0] = U(0xFA550018),
+ .timing_cfg[1] = U(0xBAB40C52),
+ .timing_cfg[2] = U(0x0048C11C),
+ .timing_cfg[3] = U(0x01111000),
+ .timing_cfg[4] = U(0x00000002),
+ .timing_cfg[5] = U(0x03401400),
+ .timing_cfg[6] = U(0x0),
+ .timing_cfg[7] = U(0x23300000),
+ .timing_cfg[8] = U(0x02116600),
+ .timing_cfg[9] = U(0x0),
+ .dq_map[0] = U(0x0),
+ .dq_map[1] = U(0x0),
+ .dq_map[2] = U(0x0),
+ .dq_map[3] = U(0x0),
+ .sdram_mode[0] = U(0x01010210),
+ .sdram_mode[1] = U(0x0),
+ .sdram_mode[8] = U(0x00000500),
+ .sdram_mode[9] = U(0x04000000),
+ .interval = U(0x18600618),
+ .zq_cntl = U(0x8A090705),
+ .ddr_sr_cntr = U(0x0),
+ .clk_cntl = U(0x2000000),
+ .cdr[0] = U(0x80040000),
+ .cdr[1] = U(0xC1),
+ .wrlvl_cntl[0] = U(0x86550607),
+ .wrlvl_cntl[1] = U(0x07070708),
+ .wrlvl_cntl[2] = U(0x0808088),
+};
+
+long long board_static_ddr(struct ddr_info *priv)
+{
+ memcpy(&priv->ddr_reg, &static_1600, sizeof(static_1600));
+
+ return 0x80000000ULL;
+}
+#else /* ifndef CONFIG_STATIC_DDR */
+static const struct rc_timing rcz[] = {
+ {U(1600), U(8), U(7)},
+ {U(2100), U(8), U(7)},
+ {}
+};
+
+static const struct board_timing ram[] = {
+ {U(0x1f), rcz, U(0x01010101), U(0x01010101)},
+};
+
+int ddr_board_options(struct ddr_info *priv)
+{
+ int ret;
+ struct memctl_opt *popts = &priv->opt;
+
+ ret = cal_board_params(priv, ram, ARRAY_SIZE(ram));
+ if (ret != 0) {
+ return ret;
+ }
+
+ popts->bstopre = 0;
+ popts->half_strength_drive_en = 1;
+ popts->cpo_sample = U(0x46);
+ popts->ddr_cdr1 = DDR_CDR1_DHC_EN | DDR_CDR1_ODT(DDR_CDR_ODT_50ohm);
+ popts->ddr_cdr2 = DDR_CDR2_ODT(DDR_CDR_ODT_50ohm) |
+ DDR_CDR2_VREF_TRAIN_EN;
+ popts->output_driver_impedance = 1;
+
+ return 0;
+}
+
+/* DDR model number: MT40A512M16JY-083E:B */
+struct dimm_params ddr_raw_timing = {
+ .n_ranks = U(1),
+ .rank_density = ULL(4294967296),
+ .capacity = ULL(4294967296),
+ .primary_sdram_width = U(64),
+ .ec_sdram_width = U(8),
+ .rdimm = U(0),
+ .mirrored_dimm = U(0),
+ .n_row_addr = U(16),
+ .n_col_addr = U(10),
+ .bank_group_bits = U(1),
+ .edc_config = U(2),
+ .burst_lengths_bitmask = U(0x0c),
+ .tckmin_x_ps = 750,
+ .tckmax_ps = 1900,
+ .caslat_x = U(0x0001FFE00),
+ .taa_ps = 13500,
+ .trcd_ps = 13500,
+ .trp_ps = 13500,
+ .tras_ps = 33000,
+ .trc_ps = 46500,
+ .twr_ps = 15000,
+ .trfc1_ps = 350000,
+ .trfc2_ps = 260000,
+ .trfc4_ps = 160000,
+ .tfaw_ps = 30000,
+ .trrds_ps = 5300,
+ .trrdl_ps = 6400,
+ .tccdl_ps = 5355,
+ .refresh_rate_ps = U(7800000),
+ .dq_mapping[0] = U(0x0),
+ .dq_mapping[1] = U(0x0),
+ .dq_mapping[2] = U(0x0),
+ .dq_mapping[3] = U(0x0),
+ .dq_mapping[4] = U(0x0),
+ .dq_mapping_ors = U(0),
+ .rc = U(0x1f),
+};
+
+int ddr_get_ddr_params(struct dimm_params *pdimm, struct ddr_conf *conf)
+{
+ static const char dimm_model[] = "Fixed DDR on board";
+
+ conf->dimm_in_use[0] = 1;
+ memcpy(pdimm, &ddr_raw_timing, sizeof(struct dimm_params));
+ memcpy(pdimm->mpart, dimm_model, sizeof(dimm_model) - 1);
+
+ return 1;
+}
+#endif /* ifdef CONFIG_STATIC_DDR */
+
+long long init_ddr(void)
+{
+ int spd_addr[] = {NXP_SPD_EEPROM0};
+ struct ddr_info info;
+ struct sysinfo sys;
+ long long dram_size;
+
+ zeromem(&sys, sizeof(sys));
+ if (get_clocks(&sys)) {
+ ERROR("System clocks are not set\n");
+ assert(0);
+ }
+ debug("platform clock %lu\n", sys.freq_platform);
+ debug("DDR PLL1 %lu\n", sys.freq_ddr_pll0);
+ debug("DDR PLL2 %lu\n", sys.freq_ddr_pll1);
+
+ zeromem(&info, sizeof(struct ddr_info));
+ info.num_ctlrs = 1;
+ info.dimm_on_ctlr = 1;
+ info.clk = get_ddr_freq(&sys, 0);
+ info.spd_addr = spd_addr;
+ info.ddr[0] = (void *)NXP_DDR_ADDR;
+
+ dram_size = dram_init(&info);
+ if (dram_size < 0) {
+ ERROR("DDR init failed.\n");
+ }
+
+#ifdef ERRATA_SOC_A008850
+ erratum_a008850_post();
+#endif
+
+ return dram_size;
+}
diff --git a/plat/nxp/soc-ls1046a/ls1046afrwy/plat_def.h b/plat/nxp/soc-ls1046a/ls1046afrwy/plat_def.h
new file mode 100644
index 0000000..5134a00
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/ls1046afrwy/plat_def.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_DEF_H
+#define PLAT_DEF_H
+
+#include <arch.h>
+/*
+ * Required without TBBR.
+ * To include the defines for DDR PHY Images.
+ */
+#include <tbbr_img_def.h>
+
+#include "policy.h"
+#include <soc.h>
+
+#define NXP_SPD_EEPROM0 0x51
+
+#define NXP_SYSCLK_FREQ 100000000
+#define NXP_DDRCLK_FREQ 100000000
+
+/* UART related definition */
+#define NXP_CONSOLE_ADDR NXP_UART_ADDR
+#define NXP_CONSOLE_BAUDRATE 115200
+
+/* Size of cacheable stacks */
+#if defined(IMAGE_BL2)
+#if defined(TRUSTED_BOARD_BOOT)
+#define PLATFORM_STACK_SIZE 0x2000
+#else
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+#elif defined(IMAGE_BL31)
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+
+/* SD block buffer */
+#define NXP_SD_BLOCK_BUF_SIZE (0x8000)
+#define NXP_SD_BLOCK_BUF_ADDR ULL(0x80000000)
+
+#define BL2_LIMIT (NXP_OCRAM_ADDR + NXP_OCRAM_SIZE)
+
+/* IO defines as needed by IO driver framework */
+#define MAX_IO_DEVICES U(3)
+#define MAX_IO_BLOCK_DEVICES U(1)
+#define MAX_IO_HANDLES U(4)
+
+/*
+ * FIP image defines - Offset at which FIP Image would be present
+ * Image would include Bl31 , Bl33 and Bl32 (optional)
+ */
+#ifdef POLICY_FUSE_PROVISION
+#define MAX_FIP_DEVICES U(2)
+#endif
+
+#ifndef MAX_FIP_DEVICES
+#define MAX_FIP_DEVICES U(1)
+#endif
+
+/*
+ * ID of the secure physical generic timer interrupt used by the BL32.
+ */
+#define BL32_IRQ_SEC_PHY_TIMER 29
+
+/*
+ * 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_LS_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(BL32_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL)
+
+#define PLAT_LS_G0_IRQ_PROPS(grp)
+
+#endif /* PLAT_DEF_H */
diff --git a/plat/nxp/soc-ls1046a/ls1046afrwy/platform.c b/plat/nxp/soc-ls1046a/ls1046afrwy/platform.c
new file mode 100644
index 0000000..cef920f
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/ls1046afrwy/platform.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_common.h>
+
+#pragma weak board_enable_povdd
+#pragma weak board_disable_povdd
+
+bool board_enable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool board_disable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
diff --git a/plat/nxp/soc-ls1046a/ls1046afrwy/platform.mk b/plat/nxp/soc-ls1046a/ls1046afrwy/platform.mk
new file mode 100644
index 0000000..1f7fad6
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/ls1046afrwy/platform.mk
@@ -0,0 +1,39 @@
+#
+# Copyright 2018-2022 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# board-specific build parameters
+
+BOOT_MODE ?= qspi
+BOARD := ls1046afrwy
+POVDD_ENABLE := no
+
+# DDR Compilation Configs
+CONFIG_STATIC_DDR := 0
+CONFIG_DDR_NODIMM := 1
+DDRC_NUM_DIMM := 0
+NUM_OF_DDRC := 1
+DDRC_NUM_CS := 1
+DDR_ECC_EN := yes
+
+# On-Board Flash Details
+QSPI_FLASH_SZ := 0x20000000
+NOR_FLASH_SZ := 0x20000000
+
+# Platform specific features.
+WARM_BOOT := no
+
+# Adding Platform files build files
+BL2_SOURCES += ${BOARD_PATH}/ddr_init.c\
+ ${BOARD_PATH}/platform.c
+
+SUPPORTED_BOOT_MODE := qspi \
+ sd
+
+# Adding platform board build info
+include plat/nxp/common/plat_make_helper/plat_common_def.mk
+
+# Adding SoC build info
+include plat/nxp/soc-ls1046a/soc.mk
diff --git a/plat/nxp/soc-ls1046a/ls1046afrwy/platform_def.h b/plat/nxp/soc-ls1046a/ls1046afrwy/platform_def.h
new file mode 100644
index 0000000..7f98bb1
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/ls1046afrwy/platform_def.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <plat_def.h>
+#include <plat_default_def.h>
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/nxp/soc-ls1046a/ls1046afrwy/policy.h b/plat/nxp/soc-ls1046a/ls1046afrwy/policy.h
new file mode 100644
index 0000000..c6c325f
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/ls1046afrwy/policy.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef POLICY_H
+#define POLICY_H
+
+/* Set this to 0x0 to leave the default SMMU page size in sACR
+ * Set this to 0x1 to change the SMMU page size to 64K
+ */
+#define POLICY_SMMU_PAGESZ_64K 0x1
+
+#endif /* POLICY_H */
diff --git a/plat/nxp/soc-ls1046a/ls1046aqds/ddr_init.c b/plat/nxp/soc-ls1046a/ls1046aqds/ddr_init.c
new file mode 100644
index 0000000..89c9c0a
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/ls1046aqds/ddr_init.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <common/debug.h>
+#include <ddr.h>
+#include <lib/utils.h>
+
+#include <errata.h>
+#include "platform_def.h"
+
+static const struct rc_timing rce[] = {
+ {U(1600), U(8), U(7)},
+ {U(1867), U(8), U(7)},
+ {U(2134), U(8), U(9)},
+ {}
+};
+
+static const struct board_timing udimm[] = {
+ {U(0x04), rce, U(0x01020304), U(0x06070805)},
+};
+
+int ddr_board_options(struct ddr_info *priv)
+{
+ int ret;
+ struct memctl_opt *popts = &priv->opt;
+
+ if (popts->rdimm) {
+ debug("RDIMM parameters not set.\n");
+ return -EINVAL;
+ }
+
+ ret = cal_board_params(priv, udimm, ARRAY_SIZE(udimm));
+ if (ret != 0) {
+ return ret;
+ }
+
+ popts->wrlvl_override = U(1);
+ popts->wrlvl_sample = U(0x0); /* 32 clocks */
+ popts->ddr_cdr1 = DDR_CDR1_DHC_EN |
+ DDR_CDR1_ODT(DDR_CDR_ODT_80ohm);
+ popts->ddr_cdr2 = DDR_CDR2_ODT(DDR_CDR_ODT_80ohm) |
+ DDR_CDR2_VREF_TRAIN_EN |
+ DDR_CDR2_VREF_RANGE_2;
+
+ /* optimize cpo for erratum A-009942 */
+ popts->cpo_sample = U(0x70);
+
+ return 0;
+}
+
+long long init_ddr(void)
+{
+ int spd_addr[] = { NXP_SPD_EEPROM0 };
+ struct ddr_info info;
+ struct sysinfo sys;
+ long long dram_size;
+
+ zeromem(&sys, sizeof(sys));
+ if (get_clocks(&sys)) {
+ ERROR("System clocks are not set\n");
+ assert(0);
+ }
+ debug("platform clock %lu\n", sys.freq_platform);
+ debug("DDR PLL1 %lu\n", sys.freq_ddr_pll0);
+ debug("DDR PLL2 %lu\n", sys.freq_ddr_pll1);
+
+ zeromem(&info, sizeof(struct ddr_info));
+ info.num_ctlrs = 1;
+ info.dimm_on_ctlr = 1;
+ info.clk = get_ddr_freq(&sys, 0);
+ info.spd_addr = spd_addr;
+ info.ddr[0] = (void *)NXP_DDR_ADDR;
+
+ dram_size = dram_init(&info);
+
+ if (dram_size < 0) {
+ ERROR("DDR init failed.\n");
+ }
+
+#ifdef ERRATA_SOC_A008850
+ erratum_a008850_post();
+#endif
+
+ return dram_size;
+}
diff --git a/plat/nxp/soc-ls1046a/ls1046aqds/plat_def.h b/plat/nxp/soc-ls1046a/ls1046aqds/plat_def.h
new file mode 100644
index 0000000..aa69a66
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/ls1046aqds/plat_def.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_DEF_H
+#define PLAT_DEF_H
+
+#include <arch.h>
+/* Required without TBBR.
+ * To include the defines for DDR PHY
+ * Images.
+ */
+#include <tbbr_img_def.h>
+
+#include <policy.h>
+#include <soc.h>
+
+#define NXP_SPD_EEPROM0 0x51
+
+#define NXP_SYSCLK_FREQ 100000000
+#define NXP_DDRCLK_FREQ 100000000
+
+/* UART related definition */
+#define NXP_CONSOLE_ADDR NXP_UART_ADDR
+#define NXP_CONSOLE_BAUDRATE 115200
+
+/* Size of cacheable stacks */
+#if defined(IMAGE_BL2)
+#if defined(TRUSTED_BOARD_BOOT)
+#define PLATFORM_STACK_SIZE 0x2000
+#else
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+#elif defined(IMAGE_BL31)
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+
+/* SD block buffer */
+#define NXP_SD_BLOCK_BUF_SIZE (0x00100000)
+#define NXP_SD_BLOCK_BUF_ADDR ULL(0x80000000)
+
+#define BL2_LIMIT (NXP_OCRAM_ADDR + NXP_OCRAM_SIZE)
+
+/* IO defines as needed by IO driver framework */
+#define MAX_IO_DEVICES U(3)
+#define MAX_IO_BLOCK_DEVICES U(1)
+#define MAX_IO_HANDLES U(4)
+
+/*
+ * FIP image defines - Offset at which FIP Image would be present
+ * Image would include Bl31 , Bl33 and Bl32 (optional)
+ */
+#ifdef POLICY_FUSE_PROVISION
+#define MAX_FIP_DEVICES U(2)
+#endif
+
+#ifndef MAX_FIP_DEVICES
+#define MAX_FIP_DEVICES U(1)
+#endif
+
+/*
+ * ID of the secure physical generic timer interrupt used by the BL32.
+ */
+#define BL32_IRQ_SEC_PHY_TIMER 29
+
+/*
+ * 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_LS_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(BL32_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL)
+
+#define PLAT_LS_G0_IRQ_PROPS(grp)
+
+#endif
diff --git a/plat/nxp/soc-ls1046a/ls1046aqds/platform.c b/plat/nxp/soc-ls1046a/ls1046aqds/platform.c
new file mode 100644
index 0000000..cef920f
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/ls1046aqds/platform.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_common.h>
+
+#pragma weak board_enable_povdd
+#pragma weak board_disable_povdd
+
+bool board_enable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool board_disable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
diff --git a/plat/nxp/soc-ls1046a/ls1046aqds/platform.mk b/plat/nxp/soc-ls1046a/ls1046aqds/platform.mk
new file mode 100644
index 0000000..9600b93
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/ls1046aqds/platform.mk
@@ -0,0 +1,39 @@
+#
+# Copyright 2018-2022 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# board-specific build parameters
+BOOT_MODE ?= qspi
+BOARD := ls1046aqds
+POVDD_ENABLE := no
+
+ # DDR Compilation Configs
+NUM_OF_DDRC := 1
+DDRC_NUM_DIMM := 1
+DDRC_NUM_CS := 4
+DDR_ECC_EN := yes
+CONFIG_STATIC_DDR := 0
+
+# On-Board Flash Details
+QSPI_FLASH_SZ := 0x20000000
+NOR_FLASH_SZ := 0x20000000
+
+# Platform specific features.
+WARM_BOOT := no
+
+# Adding Platform files build files
+BL2_SOURCES += ${BOARD_PATH}/ddr_init.c\
+ ${BOARD_PATH}/platform.c
+
+SUPPORTED_BOOT_MODE := qspi \
+ sd \
+ nor \
+ nand
+
+# Adding platform board build info
+include plat/nxp/common/plat_make_helper/plat_common_def.mk
+
+# Adding SoC build info
+include plat/nxp/soc-ls1046a/soc.mk
diff --git a/plat/nxp/soc-ls1046a/ls1046aqds/platform_def.h b/plat/nxp/soc-ls1046a/ls1046aqds/platform_def.h
new file mode 100644
index 0000000..7f98bb1
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/ls1046aqds/platform_def.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <plat_def.h>
+#include <plat_default_def.h>
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/nxp/soc-ls1046a/ls1046aqds/policy.h b/plat/nxp/soc-ls1046a/ls1046aqds/policy.h
new file mode 100644
index 0000000..c6c325f
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/ls1046aqds/policy.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef POLICY_H
+#define POLICY_H
+
+/* Set this to 0x0 to leave the default SMMU page size in sACR
+ * Set this to 0x1 to change the SMMU page size to 64K
+ */
+#define POLICY_SMMU_PAGESZ_64K 0x1
+
+#endif /* POLICY_H */
diff --git a/plat/nxp/soc-ls1046a/ls1046ardb/ddr_init.c b/plat/nxp/soc-ls1046a/ls1046ardb/ddr_init.c
new file mode 100644
index 0000000..b9940cf
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/ls1046ardb/ddr_init.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <ddr.h>
+#include <lib/utils.h>
+
+#include <errata.h>
+#include <platform_def.h>
+
+#ifdef CONFIG_STATIC_DDR
+const struct ddr_cfg_regs static_2100 = {
+ .cs[0].config = U(0x80040322),
+ .cs[0].bnds = U(0x1FF),
+ .cs[1].config = U(0x80000322),
+ .cs[1].bnds = U(0x1FF),
+ .sdram_cfg[0] = U(0xE5004000),
+ .sdram_cfg[1] = U(0x401151),
+ .timing_cfg[0] = U(0xD1770018),
+ .timing_cfg[1] = U(0xF2FC9245),
+ .timing_cfg[2] = U(0x594197),
+ .timing_cfg[3] = U(0x2101100),
+ .timing_cfg[4] = U(0x220002),
+ .timing_cfg[5] = U(0x5401400),
+ .timing_cfg[7] = U(0x26600000),
+ .timing_cfg[8] = U(0x5446A00),
+ .dq_map[0] = U(0x32C57554),
+ .dq_map[1] = U(0xD4BB0BD4),
+ .dq_map[2] = U(0x2EC2F554),
+ .dq_map[3] = U(0xD95D4001),
+ .sdram_mode[0] = U(0x3010631),
+ .sdram_mode[1] = U(0x100200),
+ .sdram_mode[9] = U(0x8400000),
+ .sdram_mode[8] = U(0x500),
+ .sdram_mode[2] = U(0x10631),
+ .sdram_mode[3] = U(0x100200),
+ .sdram_mode[10] = U(0x400),
+ .sdram_mode[11] = U(0x8400000),
+ .sdram_mode[4] = U(0x10631),
+ .sdram_mode[5] = U(0x100200),
+ .sdram_mode[12] = U(0x400),
+ .sdram_mode[13] = U(0x8400000),
+ .sdram_mode[6] = U(0x10631),
+ .sdram_mode[7] = U(0x100200),
+ .sdram_mode[14] = U(0x400),
+ .sdram_mode[15] = U(0x8400000),
+ .interval = U(0x1FFE07FF),
+ .zq_cntl = U(0x8A090705),
+ .clk_cntl = U(0x2000000),
+ .cdr[0] = U(0x80040000),
+ .cdr[1] = U(0xC1),
+ .wrlvl_cntl[0] = U(0x86750609),
+ .wrlvl_cntl[1] = U(0xA0B0C0D),
+ .wrlvl_cntl[2] = U(0xF10110E),
+};
+
+const struct ddr_cfg_regs static_1800 = {
+ .cs[0].config = U(0x80040322),
+ .cs[0].bnds = U(0x1FF),
+ .cs[1].config = U(0x80000322),
+ .cs[1].bnds = U(0x1FF),
+ .sdram_cfg[0] = U(0xE5004000),
+ .sdram_cfg[1] = U(0x401151),
+ .timing_cfg[0] = U(0x91660018),
+ .timing_cfg[1] = U(0xDDD82045),
+ .timing_cfg[2] = U(0x512153),
+ .timing_cfg[3] = U(0x10E1100),
+ .timing_cfg[4] = U(0x220002),
+ .timing_cfg[5] = U(0x4401400),
+ .timing_cfg[7] = U(0x14400000),
+ .timing_cfg[8] = U(0x3335900),
+ .dq_map[0] = U(0x32C57554),
+ .dq_map[1] = U(0xD4BB0BD4),
+ .dq_map[2] = U(0x2EC2F554),
+ .dq_map[3] = U(0xD95D4001),
+ .sdram_mode[0] = U(0x3010421),
+ .sdram_mode[1] = U(0x80200),
+ .sdram_mode[9] = U(0x4400000),
+ .sdram_mode[8] = U(0x500),
+ .sdram_mode[2] = U(0x10421),
+ .sdram_mode[3] = U(0x80200),
+ .sdram_mode[10] = U(0x400),
+ .sdram_mode[11] = U(0x4400000),
+ .sdram_mode[4] = U(0x10421),
+ .sdram_mode[5] = U(0x80200),
+ .sdram_mode[12] = U(0x400),
+ .sdram_mode[13] = U(0x4400000),
+ .sdram_mode[6] = U(0x10421),
+ .sdram_mode[7] = U(0x80200),
+ .sdram_mode[14] = U(0x400),
+ .sdram_mode[15] = U(0x4400000),
+ .interval = U(0x1B6C06DB),
+ .zq_cntl = U(0x8A090705),
+ .clk_cntl = U(0x2000000),
+ .cdr[0] = U(0x80040000),
+ .cdr[1] = U(0xC1),
+ .wrlvl_cntl[0] = U(0x86750607),
+ .wrlvl_cntl[1] = U(0x8090A0B),
+ .wrlvl_cntl[2] = U(0xD0E0F0C),
+};
+
+const struct ddr_cfg_regs static_1600 = {
+ .cs[0].config = U(0x80040322),
+ .cs[0].bnds = U(0x1FF),
+ .cs[1].config = U(0x80000322),
+ .cs[1].bnds = U(0x1FF),
+ .sdram_cfg[0] = U(0xE5004000),
+ .sdram_cfg[1] = U(0x401151),
+ .sdram_cfg[2] = U(0x0),
+ .timing_cfg[0] = U(0x91550018),
+ .timing_cfg[1] = U(0xBAB48E44),
+ .timing_cfg[2] = U(0x490111),
+ .timing_cfg[3] = U(0x10C1000),
+ .timing_cfg[4] = U(0x220002),
+ .timing_cfg[5] = U(0x3401400),
+ .timing_cfg[6] = U(0x0),
+ .timing_cfg[7] = U(0x13300000),
+ .timing_cfg[8] = U(0x1224800),
+ .timing_cfg[9] = U(0x0),
+ .dq_map[0] = U(0x32C57554),
+ .dq_map[1] = U(0xD4BB0BD4),
+ .dq_map[2] = U(0x2EC2F554),
+ .dq_map[3] = U(0xD95D4001),
+ .sdram_mode[0] = U(0x3010211),
+ .sdram_mode[1] = U(0x0),
+ .sdram_mode[9] = U(0x400000),
+ .sdram_mode[8] = U(0x500),
+ .sdram_mode[2] = U(0x10211),
+ .sdram_mode[3] = U(0x0),
+ .sdram_mode[10] = U(0x400),
+ .sdram_mode[11] = U(0x400000),
+ .sdram_mode[4] = U(0x10211),
+ .sdram_mode[5] = U(0x0),
+ .sdram_mode[12] = U(0x400),
+ .sdram_mode[13] = U(0x400000),
+ .sdram_mode[6] = U(0x10211),
+ .sdram_mode[7] = U(0x0),
+ .sdram_mode[14] = U(0x400),
+ .sdram_mode[15] = U(0x400000),
+ .interval = U(0x18600618),
+ .zq_cntl = U(0x8A090705),
+ .ddr_sr_cntr = U(0x0),
+ .clk_cntl = U(0x2000000),
+ .cdr[0] = U(0x80040000),
+ .cdr[1] = U(0xC1),
+ .wrlvl_cntl[0] = U(0x86750607),
+ .wrlvl_cntl[1] = U(0x8090A0B),
+ .wrlvl_cntl[2] = U(0xD0E0F0C),
+};
+
+struct static_table {
+ unsigned long rate;
+ const struct ddr_cfg_regs *regs;
+};
+
+const struct static_table table[] = {
+ {1600, &static_1600},
+ {1800, &static_1800},
+ {2100, &static_2100},
+};
+
+long long board_static_ddr(struct ddr_info *priv)
+{
+ const unsigned long clk = priv->clk / 1000000;
+ long long size = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(table); i++) {
+ if (table[i].rate >= clk) {
+ break;
+ }
+ }
+ if (i < ARRAY_SIZE(table)) {
+ VERBOSE("Found static setting for rate %ld\n", table[i].rate);
+ memcpy(&priv->ddr_reg, table[i].regs,
+ sizeof(struct ddr_cfg_regs));
+ size = 0x200000000UL;
+ } else {
+ ERROR("Not static settings for rate %ld\n", clk);
+ }
+
+ return size;
+}
+#else /* ifndef CONFIG_STATIC_DDR */
+static const struct rc_timing rce[] = {
+ {U(1600), U(8), U(7)},
+ {U(1867), U(8), U(7)},
+ {U(2134), U(8), U(9)},
+ {}
+};
+
+static const struct board_timing udimm[] = {
+ {U(0x04), rce, U(0x01020304), U(0x06070805)},
+ {U(0x1f), rce, U(0x01020304), U(0x06070805)},
+};
+
+int ddr_board_options(struct ddr_info *priv)
+{
+ int ret;
+ struct memctl_opt *popts = &priv->opt;
+
+ if (popts->rdimm) {
+ debug("RDIMM parameters not set.\n");
+ return -EINVAL;
+ }
+
+ ret = cal_board_params(priv, udimm, ARRAY_SIZE(udimm));
+ if (ret != 0) {
+ return ret;
+ }
+
+ popts->wrlvl_override = U(1);
+ popts->wrlvl_sample = U(0x0); /* 32 clocks */
+ popts->cpo_sample = U(0x61);
+ popts->ddr_cdr1 = DDR_CDR1_DHC_EN |
+ DDR_CDR1_ODT(DDR_CDR_ODT_80ohm);
+ popts->ddr_cdr2 = DDR_CDR2_ODT(DDR_CDR_ODT_80ohm) |
+ DDR_CDR2_VREF_TRAIN_EN |
+ DDR_CDR2_VREF_RANGE_2;
+ popts->bstopre = U(0);
+
+ return 0;
+}
+#endif /* ifdef CONFIG_STATIC_DDR */
+
+long long init_ddr(void)
+{
+ int spd_addr[] = {NXP_SPD_EEPROM0};
+ struct ddr_info info;
+ struct sysinfo sys;
+ long long dram_size;
+
+ zeromem(&sys, sizeof(sys));
+ if (get_clocks(&sys)) {
+ ERROR("System clocks are not set\n");
+ assert(0);
+ }
+ debug("platform clock %lu\n", sys.freq_platform);
+ debug("DDR PLL1 %lu\n", sys.freq_ddr_pll0);
+ debug("DDR PLL2 %lu\n", sys.freq_ddr_pll1);
+
+ zeromem(&info, sizeof(struct ddr_info));
+ info.num_ctlrs = U(1);
+ info.dimm_on_ctlr = U(1);
+ info.clk = get_ddr_freq(&sys, 0);
+ info.spd_addr = spd_addr;
+ info.ddr[0] = (void *)NXP_DDR_ADDR;
+
+ dram_size = dram_init(&info);
+
+ if (dram_size < 0) {
+ ERROR("DDR init failed.\n");
+ }
+
+#ifdef ERRATA_SOC_A008850
+ erratum_a008850_post();
+#endif
+
+ return dram_size;
+}
diff --git a/plat/nxp/soc-ls1046a/ls1046ardb/plat_def.h b/plat/nxp/soc-ls1046a/ls1046ardb/plat_def.h
new file mode 100644
index 0000000..b5e66ae
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/ls1046ardb/plat_def.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_DEF_H
+#define PLAT_DEF_H
+
+#include <arch.h>
+/*
+ * Required without TBBR.
+ * To include the defines for DDR PHY Images.
+ */
+#include <tbbr_img_def.h>
+
+#include "policy.h"
+#include <soc.h>
+
+#define NXP_SPD_EEPROM0 0x51
+
+#define NXP_SYSCLK_FREQ 100000000
+#define NXP_DDRCLK_FREQ 100000000
+
+/* UART related definition */
+#define NXP_CONSOLE_ADDR NXP_UART_ADDR
+#define NXP_CONSOLE_BAUDRATE 115200
+
+/* Size of cacheable stacks */
+#if defined(IMAGE_BL2)
+#if defined(TRUSTED_BOARD_BOOT)
+#define PLATFORM_STACK_SIZE 0x2000
+#else
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+#elif defined(IMAGE_BL31)
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+
+/* SD block buffer */
+#define NXP_SD_BLOCK_BUF_SIZE (0x00100000)
+#define NXP_SD_BLOCK_BUF_ADDR ULL(0x80000000)
+
+#define BL2_LIMIT (NXP_OCRAM_ADDR + NXP_OCRAM_SIZE)
+
+/* IO defines as needed by IO driver framework */
+#define MAX_IO_DEVICES U(3)
+#define MAX_IO_BLOCK_DEVICES U(1)
+#define MAX_IO_HANDLES U(4)
+
+/*
+ * FIP image defines - Offset at which FIP Image would be present
+ * Image would include Bl31 , Bl33 and Bl32 (optional)
+ */
+#ifdef POLICY_FUSE_PROVISION
+#define MAX_FIP_DEVICES U(2)
+#endif
+
+#ifndef MAX_FIP_DEVICES
+#define MAX_FIP_DEVICES U(1)
+#endif
+
+/*
+ * ID of the secure physical generic timer interrupt used by the BL32.
+ */
+#define BL32_IRQ_SEC_PHY_TIMER 29
+
+/*
+ * 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_LS_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(BL32_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL)
+
+#define PLAT_LS_G0_IRQ_PROPS(grp)
+
+#endif /* PLAT_DEF_H */
diff --git a/plat/nxp/soc-ls1046a/ls1046ardb/platform.c b/plat/nxp/soc-ls1046a/ls1046ardb/platform.c
new file mode 100644
index 0000000..cef920f
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/ls1046ardb/platform.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_common.h>
+
+#pragma weak board_enable_povdd
+#pragma weak board_disable_povdd
+
+bool board_enable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool board_disable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
diff --git a/plat/nxp/soc-ls1046a/ls1046ardb/platform.mk b/plat/nxp/soc-ls1046a/ls1046ardb/platform.mk
new file mode 100644
index 0000000..32e6db5
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/ls1046ardb/platform.mk
@@ -0,0 +1,38 @@
+#
+# Copyright 2018-2022 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# board-specific build parameters
+BOOT_MODE ?= qspi
+BOARD := ls1046ardb
+POVDD_ENABLE := no
+
+# DDR Compilation Configs
+NUM_OF_DDRC := 1
+DDRC_NUM_DIMM := 1
+DDRC_NUM_CS := 4
+DDR_ECC_EN := yes
+CONFIG_STATIC_DDR := 0
+
+# On-Board Flash Details
+QSPI_FLASH_SZ := 0x20000000
+NOR_FLASH_SZ := 0x20000000
+
+# Platform specific features.
+WARM_BOOT := no
+
+# Adding Platform files build files
+BL2_SOURCES += ${BOARD_PATH}/ddr_init.c\
+ ${BOARD_PATH}/platform.c
+
+SUPPORTED_BOOT_MODE := qspi \
+ sd \
+ emmc
+
+# Adding platform board build info
+include plat/nxp/common/plat_make_helper/plat_common_def.mk
+
+# Adding SoC build info
+include plat/nxp/soc-ls1046a/soc.mk
diff --git a/plat/nxp/soc-ls1046a/ls1046ardb/platform_def.h b/plat/nxp/soc-ls1046a/ls1046ardb/platform_def.h
new file mode 100644
index 0000000..7f98bb1
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/ls1046ardb/platform_def.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <plat_def.h>
+#include <plat_default_def.h>
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/nxp/soc-ls1046a/ls1046ardb/policy.h b/plat/nxp/soc-ls1046a/ls1046ardb/policy.h
new file mode 100644
index 0000000..c6c325f
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/ls1046ardb/policy.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef POLICY_H
+#define POLICY_H
+
+/* Set this to 0x0 to leave the default SMMU page size in sACR
+ * Set this to 0x1 to change the SMMU page size to 64K
+ */
+#define POLICY_SMMU_PAGESZ_64K 0x1
+
+#endif /* POLICY_H */
diff --git a/plat/nxp/soc-ls1046a/soc.c b/plat/nxp/soc-ls1046a/soc.c
new file mode 100644
index 0000000..d17e672
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/soc.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <caam.h>
+#include <cassert.h>
+#include <cci.h>
+#include <common/debug.h>
+#include <dcfg.h>
+#ifdef I2C_INIT
+#include <i2c.h>
+#endif
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <ls_interconnect.h>
+#ifdef POLICY_FUSE_PROVISION
+#include <nxp_gpio.h>
+#endif
+#if TRUSTED_BOARD_BOOT
+#include <nxp_smmu.h>
+#endif
+#include <nxp_timer.h>
+#include <plat_console.h>
+#include <plat_gic.h>
+#include <plat_tzc400.h>
+#include <scfg.h>
+#if defined(NXP_SFP_ENABLED)
+#include <sfp.h>
+#endif
+
+#include <errata.h>
+#include <ns_access.h>
+#ifdef CONFIG_OCRAM_ECC_EN
+#include <ocram.h>
+#endif
+#include <plat_common.h>
+#include <platform_def.h>
+#include <soc.h>
+
+static dcfg_init_info_t dcfg_init_data = {
+ .g_nxp_dcfg_addr = NXP_DCFG_ADDR,
+ .nxp_sysclk_freq = NXP_SYSCLK_FREQ,
+ .nxp_ddrclk_freq = NXP_DDRCLK_FREQ,
+ .nxp_plat_clk_divider = NXP_PLATFORM_CLK_DIVIDER,
+};
+
+/* Function to return the SoC SYS CLK */
+static unsigned int get_sys_clk(void)
+{
+ return NXP_SYSCLK_FREQ;
+}
+
+/*
+ * Function returns the base counter frequency
+ * after reading the first entry at CNTFID0 (0x20 offset).
+ *
+ * Function is used by:
+ * 1. ARM common code for PSCI management.
+ * 2. ARM Generic Timer init.
+ *
+ */
+unsigned int plat_get_syscnt_freq2(void)
+{
+ unsigned int counter_base_frequency;
+
+ counter_base_frequency = get_sys_clk() / 4;
+
+ return counter_base_frequency;
+}
+
+#ifdef IMAGE_BL2
+/* Functions for BL2 */
+
+static struct soc_type soc_list[] = {
+ SOC_ENTRY(LS1046A, LS1046A, 1, 4),
+ SOC_ENTRY(LS1046AE, LS1046AE, 1, 4),
+ SOC_ENTRY(LS1026A, LS1026A, 1, 2),
+ SOC_ENTRY(LS1026AE, LS1026AE, 1, 2),
+};
+
+#ifdef POLICY_FUSE_PROVISION
+static gpio_init_info_t gpio_init_data = {
+ .gpio1_base_addr = NXP_GPIO1_ADDR,
+ .gpio2_base_addr = NXP_GPIO2_ADDR,
+ .gpio3_base_addr = NXP_GPIO3_ADDR,
+ .gpio4_base_addr = NXP_GPIO4_ADDR,
+};
+#endif
+
+/*
+ * Function to set the base counter frequency at
+ * the first entry of the Frequency Mode Table,
+ * at CNTFID0 (0x20 offset).
+ *
+ * Set the value of the pirmary core register cntfrq_el0.
+ */
+static void set_base_freq_CNTFID0(void)
+{
+ /*
+ * Below register specifies the base frequency of the system counter.
+ * As per NXP Board Manuals:
+ * The system counter always works with SYS_REF_CLK/4 frequency clock.
+ */
+ unsigned int counter_base_frequency = get_sys_clk() / 4;
+
+ /* Setting the frequency in the Frequency modes table.
+ *
+ * Note: The value for ls1046ardb board at this offset
+ * is not RW as stated. This offset have the
+ * fixed value of 100000400 Hz.
+ *
+ * The below code line has no effect.
+ * Keeping it for other platforms where it has effect.
+ */
+ mmio_write_32(NXP_TIMER_ADDR + CNTFID_OFF, counter_base_frequency);
+
+ write_cntfrq_el0(counter_base_frequency);
+}
+
+void soc_preload_setup(void)
+{
+
+}
+
+/*
+ * This function implements soc specific erratas
+ * This is called before DDR is initialized or MMU is enabled
+ */
+void soc_early_init(void)
+{
+ uint8_t num_clusters, cores_per_cluster;
+ dram_regions_info_t *dram_regions_info = get_dram_regions_info();
+
+#ifdef CONFIG_OCRAM_ECC_EN
+ ocram_init(NXP_OCRAM_ADDR, NXP_OCRAM_SIZE);
+#endif
+ dcfg_init(&dcfg_init_data);
+#ifdef POLICY_FUSE_PROVISION
+ gpio_init(&gpio_init_data);
+ sec_init(NXP_CAAM_ADDR);
+#endif
+#if LOG_LEVEL > 0
+ /* Initialize the console to provide early debug support */
+
+ plat_console_init(NXP_CONSOLE_ADDR,
+ NXP_UART_CLK_DIVIDER, NXP_CONSOLE_BAUDRATE);
+#endif
+ set_base_freq_CNTFID0();
+
+ /* Enable snooping on SEC read and write transactions */
+ scfg_setbits32((void *)(NXP_SCFG_ADDR + SCFG_SNPCNFGCR_OFFSET),
+ SCFG_SNPCNFGCR_SECRDSNP | SCFG_SNPCNFGCR_SECWRSNP);
+
+ /*
+ * Initialize Interconnect for this cluster during cold boot.
+ * No need for locks as no other CPU is active.
+ */
+ cci_init(NXP_CCI_ADDR, cci_map, ARRAY_SIZE(cci_map));
+
+ /*
+ * Enable Interconnect coherency for the primary CPU's cluster.
+ */
+ get_cluster_info(soc_list, ARRAY_SIZE(soc_list), &num_clusters, &cores_per_cluster);
+ plat_ls_interconnect_enter_coherency(num_clusters);
+
+#if TRUSTED_BOARD_BOOT
+ uint32_t mode;
+
+ sfp_init(NXP_SFP_ADDR);
+ /*
+ * For secure boot disable SMMU.
+ * Later when platform security policy comes in picture,
+ * this might get modified based on the policy
+ */
+ if (check_boot_mode_secure(&mode) == true) {
+ bypass_smmu(NXP_SMMU_ADDR);
+ }
+
+ /*
+ * For Mbedtls currently crypto is not supported via CAAM
+ * enable it when that support is there. In tbbr.mk
+ * the CAAM_INTEG is set as 0.
+ */
+#ifndef MBEDTLS_X509
+ /* Initialize the crypto accelerator if enabled */
+ if (is_sec_enabled() == false) {
+ INFO("SEC is disabled.\n");
+ } else {
+ sec_init(NXP_CAAM_ADDR);
+ }
+#endif
+#elif defined(POLICY_FUSE_PROVISION)
+ gpio_init(&gpio_init_data);
+ sfp_init(NXP_SFP_ADDR);
+ sec_init(NXP_CAAM_ADDR);
+#endif
+
+ soc_errata();
+
+ /* Initialize system level generic timer for Layerscape Socs. */
+ delay_timer_init(NXP_TIMER_ADDR);
+
+#ifdef DDR_INIT
+ i2c_init(NXP_I2C_ADDR);
+ dram_regions_info->total_dram_size = init_ddr();
+#endif
+}
+
+void soc_bl2_prepare_exit(void)
+{
+#if defined(NXP_SFP_ENABLED) && defined(DISABLE_FUSE_WRITE)
+ set_sfp_wr_disable();
+#endif
+}
+
+/* This function returns the boot device based on RCW_SRC */
+enum boot_device get_boot_dev(void)
+{
+ enum boot_device src = BOOT_DEVICE_NONE;
+ uint32_t porsr1;
+ uint32_t rcw_src, val;
+
+ porsr1 = read_reg_porsr1();
+
+ rcw_src = (porsr1 & PORSR1_RCW_MASK) >> PORSR1_RCW_SHIFT;
+
+ val = rcw_src & RCW_SRC_NAND_MASK;
+
+ if (val == RCW_SRC_NAND_VAL) {
+ val = rcw_src & NAND_RESERVED_MASK;
+ if ((val != NAND_RESERVED_1) && (val != NAND_RESERVED_2)) {
+ src = BOOT_DEVICE_IFC_NAND;
+ INFO("RCW BOOT SRC is IFC NAND\n");
+ }
+ } else {
+ /* RCW SRC NOR */
+ val = rcw_src & RCW_SRC_NOR_MASK;
+ if (val == NOR_8B_VAL || val == NOR_16B_VAL) {
+ src = BOOT_DEVICE_IFC_NOR;
+ INFO("RCW BOOT SRC is IFC NOR\n");
+ } else {
+ switch (rcw_src) {
+ case QSPI_VAL1:
+ case QSPI_VAL2:
+ src = BOOT_DEVICE_QSPI;
+ INFO("RCW BOOT SRC is QSPI\n");
+ break;
+ case SD_VAL:
+ src = BOOT_DEVICE_EMMC;
+ INFO("RCW BOOT SRC is SD/EMMC\n");
+ break;
+ default:
+ src = BOOT_DEVICE_NONE;
+ }
+ }
+ }
+
+ return src;
+}
+
+/* This function sets up access permissions on memory regions */
+void soc_mem_access(void)
+{
+ dram_regions_info_t *info_dram_regions = get_dram_regions_info();
+ struct tzc400_reg tzc400_reg_list[MAX_NUM_TZC_REGION];
+ unsigned int dram_idx, index = 0U;
+
+ for (dram_idx = 0U; dram_idx < info_dram_regions->num_dram_regions;
+ dram_idx++) {
+ if (info_dram_regions->region[dram_idx].size == 0) {
+ ERROR("DDR init failure, or");
+ ERROR("DRAM regions not populated correctly.\n");
+ break;
+ }
+
+ index = populate_tzc400_reg_list(tzc400_reg_list,
+ dram_idx, index,
+ info_dram_regions->region[dram_idx].addr,
+ info_dram_regions->region[dram_idx].size,
+ NXP_SECURE_DRAM_SIZE, NXP_SP_SHRD_DRAM_SIZE);
+ }
+
+ mem_access_setup(NXP_TZC_ADDR, index, tzc400_reg_list);
+}
+
+#else /* IMAGE_BL2 */
+/* Functions for BL31 */
+
+const unsigned char _power_domain_tree_desc[] = {1, 1, 4};
+
+CASSERT(NUMBER_OF_CLUSTERS && NUMBER_OF_CLUSTERS <= 256,
+ assert_invalid_ls1046_cluster_count);
+
+/* This function returns the SoC topology */
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ return _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 CORES_PER_CLUSTER;
+}
+
+void soc_early_platform_setup2(void)
+{
+ dcfg_init(&dcfg_init_data);
+ /* Initialize system level generic timer for SoCs */
+ delay_timer_init(NXP_TIMER_ADDR);
+
+#if LOG_LEVEL > 0
+ /* Initialize the console to provide early debug support */
+ plat_console_init(NXP_CONSOLE_ADDR,
+ NXP_UART_CLK_DIVIDER, NXP_CONSOLE_BAUDRATE);
+#endif
+}
+
+void soc_platform_setup(void)
+{
+ static uint32_t target_mask_array[PLATFORM_CORE_COUNT];
+ /*
+ * On a GICv2 system, the Group 1 secure interrupts are treated
+ * as Group 0 interrupts.
+ */
+ static interrupt_prop_t ls_interrupt_props[] = {
+ PLAT_LS_G1S_IRQ_PROPS(GICV2_INTR_GROUP0),
+ PLAT_LS_G0_IRQ_PROPS(GICV2_INTR_GROUP0)
+ };
+
+ plat_ls_gic_driver_init(
+#if (TEST_BL31)
+ /* Defect in simulator - GIC base addresses (4Kb aligned) */
+ NXP_GICD_4K_ADDR,
+ NXP_GICC_4K_ADDR,
+#else
+ NXP_GICD_64K_ADDR,
+ NXP_GICC_64K_ADDR,
+#endif
+ PLATFORM_CORE_COUNT,
+ ls_interrupt_props,
+ ARRAY_SIZE(ls_interrupt_props),
+ target_mask_array);
+
+ plat_ls_gic_init();
+ enable_init_timer();
+}
+
+/* This function initializes the soc from the BL31 module */
+void soc_init(void)
+{
+ /* low-level init of the soc */
+ soc_init_lowlevel();
+ _init_global_data();
+ soc_init_percpu();
+ _initialize_psci();
+
+ /*
+ * Initialize the interconnect during cold boot.
+ * No need for locks as no other CPU is active.
+ */
+ cci_init(NXP_CCI_ADDR, cci_map, ARRAY_SIZE(cci_map));
+
+ /*
+ * Enable coherency in interconnect for the primary CPU's cluster.
+ * Earlier bootloader stages might already do this but we can't
+ * assume so. No harm in executing this code twice.
+ */
+ cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
+
+ /* Init CSU to enable non-secure access to peripherals */
+ enable_layerscape_ns_access(ns_dev, ARRAY_SIZE(ns_dev), NXP_CSU_ADDR);
+
+ /* Initialize the crypto accelerator if enabled */
+ if (is_sec_enabled() == false) {
+ INFO("SEC is disabled.\n");
+ } else {
+ sec_init(NXP_CAAM_ADDR);
+ }
+}
+
+void soc_runtime_setup(void)
+{
+
+}
+
+#endif /* IMAGE_BL2 */
diff --git a/plat/nxp/soc-ls1046a/soc.def b/plat/nxp/soc-ls1046a/soc.def
new file mode 100644
index 0000000..e6b37c0
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/soc.def
@@ -0,0 +1,107 @@
+#
+# Copyright 2022 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+#------------------------------------------------------------------------------
+#
+# This file contains the basic architecture definitions that drive the build
+#
+# -----------------------------------------------------------------------------
+
+CORE_TYPE := a72
+
+CACHE_LINE := 6
+
+# set to GIC400 or GIC500
+GIC := GIC400
+
+# set to CCI400 or CCN504 or CCN508
+INTERCONNECT := CCI400
+
+# indicate layerscape chassis level - set to 3=LSCH3 or 2=LSCH2
+CHASSIS := 2
+
+# TZC IP Details TZC used is TZC380 or TZC400
+TZC_ID := TZC400
+
+# CONSOLE Details available is NS16550 or PL011
+CONSOLE := NS16550
+
+ # Select the DDR PHY generation to be used
+PLAT_DDR_PHY := PHY_GEN1
+
+PHYS_SYS := 64
+
+# ddr controller - set to MMDC or NXP
+DDRCNTLR := NXP
+
+# ddr phy - set to NXP or SNPS
+DDRPHY := NXP
+
+# Area of OCRAM reserved by ROM code
+NXP_ROM_RSVD := 0x5900
+
+# Max Size of CSF header. Required to define BL2 TEXT LIMIT in soc.def
+# Input to CST create_hdr_esbc tool
+CSF_HDR_SZ := 0x3000
+
+# In IMAGE_BL2, compile time flag for handling Cache coherency
+# with CAAM for BL2 running from OCRAM
+SEC_MEM_NON_COHERENT := yes
+
+# OCRAM MAP
+OCRAM_START_ADDR := 0x10000000
+OCRAM_SIZE := 0x20000
+
+# BL2 binary is placed at start of OCRAM.
+# Also used by create_pbl.mk.
+BL2_BASE := 0x10000000
+
+# After BL2 bin, OCRAM is used by ROM Code:
+# (OCRAM_START_ADDR + BL2_BIN_SIZE) -> (NXP_ROM_RSVD - 1)
+
+# After ROM Code, OCRAM is used by CSF header.
+# (OCRAM_START_ADDR + BL2_TEXT_LIMIT + NXP_ROM_RSVD) -> (CSF_HDR_SZ - 1)
+
+# BL2_HDR_LOC has to be (OCRAM_START_ADDR + OCRAM_SIZE - NXP_ROM_RSVD - CSF_HDR_SZ)
+# This value should be greater than BL2_TEXT_LIMIT
+# Input to CST create_hdr_isbc tool
+BL2_HDR_LOC_HDR ?= $(shell echo $$(( $(OCRAM_START_ADDR) + $(OCRAM_SIZE) - $(NXP_ROM_RSVD) - $(CSF_HDR_SZ))))
+# Covert to HEX to be used by create_pbl.mk
+BL2_HDR_LOC := $$(echo "obase=16; ${BL2_HDR_LOC_HDR}" | bc)
+
+# Core Errata
+ERRATA_A72_859971 := 1
+
+# SoC ERRATAS
+ERRATA_SOC_A008850 := 1
+ERRATA_SOC_A010539 := 1
+
+# DDR Errata
+ERRATA_DDR_A008511 := 1
+ERRATA_DDR_A009803 := 1
+ERRATA_DDR_A009942 := 1
+ERRATA_DDR_A010165 := 1
+
+# enable dynamic memory mapping
+PLAT_XLAT_TABLES_DYNAMIC := 1
+
+# Define Endianness of each module
+NXP_GUR_ENDIANNESS := BE
+NXP_DDR_ENDIANNESS := BE
+NXP_SEC_ENDIANNESS := BE
+NXP_SFP_ENDIANNESS := BE
+NXP_SNVS_ENDIANNESS := BE
+NXP_ESDHC_ENDIANNESS := BE
+NXP_QSPI_ENDIANNESS := BE
+NXP_FSPI_ENDIANNESS := BE
+NXP_SCFG_ENDIANNESS := BE
+NXP_GPIO_ENDIANNESS := BE
+NXP_IFC_ENDIANNESS := BE
+
+NXP_SFP_VER := 3_2
+
+# OCRAM ECC Enabled
+OCRAM_ECC_EN := yes
diff --git a/plat/nxp/soc-ls1046a/soc.mk b/plat/nxp/soc-ls1046a/soc.mk
new file mode 100644
index 0000000..8207dcd
--- /dev/null
+++ b/plat/nxp/soc-ls1046a/soc.mk
@@ -0,0 +1,114 @@
+#
+# Copyright 2018-2022 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# SoC-specific build parameters
+SOC := ls1046a
+PLAT_PATH := plat/nxp
+PLAT_COMMON_PATH:= plat/nxp/common
+PLAT_DRIVERS_PATH:= drivers/nxp
+PLAT_SOC_PATH := ${PLAT_PATH}/soc-${SOC}
+BOARD_PATH := ${PLAT_SOC_PATH}/${BOARD}
+
+# Get SoC-specific defnitions
+include ${PLAT_SOC_PATH}/soc.def
+include ${PLAT_COMMON_PATH}/plat_make_helper/soc_common_def.mk
+include ${PLAT_COMMON_PATH}/plat_make_helper/plat_build_macros.mk
+
+# For Security Features
+DISABLE_FUSE_WRITE := 1
+ifeq (${TRUSTED_BOARD_BOOT}, 1)
+$(eval $(call SET_NXP_MAKE_FLAG,SMMU_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,SFP_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,SNVS_NEEDED,BL2))
+SECURE_BOOT := yes
+endif
+$(eval $(call SET_NXP_MAKE_FLAG,CRYPTO_NEEDED,BL_COMM))
+
+# Selecting Drivers for SoC
+$(eval $(call SET_NXP_MAKE_FLAG,DCFG_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,CSU_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,TIMER_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,INTERCONNECT_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,GIC_NEEDED,BL31))
+$(eval $(call SET_NXP_MAKE_FLAG,CONSOLE_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,PMU_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,DDR_DRIVER_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,TZASC_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,I2C_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,IMG_LOADR_NEEDED,BL2))
+
+# Selecting PSCI & SIP_SVC support
+$(eval $(call SET_NXP_MAKE_FLAG,PSCI_NEEDED,BL31))
+$(eval $(call SET_NXP_MAKE_FLAG,SIPSVC_NEEDED,BL31))
+
+# Source File Addition
+PLAT_INCLUDES += -I${PLAT_COMMON_PATH}/include/default\
+ -I${BOARD_PATH}\
+ -I${PLAT_COMMON_PATH}/include/default/ch_${CHASSIS}\
+ -I${PLAT_SOC_PATH}/include\
+ -I${PLAT_COMMON_PATH}/soc_errata
+
+ifeq (${SECURE_BOOT},yes)
+include ${PLAT_COMMON_PATH}/tbbr/tbbr.mk
+endif
+
+ifeq ($(WARM_BOOT),yes)
+include ${PLAT_COMMON_PATH}/warm_reset/warm_reset.mk
+endif
+
+ifeq (${NXP_NV_SW_MAINT_LAST_EXEC_DATA}, yes)
+include ${PLAT_COMMON_PATH}/nv_storage/nv_storage.mk
+endif
+
+ifeq (${PSCI_NEEDED}, yes)
+include ${PLAT_COMMON_PATH}/psci/psci.mk
+endif
+
+ifeq (${SIPSVC_NEEDED}, yes)
+include ${PLAT_COMMON_PATH}/sip_svc/sipsvc.mk
+endif
+
+# For fuse-fip & fuse-programming
+ifeq (${FUSE_PROG}, 1)
+include ${PLAT_COMMON_PATH}/fip_handler/fuse_fip/fuse.mk
+endif
+
+ifeq (${IMG_LOADR_NEEDED},yes)
+include $(PLAT_COMMON_PATH)/img_loadr/img_loadr.mk
+endif
+
+# Adding source files for the above selected drivers.
+include ${PLAT_DRIVERS_PATH}/drivers.mk
+
+# Adding SoC specific files
+include ${PLAT_COMMON_PATH}/soc_errata/errata.mk
+
+PLAT_INCLUDES += ${NV_STORAGE_INCLUDES}\
+ ${WARM_RST_INCLUDES}
+
+BL31_SOURCES += ${PLAT_SOC_PATH}/$(ARCH)/${SOC}.S\
+ ${WARM_RST_BL31_SOURCES}\
+ ${PSCI_SOURCES}\
+ ${SIPSVC_SOURCES}\
+ ${PLAT_COMMON_PATH}/$(ARCH)/bl31_data.S
+
+PLAT_BL_COMMON_SOURCES += ${PLAT_COMMON_PATH}/$(ARCH)/ls_helpers.S\
+ ${PLAT_SOC_PATH}/aarch64/${SOC}_helpers.S\
+ ${NV_STORAGE_SOURCES}\
+ ${WARM_RST_BL_COMM_SOURCES}\
+ ${PLAT_SOC_PATH}/soc.c
+
+ifeq (${TEST_BL31}, 1)
+BL31_SOURCES += ${PLAT_SOC_PATH}/$(ARCH)/bootmain64.S\
+ ${PLAT_SOC_PATH}/$(ARCH)/nonboot64.S
+endif
+
+BL2_SOURCES += ${DDR_CNTLR_SOURCES}\
+ ${TBBR_SOURCES}\
+ ${FUSE_SOURCES}
+
+# Adding TFA setup files
+include ${PLAT_PATH}/common/setup/common.mk
diff --git a/plat/nxp/soc-ls1088a/aarch64/ls1088a.S b/plat/nxp/soc-ls1088a/aarch64/ls1088a.S
new file mode 100644
index 0000000..0c6b7ea
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/aarch64/ls1088a.S
@@ -0,0 +1,1817 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+.section .text, "ax"
+
+#include <asm_macros.S>
+#include <lib/psci/psci.h>
+#include <nxp_timer.h>
+#include <plat_gic.h>
+
+#include "bl31_data.h"
+#include "plat_psci.h"
+#include "platform_def.h"
+
+/*
+ * the BASE address for these offsets is AUX_01_DATA in the
+ * bootcore's psci data region
+ */
+#define DEVDISR2_MASK_OFFSET 0x0 /* references AUX_01_DATA */
+#define DEVDISR5_MASK_OFFSET 0x8 /* references AUX_02_DATA */
+
+/*
+ * the BASE address for these offsets is AUX_04_DATA in the
+ * bootcore's psci data region
+ */
+#define GICD_BASE_ADDR_OFFSET 0x0 /* references AUX_04_DATA */
+#define GICC_BASE_ADDR_OFFSET 0x8 /* references AUX_05_DATA */
+
+#define IPSTPACK_RETRY_CNT 0x10000
+#define DDR_SLEEP_RETRY_CNT 0x10000
+#define CPUACTLR_EL1 S3_1_C15_C2_0
+#define DDR_SDRAM_CFG_2_FRCSR 0x80000000
+#define DDR_SDRAM_CFG_2_OFFSET 0x114
+#define DDR_TIMING_CFG_4_OFFSET 0x160
+#define DDR_CNTRL_BASE_ADDR 0x01080000
+
+#define DLL_LOCK_MASK 0x3
+#define DLL_LOCK_VALUE 0x2
+
+#define ERROR_DDR_SLEEP -1
+#define ERROR_DDR_WAKE -2
+#define ERROR_NO_QUIESCE -3
+
+#define CORE_RESTARTABLE 0
+#define CORE_NOT_RESTARTABLE 1
+
+.global soc_init_lowlevel
+.global soc_init_percpu
+
+.global _soc_core_release
+.global _soc_core_restart
+.global _soc_ck_disabled
+.global _soc_sys_reset
+.global _soc_sys_off
+
+.global _soc_core_prep_off
+.global _soc_core_entr_off
+.global _soc_core_exit_off
+
+.global _soc_core_prep_stdby
+.global _soc_core_entr_stdby
+.global _soc_core_exit_stdby
+.global _soc_core_prep_pwrdn
+.global _soc_core_entr_pwrdn
+.global _soc_core_exit_pwrdn
+.global _soc_clstr_prep_stdby
+.global _soc_clstr_exit_stdby
+.global _soc_clstr_prep_pwrdn
+.global _soc_clstr_exit_pwrdn
+.global _soc_sys_prep_stdby
+.global _soc_sys_exit_stdby
+.global _soc_sys_prep_pwrdn
+.global _soc_sys_pwrdn_wfi
+.global _soc_sys_exit_pwrdn
+
+.global _set_platform_security
+.global _soc_set_start_addr
+
+.equ TZPCDECPROT_0_SET_BASE, 0x02200804
+.equ TZPCDECPROT_1_SET_BASE, 0x02200810
+.equ TZPCDECPROT_2_SET_BASE, 0x0220081C
+
+.equ TZASC_REGION_ATTRIBUTES_0_0, 0x01100110
+
+.equ MPIDR_AFFINITY0_MASK, 0x00FF
+.equ MPIDR_AFFINITY1_MASK, 0xFF00
+.equ CPUECTLR_DISABLE_TWALK_PREFETCH, 0x4000000000
+.equ CPUECTLR_INS_PREFETCH_MASK, 0x1800000000
+.equ CPUECTLR_DAT_PREFETCH_MASK, 0x0300000000
+.equ OSDLR_EL1_DLK_LOCK, 0x1
+.equ CNTP_CTL_EL0_EN, 0x1
+.equ CNTP_CTL_EL0_IMASK, 0x2
+/* shifted value for incrementing cluster count in mpidr */
+.equ MPIDR_CLUSTER, 0x100
+
+/*
+ * This function initialize the soc,
+ * in: none
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11
+ */
+func soc_init_lowlevel
+ /*
+ * called from C, so save the non-volatile regs
+ * save these as pairs of registers to maintain the
+ * required 16-byte alignment on the stack
+ */
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+ stp x8, x9, [sp, #-16]!
+ stp x10, x11, [sp, #-16]!
+ stp x12, x13, [sp, #-16]!
+ stp x18, x30, [sp, #-16]!
+
+ /*
+ * make sure the personality has been established by releasing cores
+ * that are marked "to-be-disabled" from reset
+ */
+ bl release_disabled
+
+ /* set SCRATCHRW7 to 0x0 */
+ ldr x0, =DCFG_SCRATCHRW7_OFFSET
+ mov x1, xzr
+ bl _write_reg_dcfg
+
+ /* restore the aarch32/64 non-volatile registers */
+ ldp x18, x30, [sp], #16
+ ldp x12, x13, [sp], #16
+ ldp x10, x11, [sp], #16
+ ldp x8, x9, [sp], #16
+ ldp x6, x7, [sp], #16
+ ldp x4, x5, [sp], #16
+ ret
+endfunc soc_init_lowlevel
+
+/*
+ * void soc_init_percpu(void)
+ * this function performs any soc-specific initialization that is needed on
+ * a per-core basis
+ * in: none
+ * out: none
+ * uses x0, x1, x2, x3
+ */
+func soc_init_percpu
+ stp x4, x30, [sp, #-16]!
+
+ bl plat_my_core_mask
+ mov x2, x0
+
+ /* x2 = core mask */
+
+ /* see if this core is marked for prefetch disable */
+ mov x0, #PREFETCH_DIS_OFFSET
+ bl _get_global_data
+ tst x0, x2
+ b.eq 1f
+ bl _disable_ldstr_pfetch_A53
+1:
+ mov x0, #NXP_PMU_ADDR
+ bl enable_timer_base_to_cluster
+ ldp x4, x30, [sp], #16
+ ret
+endfunc soc_init_percpu
+
+/*
+ * this function sets the security mechanisms in the SoC to implement the
+ * Platform Security Policy
+ */
+func _set_platform_security
+ mov x3, x30
+
+#if (!SUPPRESS_TZC)
+ /* initialize the tzpc */
+ bl init_tzpc
+#endif
+
+#if (!SUPPRESS_SEC)
+ /* initialize secmon */
+ bl initSecMon
+#endif
+ mov x30, x3
+ ret
+endfunc _set_platform_security
+
+/*
+ * this function writes a 64-bit address to bootlocptrh/l
+ * in: x0, 64-bit address to write to BOOTLOCPTRL/H
+ * out: none
+ * uses x0, x1, x2
+ */
+func _soc_set_start_addr
+ /* get the 64-bit base address of the dcfg block */
+ ldr x2, =NXP_DCFG_ADDR
+
+ /* write the 32-bit BOOTLOCPTRL register */
+ mov x1, x0
+ str w1, [x2, #DCFG_BOOTLOCPTRL_OFFSET]
+
+ /* write the 32-bit BOOTLOCPTRH register */
+ lsr x1, x0, #32
+ str w1, [x2, #DCFG_BOOTLOCPTRH_OFFSET]
+ ret
+endfunc _soc_set_start_addr
+
+/*
+ * part of CPU_ON
+ * this function releases a secondary core from reset
+ * in: x0 = core_mask_lsb
+ * out: none
+ * uses: x0, x1, x2, x3
+ */
+_soc_core_release:
+ mov x3, x30
+
+ /* x0 = core mask */
+
+ ldr x1, =NXP_SEC_REGFILE_ADDR
+ /*
+ * write to CORE_HOLD to tell the bootrom that we want this core
+ * to run
+ */
+ str w0, [x1, #CORE_HOLD_OFFSET]
+
+ /* x0 = core mask */
+
+ /* read-modify-write BRRL to release core */
+ mov x1, #NXP_RESET_ADDR
+ ldr w2, [x1, #BRR_OFFSET]
+ orr w2, w2, w0
+ str w2, [x1, #BRR_OFFSET]
+ dsb sy
+ isb
+
+ /* send event */
+ sev
+ isb
+
+ mov x30, x3
+ ret
+
+/*
+ * this function determines if a core is disabled via COREDISABLEDSR
+ * in: w0 = core_mask_lsb
+ * out: w0 = 0, core not disabled
+ * w0 != 0, core disabled
+ * uses x0, x1
+ */
+_soc_ck_disabled:
+ /* get base addr of dcfg block */
+ ldr x1, =NXP_DCFG_ADDR
+
+ /* read COREDISABLEDSR */
+ ldr w1, [x1, #DCFG_COREDISABLEDSR_OFFSET]
+
+ /* test core bit */
+ and w0, w1, w0
+
+ ret
+
+/*
+ * part of CPU_ON
+ * this function restarts a core shutdown via _soc_core_entr_off
+ * in: x0 = core mask lsb (of the target cpu)
+ * out: x0 == 0, on success
+ * x0 != 0, on failure
+ * uses x0, x1, x2, x3, x4, x5, x6
+ */
+_soc_core_restart:
+ mov x6, x30
+ mov x4, x0
+
+ /* x4 = core mask lsb */
+
+ /* pgm GICD_CTLR - enable secure grp0 */
+ mov x5, #NXP_GICD_ADDR
+ ldr w2, [x5, #GICD_CTLR_OFFSET]
+ orr w2, w2, #GICD_CTLR_EN_GRP_0
+ str w2, [x5, #GICD_CTLR_OFFSET]
+ dsb sy
+ isb
+ /* poll on RWP til write completes */
+4:
+ ldr w2, [x5, #GICD_CTLR_OFFSET]
+ tst w2, #GICD_CTLR_RWP
+ b.ne 4b
+
+ /*
+ * x4 = core mask lsb
+ * x5 = gicd base addr
+ */
+
+ mov x0, x4
+ bl get_mpidr_value
+
+ /*
+ * x0 = mpidr of target core
+ * x4 = core mask lsb of target core
+ * x5 = gicd base addr
+ */
+
+ /* generate target list bit */
+ and x1, x0, #MPIDR_AFFINITY0_MASK
+ mov x2, #1
+ lsl x2, x2, x1
+ /* get the affinity1 field */
+ and x1, x0, #MPIDR_AFFINITY1_MASK
+ lsl x1, x1, #8
+ orr x2, x2, x1
+ /* insert the INTID for SGI15 */
+ orr x2, x2, #ICC_SGI0R_EL1_INTID
+ /* fire the SGI */
+ msr ICC_SGI0R_EL1, x2
+ dsb sy
+ isb
+
+ /* load '0' on success */
+ mov x0, xzr
+
+ mov x30, x6
+ ret
+
+/*
+ * part of CPU_OFF
+ * this function programs SoC & GIC registers in preparation for shutting down
+ * the core
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6, x7
+ */
+_soc_core_prep_off:
+ mov x8, x30
+ mov x7, x0
+
+ /* x7 = core mask lsb */
+
+ mrs x1, CPUECTLR_EL1
+ /* set smp and disable L2 snoops in cpuectlr */
+ orr x1, x1, #CPUECTLR_SMPEN_EN
+ orr x1, x1, #CPUECTLR_DISABLE_TWALK_PREFETCH
+ bic x1, x1, #CPUECTLR_INS_PREFETCH_MASK
+ bic x1, x1, #CPUECTLR_DAT_PREFETCH_MASK
+ /* set retention control in cpuectlr */
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ orr x1, x1, #CPUECTLR_TIMER_8TICKS
+ msr CPUECTLR_EL1, x1
+
+ /* get redistributor rd base addr for this core */
+ mov x0, x7
+ bl get_gic_rd_base
+ mov x6, x0
+
+ /* get redistributor sgi base addr for this core */
+ mov x0, x7
+ bl get_gic_sgi_base
+ mov x5, x0
+
+ /* x5 = gicr sgi base addr
+ * x6 = gicr rd base addr
+ * x7 = core mask lsb
+ */
+
+ /* disable SGI 15 at redistributor - GICR_ICENABLER0 */
+ mov w3, #GICR_ICENABLER0_SGI15
+ str w3, [x5, #GICR_ICENABLER0_OFFSET]
+2:
+ /* poll on rwp bit in GICR_CTLR */
+ ldr w4, [x6, #GICR_CTLR_OFFSET]
+ tst w4, #GICR_CTLR_RWP
+ b.ne 2b
+
+ /* disable GRP1 interrupts at cpu interface */
+ msr ICC_IGRPEN1_EL3, xzr
+
+ /* disable GRP0 ints at cpu interface */
+ msr ICC_IGRPEN0_EL1, xzr
+
+ /* program the redistributor - poll on GICR_CTLR.RWP as needed */
+
+ /* define SGI 15 as Grp0 - GICR_IGROUPR0 */
+ ldr w4, [x5, #GICR_IGROUPR0_OFFSET]
+ bic w4, w4, #GICR_IGROUPR0_SGI15
+ str w4, [x5, #GICR_IGROUPR0_OFFSET]
+
+ /* define SGI 15 as Grp0 - GICR_IGRPMODR0 */
+ ldr w3, [x5, #GICR_IGRPMODR0_OFFSET]
+ bic w3, w3, #GICR_IGRPMODR0_SGI15
+ str w3, [x5, #GICR_IGRPMODR0_OFFSET]
+
+ /* set priority of SGI 15 to highest (0x0) - GICR_IPRIORITYR3 */
+ ldr w4, [x5, #GICR_IPRIORITYR3_OFFSET]
+ bic w4, w4, #GICR_IPRIORITYR3_SGI15_MASK
+ str w4, [x5, #GICR_IPRIORITYR3_OFFSET]
+
+ /* enable SGI 15 at redistributor - GICR_ISENABLER0 */
+ mov w3, #GICR_ISENABLER0_SGI15
+ str w3, [x5, #GICR_ISENABLER0_OFFSET]
+ dsb sy
+ isb
+3:
+ /* poll on rwp bit in GICR_CTLR */
+ ldr w4, [x6, #GICR_CTLR_OFFSET]
+ tst w4, #GICR_CTLR_RWP
+ b.ne 3b
+
+ /* quiesce the debug interfaces */
+ mrs x3, osdlr_el1
+ orr x3, x3, #OSDLR_EL1_DLK_LOCK
+ msr osdlr_el1, x3
+ isb
+
+ /* enable grp0 ints */
+ mov x3, #ICC_IGRPEN0_EL1_EN
+ msr ICC_IGRPEN0_EL1, x3
+
+ /*
+ * x5 = gicr sgi base addr
+ * x6 = gicr rd base addr
+ * x7 = core mask lsb
+ */
+
+ /* clear any pending interrupts */
+ mvn w1, wzr
+ str w1, [x5, #GICR_ICPENDR0_OFFSET]
+
+ /* make sure system counter is enabled */
+ ldr x3, =NXP_TIMER_ADDR
+ ldr w0, [x3, #SYS_COUNTER_CNTCR_OFFSET]
+ tst w0, #SYS_COUNTER_CNTCR_EN
+ b.ne 4f
+ orr w0, w0, #SYS_COUNTER_CNTCR_EN
+ str w0, [x3, #SYS_COUNTER_CNTCR_OFFSET]
+4:
+ /* enable the core timer and mask timer interrupt */
+ mov x1, #CNTP_CTL_EL0_EN
+ orr x1, x1, #CNTP_CTL_EL0_IMASK
+ msr cntp_ctl_el0, x1
+
+ mov x30, x8
+ ret
+
+/*
+ * part of CPU_OFF
+ * this function performs the final steps to shutdown the core
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5
+ */
+_soc_core_entr_off:
+ mov x5, x30
+ mov x4, x0
+
+ /* x4 = core mask */
+1:
+ /* enter low-power state by executing wfi */
+ wfi
+
+ /* see if SGI15 woke us up */
+ mrs x2, ICC_IAR0_EL1
+ mov x3, #ICC_IAR0_EL1_SGI15
+ cmp x2, x3
+ b.ne 2f
+
+ /* deactivate the int */
+ msr ICC_EOIR0_EL1, x2
+
+ /* x4 = core mask */
+2:
+ /* check if core has been turned on */
+ mov x0, x4
+ bl _getCoreState
+
+ /* x0 = core state */
+
+ cmp x0, #CORE_WAKEUP
+ b.ne 1b
+
+ /* if we get here, then we have exited the wfi */
+
+ mov x30, x5
+ ret
+
+/*
+ * part of CPU_OFF
+ * this function starts the process of starting a core back up
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6
+ */
+_soc_core_exit_off:
+ mov x6, x30
+ mov x5, x0
+
+ /* disable forwarding of GRP0 ints at cpu interface */
+ msr ICC_IGRPEN0_EL1, xzr
+
+ /* get redistributor sgi base addr for this core */
+ mov x0, x5
+ bl get_gic_sgi_base
+ mov x4, x0
+
+ /*
+ * x4 = gicr sgi base addr
+ * x5 = core mask
+ */
+
+ /* disable SGI 15 at redistributor - GICR_ICENABLER0 */
+ mov w1, #GICR_ICENABLER0_SGI15
+ str w1, [x4, #GICR_ICENABLER0_OFFSET]
+
+ /* get redistributor rd base addr for this core */
+ mov x0, x5
+ bl get_gic_rd_base
+ mov x4, x0
+
+ /* x4 = gicr rd base addr */
+2:
+ /* poll on rwp bit in GICR_CTLR */
+ ldr w2, [x4, #GICR_CTLR_OFFSET]
+ tst w2, #GICR_CTLR_RWP
+ b.ne 2b
+
+ /* x4 = gicr rd base addr */
+
+ /* unlock the debug interfaces */
+ mrs x3, osdlr_el1
+ bic x3, x3, #OSDLR_EL1_DLK_LOCK
+ msr osdlr_el1, x3
+ isb
+
+ dsb sy
+ isb
+ mov x30, x6
+ ret
+
+/*
+ * this function requests a reset of the entire SOC
+ * in: none
+ * out: none
+ * uses: x0, x1, x2, x3, x4, x5, x6
+ */
+_soc_sys_reset:
+ mov x3, x30
+
+ /* make sure the mask is cleared in the reset request mask register */
+ mov x0, #RST_RSTRQMR1_OFFSET
+ mov w1, wzr
+ bl _write_reg_reset
+
+ /* set the reset request */
+ mov x4, #RST_RSTCR_OFFSET
+ mov x0, x4
+ mov w1, #RSTCR_RESET_REQ
+ bl _write_reg_reset
+
+ /* x4 = RST_RSTCR_OFFSET */
+
+ /*
+ * just in case this address range is mapped as cacheable,
+ * flush the write out of the dcaches
+ */
+ mov x2, #NXP_RESET_ADDR
+ add x2, x2, x4
+ dc cvac, x2
+ dsb st
+ isb
+
+ /* this function does not return */
+ b .
+
+/*
+ * this function turns off the SoC
+ * Note: this function is not intended to return, and the only allowable
+ * recovery is POR
+ * in: none
+ * out: none
+ * uses x0, x1, x2, x3
+ */
+_soc_sys_off:
+ /*
+ * A-009810: LPM20 entry sequence might cause
+ * spurious timeout reset request
+ * workaround: MASK RESET REQ RPTOE
+ */
+ ldr x0, =NXP_RESET_ADDR
+ ldr w1, [x0, #RST_RSTRQMR1_OFFSET]
+ orr w1, w1, #RSTRQMR_RPTOE_MASK
+ str w1, [x0, #RST_RSTRQMR1_OFFSET]
+
+ /* disable SEC, QBman spi and qspi */
+ ldr x2, =NXP_DCFG_ADDR
+ ldr x0, =DCFG_DEVDISR1_OFFSET
+ ldr w1, =DCFG_DEVDISR1_SEC
+ str w1, [x2, x0]
+ ldr x0, =DCFG_DEVDISR3_OFFSET
+ ldr w1, =DCFG_DEVDISR3_QBMAIN
+ str w1, [x2, x0]
+ ldr x0, =DCFG_DEVDISR4_OFFSET
+ ldr w1, =DCFG_DEVDISR4_SPI_QSPI
+ str w1, [x2, x0]
+
+ /* set TPMWAKEMR0 */
+ ldr x0, =TPMWAKEMR0_ADDR
+ mov w1, #0x1
+ str w1, [x0]
+
+ /* disable icache, dcache, mmu @ EL1 */
+ mov x1, #SCTLR_I_C_M_MASK
+ mrs x0, sctlr_el1
+ bic x0, x0, x1
+ msr sctlr_el1, x0
+
+ /* disable L2 prefetches */
+ mrs x0, CPUECTLR_EL1
+ orr x0, x0, #CPUECTLR_SMPEN_EN
+ orr x0, x0, #CPUECTLR_TIMER_8TICKS
+ msr CPUECTLR_EL1, x0
+ dsb sy
+ isb
+
+ /* disable CCN snoop domain */
+ ldr x0, =NXP_CCI_ADDR
+ mov w1, #0x1
+ str w1, [x0]
+
+ mov x2, #DAIF_SET_MASK
+
+ mrs x1, spsr_el1
+ orr x1, x1, x2
+ msr spsr_el1, x1
+
+ mrs x1, spsr_el2
+ orr x1, x1, x2
+ msr spsr_el2, x1
+
+ bl get_pmu_idle_cluster_mask
+ mov x3, #NXP_PMU_ADDR
+
+ /* x3 = pmu base addr */
+
+ /* idle the ACP interfaces */
+ str w0, [x3, #PMU_CLAINACTSETR_OFFSET]
+
+ /* force the debug interface to be quiescent */
+ mrs x0, osdlr_el1
+ orr x0, x0, #0x1
+ msr osdlr_el1, x0
+
+ bl get_pmu_flush_cluster_mask
+ /* x3 = pmu base addr */
+ mov x3, #NXP_PMU_ADDR
+
+ /* clear flush request and status */
+ ldr x2, =PMU_CLSL2FLUSHCLRR_OFFSET
+ str w0, [x3, x2]
+
+ /* close the Skyros master port */
+ ldr x2, =PMU_CLSINACTSETR_OFFSET
+ str w0, [x3, x2]
+
+ /* request lpm20 */
+ ldr x0, =PMU_POWMGTCSR_OFFSET
+ ldr w1, =PMU_POWMGTCSR_VAL
+ str w1, [x3, x0]
+
+ /* this function does not return */
+1:
+ wfi
+ b 1b
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to standby
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+_soc_core_prep_stdby:
+ /* clear CPUECTLR_EL1[2:0] */
+ mrs x1, CPUECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ msr CPUECTLR_EL1, x1
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function puts the calling core into standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0
+ */
+_soc_core_entr_stdby:
+ /* X0 = core mask lsb */
+ dsb sy
+ isb
+ wfi
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs any SoC-specific cleanup after standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+_soc_core_exit_stdby:
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3
+ */
+_soc_core_prep_pwrdn:
+ /* make sure system counter is enabled */
+ ldr x3, =NXP_TIMER_ADDR
+ ldr w0, [x3, #SYS_COUNTER_CNTCR_OFFSET]
+ tst w0, #SYS_COUNTER_CNTCR_EN
+ b.ne 1f
+ orr w0, w0, #SYS_COUNTER_CNTCR_EN
+ str w0, [x3, #SYS_COUNTER_CNTCR_OFFSET]
+1:
+ /*
+ * enable dynamic retention control (CPUECTLR[2:0])
+ * set the SMPEN bit (CPUECTLR[6])
+ */
+ mrs x1, CPUECTLR_EL1
+ bic x1, x1, #CPUECTLR_RET_MASK
+ orr x1, x1, #CPUECTLR_TIMER_8TICKS
+ orr x1, x1, #CPUECTLR_SMPEN_EN
+ msr CPUECTLR_EL1, x1
+
+ isb
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function puts the calling core into a power-down state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0
+ */
+_soc_core_entr_pwrdn:
+ /* X0 = core mask lsb */
+ dsb sy
+ isb
+ wfi
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function cleans up after a core exits power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses
+ */
+_soc_core_exit_pwrdn:
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to standby
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+_soc_clstr_prep_stdby:
+ /* clear CPUECTLR_EL1[2:0] */
+ mrs x1, CPUECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ msr CPUECTLR_EL1, x1
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs any SoC-specific cleanup after standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+_soc_clstr_exit_stdby:
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3
+ */
+_soc_clstr_prep_pwrdn:
+ /* make sure system counter is enabled */
+ ldr x3, =NXP_TIMER_ADDR
+ ldr w0, [x3, #SYS_COUNTER_CNTCR_OFFSET]
+ tst w0, #SYS_COUNTER_CNTCR_EN
+ b.ne 1f
+ orr w0, w0, #SYS_COUNTER_CNTCR_EN
+ str w0, [x3, #SYS_COUNTER_CNTCR_OFFSET]
+1:
+ /*
+ * enable dynamic retention control (CPUECTLR[2:0])
+ * set the SMPEN bit (CPUECTLR[6])
+ */
+ mrs x1, CPUECTLR_EL1
+ bic x1, x1, #CPUECTLR_RET_MASK
+ orr x1, x1, #CPUECTLR_TIMER_8TICKS
+ orr x1, x1, #CPUECTLR_SMPEN_EN
+ msr CPUECTLR_EL1, x1
+
+ isb
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function cleans up after a core exits power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses
+ */
+_soc_clstr_exit_pwrdn:
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to standby
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+_soc_sys_prep_stdby:
+ /* clear CPUECTLR_EL1[2:0] */
+ mrs x1, CPUECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ msr CPUECTLR_EL1, x1
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs any SoC-specific cleanup after standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+_soc_sys_exit_stdby:
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs SoC-specific programming prior to
+ * suspend-to-power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0
+ */
+_soc_sys_prep_pwrdn:
+ /* set retention control */
+ mrs x0, CPUECTLR_EL1
+ bic x0, x0, #CPUECTLR_TIMER_MASK
+ orr x0, x0, #CPUECTLR_TIMER_8TICKS
+ orr x0, x0, #CPUECTLR_SMPEN_EN
+ msr CPUECTLR_EL1, x0
+ dsb sy
+ isb
+
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function puts the calling core, and potentially the soc, into a
+ * low-power state
+ * in: x0 = core mask lsb
+ * out: x0 = 0, success
+ * x0 < 0, failure
+ * uses x0, x1, x2, x3, x4, x5, x6, x7, x8
+ */
+_soc_sys_pwrdn_wfi:
+ /* Save LR to stack */
+ stp x18, x30, [sp, #-16]!
+
+ /* Poll PCPW20SR for all secondary cores to be placed in PW20 */
+ bl get_tot_num_cores
+ mov x3, #0x1
+ lsl x3, x3, x0
+ sub x3, x3, #2
+1:
+ mov x0, #NXP_PMU_ADDR
+ ldr w1, [x0, #PMU_PCPW20SR_OFFSET]
+ cmp w1, w3
+ b.ne 1b
+
+ /* backup EPU registers to stack */
+ mov x3, #NXP_PMU_ADDR
+ ldr x2, =NXP_EPU_ADDR
+ ldr w4, [x2, #EPU_EPIMCR10_OFFSET]
+ ldr w5, [x2, #EPU_EPCCR10_OFFSET]
+ ldr w6, [x2, #EPU_EPCTR10_OFFSET]
+ ldr w7, [x2, #EPU_EPGCR_OFFSET]
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+
+ /*
+ * x2 = epu base addr
+ * x3 = pmu base addr
+ */
+
+ /* set up EPU event to receive the wake signal from PMU */
+ mov w4, #EPU_EPIMCR10_VAL
+ mov w5, #EPU_EPCCR10_VAL
+ mov w6, #EPU_EPCTR10_VAL
+ mov w7, #EPU_EPGCR_VAL
+ str w4, [x2, #EPU_EPIMCR10_OFFSET]
+ str w5, [x2, #EPU_EPCCR10_OFFSET]
+ str w6, [x2, #EPU_EPCTR10_OFFSET]
+ str w7, [x2, #EPU_EPGCR_OFFSET]
+
+ /*
+ * A-010194: There is logic problem
+ * in the path of GIC-to-PMU to issue
+ * wake request to core0
+ * Workaround: Re-target the wakeup interrupts
+ * to a core other than the last active core0
+ */
+ ldr x2, =NXP_GICD_ADDR
+
+ /* backup flextimer/mmc/usb interrupt router */
+ ldr x0, =GICD_IROUTER60_OFFSET
+ ldr x1, =GICD_IROUTER76_OFFSET
+ ldr w4, [x2, x0]
+ ldr w5, [x2, x1]
+ ldr x0, =GICD_IROUTER112_OFFSET
+ ldr x1, =GICD_IROUTER113_OFFSET
+ ldr w6, [x2, x0]
+ ldr w7, [x2, x1]
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+
+ /*
+ * x2 = gicd base addr
+ * x0 = GICD_IROUTER112_OFFSET
+ * x1 = GICD_IROUTER113_OFFSET
+ */
+
+ /* re-route interrupt to cluster 1 */
+ ldr w4, =GICD_IROUTER_VALUE
+ str w4, [x2, x0]
+ str w4, [x2, x1]
+ ldr x0, =GICD_IROUTER60_OFFSET
+ ldr x1, =GICD_IROUTER76_OFFSET
+ str w4, [x2, x0]
+ str w4, [x2, x1]
+ dsb sy
+ isb
+
+ /* backup flextimer/mmc/usb interrupt enabler */
+ ldr x0, =GICD_ISENABLER_1
+ ldr w4, [x2, x0]
+ ldr x1, =GICD_ISENABLER_2
+ ldr w5, [x2, x1]
+ stp x4, x5, [sp, #-16]!
+
+ ldr x0, =GICD_ISENABLER_3
+ ldr w4, [x2, x0]
+ ldr x1, =GICD_ICENABLER_1
+ ldr w5, [x2, x1]
+ stp x4, x5, [sp, #-16]!
+
+ ldr x0, =GICD_ICENABLER_2
+ ldr w4, [x2, x0]
+ ldr x1, =GICD_ICENABLER_3
+ ldr w5, [x2, x1]
+ stp x4, x5, [sp, #-16]!
+
+ /* enable related interrupt routing */
+ ldr w4, =GICD_ISENABLER_1_VALUE
+ ldr x0, =GICD_ISENABLER_1
+ str w4, [x2, x0]
+ dsb sy
+ isb
+
+ ldr w4, =GICD_ISENABLER_2_VALUE
+ ldr x0, =GICD_ISENABLER_2
+ str w4, [x2, x0]
+ dsb sy
+ isb
+
+ ldr w4, =GICD_ISENABLER_3_VALUE
+ ldr x0, =GICD_ISENABLER_3
+ str w4, [x2, x0]
+ dsb sy
+ isb
+
+ /* set POWMGTDCR [STP_PV_EN] = 1 */
+ ldr x2, =NXP_POWMGTDCR
+ ldr w4, =0x01
+ str w4, [x2]
+
+ /* program IPSTPCR for override stop request (except DDR) */
+ mov x3, #NXP_PMU_ADDR
+
+ /* build an override mask for IPSTPCR4/IPSTPACK4/DEVDISR5 */
+ ldr x2, =PMU_IPPDEXPCR4_OFFSET
+ ldr w7, [x3, x2]
+
+ mov x5, xzr
+ ldr x6, =IPPDEXPCR4_MASK
+ and x6, x6, x7
+ cbz x6, 1f
+
+ /*
+ * x5 = override mask
+ * x6 = IPPDEXPCR bits for DEVDISR5
+ * x7 = IPPDEXPCR
+ */
+
+ /* get the overrides */
+ orr x4, x5, #DEVDISR5_FLX_TMR
+ tst x6, #IPPDEXPCR_FLX_TMR
+ csel x5, x5, x4, EQ
+1:
+ /* store the DEVDISR5 override mask */
+ ldr x2, =BC_PSCI_BASE
+ add x2, x2, #AUX_01_DATA
+ str w5, [x2, #DEVDISR5_MASK_OFFSET]
+
+ mov x3, #NXP_PMU_ADDR
+
+ /* write IPSTPCR0 - no overrides */
+ ldr x2, =PMU_IPSTPCR0_OFFSET
+ ldr w5, =IPSTPCR0_VALUE
+ str w5, [x3, x2]
+
+ /* write IPSTPCR1 - no overrides */
+ ldr x2, =PMU_IPSTPCR1_OFFSET
+ ldr w5, =IPSTPCR1_VALUE
+ str w5, [x3, x2]
+
+ /* write IPSTPCR2 - no overrides */
+ ldr x2, =PMU_IPSTPCR2_OFFSET
+ ldr w5, =IPSTPCR2_VALUE
+ str w5, [x3, x2]
+
+ /* write IPSTPCR3 - no overrides */
+ ldr x2, =PMU_IPSTPCR3_OFFSET
+ ldr w5, =IPSTPCR3_VALUE
+ str w5, [x3, x2]
+
+ /* write IPSTPCR4 - overrides possible */
+ ldr x2, =BC_PSCI_BASE
+ add x2, x2, #AUX_01_DATA
+ ldr w6, [x2, #DEVDISR5_MASK_OFFSET]
+ ldr x2, =PMU_IPSTPCR4_OFFSET
+ ldr w5, =IPSTPCR4_VALUE
+ bic x5, x5, x6
+ str w5, [x3, x2]
+
+ /* write IPSTPCR5 - no overrides */
+ ldr x2, =PMU_IPSTPCR5_OFFSET
+ ldr w5, =IPSTPCR5_VALUE
+ str w5, [x3, x2]
+
+ /* write IPSTPCR6 - no overrides */
+ ldr x2, =PMU_IPSTPCR6_OFFSET
+ ldr w5, =IPSTPCR6_VALUE
+ str w5, [x3, x2]
+
+ /* poll IPSTPACK for IP stop acknowledgment (except DDR) */
+ mov x3, #NXP_PMU_ADDR
+
+ /* poll on IPSTPACK0 */
+ ldr x2, =PMU_IPSTPACK0_OFFSET
+ ldr x4, =IPSTPCR0_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+3:
+ ldr w0, [x3, x2]
+ cmp x0, x4
+ b.eq 14f
+ sub x7, x7, #1
+ cbnz x7, 3b
+
+14:
+ /* poll on IPSTPACK1 */
+ ldr x2, =PMU_IPSTPACK1_OFFSET
+ ldr x4, =IPSTPCR1_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+4:
+ ldr w0, [x3, x2]
+ cmp x0, x4
+ b.eq 15f
+ sub x7, x7, #1
+ cbnz x7, 4b
+
+15:
+ /* poll on IPSTPACK2 */
+ ldr x2, =PMU_IPSTPACK2_OFFSET
+ ldr x4, =IPSTPCR2_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+5:
+ ldr w0, [x3, x2]
+ cmp x0, x4
+ b.eq 16f
+ sub x7, x7, #1
+ cbnz x7, 5b
+
+16:
+ /* poll on IPSTPACK3 */
+ ldr x2, =PMU_IPSTPACK3_OFFSET
+ ldr x4, =IPSTPCR3_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+6:
+ ldr w0, [x3, x2]
+ cmp x0, x4
+ b.eq 17f
+ sub x7, x7, #1
+ cbnz x7, 6b
+
+17:
+ /* poll on IPSTPACK4 */
+ ldr x2, =PMU_IPSTPACK4_OFFSET
+ ldr x4, =IPSTPCR4_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+7:
+ ldr w0, [x3, x2]
+ cmp x0, x4
+ b.eq 18f
+ sub x7, x7, #1
+ cbnz x7, 7b
+
+18:
+ /* poll on IPSTPACK5 */
+ ldr x2, =PMU_IPSTPACK5_OFFSET
+ ldr x4, =IPSTPCR5_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+8:
+ ldr w0, [x3, x2]
+ cmp x0, x4
+ b.eq 19f
+ sub x7, x7, #1
+ cbnz x7, 8b
+
+19:
+ /* poll on IPSTPACK6 */
+ ldr x2, =PMU_IPSTPACK6_OFFSET
+ ldr x4, =IPSTPCR6_VALUE
+ ldr x7, =IPSTPACK_RETRY_CNT
+9:
+ ldr w0, [x3, x2]
+ cmp x0, x4
+ b.eq 20f
+ sub x7, x7, #1
+ cbnz x7, 9b
+
+20:
+ /* save current DEVDISR states to DDR. */
+ ldr x2, =NXP_DCFG_ADDR
+
+ /* save DEVDISR1 and load new value */
+ ldr x0, =DCFG_DEVDISR1_OFFSET
+ ldr w1, [x2, x0]
+ mov w13, w1
+ ldr x1, =DEVDISR1_VALUE
+ str w1, [x2, x0]
+ /* save DEVDISR2 and load new value */
+ ldr x0, =DCFG_DEVDISR2_OFFSET
+ ldr w1, [x2, x0]
+ mov w14, w1
+ ldr x1, =DEVDISR2_VALUE
+ str w1, [x2, x0]
+
+ /* x6 = DEVDISR5 override mask */
+
+ /* save DEVDISR3 and load new value */
+ ldr x0, =DCFG_DEVDISR3_OFFSET
+ ldr w1, [x2, x0]
+ mov w15, w1
+ ldr x1, =DEVDISR3_VALUE
+ str w1, [x2, x0]
+
+ /* save DEVDISR4 and load new value */
+ ldr x0, =DCFG_DEVDISR4_OFFSET
+ ldr w1, [x2, x0]
+ mov w16, w1
+ /* not stop uart print */
+ ldr x1, =0x0000332
+ str w1, [x2, x0]
+
+ /* save DEVDISR5 and load new value */
+ ldr x0, =DCFG_DEVDISR5_OFFSET
+ ldr w1, [x2, x0]
+ mov w17, w1
+ /* Enable this wakeup will fail, should enable OCRAM */
+ ldr x1, =0x00102300
+ str w1, [x2, x0]
+
+ /* save DEVDISR6 and load new value */
+ ldr x0, =DCFG_DEVDISR6_OFFSET
+ ldr w1, [x2, x0]
+ mov w18, w1
+ ldr x1, =DEVDISR6_VALUE
+ str w1, [x2, x0]
+
+ /*
+ * w13 = DEVDISR1 saved value
+ * w14 = DEVDISR2 saved value
+ * w15 = DEVDISR3 saved value
+ * w16 = DEVDISR4 saved value
+ * w17 = DEVDISR5 saved value
+ * w18 = DEVDISR6 saved value
+ */
+ /*
+ * A-009810: LPM20 entry sequence might cause
+ * spurious timeout reset request
+ * workaround: MASK RESET REQ RPTOE
+ */
+ ldr x0, =NXP_RESET_ADDR
+ ldr w1, =RSTRQMR_RPTOE_MASK
+ str w1, [x0, #RST_RSTRQMR1_OFFSET]
+
+ /* disable SEC, QBman spi and qspi */
+ ldr x2, =NXP_DCFG_ADDR
+ ldr x0, =DCFG_DEVDISR1_OFFSET
+ ldr w1, =DCFG_DEVDISR1_SEC
+ str w1, [x2, x0]
+ ldr x0, =DCFG_DEVDISR3_OFFSET
+ ldr w1, =DCFG_DEVDISR3_QBMAIN
+ str w1, [x2, x0]
+ ldr x0, =DCFG_DEVDISR4_OFFSET
+ ldr w1, =DCFG_DEVDISR4_SPI_QSPI
+ str w1, [x2, x0]
+
+ /*
+ * write the GICR_WAKER.ProcessorSleep bits to 1
+ * enable the WakeRequest signal
+ * x3 is cpu mask starting from cpu7
+ */
+ bl get_tot_num_cores
+ sub x0, x0, #1
+ mov x3, #0x1
+ lsl x3, x3, x0
+2:
+ mov x0, x3
+ bl get_gic_rd_base
+ ldr w1, [x0, #GICR_WAKER_OFFSET]
+ orr w1, w1, #GICR_WAKER_SLEEP_BIT
+ str w1, [x0, #GICR_WAKER_OFFSET]
+1:
+ ldr w1, [x0, #GICR_WAKER_OFFSET]
+ cmp w1, #GICR_WAKER_ASLEEP
+ b.ne 1b
+
+ lsr x3, x3, #1
+ cbnz x3, 2b
+
+ /* x3 = pmu base addr */
+
+ /* perform Icache Warming Sequence */
+ ldr x5, =IPSTPCR4_VALUE
+ mov x6, DDR_CNTRL_BASE_ADDR
+ mov x7, #NXP_PMU_ADDR
+ mov x8, #NXP_DCFG_ADDR
+ mov x10, #PMU_IPSTPCR4_OFFSET
+ mov x11, #PMU_IPSTPACK4_OFFSET
+ mov x12, #PMU_IPSTPCR3_OFFSET
+ mov x18, #PMU_IPSTPCR2_OFFSET
+ mov x19, #PMU_IPSTPCR1_OFFSET
+ mov x21, #PMU_IPSTPCR0_OFFSET
+ ldr x22, =DCFG_DEVDISR5_OFFSET
+ ldr x23, =NXP_EPU_ADDR
+ mov x9, #CORE_RESTARTABLE
+ bl final_pwrdown
+
+ /*
+ * disable the WakeRequest signal on cpu 0-7
+ * x3 is cpu mask starting from cpu7
+ */
+ bl get_tot_num_cores
+ sub x0, x0, #1
+ mov x3, #0x1
+ lsl x3, x3, x0
+2:
+ mov x0, x3
+ bl get_gic_rd_base
+ ldr w1, [x0, #GICR_WAKER_OFFSET]
+ bic w1, w1, #GICR_WAKER_SLEEP_BIT
+ str w1, [x0, #GICR_WAKER_OFFSET]
+1:
+ ldr w1, [x0, #GICR_WAKER_OFFSET]
+ cbnz w1, 1b
+
+ lsr x3, x3, #1
+ cbnz x3, 2b
+
+ /* set SGI for secondary core wakeup */
+ ldr x0, =0x1000002
+ msr S3_0_C12_C11_7, x0
+ isb
+ ldr x0, =0x2000004
+ msr S3_0_C12_C11_7, x0
+ isb
+ ldr x0, =0x3000008
+ msr S3_0_C12_C11_7, x0
+ isb
+ ldr x0, =0x4010001
+ msr S3_0_C12_C11_7, x0
+ isb
+ ldr x0, =0x5010002
+ msr S3_0_C12_C11_7, x0
+ isb
+ ldr x0, =0x6010004
+ msr S3_0_C12_C11_7, x0
+ isb
+ ldr x0, =0x7010008
+ msr S3_0_C12_C11_7, x0
+
+ /* enable SEC, QBman spi and qspi */
+ ldr x2, =NXP_DCFG_ADDR
+ str wzr, [x2, #DCFG_DEVDISR1_OFFSET]
+ str wzr, [x2, #DCFG_DEVDISR3_OFFSET]
+ str wzr, [x2, #DCFG_DEVDISR4_OFFSET]
+
+ /* clear POWMGTDCR [STP_PV_EN] */
+ ldr x2, =NXP_POWMGTDCR
+ ldr w4, [x2]
+ bic w4, w4, #0x01
+ str w4, [x2]
+
+ /* restore flextimer/mmc/usb interrupt enabler */
+ ldr x3, =NXP_GICD_ADDR
+ ldp x0, x2, [sp], #16
+ ldr x1, =GICD_ICENABLER_2
+ mvn w0, w0
+ str w0, [x3, x1]
+ ldr x1, =GICD_ICENABLER_3
+ mvn w2, w2
+ str w2, [x3, x1]
+
+ ldp x0, x2, [sp], #16
+ ldr x1, =GICD_ISENABLER_3
+ str w0, [x3, x1]
+ ldr x1, =GICD_ICENABLER_1
+ mvn w2, w2
+ str w0, [x3, x1]
+
+ ldp x0, x2, [sp], #16
+ ldr x1, =GICD_ISENABLER_1
+ str w0, [x3, x1]
+ ldr x1, =GICD_ISENABLER_2
+ str w0, [x3, x1]
+
+ /* restore flextimer/mmc/usb interrupt router */
+ ldr x3, =NXP_GICD_ADDR
+ ldp x0, x2, [sp], #16
+ ldr x1, =GICD_IROUTER113_OFFSET
+ str w2, [x3, x1]
+ ldr x1, =GICD_IROUTER112_OFFSET
+ str w0, [x3, x1]
+ ldp x0, x2, [sp], #16
+ ldr x1, =GICD_IROUTER76_OFFSET
+ str w2, [x3, x1]
+ ldr x1, =GICD_IROUTER60_OFFSET
+ str w0, [x3, x1]
+
+ /* restore EPU registers */
+ ldr x3, =NXP_EPU_ADDR
+ ldp x0, x2, [sp], #16
+ str w2, [x3, #EPU_EPGCR_OFFSET]
+ str w0, [x3, #EPU_EPCTR10_OFFSET]
+ ldp x2, x1, [sp], #16
+ str w1, [x3, #EPU_EPCCR10_OFFSET]
+ str w2, [x3, #EPU_EPIMCR10_OFFSET]
+
+ isb
+ /* Restor LR */
+ ldp x18, x30, [sp], #16
+ ret
+
+/*
+ * part of CPU_SUSPEND
+ * this function performs any SoC-specific cleanup after power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+_soc_sys_exit_pwrdn:
+ mrs x1, SCTLR_EL1
+ orr x1, x1, #SCTLR_I_MASK
+ msr SCTLR_EL1, x1
+ isb
+ ret
+
+/*
+ * this function checks to see if cores which are to be disabled have been
+ * released from reset - if not, it releases them
+ * in: none
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6, x7, x8
+ */
+release_disabled:
+ mov x8, x30
+
+ /* read COREDISABLESR */
+ mov x0, #NXP_DCFG_ADDR
+ ldr w4, [x0, #DCFG_COREDISABLEDSR_OFFSET]
+
+ /* get the number of cpus on this device */
+ mov x6, #PLATFORM_CORE_COUNT
+
+ mov x0, #NXP_RESET_ADDR
+ ldr w5, [x0, #BRR_OFFSET]
+
+ /* load the core mask for the first core */
+ mov x7, #1
+
+ /*
+ * x4 = COREDISABLESR
+ * x5 = BRR
+ * x6 = loop count
+ * x7 = core mask bit
+ */
+2:
+ /* check if the core is to be disabled */
+ tst x4, x7
+ b.eq 1f
+
+ /* see if disabled cores have already been released from reset */
+ tst x5, x7
+ b.ne 1f
+
+ /* if core has not been released, then release it (0-3) */
+ mov x0, x7
+ bl _soc_core_release
+
+ /* record the core state in the data area (0-3) */
+ mov x0, x7
+ mov x1, #CORE_DISABLED
+ bl _setCoreState
+
+1:
+ /* decrement the counter */
+ subs x6, x6, #1
+ b.le 3f
+
+ /* shift the core mask to the next core */
+ lsl x7, x7, #1
+ /* continue */
+ b 2b
+3:
+ mov x30, x8
+ ret
+
+/*
+ * write a register in the DCFG block
+ * in: x0 = offset
+ * in: w1 = value to write
+ * uses x0, x1, x2
+ */
+_write_reg_dcfg:
+ ldr x2, =NXP_DCFG_ADDR
+ str w1, [x2, x0]
+ ret
+
+/*
+ * read a register in the DCFG block
+ * in: x0 = offset
+ * out: w0 = value read
+ * uses x0, x1
+ */
+_read_reg_dcfg:
+ ldr x1, =NXP_DCFG_ADDR
+ ldr w0, [x1, x0]
+ ret
+
+/*
+ * this function sets up the TrustZone Address Space Controller (TZASC)
+ * in: none
+ * out: none
+ * uses x0, x1
+ */
+init_tzpc:
+ /*
+ * set Non Secure access for all devices protected via TZPC
+ * decode Protection-0 Set Reg
+ */
+ ldr x1, =TZPCDECPROT_0_SET_BASE
+ /* set decode region to NS, Bits[7:0] */
+ mov w0, #0xFF
+ str w0, [x1]
+
+ /* decode Protection-1 Set Reg */
+ ldr x1, =TZPCDECPROT_1_SET_BASE
+ /* set decode region to NS, Bits[7:0] */
+ mov w0, #0xFF
+ str w0, [x1]
+
+ /* decode Protection-2 Set Reg */
+ ldr x1, =TZPCDECPROT_2_SET_BASE
+ /* set decode region to NS, Bits[7:0] */
+ mov w0, #0xFF
+ str w0, [x1]
+
+ /*
+ * entire SRAM as NS
+ * secure RAM region size Reg
+ */
+ ldr x1, =NXP_OCRAM_TZPC_ADDR
+ /* 0x00000000 = no secure region */
+ mov w0, #0x00000000
+ str w0, [x1]
+
+ ret
+
+/* this function performs initialization on SecMon for boot services */
+initSecMon:
+ /* read the register hpcomr */
+ ldr x1, =NXP_SNVS_ADDR
+ ldr w0, [x1, #SECMON_HPCOMR_OFFSET]
+ /* turn off secure access for the privileged registers */
+ orr w0, w0, #SECMON_HPCOMR_NPSWAEN
+ /* write back */
+ str w0, [x1, #SECMON_HPCOMR_OFFSET]
+
+ ret
+
+/*
+ * this function returns the redistributor base address for the core specified
+ * in x1
+ * in: x0 - core mask lsb of specified core
+ * out: x0 = redistributor rd base address for specified core
+ * uses x0, x1, x2
+ */
+get_gic_rd_base:
+ /* get the 0-based core number */
+ clz w1, w0
+ mov w2, #0x20
+ sub w2, w2, w1
+ sub w2, w2, #1
+
+ /* x2 = core number / loop counter */
+
+ ldr x0, =NXP_GICR_ADDR
+ mov x1, #GIC_RD_OFFSET
+2:
+ cbz x2, 1f
+ add x0, x0, x1
+ sub x2, x2, #1
+ b 2b
+1:
+ ret
+
+/*
+ * this function returns the redistributor base address for the core specified
+ * in x1
+ * in: x0 - core mask lsb of specified core
+ * out: x0 = redistributor sgi base address for specified core
+ * uses x0, x1, x2
+ */
+get_gic_sgi_base:
+ /* get the 0-based core number */
+ clz w1, w0
+ mov w2, #0x20
+ sub w2, w2, w1
+ sub w2, w2, #1
+
+ /* x2 = core number / loop counter */
+
+ ldr x0, =NXP_GICR_SGI_ADDR
+ mov x1, #GIC_SGI_OFFSET
+2:
+ cbz x2, 1f
+ add x0, x0, x1
+ sub x2, x2, #1
+ b 2b
+1:
+ ret
+
+/*
+ * this function returns an mpidr value for a core, given a core_mask_lsb
+ * in: x0 = core mask lsb
+ * out: x0 = affinity2:affinity1:affinity0, where affinity is 8-bits
+ * uses x0, x1
+ */
+get_mpidr_value:
+ /* convert a core mask to an SoC core number */
+ clz w0, w0
+ mov w1, #31
+ sub w0, w1, w0
+
+ /* w0 = SoC core number */
+
+ mov w1, wzr
+2:
+ cmp w0, #CORES_PER_CLUSTER
+ b.lt 1f
+ sub w0, w0, #CORES_PER_CLUSTER
+ add w1, w1, #MPIDR_CLUSTER
+ b 2b
+
+ /* insert the mpidr core number */
+1:
+ orr w0, w1, w0
+ ret
+
+/*
+ * write a register in the RESET block
+ * in: x0 = offset
+ * in: w1 = value to write
+ * uses x0, x1, x2
+ */
+_write_reg_reset:
+ ldr x2, =NXP_RESET_ADDR
+ str w1, [x2, x0]
+ ret
+
+/*
+ * read a register in the RESET block
+ * in: x0 = offset
+ * out: w0 = value read
+ * uses x0, x1
+ */
+_read_reg_reset:
+ ldr x1, =NXP_RESET_ADDR
+ ldr w0, [x1, x0]
+ ret
+
+/*
+ * this function will pwrdown ddr and the final core - it will do this
+ * by loading itself into the icache and then executing from there
+ * in: x5 = ipstpcr4 (IPSTPCR4_VALUE bic DEVDISR5_MASK)
+ * x6 = DDR_CNTRL_BASE_ADDR
+ * x7 = NXP_PMU_ADDR
+ * x8 = NXP_DCFG_ADDR
+ * x9 = 0, restartable
+ * = 1, non-restartable
+ * x10 = PMU_IPSTPCR4_OFFSET
+ * x11 = PMU_IPSTPACK4_OFFSET
+ * x12 = PMU_IPSTPCR3_OFFSET
+ * x18 = PMU_IPSTPCR2_OFFSET
+ * x19 = PMU_IPSTPCR1_OFFSET
+ * x21 = PMU_IPSTPCR0_OFFSET
+ * w13 = DEVDISR1 saved value
+ * w14 = DEVDISR2 saved value
+ * w15 = DEVDISR3 saved value
+ * w16 = DEVDISR4 saved value
+ * w17 = DEVDISR5 saved value
+ * x22 = DCFG_DEVDISR5_OFFSET
+ * x23 = NXP_EPU_ADDR
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x13, x14, x15, x16, x17
+ * x10, x11, x12, x18, x19, x21, x22, x23
+ */
+
+final_pwrdown:
+ /* delay */
+ mov w4, #0xffffff
+554:
+ sub w4, w4, #1
+ cmp w4, #0
+ b.ge 554b
+
+ mov x0, xzr
+ b touch_line_0
+
+/* 4Kb aligned */
+.align 12
+start_line_0:
+ mov x0, #1
+ /* put ddr in self refresh - start */
+ mov x2, #DDR_SDRAM_CFG_2_FRCSR
+ ldr w3, [x6, #DDR_SDRAM_CFG_2_OFFSET]
+ orr w3, w3, w2
+ /* put ddr in self refresh - end */
+ str w3, [x6, #DDR_SDRAM_CFG_2_OFFSET]
+ nop
+ nop
+touch_line_0:
+ cbz x0, touch_line_1
+
+start_line_1:
+ /* quiesce ddr clocks - start */
+ orr w3, w5, #DCFG_DEVDISR5_MEM
+ mov w4, w3
+ /* quiesce ddr clocks - end */
+ str w4, [x7, x10]
+ mov w3, #DCFG_DEVDISR5_MEM
+ /* poll on ipstpack4 - start */
+ mov x2, #DDR_SLEEP_RETRY_CNT
+ nop
+ nop
+touch_line_1:
+ cbz x0, touch_line_2
+
+start_line_2:
+ /* x11 = PMU_IPSTPACK4_OFFSET */
+ ldr w1, [x7, x11]
+ tst w1, w3
+ b.ne 5f
+ subs x2, x2, #1
+ /* poll on ipstpack4 - end */
+ b.gt start_line_2
+
+ /* if we get here, we have a timeout err */
+ mov w4, w5
+ /* x10 = PMU_IPSTPCR4_OFFSET re-enable ddr clks interface */
+ str w4, [x7, x10]
+touch_line_2:
+ cbz x0, touch_line_3
+
+start_line_3:
+ /* load error code */
+ mov x0, #ERROR_DDR_SLEEP
+ b 2f
+5:
+ wfe
+ ldr w1, [x23, #EPU_EPCTR10_OFFSET]
+ cbz w1, 5b
+
+ mov w4, w5
+touch_line_3:
+ cbz x0, touch_line_4
+
+start_line_4:
+ /* re-enable ddr in devdisr5 */
+ str w4, [x8, x22]
+ /* re-enable ddr clk in ipstpcr4 */
+ str w4, [x7, x10]
+13:
+ /* poll on ipstpack4 - start */
+ ldr w1, [x7, x11]
+ tst w1, w3
+ b.eq 2f
+ nop
+ b 13b
+ /* poll on ipstpack4 - end */
+2:
+touch_line_4:
+ cbz x0, touch_line_5
+
+start_line_5:
+ /* take ddr out-of self refresh - start */
+ mov x2, #DDR_SDRAM_CFG_2_FRCSR
+ ldr w3, [x6, #DDR_SDRAM_CFG_2_OFFSET]
+ mov w4, w3
+ bic w4, w4, w2
+ mov w3, w4
+ /* wait for ddr cntrlr clock- start */
+ mov x1, #DDR_SLEEP_RETRY_CNT
+3:
+ subs x1, x1, #1
+touch_line_5:
+ cbz x0, touch_line_6
+
+start_line_6:
+ /* wait for ddr cntrlr clock - end */
+ b.gt 3b
+ /* take ddr out-of self refresh - end */
+ str w3, [x6, #DDR_SDRAM_CFG_2_OFFSET]
+ mov w1, w17
+ /* reset devdisr5 */
+ str w1, [x8, #DCFG_DEVDISR5_OFFSET]
+ mov w1, w16
+ /* reset devdisr4 */
+ str w1, [x8, #DCFG_DEVDISR4_OFFSET]
+ mov w1, w15
+touch_line_6:
+ cbz x0, touch_line_7
+
+start_line_7:
+ /* reset devdisr3 */
+ str w1, [x8, #DCFG_DEVDISR3_OFFSET]
+ mov w1, w14
+ /* reset devdisr2 */
+ str w1, [x8, #DCFG_DEVDISR2_OFFSET]
+ mov w1, w13
+ /* reset devdisr1 */
+ str w1, [x8, #DCFG_DEVDISR1_OFFSET]
+ /* reset ipstpcr4 */
+ str wzr, [x7, x10]
+ /* reset ipstpcr3 */
+ str wzr, [x7, x12]
+touch_line_7:
+ cbz x0, touch_line_8
+
+start_line_8:
+ /* reset ipstpcr2 */
+ str wzr, [x7, x18]
+ /* reset ipstpcr1 */
+ str wzr, [x7, x19]
+ /* reset ipstpcr0 */
+ str wzr, [x7, x21]
+
+touch_line_8:
+ cbz x0, touch_line_9
+
+start_line_9:
+ b continue_restart
+touch_line_9:
+ cbz x0, start_line_0
+
+/* execute here after ddr is back up */
+continue_restart:
+ /*
+ * if x0 = 1, all is well
+ * if x0 < 1, we had an error
+ */
+ cmp x0, #1
+ b.ne 4f
+ mov x0, #0
+4:
+ ret
diff --git a/plat/nxp/soc-ls1088a/aarch64/ls1088a_helpers.S b/plat/nxp/soc-ls1088a/aarch64/ls1088a_helpers.S
new file mode 100644
index 0000000..890cf81
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/aarch64/ls1088a_helpers.S
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .globl plat_secondary_cold_boot_setup
+ .globl plat_is_my_cpu_primary
+ .globl plat_reset_handler
+ .globl platform_mem_init
+
+func platform_mem1_init
+ ret
+endfunc platform_mem1_init
+
+func platform_mem_init
+ ret
+endfunc platform_mem_init
+
+func apply_platform_errata
+ ret
+endfunc apply_platform_errata
+
+func plat_reset_handler
+ mov x29, x30
+ bl apply_platform_errata
+
+#if defined(IMAGE_BL31)
+ ldr x0, =POLICY_SMMU_PAGESZ_64K
+ cbz x0, 1f
+ /* Set the SMMU page size in the sACR register */
+ bl _set_smmu_pagesz_64
+#endif
+1:
+ mov x30, x29
+ ret
+endfunc 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 e.g
+ * mark the cpu's presence, mechanism to place it in a
+ * holding pen etc.
+ */
+func plat_secondary_cold_boot_setup
+ /* ls1088a does not do cold boot for secondary CPU */
+cb_panic:
+ b cb_panic
+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
+ mrs x0, mpidr_el1
+ and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+ cmp x0, 0x0
+ cset w0, eq
+ ret
+endfunc plat_is_my_cpu_primary
diff --git a/plat/nxp/soc-ls1088a/include/soc.h b/plat/nxp/soc-ls1088a/include/soc.h
new file mode 100644
index 0000000..eb36c2e
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/include/soc.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOC_H
+#define SOC_H
+
+/* Chassis specific defines - common across SoC's of a particular platform */
+#include "dcfg_lsch3.h"
+#include "soc_default_base_addr.h"
+#include "soc_default_helper_macros.h"
+
+/*
+ * SVR Definition of LS1088A
+ * A: without security
+ * AE: with security
+ * (not include major and minor rev)
+ */
+#define SVR_LS1044A 0x870323
+#define SVR_LS1044AE 0x870322
+#define SVR_LS1048A 0x870321
+#define SVR_LS1048AE 0x870320
+#define SVR_LS1084A 0x870303
+#define SVR_LS1084AE 0x870302
+#define SVR_LS1088A 0x870301
+#define SVR_LS1088AE 0x870300
+
+#define SVR_WO_E 0xFFFFFE
+
+/* Number of cores in platform */
+#define NUMBER_OF_CLUSTERS 2
+#define CORES_PER_CLUSTER 4
+#define PLATFORM_CORE_COUNT (NUMBER_OF_CLUSTERS * CORES_PER_CLUSTER)
+
+/* set to 0 if the clusters are not symmetrical */
+#define SYMMETRICAL_CLUSTERS 1
+
+
+#define NUM_DRAM_REGIONS 2
+#define NXP_DRAM0_ADDR 0x80000000
+#define NXP_DRAM0_MAX_SIZE 0x80000000 /* 2 GB */
+
+#define NXP_DRAM1_ADDR 0x8080000000
+#define NXP_DRAM1_MAX_SIZE 0x7F80000000 /* 510 G */
+
+/* DRAM0 Size defined in platform_def.h */
+#define NXP_DRAM0_SIZE PLAT_DEF_DRAM0_SIZE
+
+#define NXP_POWMGTDCR 0x700123C20
+
+/* epu register offsets and values */
+#define EPU_EPGCR_OFFSET 0x0
+#define EPU_EPIMCR10_OFFSET 0x128
+#define EPU_EPCTR10_OFFSET 0xa28
+#define EPU_EPCCR10_OFFSET 0x828
+
+#ifdef EPU_EPCCR10_VAL
+#undef EPU_EPCCR10_VAL
+#endif
+#define EPU_EPCCR10_VAL 0xf2800000
+
+#define EPU_EPIMCR10_VAL 0xba000000
+#define EPU_EPCTR10_VAL 0x0
+#define EPU_EPGCR_VAL (1 << 31)
+
+/* pmu register offsets and values */
+#define PMU_PCPW20SR_OFFSET 0x830
+#define PMU_CLAINACTSETR_OFFSET 0x1100
+#define PMU_CLAINACTCLRR_OFFSET 0x1104
+#define PMU_CLSINACTSETR_OFFSET 0x1108
+#define PMU_CLSINACTCLRR_OFFSET 0x110C
+#define PMU_CLL2FLUSHSETR_OFFSET 0x1110
+#define PMU_CLSL2FLUSHCLRR_OFFSET 0x1114
+#define PMU_CLL2FLUSHSR_OFFSET 0x1118
+#define PMU_POWMGTCSR_OFFSET 0x4000
+#define PMU_IPPDEXPCR0_OFFSET 0x4040
+#define PMU_IPPDEXPCR1_OFFSET 0x4044
+#define PMU_IPPDEXPCR2_OFFSET 0x4048
+#define PMU_IPPDEXPCR3_OFFSET 0x404C
+#define PMU_IPPDEXPCR4_OFFSET 0x4050
+#define PMU_IPPDEXPCR5_OFFSET 0x4054
+#define PMU_IPSTPCR0_OFFSET 0x4120
+#define PMU_IPSTPCR1_OFFSET 0x4124
+#define PMU_IPSTPCR2_OFFSET 0x4128
+#define PMU_IPSTPCR3_OFFSET 0x412C
+#define PMU_IPSTPCR4_OFFSET 0x4130
+#define PMU_IPSTPCR5_OFFSET 0x4134
+#define PMU_IPSTPCR6_OFFSET 0x4138
+#define PMU_IPSTPACK0_OFFSET 0x4140
+#define PMU_IPSTPACK1_OFFSET 0x4144
+#define PMU_IPSTPACK2_OFFSET 0x4148
+#define PMU_IPSTPACK3_OFFSET 0x414C
+#define PMU_IPSTPACK4_OFFSET 0x4150
+#define PMU_IPSTPACK5_OFFSET 0x4154
+#define PMU_IPSTPACK6_OFFSET 0x4158
+#define PMU_POWMGTCSR_VAL (1 << 20)
+
+#define IPPDEXPCR0_MASK 0xFFFFFFFF
+#define IPPDEXPCR1_MASK 0xFFFFFFFF
+#define IPPDEXPCR2_MASK 0xFFFFFFFF
+#define IPPDEXPCR3_MASK 0xFFFFFFFF
+#define IPPDEXPCR4_MASK 0xFFFFFFFF
+#define IPPDEXPCR5_MASK 0xFFFFFFFF
+
+/* DEVDISR5_FLX_TMR */
+#define IPPDEXPCR_FLX_TMR 0x00004000
+#define DEVDISR5_FLX_TMR 0x00004000
+
+#define IPSTPCR0_VALUE 0x0041310C
+#define IPSTPCR1_VALUE 0x000003FF
+#define IPSTPCR2_VALUE 0x00013006
+
+/* Dont' stop UART */
+#define IPSTPCR3_VALUE 0x0000033A
+
+#define IPSTPCR4_VALUE 0x00103300
+#define IPSTPCR5_VALUE 0x00000001
+#define IPSTPCR6_VALUE 0x00000000
+
+
+#define TZPC_BLOCK_SIZE 0x1000
+
+/* PORSR1 */
+#define PORSR1_RCW_MASK 0xFF800000
+#define PORSR1_RCW_SHIFT 23
+
+/* CFG_RCW_SRC[6:0] */
+#define RCW_SRC_TYPE_MASK 0x70
+
+/* RCW SRC NOR */
+#define NOR_16B_VAL 0x20
+
+/*
+ * RCW SRC Serial Flash
+ * 1. SERAIL NOR (QSPI)
+ * 2. OTHERS (SD/MMC, SPI, I2C1)
+ */
+#define RCW_SRC_SERIAL_MASK 0x7F
+#define QSPI_VAL 0x62
+#define SDHC_VAL 0x40
+#define EMMC_VAL 0x41
+
+/*
+ * Required LS standard platform porting definitions
+ * for CCN-504 - Read from RN-F node ID register
+ */
+#define PLAT_CLUSTER_TO_CCN_ID_MAP 1, 9, 11, 19
+
+/* Defines required for using XLAT tables from ARM common code */
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 40)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 40)
+
+/*
+ * Clock Divisors
+ */
+#define NXP_PLATFORM_CLK_DIVIDER 1
+#define NXP_UART_CLK_DIVIDER 2
+
+/* dcfg register offsets and values */
+#define DCFG_DEVDISR1_OFFSET 0x70
+#define DCFG_DEVDISR2_OFFSET 0x74
+#define DCFG_DEVDISR3_OFFSET 0x78
+#define DCFG_DEVDISR5_OFFSET 0x80
+#define DCFG_DEVDISR6_OFFSET 0x84
+
+#define DCFG_DEVDISR1_SEC (1 << 22)
+#define DCFG_DEVDISR3_QBMAIN (1 << 12)
+#define DCFG_DEVDISR4_SPI_QSPI (1 << 4 | 1 << 5)
+#define DCFG_DEVDISR5_MEM (1 << 0)
+
+#define DEVDISR1_VALUE 0x0041310c
+#define DEVDISR2_VALUE 0x000003ff
+#define DEVDISR3_VALUE 0x00013006
+#define DEVDISR4_VALUE 0x0000033e
+#define DEVDISR5_VALUE 0x00103300
+#define DEVDISR6_VALUE 0x00000001
+
+/*
+ * pwr mgmt features supported in the soc-specific code:
+ * value == 0x0, the soc code does not support this feature
+ * value != 0x0, the soc code supports this feature
+ */
+#define SOC_CORE_RELEASE 0x1
+#define SOC_CORE_RESTART 0x1
+#define SOC_CORE_OFF 0x1
+#define SOC_CORE_STANDBY 0x1
+#define SOC_CORE_PWR_DWN 0x1
+#define SOC_CLUSTER_STANDBY 0x1
+#define SOC_CLUSTER_PWR_DWN 0x1
+#define SOC_SYSTEM_STANDBY 0x1
+#define SOC_SYSTEM_PWR_DWN 0x1
+#define SOC_SYSTEM_OFF 0x1
+#define SOC_SYSTEM_RESET 0x1
+
+#define SYSTEM_PWR_DOMAINS 1
+#define PLAT_NUM_PWR_DOMAINS (PLATFORM_CORE_COUNT + \
+ NUMBER_OF_CLUSTERS + \
+ SYSTEM_PWR_DOMAINS)
+
+/* Power state coordination occurs at the system level */
+#define PLAT_PD_COORD_LVL MPIDR_AFFLVL2
+#define PLAT_MAX_PWR_LVL PLAT_PD_COORD_LVL
+
+/* Local power state for power domains in Run state */
+#define LS_LOCAL_STATE_RUN PSCI_LOCAL_STATE_RUN
+
+/* define retention state */
+#define PLAT_MAX_RET_STATE (PSCI_LOCAL_STATE_RUN + 1)
+#define LS_LOCAL_STATE_RET PLAT_MAX_RET_STATE
+
+/* define power-down state */
+#define PLAT_MAX_OFF_STATE (PLAT_MAX_RET_STATE + 1)
+#define LS_LOCAL_STATE_OFF PLAT_MAX_OFF_STATE
+
+#ifndef __ASSEMBLER__
+/* CCI slave interfaces */
+static const int cci_map[] = {
+ 3,
+ 4,
+};
+void soc_init_lowlevel(void);
+void soc_init_percpu(void);
+void _soc_set_start_addr(unsigned long addr);
+void _set_platform_security(void);
+#endif
+
+#endif /* SOC_H */
diff --git a/plat/nxp/soc-ls1088a/ls1088aqds/ddr_init.c b/plat/nxp/soc-ls1088a/ls1088aqds/ddr_init.c
new file mode 100644
index 0000000..b7397ba
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/ls1088aqds/ddr_init.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <ddr.h>
+#include <utils.h>
+
+#include <errata.h>
+#include <platform_def.h>
+
+#ifdef CONFIG_STATIC_DDR
+#error No static value defined
+#endif
+
+static const struct rc_timing rce[] = {
+ {U(1600), U(8), U(8)},
+ {U(1867), U(8), U(8)},
+ {U(2134), U(8), U(9)},
+ {}
+};
+
+static const struct board_timing udimm[] = {
+ {U(0x04), rce, U(0x01020307), U(0x08090b06)},
+};
+
+int ddr_board_options(struct ddr_info *priv)
+{
+ int ret;
+ struct memctl_opt *popts = &priv->opt;
+
+ if (popts->rdimm != 0) {
+ debug("RDIMM parameters not set.\n");
+ return -EINVAL;
+ }
+
+ ret = cal_board_params(priv, udimm, ARRAY_SIZE(udimm));
+ if (ret != 0) {
+ return ret;
+ }
+
+ popts->addr_hash = 1;
+ popts->cpo_sample = U(0x7b);
+ popts->ddr_cdr1 = DDR_CDR1_DHC_EN |
+ DDR_CDR1_ODT(DDR_CDR_ODT_60ohm);
+ popts->ddr_cdr2 = DDR_CDR2_ODT(DDR_CDR_ODT_60ohm) |
+ DDR_CDR2_VREF_TRAIN_EN |
+ DDR_CDR2_VREF_RANGE_2;
+
+ return 0;
+}
+
+long long init_ddr(void)
+{
+ int spd_addr[] = { NXP_SPD_EEPROM0 };
+ struct ddr_info info;
+ struct sysinfo sys;
+ long long dram_size;
+
+ zeromem(&sys, sizeof(sys));
+ get_clocks(&sys);
+ debug("platform clock %lu\n", sys.freq_platform);
+ debug("DDR PLL %lu\n", sys.freq_ddr_pll0);
+
+ zeromem(&info, sizeof(struct ddr_info));
+ info.num_ctlrs = NUM_OF_DDRC;
+ info.dimm_on_ctlr = DDRC_NUM_DIMM;
+ info.clk = get_ddr_freq(&sys, 0);
+ info.spd_addr = spd_addr;
+ info.ddr[0] = (void *)NXP_DDR_ADDR;
+
+ dram_size = dram_init(&info);
+ if (dram_size < 0) {
+ ERROR("DDR init failed.\n");
+ }
+
+ erratum_a008850_post();
+
+ return dram_size;
+}
diff --git a/plat/nxp/soc-ls1088a/ls1088aqds/plat_def.h b/plat/nxp/soc-ls1088a/ls1088aqds/plat_def.h
new file mode 100644
index 0000000..ebd3a26
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/ls1088aqds/plat_def.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_DEF_H
+#define PLAT_DEF_H
+
+#include <arch.h>
+/*
+ * Required without TBBR.
+ * To include the defines for DDR PHY
+ * Images.
+ */
+#include <tbbr_img_def.h>
+
+#include <policy.h>
+#include <soc.h>
+
+#define NXP_SPD_EEPROM0 0x51
+
+#define NXP_SYSCLK_FREQ 100000000
+#define NXP_DDRCLK_FREQ 100000000
+
+/* UART related definition */
+#define NXP_CONSOLE_ADDR NXP_UART_ADDR
+#define NXP_CONSOLE_BAUDRATE 115200
+
+/* Size of cacheable stacks */
+#if defined(IMAGE_BL2)
+#if defined(TRUSTED_BOARD_BOOT)
+#define PLATFORM_STACK_SIZE 0x2000
+#else
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+#elif defined(IMAGE_BL31)
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+
+#define BL2_START NXP_OCRAM_ADDR
+#define BL2_LIMIT (NXP_OCRAM_ADDR + NXP_OCRAM_SIZE)
+#define BL2_NOLOAD_START NXP_OCRAM_ADDR
+#define BL2_NOLOAD_LIMIT BL2_BASE
+
+/* IO defines as needed by IO driver framework */
+#define MAX_IO_DEVICES 4
+#define MAX_IO_BLOCK_DEVICES 1
+#define MAX_IO_HANDLES 4
+
+/*
+ * FIP image defines - Offset at which FIP Image would be present
+ * Image would include Bl31 , Bl33 and Bl32 (optional)
+ */
+#ifdef POLICY_FUSE_PROVISION
+#define MAX_FIP_DEVICES 2
+#endif
+
+#ifndef MAX_FIP_DEVICES
+#define MAX_FIP_DEVICES 1
+#endif
+
+#define BL32_IRQ_SEC_PHY_TIMER 29
+#define BL31_WDOG_SEC 89
+
+/*
+ * ID of the secure physical generic timer interrupt used by the BL32.
+ */
+#define PLAT_LS_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(BL32_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL)
+
+/* SGI 15 and Secure watchdog interrupts assigned to Group 0 */
+#define PLAT_LS_G0_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(BL31_WDOG_SEC, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(15, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL)
+
+
+#endif /* PLAT_DEF_H */
diff --git a/plat/nxp/soc-ls1088a/ls1088aqds/platform.c b/plat/nxp/soc-ls1088a/ls1088aqds/platform.c
new file mode 100644
index 0000000..8b3eada
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/ls1088aqds/platform.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_common.h>
+
+#pragma weak board_enable_povdd
+#pragma weak board_disable_povdd
+
+bool board_enable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool board_disable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
diff --git a/plat/nxp/soc-ls1088a/ls1088aqds/platform.mk b/plat/nxp/soc-ls1088a/ls1088aqds/platform.mk
new file mode 100644
index 0000000..97ccf26
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/ls1088aqds/platform.mk
@@ -0,0 +1,31 @@
+#
+# Copyright 2022 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# board-specific build parameters
+BOOT_MODE ?= qspi
+BOARD := ls1088aqds
+
+# DDR Compilation Configs
+NUM_OF_DDRC := 1
+DDRC_NUM_DIMM := 1
+DDR_ECC_EN := yes
+
+# On-Board Flash Details
+QSPI_FLASH_SZ := 0x4000000
+NOR_FLASH_SZ := 0x20000000
+
+BL2_SOURCES += ${BOARD_PATH}/ddr_init.c \
+ ${BOARD_PATH}/platform.c
+
+SUPPORTED_BOOT_MODE := qspi \
+ sd \
+ nor
+
+# Adding platform board build info
+include plat/nxp/common/plat_make_helper/plat_common_def.mk
+
+# Adding SoC build info
+include plat/nxp/soc-ls1088a/soc.mk
diff --git a/plat/nxp/soc-ls1088a/ls1088aqds/platform_def.h b/plat/nxp/soc-ls1088a/ls1088aqds/platform_def.h
new file mode 100644
index 0000000..7daf1c0
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/ls1088aqds/platform_def.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <plat_def.h>
+#include <plat_default_def.h>
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/nxp/soc-ls1088a/ls1088aqds/policy.h b/plat/nxp/soc-ls1088a/ls1088aqds/policy.h
new file mode 100644
index 0000000..0eaafae
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/ls1088aqds/policy.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef POLICY_H
+#define POLICY_H
+
+/*
+ * Set this to 0x0 to leave the default SMMU page size in sACR
+ * Set this to 0x1 to change the SMMU page size to 64K
+ */
+#define POLICY_SMMU_PAGESZ_64K 0x1
+
+#endif /* POLICY_H */
diff --git a/plat/nxp/soc-ls1088a/ls1088ardb/ddr_init.c b/plat/nxp/soc-ls1088a/ls1088ardb/ddr_init.c
new file mode 100644
index 0000000..c88583f
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/ls1088ardb/ddr_init.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <ddr.h>
+#include <utils.h>
+
+#include <errata.h>
+#include <platform_def.h>
+
+#ifdef CONFIG_STATIC_DDR
+#error No static value defined
+#endif
+
+static const struct rc_timing rce[] = {
+ {U(1600), U(8), U(8)},
+ {U(1867), U(8), U(8)},
+ {U(2134), U(8), U(9)},
+ {}
+};
+
+static const struct board_timing udimm[] = {
+ {U(0x04), rce, U(0x01030508), U(0x090b0d06)},
+ {U(0x1f), rce, U(0x01030508), U(0x090b0d06)},
+};
+
+int ddr_board_options(struct ddr_info *priv)
+{
+ int ret;
+ struct memctl_opt *popts = &priv->opt;
+
+ if (popts->rdimm != 0) {
+ debug("RDIMM parameters not set.\n");
+ return -EINVAL;
+ }
+
+ ret = cal_board_params(priv, udimm, ARRAY_SIZE(udimm));
+ if (ret != 0) {
+ return ret;
+ }
+
+ popts->addr_hash = 1;
+ popts->cpo_sample = U(0x7b);
+ popts->ddr_cdr1 = DDR_CDR1_DHC_EN |
+ DDR_CDR1_ODT(DDR_CDR_ODT_60ohm);
+ popts->ddr_cdr2 = DDR_CDR2_ODT(DDR_CDR_ODT_60ohm) |
+ DDR_CDR2_VREF_TRAIN_EN |
+ DDR_CDR2_VREF_RANGE_2;
+
+ return 0;
+}
+
+long long init_ddr(void)
+{
+ int spd_addr[] = { NXP_SPD_EEPROM0 };
+ struct ddr_info info;
+ struct sysinfo sys;
+ long long dram_size;
+
+ zeromem(&sys, sizeof(sys));
+ get_clocks(&sys);
+ debug("platform clock %lu\n", sys.freq_platform);
+ debug("DDR PLL %lu\n", sys.freq_ddr_pll0);
+
+ zeromem(&info, sizeof(struct ddr_info));
+ info.num_ctlrs = NUM_OF_DDRC;
+ info.dimm_on_ctlr = DDRC_NUM_DIMM;
+ info.clk = get_ddr_freq(&sys, 0);
+ info.spd_addr = spd_addr;
+ info.ddr[0] = (void *)NXP_DDR_ADDR;
+
+ dram_size = dram_init(&info);
+
+ if (dram_size < 0) {
+ ERROR("DDR init failed.\n");
+ }
+
+ erratum_a008850_post();
+
+ return dram_size;
+}
diff --git a/plat/nxp/soc-ls1088a/ls1088ardb/plat_def.h b/plat/nxp/soc-ls1088a/ls1088ardb/plat_def.h
new file mode 100644
index 0000000..a6b14fe
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/ls1088ardb/plat_def.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_DEF_H
+#define PLAT_DEF_H
+
+#include <arch.h>
+/*
+ * Required without TBBR.
+ * To include the defines for DDR PHY
+ * Images.
+ */
+#include <tbbr_img_def.h>
+
+#include <policy.h>
+#include <soc.h>
+
+#define NXP_SPD_EEPROM0 0x51
+
+#define NXP_SYSCLK_FREQ 100000000
+#define NXP_DDRCLK_FREQ 100000000
+
+/* UART related definition */
+#define NXP_CONSOLE_ADDR NXP_UART_ADDR
+#define NXP_CONSOLE_BAUDRATE 115200
+
+/* Size of cacheable stacks */
+#if defined(IMAGE_BL2)
+#if defined(TRUSTED_BOARD_BOOT)
+#define PLATFORM_STACK_SIZE 0x2000
+#else
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+#elif defined(IMAGE_BL31)
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+
+#define BL2_START NXP_OCRAM_ADDR
+#define BL2_LIMIT (NXP_OCRAM_ADDR + NXP_OCRAM_SIZE)
+#define BL2_NOLOAD_START NXP_OCRAM_ADDR
+#define BL2_NOLOAD_LIMIT BL2_BASE
+
+/* IO defines as needed by IO driver framework */
+#define MAX_IO_DEVICES 4
+#define MAX_IO_BLOCK_DEVICES 1
+#define MAX_IO_HANDLES 4
+
+/*
+ * FIP image defines - Offset at which FIP Image would be present
+ * Image would include Bl31 , Bl33 and Bl32 (optional)
+ */
+#ifdef POLICY_FUSE_PROVISION
+#define MAX_FIP_DEVICES 2
+#endif
+
+#ifndef MAX_FIP_DEVICES
+#define MAX_FIP_DEVICES 1
+#endif
+
+#define BL32_IRQ_SEC_PHY_TIMER 29
+#define BL31_WDOG_SEC 89
+
+/*
+ * ID of the secure physical generic timer interrupt used by the BL32.
+ */
+#define PLAT_LS_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(BL32_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL)
+
+/* SGI 15 and Secure watchdog interrupts assigned to Group 0 */
+#define PLAT_LS_G0_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(BL31_WDOG_SEC, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(15, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL)
+
+#endif /* PLAT_DEF_H */
diff --git a/plat/nxp/soc-ls1088a/ls1088ardb/platform.c b/plat/nxp/soc-ls1088a/ls1088ardb/platform.c
new file mode 100644
index 0000000..8b3eada
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/ls1088ardb/platform.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_common.h>
+
+#pragma weak board_enable_povdd
+#pragma weak board_disable_povdd
+
+bool board_enable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool board_disable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
diff --git a/plat/nxp/soc-ls1088a/ls1088ardb/platform.mk b/plat/nxp/soc-ls1088a/ls1088ardb/platform.mk
new file mode 100644
index 0000000..6884faf
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/ls1088ardb/platform.mk
@@ -0,0 +1,30 @@
+#
+# Copyright 2022 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# board-specific build parameters
+BOOT_MODE ?= qspi
+BOARD := ls1088ardb
+
+# DDR Compilation Configs
+NUM_OF_DDRC := 1
+DDRC_NUM_DIMM := 1
+DDR_ECC_EN := yes
+
+# On-Board Flash Details
+QSPI_FLASH_SZ := 0x4000000
+
+# Adding Platform files build files
+BL2_SOURCES += ${BOARD_PATH}/ddr_init.c \
+ ${BOARD_PATH}/platform.c
+
+SUPPORTED_BOOT_MODE := qspi \
+ sd
+
+# Adding platform board build info
+include plat/nxp/common/plat_make_helper/plat_common_def.mk
+
+# Adding SoC build info
+include plat/nxp/soc-ls1088a/soc.mk
diff --git a/plat/nxp/soc-ls1088a/ls1088ardb/platform_def.h b/plat/nxp/soc-ls1088a/ls1088ardb/platform_def.h
new file mode 100644
index 0000000..7daf1c0
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/ls1088ardb/platform_def.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <plat_def.h>
+#include <plat_default_def.h>
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/nxp/soc-ls1088a/ls1088ardb/policy.h b/plat/nxp/soc-ls1088a/ls1088ardb/policy.h
new file mode 100644
index 0000000..af206f9
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/ls1088ardb/policy.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef POLICY_H
+#define POLICY_H
+
+/* Set this to 0x0 to leave the default SMMU page size in sACR
+ * Set this to 0x1 to change the SMMU page size to 64K
+ */
+#define POLICY_SMMU_PAGESZ_64K 0x1
+
+#endif /* POLICY_H */
diff --git a/plat/nxp/soc-ls1088a/soc.c b/plat/nxp/soc-ls1088a/soc.c
new file mode 100644
index 0000000..5f9f313
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/soc.c
@@ -0,0 +1,397 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <caam.h>
+#include <cci.h>
+#include <common/debug.h>
+#include <dcfg.h>
+#ifdef I2C_INIT
+#include <i2c.h>
+#endif
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <ls_interconnect.h>
+#if TRUSTED_BOARD_BOOT
+#include <nxp_smmu.h>
+#endif
+#include <nxp_timer.h>
+#include <plat_console.h>
+#include <plat_gic.h>
+#include <plat_tzc400.h>
+#include <pmu.h>
+#if defined(NXP_SFP_ENABLED)
+#include <sfp.h>
+#endif
+
+#include <errata.h>
+#ifdef CONFIG_OCRAM_ECC_EN
+#include <ocram.h>
+#endif
+#include <plat_common.h>
+#include <platform_def.h>
+#include <soc.h>
+
+static unsigned char _power_domain_tree_desc[NUMBER_OF_CLUSTERS + 2];
+static struct soc_type soc_list[] = {
+ SOC_ENTRY(LS1044A, LS1044A, 1, 4),
+ SOC_ENTRY(LS1044AE, LS1044AE, 1, 4),
+ SOC_ENTRY(LS1048A, LS1048A, 1, 4),
+ SOC_ENTRY(LS1048AE, LS1048AE, 1, 4),
+ SOC_ENTRY(LS1084A, LS1084A, 2, 4),
+ SOC_ENTRY(LS1084AE, LS1084AE, 2, 4),
+ SOC_ENTRY(LS1088A, LS1088A, 2, 4),
+ SOC_ENTRY(LS1088AE, LS1088AE, 2, 4),
+};
+
+static dcfg_init_info_t dcfg_init_data = {
+ .g_nxp_dcfg_addr = NXP_DCFG_ADDR,
+ .nxp_sysclk_freq = NXP_SYSCLK_FREQ,
+ .nxp_ddrclk_freq = NXP_DDRCLK_FREQ,
+ .nxp_plat_clk_divider = NXP_PLATFORM_CLK_DIVIDER,
+};
+
+/*
+ * This function dynamically constructs the topology according to
+ * SoC Flavor and returns it.
+ */
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ unsigned int i;
+ uint8_t num_clusters, cores_per_cluster;
+
+ get_cluster_info(soc_list, ARRAY_SIZE(soc_list), &num_clusters, &cores_per_cluster);
+
+ /*
+ * The highest level is the system level. The next level is constituted
+ * by clusters and then cores in clusters.
+ */
+ _power_domain_tree_desc[0] = 1;
+ _power_domain_tree_desc[1] = num_clusters;
+
+ for (i = 0; i < _power_domain_tree_desc[1]; i++) {
+ _power_domain_tree_desc[i + 2] = cores_per_cluster;
+ }
+
+
+ return _power_domain_tree_desc;
+}
+
+CASSERT(NUMBER_OF_CLUSTERS && NUMBER_OF_CLUSTERS <= 256,
+ assert_invalid_ls1088a_cluster_count);
+
+/*
+ * 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 CORES_PER_CLUSTER;
+}
+
+/*
+ * This function returns the total number of cores in the SoC
+ */
+unsigned int get_tot_num_cores(void)
+{
+ uint8_t num_clusters, cores_per_cluster;
+
+ get_cluster_info(soc_list, ARRAY_SIZE(soc_list), &num_clusters, &cores_per_cluster);
+
+ return (num_clusters * cores_per_cluster);
+}
+
+/*
+ * This function returns the PMU IDLE Cluster mask.
+ */
+unsigned int get_pmu_idle_cluster_mask(void)
+{
+ uint8_t num_clusters, cores_per_cluster;
+
+ get_cluster_info(soc_list, ARRAY_SIZE(soc_list), &num_clusters, &cores_per_cluster);
+
+ return ((1 << num_clusters) - 2);
+}
+
+/*
+ * This function returns the PMU Flush Cluster mask.
+ */
+unsigned int get_pmu_flush_cluster_mask(void)
+{
+ uint8_t num_clusters, cores_per_cluster;
+
+ get_cluster_info(soc_list, ARRAY_SIZE(soc_list), &num_clusters, &cores_per_cluster);
+
+ return ((1 << num_clusters) - 2);
+}
+
+/*
+ * This function returns the PMU IDLE Core mask.
+ */
+unsigned int get_pmu_idle_core_mask(void)
+{
+ return ((1 << get_tot_num_cores()) - 2);
+}
+
+#ifdef IMAGE_BL2
+
+void soc_bl2_prepare_exit(void)
+{
+#if defined(NXP_SFP_ENABLED) && defined(DISABLE_FUSE_WRITE)
+ set_sfp_wr_disable();
+#endif
+}
+
+void soc_preload_setup(void)
+{
+
+}
+
+/*
+ * This function returns the boot device based on RCW_SRC
+ */
+enum boot_device get_boot_dev(void)
+{
+ enum boot_device src = BOOT_DEVICE_NONE;
+ uint32_t porsr1;
+ uint32_t rcw_src, val;
+
+ porsr1 = read_reg_porsr1();
+
+ rcw_src = (porsr1 & PORSR1_RCW_MASK) >> PORSR1_RCW_SHIFT;
+
+ /* RCW SRC NOR */
+ val = rcw_src & RCW_SRC_TYPE_MASK;
+ if (val == NOR_16B_VAL) {
+ src = BOOT_DEVICE_IFC_NOR;
+ INFO("RCW BOOT SRC is IFC NOR\n");
+ } else {
+ val = rcw_src & RCW_SRC_SERIAL_MASK;
+ switch (val) {
+ case QSPI_VAL:
+ src = BOOT_DEVICE_QSPI;
+ INFO("RCW BOOT SRC is QSPI\n");
+ break;
+ case SDHC_VAL:
+ src = BOOT_DEVICE_EMMC;
+ INFO("RCW BOOT SRC is SD/EMMC\n");
+ break;
+ case EMMC_VAL:
+ src = BOOT_DEVICE_EMMC;
+ INFO("RCW BOOT SRC is SD/EMMC\n");
+ break;
+ default:
+ src = BOOT_DEVICE_NONE;
+ }
+ }
+
+ return src;
+}
+
+/*
+ * This function sets up access permissions on memory regions
+ */
+void soc_mem_access(void)
+{
+ dram_regions_info_t *info_dram_regions = get_dram_regions_info();
+ int i = 0;
+ struct tzc400_reg tzc400_reg_list[MAX_NUM_TZC_REGION];
+ int dram_idx, index = 1;
+
+ for (dram_idx = 0; dram_idx < info_dram_regions->num_dram_regions;
+ dram_idx++) {
+ if (info_dram_regions->region[i].size == 0) {
+ ERROR("DDR init failure, or");
+ ERROR("DRAM regions not populated correctly.\n");
+ break;
+ }
+
+ index = populate_tzc400_reg_list(tzc400_reg_list,
+ dram_idx, index,
+ info_dram_regions->region[dram_idx].addr,
+ info_dram_regions->region[dram_idx].size,
+ NXP_SECURE_DRAM_SIZE, NXP_SP_SHRD_DRAM_SIZE);
+ }
+
+ mem_access_setup(NXP_TZC_ADDR, index,
+ tzc400_reg_list);
+}
+
+/*
+ * This function implements soc specific erratum
+ * This is called before DDR is initialized or MMU is enabled
+ */
+void soc_early_init(void)
+{
+ enum boot_device dev;
+ dram_regions_info_t *dram_regions_info = get_dram_regions_info();
+
+#ifdef CONFIG_OCRAM_ECC_EN
+ ocram_init(NXP_OCRAM_ADDR, NXP_OCRAM_SIZE);
+#endif
+ dcfg_init(&dcfg_init_data);
+#if LOG_LEVEL > 0
+ /* Initialize the console to provide early debug support */
+ plat_console_init(NXP_CONSOLE_ADDR,
+ NXP_UART_CLK_DIVIDER, NXP_CONSOLE_BAUDRATE);
+#endif
+ enable_timer_base_to_cluster(NXP_PMU_ADDR);
+ enable_core_tb(NXP_PMU_ADDR);
+
+ /*
+ * Use the region(NXP_SD_BLOCK_BUF_ADDR + NXP_SD_BLOCK_BUF_SIZE)
+ * as dma of sd
+ */
+ dev = get_boot_dev();
+ if (dev == BOOT_DEVICE_EMMC) {
+ mmap_add_region(NXP_SD_BLOCK_BUF_ADDR, NXP_SD_BLOCK_BUF_ADDR,
+ NXP_SD_BLOCK_BUF_SIZE,
+ MT_DEVICE | MT_RW | MT_NS);
+ }
+
+#if TRUSTED_BOARD_BOOT
+ uint32_t mode;
+
+ sfp_init(NXP_SFP_ADDR);
+ /*
+ * For secure boot disable SMMU.
+ * Later when platform security policy comes in picture,
+ * this might get modified based on the policy
+ */
+ if (check_boot_mode_secure(&mode) == true) {
+ bypass_smmu(NXP_SMMU_ADDR);
+ }
+
+ /*
+ * For Mbedtls currently crypto is not supported via CAAM
+ * enable it when that support is there. In tbbr.mk
+ * the CAAM_INTEG is set as 0.
+ */
+#ifndef MBEDTLS_X509
+ /* Initialize the crypto accelerator if enabled */
+ if (is_sec_enabled() == false) {
+ INFO("SEC is disabled.\n");
+ } else {
+ sec_init(NXP_CAAM_ADDR);
+ }
+#endif
+#endif
+
+ soc_errata();
+
+ delay_timer_init(NXP_TIMER_ADDR);
+ i2c_init(NXP_I2C_ADDR);
+ dram_regions_info->total_dram_size = init_ddr();
+}
+#else /* !IMAGE_BL2 */
+
+void soc_early_platform_setup2(void)
+{
+ dcfg_init(&dcfg_init_data);
+ /*
+ * Initialize system level generic timer for Socs
+ */
+ delay_timer_init(NXP_TIMER_ADDR);
+
+#if LOG_LEVEL > 0
+ /* Initialize the console to provide early debug support */
+ plat_console_init(NXP_CONSOLE_ADDR,
+ NXP_UART_CLK_DIVIDER, NXP_CONSOLE_BAUDRATE);
+#endif
+}
+
+void soc_platform_setup(void)
+{
+ /* Initialize the GIC driver, cpu and distributor interfaces */
+ static uintptr_t target_mask_array[PLATFORM_CORE_COUNT];
+ static interrupt_prop_t ls_interrupt_props[] = {
+ PLAT_LS_G1S_IRQ_PROPS(INTR_GROUP1S),
+ PLAT_LS_G0_IRQ_PROPS(INTR_GROUP0)
+ };
+
+ plat_ls_gic_driver_init(NXP_GICD_ADDR, NXP_GICR_ADDR,
+ PLATFORM_CORE_COUNT,
+ ls_interrupt_props,
+ ARRAY_SIZE(ls_interrupt_props),
+ target_mask_array,
+ plat_core_pos);
+
+ plat_ls_gic_init();
+ enable_init_timer();
+}
+
+/*
+ * This function initializes the soc from the BL31 module
+ */
+void soc_init(void)
+{
+ uint8_t num_clusters, cores_per_cluster;
+
+ /* low-level init of the soc */
+ soc_init_lowlevel();
+ _init_global_data();
+ soc_init_percpu();
+ _initialize_psci();
+
+ /*
+ * Initialize Interconnect for this cluster during cold boot.
+ * No need for locks as no other CPU is active.
+ */
+ cci_init(NXP_CCI_ADDR, cci_map, ARRAY_SIZE(cci_map));
+
+ /*
+ * Enable Interconnect coherency for the primary CPU's cluster.
+ */
+ get_cluster_info(soc_list, ARRAY_SIZE(soc_list), &num_clusters, &cores_per_cluster);
+ plat_ls_interconnect_enter_coherency(num_clusters);
+
+ /* set platform security policies */
+ _set_platform_security();
+
+ /* Initialize the crypto accelerator if enabled */
+ if (is_sec_enabled() == false) {
+ INFO("SEC is disabled.\n");
+ } else {
+ sec_init(NXP_CAAM_ADDR);
+ }
+}
+
+void soc_runtime_setup(void)
+{
+
+}
+#endif /* IMAGE_BL2 */
+
+/*
+ * Function to return the SoC SYS CLK
+ */
+unsigned int get_sys_clk(void)
+{
+ return NXP_SYSCLK_FREQ;
+}
+
+/*
+ * Function returns the base counter frequency
+ * after reading the first entry at CNTFID0 (0x20 offset).
+ *
+ * Function is used by:
+ * 1. ARM common code for PSCI management.
+ * 2. ARM Generic Timer init.
+ */
+unsigned int plat_get_syscnt_freq2(void)
+{
+ unsigned int counter_base_frequency;
+ /*
+ * Below register specifies the base frequency of the system counter.
+ * As per NXP Board Manuals:
+ * The system counter always works with SYS_REF_CLK/4 frequency clock.
+ */
+ counter_base_frequency = mmio_read_32(NXP_TIMER_ADDR + CNTFID_OFF);
+
+ return counter_base_frequency;
+}
diff --git a/plat/nxp/soc-ls1088a/soc.def b/plat/nxp/soc-ls1088a/soc.def
new file mode 100644
index 0000000..25d0847
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/soc.def
@@ -0,0 +1,87 @@
+#
+# Copyright 2022 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+#------------------------------------------------------------------------------
+#
+# This file contains the basic architecture definitions that drive the build
+#
+# -----------------------------------------------------------------------------
+
+CORE_TYPE := a53
+
+CACHE_LINE := 6
+
+# Set to GIC400 or GIC500
+GIC := GIC500
+
+# Set to CCI400 or CCN504 or CCN508
+INTERCONNECT := CCI400
+
+# Select the DDR PHY generation to be used
+PLAT_DDR_PHY := PHY_GEN1
+
+PHYS_SYS := 64
+
+# Indicate layerscape chassis level - set to 3=LSCH3 or 2=LSCH2
+CHASSIS := 3
+
+# TZC IP Details TZC used is TZC380 or TZC400
+TZC_ID := TZC400
+
+# CONSOLE Details available is NS16550 or PL011
+CONSOLE := NS16550
+
+NXP_SFP_VER := 3_4
+
+# In IMAGE_BL2, compile time flag for handling Cache coherency
+# with CAAM for BL2 running from OCRAM
+SEC_MEM_NON_COHERENT := yes
+
+
+# OCRAM MAP for BL2
+# Before BL2
+# 0x18000000 - 0x18009fff -> Used by ROM code, (TBD - can it be used for xlat tables)
+# 0x1800a000 - 0x1801Cfff -> Reserved for BL2 binary (76 KB)
+# 0x1801D000 - 0x1801ffff -> CSF header for BL2 (12 KB)
+OCRAM_START_ADDR := 0x18000000
+OCRAM_SIZE := 0x20000
+
+CSF_HDR_SZ := 0x3000
+
+# Area of OCRAM reserved by ROM code
+NXP_ROM_RSVD := 0xa000
+
+# Input to CST create_hdr_isbc tool
+BL2_HDR_LOC := 0x1801D000
+
+# Location of BL2 on OCRAM
+# BL2_BASE=OCRAM_START_ADDR+NXP_ROM_RSVD
+BL2_BASE := 0x1800a000
+
+# SoC ERRATUM to be enabled
+ERRATA_SOC_A008850 := 1
+
+# ARM Erratum
+ERRATA_A53_855873 := 1
+
+# DDR Erratum
+ERRATA_DDR_A008511 := 1
+ERRATA_DDR_A009803 := 1
+ERRATA_DDR_A009942 := 1
+ERRATA_DDR_A010165 := 1
+
+# Define Endianness of each module
+NXP_ESDHC_ENDIANNESS := LE
+NXP_SFP_ENDIANNESS := LE
+NXP_GPIO_ENDIANNESS := LE
+NXP_SNVS_ENDIANNESS := LE
+NXP_GUR_ENDIANNESS := LE
+NXP_SEC_ENDIANNESS := LE
+NXP_DDR_ENDIANNESS := LE
+NXP_QSPI_ENDIANNESS := LE
+
+# OCRAM ECC Enabled
+OCRAM_ECC_EN := yes
diff --git a/plat/nxp/soc-ls1088a/soc.mk b/plat/nxp/soc-ls1088a/soc.mk
new file mode 100644
index 0000000..83ac9d0
--- /dev/null
+++ b/plat/nxp/soc-ls1088a/soc.mk
@@ -0,0 +1,110 @@
+#
+# Copyright 2022 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# SoC-specific build parameters
+SOC := ls1088a
+PLAT_PATH := plat/nxp
+PLAT_COMMON_PATH:= plat/nxp/common
+PLAT_DRIVERS_PATH:= drivers/nxp
+PLAT_SOC_PATH := ${PLAT_PATH}/soc-${SOC}
+BOARD_PATH := ${PLAT_SOC_PATH}/${BOARD}
+
+# Separate BL2 NOLOAD region (.bss, stack, page tables). need to
+# define BL2_NOLOAD_START and BL2_NOLOAD_LIMIT
+SEPARATE_BL2_NOLOAD_REGION := 1
+
+# get SoC-specific defnitions
+include ${PLAT_SOC_PATH}/soc.def
+include ${PLAT_COMMON_PATH}/plat_make_helper/soc_common_def.mk
+include ${PLAT_COMMON_PATH}/plat_make_helper/plat_build_macros.mk
+
+# For Security Features
+DISABLE_FUSE_WRITE := 1
+ifeq (${TRUSTED_BOARD_BOOT}, 1)
+ifeq (${GENERATE_COT},1)
+# Save Keys to be used by DDR FIP image
+SAVE_KEYS=1
+endif
+$(eval $(call SET_NXP_MAKE_FLAG,SMMU_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,SFP_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,SNVS_NEEDED,BL2))
+# Used by create_pbl tool to
+# create bl2_<boot_mode>_sec.pbl image
+SECURE_BOOT := yes
+endif
+$(eval $(call SET_NXP_MAKE_FLAG,CRYPTO_NEEDED,BL_COMM))
+
+# Selecting Drivers for SoC
+$(eval $(call SET_NXP_MAKE_FLAG,DCFG_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,TIMER_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,INTERCONNECT_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,GIC_NEEDED,BL31))
+$(eval $(call SET_NXP_MAKE_FLAG,CONSOLE_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,PMU_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,DDR_DRIVER_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,TZASC_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,I2C_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,IMG_LOADR_NEEDED,BL2))
+
+# Selecting PSCI & SIP_SVC support
+$(eval $(call SET_NXP_MAKE_FLAG,PSCI_NEEDED,BL31))
+$(eval $(call SET_NXP_MAKE_FLAG,SIPSVC_NEEDED,BL31))
+
+
+# Adding SoC specific files
+include ${PLAT_COMMON_PATH}/soc_errata/errata.mk
+
+PLAT_INCLUDES += -I${PLAT_COMMON_PATH}/include/default\
+ -I${BOARD_PATH}\
+ -I${PLAT_COMMON_PATH}/include/default/ch_${CHASSIS}\
+ -I${PLAT_COMMON_PATH}/soc_errata\
+ -I${PLAT_COMMON_PATH}/include\
+ -I${PLAT_SOC_PATH}/include
+
+ifeq (${SECURE_BOOT},yes)
+include ${PLAT_COMMON_PATH}/tbbr/tbbr.mk
+endif
+
+ifeq (${PSCI_NEEDED}, yes)
+include ${PLAT_COMMON_PATH}/psci/psci.mk
+endif
+
+ifeq (${SIPSVC_NEEDED}, yes)
+include ${PLAT_COMMON_PATH}/sip_svc/sipsvc.mk
+endif
+
+# for fuse-fip & fuse-programming
+ifeq (${FUSE_PROG}, 1)
+include ${PLAT_COMMON_PATH}/fip_handler/fuse_fip/fuse.mk
+endif
+
+ifeq (${IMG_LOADR_NEEDED},yes)
+include $(PLAT_COMMON_PATH)/img_loadr/img_loadr.mk
+endif
+
+# Adding source files for the above selected drivers.
+include ${PLAT_DRIVERS_PATH}/drivers.mk
+
+PLAT_BL_COMMON_SOURCES += ${PLAT_COMMON_PATH}/$(ARCH)/ls_helpers.S\
+ ${PLAT_SOC_PATH}/${ARCH}/${SOC}_helpers.S\
+ ${PLAT_SOC_PATH}/soc.c
+
+BL31_SOURCES += ${PLAT_SOC_PATH}/$(ARCH)/${SOC}.S\
+ ${PSCI_SOURCES}\
+ ${SIPSVC_SOURCES}\
+ ${PLAT_COMMON_PATH}/$(ARCH)/bl31_data.S
+
+ifeq (${TEST_BL31}, 1)
+BL31_SOURCES += ${PLAT_SOC_PATH}/$(ARCH)/bootmain64.S \
+ ${PLAT_SOC_PATH}/$(ARCH)/nonboot64.S
+endif
+
+BL2_SOURCES += ${DDR_CNTLR_SOURCES}\
+ ${TBBR_SOURCES}\
+ ${FUSE_SOURCES}
+
+# Adding TFA setup files
+include ${PLAT_PATH}/common/setup/common.mk
diff --git a/plat/nxp/soc-lx2160a/aarch64/lx2160a.S b/plat/nxp/soc-lx2160a/aarch64/lx2160a.S
new file mode 100644
index 0000000..cc679f2
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/aarch64/lx2160a.S
@@ -0,0 +1,1816 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+.section .text, "ax"
+
+#include <asm_macros.S>
+
+#include <lib/psci/psci.h>
+#include <nxp_timer.h>
+#include <plat_gic.h>
+#include <pmu.h>
+
+#include <bl31_data.h>
+#include <plat_psci.h>
+#include <platform_def.h>
+
+.global soc_init_start
+.global soc_init_percpu
+.global soc_init_finish
+.global _set_platform_security
+.global _soc_set_start_addr
+
+.global _soc_core_release
+.global _soc_ck_disabled
+.global _soc_core_restart
+.global _soc_core_prep_off
+.global _soc_core_entr_off
+.global _soc_core_exit_off
+.global _soc_sys_reset
+.global _soc_sys_off
+.global _soc_core_prep_stdby
+.global _soc_core_entr_stdby
+.global _soc_core_exit_stdby
+.global _soc_core_prep_pwrdn
+.global _soc_core_entr_pwrdn
+.global _soc_core_exit_pwrdn
+.global _soc_clstr_prep_stdby
+.global _soc_clstr_exit_stdby
+.global _soc_clstr_prep_pwrdn
+.global _soc_clstr_exit_pwrdn
+.global _soc_sys_prep_stdby
+.global _soc_sys_exit_stdby
+.global _soc_sys_prep_pwrdn
+.global _soc_sys_pwrdn_wfi
+.global _soc_sys_exit_pwrdn
+
+.equ TZPC_BASE, 0x02200000
+.equ TZPCDECPROT_0_SET_BASE, 0x02200804
+.equ TZPCDECPROT_1_SET_BASE, 0x02200810
+.equ TZPCDECPROT_2_SET_BASE, 0x0220081C
+
+#define CLUSTER_3_CORES_MASK 0xC0
+#define CLUSTER_3_IN_RESET 1
+#define CLUSTER_3_NORMAL 0
+
+/* cluster 3 handling no longer based on frequency, but rather on RCW[850],
+ * which is bit 18 of RCWSR27
+ */
+#define CLUSTER_3_RCW_BIT 0x40000
+
+/* retry count for clock-stop acks */
+.equ CLOCK_RETRY_CNT, 800
+
+/* disable prefetching in the A72 core */
+#define CPUACTLR_DIS_LS_HW_PRE 0x100000000000000
+#define CPUACTLR_DIS_L2_TLB_PRE 0x200000
+
+/* Function starts the initialization tasks of the soc,
+ * using secondary cores if they are available
+ *
+ * Called from C, saving the non-volatile regs
+ * save these as pairs of registers to maintain the
+ * required 16-byte alignment on the stack
+ *
+ * in:
+ * out:
+ * uses x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11
+ */
+func soc_init_start
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+ stp x8, x9, [sp, #-16]!
+ stp x10, x11, [sp, #-16]!
+ stp x12, x13, [sp, #-16]!
+ stp x18, x30, [sp, #-16]!
+
+ /* make sure the personality has been
+ * established by releasing cores that
+ * are marked "to-be-disabled" from reset
+ */
+ bl release_disabled /* 0-9 */
+
+ /* init the task flags */
+ bl _init_task_flags /* 0-1 */
+
+ /* set SCRATCHRW7 to 0x0 */
+ ldr x0, =DCFG_SCRATCHRW7_OFFSET
+ mov x1, xzr
+ bl _write_reg_dcfg
+
+1:
+ /* restore the aarch32/64 non-volatile registers */
+ ldp x18, x30, [sp], #16
+ ldp x12, x13, [sp], #16
+ ldp x10, x11, [sp], #16
+ ldp x8, x9, [sp], #16
+ ldp x6, x7, [sp], #16
+ ldp x4, x5, [sp], #16
+ ret
+endfunc soc_init_start
+
+
+/* Function performs any soc-specific initialization that is needed on
+ * a per-core basis.
+ * in: none
+ * out: none
+ * uses x0, x1, x2, x3
+ */
+func soc_init_percpu
+ stp x4, x30, [sp, #-16]!
+
+ bl plat_my_core_mask
+ mov x2, x0 /* x2 = core mask */
+
+ /* Check if this core is marked for prefetch disable
+ */
+ mov x0, #PREFETCH_DIS_OFFSET
+ bl _get_global_data /* 0-1 */
+ tst x0, x2
+ b.eq 1f
+ bl _disable_ldstr_pfetch_A72 /* 0 */
+1:
+ mov x0, #NXP_PMU_ADDR
+ bl enable_timer_base_to_cluster
+ ldp x4, x30, [sp], #16
+ ret
+endfunc soc_init_percpu
+
+
+/* Function completes the initialization tasks of the soc
+ * in:
+ * out:
+ * uses x0, x1, x2, x3, x4
+ */
+func soc_init_finish
+ stp x4, x30, [sp, #-16]!
+
+ ldp x4, x30, [sp], #16
+ ret
+endfunc soc_init_finish
+
+
+/* Function sets the security mechanisms in the SoC to implement the
+ * Platform Security Policy
+ */
+func _set_platform_security
+ mov x8, x30
+
+#if (!SUPPRESS_TZC)
+ /* initialize the tzpc */
+ bl init_tzpc
+#endif
+
+#if (!SUPPRESS_SEC)
+ /* initialize secmon */
+#ifdef NXP_SNVS_ENABLED
+ mov x0, #NXP_SNVS_ADDR
+ bl init_sec_mon
+#endif
+#endif
+
+ mov x30, x8
+ ret
+endfunc _set_platform_security
+
+
+/* Function writes a 64-bit address to bootlocptrh/l
+ * in: x0, 64-bit address to write to BOOTLOCPTRL/H
+ * uses x0, x1, x2
+ */
+func _soc_set_start_addr
+ /* Get the 64-bit base address of the dcfg block */
+ ldr x2, =NXP_DCFG_ADDR
+
+ /* write the 32-bit BOOTLOCPTRL register */
+ mov x1, x0
+ str w1, [x2, #DCFG_BOOTLOCPTRL_OFFSET]
+
+ /* write the 32-bit BOOTLOCPTRH register */
+ lsr x1, x0, #32
+ str w1, [x2, #DCFG_BOOTLOCPTRH_OFFSET]
+ ret
+endfunc _soc_set_start_addr
+
+/* Function releases a secondary core from reset
+ * in: x0 = core_mask_lsb
+ * out: none
+ * uses: x0, x1, x2, x3
+ */
+func _soc_core_release
+ mov x3, x30
+
+ ldr x1, =NXP_SEC_REGFILE_ADDR
+ /* write to CORE_HOLD to tell
+ * the bootrom that this core is
+ * expected to run.
+ */
+ str w0, [x1, #CORE_HOLD_OFFSET]
+
+ /* read-modify-write BRRL to release core */
+ mov x1, #NXP_RESET_ADDR
+ ldr w2, [x1, #BRR_OFFSET]
+
+ /* x0 = core mask */
+ orr w2, w2, w0
+ str w2, [x1, #BRR_OFFSET]
+ dsb sy
+ isb
+
+ /* send event */
+ sev
+ isb
+
+ mov x30, x3
+ ret
+endfunc _soc_core_release
+
+
+/* Function determines if a core is disabled via COREDISABLEDSR
+ * in: w0 = core_mask_lsb
+ * out: w0 = 0, core not disabled
+ * w0 != 0, core disabled
+ * uses x0, x1
+ */
+func _soc_ck_disabled
+
+ /* get base addr of dcfg block */
+ ldr x1, =NXP_DCFG_ADDR
+
+ /* read COREDISABLEDSR */
+ ldr w1, [x1, #DCFG_COREDISABLEDSR_OFFSET]
+
+ /* test core bit */
+ and w0, w1, w0
+
+ ret
+endfunc _soc_ck_disabled
+
+
+/* Part of CPU_ON
+ * Function restarts a core shutdown via _soc_core_entr_off
+ * in: x0 = core mask lsb (of the target cpu)
+ * out: x0 == 0, on success
+ * x0 != 0, on failure
+ * uses x0, x1, x2, x3, x4, x5, x6
+ */
+func _soc_core_restart
+ mov x6, x30
+ mov x4, x0
+
+ /* pgm GICD_CTLR - enable secure grp0 */
+ mov x5, #NXP_GICD_ADDR
+ ldr w2, [x5, #GICD_CTLR_OFFSET]
+ orr w2, w2, #GICD_CTLR_EN_GRP_0
+ str w2, [x5, #GICD_CTLR_OFFSET]
+ dsb sy
+ isb
+
+ /* poll on RWP til write completes */
+4:
+ ldr w2, [x5, #GICD_CTLR_OFFSET]
+ tst w2, #GICD_CTLR_RWP
+ b.ne 4b
+
+ /* x4 = core mask lsb
+ * x5 = gicd base addr
+ */
+ mov x0, x4
+ bl get_mpidr_value
+
+ /* x0 = mpidr of target core
+ * x4 = core mask lsb of target core
+ * x5 = gicd base addr
+ */
+
+ /* generate target list bit */
+ and x1, x0, #MPIDR_AFFINITY0_MASK
+ mov x2, #1
+ lsl x2, x2, x1
+
+ /* get the affinity1 field */
+ and x1, x0, #MPIDR_AFFINITY1_MASK
+ lsl x1, x1, #8
+ orr x2, x2, x1
+
+ /* insert the INTID for SGI15 */
+ orr x2, x2, #ICC_SGI0R_EL1_INTID
+
+ /* fire the SGI */
+ msr ICC_SGI0R_EL1, x2
+ dsb sy
+ isb
+
+ /* load '0' on success */
+ mov x0, xzr
+
+ mov x30, x6
+ ret
+endfunc _soc_core_restart
+
+
+/* Part of CPU_OFF
+ * Function programs SoC & GIC registers in preparation for shutting down
+ * the core
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6, x7
+ */
+func _soc_core_prep_off
+ mov x8, x30
+ mov x7, x0 /* x7 = core mask lsb */
+
+ mrs x1, CORTEX_A72_ECTLR_EL1
+
+ /* set smp and disable L2 snoops in cpuectlr */
+ orr x1, x1, #CPUECTLR_SMPEN_EN
+ orr x1, x1, #CPUECTLR_DISABLE_TWALK_PREFETCH
+ bic x1, x1, #CPUECTLR_INS_PREFETCH_MASK
+ bic x1, x1, #CPUECTLR_DAT_PREFETCH_MASK
+
+ /* set retention control in cpuectlr */
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ orr x1, x1, #CPUECTLR_TIMER_8TICKS
+ msr CORTEX_A72_ECTLR_EL1, x1
+
+ /* get redistributor rd base addr for this core */
+ mov x0, x7
+ bl get_gic_rd_base
+ mov x6, x0
+
+ /* get redistributor sgi base addr for this core */
+ mov x0, x7
+ bl get_gic_sgi_base
+ mov x5, x0
+
+ /* x5 = gicr sgi base addr
+ * x6 = gicr rd base addr
+ * x7 = core mask lsb
+ */
+
+ /* disable SGI 15 at redistributor - GICR_ICENABLER0 */
+ mov w3, #GICR_ICENABLER0_SGI15
+ str w3, [x5, #GICR_ICENABLER0_OFFSET]
+2:
+ /* poll on rwp bit in GICR_CTLR */
+ ldr w4, [x6, #GICR_CTLR_OFFSET]
+ tst w4, #GICR_CTLR_RWP
+ b.ne 2b
+
+ /* disable GRP1 interrupts at cpu interface */
+ msr ICC_IGRPEN1_EL3, xzr
+
+ /* disable GRP0 ints at cpu interface */
+ msr ICC_IGRPEN0_EL1, xzr
+
+ /* program the redistributor - poll on GICR_CTLR.RWP as needed */
+
+ /* define SGI 15 as Grp0 - GICR_IGROUPR0 */
+ ldr w4, [x5, #GICR_IGROUPR0_OFFSET]
+ bic w4, w4, #GICR_IGROUPR0_SGI15
+ str w4, [x5, #GICR_IGROUPR0_OFFSET]
+
+ /* define SGI 15 as Grp0 - GICR_IGRPMODR0 */
+ ldr w3, [x5, #GICR_IGRPMODR0_OFFSET]
+ bic w3, w3, #GICR_IGRPMODR0_SGI15
+ str w3, [x5, #GICR_IGRPMODR0_OFFSET]
+
+ /* set priority of SGI 15 to highest (0x0) - GICR_IPRIORITYR3 */
+ ldr w4, [x5, #GICR_IPRIORITYR3_OFFSET]
+ bic w4, w4, #GICR_IPRIORITYR3_SGI15_MASK
+ str w4, [x5, #GICR_IPRIORITYR3_OFFSET]
+
+ /* enable SGI 15 at redistributor - GICR_ISENABLER0 */
+ mov w3, #GICR_ISENABLER0_SGI15
+ str w3, [x5, #GICR_ISENABLER0_OFFSET]
+ dsb sy
+ isb
+3:
+ /* poll on rwp bit in GICR_CTLR */
+ ldr w4, [x6, #GICR_CTLR_OFFSET]
+ tst w4, #GICR_CTLR_RWP
+ b.ne 3b
+
+ /* quiesce the debug interfaces */
+ mrs x3, osdlr_el1
+ orr x3, x3, #OSDLR_EL1_DLK_LOCK
+ msr osdlr_el1, x3
+ isb
+
+ /* enable grp0 ints */
+ mov x3, #ICC_IGRPEN0_EL1_EN
+ msr ICC_IGRPEN0_EL1, x3
+
+ /* x5 = gicr sgi base addr
+ * x6 = gicr rd base addr
+ * x7 = core mask lsb
+ */
+
+ /* clear any pending interrupts */
+ mvn w1, wzr
+ str w1, [x5, #GICR_ICPENDR0_OFFSET]
+
+ /* make sure system counter is enabled */
+ ldr x3, =NXP_TIMER_ADDR
+ ldr w0, [x3, #SYS_COUNTER_CNTCR_OFFSET]
+ tst w0, #SYS_COUNTER_CNTCR_EN
+ b.ne 4f
+ orr w0, w0, #SYS_COUNTER_CNTCR_EN
+ str w0, [x3, #SYS_COUNTER_CNTCR_OFFSET]
+4:
+ /* enable the core timer and mask timer interrupt */
+ mov x1, #CNTP_CTL_EL0_EN
+ orr x1, x1, #CNTP_CTL_EL0_IMASK
+ msr cntp_ctl_el0, x1
+
+ isb
+ mov x30, x8
+ ret
+endfunc _soc_core_prep_off
+
+
+/* Part of CPU_OFF:
+ * Function performs the final steps to shutdown the core
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5
+ */
+func _soc_core_entr_off
+ mov x5, x30
+ mov x4, x0
+
+1:
+ /* enter low-power state by executing wfi */
+ wfi
+
+ /* see if SGI15 woke us up */
+ mrs x2, ICC_IAR0_EL1
+ mov x3, #ICC_IAR0_EL1_SGI15
+ cmp x2, x3
+ b.ne 2f
+
+ /* deactivate the intrrupts. */
+ msr ICC_EOIR0_EL1, x2
+
+2:
+ /* check if core is turned ON */
+ mov x0, x4
+ /* Fetched the core state in x0 */
+ bl _getCoreState
+
+ cmp x0, #CORE_WAKEUP
+ b.ne 1b
+
+ /* Reached here, exited the wfi */
+
+ mov x30, x5
+ ret
+endfunc _soc_core_entr_off
+
+
+/* Part of CPU_OFF:
+ * Function starts the process of starting a core back up
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6
+ */
+func _soc_core_exit_off
+ mov x6, x30
+ mov x5, x0
+
+ /* disable forwarding of GRP0 ints at cpu interface */
+ msr ICC_IGRPEN0_EL1, xzr
+
+ /* get redistributor sgi base addr for this core */
+ mov x0, x5
+ bl get_gic_sgi_base
+ mov x4, x0
+
+ /* x4 = gicr sgi base addr
+ * x5 = core mask
+ */
+
+ /* disable SGI 15 at redistributor - GICR_ICENABLER0 */
+ mov w1, #GICR_ICENABLER0_SGI15
+ str w1, [x4, #GICR_ICENABLER0_OFFSET]
+
+ /* get redistributor rd base addr for this core */
+ mov x0, x5
+ bl get_gic_rd_base
+ mov x4, x0
+
+2:
+ /* poll on rwp bit in GICR_CTLR */
+ ldr w2, [x4, #GICR_CTLR_OFFSET]
+ tst w2, #GICR_CTLR_RWP
+ b.ne 2b
+
+ /* unlock the debug interfaces */
+ mrs x3, osdlr_el1
+ bic x3, x3, #OSDLR_EL1_DLK_LOCK
+ msr osdlr_el1, x3
+ isb
+
+ dsb sy
+ isb
+ mov x30, x6
+ ret
+endfunc _soc_core_exit_off
+
+
+/* Function requests a reset of the entire SOC
+ * in: none
+ * out: none
+ * uses: x0, x1, x2, x3, x4, x5, x6
+ */
+func _soc_sys_reset
+ mov x6, x30
+
+ ldr x2, =NXP_RST_ADDR
+ /* clear the RST_REQ_MSK and SW_RST_REQ */
+
+ mov w0, #0x00000000
+ str w0, [x2, #RSTCNTL_OFFSET]
+
+ /* initiate the sw reset request */
+ mov w0, #SW_RST_REQ_INIT
+ str w0, [x2, #RSTCNTL_OFFSET]
+
+ /* In case this address range is mapped as cacheable,
+ * flush the write out of the dcaches.
+ */
+ add x2, x2, #RSTCNTL_OFFSET
+ dc cvac, x2
+ dsb st
+ isb
+
+ /* Function does not return */
+ b .
+endfunc _soc_sys_reset
+
+
+/* Part of SYSTEM_OFF:
+ * Function turns off the SoC clocks
+ * Note: Function is not intended to return, and the only allowable
+ * recovery is POR
+ * in: none
+ * out: none
+ * uses x0, x1, x2, x3
+ */
+func _soc_sys_off
+
+ /* disable sec, QBman, spi and qspi */
+ ldr x2, =NXP_DCFG_ADDR
+ ldr x0, =DCFG_DEVDISR1_OFFSET
+ ldr w1, =DCFG_DEVDISR1_SEC
+ str w1, [x2, x0]
+ ldr x0, =DCFG_DEVDISR3_OFFSET
+ ldr w1, =DCFG_DEVDISR3_QBMAIN
+ str w1, [x2, x0]
+ ldr x0, =DCFG_DEVDISR4_OFFSET
+ ldr w1, =DCFG_DEVDISR4_SPI_QSPI
+ str w1, [x2, x0]
+
+ /* set TPMWAKEMR0 */
+ ldr x0, =TPMWAKEMR0_ADDR
+ mov w1, #0x1
+ str w1, [x0]
+
+ /* disable icache, dcache, mmu @ EL1 */
+ mov x1, #SCTLR_I_C_M_MASK
+ mrs x0, sctlr_el1
+ bic x0, x0, x1
+ msr sctlr_el1, x0
+
+ /* disable L2 prefetches */
+ mrs x0, CORTEX_A72_ECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ orr x0, x0, #CPUECTLR_SMPEN_EN
+ orr x0, x0, #CPUECTLR_TIMER_8TICKS
+ msr CORTEX_A72_ECTLR_EL1, x0
+ isb
+
+ /* disable CCN snoop domain */
+ mov x1, #NXP_CCN_HN_F_0_ADDR
+ ldr x0, =CCN_HN_F_SNP_DMN_CTL_MASK
+ str x0, [x1, #CCN_HN_F_SNP_DMN_CTL_CLR_OFFSET]
+3:
+ ldr w2, [x1, #CCN_HN_F_SNP_DMN_CTL_OFFSET]
+ cmp w2, #0x2
+ b.ne 3b
+
+ mov x3, #NXP_PMU_ADDR
+
+4:
+ ldr w1, [x3, #PMU_PCPW20SR_OFFSET]
+ cmp w1, #PMU_IDLE_CORE_MASK
+ b.ne 4b
+
+ mov w1, #PMU_IDLE_CLUSTER_MASK
+ str w1, [x3, #PMU_CLAINACTSETR_OFFSET]
+
+1:
+ ldr w1, [x3, #PMU_PCPW20SR_OFFSET]
+ cmp w1, #PMU_IDLE_CORE_MASK
+ b.ne 1b
+
+ mov w1, #PMU_FLUSH_CLUSTER_MASK
+ str w1, [x3, #PMU_CLL2FLUSHSETR_OFFSET]
+
+2:
+ ldr w1, [x3, #PMU_CLL2FLUSHSR_OFFSET]
+ cmp w1, #PMU_FLUSH_CLUSTER_MASK
+ b.ne 2b
+
+ mov w1, #PMU_FLUSH_CLUSTER_MASK
+ str w1, [x3, #PMU_CLSL2FLUSHCLRR_OFFSET]
+
+ mov w1, #PMU_FLUSH_CLUSTER_MASK
+ str w1, [x3, #PMU_CLSINACTSETR_OFFSET]
+
+ mov x2, #DAIF_SET_MASK
+ mrs x1, spsr_el1
+ orr x1, x1, x2
+ msr spsr_el1, x1
+
+ mrs x1, spsr_el2
+ orr x1, x1, x2
+ msr spsr_el2, x1
+
+ /* force the debug interface to be quiescent */
+ mrs x0, osdlr_el1
+ orr x0, x0, #0x1
+ msr osdlr_el1, x0
+
+ /* invalidate all TLB entries at all 3 exception levels */
+ tlbi alle1
+ tlbi alle2
+ tlbi alle3
+
+ /* x3 = pmu base addr */
+
+ /* request lpm20 */
+ ldr x0, =PMU_POWMGTCSR_OFFSET
+ ldr w1, =PMU_POWMGTCSR_VAL
+ str w1, [x3, x0]
+
+5:
+ wfe
+ b.eq 5b
+endfunc _soc_sys_off
+
+
+/* Part of CPU_SUSPEND
+ * Function puts the calling core into standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0
+ */
+func _soc_core_entr_stdby
+
+ dsb sy
+ isb
+ wfi
+
+ ret
+endfunc _soc_core_entr_stdby
+
+
+/* Part of CPU_SUSPEND
+ * Function performs SoC-specific programming prior to standby
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+func _soc_core_prep_stdby
+
+ /* clear CORTEX_A72_ECTLR_EL1[2:0] */
+ mrs x1, CORTEX_A72_ECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ msr CORTEX_A72_ECTLR_EL1, x1
+
+ ret
+endfunc _soc_core_prep_stdby
+
+
+/* Part of CPU_SUSPEND
+ * Function performs any SoC-specific cleanup after standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+func _soc_core_exit_stdby
+
+ ret
+endfunc _soc_core_exit_stdby
+
+
+/* Part of CPU_SUSPEND
+ * Function performs SoC-specific programming prior to power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+func _soc_core_prep_pwrdn
+
+ /* make sure system counter is enabled */
+ ldr x2, =NXP_TIMER_ADDR
+ ldr w0, [x2, #SYS_COUNTER_CNTCR_OFFSET]
+ tst w0, #SYS_COUNTER_CNTCR_EN
+ b.ne 1f
+ orr w0, w0, #SYS_COUNTER_CNTCR_EN
+ str w0, [x2, #SYS_COUNTER_CNTCR_OFFSET]
+1:
+
+ /* enable dynamic retention control (CPUECTLR[2:0])
+ * set the SMPEN bit (CPUECTLR[6])
+ */
+ mrs x1, CORTEX_A72_ECTLR_EL1
+ bic x1, x1, #CPUECTLR_RET_MASK
+ orr x1, x1, #CPUECTLR_TIMER_8TICKS
+ orr x1, x1, #CPUECTLR_SMPEN_EN
+ msr CORTEX_A72_ECTLR_EL1, x1
+
+ isb
+ ret
+endfunc _soc_core_prep_pwrdn
+
+
+/* Part of CPU_SUSPEND
+ * Function puts the calling core into a power-down state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0
+ */
+func _soc_core_entr_pwrdn
+
+ /* X0 = core mask lsb */
+
+ dsb sy
+ isb
+ wfi
+
+ ret
+endfunc _soc_core_entr_pwrdn
+
+
+/* Part of CPU_SUSPEND
+ * Function performs any SoC-specific cleanup after power-down state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+func _soc_core_exit_pwrdn
+
+ ret
+endfunc _soc_core_exit_pwrdn
+
+
+/* Part of CPU_SUSPEND
+ * Function performs SoC-specific programming prior to standby
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+func _soc_clstr_prep_stdby
+
+ /* clear CORTEX_A72_ECTLR_EL1[2:0] */
+ mrs x1, CORTEX_A72_ECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ msr CORTEX_A72_ECTLR_EL1, x1
+
+ ret
+endfunc _soc_clstr_prep_stdby
+
+
+/* Part of CPU_SUSPEND
+ * Function performs any SoC-specific cleanup after standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+func _soc_clstr_exit_stdby
+
+ ret
+endfunc _soc_clstr_exit_stdby
+
+
+/* Part of CPU_SUSPEND
+ * Function performs SoC-specific programming prior to power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+func _soc_clstr_prep_pwrdn
+
+ /* make sure system counter is enabled */
+ ldr x2, =NXP_TIMER_ADDR
+ ldr w0, [x2, #SYS_COUNTER_CNTCR_OFFSET]
+ tst w0, #SYS_COUNTER_CNTCR_EN
+ b.ne 1f
+ orr w0, w0, #SYS_COUNTER_CNTCR_EN
+ str w0, [x2, #SYS_COUNTER_CNTCR_OFFSET]
+1:
+
+ /* enable dynamic retention control (CPUECTLR[2:0])
+ * set the SMPEN bit (CPUECTLR[6])
+ */
+ mrs x1, CORTEX_A72_ECTLR_EL1
+ bic x1, x1, #CPUECTLR_RET_MASK
+ orr x1, x1, #CPUECTLR_TIMER_8TICKS
+ orr x1, x1, #CPUECTLR_SMPEN_EN
+ msr CORTEX_A72_ECTLR_EL1, x1
+
+ isb
+ ret
+endfunc _soc_clstr_prep_pwrdn
+
+
+/* Part of CPU_SUSPEND
+ * Function performs any SoC-specific cleanup after power-down state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+func _soc_clstr_exit_pwrdn
+
+ ret
+endfunc _soc_clstr_exit_pwrdn
+
+
+/* Part of CPU_SUSPEND
+ * Function performs SoC-specific programming prior to standby
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+func _soc_sys_prep_stdby
+
+ /* clear CORTEX_A72_ECTLR_EL1[2:0] */
+ mrs x1, CORTEX_A72_ECTLR_EL1
+ bic x1, x1, #CPUECTLR_TIMER_MASK
+ msr CORTEX_A72_ECTLR_EL1, x1
+ ret
+endfunc _soc_sys_prep_stdby
+
+
+/* Part of CPU_SUSPEND
+ * Function performs any SoC-specific cleanup after standby state
+ * in: x0 = core mask lsb
+ * out: none
+ * uses none
+ */
+func _soc_sys_exit_stdby
+
+ ret
+endfunc _soc_sys_exit_stdby
+
+
+/* Part of CPU_SUSPEND
+ * Function performs SoC-specific programming prior to
+ * suspend-to-power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0, x1
+ */
+func _soc_sys_prep_pwrdn
+
+ mrs x1, CORTEX_A72_ECTLR_EL1
+ /* make sure the smp bit is set */
+ orr x1, x1, #CPUECTLR_SMPEN_MASK
+ /* set the retention control */
+ orr x1, x1, #CPUECTLR_RET_8CLK
+ /* disable tablewalk prefetch */
+ orr x1, x1, #CPUECTLR_DISABLE_TWALK_PREFETCH
+ msr CORTEX_A72_ECTLR_EL1, x1
+ isb
+
+ ret
+endfunc _soc_sys_prep_pwrdn
+
+
+/* Part of CPU_SUSPEND
+ * Function puts the calling core, and potentially the soc, into a
+ * low-power state
+ * in: x0 = core mask lsb
+ * out: x0 = 0, success
+ * x0 < 0, failure
+ * uses x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14,
+ * x15, x16, x17, x18, x19, x20, x21, x28
+ */
+func _soc_sys_pwrdn_wfi
+ mov x28, x30
+
+ /* disable cluster snooping in the CCN-508 */
+ ldr x1, =NXP_CCN_HN_F_0_ADDR
+ ldr x7, [x1, #CCN_HN_F_SNP_DMN_CTL_OFFSET]
+ mov x6, #CCN_HNF_NODE_COUNT
+1:
+ str x7, [x1, #CCN_HN_F_SNP_DMN_CTL_CLR_OFFSET]
+ sub x6, x6, #1
+ add x1, x1, #CCN_HNF_OFFSET
+ cbnz x6, 1b
+
+ /* x0 = core mask
+ * x7 = hnf sdcr
+ */
+
+ ldr x1, =NXP_PMU_CCSR_ADDR
+ ldr x2, =NXP_PMU_DCSR_ADDR
+
+ /* enable the stop-request-override */
+ mov x3, #PMU_POWMGTDCR0_OFFSET
+ mov x4, #POWMGTDCR_STP_OV_EN
+ str w4, [x2, x3]
+
+ /* x0 = core mask
+ * x1 = NXP_PMU_CCSR_ADDR
+ * x2 = NXP_PMU_DCSR_ADDR
+ * x7 = hnf sdcr
+ */
+
+ /* disable prefetching in the A72 core */
+ mrs x8, CORTEX_A72_CPUACTLR_EL1
+ tst x8, #CPUACTLR_DIS_LS_HW_PRE
+ b.ne 2f
+ dsb sy
+ isb
+ /* disable data prefetch */
+ orr x16, x8, #CPUACTLR_DIS_LS_HW_PRE
+ /* disable tlb prefetch */
+ orr x16, x16, #CPUACTLR_DIS_L2_TLB_PRE
+ msr CORTEX_A72_CPUACTLR_EL1, x16
+ isb
+
+ /* x0 = core mask
+ * x1 = NXP_PMU_CCSR_ADDR
+ * x2 = NXP_PMU_DCSR_ADDR
+ * x7 = hnf sdcr
+ * x8 = cpuactlr
+ */
+
+2:
+ /* save hnf-sdcr and cpuactlr to stack */
+ stp x7, x8, [sp, #-16]!
+
+ /* x0 = core mask
+ * x1 = NXP_PMU_CCSR_ADDR
+ * x2 = NXP_PMU_DCSR_ADDR
+ */
+
+ /* save the IPSTPCRn registers to stack */
+ mov x15, #PMU_IPSTPCR0_OFFSET
+ ldr w9, [x1, x15]
+ mov x16, #PMU_IPSTPCR1_OFFSET
+ ldr w10, [x1, x16]
+ mov x17, #PMU_IPSTPCR2_OFFSET
+ ldr w11, [x1, x17]
+ mov x18, #PMU_IPSTPCR3_OFFSET
+ ldr w12, [x1, x18]
+ mov x19, #PMU_IPSTPCR4_OFFSET
+ ldr w13, [x1, x19]
+ mov x20, #PMU_IPSTPCR5_OFFSET
+ ldr w14, [x1, x20]
+
+ stp x9, x10, [sp, #-16]!
+ stp x11, x12, [sp, #-16]!
+ stp x13, x14, [sp, #-16]!
+
+ /* x0 = core mask
+ * x1 = NXP_PMU_CCSR_ADDR
+ * x2 = NXP_PMU_DCSR_ADDR
+ * x15 = PMU_IPSTPCR0_OFFSET
+ * x16 = PMU_IPSTPCR1_OFFSET
+ * x17 = PMU_IPSTPCR2_OFFSET
+ * x18 = PMU_IPSTPCR3_OFFSET
+ * x19 = PMU_IPSTPCR4_OFFSET
+ * x20 = PMU_IPSTPCR5_OFFSET
+ */
+
+ /* load the full clock mask for IPSTPCR0 */
+ ldr x3, =DEVDISR1_MASK
+ /* get the exclusions */
+ mov x21, #PMU_IPPDEXPCR0_OFFSET
+ ldr w4, [x1, x21]
+ /* apply the exclusions to the mask */
+ bic w7, w3, w4
+ /* stop the clocks in IPSTPCR0 */
+ str w7, [x1, x15]
+
+ /* use same procedure for IPSTPCR1-IPSTPCR5 */
+
+ /* stop the clocks in IPSTPCR1 */
+ ldr x5, =DEVDISR2_MASK
+ mov x21, #PMU_IPPDEXPCR1_OFFSET
+ ldr w6, [x1, x21]
+ bic w8, w5, w6
+ str w8, [x1, x16]
+
+ /* stop the clocks in IPSTPCR2 */
+ ldr x3, =DEVDISR3_MASK
+ mov x21, #PMU_IPPDEXPCR2_OFFSET
+ ldr w4, [x1, x21]
+ bic w9, w3, w4
+ str w9, [x1, x17]
+
+ /* stop the clocks in IPSTPCR3 */
+ ldr x5, =DEVDISR4_MASK
+ mov x21, #PMU_IPPDEXPCR3_OFFSET
+ ldr w6, [x1, x21]
+ bic w10, w5, w6
+ str w10, [x1, x18]
+
+ /* stop the clocks in IPSTPCR4
+ * - exclude the ddr clocks as we are currently executing
+ * out of *some* memory, might be ddr
+ * - exclude the OCRAM clk so that we retain any code/data in
+ * OCRAM
+ * - may need to exclude the debug clock if we are testing
+ */
+ ldr x3, =DEVDISR5_MASK
+ mov w6, #DEVDISR5_MASK_ALL_MEM
+ bic w3, w3, w6
+
+ mov w5, #POLICY_DEBUG_ENABLE
+ cbz w5, 3f
+ mov w6, #DEVDISR5_MASK_DBG
+ bic w3, w3, w6
+3:
+ mov x21, #PMU_IPPDEXPCR4_OFFSET
+ ldr w4, [x1, x21]
+ bic w11, w3, w4
+ str w11, [x1, x19]
+
+ /* stop the clocks in IPSTPCR5 */
+ ldr x5, =DEVDISR6_MASK
+ mov x21, #PMU_IPPDEXPCR5_OFFSET
+ ldr w6, [x1, x21]
+ bic w12, w5, w6
+ str w12, [x1, x20]
+
+ /* x0 = core mask
+ * x1 = NXP_PMU_CCSR_ADDR
+ * x2 = NXP_PMU_DCSR_ADDR
+ * x7 = IPSTPCR0
+ * x8 = IPSTPCR1
+ * x9 = IPSTPCR2
+ * x10 = IPSTPCR3
+ * x11 = IPSTPCR4
+ * x12 = IPSTPCR5
+ */
+
+ /* poll until the clocks are stopped in IPSTPACKSR0 */
+ mov w4, #CLOCK_RETRY_CNT
+ mov x21, #PMU_IPSTPACKSR0_OFFSET
+4:
+ ldr w5, [x1, x21]
+ cmp w5, w7
+ b.eq 5f
+ sub w4, w4, #1
+ cbnz w4, 4b
+
+ /* poll until the clocks are stopped in IPSTPACKSR1 */
+5:
+ mov w4, #CLOCK_RETRY_CNT
+ mov x21, #PMU_IPSTPACKSR1_OFFSET
+6:
+ ldr w5, [x1, x21]
+ cmp w5, w8
+ b.eq 7f
+ sub w4, w4, #1
+ cbnz w4, 6b
+
+ /* poll until the clocks are stopped in IPSTPACKSR2 */
+7:
+ mov w4, #CLOCK_RETRY_CNT
+ mov x21, #PMU_IPSTPACKSR2_OFFSET
+8:
+ ldr w5, [x1, x21]
+ cmp w5, w9
+ b.eq 9f
+ sub w4, w4, #1
+ cbnz w4, 8b
+
+ /* poll until the clocks are stopped in IPSTPACKSR3 */
+9:
+ mov w4, #CLOCK_RETRY_CNT
+ mov x21, #PMU_IPSTPACKSR3_OFFSET
+10:
+ ldr w5, [x1, x21]
+ cmp w5, w10
+ b.eq 11f
+ sub w4, w4, #1
+ cbnz w4, 10b
+
+ /* poll until the clocks are stopped in IPSTPACKSR4 */
+11:
+ mov w4, #CLOCK_RETRY_CNT
+ mov x21, #PMU_IPSTPACKSR4_OFFSET
+12:
+ ldr w5, [x1, x21]
+ cmp w5, w11
+ b.eq 13f
+ sub w4, w4, #1
+ cbnz w4, 12b
+
+ /* poll until the clocks are stopped in IPSTPACKSR5 */
+13:
+ mov w4, #CLOCK_RETRY_CNT
+ mov x21, #PMU_IPSTPACKSR5_OFFSET
+14:
+ ldr w5, [x1, x21]
+ cmp w5, w12
+ b.eq 15f
+ sub w4, w4, #1
+ cbnz w4, 14b
+
+ /* x0 = core mask
+ * x1 = NXP_PMU_CCSR_ADDR
+ * x2 = NXP_PMU_DCSR_ADDR
+ * x7 = IPSTPCR0
+ * x8 = IPSTPCR1
+ * x9 = IPSTPCR2
+ * x10 = IPSTPCR3
+ * x11 = IPSTPCR4
+ * x12 = IPSTPCR5
+ */
+
+15:
+ mov x3, #NXP_DCFG_ADDR
+
+ /* save the devdisr registers to stack */
+ ldr w13, [x3, #DCFG_DEVDISR1_OFFSET]
+ ldr w14, [x3, #DCFG_DEVDISR2_OFFSET]
+ ldr w15, [x3, #DCFG_DEVDISR3_OFFSET]
+ ldr w16, [x3, #DCFG_DEVDISR4_OFFSET]
+ ldr w17, [x3, #DCFG_DEVDISR5_OFFSET]
+ ldr w18, [x3, #DCFG_DEVDISR6_OFFSET]
+
+ stp x13, x14, [sp, #-16]!
+ stp x15, x16, [sp, #-16]!
+ stp x17, x18, [sp, #-16]!
+
+ /* power down the IP in DEVDISR1 - corresponds to IPSTPCR0 */
+ str w7, [x3, #DCFG_DEVDISR1_OFFSET]
+
+ /* power down the IP in DEVDISR2 - corresponds to IPSTPCR1 */
+ str w8, [x3, #DCFG_DEVDISR2_OFFSET]
+
+ /* power down the IP in DEVDISR3 - corresponds to IPSTPCR2 */
+ str w9, [x3, #DCFG_DEVDISR3_OFFSET]
+
+ /* power down the IP in DEVDISR4 - corresponds to IPSTPCR3 */
+ str w10, [x3, #DCFG_DEVDISR4_OFFSET]
+
+ /* power down the IP in DEVDISR5 - corresponds to IPSTPCR4 */
+ str w11, [x3, #DCFG_DEVDISR5_OFFSET]
+
+ /* power down the IP in DEVDISR6 - corresponds to IPSTPCR5 */
+ str w12, [x3, #DCFG_DEVDISR6_OFFSET]
+
+ /* setup register values for the cache-only sequence */
+ mov x4, #NXP_DDR_ADDR
+ mov x5, #NXP_DDR2_ADDR
+ mov x6, x11
+ mov x7, x17
+ ldr x12, =PMU_CLAINACTSETR_OFFSET
+ ldr x13, =PMU_CLSINACTSETR_OFFSET
+ ldr x14, =PMU_CLAINACTCLRR_OFFSET
+ ldr x15, =PMU_CLSINACTCLRR_OFFSET
+
+ /* x0 = core mask
+ * x1 = NXP_PMU_CCSR_ADDR
+ * x2 = NXP_PMU_DCSR_ADDR
+ * x3 = NXP_DCFG_ADDR
+ * x4 = NXP_DDR_ADDR
+ * x5 = NXP_DDR2_ADDR
+ * w6 = IPSTPCR4
+ * w7 = DEVDISR5
+ * x12 = PMU_CLAINACTSETR_OFFSET
+ * x13 = PMU_CLSINACTSETR_OFFSET
+ * x14 = PMU_CLAINACTCLRR_OFFSET
+ * x15 = PMU_CLSINACTCLRR_OFFSET
+ */
+
+ mov x8, #POLICY_DEBUG_ENABLE
+ cbnz x8, 29f
+ /* force the debug interface to be quiescent */
+ mrs x9, OSDLR_EL1
+ orr x9, x9, #0x1
+ msr OSDLR_EL1, x9
+
+ /* enter the cache-only sequence */
+29:
+ bl final_pwrdown
+
+ /* when we are here, the core has come out of wfi and the
+ * ddr is back up
+ */
+
+ mov x8, #POLICY_DEBUG_ENABLE
+ cbnz x8, 30f
+ /* restart the debug interface */
+ mrs x9, OSDLR_EL1
+ mov x10, #1
+ bic x9, x9, x10
+ msr OSDLR_EL1, x9
+
+ /* get saved DEVDISR regs off stack */
+30:
+ ldp x17, x18, [sp], #16
+ ldp x15, x16, [sp], #16
+ ldp x13, x14, [sp], #16
+ /* restore DEVDISR regs */
+ str w18, [x3, #DCFG_DEVDISR6_OFFSET]
+ str w17, [x3, #DCFG_DEVDISR5_OFFSET]
+ str w16, [x3, #DCFG_DEVDISR4_OFFSET]
+ str w15, [x3, #DCFG_DEVDISR3_OFFSET]
+ str w14, [x3, #DCFG_DEVDISR2_OFFSET]
+ str w13, [x3, #DCFG_DEVDISR1_OFFSET]
+ isb
+
+ /* get saved IPSTPCRn regs off stack */
+ ldp x13, x14, [sp], #16
+ ldp x11, x12, [sp], #16
+ ldp x9, x10, [sp], #16
+
+ /* restore IPSTPCRn regs */
+ mov x15, #PMU_IPSTPCR5_OFFSET
+ str w14, [x1, x15]
+ mov x16, #PMU_IPSTPCR4_OFFSET
+ str w13, [x1, x16]
+ mov x17, #PMU_IPSTPCR3_OFFSET
+ str w12, [x1, x17]
+ mov x18, #PMU_IPSTPCR2_OFFSET
+ str w11, [x1, x18]
+ mov x19, #PMU_IPSTPCR1_OFFSET
+ str w10, [x1, x19]
+ mov x20, #PMU_IPSTPCR0_OFFSET
+ str w9, [x1, x20]
+ isb
+
+ /* poll on IPSTPACKCRn regs til IP clocks are restarted */
+ mov w4, #CLOCK_RETRY_CNT
+ mov x15, #PMU_IPSTPACKSR5_OFFSET
+16:
+ ldr w5, [x1, x15]
+ and w5, w5, w14
+ cbz w5, 17f
+ sub w4, w4, #1
+ cbnz w4, 16b
+
+17:
+ mov w4, #CLOCK_RETRY_CNT
+ mov x15, #PMU_IPSTPACKSR4_OFFSET
+18:
+ ldr w5, [x1, x15]
+ and w5, w5, w13
+ cbz w5, 19f
+ sub w4, w4, #1
+ cbnz w4, 18b
+
+19:
+ mov w4, #CLOCK_RETRY_CNT
+ mov x15, #PMU_IPSTPACKSR3_OFFSET
+20:
+ ldr w5, [x1, x15]
+ and w5, w5, w12
+ cbz w5, 21f
+ sub w4, w4, #1
+ cbnz w4, 20b
+
+21:
+ mov w4, #CLOCK_RETRY_CNT
+ mov x15, #PMU_IPSTPACKSR2_OFFSET
+22:
+ ldr w5, [x1, x15]
+ and w5, w5, w11
+ cbz w5, 23f
+ sub w4, w4, #1
+ cbnz w4, 22b
+
+23:
+ mov w4, #CLOCK_RETRY_CNT
+ mov x15, #PMU_IPSTPACKSR1_OFFSET
+24:
+ ldr w5, [x1, x15]
+ and w5, w5, w10
+ cbz w5, 25f
+ sub w4, w4, #1
+ cbnz w4, 24b
+
+25:
+ mov w4, #CLOCK_RETRY_CNT
+ mov x15, #PMU_IPSTPACKSR0_OFFSET
+26:
+ ldr w5, [x1, x15]
+ and w5, w5, w9
+ cbz w5, 27f
+ sub w4, w4, #1
+ cbnz w4, 26b
+
+27:
+ /* disable the stop-request-override */
+ mov x8, #PMU_POWMGTDCR0_OFFSET
+ mov w9, #POWMGTDCR_STP_OV_EN
+ str w9, [x2, x8]
+ isb
+
+ /* get hnf-sdcr and cpuactlr off stack */
+ ldp x7, x8, [sp], #16
+
+ /* restore cpuactlr */
+ msr CORTEX_A72_CPUACTLR_EL1, x8
+ isb
+
+ /* restore snooping in the hnf nodes */
+ ldr x9, =NXP_CCN_HN_F_0_ADDR
+ mov x6, #CCN_HNF_NODE_COUNT
+28:
+ str x7, [x9, #CCN_HN_F_SNP_DMN_CTL_SET_OFFSET]
+ sub x6, x6, #1
+ add x9, x9, #CCN_HNF_OFFSET
+ cbnz x6, 28b
+ isb
+
+ mov x30, x28
+ ret
+endfunc _soc_sys_pwrdn_wfi
+
+
+/* Part of CPU_SUSPEND
+ * Function performs any SoC-specific cleanup after power-down
+ * in: x0 = core mask lsb
+ * out: none
+ * uses x0,
+ */
+func _soc_sys_exit_pwrdn
+
+ mrs x1, CORTEX_A72_ECTLR_EL1
+ /* make sure the smp bit is set */
+ orr x1, x1, #CPUECTLR_SMPEN_MASK
+ /* clr the retention control */
+ mov x2, #CPUECTLR_RET_8CLK
+ bic x1, x1, x2
+ /* enable tablewalk prefetch */
+ mov x2, #CPUECTLR_DISABLE_TWALK_PREFETCH
+ bic x1, x1, x2
+ msr CORTEX_A72_ECTLR_EL1, x1
+ isb
+
+ ret
+endfunc _soc_sys_exit_pwrdn
+
+
+/* Function will pwrdown ddr and the final core - it will do this
+ * by loading itself into the icache and then executing from there
+ * in:
+ * x0 = core mask
+ * x1 = NXP_PMU_CCSR_ADDR
+ * x2 = NXP_PMU_DCSR_ADDR
+ * x3 = NXP_DCFG_ADDR
+ * x4 = NXP_DDR_ADDR
+ * x5 = NXP_DDR2_ADDR
+ * w6 = IPSTPCR4
+ * w7 = DEVDISR5
+ * x12 = PMU_CLAINACTSETR_OFFSET
+ * x13 = PMU_CLSINACTSETR_OFFSET
+ * x14 = PMU_CLAINACTCLRR_OFFSET
+ * x15 = PMU_CLSINACTCLRR_OFFSET
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x13, x14, x15, x16,
+ * x17, x18
+ */
+
+/* 4Kb aligned */
+.align 12
+func final_pwrdown
+
+ mov x0, xzr
+ b touch_line_0
+start_line_0:
+ mov x0, #1
+ /* put ddr controller 1 into self-refresh */
+ ldr w8, [x4, #DDR_CFG_2_OFFSET]
+ orr w8, w8, #CFG_2_FORCE_REFRESH
+ str w8, [x4, #DDR_CFG_2_OFFSET]
+
+ /* put ddr controller 2 into self-refresh */
+ ldr w8, [x5, #DDR_CFG_2_OFFSET]
+ orr w8, w8, #CFG_2_FORCE_REFRESH
+ str w8, [x5, #DDR_CFG_2_OFFSET]
+
+ /* stop the clocks in both ddr controllers */
+ mov w10, #DEVDISR5_MASK_DDR
+ mov x16, #PMU_IPSTPCR4_OFFSET
+ orr w9, w6, w10
+ str w9, [x1, x16]
+ isb
+
+ mov x17, #PMU_IPSTPACKSR4_OFFSET
+touch_line_0:
+ cbz x0, touch_line_1
+
+start_line_1:
+ /* poll IPSTPACKSR4 until
+ * ddr controller clocks are stopped.
+ */
+1:
+ ldr w8, [x1, x17]
+ and w8, w8, w10
+ cmp w8, w10
+ b.ne 1b
+
+ /* shut down power to the ddr controllers */
+ orr w9, w7, #DEVDISR5_MASK_DDR
+ str w9, [x3, #DCFG_DEVDISR5_OFFSET]
+
+ /* disable cluster acp ports */
+ mov w8, #CLAINACT_DISABLE_ACP
+ str w8, [x1, x12]
+
+ /* disable skyros ports */
+ mov w9, #CLSINACT_DISABLE_SKY
+ str w9, [x1, x13]
+ isb
+
+touch_line_1:
+ cbz x0, touch_line_2
+
+start_line_2:
+ isb
+3:
+ wfi
+
+ /* if we are here then we are awake
+ * - bring this device back up
+ */
+
+ /* enable skyros ports */
+ mov w9, #CLSINACT_DISABLE_SKY
+ str w9, [x1, x15]
+
+ /* enable acp ports */
+ mov w8, #CLAINACT_DISABLE_ACP
+ str w8, [x1, x14]
+ isb
+
+ /* bring up the ddr controllers */
+ str w7, [x3, #DCFG_DEVDISR5_OFFSET]
+ isb
+ str w6, [x1, x16]
+ isb
+
+ nop
+touch_line_2:
+ cbz x0, touch_line_3
+
+start_line_3:
+ /* poll IPSTPACKSR4 until
+ * ddr controller clocks are running
+ */
+ mov w10, #DEVDISR5_MASK_DDR
+2:
+ ldr w8, [x1, x17]
+ and w8, w8, w10
+ cbnz w8, 2b
+
+ /* take ddr controller 2 out of self-refresh */
+ mov w8, #CFG_2_FORCE_REFRESH
+ ldr w9, [x5, #DDR_CFG_2_OFFSET]
+ bic w9, w9, w8
+ str w9, [x5, #DDR_CFG_2_OFFSET]
+
+ /* take ddr controller 1 out of self-refresh */
+ ldr w9, [x4, #DDR_CFG_2_OFFSET]
+ bic w9, w9, w8
+ str w9, [x4, #DDR_CFG_2_OFFSET]
+ isb
+
+ nop
+ nop
+ nop
+touch_line_3:
+ cbz x0, start_line_0
+
+ /* execute here after ddr is back up */
+
+ ret
+endfunc final_pwrdown
+
+/* Function returns CLUSTER_3_NORMAL if the cores of cluster 3 are
+ * to be handled normally, and it returns CLUSTER_3_IN_RESET if the cores
+ * are to be held in reset
+ * in: none
+ * out: x0 = #CLUSTER_3_NORMAL, cluster 3 treated normal
+ * x0 = #CLUSTER_3_IN_RESET, cluster 3 cores held in reset
+ * uses x0, x1, x2
+ */
+func cluster3InReset
+
+ /* default return is treat cores normal */
+ mov x0, #CLUSTER_3_NORMAL
+
+ /* read RCW_SR27 register */
+ mov x1, #NXP_DCFG_ADDR
+ ldr w2, [x1, #RCW_SR27_OFFSET]
+
+ /* test the cluster 3 bit */
+ tst w2, #CLUSTER_3_RCW_BIT
+ b.eq 1f
+
+ /* if we are here, then the bit was set */
+ mov x0, #CLUSTER_3_IN_RESET
+1:
+ ret
+endfunc cluster3InReset
+
+
+/* Function checks to see if cores which are to be disabled have been
+ * released from reset - if not, it releases them
+ * Note: there may be special handling of cluster 3 cores depending upon the
+ * sys clk frequency
+ * in: none
+ * out: none
+ * uses x0, x1, x2, x3, x4, x5, x6, x7, x8, x9
+ */
+func release_disabled
+ mov x9, x30
+
+ /* check if we need to keep cluster 3 cores in reset */
+ bl cluster3InReset /* 0-2 */
+ mov x8, x0
+
+ /* x8 = cluster 3 handling */
+
+ /* read COREDISABLESR */
+ mov x0, #NXP_DCFG_ADDR
+ ldr w4, [x0, #DCFG_COREDISABLEDSR_OFFSET]
+ cmp x8, #CLUSTER_3_IN_RESET
+ b.ne 4f
+
+ /* the cluster 3 cores are to be held in reset, so remove
+ * them from the disable mask
+ */
+ bic x4, x4, #CLUSTER_3_CORES_MASK
+4:
+ /* get the number of cpus on this device */
+ mov x6, #PLATFORM_CORE_COUNT
+
+ mov x0, #NXP_RESET_ADDR
+ ldr w5, [x0, #BRR_OFFSET]
+
+ /* load the core mask for the first core */
+ mov x7, #1
+
+ /* x4 = COREDISABLESR
+ * x5 = BRR
+ * x6 = loop count
+ * x7 = core mask bit
+ */
+2:
+ /* check if the core is to be disabled */
+ tst x4, x7
+ b.eq 1f
+
+ /* see if disabled cores have already been released from reset */
+ tst x5, x7
+ b.ne 5f
+
+ /* if core has not been released, then release it (0-3) */
+ mov x0, x7
+ bl _soc_core_release
+
+ /* record the core state in the data area (0-3) */
+ mov x0, x7
+ mov x1, #CORE_STATE_DATA
+ mov x2, #CORE_DISABLED
+ bl _setCoreData
+
+1:
+ /* see if this is a cluster 3 core */
+ mov x3, #CLUSTER_3_CORES_MASK
+ tst x3, x7
+ b.eq 5f
+
+ /* this is a cluster 3 core - see if it needs to be held in reset */
+ cmp x8, #CLUSTER_3_IN_RESET
+ b.ne 5f
+
+ /* record the core state as disabled in the data area (0-3) */
+ mov x0, x7
+ mov x1, #CORE_STATE_DATA
+ mov x2, #CORE_DISABLED
+ bl _setCoreData
+
+5:
+ /* decrement the counter */
+ subs x6, x6, #1
+ b.le 3f
+
+ /* shift the core mask to the next core */
+ lsl x7, x7, #1
+ /* continue */
+ b 2b
+3:
+ cmp x8, #CLUSTER_3_IN_RESET
+ b.ne 6f
+
+ /* we need to hold the cluster 3 cores in reset,
+ * so mark them in the COREDISR and COREDISABLEDSR registers as
+ * "disabled", and the rest of the sw stack will leave them alone
+ * thinking that they have been disabled
+ */
+ mov x0, #NXP_DCFG_ADDR
+ ldr w1, [x0, #DCFG_COREDISR_OFFSET]
+ orr w1, w1, #CLUSTER_3_CORES_MASK
+ str w1, [x0, #DCFG_COREDISR_OFFSET]
+
+ ldr w2, [x0, #DCFG_COREDISABLEDSR_OFFSET]
+ orr w2, w2, #CLUSTER_3_CORES_MASK
+ str w2, [x0, #DCFG_COREDISABLEDSR_OFFSET]
+ dsb sy
+ isb
+
+#if (PSCI_TEST)
+ /* x0 = NXP_DCFG_ADDR : read COREDISABLESR */
+ ldr w4, [x0, #DCFG_COREDISABLEDSR_OFFSET]
+ /* read COREDISR */
+ ldr w3, [x0, #DCFG_COREDISR_OFFSET]
+#endif
+
+6:
+ mov x30, x9
+ ret
+
+endfunc release_disabled
+
+
+/* Function setc up the TrustZone Address Space Controller (TZASC)
+ * in: none
+ * out: none
+ * uses x0, x1
+ */
+func init_tzpc
+
+ /* set Non Secure access for all devices protected via TZPC */
+
+ /* decode Protection-0 Set Reg */
+ ldr x1, =TZPCDECPROT_0_SET_BASE
+ /* set decode region to NS, Bits[7:0] */
+ mov w0, #0xFF
+ str w0, [x1]
+
+ /* decode Protection-1 Set Reg */
+ ldr x1, =TZPCDECPROT_1_SET_BASE
+ /* set decode region to NS, Bits[7:0] */
+ mov w0, #0xFF
+ str w0, [x1]
+
+ /* decode Protection-2 Set Reg */
+ ldr x1, =TZPCDECPROT_2_SET_BASE
+ /* set decode region to NS, Bits[7:0] */
+ mov w0, #0xFF
+ str w0, [x1]
+
+ /* entire SRAM as NS */
+ /* secure RAM region size Reg */
+ ldr x1, =TZPC_BASE
+ /* 0x00000000 = no secure region */
+ mov w0, #0x00000000
+ str w0, [x1]
+
+ ret
+endfunc init_tzpc
+
+/* write a register in the DCFG block
+ * in: x0 = offset
+ * in: w1 = value to write
+ * uses x0, x1, x2
+ */
+func _write_reg_dcfg
+ ldr x2, =NXP_DCFG_ADDR
+ str w1, [x2, x0]
+ ret
+endfunc _write_reg_dcfg
+
+
+/* read a register in the DCFG block
+ * in: x0 = offset
+ * out: w0 = value read
+ * uses x0, x1, x2
+ */
+func _read_reg_dcfg
+ ldr x2, =NXP_DCFG_ADDR
+ ldr w1, [x2, x0]
+ mov w0, w1
+ ret
+endfunc _read_reg_dcfg
+
+
+/* Function returns an mpidr value for a core, given a core_mask_lsb
+ * in: x0 = core mask lsb
+ * out: x0 = affinity2:affinity1:affinity0, where affinity is 8-bits
+ * uses x0, x1
+ */
+func get_mpidr_value
+
+ /* convert a core mask to an SoC core number */
+ clz w0, w0
+ mov w1, #31
+ sub w0, w1, w0
+
+ /* get the mpidr core number from the SoC core number */
+ mov w1, wzr
+ tst x0, #1
+ b.eq 1f
+ orr w1, w1, #1
+
+1:
+ /* extract the cluster number */
+ lsr w0, w0, #1
+ orr w0, w1, w0, lsl #8
+
+ ret
+endfunc get_mpidr_value
+
+
+/* Function returns the redistributor base address for the core specified
+ * in x1
+ * in: x0 - core mask lsb of specified core
+ * out: x0 = redistributor rd base address for specified core
+ * uses x0, x1, x2
+ */
+func get_gic_rd_base
+ clz w1, w0
+ mov w2, #0x20
+ sub w2, w2, w1
+ sub w2, w2, #1
+
+ ldr x0, =NXP_GICR_ADDR
+ mov x1, #GIC_RD_OFFSET
+
+ /* x2 = core number
+ * loop counter
+ */
+2:
+ cbz x2, 1f
+ add x0, x0, x1
+ sub x2, x2, #1
+ b 2b
+1:
+ ret
+endfunc get_gic_rd_base
+
+
+/* Function returns the redistributor base address for the core specified
+ * in x1
+ * in: x0 - core mask lsb of specified core
+ * out: x0 = redistributor sgi base address for specified core
+ * uses x0, x1, x2
+ */
+func get_gic_sgi_base
+ clz w1, w0
+ mov w2, #0x20
+ sub w2, w2, w1
+ sub w2, w2, #1
+
+ ldr x0, =NXP_GICR_SGI_ADDR
+ mov x1, #GIC_SGI_OFFSET
+
+ /* loop counter */
+2:
+ cbz x2, 1f /* x2 = core number */
+ add x0, x0, x1
+ sub x2, x2, #1
+ b 2b
+1:
+ ret
+endfunc get_gic_sgi_base
+
+/* Function writes a register in the RESET block
+ * in: x0 = offset
+ * in: w1 = value to write
+ * uses x0, x1, x2
+ */
+func _write_reg_reset
+ ldr x2, =NXP_RESET_ADDR
+ str w1, [x2, x0]
+ ret
+endfunc _write_reg_reset
+
+
+/* Function reads a register in the RESET block
+ * in: x0 = offset
+ * out: w0 = value read
+ * uses x0, x1
+ */
+func _read_reg_reset
+ ldr x1, =NXP_RESET_ADDR
+ ldr w0, [x1, x0]
+ ret
+endfunc _read_reg_reset
diff --git a/plat/nxp/soc-lx2160a/aarch64/lx2160a_helpers.S b/plat/nxp/soc-lx2160a/aarch64/lx2160a_helpers.S
new file mode 100644
index 0000000..c364dec
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/aarch64/lx2160a_helpers.S
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+#include <platform_def.h>
+
+.globl plat_secondary_cold_boot_setup
+.globl plat_is_my_cpu_primary
+.globl plat_reset_handler
+.globl platform_mem_init
+
+
+func platform_mem1_init
+ ret
+endfunc platform_mem1_init
+
+
+func platform_mem_init
+ ret
+endfunc platform_mem_init
+
+
+func apply_platform_errata
+
+ ret
+endfunc apply_platform_errata
+
+
+func plat_reset_handler
+ mov x29, x30
+ bl apply_platform_errata
+
+#if defined(IMAGE_BL31)
+ ldr x0, =POLICY_SMMU_PAGESZ_64K
+ cbz x0, 1f
+ /* Set the SMMU page size in the sACR register */
+ bl _set_smmu_pagesz_64
+#endif
+1:
+ mov x30, x29
+
+ ret
+endfunc 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 e.g
+ * mark the cpu's presence, mechanism to place it in a
+ * holding pen etc.
+ */
+func plat_secondary_cold_boot_setup
+ /* lx2160a does not do cold boot for secondary CPU */
+cb_panic:
+ b cb_panic
+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
+ mrs x0, mpidr_el1
+ and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+ cmp x0, 0x0
+ cset w0, eq
+ ret
+endfunc plat_is_my_cpu_primary
diff --git a/plat/nxp/soc-lx2160a/aarch64/lx2160a_warm_rst.S b/plat/nxp/soc-lx2160a/aarch64/lx2160a_warm_rst.S
new file mode 100644
index 0000000..9dec3f2
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/aarch64/lx2160a_warm_rst.S
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+.section .text, "ax"
+
+#include <asm_macros.S>
+
+#ifndef NXP_COINED_BB
+#include <flash_info.h>
+#include <fspi.h>
+#endif
+#include <regs.h>
+#ifdef NXP_COINED_BB
+#include <snvs.h>
+#endif
+
+#include <plat_warm_rst.h>
+#include <platform_def.h>
+
+#define SDRAM_CFG 0x110
+#define SDRAM_CFG_2 0x114
+#define SDRAM_MD_CNTL 0x120
+#define SDRAM_INTERVAL 0x124
+#define TIMING_CFG_10 0x258
+#define DEBUG_2 0xF04
+#define DEBUG_26 0xF64
+#define DDR_DSR2 0xB24
+
+#define DDR_CNTRLR_2 0x2
+#define COUNT_100 1000
+
+ .globl _soc_sys_warm_reset
+ .align 12
+
+func _soc_sys_warm_reset
+ mov x3, xzr
+ b touch_line0
+start_line0:
+ mov x3, #1
+ mov x2, #NUM_OF_DDRC
+ ldr x1, =NXP_DDR_ADDR
+1:
+ ldr w0, [x1, #SDRAM_CFG]
+ orr w0, w0, #SDRAM_CFG_MEM_HLT
+ str w0, [x1, #SDRAM_CFG]
+2:
+ ldr w0, [x1, #DEBUG_2]
+ and w0, w0, #DDR_DBG_2_MEM_IDLE
+ cbz w0, 2b
+
+ ldr w0, [x1, #DEBUG_26]
+ orr w0, w0, #DDR_DEBUG_26_BIT_12
+ orr w0, w0, #DDR_DEBUG_26_BIT_13
+ orr w0, w0, #DDR_DEBUG_26_BIT_14
+touch_line0:
+ cbz x3, touch_line1
+
+ orr w0, w0, #DDR_DEBUG_26_BIT_15
+ orr w0, w0, #DDR_DEBUG_26_BIT_16
+ str w0, [x1, #DEBUG_26]
+
+ ldr w0, [x1, #SDRAM_CFG_2]
+ orr w0, w0, #SDRAM_CFG2_FRC_SR
+ str w0, [x1, #SDRAM_CFG_2]
+
+3:
+ ldr w0, [x1, #DDR_DSR2]
+ orr w0, w0, #DDR_DSR_2_PHY_INIT_CMPLT
+ str w0, [x1, #DDR_DSR2]
+ ldr w0, [x1, #DDR_DSR2]
+ and w0, w0, #DDR_DSR_2_PHY_INIT_CMPLT
+ cbnz w0, 3b
+
+ ldr w0, [x1, #SDRAM_INTERVAL]
+ and w0, w0, #SDRAM_INTERVAL_REFINT_CLEAR
+ str w0, [x1, #SDRAM_INTERVAL]
+touch_line1:
+ cbz x3, touch_line2
+
+ ldr w0, [x1, #SDRAM_MD_CNTL]
+ orr w0, w0, #MD_CNTL_CKE(1)
+ orr w0, w0, #MD_CNTL_MD_EN
+ str w0, [x1, #SDRAM_MD_CNTL]
+
+ ldr w0, [x1, #TIMING_CFG_10]
+ orr w0, w0, #DDR_TIMING_CFG_10_T_STAB
+ str w0, [x1, #TIMING_CFG_10]
+
+ ldr w0, [x1, #SDRAM_CFG_2]
+ and w0, w0, #SDRAM_CFG2_FRC_SR_CLEAR
+ str w0, [x1, #SDRAM_CFG_2]
+
+4:
+ ldr w0, [x1, #DDR_DSR2]
+ and w0, w0, #DDR_DSR_2_PHY_INIT_CMPLT
+ cbz w0, 4b
+ nop
+touch_line2:
+ cbz x3, touch_line3
+
+ ldr w0, [x1, #DEBUG_26]
+ orr w0, w0, #DDR_DEBUG_26_BIT_25
+ and w0, w0, #DDR_DEBUG_26_BIT_24_CLEAR
+ str w0, [x1, #DEBUG_26]
+
+ cmp x2, #DDR_CNTRLR_2
+ b.ne 5f
+ ldr x1, =NXP_DDR2_ADDR
+ mov x2, xzr
+ b 1b
+
+5:
+ mov x5, xzr
+6:
+ add x5, x5, #1
+ cmp x5, #COUNT_100
+ b.ne 6b
+ nop
+touch_line3:
+ cbz x3, touch_line4
+#ifdef NXP_COINED_BB
+ ldr x1, =NXP_SNVS_ADDR
+ ldr w0, [x1, #NXP_APP_DATA_LP_GPR_OFFSET]
+
+ /* On Warm Boot is enabled, then zeroth bit
+ * of SNVS LP GPR register 0 will used
+ * to save the status of warm-reset as a cause.
+ */
+ orr w0, w0, #(1 << NXP_LPGPR_ZEROTH_BIT)
+
+ /* write back */
+ str w0, [x1, #NXP_APP_DATA_LP_GPR_OFFSET]
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+touch_line4:
+ cbz x3, touch_line6
+#elif !(ERLY_WRM_RST_FLG_FLSH_UPDT)
+ ldr x1, =NXP_FLEXSPI_ADDR
+ ldr w0, [x1, #FSPI_IPCMD]
+ orr w0, w0, #FSPI_IPCMD_TRG_MASK
+ str w0, [x1, #FSPI_IPCMD]
+7:
+ ldr w0, [x1, #FSPI_INTR]
+ and w0, w0, #FSPI_INTR_IPCMDDONE_MASK
+ cmp w0, #0
+ b.eq 7b
+
+ ldr w0, [x1, #FSPI_IPTXFCR]
+ orr w0, w0, #FSPI_IPTXFCR_CLR
+ str w0, [x1, #FSPI_IPTXFCR]
+
+ ldr w0, [x1, #FSPI_INTR]
+ orr w0, w0, #FSPI_INTR_IPCMDDONE_MASK
+ str w0, [x1, #FSPI_INTR]
+ nop
+touch_line4:
+ cbz x3, touch_line5
+ /* flexspi driver has an api
+ * is_flash_busy().
+ * Impelementation of the api will not
+ * fit-in in 1 cache line.
+ * instead a nop-cycles are introduced to
+ * simulate the wait time for flash write
+ * completion.
+ *
+ * Note: This wait time varies from flash to flash.
+ */
+
+ mov x0, #FLASH_WR_COMP_WAIT_BY_NOP_COUNT
+8:
+ sub x0, x0, #1
+ nop
+ cmp x0, #0
+ b.ne 8b
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+touch_line5:
+ cbz x3, touch_line6
+#endif
+ ldr x2, =NXP_RST_ADDR
+ /* clear the RST_REQ_MSK and SW_RST_REQ */
+ mov w0, #0x00000000
+ str w0, [x2, #RSTCNTL_OFFSET]
+
+ /* initiate the sw reset request */
+ mov w0, #SW_RST_REQ_INIT
+ str w0, [x2, #RSTCNTL_OFFSET]
+
+ /* In case this address range is mapped as cacheable,
+ * flush the write out of the dcaches.
+ */
+ add x2, x2, #RSTCNTL_OFFSET
+ dc cvac, x2
+ dsb st
+ isb
+
+ /* Function does not return */
+ b .
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+touch_line6:
+ cbz x3, start_line0
+
+endfunc _soc_sys_warm_reset
diff --git a/plat/nxp/soc-lx2160a/ddr_fip.mk b/plat/nxp/soc-lx2160a/ddr_fip.mk
new file mode 100644
index 0000000..f14a9e8
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/ddr_fip.mk
@@ -0,0 +1,97 @@
+#
+# Copyright 2020 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+DDR_PHY_BIN_PATH ?= ./ddr-phy-binary/lx2160a
+
+ifeq (${DDR_IMEM_UDIMM_1D},)
+ DDR_IMEM_UDIMM_1D := ${DDR_PHY_BIN_PATH}/ddr4_pmu_train_imem.bin
+endif
+
+ifeq (${DDR_IMEM_UDIMM_2D},)
+ DDR_IMEM_UDIMM_2D := ${DDR_PHY_BIN_PATH}/ddr4_2d_pmu_train_imem.bin
+endif
+
+ifeq (${DDR_DMEM_UDIMM_1D},)
+ DDR_DMEM_UDIMM_1D := ${DDR_PHY_BIN_PATH}/ddr4_pmu_train_dmem.bin
+endif
+
+ifeq (${DDR_DMEM_UDIMM_2D},)
+ DDR_DMEM_UDIMM_2D := ${DDR_PHY_BIN_PATH}/ddr4_2d_pmu_train_dmem.bin
+endif
+
+ifeq (${DDR_IMEM_RDIMM_1D},)
+ DDR_IMEM_RDIMM_1D := ${DDR_PHY_BIN_PATH}/ddr4_rdimm_pmu_train_imem.bin
+endif
+
+ifeq (${DDR_IMEM_RDIMM_2D},)
+ DDR_IMEM_RDIMM_2D := ${DDR_PHY_BIN_PATH}/ddr4_rdimm2d_pmu_train_imem.bin
+endif
+
+ifeq (${DDR_DMEM_RDIMM_1D},)
+ DDR_DMEM_RDIMM_1D := ${DDR_PHY_BIN_PATH}/ddr4_rdimm_pmu_train_dmem.bin
+endif
+
+ifeq (${DDR_DMEM_RDIMM_2D},)
+ DDR_DMEM_RDIMM_2D := ${DDR_PHY_BIN_PATH}/ddr4_rdimm2d_pmu_train_dmem.bin
+endif
+
+$(shell mkdir -p '${BUILD_PLAT}')
+
+ifeq (${DDR_FIP_NAME},)
+ifeq (${TRUSTED_BOARD_BOOT},1)
+ DDR_FIP_NAME := ddr_fip_sec.bin
+else
+ DDR_FIP_NAME := ddr_fip.bin
+endif
+endif
+
+ifneq (${TRUSTED_BOARD_BOOT},1)
+
+DDR_FIP_ARGS += --ddr-immem-udimm-1d ${DDR_IMEM_UDIMM_1D} \
+ --ddr-immem-udimm-2d ${DDR_IMEM_UDIMM_2D} \
+ --ddr-dmmem-udimm-1d ${DDR_DMEM_UDIMM_1D} \
+ --ddr-dmmem-udimm-2d ${DDR_DMEM_UDIMM_2D} \
+ --ddr-immem-rdimm-1d ${DDR_IMEM_RDIMM_1D} \
+ --ddr-immem-rdimm-2d ${DDR_IMEM_RDIMM_2D} \
+ --ddr-dmmem-rdimm-1d ${DDR_DMEM_RDIMM_1D} \
+ --ddr-dmmem-rdimm-2d ${DDR_DMEM_RDIMM_2D}
+endif
+
+
+ifeq (${TRUSTED_BOARD_BOOT},1)
+ifeq (${MBEDTLS_DIR},)
+include plat/nxp/soc-lx2160a/ddr_sb.mk
+else
+include plat/nxp/soc-lx2160a/ddr_tbbr.mk
+
+# Variables for use with Certificate Generation Tool
+CRTTOOLPATH ?= tools/cert_create
+CRTTOOL ?= ${CRTTOOLPATH}/cert_create${BIN_EXT}
+
+ifneq (${GENERATE_COT},0)
+ddr_certificates: ${DDR_CRT_DEPS} ${CRTTOOL}
+ ${Q}${CRTTOOL} ${DDR_CRT_ARGS}
+ @${ECHO_BLANK_LINE}
+ @echo "Built $@ successfully"
+ @echo "DDR certificates can be found in ${BUILD_PLAT}"
+ @${ECHO_BLANK_LINE}
+endif
+endif
+endif
+
+# Variables for use with Firmware Image Package
+FIPTOOLPATH ?= tools/fiptool
+FIPTOOL ?= ${FIPTOOLPATH}/fiptool${BIN_EXT}
+
+${BUILD_PLAT}/${DDR_FIP_NAME}: ${DDR_FIP_DEPS} ${FIPTOOL}
+ $(eval ${CHECK_DDR_FIP_CMD})
+ ${Q}${FIPTOOL} create ${DDR_FIP_ARGS} $@
+ ${Q}${FIPTOOL} info $@
+ @${ECHO_BLANK_LINE}
+ @echo "Built $@ successfully"
+ @${ECHO_BLANK_LINE}
+
+fip_ddr: ${BUILD_PLAT}/${DDR_FIP_NAME}
diff --git a/plat/nxp/soc-lx2160a/ddr_sb.mk b/plat/nxp/soc-lx2160a/ddr_sb.mk
new file mode 100644
index 0000000..c11651e
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/ddr_sb.mk
@@ -0,0 +1,43 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifneq (${TRUSTED_BOARD_BOOT},0)
+
+ifeq (${GENERATE_COT},0)
+
+DDR_FIP_ARGS += --ddr-immem-udimm-1d ${DDR_IMEM_UDIMM_1D}.sb \
+ --ddr-immem-udimm-2d ${DDR_IMEM_UDIMM_2D}.sb \
+ --ddr-dmmem-udimm-1d ${DDR_DMEM_UDIMM_1D}.sb \
+ --ddr-dmmem-udimm-2d ${DDR_DMEM_UDIMM_2D}.sb \
+ --ddr-immem-rdimm-1d ${DDR_IMEM_RDIMM_1D}.sb \
+ --ddr-immem-rdimm-2d ${DDR_IMEM_RDIMM_2D}.sb \
+ --ddr-dmmem-rdimm-1d ${DDR_DMEM_RDIMM_1D}.sb \
+ --ddr-dmmem-rdimm-2d ${DDR_DMEM_RDIMM_2D}.sb
+endif
+
+UDIMM_DEPS = ${DDR_IMEM_UDIMM_1D}.sb ${DDR_IMEM_UDIMM_2D}.sb ${DDR_DMEM_UDIMM_1D}.sb ${DDR_DMEM_UDIMM_2D}.sb
+RDIMM_DEPS = ${DDR_IMEM_RDIMM_1D}.sb ${DDR_IMEM_RDIMM_2D}.sb ${DDR_DMEM_RDIMM_1D}.sb ${DDR_DMEM_RDIMM_2D}.sb
+DDR_FIP_DEPS += ${UDIMM_DEPS}
+DDR_FIP_DEPS += ${RDIMM_DEPS}
+
+# Max Size of CSF header (CSF_HDR_SZ = 0x3000).
+# Image will be appended at this offset of the header.
+# Path to CST directory is required to generate the CSF header,
+# and prepend it to image before fip image gets generated
+ifeq (${CST_DIR},)
+ $(error Error: CST_DIR not set)
+endif
+
+ifeq (${DDR_INPUT_FILE},)
+DDR_INPUT_FILE:= drivers/nxp/auth/csf_hdr_parser/${CSF_FILE}
+endif
+
+%.sb: %
+ @echo " Generating CSF Header for $@ $<"
+ $(CST_DIR)/create_hdr_esbc --in $< --out $@ --app_off ${CSF_HDR_SZ} \
+ --app $< ${DDR_INPUT_FILE}
+
+endif
diff --git a/plat/nxp/soc-lx2160a/ddr_tbbr.mk b/plat/nxp/soc-lx2160a/ddr_tbbr.mk
new file mode 100644
index 0000000..deb475b
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/ddr_tbbr.mk
@@ -0,0 +1,95 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# This file defines the keys and certificates that must be created to establish
+# a Chain of Trust for the DDR FW. These definitions include the
+# command line options passed to the cert_create and fiptool commands for DDR FW.
+# A DDR FW key is used for signing the DDR Firmware. The DDR key is authenticated
+# by the Trusted World Key. Two content certificates are created:
+# For DDR RDIMM Images [ signed by DDR FW Key]
+# For DDR UDIMM Images [ signed by DDR FW Key]
+#
+# Expected environment:
+#
+# BUILD_PLAT: output directory
+#
+# Build options added by this file:
+#
+# KEY_ALG
+# KEY_SIZE
+# TRUSTED_WORLD_KEY
+# NON_TRUSTED_WORLD_KEY
+#
+
+# Copy the tbbr.mk from PLAT_TOOL_PATH/cert_create_helper
+# to the ${PLAT_DIR}. So that cert_create is enabled
+# to create certificates for DDR
+$(shell cp ${PLAT_TOOL_PATH}/cert_create_helper/cert_create_tbbr.mk ${PLAT_DIR})
+
+# Certificate generation tool default parameters
+DDR_FW_CERT := ${BUILD_PLAT}/ddr_fw_key_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,DDR_))
+
+$(shell mkdir -p '${BUILD_PLAT}')
+
+ifeq (${DDR_KEY},)
+DDR_KEY=${BUILD_PLAT}/ddr.pem
+endif
+
+ifeq (${TRUSTED_KEY_CERT},)
+$(info Generating: Trusted key certificate as part of DDR cert creation)
+TRUSTED_KEY_CERT := ${BUILD_PLAT}/trusted_key.crt
+$(eval $(call TOOL_ADD_PAYLOAD,${TRUSTED_KEY_CERT},--trusted-key-cert,))
+$(eval $(call TOOL_ADD_PAYLOAD,${TRUSTED_KEY_CERT},--trusted-key-cert,,DDR_))
+else
+$(info Using: Trusted key certificate as part of DDR cert creation)
+DDR_FIP_ARGS += --trusted-key-cert ${TRUSTED_KEY_CERT}
+endif
+
+# 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,DDR_)))
+$(if ${KEY_SIZE},$(eval $(call CERT_ADD_CMD_OPT,${KEY_SIZE},--key-size,DDR_)))
+$(if ${HASH_ALG},$(eval $(call CERT_ADD_CMD_OPT,${HASH_ALG},--hash-alg,DDR_)))
+$(if ${ROT_KEY},$(eval $(call CERT_ADD_CMD_OPT,${ROT_KEY},--rot-key,DDR_)))
+$(if ${TRUSTED_WORLD_KEY},$(eval $(call CERT_ADD_CMD_OPT,${TRUSTED_WORLD_KEY},--trusted-world-key,DDR_)))
+$(if ${NON_TRUSTED_WORLD_KEY},$(eval $(call CERT_ADD_CMD_OPT,${NON_TRUSTED_WORLD_KEY},--non-trusted-world-key, DDR_)))
+
+# Add the DDR CoT (key cert + img cert)
+$(if ${DDR_KEY},$(eval $(call CERT_ADD_CMD_OPT,${DDR_KEY},--ddr-fw-key,DDR_)))
+$(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/ddr_fw_key.crt,--ddr-fw-key-cert,,DDR_))
+$(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/ddr_udimm_fw_content.crt,--ddr-udimm-fw-cert,,DDR_))
+$(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/ddr_rdimm_fw_content.crt,--ddr-rdimm-fw-cert,,DDR_))
+
+$(eval $(call TOOL_ADD_IMG,DDR_IMEM_UDIMM_1D,--ddr-immem-udimm-1d,DDR_))
+$(eval $(call TOOL_ADD_IMG,DDR_IMEM_UDIMM_2D,--ddr-immem-udimm-2d,DDR_))
+$(eval $(call TOOL_ADD_IMG,DDR_DMEM_UDIMM_1D,--ddr-dmmem-udimm-1d,DDR_))
+$(eval $(call TOOL_ADD_IMG,DDR_DMEM_UDIMM_2D,--ddr-dmmem-udimm-2d,DDR_))
+
+$(eval $(call TOOL_ADD_IMG,DDR_IMEM_RDIMM_1D,--ddr-immem-rdimm-1d,DDR_))
+$(eval $(call TOOL_ADD_IMG,DDR_IMEM_RDIMM_2D,--ddr-immem-rdimm-2d,DDR_))
+$(eval $(call TOOL_ADD_IMG,DDR_DMEM_RDIMM_1D,--ddr-dmmem-rdimm-1d,DDR_))
+$(eval $(call TOOL_ADD_IMG,DDR_DMEM_RDIMM_2D,--ddr-dmmem-rdimm-2d,DDR_))
+
+DDR_FIP_DEPS += ddr_certificates
+
+# Process TBB related flags
+ifneq (${GENERATE_COT},0)
+ # Common cert_create options
+ ifneq (${CREATE_KEYS},0)
+ $(eval DDR_CRT_ARGS += -n)
+ ifneq (${SAVE_KEYS},0)
+ $(eval DDR_CRT_ARGS += -k)
+ endif
+ endif
+endif
diff --git a/plat/nxp/soc-lx2160a/include/soc.h b/plat/nxp/soc-lx2160a/include/soc.h
new file mode 100644
index 0000000..7cc4a03
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/include/soc.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef _SOC_H
+#define _SOC_H
+
+/* Chassis specific defines - common across SoC's of a particular platform */
+#include <dcfg_lsch3.h>
+#include <soc_default_base_addr.h>
+#include <soc_default_helper_macros.h>
+
+
+#define NUM_DRAM_REGIONS 3
+#define NXP_DRAM0_ADDR 0x80000000
+#define NXP_DRAM0_MAX_SIZE 0x80000000 /* 2 GB */
+
+#define NXP_DRAM1_ADDR 0x2080000000
+#define NXP_DRAM1_MAX_SIZE 0x1F80000000 /* 126 G */
+
+#define NXP_DRAM2_ADDR 0x6000000000
+#define NXP_DRAM2_MAX_SIZE 0x2000000000 /* 128G */
+
+/*DRAM0 Size defined in platform_def.h */
+#define NXP_DRAM0_SIZE PLAT_DEF_DRAM0_SIZE
+
+#define DDR_PLL_FIX
+#define NXP_DDR_PHY1_ADDR 0x01400000
+#define NXP_DDR_PHY2_ADDR 0x01600000
+
+#if defined(IMAGE_BL31)
+#define LS_SYS_TIMCTL_BASE 0x2890000
+
+#ifdef LS_SYS_TIMCTL_BASE
+#define PLAT_LS_NSTIMER_FRAME_ID 0
+#define LS_CONFIG_CNTACR 1
+#endif
+#endif
+
+/* Start: Macros used by soc.c: get_boot_dev */
+#define PORSR1_RCW_MASK 0x07800000
+#define PORSR1_RCW_SHIFT 23
+
+#define SDHC1_VAL 0x8
+#define SDHC2_VAL 0x9
+#define I2C1_VAL 0xa
+#define FLEXSPI_NAND2K_VAL 0xc
+#define FLEXSPI_NAND4K_VAL 0xd
+#define FLEXSPI_NOR 0xf
+/* End: Macros used by soc.c: get_boot_dev */
+
+/* SVR Definition (not include major and minor rev) */
+#define SVR_LX2160A 0x873601
+#define SVR_LX2120A 0x873621
+#define SVR_LX2080A 0x873603
+
+/* Number of cores in platform */
+/* Used by common code for array initialization */
+#define NUMBER_OF_CLUSTERS 8
+#define CORES_PER_CLUSTER 2
+#define PLATFORM_CORE_COUNT NUMBER_OF_CLUSTERS * CORES_PER_CLUSTER
+
+/*
+ * Required LS standard platform porting definitions
+ * for CCN-508
+ */
+#define PLAT_CLUSTER_TO_CCN_ID_MAP 11, 15, 27, 31, 12, 28, 16, 0
+#define PLAT_6CLUSTER_TO_CCN_ID_MAP 11, 15, 27, 31, 12, 28
+
+
+/* Defines required for using XLAT tables from ARM common code */
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 40)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 40)
+
+/* Clock Divisors */
+#define NXP_PLATFORM_CLK_DIVIDER 2
+#define NXP_UART_CLK_DIVIDER 4
+
+/* Start: Macros used by lx2160a.S */
+#define MPIDR_AFFINITY0_MASK 0x00FF
+#define MPIDR_AFFINITY1_MASK 0xFF00
+#define CPUECTLR_DISABLE_TWALK_PREFETCH 0x4000000000
+#define CPUECTLR_INS_PREFETCH_MASK 0x1800000000
+#define CPUECTLR_DAT_PREFETCH_MASK 0x0300000000
+#define CPUECTLR_RET_8CLK 0x2
+#define OSDLR_EL1_DLK_LOCK 0x1
+#define CNTP_CTL_EL0_EN 0x1
+#define CNTP_CTL_EL0_IMASK 0x2
+/* set to 0 if the clusters are not symmetrical */
+#define SYMMETRICAL_CLUSTERS 1
+/* End: Macros used by lx2160a.S */
+
+/* Start: Macros used by lib/psci files */
+#define SYSTEM_PWR_DOMAINS 1
+#define PLAT_NUM_PWR_DOMAINS (PLATFORM_CORE_COUNT + \
+ NUMBER_OF_CLUSTERS + \
+ SYSTEM_PWR_DOMAINS)
+
+/* Power state coordination occurs at the system level */
+#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2
+
+/* define retention state */
+#define PLAT_MAX_RET_STATE (PSCI_LOCAL_STATE_RUN + 1)
+
+/* define power-down state */
+#define PLAT_MAX_OFF_STATE (PLAT_MAX_RET_STATE + 1)
+/* End: Macros used by lib/psci files */
+
+/* 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.
+ *
+ * CACHE_WRITEBACK_GRANULE is defined in soc.def
+ *
+ * One cache line needed for bakery locks on ARM platforms
+ */
+#define PLAT_PERCPU_BAKERY_LOCK_SIZE (1 * CACHE_WRITEBACK_GRANULE)
+
+#ifndef WDOG_RESET_FLAG
+#define WDOG_RESET_FLAG DEFAULT_SET_VALUE
+#endif
+
+#ifndef WARM_BOOT_SUCCESS
+#define WARM_BOOT_SUCCESS DEFAULT_SET_VALUE
+#endif
+
+#ifndef __ASSEMBLER__
+
+void set_base_freq_CNTFID0(void);
+void soc_init_start(void);
+void soc_init_finish(void);
+void soc_init_percpu(void);
+void _soc_set_start_addr(unsigned long addr);
+void _set_platform_security(void);
+
+#endif
+
+#endif /* _SOC_H */
diff --git a/plat/nxp/soc-lx2160a/lx2160aqds/ddr_init.c b/plat/nxp/soc-lx2160a/lx2160aqds/ddr_init.c
new file mode 100644
index 0000000..d44733c
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/lx2160aqds/ddr_init.c
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <ddr.h>
+#include <lib/utils.h>
+#include <load_img.h>
+
+#include "plat_common.h"
+#include <platform_def.h>
+
+#ifdef CONFIG_STATIC_DDR
+
+const struct ddr_cfg_regs static_3200 = {
+ .cs[0].bnds = U(0x03FF),
+ .cs[1].bnds = U(0x03FF),
+ .cs[0].config = U(0x80050422),
+ .cs[1].config = U(0x80000422),
+ .cs[2].bnds = U(0x00),
+ .cs[3].bnds = U(0x00),
+ .cs[2].config = U(0x00),
+ .cs[3].config = U(0x00),
+ .timing_cfg[0] = U(0xFFAA0018),
+ .timing_cfg[1] = U(0x646A8844),
+ .timing_cfg[2] = U(0x00058022),
+ .timing_cfg[3] = U(0x13622100),
+ .timing_cfg[4] = U(0x02),
+ .timing_cfg[5] = U(0x07401400),
+ .timing_cfg[7] = U(0x3BB00000),
+ .timing_cfg[8] = U(0x0944AC00),
+ .sdram_cfg[0] = U(0x65044008),
+ .sdram_cfg[1] = U(0x00401011),
+ .sdram_cfg[2] = U(0x00),
+ .sdram_mode[0] = U(0x06010C50),
+ .sdram_mode[1] = U(0x00280400),
+ .sdram_mode[2] = U(0x00),
+ .sdram_mode[3] = U(0x00),
+ .sdram_mode[4] = U(0x00),
+ .sdram_mode[5] = U(0x00),
+ .sdram_mode[6] = U(0x00),
+ .sdram_mode[7] = U(0x00),
+ .sdram_mode[8] = U(0x0500),
+ .sdram_mode[9] = U(0x10240000),
+ .sdram_mode[10] = U(0x00),
+ .sdram_mode[11] = U(0x00),
+ .sdram_mode[12] = U(0x00),
+ .sdram_mode[13] = U(0x00),
+ .sdram_mode[14] = U(0x00),
+ .sdram_mode[15] = U(0x00),
+ .md_cntl = U(0x00),
+ .interval = U(0x30C00000),
+ .data_init = U(0xDEADBEEF),
+ .init_addr = U(0x00),
+ .zq_cntl = U(0x8A090705),
+ .sdram_rcw[0] = U(0x00),
+ .sdram_rcw[1] = U(0x00),
+ .sdram_rcw[2] = U(0x00),
+ .sdram_rcw[3] = U(0x00),
+ .sdram_rcw[4] = U(0x00),
+ .sdram_rcw[5] = U(0x00),
+ .err_disable = U(0x00),
+ .err_int_en = U(0x00),
+};
+
+const struct ddr_cfg_regs static_2900 = {
+ .cs[0].bnds = U(0x03FF),
+ .cs[1].bnds = U(0x03FF),
+ .cs[0].config = U(0x80050422),
+ .cs[1].config = U(0x80000422),
+ .cs[2].bnds = U(0x00),
+ .cs[3].bnds = U(0x00),
+ .cs[2].config = U(0x00),
+ .cs[3].config = U(0x00),
+ .timing_cfg[0] = U(0xFF990018),
+ .timing_cfg[1] = U(0x4F4A4844),
+ .timing_cfg[2] = U(0x0005601F),
+ .timing_cfg[3] = U(0x125F2100),
+ .timing_cfg[4] = U(0x02),
+ .timing_cfg[5] = U(0x07401400),
+ .timing_cfg[7] = U(0x3AA00000),
+ .timing_cfg[8] = U(0x09449B00),
+ .sdram_cfg[0] = U(0x65044008),
+ .sdram_cfg[1] = U(0x00401011),
+ .sdram_cfg[2] = U(0x00),
+ .sdram_mode[0] = U(0x06010C50),
+ .sdram_mode[1] = U(0x00280400),
+ .sdram_mode[2] = U(0x00),
+ .sdram_mode[3] = U(0x00),
+ .sdram_mode[4] = U(0x00),
+ .sdram_mode[5] = U(0x00),
+ .sdram_mode[6] = U(0x00),
+ .sdram_mode[7] = U(0x00),
+ .sdram_mode[8] = U(0x0500),
+ .sdram_mode[9] = U(0x10240000),
+ .sdram_mode[10] = U(0x00),
+ .sdram_mode[11] = U(0x00),
+ .sdram_mode[12] = U(0x00),
+ .sdram_mode[13] = U(0x00),
+ .sdram_mode[14] = U(0x00),
+ .sdram_mode[15] = U(0x00),
+ .md_cntl = U(0x00),
+ .interval = U(0x2C2E0000),
+ .data_init = U(0xDEADBEEF),
+ .init_addr = U(0x00),
+ .zq_cntl = U(0x8A090705),
+ .sdram_rcw[0] = U(0x00),
+ .sdram_rcw[1] = U(0x00),
+ .sdram_rcw[2] = U(0x00),
+ .sdram_rcw[3] = U(0x00),
+ .sdram_rcw[4] = U(0x00),
+ .sdram_rcw[5] = U(0x00),
+ .err_disable = U(0x00),
+ .err_int_en = U(0x00),
+};
+
+const struct ddr_cfg_regs static_2600 = {
+ .cs[0].bnds = U(0x03FF),
+ .cs[1].bnds = U(0x03FF),
+ .cs[0].config = U(0x80050422),
+ .cs[1].config = U(0x80000422),
+ .cs[2].bnds = U(0x00),
+ .cs[3].bnds = U(0x00),
+ .cs[2].config = U(0x00),
+ .cs[3].config = U(0x00),
+ .timing_cfg[0] = U(0xFF880018),
+ .timing_cfg[1] = U(0x2A24F444),
+ .timing_cfg[2] = U(0x007141DC),
+ .timing_cfg[3] = U(0x125B2100),
+ .timing_cfg[4] = U(0x02),
+ .timing_cfg[5] = U(0x06401400),
+ .timing_cfg[7] = U(0x28800000),
+ .timing_cfg[8] = U(0x07338A00),
+ .sdram_cfg[0] = U(0x65044008),
+ .sdram_cfg[1] = U(0x00401011),
+ .sdram_cfg[2] = U(0x00),
+ .sdram_mode[0] = U(0x06010A70),
+ .sdram_mode[1] = U(0x00200400),
+ .sdram_mode[2] = U(0x00),
+ .sdram_mode[3] = U(0x00),
+ .sdram_mode[4] = U(0x00),
+ .sdram_mode[5] = U(0x00),
+ .sdram_mode[6] = U(0x00),
+ .sdram_mode[7] = U(0x00),
+ .sdram_mode[8] = U(0x0500),
+ .sdram_mode[9] = U(0x0C240000),
+ .sdram_mode[10] = U(0x00),
+ .sdram_mode[11] = U(0x00),
+ .sdram_mode[12] = U(0x00),
+ .sdram_mode[13] = U(0x00),
+ .sdram_mode[14] = U(0x00),
+ .sdram_mode[15] = U(0x00),
+ .md_cntl = U(0x00),
+ .interval = U(0x279C0000),
+ .data_init = U(0xDEADBEEF),
+ .init_addr = U(0x00),
+ .zq_cntl = U(0x8A090705),
+ .sdram_rcw[0] = U(0x00),
+ .sdram_rcw[1] = U(0x00),
+ .sdram_rcw[2] = U(0x00),
+ .sdram_rcw[3] = U(0x00),
+ .sdram_rcw[4] = U(0x00),
+ .sdram_rcw[5] = U(0x00),
+ .err_disable = U(0x00),
+ .err_int_en = U(0x00),
+};
+
+const struct dimm_params static_dimm = {
+ .rdimm = U(0),
+ .primary_sdram_width = U(64),
+ .ec_sdram_width = U(8),
+ .n_ranks = U(2),
+ .device_width = U(8),
+ .mirrored_dimm = U(1),
+};
+
+/* Sample code using two UDIMM MT18ASF1G72AZ-2G6B1, on each DDR controller */
+unsigned long long board_static_ddr(struct ddr_info *priv)
+{
+ (void)memcpy(&priv->ddr_reg, &static_2900, sizeof(static_2900));
+ (void)memcpy(&priv->dimm, &static_dimm, sizeof(static_dimm));
+ priv->conf.cs_on_dimm[0] = 0x3;
+ ddr_board_options(priv);
+ compute_ddr_phy(priv);
+
+ return ULL(0x400000000);
+}
+
+#elif defined(CONFIG_DDR_NODIMM)
+/*
+ * Sample code to bypass reading SPD. This is a sample, not recommended
+ * for boards with slots. DDR model number: UDIMM MT18ASF1G72AZ-2G6B1.
+ */
+
+const struct dimm_params ddr_raw_timing = {
+ .n_ranks = U(2),
+ .rank_density = U(4294967296u),
+ .capacity = U(8589934592u),
+ .primary_sdram_width = U(64),
+ .ec_sdram_width = U(8),
+ .device_width = U(8),
+ .die_density = U(0x4),
+ .rdimm = U(0),
+ .mirrored_dimm = U(1),
+ .n_row_addr = U(15),
+ .n_col_addr = U(10),
+ .bank_addr_bits = U(0),
+ .bank_group_bits = U(2),
+ .edc_config = U(2),
+ .burst_lengths_bitmask = U(0x0c),
+ .tckmin_x_ps = 750,
+ .tckmax_ps = 1600,
+ .caslat_x = U(0x00FFFC00),
+ .taa_ps = 13750,
+ .trcd_ps = 13750,
+ .trp_ps = 13750,
+ .tras_ps = 32000,
+ .trc_ps = 457500,
+ .twr_ps = 15000,
+ .trfc1_ps = 260000,
+ .trfc2_ps = 160000,
+ .trfc4_ps = 110000,
+ .tfaw_ps = 21000,
+ .trrds_ps = 3000,
+ .trrdl_ps = 4900,
+ .tccdl_ps = 5000,
+ .refresh_rate_ps = U(7800000),
+};
+
+int ddr_get_ddr_params(struct dimm_params *pdimm,
+ struct ddr_conf *conf)
+{
+ static const char dimm_model[] = "Fixed DDR on board";
+
+ conf->dimm_in_use[0] = 1; /* Modify accordingly */
+ memcpy(pdimm, &ddr_raw_timing, sizeof(struct dimm_params));
+ memcpy(pdimm->mpart, dimm_model, sizeof(dimm_model) - 1);
+
+ /* valid DIMM mask, change accordingly, together with dimm_on_ctlr. */
+ return 0x5;
+}
+#endif /* CONFIG_DDR_NODIMM */
+
+int ddr_board_options(struct ddr_info *priv)
+{
+ struct memctl_opt *popts = &priv->opt;
+ const struct ddr_conf *conf = &priv->conf;
+
+ popts->vref_dimm = U(0x24); /* range 1, 83.4% */
+ popts->rtt_override = 0;
+ popts->rtt_park = U(240);
+ popts->otf_burst_chop_en = 0;
+ popts->burst_length = U(DDR_BL8);
+ popts->trwt_override = U(1);
+ popts->bstopre = U(0); /* auto precharge */
+ popts->addr_hash = 1;
+
+ /* Set ODT impedance on PHY side */
+ switch (conf->cs_on_dimm[1]) {
+ case 0xc: /* Two slots dual rank */
+ case 0x4: /* Two slots single rank, not valid for interleaving */
+ popts->trwt = U(0xf);
+ popts->twrt = U(0x7);
+ popts->trrt = U(0x7);
+ popts->twwt = U(0x7);
+ popts->vref_phy = U(0x6B); /* 83.6% */
+ popts->odt = U(60);
+ popts->phy_tx_impedance = U(28);
+ break;
+ case 0: /* One slot used */
+ default:
+ popts->trwt = U(0x3);
+ popts->twrt = U(0x3);
+ popts->trrt = U(0x3);
+ popts->twwt = U(0x3);
+ popts->vref_phy = U(0x60); /* 75% */
+ popts->odt = U(48);
+ popts->phy_tx_impedance = U(28);
+ break;
+ }
+
+ return 0;
+}
+
+#ifdef NXP_WARM_BOOT
+long long init_ddr(uint32_t wrm_bt_flg)
+#else
+long long init_ddr(void)
+#endif
+{
+ int spd_addr[] = {0x51U, 0x52U, 0x53U, 0x54U};
+ struct ddr_info info;
+ struct sysinfo sys;
+ long long dram_size;
+
+ zeromem(&sys, sizeof(sys));
+ if (get_clocks(&sys) == 1) {
+ ERROR("System clocks are not set.\n");
+ panic();
+ }
+ debug("platform clock %lu\n", sys.freq_platform);
+ debug("DDR PLL1 %lu\n", sys.freq_ddr_pll0);
+ debug("DDR PLL2 %lu\n", sys.freq_ddr_pll1);
+
+ zeromem(&info, sizeof(info));
+
+ /* Set two DDRC. Unused DDRC will be removed automatically. */
+ info.num_ctlrs = NUM_OF_DDRC;
+ info.spd_addr = spd_addr;
+ info.ddr[0] = (void *)NXP_DDR_ADDR;
+ info.ddr[1] = (void *)NXP_DDR2_ADDR;
+ info.phy[0] = (void *)NXP_DDR_PHY1_ADDR;
+ info.phy[1] = (void *)NXP_DDR_PHY2_ADDR;
+ info.clk = get_ddr_freq(&sys, 0);
+ info.img_loadr = load_img;
+ info.phy_gen2_fw_img_buf = PHY_GEN2_FW_IMAGE_BUFFER;
+ if (info.clk == 0) {
+ info.clk = get_ddr_freq(&sys, 1);
+ }
+ info.dimm_on_ctlr = DDRC_NUM_DIMM;
+
+ info.warm_boot_flag = DDR_WRM_BOOT_NT_SUPPORTED;
+#ifdef NXP_WARM_BOOT
+ info.warm_boot_flag = DDR_COLD_BOOT;
+ if (wrm_bt_flg != 0U) {
+ info.warm_boot_flag = DDR_WARM_BOOT;
+ } else {
+ info.warm_boot_flag = DDR_COLD_BOOT;
+ }
+#endif
+
+ dram_size = dram_init(&info
+#if defined(NXP_HAS_CCN504) || defined(NXP_HAS_CCN508)
+ , NXP_CCN_HN_F_0_ADDR
+#endif
+ );
+
+
+ if (dram_size < 0) {
+ ERROR("DDR init failed.\n");
+ }
+
+ return dram_size;
+}
diff --git a/plat/nxp/soc-lx2160a/lx2160aqds/plat_def.h b/plat/nxp/soc-lx2160a/lx2160aqds/plat_def.h
new file mode 100644
index 0000000..f480f92
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/lx2160aqds/plat_def.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PLAT_DEF_H
+#define PLAT_DEF_H
+
+#include <arch.h>
+#include <cortex_a72.h>
+/* Required without TBBR.
+ * To include the defines for DDR PHY
+ * Images.
+ */
+#include <tbbr_img_def.h>
+
+#include <policy.h>
+#include <soc.h>
+
+#if defined(IMAGE_BL31)
+#define LS_SYS_TIMCTL_BASE 0x2890000
+#define PLAT_LS_NSTIMER_FRAME_ID 0
+#define LS_CONFIG_CNTACR 1
+#endif
+
+#define NXP_SYSCLK_FREQ 100000000
+#define NXP_DDRCLK_FREQ 100000000
+
+/* UART related definition */
+#define NXP_CONSOLE_ADDR NXP_UART_ADDR
+#define NXP_CONSOLE_BAUDRATE 115200
+
+/* Size of cacheable stacks */
+#if defined(IMAGE_BL2)
+#if defined(TRUSTED_BOARD_BOOT)
+#define PLATFORM_STACK_SIZE 0x2000
+#else
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+#elif defined(IMAGE_BL31)
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+
+/* SD block buffer */
+#define NXP_SD_BLOCK_BUF_SIZE (0x8000)
+#define NXP_SD_BLOCK_BUF_ADDR (NXP_OCRAM_ADDR + NXP_OCRAM_SIZE \
+ - NXP_SD_BLOCK_BUF_SIZE)
+
+#ifdef SD_BOOT
+#define BL2_LIMIT (NXP_OCRAM_ADDR + NXP_OCRAM_SIZE \
+ - NXP_SD_BLOCK_BUF_SIZE)
+#else
+#define BL2_LIMIT (NXP_OCRAM_ADDR + NXP_OCRAM_SIZE)
+#endif
+
+/* IO defines as needed by IO driver framework */
+#define MAX_IO_DEVICES 4
+#define MAX_IO_BLOCK_DEVICES 1
+#define MAX_IO_HANDLES 4
+
+#define PHY_GEN2_FW_IMAGE_BUFFER (NXP_OCRAM_ADDR + CSF_HDR_SZ)
+
+/*
+ * FIP image defines - Offset at which FIP Image would be present
+ * Image would include Bl31 , Bl33 and Bl32 (optional)
+ */
+#ifdef POLICY_FUSE_PROVISION
+#define MAX_FIP_DEVICES 3
+#endif
+
+#ifndef MAX_FIP_DEVICES
+#define MAX_FIP_DEVICES 2
+#endif
+
+/*
+ * ID of the secure physical generic timer interrupt used by the BL32.
+ */
+#define BL32_IRQ_SEC_PHY_TIMER 29
+
+#define BL31_WDOG_SEC 89
+
+#define BL31_NS_WDOG_WS1 108
+
+/*
+ * 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_LS_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(BL32_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE)
+
+/* SGI 15 and Secure watchdog interrupts assigned to Group 0 */
+#define NXP_IRQ_SEC_SGI_7 15
+
+#define PLAT_LS_G0_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(BL31_WDOG_SEC, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(BL31_NS_WDOG_WS1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(NXP_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL)
+#endif
diff --git a/plat/nxp/soc-lx2160a/lx2160aqds/platform.c b/plat/nxp/soc-lx2160a/lx2160aqds/platform.c
new file mode 100644
index 0000000..b00adb5
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/lx2160aqds/platform.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <plat_common.h>
+
+#pragma weak board_enable_povdd
+#pragma weak board_disable_povdd
+
+bool board_enable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool board_disable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
diff --git a/plat/nxp/soc-lx2160a/lx2160aqds/platform.mk b/plat/nxp/soc-lx2160a/lx2160aqds/platform.mk
new file mode 100644
index 0000000..226b22b
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/lx2160aqds/platform.mk
@@ -0,0 +1,51 @@
+#
+# Copyright 2018-2020 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# board-specific build parameters
+
+BOOT_MODE ?= flexspi_nor
+BOARD ?= lx2160aqds
+POVDD_ENABLE := no
+NXP_COINED_BB := no
+
+ # DDR Compilation Configs
+NUM_OF_DDRC := 1
+DDRC_NUM_DIMM := 1
+DDRC_NUM_CS := 2
+DDR_ECC_EN := yes
+ #enable address decoding feature
+DDR_ADDR_DEC := yes
+APPLY_MAX_CDD := yes
+
+# DDR Errata
+ERRATA_DDR_A011396 := 1
+ERRATA_DDR_A050450 := 1
+
+ # On-Board Flash Details
+FLASH_TYPE := MT35XU512A
+XSPI_FLASH_SZ := 0x10000000
+NXP_XSPI_NOR_UNIT_SIZE := 0x20000
+BL2_BIN_XSPI_NOR_END_ADDRESS := 0x100000
+# CONFIG_FSPI_ERASE_4K is required to erase 4K sector sizes. This
+# config is enabled for future use cases.
+FSPI_ERASE_4K := 0
+
+# Platform specific features.
+WARM_BOOT := yes
+
+# Adding Platform files build files
+BL2_SOURCES += ${BOARD_PATH}/ddr_init.c\
+ ${BOARD_PATH}/platform.c
+
+SUPPORTED_BOOT_MODE := flexspi_nor \
+ sd \
+ emmc
+
+# Adding platform board build info
+include plat/nxp/common/plat_make_helper/plat_common_def.mk
+
+# Adding SoC build info
+include plat/nxp/soc-lx2160a/soc.mk
diff --git a/plat/nxp/soc-lx2160a/lx2160aqds/platform_def.h b/plat/nxp/soc-lx2160a/lx2160aqds/platform_def.h
new file mode 100644
index 0000000..5fa774e
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/lx2160aqds/platform_def.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include "plat_def.h"
+#include "plat_default_def.h"
+
+#endif
diff --git a/plat/nxp/soc-lx2160a/lx2160aqds/policy.h b/plat/nxp/soc-lx2160a/lx2160aqds/policy.h
new file mode 100644
index 0000000..05d23e2
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/lx2160aqds/policy.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef POLICY_H
+#define POLICY_H
+
+/* Following defines affect the PLATFORM SECURITY POLICY */
+
+/* set this to 0x0 if the platform is not using/responding to ECC errors
+ * set this to 0x1 if ECC is being used (we have to do some init)
+ */
+#define POLICY_USING_ECC 0x0
+
+/* Set this to 0x0 to leave the default SMMU page size in sACR
+ * Set this to 0x1 to change the SMMU page size to 64K
+ */
+#define POLICY_SMMU_PAGESZ_64K 0x1
+
+/*
+ * POLICY_PERF_WRIOP = 0 : No Performance enhancement for WRIOP RN-I
+ * POLICY_PERF_WRIOP = 1 : No Performance enhancement for WRIOP RN-I = 7
+ * POLICY_PERF_WRIOP = 2 : No Performance enhancement for WRIOP RN-I = 23
+ */
+#define POLICY_PERF_WRIOP 0
+
+/*
+ * set this to '1' if the debug clocks need to remain enabled during
+ * system entry to low-power (LPM20) - this should only be necessary
+ * for testing and NEVER set for normal production
+ */
+#define POLICY_DEBUG_ENABLE 0
+
+
+#endif /* POLICY_H */
diff --git a/plat/nxp/soc-lx2160a/lx2160ardb/ddr_init.c b/plat/nxp/soc-lx2160a/lx2160ardb/ddr_init.c
new file mode 100644
index 0000000..8669b1d
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/lx2160ardb/ddr_init.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <ddr.h>
+#include <lib/utils.h>
+#include <load_img.h>
+
+#include "plat_common.h"
+#include <platform_def.h>
+
+#ifdef CONFIG_STATIC_DDR
+const struct ddr_cfg_regs static_1600 = {
+ .cs[0].config = U(0xA8050322),
+ .cs[1].config = U(0x80000322),
+ .cs[0].bnds = U(0x3FF),
+ .cs[1].bnds = U(0x3FF),
+ .sdram_cfg[0] = U(0xE5044000),
+ .sdram_cfg[1] = U(0x401011),
+ .timing_cfg[0] = U(0xFF550018),
+ .timing_cfg[1] = U(0xBAB48C42),
+ .timing_cfg[2] = U(0x48C111),
+ .timing_cfg[3] = U(0x10C1000),
+ .timing_cfg[4] = U(0x2),
+ .timing_cfg[5] = U(0x3401400),
+ .timing_cfg[7] = U(0x13300000),
+ .timing_cfg[8] = U(0x2114600),
+ .sdram_mode[0] = U(0x6010210),
+ .sdram_mode[8] = U(0x500),
+ .sdram_mode[9] = U(0x4240000),
+ .interval = U(0x18600000),
+ .data_init = U(0xDEADBEEF),
+ .zq_cntl = U(0x8A090705),
+};
+
+const struct dimm_params static_dimm = {
+ .rdimm = U(0),
+ .primary_sdram_width = U(64),
+ .ec_sdram_width = U(8),
+ .n_ranks = U(2),
+ .device_width = U(8),
+ .mirrored_dimm = U(1),
+};
+
+/* Sample code using two UDIMM MT18ASF1G72AZ-2G6B1, on each DDR controller */
+unsigned long long board_static_ddr(struct ddr_info *priv)
+{
+ memcpy(&priv->ddr_reg, &static_1600, sizeof(static_1600));
+ memcpy(&priv->dimm, &static_dimm, sizeof(static_dimm));
+ priv->conf.cs_on_dimm[0] = 0x3;
+ ddr_board_options(priv);
+ compute_ddr_phy(priv);
+
+ return ULL(0x400000000);
+}
+
+#elif defined(CONFIG_DDR_NODIMM)
+/*
+ * Sample code to bypass reading SPD. This is a sample, not recommended
+ * for boards with slots. DDR model number: UDIMM MT18ASF1G72AZ-2G6B1.
+ */
+
+const struct dimm_params ddr_raw_timing = {
+ .n_ranks = U(2),
+ .rank_density = U(4294967296u),
+ .capacity = U(8589934592u),
+ .primary_sdram_width = U(64),
+ .ec_sdram_width = U(8),
+ .device_width = U(8),
+ .die_density = U(0x4),
+ .rdimm = U(0),
+ .mirrored_dimm = U(1),
+ .n_row_addr = U(15),
+ .n_col_addr = U(10),
+ .bank_addr_bits = U(0),
+ .bank_group_bits = U(2),
+ .edc_config = U(2),
+ .burst_lengths_bitmask = U(0x0c),
+ .tckmin_x_ps = 750,
+ .tckmax_ps = 1600,
+ .caslat_x = U(0x00FFFC00),
+ .taa_ps = 13750,
+ .trcd_ps = 13750,
+ .trp_ps = 13750,
+ .tras_ps = 32000,
+ .trc_ps = 457500,
+ .twr_ps = 15000,
+ .trfc1_ps = 260000,
+ .trfc2_ps = 160000,
+ .trfc4_ps = 110000,
+ .tfaw_ps = 21000,
+ .trrds_ps = 3000,
+ .trrdl_ps = 4900,
+ .tccdl_ps = 5000,
+ .refresh_rate_ps = U(7800000),
+};
+
+int ddr_get_ddr_params(struct dimm_params *pdimm,
+ struct ddr_conf *conf)
+{
+ static const char dimm_model[] = "Fixed DDR on board";
+
+ conf->dimm_in_use[0] = 1; /* Modify accordingly */
+ memcpy(pdimm, &ddr_raw_timing, sizeof(struct dimm_params));
+ memcpy(pdimm->mpart, dimm_model, sizeof(dimm_model) - 1);
+
+ /* valid DIMM mask, change accordingly, together with dimm_on_ctlr. */
+ return 0x5;
+}
+#endif /* CONFIG_DDR_NODIMM */
+
+int ddr_board_options(struct ddr_info *priv)
+{
+ struct memctl_opt *popts = &priv->opt;
+ const struct ddr_conf *conf = &priv->conf;
+
+ popts->vref_dimm = U(0x24); /* range 1, 83.4% */
+ popts->rtt_override = 0;
+ popts->rtt_park = U(240);
+ popts->otf_burst_chop_en = 0;
+ popts->burst_length = U(DDR_BL8);
+ popts->trwt_override = U(1);
+ popts->bstopre = U(0); /* auto precharge */
+ popts->addr_hash = 1;
+
+ /* Set ODT impedance on PHY side */
+ switch (conf->cs_on_dimm[1]) {
+ case 0xc: /* Two slots dual rank */
+ case 0x4: /* Two slots single rank, not valid for interleaving */
+ popts->trwt = U(0xf);
+ popts->twrt = U(0x7);
+ popts->trrt = U(0x7);
+ popts->twwt = U(0x7);
+ popts->vref_phy = U(0x6B); /* 83.6% */
+ popts->odt = U(60);
+ popts->phy_tx_impedance = U(28);
+ break;
+ case 0: /* One slot used */
+ default:
+ popts->trwt = U(0x3);
+ popts->twrt = U(0x3);
+ popts->trrt = U(0x3);
+ popts->twwt = U(0x3);
+ popts->vref_phy = U(0x60); /* 75% */
+ popts->odt = U(48);
+ popts->phy_tx_impedance = U(28);
+ break;
+ }
+
+ return 0;
+}
+
+long long init_ddr(void)
+{
+ int spd_addr[] = { 0x51, 0x52, 0x53, 0x54 };
+ struct ddr_info info;
+ struct sysinfo sys;
+ long long dram_size;
+
+ zeromem(&sys, sizeof(sys));
+ if (get_clocks(&sys) != 0) {
+ ERROR("System clocks are not set\n");
+ panic();
+ }
+ debug("platform clock %lu\n", sys.freq_platform);
+ debug("DDR PLL1 %lu\n", sys.freq_ddr_pll0);
+ debug("DDR PLL2 %lu\n", sys.freq_ddr_pll1);
+
+ zeromem(&info, sizeof(info));
+
+ /* Set two DDRC. Unused DDRC will be removed automatically. */
+ info.num_ctlrs = NUM_OF_DDRC;
+ info.spd_addr = spd_addr;
+ info.ddr[0] = (void *)NXP_DDR_ADDR;
+ info.ddr[1] = (void *)NXP_DDR2_ADDR;
+ info.phy[0] = (void *)NXP_DDR_PHY1_ADDR;
+ info.phy[1] = (void *)NXP_DDR_PHY2_ADDR;
+ info.clk = get_ddr_freq(&sys, 0);
+ info.img_loadr = load_img;
+ info.phy_gen2_fw_img_buf = PHY_GEN2_FW_IMAGE_BUFFER;
+ if (info.clk == 0) {
+ info.clk = get_ddr_freq(&sys, 1);
+ }
+ info.dimm_on_ctlr = DDRC_NUM_DIMM;
+
+ info.warm_boot_flag = DDR_WRM_BOOT_NT_SUPPORTED;
+
+ dram_size = dram_init(&info
+#if defined(NXP_HAS_CCN504) || defined(NXP_HAS_CCN508)
+ , NXP_CCN_HN_F_0_ADDR
+#endif
+ );
+
+
+ if (dram_size < 0) {
+ ERROR("DDR init failed.\n");
+ }
+
+ return dram_size;
+}
diff --git a/plat/nxp/soc-lx2160a/lx2160ardb/plat_def.h b/plat/nxp/soc-lx2160a/lx2160ardb/plat_def.h
new file mode 100644
index 0000000..02f51e7
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/lx2160ardb/plat_def.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PLAT_DEF_H
+#define PLAT_DEF_H
+
+#include <arch.h>
+#include <cortex_a72.h>
+/* Required without TBBR.
+ * To include the defines for DDR PHY
+ * Images.
+ */
+#include <tbbr_img_def.h>
+
+#include <policy.h>
+#include <soc.h>
+
+#if defined(IMAGE_BL31)
+#define LS_SYS_TIMCTL_BASE 0x2890000
+#define PLAT_LS_NSTIMER_FRAME_ID 0
+#define LS_CONFIG_CNTACR 1
+#endif
+
+#define NXP_SYSCLK_FREQ 100000000
+#define NXP_DDRCLK_FREQ 100000000
+
+/* UART related definition */
+#define NXP_CONSOLE_ADDR NXP_UART_ADDR
+#define NXP_CONSOLE_BAUDRATE 115200
+
+/* Size of cacheable stacks */
+#if defined(IMAGE_BL2)
+#if defined(TRUSTED_BOARD_BOOT)
+#define PLATFORM_STACK_SIZE 0x2000
+#else
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+#elif defined(IMAGE_BL31)
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+
+/* SD block buffer */
+#define NXP_SD_BLOCK_BUF_SIZE (0x8000)
+#define NXP_SD_BLOCK_BUF_ADDR (NXP_OCRAM_ADDR + NXP_OCRAM_SIZE \
+ - NXP_SD_BLOCK_BUF_SIZE)
+
+#ifdef SD_BOOT
+#define BL2_LIMIT (NXP_OCRAM_ADDR + NXP_OCRAM_SIZE \
+ - NXP_SD_BLOCK_BUF_SIZE)
+#else
+#define BL2_LIMIT (NXP_OCRAM_ADDR + NXP_OCRAM_SIZE)
+#endif
+
+/* IO defines as needed by IO driver framework */
+#define MAX_IO_DEVICES 4
+#define MAX_IO_BLOCK_DEVICES 1
+#define MAX_IO_HANDLES 4
+
+#define PHY_GEN2_FW_IMAGE_BUFFER (NXP_OCRAM_ADDR + CSF_HDR_SZ)
+
+/*
+ * FIP image defines - Offset at which FIP Image would be present
+ * Image would include Bl31 , Bl33 and Bl32 (optional)
+ */
+#ifdef POLICY_FUSE_PROVISION
+#define MAX_FIP_DEVICES 3
+#endif
+
+#ifndef MAX_FIP_DEVICES
+#define MAX_FIP_DEVICES 2
+#endif
+
+/*
+ * ID of the secure physical generic timer interrupt used by the BL32.
+ */
+#define BL32_IRQ_SEC_PHY_TIMER 29
+
+#define BL31_WDOG_SEC 89
+
+#define BL31_NS_WDOG_WS1 108
+
+/*
+ * 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_LS_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(BL32_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE)
+
+/* SGI 15 and Secure watchdog interrupts assigned to Group 0 */
+#define NXP_IRQ_SEC_SGI_7 15
+
+#define PLAT_LS_G0_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(BL31_WDOG_SEC, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(BL31_NS_WDOG_WS1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(NXP_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL)
+#endif
diff --git a/plat/nxp/soc-lx2160a/lx2160ardb/platform.c b/plat/nxp/soc-lx2160a/lx2160ardb/platform.c
new file mode 100644
index 0000000..b00adb5
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/lx2160ardb/platform.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <plat_common.h>
+
+#pragma weak board_enable_povdd
+#pragma weak board_disable_povdd
+
+bool board_enable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool board_disable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
diff --git a/plat/nxp/soc-lx2160a/lx2160ardb/platform.mk b/plat/nxp/soc-lx2160a/lx2160ardb/platform.mk
new file mode 100644
index 0000000..ffb5fad
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/lx2160ardb/platform.mk
@@ -0,0 +1,51 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# board-specific build parameters
+
+BOOT_MODE ?= flexspi_nor
+BOARD ?= lx2160ardb
+POVDD_ENABLE := no
+NXP_COINED_BB := no
+
+ # DDR Compilation Configs
+NUM_OF_DDRC := 2
+DDRC_NUM_DIMM := 2
+DDRC_NUM_CS := 4
+DDR_ECC_EN := yes
+ #enable address decoding feature
+DDR_ADDR_DEC := yes
+APPLY_MAX_CDD := yes
+
+# DDR Errata
+ERRATA_DDR_A011396 := 1
+ERRATA_DDR_A050450 := 1
+
+ # On-Board Flash Details
+FLASH_TYPE := MT35XU512A
+XSPI_FLASH_SZ := 0x10000000
+NXP_XSPI_NOR_UNIT_SIZE := 0x20000
+BL2_BIN_XSPI_NOR_END_ADDRESS := 0x100000
+# CONFIG_FSPI_ERASE_4K is required to erase 4K sector sizes. This
+# config is enabled for future use cases.
+FSPI_ERASE_4K := 0
+
+ # Platform specific features.
+WARM_BOOT := no
+
+ # Adding Platform files build files
+BL2_SOURCES += ${BOARD_PATH}/ddr_init.c\
+ ${BOARD_PATH}/platform.c
+
+SUPPORTED_BOOT_MODE := flexspi_nor \
+ sd \
+ emmc
+
+# Adding platform board build info
+include plat/nxp/common/plat_make_helper/plat_common_def.mk
+
+ # Adding SoC build info
+include plat/nxp/soc-lx2160a/soc.mk
diff --git a/plat/nxp/soc-lx2160a/lx2160ardb/platform_def.h b/plat/nxp/soc-lx2160a/lx2160ardb/platform_def.h
new file mode 100644
index 0000000..6660998
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/lx2160ardb/platform_def.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include "plat_def.h"
+#include "plat_default_def.h"
+
+#endif
diff --git a/plat/nxp/soc-lx2160a/lx2160ardb/policy.h b/plat/nxp/soc-lx2160a/lx2160ardb/policy.h
new file mode 100644
index 0000000..19ad6db
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/lx2160ardb/policy.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef POLICY_H
+#define POLICY_H
+
+/* Following defines affect the PLATFORM SECURITY POLICY */
+
+/* set this to 0x0 if the platform is not using/responding to ECC errors
+ * set this to 0x1 if ECC is being used (we have to do some init)
+ */
+#define POLICY_USING_ECC 0x0
+
+/* Set this to 0x0 to leave the default SMMU page size in sACR
+ * Set this to 0x1 to change the SMMU page size to 64K
+ */
+#define POLICY_SMMU_PAGESZ_64K 0x1
+
+/*
+ * POLICY_PERF_WRIOP = 0 : No Performance enhancement for WRIOP RN-I
+ * POLICY_PERF_WRIOP = 1 : No Performance enhancement for WRIOP RN-I = 7
+ * POLICY_PERF_WRIOP = 2 : No Performance enhancement for WRIOP RN-I = 23
+ */
+#define POLICY_PERF_WRIOP 0
+
+/*
+ * set this to '1' if the debug clocks need to remain enabled during
+ * system entry to low-power (LPM20) - this should only be necessary
+ * for testing and NEVER set for normal production
+ */
+#define POLICY_DEBUG_ENABLE 0
+
+
+#endif /* POLICY_H */
diff --git a/plat/nxp/soc-lx2160a/lx2162aqds/ddr_init.c b/plat/nxp/soc-lx2160a/lx2162aqds/ddr_init.c
new file mode 100644
index 0000000..73bcc93
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/lx2162aqds/ddr_init.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <ddr.h>
+#include <lib/utils.h>
+#include <load_img.h>
+
+#include "plat_common.h"
+#include <platform_def.h>
+
+#ifdef CONFIG_STATIC_DDR
+
+const struct ddr_cfg_regs static_3200 = {
+ .cs[0].bnds = U(0x03FFU),
+ .cs[1].bnds = U(0x03FF),
+ .cs[0].config = U(0x80050422),
+ .cs[1].config = U(0x80000422),
+ .cs[2].bnds = U(0x00),
+ .cs[3].bnds = U(0x00),
+ .cs[2].config = U(0x00),
+ .cs[3].config = U(0x00),
+ .timing_cfg[0] = U(0xFFAA0018),
+ .timing_cfg[1] = U(0x646A8844),
+ .timing_cfg[2] = U(0x00058022),
+ .timing_cfg[3] = U(0x13622100),
+ .timing_cfg[4] = U(0x02),
+ .timing_cfg[5] = U(0x07401400),
+ .timing_cfg[7] = U(0x3BB00000),
+ .timing_cfg[8] = U(0x0944AC00),
+ .sdram_cfg[0] = U(0x65044008),
+ .sdram_cfg[1] = U(0x00401011),
+ .sdram_cfg[2] = U(0x00),
+ .sdram_mode[0] = U(0x06010C50),
+ .sdram_mode[1] = U(0x00280400),
+ .sdram_mode[2] = U(0x00),
+ .sdram_mode[3] = U(0x00),
+ .sdram_mode[4] = U(0x00),
+ .sdram_mode[5] = U(0x00),
+ .sdram_mode[6] = U(0x00),
+ .sdram_mode[7] = U(0x00),
+ .sdram_mode[8] = U(0x0500),
+ .sdram_mode[9] = U(0x10240000),
+ .sdram_mode[10] = U(0x00),
+ .sdram_mode[11] = U(0x00),
+ .sdram_mode[12] = U(0x00),
+ .sdram_mode[13] = U(0x00),
+ .sdram_mode[14] = U(0x00),
+ .sdram_mode[15] = U(0x00),
+ .md_cntl = U(0x00),
+ .interval = U(0x30C00000),
+ .data_init = U(0xDEADBEEF),
+ .init_addr = U(0x00),
+ .zq_cntl = U(0x8A090705),
+ .sdram_rcw[0] = U(0x00),
+ .sdram_rcw[1] = U(0x00),
+ .sdram_rcw[2] = U(0x00),
+ .sdram_rcw[3] = U(0x00),
+ .sdram_rcw[4] = U(0x00),
+ .sdram_rcw[5] = U(0x00),
+ .err_disable = U(0x00),
+ .err_int_en = U(0x00),
+};
+
+const struct ddr_cfg_regs static_2900 = {
+ .cs[0].bnds = U(0x03FF),
+ .cs[1].bnds = U(0x03FF),
+ .cs[0].config = U(0x80050422),
+ .cs[1].config = U(0x80000422),
+ .cs[2].bnds = U(0x00),
+ .cs[3].bnds = U(0x00),
+ .cs[2].config = U(0x00),
+ .cs[3].config = U(0x00),
+ .timing_cfg[0] = U(0xFF990018),
+ .timing_cfg[1] = U(0x4F4A4844),
+ .timing_cfg[2] = U(0x0005601F),
+ .timing_cfg[3] = U(0x125F2100),
+ .timing_cfg[4] = U(0x02),
+ .timing_cfg[5] = U(0x07401400),
+ .timing_cfg[7] = U(0x3AA00000),
+ .timing_cfg[8] = U(0x09449B00),
+ .sdram_cfg[0] = U(0x65044008),
+ .sdram_cfg[1] = U(0x00401011),
+ .sdram_cfg[2] = U(0x00),
+ .sdram_mode[0] = U(0x06010C50),
+ .sdram_mode[1] = U(0x00280400),
+ .sdram_mode[2] = U(0x00),
+ .sdram_mode[3] = U(0x00),
+ .sdram_mode[4] = U(0x00),
+ .sdram_mode[5] = U(0x00),
+ .sdram_mode[6] = U(0x00),
+ .sdram_mode[7] = U(0x00),
+ .sdram_mode[8] = U(0x0500),
+ .sdram_mode[9] = U(0x10240000),
+ .sdram_mode[10] = U(0x00),
+ .sdram_mode[11] = U(0x00),
+ .sdram_mode[12] = U(0x00),
+ .sdram_mode[13] = U(0x00),
+ .sdram_mode[14] = U(0x00),
+ .sdram_mode[15] = U(0x00),
+ .md_cntl = U(0x00),
+ .interval = U(0x2C2E0000),
+ .data_init = U(0xDEADBEEF),
+ .init_addr = U(0x00),
+ .zq_cntl = U(0x8A090705),
+ .sdram_rcw[0] = U(0x00),
+ .sdram_rcw[1] = U(0x00),
+ .sdram_rcw[2] = U(0x00),
+ .sdram_rcw[3] = U(0x00),
+ .sdram_rcw[4] = U(0x00),
+ .sdram_rcw[5] = U(0x00),
+ .err_disable = U(0x00),
+ .err_int_en = U(0x00),
+};
+
+const struct ddr_cfg_regs static_2600 = {
+ .cs[0].bnds = U(0x03FF),
+ .cs[1].bnds = U(0x03FF),
+ .cs[0].config = U(0x80050422),
+ .cs[1].config = U(0x80000422),
+ .cs[2].bnds = U(0x00),
+ .cs[3].bnds = U(0x00),
+ .cs[2].config = U(0x00),
+ .cs[3].config = U(0x00),
+ .timing_cfg[0] = U(0xFF880018),
+ .timing_cfg[1] = U(0x2A24F444),
+ .timing_cfg[2] = U(0x007141DC),
+ .timing_cfg[3] = U(0x125B2100),
+ .timing_cfg[4] = U(0x02),
+ .timing_cfg[5] = U(0x06401400),
+ .timing_cfg[7] = U(0x28800000),
+ .timing_cfg[8] = U(0x07338A00),
+ .sdram_cfg[0] = U(0x65044008),
+ .sdram_cfg[1] = U(0x00401011),
+ .sdram_cfg[2] = U(0x00),
+ .sdram_mode[0] = U(0x06010A70),
+ .sdram_mode[1] = U(0x00200400),
+ .sdram_mode[2] = U(0x00),
+ .sdram_mode[3] = U(0x00),
+ .sdram_mode[4] = U(0x00),
+ .sdram_mode[5] = U(0x00),
+ .sdram_mode[6] = U(0x00),
+ .sdram_mode[7] = U(0x00),
+ .sdram_mode[8] = U(0x0500),
+ .sdram_mode[9] = U(0x0C240000),
+ .sdram_mode[10] = U(0x00),
+ .sdram_mode[11] = U(0x00),
+ .sdram_mode[12] = U(0x00),
+ .sdram_mode[13] = U(0x00),
+ .sdram_mode[14] = U(0x00),
+ .sdram_mode[15] = U(0x00),
+ .md_cntl = U(0x00),
+ .interval = U(0x279C0000),
+ .data_init = U(0xDEADBEEF),
+ .init_addr = U(0x00),
+ .zq_cntl = U(0x8A090705),
+ .sdram_rcw[0] = U(0x00),
+ .sdram_rcw[1] = U(0x00),
+ .sdram_rcw[2] = U(0x00),
+ .sdram_rcw[3] = U(0x00),
+ .sdram_rcw[4] = U(0x00),
+ .sdram_rcw[5] = U(0x00),
+ .err_disable = U(0x00),
+ .err_int_en = U(0x00),
+};
+
+const struct dimm_params static_dimm = {
+ .rdimm = 0U,
+ .primary_sdram_width = 64U,
+ .ec_sdram_width = 8U,
+ .n_ranks = 2U,
+ .device_width = 8U,
+ .mirrored_dimm = 1U,
+};
+
+/* Sample code using two UDIMM MT18ASF1G72AZ-2G6B1, on each DDR controller */
+unsigned long long board_static_ddr(struct ddr_info *priv)
+{
+ memcpy(&priv->ddr_reg, &static_2900, sizeof(static_2900));
+ memcpy(&priv->dimm, &static_dimm, sizeof(static_dimm));
+ priv->conf.cs_on_dimm[0] = 0x3;
+ ddr_board_options(priv);
+ compute_ddr_phy(priv);
+
+ return ULL(0x400000000);
+}
+
+#elif defined(CONFIG_DDR_NODIMM)
+/*
+ * Sample code to bypass reading SPD. This is a sample, not recommended
+ * for boards with slots. DDR model number: UDIMM MT18ASF1G72AZ-2G6B1.
+ */
+struct dimm_params ddr_raw_timing = {
+ .n_ranks = 2U,
+ .rank_density = U(0x200000000),
+ .capacity = U(0x400000000),
+ .primary_sdram_width = 64U,
+ .ec_sdram_width = 8U,
+ .device_width = 8U,
+ .die_density = U(0x5),
+ .rdimm = 0U,
+ .mirrored_dimm = 1U,
+ .n_row_addr = 16U,
+ .n_col_addr = 10U,
+ .bank_addr_bits = 0U,
+ .bank_group_bits = 2U,
+ .edc_config = 2U,
+ .burst_lengths_bitmask = U(0x0c),
+ .tckmin_x_ps = 625,
+ .tckmax_ps = 1600,
+ .caslat_x = U(0x15FFFC00),
+ .taa_ps = 13750,
+ .trcd_ps = 13750,
+ .trp_ps = 13750,
+ .tras_ps = 32000,
+ .trc_ps = 457500,
+ .twr_ps = 15000,
+ .trfc1_ps = 350000,
+ .trfc2_ps = 260000,
+ .trfc4_ps = 160000,
+ .tfaw_ps = 21000,
+ .trrds_ps = 2500,
+ .trrdl_ps = 4900,
+ .tccdl_ps = 5000,
+ .refresh_rate_ps = 7800000U,
+};
+
+int ddr_get_ddr_params(struct dimm_params *pdimm,
+ struct ddr_conf *conf)
+{
+ static const char dimm_model[] = "Fixed DDR on board";
+
+ conf->dimm_in_use[0] = 1; /* Modify accordingly */
+ memcpy(pdimm, &ddr_raw_timing, sizeof(struct dimm_params));
+ memcpy(pdimm->mpart, dimm_model, sizeof(dimm_model) - 1);
+
+ /* valid DIMM mask, change accordingly, together with dimm_on_ctlr. */
+ return 0x5;
+}
+#endif /* CONFIG_DDR_NODIMM */
+
+int ddr_board_options(struct ddr_info *priv)
+{
+ struct memctl_opt *popts = &priv->opt;
+ const struct ddr_conf *conf = &priv->conf;
+
+ popts->vref_dimm = U(0x19); /* range 1, 83.4% */
+ popts->rtt_override = 1U;
+ popts->rtt_override_value = 0x5U; /* RTT being used as 60 ohm */
+ popts->rtt_park = 120U;
+ popts->otf_burst_chop_en = 0;
+ popts->burst_length = DDR_BL8;
+ popts->trwt_override = 1U;
+ popts->bstopre = 0U; /* auto precharge */
+ popts->addr_hash = 1;
+
+ /* Set ODT impedance on PHY side */
+ switch (conf->cs_on_dimm[1]) {
+ case 0xc: /* Two slots dual rank */
+ case 0x4: /* Two slots single rank, not valid for interleaving */
+ popts->trwt = U(0xf);
+ popts->twrt = U(0x7);
+ popts->trrt = U(0x7);
+ popts->twwt = U(0x7);
+ popts->vref_phy = U(0x6B); /* 83.6% */
+ popts->odt = 60U;
+ popts->phy_tx_impedance = 28U;
+ break;
+ case 0: /* Ont slot used */
+ default:
+ popts->trwt = U(0x3);
+ popts->twrt = U(0x3);
+ popts->trrt = U(0x3);
+ popts->twwt = U(0x3);
+ popts->vref_phy = U(0x5D); /* 72% */
+ popts->odt = 60U;
+ popts->phy_tx_impedance = 28U;
+ break;
+ }
+
+ return 0;
+}
+
+#ifdef NXP_WARM_BOOT
+long long init_ddr(uint32_t wrm_bt_flg)
+#else
+long long init_ddr(void)
+#endif
+{
+ int spd_addr[] = { 0x51, 0x52, 0x53, 0x54 };
+ struct ddr_info info;
+ struct sysinfo sys;
+ long long dram_size;
+
+ zeromem(&sys, sizeof(sys));
+ if (get_clocks(&sys) != 0) {
+ ERROR("System clocks are not set\n");
+ panic();
+ }
+ debug("platform clock %lu\n", sys.freq_platform);
+ debug("DDR PLL1 %lu\n", sys.freq_ddr_pll0);
+ debug("DDR PLL2 %lu\n", sys.freq_ddr_pll1);
+
+ zeromem(&info, sizeof(info));
+
+ /* Set two DDRC. Unused DDRC will be removed automatically. */
+ info.num_ctlrs = NUM_OF_DDRC;
+ info.spd_addr = spd_addr;
+ info.ddr[0] = (void *)NXP_DDR_ADDR;
+ info.ddr[1] = (void *)NXP_DDR2_ADDR;
+ info.phy[0] = (void *)NXP_DDR_PHY1_ADDR;
+ info.phy[1] = (void *)NXP_DDR_PHY2_ADDR;
+ info.clk = get_ddr_freq(&sys, 0);
+ info.img_loadr = load_img;
+ info.phy_gen2_fw_img_buf = PHY_GEN2_FW_IMAGE_BUFFER;
+ if (info.clk == 0) {
+ info.clk = get_ddr_freq(&sys, 1);
+ }
+ info.dimm_on_ctlr = DDRC_NUM_DIMM;
+
+ info.warm_boot_flag = DDR_WRM_BOOT_NT_SUPPORTED;
+#ifdef NXP_WARM_BOOT
+ if (wrm_bt_flg != 0) {
+ info.warm_boot_flag = DDR_WARM_BOOT;
+ } else {
+ info.warm_boot_flag = DDR_COLD_BOOT;
+ }
+#endif
+
+ dram_size = dram_init(&info
+#if defined(NXP_HAS_CCN504) || defined(NXP_HAS_CCN508)
+ , NXP_CCN_HN_F_0_ADDR
+#endif
+ );
+
+
+ if (dram_size < 0) {
+ ERROR("DDR init failed.\n");
+ }
+
+ return dram_size;
+}
diff --git a/plat/nxp/soc-lx2160a/lx2162aqds/plat_def.h b/plat/nxp/soc-lx2160a/lx2162aqds/plat_def.h
new file mode 100644
index 0000000..de2d244
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/lx2162aqds/plat_def.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PLAT_DEF_H
+#define PLAT_DEF_H
+
+#include <arch.h>
+#include <cortex_a72.h>
+/* Required without TBBR.
+ * To include the defines for DDR PHY
+ * Images.
+ */
+#include <tbbr_img_def.h>
+
+#include <policy.h>
+#include <soc.h>
+
+#if defined(IMAGE_BL31)
+#define LS_SYS_TIMCTL_BASE 0x2890000
+#define PLAT_LS_NSTIMER_FRAME_ID 0
+#define LS_CONFIG_CNTACR 1
+#endif
+
+#define NXP_SYSCLK_FREQ 100000000
+#define NXP_DDRCLK_FREQ 100000000
+
+/* UART related definition */
+#define NXP_CONSOLE_ADDR NXP_UART_ADDR
+#define NXP_CONSOLE_BAUDRATE 115200
+
+/* Size of cacheable stacks */
+#if defined(IMAGE_BL2)
+#if defined(TRUSTED_BOARD_BOOT)
+#define PLATFORM_STACK_SIZE 0x2000
+#else
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+#elif defined(IMAGE_BL31)
+#define PLATFORM_STACK_SIZE 0x1000
+#endif
+
+/* SD block buffer */
+#define NXP_SD_BLOCK_BUF_SIZE (0x8000)
+#define NXP_SD_BLOCK_BUF_ADDR (NXP_OCRAM_ADDR + NXP_OCRAM_SIZE \
+ - NXP_SD_BLOCK_BUF_SIZE)
+
+#ifdef SD_BOOT
+#define BL2_LIMIT (NXP_OCRAM_ADDR + NXP_OCRAM_SIZE \
+ - NXP_SD_BLOCK_BUF_SIZE)
+#else
+#define BL2_LIMIT (NXP_OCRAM_ADDR + NXP_OCRAM_SIZE)
+#endif
+
+/* IO defines as needed by IO driver framework */
+#define MAX_IO_DEVICES 4
+#define MAX_IO_BLOCK_DEVICES 1
+#define MAX_IO_HANDLES 4
+
+#define PHY_GEN2_FW_IMAGE_BUFFER (NXP_OCRAM_ADDR + CSF_HDR_SZ)
+
+/*
+ * FIP image defines - Offset at which FIP Image would be present
+ * Image would include Bl31 , Bl33 and Bl32 (optional)
+ */
+#ifdef POLICY_FUSE_PROVISION
+#define MAX_FIP_DEVICES 3
+#endif
+
+#ifndef MAX_FIP_DEVICES
+#define MAX_FIP_DEVICES 2
+#endif
+
+/*
+ * ID of the secure physical generic timer interrupt used by the BL32.
+ */
+#define BL32_IRQ_SEC_PHY_TIMER 29
+
+#define BL31_WDOG_SEC 89
+
+#define BL31_NS_WDOG_WS1 108
+
+/*
+ * 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_LS_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(BL32_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE)
+
+/* SGI 15 and Secure watchdog interrupts assigned to Group 0 */
+#define NXP_IRQ_SEC_SGI_7 15
+
+#define PLAT_LS_G0_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(BL31_WDOG_SEC, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(BL31_NS_WDOG_WS1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(NXP_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL)
+#endif
diff --git a/plat/nxp/soc-lx2160a/lx2162aqds/platform.c b/plat/nxp/soc-lx2160a/lx2162aqds/platform.c
new file mode 100644
index 0000000..7622cf0
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/lx2162aqds/platform.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <plat_common.h>
+
+#pragma weak board_enable_povdd
+#pragma weak board_disable_povdd
+
+bool board_enable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool board_disable_povdd(void)
+{
+#ifdef CONFIG_POVDD_ENABLE
+ return true;
+#else
+ return false;
+#endif
+}
diff --git a/plat/nxp/soc-lx2160a/lx2162aqds/platform.mk b/plat/nxp/soc-lx2160a/lx2162aqds/platform.mk
new file mode 100644
index 0000000..2b4712c
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/lx2162aqds/platform.mk
@@ -0,0 +1,52 @@
+#
+# Copyright 2018-2020 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# board-specific build parameters
+
+BOOT_MODE ?= flexspi_nor
+BOARD ?= lx2162aqds
+POVDD_ENABLE := no
+NXP_COINED_BB := no
+
+ # DDR Compilation Configs
+NUM_OF_DDRC := 1
+DDRC_NUM_DIMM := 1
+DDRC_NUM_CS := 2
+DDR_ECC_EN := yes
+ #enable address decoding feature
+DDR_ADDR_DEC := yes
+APPLY_MAX_CDD := yes
+
+# DDR Errata
+ERRATA_DDR_A011396 := 1
+ERRATA_DDR_A050450 := 1
+
+
+# On-Board Flash Details
+FLASH_TYPE := MT35XU512A
+XSPI_FLASH_SZ := 0x10000000
+NXP_XSPI_NOR_UNIT_SIZE := 0x20000
+BL2_BIN_XSPI_NOR_END_ADDRESS := 0x100000
+# CONFIG_FSPI_ERASE_4K is required to erase 4K sector sizes. This
+# config is enabled for future use cases.
+FSPI_ERASE_4K := 0
+
+# Platform specific features.
+WARM_BOOT := yes
+
+# Adding Platform files build files
+BL2_SOURCES += ${BOARD_PATH}/ddr_init.c\
+ ${BOARD_PATH}/platform.c
+
+SUPPORTED_BOOT_MODE := flexspi_nor \
+ sd \
+ emmc
+
+# Adding platform board build info
+include plat/nxp/common/plat_make_helper/plat_common_def.mk
+
+# Adding SoC build info
+include plat/nxp/soc-lx2160a/soc.mk
diff --git a/plat/nxp/soc-lx2160a/lx2162aqds/platform_def.h b/plat/nxp/soc-lx2160a/lx2162aqds/platform_def.h
new file mode 100644
index 0000000..5fa774e
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/lx2162aqds/platform_def.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include "plat_def.h"
+#include "plat_default_def.h"
+
+#endif
diff --git a/plat/nxp/soc-lx2160a/lx2162aqds/policy.h b/plat/nxp/soc-lx2160a/lx2162aqds/policy.h
new file mode 100644
index 0000000..1095f38
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/lx2162aqds/policy.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef POLICY_H
+#define POLICY_H
+
+/* Following defines affect the PLATFORM SECURITY POLICY */
+
+/* set this to 0x0 if the platform is not using/responding to ECC errors
+ * set this to 0x1 if ECC is being used (we have to do some init)
+ */
+#define POLICY_USING_ECC 0x0
+
+/* Set this to 0x0 to leave the default SMMU page size in sACR
+ * Set this to 0x1 to change the SMMU page size to 64K
+ */
+#define POLICY_SMMU_PAGESZ_64K 0x1
+
+/*
+ * POLICY_PERF_WRIOP = 0 : No Performance enhancement for WRIOP RN-I
+ * POLICY_PERF_WRIOP = 1 : No Performance enhancement for WRIOP RN-I = 7
+ * POLICY_PERF_WRIOP = 2 : No Performance enhancement for WRIOP RN-I = 23
+ */
+#define POLICY_PERF_WRIOP 0
+
+/*
+ * set this to '1' if the debug clocks need to remain enabled during
+ * system entry to low-power (LPM20) - this should only be necessary
+ * for testing and NEVER set for normal production
+ */
+#define POLICY_DEBUG_ENABLE 0
+
+
+#endif /* POLICY_H */
diff --git a/plat/nxp/soc-lx2160a/soc.c b/plat/nxp/soc-lx2160a/soc.c
new file mode 100644
index 0000000..2209fda
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/soc.c
@@ -0,0 +1,509 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <bl31/interrupt_mgmt.h>
+#include <caam.h>
+#include <cassert.h>
+#include <ccn.h>
+#include <common/debug.h>
+#include <dcfg.h>
+#ifdef I2C_INIT
+#include <i2c.h>
+#endif
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <ls_interconnect.h>
+#ifdef POLICY_FUSE_PROVISION
+#include <nxp_gpio.h>
+#endif
+#if TRUSTED_BOARD_BOOT
+#include <nxp_smmu.h>
+#endif
+#include <nxp_timer.h>
+#include <plat_console.h>
+#include <plat_gic.h>
+#include <plat_tzc400.h>
+#include <pmu.h>
+#if defined(NXP_SFP_ENABLED)
+#include <sfp.h>
+#endif
+
+#include <errata.h>
+#include <ls_interrupt_mgmt.h>
+#include "plat_common.h"
+#ifdef NXP_NV_SW_MAINT_LAST_EXEC_DATA
+#include <plat_nv_storage.h>
+#endif
+#ifdef NXP_WARM_BOOT
+#include <plat_warm_rst.h>
+#endif
+#include "platform_def.h"
+#include "soc.h"
+
+static struct soc_type soc_list[] = {
+ SOC_ENTRY(LX2160A, LX2160A, 8, 2),
+ SOC_ENTRY(LX2080A, LX2080A, 8, 1),
+ SOC_ENTRY(LX2120A, LX2120A, 6, 2),
+};
+
+static dcfg_init_info_t dcfg_init_data = {
+ .g_nxp_dcfg_addr = NXP_DCFG_ADDR,
+ .nxp_sysclk_freq = NXP_SYSCLK_FREQ,
+ .nxp_ddrclk_freq = NXP_DDRCLK_FREQ,
+ .nxp_plat_clk_divider = NXP_PLATFORM_CLK_DIVIDER,
+ };
+static const unsigned char master_to_6rn_id_map[] = {
+ PLAT_6CLUSTER_TO_CCN_ID_MAP
+};
+
+static const unsigned char master_to_rn_id_map[] = {
+ PLAT_CLUSTER_TO_CCN_ID_MAP
+};
+
+CASSERT(ARRAY_SIZE(master_to_rn_id_map) == NUMBER_OF_CLUSTERS,
+ assert_invalid_cluster_count_for_ccn_variant);
+
+static const ccn_desc_t plat_six_cluster_ccn_desc = {
+ .periphbase = NXP_CCN_ADDR,
+ .num_masters = ARRAY_SIZE(master_to_6rn_id_map),
+ .master_to_rn_id_map = master_to_6rn_id_map
+};
+
+static const ccn_desc_t plat_ccn_desc = {
+ .periphbase = NXP_CCN_ADDR,
+ .num_masters = ARRAY_SIZE(master_to_rn_id_map),
+ .master_to_rn_id_map = master_to_rn_id_map
+};
+
+/******************************************************************************
+ * Function returns the base counter frequency
+ * after reading the first entry at CNTFID0 (0x20 offset).
+ *
+ * Function is used by:
+ * 1. ARM common code for PSCI management.
+ * 2. ARM Generic Timer init.
+ *
+ *****************************************************************************/
+unsigned int plat_get_syscnt_freq2(void)
+{
+ unsigned int counter_base_frequency;
+ /*
+ * Below register specifies the base frequency of the system counter.
+ * As per NXP Board Manuals:
+ * The system counter always works with SYS_REF_CLK/4 frequency clock.
+ *
+ *
+ */
+ counter_base_frequency = mmio_read_32(NXP_TIMER_ADDR + CNTFID_OFF);
+
+ return counter_base_frequency;
+}
+
+#ifdef IMAGE_BL2
+
+#ifdef POLICY_FUSE_PROVISION
+static gpio_init_info_t gpio_init_data = {
+ .gpio1_base_addr = NXP_GPIO1_ADDR,
+ .gpio2_base_addr = NXP_GPIO2_ADDR,
+ .gpio3_base_addr = NXP_GPIO3_ADDR,
+ .gpio4_base_addr = NXP_GPIO4_ADDR,
+};
+#endif
+
+static void soc_interconnect_config(void)
+{
+ unsigned long long val = 0x0U;
+ uint8_t num_clusters, cores_per_cluster;
+
+ get_cluster_info(soc_list, ARRAY_SIZE(soc_list),
+ &num_clusters, &cores_per_cluster);
+
+ if (num_clusters == 6U) {
+ ccn_init(&plat_six_cluster_ccn_desc);
+ } else {
+ ccn_init(&plat_ccn_desc);
+ }
+
+ /*
+ * Enable Interconnect coherency for the primary CPU's cluster.
+ */
+ plat_ls_interconnect_enter_coherency(num_clusters);
+
+ val = ccn_read_node_reg(NODE_TYPE_HNI, 13, PCIeRC_RN_I_NODE_ID_OFFSET);
+ val |= (1 << 17);
+ ccn_write_node_reg(NODE_TYPE_HNI, 13, PCIeRC_RN_I_NODE_ID_OFFSET, val);
+
+ /* PCIe is Connected to RN-I 17 which is connected to HN-I 13. */
+ val = ccn_read_node_reg(NODE_TYPE_HNI, 30, PCIeRC_RN_I_NODE_ID_OFFSET);
+ val |= (1 << 17);
+ ccn_write_node_reg(NODE_TYPE_HNI, 30, PCIeRC_RN_I_NODE_ID_OFFSET, val);
+
+ val = ccn_read_node_reg(NODE_TYPE_HNI, 13, SA_AUX_CTRL_REG_OFFSET);
+ val |= SERIALIZE_DEV_nGnRnE_WRITES;
+ ccn_write_node_reg(NODE_TYPE_HNI, 13, SA_AUX_CTRL_REG_OFFSET, val);
+
+ val = ccn_read_node_reg(NODE_TYPE_HNI, 30, SA_AUX_CTRL_REG_OFFSET);
+ val &= ~(ENABLE_RESERVE_BIT53);
+ val |= SERIALIZE_DEV_nGnRnE_WRITES;
+ ccn_write_node_reg(NODE_TYPE_HNI, 30, SA_AUX_CTRL_REG_OFFSET, val);
+
+ val = ccn_read_node_reg(NODE_TYPE_HNI, 13, PoS_CONTROL_REG_OFFSET);
+ val &= ~(HNI_POS_EN);
+ ccn_write_node_reg(NODE_TYPE_HNI, 13, PoS_CONTROL_REG_OFFSET, val);
+
+ val = ccn_read_node_reg(NODE_TYPE_HNI, 30, PoS_CONTROL_REG_OFFSET);
+ val &= ~(HNI_POS_EN);
+ ccn_write_node_reg(NODE_TYPE_HNI, 30, PoS_CONTROL_REG_OFFSET, val);
+
+ val = ccn_read_node_reg(NODE_TYPE_HNI, 13, SA_AUX_CTRL_REG_OFFSET);
+ val &= ~(POS_EARLY_WR_COMP_EN);
+ ccn_write_node_reg(NODE_TYPE_HNI, 13, SA_AUX_CTRL_REG_OFFSET, val);
+
+ val = ccn_read_node_reg(NODE_TYPE_HNI, 30, SA_AUX_CTRL_REG_OFFSET);
+ val &= ~(POS_EARLY_WR_COMP_EN);
+ ccn_write_node_reg(NODE_TYPE_HNI, 30, SA_AUX_CTRL_REG_OFFSET, val);
+
+#if POLICY_PERF_WRIOP
+ uint16_t wriop_rni = 0U;
+
+ if (POLICY_PERF_WRIOP == 1) {
+ wriop_rni = 7U;
+ } else if (POLICY_PERF_WRIOP == 2) {
+ wriop_rni = 23U;
+ } else {
+ ERROR("Incorrect WRIOP selected.\n");
+ panic();
+ }
+
+ val = ccn_read_node_reg(NODE_TYPE_RNI, wriop_rni,
+ SA_AUX_CTRL_REG_OFFSET);
+ val |= ENABLE_WUO;
+ ccn_write_node_reg(NODE_TYPE_HNI, wriop_rni, SA_AUX_CTRL_REG_OFFSET,
+ val);
+#else
+ val = ccn_read_node_reg(NODE_TYPE_RNI, 17, SA_AUX_CTRL_REG_OFFSET);
+ val |= ENABLE_WUO;
+ ccn_write_node_reg(NODE_TYPE_RNI, 17, SA_AUX_CTRL_REG_OFFSET, val);
+#endif
+}
+
+
+void soc_preload_setup(void)
+{
+ dram_regions_info_t *info_dram_regions = get_dram_regions_info();
+#if defined(NXP_WARM_BOOT)
+ bool warm_reset = is_warm_boot();
+#endif
+ info_dram_regions->total_dram_size =
+#if defined(NXP_WARM_BOOT)
+ init_ddr(warm_reset);
+#else
+ init_ddr();
+#endif
+}
+
+/*******************************************************************************
+ * This function implements soc specific erratas
+ * This is called before DDR is initialized or MMU is enabled
+ ******************************************************************************/
+void soc_early_init(void)
+{
+ dcfg_init(&dcfg_init_data);
+#ifdef POLICY_FUSE_PROVISION
+ gpio_init(&gpio_init_data);
+ sec_init(NXP_CAAM_ADDR);
+#endif
+#if LOG_LEVEL > 0
+ /* Initialize the console to provide early debug support */
+ plat_console_init(NXP_CONSOLE_ADDR,
+ NXP_UART_CLK_DIVIDER, NXP_CONSOLE_BAUDRATE);
+#endif
+
+ enable_timer_base_to_cluster(NXP_PMU_ADDR);
+ soc_interconnect_config();
+
+ enum boot_device dev = get_boot_dev();
+ /* Mark the buffer for SD in OCRAM as non secure.
+ * The buffer is assumed to be at end of OCRAM for
+ * the logic below to calculate TZPC programming
+ */
+ if (dev == BOOT_DEVICE_EMMC || dev == BOOT_DEVICE_SDHC2_EMMC) {
+ /* Calculate the region in OCRAM which is secure
+ * The buffer for SD needs to be marked non-secure
+ * to allow SD to do DMA operations on it
+ */
+ uint32_t secure_region = (NXP_OCRAM_SIZE
+ - NXP_SD_BLOCK_BUF_SIZE);
+ uint32_t mask = secure_region/TZPC_BLOCK_SIZE;
+
+ mmio_write_32(NXP_OCRAM_TZPC_ADDR, mask);
+
+ /* Add the entry for buffer in MMU Table */
+ mmap_add_region(NXP_SD_BLOCK_BUF_ADDR, NXP_SD_BLOCK_BUF_ADDR,
+ NXP_SD_BLOCK_BUF_SIZE,
+ MT_DEVICE | MT_RW | MT_NS);
+ }
+
+ soc_errata();
+
+#if (TRUSTED_BOARD_BOOT) || defined(POLICY_FUSE_PROVISION)
+ sfp_init(NXP_SFP_ADDR);
+#endif
+
+#if TRUSTED_BOARD_BOOT
+ uint32_t mode;
+
+ /* For secure boot disable SMMU.
+ * Later when platform security policy comes in picture,
+ * this might get modified based on the policy
+ */
+ if (check_boot_mode_secure(&mode) == true) {
+ bypass_smmu(NXP_SMMU_ADDR);
+ }
+
+ /* For Mbedtls currently crypto is not supported via CAAM
+ * enable it when that support is there. In tbbr.mk
+ * the CAAM_INTEG is set as 0.
+ */
+
+#ifndef MBEDTLS_X509
+ /* Initialize the crypto accelerator if enabled */
+ if (is_sec_enabled() == false)
+ INFO("SEC is disabled.\n");
+ else
+ sec_init(NXP_CAAM_ADDR);
+#endif
+#endif
+
+ /*
+ * Initialize system level generic timer for Layerscape Socs.
+ */
+ delay_timer_init(NXP_TIMER_ADDR);
+ i2c_init(NXP_I2C_ADDR);
+}
+
+void soc_bl2_prepare_exit(void)
+{
+#if defined(NXP_SFP_ENABLED) && defined(DISABLE_FUSE_WRITE)
+ set_sfp_wr_disable();
+#endif
+}
+
+/*****************************************************************************
+ * This function returns the boot device based on RCW_SRC
+ ****************************************************************************/
+enum boot_device get_boot_dev(void)
+{
+ enum boot_device src = BOOT_DEVICE_NONE;
+ uint32_t porsr1;
+ uint32_t rcw_src;
+
+ porsr1 = read_reg_porsr1();
+
+ rcw_src = (porsr1 & PORSR1_RCW_MASK) >> PORSR1_RCW_SHIFT;
+
+ switch (rcw_src) {
+ case FLEXSPI_NOR:
+ src = BOOT_DEVICE_FLEXSPI_NOR;
+ INFO("RCW BOOT SRC is FLEXSPI NOR\n");
+ break;
+ case FLEXSPI_NAND2K_VAL:
+ case FLEXSPI_NAND4K_VAL:
+ INFO("RCW BOOT SRC is FLEXSPI NAND\n");
+ src = BOOT_DEVICE_FLEXSPI_NAND;
+ break;
+ case SDHC1_VAL:
+ src = BOOT_DEVICE_EMMC;
+ INFO("RCW BOOT SRC is SD\n");
+ break;
+ case SDHC2_VAL:
+ src = BOOT_DEVICE_SDHC2_EMMC;
+ INFO("RCW BOOT SRC is EMMC\n");
+ break;
+ default:
+ break;
+ }
+
+ return src;
+}
+
+
+void soc_mem_access(void)
+{
+ const devdisr5_info_t *devdisr5_info = get_devdisr5_info();
+ dram_regions_info_t *info_dram_regions = get_dram_regions_info();
+ struct tzc400_reg tzc400_reg_list[MAX_NUM_TZC_REGION];
+ int dram_idx, index = 0U;
+
+ for (dram_idx = 0U; dram_idx < info_dram_regions->num_dram_regions;
+ dram_idx++) {
+ if (info_dram_regions->region[dram_idx].size == 0) {
+ ERROR("DDR init failure, or");
+ ERROR("DRAM regions not populated correctly.\n");
+ break;
+ }
+
+ index = populate_tzc400_reg_list(tzc400_reg_list,
+ dram_idx, index,
+ info_dram_regions->region[dram_idx].addr,
+ info_dram_regions->region[dram_idx].size,
+ NXP_SECURE_DRAM_SIZE, NXP_SP_SHRD_DRAM_SIZE);
+ }
+
+ if (devdisr5_info->ddrc1_present != 0) {
+ INFO("DDR Controller 1.\n");
+ mem_access_setup(NXP_TZC_ADDR, index,
+ tzc400_reg_list);
+ mem_access_setup(NXP_TZC3_ADDR, index,
+ tzc400_reg_list);
+ }
+ if (devdisr5_info->ddrc2_present != 0) {
+ INFO("DDR Controller 2.\n");
+ mem_access_setup(NXP_TZC2_ADDR, index,
+ tzc400_reg_list);
+ mem_access_setup(NXP_TZC4_ADDR, index,
+ tzc400_reg_list);
+ }
+}
+
+#else
+const unsigned char _power_domain_tree_desc[] = {1, 8, 2, 2, 2, 2, 2, 2, 2, 2};
+
+CASSERT(NUMBER_OF_CLUSTERS && NUMBER_OF_CLUSTERS <= 256,
+ assert_invalid_lx2160a_cluster_count);
+
+/******************************************************************************
+ * This function returns the SoC topology
+ ****************************************************************************/
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+
+ return _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 CORES_PER_CLUSTER;
+}
+
+
+void soc_early_platform_setup2(void)
+{
+ dcfg_init(&dcfg_init_data);
+ /*
+ * Initialize system level generic timer for Socs
+ */
+ delay_timer_init(NXP_TIMER_ADDR);
+
+#if LOG_LEVEL > 0
+ /* Initialize the console to provide early debug support */
+ plat_console_init(NXP_CONSOLE_ADDR,
+ NXP_UART_CLK_DIVIDER, NXP_CONSOLE_BAUDRATE);
+#endif
+}
+
+void soc_platform_setup(void)
+{
+ /* Initialize the GIC driver, cpu and distributor interfaces */
+ static uintptr_t target_mask_array[PLATFORM_CORE_COUNT];
+ static interrupt_prop_t ls_interrupt_props[] = {
+ PLAT_LS_G1S_IRQ_PROPS(INTR_GROUP1S),
+ PLAT_LS_G0_IRQ_PROPS(INTR_GROUP0)
+ };
+
+ plat_ls_gic_driver_init(NXP_GICD_ADDR, NXP_GICR_ADDR,
+ PLATFORM_CORE_COUNT,
+ ls_interrupt_props,
+ ARRAY_SIZE(ls_interrupt_props),
+ target_mask_array,
+ plat_core_pos);
+
+ plat_ls_gic_init();
+ enable_init_timer();
+#ifdef LS_SYS_TIMCTL_BASE
+ ls_configure_sys_timer(LS_SYS_TIMCTL_BASE,
+ LS_CONFIG_CNTACR,
+ PLAT_LS_NSTIMER_FRAME_ID);
+#endif
+}
+
+/*******************************************************************************
+ * This function initializes the soc from the BL31 module
+ ******************************************************************************/
+void soc_init(void)
+{
+ uint8_t num_clusters, cores_per_cluster;
+
+ get_cluster_info(soc_list, ARRAY_SIZE(soc_list),
+ &num_clusters, &cores_per_cluster);
+
+ /* low-level init of the soc */
+ soc_init_start();
+ soc_init_percpu();
+ _init_global_data();
+ _initialize_psci();
+
+ if (ccn_get_part0_id(NXP_CCN_ADDR) != CCN_508_PART0_ID) {
+ ERROR("Unrecognized CCN variant detected.");
+ ERROR("Only CCN-508 is supported\n");
+ panic();
+ }
+
+ if (num_clusters == 6U) {
+ ccn_init(&plat_six_cluster_ccn_desc);
+ } else {
+ ccn_init(&plat_ccn_desc);
+ }
+
+ plat_ls_interconnect_enter_coherency(num_clusters);
+
+ /* Set platform security policies */
+ _set_platform_security();
+
+ /* make sure any parallel init tasks are finished */
+ soc_init_finish();
+
+ /* Initialize the crypto accelerator if enabled */
+ if (is_sec_enabled() == false) {
+ INFO("SEC is disabled.\n");
+ } else {
+ sec_init(NXP_CAAM_ADDR);
+ }
+
+}
+
+#ifdef NXP_WDOG_RESTART
+static uint64_t wdog_interrupt_handler(uint32_t id, uint32_t flags,
+ void *handle, void *cookie)
+{
+ uint8_t data = WDOG_RESET_FLAG;
+
+ wr_nv_app_data(WDT_RESET_FLAG_OFFSET,
+ (uint8_t *)&data, sizeof(data));
+
+ mmio_write_32(NXP_RST_ADDR + RSTCNTL_OFFSET, SW_RST_REQ_INIT);
+
+ return 0;
+}
+#endif
+
+void soc_runtime_setup(void)
+{
+
+#ifdef NXP_WDOG_RESTART
+ request_intr_type_el3(BL31_NS_WDOG_WS1, wdog_interrupt_handler);
+#endif
+}
+#endif
diff --git a/plat/nxp/soc-lx2160a/soc.def b/plat/nxp/soc-lx2160a/soc.def
new file mode 100644
index 0000000..81d6744
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/soc.def
@@ -0,0 +1,116 @@
+#
+# Copyright (c) 2015, 2016 Freescale Semiconductor, Inc.
+# Copyright 2017-2022 NXP Semiconductors
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+#------------------------------------------------------------------------------
+#
+# This file contains the basic architecture definitions that drive the build
+#
+# -----------------------------------------------------------------------------
+
+CORE_TYPE := a72
+
+CACHE_LINE := 6
+
+# set to GIC400 or GIC500
+GIC := GIC500
+
+# set to CCI400 or CCN504 or CCN508
+INTERCONNECT := CCN508
+
+# indicate layerscape chassis level - set to 3=LSCH3 or 2=LSCH2
+CHASSIS := 3_2
+
+# TZC IP Details TZC used is TZC380 or TZC400
+TZC_ID := TZC400
+
+# CONSOLE Details available is NS16550 or PL011
+CONSOLE := PL011
+
+# Select the DDR PHY generation to be used
+PLAT_DDR_PHY := PHY_GEN2
+
+PHYS_SYS := 64
+
+# Area of OCRAM reserved by ROM code
+NXP_ROM_RSVD := 0xa000
+
+# Max Size of CSF header. Required to define BL2 TEXT LIMIT in soc.def
+# Input to CST create_hdr_esbc tool
+CSF_HDR_SZ := 0x3000
+
+NXP_SFP_VER := 3_4
+
+# In IMAGE_BL2, compile time flag for handling Cache coherency
+# with CAAM for BL2 running from OCRAM
+SEC_MEM_NON_COHERENT := yes
+
+# Defining the endianness for NXP ESDHC
+NXP_ESDHC_ENDIANNESS := LE
+
+# Defining the endianness for NXP SFP
+NXP_SFP_ENDIANNESS := LE
+
+# Defining the endianness for NXP GPIO
+NXP_GPIO_ENDIANNESS := LE
+
+# Defining the endianness for NXP SNVS
+NXP_SNVS_ENDIANNESS := LE
+
+# Defining the endianness for NXP CCSR GUR register
+NXP_GUR_ENDIANNESS := LE
+
+# Defining the endianness for NXP FSPI register
+NXP_FSPI_ENDIANNESS := LE
+
+# Defining the endianness for NXP SEC
+NXP_SEC_ENDIANNESS := LE
+
+# Defining the endianness for NXP DDR
+NXP_DDR_ENDIANNESS := LE
+
+NXP_DDR_INTLV_256B := 1
+
+# OCRAM MAP for BL2
+# Before BL2
+# 0x18000000 - 0x18009fff -> Used by ROM code
+# 0x1800a000 - 0x1800dfff -> CSF header for BL2
+# (The above area i.e 0x18000000 - 0x1800dfff is available
+# for DDR PHY images scratch pad region during BL2 run time)
+# For FlexSPI boot
+# 0x1800e000 - 0x18040000 -> Reserved for BL2 binary
+# For SD boot
+# 0x1800e000 - 0x18030000 -> Reserved for BL2 binary
+# 0x18030000 - 0x18040000 -> Reserved for SD buffer
+OCRAM_START_ADDR := 0x18000000
+OCRAM_SIZE := 0x40000
+
+# Location of BL2 on OCRAM
+BL2_BASE_ADDR := $(shell echo $$(( $(OCRAM_START_ADDR) + $(NXP_ROM_RSVD) + $(CSF_HDR_SZ) )))
+# Covert to HEX to be used by create_pbl.mk
+BL2_BASE := $(shell echo "0x"$$(echo "obase=16; ${BL2_BASE_ADDR}" | bc))
+
+# BL2_HDR_LOC is at (OCRAM_ADDR + NXP_ROM_RSVD)
+# This value BL2_HDR_LOC + CSF_HDR_SZ should not overalp with BL2_BASE
+BL2_HDR_LOC_HDR ?= $(shell echo $$(( $(OCRAM_START_ADDR) + $(NXP_ROM_RSVD) )))
+# Covert to HEX to be used by create_pbl.mk
+BL2_HDR_LOC := $$(echo "obase=16; ${BL2_HDR_LOC_HDR}" | bc)
+
+# SoC ERRATAS to be enabled
+#
+# Core Errata
+ERRATA_A72_859971 := 1
+
+# SoC Errata
+ERRATA_SOC_A050426 := 1
+
+# DDR Errata
+ERRATA_DDR_A011396 := 1
+ERRATA_DDR_A050450 := 1
+ERRATA_DDR_A050958 := 1
+
+# enable dynamic memory mapping
+PLAT_XLAT_TABLES_DYNAMIC := 1
diff --git a/plat/nxp/soc-lx2160a/soc.mk b/plat/nxp/soc-lx2160a/soc.mk
new file mode 100644
index 0000000..75a3af2
--- /dev/null
+++ b/plat/nxp/soc-lx2160a/soc.mk
@@ -0,0 +1,174 @@
+#
+# Copyright 2018-2020 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+
+ # SoC-specific build parameters
+SOC := lx2160a
+PLAT_PATH := plat/nxp
+PLAT_COMMON_PATH:= plat/nxp/common
+PLAT_DRIVERS_PATH:= drivers/nxp
+PLAT_SOC_PATH := ${PLAT_PATH}/soc-${SOC}
+BOARD_PATH := ${PLAT_SOC_PATH}/${BOARD}
+
+ # get SoC-specific defnitions
+include ${PLAT_SOC_PATH}/soc.def
+include ${PLAT_COMMON_PATH}/plat_make_helper/soc_common_def.mk
+include ${PLAT_COMMON_PATH}/plat_make_helper/plat_build_macros.mk
+
+ # SoC-specific
+NXP_WDOG_RESTART := yes
+
+
+ # Selecting dependent module,
+ # Selecting dependent drivers, and
+ # Adding defines.
+
+ # for features enabled above.
+ifeq (${NXP_WDOG_RESTART}, yes)
+NXP_NV_SW_MAINT_LAST_EXEC_DATA := yes
+LS_EL3_INTERRUPT_HANDLER := yes
+$(eval $(call add_define, NXP_WDOG_RESTART))
+endif
+
+
+ # For Security Features
+DISABLE_FUSE_WRITE := 1
+ifeq (${TRUSTED_BOARD_BOOT}, 1)
+ifeq (${GENERATE_COT},1)
+# Save Keys to be used by DDR FIP image
+SAVE_KEYS=1
+endif
+$(eval $(call SET_NXP_MAKE_FLAG,SMMU_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,SFP_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,SNVS_NEEDED,BL2))
+# Used by create_pbl tool to
+# create bl2_<boot_mode>_sec.pbl image
+SECURE_BOOT := yes
+endif
+$(eval $(call SET_NXP_MAKE_FLAG,CRYPTO_NEEDED,BL_COMM))
+
+
+ # Selecting Drivers for SoC
+$(eval $(call SET_NXP_MAKE_FLAG,DCFG_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,TIMER_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,INTERCONNECT_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,GIC_NEEDED,BL31))
+$(eval $(call SET_NXP_MAKE_FLAG,CONSOLE_NEEDED,BL_COMM))
+$(eval $(call SET_NXP_MAKE_FLAG,PMU_NEEDED,BL_COMM))
+
+$(eval $(call SET_NXP_MAKE_FLAG,DDR_DRIVER_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,TZASC_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,I2C_NEEDED,BL2))
+$(eval $(call SET_NXP_MAKE_FLAG,IMG_LOADR_NEEDED,BL2))
+
+
+ # Selecting PSCI & SIP_SVC support
+$(eval $(call SET_NXP_MAKE_FLAG,PSCI_NEEDED,BL31))
+$(eval $(call SET_NXP_MAKE_FLAG,SIPSVC_NEEDED,BL31))
+
+
+ # Selecting Boot Source for the TFA images.
+ifeq (${BOOT_MODE}, flexspi_nor)
+$(eval $(call SET_NXP_MAKE_FLAG,XSPI_NEEDED,BL2))
+$(eval $(call add_define,FLEXSPI_NOR_BOOT))
+else
+ifeq (${BOOT_MODE}, sd)
+$(eval $(call SET_NXP_MAKE_FLAG,SD_MMC_NEEDED,BL2))
+$(eval $(call add_define,SD_BOOT))
+else
+ifeq (${BOOT_MODE}, emmc)
+$(eval $(call SET_NXP_MAKE_FLAG,SD_MMC_NEEDED,BL2))
+$(eval $(call add_define,EMMC_BOOT))
+else
+$(error Un-supported Boot Mode = ${BOOT_MODE})
+endif
+endif
+endif
+
+
+ # Separate DDR-FIP image to be loaded.
+$(eval $(call SET_NXP_MAKE_FLAG,DDR_FIP_IO_NEEDED,BL2))
+
+
+# Source File Addition
+# #####################
+
+PLAT_INCLUDES += -I${PLAT_COMMON_PATH}/include/default\
+ -I${BOARD_PATH}\
+ -I${PLAT_COMMON_PATH}/include/default/ch_${CHASSIS}\
+ -I${PLAT_SOC_PATH}/include\
+ -I${PLAT_COMMON_PATH}/soc_errata
+
+ifeq (${SECURE_BOOT},yes)
+include ${PLAT_COMMON_PATH}/tbbr/tbbr.mk
+endif
+
+ifeq ($(WARM_BOOT),yes)
+include ${PLAT_COMMON_PATH}/warm_reset/warm_reset.mk
+endif
+
+ifeq (${NXP_NV_SW_MAINT_LAST_EXEC_DATA}, yes)
+include ${PLAT_COMMON_PATH}/nv_storage/nv_storage.mk
+endif
+
+ifeq (${PSCI_NEEDED}, yes)
+include ${PLAT_COMMON_PATH}/psci/psci.mk
+endif
+
+ifeq (${SIPSVC_NEEDED}, yes)
+include ${PLAT_COMMON_PATH}/sip_svc/sipsvc.mk
+endif
+
+ifeq (${DDR_FIP_IO_NEEDED}, yes)
+include ${PLAT_COMMON_PATH}/fip_handler/ddr_fip/ddr_fip_io.mk
+endif
+
+ # for fuse-fip & fuse-programming
+ifeq (${FUSE_PROG}, 1)
+include ${PLAT_COMMON_PATH}/fip_handler/fuse_fip/fuse.mk
+endif
+
+ifeq (${IMG_LOADR_NEEDED},yes)
+include $(PLAT_COMMON_PATH)/img_loadr/img_loadr.mk
+endif
+
+ # Adding source files for the above selected drivers.
+include ${PLAT_DRIVERS_PATH}/drivers.mk
+
+ # Adding SoC specific files
+include ${PLAT_COMMON_PATH}/soc_errata/errata.mk
+
+PLAT_INCLUDES += ${NV_STORAGE_INCLUDES}\
+ ${WARM_RST_INCLUDES}
+
+BL31_SOURCES += ${PLAT_SOC_PATH}/$(ARCH)/${SOC}.S\
+ ${WARM_RST_BL31_SOURCES}\
+ ${PSCI_SOURCES}\
+ ${SIPSVC_SOURCES}\
+ ${PLAT_COMMON_PATH}/$(ARCH)/bl31_data.S
+
+PLAT_BL_COMMON_SOURCES += ${PLAT_COMMON_PATH}/$(ARCH)/ls_helpers.S\
+ ${PLAT_SOC_PATH}/aarch64/${SOC}_helpers.S\
+ ${NV_STORAGE_SOURCES}\
+ ${WARM_RST_BL_COMM_SOURCES}\
+ ${PLAT_SOC_PATH}/soc.c
+
+ifeq (${TEST_BL31}, 1)
+BL31_SOURCES += ${PLAT_SOC_PATH}/$(ARCH)/bootmain64.S\
+ ${PLAT_SOC_PATH}/$(ARCH)/nonboot64.S
+endif
+
+BL2_SOURCES += ${DDR_CNTLR_SOURCES}\
+ ${TBBR_SOURCES}\
+ ${FUSE_SOURCES}
+
+
+ # Adding TFA setup files
+include ${PLAT_PATH}/common/setup/common.mk
+
+
+ # Adding source files to generate separate DDR FIP image
+include ${PLAT_SOC_PATH}/ddr_fip.mk
diff --git a/plat/qemu/common/aarch32/plat_helpers.S b/plat/qemu/common/aarch32/plat_helpers.S
new file mode 100644
index 0000000..5e346d5
--- /dev/null
+++ b/plat/qemu/common/aarch32/plat_helpers.S
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+
+ .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, #PLAT_QEMU_HOLD_STATE_WAIT
+ beq 1f
+
+ /* Clear the mailbox again ready for next time. */
+ mov r1, #PLAT_QEMU_HOLD_STATE_WAIT
+ str r1, [r2, r0]
+
+ /* Jump to the provided entrypoint. */
+ 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
+
+ /* ---------------------------------------------
+ * void plat_crash_console_flush(int c)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * Out : void.
+ * 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
+
diff --git a/plat/qemu/common/aarch64/plat_helpers.S b/plat/qemu/common/aarch64/plat_helpers.S
new file mode 100644
index 0000000..08b2817
--- /dev/null
+++ b/plat/qemu/common/aarch64/plat_helpers.S
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+
+ .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 #(MPIDR_AFFINITY_BITS -\
+ PLATFORM_CPU_PER_CLUSTER_SHIFT)
+ 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
+
+ /* Clear the mailbox again ready for next time. */
+ mov x1, #PLAT_QEMU_HOLD_STATE_WAIT
+ str x1, [x2, x0]
+
+ /* Jump to the provided entrypoint. */
+ 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
+
+ /* ---------------------------------------------
+ * void plat_crash_console_flush(int c)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * Out : void.
+ * 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
+
diff --git a/plat/qemu/common/include/plat_macros.S b/plat/qemu/common/include/plat_macros.S
new file mode 100644
index 0000000..b6cdb07
--- /dev/null
+++ b/plat/qemu/common/include/plat_macros.S
@@ -0,0 +1,26 @@
+/*
+ * 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 <arm_macros.S>
+#include <platform_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, GICC_BASE
+ mov_imm x16, GICD_BASE
+ arm_print_gic_regs
+ .endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/qemu/common/qemu_bl1_setup.c b/plat/qemu/common/qemu_bl1_setup.c
new file mode 100644
index 0000000..67f3327
--- /dev/null
+++ b/plat/qemu/common/qemu_bl1_setup.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+
+#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();
+}
diff --git a/plat/qemu/common/qemu_bl2_mem_params_desc.c b/plat/qemu/common/qemu_bl2_mem_params_desc.c
new file mode 100644
index 0000000..5af3a22
--- /dev/null
+++ b/plat/qemu/common/qemu_bl2_mem_params_desc.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * 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) || defined(SPMC_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)
diff --git a/plat/qemu/common/qemu_bl2_setup.c b/plat/qemu/common/qemu_bl2_setup.c
new file mode 100644
index 0000000..2c0da15
--- /dev/null
+++ b/plat/qemu/common/qemu_bl2_setup.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <common/fdt_fixup.h>
+#include <lib/optee_utils.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#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)ARM_PRELOADED_DTB_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) || defined(SPMC_OPTEE)
+ bl_mem_params_node_t *pager_mem_params = NULL;
+ bl_mem_params_node_t *paged_mem_params = NULL;
+#endif
+#if defined(SPD_spmd)
+ unsigned int mode_rw = MODE_RW_64;
+ uint64_t pagable_part = 0;
+#endif
+
+ assert(bl_mem_params);
+
+ switch (image_id) {
+ case BL32_IMAGE_ID:
+#if defined(SPD_opteed) || defined(AARCH32_SP_OPTEE) || defined(SPMC_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_spmd)
+ mode_rw = bl_mem_params->ep_info.args.arg0;
+ pagable_part = bl_mem_params->ep_info.args.arg1;
+#endif
+#endif
+
+#if defined(SPD_spmd)
+ bl_mem_params->ep_info.args.arg0 = ARM_PRELOADED_DTB_BASE;
+ bl_mem_params->ep_info.args.arg1 = pagable_part;
+ bl_mem_params->ep_info.args.arg2 = mode_rw;
+ bl_mem_params->ep_info.args.arg3 = 0;
+#elif 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 = ARM_PRELOADED_DTB_BASE;
+#elif defined(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 = ARM_PRELOADED_DTB_BASE;
+ bl_mem_params->ep_info.args.arg3 = 0;
+#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
+
+#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.
+ */
+ bl_mem_params->ep_info.args.arg0 =
+ (u_register_t)ARM_PRELOADED_DTB_BASE;
+ bl_mem_params->ep_info.args.arg1 = 0U;
+ bl_mem_params->ep_info.args.arg2 = 0U;
+ bl_mem_params->ep_info.args.arg3 = 0U;
+#else
+ /* BL33 expects to receive the primary CPU MPID (through r0) */
+ bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
+#endif
+
+ 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;
+}
diff --git a/plat/qemu/common/qemu_bl31_setup.c b/plat/qemu/common/qemu_bl31_setup.c
new file mode 100644
index 0000000..4f60eb1
--- /dev/null
+++ b/plat/qemu/common/qemu_bl31_setup.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/bl_common.h>
+#include <drivers/arm/pl061_gpio.h>
+#include <plat/common/platform.h>
+
+#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);
+}
+
+static void qemu_gpio_init(void)
+{
+#ifdef SECURE_GPIO_BASE
+ pl061_gpio_init();
+ pl061_gpio_register(SECURE_GPIO_BASE, 0);
+#endif
+}
+
+void bl31_platform_setup(void)
+{
+ plat_qemu_gic_init();
+ qemu_gpio_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;
+}
diff --git a/plat/qemu/common/qemu_common.c b/plat/qemu/common/qemu_common.c
new file mode 100644
index 0000000..0c184f4
--- /dev/null
+++ b/plat/qemu/common/qemu_common.c
@@ -0,0 +1,169 @@
+
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <plat/common/platform.h>
+#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_RW | 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,
+#if SPM_MM
+ QEMU_SP_IMAGE_MMAP,
+#else
+ MAP_BL32_MEM,
+#endif
+ {0}
+};
+#endif
+#ifdef IMAGE_BL31
+static const mmap_region_t plat_qemu_mmap[] = {
+ MAP_SHARED_RAM,
+ MAP_DEVICE0,
+#ifdef MAP_DEVICE1
+ MAP_DEVICE1,
+#endif
+#ifdef MAP_DEVICE2
+ MAP_DEVICE2,
+#endif
+#if SPM_MM
+ MAP_NS_DRAM0,
+ QEMU_SPM_BUF_EL3_MMAP,
+#else
+ MAP_BL32_MEM,
+#endif
+ {0}
+};
+#endif
+#ifdef IMAGE_BL32
+static const mmap_region_t plat_qemu_mmap[] = {
+ MAP_SHARED_RAM,
+ MAP_DEVICE0,
+#ifdef MAP_DEVICE1
+ MAP_DEVICE1,
+#endif
+#ifdef MAP_DEVICE2
+ MAP_DEVICE2,
+#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
+
+#if MEASURED_BOOT || 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
diff --git a/plat/qemu/common/qemu_console.c b/plat/qemu/common/qemu_console.c
new file mode 100644
index 0000000..1f00f8a
--- /dev/null
+++ b/plat/qemu/common/qemu_console.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <drivers/console.h>
+#include <drivers/arm/pl011.h>
+
+static console_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_FLAG_BOOT |
+ CONSOLE_FLAG_RUNTIME);
+}
+
diff --git a/plat/qemu/common/qemu_gicv2.c b/plat/qemu/common/qemu_gicv2.c
new file mode 100644
index 0000000..2c358ea
--- /dev/null
+++ b/plat/qemu/common/qemu_gicv2.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gic_common.h>
+#include <platform_def.h>
+
+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();
+}
+
+void qemu_pwr_gic_off(void)
+{
+ gicv2_cpuif_disable();
+}
diff --git a/plat/qemu/common/qemu_gicv3.c b/plat/qemu/common/qemu_gicv3.c
new file mode 100644
index 0000000..0d35446
--- /dev/null
+++ b/plat/qemu/common/qemu_gicv3.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019, Linaro Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/gicv3.h>
+#include <drivers/arm/gic_common.h>
+#include <platform_def.h>
+#include <plat/common/platform.h>
+
+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());
+}
+
+void qemu_pwr_gic_off(void)
+{
+ gicv3_cpuif_disable(plat_my_core_pos());
+ gicv3_rdistif_off(plat_my_core_pos());
+}
diff --git a/plat/qemu/common/qemu_image_load.c b/plat/qemu/common/qemu_image_load.c
new file mode 100644
index 0000000..9970d1d
--- /dev/null
+++ b/plat/qemu/common/qemu_image_load.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/desc_image_load.h>
+
+/*******************************************************************************
+ * 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();
+}
diff --git a/plat/qemu/common/qemu_io_storage.c b/plat/qemu/common/qemu_io_storage.c
new file mode 100644
index 0000000..1107e44
--- /dev/null
+++ b/plat/qemu/common/qemu_io_storage.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_encrypted.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_semihosting.h>
+#include <drivers/io/io_storage.h>
+#include <lib/semihosting.h>
+#include <tools_share/firmware_image_package.h>
+
+/* 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;
+#ifndef DECRYPTION_SUPPORT_none
+static const io_dev_connector_t *enc_dev_con;
+static uintptr_t enc_dev_handle;
+#endif
+
+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);
+#ifndef DECRYPTION_SUPPORT_none
+static int open_enc_fip(const uintptr_t spec);
+#endif
+
+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
+ },
+ [ENC_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)NULL,
+ open_fip
+ },
+ [BL2_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&bl2_uuid_spec,
+ open_fip
+ },
+#if ENCRYPT_BL31 && !defined(DECRYPTION_SUPPORT_none)
+ [BL31_IMAGE_ID] = {
+ &enc_dev_handle,
+ (uintptr_t)&bl31_uuid_spec,
+ open_enc_fip
+ },
+#else
+ [BL31_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&bl31_uuid_spec,
+ open_fip
+ },
+#endif
+#if ENCRYPT_BL32 && !defined(DECRYPTION_SUPPORT_none)
+ [BL32_IMAGE_ID] = {
+ &enc_dev_handle,
+ (uintptr_t)&bl32_uuid_spec,
+ open_enc_fip
+ },
+ [BL32_EXTRA1_IMAGE_ID] = {
+ &enc_dev_handle,
+ (uintptr_t)&bl32_extra1_uuid_spec,
+ open_enc_fip
+ },
+ [BL32_EXTRA2_IMAGE_ID] = {
+ &enc_dev_handle,
+ (uintptr_t)&bl32_extra2_uuid_spec,
+ open_enc_fip
+ },
+#else
+ [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
+ },
+#endif
+ [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 && spec != (uintptr_t)NULL) {
+ 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 DECRYPTION_SUPPORT_none
+static int open_enc_fip(const uintptr_t spec)
+{
+ int result;
+ uintptr_t local_image_handle;
+
+ /* See if an encrypted FIP is available */
+ result = io_dev_init(enc_dev_handle, (uintptr_t)ENC_IMAGE_ID);
+ if (result == 0) {
+ result = io_open(enc_dev_handle, spec, &local_image_handle);
+ if (result == 0) {
+ VERBOSE("Using encrypted FIP\n");
+ io_close(local_image_handle);
+ }
+ }
+ return result;
+}
+#endif
+
+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);
+
+#ifndef DECRYPTION_SUPPORT_none
+ io_result = register_io_dev_enc(&enc_dev_con);
+ assert(io_result == 0);
+
+ io_result = io_dev_open(enc_dev_con, (uintptr_t)NULL,
+ &enc_dev_handle);
+ assert(io_result == 0);
+#endif
+
+ /* 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;
+}
diff --git a/plat/qemu/common/qemu_pm.c b/plat/qemu/common/qemu_pm.c
new file mode 100644
index 0000000..c2b5091
--- /dev/null
+++ b/plat/qemu/common/qemu_pm.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/psci/psci.h>
+#include <lib/semihosting.h>
+#include <plat/common/platform.h>
+#include <drivers/gpio.h>
+
+#include "qemu_private.h"
+
+#define ADP_STOPPED_APPLICATION_EXIT 0x20026
+
+/*
+ * 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.
+ ******************************************************************************/
+static void qemu_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ qemu_pwr_gic_off();
+}
+
+void __dead2 plat_secondary_cold_boot_setup(void);
+
+static void __dead2
+qemu_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
+{
+ disable_mmu_el3();
+ plat_secondary_cold_boot_setup();
+}
+
+/*******************************************************************************
+ * 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)
+{
+#ifdef SECURE_GPIO_BASE
+ ERROR("QEMU System Power off: with GPIO.\n");
+ gpio_set_direction(SECURE_GPIO_POWEROFF, GPIO_DIR_OUT);
+ gpio_set_value(SECURE_GPIO_POWEROFF, GPIO_LEVEL_LOW);
+ gpio_set_value(SECURE_GPIO_POWEROFF, GPIO_LEVEL_HIGH);
+#else
+ semihosting_exit(ADP_STOPPED_APPLICATION_EXIT, 0);
+ ERROR("QEMU System Off: semihosting call unexpectedly returned.\n");
+#endif
+ panic();
+}
+
+static void __dead2 qemu_system_reset(void)
+{
+ ERROR("QEMU System Reset: with GPIO.\n");
+#ifdef SECURE_GPIO_BASE
+ gpio_set_direction(SECURE_GPIO_RESET, GPIO_DIR_OUT);
+ gpio_set_value(SECURE_GPIO_RESET, GPIO_LEVEL_LOW);
+ gpio_set_value(SECURE_GPIO_RESET, GPIO_LEVEL_HIGH);
+#else
+ ERROR("QEMU System Reset: operation not handled.\n");
+#endif
+ 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_pwr_down_wfi = qemu_pwr_domain_pwr_down_wfi,
+ .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;
+}
diff --git a/plat/qemu/common/qemu_private.h b/plat/qemu/common/qemu_private.h
new file mode 100644
index 0000000..c313cb6
--- /dev/null
+++ b/plat/qemu/common/qemu_private.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QEMU_PRIVATE_H
+#define QEMU_PRIVATE_H
+
+#include <stdint.h>
+
+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);
+void qemu_pwr_gic_off(void);
+
+int qemu_set_tos_fw_info(uintptr_t config_base, uintptr_t log_addr,
+ size_t log_size);
+
+int qemu_set_nt_fw_info(
+/*
+ * Currently OP-TEE does not support reading DTBs from Secure memory
+ * and this option should be removed when feature is supported.
+ */
+#ifdef SPD_opteed
+ uintptr_t log_addr,
+#endif
+ size_t log_size,
+ uintptr_t *ns_log_addr);
+
+#endif /* QEMU_PRIVATE_H */
diff --git a/plat/qemu/common/qemu_rotpk.S b/plat/qemu/common/qemu_rotpk.S
new file mode 100644
index 0000000..5d1b83f
--- /dev/null
+++ b/plat/qemu/common/qemu_rotpk.S
@@ -0,0 +1,15 @@
+/*
+ * 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:
diff --git a/plat/qemu/common/qemu_spm.c b/plat/qemu/common/qemu_spm.c
new file mode 100644
index 0000000..c66f47e
--- /dev/null
+++ b/plat/qemu/common/qemu_spm.c
@@ -0,0 +1,147 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2020, Linaro Limited and Contributors. All rights reserved.
+ */
+
+#include <libfdt.h>
+
+#include <bl31/ehf.h>
+#include <common/debug.h>
+#include <common/fdt_fixup.h>
+#include <common/fdt_wrappers.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+#include <services/spm_mm_partition.h>
+
+#include <platform_def.h>
+
+/* Region equivalent to MAP_DEVICE1 suitable for mapping at EL0 */
+#define MAP_DEVICE1_EL0 MAP_REGION_FLAT(DEVICE1_BASE, \
+ DEVICE1_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE | MT_USER)
+
+mmap_region_t plat_qemu_secure_partition_mmap[] = {
+ QEMU_SP_IMAGE_NS_BUF_MMAP, /* must be placed at first entry */
+ MAP_DEVICE1_EL0, /* for the UART */
+ QEMU_SP_IMAGE_MMAP,
+ QEMU_SPM_BUF_EL0_MMAP,
+ QEMU_SP_IMAGE_RW_MMAP,
+ MAP_SECURE_VARSTORE,
+ {0}
+};
+
+/* Boot information passed to a secure partition during initialisation. */
+static spm_mm_mp_info_t sp_mp_info[PLATFORM_CORE_COUNT];
+
+spm_mm_boot_info_t plat_qemu_secure_partition_boot_info = {
+ .h.type = PARAM_SP_IMAGE_BOOT_INFO,
+ .h.version = VERSION_1,
+ .h.size = sizeof(spm_mm_boot_info_t),
+ .h.attr = 0,
+ .sp_mem_base = PLAT_QEMU_SP_IMAGE_BASE,
+ .sp_mem_limit = BL32_LIMIT,
+ .sp_image_base = PLAT_QEMU_SP_IMAGE_BASE,
+ .sp_stack_base = PLAT_SP_IMAGE_STACK_BASE,
+ .sp_heap_base = PLAT_QEMU_SP_IMAGE_HEAP_BASE,
+ .sp_ns_comm_buf_base = PLAT_QEMU_SP_IMAGE_NS_BUF_BASE,
+ .sp_shared_buf_base = PLAT_SPM_BUF_BASE,
+ .sp_image_size = PLAT_QEMU_SP_IMAGE_SIZE,
+ .sp_pcpu_stack_size = PLAT_SP_IMAGE_STACK_PCPU_SIZE,
+ .sp_heap_size = PLAT_QEMU_SP_IMAGE_HEAP_SIZE,
+ .sp_ns_comm_buf_size = PLAT_QEMU_SP_IMAGE_NS_BUF_SIZE,
+ .sp_shared_buf_size = PLAT_SPM_BUF_SIZE,
+ .num_sp_mem_regions = PLAT_QEMU_SP_IMAGE_NUM_MEM_REGIONS,
+ .num_cpus = PLATFORM_CORE_COUNT,
+ .mp_info = sp_mp_info
+};
+
+/* Enumeration of priority levels on QEMU platforms. */
+ehf_pri_desc_t qemu_exceptions[] = {
+ EHF_PRI_DESC(QEMU_PRI_BITS, PLAT_SP_PRI)
+};
+
+static void qemu_initialize_mp_info(spm_mm_mp_info_t *mp_info)
+{
+ unsigned int i, j;
+ spm_mm_mp_info_t *tmp = mp_info;
+
+ for (i = 0; i < PLATFORM_CLUSTER_COUNT; i++) {
+ for (j = 0; j < PLATFORM_MAX_CPUS_PER_CLUSTER; j++) {
+ tmp->mpidr = (0x80000000 | (i << MPIDR_AFF1_SHIFT)) + j;
+ /*
+ * Linear indices and flags will be filled
+ * in the spm_mm service.
+ */
+ tmp->linear_id = 0;
+ tmp->flags = 0;
+ tmp++;
+ }
+ }
+}
+
+int dt_add_ns_buf_node(uintptr_t *base)
+{
+ uintptr_t addr;
+ size_t size;
+ uintptr_t ns_buf_addr;
+ int node;
+ int err;
+ void *fdt = (void *)ARM_PRELOADED_DTB_BASE;
+
+ err = fdt_open_into(fdt, fdt, PLAT_QEMU_DT_MAX_SIZE);
+ if (err < 0) {
+ ERROR("Invalid Device Tree at %p: error %d\n", fdt, err);
+ return err;
+ }
+
+ /*
+ * reserved-memory for standaloneMM non-secure buffer
+ * is allocated at the top of the first system memory region.
+ */
+ node = fdt_path_offset(fdt, "/memory");
+
+ err = fdt_get_reg_props_by_index(fdt, node, 0, &addr, &size);
+ if (err < 0) {
+ ERROR("Failed to get the memory node information\n");
+ return err;
+ }
+ INFO("System RAM @ 0x%lx - 0x%lx\n", addr, addr + size - 1);
+
+ ns_buf_addr = addr + (size - PLAT_QEMU_SP_IMAGE_NS_BUF_SIZE);
+ INFO("reserved-memory for spm-mm @ 0x%lx - 0x%llx\n", ns_buf_addr,
+ ns_buf_addr + PLAT_QEMU_SP_IMAGE_NS_BUF_SIZE - 1);
+
+ err = fdt_add_reserved_memory(fdt, "ns-buf-spm-mm", ns_buf_addr,
+ PLAT_QEMU_SP_IMAGE_NS_BUF_SIZE);
+ if (err < 0) {
+ ERROR("Failed to add the reserved-memory node\n");
+ return err;
+ }
+
+ *base = ns_buf_addr;
+ return 0;
+}
+
+/* Plug in QEMU exceptions to Exception Handling Framework. */
+EHF_REGISTER_PRIORITIES(qemu_exceptions, ARRAY_SIZE(qemu_exceptions),
+ QEMU_PRI_BITS);
+
+const mmap_region_t *plat_get_secure_partition_mmap(void *cookie)
+{
+ uintptr_t ns_buf_base;
+
+ dt_add_ns_buf_node(&ns_buf_base);
+
+ plat_qemu_secure_partition_mmap[0].base_pa = ns_buf_base;
+ plat_qemu_secure_partition_mmap[0].base_va = ns_buf_base;
+ plat_qemu_secure_partition_boot_info.sp_ns_comm_buf_base = ns_buf_base;
+
+ return plat_qemu_secure_partition_mmap;
+}
+
+const spm_mm_boot_info_t *
+plat_get_secure_partition_boot_info(void *cookie)
+{
+ qemu_initialize_mp_info(sp_mp_info);
+
+ return &plat_qemu_secure_partition_boot_info;
+}
diff --git a/plat/qemu/common/qemu_spmd_manifest.c b/plat/qemu/common/qemu_spmd_manifest.c
new file mode 100644
index 0000000..fd46e26
--- /dev/null
+++ b/plat/qemu/common/qemu_spmd_manifest.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <services/spm_core_manifest.h>
+
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+int plat_spm_core_manifest_load(spmc_manifest_attribute_t *manifest,
+ const void *pm_addr)
+{
+ entry_point_info_t *ep_info = bl31_plat_get_next_image_ep_info(SECURE);
+
+ assert(ep_info != NULL);
+ assert(manifest != NULL);
+
+ manifest->major_version = 1;
+ manifest->minor_version = 0;
+ manifest->exec_state = ep_info->args.arg2;
+ manifest->load_address = BL32_BASE;
+ manifest->entrypoint = BL32_BASE;
+ manifest->binary_size = BL32_LIMIT - BL32_BASE;
+ manifest->spmc_id = 0x8000;
+
+ return 0;
+}
diff --git a/plat/qemu/common/qemu_stack_protector.c b/plat/qemu/common/qemu_stack_protector.c
new file mode 100644
index 0000000..15ce3d6
--- /dev/null
+++ b/plat/qemu/common/qemu_stack_protector.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <arch_features.h>
+#include <plat/common/platform.h>
+
+#define RANDOM_CANARY_VALUE ((u_register_t) 3288484550995823360ULL)
+
+u_register_t plat_get_stack_protector_canary(void)
+{
+#if ENABLE_FEAT_RNG
+ /* Use the RNDR instruction if the CPU supports it */
+ if (is_armv8_5_rng_present()) {
+ return read_rndr();
+ }
+#endif
+
+ /*
+ * Ideally, a random number should be returned above. If a random
+ * number generator is not supported, return instead a
+ * combination of a timer's value and a compile-time constant.
+ * This is better than nothing but not necessarily really secure.
+ */
+ return RANDOM_CANARY_VALUE ^ read_cntpct_el0();
+}
+
diff --git a/plat/qemu/common/qemu_trusted_boot.c b/plat/qemu/common/qemu_trusted_boot.c
new file mode 100644
index 0000000..6a8edca
--- /dev/null
+++ b/plat/qemu/common/qemu_trusted_boot.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+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;
+}
diff --git a/plat/qemu/common/sp_min/sp_min-qemu.mk b/plat/qemu/common/sp_min/sp_min-qemu.mk
new file mode 100644
index 0000000..e93a0c2
--- /dev/null
+++ b/plat/qemu/common/sp_min/sp_min-qemu.mk
@@ -0,0 +1,22 @@
+#
+# 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
diff --git a/plat/qemu/common/sp_min/sp_min_setup.c b/plat/qemu/common/sp_min/sp_min_setup.c
new file mode 100644
index 0000000..7ec657b
--- /dev/null
+++ b/plat/qemu/common/sp_min/sp_min_setup.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.h>
+
+#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);
+}
diff --git a/plat/qemu/common/topology.c b/plat/qemu/common/topology.c
new file mode 100644
index 0000000..6352706
--- /dev/null
+++ b/plat/qemu/common/topology.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+
+#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);
+}
diff --git a/plat/qemu/qemu/include/platform_def.h b/plat/qemu/qemu/include/platform_def.h
new file mode 100644
index 0000000..c9ed640
--- /dev/null
+++ b/plat/qemu/qemu/include/platform_def.h
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+/* 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 U(4)
+#define PLATFORM_CLUSTER_COUNT U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER
+#define PLATFORM_CLUSTER1_CORE_COUNT U(0)
+#else
+#define PLATFORM_MAX_CPUS_PER_CLUSTER U(4)
+/*
+ * Define the number of cores per cluster used in calculating core position.
+ * The cluster number is shifted by this value and added to the core ID,
+ * so its value represents log2(cores/cluster).
+ * Default is 2**(2) = 4 cores per cluster.
+ */
+#define PLATFORM_CPU_PER_CLUSTER_SHIFT U(2)
+
+#define PLATFORM_CLUSTER_COUNT U(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 U(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 ULL(0x40000000)
+#define NS_DRAM0_SIZE ULL(0xc0000000)
+
+#define SEC_SRAM_BASE 0x0e000000
+#define SEC_SRAM_SIZE 0x00100000
+
+#define SEC_DRAM_BASE 0x0e100000
+#define SEC_DRAM_SIZE 0x00f00000
+
+#define SECURE_GPIO_BASE 0x090b0000
+#define SECURE_GPIO_SIZE 0x00001000
+#define SECURE_GPIO_POWEROFF 0
+#define SECURE_GPIO_RESET 1
+
+/* 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 - 0x60000)
+#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 4
+#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 0x00040000
+#define PLAT_QEMU_FIP_MAX_SIZE 0x00400000
+
+#define DEVICE0_BASE 0x08000000
+#define DEVICE0_SIZE 0x01000000
+#define DEVICE1_BASE 0x09000000
+#define DEVICE1_SIZE 0x00c00000
+
+/*
+ * 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)
+
+/*
+ * Maximum size of Event Log buffer used in Measured Boot Event Log driver
+ */
+#define PLAT_EVENT_LOG_MAX_SIZE UL(0x400)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/qemu/qemu/platform.mk b/plat/qemu/qemu/platform.mk
new file mode 100644
index 0000000..6becc32
--- /dev/null
+++ b/plat/qemu/qemu/platform.mk
@@ -0,0 +1,266 @@
+#
+# Copyright (c) 2013-2022, 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))
+$(eval $(call add_define,ARMV7_SUPPORTS_VFP))
+# 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
+ifeq ($(SPMC_OPTEE),1)
+$(eval $(call add_define,SPMC_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)
+
+ AUTH_SOURCES := drivers/auth/auth_mod.c \
+ drivers/auth/img_parser_mod.c \
+ drivers/auth/tbbr/tbbr_cot_common.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 \
+ drivers/auth/tbbr/tbbr_cot_bl1.c
+
+ 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 \
+ drivers/auth/tbbr/tbbr_cot_bl2.c
+
+ include drivers/auth/mbedtls/mbedtls_x509.mk
+
+ 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): | $(BUILD_PLAT)
+ @echo " OPENSSL $@"
+ $(Q)${OPENSSL_BIN_PATH}/openssl genrsa 2048 > $@ 2>/dev/null
+
+ $(ROTPK_HASH): $(ROT_KEY)
+ @echo " OPENSSL $@"
+ $(Q)${OPENSSL_BIN_PATH}/openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+ ${OPENSSL_BIN_PATH}/openssl dgst -sha256 -binary > $@ 2>/dev/null
+endif
+
+# Include Measured Boot makefile before any Crypto library makefile.
+# Crypto library makefile may need default definitions of Measured Boot build
+# flags present in Measured Boot makefile.
+ifeq (${MEASURED_BOOT},1)
+ MEASURED_BOOT_MK := drivers/measured_boot/event_log/event_log.mk
+ $(info Including ${MEASURED_BOOT_MK})
+ include ${MEASURED_BOOT_MK}
+
+ ifneq (${MBOOT_EL_HASH_ALG}, sha256)
+ $(eval $(call add_define,TF_MBEDTLS_MBOOT_USE_SHA512))
+ endif
+
+ BL2_SOURCES += plat/qemu/qemu/qemu_measured_boot.c \
+ plat/qemu/qemu/qemu_common_measured_boot.c \
+ plat/qemu/qemu/qemu_helpers.c \
+ ${EVENT_LOG_SOURCES}
+
+ BL1_SOURCES += plat/qemu/qemu/qemu_bl1_measured_boot.c
+
+endif
+
+ifneq ($(filter 1,${MEASURED_BOOT} ${TRUSTED_BOARD_BOOT}),)
+ CRYPTO_SOURCES := drivers/auth/crypto_mod.c
+
+ BL1_SOURCES += ${CRYPTO_SOURCES}
+ BL2_SOURCES += ${CRYPTO_SOURCES}
+
+ # We expect to locate the *.mk files under the directories specified below
+ #
+ include drivers/auth/mbedtls/mbedtls_crypto.mk
+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 \
+ lib/cpus/aarch64/cortex_a72.S \
+ lib/cpus/aarch64/qemu_max.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/fdt_wrappers.c \
+ common/desc_image_load.c
+
+ifeq ($(add-lib-optee),yes)
+BL2_SOURCES += lib/optee/optee_utils.c
+endif
+
+ifneq (${DECRYPTION_SUPPORT},none)
+BL1_SOURCES += drivers/io/io_encrypted.c
+BL2_SOURCES += drivers/io/io_encrypted.c
+endif
+
+# Include GICv2 driver files
+include drivers/arm/gic/v2/gicv2.mk
+QEMU_GICV2_SOURCES := ${GICV2_SOURCES} \
+ plat/common/plat_gicv2.c \
+ ${PLAT_QEMU_COMMON_PATH}/qemu_gicv2.c
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+QEMU_GICV3_SOURCES := ${GICV3_SOURCES} \
+ 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 \
+ lib/cpus/aarch64/cortex_a72.S \
+ lib/cpus/aarch64/qemu_max.S \
+ lib/semihosting/semihosting.c \
+ lib/semihosting/${ARCH}/semihosting_call.S \
+ plat/common/plat_psci_common.c \
+ drivers/arm/pl061/pl061_gpio.c \
+ drivers/gpio/gpio.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}
+
+ifeq (${SPD},spmd)
+BL31_SOURCES += plat/qemu/common/qemu_spmd_manifest.c
+endif
+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),)
+ifneq (${DECRYPTION_SUPPORT},none)
+$(eval $(call TOOL_ADD_IMG,bl32_extra1,--tos-fw-extra1,,$(ENCRYPT_BL32)))
+else
+$(eval $(call TOOL_ADD_IMG,bl32_extra1,--tos-fw-extra1))
+endif
+endif
+ifneq ($(BL32_EXTRA2),)
+ifneq (${DECRYPTION_SUPPORT},none)
+$(eval $(call TOOL_ADD_IMG,bl32_extra2,--tos-fw-extra2,,$(ENCRYPT_BL32)))
+else
+$(eval $(call TOOL_ADD_IMG,bl32_extra2,--tos-fw-extra2))
+endif
+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))
+
+# 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))
+
+ARM_PRELOADED_DTB_BASE := PLAT_QEMU_DT_BASE
+$(eval $(call add_define,ARM_PRELOADED_DTB_BASE))
+
+# Later QEMU versions support SME and SVE.
+ifneq (${ARCH},aarch32)
+ ENABLE_SVE_FOR_NS := 1
+ ENABLE_SME_FOR_NS := 1
+endif
diff --git a/plat/qemu/qemu/qemu_bl1_measured_boot.c b/plat/qemu/qemu/qemu_bl1_measured_boot.c
new file mode 100644
index 0000000..3d20f97
--- /dev/null
+++ b/plat/qemu/qemu/qemu_bl1_measured_boot.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2022, Linaro.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <common/desc_image_load.h>
+
+/*
+ * Add dummy functions for measured boot for BL1.
+ * In most of the SoC's, ROM/BL1 code is pre-built. So we are assumimg that
+ * it doesn't have the capability to do measurements and extend eventlog.
+ * hence these are dummy functions.
+ */
+void bl1_plat_mboot_init(void)
+{
+}
+
+void bl1_plat_mboot_finish(void)
+{
+}
+
+int plat_mboot_measure_image(unsigned int image_id, image_info_t *image_data)
+{
+ return 0;
+}
diff --git a/plat/qemu/qemu/qemu_common_measured_boot.c b/plat/qemu/qemu/qemu_common_measured_boot.c
new file mode 100644
index 0000000..41f7f87
--- /dev/null
+++ b/plat/qemu/qemu/qemu_common_measured_boot.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2022, Linaro.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <common/desc_image_load.h>
+#include <drivers/measured_boot/event_log/event_log.h>
+#include <plat/common/platform.h>
+
+extern event_log_metadata_t qemu_event_log_metadata[];
+
+const event_log_metadata_t *plat_event_log_get_metadata(void)
+{
+ return qemu_event_log_metadata;
+}
+
+int plat_mboot_measure_image(unsigned int image_id, image_info_t *image_data)
+{
+ /* Calculate image hash and record data in Event Log */
+ int err = event_log_measure_and_record(image_data->image_base,
+ image_data->image_size,
+ image_id);
+ if (err != 0) {
+ ERROR("%s%s image id %u (%i)\n",
+ "Failed to ", "record", image_id, err);
+ return err;
+ }
+
+ return 0;
+}
diff --git a/plat/qemu/qemu/qemu_helpers.c b/plat/qemu/qemu/qemu_helpers.c
new file mode 100644
index 0000000..1b31ab5
--- /dev/null
+++ b/plat/qemu/qemu/qemu_helpers.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2022, Linaro.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/bl_common.h>
+#if MEASURED_BOOT
+#include <common/desc_image_load.h>
+#endif
+#include <common/fdt_wrappers.h>
+#include <platform_def.h>
+
+#include <libfdt.h>
+
+#ifdef SPD_opteed
+/*
+ * Currently OP-TEE does not support reading DTBs from Secure memory
+ * and this property should be removed when this feature is supported.
+ */
+#define DTB_PROP_HW_SM_LOG_ADDR "tpm_event_log_sm_addr"
+#endif
+
+#define DTB_PROP_HW_LOG_ADDR "tpm_event_log_addr"
+#define DTB_PROP_HW_LOG_SIZE "tpm_event_log_size"
+
+#if MEASURED_BOOT
+
+#ifdef SPD_opteed
+int qemu_set_tee_fw_info(uintptr_t config_base, uintptr_t log_addr,
+ size_t log_size)
+{
+ int offs, err = 0;
+ void *dtb = (void *)config_base;
+ const char *compatible = "arm,tpm_event_log";
+ uint64_t sec_base = cpu_to_fdt64(log_addr);
+ uint32_t sz = cpu_to_fdt32(log_size);
+
+ offs = fdtw_find_or_add_subnode(dtb, 0, "tpm-event-log");
+ if (offs < 0) {
+ ERROR("Failed to add node tpm-event-log %d\n", offs);
+ return offs;
+ }
+
+ if (fdt_appendprop(dtb, offs, "compatible", compatible,
+ strlen(compatible) + 1) < 0) {
+ return -1;
+ }
+
+ err = fdt_setprop(dtb, offs, DTB_PROP_HW_SM_LOG_ADDR, &sec_base, 8);
+ if (err < 0) {
+ ERROR("Failed to add log addr err %d\n", err);
+ return err;
+ }
+
+ err = fdt_setprop(dtb, offs, DTB_PROP_HW_LOG_SIZE, &sz, 4);
+ if (err < 0) {
+ ERROR("Failed to add log addr err %d\n", err);
+ return err;
+ }
+
+ return err;
+}
+#endif
+
+/*
+ * Write the Event Log address and its size in the DTB.
+ *
+ * This function is supposed to be called only by BL2.
+ *
+ * Returns:
+ * 0 = success
+ * < 0 = error
+ */
+static int qemu_set_event_log_info(uintptr_t config_base,
+#ifdef SPD_opteed
+ uintptr_t sm_log_addr,
+#endif
+ uintptr_t log_addr, size_t log_size)
+{
+ /* As libfdt uses void *, we can't avoid this cast */
+ void *dtb = (void *)config_base;
+ const char *compatible_tpm = "tcg,tpm-tis-mmio";
+ uint64_t base = cpu_to_fdt64(log_addr);
+ uint32_t sz = cpu_to_fdt32(log_size);
+ int err, node;
+
+ err = fdt_open_into(dtb, dtb, PLAT_QEMU_DT_MAX_SIZE);
+ if (err < 0) {
+ ERROR("Invalid Device Tree at %p: error %d\n", dtb, err);
+ return err;
+ }
+
+ /*
+ * Verify that the DTB is valid, before attempting to write to it,
+ * and get the DTB root node.
+ */
+
+ /* Check if the pointer to DT is correct */
+ err = fdt_check_header(dtb);
+ if (err < 0) {
+ WARN("Invalid DTB file passed\n");
+ return err;
+ }
+
+ /*
+ * Find the TPM node in device tree. On qemu, we assume it will
+ * be sw-tpm.
+ */
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible_tpm);
+ if (node < 0) {
+ ERROR("The compatible property '%s' not%s", compatible_tpm,
+ " found in the config\n");
+ return node;
+ }
+
+ err = fdt_setprop(dtb, node, DTB_PROP_HW_LOG_ADDR, &base, 8);
+ if (err < 0) {
+ ERROR("Failed to add log addr err %d\n", err);
+ return err;
+ }
+
+ err = fdt_setprop(dtb, node, DTB_PROP_HW_LOG_SIZE, &sz, 4);
+ if (err < 0) {
+ ERROR("Failed to add log addr err %d\n", err);
+ return err;
+ }
+
+#ifdef SPD_opteed
+ err = qemu_set_tee_fw_info(config_base, sm_log_addr, log_size);
+ if (err < 0) {
+ ERROR("Failed to add tpm-event-node at %p: err %d\n", dtb, err);
+ return err;
+ }
+#endif
+
+ err = fdt_pack(dtb);
+ if (err < 0) {
+ ERROR("Failed to pack Device Tree at %p: err %d\n", dtb, err);
+ return err;
+ }
+
+ /*
+ * Ensure that the info written to the DTB is visible
+ * to other images.
+ */
+ flush_dcache_range(config_base, fdt_totalsize(dtb));
+
+ return err;
+}
+
+/*
+ * This function writes the Event Log address and its size
+ * in the TOS_FW_CONFIG DTB.
+ *
+ * This function is supposed to be called only by BL2.
+ *
+ * Returns:
+ * 0 = success
+ * < 0 = error
+ */
+int qemu_set_tos_fw_info(uintptr_t config_base, uintptr_t log_addr,
+ size_t log_size)
+{
+ int err = 0;
+
+ assert(config_base != 0UL);
+ assert(log_addr != 0UL);
+
+ /*
+ * FIXME - add code to add/update Log address and it's
+ * size in TOS FW CONFIG.
+ * For now we don't have support for TOS FW config in OP-TEE.
+ * So leave this function blank
+ */
+
+ return err;
+}
+
+/*
+ * This function writes the Event Log address and its size
+ * in the QEMU DTB.
+ *
+ * This function is supposed to be called only by BL2.
+ *
+ * Returns:
+ * 0 = success
+ * < 0 = error
+ */
+int qemu_set_nt_fw_info(
+#ifdef SPD_opteed
+ uintptr_t log_addr,
+#endif
+ size_t log_size, uintptr_t *ns_log_addr)
+{
+ uintptr_t ns_addr;
+ int err;
+
+ assert(ns_log_addr != NULL);
+
+ ns_addr = PLAT_QEMU_DT_BASE + PLAT_QEMU_DT_MAX_SIZE;
+
+ /* Write the Event Log address and its size in the DTB */
+ err = qemu_set_event_log_info(PLAT_QEMU_DT_BASE,
+#ifdef SPD_opteed
+ log_addr,
+#endif
+ ns_addr, log_size);
+
+ /* Return Event Log address in Non-secure memory */
+ *ns_log_addr = (err < 0) ? 0UL : ns_addr;
+ return err;
+}
+#endif /* MEASURED_BOOT */
diff --git a/plat/qemu/qemu/qemu_measured_boot.c b/plat/qemu/qemu/qemu_measured_boot.c
new file mode 100644
index 0000000..d9e475a
--- /dev/null
+++ b/plat/qemu/qemu/qemu_measured_boot.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2022, Linaro.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <drivers/measured_boot/event_log/event_log.h>
+#include <plat/common/common_def.h>
+#include <tools_share/tbbr_oid.h>
+
+#include "../common/qemu_private.h"
+
+/* Event Log data */
+static uint8_t event_log[PLAT_EVENT_LOG_MAX_SIZE];
+static uint64_t event_log_base;
+
+/* FVP table with platform specific image IDs, names and PCRs */
+const event_log_metadata_t qemu_event_log_metadata[] = {
+ { BL31_IMAGE_ID, EVLOG_BL31_STRING, PCR_0 },
+ { BL32_IMAGE_ID, EVLOG_BL32_STRING, PCR_0 },
+ { BL32_EXTRA1_IMAGE_ID, EVLOG_BL32_EXTRA1_STRING, PCR_0 },
+ { BL32_EXTRA2_IMAGE_ID, EVLOG_BL32_EXTRA2_STRING, PCR_0 },
+ { BL33_IMAGE_ID, EVLOG_BL33_STRING, PCR_0 },
+ { HW_CONFIG_ID, EVLOG_HW_CONFIG_STRING, PCR_0 },
+ { NT_FW_CONFIG_ID, EVLOG_NT_FW_CONFIG_STRING, PCR_0 },
+ { SCP_BL2_IMAGE_ID, EVLOG_SCP_BL2_STRING, PCR_0 },
+ { SOC_FW_CONFIG_ID, EVLOG_SOC_FW_CONFIG_STRING, PCR_0 },
+ { TOS_FW_CONFIG_ID, EVLOG_TOS_FW_CONFIG_STRING, PCR_0 },
+
+ { EVLOG_INVALID_ID, NULL, (unsigned int)(-1) } /* Terminator */
+};
+
+void bl2_plat_mboot_init(void)
+{
+ /*
+ * Here we assume that BL1/ROM code doesn't have the driver
+ * to measure the BL2 code which is a common case for
+ * already existing platforms
+ */
+ event_log_init(event_log, event_log + sizeof(event_log));
+ event_log_write_header();
+
+ /*
+ * TBD - Add code to do self measurement of BL2 code and add an
+ * event for BL2 measurement
+ */
+
+ event_log_base = (uintptr_t)event_log;
+}
+
+void bl2_plat_mboot_finish(void)
+{
+ int rc;
+
+ /* Event Log address in Non-Secure memory */
+ uintptr_t ns_log_addr;
+
+ /* Event Log filled size */
+ size_t event_log_cur_size;
+
+ event_log_cur_size = event_log_get_cur_size((uint8_t *)event_log_base);
+
+ rc = qemu_set_nt_fw_info(
+#ifdef SPD_opteed
+ (uintptr_t)event_log_base,
+#endif
+ event_log_cur_size, &ns_log_addr);
+ if (rc != 0) {
+ ERROR("%s(): Unable to update %s_FW_CONFIG\n",
+ __func__, "NT");
+ /*
+ * It is a fatal error because on QEMU secure world software
+ * assumes that a valid event log exists and will use it to
+ * record the measurements into the fTPM or sw-tpm.
+ * Note: In QEMU platform, OP-TEE uses nt_fw_config to get the
+ * secure Event Log buffer address.
+ */
+ panic();
+ }
+
+ /* Copy Event Log to Non-secure memory */
+ (void)memcpy((void *)ns_log_addr, (const void *)event_log_base,
+ event_log_cur_size);
+
+ /* Ensure that the Event Log is visible in Non-secure memory */
+ flush_dcache_range(ns_log_addr, event_log_cur_size);
+
+#if defined(SPD_tspd) || defined(SPD_spmd)
+ /* Set Event Log data in TOS_FW_CONFIG */
+ rc = qemu_set_tos_fw_info((uintptr_t)event_log_base,
+ event_log_cur_size);
+ if (rc != 0) {
+ ERROR("%s(): Unable to update %s_FW_CONFIG\n",
+ __func__, "TOS");
+ panic();
+ }
+#endif /* defined(SPD_tspd) || defined(SPD_spmd) */
+
+ dump_event_log((uint8_t *)event_log_base, event_log_cur_size);
+}
diff --git a/plat/qemu/qemu_sbsa/include/platform_def.h b/plat/qemu/qemu_sbsa/include/platform_def.h
new file mode 100644
index 0000000..d971ebe
--- /dev/null
+++ b/plat/qemu/qemu_sbsa/include/platform_def.h
@@ -0,0 +1,378 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2019-2020, Linaro Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <plat/common/common_def.h>
+#include <tbbr_img_def.h>
+
+/* 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 U(8)
+/*
+ * Define the number of cores per cluster used in calculating core position.
+ * The cluster number is shifted by this value and added to the core ID,
+ * so its value represents log2(cores/cluster).
+ * Default is 2**(3) = 8 cores per cluster.
+ */
+#define PLATFORM_CPU_PER_CLUSTER_SHIFT U(3)
+#define PLATFORM_CLUSTER_COUNT U(64)
+#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \
+ PLATFORM_MAX_CPUS_PER_CLUSTER)
+#define QEMU_PRIMARY_CPU U(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 0x00002000
+
+#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_SIZE 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 - BL1_SIZE)
+#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_SIZE 0x1D000
+#define BL2_BASE (BL31_BASE - BL2_SIZE)
+#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_SIZE 0x300000
+#define BL31_BASE (BL31_LIMIT - BL31_SIZE)
+#define BL31_LIMIT (BL1_RW_BASE)
+#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 BL2_BASE
+
+#define BL32_MEM_BASE BL_RAM_BASE
+#define BL32_MEM_SIZE (BL_RAM_SIZE - BL1_SIZE - \
+ BL2_SIZE - BL31_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)
+#if SPM_MM
+#define MAX_MMAP_REGIONS 12
+#define MAX_XLAT_TABLES 12
+#else
+#define MAX_MMAP_REGIONS 11
+#define MAX_XLAT_TABLES 11
+#endif
+#define MAX_IO_DEVICES 3
+#define MAX_IO_HANDLES 4
+
+#if SPM_MM && defined(IMAGE_BL31)
+# define PLAT_SP_IMAGE_MMAP_REGIONS 30
+# define PLAT_SP_IMAGE_MAX_XLAT_TABLES 50
+#endif
+
+/*
+ * PL011 related constants
+ */
+#define UART0_BASE 0x60000000
+#define UART1_BASE 0x60030000
+#define UART0_CLK_IN_HZ 1
+#define UART1_CLK_IN_HZ 1
+
+/* Secure UART */
+#define UART2_BASE 0x60040000
+#define UART2_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 0x00400000
+
+/* 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 0x10041000
+/* This is a map for SECURE_EC */
+#define DEVICE2_BASE 0x50000000
+#define DEVICE2_SIZE 0x00001000
+
+/*
+ * 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 0x100000
+
+/*
+ * System counter
+ */
+#define SYS_COUNTER_FREQ_IN_TICKS ((1000 * 1000 * 1000) / 16)
+
+#if SPM_MM
+#define PLAT_QEMU_SP_IMAGE_BASE BL_RAM_BASE
+#define PLAT_QEMU_SP_IMAGE_SIZE ULL(0x300000)
+
+#ifdef IMAGE_BL2
+/* In BL2 all memory allocated to the SPM Payload image is marked as RW. */
+# define QEMU_SP_IMAGE_MMAP MAP_REGION_FLAT( \
+ PLAT_QEMU_SP_IMAGE_BASE, \
+ PLAT_QEMU_SP_IMAGE_SIZE, \
+ MT_MEMORY | MT_RW | \
+ MT_SECURE)
+#elif IMAGE_BL31
+/* All SPM Payload memory is marked as code in S-EL0 */
+# define QEMU_SP_IMAGE_MMAP MAP_REGION2(PLAT_QEMU_SP_IMAGE_BASE, \
+ PLAT_QEMU_SP_IMAGE_BASE, \
+ PLAT_QEMU_SP_IMAGE_SIZE, \
+ MT_CODE | MT_SECURE | \
+ MT_USER, \
+ PAGE_SIZE)
+#endif
+
+/*
+ * EL3 -> S-EL0 secure shared memory
+ */
+#define PLAT_SPM_BUF_PCPU_SIZE ULL(0x10000)
+#define PLAT_SPM_BUF_SIZE (PLATFORM_CORE_COUNT * \
+ PLAT_SPM_BUF_PCPU_SIZE)
+#define PLAT_SPM_BUF_BASE (BL32_LIMIT - PLAT_SPM_BUF_SIZE)
+
+#define QEMU_SPM_BUF_EL3_MMAP MAP_REGION_FLAT(PLAT_SPM_BUF_BASE, \
+ PLAT_SPM_BUF_SIZE, \
+ MT_RW_DATA | MT_SECURE)
+
+#define QEMU_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)
+
+/*
+ * Shared memory between Normal world and S-EL0 for
+ * passing data during service requests. It will be marked as RW and NS.
+ * This buffer is allocated at the top of NS_DRAM, the base address is
+ * overridden in SPM initialization.
+ */
+#define PLAT_QEMU_SP_IMAGE_NS_BUF_BASE (PLAT_QEMU_DT_BASE + \
+ PLAT_QEMU_DT_MAX_SIZE)
+#define PLAT_QEMU_SP_IMAGE_NS_BUF_SIZE ULL(0x200000)
+
+#define QEMU_SP_IMAGE_NS_BUF_MMAP MAP_REGION2( \
+ PLAT_QEMU_SP_IMAGE_NS_BUF_BASE, \
+ PLAT_QEMU_SP_IMAGE_NS_BUF_BASE, \
+ PLAT_QEMU_SP_IMAGE_NS_BUF_SIZE, \
+ MT_RW_DATA | MT_NS | \
+ MT_USER, \
+ PAGE_SIZE)
+
+#define PLAT_SP_IMAGE_NS_BUF_BASE PLAT_QEMU_SP_IMAGE_NS_BUF_BASE
+#define PLAT_SP_IMAGE_NS_BUF_SIZE PLAT_QEMU_SP_IMAGE_NS_BUF_SIZE
+
+#define PLAT_QEMU_SP_IMAGE_HEAP_BASE (PLAT_QEMU_SP_IMAGE_BASE + \
+ PLAT_QEMU_SP_IMAGE_SIZE)
+#define PLAT_QEMU_SP_IMAGE_HEAP_SIZE ULL(0x800000)
+
+#define PLAT_SP_IMAGE_STACK_BASE (PLAT_QEMU_SP_IMAGE_HEAP_BASE + \
+ PLAT_QEMU_SP_IMAGE_HEAP_SIZE)
+#define PLAT_SP_IMAGE_STACK_PCPU_SIZE ULL(0x10000)
+#define QEMU_SP_IMAGE_STACK_TOTAL_SIZE (PLATFORM_CORE_COUNT * \
+ PLAT_SP_IMAGE_STACK_PCPU_SIZE)
+
+#define QEMU_SP_IMAGE_RW_MMAP MAP_REGION2( \
+ PLAT_QEMU_SP_IMAGE_HEAP_BASE, \
+ PLAT_QEMU_SP_IMAGE_HEAP_BASE, \
+ (QEMU_SP_IMAGE_STACK_TOTAL_SIZE + \
+ PLAT_QEMU_SP_IMAGE_HEAP_SIZE), \
+ MT_RW_DATA | MT_SECURE | \
+ MT_USER, \
+ PAGE_SIZE)
+
+/*
+ * Secure variable storage is located at Secure Flash.
+ */
+#if SPM_MM
+#define QEMU_SECURE_VARSTORE_BASE 0x01000000
+#define QEMU_SECURE_VARSTORE_SIZE 0x00100000
+#define MAP_SECURE_VARSTORE MAP_REGION_FLAT( \
+ QEMU_SECURE_VARSTORE_BASE, \
+ QEMU_SECURE_VARSTORE_SIZE, \
+ MT_DEVICE | MT_RW | \
+ MT_SECURE | MT_USER)
+#endif
+
+/* Total number of memory regions with distinct properties */
+#define PLAT_QEMU_SP_IMAGE_NUM_MEM_REGIONS 6
+
+/*
+ * Name of the section to put the translation tables used by the S-EL1/S-EL0
+ * context of a Secure Partition.
+ */
+#define PLAT_SP_IMAGE_XLAT_SECTION_NAME "qemu_sp_xlat_table"
+#define PLAT_SP_IMAGE_BASE_XLAT_SECTION_NAME "qemu_sp_xlat_table"
+
+/* Cookies passed to the Secure Partition at boot. Not used by QEMU platforms.*/
+#define PLAT_SPM_COOKIE_0 ULL(0)
+#define PLAT_SPM_COOKIE_1 ULL(0)
+#endif
+
+#define QEMU_PRI_BITS 2
+#define PLAT_SP_PRI 0x20
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/qemu/qemu_sbsa/platform.mk b/plat/qemu/qemu_sbsa/platform.mk
new file mode 100644
index 0000000..5a6b1e1
--- /dev/null
+++ b/plat/qemu/qemu_sbsa/platform.mk
@@ -0,0 +1,127 @@
+#
+# Copyright (c) 2019-2021, Linaro Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include common/fdt_wrappers.mk
+
+CRASH_REPORTING := 1
+
+include lib/libfdt/libfdt.mk
+
+ifeq (${SPM_MM},1)
+NEED_BL32 := yes
+EL3_EXCEPTION_HANDLING := 1
+GICV2_G0_FOR_EL3 := 1
+endif
+
+# 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/cortex_a57.S \
+ lib/cpus/aarch64/cortex_a72.S \
+ lib/cpus/aarch64/qemu_max.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
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+QEMU_GIC_SOURCES := ${GICV3_SOURCES} \
+ plat/common/plat_gicv3.c \
+ ${PLAT_QEMU_COMMON_PATH}/qemu_gicv3.c
+
+BL31_SOURCES += lib/cpus/aarch64/cortex_a57.S \
+ lib/cpus/aarch64/cortex_a72.S \
+ lib/cpus/aarch64/qemu_max.S \
+ lib/semihosting/semihosting.c \
+ lib/semihosting/${ARCH}/semihosting_call.S \
+ plat/common/plat_psci_common.c \
+ ${PLAT_QEMU_PATH}/sbsa_pm.c \
+ ${PLAT_QEMU_PATH}/sbsa_topology.c \
+ ${PLAT_QEMU_COMMON_PATH}/aarch64/plat_helpers.S \
+ ${PLAT_QEMU_COMMON_PATH}/qemu_bl31_setup.c \
+ common/fdt_fixup.c \
+ ${QEMU_GIC_SOURCES}
+
+BL31_SOURCES += ${FDT_WRAPPERS_SOURCES}
+
+ifeq (${SPM_MM},1)
+ BL31_SOURCES += ${PLAT_QEMU_COMMON_PATH}/qemu_spm.c
+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
+
+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))
+
+# 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))
+
+ARM_PRELOADED_DTB_BASE := PLAT_QEMU_DT_BASE
+$(eval $(call add_define,ARM_PRELOADED_DTB_BASE))
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS := 0
diff --git a/plat/qemu/qemu_sbsa/sbsa_pm.c b/plat/qemu/qemu_sbsa/sbsa_pm.c
new file mode 100644
index 0000000..8d1e1d4
--- /dev/null
+++ b/plat/qemu/qemu_sbsa/sbsa_pm.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2020, Nuvia Inc
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+#include "sbsa_private.h"
+
+#define ADP_STOPPED_APPLICATION_EXIT 0x20026
+
+/*
+ * Define offset and commands for the fake EC device
+ */
+#define SBSA_SECURE_EC_OFFSET 0x50000000
+
+#define SBSA_SECURE_EC_CMD_SHUTDOWN 0x01
+#define SBSA_SECURE_EC_CMD_REBOOT 0x02
+
+/*
+ * 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;
+ unsigned 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 justifies the additional complexity.
+ */
+ for (i = 0U; qemu_pm_idle_states[i] != 0U; 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] == 0U) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ i = 0U;
+ state_id = psci_get_pstate_id(power_state);
+
+ /* Parse the State ID and populate the state info parameter */
+ while (state_id != 0U) {
+ 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 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 pos = plat_core_pos_by_mpidr(mpidr);
+ uint64_t *hold_base = (uint64_t *)PLAT_QEMU_HOLD_BASE;
+
+ if (pos < 0) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ hold_base[pos] = PLAT_QEMU_HOLD_STATE_GO;
+ dsb();
+ sev();
+
+ return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+static void qemu_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ qemu_pwr_gic_off();
+}
+
+void __dead2 plat_secondary_cold_boot_setup(void);
+
+static void __dead2
+qemu_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
+{
+ disable_mmu_el3();
+ plat_secondary_cold_boot_setup();
+}
+
+/*******************************************************************************
+ * 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(false);
+}
+
+/*******************************************************************************
+ * 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(false);
+}
+
+/*******************************************************************************
+ * Platform handlers to shutdown/reboot the system
+ ******************************************************************************/
+static void __dead2 qemu_system_off(void)
+{
+ mmio_write_32(SBSA_SECURE_EC_OFFSET, SBSA_SECURE_EC_CMD_SHUTDOWN);
+ panic();
+}
+
+static void __dead2 qemu_system_reset(void)
+{
+ mmio_write_32(SBSA_SECURE_EC_OFFSET, SBSA_SECURE_EC_CMD_REBOOT);
+ 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_pwr_down_wfi = qemu_pwr_domain_pwr_down_wfi,
+ .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
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const plat_psci_ops_t **psci_ops)
+{
+ uintptr_t *mailbox = (uintptr_t *)PLAT_QEMU_TRUSTED_MAILBOX_BASE;
+
+ *mailbox = sec_entrypoint;
+ secure_entrypoint = (unsigned long)sec_entrypoint;
+ *psci_ops = &plat_qemu_psci_pm_ops;
+
+ return 0;
+}
diff --git a/plat/qemu/qemu_sbsa/sbsa_private.h b/plat/qemu/qemu_sbsa/sbsa_private.h
new file mode 100644
index 0000000..a9f4601
--- /dev/null
+++ b/plat/qemu/qemu_sbsa/sbsa_private.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2020, Nuvia Inc
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SBSA_PRIVATE_H
+#define SBSA_PRIVATE_H
+
+#include <stdint.h>
+
+unsigned int plat_qemu_calc_core_pos(u_register_t mpidr);
+
+void qemu_pwr_gic_on_finish(void);
+void qemu_pwr_gic_off(void);
+
+#endif /* SBSA_PRIVATE_H */
diff --git a/plat/qemu/qemu_sbsa/sbsa_topology.c b/plat/qemu/qemu_sbsa/sbsa_topology.c
new file mode 100644
index 0000000..bd8d16b
--- /dev/null
+++ b/plat/qemu/qemu_sbsa/sbsa_topology.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2020, Nuvia Inc
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <common/debug.h>
+
+#include <platform_def.h>
+#include "sbsa_private.h"
+
+/* The power domain tree descriptor */
+static unsigned char power_domain_tree_desc[PLATFORM_CLUSTER_COUNT + 1];
+
+/*******************************************************************************
+ * This function returns the sbsa-ref default topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ unsigned int i;
+
+ power_domain_tree_desc[0] = PLATFORM_CLUSTER_COUNT;
+
+ for (i = 0U; i < PLATFORM_CLUSTER_COUNT; i++) {
+ power_domain_tree_desc[i + 1] = PLATFORM_MAX_CPUS_PER_CLUSTER;
+ }
+
+ 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)) != 0U) {
+ ERROR("Invalid MPIDR\n");
+ 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) {
+ ERROR("cluster_id >= PLATFORM_CLUSTER_COUNT define\n");
+ return -1;
+ }
+
+ if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER) {
+ ERROR("cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER define\n");
+ return -1;
+ }
+
+ return plat_qemu_calc_core_pos(mpidr);
+}
diff --git a/plat/qti/common/inc/aarch64/plat_macros.S b/plat/qti/common/inc/aarch64/plat_macros.S
new file mode 100644
index 0000000..2e292fb
--- /dev/null
+++ b/plat/qti/common/inc/aarch64/plat_macros.S
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018,2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLAT_MACROS_S__
+#define __PLAT_MACROS_S__
+
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gicv3.h>
+
+#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"
+
+/** Macro : plat_crash_print_regs
+ * This macro allows the crash reporting routine to print GIC registers
+ * in case of an unhandled exception in BL31. This aids in debugging and
+ * this macro can be defined to be empty in case GIC register reporting is
+ * not desired.
+ * The below required platform porting macro
+ * prints out relevant GIC registers whenever an
+ * unhandled exception is taken in BL31.
+ * Clobbers: x0 - x10, x26, x27, sp
+ * ---------------------------------------------
+ */
+ .macro plat_crash_print_regs
+print_gic_regs:
+ ldr x26, =QTI_GICD_BASE
+ ldr x27, =QTI_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:
+
+ .endm
+
+#endif /* __PLAT_MACROS_S__ */
diff --git a/plat/qti/common/inc/qti_board_def.h b/plat/qti/common/inc/qti_board_def.h
new file mode 100644
index 0000000..c95e4c0
--- /dev/null
+++ b/plat/qti/common/inc/qti_board_def.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef QTI_BOARD_DEF_H
+#define QTI_BOARD_DEF_H
+
+/*
+ * Required platform porting definitions common to all ARM
+ * development platforms
+ */
+
+/*
+ * Defines used to retrieve QTI SOC Version
+ */
+#define JEDEC_QTI_BKID U(0x0)
+#define JEDEC_QTI_MFID U(0x70)
+#define QTI_SOC_CONTINUATION_SHIFT U(24)
+#define QTI_SOC_IDENTIFICATION_SHIFT U(16)
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE 0x1000
+
+/*
+ * PLAT_QTI_MMAP_ENTRIES depends on the number of entries in the
+ * plat_qti_mmap array defined for each BL stage.
+ */
+#define PLAT_QTI_MMAP_ENTRIES 12
+
+/*
+ * Platform specific page table and MMU setup constants
+ */
+#define MAX_XLAT_TABLES 12
+
+#endif /* QTI_BOARD_DEF_H */
diff --git a/plat/qti/common/inc/qti_cpu.h b/plat/qti/common/inc/qti_cpu.h
new file mode 100644
index 0000000..3316f7b
--- /dev/null
+++ b/plat/qti/common/inc/qti_cpu.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QTI_CPU_H
+#define QTI_CPU_H
+
+/* KRYO-4xx Gold MIDR */
+#define QTI_KRYO4_GOLD_MIDR 0x517F804D
+
+/* KRYO-4xx Silver MIDR */
+#define QTI_KRYO4_SILVER_MIDR 0x517F805D
+
+/* KRYO-6xx Gold MIDR */
+#define QTI_KRYO6_GOLD_MIDR 0x412FD410
+
+/* KRYO-6xx Silver MIDR */
+#define QTI_KRYO6_SILVER_MIDR 0x412FD050
+
+#endif /* QTI_CPU_H */
diff --git a/plat/qti/common/inc/qti_interrupt_svc.h b/plat/qti/common/inc/qti_interrupt_svc.h
new file mode 100644
index 0000000..59bde86
--- /dev/null
+++ b/plat/qti/common/inc/qti_interrupt_svc.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2018,2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QTI_INTERRUPT_SVC_H
+#define QTI_INTERRUPT_SVC_H
+
+int qti_interrupt_svc_init(void);
+
+#endif /* QTI_INTERRUPT_SVC_H */
diff --git a/plat/qti/common/inc/qti_plat.h b/plat/qti/common/inc/qti_plat.h
new file mode 100644
index 0000000..7483c49
--- /dev/null
+++ b/plat/qti/common/inc/qti_plat.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QTI_PLAT_H
+#define QTI_PLAT_H
+
+#include <stdint.h>
+
+#include <common/bl_common.h>
+#include <lib/cassert.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+/*
+ * Utility functions common to QTI platforms
+ */
+int qti_mmap_add_dynamic_region(uintptr_t base_pa, size_t size,
+ unsigned int attr);
+int qti_mmap_remove_dynamic_region(uintptr_t base_va, size_t size);
+
+/*
+ * Utility functions common to ARM standard platforms
+ */
+void qti_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
+ );
+
+/*
+ * Mandatory functions required in ARM standard platforms
+ */
+void plat_qti_gic_driver_init(void);
+void plat_qti_gic_init(void);
+void plat_qti_gic_cpuif_enable(void);
+void plat_qti_gic_cpuif_disable(void);
+void plat_qti_gic_pcpu_init(void);
+
+/*
+ * Optional functions required in ARM standard platforms
+ */
+unsigned int plat_qti_core_pos_by_mpidr(u_register_t mpidr);
+unsigned int plat_qti_my_cluster_pos(void);
+
+void gic_set_spi_routing(unsigned int id, unsigned int irm, u_register_t mpidr);
+
+void qti_pmic_prepare_reset(void);
+void qti_pmic_prepare_shutdown(void);
+
+typedef struct chip_id_info {
+ uint16_t jtag_id;
+ uint16_t chipinfo_id;
+} chip_id_info_t;
+
+#endif /* QTI_PLAT_H */
diff --git a/plat/qti/common/inc/qti_rng.h b/plat/qti/common/inc/qti_rng.h
new file mode 100644
index 0000000..62c31f3
--- /dev/null
+++ b/plat/qti/common/inc/qti_rng.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QTI_RNG_H
+#define QTI_RNG_H
+
+#include <stdint.h>
+
+int qti_rng_get_data(uint8_t *out, uint32_t out_len);
+
+#endif /* QTI_RNG_H */
diff --git a/plat/qti/common/inc/qti_uart_console.h b/plat/qti/common/inc/qti_uart_console.h
new file mode 100644
index 0000000..c5a65d6
--- /dev/null
+++ b/plat/qti/common/inc/qti_uart_console.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018,2020 The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QTI_UART_CONSOLE_H
+#define QTI_UART_CONSOLE_H
+
+#include <drivers/console.h>
+
+#ifndef __ASSEMBLER__
+
+int qti_console_uart_register(console_t *console, uintptr_t uart_base_addr);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* QTI_UART_CONSOLE_H */
diff --git a/plat/qti/common/inc/spmi_arb.h b/plat/qti/common/inc/spmi_arb.h
new file mode 100644
index 0000000..362f740
--- /dev/null
+++ b/plat/qti/common/inc/spmi_arb.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2020, Google LLC. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPMI_ARB_H
+#define SPMI_ARB_H
+
+#include <stdint.h>
+
+/*******************************************************************************
+ * WARNING: This driver does not arbitrate access with the kernel. These APIs
+ * must only be called when the kernel is known to be quiesced (such as before
+ * boot or while the system is shutting down).
+ ******************************************************************************/
+
+/* 32-bit addresses combine (U)SID, PID and register address. */
+
+int spmi_arb_read8(uint32_t addr);
+int spmi_arb_write8(uint32_t addr, uint8_t data);
+
+#endif /* SPMI_ARB_H */
diff --git a/plat/qti/common/src/aarch64/qti_helpers.S b/plat/qti/common/src/aarch64/qti_helpers.S
new file mode 100644
index 0000000..d34b530
--- /dev/null
+++ b/plat/qti/common/src/aarch64/qti_helpers.S
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018,2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/console.h>
+
+#include <platform_def.h>
+
+ .globl plat_my_core_pos
+ .globl plat_qti_core_pos_by_mpidr
+ .globl plat_reset_handler
+ .globl plat_panic_handler
+
+ /* -----------------------------------------------------
+ * unsigned int plat_qti_core_pos_by_mpidr(uint64_t mpidr)
+ * Helper function to calculate the core position.
+ * With this function:
+ * CorePos = (ClusterId * 4) + CoreId
+ * - In ARM v8 (MPIDR_EL1[24]=0)
+ * ClusterId = MPIDR_EL1[15:8]
+ * CoreId = MPIDR_EL1[7:0]
+ * - In ARM v8.1 (MPIDR_EL1[24]=1)
+ * ClusterId = MPIDR_EL1[23:15]
+ * CoreId = MPIDR_EL1[15:8]
+ * Clobbers: x0 & x1.
+ * -----------------------------------------------------
+ */
+func plat_qti_core_pos_by_mpidr
+ mrs x1, mpidr_el1
+ tst x1, #MPIDR_MT_MASK
+ beq plat_qti_core_pos_by_mpidr_no_mt
+ /* Right shift mpidr by one affinity level when MT=1. */
+ lsr x0, x0, #MPIDR_AFFINITY_BITS
+plat_qti_core_pos_by_mpidr_no_mt:
+ and x1, x0, #MPIDR_CPU_MASK
+ and x0, x0, #MPIDR_CLUSTER_MASK
+ add x0, x1, x0, LSR #6
+ ret
+endfunc plat_qti_core_pos_by_mpidr
+
+ /* --------------------------------------------------------------------
+ * void plat_panic_handler(void)
+ * calls SDI and reset system
+ * --------------------------------------------------------------------
+ */
+func plat_panic_handler
+ msr spsel, #0
+ bl plat_set_my_stack
+ b qtiseclib_panic
+endfunc plat_panic_handler
+
+ /* -----------------------------------------------------
+ * unsigned int plat_my_core_pos(void)
+ * This function uses the plat_qti_calc_core_pos()
+ * definition to get the index of the calling CPU
+ * Clobbers: x0 & x1.
+ * -----------------------------------------------------
+ */
+func plat_my_core_pos
+ mrs x0, mpidr_el1
+ b plat_qti_core_pos_by_mpidr
+endfunc plat_my_core_pos
+
+func plat_reset_handler
+ /* save the lr */
+ mov x18, x30
+
+ /* pass cold boot status. */
+ ldr w0, g_qti_bl31_cold_booted
+ /* Execuete CPUSS boot set up on every core. */
+ bl qtiseclib_cpuss_reset_asm
+
+ ret x18
+endfunc plat_reset_handler
diff --git a/plat/qti/common/src/aarch64/qti_kryo4_gold.S b/plat/qti/common/src/aarch64/qti_kryo4_gold.S
new file mode 100644
index 0000000..9bcdf54
--- /dev/null
+++ b/plat/qti/common/src/aarch64/qti_kryo4_gold.S
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cpu_macros.S>
+
+#include <plat_macros.S>
+#include <qti_cpu.h>
+
+ .p2align 3
+
+/* -------------------------------------------------
+ * The CPU Ops reset function for Kryo-3 Gold
+ * -------------------------------------------------
+ */
+func qti_kryo4_gold_reset_func
+#if IMAGE_BL31 && WORKAROUND_CVE_2017_5715
+ adr x0, wa_cve_2017_5715_bpiall_vbar
+ msr vbar_el3, x0
+ isb
+#endif
+
+ mov x19, x30
+
+ bl qtiseclib_kryo4_gold_reset_asm
+ mov x30, x19
+ b cortex_a76_reset_func
+
+endfunc qti_kryo4_gold_reset_func
+
+/* -------------------------------------------------------
+ * The CPU Ops cluster power down function for Kryo-3 Gold
+ * -------------------------------------------------------
+ */
+func qti_kryo4_gold_cluster_pwr_dwn
+ ret
+endfunc qti_kryo4_gold_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Kryo4 Gold. Must follow AAPCS.
+ */
+func qti_kryo4_gold_errata_report
+ /* TODO : Need to add support. Required only for debug bl31 image.*/
+ ret
+endfunc qti_kryo4_gold_errata_report
+#endif
+
+/* ---------------------------------------------
+ * This function provides kryo4_gold 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.qti_kryo4_gold_regs, "aS"
+qti_kryo4_gold_regs: /* The ASCII list of register names to be reported */
+ .asciz ""
+
+func qti_kryo4_gold_cpu_reg_dump
+ adr x6, qti_kryo4_gold_regs
+ ret
+endfunc qti_kryo4_gold_cpu_reg_dump
+
+declare_cpu_ops_wa qti_kryo4_gold, QTI_KRYO4_GOLD_MIDR, \
+ qti_kryo4_gold_reset_func, \
+ CPU_NO_EXTRA1_FUNC, \
+ cortex_a76_disable_wa_cve_2018_3639, \
+ cortex_a76_core_pwr_dwn, \
+ qti_kryo4_gold_cluster_pwr_dwn
diff --git a/plat/qti/common/src/aarch64/qti_kryo4_silver.S b/plat/qti/common/src/aarch64/qti_kryo4_silver.S
new file mode 100644
index 0000000..36374b7
--- /dev/null
+++ b/plat/qti/common/src/aarch64/qti_kryo4_silver.S
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cpu_macros.S>
+
+#include <plat_macros.S>
+#include <qti_cpu.h>
+
+ .p2align 3
+
+/* -------------------------------------------------
+ * The CPU Ops reset function for Kryo-3 Silver
+ * -------------------------------------------------
+ */
+func qti_kryo4_silver_reset_func
+ mov x19, x30
+
+ bl qtiseclib_kryo4_silver_reset_asm
+ mov x30, x19
+ b cortex_a55_reset_func
+
+endfunc qti_kryo4_silver_reset_func
+
+/* ---------------------------------------------------------
+ * The CPU Ops cluster power down function for Kryo-3 Silver
+ * ---------------------------------------------------------
+ */
+func qti_kryo4_silver_cluster_pwr_dwn
+ ret
+endfunc qti_kryo4_silver_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Kryo4 Silver. Must follow AAPCS.
+ */
+func qti_kryo4_silver_errata_report
+ /* TODO : Need to add support. Required only for debug bl31 image.*/
+ ret
+endfunc qti_kryo4_silver_errata_report
+#endif
+
+
+/* ---------------------------------------------
+ * This function provides kryo4_silver 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.qti_kryo4_silver_regs, "aS"
+qti_kryo4_silver_regs: /* The ASCII list of register names to be reported */
+ .asciz ""
+
+func qti_kryo4_silver_cpu_reg_dump
+ adr x6, qti_kryo4_silver_regs
+ ret
+endfunc qti_kryo4_silver_cpu_reg_dump
+
+
+declare_cpu_ops qti_kryo4_silver, QTI_KRYO4_SILVER_MIDR, \
+ qti_kryo4_silver_reset_func, \
+ cortex_a55_core_pwr_dwn, \
+ qti_kryo4_silver_cluster_pwr_dwn
diff --git a/plat/qti/common/src/aarch64/qti_kryo6_gold.S b/plat/qti/common/src/aarch64/qti_kryo6_gold.S
new file mode 100644
index 0000000..577e7ff
--- /dev/null
+++ b/plat/qti/common/src/aarch64/qti_kryo6_gold.S
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015-2018, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cpu_macros.S>
+
+#include <plat_macros.S>
+#include <qti_cpu.h>
+
+ .p2align 3
+
+/* -------------------------------------------------
+ * The CPU Ops reset function for Kryo-3 Gold
+ * -------------------------------------------------
+ */
+func qti_kryo6_gold_reset_func
+#if IMAGE_BL31 && WORKAROUND_CVE_2017_5715
+ adr x0, wa_cve_2017_5715_bpiall_vbar
+ msr vbar_el3, x0
+ isb
+#endif
+
+ mov x19, x30
+
+ bl qtiseclib_kryo6_gold_reset_asm
+ mov x30, x19
+ b cortex_a78_reset_func
+
+endfunc qti_kryo6_gold_reset_func
+
+/* -------------------------------------------------------
+ * The CPU Ops cluster power down function for Kryo-3 Gold
+ * -------------------------------------------------------
+ */
+func qti_kryo6_gold_cluster_pwr_dwn
+ ret
+endfunc qti_kryo6_gold_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Kryo4 Gold. Must follow AAPCS.
+ */
+func qti_kryo6_gold_errata_report
+ /* TODO : Need to add support. Required only for debug bl31 image.*/
+ ret
+endfunc qti_kryo6_gold_errata_report
+#endif
+
+/* ---------------------------------------------
+ * This function provides kryo4_gold 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.qti_kryo4_gold_regs, "aS"
+qti_kryo6_gold_regs: /* The ASCII list of register names to be reported */
+ .asciz ""
+
+func qti_kryo6_gold_cpu_reg_dump
+ adr x6, qti_kryo6_gold_regs
+ ret
+endfunc qti_kryo6_gold_cpu_reg_dump
+
+declare_cpu_ops qti_kryo6_gold, QTI_KRYO6_GOLD_MIDR, \
+ qti_kryo6_gold_reset_func, \
+ cortex_a78_core_pwr_dwn, \
+ qti_kryo6_gold_cluster_pwr_dwn
diff --git a/plat/qti/common/src/aarch64/qti_kryo6_silver.S b/plat/qti/common/src/aarch64/qti_kryo6_silver.S
new file mode 100644
index 0000000..6ad0bca
--- /dev/null
+++ b/plat/qti/common/src/aarch64/qti_kryo6_silver.S
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015-2018, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cpu_macros.S>
+
+#include <plat_macros.S>
+#include <qti_cpu.h>
+
+ .p2align 3
+
+/* -------------------------------------------------
+ * The CPU Ops reset function for Kryo-3 Silver
+ * -------------------------------------------------
+ */
+func qti_kryo6_silver_reset_func
+ mov x19, x30
+
+ bl qtiseclib_kryo6_silver_reset_asm
+ mov x30, x19
+ b cortex_a55_reset_func
+
+endfunc qti_kryo6_silver_reset_func
+
+/* ---------------------------------------------------------
+ * The CPU Ops cluster power down function for Kryo-3 Silver
+ * ---------------------------------------------------------
+ */
+func qti_kryo6_silver_cluster_pwr_dwn
+ ret
+endfunc qti_kryo6_silver_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Kryo4 Silver. Must follow AAPCS.
+ */
+func qti_kryo6_silver_errata_report
+ /* TODO : Need to add support. Required only for debug bl31 image.*/
+ ret
+endfunc qti_kryo6_silver_errata_report
+#endif
+
+
+/* ---------------------------------------------
+ * This function provides kryo4_silver 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.qti_kryo4_silver_regs, "aS"
+qti_kryo6_silver_regs: /* The ASCII list of register names to be reported */
+ .asciz ""
+
+func qti_kryo6_silver_cpu_reg_dump
+ adr x6, qti_kryo6_silver_regs
+ ret
+endfunc qti_kryo6_silver_cpu_reg_dump
+
+
+declare_cpu_ops qti_kryo6_silver, QTI_KRYO6_SILVER_MIDR, \
+ qti_kryo6_silver_reset_func, \
+ cortex_a55_core_pwr_dwn, \
+ qti_kryo6_silver_cluster_pwr_dwn
diff --git a/plat/qti/common/src/aarch64/qti_uart_console.S b/plat/qti/common/src/aarch64/qti_uart_console.S
new file mode 100644
index 0000000..2eb33d9
--- /dev/null
+++ b/plat/qti/common/src/aarch64/qti_uart_console.S
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018,2020 The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <console_macros.S>
+
+#include <platform_def.h>
+#include <qti_uart_console.h>
+
+/*
+ * This driver implements console logging into a ring buffer.
+ */
+
+ .globl qti_console_uart_register
+
+ /* -----------------------------------------------
+ * int qti_console_uart_register(console_t *console,
+ * uintptr_t uart_base_addr)
+ * Registers uart console instance.
+ * In: x0 - pointer to empty console_t struct
+ * x1 - start address of uart block.
+ * Out: x0 - 1 to indicate success
+ * Clobber list: x0, x1, x14
+ * -----------------------------------------------
+ */
+func qti_console_uart_register
+ str x1, [x0, #CONSOLE_T_BASE] /* Save UART base. */
+ finish_console_register uart putc=1, flush=1
+endfunc qti_console_uart_register
+
+ /* -----------------------------------------------
+ * int qti_console_uart_puts(int c, console_t *console)
+ * Writes a character to the UART console.
+ * The character must be preserved in x0.
+ * In: x0 - character to be stored
+ * x1 - pointer to console_t struct
+ * Clobber list: x1, x2
+ * -----------------------------------------------
+ */
+func console_uart_putc
+ /* set x1 = UART base. */
+ ldr x1, [x1, #CONSOLE_T_BASE]
+
+ /* Loop until M_GENI_CMD_ACTIVE bit not clear. */
+1: ldr w2, [x1, #GENI_STATUS_REG]
+ and w2, w2, #GENI_STATUS_M_GENI_CMD_ACTIVE_MASK
+ cmp w2, #GENI_STATUS_M_GENI_CMD_ACTIVE_MASK
+ b.eq 1b
+
+ /* Transmit data. */
+ cmp w0, #0xA
+ b.ne 3f
+
+ /* Add '\r' when input char is '\n' */
+ mov w2, #0x1
+ mov w0, #0xD
+ str w2, [x1, #UART_TX_TRANS_LEN_REG]
+ mov w2, #GENI_M_CMD_TX
+ str w2, [x1, #GENI_M_CMD0_REG]
+ str w0, [x1, #GENI_TX_FIFOn_REG]
+ mov w0, #0xA
+
+ /* Loop until M_GENI_CMD_ACTIVE bit not clear. */
+2: ldr w2, [x1, #GENI_STATUS_REG]
+ and w2, w2, #GENI_STATUS_M_GENI_CMD_ACTIVE_MASK
+ cmp w2, #GENI_STATUS_M_GENI_CMD_ACTIVE_MASK
+ b.eq 2b
+
+ /* Transmit i/p data. */
+3: mov w2, #0x1
+ str w2, [x1, #UART_TX_TRANS_LEN_REG]
+ mov w2, #GENI_M_CMD_TX
+ str w2, [x1, #GENI_M_CMD0_REG]
+ str w0, [x1, #GENI_TX_FIFOn_REG]
+
+ ret
+endfunc console_uart_putc
+
+ /* -----------------------------------------------
+ * int qti_console_uart_flush(console_t *console)
+ * In: x0 - pointer to console_t struct
+ * Out: x0 - 0 for success
+ * Clobber list: x0, x1
+ * -----------------------------------------------
+ */
+func console_uart_flush
+ /* set x0 = UART base. */
+ ldr x0, [x0, #CONSOLE_T_BASE]
+
+ /* Loop until M_GENI_CMD_ACTIVE bit not clear. */
+1: ldr w1, [x0, #GENI_STATUS_REG]
+ and w1, w1, #GENI_STATUS_M_GENI_CMD_ACTIVE_MASK
+ cmp w1, #GENI_STATUS_M_GENI_CMD_ACTIVE_MASK
+ b.eq 1b
+
+ mov w0, #0
+ ret
+endfunc console_uart_flush
diff --git a/plat/qti/common/src/pm_ps_hold.c b/plat/qti/common/src/pm_ps_hold.c
new file mode 100644
index 0000000..208345c
--- /dev/null
+++ b/plat/qti/common/src/pm_ps_hold.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2020, Google LLC. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/delay_timer.h>
+
+#include <qti_plat.h>
+#include <spmi_arb.h>
+
+/*
+ * This driver implements PON support for PM8998-compatible PMICs. This can
+ * include other part numbers like PM6150.
+ */
+
+#define RESET_TYPE_WARM_RESET 1
+#define RESET_TYPE_SHUTDOWN 4
+
+#define S2_RESET_EN BIT(7)
+
+static void configure_ps_hold(uint32_t reset_type)
+{
+ /* QTI recommends disabling reset for 10 cycles before reconfiguring. */
+ spmi_arb_write8(PON_PS_HOLD_RESET_CTL2, 0);
+ mdelay(1);
+
+ spmi_arb_write8(PON_PS_HOLD_RESET_CTL, reset_type);
+ spmi_arb_write8(PON_PS_HOLD_RESET_CTL2, S2_RESET_EN);
+ mdelay(1);
+}
+
+void qti_pmic_prepare_reset(void)
+{
+ configure_ps_hold(RESET_TYPE_WARM_RESET);
+}
+
+void qti_pmic_prepare_shutdown(void)
+{
+ configure_ps_hold(RESET_TYPE_SHUTDOWN);
+}
diff --git a/plat/qti/common/src/qti_bl31_setup.c b/plat/qti/common/src/qti_bl31_setup.c
new file mode 100644
index 0000000..dac0253
--- /dev/null
+++ b/plat/qti/common/src/qti_bl31_setup.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <bl31/bl31.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/bl_aux_params/bl_aux_params.h>
+#include <lib/coreboot.h>
+#include <lib/spinlock.h>
+
+#include <platform.h>
+#include <qti_interrupt_svc.h>
+#include <qti_plat.h>
+#include <qti_uart_console.h>
+#include <qtiseclib_interface.h>
+
+/*
+ * Placeholder variables for copying the arguments that have been passed to
+ * BL31 from BL2.
+ */
+static entry_point_info_t bl33_image_ep_info;
+
+/*
+ * Variable to hold counter frequency for the CPU's generic timer. In this
+ * platform coreboot image configure counter frequency for boot core before
+ * reaching TF-A.
+ */
+static uint64_t g_qti_cpu_cntfrq;
+
+/*
+ * Variable to hold bl31 cold boot status. Default value 0x0 means yet to boot.
+ * Any other value means cold booted.
+ */
+uint32_t g_qti_bl31_cold_booted;
+
+/*******************************************************************************
+ * 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 & 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_setup(u_register_t from_bl2,
+ u_register_t plat_params_from_bl2)
+{
+
+ g_qti_cpu_cntfrq = read_cntfrq_el0();
+
+ bl_aux_params_parse(plat_params_from_bl2, NULL);
+
+#if COREBOOT
+ if (coreboot_serial.baseaddr != 0) {
+ static console_t g_qti_console_uart;
+
+ qti_console_uart_register(&g_qti_console_uart,
+ coreboot_serial.baseaddr);
+ }
+#endif
+
+ /*
+ * Tell BL31 where the non-trusted software image
+ * is located and the entry state information
+ */
+ bl31_params_parse_helper(from_bl2, NULL, &bl33_image_ep_info);
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3)
+{
+ bl31_early_platform_setup(arg0, arg1);
+}
+
+/*******************************************************************************
+ * 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)
+{
+ qti_setup_page_tables(
+ BL31_START,
+ BL31_END-BL31_START,
+ BL_CODE_BASE,
+ BL_CODE_END,
+ BL_RO_DATA_BASE,
+ BL_RO_DATA_END
+ );
+ enable_mmu_el3(0);
+}
+
+/*******************************************************************************
+ * Perform any BL31 platform setup common to ARM standard platforms
+ ******************************************************************************/
+void bl31_platform_setup(void)
+{
+ generic_delay_timer_init();
+ /* Initialize the GIC driver, CPU and distributor interfaces */
+ plat_qti_gic_driver_init();
+ plat_qti_gic_init();
+ qti_interrupt_svc_init();
+ qtiseclib_bl31_platform_setup();
+
+ /* set boot state to cold boot complete. */
+ g_qti_bl31_cold_booted = 0x1;
+}
+
+/*******************************************************************************
+ * 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)
+{
+ /* QTI platform don't have BL32 implementation. */
+ assert(type == NON_SECURE);
+ assert(bl33_image_ep_info.h.type == PARAM_EP);
+ assert(bl33_image_ep_info.h.attr == NON_SECURE);
+ /*
+ * None of the images on the platforms can have 0x0
+ * as the entrypoint.
+ */
+ if (bl33_image_ep_info.pc) {
+ return &bl33_image_ep_info;
+ } else {
+ return NULL;
+ }
+}
+
+/*******************************************************************************
+ * 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. This will be used later in warm boot (psci_arch_setup)
+ * of CPUs to set when CPU frequency.
+ ******************************************************************************/
+unsigned int plat_get_syscnt_freq2(void)
+{
+ assert(g_qti_cpu_cntfrq != 0);
+ return g_qti_cpu_cntfrq;
+}
diff --git a/plat/qti/common/src/qti_common.c b/plat/qti/common/src/qti_common.c
new file mode 100644
index 0000000..74ccb5b
--- /dev/null
+++ b/plat/qti/common/src/qti_common.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/smccc.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <services/arm_arch_svc.h>
+
+#include <platform_def.h>
+#include <qti_map_chipinfo.h>
+#include <qti_plat.h>
+#include <qtiseclib_interface.h>
+
+/*
+ * Table of regions for various BL stages to map using the MMU.
+ * This doesn't include TZRAM as the 'mem_layout' argument passed to
+ * qti_configure_mmu_elx() will give the available subset of that,
+ */
+
+const mmap_region_t plat_qti_mmap[] = {
+ MAP_REGION_FLAT(QTI_DEVICE_BASE, QTI_DEVICE_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(QTI_AOP_CMD_DB_BASE, QTI_AOP_CMD_DB_SIZE,
+ MT_NS | MT_RO | MT_EXECUTE_NEVER),
+ {0}
+};
+
+CASSERT(ARRAY_SIZE(plat_qti_mmap) <= MAX_MMAP_REGIONS, assert_max_mmap_regions);
+
+
+bool qti_is_overlap_atf_rg(unsigned long long addr, size_t size)
+{
+ if (addr > addr + size
+ || (BL31_BASE < addr + size && BL31_LIMIT > addr)) {
+ return true;
+ }
+ return false;
+}
+
+/*
+ * unsigned int plat_qti_my_cluster_pos(void)
+ * definition to get the cluster index of the calling CPU.
+ * - In ARM v8 (MPIDR_EL1[24]=0)
+ * ClusterId = MPIDR_EL1[15:8]
+ * - In ARM v8.1 & Later version (MPIDR_EL1[24]=1)
+ * ClusterId = MPIDR_EL1[23:15]
+ */
+unsigned int plat_qti_my_cluster_pos(void)
+{
+ unsigned int mpidr, cluster_id;
+
+ mpidr = read_mpidr_el1();
+ if ((mpidr & MPIDR_MT_MASK) == 0) { /* MT not supported */
+ cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+ } else { /* MT supported */
+ cluster_id = (mpidr >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK;
+ }
+ assert(cluster_id < PLAT_CLUSTER_COUNT);
+ return cluster_id;
+}
+
+/*
+ * 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 qti_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
+ )
+{
+ /*
+ * 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);
+
+ /* Now (re-)map the platform-specific memory regions */
+ mmap_add(plat_qti_mmap);
+
+ /* Create the page tables to reflect the above mappings */
+ init_xlat_tables();
+}
+
+static inline void qti_align_mem_region(uintptr_t addr, size_t size,
+ uintptr_t *aligned_addr,
+ size_t *aligned_size)
+{
+ *aligned_addr = round_down(addr, PAGE_SIZE);
+ *aligned_size = round_up(addr - *aligned_addr + size, PAGE_SIZE);
+}
+
+int qti_mmap_add_dynamic_region(uintptr_t base_pa, size_t size,
+ unsigned int attr)
+{
+ uintptr_t aligned_pa;
+ size_t aligned_size;
+
+ qti_align_mem_region(base_pa, size, &aligned_pa, &aligned_size);
+
+ if (qti_is_overlap_atf_rg(base_pa, size)) {
+ /* Memory shouldn't overlap with TF-A range. */
+ return -EPERM;
+ }
+
+ return mmap_add_dynamic_region(aligned_pa, aligned_pa, aligned_size,
+ attr);
+}
+
+int qti_mmap_remove_dynamic_region(uintptr_t base_va, size_t size)
+{
+ qti_align_mem_region(base_va, size, &base_va, &size);
+ return mmap_remove_dynamic_region(base_va, size);
+}
+
+/*
+ * This function returns soc version which mainly consist of below fields
+ *
+ * soc_version[30:24] = JEP-106 continuation code for the SiP
+ * soc_version[23:16] = JEP-106 identification code with parity bit for the SiP
+ * soc_version[0:15] = Implementation defined SoC ID
+ */
+int32_t plat_get_soc_version(void)
+{
+ int i = 0;
+ /* Variant other than in mapped g_map_jtag_chipinfo_id variable will have
+ * default chipinfo id as 0xFFFF
+ */
+ uint32_t soc_version = (QTI_DEFAULT_CHIPINFO_ID & QTI_SOC_VERSION_MASK);
+ uint32_t jep106az_code = (JEDEC_QTI_BKID << QTI_SOC_CONTINUATION_SHIFT)
+ | (JEDEC_QTI_MFID << QTI_SOC_IDENTIFICATION_SHIFT);
+ uint32_t jtag_id = mmio_read_32(QTI_JTAG_ID_REG);
+ uint32_t jtag_id_val = (jtag_id >> QTI_JTAG_ID_SHIFT)
+ & QTI_SOC_VERSION_MASK;
+
+ for (i = 0; i < ARRAY_SIZE(g_map_jtag_chipinfo_id); i++) {
+ if (g_map_jtag_chipinfo_id[i].jtag_id == jtag_id_val)
+ soc_version = g_map_jtag_chipinfo_id[i].chipinfo_id
+ & QTI_SOC_VERSION_MASK;
+ }
+ return (int32_t)(jep106az_code | (soc_version));
+}
+
+/*
+ * This function returns soc revision in below format
+ *
+ * soc_revision[0:30] = SOC revision of specific SOC
+ */
+int32_t plat_get_soc_revision(void)
+{
+ return mmio_read_32(QTI_SOC_REVISION_REG) & QTI_SOC_REVISION_MASK;
+}
+
+/*****************************************************************************
+ * plat_is_smccc_feature_available() - This function checks whether SMCCC feature
+ * is availabile for the platform or not.
+ * @fid: SMCCC function id
+ *
+ * Return SMC_ARCH_CALL_SUCCESS if SMCCC feature is available and
+ * SMC_ARCH_CALL_NOT_SUPPORTED otherwise.
+ *****************************************************************************/
+int32_t plat_is_smccc_feature_available(u_register_t fid)
+{
+ switch (fid) {
+ case SMCCC_ARCH_SOC_ID:
+ return SMC_ARCH_CALL_SUCCESS;
+ default:
+ return SMC_ARCH_CALL_NOT_SUPPORTED;
+ }
+}
diff --git a/plat/qti/common/src/qti_gic_v3.c b/plat/qti/common/src/qti_gic_v3.c
new file mode 100644
index 0000000..f00267a
--- /dev/null
+++ b/plat/qti/common/src/qti_gic_v3.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <drivers/arm/gicv3.h>
+
+#include <platform.h>
+#include <platform_def.h>
+#include <qti_plat.h>
+#include <qtiseclib_defs.h>
+#include <qtiseclib_defs_plat.h>
+
+/* The GICv3 driver only needs to be initialized in EL3 */
+static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+/* Array of interrupts to be configured by the gic driver */
+static const interrupt_prop_t qti_interrupt_props[] = {
+ INTR_PROP_DESC(QTISECLIB_INT_ID_CPU_WAKEUP_SGI,
+ GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+ INTR_PROP_DESC(QTISECLIB_INT_ID_RESET_SGI, GIC_HIGHEST_SEC_PRIORITY,
+ INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+ INTR_PROP_DESC(QTISECLIB_INT_ID_SEC_WDOG_BARK, GIC_HIGHEST_SEC_PRIORITY,
+ INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+ INTR_PROP_DESC(QTISECLIB_INT_ID_NON_SEC_WDOG_BITE,
+ GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+ GIC_INTR_CFG_LEVEL),
+ INTR_PROP_DESC(QTISECLIB_INT_ID_VMIDMT_ERR_CLT_SEC,
+ GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+ INTR_PROP_DESC(QTISECLIB_INT_ID_VMIDMT_ERR_CLT_NONSEC,
+ GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+ INTR_PROP_DESC(QTISECLIB_INT_ID_VMIDMT_ERR_CFG_SEC,
+ GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+ INTR_PROP_DESC(QTISECLIB_INT_ID_VMIDMT_ERR_CFG_NONSEC,
+ GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+ INTR_PROP_DESC(QTISECLIB_INT_ID_XPU_SEC, GIC_HIGHEST_SEC_PRIORITY,
+ INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+ INTR_PROP_DESC(QTISECLIB_INT_ID_XPU_NON_SEC, GIC_HIGHEST_SEC_PRIORITY,
+ INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+#ifdef QTISECLIB_INT_ID_A1_NOC_ERROR
+ INTR_PROP_DESC(QTISECLIB_INT_ID_A1_NOC_ERROR, GIC_HIGHEST_SEC_PRIORITY,
+ INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+#endif
+ INTR_PROP_DESC(QTISECLIB_INT_ID_A2_NOC_ERROR, GIC_HIGHEST_SEC_PRIORITY,
+ INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+ INTR_PROP_DESC(QTISECLIB_INT_ID_CONFIG_NOC_ERROR,
+ GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+ INTR_PROP_DESC(QTISECLIB_INT_ID_DC_NOC_ERROR, GIC_HIGHEST_SEC_PRIORITY,
+ INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+ INTR_PROP_DESC(QTISECLIB_INT_ID_MEM_NOC_ERROR, GIC_HIGHEST_SEC_PRIORITY,
+ INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+ INTR_PROP_DESC(QTISECLIB_INT_ID_SYSTEM_NOC_ERROR,
+ GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+ INTR_PROP_DESC(QTISECLIB_INT_ID_MMSS_NOC_ERROR,
+ GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+#ifdef QTISECLIB_INT_ID_LPASS_AGNOC_ERROR
+ INTR_PROP_DESC(QTISECLIB_INT_ID_LPASS_AGNOC_ERROR, GIC_HIGHEST_SEC_PRIORITY,
+ INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+#endif
+#ifdef QTISECLIB_INT_ID_NSP_NOC_ERROR
+ INTR_PROP_DESC(QTISECLIB_INT_ID_NSP_NOC_ERROR, GIC_HIGHEST_SEC_PRIORITY,
+ INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+#endif
+};
+
+const gicv3_driver_data_t qti_gic_data = {
+ .gicd_base = QTI_GICD_BASE,
+ .gicr_base = QTI_GICR_BASE,
+ .interrupt_props = qti_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(qti_interrupt_props),
+ .rdistif_num = PLATFORM_CORE_COUNT,
+ .rdistif_base_addrs = rdistif_base_addrs,
+ .mpidr_to_core_pos = plat_qti_core_pos_by_mpidr
+};
+
+void plat_qti_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.
+ */
+ gicv3_driver_init(&qti_gic_data);
+}
+
+/******************************************************************************
+ * ARM common helper to initialize the GIC. Only invoked by BL31
+ *****************************************************************************/
+void plat_qti_gic_init(void)
+{
+ unsigned int i;
+
+ gicv3_distif_init();
+ gicv3_rdistif_init(plat_my_core_pos());
+ gicv3_cpuif_enable(plat_my_core_pos());
+
+ /* Route secure spi interrupt to ANY. */
+ for (i = 0; i < ARRAY_SIZE(qti_interrupt_props); i++) {
+ unsigned int int_id = qti_interrupt_props[i].intr_num;
+
+ if (plat_ic_is_spi(int_id)) {
+ gicv3_set_spi_routing(int_id, GICV3_IRM_ANY, 0x0);
+ }
+ }
+}
+
+void gic_set_spi_routing(unsigned int id, unsigned int irm, u_register_t target)
+{
+ gicv3_set_spi_routing(id, irm, target);
+}
+
+/******************************************************************************
+ * ARM common helper to enable the GIC CPU interface
+ *****************************************************************************/
+void plat_qti_gic_cpuif_enable(void)
+{
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * ARM common helper to disable the GIC CPU interface
+ *****************************************************************************/
+void plat_qti_gic_cpuif_disable(void)
+{
+ gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * ARM common helper to initialize the per-CPU redistributor interface in GICv3
+ *****************************************************************************/
+void plat_qti_gic_pcpu_init(void)
+{
+ gicv3_rdistif_init(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * ARM common helpers to power GIC redistributor interface
+ *****************************************************************************/
+void plat_qti_gic_redistif_on(void)
+{
+ gicv3_rdistif_on(plat_my_core_pos());
+}
+
+void plat_qti_gic_redistif_off(void)
+{
+ gicv3_rdistif_off(plat_my_core_pos());
+}
diff --git a/plat/qti/common/src/qti_interrupt_svc.c b/plat/qti/common/src/qti_interrupt_svc.c
new file mode 100644
index 0000000..3017dc7
--- /dev/null
+++ b/plat/qti/common/src/qti_interrupt_svc.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018,2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <bl31/interrupt_mgmt.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/el3_runtime/context_mgmt.h>
+
+#include <platform.h>
+#include <qti_interrupt_svc.h>
+#include <qtiseclib_interface.h>
+
+#define QTI_INTR_INVALID_INT_NUM 0xFFFFFFFFU
+
+/*
+ * Top-level EL3 interrupt handler.
+ */
+static uint64_t qti_el3_interrupt_handler(uint32_t id, uint32_t flags,
+ void *handle, void *cookie)
+{
+ uint32_t irq = QTI_INTR_INVALID_INT_NUM;
+
+ /*
+ * EL3 non-interruptible. Interrupt shouldn't occur when we are at
+ * EL3 / Secure.
+ */
+ assert(handle != cm_get_context(SECURE));
+
+ irq = plat_ic_acknowledge_interrupt();
+
+ qtiseclib_invoke_isr(irq, handle);
+
+ /* End of Interrupt. */
+ if (irq < 1022U) {
+ plat_ic_end_of_interrupt(irq);
+ }
+
+ return (uint64_t) handle;
+}
+
+int qti_interrupt_svc_init(void)
+{
+ int ret;
+ uint64_t flags = 0U;
+
+ /*
+ * Route EL3 interrupts to EL3 when in Non-secure.
+ * Note: EL3 won't have interrupt enable
+ * & we don't have S-EL1 support.
+ */
+ 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,
+ qti_el3_interrupt_handler, flags);
+ assert(ret == 0);
+
+ return ret;
+}
diff --git a/plat/qti/common/src/qti_pm.c b/plat/qti/common/src/qti_pm.c
new file mode 100644
index 0000000..5f1b7aa
--- /dev/null
+++ b/plat/qti/common/src/qti_pm.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018, 2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <platform.h>
+#include <platform_def.h>
+#include <qti_cpu.h>
+#include <qti_plat.h>
+#include <qtiseclib_cb_interface.h>
+#include <qtiseclib_defs_plat.h>
+#include <qtiseclib_interface.h>
+
+#define QTI_LOCAL_PSTATE_WIDTH 4
+#define QTI_LOCAL_PSTATE_MASK ((1 << QTI_LOCAL_PSTATE_WIDTH) - 1)
+
+/* Make composite power state parameter till level 0 */
+#define qti_make_pwrstate_lvl0(lvl0_state, type) \
+ (((lvl0_state) << PSTATE_ID_SHIFT) | ((type) << PSTATE_TYPE_SHIFT))
+
+/* Make composite power state parameter till level 1 */
+#define qti_make_pwrstate_lvl1(lvl1_state, lvl0_state, type) \
+ (((lvl1_state) << QTI_LOCAL_PSTATE_WIDTH) | \
+ qti_make_pwrstate_lvl0(lvl0_state, type))
+
+/* Make composite power state parameter till level 2 */
+#define qti_make_pwrstate_lvl2(lvl2_state, lvl1_state, lvl0_state, type) \
+ (((lvl2_state) << (QTI_LOCAL_PSTATE_WIDTH * 2)) | \
+ qti_make_pwrstate_lvl1(lvl1_state, lvl0_state, type))
+
+/* Make composite power state parameter till level 3 */
+#define qti_make_pwrstate_lvl3(lvl3_state, lvl2_state, lvl1_state, lvl0_state, type) \
+ (((lvl3_state) << (QTI_LOCAL_PSTATE_WIDTH * 3)) | \
+ qti_make_pwrstate_lvl2(lvl2_state, lvl1_state, lvl0_state, type))
+
+/* QTI_CORE_PWRDN_EN_MASK happens to be same across all CPUs */
+#define QTI_CORE_PWRDN_EN_MASK 1
+
+/* cpu power control happens to be same across all CPUs */
+_DEFINE_SYSREG_WRITE_FUNC(cpu_pwrctrl_val, S3_0_C15_C2_7)
+_DEFINE_SYSREG_READ_FUNC(cpu_pwrctrl_val, S3_0_C15_C2_7)
+
+const unsigned int qti_pm_idle_states[] = {
+ qti_make_pwrstate_lvl0(QTI_LOCAL_STATE_OFF,
+ PSTATE_TYPE_POWERDOWN),
+ qti_make_pwrstate_lvl0(QTI_LOCAL_STATE_DEEPOFF,
+ PSTATE_TYPE_POWERDOWN),
+ qti_make_pwrstate_lvl1(QTI_LOCAL_STATE_DEEPOFF,
+ QTI_LOCAL_STATE_DEEPOFF,
+ PSTATE_TYPE_POWERDOWN),
+ qti_make_pwrstate_lvl2(QTI_LOCAL_STATE_OFF,
+ QTI_LOCAL_STATE_DEEPOFF,
+ QTI_LOCAL_STATE_DEEPOFF,
+ PSTATE_TYPE_POWERDOWN),
+ qti_make_pwrstate_lvl3(QTI_LOCAL_STATE_OFF,
+ QTI_LOCAL_STATE_DEEPOFF,
+ QTI_LOCAL_STATE_DEEPOFF,
+ QTI_LOCAL_STATE_DEEPOFF,
+ PSTATE_TYPE_POWERDOWN),
+ 0,
+};
+
+/*******************************************************************************
+ * QTI 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 qti_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; !!qti_pm_idle_states[i]; i++) {
+ if (power_state == qti_pm_idle_states[i])
+ break;
+ }
+
+ /* Return error if entry not found in the idle state array */
+ if (!qti_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 &
+ QTI_LOCAL_PSTATE_MASK;
+ state_id >>= QTI_LOCAL_PSTATE_WIDTH;
+ }
+
+ return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * PLATFORM FUNCTIONS
+ ******************************************************************************/
+
+static void qti_set_cpupwrctlr_val(void)
+{
+ unsigned long val;
+
+ val = read_cpu_pwrctrl_val();
+ val |= QTI_CORE_PWRDN_EN_MASK;
+ write_cpu_pwrctrl_val(val);
+
+ isb();
+}
+
+/**
+ * CPU power on function - ideally we want a wrapper since this function is
+ * target specific. But to unblock teams.
+ */
+static int qti_cpu_power_on(u_register_t mpidr)
+{
+ int core_pos = plat_core_pos_by_mpidr(mpidr);
+
+ /* If not valid mpidr, return error */
+ if (core_pos < 0 || core_pos >= QTISECLIB_PLAT_CORE_COUNT) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ return qtiseclib_psci_node_power_on(mpidr);
+}
+
+static bool is_cpu_off(const psci_power_state_t *target_state)
+{
+ if ((target_state->pwr_domain_state[QTI_PWR_LVL0] ==
+ QTI_LOCAL_STATE_OFF) ||
+ (target_state->pwr_domain_state[QTI_PWR_LVL0] ==
+ QTI_LOCAL_STATE_DEEPOFF)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static void qti_cpu_power_on_finish(const psci_power_state_t *target_state)
+{
+ const uint8_t *pwr_states =
+ (const uint8_t *)target_state->pwr_domain_state;
+ qtiseclib_psci_node_on_finish(pwr_states);
+
+ if (is_cpu_off(target_state)) {
+ plat_qti_gic_cpuif_enable();
+ }
+}
+
+static void qti_cpu_standby(plat_local_state_t cpu_state)
+{
+}
+
+static void qti_node_power_off(const psci_power_state_t *target_state)
+{
+ qtiseclib_psci_node_power_off((const uint8_t *)
+ target_state->pwr_domain_state);
+ if (is_cpu_off(target_state)) {
+ plat_qti_gic_cpuif_disable();
+ qti_set_cpupwrctlr_val();
+ }
+}
+
+static void qti_node_suspend(const psci_power_state_t *target_state)
+{
+ qtiseclib_psci_node_suspend((const uint8_t *)target_state->
+ pwr_domain_state);
+ if (is_cpu_off(target_state)) {
+ plat_qti_gic_cpuif_disable();
+ qti_set_cpupwrctlr_val();
+ }
+}
+
+static void qti_node_suspend_finish(const psci_power_state_t *target_state)
+{
+ const uint8_t *pwr_states =
+ (const uint8_t *)target_state->pwr_domain_state;
+ qtiseclib_psci_node_suspend_finish(pwr_states);
+ if (is_cpu_off(target_state)) {
+ plat_qti_gic_cpuif_enable();
+ }
+}
+
+__dead2 void qti_domain_power_down_wfi(const psci_power_state_t *target_state)
+{
+
+ /* For now just do WFI - add any target specific handling if needed */
+ psci_power_down_wfi();
+ /* We should never reach here */
+}
+
+static __dead2 void assert_ps_hold(void)
+{
+ mmio_write_32(QTI_PS_HOLD_REG, 0);
+ mdelay(1000);
+
+ /* Should be dead before reaching this. */
+ panic();
+}
+
+__dead2 void qti_system_off(void)
+{
+ qti_pmic_prepare_shutdown();
+ assert_ps_hold();
+}
+
+__dead2 void qti_system_reset(void)
+{
+ qti_pmic_prepare_reset();
+ assert_ps_hold();
+}
+
+void qti_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+ int i = 0;
+ unsigned int state_id, power_state;
+ int size = ARRAY_SIZE(qti_pm_idle_states);
+
+ /*
+ * Find deepest state.
+ * The arm_pm_idle_states[] array has last element by default 0,
+ * so the real deepest state is second last element of that array.
+ */
+ power_state = qti_pm_idle_states[size - 2];
+ 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 & QTI_LOCAL_PSTATE_MASK;
+ state_id >>= QTI_LOCAL_PSTATE_WIDTH;
+ }
+}
+
+/*
+ * Structure containing platform specific PSCI operations. Common
+ * PSCI layer will use this.
+ */
+const plat_psci_ops_t plat_qti_psci_pm_ops = {
+ .pwr_domain_on = qti_cpu_power_on,
+ .pwr_domain_on_finish = qti_cpu_power_on_finish,
+ .cpu_standby = qti_cpu_standby,
+ .pwr_domain_off = qti_node_power_off,
+ .pwr_domain_suspend = qti_node_suspend,
+ .pwr_domain_suspend_finish = qti_node_suspend_finish,
+ .pwr_domain_pwr_down_wfi = qti_domain_power_down_wfi,
+ .system_off = qti_system_off,
+ .system_reset = qti_system_reset,
+ .get_node_hw_state = NULL,
+ .translate_power_state_by_mpidr = NULL,
+ .get_sys_suspend_power_state = qti_get_sys_suspend_power_state,
+ .validate_power_state = qti_validate_power_state,
+};
+
+/**
+ * The QTI 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)
+{
+ int err;
+
+ err = qtiseclib_psci_init((uintptr_t)bl31_warm_entrypoint);
+ if (err == PSCI_E_SUCCESS) {
+ *psci_ops = &plat_qti_psci_pm_ops;
+ }
+
+ return err;
+}
diff --git a/plat/qti/common/src/qti_rng.c b/plat/qti/common/src/qti_rng.c
new file mode 100644
index 0000000..f63f3b8
--- /dev/null
+++ b/plat/qti/common/src/qti_rng.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stddef.h>
+
+#include <lib/mmio.h>
+
+#include <qti_rng.h>
+#include <qti_rng_io.h>
+
+int qti_rng_get_data(uint8_t *out, uint32_t out_len)
+{
+ uint32_t tmp_rndm = 0;
+ uint32_t bytes_left = out_len;
+ int i = 0;
+
+ if (NULL == out || 0 == out_len) {
+ return -1;
+ }
+
+ /*
+ * RNG HW initialized at previous boot image.
+ * RNG clocks are expected to be ON.
+ */
+
+ do {
+ /* There is no data to read */
+ if ((mmio_read_32(SEC_PRNG_STATUS) &
+ SEC_PRNG_STATUS_DATA_AVAIL_BMSK) == 0) {
+ continue;
+ }
+
+ while ((tmp_rndm = mmio_read_32(SEC_PRNG_DATA_OUT)) == 0) {
+ ;
+ }
+
+ for (i = 0; i < 4; i++) {
+ *out = (uint8_t) (tmp_rndm >> (8 * i));
+
+ out++;
+ bytes_left--;
+
+ if (bytes_left == 0) {
+ break;
+ }
+ }
+
+ } while (bytes_left != 0);
+
+ return 0;
+}
diff --git a/plat/qti/common/src/qti_stack_protector.c b/plat/qti/common/src/qti_stack_protector.c
new file mode 100644
index 0000000..572830f
--- /dev/null
+++ b/plat/qti/common/src/qti_stack_protector.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <platform.h>
+#include <platform_def.h>
+#include <qti_rng.h>
+#include <qtiseclib_interface.h>
+
+u_register_t plat_get_stack_protector_canary(void)
+{
+ u_register_t random = 0x0;
+
+ /*
+ * get random data , the below API doesn't return random = 0 on success
+ */
+ qti_rng_get_data((uint8_t *) &random, sizeof(random));
+ assert(random != 0x0);
+
+ return random;
+}
diff --git a/plat/qti/common/src/qti_syscall.c b/plat/qti/common/src/qti_syscall.c
new file mode 100644
index 0000000..d8e5be9
--- /dev/null
+++ b/plat/qti/common/src/qti_syscall.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <context.h>
+#include <lib/coreboot.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <smccc_helpers.h>
+#include <tools_share/uuid.h>
+
+#include <qti_plat.h>
+#include <qti_secure_io_cfg.h>
+#include <qtiseclib_interface.h>
+
+/*
+ * SIP service - SMC function IDs for SiP Service queries
+ *
+ */
+#define QTI_SIP_SVC_CALL_COUNT_ID U(0x0200ff00)
+#define QTI_SIP_SVC_UID_ID U(0x0200ff01)
+/* 0x8200ff02 is reserved*/
+#define QTI_SIP_SVC_VERSION_ID U(0x0200ff03)
+#define QTI_SIP_SVC_AVAILABLE_ID U(0x02000601)
+/*
+ * Syscall's to allow Non Secure world accessing peripheral/IO memory
+ * those are secure/proteced BUT not required to be secure.
+ */
+#define QTI_SIP_SVC_SECURE_IO_READ_ID U(0x02000501)
+#define QTI_SIP_SVC_SECURE_IO_WRITE_ID U(0x02000502)
+
+/*
+ * Syscall's to assigns a list of intermediate PAs from a
+ * source Virtual Machine (VM) to a destination VM.
+ */
+#define QTI_SIP_SVC_MEM_ASSIGN_ID U(0x02000C16)
+
+#define QTI_SIP_SVC_SECURE_IO_READ_PARAM_ID U(0x1)
+#define QTI_SIP_SVC_SECURE_IO_WRITE_PARAM_ID U(0x2)
+#define QTI_SIP_SVC_MEM_ASSIGN_PARAM_ID U(0x1117)
+
+#define QTI_SIP_SVC_CALL_COUNT U(0x3)
+#define QTI_SIP_SVC_VERSION_MAJOR U(0x0)
+#define QTI_SIP_SVC_VERSION_MINOR U(0x0)
+
+#define QTI_VM_LAST U(44)
+#define SIZE4K U(0x1000)
+#define QTI_VM_MAX_LIST_SIZE U(0x20)
+
+#define FUNCID_OEN_NUM_MASK ((FUNCID_OEN_MASK << FUNCID_OEN_SHIFT)\
+ |(FUNCID_NUM_MASK << FUNCID_NUM_SHIFT))
+
+enum {
+ QTI_SIP_SUCCESS = 0,
+ QTI_SIP_NOT_SUPPORTED = -1,
+ QTI_SIP_PREEMPTED = -2,
+ QTI_SIP_INVALID_PARAM = -3,
+};
+
+/* QTI SiP Service UUID */
+DEFINE_SVC_UUID2(qti_sip_svc_uid,
+ 0x43864748, 0x217f, 0x41ad, 0xaa, 0x5a,
+ 0xba, 0xe7, 0x0f, 0xa5, 0x52, 0xaf);
+
+static bool qti_is_secure_io_access_allowed(u_register_t addr)
+{
+ int i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(qti_secure_io_allowed_regs); i++) {
+ if ((uintptr_t) addr == qti_secure_io_allowed_regs[i]) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool qti_check_syscall_availability(u_register_t smc_fid)
+{
+ switch (smc_fid) {
+ case QTI_SIP_SVC_CALL_COUNT_ID:
+ case QTI_SIP_SVC_UID_ID:
+ case QTI_SIP_SVC_VERSION_ID:
+ case QTI_SIP_SVC_AVAILABLE_ID:
+ case QTI_SIP_SVC_SECURE_IO_READ_ID:
+ case QTI_SIP_SVC_SECURE_IO_WRITE_ID:
+ case QTI_SIP_SVC_MEM_ASSIGN_ID:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool qti_mem_assign_validate_param(memprot_info_t *mem_info,
+ u_register_t u_num_mappings,
+ uint32_t *source_vm_list,
+ u_register_t src_vm_list_cnt,
+ memprot_dst_vm_perm_info_t *dest_vm_list,
+ u_register_t dst_vm_list_cnt)
+{
+ int i;
+
+ if (!source_vm_list || !dest_vm_list || !mem_info
+ || (src_vm_list_cnt == 0)
+ || (src_vm_list_cnt >= QTI_VM_LAST) || (dst_vm_list_cnt == 0)
+ || (dst_vm_list_cnt >= QTI_VM_LAST) || (u_num_mappings == 0)
+ || u_num_mappings > QTI_VM_MAX_LIST_SIZE) {
+ ERROR("vm count is 0 or more then QTI_VM_LAST or empty list\n");
+ ERROR("source_vm_list %p dest_vm_list %p mem_info %p src_vm_list_cnt %u dst_vm_list_cnt %u u_num_mappings %u\n",
+ source_vm_list, dest_vm_list, mem_info,
+ (unsigned int)src_vm_list_cnt,
+ (unsigned int)dst_vm_list_cnt,
+ (unsigned int)u_num_mappings);
+ return false;
+ }
+ for (i = 0; i < u_num_mappings; i++) {
+ if ((mem_info[i].mem_addr & (SIZE4K - 1))
+ || (mem_info[i].mem_size == 0)
+ || (mem_info[i].mem_size & (SIZE4K - 1))) {
+ ERROR("mem_info passed buffer 0x%x or size 0x%x is not 4k aligned\n",
+ (unsigned int)mem_info[i].mem_addr,
+ (unsigned int)mem_info[i].mem_size);
+ return false;
+ }
+
+ if ((mem_info[i].mem_addr + mem_info[i].mem_size) <
+ mem_info[i].mem_addr) {
+ ERROR("overflow in mem_addr 0x%x add mem_size 0x%x\n",
+ (unsigned int)mem_info[i].mem_addr,
+ (unsigned int)mem_info[i].mem_size);
+ return false;
+ }
+ coreboot_memory_t mem_type = coreboot_get_memory_type(
+ mem_info[i].mem_addr,
+ mem_info[i].mem_size);
+ if (mem_type != CB_MEM_RAM && mem_type != CB_MEM_RESERVED) {
+ ERROR("memory region not in CB MEM RAM or RESERVED area: region start 0x%x size 0x%x\n",
+ (unsigned int)mem_info[i].mem_addr,
+ (unsigned int)mem_info[i].mem_size);
+ return false;
+ }
+ }
+ for (i = 0; i < src_vm_list_cnt; i++) {
+ if (source_vm_list[i] >= QTI_VM_LAST) {
+ ERROR("source_vm_list[%d] 0x%x is more then QTI_VM_LAST\n",
+ i, (unsigned int)source_vm_list[i]);
+ return false;
+ }
+ }
+ for (i = 0; i < dst_vm_list_cnt; i++) {
+ if (dest_vm_list[i].dst_vm >= QTI_VM_LAST) {
+ ERROR("dest_vm_list[%d] 0x%x is more then QTI_VM_LAST\n",
+ i, (unsigned int)dest_vm_list[i].dst_vm);
+ return false;
+ }
+ }
+ return true;
+}
+
+static uintptr_t qti_sip_mem_assign(void *handle, uint32_t smc_cc,
+ u_register_t x1,
+ u_register_t x2,
+ u_register_t x3, u_register_t x4)
+{
+ uintptr_t dyn_map_start = 0, dyn_map_end = 0;
+ size_t dyn_map_size = 0;
+ u_register_t x6, x7;
+ int ret = QTI_SIP_NOT_SUPPORTED;
+ u_register_t x5 = read_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X5);
+
+ if (smc_cc == SMC_32) {
+ x5 = (uint32_t) x5;
+ }
+ /* Validate input arg count & retrieve arg3-6 from NS Buffer. */
+ if ((x1 != QTI_SIP_SVC_MEM_ASSIGN_PARAM_ID) || (x5 == 0x0)) {
+ ERROR("invalid mem_assign param id or no mapping info\n");
+ goto unmap_return;
+ }
+
+ /* Map NS Buffer. */
+ dyn_map_start = x5;
+ dyn_map_size =
+ (smc_cc ==
+ SMC_32) ? (sizeof(uint32_t) * 4) : (sizeof(uint64_t) * 4);
+ if (qti_mmap_add_dynamic_region(dyn_map_start, dyn_map_size,
+ (MT_NS | MT_RO_DATA)) != 0) {
+ ERROR("map failed for params NS Buffer %x %x\n",
+ (unsigned int)dyn_map_start, (unsigned int)dyn_map_size);
+ goto unmap_return;
+ }
+ /* Retrieve indirect args. */
+ if (smc_cc == SMC_32) {
+ x6 = *((uint32_t *) x5 + 1);
+ x7 = *((uint32_t *) x5 + 2);
+ x5 = *(uint32_t *) x5;
+ } else {
+ x6 = *((uint64_t *) x5 + 1);
+ x7 = *((uint64_t *) x5 + 2);
+ x5 = *(uint64_t *) x5;
+ }
+ /* Un-Map NS Buffer. */
+ if (qti_mmap_remove_dynamic_region(dyn_map_start, dyn_map_size) != 0) {
+ ERROR("unmap failed for params NS Buffer %x %x\n",
+ (unsigned int)dyn_map_start, (unsigned int)dyn_map_size);
+ goto unmap_return;
+ }
+
+ /*
+ * Map NS Buffers.
+ * arg0,2,4 points to buffers & arg1,3,5 hold sizes.
+ * MAP api's fail to map if it's already mapped. Let's
+ * find lowest start & highest end address, then map once.
+ */
+ dyn_map_start = MIN(x2, x4);
+ dyn_map_start = MIN(dyn_map_start, x6);
+ dyn_map_end = MAX((x2 + x3), (x4 + x5));
+ dyn_map_end = MAX(dyn_map_end, (x6 + x7));
+ dyn_map_size = dyn_map_end - dyn_map_start;
+
+ if (qti_mmap_add_dynamic_region(dyn_map_start, dyn_map_size,
+ (MT_NS | MT_RO_DATA)) != 0) {
+ ERROR("map failed for params NS Buffer2 %x %x\n",
+ (unsigned int)dyn_map_start, (unsigned int)dyn_map_size);
+ goto unmap_return;
+ }
+ memprot_info_t *mem_info_p = (memprot_info_t *) x2;
+ uint32_t u_num_mappings = x3 / sizeof(memprot_info_t);
+ uint32_t *source_vm_list_p = (uint32_t *) x4;
+ uint32_t src_vm_list_cnt = x5 / sizeof(uint32_t);
+ memprot_dst_vm_perm_info_t *dest_vm_list_p =
+ (memprot_dst_vm_perm_info_t *) x6;
+ uint32_t dst_vm_list_cnt =
+ x7 / sizeof(memprot_dst_vm_perm_info_t);
+ if (qti_mem_assign_validate_param(mem_info_p, u_num_mappings,
+ source_vm_list_p, src_vm_list_cnt,
+ dest_vm_list_p,
+ dst_vm_list_cnt) != true) {
+ ERROR("Param validation failed\n");
+ goto unmap_return;
+ }
+
+ memprot_info_t mem_info[QTI_VM_MAX_LIST_SIZE];
+ /* Populating the arguments */
+ for (int i = 0; i < u_num_mappings; i++) {
+ mem_info[i].mem_addr = mem_info_p[i].mem_addr;
+ mem_info[i].mem_size = mem_info_p[i].mem_size;
+ }
+
+ memprot_dst_vm_perm_info_t dest_vm_list[QTI_VM_LAST];
+
+ for (int i = 0; i < dst_vm_list_cnt; i++) {
+ dest_vm_list[i].dst_vm = dest_vm_list_p[i].dst_vm;
+ dest_vm_list[i].dst_vm_perm = dest_vm_list_p[i].dst_vm_perm;
+ dest_vm_list[i].ctx = dest_vm_list_p[i].ctx;
+ dest_vm_list[i].ctx_size = dest_vm_list_p[i].ctx_size;
+ }
+
+ uint32_t source_vm_list[QTI_VM_LAST];
+
+ for (int i = 0; i < src_vm_list_cnt; i++) {
+ source_vm_list[i] = source_vm_list_p[i];
+ }
+ /* Un-Map NS Buffers. */
+ if (qti_mmap_remove_dynamic_region(dyn_map_start,
+ dyn_map_size) != 0) {
+ ERROR("unmap failed for params NS Buffer %x %x\n",
+ (unsigned int)dyn_map_start, (unsigned int)dyn_map_size);
+ goto unmap_return;
+ }
+ /* Invoke API lib api. */
+ ret = qtiseclib_mem_assign(mem_info, u_num_mappings,
+ source_vm_list, src_vm_list_cnt,
+ dest_vm_list, dst_vm_list_cnt);
+
+ if (ret == 0) {
+ SMC_RET2(handle, QTI_SIP_SUCCESS, ret);
+ }
+unmap_return:
+ /* Un-Map NS Buffers if mapped */
+ if (dyn_map_start && dyn_map_size) {
+ qti_mmap_remove_dynamic_region(dyn_map_start, dyn_map_size);
+ }
+
+ SMC_RET2(handle, QTI_SIP_INVALID_PARAM, ret);
+}
+
+/*
+ * This function handles QTI specific syscalls. Currently only SiP calls are present.
+ * Both FAST & YIELD type call land here.
+ */
+static uintptr_t qti_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 l_smc_fid = smc_fid & FUNCID_OEN_NUM_MASK;
+
+ if (GET_SMC_CC(smc_fid) == SMC_32) {
+ x1 = (uint32_t) x1;
+ x2 = (uint32_t) x2;
+ x3 = (uint32_t) x3;
+ x4 = (uint32_t) x4;
+ }
+
+ switch (l_smc_fid) {
+ case QTI_SIP_SVC_CALL_COUNT_ID:
+ {
+ SMC_RET1(handle, QTI_SIP_SVC_CALL_COUNT);
+ break;
+ }
+ case QTI_SIP_SVC_UID_ID:
+ {
+ /* Return UID to the caller */
+ SMC_UUID_RET(handle, qti_sip_svc_uid);
+ break;
+ }
+ case QTI_SIP_SVC_VERSION_ID:
+ {
+ /* Return the version of current implementation */
+ SMC_RET2(handle, QTI_SIP_SVC_VERSION_MAJOR,
+ QTI_SIP_SVC_VERSION_MINOR);
+ break;
+ }
+ case QTI_SIP_SVC_AVAILABLE_ID:
+ {
+ if (x1 != 1) {
+ SMC_RET1(handle, QTI_SIP_INVALID_PARAM);
+ }
+ if (qti_check_syscall_availability(x2) == true) {
+ SMC_RET2(handle, QTI_SIP_SUCCESS, 1);
+ } else {
+ SMC_RET2(handle, QTI_SIP_SUCCESS, 0);
+ }
+ break;
+ }
+ case QTI_SIP_SVC_SECURE_IO_READ_ID:
+ {
+ if ((x1 == QTI_SIP_SVC_SECURE_IO_READ_PARAM_ID) &&
+ qti_is_secure_io_access_allowed(x2)) {
+ SMC_RET2(handle, QTI_SIP_SUCCESS,
+ *((volatile uint32_t *)x2));
+ }
+ SMC_RET1(handle, QTI_SIP_INVALID_PARAM);
+ break;
+ }
+ case QTI_SIP_SVC_SECURE_IO_WRITE_ID:
+ {
+ if ((x1 == QTI_SIP_SVC_SECURE_IO_WRITE_PARAM_ID) &&
+ qti_is_secure_io_access_allowed(x2)) {
+ *((volatile uint32_t *)x2) = x3;
+ SMC_RET1(handle, QTI_SIP_SUCCESS);
+ }
+ SMC_RET1(handle, QTI_SIP_INVALID_PARAM);
+ break;
+ }
+ case QTI_SIP_SVC_MEM_ASSIGN_ID:
+ {
+ return qti_sip_mem_assign(handle, GET_SMC_CC(smc_fid),
+ x1, x2, x3, x4);
+ break;
+ }
+ default:
+ {
+ SMC_RET1(handle, QTI_SIP_NOT_SUPPORTED);
+ }
+ }
+ return (uintptr_t) handle;
+}
+
+/* Define a runtime service descriptor for both fast & yield SiP calls */
+DECLARE_RT_SVC(qti_sip_fast_svc, OEN_SIP_START,
+ OEN_SIP_END, SMC_TYPE_FAST, NULL, qti_sip_handler);
+
+DECLARE_RT_SVC(qti_sip_yield_svc, OEN_SIP_START,
+ OEN_SIP_END, SMC_TYPE_YIELD, NULL, qti_sip_handler);
diff --git a/plat/qti/common/src/qti_topology.c b/plat/qti/common/src/qti_topology.c
new file mode 100644
index 0000000..bf2e3f3
--- /dev/null
+++ b/plat/qti/common/src/qti_topology.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018,2020 The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+
+#include <platform_def.h>
+#include <qti_plat.h>
+
+/* The QTI power domain tree descriptor */
+const unsigned char qti_power_domain_tree_desc[] = {
+ /* One domain to represent PDC */
+ PLAT_PDC_COUNT,
+ /* One domain to represent RSC */
+ PLAT_RSC_COUNT,
+ /* There is one top-level FCM cluster */
+ PLAT_CLUSTER_COUNT,
+ /* No. of cores in the FCM cluster */
+ PLAT_CLUSTER0_CORE_COUNT
+};
+
+/*******************************************************************************
+ * This function returns the ARM default topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ return qti_power_domain_tree_desc;
+}
+
+/** Function: 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.
+ */
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+ int core_linear_index = plat_qti_core_pos_by_mpidr(mpidr);
+
+ if (core_linear_index < PLATFORM_CORE_COUNT) {
+ return core_linear_index;
+ } else {
+ return -1;
+ }
+}
diff --git a/plat/qti/common/src/spmi_arb.c b/plat/qti/common/src/spmi_arb.c
new file mode 100644
index 0000000..4213ed1
--- /dev/null
+++ b/plat/qti/common/src/spmi_arb.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2020, Google LLC. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <spmi_arb.h>
+
+#define REG_APID_MAP(apid) (0x0C440900U + sizeof(uint32_t) * apid)
+#define NUM_APID ((0x1100U - 0x900U) / sizeof(uint32_t))
+
+#define PPID_MASK (0xfffU << 8)
+
+#define REG_ARB_CMD(apid) (0x0C600000U + 0x10000U * apid)
+/* These are opcodes specific to this SPMI arbitrator, *not* SPMI commands. */
+#define OPC_EXT_WRITEL 0
+#define OPC_EXT_READL 1
+
+#define REG_ARB_STATUS(apid) (0x0C600008U + 0x10000U * apid)
+#define ARB_STATUS_DONE BIT(0)
+#define ARB_STATUS_FAILURE BIT(1)
+#define ARB_STATUS_DENIED BIT(2)
+#define ARB_STATUS_DROPPED BIT(3)
+
+/* Fake status to report driver errors. */
+#define ARB_FAKE_STATUS_TIMEOUT BIT(8)
+
+#define REG_ARB_RDATA0(apid) (0x0C600018U + 0x10000U * apid)
+#define REG_ARB_WDATA0(apid) (0x0C600010U + 0x10000U * apid)
+
+static int addr_to_apid(uint32_t addr)
+{
+ unsigned int i;
+
+ for (i = 0U; i < NUM_APID; i++) {
+ uint32_t reg = mmio_read_32(REG_APID_MAP(i));
+ if ((reg != 0U) && ((addr & PPID_MASK) == (reg & PPID_MASK))) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static int wait_for_done(uint16_t apid)
+{
+ unsigned int timeout = 100;
+
+ while (timeout-- != 0U) {
+ uint32_t status = mmio_read_32(REG_ARB_STATUS(apid));
+ if ((status & ARB_STATUS_DONE) != 0U) {
+ if ((status & ARB_STATUS_FAILURE) != 0U ||
+ (status & ARB_STATUS_DENIED) != 0U ||
+ (status & ARB_STATUS_DROPPED) != 0U) {
+ return status & 0xff;
+ }
+ return 0;
+ }
+ mdelay(1);
+ }
+ ERROR("SPMI_ARB timeout!\n");
+ return ARB_FAKE_STATUS_TIMEOUT;
+}
+
+static void arb_command(uint16_t apid, uint8_t opcode, uint32_t addr,
+ uint8_t bytes)
+{
+ mmio_write_32(REG_ARB_CMD(apid), (uint32_t)opcode << 27 |
+ (addr & 0xff) << 4 | (bytes - 1));
+}
+
+int spmi_arb_read8(uint32_t addr)
+{
+ int apid = addr_to_apid(addr);
+
+ if (apid < 0) {
+ return apid;
+ }
+
+ arb_command(apid, OPC_EXT_READL, addr, 1);
+
+ int ret = wait_for_done(apid);
+ if (ret != 0) {
+ ERROR("SPMI_ARB read error [0x%x]: 0x%x\n", addr, ret);
+ return ret;
+ }
+
+ return mmio_read_32(REG_ARB_RDATA0(apid)) & 0xff;
+}
+
+int spmi_arb_write8(uint32_t addr, uint8_t data)
+{
+ int apid = addr_to_apid(addr);
+
+ if (apid < 0) {
+ return apid;
+ }
+
+ mmio_write_32(REG_ARB_WDATA0(apid), data);
+ arb_command(apid, OPC_EXT_WRITEL, addr, 1);
+
+ int ret = wait_for_done(apid);
+ if (ret != 0) {
+ ERROR("SPMI_ARB write error [0x%x] = 0x%x: 0x%x\n",
+ addr, data, ret);
+ }
+
+ return ret;
+}
diff --git a/plat/qti/msm8916/aarch64/msm8916_helpers.S b/plat/qti/msm8916/aarch64/msm8916_helpers.S
new file mode 100644
index 0000000..dad9968
--- /dev/null
+++ b/plat/qti/msm8916/aarch64/msm8916_helpers.S
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+#include <msm8916_mmap.h>
+
+#define APCS_TCM_START_ADDR 0x10
+#define APCS_TCM_REDIRECT_EN_0 BIT_32(0)
+
+ .globl plat_crash_console_init
+ .globl plat_crash_console_putc
+ .globl plat_crash_console_flush
+ .globl plat_panic_handler
+ .globl plat_my_core_pos
+ .globl plat_get_my_entrypoint
+ .globl plat_reset_handler
+ .globl platform_mem_init
+ .globl msm8916_entry_point
+
+ /* -------------------------------------------------
+ * int plat_crash_console_init(void)
+ * Initialize the crash console.
+ * Out: x0 - 1 on success, 0 on error
+ * Clobber list : x0 - x4
+ * -------------------------------------------------
+ */
+func plat_crash_console_init
+ mov x1, #BLSP_UART2_BASE
+
+ /*
+ * If the non-secure world has been actively using the UART there might
+ * be still some characters left to be sent in the FIFO. In that case,
+ * resetting the transmitter too early might cause all output to become
+ * corrupted. To avoid that, try to flush (wait until FIFO empty) first.
+ */
+ mov x4, lr
+ bl console_uartdm_core_flush
+ mov lr, x4
+
+ mov x0, #1
+ b console_uartdm_core_init
+endfunc plat_crash_console_init
+
+ /* -------------------------------------------------
+ * int plat_crash_console_putc(int c)
+ * Print a character on the crash console.
+ * In : w0 - character to be printed
+ * Out: w0 - printed character on success
+ * Clobber list : x1, x2
+ * -------------------------------------------------
+ */
+func plat_crash_console_putc
+ mov x1, #BLSP_UART2_BASE
+ b console_uartdm_core_putc
+endfunc plat_crash_console_putc
+
+ /* -------------------------------------------------
+ * void plat_crash_console_flush(void)
+ * Force a write of all buffered data that has not
+ * been output.
+ * Clobber list : x1, x2
+ * -------------------------------------------------
+ */
+func plat_crash_console_flush
+ mov x1, #BLSP_UART2_BASE
+ b console_uartdm_core_flush
+endfunc plat_crash_console_flush
+
+ /* -------------------------------------------------
+ * void plat_panic_handler(void) __dead
+ * Called when an unrecoverable error occurs.
+ * -------------------------------------------------
+ */
+func plat_panic_handler
+ /* Try to shutdown/reset */
+ mov_imm x0, MPM_PS_HOLD
+ str wzr, [x0]
+1: b 1b
+endfunc plat_panic_handler
+
+ /* -------------------------------------------------
+ * unsigned int plat_my_core_pos(void)
+ * Out: x0 - index of the calling CPU
+ * -------------------------------------------------
+ */
+func plat_my_core_pos
+ /* There is just a single cluster so this is very simple */
+ mrs x0, mpidr_el1
+ and x0, x0, #MPIDR_CPU_MASK
+ ret
+endfunc plat_my_core_pos
+
+ /* -------------------------------------------------
+ * uintptr_t plat_get_my_entrypoint(void)
+ * Distinguish cold and warm boot and return warm boot
+ * entry address if available.
+ * Out: x0 - warm boot entry point or 0 on cold boot
+ * -------------------------------------------------
+ */
+func plat_get_my_entrypoint
+ ldr x0, msm8916_entry_point
+ ret
+endfunc plat_get_my_entrypoint
+
+ /* -------------------------------------------------
+ * void plat_reset_handler(void)
+ * Perform additional initialization after reset.
+ * Clobber list : x0 - x18, x30
+ * -------------------------------------------------
+ */
+func plat_reset_handler
+ /*
+ * Check if the CPU is running at the correct address.
+ * During cold boot the CPU enters here at the wrong address
+ * using the "boot remapper". (It remaps the BL31_BASE to
+ * the CPU reset address 0x0).
+ */
+ mov x0, #BL31_BASE
+ adr x1, bl31_entrypoint
+ cmp x0, x1
+ b.ne _remapped_cold_boot
+ /* Already running at correct address, just return directly */
+ ret
+
+_remapped_cold_boot:
+ /*
+ * The previous boot stage seems to use the L2 cache as TCM.
+ * Disable the TCM redirect before enabling caches to avoid
+ * strange crashes.
+ */
+ mov x2, #APCS_CFG
+ ldr w3, [x2, #APCS_TCM_START_ADDR]
+ and w3, w3, #~APCS_TCM_REDIRECT_EN_0
+ str w3, [x2, #APCS_TCM_START_ADDR]
+
+ /* Enter BL31 again at the real address */
+ br x0
+endfunc plat_reset_handler
+
+ /* -------------------------------------------------
+ * void platform_mem_init(void)
+ * Performs additional memory initialization early
+ * in the boot process.
+ * -------------------------------------------------
+ */
+func platform_mem_init
+ /* Nothing to do here, all memory is already initialized */
+ ret
+endfunc platform_mem_init
+
+ .data
+ .align 3
+
+ /* -------------------------------------------------
+ * Warm boot entry point for CPU. Set by PSCI code.
+ * -------------------------------------------------
+ */
+msm8916_entry_point:
+ .quad 0
diff --git a/plat/qti/msm8916/aarch64/uartdm_console.S b/plat/qti/msm8916/aarch64/uartdm_console.S
new file mode 100644
index 0000000..c69c193
--- /dev/null
+++ b/plat/qti/msm8916/aarch64/uartdm_console.S
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * Based on aarch64/skeleton_console.S:
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <console_macros.S>
+
+/* UART DM registers */
+#define UART_DM_DMEN 0x03c /* DMA / data packing */
+#define UART_DM_SR 0x0a4 /* status register */
+#define UART_DM_CR 0x0a8 /* command register */
+#define UART_DM_TF 0x100 /* transmit FIFO */
+
+#define UART_DM_DMEN_TX_SC BIT_32(4) /* TX single character mode */
+
+#define UART_DM_SR_TXRDY_BIT 2 /* TX FIFO has space */
+#define UART_DM_SR_TXEMT_BIT 3 /* TX FIFO is empty */
+
+#define UART_DM_CR_RESET_RX (U(0x01) << 4) /* reset receiver */
+#define UART_DM_CR_RESET_TX (U(0x02) << 4) /* reset transmitter */
+#define UART_DM_CR_TX_ENABLE BIT_32(2) /* enable transmitter */
+
+ .globl console_uartdm_register
+ .globl console_uartdm_core_init
+ .globl console_uartdm_putc
+ .globl console_uartdm_core_putc
+ .globl console_uartdm_flush
+ .globl console_uartdm_core_flush
+
+ /* -----------------------------------------------------------
+ * int console_uartdm_register(console_t *console,
+ * uintptr_t base_addr)
+ * Function to initialize and register the console. The caller
+ * needs to pass an empty console_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 - base address
+ * Out: x0 - 1 on success, 0 on error
+ * Clobber list : x0 - x7
+ * -----------------------------------------------------------
+ */
+func console_uartdm_register
+ str x1, [x0, #CONSOLE_T_BASE]
+ mov x7, lr
+ bl console_uartdm_core_init
+ mov lr, x7
+
+ /* Register the new console */
+ finish_console_register uartdm putc=1, flush=1
+endfunc console_uartdm_register
+
+ /* -----------------------------------------------------------
+ * void console_uartdm_core_init(unused, uintptr_t base_addr)
+ * Function to initialize the console.
+ * In : x0 - unused
+ * x1 - base address
+ * Out: void
+ * Clobber list : x1, x2, x3
+ * -----------------------------------------------------------
+ */
+func console_uartdm_core_init
+ /* Reset receiver */
+ mov w3, #UART_DM_CR_RESET_RX
+ str w3, [x1, #UART_DM_CR]
+
+ /* Reset transmitter */
+ mov w3, #UART_DM_CR_RESET_TX
+ str w3, [x1, #UART_DM_CR]
+
+ /*
+ * Disable BAM/DMA modes but enable single-character mode for TX.
+ * The single character mode allows simplifying the putc implementation
+ * since characters can be written directly to the FIFO instead of
+ * having to initiate a new transfer and waiting for its completion.
+ */
+ mov w3, #UART_DM_DMEN_TX_SC
+ str w3, [x1, #UART_DM_DMEN]
+
+ /* Enable transmitter */
+ mov w3, #UART_DM_CR_TX_ENABLE
+ str w3, [x1, #UART_DM_CR]
+
+ ret
+endfunc console_uartdm_core_init
+
+ /* -----------------------------------------------------------
+ * int console_uartdm_putc(int c, console_t *console)
+ * Function to output a character over the console.
+ * 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_uartdm_putc
+ ldr x1, [x1, #CONSOLE_T_BASE]
+ b console_uartdm_core_putc
+endfunc console_uartdm_putc
+
+ /* -----------------------------------------------------------
+ * int console_uartdm_core_putc(int c, uintptr_t base_addr)
+ * Function to output a character over the console.
+ * In : w0 - character to be printed
+ * x1 - base address
+ * Out: w0 - printed character on success, < 0 on error.
+ * Clobber list : x2
+ * -----------------------------------------------------------
+ */
+func console_uartdm_core_putc
+1: /* Loop until TX FIFO has space */
+ ldr w2, [x1, #UART_DM_SR]
+ tbz w2, #UART_DM_SR_TXRDY_BIT, 1b
+
+ /* Write character to FIFO */
+ str w0, [x1, #UART_DM_TF]
+ ret
+endfunc console_uartdm_core_putc
+
+ /* -----------------------------------------------------------
+ * void console_uartdm_flush(console_t *console)
+ * Function to force a write of all buffered data
+ * that has not been output.
+ * In : x0 - pointer to console_t struct
+ * Out: void
+ * Clobber list : x0, x1, x2, x3, x4, x5
+ * -----------------------------------------------------------
+ */
+func console_uartdm_flush
+ ldr x1, [x0, #CONSOLE_T_BASE]
+ b console_uartdm_core_flush
+endfunc console_uartdm_flush
+
+ /* -----------------------------------------------------------
+ * void console_uartdm_core_flush(unused, uintptr_t base_addr)
+ * Function to force a write of all buffered data
+ * that has not been output.
+ * In : x0 - unused
+ * x1 - base address
+ * Out: void
+ * Clobber list : x2
+ * -----------------------------------------------------------
+ */
+func console_uartdm_core_flush
+1: /* Loop until TX FIFO is empty */
+ ldr w2, [x1, #UART_DM_SR]
+ tbz w2, #UART_DM_SR_TXEMT_BIT, 1b
+ ret
+endfunc console_uartdm_core_flush
diff --git a/plat/qti/msm8916/include/msm8916_mmap.h b/plat/qti/msm8916/include/msm8916_mmap.h
new file mode 100644
index 0000000..406ae6b
--- /dev/null
+++ b/plat/qti/msm8916/include/msm8916_mmap.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MSM8916_MMAP_H
+#define MSM8916_MMAP_H
+
+#define PCNOC_BASE 0x00000000
+#define PCNOC_SIZE 0x8000000 /* 128 MiB */
+#define APCS_BASE 0x0b000000
+#define APCS_SIZE 0x800000 /* 8 MiB */
+
+#define MPM_BASE (PCNOC_BASE + 0x04a0000)
+#define MPM_PS_HOLD (MPM_BASE + 0xb000)
+
+#define TLMM_BASE (PCNOC_BASE + 0x1000000)
+#define TLMM_GPIO_CFG(n) (TLMM_BASE + ((n) * 0x1000))
+
+#define GCC_BASE (PCNOC_BASE + 0x1800000)
+
+#define APPS_SMMU_BASE (PCNOC_BASE + 0x1e00000)
+#define APPS_SMMU_QCOM (APPS_SMMU_BASE + 0xf0000)
+
+#define BLSP_UART1_BASE (PCNOC_BASE + 0x78af000)
+#define BLSP_UART2_BASE (PCNOC_BASE + 0x78b0000)
+
+#define APCS_QGIC2_BASE (APCS_BASE + 0x00000)
+#define APCS_QGIC2_GICD (APCS_QGIC2_BASE + 0x0000)
+#define APCS_QGIC2_GICC (APCS_QGIC2_BASE + 0x2000)
+#define APCS_BANKED_ACS (APCS_BASE + 0x08000)
+#define APCS_BANKED_SAW2 (APCS_BASE + 0x09000)
+#define APCS_CFG (APCS_BASE + 0x10000)
+#define APCS_GLB (APCS_BASE + 0x11000)
+#define APCS_L2_SAW2 (APCS_BASE + 0x12000)
+#define APCS_QTMR (APCS_BASE + 0x20000)
+#define APCS_ALIAS_ACS(cpu) (APCS_BASE + 0x88000 + ((cpu) * 0x10000))
+#define APCS_ALIAS_SAW2(cpu) (APCS_BASE + 0x89000 + ((cpu) * 0x10000))
+
+#endif /* MSM8916_MMAP_H */
diff --git a/plat/qti/msm8916/include/plat_macros.S b/plat/qti/msm8916/include/plat_macros.S
new file mode 100644
index 0000000..552add2
--- /dev/null
+++ b/plat/qti/msm8916/include/plat_macros.S
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <arm_macros.S>
+
+#include <msm8916_mmap.h>
+
+ /* ---------------------------------------------
+ * 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
+ mov_imm x16, APCS_QGIC2_GICD
+ mov_imm x17, APCS_QGIC2_GICC
+ arm_print_gic_regs
+ .endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/qti/msm8916/include/platform_def.h b/plat/qti/msm8916/include/platform_def.h
new file mode 100644
index 0000000..bfade70
--- /dev/null
+++ b/plat/qti/msm8916/include/platform_def.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <plat/common/common_def.h>
+
+/*
+ * There is at least 1 MiB available for BL31. However, at the moment the
+ * "msm8916_entry_point" variable in the data section is read through the
+ * 64 KiB region of the "boot remapper" after reset. For simplicity, limit
+ * the end of the data section (BL31_PROGBITS_LIMIT) to 64 KiB for now and
+ * the overall limit to 128 KiB. This could be increased if needed by placing
+ * the "msm8916_entry_point" variable explicitly in the first 64 KiB of BL31.
+ */
+#define BL31_LIMIT (BL31_BASE + 0x20000) /* 128 KiB */
+#define BL31_PROGBITS_LIMIT (BL31_BASE + 0x10000) /* 64 KiB */
+
+#define CACHE_WRITEBACK_GRANULE U(64)
+#define PLATFORM_STACK_SIZE U(0x1000)
+
+/* CPU topology: single cluster with 4 cores */
+#define PLATFORM_CLUSTER_COUNT U(1)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER U(4)
+#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \
+ PLATFORM_MAX_CPUS_PER_CLUSTER)
+
+/* Power management */
+#define PLATFORM_SYSTEM_COUNT U(1)
+#define PLAT_NUM_PWR_DOMAINS (PLATFORM_SYSTEM_COUNT + \
+ PLATFORM_CLUSTER_COUNT + \
+ PLATFORM_CORE_COUNT)
+#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2
+#define PLAT_MAX_RET_STATE U(2)
+#define PLAT_MAX_OFF_STATE U(3)
+
+/* Translation tables */
+#define MAX_MMAP_REGIONS 8
+#define MAX_XLAT_TABLES 4
+
+#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32)
+
+/* Timer frequency */
+#define PLAT_SYSCNT_FREQ 19200000
+
+/*
+ * The Qualcomm QGIC2 implementation seems to have PIDR0-4 and PIDR4-7
+ * erroneously swapped for some reason. PIDR2 is actually at 0xFD8.
+ * Override the address in <drivers/arm/gicv2.h> to avoid a failing assert().
+ */
+#define GICD_PIDR2_GICV2 U(0xFD8)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/qti/msm8916/include/uartdm_console.h b/plat/qti/msm8916/include/uartdm_console.h
new file mode 100644
index 0000000..0f09ba8
--- /dev/null
+++ b/plat/qti/msm8916/include/uartdm_console.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef UARTDM_CONSOLE_H
+#define UARTDM_CONSOLE_H
+
+int console_uartdm_register(console_t *console, uintptr_t base_addr);
+
+#endif /* UARTDM_CONSOLE_H */
diff --git a/plat/qti/msm8916/msm8916_bl31_setup.c b/plat/qti/msm8916/msm8916_bl31_setup.c
new file mode 100644
index 0000000..638cd09
--- /dev/null
+++ b/plat/qti/msm8916/msm8916_bl31_setup.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include "msm8916_gicv2.h"
+#include <msm8916_mmap.h>
+#include <platform_def.h>
+#include <uartdm_console.h>
+
+static const mmap_region_t msm8916_mmap[] = {
+ MAP_REGION_FLAT(PCNOC_BASE, PCNOC_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER),
+ MAP_REGION_FLAT(APCS_BASE, APCS_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER),
+ {},
+};
+
+static struct {
+ entry_point_info_t bl32;
+ entry_point_info_t bl33;
+} image_ep_info = {
+ /* BL32 entry point */
+ SET_STATIC_PARAM_HEAD(bl32, PARAM_EP, VERSION_1,
+ entry_point_info_t, SECURE),
+ .bl32.pc = BL32_BASE,
+
+ /* BL33 entry point */
+ SET_STATIC_PARAM_HEAD(bl33, PARAM_EP, VERSION_1,
+ entry_point_info_t, NON_SECURE),
+ .bl33.pc = PRELOADED_BL33_BASE,
+ .bl33.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS),
+};
+
+static console_t console;
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+ return PLAT_SYSCNT_FREQ;
+}
+
+#define CLK_ENABLE BIT_32(0)
+#define CLK_OFF BIT_32(31)
+
+#define GPIO_BLSP_UART2_TX 4
+#define GPIO_BLSP_UART2_RX 5
+#define GPIO_CFG_FUNC_BLSP_UART2 (U(0x2) << 2)
+#define GPIO_CFG_DRV_STRENGTH_16MA (U(0x7) << 6)
+
+#define GCC_BLSP1_AHB_CBCR (GCC_BASE + 0x01008)
+#define GCC_BLSP1_UART2_APPS_CBCR (GCC_BASE + 0x0302c)
+#define GCC_APCS_CLOCK_BRANCH_ENA_VOTE (GCC_BASE + 0x45004)
+#define BLSP1_AHB_CLK_ENA BIT_32(10)
+
+/*
+ * The previous boot stage seems to disable most of the UART setup before exit
+ * so it must be enabled here again before the UART console can be used.
+ */
+static void msm8916_enable_blsp_uart2(void)
+{
+ /* Route GPIOs to BLSP UART2 */
+ mmio_write_32(TLMM_GPIO_CFG(GPIO_BLSP_UART2_TX),
+ GPIO_CFG_FUNC_BLSP_UART2 | GPIO_CFG_DRV_STRENGTH_16MA);
+ mmio_write_32(TLMM_GPIO_CFG(GPIO_BLSP_UART2_RX),
+ GPIO_CFG_FUNC_BLSP_UART2 | GPIO_CFG_DRV_STRENGTH_16MA);
+
+ /* Enable AHB clock */
+ mmio_setbits_32(GCC_APCS_CLOCK_BRANCH_ENA_VOTE, BLSP1_AHB_CLK_ENA);
+ while (mmio_read_32(GCC_BLSP1_AHB_CBCR) & CLK_OFF)
+ ;
+
+ /* Enable BLSP UART2 clock */
+ mmio_setbits_32(GCC_BLSP1_UART2_APPS_CBCR, CLK_ENABLE);
+ while (mmio_read_32(GCC_BLSP1_UART2_APPS_CBCR) & CLK_OFF)
+ ;
+}
+
+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 early as possible */
+ msm8916_enable_blsp_uart2();
+ console_uartdm_register(&console, BLSP_UART2_BASE);
+}
+
+void bl31_plat_arch_setup(void)
+{
+ mmap_add_region(BL31_BASE, BL31_BASE, BL31_END - BL31_BASE,
+ MT_RW_DATA | 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_region(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_BASE,
+ BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
+ MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER);
+
+ mmap_add(msm8916_mmap);
+ init_xlat_tables();
+ enable_mmu_el3(0);
+}
+
+static void msm8916_configure_timer(void)
+{
+ /* Set timer frequency */
+ mmio_write_32(APCS_QTMR + CNTCTLBASE_CNTFRQ, plat_get_syscnt_freq2());
+
+ /* Make frame 0 available to non-secure world */
+ mmio_write_32(APCS_QTMR + CNTNSAR, BIT_32(CNTNSAR_NS_SHIFT(0)));
+ mmio_write_32(APCS_QTMR + CNTACR_BASE(0),
+ BIT_32(CNTACR_RPCT_SHIFT) | BIT_32(CNTACR_RVCT_SHIFT) |
+ BIT_32(CNTACR_RFRQ_SHIFT) | BIT_32(CNTACR_RVOFF_SHIFT) |
+ BIT_32(CNTACR_RWVT_SHIFT) | BIT_32(CNTACR_RWPT_SHIFT));
+}
+
+/*
+ * The APCS register regions always start with a SECURE register that should
+ * be cleared to 0 to only allow secure access. Since BL31 handles most of
+ * the CPU power management, most of them can be cleared to secure access only.
+ */
+#define APCS_GLB_SECURE_STS_NS BIT_32(0)
+#define APCS_GLB_SECURE_PWR_NS BIT_32(1)
+#define APCS_BOOT_START_ADDR_SEC (APCS_CFG + 0x04)
+#define REMAP_EN BIT_32(0)
+#define APCS_AA64NAA32_REG (APCS_CFG + 0x0c)
+
+static void msm8916_configure_cpu_pm(void)
+{
+ unsigned int cpu;
+
+ /* Disallow non-secure access to boot remapper / TCM registers */
+ mmio_write_32(APCS_CFG, 0);
+
+ /*
+ * Disallow non-secure access to power management registers.
+ * However, allow STS and PWR since those also seem to control access
+ * to CPU frequency related registers (e.g. APCS_CMD_RCGR). If these
+ * bits are not set, CPU frequency control fails in the non-secure world.
+ */
+ mmio_write_32(APCS_GLB, APCS_GLB_SECURE_STS_NS | APCS_GLB_SECURE_PWR_NS);
+
+ /* Disallow non-secure access to L2 SAW2 */
+ mmio_write_32(APCS_L2_SAW2, 0);
+
+ /* Disallow non-secure access to CPU ACS and SAW2 */
+ for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
+ mmio_write_32(APCS_ALIAS_ACS(cpu), 0);
+ mmio_write_32(APCS_ALIAS_SAW2(cpu), 0);
+ }
+
+ /* Make sure all further warm boots end up in BL31 and aarch64 state */
+ CASSERT((BL31_BASE & 0xffff) == 0, assert_bl31_base_64k_aligned);
+ mmio_write_32(APCS_BOOT_START_ADDR_SEC, BL31_BASE | REMAP_EN);
+ mmio_write_32(APCS_AA64NAA32_REG, 1);
+}
+
+/*
+ * MSM8916 has a special "interrupt aggregation logic" in the APPS SMMU,
+ * which allows routing context bank interrupts to one of 3 interrupt numbers
+ * ("TZ/HYP/NS"). Route all interrupts to the non-secure interrupt number
+ * by default to avoid special setup on the non-secure side.
+ */
+#define GCC_SMMU_CFG_CBCR (GCC_BASE + 0x12038)
+#define GCC_APCS_SMMU_CLOCK_BRANCH_ENA_VOTE (GCC_BASE + 0x4500c)
+#define SMMU_CFG_CLK_ENA BIT_32(12)
+#define APPS_SMMU_INTR_SEL_NS (APPS_SMMU_QCOM + 0x2000)
+#define APPS_SMMU_INTR_SEL_NS_EN_ALL U(0xffffffff)
+
+static void msm8916_configure_smmu(void)
+{
+ /* Enable SMMU configuration clock to enable register access */
+ mmio_setbits_32(GCC_APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, SMMU_CFG_CLK_ENA);
+ while (mmio_read_32(GCC_SMMU_CFG_CBCR) & CLK_OFF)
+ ;
+
+ /* Route all context bank interrupts to non-secure interrupt */
+ mmio_write_32(APPS_SMMU_INTR_SEL_NS, APPS_SMMU_INTR_SEL_NS_EN_ALL);
+
+ /* Disable configuration clock again */
+ mmio_clrbits_32(GCC_APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, SMMU_CFG_CLK_ENA);
+}
+
+void bl31_platform_setup(void)
+{
+ INFO("BL31: Platform setup start\n");
+ generic_delay_timer_init();
+ msm8916_configure_timer();
+ msm8916_gicv2_init();
+ msm8916_configure_cpu_pm();
+ msm8916_configure_smmu();
+ INFO("BL31: Platform setup done\n");
+}
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+ switch (type) {
+ case SECURE:
+ return &image_ep_info.bl32;
+ case NON_SECURE:
+ return &image_ep_info.bl33;
+ default:
+ assert(sec_state_is_valid(type));
+ return NULL;
+ }
+}
diff --git a/plat/qti/msm8916/msm8916_cpu_boot.c b/plat/qti/msm8916/msm8916_cpu_boot.c
new file mode 100644
index 0000000..b3f51f6
--- /dev/null
+++ b/plat/qti/msm8916/msm8916_cpu_boot.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <msm8916_mmap.h>
+#include "msm8916_pm.h"
+
+#define CPU_PWR_CTL 0x4
+#define APC_PWR_GATE_CTL 0x14
+
+#define CPU_PWR_CTL_CLAMP BIT_32(0)
+#define CPU_PWR_CTL_CORE_MEM_CLAMP BIT_32(1)
+#define CPU_PWR_CTL_L1_RST_DIS BIT_32(2)
+#define CPU_PWR_CTL_CORE_MEM_HS BIT_32(3)
+#define CPU_PWR_CTL_CORE_RST BIT_32(4)
+#define CPU_PWR_CTL_COREPOR_RST BIT_32(5)
+#define CPU_PWR_CTL_GATE_CLK BIT_32(6)
+#define CPU_PWR_CTL_CORE_PWRD_UP BIT_32(7)
+
+#define APC_PWR_GATE_CTL_GHDS_EN BIT_32(0)
+#define APC_PWR_GATE_CTL_GHDS_CNT(cnt) ((cnt) << 24)
+
+/* Boot a secondary CPU core for the first time. */
+void msm8916_cpu_boot(unsigned int core)
+{
+ uintptr_t acs = APCS_ALIAS_ACS(core);
+ uint32_t pwr_ctl;
+
+ pwr_ctl = CPU_PWR_CTL_CLAMP | CPU_PWR_CTL_CORE_MEM_CLAMP |
+ CPU_PWR_CTL_CORE_RST | CPU_PWR_CTL_COREPOR_RST;
+ mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl);
+ dsb();
+
+ mmio_write_32(acs + APC_PWR_GATE_CTL, APC_PWR_GATE_CTL_GHDS_EN |
+ APC_PWR_GATE_CTL_GHDS_CNT(16));
+ dsb();
+ udelay(2);
+
+ pwr_ctl &= ~CPU_PWR_CTL_CORE_MEM_CLAMP;
+ mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl);
+ dsb();
+
+ pwr_ctl |= CPU_PWR_CTL_CORE_MEM_HS;
+ mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl);
+ dsb();
+ udelay(2);
+
+ pwr_ctl &= ~CPU_PWR_CTL_CLAMP;
+ mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl);
+ dsb();
+ udelay(2);
+
+ pwr_ctl &= ~(CPU_PWR_CTL_CORE_RST | CPU_PWR_CTL_COREPOR_RST);
+ mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl);
+ dsb();
+
+ pwr_ctl |= CPU_PWR_CTL_CORE_PWRD_UP;
+ mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl);
+ dsb();
+}
diff --git a/plat/qti/msm8916/msm8916_gicv2.c b/plat/qti/msm8916/msm8916_gicv2.c
new file mode 100644
index 0000000..25a6628
--- /dev/null
+++ b/plat/qti/msm8916/msm8916_gicv2.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+
+#include "msm8916_gicv2.h"
+#include <msm8916_mmap.h>
+
+#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_PHY_TIMER (16 + 2) /* PPI #2 */
+
+static const interrupt_prop_t msm8916_interrupt_props[] = {
+ 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),
+ INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,
+ GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+};
+
+static const gicv2_driver_data_t msm8916_gic_data = {
+ .gicd_base = APCS_QGIC2_GICD,
+ .gicc_base = APCS_QGIC2_GICC,
+ .interrupt_props = msm8916_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(msm8916_interrupt_props),
+};
+
+void msm8916_gicv2_init(void)
+{
+ gicv2_driver_init(&msm8916_gic_data);
+ gicv2_distif_init();
+ gicv2_pcpu_distif_init();
+ gicv2_cpuif_enable();
+}
diff --git a/plat/qti/msm8916/msm8916_gicv2.h b/plat/qti/msm8916/msm8916_gicv2.h
new file mode 100644
index 0000000..99db0d3
--- /dev/null
+++ b/plat/qti/msm8916/msm8916_gicv2.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MSM8916_GICV2_H
+#define MSM8916_GICV2_H
+
+void msm8916_gicv2_init(void);
+
+#endif /* MSM8916_GICV2_H */
diff --git a/plat/qti/msm8916/msm8916_pm.c b/plat/qti/msm8916/msm8916_pm.c
new file mode 100644
index 0000000..6891e38
--- /dev/null
+++ b/plat/qti/msm8916/msm8916_pm.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include <msm8916_mmap.h>
+#include "msm8916_pm.h"
+
+static int msm8916_pwr_domain_on(u_register_t mpidr)
+{
+ unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
+
+ VERBOSE("PSCI: Booting CPU %d\n", core);
+ msm8916_cpu_boot(core);
+
+ return PSCI_E_SUCCESS;
+}
+
+static void msm8916_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ gicv2_pcpu_distif_init();
+ gicv2_cpuif_enable();
+}
+
+static void __dead2 msm8916_system_reset(void)
+{
+ mmio_write_32(MPM_PS_HOLD, 0);
+ mdelay(1000);
+
+ ERROR("PSCI: System reset failed\n");
+ panic();
+}
+
+static const plat_psci_ops_t msm8916_psci_ops = {
+ .pwr_domain_on = msm8916_pwr_domain_on,
+ .pwr_domain_on_finish = msm8916_pwr_domain_on_finish,
+ .system_off = msm8916_system_reset,
+ .system_reset = msm8916_system_reset,
+};
+
+/* Defined and used in msm8916_helpers.S */
+extern uintptr_t msm8916_entry_point;
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const plat_psci_ops_t **psci_ops)
+{
+ msm8916_entry_point = sec_entrypoint;
+ *psci_ops = &msm8916_psci_ops;
+ return 0;
+}
diff --git a/plat/qti/msm8916/msm8916_pm.h b/plat/qti/msm8916/msm8916_pm.h
new file mode 100644
index 0000000..5473bfa
--- /dev/null
+++ b/plat/qti/msm8916/msm8916_pm.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MSM8916_PM_H
+#define MSM8916_PM_H
+
+void msm8916_cpu_boot(unsigned int core);
+
+#endif /* MSM8916_PM_H */
diff --git a/plat/qti/msm8916/msm8916_topology.c b/plat/qti/msm8916/msm8916_topology.c
new file mode 100644
index 0000000..4d0ed8f
--- /dev/null
+++ b/plat/qti/msm8916/msm8916_topology.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+static const unsigned char plat_power_domain_tree_desc[PLAT_MAX_PWR_LVL + 1] = {
+ PLATFORM_SYSTEM_COUNT,
+ PLATFORM_CLUSTER_COUNT,
+ PLATFORM_MAX_CPUS_PER_CLUSTER,
+};
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+ unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
+
+ if (MPIDR_AFFLVL3_VAL(mpidr) > 0 ||
+ MPIDR_AFFLVL2_VAL(mpidr) > 0 ||
+ MPIDR_AFFLVL1_VAL(mpidr) > 0 ||
+ core >= PLATFORM_MAX_CPUS_PER_CLUSTER) {
+ return -1;
+ }
+
+ return core;
+}
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ return plat_power_domain_tree_desc;
+}
diff --git a/plat/qti/msm8916/platform.mk b/plat/qti/msm8916/platform.mk
new file mode 100644
index 0000000..e516cea
--- /dev/null
+++ b/plat/qti/msm8916/platform.mk
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include drivers/arm/gic/v2/gicv2.mk
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_BL_COMMON_SOURCES := ${XLAT_TABLES_LIB_SRCS}
+
+PLAT_INCLUDES := -Iinclude/plat/arm/common/${ARCH} \
+ -Iplat/qti/msm8916/include
+
+BL31_SOURCES += ${GICV2_SOURCES} \
+ 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 \
+ plat/qti/msm8916/msm8916_bl31_setup.c \
+ plat/qti/msm8916/msm8916_cpu_boot.c \
+ plat/qti/msm8916/msm8916_gicv2.c \
+ plat/qti/msm8916/msm8916_pm.c \
+ plat/qti/msm8916/msm8916_topology.c \
+ plat/qti/msm8916/${ARCH}/msm8916_helpers.S \
+ plat/qti/msm8916/${ARCH}/uartdm_console.S
+
+# Only BL31 is supported at the moment and is entered on a single CPU
+RESET_TO_BL31 := 1
+COLD_BOOT_SINGLE_CPU := 1
+
+# Build config flags
+# ------------------
+BL31_BASE ?= 0x86500000
+BL32_BASE ?= 0x86000000
+PRELOADED_BL33_BASE ?= 0x8f600000
+
+# Have different sections for code and rodata
+SEPARATE_CODE_AND_RODATA := 1
+
+# Single cluster
+WARMBOOT_ENABLE_DCACHE_EARLY := 1
+
+# Disable features unsupported in ARMv8.0
+ENABLE_AMU := 0
+ENABLE_SPE_FOR_LOWER_ELS := 0
+ENABLE_SVE_FOR_NS := 0
+
+# MSM8916 uses ARM Cortex-A53 r0p0 so likely all the errata apply
+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 := 0 # Workaround works only for >= r0p3
+ERRATA_A53_1530924 := 1
+
+$(eval $(call add_define,BL31_BASE))
+$(eval $(call add_define,BL32_BASE))
diff --git a/plat/qti/qtiseclib/inc/qtiseclib_cb_interface.h b/plat/qti/qtiseclib/inc/qtiseclib_cb_interface.h
new file mode 100644
index 0000000..deef41c
--- /dev/null
+++ b/plat/qti/qtiseclib/inc/qtiseclib_cb_interface.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QTISECLIB_CB_INTERFACE_H
+#define QTISECLIB_CB_INTERFACE_H
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <qtiseclib_defs.h>
+
+/* Standard Library API's */
+void *qtiseclib_cb_memcpy(void *dst, const void *src, size_t len);
+int qtiseclib_cb_strcmp(const char *s1, const char *s2);
+void *qtiseclib_cb_memset(void *s, int c, size_t n);
+void *qtiseclib_cb_memmove(void *dest, const void *src, size_t n);
+
+#define QTISECLIB_CB_ERROR(...) qtiseclib_cb_log(QTISECLIB_LOG_LEVEL_ERROR, __VA_ARGS__)
+#define QTISECLIB_CB_NOTICE(...) qtiseclib_cb_log(QTISECLIB_LOG_LEVEL_NOTICE, __VA_ARGS__)
+#define QTISECLIB_CB_WARN(...) qtiseclib_cb_log(QTISECLIB_LOG_LEVEL_WARNING, __VA_ARGS__)
+#define QTISECLIB_CB_INFO(...) qtiseclib_cb_log(QTISECLIB_LOG_LEVEL_INFO, __VA_ARGS__)
+
+void qtiseclib_cb_log(unsigned int loglvl, const char *fmt, ...);
+
+void qtiseclib_cb_spin_lock(qtiseclib_cb_spinlock_t *lock);
+void qtiseclib_cb_spin_unlock(qtiseclib_cb_spinlock_t *lock);
+
+unsigned int qtiseclib_cb_plat_my_core_pos(void);
+int qtiseclib_cb_plat_core_pos_by_mpidr(u_register_t mpidr);
+unsigned int qtiseclib_cb_plat_my_cluster_pos(void);
+
+/* GIC platform wrappers */
+void qtiseclib_cb_gic_pcpu_init(void);
+void qtiseclib_cb_ic_raise_sgi(int sgi_num, u_register_t target);
+void qtiseclib_cb_set_spi_routing(unsigned int id, unsigned int irm,
+ u_register_t target);
+/* Crash reporting api's wrappers */
+void qtiseclib_cb_switch_console_to_crash_state(void);
+
+void qtiseclib_cb_udelay(uint32_t usec);
+
+void qtiseclib_cb_console_flush(void);
+
+#if QTI_SDI_BUILD
+int qtiseclib_cb_mmap_remove_dynamic_region(uintptr_t base_va, size_t size);
+int qtiseclib_cb_mmap_add_dynamic_region(unsigned long long base_pa,
+ size_t size,
+ qtiseclib_mmap_attr_t attr);
+
+void qtiseclib_cb_flush_dcache_all(void);
+void qtiseclib_cb_get_ns_ctx(qtiseclib_dbg_a64_ctxt_regs_type *ns_ctx);
+#endif
+
+#endif /* QTISECLIB_CB_INTERFACE_H */
diff --git a/plat/qti/qtiseclib/inc/qtiseclib_defs.h b/plat/qti/qtiseclib/inc/qtiseclib_defs.h
new file mode 100644
index 0000000..2afefe1
--- /dev/null
+++ b/plat/qti/qtiseclib/inc/qtiseclib_defs.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QTISECLIB_DEFS_H
+#define QTISECLIB_DEFS_H
+
+#include <stdint.h>
+
+#ifndef u_register_t
+typedef uintptr_t u_register_t;
+#endif
+
+/*
+ * Different Log Level supported in qtiseclib.
+ * TODO: Currently no filtering done on QTISECLIB logs.
+ */
+#define QTISECLIB_LOG_LEVEL_NONE 0
+#define QTISECLIB_LOG_LEVEL_ERROR 10
+#define QTISECLIB_LOG_LEVEL_NOTICE 20
+#define QTISECLIB_LOG_LEVEL_WARNING 30
+#define QTISECLIB_LOG_LEVEL_INFO 40
+#define QTISECLIB_LOG_LEVEL_VERBOSE 50
+
+#define QTI_GICV3_IRM_PE 0
+#define QTI_GICV3_IRM_ANY 1
+
+/* Common interrupt number/ID defs. */
+#define QTISECLIB_INT_ID_RESET_SGI (0xf)
+#define QTISECLIB_INT_ID_CPU_WAKEUP_SGI (0x8)
+
+#define QTISECLIB_INT_INVALID_INT_NUM (0xFFFFFFFFU)
+
+typedef struct qtiseclib_cb_spinlock {
+ volatile uint32_t lock;
+} qtiseclib_cb_spinlock_t;
+
+#if QTI_SDI_BUILD
+/* External CPU Dump Structure - 64 bit EL */
+typedef struct {
+ uint64_t x0;
+ uint64_t x1;
+ uint64_t x2;
+ uint64_t x3;
+ uint64_t x4;
+ uint64_t x5;
+ uint64_t x6;
+ uint64_t x7;
+ uint64_t x8;
+ uint64_t x9;
+ uint64_t x10;
+ uint64_t x11;
+ uint64_t x12;
+ uint64_t x13;
+ uint64_t x14;
+ uint64_t x15;
+ uint64_t x16;
+ uint64_t x17;
+ uint64_t x18;
+ uint64_t x19;
+ uint64_t x20;
+ uint64_t x21;
+ uint64_t x22;
+ uint64_t x23;
+ uint64_t x24;
+ uint64_t x25;
+ uint64_t x26;
+ uint64_t x27;
+ uint64_t x28;
+ uint64_t x29;
+ uint64_t x30;
+ uint64_t pc;
+ uint64_t currentEL;
+ uint64_t sp_el3;
+ uint64_t elr_el3;
+ uint64_t spsr_el3;
+ uint64_t sp_el2;
+ uint64_t elr_el2;
+ uint64_t spsr_el2;
+ uint64_t sp_el1;
+ uint64_t elr_el1;
+ uint64_t spsr_el1;
+ uint64_t sp_el0;
+ uint64_t __reserved1;
+ uint64_t __reserved2;
+ uint64_t __reserved3;
+ uint64_t __reserved4;
+ uint64_t __reserved5;
+ uint64_t __reserved6;
+ uint64_t __reserved7;
+ uint64_t __reserved8;
+} qtiseclib_dbg_a64_ctxt_regs_type;
+
+typedef enum qtiseclib_mmap_attr_s {
+ QTISECLIB_MAP_NS_RO_XN_DATA = 1,
+ QTISECLIB_MAP_RW_XN_NC_DATA = 2,
+ QTISECLIB_MAP_RW_XN_DATA = 3,
+} qtiseclib_mmap_attr_t;
+
+#endif /* QTI_SDI_BUILD */
+
+#endif /* QTISECLIB_DEFS_H */
diff --git a/plat/qti/qtiseclib/inc/qtiseclib_interface.h b/plat/qti/qtiseclib/inc/qtiseclib_interface.h
new file mode 100644
index 0000000..babed1b
--- /dev/null
+++ b/plat/qti/qtiseclib/inc/qtiseclib_interface.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QTISECLIB_INTERFACE_H
+#define QTISECLIB_INTERFACE_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <qtiseclib_defs.h>
+
+typedef struct memprot_ipa_info_s {
+ uint64_t mem_addr;
+ uint64_t mem_size;
+} memprot_info_t;
+
+typedef struct memprot_dst_vm_perm_info_s {
+ uint32_t dst_vm;
+ uint32_t dst_vm_perm;
+ uint64_t ctx;
+ uint32_t ctx_size;
+} memprot_dst_vm_perm_info_t;
+
+/*
+ * QTISECLIB Published API's.
+ */
+
+/*
+ * Assembly API's
+ */
+
+/*
+ * CPUSS common reset handler for all CPU wake up (both cold & warm boot).
+ * Executes on all core. This API assume serialization across CPU
+ * already taken care before invoking.
+ *
+ * Clobbers: x0 - x17, x30
+ */
+void qtiseclib_cpuss_reset_asm(uint32_t bl31_cold_boot_state);
+
+/*
+ * Execute CPU (Kryo4 gold) specific reset handler / system initialization.
+ * This takes care of executing required CPU errata's.
+ *
+ * Clobbers: x0 - x16
+ */
+void qtiseclib_kryo4_gold_reset_asm(void);
+
+/*
+ * Execute CPU (Kryo46 gold) specific reset handler / system initialization.
+ * This takes care of executing required CPU errata's.
+ *
+ * Clobbers: x0 - x16
+ */
+void qtiseclib_kryo6_gold_reset_asm(void);
+
+/*
+ * Execute CPU (Kryo4 silver) specific reset handler / system initialization.
+ * This takes care of executing required CPU errata's.
+ *
+ * Clobbers: x0 - x16
+ */
+void qtiseclib_kryo4_silver_reset_asm(void);
+
+/*
+ * Execute CPU (Kryo6 silver) specific reset handler / system initialization.
+ * This takes care of executing required CPU errata's.
+ *
+ * Clobbers: x0 - x16
+ */
+void qtiseclib_kryo6_silver_reset_asm(void);
+
+/*
+ * C Api's
+ */
+void qtiseclib_bl31_platform_setup(void);
+void qtiseclib_invoke_isr(uint32_t irq, void *handle);
+void qtiseclib_panic(void);
+
+int qtiseclib_mem_assign(const memprot_info_t *mem_info,
+ uint32_t mem_info_list_cnt,
+ const uint32_t *source_vm_list,
+ uint32_t src_vm_list_cnt,
+ const memprot_dst_vm_perm_info_t *dest_vm_list,
+ uint32_t dst_vm_list_cnt);
+
+int qtiseclib_psci_init(uintptr_t warmboot_entry);
+int qtiseclib_psci_node_power_on(u_register_t mpidr);
+void qtiseclib_psci_node_on_finish(const uint8_t *states);
+void qtiseclib_psci_cpu_standby(uint8_t pwr_state);
+void qtiseclib_psci_node_power_off(const uint8_t *states);
+void qtiseclib_psci_node_suspend(const uint8_t *states);
+void qtiseclib_psci_node_suspend_finish(const uint8_t *states);
+void qtiseclib_disable_cluster_coherency(uint8_t state);
+
+#endif /* QTISECLIB_INTERFACE_H */
diff --git a/plat/qti/qtiseclib/inc/sc7180/qtiseclib_defs_plat.h b/plat/qti/qtiseclib/inc/sc7180/qtiseclib_defs_plat.h
new file mode 100644
index 0000000..3ecee20
--- /dev/null
+++ b/plat/qti/qtiseclib/inc/sc7180/qtiseclib_defs_plat.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QTISECLIB_DEFS_PLAT_H
+#define QTISECLIB_DEFS_PLAT_H
+
+#define QTISECLIB_PLAT_CLUSTER_COUNT 1
+#define QTISECLIB_PLAT_CORE_COUNT 8
+
+#define BL31_BASE 0x80b00000
+#define BL31_SIZE 0x00100000
+
+/* Chipset specific secure interrupt number/ID defs. */
+#define QTISECLIB_INT_ID_SEC_WDOG_BARK (0x204)
+#define QTISECLIB_INT_ID_NON_SEC_WDOG_BITE (0x21)
+
+#define QTISECLIB_INT_ID_VMIDMT_ERR_CLT_SEC (0xE6)
+#define QTISECLIB_INT_ID_VMIDMT_ERR_CLT_NONSEC (0xE7)
+#define QTISECLIB_INT_ID_VMIDMT_ERR_CFG_SEC (0xE8)
+#define QTISECLIB_INT_ID_VMIDMT_ERR_CFG_NONSEC (0xE9)
+
+#define QTISECLIB_INT_ID_XPU_SEC (0xE3)
+#define QTISECLIB_INT_ID_XPU_NON_SEC (0xE4)
+
+#define QTISECLIB_INT_ID_A2_NOC_ERROR (0x194)
+#define QTISECLIB_INT_ID_CONFIG_NOC_ERROR (0xE2)
+#define QTISECLIB_INT_ID_DC_NOC_ERROR (0x122)
+#define QTISECLIB_INT_ID_MEM_NOC_ERROR (0x6C)
+#define QTISECLIB_INT_ID_SYSTEM_NOC_ERROR (0xC6)
+#define QTISECLIB_INT_ID_MMSS_NOC_ERROR (0xBA)
+
+#endif /* QTISECLIB_DEFS_PLAT_H */
diff --git a/plat/qti/qtiseclib/inc/sc7280/qtiseclib_defs_plat.h b/plat/qti/qtiseclib/inc/sc7280/qtiseclib_defs_plat.h
new file mode 100644
index 0000000..b3d309f
--- /dev/null
+++ b/plat/qti/qtiseclib/inc/sc7280/qtiseclib_defs_plat.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __QTISECLIB_DEFS_PLAT_H__
+#define __QTISECLIB_DEFS_PLAT_H__
+
+#define QTISECLIB_PLAT_CLUSTER_COUNT 1
+#define QTISECLIB_PLAT_CORE_COUNT 8
+
+#define BL31_BASE 0xC0000000
+#define BL31_SIZE 0x00100000
+
+/*----------------------------------------------------------------------------*/
+/* AOP CMD DB address space for mapping */
+/*----------------------------------------------------------------------------*/
+#define QTI_AOP_CMD_DB_BASE 0x80860000
+#define QTI_AOP_CMD_DB_SIZE 0x00020000
+
+/* Chipset specific secure interrupt number/ID defs. */
+#define QTISECLIB_INT_ID_SEC_WDOG_BARK (0x204)
+#define QTISECLIB_INT_ID_NON_SEC_WDOG_BITE (0x21)
+
+#define QTISECLIB_INT_ID_VMIDMT_ERR_CLT_SEC (0xE6)
+#define QTISECLIB_INT_ID_VMIDMT_ERR_CLT_NONSEC (0xE7)
+#define QTISECLIB_INT_ID_VMIDMT_ERR_CFG_SEC (0xE8)
+#define QTISECLIB_INT_ID_VMIDMT_ERR_CFG_NONSEC (0xE9)
+
+#define QTISECLIB_INT_ID_XPU_SEC (0xE3)
+#define QTISECLIB_INT_ID_XPU_NON_SEC (0xE4)
+
+//NOC INterrupt
+#define QTISECLIB_INT_ID_A1_NOC_ERROR (0xC9)
+#define QTISECLIB_INT_ID_A2_NOC_ERROR (0xEA)
+#define QTISECLIB_INT_ID_CONFIG_NOC_ERROR (0xE2)
+#define QTISECLIB_INT_ID_DC_NOC_ERROR (0x122)
+#define QTISECLIB_INT_ID_MEM_NOC_ERROR (0x6C)
+#define QTISECLIB_INT_ID_SYSTEM_NOC_ERROR (0xC8)
+#define QTISECLIB_INT_ID_MMSS_NOC_ERROR (0xBA)
+#define QTISECLIB_INT_ID_LPASS_AGNOC_ERROR (0x143)
+#define QTISECLIB_INT_ID_NSP_NOC_ERROR (0x1CE)
+
+#endif /* __QTISECLIB_DEFS_PLAT_H__ */
diff --git a/plat/qti/qtiseclib/src/qtiseclib_cb_interface.c b/plat/qti/qtiseclib/src/qtiseclib_cb_interface.c
new file mode 100644
index 0000000..c4cd259
--- /dev/null
+++ b/plat/qti/qtiseclib/src/qtiseclib_cb_interface.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <context.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/delay_timer.h>
+#include <lib/coreboot.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/spinlock.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <platform.h>
+#include <qti_plat.h>
+#include <qtiseclib_cb_interface.h>
+
+void *qtiseclib_cb_memcpy(void *dst, const void *src, size_t len)
+{
+ return memcpy(dst, src, len);
+}
+
+int qtiseclib_cb_strcmp(const char *s1, const char *s2)
+{
+ return strcmp(s1, s2);
+}
+
+void *qtiseclib_cb_memset(void *s, int c, size_t n)
+{
+ return memset(s, c, n);
+}
+
+void *qtiseclib_cb_memmove(void *dest, const void *src, size_t n)
+{
+ return memmove(dest, src, n);
+}
+
+/* Printing logs below or equal LOG_LEVEL from QTISECLIB. */
+void qtiseclib_cb_log(unsigned int loglvl, const char *fmt, ...)
+{
+ if (loglvl <= LOG_LEVEL) {
+ va_list argp;
+ static spinlock_t qti_log_lock;
+ uint64_t uptime = read_cntpct_el0();
+
+ va_start(argp, fmt);
+
+ spin_lock(&qti_log_lock);
+ printf("QTISECLIB [%x%08x]",
+ (uint32_t) ((uptime >> 32) & 0xFFFFFFFF),
+ (uint32_t) (uptime & 0xFFFFFFFF));
+ vprintf(fmt, argp);
+ putchar('\n');
+ spin_unlock(&qti_log_lock);
+
+ va_end(argp);
+ }
+}
+
+void qtiseclib_cb_spin_lock(qtiseclib_cb_spinlock_t *lock)
+{
+ spin_lock((spinlock_t *) lock);
+}
+
+void qtiseclib_cb_spin_unlock(qtiseclib_cb_spinlock_t *lock)
+{
+ spin_unlock((spinlock_t *) lock);
+}
+
+unsigned int qtiseclib_cb_plat_my_core_pos(void)
+{
+ return plat_my_core_pos();
+}
+
+int qtiseclib_cb_plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+ return plat_core_pos_by_mpidr(mpidr);
+}
+
+unsigned int qtiseclib_cb_plat_my_cluster_pos(void)
+{
+ return plat_qti_my_cluster_pos();
+}
+
+/* GIC platform functions */
+void qtiseclib_cb_gic_pcpu_init(void)
+{
+ plat_qti_gic_pcpu_init();
+}
+
+void qtiseclib_cb_ic_raise_sgi(int sgi_num, u_register_t target)
+{
+ plat_ic_raise_el3_sgi(sgi_num, target);
+}
+
+void qtiseclib_cb_set_spi_routing(unsigned int id, unsigned int irm,
+ u_register_t target)
+{
+ assert(QTI_GICV3_IRM_PE == GICV3_IRM_PE);
+ assert(QTI_GICV3_IRM_ANY == GICV3_IRM_ANY);
+ gic_set_spi_routing(id, irm, target);
+}
+
+/* Crash reporting api's wrappers */
+void qtiseclib_cb_switch_console_to_crash_state(void)
+{
+ console_switch_state(CONSOLE_FLAG_CRASH);
+}
+
+void qtiseclib_cb_udelay(uint32_t usec)
+{
+ udelay(usec);
+}
+
+void qtiseclib_cb_console_flush(void)
+{
+ return console_flush();
+}
+
+#if QTI_SDI_BUILD
+void qtiseclib_cb_get_ns_ctx(qtiseclib_dbg_a64_ctxt_regs_type *qti_ns_ctx)
+{
+ void *ctx;
+
+ ctx = cm_get_context(NON_SECURE);
+ if (ctx) {
+ /* nothing to be done w/o ns context */
+ return;
+ }
+
+ qti_ns_ctx->spsr_el3 =
+ read_ctx_reg(get_el3state_ctx(ctx), CTX_SPSR_EL3);
+ qti_ns_ctx->elr_el3 = read_ctx_reg(get_el3state_ctx(ctx), CTX_ELR_EL3);
+
+ qti_ns_ctx->spsr_el1 =
+ read_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SPSR_EL1);
+ qti_ns_ctx->elr_el1 =
+ read_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_ELR_EL1);
+ qti_ns_ctx->sp_el1 = read_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SP_EL1);
+
+ qti_ns_ctx->x0 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X0);
+ qti_ns_ctx->x1 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X1);
+ qti_ns_ctx->x2 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X2);
+ qti_ns_ctx->x3 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X3);
+ qti_ns_ctx->x4 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X4);
+ qti_ns_ctx->x5 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X5);
+ qti_ns_ctx->x6 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X6);
+ qti_ns_ctx->x7 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X7);
+ qti_ns_ctx->x8 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X8);
+ qti_ns_ctx->x9 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X9);
+ qti_ns_ctx->x10 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X10);
+ qti_ns_ctx->x11 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X11);
+ qti_ns_ctx->x12 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X12);
+ qti_ns_ctx->x13 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X13);
+ qti_ns_ctx->x14 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X14);
+ qti_ns_ctx->x15 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X15);
+ qti_ns_ctx->x16 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X16);
+ qti_ns_ctx->x17 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X17);
+ qti_ns_ctx->x18 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X18);
+ qti_ns_ctx->x19 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X19);
+ qti_ns_ctx->x20 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X20);
+ qti_ns_ctx->x21 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X21);
+ qti_ns_ctx->x22 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X22);
+ qti_ns_ctx->x23 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X23);
+ qti_ns_ctx->x24 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X24);
+ qti_ns_ctx->x25 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X25);
+ qti_ns_ctx->x26 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X26);
+ qti_ns_ctx->x27 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X27);
+ qti_ns_ctx->x28 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X28);
+ qti_ns_ctx->x29 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X29);
+ qti_ns_ctx->x30 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_LR);
+ qti_ns_ctx->sp_el0 =
+ read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_SP_EL0);
+}
+
+void qtiseclib_cb_flush_dcache_all(void)
+{
+ dcsw_op_all(DCCISW);
+}
+
+int qtiseclib_cb_mmap_add_dynamic_region(unsigned long long base_pa,
+ size_t size,
+ qtiseclib_mmap_attr_t attr)
+{
+ unsigned int l_attr = 0;
+
+ if (attr == QTISECLIB_MAP_NS_RO_XN_DATA) {
+ l_attr = MT_NS | MT_RO | MT_EXECUTE_NEVER;
+ } else if (attr == QTISECLIB_MAP_RW_XN_NC_DATA) {
+ l_attr = MT_RW | MT_NON_CACHEABLE | MT_EXECUTE_NEVER;
+ } else if (attr == QTISECLIB_MAP_RW_XN_DATA) {
+ l_attr = MT_RW | MT_EXECUTE_NEVER;
+ }
+ return qti_mmap_add_dynamic_region(base_pa, size, l_attr);
+}
+
+int qtiseclib_cb_mmap_remove_dynamic_region(uintptr_t base_va, size_t size)
+{
+ return qti_mmap_remove_dynamic_region(base_va, size);
+}
+#endif
+
diff --git a/plat/qti/qtiseclib/src/qtiseclib_interface_stub.c b/plat/qti/qtiseclib/src/qtiseclib_interface_stub.c
new file mode 100644
index 0000000..cdaa0a7
--- /dev/null
+++ b/plat/qti/qtiseclib/src/qtiseclib_interface_stub.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include <qtiseclib_defs.h>
+#include <qtiseclib_interface.h>
+
+/*
+ * This file contains dummy implementation of QTISECLIB Published API's.
+ * which will be used to compile PLATFORM successfully when
+ * qtiseclib is not available
+ */
+
+/*
+ * CPUSS common reset handler for all CPU wake up (both cold & warm boot).
+ * Executes on all core. This API assume serialization across CPU
+ * already taken care before invoking.
+ *
+ * Clobbers: x0 - x17, x30
+ */
+void qtiseclib_cpuss_reset_asm(uint32_t bl31_cold_boot_state)
+{
+}
+
+/*
+ * Execute CPU (Kryo4 gold) specific reset handler / system initialization.
+ * This takes care of executing required CPU errata's.
+ *
+ * Clobbers: x0 - x16
+ */
+void qtiseclib_kryo4_gold_reset_asm(void)
+{
+}
+
+/*
+ * Execute CPU (Kryo4 silver) specific reset handler / system initialization.
+ * This takes care of executing required CPU errata's.
+ *
+ * Clobbers: x0 - x16
+ */
+void qtiseclib_kryo4_silver_reset_asm(void)
+{
+}
+
+/*
+ * Execute CPU (Kryo4 gold) specific reset handler / system initialization.
+ * This takes care of executing required CPU errata's.
+ *
+ * Clobbers: x0 - x16
+ */
+void qtiseclib_kryo6_gold_reset_asm(void)
+{
+}
+
+
+void qtiseclib_kryo6_silver_reset_asm(void)
+{
+}
+
+/*
+ * C Api's
+ */
+void qtiseclib_bl31_platform_setup(void)
+{
+ ERROR("Please use QTISECLIB_PATH while building TF-A\n");
+ ERROR("Please refer docs/plat/qti.rst for more details.\n");
+ panic();
+}
+
+void qtiseclib_invoke_isr(uint32_t irq, void *handle)
+{
+}
+
+void qtiseclib_panic(void)
+{
+}
+
+int
+qtiseclib_mem_assign(const memprot_info_t *mem_info,
+ uint32_t mem_info_list_cnt,
+ const uint32_t *source_vm_list,
+ uint32_t src_vm_list_cnt,
+ const memprot_dst_vm_perm_info_t *dest_vm_list,
+ uint32_t dst_vm_list_cnt)
+{
+ return 0;
+}
+
+int qtiseclib_psci_init(uintptr_t warmboot_entry)
+{
+ return 0;
+}
+
+int qtiseclib_psci_node_power_on(u_register_t mpidr)
+{
+ return 0;
+}
+
+void qtiseclib_psci_node_on_finish(const uint8_t *states)
+{
+}
+
+void qtiseclib_psci_cpu_standby(uint8_t pwr_state)
+{
+}
+
+void qtiseclib_psci_node_power_off(const uint8_t *states)
+{
+}
+
+void qtiseclib_psci_node_suspend(const uint8_t *states)
+{
+}
+
+void qtiseclib_psci_node_suspend_finish(const uint8_t *states)
+{
+}
+
+void qtiseclib_disable_cluster_coherency(uint8_t state)
+{
+}
+
diff --git a/plat/qti/sc7180/inc/platform_def.h b/plat/qti/sc7180/inc/platform_def.h
new file mode 100644
index 0000000..b69dfd9
--- /dev/null
+++ b/plat/qti/sc7180/inc/platform_def.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+/* Enable the dynamic translation tables library. */
+#define PLAT_XLAT_TABLES_DYNAMIC 1
+
+#include <common_def.h>
+
+#include <qti_board_def.h>
+#include <qtiseclib_defs_plat.h>
+
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/*
+ * MPIDR_PRIMARY_CPU
+ * You just need to have the correct core_affinity_val i.e. [7:0]
+ * and cluster_affinity_val i.e. [15:8]
+ * the other bits will be ignored
+ */
+/*----------------------------------------------------------------------------*/
+#define MPIDR_PRIMARY_CPU 0x0000
+/*----------------------------------------------------------------------------*/
+
+#define QTI_PWR_LVL0 MPIDR_AFFLVL0
+#define QTI_PWR_LVL1 MPIDR_AFFLVL1
+#define QTI_PWR_LVL2 MPIDR_AFFLVL2
+#define QTI_PWR_LVL3 MPIDR_AFFLVL3
+
+/*
+ * Macros for local power states encoded by State-ID field
+ * within the power-state parameter.
+ */
+/* Local power state for power domains in Run state. */
+#define QTI_LOCAL_STATE_RUN 0
+/*
+ * Local power state for clock-gating. Valid only for CPU and not cluster power
+ * domains
+ */
+#define QTI_LOCAL_STATE_STB 1
+/*
+ * Local power state for retention. Valid for CPU and cluster power
+ * domains
+ */
+#define QTI_LOCAL_STATE_RET 2
+/*
+ * Local power state for OFF/power down. Valid for CPU, cluster, RSC and PDC
+ * power domains
+ */
+#define QTI_LOCAL_STATE_OFF 3
+/*
+ * Local power state for DEEPOFF/power rail down. Valid for CPU, cluster and RSC
+ * power domains
+ */
+#define QTI_LOCAL_STATE_DEEPOFF 4
+
+/*
+ * 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 QTI_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 QTI_LOCAL_STATE_DEEPOFF
+
+/******************************************************************************
+ * Required platform porting definitions common to all ARM standard platforms
+ *****************************************************************************/
+
+/*
+ * Platform specific page table and MMU setup constants.
+ */
+#define MAX_MMAP_REGIONS (PLAT_QTI_MMAP_ENTRIES)
+
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 36)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 36)
+
+#define ARM_CACHE_WRITEBACK_SHIFT 6
+
+/*
+ * 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 << ARM_CACHE_WRITEBACK_SHIFT)
+
+/*
+ * One cache line needed for bakery locks on ARM platforms
+ */
+#define PLAT_PERCPU_BAKERY_LOCK_SIZE (1 * CACHE_WRITEBACK_GRANULE)
+
+/*----------------------------------------------------------------------------*/
+/* PSCI power domain topology definitions */
+/*----------------------------------------------------------------------------*/
+/* One domain each to represent RSC and PDC level */
+#define PLAT_PDC_COUNT 1
+#define PLAT_RSC_COUNT 1
+
+/* There is one top-level FCM cluster */
+#define PLAT_CLUSTER_COUNT 1
+
+/* No. of cores in the FCM cluster */
+#define PLAT_CLUSTER0_CORE_COUNT 8
+
+#define PLATFORM_CORE_COUNT (PLAT_CLUSTER0_CORE_COUNT)
+
+#define PLAT_NUM_PWR_DOMAINS (PLAT_PDC_COUNT +\
+ PLAT_RSC_COUNT +\
+ PLAT_CLUSTER_COUNT +\
+ PLATFORM_CORE_COUNT)
+
+#define PLAT_MAX_PWR_LVL 3
+
+/*****************************************************************************/
+/* Memory mapped Generic timer interfaces */
+/*****************************************************************************/
+
+/*----------------------------------------------------------------------------*/
+/* GIC-600 constants */
+/*----------------------------------------------------------------------------*/
+#define BASE_GICD_BASE 0x17A00000
+#define BASE_GICR_BASE 0x17A60000
+#define BASE_GICC_BASE 0x0
+#define BASE_GICH_BASE 0x0
+#define BASE_GICV_BASE 0x0
+
+#define QTI_GICD_BASE BASE_GICD_BASE
+#define QTI_GICR_BASE BASE_GICR_BASE
+#define QTI_GICC_BASE BASE_GICC_BASE
+
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* UART related constants. */
+/*----------------------------------------------------------------------------*/
+/* BASE ADDRESS OF DIFFERENT REGISTER SPACES IN HW */
+#define GENI4_CFG 0x0
+#define GENI4_IMAGE_REGS 0x100
+#define GENI4_DATA 0x600
+
+/* COMMON STATUS/CONFIGURATION REGISTERS AND MASKS */
+#define GENI_STATUS_REG (GENI4_CFG + 0x00000040)
+#define GENI_STATUS_M_GENI_CMD_ACTIVE_MASK (0x1)
+#define UART_TX_TRANS_LEN_REG (GENI4_IMAGE_REGS + 0x00000170)
+/* MASTER/TX ENGINE REGISTERS */
+#define GENI_M_CMD0_REG (GENI4_DATA + 0x00000000)
+/* FIFO, STATUS REGISTERS AND MASKS */
+#define GENI_TX_FIFOn_REG (GENI4_DATA + 0x00000100)
+
+#define GENI_M_CMD_TX (0x08000000)
+
+/*----------------------------------------------------------------------------*/
+/* Device address space for mapping. Excluding starting 4K */
+/*----------------------------------------------------------------------------*/
+#define QTI_DEVICE_BASE 0x1000
+#define QTI_DEVICE_SIZE (0x80000000 - QTI_DEVICE_BASE)
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL31 at DDR as per memory map. BL31_BASE is calculated using the
+ * current BL31 debug size plus a little space for growth.
+ */
+#define BL31_LIMIT (BL31_BASE + BL31_SIZE)
+
+/*----------------------------------------------------------------------------*/
+/* AOSS registers */
+/*----------------------------------------------------------------------------*/
+#define QTI_PS_HOLD_REG 0x0C264000
+/*----------------------------------------------------------------------------*/
+/* AOP CMD DB address space for mapping */
+/*----------------------------------------------------------------------------*/
+#define QTI_AOP_CMD_DB_BASE 0x80820000
+#define QTI_AOP_CMD_DB_SIZE 0x00020000
+/*----------------------------------------------------------------------------*/
+/* SOC hw version register */
+/*----------------------------------------------------------------------------*/
+#define QTI_SOC_VERSION_MASK U(0xFFFF)
+#define QTI_SOC_REVISION_REG 0x1FC8000
+#define QTI_SOC_REVISION_MASK U(0xFFFF)
+/*----------------------------------------------------------------------------*/
+/* LC PON register offsets */
+/*----------------------------------------------------------------------------*/
+#define PON_PS_HOLD_RESET_CTL 0x85a
+#define PON_PS_HOLD_RESET_CTL2 0x85b
+/*----------------------------------------------------------------------------*/
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/qti/sc7180/inc/qti_map_chipinfo.h b/plat/qti/sc7180/inc/qti_map_chipinfo.h
new file mode 100644
index 0000000..4ab6191
--- /dev/null
+++ b/plat/qti/sc7180/inc/qti_map_chipinfo.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef QTI_MAP_CHIPINFO_H
+#define QTI_MAP_CHIPINFO_H
+
+#include <stdint.h>
+
+#include <qti_plat.h>
+
+#define QTI_JTAG_ID_REG 0x786130
+#define QTI_SOC_VERSION_MASK U(0xFFFF)
+#define QTI_SOC_REVISION_REG 0x1FC8000
+#define QTI_SOC_REVISION_MASK U(0xFFFF)
+#define QTI_JTAG_ID_SHIFT 12
+#define QTI_JTAG_ID_SC7180 U(0x012C)
+#define QTI_JTAG_ID_SC7180P U(0x0195)
+#define QTI_CHIPINFO_ID_SC7180 U(0x01A9)
+#define QTI_CHIPINFO_ID_SC7180P U(0x01EF)
+#define QTI_DEFAULT_CHIPINFO_ID U(0xFFFF)
+
+static const chip_id_info_t g_map_jtag_chipinfo_id[] = {
+ {QTI_JTAG_ID_SC7180, QTI_CHIPINFO_ID_SC7180},
+ {QTI_JTAG_ID_SC7180P, QTI_CHIPINFO_ID_SC7180P},
+};
+#endif /* QTI_MAP_CHIPINFO_H */
diff --git a/plat/qti/sc7180/inc/qti_rng_io.h b/plat/qti/sc7180/inc/qti_rng_io.h
new file mode 100644
index 0000000..f50234f
--- /dev/null
+++ b/plat/qti/sc7180/inc/qti_rng_io.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef QTI_RNG_IO_H
+#define QTI_RNG_IO_H
+
+#define SEC_PRNG_STATUS 0x00791004
+#define SEC_PRNG_STATUS_DATA_AVAIL_BMSK 0x1
+#define SEC_PRNG_DATA_OUT 0x00791000
+
+
+#endif /* QTI_RNG_IO_H */
+
diff --git a/plat/qti/sc7180/inc/qti_secure_io_cfg.h b/plat/qti/sc7180/inc/qti_secure_io_cfg.h
new file mode 100644
index 0000000..3de636d
--- /dev/null
+++ b/plat/qti/sc7180/inc/qti_secure_io_cfg.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef QTI_SECURE_IO_CFG_H
+#define QTI_SECURE_IO_CFG_H
+
+#include <stdint.h>
+
+/*
+ * List of peripheral/IO memory areas that are protected from
+ * non-secure world but not required to be secure.
+ */
+
+#define APPS_SMMU_TBU_PWR_STATUS 0x15002204
+#define APPS_SMMU_CUSTOM_CFG 0x15002300
+#define APPS_SMMU_STATS_SYNC_INV_TBU_ACK 0x150025DC
+#define APPS_SMMU_SAFE_SEC_CFG 0x15002648
+#define APPS_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR 0x15002670
+
+static const uintptr_t qti_secure_io_allowed_regs[] = {
+ APPS_SMMU_TBU_PWR_STATUS,
+ APPS_SMMU_CUSTOM_CFG,
+ APPS_SMMU_STATS_SYNC_INV_TBU_ACK,
+ APPS_SMMU_SAFE_SEC_CFG,
+ APPS_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR,
+};
+
+#endif /* QTI_SECURE_IO_CFG_H */
diff --git a/plat/qti/sc7180/platform.mk b/plat/qti/sc7180/platform.mk
new file mode 100644
index 0000000..41a08ca
--- /dev/null
+++ b/plat/qti/sc7180/platform.mk
@@ -0,0 +1,128 @@
+#
+# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Make for SC7180 QTI platform.
+
+QTI_PLAT_PATH := plat/qti
+CHIPSET := ${PLAT}
+
+# Turn On Separate code & data.
+SEPARATE_CODE_AND_RODATA := 1
+USE_COHERENT_MEM := 0
+WARMBOOT_ENABLE_DCACHE_EARLY := 1
+HW_ASSISTED_COHERENCY := 1
+
+# Disable the PSCI platform compatibility layer
+ENABLE_PLAT_COMPAT := 0
+
+#Enable errata for cortex_a55 and cortex_a76
+ERRATA_A55_1530923 := 1
+ERRATA_A76_1165522 := 1
+
+# Enable PSCI v1.0 extended state ID format
+PSCI_EXTENDED_STATE_ID := 1
+ARM_RECOM_STATE_ID_ENC := 1
+
+COLD_BOOT_SINGLE_CPU := 1
+PROGRAMMABLE_RESET_ADDRESS := 1
+
+RESET_TO_BL31 := 0
+
+MULTI_CONSOLE_API := 1
+
+QTI_SDI_BUILD := 0
+$(eval $(call assert_boolean,QTI_SDI_BUILD))
+$(eval $(call add_define,QTI_SDI_BUILD))
+
+#disable CTX_INCLUDE_AARCH32_REGS to support sc7180 gold cores
+override CTX_INCLUDE_AARCH32_REGS := 0
+WORKAROUND_CVE_2017_5715 := 0
+DYNAMIC_WORKAROUND_CVE_2018_3639 := 1
+# Enable stack protector.
+ENABLE_STACK_PROTECTOR := strong
+
+
+QTI_EXTERNAL_INCLUDES := -I${QTI_PLAT_PATH}/${CHIPSET}/inc \
+ -I${QTI_PLAT_PATH}/common/inc \
+ -I${QTI_PLAT_PATH}/common/inc/$(ARCH) \
+ -I${QTI_PLAT_PATH}/qtiseclib/inc \
+ -I${QTI_PLAT_PATH}/qtiseclib/inc/${CHIPSET} \
+
+QTI_BL31_SOURCES := $(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_helpers.S \
+ $(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_kryo4_silver.S \
+ $(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_kryo4_gold.S \
+ $(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_uart_console.S \
+ $(QTI_PLAT_PATH)/common/src/pm_ps_hold.c \
+ $(QTI_PLAT_PATH)/common/src/qti_stack_protector.c \
+ $(QTI_PLAT_PATH)/common/src/qti_common.c \
+ $(QTI_PLAT_PATH)/common/src/qti_bl31_setup.c \
+ $(QTI_PLAT_PATH)/common/src/qti_gic_v3.c \
+ $(QTI_PLAT_PATH)/common/src/qti_interrupt_svc.c \
+ $(QTI_PLAT_PATH)/common/src/qti_syscall.c \
+ $(QTI_PLAT_PATH)/common/src/qti_topology.c \
+ $(QTI_PLAT_PATH)/common/src/qti_pm.c \
+ $(QTI_PLAT_PATH)/common/src/qti_rng.c \
+ $(QTI_PLAT_PATH)/common/src/spmi_arb.c \
+ $(QTI_PLAT_PATH)/qtiseclib/src/qtiseclib_cb_interface.c \
+
+
+PLAT_INCLUDES := -Iinclude/plat/common/ \
+
+PLAT_INCLUDES += ${QTI_EXTERNAL_INCLUDES}
+
+include lib/xlat_tables_v2/xlat_tables.mk
+PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} \
+ plat/common/aarch64/crash_console_helpers.S \
+ common/desc_image_load.c \
+ lib/bl_aux_params/bl_aux_params.c \
+
+include lib/coreboot/coreboot.mk
+
+#PSCI Sources.
+PSCI_SOURCES := plat/common/plat_psci_common.c \
+
+# GIC-600 configuration
+GICV3_SUPPORT_GIC600 := 1
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+#Timer sources
+TIMER_SOURCES := drivers/delay_timer/generic_delay_timer.c \
+ drivers/delay_timer/delay_timer.c \
+
+#GIC sources.
+GIC_SOURCES := plat/common/plat_gicv3.c \
+ ${GICV3_SOURCES} \
+
+CPU_SOURCES := lib/cpus/aarch64/cortex_a76.S \
+ lib/cpus/aarch64/cortex_a55.S \
+
+BL31_SOURCES += ${QTI_BL31_SOURCES} \
+ ${PSCI_SOURCES} \
+ ${GIC_SOURCES} \
+ ${TIMER_SOURCES} \
+ ${CPU_SOURCES} \
+
+LIB_QTI_PATH := ${QTI_PLAT_PATH}/qtiseclib/lib/${CHIPSET}
+
+
+# Override this on the command line to point to the qtiseclib library which
+# will be available in coreboot.org
+QTISECLIB_PATH ?=
+
+ifeq ($(QTISECLIB_PATH),)
+# if No lib then use stub implementation for qtiseclib interface
+$(warning QTISECLIB_PATH is not provided while building, using stub implementation. \
+ Please refer docs/plat/qti.rst for more details \
+ THIS FIRMWARE WILL NOT BOOT!)
+BL31_SOURCES += plat/qti/qtiseclib/src/qtiseclib_interface_stub.c
+else
+# use library provided by QTISECLIB_PATH
+LDFLAGS += -L $(dir $(QTISECLIB_PATH))
+LDLIBS += -l$(patsubst lib%.a,%,$(notdir $(QTISECLIB_PATH)))
+endif
+
diff --git a/plat/qti/sc7280/inc/platform_def.h b/plat/qti/sc7280/inc/platform_def.h
new file mode 100644
index 0000000..48b48ac
--- /dev/null
+++ b/plat/qti/sc7280/inc/platform_def.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+/* Enable the dynamic translation tables library. */
+#define PLAT_XLAT_TABLES_DYNAMIC 1
+
+#include <common_def.h>
+
+#include <qti_board_def.h>
+#include <qtiseclib_defs_plat.h>
+
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/*
+ * MPIDR_PRIMARY_CPU
+ * You just need to have the correct core_affinity_val i.e. [7:0]
+ * and cluster_affinity_val i.e. [15:8]
+ * the other bits will be ignored
+ */
+/*----------------------------------------------------------------------------*/
+#define MPIDR_PRIMARY_CPU 0x0000
+/*----------------------------------------------------------------------------*/
+
+#define QTI_PWR_LVL0 MPIDR_AFFLVL0
+#define QTI_PWR_LVL1 MPIDR_AFFLVL1
+#define QTI_PWR_LVL2 MPIDR_AFFLVL2
+#define QTI_PWR_LVL3 MPIDR_AFFLVL3
+
+/*
+ * Macros for local power states encoded by State-ID field
+ * within the power-state parameter.
+ */
+/* Local power state for power domains in Run state. */
+#define QTI_LOCAL_STATE_RUN 0
+/*
+ * Local power state for clock-gating. Valid only for CPU and not cluster power
+ * domains
+ */
+#define QTI_LOCAL_STATE_STB 1
+/*
+ * Local power state for retention. Valid for CPU and cluster power
+ * domains
+ */
+#define QTI_LOCAL_STATE_RET 2
+/*
+ * Local power state for OFF/power down. Valid for CPU, cluster, RSC and PDC
+ * power domains
+ */
+#define QTI_LOCAL_STATE_OFF 3
+/*
+ * Local power state for DEEPOFF/power rail down. Valid for CPU, cluster and RSC
+ * power domains
+ */
+#define QTI_LOCAL_STATE_DEEPOFF 4
+
+/*
+ * 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 QTI_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 QTI_LOCAL_STATE_DEEPOFF
+
+/******************************************************************************
+ * Required platform porting definitions common to all ARM standard platforms
+ *****************************************************************************/
+
+/*
+ * Platform specific page table and MMU setup constants.
+ */
+#define MAX_MMAP_REGIONS (PLAT_QTI_MMAP_ENTRIES)
+
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 36)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 36)
+
+#define ARM_CACHE_WRITEBACK_SHIFT 6
+
+/*
+ * 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 << ARM_CACHE_WRITEBACK_SHIFT)
+
+/*
+ * One cache line needed for bakery locks on ARM platforms
+ */
+#define PLAT_PERCPU_BAKERY_LOCK_SIZE (1 * CACHE_WRITEBACK_GRANULE)
+
+/*----------------------------------------------------------------------------*/
+/* PSCI power domain topology definitions */
+/*----------------------------------------------------------------------------*/
+/* One domain each to represent RSC and PDC level */
+#define PLAT_PDC_COUNT 1
+#define PLAT_RSC_COUNT 1
+
+/* There is one top-level FCM cluster */
+#define PLAT_CLUSTER_COUNT 1
+
+/* No. of cores in the FCM cluster */
+#define PLAT_CLUSTER0_CORE_COUNT 8
+
+#define PLATFORM_CORE_COUNT (PLAT_CLUSTER0_CORE_COUNT)
+
+#define PLAT_NUM_PWR_DOMAINS (PLAT_PDC_COUNT +\
+ PLAT_RSC_COUNT +\
+ PLAT_CLUSTER_COUNT +\
+ PLATFORM_CORE_COUNT)
+
+#define PLAT_MAX_PWR_LVL 3
+
+/*****************************************************************************/
+/* Memory mapped Generic timer interfaces */
+/*****************************************************************************/
+
+/*----------------------------------------------------------------------------*/
+/* GIC-600 constants */
+/*----------------------------------------------------------------------------*/
+#define BASE_GICD_BASE 0x17A00000
+#define BASE_GICR_BASE 0x17A60000
+#define BASE_GICC_BASE 0x0
+#define BASE_GICH_BASE 0x0
+#define BASE_GICV_BASE 0x0
+
+#define QTI_GICD_BASE BASE_GICD_BASE
+#define QTI_GICR_BASE BASE_GICR_BASE
+#define QTI_GICC_BASE BASE_GICC_BASE
+
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* UART related constants. */
+/*----------------------------------------------------------------------------*/
+/* BASE ADDRESS OF DIFFERENT REGISTER SPACES IN HW */
+#define GENI4_CFG 0x0
+#define GENI4_IMAGE_REGS 0x100
+#define GENI4_DATA 0x600
+
+/* COMMON STATUS/CONFIGURATION REGISTERS AND MASKS */
+#define GENI_STATUS_REG (GENI4_CFG + 0x00000040)
+#define GENI_STATUS_M_GENI_CMD_ACTIVE_MASK (0x1)
+#define UART_TX_TRANS_LEN_REG (GENI4_IMAGE_REGS + 0x00000170)
+/* MASTER/TX ENGINE REGISTERS */
+#define GENI_M_CMD0_REG (GENI4_DATA + 0x00000000)
+/* FIFO, STATUS REGISTERS AND MASKS */
+#define GENI_TX_FIFOn_REG (GENI4_DATA + 0x00000100)
+
+#define GENI_M_CMD_TX (0x08000000)
+
+/*----------------------------------------------------------------------------*/
+/* Device address space for mapping. Excluding starting 4K */
+/*----------------------------------------------------------------------------*/
+#define QTI_DEVICE_BASE 0x1000
+#define QTI_DEVICE_SIZE (0x80000000 - QTI_DEVICE_BASE)
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL31 at DDR as per memory map. BL31_BASE is calculated using the
+ * current BL31 debug size plus a little space for growth.
+ */
+#define BL31_LIMIT (BL31_BASE + BL31_SIZE)
+
+/*----------------------------------------------------------------------------*/
+/* AOSS registers */
+/*----------------------------------------------------------------------------*/
+#define QTI_PS_HOLD_REG 0x0C264000
+/*----------------------------------------------------------------------------*/
+/* AOP CMD DB address space for mapping */
+/*----------------------------------------------------------------------------*/
+#define QTI_AOP_CMD_DB_BASE 0x80860000
+#define QTI_AOP_CMD_DB_SIZE 0x00020000
+/*----------------------------------------------------------------------------*/
+/* SOC hw version register */
+/*----------------------------------------------------------------------------*/
+#define QTI_SOC_VERSION_MASK U(0xFFFF)
+#define QTI_SOC_REVISION_REG 0x1FC8000
+#define QTI_SOC_REVISION_MASK U(0xFFFF)
+/*----------------------------------------------------------------------------*/
+/* LC PON register offsets */
+/*----------------------------------------------------------------------------*/
+#define PON_PS_HOLD_RESET_CTL 0x852
+#define PON_PS_HOLD_RESET_CTL2 0x853
+/*----------------------------------------------------------------------------*/
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/qti/sc7280/inc/qti_map_chipinfo.h b/plat/qti/sc7280/inc/qti_map_chipinfo.h
new file mode 100644
index 0000000..7303e20
--- /dev/null
+++ b/plat/qti/sc7280/inc/qti_map_chipinfo.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef QTI_MAP_CHIPINFO_H
+#define QTI_MAP_CHIPINFO_H
+
+#include <stdint.h>
+
+#include <qti_plat.h>
+
+#define QTI_JTAG_ID_REG 0x786130
+#define QTI_JTAG_ID_SHIFT 12
+#define QTI_JTAG_ID_SC7280 U(0x0193)
+#define QTI_JTAG_ID_SC7280P U(0x01EB)
+#define QTI_JTAG_ID_SC8270 U(0x01E3)
+#define QTI_JTAG_ID_SC8270P U(0x020A)
+#define QTI_JTAG_ID_SC7270P U(0x0215)
+#define QTI_CHIPINFO_ID_SC7280 U(0x01E7)
+#define QTI_CHIPINFO_ID_SC7280P U(0x0222)
+#define QTI_CHIPINFO_ID_SC8270 U(0x0229)
+#define QTI_CHIPINFO_ID_SC8270P U(0x0233)
+#define QTI_CHIPINFO_ID_SC7270P U(0x0237)
+#define QTI_DEFAULT_CHIPINFO_ID U(0xFFFF)
+
+static const chip_id_info_t g_map_jtag_chipinfo_id[] = {
+ {QTI_JTAG_ID_SC7280, QTI_CHIPINFO_ID_SC7280},
+ {QTI_JTAG_ID_SC7280P, QTI_CHIPINFO_ID_SC7280P},
+ {QTI_JTAG_ID_SC8270, QTI_CHIPINFO_ID_SC8270},
+ {QTI_JTAG_ID_SC8270P, QTI_CHIPINFO_ID_SC8270P},
+ {QTI_JTAG_ID_SC7270P, QTI_CHIPINFO_ID_SC7270P},
+};
+#endif /* QTI_MAP_CHIPINFO_H */
diff --git a/plat/qti/sc7280/inc/qti_rng_io.h b/plat/qti/sc7280/inc/qti_rng_io.h
new file mode 100644
index 0000000..0f41fd6
--- /dev/null
+++ b/plat/qti/sc7280/inc/qti_rng_io.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef QTI_RNG_IO_H
+#define QTI_RNG_IO_H
+
+#define SEC_PRNG_STATUS 0x10D1004
+#define SEC_PRNG_STATUS_DATA_AVAIL_BMSK 0x1
+#define SEC_PRNG_DATA_OUT 0x10D1000
+
+
+#endif /* QTI_RNG_IO_H */
+
diff --git a/plat/qti/sc7280/inc/qti_secure_io_cfg.h b/plat/qti/sc7280/inc/qti_secure_io_cfg.h
new file mode 100644
index 0000000..058c5b5
--- /dev/null
+++ b/plat/qti/sc7280/inc/qti_secure_io_cfg.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef QTI_SECURE_IO_CFG_H
+#define QTI_SECURE_IO_CFG_H
+
+#include <stdint.h>
+
+/*
+ * List of peripheral/IO memory areas that are protected from
+ * non-secure world but not required to be secure.
+ */
+
+#define APPS_SMMU_TBU_PWR_STATUS 0x15002204
+#define APPS_SMMU_CUSTOM_CFG 0x15002300
+#define APPS_SMMU_STATS_SYNC_INV_TBU_ACK 0x150025DC
+#define APPS_SMMU_SAFE_SEC_CFG 0x15002648
+#define APPS_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR 0x15002670
+
+static const uintptr_t qti_secure_io_allowed_regs[] = {
+ APPS_SMMU_TBU_PWR_STATUS,
+ APPS_SMMU_CUSTOM_CFG,
+ APPS_SMMU_STATS_SYNC_INV_TBU_ACK,
+ APPS_SMMU_SAFE_SEC_CFG,
+ APPS_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR,
+};
+
+#endif /* QTI_SECURE_IO_CFG_H */
diff --git a/plat/qti/sc7280/platform.mk b/plat/qti/sc7280/platform.mk
new file mode 100644
index 0000000..df07bc4
--- /dev/null
+++ b/plat/qti/sc7280/platform.mk
@@ -0,0 +1,130 @@
+#
+# Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Make for SC7280 QTI platform.
+
+QTI_PLAT_PATH := plat/qti
+CHIPSET := ${PLAT}
+
+# Turn On Separate code & data.
+SEPARATE_CODE_AND_RODATA := 1
+USE_COHERENT_MEM := 0
+WARMBOOT_ENABLE_DCACHE_EARLY := 1
+HW_ASSISTED_COHERENCY := 1
+
+#Enable errata configs for cortex_a78 and cortex_a55
+ERRATA_A55_1530923 := 1
+ERRATA_A78_1941498 := 1
+ERRATA_A78_1951500 := 1
+ERRATA_A78_2132060 := 1
+
+# Disable the PSCI platform compatibility layer
+ENABLE_PLAT_COMPAT := 0
+
+# Enable PSCI v1.0 extended state ID format
+PSCI_EXTENDED_STATE_ID := 1
+ARM_RECOM_STATE_ID_ENC := 1
+
+COLD_BOOT_SINGLE_CPU := 1
+PROGRAMMABLE_RESET_ADDRESS := 1
+
+RESET_TO_BL31 := 0
+
+MULTI_CONSOLE_API := 1
+
+QTI_SDI_BUILD := 0
+$(eval $(call assert_boolean,QTI_SDI_BUILD))
+$(eval $(call add_define,QTI_SDI_BUILD))
+
+#disable CTX_INCLUDE_AARCH32_REGS to support sc7280 gold cores
+override CTX_INCLUDE_AARCH32_REGS := 0
+WORKAROUND_CVE_2017_5715 := 0
+DYNAMIC_WORKAROUND_CVE_2018_3639 := 1
+# Enable stack protector.
+ENABLE_STACK_PROTECTOR := strong
+
+
+QTI_EXTERNAL_INCLUDES := -I${QTI_PLAT_PATH}/${CHIPSET}/inc \
+ -I${QTI_PLAT_PATH}/common/inc \
+ -I${QTI_PLAT_PATH}/common/inc/$(ARCH) \
+ -I${QTI_PLAT_PATH}/qtiseclib/inc \
+ -I${QTI_PLAT_PATH}/qtiseclib/inc/${CHIPSET} \
+
+QTI_BL31_SOURCES := $(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_helpers.S \
+ $(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_kryo6_silver.S \
+ $(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_kryo6_gold.S \
+ $(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_uart_console.S \
+ $(QTI_PLAT_PATH)/common/src/pm_ps_hold.c \
+ $(QTI_PLAT_PATH)/common/src/qti_stack_protector.c \
+ $(QTI_PLAT_PATH)/common/src/qti_common.c \
+ $(QTI_PLAT_PATH)/common/src/qti_bl31_setup.c \
+ $(QTI_PLAT_PATH)/common/src/qti_gic_v3.c \
+ $(QTI_PLAT_PATH)/common/src/qti_interrupt_svc.c \
+ $(QTI_PLAT_PATH)/common/src/qti_syscall.c \
+ $(QTI_PLAT_PATH)/common/src/qti_topology.c \
+ $(QTI_PLAT_PATH)/common/src/qti_pm.c \
+ $(QTI_PLAT_PATH)/common/src/qti_rng.c \
+ $(QTI_PLAT_PATH)/common/src/spmi_arb.c \
+ $(QTI_PLAT_PATH)/qtiseclib/src/qtiseclib_cb_interface.c \
+
+
+PLAT_INCLUDES := -Iinclude/plat/common/ \
+
+PLAT_INCLUDES += ${QTI_EXTERNAL_INCLUDES}
+
+include lib/xlat_tables_v2/xlat_tables.mk
+PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} \
+ plat/common/aarch64/crash_console_helpers.S \
+ common/desc_image_load.c \
+ lib/bl_aux_params/bl_aux_params.c \
+
+include lib/coreboot/coreboot.mk
+
+#PSCI Sources.
+PSCI_SOURCES := plat/common/plat_psci_common.c \
+
+# GIC-600 configuration
+GICV3_SUPPORT_GIC600 := 1
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+#Timer sources
+TIMER_SOURCES := drivers/delay_timer/generic_delay_timer.c \
+ drivers/delay_timer/delay_timer.c \
+
+#GIC sources.
+GIC_SOURCES := plat/common/plat_gicv3.c \
+ ${GICV3_SOURCES} \
+
+CPU_SOURCES := lib/cpus/aarch64/cortex_a78.S \
+ lib/cpus/aarch64/cortex_a55.S \
+
+BL31_SOURCES += ${QTI_BL31_SOURCES} \
+ ${PSCI_SOURCES} \
+ ${GIC_SOURCES} \
+ ${TIMER_SOURCES} \
+ ${CPU_SOURCES} \
+
+LIB_QTI_PATH := ${QTI_PLAT_PATH}/qtiseclib/lib/${CHIPSET}
+
+
+# Override this on the command line to point to the qtiseclib library which
+# will be available in coreboot.org
+QTISECLIB_PATH ?=
+
+ifeq ($(QTISECLIB_PATH),)
+# if No lib then use stub implementation for qtiseclib interface
+$(warning QTISECLIB_PATH is not provided while building, using stub implementation. \
+ Please refer docs/plat/qti.rst for more details \
+ THIS FIRMWARE WILL NOT BOOT!)
+BL31_SOURCES += plat/qti/qtiseclib/src/qtiseclib_interface_stub.c
+else
+# use library provided by QTISECLIB_PATH
+LDFLAGS += -L $(dir $(QTISECLIB_PATH))
+LDLIBS += -l$(patsubst lib%.a,%,$(notdir $(QTISECLIB_PATH)))
+endif
+
diff --git a/plat/renesas/common/aarch64/plat_helpers.S b/plat/renesas/common/aarch64/plat_helpers.S
new file mode 100644
index 0000000..21c3bed
--- /dev/null
+++ b/plat/renesas/common/aarch64/plat_helpers.S
@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <common/runtime_svc.h>
+#include <cortex_a57.h>
+#include <platform_def.h>
+
+#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
+ exception_return
+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]!
+ str x6, [sp, #-16]!
+ str x7, [sp, #-16]!
+ bl console_rcar_putc
+ ldr x7, [sp], #16
+ ldr x6, [sp], #16
+ 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
+
+ /* ---------------------------------------------
+ * void 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
diff --git a/plat/renesas/common/aarch64/platform_common.c b/plat/renesas/common/aarch64/platform_common.c
new file mode 100644
index 0000000..b0a88cb
--- /dev/null
+++ b/plat/renesas/common/aarch64/platform_common.c
@@ -0,0 +1,271 @@
+/*
+ * 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 <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#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);
+}
diff --git a/plat/renesas/common/bl2_cpg_init.c b/plat/renesas/common/bl2_cpg_init.c
new file mode 100644
index 0000000..a545f71
--- /dev/null
+++ b/plat/renesas/common/bl2_cpg_init.c
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "cpg_registers.h"
+#include "rcar_def.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) || (RCAR_LSI == RZ_G2H)
+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) || (RCAR_LSI == RZ_G2M)
+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) || (RCAR_LSI == RZ_G2N)
+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) || (RCAR_LSI == RZ_G2E)
+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_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) || (RCAR_LSI == RZ_G2E)
+ 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) || (RCAR_LSI == RZ_G2H)
+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, 0x80000000U | (mmio_read_32(SMSTPCR4) & 0x4));
+ 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) || (RCAR_LSI == RZ_G2M)
+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, 0x80000000U | (mmio_read_32(SMSTPCR4) & 0x4));
+ 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) || (RCAR_LSI == RZ_G2N)
+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, 0x80000000U | (mmio_read_32(SMSTPCR4) & 0x4));
+ 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, 0x80000000U | (mmio_read_32(SMSTPCR4) & 0x4));
+ 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) || (RCAR_LSI == RZ_G2E)
+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, 0x80000000U | (mmio_read_32(SMSTPCR4) & 0x4));
+ 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_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, 0x00000080U | (mmio_read_32(SMSTPCR4) & 0x4));
+ 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:
+ /* no need */
+ break;
+ default:
+ panic();
+ break;
+ }
+#elif (RCAR_LSI == RCAR_H3) || (RCAR_LSI == RCAR_H3N) || (RCAR_LSI == RZ_G2H)
+ bl2_realtime_cpg_init_h3();
+#elif (RCAR_LSI == RCAR_M3) || (RCAR_LSI == RZ_G2M)
+ bl2_realtime_cpg_init_m3();
+#elif RCAR_LSI == RCAR_M3N || (RCAR_LSI == RZ_G2N)
+ bl2_realtime_cpg_init_m3n();
+#elif RCAR_LSI == RCAR_V3M
+ bl2_realtime_cpg_init_v3m();
+#elif RCAR_LSI == RCAR_E3 || RCAR_LSI == RZ_G2E
+ bl2_realtime_cpg_init_e3();
+#elif RCAR_LSI == RCAR_D3
+ /* no need */
+#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) || (RCAR_LSI == RZ_G2H)
+ bl2_system_cpg_init_h3();
+#elif (RCAR_LSI == RCAR_M3) || (RCAR_LSI == RZ_G2M)
+ bl2_system_cpg_init_m3();
+#elif RCAR_LSI == RCAR_M3N || (RCAR_LSI == RZ_G2N)
+ bl2_system_cpg_init_m3n();
+#elif RCAR_LSI == RCAR_V3M
+ bl2_system_cpg_init_v3m();
+#elif RCAR_LSI == RCAR_E3 || RCAR_LSI == RZ_G2E
+ 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
+}
diff --git a/plat/renesas/common/bl2_interrupt_error.c b/plat/renesas/common/bl2_interrupt_error.c
new file mode 100644
index 0000000..d9a4b8e
--- /dev/null
+++ b/plat/renesas/common/bl2_interrupt_error.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+
+#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();
+}
diff --git a/plat/renesas/common/bl2_plat_mem_params_desc.c b/plat/renesas/common/bl2_plat_mem_params_desc.c
new file mode 100644
index 0000000..bf2706d
--- /dev/null
+++ b/plat/renesas/common/bl2_plat_mem_params_desc.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/common/platform.h>
+
+#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,
+ .ep_info.args.arg3 = (uintptr_t)fdt_blob,
+
+ 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)
diff --git a/plat/renesas/common/bl2_secure_setting.c b/plat/renesas/common/bl2_secure_setting.c
new file mode 100644
index 0000000..2f8b001
--- /dev/null
+++ b/plat/renesas/common/bl2_secure_setting.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#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 /* LIFEC_DBSC_PROTECT_ENABLE == 1 */
+ { SEC_SEL3, 0xFFFFFFFFU },
+#endif /* LIFEC_DBSC_PROTECT_ENABLE == 1 */
+ /*
+ * {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/D3]
+ * Bit12: SCEG PKA (public APB) slave ports
+ * 0: registers accessed from secure resource only
+ * 1: Reserved[R-Car E3/D3]
+ * 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 /* (RCAR_LSI == RCAR_E3) || (RCAR_LSI == RCAR_D3) */
+ { SEC_SEL6, 0xFFFFCBFFU },
+#endif /* (RCAR_LSI == RCAR_E3) || (RCAR_LSI == RCAR_D3) */
+ /*
+ * {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 /* (RCAR_RPC_HYPERFLASH_LOCKED == 1) */
+ /*
+ * 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 /* (LIFEC_DBSC_PROTECT_ENABLE == 1) */
+ { SEC_GRP0COND3, 0x00000000U },
+ { SEC_GRP1COND3, 0x00000000U },
+#endif /* (LIFEC_DBSC_PROTECT_ENABLE == 1) */
+ /*
+ * 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/D3]
+ * Bit12: SCEG PKA (public APB) slave ports
+ * SecurityGroup3
+ * Reserved[R-Car E3/D3]
+ * Bit10: SCEG Secure Core slave ports
+ * SecurityGroup3
+ */
+#if RCAR_LSI == RCAR_E3 || RCAR_LSI == RCAR_D3
+ { SEC_GRP0COND6, 0x00000400U },
+ { SEC_GRP1COND6, 0x00000400U },
+#else /* RCAR_LSI == RCAR_E3 */
+ { SEC_GRP0COND6, 0x00003400U },
+ { SEC_GRP1COND6, 0x00003400U },
+#endif /* RCAR_LSI == RCAR_E3 */
+ /*
+ * 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 /* (RCAR_RPC_HYPERFLASH_LOCKED == 1) */
+ /*
+ * 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)
+{
+ lifec_security_setting();
+ axi_security_setting();
+ rcar_micro_delay(10U);
+}
diff --git a/plat/renesas/common/bl31_plat_setup.c b/plat/renesas/common/bl31_plat_setup.c
new file mode 100644
index 0000000..60960d4
--- /dev/null
+++ b/plat/renesas/common/bl31_plat_setup.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include "pwrc.h"
+#include "rcar_def.h"
+#include "rcar_private.h"
+#include "rcar_version.h"
+
+static const uint64_t BL31_RO_BASE = BL_CODE_BASE;
+static const uint64_t BL31_RO_LIMIT = BL_CODE_END;
+
+#if USE_COHERENT_MEM
+static const uint64_t BL31_COHERENT_RAM_BASE = BL_COHERENT_RAM_BASE;
+static const uint64_t BL31_COHERENT_RAM_LIMIT = BL_COHERENT_RAM_END;
+#endif /* USE_COHERENT_MEM */
+
+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_pwrc_get_cluster() == RCAR_CLUSTER_A53A57) {
+ plat_cci_init();
+ plat_cci_enable();
+ }
+#endif /* RCAR_LSI != RCAR_D3 */
+}
+
+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 /* USE_COHERENT_MEM */
+ );
+ 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;
+ rcar_pwrc_all_disable_interrupt_wakeup();
+}
diff --git a/plat/renesas/common/common.mk b/plat/renesas/common/common.mk
new file mode 100644
index 0000000..ca61f0e
--- /dev/null
+++ b/plat/renesas/common/common.mk
@@ -0,0 +1,143 @@
+#
+# Copyright (c) 2018-2022, 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_NS := 1
+
+# This option gets enabled automatically if the TRUSTED_BOARD_BOOT
+# is set via root Makefile, but Renesas support Trusted-Boot without
+# Crypto module.
+override CRYPTO_SUPPORT := 0
+
+$(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
+RZ_G2M:=100
+RZ_G2H:=101
+RZ_G2N:=102
+RZ_G2E:=103
+$(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))
+$(eval $(call add_define,RZ_G2M))
+$(eval $(call add_define,RZ_G2H))
+$(eval $(call add_define,RZ_G2N))
+$(eval $(call add_define,RZ_G2E))
+
+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))
+
+# Enable workarounds for selected Cortex-A53 erratas.
+ERRATA_A53_835769 := 1
+ERRATA_A53_843419 := 1
+ERRATA_A53_855873 := 1
+ERRATA_A53_1530924 := 1
+
+# Enable workarounds for selected Cortex-A57 erratas.
+ERRATA_A57_859972 := 1
+ERRATA_A57_813419 := 1
+ERRATA_A57_1319537 := 1
+
+PLAT_INCLUDES := -Iplat/renesas/common/include/registers \
+ -Iplat/renesas/common/include \
+ -Iplat/renesas/common
+
+PLAT_BL_COMMON_SOURCES := drivers/renesas/common/iic_dvfs/iic_dvfs.c \
+ plat/renesas/common/rcar_common.c
+
+include drivers/arm/gic/v2/gicv2.mk
+RCAR_GIC_SOURCES := ${GICV2_SOURCES} \
+ 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/common/aarch64/platform_common.c \
+ plat/renesas/common/aarch64/plat_helpers.S \
+ plat/renesas/common/bl2_interrupt_error.c \
+ plat/renesas/common/bl2_secure_setting.c \
+ plat/renesas/common/plat_storage.c \
+ plat/renesas/common/bl2_plat_mem_params_desc.c \
+ plat/renesas/common/plat_image_load.c \
+ plat/renesas/common/bl2_cpg_init.c \
+ drivers/renesas/common/console/rcar_printf.c \
+ drivers/renesas/common/scif/scif.S \
+ drivers/renesas/common/common.c \
+ drivers/renesas/common/io/io_emmcdrv.c \
+ drivers/renesas/common/io/io_memdrv.c \
+ drivers/renesas/common/io/io_rcar.c \
+ drivers/renesas/common/auth/auth_mod.c \
+ drivers/renesas/common/rpc/rpc_driver.c \
+ drivers/renesas/common/dma/dma_driver.c \
+ drivers/renesas/common/avs/avs_driver.c \
+ drivers/renesas/common/delay/micro_delay.c \
+ drivers/renesas/common/emmc/emmc_interrupt.c \
+ drivers/renesas/common/emmc/emmc_utility.c \
+ drivers/renesas/common/emmc/emmc_mount.c \
+ drivers/renesas/common/emmc/emmc_init.c \
+ drivers/renesas/common/emmc/emmc_read.c \
+ drivers/renesas/common/emmc/emmc_cmd.c \
+ drivers/renesas/common/watchdog/swdt.c \
+ drivers/renesas/common/rom/rom_api.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/common/plat_topology.c \
+ plat/renesas/common/aarch64/plat_helpers.S \
+ plat/renesas/common/aarch64/platform_common.c \
+ plat/renesas/common/bl31_plat_setup.c \
+ plat/renesas/common/plat_pm.c \
+ drivers/renesas/common/console/rcar_console.S \
+ drivers/renesas/common/console/rcar_printf.c \
+ drivers/renesas/common/delay/micro_delay.c \
+ drivers/renesas/common/pwrc/call_sram.S \
+ drivers/renesas/common/pwrc/pwrc.c \
+ drivers/renesas/common/common.c \
+ drivers/arm/cci/cci.c
+
+include lib/xlat_tables_v2/xlat_tables.mk
+PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS}
diff --git a/plat/renesas/common/include/plat.ld.S b/plat/renesas/common/include/plat.ld.S
new file mode 100644
index 0000000..7aef324
--- /dev/null
+++ b/plat/renesas/common/include/plat.ld.S
@@ -0,0 +1,36 @@
+/*
+ * 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 <lib/xlat_tables/xlat_tables_defs.h>
+#include <platform_def.h>
+
+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 */
diff --git a/plat/renesas/common/include/plat_macros.S b/plat/renesas/common/include/plat_macros.S
new file mode 100644
index 0000000..927cd39
--- /dev/null
+++ b/plat/renesas/common/include/plat_macros.S
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+
+#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
diff --git a/plat/renesas/common/include/platform_def.h b/plat/renesas/common/include/platform_def.h
new file mode 100644
index 0000000..ab071ec
--- /dev/null
+++ b/plat/renesas/common/include/platform_def.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#ifndef __ASSEMBLER__
+#include <stdlib.h>
+#endif
+
+#include <arch.h>
+
+#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(0x800)
+#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(0x200000))
+#endif
+
+/*******************************************************************************
+ * BL33
+ ******************************************************************************/
+#define BL33_BASE DRAM1_NS_BASE
+#define BL33_COMP_SIZE U(0x200000)
+#define BL33_COMP_BASE (BL33_BASE - BL33_COMP_SIZE)
+
+/*******************************************************************************
+ * 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 mailboxes 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 */
diff --git a/plat/renesas/common/include/rcar_def.h b/plat/renesas/common/include/rcar_def.h
new file mode 100644
index 0000000..2cd26ed
--- /dev/null
+++ b/plat/renesas/common/include/rcar_def.h
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RCAR_DEF_H
+#define RCAR_DEF_H
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+
+#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 depends 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 (64)
+#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_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 shutoff A53-SCU */
+#define RCAR_PWROFFCR5 U(0xE61801C4) /* Power shutoff 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 */
+#define RCAR_SYSCEXTMASK U(0xE61802F8) /* External Request Mask */
+ /* H3/H3-N, M3 v3.0, M3-N, E3 */
+/* Product register */
+#define RCAR_PRR U(0xFFF00044)
+#define RCAR_M3_CUT_VER11 U(0x00000010) /* M3 Ver.1.1/Ver.1.2 */
+#define RCAR_D3_CUT_VER10 U(0x00000000) /* D3 Ver.1.0 */
+#define RCAR_D3_CUT_VER11 U(0x00000010) /* D3 Ver.1.1 */
+#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 */
diff --git a/plat/renesas/common/include/rcar_private.h b/plat/renesas/common/include/rcar_private.h
new file mode 100644
index 0000000..36f4ca5
--- /dev/null
+++ b/plat/renesas/common/include/rcar_private.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RCAR_PRIVATE_H
+#define RCAR_PRIVATE_H
+
+#include <common/bl_common.h>
+#include <lib/bakery_lock.h>
+#include <lib/el3_runtime/cpu_data.h>
+
+#include <platform_def.h>
+
+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(sizeof(rcar_cpu_data_t) == PLAT_PCPU_DATA_SIZE,
+ 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 */
diff --git a/plat/renesas/common/include/rcar_version.h b/plat/renesas/common/include/rcar_version.h
new file mode 100644
index 0000000..5a0ca31
--- /dev/null
+++ b/plat/renesas/common/include/rcar_version.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RCAR_VERSION_H
+#define RCAR_VERSION_H
+
+#include <arch_helpers.h>
+
+#define VERSION_OF_RENESAS "3.0.3"
+#define VERSION_OF_RENESAS_MAXLEN 128
+
+extern const uint8_t version_of_renesas[VERSION_OF_RENESAS_MAXLEN];
+
+#endif /* RCAR_VERSION_H */
diff --git a/plat/renesas/common/include/registers/axi_registers.h b/plat/renesas/common/include/registers/axi_registers.h
new file mode 100644
index 0000000..36cd58b
--- /dev/null
+++ b/plat/renesas/common/include/registers/axi_registers.h
@@ -0,0 +1,246 @@
+/*
+ * 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 */
diff --git a/plat/renesas/common/include/registers/cpg_registers.h b/plat/renesas/common/include/registers/cpg_registers.h
new file mode 100644
index 0000000..5d2bb9e
--- /dev/null
+++ b/plat/renesas/common/include/registers/cpg_registers.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2015-2021, 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 module stop status 2 */
+#define CPG_MSTPSR3 (CPG_BASE + 0x0048U)
+/* 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)
+/* SDHI2 clock frequency control register */
+#define CPG_SD2CKCR (CPG_BASE + 0x0268U)
+/* SDHI3 clock frequency control register */
+#define CPG_SD3CKCR (CPG_BASE + 0x026CU)
+
+/* 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 */
diff --git a/plat/renesas/common/include/registers/lifec_registers.h b/plat/renesas/common/include/registers/lifec_registers.h
new file mode 100644
index 0000000..5f49e52
--- /dev/null
+++ b/plat/renesas/common/include/registers/lifec_registers.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2015-2020, 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 */
diff --git a/plat/renesas/common/plat_image_load.c b/plat/renesas/common/plat_image_load.c
new file mode 100644
index 0000000..9d814a6
--- /dev/null
+++ b/plat/renesas/common/plat_image_load.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+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();
+}
diff --git a/plat/renesas/common/plat_pm.c b/plat/renesas/common/plat_pm.c
new file mode 100644
index 0000000..9810596
--- /dev/null
+++ b/plat/renesas/common/plat_pm.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include "iic_dvfs.h"
+#include "platform_def.h"
+#include "pwrc.h"
+#include "rcar_def.h"
+#include "rcar_private.h"
+#if RCAR_GEN3_ULCB
+#include "ulcb_cpld.h"
+#endif /* RCAR_GEN3_ULCB */
+
+#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);
+
+static uintptr_t rcar_sec_entrypoint;
+
+static void rcar_program_mailbox(u_register_t mpidr, uintptr_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)
+{
+ u_register_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();
+ u_register_t mpidr = read_mpidr_el1();
+
+ if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+ if (cluster_type == RCAR_CLUSTER_A53A57)
+ plat_cci_enable();
+
+ rcar_program_mailbox(mpidr, 0);
+ rcar_pwrc_enable_interrupt_wakeup(mpidr);
+
+ 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
+ u_register_t mpidr = read_mpidr_el1();
+
+ rcar_pwrc_disable_interrupt_wakeup(mpidr);
+ 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();
+ u_register_t 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);
+ }
+}
+
+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_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
+{
+#if RCAR_SYSTEM_SUSPEND
+ if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+ rcar_pwrc_suspend_to_ram();
+#endif
+ wfi();
+
+ ERROR("RCAR Power Down: operation not handled.\n");
+ panic();
+}
+
+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
+ u_register_t mpidr = read_mpidr_el1();
+ u_register_t cpu = mpidr & 0x0000ffffU;
+ int32_t rtn_on;
+
+ rtn_on = rcar_pwrc_cpu_on_check(mpidr);
+
+ if (cpu != rcar_boot_mpidr) {
+ panic();
+ }
+
+ if (rtn_on != 0) {
+ panic();
+ }
+
+ rcar_pwrc_cpuoff(mpidr);
+ rcar_pwrc_clusteroff(mpidr);
+
+#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 receive 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)
+{
+ u_register_t 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,
+ .pwr_domain_pwr_down_wfi = rcar_pwr_domain_pwr_down_wfi,
+#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;
+}
+
diff --git a/plat/renesas/common/plat_storage.c b/plat/renesas/common/plat_storage.c
new file mode 100644
index 0000000..6524561
--- /dev/null
+++ b/plat/renesas/common/plat_storage.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/io/io_semihosting.h>
+
+#include "io_common.h"
+#include "io_memdrv.h"
+#include "io_emmcdrv.h"
+#include "io_private.h"
+#include "io_rcar.h"
+#include <platform_def.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;
+}
diff --git a/plat/renesas/common/plat_topology.c b/plat/renesas/common/plat_topology.c
new file mode 100644
index 0000000..0d5880d
--- /dev/null
+++ b/plat/renesas/common/plat_topology.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/psci/psci.h>
+
+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);
+}
+
diff --git a/plat/renesas/common/rcar_common.c b/plat/renesas/common/rcar_common.c
new file mode 100644
index 0000000..df4c30c
--- /dev/null
+++ b/plat/renesas/common/rcar_common.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2019-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <drivers/console.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <plat/common/platform.h>
+
+#include <lib/mmio.h>
+#include <cpg_registers.h>
+
+#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_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;
+
+ plat_default_ea_handler(ea_reason, syndrome, cookie, handle, flags);
+}
+
+#include <drivers/renesas/rcar/console/console.h>
+
+static console_t rcar_boot_console;
+static console_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_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_FLAG_RUNTIME);
+}
+
+void rcar_console_runtime_end(void)
+{
+}
diff --git a/plat/renesas/rcar/bl2_plat_setup.c b/plat/renesas/rcar/bl2_plat_setup.c
new file mode 100644
index 0000000..f85db8d
--- /dev/null
+++ b/plat/renesas/rcar/bl2_plat_setup.c
@@ -0,0 +1,1199 @@
+/*
+ * Copyright (c) 2018-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <common/image_decompress.h>
+#include <drivers/console.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/common/platform.h>
+#if RCAR_GEN3_BL33_GZIP == 1
+#include <tf_gunzip.h>
+#endif
+
+#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 "io_rcar.h"
+#include "qos_init.h"
+#include "rcar_def.h"
+#include "rcar_private.h"
+#include "rcar_version.h"
+#include "rom_api.h"
+
+#if RCAR_BL2_DCACHE == 1
+/*
+ * Following symbols are only used during plat_arch_setup() only
+ * when RCAR_BL2_DCACHE is enabled.
+ */
+static const uint64_t BL2_RO_BASE = BL_CODE_BASE;
+static const uint64_t BL2_RO_LIMIT = BL_CODE_END;
+
+#if USE_COHERENT_MEM
+static const uint64_t BL2_COHERENT_RAM_BASE = BL_COHERENT_RAM_BASE;
+static const uint64_t BL2_COHERENT_RAM_LIMIT = BL_COHERENT_RAM_END;
+#endif
+
+#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];
+ *string = 0;
+}
+
+#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;
+
+ /* 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
+}
+
+#if RCAR_GEN3_BL33_GZIP == 1
+void bl2_plat_preload_setup(void)
+{
+ image_decompress_init(BL33_COMP_BASE, BL33_COMP_SIZE, gunzip);
+}
+#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;
+
+ bl_mem_params = get_bl_mem_params_node(image_id);
+
+#if RCAR_GEN3_BL33_GZIP == 1
+ if (image_id == BL33_IMAGE_ID) {
+ image_decompress_prepare(&bl_mem_params->image_info);
+ }
+#endif
+
+ if (image_id != BL31_IMAGE_ID)
+ return 0;
+
+ 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;
+}
+
+static uint64_t rcar_get_dest_addr_from_cert(uint32_t certid, uintptr_t *dest)
+{
+ uint32_t cert, len;
+ int ret;
+
+ ret = rcar_get_certificate(certid, &cert);
+ if (ret) {
+ ERROR("%s : cert file load error", __func__);
+ return 1;
+ }
+
+ rcar_read_certificate((uint64_t) cert, &len, dest);
+
+ 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;
+ uintptr_t dest;
+ int ret;
+
+ 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:
+ ret = rcar_get_dest_addr_from_cert(SOC_FW_CONTENT_CERT_ID,
+ &dest);
+ if (!ret)
+ bl_mem_params->image_info.image_base = dest;
+ break;
+ case BL32_IMAGE_ID:
+ ret = rcar_get_dest_addr_from_cert(TRUSTED_OS_FW_CONTENT_CERT_ID,
+ &dest);
+ if (!ret)
+ bl_mem_params->image_info.image_base = dest;
+
+ memcpy(&params->bl32_ep_info, &bl_mem_params->ep_info,
+ sizeof(entry_point_info_t));
+ break;
+ case BL33_IMAGE_ID:
+#if RCAR_GEN3_BL33_GZIP == 1
+ if ((mmio_read_32(BL33_COMP_BASE) & 0xffff) == 0x8b1f) {
+ /* decompress gzip-compressed image */
+ ret = image_decompress(&bl_mem_params->image_info);
+ if (ret != 0) {
+ return ret;
+ }
+ } else {
+ /* plain image, copy it in place */
+ memcpy((void *)BL33_BASE, (void *)BL33_COMP_BASE,
+ bl_mem_params->image_info.image_size);
+ }
+#endif
+ memcpy(&params->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 *dt)
+{
+ uint32_t board_type;
+ uint32_t board_rev;
+ uint32_t reg;
+ int ret;
+
+ fdt_setprop_u32(dt, 0, "#address-cells", 2);
+ fdt_setprop_u32(dt, 0, "#size-cells", 2);
+
+ /* Populate compatible string */
+ rcar_get_board_type(&board_type, &board_rev);
+ switch (board_type) {
+ case BOARD_SALVATOR_X:
+ ret = fdt_setprop_string(dt, 0, "compatible",
+ "renesas,salvator-x");
+ break;
+ case BOARD_SALVATOR_XS:
+ ret = fdt_setprop_string(dt, 0, "compatible",
+ "renesas,salvator-xs");
+ break;
+ case BOARD_STARTER_KIT:
+ ret = fdt_setprop_string(dt, 0, "compatible",
+ "renesas,m3ulcb");
+ break;
+ case BOARD_STARTER_KIT_PRE:
+ ret = fdt_setprop_string(dt, 0, "compatible",
+ "renesas,h3ulcb");
+ break;
+ case BOARD_EAGLE:
+ ret = fdt_setprop_string(dt, 0, "compatible",
+ "renesas,eagle");
+ break;
+ case BOARD_EBISU:
+ case BOARD_EBISU_4D:
+ ret = fdt_setprop_string(dt, 0, "compatible",
+ "renesas,ebisu");
+ break;
+ case BOARD_DRAAK:
+ ret = fdt_setprop_string(dt, 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(dt, 0, "compatible",
+ "renesas,r8a7795");
+ break;
+ case PRR_PRODUCT_M3:
+ ret = fdt_appendprop_string(dt, 0, "compatible",
+ "renesas,r8a7796");
+ break;
+ case PRR_PRODUCT_M3N:
+ ret = fdt_appendprop_string(dt, 0, "compatible",
+ "renesas,r8a77965");
+ break;
+ case PRR_PRODUCT_V3M:
+ ret = fdt_appendprop_string(dt, 0, "compatible",
+ "renesas,r8a77970");
+ break;
+ case PRR_PRODUCT_E3:
+ ret = fdt_appendprop_string(dt, 0, "compatible",
+ "renesas,r8a77990");
+ break;
+ case PRR_PRODUCT_D3:
+ ret = fdt_appendprop_string(dt, 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_add_rpc_node(void)
+{
+#if (RCAR_RPC_HYPERFLASH_LOCKED == 0)
+ int ret, node;
+
+ node = ret = fdt_add_subnode(fdt, 0, "soc");
+ if (ret < 0) {
+ goto err;
+ }
+
+ node = ret = fdt_add_subnode(fdt, node, "spi@ee200000");
+ if (ret < 0) {
+ goto err;
+ }
+
+ ret = fdt_setprop_string(fdt, node, "status", "okay");
+ if (ret < 0) {
+ goto err;
+ }
+
+ return;
+err:
+ NOTICE("BL2: Cannot add RPC node to FDT (ret=%i)\n", ret);
+ panic();
+#endif
+}
+
+static void bl2_add_dram_entry(uint64_t start, uint64_t size)
+{
+ char nodename[32] = { 0 };
+ uint64_t fdtsize;
+ int ret, node;
+
+ 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 [%" PRIx64 " - %" PRIx64 "] to FDT (ret=%i)\n",
+ start, start + size - 1, ret);
+ panic();
+}
+
+static void bl2_advertise_dram_entries(uint64_t dram_config[8])
+{
+ uint64_t start, size, size32;
+ int 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: %" PRIx64 " - %" PRIx64 ", %" PRId64 " %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 and the maximum size is 2GiB.
+ */
+ if (chan == 0) {
+ /* Limit the 32bit entry to 2 GiB - 128 MiB */
+ size32 = size - 0x8000000U;
+ if (size32 >= 0x78000000U) {
+ size32 = 0x78000000U;
+ }
+
+ /* Emit 32bit entry, up to 2 GiB - 128 MiB long. */
+ bl2_add_dram_entry(0x48000000, size32);
+
+ /*
+ * If channel 0 is less than 2 GiB long, the
+ * entire memory fits into the 32bit space entry,
+ * so move on to the next channel.
+ */
+ if (size <= 0x80000000U) {
+ continue;
+ }
+
+ /*
+ * If channel 0 is more than 2 GiB long, emit
+ * another entry which covers the rest of the
+ * memory in channel 0, in the 64bit space.
+ *
+ * Start of this new entry is at 2 GiB offset
+ * from the beginning of the 64bit channel 0
+ * address, size is 2 GiB shorter than total
+ * size of the channel.
+ */
+ start += 0x80000000U;
+ size -= 0x80000000U;
+ }
+
+ bl2_add_dram_entry(start, size);
+ }
+}
+
+static void bl2_advertise_dram_size(uint32_t product)
+{
+ uint64_t dram_config[8] = {
+ [0] = 0x400000000ULL,
+ [2] = 0x500000000ULL,
+ [4] = 0x600000000ULL,
+ [6] = 0x700000000ULL,
+ };
+ uint32_t cut = mmio_read_32(RCAR_PRR) & PRR_CUT_MASK;
+
+ 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 (cut < PRR_PRODUCT_30) {
+#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
+ } else {
+ /* 8GB(2GBx4 2ch split) */
+ dram_config[1] = 0x100000000ULL;
+ dram_config[5] = 0x100000000ULL;
+ }
+ break;
+
+ case PRR_PRODUCT_M3N:
+#if (RCAR_DRAM_LPDDR4_MEMCONF == 2)
+ /* 4GB(4GBx1) */
+ dram_config[1] = 0x100000000ULL;
+#elif (RCAR_DRAM_LPDDR4_MEMCONF == 1)
+ /* 2GB(1GBx2) */
+ dram_config[1] = 0x80000000ULL;
+#endif
+ 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 if (product == PRR_PRODUCT_D3) {
+ if (RCAR_D3_CUT_VER10 == (reg & PRR_CUT_MASK)) {
+ NOTICE("BL2: PRR is R-Car %s Ver.1.0\n", str);
+ } else if (RCAR_D3_CUT_VER11 == (reg & PRR_CUT_MASK)) {
+ NOTICE("BL2: PRR is R-Car %s Ver.1.1\n", str);
+ } else {
+ NOTICE("BL2: PRR is R-Car %s Ver.X.X\n", str);
+ }
+ } 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 (PRR_PRODUCT_E3 == product || PRR_PRODUCT_D3 == product) {
+ 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:
+ 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);
+
+ /* Enable RPC if unlocked */
+ bl2_add_rpc_node();
+
+ /* 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);
+}
diff --git a/plat/renesas/rcar/platform.mk b/plat/renesas/rcar/platform.mk
new file mode 100644
index 0000000..670d499
--- /dev/null
+++ b/plat/renesas/rcar/platform.mk
@@ -0,0 +1,371 @@
+#
+# Copyright (c) 2018-2021, Renesas Electronics Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include plat/renesas/common/common.mk
+
+ifndef LSI
+ $(error "Error: Unknown LSI. Please use LSI=<LSI name> 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_MEMRANK flag
+ifndef RCAR_DRAM_MEMRANK
+RCAR_DRAM_MEMRANK :=0
+endif
+$(eval $(call add_define,RCAR_DRAM_MEMRANK))
+
+# 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))
+
+ifndef RCAR_GEN3_BL33_GZIP
+RCAR_GEN3_BL33_GZIP := 0
+endif
+$(eval $(call add_define,RCAR_GEN3_BL33_GZIP))
+
+# 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
+
+include drivers/renesas/common/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/renesas/common/ddr \
+ -Idrivers/renesas/rcar/qos \
+ -Idrivers/renesas/rcar/board \
+ -Idrivers/renesas/rcar/cpld/ \
+ -Idrivers/renesas/common \
+ -Idrivers/renesas/common/iic_dvfs \
+ -Idrivers/renesas/common/avs \
+ -Idrivers/renesas/common/delay \
+ -Idrivers/renesas/common/rom \
+ -Idrivers/renesas/common/scif \
+ -Idrivers/renesas/common/emmc \
+ -Idrivers/renesas/common/pwrc \
+ -Idrivers/renesas/common/io
+
+BL2_SOURCES += plat/renesas/rcar/bl2_plat_setup.c \
+ drivers/renesas/rcar/board/board.c
+
+ifeq (${RCAR_GEN3_BL33_GZIP},1)
+include lib/zlib/zlib.mk
+
+BL2_SOURCES += common/image_decompress.c \
+ $(ZLIB_SOURCES)
+endif
+
+ifeq (${RCAR_GEN3_ULCB},1)
+BL31_SOURCES += drivers/renesas/rcar/cpld/ulcb_cpld.c
+endif
+
+# 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
+
diff --git a/plat/renesas/rzg/bl2_plat_setup.c b/plat/renesas/rzg/bl2_plat_setup.c
new file mode 100644
index 0000000..e9dbd20
--- /dev/null
+++ b/plat/renesas/rzg/bl2_plat_setup.c
@@ -0,0 +1,1020 @@
+/*
+ * Copyright (c) 2020-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/console.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+#include <libfdt.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <platform_def.h>
+#include <plat/common/platform.h>
+
+#include "avs_driver.h"
+#include "board.h"
+#include "boot_init_dram.h"
+#include "cpg_registers.h"
+#include "emmc_def.h"
+#include "emmc_hal.h"
+#include "emmc_std.h"
+#include "io_common.h"
+#include "io_rcar.h"
+#include "qos_init.h"
+#include "rcar_def.h"
+#include "rcar_private.h"
+#include "rcar_version.h"
+#include "rom_api.h"
+
+#define MAX_DRAM_CHANNELS 4
+/*
+ * DDR ch0 has a shadow area mapped in 32bit address space.
+ * Physical address 0x4_0000_0000 - 0x4_7fff_ffff in 64bit space
+ * is mapped to 0x4000_0000 - 0xbfff_ffff in 32bit space.
+ */
+#define MAX_DRAM_SIZE_CH0_32BIT_ADDR_SPACE 0x80000000ULL
+
+#if RCAR_BL2_DCACHE == 1
+/*
+ * Following symbols are only used during plat_arch_setup() only
+ * when RCAR_BL2_DCACHE is enabled.
+ */
+static const uint64_t BL2_RO_BASE = BL_CODE_BASE;
+static const uint64_t BL2_RO_LIMIT = BL_CODE_END;
+
+#if USE_COHERENT_MEM
+static const uint64_t BL2_COHERENT_RAM_BASE = BL_COHERENT_RAM_BASE;
+static const uint64_t BL2_COHERENT_RAM_LIMIT = BL_COHERENT_RAM_END;
+#endif /* USE_COHERENT_MEM */
+
+#endif /* RCAR_BL2_DCACHE */
+
+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_dma_init(void);
+extern void rzg_pfc_init(void);
+
+static void bl2_init_generic_timer(void);
+
+/* RZ/G2 product check */
+#if RCAR_LSI == RZ_G2M
+#define TARGET_PRODUCT PRR_PRODUCT_M3
+#define TARGET_NAME "RZ/G2M"
+#elif RCAR_LSI == RZ_G2H
+#define TARGET_PRODUCT PRR_PRODUCT_H3
+#define TARGET_NAME "RZ/G2H"
+#elif RCAR_LSI == RZ_G2N
+#define TARGET_PRODUCT PRR_PRODUCT_M3N
+#define TARGET_NAME "RZ/G2N"
+#elif RCAR_LSI == RZ_G2E
+#define TARGET_PRODUCT PRR_PRODUCT_E3
+#define TARGET_NAME "RZ/G2E"
+#elif RCAR_LSI == RCAR_AUTO
+#define TARGET_NAME "RZ/G2M"
+#endif /* RCAR_LSI == RZ_G2M */
+
+#if (RCAR_LSI == RZ_G2E)
+#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 (1U << 8U)
+#endif /* RCAR_LSI == RZ_G2E */
+
+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(uint64_t 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 < 0xaU) {
+ num_buf[i] = '0' + rem;
+ } else {
+ num_buf[i] = 'a' + (rem - 0xaU);
+ }
+ i++;
+ unum /= radix;
+ } while (unum > 0U);
+
+ while (--i >= 0) {
+ *string++ = num_buf[i];
+ }
+ *string = 0;
+}
+
+#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 == 0UL && end_addr == 0UL) {
+ 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 %s (ret=%i)\n",
+ "renesas,lossy-decompression", ret);
+ panic();
+ }
+
+ ret = fdt_appendprop_string(fdt, node, "compatible",
+ "shared-dma-pool");
+ if (ret < 0) {
+ NOTICE("BL2: Cannot append FCNL compat string %s (ret=%i)\n",
+ "shared-dma-pool", 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 + 0x8U * no, reg);
+ mmio_write_32(AXI_DCMPAREACRB0 + 0x8U * no, end_addr >> 20);
+ mmio_write_32(AXI_DCMPAREACRA0 + 0x8U * no, reg | enable);
+
+ info.magic = 0x12345678U;
+ info.a0 = mmio_read_32(AXI_DCMPAREACRA0 + 0x8U * no);
+ info.b0 = mmio_read_32(AXI_DCMPAREACRB0 + 0x8U * no);
+
+ mmio_write_32(LOSSY_PARAMS_BASE + sizeof(info) * no, info.magic);
+ mmio_write_32(LOSSY_PARAMS_BASE + sizeof(info) * no + 0x4U, info.a0);
+ mmio_write_32(LOSSY_PARAMS_BASE + sizeof(info) * no + 0x8U, info.b0);
+
+ NOTICE(" Entry %d: DCMPAREACRAx:0x%x DCMPAREACRBx:0x%x\n", no,
+ mmio_read_32(AXI_DCMPAREACRA0 + 0x8U * no),
+ mmio_read_32(AXI_DCMPAREACRB0 + 0x8U * no));
+}
+#endif /* RCAR_LOSSY_ENABLE == 1 */
+
+void bl2_plat_flush_bl31_params(void)
+{
+ uint32_t product_cut, product, cut;
+ uint32_t boot_dev, boot_cpu;
+ uint32_t reg;
+
+ 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 && cut < PRR_PRODUCT_30) ||
+ (product == PRR_PRODUCT_H3 && cut < PRR_PRODUCT_20))) {
+ /* Disable MFIS write protection */
+ mmio_write_32(MFISWPCNTR, MFISWPCNTR_PASSWORD | 1U);
+ }
+
+ 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) {
+ 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);
+ }
+ }
+
+ mmio_write_32(IPMMUMM_IMSCTLR, IPMMUMM_IMSCTLR_ENABLE);
+ mmio_write_32(IPMMUMM_IMAUXCTLR, IPMMUMM_IMAUXCTLR_NMERGE40_BIT);
+
+ rcar_swdt_release();
+ bl2_system_cpg_init();
+
+#if RCAR_BL2_DCACHE == 1
+ /* Disable data cache (clean and invalidate) */
+ disable_mmu_el3();
+#endif /* RCAR_BL2_DCACHE == 1 */
+}
+
+static uint32_t is_ddr_backup_mode(void)
+{
+#if RCAR_SYSTEM_SUSPEND
+ static uint32_t reason = RCAR_COLD_BOOT;
+ static uint32_t once;
+
+ if (once != 0U) {
+ return reason;
+ }
+
+ once = 1;
+ if ((mmio_read_32(GPIO_INDT) & GPIO_BKUP_TRG_SHIFT) == 0U) {
+ return reason;
+ }
+
+ reason = RCAR_WARM_BOOT;
+ return reason;
+#else /* RCAR_SYSTEM_SUSPEND */
+ return RCAR_COLD_BOOT;
+#endif /* RCAR_SYSTEM_SUSPEND */
+}
+
+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) {
+ *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);
+ }
+
+ *boot_kind = RCAR_COLD_BOOT;
+ flush_dcache_range(BOOT_KIND_BASE, sizeof(*boot_kind));
+
+ return 0;
+}
+
+static uint64_t rzg_get_dest_addr_from_cert(uint32_t certid, uintptr_t *dest)
+{
+ uint32_t cert, len;
+ int err;
+
+ err = rcar_get_certificate(certid, &cert);
+ if (err != 0) {
+ ERROR("%s : cert file load error", __func__);
+ return 1U;
+ }
+
+ rcar_read_certificate((uint64_t)cert, &len, dest);
+
+ return 0U;
+}
+
+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;
+ uintptr_t dest;
+ uint64_t ret;
+
+ if (params == NULL) {
+ 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:
+ ret = rzg_get_dest_addr_from_cert(SOC_FW_CONTENT_CERT_ID,
+ &dest);
+ if (ret == 0U) {
+ bl_mem_params->image_info.image_base = dest;
+ }
+ break;
+ case BL32_IMAGE_ID:
+ ret = rzg_get_dest_addr_from_cert(TRUSTED_OS_FW_CONTENT_CERT_ID,
+ &dest);
+ if (ret == 0U) {
+ bl_mem_params->image_info.image_base = dest;
+ }
+
+ memcpy(&params->bl32_ep_info, &bl_mem_params->ep_info,
+ sizeof(entry_point_info_t));
+ break;
+ case BL33_IMAGE_ID:
+ memcpy(&params->bl33_ep_info, &bl_mem_params->ep_info,
+ sizeof(entry_point_info_t));
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+struct meminfo *bl2_plat_sec_mem_layout(void)
+{
+ return &bl2_tzram_layout;
+}
+
+static void bl2_populate_compatible_string(void *dt)
+{
+ uint32_t board_type;
+ uint32_t board_rev;
+ uint32_t reg;
+ int ret;
+
+ fdt_setprop_u32(dt, 0, "#address-cells", 2);
+ fdt_setprop_u32(dt, 0, "#size-cells", 2);
+
+ /* Populate compatible string */
+ rzg_get_board_type(&board_type, &board_rev);
+ switch (board_type) {
+ case BOARD_HIHOPE_RZ_G2M:
+ ret = fdt_setprop_string(dt, 0, "compatible",
+ "hoperun,hihope-rzg2m");
+ break;
+ case BOARD_HIHOPE_RZ_G2H:
+ ret = fdt_setprop_string(dt, 0, "compatible",
+ "hoperun,hihope-rzg2h");
+ break;
+ case BOARD_HIHOPE_RZ_G2N:
+ ret = fdt_setprop_string(dt, 0, "compatible",
+ "hoperun,hihope-rzg2n");
+ break;
+ case BOARD_EK874_RZ_G2E:
+ ret = fdt_setprop_string(dt, 0, "compatible",
+ "si-linux,cat874");
+ break;
+ default:
+ NOTICE("BL2: Cannot set compatible string, board unsupported\n");
+ panic();
+ break;
+ }
+
+ 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_M3:
+ ret = fdt_appendprop_string(dt, 0, "compatible",
+ "renesas,r8a774a1");
+ break;
+ case PRR_PRODUCT_H3:
+ ret = fdt_appendprop_string(dt, 0, "compatible",
+ "renesas,r8a774e1");
+ break;
+ case PRR_PRODUCT_M3N:
+ ret = fdt_appendprop_string(dt, 0, "compatible",
+ "renesas,r8a774b1");
+ break;
+ case PRR_PRODUCT_E3:
+ ret = fdt_appendprop_string(dt, 0, "compatible",
+ "renesas,r8a774c0");
+ break;
+ default:
+ NOTICE("BL2: Cannot set compatible string, SoC unsupported\n");
+ panic();
+ break;
+ }
+
+ if (ret < 0) {
+ NOTICE("BL2: Cannot set compatible string (ret=%i)\n", ret);
+ panic();
+ }
+}
+
+static int bl2_add_memory_node(uint64_t start, uint64_t size)
+{
+ char nodename[32] = { 0 };
+ uint64_t fdtsize;
+ int ret, node;
+
+ 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) {
+ return ret;
+ }
+
+ ret = fdt_setprop_string(fdt, node, "device_type", "memory");
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = fdt_setprop_u64(fdt, node, "reg", start);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return fdt_appendprop(fdt, node, "reg", &fdtsize, sizeof(fdtsize));
+}
+
+static void bl2_advertise_dram_entries(uint64_t dram_config[8])
+{
+ uint64_t start, size;
+ int ret, chan;
+
+ for (chan = 0; chan < MAX_DRAM_CHANNELS; chan++) {
+ start = dram_config[2 * chan];
+ size = dram_config[2 * chan + 1];
+ if (size == 0U) {
+ continue;
+ }
+
+ NOTICE("BL2: CH%d: %" PRIx64 " - %" PRIx64 ", %" PRId64 " %siB\n",
+ chan, start, start + size - 1U,
+ (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 = MAX_DRAM_CHANNELS - 1; chan >= 0; chan--) {
+ start = dram_config[2 * chan];
+ size = dram_config[2 * chan + 1];
+ if (size == 0U) {
+ continue;
+ }
+
+ /*
+ * Channel 0 is mapped in 32bit space and the first
+ * 128 MiB are reserved
+ */
+ if (chan == 0) {
+ /*
+ * Maximum DDR size in Channel 0 for 32 bit space is 2GB, Add DT node
+ * for remaining region in 64 bit address space
+ */
+ if (size > MAX_DRAM_SIZE_CH0_32BIT_ADDR_SPACE) {
+ start = dram_config[chan] + MAX_DRAM_SIZE_CH0_32BIT_ADDR_SPACE;
+ size -= MAX_DRAM_SIZE_CH0_32BIT_ADDR_SPACE;
+ ret = bl2_add_memory_node(start, size);
+ if (ret < 0) {
+ goto err;
+ }
+ }
+ start = 0x48000000U;
+ size -= 0x8000000U;
+ }
+
+ ret = bl2_add_memory_node(start, size);
+ 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_M3:
+ /* 4GB(2GBx2 2ch split) */
+ dram_config[1] = 0x80000000ULL;
+ dram_config[5] = 0x80000000ULL;
+ break;
+ 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_M3N:
+ /* 4GB(4GBx1) */
+ dram_config[1] = 0x100000000ULL;
+ 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;
+ default:
+ NOTICE("BL2: Detected invalid DRAM entries\n");
+ 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, boot_dev, boot_cpu, 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_g2e = "G2E";
+ const char *product_g2h = "G2H";
+ const char *product_g2m = "G2M";
+ const char *product_g2n = "G2N";
+ 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 == RZ_G2E)
+ uint32_t sscg;
+ const char *sscg_on = "PLL1 SSCG Clock select";
+ const char *sscg_off = "PLL1 nonSSCG Clock select";
+ const char *boot_hyper160 = "HyperFlash(150MHz)";
+#else
+ const char *boot_hyper160 = "HyperFlash(160MHz)";
+#endif /* RCAR_LSI == RZ_G2E */
+#if RZG_LCS_STATE_DETECTION_ENABLE
+ uint32_t lcs;
+ 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";
+#endif /* RZG_LCS_STATE_DETECTION_ENABLE */
+
+#if (RCAR_LOSSY_ENABLE == 1)
+ int fcnlnode;
+#endif /* (RCAR_LOSSY_ENABLE == 1) */
+
+ 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) {
+ rzg_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: RZ/G2 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_M3:
+ str = product_g2m;
+ break;
+ case PRR_PRODUCT_H3:
+ str = product_g2h;
+ break;
+ case PRR_PRODUCT_M3N:
+ str = product_g2n;
+ break;
+ case PRR_PRODUCT_E3:
+ str = product_g2e;
+ break;
+ default:
+ str = unknown;
+ break;
+ }
+
+ if ((product == PRR_PRODUCT_M3) &&
+ ((reg & RCAR_MAJOR_MASK) == PRR_PRODUCT_20)) {
+ if ((reg & PRR_CUT_MASK) == RCAR_M3_CUT_VER11) {
+ /* M3 Ver.1.1 or Ver.1.2 */
+ NOTICE("BL2: PRR is RZ/%s Ver.1.1 / Ver.1.2\n", str);
+ } else {
+ NOTICE("BL2: PRR is RZ/%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 RZ/%s Ver.%d.%d\n", str, major, minor);
+ }
+
+#if (RCAR_LSI == RZ_G2E)
+ 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);
+ }
+#endif /* RCAR_LSI == RZ_G2E */
+
+ rzg_get_board_type(&type, &rev);
+
+ switch (type) {
+ case BOARD_HIHOPE_RZ_G2M:
+ case BOARD_HIHOPE_RZ_G2H:
+ case BOARD_HIHOPE_RZ_G2N:
+ case BOARD_EK874_RZ_G2E:
+ 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_LSI != RCAR_AUTO */
+ 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:
+ str = boot_emmc25x1;
+ break;
+ case MODEMR_BOOT_DEV_EMMC_50X8:
+ str = boot_emmc50x8;
+ break;
+ default:
+ str = unknown;
+ break;
+ }
+ NOTICE("BL2: Boot device is %s\n", str);
+
+ rcar_avs_setting();
+
+#if RZG_LCS_STATE_DETECTION_ENABLE
+ reg = rcar_rom_get_lcs(&lcs);
+ if (reg != 0U) {
+ 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);
+#endif /* RZG_LCS_STATE_DETECTION_ENABLE */
+
+ 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 != 0) {
+ NOTICE("BL2: Failed to DRAM initialize (%d).\n", ret);
+ panic();
+ }
+ rzg_qos_init();
+ }
+
+ /* Set up FDT */
+ ret = fdt_create_empty_tree(fdt, sizeof(fdt_blob));
+ if (ret != 0) {
+ 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 /* RCAR_LOSSY_ENABLE */
+
+ 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 /* USE_COHERENT_MEM */
+ );
+#endif /* RCAR_BL2_DCACHE == 1 */
+}
+
+void bl2_platform_setup(void)
+{
+ /*
+ * Place holder for performing any platform initialization specific
+ * to BL2.
+ */
+}
+
+static void bl2_init_generic_timer(void)
+{
+#if RCAR_LSI == RZ_G2E
+ uint32_t reg_cntfid = EXTAL_EBISU;
+#else
+ uint32_t reg_cntfid;
+ uint32_t modemr;
+ uint32_t modemr_pll;
+ 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];
+#endif /* RCAR_LSI == RZ_G2E */
+
+ /* Update memory mapped and register based frequency */
+ 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);
+}
diff --git a/plat/renesas/rzg/platform.mk b/plat/renesas/rzg/platform.mk
new file mode 100644
index 0000000..f37d7d0
--- /dev/null
+++ b/plat/renesas/rzg/platform.mk
@@ -0,0 +1,274 @@
+#
+# Copyright (c) 2018-2021, Renesas Electronics Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include plat/renesas/common/common.mk
+
+ifndef LSI
+ $(error "Error: Unknown LSI. Please use LSI=<LSI name> to specify the LSI")
+else
+ ifeq (${LSI},AUTO)
+ RCAR_LSI:=${RCAR_AUTO}
+ else ifeq (${LSI},G2M)
+ RCAR_LSI:=${RZ_G2M}
+ 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},G2H)
+ RCAR_LSI:=${RZ_G2H}
+ 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},G2N)
+ RCAR_LSI:=${RZ_G2N}
+ 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},G2E)
+ RCAR_LSI:=${RZ_G2E}
+ 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
+ $(error "Error: ${LSI} is not supported.")
+ endif
+ $(eval $(call add_define,RCAR_LSI))
+endif
+
+# Process RZG_LCS_STATE_DETECTION_ENABLE flag
+# Enable to get LCS state information
+ifndef RZG_LCS_STATE_DETECTION_ENABLE
+RZG_LCS_STATE_DETECTION_ENABLE := 0
+endif
+$(eval $(call add_define,RZG_LCS_STATE_DETECTION_ENABLE))
+
+# Process RCAR_SECURE_BOOT flag
+ifndef RCAR_SECURE_BOOT
+RCAR_SECURE_BOOT := 0
+endif
+$(eval $(call add_define,RCAR_SECURE_BOOT))
+
+# LCS state of RZ/G2 Chip is all CM.
+# However certain chips(RZ/G2M and RZ/G2E) have incorrect factory Fuse settings
+# which results in getting incorrect LCS states
+# if need to enable RCAR_SECURE_BOOT, make sure the chip has proper factory Fuse settings.
+ifeq (${RCAR_SECURE_BOOT},1)
+ ifeq (${RZG_LCS_STATE_DETECTION_ENABLE},0)
+ $(error "Error: Please check the chip has proper factory Fuse settings and set RZG_LCS_STATE_DETECTION_ENABLE to enable.")
+ endif
+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_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
+ifndef AVS_SETTING_ENABLE
+AVS_SETTING_ENABLE := 0
+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 RCAR_GEN3_ULCB flag
+ifndef RCAR_GEN3_ULCB
+RCAR_GEN3_ULCB := 0
+endif
+
+# 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 := 0
+endif
+$(eval $(call add_define,RCAR_SYSTEM_SUSPEND))
+
+# 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))
+
+RZG_SOC :=1
+$(eval $(call add_define,RZG_SOC))
+
+include drivers/renesas/common/ddr/ddr.mk
+include drivers/renesas/rzg/qos/qos.mk
+include drivers/renesas/rzg/pfc/pfc.mk
+include lib/libfdt/libfdt.mk
+
+PLAT_INCLUDES += -Idrivers/renesas/common/ddr \
+ -Idrivers/renesas/rzg/qos \
+ -Idrivers/renesas/rzg/board \
+ -Idrivers/renesas/common \
+ -Idrivers/renesas/common/iic_dvfs \
+ -Idrivers/renesas/common/avs \
+ -Idrivers/renesas/common/delay \
+ -Idrivers/renesas/common/rom \
+ -Idrivers/renesas/common/scif \
+ -Idrivers/renesas/common/emmc \
+ -Idrivers/renesas/common/pwrc \
+ -Idrivers/renesas/common/io
+
+BL2_SOURCES += plat/renesas/rzg/bl2_plat_setup.c \
+ drivers/renesas/rzg/board/board.c
+
+# build the layout images for the bootrom and the necessary srecords
+rzg: rzg_layout_create rzg_srecord
+distclean realclean clean: clean_layout_tool clean_srecord
+
+# layout images
+LAYOUT_TOOLPATH ?= tools/renesas/rzg_layout_create
+
+clean_layout_tool:
+ @echo "clean layout tool"
+ ${Q}${MAKE} -C ${LAYOUT_TOOLPATH} clean
+
+.PHONY: rzg_layout_create
+rzg_layout_create:
+ @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: rzg_srecord
+rzg_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
diff --git a/plat/rockchip/common/aarch32/plat_helpers.S b/plat/rockchip/common/aarch32/plat_helpers.S
new file mode 100644
index 0000000..475c297
--- /dev/null
+++ b/plat/rockchip/common/aarch32/plat_helpers.S
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a12.h>
+#include <plat_private.h>
+#include <plat_pmu_macros.S>
+
+ .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
diff --git a/plat/rockchip/common/aarch32/platform_common.c b/plat/rockchip/common/aarch32/platform_common.c
new file mode 100644
index 0000000..9030951
--- /dev/null
+++ b/plat/rockchip/common/aarch32/platform_common.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+#include <plat_private.h>
+
+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)
+{
+}
diff --git a/plat/rockchip/common/aarch32/pmu_sram_cpus_on.S b/plat/rockchip/common/aarch32/pmu_sram_cpus_on.S
new file mode 100644
index 0000000..a05ae54
--- /dev/null
+++ b/plat/rockchip/common/aarch32/pmu_sram_cpus_on.S
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/rockchip/common/aarch64/plat_helpers.S b/plat/rockchip/common/aarch64/plat_helpers.S
new file mode 100644
index 0000000..4af052b
--- /dev/null
+++ b/plat/rockchip/common/aarch64/plat_helpers.S
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a53.h>
+#include <cortex_a72.h>
+#include <plat_private.h>
+#include <plat_pmu_macros.S>
+
+ .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
diff --git a/plat/rockchip/common/aarch64/platform_common.c b/plat/rockchip/common/aarch64/platform_common.c
new file mode 100644
index 0000000..81e8520
--- /dev/null
+++ b/plat/rockchip/common/aarch64/platform_common.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+#include <plat_private.h>
+
+#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
+}
diff --git a/plat/rockchip/common/aarch64/pmu_sram_cpus_on.S b/plat/rockchip/common/aarch64/pmu_sram_cpus_on.S
new file mode 100644
index 0000000..d91ee0e
--- /dev/null
+++ b/plat/rockchip/common/aarch64/pmu_sram_cpus_on.S
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/rockchip/common/bl31_plat_setup.c b/plat/rockchip/common/bl31_plat_setup.c
new file mode 100644
index 0000000..98ef415
--- /dev/null
+++ b/plat/rockchip/common/bl31_plat_setup.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/mmio.h>
+#include <plat_private.h>
+#include <plat/common/platform.h>
+
+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_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);
+}
diff --git a/plat/rockchip/common/drivers/parameter/ddr_parameter.c b/plat/rockchip/common/drivers/parameter/ddr_parameter.c
new file mode 100644
index 0000000..e89fe1e
--- /dev/null
+++ b/plat/rockchip/common/drivers/parameter/ddr_parameter.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <plat_private.h>
+#include <soc.h>
+
+#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
+ * -----------------------------------------------------------------------------
+ * | <name> | <size> | <description> |
+ * -----------------------------------------------------------------------------
+ * | 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;
+}
diff --git a/plat/rockchip/common/drivers/parameter/ddr_parameter.h b/plat/rockchip/common/drivers/parameter/ddr_parameter.h
new file mode 100644
index 0000000..25c93a1
--- /dev/null
+++ b/plat/rockchip/common/drivers/parameter/ddr_parameter.h
@@ -0,0 +1,44 @@
+/*
+ * 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 <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <plat_private.h>
+#include <soc.h>
+
+#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 + 1];
+ uint64_t s_top[DDR_REGION_NR_MAX + 1];
+};
+
+struct param_ddr_usage ddr_region_usage_parse(uint64_t addr, uint64_t max_mb);
+
+#endif /* DDR_PARAMETER_H */
diff --git a/plat/rockchip/common/drivers/pmu/pmu_com.h b/plat/rockchip/common/drivers/pmu/pmu_com.h
new file mode 100644
index 0000000..5359f73
--- /dev/null
+++ b/plat/rockchip/common/drivers/pmu/pmu_com.h
@@ -0,0 +1,122 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/common/include/plat_macros.S b/plat/rockchip/common/include/plat_macros.S
new file mode 100644
index 0000000..691beeb
--- /dev/null
+++ b/plat/rockchip/common/include/plat_macros.S
@@ -0,0 +1,118 @@
+/*
+ * 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 <drivers/arm/cci.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gicv3.h>
+#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"
+
+.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 */
diff --git a/plat/rockchip/common/include/plat_params.h b/plat/rockchip/common/include/plat_params.h
new file mode 100644
index 0000000..95b850f
--- /dev/null
+++ b/plat/rockchip/common/include/plat_params.h
@@ -0,0 +1,14 @@
+/*
+ * 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 <stdint.h>
+
+#include <export/plat/rockchip/common/plat_params_exp.h>
+
+#endif /* PLAT_PARAMS_H */
diff --git a/plat/rockchip/common/include/plat_private.h b/plat/rockchip/common/include/plat_private.h
new file mode 100644
index 0000000..990d106
--- /dev/null
+++ b/plat/rockchip/common/include/plat_private.h
@@ -0,0 +1,155 @@
+/*
+ * 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 <stdint.h>
+
+#include <lib/psci/psci.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <lib/mmio.h>
+#include <plat_params.h>
+
+#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 */
diff --git a/plat/rockchip/common/include/rockchip_sip_svc.h b/plat/rockchip/common/include/rockchip_sip_svc.h
new file mode 100644
index 0000000..340d653
--- /dev/null
+++ b/plat/rockchip/common/include/rockchip_sip_svc.h
@@ -0,0 +1,27 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/common/params_setup.c b/plat/rockchip/common/params_setup.c
new file mode 100644
index 0000000..68054ad
--- /dev/null
+++ b/plat/rockchip/common/params_setup.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+
+#include <lib/bl_aux_params/bl_aux_params.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/gpio.h>
+#include <libfdt.h>
+#include <lib/coreboot.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <plat_params.h>
+#include <plat_private.h>
+
+static struct bl_aux_gpio_info rst_gpio = { .index = UINT_MAX } ;
+static struct bl_aux_gpio_info poweroff_gpio = { .index = UINT_MAX };
+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;
+#define FDT_BUFFER_SIZE 0x20000
+static uint64_t fdt_buffer[FDT_BUFFER_SIZE / 8];
+
+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 <baud>{<parity>{<bits>{...}}}
+ * 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, FDT_BUFFER_SIZE);
+ 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)
+{
+ if (rst_gpio.index == UINT_MAX)
+ return NULL;
+
+ return &rst_gpio;
+}
+
+struct bl_aux_gpio_info *plat_get_rockchip_gpio_poweroff(void)
+{
+ if (poweroff_gpio.index == UINT_MAX)
+ return NULL;
+
+ 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)
+{
+ int ret;
+
+ /*
+ * Test if this is a FDT passed as a platform-specific parameter
+ * block.
+ */
+ ret = dt_process_fdt(plat_param_from_bl2);
+ if (!ret) {
+ return;
+ } else if (ret != -FDT_ERR_BADMAGIC) {
+ /*
+ * If we found an FDT but couldn't parse it (e.g. corrupt, not
+ * enough space), return and don't attempt to parse the param
+ * as something else, since we know that will also fail. All
+ * we're doing is setting up UART, this doesn't need to be
+ * fatal.
+ */
+ WARN("%s: found FDT but could not parse: error %d\n",
+ __func__, ret);
+ return;
+ }
+
+ bl_aux_params_parse(plat_param_from_bl2, rk_aux_param_handler);
+}
diff --git a/plat/rockchip/common/plat_pm.c b/plat/rockchip/common/plat_pm.c
new file mode 100644
index 0000000..6926887
--- /dev/null
+++ b/plat/rockchip/common/plat_pm.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/psci/psci.h>
+
+#include <plat_private.h>
+
+/* 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)
+{
+ u_register_t 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;
+}
diff --git a/plat/rockchip/common/plat_topology.c b/plat/rockchip/common/plat_topology.c
new file mode 100644
index 0000000..4987eeb
--- /dev/null
+++ b/plat/rockchip/common/plat_topology.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <lib/psci/psci.h>
+
+#include <plat_private.h>
+
+/*******************************************************************************
+ * 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;
+}
diff --git a/plat/rockchip/common/pmusram/cpus_on_fixed_addr.S b/plat/rockchip/common/pmusram/cpus_on_fixed_addr.S
new file mode 100644
index 0000000..6cea2ea
--- /dev/null
+++ b/plat/rockchip/common/pmusram/cpus_on_fixed_addr.S
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+#include <cpus_on_fixed_addr.h>
+
+ .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
diff --git a/plat/rockchip/common/pmusram/cpus_on_fixed_addr.h b/plat/rockchip/common/pmusram/cpus_on_fixed_addr.h
new file mode 100644
index 0000000..bcd2a7c
--- /dev/null
+++ b/plat/rockchip/common/pmusram/cpus_on_fixed_addr.h
@@ -0,0 +1,55 @@
+/*
+ * 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 struct psram_data_t sys_sleep_flag_sram;
+
+#endif /* __ASSEMBLER__ */
+
+#endif
diff --git a/plat/rockchip/common/rockchip_gicv2.c b/plat/rockchip/common/rockchip_gicv2.c
new file mode 100644
index 0000000..8db2b30
--- /dev/null
+++ b/plat/rockchip/common/rockchip_gicv2.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/utils.h>
+
+/******************************************************************************
+ * 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();
+}
diff --git a/plat/rockchip/common/rockchip_gicv3.c b/plat/rockchip/common/rockchip_gicv3.c
new file mode 100644
index 0000000..edae2ef
--- /dev/null
+++ b/plat/rockchip/common/rockchip_gicv3.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/utils.h>
+#include <plat/common/platform.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_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());
+}
diff --git a/plat/rockchip/common/rockchip_sip_svc.c b/plat/rockchip/common/rockchip_sip_svc.c
new file mode 100644
index 0000000..27ef042
--- /dev/null
+++ b/plat/rockchip/common/rockchip_sip_svc.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+#include <tools_share/uuid.h>
+
+#include <plat_sip_calls.h>
+#include <rockchip_sip_svc.h>
+
+/* 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
+);
diff --git a/plat/rockchip/common/rockchip_stack_protector.c b/plat/rockchip/common/rockchip_stack_protector.c
new file mode 100644
index 0000000..1898977
--- /dev/null
+++ b/plat/rockchip/common/rockchip_stack_protector.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <plat/common/platform.h>
+
+#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();
+}
+
diff --git a/plat/rockchip/common/sp_min_plat_setup.c b/plat/rockchip/common/sp_min_plat_setup.c
new file mode 100644
index 0000000..0237b16
--- /dev/null
+++ b/plat/rockchip/common/sp_min_plat_setup.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/mmio.h>
+#include <plat_private.h>
+#include <plat/common/platform.h>
+
+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_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);
+}
diff --git a/plat/rockchip/px30/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/px30/drivers/pmu/plat_pmu_macros.S
new file mode 100644
index 0000000..a757621
--- /dev/null
+++ b/plat/rockchip/px30/drivers/pmu/plat_pmu_macros.S
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+.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
diff --git a/plat/rockchip/px30/drivers/pmu/pmu.c b/plat/rockchip/px30/drivers/pmu/pmu.c
new file mode 100644
index 0000000..5f4e64f
--- /dev/null
+++ b/plat/rockchip/px30/drivers/pmu/pmu.c
@@ -0,0 +1,1071 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <cpus_on_fixed_addr.h>
+#include <plat_private.h>
+#include <pmu.h>
+#include <px30_def.h>
+#include <secure.h>
+#include <soc.h>
+
+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));
+}
diff --git a/plat/rockchip/px30/drivers/pmu/pmu.h b/plat/rockchip/px30/drivers/pmu/pmu.h
new file mode 100644
index 0000000..416d1c1
--- /dev/null
+++ b/plat/rockchip/px30/drivers/pmu/pmu.h
@@ -0,0 +1,331 @@
+/*
+ * 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__ */
diff --git a/plat/rockchip/px30/drivers/secure/secure.c b/plat/rockchip/px30/drivers/secure/secure.c
new file mode 100644
index 0000000..144f945
--- /dev/null
+++ b/plat/rockchip/px30/drivers/secure/secure.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <ddr_parameter.h>
+#include <plat_private.h>
+#include <secure.h>
+#include <px30_def.h>
+
+/**
+ * There are 8 regions for DDR security control
+ * @rgn - the DDR regions 0 ~ 7 which are can be configured.
+ * @st - start address to set as secure
+ * @sz - length of area to set as secure
+ * The internal unit is megabytes, so memory areas need to be aligned
+ * to megabyte borders.
+ */
+static void secure_ddr_region(uint32_t rgn,
+ uintptr_t st, size_t sz)
+{
+ uintptr_t ed = st + sz;
+ uintptr_t st_mb, ed_mb;
+ uint32_t val;
+
+ 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);
+
+ /* map top and base */
+ mmio_write_32(FIREWALL_DDR_BASE +
+ FIREWALL_DDR_FW_DDR_RGN(rgn),
+ RG_MAP_SECURE(ed_mb, st_mb));
+
+ /* enable secure */
+ val = mmio_read_32(FIREWALL_DDR_BASE + FIREWALL_DDR_FW_DDR_CON_REG);
+ val |= BIT(rgn);
+ mmio_write_32(FIREWALL_DDR_BASE +
+ FIREWALL_DDR_FW_DDR_CON_REG, val);
+}
+
+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);
+}
+
+void sgrf_init(void)
+{
+#ifdef PLAT_RK_SECURE_DDR_MINILOADER
+ uint32_t i;
+ struct param_ddr_usage usg;
+
+ /* general secure regions */
+ usg = ddr_region_usage_parse(DDR_PARAM_BASE,
+ PLAT_MAX_DDR_CAPACITY_MB);
+
+ /* region-0 for TF-A, region-1 for optional OP-TEE */
+ assert(usg.s_nr < 7);
+
+ for (i = 0; i < usg.s_nr; i++)
+ secure_ddr_region(7 - i, usg.s_top[i], usg.s_base[i]);
+#endif
+
+ /* secure the trustzone ram */
+ secure_ddr_region(0, TZRAM_BASE, TZRAM_SIZE);
+
+ /* 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);
+}
diff --git a/plat/rockchip/px30/drivers/secure/secure.h b/plat/rockchip/px30/drivers/secure/secure.h
new file mode 100644
index 0000000..498027d
--- /dev/null
+++ b/plat/rockchip/px30/drivers/secure/secure.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SECURE_H
+#define SECURE_H
+
+/***************************************************************************
+ * 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)
+
+/***************************************************************************
+ * 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))
+
+/**************************************************
+ * 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 secure_timer_init(void);
+void sgrf_init(void);
+
+#endif /* SECURE_H */
diff --git a/plat/rockchip/px30/drivers/soc/soc.c b/plat/rockchip/px30/drivers/soc/soc.c
new file mode 100644
index 0000000..200563d
--- /dev/null
+++ b/plat/rockchip/px30/drivers/soc/soc.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+#include <pmu.h>
+#include <px30_def.h>
+#include <secure.h>
+#include <soc.h>
+#include <rockchip_sip_svc.h>
+
+/* 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);
+}
+
+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();
+}
diff --git a/plat/rockchip/px30/drivers/soc/soc.h b/plat/rockchip/px30/drivers/soc/soc.h
new file mode 100644
index 0000000..648d18b
--- /dev/null
+++ b/plat/rockchip/px30/drivers/soc/soc.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __SOC_H__
+#define __SOC_H__
+
+#include <plat_private.h>
+
+#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,
+};
+
+/***************************************************************************
+ * 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
+
+/***************************************************************************
+ * 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
+
+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 px30_soc_reset_config(void);
+
+#endif /* __SOC_H__ */
diff --git a/plat/rockchip/px30/include/plat.ld.S b/plat/rockchip/px30/include/plat.ld.S
new file mode 100644
index 0000000..44cca0d
--- /dev/null
+++ b/plat/rockchip/px30/include/plat.ld.S
@@ -0,0 +1,38 @@
+/*
+ * 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__ */
diff --git a/plat/rockchip/px30/include/plat_sip_calls.h b/plat/rockchip/px30/include/plat_sip_calls.h
new file mode 100644
index 0000000..7b6a6a8
--- /dev/null
+++ b/plat/rockchip/px30/include/plat_sip_calls.h
@@ -0,0 +1,12 @@
+/*
+ * 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__ */
diff --git a/plat/rockchip/px30/include/platform_def.h b/plat/rockchip/px30/include/platform_def.h
new file mode 100644
index 0000000..a11f84f
--- /dev/null
+++ b/plat/rockchip/px30/include/platform_def.h
@@ -0,0 +1,118 @@
+/*
+ * 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 <arch.h>
+#include <common_def.h>
+#include <px30_def.h>
+
+#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 U(1)
+#define PLATFORM_CLUSTER_COUNT U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT U(4)
+#define PLATFORM_CLUSTER1_CORE_COUNT U(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: 1MB */
+#define TZRAM_BASE (0x0)
+#define TZRAM_SIZE (0x100000)
+
+/*******************************************************************************
+ * 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__ */
diff --git a/plat/rockchip/px30/plat_sip_calls.c b/plat/rockchip/px30/plat_sip_calls.c
new file mode 100644
index 0000000..a4b8e55
--- /dev/null
+++ b/plat/rockchip/px30/plat_sip_calls.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+
+#include <plat_sip_calls.h>
+#include <rockchip_sip_svc.h>
+
+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);
+}
diff --git a/plat/rockchip/px30/platform.mk b/plat/rockchip/px30/platform.mk
new file mode 100644
index 0000000..d14ffc4
--- /dev/null
+++ b/plat/rockchip/px30/platform.mk
@@ -0,0 +1,73 @@
+#
+#Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+#
+#SPDX-License-Identifier: BSD-3-Clause
+#
+
+include drivers/arm/gic/v2/gicv2.mk
+
+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/secure/ \
+ -I${RK_PLAT_SOC}/drivers/soc/ \
+ -I${RK_PLAT_SOC}/include/
+
+RK_GIC_SOURCES := ${GICV2_SOURCES} \
+ 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
+
+ifneq (${ENABLE_STACK_PROTECTOR},0)
+PLAT_BL_COMMON_SOURCES += ${RK_PLAT_COMMON}/rockchip_stack_protector.c
+endif
+
+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}/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/secure/secure.c \
+ ${RK_PLAT_SOC}/drivers/soc/soc.c \
+ ${RK_PLAT_SOC}/plat_sip_calls.c
+
+ifdef PLAT_RK_SECURE_DDR_MINILOADER
+BL31_SOURCES += ${RK_PLAT_COMMON}/drivers/parameter/ddr_parameter.c
+endif
+
+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))
diff --git a/plat/rockchip/px30/px30_def.h b/plat/rockchip/px30/px30_def.h
new file mode 100644
index 0000000..efe789e
--- /dev/null
+++ b/plat/rockchip/px30/px30_def.h
@@ -0,0 +1,176 @@
+/*
+ * 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 SIZE_M(n) ((n) * 1024 * 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 UART3_BASE 0xff168000
+#define UART3_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__ */
diff --git a/plat/rockchip/rk3288/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/rk3288/drivers/pmu/plat_pmu_macros.S
new file mode 100644
index 0000000..2003749
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/pmu/plat_pmu_macros.S
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+.macro func_rockchip_clst_warmboot
+ /* Nothing to do for rk3288 */
+.endm
+
+.macro rockchip_clst_warmboot_data
+ /* Nothing to do for rk3288 */
+.endm
diff --git a/plat/rockchip/rk3288/drivers/pmu/pmu.c b/plat/rockchip/rk3288/drivers/pmu/pmu.c
new file mode 100644
index 0000000..d6d7098
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/pmu/pmu.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <plat_private.h>
+#include <pmu.h>
+#include <pmu_com.h>
+#include <rk3288_def.h>
+#include <secure.h>
+#include <soc.h>
+
+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();
+}
diff --git a/plat/rockchip/rk3288/drivers/pmu/pmu.h b/plat/rockchip/rk3288/drivers/pmu/pmu.h
new file mode 100644
index 0000000..06d5528
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/pmu/pmu.h
@@ -0,0 +1,151 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3288/drivers/secure/secure.c b/plat/rockchip/rk3288/drivers/secure/secure.c
new file mode 100644
index 0000000..25e1cca
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/secure/secure.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+
+#include <plat_private.h>
+#include <secure.h>
+#include <soc.h>
+
+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.
+ * @st - start address to set as secure
+ * @sz - length of area to set as secure
+ * 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, size_t sz)
+{
+ uintptr_t ed = st + sz;
+ 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);
+}
diff --git a/plat/rockchip/rk3288/drivers/secure/secure.h b/plat/rockchip/rk3288/drivers/secure/secure.h
new file mode 100644
index 0000000..6c0b2b7
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/secure/secure.h
@@ -0,0 +1,102 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3288/drivers/soc/soc.c b/plat/rockchip/rk3288/drivers/soc/soc.c
new file mode 100644
index 0000000..36f410b
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/soc/soc.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <plat_private.h>
+#include <rk3288_def.h>
+#include <soc.h>
+#include <secure.h>
+
+/* 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)
+ ;
+}
diff --git a/plat/rockchip/rk3288/drivers/soc/soc.h b/plat/rockchip/rk3288/drivers/soc/soc.h
new file mode 100644
index 0000000..b96c4dc
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/soc/soc.h
@@ -0,0 +1,110 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3288/include/plat_sip_calls.h b/plat/rockchip/rk3288/include/plat_sip_calls.h
new file mode 100644
index 0000000..66c4868
--- /dev/null
+++ b/plat/rockchip/rk3288/include/plat_sip_calls.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3288/include/plat_sp_min.ld.S b/plat/rockchip/rk3288/include/plat_sp_min.ld.S
new file mode 100644
index 0000000..2878437
--- /dev/null
+++ b/plat/rockchip/rk3288/include/plat_sp_min.ld.S
@@ -0,0 +1,72 @@
+/*
+ * 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 <lib/xlat_tables/xlat_tables_defs.h>
+
+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 */
diff --git a/plat/rockchip/rk3288/include/platform_def.h b/plat/rockchip/rk3288/include/platform_def.h
new file mode 100644
index 0000000..85ec3fb
--- /dev/null
+++ b/plat/rockchip/rk3288/include/platform_def.h
@@ -0,0 +1,101 @@
+/*
+ * 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 <arch.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#include <bl32_param.h>
+#include <rk3288_def.h>
+
+/*******************************************************************************
+ * 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 U(1)
+#define PLATFORM_CLUSTER_COUNT U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT U(4)
+#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER U(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 */
diff --git a/plat/rockchip/rk3288/include/shared/bl32_param.h b/plat/rockchip/rk3288/include/shared/bl32_param.h
new file mode 100644
index 0000000..ffdb2f3
--- /dev/null
+++ b/plat/rockchip/rk3288/include/shared/bl32_param.h
@@ -0,0 +1,26 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3288/plat_sip_calls.c b/plat/rockchip/rk3288/plat_sip_calls.c
new file mode 100644
index 0000000..5918d58
--- /dev/null
+++ b/plat/rockchip/rk3288/plat_sip_calls.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+
+#include <plat_sip_calls.h>
+#include <rockchip_sip_svc.h>
+
+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);
+}
diff --git a/plat/rockchip/rk3288/platform.mk b/plat/rockchip/rk3288/platform.mk
new file mode 100644
index 0000000..b8dd195
--- /dev/null
+++ b/plat/rockchip/rk3288/platform.mk
@@ -0,0 +1,69 @@
+#
+# Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include drivers/arm/gic/v2/gicv2.mk
+
+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 := ${GICV2_SOURCES} \
+ 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
diff --git a/plat/rockchip/rk3288/rk3288_def.h b/plat/rockchip/rk3288/rk3288_def.h
new file mode 100644
index 0000000..7bff865
--- /dev/null
+++ b/plat/rockchip/rk3288/rk3288_def.h
@@ -0,0 +1,127 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3288/sp_min/sp_min-rk3288.mk b/plat/rockchip/rk3288/sp_min/sp_min-rk3288.mk
new file mode 100644
index 0000000..befdca3
--- /dev/null
+++ b/plat/rockchip/rk3288/sp_min/sp_min-rk3288.mk
@@ -0,0 +1,8 @@
+#
+# 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
diff --git a/plat/rockchip/rk3328/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/rk3328/drivers/pmu/plat_pmu_macros.S
new file mode 100644
index 0000000..cd604d2
--- /dev/null
+++ b/plat/rockchip/rk3328/drivers/pmu/plat_pmu_macros.S
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+.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
diff --git a/plat/rockchip/rk3328/drivers/pmu/pmu.c b/plat/rockchip/rk3328/drivers/pmu/pmu.c
new file mode 100644
index 0000000..a17fef9
--- /dev/null
+++ b/plat/rockchip/rk3328/drivers/pmu/pmu.c
@@ -0,0 +1,667 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <plat_private.h>
+#include <pmu.h>
+#include <pmu_com.h>
+#include <rk3328_def.h>
+
+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));
+}
diff --git a/plat/rockchip/rk3328/drivers/pmu/pmu.h b/plat/rockchip/rk3328/drivers/pmu/pmu.h
new file mode 100644
index 0000000..dfb8912
--- /dev/null
+++ b/plat/rockchip/rk3328/drivers/pmu/pmu.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMU_H
+#define PMU_H
+
+#include <soc.h>
+
+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 */
diff --git a/plat/rockchip/rk3328/drivers/soc/soc.c b/plat/rockchip/rk3328/drivers/soc/soc.c
new file mode 100644
index 0000000..306308f
--- /dev/null
+++ b/plat/rockchip/rk3328/drivers/soc/soc.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <ddr_parameter.h>
+#include <plat_private.h>
+#include <rk3328_def.h>
+#include <soc.h>
+
+/* 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)
+{
+#ifdef PLAT_RK_SECURE_DDR_MINILOADER
+ 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]));
+ }
+#endif
+
+ /* 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);
+}
diff --git a/plat/rockchip/rk3328/drivers/soc/soc.h b/plat/rockchip/rk3328/drivers/soc/soc.h
new file mode 100644
index 0000000..e8cbc09
--- /dev/null
+++ b/plat/rockchip/rk3328/drivers/soc/soc.h
@@ -0,0 +1,111 @@
+/*
+ * 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
+
+/**************************** 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 */
diff --git a/plat/rockchip/rk3328/include/plat.ld.S b/plat/rockchip/rk3328/include/plat.ld.S
new file mode 100644
index 0000000..e9bb3a2
--- /dev/null
+++ b/plat/rockchip/rk3328/include/plat.ld.S
@@ -0,0 +1,37 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3328/include/platform_def.h b/plat/rockchip/rk3328/include/platform_def.h
new file mode 100644
index 0000000..6579756
--- /dev/null
+++ b/plat/rockchip/rk3328/include/platform_def.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <plat/common/common_def.h>
+
+#include <rk3328_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 PLATFORM_SYSTEM_COUNT 1
+#define PLATFORM_CLUSTER_COUNT U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT U(4)
+#define PLATFORM_CLUSTER1_CORE_COUNT U(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: 1MB */
+#define TZRAM_BASE (0x0)
+#define TZRAM_SIZE (0x100000)
+
+/*******************************************************************************
+ * 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 */
diff --git a/plat/rockchip/rk3328/platform.mk b/plat/rockchip/rk3328/platform.mk
new file mode 100644
index 0000000..5b4766d
--- /dev/null
+++ b/plat/rockchip/rk3328/platform.mk
@@ -0,0 +1,75 @@
+#
+# Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include drivers/arm/gic/v2/gicv2.mk
+
+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 := ${GICV2_SOURCES} \
+ 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
+
+ifneq (${ENABLE_STACK_PROTECTOR},0)
+PLAT_BL_COMMON_SOURCES += ${RK_PLAT_COMMON}/rockchip_stack_protector.c
+endif
+
+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}/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
+
+ifdef PLAT_RK_SECURE_DDR_MINILOADER
+BL31_SOURCES += ${RK_PLAT_COMMON}/drivers/parameter/ddr_parameter.c
+endif
+
+include lib/coreboot/coreboot.mk
+include lib/libfdt/libfdt.mk
+
+# Enable workarounds for selected Cortex-A53 errata
+ERRATA_A53_855873 := 1
+
+$(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
diff --git a/plat/rockchip/rk3328/rk3328_def.h b/plat/rockchip/rk3328/rk3328_def.h
new file mode 100644
index 0000000..60055e8
--- /dev/null
+++ b/plat/rockchip/rk3328/rk3328_def.h
@@ -0,0 +1,151 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3368/drivers/ddr/ddr_rk3368.c b/plat/rockchip/rk3368/drivers/ddr/ddr_rk3368.c
new file mode 100644
index 0000000..fa98eb3
--- /dev/null
+++ b/plat/rockchip/rk3368/drivers/ddr/ddr_rk3368.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <ddr_rk3368.h>
+#include <pmu.h>
+#include <rk3368_def.h>
+#include <soc.h>
+
+/* 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;
+}
diff --git a/plat/rockchip/rk3368/drivers/ddr/ddr_rk3368.h b/plat/rockchip/rk3368/drivers/ddr/ddr_rk3368.h
new file mode 100644
index 0000000..6663bcb
--- /dev/null
+++ b/plat/rockchip/rk3368/drivers/ddr/ddr_rk3368.h
@@ -0,0 +1,247 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3368/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/rk3368/drivers/pmu/plat_pmu_macros.S
new file mode 100644
index 0000000..399f61c
--- /dev/null
+++ b/plat/rockchip/rk3368/drivers/pmu/plat_pmu_macros.S
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+.macro func_rockchip_clst_warmboot
+ /* Nothing to do for rk3368 */
+.endm
+
+.macro rockchip_clst_warmboot_data
+ /* Nothing to do for rk3368 */
+.endm
diff --git a/plat/rockchip/rk3368/drivers/pmu/pmu.c b/plat/rockchip/rk3368/drivers/pmu/pmu.c
new file mode 100644
index 0000000..e277a18
--- /dev/null
+++ b/plat/rockchip/rk3368/drivers/pmu/pmu.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <ddr_rk3368.h>
+#include <plat_private.h>
+#include <pmu.h>
+#include <pmu_com.h>
+#include <rk3368_def.h>
+#include <soc.h>
+
+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));
+}
diff --git a/plat/rockchip/rk3368/drivers/pmu/pmu.h b/plat/rockchip/rk3368/drivers/pmu/pmu.h
new file mode 100644
index 0000000..b4d4807
--- /dev/null
+++ b/plat/rockchip/rk3368/drivers/pmu/pmu.h
@@ -0,0 +1,207 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3368/drivers/soc/soc.c b/plat/rockchip/rk3368/drivers/soc/soc.c
new file mode 100644
index 0000000..7d51bb8
--- /dev/null
+++ b/plat/rockchip/rk3368/drivers/soc/soc.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <plat_private.h>
+#include <rk3368_def.h>
+#include <soc.h>
+
+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)
+ ;
+}
diff --git a/plat/rockchip/rk3368/drivers/soc/soc.h b/plat/rockchip/rk3368/drivers/soc/soc.h
new file mode 100644
index 0000000..6c7a01b
--- /dev/null
+++ b/plat/rockchip/rk3368/drivers/soc/soc.h
@@ -0,0 +1,141 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3368/include/plat.ld.S b/plat/rockchip/rk3368/include/plat.ld.S
new file mode 100644
index 0000000..e9bb3a2
--- /dev/null
+++ b/plat/rockchip/rk3368/include/plat.ld.S
@@ -0,0 +1,37 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3368/include/plat_sip_calls.h b/plat/rockchip/rk3368/include/plat_sip_calls.h
new file mode 100644
index 0000000..66c4868
--- /dev/null
+++ b/plat/rockchip/rk3368/include/plat_sip_calls.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3368/include/platform_def.h b/plat/rockchip/rk3368/include/platform_def.h
new file mode 100644
index 0000000..519a025
--- /dev/null
+++ b/plat/rockchip/rk3368/include/platform_def.h
@@ -0,0 +1,120 @@
+/*
+ * 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 <arch.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#include <rk3368_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 PLATFORM_SYSTEM_COUNT U(1)
+#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 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 memory map related constants
+ ******************************************************************************/
+/* TF text, ro, rw, Size: 1MB */
+#define TZRAM_BASE (0x0)
+#define TZRAM_SIZE (0x100000)
+
+/*******************************************************************************
+ * 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 20
+
+/*******************************************************************************
+ * 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 */
diff --git a/plat/rockchip/rk3368/plat_sip_calls.c b/plat/rockchip/rk3368/plat_sip_calls.c
new file mode 100644
index 0000000..5918d58
--- /dev/null
+++ b/plat/rockchip/rk3368/plat_sip_calls.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+
+#include <plat_sip_calls.h>
+#include <rockchip_sip_svc.h>
+
+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);
+}
diff --git a/plat/rockchip/rk3368/platform.mk b/plat/rockchip/rk3368/platform.mk
new file mode 100644
index 0000000..e6c62de
--- /dev/null
+++ b/plat/rockchip/rk3368/platform.mk
@@ -0,0 +1,67 @@
+#
+# Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include drivers/arm/gic/v2/gicv2.mk
+
+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 := ${GICV2_SOURCES} \
+ 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
+
+ifneq (${ENABLE_STACK_PROTECTOR},0)
+PLAT_BL_COMMON_SOURCES += ${RK_PLAT_COMMON}/rockchip_stack_protector.c
+endif
+
+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
diff --git a/plat/rockchip/rk3368/rk3368_def.h b/plat/rockchip/rk3368/rk3368_def.h
new file mode 100644
index 0000000..4b0fbab
--- /dev/null
+++ b/plat/rockchip/rk3368/rk3368_def.h
@@ -0,0 +1,116 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3399/drivers/dp/cdn_dp.c b/plat/rockchip/rk3399/drivers/dp/cdn_dp.c
new file mode 100644
index 0000000..a8773f4
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dp/cdn_dp.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <cdefs.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <lib/smccc.h>
+
+#include <cdn_dp.h>
+
+__asm__(
+ ".pushsection .text.hdcp_handler, \"ax\", %progbits\n"
+ ".global hdcp_handler\n"
+ ".balign 4\n"
+ "hdcp_handler:\n"
+ ".incbin \"" 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;
+}
diff --git a/plat/rockchip/rk3399/drivers/dp/cdn_dp.h b/plat/rockchip/rk3399/drivers/dp/cdn_dp.h
new file mode 100644
index 0000000..c5cbae2
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dp/cdn_dp.h
@@ -0,0 +1,49 @@
+/*
+ * 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 <plat_private.h>
+
+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 */
diff --git a/plat/rockchip/rk3399/drivers/dram/dfs.c b/plat/rockchip/rk3399/drivers/dram/dfs.c
new file mode 100644
index 0000000..816372b
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/dfs.c
@@ -0,0 +1,2114 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <m0_ctl.h>
+#include <plat_private.h>
+#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 *ram_config,
+ uint8_t channel, uint8_t cs)
+{
+ struct rk3399_sdram_channel *ch = &ram_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);
+}
diff --git a/plat/rockchip/rk3399/drivers/dram/dfs.h b/plat/rockchip/rk3399/drivers/dram/dfs.h
new file mode 100644
index 0000000..172b2a7
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/dfs.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DFS_H
+#define DFS_H
+
+#include <stdint.h>
+
+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 */
diff --git a/plat/rockchip/rk3399/drivers/dram/dram.c b/plat/rockchip/rk3399/drivers/dram/dram.c
new file mode 100644
index 0000000..42b6294
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/dram.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <dram.h>
+#include <plat_private.h>
+#include <rk3399_def.h>
+#include <secure.h>
+#include <soc.h>
+
+__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);
+ }
+}
diff --git a/plat/rockchip/rk3399/drivers/dram/dram.h b/plat/rockchip/rk3399/drivers/dram/dram.h
new file mode 100644
index 0000000..5572b16
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/dram.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRAM_H
+#define DRAM_H
+
+#include <stdint.h>
+
+#include <dram_regs.h>
+#include <plat_private.h>
+
+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 struct rk3399_sdram_params sdram_config;
+
+void dram_init(void);
+
+#endif /* DRAM_H */
diff --git a/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c
new file mode 100644
index 0000000..3cdb7a2
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c
@@ -0,0 +1,1324 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <lib/utils.h>
+
+#include <dram.h>
+
+#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;
+ }
+}
diff --git a/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.h b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.h
new file mode 100644
index 0000000..9cda22c
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.h
@@ -0,0 +1,507 @@
+/*
+ * 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 <stdint.h>
+
+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 */
diff --git a/plat/rockchip/rk3399/drivers/dram/suspend.c b/plat/rockchip/rk3399/drivers/dram/suspend.c
new file mode 100644
index 0000000..a8b1c32
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/suspend.c
@@ -0,0 +1,852 @@
+/*
+ * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#include <dram.h>
+#include <plat_private.h>
+#include <pmu.h>
+#include <pmu_bits.h>
+#include <pmu_regs.h>
+#include <rk3399_def.h>
+#include <secure.h>
+#include <soc.h>
+#include <suspend.h>
+
+#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;
+__pmusramdata uint8_t pmu_enable_watchdog0;
+
+/*
+ * 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)&params_ctl[1],
+ CTL_REG_NUM - 1);
+ mmio_write_32(CTL_REG(ch, 0), params_ctl[0]);
+ sram_regcpy(PI_REG(ch, 0), (uintptr_t)&params_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++) {
+ /*
+ * Without this disabled for LPDDR4 we end up writing 0's
+ * in place of real data in an interesting pattern.
+ */
+ if (sdram_params->dramtype != LPDDR4) {
+ 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)&params_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)&params_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 phy_dll_bypass_set(uint32_t ch, uint32_t freq)
+{
+ if (freq <= (125 * 1000 * 1000)) {
+ /* Set master mode to SW for slices*/
+ mmio_setbits_32(PHY_REG(ch, 86), 3 << 10);
+ mmio_setbits_32(PHY_REG(ch, 214), 3 << 10);
+ mmio_setbits_32(PHY_REG(ch, 342), 3 << 10);
+ mmio_setbits_32(PHY_REG(ch, 470), 3 << 10);
+ /* Set master mode to SW for address slices*/
+ mmio_setbits_32(PHY_REG(ch, 547), 3 << 18);
+ mmio_setbits_32(PHY_REG(ch, 675), 3 << 18);
+ mmio_setbits_32(PHY_REG(ch, 803), 3 << 18);
+ } else {
+ /* Clear SW master mode for slices*/
+ mmio_clrbits_32(PHY_REG(ch, 86), 3 << 10);
+ mmio_clrbits_32(PHY_REG(ch, 214), 3 << 10);
+ mmio_clrbits_32(PHY_REG(ch, 342), 3 << 10);
+ mmio_clrbits_32(PHY_REG(ch, 470), 3 << 10);
+ /* Clear SW master mode for address slices*/
+ mmio_clrbits_32(PHY_REG(ch, 547), 3 << 18);
+ mmio_clrbits_32(PHY_REG(ch, 675), 3 << 18);
+ mmio_clrbits_32(PHY_REG(ch, 803), 3 << 18);
+ }
+}
+
+__pmusramfunc void dmc_resume(void)
+{
+ struct rk3399_sdram_params *sdram_params = &sdram_config;
+ uint32_t channel_mask = 0;
+ uint32_t channel;
+
+ /*
+ * We can't turn off the watchdog, so if we have not turned it on before
+ * we should not turn it on here.
+ */
+ if ((pmu_enable_watchdog0 & 0x1) == 0x1) {
+ 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);
+ /*
+ * Without this, LPDDR4 will write 0's in place of real data
+ * in a strange pattern.
+ */
+ if (sdram_params->dramtype == LPDDR4) {
+ phy_dll_bypass_set(channel, sdram_params->ddr_freq);
+ }
+ 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);
+
+ /*
+ * Training here will always fail for LPDDR4, so skip it
+ * If traning fail, retry to do it again.
+ */
+ if (sdram_params->dramtype != LPDDR4 &&
+ 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);
+}
diff --git a/plat/rockchip/rk3399/drivers/dram/suspend.h b/plat/rockchip/rk3399/drivers/dram/suspend.h
new file mode 100644
index 0000000..1389944
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/suspend.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUSPEND_H
+#define SUSPEND_H
+
+#include <stdint.h>
+#include <dram.h>
+
+#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);
+extern __pmusramdata uint8_t pmu_enable_watchdog0;
+
+#endif /* SUSPEND_H */
diff --git a/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c b/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c
new file mode 100644
index 0000000..724968f
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/gpio.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <plat_private.h>
+#include <soc.h>
+
+struct gpio_save {
+ 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)
+
+enum {
+ ENC_ZDZU,
+ ENC_ZUDR,
+ ENC_ZUDZ,
+ NUM_ENC
+};
+
+static const struct port_info {
+ uint32_t clkgate_reg;
+ uint32_t pull_base;
+ uint32_t port_base;
+ /*
+ * Selects the pull mode encoding per bank,
+ * first index for pull_type_{hw2sw,sw2hw}
+ */
+ uint8_t pull_enc[4];
+ uint8_t clkgate_bit;
+ uint8_t max_bank;
+} port_info[] = {
+ {
+ .clkgate_reg = PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
+ .pull_base = PMUGRF_BASE + PMUGRF_GPIO0A_P,
+ .port_base = GPIO0_BASE,
+ .pull_enc = {ENC_ZDZU, ENC_ZDZU},
+ .clkgate_bit = PCLK_GPIO0_GATE_SHIFT,
+ .max_bank = 1,
+ }, {
+ .clkgate_reg = PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
+ .pull_base = PMUGRF_BASE + PMUGRF_GPIO1A_P,
+ .port_base = GPIO1_BASE,
+ .pull_enc = {ENC_ZUDR, ENC_ZUDR, ENC_ZUDR, ENC_ZUDR},
+ .clkgate_bit = PCLK_GPIO1_GATE_SHIFT,
+ .max_bank = 3,
+ }, {
+ .clkgate_reg = CRU_BASE + CRU_CLKGATE_CON(31),
+ .pull_base = GRF_BASE + GRF_GPIO2A_P,
+ .port_base = GPIO2_BASE,
+ .pull_enc = {ENC_ZUDR, ENC_ZUDR, ENC_ZDZU, ENC_ZDZU},
+ .clkgate_bit = PCLK_GPIO2_GATE_SHIFT,
+ .max_bank = 3,
+ }, {
+ .clkgate_reg = CRU_BASE + CRU_CLKGATE_CON(31),
+ .pull_base = GRF_BASE + GRF_GPIO3A_P,
+ .port_base = GPIO3_BASE,
+ .pull_enc = {ENC_ZUDR, ENC_ZUDR, ENC_ZUDR, ENC_ZUDR},
+ .clkgate_bit = PCLK_GPIO3_GATE_SHIFT,
+ .max_bank = 3,
+ }, {
+ .clkgate_reg = CRU_BASE + CRU_CLKGATE_CON(31),
+ .pull_base = GRF_BASE + GRF_GPIO4A_P,
+ .port_base = GPIO4_BASE,
+ .pull_enc = {ENC_ZUDR, ENC_ZUDR, ENC_ZUDR, ENC_ZUDR},
+ .clkgate_bit = PCLK_GPIO4_GATE_SHIFT,
+ .max_bank = 3,
+ }
+};
+
+/*
+ * Mappings between TF-A constants and hardware encodings:
+ * there are 3 different encoding schemes that may differ between
+ * banks of the same port: the corresponding value of the pull_enc array
+ * in port_info is used as the first index
+ */
+static const uint8_t pull_type_hw2sw[NUM_ENC][4] = {
+ [ENC_ZDZU] = {GPIO_PULL_NONE, GPIO_PULL_DOWN, GPIO_PULL_NONE, GPIO_PULL_UP},
+ [ENC_ZUDR] = {GPIO_PULL_NONE, GPIO_PULL_UP, GPIO_PULL_DOWN, GPIO_PULL_REPEATER},
+ [ENC_ZUDZ] = {GPIO_PULL_NONE, GPIO_PULL_UP, GPIO_PULL_DOWN, GPIO_PULL_NONE}
+};
+static const uint8_t pull_type_sw2hw[NUM_ENC][4] = {
+ [ENC_ZDZU] = {
+ [GPIO_PULL_NONE] = 0,
+ [GPIO_PULL_DOWN] = 1,
+ [GPIO_PULL_UP] = 3,
+ [GPIO_PULL_REPEATER] = -1
+ },
+ [ENC_ZUDR] = {
+ [GPIO_PULL_NONE] = 0,
+ [GPIO_PULL_DOWN] = 2,
+ [GPIO_PULL_UP] = 1,
+ [GPIO_PULL_REPEATER] = 3
+ },
+ [ENC_ZUDZ] = {
+ [GPIO_PULL_NONE] = 0,
+ [GPIO_PULL_DOWN] = 2,
+ [GPIO_PULL_UP] = 1,
+ [GPIO_PULL_REPEATER] = -1
+ }
+};
+
+/* Return 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);
+ assert(port < 5U);
+
+ const struct port_info *info = &port_info[port];
+
+ if ((mmio_read_32(info->clkgate_reg) & (1U << info->clkgate_bit)) == 0U) {
+ return 0;
+ }
+ mmio_write_32(
+ info->clkgate_reg,
+ BITS_WITH_WMASK(0, 1, info->clkgate_bit)
+ );
+ return 1;
+}
+
+/* Restore old state of gpio clock, assuming it is running now */
+void gpio_put_clock(uint32_t gpio_number, uint32_t clock_state)
+{
+ if (clock_state == 0) {
+ return;
+ }
+ uint32_t port = GET_GPIO_PORT(gpio_number);
+ const struct port_info *info = &port_info[port];
+
+ mmio_write_32(info->clkgate_reg, BITS_WITH_WMASK(1, 1, info->clkgate_bit));
+}
+
+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 < 5U);
+ const struct port_info *info = &port_info[port];
+
+ assert(bank <= info->max_bank);
+
+ clock_state = gpio_get_clock(gpio);
+ val = (mmio_read_32(info->pull_base + 4 * bank) >> (id * 2)) & GPIO_P_MASK;
+ gpio_put_clock(gpio, clock_state);
+
+ return pull_type_hw2sw[info->pull_enc[bank]][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 < 5U);
+ const struct port_info *info = &port_info[port];
+
+ assert(bank <= info->max_bank);
+
+ uint8_t val = pull_type_sw2hw[info->pull_enc[bank]][pull];
+
+ assert(val != (uint8_t)-1);
+
+ clock_state = gpio_get_clock(gpio);
+ mmio_write_32(
+ info->pull_base + 4 * bank,
+ BITS_WITH_WMASK(val, 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(
+ port_info[port].port_base + SWPORTA_DDR,
+ ((direction == 0) ? 1 : 0) << 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 < 5U) && (num < 32U));
+
+ 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(
+ port_info[port].port_base + SWPORTA_DDR
+ ) >> num) & 1U) == 0) ? 1 : 0;
+ 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(port_info[port].port_base + EXT_PORTA) >> num) &
+ 0x1U;
+ 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 < 5U) && (num < 32U));
+
+ clock_state = gpio_get_clock(gpio);
+ mmio_clrsetbits_32(
+ port_info[port].port_base + SWPORTA_DR,
+ 1 << num,
+ ((value == 0) ? 0 : 1) << num
+ );
+ gpio_put_clock(gpio, clock_state);
+}
+
+void plat_rockchip_save_gpio(void)
+{
+ unsigned 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++) {
+ uint32_t base = port_info[i].port_base;
+
+ store_gpio[i - 2] = (struct gpio_save) {
+ .swporta_dr = mmio_read_32(base + SWPORTA_DR),
+ .swporta_ddr = mmio_read_32(base + SWPORTA_DDR),
+ .inten = mmio_read_32(base + INTEN),
+ .intmask = mmio_read_32(base + INTMASK),
+ .inttype_level = mmio_read_32(base + INTTYPE_LEVEL),
+ .int_polarity = mmio_read_32(base + INT_POLARITY),
+ .debounce = mmio_read_32(base + DEBOUNCE),
+ .ls_sync = mmio_read_32(base + 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++) {
+ uint32_t base = port_info[i].port_base;
+ const struct gpio_save *save = &store_gpio[i - 2];
+
+ mmio_write_32(base + SWPORTA_DR, save->swporta_dr);
+ mmio_write_32(base + SWPORTA_DDR, save->swporta_ddr);
+ mmio_write_32(base + INTEN, save->inten);
+ mmio_write_32(base + INTMASK, save->intmask);
+ mmio_write_32(base + INTTYPE_LEVEL, save->inttype_level),
+ mmio_write_32(base + INT_POLARITY, save->int_polarity);
+ mmio_write_32(base + DEBOUNCE, save->debounce);
+ mmio_write_32(base + LS_SYNC, save->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);
+}
diff --git a/plat/rockchip/rk3399/drivers/m0/Makefile b/plat/rockchip/rk3399/drivers/m0/Makefile
new file mode 100644
index 0000000..79e09f0
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/Makefile
@@ -0,0 +1,125 @@
+#
+# 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)))
diff --git a/plat/rockchip/rk3399/drivers/m0/include/addressmap.h b/plat/rockchip/rk3399/drivers/m0/include/addressmap.h
new file mode 100644
index 0000000..d431437
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/include/addressmap.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ADDRESSMAP_H
+#define ADDRESSMAP_H
+
+#include <addressmap_shared.h>
+
+/* Registers base address for M0 */
+#define MMIO_BASE 0x40000000
+
+#endif /* ADDRESSMAP_H */
diff --git a/plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h b/plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h
new file mode 100644
index 0000000..2e90694
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h
@@ -0,0 +1,32 @@
+/*
+ * 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 <addressmap.h>
+
+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 */
diff --git a/plat/rockchip/rk3399/drivers/m0/src/dram.c b/plat/rockchip/rk3399/drivers/m0/src/dram.c
new file mode 100644
index 0000000..84e8884
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/src/dram.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <dram_regs.h>
+#include <m0_param.h>
+#include <pmu_bits.h>
+#include <pmu_regs.h>
+#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");
+}
diff --git a/plat/rockchip/rk3399/drivers/m0/src/rk3399m0.ld.S b/plat/rockchip/rk3399/drivers/m0/src/rk3399m0.ld.S
new file mode 100644
index 0000000..bfe054e
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/src/rk3399m0.ld.S
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <m0_param.h>
+
+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*) }
+}
diff --git a/plat/rockchip/rk3399/drivers/m0/src/startup.c b/plat/rockchip/rk3399/drivers/m0/src/startup.c
new file mode 100644
index 0000000..dfd8af2
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/src/startup.c
@@ -0,0 +1,92 @@
+/*
+ * 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)
+ ;
+}
diff --git a/plat/rockchip/rk3399/drivers/m0/src/stopwatch.c b/plat/rockchip/rk3399/drivers/m0/src/stopwatch.c
new file mode 100644
index 0000000..5af8caa
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/src/stopwatch.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <m0_param.h>
+#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;
+}
diff --git a/plat/rockchip/rk3399/drivers/m0/src/suspend.c b/plat/rockchip/rk3399/drivers/m0/src/suspend.c
new file mode 100644
index 0000000..9ad2fa2
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/src/suspend.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <pmu_regs.h>
+#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");
+}
diff --git a/plat/rockchip/rk3399/drivers/pmu/m0_ctl.c b/plat/rockchip/rk3399/drivers/pmu/m0_ctl.c
new file mode 100644
index 0000000..cad76ac
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pmu/m0_ctl.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <m0_ctl.h>
+#include <plat_private.h>
+#include <rk3399_def.h>
+#include <secure.h>
+#include <soc.h>
+
+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();
+}
diff --git a/plat/rockchip/rk3399/drivers/pmu/m0_ctl.h b/plat/rockchip/rk3399/drivers/pmu/m0_ctl.h
new file mode 100644
index 0000000..7542e22
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pmu/m0_ctl.h
@@ -0,0 +1,29 @@
+/*
+ * 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 <m0_param.h>
+
+#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 */
diff --git a/plat/rockchip/rk3399/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/rk3399/drivers/pmu/plat_pmu_macros.S
new file mode 100644
index 0000000..546c09a
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pmu/plat_pmu_macros.S
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+#include <pmu_regs.h>
+
+ .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
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.c b/plat/rockchip/rk3399/drivers/pmu/pmu.c
new file mode 100644
index 0000000..3084c4f
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c
@@ -0,0 +1,1626 @@
+/*
+ * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/delay_timer.h>
+#include <drivers/gpio.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <dfs.h>
+#include <m0_ctl.h>
+#include <plat_params.h>
+#include <plat_private.h>
+#include <pmu.h>
+#include <pmu_com.h>
+#include <pwm.h>
+#include <rk3399_def.h>
+#include <secure.h>
+#include <soc.h>
+#include <suspend.h>
+
+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 pmu_power_domains_on(void)
+{
+ clk_gate_con_disable();
+ pmu_set_power_domain(PD_VDU, pmu_pd_on);
+ pmu_set_power_domain(PD_VCODEC, pmu_pd_on);
+ pmu_set_power_domain(PD_RGA, pmu_pd_on);
+ pmu_set_power_domain(PD_IEP, pmu_pd_on);
+ pmu_set_power_domain(PD_EDP, pmu_pd_on);
+ pmu_set_power_domain(PD_GMAC, pmu_pd_on);
+ pmu_set_power_domain(PD_SDIOAUDIO, pmu_pd_on);
+ pmu_set_power_domain(PD_HDCP, pmu_pd_on);
+ pmu_set_power_domain(PD_ISP1, pmu_pd_on);
+ pmu_set_power_domain(PD_ISP0, pmu_pd_on);
+ pmu_set_power_domain(PD_VO, pmu_pd_on);
+ pmu_set_power_domain(PD_TCPD1, pmu_pd_on);
+ pmu_set_power_domain(PD_TCPD0, pmu_pd_on);
+ pmu_set_power_domain(PD_GPU, pmu_pd_on);
+}
+
+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);
+ }
+ pmu_enable_watchdog0 = (uint8_t) store_wdt0[0] & 0x1;
+}
+
+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));
+}
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.h b/plat/rockchip/rk3399/drivers/pmu/pmu.h
new file mode 100644
index 0000000..bb7de50
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMU_H
+#define PMU_H
+
+#include <pmu_bits.h>
+#include <pmu_regs.h>
+#include <soc.h>
+
+/* 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);
+void pmu_power_domains_on(void);
+
+#endif /* PMU_H */
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu_fw.c b/plat/rockchip/rk3399/drivers/pmu/pmu_fw.c
new file mode 100644
index 0000000..25596b1
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu_fw.c
@@ -0,0 +1,22 @@
+/*
+ * 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" \
+ )
+
+INCBIN(RK3399M0FW, "rk3399m0_bin", ".sram.incbin");
+INCBIN(RK3399M0PMUFW, "rk3399m0pmu_bin", ".pmusram.incbin");
diff --git a/plat/rockchip/rk3399/drivers/pwm/pwm.c b/plat/rockchip/rk3399/drivers/pwm/pwm.c
new file mode 100644
index 0000000..11c1565
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pwm/pwm.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_private.h>
+#include <pmu.h>
+#include <pwm.h>
+#include <soc.h>
+
+#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);
+ }
+}
diff --git a/plat/rockchip/rk3399/drivers/pwm/pwm.h b/plat/rockchip/rk3399/drivers/pwm/pwm.h
new file mode 100644
index 0000000..d665392
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pwm/pwm.h
@@ -0,0 +1,13 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3399/drivers/secure/secure.c b/plat/rockchip/rk3399/drivers/secure/secure.c
new file mode 100644
index 0000000..13c83ca
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/secure/secure.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+
+#include <plat_private.h>
+#include <secure.h>
+#include <soc.h>
+
+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.
+ * @st - start address to set as secure
+ * @sz - length of area to set as secure
+ * 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, size_t sz)
+{
+ uintptr_t ed = st + sz;
+ 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);
+}
diff --git a/plat/rockchip/rk3399/drivers/secure/secure.h b/plat/rockchip/rk3399/drivers/secure/secure.h
new file mode 100644
index 0000000..e31c999
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/secure/secure.h
@@ -0,0 +1,105 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3399/drivers/soc/soc.c b/plat/rockchip/rk3399/drivers/soc/soc.c
new file mode 100644
index 0000000..98b5ad6
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/soc/soc.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <dfs.h>
+#include <dram.h>
+#include <m0_ctl.h>
+#include <plat_private.h>
+#include <pmu.h>
+#include <rk3399_def.h>
+#include <secure.h>
+#include <soc.h>
+
+/* 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)
+{
+ pmu_power_domains_on();
+ 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();
+}
diff --git a/plat/rockchip/rk3399/drivers/soc/soc.h b/plat/rockchip/rk3399/drivers/soc/soc.h
new file mode 100644
index 0000000..8daa5bb
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/soc/soc.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOC_H
+#define SOC_H
+
+#include <lib/utils.h>
+
+#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)
+#define PMUGRF_GPIO0A_P 0x040
+#define PMUGRF_GPIO1A_P 0x050
+
+/**************************************************
+ * 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_GPIO2A_P 0xe040
+#define GRF_GPIO3A_P 0xe050
+#define GRF_GPIO4A_P 0xe060
+#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 */
diff --git a/plat/rockchip/rk3399/include/addressmap.h b/plat/rockchip/rk3399/include/addressmap.h
new file mode 100644
index 0000000..dc1c703
--- /dev/null
+++ b/plat/rockchip/rk3399/include/addressmap.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ADDRESSMAP_H
+#define ADDRESSMAP_H
+
+#include <addressmap_shared.h>
+
+/* 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 */
diff --git a/plat/rockchip/rk3399/include/plat.ld.S b/plat/rockchip/rk3399/include/plat.ld.S
new file mode 100644
index 0000000..cfa912f
--- /dev/null
+++ b/plat/rockchip/rk3399/include/plat.ld.S
@@ -0,0 +1,98 @@
+/*
+ * 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 <lib/xlat_tables/xlat_tables_defs.h>
+
+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 */
diff --git a/plat/rockchip/rk3399/include/plat_sip_calls.h b/plat/rockchip/rk3399/include/plat_sip_calls.h
new file mode 100644
index 0000000..66c4868
--- /dev/null
+++ b/plat/rockchip/rk3399/include/plat_sip_calls.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3399/include/platform_def.h b/plat/rockchip/rk3399/include/platform_def.h
new file mode 100644
index 0000000..78269b6
--- /dev/null
+++ b/plat/rockchip/rk3399/include/platform_def.h
@@ -0,0 +1,104 @@
+/*
+ * 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 <arch.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#include <bl31_param.h>
+#include <rk3399_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 PLATFORM_SYSTEM_COUNT U(1)
+#define PLATFORM_CLUSTER_COUNT U(2)
+#define PLATFORM_CLUSTER0_CORE_COUNT U(4)
+#define PLATFORM_CLUSTER1_CORE_COUNT U(2)
+#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER1_CORE_COUNT + \
+ PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER U(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 */
diff --git a/plat/rockchip/rk3399/include/shared/addressmap_shared.h b/plat/rockchip/rk3399/include/shared/addressmap_shared.h
new file mode 100644
index 0000000..84a31b2
--- /dev/null
+++ b/plat/rockchip/rk3399/include/shared/addressmap_shared.h
@@ -0,0 +1,104 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3399/include/shared/bl31_param.h b/plat/rockchip/rk3399/include/shared/bl31_param.h
new file mode 100644
index 0000000..6e7e8ba
--- /dev/null
+++ b/plat/rockchip/rk3399/include/shared/bl31_param.h
@@ -0,0 +1,26 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3399/include/shared/dram_regs.h b/plat/rockchip/rk3399/include/shared/dram_regs.h
new file mode 100644
index 0000000..4d4ebf6
--- /dev/null
+++ b/plat/rockchip/rk3399/include/shared/dram_regs.h
@@ -0,0 +1,100 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3399/include/shared/m0_param.h b/plat/rockchip/rk3399/include/shared/m0_param.h
new file mode 100644
index 0000000..a5311c9
--- /dev/null
+++ b/plat/rockchip/rk3399/include/shared/m0_param.h
@@ -0,0 +1,25 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3399/include/shared/misc_regs.h b/plat/rockchip/rk3399/include/shared/misc_regs.h
new file mode 100644
index 0000000..0160453
--- /dev/null
+++ b/plat/rockchip/rk3399/include/shared/misc_regs.h
@@ -0,0 +1,27 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3399/include/shared/pmu_bits.h b/plat/rockchip/rk3399/include/shared/pmu_bits.h
new file mode 100644
index 0000000..2968d5b
--- /dev/null
+++ b/plat/rockchip/rk3399/include/shared/pmu_bits.h
@@ -0,0 +1,697 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3399/include/shared/pmu_regs.h b/plat/rockchip/rk3399/include/shared/pmu_regs.h
new file mode 100644
index 0000000..43e785e
--- /dev/null
+++ b/plat/rockchip/rk3399/include/shared/pmu_regs.h
@@ -0,0 +1,148 @@
+/*
+ * 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 */
diff --git a/plat/rockchip/rk3399/plat_sip_calls.c b/plat/rockchip/rk3399/plat_sip_calls.c
new file mode 100644
index 0000000..ce8476c
--- /dev/null
+++ b/plat/rockchip/rk3399/plat_sip_calls.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+
+#include <cdn_dp.h>
+#include <dfs.h>
+#include <plat_sip_calls.h>
+#include <rockchip_sip_svc.h>
+
+#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)
+{
+#ifdef PLAT_RK_DP_HDCP
+ uint64_t x5, x6;
+#endif
+
+ switch (smc_fid) {
+ case RK_SIP_DDR_CFG:
+ SMC_RET1(handle, ddr_smc_handler(x1, x2, x3, x4));
+#ifdef PLAT_RK_DP_HDCP
+ 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));
+#endif
+ default:
+ ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+ }
+}
diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk
new file mode 100644
index 0000000..aba67c2
--- /dev/null
+++ b/plat/rockchip/rk3399/platform.mk
@@ -0,0 +1,113 @@
+#
+# Copyright (c) 2016-2020, 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/ \
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+RK_GIC_SOURCES := ${GICV3_SOURCES} \
+ 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
+
+ifneq (${ENABLE_STACK_PROTECTOR},0)
+PLAT_BL_COMMON_SOURCES += ${RK_PLAT_COMMON}/rockchip_stack_protector.c
+endif
+
+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/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_val,RK3399M0FW,\"$(RK3399M0FW)\"))
+
+RK3399M0PMUFW=${BUILD_M0}/${PLAT_M0}pmu.bin
+$(eval $(call add_define_val,RK3399M0PMUFW,\"$(RK3399M0PMUFW)\"))
+
+ifdef PLAT_RK_DP_HDCP
+BL31_SOURCES += ${RK_PLAT_SOC}/drivers/dp/cdn_dp.c
+
+HDCPFW=${RK_PLAT_SOC}/drivers/dp/hdcp.bin
+$(eval $(call add_define_val,HDCPFW,\"$(HDCPFW)\"))
+
+${BUILD_PLAT}/bl31/cdn_dp.o: CCACHE_EXTRAFILES=$(HDCPFW)
+${RK_PLAT_SOC}/drivers/dp/cdn_dp.c: $(HDCPFW)
+endif
+
+# 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)
+
+$(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
diff --git a/plat/rockchip/rk3399/rk3399_def.h b/plat/rockchip/rk3399/rk3399_def.h
new file mode 100644
index 0000000..ba83242
--- /dev/null
+++ b/plat/rockchip/rk3399/rk3399_def.h
@@ -0,0 +1,65 @@
+/*
+ * 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 <addressmap.h>
+
+#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 */
diff --git a/plat/rpi/common/aarch64/plat_helpers.S b/plat/rpi/common/aarch64/plat_helpers.S
new file mode 100644
index 0000000..f045e21
--- /dev/null
+++ b/plat/rpi/common/aarch64/plat_helpers.S
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+#include <cortex_a72.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
+ .globl plat_rpi_get_model
+
+ /* -----------------------------------------------------
+ * 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, #RPI_PRIMARY_CPU
+ cset w0, eq
+ ret
+endfunc plat_is_my_cpu_primary
+
+ /* -----------------------------------------------------
+ * void plat_wait_for_warm_boot (void);
+ *
+ * This function performs any platform specific actions
+ * needed for a CPU to be put into holding pen to wait
+ * for a warm boot request.
+ * The function will never return.
+ * -----------------------------------------------------
+ */
+func plat_wait_for_warm_boot
+ /*
+ * Calculate address of our hold entry.
+ * As the function will never return, there is no need to save LR.
+ */
+ 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_wait_for_warm_boot
+
+ /* -----------------------------------------------------
+ * 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
+ b plat_wait_for_warm_boot
+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
+ mov x1, x30
+ bl plat_is_my_cpu_primary
+ /*
+ * Secondaries always cold boot.
+ */
+ cbz w0, 1f
+ /*
+ * Primaries warm boot if they are requested
+ * to power off.
+ */
+ mov_imm x0, PLAT_RPI3_TM_HOLD_BASE
+ ldr x0, [x0]
+ cmp x0, PLAT_RPI3_TM_HOLD_STATE_BSP_OFF
+ adr x0, plat_wait_for_warm_boot
+ csel x0, x0, xzr, eq
+ ret x1
+1: mov x0, #0
+ ret x1
+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_RPI_MINI_UART_BASE
+ mov x1, xzr
+ mov x2, xzr
+ 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_RPI_MINI_UART_BASE
+ b console_16550_core_putc
+endfunc plat_crash_console_putc
+
+ /* ---------------------------------------------
+ * void plat_crash_console_flush()
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * Out : void.
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func plat_crash_console_flush
+ mov_imm x0, PLAT_RPI_MINI_UART_BASE
+ b console_16550_core_flush
+endfunc plat_crash_console_flush
+
+ /* ---------------------------------------------
+ * int plat_rpi_get_model()
+ * Macro to determine whether we are running on
+ * a Raspberry Pi 3 or 4. Just checks the MIDR for
+ * being either a Cortex-A72 or a Cortex-A53.
+ * Out : return 4 if RPi4, 3 otherwise.
+ * Clobber list : x0
+ * ---------------------------------------------
+ */
+ .macro _plat_rpi_get_model
+ mrs x0, midr_el1
+ and x0, x0, #0xf0 /* Isolate low byte of part number */
+ cmp w0, #0x80 /* Cortex-A72 (RPi4) is 0xd08, A53 is 0xd03 */
+ mov w0, #3
+ csinc w0, w0, w0, ne
+ .endm
+
+ func plat_rpi_get_model
+ _plat_rpi_get_model
+ ret
+ endfunc plat_rpi_get_model
+
+ /* ---------------------------------------------
+ * void plat_reset_handler(void);
+ * ---------------------------------------------
+ */
+func plat_reset_handler
+ /* L2 cache setup only needed on RPi4 */
+ _plat_rpi_get_model
+ cmp w0, #4
+ b.ne 1f
+
+ /* ------------------------------------------------
+ * 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
+
+1:
+ ret
+endfunc plat_reset_handler
diff --git a/plat/rpi/common/include/rpi_shared.h b/plat/rpi/common/include/rpi_shared.h
new file mode 100644
index 0000000..ddf239e
--- /dev/null
+++ b/plat/rpi/common/include/rpi_shared.h
@@ -0,0 +1,41 @@
+/*
+ * 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 <stdint.h>
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+
+/* Utility functions */
+void rpi3_console_init(void);
+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);
+
+int plat_rpi_get_model(void);
+
+#endif /* RPI3_PRIVATE_H */
diff --git a/plat/rpi/common/rpi3_common.c b/plat/rpi/common/rpi3_common.c
new file mode 100644
index 0000000..ef88bf1
--- /dev/null
+++ b/plat/rpi/common/rpi3_common.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <bl31/interrupt_mgmt.h>
+#include <drivers/console.h>
+#include <drivers/rpi3/gpio/rpi3_gpio.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <drivers/arm/pl011.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <rpi_hw.h>
+#include <rpi_shared.h>
+
+#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_t rpi3_console;
+
+
+static bool rpi3_use_mini_uart(void)
+{
+ return rpi3_gpio_get_select(14) == RPI3_GPIO_FUNC_ALT5;
+}
+
+void rpi3_console_init(void)
+{
+ int console_scope = CONSOLE_FLAG_BOOT;
+ int rc;
+
+ if (RPI3_RUNTIME_UART != -1)
+ console_scope |= CONSOLE_FLAG_RUNTIME;
+
+ rpi3_gpio_init();
+
+ if (rpi3_use_mini_uart())
+ rc = console_16550_register(PLAT_RPI_MINI_UART_BASE,
+ 0,
+ PLAT_RPI_UART_BAUDRATE,
+ &rpi3_console);
+ else
+ rc = console_pl011_register(PLAT_RPI_PL011_UART_BASE,
+ PLAT_RPI_PL011_UART_CLOCK,
+ PLAT_RPI_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_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);
+}
diff --git a/plat/rpi/common/rpi3_image_load.c b/plat/rpi/common/rpi3_image_load.c
new file mode 100644
index 0000000..5394c6f
--- /dev/null
+++ b/plat/rpi/common/rpi3_image_load.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.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();
+}
diff --git a/plat/rpi/common/rpi3_io_storage.c b/plat/rpi/common/rpi3_io_storage.c
new file mode 100644
index 0000000..49c6a76
--- /dev/null
+++ b/plat/rpi/common/rpi3_io_storage.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <tools_share/firmware_image_package.h>
+
+/* 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;
+}
diff --git a/plat/rpi/common/rpi3_pm.c b/plat/rpi/common/rpi3_pm.c
new file mode 100644
index 0000000..d98ac66
--- /dev/null
+++ b/plat/rpi/common/rpi3_pm.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include <rpi_hw.h>
+
+#ifdef RPI_HAVE_GIC
+#include <drivers/arm/gicv2.h>
+#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);
+ uintptr_t hold_base = PLAT_RPI3_TM_HOLD_BASE;
+
+ assert(pos < PLATFORM_CORE_COUNT);
+
+ hold_base += pos * PLAT_RPI3_TM_HOLD_ENTRY_SIZE;
+
+ mmio_write_64(hold_base, PLAT_RPI3_TM_HOLD_STATE_GO);
+ /* No cache maintenance here, hold_base is mapped as device memory. */
+
+ /* 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
+}
+
+static void __dead2 rpi3_pwr_down_wfi(
+ const psci_power_state_t *target_state)
+{
+ uintptr_t hold_base = PLAT_RPI3_TM_HOLD_BASE;
+ unsigned int pos = plat_my_core_pos();
+
+ if (pos == 0) {
+ /*
+ * The secondaries will always be in a wait
+ * for warm boot on reset, but the BSP needs
+ * to be able to distinguish between waiting
+ * for warm boot (e.g. after psci_off, waiting
+ * for psci_on) and a cold boot.
+ */
+ mmio_write_64(hold_base, PLAT_RPI3_TM_HOLD_STATE_BSP_OFF);
+ /* No cache maintenance here, we run with caches off already. */
+ dsb();
+ isb();
+ }
+
+ write_rmr_el3(RMR_EL3_RR_BIT | RMR_EL3_AA64_BIT);
+
+ while (1) {
+ wfi();
+ }
+}
+
+/*******************************************************************************
+ * 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,
+ .pwr_domain_pwr_down_wfi = rpi3_pwr_down_wfi,
+ .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;
+}
diff --git a/plat/rpi/common/rpi3_rotpk.S b/plat/rpi/common/rpi3_rotpk.S
new file mode 100644
index 0000000..1c17b21
--- /dev/null
+++ b/plat/rpi/common/rpi3_rotpk.S
@@ -0,0 +1,15 @@
+/*
+ * 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:
diff --git a/plat/rpi/common/rpi3_stack_protector.c b/plat/rpi/common/rpi3_stack_protector.c
new file mode 100644
index 0000000..aae5fac
--- /dev/null
+++ b/plat/rpi/common/rpi3_stack_protector.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <lib/utils.h>
+#include <lib/utils_def.h>
+
+#include <drivers/rpi3/rng/rpi3_rng.h>
+
+/* 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;
+}
diff --git a/plat/rpi/common/rpi3_topology.c b/plat/rpi/common/rpi3_topology.c
new file mode 100644
index 0000000..3747287
--- /dev/null
+++ b/plat/rpi/common/rpi3_topology.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+
+#include <rpi_shared.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_rpi3_calc_core_pos(mpidr);
+}
diff --git a/plat/rpi/common/rpi3_trusted_boot.c b/plat/rpi/common/rpi3_trusted_boot.c
new file mode 100644
index 0000000..f6c669f
--- /dev/null
+++ b/plat/rpi/common/rpi3_trusted_boot.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+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);
+}
diff --git a/plat/rpi/rpi3/aarch64/rpi3_bl2_mem_params_desc.c b/plat/rpi/rpi3/aarch64/rpi3_bl2_mem_params_desc.c
new file mode 100644
index 0000000..715aec4
--- /dev/null
+++ b/plat/rpi/rpi3/aarch64/rpi3_bl2_mem_params_desc.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * 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)
diff --git a/plat/rpi/rpi3/include/plat_macros.S b/plat/rpi/rpi3/include/plat_macros.S
new file mode 100644
index 0000000..c0c3967
--- /dev/null
+++ b/plat/rpi/rpi3/include/plat_macros.S
@@ -0,0 +1,20 @@
+/*
+ * 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 */
diff --git a/plat/rpi/rpi3/include/platform_def.h b/plat/rpi/rpi3/include/platform_def.h
new file mode 100644
index 0000000..f44d1f5
--- /dev/null
+++ b/plat/rpi/rpi3/include/platform_def.h
@@ -0,0 +1,263 @@
+/*
+ * 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 <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#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 RPI_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)
+#define PLAT_RPI3_TM_HOLD_STATE_BSP_OFF ULL(2)
+
+/*
+ * 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_RPI_MINI_UART_BASE RPI3_MINI_UART_BASE
+#define PLAT_RPI_PL011_UART_BASE RPI3_PL011_UART_BASE
+#define PLAT_RPI_PL011_UART_CLOCK RPI3_PL011_UART_CLOCK
+#define PLAT_RPI_UART_BAUDRATE ULL(115200)
+
+/*
+ * System counter
+ */
+#define SYS_COUNTER_FREQ_IN_TICKS ULL(19200000)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/rpi/rpi3/include/rpi_hw.h b/plat/rpi/rpi3/include/rpi_hw.h
new file mode 100644
index 0000000..2aecab3
--- /dev/null
+++ b/plat/rpi/rpi3/include/rpi_hw.h
@@ -0,0 +1,114 @@
+/*
+ * 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 <lib/utils_def.h>
+
+/*
+ * 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 ports:
+ * 'Mini UART' in the BCM docucmentation is the 8250 compatible UART.
+ * There is also a PL011 UART, multiplexed to the same pins.
+ */
+#define RPI3_IO_MINI_UART_OFFSET ULL(0x00215040)
+#define RPI3_MINI_UART_BASE (RPI_IO_BASE + RPI3_IO_MINI_UART_OFFSET)
+#define RPI3_IO_PL011_UART_OFFSET ULL(0x00201000)
+#define RPI3_PL011_UART_BASE (RPI_IO_BASE + RPI3_IO_PL011_UART_OFFSET)
+#define RPI3_PL011_UART_CLOCK ULL(48000000)
+
+/*
+ * 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 */
diff --git a/plat/rpi/rpi3/platform.mk b/plat/rpi/rpi3/platform.mk
new file mode 100644
index 0000000..53c97e2
--- /dev/null
+++ b/plat/rpi/rpi3/platform.mk
@@ -0,0 +1,221 @@
+#
+# Copyright (c) 2013-2020, 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 \
+ drivers/arm/pl011/aarch64/pl011_console.S \
+ drivers/gpio/gpio.c \
+ drivers/delay_timer/delay_timer.c \
+ drivers/rpi3/gpio/rpi3_gpio.c \
+ plat/rpi/common/aarch64/plat_helpers.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/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/delay_timer/generic_delay_timer.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/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/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_common.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 \
+ drivers/auth/tbbr/tbbr_cot_bl1.c
+
+ BL2_SOURCES += ${AUTH_SOURCES} \
+ plat/common/tbbr/plat_tbbr.c \
+ plat/rpi/common/rpi3_trusted_boot.c \
+ plat/rpi/common/rpi3_rotpk.S \
+ drivers/auth/tbbr/tbbr_cot_bl2.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)/bl1/rpi3_rotpk.o: $(ROTPK_HASH)
+ $(BUILD_PLAT)/bl2/rpi3_rotpk.o: $(ROTPK_HASH)
+
+ certificates: $(ROT_KEY)
+
+ $(ROT_KEY): | $(BUILD_PLAT)
+ @echo " OPENSSL $@"
+ $(Q)${OPENSSL_BIN_PATH}/openssl genrsa 2048 > $@ 2>/dev/null
+
+ $(ROTPK_HASH): $(ROT_KEY)
+ @echo " OPENSSL $@"
+ $(Q)${OPENSSL_BIN_PATH}/openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+ ${OPENSSL_BIN_PATH}/openssl dgst -sha256 -binary > $@ 2>/dev/null
+endif
diff --git a/plat/rpi/rpi3/rpi3_bl1_setup.c b/plat/rpi/rpi3/rpi3_bl1_setup.c
new file mode 100644
index 0000000..3ac30e0
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_bl1_setup.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#include <rpi_shared.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)
+{
+ /* 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();
+
+ /* 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();
+}
diff --git a/plat/rpi/rpi3/rpi3_bl2_setup.c b/plat/rpi/rpi3/rpi3_bl2_setup.c
new file mode 100644
index 0000000..db71817
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_bl2_setup.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <lib/optee_utils.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/rpi3/gpio/rpi3_gpio.h>
+#include <drivers/rpi3/sdhost/rpi3_sdhost.h>
+
+#include <rpi_shared.h>
+
+/* Data structure which holds the extents of the trusted SRAM for BL2 */
+static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
+
+/* 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(&params, 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(&params, &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();
+
+ /* Enable arch timer */
+ generic_delay_timer_init();
+
+ /* Setup GPIO driver */
+ rpi3_gpio_init();
+
+ /* 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;
+}
diff --git a/plat/rpi/rpi3/rpi3_bl31_setup.c b/plat/rpi/rpi3/rpi3_bl31_setup.c
new file mode 100644
index 0000000..5915753
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_bl31_setup.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/common/platform.h>
+
+#include <rpi_shared.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;
+
+/*******************************************************************************
+ * 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();
+
+ /*
+ * 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
+}
diff --git a/plat/rpi/rpi3/rpi_mbox_board.c b/plat/rpi/rpi3/rpi_mbox_board.c
new file mode 100644
index 0000000..e7c1e2b
--- /dev/null
+++ b/plat/rpi/rpi3/rpi_mbox_board.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+
+#include <drivers/rpi3/mailbox/rpi3_mbox.h>
+
+#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;
+}
diff --git a/plat/rpi/rpi4/aarch64/armstub8_header.S b/plat/rpi/rpi4/aarch64/armstub8_header.S
new file mode 100644
index 0000000..246358d
--- /dev/null
+++ b/plat/rpi/rpi4/aarch64/armstub8_header.S
@@ -0,0 +1,37 @@
+/*
+ * 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:
diff --git a/plat/rpi/rpi4/include/plat.ld.S b/plat/rpi/rpi4/include/plat.ld.S
new file mode 100644
index 0000000..9262fad
--- /dev/null
+++ b/plat/rpi/rpi4/include/plat.ld.S
@@ -0,0 +1,23 @@
+/*
+ * 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
+}
diff --git a/plat/rpi/rpi4/include/plat_macros.S b/plat/rpi/rpi4/include/plat_macros.S
new file mode 100644
index 0000000..6007d03
--- /dev/null
+++ b/plat/rpi/rpi4/include/plat_macros.S
@@ -0,0 +1,20 @@
+/*
+ * 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 */
diff --git a/plat/rpi/rpi4/include/platform_def.h b/plat/rpi/rpi4/include/platform_def.h
new file mode 100644
index 0000000..6787ebf
--- /dev/null
+++ b/plat/rpi/rpi4/include/platform_def.h
@@ -0,0 +1,140 @@
+/*
+ * 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 <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#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 RPI_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)
+#define PLAT_RPI3_TM_HOLD_STATE_BSP_OFF ULL(2)
+
+/*
+ * 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_RPI_MINI_UART_BASE RPI4_MINI_UART_BASE
+#define PLAT_RPI_PL011_UART_BASE RPI4_PL011_UART_BASE
+#define PLAT_RPI_PL011_UART_CLOCK RPI4_PL011_UART_CLOCK
+#define PLAT_RPI_UART_BAUDRATE ULL(115200)
+
+/*
+ * System counter
+ */
+#define SYS_COUNTER_FREQ_IN_TICKS ULL(54000000)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/rpi/rpi4/include/rpi_hw.h b/plat/rpi/rpi4/include/rpi_hw.h
new file mode 100644
index 0000000..0430d46
--- /dev/null
+++ b/plat/rpi/rpi4/include/rpi_hw.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPI_HW_H
+#define RPI_HW_H
+
+#include <lib/utils_def.h>
+
+/*
+ * Peripherals
+ */
+
+#define RPI_IO_BASE ULL(0xFC000000)
+#define RPI_IO_SIZE ULL(0x04000000)
+
+#define RPI_LEGACY_BASE (ULL(0x02000000) + RPI_IO_BASE)
+
+/*
+ * ARM <-> VideoCore mailboxes
+ */
+#define RPI3_MBOX_OFFSET ULL(0x0000B880)
+#define RPI3_MBOX_BASE (RPI_LEGACY_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_LEGACY_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_LEGACY_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 ports:
+ * 'Mini UART' in the BCM docucmentation is the 8250 compatible UART.
+ * There is also a PL011 UART, multiplexed to the same pins.
+ */
+#define RPI4_IO_MINI_UART_OFFSET ULL(0x00215040)
+#define RPI4_MINI_UART_BASE (RPI_LEGACY_BASE + RPI4_IO_MINI_UART_OFFSET)
+#define RPI4_IO_PL011_UART_OFFSET ULL(0x00201000)
+#define RPI4_PL011_UART_BASE (RPI_LEGACY_BASE + RPI4_IO_PL011_UART_OFFSET)
+#define RPI4_PL011_UART_CLOCK ULL(48000000)
+
+/*
+ * GPIO controller
+ */
+#define RPI3_IO_GPIO_OFFSET ULL(0x00200000)
+#define RPI3_GPIO_BASE (RPI_LEGACY_BASE + RPI3_IO_GPIO_OFFSET)
+
+/*
+ * SDHost controller
+ */
+#define RPI3_IO_SDHOST_OFFSET ULL(0x00202000)
+#define RPI3_SDHOST_BASE (RPI_LEGACY_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 */
diff --git a/plat/rpi/rpi4/platform.mk b/plat/rpi/rpi4/platform.mk
new file mode 100644
index 0000000..528eb1d
--- /dev/null
+++ b/plat/rpi/rpi4/platform.mk
@@ -0,0 +1,116 @@
+#
+# Copyright (c) 2013-2021, 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
+
+include drivers/arm/gic/v2/gicv2.mk
+
+PLAT_INCLUDES := -Iplat/rpi/common/include \
+ -Iplat/rpi/rpi4/include
+
+PLAT_BL_COMMON_SOURCES := drivers/ti/uart/aarch64/16550_console.S \
+ drivers/arm/pl011/aarch64/pl011_console.S \
+ plat/rpi/common/rpi3_common.c \
+ ${XLAT_TABLES_LIB_SRCS}
+
+BL31_SOURCES += lib/cpus/aarch64/cortex_a72.S \
+ plat/rpi/common/aarch64/plat_helpers.S \
+ plat/rpi/rpi4/aarch64/armstub8_header.S \
+ drivers/delay_timer/delay_timer.c \
+ drivers/gpio/gpio.c \
+ drivers/rpi3/gpio/rpi3_gpio.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} \
+ ${GICV2_SOURCES}
+
+# 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
+
+# SMCCC PCI support (should be enabled for ACPI builds)
+SMC_PCI_SUPPORT := 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))
+$(eval $(call add_define,SMC_PCI_SUPPORT))
+
+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
+
+ifeq ($(SMC_PCI_SUPPORT), 1)
+BL31_SOURCES += plat/rpi/rpi4/rpi4_pci_svc.c
+endif
+
diff --git a/plat/rpi/rpi4/rpi4_bl31_setup.c b/plat/rpi/rpi4/rpi4_bl31_setup.c
new file mode 100644
index 0000000..2fb4d3d
--- /dev/null
+++ b/plat/rpi/rpi4/rpi4_bl31_setup.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#include <common/fdt_fixup.h>
+#include <common/fdt_wrappers.h>
+#include <libfdt.h>
+
+#include <drivers/arm/gicv2.h>
+
+#include <rpi_shared.h>
+
+/*
+ * 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)
+
+{
+ /*
+ * 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. */
+ rpi3_console_init();
+
+ 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);
+}
+
+/*
+ * Remove the FDT /memreserve/ entry that covers the region at the very
+ * beginning of memory (if that exists). This is where the secondaries
+ * originally spin, but we pull them out there.
+ * Having overlapping /reserved-memory and /memreserve/ regions confuses
+ * the Linux kernel, so we need to get rid of this one.
+ */
+static void remove_spintable_memreserve(void *dtb)
+{
+ uint64_t addr, size;
+ int regions = fdt_num_mem_rsv(dtb);
+ int i;
+
+ for (i = 0; i < regions; i++) {
+ if (fdt_get_mem_rsv(dtb, i, &addr, &size) != 0) {
+ return;
+ }
+ if (size == 0U) {
+ return;
+ }
+ /* We only look for the region at the beginning of DRAM. */
+ if (addr != 0U) {
+ continue;
+ }
+ /*
+ * Currently the region in the existing DTs is exactly 4K
+ * in size. Should this value ever change, there is probably
+ * a reason for that, so inform the user about this.
+ */
+ if (size == 4096U) {
+ fdt_del_mem_rsv(dtb, i);
+ return;
+ }
+ WARN("Keeping unknown /memreserve/ region at 0, size: %" PRId64 "\n",
+ size);
+ }
+}
+
+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;
+ }
+
+ /*
+ * Remove the original reserved region (used for the spintable), and
+ * replace it with a region describing the whole of Trusted Firmware.
+ */
+ remove_spintable_memreserve(dtb);
+ 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, fdt_blob_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();
+}
diff --git a/plat/rpi/rpi4/rpi4_pci_svc.c b/plat/rpi/rpi4/rpi4_pci_svc.c
new file mode 100644
index 0000000..7d1ca5c
--- /dev/null
+++ b/plat/rpi/rpi4/rpi4_pci_svc.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * The RPi4 has a single nonstandard PCI config region. It is broken into two
+ * pieces, the root port config registers and a window to a single device's
+ * config space which can move between devices. There isn't (yet) an
+ * authoritative public document on this since the available BCM2711 reference
+ * notes that there is a PCIe root port in the memory map but doesn't describe
+ * it. Given that it's not ECAM compliant yet reasonably simple, it makes for
+ * an excellent example of the PCI SMCCC interface.
+ *
+ * The PCI SMCCC interface is described in DEN0115 availabe from:
+ * https://developer.arm.com/documentation/den0115/latest
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/pmf/pmf.h>
+#include <lib/runtime_instr.h>
+#include <services/pci_svc.h>
+#include <services/sdei.h>
+#include <services/std_svc.h>
+#include <smccc_helpers.h>
+
+#include <lib/mmio.h>
+
+static spinlock_t pci_lock;
+
+#define PCIE_REG_BASE U(RPI_IO_BASE + 0x01500000)
+#define PCIE_MISC_PCIE_STATUS 0x4068
+#define PCIE_EXT_CFG_INDEX 0x9000
+/* A small window pointing at the ECAM of the device selected by CFG_INDEX */
+#define PCIE_EXT_CFG_DATA 0x8000
+#define INVALID_PCI_ADDR 0xFFFFFFFF
+
+#define PCIE_EXT_BUS_SHIFT 20
+#define PCIE_EXT_DEV_SHIFT 15
+#define PCIE_EXT_FUN_SHIFT 12
+
+
+static uint64_t pci_segment_lib_get_base(uint32_t address, uint32_t offset)
+{
+ uint64_t base;
+ uint32_t bus, dev, fun;
+ uint32_t status;
+
+ base = PCIE_REG_BASE;
+
+ offset &= PCI_OFFSET_MASK; /* Pick off the 4k register offset */
+
+ /* The root port is at the base of the PCIe register space */
+ if (address != 0U) {
+ /*
+ * The current device must be at CFG_DATA, a 4K window mapped,
+ * via CFG_INDEX, to the device we are accessing. At the same
+ * time we must avoid accesses to certain areas of the cfg
+ * space via CFG_DATA. Detect those accesses and report that
+ * the address is invalid.
+ */
+ base += PCIE_EXT_CFG_DATA;
+ bus = PCI_ADDR_BUS(address);
+ dev = PCI_ADDR_DEV(address);
+ fun = PCI_ADDR_FUN(address);
+ address = (bus << PCIE_EXT_BUS_SHIFT) |
+ (dev << PCIE_EXT_DEV_SHIFT) |
+ (fun << PCIE_EXT_FUN_SHIFT);
+
+ /* Allow only dev = 0 on root port and bus 1 */
+ if ((bus < 2U) && (dev > 0U)) {
+ return INVALID_PCI_ADDR;
+ }
+
+ /* Assure link up before reading bus 1 */
+ status = mmio_read_32(PCIE_REG_BASE + PCIE_MISC_PCIE_STATUS);
+ if ((status & 0x30) != 0x30) {
+ return INVALID_PCI_ADDR;
+ }
+
+ /* Adjust which device the CFG_DATA window is pointing at */
+ mmio_write_32(PCIE_REG_BASE + PCIE_EXT_CFG_INDEX, address);
+ }
+ return base + offset;
+}
+
+/**
+ * pci_read_config() - Performs a config space read at addr
+ * @addr: 32-bit, segment, BDF of requested function encoded per DEN0115
+ * @off: register offset of function described by @addr to read
+ * @sz: size of read (8,16,32) bits.
+ * @val: returned zero extended value read from config space
+ *
+ * sz bits of PCI config space is read at addr:offset, and the value
+ * is returned in val. Invalid segment/offset values return failure.
+ * Reads to valid functions that don't exist return INVALID_PCI_ADDR
+ * as is specified by PCI for requests that aren't completed by EPs.
+ * The boilerplate in pci_svc.c tends to do basic segment, off
+ * and sz validation. This routine should avoid duplicating those
+ * checks.
+ *
+ * This function maps directly to the PCI_READ function in DEN0115
+ * where detailed requirements may be found.
+ *
+ * Return: SMC_PCI_CALL_SUCCESS with val set
+ * SMC_PCI_CALL_INVAL_PARAM, on parameter error
+ */
+uint32_t pci_read_config(uint32_t addr, uint32_t off, uint32_t sz, uint32_t *val)
+{
+ uint32_t ret = SMC_PCI_CALL_SUCCESS;
+ uint64_t base;
+
+ spin_lock(&pci_lock);
+ base = pci_segment_lib_get_base(addr, off);
+
+ if (base == INVALID_PCI_ADDR) {
+ *val = base;
+ } else {
+ switch (sz) {
+ case SMC_PCI_SZ_8BIT:
+ *val = mmio_read_8(base);
+ break;
+ case SMC_PCI_SZ_16BIT:
+ *val = mmio_read_16(base);
+ break;
+ case SMC_PCI_SZ_32BIT:
+ *val = mmio_read_32(base);
+ break;
+ default: /* should be unreachable */
+ *val = 0;
+ ret = SMC_PCI_CALL_INVAL_PARAM;
+ }
+ }
+ spin_unlock(&pci_lock);
+ return ret;
+}
+
+/**
+ * pci_write_config() - Performs a config space write at addr
+ * @addr: 32-bit, segment, BDF of requested function encoded per DEN0115
+ * @off: register offset of function described by @addr to write
+ * @sz: size of write (8,16,32) bits.
+ * @val: value to be written
+ *
+ * sz bits of PCI config space is written at addr:offset. Invalid
+ * segment/BDF values return failure. Writes to valid functions
+ * without valid EPs are ignored, as is specified by PCI.
+ * The boilerplate in pci_svc.c tends to do basic segment, off
+ * and sz validation, so it shouldn't need to be repeated here.
+ *
+ * This function maps directly to the PCI_WRITE function in DEN0115
+ * where detailed requirements may be found.
+ *
+ * Return: SMC_PCI_CALL_SUCCESS
+ * SMC_PCI_CALL_INVAL_PARAM, on parameter error
+ */
+uint32_t pci_write_config(uint32_t addr, uint32_t off, uint32_t sz, uint32_t val)
+{
+ uint32_t ret = SMC_PCI_CALL_SUCCESS;
+ uint64_t base;
+
+ spin_lock(&pci_lock);
+ base = pci_segment_lib_get_base(addr, off);
+
+ if (base != INVALID_PCI_ADDR) {
+ switch (sz) {
+ case SMC_PCI_SZ_8BIT:
+ mmio_write_8(base, val);
+ break;
+ case SMC_PCI_SZ_16BIT:
+ mmio_write_16(base, val);
+ break;
+ case SMC_PCI_SZ_32BIT:
+ mmio_write_32(base, val);
+ break;
+ default: /* should be unreachable */
+ ret = SMC_PCI_CALL_INVAL_PARAM;
+ }
+ }
+ spin_unlock(&pci_lock);
+ return ret;
+}
+
+/**
+ * pci_get_bus_for_seg() - returns the start->end bus range for a segment
+ * @seg: segment being queried
+ * @bus_range: returned bus begin + (end << 8)
+ * @nseg: returns next segment in this machine or 0 for end
+ *
+ * pci_get_bus_for_seg is called to check if a given segment is
+ * valid on this machine. If it is valid, then its bus ranges are
+ * returned along with the next valid segment on the machine. If
+ * this is the last segment, then nseg must be 0.
+ *
+ * This function maps directly to the PCI_GET_SEG_INFO function
+ * in DEN0115 where detailed requirements may be found.
+ *
+ * Return: SMC_PCI_CALL_SUCCESS, and appropriate bus_range and nseg
+ * SMC_PCI_CALL_NOT_IMPL, if the segment is invalid
+ */
+uint32_t pci_get_bus_for_seg(uint32_t seg, uint32_t *bus_range, uint32_t *nseg)
+{
+ uint32_t ret = SMC_PCI_CALL_SUCCESS;
+ *nseg = 0U; /* only a single segment */
+ if (seg == 0U) {
+ *bus_range = 0xFF00; /* start 0, end 255 */
+ } else {
+ *bus_range = 0U;
+ ret = SMC_PCI_CALL_NOT_IMPL;
+ }
+ return ret;
+}
diff --git a/plat/socionext/synquacer/drivers/mhu/sq_mhu.c b/plat/socionext/synquacer/drivers/mhu/sq_mhu.c
new file mode 100644
index 0000000..925ed97
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/mhu/sq_mhu.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include <sq_common.h>
+#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();
+}
diff --git a/plat/socionext/synquacer/drivers/mhu/sq_mhu.h b/plat/socionext/synquacer/drivers/mhu/sq_mhu.h
new file mode 100644
index 0000000..f6b5cc3
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/mhu/sq_mhu.h
@@ -0,0 +1,19 @@
+/*
+ * 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 <stdint.h>
+
+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 */
diff --git a/plat/socionext/synquacer/drivers/scp/sq_scmi.c b/plat/socionext/synquacer/drivers/scp/sq_scmi.c
new file mode 100644
index 0000000..0e99256
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/scp/sq_scmi.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_mhu_doorbell.h>
+#include <drivers/arm/css/css_scp.h>
+#include <drivers/arm/css/scmi.h>
+#include <plat/arm/css/common/css_pm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include <scmi_sq.h>
+#include <sq_common.h>
+
+/*
+ * 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_shutdown(void)
+{
+ sq_scmi_system_off(SCMI_SYS_PWR_SHUTDOWN);
+}
+
+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;
+}
diff --git a/plat/socionext/synquacer/drivers/scp/sq_scp.c b/plat/socionext/synquacer/drivers/scp/sq_scp.c
new file mode 100644
index 0000000..e494022
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/scp/sq_scp.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <sq_common.h>
+#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;
+}
diff --git a/plat/socionext/synquacer/drivers/scpi/sq_scpi.c b/plat/socionext/synquacer/drivers/scpi/sq_scpi.c
new file mode 100644
index 0000000..0cb75a0
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/scpi/sq_scpi.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <sq_common.h>
+
+#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;
+}
diff --git a/plat/socionext/synquacer/drivers/scpi/sq_scpi.h b/plat/socionext/synquacer/drivers/scpi/sq_scpi.h
new file mode 100644
index 0000000..eb6ce5c
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/scpi/sq_scpi.h
@@ -0,0 +1,83 @@
+/*
+ * 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 <stddef.h>
+#include <stdint.h>
+
+/*
+ * 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 */
diff --git a/plat/socionext/synquacer/include/plat.ld.S b/plat/socionext/synquacer/include/plat.ld.S
new file mode 100644
index 0000000..af7a172
--- /dev/null
+++ b/plat/socionext/synquacer/include/plat.ld.S
@@ -0,0 +1,31 @@
+/*
+ * 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 <lib/xlat_tables/xlat_tables_defs.h>
+
+#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)
+ } >SP_DRAM
+}
+
+#endif /* SYNQUACER_PLAT_LD_S__ */
diff --git a/plat/socionext/synquacer/include/plat_macros.S b/plat/socionext/synquacer/include/plat_macros.S
new file mode 100644
index 0000000..932b21d
--- /dev/null
+++ b/plat/socionext/synquacer/include/plat_macros.S
@@ -0,0 +1,16 @@
+/*
+ * 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 */
diff --git a/plat/socionext/synquacer/include/platform_def.h b/plat/socionext/synquacer/include/platform_def.h
new file mode 100644
index 0000000..d6bfe42
--- /dev/null
+++ b/plat/socionext/synquacer/include/platform_def.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+/* CPU topology */
+#define PLAT_MAX_CORES_PER_CLUSTER U(2)
+#define PLAT_CLUSTER_COUNT U(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
+
+#if TRUSTED_BOARD_BOOT
+#define PLATFORM_STACK_SIZE 0x1000
+#else
+#define PLATFORM_STACK_SIZE 0x400
+#endif
+
+#if !RESET_TO_BL31
+
+/* A mailbox page will be mapped from BL2 and BL31 */
+#define BL2_MAILBOX_BASE 0x0403f000
+#define BL2_MAILBOX_SIZE 0x1000
+
+#define PLAT_SQ_BOOTIDX_BASE 0x08510000
+#define PLAT_SQ_MAX_BOOT_INDEX 2
+
+#define MAX_IO_HANDLES 2
+#define MAX_IO_DEVICES 2
+#define MAX_IO_BLOCK_DEVICES U(1)
+
+#define BL2_BASE 0x04000000
+#define BL2_SIZE (256 * 1024)
+#define BL2_LIMIT (BL2_BASE + BL2_SIZE)
+
+/* If BL2 is enabled, the BL31 is loaded on secure DRAM */
+#define BL31_BASE 0xfbe00000
+#define BL31_SIZE 0x00100000
+#else
+
+#define BL31_BASE 0x04000000
+#define BL31_SIZE 0x00080000
+#endif
+
+#define BL31_LIMIT (BL31_BASE + BL31_SIZE)
+
+#define BL32_BASE 0xfc000000
+#define BL32_SIZE 0x03c00000
+#define BL32_LIMIT (BL32_BASE + BL32_SIZE)
+
+/* Alternative BL33 */
+#define PLAT_SQ_BL33_BASE 0xe0000000
+#define PLAT_SQ_BL33_SIZE 0x00200000
+
+/* FWU FIP IO base */
+#define PLAT_SQ_FIP_IOBASE 0x08600000
+#define PLAT_SQ_FIP_MAXSIZE 0x00400000
+
+#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 SQ_SYS_CNT_BASE_NS 0x2a830000
+
+#define DRAMINFO_BASE 0x2E00FFC0
+
+#define PLAT_SQ_MHU_BASE 0x45000000
+
+#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_SP_IMAGE_BASE_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 */
diff --git a/plat/socionext/synquacer/include/sq_common.h b/plat/socionext/synquacer/include/sq_common.h
new file mode 100644
index 0000000..eef0e1f
--- /dev/null
+++ b/plat/socionext/synquacer/include/sq_common.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SQ_COMMON_H
+#define SQ_COMMON_H
+
+#include <stdint.h>
+
+#include <lib/psci/psci.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+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);
+
+int sq_io_setup(void);
+struct image_info *sq_get_image_info(unsigned int image_id);
+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_shutdown(void);
+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 */
diff --git a/plat/socionext/synquacer/platform.mk b/plat/socionext/synquacer/platform.mk
new file mode 100644
index 0000000..b76ae88
--- /dev/null
+++ b/plat/socionext/synquacer/platform.mk
@@ -0,0 +1,117 @@
+#
+# Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+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
+
+ifeq (${RESET_TO_BL31}, 1)
+override RESET_TO_BL31 := 1
+override TRUSTED_BOARD_BOOT := 0
+SQ_USE_SCMI_DRIVER ?= 0
+else
+override RESET_TO_BL31 := 0
+override BL2_AT_EL3 := 1
+SQ_USE_SCMI_DRIVER := 1
+BL2_CPPFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC
+endif
+
+# 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 \
+ lib/cpus/aarch64/cortex_a53.S \
+ $(PLAT_PATH)/sq_xlat_setup.c \
+ ${XLAT_TABLES_LIB_SRCS}
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+ifneq (${RESET_TO_BL31}, 1)
+BL2_SOURCES += common/desc_image_load.c \
+ drivers/io/io_fip.c \
+ drivers/io/io_memmap.c \
+ drivers/io/io_storage.c \
+ $(PLAT_PATH)/sq_bl2_setup.c \
+ $(PLAT_PATH)/sq_image_desc.c \
+ $(PLAT_PATH)/sq_io_storage.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_common.c \
+ drivers/auth/tbbr/tbbr_cot_bl2.c \
+ plat/common/tbbr/plat_tbbr.c \
+ $(PLAT_PATH)/sq_rotpk.S \
+ $(PLAT_PATH)/sq_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/sq_rotpk.o: $(ROTPK_HASH)
+
+certificates: $(ROT_KEY)
+$(ROT_KEY): | $(BUILD_PLAT)
+ @echo " OPENSSL $@"
+ $(Q)${OPENSSL_BIN_PATH}/openssl genrsa 2048 > $@ 2>/dev/null
+
+$(ROTPK_HASH): $(ROT_KEY)
+ @echo " OPENSSL $@"
+ $(Q)${OPENSSL_BIN_PATH}/openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+ ${OPENSSL_BIN_PATH}/openssl dgst -sha256 -binary > $@ 2>/dev/null
+
+endif # TRUSTED_BOARD_BOOT
+endif
+
+BL31_SOURCES += drivers/arm/ccn/ccn.c \
+ ${GICV3_SOURCES} \
+ 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)/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 (${SPM_MM},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
diff --git a/plat/socionext/synquacer/sq_bl2_setup.c b/plat/socionext/synquacer/sq_bl2_setup.c
new file mode 100644
index 0000000..a98d912
--- /dev/null
+++ b/plat/socionext/synquacer/sq_bl2_setup.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2022, Socionext Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <common/image_decompress.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/io/io_storage.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+#include <sq_common.h>
+
+static console_t console;
+
+void bl2_el3_early_platform_setup(u_register_t x0, u_register_t x1,
+ u_register_t x2, u_register_t x3)
+{
+ /* 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_FLAG_BOOT);
+}
+
+void bl2_el3_plat_arch_setup(void)
+{
+ int ret;
+
+ sq_mmap_setup(BL2_BASE, BL2_SIZE, NULL);
+
+ ret = sq_io_setup();
+ if (ret) {
+ ERROR("failed to setup io devices\n");
+ plat_error_handler(ret);
+ }
+}
+
+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)
+{
+}
+
+int bl2_plat_handle_pre_image_load(unsigned int image_id)
+{
+ struct image_info *image_info;
+
+ image_info = sq_get_image_info(image_id);
+
+ return mmap_add_dynamic_region(image_info->image_base,
+ image_info->image_base,
+ image_info->image_max_size,
+ MT_MEMORY | MT_RW | MT_NS);
+}
+
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+ return 0;
+}
diff --git a/plat/socionext/synquacer/sq_bl31_setup.c b/plat/socionext/synquacer/sq_bl31_setup.c
new file mode 100644
index 0000000..967437b
--- /dev/null
+++ b/plat/socionext/synquacer/sq_bl31_setup.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/pl011.h>
+#include <lib/mmio.h>
+#include <sq_common.h>
+
+static console_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);
+
+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;
+}
+
+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;
+}
+
+#if !RESET_TO_BL31
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3)
+{
+ void *from_bl2 = (void *) arg0;
+ bl_params_node_t *bl_params = ((bl_params_t *) from_bl2)->head;
+
+ /* 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_FLAG_BOOT | CONSOLE_FLAG_RUNTIME);
+
+ /* Initialize power controller before setting up topology */
+ plat_sq_pwrc_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;
+ }
+}
+
+#else
+/*******************************************************************************
+ * 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_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);
+}
+#endif
+
+static void sq_configure_sys_timer(void)
+{
+ unsigned int reg_val;
+ unsigned int freq_val = plat_get_syscnt_freq2();
+
+ 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);
+
+ /* Initialize CNTFRQ register in CNTCTLBase frame */
+ mmio_write_32(SQ_SYS_TIMCTL_BASE + CNTCTLBASE_CNTFRQ, freq_val);
+
+ /*
+ * Initialize CNTFRQ register in Non-secure CNTBase frame.
+ * This is required for SynQuacer, because it does 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(SQ_SYS_CNT_BASE_NS + CNTBASEN_CNTFRQ, freq_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 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
+#if !RESET_TO_BL31
+ MAP_REGION_FLAT(BL2_MAILBOX_BASE,
+ BL2_MAILBOX_SIZE,
+ MT_RW | MT_SECURE),
+#endif
+ {0},
+ };
+
+ sq_mmap_setup(BL31_BASE, BL31_SIZE, secure_partition_mmap);
+ enable_mmu_el3(XLAT_TABLE_NC);
+
+#if 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);
+}
diff --git a/plat/socionext/synquacer/sq_ccn.c b/plat/socionext/synquacer/sq_ccn.c
new file mode 100644
index 0000000..fa6ea87
--- /dev/null
+++ b/plat/socionext/synquacer/sq_ccn.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <drivers/arm/ccn.h>
+
+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()));
+}
diff --git a/plat/socionext/synquacer/sq_gicv3.c b/plat/socionext/synquacer/sq_gicv3.c
new file mode 100644
index 0000000..05318e3
--- /dev/null
+++ b/plat/socionext/synquacer/sq_gicv3.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <plat/common/platform.h>
+
+#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());
+}
diff --git a/plat/socionext/synquacer/sq_helpers.S b/plat/socionext/synquacer/sq_helpers.S
new file mode 100644
index 0000000..5f9eab4
--- /dev/null
+++ b/plat/socionext/synquacer/sq_helpers.S
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+
+ .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
+#if !RESET_TO_BL31
+ mov_imm x0, BL2_MAILBOX_BASE
+ ldr x0, [x0]
+#else
+ ldr x0, sq_sec_entrypoint
+#endif
+
+ /* 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
+
+/*
+ * void plat_crash_console_flush(int c)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * Out : void.
+ * 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
diff --git a/plat/socionext/synquacer/sq_image_desc.c b/plat/socionext/synquacer/sq_image_desc.c
new file mode 100644
index 0000000..5fe125b
--- /dev/null
+++ b/plat/socionext/synquacer/sq_image_desc.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2022, Socionext Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <common/desc_image_load.h>
+
+#include <platform_def.h>
+
+static struct bl_mem_params_node sq_image_descs[] = {
+ {
+ .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_SIZE,
+
+ 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),
+
+ .next_handoff_image_id = BL32_IMAGE_ID,
+ },
+ {
+ .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_SIZE,
+
+ 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,
+ },
+ {
+ .image_id = BL33_IMAGE_ID,
+
+ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+ VERSION_2, image_info_t, 0),
+ .image_info.image_base = PLAT_SQ_BL33_BASE,
+ .image_info.image_max_size = PLAT_SQ_BL33_SIZE,
+
+ SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+ VERSION_2, entry_point_info_t,
+ NON_SECURE | EXECUTABLE),
+ .ep_info.pc = PLAT_SQ_BL33_BASE,
+ .ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS),
+
+ .next_handoff_image_id = INVALID_IMAGE_ID,
+ },
+};
+REGISTER_BL_IMAGE_DESCS(sq_image_descs)
+
+struct image_info *sq_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;
+}
diff --git a/plat/socionext/synquacer/sq_io_storage.c b/plat/socionext/synquacer/sq_io_storage.c
new file mode 100644
index 0000000..ea83dad
--- /dev/null
+++ b/plat/socionext/synquacer/sq_io_storage.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2022, Socionext Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <tools_share/firmware_image_package.h>
+
+#include <platform_def.h>
+#include <sq_common.h>
+
+static const io_dev_connector_t *sq_fip_dev_con;
+static uintptr_t sq_fip_dev_handle;
+
+static const io_dev_connector_t *sq_backend_dev_con;
+static uintptr_t sq_backend_dev_handle;
+
+static io_block_spec_t sq_fip_spec = {
+ .offset = PLAT_SQ_FIP_IOBASE, /* FIP Image is at 5MB offset on memory-mapped NOR flash */
+ .length = PLAT_SQ_FIP_MAXSIZE, /* Expected maximum FIP image size */
+};
+
+static const io_uuid_spec_t sq_bl2_spec = {
+ .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+};
+
+static const io_uuid_spec_t sq_bl31_spec = {
+ .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+
+static const io_uuid_spec_t sq_bl32_spec = {
+ .uuid = UUID_SECURE_PAYLOAD_BL32,
+};
+
+static const io_uuid_spec_t sq_bl33_spec = {
+ .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+#if TRUSTED_BOARD_BOOT
+static const io_uuid_spec_t sq_tb_fw_cert_spec = {
+ .uuid = UUID_TRUSTED_BOOT_FW_CERT,
+};
+
+static const io_uuid_spec_t sq_trusted_key_cert_spec = {
+ .uuid = UUID_TRUSTED_KEY_CERT,
+};
+
+static const io_uuid_spec_t sq_soc_fw_key_cert_spec = {
+ .uuid = UUID_SOC_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t sq_tos_fw_key_cert_spec = {
+ .uuid = UUID_TRUSTED_OS_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t sq_nt_fw_key_cert_spec = {
+ .uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t sq_soc_fw_cert_spec = {
+ .uuid = UUID_SOC_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t sq_tos_fw_cert_spec = {
+ .uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t sq_nt_fw_cert_spec = {
+ .uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
+};
+#endif /* TRUSTED_BOARD_BOOT */
+
+struct sq_io_policy {
+ uintptr_t *dev_handle;
+ uintptr_t image_spec;
+ uintptr_t init_params;
+};
+
+static const struct sq_io_policy sq_io_policies[] = {
+ [FIP_IMAGE_ID] = {
+ .dev_handle = &sq_backend_dev_handle,
+ .image_spec = (uintptr_t)&sq_fip_spec,
+ },
+ [BL2_IMAGE_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_bl2_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [BL31_IMAGE_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_bl31_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [BL32_IMAGE_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_bl32_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [BL33_IMAGE_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_bl33_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+#if TRUSTED_BOARD_BOOT
+ [TRUSTED_BOOT_FW_CERT_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_tb_fw_cert_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [TRUSTED_KEY_CERT_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_trusted_key_cert_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [SOC_FW_KEY_CERT_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_soc_fw_key_cert_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [TRUSTED_OS_FW_KEY_CERT_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_tos_fw_key_cert_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [NON_TRUSTED_FW_KEY_CERT_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_nt_fw_key_cert_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [SOC_FW_CONTENT_CERT_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_soc_fw_cert_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [TRUSTED_OS_FW_CONTENT_CERT_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_tos_fw_cert_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [NON_TRUSTED_FW_CONTENT_CERT_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_nt_fw_cert_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+#endif
+};
+
+static int sq_update_fip_spec(void)
+{
+ uint32_t boot_index;
+ int ret;
+
+ ret = mmap_add_dynamic_region(PLAT_SQ_BOOTIDX_BASE, PLAT_SQ_BOOTIDX_BASE,
+ PAGE_SIZE, MT_RO_DATA | MT_SECURE);
+ if (ret) {
+ return ret;
+ }
+
+ boot_index = mmio_read_32(PLAT_SQ_BOOTIDX_BASE);
+ if (boot_index < PLAT_SQ_MAX_BOOT_INDEX) {
+ sq_fip_spec.offset += PLAT_SQ_FIP_MAXSIZE * boot_index;
+ INFO("FWU Enabled: boot_index %d\n", boot_index);
+ } else {
+ WARN("FWU Disabled: wrong boot_index value. Fallback to index 0.\n");
+ }
+
+ mmap_remove_dynamic_region(PLAT_SQ_BOOTIDX_BASE, PAGE_SIZE);
+ return 0;
+}
+
+static int sq_io_memmap_setup(void)
+{
+ int ret;
+
+ ret = sq_update_fip_spec();
+ if (ret) {
+ return ret;
+ }
+
+ ret = mmap_add_dynamic_region(sq_fip_spec.offset, sq_fip_spec.offset,
+ sq_fip_spec.length, MT_RO_DATA | MT_SECURE);
+ if (ret) {
+ return ret;
+ }
+
+ ret = register_io_dev_memmap(&sq_backend_dev_con);
+ if (ret) {
+ return ret;
+ }
+
+ return io_dev_open(sq_backend_dev_con, 0, &sq_backend_dev_handle);
+}
+
+static int sq_io_fip_setup(void)
+{
+ int ret;
+
+ ret = register_io_dev_fip(&sq_fip_dev_con);
+ if (ret) {
+ return ret;
+ }
+
+ return io_dev_open(sq_fip_dev_con, 0, &sq_fip_dev_handle);
+}
+
+int sq_io_setup(void)
+{
+ int ret;
+
+ ret = sq_io_memmap_setup();
+ if (ret) {
+ return ret;
+ }
+
+ ret = sq_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(sq_io_policies));
+
+ *dev_handle = *sq_io_policies[image_id].dev_handle;
+ *image_spec = sq_io_policies[image_id].image_spec;
+ init_params = sq_io_policies[image_id].init_params;
+
+ return io_dev_init(*dev_handle, init_params);
+}
diff --git a/plat/socionext/synquacer/sq_psci.c b/plat/socionext/synquacer/sq_psci.c
new file mode 100644
index 0000000..017516f
--- /dev/null
+++ b/plat/socionext/synquacer/sq_psci.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/cassert.h>
+#include <lib/psci/psci.h>
+
+#include <sq_common.h>
+#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
+ /* Prevent interrupts from spuriously waking up this cpu */
+ sq_gic_cpuif_disable();
+
+ /* 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();
+ }
+
+ sq_scmi_off(target_state);
+#else
+ sq_power_down_common(target_state);
+#endif
+}
+
+void __dead2 sq_system_off(void)
+{
+#if SQ_USE_SCMI_DRIVER
+ sq_scmi_sys_shutdown();
+#else
+ 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();
+#endif
+}
+
+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)
+{
+ u_register_t 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)
+{
+#if !RESET_TO_BL31
+ uintptr_t *sq_sec_ep = (uintptr_t *)BL2_MAILBOX_BASE;
+
+ *sq_sec_ep = sec_entrypoint;
+ flush_dcache_range((uint64_t)sq_sec_ep,
+ sizeof(*sq_sec_ep));
+#else
+ sq_sec_entrypoint = sec_entrypoint;
+ flush_dcache_range((uint64_t)&sq_sec_entrypoint,
+ sizeof(sq_sec_entrypoint));
+#endif
+
+ *psci_ops = &sq_psci_ops;
+
+ return 0;
+}
diff --git a/plat/socionext/synquacer/sq_rotpk.S b/plat/socionext/synquacer/sq_rotpk.S
new file mode 100644
index 0000000..61227ed
--- /dev/null
+++ b/plat/socionext/synquacer/sq_rotpk.S
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2022, Socionext Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+ .global sq_rotpk_hash
+ .global sq_rotpk_hash_end
+ .section .rodata.sq_rotpk_hash, "a"
+sq_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
+sq_rotpk_hash_end:
diff --git a/plat/socionext/synquacer/sq_spm.c b/plat/socionext/synquacer/sq_spm.c
new file mode 100644
index 0000000..7bea111
--- /dev/null
+++ b/plat/socionext/synquacer/sq_spm.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <bl31/ehf.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <services/spm_mm_partition.h>
+
+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 spm_mm_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 spm_mm_boot_info_t plat_arm_secure_partition_boot_info = {
+ .h.type = PARAM_SP_IMAGE_BOOT_INFO,
+ .h.version = VERSION_1,
+ .h.size = sizeof(spm_mm_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 spm_mm_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);
diff --git a/plat/socionext/synquacer/sq_tbbr.c b/plat/socionext/synquacer/sq_tbbr.c
new file mode 100644
index 0000000..e9fa18c
--- /dev/null
+++ b/plat/socionext/synquacer/sq_tbbr.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022, Socionext Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+extern char sq_rotpk_hash[], sq_rotpk_hash_end[];
+
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+ unsigned int *flags)
+{
+ *key_ptr = sq_rotpk_hash;
+ *key_len = sq_rotpk_hash_end - sq_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);
+}
diff --git a/plat/socionext/synquacer/sq_topology.c b/plat/socionext/synquacer/sq_topology.c
new file mode 100644
index 0000000..359997a
--- /dev/null
+++ b/plat/socionext/synquacer/sq_topology.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+
+#include <sq_common.h>
+
+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;
+}
diff --git a/plat/socionext/synquacer/sq_xlat_setup.c b/plat/socionext/synquacer/sq_xlat_setup.c
new file mode 100644
index 0000000..5d1669d
--- /dev/null
+++ b/plat/socionext/synquacer/sq_xlat_setup.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#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();
+}
diff --git a/plat/socionext/uniphier/include/plat_macros.S b/plat/socionext/uniphier/include/plat_macros.S
new file mode 100644
index 0000000..d6d2579
--- /dev/null
+++ b/plat/socionext/uniphier/include/plat_macros.S
@@ -0,0 +1,13 @@
+/*
+ * 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 */
diff --git a/plat/socionext/uniphier/include/platform_def.h b/plat/socionext/uniphier/include/platform_def.h
new file mode 100644
index 0000000..b23386d
--- /dev/null
+++ b/plat/socionext/uniphier/include/platform_def.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#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 U(4)
+#define UNIPHIER_CLUSTER_COUNT U(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 UNIPHIER_BL2_OFFSET UL(0x00000000)
+#define UNIPHIER_BL2_MAX_SIZE UL(0x00080000)
+
+/* 0x00080000-0x01000000: reserved for DSP */
+
+#define UNIPHIER_BL31_OFFSET UL(0x01000000)
+#define UNIPHIER_BL31_MAX_SIZE UL(0x00080000)
+
+#define UNIPHIER_BL32_OFFSET UL(0x01080000)
+#define UNIPHIER_BL32_MAX_SIZE UL(0x00100000)
+
+/*
+ * The link addresses are determined by UNIPHIER_MEM_BASE + offset.
+ * When ENABLE_PIE is set, all the TF images can be loaded anywhere, so
+ * UNIPHIER_MEM_BASE is arbitrary.
+ *
+ * When ENABLE_PIE is unset, UNIPHIER_MEM_BASE should be chosen so that
+ * BL2_BASE matches to the physical address where BL2 is loaded, that is,
+ * UNIPHIER_MEM_BASE should be the base address of the DRAM region.
+ */
+#define UNIPHIER_MEM_BASE UL(0x00000000)
+
+#define BL2_BASE (UNIPHIER_MEM_BASE + UNIPHIER_BL2_OFFSET)
+#define BL2_LIMIT (BL2_BASE + UNIPHIER_BL2_MAX_SIZE)
+
+#define BL31_BASE (UNIPHIER_MEM_BASE + UNIPHIER_BL31_OFFSET)
+#define BL31_LIMIT (BL31_BASE + UNIPHIER_BL31_MAX_SIZE)
+
+#define BL32_BASE (UNIPHIER_MEM_BASE + UNIPHIER_BL32_OFFSET)
+#define BL32_LIMIT (BL32_BASE + UNIPHIER_BL32_MAX_SIZE)
+
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
+
+#define MAX_XLAT_TABLES 9
+#define MAX_MMAP_REGIONS 13
+
+#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 */
diff --git a/plat/socionext/uniphier/platform.mk b/plat/socionext/uniphier/platform.mk
new file mode 100644
index 0000000..378497a
--- /dev/null
+++ b/plat/socionext/uniphier/platform.mk
@@ -0,0 +1,140 @@
+#
+# Copyright (c) 2017-2020, 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
+
+# Disabling ENABLE_PIE saves memory footprint a lot, but you need to adjust
+# UNIPHIER_MEM_BASE so that all TF images are loaded at their link addresses.
+override ENABLE_PIE := 1
+
+ALLOW_RO_XLAT_TABLES := 1
+
+ifeq ($(ALLOW_RO_XLAT_TABLES),1)
+BL31_CPPFLAGS += -DPLAT_RO_XLAT_TABLES
+BL32_CPPFLAGS += -DPLAT_RO_XLAT_TABLES
+endif
+
+# The dynamic xlat table is only used in BL2
+BL2_CPPFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC
+
+# 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
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+BL31_SOURCES += drivers/arm/cci/cci.c \
+ ${GICV3_SOURCES} \
+ 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_boot_device.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_common.c \
+ drivers/auth/tbbr/tbbr_cot_bl2.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_BIN_PATH}/openssl genrsa 2048 > $@ 2>/dev/null
+
+$(ROTPK_HASH): $(ROT_KEY)
+ @echo " OPENSSL $@"
+ $(Q)${OPENSSL_BIN_PATH}/openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+ ${OPENSSL_BIN_PATH}/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 > $@
diff --git a/plat/socionext/uniphier/tsp/tsp-uniphier.mk b/plat/socionext/uniphier/tsp/tsp-uniphier.mk
new file mode 100644
index 0000000..54d4f51
--- /dev/null
+++ b/plat/socionext/uniphier/tsp/tsp-uniphier.mk
@@ -0,0 +1,9 @@
+#
+# 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
diff --git a/plat/socionext/uniphier/tsp/uniphier_tsp_setup.c b/plat/socionext/uniphier/tsp/uniphier_tsp_setup.c
new file mode 100644
index 0000000..4bbb259
--- /dev/null
+++ b/plat/socionext/uniphier/tsp/uniphier_tsp_setup.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <plat/common/platform.h>
+
+#include "../uniphier.h"
+
+static unsigned int uniphier_soc = UNIPHIER_SOC_UNKNOWN;
+
+void tsp_early_platform_setup(void)
+{
+ uniphier_soc = uniphier_get_soc_id();
+ if (uniphier_soc == UNIPHIER_SOC_UNKNOWN)
+ plat_error_handler(-ENOTSUP);
+
+ uniphier_console_setup(uniphier_soc);
+}
+
+void tsp_platform_setup(void)
+{
+}
+
+void tsp_plat_arch_setup(void)
+{
+ uniphier_mmap_setup(uniphier_soc);
+}
diff --git a/plat/socionext/uniphier/uniphier.h b/plat/socionext/uniphier/uniphier.h
new file mode 100644
index 0000000..ee520ad
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef UNIPHIER_H
+#define UNIPHIER_H
+
+#include <stdint.h>
+#include <string.h>
+
+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_SD 3
+#define UNIPHIER_BOOT_DEVICE_USB 4
+#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(unsigned int soc);
+
+struct io_block_dev_spec;
+int uniphier_emmc_init(unsigned int soc,
+ struct io_block_dev_spec **block_dev_spec);
+int uniphier_nand_init(unsigned int soc,
+ struct io_block_dev_spec **block_dev_spec);
+int uniphier_usb_init(unsigned int soc,
+ struct io_block_dev_spec **block_dev_spec);
+
+int uniphier_io_setup(unsigned int soc, uintptr_t mem_base);
+
+void uniphier_init_image_descs(uintptr_t mem_base);
+struct image_info;
+struct image_info *uniphier_get_image_info(unsigned int image_id);
+
+int uniphier_scp_is_running(void);
+void uniphier_scp_start(uint32_t scp_base);
+void uniphier_scp_open_com(void);
+void uniphier_scp_system_off(void);
+void uniphier_scp_system_reset(void);
+
+void uniphier_mmap_setup(unsigned int soc);
+
+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);
+
+void uniphier_psci_init(unsigned int soc);
+
+unsigned int uniphier_calc_core_pos(u_register_t mpidr);
+
+#endif /* UNIPHIER_H */
diff --git a/plat/socionext/uniphier/uniphier_bl2_setup.c b/plat/socionext/uniphier/uniphier_bl2_setup.c
new file mode 100644
index 0000000..4524610
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_bl2_setup.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <common/image_decompress.h>
+#include <drivers/io/io_storage.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#ifdef UNIPHIER_DECOMPRESS_GZIP
+#include <tf_gunzip.h>
+#endif
+
+#include "uniphier.h"
+
+#define UNIPHIER_IMAGE_BUF_OFFSET 0x03800000UL
+#define UNIPHIER_IMAGE_BUF_SIZE 0x00800000UL
+
+static uintptr_t uniphier_mem_base = UNIPHIER_MEM_BASE;
+static unsigned int uniphier_soc = UNIPHIER_SOC_UNKNOWN;
+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_soc = uniphier_get_soc_id();
+ if (uniphier_soc == UNIPHIER_SOC_UNKNOWN)
+ plat_error_handler(-ENOTSUP);
+
+ uniphier_console_setup(uniphier_soc);
+}
+
+void bl2_el3_plat_arch_setup(void)
+{
+ int skip_scp = 0;
+ int ret;
+
+ uniphier_mmap_setup(uniphier_soc);
+
+ /* add relocation offset (run-time-address - link-address) */
+ uniphier_mem_base += BL_CODE_BASE - BL2_BASE;
+
+ ret = uniphier_io_setup(uniphier_soc, uniphier_mem_base);
+ if (ret) {
+ ERROR("failed to setup io devices\n");
+ plat_error_handler(ret);
+ }
+
+ switch (uniphier_get_boot_master(uniphier_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
+ uintptr_t buf_base = uniphier_mem_base + UNIPHIER_IMAGE_BUF_OFFSET;
+ int ret;
+
+ ret = mmap_add_dynamic_region(buf_base, buf_base,
+ UNIPHIER_IMAGE_BUF_SIZE,
+ MT_MEMORY | MT_RW | MT_NS);
+ if (ret)
+ plat_error_handler(ret);
+
+ image_decompress_init(buf_base, UNIPHIER_IMAGE_BUF_SIZE, gunzip);
+#endif
+
+ uniphier_init_image_descs(uniphier_mem_base);
+}
+
+int bl2_plat_handle_pre_image_load(unsigned int image_id)
+{
+ struct image_info *image_info;
+ int ret;
+
+ image_info = uniphier_get_image_info(image_id);
+
+ ret = mmap_add_dynamic_region(image_info->image_base,
+ image_info->image_base,
+ image_info->image_max_size,
+ MT_MEMORY | MT_RW | MT_NS);
+ if (ret)
+ return ret;
+
+#ifdef UNIPHIER_DECOMPRESS_GZIP
+ image_decompress_prepare(image_info);
+#endif
+ return 0;
+}
+
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+ struct image_info *image_info = uniphier_get_image_info(image_id);
+#ifdef UNIPHIER_DECOMPRESS_GZIP
+ int ret;
+
+ 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(image_info->image_base);
+
+ return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_bl31_setup.c b/plat/socionext/uniphier/uniphier_bl31_setup.c
new file mode 100644
index 0000000..c2baebd
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_bl31_setup.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include "uniphier.h"
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+static unsigned int uniphier_soc = UNIPHIER_SOC_UNKNOWN;
+
+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_soc = uniphier_get_soc_id();
+ if (uniphier_soc == UNIPHIER_SOC_UNKNOWN)
+ plat_error_handler(-ENOTSUP);
+
+ uniphier_console_setup(uniphier_soc);
+
+ 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();
+}
+
+static const uintptr_t uniphier_cntctl_base[] = {
+ [UNIPHIER_SOC_LD11] = 0x60e00000,
+ [UNIPHIER_SOC_LD20] = 0x60e00000,
+ [UNIPHIER_SOC_PXS3] = 0x60e00000,
+};
+
+void bl31_platform_setup(void)
+{
+ uintptr_t cntctl_base;
+
+ uniphier_cci_init(uniphier_soc);
+ uniphier_cci_enable();
+
+ /* Initialize the GIC driver, cpu and distributor interfaces */
+ uniphier_gic_driver_init(uniphier_soc);
+ uniphier_gic_init();
+
+ assert(uniphier_soc < ARRAY_SIZE(uniphier_cntctl_base));
+ cntctl_base = uniphier_cntctl_base[uniphier_soc];
+
+ /* Enable and initialize the System level generic timer */
+ mmio_write_32(cntctl_base + CNTCR_OFF, CNTCR_FCREQ(0U) | CNTCR_EN);
+
+ uniphier_psci_init(uniphier_soc);
+}
+
+void bl31_plat_arch_setup(void)
+{
+ uniphier_mmap_setup(uniphier_soc);
+}
diff --git a/plat/socionext/uniphier/uniphier_boot_device.c b/plat/socionext/uniphier/uniphier_boot_device.c
new file mode 100644
index 0000000..36a9908
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_boot_device.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_PINMON0 0x0
+#define UNIPHIER_PINMON2 0x8
+
+static const uintptr_t uniphier_pinmon_base[] = {
+ [UNIPHIER_SOC_LD11] = 0x5f900100,
+ [UNIPHIER_SOC_LD20] = 0x5f900100,
+ [UNIPHIER_SOC_PXS3] = 0x5f900100,
+};
+
+static bool uniphier_ld11_is_usb_boot(uint32_t pinmon)
+{
+ return !!(~pinmon & 0x00000080);
+}
+
+static bool uniphier_ld20_is_usb_boot(uint32_t pinmon)
+{
+ return !!(~pinmon & 0x00000780);
+}
+
+static bool uniphier_pxs3_is_usb_boot(uint32_t pinmon)
+{
+ uintptr_t pinmon_base = uniphier_pinmon_base[UNIPHIER_SOC_PXS3];
+ uint32_t pinmon2 = mmio_read_32(pinmon_base + 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 {
+ bool have_boot_swap;
+ bool (*is_sd_boot)(uint32_t pinmon);
+ bool (*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] = {
+ .have_boot_swap = true,
+ .is_usb_boot = uniphier_ld11_is_usb_boot,
+ .get_boot_device = uniphier_ld11_get_boot_device,
+ },
+ [UNIPHIER_SOC_LD20] = {
+ .have_boot_swap = true,
+ .is_usb_boot = uniphier_ld20_is_usb_boot,
+ .get_boot_device = uniphier_ld11_get_boot_device,
+ },
+ [UNIPHIER_SOC_PXS3] = {
+ .have_boot_swap = true,
+ .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;
+ uintptr_t pinmon_base;
+ uint32_t pinmon;
+
+ assert(soc < ARRAY_SIZE(uniphier_boot_device_info));
+ info = &uniphier_boot_device_info[soc];
+
+ assert(soc < ARRAY_SIZE(uniphier_boot_device_info));
+ pinmon_base = uniphier_pinmon_base[soc];
+
+ pinmon = mmio_read_32(pinmon_base + UNIPHIER_PINMON0);
+
+ if (info->have_boot_swap && !(pinmon & BIT(29)))
+ return UNIPHIER_BOOT_DEVICE_NOR;
+
+ if (info->is_sd_boot && info->is_sd_boot(pinmon))
+ return UNIPHIER_BOOT_DEVICE_SD;
+
+ if (info->is_usb_boot && 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]) {
+ uintptr_t pinmon_base;
+
+ assert(soc < ARRAY_SIZE(uniphier_boot_device_info));
+ pinmon_base = uniphier_pinmon_base[soc];
+
+ if (mmio_read_32(pinmon_base + UNIPHIER_PINMON0) & BIT(27))
+ return UNIPHIER_BOOT_MASTER_THIS;
+ else
+ return UNIPHIER_BOOT_MASTER_SCP;
+ } else {
+ return UNIPHIER_BOOT_MASTER_EXT;
+ }
+}
diff --git a/plat/socionext/uniphier/uniphier_cci.c b/plat/socionext/uniphier/uniphier_cci.c
new file mode 100644
index 0000000..3ca1768
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_cci.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <arch_helpers.h>
+#include <drivers/arm/cci.h>
+#include <lib/utils_def.h>
+
+#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();
+}
diff --git a/plat/socionext/uniphier/uniphier_console.S b/plat/socionext/uniphier/uniphier_console.S
new file mode 100644
index 0000000..48927f4
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_console.S
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <drivers/console.h>
+
+#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_BASE]
+
+ /* 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_BASE]
+
+ 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_BASE]
+
+ /* wait until the transmitter gets empty */
+0: ldr w1, [x0, #UNIPHIER_UART_LSR]
+ tbz w1, #UNIPHIER_UART_LSR_TEMT_BIT, 0b
+
+ ret
+endfunc uniphier_console_flush
diff --git a/plat/socionext/uniphier/uniphier_console.h b/plat/socionext/uniphier/uniphier_console.h
new file mode 100644
index 0000000..e35fc88
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_console.h
@@ -0,0 +1,25 @@
+/*
+ * 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 */
diff --git a/plat/socionext/uniphier/uniphier_console_setup.c b/plat/socionext/uniphier/uniphier_console_setup.c
new file mode 100644
index 0000000..9fda26e
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_console_setup.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2019-2020, Socionext Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <drivers/console.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include "uniphier.h"
+#include "uniphier_console.h"
+
+#define UNIPHIER_UART_OFFSET 0x100
+#define UNIPHIER_UART_NR_PORTS 4
+
+/* 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);
+void uniphier_console_flush(struct console *console);
+
+static console_t uniphier_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,
+};
+
+static const uintptr_t uniphier_uart_base[] = {
+ [UNIPHIER_SOC_LD11] = 0x54006800,
+ [UNIPHIER_SOC_LD20] = 0x54006800,
+ [UNIPHIER_SOC_PXS3] = 0x54006800,
+};
+
+/*
+ * 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(unsigned int soc)
+{
+ uintptr_t base, end;
+ uint32_t div;
+
+ assert(soc < ARRAY_SIZE(uniphier_uart_base));
+ base = uniphier_uart_base[soc];
+ end = base + UNIPHIER_UART_OFFSET * UNIPHIER_UART_NR_PORTS;
+
+ while (base < 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(unsigned int soc)
+{
+ uintptr_t base;
+
+ base = uniphier_console_get_base(soc);
+ if (!base)
+ plat_error_handler(-EINVAL);
+
+ uniphier_console.base = base;
+ console_register(&uniphier_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);
+}
diff --git a/plat/socionext/uniphier/uniphier_emmc.c b/plat/socionext/uniphier/uniphier_emmc.c
new file mode 100644
index 0000000..b3d23cb
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_emmc.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <drivers/io/io_block.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#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;
+};
+
+struct uniphier_emmc_host {
+ uintptr_t base;
+ bool is_block_addressing;
+};
+
+static struct uniphier_emmc_host uniphier_emmc_host;
+
+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_check_device_size(uintptr_t host_base,
+ bool *is_block_addressing)
+{
+ 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);
+
+ /* C_SIZE == 0xfff && C_SIZE_MULT == 0x7 ? */
+ *is_block_addressing = !(~csd40 & 0xffc00380) && !(~csd72 & 0x3);
+
+ return 0;
+}
+
+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)
+{
+ int ret;
+
+ inv_dcache_range(buf, size);
+
+ if (!uniphier_emmc_host.is_block_addressing)
+ lba *= 512;
+
+ ret = uniphier_emmc_load_image(uniphier_emmc_host.base,
+ lba, buf, size / 512);
+
+ inv_dcache_range(buf, size);
+
+ return ret ? 0 : size;
+}
+
+static struct io_block_dev_spec uniphier_emmc_dev_spec = {
+ .ops = {
+ .read = uniphier_emmc_read,
+ },
+ .block_size = 512,
+};
+
+static int uniphier_emmc_hw_init(struct uniphier_emmc_host *host)
+{
+ struct uniphier_mmc_cmd cmd = {0};
+ uintptr_t host_base = uniphier_emmc_host.base;
+ 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_check_device_size(host_base,
+ &uniphier_emmc_host.is_block_addressing);
+ if (ret)
+ return 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;
+}
+
+static const uintptr_t uniphier_emmc_base[] = {
+ [UNIPHIER_SOC_LD11] = 0x5a000200,
+ [UNIPHIER_SOC_LD20] = 0x5a000200,
+ [UNIPHIER_SOC_PXS3] = 0x5a000200,
+};
+
+int uniphier_emmc_init(unsigned int soc,
+ struct io_block_dev_spec **block_dev_spec)
+{
+ int ret;
+
+ assert(soc < ARRAY_SIZE(uniphier_emmc_base));
+ uniphier_emmc_host.base = uniphier_emmc_base[soc];
+ if (uniphier_emmc_host.base == 0UL)
+ return -ENOTSUP;
+
+ ret = uniphier_emmc_hw_init(&uniphier_emmc_host);
+ if (ret)
+ return ret;
+
+ *block_dev_spec = &uniphier_emmc_dev_spec;
+
+ return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_gicv3.c b/plat/socionext/uniphier/uniphier_gicv3.c
new file mode 100644
index 0000000..266efe7
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_gicv3.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <drivers/arm/gicv3.h>
+#include <common/interrupt_props.h>
+#include <plat/common/platform.h>
+
+#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());
+}
diff --git a/plat/socionext/uniphier/uniphier_helpers.S b/plat/socionext/uniphier/uniphier_helpers.S
new file mode 100644
index 0000000..105cf9e
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_helpers.S
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/socionext/uniphier/uniphier_image_desc.c b/plat/socionext/uniphier/uniphier_image_desc.c
new file mode 100644
index 0000000..dd62d1e
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_image_desc.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <common/desc_image_load.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_BL33_OFFSET 0x04000000UL
+#define UNIPHIER_BL33_MAX_SIZE 0x00800000UL
+
+#define UNIPHIER_SCP_OFFSET 0x04800000UL
+#define UNIPHIER_SCP_MAX_SIZE 0x00020000UL
+
+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_OFFSET,
+ .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 = UNIPHIER_BL31_OFFSET,
+ .image_info.image_max_size = UNIPHIER_BL31_MAX_SIZE,
+
+ SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+ VERSION_2, entry_point_info_t,
+ SECURE | EXECUTABLE | EP_FIRST_EXE),
+ .ep_info.pc = UNIPHIER_BL31_OFFSET,
+ .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 = UNIPHIER_BL32_OFFSET,
+ .image_info.image_max_size = UNIPHIER_BL32_MAX_SIZE,
+
+ SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+ VERSION_2, entry_point_info_t,
+ SECURE | EXECUTABLE),
+ .ep_info.pc = UNIPHIER_BL32_OFFSET,
+ .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_OFFSET,
+ .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_OFFSET,
+ .ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS),
+
+ .next_handoff_image_id = INVALID_IMAGE_ID,
+ },
+};
+REGISTER_BL_IMAGE_DESCS(uniphier_image_descs)
+
+/*
+ * image_info.image_base and ep_info.pc are the offset from the memory base.
+ * When ENABLE_PIE is set, we never know the real memory base at link-time.
+ * Fix-up the addresses by adding the run-time detected base.
+ */
+void uniphier_init_image_descs(uintptr_t mem_base)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(uniphier_image_descs); i++) {
+ uniphier_image_descs[i].image_info.image_base += mem_base;
+ uniphier_image_descs[i].ep_info.pc += mem_base;
+ }
+}
+
+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;
+}
diff --git a/plat/socionext/uniphier/uniphier_io_storage.c b/plat/socionext/uniphier/uniphier_io_storage.c
new file mode 100644
index 0000000..92e15b0
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_io_storage.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <tools_share/firmware_image_package.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_ROM_REGION_BASE 0x00000000ULL
+#define UNIPHIER_ROM_REGION_SIZE 0x04000000ULL
+
+#define UNIPHIER_OCM_REGION_SIZE 0x00040000ULL
+
+#define UNIPHIER_BLOCK_BUF_OFFSET 0x03000000UL
+#define UNIPHIER_BLOCK_BUF_SIZE 0x00800000UL
+
+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,
+ struct io_block_dev_spec *block_dev_spec,
+ size_t buffer_offset)
+{
+ int ret;
+
+ uniphier_fip_spec.offset = fip_offset;
+
+ block_dev_spec->buffer.offset = buffer_offset;
+ block_dev_spec->buffer.length = UNIPHIER_BLOCK_BUF_SIZE;
+
+ ret = mmap_add_dynamic_region(block_dev_spec->buffer.offset,
+ block_dev_spec->buffer.offset,
+ block_dev_spec->buffer.length,
+ MT_MEMORY | MT_RW | MT_NS);
+ if (ret)
+ return ret;
+
+ ret = register_io_dev_block(&uniphier_backend_dev_con);
+ if (ret)
+ return ret;
+
+ return io_dev_open(uniphier_backend_dev_con, (uintptr_t)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, size_t buffer_offset)
+{
+ struct io_block_dev_spec *block_dev_spec;
+ int ret;
+
+ ret = uniphier_emmc_init(soc, &block_dev_spec);
+ if (ret)
+ return ret;
+
+ return uniphier_io_block_setup(0x20000, block_dev_spec, buffer_offset);
+}
+
+static int uniphier_io_nand_setup(unsigned int soc, size_t buffer_offset)
+{
+ struct io_block_dev_spec *block_dev_spec;
+ int ret;
+
+ ret = uniphier_nand_init(soc, &block_dev_spec);
+ if (ret)
+ return ret;
+
+ return uniphier_io_block_setup(0x20000, block_dev_spec, buffer_offset);
+}
+
+static int uniphier_io_nor_setup(unsigned int soc_id, size_t buffer_offset)
+{
+ return uniphier_io_memmap_setup(0x70000);
+}
+
+static const uintptr_t uniphier_ocm_base[] = {
+ [UNIPHIER_SOC_LD11] = 0x30000000,
+ [UNIPHIER_SOC_LD20] = 0x30000000,
+ [UNIPHIER_SOC_PXS3] = 0x30000000,
+};
+
+static int uniphier_io_rom_api_setup(unsigned int soc)
+{
+ uintptr_t ocm_base;
+ int ret;
+
+ assert(soc < ARRAY_SIZE(uniphier_ocm_base));
+ ocm_base = uniphier_ocm_base[soc];
+
+ 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(ocm_base, ocm_base,
+ UNIPHIER_OCM_REGION_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int uniphier_io_usb_setup(unsigned int soc, size_t buffer_offset)
+{
+ struct io_block_dev_spec *block_dev_spec;
+ int ret;
+
+ /* use ROM API for loading images from USB storage */
+ ret = uniphier_io_rom_api_setup(soc);
+ if (ret)
+ return ret;
+
+ ret = uniphier_usb_init(soc, &block_dev_spec);
+ if (ret)
+ return ret;
+
+ return uniphier_io_block_setup(0x20000, block_dev_spec, buffer_offset);
+}
+
+static int (* const uniphier_io_setup_table[])(unsigned int, size_t) = {
+ [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, uintptr_t mem_base)
+{
+ int (*io_setup)(unsigned int soc_id, size_t buffer_offset);
+ 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, mem_base + UNIPHIER_BLOCK_BUF_OFFSET);
+ 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);
+}
diff --git a/plat/socionext/uniphier/uniphier_nand.c b/plat/socionext/uniphier/uniphier_nand.c
new file mode 100644
index 0000000..71cb96c
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_nand.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/io/io_block.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#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 = {
+ .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->reg_base = nand->host_base + 0x100000;
+
+ 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;
+}
+
+static const uintptr_t uniphier_nand_base[] = {
+ [UNIPHIER_SOC_LD11] = 0x68000000,
+ [UNIPHIER_SOC_LD20] = 0x68000000,
+ [UNIPHIER_SOC_PXS3] = 0x68000000,
+};
+
+int uniphier_nand_init(unsigned int soc,
+ struct io_block_dev_spec **block_dev_spec)
+{
+ int ret;
+
+ assert(soc < ARRAY_SIZE(uniphier_nand_base));
+ uniphier_nand.host_base = uniphier_nand_base[soc];
+ if (!uniphier_nand.host_base)
+ return -ENOTSUP;
+
+ ret = uniphier_nand_hw_init(&uniphier_nand);
+ if (ret)
+ return ret;
+
+ uniphier_nand_dev_spec.block_size = uniphier_nand.page_size;
+
+ *block_dev_spec = &uniphier_nand_dev_spec;
+
+ return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_psci.c b/plat/socionext/uniphier/uniphier_psci.c
new file mode 100644
index 0000000..a371705
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_psci.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_ROM_RSV0 0x0
+
+#define UNIPHIER_SLFRSTSEL 0x10
+#define UNIPHIER_SLFRSTSEL_MASK GENMASK(1, 0)
+#define UNIPHIER_SLFRSTCTL 0x14
+#define UNIPHIER_SLFRSTCTL_RST BIT(0)
+
+#define MPIDR_AFFINITY_INVALID ((u_register_t)-1)
+
+static uintptr_t uniphier_rom_rsv_base;
+static uintptr_t uniphier_slfrst_base;
+
+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_rsv_base + 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_slfrst_base + UNIPHIER_SLFRSTSEL,
+ UNIPHIER_SLFRSTSEL_MASK);
+ mmio_setbits_32(uniphier_slfrst_base + 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));
+
+ *psci_ops = &uniphier_psci_ops;
+
+ return 0;
+}
+
+struct uniphier_psci_ctrl_base {
+ uintptr_t rom_rsv_base;
+ uintptr_t slfrst_base;
+};
+
+static const struct uniphier_psci_ctrl_base uniphier_psci_ctrl_base[] = {
+ [UNIPHIER_SOC_LD11] = {
+ .rom_rsv_base = 0x59801200,
+ .slfrst_base = 0x61843000,
+ },
+ [UNIPHIER_SOC_LD20] = {
+ .rom_rsv_base = 0x59801200,
+ .slfrst_base = 0x61843000,
+ },
+ [UNIPHIER_SOC_PXS3] = {
+ .rom_rsv_base = 0x59801200,
+ .slfrst_base = 0x61843000,
+ },
+};
+
+void uniphier_psci_init(unsigned int soc)
+{
+ assert(soc < ARRAY_SIZE(uniphier_psci_ctrl_base));
+ uniphier_rom_rsv_base = uniphier_psci_ctrl_base[soc].rom_rsv_base;
+ uniphier_slfrst_base = uniphier_psci_ctrl_base[soc].slfrst_base;
+
+ if (uniphier_get_boot_master(soc) == UNIPHIER_BOOT_MASTER_SCP) {
+ 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();
+ }
+}
diff --git a/plat/socionext/uniphier/uniphier_rotpk.S b/plat/socionext/uniphier/uniphier_rotpk.S
new file mode 100644
index 0000000..21c44b6
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_rotpk.S
@@ -0,0 +1,16 @@
+/*
+ * 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:
diff --git a/plat/socionext/uniphier/uniphier_scp.c b/plat/socionext/uniphier/uniphier_scp.c
new file mode 100644
index 0000000..8a12d5d
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_scp.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#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(uint32_t scp_base)
+{
+ uint32_t tmp;
+
+ mmio_write_32(UNIPHIER_STMBE2COM + 4, 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)
diff --git a/plat/socionext/uniphier/uniphier_smp.S b/plat/socionext/uniphier/uniphier_smp.S
new file mode 100644
index 0000000..d6cb9ff
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_smp.S
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+ .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
diff --git a/plat/socionext/uniphier/uniphier_soc_info.c b/plat/socionext/uniphier/uniphier_soc_info.c
new file mode 100644
index 0000000..0e7a2d1
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_soc_info.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <lib/mmio.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_REVISION 0x5f800000UL
+#define UNIPHIER_REVISION_NEW 0x1f800000UL
+
+static unsigned int uniphier_get_revision_field(unsigned int mask,
+ unsigned int shift)
+{
+ uintptr_t reg;
+
+ if (BL_CODE_BASE >= 0x80000000UL)
+ reg = UNIPHIER_REVISION;
+ else
+ reg = UNIPHIER_REVISION_NEW;
+
+ return (mmio_read_32(reg) >> 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;
+ }
+}
diff --git a/plat/socionext/uniphier/uniphier_syscnt.c b/plat/socionext/uniphier/uniphier_syscnt.c
new file mode 100644
index 0000000..1937843
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_syscnt.c
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+ return 50000000;
+}
diff --git a/plat/socionext/uniphier/uniphier_tbbr.c b/plat/socionext/uniphier/uniphier_tbbr.c
new file mode 100644
index 0000000..e31ca03
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_tbbr.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+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);
+}
diff --git a/plat/socionext/uniphier/uniphier_topology.c b/plat/socionext/uniphier/uniphier_topology.c
new file mode 100644
index 0000000..c106c98
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_topology.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <plat/common/platform.h>
+
+#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);
+}
diff --git a/plat/socionext/uniphier/uniphier_usb.c b/plat/socionext/uniphier/uniphier_usb.c
new file mode 100644
index 0000000..7469ad1
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_usb.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <drivers/io/io_block.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#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 = {
+ .ops = {
+ .read = uniphier_usb_read,
+ },
+ .block_size = 512,
+};
+
+int uniphier_usb_init(unsigned int soc,
+ struct io_block_dev_spec **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 = &uniphier_usb_dev_spec;
+
+ return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_xlat_setup.c b/plat/socionext/uniphier/uniphier_xlat_setup.c
new file mode 100644
index 0000000..5043f4b
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_xlat_setup.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include "uniphier.h"
+
+struct uniphier_reg_region {
+ uintptr_t base;
+ size_t size;
+};
+
+static const struct uniphier_reg_region uniphier_reg_region[] = {
+ [UNIPHIER_SOC_LD11] = {
+ .base = 0x50000000UL,
+ .size = 0x20000000UL,
+ },
+ [UNIPHIER_SOC_LD20] = {
+ .base = 0x50000000UL,
+ .size = 0x20000000UL,
+ },
+ [UNIPHIER_SOC_PXS3] = {
+ .base = 0x50000000UL,
+ .size = 0x20000000UL,
+ },
+};
+
+void uniphier_mmap_setup(unsigned int soc)
+{
+ VERBOSE("Trusted RAM seen by this BL image: %p - %p\n",
+ (void *)BL_CODE_BASE, (void *)BL_END);
+ mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
+ round_up(BL_END, PAGE_SIZE) - BL_CODE_BASE,
+ 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 */
+ assert(soc < ARRAY_SIZE(uniphier_reg_region));
+ mmap_add_region(uniphier_reg_region[soc].base,
+ uniphier_reg_region[soc].base,
+ uniphier_reg_region[soc].size,
+ MT_DEVICE | MT_RW | MT_SECURE);
+
+ init_xlat_tables();
+
+ enable_mmu(0);
+
+#if PLAT_RO_XLAT_TABLES
+ {
+ int ret;
+
+ ret = xlat_make_tables_readonly();
+ if (ret) {
+ ERROR("Failed to make translation tables read-only.");
+ plat_error_handler(ret);
+ }
+ }
+#endif
+}
diff --git a/plat/st/common/bl2_io_storage.c b/plat/st/common/bl2_io_storage.c
new file mode 100644
index 0000000..b271ed6
--- /dev/null
+++ b/plat/st/common/bl2_io_storage.c
@@ -0,0 +1,731 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/fwu/fwu.h>
+#include <drivers/fwu/fwu_metadata.h>
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_encrypted.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_mtd.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/mmc.h>
+#include <drivers/partition/efi.h>
+#include <drivers/partition/partition.h>
+#include <drivers/raw_nand.h>
+#include <drivers/spi_nand.h>
+#include <drivers/spi_nor.h>
+#include <drivers/st/io_mmc.h>
+#include <drivers/st/stm32_fmc2_nand.h>
+#include <drivers/st/stm32_qspi.h>
+#include <drivers/st/stm32_sdmmc2.h>
+#include <drivers/usb_device.h>
+#include <lib/fconf/fconf.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <tools_share/firmware_image_package.h>
+
+#include <platform_def.h>
+#include <stm32cubeprogrammer.h>
+#include <stm32mp_efi.h>
+#include <stm32mp_fconf_getter.h>
+#include <stm32mp_io_storage.h>
+#include <usb_dfu.h>
+
+/* IO devices */
+uintptr_t fip_dev_handle;
+uintptr_t storage_dev_handle;
+
+static const io_dev_connector_t *fip_dev_con;
+
+#ifndef DECRYPTION_SUPPORT_none
+static const io_dev_connector_t *enc_dev_con;
+uintptr_t enc_dev_handle;
+#endif
+
+#if STM32MP_SDMMC || STM32MP_EMMC
+static struct mmc_device_info mmc_info;
+
+static uint32_t block_buffer[MMC_BLOCK_SIZE] __aligned(MMC_BLOCK_SIZE);
+
+static 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 const io_dev_connector_t *mmc_dev_con;
+#endif /* STM32MP_SDMMC || STM32MP_EMMC */
+
+#if STM32MP_SPI_NOR
+static io_mtd_dev_spec_t spi_nor_dev_spec = {
+ .ops = {
+ .init = spi_nor_init,
+ .read = spi_nor_read,
+ },
+};
+#endif
+
+#if STM32MP_RAW_NAND
+static io_mtd_dev_spec_t nand_dev_spec = {
+ .ops = {
+ .init = nand_raw_init,
+ .read = nand_read,
+ .seek = nand_seek_bb
+ },
+};
+
+static const io_dev_connector_t *nand_dev_con;
+#endif
+
+#if STM32MP_SPI_NAND
+static io_mtd_dev_spec_t spi_nand_dev_spec = {
+ .ops = {
+ .init = spi_nand_init,
+ .read = nand_read,
+ .seek = nand_seek_bb
+ },
+};
+#endif
+
+#if STM32MP_SPI_NAND || STM32MP_SPI_NOR
+static const io_dev_connector_t *spi_dev_con;
+#endif
+
+#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
+static const io_dev_connector_t *memmap_dev_con;
+#endif
+
+io_block_spec_t image_block_spec = {
+ .offset = 0U,
+ .length = 0U,
+};
+
+int open_fip(const uintptr_t spec)
+{
+ return io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+}
+
+#ifndef DECRYPTION_SUPPORT_none
+int open_enc_fip(const uintptr_t spec)
+{
+ int result;
+ uintptr_t local_image_handle;
+
+ result = io_dev_init(enc_dev_handle, (uintptr_t)ENC_IMAGE_ID);
+ if (result != 0) {
+ return result;
+ }
+
+ result = io_open(enc_dev_handle, spec, &local_image_handle);
+ if (result != 0) {
+ return result;
+ }
+
+ VERBOSE("Using encrypted FIP\n");
+ io_close(local_image_handle);
+
+ return 0;
+}
+#endif
+
+int open_storage(const uintptr_t spec)
+{
+ return io_dev_init(storage_dev_handle, 0);
+}
+
+#if STM32MP_EMMC_BOOT
+static uint32_t get_boot_part_fip_header(void)
+{
+ io_block_spec_t emmc_boot_fip_block_spec = {
+ .offset = STM32MP_EMMC_BOOT_FIP_OFFSET,
+ .length = MMC_BLOCK_SIZE, /* We are interested only in first 4 bytes */
+ };
+ uint32_t magic = 0U;
+ int io_result;
+ size_t bytes_read;
+ uintptr_t fip_hdr_handle;
+
+ io_result = io_open(storage_dev_handle, (uintptr_t)&emmc_boot_fip_block_spec,
+ &fip_hdr_handle);
+ assert(io_result == 0);
+
+ io_result = io_read(fip_hdr_handle, (uintptr_t)&magic, sizeof(magic),
+ &bytes_read);
+ if ((io_result != 0) || (bytes_read != sizeof(magic))) {
+ panic();
+ }
+
+ io_close(fip_hdr_handle);
+
+ VERBOSE("%s: eMMC boot magic at offset 256K: %08x\n",
+ __func__, magic);
+
+ return magic;
+}
+#endif
+
+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;
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI:
+ INFO("Using QSPI NOR\n");
+ break;
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC:
+ INFO("Using FMC NAND\n");
+ break;
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI:
+ INFO("Using SPI NAND\n");
+ break;
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
+ INFO("Using UART\n");
+ break;
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
+ INFO("Using USB\n");
+ break;
+ default:
+ ERROR("Boot interface %u not found\n",
+ boot_context->boot_interface_selected);
+ panic();
+ break;
+ }
+
+ if (boot_context->boot_interface_instance != 0U) {
+ INFO(" Instance %d\n", boot_context->boot_interface_instance);
+ }
+}
+
+#if STM32MP_SDMMC || STM32MP_EMMC
+static void boot_mmc(enum mmc_device_type mmc_dev_type,
+ uint16_t boot_interface_instance)
+{
+ int io_result __unused;
+ struct stm32_sdmmc2_params params;
+
+ zeromem(&params, sizeof(struct stm32_sdmmc2_params));
+
+ mmc_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;
+ }
+
+ if (mmc_dev_type != MMC_IS_EMMC) {
+ params.flags = MMC_FLAG_SD_CMD6;
+ }
+
+ params.device_info = &mmc_info;
+ if (stm32_sdmmc2_mmc_init(&params) != 0) {
+ ERROR("SDMMC%u init failed\n", boot_interface_instance);
+ panic();
+ }
+
+ /* Open MMC as a block device to read FIP */
+ 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);
+
+#if STM32MP_EMMC_BOOT
+ if (mmc_dev_type == MMC_IS_EMMC) {
+ io_result = mmc_part_switch_current_boot();
+ assert(io_result == 0);
+
+ if (get_boot_part_fip_header() != TOC_HEADER_NAME) {
+ WARN("%s: Can't find FIP header on eMMC boot partition. Trying GPT\n",
+ __func__);
+ io_result = mmc_part_switch_user();
+ assert(io_result == 0);
+ return;
+ }
+
+ VERBOSE("%s: FIP header found on eMMC boot partition\n",
+ __func__);
+ image_block_spec.offset = STM32MP_EMMC_BOOT_FIP_OFFSET;
+ image_block_spec.length = mmc_boot_part_size() - STM32MP_EMMC_BOOT_FIP_OFFSET;
+ }
+#endif
+}
+#endif /* STM32MP_SDMMC || STM32MP_EMMC */
+
+#if STM32MP_SPI_NOR
+static void boot_spi_nor(boot_api_context_t *boot_context)
+{
+ int io_result __unused;
+
+ io_result = stm32_qspi_init();
+ assert(io_result == 0);
+
+ io_result = register_io_dev_mtd(&spi_dev_con);
+ assert(io_result == 0);
+
+ /* Open connections to device */
+ io_result = io_dev_open(spi_dev_con,
+ (uintptr_t)&spi_nor_dev_spec,
+ &storage_dev_handle);
+ assert(io_result == 0);
+}
+#endif /* STM32MP_SPI_NOR */
+
+#if STM32MP_RAW_NAND
+static void boot_fmc2_nand(boot_api_context_t *boot_context)
+{
+ int io_result __unused;
+
+ io_result = stm32_fmc2_init();
+ assert(io_result == 0);
+
+ /* Register the IO device on this platform */
+ io_result = register_io_dev_mtd(&nand_dev_con);
+ assert(io_result == 0);
+
+ /* Open connections to device */
+ io_result = io_dev_open(nand_dev_con, (uintptr_t)&nand_dev_spec,
+ &storage_dev_handle);
+ assert(io_result == 0);
+}
+#endif /* STM32MP_RAW_NAND */
+
+#if STM32MP_SPI_NAND
+static void boot_spi_nand(boot_api_context_t *boot_context)
+{
+ int io_result __unused;
+
+ io_result = stm32_qspi_init();
+ assert(io_result == 0);
+
+ io_result = register_io_dev_mtd(&spi_dev_con);
+ assert(io_result == 0);
+
+ /* Open connections to device */
+ io_result = io_dev_open(spi_dev_con,
+ (uintptr_t)&spi_nand_dev_spec,
+ &storage_dev_handle);
+ assert(io_result == 0);
+}
+#endif /* STM32MP_SPI_NAND */
+
+#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
+static void mmap_io_setup(void)
+{
+ int io_result __unused;
+
+ io_result = register_io_dev_memmap(&memmap_dev_con);
+ assert(io_result == 0);
+
+ io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL,
+ &storage_dev_handle);
+ assert(io_result == 0);
+}
+
+#if STM32MP_UART_PROGRAMMER
+static void stm32cubeprogrammer_uart(void)
+{
+ int ret __unused;
+ boot_api_context_t *boot_context =
+ (boot_api_context_t *)stm32mp_get_boot_ctx_address();
+ uintptr_t uart_base;
+
+ uart_base = get_uart_address(boot_context->boot_interface_instance);
+ ret = stm32cubeprog_uart_load(uart_base, DWL_BUFFER_BASE, DWL_BUFFER_SIZE);
+ assert(ret == 0);
+}
+#endif
+
+#if STM32MP_USB_PROGRAMMER
+static void stm32cubeprogrammer_usb(void)
+{
+ int ret __unused;
+ struct usb_handle *pdev;
+
+ /* Init USB on platform */
+ pdev = usb_dfu_plat_init();
+
+ ret = stm32cubeprog_usb_load(pdev, DWL_BUFFER_BASE, DWL_BUFFER_SIZE);
+ assert(ret == 0);
+}
+#endif
+#endif /* STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER */
+
+
+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%u\n",
+ boot_context->boot_partition_used_toboot);
+ }
+
+ io_result = register_io_dev_fip(&fip_dev_con);
+ assert(io_result == 0);
+
+ io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL,
+ &fip_dev_handle);
+
+#ifndef DECRYPTION_SUPPORT_none
+ io_result = register_io_dev_enc(&enc_dev_con);
+ assert(io_result == 0);
+
+ io_result = io_dev_open(enc_dev_con, (uintptr_t)NULL,
+ &enc_dev_handle);
+ assert(io_result == 0);
+#endif
+
+ switch (boot_context->boot_interface_selected) {
+#if STM32MP_SDMMC
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD:
+ dmbsy();
+ boot_mmc(MMC_IS_SD, boot_context->boot_interface_instance);
+ break;
+#endif
+#if STM32MP_EMMC
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC:
+ dmbsy();
+ boot_mmc(MMC_IS_EMMC, boot_context->boot_interface_instance);
+ break;
+#endif
+#if STM32MP_SPI_NOR
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI:
+ dmbsy();
+ boot_spi_nor(boot_context);
+ break;
+#endif
+#if STM32MP_RAW_NAND
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC:
+ dmbsy();
+ boot_fmc2_nand(boot_context);
+ break;
+#endif
+#if STM32MP_SPI_NAND
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI:
+ dmbsy();
+ boot_spi_nand(boot_context);
+ break;
+#endif
+#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
+#if STM32MP_UART_PROGRAMMER
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
+#endif
+#if STM32MP_USB_PROGRAMMER
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
+#endif
+ dmbsy();
+ mmap_io_setup();
+ break;
+#endif
+
+ default:
+ ERROR("Boot interface %d not supported\n",
+ boot_context->boot_interface_selected);
+ panic();
+ break;
+ }
+}
+
+int bl2_plat_handle_pre_image_load(unsigned int image_id)
+{
+ static bool gpt_init_done __unused;
+ uint16_t boot_itf = stm32mp_get_boot_itf_selected();
+
+ switch (boot_itf) {
+#if STM32MP_SDMMC || STM32MP_EMMC
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC:
+#if STM32MP_EMMC_BOOT
+ if (image_block_spec.offset == STM32MP_EMMC_BOOT_FIP_OFFSET) {
+ break;
+ }
+#endif
+ /* fallthrough */
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD:
+ if (!gpt_init_done) {
+/*
+ * With FWU Multi Bank feature enabled, the selection of
+ * the image to boot will be done by fwu_init calling the
+ * platform hook, plat_fwu_set_images_source.
+ */
+#if !PSA_FWU_SUPPORT
+ const partition_entry_t *entry;
+ const struct efi_guid img_type_guid = STM32MP_FIP_GUID;
+ uuid_t img_type_uuid;
+
+ guidcpy(&img_type_uuid, &img_type_guid);
+ partition_init(GPT_IMAGE_ID);
+ entry = get_partition_entry_by_type(&img_type_uuid);
+ if (entry == NULL) {
+ entry = get_partition_entry(FIP_IMAGE_NAME);
+ if (entry == NULL) {
+ ERROR("Could NOT find the %s partition!\n",
+ FIP_IMAGE_NAME);
+
+ return -ENOENT;
+ }
+ }
+
+ image_block_spec.offset = entry->start;
+ image_block_spec.length = entry->length;
+#endif
+ gpt_init_done = true;
+ } else {
+ bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
+ assert(bl_mem_params != NULL);
+
+ mmc_block_dev_spec.buffer.offset = bl_mem_params->image_info.image_base;
+ mmc_block_dev_spec.buffer.length = bl_mem_params->image_info.image_max_size;
+ }
+
+ break;
+#endif
+
+#if STM32MP_RAW_NAND || STM32MP_SPI_NAND
+#if STM32MP_RAW_NAND
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC:
+#endif
+#if STM32MP_SPI_NAND
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI:
+#endif
+ image_block_spec.offset = STM32MP_NAND_FIP_OFFSET;
+ break;
+#endif
+
+#if STM32MP_SPI_NOR
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI:
+ image_block_spec.offset = STM32MP_NOR_FIP_OFFSET;
+ break;
+#endif
+
+#if STM32MP_UART_PROGRAMMER
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
+ if (image_id == FW_CONFIG_ID) {
+ stm32cubeprogrammer_uart();
+ /* FIP loaded at DWL address */
+ image_block_spec.offset = DWL_BUFFER_BASE;
+ image_block_spec.length = DWL_BUFFER_SIZE;
+ }
+ break;
+#endif
+#if STM32MP_USB_PROGRAMMER
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
+ if (image_id == FW_CONFIG_ID) {
+ stm32cubeprogrammer_usb();
+ /* FIP loaded at DWL address */
+ image_block_spec.offset = DWL_BUFFER_BASE;
+ image_block_spec.length = DWL_BUFFER_SIZE;
+ }
+ break;
+#endif
+
+ default:
+ ERROR("FIP Not found\n");
+ panic();
+ }
+
+ 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 rc;
+ const struct plat_io_policy *policy;
+
+ policy = FCONF_GET_PROPERTY(stm32mp, io_policies, image_id);
+ rc = policy->check(policy->image_spec);
+ if (rc == 0) {
+ *image_spec = policy->image_spec;
+ *dev_handle = *(policy->dev_handle);
+ }
+
+ return rc;
+}
+
+#if (STM32MP_SDMMC || STM32MP_EMMC) && PSA_FWU_SUPPORT
+/*
+ * In each boot in non-trial mode, we set the BKP register to
+ * FWU_MAX_TRIAL_REBOOT, and return the active_index from metadata.
+ *
+ * As long as the update agent didn't update the "accepted" field in metadata
+ * (i.e. we are in trial mode), we select the new active_index.
+ * To avoid infinite boot loop at trial boot we decrement a BKP register.
+ * If this counter is 0:
+ * - an unexpected TAMPER event raised (that resets the BKP registers to 0)
+ * - a power-off occurs before the update agent was able to update the
+ * "accepted' field
+ * - we already boot FWU_MAX_TRIAL_REBOOT times in trial mode.
+ * we select the previous_active_index.
+ */
+#define INVALID_BOOT_IDX 0xFFFFFFFF
+
+uint32_t plat_fwu_get_boot_idx(void)
+{
+ /*
+ * Select boot index and update boot counter only once per boot
+ * even if this function is called several times.
+ */
+ static uint32_t boot_idx = INVALID_BOOT_IDX;
+ const struct fwu_metadata *data;
+
+ data = fwu_get_metadata();
+
+ if (boot_idx == INVALID_BOOT_IDX) {
+ boot_idx = data->active_index;
+ if (fwu_is_trial_run_state()) {
+ if (stm32_get_and_dec_fwu_trial_boot_cnt() == 0U) {
+ WARN("Trial FWU fails %u times\n",
+ FWU_MAX_TRIAL_REBOOT);
+ boot_idx = data->previous_active_index;
+ }
+ } else {
+ stm32_set_max_fwu_trial_boot_cnt();
+ }
+ }
+
+ return boot_idx;
+}
+
+static void *stm32_get_image_spec(const uuid_t *img_type_uuid)
+{
+ unsigned int i;
+
+ for (i = 0U; i < MAX_NUMBER_IDS; i++) {
+ if ((guidcmp(&policies[i].img_type_guid, img_type_uuid)) == 0) {
+ return (void *)policies[i].image_spec;
+ }
+ }
+
+ return NULL;
+}
+
+void plat_fwu_set_images_source(const struct fwu_metadata *metadata)
+{
+ unsigned int i;
+ uint32_t boot_idx;
+ const partition_entry_t *entry;
+ const uuid_t *img_type_uuid, *img_uuid;
+ io_block_spec_t *image_spec;
+
+ boot_idx = plat_fwu_get_boot_idx();
+ assert(boot_idx < NR_OF_FW_BANKS);
+
+ for (i = 0U; i < NR_OF_IMAGES_IN_FW_BANK; i++) {
+ img_type_uuid = &metadata->img_entry[i].img_type_uuid;
+ image_spec = stm32_get_image_spec(img_type_uuid);
+ if (image_spec == NULL) {
+ ERROR("Unable to get image spec for the image in the metadata\n");
+ panic();
+ }
+
+ img_uuid =
+ &metadata->img_entry[i].img_props[boot_idx].img_uuid;
+
+ entry = get_partition_entry_by_uuid(img_uuid);
+ if (entry == NULL) {
+ ERROR("Unable to find the partition with the uuid mentioned in metadata\n");
+ panic();
+ }
+
+ image_spec->offset = entry->start;
+ image_spec->length = entry->length;
+ }
+}
+
+static int plat_set_image_source(unsigned int image_id,
+ uintptr_t *handle,
+ uintptr_t *image_spec,
+ const char *part_name)
+{
+ struct plat_io_policy *policy;
+ io_block_spec_t *spec;
+ const partition_entry_t *entry = get_partition_entry(part_name);
+
+ if (entry == NULL) {
+ ERROR("Unable to find the %s partition\n", part_name);
+ return -ENOENT;
+ }
+
+ policy = &policies[image_id];
+
+ spec = (io_block_spec_t *)policy->image_spec;
+ spec->offset = entry->start;
+ spec->length = entry->length;
+
+ *image_spec = policy->image_spec;
+ *handle = *policy->dev_handle;
+
+ return 0;
+}
+
+int plat_fwu_set_metadata_image_source(unsigned int image_id,
+ uintptr_t *handle,
+ uintptr_t *image_spec)
+{
+ char *part_name;
+
+ assert((image_id == FWU_METADATA_IMAGE_ID) ||
+ (image_id == BKUP_FWU_METADATA_IMAGE_ID));
+
+ partition_init(GPT_IMAGE_ID);
+
+ if (image_id == FWU_METADATA_IMAGE_ID) {
+ part_name = METADATA_PART_1;
+ } else {
+ part_name = METADATA_PART_2;
+ }
+
+ return plat_set_image_source(image_id, handle, image_spec,
+ part_name);
+}
+#endif /* (STM32MP_SDMMC || STM32MP_EMMC) && PSA_FWU_SUPPORT */
diff --git a/plat/st/common/include/stm32cubeprogrammer.h b/plat/st/common/include/stm32cubeprogrammer.h
new file mode 100644
index 0000000..0f5a64d
--- /dev/null
+++ b/plat/st/common/include/stm32cubeprogrammer.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32CUBEPROGRAMMER_H
+#define STM32CUBEPROGRAMMER_H
+
+#include <stdint.h>
+
+#include <usb_dfu.h>
+
+/* Phase definition */
+#define PHASE_FLASHLAYOUT 0U
+#define PHASE_SSBL 3U
+#define PHASE_CMD 0xF1U
+#define PHASE_RESET 0xFFU
+
+/* Functions provided by plat */
+uint8_t usb_dfu_get_phase(uint8_t alt);
+
+int stm32cubeprog_usb_load(struct usb_handle *usb_core_handle,
+ uintptr_t ssbl_base,
+ size_t ssbl_len);
+
+int stm32cubeprog_uart_load(uintptr_t instance, uintptr_t base, size_t len);
+
+#endif /* STM32CUBEPROGRAMMER_H */
diff --git a/plat/st/common/include/stm32mp_common.h b/plat/st/common/include/stm32mp_common.h
new file mode 100644
index 0000000..a5316b6
--- /dev/null
+++ b/plat/st/common/include/stm32mp_common.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2018-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP_COMMON_H
+#define STM32MP_COMMON_H
+
+#include <stdbool.h>
+
+#include <platform_def.h>
+
+#define JEDEC_ST_BKID U(0x0)
+#define JEDEC_ST_MFID U(0x20)
+
+/* 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);
+uint16_t stm32mp_get_boot_itf_selected(void);
+
+bool stm32mp_is_single_core(void);
+bool stm32mp_is_closed_device(void);
+bool stm32mp_is_auth_supported(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);
+
+int stm32_get_otp_index(const char *otp_name, uint32_t *otp_idx,
+ uint32_t *otp_len);
+int stm32_get_otp_value(const char *otp_name, uint32_t *otp_val);
+int stm32_get_otp_value_from_idx(const uint32_t otp_idx, uint32_t *otp_val);
+
+/* Get IWDG platform instance ID from peripheral IO memory base address */
+uint32_t stm32_iwdg_get_instance(uintptr_t base);
+
+/* 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
+
+#if STM32MP_UART_PROGRAMMER || !defined(IMAGE_BL2)
+/* Get the UART address from its instance number */
+uintptr_t get_uart_address(uint32_t instance_nb);
+#endif
+
+/* Setup the UART console */
+int stm32mp_uart_console_setup(void);
+
+#if STM32MP_EARLY_CONSOLE
+void stm32mp_setup_early_console(void);
+#else
+static inline void stm32mp_setup_early_console(void)
+{
+}
+#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);
+bool stm32_gpio_is_secure_at_reset(unsigned int bank);
+
+/* Return node offset for target GPIO bank ID @bank or a FDT error code */
+int stm32_get_gpio_bank_pinctrl_node(void *fdt, unsigned int bank);
+
+/* Get the chip revision */
+uint32_t stm32mp_get_chip_version(void);
+/* Get the chip device ID */
+uint32_t stm32mp_get_chip_dev_id(void);
+
+/* Get SOC name */
+#define STM32_SOC_NAME_SIZE 20
+void stm32mp_get_soc_name(char name[STM32_SOC_NAME_SIZE]);
+
+/* Print CPU information */
+void stm32mp_print_cpuinfo(void);
+
+/* Print board information */
+void stm32mp_print_boardinfo(void);
+
+/* Initialise the IO layer and register platform IO devices */
+void stm32mp_io_setup(void);
+
+/* Functions to map DDR in MMU with non-cacheable attribute, and unmap it */
+int stm32mp_map_ddr_non_cacheable(void);
+int stm32mp_unmap_ddr(void);
+
+/* Functions to save and get boot peripheral info */
+void stm32_save_boot_interface(uint32_t interface, uint32_t instance);
+void stm32_get_boot_interface(uint32_t *interface, uint32_t *instance);
+
+/* Functions to save and get boot authentication status and partition used */
+void stm32_save_boot_auth(uint32_t auth_status, uint32_t boot_partition);
+
+#if PSA_FWU_SUPPORT
+void stm32mp1_fwu_set_boot_idx(void);
+uint32_t stm32_get_and_dec_fwu_trial_boot_cnt(void);
+void stm32_set_max_fwu_trial_boot_cnt(void);
+#endif /* PSA_FWU_SUPPORT */
+
+#endif /* STM32MP_COMMON_H */
diff --git a/plat/st/common/include/stm32mp_dt.h b/plat/st/common/include/stm32mp_dt.h
new file mode 100644
index 0000000..b7bf1d0
--- /dev/null
+++ b/plat/st/common/include/stm32mp_dt.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020-2022, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP_DT_H
+#define STM32MP_DT_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define DT_DISABLED U(0)
+#define DT_NON_SECURE U(1)
+#define DT_SECURE U(2)
+#define DT_SHARED (DT_NON_SECURE | DT_SECURE)
+
+struct dt_node_info {
+ uint32_t base;
+ int32_t clock;
+ int32_t reset;
+ uint32_t status;
+};
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+int dt_open_and_check(uintptr_t dt_addr);
+int fdt_get_address(void **fdt_addr);
+bool fdt_check_node(int node);
+uint8_t fdt_get_status(int node);
+int dt_set_stdout_pinctrl(void);
+void dt_fill_device_info(struct dt_node_info *info, int node);
+int dt_get_node(struct dt_node_info *info, int offset, const char *compat);
+int dt_get_stdout_uart_info(struct dt_node_info *info);
+int dt_match_instance_by_compatible(const char *compatible, uintptr_t address);
+uint32_t dt_get_ddr_size(void);
+uint32_t dt_get_pwr_vdd_voltage(void);
+struct rdev *dt_get_vdd_regulator(void);
+struct rdev *dt_get_cpu_regulator(void);
+const char *dt_get_board_model(void);
+int dt_find_otp_name(const char *name, uint32_t *otp, uint32_t *otp_len);
+int fdt_get_gpio_bank_pin_count(unsigned int bank);
+
+#endif /* STM32MP_DT_H */
diff --git a/plat/st/common/include/stm32mp_efi.h b/plat/st/common/include/stm32mp_efi.h
new file mode 100644
index 0000000..490560f
--- /dev/null
+++ b/plat/st/common/include/stm32mp_efi.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021, Linaro Limited
+ */
+
+#ifndef STM32MP_EFI_H
+#define STM32MP_EFI_H
+
+#include <drivers/partition/efi.h>
+
+#define STM32MP_FIP_GUID \
+ EFI_GUID(0x19d5df83, 0x11b0, 0x457b, \
+ 0xbe, 0x2c, 0x75, 0x59, 0xc1, 0x31, 0x42, 0xa5)
+
+#endif /* STM32MP_EFI_H */
diff --git a/plat/st/common/include/stm32mp_fconf_getter.h b/plat/st/common/include/stm32mp_fconf_getter.h
new file mode 100644
index 0000000..18884ae
--- /dev/null
+++ b/plat/st/common/include/stm32mp_fconf_getter.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP_FCONF_GETTER
+#define STM32MP_FCONF_GETTER
+
+#include <assert.h>
+
+#include <lib/fconf/fconf.h>
+#include <tools_share/uuid.h>
+
+/* IO policies */
+#define stm32mp__io_policies_getter(id) __extension__ ({ \
+ assert((id) < MAX_NUMBER_IDS); \
+ &policies[id]; \
+})
+
+struct plat_io_policy {
+ uintptr_t *dev_handle;
+ uintptr_t image_spec;
+ struct efi_guid img_type_guid;
+ int (*check)(const uintptr_t spec);
+};
+
+extern struct plat_io_policy policies[];
+int fconf_populate_stm32mp_io_policies(uintptr_t config);
+
+#endif /* STM32MP_FCONF_GETTER */
diff --git a/plat/st/common/include/stm32mp_io_storage.h b/plat/st/common/include/stm32mp_io_storage.h
new file mode 100644
index 0000000..3c04c47
--- /dev/null
+++ b/plat/st/common/include/stm32mp_io_storage.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef STM32MP_IO_STORAGE_H
+#define STM32MP_IO_STORAGE_H
+
+#include <stdint.h>
+
+#include <drivers/io/io_storage.h>
+
+/* IO devices handle */
+extern uintptr_t storage_dev_handle;
+extern uintptr_t fip_dev_handle;
+extern uintptr_t enc_dev_handle;
+
+extern io_block_spec_t image_block_spec;
+
+/* Function declarations */
+int open_fip(const uintptr_t spec);
+#ifndef DECRYPTION_SUPPORT_none
+int open_enc_fip(const uintptr_t spec);
+#endif
+int open_storage(const uintptr_t spec);
+
+#endif /* STM32MP_IO_STORAGE_H */
diff --git a/plat/st/common/include/stm32mp_shared_resources.h b/plat/st/common/include/stm32mp_shared_resources.h
new file mode 100644
index 0000000..13f4b13
--- /dev/null
+++ b/plat/st/common/include/stm32mp_shared_resources.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP_SHARED_RESOURCES_H
+#define STM32MP_SHARED_RESOURCES_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef STM32MP_SHARED_RESOURCES
+enum stm32mp_shres;
+
+/* Return true if @clock_id is shared by secure and non-secure worlds */
+bool stm32mp_nsec_can_access_clock(unsigned long clock_id);
+
+/* Return true if and only if @reset_id relates to a non-secure peripheral */
+bool stm32mp_nsec_can_access_reset(unsigned int reset_id);
+
+/* Register a shared resource assigned to the secure world */
+void stm32mp_register_secure_periph(enum stm32mp_shres id);
+
+/* Register a shared resource assigned to the non-secure world */
+void stm32mp_register_non_secure_periph(enum stm32mp_shres id);
+
+/* Register a peripheral as secure or non-secure based on IO base address */
+void stm32mp_register_secure_periph_iomem(uintptr_t base);
+void stm32mp_register_non_secure_periph_iomem(uintptr_t base);
+
+/* Register a GPIO as secure or non-secure based on its bank and pin numbers */
+void stm32mp_register_secure_gpio(unsigned int bank, unsigned int pin);
+void stm32mp_register_non_secure_gpio(unsigned int bank, unsigned int pin);
+
+/* Consolidate peripheral states and lock against new peripheral registering */
+void stm32mp_lock_periph_registering(void);
+#else
+static inline void stm32mp_register_secure_periph_iomem(uintptr_t base __unused)
+{
+}
+
+static inline
+void stm32mp_register_non_secure_periph_iomem(uintptr_t base __unused)
+{
+}
+
+static inline void stm32mp_register_secure_gpio(unsigned int bank __unused,
+ unsigned int pin __unused)
+{
+}
+
+static inline void stm32mp_register_non_secure_gpio(unsigned int bank __unused,
+ unsigned int pin __unused)
+{
+}
+#endif /* STM32MP_SHARED_RESOURCES */
+#endif /* STM32MP_SHARED_RESOURCES_H */
diff --git a/plat/st/common/include/usb_dfu.h b/plat/st/common/include/usb_dfu.h
new file mode 100644
index 0000000..f7d4245
--- /dev/null
+++ b/plat/st/common/include/usb_dfu.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef USB_DFU_H
+#define USB_DFU_H
+
+#include <stdint.h>
+
+#include <drivers/usb_device.h>
+
+#define DFU_DESCRIPTOR_TYPE 0x21U
+
+/* Max DFU Packet Size = 1024 bytes */
+#define USBD_DFU_XFER_SIZE 1024U
+
+#define TRANSFER_SIZE_BYTES(size) \
+ ((uint8_t)((size) & 0xFF)), /* XFERSIZEB0 */\
+ ((uint8_t)((size) >> 8)) /* XFERSIZEB1 */
+
+/*
+ * helper for descriptor of DFU interface 0 Alternate setting n
+ * with iInterface = index of string descriptor, assumed Nth user string
+ */
+#define USBD_DFU_IF_DESC(n) 0x09U, /* Interface Descriptor size */\
+ USB_DESC_TYPE_INTERFACE, /* descriptor type */\
+ 0x00U, /* Number of Interface */\
+ (n), /* Alternate setting */\
+ 0x00U, /* bNumEndpoints*/\
+ 0xFEU, /* Application Specific Class Code */\
+ 0x01U, /* Device Firmware Upgrade Code */\
+ 0x02U, /* DFU mode protocol */ \
+ USBD_IDX_USER0_STR + (n) /* iInterface */
+
+/* DFU1.1 Standard */
+#define USB_DFU_VERSION 0x0110U
+#define USB_DFU_ITF_SIZ 9U
+#define USB_DFU_DESC_SIZ(itf) (USB_DFU_ITF_SIZ * ((itf) + 2U))
+
+/*
+ * bmAttribute value for DFU:
+ * bitCanDnload = 1(bit 0)
+ * bitCanUpload = 1(bit 1)
+ * bitManifestationTolerant = 1 (bit 2)
+ * bitWillDetach = 1(bit 3)
+ * Reserved (bit4-6)
+ * bitAcceleratedST = 0(bit 7)
+ */
+#define DFU_BM_ATTRIBUTE 0x0FU
+
+#define DFU_STATUS_SIZE 6U
+
+/* Callback for media access */
+struct usb_dfu_media {
+ int (*upload)(uint8_t alt, uintptr_t *buffer, uint32_t *len,
+ void *user_data);
+ int (*download)(uint8_t alt, uintptr_t *buffer, uint32_t *len,
+ void *user_data);
+ int (*manifestation)(uint8_t alt, void *user_data);
+};
+
+/* Internal DFU handle */
+struct usb_dfu_handle {
+ uint8_t status[DFU_STATUS_SIZE];
+ uint8_t dev_state;
+ uint8_t dev_status;
+ uint8_t alt_setting;
+ const struct usb_dfu_media *callback;
+};
+
+void usb_dfu_register(struct usb_handle *pdev, struct usb_dfu_handle *phandle);
+
+int usb_dfu_loop(struct usb_handle *pdev, const struct usb_dfu_media *pmedia);
+
+/* Function provided by plat */
+struct usb_handle *usb_dfu_plat_init(void);
+
+#endif /* USB_DFU_H */
diff --git a/plat/st/common/stm32cubeprogrammer_uart.c b/plat/st/common/stm32cubeprogrammer_uart.c
new file mode 100644
index 0000000..d004dcf
--- /dev/null
+++ b/plat/st/common/stm32cubeprogrammer_uart.c
@@ -0,0 +1,520 @@
+/*
+ * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <endian.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_iwdg.h>
+#include <drivers/st/stm32_uart.h>
+#include <drivers/st/stm32_uart_regs.h>
+#include <lib/mmio.h>
+#include <tools_share/firmware_image_package.h>
+
+#include <platform_def.h>
+#include <stm32cubeprogrammer.h>
+
+/* USART bootloader protocol version V4.0 */
+#define USART_BL_VERSION 0x40U
+
+/* Command definition */
+#define GET_CMD_COMMAND 0x00U
+#define GET_VER_COMMAND 0x01U
+#define GET_ID_COMMAND 0x02U
+#define PHASE_COMMAND 0x03U
+#define READ_PART_COMMAND 0x12U
+#define START_COMMAND 0x21U
+#define DOWNLOAD_COMMAND 0x31U
+
+/* Answer defines */
+#define INIT_BYTE 0x7FU
+#define ACK_BYTE 0x79U
+#define NACK_BYTE 0x1FU
+#define ABORT 0x5FU
+
+#define UNDEFINED_DOWN_ADDR U(0xFFFFFFFF)
+#define PROGRAMMER_TIMEOUT_US 20000U
+
+static const uint8_t command_tab[] = {
+ GET_CMD_COMMAND,
+ GET_VER_COMMAND,
+ GET_ID_COMMAND,
+ PHASE_COMMAND,
+ START_COMMAND,
+ DOWNLOAD_COMMAND
+};
+
+/* STM32CubeProgrammer over UART handle */
+struct stm32prog_uart_handle_s {
+ struct stm32_uart_handle_s uart;
+ uint32_t packet;
+ uint8_t *addr;
+ uint32_t len;
+ uint8_t phase;
+ /* Error msg buffer: max 255 in UART protocol, reduced in TF-A */
+ uint8_t error[64];
+} handle;
+
+/* Trace and handle unrecoverable UART protocol error */
+#define STM32PROG_ERROR(...) \
+ { \
+ ERROR(__VA_ARGS__); \
+ if (handle.phase != PHASE_RESET) { \
+ snprintf((char *)&handle.error, sizeof(handle.error), __VA_ARGS__); \
+ handle.phase = PHASE_RESET; \
+ handle.addr = (uint8_t *)UNDEFINED_DOWN_ADDR; \
+ handle.len = 0U; \
+ handle.packet = 0U; \
+ } \
+ }
+
+static int uart_write(const uint8_t *addr, uint16_t size)
+{
+ while (size != 0U) {
+ if (stm32_uart_putc(&handle.uart, *addr) != 0) {
+ return -EIO;
+ }
+ size--;
+ addr++;
+ }
+
+ return 0;
+}
+
+static int uart_write_8(uint8_t byte)
+{
+ return stm32_uart_putc(&handle.uart, byte);
+}
+
+static int uart_write_32(uint32_t value)
+{
+ return uart_write((uint8_t *)&value, 4U);
+}
+
+static int uart_read_8(uint8_t *byte)
+{
+ int ret;
+ uint64_t timeout_ref = timeout_init_us(PROGRAMMER_TIMEOUT_US);
+
+ do {
+ ret = stm32_uart_getc(&handle.uart);
+ if (ret == -EAGAIN) {
+ if (timeout_elapsed(timeout_ref)) {
+ return -ETIMEDOUT;
+ }
+ } else if (ret < 0) {
+ return ret;
+ }
+ } while (ret == -EAGAIN);
+
+ *byte = (uint8_t)ret;
+
+ return 0;
+}
+
+static int uart_send_result(uint8_t byte)
+{
+ int ret;
+
+ /* Always flush fifo before to send result = read all pending data */
+ do {
+ ret = stm32_uart_getc(&handle.uart);
+ } while (ret >= 0);
+
+ return uart_write_8(byte);
+}
+
+static bool is_valid_header(fip_toc_header_t *header)
+{
+ return (header->name == TOC_HEADER_NAME) &&
+ (header->serial_number != 0U);
+}
+
+static int uart_receive_command(uint8_t *command)
+{
+ uint8_t byte = 0U;
+ uint8_t xor = 0U;
+ unsigned int count;
+ bool found = false;
+ int ret;
+
+ /* Repeat read until something is received */
+ do {
+ stm32_iwdg_refresh();
+ ret = uart_read_8(&byte);
+ } while (ret == -ETIMEDOUT);
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Handle reconnection request */
+ if (byte == INIT_BYTE) {
+ *command = byte;
+ return 0;
+ }
+
+ for (count = 0U; count < ARRAY_SIZE(command_tab); count++) {
+ if (command_tab[count] == byte) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ VERBOSE("UART: Command unknown (byte=0x%x)\n", byte);
+ return -EPROTO;
+ }
+
+ ret = uart_read_8(&xor);
+ if (ret != 0) {
+ return ret;
+ }
+ if ((byte ^ xor) != 0xFF) {
+ VERBOSE("UART: Command XOR check fail (byte=0x%x, xor=0x%x)\n",
+ byte, xor);
+ return -EPROTO;
+ }
+
+ *command = byte;
+
+ return 0;
+}
+
+static int get_cmd_command(void)
+{
+ const uint8_t msg[2] = {
+ sizeof(command_tab), /* Length of data - 1 */
+ USART_BL_VERSION
+ };
+ int ret;
+
+ ret = uart_write(msg, sizeof(msg));
+ if (ret != 0) {
+ return ret;
+ }
+
+ return uart_write(command_tab, sizeof(command_tab));
+}
+
+static int get_version_command(void)
+{
+ return uart_write_8(STM32_TF_VERSION);
+}
+
+static int get_id_command(void)
+{
+ uint8_t msg[3] = {
+ sizeof(msg) - 1 /* Length of data - 1 */
+ };
+ uint32_t chip_id = stm32mp_get_chip_dev_id();
+
+ be16enc(&msg[1], chip_id);
+
+ return uart_write(msg, sizeof(msg));
+}
+
+static int uart_send_phase(uint32_t address)
+{
+ int ret;
+ uint8_t msg_size = 5U; /* Length of data - 1 */
+ uint8_t error_size = 0U;
+
+ /* Additional information only for RESET phase */
+ if (handle.phase == PHASE_RESET) {
+ error_size = strnlen((char *)&handle.error, sizeof(handle.error));
+ }
+ ret = uart_write_8(msg_size + error_size);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Send the ID of next partition */
+ ret = uart_write_8(handle.phase);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Destination address */
+ ret = uart_write_32(address);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = uart_write_8(error_size);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Additional information: message error */
+ if (error_size > 0U) {
+ ret = uart_write(handle.error, error_size);
+ }
+
+ return ret;
+}
+
+static int uart_download_part(void)
+{
+ uint8_t operation = 0U;
+ uint8_t xor;
+ uint8_t byte = 0U;
+ uint32_t packet_number = 0U;
+ uint32_t packet_size = 0U;
+ uint32_t i = 0U;
+ int ret;
+
+ /* Get operation number */
+ ret = uart_read_8(&operation);
+ if (ret != 0) {
+ return ret;
+ }
+
+ xor = operation;
+
+ /* Get packet number */
+ for (i = 3U; i != 0U; i--) {
+ ret = uart_read_8(&byte);
+ if (ret != 0) {
+ return ret;
+ }
+
+ xor ^= byte;
+ packet_number = (packet_number << 8) | byte;
+ }
+
+ if (packet_number != handle.packet) {
+ WARN("UART: Bad packet number receive: %u, expected %u\n",
+ packet_number, handle.packet);
+ return -EPROTO;
+ }
+
+ /* Checksum */
+ ret = uart_read_8(&byte);
+ if (ret != 0) {
+ return ret;
+ }
+ if (xor != byte) {
+ VERBOSE("UART: Download Command checksum xor: %x, received %x\n",
+ xor, byte);
+ return -EPROTO;
+ }
+
+ ret = uart_send_result(ACK_BYTE);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = uart_read_8(&byte);
+ if (ret != 0) {
+ return ret;
+ }
+ xor = byte;
+ packet_size = byte + 1U;
+ if (handle.len < packet_size) {
+ STM32PROG_ERROR("Download overflow at %p\n", handle.addr + packet_size);
+ return 0;
+ }
+
+ for (i = 0U; i < packet_size; i++) {
+ ret = uart_read_8(&byte);
+ if (ret != 0) {
+ return ret;
+ }
+
+ *(handle.addr + i) = byte;
+ xor ^= byte;
+ }
+
+ /* Checksum */
+ ret = uart_read_8(&byte) != 0;
+ if (ret != 0) {
+ return ret;
+ }
+ if (xor != byte) {
+ VERBOSE("UART: Download Data checksum xor: %x, received %x\n",
+ xor, byte);
+ return -EPROTO;
+ }
+
+ /* Packet treated */
+ handle.packet++;
+ handle.addr += packet_size;
+ handle.len -= packet_size;
+
+ return 0;
+}
+
+static int uart_start_cmd(uintptr_t buffer)
+{
+ uint8_t byte = 0U;
+ uint8_t xor = 0U;
+ uint32_t i;
+ uint32_t start_address = 0U;
+ int ret;
+
+ /* Get address */
+ for (i = 4U; i != 0U; i--) {
+ ret = uart_read_8(&byte);
+ if (ret != 0U) {
+ return ret;
+ }
+
+ xor ^= byte;
+ start_address = (start_address << 8) | byte;
+ }
+
+ /* Checksum */
+ ret = uart_read_8(&byte);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (xor != byte) {
+ VERBOSE("UART: Start Command checksum xor: %x, received %x\n",
+ xor, byte);
+ return -EPROTO;
+ }
+
+ if (start_address != UNDEFINED_DOWN_ADDR) {
+ STM32PROG_ERROR("Invalid start at %x, for phase %u\n",
+ start_address, handle.phase);
+ return 0;
+ }
+
+ if (!is_valid_header((fip_toc_header_t *)buffer)) {
+ STM32PROG_ERROR("FIP Header check failed %lx, for phase %u\n",
+ buffer, handle.phase);
+ return -EIO;
+ }
+ VERBOSE("FIP header looks OK.\n");
+
+ return 0;
+}
+
+static int uart_read(uint8_t id, uintptr_t buffer, size_t length)
+{
+ bool start_done = false;
+ int ret;
+ uint8_t command = 0U;
+
+ handle.phase = id;
+ handle.packet = 0U;
+ handle.addr = (uint8_t *)buffer;
+ handle.len = length;
+
+ INFO("UART: read phase %u at 0x%lx size 0x%x\n",
+ id, buffer, length);
+ while (!start_done) {
+ ret = uart_receive_command(&command);
+ if (ret != 0) {
+ /* Delay to wait STM32CubeProgrammer end of transmission */
+ mdelay(3);
+
+ ret = uart_send_result(NACK_BYTE);
+ if (ret != 0U) {
+ return ret;
+ }
+
+ continue;
+ }
+
+ uart_send_result(ACK_BYTE);
+
+ switch (command) {
+ case INIT_BYTE:
+ INFO("UART: Connected\n");
+ /* Nothing to do */
+ continue;
+
+ case GET_CMD_COMMAND:
+ ret = get_cmd_command();
+ break;
+
+ case GET_VER_COMMAND:
+ ret = get_version_command();
+ break;
+
+ case GET_ID_COMMAND:
+ ret = get_id_command();
+ break;
+
+ case PHASE_COMMAND:
+ ret = uart_send_phase((uint32_t)buffer);
+ if ((ret == 0) && (handle.phase == PHASE_RESET)) {
+ start_done = true;
+ INFO("UART: Reset\n");
+ }
+ break;
+
+ case DOWNLOAD_COMMAND:
+ ret = uart_download_part();
+ break;
+
+ case START_COMMAND:
+ ret = uart_start_cmd(buffer);
+ if ((ret == 0) && (handle.phase == id)) {
+ INFO("UART: Start phase %u\n", handle.phase);
+ start_done = true;
+ }
+ break;
+
+ default:
+ WARN("UART: Unknown command\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret == 0) {
+ ret = uart_send_result(ACK_BYTE);
+ } else {
+ ret = uart_send_result(NACK_BYTE);
+ }
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* Init UART: 115200, 8bit 1stop parity even and enable FIFO mode */
+const struct stm32_uart_init_s init = {
+ .baud_rate = STM32MP_UART_BAUDRATE,
+ .word_length = STM32_UART_WORDLENGTH_9B,
+ .stop_bits = STM32_UART_STOPBITS_1,
+ .parity = STM32_UART_PARITY_EVEN,
+ .hw_flow_control = STM32_UART_HWCONTROL_NONE,
+ .mode = STM32_UART_MODE_TX_RX,
+ .fifo_mode = STM32_UART_FIFOMODE_EN,
+};
+
+int stm32cubeprog_uart_load(uintptr_t instance, uintptr_t base, size_t len)
+{
+ int ret;
+
+ if (stm32_uart_init(&handle.uart, instance, &init) != 0) {
+ return -EIO;
+ }
+
+ /*
+ * The following NACK_BYTE is written because STM32CubeProgrammer has
+ * already sent its command before TF-A has reached this point, and
+ * because FIFO was not configured by BootROM.
+ * The byte in the UART_RX register is then the checksum and not the
+ * command. NACK_BYTE has to be written, so that the programmer will
+ * re-send the good command.
+ */
+ ret = uart_send_result(NACK_BYTE);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return uart_read(PHASE_SSBL, base, len);
+}
diff --git a/plat/st/common/stm32cubeprogrammer_usb.c b/plat/st/common/stm32cubeprogrammer_usb.c
new file mode 100644
index 0000000..75e8038
--- /dev/null
+++ b/plat/st/common/stm32cubeprogrammer_usb.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <tools_share/firmware_image_package.h>
+
+#include <stm32cubeprogrammer.h>
+#include <usb_dfu.h>
+
+/* Undefined download address */
+#define UNDEFINED_DOWN_ADDR 0xFFFFFFFF
+
+struct dfu_state {
+ uint8_t phase;
+ uintptr_t base;
+ size_t len;
+ uintptr_t address;
+ /* working buffer */
+ uint8_t buffer[UCHAR_MAX];
+};
+
+static struct dfu_state dfu_state;
+
+/* minimal size of Get Pḧase = offset for additionnl information */
+#define GET_PHASE_LEN 9
+
+#define DFU_ERROR(...) \
+ { \
+ ERROR(__VA_ARGS__); \
+ if (dfu->phase != PHASE_RESET) { \
+ snprintf((char *)&dfu->buffer[GET_PHASE_LEN], \
+ sizeof(dfu->buffer) - GET_PHASE_LEN, \
+ __VA_ARGS__); \
+ dfu->phase = PHASE_RESET; \
+ dfu->address = UNDEFINED_DOWN_ADDR; \
+ dfu->len = 0; \
+ } \
+ }
+
+static bool is_valid_header(fip_toc_header_t *header)
+{
+ if ((header->name == TOC_HEADER_NAME) && (header->serial_number != 0U)) {
+ return true;
+ }
+
+ return false;
+}
+
+static int dfu_callback_upload(uint8_t alt, uintptr_t *buffer, uint32_t *len,
+ void *user_data)
+{
+ int result = 0;
+ uint32_t length = 0;
+ struct dfu_state *dfu = (struct dfu_state *)user_data;
+
+ switch (usb_dfu_get_phase(alt)) {
+ case PHASE_CMD:
+ /* Get Pḧase */
+ dfu->buffer[0] = dfu->phase;
+ dfu->buffer[1] = (uint8_t)(dfu->address);
+ dfu->buffer[2] = (uint8_t)(dfu->address >> 8);
+ dfu->buffer[3] = (uint8_t)(dfu->address >> 16);
+ dfu->buffer[4] = (uint8_t)(dfu->address >> 24);
+ dfu->buffer[5] = 0x00;
+ dfu->buffer[6] = 0x00;
+ dfu->buffer[7] = 0x00;
+ dfu->buffer[8] = 0x00;
+ length = GET_PHASE_LEN;
+ if (dfu->phase == PHASE_FLASHLAYOUT &&
+ dfu->address == UNDEFINED_DOWN_ADDR) {
+ INFO("Send detach request\n");
+ dfu->buffer[length++] = 0x01;
+ }
+ if (dfu->phase == PHASE_RESET) {
+ /* error information is added by DFU_ERROR macro */
+ length += strnlen((char *)&dfu->buffer[GET_PHASE_LEN],
+ sizeof(dfu->buffer) - GET_PHASE_LEN)
+ - 1;
+ }
+ break;
+
+ default:
+ DFU_ERROR("phase ID :%i, alternate %i for phase %i\n",
+ dfu->phase, alt, usb_dfu_get_phase(alt));
+ result = -EIO;
+ break;
+ }
+
+ if (result == 0) {
+ *len = length;
+ *buffer = (uintptr_t)dfu->buffer;
+ }
+
+ return result;
+}
+
+static int dfu_callback_download(uint8_t alt, uintptr_t *buffer, uint32_t *len,
+ void *user_data)
+{
+ struct dfu_state *dfu = (struct dfu_state *)user_data;
+
+ if ((dfu->phase != usb_dfu_get_phase(alt)) ||
+ (dfu->address == UNDEFINED_DOWN_ADDR)) {
+ DFU_ERROR("phase ID :%i, alternate %i, address %x\n",
+ dfu->phase, alt, (uint32_t)dfu->address);
+ return -EIO;
+ }
+
+ VERBOSE("Download %d %lx %x\n", alt, dfu->address, *len);
+ *buffer = dfu->address;
+ dfu->address += *len;
+
+ if (dfu->address - dfu->base > dfu->len) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int dfu_callback_manifestation(uint8_t alt, void *user_data)
+{
+ struct dfu_state *dfu = (struct dfu_state *)user_data;
+
+ if (dfu->phase != usb_dfu_get_phase(alt)) {
+ ERROR("Manifestation phase ID :%i, alternate %i, address %lx\n",
+ dfu->phase, alt, dfu->address);
+ return -EIO;
+ }
+
+ INFO("phase ID :%i, Manifestation %d at %lx\n",
+ dfu->phase, alt, dfu->address);
+
+ switch (dfu->phase) {
+ case PHASE_SSBL:
+ if (!is_valid_header((fip_toc_header_t *)dfu->base)) {
+ DFU_ERROR("FIP Header check failed for phase %d\n", alt);
+ return -EIO;
+ }
+ VERBOSE("FIP header looks OK.\n");
+
+ /* Configure End with request detach */
+ dfu->phase = PHASE_FLASHLAYOUT;
+ dfu->address = UNDEFINED_DOWN_ADDR;
+ dfu->len = 0;
+ break;
+ default:
+ DFU_ERROR("Unknown phase\n");
+ }
+
+ return 0;
+}
+
+/* Open a connection to the USB device */
+static const struct usb_dfu_media usb_dfu_fops = {
+ .upload = dfu_callback_upload,
+ .download = dfu_callback_download,
+ .manifestation = dfu_callback_manifestation,
+};
+
+int stm32cubeprog_usb_load(struct usb_handle *usb_core_handle,
+ uintptr_t base,
+ size_t len)
+{
+ int ret;
+
+ usb_core_handle->user_data = (void *)&dfu_state;
+
+ INFO("DFU USB START...\n");
+ ret = usb_core_start(usb_core_handle);
+ if (ret != USBD_OK) {
+ return -EIO;
+ }
+
+ dfu_state.phase = PHASE_SSBL;
+ dfu_state.address = base;
+ dfu_state.base = base;
+ dfu_state.len = len;
+
+ ret = usb_dfu_loop(usb_core_handle, &usb_dfu_fops);
+ if (ret != USBD_OK) {
+ return -EIO;
+ }
+
+ INFO("DFU USB STOP...\n");
+ ret = usb_core_stop(usb_core_handle);
+ if (ret != USBD_OK) {
+ return -EIO;
+ }
+
+ return 0;
+}
diff --git a/plat/st/common/stm32mp_common.c b/plat/st/common/stm32mp_common.c
new file mode 100644
index 0000000..bb56bac
--- /dev/null
+++ b/plat/st/common/stm32mp_common.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_console.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/smccc.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#include <services/arm_arch_svc.h>
+
+#include <platform_def.h>
+
+#define HEADER_VERSION_MAJOR_MASK GENMASK(23, 16)
+#define RESET_TIMEOUT_US_1MS 1000U
+
+static console_t console;
+
+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;
+static uint16_t boot_itf_selected;
+
+void stm32mp_save_boot_ctx_address(uintptr_t address)
+{
+ boot_api_context_t *boot_context = (boot_api_context_t *)address;
+
+ boot_ctx_address = address;
+ boot_itf_selected = boot_context->boot_interface_selected;
+}
+
+uintptr_t stm32mp_get_boot_ctx_address(void)
+{
+ return boot_ctx_address;
+}
+
+uint16_t stm32mp_get_boot_itf_selected(void)
+{
+ return boot_itf_selected;
+}
+
+uintptr_t stm32mp_ddrctrl_base(void)
+{
+ return DDRCTRL_BASE;
+}
+
+uintptr_t stm32mp_ddrphyc_base(void)
+{
+ return DDRPHYC_BASE;
+}
+
+uintptr_t stm32mp_pwr_base(void)
+{
+ return PWR_BASE;
+}
+
+uintptr_t stm32mp_rcc_base(void)
+{
+ 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;
+}
+
+int stm32mp_map_ddr_non_cacheable(void)
+{
+ return mmap_add_dynamic_region(STM32MP_DDR_BASE, STM32MP_DDR_BASE,
+ STM32MP_DDR_MAX_SIZE,
+ MT_NON_CACHEABLE | MT_RW | MT_SECURE);
+}
+
+int stm32mp_unmap_ddr(void)
+{
+ return mmap_remove_dynamic_region(STM32MP_DDR_BASE,
+ STM32MP_DDR_MAX_SIZE);
+}
+
+int stm32_get_otp_index(const char *otp_name, uint32_t *otp_idx,
+ uint32_t *otp_len)
+{
+ assert(otp_name != NULL);
+ assert(otp_idx != NULL);
+
+ return dt_find_otp_name(otp_name, otp_idx, otp_len);
+}
+
+int stm32_get_otp_value(const char *otp_name, uint32_t *otp_val)
+{
+ uint32_t otp_idx;
+
+ assert(otp_name != NULL);
+ assert(otp_val != NULL);
+
+ if (stm32_get_otp_index(otp_name, &otp_idx, NULL) != 0) {
+ return -1;
+ }
+
+ if (stm32_get_otp_value_from_idx(otp_idx, otp_val) != 0) {
+ ERROR("BSEC: %s Read Error\n", otp_name);
+ return -1;
+ }
+
+ return 0;
+}
+
+int stm32_get_otp_value_from_idx(const uint32_t otp_idx, uint32_t *otp_val)
+{
+ uint32_t ret = BSEC_NOT_SUPPORTED;
+
+ assert(otp_val != NULL);
+
+#if defined(IMAGE_BL2)
+ ret = bsec_shadow_read_otp(otp_val, otp_idx);
+#elif defined(IMAGE_BL32)
+ ret = bsec_read_otp(otp_val, otp_idx);
+#else
+#error "Not supported"
+#endif
+ if (ret != BSEC_OK) {
+ ERROR("BSEC: idx=%u Read Error\n", otp_idx);
+ return -1;
+ }
+
+ return 0;
+}
+
+#if defined(IMAGE_BL2)
+static void reset_uart(uint32_t reset)
+{
+ int ret;
+
+ ret = stm32mp_reset_assert(reset, RESET_TIMEOUT_US_1MS);
+ if (ret != 0) {
+ panic();
+ }
+
+ udelay(2);
+
+ ret = stm32mp_reset_deassert(reset, RESET_TIMEOUT_US_1MS);
+ if (ret != 0) {
+ panic();
+ }
+
+ mdelay(1);
+}
+#endif
+
+static void set_console(uintptr_t base, uint32_t clk_rate)
+{
+ unsigned int console_flags;
+
+ if (console_stm32_register(base, clk_rate,
+ (uint32_t)STM32MP_UART_BAUDRATE, &console) == 0) {
+ panic();
+ }
+
+ console_flags = CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH |
+ CONSOLE_FLAG_TRANSLATE_CRLF;
+#if !defined(IMAGE_BL2) && defined(DEBUG)
+ console_flags |= CONSOLE_FLAG_RUNTIME;
+#endif
+
+ console_set_scope(&console, console_flags);
+}
+
+int stm32mp_uart_console_setup(void)
+{
+ struct dt_node_info dt_uart_info;
+ uint32_t clk_rate = 0U;
+ int result;
+ uint32_t boot_itf __unused;
+ uint32_t boot_instance __unused;
+
+ result = dt_get_stdout_uart_info(&dt_uart_info);
+
+ if ((result <= 0) ||
+ (dt_uart_info.status == DT_DISABLED)) {
+ return -ENODEV;
+ }
+
+#if defined(IMAGE_BL2)
+ if ((dt_uart_info.clock < 0) ||
+ (dt_uart_info.reset < 0)) {
+ return -ENODEV;
+ }
+#endif
+
+#if STM32MP_UART_PROGRAMMER || !defined(IMAGE_BL2)
+ stm32_get_boot_interface(&boot_itf, &boot_instance);
+
+ if ((boot_itf == BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART) &&
+ (get_uart_address(boot_instance) == dt_uart_info.base)) {
+ return -EACCES;
+ }
+#endif
+
+#if defined(IMAGE_BL2)
+ if (dt_set_stdout_pinctrl() != 0) {
+ return -ENODEV;
+ }
+
+ clk_enable((unsigned long)dt_uart_info.clock);
+
+ reset_uart((uint32_t)dt_uart_info.reset);
+
+ clk_rate = clk_get_rate((unsigned long)dt_uart_info.clock);
+#endif
+
+ set_console(dt_uart_info.base, clk_rate);
+
+ return 0;
+}
+
+#if STM32MP_EARLY_CONSOLE
+void stm32mp_setup_early_console(void)
+{
+#if defined(IMAGE_BL2) || STM32MP_RECONFIGURE_CONSOLE
+ plat_crash_console_init();
+#endif
+ set_console(STM32MP_DEBUG_USART_BASE, STM32MP_DEBUG_USART_CLK_FRQ);
+ NOTICE("Early console setup\n");
+}
+#endif /* STM32MP_EARLY_CONSOLE */
+
+/*****************************************************************************
+ * plat_is_smccc_feature_available() - This function checks whether SMCCC
+ * feature is availabile for platform.
+ * @fid: SMCCC function id
+ *
+ * Return SMC_ARCH_CALL_SUCCESS if SMCCC feature is available and
+ * SMC_ARCH_CALL_NOT_SUPPORTED otherwise.
+ *****************************************************************************/
+int32_t plat_is_smccc_feature_available(u_register_t fid)
+{
+ switch (fid) {
+ case SMCCC_ARCH_SOC_ID:
+ return SMC_ARCH_CALL_SUCCESS;
+ default:
+ return SMC_ARCH_CALL_NOT_SUPPORTED;
+ }
+}
+
+/* Get SOC version */
+int32_t plat_get_soc_version(void)
+{
+ uint32_t chip_id = stm32mp_get_chip_dev_id();
+ uint32_t manfid = SOC_ID_SET_JEP_106(JEDEC_ST_BKID, JEDEC_ST_MFID);
+
+ return (int32_t)(manfid | (chip_id & SOC_ID_IMPL_DEF_MASK));
+}
+
+/* Get SOC revision */
+int32_t plat_get_soc_revision(void)
+{
+ return (int32_t)(stm32mp_get_chip_version() & SOC_ID_REV_MASK);
+}
diff --git a/plat/st/common/stm32mp_crypto_lib.c b/plat/st/common/stm32mp_crypto_lib.c
new file mode 100644
index 0000000..d644242
--- /dev/null
+++ b/plat/st/common/stm32mp_crypto_lib.c
@@ -0,0 +1,661 @@
+/*
+ * Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <endian.h>
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/st/bsec.h>
+#include <drivers/st/stm32_hash.h>
+#include <drivers/st/stm32_pka.h>
+#include <drivers/st/stm32_rng.h>
+#include <drivers/st/stm32_saes.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <mbedtls/asn1.h>
+#include <mbedtls/md.h>
+#include <mbedtls/oid.h>
+#include <mbedtls/platform.h>
+#include <mbedtls/x509.h>
+#include <plat/common/platform.h>
+#include <tools_share/firmware_encrypted.h>
+
+#include <platform_def.h>
+
+#define CRYPTO_HASH_MAX_SIZE 32U
+#define CRYPTO_SIGN_MAX_SIZE 64U
+#define CRYPTO_PUBKEY_MAX_SIZE 64U
+#define CRYPTO_MAX_TAG_SIZE 16U
+
+/* brainpoolP256t1 OID is not defined in mbedTLS */
+#define OID_EC_GRP_BP256T1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x08"
+
+#if STM32MP_CRYPTO_ROM_LIB
+struct stm32mp_auth_ops {
+ uint32_t (*verify_signature)(uint8_t *hash_in, uint8_t *pubkey_in,
+ uint8_t *signature, uint32_t ecc_algo);
+};
+
+static struct stm32mp_auth_ops auth_ops;
+#endif
+
+static void crypto_lib_init(void)
+{
+ boot_api_context_t *boot_context __maybe_unused;
+ int ret;
+
+ NOTICE("TRUSTED_BOARD_BOOT support enabled\n");
+
+ ret = stm32_hash_register();
+ if (ret != 0) {
+ ERROR("HASH init (%d)\n", ret);
+ panic();
+ }
+
+ if (stm32mp_is_closed_device() || stm32mp_is_auth_supported()) {
+#if STM32MP_CRYPTO_ROM_LIB
+ boot_context = (boot_api_context_t *)stm32mp_get_boot_ctx_address();
+ auth_ops.verify_signature = boot_context->bootrom_ecdsa_verify_signature;
+#else
+ /* Use hardware peripherals */
+ if (stm32_rng_init() != 0) {
+ panic();
+ }
+
+ if (stm32_saes_driver_init() != 0) {
+ panic();
+ }
+
+ if (stm32_pka_init() != 0) {
+ panic();
+ }
+#endif
+ }
+}
+
+int get_plain_pk_from_asn1(void *pk_ptr, unsigned int pk_len, void **plain_pk,
+ unsigned int *len, int *pk_alg)
+{
+ int ret;
+ mbedtls_pk_context mbedtls_pk = {0};
+ unsigned char *p, *end;
+ mbedtls_asn1_buf alg_params = {0};
+ mbedtls_asn1_buf alg_oid = {0};
+
+ *plain_pk = NULL;
+ *len = 0U;
+
+ /* Parse the public key */
+ mbedtls_pk_init(&mbedtls_pk);
+ p = (unsigned char *)pk_ptr;
+ end = (unsigned char *)(p + pk_len);
+
+ ret = mbedtls_asn1_get_tag(&p, end, len,
+ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
+ if (ret != 0) {
+ return -EINVAL;
+ }
+
+ end = p + *len;
+ ret = mbedtls_asn1_get_alg(&p, end, &alg_oid, &alg_params);
+ if (ret != 0) {
+ VERBOSE("%s: mbedtls_asn1_get_alg (%d)\n", __func__, ret);
+ return -EINVAL;
+ }
+
+ if (pk_alg != NULL) {
+ if ((strlen(MBEDTLS_OID_EC_GRP_SECP256R1) == alg_params.len) &&
+ (memcmp(MBEDTLS_OID_EC_GRP_SECP256R1, alg_params.p, alg_params.len) == 0)) {
+ *pk_alg = BOOT_API_ECDSA_ALGO_TYPE_P256NIST;
+ } else if ((strlen(OID_EC_GRP_BP256T1) == alg_params.len) &&
+ (memcmp(OID_EC_GRP_BP256T1, alg_params.p, alg_params.len) == 0)) {
+ *pk_alg = BOOT_API_ECDSA_ALGO_TYPE_BRAINPOOL256;
+ } else {
+ ERROR("%s: Algorithm is not supported\n", __func__);
+ return -EINVAL;
+ }
+ }
+
+ ret = mbedtls_asn1_get_bitstring_null(&p, end, len);
+ if (ret != 0) {
+ VERBOSE("%s: mbedtls_asn1_get_bitstring_null (%d)\n", __func__, ret);
+ return -EINVAL;
+ }
+
+ /* We remove the ident (0x04) first byte. */
+ if ((*len < 1U) || (p[0] != MBEDTLS_ASN1_OCTET_STRING)) {
+ VERBOSE("%s: not expected len or tag\n", __func__);
+ return -EINVAL;
+ }
+
+ *len = *len - 1U;
+ *plain_pk = p + 1U;
+
+ return 0;
+}
+
+#if STM32MP_CRYPTO_ROM_LIB
+uint32_t verify_signature(uint8_t *hash_in, uint8_t *pubkey_in,
+ uint8_t *signature, uint32_t ecc_algo)
+{
+ int ret;
+
+ ret = mmap_add_dynamic_region(STM32MP_ROM_BASE, STM32MP_ROM_BASE,
+ STM32MP_ROM_SIZE_2MB_ALIGNED, MT_CODE | MT_SECURE);
+ if (ret != 0) {
+ VERBOSE("%s: mmap_add_dynamic_region (%d)\n", __func__, ret);
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ ret = auth_ops.verify_signature(hash_in, pubkey_in, signature, ecc_algo);
+
+ if (ret != BOOT_API_RETURN_OK) {
+ VERBOSE("%s: auth_ops.verify_sign (%d)\n", __func__, ret);
+ ret = CRYPTO_ERR_SIGNATURE;
+ } else {
+ ret = 0;
+ }
+
+ mmap_remove_dynamic_region(STM32MP_ROM_BASE, STM32MP_ROM_SIZE_2MB_ALIGNED);
+
+ return ret;
+}
+
+int plat_convert_pk(void *full_pk_ptr, unsigned int full_pk_len,
+ void **hashed_pk_ptr, unsigned int *hashed_pk_len)
+{
+ return get_plain_pk_from_asn1(full_pk_ptr, full_pk_len, hashed_pk_ptr, hashed_pk_len, NULL);
+}
+#else /* STM32MP_CRYPTO_ROM_LIB*/
+static uint32_t verify_signature(uint8_t *hash_in, uint8_t *pubkey_in,
+ uint8_t *signature, uint32_t ecc_algo)
+{
+ int ret = -1;
+ enum stm32_pka_ecdsa_curve_id cid;
+
+ switch (ecc_algo) {
+ case BOOT_API_ECDSA_ALGO_TYPE_P256NIST:
+#if PKA_USE_NIST_P256
+ cid = PKA_NIST_P256;
+ ret = 0;
+#else
+ WARN("%s nist_p256 requested but not included\n", __func__);
+#endif
+ break;
+ case BOOT_API_ECDSA_ALGO_TYPE_BRAINPOOL256:
+#if PKA_USE_BRAINPOOL_P256T1
+ cid = PKA_BRAINPOOL_P256T1;
+ ret = 0;
+#else
+ WARN("%s brainpool_p256t1 requested but not included\n", __func__);
+#endif
+ break;
+ default:
+ WARN("%s unexpected ecc_algo(%u)\n", __func__, ecc_algo);
+ break;
+ }
+
+ if (ret < 0) {
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ ret = stm32_pka_ecdsa_verif(hash_in,
+ BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES,
+ signature, BOOT_API_ECDSA_SIGNATURE_LEN_IN_BYTES / 2U,
+ signature + BOOT_API_ECDSA_SIGNATURE_LEN_IN_BYTES / 2U,
+ BOOT_API_ECDSA_SIGNATURE_LEN_IN_BYTES / 2U,
+ pubkey_in, BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES / 2U,
+ pubkey_in + BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES / 2U,
+ BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES / 2U, cid);
+ if (ret < 0) {
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ return 0;
+}
+
+int plat_convert_pk(void *full_pk_ptr, unsigned int full_pk_len,
+ void **hashed_pk_ptr, unsigned int *hashed_pk_len)
+{
+ static uint8_t st_pk[CRYPTO_PUBKEY_MAX_SIZE + sizeof(uint32_t)];
+ int ret;
+ void *plain_pk;
+ unsigned int len;
+ int curve_id;
+ uint32_t cid;
+
+ ret = get_plain_pk_from_asn1(full_pk_ptr, full_pk_len, &plain_pk, &len, &curve_id);
+ if ((ret != 0) || (len > CRYPTO_PUBKEY_MAX_SIZE)) {
+ return -EINVAL;
+ }
+
+ cid = curve_id; /* we want value of curve_id (1 or 2) in a uint32_t */
+
+ memcpy(st_pk, &cid, sizeof(cid));
+ memcpy(st_pk + sizeof(cid), plain_pk, len);
+
+ *hashed_pk_ptr = st_pk;
+ *hashed_pk_len = len + sizeof(cid);
+
+ return 0;
+}
+#endif /* STM32MP_CRYPTO_ROM_LIB */
+
+static int get_plain_digest_from_asn1(void *digest_ptr, unsigned int digest_len,
+ uint8_t **out, size_t *out_len, mbedtls_md_type_t *md_alg)
+{
+ int ret;
+ mbedtls_asn1_buf hash_oid, params;
+ size_t len;
+ unsigned char *p, *end;
+
+ *out = NULL;
+ *out_len = 0U;
+
+ /* Digest info should be an MBEDTLS_ASN1_SEQUENCE */
+ p = (unsigned char *)digest_ptr;
+ end = p + digest_len;
+ ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+ MBEDTLS_ASN1_SEQUENCE);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Get the hash algorithm */
+ ret = mbedtls_asn1_get_alg(&p, end, &hash_oid, &params);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = mbedtls_oid_get_md_alg(&hash_oid, md_alg);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Length of hash must match the algorithm's size */
+ if (len != BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES) {
+ return -1;
+ }
+
+ *out = p;
+ *out_len = len;
+
+ return 0;
+}
+
+static int crypto_verify_signature(void *data_ptr, unsigned int data_len,
+ void *sig_ptr, unsigned int sig_len,
+ void *sig_alg, unsigned int sig_alg_len,
+ void *pk_ptr, unsigned int pk_len)
+{
+ uint8_t image_hash[CRYPTO_HASH_MAX_SIZE] = {0};
+ uint8_t sig[CRYPTO_SIGN_MAX_SIZE];
+ uint8_t my_pk[CRYPTO_PUBKEY_MAX_SIZE];
+ int ret;
+ size_t len;
+ mbedtls_asn1_sequence seq;
+ mbedtls_asn1_sequence *cur;
+ unsigned char *p, *end;
+ int curve_id;
+ mbedtls_asn1_buf sig_oid, sig_params;
+ mbedtls_md_type_t md_alg;
+ mbedtls_pk_type_t pk_alg;
+ size_t bignum_len = sizeof(sig) / 2U;
+ unsigned int seq_num = 0U;
+
+ if (!stm32mp_is_closed_device() && !stm32mp_is_auth_supported()) {
+ return CRYPTO_SUCCESS;
+ }
+
+ /* Get pointers to signature OID and parameters */
+ p = (unsigned char *)sig_alg;
+ end = (unsigned char *)(p + sig_alg_len);
+ ret = mbedtls_asn1_get_alg(&p, end, &sig_oid, &sig_params);
+ if (ret != 0) {
+ VERBOSE("%s: mbedtls_asn1_get_alg (%d)\n", __func__, ret);
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ /* Get the actual signature algorithm (MD + PK) */
+ ret = mbedtls_oid_get_sig_alg(&sig_oid, &md_alg, &pk_alg);
+ if (ret != 0) {
+ VERBOSE("%s: mbedtls_oid_get_sig_alg (%d)\n", __func__, ret);
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ if ((md_alg != MBEDTLS_MD_SHA256) || (pk_alg != MBEDTLS_PK_ECDSA)) {
+ VERBOSE("%s: md_alg=%u pk_alg=%u\n", __func__, md_alg, pk_alg);
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ ret = get_plain_pk_from_asn1(pk_ptr, pk_len, &pk_ptr, &pk_len, &curve_id);
+ if (ret != 0) {
+ VERBOSE("%s: get_plain_pk_from_asn1 (%d)\n", __func__, ret);
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ /* We expect a known pk_len */
+ if (pk_len != sizeof(my_pk)) {
+ VERBOSE("%s: pk_len=%u sizeof(my_pk)=%zu)\n", __func__, pk_len, sizeof(my_pk));
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ /* Need to copy as auth_ops.verify_signature
+ * expects aligned public key.
+ */
+ memcpy(my_pk, pk_ptr, sizeof(my_pk));
+
+ /* Get the signature (bitstring) */
+ p = (unsigned char *)sig_ptr;
+ end = (unsigned char *)(p + sig_len);
+ ret = mbedtls_asn1_get_bitstring_null(&p, end, &len);
+ if (ret != 0) {
+ VERBOSE("%s: mbedtls_asn1_get_bitstring_null (%d)\n", __func__, ret);
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ /* Get r and s from sequence */
+ ret = mbedtls_asn1_get_sequence_of(&p, end, &seq, MBEDTLS_ASN1_INTEGER);
+ if (ret != 0) {
+ VERBOSE("%s: mbedtls_asn1_get_sequence_of (%d)\n", __func__, ret);
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ /* We expect only 2 integers (r and s) from the sequence */
+ if (seq.next->next != NULL) {
+ cur = seq.next;
+ mbedtls_asn1_sequence *next;
+
+ VERBOSE("%s: nb seq != 2\n", __func__);
+ /* Free all the sequences */
+ while (cur != NULL) {
+ next = cur->next;
+ mbedtls_free(cur);
+ cur = next;
+ }
+
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ /*
+ * ECDSA signatures are composed of a tuple (R,S) where R and S are between 0 and n.
+ * This means that the R and S can have a maximum of 32 each, but can also be smaller.
+ * Also seen the integer sequence may (sometime) start with 0x00 as MSB, but we can only
+ * manage exactly 2*32 bytes, we remove this higher byte if there are not 00,
+ * we will fail either.
+ */
+ cur = &seq;
+ memset(sig, 0U, sizeof(sig));
+
+ while (cur != NULL) {
+ size_t skip = 0U;
+ size_t seek = seq_num * bignum_len;
+
+ if (cur->buf.len > bignum_len) {
+ /* Remove extra 0x00 bytes */
+ skip = cur->buf.len - bignum_len;
+ } else if (cur->buf.len < bignum_len) {
+ /* Add padding to match HW required size */
+ seek += (bignum_len % cur->buf.len);
+ }
+
+ if (seek + cur->buf.len > sizeof(sig) + skip) {
+ panic();
+ }
+
+ memcpy(sig + seek, cur->buf.p + skip, cur->buf.len - skip);
+ cur = cur->next;
+ seq_num++;
+ }
+
+ /* Need to free allocated 'next' in mbedtls_asn1_get_sequence_of */
+ mbedtls_free(seq.next);
+
+ /* Compute hash for the data covered by the signature */
+ stm32_hash_init(HASH_SHA256);
+
+ ret = stm32_hash_final_update((uint8_t *)data_ptr, data_len, image_hash);
+ if (ret != 0) {
+ VERBOSE("%s: stm32_hash_final_update (%d)\n", __func__, ret);
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ return verify_signature(image_hash, my_pk, sig, curve_id);
+}
+
+static int crypto_verify_hash(void *data_ptr, unsigned int data_len,
+ void *digest_info_ptr,
+ unsigned int digest_info_len)
+{
+ int ret;
+ uint8_t calc_hash[BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES];
+ unsigned char *p;
+ mbedtls_md_type_t md_alg;
+ size_t len;
+
+ /* we receive an asn1 encapsulated digest, we flatten it */
+ ret = get_plain_digest_from_asn1(digest_info_ptr,
+ digest_info_len, &p, &len,
+ &md_alg);
+ if ((ret != 0) || (md_alg != MBEDTLS_MD_SHA256) || (len != sizeof(calc_hash))) {
+ return CRYPTO_ERR_HASH;
+ }
+
+ digest_info_ptr = p;
+ digest_info_len = len;
+
+ stm32_hash_init(HASH_SHA256);
+
+ ret = stm32_hash_final_update(data_ptr, data_len, calc_hash);
+ if (ret != 0) {
+ VERBOSE("%s: hash failed\n", __func__);
+ return CRYPTO_ERR_HASH;
+ }
+
+ ret = memcmp(calc_hash, digest_info_ptr, digest_info_len);
+ if (ret != 0) {
+ VERBOSE("%s: not expected digest\n", __func__);
+ ret = CRYPTO_ERR_HASH;
+ }
+
+ return ret;
+}
+
+#if !defined(DECRYPTION_SUPPORT_none)
+static int derive_key(uint8_t *key, size_t *key_len, size_t len,
+ unsigned int *flags, const uint8_t *img_id, size_t img_id_len)
+{
+ size_t i, j;
+
+ assert(*key_len >= 32U);
+
+ /*
+ * Not a real derivation yet
+ *
+ * But we expect a 32 bytes key, and OTP is only 16 bytes
+ * => duplicate.
+ */
+ for (i = 0U, j = len; j < 32U;
+ i += sizeof(uint32_t), j += sizeof(uint32_t)) {
+ memcpy(key + j, key + i, sizeof(uint32_t));
+ }
+
+ *key_len = 32U;
+ /* Variable 'key' store a real key */
+ *flags = 0U;
+
+ return 0;
+}
+
+int plat_get_enc_key_info(enum fw_enc_status_t fw_enc_status, uint8_t *key,
+ size_t *key_len, unsigned int *flags,
+ const uint8_t *img_id, size_t img_id_len)
+{
+ uint32_t otp_idx;
+ uint32_t otp_len;
+ size_t read_len;
+ size_t i;
+
+ if (fw_enc_status == FW_ENC_WITH_BSSK) {
+ return -EINVAL;
+ }
+
+ if (stm32_get_otp_index(ENCKEY_OTP, &otp_idx, &otp_len) != 0) {
+ VERBOSE("%s: get %s index error\n", __func__, ENCKEY_OTP);
+ return -EINVAL;
+ }
+
+ if (otp_len > (*key_len * CHAR_BIT)) {
+ VERBOSE("%s: length Error otp_len=%u key_len=%u\n", __func__,
+ otp_len, *key_len * CHAR_BIT);
+ return -EINVAL;
+ }
+
+ read_len = otp_len / CHAR_BIT;
+ assert(read_len % sizeof(uint32_t) == 0);
+
+ for (i = 0U; i < read_len / sizeof(uint32_t); i++) {
+ uint32_t tmp;
+ uint32_t otp_val;
+
+ if (stm32_get_otp_value_from_idx(otp_idx + i, &otp_val) != 0) {
+ zeromem(key, *key_len);
+ VERBOSE("%s: unable to read from otp\n", __func__);
+ return -EINVAL;
+ }
+
+ tmp = bswap32(otp_val);
+ memcpy(key + i * sizeof(uint32_t), &tmp, sizeof(tmp));
+ }
+
+ /* Now we have the OTP values in key till read_len */
+
+ if (derive_key(key, key_len, read_len, flags, img_id,
+ img_id_len) != 0) {
+ zeromem(key, *key_len);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static enum stm32_saes_key_selection select_key(unsigned int key_flags)
+{
+ if ((key_flags & ENC_KEY_IS_IDENTIFIER) != 0U) {
+ panic();
+ }
+
+ /* Use the provided key buffer */
+ return STM32_SAES_KEY_SOFT;
+}
+
+static int stm32_decrypt_aes_gcm(void *data, size_t data_len,
+ const void *key, unsigned int key_len,
+ unsigned int key_flags,
+ const void *iv, unsigned int iv_len,
+ const void *tag, unsigned int tag_len)
+{
+ int ret;
+ struct stm32_saes_context ctx;
+ unsigned char tag_buf[CRYPTO_MAX_TAG_SIZE];
+ enum stm32_saes_key_selection key_mode;
+ unsigned int diff = 0U;
+ unsigned int i;
+
+ key_mode = select_key(key_flags);
+
+ ret = stm32_saes_init(&ctx, true, STM32_SAES_MODE_GCM, key_mode, key,
+ key_len, iv, iv_len);
+ if (ret != 0) {
+ return CRYPTO_ERR_INIT;
+ }
+
+ ret = stm32_saes_update_assodata(&ctx, true, NULL, 0U);
+ if (ret != 0) {
+ return CRYPTO_ERR_DECRYPTION;
+ }
+
+ ret = stm32_saes_update_load(&ctx, true, data, data, data_len);
+ if (ret != 0) {
+ return CRYPTO_ERR_DECRYPTION;
+ }
+
+ ret = stm32_saes_final(&ctx, tag_buf, sizeof(tag_buf));
+ if (ret != 0) {
+ return CRYPTO_ERR_DECRYPTION;
+ }
+
+ /* Check tag in "constant-time" */
+ for (i = 0U; i < tag_len; i++) {
+ diff |= ((const unsigned char *)tag)[i] ^ tag_buf[i];
+ }
+
+ if (diff != 0U) {
+ return CRYPTO_ERR_DECRYPTION;
+ }
+
+ return CRYPTO_SUCCESS;
+}
+
+/*
+ * Authenticated decryption of an image
+ *
+ */
+static int crypto_auth_decrypt(enum crypto_dec_algo dec_algo, void *data_ptr, size_t len,
+ const void *key, unsigned int key_len, unsigned int key_flags,
+ const void *iv, unsigned int iv_len, const void *tag,
+ unsigned int tag_len)
+{
+ int rc = -1;
+ uint32_t real_iv[4];
+
+ switch (dec_algo) {
+ case CRYPTO_GCM_DECRYPT:
+ /*
+ * GCM expect a Nonce
+ * The AES IV is the nonce (a uint32_t[3])
+ * then a counter (a uint32_t big endian)
+ * The counter starts at 2.
+ */
+ memcpy(real_iv, iv, iv_len);
+ real_iv[3] = htobe32(0x2U);
+
+ rc = stm32_decrypt_aes_gcm(data_ptr, len, key, key_len, key_flags,
+ real_iv, sizeof(real_iv), tag, tag_len);
+ break;
+ default:
+ rc = CRYPTO_ERR_DECRYPTION;
+ break;
+ }
+
+ if (rc != 0) {
+ return rc;
+ }
+
+ return CRYPTO_SUCCESS;
+}
+
+REGISTER_CRYPTO_LIB("stm32_crypto_lib",
+ crypto_lib_init,
+ crypto_verify_signature,
+ crypto_verify_hash,
+ crypto_auth_decrypt);
+
+#else /* No decryption support */
+REGISTER_CRYPTO_LIB("stm32_crypto_lib",
+ crypto_lib_init,
+ crypto_verify_signature,
+ crypto_verify_hash,
+ NULL);
+
+#endif
diff --git a/plat/st/common/stm32mp_dt.c b/plat/st/common/stm32mp_dt.c
new file mode 100644
index 0000000..c9efeb5
--- /dev/null
+++ b/plat/st/common/stm32mp_dt.c
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/st/regulator.h>
+#include <drivers/st/stm32_gpio.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+#include <stm32mp_dt.h>
+
+static void *fdt;
+
+/*******************************************************************************
+ * 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(uintptr_t dt_addr)
+{
+ int ret;
+
+ ret = fdt_check_header((void *)dt_addr);
+ if (ret == 0) {
+ fdt = (void *)dt_addr;
+ }
+
+ 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 == NULL) {
+ return 0;
+ }
+
+ *fdt_addr = fdt;
+
+ return 1;
+}
+
+/*******************************************************************************
+ * 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;
+ const char *cchar;
+
+ cchar = fdt_getprop(fdt, node, "status", NULL);
+ if ((cchar == NULL) ||
+ (strncmp(cchar, "okay", strlen("okay")) == 0)) {
+ status |= DT_NON_SECURE;
+ }
+
+ cchar = fdt_getprop(fdt, node, "secure-status", NULL);
+ if (cchar == NULL) {
+ if (status == DT_NON_SECURE) {
+ status |= DT_SECURE;
+ }
+ } else if (strncmp(cchar, "okay", strlen("okay")) == 0) {
+ status |= DT_SECURE;
+ }
+
+ return status;
+}
+
+#if ENABLE_ASSERTIONS
+/*******************************************************************************
+ * This function returns the address cells from the node parent.
+ * Returns:
+ * - #address-cells value if success.
+ * - invalid value if error.
+ * - a default value if undefined #address-cells property as per libfdt
+ * implementation.
+ ******************************************************************************/
+static int fdt_get_node_parent_address_cells(int node)
+{
+ int parent;
+
+ parent = fdt_parent_offset(fdt, node);
+ if (parent < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ return fdt_address_cells(fdt, parent);
+}
+#endif
+
+/*******************************************************************************
+ * 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 = fdt_get_stdout_node_offset(fdt);
+ 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;
+
+ assert(fdt_get_node_parent_address_cells(node) == 1);
+
+ cuint = fdt_getprop(fdt, node, "reg", NULL);
+ if (cuint != NULL) {
+ info->base = fdt32_to_cpu(*cuint);
+ } 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 = fdt_get_stdout_node_offset(fdt);
+ if (node < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ dt_fill_device_info(info, node);
+
+ return node;
+}
+
+/*******************************************************************************
+ * This function returns the node offset matching compatible string in the DT,
+ * and also matching the reg property with the given address.
+ * Returns value on success, and error value on failure.
+ ******************************************************************************/
+int dt_match_instance_by_compatible(const char *compatible, uintptr_t address)
+{
+ int node;
+
+ fdt_for_each_compatible_node(fdt, node, compatible) {
+ const fdt32_t *cuint;
+
+ assert(fdt_get_node_parent_address_cells(node) == 1);
+
+ cuint = fdt_getprop(fdt, node, "reg", NULL);
+ if (cuint == NULL) {
+ continue;
+ }
+
+ if ((uintptr_t)fdt32_to_cpu(*cuint) == address) {
+ return node;
+ }
+ }
+
+ return -FDT_ERR_NOTFOUND;
+}
+
+/*******************************************************************************
+ * This function gets DDR size information from the DT.
+ * Returns value in bytes on success, and 0 on failure.
+ ******************************************************************************/
+uint32_t dt_get_ddr_size(void)
+{
+ static uint32_t size;
+ int node;
+
+ if (size != 0U) {
+ return size;
+ }
+
+ 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;
+ }
+
+ size = fdt_read_uint32_default(fdt, node, "st,mem-size", 0U);
+
+ flush_dcache_range((uintptr_t)&size, sizeof(uint32_t));
+
+ return size;
+}
+
+/*******************************************************************************
+ * 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)
+{
+ struct rdev *regul = dt_get_vdd_regulator();
+ uint16_t min;
+
+ if (regul == NULL) {
+ return 0;
+ }
+
+ regulator_get_range(regul, &min, NULL);
+
+ return (uint32_t)min * 1000U;
+}
+
+/*******************************************************************************
+ * This function retrieves VDD supply regulator from DT.
+ * Returns an rdev taken from supply node, NULL otherwise.
+ ******************************************************************************/
+struct rdev *dt_get_vdd_regulator(void)
+{
+ int node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
+
+ if (node < 0) {
+ return NULL;
+ }
+
+ return regulator_get_by_supply_name(fdt, node, "vdd");
+}
+
+/*******************************************************************************
+ * This function retrieves CPU supply regulator from DT.
+ * Returns an rdev taken from supply node, NULL otherwise.
+ ******************************************************************************/
+struct rdev *dt_get_cpu_regulator(void)
+{
+ int node = fdt_path_offset(fdt, "/cpus/cpu@0");
+
+ if (node < 0) {
+ return NULL;
+ }
+
+ return regulator_get_by_supply_name(fdt, node, "cpu");
+}
+
+/*******************************************************************************
+ * 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);
+}
+
+/*******************************************************************************
+ * dt_find_otp_name: get OTP ID and length in DT.
+ * name: sub-node name to look up.
+ * otp: pointer to read OTP number or NULL.
+ * otp_len: pointer to read OTP length in bits or NULL.
+ * return value: 0 if no error, an FDT error value otherwise.
+ ******************************************************************************/
+int dt_find_otp_name(const char *name, uint32_t *otp, uint32_t *otp_len)
+{
+ int node;
+ int len;
+ const fdt32_t *cuint;
+
+ if ((name == NULL) || (otp == NULL)) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ node = fdt_node_offset_by_compatible(fdt, -1, DT_BSEC_COMPAT);
+ if (node < 0) {
+ return node;
+ }
+
+ node = fdt_subnode_offset(fdt, node, name);
+ if (node < 0) {
+ ERROR("nvmem node %s not found\n", name);
+ return node;
+ }
+
+ cuint = fdt_getprop(fdt, node, "reg", &len);
+ if ((cuint == NULL) || (len != (2 * (int)sizeof(uint32_t)))) {
+ ERROR("Malformed nvmem node %s: ignored\n", name);
+ return -FDT_ERR_BADVALUE;
+ }
+
+ if (fdt32_to_cpu(*cuint) % sizeof(uint32_t)) {
+ ERROR("Misaligned nvmem %s element: ignored\n", name);
+ return -FDT_ERR_BADVALUE;
+ }
+
+ if (otp != NULL) {
+ *otp = fdt32_to_cpu(*cuint) / sizeof(uint32_t);
+ }
+
+ if (otp_len != NULL) {
+ cuint++;
+ *otp_len = fdt32_to_cpu(*cuint) * CHAR_BIT;
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ * This function gets the pin count for a GPIO bank based from the FDT.
+ * It also checks node consistency.
+ ******************************************************************************/
+int fdt_get_gpio_bank_pin_count(unsigned int bank)
+{
+ int pinctrl_node;
+ int node;
+ uint32_t bank_offset;
+
+ pinctrl_node = stm32_get_gpio_bank_pinctrl_node(fdt, bank);
+ if (pinctrl_node < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ bank_offset = stm32_get_gpio_bank_offset(bank);
+
+ fdt_for_each_subnode(node, fdt, pinctrl_node) {
+ const fdt32_t *cuint;
+ int pin_count;
+ int len;
+ int i;
+
+ if (fdt_getprop(fdt, node, "gpio-controller", NULL) == NULL) {
+ continue;
+ }
+
+ cuint = fdt_getprop(fdt, node, "reg", NULL);
+ if (cuint == NULL) {
+ continue;
+ }
+
+ if (fdt32_to_cpu(*cuint) != bank_offset) {
+ continue;
+ }
+
+ if (fdt_get_status(node) == DT_DISABLED) {
+ return 0;
+ }
+
+ /* Parse gpio-ranges with its 4 parameters */
+ cuint = fdt_getprop(fdt, node, "gpio-ranges", &len);
+ len /= sizeof(*cuint);
+ if ((len % 4) != 0) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ /* Get the last defined gpio line (offset + nb of pins) */
+ pin_count = fdt32_to_cpu(*(cuint + 1)) + fdt32_to_cpu(*(cuint + 3));
+ for (i = 0; i < len / 4; i++) {
+ pin_count = MAX(pin_count, (int)(fdt32_to_cpu(*(cuint + 1)) +
+ fdt32_to_cpu(*(cuint + 3))));
+ cuint += 4;
+ }
+
+ return pin_count;
+ }
+
+ return 0;
+}
diff --git a/plat/st/common/stm32mp_fconf_io.c b/plat/st/common/stm32mp_fconf_io.c
new file mode 100644
index 0000000..0b6cc78
--- /dev/null
+++ b/plat/st/common/stm32mp_fconf_io.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/mmc.h>
+#include <lib/fconf/fconf.h>
+#include <lib/object_pool.h>
+#include <libfdt.h>
+#include <tools_share/firmware_image_package.h>
+
+#include <platform_def.h>
+#include <stm32mp_efi.h>
+#include <stm32mp_fconf_getter.h>
+#include <stm32mp_io_storage.h>
+
+#if STM32MP_SDMMC || STM32MP_EMMC
+static io_block_spec_t gpt_block_spec = {
+ .offset = 0U,
+ .length = 34U * MMC_BLOCK_SIZE, /* Size of GPT table */
+};
+#endif
+
+#if (STM32MP_SDMMC || STM32MP_EMMC) && PSA_FWU_SUPPORT
+io_block_spec_t metadata_block_spec = {
+ .offset = 0, /* To be filled at runtime */
+ .length = 0, /* To be filled at runtime */
+};
+#endif /* (STM32MP_SDMMC || STM32MP_EMMC) && PSA_FWU_SUPPORT */
+
+/* By default, STM32 platforms load images from the FIP */
+struct plat_io_policy policies[MAX_NUMBER_IDS] = {
+ [FIP_IMAGE_ID] = {
+ .dev_handle = &storage_dev_handle,
+ .image_spec = (uintptr_t)&image_block_spec,
+ .img_type_guid = STM32MP_FIP_GUID,
+ .check = open_storage
+ },
+#ifndef DECRYPTION_SUPPORT_none
+ [ENC_IMAGE_ID] = {
+ .dev_handle = &fip_dev_handle,
+ .image_spec = (uintptr_t)NULL,
+ .img_type_guid = NULL_GUID,
+ .check = open_fip
+ },
+#endif
+#if STM32MP_SDMMC || STM32MP_EMMC
+ [GPT_IMAGE_ID] = {
+ .dev_handle = &storage_dev_handle,
+ .image_spec = (uintptr_t)&gpt_block_spec,
+ .img_type_guid = NULL_GUID,
+ .check = open_storage
+ },
+#endif
+#if (STM32MP_SDMMC || STM32MP_EMMC) && PSA_FWU_SUPPORT
+ [FWU_METADATA_IMAGE_ID] = {
+ .dev_handle = &storage_dev_handle,
+ .image_spec = (uintptr_t)&metadata_block_spec,
+ .img_type_guid = NULL_GUID,
+ .check = open_storage
+ },
+ [BKUP_FWU_METADATA_IMAGE_ID] = {
+ .dev_handle = &storage_dev_handle,
+ .image_spec = (uintptr_t)&metadata_block_spec,
+ .img_type_guid = NULL_GUID,
+ .check = open_storage
+ },
+#endif /* (STM32MP_SDMMC || STM32MP_EMMC) && PSA_FWU_SUPPORT */
+};
+
+#define DEFAULT_UUID_NUMBER U(7)
+
+#if TRUSTED_BOARD_BOOT
+#define TBBR_UUID_NUMBER U(6)
+#else
+#define TBBR_UUID_NUMBER U(0)
+#endif
+
+#define FCONF_ST_IO_UUID_NUMBER (DEFAULT_UUID_NUMBER + \
+ TBBR_UUID_NUMBER)
+
+static io_uuid_spec_t fconf_stm32mp_uuids[FCONF_ST_IO_UUID_NUMBER];
+static OBJECT_POOL_ARRAY(fconf_stm32mp_uuids_pool, fconf_stm32mp_uuids);
+
+struct policies_load_info {
+ unsigned int image_id;
+ const char *name;
+};
+
+/* image id to property name table */
+static const struct policies_load_info load_info[FCONF_ST_IO_UUID_NUMBER] = {
+ {FW_CONFIG_ID, "fw_cfg_uuid"},
+ {BL32_IMAGE_ID, "bl32_uuid"},
+ {BL32_EXTRA1_IMAGE_ID, "bl32_extra1_uuid"},
+ {BL32_EXTRA2_IMAGE_ID, "bl32_extra2_uuid"},
+ {BL33_IMAGE_ID, "bl33_uuid"},
+ {HW_CONFIG_ID, "hw_cfg_uuid"},
+ {TOS_FW_CONFIG_ID, "tos_fw_cfg_uuid"},
+#if TRUSTED_BOARD_BOOT
+ {STM32MP_CONFIG_CERT_ID, "stm32mp_cfg_cert_uuid"},
+ {TRUSTED_KEY_CERT_ID, "t_key_cert_uuid"},
+ {TRUSTED_OS_FW_KEY_CERT_ID, "tos_fw_key_cert_uuid"},
+ {NON_TRUSTED_FW_KEY_CERT_ID, "nt_fw_key_cert_uuid"},
+ {TRUSTED_OS_FW_CONTENT_CERT_ID, "tos_fw_content_cert_uuid"},
+ {NON_TRUSTED_FW_CONTENT_CERT_ID, "nt_fw_content_cert_uuid"},
+#endif /* TRUSTED_BOARD_BOOT */
+};
+
+int fconf_populate_stm32mp_io_policies(uintptr_t config)
+{
+ int node;
+ unsigned int i;
+
+ /* As libfdt uses void *, we can't avoid this cast */
+ const void *dtb = (void *)config;
+
+ /* Assert the node offset point to "st,io-fip-handle" compatible property */
+ const char *compatible_str = "st,io-fip-handle";
+
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
+ if (node < 0) {
+ ERROR("FCONF: Can't find %s compatible in dtb\n", compatible_str);
+ return node;
+ }
+
+ /* Locate the uuid cells and read the value for all the load info uuid */
+ for (i = 0U; i < FCONF_ST_IO_UUID_NUMBER; i++) {
+ union uuid_helper_t uuid_helper;
+ io_uuid_spec_t *uuid_ptr;
+ int err;
+
+ uuid_ptr = pool_alloc(&fconf_stm32mp_uuids_pool);
+ err = fdtw_read_uuid(dtb, node, load_info[i].name, 16,
+ (uint8_t *)&uuid_helper);
+ if (err < 0) {
+ WARN("FCONF: Read cell failed for %s\n", load_info[i].name);
+ return err;
+ }
+
+ VERBOSE("FCONF: stm32mp-io_policies.%s cell found with value = "
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
+ load_info[i].name,
+ uuid_helper.uuid_struct.time_low[0], uuid_helper.uuid_struct.time_low[1],
+ uuid_helper.uuid_struct.time_low[2], uuid_helper.uuid_struct.time_low[3],
+ uuid_helper.uuid_struct.time_mid[0], uuid_helper.uuid_struct.time_mid[1],
+ uuid_helper.uuid_struct.time_hi_and_version[0],
+ uuid_helper.uuid_struct.time_hi_and_version[1],
+ uuid_helper.uuid_struct.clock_seq_hi_and_reserved,
+ uuid_helper.uuid_struct.clock_seq_low,
+ uuid_helper.uuid_struct.node[0], uuid_helper.uuid_struct.node[1],
+ uuid_helper.uuid_struct.node[2], uuid_helper.uuid_struct.node[3],
+ uuid_helper.uuid_struct.node[4], uuid_helper.uuid_struct.node[5]);
+
+ uuid_ptr->uuid = uuid_helper.uuid_struct;
+ policies[load_info[i].image_id].image_spec = (uintptr_t)uuid_ptr;
+ switch (load_info[i].image_id) {
+#if ENCRYPT_BL32 && !defined(DECRYPTION_SUPPORT_none)
+ case BL32_IMAGE_ID:
+ case BL32_EXTRA1_IMAGE_ID:
+ case BL32_EXTRA2_IMAGE_ID:
+ policies[load_info[i].image_id].dev_handle = &enc_dev_handle;
+ policies[load_info[i].image_id].check = open_enc_fip;
+ break;
+#endif
+ default:
+ policies[load_info[i].image_id].dev_handle = &fip_dev_handle;
+ policies[load_info[i].image_id].check = open_fip;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+FCONF_REGISTER_POPULATOR(TB_FW, stm32mp_io, fconf_populate_stm32mp_io_policies);
diff --git a/plat/st/common/stm32mp_trusted_boot.c b/plat/st/common/stm32mp_trusted_boot.c
new file mode 100644
index 0000000..051d6fc
--- /dev/null
+++ b/plat/st/common/stm32mp_trusted_boot.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <endian.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <common/debug.h>
+#include <common/tbbr/cot_def.h>
+#include <drivers/st/stm32_hash.h>
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_dyn_cfg_getter.h>
+#include <lib/fconf/fconf_tbbr_getter.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include <boot_api.h>
+#include <platform_def.h>
+
+#define HEADER_AND_EXT_TOTAL_SIZE 512
+
+static uint8_t der_sha256_header[] = {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60,
+ 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
+static uint8_t root_pk_hash[HASH_DER_LEN];
+
+static int copy_hash_from_otp(const char *otp_name, uint8_t *hash, size_t len)
+{
+ uint32_t otp_idx;
+ uint32_t otp_len;
+ size_t i;
+ bool valid = false;
+
+ assert(len % sizeof(uint32_t) == 0);
+
+ if (stm32_get_otp_index(otp_name, &otp_idx, &otp_len) != 0) {
+ VERBOSE("%s: get %s index error\n", __func__, otp_name);
+ return -EINVAL;
+ }
+ if (otp_len != (len * CHAR_BIT)) {
+ VERBOSE("%s: length Error\n", __func__);
+ return -EINVAL;
+ }
+
+ for (i = 0U; i < len / sizeof(uint32_t); i++) {
+ uint32_t tmp;
+ uint32_t otp_val;
+ uint32_t first;
+
+ if (stm32_get_otp_value_from_idx(otp_idx + i, &otp_val) != 0) {
+ VERBOSE("%s: unable to read from otp\n", __func__);
+ return -EINVAL;
+ }
+
+ tmp = bswap32(otp_val);
+ memcpy(hash + i * sizeof(uint32_t), &tmp, sizeof(tmp));
+
+ if (i == 0U) {
+ first = tmp;
+ }
+
+ /*
+ * Check if key hash values in OTP are 0 or 0xFFFFFFFFF
+ * programmed : Invalid Key
+ */
+ if (!stm32mp_is_closed_device() && !valid) {
+ if ((tmp != 0U) && (tmp != 0xFFFFFFFFU) && (tmp != first)) {
+ valid = true;
+ }
+ }
+ }
+
+ if (!stm32mp_is_closed_device() && !valid) {
+ return 0;
+ }
+
+ return len;
+}
+
+#if STM32_HEADER_VERSION_MAJOR == 1
+static int get_rotpk_hash(void *cookie, uint8_t *hash, size_t len)
+{
+ if (cookie != NULL) {
+ return -EINVAL;
+ }
+
+ return copy_hash_from_otp(PKH_OTP, hash, len);
+}
+#else
+static int get_rotpk_hash(void *cookie, uint8_t *hash, size_t len)
+{
+ int ret;
+ uint32_t pk_idx = 0U;
+ uint8_t calc_hash[BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES];
+ uint8_t otp_hash[BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES];
+ boot_api_image_header_t *hdr = (boot_api_image_header_t *)(SRAM3_BASE + SRAM3_SIZE -
+ HEADER_AND_EXT_TOTAL_SIZE);
+ boot_extension_header_t *ext_header = (boot_extension_header_t *)hdr->ext_header;
+ boot_ext_header_params_authentication_t *param;
+
+ if (cookie != NULL) {
+ return -EINVAL;
+ }
+
+ if (hdr->header_version != BOOT_API_HEADER_VERSION) {
+ VERBOSE("%s: unexpected header_version\n", __func__);
+ return -EINVAL;
+ }
+
+ param = (boot_ext_header_params_authentication_t *)ext_header->params;
+
+ pk_idx = param->pk_idx;
+
+ stm32_hash_init(HASH_SHA256);
+ ret = stm32_hash_final_update((uint8_t *)param->pk_hashes,
+ param->nb_pk * sizeof(boot_api_sha256_t), calc_hash);
+ if (ret != 0) {
+ VERBOSE("%s: hash failed\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = copy_hash_from_otp(PKH_OTP, otp_hash, len);
+ if (ret < 0) {
+ return -EINVAL;
+ }
+
+ if (ret != 0) {
+ ret = memcmp(calc_hash, otp_hash, sizeof(calc_hash));
+ if (ret != 0) {
+ VERBOSE("%s: not expected digest\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = sizeof(otp_hash);
+ }
+
+ memcpy(hash, param->pk_hashes[pk_idx], sizeof(otp_hash));
+
+ return ret;
+}
+#endif
+
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+ unsigned int *flags)
+{
+ size_t start_copy_idx = 0U;
+ int res;
+
+ memcpy(root_pk_hash, der_sha256_header, sizeof(der_sha256_header));
+ start_copy_idx = sizeof(der_sha256_header);
+
+ res = get_rotpk_hash(cookie, root_pk_hash + start_copy_idx,
+ BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES);
+ if (res < 0) {
+ return -EINVAL;
+ }
+
+ *key_len = HASH_DER_LEN;
+ *key_ptr = &root_pk_hash;
+ *flags = ROTPK_IS_HASH;
+
+ if ((res == 0) && !stm32mp_is_closed_device()) {
+ *flags |= ROTPK_NOT_DEPLOYED;
+ }
+
+ return 0;
+}
+
+int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
+{
+ *nv_ctr = mmio_read_32(TAMP_BASE + TAMP_COUNTR);
+
+ return 0;
+}
+
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+ while (mmio_read_32(TAMP_BASE + TAMP_COUNTR) != nv_ctr) {
+ mmio_write_32(TAMP_BASE + TAMP_COUNTR, 1U);
+ }
+
+ return 0;
+}
+
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+ assert(heap_addr != NULL);
+ assert(heap_size != NULL);
+
+#if STM32MP_USE_EXTERNAL_HEAP
+ /* Retrieve the already allocated heap's info from DTB */
+ *heap_addr = FCONF_GET_PROPERTY(tbbr, dyn_config, mbedtls_heap_addr);
+ *heap_size = FCONF_GET_PROPERTY(tbbr, dyn_config, mbedtls_heap_size);
+
+ /* We expect heap already statically mapped */
+
+ return 0;
+#else
+ return get_mbedtls_heap_helper(heap_addr, heap_size);
+#endif
+}
diff --git a/plat/st/common/usb_dfu.c b/plat/st/common/usb_dfu.c
new file mode 100644
index 0000000..8bb0994
--- /dev/null
+++ b/plat/st/common/usb_dfu.c
@@ -0,0 +1,538 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+
+#include <platform_def.h>
+#include <usb_dfu.h>
+
+/* Device states as defined in DFU spec */
+#define STATE_APP_IDLE 0
+#define STATE_APP_DETACH 1
+#define STATE_DFU_IDLE 2
+#define STATE_DFU_DNLOAD_SYNC 3
+#define STATE_DFU_DNLOAD_BUSY 4
+#define STATE_DFU_DNLOAD_IDLE 5
+#define STATE_DFU_MANIFEST_SYNC 6
+#define STATE_DFU_MANIFEST 7
+#define STATE_DFU_MANIFEST_WAIT_RESET 8
+#define STATE_DFU_UPLOAD_IDLE 9
+#define STATE_DFU_ERROR 10
+
+/* DFU errors */
+#define DFU_ERROR_NONE 0x00
+#define DFU_ERROR_TARGET 0x01
+#define DFU_ERROR_FILE 0x02
+#define DFU_ERROR_WRITE 0x03
+#define DFU_ERROR_ERASE 0x04
+#define DFU_ERROR_CHECK_ERASED 0x05
+#define DFU_ERROR_PROG 0x06
+#define DFU_ERROR_VERIFY 0x07
+#define DFU_ERROR_ADDRESS 0x08
+#define DFU_ERROR_NOTDONE 0x09
+#define DFU_ERROR_FIRMWARE 0x0A
+#define DFU_ERROR_VENDOR 0x0B
+#define DFU_ERROR_USB 0x0C
+#define DFU_ERROR_POR 0x0D
+#define DFU_ERROR_UNKNOWN 0x0E
+#define DFU_ERROR_STALLEDPKT 0x0F
+
+/* DFU request */
+#define DFU_DETACH 0
+#define DFU_DNLOAD 1
+#define DFU_UPLOAD 2
+#define DFU_GETSTATUS 3
+#define DFU_CLRSTATUS 4
+#define DFU_GETSTATE 5
+#define DFU_ABORT 6
+
+static bool usb_dfu_detach_req;
+
+/*
+ * usb_dfu_init
+ * Initialize the DFU interface
+ * pdev: device instance
+ * cfgidx: Configuration index
+ * return: status
+ */
+static uint8_t usb_dfu_init(struct usb_handle *pdev, uint8_t cfgidx)
+{
+ (void)pdev;
+ (void)cfgidx;
+
+ /* Nothing to do in this stage */
+ return USBD_OK;
+}
+
+/*
+ * usb_dfu_de_init
+ * De-Initialize the DFU layer
+ * pdev: device instance
+ * cfgidx: Configuration index
+ * return: status
+ */
+static uint8_t usb_dfu_de_init(struct usb_handle *pdev, uint8_t cfgidx)
+{
+ (void)pdev;
+ (void)cfgidx;
+
+ /* Nothing to do in this stage */
+ return USBD_OK;
+}
+
+/*
+ * usb_dfu_data_in
+ * handle data IN Stage
+ * pdev: device instance
+ * epnum: endpoint index
+ * return: status
+ */
+static uint8_t usb_dfu_data_in(struct usb_handle *pdev, uint8_t epnum)
+{
+ (void)pdev;
+ (void)epnum;
+
+ return USBD_OK;
+}
+
+/*
+ * usb_dfu_ep0_rx_ready
+ * handle EP0 Rx Ready event
+ * pdev: device
+ * return: status
+ */
+static uint8_t usb_dfu_ep0_rx_ready(struct usb_handle *pdev)
+{
+ (void)pdev;
+
+ return USBD_OK;
+}
+
+/*
+ * usb_dfu_ep0_tx_ready
+ * handle EP0 TRx Ready event
+ * pdev: device instance
+ * return: status
+ */
+static uint8_t usb_dfu_ep0_tx_ready(struct usb_handle *pdev)
+{
+ (void)pdev;
+
+ return USBD_OK;
+}
+
+/*
+ * usb_dfu_sof
+ * handle SOF event
+ * pdev: device instance
+ * return: status
+ */
+static uint8_t usb_dfu_sof(struct usb_handle *pdev)
+{
+ (void)pdev;
+
+ return USBD_OK;
+}
+
+/*
+ * usb_dfu_iso_in_incomplete
+ * handle data ISO IN Incomplete event
+ * pdev: device instance
+ * epnum: endpoint index
+ * return: status
+ */
+static uint8_t usb_dfu_iso_in_incomplete(struct usb_handle *pdev, uint8_t epnum)
+{
+ (void)pdev;
+ (void)epnum;
+
+ return USBD_OK;
+}
+
+/*
+ * usb_dfu_iso_out_incomplete
+ * handle data ISO OUT Incomplete event
+ * pdev: device instance
+ * epnum: endpoint index
+ * return: status
+ */
+static uint8_t usb_dfu_iso_out_incomplete(struct usb_handle *pdev,
+ uint8_t epnum)
+{
+ (void)pdev;
+ (void)epnum;
+
+ return USBD_OK;
+}
+
+/*
+ * usb_dfu_data_out
+ * handle data OUT Stage
+ * pdev: device instance
+ * epnum: endpoint index
+ * return: status
+ */
+static uint8_t usb_dfu_data_out(struct usb_handle *pdev, uint8_t epnum)
+{
+ (void)pdev;
+ (void)epnum;
+
+ return USBD_OK;
+}
+
+/*
+ * usb_dfu_detach
+ * Handles the DFU DETACH request.
+ * pdev: device instance
+ * req: pointer to the request structure.
+ */
+static void usb_dfu_detach(struct usb_handle *pdev, struct usb_setup_req *req)
+{
+ struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
+
+ INFO("Receive DFU Detach\n");
+
+ if ((hdfu->dev_state == STATE_DFU_IDLE) ||
+ (hdfu->dev_state == STATE_DFU_DNLOAD_SYNC) ||
+ (hdfu->dev_state == STATE_DFU_DNLOAD_IDLE) ||
+ (hdfu->dev_state == STATE_DFU_MANIFEST_SYNC) ||
+ (hdfu->dev_state == STATE_DFU_UPLOAD_IDLE)) {
+ /* Update the state machine */
+ hdfu->dev_state = STATE_DFU_IDLE;
+ hdfu->dev_status = DFU_ERROR_NONE;
+ }
+
+ usb_dfu_detach_req = true;
+}
+
+/*
+ * usb_dfu_download
+ * Handles the DFU DNLOAD request.
+ * pdev: device instance
+ * req: pointer to the request structure
+ */
+static void usb_dfu_download(struct usb_handle *pdev, struct usb_setup_req *req)
+{
+ struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
+ uintptr_t data_ptr;
+ uint32_t length;
+ int ret;
+
+ /* Data setup request */
+ if (req->length > 0) {
+ /* Unsupported state */
+ if ((hdfu->dev_state != STATE_DFU_IDLE) &&
+ (hdfu->dev_state != STATE_DFU_DNLOAD_IDLE)) {
+ /* Call the error management function (command will be nacked) */
+ usb_core_ctl_error(pdev);
+ return;
+ }
+
+ /* Get the data address */
+ length = req->length;
+ ret = hdfu->callback->download(hdfu->alt_setting, &data_ptr,
+ &length, pdev->user_data);
+ if (ret == 0U) {
+ /* Update the state machine */
+ hdfu->dev_state = STATE_DFU_DNLOAD_SYNC;
+ /* Start the transfer */
+ usb_core_receive_ep0(pdev, (uint8_t *)data_ptr, length);
+ } else {
+ usb_core_ctl_error(pdev);
+ }
+ } else {
+ /* End of DNLOAD operation*/
+ if (hdfu->dev_state != STATE_DFU_DNLOAD_IDLE) {
+ /* Call the error management function (command will be nacked) */
+ usb_core_ctl_error(pdev);
+ return;
+ }
+ /* End of DNLOAD operation*/
+ hdfu->dev_state = STATE_DFU_MANIFEST_SYNC;
+ ret = hdfu->callback->manifestation(hdfu->alt_setting, pdev->user_data);
+ if (ret == 0U) {
+ hdfu->dev_state = STATE_DFU_MANIFEST_SYNC;
+ } else {
+ usb_core_ctl_error(pdev);
+ }
+ }
+}
+
+/*
+ * usb_dfu_upload
+ * Handles the DFU UPLOAD request.
+ * pdev: instance
+ * req: pointer to the request structure
+ */
+static void usb_dfu_upload(struct usb_handle *pdev, struct usb_setup_req *req)
+{
+ struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
+ uintptr_t data_ptr;
+ uint32_t length;
+ int ret;
+
+ /* Data setup request */
+ if (req->length == 0) {
+ /* No Data setup request */
+ hdfu->dev_state = STATE_DFU_IDLE;
+ return;
+ }
+
+ /* Unsupported state */
+ if ((hdfu->dev_state != STATE_DFU_IDLE) && (hdfu->dev_state != STATE_DFU_UPLOAD_IDLE)) {
+ ERROR("UPLOAD : Unsupported State\n");
+ /* Call the error management function (command will be nacked) */
+ usb_core_ctl_error(pdev);
+ return;
+ }
+
+ /* Update the data address */
+ length = req->length;
+ ret = hdfu->callback->upload(hdfu->alt_setting, &data_ptr, &length, pdev->user_data);
+ if (ret == 0U) {
+ /* Short frame */
+ hdfu->dev_state = (req->length > length) ? STATE_DFU_IDLE : STATE_DFU_UPLOAD_IDLE;
+
+ /* Start the transfer */
+ usb_core_transmit_ep0(pdev, (uint8_t *)data_ptr, length);
+ } else {
+ ERROR("UPLOAD : bad block %i on alt %i\n", req->value, req->index);
+ hdfu->dev_state = STATE_DFU_ERROR;
+ hdfu->dev_status = DFU_ERROR_STALLEDPKT;
+
+ /* Call the error management function (command will be nacked) */
+ usb_core_ctl_error(pdev);
+ }
+}
+
+/*
+ * usb_dfu_get_status
+ * Handles the DFU GETSTATUS request.
+ * pdev: instance
+ */
+static void usb_dfu_get_status(struct usb_handle *pdev)
+{
+ struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
+
+ hdfu->status[0] = hdfu->dev_status; /* bStatus */
+ hdfu->status[1] = 0; /* bwPollTimeout[3] */
+ hdfu->status[2] = 0;
+ hdfu->status[3] = 0;
+ hdfu->status[4] = hdfu->dev_state; /* bState */
+ hdfu->status[5] = 0; /* iString */
+
+ /* next step */
+ switch (hdfu->dev_state) {
+ case STATE_DFU_DNLOAD_SYNC:
+ hdfu->dev_state = STATE_DFU_DNLOAD_IDLE;
+ break;
+ case STATE_DFU_MANIFEST_SYNC:
+ /* the device is 'ManifestationTolerant' */
+ hdfu->status[4] = STATE_DFU_MANIFEST;
+ hdfu->status[1] = 1U; /* bwPollTimeout = 1ms */
+ hdfu->dev_state = STATE_DFU_IDLE;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Start the transfer */
+ usb_core_transmit_ep0(pdev, (uint8_t *)&hdfu->status[0], sizeof(hdfu->status));
+}
+
+/*
+ * usb_dfu_clear_status
+ * Handles the DFU CLRSTATUS request.
+ * pdev: device instance
+ */
+static void usb_dfu_clear_status(struct usb_handle *pdev)
+{
+ struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
+
+ if (hdfu->dev_state == STATE_DFU_ERROR) {
+ hdfu->dev_state = STATE_DFU_IDLE;
+ hdfu->dev_status = DFU_ERROR_NONE;
+ } else {
+ /* State Error */
+ hdfu->dev_state = STATE_DFU_ERROR;
+ hdfu->dev_status = DFU_ERROR_UNKNOWN;
+ }
+}
+
+/*
+ * usb_dfu_get_state
+ * Handles the DFU GETSTATE request.
+ * pdev: device instance
+ */
+static void usb_dfu_get_state(struct usb_handle *pdev)
+{
+ struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
+
+ /* Return the current state of the DFU interface */
+ usb_core_transmit_ep0(pdev, &hdfu->dev_state, 1);
+}
+
+/*
+ * usb_dfu_abort
+ * Handles the DFU ABORT request.
+ * pdev: device instance
+ */
+static void usb_dfu_abort(struct usb_handle *pdev)
+{
+ struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
+
+ if ((hdfu->dev_state == STATE_DFU_IDLE) ||
+ (hdfu->dev_state == STATE_DFU_DNLOAD_SYNC) ||
+ (hdfu->dev_state == STATE_DFU_DNLOAD_IDLE) ||
+ (hdfu->dev_state == STATE_DFU_MANIFEST_SYNC) ||
+ (hdfu->dev_state == STATE_DFU_UPLOAD_IDLE)) {
+ hdfu->dev_state = STATE_DFU_IDLE;
+ hdfu->dev_status = DFU_ERROR_NONE;
+ }
+}
+
+/*
+ * usb_dfu_setup
+ * Handle the DFU specific requests
+ * pdev: instance
+ * req: usb requests
+ * return: status
+ */
+static uint8_t usb_dfu_setup(struct usb_handle *pdev, struct usb_setup_req *req)
+{
+ uint8_t *pbuf = NULL;
+ uint16_t len = 0U;
+ uint8_t ret = USBD_OK;
+ struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
+
+ switch (req->bm_request & USB_REQ_TYPE_MASK) {
+ case USB_REQ_TYPE_CLASS:
+ switch (req->b_request) {
+ case DFU_DNLOAD:
+ usb_dfu_download(pdev, req);
+ break;
+
+ case DFU_UPLOAD:
+ usb_dfu_upload(pdev, req);
+ break;
+
+ case DFU_GETSTATUS:
+ usb_dfu_get_status(pdev);
+ break;
+
+ case DFU_CLRSTATUS:
+ usb_dfu_clear_status(pdev);
+ break;
+
+ case DFU_GETSTATE:
+ usb_dfu_get_state(pdev);
+ break;
+
+ case DFU_ABORT:
+ usb_dfu_abort(pdev);
+ break;
+
+ case DFU_DETACH:
+ usb_dfu_detach(pdev, req);
+ break;
+
+ default:
+ ERROR("unknown request %x on alternate %i\n",
+ req->b_request, hdfu->alt_setting);
+ usb_core_ctl_error(pdev);
+ ret = USBD_FAIL;
+ break;
+ }
+ break;
+ case USB_REQ_TYPE_STANDARD:
+ switch (req->b_request) {
+ case USB_REQ_GET_DESCRIPTOR:
+ if (HIBYTE(req->value) == DFU_DESCRIPTOR_TYPE) {
+ pbuf = pdev->desc->get_config_desc(&len);
+ /* DFU descriptor at the end of the USB */
+ pbuf += len - 9U;
+ len = 9U;
+ len = MIN(len, req->length);
+ }
+
+ /* Start the transfer */
+ usb_core_transmit_ep0(pdev, pbuf, len);
+
+ break;
+
+ case USB_REQ_GET_INTERFACE:
+ /* Start the transfer */
+ usb_core_transmit_ep0(pdev, (uint8_t *)&hdfu->alt_setting, 1U);
+ break;
+
+ case USB_REQ_SET_INTERFACE:
+ hdfu->alt_setting = LOBYTE(req->value);
+ break;
+
+ default:
+ usb_core_ctl_error(pdev);
+ ret = USBD_FAIL;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static const struct usb_class usb_dfu = {
+ .init = usb_dfu_init,
+ .de_init = usb_dfu_de_init,
+ .setup = usb_dfu_setup,
+ .ep0_tx_sent = usb_dfu_ep0_tx_ready,
+ .ep0_rx_ready = usb_dfu_ep0_rx_ready,
+ .data_in = usb_dfu_data_in,
+ .data_out = usb_dfu_data_out,
+ .sof = usb_dfu_sof,
+ .iso_in_incomplete = usb_dfu_iso_in_incomplete,
+ .iso_out_incomplete = usb_dfu_iso_out_incomplete,
+};
+
+void usb_dfu_register(struct usb_handle *pdev, struct usb_dfu_handle *phandle)
+{
+ pdev->class = (struct usb_class *)&usb_dfu;
+ pdev->class_data = phandle;
+
+ phandle->dev_state = STATE_DFU_IDLE;
+ phandle->dev_status = DFU_ERROR_NONE;
+}
+
+int usb_dfu_loop(struct usb_handle *pdev, const struct usb_dfu_media *pmedia)
+{
+ uint32_t it_count;
+ enum usb_status ret;
+ struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
+
+ hdfu->callback = pmedia;
+ usb_dfu_detach_req = false;
+ /* Continue to handle USB core IT to assure complete data transmission */
+ it_count = 100U;
+
+ /* DFU infinite loop until DETACH_REQ */
+ while (it_count != 0U) {
+ ret = usb_core_handle_it(pdev);
+ if (ret != USBD_OK) {
+ return -EIO;
+ }
+
+ /* Detach request received */
+ if (usb_dfu_detach_req) {
+ it_count--;
+ }
+ }
+
+ return 0;
+}
diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c
new file mode 100644
index 0000000..4f04a6f
--- /dev/null
+++ b/plat/st/stm32mp1/bl2_plat_setup.c
@@ -0,0 +1,562 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/mmc.h>
+#include <drivers/st/bsec.h>
+#include <drivers/st/regulator_fixed.h>
+#include <drivers/st/stm32_iwdg.h>
+#include <drivers/st/stm32_rng.h>
+#include <drivers/st/stm32_uart.h>
+#include <drivers/st/stm32mp1_clk.h>
+#include <drivers/st/stm32mp1_pwr.h>
+#include <drivers/st/stm32mp1_ram.h>
+#include <drivers/st/stm32mp_pmic.h>
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_dyn_cfg_getter.h>
+#include <lib/mmio.h>
+#include <lib/optee_utils.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+#include <stm32mp_common.h>
+#include <stm32mp1_dbgmcu.h>
+
+#if DEBUG
+static const char debug_msg[] = {
+ "***************************************************\n"
+ "** DEBUG ACCESS PORT IS OPEN! **\n"
+ "** This boot image is only for debugging purpose **\n"
+ "** and is unsafe for production use. **\n"
+ "** **\n"
+ "** If you see this message and you are not **\n"
+ "** debugging report this immediately to your **\n"
+ "** vendor! **\n"
+ "***************************************************\n"
+};
+#endif
+
+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 STM32MP15
+ 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;
+ }
+#endif
+
+ 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 STM32MP15
+ if ((rstsr & RCC_MP_RSTSCLRR_MPUP1RSTF) != 0U) {
+ INFO(" MPU Processor 1 Reset\n");
+ return;
+ }
+#endif
+
+ 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_setup_early_console();
+
+ stm32mp_save_boot_ctx_address(arg0);
+}
+
+void bl2_platform_setup(void)
+{
+ int ret;
+
+ ret = stm32mp1_ddr_probe();
+ if (ret < 0) {
+ ERROR("Invalid DDR init: error %d\n", ret);
+ panic();
+ }
+
+ /* Map DDR for binary load, now with cacheable attribute */
+ ret = mmap_add_dynamic_region(STM32MP_DDR_BASE, STM32MP_DDR_BASE,
+ STM32MP_DDR_MAX_SIZE, MT_MEMORY | MT_RW | MT_SECURE);
+ if (ret < 0) {
+ ERROR("DDR mapping: error %d\n", ret);
+ panic();
+ }
+}
+
+#if STM32MP15
+static void update_monotonic_counter(void)
+{
+ uint32_t version;
+ uint32_t otp;
+
+ CASSERT(STM32_TF_VERSION <= MAX_MONOTONIC_VALUE,
+ assert_stm32mp1_monotonic_counter_reach_max);
+
+ /* Check if monotonic counter needs to be incremented */
+ if (stm32_get_otp_index(MONOTONIC_OTP, &otp, NULL) != 0) {
+ panic();
+ }
+
+ if (stm32_get_otp_value_from_idx(otp, &version) != 0) {
+ panic();
+ }
+
+ if ((version + 1U) < BIT(STM32_TF_VERSION)) {
+ uint32_t result;
+
+ /* Need to increment the monotonic counter. */
+ version = BIT(STM32_TF_VERSION) - 1U;
+
+ result = bsec_program_otp(version, otp);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: MONOTONIC_OTP program Error %u\n",
+ result);
+ panic();
+ }
+ INFO("Monotonic counter has been incremented (value 0x%x)\n",
+ version);
+ }
+}
+#endif
+
+void bl2_el3_plat_arch_setup(void)
+{
+ const char *board_model;
+ boot_api_context_t *boot_context =
+ (boot_api_context_t *)stm32mp_get_boot_ctx_address();
+ uintptr_t pwr_base;
+ uintptr_t rcc_base;
+
+ if (bsec_probe() != 0U) {
+ panic();
+ }
+
+ mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
+ BL_CODE_END - BL_CODE_BASE,
+ MT_CODE | MT_SECURE);
+
+ /* Prevent corruption of preloaded Device Tree */
+ mmap_add_region(DTB_BASE, DTB_BASE,
+ DTB_LIMIT - DTB_BASE,
+ MT_RO_DATA | MT_SECURE);
+
+ configure_mmu();
+
+ if (dt_open_and_check(STM32MP_DTB_BASE) < 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) {
+ ;
+ }
+
+ /* 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);
+ }
+
+#if STM32MP15
+ /* Disable MCKPROT */
+ mmio_clrbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT);
+#endif
+
+ /*
+ * Set minimum reset pulse duration to 31ms for discrete power
+ * supplied boards.
+ */
+ if (dt_pmic_status() <= 0) {
+ mmio_clrsetbits_32(rcc_base + RCC_RDLSICR,
+ RCC_RDLSICR_MRD_MASK,
+ 31U << RCC_RDLSICR_MRD_SHIFT);
+ }
+
+ generic_delay_timer_init();
+
+#if STM32MP_UART_PROGRAMMER
+ /* Disable programmer UART before changing clock tree */
+ if (boot_context->boot_interface_selected ==
+ BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART) {
+ uintptr_t uart_prog_addr =
+ get_uart_address(boot_context->boot_interface_instance);
+
+ stm32_uart_stop(uart_prog_addr);
+ }
+#endif
+ if (stm32mp1_clk_probe() < 0) {
+ panic();
+ }
+
+ if (stm32mp1_clk_init() < 0) {
+ panic();
+ }
+
+ stm32_save_boot_interface(boot_context->boot_interface_selected,
+ boot_context->boot_interface_instance);
+ stm32_save_boot_auth(boot_context->auth_status,
+ boot_context->boot_partition_used_toboot);
+
+#if STM32MP_USB_PROGRAMMER && STM32MP15
+ /* Deconfigure all UART RX pins configured by ROM code */
+ stm32mp1_deconfigure_uart_pins();
+#endif
+
+ if (stm32mp_uart_console_setup() != 0) {
+ goto skip_console_init;
+ }
+
+ 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 !TRUSTED_BOARD_BOOT
+ if (stm32mp_is_closed_device()) {
+ /* Closed chip mandates authentication */
+ ERROR("Secure chip: TRUSTED_BOARD_BOOT must be enabled\n");
+ panic();
+ }
+#endif
+
+ if (fixed_regulator_register() != 0) {
+ panic();
+ }
+
+ if (dt_pmic_status() > 0) {
+ initialize_pmic();
+ if (pmic_voltages_init() != 0) {
+ ERROR("PMIC voltages init failed\n");
+ panic();
+ }
+ print_pmic_info_and_debug();
+ }
+
+ stm32mp1_syscfg_init();
+
+ if (stm32_iwdg_init() < 0) {
+ panic();
+ }
+
+ stm32_iwdg_refresh();
+
+ if (bsec_read_debug_conf() != 0U) {
+ if (stm32mp_is_closed_device()) {
+#if DEBUG
+ WARN("\n%s", debug_msg);
+#else
+ ERROR("***Debug opened on closed chip***\n");
+#endif
+ }
+ }
+
+#if STM32MP13
+ if (stm32_rng_init() != 0) {
+ panic();
+ }
+#endif
+
+ stm32mp1_arch_security_setup();
+
+ print_reset_reason();
+
+#if STM32MP15
+ update_monotonic_counter();
+#endif
+
+ stm32mp1_syscfg_enable_io_compensation_finish();
+
+ fconf_populate("TB_FW", STM32MP_DTB_BASE);
+
+ stm32mp_io_setup();
+}
+
+/*******************************************************************************
+ * 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 __unused;
+ bl_mem_params_node_t *paged_mem_params __unused;
+ const struct dyn_cfg_dtb_info_t *config_info;
+ bl_mem_params_node_t *tos_fw_mem_params;
+ unsigned int i;
+ unsigned int idx;
+ unsigned long long ddr_top __unused;
+ const unsigned int image_ids[] = {
+ BL32_IMAGE_ID,
+ BL33_IMAGE_ID,
+ HW_CONFIG_ID,
+ TOS_FW_CONFIG_ID,
+ };
+
+ assert(bl_mem_params != NULL);
+
+ switch (image_id) {
+ case FW_CONFIG_ID:
+ /* Set global DTB info for fixed fw_config information */
+ set_config_info(STM32MP_FW_CONFIG_BASE, ~0UL, STM32MP_FW_CONFIG_MAX_SIZE,
+ FW_CONFIG_ID);
+ fconf_populate("FW_CONFIG", STM32MP_FW_CONFIG_BASE);
+
+ idx = dyn_cfg_dtb_info_get_index(TOS_FW_CONFIG_ID);
+
+ /* Iterate through all the fw config IDs */
+ for (i = 0U; i < ARRAY_SIZE(image_ids); i++) {
+ if ((image_ids[i] == TOS_FW_CONFIG_ID) && (idx == FCONF_INVALID_IDX)) {
+ continue;
+ }
+
+ bl_mem_params = get_bl_mem_params_node(image_ids[i]);
+ assert(bl_mem_params != NULL);
+
+ config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, image_ids[i]);
+ if (config_info == NULL) {
+ continue;
+ }
+
+ bl_mem_params->image_info.image_base = config_info->config_addr;
+ bl_mem_params->image_info.image_max_size = config_info->config_max_size;
+
+ bl_mem_params->image_info.h.attr &= ~IMAGE_ATTRIB_SKIP_LOADING;
+
+ switch (image_ids[i]) {
+ case BL32_IMAGE_ID:
+ bl_mem_params->ep_info.pc = config_info->config_addr;
+
+ /* In case of OPTEE, initialize address space with tos_fw addr */
+ pager_mem_params = get_bl_mem_params_node(BL32_EXTRA1_IMAGE_ID);
+ assert(pager_mem_params != NULL);
+ pager_mem_params->image_info.image_base = config_info->config_addr;
+ pager_mem_params->image_info.image_max_size =
+ config_info->config_max_size;
+
+ /* Init base and size for pager if exist */
+ paged_mem_params = get_bl_mem_params_node(BL32_EXTRA2_IMAGE_ID);
+ if (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;
+ }
+ break;
+
+ case BL33_IMAGE_ID:
+ bl_mem_params->ep_info.pc = config_info->config_addr;
+ break;
+
+ case HW_CONFIG_ID:
+ case TOS_FW_CONFIG_ID:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+ break;
+
+ case BL32_IMAGE_ID:
+ if (optee_header_is_valid(bl_mem_params->image_info.image_base)) {
+ image_info_t *paged_image_info = NULL;
+
+ /* BL32 is OP-TEE header */
+ 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);
+
+ paged_mem_params = get_bl_mem_params_node(BL32_EXTRA2_IMAGE_ID);
+ if (paged_mem_params != NULL) {
+ paged_image_info = &paged_mem_params->image_info;
+ }
+
+ err = parse_optee_header(&bl_mem_params->ep_info,
+ &pager_mem_params->image_info,
+ paged_image_info);
+ if (err != 0) {
+ ERROR("OPTEE header parse error.\n");
+ panic();
+ }
+
+ /* Set optee boot info from parsed header data */
+ if (paged_mem_params != NULL) {
+ bl_mem_params->ep_info.args.arg0 =
+ paged_mem_params->image_info.image_base;
+ } else {
+ bl_mem_params->ep_info.args.arg0 = 0U;
+ }
+
+ bl_mem_params->ep_info.args.arg1 = 0U; /* Unused */
+ bl_mem_params->ep_info.args.arg2 = 0U; /* No DT supported */
+ } else {
+ bl_mem_params->ep_info.pc = bl_mem_params->image_info.image_base;
+ tos_fw_mem_params = get_bl_mem_params_node(TOS_FW_CONFIG_ID);
+ assert(tos_fw_mem_params != NULL);
+ bl_mem_params->image_info.image_max_size +=
+ tos_fw_mem_params->image_info.image_max_size;
+ bl_mem_params->ep_info.args.arg0 = 0;
+ }
+ 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;
+#if PSA_FWU_SUPPORT
+ stm32mp1_fwu_set_boot_idx();
+#endif /* PSA_FWU_SUPPORT */
+ break;
+
+ default:
+ /* Do nothing in default case */
+ break;
+ }
+
+#if STM32MP_SDMMC || STM32MP_EMMC
+ /*
+ * Invalidate remaining data read from MMC but not flushed by load_image_flush().
+ * We take the worst case which is 2 MMC blocks.
+ */
+ if ((image_id != FW_CONFIG_ID) &&
+ ((bl_mem_params->image_info.h.attr & IMAGE_ATTRIB_SKIP_LOADING) == 0U)) {
+ inv_dcache_range(bl_mem_params->image_info.image_base +
+ bl_mem_params->image_info.image_size,
+ 2U * MMC_BLOCK_SIZE);
+ }
+#endif /* STM32MP_SDMMC || STM32MP_EMMC */
+
+ return err;
+}
+
+void bl2_el3_plat_prepare_exit(void)
+{
+ uint16_t boot_itf = stm32mp_get_boot_itf_selected();
+
+ switch (boot_itf) {
+#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
+ /* Invalidate the downloaded buffer used with io_memmap */
+ inv_dcache_range(DWL_BUFFER_BASE, DWL_BUFFER_SIZE);
+ break;
+#endif /* STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER */
+ default:
+ /* Do nothing in default case */
+ break;
+ }
+
+ stm32mp1_security_setup();
+}
diff --git a/plat/st/stm32mp1/cert_create_tbbr.mk b/plat/st/stm32mp1/cert_create_tbbr.mk
new file mode 100644
index 0000000..5b1a3ed
--- /dev/null
+++ b/plat/st/stm32mp1/cert_create_tbbr.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Override TBBR Cert to update generic certificate
+
+$(eval $(call add_define,PDEF_CERTS))
+
+PLAT_INCLUDE += -I${PLAT_DIR}include
+
+src/stm32mp1_tbb_cert.o: ${PLAT_DIR}stm32mp1_tbb_cert.c
+ ${Q}${HOSTCC} -c ${HOSTCCFLAGS} ${INC_DIR} $< -o $@
+
+PLAT_OBJECTS = src/stm32mp1_tbb_cert.o
+
+OBJECTS += $(PLAT_OBJECTS)
+
diff --git a/plat/st/stm32mp1/include/boot_api.h b/plat/st/stm32mp1/include/boot_api.h
new file mode 100644
index 0000000..1054609
--- /dev/null
+++ b/plat/st/stm32mp1/include/boot_api.h
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BOOT_API_H
+#define BOOT_API_H
+
+#include <stdint.h>
+#include <stdio.h>
+
+/*
+ * Possible value of boot context field 'auth_status'
+ */
+#if STM32MP13
+ /* No authentication done */
+#define BOOT_API_CTX_AUTH_NO 0x7CFDD351U
+ /* Authentication done and failed */
+#define BOOT_API_CTX_AUTH_FAILED 0x51330884U
+ /* Authentication done and success */
+#define BOOT_API_CTX_AUTH_SUCCESS 0x67E8CAE1U
+#endif
+#if STM32MP15
+/* 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
+#endif
+
+/*
+ * 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
+
+/* Boot occurred on FMC */
+#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC 0x3U
+
+/* Boot occurred on QSPI NOR */
+#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI 0x4U
+
+/* Boot occurred on UART */
+#define BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART 0x5U
+
+/* Boot occurred on USB */
+#define BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB 0x6U
+
+/* Boot occurred on QSPI NAND */
+#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI 0x7U
+
+/**
+ * @brief Possible value of boot context field 'EmmcXferStatus'
+ */
+/*
+ * 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
+#define BOOT_API_CTX_EMMC_ERROR_STATUS_ACK_ERROR 0x8U
+
+/* Image Header related definitions */
+
+/* Definition of header version */
+#if STM32MP13
+#define BOOT_API_HEADER_VERSION 0x00020000U
+#endif
+#if STM32MP15
+#define BOOT_API_HEADER_VERSION 0x00010000U
+#endif
+
+/*
+ * 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
+
+/*
+ * Extension headers related definitions
+ */
+/* 'bootapi_image_header_t.extension_flag' used for authentication feature */
+#define BOOT_API_AUTHENTICATION_EXTENSION_BIT BIT(0)
+/* 'bootapi_image_header_t.extension_flag' used for FSBL decryption feature */
+#define BOOT_API_FSBL_DECRYPTION_EXTENSION_BIT BIT(1)
+/* 'bootapi_image_header_t.extension_flag' used for padding header feature */
+#define BOOT_API_PADDING_EXTENSION_BIT BIT(31)
+/*
+ * mask of bits of field 'bootapi_image_header_t.extension_flag'
+ * used for extension headers
+ */
+#define BOOT_API_ALL_EXTENSIONS_MASK \
+ (BOOT_API_AUTHENTICATION_EXTENSION_BIT | \
+ BOOT_API_FSBL_DECRYPTION_EXTENSION_BIT | \
+ BOOT_API_PADDING_EXTENSION_BIT)
+/*
+ * Magic number of FSBL decryption extension header
+ * The value shall gives the four bytes 'S','T',0x00,0x01 in memory
+ */
+#define BOOT_API_FSBL_DECRYPTION_HEADER_MAGIC_NB 0x01005453U
+
+/*
+ * Magic number of PKH revocation extension header
+ * The value shall gives the four bytes 'S','T',0x00,0x02 in memory
+ */
+#define BOOT_API_AUTHENTICATION_HEADER_MAGIC_NB 0x02005453U
+
+/* Max number of ECDSA public key hash in table */
+#define BOOT_API_AUTHENTICATION_NB_PKH_MAX 8U
+
+/* ECDSA public key hash table size in bytes */
+#define BOOT_API_AUTHENTICATION_TABLE_SIZE_BYTES \
+ (BOOT_API_AUTHENTICATION_NB_PKH_MAX * \
+ BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES)
+
+/*
+ * Magic number of padding extension header
+ * The value shall gives the four bytes 'S','T',0xFF,0xFF in memory
+ */
+#define BOOT_API_PADDING_HEADER_MAGIC_NB 0xFFFF5453U
+
+/*
+ * 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 0x77U
+
+/*
+ * 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;
+#if STM32MP13
+ uint32_t reserved1[12];
+#endif
+#if STM32MP15
+ uint32_t reserved1[13];
+#endif
+ uint32_t otp_afmux_values[3];
+ uint32_t reserved[3];
+#if STM32MP15
+ uint32_t reserved2[2];
+#endif
+ uint32_t auth_status;
+
+#if STM32MP15
+ /*
+ * Pointers to bootROM External Secure Services
+ * - ECDSA verify signature
+ */
+ uint32_t reserved3;
+ uint32_t (*bootrom_ecdsa_verify_signature)(uint8_t *hash_in,
+ uint8_t *pubkey_in,
+ uint8_t *signature,
+ uint32_t ecc_algo);
+ uint32_t reserved4;
+#endif
+ /*
+ * 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 payload bytes considered as 8 bit unsigned
+ * numbers, discarding any overflow bits.
+ * Use to check UART/USB downloaded image integrity when signature
+ * is not used
+ */
+ 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;
+
+#if STM32MP13
+ /*
+ * Extension flags :
+ *
+ * Bit 0 : Authentication extension header
+ * value 0 : No signature check request
+ * Bit 1 : Encryption extension header
+ * Bit 2 : Padding extension header
+ */
+ uint32_t extension_flags;
+ /* Length in bytes of all extension headers */
+ uint32_t extension_headers_length;
+ /* Add binary type information */
+ uint32_t binary_type;
+ /* Pad up to 128 byte total size */
+ uint8_t pad[16];
+ /* Followed by extension header */
+ uint8_t ext_header[];
+#endif
+#if STM32MP15
+ /*
+ * 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;
+#endif
+} __packed boot_api_image_header_t;
+
+typedef uint8_t boot_api_sha256_t[BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES];
+
+typedef struct {
+ /* Extension header type:
+ * BOOT_API_FSBL_DECRYPTION_HEADER_MAGIC_NB or
+ * BOOT_API_AUTHENTICATION_HEADER_MAGIC_NB
+ * BOOT_API_PADDING_HEADER_MAGIC_NB
+ */
+ uint32_t type;
+ /* Extension header len in byte */
+ uint32_t len;
+ /* parameters of this extension */
+ uint8_t params[];
+} __packed boot_extension_header_t;
+
+typedef struct {
+ /* Idx of ECDSA public key to be used in table */
+ uint32_t pk_idx;
+ /* Number of ECDSA public key in table */
+ uint32_t nb_pk;
+ /*
+ * 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;
+ /* ECDSA public key to be used to check signature. */
+ uint8_t ecc_pubk[BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES];
+ /* table of Hash of Algo+ECDSA public key */
+ boot_api_sha256_t pk_hashes[];
+} __packed boot_ext_header_params_authentication_t;
+
+typedef struct {
+ /* Size of encryption key (128 or 256) */
+ uint32_t key_size;
+ uint32_t derivation_cont;
+ /* 128 msb bits of plain payload SHA256 */
+ uint32_t hash[4];
+} __packed boot_ext_header_params_encrypted_fsbl_t;
+
+#endif /* BOOT_API_H */
diff --git a/plat/st/stm32mp1/include/plat_def_fip_uuid.h b/plat/st/stm32mp1/include/plat_def_fip_uuid.h
new file mode 100644
index 0000000..e5fbc2d
--- /dev/null
+++ b/plat/st/stm32mp1/include/plat_def_fip_uuid.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_DEF_FIP_UUID_H
+#define PLAT_DEF_FIP_UUID_H
+
+#define UUID_STM32MP_CONFIG_CERT \
+ {{0x50, 0x1d, 0x8d, 0xd2}, {0x8b, 0xce}, {0x49, 0xa5}, 0x84, 0xeb, \
+ {0x55, 0x9a, 0x9f, 0x2e, 0xae, 0xaf} }
+#endif /* PLAT_DEF_FIP_UUID_H */
+
diff --git a/plat/st/stm32mp1/include/plat_tbbr_img_def.h b/plat/st/stm32mp1/include/plat_tbbr_img_def.h
new file mode 100644
index 0000000..984aae8
--- /dev/null
+++ b/plat/st/stm32mp1/include/plat_tbbr_img_def.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef STM32MP1_IMG_DEF_H
+#define STM32MP1_IMG_DEF_H
+
+#include <export/common/tbbr/tbbr_img_def_exp.h>
+
+/* Undef the existing values */
+#undef BL32_EXTRA1_IMAGE_ID
+#undef BL32_EXTRA2_IMAGE_ID
+#undef TOS_FW_CONFIG_ID
+#undef TRUSTED_BOOT_FW_CERT_ID
+#undef FWU_METADATA_IMAGE_ID
+#undef BKUP_FWU_METADATA_IMAGE_ID
+#undef FW_CONFIG_ID
+#undef HW_CONFIG_ID
+#undef GPT_IMAGE_ID
+#undef ENC_IMAGE_ID
+
+/* Define the STM32MP1 used ID */
+#define FW_CONFIG_ID U(1)
+#define HW_CONFIG_ID U(2)
+#define GPT_IMAGE_ID U(3)
+#define ENC_IMAGE_ID U(6)
+#define BL32_EXTRA1_IMAGE_ID U(8)
+#define BL32_EXTRA2_IMAGE_ID U(9)
+#define FWU_METADATA_IMAGE_ID U(12)
+#define BKUP_FWU_METADATA_IMAGE_ID U(13)
+#define TOS_FW_CONFIG_ID U(16)
+#define STM32MP_CONFIG_CERT_ID U(17)
+
+/* Increase the MAX_NUMBER_IDS to match the authentication pool required */
+#define MAX_NUMBER_IDS U(19)
+
+#endif /* STM32MP1_IMG_DEF_H */
diff --git a/plat/st/stm32mp1/include/platform_def.h b/plat/st/stm32mp1/include/platform_def.h
new file mode 100644
index 0000000..61b847f
--- /dev/null
+++ b/plat/st/stm32mp1/include/platform_def.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#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
+
+#define FIP_IMAGE_NAME "fip"
+#define METADATA_PART_1 "metadata1"
+#define METADATA_PART_2 "metadata2"
+
+#define STM32MP_PRIMARY_CPU U(0x0)
+#define STM32MP_SECONDARY_CPU U(0x1)
+
+#define PLATFORM_CLUSTER_COUNT U(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)
+#define MAX_IO_MTD_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)
+
+#define BL2_RO_BASE STM32MP_BL2_RO_BASE
+#define BL2_RO_LIMIT (STM32MP_BL2_RO_BASE + \
+ STM32MP_BL2_RO_SIZE)
+
+#define BL2_RW_BASE STM32MP_BL2_RW_BASE
+#define BL2_RW_LIMIT (STM32MP_BL2_RW_BASE + \
+ STM32MP_BL2_RW_SIZE)
+/*******************************************************************************
+ * BL32 specific defines.
+ ******************************************************************************/
+#if defined(IMAGE_BL32)
+#if ENABLE_PIE
+#define BL32_BASE 0
+#define BL32_LIMIT STM32MP_BL32_SIZE
+#else
+#define BL32_BASE STM32MP_BL32_BASE
+#define BL32_LIMIT (STM32MP_BL32_BASE + \
+ STM32MP_BL32_SIZE)
+#endif
+#endif /* defined(IMAGE_BL32) */
+
+/*******************************************************************************
+ * 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
+
+/* Needed by STM32CubeProgrammer support */
+#define DWL_BUFFER_SIZE U(0x01000000)
+
+/*
+ * SSBL offset in case it's stored in eMMC boot partition.
+ * We can fix it to 256K because TF-A size can't be bigger than SRAM
+ */
+#define PLAT_EMMC_BOOT_SSBL_OFFSET U(0x40000)
+
+/*******************************************************************************
+ * 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
+
+/*******************************************************************************
+ * Number of parallel entry slots in SMT SCMI server entry context. For this
+ * platform, SCMI server is reached through SMC only, hence the number of
+ * entry slots.
+ ******************************************************************************/
+#define PLAT_SMT_ENTRY_COUNT PLATFORM_CORE_COUNT
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/st/stm32mp1/include/stm32mp1_dbgmcu.h b/plat/st/stm32mp1/include/stm32mp1_dbgmcu.h
new file mode 100644
index 0000000..3663bce
--- /dev/null
+++ b/plat/st/stm32mp1/include/stm32mp1_dbgmcu.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2015-2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_DBGMCU_H
+#define STM32MP1_DBGMCU_H
+
+#include <stdint.h>
+
+/* 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);
+
+#endif /* STM32MP1_DBGMCU_H */
diff --git a/plat/st/stm32mp1/include/stm32mp1_mbedtls_config.h b/plat/st/stm32mp1/include/stm32mp1_mbedtls_config.h
new file mode 100644
index 0000000..2f07621
--- /dev/null
+++ b/plat/st/stm32mp1/include/stm32mp1_mbedtls_config.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2022, STMicroelectronics - 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_USE_RSA 0
+#define TF_MBEDTLS_USE_ECDSA 1
+
+/*
+ * 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
+#define MBEDTLS_ECP_NO_INTERNAL_RNG
+#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
+
+#if TF_MBEDTLS_USE_AES_GCM
+#define MBEDTLS_AES_C
+#define MBEDTLS_CIPHER_C
+#define MBEDTLS_GCM_C
+#endif
+
+/* 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
+
+/*
+ * Prevent the use of 128-bit division which
+ * creates dependency on external libraries.
+ */
+#define MBEDTLS_NO_UDBL_DIVISION
+
+#ifndef __ASSEMBLER__
+/* System headers required to build mbed TLS with the current configuration */
+#include <stdlib.h>
+#include <mbedtls/check_config.h>
+#endif
+
+/*
+ * Mbed TLS heap size is smal as we only use the asn1
+ * parsing functions
+ * digest, signature and crypto algorithm are done by
+ * other library.
+ */
+
+#define TF_MBEDTLS_HEAP_SIZE U(5120)
+#endif /* MBEDTLS_CONFIG_H */
diff --git a/plat/st/stm32mp1/include/stm32mp1_private.h b/plat/st/stm32mp1/include/stm32mp1_private.h
new file mode 100644
index 0000000..21ef60d
--- /dev/null
+++ b/plat/st/stm32mp1/include/stm32mp1_private.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_PRIVATE_H
+#define STM32MP1_PRIVATE_H
+
+#include <stdint.h>
+
+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_start(void);
+void stm32mp1_syscfg_enable_io_compensation_finish(void);
+void stm32mp1_syscfg_disable_io_compensation(void);
+uint32_t stm32mp1_syscfg_get_chip_version(void);
+uint32_t stm32mp1_syscfg_get_chip_dev_id(void);
+#if STM32MP13
+void stm32mp1_syscfg_boot_mode_enable(void);
+void stm32mp1_syscfg_boot_mode_disable(void);
+#endif
+#if STM32MP15
+static inline void stm32mp1_syscfg_boot_mode_enable(void){}
+static inline void stm32mp1_syscfg_boot_mode_disable(void){}
+#endif
+
+void stm32mp1_deconfigure_uart_pins(void);
+
+void stm32mp1_init_scmi_server(void);
+#endif /* STM32MP1_PRIVATE_H */
diff --git a/plat/st/stm32mp1/include/stm32mp1_shared_resources.h b/plat/st/stm32mp1/include/stm32mp1_shared_resources.h
new file mode 100644
index 0000000..3f6367e
--- /dev/null
+++ b/plat/st/stm32mp1/include/stm32mp1_shared_resources.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_SHARED_RESOURCES_H
+#define STM32MP1_SHARED_RESOURCES_H
+
+#include <stm32mp_shared_resources.h>
+
+#define STM32MP1_SHRES_GPIOZ(i) (STM32MP1_SHRES_GPIOZ_0 + (i))
+
+enum stm32mp_shres {
+ STM32MP1_SHRES_CRYP1,
+ STM32MP1_SHRES_GPIOZ_0,
+ STM32MP1_SHRES_GPIOZ_1,
+ STM32MP1_SHRES_GPIOZ_2,
+ STM32MP1_SHRES_GPIOZ_3,
+ STM32MP1_SHRES_GPIOZ_4,
+ STM32MP1_SHRES_GPIOZ_5,
+ STM32MP1_SHRES_GPIOZ_6,
+ STM32MP1_SHRES_GPIOZ_7,
+ STM32MP1_SHRES_HASH1,
+ STM32MP1_SHRES_I2C4,
+ STM32MP1_SHRES_I2C6,
+ STM32MP1_SHRES_IWDG1,
+ STM32MP1_SHRES_MCU,
+ STM32MP1_SHRES_MDMA,
+ STM32MP1_SHRES_PLL3,
+ STM32MP1_SHRES_RNG1,
+ STM32MP1_SHRES_RTC,
+ STM32MP1_SHRES_SPI6,
+ STM32MP1_SHRES_USART1,
+
+ STM32MP1_SHRES_COUNT
+};
+#endif /* STM32MP1_SHARED_RESOURCES_H */
diff --git a/plat/st/stm32mp1/include/stm32mp1_smc.h b/plat/st/stm32mp1/include/stm32mp1_smc.h
new file mode 100644
index 0000000..52088de
--- /dev/null
+++ b/plat/st/stm32mp1/include/stm32mp1_smc.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016-2021, 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
+
+/*
+ * STM32_SIP_SMC_SCMI_AGENT0
+ * STM32_SIP_SMC_SCMI_AGENT1
+ * Process SCMI message pending in SCMI shared memory buffer.
+ *
+ * Argument a0: (input) SMCC ID
+ */
+#define STM32_SIP_SMC_SCMI_AGENT0 0x82002000
+#define STM32_SIP_SMC_SCMI_AGENT1 0x82002001
+
+/* 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 3
+
+/* 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
+
+/* SMC error codes */
+#define STM32_SMC_OK 0x00000000U
+#define STM32_SMC_NOT_SUPPORTED 0xFFFFFFFFU
+#define STM32_SMC_FAILED 0xFFFFFFFEU
+#define STM32_SMC_INVALID_PARAMS 0xFFFFFFFDU
+
+#endif /* STM32MP1_SMC_H */
diff --git a/plat/st/stm32mp1/include/tbbr/stm32mp1_tbb_cert.h b/plat/st/stm32mp1/include/tbbr/stm32mp1_tbb_cert.h
new file mode 100644
index 0000000..2cc1e19
--- /dev/null
+++ b/plat/st/stm32mp1/include/tbbr/stm32mp1_tbb_cert.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_TBB_CERT_H
+#define STM32MP1_TBB_CERT_H
+
+#include <tbbr/tbb_cert.h>
+
+/*
+ * Enumerate the certificates that are used to establish the chain of trust
+ */
+enum {
+ STM32MP_CONFIG_CERT = FWU_CERT + 1
+};
+
+#endif /* STM32MP1_TBB_CERT_H */
diff --git a/plat/st/stm32mp1/plat_bl2_mem_params_desc.c b/plat/st/stm32mp1/plat_bl2_mem_params_desc.c
new file mode 100644
index 0000000..9ca0930
--- /dev/null
+++ b/plat/st/stm32mp1/plat_bl2_mem_params_desc.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+/*******************************************************************************
+ * 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 FW_CONFIG related information if it exists */
+ {
+ .image_id = 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_PLAT_SETUP),
+
+ .image_info.image_base = STM32MP_FW_CONFIG_BASE,
+ .image_info.image_max_size = STM32MP_FW_CONFIG_MAX_SIZE,
+
+ .next_handoff_image_id = INVALID_IMAGE_ID,
+ },
+
+ /* 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.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_SKIP_LOADING),
+
+ .next_handoff_image_id = BL33_IMAGE_ID,
+ },
+
+ /* 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,
+ },
+#if STM32MP15
+ /* 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
+
+ /* 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 TOS_FW_CONFIG related information if it exists */
+ {
+ .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,
+ },
+
+ /* 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.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_SKIP_LOADING),
+
+ .next_handoff_image_id = INVALID_IMAGE_ID,
+ }
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
diff --git a/plat/st/stm32mp1/plat_def_uuid_config.c b/plat/st/stm32mp1/plat_def_uuid_config.c
new file mode 100644
index 0000000..efaf567
--- /dev/null
+++ b/plat/st/stm32mp1/plat_def_uuid_config.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <firmware_image_package.h>
+
+#include "tbbr_config.h"
+
+toc_entry_t plat_def_toc_entries[] = {
+ {
+ .name = "STM32MP CONFIG CERT",
+ .uuid = UUID_STM32MP_CONFIG_CERT,
+ .cmdline_name = "stm32mp-cfg-cert"
+ }
+};
+
diff --git a/plat/st/stm32mp1/plat_fiptool.mk b/plat/st/stm32mp1/plat_fiptool.mk
new file mode 100644
index 0000000..00570c2
--- /dev/null
+++ b/plat/st/stm32mp1/plat_fiptool.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Name of the platform defined source file name,
+# which contains platform defined UUID entries populated
+# in the plat_def_toc_entries[].
+PLAT_DEF_UUID_FILE_NAME := plat_def_uuid_config
+
+INCLUDE_PATHS += -I${PLAT_DIR}/include -I./
+
+PLAT_DEF_UUID := yes
+
+ifeq (${PLAT_DEF_UUID},yes)
+HOSTCCFLAGS += -DPLAT_DEF_FIP_UUID
+
+${PLAT_DEF_UUID_FILE_NAME}.o: ${PLAT_DIR}${PLAT_DEF_UUID_FILE_NAME}.c
+ ${HOSTCC} -c ${CPPFLAGS} ${HOSTCCFLAGS} ${INCLUDE_PATHS} $< -o $@
+
+PLAT_OBJECTS += ${PLAT_DEF_UUID_FILE_NAME}.o
+endif
+
+OBJECTS += ${PLAT_OBJECTS}
diff --git a/plat/st/stm32mp1/plat_image_load.c b/plat/st/stm32mp1/plat_image_load.c
new file mode 100644
index 0000000..c4048fc
--- /dev/null
+++ b/plat/st/stm32mp1/plat_image_load.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/desc_image_load.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)
+{
+ bl_params_t *bl_params = get_next_bl_params_from_mem_params_desc();
+
+ populate_next_bl_params_config(bl_params);
+
+ return bl_params;
+}
diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk
new file mode 100644
index 0000000..7eecf30
--- /dev/null
+++ b/plat/st/stm32mp1/platform.mk
@@ -0,0 +1,553 @@
+#
+# Copyright (c) 2015-2022, 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
+
+STM32MP_EARLY_CONSOLE ?= 0
+STM32MP_RECONFIGURE_CONSOLE ?= 0
+STM32MP_UART_BAUDRATE ?= 115200
+
+TRUSTED_BOARD_BOOT ?= 0
+STM32MP_USE_EXTERNAL_HEAP ?= 0
+
+# Use secure library from the ROM code for authentication
+STM32MP_CRYPTO_ROM_LIB ?= 0
+
+# Please don't increment this value without good understanding of
+# the monotonic counter
+STM32_TF_VERSION ?= 0
+
+# Enable dynamic memory mapping
+PLAT_XLAT_TABLES_DYNAMIC := 1
+
+# Default Device tree
+DTB_FILE_NAME ?= stm32mp157c-ev1.dtb
+
+STM32MP13 ?= 0
+STM32MP15 ?= 0
+
+ifeq ($(STM32MP13),1)
+ifeq ($(STM32MP15),1)
+$(error Cannot enable both flags STM32MP13 and STM32MP15)
+endif
+STM32MP13 := 1
+STM32MP15 := 0
+else ifeq ($(STM32MP15),1)
+STM32MP13 := 0
+STM32MP15 := 1
+else ifneq ($(findstring stm32mp13,$(DTB_FILE_NAME)),)
+STM32MP13 := 1
+STM32MP15 := 0
+else ifneq ($(findstring stm32mp15,$(DTB_FILE_NAME)),)
+STM32MP13 := 0
+STM32MP15 := 1
+endif
+
+ifeq ($(STM32MP13),1)
+# Will use SRAM2 as mbedtls heap
+STM32MP_USE_EXTERNAL_HEAP := 1
+
+# DDR controller with single AXI port and 16-bit interface
+STM32MP_DDR_DUAL_AXI_PORT:= 0
+STM32MP_DDR_32BIT_INTERFACE:= 0
+
+ifeq (${TRUSTED_BOARD_BOOT},1)
+# PKA algo to include
+PKA_USE_NIST_P256 := 1
+PKA_USE_BRAINPOOL_P256T1:= 1
+endif
+
+# STM32 image header version v2.0
+STM32_HEADER_VERSION_MAJOR:= 2
+STM32_HEADER_VERSION_MINOR:= 0
+endif
+
+ifeq ($(STM32MP15),1)
+# DDR controller with dual AXI port and 32-bit interface
+STM32MP_DDR_DUAL_AXI_PORT:= 1
+STM32MP_DDR_32BIT_INTERFACE:= 1
+
+# STM32 image header version v1.0
+STM32_HEADER_VERSION_MAJOR:= 1
+STM32_HEADER_VERSION_MINOR:= 0
+
+# Add OP-TEE reserved shared memory area in mapping
+STM32MP15_OPTEE_RSV_SHM := 1
+$(eval $(call add_defines,STM32MP15_OPTEE_RSV_SHM))
+
+STM32MP_CRYPTO_ROM_LIB := 1
+
+# Decryption support
+ifneq ($(DECRYPTION_SUPPORT),none)
+$(error "DECRYPTION_SUPPORT not supported on STM32MP15")
+endif
+endif
+
+# STM32 image header binary type for BL2
+STM32_HEADER_BL2_BINARY_TYPE:= 0x10
+
+ifeq ($(AARCH32_SP),sp_min)
+# Disable Neon support: sp_min runtime may conflict with non-secure world
+TF_CFLAGS += -mfloat-abi=soft
+endif
+
+TF_CFLAGS += -Wsign-compare
+TF_CFLAGS += -Wformat-signedness
+
+# Not needed for Cortex-A7
+WORKAROUND_CVE_2017_5715:= 0
+WORKAROUND_CVE_2022_23960:= 0
+
+# Number of TF-A copies in the device
+STM32_TF_A_COPIES := 2
+
+# PLAT_PARTITION_MAX_ENTRIES must take care of STM32_TF-A_COPIES and other partitions
+# such as metadata (2) to find all the FIP partitions (default is 2).
+PLAT_PARTITION_MAX_ENTRIES := $(shell echo $$(($(STM32_TF_A_COPIES) + 4)))
+
+ifeq (${PSA_FWU_SUPPORT},1)
+# Number of banks of updatable firmware
+NR_OF_FW_BANKS := 2
+NR_OF_IMAGES_IN_FW_BANK := 1
+
+FWU_MAX_PART = $(shell echo $$(($(STM32_TF_A_COPIES) + 2 + $(NR_OF_FW_BANKS))))
+ifeq ($(shell test $(FWU_MAX_PART) -gt $(PLAT_PARTITION_MAX_ENTRIES); echo $$?),0)
+$(error "Required partition number is $(FWU_MAX_PART) where PLAT_PARTITION_MAX_ENTRIES is only \
+$(PLAT_PARTITION_MAX_ENTRIES)")
+endif
+endif
+
+ifeq ($(STM32MP13),1)
+STM32_HASH_VER := 4
+STM32_RNG_VER := 4
+else # Assuming STM32MP15
+STM32_HASH_VER := 2
+STM32_RNG_VER := 2
+endif
+
+# Boot devices
+STM32MP_EMMC ?= 0
+STM32MP_SDMMC ?= 0
+STM32MP_RAW_NAND ?= 0
+STM32MP_SPI_NAND ?= 0
+STM32MP_SPI_NOR ?= 0
+STM32MP_EMMC_BOOT ?= 0
+
+# Serial boot devices
+STM32MP_USB_PROGRAMMER ?= 0
+STM32MP_UART_PROGRAMMER ?= 0
+
+# Download load address for serial boot devices
+DWL_BUFFER_BASE ?= 0xC7000000
+
+# Device tree
+ifeq ($(STM32MP13),1)
+BL2_DTSI := stm32mp13-bl2.dtsi
+FDT_SOURCES := $(addprefix ${BUILD_PLAT}/fdts/, $(patsubst %.dtb,%-bl2.dts,$(DTB_FILE_NAME)))
+else
+BL2_DTSI := stm32mp15-bl2.dtsi
+FDT_SOURCES := $(addprefix ${BUILD_PLAT}/fdts/, $(patsubst %.dtb,%-bl2.dts,$(DTB_FILE_NAME)))
+ifeq ($(AARCH32_SP),sp_min)
+BL32_DTSI := stm32mp15-bl32.dtsi
+FDT_SOURCES += $(addprefix ${BUILD_PLAT}/fdts/, $(patsubst %.dtb,%-bl32.dts,$(DTB_FILE_NAME)))
+endif
+endif
+
+$(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" | grep -o "[0-9]*")))
+DTC_CPPFLAGS += ${INCLUDES}
+DTC_FLAGS += -Wno-unit_address_vs_reg
+ifeq ($(shell test $(DTC_VERSION) -ge 10601; echo $$?),0)
+DTC_FLAGS += -Wno-interrupt_provider
+endif
+
+# Macros and rules to build TF binary
+STM32_TF_ELF_LDFLAGS := --hash-style=gnu --as-needed
+STM32_TF_STM32 := $(addprefix ${BUILD_PLAT}/tf-a-, $(patsubst %.dtb,%.stm32,$(DTB_FILE_NAME)))
+STM32_TF_LINKERFILE := ${BUILD_PLAT}/stm32mp1.ld
+
+ASFLAGS += -DBL2_BIN_PATH=\"${BUILD_PLAT}/bl2.bin\"
+ifeq ($(AARCH32_SP),sp_min)
+# BL32 is built only if using SP_MIN
+BL32_DEP := bl32
+ASFLAGS += -DBL32_BIN_PATH=\"${BUILD_PLAT}/bl32.bin\"
+endif
+
+# Variables for use with stm32image
+STM32IMAGEPATH ?= tools/stm32image
+STM32IMAGE ?= ${STM32IMAGEPATH}/stm32image${BIN_EXT}
+STM32IMAGE_SRC := ${STM32IMAGEPATH}/stm32image.c
+
+FIP_DEPS += dtbs
+STM32MP_HW_CONFIG := ${BL33_CFG}
+STM32MP_FW_CONFIG_NAME := $(patsubst %.dtb,%-fw-config.dtb,$(DTB_FILE_NAME))
+STM32MP_FW_CONFIG := ${BUILD_PLAT}/fdts/$(STM32MP_FW_CONFIG_NAME)
+ifneq (${AARCH32_SP},none)
+FDT_SOURCES += $(addprefix fdts/, $(patsubst %.dtb,%.dts,$(STM32MP_FW_CONFIG_NAME)))
+endif
+# Add the FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${STM32MP_FW_CONFIG},--fw-config))
+# Add the HW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${STM32MP_HW_CONFIG},--hw-config))
+ifeq ($(GENERATE_COT),1)
+STM32MP_CFG_CERT := $(BUILD_PLAT)/stm32mp_cfg_cert.crt
+# Add the STM32MP_CFG_CERT to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${STM32MP_CFG_CERT},--stm32mp-cfg-cert))
+endif
+ifeq ($(AARCH32_SP),sp_min)
+STM32MP_TOS_FW_CONFIG := $(addprefix ${BUILD_PLAT}/fdts/, $(patsubst %.dtb,%-bl32.dtb,$(DTB_FILE_NAME)))
+$(eval $(call TOOL_ADD_PAYLOAD,${STM32MP_TOS_FW_CONFIG},--tos-fw-config))
+else
+# 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,,$(ENCRYPT_BL32)))
+endif
+ifneq ($(BL32_EXTRA2),)
+$(eval $(call TOOL_ADD_IMG,BL32_EXTRA2,--tos-fw-extra2,,$(ENCRYPT_BL32)))
+endif
+endif
+
+# Enable flags for C files
+$(eval $(call assert_booleans,\
+ $(sort \
+ PKA_USE_BRAINPOOL_P256T1 \
+ PKA_USE_NIST_P256 \
+ PLAT_TBBR_IMG_DEF \
+ PLAT_XLAT_TABLES_DYNAMIC \
+ STM32MP_CRYPTO_ROM_LIB \
+ STM32MP_DDR_32BIT_INTERFACE \
+ STM32MP_DDR_DUAL_AXI_PORT \
+ STM32MP_EARLY_CONSOLE \
+ STM32MP_EMMC \
+ STM32MP_EMMC_BOOT \
+ STM32MP_RAW_NAND \
+ STM32MP_RECONFIGURE_CONSOLE \
+ STM32MP_SDMMC \
+ STM32MP_SPI_NAND \
+ STM32MP_SPI_NOR \
+ STM32MP_UART_PROGRAMMER \
+ STM32MP_USB_PROGRAMMER \
+ STM32MP_USE_EXTERNAL_HEAP \
+ STM32MP13 \
+ STM32MP15 \
+)))
+
+$(eval $(call assert_numerics,\
+ $(sort \
+ PLAT_PARTITION_MAX_ENTRIES \
+ STM32_HASH_VER \
+ STM32_HEADER_VERSION_MAJOR \
+ STM32_RNG_VER \
+ STM32_TF_A_COPIES \
+ STM32_TF_VERSION \
+ STM32MP_UART_BAUDRATE \
+)))
+
+$(eval $(call add_defines,\
+ $(sort \
+ DWL_BUFFER_BASE \
+ PKA_USE_BRAINPOOL_P256T1 \
+ PKA_USE_NIST_P256 \
+ PLAT_PARTITION_MAX_ENTRIES \
+ PLAT_TBBR_IMG_DEF \
+ PLAT_XLAT_TABLES_DYNAMIC \
+ STM32_HASH_VER \
+ STM32_HEADER_VERSION_MAJOR \
+ STM32_RNG_VER \
+ STM32_TF_A_COPIES \
+ STM32_TF_VERSION \
+ STM32MP_CRYPTO_ROM_LIB \
+ STM32MP_DDR_32BIT_INTERFACE \
+ STM32MP_DDR_DUAL_AXI_PORT \
+ STM32MP_EARLY_CONSOLE \
+ STM32MP_EMMC \
+ STM32MP_EMMC_BOOT \
+ STM32MP_RAW_NAND \
+ STM32MP_RECONFIGURE_CONSOLE \
+ STM32MP_SDMMC \
+ STM32MP_SPI_NAND \
+ STM32MP_SPI_NOR \
+ STM32MP_UART_BAUDRATE \
+ STM32MP_UART_PROGRAMMER \
+ STM32MP_USB_PROGRAMMER \
+ STM32MP_USE_EXTERNAL_HEAP \
+ STM32MP13 \
+ STM32MP15 \
+)))
+
+# Include paths and source files
+PLAT_INCLUDES := -Iplat/st/common/include/
+PLAT_INCLUDES += -Iplat/st/stm32mp1/include/
+
+include lib/fconf/fconf.mk
+include lib/libfdt/libfdt.mk
+
+PLAT_BL_COMMON_SOURCES := common/uuid.c \
+ 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/clk/clk.c \
+ drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ drivers/st/bsec/bsec2.c \
+ drivers/st/clk/stm32mp_clkfunc.c \
+ drivers/st/ddr/stm32mp_ddr.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/regulator/regulator_core.c \
+ drivers/st/regulator/regulator_fixed.c \
+ drivers/st/reset/stm32mp1_reset.c \
+ plat/st/common/stm32mp_dt.c \
+ plat/st/stm32mp1/stm32mp1_dbgmcu.c \
+ plat/st/stm32mp1/stm32mp1_helper.S \
+ plat/st/stm32mp1/stm32mp1_syscfg.c
+
+ifeq ($(STM32MP13),1)
+PLAT_BL_COMMON_SOURCES += drivers/st/clk/clk-stm32-core.c \
+ drivers/st/clk/clk-stm32mp13.c \
+ drivers/st/crypto/stm32_rng.c
+else
+PLAT_BL_COMMON_SOURCES += drivers/st/clk/stm32mp1_clk.c
+endif
+
+BL2_SOURCES += ${FCONF_SOURCES} ${FCONF_DYN_SOURCES}
+
+BL2_SOURCES += drivers/io/io_fip.c \
+ plat/st/common/bl2_io_storage.c \
+ plat/st/common/stm32mp_fconf_io.c \
+ plat/st/stm32mp1/plat_bl2_mem_params_desc.c \
+ plat/st/stm32mp1/stm32mp1_fconf_firewall.c
+
+include lib/zlib/zlib.mk
+
+ifeq (${PSA_FWU_SUPPORT},1)
+include drivers/fwu/fwu.mk
+endif
+
+
+BL2_SOURCES += $(ZLIB_SOURCES)
+
+BL2_SOURCES += drivers/io/io_block.c \
+ drivers/io/io_mtd.c \
+ drivers/io/io_storage.c \
+ drivers/st/crypto/stm32_hash.c \
+ plat/st/stm32mp1/bl2_plat_setup.c
+
+ifneq (${DECRYPTION_SUPPORT},none)
+BL2_SOURCES += drivers/io/io_encrypted.c
+endif
+
+ifeq (${TRUSTED_BOARD_BOOT},1)
+AUTH_SOURCES := drivers/auth/auth_mod.c \
+ drivers/auth/crypto_mod.c \
+ drivers/auth/img_parser_mod.c
+
+ifeq (${GENERATE_COT},1)
+TFW_NVCTR_VAL := 0
+NTFW_NVCTR_VAL := 0
+KEY_SIZE :=
+KEY_ALG := ecdsa
+HASH_ALG := sha256
+
+ifeq (${SAVE_KEYS},1)
+TRUSTED_WORLD_KEY ?= ${BUILD_PLAT}/trusted.pem
+NON_TRUSTED_WORLD_KEY ?= ${BUILD_PLAT}/non-trusted.pem
+BL32_KEY ?= ${BUILD_PLAT}/trusted_os.pem
+BL33_KEY ?= ${BUILD_PLAT}/non-trusted_os.pem
+endif
+
+endif
+TF_MBEDTLS_KEY_ALG := ecdsa
+MBEDTLS_CONFIG_FILE ?= "<stm32mp1_mbedtls_config.h>"
+
+include drivers/auth/mbedtls/mbedtls_x509.mk
+
+COT_DESC_IN_DTB := 1
+AUTH_SOURCES += lib/fconf/fconf_cot_getter.c \
+ lib/fconf/fconf_tbbr_getter.c \
+ plat/st/common/stm32mp_crypto_lib.c
+
+ifeq ($(STM32MP13),1)
+AUTH_SOURCES += drivers/st/crypto/stm32_pka.c
+AUTH_SOURCES += drivers/st/crypto/stm32_saes.c
+endif
+
+BL2_SOURCES += $(AUTH_SOURCES) \
+ plat/st/common/stm32mp_trusted_boot.c
+endif
+
+ifneq ($(filter 1,${STM32MP_EMMC} ${STM32MP_SDMMC}),)
+BL2_SOURCES += drivers/mmc/mmc.c \
+ drivers/partition/gpt.c \
+ drivers/partition/partition.c \
+ drivers/st/io/io_mmc.c \
+ drivers/st/mmc/stm32_sdmmc2.c
+endif
+
+ifeq (${STM32MP_RAW_NAND},1)
+$(eval $(call add_define_val,NAND_ONFI_DETECT,1))
+BL2_SOURCES += drivers/mtd/nand/raw_nand.c \
+ drivers/st/fmc/stm32_fmc2_nand.c
+endif
+
+ifeq (${STM32MP_SPI_NAND},1)
+BL2_SOURCES += drivers/mtd/nand/spi_nand.c
+endif
+
+ifeq (${STM32MP_SPI_NOR},1)
+ifneq (${STM32MP_FORCE_MTD_START_OFFSET},)
+$(eval $(call add_define_val,STM32MP_NOR_FIP_OFFSET,${STM32MP_FORCE_MTD_START_OFFSET}))
+endif
+BL2_SOURCES += drivers/mtd/nor/spi_nor.c
+endif
+
+ifneq ($(filter 1,${STM32MP_SPI_NAND} ${STM32MP_SPI_NOR}),)
+BL2_SOURCES += drivers/mtd/spi-mem/spi_mem.c \
+ drivers/st/spi/stm32_qspi.c
+endif
+
+ifneq ($(filter 1,${STM32MP_RAW_NAND} ${STM32MP_SPI_NAND}),)
+ifneq (${STM32MP_FORCE_MTD_START_OFFSET},)
+$(eval $(call add_define_val,STM32MP_NAND_FIP_OFFSET,${STM32MP_FORCE_MTD_START_OFFSET}))
+endif
+BL2_SOURCES += drivers/mtd/nand/core.c
+endif
+
+ifneq ($(filter 1,${STM32MP_RAW_NAND} ${STM32MP_SPI_NAND} ${STM32MP_SPI_NOR}),)
+BL2_SOURCES += plat/st/stm32mp1/stm32mp1_boot_device.c
+endif
+
+ifneq ($(filter 1,${STM32MP_UART_PROGRAMMER} ${STM32MP_USB_PROGRAMMER}),)
+BL2_SOURCES += drivers/io/io_memmap.c
+endif
+
+ifeq (${STM32MP_UART_PROGRAMMER},1)
+BL2_SOURCES += drivers/st/uart/stm32_uart.c \
+ plat/st/common/stm32cubeprogrammer_uart.c
+endif
+
+ifeq (${STM32MP_USB_PROGRAMMER},1)
+#The DFU stack uses only one end point, reduce the USB stack footprint
+$(eval $(call add_define_val,CONFIG_USBD_EP_NB,1U))
+BL2_SOURCES += drivers/st/usb/stm32mp1_usb.c \
+ drivers/usb/usb_device.c \
+ plat/st/common/stm32cubeprogrammer_usb.c \
+ plat/st/common/usb_dfu.c \
+ plat/st/stm32mp1/stm32mp1_usb_dfu.c
+endif
+
+BL2_SOURCES += drivers/st/ddr/stm32mp_ddr_test.c \
+ drivers/st/ddr/stm32mp_ram.c \
+ drivers/st/ddr/stm32mp1_ddr.c \
+ drivers/st/ddr/stm32mp1_ram.c
+
+BL2_SOURCES += common/desc_image_load.c \
+ plat/st/stm32mp1/plat_image_load.c
+
+BL2_SOURCES += lib/optee/optee_utils.c
+
+# Compilation rules
+.PHONY: check_dtc_version stm32image clean_stm32image check_boot_device
+.SUFFIXES:
+
+all: check_dtc_version stm32image ${STM32_TF_STM32}
+
+distclean realclean clean: clean_stm32image
+
+bl2: check_boot_device
+
+check_boot_device:
+ @if [ ${STM32MP_EMMC} != 1 ] && \
+ [ ${STM32MP_SDMMC} != 1 ] && \
+ [ ${STM32MP_RAW_NAND} != 1 ] && \
+ [ ${STM32MP_SPI_NAND} != 1 ] && \
+ [ ${STM32MP_SPI_NOR} != 1 ] && \
+ [ ${STM32MP_UART_PROGRAMMER} != 1 ] && \
+ [ ${STM32MP_USB_PROGRAMMER} != 1 ]; then \
+ echo "No boot device driver is enabled"; \
+ false; \
+ fi
+
+stm32image: ${STM32IMAGE}
+
+${STM32IMAGE}: ${STM32IMAGE_SRC}
+ ${Q}${MAKE} CPPFLAGS="" --no-print-directory -C ${STM32IMAGEPATH}
+
+clean_stm32image:
+ ${Q}${MAKE} --no-print-directory -C ${STM32IMAGEPATH} clean
+
+check_dtc_version:
+ @if [ ${DTC_VERSION} -lt 10404 ]; then \
+ echo "dtc version too old (${DTC_V}), you need at least version 1.4.4"; \
+ false; \
+ fi
+
+# Create DTB file for BL2
+${BUILD_PLAT}/fdts/%-bl2.dts: fdts/%.dts fdts/${BL2_DTSI} | ${BUILD_PLAT} fdt_dirs
+ @echo '#include "$(patsubst fdts/%,%,$<)"' > $@
+ @echo '#include "${BL2_DTSI}"' >> $@
+
+${BUILD_PLAT}/fdts/%-bl2.dtb: ${BUILD_PLAT}/fdts/%-bl2.dts
+
+ifeq ($(AARCH32_SP),sp_min)
+# Create DTB file for BL32
+${BUILD_PLAT}/fdts/%-bl32.dts: fdts/%.dts fdts/${BL32_DTSI} | ${BUILD_PLAT} fdt_dirs
+ @echo '#include "$(patsubst fdts/%,%,$<)"' > $@
+ @echo '#include "${BL32_DTSI}"' >> $@
+
+${BUILD_PLAT}/fdts/%-bl32.dtb: ${BUILD_PLAT}/fdts/%-bl32.dts
+endif
+
+${BUILD_PLAT}/stm32mp1-%.o: ${BUILD_PLAT}/fdts/%-bl2.dtb plat/st/stm32mp1/stm32mp1.S bl2
+ @echo " AS stm32mp1.S"
+ ${Q}${AS} ${ASFLAGS} ${TF_CFLAGS} \
+ -DDTB_BIN_PATH=\"$<\" \
+ -c plat/st/stm32mp1/stm32mp1.S -o $@
+
+$(eval $(call MAKE_LD,${STM32_TF_LINKERFILE},plat/st/stm32mp1/stm32mp1.ld.S,bl2))
+
+tf-a-%.elf: stm32mp1-%.o ${STM32_TF_LINKERFILE}
+ @echo " LDS $<"
+ ${Q}${LD} -o $@ ${STM32_TF_ELF_LDFLAGS} -Map=$(@:.elf=.map) --script ${STM32_TF_LINKERFILE} $<
+
+tf-a-%.bin: tf-a-%.elf
+ ${Q}${OC} -O binary $< $@
+ @echo
+ @echo "Built $@ successfully"
+ @echo
+
+tf-a-%.stm32: ${STM32IMAGE} tf-a-%.bin
+ @echo
+ @echo "Generate $@"
+ $(eval LOADADDR = $(shell cat $(@:.stm32=.map) | grep RAM | awk '{print $$2}'))
+ $(eval ENTRY = $(shell cat $(@:.stm32=.map) | grep "__BL2_IMAGE_START" | awk '{print $$1}'))
+ ${Q}${STM32IMAGE} -s $(word 2,$^) -d $@ \
+ -l $(LOADADDR) -e ${ENTRY} \
+ -v ${STM32_TF_VERSION} \
+ -m ${STM32_HEADER_VERSION_MAJOR} \
+ -n ${STM32_HEADER_VERSION_MINOR} \
+ -b ${STM32_HEADER_BL2_BINARY_TYPE}
+ @echo
diff --git a/plat/st/stm32mp1/services/bsec_svc.c b/plat/st/stm32mp1/services/bsec_svc.c
new file mode 100644
index 0000000..1fb44b4
--- /dev/null
+++ b/plat/st/stm32mp1/services/bsec_svc.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/st/bsec.h>
+#include <drivers/st/bsec2_reg.h>
+
+#include <stm32mp1_smc.h>
+
+#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 = 0U;
+ result = bsec_write_otp(x3, x2);
+ break;
+ case STM32_SMC_READ_OTP:
+ *ret_otp_value = 0U;
+ 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:
+ return STM32_SMC_INVALID_PARAMS;
+ }
+
+ return (result == BSEC_OK) ? STM32_SMC_OK : STM32_SMC_FAILED;
+}
diff --git a/plat/st/stm32mp1/services/bsec_svc.h b/plat/st/stm32mp1/services/bsec_svc.h
new file mode 100644
index 0000000..06752ef
--- /dev/null
+++ b/plat/st/stm32mp1/services/bsec_svc.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BSEC_SVC_H
+#define BSEC_SVC_H
+
+#include <stdint.h>
+
+/* version of this service */
+/* must be increase at each structure modification */
+#define BSEC_SERVICE_VERSION 0x01U
+
+uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3,
+ uint32_t *ret_otp_value);
+
+#endif /* BSEC_SVC_H */
diff --git a/plat/st/stm32mp1/services/stm32mp1_svc_setup.c b/plat/st/stm32mp1/services/stm32mp1_svc_setup.c
new file mode 100644
index 0000000..ed8a448
--- /dev/null
+++ b/plat/st/stm32mp1/services/stm32mp1_svc_setup.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014-2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <drivers/scmi-msg.h>
+#include <lib/psci/psci.h>
+#include <tools_share/uuid.h>
+
+#include <stm32mp1_smc.h>
+
+#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;
+
+ case STM32_SIP_SMC_SCMI_AGENT0:
+ scmi_smt_fastcall_smc_entry(0);
+ break;
+ case STM32_SIP_SMC_SCMI_AGENT1:
+ scmi_smt_fastcall_smc_entry(1);
+ break;
+
+ default:
+ WARN("Unimplemented STM32MP1 Service Call: 0x%x\n", smc_fid);
+ ret1 = STM32_SMC_NOT_SUPPORTED;
+ break;
+ }
+
+ if (ret_uid) {
+ SMC_UUID_RET(handle, stm32_sip_svc_uid);
+ }
+
+ if (ret2_enabled) {
+ SMC_RET2(handle, ret1, ret2);
+ }
+
+ SMC_RET1(handle, ret1);
+}
+
+/* Register Standard Service Calls as runtime service */
+DECLARE_RT_SVC(stm32mp1_sip_svc,
+ OEN_SIP_START,
+ OEN_SIP_END,
+ SMC_TYPE_FAST,
+ stm32mp1_svc_setup,
+ stm32mp1_svc_smc_handler
+);
diff --git a/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk
new file mode 100644
index 0000000..1d754d9
--- /dev/null
+++ b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk
@@ -0,0 +1,53 @@
+#
+# Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq ($(STM32MP13),1)
+$(error "SP_min is not supported on STM32MP13 platform")
+endif
+
+SP_MIN_WITH_SECURE_FIQ := 1
+
+override ENABLE_PIE := 1
+BL32_CFLAGS += -fpie -DENABLE_PIE
+BL32_LDFLAGS += $(PIE_LDFLAGS)
+
+BL32_CFLAGS += -DSTM32MP_SHARED_RESOURCES
+
+BL32_SOURCES += drivers/st/etzpc/etzpc.c \
+ 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_shared_resources.c \
+ plat/st/stm32mp1/stm32mp1_topology.c
+
+# FDT wrappers
+include common/fdt_wrappers.mk
+BL32_SOURCES += ${FDT_WRAPPERS_SOURCES}
+
+# Generic GIC v2
+include drivers/arm/gic/v2/gicv2.mk
+
+BL32_SOURCES += ${GICV2_SOURCES} \
+ plat/common/plat_gicv2.c \
+ plat/st/stm32mp1/stm32mp1_gic.c
+
+# Generic PSCI
+BL32_SOURCES += plat/common/plat_psci_common.c
+
+# SCMI server drivers
+BL32_SOURCES += drivers/scmi-msg/base.c \
+ drivers/scmi-msg/clock.c \
+ drivers/scmi-msg/entry.c \
+ drivers/scmi-msg/reset_domain.c \
+ drivers/scmi-msg/smt.c
+
+# stm32mp1 specific services
+BL32_SOURCES += plat/st/stm32mp1/services/bsec_svc.c \
+ plat/st/stm32mp1/services/stm32mp1_svc_setup.c \
+ plat/st/stm32mp1/stm32mp1_scmi.c
+
+# Arm Archtecture services
+BL32_SOURCES += services/arm_arch_svc/arm_arch_svc_setup.c
diff --git a/plat/st/stm32mp1/sp_min/sp_min_setup.c b/plat/st/stm32mp1/sp_min/sp_min_setup.c
new file mode 100644
index 0000000..50b0794
--- /dev/null
+++ b/plat/st/stm32mp1/sp_min/sp_min_setup.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/tzc400.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/st/bsec.h>
+#include <drivers/st/etzpc.h>
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32_iwdg.h>
+#include <drivers/st/stm32mp1_clk.h>
+#include <dt-bindings/clock/stm32mp1-clks.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include <platform_sp_min.h>
+
+/******************************************************************************
+ * Placeholder variables for copying the arguments that have been passed to
+ * BL32 from BL2.
+ ******************************************************************************/
+static entry_point_info_t bl33_image_ep_info;
+
+/*******************************************************************************
+ * Interrupt handler for FIQ (secure IRQ)
+ ******************************************************************************/
+void sp_min_plat_fiq_handler(uint32_t id)
+{
+ (void)plat_crash_console_init();
+
+ switch (id & INT_ID_MASK) {
+ case STM32MP1_IRQ_TZC400:
+ tzc400_init(STM32MP1_TZC_BASE);
+ (void)tzc400_it_handler();
+ panic();
+ break;
+ case STM32MP1_IRQ_AXIERRIRQ:
+ ERROR("STM32MP1_IRQ_AXIERRIRQ generated\n");
+ panic();
+ break;
+ default:
+ ERROR("SECURE IT handler not define for it : %u\n", 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;
+}
+
+CASSERT((STM32MP_SEC_SYSRAM_BASE == STM32MP_SYSRAM_BASE) &&
+ ((STM32MP_SEC_SYSRAM_BASE + STM32MP_SEC_SYSRAM_SIZE) <=
+ (STM32MP_SYSRAM_BASE + STM32MP_SYSRAM_SIZE)),
+ assert_secure_sysram_fits_at_begining_of_sysram);
+
+#ifdef STM32MP_NS_SYSRAM_BASE
+CASSERT((STM32MP_NS_SYSRAM_BASE >= STM32MP_SEC_SYSRAM_BASE) &&
+ ((STM32MP_NS_SYSRAM_BASE + STM32MP_NS_SYSRAM_SIZE) ==
+ (STM32MP_SYSRAM_BASE + STM32MP_SYSRAM_SIZE)),
+ assert_non_secure_sysram_fits_at_end_of_sysram);
+
+CASSERT((STM32MP_NS_SYSRAM_BASE & (PAGE_SIZE_4KB - U(1))) == 0U,
+ assert_non_secure_sysram_base_is_4kbyte_aligned);
+
+#define TZMA1_SECURE_RANGE \
+ (((STM32MP_NS_SYSRAM_BASE - STM32MP_SYSRAM_BASE) >> FOUR_KB_SHIFT) - 1U)
+#else
+#define TZMA1_SECURE_RANGE STM32MP1_ETZPC_TZMA_ALL_SECURE
+#endif /* STM32MP_NS_SYSRAM_BASE */
+#define TZMA0_SECURE_RANGE STM32MP1_ETZPC_TZMA_ALL_SECURE
+
+static void stm32mp1_etzpc_early_setup(void)
+{
+ if (etzpc_init() != 0) {
+ panic();
+ }
+
+ etzpc_configure_tzma(STM32MP1_ETZPC_TZMA_ROM, TZMA0_SECURE_RANGE);
+ etzpc_configure_tzma(STM32MP1_ETZPC_TZMA_SYSRAM, TZMA1_SECURE_RANGE);
+}
+
+/*******************************************************************************
+ * Perform any BL32 specific platform actions.
+ ******************************************************************************/
+void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3)
+{
+ bl_params_t *params_from_bl2 = (bl_params_t *)arg0;
+ uintptr_t dt_addr = arg1;
+
+ stm32mp_setup_early_console();
+
+ /* 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;
+ /*
+ * Check if hw_configuration is given to BL32 and
+ * share it to BL33.
+ */
+ if (arg2 != 0U) {
+ bl33_image_ep_info.args.arg0 = 0U;
+ bl33_image_ep_info.args.arg1 = 0U;
+ bl33_image_ep_info.args.arg2 = arg2;
+ }
+
+ break;
+ }
+
+ bl_params = bl_params->next_params_info;
+ }
+
+ if (dt_open_and_check(dt_addr) < 0) {
+ panic();
+ }
+
+ if (bsec_probe() != 0) {
+ panic();
+ }
+
+ if (stm32mp1_clk_probe() < 0) {
+ panic();
+ }
+
+ (void)stm32mp_uart_console_setup();
+
+ stm32mp1_etzpc_early_setup();
+}
+
+/*******************************************************************************
+ * Initialize the MMU, security and the GIC.
+ ******************************************************************************/
+void sp_min_platform_setup(void)
+{
+ generic_delay_timer_init();
+
+ stm32mp1_gic_init();
+
+ if (stm32_iwdg_init() < 0) {
+ panic();
+ }
+
+ stm32mp_lock_periph_registering();
+
+ stm32mp1_init_scmi_server();
+}
+
+void sp_min_plat_arch_setup(void)
+{
+}
diff --git a/plat/st/stm32mp1/stm32mp1.S b/plat/st/stm32mp1/stm32mp1.S
new file mode 100644
index 0000000..aee4f0e
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1.S
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+.section .bl2_image
+.incbin BL2_BIN_PATH
+
+.section .dtb_image
+.incbin DTB_BIN_PATH
diff --git a/plat/st/stm32mp1/stm32mp1.ld.S b/plat/st/stm32mp1/stm32mp1.ld.S
new file mode 100644
index 0000000..1be8219
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1.ld.S
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_LD_S
+#define STM32MP1_LD_S
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <platform_def.h>
+
+OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
+OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
+
+ENTRY(__BL2_IMAGE_START__)
+
+MEMORY {
+ HEADER (rw) : ORIGIN = 0x00000000, LENGTH = STM32MP_HEADER_RESERVED_SIZE
+ 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_BL2_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.
+ */
+#if SEPARATE_CODE_AND_RODATA
+ . = ( STM32MP_BL2_RO_BASE - STM32MP_BINARY_BASE );
+#else
+ . = ( STM32MP_BL2_BASE - STM32MP_BINARY_BASE );
+#endif
+ __BL2_IMAGE_START__ = .;
+ *(.bl2_image*)
+ __BL2_IMAGE_END__ = .;
+
+ __DATA_END__ = .;
+ } >RAM
+
+ __TF_END__ = .;
+
+}
+#endif /* STM32MP1_LD_S */
diff --git a/plat/st/stm32mp1/stm32mp1_boot_device.c b/plat/st/stm32mp1/stm32mp1_boot_device.c
new file mode 100644
index 0000000..3a8a27a
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_boot_device.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/nand.h>
+#include <drivers/raw_nand.h>
+#include <drivers/spi_nand.h>
+#include <drivers/spi_nor.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#if STM32MP_RAW_NAND || STM32MP_SPI_NAND
+#if STM32MP13
+void plat_get_scratch_buffer(void **buffer_addr, size_t *buf_size)
+{
+ assert(buffer_addr != NULL);
+ assert(buf_size != NULL);
+
+ *buffer_addr = (void *)STM32MP_MTD_BUFFER;
+ *buf_size = PLATFORM_MTD_MAX_PAGE_SIZE;
+}
+#endif
+
+static int get_data_from_otp(struct nand_device *nand_dev, bool is_slc)
+{
+ uint32_t nand_param;
+ uint32_t nand2_param __maybe_unused;
+
+ /* Check if NAND parameters are stored in OTP */
+ if (stm32_get_otp_value(NAND_OTP, &nand_param) != 0) {
+ ERROR("BSEC: NAND_OTP Error\n");
+ return -EACCES;
+ }
+
+ if (nand_param == 0U) {
+#if STM32MP13
+ if (is_slc) {
+ return 0;
+ }
+#endif
+#if STM32MP15
+ return 0;
+#endif
+ }
+
+ if ((nand_param & NAND_PARAM_STORED_IN_OTP) == 0U) {
+#if STM32MP13
+ if (is_slc) {
+ goto ecc;
+ }
+#endif
+#if STM32MP15
+ goto ecc;
+#endif
+ }
+
+#if STM32MP13
+ if (stm32_get_otp_value(NAND2_OTP, &nand2_param) != 0) {
+ ERROR("BSEC: NAND_OTP Error\n");
+ return -EACCES;
+ }
+
+ /* Check OTP configuration for this device */
+ if ((((nand2_param & NAND2_CONFIG_DISTRIB) == NAND2_PNAND_NAND1_SNAND_NAND2) && !is_slc) ||
+ (((nand2_param & NAND2_CONFIG_DISTRIB) == NAND2_PNAND_NAND2_SNAND_NAND1) && is_slc)) {
+ nand_param = nand2_param << (NAND_PAGE_SIZE_SHIFT - NAND2_PAGE_SIZE_SHIFT);
+ }
+#endif
+
+ /* NAND parameter shall be read from OTP */
+ if ((nand_param & NAND_WIDTH_MASK) != 0U) {
+ nand_dev->buswidth = NAND_BUS_WIDTH_16;
+ } else {
+ nand_dev->buswidth = NAND_BUS_WIDTH_8;
+ }
+
+ switch ((nand_param & NAND_PAGE_SIZE_MASK) >> NAND_PAGE_SIZE_SHIFT) {
+ case NAND_PAGE_SIZE_2K:
+ nand_dev->page_size = 0x800U;
+ break;
+
+ case NAND_PAGE_SIZE_4K:
+ nand_dev->page_size = 0x1000U;
+ break;
+
+ case NAND_PAGE_SIZE_8K:
+ nand_dev->page_size = 0x2000U;
+ break;
+
+ default:
+ ERROR("Cannot read NAND page size\n");
+ return -EINVAL;
+ }
+
+ switch ((nand_param & NAND_BLOCK_SIZE_MASK) >> NAND_BLOCK_SIZE_SHIFT) {
+ case NAND_BLOCK_SIZE_64_PAGES:
+ nand_dev->block_size = 64U * nand_dev->page_size;
+ break;
+
+ case NAND_BLOCK_SIZE_128_PAGES:
+ nand_dev->block_size = 128U * nand_dev->page_size;
+ break;
+
+ case NAND_BLOCK_SIZE_256_PAGES:
+ nand_dev->block_size = 256U * nand_dev->page_size;
+ break;
+
+ default:
+ ERROR("Cannot read NAND block size\n");
+ return -EINVAL;
+ }
+
+ nand_dev->size = ((nand_param & NAND_BLOCK_NB_MASK) >>
+ NAND_BLOCK_NB_SHIFT) *
+ NAND_BLOCK_NB_UNIT * nand_dev->block_size;
+
+ecc:
+ if (is_slc) {
+ switch ((nand_param & NAND_ECC_BIT_NB_MASK) >>
+ NAND_ECC_BIT_NB_SHIFT) {
+ case NAND_ECC_BIT_NB_1_BITS:
+ nand_dev->ecc.max_bit_corr = 1U;
+ break;
+
+ case NAND_ECC_BIT_NB_4_BITS:
+ nand_dev->ecc.max_bit_corr = 4U;
+ break;
+
+ case NAND_ECC_BIT_NB_8_BITS:
+ nand_dev->ecc.max_bit_corr = 8U;
+ break;
+
+ case NAND_ECC_ON_DIE:
+ nand_dev->ecc.mode = NAND_ECC_ONDIE;
+ break;
+
+ default:
+ if (nand_dev->ecc.max_bit_corr == 0U) {
+ ERROR("No valid eccbit number\n");
+ return -EINVAL;
+ }
+ }
+ } else {
+ /* Selected multiple plane NAND */
+ if ((nand_param & NAND_PLANE_BIT_NB_MASK) != 0U) {
+ nand_dev->nb_planes = 2U;
+ } else {
+ nand_dev->nb_planes = 1U;
+ }
+ }
+
+ VERBOSE("OTP: Block %u Page %u Size %llu\n", nand_dev->block_size,
+ nand_dev->page_size, nand_dev->size);
+
+ return 0;
+}
+#endif /* STM32MP_RAW_NAND || STM32MP_SPI_NAND */
+
+#if STM32MP_RAW_NAND
+int plat_get_raw_nand_data(struct rawnand_device *device)
+{
+ device->nand_dev->ecc.mode = NAND_ECC_HW;
+ device->nand_dev->ecc.size = SZ_512;
+
+ return get_data_from_otp(device->nand_dev, true);
+}
+#endif
+
+#if STM32MP_SPI_NAND
+int plat_get_spi_nand_data(struct spinand_device *device)
+{
+ zeromem(&device->spi_read_cache_op, sizeof(struct spi_mem_op));
+ device->spi_read_cache_op.cmd.opcode = SPI_NAND_OP_READ_FROM_CACHE_4X;
+ device->spi_read_cache_op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->spi_read_cache_op.addr.nbytes = 2U;
+ device->spi_read_cache_op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->spi_read_cache_op.dummy.nbytes = 1U;
+ device->spi_read_cache_op.dummy.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->spi_read_cache_op.data.buswidth = SPI_MEM_BUSWIDTH_4_LINE;
+ device->spi_read_cache_op.data.dir = SPI_MEM_DATA_IN;
+
+ return get_data_from_otp(device->nand_dev, false);
+}
+#endif
+
+#if STM32MP_SPI_NOR
+int plat_get_nor_data(struct nor_device *device)
+{
+ device->size = SZ_64M;
+
+ zeromem(&device->read_op, sizeof(struct spi_mem_op));
+ device->read_op.cmd.opcode = SPI_NOR_OP_READ_1_1_4;
+ device->read_op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->read_op.addr.nbytes = 3U;
+ device->read_op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->read_op.dummy.nbytes = 1U;
+ device->read_op.dummy.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->read_op.data.buswidth = SPI_MEM_BUSWIDTH_4_LINE;
+ device->read_op.data.dir = SPI_MEM_DATA_IN;
+
+ return 0;
+}
+#endif
diff --git a/plat/st/stm32mp1/stm32mp1_dbgmcu.c b/plat/st/stm32mp1/stm32mp1_dbgmcu.c
new file mode 100644
index 0000000..08e332a
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_dbgmcu.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/st/bsec.h>
+#include <drivers/st/bsec2_reg.h>
+#include <drivers/st/stm32mp1_rcc.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include <platform_def.h>
+#include <stm32mp1_dbgmcu.h>
+
+#define DBGMCU_IDC U(0x00)
+
+#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
+
+static int stm32mp1_dbgmcu_init(void)
+{
+ if ((bsec_read_debug_conf() & BSEC_DBGSWGEN) == 0U) {
+ INFO("Software access to all debug components is disabled\n");
+ return -1;
+ }
+
+ mmio_setbits_32(RCC_BASE + RCC_DBGCFGR, RCC_DBGCFGR_DBGCKEN);
+
+ return 0;
+}
+
+/*
+ * @brief Get silicon revision from DBGMCU registers.
+ * @param chip_version: pointer to the read value.
+ * @retval 0 on success, negative value on failure.
+ */
+int stm32mp1_dbgmcu_get_chip_version(uint32_t *chip_version)
+{
+ assert(chip_version != NULL);
+
+ if (stm32mp1_dbgmcu_init() != 0) {
+ return -EPERM;
+ }
+
+ *chip_version = (mmio_read_32(DBGMCU_BASE + DBGMCU_IDC) &
+ DBGMCU_IDC_REV_ID_MASK) >> DBGMCU_IDC_REV_ID_SHIFT;
+
+ return 0;
+}
+
+/*
+ * @brief Get device ID from DBGMCU registers.
+ * @param chip_dev_id: pointer to the read value.
+ * @retval 0 on success, negative value on failure.
+ */
+int stm32mp1_dbgmcu_get_chip_dev_id(uint32_t *chip_dev_id)
+{
+ assert(chip_dev_id != NULL);
+
+ if (stm32mp1_dbgmcu_init() != 0) {
+ return -EPERM;
+ }
+
+ *chip_dev_id = mmio_read_32(DBGMCU_BASE + DBGMCU_IDC) &
+ DBGMCU_IDC_DEV_ID_MASK;
+
+ return 0;
+}
diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h
new file mode 100644
index 0000000..f0d8526
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_def.h
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_DEF_H
+#define STM32MP1_DEF_H
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/st/stm32mp1_rcc.h>
+#include <dt-bindings/clock/stm32mp1-clks.h>
+#include <dt-bindings/reset/stm32mp1-resets.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#ifndef __ASSEMBLER__
+#include <drivers/st/bsec.h>
+#include <drivers/st/stm32mp1_clk.h>
+
+#include <boot_api.h>
+#include <stm32mp_common.h>
+#include <stm32mp_dt.h>
+#include <stm32mp1_dbgmcu.h>
+#include <stm32mp1_private.h>
+#include <stm32mp1_shared_resources.h>
+#endif
+
+#include "stm32mp1_fip_def.h"
+
+/*******************************************************************************
+ * CHIP ID
+ ******************************************************************************/
+#if STM32MP13
+#define STM32MP1_CHIP_ID U(0x501)
+
+#define STM32MP135C_PART_NB U(0x05010000)
+#define STM32MP135A_PART_NB U(0x05010001)
+#define STM32MP133C_PART_NB U(0x050100C0)
+#define STM32MP133A_PART_NB U(0x050100C1)
+#define STM32MP131C_PART_NB U(0x050106C8)
+#define STM32MP131A_PART_NB U(0x050106C9)
+#define STM32MP135F_PART_NB U(0x05010800)
+#define STM32MP135D_PART_NB U(0x05010801)
+#define STM32MP133F_PART_NB U(0x050108C0)
+#define STM32MP133D_PART_NB U(0x050108C1)
+#define STM32MP131F_PART_NB U(0x05010EC8)
+#define STM32MP131D_PART_NB U(0x05010EC9)
+#endif
+#if STM32MP15
+#define STM32MP1_CHIP_ID U(0x500)
+
+#define STM32MP157C_PART_NB U(0x05000000)
+#define STM32MP157A_PART_NB U(0x05000001)
+#define STM32MP153C_PART_NB U(0x05000024)
+#define STM32MP153A_PART_NB U(0x05000025)
+#define STM32MP151C_PART_NB U(0x0500002E)
+#define STM32MP151A_PART_NB U(0x0500002F)
+#define STM32MP157F_PART_NB U(0x05000080)
+#define STM32MP157D_PART_NB U(0x05000081)
+#define STM32MP153F_PART_NB U(0x050000A4)
+#define STM32MP153D_PART_NB U(0x050000A5)
+#define STM32MP151F_PART_NB U(0x050000AE)
+#define STM32MP151D_PART_NB U(0x050000AF)
+#endif
+
+#define STM32MP1_REV_B U(0x2000)
+#if STM32MP13
+#define STM32MP1_REV_Y U(0x1003)
+#define STM32MP1_REV_Z U(0x1001)
+#endif
+#if STM32MP15
+#define STM32MP1_REV_Z U(0x2001)
+#endif
+
+/*******************************************************************************
+ * PACKAGE ID
+ ******************************************************************************/
+#if STM32MP15
+#define PKG_AA_LFBGA448 U(4)
+#define PKG_AB_LFBGA354 U(3)
+#define PKG_AC_TFBGA361 U(2)
+#define PKG_AD_TFBGA257 U(1)
+#endif
+
+/*******************************************************************************
+ * STM32MP1 memory map related constants
+ ******************************************************************************/
+#define STM32MP_ROM_BASE U(0x00000000)
+#define STM32MP_ROM_SIZE U(0x00020000)
+#define STM32MP_ROM_SIZE_2MB_ALIGNED U(0x00200000)
+
+#if STM32MP13
+#define STM32MP_SYSRAM_BASE U(0x2FFE0000)
+#define STM32MP_SYSRAM_SIZE U(0x00020000)
+#define SRAM1_BASE U(0x30000000)
+#define SRAM1_SIZE U(0x00004000)
+#define SRAM2_BASE U(0x30004000)
+#define SRAM2_SIZE U(0x00002000)
+#define SRAM3_BASE U(0x30006000)
+#define SRAM3_SIZE U(0x00002000)
+#define SRAMS_BASE SRAM1_BASE
+#define SRAMS_SIZE_2MB_ALIGNED U(0x00200000)
+#endif /* STM32MP13 */
+#if STM32MP15
+#define STM32MP_SYSRAM_BASE U(0x2FFC0000)
+#define STM32MP_SYSRAM_SIZE U(0x00040000)
+#endif /* STM32MP15 */
+
+#define STM32MP_NS_SYSRAM_SIZE PAGE_SIZE
+#define STM32MP_NS_SYSRAM_BASE (STM32MP_SYSRAM_BASE + \
+ STM32MP_SYSRAM_SIZE - \
+ STM32MP_NS_SYSRAM_SIZE)
+
+#define STM32MP_SCMI_NS_SHM_BASE STM32MP_NS_SYSRAM_BASE
+#define STM32MP_SCMI_NS_SHM_SIZE STM32MP_NS_SYSRAM_SIZE
+
+#define STM32MP_SEC_SYSRAM_BASE STM32MP_SYSRAM_BASE
+#define STM32MP_SEC_SYSRAM_SIZE (STM32MP_SYSRAM_SIZE - \
+ STM32MP_NS_SYSRAM_SIZE)
+
+/* DDR configuration */
+#define STM32MP_DDR_BASE U(0xC0000000)
+#define STM32MP_DDR_MAX_SIZE U(0x40000000) /* Max 1GB */
+
+/* DDR power initializations */
+#ifndef __ASSEMBLER__
+enum ddr_type {
+ STM32MP_DDR3,
+ STM32MP_LPDDR2,
+ STM32MP_LPDDR3
+};
+#endif
+
+/* Section used inside TF binaries */
+#if STM32MP13
+/* 512 Octets reserved for header */
+#define STM32MP_HEADER_RESERVED_SIZE U(0x200)
+
+#define STM32MP_BINARY_BASE STM32MP_SEC_SYSRAM_BASE
+
+#define STM32MP_BINARY_SIZE STM32MP_SEC_SYSRAM_SIZE
+#endif
+#if STM32MP15
+#define STM32MP_PARAM_LOAD_SIZE U(0x00002400) /* 9 KB for param */
+/* 256 Octets reserved for header */
+#define STM32MP_HEADER_SIZE U(0x00000100)
+/* round_up(STM32MP_PARAM_LOAD_SIZE + STM32MP_HEADER_SIZE, PAGE_SIZE) */
+#define STM32MP_HEADER_RESERVED_SIZE U(0x3000)
+
+#define STM32MP_BINARY_BASE (STM32MP_SEC_SYSRAM_BASE + \
+ STM32MP_PARAM_LOAD_SIZE + \
+ STM32MP_HEADER_SIZE)
+
+#define STM32MP_BINARY_SIZE (STM32MP_SEC_SYSRAM_SIZE - \
+ (STM32MP_PARAM_LOAD_SIZE + \
+ STM32MP_HEADER_SIZE))
+#endif
+
+/* BL2 and BL32/sp_min require finer granularity tables */
+#if defined(IMAGE_BL2)
+#define MAX_XLAT_TABLES U(2) /* 8 KB for mapping */
+#endif
+
+#if defined(IMAGE_BL32)
+#define MAX_XLAT_TABLES U(4) /* 16 KB for mapping */
+#endif
+
+/*
+ * MAX_MMAP_REGIONS is usually:
+ * BL stm32mp1_mmap size + mmap regions in *_plat_arch_setup
+ */
+#if defined(IMAGE_BL2)
+ #if STM32MP_USB_PROGRAMMER
+ #define MAX_MMAP_REGIONS 8
+ #else
+ #define MAX_MMAP_REGIONS 7
+ #endif
+#endif
+
+#if STM32MP13
+#define STM32MP_BL33_BASE STM32MP_DDR_BASE
+#endif
+#if STM32MP15
+#define STM32MP_BL33_BASE (STM32MP_DDR_BASE + U(0x100000))
+#endif
+#define STM32MP_BL33_MAX_SIZE U(0x400000)
+
+/* Define maximum page size for NAND devices */
+#define PLATFORM_MTD_MAX_PAGE_SIZE U(0x1000)
+
+/* Define location for the MTD scratch buffer */
+#if STM32MP13
+#define STM32MP_MTD_BUFFER (SRAM1_BASE + \
+ SRAM1_SIZE - \
+ PLATFORM_MTD_MAX_PAGE_SIZE)
+#endif
+/*******************************************************************************
+ * 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)
+#if STM32MP15
+#define GPIOJ_BASE U(0x5000B000)
+#define GPIOK_BASE U(0x5000C000)
+#define GPIOZ_BASE U(0x54004000)
+#endif
+#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)
+#if STM32MP15
+#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
+#endif
+
+/*******************************************************************************
+ * STM32MP1 UART
+ ******************************************************************************/
+#if STM32MP13
+#define USART1_BASE U(0x4C000000)
+#define USART2_BASE U(0x4C001000)
+#endif
+#if STM32MP15
+#define USART1_BASE U(0x5C000000)
+#define USART2_BASE U(0x4000E000)
+#endif
+#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)
+
+/* For UART crash console */
+#define STM32MP_DEBUG_USART_BASE UART4_BASE
+#if STM32MP13
+/* UART4 on HSI@64MHz, TX on GPIOF12 Alternate 8 (Disco board) */
+#define STM32MP_DEBUG_USART_CLK_FRQ 64000000
+#define DEBUG_UART_TX_GPIO_BANK_ADDRESS GPIOD_BASE
+#define DEBUG_UART_TX_GPIO_BANK_CLK_REG RCC_MP_S_AHB4ENSETR
+#define DEBUG_UART_TX_GPIO_BANK_CLK_EN RCC_MP_S_AHB4ENSETR_GPIODEN
+#define DEBUG_UART_TX_GPIO_PORT 6
+#define DEBUG_UART_TX_GPIO_ALTERNATE 8
+#define DEBUG_UART_TX_CLKSRC_REG RCC_UART4CKSELR
+#define DEBUG_UART_TX_CLKSRC RCC_UART4CKSELR_HSI
+#endif /* STM32MP13 */
+#if STM32MP15
+/* 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
+#endif /* STM32MP15 */
+#define DEBUG_UART_TX_EN_REG RCC_MP_APB1ENSETR
+#define DEBUG_UART_TX_EN RCC_MP_APB1ENSETR_UART4EN
+#define DEBUG_UART_RST_REG RCC_APB1RSTSETR
+#define DEBUG_UART_RST_BIT RCC_APB1RSTSETR_UART4RST
+
+/*******************************************************************************
+ * STM32MP1 ETZPC
+ ******************************************************************************/
+#define STM32MP1_ETZPC_BASE U(0x5C007000)
+
+/* ETZPC TZMA IDs */
+#define STM32MP1_ETZPC_TZMA_ROM U(0)
+#define STM32MP1_ETZPC_TZMA_SYSRAM U(1)
+
+#define STM32MP1_ETZPC_TZMA_ALL_SECURE GENMASK_32(9, 0)
+
+/* ETZPC DECPROT IDs */
+#define STM32MP1_ETZPC_STGENC_ID 0
+#define STM32MP1_ETZPC_BKPSRAM_ID 1
+#define STM32MP1_ETZPC_IWDG1_ID 2
+#define STM32MP1_ETZPC_USART1_ID 3
+#define STM32MP1_ETZPC_SPI6_ID 4
+#define STM32MP1_ETZPC_I2C4_ID 5
+#define STM32MP1_ETZPC_RNG1_ID 7
+#define STM32MP1_ETZPC_HASH1_ID 8
+#define STM32MP1_ETZPC_CRYP1_ID 9
+#define STM32MP1_ETZPC_DDRCTRL_ID 10
+#define STM32MP1_ETZPC_DDRPHYC_ID 11
+#define STM32MP1_ETZPC_I2C6_ID 12
+#define STM32MP1_ETZPC_SEC_ID_LIMIT 13
+
+#define STM32MP1_ETZPC_TIM2_ID 16
+#define STM32MP1_ETZPC_TIM3_ID 17
+#define STM32MP1_ETZPC_TIM4_ID 18
+#define STM32MP1_ETZPC_TIM5_ID 19
+#define STM32MP1_ETZPC_TIM6_ID 20
+#define STM32MP1_ETZPC_TIM7_ID 21
+#define STM32MP1_ETZPC_TIM12_ID 22
+#define STM32MP1_ETZPC_TIM13_ID 23
+#define STM32MP1_ETZPC_TIM14_ID 24
+#define STM32MP1_ETZPC_LPTIM1_ID 25
+#define STM32MP1_ETZPC_WWDG1_ID 26
+#define STM32MP1_ETZPC_SPI2_ID 27
+#define STM32MP1_ETZPC_SPI3_ID 28
+#define STM32MP1_ETZPC_SPDIFRX_ID 29
+#define STM32MP1_ETZPC_USART2_ID 30
+#define STM32MP1_ETZPC_USART3_ID 31
+#define STM32MP1_ETZPC_UART4_ID 32
+#define STM32MP1_ETZPC_UART5_ID 33
+#define STM32MP1_ETZPC_I2C1_ID 34
+#define STM32MP1_ETZPC_I2C2_ID 35
+#define STM32MP1_ETZPC_I2C3_ID 36
+#define STM32MP1_ETZPC_I2C5_ID 37
+#define STM32MP1_ETZPC_CEC_ID 38
+#define STM32MP1_ETZPC_DAC_ID 39
+#define STM32MP1_ETZPC_UART7_ID 40
+#define STM32MP1_ETZPC_UART8_ID 41
+#define STM32MP1_ETZPC_MDIOS_ID 44
+#define STM32MP1_ETZPC_TIM1_ID 48
+#define STM32MP1_ETZPC_TIM8_ID 49
+#define STM32MP1_ETZPC_USART6_ID 51
+#define STM32MP1_ETZPC_SPI1_ID 52
+#define STM32MP1_ETZPC_SPI4_ID 53
+#define STM32MP1_ETZPC_TIM15_ID 54
+#define STM32MP1_ETZPC_TIM16_ID 55
+#define STM32MP1_ETZPC_TIM17_ID 56
+#define STM32MP1_ETZPC_SPI5_ID 57
+#define STM32MP1_ETZPC_SAI1_ID 58
+#define STM32MP1_ETZPC_SAI2_ID 59
+#define STM32MP1_ETZPC_SAI3_ID 60
+#define STM32MP1_ETZPC_DFSDM_ID 61
+#define STM32MP1_ETZPC_TT_FDCAN_ID 62
+#define STM32MP1_ETZPC_LPTIM2_ID 64
+#define STM32MP1_ETZPC_LPTIM3_ID 65
+#define STM32MP1_ETZPC_LPTIM4_ID 66
+#define STM32MP1_ETZPC_LPTIM5_ID 67
+#define STM32MP1_ETZPC_SAI4_ID 68
+#define STM32MP1_ETZPC_VREFBUF_ID 69
+#define STM32MP1_ETZPC_DCMI_ID 70
+#define STM32MP1_ETZPC_CRC2_ID 71
+#define STM32MP1_ETZPC_ADC_ID 72
+#define STM32MP1_ETZPC_HASH2_ID 73
+#define STM32MP1_ETZPC_RNG2_ID 74
+#define STM32MP1_ETZPC_CRYP2_ID 75
+#define STM32MP1_ETZPC_SRAM1_ID 80
+#define STM32MP1_ETZPC_SRAM2_ID 81
+#define STM32MP1_ETZPC_SRAM3_ID 82
+#define STM32MP1_ETZPC_SRAM4_ID 83
+#define STM32MP1_ETZPC_RETRAM_ID 84
+#define STM32MP1_ETZPC_OTG_ID 85
+#define STM32MP1_ETZPC_SDMMC3_ID 86
+#define STM32MP1_ETZPC_DLYBSD3_ID 87
+#define STM32MP1_ETZPC_DMA1_ID 88
+#define STM32MP1_ETZPC_DMA2_ID 89
+#define STM32MP1_ETZPC_DMAMUX_ID 90
+#define STM32MP1_ETZPC_FMC_ID 91
+#define STM32MP1_ETZPC_QSPI_ID 92
+#define STM32MP1_ETZPC_DLYBQ_ID 93
+#define STM32MP1_ETZPC_ETH_ID 94
+#define STM32MP1_ETZPC_RSV_ID 95
+
+#define STM32MP_ETZPC_MAX_ID 96
+
+/*******************************************************************************
+ * STM32MP1 TZC (TZ400)
+ ******************************************************************************/
+#define STM32MP1_TZC_BASE U(0x5C006000)
+
+#if STM32MP13
+#define STM32MP1_FILTER_BIT_ALL TZC_400_REGION_ATTR_FILTER_BIT(0)
+#endif
+#if STM32MP15
+#define STM32MP1_FILTER_BIT_ALL (TZC_400_REGION_ATTR_FILTER_BIT(0) | \
+ TZC_400_REGION_ATTR_FILTER_BIT(1))
+#endif
+
+/*******************************************************************************
+ * 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 labels */
+#define CFG0_OTP "cfg0_otp"
+#define PART_NUMBER_OTP "part_number_otp"
+#if STM32MP15
+#define PACKAGE_OTP "package_otp"
+#endif
+#define HW2_OTP "hw2_otp"
+#if STM32MP13
+#define NAND_OTP "cfg9_otp"
+#define NAND2_OTP "cfg10_otp"
+#endif
+#if STM32MP15
+#define NAND_OTP "nand_otp"
+#endif
+#define MONOTONIC_OTP "monotonic_otp"
+#define UID_OTP "uid_otp"
+#define PKH_OTP "pkh_otp"
+#define ENCKEY_OTP "enckey_otp"
+#define BOARD_ID_OTP "board_id"
+
+/* OTP mask */
+/* CFG0 */
+#if STM32MP13
+#define CFG0_OTP_MODE_MASK GENMASK_32(9, 0)
+#define CFG0_OTP_MODE_SHIFT 0
+#define CFG0_OPEN_DEVICE 0x17U
+#define CFG0_CLOSED_DEVICE 0x3FU
+#define CFG0_CLOSED_DEVICE_NO_BOUNDARY_SCAN 0x17FU
+#define CFG0_CLOSED_DEVICE_NO_JTAG 0x3FFU
+#endif
+#if STM32MP15
+#define CFG0_CLOSED_DEVICE BIT(6)
+#endif
+
+/* PART NUMBER */
+#if STM32MP13
+#define PART_NUMBER_OTP_PART_MASK GENMASK_32(11, 0)
+#endif
+#if STM32MP15
+#define PART_NUMBER_OTP_PART_MASK GENMASK_32(7, 0)
+#endif
+#define PART_NUMBER_OTP_PART_SHIFT 0
+
+/* PACKAGE */
+#if STM32MP15
+#define PACKAGE_OTP_PKG_MASK GENMASK_32(29, 27)
+#define PACKAGE_OTP_PKG_SHIFT 27
+#endif
+
+/* 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)
+
+/* NAND OTP */
+/* NAND parameter storage flag */
+#define NAND_PARAM_STORED_IN_OTP BIT(31)
+
+/* NAND page size in bytes */
+#define NAND_PAGE_SIZE_MASK GENMASK_32(30, 29)
+#define NAND_PAGE_SIZE_SHIFT 29
+#define NAND_PAGE_SIZE_2K U(0)
+#define NAND_PAGE_SIZE_4K U(1)
+#define NAND_PAGE_SIZE_8K U(2)
+
+/* NAND block size in pages */
+#define NAND_BLOCK_SIZE_MASK GENMASK_32(28, 27)
+#define NAND_BLOCK_SIZE_SHIFT 27
+#define NAND_BLOCK_SIZE_64_PAGES U(0)
+#define NAND_BLOCK_SIZE_128_PAGES U(1)
+#define NAND_BLOCK_SIZE_256_PAGES U(2)
+
+/* NAND number of block (in unit of 256 blocks) */
+#define NAND_BLOCK_NB_MASK GENMASK_32(26, 19)
+#define NAND_BLOCK_NB_SHIFT 19
+#define NAND_BLOCK_NB_UNIT U(256)
+
+/* NAND bus width in bits */
+#define NAND_WIDTH_MASK BIT(18)
+#define NAND_WIDTH_SHIFT 18
+
+/* NAND number of ECC bits per 512 bytes */
+#define NAND_ECC_BIT_NB_MASK GENMASK_32(17, 15)
+#define NAND_ECC_BIT_NB_SHIFT 15
+#define NAND_ECC_BIT_NB_UNSET U(0)
+#define NAND_ECC_BIT_NB_1_BITS U(1)
+#define NAND_ECC_BIT_NB_4_BITS U(2)
+#define NAND_ECC_BIT_NB_8_BITS U(3)
+#define NAND_ECC_ON_DIE U(4)
+
+/* NAND number of planes */
+#define NAND_PLANE_BIT_NB_MASK BIT(14)
+
+/* NAND2 OTP */
+#define NAND2_PAGE_SIZE_SHIFT 16
+
+/* NAND2 config distribution */
+#define NAND2_CONFIG_DISTRIB BIT(0)
+#define NAND2_PNAND_NAND2_SNAND_NAND1 U(0)
+#define NAND2_PNAND_NAND1_SNAND_NAND2 U(1)
+
+/* MONOTONIC OTP */
+#define MAX_MONOTONIC_VALUE 32
+
+/* UID OTP */
+#define UID_WORD_NB U(3)
+
+/* FWU configuration (max supported value is 15) */
+#define FWU_MAX_TRIAL_REBOOT U(3)
+
+/*******************************************************************************
+ * STM32MP1 TAMP
+ ******************************************************************************/
+#define TAMP_BASE U(0x5C00A000)
+#define TAMP_BKP_REGISTER_BASE (TAMP_BASE + U(0x100))
+#define TAMP_COUNTR U(0x40)
+
+#if !(defined(__LINKER__) || defined(__ASSEMBLER__))
+static inline uintptr_t tamp_bkpr(uint32_t idx)
+{
+ return TAMP_BKP_REGISTER_BASE + (idx << 2);
+}
+#endif
+
+/*******************************************************************************
+ * STM32MP1 USB
+ ******************************************************************************/
+#define USB_OTG_BASE U(0x49000000)
+
+/*******************************************************************************
+ * 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)
+
+/*******************************************************************************
+ * Miscellaneous STM32MP1 peripherals base address
+ ******************************************************************************/
+#define BSEC_BASE U(0x5C005000)
+#if STM32MP13
+#define CRYP_BASE U(0x54002000)
+#endif
+#if STM32MP15
+#define CRYP1_BASE U(0x54001000)
+#endif
+#define DBGMCU_BASE U(0x50081000)
+#if STM32MP13
+#define HASH_BASE U(0x54003000)
+#endif
+#if STM32MP15
+#define HASH1_BASE U(0x54002000)
+#endif
+#if STM32MP13
+#define I2C3_BASE U(0x4C004000)
+#define I2C4_BASE U(0x4C005000)
+#define I2C5_BASE U(0x4C006000)
+#endif
+#if STM32MP15
+#define I2C4_BASE U(0x5C002000)
+#define I2C6_BASE U(0x5c009000)
+#endif
+#if STM32MP13
+#define RNG_BASE U(0x54004000)
+#endif
+#if STM32MP15
+#define RNG1_BASE U(0x54003000)
+#endif
+#define RTC_BASE U(0x5c004000)
+#if STM32MP13
+#define SPI4_BASE U(0x4C002000)
+#define SPI5_BASE U(0x4C003000)
+#endif
+#if STM32MP15
+#define SPI6_BASE U(0x5c001000)
+#endif
+#define STGEN_BASE U(0x5c008000)
+#define SYSCFG_BASE U(0x50020000)
+
+/*******************************************************************************
+ * STM32MP13 SAES
+ ******************************************************************************/
+#define SAES_BASE U(0x54005000)
+
+/*******************************************************************************
+ * STM32MP13 PKA
+ ******************************************************************************/
+#define PKA_BASE U(0x54006000)
+
+/*******************************************************************************
+ * REGULATORS
+ ******************************************************************************/
+/* 3 PWR + 1 VREFBUF + 14 PMIC regulators + 1 FIXED */
+#define PLAT_NB_RDEVS U(19)
+/* 2 FIXED */
+#define PLAT_NB_FIXED_REGS U(2)
+
+/*******************************************************************************
+ * Device Tree defines
+ ******************************************************************************/
+#define DT_BSEC_COMPAT "st,stm32mp15-bsec"
+#if STM32MP13
+#define DT_DDR_COMPAT "st,stm32mp13-ddr"
+#endif
+#if STM32MP15
+#define DT_DDR_COMPAT "st,stm32mp1-ddr"
+#endif
+#define DT_IWDG_COMPAT "st,stm32mp1-iwdg"
+#define DT_PWR_COMPAT "st,stm32mp1,pwr-reg"
+#if STM32MP13
+#define DT_RCC_CLK_COMPAT "st,stm32mp13-rcc"
+#define DT_RCC_SEC_CLK_COMPAT "st,stm32mp13-rcc-secure"
+#endif
+#if STM32MP15
+#define DT_RCC_CLK_COMPAT "st,stm32mp1-rcc"
+#define DT_RCC_SEC_CLK_COMPAT "st,stm32mp1-rcc-secure"
+#endif
+#define DT_SDMMC2_COMPAT "st,stm32-sdmmc2"
+#define DT_UART_COMPAT "st,stm32h7-uart"
+
+#endif /* STM32MP1_DEF_H */
diff --git a/plat/st/stm32mp1/stm32mp1_fconf_firewall.c b/plat/st/stm32mp1/stm32mp1_fconf_firewall.c
new file mode 100644
index 0000000..f2568ab
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_fconf_firewall.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/arm/tzc400.h>
+#include <drivers/clk.h>
+#include <dt-bindings/clock/stm32mp1-clks.h>
+#include <lib/fconf/fconf.h>
+#include <lib/object_pool.h>
+#include <libfdt.h>
+#include <tools_share/firmware_image_package.h>
+
+#include <platform_def.h>
+#include <stm32mp_fconf_getter.h>
+
+#define STM32MP_REGION_PARAMS 4
+#define STM32MP_MAX_REGIONS 8
+#define FORCE_SEC_REGION BIT(31)
+
+static uint32_t nb_regions;
+
+struct dt_id_attr {
+ fdt32_t id_attr[STM32MP_MAX_REGIONS];
+};
+
+void stm32mp1_arch_security_setup(void)
+{
+#if STM32MP13
+ clk_enable(TZC);
+#endif
+#if STM32MP15
+ clk_enable(TZC1);
+ clk_enable(TZC2);
+#endif
+
+ tzc400_init(STM32MP1_TZC_BASE);
+ tzc400_disable_filters();
+
+ /*
+ * Region 0 set to cover all DRAM at 0xC000_0000
+ * Only secure access is granted in read/write.
+ */
+ tzc400_configure_region0(TZC_REGION_S_RDWR, 0);
+
+ tzc400_set_action(TZC_ACTION_ERR);
+ tzc400_enable_filters();
+}
+
+void stm32mp1_security_setup(void)
+{
+ uint8_t i;
+
+ assert(nb_regions > 0U);
+
+ tzc400_init(STM32MP1_TZC_BASE);
+ tzc400_disable_filters();
+
+ /*
+ * Region 0 set to cover all DRAM at 0xC000_0000
+ * No access is allowed.
+ */
+ tzc400_configure_region0(TZC_REGION_S_NONE, 0);
+
+ for (i = 1U; i <= nb_regions; i++) {
+ tzc400_update_filters(i, STM32MP1_FILTER_BIT_ALL);
+ }
+
+ tzc400_set_action(TZC_ACTION_INT);
+ tzc400_enable_filters();
+}
+
+static int fconf_populate_stm32mp1_firewall(uintptr_t config)
+{
+ int node, len;
+ unsigned int i;
+ const struct dt_id_attr *conf_list;
+ const void *dtb = (const void *)config;
+
+ /* Assert the node offset point to "st,mem-firewall" compatible property */
+ const char *compatible_str = "st,mem-firewall";
+
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
+ if (node < 0) {
+ ERROR("FCONF: Can't find %s compatible in dtb\n", compatible_str);
+ return node;
+ }
+
+ conf_list = (const struct dt_id_attr *)fdt_getprop(dtb, node, "memory-ranges", &len);
+ if (conf_list == NULL) {
+ WARN("FCONF: Read cell failed for %s\n", "memory-ranges");
+ return -1;
+ }
+
+ /* Locate the memory cells and read all values */
+ for (i = 0U; i < (unsigned int)(len / (sizeof(uint32_t) * STM32MP_REGION_PARAMS)); i++) {
+ uint32_t base;
+ uint32_t size;
+ uint32_t sec_attr;
+ uint32_t nsaid;
+
+ base = fdt32_to_cpu(conf_list->id_attr[i * STM32MP_REGION_PARAMS]);
+ size = fdt32_to_cpu(conf_list->id_attr[i * STM32MP_REGION_PARAMS + 1]);
+ sec_attr = fdt32_to_cpu(conf_list->id_attr[i * STM32MP_REGION_PARAMS + 2]);
+ nsaid = fdt32_to_cpu(conf_list->id_attr[i * STM32MP_REGION_PARAMS + 3]);
+
+ VERBOSE("FCONF: stm32mp1-firewall cell found with value = 0x%x 0x%x 0x%x 0x%x\n",
+ base, size, sec_attr, nsaid);
+
+ nb_regions++;
+
+ /* Configure region but keep disabled for secure access for BL2 load */
+ tzc400_configure_region(0U, nb_regions, (unsigned long long)base,
+ (unsigned long long)base + size - 1ULL, sec_attr, nsaid);
+ }
+
+ /* Force flush as the value will be used cache off */
+ flush_dcache_range((uintptr_t)&nb_regions, sizeof(uint32_t));
+
+ return 0;
+}
+
+FCONF_REGISTER_POPULATOR(FW_CONFIG, stm32mp1_firewall, fconf_populate_stm32mp1_firewall);
diff --git a/plat/st/stm32mp1/stm32mp1_fip_def.h b/plat/st/stm32mp1/stm32mp1_fip_def.h
new file mode 100644
index 0000000..4098386
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_fip_def.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2021-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_FIP_DEF_H
+#define STM32MP1_FIP_DEF_H
+
+#if STM32MP15_OPTEE_RSV_SHM
+#define STM32MP_DDR_S_SIZE U(0x01E00000) /* 30 MB */
+#define STM32MP_DDR_SHMEM_SIZE U(0x00200000) /* 2 MB */
+#else
+#define STM32MP_DDR_S_SIZE U(0x02000000) /* 32 MB */
+#define STM32MP_DDR_SHMEM_SIZE U(0) /* empty */
+#endif
+
+#if TRUSTED_BOARD_BOOT && !STM32MP_USE_EXTERNAL_HEAP
+#if STM32MP15
+#define STM32MP_BL2_RO_SIZE U(0x00014000) /* 80 KB */
+#define STM32MP_BL2_SIZE U(0x0001B000) /* 108 KB for BL2 */
+#endif /* STM32MP15 */
+#else /* TRUSTED_BOARD_BOOT && !STM32MP_USE_EXTERNAL_HEAP */
+#if STM32MP13
+#if BL2_IN_XIP_MEM
+#define STM32MP_BL2_RO_SIZE U(0x00015000) /* 84 KB */
+#define STM32MP_BL2_SIZE U(0x00017000) /* 92 KB for BL2 */
+#else
+/* STM32MP_BL2_RO_SIZE not used if !BL2_IN_XIP_MEM */
+#define STM32MP_BL2_SIZE U(0x0001B000) /* 108KB for BL2 */
+ /* with 20KB for DTB, SYSRAM is full */
+#endif
+#endif /* STM32MP13 */
+#if STM32MP15
+#define STM32MP_BL2_RO_SIZE U(0x00011000) /* 68 KB */
+#define STM32MP_BL2_SIZE U(0x00016000) /* 88 KB for BL2 */
+#endif /* STM32MP15 */
+#endif /* TRUSTED_BOARD_BOOT && !STM32MP_USE_EXTERNAL_HEAP */
+
+#if STM32MP13
+#if TRUSTED_BOARD_BOOT
+#define STM32MP_BL2_DTB_SIZE U(0x00005000) /* 20 KB for DTB */
+#else /* TRUSTED_BOARD_BOOT */
+#define STM32MP_BL2_DTB_SIZE U(0x00004000) /* 16 KB for DTB */
+#endif /* TRUSTED_BOARD_BOOT */
+#endif /* STM32MP13 */
+#if STM32MP15
+#define STM32MP_BL2_DTB_SIZE U(0x00007000) /* 28 KB for DTB */
+#endif /* STM32MP15 */
+#define STM32MP_BL32_SIZE U(0x0001B000) /* 108 KB for BL32 */
+#define STM32MP_BL32_DTB_SIZE U(0x00005000) /* 20 KB for DTB */
+#define STM32MP_FW_CONFIG_MAX_SIZE PAGE_SIZE /* 4 KB for FCONF DTB */
+#define STM32MP_HW_CONFIG_MAX_SIZE U(0x40000) /* 256 KB for HW config DTB */
+
+#if STM32MP13
+#define STM32MP_BL2_BASE (STM32MP_BL2_DTB_BASE + \
+ STM32MP_BL2_DTB_SIZE)
+#endif /* STM32MP13 */
+#if STM32MP15
+#define STM32MP_BL2_BASE (STM32MP_SEC_SYSRAM_BASE + \
+ STM32MP_SEC_SYSRAM_SIZE - \
+ STM32MP_BL2_SIZE)
+#endif /* STM32MP15 */
+
+#define STM32MP_BL2_RO_BASE STM32MP_BL2_BASE
+
+#define STM32MP_BL2_RW_BASE (STM32MP_BL2_RO_BASE + \
+ STM32MP_BL2_RO_SIZE)
+
+#if STM32MP13
+#define STM32MP_BL2_RW_SIZE (STM32MP_SYSRAM_BASE + \
+ STM32MP_SYSRAM_SIZE - \
+ STM32MP_BL2_RW_BASE)
+
+#define STM32MP_BL2_DTB_BASE STM32MP_SEC_SYSRAM_BASE
+#endif /* STM32MP13 */
+#if STM32MP15
+#define STM32MP_BL2_RW_SIZE (STM32MP_SEC_SYSRAM_BASE + \
+ STM32MP_SEC_SYSRAM_SIZE - \
+ STM32MP_BL2_RW_BASE)
+
+#define STM32MP_BL2_DTB_BASE (STM32MP_BL2_BASE - \
+ STM32MP_BL2_DTB_SIZE)
+#endif /* STM32MP15 */
+
+#define STM32MP_BL32_DTB_BASE STM32MP_SYSRAM_BASE
+
+#define STM32MP_BL32_BASE (STM32MP_BL32_DTB_BASE + \
+ STM32MP_BL32_DTB_SIZE)
+
+
+#if defined(IMAGE_BL2)
+#define STM32MP_DTB_SIZE STM32MP_BL2_DTB_SIZE
+#define STM32MP_DTB_BASE STM32MP_BL2_DTB_BASE
+#endif
+#if defined(IMAGE_BL32)
+#define STM32MP_DTB_SIZE STM32MP_BL32_DTB_SIZE
+#define STM32MP_DTB_BASE STM32MP_BL32_DTB_BASE
+#endif
+
+#ifdef AARCH32_SP_OPTEE
+#define STM32MP_OPTEE_BASE STM32MP_SEC_SYSRAM_BASE
+
+#define STM32MP_OPTEE_SIZE (STM32MP_BL2_DTB_BASE - \
+ STM32MP_OPTEE_BASE)
+#endif
+
+#if STM32MP13
+#define STM32MP_FW_CONFIG_BASE SRAM3_BASE
+#endif /* STM32MP13 */
+#if STM32MP15
+#define STM32MP_FW_CONFIG_BASE (STM32MP_SYSRAM_BASE + \
+ STM32MP_SYSRAM_SIZE - \
+ PAGE_SIZE)
+#endif /* STM32MP15 */
+#define STM32MP_HW_CONFIG_BASE (STM32MP_BL33_BASE + \
+ STM32MP_BL33_MAX_SIZE)
+
+/*
+ * MAX_MMAP_REGIONS is usually:
+ * BL stm32mp1_mmap size + mmap regions in *_plat_arch_setup
+ */
+#if defined(IMAGE_BL32)
+#define MAX_MMAP_REGIONS 10
+#endif
+
+/*******************************************************************************
+ * STM32MP1 RAW partition offset for devices without GPT
+ ******************************************************************************/
+#define STM32MP_EMMC_BOOT_FIP_OFFSET U(0x00040000)
+#ifndef STM32MP_NOR_FIP_OFFSET
+#define STM32MP_NOR_FIP_OFFSET U(0x00080000)
+#endif
+#ifndef STM32MP_NAND_FIP_OFFSET
+#define STM32MP_NAND_FIP_OFFSET U(0x00200000)
+#endif
+
+#endif /* STM32MP1_FIP_DEF_H */
diff --git a/plat/st/stm32mp1/stm32mp1_gic.c b/plat/st/stm32mp1/stm32mp1_gic.c
new file mode 100644
index 0000000..851a9cf
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_gic.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+struct stm32_gic_instance {
+ uint32_t cells;
+ uint32_t phandle_node;
+};
+
+/******************************************************************************
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ *****************************************************************************/
+static const interrupt_prop_t stm32mp1_interrupt_props[] = {
+ PLATFORM_G1S_PROPS(GICV2_INTR_GROUP0),
+ PLATFORM_G0_PROPS(GICV2_INTR_GROUP0)
+};
+
+/* Fix target_mask_array as secondary core is not able to initialize it */
+static unsigned int target_mask_array[PLATFORM_CORE_COUNT] = {1, 2};
+
+static gicv2_driver_data_t platform_gic_data = {
+ .interrupt_props = stm32mp1_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(stm32mp1_interrupt_props),
+ .target_masks = target_mask_array,
+ .target_masks_num = ARRAY_SIZE(target_mask_array),
+};
+
+static struct stm32_gic_instance stm32_gic;
+
+void stm32mp1_gic_init(void)
+{
+ int node;
+ void *fdt;
+ const fdt32_t *cuint;
+ struct dt_node_info dt_gic;
+
+ if (fdt_get_address(&fdt) == 0) {
+ panic();
+ }
+
+ node = dt_get_node(&dt_gic, -1, "arm,cortex-a7-gic");
+ if (node < 0) {
+ panic();
+ }
+
+ platform_gic_data.gicd_base = dt_gic.base;
+
+ cuint = fdt_getprop(fdt, node, "reg", NULL);
+ if (cuint == NULL) {
+ panic();
+ }
+
+ platform_gic_data.gicc_base = fdt32_to_cpu(*(cuint + 2));
+
+ cuint = fdt_getprop(fdt, node, "#interrupt-cells", NULL);
+ if (cuint == NULL) {
+ panic();
+ }
+
+ stm32_gic.cells = fdt32_to_cpu(*cuint);
+
+ stm32_gic.phandle_node = fdt_get_phandle(fdt, node);
+ if (stm32_gic.phandle_node == 0U) {
+ panic();
+ }
+
+ gicv2_driver_init(&platform_gic_data);
+ gicv2_distif_init();
+
+ stm32mp1_gic_pcpu_init();
+}
+
+void stm32mp1_gic_pcpu_init(void)
+{
+ gicv2_pcpu_distif_init();
+ gicv2_set_pe_target_mask(plat_my_core_pos());
+ gicv2_cpuif_enable();
+}
diff --git a/plat/st/stm32mp1/stm32mp1_helper.S b/plat/st/stm32mp1/stm32mp1_helper.S
new file mode 100644
index 0000000..eb8823b
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_helper.S
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <drivers/st/stm32_gpio.h>
+
+#define GPIO_TX_SHIFT (DEBUG_UART_TX_GPIO_PORT << 1)
+
+ .globl platform_mem_init
+ .globl plat_report_exception
+ .globl plat_report_prefetch_abort
+ .globl plat_report_data_abort
+ .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
+
+#if DEBUG
+func plat_report_exception
+ mov r8, lr
+
+ /*
+ * Test if an abort occurred
+ * In this case the error message has already been displayed
+ * by dedicated functions
+ */
+ cmp r0, #MODE32_abt
+ beq 1f
+
+ /* Test for an undefined instruction */
+ cmp r0, #MODE32_und
+ bne other_exception_lbl
+ ldr r4, =undefined_str
+ bl asm_print_str
+ mrs r4, lr_und
+ b print_exception_info
+
+other_exception_lbl:
+ /* Other exceptions */
+ mov r9, r0
+ ldr r4, =exception_start_str
+ bl asm_print_str
+ mov r4, r9
+ bl asm_print_hex
+ ldr r4, =exception_end_str
+ bl asm_print_str
+ mov r4, r6
+
+print_exception_info:
+ bl asm_print_hex
+
+ ldr r4, =end_error_str
+ bl asm_print_str
+
+1:
+ bx r8
+endfunc plat_report_exception
+
+func plat_report_prefetch_abort
+ mov r8, lr
+ mov r9, r0
+
+ ldr r4, =prefetch_abort_str
+ bl asm_print_str
+
+ mov r4, r9
+ sub r4, r4, #4
+ bl asm_print_hex
+
+ ldr r4, =ifsr_str
+ bl asm_print_str
+
+ ldcopr r4, IFSR
+ bl asm_print_hex
+
+ ldr r4, =ifar_str
+ bl asm_print_str
+
+ ldcopr r4, IFAR
+ bl asm_print_hex
+
+ ldr r4, =end_error_str
+ bl asm_print_str
+
+ bx r8
+endfunc plat_report_prefetch_abort
+
+func plat_report_data_abort
+ mov r8, lr
+ mov r9, r0
+
+ ldr r4, =data_abort_str
+ bl asm_print_str
+
+ mov r4, r9
+ sub r4, r4, #8
+ bl asm_print_hex
+
+ ldr r4, =dfsr_str
+ bl asm_print_str
+
+ ldcopr r4, DFSR
+ bl asm_print_hex
+
+ ldr r4, =dfar_str
+ bl asm_print_str
+
+ ldcopr r4, DFAR
+ bl asm_print_hex
+
+ ldr r4, =end_error_str
+ bl asm_print_str
+
+ bx r8
+endfunc plat_report_data_abort
+#endif /* DEBUG */
+
+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
+ /* Reset UART peripheral */
+ ldr r1, =(RCC_BASE + DEBUG_UART_RST_REG)
+ ldr r2, =DEBUG_UART_RST_BIT
+ str r2, [r1]
+1:
+ ldr r0, [r1]
+ ands r2, r0, r2
+ beq 1b
+ str r2, [r1, #4] /* RSTCLR register */
+2:
+ ldr r0, [r1]
+ ands r2, r0, r2
+ bne 2b
+ /* 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 */
+#if DEBUG_UART_TX_GPIO_PORT >= GPIO_ALT_LOWER_LIMIT
+ ldr r2, [r1, #GPIO_AFRH_OFFSET]
+ bic r2, r2, #(GPIO_ALTERNATE_MASK << \
+ ((DEBUG_UART_TX_GPIO_PORT - GPIO_ALT_LOWER_LIMIT) << 2))
+ orr r2, r2, #(DEBUG_UART_TX_GPIO_ALTERNATE << \
+ ((DEBUG_UART_TX_GPIO_PORT - GPIO_ALT_LOWER_LIMIT) << 2))
+ str r2, [r1, #GPIO_AFRH_OFFSET]
+#else
+ ldr r2, [r1, #GPIO_AFRL_OFFSET]
+ bic r2, r2, #(GPIO_ALTERNATE_MASK << (DEBUG_UART_TX_GPIO_PORT << 2))
+ orr r2, r2, #(DEBUG_UART_TX_GPIO_ALTERNATE << (DEBUG_UART_TX_GPIO_PORT << 2))
+ str r2, [r1, #GPIO_AFRL_OFFSET]
+#endif
+ /* 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
+
+ /* ---------------------------------------------
+ * void plat_crash_console_flush(void)
+ *
+ * Flush the crash console without a C Runtime stack.
+ * ---------------------------------------------
+ */
+func plat_crash_console_flush
+ ldr r0, =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
+
+ /* ----------------------------------------------------------
+ * void plat_panic_handler(void) __dead2;
+ * Report exception + endless loop.
+ *
+ * r6 holds the address where the fault occurred.
+ * Filling lr with this value allows debuggers to reconstruct
+ * the backtrace.
+ * ----------------------------------------------------------
+ */
+func plat_panic_handler
+ mrs r0, cpsr
+ and r0, #MODE32_MASK
+ bl plat_report_exception
+ mov lr, r6
+ b .
+endfunc plat_panic_handler
+
+#if DEBUG
+.section .rodata.rev_err_str, "aS"
+prefetch_abort_str:
+ .asciz "\nPrefetch Abort at: 0x"
+data_abort_str:
+ .asciz "\nData Abort at: 0x"
+undefined_str:
+ .asciz "\nUndefined instruction at: 0x"
+exception_start_str:
+ .asciz "\nException mode=0x"
+exception_end_str:
+ .asciz " at: 0x"
+dfsr_str:
+ .asciz " DFSR = 0x"
+dfar_str:
+ .asciz " DFAR = 0x"
+ifsr_str:
+ .asciz " IFSR = 0x"
+ifar_str:
+ .asciz " IFAR = 0x"
+end_error_str:
+ .asciz "\n\r"
+#endif
diff --git a/plat/st/stm32mp1/stm32mp1_pm.c b/plat/st/stm32mp1/stm32mp1_pm.c
new file mode 100644
index 0000000..6e438c4
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_pm.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <bl32/sp_min/platform_sp_min.h>
+#include <common/debug.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/clk.h>
+#include <dt-bindings/clock/stm32mp1-clks.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+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();
+ uintptr_t bkpr_core1_addr =
+ tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX);
+ uintptr_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;
+ }
+
+ /* Only one valid entry point */
+ if (stm32_sec_entrypoint != (uintptr_t)&sp_min_warm_entrypoint) {
+ return PSCI_E_INVALID_ADDRESS;
+ }
+
+ 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);
+
+ clk_disable(RTCAPB);
+
+ /* Generate an IT to core 1 */
+ gicv2_raise_sgi(ARM_IRQ_SEC_SGI_0, false, 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;
+}
diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c
new file mode 100644
index 0000000..9bdb075
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_private.c
@@ -0,0 +1,788 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <drivers/clk.h>
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32_iwdg.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <libfdt.h>
+
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+/* Internal layout of the 32bit OTP word board_id */
+#define BOARD_ID_BOARD_NB_MASK GENMASK(31, 16)
+#define BOARD_ID_BOARD_NB_SHIFT 16
+#define BOARD_ID_VARCPN_MASK GENMASK(15, 12)
+#define BOARD_ID_VARCPN_SHIFT 12
+#define BOARD_ID_REVISION_MASK GENMASK(11, 8)
+#define BOARD_ID_REVISION_SHIFT 8
+#define BOARD_ID_VARFG_MASK GENMASK(7, 4)
+#define BOARD_ID_VARFG_SHIFT 4
+#define BOARD_ID_BOM_MASK GENMASK(3, 0)
+
+#define BOARD_ID2NB(_id) (((_id) & BOARD_ID_BOARD_NB_MASK) >> \
+ BOARD_ID_BOARD_NB_SHIFT)
+#define BOARD_ID2VARCPN(_id) (((_id) & BOARD_ID_VARCPN_MASK) >> \
+ BOARD_ID_VARCPN_SHIFT)
+#define BOARD_ID2REV(_id) (((_id) & BOARD_ID_REVISION_MASK) >> \
+ BOARD_ID_REVISION_SHIFT)
+#define BOARD_ID2VARFG(_id) (((_id) & BOARD_ID_VARFG_MASK) >> \
+ BOARD_ID_VARFG_SHIFT)
+#define BOARD_ID2BOM(_id) ((_id) & BOARD_ID_BOM_MASK)
+
+#if STM32MP13
+#define TAMP_BOOT_MODE_BACKUP_REG_ID U(30)
+#endif
+#if STM32MP15
+#define TAMP_BOOT_MODE_BACKUP_REG_ID U(20)
+#endif
+#define TAMP_BOOT_MODE_ITF_MASK GENMASK(15, 8)
+#define TAMP_BOOT_MODE_ITF_SHIFT 8
+#define TAMP_BOOT_MODE_AUTH_MASK GENMASK(23, 16)
+#define TAMP_BOOT_MODE_AUTH_SHIFT 16
+
+/*
+ * Backup register to store fwu update information.
+ * It should be writeable only by secure world, but also readable by non secure
+ * (so it should be in Zone 2).
+ */
+#define TAMP_BOOT_FWU_INFO_REG_ID U(10)
+#define TAMP_BOOT_FWU_INFO_IDX_MSK GENMASK(3, 0)
+#define TAMP_BOOT_FWU_INFO_IDX_OFF U(0)
+#define TAMP_BOOT_FWU_INFO_CNT_MSK GENMASK(7, 4)
+#define TAMP_BOOT_FWU_INFO_CNT_OFF U(4)
+
+#if defined(IMAGE_BL2)
+#define MAP_SEC_SYSRAM MAP_REGION_FLAT(STM32MP_SYSRAM_BASE, \
+ STM32MP_SYSRAM_SIZE, \
+ MT_MEMORY | \
+ MT_RW | \
+ MT_SECURE | \
+ MT_EXECUTE_NEVER)
+#elif defined(IMAGE_BL32)
+#define MAP_SEC_SYSRAM MAP_REGION_FLAT(STM32MP_SEC_SYSRAM_BASE, \
+ STM32MP_SEC_SYSRAM_SIZE, \
+ MT_MEMORY | \
+ MT_RW | \
+ MT_SECURE | \
+ MT_EXECUTE_NEVER)
+
+/* Non-secure SYSRAM is used a uncached memory for SCMI message transfer */
+#define MAP_NS_SYSRAM MAP_REGION_FLAT(STM32MP_NS_SYSRAM_BASE, \
+ STM32MP_NS_SYSRAM_SIZE, \
+ MT_DEVICE | \
+ MT_RW | \
+ MT_NS | \
+ MT_EXECUTE_NEVER)
+#endif
+
+#if STM32MP13
+#define MAP_SRAM_ALL MAP_REGION_FLAT(SRAMS_BASE, \
+ SRAMS_SIZE_2MB_ALIGNED, \
+ MT_MEMORY | \
+ MT_RW | \
+ MT_SECURE | \
+ MT_EXECUTE_NEVER)
+#endif
+
+#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_SEC_SYSRAM,
+#if STM32MP13
+ MAP_SRAM_ALL,
+#endif
+ MAP_DEVICE1,
+#if STM32MP_RAW_NAND
+ MAP_DEVICE2,
+#endif
+ {0}
+};
+#endif
+#if defined(IMAGE_BL32)
+static const mmap_region_t stm32mp1_mmap[] = {
+ MAP_SEC_SYSRAM,
+ MAP_NS_SYSRAM,
+ MAP_DEVICE1,
+ MAP_DEVICE2,
+ {0}
+};
+#endif
+
+void configure_mmu(void)
+{
+ mmap_add(stm32mp1_mmap);
+ init_xlat_tables();
+
+ enable_mmu_svc_mon(0);
+}
+
+uintptr_t stm32_get_gpio_bank_base(unsigned int bank)
+{
+#if STM32MP13
+ assert(GPIO_BANK_A == 0 && bank <= GPIO_BANK_I);
+#endif
+#if STM32MP15
+ if (bank == GPIO_BANK_Z) {
+ return GPIOZ_BASE;
+ }
+
+ assert(GPIO_BANK_A == 0 && bank <= GPIO_BANK_K);
+#endif
+
+ return GPIOA_BASE + (bank * GPIO_BANK_OFFSET);
+}
+
+uint32_t stm32_get_gpio_bank_offset(unsigned int bank)
+{
+#if STM32MP13
+ assert(GPIO_BANK_A == 0 && bank <= GPIO_BANK_I);
+#endif
+#if STM32MP15
+ if (bank == GPIO_BANK_Z) {
+ return 0;
+ }
+
+ assert(GPIO_BANK_A == 0 && bank <= GPIO_BANK_K);
+#endif
+
+ return bank * GPIO_BANK_OFFSET;
+}
+
+bool stm32_gpio_is_secure_at_reset(unsigned int bank)
+{
+#if STM32MP13
+ return true;
+#endif
+#if STM32MP15
+ if (bank == GPIO_BANK_Z) {
+ return true;
+ }
+
+ return false;
+#endif
+}
+
+unsigned long stm32_get_gpio_bank_clock(unsigned int bank)
+{
+#if STM32MP13
+ assert(GPIO_BANK_A == 0 && bank <= GPIO_BANK_I);
+#endif
+#if STM32MP15
+ if (bank == GPIO_BANK_Z) {
+ return GPIOZ;
+ }
+
+ assert(GPIO_BANK_A == 0 && bank <= GPIO_BANK_K);
+#endif
+
+ return GPIOA + (bank - GPIO_BANK_A);
+}
+
+int stm32_get_gpio_bank_pinctrl_node(void *fdt, unsigned int bank)
+{
+ const char *node_compatible = NULL;
+
+ switch (bank) {
+ case GPIO_BANK_A:
+ case GPIO_BANK_B:
+ case GPIO_BANK_C:
+ case GPIO_BANK_D:
+ case GPIO_BANK_E:
+ case GPIO_BANK_F:
+ case GPIO_BANK_G:
+ case GPIO_BANK_H:
+ case GPIO_BANK_I:
+#if STM32MP13
+ node_compatible = "st,stm32mp135-pinctrl";
+ break;
+#endif
+#if STM32MP15
+ case GPIO_BANK_J:
+ case GPIO_BANK_K:
+ node_compatible = "st,stm32mp157-pinctrl";
+ break;
+ case GPIO_BANK_Z:
+ node_compatible = "st,stm32mp157-z-pinctrl";
+ break;
+#endif
+ default:
+ panic();
+ }
+
+ return fdt_node_offset_by_compatible(fdt, -1, node_compatible);
+}
+
+#if STM32MP_UART_PROGRAMMER || !defined(IMAGE_BL2)
+/*
+ * UART Management
+ */
+static const uintptr_t stm32mp1_uart_addresses[8] = {
+ USART1_BASE,
+ USART2_BASE,
+ USART3_BASE,
+ UART4_BASE,
+ UART5_BASE,
+ USART6_BASE,
+ UART7_BASE,
+ UART8_BASE,
+};
+
+uintptr_t get_uart_address(uint32_t instance_nb)
+{
+ if ((instance_nb == 0U) ||
+ (instance_nb > ARRAY_SIZE(stm32mp1_uart_addresses))) {
+ return 0U;
+ }
+
+ return stm32mp1_uart_addresses[instance_nb - 1U];
+}
+#endif
+
+#if STM32MP_USB_PROGRAMMER
+struct gpio_bank_pin_list {
+ uint32_t bank;
+ uint32_t pin;
+};
+
+static const struct gpio_bank_pin_list gpio_list[] = {
+ { /* USART2_RX: GPIOA3 */
+ .bank = 0U,
+ .pin = 3U,
+ },
+ { /* USART3_RX: GPIOB12 */
+ .bank = 1U,
+ .pin = 12U,
+ },
+ { /* UART4_RX: GPIOB2 */
+ .bank = 1U,
+ .pin = 2U,
+ },
+ { /* UART5_RX: GPIOB4 */
+ .bank = 1U,
+ .pin = 5U,
+ },
+ { /* USART6_RX: GPIOC7 */
+ .bank = 2U,
+ .pin = 7U,
+ },
+ { /* UART7_RX: GPIOF6 */
+ .bank = 5U,
+ .pin = 6U,
+ },
+ { /* UART8_RX: GPIOE0 */
+ .bank = 4U,
+ .pin = 0U,
+ },
+};
+
+void stm32mp1_deconfigure_uart_pins(void)
+{
+ size_t i;
+
+ for (i = 0U; i < ARRAY_SIZE(gpio_list); i++) {
+ set_gpio_reset_cfg(gpio_list[i].bank, gpio_list[i].pin);
+ }
+}
+#endif
+
+uint32_t stm32mp_get_chip_version(void)
+{
+#if STM32MP13
+ return stm32mp1_syscfg_get_chip_version();
+#endif
+#if STM32MP15
+ uint32_t version = 0U;
+
+ if (stm32mp1_dbgmcu_get_chip_version(&version) < 0) {
+ INFO("Cannot get CPU version, debug disabled\n");
+ return 0U;
+ }
+
+ return version;
+#endif
+}
+
+uint32_t stm32mp_get_chip_dev_id(void)
+{
+#if STM32MP13
+ return stm32mp1_syscfg_get_chip_dev_id();
+#endif
+#if STM32MP15
+ uint32_t dev_id;
+
+ if (stm32mp1_dbgmcu_get_chip_dev_id(&dev_id) < 0) {
+ INFO("Use default chip ID, debug disabled\n");
+ dev_id = STM32MP1_CHIP_ID;
+ }
+
+ return dev_id;
+#endif
+}
+
+static uint32_t get_part_number(void)
+{
+ static uint32_t part_number;
+
+ if (part_number != 0U) {
+ return part_number;
+ }
+
+ if (stm32_get_otp_value(PART_NUMBER_OTP, &part_number) != 0) {
+ panic();
+ }
+
+ part_number = (part_number & PART_NUMBER_OTP_PART_MASK) >>
+ PART_NUMBER_OTP_PART_SHIFT;
+
+ part_number |= stm32mp_get_chip_dev_id() << 16;
+
+ return part_number;
+}
+
+#if STM32MP15
+static uint32_t get_cpu_package(void)
+{
+ uint32_t package;
+
+ if (stm32_get_otp_value(PACKAGE_OTP, &package) != 0) {
+ panic();
+ }
+
+ package = (package & PACKAGE_OTP_PKG_MASK) >>
+ PACKAGE_OTP_PKG_SHIFT;
+
+ return package;
+}
+#endif
+
+void stm32mp_get_soc_name(char name[STM32_SOC_NAME_SIZE])
+{
+ char *cpu_s, *cpu_r, *pkg;
+
+ /* MPUs Part Numbers */
+ switch (get_part_number()) {
+#if STM32MP13
+ case STM32MP135F_PART_NB:
+ cpu_s = "135F";
+ break;
+ case STM32MP135D_PART_NB:
+ cpu_s = "135D";
+ break;
+ case STM32MP135C_PART_NB:
+ cpu_s = "135C";
+ break;
+ case STM32MP135A_PART_NB:
+ cpu_s = "135A";
+ break;
+ case STM32MP133F_PART_NB:
+ cpu_s = "133F";
+ break;
+ case STM32MP133D_PART_NB:
+ cpu_s = "133D";
+ break;
+ case STM32MP133C_PART_NB:
+ cpu_s = "133C";
+ break;
+ case STM32MP133A_PART_NB:
+ cpu_s = "133A";
+ break;
+ case STM32MP131F_PART_NB:
+ cpu_s = "131F";
+ break;
+ case STM32MP131D_PART_NB:
+ cpu_s = "131D";
+ break;
+ case STM32MP131C_PART_NB:
+ cpu_s = "131C";
+ break;
+ case STM32MP131A_PART_NB:
+ cpu_s = "131A";
+ break;
+#endif
+#if STM32MP15
+ 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;
+ case STM32MP157F_PART_NB:
+ cpu_s = "157F";
+ break;
+ case STM32MP157D_PART_NB:
+ cpu_s = "157D";
+ break;
+ case STM32MP153F_PART_NB:
+ cpu_s = "153F";
+ break;
+ case STM32MP153D_PART_NB:
+ cpu_s = "153D";
+ break;
+ case STM32MP151F_PART_NB:
+ cpu_s = "151F";
+ break;
+ case STM32MP151D_PART_NB:
+ cpu_s = "151D";
+ break;
+#endif
+ default:
+ cpu_s = "????";
+ break;
+ }
+
+ /* Package */
+#if STM32MP13
+ /* On STM32MP13, package is not present in OTP */
+ pkg = "";
+#endif
+#if STM32MP15
+ switch (get_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;
+ }
+#endif
+
+ /* REVISION */
+ switch (stm32mp_get_chip_version()) {
+ case STM32MP1_REV_B:
+ cpu_r = "B";
+ break;
+#if STM32MP13
+ case STM32MP1_REV_Y:
+ cpu_r = "Y";
+ break;
+#endif
+ case STM32MP1_REV_Z:
+ cpu_r = "Z";
+ break;
+ default:
+ cpu_r = "?";
+ break;
+ }
+
+ snprintf(name, STM32_SOC_NAME_SIZE,
+ "STM32MP%s%s Rev.%s", cpu_s, pkg, cpu_r);
+}
+
+void stm32mp_print_cpuinfo(void)
+{
+ char name[STM32_SOC_NAME_SIZE];
+
+ stm32mp_get_soc_name(name);
+ NOTICE("CPU: %s\n", name);
+}
+
+void stm32mp_print_boardinfo(void)
+{
+ uint32_t board_id = 0;
+
+ if (stm32_get_otp_value(BOARD_ID_OTP, &board_id) != 0) {
+ return;
+ }
+
+ if (board_id != 0U) {
+ char rev[2];
+
+ rev[0] = BOARD_ID2REV(board_id) - 1 + 'A';
+ rev[1] = '\0';
+ NOTICE("Board: MB%04x Var%u.%u Rev.%s-%02u\n",
+ BOARD_ID2NB(board_id),
+ BOARD_ID2VARCPN(board_id),
+ BOARD_ID2VARFG(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)
+{
+#if STM32MP13
+ return true;
+#endif
+#if STM32MP15
+ bool single_core = false;
+
+ switch (get_part_number()) {
+ case STM32MP151A_PART_NB:
+ case STM32MP151C_PART_NB:
+ case STM32MP151D_PART_NB:
+ case STM32MP151F_PART_NB:
+ single_core = true;
+ break;
+ default:
+ break;
+ }
+
+ return single_core;
+#endif
+}
+
+/* Return true when device is in closed state */
+bool stm32mp_is_closed_device(void)
+{
+ uint32_t value;
+
+ if (stm32_get_otp_value(CFG0_OTP, &value) != 0) {
+ return true;
+ }
+
+#if STM32MP13
+ value = (value & CFG0_OTP_MODE_MASK) >> CFG0_OTP_MODE_SHIFT;
+
+ switch (value) {
+ case CFG0_OPEN_DEVICE:
+ return false;
+ case CFG0_CLOSED_DEVICE:
+ case CFG0_CLOSED_DEVICE_NO_BOUNDARY_SCAN:
+ case CFG0_CLOSED_DEVICE_NO_JTAG:
+ return true;
+ default:
+ panic();
+ }
+#endif
+#if STM32MP15
+ return (value & CFG0_CLOSED_DEVICE) == CFG0_CLOSED_DEVICE;
+#endif
+}
+
+/* Return true when device supports secure boot */
+bool stm32mp_is_auth_supported(void)
+{
+ bool supported = false;
+
+ switch (get_part_number()) {
+#if STM32MP13
+ case STM32MP131C_PART_NB:
+ case STM32MP131F_PART_NB:
+ case STM32MP133C_PART_NB:
+ case STM32MP133F_PART_NB:
+ case STM32MP135C_PART_NB:
+ case STM32MP135F_PART_NB:
+#endif
+#if STM32MP15
+ case STM32MP151C_PART_NB:
+ case STM32MP151F_PART_NB:
+ case STM32MP153C_PART_NB:
+ case STM32MP153F_PART_NB:
+ case STM32MP157C_PART_NB:
+ case STM32MP157F_PART_NB:
+#endif
+ supported = true;
+ break;
+ default:
+ break;
+ }
+
+ return supported;
+}
+
+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 (stm32_get_otp_value(HW2_OTP, &otp_value) != 0) {
+ 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_value;
+ uint32_t otp;
+ uint32_t result;
+
+ if (stm32_get_otp_index(HW2_OTP, &otp, NULL) != 0) {
+ panic();
+ }
+
+ if (stm32_get_otp_value(HW2_OTP, &otp_value) != 0) {
+ panic();
+ }
+
+ if ((flags & IWDG_DISABLE_ON_STOP) != 0) {
+ otp_value |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STOP_POS);
+ }
+
+ if ((flags & IWDG_DISABLE_ON_STANDBY) != 0) {
+ otp_value |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STANDBY_POS);
+ }
+
+ result = bsec_write_otp(otp_value, otp);
+ if (result != BSEC_OK) {
+ return result;
+ }
+
+ /* Sticky lock OTP_IWDG (read and write) */
+ if ((bsec_set_sr_lock(otp) != BSEC_OK) ||
+ (bsec_set_sw_lock(otp) != BSEC_OK)) {
+ return BSEC_LOCK_FAIL;
+ }
+
+ return BSEC_OK;
+}
+#endif
+
+void stm32_save_boot_interface(uint32_t interface, uint32_t instance)
+{
+ uintptr_t bkpr_itf_idx = tamp_bkpr(TAMP_BOOT_MODE_BACKUP_REG_ID);
+
+ clk_enable(RTCAPB);
+
+ mmio_clrsetbits_32(bkpr_itf_idx,
+ TAMP_BOOT_MODE_ITF_MASK,
+ ((interface << 4) | (instance & 0xFU)) <<
+ TAMP_BOOT_MODE_ITF_SHIFT);
+
+ clk_disable(RTCAPB);
+}
+
+void stm32_get_boot_interface(uint32_t *interface, uint32_t *instance)
+{
+ static uint32_t itf;
+
+ if (itf == 0U) {
+ uintptr_t bkpr = tamp_bkpr(TAMP_BOOT_MODE_BACKUP_REG_ID);
+
+ clk_enable(RTCAPB);
+
+ itf = (mmio_read_32(bkpr) & TAMP_BOOT_MODE_ITF_MASK) >>
+ TAMP_BOOT_MODE_ITF_SHIFT;
+
+ clk_disable(RTCAPB);
+ }
+
+ *interface = itf >> 4;
+ *instance = itf & 0xFU;
+}
+
+void stm32_save_boot_auth(uint32_t auth_status, uint32_t boot_partition)
+{
+ uint32_t boot_status = tamp_bkpr(TAMP_BOOT_MODE_BACKUP_REG_ID);
+
+ clk_enable(RTCAPB);
+
+ mmio_clrsetbits_32(boot_status,
+ TAMP_BOOT_MODE_AUTH_MASK,
+ ((auth_status << 4) | (boot_partition & 0xFU)) <<
+ TAMP_BOOT_MODE_AUTH_SHIFT);
+
+ clk_disable(RTCAPB);
+}
+
+#if PSA_FWU_SUPPORT
+void stm32mp1_fwu_set_boot_idx(void)
+{
+ clk_enable(RTCAPB);
+ mmio_clrsetbits_32(tamp_bkpr(TAMP_BOOT_FWU_INFO_REG_ID),
+ TAMP_BOOT_FWU_INFO_IDX_MSK,
+ (plat_fwu_get_boot_idx() << TAMP_BOOT_FWU_INFO_IDX_OFF) &
+ TAMP_BOOT_FWU_INFO_IDX_MSK);
+ clk_disable(RTCAPB);
+}
+
+uint32_t stm32_get_and_dec_fwu_trial_boot_cnt(void)
+{
+ uintptr_t bkpr_fwu_cnt = tamp_bkpr(TAMP_BOOT_FWU_INFO_REG_ID);
+ uint32_t try_cnt;
+
+ clk_enable(RTCAPB);
+ try_cnt = (mmio_read_32(bkpr_fwu_cnt) & TAMP_BOOT_FWU_INFO_CNT_MSK) >>
+ TAMP_BOOT_FWU_INFO_CNT_OFF;
+
+ assert(try_cnt <= FWU_MAX_TRIAL_REBOOT);
+
+ if (try_cnt != 0U) {
+ mmio_clrsetbits_32(bkpr_fwu_cnt, TAMP_BOOT_FWU_INFO_CNT_MSK,
+ (try_cnt - 1U) << TAMP_BOOT_FWU_INFO_CNT_OFF);
+ }
+ clk_disable(RTCAPB);
+
+ return try_cnt;
+}
+
+void stm32_set_max_fwu_trial_boot_cnt(void)
+{
+ uintptr_t bkpr_fwu_cnt = tamp_bkpr(TAMP_BOOT_FWU_INFO_REG_ID);
+
+ clk_enable(RTCAPB);
+ mmio_clrsetbits_32(bkpr_fwu_cnt, TAMP_BOOT_FWU_INFO_CNT_MSK,
+ (FWU_MAX_TRIAL_REBOOT << TAMP_BOOT_FWU_INFO_CNT_OFF) &
+ TAMP_BOOT_FWU_INFO_CNT_MSK);
+ clk_disable(RTCAPB);
+}
+#endif /* PSA_FWU_SUPPORT */
diff --git a/plat/st/stm32mp1/stm32mp1_scmi.c b/plat/st/stm32mp1/stm32mp1_scmi.c
new file mode 100644
index 0000000..98585dc
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_scmi.c
@@ -0,0 +1,479 @@
+/*
+ * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <drivers/clk.h>
+#include <drivers/scmi-msg.h>
+#include <drivers/scmi.h>
+#include <drivers/st/stm32mp1_clk.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <dt-bindings/clock/stm32mp1-clks.h>
+#include <dt-bindings/reset/stm32mp1-resets.h>
+
+#define TIMEOUT_US_1MS 1000U
+
+#define SCMI_CLOCK_NAME_SIZE 16U
+#define SCMI_RSTD_NAME_SIZE 16U
+
+/*
+ * struct stm32_scmi_clk - Data for the exposed clock
+ * @clock_id: Clock identifier in RCC clock driver
+ * @name: Clock string ID exposed to agent
+ * @enabled: State of the SCMI clock
+ */
+struct stm32_scmi_clk {
+ unsigned long clock_id;
+ const char *name;
+ bool enabled;
+};
+
+/*
+ * struct stm32_scmi_rstd - Data for the exposed reset controller
+ * @reset_id: Reset identifier in RCC reset driver
+ * @name: Reset string ID exposed to agent
+ */
+struct stm32_scmi_rstd {
+ unsigned long reset_id;
+ const char *name;
+};
+
+/* Locate all non-secure SMT message buffers in last page of SYSRAM */
+#define SMT_BUFFER_BASE STM32MP_SCMI_NS_SHM_BASE
+#define SMT_BUFFER0_BASE SMT_BUFFER_BASE
+#define SMT_BUFFER1_BASE (SMT_BUFFER_BASE + 0x200)
+
+CASSERT((STM32MP_SCMI_NS_SHM_BASE + STM32MP_SCMI_NS_SHM_SIZE) >=
+ (SMT_BUFFER1_BASE + SMT_BUF_SLOT_SIZE),
+ assert_scmi_non_secure_shm_fits_scmi_overall_buffer_size);
+
+static struct scmi_msg_channel scmi_channel[] = {
+ [0] = {
+ .shm_addr = SMT_BUFFER0_BASE,
+ .shm_size = SMT_BUF_SLOT_SIZE,
+ },
+ [1] = {
+ .shm_addr = SMT_BUFFER1_BASE,
+ .shm_size = SMT_BUF_SLOT_SIZE,
+ },
+};
+
+struct scmi_msg_channel *plat_scmi_get_channel(unsigned int agent_id)
+{
+ assert(agent_id < ARRAY_SIZE(scmi_channel));
+
+ return &scmi_channel[agent_id];
+}
+
+#define CLOCK_CELL(_scmi_id, _id, _name, _init_enabled) \
+ [_scmi_id] = { \
+ .clock_id = _id, \
+ .name = _name, \
+ .enabled = _init_enabled, \
+ }
+
+static struct stm32_scmi_clk stm32_scmi0_clock[] = {
+ CLOCK_CELL(CK_SCMI0_HSE, CK_HSE, "ck_hse", true),
+ CLOCK_CELL(CK_SCMI0_HSI, CK_HSI, "ck_hsi", true),
+ CLOCK_CELL(CK_SCMI0_CSI, CK_CSI, "ck_csi", true),
+ CLOCK_CELL(CK_SCMI0_LSE, CK_LSE, "ck_lse", true),
+ CLOCK_CELL(CK_SCMI0_LSI, CK_LSI, "ck_lsi", true),
+ CLOCK_CELL(CK_SCMI0_PLL2_Q, PLL2_Q, "pll2_q", true),
+ CLOCK_CELL(CK_SCMI0_PLL2_R, PLL2_R, "pll2_r", true),
+ CLOCK_CELL(CK_SCMI0_MPU, CK_MPU, "ck_mpu", true),
+ CLOCK_CELL(CK_SCMI0_AXI, CK_AXI, "ck_axi", true),
+ CLOCK_CELL(CK_SCMI0_BSEC, BSEC, "bsec", true),
+ CLOCK_CELL(CK_SCMI0_CRYP1, CRYP1, "cryp1", false),
+ CLOCK_CELL(CK_SCMI0_GPIOZ, GPIOZ, "gpioz", false),
+ CLOCK_CELL(CK_SCMI0_HASH1, HASH1, "hash1", false),
+ CLOCK_CELL(CK_SCMI0_I2C4, I2C4_K, "i2c4_k", false),
+ CLOCK_CELL(CK_SCMI0_I2C6, I2C6_K, "i2c6_k", false),
+ CLOCK_CELL(CK_SCMI0_IWDG1, IWDG1, "iwdg1", false),
+ CLOCK_CELL(CK_SCMI0_RNG1, RNG1_K, "rng1_k", true),
+ CLOCK_CELL(CK_SCMI0_RTC, RTC, "ck_rtc", true),
+ CLOCK_CELL(CK_SCMI0_RTCAPB, RTCAPB, "rtcapb", true),
+ CLOCK_CELL(CK_SCMI0_SPI6, SPI6_K, "spi6_k", false),
+ CLOCK_CELL(CK_SCMI0_USART1, USART1_K, "usart1_k", false),
+};
+
+static struct stm32_scmi_clk stm32_scmi1_clock[] = {
+ CLOCK_CELL(CK_SCMI1_PLL3_Q, PLL3_Q, "pll3_q", true),
+ CLOCK_CELL(CK_SCMI1_PLL3_R, PLL3_R, "pll3_r", true),
+ CLOCK_CELL(CK_SCMI1_MCU, CK_MCU, "ck_mcu", false),
+};
+
+#define RESET_CELL(_scmi_id, _id, _name) \
+ [_scmi_id] = { \
+ .reset_id = _id, \
+ .name = _name, \
+ }
+
+static struct stm32_scmi_rstd stm32_scmi0_reset_domain[] = {
+ RESET_CELL(RST_SCMI0_SPI6, SPI6_R, "spi6"),
+ RESET_CELL(RST_SCMI0_I2C4, I2C4_R, "i2c4"),
+ RESET_CELL(RST_SCMI0_I2C6, I2C6_R, "i2c6"),
+ RESET_CELL(RST_SCMI0_USART1, USART1_R, "usart1"),
+ RESET_CELL(RST_SCMI0_STGEN, STGEN_R, "stgen"),
+ RESET_CELL(RST_SCMI0_GPIOZ, GPIOZ_R, "gpioz"),
+ RESET_CELL(RST_SCMI0_CRYP1, CRYP1_R, "cryp1"),
+ RESET_CELL(RST_SCMI0_HASH1, HASH1_R, "hash1"),
+ RESET_CELL(RST_SCMI0_RNG1, RNG1_R, "rng1"),
+ RESET_CELL(RST_SCMI0_MDMA, MDMA_R, "mdma"),
+ RESET_CELL(RST_SCMI0_MCU, MCU_R, "mcu"),
+};
+
+struct scmi_agent_resources {
+ struct stm32_scmi_clk *clock;
+ size_t clock_count;
+ struct stm32_scmi_rstd *rstd;
+ size_t rstd_count;
+};
+
+static const struct scmi_agent_resources agent_resources[] = {
+ [0] = {
+ .clock = stm32_scmi0_clock,
+ .clock_count = ARRAY_SIZE(stm32_scmi0_clock),
+ .rstd = stm32_scmi0_reset_domain,
+ .rstd_count = ARRAY_SIZE(stm32_scmi0_reset_domain),
+ },
+ [1] = {
+ .clock = stm32_scmi1_clock,
+ .clock_count = ARRAY_SIZE(stm32_scmi1_clock),
+ },
+};
+
+static const struct scmi_agent_resources *find_resource(unsigned int agent_id)
+{
+ assert(agent_id < ARRAY_SIZE(agent_resources));
+
+ return &agent_resources[agent_id];
+}
+
+#if ENABLE_ASSERTIONS
+static size_t plat_scmi_protocol_count_paranoid(void)
+{
+ unsigned int n = 0U;
+ unsigned int count = 0U;
+
+ for (n = 0U; n < ARRAY_SIZE(agent_resources); n++) {
+ if (agent_resources[n].clock_count) {
+ count++;
+ break;
+ }
+ }
+
+ for (n = 0U; n < ARRAY_SIZE(agent_resources); n++) {
+ if (agent_resources[n].rstd_count) {
+ count++;
+ break;
+ }
+ }
+
+ return count;
+}
+#endif
+
+static const char vendor[] = "ST";
+static const char sub_vendor[] = "";
+
+const char *plat_scmi_vendor_name(void)
+{
+ return vendor;
+}
+
+const char *plat_scmi_sub_vendor_name(void)
+{
+ return sub_vendor;
+}
+
+/* Currently supporting Clocks and Reset Domains */
+static const uint8_t plat_protocol_list[] = {
+ SCMI_PROTOCOL_ID_CLOCK,
+ SCMI_PROTOCOL_ID_RESET_DOMAIN,
+ 0U /* Null termination */
+};
+
+size_t plat_scmi_protocol_count(void)
+{
+ const size_t count = ARRAY_SIZE(plat_protocol_list) - 1U;
+
+ assert(count == plat_scmi_protocol_count_paranoid());
+
+ return count;
+}
+
+const uint8_t *plat_scmi_protocol_list(unsigned int agent_id __unused)
+{
+ assert(plat_scmi_protocol_count_paranoid() ==
+ (ARRAY_SIZE(plat_protocol_list) - 1U));
+
+ return plat_protocol_list;
+}
+
+/*
+ * Platform SCMI clocks
+ */
+static struct stm32_scmi_clk *find_clock(unsigned int agent_id,
+ unsigned int scmi_id)
+{
+ const struct scmi_agent_resources *resource = find_resource(agent_id);
+ size_t n = 0U;
+
+ if (resource != NULL) {
+ for (n = 0U; n < resource->clock_count; n++) {
+ if (n == scmi_id) {
+ return &resource->clock[n];
+ }
+ }
+ }
+
+ return NULL;
+}
+
+size_t plat_scmi_clock_count(unsigned int agent_id)
+{
+ const struct scmi_agent_resources *resource = find_resource(agent_id);
+
+ if (resource == NULL) {
+ return 0U;
+ }
+
+ return resource->clock_count;
+}
+
+const char *plat_scmi_clock_get_name(unsigned int agent_id,
+ unsigned int scmi_id)
+{
+ struct stm32_scmi_clk *clock = find_clock(agent_id, scmi_id);
+
+ if ((clock == NULL) ||
+ !stm32mp_nsec_can_access_clock(clock->clock_id)) {
+ return NULL;
+ }
+
+ return clock->name;
+}
+
+int32_t plat_scmi_clock_rates_array(unsigned int agent_id, unsigned int scmi_id,
+ unsigned long *array, size_t *nb_elts)
+{
+ struct stm32_scmi_clk *clock = find_clock(agent_id, scmi_id);
+
+ if (clock == NULL) {
+ return SCMI_NOT_FOUND;
+ }
+
+ if (!stm32mp_nsec_can_access_clock(clock->clock_id)) {
+ return SCMI_DENIED;
+ }
+
+ if (array == NULL) {
+ *nb_elts = 1U;
+ } else if (*nb_elts == 1U) {
+ *array = clk_get_rate(clock->clock_id);
+ } else {
+ return SCMI_GENERIC_ERROR;
+ }
+
+ return SCMI_SUCCESS;
+}
+
+unsigned long plat_scmi_clock_get_rate(unsigned int agent_id,
+ unsigned int scmi_id)
+{
+ struct stm32_scmi_clk *clock = find_clock(agent_id, scmi_id);
+
+ if ((clock == NULL) ||
+ !stm32mp_nsec_can_access_clock(clock->clock_id)) {
+ return 0U;
+ }
+
+ return clk_get_rate(clock->clock_id);
+}
+
+int32_t plat_scmi_clock_get_state(unsigned int agent_id, unsigned int scmi_id)
+{
+ struct stm32_scmi_clk *clock = find_clock(agent_id, scmi_id);
+
+ if ((clock == NULL) ||
+ !stm32mp_nsec_can_access_clock(clock->clock_id)) {
+ return 0U;
+ }
+
+ return (int32_t)clock->enabled;
+}
+
+int32_t plat_scmi_clock_set_state(unsigned int agent_id, unsigned int scmi_id,
+ bool enable_not_disable)
+{
+ struct stm32_scmi_clk *clock = find_clock(agent_id, scmi_id);
+
+ if (clock == NULL) {
+ return SCMI_NOT_FOUND;
+ }
+
+ if (!stm32mp_nsec_can_access_clock(clock->clock_id)) {
+ return SCMI_DENIED;
+ }
+
+ if (enable_not_disable) {
+ if (!clock->enabled) {
+ VERBOSE("SCMI clock %u enable\n", scmi_id);
+ clk_enable(clock->clock_id);
+ clock->enabled = true;
+ }
+ } else {
+ if (clock->enabled) {
+ VERBOSE("SCMI clock %u disable\n", scmi_id);
+ clk_disable(clock->clock_id);
+ clock->enabled = false;
+ }
+ }
+
+ return SCMI_SUCCESS;
+}
+
+/*
+ * Platform SCMI reset domains
+ */
+static struct stm32_scmi_rstd *find_rstd(unsigned int agent_id,
+ unsigned int scmi_id)
+{
+ const struct scmi_agent_resources *resource = find_resource(agent_id);
+ size_t n;
+
+ if (resource != NULL) {
+ for (n = 0U; n < resource->rstd_count; n++) {
+ if (n == scmi_id) {
+ return &resource->rstd[n];
+ }
+ }
+ }
+
+ return NULL;
+}
+
+const char *plat_scmi_rstd_get_name(unsigned int agent_id, unsigned int scmi_id)
+{
+ const struct stm32_scmi_rstd *rstd = find_rstd(agent_id, scmi_id);
+
+ if (rstd == NULL) {
+ return NULL;
+ }
+
+ return rstd->name;
+}
+
+size_t plat_scmi_rstd_count(unsigned int agent_id)
+{
+ const struct scmi_agent_resources *resource = find_resource(agent_id);
+
+ if (resource == NULL) {
+ return 0U;
+ }
+
+ return resource->rstd_count;
+}
+
+int32_t plat_scmi_rstd_autonomous(unsigned int agent_id, unsigned int scmi_id,
+ uint32_t state)
+{
+ const struct stm32_scmi_rstd *rstd = find_rstd(agent_id, scmi_id);
+
+ if (rstd == NULL) {
+ return SCMI_NOT_FOUND;
+ }
+
+ if (!stm32mp_nsec_can_access_reset(rstd->reset_id)) {
+ return SCMI_DENIED;
+ }
+
+ /* Supports only reset with context loss */
+ if (state != 0U) {
+ return SCMI_NOT_SUPPORTED;
+ }
+
+ VERBOSE("SCMI reset %lu cycle\n", rstd->reset_id);
+
+ if (stm32mp_reset_assert(rstd->reset_id, TIMEOUT_US_1MS)) {
+ return SCMI_HARDWARE_ERROR;
+ }
+
+ if (stm32mp_reset_deassert(rstd->reset_id, TIMEOUT_US_1MS)) {
+ return SCMI_HARDWARE_ERROR;
+ }
+
+ return SCMI_SUCCESS;
+}
+
+int32_t plat_scmi_rstd_set_state(unsigned int agent_id, unsigned int scmi_id,
+ bool assert_not_deassert)
+{
+ const struct stm32_scmi_rstd *rstd = find_rstd(agent_id, scmi_id);
+
+ if (rstd == NULL) {
+ return SCMI_NOT_FOUND;
+ }
+
+ if (!stm32mp_nsec_can_access_reset(rstd->reset_id)) {
+ return SCMI_DENIED;
+ }
+
+ if (assert_not_deassert) {
+ VERBOSE("SCMI reset %lu set\n", rstd->reset_id);
+ stm32mp_reset_set(rstd->reset_id);
+ } else {
+ VERBOSE("SCMI reset %lu release\n", rstd->reset_id);
+ stm32mp_reset_release(rstd->reset_id);
+ }
+
+ return SCMI_SUCCESS;
+}
+
+/*
+ * Initialize platform SCMI resources
+ */
+void stm32mp1_init_scmi_server(void)
+{
+ size_t i;
+
+ for (i = 0U; i < ARRAY_SIZE(scmi_channel); i++) {
+ scmi_smt_init_agent_channel(&scmi_channel[i]);
+ }
+
+ for (i = 0U; i < ARRAY_SIZE(agent_resources); i++) {
+ const struct scmi_agent_resources *res = &agent_resources[i];
+ size_t j;
+
+ for (j = 0U; j < res->clock_count; j++) {
+ struct stm32_scmi_clk *clk = &res->clock[j];
+
+ if ((clk->name == NULL) ||
+ (strlen(clk->name) >= SCMI_CLOCK_NAME_SIZE)) {
+ ERROR("Invalid SCMI clock name\n");
+ panic();
+ }
+
+ /* Sync SCMI clocks with their targeted initial state */
+ if (clk->enabled &&
+ stm32mp_nsec_can_access_clock(clk->clock_id)) {
+ clk_enable(clk->clock_id);
+ }
+ }
+
+ for (j = 0U; j < res->rstd_count; j++) {
+ struct stm32_scmi_rstd *rstd = &res->rstd[j];
+
+ if ((rstd->name == NULL) ||
+ (strlen(rstd->name) >= SCMI_RSTD_NAME_SIZE)) {
+ ERROR("Invalid SCMI reset domain name\n");
+ panic();
+ }
+ }
+ }
+}
diff --git a/plat/st/stm32mp1/stm32mp1_shared_resources.c b/plat/st/stm32mp1/stm32mp1_shared_resources.c
new file mode 100644
index 0000000..a0ca697
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_shared_resources.c
@@ -0,0 +1,596 @@
+/*
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <drivers/st/etzpc.h>
+#include <drivers/st/stm32_gpio.h>
+
+#include <platform_def.h>
+#include <stm32mp_shared_resources.h>
+
+/*
+ * Once one starts to get the resource registering state, one cannot register
+ * new resources. This ensures resource state cannot change.
+ */
+static bool registering_locked;
+
+/*
+ * Shared peripherals and resources registration
+ *
+ * Each resource assignation is stored in a table. The state defaults
+ * to PERIPH_UNREGISTERED if the resource is not explicitly assigned.
+ *
+ * Resource driver that as not embedded (a.k.a their related CFG_xxx build
+ * directive is disabled) are assigned to the non-secure world.
+ *
+ * Each pin of the GPIOZ bank can be secure or non-secure.
+ *
+ * It is the platform responsibility the ensure resource assignation
+ * matches the access permission firewalls configuration.
+ */
+enum shres_state {
+ SHRES_UNREGISTERED = 0,
+ SHRES_SECURE,
+ SHRES_NON_SECURE,
+};
+
+/* Force uint8_t array for array of enum shres_state for size considerations */
+static uint8_t shres_state[STM32MP1_SHRES_COUNT];
+
+static const char *shres2str_id_tbl[STM32MP1_SHRES_COUNT] __unused = {
+ [STM32MP1_SHRES_GPIOZ(0)] = "GPIOZ0",
+ [STM32MP1_SHRES_GPIOZ(1)] = "GPIOZ1",
+ [STM32MP1_SHRES_GPIOZ(2)] = "GPIOZ2",
+ [STM32MP1_SHRES_GPIOZ(3)] = "GPIOZ3",
+ [STM32MP1_SHRES_GPIOZ(4)] = "GPIOZ4",
+ [STM32MP1_SHRES_GPIOZ(5)] = "GPIOZ5",
+ [STM32MP1_SHRES_GPIOZ(6)] = "GPIOZ6",
+ [STM32MP1_SHRES_GPIOZ(7)] = "GPIOZ7",
+ [STM32MP1_SHRES_IWDG1] = "IWDG1",
+ [STM32MP1_SHRES_USART1] = "USART1",
+ [STM32MP1_SHRES_SPI6] = "SPI6",
+ [STM32MP1_SHRES_I2C4] = "I2C4",
+ [STM32MP1_SHRES_RNG1] = "RNG1",
+ [STM32MP1_SHRES_HASH1] = "HASH1",
+ [STM32MP1_SHRES_CRYP1] = "CRYP1",
+ [STM32MP1_SHRES_I2C6] = "I2C6",
+ [STM32MP1_SHRES_RTC] = "RTC",
+ [STM32MP1_SHRES_MCU] = "MCU",
+ [STM32MP1_SHRES_MDMA] = "MDMA",
+ [STM32MP1_SHRES_PLL3] = "PLL3",
+};
+
+static const char __unused *shres2str_id(enum stm32mp_shres id)
+{
+ assert(id < ARRAY_SIZE(shres2str_id_tbl));
+
+ return shres2str_id_tbl[id];
+}
+
+static const char __unused *shres2str_state_tbl[] = {
+ [SHRES_UNREGISTERED] = "unregistered",
+ [SHRES_NON_SECURE] = "non-secure",
+ [SHRES_SECURE] = "secure",
+};
+
+static const char __unused *shres2str_state(unsigned int state)
+{
+ assert(state < ARRAY_SIZE(shres2str_state_tbl));
+
+ return shres2str_state_tbl[state];
+}
+
+/* Get resource state: these accesses lock the registering support */
+static void lock_registering(void)
+{
+ registering_locked = true;
+}
+
+static bool periph_is_non_secure(enum stm32mp_shres id)
+{
+ lock_registering();
+
+ return (shres_state[id] == SHRES_NON_SECURE) ||
+ (shres_state[id] == SHRES_UNREGISTERED);
+}
+
+static bool periph_is_secure(enum stm32mp_shres id)
+{
+ return !periph_is_non_secure(id);
+}
+
+/* GPIOZ pin count is saved in RAM to prevent parsing FDT several times */
+static int8_t gpioz_nbpin = -1;
+
+static unsigned int get_gpio_nbpin(unsigned int bank)
+{
+ if (bank != GPIO_BANK_Z) {
+ int count = fdt_get_gpio_bank_pin_count(bank);
+
+ assert((count >= 0) && ((unsigned int)count <= (GPIO_PIN_MAX + 1)));
+
+ return (unsigned int)count;
+ }
+
+ if (gpioz_nbpin < 0) {
+ int count = fdt_get_gpio_bank_pin_count(GPIO_BANK_Z);
+
+ assert((count == 0) || (count == STM32MP_GPIOZ_PIN_MAX_COUNT));
+
+ gpioz_nbpin = count;
+ }
+
+ return (unsigned int)gpioz_nbpin;
+}
+
+static unsigned int get_gpioz_nbpin(void)
+{
+ return get_gpio_nbpin(GPIO_BANK_Z);
+}
+
+static void register_periph(enum stm32mp_shres id, unsigned int state)
+{
+ assert((id < STM32MP1_SHRES_COUNT) &&
+ ((state == SHRES_SECURE) || (state == SHRES_NON_SECURE)));
+
+ if (registering_locked) {
+ if (shres_state[id] == state) {
+ return;
+ }
+ panic();
+ }
+
+ if ((shres_state[id] != SHRES_UNREGISTERED) &&
+ (shres_state[id] != state)) {
+ VERBOSE("Cannot change %s from %s to %s\n",
+ shres2str_id(id),
+ shres2str_state(shres_state[id]),
+ shres2str_state(state));
+ panic();
+ }
+
+ if (shres_state[id] == SHRES_UNREGISTERED) {
+ VERBOSE("Register %s as %s\n",
+ shres2str_id(id), shres2str_state(state));
+ }
+
+ if ((id >= STM32MP1_SHRES_GPIOZ(0)) &&
+ (id <= STM32MP1_SHRES_GPIOZ(7)) &&
+ ((unsigned int)(id - STM32MP1_SHRES_GPIOZ(0)) >= get_gpioz_nbpin())) {
+ ERROR("Invalid GPIO pin %d, %u pin(s) available\n",
+ (int)(id - STM32MP1_SHRES_GPIOZ(0)), get_gpioz_nbpin());
+ panic();
+ }
+
+ shres_state[id] = (uint8_t)state;
+
+ /* Explore clock tree to lock dependencies */
+ if (state == SHRES_SECURE) {
+ enum stm32mp_shres clock_res_id;
+
+ switch (id) {
+ case STM32MP1_SHRES_GPIOZ(0):
+ case STM32MP1_SHRES_GPIOZ(1):
+ case STM32MP1_SHRES_GPIOZ(2):
+ case STM32MP1_SHRES_GPIOZ(3):
+ case STM32MP1_SHRES_GPIOZ(4):
+ case STM32MP1_SHRES_GPIOZ(5):
+ case STM32MP1_SHRES_GPIOZ(6):
+ case STM32MP1_SHRES_GPIOZ(7):
+ clock_res_id = GPIOZ;
+ break;
+ case STM32MP1_SHRES_IWDG1:
+ clock_res_id = IWDG1;
+ break;
+ case STM32MP1_SHRES_USART1:
+ clock_res_id = USART1_K;
+ break;
+ case STM32MP1_SHRES_SPI6:
+ clock_res_id = SPI6_K;
+ break;
+ case STM32MP1_SHRES_I2C4:
+ clock_res_id = I2C4_K;
+ break;
+ case STM32MP1_SHRES_RNG1:
+ clock_res_id = RNG1_K;
+ break;
+ case STM32MP1_SHRES_HASH1:
+ clock_res_id = HASH1;
+ break;
+ case STM32MP1_SHRES_CRYP1:
+ clock_res_id = CRYP1;
+ break;
+ case STM32MP1_SHRES_I2C6:
+ clock_res_id = I2C6_K;
+ break;
+ case STM32MP1_SHRES_RTC:
+ clock_res_id = RTC;
+ break;
+ default:
+ /* No clock resource dependency */
+ return;
+ }
+
+ stm32mp1_register_clock_parents_secure(clock_res_id);
+ }
+}
+
+/* Register resource by ID */
+void stm32mp_register_secure_periph(enum stm32mp_shres id)
+{
+ register_periph(id, SHRES_SECURE);
+}
+
+void stm32mp_register_non_secure_periph(enum stm32mp_shres id)
+{
+ register_periph(id, SHRES_NON_SECURE);
+}
+
+static void register_periph_iomem(uintptr_t base, unsigned int state)
+{
+ enum stm32mp_shres id;
+
+ switch (base) {
+ case CRYP1_BASE:
+ id = STM32MP1_SHRES_CRYP1;
+ break;
+ case HASH1_BASE:
+ id = STM32MP1_SHRES_HASH1;
+ break;
+ case I2C4_BASE:
+ id = STM32MP1_SHRES_I2C4;
+ break;
+ case I2C6_BASE:
+ id = STM32MP1_SHRES_I2C6;
+ break;
+ case IWDG1_BASE:
+ id = STM32MP1_SHRES_IWDG1;
+ break;
+ case RNG1_BASE:
+ id = STM32MP1_SHRES_RNG1;
+ break;
+ case RTC_BASE:
+ id = STM32MP1_SHRES_RTC;
+ break;
+ case SPI6_BASE:
+ id = STM32MP1_SHRES_SPI6;
+ break;
+ case USART1_BASE:
+ id = STM32MP1_SHRES_USART1;
+ break;
+
+ case GPIOA_BASE:
+ case GPIOB_BASE:
+ case GPIOC_BASE:
+ case GPIOD_BASE:
+ case GPIOE_BASE:
+ case GPIOF_BASE:
+ case GPIOG_BASE:
+ case GPIOH_BASE:
+ case GPIOI_BASE:
+ case GPIOJ_BASE:
+ case GPIOK_BASE:
+ case USART2_BASE:
+ case USART3_BASE:
+ case UART4_BASE:
+ case UART5_BASE:
+ case USART6_BASE:
+ case UART7_BASE:
+ case UART8_BASE:
+ case IWDG2_BASE:
+ /* Allow drivers to register some non-secure resources */
+ VERBOSE("IO for non-secure resource 0x%x\n",
+ (unsigned int)base);
+ if (state != SHRES_NON_SECURE) {
+ panic();
+ }
+
+ return;
+
+ default:
+ panic();
+ }
+
+ register_periph(id, state);
+}
+
+void stm32mp_register_secure_periph_iomem(uintptr_t base)
+{
+ register_periph_iomem(base, SHRES_SECURE);
+}
+
+void stm32mp_register_non_secure_periph_iomem(uintptr_t base)
+{
+ register_periph_iomem(base, SHRES_NON_SECURE);
+}
+
+void stm32mp_register_secure_gpio(unsigned int bank, unsigned int pin)
+{
+ switch (bank) {
+ case GPIO_BANK_Z:
+ register_periph(STM32MP1_SHRES_GPIOZ(pin), SHRES_SECURE);
+ break;
+ default:
+ ERROR("GPIO bank %u cannot be secured\n", bank);
+ panic();
+ }
+}
+
+void stm32mp_register_non_secure_gpio(unsigned int bank, unsigned int pin)
+{
+ switch (bank) {
+ case GPIO_BANK_Z:
+ register_periph(STM32MP1_SHRES_GPIOZ(pin), SHRES_NON_SECURE);
+ break;
+ default:
+ break;
+ }
+}
+
+static bool stm32mp_gpio_bank_is_non_secure(unsigned int bank)
+{
+ unsigned int non_secure = 0U;
+ unsigned int i;
+
+ lock_registering();
+
+ if (bank != GPIO_BANK_Z) {
+ return true;
+ }
+
+ for (i = 0U; i < get_gpioz_nbpin(); i++) {
+ if (periph_is_non_secure(STM32MP1_SHRES_GPIOZ(i))) {
+ non_secure++;
+ }
+ }
+
+ return non_secure == get_gpioz_nbpin();
+}
+
+static bool stm32mp_gpio_bank_is_secure(unsigned int bank)
+{
+ unsigned int secure = 0U;
+ unsigned int i;
+
+ lock_registering();
+
+ if (bank != GPIO_BANK_Z) {
+ return false;
+ }
+
+ for (i = 0U; i < get_gpioz_nbpin(); i++) {
+ if (periph_is_secure(STM32MP1_SHRES_GPIOZ(i))) {
+ secure++;
+ }
+ }
+
+ return secure == get_gpioz_nbpin();
+}
+
+bool stm32mp_nsec_can_access_clock(unsigned long clock_id)
+{
+ enum stm32mp_shres shres_id = STM32MP1_SHRES_COUNT;
+
+ switch (clock_id) {
+ case CK_CSI:
+ case CK_HSE:
+ case CK_HSE_DIV2:
+ case CK_HSI:
+ case CK_LSE:
+ case CK_LSI:
+ case PLL1_P:
+ case PLL1_Q:
+ case PLL1_R:
+ case PLL2_P:
+ case PLL2_Q:
+ case PLL2_R:
+ case PLL3_P:
+ case PLL3_Q:
+ case PLL3_R:
+ case RTCAPB:
+ return true;
+ case GPIOZ:
+ /* Allow clock access if at least one pin is non-secure */
+ return !stm32mp_gpio_bank_is_secure(GPIO_BANK_Z);
+ case CRYP1:
+ shres_id = STM32MP1_SHRES_CRYP1;
+ break;
+ case HASH1:
+ shres_id = STM32MP1_SHRES_HASH1;
+ break;
+ case I2C4_K:
+ shres_id = STM32MP1_SHRES_I2C4;
+ break;
+ case I2C6_K:
+ shres_id = STM32MP1_SHRES_I2C6;
+ break;
+ case IWDG1:
+ shres_id = STM32MP1_SHRES_IWDG1;
+ break;
+ case RNG1_K:
+ shres_id = STM32MP1_SHRES_RNG1;
+ break;
+ case RTC:
+ shres_id = STM32MP1_SHRES_RTC;
+ break;
+ case SPI6_K:
+ shres_id = STM32MP1_SHRES_SPI6;
+ break;
+ case USART1_K:
+ shres_id = STM32MP1_SHRES_USART1;
+ break;
+ default:
+ return false;
+ }
+
+ return periph_is_non_secure(shres_id);
+}
+
+bool stm32mp_nsec_can_access_reset(unsigned int reset_id)
+{
+ enum stm32mp_shres shres_id = STM32MP1_SHRES_COUNT;
+
+ switch (reset_id) {
+ case CRYP1_R:
+ shres_id = STM32MP1_SHRES_CRYP1;
+ break;
+ case GPIOZ_R:
+ /* GPIOZ reset mandates all pins are non-secure */
+ return stm32mp_gpio_bank_is_non_secure(GPIO_BANK_Z);
+ case HASH1_R:
+ shres_id = STM32MP1_SHRES_HASH1;
+ break;
+ case I2C4_R:
+ shres_id = STM32MP1_SHRES_I2C4;
+ break;
+ case I2C6_R:
+ shres_id = STM32MP1_SHRES_I2C6;
+ break;
+ case MCU_R:
+ shres_id = STM32MP1_SHRES_MCU;
+ break;
+ case MDMA_R:
+ shres_id = STM32MP1_SHRES_MDMA;
+ break;
+ case RNG1_R:
+ shres_id = STM32MP1_SHRES_RNG1;
+ break;
+ case SPI6_R:
+ shres_id = STM32MP1_SHRES_SPI6;
+ break;
+ case USART1_R:
+ shres_id = STM32MP1_SHRES_USART1;
+ break;
+ default:
+ return false;
+ }
+
+ return periph_is_non_secure(shres_id);
+}
+
+static bool mckprot_protects_periph(enum stm32mp_shres id)
+{
+ switch (id) {
+ case STM32MP1_SHRES_MCU:
+ case STM32MP1_SHRES_PLL3:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* ETZPC configuration at drivers initialization completion */
+static enum etzpc_decprot_attributes shres2decprot_attr(enum stm32mp_shres id)
+{
+ assert((id < STM32MP1_SHRES_GPIOZ(0)) ||
+ (id > STM32MP1_SHRES_GPIOZ(7)));
+
+ if (periph_is_non_secure(id)) {
+ return ETZPC_DECPROT_NS_RW;
+ }
+
+ return ETZPC_DECPROT_S_RW;
+}
+
+static void set_etzpc_secure_configuration(void)
+{
+ /* Some system peripherals shall be secure */
+ etzpc_configure_decprot(STM32MP1_ETZPC_STGENC_ID, ETZPC_DECPROT_S_RW);
+ etzpc_configure_decprot(STM32MP1_ETZPC_BKPSRAM_ID, ETZPC_DECPROT_S_RW);
+ etzpc_configure_decprot(STM32MP1_ETZPC_DDRCTRL_ID,
+ ETZPC_DECPROT_NS_R_S_W);
+ etzpc_configure_decprot(STM32MP1_ETZPC_DDRPHYC_ID,
+ ETZPC_DECPROT_NS_R_S_W);
+
+ /* Configure ETZPC with peripheral registering */
+ etzpc_configure_decprot(STM32MP1_ETZPC_CRYP1_ID,
+ shres2decprot_attr(STM32MP1_SHRES_CRYP1));
+ etzpc_configure_decprot(STM32MP1_ETZPC_HASH1_ID,
+ shres2decprot_attr(STM32MP1_SHRES_HASH1));
+ etzpc_configure_decprot(STM32MP1_ETZPC_I2C4_ID,
+ shres2decprot_attr(STM32MP1_SHRES_I2C4));
+ etzpc_configure_decprot(STM32MP1_ETZPC_I2C6_ID,
+ shres2decprot_attr(STM32MP1_SHRES_I2C6));
+ etzpc_configure_decprot(STM32MP1_ETZPC_IWDG1_ID,
+ shres2decprot_attr(STM32MP1_SHRES_IWDG1));
+ etzpc_configure_decprot(STM32MP1_ETZPC_RNG1_ID,
+ shres2decprot_attr(STM32MP1_SHRES_RNG1));
+ etzpc_configure_decprot(STM32MP1_ETZPC_USART1_ID,
+ shres2decprot_attr(STM32MP1_SHRES_USART1));
+ etzpc_configure_decprot(STM32MP1_ETZPC_SPI6_ID,
+ shres2decprot_attr(STM32MP1_SHRES_SPI6));
+}
+
+static void check_rcc_secure_configuration(void)
+{
+ uint32_t n;
+ uint32_t error = 0U;
+ bool mckprot = stm32mp1_rcc_is_mckprot();
+ bool secure = stm32mp1_rcc_is_secure();
+
+ for (n = 0U; n < ARRAY_SIZE(shres_state); n++) {
+ if (shres_state[n] != SHRES_SECURE) {
+ continue;
+ }
+
+ if (!secure || (mckprot_protects_periph(n) && (!mckprot))) {
+ ERROR("RCC %s MCKPROT %s and %s secure\n",
+ secure ? "secure" : "non-secure",
+ mckprot ? "set" : "not set",
+ shres2str_id(n));
+ error++;
+ }
+ }
+
+ if (error != 0U) {
+ panic();
+ }
+}
+
+static void set_gpio_secure_configuration(void)
+{
+ uint32_t pin;
+
+ for (pin = 0U; pin < get_gpioz_nbpin(); pin++) {
+ bool secure_state = periph_is_secure(STM32MP1_SHRES_GPIOZ(pin));
+
+ set_gpio_secure_cfg(GPIO_BANK_Z, pin, secure_state);
+ }
+}
+
+static void print_shared_resources_state(void)
+{
+ unsigned int id;
+
+ for (id = 0U; id < STM32MP1_SHRES_COUNT; id++) {
+ switch (shres_state[id]) {
+ case SHRES_SECURE:
+ INFO("stm32mp1 %s is secure\n", shres2str_id(id));
+ break;
+ case SHRES_NON_SECURE:
+ case SHRES_UNREGISTERED:
+ VERBOSE("stm32mp %s is non-secure\n", shres2str_id(id));
+ break;
+ default:
+ VERBOSE("stm32mp %s is invalid\n", shres2str_id(id));
+ panic();
+ }
+ }
+}
+
+void stm32mp_lock_periph_registering(void)
+{
+ registering_locked = true;
+
+ print_shared_resources_state();
+
+ check_rcc_secure_configuration();
+ set_etzpc_secure_configuration();
+ set_gpio_secure_configuration();
+}
diff --git a/plat/st/stm32mp1/stm32mp1_stack_protector.c b/plat/st/stm32mp1/stm32mp1_stack_protector.c
new file mode 100644
index 0000000..14e8e16
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_stack_protector.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <plat/common/platform.h>
+
+#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();
+}
+
diff --git a/plat/st/stm32mp1/stm32mp1_syscfg.c b/plat/st/stm32mp1/stm32mp1_syscfg.c
new file mode 100644
index 0000000..ff79428
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_syscfg.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stpmic1.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+#include <stm32mp_common.h>
+#include <stm32mp_dt.h>
+#include <stm32mp1_private.h>
+
+/*
+ * SYSCFG REGISTER OFFSET (base relative)
+ */
+#define SYSCFG_BOOTR 0x00U
+#define SYSCFG_BOOTCR 0x0CU
+#if STM32MP15
+#define SYSCFG_IOCTRLSETR 0x18U
+#define SYSCFG_ICNR 0x1CU
+#endif
+#define SYSCFG_CMPCR 0x20U
+#define SYSCFG_CMPENSETR 0x24U
+#define SYSCFG_CMPENCLRR 0x28U
+#if STM32MP13
+#define SYSCFG_CMPSD1CR 0x30U
+#define SYSCFG_CMPSD1ENSETR 0x34U
+#define SYSCFG_CMPSD1ENCLRR 0x38U
+#define SYSCFG_CMPSD2CR 0x40U
+#define SYSCFG_CMPSD2ENSETR 0x44U
+#define SYSCFG_CMPSD2ENCLRR 0x48U
+#define SYSCFG_HSLVEN0R 0x50U
+#endif
+#define SYSCFG_IDC 0x380U
+
+#define CMPCR_CMPENSETR_OFFSET 0x4U
+#define CMPCR_CMPENCLRR_OFFSET 0x8U
+
+/*
+ * SYSCFG_BOOTR Register
+ */
+#define SYSCFG_BOOTR_BOOT_MASK GENMASK(2, 0)
+#if STM32MP15
+#define SYSCFG_BOOTR_BOOTPD_MASK GENMASK(6, 4)
+#define SYSCFG_BOOTR_BOOTPD_SHIFT 4
+#endif
+
+/*
+ * SYSCFG_BOOTCR Register
+ */
+#define SYSCFG_BOOTCR_BMEN BIT(0)
+
+/*
+ * 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
+
+#define SYSCFG_CMPCR_READY_TIMEOUT_US 10000U
+
+/*
+ * SYSCFG_CMPENSETR Register
+ */
+#define SYSCFG_CMPENSETR_MPU_EN BIT(0)
+
+/*
+ * HSLV definitions
+ */
+#define HSLV_IDX_TPIU 0U
+#define HSLV_IDX_QSPI 1U
+#define HSLV_IDX_ETH1 2U
+#define HSLV_IDX_ETH2 3U
+#define HSLV_IDX_SDMMC1 4U
+#define HSLV_IDX_SDMMC2 5U
+#define HSLV_IDX_SPI1 6U
+#define HSLV_IDX_SPI2 7U
+#define HSLV_IDX_SPI3 8U
+#define HSLV_IDX_SPI4 9U
+#define HSLV_IDX_SPI5 10U
+#define HSLV_IDX_LTDC 11U
+#define HSLV_NB_IDX 12U
+
+#define HSLV_KEY 0x1018U
+
+/*
+ * SYSCFG_IDC Register
+ */
+#define SYSCFG_IDC_DEV_ID_MASK GENMASK(11, 0)
+#define SYSCFG_IDC_REV_ID_MASK GENMASK(31, 16)
+#define SYSCFG_IDC_REV_ID_SHIFT 16
+
+static void enable_io_comp_cell_finish(uintptr_t cmpcr_off)
+{
+ uint64_t start;
+
+ start = timeout_init_us(SYSCFG_CMPCR_READY_TIMEOUT_US);
+
+ while ((mmio_read_32(SYSCFG_BASE + cmpcr_off) & SYSCFG_CMPCR_READY) == 0U) {
+ if (timeout_elapsed(start)) {
+ /* Failure on IO compensation enable is not a issue: warn only. */
+ WARN("IO compensation cell not ready\n");
+ break;
+ }
+ }
+
+ mmio_clrbits_32(SYSCFG_BASE + cmpcr_off, SYSCFG_CMPCR_SW_CTRL);
+}
+
+static void disable_io_comp_cell(uintptr_t cmpcr_off)
+{
+ uint32_t value;
+
+ if (((mmio_read_32(SYSCFG_BASE + cmpcr_off) & SYSCFG_CMPCR_READY) == 0U) ||
+ ((mmio_read_32(SYSCFG_BASE + cmpcr_off + CMPCR_CMPENSETR_OFFSET) &
+ SYSCFG_CMPENSETR_MPU_EN) == 0U)) {
+ return;
+ }
+
+ value = mmio_read_32(SYSCFG_BASE + cmpcr_off) >> SYSCFG_CMPCR_ANSRC_SHIFT;
+
+ mmio_clrbits_32(SYSCFG_BASE + cmpcr_off, SYSCFG_CMPCR_RANSRC | SYSCFG_CMPCR_RAPSRC);
+
+ value <<= SYSCFG_CMPCR_RANSRC_SHIFT;
+ value |= mmio_read_32(SYSCFG_BASE + cmpcr_off);
+
+ mmio_write_32(SYSCFG_BASE + cmpcr_off, value | SYSCFG_CMPCR_SW_CTRL);
+
+ mmio_setbits_32(SYSCFG_BASE + cmpcr_off + CMPCR_CMPENCLRR_OFFSET, SYSCFG_CMPENSETR_MPU_EN);
+}
+
+#if STM32MP13
+static int get_regu_max_voltage(void *fdt, int sdmmc_node,
+ const char *regu_name, uint32_t *regu_val)
+{
+ int node;
+ const fdt32_t *cuint;
+
+ cuint = fdt_getprop(fdt, sdmmc_node, regu_name, NULL);
+ if (cuint == NULL) {
+ return -ENODEV;
+ }
+
+ node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
+ if (node < 0) {
+ return -ENODEV;
+ }
+
+ cuint = fdt_getprop(fdt, node, "regulator-max-microvolt", NULL);
+ if (cuint == NULL) {
+ return -ENODEV;
+ }
+
+ *regu_val = fdt32_to_cpu(*cuint);
+
+ return 0;
+}
+
+static bool sdmmc_is_low_voltage(uintptr_t sdmmc_base)
+{
+ int ret;
+ int node;
+ void *fdt = NULL;
+ uint32_t regu_max_val;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return false;
+ }
+
+ if (fdt == NULL) {
+ return false;
+ }
+
+ node = dt_match_instance_by_compatible(DT_SDMMC2_COMPAT, sdmmc_base);
+ if (node < 0) {
+ /* No SD or eMMC device on this instance, enable HSLV */
+ return true;
+ }
+
+ ret = get_regu_max_voltage(fdt, node, "vqmmc-supply", &regu_max_val);
+ if ((ret < 0) || (regu_max_val > 1800000U)) {
+ /*
+ * The vqmmc-supply property should always be present for eMMC.
+ * For SD-card, if it is not, then the card only supports 3.3V.
+ */
+ return false;
+ }
+
+ return true;
+}
+
+static void enable_hslv_by_index(uint32_t index)
+{
+ bool apply_hslv;
+
+ assert(index < HSLV_NB_IDX);
+
+ switch (index) {
+ case HSLV_IDX_SDMMC1:
+ apply_hslv = sdmmc_is_low_voltage(STM32MP_SDMMC1_BASE);
+ break;
+ case HSLV_IDX_SDMMC2:
+ apply_hslv = sdmmc_is_low_voltage(STM32MP_SDMMC2_BASE);
+ break;
+ default:
+ apply_hslv = true;
+ break;
+ }
+
+ if (apply_hslv) {
+ mmio_write_32(SYSCFG_BASE + SYSCFG_HSLVEN0R + index * sizeof(uint32_t), HSLV_KEY);
+ }
+}
+#endif
+
+static void enable_high_speed_mode_low_voltage(void)
+{
+#if STM32MP13
+ uint32_t idx;
+
+ for (idx = 0U; idx < HSLV_NB_IDX; idx++) {
+ enable_hslv_by_index(idx);
+ }
+#endif
+#if STM32MP15
+ 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);
+#endif
+}
+
+static void stm32mp1_syscfg_set_hslv(void)
+{
+ uint32_t otp_value;
+ uint32_t vdd_voltage;
+ bool product_below_2v5;
+
+ /*
+ * 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 (stm32_get_otp_value(HW2_OTP, &otp_value) != 0) {
+ panic();
+ }
+
+ product_below_2v5 = (otp_value & HW2_OTP_PRODUCT_BELOW_2V5) != 0U;
+
+ /* Get VDD supply */
+ vdd_voltage = dt_get_pwr_vdd_voltage();
+
+ /* Check if VDD is Low Voltage */
+ if (vdd_voltage == 0U) {
+ WARN("VDD unknown\n");
+ } else if (vdd_voltage < 2700000U) {
+ enable_high_speed_mode_low_voltage();
+
+ if (!product_below_2v5) {
+ INFO("Product_below_2v5=0: HSLVEN protected by HW\n");
+ }
+ } else {
+ if (product_below_2v5) {
+ ERROR("Product_below_2v5=1:\n");
+ ERROR("\tHSLVEN update is destructive,\n");
+ ERROR("\tno update as VDD > 2.7V\n");
+ panic();
+ }
+ }
+}
+
+void stm32mp1_syscfg_init(void)
+{
+#if STM32MP15
+ uint32_t bootr;
+
+ /*
+ * 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);
+#endif
+
+ stm32mp1_syscfg_set_hslv();
+
+ stm32mp1_syscfg_enable_io_compensation_start();
+}
+
+void stm32mp1_syscfg_enable_io_compensation_start(void)
+{
+ /*
+ * 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.
+ */
+ clk_enable(SYSCFG);
+
+ mmio_setbits_32(SYSCFG_BASE + CMPCR_CMPENSETR_OFFSET + SYSCFG_CMPCR,
+ SYSCFG_CMPENSETR_MPU_EN);
+#if STM32MP13
+ mmio_setbits_32(SYSCFG_BASE + CMPCR_CMPENSETR_OFFSET + SYSCFG_CMPSD1CR,
+ SYSCFG_CMPENSETR_MPU_EN);
+ mmio_setbits_32(SYSCFG_BASE + CMPCR_CMPENSETR_OFFSET + SYSCFG_CMPSD2CR,
+ SYSCFG_CMPENSETR_MPU_EN);
+
+#endif
+}
+
+void stm32mp1_syscfg_enable_io_compensation_finish(void)
+{
+ enable_io_comp_cell_finish(SYSCFG_CMPCR);
+#if STM32MP13
+ enable_io_comp_cell_finish(SYSCFG_CMPSD1CR);
+ enable_io_comp_cell_finish(SYSCFG_CMPSD2CR);
+#endif
+}
+
+void stm32mp1_syscfg_disable_io_compensation(void)
+{
+ clk_enable(SYSCFG);
+
+ /*
+ * 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.
+ */
+ disable_io_comp_cell(SYSCFG_CMPCR);
+#if STM32MP13
+ disable_io_comp_cell(SYSCFG_CMPSD1CR);
+ disable_io_comp_cell(SYSCFG_CMPSD2CR);
+#endif
+
+ clk_disable(SYSCFG);
+}
+
+/*
+ * @brief Get silicon revision from SYSCFG registers.
+ * @retval chip version (REV_ID).
+ */
+uint32_t stm32mp1_syscfg_get_chip_version(void)
+{
+ return (mmio_read_32(SYSCFG_BASE + SYSCFG_IDC) &
+ SYSCFG_IDC_REV_ID_MASK) >> SYSCFG_IDC_REV_ID_SHIFT;
+}
+
+/*
+ * @brief Get device ID from SYSCFG registers.
+ * @retval device ID (DEV_ID).
+ */
+uint32_t stm32mp1_syscfg_get_chip_dev_id(void)
+{
+ return mmio_read_32(SYSCFG_BASE + SYSCFG_IDC) & SYSCFG_IDC_DEV_ID_MASK;
+}
+
+#if STM32MP13
+void stm32mp1_syscfg_boot_mode_enable(void)
+{
+ mmio_setbits_32(SYSCFG_BASE + SYSCFG_BOOTCR, SYSCFG_BOOTCR_BMEN);
+}
+
+void stm32mp1_syscfg_boot_mode_disable(void)
+{
+ mmio_clrbits_32(SYSCFG_BASE + SYSCFG_BOOTCR, SYSCFG_BOOTCR_BMEN);
+}
+#endif
diff --git a/plat/st/stm32mp1/stm32mp1_tbb_cert.c b/plat/st/stm32mp1/stm32mp1_tbb_cert.c
new file mode 100644
index 0000000..0e77397
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_tbb_cert.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "tbbr/tbb_ext.h"
+#include "tbbr/tbb_key.h"
+
+#include "tbbr/stm32mp1_tbb_cert.h"
+
+/*
+ * Certificates used in the chain of trust
+ *
+ * The order of the certificates must follow the enumeration specified in
+ * stm32mp1_tbb_cert.h. All certificates are self-signed, so the issuer certificate
+ * field points to itself.
+ */
+static cert_t stm32mp1_tbb_certs[] = {
+ [0] = {
+ .id = STM32MP_CONFIG_CERT,
+ .opt = "stm32mp-cfg-cert",
+ .help_msg = "STM32MP Config Certificate (output file)",
+ .fn = NULL,
+ .cn = "STM32MP config FW Certificate",
+ .key = ROT_KEY,
+ .issuer = STM32MP_CONFIG_CERT,
+ .ext = {
+ TRUSTED_FW_NVCOUNTER_EXT,
+ HW_CONFIG_HASH_EXT,
+ FW_CONFIG_HASH_EXT
+ },
+ .num_ext = 3
+ },
+};
+
+PLAT_REGISTER_COT(stm32mp1_tbb_certs);
diff --git a/plat/st/stm32mp1/stm32mp1_topology.c b/plat/st/stm32mp1/stm32mp1_topology.c
new file mode 100644
index 0000000..59a0c17
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_topology.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+/* 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;
+}
diff --git a/plat/st/stm32mp1/stm32mp1_usb_dfu.c b/plat/st/stm32mp1/stm32mp1_usb_dfu.c
new file mode 100644
index 0000000..0fe2d24
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_usb_dfu.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <limits.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/st/bsec.h>
+#include <drivers/st/stm32mp1_usb.h>
+#include <drivers/usb_device.h>
+
+#include <platform_def.h>
+#include <stm32cubeprogrammer.h>
+#include <stm32mp_common.h>
+#include <usb_dfu.h>
+
+/* String size (1 byte) + type (1 byte) + 24 UTF16 characters: 2 bytes each */
+#define SIZ_STRING_SERIAL U(24)
+#define USB_SIZ_STRING_SERIAL (1U + 1U + (SIZ_STRING_SERIAL * 2U))
+#define USBD_MAX_STR_DESC_SIZ 0x100
+#define USBD_VID 0x0483
+#define USBD_PID 0xDF11
+#define USBD_LANGID_STRING 0x409
+#define USBD_MANUFACTURER_STRING "STMicroelectronics"
+#define USBD_CONFIGURATION_STRING "DFU Config"
+#define USBD_INTERFACE_STRING "DFU Interface"
+
+#if STM32MP13
+#define USB_DFU_ITF_NUM 2
+#endif
+#if STM32MP15
+#define USB_DFU_ITF_NUM 6
+#endif
+
+#define USB_DFU_CONFIG_DESC_SIZ USB_DFU_DESC_SIZ(USB_DFU_ITF_NUM)
+
+/* DFU devices */
+static struct usb_dfu_handle usb_dfu_handle;
+
+/* USB Standard Device Descriptor */
+static const uint8_t usb_stm32mp1_desc[USB_LEN_DEV_DESC] = {
+ USB_LEN_DEV_DESC, /* bLength */
+ USB_DESC_TYPE_DEVICE, /* bDescriptorType */
+ 0x00, /* bcdUSB */
+ 0x02, /* version */
+ 0x00, /* bDeviceClass */
+ 0x00, /* bDeviceSubClass */
+ 0x00, /* bDeviceProtocol */
+ USB_MAX_EP0_SIZE, /* bMaxPacketSize */
+ LOBYTE(USBD_VID), /* idVendor */
+ HIBYTE(USBD_VID), /* idVendor */
+ LOBYTE(USBD_PID), /* idVendor */
+ HIBYTE(USBD_PID), /* idVendor */
+ 0x00, /* bcdDevice rel. 2.00 */
+ 0x02,
+ USBD_IDX_MFC_STR, /* Index of manufacturer string */
+ USBD_IDX_PRODUCT_STR, /* Index of product string */
+ USBD_IDX_SERIAL_STR, /* Index of serial number string */
+ USBD_MAX_NUM_CONFIGURATION /* bNumConfigurations */
+}; /* USB_DeviceDescriptor */
+
+/* USB Standard String Descriptor */
+static const uint8_t usb_stm32mp1_lang_id_desc[USB_LEN_LANGID_STR_DESC] = {
+ USB_LEN_LANGID_STR_DESC,
+ USB_DESC_TYPE_STRING,
+ LOBYTE(USBD_LANGID_STRING),
+ HIBYTE(USBD_LANGID_STRING),
+};
+
+/* USB Standard Device Descriptor */
+static const uint8_t
+usbd_stm32mp1_qualifier_desc[USB_LEN_DEV_QUALIFIER_DESC] = {
+ USB_LEN_DEV_QUALIFIER_DESC,
+ USB_DESC_TYPE_DEVICE_QUALIFIER,
+ 0x00,
+ 0x02,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x40,
+ 0x01,
+ 0x00,
+};
+
+/* USB serial number: build dynamically */
+static uint8_t usb_stm32mp1_serial[USB_SIZ_STRING_SERIAL + 1];
+
+/* USB DFU device Configuration Descriptor */
+static const uint8_t usb_stm32mp1_config_desc[USB_DFU_CONFIG_DESC_SIZ] = {
+ 0x09, /* bLength: Configuration Descriptor size */
+ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
+ USB_DFU_CONFIG_DESC_SIZ, /* wTotalLength: Bytes returned */
+ 0x00,
+ 0x01, /* bNumInterfaces: 1 interface */
+ 0x01, /* bConfigurationValue: Configuration value */
+ 0x02, /* iConfiguration: Index of string descriptor for configuration */
+ 0xC0, /* bmAttributes: bus powered and Supprts Remote Wakeup */
+ 0x32, /* MaxPower 100 mA: this current is used for detecting Vbus */
+
+ /* Descriptor of DFU interface 0 Alternate setting 0..N */
+ USBD_DFU_IF_DESC(0),
+ USBD_DFU_IF_DESC(1),
+#if USB_DFU_ITF_NUM > 2
+ USBD_DFU_IF_DESC(2),
+#endif
+#if USB_DFU_ITF_NUM > 3
+ USBD_DFU_IF_DESC(3),
+#endif
+#if USB_DFU_ITF_NUM > 4
+ USBD_DFU_IF_DESC(4),
+#endif
+#if USB_DFU_ITF_NUM > 5
+ USBD_DFU_IF_DESC(5),
+#endif
+ /* DFU Functional Descriptor */
+ 0x09, /* blength = 9 Bytes */
+ DFU_DESCRIPTOR_TYPE, /* DFU Functional Descriptor */
+ DFU_BM_ATTRIBUTE, /* bmAttribute for DFU */
+ 0xFF, /* DetachTimeOut = 255 ms */
+ 0x00,
+ TRANSFER_SIZE_BYTES(USBD_DFU_XFER_SIZE), /* TransferSize = 1024 Byte */
+ ((USB_DFU_VERSION >> 0) & 0xFF), /* bcdDFUVersion */
+ ((USB_DFU_VERSION >> 8) & 0xFF)
+};
+
+/* The user strings: one by alternate as defined in USBD_DFU_IF_DESC */
+#if STM32MP13
+const char *const if_desc_string[USB_DFU_ITF_NUM] = {
+ "@SSBL /0x03/1*16Me",
+ "@virtual /0xF1/1*512Ba"
+};
+#endif
+#if STM32MP15
+const char *const if_desc_string[USB_DFU_ITF_NUM] = {
+ "@Partition0 /0x00/1*256Ke",
+ "@FSBL /0x01/1*1Me",
+ "@Partition2 /0x02/1*1Me",
+ "@Partition3 /0x03/1*16Me",
+ "@Partition4 /0x04/1*16Me",
+ "@virtual /0xF1/1*512Ba"
+};
+#endif
+
+/* Buffer to build the unicode string provided to USB device stack */
+static uint8_t usb_str_dec[USBD_MAX_STR_DESC_SIZ];
+
+/*
+ * Convert Ascii string into unicode one
+ * desc : descriptor buffer
+ * unicode : Formatted string buffer (unicode)
+ * len : descriptor length
+ */
+static void stm32mp1_get_string(const char *desc, uint8_t *unicode, uint16_t *len)
+{
+ uint8_t idx = 0U;
+
+ if (desc == NULL) {
+ return;
+ }
+
+ *len = strlen(desc) * 2U + 2U;
+ unicode[idx++] = *len;
+ unicode[idx++] = USB_DESC_TYPE_STRING;
+
+ while (*desc != '\0') {
+ unicode[idx++] = *desc++;
+ unicode[idx++] = 0x00U;
+ }
+}
+
+/*
+ * Create the serial number string descriptor
+ */
+static void update_serial_num_string(void)
+{
+ uint8_t i;
+ char serial_string[SIZ_STRING_SERIAL + 2U];
+ /* serial number is set to 0 */
+ uint32_t deviceserial[UID_WORD_NB] = {0U, 0U, 0U};
+ uint32_t otp;
+ uint32_t len;
+ uint16_t length;
+
+ if (stm32_get_otp_index(UID_OTP, &otp, &len) != 0) {
+ ERROR("BSEC: Get UID_OTP number Error\n");
+ return;
+ }
+
+ if ((len / __WORD_BIT) != UID_WORD_NB) {
+ ERROR("BSEC: Get UID_OTP length Error\n");
+ return;
+ }
+
+ for (i = 0; i < UID_WORD_NB; i++) {
+ if (bsec_shadow_read_otp(&deviceserial[i], i + otp) !=
+ BSEC_OK) {
+ ERROR("BSEC: UID%d Error\n", i);
+ return;
+ }
+ }
+ /* build serial number with OTP value as in ROM code */
+ snprintf(serial_string, sizeof(serial_string), "%08X%08X%08X",
+ deviceserial[0], deviceserial[1], deviceserial[2]);
+
+ length = USB_SIZ_STRING_SERIAL;
+ stm32mp1_get_string(serial_string, usb_stm32mp1_serial, &length);
+}
+
+/*
+ * Return Device Qualifier descriptor
+ * length : pointer data length
+ * return : pointer to descriptor buffer
+ */
+static uint8_t *stm32mp1_get_qualifier_desc(uint16_t *length)
+{
+ *length = sizeof(usbd_stm32mp1_qualifier_desc);
+
+ return (uint8_t *)usbd_stm32mp1_qualifier_desc;
+}
+
+/*
+ * Return configuration descriptor
+ * length : pointer data length
+ * return : pointer to descriptor buffer
+ */
+static uint8_t *stm32mp1_get_config_desc(uint16_t *length)
+{
+ *length = sizeof(usb_stm32mp1_config_desc);
+
+ return (uint8_t *)usb_stm32mp1_config_desc;
+}
+
+/*
+ * Returns the device descriptor.
+ * length: Pointer to data length variable
+ * return : Pointer to descriptor buffer
+ */
+static uint8_t *stm32mp1_device_desc(uint16_t *length)
+{
+ *length = sizeof(usb_stm32mp1_desc);
+
+ return (uint8_t *)usb_stm32mp1_desc;
+}
+
+/*
+ * Returns the LangID string descriptor.
+ * length: Pointer to data length variable
+ * return : Pointer to descriptor buffer
+ */
+static uint8_t *stm32mp1_lang_id_desc(uint16_t *length)
+{
+ *length = sizeof(usb_stm32mp1_lang_id_desc);
+
+ return (uint8_t *)usb_stm32mp1_lang_id_desc;
+}
+
+/*
+ * Returns the product string descriptor.
+ * length: Pointer to data length variable
+ * return : Pointer to descriptor buffer
+ */
+static uint8_t *stm32mp1_product_desc(uint16_t *length)
+{
+ char name[STM32_SOC_NAME_SIZE];
+ char product[128];
+ uint32_t chip_id;
+ uint32_t chip_version;
+
+ stm32mp_get_soc_name(name);
+ chip_id = stm32mp_get_chip_dev_id();
+ chip_version = stm32mp_get_chip_version();
+
+ snprintf(product, sizeof(product),
+ "DFU @Device ID /0x%03X, @Revision ID /0x%04X, @Name /%s,",
+ chip_id, chip_version, name);
+
+ stm32mp1_get_string(product, usb_str_dec, length);
+
+ return usb_str_dec;
+}
+
+/*
+ * Returns the manufacturer string descriptor.
+ * length: Pointer to data length variable
+ * return : Pointer to descriptor buffer
+ */
+static uint8_t *stm32mp1_manufacturer_desc(uint16_t *length)
+{
+ stm32mp1_get_string(USBD_MANUFACTURER_STRING, usb_str_dec, length);
+
+ return usb_str_dec;
+}
+
+/*
+ * Returns the serial number string descriptor.
+ * length: Pointer to data length variable
+ * return : Pointer to descriptor buffer
+ */
+static uint8_t *stm32mp1_serial_desc(uint16_t *length)
+{
+ *length = USB_SIZ_STRING_SERIAL;
+
+ return (uint8_t *)usb_stm32mp1_serial;
+}
+
+/*
+ * Returns the configuration string descriptor.
+ * length: Pointer to data length variable
+ * return : Pointer to descriptor buffer
+ */
+static uint8_t *stm32mp1_config_desc(uint16_t *length)
+{
+ stm32mp1_get_string(USBD_CONFIGURATION_STRING, usb_str_dec, length);
+
+ return usb_str_dec;
+}
+
+/*
+ * Returns the interface string descriptor.
+ * length : Pointer to data length variable
+ * return : Pointer to descriptor buffer
+ */
+static uint8_t *stm32mp1_interface_desc(uint16_t *length)
+{
+ stm32mp1_get_string(USBD_INTERFACE_STRING, usb_str_dec, length);
+
+ return usb_str_dec;
+}
+
+/*
+ * Manages the transfer of memory interfaces string descriptors.
+ * index: descriptor index
+ * length : pointer data length
+ * return : pointer to the descriptor table or NULL if the descriptor
+ * is not supported.
+ */
+static uint8_t *stm32mp1_get_usr_desc(uint8_t index, uint16_t *length)
+{
+ if (index >= ARRAY_SIZE(if_desc_string)) {
+ return NULL;
+ }
+
+ stm32mp1_get_string(if_desc_string[index], usb_str_dec, length);
+
+ return usb_str_dec;
+}
+
+static const struct usb_desc dfu_desc = {
+ .get_device_desc = stm32mp1_device_desc,
+ .get_lang_id_desc = stm32mp1_lang_id_desc,
+ .get_manufacturer_desc = stm32mp1_manufacturer_desc,
+ .get_product_desc = stm32mp1_product_desc,
+ .get_configuration_desc = stm32mp1_config_desc,
+ .get_serial_desc = stm32mp1_serial_desc,
+ .get_interface_desc = stm32mp1_interface_desc,
+ .get_usr_desc = stm32mp1_get_usr_desc,
+ .get_config_desc = stm32mp1_get_config_desc,
+ .get_device_qualifier_desc = stm32mp1_get_qualifier_desc,
+ /* only HS is supported, as ROM code */
+ .get_other_speed_config_desc = NULL,
+};
+
+static struct usb_handle usb_core_handle;
+static struct pcd_handle pcd_handle;
+
+struct usb_handle *usb_dfu_plat_init(void)
+{
+ /* Prepare USB Driver */
+ pcd_handle.in_ep[0].maxpacket = USB_MAX_EP0_SIZE;
+ pcd_handle.out_ep[0].maxpacket = USB_MAX_EP0_SIZE;
+ stm32mp1_usb_init_driver(&usb_core_handle, &pcd_handle,
+ (uint32_t *)USB_OTG_BASE);
+
+#if STM32MP15
+ /* STM32MP15 = keep the configuration from ROM code */
+ usb_core_handle.ep0_state = USBD_EP0_DATA_IN;
+ usb_core_handle.dev_state = USBD_STATE_CONFIGURED;
+#endif
+
+ /* Update the serial number string descriptor from the unique ID */
+ update_serial_num_string();
+
+ /* Prepare USB DFU stack */
+ usb_dfu_register(&usb_core_handle, &usb_dfu_handle);
+
+ /* Register DFU descriptor in USB stack */
+ register_platform(&usb_core_handle, &dfu_desc);
+
+ return &usb_core_handle;
+}
+
+/* Link between USB alternate and STM32CubeProgramer phase */
+uint8_t usb_dfu_get_phase(uint8_t alt)
+{
+ uint8_t ret;
+
+ switch (alt) {
+#if STM32MP13
+ case 0:
+ ret = PHASE_SSBL;
+ break;
+ case 1:
+ ret = PHASE_CMD;
+ break;
+#endif
+#if STM32MP15
+ case 3:
+ ret = PHASE_SSBL;
+ break;
+ case 5:
+ ret = PHASE_CMD;
+ break;
+#endif
+ default:
+ ret = PHASE_RESET;
+ break;
+ }
+
+ return ret;
+}
diff --git a/plat/ti/k3/board/generic/board.mk b/plat/ti/k3/board/generic/board.mk
new file mode 100644
index 0000000..ef74cd6
--- /dev/null
+++ b/plat/ti/k3/board/generic/board.mk
@@ -0,0 +1,24 @@
+#
+# 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))
+
+# Define sec_proxy usage as the full prioritized communication scheme
+K3_SEC_PROXY_LITE := 0
+$(eval $(call add_define,K3_SEC_PROXY_LITE))
+
+# System coherency is managed in hardware
+USE_COHERENT_MEM := 1
+
+PLAT_INCLUDES += \
+ -Iplat/ti/k3/board/generic/include \
diff --git a/plat/ti/k3/board/generic/include/board_def.h b/plat/ti/k3/board/generic/include/board_def.h
new file mode 100644
index 0000000..4ff687c
--- /dev/null
+++ b/plat/ti/k3/board/generic/include/board_def.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BOARD_DEF_H
+#define BOARD_DEF_H
+
+#include <lib/utils_def.h>
+
+/* The ports must be in order and contiguous */
+#define K3_CLUSTER0_CORE_COUNT U(2)
+#define K3_CLUSTER1_CORE_COUNT U(2)
+#define K3_CLUSTER2_CORE_COUNT U(2)
+#define K3_CLUSTER3_CORE_COUNT U(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.
+ *
+ * The link addresses are determined by SEC_SRAM_BASE + offset.
+ * When ENABLE_PIE is set, the TF images can be loaded anywhere, so
+ * SEC_SRAM_BASE is really arbitrary.
+ *
+ * When ENABLE_PIE is unset, SEC_SRAM_BASE should be chosen so that
+ * it matches to the physical address where BL31 is loaded, that is,
+ * SEC_SRAM_BASE should be the base address of the RAM region.
+ *
+ * Lets make things explicit by mapping SRAM_BASE to 0x0 since ENABLE_PIE is
+ * defined as default for our platform.
+ */
+#define SEC_SRAM_BASE UL(0x00000000) /* PIE remapped on fly */
+#define SEC_SRAM_SIZE UL(0x00020000) /* 128k */
+
+#define PLAT_MAX_OFF_STATE U(2)
+#define PLAT_MAX_RET_STATE U(1)
+
+#define PLAT_PROC_START_ID U(32)
+#define PLAT_PROC_DEVICE_START_ID U(202)
+#define PLAT_CLUSTER_DEVICE_START_ID U(198)
+
+#endif /* BOARD_DEF_H */
diff --git a/plat/ti/k3/board/j784s4/board.mk b/plat/ti/k3/board/j784s4/board.mk
new file mode 100644
index 0000000..92433ab
--- /dev/null
+++ b/plat/ti/k3/board/j784s4/board.mk
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2022, 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))
+
+# Define sec_proxy usage as the full prioritized communication scheme
+K3_SEC_PROXY_LITE := 0
+$(eval $(call add_define,K3_SEC_PROXY_LITE))
+
+# System coherency is managed in hardware
+USE_COHERENT_MEM := 1
+
+PLAT_INCLUDES += \
+ -Iplat/ti/k3/board/j784s4/include \
diff --git a/plat/ti/k3/board/j784s4/include/board_def.h b/plat/ti/k3/board/j784s4/include/board_def.h
new file mode 100644
index 0000000..c2debc7
--- /dev/null
+++ b/plat/ti/k3/board/j784s4/include/board_def.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BOARD_DEF_H
+#define BOARD_DEF_H
+
+#include <lib/utils_def.h>
+
+/* The ports must be in order and contiguous */
+#define K3_CLUSTER0_CORE_COUNT U(4)
+#define K3_CLUSTER1_CORE_COUNT U(4)
+#define K3_CLUSTER2_CORE_COUNT U(0)
+#define K3_CLUSTER3_CORE_COUNT U(0)
+/*
+ * This RAM will be used for the bootloader including code, bss, and stacks.
+ * It may need to be increased if BL31 grows in size.
+ *
+ * The link addresses are determined by SEC_SRAM_BASE + offset.
+ * When ENABLE_PIE is set, the TF images can be loaded anywhere, so
+ * SEC_SRAM_BASE is really arbitrary.
+ *
+ * When ENABLE_PIE is unset, SEC_SRAM_BASE should be chosen so that
+ * it matches to the physical address where BL31 is loaded, that is,
+ * SEC_SRAM_BASE should be the base address of the RAM region.
+ *
+ * Lets make things explicit by mapping SRAM_BASE to 0x0 since ENABLE_PIE is
+ * defined as default for our platform.
+ */
+#define SEC_SRAM_BASE UL(0x00000000) /* PIE remapped on fly */
+#define SEC_SRAM_SIZE UL(0x00020000) /* 128k */
+
+#define PLAT_MAX_OFF_STATE U(2)
+#define PLAT_MAX_RET_STATE U(1)
+
+#define PLAT_PROC_START_ID U(32)
+
+#define PLAT_PROC_DEVICE_START_ID U(202)
+#define PLAT_CLUSTER_DEVICE_START_ID U(198)
+
+#endif /* BOARD_DEF_H */
diff --git a/plat/ti/k3/board/lite/board.mk b/plat/ti/k3/board/lite/board.mk
new file mode 100644
index 0000000..76246be
--- /dev/null
+++ b/plat/ti/k3/board/lite/board.mk
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2020, 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))
+
+# Define sec_proxy usage as the lite version
+K3_SEC_PROXY_LITE := 1
+$(eval $(call add_define,K3_SEC_PROXY_LITE))
+
+# We dont have system level coherency capability
+USE_COHERENT_MEM := 0
+
+PLAT_INCLUDES += \
+ -Iplat/ti/k3/board/lite/include \
diff --git a/plat/ti/k3/board/lite/include/board_def.h b/plat/ti/k3/board/lite/include/board_def.h
new file mode 100644
index 0000000..fd4e5b1
--- /dev/null
+++ b/plat/ti/k3/board/lite/include/board_def.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BOARD_DEF_H
+#define BOARD_DEF_H
+
+#include <lib/utils_def.h>
+
+/* The ports must be in order and contiguous */
+#define K3_CLUSTER0_CORE_COUNT U(4)
+#define K3_CLUSTER1_CORE_COUNT U(0)
+#define K3_CLUSTER2_CORE_COUNT U(0)
+#define K3_CLUSTER3_CORE_COUNT U(0)
+
+/*
+ * This RAM will be used for the bootloader including code, bss, and stacks.
+ * It may need to be increased if BL31 grows in size.
+ * Current computation assumes data structures necessary for GIC and ARM for
+ * a single cluster of 4 processor.
+ *
+ * The link addresses are determined by SEC_SRAM_BASE + offset.
+ * When ENABLE_PIE is set, the TF images can be loaded anywhere, so
+ * SEC_SRAM_BASE is really arbitrary.
+ *
+ * When ENABLE_PIE is unset, SEC_SRAM_BASE should be chosen so that
+ * it matches to the physical address where BL31 is loaded, that is,
+ * SEC_SRAM_BASE should be the base address of the RAM region.
+ *
+ * Lets make things explicit by mapping SRAM_BASE to 0x0 since ENABLE_PIE is
+ * defined as default for our platform.
+ */
+#define SEC_SRAM_BASE UL(0x00000000) /* PIE remapped on fly */
+#define SEC_SRAM_SIZE UL(0x00020000) /* 128k */
+
+#define PLAT_MAX_OFF_STATE U(2)
+#define PLAT_MAX_RET_STATE U(1)
+
+#define PLAT_PROC_START_ID U(32)
+#define PLAT_PROC_DEVICE_START_ID U(135)
+#define PLAT_CLUSTER_DEVICE_START_ID U(134)
+
+#endif /* BOARD_DEF_H */
diff --git a/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c b/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c
new file mode 100644
index 0000000..a0bfdee
--- /dev/null
+++ b/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c
@@ -0,0 +1,341 @@
+/*
+ * 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 <errno.h>
+#include <stdlib.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <lib/utils_def.h>
+
+#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 = {
+#if !K3_SEC_PROXY_LITE
+ SP_THREAD(SP_NOTIFY),
+ SP_THREAD(SP_RESPONSE),
+ SP_THREAD(SP_HIGH_PRIORITY),
+ SP_THREAD(SP_LOW_PRIORITY),
+ SP_THREAD(SP_NOTIFY_RESP),
+#else
+ SP_THREAD(SP_RESPONSE),
+ SP_THREAD(SP_HIGH_PRIORITY),
+#endif /* K3_SEC_PROXY_LITE */
+ },
+};
+
+/**
+ * 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
+ * In addition, we also need to make sure all intermediate data
+ * registers(if any required), are reset to 0 for TISCI backward
+ * compatibility to be maintained.
+ */
+ while (data_reg <= spm.desc.data_end_offset) {
+ mmio_write_32(spt->data + data_reg, 0);
+ data_reg += sizeof(uint32_t);
+ }
+
+ 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;
+}
diff --git a/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h b/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h
new file mode 100644
index 0000000..f4b0b4b
--- /dev/null
+++ b/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h
@@ -0,0 +1,82 @@
+/*
+ * 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 <stdint.h>
+
+/**
+ * enum k3_sec_proxy_chan_id - Secure Proxy thread IDs
+ *
+ * These the available IDs used in k3_sec_proxy_{send,recv}()
+ * There are two schemes we use:
+ * * if K3_SEC_PROXY_LITE = 1, we just have two threads to talk
+ * * if K3_SEC_PROXY_LITE = 0, we have the full fledged
+ * communication scheme available.
+ */
+enum k3_sec_proxy_chan_id {
+#if !K3_SEC_PROXY_LITE
+ SP_NOTIFY = 0,
+ SP_RESPONSE,
+ SP_HIGH_PRIORITY,
+ SP_LOW_PRIORITY,
+ SP_NOTIFY_RESP,
+#else
+ SP_RESPONSE = 8,
+ /*
+ * Note: TISCI documentation indicates "low priority", but in reality
+ * with a single thread, there is no low or high priority.. This usage
+ * is more appropriate for TF-A since we can reduce the churn as a
+ * result.
+ */
+ SP_HIGH_PRIORITY,
+#endif /* K3_SEC_PROXY_LITE */
+};
+
+/**
+ * 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 */
diff --git a/plat/ti/k3/common/drivers/ti_sci/ti_sci.c b/plat/ti/k3/common/drivers/ti_sci/ti_sci.c
new file mode 100644
index 0000000..2cbfa3d
--- /dev/null
+++ b/plat/ti/k3/common/drivers/ti_sci/ti_sci.c
@@ -0,0 +1,1739 @@
+/*
+ * Texas Instruments System Control Interface Driver
+ * Based on Linux and U-Boot implementation
+ *
+ * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <sec_proxy.h>
+
+#include "ti_sci_protocol.h"
+#include "ti_sci.h"
+
+#if USE_COHERENT_MEM
+__section("tzfw_coherent_mem")
+#endif
+static uint8_t message_sequence;
+
+/**
+ * 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 > TI_SCI_MAX_MESSAGE_SIZE ||
+ tx_message_size > TI_SCI_MAX_MESSAGE_SIZE ||
+ rx_message_size < sizeof(*hdr) ||
+ tx_message_size < sizeof(*hdr))
+ return -ERANGE;
+
+ hdr = (struct ti_sci_msg_hdr *)tx_buf;
+ hdr->seq = ++message_sequence;
+ hdr->type = msg_type;
+ hdr->host = TI_SCI_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 == message_sequence)
+ 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 > TI_SCI_MAX_MESSAGE_SIZE) {
+ ERROR("Unable to handle %lu xfer (max %d)\n",
+ msg->len, TI_SCI_MAX_MESSAGE_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) > TI_SCI_MAX_MESSAGE_SIZE)
+ return -ERANGE;
+
+ hdr = (struct ti_sci_msg_hdr *)&req;
+ hdr->seq = ++message_sequence;
+ hdr->type = TI_SCI_MSG_SET_DEVICE_STATE;
+ hdr->host = TI_SCI_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;
+ }
+ req.domain = TI_SCI_DOMAIN_FULL_SOC_RESET;
+
+ 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) > TI_SCI_MAX_MESSAGE_SIZE)
+ return -ERANGE;
+
+ hdr = (struct ti_sci_msg_hdr *)&req;
+ hdr->seq = ++message_sequence;
+ hdr->type = TISCI_MSG_SET_PROC_BOOT_CTRL;
+ hdr->host = TI_SCI_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) > TI_SCI_MAX_MESSAGE_SIZE)
+ return -ERANGE;
+
+ hdr = (struct ti_sci_msg_hdr *)&req;
+ hdr->seq = ++message_sequence;
+ hdr->type = TISCI_MSG_WAIT_PROC_BOOT_STATUS;
+ hdr->host = TI_SCI_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_enter_sleep - Command to initiate system transition into suspend.
+ *
+ * @proc_id: Processor ID.
+ * @mode: Low power mode to enter.
+ * @core_resume_addr: Address that core should be
+ * resumed from after low power transition.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_enter_sleep(uint8_t proc_id,
+ uint8_t mode,
+ uint64_t core_resume_addr)
+{
+ struct ti_sci_msg_req_enter_sleep 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) > TI_SCI_MAX_MESSAGE_SIZE) {
+ return -ERANGE;
+ }
+
+ hdr = (struct ti_sci_msg_hdr *)&req;
+ hdr->seq = ++message_sequence;
+ hdr->type = TI_SCI_MSG_ENTER_SLEEP;
+ hdr->host = TI_SCI_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.mode = mode;
+ req.core_resume_lo = core_resume_addr & TISCI_ADDR_LOW_MASK;
+ req.core_resume_hi = (core_resume_addr & TISCI_ADDR_HIGH_MASK) >>
+ TISCI_ADDR_HIGH_SHIFT;
+
+ 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 != 0) {
+ 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;
+}
diff --git a/plat/ti/k3/common/drivers/ti_sci/ti_sci.h b/plat/ti/k3/common/drivers/ti_sci/ti_sci.h
new file mode 100644
index 0000000..06944a7
--- /dev/null
+++ b/plat/ti/k3/common/drivers/ti_sci/ti_sci.h
@@ -0,0 +1,232 @@
+/*
+ * Texas Instruments System Control Interface API
+ * Based on Linux and U-Boot implementation
+ *
+ * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TI_SCI_H
+#define TI_SCI_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/**
+ * 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);
+
+/**
+ * System Low Power Operations
+ *
+ * - ti_sci_enter_sleep - Command to initiate system transition into suspend.
+ * @proc_id: Processor ID.
+ * @mode: Low power mode to enter.
+ * @core_resume_addr: Address that core should be resumed from
+ * after low power transition.
+ *
+ * NOTE: for all these functions, the following are generic in nature:
+ * Returns 0 for successful request, else returns corresponding error message.
+ */
+int ti_sci_enter_sleep(uint8_t proc_id,
+ uint8_t mode,
+ uint64_t core_resume_addr);
+
+/**
+ * ti_sci_init() - Basic initialization
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+int ti_sci_init(void);
+
+#endif /* TI_SCI_H */
diff --git a/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h b/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h
new file mode 100644
index 0000000..d220612
--- /dev/null
+++ b/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h
@@ -0,0 +1,734 @@
+/*
+ * 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-2022 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TI_SCI_PROTOCOL_H
+#define TI_SCI_PROTOCOL_H
+
+#include <stdint.h>
+
+/* 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
+
+/* Low Power Mode Requests */
+#define TI_SCI_MSG_ENTER_SLEEP 0x0301
+
+/* 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
+ * @domain: Domain to be reset, 0 for full SoC reboot
+ *
+ * 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;
+#define TI_SCI_DOMAIN_FULL_SOC_RESET 0x0
+ uint8_t domain;
+} __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;
+
+/* ARMV8 Control Flags */
+#define PROC_BOOT_CTRL_FLAG_ARMV8_ACINACTM 0x00000001
+#define PROC_BOOT_CTRL_FLAG_ARMV8_AINACTS 0x00000002
+#define PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ 0x00000100
+
+/* 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
+#define PROC_BOOT_STATUS_FLAG_ARMV8_L2F_DONE 0x00000010
+#define PROC_BOOT_STATUS_FLAG_ARMV8_STANDBYWFIL2 0x00000020
+
+/* 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;
+
+/**
+ * struct ti_sci_msg_req_enter_sleep - Request for TI_SCI_MSG_ENTER_SLEEP.
+ *
+ * @hdr Generic Header
+ * @mode Low power mode to enter.
+ * @proc_id Processor id to be restored.
+ * @core_resume_lo Low 32-bits of physical pointer to address for core
+ * to begin execution upon resume.
+ * @core_resume_hi High 32-bits of physical pointer to address for core
+ * to begin execution upon resume.
+ *
+ * This message is to be sent after TI_SCI_MSG_PREPARE_SLEEP is sent from OS
+ * and is what actually triggers entry into the specified low power mode.
+ */
+struct ti_sci_msg_req_enter_sleep {
+ struct ti_sci_msg_hdr hdr;
+ uint8_t mode;
+ uint8_t processor_id;
+ uint32_t core_resume_lo;
+ uint32_t core_resume_hi;
+} __packed;
+
+#endif /* TI_SCI_PROTOCOL_H */
diff --git a/plat/ti/k3/common/k3_bl31_setup.c b/plat/ti/k3/common/k3_bl31_setup.c
new file mode 100644
index 0000000..457c95d
--- /dev/null
+++ b/plat/ti/k3/common/k3_bl31_setup.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <k3_console.h>
+#include <k3_gicv3.h>
+#include <ti_sci.h>
+
+/* 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(K3_GTC_BASE, K3_GTC_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_SIZE, 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)
+{
+ uint32_t gtc_freq;
+ uint32_t gtc_ctrl;
+
+ /* Lets try and provide basic diagnostics - cost is low */
+ gtc_ctrl = mmio_read_32(K3_GTC_BASE + K3_GTC_CNTCR_OFFSET);
+ /* Did the bootloader fail to enable timer and OS guys are confused? */
+ if ((gtc_ctrl & K3_GTC_CNTCR_EN_MASK) == 0U) {
+ ERROR("GTC is disabled! Timekeeping broken. Fix Bootloader\n");
+ }
+ /*
+ * If debug will not pause time, we will have issues like
+ * drivers timing out while debugging, in cases of OS like Linux,
+ * RCU stall errors, which can be hard to differentiate vs real issues.
+ */
+ if ((gtc_ctrl & K3_GTC_CNTCR_HDBG_MASK) == 0U) {
+ WARN("GTC: Debug access doesn't stop time. Fix Bootloader\n");
+ }
+
+ gtc_freq = mmio_read_32(K3_GTC_BASE + K3_GTC_CNTFID0_OFFSET);
+ /* Many older bootloaders may have missed programming FID0 register */
+ if (gtc_freq != 0U) {
+ return gtc_freq;
+ }
+
+ /*
+ * We could have just warned about this, but this can have serious
+ * hard to debug side effects if we are NOT sure what the actual
+ * frequency is. Lets make sure people don't miss this.
+ */
+ ERROR("GTC_CNTFID0 is 0! Assuming %d Hz. Fix Bootloader\n",
+ SYS_COUNTER_FREQ_IN_TICKS);
+
+ 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;
+}
diff --git a/plat/ti/k3/common/k3_console.c b/plat/ti/k3/common/k3_console.c
new file mode 100644
index 0000000..8c44c17
--- /dev/null
+++ b/plat/ti/k3/common/k3_console.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <drivers/console.h>
+#include <drivers/ti/uart/uart_16550.h>
+
+#include <k3_console.h>
+
+void bl31_console_setup(void)
+{
+ static console_t console;
+
+ /* Initialize the console to provide early debug support */
+ console_16550_register(K3_USART_BASE, K3_USART_CLK_SPEED,
+ K3_USART_BAUD, &console);
+}
diff --git a/plat/ti/k3/common/k3_gicv3.c b/plat/ti/k3/common/k3_gicv3.c
new file mode 100644
index 0000000..0199822
--- /dev/null
+++ b/plat/ti/k3/common/k3_gicv3.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/utils.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <k3_gicv3.h>
+
+/* The GICv3 driver only needs to be initialized in EL3 */
+uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+#if K3_PM_SYSTEM_SUSPEND
+static gicv3_redist_ctx_t rdist_ctx[PLATFORM_CORE_COUNT];
+static gicv3_dist_ctx_t dist_ctx;
+#endif
+
+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());
+}
+
+#if K3_PM_SYSTEM_SUSPEND
+void k3_gic_save_context(void)
+{
+ for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++) {
+ gicv3_rdistif_save(i, &rdist_ctx[i]);
+ }
+ gicv3_distif_save(&dist_ctx);
+}
+
+void k3_gic_restore_context(void)
+{
+ gicv3_distif_init_restore(&dist_ctx);
+ for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++) {
+ gicv3_rdistif_init_restore(i, &rdist_ctx[i]);
+ }
+}
+#endif
diff --git a/plat/ti/k3/common/k3_helpers.S b/plat/ti/k3/common/k3_helpers.S
new file mode 100644
index 0000000..f4f7d18
--- /dev/null
+++ b/plat/ti/k3/common/k3_helpers.S
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cortex_a72.h>
+#include <cpu_macros.S>
+#include <platform_def.h>
+
+#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
+
+ /* ---------------------------------------------
+ * void plat_crash_console_flush()
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * Out : void.
+ * 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
diff --git a/plat/ti/k3/common/k3_psci.c b/plat/ti/k3/common/k3_psci.c
new file mode 100644
index 0000000..6febbc6
--- /dev/null
+++ b/plat/ti/k3/common/k3_psci.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include <ti_sci_protocol.h>
+#include <k3_gicv3.h>
+#include <ti_sci.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])
+
+uintptr_t k3_sec_entrypoint;
+
+static void k3_cpu_standby(plat_local_state_t cpu_state)
+{
+ u_register_t 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, proc_id, device_id, ret;
+
+ core = plat_core_pos_by_mpidr(mpidr);
+ if (core < 0) {
+ ERROR("Could not get target core id: %d\n", core);
+ return PSCI_E_INTERN_FAIL;
+ }
+
+ proc_id = PLAT_PROC_START_ID + core;
+ device_id = PLAT_PROC_DEVICE_START_ID + core;
+
+ ret = ti_sci_proc_request(proc_id);
+ if (ret) {
+ ERROR("Request for processor failed: %d\n", ret);
+ return PSCI_E_INTERN_FAIL;
+ }
+
+ ret = ti_sci_proc_set_boot_cfg(proc_id, k3_sec_entrypoint, 0, 0);
+ if (ret) {
+ ERROR("Request to set core boot address failed: %d\n", ret);
+ return PSCI_E_INTERN_FAIL;
+ }
+
+ /* sanity check these are off before starting a core */
+ ret = ti_sci_proc_set_boot_ctrl(proc_id,
+ 0, PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ |
+ PROC_BOOT_CTRL_FLAG_ARMV8_AINACTS |
+ PROC_BOOT_CTRL_FLAG_ARMV8_ACINACTM);
+ if (ret) {
+ ERROR("Request to clear boot configuration failed: %d\n", ret);
+ return PSCI_E_INTERN_FAIL;
+ }
+
+ ret = ti_sci_device_get(device_id);
+ 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, cluster, proc_id, device_id, cluster_id, ret;
+
+ /* At very least the local core should be powering down */
+ assert(CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE);
+
+ /* Prevent interrupts from spuriously waking up this cpu */
+ k3_gic_cpuif_disable();
+
+ core = plat_my_core_pos();
+ cluster = MPIDR_AFFLVL1_VAL(read_mpidr_el1());
+ proc_id = PLAT_PROC_START_ID + core;
+ device_id = PLAT_PROC_DEVICE_START_ID + core;
+ cluster_id = PLAT_CLUSTER_DEVICE_START_ID + (cluster * 2);
+
+ /*
+ * If we are the last core in the cluster then we take a reference to
+ * the cluster device so that it does not get shutdown before we
+ * execute the entire cluster L2 cleaning sequence below.
+ */
+ if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+ ret = ti_sci_device_get(cluster_id);
+ if (ret) {
+ ERROR("Request to get cluster failed: %d\n", ret);
+ return;
+ }
+ }
+
+ /* Start by sending wait for WFI command */
+ ret = ti_sci_proc_wait_boot_status_no_wait(proc_id,
+ /*
+ * 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_id);
+ if (ret) {
+ ERROR("Sending core shutdown message failed (%d)\n", ret);
+ return;
+ }
+
+ /* If our cluster is not going down we stop here */
+ if (CLUSTER_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+ return;
+
+ /* set AINACTS */
+ ret = ti_sci_proc_set_boot_ctrl_no_wait(proc_id,
+ PROC_BOOT_CTRL_FLAG_ARMV8_AINACTS, 0);
+ if (ret) {
+ ERROR("Sending set control message failed (%d)\n", ret);
+ return;
+ }
+
+ /* set L2FLUSHREQ */
+ ret = ti_sci_proc_set_boot_ctrl_no_wait(proc_id,
+ PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ, 0);
+ if (ret) {
+ ERROR("Sending set control message failed (%d)\n", ret);
+ return;
+ }
+
+ /* wait for L2FLUSHDONE*/
+ ret = ti_sci_proc_wait_boot_status_no_wait(proc_id,
+ UINT8_MAX, 2, UINT8_MAX, UINT8_MAX,
+ PROC_BOOT_STATUS_FLAG_ARMV8_L2F_DONE, 0, 0, 0);
+ if (ret) {
+ ERROR("Sending wait message failed (%d)\n", ret);
+ return;
+ }
+
+ /* clear L2FLUSHREQ */
+ ret = ti_sci_proc_set_boot_ctrl_no_wait(proc_id,
+ 0, PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ);
+ if (ret) {
+ ERROR("Sending set control message failed (%d)\n", ret);
+ return;
+ }
+
+ /* set ACINACTM */
+ ret = ti_sci_proc_set_boot_ctrl_no_wait(proc_id,
+ PROC_BOOT_CTRL_FLAG_ARMV8_ACINACTM, 0);
+ if (ret) {
+ ERROR("Sending set control message failed (%d)\n", ret);
+ return;
+ }
+
+ /* wait for STANDBYWFIL2 */
+ ret = ti_sci_proc_wait_boot_status_no_wait(proc_id,
+ UINT8_MAX, 2, UINT8_MAX, UINT8_MAX,
+ PROC_BOOT_STATUS_FLAG_ARMV8_STANDBYWFIL2, 0, 0, 0);
+ if (ret) {
+ ERROR("Sending wait message failed (%d)\n", ret);
+ return;
+ }
+
+ /* Now queue up the cluster shutdown request */
+ ret = ti_sci_device_put_no_wait(cluster_id);
+ if (ret) {
+ ERROR("Sending cluster 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_off(void)
+{
+ ERROR("System Off: operation not handled.\n");
+ while (true)
+ wfi();
+}
+
+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;
+}
+
+#if K3_PM_SYSTEM_SUSPEND
+static void k3_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+ unsigned int core, proc_id;
+
+ core = plat_my_core_pos();
+ proc_id = PLAT_PROC_START_ID + core;
+
+ /* Prevent interrupts from spuriously waking up this cpu */
+ k3_gic_cpuif_disable();
+ k3_gic_save_context();
+
+ k3_pwr_domain_off(target_state);
+
+ ti_sci_enter_sleep(proc_id, 0, k3_sec_entrypoint);
+}
+
+static void k3_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+ k3_gic_restore_context();
+ k3_gic_cpuif_enable();
+}
+
+static void k3_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;
+ }
+}
+#endif
+
+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,
+#if K3_PM_SYSTEM_SUSPEND
+ .pwr_domain_suspend = k3_pwr_domain_suspend,
+ .pwr_domain_suspend_finish = k3_pwr_domain_suspend_finish,
+ .get_sys_suspend_power_state = k3_get_sys_suspend_power_state,
+#endif
+ .system_off = k3_system_off,
+ .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;
+}
diff --git a/plat/ti/k3/common/k3_topology.c b/plat/ti/k3/common/k3_topology.c
new file mode 100644
index 0000000..139f1fd
--- /dev/null
+++ b/plat/ti/k3/common/k3_topology.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <lib/psci/psci.h>
+
+/* 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;
+}
diff --git a/plat/ti/k3/common/plat_common.mk b/plat/ti/k3/common/plat_common.mk
new file mode 100644
index 0000000..026d6a3
--- /dev/null
+++ b/plat/ti/k3/common/plat_common.mk
@@ -0,0 +1,95 @@
+#
+# Copyright (c) 2017-2022, 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
+
+# ARM coherency is managed in hardware
+WARMBOOT_ENABLE_DCACHE_EARLY := 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
+ERRATA_A53_1530924 := 1
+
+# A72 Erratum for SoC
+ERRATA_A72_859971 := 1
+ERRATA_A72_1319367 := 1
+
+CRASH_REPORTING := 1
+HANDLE_EA_EL3_FIRST_NS := 1
+
+# Split out RO data into a non-executable section
+SEPARATE_CODE_AND_RODATA := 1
+
+# Generate a Position Independent Executable
+ENABLE_PIE := 1
+
+TI_16550_MDR_QUIRK := 1
+$(eval $(call add_define,TI_16550_MDR_QUIRK))
+
+K3_USART := 0
+$(eval $(call add_define,K3_USART))
+
+# Allow customizing the UART baud rate
+K3_USART_BAUD := 115200
+$(eval $(call add_define,K3_USART_BAUD))
+
+# Enable system suspend modes
+K3_PM_SYSTEM_SUSPEND := 0
+$(eval $(call add_define,K3_PM_SYSTEM_SUSPEND))
+
+# 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 \
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+K3_GIC_SOURCES += \
+ ${GICV3_SOURCES} \
+ 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} \
diff --git a/plat/ti/k3/include/k3_console.h b/plat/ti/k3/include/k3_console.h
new file mode 100644
index 0000000..6376ab3
--- /dev/null
+++ b/plat/ti/k3/include/k3_console.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/plat/ti/k3/include/k3_gicv3.h b/plat/ti/k3/include/k3_gicv3.h
new file mode 100644
index 0000000..2c68a75
--- /dev/null
+++ b/plat/ti/k3/include/k3_gicv3.h
@@ -0,0 +1,20 @@
+/*
+ * 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 <stdint.h>
+
+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);
+void k3_gic_save_context(void);
+void k3_gic_restore_context(void);
+
+#endif /* K3_GICV3_H */
diff --git a/plat/ti/k3/include/plat_macros.S b/plat/ti/k3/include/plat_macros.S
new file mode 100644
index 0000000..38056b5
--- /dev/null
+++ b/plat/ti/k3/include/plat_macros.S
@@ -0,0 +1,21 @@
+/*
+ * 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 */
diff --git a/plat/ti/k3/include/platform_def.h b/plat/ti/k3/include/platform_def.h
new file mode 100644
index 0000000..81a383a
--- /dev/null
+++ b/plat/ti/k3/include/platform_def.h
@@ -0,0 +1,191 @@
+/*
+ * 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 <arch.h>
+#include <plat/common/common_def.h>
+
+#include <board_def.h>
+
+/*******************************************************************************
+ * 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.
+ */
+#if USE_COHERENT_MEM
+#define MAX_XLAT_TABLES 10
+#else
+#define MAX_XLAT_TABLES 9
+#endif
+
+/*
+ * 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 + 0x10000 * K3_USART)
+#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_GTC_BASE 0x00A90000
+/* We just need 20 byte offset, but simpler to just remap the 64K page in */
+#define K3_GTC_SIZE 0x10000
+#define K3_GTC_CNTCR_OFFSET 0x00
+#define K3_GTC_CNTCR_EN_MASK 0x01
+#define K3_GTC_CNTCR_HDBG_MASK 0x02
+#define K3_GTC_CNTFID0_OFFSET 0x20
+
+#define K3_GIC_BASE 0x01800000
+#define K3_GIC_SIZE 0x200000
+
+#if !K3_SEC_PROXY_LITE
+#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
+#else
+#define SEC_PROXY_DATA_BASE 0x4D000000
+#define SEC_PROXY_DATA_SIZE 0x80000
+#define SEC_PROXY_SCFG_BASE 0x4A400000
+#define SEC_PROXY_SCFG_SIZE 0x80000
+#define SEC_PROXY_RT_BASE 0x4A600000
+#define SEC_PROXY_RT_SIZE 0x80000
+#endif /* K3_SEC_PROXY_LITE */
+
+#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 */
diff --git a/plat/ti/k3/platform.mk b/plat/ti/k3/platform.mk
new file mode 100644
index 0000000..2de21aa
--- /dev/null
+++ b/plat/ti/k3/platform.mk
@@ -0,0 +1,14 @@
+#
+# 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 := $(abspath ${BUILD_BASE})/${PLAT}/${TARGET_BOARD}/${BUILD_TYPE}
diff --git a/plat/xilinx/common/include/ipi.h b/plat/xilinx/common/include/ipi.h
new file mode 100644
index 0000000..1d62f3e
--- /dev/null
+++ b/plat/xilinx/common/include/ipi.h
@@ -0,0 +1,77 @@
+/*
+ * 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 <stdint.h>
+
+/*********************************************************************
+ * IPI mailbox status macros
+ ********************************************************************/
+#define IPI_MB_STATUS_IDLE (0U)
+#define IPI_MB_STATUS_SEND_PENDING (1U)
+#define IPI_MB_STATUS_RECV_PENDING (2U)
+
+/*********************************************************************
+ * IPI mailbox call is secure or not macros
+ ********************************************************************/
+#define IPI_MB_CALL_NOTSECURE (0U)
+#define IPI_MB_CALL_SECURE (1U)
+
+/*********************************************************************
+ * 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_config_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 */
diff --git a/plat/xilinx/common/include/plat_startup.h b/plat/xilinx/common/include/plat_startup.h
new file mode 100644
index 0000000..1733930
--- /dev/null
+++ b/plat/xilinx/common/include/plat_startup.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_STARTUP_H
+#define PLAT_STARTUP_H
+
+#include <common/bl_common.h>
+
+/* For FSBL handover */
+enum fsbl_handoff {
+ FSBL_HANDOFF_SUCCESS = 0,
+ FSBL_HANDOFF_NO_STRUCT,
+ FSBL_HANDOFF_INVAL_STRUCT,
+ FSBL_HANDOFF_TOO_MANY_PARTS
+};
+
+#define FSBL_MAX_PARTITIONS 8U
+
+/* 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];
+};
+
+#define ATF_HANDOFF_PARAMS_MAX_SIZE sizeof(struct xfsbl_atf_handoff_params)
+
+enum fsbl_handoff fsbl_atf_handover(entry_point_info_t *bl32,
+ entry_point_info_t *bl33,
+ uint64_t atf_handoff_addr);
+
+#endif /* PLAT_STARTUP_H */
diff --git a/plat/xilinx/common/include/pm_client.h b/plat/xilinx/common/include/pm_client.h
new file mode 100644
index 0000000..eae1d98
--- /dev/null
+++ b/plat/xilinx/common/include/pm_client.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022, Advanced Micro Devices, Inc. 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, uint32_t state);
+void pm_client_abort_suspend(void);
+void pm_client_wakeup(const struct pm_proc *proc);
+
+/* Global variables to be set in pm_client.c */
+extern const struct pm_proc *primary_proc;
+
+#if defined(PLAT_zynqmp)
+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);
+#endif /* PLAT_zynqmp */
+
+#endif /* PM_CLIENT_H */
diff --git a/plat/xilinx/common/include/pm_common.h b/plat/xilinx/common/include/pm_common.h
new file mode 100644
index 0000000..89626e5
--- /dev/null
+++ b/plat/xilinx/common/include/pm_common.h
@@ -0,0 +1,62 @@
+/*
+ * 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 <stdint.h>
+#include <plat_pm_common.h>
+
+#if IPI_CRC_CHECK
+#define PAYLOAD_ARG_CNT 8U
+#define IPI_W0_TO_W6_SIZE 28U
+#define PAYLOAD_CRC_POS 7U
+#define CRC_INIT_VALUE 0x4F4EU
+#define CRC_ORDER 16U
+#define CRC_POLYNOM 0x8005U
+#else
+#define PAYLOAD_ARG_CNT 6U
+#endif
+#define PAYLOAD_ARG_SIZE 4U /* size in bytes */
+
+#define TZ_VERSION_MAJOR 1
+#define TZ_VERSION_MINOR 0
+#define TZ_VERSION ((TZ_VERSION_MAJOR << 16) | \
+ TZ_VERSION_MINOR)
+
+/**
+ * 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 uint32_t pwrdn_mask;
+ const struct pm_ipi *ipi;
+};
+
+const struct pm_proc *pm_get_proc(uint32_t cpuid);
+
+#endif /* PM_COMMON_H */
diff --git a/plat/xilinx/common/include/pm_ipi.h b/plat/xilinx/common/include/pm_ipi.h
new file mode 100644
index 0000000..52dfc47
--- /dev/null
+++ b/plat/xilinx/common/include/pm_ipi.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PM_IPI_H
+#define PM_IPI_H
+
+#include <plat_ipi.h>
+#include <stddef.h>
+#include "pm_common.h"
+
+#define IPI_BLOCKING 1
+#define IPI_NON_BLOCKING 0
+
+void 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],
+ uint32_t *value, size_t count);
+void pm_ipi_buff_read_callb(uint32_t *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);
+#if IPI_CRC_CHECK
+uint32_t calculate_crc(uint32_t payload[PAYLOAD_ARG_CNT], uint32_t buffersize);
+#endif
+
+#endif /* PM_IPI_H */
diff --git a/plat/xilinx/common/ipi.c b/plat/xilinx/common/ipi.c
new file mode 100644
index 0000000..6438896
--- /dev/null
+++ b/plat/xilinx/common/ipi.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Xilinx IPI agent registers access management
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include <ipi.h>
+#include <plat_private.h>
+
+/*********************************************************************
+ * 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;
+ } else {
+ /* To fix the misra 15.7 warning */
+ }
+
+ 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 = 0U;
+ 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));
+}
diff --git a/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c
new file mode 100644
index 0000000..cb6aaa5
--- /dev/null
+++ b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Top-level SMC handler for ZynqMP IPI Mailbox doorbell functions.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include <ipi.h>
+#include <plat_ipi.h>
+#include <plat_private.h>
+
+#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, const void *cookie,
+ void *handle, uint64_t flags)
+{
+ int32_t ret;
+ uint32_t ipi_local_id;
+ uint32_t ipi_remote_id;
+ uint32_t 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:
+ {
+ int32_t 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:
+ {
+ int32_t 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);
+ }
+}
diff --git a/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h
new file mode 100644
index 0000000..af13db9
--- /dev/null
+++ b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017-2019, 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 <stdint.h>
+
+/*********************************************************************
+ * 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, const void *cookie, void *handle,
+ uint64_t flags);
+
+#endif /* IPI_MAILBOX_SVC_H */
diff --git a/plat/xilinx/common/plat_startup.c b/plat/xilinx/common/plat_startup.c
new file mode 100644
index 0000000..de9cf4d
--- /dev/null
+++ b/plat/xilinx/common/plat_startup.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <plat_startup.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 0U
+#define FSBL_FLAGS_ESTATE_MASK (1U << FSBL_FLAGS_ESTATE_SHIFT)
+#define FSBL_FLAGS_ESTATE_A64 0U
+#define FSBL_FLAGS_ESTATE_A32 1U
+
+#define FSBL_FLAGS_ENDIAN_SHIFT 1U
+#define FSBL_FLAGS_ENDIAN_MASK (1U << FSBL_FLAGS_ENDIAN_SHIFT)
+#define FSBL_FLAGS_ENDIAN_LE 0U
+#define FSBL_FLAGS_ENDIAN_BE 1U
+
+#define FSBL_FLAGS_TZ_SHIFT 2U
+#define FSBL_FLAGS_TZ_MASK (1U << FSBL_FLAGS_TZ_SHIFT)
+#define FSBL_FLAGS_NON_SECURE 0U
+#define FSBL_FLAGS_SECURE 1U
+
+#define FSBL_FLAGS_EL_SHIFT 3U
+#define FSBL_FLAGS_EL_MASK (3U << FSBL_FLAGS_EL_SHIFT)
+#define FSBL_FLAGS_EL0 0U
+#define FSBL_FLAGS_EL1 1U
+#define FSBL_FLAGS_EL2 2U
+#define FSBL_FLAGS_EL3 3U
+
+#define FSBL_FLAGS_CPU_SHIFT 5U
+#define FSBL_FLAGS_CPU_MASK (3U << FSBL_FLAGS_CPU_SHIFT)
+#define FSBL_FLAGS_A53_0 0U
+#define FSBL_FLAGS_A53_1 1U
+#define FSBL_FLAGS_A53_2 2U
+#define FSBL_FLAGS_A53_3 3U
+
+/**
+ * @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 int32_t 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 int32_t 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 int32_t 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 int32_t 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 int32_t 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
+ * atf_handoff_addr: ATF handoff address
+ *
+ * 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;
+ 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 %" PRIx64 "\n",
+ atf_handoff_addr);
+ return FSBL_HANDOFF_INVAL_STRUCT;
+ }
+
+ VERBOSE("BL31: ATF handoff params at:0x%" PRIx64 ", 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;
+ int32_t target_estate, target_secure, target_cpu;
+ uint32_t target_endianness, target_el;
+
+ VERBOSE("BL31: %zd: entry:0x%" PRIx64 ", flags:0x%" PRIx64 "\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:%" PRIx64 ", 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;
+}
diff --git a/plat/xilinx/common/pm_service/pm_ipi.c b/plat/xilinx/common/pm_service/pm_ipi.c
new file mode 100644
index 0000000..513d6be
--- /dev/null
+++ b/plat/xilinx/common/pm_service/pm_ipi.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#include <arch_helpers.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <ipi.h>
+#include <plat_ipi.h>
+#include <plat_private.h>
+#include <plat/common/platform.h>
+
+#include "pm_defs.h"
+#include "pm_ipi.h"
+
+#define ERROR_CODE_MASK (0xFFFFU)
+#define PM_OFFSET (0U)
+
+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
+ */
+void 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);
+}
+
+/**
+ * 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)
+{
+ uint32_t offset = PM_OFFSET;
+ uintptr_t buffer_base = proc->ipi->buffer_base +
+ IPI_BUFFER_TARGET_REMOTE_OFFSET +
+ IPI_BUFFER_REQ_OFFSET;
+#if IPI_CRC_CHECK
+ payload[PAYLOAD_CRC_POS] = calculate_crc(payload, IPI_W0_TO_W6_SIZE);
+#endif
+
+ /* 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,
+ uint32_t *value, size_t count)
+{
+ size_t i;
+#if IPI_CRC_CHECK
+ size_t j;
+ uint32_t response_payload[PAYLOAD_ARG_CNT];
+#endif
+ 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++;
+ }
+#if IPI_CRC_CHECK
+ for (j = 0; j < PAYLOAD_ARG_CNT; j++) {
+ response_payload[j] = mmio_read_32(buffer_base +
+ (j * PAYLOAD_ARG_SIZE));
+ }
+
+ if (response_payload[PAYLOAD_CRC_POS] !=
+ calculate_crc(response_payload, IPI_W0_TO_W6_SIZE)) {
+ NOTICE("ERROR in CRC response payload value:0x%x\n",
+ response_payload[PAYLOAD_CRC_POS]);
+ }
+#endif
+
+ 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(uint32_t *value, size_t count)
+{
+ size_t i;
+#if IPI_CRC_CHECK
+ size_t j;
+ unsigned int response_payload[PAYLOAD_ARG_CNT] = {0};
+#endif
+ 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++;
+ }
+#if IPI_CRC_CHECK
+ for (j = 0; j < PAYLOAD_ARG_CNT; j++) {
+ response_payload[j] = mmio_read_32(buffer_base +
+ (j * PAYLOAD_ARG_SIZE));
+ }
+
+ if (response_payload[PAYLOAD_CRC_POS] !=
+ calculate_crc(response_payload, IPI_W0_TO_W6_SIZE)) {
+ NOTICE("ERROR in CRC response payload value:0x%x\n",
+ response_payload[PAYLOAD_CRC_POS]);
+ }
+#endif
+}
+
+/**
+ * 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],
+ uint32_t *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 = ERROR_CODE_MASK & (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)
+{
+ int32_t 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;
+ }
+}
+
+#if IPI_CRC_CHECK
+uint32_t calculate_crc(uint32_t payload[PAYLOAD_ARG_CNT], uint32_t bufsize)
+{
+ uint32_t crcinit = CRC_INIT_VALUE;
+ uint32_t order = CRC_ORDER;
+ uint32_t polynom = CRC_POLYNOM;
+ uint32_t i, j, c, bit, datain, crcmask, crchighbit;
+ uint32_t crc = crcinit;
+
+ crcmask = ((uint32_t)((1U << (order - 1U)) - 1U) << 1U) | 1U;
+ crchighbit = (uint32_t)(1U << (order - 1U));
+
+ for (i = 0U; i < bufsize; i++) {
+ datain = mmio_read_8((unsigned long)payload + i);
+ c = datain;
+ j = 0x80U;
+ while (j != 0U) {
+ bit = crc & crchighbit;
+ crc <<= 1U;
+ if (0U != (c & j))
+ bit ^= crchighbit;
+ if (bit != 0U)
+ crc ^= polynom;
+ j >>= 1U;
+ }
+ crc &= crcmask;
+ }
+ return crc;
+}
+#endif
diff --git a/plat/xilinx/versal/aarch64/versal_common.c b/plat/xilinx/versal/aarch64/versal_common.c
new file mode 100644
index 0000000..f55cde9
--- /dev/null
+++ b/plat/xilinx/versal/aarch64/versal_common.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_ipi.h>
+#include <versal_def.h>
+#include <plat_private.h>
+#include <common/debug.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.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),
+ MAP_REGION_FLAT(FPD_MAINCCI_BASE, FPD_MAINCCI_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)
+{
+ /* Configure IPI data for versal */
+ versal_ipi_config_table_init();
+
+ versal_print_platform_name();
+
+ generic_delay_timer_init();
+}
+
+uint32_t plat_get_syscnt_freq2(void)
+{
+ return VERSAL_CPU_CLOCK;
+}
+
diff --git a/plat/xilinx/versal/aarch64/versal_helpers.S b/plat/xilinx/versal/aarch64/versal_helpers.S
new file mode 100644
index 0000000..26eb052
--- /dev/null
+++ b/plat/xilinx/versal/aarch64/versal_helpers.S
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/gicv3.h>
+#include <platform_def.h>
+
+ .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
diff --git a/plat/xilinx/versal/bl31_versal_setup.c b/plat/xilinx/versal/bl31_versal_setup.c
new file mode 100644
index 0000000..9b36208
--- /dev/null
+++ b/plat/xilinx/versal/bl31_versal_setup.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <plat_arm.h>
+#include <plat_private.h>
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/dcc.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.h>
+#include <versal_def.h>
+#include <plat_private.h>
+#include <plat_startup.h>
+#include <pm_ipi.h>
+#include "pm_client.h"
+#include "pm_api_sys.h"
+
+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,if we can't find any config data.
+ */
+static inline void bl31_set_default_config(void)
+{
+ bl32_image_ep_info.pc = (uintptr_t)BL32_BASE;
+ bl32_image_ep_info.spsr = (uint32_t)arm_get_spsr_for_bl32_entry();
+ bl33_image_ep_info.pc = (uintptr_t)plat_get_ns_image_entrypoint();
+ bl33_image_ep_info.spsr = (uint32_t)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 & 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)
+{
+ uint64_t atf_handoff_addr;
+ uint32_t payload[PAYLOAD_ARG_CNT], max_size = ATF_HANDOFF_PARAMS_MAX_SIZE;
+ enum pm_ret_status ret_status;
+ uint64_t addr[ATF_HANDOFF_PARAMS_MAX_SIZE];
+
+ if (VERSAL_CONSOLE_IS(pl011) || (VERSAL_CONSOLE_IS(pl011_1))) {
+ static console_t versal_runtime_console;
+ /* Initialize the console to provide early debug support */
+ int32_t rc = console_pl011_register((uintptr_t)VERSAL_UART_BASE,
+ (uint32_t)VERSAL_UART_CLOCK,
+ (uint32_t)VERSAL_UART_BAUDRATE,
+ &versal_runtime_console);
+ if (rc == 0) {
+ panic();
+ }
+
+ console_set_scope(&versal_runtime_console, (uint32_t)(CONSOLE_FLAG_BOOT |
+ CONSOLE_FLAG_RUNTIME));
+ } else if (VERSAL_CONSOLE_IS(dcc)) {
+ /* Initialize the dcc console for debug */
+ int32_t rc = console_dcc_register();
+ if (rc == 0) {
+ panic();
+ }
+ } else {
+ NOTICE("BL31: Did not register for any console.\n");
+ }
+
+ /* 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);
+
+ PM_PACK_PAYLOAD4(payload, LOADER_MODULE_ID, 1, PM_LOAD_GET_HANDOFF_PARAMS,
+ (uintptr_t)addr >> 32U, (uintptr_t)addr, max_size);
+ ret_status = pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+ if (ret_status == PM_RET_SUCCESS) {
+ INFO("BL31: GET_HANDOFF_PARAMS call success=%d\n", ret_status);
+ atf_handoff_addr = (uintptr_t)&addr;
+ } else {
+ ERROR("BL31: GET_HANDOFF_PARAMS Failed, read atf_handoff_addr from reg\n");
+ atf_handoff_addr = mmio_read_32(PMC_GLOBAL_GLOB_GEN_STORAGE4);
+ }
+
+ enum fsbl_handoff ret = fsbl_atf_handover(&bl32_image_ep_info,
+ &bl33_image_ep_info,
+ atf_handoff_addr);
+ if (ret == FSBL_HANDOFF_NO_STRUCT || ret == FSBL_HANDOFF_INVAL_STRUCT) {
+ bl31_set_default_config();
+ } else if (ret == FSBL_HANDOFF_TOO_MANY_PARTS) {
+ ERROR("BL31: Error too many partitions %u\n", ret);
+ } else if (ret != FSBL_HANDOFF_SUCCESS) {
+ panic();
+ } else {
+ INFO("BL31: fsbl-atf handover success %u\n", ret);
+ }
+
+ 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);
+}
+
+static versal_intr_info_type_el3_t type_el3_interrupt_table[MAX_INTR_EL3];
+
+int request_intr_type_el3(uint32_t id, interrupt_type_handler_t handler)
+{
+ static uint32_t index;
+ uint32_t i;
+
+ /* Validate 'handler' and 'id' parameters */
+ if (handler == NULL || index >= MAX_INTR_EL3) {
+ return -EINVAL;
+ }
+
+ /* Check if a handler has already been registered */
+ for (i = 0; i < index; i++) {
+ if (id == type_el3_interrupt_table[i].id) {
+ return -EALREADY;
+ }
+ }
+
+ type_el3_interrupt_table[index].id = id;
+ type_el3_interrupt_table[index].handler = handler;
+
+ index++;
+
+ return 0;
+}
+
+static uint64_t rdo_el3_interrupt_handler(uint32_t id, uint32_t flags,
+ void *handle, void *cookie)
+{
+ uint32_t intr_id;
+ uint32_t i;
+ interrupt_type_handler_t handler = NULL;
+
+ intr_id = plat_ic_get_pending_interrupt_id();
+
+ for (i = 0; i < MAX_INTR_EL3; i++) {
+ if (intr_id == type_el3_interrupt_table[i].id) {
+ handler = type_el3_interrupt_table[i].handler;
+ }
+ }
+
+ if (handler != NULL) {
+ return handler(intr_id, flags, handle, cookie);
+ }
+
+ return 0;
+}
+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)
+{
+ uint64_t flags = 0;
+ int32_t rc;
+
+ set_interrupt_rm_flag(flags, NON_SECURE);
+ rc = register_interrupt_type_handler(INTR_TYPE_EL3,
+ rdo_el3_interrupt_handler, flags);
+ if (rc != 0) {
+ panic();
+ }
+}
+
+/*
+ * 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_versal_get_mmap());
+ enable_mmu_el3(0);
+}
diff --git a/plat/xilinx/versal/include/plat_ipi.h b/plat/xilinx/versal/include/plat_ipi.h
new file mode 100644
index 0000000..36a4380
--- /dev/null
+++ b/plat/xilinx/versal/include/plat_ipi.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Versal IPI management enums and defines */
+
+#ifndef PLAT_IPI_H
+#define PLAT_IPI_H
+
+#include <ipi.h>
+#include <stdint.h>
+
+/*********************************************************************
+ * IPI agent IDs macros
+ ********************************************************************/
+#define IPI_ID_PMC 1U
+#define IPI_ID_APU 2U
+#define IPI_ID_RPU0 3U
+#define IPI_ID_RPU1 4U
+#define IPI_ID_3 5U
+#define IPI_ID_4 6U
+#define IPI_ID_5 7U
+
+/*********************************************************************
+ * IPI message buffers
+ ********************************************************************/
+#define IPI_BUFFER_BASEADDR 0xFF3F0000U
+
+#define IPI_BUFFER_APU_BASE (IPI_BUFFER_BASEADDR + 0x400U)
+#define IPI_BUFFER_PMC_BASE (IPI_BUFFER_BASEADDR + 0x200U)
+
+#define IPI_BUFFER_TARGET_APU_OFFSET 0x80U
+#define IPI_BUFFER_TARGET_PMC_OFFSET 0x40U
+
+#define IPI_BUFFER_LOCAL_BASE IPI_BUFFER_APU_BASE
+#define IPI_BUFFER_REMOTE_BASE IPI_BUFFER_PMC_BASE
+
+#define IPI_BUFFER_TARGET_LOCAL_OFFSET IPI_BUFFER_TARGET_APU_OFFSET
+#define IPI_BUFFER_TARGET_REMOTE_OFFSET IPI_BUFFER_TARGET_PMC_OFFSET
+
+#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 versal */
+void versal_ipi_config_table_init(void);
+
+#endif /* PLAT_IPI_H */
diff --git a/plat/xilinx/versal/include/plat_macros.S b/plat/xilinx/versal/include/plat_macros.S
new file mode 100644
index 0000000..3a52212
--- /dev/null
+++ b/plat/xilinx/versal/include/plat_macros.S
@@ -0,0 +1,110 @@
+/*
+ * 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 <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gicv3.h>
+
+#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 */
diff --git a/plat/xilinx/versal/include/plat_pm_common.h b/plat/xilinx/versal/include/plat_pm_common.h
new file mode 100644
index 0000000..4c057b8
--- /dev/null
+++ b/plat/xilinx/versal/include/plat_pm_common.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2019, Xilinx, Inc. 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 <common/debug.h>
+#include <stdint.h>
+#include "pm_defs.h"
+
+#define NON_SECURE_FLAG 1U
+#define SECURE_FLAG 0U
+
+#endif /* PLAT_PM_COMMON_H */
diff --git a/plat/xilinx/versal/include/plat_private.h b/plat/xilinx/versal/include/plat_private.h
new file mode 100644
index 0000000..818797d
--- /dev/null
+++ b/plat/xilinx/versal/include/plat_private.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PRIVATE_H
+#define PLAT_PRIVATE_H
+
+#include <lib/xlat_tables/xlat_tables.h>
+#include <bl31/interrupt_mgmt.h>
+
+typedef struct versal_intr_info_type_el3 {
+ uint32_t id;
+ interrupt_type_handler_t handler;
+} versal_intr_info_type_el3_t;
+
+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);
+void plat_versal_gic_save(void);
+void plat_versal_gic_resume(void);
+
+uint32_t versal_calc_core_pos(u_register_t mpidr);
+/*
+ * Register handler to specific GIC entrance
+ * for INTR_TYPE_EL3 type of interrupt
+ */
+int32_t request_intr_type_el3(uint32_t irq, interrupt_type_handler_t fiq_handler);
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/xilinx/versal/include/platform_def.h b/plat/xilinx/versal/include/platform_def.h
new file mode 100644
index 0000000..6d95fdc
--- /dev/null
+++ b/plat/xilinx/versal/include/platform_def.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include "versal_def.h"
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE U(0x440)
+
+#define PLATFORM_CORE_COUNT U(2)
+#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 VERSAL_ATF_MEM_BASE
+# define BL31_BASE U(0xfffe0000)
+# define BL31_LIMIT U(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 U(0x60000000)
+# define BL32_LIMIT U(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_ARM_NS_IMAGE_BASE U(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 8
+#define MAX_XLAT_TABLES 5
+
+#define CACHE_WRITEBACK_SHIFT 6
+#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
+
+#define PLAT_VERSAL_GICD_BASE U(0xF9000000)
+#define PLAT_VERSAL_GICR_BASE U(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_IPI_IRQ U(62)
+
+#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) \
+ INTR_PROP_DESC(PLAT_VERSAL_IPI_IRQ, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/xilinx/versal/include/versal_def.h b/plat/xilinx/versal/include/versal_def.h
new file mode 100644
index 0000000..60431a5
--- /dev/null
+++ b/plat/xilinx/versal/include/versal_def.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef VERSAL_DEF_H
+#define VERSAL_DEF_H
+
+#include <plat/arm/common/smccc_def.h>
+#include <plat/common/common_def.h>
+
+/* number of interrupt handlers. increase as required */
+#define MAX_INTR_EL3 2
+/* 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_ID_spp_itr6 2
+#define VERSAL_PLATFORM_ID_emu_itr6 3
+#define VERSAL_PLATFORM_ID_silicon 4
+
+#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
+
+/*******************************************************************************
+ * IRQ constants
+ ******************************************************************************/
+#define VERSAL_IRQ_SEC_PHY_TIMER U(29)
+
+/*******************************************************************************
+ * CCI-400 related constants
+ ******************************************************************************/
+#define PLAT_ARM_CCI_BASE 0xFD000000
+#define PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX 4
+#define PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX 5
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define VERSAL_UART0_BASE 0xFF000000
+#define VERSAL_UART1_BASE 0xFF010000
+
+#if VERSAL_CONSOLE_IS(pl011) || VERSAL_CONSOLE_IS(dcc)
+# 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 2720000
+#elif VERSAL_PLATFORM_IS(silicon)
+# define PLATFORM_NAME "Versal Silicon"
+# define VERSAL_UART_CLOCK 100000000
+# define VERSAL_UART_BAUDRATE 115200
+# define VERSAL_CPU_CLOCK 100000000
+#elif VERSAL_PLATFORM_IS(spp_itr6)
+# define PLATFORM_NAME "SPP ITR6"
+# define VERSAL_UART_CLOCK 25000000
+# define VERSAL_UART_BAUDRATE 115200
+# define VERSAL_CPU_CLOCK 2720000
+#elif VERSAL_PLATFORM_IS(emu_itr6)
+# define PLATFORM_NAME "EMU ITR6"
+# define VERSAL_UART_CLOCK 212000
+# define VERSAL_UART_BAUDRATE 9600
+# define VERSAL_CPU_CLOCK 212000
+#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)
+
+#define FPD_MAINCCI_BASE 0xFD000000
+#define FPD_MAINCCI_SIZE 0x00100000
+
+/* APU registers and bitfields */
+#define FPD_APU_BASE 0xFD5C0000U
+#define FPD_APU_CONFIG_0 (FPD_APU_BASE + 0x20U)
+#define FPD_APU_RVBAR_L_0 (FPD_APU_BASE + 0x40U)
+#define FPD_APU_RVBAR_H_0 (FPD_APU_BASE + 0x44U)
+#define FPD_APU_PWRCTL (FPD_APU_BASE + 0x90U)
+
+#define FPD_APU_CONFIG_0_VINITHI_SHIFT 8U
+#define APU_0_PWRCTL_CPUPWRDWNREQ_MASK 1U
+#define APU_1_PWRCTL_CPUPWRDWNREQ_MASK 2U
+
+/* PMC registers and bitfields */
+#define PMC_GLOBAL_BASE 0xF1110000U
+#define PMC_GLOBAL_GLOB_GEN_STORAGE4 (PMC_GLOBAL_BASE + 0x40U)
+
+/* IPI registers and bitfields */
+#define IPI0_REG_BASE U(0xFF330000)
+#define IPI0_TRIG_BIT (1U << 2U)
+#define PMC_IPI_TRIG_BIT (1U << 1U)
+#define IPI1_REG_BASE U(0xFF340000)
+#define IPI1_TRIG_BIT (1U << 3U)
+#define IPI2_REG_BASE U(0xFF350000)
+#define IPI2_TRIG_BIT (1U << 4U)
+#define IPI3_REG_BASE U(0xFF360000)
+#define IPI3_TRIG_BIT (1U << 5U)
+#define IPI4_REG_BASE U(0xFF370000)
+#define IPI4_TRIG_BIT (1U << 5U)
+#define IPI5_REG_BASE U(0xFF380000)
+#define IPI5_TRIG_BIT (1U << 6U)
+
+#endif /* VERSAL_DEF_H */
diff --git a/plat/xilinx/versal/plat_psci.c b/plat/xilinx/versal/plat_psci.c
new file mode 100644
index 0000000..6787f31
--- /dev/null
+++ b/plat/xilinx/versal/plat_psci.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <plat_arm.h>
+#include <plat_private.h>
+#include <pm_common.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+#include <plat/arm/common/plat_arm.h>
+
+#include "pm_api_sys.h"
+#include "pm_client.h"
+
+static uintptr_t versal_sec_entry;
+
+static int32_t versal_pwr_domain_on(u_register_t mpidr)
+{
+ int32_t 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((uint32_t)cpu_id);
+
+ /* Send request to PMC to wake up selected ACPU core */
+ (void)pm_req_wakeup(proc->node_id, (versal_sec_entry & 0xFFFFFFFFU) | 0x1U,
+ versal_sec_entry >> 32, 0, SECURE_FLAG);
+
+ /* Clear power down request */
+ pm_client_wakeup(proc);
+
+ return PSCI_E_SUCCESS;
+}
+
+/**
+ * versal_pwr_domain_suspend() - This function sends request to PMC to suspend
+ * core.
+ *
+ * @target_state Targated state
+ */
+static void versal_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+ uint32_t state;
+ uint32_t cpu_id = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+ for (size_t i = 0U; i <= PLAT_MAX_PWR_LVL; i++) {
+ VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+ __func__, i, target_state->pwr_domain_state[i]);
+ }
+
+ plat_versal_gic_cpuif_disable();
+
+ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+ plat_versal_gic_save();
+ }
+
+ state = target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE ?
+ PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE;
+
+ /* Send request to PMC to suspend this core */
+ (void)pm_self_suspend(proc->node_id, MAX_LATENCY, state, versal_sec_entry,
+ SECURE_FLAG);
+
+ /* APU is to be turned off */
+ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+ /* disable coherency */
+ plat_arm_interconnect_exit_coherency();
+ }
+}
+
+/**
+ * versal_pwr_domain_suspend_finish() - This function performs actions to finish
+ * suspend procedure.
+ *
+ * @target_state Targated state
+ */
+static void versal_pwr_domain_suspend_finish(
+ const psci_power_state_t *target_state)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+ for (size_t i = 0U; 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, so restore GIC context */
+ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+ plat_versal_gic_resume();
+ }
+
+ plat_versal_gic_cpuif_enable();
+}
+
+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();
+}
+
+/**
+ * versal_system_off() - This function sends the system off request
+ * to firmware. This function does not return.
+ */
+static void __dead2 versal_system_off(void)
+{
+ /* Send the power down request to the PMC */
+ (void)pm_system_shutdown(XPM_SHUTDOWN_TYPE_SHUTDOWN,
+ pm_get_shutdown_scope(), SECURE_FLAG);
+
+ while (1) {
+ wfi();
+ }
+}
+
+/**
+ * versal_system_reset() - This function sends the reset request
+ * to firmware for the system to reset. This function does not return.
+ */
+static void __dead2 versal_system_reset(void)
+{
+ /* Send the system reset request to the PMC */
+ (void)pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET,
+ pm_get_shutdown_scope(), SECURE_FLAG);
+
+ while (1) {
+ wfi();
+ }
+}
+
+/**
+ * versal_pwr_domain_off() - This function performs actions to turn off core
+ *
+ * @target_state Targated state
+ */
+static void versal_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+ for (size_t i = 0U; 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 */
+ plat_versal_gic_cpuif_disable();
+
+ /*
+ * Send request to PMC 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.
+ */
+ (void)pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0,
+ SECURE_FLAG);
+}
+
+/**
+ * versal_validate_power_state() - This function ensures that the power state
+ * parameter in request is valid.
+ *
+ * @power_state Power state of core
+ * @req_state Requested state
+ *
+ * @return Returns status, either success or reason
+ */
+static int32_t versal_validate_power_state(uint32_t power_state,
+ psci_power_state_t *req_state)
+{
+ VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
+
+ uint32_t 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) != 0U) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ return PSCI_E_SUCCESS;
+}
+
+/**
+ * versal_get_sys_suspend_power_state() - Get power state for system suspend
+ *
+ * @req_state Requested state
+ */
+static void versal_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;
+}
+
+static const struct plat_psci_ops versal_nopmc_psci_ops = {
+ .pwr_domain_on = versal_pwr_domain_on,
+ .pwr_domain_off = versal_pwr_domain_off,
+ .pwr_domain_on_finish = versal_pwr_domain_on_finish,
+ .pwr_domain_suspend = versal_pwr_domain_suspend,
+ .pwr_domain_suspend_finish = versal_pwr_domain_suspend_finish,
+ .system_off = versal_system_off,
+ .system_reset = versal_system_reset,
+ .validate_power_state = versal_validate_power_state,
+ .get_sys_suspend_power_state = versal_get_sys_suspend_power_state,
+};
+
+/*******************************************************************************
+ * Export the platform specific power ops.
+ ******************************************************************************/
+int32_t 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;
+}
diff --git a/plat/xilinx/versal/plat_topology.c b/plat/xilinx/versal/plat_topology.c
new file mode 100644
index 0000000..6a94544
--- /dev/null
+++ b/plat/xilinx/versal/plat_topology.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+static const uint8_t plat_power_domain_tree_desc[] = {1, PLATFORM_CORE_COUNT};
+
+const uint8_t *plat_get_power_domain_tree_desc(void)
+{
+ return plat_power_domain_tree_desc;
+}
diff --git a/plat/xilinx/versal/plat_versal.c b/plat/xilinx/versal/plat_versal.c
new file mode 100644
index 0000000..132c7b7
--- /dev/null
+++ b/plat/xilinx/versal/plat_versal.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_private.h>
+#include <plat/common/platform.h>
+
+int32_t plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+ if ((mpidr & MPIDR_CLUSTER_MASK) != 0U) {
+ return -1;
+ }
+
+ if ((mpidr & MPIDR_CPU_MASK) >= PLATFORM_CORE_COUNT) {
+ return -1;
+ }
+
+ return (int32_t)versal_calc_core_pos(mpidr);
+}
diff --git a/plat/xilinx/versal/platform.mk b/plat/xilinx/versal/platform.mk
new file mode 100644
index 0000000..8087297
--- /dev/null
+++ b/plat/xilinx/versal/platform.mk
@@ -0,0 +1,98 @@
+# Copyright (c) 2018-2021, 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
+IPI_CRC_CHECK := 0
+HARDEN_SLS_ALL := 0
+
+# A72 Erratum for SoC
+ERRATA_A72_859971 := 1
+ERRATA_A72_1319367 := 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
+
+ifdef IPI_CRC_CHECK
+ $(eval $(call add_define,IPI_CRC_CHECK))
+endif
+
+VERSAL_PLATFORM ?= silicon
+$(eval $(call add_define_val,VERSAL_PLATFORM,VERSAL_PLATFORM_ID_${VERSAL_PLATFORM}))
+
+PLAT_INCLUDES := -Iinclude/plat/arm/common/ \
+ -Iplat/xilinx/common/include/ \
+ -Iplat/xilinx/common/ipi_mailbox_service/ \
+ -Iplat/xilinx/versal/include/ \
+ -Iplat/xilinx/versal/pm_service/
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \
+ lib/xlat_tables/aarch64/xlat_tables.c \
+ drivers/arm/dcc/dcc_console.c \
+ drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ ${GICV3_SOURCES} \
+ drivers/arm/pl011/aarch64/pl011_console.S \
+ plat/common/aarch64/crash_console_helpers.S \
+ plat/arm/common/arm_cci.c \
+ plat/arm/common/arm_common.c \
+ plat/common/plat_gicv3.c \
+ plat/xilinx/versal/aarch64/versal_helpers.S \
+ plat/xilinx/versal/aarch64/versal_common.c
+
+VERSAL_CONSOLE ?= pl011
+ifeq (${VERSAL_CONSOLE}, $(filter ${VERSAL_CONSOLE},pl011 pl011_0 pl011_1 dcc))
+else
+ $(error "Please define VERSAL_CONSOLE")
+endif
+
+$(eval $(call add_define_val,VERSAL_CONSOLE,VERSAL_CONSOLE_ID_${VERSAL_CONSOLE}))
+
+BL31_SOURCES += drivers/arm/cci/cci.c \
+ lib/cpus/aarch64/cortex_a72.S \
+ plat/common/plat_psci_common.c \
+ plat/xilinx/common/ipi.c \
+ plat/xilinx/common/plat_startup.c \
+ plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c \
+ plat/xilinx/common/pm_service/pm_ipi.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 \
+ plat/xilinx/versal/versal_ipi.c \
+ plat/xilinx/versal/pm_service/pm_svc_main.c \
+ plat/xilinx/versal/pm_service/pm_api_sys.c \
+ plat/xilinx/versal/pm_service/pm_client.c
+
+ifeq ($(HARDEN_SLS_ALL), 1)
+TF_CFLAGS_aarch64 += -mharden-sls=all
+endif
diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.c b/plat/xilinx/versal/pm_service/pm_api_sys.c
new file mode 100644
index 0000000..db9fae4
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_api_sys.c
@@ -0,0 +1,589 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Versal system level PM-API functions and communication with PMC via
+ * IPI interrupts
+ */
+
+#include <pm_common.h>
+#include <pm_ipi.h>
+#include <plat/common/platform.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_defs.h"
+#include "pm_svc_main.h"
+
+/* default shutdown/reboot scope is system(2) */
+static uint32_t pm_shutdown_scope = XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM;
+
+/**
+ * pm_get_shutdown_scope() - Get the currently set shutdown scope
+ *
+ * @return Shutdown scope value
+ */
+uint32_t pm_get_shutdown_scope(void)
+{
+ return pm_shutdown_scope;
+}
+
+/* PM API functions */
+
+/**
+ * pm_handle_eemi_call() - PM call for processor to send eemi payload
+ * @flag 0 - Call from secure source
+ * 1 - Call from non-secure source
+ * @x0 to x5 Arguments received per SMC64 standard
+ * @result Payload received from firmware
+ *
+ * @return PM_RET_SUCCESS on success or error code
+ */
+enum pm_ret_status pm_handle_eemi_call(uint32_t flag, uint32_t x0, uint32_t x1,
+ uint32_t x2, uint32_t x3, uint32_t x4,
+ uint32_t x5, uint64_t *result)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT] = {0};
+ uint32_t module_id;
+
+ module_id = (x0 & MODULE_ID_MASK) >> 8U;
+
+ //default module id is for LIBPM
+ if (module_id == 0) {
+ module_id = LIBPM_MODULE_ID;
+ }
+
+ PM_PACK_PAYLOAD6(payload, module_id, flag, x0, x1, x2, x3, x4, x5);
+ return pm_ipi_send_sync(primary_proc, payload, (uint32_t *)result, PAYLOAD_ARG_CNT);
+}
+
+/**
+ * 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
+ * @flag 0 - Call from secure source
+ * 1 - Call from non-secure source
+ *
+ * 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(uint32_t nid,
+ uint32_t latency,
+ uint32_t state,
+ uintptr_t address, uint32_t flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+ uint32_t cpuid = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpuid);
+
+ if (proc == NULL) {
+ WARN("Failed to get proc %d\n", cpuid);
+ return PM_RET_ERROR_INTERNAL;
+ }
+
+ /*
+ * Do client specific suspend operations
+ * (e.g. set powerdown request bit)
+ */
+ pm_client_suspend(proc, state);
+
+ /* Send request to the PLM */
+ PM_PACK_PAYLOAD6(payload, LIBPM_MODULE_ID, flag, PM_SELF_SUSPEND,
+ proc->node_id, latency, state, address,
+ (address >> 32));
+ return pm_ipi_send_sync(proc, payload, NULL, 0);
+}
+
+/**
+ * pm_abort_suspend() - PM call to announce that a prior suspend request
+ * is to be aborted.
+ * @reason Reason for the abort
+ * @flag 0 - Call from secure source
+ * 1 - Call from non-secure source
+ *
+ * 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 flag)
+{
+ 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 PLM */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_ABORT_SUSPEND,
+ reason, primary_proc->node_id);
+ return pm_ipi_send_sync(primary_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)
+ * @flag 0 - Call from secure source
+ * 1 - Call from non-secure source
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_req_suspend(uint32_t target, uint8_t ack,
+ uint32_t latency, uint32_t state,
+ uint32_t flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag, PM_REQ_SUSPEND, target,
+ latency, state);
+ if (ack == IPI_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 Device ID of the processor or subsystem to wake up
+ * @set_address Resume address presence indicator
+ * 1 - resume address specified, 0 - otherwise
+ * @address Resume address
+ * @ack Flag to specify whether acknowledge requested
+ * @flag 0 - Call from secure source
+ * 1 - Call from non-secure source
+ *
+ * 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 PMC.
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_req_wakeup(uint32_t target, uint32_t set_address,
+ uintptr_t address, uint8_t ack, uint32_t flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC to perform the wake of the PU */
+ PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_REQ_WAKEUP, target,
+ set_address, address, ack);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_get_callbackdata() - Read from IPI response buffer
+ * @data - array of PAYLOAD_ARG_CNT elements
+ * @flag - 0 - Call from secure source
+ * 1 - Call from non-secure source
+ * @ack - 0 - Do not ack IPI after reading payload
+ * 1 - Ack IPI after reading payload
+ *
+ * Read value from ipi buffer response buffer.
+ */
+void pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag, uint32_t ack)
+{
+ /* Return if interrupt is not from PMU */
+ if (pm_ipi_irq_status(primary_proc) == 0) {
+ return;
+ }
+
+ pm_ipi_buff_read_callb(data, count);
+
+ if (ack != 0U) {
+ pm_ipi_irq_clear(primary_proc);
+ }
+}
+
+/**
+ * pm_pll_set_param() - Set PLL parameter
+ *
+ * This API is deprecated and maintained here for backward compatibility.
+ * New use of this API should be avoided for versal platform.
+ * This API and its use cases will be removed for versal platform.
+ *
+ * @clk_id PLL clock ID
+ * @param PLL parameter ID
+ * @value Value to set for PLL parameter
+ * @flag 0 - Call from secure source
+ * 1 - Call from non-secure source
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pll_set_param(uint32_t clk_id, uint32_t param,
+ uint32_t value, uint32_t flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag, PM_PLL_SET_PARAMETER,
+ clk_id, param, value);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_pll_get_param() - Get PLL parameter value
+ *
+ * This API is deprecated and maintained here for backward compatibility.
+ * New use of this API should be avoided for versal platform.
+ * This API and its use cases will be removed for versal platform.
+ *
+ * @clk_id PLL clock ID
+ * @param PLL parameter ID
+ * @value: Buffer to store PLL parameter value
+ * @flag 0 - Call from secure source
+ * 1 - Call from non-secure source
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pll_get_param(uint32_t clk_id, uint32_t param,
+ uint32_t *value, uint32_t flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_PLL_GET_PARAMETER,
+ clk_id, param);
+
+ return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+/**
+ * pm_pll_set_mode() - Set PLL mode
+ *
+ * This API is deprecated and maintained here for backward compatibility.
+ * New use of this API should be avoided for versal platform.
+ * This API and its use cases will be removed for versal platform.
+ *
+ * @clk_id PLL clock ID
+ * @mode PLL mode
+ * @flag 0 - Call from secure source
+ * 1 - Call from non-secure source
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pll_set_mode(uint32_t clk_id, uint32_t mode,
+ uint32_t flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_PLL_SET_MODE,
+ clk_id, mode);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_pll_get_mode() - Get PLL mode
+ *
+ * This API is deprecated and maintained here for backward compatibility.
+ * New use of this API should be avoided for versal platform.
+ * This API and its use cases will be removed for versal platform.
+ *
+ * @clk_id PLL clock ID
+ * @mode: Buffer to store PLL mode
+ * @flag 0 - Call from secure source
+ * 1 - Call from non-secure source
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pll_get_mode(uint32_t clk_id, uint32_t *mode,
+ uint32_t flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, PM_PLL_GET_MODE,
+ clk_id);
+
+ return pm_ipi_send_sync(primary_proc, payload, mode, 1);
+}
+
+/**
+ * pm_force_powerdown() - PM call to request for another PU or subsystem to
+ * be powered down forcefully
+ * @target Device ID of the PU node to be forced powered down.
+ * @ack Flag to specify whether acknowledge is requested
+ * @flag 0 - Call from secure source
+ * 1 - Call from non-secure source
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_force_powerdown(uint32_t target, uint8_t ack,
+ uint32_t flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_FORCE_POWERDOWN,
+ target, ack);
+
+ if (ack == IPI_BLOCKING) {
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+ } else {
+ 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
+ * @flag 0 - Call from secure source
+ * 1 - Call from non-secure source
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype,
+ uint32_t flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ if (type == XPM_SHUTDOWN_TYPE_SETSCOPE_ONLY) {
+ /* Setting scope for subsequent PSCI reboot or shutdown */
+ pm_shutdown_scope = subtype;
+ return PM_RET_SUCCESS;
+ }
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_SYSTEM_SHUTDOWN,
+ type, subtype);
+
+ return pm_ipi_send_non_blocking(primary_proc, payload);
+}
+
+/**
+ * pm_query_data() - PM API for querying firmware data
+ *
+ * This API is deprecated and maintained here for backward compatibility.
+ * New use of this API should be avoided for versal platform.
+ * This API and its use cases will be removed for versal platform.
+ *
+ * @qid The type of data to query
+ * @arg1 Argument 1 to requested query data call
+ * @arg2 Argument 2 to requested query data call
+ * @arg3 Argument 3 to requested query data call
+ * @data Returned output data
+ * @flag 0 - Call from secure source
+ * 1 - Call from non-secure source
+ *
+ * @retur - 0 if success else non-zero error code of type
+ * enum pm_ret_status
+ */
+enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t *data, uint32_t flag)
+{
+ uint32_t ret;
+ uint32_t version[PAYLOAD_ARG_CNT] = {0};
+ uint32_t payload[PAYLOAD_ARG_CNT];
+ uint32_t fw_api_version;
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_QUERY_DATA, qid,
+ arg1, arg2, arg3);
+
+ ret = pm_feature_check(PM_QUERY_DATA, &version[0], flag);
+ if (ret == PM_RET_SUCCESS) {
+ fw_api_version = version[0] & 0xFFFFU;
+ if ((fw_api_version == 2U) &&
+ ((qid == XPM_QID_CLOCK_GET_NAME) ||
+ (qid == XPM_QID_PINCTRL_GET_FUNCTION_NAME))) {
+ ret = pm_ipi_send_sync(primary_proc, payload, data, PAYLOAD_ARG_CNT);
+ if (ret == PM_RET_SUCCESS) {
+ ret = data[0];
+ data[0] = data[1];
+ data[1] = data[2];
+ data[2] = data[3];
+ }
+ } else {
+ ret = pm_ipi_send_sync(primary_proc, payload, data, PAYLOAD_ARG_CNT);
+ }
+ }
+ return ret;
+}
+/**
+ * pm_api_ioctl() - PM IOCTL API for device control and configs
+ *
+ * This API is deprecated and maintained here for backward compatibility.
+ * New use of this API should be avoided for versal platform.
+ * This API and its use cases will be removed for versal platform.
+ *
+ * @device_id Device ID
+ * @ioctl_id ID of the requested IOCTL
+ * @arg1 Argument 1 to requested IOCTL call
+ * @arg2 Argument 2 to requested IOCTL call
+ * @arg3 Argument 3 to requested IOCTL call
+ * @value Returned output value
+ * @flag 0 - Call from secure source
+ * 1 - Call from non-secure source
+ *
+ * This function calls IOCTL to firmware for device control and configuration.
+ *
+ * @return Returns status, either 0 on success or non-zero error code
+ * of type enum pm_ret_status
+ */
+enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id,
+ uint32_t arg1, uint32_t arg2, uint32_t arg3,
+ uint32_t *value, uint32_t flag)
+{
+ enum pm_ret_status ret;
+
+ switch (ioctl_id) {
+ case IOCTL_SET_PLL_FRAC_MODE:
+ ret = pm_pll_set_mode(arg1, arg2, flag);
+ break;
+ case IOCTL_GET_PLL_FRAC_MODE:
+ ret = pm_pll_get_mode(arg1, value, flag);
+ break;
+ case IOCTL_SET_PLL_FRAC_DATA:
+ ret = pm_pll_set_param(arg1, PM_PLL_PARAM_DATA, arg2, flag);
+ break;
+ case IOCTL_GET_PLL_FRAC_DATA:
+ ret = pm_pll_get_param(arg1, PM_PLL_PARAM_DATA, value, flag);
+ break;
+ case IOCTL_SET_SGI:
+ /* Get the sgi number */
+ ret = pm_register_sgi(arg1, arg2);
+ if (ret != 0) {
+ return PM_RET_ERROR_ARGS;
+ }
+ ret = PM_RET_SUCCESS;
+ break;
+ default:
+ return PM_RET_ERROR_NOTSUPPORTED;
+ }
+
+ return ret;
+}
+
+/**
+ * pm_set_wakeup_source() - PM call to specify the wakeup source while suspended
+ * @target Device id of the targeted PU or subsystem
+ * @wkup_node Device id of the wakeup peripheral
+ * @enable Enable or disable the specified peripheral as wake source
+ * @flag 0 - Call from secure source
+ * 1 - Call from non-secure source
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t wkup_device,
+ uint8_t enable, uint32_t flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag, PM_SET_WAKEUP_SOURCE,
+ target, wkup_device, enable);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_feature_check() - Returns the supported API version if supported
+ * @api_id API ID to check
+ * @flag 0 - Call from secure source
+ * 1 - Call from non-secure source
+ * @ret_payload pointer to array of PAYLOAD_ARG_CNT number of
+ * words Returned supported API version and bitmasks
+ * for IOCTL and QUERY ID
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *ret_payload,
+ uint32_t flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+ uint32_t module_id;
+
+ /* Return version of API which are implemented in ATF only */
+ switch (api_id) {
+ case PM_GET_CALLBACK_DATA:
+ case PM_GET_TRUSTZONE_VERSION:
+ ret_payload[0] = PM_API_VERSION_2;
+ return PM_RET_SUCCESS;
+ case TF_A_PM_REGISTER_SGI:
+ ret_payload[0] = PM_API_BASE_VERSION;
+ return PM_RET_SUCCESS;
+ default:
+ break;
+ }
+
+ module_id = (api_id & MODULE_ID_MASK) >> 8U;
+
+ /*
+ * feature check should be done only for LIBPM module
+ * If module_id is 0, then we consider it LIBPM module as default id
+ */
+ if ((module_id > 0) && (module_id != LIBPM_MODULE_ID)) {
+ return PM_RET_SUCCESS;
+ }
+
+ PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag,
+ PM_FEATURE_CHECK, api_id);
+ return pm_ipi_send_sync(primary_proc, payload, ret_payload, PAYLOAD_ARG_CNT);
+}
+
+/**
+ * pm_load_pdi() - Load the PDI
+ *
+ * This function provides support to load PDI from linux
+ *
+ * src: Source device of pdi(DDR, OCM, SD etc)
+ * address_low: lower 32-bit Linear memory space address
+ * address_high: higher 32-bit Linear memory space address
+ * @flag 0 - Call from secure source
+ * 1 - Call from non-secure source
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_load_pdi(uint32_t src, uint32_t address_low,
+ uint32_t address_high, uint32_t flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD4(payload, LOADER_MODULE_ID, flag, PM_LOAD_PDI, src,
+ address_high, address_low);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_register_notifier() - PM call to register a subsystem to be notified
+ * about the device event
+ * @device_id Device ID for the Node to which the event is related
+ * @event Event in question
+ * @wake Wake subsystem upon capturing the event if value 1
+ * @enable Enable the registration for value 1, disable for value 0
+ * @flag 0 - Call from secure source
+ * 1 - Call from non-secure source
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_register_notifier(uint32_t device_id, uint32_t event,
+ uint32_t wake, uint32_t enable,
+ uint32_t flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_REGISTER_NOTIFIER,
+ device_id, event, wake, enable);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.h b/plat/xilinx/versal/pm_service/pm_api_sys.h
new file mode 100644
index 0000000..c539aa7
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_api_sys.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PM_API_SYS_H
+#define PM_API_SYS_H
+
+#include <stdint.h>
+#include "pm_defs.h"
+
+/*********************************************************************
+ * Target module IDs macros
+ ********************************************************************/
+#define LIBPM_MODULE_ID 0x2U
+#define LOADER_MODULE_ID 0x7U
+
+#define MODULE_ID_MASK 0x0000ff00U
+/**********************************************************
+ * PM API function declarations
+ **********************************************************/
+
+enum pm_ret_status pm_handle_eemi_call(uint32_t flag, uint32_t x0, uint32_t x1,
+ uint32_t x2, uint32_t x3, uint32_t x4,
+ uint32_t x5, uint64_t *result);
+enum pm_ret_status pm_self_suspend(uint32_t nid,
+ uint32_t latency,
+ uint32_t state,
+ uintptr_t address, uint32_t flag);
+enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason, uint32_t flag);
+enum pm_ret_status pm_req_suspend(uint32_t target,
+ uint8_t ack,
+ uint32_t latency,
+ uint32_t state, uint32_t flag);
+enum pm_ret_status pm_req_wakeup(uint32_t target, uint32_t set_address,
+ uintptr_t address, uint8_t ack, uint32_t flag);
+enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t device_id,
+ uint8_t enable, uint32_t flag);
+void pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag,
+ uint32_t ack);
+enum pm_ret_status pm_pll_set_param(uint32_t clk_id, uint32_t param,
+ uint32_t value, uint32_t flag);
+enum pm_ret_status pm_pll_get_param(uint32_t clk_id, uint32_t param,
+ uint32_t *value, uint32_t flag);
+enum pm_ret_status pm_pll_set_mode(uint32_t clk_id, uint32_t mode,
+ uint32_t flag);
+enum pm_ret_status pm_pll_get_mode(uint32_t clk_id, uint32_t *mode,
+ uint32_t flag);
+enum pm_ret_status pm_force_powerdown(uint32_t target, uint8_t ack,
+ uint32_t flag);
+enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype,
+ uint32_t flag);
+enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id,
+ uint32_t arg1, uint32_t arg2, uint32_t arg3,
+ uint32_t *value, uint32_t flag);
+enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t *data, uint32_t flag);
+uint32_t pm_get_shutdown_scope(void);
+enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *ret_payload,
+ uint32_t flag);
+enum pm_ret_status pm_load_pdi(uint32_t src, uint32_t address_low,
+ uint32_t address_high, uint32_t flag);
+enum pm_ret_status pm_register_notifier(uint32_t device_id, uint32_t event,
+ uint32_t wake, uint32_t enable,
+ uint32_t flag);
+
+/**
+ * Assigning of argument values into array elements.
+ */
+#define PM_PACK_PAYLOAD1(pl, mid, flag, arg0) { \
+ pl[0] = (uint32_t)(((uint32_t)(arg0) & 0xFFU) | ((mid) << 8U) | ((flag) << 24U)); \
+}
+
+#define PM_PACK_PAYLOAD2(pl, mid, flag, arg0, arg1) { \
+ pl[1] = (uint32_t)(arg1); \
+ PM_PACK_PAYLOAD1(pl, (mid), (flag), (arg0)); \
+}
+
+#define PM_PACK_PAYLOAD3(pl, mid, flag, arg0, arg1, arg2) { \
+ pl[2] = (uint32_t)(arg2); \
+ PM_PACK_PAYLOAD2(pl, (mid), (flag), (arg0), (arg1)); \
+}
+
+#define PM_PACK_PAYLOAD4(pl, mid, flag, arg0, arg1, arg2, arg3) { \
+ pl[3] = (uint32_t)(arg3); \
+ PM_PACK_PAYLOAD3(pl, (mid), (flag), (arg0), (arg1), (arg2)); \
+}
+
+#define PM_PACK_PAYLOAD5(pl, mid, flag, arg0, arg1, arg2, arg3, arg4) { \
+ pl[4] = (uint32_t)(arg4); \
+ PM_PACK_PAYLOAD4(pl, (mid), (flag), (arg0), (arg1), (arg2), (arg3)); \
+}
+
+#define PM_PACK_PAYLOAD6(pl, mid, flag, arg0, arg1, arg2, arg3, arg4, arg5) { \
+ pl[5] = (uint32_t)(arg5); \
+ PM_PACK_PAYLOAD5(pl, (mid), (flag), (arg0), (arg1), (arg2), (arg3), (arg4)); \
+}
+
+#endif /* PM_API_SYS_H */
diff --git a/plat/xilinx/versal/pm_service/pm_client.c b/plat/xilinx/versal/pm_service/pm_client.c
new file mode 100644
index 0000000..ce5e533
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_client.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. 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 <assert.h>
+#include <plat_ipi.h>
+#include <platform_def.h>
+#include <versal_def.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/arm/gic_common.h>
+#include <plat/common/platform.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_defs.h"
+
+#define UNDEFINED_CPUID (~0)
+#define IRQ_MAX 142U
+#define NUM_GICD_ISENABLER ((IRQ_MAX >> 5U) + 1U)
+
+DEFINE_BAKERY_LOCK(pm_client_secure_lock);
+
+static const struct pm_ipi apu_ipi = {
+ .local_ipi_id = IPI_ID_APU,
+ .remote_ipi_id = IPI_ID_PMC,
+ .buffer_base = IPI_BUFFER_APU_BASE,
+};
+
+/* Order in pm_procs_all array must match cpu ids */
+static const struct pm_proc pm_procs_all[] = {
+ {
+ .node_id = XPM_DEVID_ACPU_0,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK,
+ },
+ {
+ .node_id = XPM_DEVID_ACPU_1,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK,
+ }
+};
+
+const struct pm_proc *primary_proc = &pm_procs_all[0];
+
+/* Interrupt to PM node index map */
+static enum pm_device_node_idx irq_node_map[IRQ_MAX + 1] = {
+ [13] = XPM_NODEIDX_DEV_GPIO,
+ [14] = XPM_NODEIDX_DEV_I2C_0,
+ [15] = XPM_NODEIDX_DEV_I2C_1,
+ [16] = XPM_NODEIDX_DEV_SPI_0,
+ [17] = XPM_NODEIDX_DEV_SPI_1,
+ [18] = XPM_NODEIDX_DEV_UART_0,
+ [19] = XPM_NODEIDX_DEV_UART_1,
+ [20] = XPM_NODEIDX_DEV_CAN_FD_0,
+ [21] = XPM_NODEIDX_DEV_CAN_FD_1,
+ [22] = XPM_NODEIDX_DEV_USB_0,
+ [23] = XPM_NODEIDX_DEV_USB_0,
+ [24] = XPM_NODEIDX_DEV_USB_0,
+ [25] = XPM_NODEIDX_DEV_USB_0,
+ [26] = XPM_NODEIDX_DEV_USB_0,
+ [37] = XPM_NODEIDX_DEV_TTC_0,
+ [38] = XPM_NODEIDX_DEV_TTC_0,
+ [39] = XPM_NODEIDX_DEV_TTC_0,
+ [40] = XPM_NODEIDX_DEV_TTC_1,
+ [41] = XPM_NODEIDX_DEV_TTC_1,
+ [42] = XPM_NODEIDX_DEV_TTC_1,
+ [43] = XPM_NODEIDX_DEV_TTC_2,
+ [44] = XPM_NODEIDX_DEV_TTC_2,
+ [45] = XPM_NODEIDX_DEV_TTC_2,
+ [46] = XPM_NODEIDX_DEV_TTC_3,
+ [47] = XPM_NODEIDX_DEV_TTC_3,
+ [48] = XPM_NODEIDX_DEV_TTC_3,
+ [56] = XPM_NODEIDX_DEV_GEM_0,
+ [57] = XPM_NODEIDX_DEV_GEM_0,
+ [58] = XPM_NODEIDX_DEV_GEM_1,
+ [59] = XPM_NODEIDX_DEV_GEM_1,
+ [60] = XPM_NODEIDX_DEV_ADMA_0,
+ [61] = XPM_NODEIDX_DEV_ADMA_1,
+ [62] = XPM_NODEIDX_DEV_ADMA_2,
+ [63] = XPM_NODEIDX_DEV_ADMA_3,
+ [64] = XPM_NODEIDX_DEV_ADMA_4,
+ [65] = XPM_NODEIDX_DEV_ADMA_5,
+ [66] = XPM_NODEIDX_DEV_ADMA_6,
+ [67] = XPM_NODEIDX_DEV_ADMA_7,
+ [74] = XPM_NODEIDX_DEV_USB_0,
+ [126] = XPM_NODEIDX_DEV_SDIO_0,
+ [127] = XPM_NODEIDX_DEV_SDIO_0,
+ [128] = XPM_NODEIDX_DEV_SDIO_1,
+ [129] = XPM_NODEIDX_DEV_SDIO_1,
+ [142] = XPM_NODEIDX_DEV_RTC,
+};
+
+/**
+ * irq_to_pm_node_idx - Get PM node index corresponding to the interrupt number
+ * @irq: Interrupt number
+ *
+ * Return: PM node index corresponding to the specified interrupt
+ */
+static enum pm_device_node_idx irq_to_pm_node_idx(uint32_t irq)
+{
+ assert(irq <= IRQ_MAX);
+ return irq_node_map[irq];
+}
+
+/**
+ * pm_client_set_wakeup_sources - Set all devices with enabled interrupts as
+ * wake sources in the LibPM.
+ * @node_id: Node id of processor
+ */
+static void pm_client_set_wakeup_sources(uint32_t node_id)
+{
+ uint32_t reg_num;
+ uint32_t device_id;
+ uint8_t pm_wakeup_nodes_set[XPM_NODEIDX_DEV_MAX];
+ uintptr_t isenabler1 = PLAT_VERSAL_GICD_BASE + GICD_ISENABLER + 4;
+
+ zeromem(&pm_wakeup_nodes_set, (u_register_t)sizeof(pm_wakeup_nodes_set));
+
+ for (reg_num = 0U; 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 == 0U) {
+ continue;
+ }
+
+ while (reg != 0U) {
+ enum pm_device_node_idx node_idx;
+ uint32_t idx, irq, lowest_set = reg & (-reg);
+ enum pm_ret_status ret;
+
+ idx = __builtin_ctz(lowest_set);
+ irq = base_irq + idx;
+
+ if (irq > IRQ_MAX) {
+ break;
+ }
+
+ node_idx = irq_to_pm_node_idx(irq);
+ reg &= ~lowest_set;
+
+ if (node_idx > XPM_NODEIDX_DEV_MIN && node_idx < XPM_NODEIDX_DEV_MAX) {
+ if (pm_wakeup_nodes_set[node_idx] == 0U) {
+ /* Get device ID from node index */
+ device_id = PERIPH_DEVID(node_idx);
+ ret = pm_set_wakeup_source(node_id,
+ device_id, 1,
+ SECURE_FLAG);
+ pm_wakeup_nodes_set[node_idx] = (ret == PM_RET_SUCCESS) ?
+ 1 : 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, uint32_t state)
+{
+ bakery_lock_get(&pm_client_secure_lock);
+
+ if (state == PM_STATE_SUSPEND_TO_RAM) {
+ pm_client_set_wakeup_sources((uint32_t)proc->node_id);
+ }
+
+ /* Set powerdown request */
+ mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) |
+ (uint32_t)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) */
+ gicv3_cpuif_enable(plat_my_core_pos());
+
+ bakery_lock_get(&pm_client_secure_lock);
+
+ /* Clear powerdown request */
+ mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) &
+ ~((uint32_t)primary_proc->pwrdn_mask));
+
+ bakery_lock_release(&pm_client_secure_lock);
+}
+
+/**
+ * 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 uint32_t pm_get_cpuid(uint32_t nid)
+{
+ for (size_t i = 0U; i < ARRAY_SIZE(pm_procs_all); i++) {
+ if (pm_procs_all[i].node_id == nid) {
+ return i;
+ }
+ }
+ return UNDEFINED_CPUID;
+}
+
+/**
+ * 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)
+{
+ uint32_t 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(FPD_APU_PWRCTL);
+ val &= ~(proc->pwrdn_mask);
+ mmio_write_32(FPD_APU_PWRCTL, val);
+
+ bakery_lock_release(&pm_client_secure_lock);
+}
+
+/**
+ * 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(uint32_t cpuid)
+{
+ if (cpuid < ARRAY_SIZE(pm_procs_all)) {
+ return &pm_procs_all[cpuid];
+ }
+
+ return NULL;
+}
diff --git a/plat/xilinx/versal/pm_service/pm_defs.h b/plat/xilinx/versal/pm_service/pm_defs.h
new file mode 100644
index 0000000..2922b5d
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_defs.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Versal power management enums and defines */
+
+#ifndef PM_DEFS_H
+#define PM_DEFS_H
+
+#include "pm_node.h"
+
+/*********************************************************************
+ * Macro definitions
+ ********************************************************************/
+
+/* State arguments of the self suspend */
+#define PM_STATE_CPU_IDLE 0x0U
+#define PM_STATE_SUSPEND_TO_RAM 0xFU
+
+#define MAX_LATENCY (~0U)
+#define MAX_QOS 100U
+
+/* Processor core device IDs */
+#define APU_DEVID(IDX) NODEID(XPM_NODECLASS_DEVICE, XPM_NODESUBCL_DEV_CORE, \
+ XPM_NODETYPE_DEV_CORE_APU, (IDX))
+
+#define XPM_DEVID_ACPU_0 APU_DEVID(XPM_NODEIDX_DEV_ACPU_0)
+#define XPM_DEVID_ACPU_1 APU_DEVID(XPM_NODEIDX_DEV_ACPU_1)
+
+#define PERIPH_DEVID(IDX) NODEID(XPM_NODECLASS_DEVICE, \
+ XPM_NODESUBCL_DEV_PERIPH, \
+ XPM_NODETYPE_DEV_PERIPH, (IDX))
+
+#define PM_GET_CALLBACK_DATA 0xa01U
+#define PM_GET_TRUSTZONE_VERSION 0xa03U
+#define TF_A_PM_REGISTER_SGI 0xa04U
+
+/* PM API Versions */
+#define PM_API_BASE_VERSION 1U
+#define PM_API_VERSION_2 2U
+
+/* PM API ids */
+#define PM_REGISTER_NOTIFIER 5U
+#define PM_REQ_SUSPEND 6U
+#define PM_SELF_SUSPEND 7U
+#define PM_FORCE_POWERDOWN 8U
+#define PM_ABORT_SUSPEND 9U
+#define PM_REQ_WAKEUP 10U
+#define PM_SET_WAKEUP_SOURCE 11U
+#define PM_SYSTEM_SHUTDOWN 12U
+#define PM_IOCTL 34U
+#define PM_QUERY_DATA 35U
+#define PM_PLL_SET_PARAMETER 48U
+#define PM_PLL_GET_PARAMETER 49U
+#define PM_PLL_SET_MODE 50U
+#define PM_PLL_GET_MODE 51U
+#define PM_FEATURE_CHECK 63U
+
+/* Loader API ids */
+#define PM_LOAD_PDI 0x701U
+#define PM_LOAD_GET_HANDOFF_PARAMS 0x70BU
+
+/* IOCTL IDs for clock driver */
+#define IOCTL_SET_PLL_FRAC_MODE 8U
+#define IOCTL_GET_PLL_FRAC_MODE 9U
+#define IOCTL_SET_PLL_FRAC_DATA 10U
+#define IOCTL_GET_PLL_FRAC_DATA 11U
+#define IOCTL_SET_SGI 25U
+
+/* Parameter ID for PLL IOCTLs */
+/* Fractional data portion for PLL */
+#define PM_PLL_PARAM_DATA 2
+
+/* System shutdown macros */
+#define XPM_SHUTDOWN_TYPE_SHUTDOWN 0U
+#define XPM_SHUTDOWN_TYPE_RESET 1U
+#define XPM_SHUTDOWN_TYPE_SETSCOPE_ONLY 2U
+
+#define XPM_SHUTDOWN_SUBTYPE_RST_SUBSYSTEM 0U
+#define XPM_SHUTDOWN_SUBTYPE_RST_PS_ONLY 1U
+#define XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM 2U
+
+/*********************************************************************
+ * Enum definitions
+ ********************************************************************/
+
+enum pm_abort_reason {
+ ABORT_REASON_WKUP_EVENT = 100,
+ ABORT_REASON_PU_BUSY,
+ ABORT_REASON_NO_PWRDN,
+ ABORT_REASON_UNKNOWN,
+};
+
+enum pm_opchar_type {
+ PM_OPCHAR_TYPE_POWER = 1,
+ PM_OPCHAR_TYPE_TEMP,
+ PM_OPCHAR_TYPE_LATENCY,
+};
+
+/**
+ * Subsystem IDs
+ */
+typedef enum {
+ XPM_SUBSYSID_PMC,
+ XPM_SUBSYSID_PSM,
+ XPM_SUBSYSID_APU,
+ XPM_SUBSYSID_RPU0_LOCK,
+ XPM_SUBSYSID_RPU0_0,
+ XPM_SUBSYSID_RPU0_1,
+ XPM_SUBSYSID_DDR0,
+ XPM_SUBSYSID_ME,
+ XPM_SUBSYSID_PL,
+ XPM_SUBSYSID_MAX,
+} XPm_SubsystemId;
+
+/**
+ * @PM_RET_SUCCESS: success
+ * @PM_RET_ERROR_ARGS: illegal arguments provided (deprecated)
+ * @PM_RET_ERROR_NOTSUPPORTED: feature not supported (deprecated)
+ * @PM_RET_ERROR_NOFEATURE: feature is not available
+ * @PM_RET_ERROR_INTERNAL: internal error
+ * @PM_RET_ERROR_CONFLICT: conflict
+ * @PM_RET_ERROR_ACCESS: access rights violation
+ * @PM_RET_ERROR_INVALID_NODE: invalid node
+ * @PM_RET_ERROR_DOUBLE_REQ: duplicate request for same node
+ * @PM_RET_ERROR_ABORT_SUSPEND: suspend procedure has been aborted
+ * @PM_RET_ERROR_TIMEOUT: timeout in communication with PMU
+ * @PM_RET_ERROR_NODE_USED: node is already in use
+ */
+enum pm_ret_status {
+ PM_RET_SUCCESS,
+ PM_RET_ERROR_ARGS = 1,
+ PM_RET_ERROR_NOTSUPPORTED = 4,
+ PM_RET_ERROR_NOFEATURE = 19,
+ PM_RET_ERROR_INTERNAL = 2000,
+ PM_RET_ERROR_CONFLICT = 2001,
+ PM_RET_ERROR_ACCESS = 2002,
+ PM_RET_ERROR_INVALID_NODE = 2003,
+ PM_RET_ERROR_DOUBLE_REQ = 2004,
+ PM_RET_ERROR_ABORT_SUSPEND = 2005,
+ PM_RET_ERROR_TIMEOUT = 2006,
+ PM_RET_ERROR_NODE_USED = 2007
+};
+
+/**
+ * Qids
+ */
+enum pm_query_id {
+ XPM_QID_INVALID,
+ XPM_QID_CLOCK_GET_NAME,
+ XPM_QID_CLOCK_GET_TOPOLOGY,
+ XPM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS,
+ XPM_QID_CLOCK_GET_MUXSOURCES,
+ XPM_QID_CLOCK_GET_ATTRIBUTES,
+ XPM_QID_PINCTRL_GET_NUM_PINS,
+ XPM_QID_PINCTRL_GET_NUM_FUNCTIONS,
+ XPM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS,
+ XPM_QID_PINCTRL_GET_FUNCTION_NAME,
+ XPM_QID_PINCTRL_GET_FUNCTION_GROUPS,
+ XPM_QID_PINCTRL_GET_PIN_GROUPS,
+ XPM_QID_CLOCK_GET_NUM_CLOCKS,
+ XPM_QID_CLOCK_GET_MAX_DIVISOR,
+ XPM_QID_PLD_GET_PARENT,
+};
+#endif /* PM_DEFS_H */
diff --git a/plat/xilinx/versal/pm_service/pm_node.h b/plat/xilinx/versal/pm_service/pm_node.h
new file mode 100644
index 0000000..1b82ec7
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_node.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Versal PM nodes enums and defines */
+
+#ifndef PM_NODE_H
+#define PM_NODE_H
+
+/*********************************************************************
+ * Macro definitions
+ ********************************************************************/
+
+#define NODE_CLASS_SHIFT 26U
+#define NODE_SUBCLASS_SHIFT 20U
+#define NODE_TYPE_SHIFT 14U
+#define NODE_INDEX_SHIFT 0U
+#define NODE_CLASS_MASK_BITS 0x3F
+#define NODE_SUBCLASS_MASK_BITS 0x3F
+#define NODE_TYPE_MASK_BITS 0x3F
+#define NODE_INDEX_MASK_BITS 0x3FFF
+#define NODE_CLASS_MASK (NODE_CLASS_MASK_BITS << NODE_CLASS_SHIFT)
+#define NODE_SUBCLASS_MASK (NODE_SUBCLASS_MASK_BITS << NODE_SUBCLASS_SHIFT)
+#define NODE_TYPE_MASK (NODE_TYPE_MASK_BITS << NODE_TYPE_SHIFT)
+#define NODE_INDEX_MASK (NODE_INDEX_MASK_BITS << NODE_INDEX_SHIFT)
+
+#define NODEID(CLASS, SUBCLASS, TYPE, INDEX) \
+ ((((CLASS) & NODE_CLASS_MASK_BITS) << NODE_CLASS_SHIFT) | \
+ (((SUBCLASS) & NODE_SUBCLASS_MASK_BITS) << NODE_SUBCLASS_SHIFT) | \
+ (((TYPE) & NODE_TYPE_MASK_BITS) << NODE_TYPE_SHIFT) | \
+ (((INDEX) & NODE_INDEX_MASK_BITS) << NODE_INDEX_SHIFT))
+
+#define NODECLASS(ID) (((ID) & NODE_CLASS_MASK) >> NODE_CLASS_SHIFT)
+#define NODESUBCLASS(ID) (((ID) & NODE_SUBCLASS_MASK) >> \
+ NODE_SUBCLASS_SHIFT)
+#define NODETYPE(ID) (((ID) & NODE_TYPE_MASK) >> NODE_TYPE_SHIFT)
+#define NODEINDEX(ID) (((ID) & NODE_INDEX_MASK) >> NODE_INDEX_SHIFT)
+
+/*********************************************************************
+ * Enum definitions
+ ********************************************************************/
+
+/* Node class types */
+enum pm_node_class {
+ XPM_NODECLASS_MIN,
+
+ XPM_NODECLASS_POWER,
+ XPM_NODECLASS_CLOCK,
+ XPM_NODECLASS_RESET,
+ XPM_NODECLASS_MEMIC,
+ XPM_NODECLASS_STMIC,
+ XPM_NODECLASS_DEVICE,
+
+ XPM_NODECLASS_MAX
+};
+
+enum pm_device_node_subclass {
+ /* Device types */
+ XPM_NODESUBCL_DEV_CORE = 1,
+ XPM_NODESUBCL_DEV_PERIPH,
+ XPM_NODESUBCL_DEV_MEM,
+ XPM_NODESUBCL_DEV_SOC,
+ XPM_NODESUBCL_DEV_MEM_CTRLR,
+ XPM_NODESUBCL_DEV_PHY,
+};
+
+enum pm_device_node_type {
+ /* Device types */
+ XPM_NODETYPE_DEV_CORE_PMC = 1,
+ XPM_NODETYPE_DEV_CORE_PSM,
+ XPM_NODETYPE_DEV_CORE_APU,
+ XPM_NODETYPE_DEV_CORE_RPU,
+ XPM_NODETYPE_DEV_OCM,
+ XPM_NODETYPE_DEV_TCM,
+ XPM_NODETYPE_DEV_L2CACHE,
+ XPM_NODETYPE_DEV_DDR,
+ XPM_NODETYPE_DEV_PERIPH,
+ XPM_NODETYPE_DEV_SOC,
+ XPM_NODETYPE_DEV_GT,
+};
+
+/* Device node Indexes */
+enum pm_device_node_idx {
+ /* Device nodes */
+ XPM_NODEIDX_DEV_MIN,
+
+ /* Processor devices */
+ XPM_NODEIDX_DEV_PMC_PROC,
+ XPM_NODEIDX_DEV_PSM_PROC,
+ XPM_NODEIDX_DEV_ACPU_0,
+ XPM_NODEIDX_DEV_ACPU_1,
+ XPM_NODEIDX_DEV_RPU0_0,
+ XPM_NODEIDX_DEV_RPU0_1,
+
+ /* Memory devices */
+ XPM_NODEIDX_DEV_OCM_0,
+ XPM_NODEIDX_DEV_OCM_1,
+ XPM_NODEIDX_DEV_OCM_2,
+ XPM_NODEIDX_DEV_OCM_3,
+ XPM_NODEIDX_DEV_TCM_0_A,
+ XPM_NODEIDX_DEV_TCM_0_B,
+ XPM_NODEIDX_DEV_TCM_1_A,
+ XPM_NODEIDX_DEV_TCM_1_B,
+ XPM_NODEIDX_DEV_L2_BANK_0,
+ XPM_NODEIDX_DEV_DDR_0,
+ XPM_NODEIDX_DEV_DDR_1,
+ XPM_NODEIDX_DEV_DDR_2,
+ XPM_NODEIDX_DEV_DDR_3,
+ XPM_NODEIDX_DEV_DDR_4,
+ XPM_NODEIDX_DEV_DDR_5,
+ XPM_NODEIDX_DEV_DDR_6,
+ XPM_NODEIDX_DEV_DDR_7,
+
+ /* LPD Peripheral devices */
+ XPM_NODEIDX_DEV_USB_0,
+ XPM_NODEIDX_DEV_GEM_0,
+ XPM_NODEIDX_DEV_GEM_1,
+ XPM_NODEIDX_DEV_SPI_0,
+ XPM_NODEIDX_DEV_SPI_1,
+ XPM_NODEIDX_DEV_I2C_0,
+ XPM_NODEIDX_DEV_I2C_1,
+ XPM_NODEIDX_DEV_CAN_FD_0,
+ XPM_NODEIDX_DEV_CAN_FD_1,
+ XPM_NODEIDX_DEV_UART_0,
+ XPM_NODEIDX_DEV_UART_1,
+ XPM_NODEIDX_DEV_GPIO,
+ XPM_NODEIDX_DEV_TTC_0,
+ XPM_NODEIDX_DEV_TTC_1,
+ XPM_NODEIDX_DEV_TTC_2,
+ XPM_NODEIDX_DEV_TTC_3,
+ XPM_NODEIDX_DEV_SWDT_LPD,
+
+ /* FPD Peripheral devices */
+ XPM_NODEIDX_DEV_SWDT_FPD,
+
+ /* PMC Peripheral devices */
+ XPM_NODEIDX_DEV_OSPI,
+ XPM_NODEIDX_DEV_QSPI,
+ XPM_NODEIDX_DEV_GPIO_PMC,
+ XPM_NODEIDX_DEV_I2C_PMC,
+ XPM_NODEIDX_DEV_SDIO_0,
+ XPM_NODEIDX_DEV_SDIO_1,
+
+ XPM_NODEIDX_DEV_PL_0,
+ XPM_NODEIDX_DEV_PL_1,
+ XPM_NODEIDX_DEV_PL_2,
+ XPM_NODEIDX_DEV_PL_3,
+ XPM_NODEIDX_DEV_RTC,
+ XPM_NODEIDX_DEV_ADMA_0,
+ XPM_NODEIDX_DEV_ADMA_1,
+ XPM_NODEIDX_DEV_ADMA_2,
+ XPM_NODEIDX_DEV_ADMA_3,
+ XPM_NODEIDX_DEV_ADMA_4,
+ XPM_NODEIDX_DEV_ADMA_5,
+ XPM_NODEIDX_DEV_ADMA_6,
+ XPM_NODEIDX_DEV_ADMA_7,
+ XPM_NODEIDX_DEV_IPI_0,
+ XPM_NODEIDX_DEV_IPI_1,
+ XPM_NODEIDX_DEV_IPI_2,
+ XPM_NODEIDX_DEV_IPI_3,
+ XPM_NODEIDX_DEV_IPI_4,
+ XPM_NODEIDX_DEV_IPI_5,
+ XPM_NODEIDX_DEV_IPI_6,
+
+ /* Entire SoC */
+ XPM_NODEIDX_DEV_SOC,
+
+ /* DDR memory controllers */
+ XPM_NODEIDX_DEV_DDRMC_0,
+ XPM_NODEIDX_DEV_DDRMC_1,
+ XPM_NODEIDX_DEV_DDRMC_2,
+ XPM_NODEIDX_DEV_DDRMC_3,
+
+ /* GT devices */
+ XPM_NODEIDX_DEV_GT_0,
+ XPM_NODEIDX_DEV_GT_1,
+ XPM_NODEIDX_DEV_GT_2,
+ XPM_NODEIDX_DEV_GT_3,
+ XPM_NODEIDX_DEV_GT_4,
+ XPM_NODEIDX_DEV_GT_5,
+ XPM_NODEIDX_DEV_GT_6,
+ XPM_NODEIDX_DEV_GT_7,
+ XPM_NODEIDX_DEV_GT_8,
+ XPM_NODEIDX_DEV_GT_9,
+ XPM_NODEIDX_DEV_GT_10,
+
+ XPM_NODEIDX_DEV_MAX
+};
+
+#endif /* PM_NODE_H */
diff --git a/plat/xilinx/versal/pm_service/pm_svc_main.c b/plat/xilinx/versal/pm_service/pm_svc_main.c
new file mode 100644
index 0000000..9eb426a
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_svc_main.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Top-level SMC handler for Versal power management calls and
+ * IPI setup functions for communication with PMC.
+ */
+
+#include <errno.h>
+#include <plat_private.h>
+#include <stdbool.h>
+#include <common/runtime_svc.h>
+#include <plat/common/platform.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_ipi.h"
+#include <drivers/arm/gicv3.h>
+#include "../drivers/arm/gic/v3/gicv3_private.h"
+
+#define MODE 0x80000000U
+
+#define XSCUGIC_SGIR_EL1_INITID_SHIFT 24U
+#define INVALID_SGI 0xFFU
+#define PM_INIT_SUSPEND_CB (30U)
+#define PM_NOTIFY_CB (32U)
+DEFINE_RENAME_SYSREG_RW_FUNCS(icc_asgi1r_el1, S3_0_C12_C11_6)
+
+/* pm_up = true - UP, pm_up = false - DOWN */
+static bool pm_up;
+static uint32_t sgi = (uint32_t)INVALID_SGI;
+
+static void notify_os(void)
+{
+ int32_t cpu;
+ uint32_t reg;
+
+ cpu = plat_my_core_pos() + 1U;
+
+ reg = (cpu | (sgi << XSCUGIC_SGIR_EL1_INITID_SHIFT));
+ write_icc_asgi1r_el1(reg);
+}
+
+static uint64_t ipi_fiq_handler(uint32_t id, uint32_t flags, void *handle,
+ void *cookie)
+{
+ uint32_t payload[4] = {0};
+
+ VERBOSE("Received IPI FIQ from firmware\n");
+
+ (void)plat_ic_acknowledge_interrupt();
+
+ pm_get_callbackdata(payload, ARRAY_SIZE(payload), 0, 0);
+ switch (payload[0]) {
+ case PM_INIT_SUSPEND_CB:
+ case PM_NOTIFY_CB:
+ if (sgi != INVALID_SGI) {
+ notify_os();
+ }
+ break;
+ default:
+ pm_ipi_irq_clear(primary_proc);
+ WARN("Invalid IPI payload\n");
+ break;
+ }
+
+ /* Clear FIQ */
+ plat_ic_end_of_interrupt(id);
+
+ return 0;
+}
+
+/**
+ * pm_register_sgi() - PM register the IPI interrupt
+ *
+ * @sgi - SGI number to be used for communication.
+ * @reset - Reset to invalid SGI when reset=1.
+ * @return On success, the initialization function must return 0.
+ * Any other return value will cause the framework to ignore
+ * the service
+ *
+ * Update the SGI number to be used.
+ *
+ */
+int32_t pm_register_sgi(uint32_t sgi_num, uint32_t reset)
+{
+ if (reset == 1U) {
+ sgi = INVALID_SGI;
+ return 0;
+ }
+
+ if (sgi != INVALID_SGI) {
+ return -EBUSY;
+ }
+
+ if (sgi_num >= GICV3_MAX_SGI_TARGETS) {
+ return -EINVAL;
+ }
+
+ sgi = (uint32_t)sgi_num;
+ return 0;
+}
+
+/**
+ * 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 Versal power management for
+ * communicaton with PMC.
+ *
+ * Called from sip_svc_setup initialization function with the
+ * rt_svc_init signature.
+ */
+int32_t pm_setup(void)
+{
+ int32_t ret = 0;
+
+ pm_ipi_init(primary_proc);
+ pm_up = true;
+
+ /*
+ * 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);
+
+ ret = request_intr_type_el3(PLAT_VERSAL_IPI_IRQ, ipi_fiq_handler);
+ if (ret != 0) {
+ WARN("BL31: registering IPI interrupt failed\n");
+ }
+
+ gicd_write_irouter(gicv3_driver_data->gicd_base, PLAT_VERSAL_IPI_IRQ, MODE);
+ return ret;
+}
+
+/**
+ * eemi_for_compatibility() - EEMI calls handler for deprecated calls
+ *
+ * @return - If EEMI API found then, uintptr_t type address, else 0
+ *
+ * Some EEMI API's use case needs to be changed in Linux driver, so they
+ * can take advantage of common EEMI handler in TF-A. As of now the old
+ * implementation of these APIs are required to maintain backward compatibility
+ * until their use case in linux driver changes.
+ */
+static uintptr_t eemi_for_compatibility(uint32_t api_id, uint32_t *pm_arg,
+ void *handle, uint32_t security_flag)
+{
+ enum pm_ret_status ret;
+
+ switch (api_id) {
+
+ case PM_IOCTL:
+ {
+ uint32_t value;
+
+ ret = pm_api_ioctl(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3], pm_arg[4],
+ &value, security_flag);
+ if (ret == PM_RET_ERROR_NOTSUPPORTED)
+ return (uintptr_t)0;
+
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U);
+ }
+
+ case PM_QUERY_DATA:
+ {
+ uint32_t data[PAYLOAD_ARG_CNT] = { 0 };
+
+ ret = pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3], data, security_flag);
+
+ SMC_RET2(handle, (uint64_t)ret | ((uint64_t)data[0] << 32U),
+ (uint64_t)data[1] | ((uint64_t)data[2] << 32U));
+ }
+
+ case PM_FEATURE_CHECK:
+ {
+ uint32_t result[PAYLOAD_ARG_CNT] = {0U};
+
+ ret = pm_feature_check(pm_arg[0], result, security_flag);
+ SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U),
+ (uint64_t)result[1] | ((uint64_t)result[2] << 32U));
+ }
+
+ case PM_LOAD_PDI:
+ {
+ ret = pm_load_pdi(pm_arg[0], pm_arg[1], pm_arg[2],
+ security_flag);
+ SMC_RET1(handle, (uint64_t)ret);
+ }
+
+ default:
+ return (uintptr_t)0;
+ }
+}
+
+/**
+ * eemi_psci_debugfs_handler() - EEMI API invoked from PSCI
+ *
+ * These EEMI APIs performs CPU specific power management tasks.
+ * These EEMI APIs are invoked either from PSCI or from debugfs in kernel.
+ * These calls require CPU specific processing before sending IPI request to
+ * Platform Management Controller. For example enable/disable CPU specific
+ * interrupts. This requires separate handler for these calls and may not be
+ * handled using common eemi handler
+ */
+static uintptr_t eemi_psci_debugfs_handler(uint32_t api_id, uint32_t *pm_arg,
+ void *handle, uint32_t security_flag)
+{
+ enum pm_ret_status ret;
+
+ switch (api_id) {
+
+ case PM_SELF_SUSPEND:
+ ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3], security_flag);
+ SMC_RET1(handle, (u_register_t)ret);
+
+ case PM_FORCE_POWERDOWN:
+ ret = pm_force_powerdown(pm_arg[0], pm_arg[1], security_flag);
+ SMC_RET1(handle, (u_register_t)ret);
+
+ case PM_REQ_SUSPEND:
+ ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3], security_flag);
+ SMC_RET1(handle, (u_register_t)ret);
+
+ case PM_ABORT_SUSPEND:
+ ret = pm_abort_suspend(pm_arg[0], security_flag);
+ SMC_RET1(handle, (u_register_t)ret);
+
+ case PM_SYSTEM_SHUTDOWN:
+ ret = pm_system_shutdown(pm_arg[0], pm_arg[1], security_flag);
+ SMC_RET1(handle, (u_register_t)ret);
+
+ default:
+ return (uintptr_t)0;
+ }
+}
+
+/**
+ * TF_A_specific_handler() - SMC handler for TF-A specific functionality
+ *
+ * These EEMI calls performs functionality that does not require
+ * IPI transaction. The handler ends in TF-A and returns requested data to
+ * kernel from TF-A.
+ */
+static uintptr_t TF_A_specific_handler(uint32_t api_id, uint32_t *pm_arg,
+ void *handle, uint32_t security_flag)
+{
+ switch (api_id) {
+
+ case TF_A_PM_REGISTER_SGI:
+ {
+ int32_t ret;
+
+ ret = pm_register_sgi(pm_arg[0], pm_arg[1]);
+ if (ret != 0) {
+ SMC_RET1(handle, (uint32_t)PM_RET_ERROR_ARGS);
+ }
+
+ SMC_RET1(handle, (uint32_t)PM_RET_SUCCESS);
+ }
+
+ case PM_GET_CALLBACK_DATA:
+ {
+ uint32_t result[4] = {0};
+
+ pm_get_callbackdata(result, ARRAY_SIZE(result), security_flag, 1U);
+ SMC_RET2(handle,
+ (uint64_t)result[0] | ((uint64_t)result[1] << 32U),
+ (uint64_t)result[2] | ((uint64_t)result[3] << 32U));
+ }
+
+ case PM_GET_TRUSTZONE_VERSION:
+ SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
+ ((uint64_t)TZ_VERSION << 32U));
+
+ default:
+ return (uintptr_t)0;
+ }
+}
+
+/**
+ * eemi_handler() - Prepare EEMI payload and perform IPI transaction
+ *
+ * EEMI - Embedded Energy Management Interface is Xilinx proprietary protocol
+ * to allow communication between power management controller and different
+ * processing clusters.
+ *
+ * This handler prepares EEMI protocol payload received from kernel and performs
+ * IPI transaction.
+ */
+static uintptr_t eemi_handler(uint32_t api_id, uint32_t *pm_arg,
+ void *handle, uint32_t security_flag)
+{
+ enum pm_ret_status ret;
+ uint32_t buf[PAYLOAD_ARG_CNT] = {0};
+
+ ret = pm_handle_eemi_call(security_flag, api_id, pm_arg[0], pm_arg[1],
+ pm_arg[2], pm_arg[3], pm_arg[4],
+ (uint64_t *)buf);
+ /*
+ * Two IOCTLs, to get clock name and pinctrl name of pm_query_data API
+ * receives 5 words of respoonse from firmware. Currently linux driver can
+ * receive only 4 words from TF-A. So, this needs to be handled separately
+ * than other eemi calls.
+ */
+ if (api_id == PM_QUERY_DATA) {
+ if ((pm_arg[0] == XPM_QID_CLOCK_GET_NAME ||
+ pm_arg[0] == XPM_QID_PINCTRL_GET_FUNCTION_NAME) &&
+ ret == PM_RET_SUCCESS) {
+ SMC_RET2(handle, (uint64_t)buf[0] | ((uint64_t)buf[1] << 32U),
+ (uint64_t)buf[2] | ((uint64_t)buf[3] << 32U));
+ }
+ }
+
+ SMC_RET2(handle, (uint64_t)ret | ((uint64_t)buf[0] << 32U),
+ (uint64_t)buf[1] | ((uint64_t)buf[2] << 32U));
+}
+
+/**
+ * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2.
+ * @smc_fid - Function Identifier
+ * @x1 - x4 - SMC64 Arguments from kernel
+ * x3 (upper 32-bits) and x4 are Unused
+ * @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, const void *cookie, void *handle, uint64_t flags)
+{
+ uintptr_t ret;
+ uint32_t pm_arg[PAYLOAD_ARG_CNT] = {0};
+ uint32_t security_flag = SECURE_FLAG;
+ uint32_t api_id;
+
+ /* Handle case where PM wasn't initialized properly */
+ if (pm_up == false) {
+ SMC_RET1(handle, SMC_UNK);
+ }
+
+ /*
+ * Mark BIT24 payload (i.e 1st bit of pm_arg[3] ) as non-secure (1)
+ * if smc called is non secure
+ */
+ if (is_caller_non_secure(flags) != 0) {
+ security_flag = NON_SECURE_FLAG;
+ }
+
+ pm_arg[0] = (uint32_t)x1;
+ pm_arg[1] = (uint32_t)(x1 >> 32U);
+ pm_arg[2] = (uint32_t)x2;
+ pm_arg[3] = (uint32_t)(x2 >> 32U);
+ pm_arg[4] = (uint32_t)x3;
+ (void)(x4);
+ api_id = smc_fid & FUNCID_NUM_MASK;
+
+ ret = eemi_for_compatibility(api_id, pm_arg, handle, security_flag);
+ if (ret != (uintptr_t)0) {
+ return ret;
+ }
+
+ ret = eemi_psci_debugfs_handler(api_id, pm_arg, handle, flags);
+ if (ret != (uintptr_t)0) {
+ return ret;
+ }
+
+ ret = TF_A_specific_handler(api_id, pm_arg, handle, security_flag);
+ if (ret != (uintptr_t)0) {
+ return ret;
+ }
+
+ ret = eemi_handler(api_id, pm_arg, handle, security_flag);
+
+ return ret;
+}
diff --git a/plat/xilinx/versal/pm_service/pm_svc_main.h b/plat/xilinx/versal/pm_service/pm_svc_main.h
new file mode 100644
index 0000000..b6e764f
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_svc_main.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PM_SVC_MAIN_H
+#define PM_SVC_MAIN_H
+
+#include <pm_common.h>
+
+int32_t pm_setup(void);
+uint64_t pm_smc_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 pm_register_sgi(uint32_t sgi_num, uint32_t reset);
+#endif /* PM_SVC_MAIN_H */
diff --git a/plat/xilinx/versal/sip_svc_setup.c b/plat/xilinx/versal/sip_svc_setup.c
new file mode 100644
index 0000000..6f2ff94
--- /dev/null
+++ b/plat/xilinx/versal/sip_svc_setup.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2018-2021, 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 <common/debug.h>
+#include <common/runtime_svc.h>
+#include <tools_share/uuid.h>
+
+#include "ipi_mailbox_svc.h"
+#include "pm_svc_main.h"
+
+/* SMC function IDs for SiP Service queries */
+#define VERSAL_SIP_SVC_CALL_COUNT U(0x8200ff00)
+#define VERSAL_SIP_SVC_UID U(0x8200ff01)
+#define VERSAL_SIP_SVC_VERSION U(0x8200ff03)
+
+/* SiP Service Calls version numbers */
+#define SIP_SVC_VERSION_MAJOR U(0)
+#define SIP_SVC_VERSION_MINOR U(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 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(versal_sip_uuid,
+ 0x2ab9e4ecU, 0x93b9U, 0x11e7U, 0xa0U, 0x19U,
+ 0xdfU, 0xe0U, 0xdbU, 0xadU, 0x0aU, 0xe0U);
+
+/**
+ * sip_svc_setup() - Setup SiP Service
+ *
+ * Invokes PM setup
+ */
+static int32_t sip_svc_setup(void)
+{
+ /* PM implementation as SiP Service */
+ (void)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);
+ }
+
+ /* 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);
diff --git a/plat/xilinx/versal/versal_gicv3.c b/plat/xilinx/versal/versal_gicv3.c
new file mode 100644
index 0000000..d410906
--- /dev/null
+++ b/plat/xilinx/versal/versal_gicv3.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_private.h>
+#include <platform_def.h>
+
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/utils.h>
+#include <plat/common/platform.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 uint32_t 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.
+ */
+}
diff --git a/plat/xilinx/versal/versal_ipi.c b/plat/xilinx/versal/versal_ipi.c
new file mode 100644
index 0000000..f99af82
--- /dev/null
+++ b/plat/xilinx/versal/versal_ipi.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2019-2021, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Versal IPI agent registers access management
+ */
+
+#include <errno.h>
+#include <ipi.h>
+#include <plat_ipi.h>
+#include <plat_private.h>
+#include <string.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+/* versal ipi configuration table */
+const static struct ipi_config versal_ipi_table[] = {
+ /* A72 IPI */
+ [IPI_ID_APU] = {
+ .ipi_bit_mask = IPI0_TRIG_BIT,
+ .ipi_reg_base = IPI0_REG_BASE,
+ .secure_only = 0U,
+ },
+
+ /* PMC IPI */
+ [IPI_ID_PMC] = {
+ .ipi_bit_mask = PMC_IPI_TRIG_BIT,
+ .ipi_reg_base = IPI0_REG_BASE,
+ .secure_only = 0U,
+ },
+
+ /* RPU0 IPI */
+ [IPI_ID_RPU0] = {
+ .ipi_bit_mask = IPI1_TRIG_BIT,
+ .ipi_reg_base = IPI1_REG_BASE,
+ .secure_only = 0U,
+ },
+
+ /* RPU1 IPI */
+ [IPI_ID_RPU1] = {
+ .ipi_bit_mask = IPI2_TRIG_BIT,
+ .ipi_reg_base = IPI2_REG_BASE,
+ .secure_only = 0U,
+ },
+
+ /* IPI3 IPI */
+ [IPI_ID_3] = {
+ .ipi_bit_mask = IPI3_TRIG_BIT,
+ .ipi_reg_base = IPI3_REG_BASE,
+ .secure_only = 0U,
+ },
+
+ /* IPI4 IPI */
+ [IPI_ID_4] = {
+ .ipi_bit_mask = IPI4_TRIG_BIT,
+ .ipi_reg_base = IPI4_REG_BASE,
+ .secure_only = 0U,
+ },
+
+ /* IPI5 IPI */
+ [IPI_ID_5] = {
+ .ipi_bit_mask = IPI5_TRIG_BIT,
+ .ipi_reg_base = IPI5_REG_BASE,
+ .secure_only = 0U,
+ },
+};
+
+/* versal_ipi_config_table_init() - Initialize versal IPI configuration data
+ *
+ * @ipi_config_table - IPI configuration table
+ * @ipi_total - Total number of IPI available
+ *
+ */
+void versal_ipi_config_table_init(void)
+{
+ ipi_config_table_init(versal_ipi_table, ARRAY_SIZE(versal_ipi_table));
+}
diff --git a/plat/xilinx/versal_net/aarch64/versal_net_common.c b/plat/xilinx/versal_net/aarch64/versal_net_common.c
new file mode 100644
index 0000000..c78b5d0
--- /dev/null
+++ b/plat/xilinx/versal_net/aarch64/versal_net_common.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#include <plat_ipi.h>
+
+#include <plat_private.h>
+#include <versal_net_def.h>
+
+uint32_t platform_id, platform_version;
+
+/*
+ * 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_net_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(DEVICE2_BASE, DEVICE2_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(CRF_BASE, CRF_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(IPI_BASE, IPI_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+ { 0 }
+};
+
+const mmap_region_t *plat_versal_net_get_mmap(void)
+{
+ return plat_versal_net_mmap;
+}
+
+/* For saving cpu clock for certain platform */
+uint32_t cpu_clock;
+
+char *board_name_decode(void)
+{
+ switch (platform_id) {
+ case VERSAL_NET_SPP:
+ return "IPP";
+ case VERSAL_NET_EMU:
+ return "EMU";
+ case VERSAL_NET_SILICON:
+ return "Silicon";
+ case VERSAL_NET_QEMU:
+ return "QEMU";
+ default:
+ return "Unknown";
+ }
+}
+
+void board_detection(void)
+{
+ uint32_t version;
+
+ version = mmio_read_32(PMC_TAP_VERSION);
+ platform_id = FIELD_GET(PLATFORM_MASK, version);
+ platform_version = FIELD_GET(PLATFORM_VERSION_MASK, version);
+
+ if (platform_id == VERSAL_NET_QEMU_COSIM) {
+ platform_id = VERSAL_NET_QEMU;
+ }
+
+ if ((platform_id == VERSAL_NET_SPP) ||
+ (platform_id == VERSAL_NET_EMU) ||
+ (platform_id == VERSAL_NET_QEMU)) {
+ /*
+ * 9 is diff for
+ * 0 means 0.9 version
+ * 1 means 1.0 version
+ * 2 means 1.1 version
+ * etc,
+ */
+ platform_version += 9U;
+ }
+
+ /* Make sure that console is setup to see this message */
+ VERBOSE("Platform id: %d version: %d.%d\n", platform_id,
+ platform_version / 10U, platform_version % 10U);
+}
+
+void versal_net_config_setup(void)
+{
+ uint32_t val;
+ uintptr_t crl_base, iou_scntrs_base, psx_base;
+
+ crl_base = VERSAL_NET_CRL;
+ iou_scntrs_base = VERSAL_NET_IOU_SCNTRS;
+ psx_base = PSX_CRF;
+
+ /* Reset for system timestamp generator in FPX */
+ mmio_write_32(psx_base + PSX_CRF_RST_TIMESTAMP_OFFSET, 0);
+
+ /* Global timer init - Program time stamp reference clk */
+ val = mmio_read_32(crl_base + VERSAL_NET_CRL_TIMESTAMP_REF_CTRL_OFFSET);
+ val |= VERSAL_NET_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT;
+ mmio_write_32(crl_base + VERSAL_NET_CRL_TIMESTAMP_REF_CTRL_OFFSET, val);
+
+ /* Clear reset of timestamp reg */
+ mmio_write_32(crl_base + VERSAL_NET_CRL_RST_TIMESTAMP_OFFSET, 0);
+
+ /* Program freq register in System counter and enable system counter. */
+ mmio_write_32(iou_scntrs_base + VERSAL_NET_IOU_SCNTRS_BASE_FREQ_OFFSET,
+ cpu_clock);
+ mmio_write_32(iou_scntrs_base + VERSAL_NET_IOU_SCNTRS_COUNTER_CONTROL_REG_OFFSET,
+ VERSAL_NET_IOU_SCNTRS_CONTROL_EN);
+
+ generic_delay_timer_init();
+
+#if (TFA_NO_PM == 0)
+ /* Configure IPI data for versal_net */
+ versal_net_ipi_config_table_init();
+#endif
+}
+
+uint32_t plat_get_syscnt_freq2(void)
+{
+ return cpu_clock;
+}
diff --git a/plat/xilinx/versal_net/aarch64/versal_net_helpers.S b/plat/xilinx/versal_net/aarch64/versal_net_helpers.S
new file mode 100644
index 0000000..48082a6
--- /dev/null
+++ b/plat/xilinx/versal_net/aarch64/versal_net_helpers.S
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/gicv3.h>
+#include <platform_def.h>
+
+ .globl plat_secondary_cold_boot_setup
+ .globl plat_is_my_cpu_primary
+ .globl platform_mem_init
+ .globl plat_my_core_pos
+ .globl plat_crash_console_init
+ .globl plat_crash_console_putc
+ .globl plat_crash_console_flush
+
+ /* -----------------------------------------------------
+ * 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_NET_PRIMARY_CPU
+ cset x0, eq
+ ret x9
+endfunc plat_is_my_cpu_primary
+
+ /* -----------------------------------------------------
+ * unsigned int plat_my_core_pos(void)
+ * This function uses the plat_core_pos_by_mpidr()
+ * definition to get the index of the calling CPU.
+ * -----------------------------------------------------
+ */
+func plat_my_core_pos
+ mrs x0, mpidr_el1
+ b plat_core_pos_by_mpidr
+endfunc plat_my_core_pos
+
+ /* ---------------------------------------------------------------------
+ * We don't need to carry out any memory initialization on Versal NET
+ * platform. 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, PLAT_VERSAL_NET_CRASH_UART_BASE
+ mov_imm x1, PLAT_VERSAL_NET_CRASH_UART_CLK_IN_HZ
+ mov_imm x2, VERSAL_NET_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_VERSAL_NET_CRASH_UART_BASE
+ b console_pl011_core_putc
+endfunc plat_crash_console_putc
+
+ /* ---------------------------------------------
+ * void plat_crash_console_flush()
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * Out : void.
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func plat_crash_console_flush
+ mov_imm x0, PLAT_VERSAL_NET_CRASH_UART_BASE
+ b console_pl011_core_flush
+endfunc plat_crash_console_flush
diff --git a/plat/xilinx/versal_net/bl31_versal_net_setup.c b/plat/xilinx/versal_net/bl31_versal_net_setup.c
new file mode 100644
index 0000000..c9942d6
--- /dev/null
+++ b/plat/xilinx/versal_net/bl31_versal_net_setup.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/fdt_fixup.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <libfdt.h>
+#include <plat/common/platform.h>
+#include <plat_arm.h>
+
+#include <plat_private.h>
+#include <plat_startup.h>
+#include <versal_net_def.h>
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+static console_t versal_net_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;
+}
+
+/*
+ * Set the build time defaults,if we can't find any 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 & 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)
+{
+ uint32_t uart_clock;
+ int32_t rc;
+
+ board_detection();
+
+ switch (platform_id) {
+ case VERSAL_NET_SPP:
+ cpu_clock = 1000000;
+ uart_clock = 1000000;
+ break;
+ case VERSAL_NET_EMU:
+ cpu_clock = 3660000;
+ uart_clock = 25000000;
+ break;
+ case VERSAL_NET_QEMU:
+ /* Random values now */
+ cpu_clock = 100000000;
+ uart_clock = 25000000;
+ break;
+ case VERSAL_NET_SILICON:
+ cpu_clock = 100000000;
+ uart_clock = 100000000;
+ break;
+ default:
+ panic();
+ }
+
+ /* Initialize the console to provide early debug support */
+ rc = console_pl011_register(VERSAL_NET_UART_BASE, uart_clock,
+ VERSAL_NET_UART_BAUDRATE,
+ &versal_net_runtime_console);
+ if (rc == 0) {
+ panic();
+ }
+
+ console_set_scope(&versal_net_runtime_console, CONSOLE_FLAG_BOOT |
+ CONSOLE_FLAG_RUNTIME);
+
+ NOTICE("TF-A running on Xilinx %s %d.%d\n", board_name_decode(),
+ platform_version / 10U, platform_version % 10U);
+
+ /* Initialize the platform config for future decision making */
+ versal_net_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_NET 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);
+
+ bl31_set_default_config();
+
+ 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);
+}
+
+static versal_intr_info_type_el3_t type_el3_interrupt_table[MAX_INTR_EL3];
+
+int request_intr_type_el3(uint32_t id, interrupt_type_handler_t handler)
+{
+ static uint32_t index;
+ uint32_t i;
+
+ /* Validate 'handler' and 'id' parameters */
+ if (handler == NULL || index >= MAX_INTR_EL3) {
+ return -EINVAL;
+ }
+
+ /* Check if a handler has already been registered */
+ for (i = 0; i < index; i++) {
+ if (id == type_el3_interrupt_table[i].id) {
+ return -EALREADY;
+ }
+ }
+
+ type_el3_interrupt_table[index].id = id;
+ type_el3_interrupt_table[index].handler = handler;
+
+ index++;
+
+ return 0;
+}
+
+static uint64_t rdo_el3_interrupt_handler(uint32_t id, uint32_t flags,
+ void *handle, void *cookie)
+{
+ uint32_t intr_id;
+ uint32_t i;
+ interrupt_type_handler_t handler = NULL;
+
+ intr_id = plat_ic_get_pending_interrupt_id();
+
+ for (i = 0; i < MAX_INTR_EL3; i++) {
+ if (intr_id == type_el3_interrupt_table[i].id) {
+ handler = type_el3_interrupt_table[i].handler;
+ }
+ }
+
+ if (handler != NULL) {
+ handler(intr_id, flags, handle, cookie);
+ }
+
+ return 0;
+}
+
+void bl31_platform_setup(void)
+{
+ /* Initialize the gic cpu and distributor interfaces */
+ plat_versal_net_gic_driver_init();
+ plat_versal_net_gic_init();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+ uint64_t flags = 0;
+ int32_t rc;
+
+ set_interrupt_rm_flag(flags, NON_SECURE);
+ rc = register_interrupt_type_handler(INTR_TYPE_EL3,
+ rdo_el3_interrupt_handler, flags);
+ if (rc != 0) {
+ panic();
+ }
+}
+
+/*
+ * 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),
+ {0}
+ };
+
+ setup_page_tables(bl_regions, plat_versal_net_get_mmap());
+ enable_mmu(0);
+}
diff --git a/plat/xilinx/versal_net/include/plat_ipi.h b/plat/xilinx/versal_net/include/plat_ipi.h
new file mode 100644
index 0000000..5255f8f
--- /dev/null
+++ b/plat/xilinx/versal_net/include/plat_ipi.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Versal IPI management enums and defines */
+
+#ifndef PLAT_IPI_H
+#define PLAT_IPI_H
+
+#include <stdint.h>
+
+#include <ipi.h>
+
+/*********************************************************************
+ * IPI agent IDs macros
+ ********************************************************************/
+#define IPI_ID_PMC 1U
+#define IPI_ID_APU 2U
+#define IPI_ID_RPU0 3U
+#define IPI_ID_RPU1 4U
+#define IPI_ID_3 5U
+#define IPI_ID_4 6U
+#define IPI_ID_5 7U
+#define IPI_ID_MAX 8U
+
+/*********************************************************************
+ * IPI message buffers
+ ********************************************************************/
+#define IPI_BUFFER_BASEADDR (0xEB3F0000U)
+
+#define IPI_BUFFER_APU_BASE (IPI_BUFFER_BASEADDR + 0x400U)
+#define IPI_BUFFER_PMC_BASE (IPI_BUFFER_BASEADDR + 0x200U)
+
+#define IPI_BUFFER_TARGET_APU_OFFSET 0x80U
+#define IPI_BUFFER_TARGET_PMC_OFFSET 0x40U
+
+#define IPI_BUFFER_LOCAL_BASE IPI_BUFFER_APU_BASE
+#define IPI_BUFFER_REMOTE_BASE IPI_BUFFER_PMC_BASE
+
+#define IPI_BUFFER_TARGET_LOCAL_OFFSET IPI_BUFFER_TARGET_APU_OFFSET
+#define IPI_BUFFER_TARGET_REMOTE_OFFSET IPI_BUFFER_TARGET_PMC_OFFSET
+
+#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 versal_net */
+void versal_net_ipi_config_table_init(void);
+
+#endif /* PLAT_IPI_H */
diff --git a/plat/xilinx/versal_net/include/plat_macros.S b/plat/xilinx/versal_net/include/plat_macros.S
new file mode 100644
index 0000000..fb108b6
--- /dev/null
+++ b/plat/xilinx/versal_net/include/plat_macros.S
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gicv3.h>
+
+#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 NET platform.
+ * Expects: GICD base in x16, GICC base in x17
+ * Clobbers: x0 - x10, sp
+ * ---------------------------------------------
+ */
+ .macro versal_net_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
+ /*
+ * Empty for now to handle more platforms variant.
+ * Uncomment it when versions are stable
+ */
+ /*
+ mov_imm x17, PLAT_VERSAL_NET_GICD_BASE
+ mov_imm x16, PLAT_VERSAL_NET_GICR_BASE
+ versal_net_print_gic_regs
+ */
+ .endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/xilinx/versal_net/include/plat_pm_common.h b/plat/xilinx/versal_net/include/plat_pm_common.h
new file mode 100644
index 0000000..ad7b40f
--- /dev/null
+++ b/plat/xilinx/versal_net/include/plat_pm_common.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. 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 <stdint.h>
+
+#include <common/debug.h>
+
+#include "pm_defs.h"
+
+#define NON_SECURE_FLAG 1U
+#define SECURE_FLAG 0U
+
+#endif /* PLAT_PM_COMMON_H */
diff --git a/plat/xilinx/versal_net/include/plat_private.h b/plat/xilinx/versal_net/include/plat_private.h
new file mode 100644
index 0000000..6a3bc19
--- /dev/null
+++ b/plat/xilinx/versal_net/include/plat_private.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PRIVATE_H
+#define PLAT_PRIVATE_H
+
+#include <bl31/interrupt_mgmt.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+typedef struct versal_intr_info_type_el3 {
+ uint32_t id;
+ interrupt_type_handler_t handler;
+} versal_intr_info_type_el3_t;
+
+void versal_net_config_setup(void);
+
+const mmap_region_t *plat_versal_net_get_mmap(void);
+
+void plat_versal_net_gic_driver_init(void);
+void plat_versal_net_gic_init(void);
+void plat_versal_net_gic_cpuif_enable(void);
+void plat_versal_net_gic_cpuif_disable(void);
+void plat_versal_net_gic_pcpu_init(void);
+void plat_versal_net_gic_save(void);
+void plat_versal_net_gic_resume(void);
+void plat_versal_net_gic_redistif_on(void);
+void plat_versal_net_gic_redistif_off(void);
+
+extern uint32_t cpu_clock, platform_id, platform_version;
+void board_detection(void);
+char *board_name_decode(void);
+uint64_t 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);
+int32_t sip_svc_setup_init(void);
+/*
+ * Register handler to specific GIC entrance
+ * for INTR_TYPE_EL3 type of interrupt
+ */
+int request_intr_type_el3(uint32_t irq, interrupt_type_handler_t fiq_handler);
+
+#define PM_GET_CHIPID (24U)
+#define IOCTL_OSPI_MUX_SELECT (21U)
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/xilinx/versal_net/include/platform_def.h b/plat/xilinx/versal_net/include/platform_def.h
new file mode 100644
index 0000000..696771f
--- /dev/null
+++ b/plat/xilinx/versal_net/include/platform_def.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include "versal_net_def.h"
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE U(0x440)
+
+#define PLATFORM_CLUSTER_COUNT U(4)
+#define PLATFORM_CORE_COUNT_PER_CLUSTER U(4) /* 4 CPUs per cluster */
+
+#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * PLATFORM_CORE_COUNT_PER_CLUSTER)
+
+#define PLAT_MAX_PWR_LVL U(2)
+#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 VERSAL_NET_ATF_MEM_BASE
+# define BL31_BASE U(0xBBF00000)
+# define BL31_LIMIT U(0xBBFFFFFF)
+#else
+# define BL31_BASE U(VERSAL_NET_ATF_MEM_BASE)
+# define BL31_LIMIT U(VERSAL_NET_ATF_MEM_BASE + VERSAL_NET_ATF_MEM_SIZE - 1)
+# ifdef VERSAL_NET_ATF_MEM_PROGBITS_SIZE
+# define BL31_PROGBITS_LIMIT U(VERSAL_NET_ATF_MEM_BASE + \
+ VERSAL_NET_ATF_MEM_PROGBITS_SIZE - 1)
+# endif
+#endif
+
+/*******************************************************************************
+ * BL32 specific defines.
+ ******************************************************************************/
+#ifndef VERSAL_NET_BL32_MEM_BASE
+# define BL32_BASE U(0x60000000)
+# define BL32_LIMIT U(0x7FFFFFFF)
+#else
+# define BL32_BASE U(VERSAL_NET_BL32_MEM_BASE)
+# define BL32_LIMIT U(VERSAL_NET_BL32_MEM_BASE + VERSAL_NET_BL32_MEM_SIZE - 1)
+#endif
+
+/*******************************************************************************
+ * BL33 specific defines.
+ ******************************************************************************/
+#ifndef PRELOADED_BL33_BASE
+# define PLAT_ARM_NS_IMAGE_BASE U(0x8000000)
+#else
+# define PLAT_ARM_NS_IMAGE_BASE U(PRELOADED_BL33_BASE)
+#endif
+
+/*******************************************************************************
+ * TSP specific defines.
+ ******************************************************************************/
+#define TSP_SEC_MEM_BASE BL32_BASE
+#define TSP_SEC_MEM_SIZE (BL32_LIMIT - BL32_BASE + 1U)
+
+/* 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_DDR_LOWMEM_MAX U(0x80000000)
+
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32U)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32U)
+#if (BL31_LIMIT < PLAT_DDR_LOWMEM_MAX)
+#define MAX_MMAP_REGIONS U(10)
+#else
+#define MAX_MMAP_REGIONS U(9)
+#endif
+
+#define MAX_XLAT_TABLES U(8)
+
+#define CACHE_WRITEBACK_SHIFT U(6)
+#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
+
+#define PLAT_VERSAL_NET_GICD_BASE U(0xE2000000)
+#define PLAT_VERSAL_NET_GICR_BASE U(0xE2060000)
+
+/*
+ * 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_IPI_IRQ 62
+
+#define PLAT_VERSAL_NET_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(VERSAL_NET_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL)
+
+#define PLAT_VERSAL_NET_G0_IRQ_PROPS(grp)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/xilinx/versal_net/include/versal_net_def.h b/plat/xilinx/versal_net/include/versal_net_def.h
new file mode 100644
index 0000000..8cb5bf3
--- /dev/null
+++ b/plat/xilinx/versal_net/include/versal_net_def.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef VERSAL_NET_DEF_H
+#define VERSAL_NET_DEF_H
+
+#include <plat/arm/common/smccc_def.h>
+#include <plat/common/common_def.h>
+
+#define MAX_INTR_EL3 2
+/* This part is taken from U-Boot project under GPL that's why dual license above */
+#define __bf_shf(x) (__builtin_ffsll(x) - 1U)
+#define FIELD_GET(_mask, _reg) \
+ ({ \
+ (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \
+ })
+
+/* List all consoles */
+#define VERSAL_NET_CONSOLE_ID_pl011 U(1)
+#define VERSAL_NET_CONSOLE_ID_pl011_0 U(1)
+#define VERSAL_NET_CONSOLE_ID_pl011_1 U(2)
+
+#define VERSAL_NET_CONSOLE_IS(con) (VERSAL_NET_CONSOLE_ID_ ## con == VERSAL_NET_CONSOLE)
+
+/* List all platforms */
+#define VERSAL_NET_SILICON U(0)
+#define VERSAL_NET_SPP U(1)
+#define VERSAL_NET_EMU U(2)
+#define VERSAL_NET_QEMU U(3)
+#define VERSAL_NET_QEMU_COSIM U(7)
+
+/* For platform detection */
+#define PMC_TAP U(0xF11A0000)
+#define PMC_TAP_VERSION (PMC_TAP + 0x4U)
+# define PLATFORM_MASK GENMASK(27U, 24U)
+# define PLATFORM_VERSION_MASK GENMASK(31U, 28U)
+
+/* Global timer reset */
+#define PSX_CRF U(0xEC200000)
+#define ACPU0_CLK_CTRL U(0x10C)
+#define ACPU_CLK_CTRL_CLKACT BIT(25)
+
+#define RST_APU0_OFFSET U(0x300)
+#define RST_APU_COLD_RESET BIT(0)
+#define RST_APU_WARN_RESET BIT(4)
+#define RST_APU_CLUSTER_COLD_RESET BIT(8)
+#define RST_APU_CLUSTER_WARM_RESET BIT(9)
+
+#define PSX_CRF_RST_TIMESTAMP_OFFSET U(0x33C)
+
+#define APU_PCLI U(0xECB10000)
+#define APU_PCLI_CPU_STEP U(0x30)
+#define APU_PCLI_CLUSTER_CPU_STEP (4U * APU_PCLI_CPU_STEP)
+#define APU_PCLI_CLUSTER_OFFSET U(0x8000)
+#define APU_PCLI_CLUSTER_STEP U(0x1000)
+#define PCLI_PREQ_OFFSET U(0x4)
+#define PREQ_CHANGE_REQUEST BIT(0)
+#define PCLI_PSTATE_OFFSET U(0x8)
+#define PCLI_PSTATE_VAL_SET U(0x48)
+#define PCLI_PSTATE_VAL_CLEAR U(0x38)
+
+/* Firmware Image Package */
+#define VERSAL_NET_PRIMARY_CPU U(0)
+
+#define CORE_0_IEN_POWER_OFFSET (0x00000018U)
+#define APU_PCIL_CORE_X_IEN_POWER_REG(cpu_id) (APU_PCLI + (CORE_0_IEN_POWER_OFFSET + \
+ (0x30 * cpu_id)))
+#define APU_PCIL_CORE_X_IEN_POWER_MASK (0x00000001U)
+#define CORE_0_IDS_POWER_OFFSET (0x0000001CU)
+#define APU_PCIL_CORE_X_IDS_POWER_REG(cpu_id) (APU_PCLI + (CORE_0_IDS_POWER_OFFSET + \
+ (0x30 * cpu_id)))
+#define APU_PCIL_CORE_X_IDS_POWER_MASK (0x00000001U)
+#define CORE_PWRDN_EN_BIT_MASK (0x1U)
+
+/*******************************************************************************
+ * memory map related constants
+ ******************************************************************************/
+/* IPP 1.2/SPP 0.9 mapping */
+#define DEVICE0_BASE U(0xE8000000) /* psx, crl, iou */
+#define DEVICE0_SIZE U(0x08000000)
+#define DEVICE1_BASE U(0xE2000000) /* gic */
+#define DEVICE1_SIZE U(0x00800000)
+#define DEVICE2_BASE U(0xF1000000) /* uart, pmc_tap */
+#define DEVICE2_SIZE U(0x01000000)
+#define CRF_BASE U(0xFD1A0000)
+#define CRF_SIZE U(0x00600000)
+#define IPI_BASE U(0xEB300000)
+#define IPI_SIZE U(0x00100000)
+
+/* CRL */
+#define VERSAL_NET_CRL U(0xEB5E0000)
+#define VERSAL_NET_CRL_TIMESTAMP_REF_CTRL_OFFSET U(0x14C)
+#define VERSAL_NET_CRL_RST_TIMESTAMP_OFFSET U(0x348)
+
+#define VERSAL_NET_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT (1U << 25U)
+
+/* IOU SCNTRS */
+#define VERSAL_NET_IOU_SCNTRS U(0xEC920000)
+#define VERSAL_NET_IOU_SCNTRS_COUNTER_CONTROL_REG_OFFSET U(0)
+#define VERSAL_NET_IOU_SCNTRS_BASE_FREQ_OFFSET U(0x20)
+
+#define VERSAL_NET_IOU_SCNTRS_CONTROL_EN U(1)
+
+#define APU_CLUSTER0 U(0xECC00000)
+#define APU_RVBAR_L_0 U(0x40)
+#define APU_RVBAR_H_0 U(0x44)
+#define APU_CLUSTER_STEP U(0x100000)
+
+#define SLCR_OSPI_QSPI_IOU_AXI_MUX_SEL U(0xF1060504)
+
+/*******************************************************************************
+ * IRQ constants
+ ******************************************************************************/
+#define VERSAL_NET_IRQ_SEC_PHY_TIMER U(29)
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define VERSAL_NET_UART0_BASE U(0xF1920000)
+#define VERSAL_NET_UART_BAUDRATE 115200
+
+#define VERSAL_NET_UART_BASE VERSAL_NET_UART0_BASE
+
+#define PLAT_VERSAL_NET_CRASH_UART_BASE VERSAL_NET_UART_BASE
+#define PLAT_VERSAL_NET_CRASH_UART_CLK_IN_HZ VERSAL_NET_UART_CLOCK
+#define VERSAL_NET_CONSOLE_BAUDRATE VERSAL_NET_UART_BAUDRATE
+
+/*******************************************************************************
+ * IPI registers and bitfields
+ ******************************************************************************/
+#define IPI0_REG_BASE (0xEB330000U)
+#define IPI0_TRIG_BIT (1 << 2)
+#define PMC_IPI_TRIG_BIT (1 << 1)
+#define IPI1_REG_BASE (0xEB340000U)
+#define IPI1_TRIG_BIT (1 << 3)
+#define IPI2_REG_BASE (0xEB350000U)
+#define IPI2_TRIG_BIT (1 << 4)
+#define IPI3_REG_BASE (0xEB360000U)
+#define IPI3_TRIG_BIT (1 << 5)
+#define IPI4_REG_BASE (0xEB370000U)
+#define IPI4_TRIG_BIT (1 << 6)
+#define IPI5_REG_BASE (0xEB380000U)
+#define IPI5_TRIG_BIT (1 << 7)
+
+/* Processor core device IDs */
+#define PM_DEV_CLUSTER0_ACPU_0 (0x1810C0AFU)
+#define PM_DEV_CLUSTER0_ACPU_1 (0x1810C0B0U)
+#define PM_DEV_CLUSTER0_ACPU_2 (0x1810C0B1U)
+#define PM_DEV_CLUSTER0_ACPU_3 (0x1810C0B2U)
+
+#define PM_DEV_CLUSTER1_ACPU_0 (0x1810C0B3U)
+#define PM_DEV_CLUSTER1_ACPU_1 (0x1810C0B4U)
+#define PM_DEV_CLUSTER1_ACPU_2 (0x1810C0B5U)
+#define PM_DEV_CLUSTER1_ACPU_3 (0x1810C0B6U)
+
+#define PM_DEV_CLUSTER2_ACPU_0 (0x1810C0B7U)
+#define PM_DEV_CLUSTER2_ACPU_1 (0x1810C0B8U)
+#define PM_DEV_CLUSTER2_ACPU_2 (0x1810C0B9U)
+#define PM_DEV_CLUSTER2_ACPU_3 (0x1810C0BAU)
+
+#define PM_DEV_CLUSTER3_ACPU_0 (0x1810C0BBU)
+#define PM_DEV_CLUSTER3_ACPU_1 (0x1810C0BCU)
+#define PM_DEV_CLUSTER3_ACPU_2 (0x1810C0BDU)
+#define PM_DEV_CLUSTER3_ACPU_3 (0x1810C0BEU)
+
+#endif /* VERSAL_NET_DEF_H */
diff --git a/plat/xilinx/versal_net/plat_psci.c b/plat/xilinx/versal_net/plat_psci.c
new file mode 100644
index 0000000..c5833a9
--- /dev/null
+++ b/plat/xilinx/versal_net/plat_psci.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <plat_arm.h>
+
+#include <plat_private.h>
+
+#define PM_RET_ERROR_NOFEATURE U(19)
+
+#define PM_IOCTL 34U
+
+static uintptr_t versal_net_sec_entry;
+
+static void zynqmp_cpu_standby(plat_local_state_t cpu_state)
+{
+ dsb();
+ wfi();
+}
+
+static int32_t zynqmp_nopmu_pwr_domain_on(u_register_t mpidr)
+{
+ uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
+ uint32_t cpu = cpu_id % PLATFORM_CORE_COUNT_PER_CLUSTER;
+ uint32_t cluster = cpu_id / PLATFORM_CORE_COUNT_PER_CLUSTER;
+ uintptr_t apu_cluster_base = 0, apu_pcli_base, apu_pcli_cluster = 0;
+ uintptr_t rst_apu_cluster = PSX_CRF + RST_APU0_OFFSET + (cluster * 0x4);
+
+ VERBOSE("%s: mpidr: 0x%lx, cpuid: %x, cpu: %x, cluster: %x\n",
+ __func__, mpidr, cpu_id, cpu, cluster);
+
+ if (cpu_id == -1) {
+ return PSCI_E_INTERN_FAIL;
+ }
+
+ if (platform_id == VERSAL_NET_SPP && cluster > 1) {
+ panic();
+ }
+
+ if (cluster > 3) {
+ panic();
+ }
+
+ apu_pcli_cluster = APU_PCLI + APU_PCLI_CLUSTER_OFFSET + (cluster * APU_PCLI_CLUSTER_STEP);
+ apu_cluster_base = APU_CLUSTER0 + (cluster * APU_CLUSTER_STEP);
+
+ /* Enable clock */
+ mmio_setbits_32(PSX_CRF + ACPU0_CLK_CTRL + (cluster * 0x4), ACPU_CLK_CTRL_CLKACT);
+
+ /* Enable cluster states */
+ mmio_setbits_32(apu_pcli_cluster + PCLI_PSTATE_OFFSET, PCLI_PSTATE_VAL_SET);
+ mmio_setbits_32(apu_pcli_cluster + PCLI_PREQ_OFFSET, PREQ_CHANGE_REQUEST);
+
+ /* assert core reset */
+ mmio_setbits_32(rst_apu_cluster, ((RST_APU_COLD_RESET|RST_APU_WARN_RESET) << cpu));
+
+ /* program RVBAR */
+ mmio_write_32(apu_cluster_base + APU_RVBAR_L_0 + (cpu << 3),
+ (uint32_t)versal_net_sec_entry);
+ mmio_write_32(apu_cluster_base + APU_RVBAR_H_0 + (cpu << 3),
+ versal_net_sec_entry >> 32);
+
+ /* de-assert core reset */
+ mmio_clrbits_32(rst_apu_cluster, ((RST_APU_COLD_RESET|RST_APU_WARN_RESET) << cpu));
+
+ /* clear cluster resets */
+ mmio_clrbits_32(rst_apu_cluster, RST_APU_CLUSTER_WARM_RESET);
+ mmio_clrbits_32(rst_apu_cluster, RST_APU_CLUSTER_COLD_RESET);
+
+ apu_pcli_base = APU_PCLI + (APU_PCLI_CPU_STEP * cpu) +
+ (APU_PCLI_CLUSTER_CPU_STEP * cluster);
+
+ mmio_write_32(apu_pcli_base + PCLI_PSTATE_OFFSET, PCLI_PSTATE_VAL_CLEAR);
+ mmio_write_32(apu_pcli_base + PCLI_PREQ_OFFSET, PREQ_CHANGE_REQUEST);
+
+ return PSCI_E_SUCCESS;
+}
+
+static void zynqmp_nopmu_pwr_domain_off(const psci_power_state_t *target_state)
+{
+}
+
+static void __dead2 zynqmp_nopmu_system_reset(void)
+{
+ while (1)
+ wfi();
+}
+
+static int32_t zynqmp_validate_ns_entrypoint(uint64_t ns_entrypoint)
+{
+ return PSCI_E_SUCCESS;
+}
+
+static void zynqmp_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+}
+
+static void zynqmp_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ plat_versal_net_gic_pcpu_init();
+ plat_versal_net_gic_cpuif_enable();
+}
+
+static void zynqmp_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+}
+
+static void __dead2 zynqmp_system_off(void)
+{
+ while (1)
+ wfi();
+}
+
+static int32_t zynqmp_validate_power_state(uint32_t power_state, psci_power_state_t *req_state)
+{
+ return PSCI_E_SUCCESS;
+}
+
+static 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;
+}
+
+static const struct plat_psci_ops versal_net_nopmc_psci_ops = {
+ .cpu_standby = zynqmp_cpu_standby,
+ .pwr_domain_on = zynqmp_nopmu_pwr_domain_on,
+ .pwr_domain_off = zynqmp_nopmu_pwr_domain_off,
+ .system_reset = zynqmp_nopmu_system_reset,
+ .validate_ns_entrypoint = zynqmp_validate_ns_entrypoint,
+ .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,
+ .validate_power_state = zynqmp_validate_power_state,
+ .get_sys_suspend_power_state = zynqmp_get_sys_suspend_power_state,
+};
+
+/*******************************************************************************
+ * Export the platform specific power ops.
+ ******************************************************************************/
+int32_t plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const struct plat_psci_ops **psci_ops)
+{
+ versal_net_sec_entry = sec_entrypoint;
+
+ VERBOSE("Setting up entry point %lx\n", versal_net_sec_entry);
+
+ *psci_ops = &versal_net_nopmc_psci_ops;
+
+ return 0;
+}
+
+int sip_svc_setup_init(void)
+{
+ return 0;
+}
+
+static int32_t no_pm_ioctl(uint32_t device_id, uint32_t ioctl_id,
+ uint32_t arg1, uint32_t arg2)
+{
+ VERBOSE("%s: ioctl_id: %x, arg1: %x\n", __func__, ioctl_id, arg1);
+ if (ioctl_id == IOCTL_OSPI_MUX_SELECT) {
+ mmio_write_32(SLCR_OSPI_QSPI_IOU_AXI_MUX_SEL, arg1);
+ return 0;
+ }
+ return PM_RET_ERROR_NOFEATURE;
+}
+
+static uint64_t no_pm_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
+ uint64_t x4, void *cookie, void *handle, uint64_t flags)
+{
+ int32_t ret;
+ uint32_t arg[4], api_id;
+
+ arg[0] = (uint32_t)x1;
+ arg[1] = (uint32_t)(x1 >> 32);
+ arg[2] = (uint32_t)x2;
+ arg[3] = (uint32_t)(x2 >> 32);
+
+ api_id = smc_fid & FUNCID_NUM_MASK;
+ VERBOSE("%s: smc_fid: %x, api_id=0x%x\n", __func__, smc_fid, api_id);
+
+ switch (api_id) {
+ case PM_IOCTL:
+ {
+ ret = no_pm_ioctl(arg[0], arg[1], arg[2], arg[3]);
+ SMC_RET1(handle, (uint64_t)ret);
+ }
+ case PM_GET_CHIPID:
+ {
+ uint32_t idcode, version;
+
+ idcode = mmio_read_32(PMC_TAP);
+ version = mmio_read_32(PMC_TAP_VERSION);
+ SMC_RET2(handle, ((uint64_t)idcode << 32), version);
+ }
+ default:
+ WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+ }
+}
+
+uint64_t 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)
+{
+ return no_pm_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
+}
diff --git a/plat/xilinx/versal_net/plat_psci_pm.c b/plat/xilinx/versal_net/plat_psci_pm.c
new file mode 100644
index 0000000..8beaa9a
--- /dev/null
+++ b/plat/xilinx/versal_net/plat_psci_pm.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <plat_arm.h>
+
+#include <plat_private.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include <pm_common.h>
+#include "pm_svc_main.h"
+#include "versal_net_def.h"
+
+static uintptr_t versal_net_sec_entry;
+
+static int32_t versal_net_pwr_domain_on(u_register_t mpidr)
+{
+ uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
+ const struct pm_proc *proc;
+
+ VERBOSE("%s: mpidr: 0x%lx, cpuid: %x\n",
+ __func__, mpidr, cpu_id);
+
+ if (cpu_id == -1) {
+ return PSCI_E_INTERN_FAIL;
+ }
+
+ proc = pm_get_proc(cpu_id);
+ if (!proc) {
+ return PSCI_E_INTERN_FAIL;
+ }
+
+ pm_req_wakeup(proc->node_id, (versal_net_sec_entry & 0xFFFFFFFFU) | 0x1U,
+ versal_net_sec_entry >> 32, 0, 0);
+
+ /* Clear power down request */
+ pm_client_wakeup(proc);
+
+ return PSCI_E_SUCCESS;
+}
+
+/**
+ * versal_net_pwr_domain_off() - This function performs actions to turn off core
+ *
+ * @param target_state Targeted state
+ */
+static void versal_net_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ uint32_t 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 */
+ plat_versal_net_gic_cpuif_disable();
+
+ /*
+ * Send request to PMC 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,
+ SECURE_FLAG);
+}
+
+/**
+ * versal_net_system_reset() - This function sends the reset request
+ * to firmware for the system to reset. This function does not return.
+ */
+static void __dead2 versal_net_system_reset(void)
+{
+ /* Send the system reset request to the PMC */
+ pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET,
+ pm_get_shutdown_scope(), SECURE_FLAG);
+
+ while (1) {
+ wfi();
+ }
+}
+
+/**
+ * versal_net_pwr_domain_suspend() - This function sends request to PMC to suspend
+ * core.
+ *
+ * @param target_state Targeted state
+ */
+static void versal_net_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+ uint32_t state;
+ uint32_t 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]);
+ }
+
+ plat_versal_net_gic_cpuif_disable();
+
+ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+ plat_versal_net_gic_save();
+ }
+
+ state = target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE ?
+ PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE;
+
+ /* Send request to PMC to suspend this core */
+ pm_self_suspend(proc->node_id, MAX_LATENCY, state, versal_net_sec_entry,
+ SECURE_FLAG);
+
+ /* TODO: disable coherency */
+}
+
+static void versal_net_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ (void)target_state;
+
+ /* Enable the gic cpu interface */
+ plat_versal_net_gic_pcpu_init();
+
+ /* Program the gic per-cpu distributor or re-distributor interface */
+ plat_versal_net_gic_cpuif_enable();
+}
+
+/**
+ * versal_net_pwr_domain_suspend_finish() - This function performs actions to finish
+ * suspend procedure.
+ *
+ * @param target_state Targeted state
+ */
+static void versal_net_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+ uint32_t 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);
+
+ /* TODO: enable coherency */
+
+ /* APU was turned off, so restore GIC context */
+ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+ plat_versal_net_gic_resume();
+ }
+
+ plat_versal_net_gic_cpuif_enable();
+}
+
+/**
+ * versal_net_system_off() - This function sends the system off request
+ * to firmware. This function does not return.
+ */
+static void __dead2 versal_net_system_off(void)
+{
+ /* Send the power down request to the PMC */
+ pm_system_shutdown(XPM_SHUTDOWN_TYPE_SHUTDOWN,
+ pm_get_shutdown_scope(), SECURE_FLAG);
+
+ while (1) {
+ wfi();
+ }
+}
+
+/**
+ * versal_net_validate_power_state() - This function ensures that the power state
+ * parameter in request is valid.
+ *
+ * @param power_state Power state of core
+ * @param req_state Requested state
+ *
+ * @return Returns status, either PSCI_E_SUCCESS or reason
+ */
+static int32_t versal_net_validate_power_state(unsigned int power_state,
+ psci_power_state_t *req_state)
+{
+ VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
+
+ int32_t 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;
+}
+
+/**
+ * versal_net_get_sys_suspend_power_state() - Get power state for system suspend
+ *
+ * @param req_state Requested state
+ */
+static void versal_net_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;
+}
+
+static const struct plat_psci_ops versal_net_nopmc_psci_ops = {
+ .pwr_domain_on = versal_net_pwr_domain_on,
+ .pwr_domain_off = versal_net_pwr_domain_off,
+ .pwr_domain_on_finish = versal_net_pwr_domain_on_finish,
+ .pwr_domain_suspend = versal_net_pwr_domain_suspend,
+ .pwr_domain_suspend_finish = versal_net_pwr_domain_suspend_finish,
+ .system_off = versal_net_system_off,
+ .system_reset = versal_net_system_reset,
+ .validate_power_state = versal_net_validate_power_state,
+ .get_sys_suspend_power_state = versal_net_get_sys_suspend_power_state,
+};
+
+/*******************************************************************************
+ * Export the platform specific power ops.
+ ******************************************************************************/
+int32_t plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const struct plat_psci_ops **psci_ops)
+{
+ versal_net_sec_entry = sec_entrypoint;
+
+ VERBOSE("Setting up entry point %lx\n", versal_net_sec_entry);
+
+ *psci_ops = &versal_net_nopmc_psci_ops;
+
+ return 0;
+}
+
+int32_t sip_svc_setup_init(void)
+{
+ return pm_setup();
+}
+
+uint64_t 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)
+{
+ return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
+}
diff --git a/plat/xilinx/versal_net/plat_topology.c b/plat/xilinx/versal_net/plat_topology.c
new file mode 100644
index 0000000..7f985b0
--- /dev/null
+++ b/plat/xilinx/versal_net/plat_topology.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+#include <plat_private.h>
+#include <platform_def.h>
+
+static const uint8_t plat_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,
+ /* Number of children for the third cluster node */
+ PLATFORM_CORE_COUNT_PER_CLUSTER,
+ /* Number of children for the fourth cluster node */
+ PLATFORM_CORE_COUNT_PER_CLUSTER,
+};
+
+const uint8_t *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.
+ ******************************************************************************/
+int32_t plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+ uint32_t cluster_id, cpu_id;
+
+ mpidr &= MPIDR_AFFINITY_MASK;
+
+ cluster_id = MPIDR_AFFLVL2_VAL(mpidr);
+ cpu_id = MPIDR_AFFLVL1_VAL(mpidr);
+
+ if (cluster_id >= PLATFORM_CLUSTER_COUNT) {
+ return -3;
+ }
+
+ /*
+ * 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 * PLATFORM_CORE_COUNT_PER_CLUSTER));
+}
diff --git a/plat/xilinx/versal_net/platform.mk b/plat/xilinx/versal_net/platform.mk
new file mode 100644
index 0000000..b3d56bc
--- /dev/null
+++ b/plat/xilinx/versal_net/platform.mk
@@ -0,0 +1,102 @@
+# Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
+# Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+PLAT_PATH := plat/xilinx/versal_net
+
+# A78 Erratum for SoC
+ERRATA_A78_AE_1941500 := 1
+ERRATA_A78_AE_1951502 := 1
+ERRATA_A78_AE_2376748 := 1
+ERRATA_A78_AE_2395408 := 1
+
+override PROGRAMMABLE_RESET_ADDRESS := 1
+PSCI_EXTENDED_STATE_ID := 1
+SEPARATE_CODE_AND_RODATA := 1
+override RESET_TO_BL31 := 1
+PL011_GENERIC_UART := 1
+GIC_ENABLE_V4_EXTN := 0
+GICV3_SUPPORT_GIC600 := 1
+TFA_NO_PM := 0
+
+override CTX_INCLUDE_AARCH32_REGS := 0
+
+ifdef TFA_NO_PM
+ $(eval $(call add_define,TFA_NO_PM))
+endif
+
+ifdef VERSAL_NET_ATF_MEM_BASE
+ $(eval $(call add_define,VERSAL_NET_ATF_MEM_BASE))
+
+ ifndef VERSAL_NET_ATF_MEM_SIZE
+ $(error "VERSAL_NET_ATF_BASE defined without VERSAL_NET_ATF_SIZE")
+ endif
+ $(eval $(call add_define,VERSAL_NET_ATF_MEM_SIZE))
+
+ ifdef VERSAL_NET_ATF_MEM_PROGBITS_SIZE
+ $(eval $(call add_define,VERSAL_NET_ATF_MEM_PROGBITS_SIZE))
+ endif
+endif
+
+ifdef VERSAL_NET_BL32_MEM_BASE
+ $(eval $(call add_define,VERSAL_NET_BL32_MEM_BASE))
+
+ ifndef VERSAL_NET_BL32_MEM_SIZE
+ $(error "VERSAL_NET_BL32_BASE defined without VERSAL_NET_BL32_SIZE")
+ endif
+ $(eval $(call add_define,VERSAL_NET_BL32_MEM_SIZE))
+endif
+
+USE_COHERENT_MEM := 0
+HW_ASSISTED_COHERENCY := 1
+
+VERSAL_NET_CONSOLE ?= pl011
+$(eval $(call add_define_val,VERSAL_NET_CONSOLE,VERSAL_NET_CONSOLE_ID_${VERSAL_NET_CONSOLE}))
+
+PLAT_INCLUDES := -Iinclude/plat/arm/common/ \
+ -Iplat/xilinx/common/include/ \
+ -Iplat/xilinx/common/ipi_mailbox_service/ \
+ -I${PLAT_PATH}/include/ \
+ -Iplat/xilinx/versal/pm_service/
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+include lib/xlat_tables_v2/xlat_tables.mk
+include lib/libfdt/libfdt.mk
+
+PLAT_BL_COMMON_SOURCES := \
+ drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ ${GICV3_SOURCES} \
+ drivers/arm/pl011/aarch64/pl011_console.S \
+ plat/arm/common/arm_common.c \
+ plat/common/plat_gicv3.c \
+ ${PLAT_PATH}/aarch64/versal_net_helpers.S \
+ ${PLAT_PATH}/aarch64/versal_net_common.c
+
+BL31_SOURCES += drivers/arm/cci/cci.c \
+ lib/cpus/aarch64/cortex_a78_ae.S \
+ lib/cpus/aarch64/cortex_a78.S \
+ plat/common/plat_psci_common.c
+ifeq ($(TFA_NO_PM), 0)
+BL31_SOURCES += plat/xilinx/versal/pm_service/pm_api_sys.c \
+ plat/xilinx/common/pm_service/pm_ipi.c \
+ ${PLAT_PATH}/plat_psci_pm.c \
+ plat/xilinx/versal/pm_service/pm_svc_main.c \
+ ${PLAT_PATH}/pm_service/pm_client.c \
+ ${PLAT_PATH}/versal_net_ipi.c
+else
+BL31_SOURCES += ${PLAT_PATH}/plat_psci.c
+endif
+BL31_SOURCES += plat/xilinx/common/plat_startup.c \
+ plat/xilinx/common/ipi.c \
+ plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c \
+ ${PLAT_PATH}/bl31_versal_net_setup.c \
+ ${PLAT_PATH}/plat_topology.c \
+ common/fdt_fixup.c \
+ ${LIBFDT_SRCS} \
+ ${PLAT_PATH}/sip_svc_setup.c \
+ ${PLAT_PATH}/versal_net_gicv3.c \
+ ${XLAT_TABLES_LIB_SRCS}
diff --git a/plat/xilinx/versal_net/pm_service/pm_client.c b/plat/xilinx/versal_net/pm_service/pm_client.c
new file mode 100644
index 0000000..6487324
--- /dev/null
+++ b/plat/xilinx/versal_net/pm_service/pm_client.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. 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 <assert.h>
+
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#include <plat_ipi.h>
+#include <platform_def.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include <versal_net_def.h>
+
+#define UNDEFINED_CPUID (~0)
+
+DEFINE_RENAME_SYSREG_RW_FUNCS(cpu_pwrctrl_val, S3_0_C15_C2_7)
+DEFINE_BAKERY_LOCK(pm_client_secure_lock);
+
+static const struct pm_ipi apu_ipi = {
+ .local_ipi_id = IPI_ID_APU,
+ .remote_ipi_id = IPI_ID_PMC,
+ .buffer_base = IPI_BUFFER_APU_BASE,
+};
+
+/* Order in pm_procs_all array must match cpu ids */
+static const struct pm_proc pm_procs_all[] = {
+ {
+ .node_id = PM_DEV_CLUSTER0_ACPU_0,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER0_ACPU_1,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER0_ACPU_2,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER0_ACPU_3,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER1_ACPU_0,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER1_ACPU_1,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER1_ACPU_2,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER1_ACPU_3,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER2_ACPU_0,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER2_ACPU_1,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER2_ACPU_2,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER2_ACPU_3,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER3_ACPU_0,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER3_ACPU_1,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER3_ACPU_2,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER3_ACPU_3,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ }
+};
+
+const struct pm_proc *primary_proc = &pm_procs_all[0];
+
+/**
+ * pm_get_proc() - returns pointer to the proc structure
+ * @param 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(uint32_t cpuid)
+{
+ if (cpuid < ARRAY_SIZE(pm_procs_all)) {
+ return &pm_procs_all[cpuid];
+ }
+
+ NOTICE("ERROR: cpuid: %d proc NULL\n", cpuid);
+ return NULL;
+}
+
+/**
+ * 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.
+ *
+ * @param proc processor which need to suspend
+ * @param state desired suspend state
+ */
+void pm_client_suspend(const struct pm_proc *proc, uint32_t state)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+ uintptr_t val;
+
+ bakery_lock_get(&pm_client_secure_lock);
+
+ /* TODO: Set wakeup source */
+
+ val = read_cpu_pwrctrl_val();
+ val |= CORE_PWRDN_EN_BIT_MASK;
+ write_cpu_pwrctrl_val(val);
+
+ isb();
+
+ mmio_write_32(APU_PCIL_CORE_X_IEN_POWER_REG(cpu_id),
+ APU_PCIL_CORE_X_IEN_POWER_MASK);
+
+ bakery_lock_release(&pm_client_secure_lock);
+}
+
+/**
+ * pm_get_cpuid() - get the local cpu ID for a global node ID
+ * @param nid node id of the processor
+ *
+ * @return the cpu ID (starting from 0) for the subsystem
+ */
+static uint32_t pm_get_cpuid(uint32_t 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;
+}
+
+/**
+ * pm_client_wakeup() - Client-specific wakeup actions
+ *
+ * This function should contain any PU-specific actions
+ * required for waking up another APU core
+ *
+ * @param proc Processor which need to wakeup
+ */
+void pm_client_wakeup(const struct pm_proc *proc)
+{
+ uint32_t cpuid = pm_get_cpuid(proc->node_id);
+
+ if (cpuid == UNDEFINED_CPUID) {
+ return;
+ }
+
+ bakery_lock_get(&pm_client_secure_lock);
+
+ /* TODO: clear powerdown bit for affected cpu */
+
+ 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)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+ uintptr_t val;
+
+ /* Enable interrupts at processor level (for current cpu) */
+ gicv3_cpuif_enable(plat_my_core_pos());
+
+ bakery_lock_get(&pm_client_secure_lock);
+
+ /* Clear powerdown request */
+ val = read_cpu_pwrctrl_val();
+ val &= ~CORE_PWRDN_EN_BIT_MASK;
+ write_cpu_pwrctrl_val(val);
+
+ isb();
+
+ /* Disabled power down interrupt */
+ mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(cpu_id),
+ APU_PCIL_CORE_X_IDS_POWER_MASK);
+
+ bakery_lock_release(&pm_client_secure_lock);
+}
diff --git a/plat/xilinx/versal_net/sip_svc_setup.c b/plat/xilinx/versal_net/sip_svc_setup.c
new file mode 100644
index 0000000..0e3940f
--- /dev/null
+++ b/plat/xilinx/versal_net/sip_svc_setup.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Top level SMC handler for SiP calls. Dispatch PM calls to PM SMC handler. */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <tools_share/uuid.h>
+
+#include "ipi_mailbox_svc.h"
+#include "plat_private.h"
+#include "pm_svc_main.h"
+
+/* SMC function IDs for SiP Service queries */
+#define VERSAL_NET_SIP_SVC_CALL_COUNT (0x8200ff00U)
+#define VERSAL_NET_SIP_SVC_UID (0x8200ff01U)
+#define VERSAL_NET_SIP_SVC_VERSION (0x8200ff03U)
+
+/* SiP Service Calls version numbers */
+#define SIP_SVC_VERSION_MAJOR (0U)
+#define SIP_SVC_VERSION_MINOR (1U)
+
+/* These macros are used to identify PM 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(versal_net_sip_uuid,
+ 0x80d4c25a, 0xebaf, 0x11eb, 0x94, 0x68,
+ 0x0b, 0x4e, 0x3b, 0x8f, 0xc3, 0x60);
+
+/**
+ * sip_svc_setup() - Setup SiP Service
+ */
+static int32_t sip_svc_setup(void)
+{
+ return sip_svc_setup_init();
+}
+
+/*
+ * 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.
+ */
+static 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 smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
+ flags);
+ }
+
+ /* Let IPI SMC handler deal with IPI-related requests if platform */
+ if (is_ipi_fid(smc_fid)) {
+ return ipi_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
+ }
+
+ /* Let PM SMC handler deal with PM-related requests */
+ switch (smc_fid) {
+ case VERSAL_NET_SIP_SVC_CALL_COUNT:
+ /* PM functions + default functions */
+ SMC_RET1(handle, 2);
+
+ case VERSAL_NET_SIP_SVC_UID:
+ SMC_UUID_RET(handle, versal_net_sip_uuid);
+
+ case VERSAL_NET_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);
diff --git a/plat/xilinx/versal_net/versal_net_gicv3.c b/plat/xilinx/versal_net/versal_net_gicv3.c
new file mode 100644
index 0000000..b7ac6ab
--- /dev/null
+++ b/plat/xilinx/versal_net/versal_net_gicv3.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#include <plat_private.h>
+#include <platform_def.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_net_gic_driver_init
+#pragma weak plat_versal_net_gic_init
+#pragma weak plat_versal_net_gic_cpuif_enable
+#pragma weak plat_versal_net_gic_cpuif_disable
+#pragma weak plat_versal_net_gic_pcpu_init
+#pragma weak plat_versal_net_gic_redistif_on
+#pragma weak plat_versal_net_gic_redistif_off
+
+/* The GICv3 driver only needs to be initialized in EL3 */
+static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static const uintptr_t gicr_base_addrs[2] = {
+ PLAT_VERSAL_NET_GICR_BASE, /* GICR Base address of the primary CPU */
+ 0U /* Zero Termination */
+};
+
+/* List of zero terminated GICR frame addresses which CPUs will probe */
+static const uintptr_t *gicr_frames;
+
+static const interrupt_prop_t versal_net_interrupt_props[] = {
+ PLAT_VERSAL_NET_G1S_IRQ_PROPS(INTR_GROUP1S),
+ PLAT_VERSAL_NET_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_net_el3_tzc_dram");
+static gicv3_dist_ctx_t dist_ctx __section("versal_net_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 uint32_t versal_net_gicv3_mpidr_hash(u_register_t mpidr)
+{
+ mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK);
+ return plat_core_pos_by_mpidr(mpidr);
+}
+
+static const gicv3_driver_data_t versal_net_gic_data __unused = {
+ .gicd_base = PLAT_VERSAL_NET_GICD_BASE,
+ .gicr_base = 0U,
+ .interrupt_props = versal_net_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(versal_net_interrupt_props),
+ .rdistif_num = PLATFORM_CORE_COUNT,
+ .rdistif_base_addrs = rdistif_base_addrs,
+ .mpidr_to_core_pos = versal_net_gicv3_mpidr_hash
+};
+
+void __init plat_versal_net_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_net_gic_data);
+ gicr_frames = gicr_base_addrs;
+
+ if (gicv3_rdistif_probe(gicr_frames[0]) == -1) {
+ ERROR("No GICR base frame found for Primary CPU\n");
+ panic();
+ }
+#endif
+}
+
+/******************************************************************************
+ * Versal NET common helper to initialize the GIC. Only invoked by BL31
+ *****************************************************************************/
+void __init plat_versal_net_gic_init(void)
+{
+ gicv3_distif_init();
+ gicv3_rdistif_init(plat_my_core_pos());
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal NET common helper to enable the GIC CPU interface
+ *****************************************************************************/
+void plat_versal_net_gic_cpuif_enable(void)
+{
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal NET common helper to disable the GIC CPU interface
+ *****************************************************************************/
+void plat_versal_net_gic_cpuif_disable(void)
+{
+ gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal NET common helper to initialize the per-cpu redistributor interface in
+ * GICv3
+ *****************************************************************************/
+void plat_versal_net_gic_pcpu_init(void)
+{
+ int32_t result;
+ const uintptr_t *plat_gicr_frames = gicr_frames;
+
+ do {
+ result = gicv3_rdistif_probe(*plat_gicr_frames);
+
+ /* If the probe is successful, no need to proceed further */
+ if (result == 0) {
+ break;
+ }
+
+ plat_gicr_frames++;
+ } while (*plat_gicr_frames != 0U);
+
+ if (result == -1) {
+ ERROR("No GICR base frame found for CPU 0x%lx\n", read_mpidr());
+ panic();
+ }
+
+ gicv3_rdistif_init(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal NET common helpers to power GIC redistributor interface
+ *****************************************************************************/
+void plat_versal_net_gic_redistif_on(void)
+{
+ gicv3_rdistif_on(plat_my_core_pos());
+}
+
+void plat_versal_net_gic_redistif_off(void)
+{
+ gicv3_rdistif_off(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal NET common helper to save & restore the GICv3 on resume from system
+ * suspend
+ *****************************************************************************/
+void plat_versal_net_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_net_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.
+ */
+}
diff --git a/plat/xilinx/versal_net/versal_net_ipi.c b/plat/xilinx/versal_net/versal_net_ipi.c
new file mode 100644
index 0000000..26ded89
--- /dev/null
+++ b/plat/xilinx/versal_net/versal_net_ipi.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Versal NET IPI agent registers access management
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include <ipi.h>
+#include <plat_ipi.h>
+#include <plat_private.h>
+
+/* versal_net ipi configuration table */
+static const struct ipi_config versal_net_ipi_table[IPI_ID_MAX] = {
+ /* A72 IPI */
+ [IPI_ID_APU] = {
+ .ipi_bit_mask = IPI0_TRIG_BIT,
+ .ipi_reg_base = IPI0_REG_BASE,
+ .secure_only = 0,
+ },
+
+ /* PMC IPI */
+ [IPI_ID_PMC] = {
+ .ipi_bit_mask = PMC_IPI_TRIG_BIT,
+ .ipi_reg_base = IPI0_REG_BASE,
+ .secure_only = 0,
+ },
+
+ /* RPU0 IPI */
+ [IPI_ID_RPU0] = {
+ .ipi_bit_mask = IPI1_TRIG_BIT,
+ .ipi_reg_base = IPI1_REG_BASE,
+ .secure_only = 0,
+ },
+
+ /* RPU1 IPI */
+ [IPI_ID_RPU1] = {
+ .ipi_bit_mask = IPI2_TRIG_BIT,
+ .ipi_reg_base = IPI2_REG_BASE,
+ .secure_only = 0,
+ },
+
+ /* IPI3 IPI */
+ [IPI_ID_3] = {
+ .ipi_bit_mask = IPI3_TRIG_BIT,
+ .ipi_reg_base = IPI3_REG_BASE,
+ .secure_only = 0,
+ },
+
+ /* IPI4 IPI */
+ [IPI_ID_4] = {
+ .ipi_bit_mask = IPI4_TRIG_BIT,
+ .ipi_reg_base = IPI4_REG_BASE,
+ .secure_only = 0,
+ },
+
+ /* IPI5 IPI */
+ [IPI_ID_5] = {
+ .ipi_bit_mask = IPI5_TRIG_BIT,
+ .ipi_reg_base = IPI5_REG_BASE,
+ .secure_only = 0,
+ },
+};
+
+/* versal_net_ipi_config_table_init() - Initialize versal_net IPI configuration data
+ *
+ * @ipi_config_table - IPI configuration table
+ * @ipi_total - Total number of IPI available
+ *
+ */
+void versal_net_ipi_config_table_init(void)
+{
+ ipi_config_table_init(versal_net_ipi_table, ARRAY_SIZE(versal_net_ipi_table));
+}
diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
new file mode 100644
index 0000000..3946e9b
--- /dev/null
+++ b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat_ipi.h>
+#include <plat_private.h>
+#include <plat/common/platform.h>
+
+#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 uint32_t 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;
+}
+
+uint32_t 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 {
+ uint32_t id;
+ uint32_t ver;
+ char *name;
+ bool evexists;
+} zynqmp_devices[] = {
+ {
+ .id = 0x10,
+ .name = "XCZU3EG",
+ },
+ {
+ .id = 0x10,
+ .ver = 0x2c,
+ .name = "XCZU3CG",
+ },
+ {
+ .id = 0x11,
+ .name = "XCZU2EG",
+ },
+ {
+ .id = 0x11,
+ .ver = 0x2c,
+ .name = "XCZU2CG",
+ },
+ {
+ .id = 0x20,
+ .name = "XCZU5EV",
+ .evexists = true,
+ },
+ {
+ .id = 0x20,
+ .ver = 0x100,
+ .name = "XCZU5EG",
+ .evexists = true,
+ },
+ {
+ .id = 0x20,
+ .ver = 0x12c,
+ .name = "XCZU5CG",
+ },
+ {
+ .id = 0x21,
+ .name = "XCZU4EV",
+ .evexists = true,
+ },
+ {
+ .id = 0x21,
+ .ver = 0x100,
+ .name = "XCZU4EG",
+ .evexists = true,
+ },
+ {
+ .id = 0x21,
+ .ver = 0x12c,
+ .name = "XCZU4CG",
+ },
+ {
+ .id = 0x30,
+ .name = "XCZU7EV",
+ .evexists = true,
+ },
+ {
+ .id = 0x30,
+ .ver = 0x100,
+ .name = "XCZU7EG",
+ .evexists = true,
+ },
+ {
+ .id = 0x30,
+ .ver = 0x12c,
+ .name = "XCZU7CG",
+ },
+ {
+ .id = 0x38,
+ .name = "XCZU9EG",
+ },
+ {
+ .id = 0x38,
+ .ver = 0x2c,
+ .name = "XCZU9CG",
+ },
+ {
+ .id = 0x39,
+ .name = "XCZU6EG",
+ },
+ {
+ .id = 0x39,
+ .ver = 0x2c,
+ .name = "XCZU6CG",
+ },
+ {
+ .id = 0x40,
+ .name = "XCZU11EG",
+ },
+ {
+ .id = 0x50,
+ .name = "XCZU15EG",
+ },
+ {
+ .id = 0x58,
+ .name = "XCZU19EG",
+ },
+ {
+ .id = 0x59,
+ .name = "XCZU17EG",
+ },
+ {
+ .id = 0x60,
+ .name = "XCZU28DR",
+ },
+ {
+ .id = 0x61,
+ .name = "XCZU21DR",
+ },
+ {
+ .id = 0x62,
+ .name = "XCZU29DR",
+ },
+ {
+ .id = 0x63,
+ .name = "XCZU23DR",
+ },
+ {
+ .id = 0x64,
+ .name = "XCZU27DR",
+ },
+ {
+ .id = 0x65,
+ .name = "XCZU25DR",
+ },
+ {
+ .id = 0x66,
+ .name = "XCZU39DR",
+ },
+ {
+ .id = 0x7d,
+ .name = "XCZU43DR",
+ },
+ {
+ .id = 0x78,
+ .name = "XCZU46DR",
+ },
+ {
+ .id = 0x7f,
+ .name = "XCZU47DR",
+ },
+ {
+ .id = 0x7b,
+ .name = "XCZU48DR",
+ },
+ {
+ .id = 0x7e,
+ .name = "XCZU49DR",
+ },
+};
+
+#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)
+
+#define SILICON_ID_XCK24 0x4714093U
+#define SILICON_ID_XCK26 0x4724093U
+
+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 "XCZUUNKN";
+ }
+#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)) {
+ switch (chipid[0]) {
+ case SILICON_ID_XCK24:
+ return "XCK24";
+ case SILICON_ID_XCK26:
+ return "XCK26";
+ default:
+ return "XCZUUNKN";
+ }
+ }
+
+ if (!zynqmp_devices[i].evexists) {
+ return zynqmp_devices[i].name;
+ }
+
+ if ((ver & ZYNQMP_PL_STATUS_MASK) != 0U) {
+ 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 uint32_t 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 + 1U;
+}
+
+static void zynqmp_print_platform_name(void)
+{
+ uint32_t ver = zynqmp_get_silicon_ver();
+ uint32_t 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;
+ }
+
+ VERBOSE("TF-A running on %s/%s at 0x%x\n",
+ zynqmp_print_silicon_idcode(), label, BL31_BASE);
+ VERBOSE("TF-A running on v%d/RTL%d.%d\n",
+ zynqmp_get_ps_ver(), (rtl & 0xf0) >> 4, rtl & 0xf);
+}
+#else
+static inline void zynqmp_print_platform_name(void) { }
+#endif
+
+uint32_t 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)
+{
+ uint64_t counter_freq;
+
+ /* Configure IPI data for ZynqMP */
+ zynqmp_ipi_config_table_init();
+
+ zynqmp_print_platform_name();
+
+ /* Configure counter frequency */
+ counter_freq = read_cntfrq_el0();
+ if (counter_freq == ZYNQMP_DEFAULT_COUNTER_FREQ) {
+ write_cntfrq_el0(plat_get_syscnt_freq2());
+ }
+
+ generic_delay_timer_init();
+}
+
+uint32_t plat_get_syscnt_freq2(void)
+{
+ uint32_t ver = zynqmp_get_silicon_ver();
+
+ if (ver == ZYNQMP_CSU_VERSION_QEMU) {
+ return 65000000;
+ } else {
+ return mmio_read_32(IOU_SCNTRS_BASEFREQ);
+ }
+}
diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S b/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S
new file mode 100644
index 0000000..d8439f7
--- /dev/null
+++ b/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <drivers/arm/gicv2.h>
+#include <platform_def.h>
+
+ .globl plat_secondary_cold_boot_setup
+ .globl plat_is_my_cpu_primary
+ .globl zynqmp_calc_core_pos
+ .globl plat_my_core_pos
+ .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
+
+ /* ---------------------------------------------------------------------
+ * 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
diff --git a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
new file mode 100644
index 0000000..1d59537
--- /dev/null
+++ b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/dcc.h>
+#include <drivers/console.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <lib/mmio.h>
+
+#include <plat_startup.h>
+#include <plat_private.h>
+#include <zynqmp_def.h>
+
+#include <common/fdt_fixup.h>
+#include <common/fdt_wrappers.h>
+#include <libfdt.h>
+
+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.
+ */
+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));
+ if (type == NON_SECURE) {
+ next_image_info = &bl33_image_ep_info;
+ } else {
+ next_image_info = &bl32_image_ep_info;
+ }
+
+ return next_image_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)
+{
+ uint64_t atf_handoff_addr;
+
+ if (ZYNQMP_CONSOLE_IS(cadence) || (ZYNQMP_CONSOLE_IS(cadence1))) {
+ /* Register the console to provide early debug support */
+ static console_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_FLAG_RUNTIME | CONSOLE_FLAG_BOOT);
+ } else if (ZYNQMP_CONSOLE_IS(dcc)) {
+ /* Initialize the dcc console for debug */
+ int32_t rc = console_dcc_register();
+ if (rc == 0) {
+ panic();
+ }
+ } else {
+ ERROR("BL31: No console device found.\n");
+ }
+ /* 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);
+
+ atf_handoff_addr = mmio_read_32(PMU_GLOBAL_GEN_STORAGE6);
+
+ 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,
+ atf_handoff_addr);
+ if (ret == FSBL_HANDOFF_NO_STRUCT) {
+ bl31_set_default_config();
+ } else if (ret != FSBL_HANDOFF_SUCCESS) {
+ panic();
+ }
+ }
+ if (bl32_image_ep_info.pc != 0) {
+ VERBOSE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc);
+ }
+ if (bl33_image_ep_info.pc != 0) {
+ VERBOSE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc);
+ }
+}
+
+#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
+
+#if (BL31_LIMIT < PLAT_DDR_LOWMEM_MAX)
+static void prepare_dtb(void)
+{
+ void *dtb = (void *)XILINX_OF_BOARD_DTB_ADDR;
+ int ret;
+
+ /* Return if no device tree is detected */
+ if (fdt_check_header(dtb) != 0) {
+ NOTICE("Can't read DT at %p\n", dtb);
+ return;
+ }
+
+ ret = fdt_open_into(dtb, dtb, XILINX_OF_BOARD_DTB_MAX_SIZE);
+ 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, "tf-a", BL31_BASE, BL31_LIMIT - BL31_BASE)) {
+ WARN("Failed to add reserved memory nodes to DT.\n");
+ }
+
+ 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, fdt_blob_size(dtb));
+ INFO("Changed device tree to advertise PSCI and reserved memories.\n");
+}
+#endif
+
+void bl31_platform_setup(void)
+{
+#if (BL31_LIMIT < PLAT_DDR_LOWMEM_MAX)
+ prepare_dtb();
+#endif
+
+ /* Initialize the gic cpu and distributor interfaces */
+ plat_arm_gic_driver_init();
+ plat_arm_gic_init();
+}
+
+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[] = {
+#if (BL31_LIMIT < PLAT_DDR_LOWMEM_MAX)
+ MAP_REGION_FLAT(XILINX_OF_BOARD_DTB_ADDR, XILINX_OF_BOARD_DTB_MAX_SIZE,
+ MT_MEMORY | MT_RW | MT_NS),
+#endif
+ 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);
+}
diff --git a/plat/xilinx/zynqmp/include/plat_ipi.h b/plat/xilinx/zynqmp/include/plat_ipi.h
new file mode 100644
index 0000000..a78f93a
--- /dev/null
+++ b/plat/xilinx/zynqmp/include/plat_ipi.h
@@ -0,0 +1,56 @@
+/*
+ * 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 <stdint.h>
+#include <ipi.h>
+
+/*********************************************************************
+ * 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 8U
+
+#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 */
diff --git a/plat/xilinx/zynqmp/include/plat_macros.S b/plat/xilinx/zynqmp/include/plat_macros.S
new file mode 100644
index 0000000..bf1ff82
--- /dev/null
+++ b/plat/xilinx/zynqmp/include/plat_macros.S
@@ -0,0 +1,28 @@
+/*
+ * 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 <arm_macros.S>
+#include <cci_macros.S>
+#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 */
diff --git a/plat/xilinx/zynqmp/include/plat_pm_common.h b/plat/xilinx/zynqmp/include/plat_pm_common.h
new file mode 100644
index 0000000..a57aebe
--- /dev/null
+++ b/plat/xilinx/zynqmp/include/plat_pm_common.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2013-2020, 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 <stdint.h>
+#include <common/debug.h>
+#include "pm_defs.h"
+
+
+#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_ */
diff --git a/plat/xilinx/zynqmp/include/plat_private.h b/plat/xilinx/zynqmp/include/plat_private.h
new file mode 100644
index 0000000..534777b
--- /dev/null
+++ b/plat/xilinx/zynqmp/include/plat_private.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PRIVATE_H
+#define PLAT_PRIVATE_H
+
+#include <stdint.h>
+
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <drivers/cadence/cdns_uart.h>
+
+void zynqmp_config_setup(void);
+
+uint32_t zynqmp_calc_core_pos(u_register_t mpidr);
+
+/* ZynqMP specific functions */
+uint32_t zynqmp_get_uart_clk(void);
+uint32_t zynqmp_get_bootmode(void);
+
+
+#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
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/xilinx/zynqmp/include/platform_def.h b/plat/xilinx/zynqmp/include/platform_def.h
new file mode 100644
index 0000000..c2d22c2
--- /dev/null
+++ b/plat/xilinx/zynqmp/include/platform_def.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2014-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/utils_def.h>
+
+#include "zynqmp_def.h"
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE 0x440
+
+#define PLATFORM_CORE_COUNT U(4)
+#define PLAT_NUM_POWER_DOMAINS U(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) && !SDEI_SUPPORT
+# define BL31_BASE U(0xfffea000)
+# define BL31_LIMIT U(0x100000000)
+#else
+# define BL31_BASE U(0xfffe5000)
+# define BL31_LIMIT U(0x100000000)
+#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 U(0x60000000)
+# define BL32_LIMIT U(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 U(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 XILINX_OF_BOARD_DTB_ADDR U(0x100000)
+#define XILINX_OF_BOARD_DTB_MAX_SIZE U(0x200000)
+#define PLAT_DDR_LOWMEM_MAX U(0x80000000)
+
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
+#if (BL31_LIMIT < PLAT_DDR_LOWMEM_MAX)
+#define MAX_MMAP_REGIONS 8
+#define MAX_XLAT_TABLES 6
+#else
+#define MAX_MMAP_REGIONS 7
+#define MAX_XLAT_TABLES 5
+#endif
+
+#define CACHE_WRITEBACK_SHIFT 6
+#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
+
+#define ZYNQMP_SDEI_SGI_PRIVATE U(8)
+
+/* Platform macros to support exception handling framework */
+#define PLAT_PRI_BITS U(3)
+#define PLAT_SDEI_CRITICAL_PRI 0x10
+#define PLAT_SDEI_NORMAL_PRI 0x20
+
+#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_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_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) \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, PLAT_SDEI_NORMAL_PRI, grp, \
+ GIC_INTR_CFG_EDGE)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/xilinx/zynqmp/include/zynqmp_def.h b/plat/xilinx/zynqmp/include/zynqmp_def.h
new file mode 100644
index 0000000..428bed5
--- /dev/null
+++ b/plat/xilinx/zynqmp/include/zynqmp_def.h
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ZYNQMP_DEF_H
+#define ZYNQMP_DEF_H
+
+#include <plat/arm/common/smccc_def.h>
+#include <plat/common/common_def.h>
+
+#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)
+
+/* Default counter frequency */
+#define ZYNQMP_DEFAULT_COUNTER_FREQ 0U
+
+/* 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 U(0xFF260000)
+#define IOU_SCNTRS_BASEFREQ (IOU_SCNTRS_BASE + 0x20)
+
+/* APU registers and bitfields */
+#define APU_BASE U(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 U(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 U(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 U(0xF9010000)
+#define BASE_GICC_BASE U(0xF9020000)
+#define BASE_GICH_BASE U(0xF9040000)
+#define BASE_GICV_BASE U(0xF9060000)
+
+#if ZYNQMP_WDT_RESTART
+#define IRQ_SEC_IPI_APU 67
+#define IRQ_TTC3_1 77
+#define TTC3_BASE_ADDR U(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 U(0xFF000000)
+#define ZYNQMP_UART1_BASE U(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 0xFF0U
+#define ZYNQMP_RTL_VER_SHIFT 4
+
+#define ZYNQMP_PS_VER_MASK 0xFU
+#define ZYNQMP_PS_VER_SHIFT 0
+
+#define ZYNQMP_CSU_BASEADDR U(0xFFCA0000)
+#define ZYNQMP_CSU_IDCODE_OFFSET 0x40U
+
+#define ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT 0U
+#define ZYNQMP_CSU_IDCODE_XILINX_ID_MASK (0xFFFU << \
+ ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT)
+#define ZYNQMP_CSU_IDCODE_XILINX_ID 0x093
+
+#define ZYNQMP_CSU_IDCODE_SVD_SHIFT 12U
+#define ZYNQMP_CSU_IDCODE_SVD_MASK (0x7U << \
+ ZYNQMP_CSU_IDCODE_SVD_SHIFT)
+#define ZYNQMP_CSU_IDCODE_DEVICE_CODE_SHIFT 15U
+#define ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK (0xFU << \
+ ZYNQMP_CSU_IDCODE_DEVICE_CODE_SHIFT)
+#define ZYNQMP_CSU_IDCODE_SUB_FAMILY_SHIFT 19U
+#define ZYNQMP_CSU_IDCODE_SUB_FAMILY_MASK (0x3U << \
+ ZYNQMP_CSU_IDCODE_SUB_FAMILY_SHIFT)
+#define ZYNQMP_CSU_IDCODE_FAMILY_SHIFT 21U
+#define ZYNQMP_CSU_IDCODE_FAMILY_MASK (0x7FU << \
+ ZYNQMP_CSU_IDCODE_FAMILY_SHIFT)
+#define ZYNQMP_CSU_IDCODE_FAMILY 0x23
+
+#define ZYNQMP_CSU_IDCODE_REVISION_SHIFT 28U
+#define ZYNQMP_CSU_IDCODE_REVISION_MASK (0xFU << \
+ ZYNQMP_CSU_IDCODE_REVISION_SHIFT)
+#define ZYNQMP_CSU_IDCODE_REVISION 0U
+
+#define ZYNQMP_CSU_VERSION_OFFSET 0x44U
+
+/* Efuse */
+#define EFUSE_BASEADDR U(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)
+#define IOU_SLCR_WDT_CLK_SEL (IOU_SLCR_BASEADDR + 0x300)
+
+/* 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)
+
+/* PMU GGS4 register 4 is used for warm restart boot health status */
+#define PMU_GLOBAL_GEN_STORAGE4 (GGS_BASEADDR + 0x10)
+/* Warm restart boot health status mask */
+#define PM_BOOT_HEALTH_STATUS_MASK U(0x01)
+/* WDT restart scope shift and mask */
+#define RESTART_SCOPE_SHIFT (3)
+#define RESTART_SCOPE_MASK (0x3U << RESTART_SCOPE_SHIFT)
+
+/* AFI registers */
+#define AFIFM6_WRCTRL U(13)
+#define FABRIC_WIDTH U(3)
+
+/* CSUDMA Module Base Address*/
+#define CSUDMA_BASE U(0xFFC80000)
+
+/* RSA-CORE Module Base Address*/
+#define RSA_CORE_BASE U(0xFFCE0000)
+
+#endif /* ZYNQMP_DEF_H */
diff --git a/plat/xilinx/zynqmp/plat_psci.c b/plat/xilinx/zynqmp/plat_psci.c
new file mode 100644
index 0000000..b7408b1
--- /dev/null
+++ b/plat/xilinx/zynqmp/plat_psci.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#include <plat_private.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+
+static uintptr_t zynqmp_sec_entry;
+
+static void zynqmp_cpu_standby(plat_local_state_t cpu_state)
+{
+ VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state);
+
+ dsb();
+ wfi();
+}
+
+static int32_t zynqmp_pwr_domain_on(u_register_t mpidr)
+{
+ uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
+ const struct pm_proc *proc;
+ uint32_t buff[3];
+ enum pm_ret_status ret;
+
+ VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
+
+ if (cpu_id == -1) {
+ return PSCI_E_INTERN_FAIL;
+ }
+ proc = pm_get_proc(cpu_id);
+
+ /* Check the APU proc status before wakeup */
+ ret = pm_get_node_status(proc->node_id, buff);
+ if ((ret != PM_RET_SUCCESS) || (buff[0] == PM_PROC_STATE_SUSPENDING)) {
+ return PSCI_E_INTERN_FAIL;
+ }
+
+ /* 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)
+{
+ uint32_t 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)
+{
+ uint32_t state;
+ uint32_t 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]);
+ }
+ plat_arm_gic_pcpu_init();
+ gicv2_cpuif_enable();
+}
+
+static void zynqmp_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+ uint32_t 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();
+ }
+}
+
+static int32_t zynqmp_validate_power_state(uint32_t power_state,
+ psci_power_state_t *req_state)
+{
+ VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
+
+ uint32_t 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 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,
+ .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;
+}
diff --git a/plat/xilinx/zynqmp/plat_topology.c b/plat/xilinx/zynqmp/plat_topology.c
new file mode 100644
index 0000000..41add9f
--- /dev/null
+++ b/plat/xilinx/zynqmp/plat_topology.c
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stdint.h>
+
+static const uint8_t plat_power_domain_tree_desc[] = {1, 4};
+
+const uint8_t *plat_get_power_domain_tree_desc(void)
+{
+ return plat_power_domain_tree_desc;
+}
diff --git a/plat/xilinx/zynqmp/plat_zynqmp.c b/plat/xilinx/zynqmp/plat_zynqmp.c
new file mode 100644
index 0000000..25ebac6
--- /dev/null
+++ b/plat/xilinx/zynqmp/plat_zynqmp.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_private.h>
+#include <plat/common/platform.h>
+
+int32_t 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);
+}
diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk
new file mode 100644
index 0000000..05adbd0
--- /dev/null
+++ b/plat/xilinx/zynqmp/platform.mk
@@ -0,0 +1,143 @@
+#
+# Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+# Portions copyright (c) 2021-2022, ProvenRun S.A.S. 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
+IPI_CRC_CHECK := 0
+override RESET_TO_BL31 := 1
+override WARMBOOT_ENABLE_DCACHE_EARLY := 1
+
+EL3_EXCEPTION_HANDLING := $(SDEI_SUPPORT)
+
+# pncd SPD requires secure SGI to be handled at EL1
+ifeq (${SPD},pncd)
+ifeq (${ZYNQMP_WDT_RESTART},1)
+$(error "Error: ZYNQMP_WDT_RESTART and SPD=pncd are incompatible")
+endif
+override GICV2_G0_FOR_EL3 := 0
+else
+override GICV2_G0_FOR_EL3 := 1
+endif
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS := 0
+
+WORKAROUND_CVE_2017_5715 := 0
+
+ARM_XLAT_TABLES_LIB_V1 := 1
+$(eval $(call assert_boolean,ARM_XLAT_TABLES_LIB_V1))
+$(eval $(call add_define,ARM_XLAT_TABLES_LIB_V1))
+
+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
+
+
+ifdef ZYNQMP_WDT_RESTART
+ $(eval $(call add_define,ZYNQMP_WDT_RESTART))
+endif
+
+ifdef ZYNQMP_IPI_CRC_CHECK
+ $(warning "ZYNQMP_IPI_CRC_CHECK macro is deprecated...instead please use IPI_CRC_CHECK.")
+endif
+
+ifdef IPI_CRC_CHECK
+ $(eval $(call add_define,IPI_CRC_CHECK))
+endif
+
+ifdef ZYNQMP_SECURE_EFUSES
+ $(eval $(call add_define,ZYNQMP_SECURE_EFUSES))
+endif
+
+PLAT_INCLUDES := -Iinclude/plat/arm/common/ \
+ -Iinclude/plat/arm/common/aarch64/ \
+ -Iplat/xilinx/common/include/ \
+ -Iplat/xilinx/common/ipi_mailbox_service/ \
+ -Iplat/xilinx/zynqmp/include/ \
+ -Iplat/xilinx/zynqmp/pm_service/ \
+
+include lib/libfdt/libfdt.mk
+# Include GICv2 driver files
+include drivers/arm/gic/v2/gicv2.mk
+
+PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \
+ lib/xlat_tables/aarch64/xlat_tables.c \
+ drivers/arm/dcc/dcc_console.c \
+ drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ ${GICV2_SOURCES} \
+ 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/common/aarch64/crash_console_helpers.S \
+ plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S \
+ plat/xilinx/zynqmp/aarch64/zynqmp_common.c
+
+ZYNQMP_CONSOLE ?= cadence
+ifeq (${ZYNQMP_CONSOLE}, $(filter ${ZYNQMP_CONSOLE},cadence cadence0 cadence1 dcc))
+else
+ $(error "Please define ZYNQMP_CONSOLE")
+endif
+$(eval $(call add_define_val,ZYNQMP_CONSOLE,ZYNQMP_CONSOLE_ID_${ZYNQMP_CONSOLE}))
+
+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 \
+ common/fdt_fixup.c \
+ ${LIBFDT_SRCS} \
+ plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c \
+ plat/xilinx/common/pm_service/pm_ipi.c \
+ plat/xilinx/common/plat_startup.c \
+ plat/xilinx/zynqmp/bl31_zynqmp_setup.c \
+ plat/xilinx/zynqmp/plat_psci.c \
+ plat/xilinx/zynqmp/plat_zynqmp.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
+
+ifeq (${SDEI_SUPPORT},1)
+BL31_SOURCES += plat/xilinx/zynqmp/zynqmp_ehf.c \
+ plat/xilinx/zynqmp/zynqmp_sdei.c
+endif
+
+BL31_CPPFLAGS += -fno-jump-tables
+TF_CFLAGS_aarch64 += -mbranch-protection=none
+
+ifneq (${RESET_TO_BL31},1)
+ $(error "Using BL31 as the reset vector is only one option supported on ZynqMP. Please set RESET_TO_BL31 to 1.")
+endif
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
new file mode 100644
index 0000000..e61310a
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
@@ -0,0 +1,3048 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions for clock control.
+ */
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#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 (6U)
+
+#define CLK_PARENTS_ID_LEN (16U)
+#define CLK_TOPOLOGY_NODE_OFFSET (16U)
+#define CLK_TOPOLOGY_PAYLOAD_LEN (12U)
+#define CLK_PARENTS_PAYLOAD_LEN (12U)
+#define CLK_TYPE_SHIFT (2U)
+#define CLK_CLKFLAGS_SHIFT (8U)
+#define CLK_TYPEFLAGS_SHIFT (24U)
+#define CLK_TYPEFLAGS2_SHIFT (4U)
+#define CLK_TYPEFLAGS_BITS_MASK (0xFFU)
+#define CLK_TYPEFLAGS2_BITS_MASK (0x0F00U)
+#define CLK_TYPEFLAGS_BITS (8U)
+
+#define CLK_EXTERNAL_PARENT (PARENT_CLK_EXTERNAL << CLK_PARENTS_ID_LEN)
+
+#define NA_MULT (0U)
+#define NA_DIV (0U)
+#define NA_SHIFT (0U)
+#define NA_WIDTH (0U)
+#define NA_CLK_FLAGS (0U)
+#define NA_TYPE_FLAGS (0U)
+
+/* PLL nodes related definitions */
+#define PLL_PRESRC_MUX_SHIFT (20U)
+#define PLL_PRESRC_MUX_WIDTH (3U)
+#define PLL_POSTSRC_MUX_SHIFT (24U)
+#define PLL_POSTSRC_MUX_WIDTH (3U)
+#define PLL_DIV2_MUX_SHIFT (16U)
+#define PLL_DIV2_MUX_WIDTH (1U)
+#define PLL_BYPASS_MUX_SHIFT (3U)
+#define PLL_BYPASS_MUX_WIDTH (1U)
+
+/* Peripheral nodes related definitions */
+/* Peripheral Clocks */
+#define PERIPH_MUX_SHIFT (0U)
+#define PERIPH_MUX_WIDTH (3U)
+#define PERIPH_DIV1_SHIFT (8U)
+#define PERIPH_DIV1_WIDTH (6U)
+#define PERIPH_DIV2_SHIFT (16U)
+#define PERIPH_DIV2_WIDTH (6U)
+#define PERIPH_GATE_SHIFT (24U)
+#define PERIPH_GATE_WIDTH (1U)
+
+#define USB_GATE_SHIFT (25U)
+
+/* 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 (1U)
+#define PLL_FRAC_OFFSET (8U)
+#define PLL_FRAC_MODE (1U)
+#define PLL_INT_MODE (0U)
+#define PLL_FRAC_MODE_MASK (0x80000000U)
+#define PLL_FRAC_MODE_SHIFT (31U)
+#define PLL_FRAC_DATA_MASK (0xFFFFU)
+#define PLL_FRAC_DATA_SHIFT (0U)
+#define PLL_FBDIV_MASK (0x7F00U)
+#define PLL_FBDIV_WIDTH (7U)
+#define PLL_FBDIV_SHIFT (8U)
+
+#define CLK_PLL_RESET_ASSERT (1U)
+#define CLK_PLL_RESET_RELEASE (2U)
+#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_DIV1 \
+ { \
+ .type = TYPE_DIV1, \
+ .offset = PERIPH_DIV1_SHIFT, \
+ .width = PERIPH_DIV1_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 GENERIC_DIV2 \
+ { \
+ .type = TYPE_DIV2, \
+ .offset = PERIPH_DIV2_SHIFT, \
+ .width = PERIPH_DIV2_WIDTH, \
+ .clkflags = CLK_SET_RATE_NO_REPARENT | \
+ CLK_SET_RATE_PARENT | \
+ 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;
+ uint32_t control_reg;
+ uint32_t 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_DIV1,
+};
+
+static struct pm_clock_node generic_mux_div_gate_nodes[] = {
+ GENERIC_MUX,
+ GENERIC_DIV1,
+ GENERIC_GATE,
+};
+
+static struct pm_clock_node generic_mux_div_unused_gate_nodes[] = {
+ GENERIC_MUX,
+ GENERIC_DIV1,
+ IGNORE_UNUSED_GATE,
+};
+
+static struct pm_clock_node generic_mux_div_div_gate_nodes[] = {
+ GENERIC_MUX,
+ GENERIC_DIV1,
+ GENERIC_DIV2,
+ 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_IS_BASIC,
+ .typeflags = CLK_FRAC,
+ .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_IS_BASIC,
+ .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO |
+ CLK_FRAC,
+ .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_IS_BASIC,
+ .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO |
+ CLK_FRAC,
+ .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_DIV1,
+ GENERIC_DIV2,
+ {
+ .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_ref_ungated_nodes[] = {
+ GENERIC_MUX,
+ {
+ .type = TYPE_DIV1,
+ .offset = 8,
+ .width = 6,
+ .clkflags = CLK_SET_RATE_NO_REPARENT | 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_SET_RATE_NO_REPARENT | CLK_IS_BASIC |
+ CLK_SET_RATE_PARENT,
+ .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node gem0_ref_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = 1,
+ .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 gem1_ref_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = 6,
+ .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 gem2_ref_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = 11,
+ .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 gem3_ref_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = 16,
+ .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 gem_tx_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 gem_rx_nodes[] = {
+ {
+ .type = TYPE_GATE,
+ .offset = 26,
+ .width = PERIPH_GATE_WIDTH,
+ .clkflags = 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_UNGATED] = {
+ .name = "gem0_ref_ung",
+ .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_ref_ungated_nodes,
+ .num_nodes = ARRAY_SIZE(gem_ref_ungated_nodes),
+ },
+ [CLK_GEM1_REF_UNGATED] = {
+ .name = "gem1_ref_ung",
+ .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_ref_ungated_nodes,
+ .num_nodes = ARRAY_SIZE(gem_ref_ungated_nodes),
+ },
+ [CLK_GEM2_REF_UNGATED] = {
+ .name = "gem2_ref_ung",
+ .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_ref_ungated_nodes,
+ .num_nodes = ARRAY_SIZE(gem_ref_ungated_nodes),
+ },
+ [CLK_GEM3_REF_UNGATED] = {
+ .name = "gem3_ref_ung",
+ .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_ref_ungated_nodes,
+ .num_nodes = ARRAY_SIZE(gem_ref_ungated_nodes),
+ },
+ [CLK_GEM0_REF] = {
+ .name = "gem0_ref",
+ .control_reg = IOU_SLCR_GEM_CLK_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GEM0_REF_UNGATED |
+ (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN),
+ EXT_CLK_GEM0_TX_EMIO | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem0_ref_nodes,
+ .num_nodes = ARRAY_SIZE(gem0_ref_nodes),
+ },
+ [CLK_GEM1_REF] = {
+ .name = "gem1_ref",
+ .control_reg = IOU_SLCR_GEM_CLK_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GEM1_REF_UNGATED |
+ (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN),
+ EXT_CLK_GEM1_TX_EMIO | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem1_ref_nodes,
+ .num_nodes = ARRAY_SIZE(gem1_ref_nodes),
+ },
+ [CLK_GEM2_REF] = {
+ .name = "gem2_ref",
+ .control_reg = IOU_SLCR_GEM_CLK_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GEM2_REF_UNGATED |
+ (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN),
+ EXT_CLK_GEM2_TX_EMIO | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem2_ref_nodes,
+ .num_nodes = ARRAY_SIZE(gem2_ref_nodes),
+ },
+ [CLK_GEM3_REF] = {
+ .name = "gem3_ref",
+ .control_reg = IOU_SLCR_GEM_CLK_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GEM3_REF_UNGATED |
+ (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN),
+ EXT_CLK_GEM3_TX_EMIO | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem3_ref_nodes,
+ .num_nodes = ARRAY_SIZE(gem3_ref_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 = &timestamp_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),
+ },
+ [CLK_GEM0_TX] = {
+ .name = "gem0_tx",
+ .control_reg = CRL_APB_GEM0_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GEM0_REF,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_tx_nodes,
+ .num_nodes = ARRAY_SIZE(gem_tx_nodes),
+ },
+ [CLK_GEM1_TX] = {
+ .name = "gem1_tx",
+ .control_reg = CRL_APB_GEM1_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GEM1_REF,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_tx_nodes,
+ .num_nodes = ARRAY_SIZE(gem_tx_nodes),
+ },
+ [CLK_GEM2_TX] = {
+ .name = "gem2_tx",
+ .control_reg = CRL_APB_GEM2_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GEM2_REF,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_tx_nodes,
+ .num_nodes = ARRAY_SIZE(gem_tx_nodes),
+ },
+ [CLK_GEM3_TX] = {
+ .name = "gem3_tx",
+ .control_reg = CRL_APB_GEM3_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GEM3_REF,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_tx_nodes,
+ .num_nodes = ARRAY_SIZE(gem_tx_nodes),
+ },
+ [CLK_GEM0_RX] = {
+ .name = "gem0_rx",
+ .control_reg = CRL_APB_GEM0_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ EXT_CLK_GEM0_RX_EMIO | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_rx_nodes,
+ .num_nodes = ARRAY_SIZE(gem_rx_nodes),
+ },
+ [CLK_GEM1_RX] = {
+ .name = "gem1_rx",
+ .control_reg = CRL_APB_GEM1_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ EXT_CLK_GEM1_RX_EMIO | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_rx_nodes,
+ .num_nodes = ARRAY_SIZE(gem_rx_nodes),
+ },
+ [CLK_GEM2_RX] = {
+ .name = "gem2_rx",
+ .control_reg = CRL_APB_GEM2_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ EXT_CLK_GEM2_RX_EMIO | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_rx_nodes,
+ .num_nodes = ARRAY_SIZE(gem_rx_nodes),
+ },
+ [CLK_GEM3_RX] = {
+ .name = "gem3_rx",
+ .control_reg = CRL_APB_GEM3_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ EXT_CLK_GEM3_RX_EMIO | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_rx_nodes,
+ .num_nodes = ARRAY_SIZE(gem_rx_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_FPD_WDT] = {
+ .name = "fpd_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),
+ },
+ [CLK_LPD_WDT] = {
+ .name = "lpd_wdt",
+ .control_reg = IOU_SLCR_WDT_CLK_SEL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_LPD_LSBUS,
+ EXT_CLK_SWDT1 | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &wdt_nodes,
+ .num_nodes = ARRAY_SIZE(wdt_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_TX_EMIO)] = {
+ .name = "gem0_tx_ext",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_GEM1_TX_EMIO)] = {
+ .name = "gem1_tx_ext",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_GEM2_TX_EMIO)] = {
+ .name = "gem2_tx_ext",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_GEM3_TX_EMIO)] = {
+ .name = "gem3_tx_ext",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_GEM0_RX_EMIO)] = {
+ .name = "gem0_rx_ext",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_GEM1_RX_EMIO)] = {
+ .name = "gem1_rx_ext",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_GEM2_RX_EMIO)] = {
+ .name = "gem2_rx_ext",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_GEM3_RX_EMIO)] = {
+ .name = "gem3_rx_ext",
+ },
+ [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_GTGREF0_REF,
+ CLK_LPD_SWITCH,
+ 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(uint32_t clock_id)
+{
+ unsigned int i;
+
+ for (i = 0U; 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 uint32_t pm_clock_type(uint32_t 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(uint32_t *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.
+ */
+void pm_api_clock_get_name(uint32_t clock_id, char *name)
+{
+ if (clock_id == CLK_MAX) {
+ memcpy(name, END_OF_CLK, sizeof(END_OF_CLK) > CLK_NAME_LEN ?
+ CLK_NAME_LEN : sizeof(END_OF_CLK));
+ } 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);
+ }
+}
+
+/**
+ * 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(uint32_t clock_id,
+ uint32_t index,
+ uint32_t *topology)
+{
+ struct pm_clock_node *clock_nodes;
+ uint8_t num_nodes;
+ uint32_t i;
+ uint16_t typeflags;
+
+ 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;
+ typeflags = clock_nodes[index + i].typeflags;
+ topology[i] |= (typeflags & CLK_TYPEFLAGS_BITS_MASK) <<
+ CLK_TYPEFLAGS_SHIFT;
+ topology[i] |= (typeflags & CLK_TYPEFLAGS2_BITS_MASK) >>
+ (CLK_TYPEFLAGS_BITS - CLK_TYPEFLAGS2_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(uint32_t clock_id,
+ uint32_t *mul,
+ uint32_t *div)
+{
+ struct pm_clock_node *clock_nodes;
+ uint8_t num_nodes;
+ uint32_t 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(uint32_t clock_id,
+ uint32_t index,
+ uint32_t *parents)
+{
+ uint32_t 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 < 3U; 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(uint32_t 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;
+}
+
+/**
+ * pm_api_clock_get_max_divisor - PM call to get max divisor
+ * @clock_id Clock ID
+ * @div_type Divisor Type (TYPE_DIV1 or TYPE_DIV2)
+ * @max_div Maximum supported divisor
+ *
+ * This function is used by master to get maximum supported value.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_api_clock_get_max_divisor(enum clock_id clock_id,
+ uint8_t div_type,
+ uint32_t *max_div)
+{
+ uint32_t i;
+ struct pm_clock_node *nodes;
+
+ if (clock_id >= CLK_MAX_OUTPUT_CLK) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ nodes = *clocks[clock_id].nodes;
+ for (i = 0; i < clocks[clock_id].num_nodes; i++) {
+ if (nodes[i].type == div_type) {
+ if (CLK_DIVIDER_POWER_OF_TWO &
+ nodes[i].typeflags) {
+ *max_div = (1U << (BIT(nodes[i].width) - 1U));
+ } else {
+ *max_div = BIT(nodes[i].width) - 1U;
+ }
+ return PM_RET_SUCCESS;
+ }
+ }
+
+ return PM_RET_ERROR_ARGS;
+}
+
+/**
+ * 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 == NULL) {
+ 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 == NULL) {
+ 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,
+ uint32_t *state)
+{
+ enum pm_ret_status status;
+ enum pm_pll_mode mode;
+
+ if ((pll == NULL) || !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,
+ uint32_t parent_index)
+{
+ if (pll == NULL) {
+ 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,
+ uint32_t *parent_index)
+{
+ if (pll == NULL) {
+ 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,
+ uint32_t mode)
+{
+ struct pm_pll *pll = pm_clock_get_pll(clock_id);
+
+ if ((pll == NULL) || (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,
+ uint32_t *mode)
+{
+ struct pm_pll *pll = pm_clock_get_pll(clock_id);
+
+ if ((pll == NULL) || !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(uint32_t 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(uint32_t 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;
+ } else {
+ /* To fix the misra 15.7 warning */
+ }
+ }
+
+ return 0;
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.h b/plat/xilinx/zynqmp/pm_service/pm_api_clock.h
new file mode 100644
index 0000000..cc0dacc
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.h
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2018-2020, 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 <lib/utils_def.h>
+
+#include "pm_common.h"
+
+#define CLK_NAME_LEN (15U)
+#define MAX_PARENTS (100U)
+#define CLK_NA_PARENT -1
+#define CLK_DUMMY_PARENT -2
+
+/* Flags for parent id */
+#define PARENT_CLK_SELF (0U)
+#define PARENT_CLK_NODE1 (1U)
+#define PARENT_CLK_NODE2 (2U)
+#define PARENT_CLK_NODE3 (3U)
+#define PARENT_CLK_NODE4 (4U)
+#define PARENT_CLK_EXTERNAL (5U)
+#define PARENT_CLK_MIO0_MIO77 (6U)
+
+#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_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 CLK_FRAC BIT(8)
+
+#define END_OF_CLK "END_OF_CLK"
+
+//CLock Ids
+enum clock_id {
+ CLK_IOPLL = (0U),
+ CLK_RPLL = (1U),
+ CLK_APLL = (2U),
+ CLK_DPLL = (3U),
+ CLK_VPLL = (4U),
+ CLK_IOPLL_TO_FPD = (5U),
+ CLK_RPLL_TO_FPD = (6U),
+ CLK_APLL_TO_LPD = (7U),
+ CLK_DPLL_TO_LPD = (8U),
+ CLK_VPLL_TO_LPD = (9U),
+ CLK_ACPU = (10U),
+ CLK_ACPU_HALF = (11U),
+ CLK_DBG_FPD = (12U),
+ CLK_DBG_LPD = (13U),
+ CLK_DBG_TRACE = (14U),
+ CLK_DBG_TSTMP = (15U),
+ CLK_DP_VIDEO_REF = (16U),
+ CLK_DP_AUDIO_REF = (17U),
+ CLK_DP_STC_REF = (18U),
+ CLK_GDMA_REF = (19U),
+ CLK_DPDMA_REF = (20U),
+ CLK_DDR_REF = (21U),
+ CLK_SATA_REF = (22U),
+ CLK_PCIE_REF = (23U),
+ CLK_GPU_REF = (24U),
+ CLK_GPU_PP0_REF = (25U),
+ CLK_GPU_PP1_REF = (26U),
+ CLK_TOPSW_MAIN = (27U),
+ CLK_TOPSW_LSBUS = (28U),
+ CLK_GTGREF0_REF = (29U),
+ CLK_LPD_SWITCH = (30U),
+ CLK_LPD_LSBUS = (31U),
+ CLK_USB0_BUS_REF = (32U),
+ CLK_USB1_BUS_REF = (33U),
+ CLK_USB3_DUAL_REF = (34U),
+ CLK_USB0 = (35U),
+ CLK_USB1 = (36U),
+ CLK_CPU_R5 = (37U),
+ CLK_CPU_R5_CORE = (38U),
+ CLK_CSU_SPB = (39U),
+ CLK_CSU_PLL = (40U),
+ CLK_PCAP = (41U),
+ CLK_IOU_SWITCH = (42U),
+ CLK_GEM_TSU_REF = (43U),
+ CLK_GEM_TSU = (44U),
+ CLK_GEM0_TX = (45U),
+ CLK_GEM1_TX = (46U),
+ CLK_GEM2_TX = (47U),
+ CLK_GEM3_TX = (48U),
+ CLK_GEM0_RX = (49U),
+ CLK_GEM1_RX = (50U),
+ CLK_GEM2_RX = (51U),
+ CLK_GEM3_RX = (52U),
+ CLK_QSPI_REF = (53U),
+ CLK_SDIO0_REF = (54U),
+ CLK_SDIO1_REF = (55U),
+ CLK_UART0_REF = (56U),
+ CLK_UART1_REF = (57U),
+ CLK_SPI0_REF = (58U),
+ CLK_SPI1_REF = (59U),
+ CLK_NAND_REF = (60U),
+ CLK_I2C0_REF = (61U),
+ CLK_I2C1_REF = (62U),
+ CLK_CAN0_REF = (63U),
+ CLK_CAN1_REF = (64U),
+ CLK_CAN0 = (65U),
+ CLK_CAN1 = (66U),
+ CLK_DLL_REF = (67U),
+ CLK_ADMA_REF = (68U),
+ CLK_TIMESTAMP_REF = (69U),
+ CLK_AMS_REF = (70U),
+ CLK_PL0_REF = (71U),
+ CLK_PL1_REF = (72U),
+ CLK_PL2_REF = (73U),
+ CLK_PL3_REF = (74U),
+ CLK_FPD_WDT = (75U),
+ CLK_IOPLL_INT = (76U),
+ CLK_IOPLL_PRE_SRC = (77U),
+ CLK_IOPLL_HALF = (78U),
+ CLK_IOPLL_INT_MUX = (79U),
+ CLK_IOPLL_POST_SRC = (80U),
+ CLK_RPLL_INT = (81U),
+ CLK_RPLL_PRE_SRC = (82U),
+ CLK_RPLL_HALF = (83U),
+ CLK_RPLL_INT_MUX = (84U),
+ CLK_RPLL_POST_SRC = (85U),
+ CLK_APLL_INT = (86U),
+ CLK_APLL_PRE_SRC = (87U),
+ CLK_APLL_HALF = (88U),
+ CLK_APLL_INT_MUX = (89U),
+ CLK_APLL_POST_SRC = (90U),
+ CLK_DPLL_INT = (91U),
+ CLK_DPLL_PRE_SRC = (92U),
+ CLK_DPLL_HALF = (93U),
+ CLK_DPLL_INT_MUX = (94U),
+ CLK_DPLL_POST_SRC = (95U),
+ CLK_VPLL_INT = (96U),
+ CLK_VPLL_PRE_SRC = (97U),
+ CLK_VPLL_HALF = (98U),
+ CLK_VPLL_INT_MUX = (99U),
+ CLK_VPLL_POST_SRC = (100U),
+ CLK_CAN0_MIO = (101U),
+ CLK_CAN1_MIO = (102U),
+ CLK_ACPU_FULL = (103U),
+ CLK_GEM0_REF = (104U),
+ CLK_GEM1_REF = (105U),
+ CLK_GEM2_REF = (106U),
+ CLK_GEM3_REF = (107U),
+ CLK_GEM0_REF_UNGATED = (108U),
+ CLK_GEM1_REF_UNGATED = (109U),
+ CLK_GEM2_REF_UNGATED = (110U),
+ CLK_GEM3_REF_UNGATED = (111U),
+ CLK_LPD_WDT = (112U),
+ END_OF_OUTPUT_CLKS = (113U),
+};
+
+#define CLK_MAX_OUTPUT_CLK END_OF_OUTPUT_CLKS
+
+//External clock ids
+enum {
+ EXT_CLK_PSS_REF = END_OF_OUTPUT_CLKS,
+ EXT_CLK_VIDEO = (114U),
+ EXT_CLK_PSS_ALT_REF = (115U),
+ EXT_CLK_AUX_REF = (116U),
+ EXT_CLK_GT_CRX_REF = (117U),
+ EXT_CLK_SWDT0 = (118U),
+ EXT_CLK_SWDT1 = (119U),
+ EXT_CLK_GEM0_TX_EMIO = (120U),
+ EXT_CLK_GEM1_TX_EMIO = (121U),
+ EXT_CLK_GEM2_TX_EMIO = (122U),
+ EXT_CLK_GEM3_TX_EMIO = (123U),
+ EXT_CLK_GEM0_RX_EMIO = (124U),
+ EXT_CLK_GEM1_RX_EMIO = (125U),
+ EXT_CLK_GEM2_RX_EMIO = (126U),
+ EXT_CLK_GEM3_RX_EMIO = (127U),
+ EXT_CLK_MIO50_OR_MIO51 = (128U),
+ EXT_CLK_MIO0 = (129U),
+ EXT_CLK_MIO1 = (130U),
+ EXT_CLK_MIO2 = (131U),
+ EXT_CLK_MIO3 = (132U),
+ EXT_CLK_MIO4 = (133U),
+ EXT_CLK_MIO5 = (134U),
+ EXT_CLK_MIO6 = (135U),
+ EXT_CLK_MIO7 = (136U),
+ EXT_CLK_MIO8 = (137U),
+ EXT_CLK_MIO9 = (138U),
+ EXT_CLK_MIO10 = (139U),
+ EXT_CLK_MIO11 = (140U),
+ EXT_CLK_MIO12 = (141U),
+ EXT_CLK_MIO13 = (142U),
+ EXT_CLK_MIO14 = (143U),
+ EXT_CLK_MIO15 = (144U),
+ EXT_CLK_MIO16 = (145U),
+ EXT_CLK_MIO17 = (146U),
+ EXT_CLK_MIO18 = (147U),
+ EXT_CLK_MIO19 = (148U),
+ EXT_CLK_MIO20 = (149U),
+ EXT_CLK_MIO21 = (150U),
+ EXT_CLK_MIO22 = (151U),
+ EXT_CLK_MIO23 = (152U),
+ EXT_CLK_MIO24 = (153U),
+ EXT_CLK_MIO25 = (154U),
+ EXT_CLK_MIO26 = (155U),
+ EXT_CLK_MIO27 = (156U),
+ EXT_CLK_MIO28 = (157U),
+ EXT_CLK_MIO29 = (158U),
+ EXT_CLK_MIO30 = (159U),
+ EXT_CLK_MIO31 = (160U),
+ EXT_CLK_MIO32 = (161U),
+ EXT_CLK_MIO33 = (162U),
+ EXT_CLK_MIO34 = (163U),
+ EXT_CLK_MIO35 = (164U),
+ EXT_CLK_MIO36 = (165U),
+ EXT_CLK_MIO37 = (166U),
+ EXT_CLK_MIO38 = (167U),
+ EXT_CLK_MIO39 = (168U),
+ EXT_CLK_MIO40 = (169U),
+ EXT_CLK_MIO41 = (170U),
+ EXT_CLK_MIO42 = (171U),
+ EXT_CLK_MIO43 = (172U),
+ EXT_CLK_MIO44 = (173U),
+ EXT_CLK_MIO45 = (174U),
+ EXT_CLK_MIO46 = (175U),
+ EXT_CLK_MIO47 = (176U),
+ EXT_CLK_MIO48 = (177U),
+ EXT_CLK_MIO49 = (178U),
+ EXT_CLK_MIO50 = (179U),
+ EXT_CLK_MIO51 = (180U),
+ EXT_CLK_MIO52 = (181U),
+ EXT_CLK_MIO53 = (182U),
+ EXT_CLK_MIO54 = (183U),
+ EXT_CLK_MIO55 = (184U),
+ EXT_CLK_MIO56 = (185U),
+ EXT_CLK_MIO57 = (186U),
+ EXT_CLK_MIO58 = (187U),
+ EXT_CLK_MIO59 = (188U),
+ EXT_CLK_MIO60 = (189U),
+ EXT_CLK_MIO61 = (190U),
+ EXT_CLK_MIO62 = (191U),
+ EXT_CLK_MIO63 = (192U),
+ EXT_CLK_MIO64 = (193U),
+ EXT_CLK_MIO65 = (194U),
+ EXT_CLK_MIO66 = (195U),
+ EXT_CLK_MIO67 = (196U),
+ EXT_CLK_MIO68 = (197U),
+ EXT_CLK_MIO69 = (198U),
+ EXT_CLK_MIO70 = (199U),
+ EXT_CLK_MIO71 = (200U),
+ EXT_CLK_MIO72 = (201U),
+ EXT_CLK_MIO73 = (202U),
+ EXT_CLK_MIO74 = (203U),
+ EXT_CLK_MIO75 = (204U),
+ EXT_CLK_MIO76 = (205U),
+ EXT_CLK_MIO77 = (206U),
+ END_OF_CLKS = (207U),
+};
+
+#define CLK_MAX 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(uint32_t clock_id, enum pm_clock_div_id div_id);
+
+void pm_api_clock_get_name(uint32_t clock_id, char *name);
+enum pm_ret_status pm_api_clock_get_num_clocks(uint32_t *nclocks);
+enum pm_ret_status pm_api_clock_get_topology(uint32_t clock_id,
+ uint32_t index,
+ uint32_t *topology);
+enum pm_ret_status pm_api_clock_get_fixedfactor_params(uint32_t clock_id,
+ uint32_t *mul,
+ uint32_t *div);
+enum pm_ret_status pm_api_clock_get_parents(uint32_t clock_id,
+ uint32_t index,
+ uint32_t *parents);
+enum pm_ret_status pm_api_clock_get_attributes(uint32_t clock_id,
+ uint32_t *attr);
+enum pm_ret_status pm_api_clock_get_max_divisor(enum clock_id clock_id,
+ uint8_t div_type,
+ uint32_t *max_div);
+
+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(uint32_t 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,
+ uint32_t *state);
+enum pm_ret_status pm_clock_pll_set_parent(struct pm_pll *pll,
+ enum clock_id clock_id,
+ uint32_t parent_index);
+enum pm_ret_status pm_clock_pll_get_parent(struct pm_pll *pll,
+ enum clock_id clock_id,
+ uint32_t *parent_index);
+enum pm_ret_status pm_clock_set_pll_mode(enum clock_id clock_id,
+ uint32_t mode);
+enum pm_ret_status pm_clock_get_pll_mode(enum clock_id clock_id,
+ uint32_t *mode);
+
+#endif /* PM_API_CLOCK_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c
new file mode 100644
index 0000000..c0bfd51
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c
@@ -0,0 +1,767 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions for ioctl.
+ */
+
+#include <arch_helpers.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <zynqmp_def.h>
+
+#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(uint32_t *mode)
+{
+ uint32_t val;
+
+ val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL);
+ val &= ZYNQMP_SLSPLIT_MASK;
+ if (val == 0U) {
+ *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(uint32_t mode)
+{
+ uint32_t 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,
+ uint32_t value)
+{
+ uint32_t 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(uint32_t value)
+{
+ uint32_t 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(uint32_t type,
+ uint32_t 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,
+ uint32_t value)
+{
+ uint32_t 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,
+ uint32_t type)
+{
+ uint32_t 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,
+ uint32_t value)
+{
+ uint32_t shift;
+ enum pm_ret_status ret;
+ uint32_t val, mask;
+
+ if (nid == NODE_SD_0) {
+ shift = 0;
+ mask = ZYNQMP_SD0_DLL_RST_MASK;
+ } else if (nid == NODE_SD_1) {
+ shift = ZYNQMP_SD_TAP_OFFSET;
+ mask = ZYNQMP_SD1_DLL_RST_MASK;
+ } else {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ ret = pm_mmio_read(ZYNQMP_SD_DLL_CTRL, &val);
+ if (ret != PM_RET_SUCCESS) {
+ return ret;
+ }
+
+ if ((val & mask) == 0U) {
+ 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;
+ }
+
+ if (value == 0U) {
+ ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
+ (ZYNQMP_SD_ITAPDLYENA_MASK <<
+ shift), 0);
+ } else {
+ 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), 0);
+
+ 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:
+ if ((val & mask) == 0) {
+ (void)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
+ (uint32_t pll, uint32_t 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
+ (uint32_t pll, uint32_t *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
+ (uint32_t pll, uint32_t 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
+ (uint32_t pll, uint32_t *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(uint32_t index,
+ uint32_t 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(uint32_t index,
+ uint32_t *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(uint32_t index,
+ uint32_t 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(uint32_t index,
+ uint32_t value)
+{
+ uint32_t mask;
+ uint32_t regarr[] = {0xFD360000U,
+ 0xFD360014U,
+ 0xFD370000U,
+ 0xFD370014U,
+ 0xFD380000U,
+ 0xFD380014U,
+ 0xFD390000U,
+ 0xFD390014U,
+ 0xFD3a0000U,
+ 0xFD3a0014U,
+ 0xFD3b0000U,
+ 0xFD3b0014U,
+ 0xFF9b0000U,
+ 0xFF9b0014U,
+ 0xFD615000U,
+ 0xFF419000U,
+ };
+
+ 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(uint32_t index,
+ uint32_t *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(uint32_t value)
+{
+ return pm_mmio_write(PMU_GLOBAL_GEN_STORAGE4,
+ 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,
+ uint32_t ioctl_id,
+ uint32_t arg1,
+ uint32_t arg2,
+ uint32_t *value)
+{
+ enum pm_ret_status ret;
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ 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:
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD5(payload, PM_IOCTL, nid, ioctl_id, arg1, arg2);
+
+ ret = pm_ipi_send_sync(primary_proc, payload, value, 1);
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pm_update_ioctl_bitmask() - API to get supported IOCTL ID mask
+ * @bit_mask Returned bit mask of supported IOCTL IDs
+ */
+enum pm_ret_status atf_ioctl_bitmask(uint32_t *bit_mask)
+{
+ uint8_t supported_ids[] = {
+ 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_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_ULPI_RESET,
+ IOCTL_SET_BOOT_HEALTH_STATUS,
+ IOCTL_AFI,
+ };
+ uint8_t i, ioctl_id;
+ int32_t ret;
+
+ for (i = 0U; i < ARRAY_SIZE(supported_ids); i++) {
+ ioctl_id = supported_ids[i];
+ if (ioctl_id >= 64U) {
+ return PM_RET_ERROR_NOTSUPPORTED;
+ }
+ ret = check_api_dependency(ioctl_id);
+ if (ret == PM_RET_SUCCESS) {
+ bit_mask[ioctl_id / 32U] |= BIT(ioctl_id % 32U);
+ }
+ }
+
+ return PM_RET_SUCCESS;
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h
new file mode 100644
index 0000000..3b0d6ee
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018-2022, 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 = 0,
+ IOCTL_SET_RPU_OPER_MODE = 1,
+ IOCTL_RPU_BOOT_ADDR_CONFIG = 2,
+ IOCTL_TCM_COMB_CONFIG = 3,
+ IOCTL_SET_TAPDELAY_BYPASS = 4,
+ IOCTL_SET_SGMII_MODE = 5,
+ IOCTL_SD_DLL_RESET = 6,
+ IOCTL_SET_SD_TAPDELAY = 7,
+ /* Ioctl for clock driver */
+ IOCTL_SET_PLL_FRAC_MODE = 8,
+ IOCTL_GET_PLL_FRAC_MODE = 9,
+ IOCTL_SET_PLL_FRAC_DATA = 10,
+ IOCTL_GET_PLL_FRAC_DATA = 11,
+ IOCTL_WRITE_GGS = 12,
+ IOCTL_READ_GGS = 13,
+ IOCTL_WRITE_PGGS = 14,
+ IOCTL_READ_PGGS = 15,
+ /* IOCTL for ULPI reset */
+ IOCTL_ULPI_RESET = 16,
+ /* Set healthy bit value */
+ IOCTL_SET_BOOT_HEALTH_STATUS = 17,
+ IOCTL_AFI = 18,
+ /* Probe counter read/write */
+ IOCTL_PROBE_COUNTER_READ = 19,
+ IOCTL_PROBE_COUNTER_WRITE = 20,
+ IOCTL_OSPI_MUX_SELECT = 21,
+ /* IOCTL for USB power request */
+ IOCTL_USB_SET_STATE = 22,
+ /* IOCTL to get last reset reason */
+ IOCTL_GET_LAST_RESET_REASON = 23,
+ /* AI engine NPI ISR clear */
+ IOCTL_AIE_ISR_CLEAR = 24,
+ /* Register SGI to ATF */
+ IOCTL_REGISTER_SGI = 25,
+};
+
+//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,
+ uint32_t ioctl_id,
+ uint32_t arg1,
+ uint32_t arg2,
+ uint32_t *value);
+enum pm_ret_status atf_ioctl_bitmask(uint32_t *bit_mask);
+#endif /* PM_API_IOCTL_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c
new file mode 100644
index 0000000..8f37341
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c
@@ -0,0 +1,2112 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions for pin control.
+ */
+
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <plat/common/platform.h>
+
+#include "pm_api_pinctrl.h"
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_common.h"
+#include "pm_ipi.h"
+
+struct pinctrl_function {
+ char name[FUNCTION_NAME_LEN];
+ uint16_t group_base;
+ uint8_t group_size;
+ uint8_t regval;
+};
+
+/* Max groups for one pin */
+#define MAX_PIN_GROUPS (13U)
+
+struct zynqmp_pin_group {
+ uint16_t (*groups)[];
+};
+
+static struct pinctrl_function pinctrl_functions[MAX_FUNCTION] = {
+ [PINCTRL_FUNC_CAN0] = {
+ .name = "can0",
+ .regval = 0x20,
+ .group_base = PINCTRL_GRP_CAN0_0,
+ .group_size = PINCTRL_GRP_CAN0_18 - PINCTRL_GRP_CAN0_0 + 1U,
+ },
+ [PINCTRL_FUNC_CAN1] = {
+ .name = "can1",
+ .regval = 0x20,
+ .group_base = PINCTRL_GRP_CAN1_0,
+ .group_size = PINCTRL_GRP_CAN1_19 - PINCTRL_GRP_CAN1_0 + 1U,
+ },
+ [PINCTRL_FUNC_ETHERNET0] = {
+ .name = "ethernet0",
+ .regval = 0x02,
+ .group_base = PINCTRL_GRP_ETHERNET0_0,
+ .group_size = PINCTRL_GRP_ETHERNET0_0 - PINCTRL_GRP_ETHERNET0_0 + 1U,
+ },
+ [PINCTRL_FUNC_ETHERNET1] = {
+ .name = "ethernet1",
+ .regval = 0x02,
+ .group_base = PINCTRL_GRP_ETHERNET1_0,
+ .group_size = PINCTRL_GRP_ETHERNET1_0 - PINCTRL_GRP_ETHERNET1_0 + 1U,
+ },
+ [PINCTRL_FUNC_ETHERNET2] = {
+ .name = "ethernet2",
+ .regval = 0x02,
+ .group_base = PINCTRL_GRP_ETHERNET2_0,
+ .group_size = PINCTRL_GRP_ETHERNET2_0 - PINCTRL_GRP_ETHERNET2_0 + 1U,
+ },
+ [PINCTRL_FUNC_ETHERNET3] = {
+ .name = "ethernet3",
+ .regval = 0x02,
+ .group_base = PINCTRL_GRP_ETHERNET3_0,
+ .group_size = PINCTRL_GRP_ETHERNET3_0 - PINCTRL_GRP_ETHERNET3_0 + 1U,
+ },
+ [PINCTRL_FUNC_GEMTSU0] = {
+ .name = "gemtsu0",
+ .regval = 0x02,
+ .group_base = PINCTRL_GRP_GEMTSU0_0,
+ .group_size = PINCTRL_GRP_GEMTSU0_2 - PINCTRL_GRP_GEMTSU0_0 + 1U,
+ },
+ [PINCTRL_FUNC_GPIO0] = {
+ .name = "gpio0",
+ .regval = 0x00,
+ .group_base = PINCTRL_GRP_GPIO0_0,
+ .group_size = PINCTRL_GRP_GPIO0_77 - PINCTRL_GRP_GPIO0_0 + 1U,
+ },
+ [PINCTRL_FUNC_I2C0] = {
+ .name = "i2c0",
+ .regval = 0x40,
+ .group_base = PINCTRL_GRP_I2C0_0,
+ .group_size = PINCTRL_GRP_I2C0_18 - PINCTRL_GRP_I2C0_0 + 1U,
+ },
+ [PINCTRL_FUNC_I2C1] = {
+ .name = "i2c1",
+ .regval = 0x40,
+ .group_base = PINCTRL_GRP_I2C1_0,
+ .group_size = PINCTRL_GRP_I2C1_19 - PINCTRL_GRP_I2C1_0 + 1U,
+ },
+ [PINCTRL_FUNC_MDIO0] = {
+ .name = "mdio0",
+ .regval = 0x60,
+ .group_base = PINCTRL_GRP_MDIO0_0,
+ .group_size = PINCTRL_GRP_MDIO0_0 - PINCTRL_GRP_MDIO0_0 + 1U,
+ },
+ [PINCTRL_FUNC_MDIO1] = {
+ .name = "mdio1",
+ .regval = 0x80,
+ .group_base = PINCTRL_GRP_MDIO1_0,
+ .group_size = PINCTRL_GRP_MDIO1_1 - PINCTRL_GRP_MDIO1_0 + 1U,
+ },
+ [PINCTRL_FUNC_MDIO2] = {
+ .name = "mdio2",
+ .regval = 0xa0,
+ .group_base = PINCTRL_GRP_MDIO2_0,
+ .group_size = PINCTRL_GRP_MDIO2_0 - PINCTRL_GRP_MDIO2_0 + 1U,
+ },
+ [PINCTRL_FUNC_MDIO3] = {
+ .name = "mdio3",
+ .regval = 0xc0,
+ .group_base = PINCTRL_GRP_MDIO3_0,
+ .group_size = PINCTRL_GRP_MDIO3_0 - PINCTRL_GRP_MDIO3_0 + 1U,
+ },
+ [PINCTRL_FUNC_QSPI0] = {
+ .name = "qspi0",
+ .regval = 0x02,
+ .group_base = PINCTRL_GRP_QSPI0_0,
+ .group_size = PINCTRL_GRP_QSPI0_0 - PINCTRL_GRP_QSPI0_0 + 1U,
+ },
+ [PINCTRL_FUNC_QSPI_FBCLK] = {
+ .name = "qspi_fbclk",
+ .regval = 0x02,
+ .group_base = PINCTRL_GRP_QSPI_FBCLK,
+ .group_size = PINCTRL_GRP_QSPI_FBCLK - PINCTRL_GRP_QSPI_FBCLK + 1U,
+ },
+ [PINCTRL_FUNC_QSPI_SS] = {
+ .name = "qspi_ss",
+ .regval = 0x02,
+ .group_base = PINCTRL_GRP_QSPI_SS,
+ .group_size = PINCTRL_GRP_QSPI_SS - PINCTRL_GRP_QSPI_SS + 1U,
+ },
+ [PINCTRL_FUNC_SPI0] = {
+ .name = "spi0",
+ .regval = 0x80,
+ .group_base = PINCTRL_GRP_SPI0_0,
+ .group_size = PINCTRL_GRP_SPI0_5 - PINCTRL_GRP_SPI0_0 + 1U,
+ },
+ [PINCTRL_FUNC_SPI1] = {
+ .name = "spi1",
+ .regval = 0x80,
+ .group_base = PINCTRL_GRP_SPI1_0,
+ .group_size = PINCTRL_GRP_SPI1_5 - PINCTRL_GRP_SPI1_0 + 1U,
+ },
+ [PINCTRL_FUNC_SPI0_SS] = {
+ .name = "spi0_ss",
+ .regval = 0x80,
+ .group_base = PINCTRL_GRP_SPI0_0_SS0,
+ .group_size = PINCTRL_GRP_SPI0_5_SS2 - PINCTRL_GRP_SPI0_0_SS0 + 1U,
+ },
+ [PINCTRL_FUNC_SPI1_SS] = {
+ .name = "spi1_ss",
+ .regval = 0x80,
+ .group_base = PINCTRL_GRP_SPI1_0_SS0,
+ .group_size = PINCTRL_GRP_SPI1_5_SS2 - PINCTRL_GRP_SPI1_0_SS0 + 1U,
+ },
+ [PINCTRL_FUNC_SDIO0] = {
+ .name = "sdio0",
+ .regval = 0x08,
+ .group_base = PINCTRL_GRP_SDIO0_0,
+ .group_size = PINCTRL_GRP_SDIO0_1BIT_2_7 - PINCTRL_GRP_SDIO0_0 + 1U,
+ },
+ [PINCTRL_FUNC_SDIO0_PC] = {
+ .name = "sdio0_pc",
+ .regval = 0x08,
+ .group_base = PINCTRL_GRP_SDIO0_0_PC,
+ .group_size = PINCTRL_GRP_SDIO0_2_PC - PINCTRL_GRP_SDIO0_0_PC + 1U,
+ },
+ [PINCTRL_FUNC_SDIO0_CD] = {
+ .name = "sdio0_cd",
+ .regval = 0x08,
+ .group_base = PINCTRL_GRP_SDIO0_0_CD,
+ .group_size = PINCTRL_GRP_SDIO0_2_CD - PINCTRL_GRP_SDIO0_0_CD + 1U,
+ },
+ [PINCTRL_FUNC_SDIO0_WP] = {
+ .name = "sdio0_wp",
+ .regval = 0x08,
+ .group_base = PINCTRL_GRP_SDIO0_0_WP,
+ .group_size = PINCTRL_GRP_SDIO0_2_WP - PINCTRL_GRP_SDIO0_0_WP + 1U,
+ },
+ [PINCTRL_FUNC_SDIO1] = {
+ .name = "sdio1",
+ .regval = 0x10,
+ .group_base = PINCTRL_GRP_SDIO1_0,
+ .group_size = PINCTRL_GRP_SDIO1_1BIT_1_3 - PINCTRL_GRP_SDIO1_0 + 1U,
+ },
+ [PINCTRL_FUNC_SDIO1_PC] = {
+ .name = "sdio1_pc",
+ .regval = 0x10,
+ .group_base = PINCTRL_GRP_SDIO1_0_PC,
+ .group_size = PINCTRL_GRP_SDIO1_1_PC - PINCTRL_GRP_SDIO1_0_PC + 1U,
+ },
+ [PINCTRL_FUNC_SDIO1_CD] = {
+ .name = "sdio1_cd",
+ .regval = 0x10,
+ .group_base = PINCTRL_GRP_SDIO1_0_CD,
+ .group_size = PINCTRL_GRP_SDIO1_1_CD - PINCTRL_GRP_SDIO1_0_CD + 1U,
+ },
+ [PINCTRL_FUNC_SDIO1_WP] = {
+ .name = "sdio1_wp",
+ .regval = 0x10,
+ .group_base = PINCTRL_GRP_SDIO1_0_WP,
+ .group_size = PINCTRL_GRP_SDIO1_1_WP - PINCTRL_GRP_SDIO1_0_WP + 1U,
+ },
+ [PINCTRL_FUNC_NAND0] = {
+ .name = "nand0",
+ .regval = 0x04,
+ .group_base = PINCTRL_GRP_NAND0_0,
+ .group_size = PINCTRL_GRP_NAND0_0 - PINCTRL_GRP_NAND0_0 + 1U,
+ },
+ [PINCTRL_FUNC_NAND0_CE] = {
+ .name = "nand0_ce",
+ .regval = 0x04,
+ .group_base = PINCTRL_GRP_NAND0_0_CE,
+ .group_size = PINCTRL_GRP_NAND0_1_CE - PINCTRL_GRP_NAND0_0_CE + 1U,
+ },
+ [PINCTRL_FUNC_NAND0_RB] = {
+ .name = "nand0_rb",
+ .regval = 0x04,
+ .group_base = PINCTRL_GRP_NAND0_0_RB,
+ .group_size = PINCTRL_GRP_NAND0_1_RB - PINCTRL_GRP_NAND0_0_RB + 1U,
+ },
+ [PINCTRL_FUNC_NAND0_DQS] = {
+ .name = "nand0_dqs",
+ .regval = 0x04,
+ .group_base = PINCTRL_GRP_NAND0_0_DQS,
+ .group_size = PINCTRL_GRP_NAND0_1_DQS - PINCTRL_GRP_NAND0_0_DQS + 1U,
+ },
+ [PINCTRL_FUNC_TTC0_CLK] = {
+ .name = "ttc0_clk",
+ .regval = 0xa0,
+ .group_base = PINCTRL_GRP_TTC0_0_CLK,
+ .group_size = PINCTRL_GRP_TTC0_8_CLK - PINCTRL_GRP_TTC0_0_CLK + 1U,
+ },
+ [PINCTRL_FUNC_TTC0_WAV] = {
+ .name = "ttc0_wav",
+ .regval = 0xa0,
+ .group_base = PINCTRL_GRP_TTC0_0_WAV,
+ .group_size = PINCTRL_GRP_TTC0_8_WAV - PINCTRL_GRP_TTC0_0_WAV + 1U,
+ },
+ [PINCTRL_FUNC_TTC1_CLK] = {
+ .name = "ttc1_clk",
+ .regval = 0xa0,
+ .group_base = PINCTRL_GRP_TTC1_0_CLK,
+ .group_size = PINCTRL_GRP_TTC1_8_CLK - PINCTRL_GRP_TTC1_0_CLK + 1U,
+ },
+ [PINCTRL_FUNC_TTC1_WAV] = {
+ .name = "ttc1_wav",
+ .regval = 0xa0,
+ .group_base = PINCTRL_GRP_TTC1_0_WAV,
+ .group_size = PINCTRL_GRP_TTC1_8_WAV - PINCTRL_GRP_TTC1_0_WAV + 1U,
+ },
+ [PINCTRL_FUNC_TTC2_CLK] = {
+ .name = "ttc2_clk",
+ .regval = 0xa0,
+ .group_base = PINCTRL_GRP_TTC2_0_CLK,
+ .group_size = PINCTRL_GRP_TTC2_8_CLK - PINCTRL_GRP_TTC2_0_CLK + 1U,
+ },
+ [PINCTRL_FUNC_TTC2_WAV] = {
+ .name = "ttc2_wav",
+ .regval = 0xa0,
+ .group_base = PINCTRL_GRP_TTC2_0_WAV,
+ .group_size = PINCTRL_GRP_TTC2_8_WAV - PINCTRL_GRP_TTC2_0_WAV + 1U,
+ },
+ [PINCTRL_FUNC_TTC3_CLK] = {
+ .name = "ttc3_clk",
+ .regval = 0xa0,
+ .group_base = PINCTRL_GRP_TTC3_0_CLK,
+ .group_size = PINCTRL_GRP_TTC3_8_CLK - PINCTRL_GRP_TTC3_0_CLK + 1U,
+ },
+ [PINCTRL_FUNC_TTC3_WAV] = {
+ .name = "ttc3_wav",
+ .regval = 0xa0,
+ .group_base = PINCTRL_GRP_TTC3_0_WAV,
+ .group_size = PINCTRL_GRP_TTC3_8_WAV - PINCTRL_GRP_TTC3_0_WAV + 1U,
+ },
+ [PINCTRL_FUNC_UART0] = {
+ .name = "uart0",
+ .regval = 0xc0,
+ .group_base = PINCTRL_GRP_UART0_0,
+ .group_size = PINCTRL_GRP_UART0_18 - PINCTRL_GRP_UART0_0 + 1U,
+ },
+ [PINCTRL_FUNC_UART1] = {
+ .name = "uart1",
+ .regval = 0xc0,
+ .group_base = PINCTRL_GRP_UART1_0,
+ .group_size = PINCTRL_GRP_UART1_18 - PINCTRL_GRP_UART1_0 + 1U,
+ },
+ [PINCTRL_FUNC_USB0] = {
+ .name = "usb0",
+ .regval = 0x04,
+ .group_base = PINCTRL_GRP_USB0_0,
+ .group_size = PINCTRL_GRP_USB0_0 - PINCTRL_GRP_USB0_0 + 1U,
+ },
+ [PINCTRL_FUNC_USB1] = {
+ .name = "usb1",
+ .regval = 0x04,
+ .group_base = PINCTRL_GRP_USB1_0,
+ .group_size = PINCTRL_GRP_USB1_0 - PINCTRL_GRP_USB1_0 + 1U,
+ },
+ [PINCTRL_FUNC_SWDT0_CLK] = {
+ .name = "swdt0_clk",
+ .regval = 0x60,
+ .group_base = PINCTRL_GRP_SWDT0_0_CLK,
+ .group_size = PINCTRL_GRP_SWDT0_12_CLK - PINCTRL_GRP_SWDT0_0_CLK + 1U,
+ },
+ [PINCTRL_FUNC_SWDT0_RST] = {
+ .name = "swdt0_rst",
+ .regval = 0x60,
+ .group_base = PINCTRL_GRP_SWDT0_0_RST,
+ .group_size = PINCTRL_GRP_SWDT0_12_RST - PINCTRL_GRP_SWDT0_0_RST + 1U,
+ },
+ [PINCTRL_FUNC_SWDT1_CLK] = {
+ .name = "swdt1_clk",
+ .regval = 0x60,
+ .group_base = PINCTRL_GRP_SWDT1_0_CLK,
+ .group_size = PINCTRL_GRP_SWDT1_12_CLK - PINCTRL_GRP_SWDT1_0_CLK + 1U,
+ },
+ [PINCTRL_FUNC_SWDT1_RST] = {
+ .name = "swdt1_rst",
+ .regval = 0x60,
+ .group_base = PINCTRL_GRP_SWDT1_0_RST,
+ .group_size = PINCTRL_GRP_SWDT1_12_RST - PINCTRL_GRP_SWDT1_0_RST + 1U,
+ },
+ [PINCTRL_FUNC_PMU0] = {
+ .name = "pmu0",
+ .regval = 0x08,
+ .group_base = PINCTRL_GRP_PMU0_0,
+ .group_size = PINCTRL_GRP_PMU0_11 - PINCTRL_GRP_PMU0_0 + 1U,
+ },
+ [PINCTRL_FUNC_PCIE0] = {
+ .name = "pcie0",
+ .regval = 0x04,
+ .group_base = PINCTRL_GRP_PCIE0_0,
+ .group_size = PINCTRL_GRP_PCIE0_7 - PINCTRL_GRP_PCIE0_0 + 1U,
+ },
+ [PINCTRL_FUNC_CSU0] = {
+ .name = "csu0",
+ .regval = 0x18,
+ .group_base = PINCTRL_GRP_CSU0_0,
+ .group_size = PINCTRL_GRP_CSU0_11 - PINCTRL_GRP_CSU0_0 + 1U,
+ },
+ [PINCTRL_FUNC_DPAUX0] = {
+ .name = "dpaux0",
+ .regval = 0x18,
+ .group_base = PINCTRL_GRP_DPAUX0_0,
+ .group_size = PINCTRL_GRP_DPAUX0_3 - PINCTRL_GRP_DPAUX0_0 + 1U,
+ },
+ [PINCTRL_FUNC_PJTAG0] = {
+ .name = "pjtag0",
+ .regval = 0x60,
+ .group_base = PINCTRL_GRP_PJTAG0_0,
+ .group_size = PINCTRL_GRP_PJTAG0_5 - PINCTRL_GRP_PJTAG0_0 + 1U,
+ },
+ [PINCTRL_FUNC_TRACE0] = {
+ .name = "trace0",
+ .regval = 0xe0,
+ .group_base = PINCTRL_GRP_TRACE0_0,
+ .group_size = PINCTRL_GRP_TRACE0_2 - PINCTRL_GRP_TRACE0_0 + 1U,
+ },
+ [PINCTRL_FUNC_TRACE0_CLK] = {
+ .name = "trace0_clk",
+ .regval = 0xe0,
+ .group_base = PINCTRL_GRP_TRACE0_0_CLK,
+ .group_size = PINCTRL_GRP_TRACE0_2_CLK - PINCTRL_GRP_TRACE0_0_CLK + 1U,
+ },
+ [PINCTRL_FUNC_TESTSCAN0] = {
+ .name = "testscan0",
+ .regval = 0x10,
+ .group_base = PINCTRL_GRP_TESTSCAN0_0,
+ .group_size = PINCTRL_GRP_TESTSCAN0_0 - PINCTRL_GRP_TESTSCAN0_0 + 1U,
+ },
+};
+
+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_ETHERNET0_0,
+ 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(uint32_t *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(uint32_t *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(uint32_t fid,
+ uint32_t *ngroups)
+{
+ if (fid >= MAX_FUNCTION) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ *ngroups = pinctrl_functions[fid].group_size;
+
+ 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.
+ */
+void pm_api_pinctrl_get_function_name(uint32_t 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);
+ }
+}
+
+/**
+ * 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(uint32_t fid,
+ uint32_t index,
+ uint16_t *groups)
+{
+ uint16_t grps;
+ uint16_t end_of_grp_offset;
+ uint16_t i;
+
+ if (fid >= MAX_FUNCTION) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ memset(groups, END_OF_GROUPS, GROUPS_PAYLOAD_LEN);
+
+ grps = pinctrl_functions[fid].group_base;
+ end_of_grp_offset = grps + pinctrl_functions[fid].group_size;
+
+ for (i = 0U; i < NUM_GROUPS_PER_RESP; i++) {
+ if ((grps + index + i) >= end_of_grp_offset) {
+ break;
+ }
+ groups[i] = (grps + index + i);
+ }
+
+ 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(uint32_t pin,
+ uint32_t index,
+ uint16_t *groups)
+{
+ uint32_t 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 == 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;
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h
new file mode 100644
index 0000000..5c4cb45
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h
@@ -0,0 +1,723 @@
+/*
+ * Copyright (c) 2018-2020, 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 (16U)
+#define GROUPS_PAYLOAD_LEN (12U)
+#define NUM_GROUPS_PER_RESP (6U)
+#define END_OF_FUNCTION "END_OF_FUNCTION"
+#define END_OF_GROUPS -1
+#define PINCTRL_GRP_RESERVED -2
+
+//pinctrl function ids
+enum {
+ PINCTRL_FUNC_CAN0 = (0U),
+ PINCTRL_FUNC_CAN1 = (1U),
+ PINCTRL_FUNC_ETHERNET0 = (2U),
+ PINCTRL_FUNC_ETHERNET1 = (3U),
+ PINCTRL_FUNC_ETHERNET2 = (4U),
+ PINCTRL_FUNC_ETHERNET3 = (5U),
+ PINCTRL_FUNC_GEMTSU0 = (6U),
+ PINCTRL_FUNC_GPIO0 = (7U),
+ PINCTRL_FUNC_I2C0 = (8U),
+ PINCTRL_FUNC_I2C1 = (9U),
+ PINCTRL_FUNC_MDIO0 = (10U),
+ PINCTRL_FUNC_MDIO1 = (11U),
+ PINCTRL_FUNC_MDIO2 = (12U),
+ PINCTRL_FUNC_MDIO3 = (13U),
+ PINCTRL_FUNC_QSPI0 = (14U),
+ PINCTRL_FUNC_QSPI_FBCLK = (15U),
+ PINCTRL_FUNC_QSPI_SS = (16U),
+ PINCTRL_FUNC_SPI0 = (17U),
+ PINCTRL_FUNC_SPI1 = (18U),
+ PINCTRL_FUNC_SPI0_SS = (19U),
+ PINCTRL_FUNC_SPI1_SS = (20U),
+ PINCTRL_FUNC_SDIO0 = (21U),
+ PINCTRL_FUNC_SDIO0_PC = (22U),
+ PINCTRL_FUNC_SDIO0_CD = (23U),
+ PINCTRL_FUNC_SDIO0_WP = (24U),
+ PINCTRL_FUNC_SDIO1 = (25U),
+ PINCTRL_FUNC_SDIO1_PC = (26U),
+ PINCTRL_FUNC_SDIO1_CD = (27U),
+ PINCTRL_FUNC_SDIO1_WP = (28U),
+ PINCTRL_FUNC_NAND0 = (29U),
+ PINCTRL_FUNC_NAND0_CE = (30U),
+ PINCTRL_FUNC_NAND0_RB = (31U),
+ PINCTRL_FUNC_NAND0_DQS = (32U),
+ PINCTRL_FUNC_TTC0_CLK = (33U),
+ PINCTRL_FUNC_TTC0_WAV = (34U),
+ PINCTRL_FUNC_TTC1_CLK = (35U),
+ PINCTRL_FUNC_TTC1_WAV = (36U),
+ PINCTRL_FUNC_TTC2_CLK = (37U),
+ PINCTRL_FUNC_TTC2_WAV = (38U),
+ PINCTRL_FUNC_TTC3_CLK = (39U),
+ PINCTRL_FUNC_TTC3_WAV = (40U),
+ PINCTRL_FUNC_UART0 = (41U),
+ PINCTRL_FUNC_UART1 = (42U),
+ PINCTRL_FUNC_USB0 = (43U),
+ PINCTRL_FUNC_USB1 = (44U),
+ PINCTRL_FUNC_SWDT0_CLK = (45U),
+ PINCTRL_FUNC_SWDT0_RST = (46U),
+ PINCTRL_FUNC_SWDT1_CLK = (47U),
+ PINCTRL_FUNC_SWDT1_RST = (48U),
+ PINCTRL_FUNC_PMU0 = (49U),
+ PINCTRL_FUNC_PCIE0 = (50U),
+ PINCTRL_FUNC_CSU0 = (51U),
+ PINCTRL_FUNC_DPAUX0 = (52U),
+ PINCTRL_FUNC_PJTAG0 = (53U),
+ PINCTRL_FUNC_TRACE0 = (54U),
+ PINCTRL_FUNC_TRACE0_CLK = (55U),
+ PINCTRL_FUNC_TESTSCAN0 = (56U),
+ END_FUNCTION = (57U),
+};
+
+#define MAX_FUNCTION 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 = (78U),
+};
+
+#define MAX_PIN 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_1,
+ PINCTRL_GRP_SPI0_2,
+ PINCTRL_GRP_SPI0_3,
+ PINCTRL_GRP_SPI0_4,
+ PINCTRL_GRP_SPI0_5,
+ 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,
+ PINCTRL_GRP_SPI1_0,
+ PINCTRL_GRP_SPI1_1,
+ PINCTRL_GRP_SPI1_2,
+ PINCTRL_GRP_SPI1_3,
+ PINCTRL_GRP_SPI1_4,
+ PINCTRL_GRP_SPI1_5,
+ 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,
+ 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_1_PC,
+ PINCTRL_GRP_SDIO0_2_PC,
+ PINCTRL_GRP_SDIO0_0_CD,
+ PINCTRL_GRP_SDIO0_1_CD,
+ PINCTRL_GRP_SDIO0_2_CD,
+ PINCTRL_GRP_SDIO0_0_WP,
+ PINCTRL_GRP_SDIO0_1_WP,
+ 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_1_PC,
+ PINCTRL_GRP_SDIO1_0_CD,
+ PINCTRL_GRP_SDIO1_1_CD,
+ PINCTRL_GRP_SDIO1_0_WP,
+ PINCTRL_GRP_SDIO1_1_WP,
+ PINCTRL_GRP_NAND0_0,
+ PINCTRL_GRP_NAND0_0_CE,
+ PINCTRL_GRP_NAND0_1_CE,
+ PINCTRL_GRP_NAND0_0_RB,
+ PINCTRL_GRP_NAND0_1_RB,
+ PINCTRL_GRP_NAND0_0_DQS,
+ 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_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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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_1,
+ PINCTRL_GRP_TRACE0_2,
+ PINCTRL_GRP_TRACE0_0_CLK,
+ PINCTRL_GRP_TRACE0_1_CLK,
+ 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
+
+void pm_api_pinctrl_get_function_name(uint32_t fid, char *name);
+enum pm_ret_status pm_api_pinctrl_get_function_groups(uint32_t fid,
+ uint32_t index,
+ uint16_t *groups);
+enum pm_ret_status pm_api_pinctrl_get_pin_groups(uint32_t pin,
+ uint32_t index,
+ uint16_t *groups);
+enum pm_ret_status pm_api_pinctrl_get_num_pins(uint32_t *npins);
+enum pm_ret_status pm_api_pinctrl_get_num_functions(uint32_t *nfuncs);
+enum pm_ret_status pm_api_pinctrl_get_num_func_groups(uint32_t fid,
+ uint32_t *ngroups);
+#endif /* PM_API_PINCTRL_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
new file mode 100644
index 0000000..a17b6c5
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
@@ -0,0 +1,1836 @@
+/*
+ * Copyright (c) 2013-2022, 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 <arch_helpers.h>
+#include <plat/common/platform.h>
+
+#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"
+
+#define PM_QUERY_FEATURE_BITMASK ( \
+ (1ULL << (uint64_t)PM_QID_CLOCK_GET_NAME) | \
+ (1ULL << (uint64_t)PM_QID_CLOCK_GET_TOPOLOGY) | \
+ (1ULL << (uint64_t)PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS) | \
+ (1ULL << (uint64_t)PM_QID_CLOCK_GET_PARENTS) | \
+ (1ULL << (uint64_t)PM_QID_CLOCK_GET_ATTRIBUTES) | \
+ (1ULL << (uint64_t)PM_QID_PINCTRL_GET_NUM_PINS) | \
+ (1ULL << (uint64_t)PM_QID_PINCTRL_GET_NUM_FUNCTIONS) | \
+ (1ULL << (uint64_t)PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS) | \
+ (1ULL << (uint64_t)PM_QID_PINCTRL_GET_FUNCTION_NAME) | \
+ (1ULL << (uint64_t)PM_QID_PINCTRL_GET_FUNCTION_GROUPS) | \
+ (1ULL << (uint64_t)PM_QID_PINCTRL_GET_PIN_GROUPS) | \
+ (1ULL << (uint64_t)PM_QID_CLOCK_GET_NUM_CLOCKS) | \
+ (1ULL << (uint64_t)PM_QID_CLOCK_GET_MAX_DIVISOR))
+
+/**
+ * struct eemi_api_dependency - Dependent EEMI APIs which are implemented
+ * on both the ATF and firmware
+ *
+ * @id: EEMI API id or IOCTL id to be checked
+ * @api_id: Dependent EEMI API
+ */
+typedef struct __attribute__((packed)) {
+ uint8_t id;
+ uint8_t api_id;
+} eemi_api_dependency;
+
+/* Dependent APIs for ATF to check their version from firmware */
+static const eemi_api_dependency api_dep_table[] = {
+ {
+ .id = PM_SELF_SUSPEND,
+ .api_id = PM_SELF_SUSPEND,
+ },
+ {
+ .id = PM_REQ_WAKEUP,
+ .api_id = PM_REQ_WAKEUP,
+ },
+ {
+ .id = PM_ABORT_SUSPEND,
+ .api_id = PM_ABORT_SUSPEND,
+ },
+ {
+ .id = PM_SET_WAKEUP_SOURCE,
+ .api_id = PM_SET_WAKEUP_SOURCE,
+ },
+ {
+ .id = PM_SYSTEM_SHUTDOWN,
+ .api_id = PM_SYSTEM_SHUTDOWN,
+ },
+ {
+ .id = PM_GET_API_VERSION,
+ .api_id = PM_GET_API_VERSION,
+ },
+ {
+ .id = PM_CLOCK_ENABLE,
+ .api_id = PM_PLL_SET_MODE,
+ },
+ {
+ .id = PM_CLOCK_ENABLE,
+ .api_id = PM_CLOCK_ENABLE,
+ },
+ {
+ .id = PM_CLOCK_DISABLE,
+ .api_id = PM_PLL_SET_MODE,
+ },
+ {
+ .id = PM_CLOCK_DISABLE,
+ .api_id = PM_CLOCK_DISABLE,
+ },
+ {
+ .id = PM_CLOCK_GETSTATE,
+ .api_id = PM_PLL_GET_MODE,
+ },
+ {
+ .id = PM_CLOCK_GETSTATE,
+ .api_id = PM_CLOCK_GETSTATE,
+ },
+ {
+ .id = PM_CLOCK_SETDIVIDER,
+ .api_id = PM_PLL_SET_PARAMETER,
+ },
+ {
+ .id = PM_CLOCK_SETDIVIDER,
+ .api_id = PM_CLOCK_SETDIVIDER,
+ },
+ {
+ .id = PM_CLOCK_GETDIVIDER,
+ .api_id = PM_PLL_GET_PARAMETER,
+ },
+ {
+ .id = PM_CLOCK_GETDIVIDER,
+ .api_id = PM_CLOCK_GETDIVIDER,
+ },
+ {
+ .id = PM_CLOCK_SETPARENT,
+ .api_id = PM_PLL_SET_PARAMETER,
+ },
+ {
+ .id = PM_CLOCK_SETPARENT,
+ .api_id = PM_CLOCK_SETPARENT,
+ },
+ {
+ .id = PM_CLOCK_GETPARENT,
+ .api_id = PM_PLL_GET_PARAMETER,
+ },
+ {
+ .id = PM_CLOCK_GETPARENT,
+ .api_id = PM_CLOCK_GETPARENT,
+ },
+ {
+ .id = PM_PLL_SET_PARAMETER,
+ .api_id = PM_PLL_SET_PARAMETER,
+ },
+ {
+ .id = PM_PLL_GET_PARAMETER,
+ .api_id = PM_PLL_GET_PARAMETER,
+ },
+ {
+ .id = PM_PLL_SET_MODE,
+ .api_id = PM_PLL_SET_MODE,
+ },
+ {
+ .id = PM_PLL_GET_MODE,
+ .api_id = PM_PLL_GET_MODE,
+ },
+ {
+ .id = PM_REGISTER_ACCESS,
+ .api_id = PM_MMIO_WRITE,
+ },
+ {
+ .id = PM_REGISTER_ACCESS,
+ .api_id = PM_MMIO_READ,
+ },
+ {
+ .id = PM_FEATURE_CHECK,
+ .api_id = PM_FEATURE_CHECK,
+ },
+ {
+ .id = IOCTL_SET_TAPDELAY_BYPASS,
+ .api_id = PM_MMIO_WRITE,
+ },
+ {
+ .id = IOCTL_SET_SGMII_MODE,
+ .api_id = PM_MMIO_WRITE,
+ },
+ {
+ .id = IOCTL_SD_DLL_RESET,
+ .api_id = PM_MMIO_WRITE,
+ },
+ {
+ .id = IOCTL_SET_SD_TAPDELAY,
+ .api_id = PM_MMIO_WRITE,
+ },
+ {
+ .id = IOCTL_SET_SD_TAPDELAY,
+ .api_id = PM_MMIO_READ,
+ },
+ {
+ .id = IOCTL_SET_PLL_FRAC_DATA,
+ .api_id = PM_PLL_SET_PARAMETER,
+ },
+ {
+ .id = IOCTL_GET_PLL_FRAC_DATA,
+ .api_id = PM_PLL_GET_PARAMETER,
+ },
+ {
+ .id = IOCTL_WRITE_GGS,
+ .api_id = PM_MMIO_WRITE,
+ },
+ {
+ .id = IOCTL_READ_GGS,
+ .api_id = PM_MMIO_READ,
+ },
+ {
+ .id = IOCTL_WRITE_PGGS,
+ .api_id = PM_MMIO_WRITE,
+ },
+ {
+ .id = IOCTL_READ_PGGS,
+ .api_id = PM_MMIO_READ,
+ },
+ {
+ .id = IOCTL_ULPI_RESET,
+ .api_id = PM_MMIO_WRITE,
+ },
+ {
+ .id = IOCTL_SET_BOOT_HEALTH_STATUS,
+ .api_id = PM_MMIO_WRITE,
+ },
+ {
+ .id = IOCTL_AFI,
+ .api_id = PM_MMIO_WRITE,
+ },
+};
+
+/* Expected firmware API version to ATF */
+static const uint8_t atf_expected_ver_id[] = {
+ [PM_SELF_SUSPEND] = FW_API_BASE_VERSION,
+ [PM_REQ_WAKEUP] = FW_API_BASE_VERSION,
+ [PM_ABORT_SUSPEND] = FW_API_BASE_VERSION,
+ [PM_SET_WAKEUP_SOURCE] = FW_API_BASE_VERSION,
+ [PM_SYSTEM_SHUTDOWN] = FW_API_BASE_VERSION,
+ [PM_GET_API_VERSION] = FW_API_BASE_VERSION,
+ [PM_PLL_SET_MODE] = FW_API_BASE_VERSION,
+ [PM_PLL_GET_MODE] = FW_API_BASE_VERSION,
+ [PM_CLOCK_ENABLE] = FW_API_BASE_VERSION,
+ [PM_CLOCK_DISABLE] = FW_API_BASE_VERSION,
+ [PM_CLOCK_GETSTATE] = FW_API_BASE_VERSION,
+ [PM_PLL_SET_PARAMETER] = FW_API_BASE_VERSION,
+ [PM_PLL_GET_PARAMETER] = FW_API_BASE_VERSION,
+ [PM_CLOCK_SETDIVIDER] = FW_API_BASE_VERSION,
+ [PM_CLOCK_GETDIVIDER] = FW_API_BASE_VERSION,
+ [PM_CLOCK_SETPARENT] = FW_API_BASE_VERSION,
+ [PM_CLOCK_GETPARENT] = FW_API_BASE_VERSION,
+ [PM_MMIO_WRITE] = FW_API_BASE_VERSION,
+ [PM_MMIO_READ] = FW_API_BASE_VERSION,
+ [PM_FEATURE_CHECK] = FW_API_VERSION_2,
+};
+
+/* default shutdown/reboot scope is system(2) */
+static uint32_t pm_shutdown_scope = PMF_SHUTDOWN_SUBTYPE_SYSTEM;
+
+/**
+ * pm_get_shutdown_scope() - Get the currently set shutdown scope
+ *
+ * @return Shutdown scope value
+ */
+uint32_t pm_get_shutdown_scope(void)
+{
+ return pm_shutdown_scope;
+}
+
+#define EM_PACK_PAYLOAD1(pl, arg0) { \
+ pl[0] = (uint16_t)(0xE) << 16 | (uint16_t)arg0; \
+}
+
+/**
+ * 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,
+ uint32_t latency,
+ uint32_t state,
+ uintptr_t address)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+ uint32_t 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,
+ uint32_t latency, uint32_t 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,
+ uint32_t 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_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * 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,
+ uint32_t enable)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ PM_PACK_PAYLOAD4(payload, PM_SET_WAKEUP_SOURCE, target, wkup_node,
+ enable);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * 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(uint32_t type, uint32_t 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,
+ uint32_t capabilities,
+ uint32_t 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,
+ uint32_t capabilities,
+ uint32_t 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);
+ }
+}
+
+/* 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(uint32_t *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_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_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,
+ uint32_t mask,
+ uint32_t 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, uint32_t *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(uint32_t *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_get_callbackdata() - Read from IPI response buffer
+ * @data - array of PAYLOAD_ARG_CNT elements
+ *
+ * Read value from ipi buffer response buffer.
+ */
+void pm_get_callbackdata(uint32_t *data, size_t count)
+{
+ /* Return if interrupt is not from PMU */
+ if (!pm_ipi_irq_status(primary_proc)) {
+ return;
+ }
+
+ pm_ipi_buff_read_callb(data, count);
+ pm_ipi_irq_clear(primary_proc);
+}
+
+/**
+ * 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,
+ uint32_t ioctl_id,
+ uint32_t arg1,
+ uint32_t arg2,
+ uint32_t *value)
+{
+ return pm_api_ioctl(nid, ioctl_id, arg1, arg2, value);
+}
+
+/**
+ * fw_api_version() - Returns API version implemented in firmware
+ * @api_id API ID to check
+ * @version Returned supported API version
+ * @len Number of words to be returned
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status fw_api_version(uint32_t id, uint32_t *version,
+ uint32_t len)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ PM_PACK_PAYLOAD2(payload, PM_FEATURE_CHECK, id);
+ return pm_ipi_send_sync(primary_proc, payload, version, len);
+}
+
+/**
+ * check_api_dependency() - API to check dependent EEMI API version
+ * @id EEMI API ID to check
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status check_api_dependency(uint8_t id)
+{
+ uint8_t i;
+ uint32_t version;
+ int ret;
+
+ for (i = 0U; i < ARRAY_SIZE(api_dep_table); i++) {
+ if (api_dep_table[i].id == id) {
+ if (api_dep_table[i].api_id == 0U) {
+ break;
+ }
+
+ ret = fw_api_version(api_dep_table[i].api_id,
+ &version, 1);
+ if (ret != PM_RET_SUCCESS) {
+ return ret;
+ }
+
+ /* Check if fw version matches ATF expected version */
+ if (version != atf_expected_ver_id[api_dep_table[i].api_id]) {
+ return PM_RET_ERROR_NOTSUPPORTED;
+ }
+ }
+ }
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * feature_check_atf() - These are API's completely implemented in ATF
+ * @api_id API ID to check
+ * @version Returned supported API version
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status feature_check_atf(uint32_t api_id, uint32_t *version,
+ uint32_t *bit_mask)
+{
+ switch (api_id) {
+ case PM_QUERY_DATA:
+ *version = ATF_API_BASE_VERSION;
+ bit_mask[0] = (uint32_t)(PM_QUERY_FEATURE_BITMASK);
+ bit_mask[1] = (uint32_t)(PM_QUERY_FEATURE_BITMASK >> 32);
+ return PM_RET_SUCCESS;
+ case PM_GET_CALLBACK_DATA:
+ case PM_GET_TRUSTZONE_VERSION:
+ case PM_SET_SUSPEND_MODE:
+ *version = ATF_API_BASE_VERSION;
+ return PM_RET_SUCCESS;
+ default:
+ return PM_RET_ERROR_NO_FEATURE;
+ }
+}
+
+/**
+ * get_atf_version_for_partial_apis() - Return ATF version for partially
+ * implemented APIs
+ * @api_id API ID to check
+ * @version Returned supported API version
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status get_atf_version_for_partial_apis(uint32_t api_id,
+ uint32_t *version)
+{
+ switch (api_id) {
+ case PM_SELF_SUSPEND:
+ case PM_REQ_WAKEUP:
+ case PM_ABORT_SUSPEND:
+ case PM_SET_WAKEUP_SOURCE:
+ case PM_SYSTEM_SHUTDOWN:
+ case PM_GET_API_VERSION:
+ case PM_CLOCK_ENABLE:
+ case PM_CLOCK_DISABLE:
+ case PM_CLOCK_GETSTATE:
+ case PM_CLOCK_SETDIVIDER:
+ case PM_CLOCK_GETDIVIDER:
+ case PM_CLOCK_SETPARENT:
+ case PM_CLOCK_GETPARENT:
+ case PM_PLL_SET_PARAMETER:
+ case PM_PLL_GET_PARAMETER:
+ case PM_PLL_SET_MODE:
+ case PM_PLL_GET_MODE:
+ case PM_REGISTER_ACCESS:
+ *version = ATF_API_BASE_VERSION;
+ return PM_RET_SUCCESS;
+ case PM_FEATURE_CHECK:
+ *version = FW_API_VERSION_2;
+ return PM_RET_SUCCESS;
+ default:
+ return PM_RET_ERROR_ARGS;
+ }
+}
+
+/**
+ * feature_check_partial() - These are API's partially implemented in
+ * ATF and firmware both
+ * @api_id API ID to check
+ * @version Returned supported API version
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status feature_check_partial(uint32_t api_id,
+ uint32_t *version)
+{
+ uint32_t status;
+
+ switch (api_id) {
+ case PM_SELF_SUSPEND:
+ case PM_REQ_WAKEUP:
+ case PM_ABORT_SUSPEND:
+ case PM_SET_WAKEUP_SOURCE:
+ case PM_SYSTEM_SHUTDOWN:
+ case PM_GET_API_VERSION:
+ case PM_CLOCK_ENABLE:
+ case PM_CLOCK_DISABLE:
+ case PM_CLOCK_GETSTATE:
+ case PM_CLOCK_SETDIVIDER:
+ case PM_CLOCK_GETDIVIDER:
+ case PM_CLOCK_SETPARENT:
+ case PM_CLOCK_GETPARENT:
+ case PM_PLL_SET_PARAMETER:
+ case PM_PLL_GET_PARAMETER:
+ case PM_PLL_SET_MODE:
+ case PM_PLL_GET_MODE:
+ case PM_REGISTER_ACCESS:
+ case PM_FEATURE_CHECK:
+ status = check_api_dependency(api_id);
+ if (status != PM_RET_SUCCESS) {
+ return status;
+ }
+ return get_atf_version_for_partial_apis(api_id, version);
+ default:
+ return PM_RET_ERROR_NO_FEATURE;
+ }
+}
+
+/**
+ * pm_feature_check() - Returns the supported API version if supported
+ * @api_id API ID to check
+ * @version Returned supported API version
+ * @bit_mask Returned supported IOCTL id version
+ * @len Number of bytes to be returned in bit_mask variable
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *version,
+ uint32_t *bit_mask, uint8_t len)
+{
+ uint32_t ret_payload[PAYLOAD_ARG_CNT] = {0U};
+ uint32_t status;
+
+ /* Get API version implemented in ATF */
+ status = feature_check_atf(api_id, version, bit_mask);
+ if (status != PM_RET_ERROR_NO_FEATURE) {
+ return status;
+ }
+
+ /* Get API version implemented by firmware and ATF both */
+ status = feature_check_partial(api_id, version);
+ if (status != PM_RET_ERROR_NO_FEATURE) {
+ return status;
+ }
+
+ /* Get API version implemented by firmware */
+ status = fw_api_version(api_id, ret_payload, 3);
+ /* IOCTL call may return failure whose ID is not implemented in
+ * firmware but implemented in ATF
+ */
+ if ((api_id != PM_IOCTL) && (status != PM_RET_SUCCESS)) {
+ return status;
+ }
+
+ *version = ret_payload[0];
+
+ /* Update IOCTL bit mask which are implemented in ATF */
+ if (api_id == PM_IOCTL) {
+ if (len < 2) {
+ return PM_RET_ERROR_ARGS;
+ }
+ bit_mask[0] = ret_payload[1];
+ bit_mask[1] = ret_payload[2];
+ /* Get IOCTL's implemented by ATF */
+ status = atf_ioctl_bitmask(bit_mask);
+ } else {
+ /* Requires for MISRA */
+ }
+
+ return status;
+}
+
+/**
+ * pm_clock_get_max_divisor - PM call to get max divisor
+ * @clock_id Clock ID
+ * @div_type Divisor ID (TYPE_DIV1 or TYPE_DIV2)
+ * @max_div Maximum supported divisor
+ *
+ * This function is used by master to get maximum supported value.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+static enum pm_ret_status pm_clock_get_max_divisor(uint32_t clock_id,
+ uint8_t div_type,
+ uint32_t *max_div)
+{
+ return pm_api_clock_get_max_divisor(clock_id, div_type, max_div);
+}
+
+/**
+ * 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.
+ */
+static void pm_clock_get_name(uint32_t clock_id, char *name)
+{
+ 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(uint32_t clock_id,
+ uint32_t 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(uint32_t 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(uint32_t clock_id,
+ uint32_t 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(uint32_t 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(uint32_t clock_id,
+ uint8_t 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);
+ status = pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+
+ /* If action fails due to the lack of permissions filter the error */
+ if (status == PM_RET_ERROR_ACCESS) {
+ status = PM_RET_SUCCESS;
+ }
+
+ return status;
+}
+
+/**
+ * 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(uint32_t 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(uint32_t 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(uint32_t clock_id,
+ uint32_t *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(uint32_t clock_id,
+ uint32_t 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(uint32_t clock_id,
+ uint32_t *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(uint32_t 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(uint32_t 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(uint32_t clock_id,
+ uint32_t 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(uint32_t clock_id,
+ uint32_t *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(uint32_t 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
+ */
+static void pm_pinctrl_get_function_name(uint32_t fid, char *name)
+{
+ 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(uint32_t fid,
+ uint32_t 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(uint32_t pin_id,
+ uint32_t 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.
+ */
+void pm_query_data(enum pm_query_id qid, uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t *data)
+{
+ switch (qid) {
+ case PM_QID_CLOCK_GET_NAME:
+ pm_clock_get_name(arg1, (char *)data);
+ break;
+ case PM_QID_CLOCK_GET_TOPOLOGY:
+ data[0] = pm_clock_get_topology(arg1, arg2, &data[1]);
+ break;
+ case PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS:
+ data[0] = pm_clock_get_fixedfactor_params(arg1, &data[1],
+ &data[2]);
+ break;
+ case PM_QID_CLOCK_GET_PARENTS:
+ data[0] = pm_clock_get_parents(arg1, arg2, &data[1]);
+ break;
+ case PM_QID_CLOCK_GET_ATTRIBUTES:
+ data[0] = pm_clock_get_attributes(arg1, &data[1]);
+ break;
+ case PM_QID_PINCTRL_GET_NUM_PINS:
+ data[0] = pm_pinctrl_get_num_pins(&data[1]);
+ break;
+ case PM_QID_PINCTRL_GET_NUM_FUNCTIONS:
+ data[0] = pm_pinctrl_get_num_functions(&data[1]);
+ break;
+ case PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS:
+ data[0] = pm_pinctrl_get_num_function_groups(arg1, &data[1]);
+ break;
+ case PM_QID_PINCTRL_GET_FUNCTION_NAME:
+ pm_pinctrl_get_function_name(arg1, (char *)data);
+ break;
+ case PM_QID_PINCTRL_GET_FUNCTION_GROUPS:
+ data[0] = pm_pinctrl_get_function_groups(arg1, arg2,
+ (uint16_t *)&data[1]);
+ break;
+ case PM_QID_PINCTRL_GET_PIN_GROUPS:
+ data[0] = pm_pinctrl_get_pin_groups(arg1, arg2,
+ (uint16_t *)&data[1]);
+ break;
+ case PM_QID_CLOCK_GET_NUM_CLOCKS:
+ data[0] = pm_clock_get_num_clocks(&data[1]);
+ break;
+
+ case PM_QID_CLOCK_GET_MAX_DIVISOR:
+ data[0] = pm_clock_get_max_divisor(arg1, arg2, &data[1]);
+ break;
+ default:
+ data[0] = PM_RET_ERROR_ARGS;
+ WARN("Unimplemented query service call: 0x%x\n", qid);
+ break;
+ }
+}
+
+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,
+ uint32_t 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,
+ uint32_t *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);
+}
+
+/**
+ * pm_register_access() - PM API for register read/write access data
+ *
+ * @register_access_id Register_access_id which says register read/write
+ *
+ * @address Address of the register to be accessed
+ *
+ * @mask Mask value to be used while writing value
+ *
+ * @value Value to be written to register
+ *
+ * @out Returned output data
+ *
+ * This function returns requested data.
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_register_access(uint32_t register_access_id,
+ uint32_t address,
+ uint32_t mask,
+ uint32_t value,
+ uint32_t *out)
+{
+ enum pm_ret_status ret;
+
+ if (((ZYNQMP_CSU_BASEADDR & address) != ZYNQMP_CSU_BASEADDR) &&
+ ((CSUDMA_BASE & address) != CSUDMA_BASE) &&
+ ((RSA_CORE_BASE & address) != RSA_CORE_BASE) &&
+ ((PMU_GLOBAL_BASE & address) != PMU_GLOBAL_BASE)) {
+ return PM_RET_ERROR_ACCESS;
+ }
+
+ switch (register_access_id) {
+ case CONFIG_REG_WRITE:
+ ret = pm_mmio_write(address, mask, value);
+ break;
+ case CONFIG_REG_READ:
+ ret = pm_mmio_read(address, out);
+ break;
+ default:
+ ret = PM_RET_ERROR_ARGS;
+ WARN("Unimplemented register_access call\n\r");
+ break;
+ }
+ return ret;
+}
+
+/**
+ * pm_efuse_access() - To program or read efuse bits.
+ *
+ * This function provides access to the xilskey library to program/read
+ * efuse bits.
+ *
+ * address_low: lower 32-bit Linear memory space address
+ * address_high: higher 32-bit Linear memory space address
+ *
+ * value: Returned output value
+ *
+ * @return Returns status, either success or error+reason
+ *
+ */
+enum pm_ret_status pm_efuse_access(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_EFUSE_ACCESS, address_high, address_low);
+
+ return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+enum pm_ret_status em_set_action(uint32_t *value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ EM_PACK_PAYLOAD1(payload, EM_SET_ACTION);
+ return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+enum pm_ret_status em_remove_action(uint32_t *value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ EM_PACK_PAYLOAD1(payload, EM_REMOVE_ACTION);
+ return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+enum pm_ret_status em_send_errors(uint32_t *value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ EM_PACK_PAYLOAD1(payload, EM_SEND_ERRORS);
+ return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
new file mode 100644
index 0000000..9ba9475
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PM_API_SYS_H
+#define PM_API_SYS_H
+
+#include <stdint.h>
+
+#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,
+ PM_QID_CLOCK_GET_MAX_DIVISOR,
+};
+
+enum pm_register_access_id {
+ CONFIG_REG_WRITE,
+ CONFIG_REG_READ,
+};
+
+/**
+ * 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); \
+}
+
+/**********************************************************
+ * System-level API function declarations
+ **********************************************************/
+enum pm_ret_status pm_req_suspend(enum pm_node_id target,
+ enum pm_request_ack ack,
+ uint32_t latency,
+ uint32_t state);
+
+enum pm_ret_status pm_self_suspend(enum pm_node_id nid,
+ uint32_t latency,
+ uint32_t state,
+ uintptr_t address);
+
+enum pm_ret_status pm_force_powerdown(enum pm_node_id target,
+ 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 target,
+ uint32_t 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,
+ uint32_t enable);
+
+enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype);
+
+/* API functions for managing PM Slaves */
+enum pm_ret_status pm_req_node(enum pm_node_id nid,
+ uint32_t capabilities,
+ uint32_t qos,
+ enum pm_request_ack ack);
+
+enum pm_ret_status pm_set_requirement(enum pm_node_id nid,
+ uint32_t capabilities,
+ uint32_t qos,
+ enum pm_request_ack ack);
+
+/* Miscellaneous API functions */
+enum pm_ret_status pm_get_api_version(uint32_t *version);
+enum pm_ret_status pm_get_node_status(enum pm_node_id nid,
+ uint32_t *ret_buff);
+
+/* Direct-Control API functions */
+enum pm_ret_status pm_mmio_write(uintptr_t address,
+ uint32_t mask,
+ uint32_t value);
+enum pm_ret_status pm_mmio_read(uintptr_t address, uint32_t *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(uint32_t *value);
+
+enum pm_ret_status pm_get_chipid(uint32_t *value);
+enum pm_ret_status pm_secure_rsaaes(uint32_t address_low,
+ uint32_t address_high,
+ uint32_t size,
+ uint32_t flags);
+uint32_t pm_get_shutdown_scope(void);
+void pm_get_callbackdata(uint32_t *data, size_t count);
+enum pm_ret_status pm_ioctl(enum pm_node_id nid,
+ uint32_t ioctl_id,
+ uint32_t arg1,
+ uint32_t arg2,
+ uint32_t *value);
+enum pm_ret_status pm_clock_enable(uint32_t clock_id);
+enum pm_ret_status pm_clock_disable(uint32_t clock_id);
+enum pm_ret_status pm_clock_getstate(uint32_t clock_id,
+ uint32_t *state);
+enum pm_ret_status pm_clock_setdivider(uint32_t clock_id,
+ uint32_t divider);
+enum pm_ret_status pm_clock_getdivider(uint32_t clock_id,
+ uint32_t *divider);
+enum pm_ret_status pm_clock_setrate(uint32_t clock_id,
+ uint64_t rate);
+enum pm_ret_status pm_clock_getrate(uint32_t clock_id,
+ uint64_t *rate);
+enum pm_ret_status pm_clock_setparent(uint32_t clock_id,
+ uint32_t parent_index);
+enum pm_ret_status pm_clock_getparent(uint32_t clock_id,
+ uint32_t *parent_index);
+void pm_query_data(enum pm_query_id qid, uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t *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_register_access(uint32_t register_access_id,
+ uint32_t address,
+ uint32_t mask,
+ uint32_t value,
+ uint32_t *out);
+enum pm_ret_status pm_pll_set_parameter(enum pm_node_id nid,
+ enum pm_pll_param param_id,
+ uint32_t value);
+enum pm_ret_status pm_pll_get_parameter(enum pm_node_id nid,
+ enum pm_pll_param param_id,
+ uint32_t *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);
+enum pm_ret_status pm_efuse_access(uint32_t address_high,
+ uint32_t address_low, uint32_t *value);
+enum pm_ret_status em_set_action(uint32_t *value);
+enum pm_ret_status em_remove_action(uint32_t *value);
+enum pm_ret_status em_send_errors(uint32_t *value);
+enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *version,
+ uint32_t *bit_mask, uint8_t len);
+enum pm_ret_status check_api_dependency(uint8_t id);
+
+#endif /* PM_API_SYS_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.c b/plat/xilinx/zynqmp/pm_service/pm_client.c
new file mode 100644
index 0000000..7217fa1
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_client.c
@@ -0,0 +1,354 @@
+/*
+ * 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 <assert.h>
+#include <string.h>
+
+#include <common/bl_common.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+
+#include <plat_ipi.h>
+#include <zynqmp_def.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_ipi.h"
+
+#define IRQ_MAX 84U
+#define NUM_GICD_ISENABLER ((IRQ_MAX >> 5U) + 1U)
+#define UNDEFINED_CPUID (~0U)
+
+#define PM_SUSPEND_MODE_STD 0U
+#define PM_SUSPEND_MODE_POWER_OFF 1U
+
+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 + 1U] = {
+ 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(uint32_t 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] = { 0 };
+ uintptr_t isenabler1 = BASE_GICD_BASE + GICD_ISENABLER + 4U;
+
+ /* 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, 1U);
+ /**
+ * 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 = 0U; reg_num < NUM_GICD_ISENABLER; reg_num++) {
+ uint32_t base_irq = reg_num << ISENABLER_SHIFT;
+ uint32_t reg = mmio_read_32(isenabler1 + (reg_num << 2U));
+
+ if (reg == 0) {
+ 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 && node < NODE_MAX) {
+ if (pm_wakeup_nodes_set[node] == 0U) {
+ ret = pm_set_wakeup_source(NODE_APU, node, 1U);
+ pm_wakeup_nodes_set[node] = (ret == PM_RET_SUCCESS) ? 1U : 0U;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * 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(uint32_t 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 uint32_t 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, uint32_t 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)
+{
+ uint32_t 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;
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_defs.h b/plat/xilinx/zynqmp/pm_service/pm_defs.h
new file mode 100644
index 0000000..e335b94
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_defs.h
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2013-2022, 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 1U
+#define PM_VERSION_MINOR 1U
+
+#define PM_VERSION ((PM_VERSION_MAJOR << 16U) | PM_VERSION_MINOR)
+
+/**
+ * PM API versions
+ */
+/* Expected version of firmware APIs */
+#define FW_API_BASE_VERSION (1U)
+/* Expected version of firmware API for feature check */
+#define FW_API_VERSION_2 (2U)
+/* Version of APIs implemented in ATF */
+#define ATF_API_BASE_VERSION (1U)
+
+/* 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
+
+/* APU processor states */
+#define PM_PROC_STATE_FORCEDOFF 0U
+#define PM_PROC_STATE_ACTIVE 1U
+#define PM_PROC_STATE_SLEEP 2U
+#define PM_PROC_STATE_SUSPENDING 3U
+
+#define EM_FUNID_NUM_MASK 0xF0000U
+
+#define PM_GET_CALLBACK_DATA 0xa01
+#define PM_SET_SUSPEND_MODE 0xa02
+#define PM_GET_TRUSTZONE_VERSION 0xa03
+
+/*********************************************************************
+ * 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 Register Access API */
+ PM_REGISTER_ACCESS,
+ PM_EFUSE_ACCESS,
+ PM_FPGA_GET_VERSION,
+ PM_FPGA_GET_FEATURE_LIST,
+ PM_FEATURE_CHECK = 63,
+ 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 (deprecated)
+ * @PM_RET_ERROR_NOTSUPPORTED: feature not supported (deprecated)
+ * @PM_RET_ERROR_NOT_ENABLED: feature is not enabled
+ * @PM_RET_ERROR_INTERNAL: internal error
+ * @PM_RET_ERROR_CONFLICT: conflict
+ * @PM_RET_ERROR_ACCESS: access rights violation
+ * @PM_RET_ERROR_INVALID_NODE: invalid node
+ * @PM_RET_ERROR_DOUBLE_REQ: duplicate request for same node
+ * @PM_RET_ERROR_ABORT_SUSPEND: suspend procedure has been aborted
+ * @PM_RET_ERROR_TIMEOUT: timeout in communication with PMU
+ * @PM_RET_ERROR_NODE_USED: node is already in use
+ */
+enum pm_ret_status {
+ PM_RET_SUCCESS = (0U),
+ PM_RET_ERROR_ARGS = (1U),
+ PM_RET_ERROR_NOTSUPPORTED = (4U),
+ PM_RET_ERROR_NOT_ENABLED = (29U),
+ PM_RET_ERROR_INTERNAL = (2000U),
+ PM_RET_ERROR_CONFLICT = (2001U),
+ PM_RET_ERROR_ACCESS = (2002U),
+ PM_RET_ERROR_INVALID_NODE = (2003U),
+ PM_RET_ERROR_DOUBLE_REQ = (2004U),
+ PM_RET_ERROR_ABORT_SUSPEND = (2005U),
+ PM_RET_ERROR_TIMEOUT = (2006U),
+ PM_RET_ERROR_NODE_USED = (2007U),
+ PM_RET_ERROR_NO_FEATURE = (2008U)
+};
+
+/**
+ * @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,
+};
+
+/**
+ * EM API IDs
+ */
+enum em_api_id {
+ EM_SET_ACTION = 1,
+ EM_REMOVE_ACTION,
+ EM_SEND_ERRORS,
+};
+
+#endif /* PM_DEFS_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
new file mode 100644
index 0000000..03fa316
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
@@ -0,0 +1,621 @@
+/*
+ * Copyright (c) 2013-2022, 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 <errno.h>
+
+#include <common/runtime_svc.h>
+#if ZYNQMP_WDT_RESTART
+#include <arch_helpers.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <plat/common/platform.h>
+#endif
+
+#include <plat_private.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_defs.h"
+#include "pm_ipi.h"
+
+/* pm_up = !0 - UP, pm_up = 0 - DOWN */
+static int32_t pm_up, ipi_irq_flag;
+
+#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);
+
+ for (i = PLATFORM_CORE_COUNT - 1; i >= 0; i--) {
+ if (target_cpu_list & (1 << i)) {
+ /* trigger SGI to active cores */
+ plat_ic_raise_el3_sgi(ARM_IRQ_SEC_SGI_7, i);
+ }
+ }
+}
+
+/**
+ * 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");
+
+ plat_ic_end_of_interrupt(id);
+
+ /* 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;
+ uint32_t value;
+
+ /* 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);
+ }
+
+ dsb();
+
+ spin_unlock(&inc_lock);
+
+ if (active_cores == 0) {
+ pm_mmio_read(PMU_GLOBAL_GEN_STORAGE4, &value);
+ value = (value & RESTART_SCOPE_MASK) >> RESTART_SCOPE_SHIFT;
+ pm_system_shutdown(PMF_SHUTDOWN_TYPE_RESET, value);
+ }
+
+ /* 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.
+ */
+int32_t pm_setup(void)
+{
+
+ pm_ipi_init(primary_proc);
+
+ pm_get_api_version(&pm_ctx.api_version);
+ if (pm_ctx.api_version < PM_VERSION) {
+ ERROR("BL31: Platform Management API version error. Expected: "
+ "v%d.%d - Found: v%d.%d\n", PM_VERSION_MAJOR,
+ PM_VERSION_MINOR, pm_ctx.api_version >> 16,
+ pm_ctx.api_version & 0xFFFFU);
+ return -EINVAL;
+ }
+
+ int32_t status = 0, ret = 0;
+#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, const void *cookie, void *handle, uint64_t flags)
+{
+ enum pm_ret_status ret;
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ uint32_t pm_arg[5];
+ uint32_t result[PAYLOAD_ARG_CNT] = {0};
+ uint32_t api_id;
+
+ /* Handle case where PM wasn't initialized properly */
+ if (pm_up == 0)
+ 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);
+ pm_arg[4] = (uint32_t)x3;
+
+ api_id = smc_fid & FUNCID_NUM_MASK;
+
+ switch (api_id) {
+ /* 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 */
+ uint32_t set_addr = pm_arg[1] & 0x1U;
+ uint64_t address = (uint64_t)pm_arg[2] << 32U;
+
+ address |= pm_arg[1] & (~0x1U);
+ 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_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_GET_API_VERSION:
+ /* Check is PM API version already verified */
+ if (pm_ctx.api_version >= PM_VERSION) {
+ if (ipi_irq_flag == 0U) {
+ /*
+ * 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);
+ ipi_irq_flag = 1U;
+ }
+ SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
+ ((uint64_t)pm_ctx.api_version << 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 = 0;
+
+ ret = pm_fpga_get_status(&value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+ }
+
+ 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_GET_CALLBACK_DATA:
+ pm_get_callbackdata(result, ARRAY_SIZE(result));
+ SMC_RET2(handle,
+ (uint64_t)result[0] | ((uint64_t)result[1] << 32),
+ (uint64_t)result[2] | ((uint64_t)result[3] << 32));
+ case PM_IOCTL:
+ {
+ uint32_t value = 0;
+
+ 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 };
+
+ 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 = 0;
+
+ 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 = 0;
+
+ 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 = 0;
+
+ 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 = 0;
+
+ ret = pm_clock_getparent(pm_arg[0], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U);
+ }
+
+ case PM_GET_TRUSTZONE_VERSION:
+ SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
+ ((uint64_t)ZYNQMP_TZ_VERSION << 32U));
+
+ 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:
+ {
+ 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] << 32U),
+ result[1]);
+ }
+
+ case PM_FPGA_READ:
+ {
+ uint32_t value = 0;
+
+ 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) << 32U);
+ }
+
+ case PM_SECURE_AES:
+ {
+ uint32_t value = 0;
+
+ ret = pm_aes_engine(pm_arg[0], pm_arg[1], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U);
+ }
+
+ 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 = 0;
+
+ ret = pm_pll_get_parameter(pm_arg[0], pm_arg[1], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value << 32U));
+ }
+
+ 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 = 0;
+
+ ret = pm_pll_get_mode(pm_arg[0], &mode);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)mode << 32U));
+ }
+
+ case PM_REGISTER_ACCESS:
+ {
+ uint32_t value = 0;
+
+ ret = pm_register_access(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U);
+ }
+
+ case PM_EFUSE_ACCESS:
+ {
+ uint32_t value = 0;
+
+#if defined(ZYNQMP_SECURE_EFUSES)
+ if (is_caller_non_secure(flags)) {
+ SMC_RET1(handle,
+ (((uint64_t)PM_RET_ERROR_NOT_ENABLED) << 32U) |
+ (uint64_t)PM_RET_ERROR_ACCESS);
+ }
+#endif
+ ret = pm_efuse_access(pm_arg[0], pm_arg[1], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U);
+ }
+
+ case PM_FPGA_GET_VERSION:
+ case PM_FPGA_GET_FEATURE_LIST:
+ {
+ uint32_t ret_payload[PAYLOAD_ARG_CNT];
+
+ PM_PACK_PAYLOAD5(payload, smc_fid & FUNCID_NUM_MASK,
+ pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]);
+ ret = pm_ipi_send_sync(primary_proc, payload, ret_payload, 3U);
+ SMC_RET2(handle, (uint64_t)ret | (uint64_t)ret_payload[0] << 32U,
+ (uint64_t)ret_payload[1] | (uint64_t)ret_payload[2] << 32U);
+ }
+
+ case PM_FEATURE_CHECK:
+ {
+ uint32_t version = 0;
+ uint32_t bit_mask[2] = {0};
+
+ ret = pm_feature_check(pm_arg[0], &version, bit_mask,
+ ARRAY_SIZE(bit_mask));
+ SMC_RET2(handle, (uint64_t)ret | ((uint64_t)version << 32U),
+ (uint64_t)bit_mask[0] | ((uint64_t)bit_mask[1] << 32U));
+ }
+
+ default:
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD6(payload, api_id, pm_arg[0], pm_arg[1],
+ pm_arg[2], pm_arg[3], pm_arg[4]);
+ ret = pm_ipi_send_sync(primary_proc, payload, result,
+ PAYLOAD_ARG_CNT);
+ SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U),
+ (uint64_t)result[1] | ((uint64_t)result[2] << 32U));
+ }
+}
+
+/**
+ * em_smc_handler() - SMC handler for EM-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 EM SMC Function ID from the
+ * list of em_api_ids, otherwise completes the request with
+ * the unknown SMC Function ID
+ *
+ * The SMC calls for EM service are forwarded from SIP Service SMC handler
+ * function with rt_svc_handle signature
+ */
+uint64_t em_smc_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)
+{
+ enum pm_ret_status ret;
+
+ switch (smc_fid & FUNCID_NUM_MASK) {
+ /* EM API Functions */
+ case EM_SET_ACTION:
+ {
+ uint32_t value;
+
+ ret = em_set_action(&value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U);
+ }
+
+ case EM_REMOVE_ACTION:
+ {
+ uint32_t value;
+
+ ret = em_remove_action(&value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U);
+ }
+
+ case EM_SEND_ERRORS:
+ {
+ uint32_t value;
+
+ ret = em_send_errors(&value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U);
+ }
+
+ default:
+ WARN("Unimplemented EM Service Call: 0x%x\n", smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+ }
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.h b/plat/xilinx/zynqmp/pm_service/pm_svc_main.h
new file mode 100644
index 0000000..c1781f3
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2013-2020, 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"
+
+int32_t pm_setup(void);
+uint64_t pm_smc_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);
+
+uint64_t em_smc_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 /* PM_SVC_MAIN_H */
diff --git a/plat/xilinx/zynqmp/sip_svc_setup.c b/plat/xilinx/zynqmp/sip_svc_setup.c
new file mode 100644
index 0000000..4ce9b8a
--- /dev/null
+++ b/plat/xilinx/zynqmp/sip_svc_setup.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2013-2020, 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 <common/runtime_svc.h>
+#include <tools_share/uuid.h>
+
+#include "ipi_mailbox_svc.h"
+#include "pm_svc_main.h"
+
+/* SMC function IDs for SiP Service queries */
+#define ZYNQMP_SIP_SVC_CALL_COUNT U(0x8200ff00)
+#define ZYNQMP_SIP_SVC_UID U(0x8200ff01)
+#define ZYNQMP_SIP_SVC_VERSION U(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 EM_FID_MASK 0xf0000u
+#define EM_FID_VALUE 0xE0000u
+#define is_em_fid(_fid) (((_fid) & EM_FID_MASK) == EM_FID_VALUE)
+#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 */
+ return pm_setup();
+}
+
+/**
+ * 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.
+ */
+static 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 EM SMC handler deal with EM-related requests */
+ if (is_em_fid(smc_fid)) {
+ return em_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
+ flags);
+ } else if (is_pm_fid(smc_fid)) {
+ /* Let PM SMC handler deal with PM-related requests */
+ 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,
+ (uint8_t)SMC_TYPE_FAST,
+ sip_svc_setup,
+ sip_svc_smc_handler);
diff --git a/plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk b/plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk
new file mode 100644
index 0000000..318b01d
--- /dev/null
+++ b/plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk
@@ -0,0 +1,8 @@
+#
+# 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
diff --git a/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c b/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c
new file mode 100644
index 0000000..352ba82
--- /dev/null
+++ b/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat_private.h>
+#include <platform_tsp.h>
+
+/*******************************************************************************
+ * Initialize the UART
+ ******************************************************************************/
+void tsp_early_platform_setup(void)
+{
+ /*
+ * Register a different console than already in use to display
+ * messages from TSP
+ */
+ static console_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_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);
+}
diff --git a/plat/xilinx/zynqmp/zynqmp_ehf.c b/plat/xilinx/zynqmp/zynqmp_ehf.c
new file mode 100644
index 0000000..fbf1ed0
--- /dev/null
+++ b/plat/xilinx/zynqmp/zynqmp_ehf.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) Siemens AG, 2020-2021
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <bl31/ehf.h>
+
+/*
+ * Enumeration of priority levels on ARM platforms.
+ */
+ehf_pri_desc_t zynqmp_exceptions[] = {
+ /* Critical priority SDEI */
+ EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SDEI_CRITICAL_PRI),
+
+ /* Normal priority SDEI */
+ EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SDEI_NORMAL_PRI),
+};
+
+/* Plug in ARM exceptions to Exception Handling Framework. */
+EHF_REGISTER_PRIORITIES(zynqmp_exceptions, ARRAY_SIZE(zynqmp_exceptions), PLAT_PRI_BITS);
diff --git a/plat/xilinx/zynqmp/zynqmp_ipi.c b/plat/xilinx/zynqmp/zynqmp_ipi.c
new file mode 100644
index 0000000..4ea3c6a
--- /dev/null
+++ b/plat/xilinx/zynqmp/zynqmp_ipi.c
@@ -0,0 +1,100 @@
+/*
+ * 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 <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include <ipi.h>
+#include <plat_ipi.h>
+#include <plat_private.h>
+
+/* Zynqmp ipi configuration table */
+const static struct ipi_config zynqmp_ipi_table[] = {
+ /* APU IPI */
+ {
+ .ipi_bit_mask = 0x1,
+ .ipi_reg_base = 0xFF300000U,
+ .secure_only = 0,
+ },
+ /* RPU0 IPI */
+ {
+ .ipi_bit_mask = 0x100,
+ .ipi_reg_base = 0xFF310000U,
+ .secure_only = 0,
+ },
+ /* RPU1 IPI */
+ {
+ .ipi_bit_mask = 0x200,
+ .ipi_reg_base = 0xFF320000U,
+ .secure_only = 0,
+ },
+ /* PMU0 IPI */
+ {
+ .ipi_bit_mask = 0x10000,
+ .ipi_reg_base = 0xFF330000U,
+ .secure_only = IPI_SECURE_MASK,
+ },
+ /* PMU1 IPI */
+ {
+ .ipi_bit_mask = 0x20000,
+ .ipi_reg_base = 0xFF331000U,
+ .secure_only = 0,
+ },
+ /* PMU2 IPI */
+ {
+ .ipi_bit_mask = 0x40000,
+ .ipi_reg_base = 0xFF332000U,
+ .secure_only = IPI_SECURE_MASK,
+ },
+ /* PMU3 IPI */
+ {
+ .ipi_bit_mask = 0x80000,
+ .ipi_reg_base = 0xFF333000U,
+ .secure_only = IPI_SECURE_MASK,
+ },
+ /* PL0 IPI */
+ {
+ .ipi_bit_mask = 0x1000000,
+ .ipi_reg_base = 0xFF340000U,
+ .secure_only = 0,
+ },
+ /* PL1 IPI */
+ {
+ .ipi_bit_mask = 0x2000000,
+ .ipi_reg_base = 0xFF350000U,
+ .secure_only = 0,
+ },
+ /* PL2 IPI */
+ {
+ .ipi_bit_mask = 0x4000000,
+ .ipi_reg_base = 0xFF360000U,
+ .secure_only = 0,
+ },
+ /* PL3 IPI */
+ {
+ .ipi_bit_mask = 0x8000000,
+ .ipi_reg_base = 0xFF370000U,
+ .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));
+}
diff --git a/plat/xilinx/zynqmp/zynqmp_sdei.c b/plat/xilinx/zynqmp/zynqmp_sdei.c
new file mode 100644
index 0000000..7e92b58
--- /dev/null
+++ b/plat/xilinx/zynqmp/zynqmp_sdei.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) Siemens AG, 2020-2021
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* SDEI configuration for ARM platforms */
+
+#include <bl31/ehf.h>
+#include <common/debug.h>
+#include <services/sdei.h>
+
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+int arm_validate_ns_entrypoint(uintptr_t entrypoint)
+{
+ return (entrypoint < BL31_BASE || entrypoint > BL31_LIMIT) ? 0 : -1;
+}
+
+/* Private event mappings */
+static sdei_ev_map_t zynqmp_sdei_private[] = {
+ SDEI_DEFINE_EVENT_0(ZYNQMP_SDEI_SGI_PRIVATE),
+};
+
+/* Shared event mappings */
+static sdei_ev_map_t zynqmp_sdei_shared[] = {
+};
+
+void plat_sdei_setup(void)
+{
+ INFO("SDEI platform setup\n");
+}
+
+/* Export ARM SDEI events */
+REGISTER_SDEI_MAP(zynqmp_sdei_private, zynqmp_sdei_shared);
diff --git a/readme.rst b/readme.rst
new file mode 100644
index 0000000..148d477
--- /dev/null
+++ b/readme.rst
@@ -0,0 +1,51 @@
+Trusted 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
+
diff --git a/services/arm_arch_svc/arm_arch_svc_setup.c b/services/arm_arch_svc/arm_arch_svc_setup.c
new file mode 100644
index 0000000..46ccd9e
--- /dev/null
+++ b/services/arm_arch_svc/arm_arch_svc_setup.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/cpus/errata_report.h>
+#include <lib/cpus/wa_cve_2017_5715.h>
+#include <lib/cpus/wa_cve_2018_3639.h>
+#include <lib/cpus/wa_cve_2022_23960.h>
+#include <lib/smccc.h>
+#include <services/arm_arch_svc.h>
+#include <smccc_helpers.h>
+#include <plat/common/platform.h>
+
+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 arg1)
+{
+ switch (arg1) {
+ case SMCCC_VERSION:
+ case SMCCC_ARCH_FEATURES:
+ return SMC_ARCH_CALL_SUCCESS;
+ case SMCCC_ARCH_SOC_ID:
+ return plat_is_smccc_feature_available(arg1);
+#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 SMC_ARCH_CALL_NOT_REQUIRED;
+#endif
+ }
+#endif
+
+#if (WORKAROUND_CVE_2022_23960 || WORKAROUND_CVE_2017_5715)
+ case SMCCC_ARCH_WORKAROUND_3:
+ /*
+ * SMCCC_ARCH_WORKAROUND_3 should also take into account
+ * CVE-2017-5715 since this SMC can be used instead of
+ * SMCCC_ARCH_WORKAROUND_1.
+ */
+ if ((check_smccc_arch_wa3_applies() == ERRATA_NOT_APPLIES) &&
+ (check_wa_cve_2017_5715() == ERRATA_NOT_APPLIES)) {
+ return 1;
+ }
+ return 0; /* ERRATA_APPLIES || ERRATA_MISSING */
+#endif
+
+ /* Fallthrough */
+
+ default:
+ return SMC_UNK;
+ }
+}
+
+/* return soc revision or soc version on success otherwise
+ * return invalid parameter */
+static int32_t smccc_arch_id(u_register_t arg1)
+{
+ if (arg1 == SMCCC_GET_SOC_REVISION) {
+ return plat_get_soc_revision();
+ }
+ if (arg1 == SMCCC_GET_SOC_VERSION) {
+ return plat_get_soc_version();
+ }
+ return SMC_ARCH_CALL_INVAL_PARAM;
+}
+
+/*
+ * 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));
+ case SMCCC_ARCH_SOC_ID:
+ SMC_RET1(handle, smccc_arch_id(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
+#if (WORKAROUND_CVE_2022_23960 || WORKAROUND_CVE_2017_5715)
+ case SMCCC_ARCH_WORKAROUND_3:
+ /*
+ * 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
+ 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
+);
diff --git a/services/spd/opteed/opteed.mk b/services/spd/opteed/opteed.mk
new file mode 100644
index 0000000..643b054
--- /dev/null
+++ b/services/spd/opteed/opteed.mk
@@ -0,0 +1,18 @@
+#
+# 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
diff --git a/services/spd/opteed/opteed_common.c b/services/spd/opteed/opteed_common.c
new file mode 100644
index 0000000..9aa19c5
--- /dev/null
+++ b/services/spd/opteed/opteed_common.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/utils.h>
+
+#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);
+}
diff --git a/services/spd/opteed/opteed_helpers.S b/services/spd/opteed/opteed_helpers.S
new file mode 100644
index 0000000..075a71b
--- /dev/null
+++ b/services/spd/opteed/opteed_helpers.S
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#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
diff --git a/services/spd/opteed/opteed_main.c b/services/spd/opteed/opteed_main.c
new file mode 100644
index 0000000..160a693
--- /dev/null
+++ b/services/spd/opteed/opteed_main.c
@@ -0,0 +1,420 @@
+/*
+ * 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 <assert.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+#include <tools_share/uuid.h>
+
+#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
+);
diff --git a/services/spd/opteed/opteed_pm.c b/services/spd/opteed/opteed_pm.c
new file mode 100644
index 0000000..719eeb7
--- /dev/null
+++ b/services/spd/opteed/opteed_pm.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+
+#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,
+};
diff --git a/services/spd/opteed/opteed_private.h b/services/spd/opteed/opteed_private.h
new file mode 100644
index 0000000..242154f
--- /dev/null
+++ b/services/spd/opteed/opteed_private.h
@@ -0,0 +1,162 @@
+/*
+ * 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 <platform_def.h>
+
+#include <arch.h>
+#include <bl31/interrupt_mgmt.h>
+#include <context.h>
+#include <lib/psci/psci.h>
+
+/*******************************************************************************
+ * 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 <stdint.h>
+
+#include <lib/cassert.h>
+
+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 */
diff --git a/services/spd/opteed/teesmc_opteed.h b/services/spd/opteed/teesmc_opteed.h
new file mode 100644
index 0000000..c82b58a
--- /dev/null
+++ b/services/spd/opteed/teesmc_opteed.h
@@ -0,0 +1,123 @@
+/*
+ * 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*/
diff --git a/services/spd/opteed/teesmc_opteed_macros.h b/services/spd/opteed/teesmc_opteed_macros.h
new file mode 100644
index 0000000..9d8a169
--- /dev/null
+++ b/services/spd/opteed/teesmc_opteed_macros.h
@@ -0,0 +1,17 @@
+/*
+ * 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 <common/runtime_svc.h>
+
+#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 */
diff --git a/services/spd/pncd/pncd.mk b/services/spd/pncd/pncd.mk
new file mode 100644
index 0000000..0f8eb25
--- /dev/null
+++ b/services/spd/pncd/pncd.mk
@@ -0,0 +1,24 @@
+# Copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+PNCD_DIR := services/spd/pncd
+SPD_INCLUDES := -Iinclude/bl32/pnc
+SPD_INCLUDES += -Iinclude/common/
+
+SPD_SOURCES := services/spd/pncd/pncd_common.c \
+ services/spd/pncd/pncd_helpers.S \
+ services/spd/pncd/pncd_main.c
+
+NEED_BL32 := yes
+
+# The following constants need to be defined:
+# - SPD_PNCD_NS_IRQ: IRQ number used to notify NS world when SMC_ACTION_FROM_S is received
+# - SPD_PNCD_S_IRQ: IRQ number used to notify S world when SMC_ACTION_FROM_NS is received
+$(eval $(call assert_numerics, SPD_PNCD_NS_IRQ SPD_PNCD_S_IRQ))
+
+$(eval $(call add_defines,\
+ $(sort \
+ SPD_PNCD_NS_IRQ \
+ SPD_PNCD_S_IRQ \
+)))
diff --git a/services/spd/pncd/pncd_common.c b/services/spd/pncd/pncd_common.c
new file mode 100644
index 0000000..6fdb629
--- /dev/null
+++ b/services/spd/pncd/pncd_common.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#include "pncd_private.h"
+
+/*******************************************************************************
+ * Given a secure payload entrypoint info pointer, entry point PC & pointer to a
+ * context data structure, this function will initialize pnc context and entry
+ * point info for the secure payload
+ ******************************************************************************/
+void pncd_init_pnc_ep_state(struct entry_point_info *pnc_entry_point,
+ uint64_t pc,
+ pnc_context_t *pnc_ctx)
+{
+ uint32_t ep_attr;
+
+ /* Passing a NULL context is a critical programming error */
+ assert(pnc_ctx);
+ assert(pnc_entry_point);
+ assert(pc);
+
+ /* Associate this context with the current cpu */
+ pnc_ctx->mpidr = read_mpidr();
+
+ cm_set_context(&pnc_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(pnc_entry_point, PARAM_EP, VERSION_1, ep_attr);
+
+ pnc_entry_point->pc = pc;
+ pnc_entry_point->spsr = SPSR_64(MODE_EL1,
+ MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS);
+ memset(&pnc_entry_point->args, 0, sizeof(pnc_entry_point->args));
+}
+
+/*******************************************************************************
+ * This function takes an SP context pointer and:
+ * 1. Applies the S-EL1 system register context from pnc_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 pnc_ctx->cpu_ctx are used to enter the secure payload image.
+ ******************************************************************************/
+uint64_t pncd_synchronous_sp_entry(pnc_context_t *pnc_ctx)
+{
+ assert(pnc_ctx != NULL);
+ assert(pnc_ctx->c_rt_ctx == 0U);
+
+ /* Apply the Secure EL1 system register context and switch to it */
+ assert(cm_get_context(SECURE) == &pnc_ctx->cpu_ctx);
+ cm_el1_sysregs_context_restore(SECURE);
+#if CTX_INCLUDE_FPREGS
+ fpregs_context_restore(get_fpregs_ctx(cm_get_context(SECURE)));
+#endif
+ cm_set_next_eret_context(SECURE);
+
+ return pncd_enter_sp(&pnc_ctx->c_rt_ctx);
+}
+
+
+/*******************************************************************************
+ * This function takes an SP context pointer and:
+ * 1. Saves the S-EL1 system register context tp pnc_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 pncd_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 pncd_synchronous_sp_exit(pnc_context_t *pnc_ctx, uint64_t ret)
+{
+ assert(pnc_ctx != NULL);
+ /* Save the Secure EL1 system register context */
+ assert(cm_get_context(SECURE) == &pnc_ctx->cpu_ctx);
+ cm_el1_sysregs_context_save(SECURE);
+#if CTX_INCLUDE_FPREGS
+ fpregs_context_save(get_fpregs_ctx(cm_get_context(SECURE)));
+#endif
+
+ assert(pnc_ctx->c_rt_ctx != 0);
+ pncd_exit_sp(pnc_ctx->c_rt_ctx, ret);
+
+ /* Should never reach here */
+ panic();
+}
diff --git a/services/spd/pncd/pncd_helpers.S b/services/spd/pncd/pncd_helpers.S
new file mode 100644
index 0000000..736b30f
--- /dev/null
+++ b/services/spd/pncd/pncd_helpers.S
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include "pncd_private.h"
+
+ .global pncd_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 pncd_enter_sp
+ /* Make space for the registers that we're going to save */
+ mov x3, sp
+ str x3, [x0, #0]
+ sub sp, sp, #PNCD_C_RT_CTX_SIZE
+
+ /* Save callee-saved registers on to the stack */
+ stp x19, x20, [sp, #PNCD_C_RT_CTX_X19]
+ stp x21, x22, [sp, #PNCD_C_RT_CTX_X21]
+ stp x23, x24, [sp, #PNCD_C_RT_CTX_X23]
+ stp x25, x26, [sp, #PNCD_C_RT_CTX_X25]
+ stp x27, x28, [sp, #PNCD_C_RT_CTX_X27]
+ stp x29, x30, [sp, #PNCD_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 pncd_enter_sp
+
+ /* ---------------------------------------------
+ * This function is called 'x0' pointing to a C
+ * runtime context saved in pncd_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 pncd_exit_sp
+func pncd_exit_sp
+ /* Restore the previous stack */
+ mov sp, x0
+
+ /* Restore callee-saved registers on to the stack */
+ ldp x19, x20, [x0, #(PNCD_C_RT_CTX_X19 - PNCD_C_RT_CTX_SIZE)]
+ ldp x21, x22, [x0, #(PNCD_C_RT_CTX_X21 - PNCD_C_RT_CTX_SIZE)]
+ ldp x23, x24, [x0, #(PNCD_C_RT_CTX_X23 - PNCD_C_RT_CTX_SIZE)]
+ ldp x25, x26, [x0, #(PNCD_C_RT_CTX_X25 - PNCD_C_RT_CTX_SIZE)]
+ ldp x27, x28, [x0, #(PNCD_C_RT_CTX_X27 - PNCD_C_RT_CTX_SIZE)]
+ ldp x29, x30, [x0, #(PNCD_C_RT_CTX_X29 - PNCD_C_RT_CTX_SIZE)]
+
+ /* ---------------------------------------------
+ * This should take us back to the instruction
+ * after the call to the last pncd_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 pncd_exit_sp
diff --git a/services/spd/pncd/pncd_main.c b/services/spd/pncd/pncd_main.c
new file mode 100644
index 0000000..99c4aa1
--- /dev/null
+++ b/services/spd/pncd/pncd_main.c
@@ -0,0 +1,471 @@
+/*
+ * Copyright (c) 2021-2022, ProvenRun S.A.S. 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 <assert.h>
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <bl31/interrupt_mgmt.h>
+#include <bl_common.h>
+#include <common/debug.h>
+#include <common/ep_info.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/spinlock.h>
+#include <plat/common/platform.h>
+#include <pnc.h>
+#include "pncd_private.h"
+#include <runtime_svc.h>
+#include <tools_share/uuid.h>
+
+/*******************************************************************************
+ * Structure to keep track of ProvenCore state
+ ******************************************************************************/
+static pnc_context_t pncd_sp_context;
+
+static bool ree_info;
+static uint64_t ree_base_addr;
+static uint64_t ree_length;
+static uint64_t ree_tag;
+
+static bool pnc_initialized;
+
+static spinlock_t smc_handler_lock;
+
+static int pncd_init(void);
+
+static void context_save(unsigned long security_state)
+{
+ assert(sec_state_is_valid(security_state));
+
+ cm_el1_sysregs_context_save((uint32_t) security_state);
+#if CTX_INCLUDE_FPREGS
+ fpregs_context_save(get_fpregs_ctx(cm_get_context(security_state)));
+#endif
+}
+
+static void *context_restore(unsigned long security_state)
+{
+ void *handle;
+
+ assert(sec_state_is_valid(security_state));
+
+ /* Get a reference to the next context */
+ handle = cm_get_context((uint32_t) security_state);
+ assert(handle);
+
+ /* Restore state */
+ cm_el1_sysregs_context_restore((uint32_t) security_state);
+#if CTX_INCLUDE_FPREGS
+ fpregs_context_restore(get_fpregs_ctx(cm_get_context(security_state)));
+#endif
+
+ cm_set_next_eret_context((uint32_t) security_state);
+
+ return handle;
+}
+
+static uint64_t pncd_sel1_interrupt_handler(uint32_t id,
+ uint32_t flags, void *handle, void *cookie);
+
+/*******************************************************************************
+ * Switch context to the specified security state and return the targeted
+ * handle. Note that the context may remain unchanged if the switch is not
+ * allowed.
+ ******************************************************************************/
+void *pncd_context_switch_to(unsigned long security_state)
+{
+ unsigned long sec_state_from =
+ security_state == SECURE ? NON_SECURE : SECURE;
+
+ assert(sec_state_is_valid(security_state));
+
+ /* Check if this is the first world switch */
+ if (!pnc_initialized) {
+ int rc;
+ uint32_t flags;
+
+ assert(sec_state_from == SECURE);
+
+ INFO("PnC initialization done\n");
+
+ /*
+ * Register an interrupt handler for S-EL1 interrupts
+ * when generated during code executing in the
+ * non-secure state.
+ */
+ flags = 0U;
+ set_interrupt_rm_flag(flags, NON_SECURE);
+ rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
+ pncd_sel1_interrupt_handler,
+ flags);
+ if (rc != 0) {
+ ERROR("Failed to register S-EL1 interrupt handler (%d)\n",
+ rc);
+ panic();
+ }
+
+ context_save(SECURE);
+
+ pnc_initialized = true;
+
+ /*
+ * Release the lock before restoring the EL3 context to
+ * bl31_main.
+ */
+ spin_unlock(&smc_handler_lock);
+
+ /*
+ * 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.
+ */
+ pncd_synchronous_sp_exit(&pncd_sp_context, (uint64_t) 0x0);
+
+ /* Unreachable */
+ ERROR("Returned from pncd_synchronous_sp_exit... Should not happen\n");
+ panic();
+ }
+
+ /* Check that the world switch is allowed */
+ if (read_mpidr() != pncd_sp_context.mpidr) {
+ if (sec_state_from == SECURE) {
+ /*
+ * Secure -> Non-Secure world switch initiated on a CPU where there
+ * should be no Trusted OS running
+ */
+ WARN("Secure to Non-Secure switch requested on CPU where ProvenCore is not supposed to be running...\n");
+ }
+
+ /*
+ * Secure or Non-Secure world wants to switch world but there is no Secure
+ * software on this core
+ */
+ return cm_get_context((uint32_t) sec_state_from);
+ }
+
+ context_save(sec_state_from);
+
+ return context_restore(security_state);
+}
+
+/*******************************************************************************
+ * This function is the handler registered for S-EL1 interrupts by the PNCD. It
+ * validates the interrupt and upon success arranges entry into the PNC at
+ * 'pnc_sel1_intr_entry()' for handling the interrupt.
+ ******************************************************************************/
+static uint64_t pncd_sel1_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) == NON_SECURE);
+
+ /* Sanity check the pointer to this cpu's context */
+ assert(handle == cm_get_context(NON_SECURE));
+
+ /* switch to PnC */
+ handle = pncd_context_switch_to(SECURE);
+
+ assert(handle != NULL);
+
+ SMC_RET0(handle);
+}
+
+#pragma weak plat_pncd_setup
+int plat_pncd_setup(void)
+{
+ return 0;
+}
+
+/*******************************************************************************
+ * 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 int pncd_setup(void)
+{
+ entry_point_info_t *pnc_ep_info;
+
+ /*
+ * Get information about the Secure Payload (BL32) image. Its
+ * absence is a critical failure.
+ *
+ * TODO: Add support to conditionally include the SPD service
+ */
+ pnc_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
+ if (!pnc_ep_info) {
+ WARN("No PNC provided by BL2 boot loader, Booting device without PNC initialization. SMC`s destined for PNC 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 (!pnc_ep_info->pc) {
+ return 1;
+ }
+
+ pncd_init_pnc_ep_state(pnc_ep_info,
+ pnc_ep_info->pc,
+ &pncd_sp_context);
+
+ /*
+ * All PNCD initialization done. Now register our init function with
+ * BL31 for deferred invocation
+ */
+ bl31_register_bl32_init(&pncd_init);
+ bl31_set_next_image_type(NON_SECURE);
+
+ return plat_pncd_setup();
+}
+
+/*******************************************************************************
+ * 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 pncd_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.
+ ******************************************************************************/
+static int32_t pncd_init(void)
+{
+ entry_point_info_t *pnc_entry_point;
+ uint64_t rc = 0;
+
+ /*
+ * Get information about the Secure Payload (BL32) image. Its
+ * absence is a critical failure.
+ */
+ pnc_entry_point = bl31_plat_get_next_image_ep_info(SECURE);
+ assert(pnc_entry_point);
+
+ cm_init_my_context(pnc_entry_point);
+
+ /*
+ * Arrange for an entry into the test secure payload. It will be
+ * returned via PNC_ENTRY_DONE case
+ */
+ rc = pncd_synchronous_sp_entry(&pncd_sp_context);
+
+ /*
+ * If everything went well at this point, the return value should be 0.
+ */
+ return rc == 0;
+}
+
+#pragma weak plat_pncd_smc_handler
+/*******************************************************************************
+ * This function is responsible for handling the platform-specific SMCs in the
+ * Trusted OS/App range as defined in the SMC Calling Convention Document.
+ ******************************************************************************/
+uintptr_t plat_pncd_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)
+{
+ (void) smc_fid;
+ (void) x1;
+ (void) x2;
+ (void) x3;
+ (void) x4;
+ (void) cookie;
+ (void) flags;
+
+ SMC_RET1(handle, SMC_UNK);
+}
+
+/*******************************************************************************
+ * This function is responsible for handling all SMCs in the Trusted OS/App
+ * range 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.
+ *
+ * It should only be called with the smc_handler_lock held.
+ ******************************************************************************/
+static uintptr_t pncd_smc_handler_unsafe(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);
+
+ assert(ns != 0 || read_mpidr() == pncd_sp_context.mpidr);
+
+ switch (smc_fid) {
+ case SMC_CONFIG_SHAREDMEM:
+ if (ree_info) {
+ /* Do not Yield */
+ SMC_RET0(handle);
+ }
+
+ /*
+ * Fetch the physical base address (x1) and size (x2) of the
+ * shared memory allocated by the Non-Secure world. This memory
+ * will be used by PNC to communicate with the Non-Secure world.
+ * Verifying the validity of these values is up to the Trusted
+ * OS.
+ */
+ ree_base_addr = x1 | (x2 << 32);
+ ree_length = x3;
+ ree_tag = x4;
+
+ INFO("IN SMC_CONFIG_SHAREDMEM: addr=%lx, length=%lx, tag=%lx\n",
+ (unsigned long) ree_base_addr,
+ (unsigned long) ree_length,
+ (unsigned long) ree_tag);
+
+ if ((ree_base_addr % 0x200000) != 0) {
+ SMC_RET1(handle, SMC_UNK);
+ }
+
+ if ((ree_length % 0x200000) != 0) {
+ SMC_RET1(handle, SMC_UNK);
+ }
+
+ ree_info = true;
+
+ /* Do not Yield */
+ SMC_RET4(handle, 0, 0, 0, 0);
+
+ break;
+
+ case SMC_GET_SHAREDMEM:
+ if (ree_info) {
+ x1 = (1U << 16) | ree_tag;
+ x2 = ree_base_addr & 0xFFFFFFFF;
+ x3 = (ree_base_addr >> 32) & 0xFFFFFFFF;
+ x4 = ree_length & 0xFFFFFFFF;
+ SMC_RET4(handle, x1, x2, x3, x4);
+ } else {
+ SMC_RET4(handle, 0, 0, 0, 0);
+ }
+
+ break;
+
+ case SMC_ACTION_FROM_NS:
+ if (ns == 0) {
+ SMC_RET1(handle, SMC_UNK);
+ }
+
+ if (SPD_PNCD_S_IRQ < MIN_PPI_ID) {
+ plat_ic_raise_s_el1_sgi(SPD_PNCD_S_IRQ,
+ pncd_sp_context.mpidr);
+ } else {
+ plat_ic_set_interrupt_pending(SPD_PNCD_S_IRQ);
+ }
+
+ SMC_RET0(handle);
+
+ break;
+
+ case SMC_ACTION_FROM_S:
+ if (ns != 0) {
+ SMC_RET1(handle, SMC_UNK);
+ }
+
+ if (SPD_PNCD_NS_IRQ < MIN_PPI_ID) {
+ /*
+ * NS SGI is sent to the same core as the one running
+ * PNC
+ */
+ plat_ic_raise_ns_sgi(SPD_PNCD_NS_IRQ, read_mpidr());
+ } else {
+ plat_ic_set_interrupt_pending(SPD_PNCD_NS_IRQ);
+ }
+
+ SMC_RET0(handle);
+
+ break;
+
+ case SMC_YIELD:
+ assert(handle == cm_get_context(ns != 0 ? NON_SECURE : SECURE));
+ handle = pncd_context_switch_to(ns != 0 ? SECURE : NON_SECURE);
+
+ assert(handle != NULL);
+
+ SMC_RET0(handle);
+
+ break;
+
+ default:
+ INFO("Unknown smc: %x\n", smc_fid);
+ break;
+ }
+
+ return plat_pncd_smc_handler(smc_fid, x1, x2, x3, x4,
+ cookie, handle, flags);
+}
+
+static uintptr_t pncd_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)
+{
+ uintptr_t ret;
+
+ /* SMC handling is serialized */
+ spin_lock(&smc_handler_lock);
+ ret = pncd_smc_handler_unsafe(smc_fid, x1, x2, x3, x4, cookie, handle,
+ flags);
+ spin_unlock(&smc_handler_lock);
+
+ return ret;
+}
+
+/* Define a SPD runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+ pncd_fast,
+ OEN_TOS_START,
+ OEN_TOS_END,
+ SMC_TYPE_FAST,
+ pncd_setup,
+ pncd_smc_handler
+);
+
+/* Define a SPD runtime service descriptor for standard SMC calls */
+DECLARE_RT_SVC(
+ pncd_std,
+ OEN_TOS_START,
+ OEN_TOS_END,
+ SMC_TYPE_YIELD,
+ NULL,
+ pncd_smc_handler
+);
diff --git a/services/spd/pncd/pncd_private.h b/services/spd/pncd/pncd_private.h
new file mode 100644
index 0000000..8c9b634
--- /dev/null
+++ b/services/spd/pncd/pncd_private.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ * Portions copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PNCD_PRIVATE_H__
+#define __PNCD_PRIVATE_H__
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+#endif /* __ASSEMBLER __ */
+
+#include <context.h>
+#ifndef __ASSEMBLER__
+#include <lib/cassert.h>
+#endif /* __ASSEMBLER __ */
+
+#include <platform_def.h>
+
+/*******************************************************************************
+ * Constants that allow assembler code to preserve callee-saved registers of the
+ * C runtime context while performing a security state switch.
+ ******************************************************************************/
+#define PNCD_C_RT_CTX_X19 U(0x0)
+#define PNCD_C_RT_CTX_X20 U(0x8)
+#define PNCD_C_RT_CTX_X21 U(0x10)
+#define PNCD_C_RT_CTX_X22 U(0x18)
+#define PNCD_C_RT_CTX_X23 U(0x20)
+#define PNCD_C_RT_CTX_X24 U(0x28)
+#define PNCD_C_RT_CTX_X25 U(0x30)
+#define PNCD_C_RT_CTX_X26 U(0x38)
+#define PNCD_C_RT_CTX_X27 U(0x40)
+#define PNCD_C_RT_CTX_X28 U(0x48)
+#define PNCD_C_RT_CTX_X29 U(0x50)
+#define PNCD_C_RT_CTX_X30 U(0x58)
+#define PNCD_C_RT_CTX_SIZE U(0x60)
+#define PNCD_C_RT_CTX_ENTRIES (PNCD_C_RT_CTX_SIZE >> DWORD_SHIFT)
+
+#ifndef __ASSEMBLER__
+
+/* AArch64 callee saved general purpose register context structure. */
+DEFINE_REG_STRUCT(c_rt_regs, PNCD_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(sizeof(c_rt_regs_t) == PNCD_C_RT_CTX_SIZE,
+ assert_spd_c_rt_regs_size_mismatch);
+
+/*******************************************************************************
+ * Structure which helps the SPD to maintain the per-cpu state of the SP.
+ * 'mpidr' - mpidr of the CPU running PNC
+ * '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
+ ******************************************************************************/
+typedef struct pnc_context {
+ uint64_t mpidr;
+ uint64_t c_rt_ctx;
+ cpu_context_t cpu_ctx;
+} pnc_context_t;
+
+/*******************************************************************************
+ * Function & Data prototypes
+ ******************************************************************************/
+uint64_t pncd_enter_sp(uint64_t *c_rt_ctx);
+void __dead2 pncd_exit_sp(uint64_t c_rt_ctx, uint64_t ret);
+uint64_t pncd_synchronous_sp_entry(pnc_context_t *pnc_ctx);
+void __dead2 pncd_synchronous_sp_exit(pnc_context_t *pnc_ctx, uint64_t ret);
+void pncd_init_pnc_ep_state(struct entry_point_info *pnc_ep,
+ uint64_t pc,
+ pnc_context_t *pnc_ctx);
+#endif /* __ASSEMBLER__ */
+
+#endif /* __PNCD_PRIVATE_H__ */
diff --git a/services/spd/tlkd/tlkd.mk b/services/spd/tlkd/tlkd.mk
new file mode 100644
index 0000000..56de0a6
--- /dev/null
+++ b/services/spd/tlkd/tlkd.mk
@@ -0,0 +1,14 @@
+#
+# 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
diff --git a/services/spd/tlkd/tlkd_common.c b/services/spd/tlkd/tlkd_common.c
new file mode 100644
index 0000000..820bd8a
--- /dev/null
+++ b/services/spd/tlkd/tlkd_common.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <lib/el3_runtime/context_mgmt.h>
+
+#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:
+ AT(ats12e1r, va);
+ break;
+ case 1:
+ AT(ats12e1w, va);
+ break;
+ case 2:
+ AT(ats12e0r, va);
+ break;
+ case 3:
+ AT(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);
+}
diff --git a/services/spd/tlkd/tlkd_helpers.S b/services/spd/tlkd/tlkd_helpers.S
new file mode 100644
index 0000000..6e616a6
--- /dev/null
+++ b/services/spd/tlkd/tlkd_helpers.S
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#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
diff --git a/services/spd/tlkd/tlkd_main.c b/services/spd/tlkd/tlkd_main.c
new file mode 100644
index 0000000..ecac435
--- /dev/null
+++ b/services/spd/tlkd/tlkd_main.c
@@ -0,0 +1,546 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. 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 <assert.h>
+#include <bl31/interrupt_mgmt.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <bl32/payloads/tlk.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+#include <tools_share/uuid.h>
+
+#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's timer interrupt handler
+ ******************************************************************************/
+static uint64_t tlkd_interrupt_handler(uint32_t id,
+ uint32_t flags,
+ void *handle,
+ void *cookie)
+{
+ cpu_context_t *s_cpu_context;
+ int irq = plat_ic_get_pending_interrupt_id();
+
+ /* acknowledge the interrupt and mark it complete */
+ (void)plat_ic_acknowledge_interrupt();
+ plat_ic_end_of_interrupt(irq);
+
+ /*
+ * Disable the routing of NS interrupts from secure world to
+ * EL3 while interrupted on this core.
+ */
+ disable_intr_rm_local(INTR_TYPE_S_EL1, SECURE);
+
+ /* Check the security state when the exception was generated */
+ assert(get_interrupt_src_ss(flags) == NON_SECURE);
+ assert(handle == cm_get_context(NON_SECURE));
+
+ /* Save non-secure state */
+ cm_el1_sysregs_context_save(NON_SECURE);
+
+ /* Get a reference to the secure context */
+ s_cpu_context = cm_get_context(SECURE);
+ assert(s_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(SECURE);
+ cm_set_next_eret_context(SECURE);
+
+ /* Provide the IRQ number to the SPD */
+ SMC_RET4(s_cpu_context, (uint32_t)TLK_IRQ_FIRED, 0, (uint32_t)irq, 0);
+}
+
+/*******************************************************************************
+ * 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;
+ uint32_t flags;
+ int32_t ret;
+
+ /*
+ * 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);
+
+ /* get a list of all S-EL1 IRQs from the platform */
+
+ /* register interrupt handler */
+ flags = 0;
+ set_interrupt_rm_flag(flags, NON_SECURE);
+ ret = register_interrupt_type_handler(INTR_TYPE_S_EL1,
+ tlkd_interrupt_handler,
+ flags);
+ if (ret != 0) {
+ ERROR("failed to register tlkd interrupt handler (%d)\n", ret);
+ }
+
+ /*
+ * 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:
+ case TLK_SET_BL_VERSION:
+ case TLK_LOCK_BL_INTERFACE:
+ case TLK_BL_RPMB_SERVICE:
+
+ 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:
+
+ 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;
+
+ /*
+ * This function ID is used by SP to indicate that it has completed
+ * handling the secure interrupt.
+ */
+ case TLK_IRQ_DONE:
+
+ if (ns)
+ SMC_RET1(handle, SMC_UNK);
+
+ assert(handle == cm_get_context(SECURE));
+
+ /* save secure world context */
+ 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_RET0(ns_cpu_context);
+
+ /*
+ * 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
+);
diff --git a/services/spd/tlkd/tlkd_pm.c b/services/spd/tlkd/tlkd_pm.c
new file mode 100644
index 0000000..ed5bf77
--- /dev/null
+++ b/services/spd/tlkd/tlkd_pm.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <bl32/payloads/tlk.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/psci/psci.h>
+
+#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();
+}
+
+/*******************************************************************************
+ * 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,
+};
diff --git a/services/spd/tlkd/tlkd_private.h b/services/spd/tlkd/tlkd_private.h
new file mode 100644
index 0000000..5d5d0e8
--- /dev/null
+++ b/services/spd/tlkd/tlkd_private.h
@@ -0,0 +1,124 @@
+/*
+ * 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 <platform_def.h>
+
+#include <arch.h>
+#include <bl31/interrupt_mgmt.h>
+#include <context.h>
+#include <lib/psci/psci.h>
+
+/*
+ * 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 <stdint.h>
+
+#include <lib/cassert.h>
+
+/* 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 */
diff --git a/services/spd/trusty/generic-arm64-smcall.c b/services/spd/trusty/generic-arm64-smcall.c
new file mode 100644
index 0000000..5c3a628
--- /dev/null
+++ b/services/spd/trusty/generic-arm64-smcall.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <platform_def.h>
+
+#include "generic-arm64-smcall.h"
+
+#ifndef PLAT_ARM_GICD_BASE
+#ifdef GICD_BASE
+#define PLAT_ARM_GICD_BASE GICD_BASE
+#define PLAT_ARM_GICC_BASE GICC_BASE
+#ifdef GICR_BASE
+#define PLAT_ARM_GICR_BASE GICR_BASE
+#endif
+#else
+#error PLAT_ARM_GICD_BASE or GICD_BASE must be defined
+#endif
+#endif
+
+#ifndef PLAT_ARM_GICR_BASE
+#define PLAT_ARM_GICR_BASE SMC_UNK
+#endif
+
+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 SMC_GET_GIC_BASE_GICD:
+ return PLAT_ARM_GICD_BASE;
+
+ case SMC_GET_GIC_BASE_GICC:
+ return PLAT_ARM_GICC_BASE;
+
+ case SMC_GET_GIC_BASE_GICR:
+ return PLAT_ARM_GICR_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
+);
+
diff --git a/services/spd/trusty/generic-arm64-smcall.h b/services/spd/trusty/generic-arm64-smcall.h
new file mode 100644
index 0000000..ac03469
--- /dev/null
+++ b/services/spd/trusty/generic-arm64-smcall.h
@@ -0,0 +1,28 @@
+/*
+ * 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_GET_GIC_BASE_GICR 2
+#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)
diff --git a/services/spd/trusty/sm_err.h b/services/spd/trusty/sm_err.h
new file mode 100644
index 0000000..80a8748
--- /dev/null
+++ b/services/spd/trusty/sm_err.h
@@ -0,0 +1,22 @@
+/*
+ * 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 */
diff --git a/services/spd/trusty/smcall.h b/services/spd/trusty/smcall.h
new file mode 100644
index 0000000..c66f7db
--- /dev/null
+++ b/services/spd/trusty/smcall.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. 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)
+
+/*
+ * Standard Trusted OS Function IDs that fall under Trusted OS call range
+ * according to SMC calling convention
+ */
+#define SMC_FC64_GET_UUID SMC_FASTCALL64_NR(63U, 0xFF01U) /* Implementation UID */
+#define SMC_FC_GET_UUID SMC_FASTCALL_NR(63U, 0xFF01U) /* Implementation.UID */
+
+#endif /* SMCALL_H */
diff --git a/services/spd/trusty/trusty.c b/services/spd/trusty/trusty.c
new file mode 100644
index 0000000..7daebcd
--- /dev/null
+++ b/services/spd/trusty/trusty.c
@@ -0,0 +1,541 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/smccc.h>
+#include <plat/common/platform.h>
+#include <tools_share/uuid.h>
+
+#include "sm_err.h"
+#include "smcall.h"
+
+/* Trusty UID: RFC-4122 compliant UUID version 4 */
+DEFINE_SVC_UUID2(trusty_uuid,
+ 0x40ee25f0, 0xa2bc, 0x304c, 0x8c, 0x4c,
+ 0xa1, 0x73, 0xc5, 0x7d, 0x8a, 0xf1);
+
+/* 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_el1_sysregs_ctx(handle), CTX_SP_EL1);
+
+ write_ctx_reg(get_el1_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 %" PRId64 " >= %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, %" PRId64 "\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_el1_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_GET_UUID:
+ case SMC_FC_GET_UUID:
+ /* provide the UUID for the service to the client */
+ SMC_UUID_RET(handle, trusty_uuid);
+ break;
+ 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:
+ /* Not all OENs greater than SMC_ENTITY_SECURE_MONITOR are supported */
+ if (SMC_ENTITY(smc_fid) > SMC_ENTITY_SECURE_MONITOR) {
+ VERBOSE("%s: unsupported SMC FID (0x%x)\n", __func__, smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+ }
+
+ 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, %" PRId64 "\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, %" PRId64 "\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);
+
+#if !defined(TSP_SEC_MEM_SIZE) && defined(BL32_MEM_SIZE)
+#define TSP_SEC_MEM_SIZE BL32_MEM_SIZE
+#endif
+
+#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) {
+ VERBOSE("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) {
+ VERBOSE("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,
+ OEN_TOS_END,
+ 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
+);
diff --git a/services/spd/trusty/trusty.mk b/services/spd/trusty/trusty.mk
new file mode 100644
index 0000000..43b80bb
--- /dev/null
+++ b/services/spd/trusty/trusty.mk
@@ -0,0 +1,18 @@
+#
+# 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
diff --git a/services/spd/trusty/trusty_helpers.S b/services/spd/trusty/trusty_helpers.S
new file mode 100644
index 0000000..da5cb57
--- /dev/null
+++ b/services/spd/trusty/trusty_helpers.S
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+.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
diff --git a/services/spd/tspd/tspd.mk b/services/spd/tspd/tspd.mk
new file mode 100644
index 0000000..bda8338
--- /dev/null
+++ b/services/spd/tspd/tspd.mk
@@ -0,0 +1,46 @@
+#
+# 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))
diff --git a/services/spd/tspd/tspd_common.c b/services/spd/tspd/tspd_common.c
new file mode 100644
index 0000000..063fd01
--- /dev/null
+++ b/services/spd/tspd/tspd_common.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <bl32/tsp/tsp.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/utils.h>
+
+#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;
+}
+
diff --git a/services/spd/tspd/tspd_helpers.S b/services/spd/tspd/tspd_helpers.S
new file mode 100644
index 0000000..f15d66b
--- /dev/null
+++ b/services/spd/tspd/tspd_helpers.S
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#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
diff --git a/services/spd/tspd/tspd_main.c b/services/spd/tspd/tspd_main.c
new file mode 100644
index 0000000..6cb4992
--- /dev/null
+++ b/services/spd/tspd/tspd_main.c
@@ -0,0 +1,819 @@
+/*
+ * Copyright (c) 2013-2022, 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 <assert.h>
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <bl31/ehf.h>
+#include <bl32/tsp/tsp.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+#include <tools_share/uuid.h>
+
+#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.
+ * Typically, interrupts for a specific security state get handled in the same
+ * security execption level if the execution is in the same security state. For
+ * example, if a non-secure interrupt gets fired when CPU is executing in NS-EL2
+ * it gets handled in the non-secure world.
+ * However, interrupts belonging to the opposite security state typically demand
+ * a world(context) switch. This is inline with the security principle which
+ * states a secure interrupt has to be handled in the secure world.
+ * Hence, the TSPD in EL3 expects the context(handle) for a secure interrupt to
+ * be non-secure and vice versa.
+ * However, a race condition between non-secure and secure interrupts can lead to
+ * a scenario where the above assumptions do not hold true. This is demonstrated
+ * below through Note 1.
+ ******************************************************************************/
+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;
+
+ /* Get a reference to this cpu's TSP context */
+ linear_id = plat_my_core_pos();
+ tsp_ctx = &tspd_sp_context[linear_id];
+
+#if TSP_NS_INTR_ASYNC_PREEMPT
+
+ /*
+ * Note 1:
+ * Under the current interrupt routing model, interrupts from other
+ * world are routed to EL3 when TSP_NS_INTR_ASYNC_PREEMPT is enabled.
+ * Consider the following scenario:
+ * 1/ A non-secure payload(like tftf) requests a secure service from
+ * TSP by invoking a yielding SMC call.
+ * 2/ Later, execution jumps to TSP in S-EL1 with the help of TSP
+ * Dispatcher in Secure Monitor(EL3).
+ * 3/ While CPU is executing TSP, a Non-secure interrupt gets fired.
+ * this demands a context switch to the non-secure world through
+ * secure monitor.
+ * 4/ Consequently, TSP in S-EL1 get asynchronously pre-empted and
+ * execution switches to secure monitor(EL3).
+ * 5/ EL3 tries to triage the (Non-secure) interrupt based on the
+ * highest pending interrupt.
+ * 6/ However, while the NS Interrupt was pending, secure timer gets
+ * fired which makes a S-EL1 interrupt to be pending.
+ * 7/ Hence, execution jumps to this companion handler of S-EL1
+ * interrupt (i.e., tspd_sel1_interrupt_handler) even though the TSP
+ * was pre-empted due to non-secure interrupt.
+ * 8/ The above sequence of events explain how TSP was pre-empted by
+ * S-EL1 interrupt indirectly in an asynchronous way.
+ * 9/ Hence, we track the TSP pre-emption by S-EL1 interrupt using a
+ * boolean variable per each core.
+ * 10/ This helps us to indicate that SMC call for TSP service was
+ * pre-empted when execution resumes in non-secure world.
+ */
+
+ /* Check the security state when the exception was generated */
+ if (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);
+ tsp_ctx->preempted_by_sel1_intr = false;
+ } else {
+ /* Sanity check the pointer to this cpu's context */
+ assert(handle == cm_get_context(SECURE));
+
+ /* Save the secure context before entering the TSP for S-EL1
+ * interrupt handling
+ */
+ cm_el1_sysregs_context_save(SECURE);
+ tsp_ctx->preempted_by_sel1_intr = true;
+ }
+#else
+ /* 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);
+#endif
+
+ 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 = (uint32_t)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
+ 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);
+
+ /* Refer to Note 1 in function tspd_sel1_interrupt_handler()*/
+#if TSP_NS_INTR_ASYNC_PREEMPT
+ if (tsp_ctx->preempted_by_sel1_intr) {
+ /* Reset the flag */
+ tsp_ctx->preempted_by_sel1_intr = false;
+
+ SMC_RET1(ns_cpu_context, SMC_PREEMPTED);
+ } else {
+ SMC_RET0((uint64_t) ns_cpu_context);
+ }
+#else
+ SMC_RET0((uint64_t) ns_cpu_context);
+#endif
+
+
+ /*
+ * 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):
+ /*
+ * Request from non-secure client to perform a check
+ * of the DIT PSTATE bit.
+ */
+ case TSP_YIELD_FID(TSP_CHECK_DIT):
+ 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
+);
diff --git a/services/spd/tspd/tspd_pm.c b/services/spd/tspd/tspd_pm.c
new file mode 100644
index 0000000..b95ee8f
--- /dev/null
+++ b/services/spd/tspd/tspd_pm.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <bl32/tsp/tsp.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+
+#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
+};
diff --git a/services/spd/tspd/tspd_private.h b/services/spd/tspd/tspd_private.h
new file mode 100644
index 0000000..d6c03c9
--- /dev/null
+++ b/services/spd/tspd/tspd_private.h
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TSPD_PRIVATE_H
+#define TSPD_PRIVATE_H
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <bl31/interrupt_mgmt.h>
+#include <context.h>
+#include <lib/psci/psci.h>
+
+/*******************************************************************************
+ * 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 <stdint.h>
+
+#include <lib/cassert.h>
+
+/*
+ * 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;
+ bool preempted_by_sel1_intr;
+#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 */
diff --git a/services/std_svc/drtm/drtm_dma_prot.c b/services/std_svc/drtm/drtm_dma_prot.c
new file mode 100644
index 0000000..48317fd
--- /dev/null
+++ b/services/std_svc/drtm/drtm_dma_prot.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2022 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * DRTM DMA protection.
+ *
+ * Authors:
+ * Lucian Paul-Trifu <lucian.paultrifu@gmail.com>
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/arm/smmu_v3.h>
+#include "drtm_dma_prot.h"
+#include "drtm_main.h"
+#include "drtm_remediation.h"
+#include <plat/common/platform.h>
+#include <smccc_helpers.h>
+
+/*
+ * ________________________ LAUNCH success ________________________
+ * | Initial | -------------------> | Prot engaged |
+ * |````````````````````````| |````````````````````````|
+ * | request.type == NONE | | request.type != NONE |
+ * | | <------------------- | |
+ * `________________________' UNPROTECT_MEM `________________________'
+ *
+ * Transitions that are not shown correspond to ABI calls that do not change
+ * state and result in an error being returned to the caller.
+ */
+static struct dma_prot active_prot = {
+ .type = PROTECT_NONE,
+};
+
+/* Version-independent type. */
+typedef struct drtm_dl_dma_prot_args_v1 struct_drtm_dl_dma_prot_args;
+
+/*
+ * This function checks that platform supports complete DMA protection.
+ * and returns false - if the platform supports complete DMA protection.
+ * and returns true - if the platform does not support complete DMA protection.
+ */
+bool drtm_dma_prot_init(void)
+{
+ bool must_init_fail = false;
+ const uintptr_t *smmus;
+ size_t num_smmus = 0;
+ unsigned int total_smmus;
+
+ /* Warns presence of non-host platforms */
+ if (plat_has_non_host_platforms()) {
+ WARN("DRTM: the platform includes trusted DMA-capable devices"
+ " (non-host platforms)\n");
+ }
+
+ /*
+ * DLME protection is uncertain on platforms with peripherals whose
+ * DMA is not managed by an SMMU. DRTM doesn't work on such platforms.
+ */
+ if (plat_has_unmanaged_dma_peripherals()) {
+ ERROR("DRTM: this platform does not provide DMA protection\n");
+ must_init_fail = true;
+ }
+
+ /*
+ * Check that the platform reported all SMMUs.
+ * It is acceptable if the platform doesn't have any SMMUs when it
+ * doesn't have any DMA-capable devices.
+ */
+ total_smmus = plat_get_total_smmus();
+ plat_enumerate_smmus(&smmus, &num_smmus);
+ if (num_smmus != total_smmus) {
+ ERROR("DRTM: could not discover all SMMUs\n");
+ must_init_fail = true;
+ }
+
+ return must_init_fail;
+}
+
+/*
+ * Checks that the DMA protection arguments are valid and that the given
+ * protected regions are covered by DMA protection.
+ */
+enum drtm_retc drtm_dma_prot_check_args(const struct_drtm_dl_dma_prot_args *a,
+ int a_dma_prot_type,
+ drtm_mem_region_t p)
+{
+ switch ((enum dma_prot_type)a_dma_prot_type) {
+ case PROTECT_MEM_ALL:
+ if (a->dma_prot_table_paddr || a->dma_prot_table_size) {
+ ERROR("DRTM: invalid launch due to inconsistent"
+ " DMA protection arguments\n");
+ return MEM_PROTECT_INVALID;
+ }
+ /*
+ * Full DMA protection ought to ensure that the DLME and NWd
+ * DCE regions are protected, no further checks required.
+ */
+ return SUCCESS;
+
+ default:
+ ERROR("DRTM: invalid launch due to unsupported DMA protection type\n");
+ return MEM_PROTECT_INVALID;
+ }
+}
+
+enum drtm_retc drtm_dma_prot_engage(const struct_drtm_dl_dma_prot_args *a,
+ int a_dma_prot_type)
+{
+ const uintptr_t *smmus;
+ size_t num_smmus = 0;
+
+ if (active_prot.type != PROTECT_NONE) {
+ ERROR("DRTM: launch denied as previous DMA protection"
+ " is still engaged\n");
+ return DENIED;
+ }
+
+ if (a_dma_prot_type == PROTECT_NONE) {
+ return SUCCESS;
+ /* Only PROTECT_MEM_ALL is supported currently. */
+ } else if (a_dma_prot_type != PROTECT_MEM_ALL) {
+ ERROR("%s(): unimplemented DMA protection type\n", __func__);
+ panic();
+ }
+
+ /*
+ * Engage SMMUs in accordance with the request we have previously received.
+ * Only PROTECT_MEM_ALL is implemented currently.
+ */
+ plat_enumerate_smmus(&smmus, &num_smmus);
+ for (const uintptr_t *smmu = smmus; smmu < smmus+num_smmus; smmu++) {
+ /*
+ * TODO: Invalidate SMMU's Stage-1 and Stage-2 TLB entries. This ensures
+ * that any outstanding device transactions are completed, see Section
+ * 3.21.1, specification IHI_0070_C_a for an approximate reference.
+ */
+ int rc = smmuv3_ns_set_abort_all(*smmu);
+ if (rc != 0) {
+ ERROR("DRTM: SMMU at PA 0x%lx failed to engage DMA protection"
+ " rc=%d\n", *smmu, rc);
+ return INTERNAL_ERROR;
+ }
+ }
+
+ /*
+ * TODO: Restrict DMA from the GIC.
+ *
+ * Full DMA protection may be achieved as follows:
+ *
+ * With a GICv3:
+ * - Set GICR_CTLR.EnableLPIs to 0, for each GICR;
+ * GICR_CTLR.RWP == 0 must be the case before finishing, for each GICR.
+ * - Set GITS_CTLR.Enabled to 0;
+ * GITS_CTLR.Quiescent == 1 must be the case before finishing.
+ *
+ * In addition, with a GICv4:
+ * - Set GICR_VPENDBASER.Valid to 0, for each GICR;
+ * GICR_CTLR.RWP == 0 must be the case before finishing, for each GICR.
+ *
+ * Alternatively, e.g. if some bit values cannot be changed at runtime,
+ * this procedure should return an error if the LPI Pending and
+ * Configuration tables overlap the regions being protected.
+ */
+
+ active_prot.type = a_dma_prot_type;
+
+ return SUCCESS;
+}
+
+/*
+ * Undo what has previously been done in drtm_dma_prot_engage(), or enter
+ * remediation if it is not possible.
+ */
+enum drtm_retc drtm_dma_prot_disengage(void)
+{
+ const uintptr_t *smmus;
+ size_t num_smmus = 0;
+ const char *err_str = "cannot undo PROTECT_MEM_ALL SMMU config";
+
+ if (active_prot.type == PROTECT_NONE) {
+ return SUCCESS;
+ /* Only PROTECT_MEM_ALL is supported currently. */
+ } else if (active_prot.type != PROTECT_MEM_ALL) {
+ ERROR("%s(): unimplemented DMA protection type\n", __func__);
+ panic();
+ }
+
+ /*
+ * For PROTECT_MEM_ALL, undo the SMMU configuration for "abort all" mode
+ * done during engage().
+ */
+ /* Simply enter remediation for now. */
+ (void)smmus;
+ (void)num_smmus;
+ drtm_enter_remediation(1ULL, err_str);
+
+ /* TODO: Undo GIC DMA restrictions. */
+
+ active_prot.type = PROTECT_NONE;
+
+ return SUCCESS;
+}
+
+uint64_t drtm_unprotect_mem(void *ctx)
+{
+ enum drtm_retc ret;
+
+ switch (active_prot.type) {
+ case PROTECT_NONE:
+ ERROR("DRTM: invalid UNPROTECT_MEM, no DMA protection has"
+ " previously been engaged\n");
+ ret = DENIED;
+ break;
+
+ case PROTECT_MEM_ALL:
+ /*
+ * UNPROTECT_MEM is a no-op for PROTECT_MEM_ALL: DRTM must not touch
+ * the NS SMMU as it is expected that the DLME has configured it.
+ */
+ active_prot.type = PROTECT_NONE;
+
+ ret = SUCCESS;
+ break;
+
+ default:
+ ret = drtm_dma_prot_disengage();
+ break;
+ }
+
+ SMC_RET1(ctx, ret);
+}
+
+void drtm_dma_prot_serialise_table(uint8_t *dst, size_t *size_out)
+{
+ if (active_prot.type == PROTECT_NONE) {
+ return;
+ } else if (active_prot.type != PROTECT_MEM_ALL) {
+ ERROR("%s(): unimplemented DMA protection type\n", __func__);
+ panic();
+ }
+
+ struct __packed descr_table_1 {
+ drtm_memory_region_descriptor_table_t header;
+ drtm_mem_region_t regions[1];
+ } prot_table = {
+ .header = {
+ .revision = 1,
+ .num_regions = sizeof(((struct descr_table_1 *)NULL)->regions) /
+ sizeof(((struct descr_table_1 *)NULL)->regions[0])
+ },
+ .regions = {
+ {.region_address = 0, PAGES_AND_TYPE(UINT64_MAX, 0x3)},
+ }
+ };
+
+ memcpy(dst, &prot_table, sizeof(prot_table));
+ *size_out = sizeof(prot_table);
+}
diff --git a/services/std_svc/drtm/drtm_dma_prot.h b/services/std_svc/drtm/drtm_dma_prot.h
new file mode 100644
index 0000000..79dc9cb
--- /dev/null
+++ b/services/std_svc/drtm/drtm_dma_prot.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2022 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef DRTM_DMA_PROT_H
+#define DRTM_DMA_PROT_H
+
+#include <stdint.h>
+#include <plat/common/platform.h>
+#include <services/drtm_svc.h>
+
+struct __packed drtm_dl_dma_prot_args_v1 {
+ uint64_t dma_prot_table_paddr;
+ uint64_t dma_prot_table_size;
+};
+
+/* Values for DRTM_PROTECT_MEMORY */
+enum dma_prot_type {
+ PROTECT_NONE = -1,
+ PROTECT_MEM_ALL = 0,
+ PROTECT_MEM_REGION = 2,
+};
+
+struct dma_prot {
+ enum dma_prot_type type;
+};
+
+#define DRTM_MEM_REGION_PAGES_AND_TYPE(pages, type) \
+ (((uint64_t)(pages) & (((uint64_t)1 << 52) - 1)) \
+ | (((uint64_t)(type) & 0x7) << 52))
+
+#define PAGES_AND_TYPE(pages, type) \
+ .region_size_type = DRTM_MEM_REGION_PAGES_AND_TYPE(pages, type)
+
+/* Opaque / encapsulated type. */
+typedef struct drtm_dl_dma_prot_args_v1 drtm_dl_dma_prot_args_v1_t;
+
+bool drtm_dma_prot_init(void);
+enum drtm_retc drtm_dma_prot_check_args(const drtm_dl_dma_prot_args_v1_t *a,
+ int a_dma_prot_type,
+ drtm_mem_region_t p);
+enum drtm_retc drtm_dma_prot_engage(const drtm_dl_dma_prot_args_v1_t *a,
+ int a_dma_prot_type);
+enum drtm_retc drtm_dma_prot_disengage(void);
+uint64_t drtm_unprotect_mem(void *ctx);
+void drtm_dma_prot_serialise_table(uint8_t *dst, size_t *size_out);
+
+#endif /* DRTM_DMA_PROT_H */
diff --git a/services/std_svc/drtm/drtm_main.c b/services/std_svc/drtm/drtm_main.c
new file mode 100644
index 0000000..3acf683
--- /dev/null
+++ b/services/std_svc/drtm/drtm_main.c
@@ -0,0 +1,839 @@
+/*
+ * Copyright (c) 2022 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * DRTM service
+ *
+ * Authors:
+ * Lucian Paul-Trifu <lucian.paultrifu@gmail.com>
+ * Brian Nezvadovitz <brinez@microsoft.com> 2021-02-01
+ */
+
+#include <stdint.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <drivers/auth/crypto_mod.h>
+#include "drtm_main.h"
+#include "drtm_measurements.h"
+#include "drtm_remediation.h"
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/psci/psci_lib.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#include <services/drtm_svc.h>
+#include <services/sdei.h>
+#include <platform_def.h>
+
+/* Structure to store DRTM features specific to the platform. */
+static drtm_features_t plat_drtm_features;
+
+/* DRTM-formatted memory map. */
+static drtm_memory_region_descriptor_table_t *plat_drtm_mem_map;
+
+/* DLME header */
+struct_dlme_data_header dlme_data_hdr_init;
+
+/* Minimum data memory requirement */
+uint64_t dlme_data_min_size;
+
+int drtm_setup(void)
+{
+ bool rc;
+ const plat_drtm_tpm_features_t *plat_tpm_feat;
+ const plat_drtm_dma_prot_features_t *plat_dma_prot_feat;
+
+ INFO("DRTM service setup\n");
+
+ /* Read boot PE ID from MPIDR */
+ plat_drtm_features.boot_pe_id = read_mpidr_el1() & MPIDR_AFFINITY_MASK;
+
+ rc = drtm_dma_prot_init();
+ if (rc) {
+ return INTERNAL_ERROR;
+ }
+
+ /*
+ * initialise the platform supported crypto module that will
+ * be used by the DRTM-service to calculate hash of DRTM-
+ * implementation specific components
+ */
+ crypto_mod_init();
+
+ /* Build DRTM-compatible address map. */
+ plat_drtm_mem_map = drtm_build_address_map();
+ if (plat_drtm_mem_map == NULL) {
+ return INTERNAL_ERROR;
+ }
+
+ /* Get DRTM features from platform hooks. */
+ plat_tpm_feat = plat_drtm_get_tpm_features();
+ if (plat_tpm_feat == NULL) {
+ return INTERNAL_ERROR;
+ }
+
+ plat_dma_prot_feat = plat_drtm_get_dma_prot_features();
+ if (plat_dma_prot_feat == NULL) {
+ return INTERNAL_ERROR;
+ }
+
+ /*
+ * Add up minimum DLME data memory.
+ *
+ * For systems with complete DMA protection there is only one entry in
+ * the protected regions table.
+ */
+ if (plat_dma_prot_feat->dma_protection_support ==
+ ARM_DRTM_DMA_PROT_FEATURES_DMA_SUPPORT_COMPLETE) {
+ dlme_data_min_size =
+ sizeof(drtm_memory_region_descriptor_table_t) +
+ sizeof(drtm_mem_region_t);
+ dlme_data_hdr_init.dlme_prot_regions_size = dlme_data_min_size;
+ } else {
+ /*
+ * TODO set protected regions table size based on platform DMA
+ * protection configuration
+ */
+ panic();
+ }
+
+ dlme_data_hdr_init.dlme_addr_map_size = drtm_get_address_map_size();
+ dlme_data_hdr_init.dlme_tcb_hashes_table_size =
+ plat_drtm_get_tcb_hash_table_size();
+ dlme_data_hdr_init.dlme_impdef_region_size =
+ plat_drtm_get_imp_def_dlme_region_size();
+
+ dlme_data_min_size += dlme_data_hdr_init.dlme_addr_map_size +
+ PLAT_DRTM_EVENT_LOG_MAX_SIZE +
+ dlme_data_hdr_init.dlme_tcb_hashes_table_size +
+ dlme_data_hdr_init.dlme_impdef_region_size;
+
+ dlme_data_min_size = page_align(dlme_data_min_size, UP)/PAGE_SIZE;
+
+ /* Fill out platform DRTM features structure */
+ /* Only support default PCR schema (0x1) in this implementation. */
+ ARM_DRTM_TPM_FEATURES_SET_PCR_SCHEMA(plat_drtm_features.tpm_features,
+ ARM_DRTM_TPM_FEATURES_PCR_SCHEMA_DEFAULT);
+ ARM_DRTM_TPM_FEATURES_SET_TPM_HASH(plat_drtm_features.tpm_features,
+ plat_tpm_feat->tpm_based_hash_support);
+ ARM_DRTM_TPM_FEATURES_SET_FW_HASH(plat_drtm_features.tpm_features,
+ plat_tpm_feat->firmware_hash_algorithm);
+ ARM_DRTM_MIN_MEM_REQ_SET_MIN_DLME_DATA_SIZE(plat_drtm_features.minimum_memory_requirement,
+ dlme_data_min_size);
+ ARM_DRTM_MIN_MEM_REQ_SET_DCE_SIZE(plat_drtm_features.minimum_memory_requirement,
+ plat_drtm_get_min_size_normal_world_dce());
+ ARM_DRTM_DMA_PROT_FEATURES_SET_MAX_REGIONS(plat_drtm_features.dma_prot_features,
+ plat_dma_prot_feat->max_num_mem_prot_regions);
+ ARM_DRTM_DMA_PROT_FEATURES_SET_DMA_SUPPORT(plat_drtm_features.dma_prot_features,
+ plat_dma_prot_feat->dma_protection_support);
+ ARM_DRTM_TCB_HASH_FEATURES_SET_MAX_NUM_HASHES(plat_drtm_features.tcb_hash_features,
+ plat_drtm_get_tcb_hash_features());
+
+ return 0;
+}
+
+static inline void invalidate_icache_all(void)
+{
+ __asm__ volatile("ic ialluis");
+ dsb();
+ isb();
+}
+
+static inline uint64_t drtm_features_tpm(void *ctx)
+{
+ SMC_RET2(ctx, 1ULL, /* TPM feature is supported */
+ plat_drtm_features.tpm_features);
+}
+
+static inline uint64_t drtm_features_mem_req(void *ctx)
+{
+ SMC_RET2(ctx, 1ULL, /* memory req Feature is supported */
+ plat_drtm_features.minimum_memory_requirement);
+}
+
+static inline uint64_t drtm_features_boot_pe_id(void *ctx)
+{
+ SMC_RET2(ctx, 1ULL, /* Boot PE feature is supported */
+ plat_drtm_features.boot_pe_id);
+}
+
+static inline uint64_t drtm_features_dma_prot(void *ctx)
+{
+ SMC_RET2(ctx, 1ULL, /* DMA protection feature is supported */
+ plat_drtm_features.dma_prot_features);
+}
+
+static inline uint64_t drtm_features_tcb_hashes(void *ctx)
+{
+ SMC_RET2(ctx, 1ULL, /* TCB hash feature is supported */
+ plat_drtm_features.tcb_hash_features);
+}
+
+static enum drtm_retc drtm_dl_check_caller_el(void *ctx)
+{
+ uint64_t spsr_el3 = read_ctx_reg(get_el3state_ctx(ctx), CTX_SPSR_EL3);
+ uint64_t dl_caller_el;
+ uint64_t dl_caller_aarch;
+
+ dl_caller_el = spsr_el3 >> MODE_EL_SHIFT & MODE_EL_MASK;
+ dl_caller_aarch = spsr_el3 >> MODE_RW_SHIFT & MODE_RW_MASK;
+
+ /* Caller's security state is checked from drtm_smc_handle function */
+
+ /* Caller can be NS-EL2/EL1 */
+ if (dl_caller_el == MODE_EL3) {
+ ERROR("DRTM: invalid launch from EL3\n");
+ return DENIED;
+ }
+
+ if (dl_caller_aarch != MODE_RW_64) {
+ ERROR("DRTM: invalid launch from non-AArch64 execution state\n");
+ return DENIED;
+ }
+
+ return SUCCESS;
+}
+
+static enum drtm_retc drtm_dl_check_cores(void)
+{
+ bool running_on_single_core;
+ uint64_t this_pe_aff_value = read_mpidr_el1() & MPIDR_AFFINITY_MASK;
+
+ if (this_pe_aff_value != plat_drtm_features.boot_pe_id) {
+ ERROR("DRTM: invalid launch on a non-boot PE\n");
+ return DENIED;
+ }
+
+ running_on_single_core = psci_is_last_on_cpu_safe();
+ if (!running_on_single_core) {
+ ERROR("DRTM: invalid launch due to non-boot PE not being turned off\n");
+ return DENIED;
+ }
+
+ return SUCCESS;
+}
+
+static enum drtm_retc drtm_dl_prepare_dlme_data(const struct_drtm_dl_args *args)
+{
+ int rc;
+ uint64_t dlme_data_paddr;
+ size_t dlme_data_max_size;
+ uintptr_t dlme_data_mapping;
+ struct_dlme_data_header *dlme_data_hdr;
+ uint8_t *dlme_data_cursor;
+ size_t dlme_data_mapping_bytes;
+ size_t serialised_bytes_actual;
+
+ dlme_data_paddr = args->dlme_paddr + args->dlme_data_off;
+ dlme_data_max_size = args->dlme_size - args->dlme_data_off;
+
+ /*
+ * The capacity of the given DLME data region is checked when
+ * the other dynamic launch arguments are.
+ */
+ if (dlme_data_max_size < dlme_data_min_size) {
+ ERROR("%s: assertion failed:"
+ " dlme_data_max_size (%ld) < dlme_data_total_bytes_req (%ld)\n",
+ __func__, dlme_data_max_size, dlme_data_min_size);
+ panic();
+ }
+
+ /* Map the DLME data region as NS memory. */
+ dlme_data_mapping_bytes = ALIGNED_UP(dlme_data_max_size, DRTM_PAGE_SIZE);
+ rc = mmap_add_dynamic_region_alloc_va(dlme_data_paddr,
+ &dlme_data_mapping,
+ dlme_data_mapping_bytes,
+ MT_RW_DATA | MT_NS |
+ MT_SHAREABILITY_ISH);
+ if (rc != 0) {
+ WARN("DRTM: %s: mmap_add_dynamic_region() failed rc=%d\n",
+ __func__, rc);
+ return INTERNAL_ERROR;
+ }
+ dlme_data_hdr = (struct_dlme_data_header *)dlme_data_mapping;
+ dlme_data_cursor = (uint8_t *)dlme_data_hdr + sizeof(*dlme_data_hdr);
+
+ memcpy(dlme_data_hdr, (const void *)&dlme_data_hdr_init,
+ sizeof(*dlme_data_hdr));
+
+ /* Set the header version and size. */
+ dlme_data_hdr->version = 1;
+ dlme_data_hdr->this_hdr_size = sizeof(*dlme_data_hdr);
+
+ /* Prepare DLME protected regions. */
+ drtm_dma_prot_serialise_table(dlme_data_cursor,
+ &serialised_bytes_actual);
+ assert(serialised_bytes_actual ==
+ dlme_data_hdr->dlme_prot_regions_size);
+ dlme_data_cursor += serialised_bytes_actual;
+
+ /* Prepare DLME address map. */
+ if (plat_drtm_mem_map != NULL) {
+ memcpy(dlme_data_cursor, plat_drtm_mem_map,
+ dlme_data_hdr->dlme_addr_map_size);
+ } else {
+ WARN("DRTM: DLME address map is not in the cache\n");
+ }
+ dlme_data_cursor += dlme_data_hdr->dlme_addr_map_size;
+
+ /* Prepare DRTM event log for DLME. */
+ drtm_serialise_event_log(dlme_data_cursor, &serialised_bytes_actual);
+ assert(serialised_bytes_actual <= PLAT_DRTM_EVENT_LOG_MAX_SIZE);
+ dlme_data_hdr->dlme_tpm_log_size = serialised_bytes_actual;
+ dlme_data_cursor += serialised_bytes_actual;
+
+ /*
+ * TODO: Prepare the TCB hashes for DLME, currently its size
+ * 0
+ */
+ dlme_data_cursor += dlme_data_hdr->dlme_tcb_hashes_table_size;
+
+ /* Implementation-specific region size is unused. */
+ dlme_data_cursor += dlme_data_hdr->dlme_impdef_region_size;
+
+ /*
+ * Prepare DLME data size, includes all data region referenced above
+ * alongwith the DLME data header
+ */
+ dlme_data_hdr->dlme_data_size = dlme_data_cursor - (uint8_t *)dlme_data_hdr;
+
+ /* Unmap the DLME data region. */
+ rc = mmap_remove_dynamic_region(dlme_data_mapping, dlme_data_mapping_bytes);
+ if (rc != 0) {
+ ERROR("%s(): mmap_remove_dynamic_region() failed"
+ " unexpectedly rc=%d\n", __func__, rc);
+ panic();
+ }
+
+ return SUCCESS;
+}
+
+/*
+ * Note: accesses to the dynamic launch args, and to the DLME data are
+ * little-endian as required, thanks to TF-A BL31 init requirements.
+ */
+static enum drtm_retc drtm_dl_check_args(uint64_t x1,
+ struct_drtm_dl_args *a_out)
+{
+ uint64_t dlme_start, dlme_end;
+ uint64_t dlme_img_start, dlme_img_ep, dlme_img_end;
+ uint64_t dlme_data_start, dlme_data_end;
+ uintptr_t va_mapping;
+ size_t va_mapping_size;
+ struct_drtm_dl_args *a;
+ struct_drtm_dl_args args_buf;
+ int rc;
+
+ if (x1 % DRTM_PAGE_SIZE != 0) {
+ ERROR("DRTM: parameters structure is not "
+ DRTM_PAGE_SIZE_STR "-aligned\n");
+ return INVALID_PARAMETERS;
+ }
+
+ va_mapping_size = ALIGNED_UP(sizeof(struct_drtm_dl_args), DRTM_PAGE_SIZE);
+
+ /* check DRTM parameters are within NS address region */
+ rc = plat_drtm_validate_ns_region(x1, va_mapping_size);
+ if (rc != 0) {
+ ERROR("DRTM: parameters lies within secure memory\n");
+ return INVALID_PARAMETERS;
+ }
+
+ rc = mmap_add_dynamic_region_alloc_va(x1, &va_mapping, va_mapping_size,
+ MT_MEMORY | MT_NS | MT_RO |
+ MT_SHAREABILITY_ISH);
+ if (rc != 0) {
+ WARN("DRTM: %s: mmap_add_dynamic_region() failed rc=%d\n",
+ __func__, rc);
+ return INTERNAL_ERROR;
+ }
+ a = (struct_drtm_dl_args *)va_mapping;
+
+ /* Sanitize cache of data passed in args by the DCE Preamble. */
+ flush_dcache_range(va_mapping, va_mapping_size);
+
+ args_buf = *a;
+
+ rc = mmap_remove_dynamic_region(va_mapping, va_mapping_size);
+ if (rc) {
+ ERROR("%s(): mmap_remove_dynamic_region() failed unexpectedly"
+ " rc=%d\n", __func__, rc);
+ panic();
+ }
+ a = &args_buf;
+
+ if (!((a->version >= ARM_DRTM_PARAMS_MIN_VERSION) &&
+ (a->version <= ARM_DRTM_PARAMS_MAX_VERSION))) {
+ ERROR("DRTM: parameters structure version %u is unsupported\n",
+ a->version);
+ return NOT_SUPPORTED;
+ }
+
+ if (!(a->dlme_img_off < a->dlme_size &&
+ a->dlme_data_off < a->dlme_size)) {
+ ERROR("DRTM: argument offset is outside of the DLME region\n");
+ return INVALID_PARAMETERS;
+ }
+ dlme_start = a->dlme_paddr;
+ dlme_end = a->dlme_paddr + a->dlme_size;
+ dlme_img_start = a->dlme_paddr + a->dlme_img_off;
+ dlme_img_ep = dlme_img_start + a->dlme_img_ep_off;
+ dlme_img_end = dlme_img_start + a->dlme_img_size;
+ dlme_data_start = a->dlme_paddr + a->dlme_data_off;
+ dlme_data_end = dlme_end;
+
+ /* Check the DLME regions arguments. */
+ if ((dlme_start % DRTM_PAGE_SIZE) != 0) {
+ ERROR("DRTM: argument DLME region is not "
+ DRTM_PAGE_SIZE_STR "-aligned\n");
+ return INVALID_PARAMETERS;
+ }
+
+ if (!(dlme_start < dlme_end &&
+ dlme_start <= dlme_img_start && dlme_img_start < dlme_img_end &&
+ dlme_start <= dlme_data_start && dlme_data_start < dlme_data_end)) {
+ ERROR("DRTM: argument DLME region is discontiguous\n");
+ return INVALID_PARAMETERS;
+ }
+
+ if (dlme_img_start < dlme_data_end && dlme_data_start < dlme_img_end) {
+ ERROR("DRTM: argument DLME regions overlap\n");
+ return INVALID_PARAMETERS;
+ }
+
+ /* Check the DLME image region arguments. */
+ if ((dlme_img_start % DRTM_PAGE_SIZE) != 0) {
+ ERROR("DRTM: argument DLME image region is not "
+ DRTM_PAGE_SIZE_STR "-aligned\n");
+ return INVALID_PARAMETERS;
+ }
+
+ if (!(dlme_img_start <= dlme_img_ep && dlme_img_ep < dlme_img_end)) {
+ ERROR("DRTM: DLME entry point is outside of the DLME image region\n");
+ return INVALID_PARAMETERS;
+ }
+
+ if ((dlme_img_ep % 4) != 0) {
+ ERROR("DRTM: DLME image entry point is not 4-byte-aligned\n");
+ return INVALID_PARAMETERS;
+ }
+
+ /* Check the DLME data region arguments. */
+ if ((dlme_data_start % DRTM_PAGE_SIZE) != 0) {
+ ERROR("DRTM: argument DLME data region is not "
+ DRTM_PAGE_SIZE_STR "-aligned\n");
+ return INVALID_PARAMETERS;
+ }
+
+ if (dlme_data_end - dlme_data_start < dlme_data_min_size) {
+ ERROR("DRTM: argument DLME data region is short of %lu bytes\n",
+ dlme_data_min_size - (size_t)(dlme_data_end - dlme_data_start));
+ return INVALID_PARAMETERS;
+ }
+
+ /* check DLME region (paddr + size) is within a NS address region */
+ rc = plat_drtm_validate_ns_region(dlme_start, (size_t)a->dlme_size);
+ if (rc != 0) {
+ ERROR("DRTM: DLME region lies within secure memory\n");
+ return INVALID_PARAMETERS;
+ }
+
+ /* Check the Normal World DCE region arguments. */
+ if (a->dce_nwd_paddr != 0) {
+ uint32_t dce_nwd_start = a->dce_nwd_paddr;
+ uint32_t dce_nwd_end = dce_nwd_start + a->dce_nwd_size;
+
+ if (!(dce_nwd_start < dce_nwd_end)) {
+ ERROR("DRTM: argument Normal World DCE region is dicontiguous\n");
+ return INVALID_PARAMETERS;
+ }
+
+ if (dce_nwd_start < dlme_end && dlme_start < dce_nwd_end) {
+ ERROR("DRTM: argument Normal World DCE regions overlap\n");
+ return INVALID_PARAMETERS;
+ }
+ }
+
+ /*
+ * Map and sanitize the cache of data range passed by DCE Preamble. This
+ * is required to avoid / defend against racing with cache evictions
+ */
+ va_mapping_size = ALIGNED_UP((dlme_end - dlme_start), DRTM_PAGE_SIZE);
+ rc = mmap_add_dynamic_region_alloc_va(dlme_img_start, &va_mapping, va_mapping_size,
+ MT_MEMORY | MT_NS | MT_RO |
+ MT_SHAREABILITY_ISH);
+ if (rc != 0) {
+ ERROR("DRTM: %s: mmap_add_dynamic_region_alloc_va() failed rc=%d\n",
+ __func__, rc);
+ return INTERNAL_ERROR;
+ }
+ flush_dcache_range(va_mapping, va_mapping_size);
+
+ rc = mmap_remove_dynamic_region(va_mapping, va_mapping_size);
+ if (rc) {
+ ERROR("%s(): mmap_remove_dynamic_region() failed unexpectedly"
+ " rc=%d\n", __func__, rc);
+ panic();
+ }
+
+ *a_out = *a;
+ return SUCCESS;
+}
+
+static void drtm_dl_reset_dlme_el_state(enum drtm_dlme_el dlme_el)
+{
+ uint64_t sctlr;
+
+ /*
+ * TODO: Set PE state according to the PSCI's specification of the initial
+ * state after CPU_ON, or to reset values if unspecified, where they exist,
+ * or define sensible values otherwise.
+ */
+
+ switch (dlme_el) {
+ case DLME_AT_EL1:
+ sctlr = read_sctlr_el1();
+ break;
+
+ case DLME_AT_EL2:
+ sctlr = read_sctlr_el2();
+ break;
+
+ default: /* Not reached */
+ ERROR("%s(): dlme_el has the unexpected value %d\n",
+ __func__, dlme_el);
+ panic();
+ }
+
+ sctlr &= ~(/* Disable DLME's EL MMU, since the existing page-tables are untrusted. */
+ SCTLR_M_BIT
+ | SCTLR_EE_BIT /* Little-endian data accesses. */
+ );
+
+ sctlr |= SCTLR_C_BIT | SCTLR_I_BIT; /* Allow instruction and data caching. */
+
+ switch (dlme_el) {
+ case DLME_AT_EL1:
+ write_sctlr_el1(sctlr);
+ break;
+
+ case DLME_AT_EL2:
+ write_sctlr_el2(sctlr);
+ break;
+ }
+}
+
+static void drtm_dl_reset_dlme_context(enum drtm_dlme_el dlme_el)
+{
+ void *ns_ctx = cm_get_context(NON_SECURE);
+ gp_regs_t *gpregs = get_gpregs_ctx(ns_ctx);
+ uint64_t spsr_el3 = read_ctx_reg(get_el3state_ctx(ns_ctx), CTX_SPSR_EL3);
+
+ /* Reset all gpregs, including SP_EL0. */
+ memset(gpregs, 0, sizeof(*gpregs));
+
+ /* Reset SP_ELx. */
+ switch (dlme_el) {
+ case DLME_AT_EL1:
+ write_sp_el1(0);
+ break;
+
+ case DLME_AT_EL2:
+ write_sp_el2(0);
+ break;
+ }
+
+ /*
+ * DLME's async exceptions are masked to avoid a NWd attacker's timed
+ * interference with any state we established trust in or measured.
+ */
+ spsr_el3 |= SPSR_DAIF_MASK << SPSR_DAIF_SHIFT;
+
+ write_ctx_reg(get_el3state_ctx(ns_ctx), CTX_SPSR_EL3, spsr_el3);
+}
+
+static void drtm_dl_prepare_eret_to_dlme(const struct_drtm_dl_args *args, enum drtm_dlme_el dlme_el)
+{
+ void *ctx = cm_get_context(NON_SECURE);
+ uint64_t dlme_ep = DL_ARGS_GET_DLME_ENTRY_POINT(args);
+ uint64_t spsr_el3 = read_ctx_reg(get_el3state_ctx(ctx), CTX_SPSR_EL3);
+
+ /* Next ERET is to the DLME's EL. */
+ spsr_el3 &= ~(MODE_EL_MASK << MODE_EL_SHIFT);
+ switch (dlme_el) {
+ case DLME_AT_EL1:
+ spsr_el3 |= MODE_EL1 << MODE_EL_SHIFT;
+ break;
+
+ case DLME_AT_EL2:
+ spsr_el3 |= MODE_EL2 << MODE_EL_SHIFT;
+ break;
+ }
+
+ /* Next ERET is to the DLME entry point. */
+ cm_set_elr_spsr_el3(NON_SECURE, dlme_ep, spsr_el3);
+}
+
+static uint64_t drtm_dynamic_launch(uint64_t x1, void *handle)
+{
+ enum drtm_retc ret = SUCCESS;
+ enum drtm_retc dma_prot_ret;
+ struct_drtm_dl_args args;
+ /* DLME should be highest NS exception level */
+ enum drtm_dlme_el dlme_el = (el_implemented(2) != EL_IMPL_NONE) ? MODE_EL2 : MODE_EL1;
+
+ /* Ensure that only boot PE is powered on */
+ ret = drtm_dl_check_cores();
+ if (ret != SUCCESS) {
+ SMC_RET1(handle, ret);
+ }
+
+ /*
+ * Ensure that execution state is AArch64 and the caller
+ * is highest non-secure exception level
+ */
+ ret = drtm_dl_check_caller_el(handle);
+ if (ret != SUCCESS) {
+ SMC_RET1(handle, ret);
+ }
+
+ ret = drtm_dl_check_args(x1, &args);
+ if (ret != SUCCESS) {
+ SMC_RET1(handle, ret);
+ }
+
+ /* Ensure that there are no SDEI event registered */
+#if SDEI_SUPPORT
+ if (sdei_get_registered_event_count() != 0) {
+ SMC_RET1(handle, DENIED);
+ }
+#endif /* SDEI_SUPPORT */
+
+ /*
+ * Engage the DMA protections. The launch cannot proceed without the DMA
+ * protections due to potential TOC/TOU vulnerabilities w.r.t. the DLME
+ * region (and to the NWd DCE region).
+ */
+ ret = drtm_dma_prot_engage(&args.dma_prot_args,
+ DL_ARGS_GET_DMA_PROT_TYPE(&args));
+ if (ret != SUCCESS) {
+ SMC_RET1(handle, ret);
+ }
+
+ /*
+ * The DMA protection is now engaged. Note that any failure mode that
+ * returns an error to the DRTM-launch caller must now disengage DMA
+ * protections before returning to the caller.
+ */
+
+ ret = drtm_take_measurements(&args);
+ if (ret != SUCCESS) {
+ goto err_undo_dma_prot;
+ }
+
+ ret = drtm_dl_prepare_dlme_data(&args);
+ if (ret != SUCCESS) {
+ goto err_undo_dma_prot;
+ }
+
+ /*
+ * Note that, at the time of writing, the DRTM spec allows a successful
+ * launch from NS-EL1 to return to a DLME in NS-EL2. The practical risk
+ * of a privilege escalation, e.g. due to a compromised hypervisor, is
+ * considered small enough not to warrant the specification of additional
+ * DRTM conduits that would be necessary to maintain OSs' abstraction from
+ * the presence of EL2 were the dynamic launch only be allowed from the
+ * highest NS EL.
+ */
+
+ dlme_el = (el_implemented(2) != EL_IMPL_NONE) ? MODE_EL2 : MODE_EL1;
+
+ drtm_dl_reset_dlme_el_state(dlme_el);
+ drtm_dl_reset_dlme_context(dlme_el);
+
+ drtm_dl_prepare_eret_to_dlme(&args, dlme_el);
+
+ /*
+ * As per DRTM beta0 spec table #28 invalidate the instruction cache
+ * before jumping to the DLME. This is required to defend against
+ * potentially-malicious cache contents.
+ */
+ invalidate_icache_all();
+
+ /* Return the DLME region's address in x0, and the DLME data offset in x1.*/
+ SMC_RET2(handle, args.dlme_paddr, args.dlme_data_off);
+
+err_undo_dma_prot:
+ dma_prot_ret = drtm_dma_prot_disengage();
+ if (dma_prot_ret != SUCCESS) {
+ ERROR("%s(): drtm_dma_prot_disengage() failed unexpectedly"
+ " rc=%d\n", __func__, ret);
+ panic();
+ }
+
+ SMC_RET1(handle, ret);
+}
+
+uint64_t drtm_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)
+{
+ /* Check that the SMC call is from the Normal World. */
+ if (!is_caller_non_secure(flags)) {
+ SMC_RET1(handle, NOT_SUPPORTED);
+ }
+
+ switch (smc_fid) {
+ case ARM_DRTM_SVC_VERSION:
+ INFO("DRTM service handler: version\n");
+ /* Return the version of current implementation */
+ SMC_RET1(handle, ARM_DRTM_VERSION);
+ break; /* not reached */
+
+ case ARM_DRTM_SVC_FEATURES:
+ if (((x1 >> ARM_DRTM_FUNC_SHIFT) & ARM_DRTM_FUNC_MASK) ==
+ ARM_DRTM_FUNC_ID) {
+ /* Dispatch function-based queries. */
+ switch (x1 & FUNCID_MASK) {
+ case ARM_DRTM_SVC_VERSION:
+ SMC_RET1(handle, SUCCESS);
+ break; /* not reached */
+
+ case ARM_DRTM_SVC_FEATURES:
+ SMC_RET1(handle, SUCCESS);
+ break; /* not reached */
+
+ case ARM_DRTM_SVC_UNPROTECT_MEM:
+ SMC_RET1(handle, SUCCESS);
+ break; /* not reached */
+
+ case ARM_DRTM_SVC_DYNAMIC_LAUNCH:
+ SMC_RET1(handle, SUCCESS);
+ break; /* not reached */
+
+ case ARM_DRTM_SVC_CLOSE_LOCALITY:
+ WARN("ARM_DRTM_SVC_CLOSE_LOCALITY feature %s",
+ "is not supported\n");
+ SMC_RET1(handle, NOT_SUPPORTED);
+ break; /* not reached */
+
+ case ARM_DRTM_SVC_GET_ERROR:
+ SMC_RET1(handle, SUCCESS);
+ break; /* not reached */
+
+ case ARM_DRTM_SVC_SET_ERROR:
+ SMC_RET1(handle, SUCCESS);
+ break; /* not reached */
+
+ case ARM_DRTM_SVC_SET_TCB_HASH:
+ WARN("ARM_DRTM_SVC_TCB_HASH feature %s",
+ "is not supported\n");
+ SMC_RET1(handle, NOT_SUPPORTED);
+ break; /* not reached */
+
+ case ARM_DRTM_SVC_LOCK_TCB_HASH:
+ WARN("ARM_DRTM_SVC_LOCK_TCB_HASH feature %s",
+ "is not supported\n");
+ SMC_RET1(handle, NOT_SUPPORTED);
+ break; /* not reached */
+
+ default:
+ ERROR("Unknown DRTM service function\n");
+ SMC_RET1(handle, NOT_SUPPORTED);
+ break; /* not reached */
+ }
+ } else {
+ /* Dispatch feature-based queries. */
+ switch (x1 & ARM_DRTM_FEAT_ID_MASK) {
+ case ARM_DRTM_FEATURES_TPM:
+ INFO("++ DRTM service handler: TPM features\n");
+ return drtm_features_tpm(handle);
+ break; /* not reached */
+
+ case ARM_DRTM_FEATURES_MEM_REQ:
+ INFO("++ DRTM service handler: Min. mem."
+ " requirement features\n");
+ return drtm_features_mem_req(handle);
+ break; /* not reached */
+
+ case ARM_DRTM_FEATURES_DMA_PROT:
+ INFO("++ DRTM service handler: "
+ "DMA protection features\n");
+ return drtm_features_dma_prot(handle);
+ break; /* not reached */
+
+ case ARM_DRTM_FEATURES_BOOT_PE_ID:
+ INFO("++ DRTM service handler: "
+ "Boot PE ID features\n");
+ return drtm_features_boot_pe_id(handle);
+ break; /* not reached */
+
+ case ARM_DRTM_FEATURES_TCB_HASHES:
+ INFO("++ DRTM service handler: "
+ "TCB-hashes features\n");
+ return drtm_features_tcb_hashes(handle);
+ break; /* not reached */
+
+ default:
+ ERROR("Unknown ARM DRTM service feature\n");
+ SMC_RET1(handle, NOT_SUPPORTED);
+ break; /* not reached */
+ }
+ }
+
+ case ARM_DRTM_SVC_UNPROTECT_MEM:
+ INFO("DRTM service handler: unprotect mem\n");
+ return drtm_unprotect_mem(handle);
+ break; /* not reached */
+
+ case ARM_DRTM_SVC_DYNAMIC_LAUNCH:
+ INFO("DRTM service handler: dynamic launch\n");
+ return drtm_dynamic_launch(x1, handle);
+ break; /* not reached */
+
+ case ARM_DRTM_SVC_CLOSE_LOCALITY:
+ WARN("DRTM service handler: close locality %s\n",
+ "is not supported");
+ SMC_RET1(handle, NOT_SUPPORTED);
+ break; /* not reached */
+
+ case ARM_DRTM_SVC_GET_ERROR:
+ INFO("DRTM service handler: get error\n");
+ drtm_get_error(handle);
+ break; /* not reached */
+
+ case ARM_DRTM_SVC_SET_ERROR:
+ INFO("DRTM service handler: set error\n");
+ drtm_set_error(x1, handle);
+ break; /* not reached */
+
+ case ARM_DRTM_SVC_SET_TCB_HASH:
+ WARN("DRTM service handler: set TCB hash %s\n",
+ "is not supported");
+ SMC_RET1(handle, NOT_SUPPORTED);
+ break; /* not reached */
+
+ case ARM_DRTM_SVC_LOCK_TCB_HASH:
+ WARN("DRTM service handler: lock TCB hash %s\n",
+ "is not supported");
+ SMC_RET1(handle, NOT_SUPPORTED);
+ break; /* not reached */
+
+ default:
+ ERROR("Unknown DRTM service function: 0x%x\n", smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+ break; /* not reached */
+ }
+
+ /* not reached */
+ SMC_RET1(handle, SMC_UNK);
+}
diff --git a/services/std_svc/drtm/drtm_main.h b/services/std_svc/drtm/drtm_main.h
new file mode 100644
index 0000000..6005163
--- /dev/null
+++ b/services/std_svc/drtm/drtm_main.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2022 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef DRTM_MAIN_H
+#define DRTM_MAIN_H
+
+#include <stdint.h>
+
+#include <assert.h>
+#include <lib/smccc.h>
+
+#include "drtm_dma_prot.h"
+
+#define ALIGNED_UP(x, a) __extension__ ({ \
+ __typeof__(a) _a = (a); \
+ __typeof__(a) _one = 1; \
+ assert(IS_POWER_OF_TWO(_a)); \
+ ((x) + (_a - _one)) & ~(_a - _one); \
+})
+
+#define ALIGNED_DOWN(x, a) __extension__ ({ \
+ __typeof__(a) _a = (a); \
+ __typeof__(a) _one = 1; \
+ assert(IS_POWER_OF_TWO(_a)); \
+ (x) & ~(_a - _one); \
+})
+
+#define DRTM_PAGE_SIZE (4 * (1 << 10))
+#define DRTM_PAGE_SIZE_STR "4-KiB"
+
+#define DL_ARGS_GET_DMA_PROT_TYPE(a) (((a)->features >> 3) & 0x7U)
+#define DL_ARGS_GET_PCR_SCHEMA(a) (((a)->features >> 1) & 0x3U)
+#define DL_ARGS_GET_DLME_ENTRY_POINT(a) \
+ (((a)->dlme_paddr + (a)->dlme_img_off + (a)->dlme_img_ep_off))
+
+/*
+ * Range(Min/Max) of DRTM parameter structure versions supported
+ */
+#define ARM_DRTM_PARAMS_MIN_VERSION U(1)
+#define ARM_DRTM_PARAMS_MAX_VERSION U(1)
+
+enum drtm_dlme_el {
+ DLME_AT_EL1 = MODE_EL1,
+ DLME_AT_EL2 = MODE_EL2
+};
+
+enum drtm_retc {
+ SUCCESS = SMC_OK,
+ NOT_SUPPORTED = SMC_UNK,
+ INVALID_PARAMETERS = -2,
+ DENIED = -3,
+ NOT_FOUND = -4,
+ INTERNAL_ERROR = -5,
+ MEM_PROTECT_INVALID = -6,
+};
+
+typedef struct {
+ uint64_t tpm_features;
+ uint64_t minimum_memory_requirement;
+ uint64_t dma_prot_features;
+ uint64_t boot_pe_id;
+ uint64_t tcb_hash_features;
+} drtm_features_t;
+
+struct __packed drtm_dl_args_v1 {
+ uint16_t version; /* Must be 1. */
+ uint8_t __res[2];
+ uint32_t features;
+ uint64_t dlme_paddr;
+ uint64_t dlme_size;
+ uint64_t dlme_img_off;
+ uint64_t dlme_img_ep_off;
+ uint64_t dlme_img_size;
+ uint64_t dlme_data_off;
+ uint64_t dce_nwd_paddr;
+ uint64_t dce_nwd_size;
+ drtm_dl_dma_prot_args_v1_t dma_prot_args;
+} __aligned(__alignof(uint16_t /* First member's type, `uint16_t version' */));
+
+struct __packed dlme_data_header_v1 {
+ uint16_t version; /* Must be 1. */
+ uint16_t this_hdr_size;
+ uint8_t __res[4];
+ uint64_t dlme_data_size;
+ uint64_t dlme_prot_regions_size;
+ uint64_t dlme_addr_map_size;
+ uint64_t dlme_tpm_log_size;
+ uint64_t dlme_tcb_hashes_table_size;
+ uint64_t dlme_impdef_region_size;
+} __aligned(__alignof(uint16_t /* First member's type, `uint16_t version'. */));
+
+typedef struct dlme_data_header_v1 struct_dlme_data_header;
+
+drtm_memory_region_descriptor_table_t *drtm_build_address_map(void);
+uint64_t drtm_get_address_map_size(void);
+
+/*
+ * Version-independent type. May be used to avoid excessive line of code
+ * changes when migrating to new struct versions.
+ */
+typedef struct drtm_dl_args_v1 struct_drtm_dl_args;
+
+#endif /* DRTM_MAIN_H */
diff --git a/services/std_svc/drtm/drtm_measurements.c b/services/std_svc/drtm/drtm_measurements.c
new file mode 100644
index 0000000..a8f2b32
--- /dev/null
+++ b/services/std_svc/drtm/drtm_measurements.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2022 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * DRTM measurements into TPM PCRs.
+ *
+ * Authors:
+ * Lucian Paul-Trifu <lucian.paultrifu@gmail.com>
+ *
+ */
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/measured_boot/event_log/event_log.h>
+#include "drtm_main.h"
+#include "drtm_measurements.h"
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+/* Event Log buffer */
+static uint8_t drtm_event_log[PLAT_DRTM_EVENT_LOG_MAX_SIZE];
+
+/*
+ * Calculate and write hash of various payloads as per DRTM specification
+ * to Event Log.
+ *
+ * @param[in] data_base Address of data
+ * @param[in] data_size Size of data
+ * @param[in] event_type Type of Event
+ * @param[in] event_name Name of the Event
+ * @return:
+ * 0 = success
+ * < 0 = error
+ */
+static int drtm_event_log_measure_and_record(uintptr_t data_base,
+ uint32_t data_size,
+ uint32_t event_type,
+ const char *event_name,
+ unsigned int pcr)
+{
+ int rc;
+ unsigned char hash_data[CRYPTO_MD_MAX_SIZE];
+ event_log_metadata_t metadata = {0};
+
+ metadata.name = event_name;
+ metadata.pcr = pcr;
+
+ /*
+ * Measure the payloads requested by D-CRTM and DCE commponents
+ * Hash algorithm decided by the Event Log driver at build-time
+ */
+ rc = event_log_measure(data_base, data_size, hash_data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ /* Record the mesasurement in the EventLog buffer */
+ event_log_record(hash_data, event_type, &metadata);
+
+ return 0;
+}
+
+/*
+ * Initialise Event Log global variables, used during the recording
+ * of various payload measurements into the Event Log buffer
+ *
+ * @param[in] event_log_start Base address of Event Log buffer
+ * @param[in] event_log_finish End address of Event Log buffer,
+ * it is a first byte past end of the
+ * buffer
+ */
+static void drtm_event_log_init(uint8_t *event_log_start,
+ uint8_t *event_log_finish)
+{
+ event_log_buf_init(event_log_start, event_log_finish);
+ event_log_write_specid_event();
+}
+
+enum drtm_retc drtm_take_measurements(const struct_drtm_dl_args *a)
+{
+ int rc;
+ uintptr_t dlme_img_mapping;
+ uint64_t dlme_img_ep;
+ size_t dlme_img_mapping_bytes;
+ uint8_t drtm_null_data = 0U;
+ uint8_t pcr_schema = DL_ARGS_GET_PCR_SCHEMA(a);
+ const char *drtm_event_arm_sep_data = "ARM_DRTM";
+
+ /* Initialise the EventLog driver */
+ drtm_event_log_init(drtm_event_log, drtm_event_log +
+ sizeof(drtm_event_log));
+
+ /**
+ * Measurements extended into PCR-17.
+ *
+ * PCR-17: Measure the DCE image. Extend digest of (char)0 into PCR-17
+ * since the D-CRTM and the DCE are not separate.
+ */
+ rc = drtm_event_log_measure_and_record((uintptr_t)&drtm_null_data,
+ sizeof(drtm_null_data),
+ DRTM_EVENT_ARM_DCE, NULL,
+ PCR_17);
+ CHECK_RC(rc, drtm_event_log_measure_and_record(DRTM_EVENT_ARM_DCE));
+
+ /* PCR-17: Measure the PCR schema DRTM launch argument. */
+ rc = drtm_event_log_measure_and_record((uintptr_t)&pcr_schema,
+ sizeof(pcr_schema),
+ DRTM_EVENT_ARM_PCR_SCHEMA,
+ NULL, PCR_17);
+ CHECK_RC(rc,
+ drtm_event_log_measure_and_record(DRTM_EVENT_ARM_PCR_SCHEMA));
+
+ /* PCR-17: Measure the enable state of external-debug, and trace. */
+ /*
+ * TODO: Measure the enable state of external-debug and trace. This should
+ * be returned through a platform-specific hook.
+ */
+
+ /* PCR-17: Measure the security lifecycle state. */
+ /*
+ * TODO: Measure the security lifecycle state. This is an implementation-
+ * defined value, retrieved through an implementation-defined mechanisms.
+ */
+
+ /*
+ * PCR-17: Optionally measure the NWd DCE.
+ * It is expected that such subsequent DCE stages are signed and verified.
+ * Whether they are measured in addition to signing is implementation
+ * -defined.
+ * Here the choice is to not measure any NWd DCE, in favour of PCR value
+ * resilience to any NWd DCE updates.
+ */
+
+ /* PCR-17: End of DCE measurements. */
+ rc = drtm_event_log_measure_and_record((uintptr_t)drtm_event_arm_sep_data,
+ strlen(drtm_event_arm_sep_data),
+ DRTM_EVENT_ARM_SEPARATOR, NULL,
+ PCR_17);
+ CHECK_RC(rc, drtm_event_log_measure_and_record(DRTM_EVENT_ARM_SEPARATOR));
+
+ /**
+ * Measurements extended into PCR-18.
+ *
+ * PCR-18: Measure the PCR schema DRTM launch argument.
+ */
+ rc = drtm_event_log_measure_and_record((uintptr_t)&pcr_schema,
+ sizeof(pcr_schema),
+ DRTM_EVENT_ARM_PCR_SCHEMA,
+ NULL, PCR_18);
+ CHECK_RC(rc,
+ drtm_event_log_measure_and_record(DRTM_EVENT_ARM_PCR_SCHEMA));
+
+ /*
+ * PCR-18: Measure the public key used to verify DCE image(s) signatures.
+ * Extend digest of (char)0, since we do not expect the NWd DCE to be
+ * present.
+ */
+ assert(a->dce_nwd_size == 0);
+ rc = drtm_event_log_measure_and_record((uintptr_t)&drtm_null_data,
+ sizeof(drtm_null_data),
+ DRTM_EVENT_ARM_DCE_PUBKEY,
+ NULL, PCR_18);
+ CHECK_RC(rc,
+ drtm_event_log_measure_and_record(DRTM_EVENT_ARM_DCE_PUBKEY));
+
+ /* PCR-18: Measure the DLME image. */
+ dlme_img_mapping_bytes = page_align(a->dlme_img_size, UP);
+ rc = mmap_add_dynamic_region_alloc_va(a->dlme_paddr + a->dlme_img_off,
+ &dlme_img_mapping,
+ dlme_img_mapping_bytes, MT_RO_DATA | MT_NS);
+ if (rc) {
+ WARN("DRTM: %s: mmap_add_dynamic_region() failed rc=%d\n",
+ __func__, rc);
+ return INTERNAL_ERROR;
+ }
+
+ rc = drtm_event_log_measure_and_record(dlme_img_mapping, a->dlme_img_size,
+ DRTM_EVENT_ARM_DLME, NULL,
+ PCR_18);
+ CHECK_RC(rc, drtm_event_log_measure_and_record(DRTM_EVENT_ARM_DLME));
+
+ rc = mmap_remove_dynamic_region(dlme_img_mapping, dlme_img_mapping_bytes);
+ CHECK_RC(rc, mmap_remove_dynamic_region);
+
+ /* PCR-18: Measure the DLME image entry point. */
+ dlme_img_ep = DL_ARGS_GET_DLME_ENTRY_POINT(a);
+ drtm_event_log_measure_and_record((uintptr_t)&dlme_img_ep,
+ sizeof(dlme_img_ep),
+ DRTM_EVENT_ARM_DLME_EP, NULL,
+ PCR_18);
+ CHECK_RC(rc, drtm_event_log_measure_and_record(DRTM_EVENT_ARM_DLME_EP));
+
+ /* PCR-18: End of DCE measurements. */
+ rc = drtm_event_log_measure_and_record((uintptr_t)drtm_event_arm_sep_data,
+ strlen(drtm_event_arm_sep_data),
+ DRTM_EVENT_ARM_SEPARATOR, NULL,
+ PCR_18);
+ CHECK_RC(rc,
+ drtm_event_log_measure_and_record(DRTM_EVENT_ARM_SEPARATOR));
+ /*
+ * If the DCE is unable to log a measurement because there is no available
+ * space in the event log region, the DCE must extend a hash of the value
+ * 0xFF (1 byte in size) into PCR[17] and PCR[18] and enter remediation.
+ */
+
+ return SUCCESS;
+}
+
+void drtm_serialise_event_log(uint8_t *dst, size_t *event_log_size_out)
+{
+ *event_log_size_out = event_log_get_cur_size(drtm_event_log);
+ memcpy(dst, drtm_event_log, *event_log_size_out);
+}
diff --git a/services/std_svc/drtm/drtm_measurements.h b/services/std_svc/drtm/drtm_measurements.h
new file mode 100644
index 0000000..6d7a84e
--- /dev/null
+++ b/services/std_svc/drtm/drtm_measurements.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef DRTM_MEASUREMENTS_H
+#define DRTM_MEASUREMENTS_H
+
+#include <stdint.h>
+
+#include "drtm_main.h"
+#include <platform_def.h>
+
+#define DRTM_EVENT_ARM_BASE 0x9000U
+#define DRTM_EVENT_TYPE(n) (DRTM_EVENT_ARM_BASE + (unsigned int)(n))
+
+#define DRTM_EVENT_ARM_PCR_SCHEMA DRTM_EVENT_TYPE(1)
+#define DRTM_EVENT_ARM_DCE DRTM_EVENT_TYPE(2)
+#define DRTM_EVENT_ARM_DCE_PUBKEY DRTM_EVENT_TYPE(3)
+#define DRTM_EVENT_ARM_DLME DRTM_EVENT_TYPE(4)
+#define DRTM_EVENT_ARM_DLME_EP DRTM_EVENT_TYPE(5)
+#define DRTM_EVENT_ARM_DEBUG_CONFIG DRTM_EVENT_TYPE(6)
+#define DRTM_EVENT_ARM_NONSECURE_CONFIG DRTM_EVENT_TYPE(7)
+#define DRTM_EVENT_ARM_DCE_SECONDARY DRTM_EVENT_TYPE(8)
+#define DRTM_EVENT_ARM_TZFW DRTM_EVENT_TYPE(9)
+#define DRTM_EVENT_ARM_SEPARATOR DRTM_EVENT_TYPE(10)
+
+#define CHECK_RC(rc, func_call) { \
+ if (rc != 0) { \
+ ERROR("%s(): " #func_call "failed unexpectedly rc=%d\n", \
+ __func__, rc); \
+ panic(); \
+ } \
+}
+
+enum drtm_retc drtm_take_measurements(const struct_drtm_dl_args *a);
+void drtm_serialise_event_log(uint8_t *dst, size_t *event_log_size_out);
+
+#endif /* DRTM_MEASUREMENTS_H */
diff --git a/services/std_svc/drtm/drtm_remediation.c b/services/std_svc/drtm/drtm_remediation.c
new file mode 100644
index 0000000..696b4ea
--- /dev/null
+++ b/services/std_svc/drtm/drtm_remediation.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2022 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * DRTM support for DRTM error remediation.
+ *
+ */
+#include <inttypes.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include "drtm_main.h"
+#include <plat/common/platform.h>
+
+uint64_t drtm_set_error(uint64_t x1, void *ctx)
+{
+ int rc;
+
+ rc = plat_set_drtm_error(x1);
+
+ if (rc != 0) {
+ SMC_RET1(ctx, INTERNAL_ERROR);
+ }
+
+ SMC_RET1(ctx, SUCCESS);
+}
+
+uint64_t drtm_get_error(void *ctx)
+{
+ uint64_t error_code;
+ int rc;
+
+ rc = plat_get_drtm_error(&error_code);
+
+ if (rc != 0) {
+ SMC_RET1(ctx, INTERNAL_ERROR);
+ }
+
+ SMC_RET2(ctx, SUCCESS, error_code);
+}
+
+void drtm_enter_remediation(uint64_t err_code, const char *err_str)
+{
+ int rc = plat_set_drtm_error(err_code);
+
+ if (rc != 0) {
+ ERROR("%s(): drtm_error_set() failed unexpectedly rc=%d\n",
+ __func__, rc);
+ panic();
+ }
+
+ ERROR("DRTM: entering remediation of error:\n%" PRIu64 "\t\'%s\'\n",
+ err_code, err_str);
+
+ ERROR("%s(): system reset is not yet supported\n", __func__);
+ plat_system_reset();
+}
diff --git a/services/std_svc/drtm/drtm_remediation.h b/services/std_svc/drtm/drtm_remediation.h
new file mode 100644
index 0000000..8f965f1
--- /dev/null
+++ b/services/std_svc/drtm/drtm_remediation.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2022 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef DRTM_REMEDIATION_H
+#define DRTM_REMEDIATION_H
+
+uint64_t drtm_set_error(uint64_t x1, void *ctx);
+uint64_t drtm_get_error(void *ctx);
+
+void drtm_enter_remediation(uint64_t error_code, const char *error_str);
+
+#endif /* DRTM_REMEDIATION_H */
diff --git a/services/std_svc/drtm/drtm_res_address_map.c b/services/std_svc/drtm/drtm_res_address_map.c
new file mode 100644
index 0000000..8636706
--- /dev/null
+++ b/services/std_svc/drtm/drtm_res_address_map.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2022 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <plat/common/platform.h>
+#include <services/drtm_svc.h>
+#include <platform_def.h>
+
+/* Address map revision generated by this code. */
+#define DRTM_ADDRESS_MAP_REVISION U(0x0001)
+
+/* Amount of space needed for address map based on PLAT_DRTM_MMAP_ENTRIES */
+#define DRTM_ADDRESS_MAP_SIZE (sizeof(drtm_memory_region_descriptor_table_t) + \
+ (sizeof(drtm_mem_region_t) * \
+ PLAT_DRTM_MMAP_ENTRIES))
+
+/* Allocate space for DRTM-formatted address map to be constructed. */
+static uint8_t drtm_address_map[DRTM_ADDRESS_MAP_SIZE];
+
+static uint64_t drtm_address_map_size;
+
+drtm_memory_region_descriptor_table_t *drtm_build_address_map(void)
+{
+ /* Set up pointer to DRTM memory map. */
+ drtm_memory_region_descriptor_table_t *map =
+ (drtm_memory_region_descriptor_table_t *)drtm_address_map;
+
+ /* Get the platform memory map. */
+ const mmap_region_t *mmap = plat_get_addr_mmap();
+ unsigned int i;
+
+ /* Set up header for address map structure. */
+ map->revision = DRTM_ADDRESS_MAP_REVISION;
+ map->reserved = 0x0000;
+
+ /* Iterate through mmap and generate DRTM address map. */
+ for (i = 0U; mmap[i].base_pa != 0UL; i++) {
+ /* Set PA of region. */
+ map->region[i].region_address = mmap[i].base_pa;
+
+ /* Set size of region (in 4kb chunks). */
+ map->region[i].region_size_type = 0;
+ ARM_DRTM_REGION_SIZE_TYPE_SET_4K_PAGE_NUM(
+ map->region[i].region_size_type,
+ mmap[i].size / PAGE_SIZE_4KB);
+
+ /* Set type and cacheability. */
+ switch (MT_TYPE(mmap[i].attr)) {
+ case MT_DEVICE:
+ ARM_DRTM_REGION_SIZE_TYPE_SET_REGION_TYPE(
+ map->region[i].region_size_type,
+ ARM_DRTM_REGION_SIZE_TYPE_REGION_TYPE_DEVICE);
+ break;
+ case MT_NON_CACHEABLE:
+ ARM_DRTM_REGION_SIZE_TYPE_SET_REGION_TYPE(
+ map->region[i].region_size_type,
+ ARM_DRTM_REGION_SIZE_TYPE_REGION_TYPE_NCAR);
+ ARM_DRTM_REGION_SIZE_TYPE_SET_CACHEABILITY(
+ map->region[i].region_size_type,
+ ARM_DRTM_REGION_SIZE_TYPE_CACHEABILITY_NC);
+ break;
+ case MT_MEMORY:
+ ARM_DRTM_REGION_SIZE_TYPE_SET_REGION_TYPE(
+ map->region[i].region_size_type,
+ ARM_DRTM_REGION_SIZE_TYPE_REGION_TYPE_NORMAL);
+ break;
+ default:
+ return NULL;
+ }
+ }
+
+ map->num_regions = i;
+
+ /* Store total size of address map. */
+ drtm_address_map_size = sizeof(drtm_memory_region_descriptor_table_t);
+ drtm_address_map_size += (i * sizeof(drtm_mem_region_t));
+
+ return map;
+}
+
+uint64_t drtm_get_address_map_size(void)
+{
+ return drtm_address_map_size;
+}
diff --git a/services/std_svc/pci_svc.c b/services/std_svc/pci_svc.c
new file mode 100644
index 0000000..a02b8a7
--- /dev/null
+++ b/services/std_svc/pci_svc.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <services/pci_svc.h>
+#include <services/std_svc.h>
+#include <smccc_helpers.h>
+
+static uint64_t validate_rw_addr_sz(uint32_t addr, uint64_t off, uint64_t sz)
+{
+ uint32_t nseg;
+ uint32_t ret;
+ uint32_t start_end_bus;
+
+ ret = pci_get_bus_for_seg(PCI_ADDR_SEG(addr), &start_end_bus, &nseg);
+
+ if (ret != SMC_PCI_CALL_SUCCESS) {
+ return SMC_PCI_CALL_INVAL_PARAM;
+ }
+ switch (sz) {
+ case SMC_PCI_SZ_8BIT:
+ case SMC_PCI_SZ_16BIT:
+ case SMC_PCI_SZ_32BIT:
+ break;
+ default:
+ return SMC_PCI_CALL_INVAL_PARAM;
+ }
+ if ((off + sz) > (PCI_OFFSET_MASK + 1U)) {
+ return SMC_PCI_CALL_INVAL_PARAM;
+ }
+ return SMC_PCI_CALL_SUCCESS;
+}
+
+uint64_t pci_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 SMC_PCI_VERSION: {
+ pcie_version ver;
+
+ ver.major = 1U;
+ ver.minor = 0U;
+ SMC_RET4(handle, ver.val, 0U, 0U, 0U);
+ }
+ case SMC_PCI_FEATURES:
+ switch (x1) {
+ case SMC_PCI_VERSION:
+ case SMC_PCI_FEATURES:
+ case SMC_PCI_READ:
+ case SMC_PCI_WRITE:
+ case SMC_PCI_SEG_INFO:
+ SMC_RET1(handle, SMC_PCI_CALL_SUCCESS);
+ default:
+ SMC_RET1(handle, SMC_PCI_CALL_NOT_SUPPORTED);
+ }
+ break;
+ case SMC_PCI_READ: {
+ uint32_t ret;
+
+ if (validate_rw_addr_sz(x1, x2, x3) != SMC_PCI_CALL_SUCCESS) {
+ SMC_RET2(handle, SMC_PCI_CALL_INVAL_PARAM, 0U);
+ }
+ if (x4 != 0U) {
+ SMC_RET2(handle, SMC_PCI_CALL_INVAL_PARAM, 0U);
+ }
+ if (pci_read_config(x1, x2, x3, &ret) != 0U) {
+ SMC_RET2(handle, SMC_PCI_CALL_INVAL_PARAM, 0U);
+ } else {
+ SMC_RET2(handle, SMC_PCI_CALL_SUCCESS, ret);
+ }
+ break;
+ }
+ case SMC_PCI_WRITE: {
+ uint32_t ret;
+
+ if (validate_rw_addr_sz(x1, x2, x3) != SMC_PCI_CALL_SUCCESS) {
+ SMC_RET1(handle, SMC_PCI_CALL_INVAL_PARAM);
+ }
+ ret = pci_write_config(x1, x2, x3, x4);
+ SMC_RET1(handle, ret);
+ break;
+ }
+ case SMC_PCI_SEG_INFO: {
+ uint32_t nseg;
+ uint32_t ret;
+ uint32_t start_end_bus;
+
+ if ((x2 != 0U) || (x3 != 0U) || (x4 != 0U)) {
+ SMC_RET3(handle, SMC_PCI_CALL_INVAL_PARAM, 0U, 0U);
+ }
+ ret = pci_get_bus_for_seg(x1, &start_end_bus, &nseg);
+ SMC_RET3(handle, ret, start_end_bus, nseg);
+ break;
+ }
+ default:
+ /* should be unreachable */
+ WARN("Unimplemented PCI Service Call: 0x%x\n", smc_fid);
+ SMC_RET1(handle, SMC_PCI_CALL_NOT_SUPPORTED);
+ }
+}
diff --git a/services/std_svc/rmmd/aarch64/rmmd_helpers.S b/services/std_svc/rmmd/aarch64/rmmd_helpers.S
new file mode 100644
index 0000000..6229baf
--- /dev/null
+++ b/services/std_svc/rmmd/aarch64/rmmd_helpers.S
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "../rmmd_private.h"
+#include <asm_macros.S>
+
+ .global rmmd_rmm_enter
+ .global rmmd_rmm_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 rmmd_rmm_enter
+ /* Make space for the registers that we're going to save */
+ mov x3, sp
+ str x3, [x0, #0]
+ sub sp, sp, #RMMD_C_RT_CTX_SIZE
+
+ /* Save callee-saved registers on to the stack */
+ stp x19, x20, [sp, #RMMD_C_RT_CTX_X19]
+ stp x21, x22, [sp, #RMMD_C_RT_CTX_X21]
+ stp x23, x24, [sp, #RMMD_C_RT_CTX_X23]
+ stp x25, x26, [sp, #RMMD_C_RT_CTX_X25]
+ stp x27, x28, [sp, #RMMD_C_RT_CTX_X27]
+ stp x29, x30, [sp, #RMMD_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 rmmd_rmm_enter
+
+ /* ---------------------------------------------------------------------
+ * This function is called with 'x0' pointing to a C runtime context.
+ * 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 rmmd_rmm_exit
+ /* Restore the previous stack */
+ mov sp, x0
+
+ /* Restore callee-saved registers on to the stack */
+ ldp x19, x20, [x0, #(RMMD_C_RT_CTX_X19 - RMMD_C_RT_CTX_SIZE)]
+ ldp x21, x22, [x0, #(RMMD_C_RT_CTX_X21 - RMMD_C_RT_CTX_SIZE)]
+ ldp x23, x24, [x0, #(RMMD_C_RT_CTX_X23 - RMMD_C_RT_CTX_SIZE)]
+ ldp x25, x26, [x0, #(RMMD_C_RT_CTX_X25 - RMMD_C_RT_CTX_SIZE)]
+ ldp x27, x28, [x0, #(RMMD_C_RT_CTX_X27 - RMMD_C_RT_CTX_SIZE)]
+ ldp x29, x30, [x0, #(RMMD_C_RT_CTX_X29 - RMMD_C_RT_CTX_SIZE)]
+
+ /* ---------------------------------------------------------------------
+ * This should take us back to the instruction after the call to the
+ * last rmmd_rmm_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 rmmd_rmm_exit
diff --git a/services/std_svc/rmmd/rmmd.mk b/services/std_svc/rmmd/rmmd.mk
new file mode 100644
index 0000000..bcf54e1
--- /dev/null
+++ b/services/std_svc/rmmd/rmmd.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifneq (${ARCH},aarch64)
+ $(error "Error: RMMD is only supported on aarch64.")
+endif
+
+include services/std_svc/rmmd/trp/trp.mk
+
+RMMD_SOURCES += $(addprefix services/std_svc/rmmd/, \
+ ${ARCH}/rmmd_helpers.S \
+ rmmd_main.c \
+ rmmd_attest.c)
+
+# Let the top-level Makefile know that we intend to include RMM image
+NEED_RMM := yes
diff --git a/services/std_svc/rmmd/rmmd_attest.c b/services/std_svc/rmmd/rmmd_attest.c
new file mode 100644
index 0000000..25adf50
--- /dev/null
+++ b/services/std_svc/rmmd/rmmd_attest.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <lib/spinlock.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#include "rmmd_private.h"
+#include <services/rmmd_svc.h>
+
+static spinlock_t lock;
+
+/* For printing Realm attestation token hash */
+#define DIGITS_PER_BYTE 2UL
+#define LENGTH_OF_TERMINATING_ZERO_IN_BYTES 1UL
+#define BYTES_PER_LINE_BASE 4UL
+
+static void print_challenge(uint8_t *hash, size_t hash_size)
+{
+ size_t leftover;
+ /*
+ * bytes_per_line is always a power of two, so it can be used to
+ * construct mask with it when it is necessary to count remainder.
+ *
+ */
+ const size_t bytes_per_line = 1 << BYTES_PER_LINE_BASE;
+ char hash_text[(1 << BYTES_PER_LINE_BASE) * DIGITS_PER_BYTE +
+ LENGTH_OF_TERMINATING_ZERO_IN_BYTES];
+ const char hex_chars[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+ unsigned int i;
+
+ for (i = 0U; i < hash_size; ++i) {
+ hash_text[(i & (bytes_per_line - 1)) * DIGITS_PER_BYTE] =
+ hex_chars[hash[i] >> 4];
+ hash_text[(i & (bytes_per_line - 1)) * DIGITS_PER_BYTE + 1] =
+ hex_chars[hash[i] & 0x0f];
+ if (((i + 1) & (bytes_per_line - 1)) == 0U) {
+ hash_text[bytes_per_line * DIGITS_PER_BYTE] = '\0';
+ VERBOSE("hash part %u = %s\n",
+ (i >> BYTES_PER_LINE_BASE) + 1, hash_text);
+ }
+ }
+
+ leftover = (size_t)i & (bytes_per_line - 1);
+
+ if (leftover != 0UL) {
+ hash_text[leftover * DIGITS_PER_BYTE] = '\0';
+ VERBOSE("hash part %u = %s\n", (i >> BYTES_PER_LINE_BASE) + 1,
+ hash_text);
+ }
+}
+
+/*
+ * Helper function to validate that the buffer base and length are
+ * within range.
+ */
+static int validate_buffer_params(uint64_t buf_pa, uint64_t buf_len)
+{
+ unsigned long shared_buf_page;
+ uintptr_t shared_buf_base;
+
+ (void)plat_rmmd_get_el3_rmm_shared_mem(&shared_buf_base);
+
+ shared_buf_page = shared_buf_base & ~PAGE_SIZE_MASK;
+
+ /* Validate the buffer pointer */
+ if ((buf_pa & ~PAGE_SIZE_MASK) != shared_buf_page) {
+ ERROR("Buffer PA out of range\n");
+ return E_RMM_BAD_ADDR;
+ }
+
+ /* Validate the size of the shared area */
+ if (((buf_pa + buf_len - 1UL) & ~PAGE_SIZE_MASK) != shared_buf_page) {
+ ERROR("Invalid buffer length\n");
+ return E_RMM_INVAL;
+ }
+
+ return 0; /* No error */
+}
+
+int rmmd_attest_get_platform_token(uint64_t buf_pa, uint64_t *buf_size,
+ uint64_t c_size)
+{
+ int err;
+ uint8_t temp_buf[SHA512_DIGEST_SIZE];
+
+ err = validate_buffer_params(buf_pa, *buf_size);
+ if (err != 0) {
+ return err;
+ }
+
+ if ((c_size != SHA256_DIGEST_SIZE) &&
+ (c_size != SHA384_DIGEST_SIZE) &&
+ (c_size != SHA512_DIGEST_SIZE)) {
+ ERROR("Invalid hash size: %lu\n", c_size);
+ return E_RMM_INVAL;
+ }
+
+ spin_lock(&lock);
+
+ (void)memcpy(temp_buf, (void *)buf_pa, c_size);
+
+ print_challenge((uint8_t *)temp_buf, c_size);
+
+ /* Get the platform token. */
+ err = plat_rmmd_get_cca_attest_token((uintptr_t)buf_pa,
+ buf_size, (uintptr_t)temp_buf, c_size);
+
+ if (err != 0) {
+ ERROR("Failed to get platform token: %d.\n", err);
+ err = E_RMM_UNK;
+ }
+
+ spin_unlock(&lock);
+
+ return err;
+}
+
+int rmmd_attest_get_signing_key(uint64_t buf_pa, uint64_t *buf_size,
+ uint64_t ecc_curve)
+{
+ int err;
+
+ err = validate_buffer_params(buf_pa, *buf_size);
+ if (err != 0) {
+ return err;
+ }
+
+ if (ecc_curve != ATTEST_KEY_CURVE_ECC_SECP384R1) {
+ ERROR("Invalid ECC curve specified\n");
+ return E_RMM_INVAL;
+ }
+
+ spin_lock(&lock);
+
+ /* Get the Realm attestation key. */
+ err = plat_rmmd_get_cca_realm_attest_key((uintptr_t)buf_pa, buf_size,
+ (unsigned int)ecc_curve);
+ if (err != 0) {
+ ERROR("Failed to get attestation key: %d.\n", err);
+ err = E_RMM_UNK;
+ }
+
+ spin_unlock(&lock);
+
+ return err;
+}
diff --git a/services/std_svc/rmmd/rmmd_initial_context.h b/services/std_svc/rmmd/rmmd_initial_context.h
new file mode 100644
index 0000000..d7a743d
--- /dev/null
+++ b/services/std_svc/rmmd/rmmd_initial_context.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RMMD_INITIAL_CONTEXT_H
+#define RMMD_INITIAL_CONTEXT_H
+
+#include <arch.h>
+
+/*
+ * SPSR_EL2
+ * M=0x9 (0b1001 EL2h)
+ * M[4]=0
+ * DAIF=0xF Exceptions masked on entry.
+ * BTYPE=0 BTI not yet supported.
+ * SSBS=0 Not yet supported.
+ * IL=0 Not an illegal exception return.
+ * SS=0 Not single stepping.
+ * PAN=1 RMM shouldn't access realm memory.
+ * UAO=0
+ * DIT=0
+ * TCO=0
+ * NZCV=0
+ */
+#define REALM_SPSR_EL2 ( \
+ SPSR_M_EL2H | \
+ (0xF << SPSR_DAIF_SHIFT) | \
+ SPSR_PAN_BIT \
+ )
+
+#endif /* RMMD_INITIAL_CONTEXT_H */
diff --git a/services/std_svc/rmmd/rmmd_main.c b/services/std_svc/rmmd/rmmd_main.c
new file mode 100644
index 0000000..6bd9fdf
--- /dev/null
+++ b/services/std_svc/rmmd/rmmd_main.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <arch_features.h>
+#include <bl31/bl31.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/el3_runtime/pubsub.h>
+#include <lib/gpt_rme/gpt_rme.h>
+
+#include <lib/spinlock.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/common_def.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <services/rmmd_svc.h>
+#include <smccc_helpers.h>
+#include <lib/extensions/sve.h>
+#include "rmmd_initial_context.h"
+#include "rmmd_private.h"
+
+/*******************************************************************************
+ * RMM boot failure flag
+ ******************************************************************************/
+static bool rmm_boot_failed;
+
+/*******************************************************************************
+ * RMM context information.
+ ******************************************************************************/
+rmmd_rmm_context_t rmm_context[PLATFORM_CORE_COUNT];
+
+/*******************************************************************************
+ * RMM entry point information. Discovered on the primary core and reused
+ * on secondary cores.
+ ******************************************************************************/
+static entry_point_info_t *rmm_ep_info;
+
+/*******************************************************************************
+ * Static function declaration.
+ ******************************************************************************/
+static int32_t rmm_init(void);
+
+/*******************************************************************************
+ * This function takes an RMM context pointer and performs a synchronous entry
+ * into it.
+ ******************************************************************************/
+uint64_t rmmd_rmm_sync_entry(rmmd_rmm_context_t *rmm_ctx)
+{
+ uint64_t rc;
+
+ assert(rmm_ctx != NULL);
+
+ cm_set_context(&(rmm_ctx->cpu_ctx), REALM);
+
+ /* Restore the realm context assigned above */
+ cm_el1_sysregs_context_restore(REALM);
+ cm_el2_sysregs_context_restore(REALM);
+ cm_set_next_eret_context(REALM);
+
+ /* Enter RMM */
+ rc = rmmd_rmm_enter(&rmm_ctx->c_rt_ctx);
+
+ /*
+ * Save realm context. EL1 and EL2 Non-secure
+ * contexts will be restored before exiting to
+ * Non-secure world, therefore there is no need
+ * to clear EL1 and EL2 context registers.
+ */
+ cm_el1_sysregs_context_save(REALM);
+ cm_el2_sysregs_context_save(REALM);
+
+ return rc;
+}
+
+/*******************************************************************************
+ * This function returns to the place where rmmd_rmm_sync_entry() was
+ * called originally.
+ ******************************************************************************/
+__dead2 void rmmd_rmm_sync_exit(uint64_t rc)
+{
+ rmmd_rmm_context_t *ctx = &rmm_context[plat_my_core_pos()];
+
+ /* Get context of the RMM in use by this CPU. */
+ assert(cm_get_context(REALM) == &(ctx->cpu_ctx));
+
+ /*
+ * The RMMD must have initiated the original request through a
+ * synchronous entry into RMM. Jump back to the original C runtime
+ * context with the value of rc in x0;
+ */
+ rmmd_rmm_exit(ctx->c_rt_ctx, rc);
+
+ panic();
+}
+
+static void rmm_el2_context_init(el2_sysregs_t *regs)
+{
+ regs->ctx_regs[CTX_SPSR_EL2 >> 3] = REALM_SPSR_EL2;
+ regs->ctx_regs[CTX_SCTLR_EL2 >> 3] = SCTLR_EL2_RES1;
+}
+
+/*******************************************************************************
+ * Enable architecture extensions on first entry to Realm world.
+ ******************************************************************************/
+static void manage_extensions_realm(cpu_context_t *ctx)
+{
+#if ENABLE_SVE_FOR_NS
+ /*
+ * Enable SVE and FPU in realm context when it is enabled for NS.
+ * Realm manager must ensure that the SVE and FPU register
+ * contexts are properly managed.
+ */
+ sve_enable(ctx);
+#else
+ /*
+ * Disable SVE and FPU in realm context when it is disabled for NS.
+ */
+ sve_disable(ctx);
+#endif /* ENABLE_SVE_FOR_NS */
+}
+
+/*******************************************************************************
+ * Jump to the RMM for the first time.
+ ******************************************************************************/
+static int32_t rmm_init(void)
+{
+ long rc;
+ rmmd_rmm_context_t *ctx = &rmm_context[plat_my_core_pos()];
+
+ INFO("RMM init start.\n");
+
+ /* Enable architecture extensions */
+ manage_extensions_realm(&ctx->cpu_ctx);
+
+ /* Initialize RMM EL2 context. */
+ rmm_el2_context_init(&ctx->cpu_ctx.el2_sysregs_ctx);
+
+ rc = rmmd_rmm_sync_entry(ctx);
+ if (rc != E_RMM_BOOT_SUCCESS) {
+ ERROR("RMM init failed: %ld\n", rc);
+ /* Mark the boot as failed for all the CPUs */
+ rmm_boot_failed = true;
+ return 0;
+ }
+
+ INFO("RMM init end.\n");
+
+ return 1;
+}
+
+/*******************************************************************************
+ * Load and read RMM manifest, setup RMM.
+ ******************************************************************************/
+int rmmd_setup(void)
+{
+ size_t shared_buf_size __unused;
+ uintptr_t shared_buf_base;
+ uint32_t ep_attr;
+ unsigned int linear_id = plat_my_core_pos();
+ rmmd_rmm_context_t *rmm_ctx = &rmm_context[linear_id];
+ rmm_manifest_t *manifest;
+ int rc;
+
+ /* Make sure RME is supported. */
+ assert(get_armv9_2_feat_rme_support() != 0U);
+
+ rmm_ep_info = bl31_plat_get_next_image_ep_info(REALM);
+ if (rmm_ep_info == NULL) {
+ WARN("No RMM image provided by BL2 boot loader, Booting "
+ "device without RMM initialization. SMCs destined for "
+ "RMM will return SMC_UNK\n");
+ return -ENOENT;
+ }
+
+ /* Under no circumstances will this parameter be 0 */
+ assert(rmm_ep_info->pc == RMM_BASE);
+
+ /* Initialise an entrypoint to set up the CPU context */
+ ep_attr = EP_REALM;
+ if ((read_sctlr_el3() & SCTLR_EE_BIT) != 0U) {
+ ep_attr |= EP_EE_BIG;
+ }
+
+ SET_PARAM_HEAD(rmm_ep_info, PARAM_EP, VERSION_1, ep_attr);
+ rmm_ep_info->spsr = SPSR_64(MODE_EL2,
+ MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS);
+
+ shared_buf_size =
+ plat_rmmd_get_el3_rmm_shared_mem(&shared_buf_base);
+
+ assert((shared_buf_size == SZ_4K) &&
+ ((void *)shared_buf_base != NULL));
+
+ /* Load the boot manifest at the beginning of the shared area */
+ manifest = (rmm_manifest_t *)shared_buf_base;
+ rc = plat_rmmd_load_manifest(manifest);
+ if (rc != 0) {
+ ERROR("Error loading RMM Boot Manifest (%i)\n", rc);
+ return rc;
+ }
+ flush_dcache_range((uintptr_t)shared_buf_base, shared_buf_size);
+
+ /*
+ * Prepare coldboot arguments for RMM:
+ * arg0: This CPUID (primary processor).
+ * arg1: Version for this Boot Interface.
+ * arg2: PLATFORM_CORE_COUNT.
+ * arg3: Base address for the EL3 <-> RMM shared area. The boot
+ * manifest will be stored at the beginning of this area.
+ */
+ rmm_ep_info->args.arg0 = linear_id;
+ rmm_ep_info->args.arg1 = RMM_EL3_INTERFACE_VERSION;
+ rmm_ep_info->args.arg2 = PLATFORM_CORE_COUNT;
+ rmm_ep_info->args.arg3 = shared_buf_base;
+
+ /* Initialise RMM context with this entry point information */
+ cm_setup_context(&rmm_ctx->cpu_ctx, rmm_ep_info);
+
+ INFO("RMM setup done.\n");
+
+ /* Register init function for deferred init. */
+ bl31_register_rmm_init(&rmm_init);
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Forward SMC to the other security state
+ ******************************************************************************/
+static uint64_t rmmd_smc_forward(uint32_t src_sec_state,
+ uint32_t dst_sec_state, uint64_t x0,
+ uint64_t x1, uint64_t x2, uint64_t x3,
+ uint64_t x4, void *handle)
+{
+ cpu_context_t *ctx = cm_get_context(dst_sec_state);
+
+ /* Save incoming security state */
+ cm_el1_sysregs_context_save(src_sec_state);
+ cm_el2_sysregs_context_save(src_sec_state);
+
+ /* Restore outgoing security state */
+ cm_el1_sysregs_context_restore(dst_sec_state);
+ cm_el2_sysregs_context_restore(dst_sec_state);
+ cm_set_next_eret_context(dst_sec_state);
+
+ /*
+ * As per SMCCCv1.2, we need to preserve x4 to x7 unless
+ * being used as return args. Hence we differentiate the
+ * onward and backward path. Support upto 8 args in the
+ * onward path and 4 args in return path.
+ * Register x4 will be preserved by RMM in case it is not
+ * used in return path.
+ */
+ if (src_sec_state == NON_SECURE) {
+ SMC_RET8(ctx, x0, x1, x2, x3, x4,
+ SMC_GET_GP(handle, CTX_GPREG_X5),
+ SMC_GET_GP(handle, CTX_GPREG_X6),
+ SMC_GET_GP(handle, CTX_GPREG_X7));
+ }
+
+ SMC_RET5(ctx, x0, x1, x2, x3, x4);
+}
+
+/*******************************************************************************
+ * This function handles all SMCs in the range reserved for RMI. Each call is
+ * either forwarded to the other security state or handled by the RMM dispatcher
+ ******************************************************************************/
+uint64_t rmmd_rmi_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2,
+ uint64_t x3, uint64_t x4, void *cookie,
+ void *handle, uint64_t flags)
+{
+ uint32_t src_sec_state;
+
+ /* If RMM failed to boot, treat any RMI SMC as unknown */
+ if (rmm_boot_failed) {
+ WARN("RMMD: Failed to boot up RMM. Ignoring RMI call\n");
+ SMC_RET1(handle, SMC_UNK);
+ }
+
+ /* Determine which security state this SMC originated from */
+ src_sec_state = caller_sec_state(flags);
+
+ /* RMI must not be invoked by the Secure world */
+ if (src_sec_state == SMC_FROM_SECURE) {
+ WARN("RMMD: RMI invoked by secure world.\n");
+ SMC_RET1(handle, SMC_UNK);
+ }
+
+ /*
+ * Forward an RMI call from the Normal world to the Realm world as it
+ * is.
+ */
+ if (src_sec_state == SMC_FROM_NON_SECURE) {
+ VERBOSE("RMMD: RMI call from non-secure world.\n");
+ return rmmd_smc_forward(NON_SECURE, REALM, smc_fid,
+ x1, x2, x3, x4, handle);
+ }
+
+ if (src_sec_state != SMC_FROM_REALM) {
+ SMC_RET1(handle, SMC_UNK);
+ }
+
+ switch (smc_fid) {
+ case RMM_RMI_REQ_COMPLETE: {
+ uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+
+ return rmmd_smc_forward(REALM, NON_SECURE, x1,
+ x2, x3, x4, x5, handle);
+ }
+ default:
+ WARN("RMMD: Unsupported RMM call 0x%08x\n", smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+ }
+}
+
+/*******************************************************************************
+ * This cpu has been turned on. Enter RMM to initialise R-EL2. Entry into RMM
+ * is done after initialising minimal architectural state that guarantees safe
+ * execution.
+ ******************************************************************************/
+static void *rmmd_cpu_on_finish_handler(const void *arg)
+{
+ long rc;
+ uint32_t linear_id = plat_my_core_pos();
+ rmmd_rmm_context_t *ctx = &rmm_context[linear_id];
+
+ if (rmm_boot_failed) {
+ /* RMM Boot failed on a previous CPU. Abort. */
+ ERROR("RMM Failed to initialize. Ignoring for CPU%d\n",
+ linear_id);
+ return NULL;
+ }
+
+ /*
+ * Prepare warmboot arguments for RMM:
+ * arg0: This CPUID.
+ * arg1 to arg3: Not used.
+ */
+ rmm_ep_info->args.arg0 = linear_id;
+ rmm_ep_info->args.arg1 = 0ULL;
+ rmm_ep_info->args.arg2 = 0ULL;
+ rmm_ep_info->args.arg3 = 0ULL;
+
+ /* Initialise RMM context with this entry point information */
+ cm_setup_context(&ctx->cpu_ctx, rmm_ep_info);
+
+ /* Enable architecture extensions */
+ manage_extensions_realm(&ctx->cpu_ctx);
+
+ /* Initialize RMM EL2 context. */
+ rmm_el2_context_init(&ctx->cpu_ctx.el2_sysregs_ctx);
+
+ rc = rmmd_rmm_sync_entry(ctx);
+
+ if (rc != E_RMM_BOOT_SUCCESS) {
+ ERROR("RMM init failed on CPU%d: %ld\n", linear_id, rc);
+ /* Mark the boot as failed for any other booting CPU */
+ rmm_boot_failed = true;
+ }
+
+ return NULL;
+}
+
+/* Subscribe to PSCI CPU on to initialize RMM on secondary */
+SUBSCRIBE_TO_EVENT(psci_cpu_on_finish, rmmd_cpu_on_finish_handler);
+
+/* Convert GPT lib error to RMMD GTS error */
+static int gpt_to_gts_error(int error, uint32_t smc_fid, uint64_t address)
+{
+ int ret;
+
+ if (error == 0) {
+ return E_RMM_OK;
+ }
+
+ if (error == -EINVAL) {
+ ret = E_RMM_BAD_ADDR;
+ } else {
+ /* This is the only other error code we expect */
+ assert(error == -EPERM);
+ ret = E_RMM_BAD_PAS;
+ }
+
+ ERROR("RMMD: PAS Transition failed. GPT ret = %d, PA: 0x%"PRIx64 ", FID = 0x%x\n",
+ error, address, smc_fid);
+ return ret;
+}
+
+/*******************************************************************************
+ * This function handles RMM-EL3 interface SMCs
+ ******************************************************************************/
+uint64_t rmmd_rmm_el3_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2,
+ uint64_t x3, uint64_t x4, void *cookie,
+ void *handle, uint64_t flags)
+{
+ uint32_t src_sec_state;
+ int ret;
+
+ /* If RMM failed to boot, treat any RMM-EL3 interface SMC as unknown */
+ if (rmm_boot_failed) {
+ WARN("RMMD: Failed to boot up RMM. Ignoring RMM-EL3 call\n");
+ SMC_RET1(handle, SMC_UNK);
+ }
+
+ /* Determine which security state this SMC originated from */
+ src_sec_state = caller_sec_state(flags);
+
+ if (src_sec_state != SMC_FROM_REALM) {
+ WARN("RMMD: RMM-EL3 call originated from secure or normal world\n");
+ SMC_RET1(handle, SMC_UNK);
+ }
+
+ switch (smc_fid) {
+ case RMM_GTSI_DELEGATE:
+ ret = gpt_delegate_pas(x1, PAGE_SIZE_4KB, SMC_FROM_REALM);
+ SMC_RET1(handle, gpt_to_gts_error(ret, smc_fid, x1));
+ case RMM_GTSI_UNDELEGATE:
+ ret = gpt_undelegate_pas(x1, PAGE_SIZE_4KB, SMC_FROM_REALM);
+ SMC_RET1(handle, gpt_to_gts_error(ret, smc_fid, x1));
+ case RMM_ATTEST_GET_PLAT_TOKEN:
+ ret = rmmd_attest_get_platform_token(x1, &x2, x3);
+ SMC_RET2(handle, ret, x2);
+ case RMM_ATTEST_GET_REALM_KEY:
+ ret = rmmd_attest_get_signing_key(x1, &x2, x3);
+ SMC_RET2(handle, ret, x2);
+
+ case RMM_BOOT_COMPLETE:
+ VERBOSE("RMMD: running rmmd_rmm_sync_exit\n");
+ rmmd_rmm_sync_exit(x1);
+
+ default:
+ WARN("RMMD: Unsupported RMM-EL3 call 0x%08x\n", smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+ }
+}
diff --git a/services/std_svc/rmmd/rmmd_private.h b/services/std_svc/rmmd/rmmd_private.h
new file mode 100644
index 0000000..4954a43
--- /dev/null
+++ b/services/std_svc/rmmd/rmmd_private.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RMMD_PRIVATE_H
+#define RMMD_PRIVATE_H
+
+#include <context.h>
+
+/*******************************************************************************
+ * Constants that allow assembler code to preserve callee-saved registers of the
+ * C runtime context while performing a security state switch.
+ ******************************************************************************/
+#define RMMD_C_RT_CTX_X19 0x0
+#define RMMD_C_RT_CTX_X20 0x8
+#define RMMD_C_RT_CTX_X21 0x10
+#define RMMD_C_RT_CTX_X22 0x18
+#define RMMD_C_RT_CTX_X23 0x20
+#define RMMD_C_RT_CTX_X24 0x28
+#define RMMD_C_RT_CTX_X25 0x30
+#define RMMD_C_RT_CTX_X26 0x38
+#define RMMD_C_RT_CTX_X27 0x40
+#define RMMD_C_RT_CTX_X28 0x48
+#define RMMD_C_RT_CTX_X29 0x50
+#define RMMD_C_RT_CTX_X30 0x58
+
+#define RMMD_C_RT_CTX_SIZE 0x60
+#define RMMD_C_RT_CTX_ENTRIES (RMMD_C_RT_CTX_SIZE >> DWORD_SHIFT)
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+
+/*
+ * Data structure used by the RMM dispatcher (RMMD) in EL3 to track context of
+ * the RMM at R-EL2.
+ */
+typedef struct rmmd_rmm_context {
+ uint64_t c_rt_ctx;
+ cpu_context_t cpu_ctx;
+} rmmd_rmm_context_t;
+
+/* Functions used to enter/exit the RMM synchronously */
+uint64_t rmmd_rmm_sync_entry(rmmd_rmm_context_t *ctx);
+__dead2 void rmmd_rmm_sync_exit(uint64_t rc);
+
+/* Functions implementing attestation utilities for RMM */
+int rmmd_attest_get_platform_token(uint64_t buf_pa, uint64_t *buf_size,
+ uint64_t c_size);
+int rmmd_attest_get_signing_key(uint64_t buf_pa, uint64_t *buf_size,
+ uint64_t ecc_curve);
+
+/* Assembly helpers */
+uint64_t rmmd_rmm_enter(uint64_t *c_rt_ctx);
+void __dead2 rmmd_rmm_exit(uint64_t c_rt_ctx, uint64_t ret);
+
+/* Reference to PM ops for the RMMD */
+extern const spd_pm_ops_t rmmd_pm;
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* RMMD_PRIVATE_H */
diff --git a/services/std_svc/rmmd/trp/linker.lds b/services/std_svc/rmmd/trp/linker.lds
new file mode 100644
index 0000000..2b7f383
--- /dev/null
+++ b/services/std_svc/rmmd/trp/linker.lds
@@ -0,0 +1,71 @@
+/*
+ * (C) COPYRIGHT 2021 Arm Limited or its affiliates.
+ * ALL RIGHTS RESERVED
+ */
+
+#include <common/bl_common.ld.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+/* Mapped using 4K pages, requires us to align different sections with
+ * different property at the same granularity. */
+PAGE_SIZE_4K = 4096;
+
+OUTPUT_FORMAT("elf64-littleaarch64")
+OUTPUT_ARCH(aarch64)
+ENTRY(trp_head)
+
+MEMORY {
+ RAM (rwx): ORIGIN = RMM_BASE, LENGTH = RMM_LIMIT - RMM_BASE
+}
+
+
+SECTIONS
+{
+ . = RMM_BASE;
+
+ .text : {
+ *(.head.text)
+ . = ALIGN(8);
+ *(.text*)
+ } >RAM
+
+ . = ALIGN(PAGE_SIZE_4K);
+
+ .rodata : {
+ *(.rodata*)
+ } >RAM
+
+ . = ALIGN(PAGE_SIZE_4K);
+
+ __RW_START__ = . ;
+
+ .data : {
+ *(.data*)
+ } >RAM
+
+ .bss (NOLOAD) : {
+ __BSS_START__ = .;
+ *(.bss*)
+ __BSS_END__ = .;
+ } >RAM
+ __BSS_SIZE__ = SIZEOF(.bss);
+
+
+ STACK_SECTION >RAM
+
+
+ /*
+ * Define a linker symbol to mark the end of the RW memory area for this
+ * image.
+ */
+ __RW_END__ = .;
+ __RMM_END__ = .;
+
+
+ /DISCARD/ : { *(.dynstr*) }
+ /DISCARD/ : { *(.dynamic*) }
+ /DISCARD/ : { *(.plt*) }
+ /DISCARD/ : { *(.interp*) }
+ /DISCARD/ : { *(.gnu*) }
+ /DISCARD/ : { *(.note*) }
+}
diff --git a/services/std_svc/rmmd/trp/trp.mk b/services/std_svc/rmmd/trp/trp.mk
new file mode 100644
index 0000000..44bbf22
--- /dev/null
+++ b/services/std_svc/rmmd/trp/trp.mk
@@ -0,0 +1,21 @@
+#
+# Copyright (c) 2021-2022 Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+RMM_SOURCES += services/std_svc/rmmd/trp/trp_entry.S \
+ services/std_svc/rmmd/trp/trp_main.c \
+ services/std_svc/rmmd/trp/trp_helpers.c
+
+RMM_LINKERFILE := services/std_svc/rmmd/trp/linker.lds
+
+# Include the platform-specific TRP Makefile
+# If no platform-specific TRP Makefile exists, it means TRP is not supported
+# on this platform.
+TRP_PLAT_MAKEFILE := $(wildcard ${PLAT_DIR}/trp/trp-${PLAT}.mk)
+ifeq (,${TRP_PLAT_MAKEFILE})
+ $(error TRP is not supported on platform ${PLAT})
+else
+ include ${TRP_PLAT_MAKEFILE}
+endif
diff --git a/services/std_svc/rmmd/trp/trp_entry.S b/services/std_svc/rmmd/trp/trp_entry.S
new file mode 100644
index 0000000..47c1df1
--- /dev/null
+++ b/services/std_svc/rmmd/trp/trp_entry.S
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <services/rmmd_svc.h>
+
+#include <platform_def.h>
+#include "trp_private.h"
+
+.global trp_head
+.global trp_smc
+
+.section ".head.text", "ax"
+
+ /* ---------------------------------------------
+ * 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, #TRP_ARG6]
+ ldp x4, x5, [x0, #TRP_ARG4]
+ ldp x2, x3, [x0, #TRP_ARG2]
+ ldp x0, x1, [x0, #TRP_ARG0]
+ smc #0
+ .endm
+
+ /* ---------------------------------------------
+ * Entry point for TRP
+ * ---------------------------------------------
+ */
+trp_head:
+ /*
+ * Stash arguments from previous boot stage
+ */
+ mov x20, x0
+ mov x21, x1
+ mov x22, x2
+ mov x23, x3
+
+ /*
+ * Validate CPUId before allocating a stack.
+ */
+ cmp x20, #PLATFORM_CORE_COUNT
+ b.lo 1f
+
+ mov_imm x0, RMM_BOOT_COMPLETE
+ mov_imm x1, E_RMM_BOOT_CPU_ID_OUT_OF_RANGE
+ smc #0
+
+ /* EL3 should never return back here, so panic if it does */
+ b trp_panic
+
+1:
+ bl plat_set_my_stack
+
+ /*
+ * Find out whether this is a cold or warm boot
+ */
+ ldr x1, cold_boot_flag
+ cbz x1, warm_boot
+
+ /*
+ * Update cold boot flag to indicate cold boot is done
+ */
+ adr x2, cold_boot_flag
+ str xzr, [x2]
+
+ /* ---------------------------------------------
+ * Zero out BSS section
+ * ---------------------------------------------
+ */
+ ldr x0, =__BSS_START__
+ ldr x1, =__BSS_SIZE__
+ bl zeromem
+
+ mov x0, x20
+ mov x1, x21
+ mov x2, x22
+ mov x3, x23
+ bl trp_setup
+ bl trp_main
+warm_boot:
+ mov_imm x0, RMM_BOOT_COMPLETE
+ mov x1, xzr /* RMM_BOOT_SUCCESS */
+ smc #0
+ b trp_handler
+
+trp_panic:
+ no_ret plat_panic_handler
+
+ /*
+ * Flag to mark if it is a cold boot.
+ * 1: cold boot, 0: warmboot.
+ */
+.align 3
+cold_boot_flag:
+ .dword 1
+
+ /* ---------------------------------------------
+ * Direct SMC call to BL31 service provided by
+ * RMM Dispatcher
+ * ---------------------------------------------
+ */
+func trp_smc
+ restore_args_call_smc
+ ret
+endfunc trp_smc
+
+ /* ---------------------------------------------
+ * RMI call handler
+ * ---------------------------------------------
+ */
+func trp_handler
+ bl trp_rmi_handler
+ restore_args_call_smc
+ b trp_handler
+endfunc trp_handler
diff --git a/services/std_svc/rmmd/trp/trp_helpers.c b/services/std_svc/rmmd/trp/trp_helpers.c
new file mode 100644
index 0000000..159f3a5
--- /dev/null
+++ b/services/std_svc/rmmd/trp/trp_helpers.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#include <plat/common/platform.h>
+#include <services/rmmd_svc.h>
+#include "trp_private.h"
+
+/*
+ * 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 trp_args_t trp_smc_args[PLATFORM_CORE_COUNT];
+
+/*
+ * Set the arguments for SMC call
+ */
+trp_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;
+ trp_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 = &trp_smc_args[linear_id];
+ write_trp_arg(pcpu_smc_args, TRP_ARG0, arg0);
+ write_trp_arg(pcpu_smc_args, TRP_ARG1, arg1);
+ write_trp_arg(pcpu_smc_args, TRP_ARG2, arg2);
+ write_trp_arg(pcpu_smc_args, TRP_ARG3, arg3);
+ write_trp_arg(pcpu_smc_args, TRP_ARG4, arg4);
+ write_trp_arg(pcpu_smc_args, TRP_ARG5, arg5);
+ write_trp_arg(pcpu_smc_args, TRP_ARG6, arg6);
+ write_trp_arg(pcpu_smc_args, TRP_ARG7, arg7);
+
+ return pcpu_smc_args;
+}
+
+/*
+ * Abort the boot process with the reason given in err.
+ */
+__dead2 void trp_boot_abort(uint64_t err)
+{
+ (void)trp_smc(set_smc_args(RMM_BOOT_COMPLETE, err, 0, 0, 0, 0, 0, 0));
+ panic();
+}
diff --git a/services/std_svc/rmmd/trp/trp_main.c b/services/std_svc/rmmd/trp/trp_main.c
new file mode 100644
index 0000000..5a56af0
--- /dev/null
+++ b/services/std_svc/rmmd/trp/trp_main.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#include <common/debug.h>
+#include <plat/common/platform.h>
+#include <services/rmm_core_manifest.h>
+#include <services/rmmd_svc.h>
+#include <services/trp/platform_trp.h>
+#include <trp_helpers.h>
+#include "trp_private.h"
+
+#include <platform_def.h>
+
+/* Parameters received from the previous image */
+static unsigned int trp_boot_abi_version;
+static uintptr_t trp_shared_region_start;
+
+/* Parameters received from boot manifest */
+uint32_t trp_boot_manifest_version;
+
+/*******************************************************************************
+ * Setup function for TRP.
+ ******************************************************************************/
+void trp_setup(uint64_t x0,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3)
+{
+ /*
+ * Validate boot parameters.
+ *
+ * According to the Boot Interface ABI v.0.1, the
+ * parameters recived from EL3 are:
+ * x0: CPUID (verified earlier so not used)
+ * x1: Boot Interface version
+ * x2: PLATFORM_CORE_COUNT
+ * x3: Pointer to the shared memory area.
+ */
+
+ (void)x0;
+
+ if (TRP_RMM_EL3_VERSION_GET_MAJOR(x1) != TRP_RMM_EL3_ABI_VERS_MAJOR) {
+ trp_boot_abort(E_RMM_BOOT_VERSION_MISMATCH);
+ }
+
+ if ((void *)x3 == NULL) {
+ trp_boot_abort(E_RMM_BOOT_INVALID_SHARED_BUFFER);
+ }
+
+ if (x2 > TRP_PLATFORM_CORE_COUNT) {
+ trp_boot_abort(E_RMM_BOOT_CPUS_OUT_OF_RANGE);
+ }
+
+ trp_boot_abi_version = x1;
+ trp_shared_region_start = x3;
+ flush_dcache_range((uintptr_t)&trp_boot_abi_version,
+ sizeof(trp_boot_abi_version));
+ flush_dcache_range((uintptr_t)&trp_shared_region_start,
+ sizeof(trp_shared_region_start));
+
+ /* Perform early platform-specific setup */
+ trp_early_platform_setup((rmm_manifest_t *)trp_shared_region_start);
+}
+
+/* Main function for TRP */
+void trp_main(void)
+{
+ NOTICE("TRP: %s\n", version_string);
+ NOTICE("TRP: %s\n", build_message);
+ NOTICE("TRP: Supported RMM-EL3 Interface ABI: v.%u.%u\n",
+ TRP_RMM_EL3_ABI_VERS_MAJOR, TRP_RMM_EL3_ABI_VERS_MINOR);
+ NOTICE("TRP: Boot Manifest Version : v.%u.%u\n",
+ RMMD_GET_MANIFEST_VERSION_MAJOR(trp_boot_manifest_version),
+ RMMD_GET_MANIFEST_VERSION_MINOR(trp_boot_manifest_version));
+ INFO("TRP: Memory base : 0x%lx\n", (unsigned long)RMM_BASE);
+ INFO("TRP: Base address for the shared region : 0x%lx\n",
+ (unsigned long)trp_shared_region_start);
+ INFO("TRP: Total size : 0x%lx bytes\n", (unsigned long)(RMM_END
+ - RMM_BASE));
+ INFO("TRP: RMM-EL3 Interface ABI reported by EL3: v.%u.%u\n",
+ TRP_RMM_EL3_VERSION_GET_MAJOR(trp_boot_abi_version),
+ TRP_RMM_EL3_VERSION_GET_MINOR(trp_boot_abi_version));
+}
+
+/*******************************************************************************
+ * Returning RMI version back to Normal World
+ ******************************************************************************/
+static trp_args_t *trp_ret_rmi_version(void)
+{
+ VERBOSE("RMM version is %u.%u\n", RMI_ABI_VERSION_MAJOR,
+ RMI_ABI_VERSION_MINOR);
+ return set_smc_args(RMM_RMI_REQ_COMPLETE, RMI_ABI_VERSION,
+ 0, 0, 0, 0, 0, 0);
+}
+
+/*******************************************************************************
+ * Transitioning granule of NON-SECURE type to REALM type
+ ******************************************************************************/
+static trp_args_t *trp_asc_mark_realm(unsigned long long x1)
+{
+ unsigned long long ret;
+
+ VERBOSE("Delegating granule 0x%llx\n", x1);
+ ret = trp_smc(set_smc_args(RMM_GTSI_DELEGATE, x1, 0, 0, 0, 0, 0, 0));
+
+ if (ret != 0ULL) {
+ ERROR("Granule transition from NON-SECURE type to REALM type "
+ "failed 0x%llx\n", ret);
+ }
+ return set_smc_args(RMM_RMI_REQ_COMPLETE, ret, 0, 0, 0, 0, 0, 0);
+}
+
+/*******************************************************************************
+ * Transitioning granule of REALM type to NON-SECURE type
+ ******************************************************************************/
+static trp_args_t *trp_asc_mark_nonsecure(unsigned long long x1)
+{
+ unsigned long long ret;
+
+ VERBOSE("Undelegating granule 0x%llx\n", x1);
+ ret = trp_smc(set_smc_args(RMM_GTSI_UNDELEGATE, x1, 0, 0, 0, 0, 0, 0));
+
+ if (ret != 0ULL) {
+ ERROR("Granule transition from REALM type to NON-SECURE type "
+ "failed 0x%llx\n", ret);
+ }
+ return set_smc_args(RMM_RMI_REQ_COMPLETE, ret, 0, 0, 0, 0, 0, 0);
+}
+
+/*******************************************************************************
+ * Main RMI SMC handler function
+ ******************************************************************************/
+trp_args_t *trp_rmi_handler(unsigned long fid, unsigned long long x1)
+{
+ switch (fid) {
+ case RMI_RMM_REQ_VERSION:
+ return trp_ret_rmi_version();
+ case RMI_RMM_GRANULE_DELEGATE:
+ return trp_asc_mark_realm(x1);
+ case RMI_RMM_GRANULE_UNDELEGATE:
+ return trp_asc_mark_nonsecure(x1);
+ default:
+ ERROR("Invalid SMC code to %s, FID %lu\n", __func__, fid);
+ }
+ return set_smc_args(SMC_UNK, 0, 0, 0, 0, 0, 0, 0);
+}
diff --git a/services/std_svc/rmmd/trp/trp_private.h b/services/std_svc/rmmd/trp/trp_private.h
new file mode 100644
index 0000000..945ae1c
--- /dev/null
+++ b/services/std_svc/rmmd/trp/trp_private.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TRP_PRIVATE_H
+#define TRP_PRIVATE_H
+
+#include <services/rmmd_svc.h>
+#include <trp_helpers.h>
+
+/* Definitions for RMM-EL3 Interface ABI VERSION */
+#define TRP_RMM_EL3_ABI_VERS_MAJOR RMM_EL3_IFC_VERSION_MAJOR
+#define TRP_RMM_EL3_ABI_VERS_MINOR RMM_EL3_IFC_VERSION_MINOR
+#define TRP_RMM_EL3_ABI_VERS (((TRP_RMM_EL3_ABI_VERS_MAJOR & 0x7FFF) << 16) | \
+ (TRP_RMM_EL3_ABI_VERS_MINOR & 0xFFFF))
+
+#define TRP_PLATFORM_CORE_COUNT PLATFORM_CORE_COUNT
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+#define write_trp_arg(args, offset, val) (((args)->regs[offset >> 3]) \
+ = val)
+/* RMI SMC64 FIDs handled by the TRP */
+#define RMI_RMM_REQ_VERSION SMC64_RMI_FID(U(0))
+#define RMI_RMM_GRANULE_DELEGATE SMC64_RMI_FID(U(1))
+#define RMI_RMM_GRANULE_UNDELEGATE SMC64_RMI_FID(U(2))
+
+/* Definitions for RMI VERSION */
+#define RMI_ABI_VERSION_MAJOR U(0x0)
+#define RMI_ABI_VERSION_MINOR U(0x0)
+#define RMI_ABI_VERSION (((RMI_ABI_VERSION_MAJOR & 0x7FFF) \
+ << 16) | \
+ (RMI_ABI_VERSION_MINOR & 0xFFFF))
+
+#define TRP_RMM_EL3_VERSION_GET_MAJOR(x) \
+ RMM_EL3_IFC_VERSION_GET_MAJOR((x))
+#define TRP_RMM_EL3_VERSION_GET_MINOR(x) \
+ RMM_EL3_IFC_VERSION_GET_MAJOR_MINOR((x))
+
+/* Helper to issue SMC calls to BL31 */
+uint64_t trp_smc(trp_args_t *);
+
+/* The main function to executed only by Primary CPU */
+void trp_main(void);
+
+/* Setup TRP. Executed only by Primary CPU */
+void trp_setup(uint64_t x0,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3);
+
+#endif /* __ASSEMBLER__ */
+#endif /* TRP_PRIVATE_H */
diff --git a/services/std_svc/sdei/sdei_dispatch.S b/services/std_svc/sdei/sdei_dispatch.S
new file mode 100644
index 0000000..8449e4b
--- /dev/null
+++ b/services/std_svc/sdei/sdei_dispatch.S
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+ .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
diff --git a/services/std_svc/sdei/sdei_event.c b/services/std_svc/sdei/sdei_event.c
new file mode 100644
index 0000000..e0c7971
--- /dev/null
+++ b/services/std_svc/sdei/sdei_event.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <lib/utils.h>
+
+#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;
+}
+
+/*
+ * Return the total number of currently registered SDEI events.
+ */
+int sdei_get_registered_event_count(void)
+{
+ const sdei_mapping_t *mapping;
+ sdei_ev_map_t *map;
+ unsigned int i;
+ unsigned int j;
+ int count = 0;
+
+ /* Add up reg counts for each mapping. */
+ for_each_mapping_type(i, mapping) {
+ iterate_mapping(mapping, j, map) {
+ count += map->reg_count;
+ }
+ }
+
+ return count;
+}
diff --git a/services/std_svc/sdei/sdei_intr_mgmt.c b/services/std_svc/sdei/sdei_intr_mgmt.c
new file mode 100644
index 0000000..87a1fb7
--- /dev/null
+++ b/services/std_svc/sdei/sdei_intr_mgmt.c
@@ -0,0 +1,774 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <arch_features.h>
+#include <bl31/ehf.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/cassert.h>
+#include <services/sdei.h>
+
+#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;
+}
+
+/*
+ * Prepare for ERET:
+ * - Set the ELR to the registered handler address
+ * - Set the SPSR register as described in the SDEI documentation and
+ * the AArch64.TakeException() pseudocode function in
+ * ARM DDI 0487F.c page J1-7635
+ */
+
+static void sdei_set_elr_spsr(sdei_entry_t *se, sdei_dispatch_context_t *disp_ctx)
+{
+ unsigned int client_el = sdei_client_el();
+ u_register_t sdei_spsr = SPSR_64(client_el, MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS);
+
+ u_register_t interrupted_pstate = disp_ctx->spsr_el3;
+
+ /* Check the SPAN bit in the client el SCTLR */
+ u_register_t client_el_sctlr;
+
+ if (client_el == MODE_EL2) {
+ client_el_sctlr = read_sctlr_el2();
+ } else {
+ client_el_sctlr = read_sctlr_el1();
+ }
+
+ /*
+ * Check whether to force the PAN bit or use the value in the
+ * interrupted EL according to the check described in
+ * TakeException. Since the client can only be Non-Secure
+ * EL2 or El1 some of the conditions in ElIsInHost() we know
+ * will always be True.
+ * When the client_el is EL2 we know that there will be a SPAN
+ * bit in SCTLR_EL2 as we have already checked for the condition
+ * HCR_EL2.E2H = 1 and HCR_EL2.TGE = 1
+ */
+ u_register_t hcr_el2 = read_hcr();
+ bool el_is_in_host = is_armv8_1_vhe_present() &&
+ (hcr_el2 & HCR_TGE_BIT) &&
+ (hcr_el2 & HCR_E2H_BIT);
+
+ if (is_armv8_1_pan_present() &&
+ ((client_el == MODE_EL1) ||
+ (client_el == MODE_EL2 && el_is_in_host)) &&
+ ((client_el_sctlr & SCTLR_SPAN_BIT) == 0U)) {
+ sdei_spsr |= SPSR_PAN_BIT;
+ } else {
+ sdei_spsr |= (interrupted_pstate & SPSR_PAN_BIT);
+ }
+
+ /* If SSBS is implemented, take the value from the client el SCTLR */
+ u_register_t ssbs_enabled = (read_id_aa64pfr1_el1()
+ >> ID_AA64PFR1_EL1_SSBS_SHIFT)
+ & ID_AA64PFR1_EL1_SSBS_MASK;
+ if (ssbs_enabled != SSBS_UNAVAILABLE) {
+ u_register_t ssbs_bit = ((client_el_sctlr & SCTLR_DSSBS_BIT)
+ >> SCTLR_DSSBS_SHIFT)
+ << SPSR_SSBS_SHIFT_AARCH64;
+ sdei_spsr |= ssbs_bit;
+ }
+
+ /* If MTE is implemented in the client el set the TCO bit */
+ if (get_armv8_5_mte_support() >= MTE_IMPLEMENTED_ELX) {
+ sdei_spsr |= SPSR_TCO_BIT_AARCH64;
+ }
+
+ /* Take the DIT field from the pstate of the interrupted el */
+ sdei_spsr |= (interrupted_pstate & SPSR_DIT_BIT);
+
+ cm_set_elr_spsr_el3(NON_SECURE, (uintptr_t) se->ep, sdei_spsr);
+}
+
+/*
+ * 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);
+
+ /* Setup the elr and spsr register to prepare for ERET */
+ sdei_set_elr_spsr(se, disp_ctx);
+
+#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 %" PRIx64 " 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 %" PRIx64 ", ev:0x%x 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=0x%x\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;
+
+ /*
+ * Prepare for NS dispatch by restoring the Non-secure context and
+ * marking that as active.
+ */
+ ns_ctx = restore_and_resume_ns_context();
+
+ /* Activate the priority corresponding to the event being dispatched */
+ ehf_activate_priority(sdei_event_priority(map));
+
+ /* 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];
+}
diff --git a/services/std_svc/sdei/sdei_main.c b/services/std_svc/sdei/sdei_main.c
new file mode 100644
index 0000000..44178ed
--- /dev/null
+++ b/services/std_svc/sdei/sdei_main.c
@@ -0,0 +1,1114 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <bl31/bl31.h>
+#include <bl31/ehf.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <context.h>
+#include <lib/cassert.h>
+#include <lib/el3_runtime/pubsub.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <services/sdei.h>
+
+#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)
+{
+ plat_sdei_setup();
+ 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;
+ if (flags == SDEI_REGF_RM_PE) {
+ se->affinity = (mpidr & MPIDR_AFFINITY_MASK);
+ }
+
+ /*
+ * 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)) {
+ /*
+ * SDEI internally handles private events in the same manner
+ * as public events with routing mode=RM_PE, since the routing
+ * mode flag and affinity fields are not used when registering
+ * a private event, set them here.
+ */
+ flags = SDEI_REGF_RM_PE;
+ /*
+ * Kernel may pass 0 as mpidr, as we set flags to
+ * SDEI_REGF_RM_PE, so set mpidr also.
+ */
+ mpidr = read_mpidr_el1();
+ }
+
+ 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:%" PRIx64 "\n", ret);
+ SMC_RET1(ctx, ret);
+
+ case SDEI_EVENT_REGISTER:
+ x5 = SMC_GET_GP(ctx, CTX_GPREG_X5);
+ SDEI_LOG("> REG(n:%d e:%" PRIx64 " a:%" PRIx64 " f:%x m:%" PRIx64 "\n", ev_num,
+ x2, x3, (int) x4, x5);
+ ret = sdei_event_register(ev_num, x2, x3, x4, x5);
+ SDEI_LOG("< REG:%" PRId64 "\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:%" PRId64 "\n", ret);
+ SMC_RET1(ctx, ret);
+
+ case SDEI_EVENT_DISABLE:
+ SDEI_LOG("> DISABLE(n:0x%x)\n", ev_num);
+ ret = sdei_event_disable(ev_num);
+ SDEI_LOG("< DISABLE:%" PRId64 "\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:%" PRId64 "\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:%" PRIx64 "):%lx\n",
+ (unsigned int) resume, x1, read_mpidr_el1());
+ ret = sdei_event_complete(resume, x1);
+ SDEI_LOG("< COMPLETE:%" PRIx64 "\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:0x%x)\n", ev_num);
+ ret = sdei_event_status(ev_num);
+ SDEI_LOG("< STAT:%" PRId64 "\n", ret);
+ SMC_RET1(ctx, ret);
+
+ case SDEI_EVENT_GET_INFO:
+ SDEI_LOG("> INFO(n:0x%x, %d)\n", ev_num, (int) x2);
+ ret = sdei_event_get_info(ev_num, (int) x2);
+ SDEI_LOG("< INFO:%" PRId64 "\n", ret);
+ SMC_RET1(ctx, ret);
+
+ case SDEI_EVENT_UNREGISTER:
+ SDEI_LOG("> UNREG(n:0x%x)\n", ev_num);
+ ret = sdei_event_unregister(ev_num);
+ SDEI_LOG("< UNREG:%" PRId64 "\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:%" PRId64 "\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:%" PRId64 "\n", ret);
+ SMC_RET1(ctx, ret);
+
+ case SDEI_INTERRUPT_RELEASE:
+ SDEI_LOG("> REL(0x%x)\n", ev_num);
+ ret = sdei_interrupt_release(ev_num);
+ SDEI_LOG("< REL:%" PRId64 "\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:%" PRId64 "\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:%" PRId64 "\n", ret);
+ SMC_RET1(ctx, ret);
+
+ case SDEI_EVENT_ROUTING_SET:
+ SDEI_LOG("> ROUTE_SET(n:%d f:%" PRIx64 " aff:%" PRIx64 ")\n", ev_num, x2, x3);
+ ret = sdei_event_routing_set(ev_num, x2, x3);
+ SDEI_LOG("< ROUTE_SET:%" PRId64 "\n", ret);
+ SMC_RET1(ctx, ret);
+
+ case SDEI_FEATURES:
+ SDEI_LOG("> FTRS(f:%" PRIx64 ")\n", x1);
+ ret = (int64_t) sdei_features((unsigned int) x1);
+ SDEI_LOG("< FTRS:%" PRIx64 "\n", ret);
+ SMC_RET1(ctx, ret);
+
+ case SDEI_EVENT_SIGNAL:
+ SDEI_LOG("> SIGNAL(e:%d t:%" PRIx64 ")\n", ev_num, x2);
+ ret = sdei_signal(ev_num, x2);
+ SDEI_LOG("< SIGNAL:%" PRId64 "\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);
diff --git a/services/std_svc/sdei/sdei_private.h b/services/std_svc/sdei/sdei_private.h
new file mode 100644
index 0000000..44a7301
--- /dev/null
+++ b/services/std_svc/sdei/sdei_private.h
@@ -0,0 +1,248 @@
+/*
+ * 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 <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/debug.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/spinlock.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+#include <services/sdei.h>
+#include <setjmp.h>
+
+#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 */
diff --git a/services/std_svc/sdei/sdei_state.c b/services/std_svc/sdei/sdei_state.c
new file mode 100644
index 0000000..1b448e6
--- /dev/null
+++ b/services/std_svc/sdei/sdei_state.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <lib/cassert.h>
+
+#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;
+ }
+}
diff --git a/services/std_svc/spm/common/aarch64/spm_helpers.S b/services/std_svc/spm/common/aarch64/spm_helpers.S
new file mode 100644
index 0000000..95e69fb
--- /dev/null
+++ b/services/std_svc/spm/common/aarch64/spm_helpers.S
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include "spm_common.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
diff --git a/services/std_svc/spm/common/include/spm_common.h b/services/std_svc/spm/common/include/spm_common.h
new file mode 100644
index 0000000..68805fc
--- /dev/null
+++ b/services/std_svc/spm/common/include/spm_common.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPM_COMMON_H
+#define SPM_COMMON_H
+
+#include <context.h>
+
+/*******************************************************************************
+ * 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 <stdint.h>
+
+/* 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);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* SPM_COMMON_H */
diff --git a/services/std_svc/spm/common/spm.mk b/services/std_svc/spm/common/spm.mk
new file mode 100644
index 0000000..9aa96be
--- /dev/null
+++ b/services/std_svc/spm/common/spm.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifneq (${ARCH},aarch64)
+ $(error "Error: SPM is only supported on aarch64.")
+endif
+
+INCLUDES += -Iservices/std_svc/spm/common/include
+
+SPM_SOURCES := $(addprefix services/std_svc/spm/common/,\
+ ${ARCH}/spm_helpers.S)
+
+# Let the top-level Makefile know that we intend to include a BL32 image
+NEED_BL32 := yes
diff --git a/services/std_svc/spm/el3_spmc/logical_sp.c b/services/std_svc/spm/el3_spmc/logical_sp.c
new file mode 100644
index 0000000..e080832
--- /dev/null
+++ b/services/std_svc/spm/el3_spmc/logical_sp.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <services/el3_spmc_logical_sp.h>
+#include <services/ffa_svc.h>
+#include "spmc.h"
+
+/*******************************************************************************
+ * Validate any logical partition descriptors before we initialise.
+ * Initialization of said partitions will be taken care of during SPMC boot.
+ ******************************************************************************/
+int el3_sp_desc_validate(void)
+{
+ struct el3_lp_desc *lp_array;
+
+ /*
+ * Assert the number of descriptors is less than maximum allowed.
+ * This constant should be define on a per platform basis.
+ */
+ assert(EL3_LP_DESCS_COUNT <= MAX_EL3_LP_DESCS_COUNT);
+
+ /* Check the array bounds are valid. */
+ assert(EL3_LP_DESCS_END >= EL3_LP_DESCS_START);
+
+ /* If no logical partitions are implemented then simply bail out. */
+ if (EL3_LP_DESCS_COUNT == 0U) {
+ return 0;
+ }
+
+ lp_array = get_el3_lp_array();
+
+ for (unsigned int index = 0; index < EL3_LP_DESCS_COUNT; index++) {
+ struct el3_lp_desc *lp_desc = &lp_array[index];
+
+ /* Validate our logical partition descriptors. */
+ if (lp_desc == NULL) {
+ ERROR("Invalid Logical SP Descriptor\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Ensure the ID follows the convention to indidate it resides
+ * in the secure world.
+ */
+ if (!ffa_is_secure_world_id(lp_desc->sp_id)) {
+ ERROR("Invalid Logical SP ID (0x%x)\n",
+ lp_desc->sp_id);
+ return -EINVAL;
+ }
+
+ /* Ensure we don't conflict with the SPMC partition ID. */
+ if (lp_desc->sp_id == FFA_SPMC_ID) {
+ ERROR("Logical SP ID clashes with SPMC ID(0x%x)\n",
+ lp_desc->sp_id);
+ return -EINVAL;
+ }
+
+ /* Ensure the UUID is not the NULL UUID. */
+ if (lp_desc->uuid[0] == 0 && lp_desc->uuid[1] == 0 &&
+ lp_desc->uuid[2] == 0 && lp_desc->uuid[3] == 0) {
+ ERROR("Invalid UUID for Logical SP (0x%x)\n",
+ lp_desc->sp_id);
+ return -EINVAL;
+ }
+
+ /* Ensure init function callback is registered. */
+ if (lp_desc->init == NULL) {
+ ERROR("Missing init function for Logical SP(0x%x)\n",
+ lp_desc->sp_id);
+ return -EINVAL;
+ }
+
+ /* Ensure that LP only supports receiving direct requests. */
+ if (lp_desc->properties &
+ ~(FFA_PARTITION_DIRECT_REQ_RECV)) {
+ ERROR("Invalid partition properties (0x%x)\n",
+ lp_desc->properties);
+ return -EINVAL;
+ }
+
+ /* Ensure direct request function callback is registered. */
+ if (lp_desc->direct_req == NULL) {
+ ERROR("No Direct Req handler for Logical SP (0x%x)\n",
+ lp_desc->sp_id);
+ return -EINVAL;
+ }
+
+ /* Ensure that all partition IDs are unique. */
+ for (unsigned int inner_idx = index + 1;
+ inner_idx < EL3_LP_DESCS_COUNT; inner_idx++) {
+ if (lp_desc->sp_id == lp_array[inner_idx].sp_id) {
+ ERROR("Duplicate SP ID Detected (0x%x)\n",
+ lp_desc->sp_id);
+ return -EINVAL;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/services/std_svc/spm/el3_spmc/spmc.h b/services/std_svc/spm/el3_spmc/spmc.h
new file mode 100644
index 0000000..5233650
--- /dev/null
+++ b/services/std_svc/spm/el3_spmc/spmc.h
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPMC_H
+#define SPMC_H
+
+#include <stdint.h>
+
+#include <common/bl_common.h>
+#include <lib/psci/psci.h>
+#include <lib/spinlock.h>
+#include <services/el3_spmc_logical_sp.h>
+#include "spm_common.h"
+
+/*
+ * Ranges of FF-A IDs for Normal world and Secure world components. The
+ * convention matches that used by other SPMCs i.e. Hafnium and OP-TEE.
+ */
+#define FFA_NWD_ID_BASE 0x0
+#define FFA_NWD_ID_LIMIT 0x7FFF
+#define FFA_SWD_ID_BASE 0x8000
+#define FFA_SWD_ID_LIMIT SPMD_DIRECT_MSG_ENDPOINT_ID - 1
+#define FFA_SWD_ID_MASK 0x8000
+
+/* ID 0 is reserved for the normal world entity, (Hypervisor or OS Kernel). */
+#define FFA_NWD_ID U(0)
+/* First ID is reserved for the SPMC */
+#define FFA_SPMC_ID U(FFA_SWD_ID_BASE)
+/* SP IDs are allocated after the SPMC ID */
+#define FFA_SP_ID_BASE (FFA_SPMC_ID + 1)
+/* Align with Hafnium implementation */
+#define INV_SP_ID 0x7FFF
+
+/* FF-A Related helper macros. */
+#define FFA_ID_MASK U(0xFFFF)
+#define FFA_PARTITION_ID_SHIFT U(16)
+#define FFA_FEATURES_BIT31_MASK U(0x1u << 31)
+#define FFA_FEATURES_RET_REQ_NS_BIT U(0x1 << 1)
+
+#define FFA_RUN_EP_ID(ep_vcpu_ids) \
+ ((ep_vcpu_ids >> FFA_PARTITION_ID_SHIFT) & FFA_ID_MASK)
+#define FFA_RUN_VCPU_ID(ep_vcpu_ids) \
+ (ep_vcpu_ids & FFA_ID_MASK)
+
+#define FFA_PAGE_SIZE (4096)
+#define FFA_RXTX_PAGE_COUNT_MASK 0x1F
+
+/* Ensure that the page size used by TF-A is 4k aligned. */
+CASSERT((PAGE_SIZE % FFA_PAGE_SIZE) == 0, assert_aligned_page_size);
+
+/*
+ * Defines to allow an SP to subscribe for power management messages
+ */
+#define FFA_PM_MSG_SUB_CPU_OFF U(1 << 0)
+#define FFA_PM_MSG_SUB_CPU_SUSPEND U(1 << 1)
+#define FFA_PM_MSG_SUB_CPU_SUSPEND_RESUME U(1 << 2)
+
+/*
+ * Runtime states of an execution context as per the FF-A v1.1 specification.
+ */
+enum sp_runtime_states {
+ RT_STATE_WAITING,
+ RT_STATE_RUNNING,
+ RT_STATE_PREEMPTED,
+ RT_STATE_BLOCKED
+};
+
+/*
+ * Runtime model of an execution context as per the FF-A v1.1 specification. Its
+ * value is valid only if the execution context is not in the waiting state.
+ */
+enum sp_runtime_model {
+ RT_MODEL_DIR_REQ,
+ RT_MODEL_RUN,
+ RT_MODEL_INIT,
+ RT_MODEL_INTR
+};
+
+enum sp_runtime_el {
+ EL1 = 0,
+ S_EL0,
+ S_EL1
+};
+
+enum sp_execution_state {
+ SP_STATE_AARCH64 = 0,
+ SP_STATE_AARCH32
+};
+
+enum mailbox_state {
+ /* There is no message in the mailbox. */
+ MAILBOX_STATE_EMPTY,
+
+ /* There is a message that has been populated in the mailbox. */
+ MAILBOX_STATE_FULL,
+};
+
+struct mailbox {
+ enum mailbox_state state;
+
+ /* RX/TX Buffers. */
+ void *rx_buffer;
+ const void *tx_buffer;
+
+ /* Size of RX/TX Buffer. */
+ uint32_t rxtx_page_count;
+
+ /* Lock access to mailbox. */
+ spinlock_t lock;
+};
+
+/*
+ * Execution context members for an SP. This is a bit like struct
+ * vcpu in a hypervisor.
+ */
+struct sp_exec_ctx {
+ /*
+ * Store the stack address to restore C runtime context from after
+ * returning from a synchronous entry into the SP.
+ */
+ uint64_t c_rt_ctx;
+
+ /* Space to maintain the architectural state of an SP. */
+ cpu_context_t cpu_ctx;
+
+ /* Track the current runtime state of the SP. */
+ enum sp_runtime_states rt_state;
+
+ /* Track the current runtime model of the SP. */
+ enum sp_runtime_model rt_model;
+};
+
+/*
+ * Structure to describe the cumulative properties of an SP.
+ */
+struct secure_partition_desc {
+ /*
+ * Execution contexts allocated to this endpoint. Ideally,
+ * we need as many contexts as there are physical cpus only
+ * for a S-EL1 SP which is MP-pinned.
+ */
+ struct sp_exec_ctx ec[PLATFORM_CORE_COUNT];
+
+ /* ID of the Secure Partition. */
+ uint16_t sp_id;
+
+ /* Runtime EL. */
+ enum sp_runtime_el runtime_el;
+
+ /* Partition UUID. */
+ uint32_t uuid[4];
+
+ /* Partition Properties. */
+ uint32_t properties;
+
+ /* Supported FF-A Version. */
+ uint32_t ffa_version;
+
+ /* Execution State. */
+ enum sp_execution_state execution_state;
+
+ /* Mailbox tracking. */
+ struct mailbox mailbox;
+
+ /* Secondary entrypoint. Only valid for a S-EL1 SP. */
+ uintptr_t secondary_ep;
+
+ /*
+ * Store whether the SP has subscribed to any power management messages.
+ */
+ uint16_t pwr_mgmt_msgs;
+
+ /*
+ * Store whether the SP has requested the use of the NS bit for memory
+ * management transactions if it is using FF-A v1.0.
+ */
+ bool ns_bit_requested;
+};
+
+/*
+ * This define identifies the only SP that will be initialised and participate
+ * in FF-A communication. The implementation leaves the door open for more SPs
+ * to be managed in future but for now it is reasonable to assume that either a
+ * single S-EL0 or a single S-EL1 SP will be supported. This define will be used
+ * to identify which SP descriptor to initialise and manage during SP runtime.
+ */
+#define ACTIVE_SP_DESC_INDEX 0
+
+/*
+ * Structure to describe the cumulative properties of the Hypervisor and
+ * NS-Endpoints.
+ */
+struct ns_endpoint_desc {
+ /*
+ * ID of the NS-Endpoint or Hypervisor.
+ */
+ uint16_t ns_ep_id;
+
+ /*
+ * Mailbox tracking.
+ */
+ struct mailbox mailbox;
+
+ /*
+ * Supported FF-A Version
+ */
+ uint32_t ffa_version;
+};
+
+/**
+ * Holds information returned for each partition by the FFA_PARTITION_INFO_GET
+ * interface.
+ */
+struct ffa_partition_info_v1_0 {
+ uint16_t ep_id;
+ uint16_t execution_ctx_count;
+ uint32_t properties;
+};
+
+/* Extended structure for v1.1. */
+struct ffa_partition_info_v1_1 {
+ uint16_t ep_id;
+ uint16_t execution_ctx_count;
+ uint32_t properties;
+ uint32_t uuid[4];
+};
+
+/* Reference to power management hooks */
+extern const spd_pm_ops_t spmc_pm;
+
+/* Setup Function for different SP types. */
+void spmc_sp_common_setup(struct secure_partition_desc *sp,
+ entry_point_info_t *ep_info,
+ int32_t boot_info_reg);
+void spmc_el1_sp_setup(struct secure_partition_desc *sp,
+ entry_point_info_t *ep_info);
+void spmc_sp_common_ep_commit(struct secure_partition_desc *sp,
+ entry_point_info_t *ep_info);
+
+/*
+ * Helper function to perform a synchronous entry into a SP.
+ */
+uint64_t spmc_sp_synchronous_entry(struct sp_exec_ctx *ec);
+
+/*
+ * Helper function to obtain the descriptor of the current SP on a physical cpu.
+ */
+struct secure_partition_desc *spmc_get_current_sp_ctx(void);
+
+/*
+ * Helper function to obtain the execution context of an SP on a
+ * physical cpu.
+ */
+struct sp_exec_ctx *spmc_get_sp_ec(struct secure_partition_desc *sp);
+
+/*
+ * Helper function to obtain the index of the execution context of an SP on a
+ * physical cpu.
+ */
+unsigned int get_ec_index(struct secure_partition_desc *sp);
+
+uint64_t spmc_ffa_error_return(void *handle, int error_code);
+
+/*
+ * Ensure a partition ID does not clash and follows the secure world convention.
+ */
+bool is_ffa_secure_id_valid(uint16_t partition_id);
+
+/*
+ * Helper function to obtain the array storing the EL3
+ * Logical Partition descriptors.
+ */
+struct el3_lp_desc *get_el3_lp_array(void);
+
+/*
+ * Helper function to obtain the RX/TX buffer pair descriptor of the Hypervisor
+ * or OS kernel in the normal world or the last SP that was run.
+ */
+struct mailbox *spmc_get_mbox_desc(bool secure_origin);
+
+/*
+ * Helper function to obtain the context of an SP with a given partition ID.
+ */
+struct secure_partition_desc *spmc_get_sp_ctx(uint16_t id);
+
+/*
+ * Add helper function to obtain the FF-A version of the calling
+ * partition.
+ */
+uint32_t get_partition_ffa_version(bool secure_origin);
+
+
+#endif /* SPMC_H */
diff --git a/services/std_svc/spm/el3_spmc/spmc.mk b/services/std_svc/spm/el3_spmc/spmc.mk
new file mode 100644
index 0000000..c674e71
--- /dev/null
+++ b/services/std_svc/spm/el3_spmc/spmc.mk
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifneq (${ARCH},aarch64)
+ $(error "Error: SPMC is only supported on aarch64.")
+endif
+
+SPMC_SOURCES := $(addprefix services/std_svc/spm/el3_spmc/, \
+ spmc_main.c \
+ spmc_setup.c \
+ logical_sp.c \
+ spmc_pm.c \
+ spmc_shared_mem.c)
+
+# Specify platform specific logical partition implementation.
+SPMC_LP_SOURCES := $(addprefix ${PLAT_DIR}/, \
+ ${PLAT}_el3_spmc_logical_sp.c)
+
+
+SPMC_SOURCES += $(SPMC_LP_SOURCES)
+
+# Let the top-level Makefile know that we intend to include a BL32 image
+NEED_BL32 := yes
+
+ifndef BL32
+# The SPMC is paired with a Test Secure Payload source and we intend to
+# build the Test Secure Payload if no other image has been provided
+# for BL32.
+#
+# In cases where an associated Secure Payload lies outside this build
+# system/source tree, the dispatcher Makefile can either invoke an external
+# build command or assume it is pre-built.
+
+BL32_ROOT := bl32/tsp
+
+# Conditionally 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
+endif
diff --git a/services/std_svc/spm/el3_spmc/spmc_main.c b/services/std_svc/spm/el3_spmc/spmc_main.c
new file mode 100644
index 0000000..9b8621a
--- /dev/null
+++ b/services/std_svc/spm/el3_spmc/spmc_main.c
@@ -0,0 +1,1995 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <bl31/ehf.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <common/runtime_svc.h>
+#include <common/uuid.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/smccc.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <libfdt.h>
+#include <plat/common/platform.h>
+#include <services/el3_spmc_logical_sp.h>
+#include <services/ffa_svc.h>
+#include <services/spmc_svc.h>
+#include <services/spmd_svc.h>
+#include "spmc.h"
+#include "spmc_shared_mem.h"
+
+#include <platform_def.h>
+
+/* Declare the maximum number of SPs and El3 LPs. */
+#define MAX_SP_LP_PARTITIONS SECURE_PARTITION_COUNT + MAX_EL3_LP_DESCS_COUNT
+
+/*
+ * Allocate a secure partition descriptor to describe each SP in the system that
+ * does not reside at EL3.
+ */
+static struct secure_partition_desc sp_desc[SECURE_PARTITION_COUNT];
+
+/*
+ * Allocate an NS endpoint descriptor to describe each VM and the Hypervisor in
+ * the system that interacts with a SP. It is used to track the Hypervisor
+ * buffer pair, version and ID for now. It could be extended to track VM
+ * properties when the SPMC supports indirect messaging.
+ */
+static struct ns_endpoint_desc ns_ep_desc[NS_PARTITION_COUNT];
+
+static uint64_t spmc_sp_interrupt_handler(uint32_t id,
+ uint32_t flags,
+ void *handle,
+ void *cookie);
+
+/*
+ * Helper function to obtain the array storing the EL3
+ * Logical Partition descriptors.
+ */
+struct el3_lp_desc *get_el3_lp_array(void)
+{
+ return (struct el3_lp_desc *) EL3_LP_DESCS_START;
+}
+
+/*
+ * Helper function to obtain the descriptor of the last SP to whom control was
+ * handed to on this physical cpu. Currently, we assume there is only one SP.
+ * TODO: Expand to track multiple partitions when required.
+ */
+struct secure_partition_desc *spmc_get_current_sp_ctx(void)
+{
+ return &(sp_desc[ACTIVE_SP_DESC_INDEX]);
+}
+
+/*
+ * Helper function to obtain the execution context of an SP on the
+ * current physical cpu.
+ */
+struct sp_exec_ctx *spmc_get_sp_ec(struct secure_partition_desc *sp)
+{
+ return &(sp->ec[get_ec_index(sp)]);
+}
+
+/* Helper function to get pointer to SP context from its ID. */
+struct secure_partition_desc *spmc_get_sp_ctx(uint16_t id)
+{
+ /* Check for Secure World Partitions. */
+ for (unsigned int i = 0U; i < SECURE_PARTITION_COUNT; i++) {
+ if (sp_desc[i].sp_id == id) {
+ return &(sp_desc[i]);
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Helper function to obtain the descriptor of the Hypervisor or OS kernel.
+ * We assume that the first descriptor is reserved for this entity.
+ */
+struct ns_endpoint_desc *spmc_get_hyp_ctx(void)
+{
+ return &(ns_ep_desc[0]);
+}
+
+/*
+ * Helper function to obtain the RX/TX buffer pair descriptor of the Hypervisor
+ * or OS kernel in the normal world or the last SP that was run.
+ */
+struct mailbox *spmc_get_mbox_desc(bool secure_origin)
+{
+ /* Obtain the RX/TX buffer pair descriptor. */
+ if (secure_origin) {
+ return &(spmc_get_current_sp_ctx()->mailbox);
+ } else {
+ return &(spmc_get_hyp_ctx()->mailbox);
+ }
+}
+
+/******************************************************************************
+ * This function returns to the place where spmc_sp_synchronous_entry() was
+ * called originally.
+ ******************************************************************************/
+__dead2 void spmc_sp_synchronous_exit(struct sp_exec_ctx *ec, uint64_t rc)
+{
+ /*
+ * 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(ec->c_rt_ctx, rc);
+
+ panic();
+}
+
+/*******************************************************************************
+ * Return FFA_ERROR with specified error code.
+ ******************************************************************************/
+uint64_t spmc_ffa_error_return(void *handle, int error_code)
+{
+ SMC_RET8(handle, FFA_ERROR,
+ FFA_TARGET_INFO_MBZ, error_code,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ);
+}
+
+/******************************************************************************
+ * Helper function to validate a secure partition ID to ensure it does not
+ * conflict with any other FF-A component and follows the convention to
+ * indicate it resides within the secure world.
+ ******************************************************************************/
+bool is_ffa_secure_id_valid(uint16_t partition_id)
+{
+ struct el3_lp_desc *el3_lp_descs = get_el3_lp_array();
+
+ /* Ensure the ID is not the invalid partition ID. */
+ if (partition_id == INV_SP_ID) {
+ return false;
+ }
+
+ /* Ensure the ID is not the SPMD ID. */
+ if (partition_id == SPMD_DIRECT_MSG_ENDPOINT_ID) {
+ return false;
+ }
+
+ /*
+ * Ensure the ID follows the convention to indicate it resides
+ * in the secure world.
+ */
+ if (!ffa_is_secure_world_id(partition_id)) {
+ return false;
+ }
+
+ /* Ensure we don't conflict with the SPMC partition ID. */
+ if (partition_id == FFA_SPMC_ID) {
+ return false;
+ }
+
+ /* Ensure we do not already have an SP context with this ID. */
+ if (spmc_get_sp_ctx(partition_id)) {
+ return false;
+ }
+
+ /* Ensure we don't clash with any Logical SP's. */
+ for (unsigned int i = 0U; i < EL3_LP_DESCS_COUNT; i++) {
+ if (el3_lp_descs[i].sp_id == partition_id) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ * This function either forwards the request to the other world or returns
+ * with an ERET depending on the source of the call.
+ * We can assume that the destination is for an entity at a lower exception
+ * level as any messages destined for a logical SP resident in EL3 will have
+ * already been taken care of by the SPMC before entering this function.
+ ******************************************************************************/
+static uint64_t spmc_smc_return(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *handle,
+ void *cookie,
+ uint64_t flags,
+ uint16_t dst_id)
+{
+ /* If the destination is in the normal world always go via the SPMD. */
+ if (ffa_is_normal_world_id(dst_id)) {
+ return spmd_smc_handler(smc_fid, x1, x2, x3, x4,
+ cookie, handle, flags);
+ }
+ /*
+ * If the caller is secure and we want to return to the secure world,
+ * ERET directly.
+ */
+ else if (secure_origin && ffa_is_secure_world_id(dst_id)) {
+ SMC_RET5(handle, smc_fid, x1, x2, x3, x4);
+ }
+ /* If we originated in the normal world then switch contexts. */
+ else if (!secure_origin && ffa_is_secure_world_id(dst_id)) {
+ return spmd_smc_switch_state(smc_fid, secure_origin, x1, x2,
+ x3, x4, handle);
+ } else {
+ /* Unknown State. */
+ panic();
+ }
+
+ /* Shouldn't be Reached. */
+ return 0;
+}
+
+/*******************************************************************************
+ * FF-A ABI Handlers.
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Helper function to validate arg2 as part of a direct message.
+ ******************************************************************************/
+static inline bool direct_msg_validate_arg2(uint64_t x2)
+{
+ /* Check message type. */
+ if (x2 & FFA_FWK_MSG_BIT) {
+ /* We have a framework message, ensure it is a known message. */
+ if (x2 & ~(FFA_FWK_MSG_MASK | FFA_FWK_MSG_BIT)) {
+ VERBOSE("Invalid message format 0x%lx.\n", x2);
+ return false;
+ }
+ } else {
+ /* We have a partition messages, ensure x2 is not set. */
+ if (x2 != (uint64_t) 0) {
+ VERBOSE("Arg2 MBZ for partition messages. (0x%lx).\n",
+ x2);
+ return false;
+ }
+ }
+ return true;
+}
+
+/*******************************************************************************
+ * Handle direct request messages and route to the appropriate destination.
+ ******************************************************************************/
+static uint64_t direct_req_smc_handler(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ uint16_t dst_id = ffa_endpoint_destination(x1);
+ struct el3_lp_desc *el3_lp_descs;
+ struct secure_partition_desc *sp;
+ unsigned int idx;
+
+ /* Check if arg2 has been populated correctly based on message type. */
+ if (!direct_msg_validate_arg2(x2)) {
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ el3_lp_descs = get_el3_lp_array();
+
+ /* Check if the request is destined for a Logical Partition. */
+ for (unsigned int i = 0U; i < MAX_EL3_LP_DESCS_COUNT; i++) {
+ if (el3_lp_descs[i].sp_id == dst_id) {
+ return el3_lp_descs[i].direct_req(
+ smc_fid, secure_origin, x1, x2, x3, x4,
+ cookie, handle, flags);
+ }
+ }
+
+ /*
+ * If the request was not targeted to a LSP and from the secure world
+ * then it is invalid since a SP cannot call into the Normal world and
+ * there is no other SP to call into. If there are other SPs in future
+ * then the partition runtime model would need to be validated as well.
+ */
+ if (secure_origin) {
+ VERBOSE("Direct request not supported to the Normal World.\n");
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ /* Check if the SP ID is valid. */
+ sp = spmc_get_sp_ctx(dst_id);
+ if (sp == NULL) {
+ VERBOSE("Direct request to unknown partition ID (0x%x).\n",
+ dst_id);
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ /*
+ * Check that the target execution context is in a waiting state before
+ * forwarding the direct request to it.
+ */
+ idx = get_ec_index(sp);
+ if (sp->ec[idx].rt_state != RT_STATE_WAITING) {
+ VERBOSE("SP context on core%u is not waiting (%u).\n",
+ idx, sp->ec[idx].rt_model);
+ return spmc_ffa_error_return(handle, FFA_ERROR_BUSY);
+ }
+
+ /*
+ * Everything checks out so forward the request to the SP after updating
+ * its state and runtime model.
+ */
+ sp->ec[idx].rt_state = RT_STATE_RUNNING;
+ sp->ec[idx].rt_model = RT_MODEL_DIR_REQ;
+ return spmc_smc_return(smc_fid, secure_origin, x1, x2, x3, x4,
+ handle, cookie, flags, dst_id);
+}
+
+/*******************************************************************************
+ * Handle direct response messages and route to the appropriate destination.
+ ******************************************************************************/
+static uint64_t direct_resp_smc_handler(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ uint16_t dst_id = ffa_endpoint_destination(x1);
+ struct secure_partition_desc *sp;
+ unsigned int idx;
+
+ /* Check if arg2 has been populated correctly based on message type. */
+ if (!direct_msg_validate_arg2(x2)) {
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ /* Check that the response did not originate from the Normal world. */
+ if (!secure_origin) {
+ VERBOSE("Direct Response not supported from Normal World.\n");
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ /*
+ * Check that the response is either targeted to the Normal world or the
+ * SPMC e.g. a PM response.
+ */
+ if ((dst_id != FFA_SPMC_ID) && ffa_is_secure_world_id(dst_id)) {
+ VERBOSE("Direct response to invalid partition ID (0x%x).\n",
+ dst_id);
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ /* Obtain the SP descriptor and update its runtime state. */
+ sp = spmc_get_sp_ctx(ffa_endpoint_source(x1));
+ if (sp == NULL) {
+ VERBOSE("Direct response to unknown partition ID (0x%x).\n",
+ dst_id);
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ /* Sanity check state is being tracked correctly in the SPMC. */
+ idx = get_ec_index(sp);
+ assert(sp->ec[idx].rt_state == RT_STATE_RUNNING);
+
+ /* Ensure SP execution context was in the right runtime model. */
+ if (sp->ec[idx].rt_model != RT_MODEL_DIR_REQ) {
+ VERBOSE("SP context on core%u not handling direct req (%u).\n",
+ idx, sp->ec[idx].rt_model);
+ return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
+ }
+
+ /* Update the state of the SP execution context. */
+ sp->ec[idx].rt_state = RT_STATE_WAITING;
+
+ /*
+ * If the receiver is not the SPMC then forward the response to the
+ * Normal world.
+ */
+ if (dst_id == FFA_SPMC_ID) {
+ spmc_sp_synchronous_exit(&sp->ec[idx], x4);
+ /* Should not get here. */
+ panic();
+ }
+
+ return spmc_smc_return(smc_fid, secure_origin, x1, x2, x3, x4,
+ handle, cookie, flags, dst_id);
+}
+
+/*******************************************************************************
+ * This function handles the FFA_MSG_WAIT SMC to allow an SP to relinquish its
+ * cycles.
+ ******************************************************************************/
+static uint64_t msg_wait_handler(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ struct secure_partition_desc *sp;
+ unsigned int idx;
+
+ /*
+ * Check that the response did not originate from the Normal world as
+ * only the secure world can call this ABI.
+ */
+ if (!secure_origin) {
+ VERBOSE("Normal world cannot call FFA_MSG_WAIT.\n");
+ return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
+ }
+
+ /* Get the descriptor of the SP that invoked FFA_MSG_WAIT. */
+ sp = spmc_get_current_sp_ctx();
+ if (sp == NULL) {
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ /*
+ * Get the execution context of the SP that invoked FFA_MSG_WAIT.
+ */
+ idx = get_ec_index(sp);
+
+ /* Ensure SP execution context was in the right runtime model. */
+ if (sp->ec[idx].rt_model == RT_MODEL_DIR_REQ) {
+ return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
+ }
+
+ /* Sanity check the state is being tracked correctly in the SPMC. */
+ assert(sp->ec[idx].rt_state == RT_STATE_RUNNING);
+
+ /*
+ * Perform a synchronous exit if the partition was initialising. The
+ * state is updated after the exit.
+ */
+ if (sp->ec[idx].rt_model == RT_MODEL_INIT) {
+ spmc_sp_synchronous_exit(&sp->ec[idx], x4);
+ /* Should not get here */
+ panic();
+ }
+
+ /* Update the state of the SP execution context. */
+ sp->ec[idx].rt_state = RT_STATE_WAITING;
+
+ /* Resume normal world if a secure interrupt was handled. */
+ if (sp->ec[idx].rt_model == RT_MODEL_INTR) {
+ /* FFA_MSG_WAIT can only be called from the secure world. */
+ unsigned int secure_state_in = SECURE;
+ unsigned int secure_state_out = NON_SECURE;
+
+ cm_el1_sysregs_context_save(secure_state_in);
+ cm_el1_sysregs_context_restore(secure_state_out);
+ cm_set_next_eret_context(secure_state_out);
+ SMC_RET0(cm_get_context(secure_state_out));
+ }
+
+ /* Forward the response to the Normal world. */
+ return spmc_smc_return(smc_fid, secure_origin, x1, x2, x3, x4,
+ handle, cookie, flags, FFA_NWD_ID);
+}
+
+static uint64_t ffa_error_handler(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ struct secure_partition_desc *sp;
+ unsigned int idx;
+
+ /* Check that the response did not originate from the Normal world. */
+ if (!secure_origin) {
+ return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
+ }
+
+ /* Get the descriptor of the SP that invoked FFA_ERROR. */
+ sp = spmc_get_current_sp_ctx();
+ if (sp == NULL) {
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ /* Get the execution context of the SP that invoked FFA_ERROR. */
+ idx = get_ec_index(sp);
+
+ /*
+ * We only expect FFA_ERROR to be received during SP initialisation
+ * otherwise this is an invalid call.
+ */
+ if (sp->ec[idx].rt_model == RT_MODEL_INIT) {
+ ERROR("SP 0x%x failed to initialize.\n", sp->sp_id);
+ spmc_sp_synchronous_exit(&sp->ec[idx], x2);
+ /* Should not get here. */
+ panic();
+ }
+
+ return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
+}
+
+static uint64_t ffa_version_handler(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ uint32_t requested_version = x1 & FFA_VERSION_MASK;
+
+ if (requested_version & FFA_VERSION_BIT31_MASK) {
+ /* Invalid encoding, return an error. */
+ SMC_RET1(handle, FFA_ERROR_NOT_SUPPORTED);
+ /* Execution stops here. */
+ }
+
+ /* Determine the caller to store the requested version. */
+ if (secure_origin) {
+ /*
+ * Ensure that the SP is reporting the same version as
+ * specified in its manifest. If these do not match there is
+ * something wrong with the SP.
+ * TODO: Should we abort the SP? For now assert this is not
+ * case.
+ */
+ assert(requested_version ==
+ spmc_get_current_sp_ctx()->ffa_version);
+ } else {
+ /*
+ * If this is called by the normal world, record this
+ * information in its descriptor.
+ */
+ spmc_get_hyp_ctx()->ffa_version = requested_version;
+ }
+
+ SMC_RET1(handle, MAKE_FFA_VERSION(FFA_VERSION_MAJOR,
+ FFA_VERSION_MINOR));
+}
+
+/*******************************************************************************
+ * Helper function to obtain the FF-A version of the calling partition.
+ ******************************************************************************/
+uint32_t get_partition_ffa_version(bool secure_origin)
+{
+ if (secure_origin) {
+ return spmc_get_current_sp_ctx()->ffa_version;
+ } else {
+ return spmc_get_hyp_ctx()->ffa_version;
+ }
+}
+
+static uint64_t rxtx_map_handler(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ int ret;
+ uint32_t error_code;
+ uint32_t mem_atts = secure_origin ? MT_SECURE : MT_NS;
+ struct mailbox *mbox;
+ uintptr_t tx_address = x1;
+ uintptr_t rx_address = x2;
+ uint32_t page_count = x3 & FFA_RXTX_PAGE_COUNT_MASK; /* Bits [5:0] */
+ uint32_t buf_size = page_count * FFA_PAGE_SIZE;
+
+ /*
+ * The SPMC does not support mapping of VM RX/TX pairs to facilitate
+ * indirect messaging with SPs. Check if the Hypervisor has invoked this
+ * ABI on behalf of a VM and reject it if this is the case.
+ */
+ if (tx_address == 0 || rx_address == 0) {
+ WARN("Mapping RX/TX Buffers on behalf of VM not supported.\n");
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ /* Ensure the specified buffers are not the same. */
+ if (tx_address == rx_address) {
+ WARN("TX Buffer must not be the same as RX Buffer.\n");
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ /* Ensure the buffer size is not 0. */
+ if (buf_size == 0U) {
+ WARN("Buffer size must not be 0\n");
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ /*
+ * Ensure the buffer size is a multiple of the translation granule size
+ * in TF-A.
+ */
+ if (buf_size % PAGE_SIZE != 0U) {
+ WARN("Buffer size must be aligned to translation granule.\n");
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ /* Obtain the RX/TX buffer pair descriptor. */
+ mbox = spmc_get_mbox_desc(secure_origin);
+
+ spin_lock(&mbox->lock);
+
+ /* Check if buffers have already been mapped. */
+ if (mbox->rx_buffer != 0 || mbox->tx_buffer != 0) {
+ WARN("RX/TX Buffers already mapped (%p/%p)\n",
+ (void *) mbox->rx_buffer, (void *)mbox->tx_buffer);
+ error_code = FFA_ERROR_DENIED;
+ goto err;
+ }
+
+ /* memmap the TX buffer as read only. */
+ ret = mmap_add_dynamic_region(tx_address, /* PA */
+ tx_address, /* VA */
+ buf_size, /* size */
+ mem_atts | MT_RO_DATA); /* attrs */
+ if (ret != 0) {
+ /* Return the correct error code. */
+ error_code = (ret == -ENOMEM) ? FFA_ERROR_NO_MEMORY :
+ FFA_ERROR_INVALID_PARAMETER;
+ WARN("Unable to map TX buffer: %d\n", error_code);
+ goto err;
+ }
+
+ /* memmap the RX buffer as read write. */
+ ret = mmap_add_dynamic_region(rx_address, /* PA */
+ rx_address, /* VA */
+ buf_size, /* size */
+ mem_atts | MT_RW_DATA); /* attrs */
+
+ if (ret != 0) {
+ error_code = (ret == -ENOMEM) ? FFA_ERROR_NO_MEMORY :
+ FFA_ERROR_INVALID_PARAMETER;
+ WARN("Unable to map RX buffer: %d\n", error_code);
+ /* Unmap the TX buffer again. */
+ mmap_remove_dynamic_region(tx_address, buf_size);
+ goto err;
+ }
+
+ mbox->tx_buffer = (void *) tx_address;
+ mbox->rx_buffer = (void *) rx_address;
+ mbox->rxtx_page_count = page_count;
+ spin_unlock(&mbox->lock);
+
+ SMC_RET1(handle, FFA_SUCCESS_SMC32);
+ /* Execution stops here. */
+err:
+ spin_unlock(&mbox->lock);
+ return spmc_ffa_error_return(handle, error_code);
+}
+
+static uint64_t rxtx_unmap_handler(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ struct mailbox *mbox = spmc_get_mbox_desc(secure_origin);
+ uint32_t buf_size = mbox->rxtx_page_count * FFA_PAGE_SIZE;
+
+ /*
+ * The SPMC does not support mapping of VM RX/TX pairs to facilitate
+ * indirect messaging with SPs. Check if the Hypervisor has invoked this
+ * ABI on behalf of a VM and reject it if this is the case.
+ */
+ if (x1 != 0UL) {
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ spin_lock(&mbox->lock);
+
+ /* Check if buffers are currently mapped. */
+ if (mbox->rx_buffer == 0 || mbox->tx_buffer == 0) {
+ spin_unlock(&mbox->lock);
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ /* Unmap RX Buffer */
+ if (mmap_remove_dynamic_region((uintptr_t) mbox->rx_buffer,
+ buf_size) != 0) {
+ WARN("Unable to unmap RX buffer!\n");
+ }
+
+ mbox->rx_buffer = 0;
+
+ /* Unmap TX Buffer */
+ if (mmap_remove_dynamic_region((uintptr_t) mbox->tx_buffer,
+ buf_size) != 0) {
+ WARN("Unable to unmap TX buffer!\n");
+ }
+
+ mbox->tx_buffer = 0;
+ mbox->rxtx_page_count = 0;
+
+ spin_unlock(&mbox->lock);
+ SMC_RET1(handle, FFA_SUCCESS_SMC32);
+}
+
+/*
+ * Collate the partition information in a v1.1 partition information
+ * descriptor format, this will be converter later if required.
+ */
+static int partition_info_get_handler_v1_1(uint32_t *uuid,
+ struct ffa_partition_info_v1_1
+ *partitions,
+ uint32_t max_partitions,
+ uint32_t *partition_count)
+{
+ uint32_t index;
+ struct ffa_partition_info_v1_1 *desc;
+ bool null_uuid = is_null_uuid(uuid);
+ struct el3_lp_desc *el3_lp_descs = get_el3_lp_array();
+
+ /* Deal with Logical Partitions. */
+ for (index = 0U; index < EL3_LP_DESCS_COUNT; index++) {
+ if (null_uuid || uuid_match(uuid, el3_lp_descs[index].uuid)) {
+ /* Found a matching UUID, populate appropriately. */
+ if (*partition_count >= max_partitions) {
+ return FFA_ERROR_NO_MEMORY;
+ }
+
+ desc = &partitions[*partition_count];
+ desc->ep_id = el3_lp_descs[index].sp_id;
+ desc->execution_ctx_count = PLATFORM_CORE_COUNT;
+ desc->properties = el3_lp_descs[index].properties;
+ if (null_uuid) {
+ copy_uuid(desc->uuid, el3_lp_descs[index].uuid);
+ }
+ (*partition_count)++;
+ }
+ }
+
+ /* Deal with physical SP's. */
+ for (index = 0U; index < SECURE_PARTITION_COUNT; index++) {
+ if (null_uuid || uuid_match(uuid, sp_desc[index].uuid)) {
+ /* Found a matching UUID, populate appropriately. */
+ if (*partition_count >= max_partitions) {
+ return FFA_ERROR_NO_MEMORY;
+ }
+
+ desc = &partitions[*partition_count];
+ desc->ep_id = sp_desc[index].sp_id;
+ /*
+ * Execution context count must match No. cores for
+ * S-EL1 SPs.
+ */
+ desc->execution_ctx_count = PLATFORM_CORE_COUNT;
+ desc->properties = sp_desc[index].properties;
+ if (null_uuid) {
+ copy_uuid(desc->uuid, sp_desc[index].uuid);
+ }
+ (*partition_count)++;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Handle the case where that caller only wants the count of partitions
+ * matching a given UUID and does not want the corresponding descriptors
+ * populated.
+ */
+static uint32_t partition_info_get_handler_count_only(uint32_t *uuid)
+{
+ uint32_t index = 0;
+ uint32_t partition_count = 0;
+ bool null_uuid = is_null_uuid(uuid);
+ struct el3_lp_desc *el3_lp_descs = get_el3_lp_array();
+
+ /* Deal with Logical Partitions. */
+ for (index = 0U; index < EL3_LP_DESCS_COUNT; index++) {
+ if (null_uuid ||
+ uuid_match(uuid, el3_lp_descs[index].uuid)) {
+ (partition_count)++;
+ }
+ }
+
+ /* Deal with physical SP's. */
+ for (index = 0U; index < SECURE_PARTITION_COUNT; index++) {
+ if (null_uuid || uuid_match(uuid, sp_desc[index].uuid)) {
+ (partition_count)++;
+ }
+ }
+ return partition_count;
+}
+
+/*
+ * If the caller of the PARTITION_INFO_GET ABI was a v1.0 caller, populate
+ * the coresponding descriptor format from the v1.1 descriptor array.
+ */
+static uint64_t partition_info_populate_v1_0(struct ffa_partition_info_v1_1
+ *partitions,
+ struct mailbox *mbox,
+ int partition_count)
+{
+ uint32_t index;
+ uint32_t buf_size;
+ uint32_t descriptor_size;
+ struct ffa_partition_info_v1_0 *v1_0_partitions =
+ (struct ffa_partition_info_v1_0 *) mbox->rx_buffer;
+
+ buf_size = mbox->rxtx_page_count * FFA_PAGE_SIZE;
+ descriptor_size = partition_count *
+ sizeof(struct ffa_partition_info_v1_0);
+
+ if (descriptor_size > buf_size) {
+ return FFA_ERROR_NO_MEMORY;
+ }
+
+ for (index = 0U; index < partition_count; index++) {
+ v1_0_partitions[index].ep_id = partitions[index].ep_id;
+ v1_0_partitions[index].execution_ctx_count =
+ partitions[index].execution_ctx_count;
+ v1_0_partitions[index].properties =
+ partitions[index].properties;
+ }
+ return 0;
+}
+
+/*
+ * Main handler for FFA_PARTITION_INFO_GET which supports both FF-A v1.1 and
+ * v1.0 implementations.
+ */
+static uint64_t partition_info_get_handler(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ int ret;
+ uint32_t partition_count = 0;
+ uint32_t size = 0;
+ uint32_t ffa_version = get_partition_ffa_version(secure_origin);
+ struct mailbox *mbox;
+ uint64_t info_get_flags;
+ bool count_only;
+ uint32_t uuid[4];
+
+ uuid[0] = x1;
+ uuid[1] = x2;
+ uuid[2] = x3;
+ uuid[3] = x4;
+
+ /* Determine if the Partition descriptors should be populated. */
+ info_get_flags = SMC_GET_GP(handle, CTX_GPREG_X5);
+ count_only = (info_get_flags & FFA_PARTITION_INFO_GET_COUNT_FLAG_MASK);
+
+ /* Handle the case where we don't need to populate the descriptors. */
+ if (count_only) {
+ partition_count = partition_info_get_handler_count_only(uuid);
+ if (partition_count == 0) {
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+ } else {
+ struct ffa_partition_info_v1_1 partitions[MAX_SP_LP_PARTITIONS];
+
+ /*
+ * Handle the case where the partition descriptors are required,
+ * check we have the buffers available and populate the
+ * appropriate structure version.
+ */
+
+ /* Obtain the v1.1 format of the descriptors. */
+ ret = partition_info_get_handler_v1_1(uuid, partitions,
+ MAX_SP_LP_PARTITIONS,
+ &partition_count);
+
+ /* Check if an error occurred during discovery. */
+ if (ret != 0) {
+ goto err;
+ }
+
+ /* If we didn't find any matches the UUID is unknown. */
+ if (partition_count == 0) {
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err;
+ }
+
+ /* Obtain the partition mailbox RX/TX buffer pair descriptor. */
+ mbox = spmc_get_mbox_desc(secure_origin);
+
+ /*
+ * If the caller has not bothered registering its RX/TX pair
+ * then return an error code.
+ */
+ spin_lock(&mbox->lock);
+ if (mbox->rx_buffer == NULL) {
+ ret = FFA_ERROR_BUSY;
+ goto err_unlock;
+ }
+
+ /* Ensure the RX buffer is currently free. */
+ if (mbox->state != MAILBOX_STATE_EMPTY) {
+ ret = FFA_ERROR_BUSY;
+ goto err_unlock;
+ }
+
+ /* Zero the RX buffer before populating. */
+ (void)memset(mbox->rx_buffer, 0,
+ mbox->rxtx_page_count * FFA_PAGE_SIZE);
+
+ /*
+ * Depending on the FF-A version of the requesting partition
+ * we may need to convert to a v1.0 format otherwise we can copy
+ * directly.
+ */
+ if (ffa_version == MAKE_FFA_VERSION(U(1), U(0))) {
+ ret = partition_info_populate_v1_0(partitions,
+ mbox,
+ partition_count);
+ if (ret != 0) {
+ goto err_unlock;
+ }
+ } else {
+ uint32_t buf_size = mbox->rxtx_page_count *
+ FFA_PAGE_SIZE;
+
+ /* Ensure the descriptor will fit in the buffer. */
+ size = sizeof(struct ffa_partition_info_v1_1);
+ if (partition_count * size > buf_size) {
+ ret = FFA_ERROR_NO_MEMORY;
+ goto err_unlock;
+ }
+ memcpy(mbox->rx_buffer, partitions,
+ partition_count * size);
+ }
+
+ mbox->state = MAILBOX_STATE_FULL;
+ spin_unlock(&mbox->lock);
+ }
+ SMC_RET4(handle, FFA_SUCCESS_SMC32, 0, partition_count, size);
+
+err_unlock:
+ spin_unlock(&mbox->lock);
+err:
+ return spmc_ffa_error_return(handle, ret);
+}
+
+static uint64_t ffa_feature_success(void *handle, uint32_t arg2)
+{
+ SMC_RET3(handle, FFA_SUCCESS_SMC32, 0, arg2);
+}
+
+static uint64_t ffa_features_retrieve_request(bool secure_origin,
+ uint32_t input_properties,
+ void *handle)
+{
+ /*
+ * If we're called by the normal world we don't support any
+ * additional features.
+ */
+ if (!secure_origin) {
+ if ((input_properties & FFA_FEATURES_RET_REQ_NS_BIT) != 0U) {
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_NOT_SUPPORTED);
+ }
+
+ } else {
+ struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
+ /*
+ * If v1.1 the NS bit must be set otherwise it is an invalid
+ * call. If v1.0 check and store whether the SP has requested
+ * the use of the NS bit.
+ */
+ if (sp->ffa_version == MAKE_FFA_VERSION(1, 1)) {
+ if ((input_properties &
+ FFA_FEATURES_RET_REQ_NS_BIT) == 0U) {
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_NOT_SUPPORTED);
+ }
+ return ffa_feature_success(handle,
+ FFA_FEATURES_RET_REQ_NS_BIT);
+ } else {
+ sp->ns_bit_requested = (input_properties &
+ FFA_FEATURES_RET_REQ_NS_BIT) !=
+ 0U;
+ }
+ if (sp->ns_bit_requested) {
+ return ffa_feature_success(handle,
+ FFA_FEATURES_RET_REQ_NS_BIT);
+ }
+ }
+ SMC_RET1(handle, FFA_SUCCESS_SMC32);
+}
+
+static uint64_t ffa_features_handler(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ uint32_t function_id = (uint32_t) x1;
+ uint32_t input_properties = (uint32_t) x2;
+
+ /* Check if a Feature ID was requested. */
+ if ((function_id & FFA_FEATURES_BIT31_MASK) == 0U) {
+ /* We currently don't support any additional features. */
+ return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
+ }
+
+ /*
+ * Handle the cases where we have separate handlers due to additional
+ * properties.
+ */
+ switch (function_id) {
+ case FFA_MEM_RETRIEVE_REQ_SMC32:
+ case FFA_MEM_RETRIEVE_REQ_SMC64:
+ return ffa_features_retrieve_request(secure_origin,
+ input_properties,
+ handle);
+ }
+
+ /*
+ * We don't currently support additional input properties for these
+ * other ABIs therefore ensure this value is set to 0.
+ */
+ if (input_properties != 0U) {
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_NOT_SUPPORTED);
+ }
+
+ /* Report if any other FF-A ABI is supported. */
+ switch (function_id) {
+ /* Supported features from both worlds. */
+ case FFA_ERROR:
+ case FFA_SUCCESS_SMC32:
+ case FFA_INTERRUPT:
+ case FFA_SPM_ID_GET:
+ case FFA_ID_GET:
+ case FFA_FEATURES:
+ case FFA_VERSION:
+ case FFA_RX_RELEASE:
+ case FFA_MSG_SEND_DIRECT_REQ_SMC32:
+ case FFA_MSG_SEND_DIRECT_REQ_SMC64:
+ case FFA_PARTITION_INFO_GET:
+ case FFA_RXTX_MAP_SMC32:
+ case FFA_RXTX_MAP_SMC64:
+ case FFA_RXTX_UNMAP:
+ case FFA_MEM_FRAG_TX:
+ case FFA_MSG_RUN:
+
+ /*
+ * We are relying on the fact that the other registers
+ * will be set to 0 as these values align with the
+ * currently implemented features of the SPMC. If this
+ * changes this function must be extended to handle
+ * reporting the additional functionality.
+ */
+
+ SMC_RET1(handle, FFA_SUCCESS_SMC32);
+ /* Execution stops here. */
+
+ /* Supported ABIs only from the secure world. */
+ case FFA_SECONDARY_EP_REGISTER_SMC64:
+ case FFA_MSG_SEND_DIRECT_RESP_SMC32:
+ case FFA_MSG_SEND_DIRECT_RESP_SMC64:
+ case FFA_MEM_RELINQUISH:
+ case FFA_MSG_WAIT:
+
+ if (!secure_origin) {
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_NOT_SUPPORTED);
+ }
+ SMC_RET1(handle, FFA_SUCCESS_SMC32);
+ /* Execution stops here. */
+
+ /* Supported features only from the normal world. */
+ case FFA_MEM_SHARE_SMC32:
+ case FFA_MEM_SHARE_SMC64:
+ case FFA_MEM_LEND_SMC32:
+ case FFA_MEM_LEND_SMC64:
+ case FFA_MEM_RECLAIM:
+ case FFA_MEM_FRAG_RX:
+
+ if (secure_origin) {
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_NOT_SUPPORTED);
+ }
+ SMC_RET1(handle, FFA_SUCCESS_SMC32);
+ /* Execution stops here. */
+
+ default:
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_NOT_SUPPORTED);
+ }
+}
+
+static uint64_t ffa_id_get_handler(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ if (secure_origin) {
+ SMC_RET3(handle, FFA_SUCCESS_SMC32, 0x0,
+ spmc_get_current_sp_ctx()->sp_id);
+ } else {
+ SMC_RET3(handle, FFA_SUCCESS_SMC32, 0x0,
+ spmc_get_hyp_ctx()->ns_ep_id);
+ }
+}
+
+/*
+ * Enable an SP to query the ID assigned to the SPMC.
+ */
+static uint64_t ffa_spm_id_get_handler(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ assert(x1 == 0UL);
+ assert(x2 == 0UL);
+ assert(x3 == 0UL);
+ assert(x4 == 0UL);
+ assert(SMC_GET_GP(handle, CTX_GPREG_X5) == 0UL);
+ assert(SMC_GET_GP(handle, CTX_GPREG_X6) == 0UL);
+ assert(SMC_GET_GP(handle, CTX_GPREG_X7) == 0UL);
+
+ SMC_RET3(handle, FFA_SUCCESS_SMC32, 0x0, FFA_SPMC_ID);
+}
+
+static uint64_t ffa_run_handler(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ struct secure_partition_desc *sp;
+ uint16_t target_id = FFA_RUN_EP_ID(x1);
+ uint16_t vcpu_id = FFA_RUN_VCPU_ID(x1);
+ unsigned int idx;
+ unsigned int *rt_state;
+ unsigned int *rt_model;
+
+ /* Can only be called from the normal world. */
+ if (secure_origin) {
+ ERROR("FFA_RUN can only be called from NWd.\n");
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ /* Cannot run a Normal world partition. */
+ if (ffa_is_normal_world_id(target_id)) {
+ ERROR("Cannot run a NWd partition (0x%x).\n", target_id);
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ /* Check that the target SP exists. */
+ sp = spmc_get_sp_ctx(target_id);
+ ERROR("Unknown partition ID (0x%x).\n", target_id);
+ if (sp == NULL) {
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ idx = get_ec_index(sp);
+ if (idx != vcpu_id) {
+ ERROR("Cannot run vcpu %d != %d.\n", idx, vcpu_id);
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+ rt_state = &((sp->ec[idx]).rt_state);
+ rt_model = &((sp->ec[idx]).rt_model);
+ if (*rt_state == RT_STATE_RUNNING) {
+ ERROR("Partition (0x%x) is already running.\n", target_id);
+ return spmc_ffa_error_return(handle, FFA_ERROR_BUSY);
+ }
+
+ /*
+ * Sanity check that if the execution context was not waiting then it
+ * was either in the direct request or the run partition runtime model.
+ */
+ if (*rt_state == RT_STATE_PREEMPTED || *rt_state == RT_STATE_BLOCKED) {
+ assert(*rt_model == RT_MODEL_RUN ||
+ *rt_model == RT_MODEL_DIR_REQ);
+ }
+
+ /*
+ * If the context was waiting then update the partition runtime model.
+ */
+ if (*rt_state == RT_STATE_WAITING) {
+ *rt_model = RT_MODEL_RUN;
+ }
+
+ /*
+ * Forward the request to the correct SP vCPU after updating
+ * its state.
+ */
+ *rt_state = RT_STATE_RUNNING;
+
+ return spmc_smc_return(smc_fid, secure_origin, x1, 0, 0, 0,
+ handle, cookie, flags, target_id);
+}
+
+static uint64_t rx_release_handler(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ struct mailbox *mbox = spmc_get_mbox_desc(secure_origin);
+
+ spin_lock(&mbox->lock);
+
+ if (mbox->state != MAILBOX_STATE_FULL) {
+ spin_unlock(&mbox->lock);
+ return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
+ }
+
+ mbox->state = MAILBOX_STATE_EMPTY;
+ spin_unlock(&mbox->lock);
+
+ SMC_RET1(handle, FFA_SUCCESS_SMC32);
+}
+
+/*
+ * Perform initial validation on the provided secondary entry point.
+ * For now ensure it does not lie within the BL31 Image or the SP's
+ * RX/TX buffers as these are mapped within EL3.
+ * TODO: perform validation for additional invalid memory regions.
+ */
+static int validate_secondary_ep(uintptr_t ep, struct secure_partition_desc *sp)
+{
+ struct mailbox *mb;
+ uintptr_t buffer_size;
+ uintptr_t sp_rx_buffer;
+ uintptr_t sp_tx_buffer;
+ uintptr_t sp_rx_buffer_limit;
+ uintptr_t sp_tx_buffer_limit;
+
+ mb = &sp->mailbox;
+ buffer_size = (uintptr_t) (mb->rxtx_page_count * FFA_PAGE_SIZE);
+ sp_rx_buffer = (uintptr_t) mb->rx_buffer;
+ sp_tx_buffer = (uintptr_t) mb->tx_buffer;
+ sp_rx_buffer_limit = sp_rx_buffer + buffer_size;
+ sp_tx_buffer_limit = sp_tx_buffer + buffer_size;
+
+ /*
+ * Check if the entry point lies within BL31, or the
+ * SP's RX or TX buffer.
+ */
+ if ((ep >= BL31_BASE && ep < BL31_LIMIT) ||
+ (ep >= sp_rx_buffer && ep < sp_rx_buffer_limit) ||
+ (ep >= sp_tx_buffer && ep < sp_tx_buffer_limit)) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*******************************************************************************
+ * This function handles the FFA_SECONDARY_EP_REGISTER SMC to allow an SP to
+ * register an entry point for initialization during a secondary cold boot.
+ ******************************************************************************/
+static uint64_t ffa_sec_ep_register_handler(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ struct secure_partition_desc *sp;
+ struct sp_exec_ctx *sp_ctx;
+
+ /* This request cannot originate from the Normal world. */
+ if (!secure_origin) {
+ WARN("%s: Can only be called from SWd.\n", __func__);
+ return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
+ }
+
+ /* Get the context of the current SP. */
+ sp = spmc_get_current_sp_ctx();
+ if (sp == NULL) {
+ WARN("%s: Cannot find SP context.\n", __func__);
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ /* Only an S-EL1 SP should be invoking this ABI. */
+ if (sp->runtime_el != S_EL1) {
+ WARN("%s: Can only be called for a S-EL1 SP.\n", __func__);
+ return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
+ }
+
+ /* Ensure the SP is in its initialization state. */
+ sp_ctx = spmc_get_sp_ec(sp);
+ if (sp_ctx->rt_model != RT_MODEL_INIT) {
+ WARN("%s: Can only be called during SP initialization.\n",
+ __func__);
+ return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
+ }
+
+ /* Perform initial validation of the secondary entry point. */
+ if (validate_secondary_ep(x1, sp)) {
+ WARN("%s: Invalid entry point provided (0x%lx).\n",
+ __func__, x1);
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ /*
+ * Update the secondary entrypoint in SP context.
+ * We don't need a lock here as during partition initialization there
+ * will only be a single core online.
+ */
+ sp->secondary_ep = x1;
+ VERBOSE("%s: 0x%lx\n", __func__, sp->secondary_ep);
+
+ SMC_RET1(handle, FFA_SUCCESS_SMC32);
+}
+
+/*******************************************************************************
+ * This function will parse the Secure Partition Manifest. From manifest, it
+ * will fetch details for preparing Secure partition image context and secure
+ * partition image boot arguments if any.
+ ******************************************************************************/
+static int sp_manifest_parse(void *sp_manifest, int offset,
+ struct secure_partition_desc *sp,
+ entry_point_info_t *ep_info,
+ int32_t *boot_info_reg)
+{
+ int32_t ret, node;
+ uint32_t config_32;
+
+ /*
+ * Look for the mandatory fields that are expected to be present in
+ * the SP manifests.
+ */
+ node = fdt_path_offset(sp_manifest, "/");
+ if (node < 0) {
+ ERROR("Did not find root node.\n");
+ return node;
+ }
+
+ ret = fdt_read_uint32_array(sp_manifest, node, "uuid",
+ ARRAY_SIZE(sp->uuid), sp->uuid);
+ if (ret != 0) {
+ ERROR("Missing Secure Partition UUID.\n");
+ return ret;
+ }
+
+ ret = fdt_read_uint32(sp_manifest, node, "exception-level", &config_32);
+ if (ret != 0) {
+ ERROR("Missing SP Exception Level information.\n");
+ return ret;
+ }
+
+ sp->runtime_el = config_32;
+
+ ret = fdt_read_uint32(sp_manifest, node, "ffa-version", &config_32);
+ if (ret != 0) {
+ ERROR("Missing Secure Partition FF-A Version.\n");
+ return ret;
+ }
+
+ sp->ffa_version = config_32;
+
+ ret = fdt_read_uint32(sp_manifest, node, "execution-state", &config_32);
+ if (ret != 0) {
+ ERROR("Missing Secure Partition Execution State.\n");
+ return ret;
+ }
+
+ sp->execution_state = config_32;
+
+ ret = fdt_read_uint32(sp_manifest, node,
+ "messaging-method", &config_32);
+ if (ret != 0) {
+ ERROR("Missing Secure Partition messaging method.\n");
+ return ret;
+ }
+
+ /* Validate this entry, we currently only support direct messaging. */
+ if ((config_32 & ~(FFA_PARTITION_DIRECT_REQ_RECV |
+ FFA_PARTITION_DIRECT_REQ_SEND)) != 0U) {
+ WARN("Invalid Secure Partition messaging method (0x%x)\n",
+ config_32);
+ return -EINVAL;
+ }
+
+ sp->properties = config_32;
+
+ ret = fdt_read_uint32(sp_manifest, node,
+ "execution-ctx-count", &config_32);
+
+ if (ret != 0) {
+ ERROR("Missing SP Execution Context Count.\n");
+ return ret;
+ }
+
+ /*
+ * Ensure this field is set correctly in the manifest however
+ * since this is currently a hardcoded value for S-EL1 partitions
+ * we don't need to save it here, just validate.
+ */
+ if (config_32 != PLATFORM_CORE_COUNT) {
+ ERROR("SP Execution Context Count (%u) must be %u.\n",
+ config_32, PLATFORM_CORE_COUNT);
+ return -EINVAL;
+ }
+
+ /*
+ * Look for the optional fields that are expected to be present in
+ * an SP manifest.
+ */
+ ret = fdt_read_uint32(sp_manifest, node, "id", &config_32);
+ if (ret != 0) {
+ WARN("Missing Secure Partition ID.\n");
+ } else {
+ if (!is_ffa_secure_id_valid(config_32)) {
+ ERROR("Invalid Secure Partition ID (0x%x).\n",
+ config_32);
+ return -EINVAL;
+ }
+ sp->sp_id = config_32;
+ }
+
+ ret = fdt_read_uint32(sp_manifest, node,
+ "power-management-messages", &config_32);
+ if (ret != 0) {
+ WARN("Missing Power Management Messages entry.\n");
+ } else {
+ /*
+ * Ensure only the currently supported power messages have
+ * been requested.
+ */
+ if (config_32 & ~(FFA_PM_MSG_SUB_CPU_OFF |
+ FFA_PM_MSG_SUB_CPU_SUSPEND |
+ FFA_PM_MSG_SUB_CPU_SUSPEND_RESUME)) {
+ ERROR("Requested unsupported PM messages (%x)\n",
+ config_32);
+ return -EINVAL;
+ }
+ sp->pwr_mgmt_msgs = config_32;
+ }
+
+ ret = fdt_read_uint32(sp_manifest, node,
+ "gp-register-num", &config_32);
+ if (ret != 0) {
+ WARN("Missing boot information register.\n");
+ } else {
+ /* Check if a register number between 0-3 is specified. */
+ if (config_32 < 4) {
+ *boot_info_reg = config_32;
+ } else {
+ WARN("Incorrect boot information register (%u).\n",
+ config_32);
+ }
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ * This function gets the Secure Partition Manifest base and maps the manifest
+ * region.
+ * Currently only one Secure Partition manifest is considered which is used to
+ * prepare the context for the single Secure Partition.
+ ******************************************************************************/
+static int find_and_prepare_sp_context(void)
+{
+ void *sp_manifest;
+ uintptr_t manifest_base;
+ uintptr_t manifest_base_align;
+ entry_point_info_t *next_image_ep_info;
+ int32_t ret, boot_info_reg = -1;
+ struct secure_partition_desc *sp;
+
+ next_image_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
+ if (next_image_ep_info == NULL) {
+ WARN("No Secure Partition image provided by BL2.\n");
+ return -ENOENT;
+ }
+
+ sp_manifest = (void *)next_image_ep_info->args.arg0;
+ if (sp_manifest == NULL) {
+ WARN("Secure Partition manifest absent.\n");
+ return -ENOENT;
+ }
+
+ manifest_base = (uintptr_t)sp_manifest;
+ manifest_base_align = page_align(manifest_base, DOWN);
+
+ /*
+ * Map the secure partition manifest region in the EL3 translation
+ * regime.
+ * Map an area equal to (2 * PAGE_SIZE) for now. During manifest base
+ * alignment the region of 1 PAGE_SIZE from manifest align base may
+ * not completely accommodate the secure partition manifest region.
+ */
+ ret = mmap_add_dynamic_region((unsigned long long)manifest_base_align,
+ manifest_base_align,
+ PAGE_SIZE * 2,
+ MT_RO_DATA);
+ if (ret != 0) {
+ ERROR("Error while mapping SP manifest (%d).\n", ret);
+ return ret;
+ }
+
+ ret = fdt_node_offset_by_compatible(sp_manifest, -1,
+ "arm,ffa-manifest-1.0");
+ if (ret < 0) {
+ ERROR("Error happened in SP manifest reading.\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Store the size of the manifest so that it can be used later to pass
+ * the manifest as boot information later.
+ */
+ next_image_ep_info->args.arg1 = fdt_totalsize(sp_manifest);
+ INFO("Manifest size = %lu bytes.\n", next_image_ep_info->args.arg1);
+
+ /*
+ * Select an SP descriptor for initialising the partition's execution
+ * context on the primary CPU.
+ */
+ sp = spmc_get_current_sp_ctx();
+
+ /* Initialize entry point information for the SP */
+ SET_PARAM_HEAD(next_image_ep_info, PARAM_EP, VERSION_1,
+ SECURE | EP_ST_ENABLE);
+
+ /* Parse the SP manifest. */
+ ret = sp_manifest_parse(sp_manifest, ret, sp, next_image_ep_info,
+ &boot_info_reg);
+ if (ret != 0) {
+ ERROR("Error in Secure Partition manifest parsing.\n");
+ return ret;
+ }
+
+ /* Check that the runtime EL in the manifest was correct. */
+ if (sp->runtime_el != S_EL1) {
+ ERROR("Unexpected runtime EL: %d\n", sp->runtime_el);
+ return -EINVAL;
+ }
+
+ /* Perform any common initialisation. */
+ spmc_sp_common_setup(sp, next_image_ep_info, boot_info_reg);
+
+ /* Perform any initialisation specific to S-EL1 SPs. */
+ spmc_el1_sp_setup(sp, next_image_ep_info);
+
+ /* Initialize the SP context with the required ep info. */
+ spmc_sp_common_ep_commit(sp, next_image_ep_info);
+
+ return 0;
+}
+
+/*******************************************************************************
+ * This function takes an SP context pointer and performs a synchronous entry
+ * into it.
+ ******************************************************************************/
+static int32_t logical_sp_init(void)
+{
+ int32_t rc = 0;
+ struct el3_lp_desc *el3_lp_descs;
+
+ /* Perform initial validation of the Logical Partitions. */
+ rc = el3_sp_desc_validate();
+ if (rc != 0) {
+ ERROR("Logical Partition validation failed!\n");
+ return rc;
+ }
+
+ el3_lp_descs = get_el3_lp_array();
+
+ INFO("Logical Secure Partition init start.\n");
+ for (unsigned int i = 0U; i < EL3_LP_DESCS_COUNT; i++) {
+ rc = el3_lp_descs[i].init();
+ if (rc != 0) {
+ ERROR("Logical SP (0x%x) Failed to Initialize\n",
+ el3_lp_descs[i].sp_id);
+ return rc;
+ }
+ VERBOSE("Logical SP (0x%x) Initialized\n",
+ el3_lp_descs[i].sp_id);
+ }
+
+ INFO("Logical Secure Partition init completed.\n");
+
+ return rc;
+}
+
+uint64_t spmc_sp_synchronous_entry(struct sp_exec_ctx *ec)
+{
+ uint64_t rc;
+
+ assert(ec != NULL);
+
+ /* Assign the context of the SP to this CPU */
+ cm_set_context(&(ec->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(&ec->c_rt_ctx);
+
+ /* Save secure state */
+ cm_el1_sysregs_context_save(SECURE);
+
+ return rc;
+}
+
+/*******************************************************************************
+ * SPMC Helper Functions.
+ ******************************************************************************/
+static int32_t sp_init(void)
+{
+ uint64_t rc;
+ struct secure_partition_desc *sp;
+ struct sp_exec_ctx *ec;
+
+ sp = spmc_get_current_sp_ctx();
+ ec = spmc_get_sp_ec(sp);
+ ec->rt_model = RT_MODEL_INIT;
+ ec->rt_state = RT_STATE_RUNNING;
+
+ INFO("Secure Partition (0x%x) init start.\n", sp->sp_id);
+
+ rc = spmc_sp_synchronous_entry(ec);
+ if (rc != 0) {
+ /* Indicate SP init was not successful. */
+ ERROR("SP (0x%x) failed to initialize (%lu).\n",
+ sp->sp_id, rc);
+ return 0;
+ }
+
+ ec->rt_state = RT_STATE_WAITING;
+ INFO("Secure Partition initialized.\n");
+
+ return 1;
+}
+
+static void initalize_sp_descs(void)
+{
+ struct secure_partition_desc *sp;
+
+ for (unsigned int i = 0U; i < SECURE_PARTITION_COUNT; i++) {
+ sp = &sp_desc[i];
+ sp->sp_id = INV_SP_ID;
+ sp->mailbox.rx_buffer = NULL;
+ sp->mailbox.tx_buffer = NULL;
+ sp->mailbox.state = MAILBOX_STATE_EMPTY;
+ sp->secondary_ep = 0;
+ }
+}
+
+static void initalize_ns_ep_descs(void)
+{
+ struct ns_endpoint_desc *ns_ep;
+
+ for (unsigned int i = 0U; i < NS_PARTITION_COUNT; i++) {
+ ns_ep = &ns_ep_desc[i];
+ /*
+ * Clashes with the Hypervisor ID but will not be a
+ * problem in practice.
+ */
+ ns_ep->ns_ep_id = 0;
+ ns_ep->ffa_version = 0;
+ ns_ep->mailbox.rx_buffer = NULL;
+ ns_ep->mailbox.tx_buffer = NULL;
+ ns_ep->mailbox.state = MAILBOX_STATE_EMPTY;
+ }
+}
+
+/*******************************************************************************
+ * Initialize SPMC attributes for the SPMD.
+ ******************************************************************************/
+void spmc_populate_attrs(spmc_manifest_attribute_t *spmc_attrs)
+{
+ spmc_attrs->major_version = FFA_VERSION_MAJOR;
+ spmc_attrs->minor_version = FFA_VERSION_MINOR;
+ spmc_attrs->exec_state = MODE_RW_64;
+ spmc_attrs->spmc_id = FFA_SPMC_ID;
+}
+
+/*******************************************************************************
+ * Initialize contexts of all Secure Partitions.
+ ******************************************************************************/
+int32_t spmc_setup(void)
+{
+ int32_t ret;
+ uint32_t flags;
+
+ /* Initialize endpoint descriptors */
+ initalize_sp_descs();
+ initalize_ns_ep_descs();
+
+ /*
+ * Retrieve the information of the datastore for tracking shared memory
+ * requests allocated by platform code and zero the region if available.
+ */
+ ret = plat_spmc_shmem_datastore_get(&spmc_shmem_obj_state.data,
+ &spmc_shmem_obj_state.data_size);
+ if (ret != 0) {
+ ERROR("Failed to obtain memory descriptor backing store!\n");
+ return ret;
+ }
+ memset(spmc_shmem_obj_state.data, 0, spmc_shmem_obj_state.data_size);
+
+ /* Setup logical SPs. */
+ ret = logical_sp_init();
+ if (ret != 0) {
+ ERROR("Failed to initialize Logical Partitions.\n");
+ return ret;
+ }
+
+ /* Perform physical SP setup. */
+
+ /* Disable MMU at EL1 (initialized by BL2) */
+ disable_mmu_icache_el1();
+
+ /* Initialize context of the SP */
+ INFO("Secure Partition context setup start.\n");
+
+ ret = find_and_prepare_sp_context();
+ if (ret != 0) {
+ ERROR("Error in SP finding and context preparation.\n");
+ return ret;
+ }
+
+ /* Register power management hooks with PSCI */
+ psci_register_spd_pm_hook(&spmc_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);
+ ret = register_interrupt_type_handler(INTR_TYPE_S_EL1,
+ spmc_sp_interrupt_handler,
+ flags);
+ if (ret != 0) {
+ ERROR("Failed to register interrupt handler! (%d)\n", ret);
+ panic();
+ }
+
+ /* Register init function for deferred init. */
+ bl31_register_bl32_init(&sp_init);
+
+ INFO("Secure Partition setup done.\n");
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Secure Partition Manager SMC handler.
+ ******************************************************************************/
+uint64_t spmc_smc_handler(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ switch (smc_fid) {
+
+ case FFA_VERSION:
+ return ffa_version_handler(smc_fid, secure_origin, x1, x2, x3,
+ x4, cookie, handle, flags);
+
+ case FFA_SPM_ID_GET:
+ return ffa_spm_id_get_handler(smc_fid, secure_origin, x1, x2,
+ x3, x4, cookie, handle, flags);
+
+ case FFA_ID_GET:
+ return ffa_id_get_handler(smc_fid, secure_origin, x1, x2, x3,
+ x4, cookie, handle, flags);
+
+ case FFA_FEATURES:
+ return ffa_features_handler(smc_fid, secure_origin, x1, x2, x3,
+ x4, cookie, handle, flags);
+
+ case FFA_SECONDARY_EP_REGISTER_SMC64:
+ return ffa_sec_ep_register_handler(smc_fid, secure_origin, x1,
+ x2, x3, x4, cookie, handle,
+ flags);
+
+ case FFA_MSG_SEND_DIRECT_REQ_SMC32:
+ case FFA_MSG_SEND_DIRECT_REQ_SMC64:
+ return direct_req_smc_handler(smc_fid, secure_origin, x1, x2,
+ x3, x4, cookie, handle, flags);
+
+ case FFA_MSG_SEND_DIRECT_RESP_SMC32:
+ case FFA_MSG_SEND_DIRECT_RESP_SMC64:
+ return direct_resp_smc_handler(smc_fid, secure_origin, x1, x2,
+ x3, x4, cookie, handle, flags);
+
+ case FFA_RXTX_MAP_SMC32:
+ case FFA_RXTX_MAP_SMC64:
+ return rxtx_map_handler(smc_fid, secure_origin, x1, x2, x3, x4,
+ cookie, handle, flags);
+
+ case FFA_RXTX_UNMAP:
+ return rxtx_unmap_handler(smc_fid, secure_origin, x1, x2, x3,
+ x4, cookie, handle, flags);
+
+ case FFA_PARTITION_INFO_GET:
+ return partition_info_get_handler(smc_fid, secure_origin, x1,
+ x2, x3, x4, cookie, handle,
+ flags);
+
+ case FFA_RX_RELEASE:
+ return rx_release_handler(smc_fid, secure_origin, x1, x2, x3,
+ x4, cookie, handle, flags);
+
+ case FFA_MSG_WAIT:
+ return msg_wait_handler(smc_fid, secure_origin, x1, x2, x3, x4,
+ cookie, handle, flags);
+
+ case FFA_ERROR:
+ return ffa_error_handler(smc_fid, secure_origin, x1, x2, x3, x4,
+ cookie, handle, flags);
+
+ case FFA_MSG_RUN:
+ return ffa_run_handler(smc_fid, secure_origin, x1, x2, x3, x4,
+ cookie, handle, flags);
+
+ case FFA_MEM_SHARE_SMC32:
+ case FFA_MEM_SHARE_SMC64:
+ case FFA_MEM_LEND_SMC32:
+ case FFA_MEM_LEND_SMC64:
+ return spmc_ffa_mem_send(smc_fid, secure_origin, x1, x2, x3, x4,
+ cookie, handle, flags);
+
+ case FFA_MEM_FRAG_TX:
+ return spmc_ffa_mem_frag_tx(smc_fid, secure_origin, x1, x2, x3,
+ x4, cookie, handle, flags);
+
+ case FFA_MEM_FRAG_RX:
+ return spmc_ffa_mem_frag_rx(smc_fid, secure_origin, x1, x2, x3,
+ x4, cookie, handle, flags);
+
+ case FFA_MEM_RETRIEVE_REQ_SMC32:
+ case FFA_MEM_RETRIEVE_REQ_SMC64:
+ return spmc_ffa_mem_retrieve_req(smc_fid, secure_origin, x1, x2,
+ x3, x4, cookie, handle, flags);
+
+ case FFA_MEM_RELINQUISH:
+ return spmc_ffa_mem_relinquish(smc_fid, secure_origin, x1, x2,
+ x3, x4, cookie, handle, flags);
+
+ case FFA_MEM_RECLAIM:
+ return spmc_ffa_mem_reclaim(smc_fid, secure_origin, x1, x2, x3,
+ x4, cookie, handle, flags);
+
+ default:
+ WARN("Unsupported FF-A call 0x%08x.\n", smc_fid);
+ break;
+ }
+ return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
+}
+
+/*******************************************************************************
+ * This function is the handler registered for S-EL1 interrupts by the SPMC. It
+ * validates the interrupt and upon success arranges entry into the SP for
+ * handling the interrupt.
+ ******************************************************************************/
+static uint64_t spmc_sp_interrupt_handler(uint32_t id,
+ uint32_t flags,
+ void *handle,
+ void *cookie)
+{
+ struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
+ struct sp_exec_ctx *ec;
+ uint32_t linear_id = plat_my_core_pos();
+
+ /* Sanity check for a NULL pointer dereference. */
+ assert(sp != NULL);
+
+ /* Check the security state when the exception was generated. */
+ assert(get_interrupt_src_ss(flags) == NON_SECURE);
+
+ /* Panic if not an S-EL1 Partition. */
+ if (sp->runtime_el != S_EL1) {
+ ERROR("Interrupt received for a non S-EL1 SP on core%u.\n",
+ linear_id);
+ panic();
+ }
+
+ /* Obtain a reference to the SP execution context. */
+ ec = spmc_get_sp_ec(sp);
+
+ /* Ensure that the execution context is in waiting state else panic. */
+ if (ec->rt_state != RT_STATE_WAITING) {
+ ERROR("SP EC on core%u is not waiting (%u), it is (%u).\n",
+ linear_id, RT_STATE_WAITING, ec->rt_state);
+ panic();
+ }
+
+ /* Update the runtime model and state of the partition. */
+ ec->rt_model = RT_MODEL_INTR;
+ ec->rt_state = RT_STATE_RUNNING;
+
+ VERBOSE("SP (0x%x) interrupt start on core%u.\n", sp->sp_id, linear_id);
+
+ /*
+ * Forward the interrupt to the S-EL1 SP. The interrupt ID is not
+ * populated as the SP can determine this by itself.
+ */
+ return spmd_smc_switch_state(FFA_INTERRUPT, false,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ handle);
+}
diff --git a/services/std_svc/spm/el3_spmc/spmc_pm.c b/services/std_svc/spm/el3_spmc/spmc_pm.c
new file mode 100644
index 0000000..d25344c
--- /dev/null
+++ b/services/std_svc/spm/el3_spmc/spmc_pm.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/spinlock.h>
+#include <plat/common/common_def.h>
+#include <plat/common/platform.h>
+#include <services/ffa_svc.h>
+#include "spmc.h"
+
+#include <platform_def.h>
+
+/*******************************************************************************
+ * spmc_build_pm_message
+ *
+ * Builds an SPMC to SP direct message request.
+ ******************************************************************************/
+static void spmc_build_pm_message(gp_regs_t *gpregs,
+ unsigned long long message,
+ uint8_t pm_msg_type,
+ uint16_t sp_id)
+{
+ write_ctx_reg(gpregs, CTX_GPREG_X0, FFA_MSG_SEND_DIRECT_REQ_SMC32);
+ write_ctx_reg(gpregs, CTX_GPREG_X1,
+ (FFA_SPMC_ID << FFA_DIRECT_MSG_SOURCE_SHIFT) |
+ sp_id);
+ write_ctx_reg(gpregs, CTX_GPREG_X2, FFA_FWK_MSG_BIT |
+ (pm_msg_type & FFA_FWK_MSG_MASK));
+ write_ctx_reg(gpregs, CTX_GPREG_X3, message);
+}
+
+/*******************************************************************************
+ * This CPU has been turned on. Enter the SP to initialise S-EL1.
+ ******************************************************************************/
+static void spmc_cpu_on_finish_handler(u_register_t unused)
+{
+ struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
+ struct sp_exec_ctx *ec;
+ unsigned int linear_id = plat_my_core_pos();
+ entry_point_info_t sec_ec_ep_info = {0};
+ uint64_t rc;
+
+ /* Sanity check for a NULL pointer dereference. */
+ assert(sp != NULL);
+
+ /* Initialize entry point information for the SP. */
+ SET_PARAM_HEAD(&sec_ec_ep_info, PARAM_EP, VERSION_1,
+ SECURE | EP_ST_ENABLE);
+
+ /*
+ * Check if the primary execution context registered an entry point else
+ * bail out early.
+ * TODO: Add support for boot reason in manifest to allow jumping to
+ * entrypoint into the primary execution context.
+ */
+ if (sp->secondary_ep == 0) {
+ WARN("%s: No secondary ep on core%u\n", __func__, linear_id);
+ return;
+ }
+
+ sec_ec_ep_info.pc = sp->secondary_ep;
+
+ /*
+ * Setup and initialise the SP execution context on this physical cpu.
+ */
+ spmc_el1_sp_setup(sp, &sec_ec_ep_info);
+ spmc_sp_common_ep_commit(sp, &sec_ec_ep_info);
+
+ /* Obtain a reference to the SP execution context. */
+ ec = spmc_get_sp_ec(sp);
+
+ /*
+ * TODO: Should we do some PM related state tracking of the SP execution
+ * context here?
+ */
+
+ /* Update the runtime model and state of the partition. */
+ ec->rt_model = RT_MODEL_INIT;
+ ec->rt_state = RT_STATE_RUNNING;
+
+ INFO("SP (0x%x) init start on core%u.\n", sp->sp_id, linear_id);
+
+ rc = spmc_sp_synchronous_entry(ec);
+ if (rc != 0ULL) {
+ ERROR("%s failed (%lu) on CPU%u\n", __func__, rc, linear_id);
+ }
+
+ /* Update the runtime state of the partition. */
+ ec->rt_state = RT_STATE_WAITING;
+
+ VERBOSE("CPU %u on!\n", linear_id);
+}
+/*******************************************************************************
+ * Helper function to send a FF-A power management message to an SP.
+ ******************************************************************************/
+static int32_t spmc_send_pm_msg(uint8_t pm_msg_type,
+ unsigned long long psci_event)
+{
+ struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
+ struct sp_exec_ctx *ec;
+ gp_regs_t *gpregs_ctx;
+ unsigned int linear_id = plat_my_core_pos();
+ u_register_t resp;
+ uint64_t rc;
+
+ /* Obtain a reference to the SP execution context. */
+ ec = spmc_get_sp_ec(sp);
+
+ /*
+ * TODO: Should we do some PM related state tracking of the SP execution
+ * context here?
+ */
+
+ /*
+ * Build an SPMC to SP direct message request.
+ * Note that x4-x6 should be populated with the original PSCI arguments.
+ */
+ spmc_build_pm_message(get_gpregs_ctx(&ec->cpu_ctx),
+ psci_event,
+ pm_msg_type,
+ sp->sp_id);
+
+ /* Sanity check partition state. */
+ assert(ec->rt_state == RT_STATE_WAITING);
+
+ /* Update the runtime model and state of the partition. */
+ ec->rt_model = RT_MODEL_DIR_REQ;
+ ec->rt_state = RT_STATE_RUNNING;
+
+ rc = spmc_sp_synchronous_entry(ec);
+ if (rc != 0ULL) {
+ ERROR("%s failed (%lu) on CPU%u.\n", __func__, rc, linear_id);
+ assert(false);
+ return -EINVAL;
+ }
+
+ /*
+ * Validate we receive an expected response from the SP.
+ * TODO: We don't currently support aborting an SP in the scenario
+ * where it is misbehaving so assert these conditions are not
+ * met for now.
+ */
+ gpregs_ctx = get_gpregs_ctx(&ec->cpu_ctx);
+
+ /* Expect a direct message response from the SP. */
+ resp = read_ctx_reg(gpregs_ctx, CTX_GPREG_X0);
+ if (resp != FFA_MSG_SEND_DIRECT_RESP_SMC32) {
+ ERROR("%s invalid SP response (%lx).\n", __func__, resp);
+ assert(false);
+ return -EINVAL;
+ }
+
+ /* Ensure the sender and receiver are populated correctly. */
+ resp = read_ctx_reg(gpregs_ctx, CTX_GPREG_X1);
+ if (!(ffa_endpoint_source(resp) == sp->sp_id &&
+ ffa_endpoint_destination(resp) == FFA_SPMC_ID)) {
+ ERROR("%s invalid src/dst response (%lx).\n", __func__, resp);
+ assert(false);
+ return -EINVAL;
+ }
+
+ /* Expect a PM message response from the SP. */
+ resp = read_ctx_reg(gpregs_ctx, CTX_GPREG_X2);
+ if ((resp & FFA_FWK_MSG_BIT) == 0U ||
+ ((resp & FFA_FWK_MSG_MASK) != FFA_PM_MSG_PM_RESP)) {
+ ERROR("%s invalid PM response (%lx).\n", __func__, resp);
+ assert(false);
+ return -EINVAL;
+ }
+
+ /* Update the runtime state of the partition. */
+ ec->rt_state = RT_STATE_WAITING;
+
+ /* Return the status code returned by the SP */
+ return read_ctx_reg(gpregs_ctx, CTX_GPREG_X3);
+}
+
+/*******************************************************************************
+ * spmc_cpu_suspend_finish_handler
+ ******************************************************************************/
+static void spmc_cpu_suspend_finish_handler(u_register_t unused)
+{
+ struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
+ unsigned int linear_id = plat_my_core_pos();
+ int32_t rc;
+
+ /* Sanity check for a NULL pointer dereference. */
+ assert(sp != NULL);
+
+ /*
+ * Check if the SP has subscribed for this power management message.
+ * If not then we don't have anything else to do here.
+ */
+ if ((sp->pwr_mgmt_msgs & FFA_PM_MSG_SUB_CPU_SUSPEND_RESUME) == 0U) {
+ goto exit;
+ }
+
+ rc = spmc_send_pm_msg(FFA_PM_MSG_WB_REQ, FFA_WB_TYPE_NOTS2RAM);
+ if (rc < 0) {
+ ERROR("%s failed (%d) on CPU%u\n", __func__, rc, linear_id);
+ return;
+ }
+
+exit:
+ VERBOSE("CPU %u resumed!\n", linear_id);
+}
+
+/*******************************************************************************
+ * spmc_cpu_suspend_handler
+ ******************************************************************************/
+static void spmc_cpu_suspend_handler(u_register_t unused)
+{
+ struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
+ unsigned int linear_id = plat_my_core_pos();
+ int32_t rc;
+
+ /* Sanity check for a NULL pointer dereference. */
+ assert(sp != NULL);
+
+ /*
+ * Check if the SP has subscribed for this power management message.
+ * If not then we don't have anything else to do here.
+ */
+ if ((sp->pwr_mgmt_msgs & FFA_PM_MSG_SUB_CPU_SUSPEND) == 0U) {
+ goto exit;
+ }
+
+ rc = spmc_send_pm_msg(FFA_FWK_MSG_PSCI, PSCI_CPU_SUSPEND_AARCH64);
+ if (rc < 0) {
+ ERROR("%s failed (%d) on CPU%u\n", __func__, rc, linear_id);
+ return;
+ }
+exit:
+ VERBOSE("CPU %u suspend!\n", linear_id);
+}
+
+/*******************************************************************************
+ * spmc_cpu_off_handler
+ ******************************************************************************/
+static int32_t spmc_cpu_off_handler(u_register_t unused)
+{
+ struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
+ unsigned int linear_id = plat_my_core_pos();
+ int32_t ret = 0;
+
+ /* Sanity check for a NULL pointer dereference. */
+ assert(sp != NULL);
+
+ /*
+ * Check if the SP has subscribed for this power management message.
+ * If not then we don't have anything else to do here.
+ */
+ if ((sp->pwr_mgmt_msgs & FFA_PM_MSG_SUB_CPU_OFF) == 0U) {
+ goto exit;
+ }
+
+ ret = spmc_send_pm_msg(FFA_FWK_MSG_PSCI, PSCI_CPU_OFF);
+ if (ret < 0) {
+ ERROR("%s failed (%d) on CPU%u\n", __func__, ret, linear_id);
+ return ret;
+ }
+
+exit:
+ VERBOSE("CPU %u off!\n", linear_id);
+ return ret;
+}
+
+/*******************************************************************************
+ * Structure populated by the SPM Core to perform any bookkeeping before
+ * PSCI executes a power mgmt. operation.
+ ******************************************************************************/
+const spd_pm_ops_t spmc_pm = {
+ .svc_on_finish = spmc_cpu_on_finish_handler,
+ .svc_off = spmc_cpu_off_handler,
+ .svc_suspend = spmc_cpu_suspend_handler,
+ .svc_suspend_finish = spmc_cpu_suspend_finish_handler
+};
diff --git a/services/std_svc/spm/el3_spmc/spmc_setup.c b/services/std_svc/spm/el3_spmc/spmc_setup.c
new file mode 100644
index 0000000..8ebae28
--- /dev/null
+++ b/services/std_svc/spm/el3_spmc/spmc_setup.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <libfdt.h>
+#include <plat/common/common_def.h>
+#include <plat/common/platform.h>
+#include <services/ffa_svc.h>
+#include "spm_common.h"
+#include "spmc.h"
+#include <tools_share/firmware_image_package.h>
+
+#include <platform_def.h>
+
+/*
+ * Statically allocate a page of memory for passing boot information to an SP.
+ */
+static uint8_t ffa_boot_info_mem[PAGE_SIZE] __aligned(PAGE_SIZE);
+
+/*
+ * This function creates a initialization descriptor in the memory reserved
+ * for passing boot information to an SP. It then copies the partition manifest
+ * into this region and ensures that its reference in the initialization
+ * descriptor is updated.
+ */
+static void spmc_create_boot_info(entry_point_info_t *ep_info,
+ struct secure_partition_desc *sp)
+{
+ struct ffa_boot_info_header *boot_header;
+ struct ffa_boot_info_desc *boot_descriptor;
+ uintptr_t manifest_addr;
+
+ /*
+ * Calculate the maximum size of the manifest that can be accommodated
+ * in the boot information memory region.
+ */
+ const unsigned int
+ max_manifest_sz = sizeof(ffa_boot_info_mem) -
+ (sizeof(struct ffa_boot_info_header) +
+ sizeof(struct ffa_boot_info_desc));
+
+ /*
+ * The current implementation only supports the FF-A v1.1
+ * implementation of the boot protocol, therefore check
+ * that a v1.0 SP has not requested use of the protocol.
+ */
+ if (sp->ffa_version == MAKE_FFA_VERSION(1, 0)) {
+ ERROR("FF-A boot protocol not supported for v1.0 clients\n");
+ return;
+ }
+
+ /*
+ * Check if the manifest will fit into the boot info memory region else
+ * bail.
+ */
+ if (ep_info->args.arg1 > max_manifest_sz) {
+ WARN("Unable to copy manifest into boot information. ");
+ WARN("Max sz = %u bytes. Manifest sz = %lu bytes\n",
+ max_manifest_sz, ep_info->args.arg1);
+ return;
+ }
+
+ /* Zero the memory region before populating. */
+ memset(ffa_boot_info_mem, 0, PAGE_SIZE);
+
+ /*
+ * Populate the ffa_boot_info_header at the start of the boot info
+ * region.
+ */
+ boot_header = (struct ffa_boot_info_header *) ffa_boot_info_mem;
+
+ /* Position the ffa_boot_info_desc after the ffa_boot_info_header. */
+ boot_header->offset_boot_info_desc =
+ sizeof(struct ffa_boot_info_header);
+ boot_descriptor = (struct ffa_boot_info_desc *)
+ (ffa_boot_info_mem +
+ boot_header->offset_boot_info_desc);
+
+ /*
+ * We must use the FF-A version coresponding to the version implemented
+ * by the SP. Currently this can only be v1.1.
+ */
+ boot_header->version = sp->ffa_version;
+
+ /* Populate the boot information header. */
+ boot_header->size_boot_info_desc = sizeof(struct ffa_boot_info_desc);
+
+ /* Set the signature "0xFFA". */
+ boot_header->signature = FFA_INIT_DESC_SIGNATURE;
+
+ /* Set the count. Currently 1 since only the manifest is specified. */
+ boot_header->count_boot_info_desc = 1;
+
+ /* Populate the boot information descriptor for the manifest. */
+ boot_descriptor->type =
+ FFA_BOOT_INFO_TYPE(FFA_BOOT_INFO_TYPE_STD) |
+ FFA_BOOT_INFO_TYPE_ID(FFA_BOOT_INFO_TYPE_ID_FDT);
+
+ boot_descriptor->flags =
+ FFA_BOOT_INFO_FLAG_NAME(FFA_BOOT_INFO_FLAG_NAME_UUID) |
+ FFA_BOOT_INFO_FLAG_CONTENT(FFA_BOOT_INFO_FLAG_CONTENT_ADR);
+
+ /*
+ * Copy the manifest into boot info region after the boot information
+ * descriptor.
+ */
+ boot_descriptor->size_boot_info = (uint32_t) ep_info->args.arg1;
+
+ manifest_addr = (uintptr_t) (ffa_boot_info_mem +
+ boot_header->offset_boot_info_desc +
+ boot_header->size_boot_info_desc);
+
+ memcpy((void *) manifest_addr, (void *) ep_info->args.arg0,
+ boot_descriptor->size_boot_info);
+
+ boot_descriptor->content = manifest_addr;
+
+ /* Calculate the size of the total boot info blob. */
+ boot_header->size_boot_info_blob = boot_header->offset_boot_info_desc +
+ boot_descriptor->size_boot_info +
+ (boot_header->count_boot_info_desc *
+ boot_header->size_boot_info_desc);
+
+ INFO("SP boot info @ 0x%lx, size: %u bytes.\n",
+ (uintptr_t) ffa_boot_info_mem,
+ boot_header->size_boot_info_blob);
+ INFO("SP manifest @ 0x%lx, size: %u bytes.\n",
+ boot_descriptor->content,
+ boot_descriptor->size_boot_info);
+}
+
+/*
+ * We are assuming that the index of the execution
+ * context used is the linear index of the current physical cpu.
+ */
+unsigned int get_ec_index(struct secure_partition_desc *sp)
+{
+ return plat_my_core_pos();
+}
+
+/* S-EL1 partition specific initialisation. */
+void spmc_el1_sp_setup(struct secure_partition_desc *sp,
+ entry_point_info_t *ep_info)
+{
+ /* Sanity check input arguments. */
+ assert(sp != NULL);
+ assert(ep_info != NULL);
+
+ /* Initialise the SPSR for S-EL1 SPs. */
+ ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS);
+
+ /*
+ * TF-A Implementation defined behaviour to provide the linear
+ * core ID in the x4 register.
+ */
+ ep_info->args.arg4 = (uintptr_t) plat_my_core_pos();
+
+ /*
+ * Check whether setup is being performed for the primary or a secondary
+ * execution context. In the latter case, indicate to the SP that this
+ * is a warm boot.
+ * TODO: This check would need to be reworked if the same entry point is
+ * used for both primary and secondary initialisation.
+ */
+ if (sp->secondary_ep != 0U) {
+ /*
+ * Sanity check that the secondary entry point is still what was
+ * originally set.
+ */
+ assert(sp->secondary_ep == ep_info->pc);
+ ep_info->args.arg0 = FFA_WB_TYPE_S2RAM;
+ }
+}
+
+/* Common initialisation for all SPs. */
+void spmc_sp_common_setup(struct secure_partition_desc *sp,
+ entry_point_info_t *ep_info,
+ int32_t boot_info_reg)
+{
+ uint16_t sp_id;
+
+ /* Assign FF-A Partition ID if not already assigned. */
+ if (sp->sp_id == INV_SP_ID) {
+ sp_id = FFA_SP_ID_BASE + ACTIVE_SP_DESC_INDEX;
+ /*
+ * Ensure we don't clash with previously assigned partition
+ * IDs.
+ */
+ while (!is_ffa_secure_id_valid(sp_id)) {
+ sp_id++;
+
+ if (sp_id == FFA_SWD_ID_LIMIT) {
+ ERROR("Unable to determine valid SP ID.\n");
+ panic();
+ }
+ }
+ sp->sp_id = sp_id;
+ }
+
+ /*
+ * We currently only support S-EL1 partitions so ensure this is the
+ * case.
+ */
+ assert(sp->runtime_el == S_EL1);
+
+ /* Check if the SP wants to use the FF-A boot protocol. */
+ if (boot_info_reg >= 0) {
+ /*
+ * Create a boot information descriptor and copy the partition
+ * manifest into the reserved memory region for consumption by
+ * the SP.
+ */
+ spmc_create_boot_info(ep_info, sp);
+
+ /*
+ * We have consumed what we need from ep args so we can now
+ * zero them before we start populating with new information
+ * specifically for the SP.
+ */
+ zeromem(&ep_info->args, sizeof(ep_info->args));
+
+ /*
+ * Pass the address of the boot information in the
+ * boot_info_reg.
+ */
+ switch (boot_info_reg) {
+ case 0:
+ ep_info->args.arg0 = (uintptr_t) ffa_boot_info_mem;
+ break;
+ case 1:
+ ep_info->args.arg1 = (uintptr_t) ffa_boot_info_mem;
+ break;
+ case 2:
+ ep_info->args.arg2 = (uintptr_t) ffa_boot_info_mem;
+ break;
+ case 3:
+ ep_info->args.arg3 = (uintptr_t) ffa_boot_info_mem;
+ break;
+ default:
+ ERROR("Invalid value for \"gp-register-num\" %d.\n",
+ boot_info_reg);
+ }
+ } else {
+ /*
+ * We don't need any of the information that was populated
+ * in ep_args so we can clear them.
+ */
+ zeromem(&ep_info->args, sizeof(ep_info->args));
+ }
+}
+
+/*
+ * Initialise the SP context now we have populated the common and EL specific
+ * entrypoint information.
+ */
+void spmc_sp_common_ep_commit(struct secure_partition_desc *sp,
+ entry_point_info_t *ep_info)
+{
+ cpu_context_t *cpu_ctx;
+
+ cpu_ctx = &(spmc_get_sp_ec(sp)->cpu_ctx);
+ print_entry_point_info(ep_info);
+ cm_setup_context(cpu_ctx, ep_info);
+}
diff --git a/services/std_svc/spm/el3_spmc/spmc_shared_mem.c b/services/std_svc/spm/el3_spmc/spmc_shared_mem.c
new file mode 100644
index 0000000..89d7b31
--- /dev/null
+++ b/services/std_svc/spm/el3_spmc/spmc_shared_mem.c
@@ -0,0 +1,1861 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+#include <errno.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/object_pool.h>
+#include <lib/spinlock.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <services/ffa_svc.h>
+#include "spmc.h"
+#include "spmc_shared_mem.h"
+
+#include <platform_def.h>
+
+/**
+ * struct spmc_shmem_obj - Shared memory object.
+ * @desc_size: Size of @desc.
+ * @desc_filled: Size of @desc already received.
+ * @in_use: Number of clients that have called ffa_mem_retrieve_req
+ * without a matching ffa_mem_relinquish call.
+ * @desc: FF-A memory region descriptor passed in ffa_mem_share.
+ */
+struct spmc_shmem_obj {
+ size_t desc_size;
+ size_t desc_filled;
+ size_t in_use;
+ struct ffa_mtd desc;
+};
+
+/*
+ * Declare our data structure to store the metadata of memory share requests.
+ * The main datastore is allocated on a per platform basis to ensure enough
+ * storage can be made available.
+ * The address of the data store will be populated by the SPMC during its
+ * initialization.
+ */
+
+struct spmc_shmem_obj_state spmc_shmem_obj_state = {
+ /* Set start value for handle so top 32 bits are needed quickly. */
+ .next_handle = 0xffffffc0U,
+};
+
+/**
+ * spmc_shmem_obj_size - Convert from descriptor size to object size.
+ * @desc_size: Size of struct ffa_memory_region_descriptor object.
+ *
+ * Return: Size of struct spmc_shmem_obj object.
+ */
+static size_t spmc_shmem_obj_size(size_t desc_size)
+{
+ return desc_size + offsetof(struct spmc_shmem_obj, desc);
+}
+
+/**
+ * spmc_shmem_obj_alloc - Allocate struct spmc_shmem_obj.
+ * @state: Global state.
+ * @desc_size: Size of struct ffa_memory_region_descriptor object that
+ * allocated object will hold.
+ *
+ * Return: Pointer to newly allocated object, or %NULL if there not enough space
+ * left. The returned pointer is only valid while @state is locked, to
+ * used it again after unlocking @state, spmc_shmem_obj_lookup must be
+ * called.
+ */
+static struct spmc_shmem_obj *
+spmc_shmem_obj_alloc(struct spmc_shmem_obj_state *state, size_t desc_size)
+{
+ struct spmc_shmem_obj *obj;
+ size_t free = state->data_size - state->allocated;
+ size_t obj_size;
+
+ if (state->data == NULL) {
+ ERROR("Missing shmem datastore!\n");
+ return NULL;
+ }
+
+ obj_size = spmc_shmem_obj_size(desc_size);
+
+ /* Ensure the obj size has not overflowed. */
+ if (obj_size < desc_size) {
+ WARN("%s(0x%zx) desc_size overflow\n",
+ __func__, desc_size);
+ return NULL;
+ }
+
+ if (obj_size > free) {
+ WARN("%s(0x%zx) failed, free 0x%zx\n",
+ __func__, desc_size, free);
+ return NULL;
+ }
+ obj = (struct spmc_shmem_obj *)(state->data + state->allocated);
+ obj->desc = (struct ffa_mtd) {0};
+ obj->desc_size = desc_size;
+ obj->desc_filled = 0;
+ obj->in_use = 0;
+ state->allocated += obj_size;
+ return obj;
+}
+
+/**
+ * spmc_shmem_obj_free - Free struct spmc_shmem_obj.
+ * @state: Global state.
+ * @obj: Object to free.
+ *
+ * Release memory used by @obj. Other objects may move, so on return all
+ * pointers to struct spmc_shmem_obj object should be considered invalid, not
+ * just @obj.
+ *
+ * The current implementation always compacts the remaining objects to simplify
+ * the allocator and to avoid fragmentation.
+ */
+
+static void spmc_shmem_obj_free(struct spmc_shmem_obj_state *state,
+ struct spmc_shmem_obj *obj)
+{
+ size_t free_size = spmc_shmem_obj_size(obj->desc_size);
+ uint8_t *shift_dest = (uint8_t *)obj;
+ uint8_t *shift_src = shift_dest + free_size;
+ size_t shift_size = state->allocated - (shift_src - state->data);
+
+ if (shift_size != 0U) {
+ memmove(shift_dest, shift_src, shift_size);
+ }
+ state->allocated -= free_size;
+}
+
+/**
+ * spmc_shmem_obj_lookup - Lookup struct spmc_shmem_obj by handle.
+ * @state: Global state.
+ * @handle: Unique handle of object to return.
+ *
+ * Return: struct spmc_shmem_obj_state object with handle matching @handle.
+ * %NULL, if not object in @state->data has a matching handle.
+ */
+static struct spmc_shmem_obj *
+spmc_shmem_obj_lookup(struct spmc_shmem_obj_state *state, uint64_t handle)
+{
+ uint8_t *curr = state->data;
+
+ while (curr - state->data < state->allocated) {
+ struct spmc_shmem_obj *obj = (struct spmc_shmem_obj *)curr;
+
+ if (obj->desc.handle == handle) {
+ return obj;
+ }
+ curr += spmc_shmem_obj_size(obj->desc_size);
+ }
+ return NULL;
+}
+
+/**
+ * spmc_shmem_obj_get_next - Get the next memory object from an offset.
+ * @offset: Offset used to track which objects have previously been
+ * returned.
+ *
+ * Return: the next struct spmc_shmem_obj_state object from the provided
+ * offset.
+ * %NULL, if there are no more objects.
+ */
+static struct spmc_shmem_obj *
+spmc_shmem_obj_get_next(struct spmc_shmem_obj_state *state, size_t *offset)
+{
+ uint8_t *curr = state->data + *offset;
+
+ if (curr - state->data < state->allocated) {
+ struct spmc_shmem_obj *obj = (struct spmc_shmem_obj *)curr;
+
+ *offset += spmc_shmem_obj_size(obj->desc_size);
+
+ return obj;
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ * FF-A memory descriptor helper functions.
+ ******************************************************************************/
+/**
+ * spmc_shmem_obj_get_emad - Get the emad from a given index depending on the
+ * clients FF-A version.
+ * @desc: The memory transaction descriptor.
+ * @index: The index of the emad element to be accessed.
+ * @ffa_version: FF-A version of the provided structure.
+ * @emad_size: Will be populated with the size of the returned emad
+ * descriptor.
+ * Return: A pointer to the requested emad structure.
+ */
+static void *
+spmc_shmem_obj_get_emad(const struct ffa_mtd *desc, uint32_t index,
+ uint32_t ffa_version, size_t *emad_size)
+{
+ uint8_t *emad;
+ /*
+ * If the caller is using FF-A v1.0 interpret the descriptor as a v1.0
+ * format, otherwise assume it is a v1.1 format.
+ */
+ if (ffa_version == MAKE_FFA_VERSION(1, 0)) {
+ /* Cast our descriptor to the v1.0 format. */
+ struct ffa_mtd_v1_0 *mtd_v1_0 =
+ (struct ffa_mtd_v1_0 *) desc;
+ emad = (uint8_t *) &(mtd_v1_0->emad);
+ *emad_size = sizeof(struct ffa_emad_v1_0);
+ } else {
+ if (!is_aligned(desc->emad_offset, 16)) {
+ WARN("Emad offset is not aligned.\n");
+ return NULL;
+ }
+ emad = ((uint8_t *) desc + desc->emad_offset);
+ *emad_size = desc->emad_size;
+ }
+ return (emad + (*emad_size * index));
+}
+
+/**
+ * spmc_shmem_obj_get_comp_mrd - Get comp_mrd from a mtd struct based on the
+ * FF-A version of the descriptor.
+ * @obj: Object containing ffa_memory_region_descriptor.
+ *
+ * Return: struct ffa_comp_mrd object corresponding to the composite memory
+ * region descriptor.
+ */
+static struct ffa_comp_mrd *
+spmc_shmem_obj_get_comp_mrd(struct spmc_shmem_obj *obj, uint32_t ffa_version)
+{
+ size_t emad_size;
+ /*
+ * The comp_mrd_offset field of the emad descriptor remains consistent
+ * between FF-A versions therefore we can use the v1.0 descriptor here
+ * in all cases.
+ */
+ struct ffa_emad_v1_0 *emad = spmc_shmem_obj_get_emad(&obj->desc, 0,
+ ffa_version,
+ &emad_size);
+ /* Ensure the emad array was found. */
+ if (emad == NULL) {
+ return NULL;
+ }
+
+ /* Ensure the composite descriptor offset is aligned. */
+ if (!is_aligned(emad->comp_mrd_offset, 8)) {
+ WARN("Unaligned composite memory region descriptor offset.\n");
+ return NULL;
+ }
+
+ return (struct ffa_comp_mrd *)
+ ((uint8_t *)(&obj->desc) + emad->comp_mrd_offset);
+}
+
+/**
+ * spmc_shmem_obj_ffa_constituent_size - Calculate variable size part of obj.
+ * @obj: Object containing ffa_memory_region_descriptor.
+ *
+ * Return: Size of ffa_constituent_memory_region_descriptors in @obj.
+ */
+static size_t
+spmc_shmem_obj_ffa_constituent_size(struct spmc_shmem_obj *obj,
+ uint32_t ffa_version)
+{
+ struct ffa_comp_mrd *comp_mrd;
+
+ comp_mrd = spmc_shmem_obj_get_comp_mrd(obj, ffa_version);
+ if (comp_mrd == NULL) {
+ return 0;
+ }
+ return comp_mrd->address_range_count * sizeof(struct ffa_cons_mrd);
+}
+
+/**
+ * spmc_shmem_obj_validate_id - Validate a partition ID is participating in
+ * a given memory transaction.
+ * @sp_id: Partition ID to validate.
+ * @desc: Descriptor of the memory transaction.
+ *
+ * Return: true if ID is valid, else false.
+ */
+bool spmc_shmem_obj_validate_id(const struct ffa_mtd *desc, uint16_t sp_id)
+{
+ bool found = false;
+
+ /* Validate the partition is a valid participant. */
+ for (unsigned int i = 0U; i < desc->emad_count; i++) {
+ size_t emad_size;
+ struct ffa_emad_v1_0 *emad;
+
+ emad = spmc_shmem_obj_get_emad(desc, i,
+ MAKE_FFA_VERSION(1, 1),
+ &emad_size);
+ if (sp_id == emad->mapd.endpoint_id) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+}
+
+/*
+ * Compare two memory regions to determine if any range overlaps with another
+ * ongoing memory transaction.
+ */
+static bool
+overlapping_memory_regions(struct ffa_comp_mrd *region1,
+ struct ffa_comp_mrd *region2)
+{
+ uint64_t region1_start;
+ uint64_t region1_size;
+ uint64_t region1_end;
+ uint64_t region2_start;
+ uint64_t region2_size;
+ uint64_t region2_end;
+
+ assert(region1 != NULL);
+ assert(region2 != NULL);
+
+ if (region1 == region2) {
+ return true;
+ }
+
+ /*
+ * Check each memory region in the request against existing
+ * transactions.
+ */
+ for (size_t i = 0; i < region1->address_range_count; i++) {
+
+ region1_start = region1->address_range_array[i].address;
+ region1_size =
+ region1->address_range_array[i].page_count *
+ PAGE_SIZE_4KB;
+ region1_end = region1_start + region1_size;
+
+ for (size_t j = 0; j < region2->address_range_count; j++) {
+
+ region2_start = region2->address_range_array[j].address;
+ region2_size =
+ region2->address_range_array[j].page_count *
+ PAGE_SIZE_4KB;
+ region2_end = region2_start + region2_size;
+
+ /* Check if regions are not overlapping. */
+ if (!((region2_end <= region1_start) ||
+ (region1_end <= region2_start))) {
+ WARN("Overlapping mem regions 0x%lx-0x%lx & 0x%lx-0x%lx\n",
+ region1_start, region1_end,
+ region2_start, region2_end);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/*******************************************************************************
+ * FF-A v1.0 Memory Descriptor Conversion Helpers.
+ ******************************************************************************/
+/**
+ * spmc_shm_get_v1_1_descriptor_size - Calculate the required size for a v1.1
+ * converted descriptor.
+ * @orig: The original v1.0 memory transaction descriptor.
+ * @desc_size: The size of the original v1.0 memory transaction descriptor.
+ *
+ * Return: the size required to store the descriptor store in the v1.1 format.
+ */
+static size_t
+spmc_shm_get_v1_1_descriptor_size(struct ffa_mtd_v1_0 *orig, size_t desc_size)
+{
+ size_t size = 0;
+ struct ffa_comp_mrd *mrd;
+ struct ffa_emad_v1_0 *emad_array = orig->emad;
+
+ /* Get the size of the v1.1 descriptor. */
+ size += sizeof(struct ffa_mtd);
+
+ /* Add the size of the emad descriptors. */
+ size += orig->emad_count * sizeof(struct ffa_emad_v1_0);
+
+ /* Add the size of the composite mrds. */
+ size += sizeof(struct ffa_comp_mrd);
+
+ /* Add the size of the constituent mrds. */
+ mrd = (struct ffa_comp_mrd *) ((uint8_t *) orig +
+ emad_array[0].comp_mrd_offset);
+
+ /* Check the calculated address is within the memory descriptor. */
+ if ((uintptr_t) mrd >= (uintptr_t)((uint8_t *) orig + desc_size)) {
+ return 0;
+ }
+ size += mrd->address_range_count * sizeof(struct ffa_cons_mrd);
+
+ return size;
+}
+
+/**
+ * spmc_shm_get_v1_0_descriptor_size - Calculate the required size for a v1.0
+ * converted descriptor.
+ * @orig: The original v1.1 memory transaction descriptor.
+ * @desc_size: The size of the original v1.1 memory transaction descriptor.
+ *
+ * Return: the size required to store the descriptor store in the v1.0 format.
+ */
+static size_t
+spmc_shm_get_v1_0_descriptor_size(struct ffa_mtd *orig, size_t desc_size)
+{
+ size_t size = 0;
+ struct ffa_comp_mrd *mrd;
+ struct ffa_emad_v1_0 *emad_array = (struct ffa_emad_v1_0 *)
+ ((uint8_t *) orig +
+ orig->emad_offset);
+
+ /* Get the size of the v1.0 descriptor. */
+ size += sizeof(struct ffa_mtd_v1_0);
+
+ /* Add the size of the v1.0 emad descriptors. */
+ size += orig->emad_count * sizeof(struct ffa_emad_v1_0);
+
+ /* Add the size of the composite mrds. */
+ size += sizeof(struct ffa_comp_mrd);
+
+ /* Add the size of the constituent mrds. */
+ mrd = (struct ffa_comp_mrd *) ((uint8_t *) orig +
+ emad_array[0].comp_mrd_offset);
+
+ /* Check the calculated address is within the memory descriptor. */
+ if ((uintptr_t) mrd >= (uintptr_t)((uint8_t *) orig + desc_size)) {
+ return 0;
+ }
+ size += mrd->address_range_count * sizeof(struct ffa_cons_mrd);
+
+ return size;
+}
+
+/**
+ * spmc_shm_convert_shmem_obj_from_v1_0 - Converts a given v1.0 memory object.
+ * @out_obj: The shared memory object to populate the converted descriptor.
+ * @orig: The shared memory object containing the v1.0 descriptor.
+ *
+ * Return: true if the conversion is successful else false.
+ */
+static bool
+spmc_shm_convert_shmem_obj_from_v1_0(struct spmc_shmem_obj *out_obj,
+ struct spmc_shmem_obj *orig)
+{
+ struct ffa_mtd_v1_0 *mtd_orig = (struct ffa_mtd_v1_0 *) &orig->desc;
+ struct ffa_mtd *out = &out_obj->desc;
+ struct ffa_emad_v1_0 *emad_array_in;
+ struct ffa_emad_v1_0 *emad_array_out;
+ struct ffa_comp_mrd *mrd_in;
+ struct ffa_comp_mrd *mrd_out;
+
+ size_t mrd_in_offset;
+ size_t mrd_out_offset;
+ size_t mrd_size = 0;
+
+ /* Populate the new descriptor format from the v1.0 struct. */
+ out->sender_id = mtd_orig->sender_id;
+ out->memory_region_attributes = mtd_orig->memory_region_attributes;
+ out->flags = mtd_orig->flags;
+ out->handle = mtd_orig->handle;
+ out->tag = mtd_orig->tag;
+ out->emad_count = mtd_orig->emad_count;
+ out->emad_size = sizeof(struct ffa_emad_v1_0);
+
+ /*
+ * We will locate the emad descriptors directly after the ffa_mtd
+ * struct. This will be 8-byte aligned.
+ */
+ out->emad_offset = sizeof(struct ffa_mtd);
+
+ emad_array_in = mtd_orig->emad;
+ emad_array_out = (struct ffa_emad_v1_0 *)
+ ((uint8_t *) out + out->emad_offset);
+
+ /* Copy across the emad structs. */
+ for (unsigned int i = 0U; i < out->emad_count; i++) {
+ memcpy(&emad_array_out[i], &emad_array_in[i],
+ sizeof(struct ffa_emad_v1_0));
+ }
+
+ /* Place the mrd descriptors after the end of the emad descriptors.*/
+ mrd_in_offset = emad_array_in->comp_mrd_offset;
+ mrd_out_offset = out->emad_offset + (out->emad_size * out->emad_count);
+ mrd_out = (struct ffa_comp_mrd *) ((uint8_t *) out + mrd_out_offset);
+
+ /* Add the size of the composite memory region descriptor. */
+ mrd_size += sizeof(struct ffa_comp_mrd);
+
+ /* Find the mrd descriptor. */
+ mrd_in = (struct ffa_comp_mrd *) ((uint8_t *) mtd_orig + mrd_in_offset);
+
+ /* Add the size of the constituent memory region descriptors. */
+ mrd_size += mrd_in->address_range_count * sizeof(struct ffa_cons_mrd);
+
+ /*
+ * Update the offset in the emads by the delta between the input and
+ * output addresses.
+ */
+ for (unsigned int i = 0U; i < out->emad_count; i++) {
+ emad_array_out[i].comp_mrd_offset =
+ emad_array_in[i].comp_mrd_offset +
+ (mrd_out_offset - mrd_in_offset);
+ }
+
+ /* Verify that we stay within bound of the memory descriptors. */
+ if ((uintptr_t)((uint8_t *) mrd_in + mrd_size) >
+ (uintptr_t)((uint8_t *) mtd_orig + orig->desc_size) ||
+ ((uintptr_t)((uint8_t *) mrd_out + mrd_size) >
+ (uintptr_t)((uint8_t *) out + out_obj->desc_size))) {
+ ERROR("%s: Invalid mrd structure.\n", __func__);
+ return false;
+ }
+
+ /* Copy the mrd descriptors directly. */
+ memcpy(mrd_out, mrd_in, mrd_size);
+
+ return true;
+}
+
+/**
+ * spmc_shm_convert_mtd_to_v1_0 - Converts a given v1.1 memory object to
+ * v1.0 memory object.
+ * @out_obj: The shared memory object to populate the v1.0 descriptor.
+ * @orig: The shared memory object containing the v1.1 descriptor.
+ *
+ * Return: true if the conversion is successful else false.
+ */
+static bool
+spmc_shm_convert_mtd_to_v1_0(struct spmc_shmem_obj *out_obj,
+ struct spmc_shmem_obj *orig)
+{
+ struct ffa_mtd *mtd_orig = &orig->desc;
+ struct ffa_mtd_v1_0 *out = (struct ffa_mtd_v1_0 *) &out_obj->desc;
+ struct ffa_emad_v1_0 *emad_in;
+ struct ffa_emad_v1_0 *emad_array_in;
+ struct ffa_emad_v1_0 *emad_array_out;
+ struct ffa_comp_mrd *mrd_in;
+ struct ffa_comp_mrd *mrd_out;
+
+ size_t mrd_in_offset;
+ size_t mrd_out_offset;
+ size_t emad_out_array_size;
+ size_t mrd_size = 0;
+
+ /* Populate the v1.0 descriptor format from the v1.1 struct. */
+ out->sender_id = mtd_orig->sender_id;
+ out->memory_region_attributes = mtd_orig->memory_region_attributes;
+ out->flags = mtd_orig->flags;
+ out->handle = mtd_orig->handle;
+ out->tag = mtd_orig->tag;
+ out->emad_count = mtd_orig->emad_count;
+
+ /* Determine the location of the emad array in both descriptors. */
+ emad_array_in = (struct ffa_emad_v1_0 *)
+ ((uint8_t *) mtd_orig + mtd_orig->emad_offset);
+ emad_array_out = out->emad;
+
+ /* Copy across the emad structs. */
+ emad_in = emad_array_in;
+ for (unsigned int i = 0U; i < out->emad_count; i++) {
+ memcpy(&emad_array_out[i], emad_in,
+ sizeof(struct ffa_emad_v1_0));
+
+ emad_in += mtd_orig->emad_size;
+ }
+
+ /* Place the mrd descriptors after the end of the emad descriptors. */
+ emad_out_array_size = sizeof(struct ffa_emad_v1_0) * out->emad_count;
+
+ mrd_out_offset = (uint8_t *) out->emad - (uint8_t *) out +
+ emad_out_array_size;
+
+ mrd_out = (struct ffa_comp_mrd *) ((uint8_t *) out + mrd_out_offset);
+
+ mrd_in_offset = mtd_orig->emad_offset +
+ (mtd_orig->emad_size * mtd_orig->emad_count);
+
+ /* Add the size of the composite memory region descriptor. */
+ mrd_size += sizeof(struct ffa_comp_mrd);
+
+ /* Find the mrd descriptor. */
+ mrd_in = (struct ffa_comp_mrd *) ((uint8_t *) mtd_orig + mrd_in_offset);
+
+ /* Add the size of the constituent memory region descriptors. */
+ mrd_size += mrd_in->address_range_count * sizeof(struct ffa_cons_mrd);
+
+ /*
+ * Update the offset in the emads by the delta between the input and
+ * output addresses.
+ */
+ emad_in = emad_array_in;
+
+ for (unsigned int i = 0U; i < out->emad_count; i++) {
+ emad_array_out[i].comp_mrd_offset = emad_in->comp_mrd_offset +
+ (mrd_out_offset -
+ mrd_in_offset);
+ emad_in += mtd_orig->emad_size;
+ }
+
+ /* Verify that we stay within bound of the memory descriptors. */
+ if ((uintptr_t)((uint8_t *) mrd_in + mrd_size) >
+ (uintptr_t)((uint8_t *) mtd_orig + orig->desc_size) ||
+ ((uintptr_t)((uint8_t *) mrd_out + mrd_size) >
+ (uintptr_t)((uint8_t *) out + out_obj->desc_size))) {
+ ERROR("%s: Invalid mrd structure.\n", __func__);
+ return false;
+ }
+
+ /* Copy the mrd descriptors directly. */
+ memcpy(mrd_out, mrd_in, mrd_size);
+
+ return true;
+}
+
+/**
+ * spmc_populate_ffa_v1_0_descriptor - Converts a given v1.1 memory object to
+ * the v1.0 format and populates the
+ * provided buffer.
+ * @dst: Buffer to populate v1.0 ffa_memory_region_descriptor.
+ * @orig_obj: Object containing v1.1 ffa_memory_region_descriptor.
+ * @buf_size: Size of the buffer to populate.
+ * @offset: The offset of the converted descriptor to copy.
+ * @copy_size: Will be populated with the number of bytes copied.
+ * @out_desc_size: Will be populated with the total size of the v1.0
+ * descriptor.
+ *
+ * Return: 0 if conversion and population succeeded.
+ * Note: This function invalidates the reference to @orig therefore
+ * `spmc_shmem_obj_lookup` must be called if further usage is required.
+ */
+static uint32_t
+spmc_populate_ffa_v1_0_descriptor(void *dst, struct spmc_shmem_obj *orig_obj,
+ size_t buf_size, size_t offset,
+ size_t *copy_size, size_t *v1_0_desc_size)
+{
+ struct spmc_shmem_obj *v1_0_obj;
+
+ /* Calculate the size that the v1.0 descriptor will require. */
+ *v1_0_desc_size = spmc_shm_get_v1_0_descriptor_size(
+ &orig_obj->desc, orig_obj->desc_size);
+
+ if (*v1_0_desc_size == 0) {
+ ERROR("%s: cannot determine size of descriptor.\n",
+ __func__);
+ return FFA_ERROR_INVALID_PARAMETER;
+ }
+
+ /* Get a new obj to store the v1.0 descriptor. */
+ v1_0_obj = spmc_shmem_obj_alloc(&spmc_shmem_obj_state,
+ *v1_0_desc_size);
+
+ if (!v1_0_obj) {
+ return FFA_ERROR_NO_MEMORY;
+ }
+
+ /* Perform the conversion from v1.1 to v1.0. */
+ if (!spmc_shm_convert_mtd_to_v1_0(v1_0_obj, orig_obj)) {
+ spmc_shmem_obj_free(&spmc_shmem_obj_state, v1_0_obj);
+ return FFA_ERROR_INVALID_PARAMETER;
+ }
+
+ *copy_size = MIN(v1_0_obj->desc_size - offset, buf_size);
+ memcpy(dst, (uint8_t *) &v1_0_obj->desc + offset, *copy_size);
+
+ /*
+ * We're finished with the v1.0 descriptor for now so free it.
+ * Note that this will invalidate any references to the v1.1
+ * descriptor.
+ */
+ spmc_shmem_obj_free(&spmc_shmem_obj_state, v1_0_obj);
+
+ return 0;
+}
+
+/**
+ * spmc_shmem_check_obj - Check that counts in descriptor match overall size.
+ * @obj: Object containing ffa_memory_region_descriptor.
+ * @ffa_version: FF-A version of the provided descriptor.
+ *
+ * Return: 0 if object is valid, -EINVAL if constituent_memory_region_descriptor
+ * offset or count is invalid.
+ */
+static int spmc_shmem_check_obj(struct spmc_shmem_obj *obj,
+ uint32_t ffa_version)
+{
+ uint32_t comp_mrd_offset = 0;
+
+ if (obj->desc.emad_count == 0U) {
+ WARN("%s: unsupported attribute desc count %u.\n",
+ __func__, obj->desc.emad_count);
+ return -EINVAL;
+ }
+
+ for (size_t emad_num = 0; emad_num < obj->desc.emad_count; emad_num++) {
+ size_t size;
+ size_t count;
+ size_t expected_size;
+ size_t total_page_count;
+ size_t emad_size;
+ size_t desc_size;
+ size_t header_emad_size;
+ uint32_t offset;
+ struct ffa_comp_mrd *comp;
+ struct ffa_emad_v1_0 *emad;
+
+ emad = spmc_shmem_obj_get_emad(&obj->desc, emad_num,
+ ffa_version, &emad_size);
+ if (emad == NULL) {
+ WARN("%s: invalid emad structure.\n", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * Validate the calculated emad address resides within the
+ * descriptor.
+ */
+ if ((uintptr_t) emad >=
+ (uintptr_t)((uint8_t *) &obj->desc + obj->desc_size)) {
+ WARN("Invalid emad access.\n");
+ return -EINVAL;
+ }
+
+ offset = emad->comp_mrd_offset;
+
+ if (ffa_version == MAKE_FFA_VERSION(1, 0)) {
+ desc_size = sizeof(struct ffa_mtd_v1_0);
+ } else {
+ desc_size = sizeof(struct ffa_mtd);
+ }
+
+ header_emad_size = desc_size +
+ (obj->desc.emad_count * emad_size);
+
+ if (offset < header_emad_size) {
+ WARN("%s: invalid object, offset %u < header + emad %zu\n",
+ __func__, offset, header_emad_size);
+ return -EINVAL;
+ }
+
+ size = obj->desc_size;
+
+ if (offset > size) {
+ WARN("%s: invalid object, offset %u > total size %zu\n",
+ __func__, offset, obj->desc_size);
+ return -EINVAL;
+ }
+ size -= offset;
+
+ if (size < sizeof(struct ffa_comp_mrd)) {
+ WARN("%s: invalid object, offset %u, total size %zu, no header space.\n",
+ __func__, offset, obj->desc_size);
+ return -EINVAL;
+ }
+ size -= sizeof(struct ffa_comp_mrd);
+
+ count = size / sizeof(struct ffa_cons_mrd);
+
+ comp = spmc_shmem_obj_get_comp_mrd(obj, ffa_version);
+
+ if (comp == NULL) {
+ WARN("%s: invalid comp_mrd offset\n", __func__);
+ return -EINVAL;
+ }
+
+ if (comp->address_range_count != count) {
+ WARN("%s: invalid object, desc count %u != %zu\n",
+ __func__, comp->address_range_count, count);
+ return -EINVAL;
+ }
+
+ expected_size = offset + sizeof(*comp) +
+ spmc_shmem_obj_ffa_constituent_size(obj,
+ ffa_version);
+
+ if (expected_size != obj->desc_size) {
+ WARN("%s: invalid object, computed size %zu != size %zu\n",
+ __func__, expected_size, obj->desc_size);
+ return -EINVAL;
+ }
+
+ if (obj->desc_filled < obj->desc_size) {
+ /*
+ * The whole descriptor has not yet been received.
+ * Skip final checks.
+ */
+ return 0;
+ }
+
+ /*
+ * The offset provided to the composite memory region descriptor
+ * should be consistent across endpoint descriptors. Store the
+ * first entry and compare against subsequent entries.
+ */
+ if (comp_mrd_offset == 0) {
+ comp_mrd_offset = offset;
+ } else {
+ if (comp_mrd_offset != offset) {
+ ERROR("%s: mismatching offsets provided, %u != %u\n",
+ __func__, offset, comp_mrd_offset);
+ return -EINVAL;
+ }
+ }
+
+ total_page_count = 0;
+
+ for (size_t i = 0; i < count; i++) {
+ total_page_count +=
+ comp->address_range_array[i].page_count;
+ }
+ if (comp->total_page_count != total_page_count) {
+ WARN("%s: invalid object, desc total_page_count %u != %zu\n",
+ __func__, comp->total_page_count,
+ total_page_count);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+/**
+ * spmc_shmem_check_state_obj - Check if the descriptor describes memory
+ * regions that are currently involved with an
+ * existing memory transactions. This implies that
+ * the memory is not in a valid state for lending.
+ * @obj: Object containing ffa_memory_region_descriptor.
+ *
+ * Return: 0 if object is valid, -EINVAL if invalid memory state.
+ */
+static int spmc_shmem_check_state_obj(struct spmc_shmem_obj *obj,
+ uint32_t ffa_version)
+{
+ size_t obj_offset = 0;
+ struct spmc_shmem_obj *inflight_obj;
+
+ struct ffa_comp_mrd *other_mrd;
+ struct ffa_comp_mrd *requested_mrd = spmc_shmem_obj_get_comp_mrd(obj,
+ ffa_version);
+
+ if (requested_mrd == NULL) {
+ return -EINVAL;
+ }
+
+ inflight_obj = spmc_shmem_obj_get_next(&spmc_shmem_obj_state,
+ &obj_offset);
+
+ while (inflight_obj != NULL) {
+ /*
+ * Don't compare the transaction to itself or to partially
+ * transmitted descriptors.
+ */
+ if ((obj->desc.handle != inflight_obj->desc.handle) &&
+ (obj->desc_size == obj->desc_filled)) {
+ other_mrd = spmc_shmem_obj_get_comp_mrd(inflight_obj,
+ FFA_VERSION_COMPILED);
+ if (other_mrd == NULL) {
+ return -EINVAL;
+ }
+ if (overlapping_memory_regions(requested_mrd,
+ other_mrd)) {
+ return -EINVAL;
+ }
+ }
+
+ inflight_obj = spmc_shmem_obj_get_next(&spmc_shmem_obj_state,
+ &obj_offset);
+ }
+ return 0;
+}
+
+static long spmc_ffa_fill_desc(struct mailbox *mbox,
+ struct spmc_shmem_obj *obj,
+ uint32_t fragment_length,
+ ffa_mtd_flag32_t mtd_flag,
+ uint32_t ffa_version,
+ void *smc_handle)
+{
+ int ret;
+ size_t emad_size;
+ uint32_t handle_low;
+ uint32_t handle_high;
+ struct ffa_emad_v1_0 *emad;
+ struct ffa_emad_v1_0 *other_emad;
+
+ if (mbox->rxtx_page_count == 0U) {
+ WARN("%s: buffer pair not registered.\n", __func__);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_arg;
+ }
+
+ if (fragment_length > mbox->rxtx_page_count * PAGE_SIZE_4KB) {
+ WARN("%s: bad fragment size %u > %u buffer size\n", __func__,
+ fragment_length, mbox->rxtx_page_count * PAGE_SIZE_4KB);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_arg;
+ }
+
+ if (fragment_length > obj->desc_size - obj->desc_filled) {
+ WARN("%s: bad fragment size %u > %zu remaining\n", __func__,
+ fragment_length, obj->desc_size - obj->desc_filled);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_arg;
+ }
+
+ memcpy((uint8_t *)&obj->desc + obj->desc_filled,
+ (uint8_t *) mbox->tx_buffer, fragment_length);
+
+ /* Ensure that the sender ID resides in the normal world. */
+ if (ffa_is_secure_world_id(obj->desc.sender_id)) {
+ WARN("%s: Invalid sender ID 0x%x.\n",
+ __func__, obj->desc.sender_id);
+ ret = FFA_ERROR_DENIED;
+ goto err_arg;
+ }
+
+ /* Ensure the NS bit is set to 0. */
+ if ((obj->desc.memory_region_attributes & FFA_MEM_ATTR_NS_BIT) != 0U) {
+ WARN("%s: NS mem attributes flags MBZ.\n", __func__);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_arg;
+ }
+
+ /*
+ * We don't currently support any optional flags so ensure none are
+ * requested.
+ */
+ if (obj->desc.flags != 0U && mtd_flag != 0U &&
+ (obj->desc.flags != mtd_flag)) {
+ WARN("%s: invalid memory transaction flags %u != %u\n",
+ __func__, obj->desc.flags, mtd_flag);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_arg;
+ }
+
+ if (obj->desc_filled == 0U) {
+ /* First fragment, descriptor header has been copied */
+ obj->desc.handle = spmc_shmem_obj_state.next_handle++;
+ obj->desc.flags |= mtd_flag;
+ }
+
+ obj->desc_filled += fragment_length;
+ ret = spmc_shmem_check_obj(obj, ffa_version);
+ if (ret != 0) {
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_bad_desc;
+ }
+
+ handle_low = (uint32_t)obj->desc.handle;
+ handle_high = obj->desc.handle >> 32;
+
+ if (obj->desc_filled != obj->desc_size) {
+ SMC_RET8(smc_handle, FFA_MEM_FRAG_RX, handle_low,
+ handle_high, obj->desc_filled,
+ (uint32_t)obj->desc.sender_id << 16, 0, 0, 0);
+ }
+
+ /* The full descriptor has been received, perform any final checks. */
+
+ /*
+ * If a partition ID resides in the secure world validate that the
+ * partition ID is for a known partition. Ignore any partition ID
+ * belonging to the normal world as it is assumed the Hypervisor will
+ * have validated these.
+ */
+ for (size_t i = 0; i < obj->desc.emad_count; i++) {
+ emad = spmc_shmem_obj_get_emad(&obj->desc, i, ffa_version,
+ &emad_size);
+ if (emad == NULL) {
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_bad_desc;
+ }
+
+ ffa_endpoint_id16_t ep_id = emad->mapd.endpoint_id;
+
+ if (ffa_is_secure_world_id(ep_id)) {
+ if (spmc_get_sp_ctx(ep_id) == NULL) {
+ WARN("%s: Invalid receiver id 0x%x\n",
+ __func__, ep_id);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_bad_desc;
+ }
+ }
+ }
+
+ /* Ensure partition IDs are not duplicated. */
+ for (size_t i = 0; i < obj->desc.emad_count; i++) {
+ emad = spmc_shmem_obj_get_emad(&obj->desc, i, ffa_version,
+ &emad_size);
+ if (emad == NULL) {
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_bad_desc;
+ }
+ for (size_t j = i + 1; j < obj->desc.emad_count; j++) {
+ other_emad = spmc_shmem_obj_get_emad(&obj->desc, j,
+ ffa_version,
+ &emad_size);
+ if (other_emad == NULL) {
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_bad_desc;
+ }
+
+ if (emad->mapd.endpoint_id ==
+ other_emad->mapd.endpoint_id) {
+ WARN("%s: Duplicated endpoint id 0x%x\n",
+ __func__, emad->mapd.endpoint_id);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_bad_desc;
+ }
+ }
+ }
+
+ ret = spmc_shmem_check_state_obj(obj, ffa_version);
+ if (ret) {
+ ERROR("%s: invalid memory region descriptor.\n", __func__);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_bad_desc;
+ }
+
+ /*
+ * Everything checks out, if the sender was using FF-A v1.0, convert
+ * the descriptor format to use the v1.1 structures.
+ */
+ if (ffa_version == MAKE_FFA_VERSION(1, 0)) {
+ struct spmc_shmem_obj *v1_1_obj;
+ uint64_t mem_handle;
+
+ /* Calculate the size that the v1.1 descriptor will required. */
+ size_t v1_1_desc_size =
+ spmc_shm_get_v1_1_descriptor_size((void *) &obj->desc,
+ obj->desc_size);
+
+ if (v1_1_desc_size == 0U) {
+ ERROR("%s: cannot determine size of descriptor.\n",
+ __func__);
+ goto err_arg;
+ }
+
+ /* Get a new obj to store the v1.1 descriptor. */
+ v1_1_obj =
+ spmc_shmem_obj_alloc(&spmc_shmem_obj_state, v1_1_desc_size);
+
+ if (!v1_1_obj) {
+ ret = FFA_ERROR_NO_MEMORY;
+ goto err_arg;
+ }
+
+ /* Perform the conversion from v1.0 to v1.1. */
+ v1_1_obj->desc_size = v1_1_desc_size;
+ v1_1_obj->desc_filled = v1_1_desc_size;
+ if (!spmc_shm_convert_shmem_obj_from_v1_0(v1_1_obj, obj)) {
+ ERROR("%s: Could not convert mtd!\n", __func__);
+ spmc_shmem_obj_free(&spmc_shmem_obj_state, v1_1_obj);
+ goto err_arg;
+ }
+
+ /*
+ * We're finished with the v1.0 descriptor so free it
+ * and continue our checks with the new v1.1 descriptor.
+ */
+ mem_handle = obj->desc.handle;
+ spmc_shmem_obj_free(&spmc_shmem_obj_state, obj);
+ obj = spmc_shmem_obj_lookup(&spmc_shmem_obj_state, mem_handle);
+ if (obj == NULL) {
+ ERROR("%s: Failed to find converted descriptor.\n",
+ __func__);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ return spmc_ffa_error_return(smc_handle, ret);
+ }
+ }
+
+ /* Allow for platform specific operations to be performed. */
+ ret = plat_spmc_shmem_begin(&obj->desc);
+ if (ret != 0) {
+ goto err_arg;
+ }
+
+ SMC_RET8(smc_handle, FFA_SUCCESS_SMC32, 0, handle_low, handle_high, 0,
+ 0, 0, 0);
+
+err_bad_desc:
+err_arg:
+ spmc_shmem_obj_free(&spmc_shmem_obj_state, obj);
+ return spmc_ffa_error_return(smc_handle, ret);
+}
+
+/**
+ * spmc_ffa_mem_send - FFA_MEM_SHARE/LEND implementation.
+ * @client: Client state.
+ * @total_length: Total length of shared memory descriptor.
+ * @fragment_length: Length of fragment of shared memory descriptor passed in
+ * this call.
+ * @address: Not supported, must be 0.
+ * @page_count: Not supported, must be 0.
+ * @smc_handle: Handle passed to smc call. Used to return
+ * FFA_MEM_FRAG_RX or SMC_FC_FFA_SUCCESS.
+ *
+ * Implements a subset of the FF-A FFA_MEM_SHARE and FFA_MEM_LEND calls needed
+ * to share or lend memory from non-secure os to secure os (with no stream
+ * endpoints).
+ *
+ * Return: 0 on success, error code on failure.
+ */
+long spmc_ffa_mem_send(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t total_length,
+ uint32_t fragment_length,
+ uint64_t address,
+ uint32_t page_count,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+
+{
+ long ret;
+ struct spmc_shmem_obj *obj;
+ struct mailbox *mbox = spmc_get_mbox_desc(secure_origin);
+ ffa_mtd_flag32_t mtd_flag;
+ uint32_t ffa_version = get_partition_ffa_version(secure_origin);
+
+ if (address != 0U || page_count != 0U) {
+ WARN("%s: custom memory region for message not supported.\n",
+ __func__);
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ if (secure_origin) {
+ WARN("%s: unsupported share direction.\n", __func__);
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ /*
+ * Check if the descriptor is smaller than the v1.0 descriptor. The
+ * descriptor cannot be smaller than this structure.
+ */
+ if (fragment_length < sizeof(struct ffa_mtd_v1_0)) {
+ WARN("%s: bad first fragment size %u < %zu\n",
+ __func__, fragment_length, sizeof(struct ffa_mtd_v1_0));
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ if ((smc_fid & FUNCID_NUM_MASK) == FFA_FNUM_MEM_SHARE) {
+ mtd_flag = FFA_MTD_FLAG_TYPE_SHARE_MEMORY;
+ } else if ((smc_fid & FUNCID_NUM_MASK) == FFA_FNUM_MEM_LEND) {
+ mtd_flag = FFA_MTD_FLAG_TYPE_LEND_MEMORY;
+ } else {
+ WARN("%s: invalid memory management operation.\n", __func__);
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ spin_lock(&spmc_shmem_obj_state.lock);
+ obj = spmc_shmem_obj_alloc(&spmc_shmem_obj_state, total_length);
+ if (obj == NULL) {
+ ret = FFA_ERROR_NO_MEMORY;
+ goto err_unlock;
+ }
+
+ spin_lock(&mbox->lock);
+ ret = spmc_ffa_fill_desc(mbox, obj, fragment_length, mtd_flag,
+ ffa_version, handle);
+ spin_unlock(&mbox->lock);
+
+ spin_unlock(&spmc_shmem_obj_state.lock);
+ return ret;
+
+err_unlock:
+ spin_unlock(&spmc_shmem_obj_state.lock);
+ return spmc_ffa_error_return(handle, ret);
+}
+
+/**
+ * spmc_ffa_mem_frag_tx - FFA_MEM_FRAG_TX implementation.
+ * @client: Client state.
+ * @handle_low: Handle_low value returned from FFA_MEM_FRAG_RX.
+ * @handle_high: Handle_high value returned from FFA_MEM_FRAG_RX.
+ * @fragment_length: Length of fragments transmitted.
+ * @sender_id: Vmid of sender in bits [31:16]
+ * @smc_handle: Handle passed to smc call. Used to return
+ * FFA_MEM_FRAG_RX or SMC_FC_FFA_SUCCESS.
+ *
+ * Return: @smc_handle on success, error code on failure.
+ */
+long spmc_ffa_mem_frag_tx(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t handle_low,
+ uint64_t handle_high,
+ uint32_t fragment_length,
+ uint32_t sender_id,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ long ret;
+ uint32_t desc_sender_id;
+ uint32_t ffa_version = get_partition_ffa_version(secure_origin);
+ struct mailbox *mbox = spmc_get_mbox_desc(secure_origin);
+
+ struct spmc_shmem_obj *obj;
+ uint64_t mem_handle = handle_low | (((uint64_t)handle_high) << 32);
+
+ spin_lock(&spmc_shmem_obj_state.lock);
+
+ obj = spmc_shmem_obj_lookup(&spmc_shmem_obj_state, mem_handle);
+ if (obj == NULL) {
+ WARN("%s: invalid handle, 0x%lx, not a valid handle.\n",
+ __func__, mem_handle);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock;
+ }
+
+ desc_sender_id = (uint32_t)obj->desc.sender_id << 16;
+ if (sender_id != desc_sender_id) {
+ WARN("%s: invalid sender_id 0x%x != 0x%x\n", __func__,
+ sender_id, desc_sender_id);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock;
+ }
+
+ if (obj->desc_filled == obj->desc_size) {
+ WARN("%s: object desc already filled, %zu\n", __func__,
+ obj->desc_filled);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock;
+ }
+
+ spin_lock(&mbox->lock);
+ ret = spmc_ffa_fill_desc(mbox, obj, fragment_length, 0, ffa_version,
+ handle);
+ spin_unlock(&mbox->lock);
+
+ spin_unlock(&spmc_shmem_obj_state.lock);
+ return ret;
+
+err_unlock:
+ spin_unlock(&spmc_shmem_obj_state.lock);
+ return spmc_ffa_error_return(handle, ret);
+}
+
+/**
+ * spmc_ffa_mem_retrieve_set_ns_bit - Set the NS bit in the response descriptor
+ * if the caller implements a version greater
+ * than FF-A 1.0 or if they have requested
+ * the functionality.
+ * TODO: We are assuming that the caller is
+ * an SP. To support retrieval from the
+ * normal world this function will need to be
+ * expanded accordingly.
+ * @resp: Descriptor populated in callers RX buffer.
+ * @sp_ctx: Context of the calling SP.
+ */
+void spmc_ffa_mem_retrieve_set_ns_bit(struct ffa_mtd *resp,
+ struct secure_partition_desc *sp_ctx)
+{
+ if (sp_ctx->ffa_version > MAKE_FFA_VERSION(1, 0) ||
+ sp_ctx->ns_bit_requested) {
+ /*
+ * Currently memory senders must reside in the normal
+ * world, and we do not have the functionlaity to change
+ * the state of memory dynamically. Therefore we can always set
+ * the NS bit to 1.
+ */
+ resp->memory_region_attributes |= FFA_MEM_ATTR_NS_BIT;
+ }
+}
+
+/**
+ * spmc_ffa_mem_retrieve_req - FFA_MEM_RETRIEVE_REQ implementation.
+ * @smc_fid: FID of SMC
+ * @total_length: Total length of retrieve request descriptor if this is
+ * the first call. Otherwise (unsupported) must be 0.
+ * @fragment_length: Length of fragment of retrieve request descriptor passed
+ * in this call. Only @fragment_length == @length is
+ * supported by this implementation.
+ * @address: Not supported, must be 0.
+ * @page_count: Not supported, must be 0.
+ * @smc_handle: Handle passed to smc call. Used to return
+ * FFA_MEM_RETRIEVE_RESP.
+ *
+ * Implements a subset of the FF-A FFA_MEM_RETRIEVE_REQ call.
+ * Used by secure os to retrieve memory already shared by non-secure os.
+ * If the data does not fit in a single FFA_MEM_RETRIEVE_RESP message,
+ * the client must call FFA_MEM_FRAG_RX until the full response has been
+ * received.
+ *
+ * Return: @handle on success, error code on failure.
+ */
+long
+spmc_ffa_mem_retrieve_req(uint32_t smc_fid,
+ bool secure_origin,
+ uint32_t total_length,
+ uint32_t fragment_length,
+ uint64_t address,
+ uint32_t page_count,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ int ret;
+ size_t buf_size;
+ size_t copy_size = 0;
+ size_t min_desc_size;
+ size_t out_desc_size = 0;
+
+ /*
+ * Currently we are only accessing fields that are the same in both the
+ * v1.0 and v1.1 mtd struct therefore we can use a v1.1 struct directly
+ * here. We only need validate against the appropriate struct size.
+ */
+ struct ffa_mtd *resp;
+ const struct ffa_mtd *req;
+ struct spmc_shmem_obj *obj = NULL;
+ struct mailbox *mbox = spmc_get_mbox_desc(secure_origin);
+ uint32_t ffa_version = get_partition_ffa_version(secure_origin);
+ struct secure_partition_desc *sp_ctx = spmc_get_current_sp_ctx();
+
+ if (!secure_origin) {
+ WARN("%s: unsupported retrieve req direction.\n", __func__);
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ if (address != 0U || page_count != 0U) {
+ WARN("%s: custom memory region not supported.\n", __func__);
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ spin_lock(&mbox->lock);
+
+ req = mbox->tx_buffer;
+ resp = mbox->rx_buffer;
+ buf_size = mbox->rxtx_page_count * FFA_PAGE_SIZE;
+
+ if (mbox->rxtx_page_count == 0U) {
+ WARN("%s: buffer pair not registered.\n", __func__);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_mailbox;
+ }
+
+ if (mbox->state != MAILBOX_STATE_EMPTY) {
+ WARN("%s: RX Buffer is full! %d\n", __func__, mbox->state);
+ ret = FFA_ERROR_DENIED;
+ goto err_unlock_mailbox;
+ }
+
+ if (fragment_length != total_length) {
+ WARN("%s: fragmented retrieve request not supported.\n",
+ __func__);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_mailbox;
+ }
+
+ if (req->emad_count == 0U) {
+ WARN("%s: unsupported attribute desc count %u.\n",
+ __func__, obj->desc.emad_count);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_mailbox;
+ }
+
+ /* Determine the appropriate minimum descriptor size. */
+ if (ffa_version == MAKE_FFA_VERSION(1, 0)) {
+ min_desc_size = sizeof(struct ffa_mtd_v1_0);
+ } else {
+ min_desc_size = sizeof(struct ffa_mtd);
+ }
+ if (total_length < min_desc_size) {
+ WARN("%s: invalid length %u < %zu\n", __func__, total_length,
+ min_desc_size);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_mailbox;
+ }
+
+ spin_lock(&spmc_shmem_obj_state.lock);
+
+ obj = spmc_shmem_obj_lookup(&spmc_shmem_obj_state, req->handle);
+ if (obj == NULL) {
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+
+ if (obj->desc_filled != obj->desc_size) {
+ WARN("%s: incomplete object desc filled %zu < size %zu\n",
+ __func__, obj->desc_filled, obj->desc_size);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+
+ if (req->emad_count != 0U && req->sender_id != obj->desc.sender_id) {
+ WARN("%s: wrong sender id 0x%x != 0x%x\n",
+ __func__, req->sender_id, obj->desc.sender_id);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+
+ if (req->emad_count != 0U && req->tag != obj->desc.tag) {
+ WARN("%s: wrong tag 0x%lx != 0x%lx\n",
+ __func__, req->tag, obj->desc.tag);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+
+ if (req->emad_count != 0U && req->emad_count != obj->desc.emad_count) {
+ WARN("%s: mistmatch of endpoint counts %u != %u\n",
+ __func__, req->emad_count, obj->desc.emad_count);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+
+ /* Ensure the NS bit is set to 0 in the request. */
+ if ((req->memory_region_attributes & FFA_MEM_ATTR_NS_BIT) != 0U) {
+ WARN("%s: NS mem attributes flags MBZ.\n", __func__);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+
+ if (req->flags != 0U) {
+ if ((req->flags & FFA_MTD_FLAG_TYPE_MASK) !=
+ (obj->desc.flags & FFA_MTD_FLAG_TYPE_MASK)) {
+ /*
+ * If the retrieve request specifies the memory
+ * transaction ensure it matches what we expect.
+ */
+ WARN("%s: wrong mem transaction flags %x != %x\n",
+ __func__, req->flags, obj->desc.flags);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+
+ if (req->flags != FFA_MTD_FLAG_TYPE_SHARE_MEMORY &&
+ req->flags != FFA_MTD_FLAG_TYPE_LEND_MEMORY) {
+ /*
+ * Current implementation does not support donate and
+ * it supports no other flags.
+ */
+ WARN("%s: invalid flags 0x%x\n", __func__, req->flags);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+ }
+
+ /* Validate the caller is a valid participant. */
+ if (!spmc_shmem_obj_validate_id(&obj->desc, sp_ctx->sp_id)) {
+ WARN("%s: Invalid endpoint ID (0x%x).\n",
+ __func__, sp_ctx->sp_id);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+
+ /* Validate that the provided emad offset and structure is valid.*/
+ for (size_t i = 0; i < req->emad_count; i++) {
+ size_t emad_size;
+ struct ffa_emad_v1_0 *emad;
+
+ emad = spmc_shmem_obj_get_emad(req, i, ffa_version,
+ &emad_size);
+ if (emad == NULL) {
+ WARN("%s: invalid emad structure.\n", __func__);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+
+ if ((uintptr_t) emad >= (uintptr_t)
+ ((uint8_t *) req + total_length)) {
+ WARN("Invalid emad access.\n");
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+ }
+
+ /*
+ * Validate all the endpoints match in the case of multiple
+ * borrowers. We don't mandate that the order of the borrowers
+ * must match in the descriptors therefore check to see if the
+ * endpoints match in any order.
+ */
+ for (size_t i = 0; i < req->emad_count; i++) {
+ bool found = false;
+ size_t emad_size;
+ struct ffa_emad_v1_0 *emad;
+ struct ffa_emad_v1_0 *other_emad;
+
+ emad = spmc_shmem_obj_get_emad(req, i, ffa_version,
+ &emad_size);
+ if (emad == NULL) {
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+
+ for (size_t j = 0; j < obj->desc.emad_count; j++) {
+ other_emad = spmc_shmem_obj_get_emad(
+ &obj->desc, j, MAKE_FFA_VERSION(1, 1),
+ &emad_size);
+
+ if (other_emad == NULL) {
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+
+ if (req->emad_count &&
+ emad->mapd.endpoint_id ==
+ other_emad->mapd.endpoint_id) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ WARN("%s: invalid receiver id (0x%x).\n",
+ __func__, emad->mapd.endpoint_id);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+ }
+
+ mbox->state = MAILBOX_STATE_FULL;
+
+ if (req->emad_count != 0U) {
+ obj->in_use++;
+ }
+
+ /*
+ * If the caller is v1.0 convert the descriptor, otherwise copy
+ * directly.
+ */
+ if (ffa_version == MAKE_FFA_VERSION(1, 0)) {
+ ret = spmc_populate_ffa_v1_0_descriptor(resp, obj, buf_size, 0,
+ &copy_size,
+ &out_desc_size);
+ if (ret != 0U) {
+ ERROR("%s: Failed to process descriptor.\n", __func__);
+ goto err_unlock_all;
+ }
+ } else {
+ copy_size = MIN(obj->desc_size, buf_size);
+ out_desc_size = obj->desc_size;
+
+ memcpy(resp, &obj->desc, copy_size);
+ }
+
+ /* Set the NS bit in the response if applicable. */
+ spmc_ffa_mem_retrieve_set_ns_bit(resp, sp_ctx);
+
+ spin_unlock(&spmc_shmem_obj_state.lock);
+ spin_unlock(&mbox->lock);
+
+ SMC_RET8(handle, FFA_MEM_RETRIEVE_RESP, out_desc_size,
+ copy_size, 0, 0, 0, 0, 0);
+
+err_unlock_all:
+ spin_unlock(&spmc_shmem_obj_state.lock);
+err_unlock_mailbox:
+ spin_unlock(&mbox->lock);
+ return spmc_ffa_error_return(handle, ret);
+}
+
+/**
+ * spmc_ffa_mem_frag_rx - FFA_MEM_FRAG_RX implementation.
+ * @client: Client state.
+ * @handle_low: Handle passed to &FFA_MEM_RETRIEVE_REQ. Bit[31:0].
+ * @handle_high: Handle passed to &FFA_MEM_RETRIEVE_REQ. Bit[63:32].
+ * @fragment_offset: Byte offset in descriptor to resume at.
+ * @sender_id: Bit[31:16]: Endpoint id of sender if client is a
+ * hypervisor. 0 otherwise.
+ * @smc_handle: Handle passed to smc call. Used to return
+ * FFA_MEM_FRAG_TX.
+ *
+ * Return: @smc_handle on success, error code on failure.
+ */
+long spmc_ffa_mem_frag_rx(uint32_t smc_fid,
+ bool secure_origin,
+ uint32_t handle_low,
+ uint32_t handle_high,
+ uint32_t fragment_offset,
+ uint32_t sender_id,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ int ret;
+ void *src;
+ size_t buf_size;
+ size_t copy_size;
+ size_t full_copy_size;
+ uint32_t desc_sender_id;
+ struct mailbox *mbox = spmc_get_mbox_desc(secure_origin);
+ uint64_t mem_handle = handle_low | (((uint64_t)handle_high) << 32);
+ struct spmc_shmem_obj *obj;
+ uint32_t ffa_version = get_partition_ffa_version(secure_origin);
+
+ if (!secure_origin) {
+ WARN("%s: can only be called from swld.\n",
+ __func__);
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ spin_lock(&spmc_shmem_obj_state.lock);
+
+ obj = spmc_shmem_obj_lookup(&spmc_shmem_obj_state, mem_handle);
+ if (obj == NULL) {
+ WARN("%s: invalid handle, 0x%lx, not a valid handle.\n",
+ __func__, mem_handle);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_shmem;
+ }
+
+ desc_sender_id = (uint32_t)obj->desc.sender_id << 16;
+ if (sender_id != 0U && sender_id != desc_sender_id) {
+ WARN("%s: invalid sender_id 0x%x != 0x%x\n", __func__,
+ sender_id, desc_sender_id);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_shmem;
+ }
+
+ if (fragment_offset >= obj->desc_size) {
+ WARN("%s: invalid fragment_offset 0x%x >= 0x%zx\n",
+ __func__, fragment_offset, obj->desc_size);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_shmem;
+ }
+
+ spin_lock(&mbox->lock);
+
+ if (mbox->rxtx_page_count == 0U) {
+ WARN("%s: buffer pair not registered.\n", __func__);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+
+ if (mbox->state != MAILBOX_STATE_EMPTY) {
+ WARN("%s: RX Buffer is full!\n", __func__);
+ ret = FFA_ERROR_DENIED;
+ goto err_unlock_all;
+ }
+
+ buf_size = mbox->rxtx_page_count * FFA_PAGE_SIZE;
+
+ mbox->state = MAILBOX_STATE_FULL;
+
+ /*
+ * If the caller is v1.0 convert the descriptor, otherwise copy
+ * directly.
+ */
+ if (ffa_version == MAKE_FFA_VERSION(1, 0)) {
+ size_t out_desc_size;
+
+ ret = spmc_populate_ffa_v1_0_descriptor(mbox->rx_buffer, obj,
+ buf_size,
+ fragment_offset,
+ &copy_size,
+ &out_desc_size);
+ if (ret != 0U) {
+ ERROR("%s: Failed to process descriptor.\n", __func__);
+ goto err_unlock_all;
+ }
+ } else {
+ full_copy_size = obj->desc_size - fragment_offset;
+ copy_size = MIN(full_copy_size, buf_size);
+
+ src = &obj->desc;
+
+ memcpy(mbox->rx_buffer, src + fragment_offset, copy_size);
+ }
+
+ spin_unlock(&mbox->lock);
+ spin_unlock(&spmc_shmem_obj_state.lock);
+
+ SMC_RET8(handle, FFA_MEM_FRAG_TX, handle_low, handle_high,
+ copy_size, sender_id, 0, 0, 0);
+
+err_unlock_all:
+ spin_unlock(&mbox->lock);
+err_unlock_shmem:
+ spin_unlock(&spmc_shmem_obj_state.lock);
+ return spmc_ffa_error_return(handle, ret);
+}
+
+/**
+ * spmc_ffa_mem_relinquish - FFA_MEM_RELINQUISH implementation.
+ * @client: Client state.
+ *
+ * Implements a subset of the FF-A FFA_MEM_RELINQUISH call.
+ * Used by secure os release previously shared memory to non-secure os.
+ *
+ * The handle to release must be in the client's (secure os's) transmit buffer.
+ *
+ * Return: 0 on success, error code on failure.
+ */
+int spmc_ffa_mem_relinquish(uint32_t smc_fid,
+ bool secure_origin,
+ uint32_t handle_low,
+ uint32_t handle_high,
+ uint32_t fragment_offset,
+ uint32_t sender_id,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ int ret;
+ struct mailbox *mbox = spmc_get_mbox_desc(secure_origin);
+ struct spmc_shmem_obj *obj;
+ const struct ffa_mem_relinquish_descriptor *req;
+ struct secure_partition_desc *sp_ctx = spmc_get_current_sp_ctx();
+
+ if (!secure_origin) {
+ WARN("%s: unsupported relinquish direction.\n", __func__);
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ spin_lock(&mbox->lock);
+
+ if (mbox->rxtx_page_count == 0U) {
+ WARN("%s: buffer pair not registered.\n", __func__);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_mailbox;
+ }
+
+ req = mbox->tx_buffer;
+
+ if (req->flags != 0U) {
+ WARN("%s: unsupported flags 0x%x\n", __func__, req->flags);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_mailbox;
+ }
+
+ if (req->endpoint_count == 0) {
+ WARN("%s: endpoint count cannot be 0.\n", __func__);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_mailbox;
+ }
+
+ spin_lock(&spmc_shmem_obj_state.lock);
+
+ obj = spmc_shmem_obj_lookup(&spmc_shmem_obj_state, req->handle);
+ if (obj == NULL) {
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+
+ /*
+ * Validate the endpoint ID was populated correctly. We don't currently
+ * support proxy endpoints so the endpoint count should always be 1.
+ */
+ if (req->endpoint_count != 1U) {
+ WARN("%s: unsupported endpoint count %u != 1\n", __func__,
+ req->endpoint_count);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+
+ /* Validate provided endpoint ID matches the partition ID. */
+ if (req->endpoint_array[0] != sp_ctx->sp_id) {
+ WARN("%s: invalid endpoint ID %u != %u\n", __func__,
+ req->endpoint_array[0], sp_ctx->sp_id);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+
+ /* Validate the caller is a valid participant. */
+ if (!spmc_shmem_obj_validate_id(&obj->desc, sp_ctx->sp_id)) {
+ WARN("%s: Invalid endpoint ID (0x%x).\n",
+ __func__, req->endpoint_array[0]);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+
+ if (obj->in_use == 0U) {
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+ obj->in_use--;
+
+ spin_unlock(&spmc_shmem_obj_state.lock);
+ spin_unlock(&mbox->lock);
+
+ SMC_RET1(handle, FFA_SUCCESS_SMC32);
+
+err_unlock_all:
+ spin_unlock(&spmc_shmem_obj_state.lock);
+err_unlock_mailbox:
+ spin_unlock(&mbox->lock);
+ return spmc_ffa_error_return(handle, ret);
+}
+
+/**
+ * spmc_ffa_mem_reclaim - FFA_MEM_RECLAIM implementation.
+ * @client: Client state.
+ * @handle_low: Unique handle of shared memory object to reclaim. Bit[31:0].
+ * @handle_high: Unique handle of shared memory object to reclaim.
+ * Bit[63:32].
+ * @flags: Unsupported, ignored.
+ *
+ * Implements a subset of the FF-A FFA_MEM_RECLAIM call.
+ * Used by non-secure os reclaim memory previously shared with secure os.
+ *
+ * Return: 0 on success, error code on failure.
+ */
+int spmc_ffa_mem_reclaim(uint32_t smc_fid,
+ bool secure_origin,
+ uint32_t handle_low,
+ uint32_t handle_high,
+ uint32_t mem_flags,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ int ret;
+ struct spmc_shmem_obj *obj;
+ uint64_t mem_handle = handle_low | (((uint64_t)handle_high) << 32);
+
+ if (secure_origin) {
+ WARN("%s: unsupported reclaim direction.\n", __func__);
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ if (mem_flags != 0U) {
+ WARN("%s: unsupported flags 0x%x\n", __func__, mem_flags);
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
+ spin_lock(&spmc_shmem_obj_state.lock);
+
+ obj = spmc_shmem_obj_lookup(&spmc_shmem_obj_state, mem_handle);
+ if (obj == NULL) {
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock;
+ }
+ if (obj->in_use != 0U) {
+ ret = FFA_ERROR_DENIED;
+ goto err_unlock;
+ }
+
+ if (obj->desc_filled != obj->desc_size) {
+ WARN("%s: incomplete object desc filled %zu < size %zu\n",
+ __func__, obj->desc_filled, obj->desc_size);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock;
+ }
+
+ /* Allow for platform specific operations to be performed. */
+ ret = plat_spmc_shmem_reclaim(&obj->desc);
+ if (ret != 0) {
+ goto err_unlock;
+ }
+
+ spmc_shmem_obj_free(&spmc_shmem_obj_state, obj);
+ spin_unlock(&spmc_shmem_obj_state.lock);
+
+ SMC_RET1(handle, FFA_SUCCESS_SMC32);
+
+err_unlock:
+ spin_unlock(&spmc_shmem_obj_state.lock);
+ return spmc_ffa_error_return(handle, ret);
+}
diff --git a/services/std_svc/spm/el3_spmc/spmc_shared_mem.h b/services/std_svc/spm/el3_spmc/spmc_shared_mem.h
new file mode 100644
index 0000000..839f7a1
--- /dev/null
+++ b/services/std_svc/spm/el3_spmc/spmc_shared_mem.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPMC_SHARED_MEM_H
+#define SPMC_SHARED_MEM_H
+
+#include <services/el3_spmc_ffa_memory.h>
+
+/**
+ * struct ffa_mem_relinquish_descriptor - Relinquish request descriptor.
+ * @handle:
+ * Id of shared memory object to relinquish.
+ * @flags:
+ * If bit 0 is set clear memory after unmapping from borrower. Must be 0
+ * for share. Bit[1]: Time slicing. Not supported, must be 0. All other
+ * bits are reserved 0.
+ * @endpoint_count:
+ * Number of entries in @endpoint_array.
+ * @endpoint_array:
+ * Array of endpoint ids.
+ */
+struct ffa_mem_relinquish_descriptor {
+ uint64_t handle;
+ uint32_t flags;
+ uint32_t endpoint_count;
+ ffa_endpoint_id16_t endpoint_array[];
+};
+CASSERT(sizeof(struct ffa_mem_relinquish_descriptor) == 16,
+ assert_ffa_mem_relinquish_descriptor_size_mismatch);
+
+/**
+ * struct spmc_shmem_obj_state - Global state.
+ * @data: Backing store for spmc_shmem_obj objects.
+ * @data_size: The size allocated for the backing store.
+ * @allocated: Number of bytes allocated in @data.
+ * @next_handle: Handle used for next allocated object.
+ * @lock: Lock protecting all state in this file.
+ */
+struct spmc_shmem_obj_state {
+ uint8_t *data;
+ size_t data_size;
+ size_t allocated;
+ uint64_t next_handle;
+ spinlock_t lock;
+};
+
+extern struct spmc_shmem_obj_state spmc_shmem_obj_state;
+extern int plat_spmc_shmem_begin(struct ffa_mtd *desc);
+extern int plat_spmc_shmem_reclaim(struct ffa_mtd *desc);
+
+long spmc_ffa_mem_send(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t total_length,
+ uint32_t fragment_length,
+ uint64_t address,
+ uint32_t page_count,
+ void *cookie,
+ void *handle,
+ uint64_t flags);
+
+long spmc_ffa_mem_frag_tx(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t handle_low,
+ uint64_t handle_high,
+ uint32_t fragment_length,
+ uint32_t sender_id,
+ void *cookie,
+ void *handle,
+ uint64_t flags);
+
+long spmc_ffa_mem_retrieve_req(uint32_t smc_fid,
+ bool secure_origin,
+ uint32_t total_length,
+ uint32_t fragment_length,
+ uint64_t address,
+ uint32_t page_count,
+ void *cookie,
+ void *handle,
+ uint64_t flags);
+
+long spmc_ffa_mem_frag_rx(uint32_t smc_fid,
+ bool secure_origin,
+ uint32_t handle_low,
+ uint32_t handle_high,
+ uint32_t fragment_offset,
+ uint32_t sender_id,
+ void *cookie,
+ void *handle,
+ uint64_t flags);
+
+
+int spmc_ffa_mem_relinquish(uint32_t smc_fid,
+ bool secure_origin,
+ uint32_t handle_low,
+ uint32_t handle_high,
+ uint32_t fragment_offset,
+ uint32_t sender_id,
+ void *cookie,
+ void *handle,
+ uint64_t flags);
+
+int spmc_ffa_mem_reclaim(uint32_t smc_fid,
+ bool secure_origin,
+ uint32_t handle_low,
+ uint32_t handle_high,
+ uint32_t mem_flags,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags);
+
+#endif /* SPMC_SHARED_MEM_H */
diff --git a/services/std_svc/spm/spm_mm/aarch64/spm_mm_shim_exceptions.S b/services/std_svc/spm/spm_mm/aarch64/spm_mm_shim_exceptions.S
new file mode 100644
index 0000000..836f75c
--- /dev/null
+++ b/services/std_svc/spm/spm_mm/aarch64/spm_mm_shim_exceptions.S
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <context.h>
+
+/* -----------------------------------------------------------------------------
+ * 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
+ exception_return
+
+ /* 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
diff --git a/services/std_svc/spm/spm_mm/spm_mm.mk b/services/std_svc/spm/spm_mm/spm_mm.mk
new file mode 100644
index 0000000..f6691c3
--- /dev/null
+++ b/services/std_svc/spm/spm_mm/spm_mm.mk
@@ -0,0 +1,34 @@
+#
+# Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifneq (${SPD},none)
+ $(error "Error: SPD and SPM_MM are incompatible build options.")
+endif
+ifneq (${ARCH},aarch64)
+ $(error "Error: SPM_MM is only supported on aarch64.")
+endif
+ifeq (${ENABLE_SVE_FOR_NS},1)
+ $(error "Error: SPM_MM is not compatible with ENABLE_SVE_FOR_NS")
+endif
+ifeq (${ENABLE_SME_FOR_NS},1)
+ $(error "Error: SPM_MM is not compatible with ENABLE_SME_FOR_NS")
+endif
+ifeq (${CTX_INCLUDE_FPREGS},0)
+ $(warning "Warning: SPM_MM: CTX_INCLUDE_FPREGS is set to 0")
+endif
+
+SPM_MM_SOURCES := $(addprefix services/std_svc/spm/spm_mm/, \
+ ${ARCH}/spm_mm_shim_exceptions.S \
+ spm_mm_main.c \
+ spm_mm_setup.c \
+ spm_mm_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
diff --git a/services/std_svc/spm/spm_mm/spm_mm_main.c b/services/std_svc/spm/spm_mm/spm_mm_main.c
new file mode 100644
index 0000000..8525cd2
--- /dev/null
+++ b/services/std_svc/spm/spm_mm/spm_mm_main.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <bl31/bl31.h>
+#include <bl31/ehf.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/smccc.h>
+#include <lib/spinlock.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#include <services/spm_mm_partition.h>
+#include <services/spm_mm_svc.h>
+#include <smccc_helpers.h>
+
+#include "spm_common.h"
+#include "spm_mm_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 *ctx)
+{
+ uint64_t rc;
+
+ assert(ctx != NULL);
+
+ /* Assign the context of the SP to this CPU */
+ cm_set_context(&(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(&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_mm_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_mm_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;
+
+#if CTX_INCLUDE_FPREGS
+ /*
+ * SP runs to completion, no need to restore FP registers of secure context.
+ * Save FP registers only for non secure context.
+ */
+ fpregs_context_save(get_fpregs_ctx(cm_get_context(NON_SECURE)));
+#endif
+
+ /* 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);
+
+#if CTX_INCLUDE_FPREGS
+ /*
+ * SP runs to completion, no need to save FP registers of secure context.
+ * Restore only non secure world FP registers.
+ */
+ fpregs_context_restore(get_fpregs_ctx(cm_get_context(NON_SECURE)));
+#endif
+
+ 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_MM_INVALID_PARAMETER);
+ }
+
+ if (comm_buffer_address == 0U) {
+ ERROR("MM_COMMUNICATE: comm_buffer_address is zero\n");
+ SMC_RET1(handle, SPM_MM_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_mm_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_mm_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_MM_VERSION_AARCH32:
+ SMC_RET1(handle, SPM_MM_VERSION_COMPILED);
+
+ case MM_SP_EVENT_COMPLETE_AARCH64:
+ spm_sp_synchronous_exit(x1);
+
+ case MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64:
+ INFO("Received MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
+
+ if (sp_ctx.state != SP_STATE_RESET) {
+ WARN("MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
+ SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
+ }
+ SMC_RET1(handle,
+ spm_memory_attributes_get_smc_handler(
+ &sp_ctx, x1));
+
+ case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
+ INFO("Received MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
+
+ if (sp_ctx.state != SP_STATE_RESET) {
+ WARN("MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
+ SMC_RET1(handle, SPM_MM_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 MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64:
+ case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
+ /* SMC interfaces reserved for secure callers. */
+ SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
+
+ default:
+ break;
+ }
+ }
+
+ SMC_RET1(handle, SMC_UNK);
+}
diff --git a/services/std_svc/spm/spm_mm/spm_mm_private.h b/services/std_svc/spm/spm_mm/spm_mm_private.h
new file mode 100644
index 0000000..0eff1c0
--- /dev/null
+++ b/services/std_svc/spm/spm_mm/spm_mm_private.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPM_MM_PRIVATE_H
+#define SPM_MM_PRIVATE_H
+
+#include <context.h>
+#include "spm_common.h"
+
+/*******************************************************************************
+ * 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 <stdint.h>
+
+#include <lib/spinlock.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+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;
+
+
+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_MM_PRIVATE_H */
diff --git a/services/std_svc/spm/spm_mm/spm_mm_setup.c b/services/std_svc/spm/spm_mm/spm_mm_setup.c
new file mode 100644
index 0000000..04dc212
--- /dev/null
+++ b/services/std_svc/spm/spm_mm/spm_mm_setup.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <context.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <platform_def.h>
+#include <plat/common/common_def.h>
+#include <plat/common/platform.h>
+#include <services/spm_mm_partition.h>
+
+#include "spm_common.h"
+#include "spm_mm_private.h"
+#include "spm_mm_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);
+
+ /* Pointer to the MP information from the platform port. */
+ const spm_mm_boot_info_t *sp_boot_info =
+ plat_get_secure_partition_boot_info(NULL);
+
+ /*
+ * 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_boot_info->sp_image_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 = sp_boot_info->sp_shared_buf_base;
+ ep_info.args.arg1 = sp_boot_info->sp_shared_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,
+ sp_boot_info->sp_stack_base + sp_boot_info->sp_pcpu_stack_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((sp_boot_info->sp_ns_comm_buf_base & max_granule_mask) == 0);
+
+ /* Size must be a multiple of the max granularity */
+ assert((sp_boot_info->sp_ns_comm_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_el1_sysregs_ctx(ctx), CTX_MAIR_EL1,
+ mmu_cfg_params[MMU_CFG_MAIR]);
+
+ write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_TCR_EL1,
+ mmu_cfg_params[MMU_CFG_TCR]);
+
+ write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_TTBR0_EL1,
+ mmu_cfg_params[MMU_CFG_TTBR0]);
+
+ /* Setup SCTLR_EL1 */
+ u_register_t sctlr_el1 = read_ctx_reg(get_el1_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 |
+ /* Don't change PSTATE.PAN on taking an exception to EL1 */
+ SCTLR_SPAN_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_el1_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_el1);
+
+ /*
+ * Setup other system registers
+ * ----------------------------
+ */
+
+ /* Shim Exception Vector Base Address */
+ write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_VBAR_EL1,
+ SPM_SHIM_EXCEPTIONS_PTR);
+
+ write_ctx_reg(get_el1_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_el1_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 *) sp_boot_info->sp_shared_buf_base;
+
+ /* Copy the boot information into the shared buffer with the SP. */
+ assert((uintptr_t)shared_buf_ptr + sizeof(spm_mm_boot_info_t)
+ <= (sp_boot_info->sp_shared_buf_base + sp_boot_info->sp_shared_buf_size));
+
+ assert(sp_boot_info->sp_shared_buf_base <=
+ (UINTPTR_MAX - sp_boot_info->sp_shared_buf_size + 1));
+
+ assert(sp_boot_info != NULL);
+
+ memcpy((void *) shared_buf_ptr, (const void *) sp_boot_info,
+ sizeof(spm_mm_boot_info_t));
+
+ /* Pointer to the MP information from the platform port. */
+ spm_mm_mp_info_t *sp_mp_info =
+ ((spm_mm_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.
+ */
+ ((spm_mm_boot_info_t *) shared_buf_ptr)->mp_info =
+ (spm_mm_mp_info_t *) ((uintptr_t)shared_buf_ptr
+ + sizeof(spm_mm_boot_info_t));
+
+ /*
+ * Update the shared buffer pointer to where the MP information for the
+ * payload will be populated
+ */
+ shared_buf_ptr = ((spm_mm_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
+ <= (sp_boot_info->sp_shared_buf_base + sp_boot_info->sp_shared_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 = (spm_mm_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;
+ }
+}
diff --git a/services/std_svc/spm/spm_mm/spm_mm_shim_private.h b/services/std_svc/spm/spm_mm/spm_mm_shim_private.h
new file mode 100644
index 0000000..f69c748
--- /dev/null
+++ b/services/std_svc/spm/spm_mm/spm_mm_shim_private.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPM_MM_SHIM_PRIVATE_H
+#define SPM_MM_SHIM_PRIVATE_H
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+/* 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_MM_SHIM_PRIVATE_H */
diff --git a/services/std_svc/spm/spm_mm/spm_mm_xlat.c b/services/std_svc/spm/spm_mm/spm_mm_xlat.c
new file mode 100644
index 0000000..6261016
--- /dev/null
+++ b/services/std_svc/spm/spm_mm/spm_mm_xlat.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <errno.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <platform_def.h>
+#include <plat/common/platform.h>
+#include <services/spm_mm_partition.h>
+#include <services/spm_mm_svc.h>
+
+#include "spm_mm_private.h"
+#include "spm_mm_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
+#ifndef PLAT_SP_IMAGE_BASE_XLAT_SECTION_NAME
+#define PLAT_SP_IMAGE_BASE_XLAT_SECTION_NAME ".bss"
+#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,
+ PLAT_SP_IMAGE_BASE_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 & MM_SP_MEMORY_ATTRIBUTES_ACCESS_MASK)
+ >> MM_SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT;
+
+ if (access == MM_SP_MEMORY_ATTRIBUTES_ACCESS_RW) {
+ tf_attr |= MT_RW | MT_USER;
+ } else if (access == MM_SP_MEMORY_ATTRIBUTES_ACCESS_RO) {
+ tf_attr |= MT_RO | MT_USER;
+ } else {
+ /* Other values are reserved. */
+ assert(access == MM_SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS);
+ /* The only requirement is that there's no access from EL0 */
+ tf_attr |= MT_RO | MT_PRIVILEGED;
+ }
+
+ if ((attributes & MM_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 = MM_SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS;
+ } else {
+ if ((attr & MT_RW) != 0) {
+ assert(MT_TYPE(attr) != MT_DEVICE);
+ data_access = MM_SP_MEMORY_ATTRIBUTES_ACCESS_RW;
+ } else {
+ data_access = MM_SP_MEMORY_ATTRIBUTES_ACCESS_RO;
+ }
+ }
+
+ smc_attr |= (data_access & MM_SP_MEMORY_ATTRIBUTES_ACCESS_MASK)
+ << MM_SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT;
+
+ if ((attr & MT_EXECUTE_NEVER) != 0U) {
+ smc_attr |= MM_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_MM_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_MM_SUCCESS : SPM_MM_INVALID_PARAMETER;
+}
diff --git a/services/std_svc/spmd/aarch64/spmd_helpers.S b/services/std_svc/spmd/aarch64/spmd_helpers.S
new file mode 100644
index 0000000..d7bffca
--- /dev/null
+++ b/services/std_svc/spmd/aarch64/spmd_helpers.S
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include "../spmd_private.h"
+
+ .global spmd_spm_core_enter
+ .global spmd_spm_core_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 spmd_spm_core_enter
+ /* Make space for the registers that we're going to save */
+ mov x3, sp
+ str x3, [x0, #0]
+ sub sp, sp, #SPMD_C_RT_CTX_SIZE
+
+ /* Save callee-saved registers on to the stack */
+ stp x19, x20, [sp, #SPMD_C_RT_CTX_X19]
+ stp x21, x22, [sp, #SPMD_C_RT_CTX_X21]
+ stp x23, x24, [sp, #SPMD_C_RT_CTX_X23]
+ stp x25, x26, [sp, #SPMD_C_RT_CTX_X25]
+ stp x27, x28, [sp, #SPMD_C_RT_CTX_X27]
+ stp x29, x30, [sp, #SPMD_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 spmd_spm_core_enter
+
+ /* ---------------------------------------------------------------------
+ * This function is called with 'x0' pointing to a C runtime context.
+ * 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 spmd_spm_core_exit
+ /* Restore the previous stack */
+ mov sp, x0
+
+ /* Restore callee-saved registers on to the stack */
+ ldp x19, x20, [x0, #(SPMD_C_RT_CTX_X19 - SPMD_C_RT_CTX_SIZE)]
+ ldp x21, x22, [x0, #(SPMD_C_RT_CTX_X21 - SPMD_C_RT_CTX_SIZE)]
+ ldp x23, x24, [x0, #(SPMD_C_RT_CTX_X23 - SPMD_C_RT_CTX_SIZE)]
+ ldp x25, x26, [x0, #(SPMD_C_RT_CTX_X25 - SPMD_C_RT_CTX_SIZE)]
+ ldp x27, x28, [x0, #(SPMD_C_RT_CTX_X27 - SPMD_C_RT_CTX_SIZE)]
+ ldp x29, x30, [x0, #(SPMD_C_RT_CTX_X29 - SPMD_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 spmd_spm_core_exit
diff --git a/services/std_svc/spmd/spmd.mk b/services/std_svc/spmd/spmd.mk
new file mode 100644
index 0000000..8efbdc8
--- /dev/null
+++ b/services/std_svc/spmd/spmd.mk
@@ -0,0 +1,26 @@
+#
+# Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifneq (${ARCH},aarch64)
+ $(error "Error: SPMD is only supported on aarch64.")
+endif
+
+ifeq (${ENABLE_SME_FOR_NS},1)
+ $(error "Error: SPMD is not compatible with ENABLE_SME_FOR_NS")
+endif
+
+SPMD_SOURCES += $(addprefix services/std_svc/spmd/, \
+ ${ARCH}/spmd_helpers.S \
+ spmd_pm.c \
+ spmd_main.c)
+
+# Let the top-level Makefile know that we intend to include a BL32 image
+NEED_BL32 := yes
+
+# Enable dynamic memory mapping
+# The SPMD component maps the SPMC DTB within BL31 virtual space.
+PLAT_XLAT_TABLES_DYNAMIC := 1
+$(eval $(call add_define,PLAT_XLAT_TABLES_DYNAMIC))
diff --git a/services/std_svc/spmd/spmd_main.c b/services/std_svc/spmd/spmd_main.c
new file mode 100644
index 0000000..7e6c89d
--- /dev/null
+++ b/services/std_svc/spmd/spmd_main.c
@@ -0,0 +1,937 @@
+/*
+ * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <arch/aarch64/arch_features.h>
+#include <bl31/bl31.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/smccc.h>
+#include <lib/spinlock.h>
+#include <lib/utils.h>
+#include <plat/common/common_def.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <services/ffa_svc.h>
+#include <services/spmc_svc.h>
+#include <services/spmd_svc.h>
+#include <smccc_helpers.h>
+#include "spmd_private.h"
+
+/*******************************************************************************
+ * SPM Core context information.
+ ******************************************************************************/
+static spmd_spm_core_context_t spm_core_context[PLATFORM_CORE_COUNT];
+
+/*******************************************************************************
+ * SPM Core attribute information is read from its manifest if the SPMC is not
+ * at EL3. Else, it is populated from the SPMC directly.
+ ******************************************************************************/
+static spmc_manifest_attribute_t spmc_attrs;
+
+/*******************************************************************************
+ * SPM Core entry point information. Discovered on the primary core and reused
+ * on secondary cores.
+ ******************************************************************************/
+static entry_point_info_t *spmc_ep_info;
+
+/*******************************************************************************
+ * SPM Core context on CPU based on mpidr.
+ ******************************************************************************/
+spmd_spm_core_context_t *spmd_get_context_by_mpidr(uint64_t mpidr)
+{
+ int core_idx = plat_core_pos_by_mpidr(mpidr);
+
+ if (core_idx < 0) {
+ ERROR("Invalid mpidr: %" PRIx64 ", returned ID: %d\n", mpidr, core_idx);
+ panic();
+ }
+
+ return &spm_core_context[core_idx];
+}
+
+/*******************************************************************************
+ * SPM Core context on current CPU get helper.
+ ******************************************************************************/
+spmd_spm_core_context_t *spmd_get_context(void)
+{
+ return spmd_get_context_by_mpidr(read_mpidr());
+}
+
+/*******************************************************************************
+ * SPM Core ID getter.
+ ******************************************************************************/
+uint16_t spmd_spmc_id_get(void)
+{
+ return spmc_attrs.spmc_id;
+}
+
+/*******************************************************************************
+ * Static function declaration.
+ ******************************************************************************/
+static int32_t spmd_init(void);
+static int spmd_spmc_init(void *pm_addr);
+static uint64_t spmd_ffa_error_return(void *handle,
+ int error_code);
+static uint64_t spmd_smc_forward(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags);
+
+/******************************************************************************
+ * Builds an SPMD to SPMC direct message request.
+ *****************************************************************************/
+void spmd_build_spmc_message(gp_regs_t *gpregs, uint8_t target_func,
+ unsigned long long message)
+{
+ write_ctx_reg(gpregs, CTX_GPREG_X0, FFA_MSG_SEND_DIRECT_REQ_SMC32);
+ write_ctx_reg(gpregs, CTX_GPREG_X1,
+ (SPMD_DIRECT_MSG_ENDPOINT_ID << FFA_DIRECT_MSG_SOURCE_SHIFT) |
+ spmd_spmc_id_get());
+ write_ctx_reg(gpregs, CTX_GPREG_X2, BIT(31) | target_func);
+ write_ctx_reg(gpregs, CTX_GPREG_X3, message);
+}
+
+
+/*******************************************************************************
+ * This function takes an SPMC context pointer and performs a synchronous
+ * SPMC entry.
+ ******************************************************************************/
+uint64_t spmd_spm_core_sync_entry(spmd_spm_core_context_t *spmc_ctx)
+{
+ uint64_t rc;
+
+ assert(spmc_ctx != NULL);
+
+ cm_set_context(&(spmc_ctx->cpu_ctx), SECURE);
+
+ /* Restore the context assigned above */
+#if SPMD_SPM_AT_SEL2
+ cm_el2_sysregs_context_restore(SECURE);
+#else
+ cm_el1_sysregs_context_restore(SECURE);
+#endif
+ cm_set_next_eret_context(SECURE);
+
+ /* Enter SPMC */
+ rc = spmd_spm_core_enter(&spmc_ctx->c_rt_ctx);
+
+ /* Save secure state */
+#if SPMD_SPM_AT_SEL2
+ cm_el2_sysregs_context_save(SECURE);
+#else
+ cm_el1_sysregs_context_save(SECURE);
+#endif
+
+ return rc;
+}
+
+/*******************************************************************************
+ * This function returns to the place where spmd_spm_core_sync_entry() was
+ * called originally.
+ ******************************************************************************/
+__dead2 void spmd_spm_core_sync_exit(uint64_t rc)
+{
+ spmd_spm_core_context_t *ctx = spmd_get_context();
+
+ /* Get current CPU context from SPMC context */
+ assert(cm_get_context(SECURE) == &(ctx->cpu_ctx));
+
+ /*
+ * The SPMD must have initiated the original request through a
+ * synchronous entry into SPMC. Jump back to the original C runtime
+ * context with the value of rc in x0;
+ */
+ spmd_spm_core_exit(ctx->c_rt_ctx, rc);
+
+ panic();
+}
+
+/*******************************************************************************
+ * Jump to the SPM Core for the first time.
+ ******************************************************************************/
+static int32_t spmd_init(void)
+{
+ spmd_spm_core_context_t *ctx = spmd_get_context();
+ uint64_t rc;
+
+ VERBOSE("SPM Core init start.\n");
+
+ /* Primary boot core enters the SPMC for initialization. */
+ ctx->state = SPMC_STATE_ON_PENDING;
+
+ rc = spmd_spm_core_sync_entry(ctx);
+ if (rc != 0ULL) {
+ ERROR("SPMC initialisation failed 0x%" PRIx64 "\n", rc);
+ return 0;
+ }
+
+ ctx->state = SPMC_STATE_ON;
+
+ VERBOSE("SPM Core init end.\n");
+
+ return 1;
+}
+
+/*******************************************************************************
+ * spmd_secure_interrupt_handler
+ * Enter the SPMC for further handling of the secure interrupt by the SPMC
+ * itself or a Secure Partition.
+ ******************************************************************************/
+static uint64_t spmd_secure_interrupt_handler(uint32_t id,
+ uint32_t flags,
+ void *handle,
+ void *cookie)
+{
+ spmd_spm_core_context_t *ctx = spmd_get_context();
+ gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx);
+ unsigned int linear_id = plat_my_core_pos();
+ int64_t rc;
+
+ /* Sanity 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 SPMC */
+ cm_el1_sysregs_context_save(NON_SECURE);
+#if SPMD_SPM_AT_SEL2
+ cm_el2_sysregs_context_save(NON_SECURE);
+#endif
+
+ /* Convey the event to the SPMC through the FFA_INTERRUPT interface. */
+ write_ctx_reg(gpregs, CTX_GPREG_X0, FFA_INTERRUPT);
+ write_ctx_reg(gpregs, CTX_GPREG_X1, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X2, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X3, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X4, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X5, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X6, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X7, 0);
+
+ /* Mark current core as handling a secure interrupt. */
+ ctx->secure_interrupt_ongoing = true;
+
+ rc = spmd_spm_core_sync_entry(ctx);
+ if (rc != 0ULL) {
+ ERROR("%s failed (%" PRId64 ") on CPU%u\n", __func__, rc, linear_id);
+ }
+
+ ctx->secure_interrupt_ongoing = false;
+
+ cm_el1_sysregs_context_restore(NON_SECURE);
+#if SPMD_SPM_AT_SEL2
+ cm_el2_sysregs_context_restore(NON_SECURE);
+#endif
+ cm_set_next_eret_context(NON_SECURE);
+
+ SMC_RET0(&ctx->cpu_ctx);
+}
+
+/*******************************************************************************
+ * Loads SPMC manifest and inits SPMC.
+ ******************************************************************************/
+static int spmd_spmc_init(void *pm_addr)
+{
+ cpu_context_t *cpu_ctx;
+ unsigned int core_id;
+ uint32_t ep_attr, flags;
+ int rc;
+
+ /* Load the SPM Core manifest */
+ rc = plat_spm_core_manifest_load(&spmc_attrs, pm_addr);
+ if (rc != 0) {
+ WARN("No or invalid SPM Core manifest image provided by BL2\n");
+ return rc;
+ }
+
+ /*
+ * Ensure that the SPM Core version is compatible with the SPM
+ * Dispatcher version.
+ */
+ if ((spmc_attrs.major_version != FFA_VERSION_MAJOR) ||
+ (spmc_attrs.minor_version > FFA_VERSION_MINOR)) {
+ WARN("Unsupported FFA version (%u.%u)\n",
+ spmc_attrs.major_version, spmc_attrs.minor_version);
+ return -EINVAL;
+ }
+
+ VERBOSE("FFA version (%u.%u)\n", spmc_attrs.major_version,
+ spmc_attrs.minor_version);
+
+ VERBOSE("SPM Core run time EL%x.\n",
+ SPMD_SPM_AT_SEL2 ? MODE_EL2 : MODE_EL1);
+
+ /* Validate the SPMC ID, Ensure high bit is set */
+ if (((spmc_attrs.spmc_id >> SPMC_SECURE_ID_SHIFT) &
+ SPMC_SECURE_ID_MASK) == 0U) {
+ WARN("Invalid ID (0x%x) for SPMC.\n", spmc_attrs.spmc_id);
+ return -EINVAL;
+ }
+
+ /* Validate the SPM Core execution state */
+ if ((spmc_attrs.exec_state != MODE_RW_64) &&
+ (spmc_attrs.exec_state != MODE_RW_32)) {
+ WARN("Unsupported %s%x.\n", "SPM Core execution state 0x",
+ spmc_attrs.exec_state);
+ return -EINVAL;
+ }
+
+ VERBOSE("%s%x.\n", "SPM Core execution state 0x",
+ spmc_attrs.exec_state);
+
+#if SPMD_SPM_AT_SEL2
+ /* Ensure manifest has not requested AArch32 state in S-EL2 */
+ if (spmc_attrs.exec_state == MODE_RW_32) {
+ WARN("AArch32 state at S-EL2 is not supported.\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Check if S-EL2 is supported on this system if S-EL2
+ * is required for SPM
+ */
+ if (!is_armv8_4_sel2_present()) {
+ WARN("SPM Core run time S-EL2 is not supported.\n");
+ return -EINVAL;
+ }
+#endif /* SPMD_SPM_AT_SEL2 */
+
+ /* Initialise an entrypoint to set up the CPU context */
+ ep_attr = SECURE | EP_ST_ENABLE;
+ if ((read_sctlr_el3() & SCTLR_EE_BIT) != 0ULL) {
+ ep_attr |= EP_EE_BIG;
+ }
+
+ SET_PARAM_HEAD(spmc_ep_info, PARAM_EP, VERSION_1, ep_attr);
+
+ /*
+ * Populate SPSR for SPM Core based upon validated parameters from the
+ * manifest.
+ */
+ if (spmc_attrs.exec_state == MODE_RW_32) {
+ spmc_ep_info->spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM,
+ SPSR_E_LITTLE,
+ DAIF_FIQ_BIT |
+ DAIF_IRQ_BIT |
+ DAIF_ABT_BIT);
+ } else {
+
+#if SPMD_SPM_AT_SEL2
+ static const uint32_t runtime_el = MODE_EL2;
+#else
+ static const uint32_t runtime_el = MODE_EL1;
+#endif
+ spmc_ep_info->spsr = SPSR_64(runtime_el,
+ MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS);
+ }
+
+ /* Set an initial SPMC context state for all cores. */
+ for (core_id = 0U; core_id < PLATFORM_CORE_COUNT; core_id++) {
+ spm_core_context[core_id].state = SPMC_STATE_OFF;
+
+ /* Setup an initial cpu context for the SPMC. */
+ cpu_ctx = &spm_core_context[core_id].cpu_ctx;
+ cm_setup_context(cpu_ctx, spmc_ep_info);
+
+ /*
+ * Pass the core linear ID to the SPMC through x4.
+ * (TF-A implementation defined behavior helping
+ * a legacy TOS migration to adopt FF-A).
+ */
+ write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X4, core_id);
+ }
+
+ /* Register power management hooks with PSCI */
+ psci_register_spd_pm_hook(&spmd_pm);
+
+ /* Register init function for deferred init. */
+ bl31_register_bl32_init(&spmd_init);
+
+ INFO("SPM Core setup done.\n");
+
+ /*
+ * Register an interrupt handler routing secure interrupts to SPMD
+ * while the NWd is running.
+ */
+ flags = 0;
+ set_interrupt_rm_flag(flags, NON_SECURE);
+ rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
+ spmd_secure_interrupt_handler,
+ flags);
+ if (rc != 0) {
+ panic();
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Initialize context of SPM Core.
+ ******************************************************************************/
+int spmd_setup(void)
+{
+ int rc;
+ void *spmc_manifest;
+
+ /*
+ * If the SPMC is at EL3, then just initialise it directly. The
+ * shenanigans of when it is at a lower EL are not needed.
+ */
+ if (is_spmc_at_el3()) {
+ /* Allow the SPMC to populate its attributes directly. */
+ spmc_populate_attrs(&spmc_attrs);
+
+ rc = spmc_setup();
+ if (rc != 0) {
+ ERROR("SPMC initialisation failed 0x%x.\n", rc);
+ }
+ return rc;
+ }
+
+ spmc_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
+ if (spmc_ep_info == NULL) {
+ WARN("No SPM Core image provided by BL2 boot loader.\n");
+ return -EINVAL;
+ }
+
+ /* Under no circumstances will this parameter be 0 */
+ assert(spmc_ep_info->pc != 0ULL);
+
+ /*
+ * Check if BL32 ep_info has a reference to 'tos_fw_config'. This will
+ * be used as a manifest for the SPM Core at the next lower EL/mode.
+ */
+ spmc_manifest = (void *)spmc_ep_info->args.arg0;
+ if (spmc_manifest == NULL) {
+ ERROR("Invalid or absent SPM Core manifest.\n");
+ return -EINVAL;
+ }
+
+ /* Load manifest, init SPMC */
+ rc = spmd_spmc_init(spmc_manifest);
+ if (rc != 0) {
+ WARN("Booting device without SPM initialization.\n");
+ }
+
+ return rc;
+}
+
+/*******************************************************************************
+ * Forward FF-A SMCs to the other security state.
+ ******************************************************************************/
+uint64_t spmd_smc_switch_state(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *handle)
+{
+ unsigned int secure_state_in = (secure_origin) ? SECURE : NON_SECURE;
+ unsigned int secure_state_out = (!secure_origin) ? SECURE : NON_SECURE;
+
+ /* Save incoming security state */
+#if SPMD_SPM_AT_SEL2
+ if (secure_state_in == NON_SECURE) {
+ cm_el1_sysregs_context_save(secure_state_in);
+ }
+ cm_el2_sysregs_context_save(secure_state_in);
+#else
+ cm_el1_sysregs_context_save(secure_state_in);
+#endif
+
+ /* Restore outgoing security state */
+#if SPMD_SPM_AT_SEL2
+ if (secure_state_out == NON_SECURE) {
+ cm_el1_sysregs_context_restore(secure_state_out);
+ }
+ cm_el2_sysregs_context_restore(secure_state_out);
+#else
+ cm_el1_sysregs_context_restore(secure_state_out);
+#endif
+ cm_set_next_eret_context(secure_state_out);
+
+ SMC_RET8(cm_get_context(secure_state_out), smc_fid, x1, x2, x3, x4,
+ SMC_GET_GP(handle, CTX_GPREG_X5),
+ SMC_GET_GP(handle, CTX_GPREG_X6),
+ SMC_GET_GP(handle, CTX_GPREG_X7));
+}
+
+/*******************************************************************************
+ * Forward SMCs to the other security state.
+ ******************************************************************************/
+static uint64_t spmd_smc_forward(uint32_t smc_fid,
+ bool secure_origin,
+ uint64_t x1,
+ uint64_t x2,
+ uint64_t x3,
+ uint64_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ if (is_spmc_at_el3() && !secure_origin) {
+ return spmc_smc_handler(smc_fid, secure_origin, x1, x2, x3, x4,
+ cookie, handle, flags);
+ }
+ return spmd_smc_switch_state(smc_fid, secure_origin, x1, x2, x3, x4,
+ handle);
+
+}
+
+/*******************************************************************************
+ * Return FFA_ERROR with specified error code
+ ******************************************************************************/
+static uint64_t spmd_ffa_error_return(void *handle, int error_code)
+{
+ SMC_RET8(handle, (uint32_t) FFA_ERROR,
+ FFA_TARGET_INFO_MBZ, (uint32_t)error_code,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ);
+}
+
+/*******************************************************************************
+ * spmd_check_address_in_binary_image
+ ******************************************************************************/
+bool spmd_check_address_in_binary_image(uint64_t address)
+{
+ assert(!check_uptr_overflow(spmc_attrs.load_address, spmc_attrs.binary_size));
+
+ return ((address >= spmc_attrs.load_address) &&
+ (address < (spmc_attrs.load_address + spmc_attrs.binary_size)));
+}
+
+/******************************************************************************
+ * spmd_is_spmc_message
+ *****************************************************************************/
+static bool spmd_is_spmc_message(unsigned int ep)
+{
+ if (is_spmc_at_el3()) {
+ return false;
+ }
+
+ return ((ffa_endpoint_destination(ep) == SPMD_DIRECT_MSG_ENDPOINT_ID)
+ && (ffa_endpoint_source(ep) == spmc_attrs.spmc_id));
+}
+
+/******************************************************************************
+ * spmd_handle_spmc_message
+ *****************************************************************************/
+static int spmd_handle_spmc_message(unsigned long long msg,
+ unsigned long long parm1, unsigned long long parm2,
+ unsigned long long parm3, unsigned long long parm4)
+{
+ VERBOSE("%s %llx %llx %llx %llx %llx\n", __func__,
+ msg, parm1, parm2, parm3, parm4);
+
+ return -EINVAL;
+}
+
+/*******************************************************************************
+ * This function forwards FF-A SMCs to either the main SPMD handler or the
+ * SPMC at EL3, depending on the origin security state, if enabled.
+ ******************************************************************************/
+uint64_t spmd_ffa_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)
+{
+ if (is_spmc_at_el3()) {
+ /*
+ * If we have an SPMC at EL3 allow handling of the SMC first.
+ * The SPMC will call back through to SPMD handler if required.
+ */
+ if (is_caller_secure(flags)) {
+ return spmc_smc_handler(smc_fid,
+ is_caller_secure(flags),
+ x1, x2, x3, x4, cookie,
+ handle, flags);
+ }
+ }
+ return spmd_smc_handler(smc_fid, x1, x2, x3, x4, cookie,
+ handle, flags);
+}
+
+/*******************************************************************************
+ * This function handles all SMCs in the range reserved for FFA. Each call is
+ * either forwarded to the other security state or handled by the SPM dispatcher
+ ******************************************************************************/
+uint64_t spmd_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 linear_id = plat_my_core_pos();
+ spmd_spm_core_context_t *ctx = spmd_get_context();
+ bool secure_origin;
+ int32_t ret;
+ uint32_t input_version;
+
+ /* Determine which security state this SMC originated from */
+ secure_origin = is_caller_secure(flags);
+
+ VERBOSE("SPM(%u): 0x%x 0x%" PRIx64 " 0x%" PRIx64 " 0x%" PRIx64 " 0x%" PRIx64
+ " 0x%" PRIx64 " 0x%" PRIx64 " 0x%" PRIx64 "\n",
+ linear_id, smc_fid, x1, x2, x3, x4,
+ SMC_GET_GP(handle, CTX_GPREG_X5),
+ SMC_GET_GP(handle, CTX_GPREG_X6),
+ SMC_GET_GP(handle, CTX_GPREG_X7));
+
+ switch (smc_fid) {
+ case FFA_ERROR:
+ /*
+ * Check if this is the first invocation of this interface on
+ * this CPU. If so, then indicate that the SPM Core initialised
+ * unsuccessfully.
+ */
+ if (secure_origin && (ctx->state == SPMC_STATE_ON_PENDING)) {
+ spmd_spm_core_sync_exit(x2);
+ }
+
+ return spmd_smc_forward(smc_fid, secure_origin,
+ x1, x2, x3, x4, cookie,
+ handle, flags);
+ break; /* not reached */
+
+ case FFA_VERSION:
+ input_version = (uint32_t)(0xFFFFFFFF & x1);
+ /*
+ * If caller is secure and SPMC was initialized,
+ * return FFA_VERSION of SPMD.
+ * If caller is non secure and SPMC was initialized,
+ * forward to the EL3 SPMC if enabled, otherwise return
+ * the SPMC version if implemented at a lower EL.
+ * Sanity check to "input_version".
+ * If the EL3 SPMC is enabled, ignore the SPMC state as
+ * this is not used.
+ */
+ if ((input_version & FFA_VERSION_BIT31_MASK) ||
+ (!is_spmc_at_el3() && (ctx->state == SPMC_STATE_RESET))) {
+ ret = FFA_ERROR_NOT_SUPPORTED;
+ } else if (!secure_origin) {
+ if (is_spmc_at_el3()) {
+ /*
+ * Forward the call directly to the EL3 SPMC, if
+ * enabled, as we don't need to wrap the call in
+ * a direct request.
+ */
+ return spmd_smc_forward(smc_fid, secure_origin,
+ x1, x2, x3, x4, cookie,
+ handle, flags);
+ }
+
+ gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx);
+ uint64_t rc;
+
+ if (spmc_attrs.major_version == 1 &&
+ spmc_attrs.minor_version == 0) {
+ ret = MAKE_FFA_VERSION(spmc_attrs.major_version,
+ spmc_attrs.minor_version);
+ SMC_RET8(handle, (uint32_t)ret,
+ FFA_TARGET_INFO_MBZ,
+ FFA_TARGET_INFO_MBZ,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ);
+ break;
+ }
+ /* Save non-secure system registers context */
+ cm_el1_sysregs_context_save(NON_SECURE);
+#if SPMD_SPM_AT_SEL2
+ cm_el2_sysregs_context_save(NON_SECURE);
+#endif
+
+ /*
+ * The incoming request has FFA_VERSION as X0 smc_fid
+ * and requested version in x1. Prepare a direct request
+ * from SPMD to SPMC with FFA_VERSION framework function
+ * identifier in X2 and requested version in X3.
+ */
+ spmd_build_spmc_message(gpregs,
+ SPMD_FWK_MSG_FFA_VERSION_REQ,
+ input_version);
+
+ rc = spmd_spm_core_sync_entry(ctx);
+
+ if ((rc != 0ULL) ||
+ (SMC_GET_GP(gpregs, CTX_GPREG_X0) !=
+ FFA_MSG_SEND_DIRECT_RESP_SMC32) ||
+ (SMC_GET_GP(gpregs, CTX_GPREG_X2) !=
+ (FFA_FWK_MSG_BIT |
+ SPMD_FWK_MSG_FFA_VERSION_RESP))) {
+ ERROR("Failed to forward FFA_VERSION\n");
+ ret = FFA_ERROR_NOT_SUPPORTED;
+ } else {
+ ret = SMC_GET_GP(gpregs, CTX_GPREG_X3);
+ }
+
+ /*
+ * Return here after SPMC has handled FFA_VERSION.
+ * The returned SPMC version is held in X3.
+ * Forward this version in X0 to the non-secure caller.
+ */
+ return spmd_smc_forward(ret, true, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ, cookie, gpregs,
+ flags);
+ } else {
+ ret = MAKE_FFA_VERSION(FFA_VERSION_MAJOR,
+ FFA_VERSION_MINOR);
+ }
+
+ SMC_RET8(handle, (uint32_t)ret, FFA_TARGET_INFO_MBZ,
+ FFA_TARGET_INFO_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ);
+ break; /* not reached */
+
+ case FFA_FEATURES:
+ /*
+ * This is an optional interface. Do the minimal checks and
+ * forward to SPM Core which will handle it if implemented.
+ */
+
+ /* Forward SMC from Normal world to the SPM Core */
+ if (!secure_origin) {
+ return spmd_smc_forward(smc_fid, secure_origin,
+ x1, x2, x3, x4, cookie,
+ handle, flags);
+ }
+
+ /*
+ * Return success if call was from secure world i.e. all
+ * FFA functions are supported. This is essentially a
+ * nop.
+ */
+ SMC_RET8(handle, FFA_SUCCESS_SMC32, x1, x2, x3, x4,
+ SMC_GET_GP(handle, CTX_GPREG_X5),
+ SMC_GET_GP(handle, CTX_GPREG_X6),
+ SMC_GET_GP(handle, CTX_GPREG_X7));
+
+ break; /* not reached */
+
+ case FFA_ID_GET:
+ /*
+ * Returns the ID of the calling FFA component.
+ */
+ if (!secure_origin) {
+ SMC_RET8(handle, FFA_SUCCESS_SMC32,
+ FFA_TARGET_INFO_MBZ, FFA_NS_ENDPOINT_ID,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ);
+ }
+
+ SMC_RET8(handle, FFA_SUCCESS_SMC32,
+ FFA_TARGET_INFO_MBZ, spmc_attrs.spmc_id,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ);
+
+ break; /* not reached */
+
+ case FFA_SECONDARY_EP_REGISTER_SMC64:
+ if (secure_origin) {
+ ret = spmd_pm_secondary_ep_register(x1);
+
+ if (ret < 0) {
+ SMC_RET8(handle, FFA_ERROR_SMC64,
+ FFA_TARGET_INFO_MBZ, ret,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ);
+ } else {
+ SMC_RET8(handle, FFA_SUCCESS_SMC64,
+ FFA_TARGET_INFO_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ);
+ }
+ }
+
+ return spmd_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
+ break; /* Not reached */
+
+ case FFA_SPM_ID_GET:
+ if (MAKE_FFA_VERSION(1, 1) > FFA_VERSION_COMPILED) {
+ return spmd_ffa_error_return(handle,
+ FFA_ERROR_NOT_SUPPORTED);
+ }
+ /*
+ * Returns the ID of the SPMC or SPMD depending on the FF-A
+ * instance where this function is invoked
+ */
+ if (!secure_origin) {
+ SMC_RET8(handle, FFA_SUCCESS_SMC32,
+ FFA_TARGET_INFO_MBZ, spmc_attrs.spmc_id,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ);
+ }
+ SMC_RET8(handle, FFA_SUCCESS_SMC32,
+ FFA_TARGET_INFO_MBZ, SPMD_DIRECT_MSG_ENDPOINT_ID,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ);
+
+ break; /* not reached */
+
+ case FFA_MSG_SEND_DIRECT_REQ_SMC32:
+ case FFA_MSG_SEND_DIRECT_REQ_SMC64:
+ if (!secure_origin) {
+ /* Validate source endpoint is non-secure for non-secure caller. */
+ if (ffa_is_secure_world_id(ffa_endpoint_source(x1))) {
+ return spmd_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+ }
+ if (secure_origin && spmd_is_spmc_message(x1)) {
+ ret = spmd_handle_spmc_message(x3, x4,
+ SMC_GET_GP(handle, CTX_GPREG_X5),
+ SMC_GET_GP(handle, CTX_GPREG_X6),
+ SMC_GET_GP(handle, CTX_GPREG_X7));
+
+ SMC_RET8(handle, FFA_SUCCESS_SMC32,
+ FFA_TARGET_INFO_MBZ, ret,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+ FFA_PARAM_MBZ);
+ } else {
+ /* Forward direct message to the other world */
+ return spmd_smc_forward(smc_fid, secure_origin,
+ x1, x2, x3, x4, cookie,
+ handle, flags);
+ }
+ break; /* Not reached */
+
+ case FFA_MSG_SEND_DIRECT_RESP_SMC32:
+ if (secure_origin && spmd_is_spmc_message(x1)) {
+ spmd_spm_core_sync_exit(0ULL);
+ } else {
+ /* Forward direct message to the other world */
+ return spmd_smc_forward(smc_fid, secure_origin,
+ x1, x2, x3, x4, cookie,
+ handle, flags);
+ }
+ break; /* Not reached */
+
+ case FFA_RX_RELEASE:
+ case FFA_RXTX_MAP_SMC32:
+ case FFA_RXTX_MAP_SMC64:
+ case FFA_RXTX_UNMAP:
+ case FFA_PARTITION_INFO_GET:
+#if MAKE_FFA_VERSION(1, 1) <= FFA_VERSION_COMPILED
+ case FFA_NOTIFICATION_BITMAP_CREATE:
+ case FFA_NOTIFICATION_BITMAP_DESTROY:
+ case FFA_NOTIFICATION_BIND:
+ case FFA_NOTIFICATION_UNBIND:
+ case FFA_NOTIFICATION_SET:
+ case FFA_NOTIFICATION_GET:
+ case FFA_NOTIFICATION_INFO_GET:
+ case FFA_NOTIFICATION_INFO_GET_SMC64:
+ case FFA_MSG_SEND2:
+ case FFA_RX_ACQUIRE:
+#endif
+ case FFA_MSG_RUN:
+ /*
+ * Above calls should be invoked only by the Normal world and
+ * must not be forwarded from Secure world to Normal world.
+ */
+ if (secure_origin) {
+ return spmd_ffa_error_return(handle,
+ FFA_ERROR_NOT_SUPPORTED);
+ }
+
+ /* Fall through to forward the call to the other world */
+ case FFA_MSG_SEND:
+ case FFA_MSG_SEND_DIRECT_RESP_SMC64:
+ case FFA_MEM_DONATE_SMC32:
+ case FFA_MEM_DONATE_SMC64:
+ case FFA_MEM_LEND_SMC32:
+ case FFA_MEM_LEND_SMC64:
+ case FFA_MEM_SHARE_SMC32:
+ case FFA_MEM_SHARE_SMC64:
+ case FFA_MEM_RETRIEVE_REQ_SMC32:
+ case FFA_MEM_RETRIEVE_REQ_SMC64:
+ case FFA_MEM_RETRIEVE_RESP:
+ case FFA_MEM_RELINQUISH:
+ case FFA_MEM_RECLAIM:
+ case FFA_MEM_FRAG_TX:
+ case FFA_MEM_FRAG_RX:
+ case FFA_SUCCESS_SMC32:
+ case FFA_SUCCESS_SMC64:
+ /*
+ * TODO: Assume that no requests originate from EL3 at the
+ * moment. This will change if a SP service is required in
+ * response to secure interrupts targeted to EL3. Until then
+ * simply forward the call to the Normal world.
+ */
+
+ return spmd_smc_forward(smc_fid, secure_origin,
+ x1, x2, x3, x4, cookie,
+ handle, flags);
+ break; /* not reached */
+
+ case FFA_MSG_WAIT:
+ /*
+ * Check if this is the first invocation of this interface on
+ * this CPU from the Secure world. If so, then indicate that the
+ * SPM Core initialised successfully.
+ */
+ if (secure_origin && (ctx->state == SPMC_STATE_ON_PENDING)) {
+ spmd_spm_core_sync_exit(0ULL);
+ }
+
+ /* Fall through to forward the call to the other world */
+ case FFA_INTERRUPT:
+ case FFA_MSG_YIELD:
+ /* This interface must be invoked only by the Secure world */
+ if (!secure_origin) {
+ return spmd_ffa_error_return(handle,
+ FFA_ERROR_NOT_SUPPORTED);
+ }
+
+ return spmd_smc_forward(smc_fid, secure_origin,
+ x1, x2, x3, x4, cookie,
+ handle, flags);
+ break; /* not reached */
+
+ case FFA_NORMAL_WORLD_RESUME:
+ if (secure_origin && ctx->secure_interrupt_ongoing) {
+ spmd_spm_core_sync_exit(0ULL);
+ } else {
+ return spmd_ffa_error_return(handle, FFA_ERROR_DENIED);
+ }
+ break; /* Not reached */
+
+ default:
+ WARN("SPM: Unsupported call 0x%08x\n", smc_fid);
+ return spmd_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
+ }
+}
diff --git a/services/std_svc/spmd/spmd_pm.c b/services/std_svc/spmd/spmd_pm.c
new file mode 100644
index 0000000..a2704dd
--- /dev/null
+++ b/services/std_svc/spmd/spmd_pm.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/spinlock.h>
+#include "spmd_private.h"
+
+static struct {
+ bool secondary_ep_locked;
+ uintptr_t secondary_ep;
+ spinlock_t lock;
+} g_spmd_pm;
+
+/*******************************************************************************
+ * spmd_pm_secondary_ep_register
+ ******************************************************************************/
+int spmd_pm_secondary_ep_register(uintptr_t entry_point)
+{
+ int ret = FFA_ERROR_INVALID_PARAMETER;
+
+ spin_lock(&g_spmd_pm.lock);
+
+ if (g_spmd_pm.secondary_ep_locked == true) {
+ goto out;
+ }
+
+ /*
+ * Check entry_point address is a PA within
+ * load_address <= entry_point < load_address + binary_size
+ */
+ if (!spmd_check_address_in_binary_image(entry_point)) {
+ ERROR("%s entry point is not within image boundaries\n",
+ __func__);
+ goto out;
+ }
+
+ g_spmd_pm.secondary_ep = entry_point;
+ g_spmd_pm.secondary_ep_locked = true;
+
+ VERBOSE("%s %lx\n", __func__, entry_point);
+
+ ret = 0;
+
+out:
+ spin_unlock(&g_spmd_pm.lock);
+
+ return ret;
+}
+
+/*******************************************************************************
+ * This CPU has been turned on. Enter SPMC to initialise S-EL1 or S-EL2. As part
+ * of the SPMC initialization path, they will initialize any SPs that they
+ * manage. Entry into SPMC is done after initialising minimal architectural
+ * state that guarantees safe execution.
+ ******************************************************************************/
+static void spmd_cpu_on_finish_handler(u_register_t unused)
+{
+ spmd_spm_core_context_t *ctx = spmd_get_context();
+ unsigned int linear_id = plat_my_core_pos();
+ el3_state_t *el3_state;
+ uintptr_t entry_point;
+ uint64_t rc;
+
+ assert(ctx != NULL);
+ assert(ctx->state != SPMC_STATE_ON);
+
+ spin_lock(&g_spmd_pm.lock);
+
+ /*
+ * Leave the possibility that the SPMC does not call
+ * FFA_SECONDARY_EP_REGISTER in which case re-use the
+ * primary core address for booting secondary cores.
+ */
+ if (g_spmd_pm.secondary_ep_locked == true) {
+ /*
+ * The CPU context has already been initialized at boot time
+ * (in spmd_spmc_init by a call to cm_setup_context). Adjust
+ * below the target core entry point based on the address
+ * passed to by FFA_SECONDARY_EP_REGISTER.
+ */
+ entry_point = g_spmd_pm.secondary_ep;
+ el3_state = get_el3state_ctx(&ctx->cpu_ctx);
+ write_ctx_reg(el3_state, CTX_ELR_EL3, entry_point);
+ }
+
+ spin_unlock(&g_spmd_pm.lock);
+
+ /* Mark CPU as initiating ON operation. */
+ ctx->state = SPMC_STATE_ON_PENDING;
+
+ rc = spmd_spm_core_sync_entry(ctx);
+ if (rc != 0ULL) {
+ ERROR("%s failed (%" PRIu64 ") on CPU%u\n", __func__, rc,
+ linear_id);
+ ctx->state = SPMC_STATE_OFF;
+ return;
+ }
+
+ ctx->state = SPMC_STATE_ON;
+
+ VERBOSE("CPU %u on!\n", linear_id);
+}
+
+/*******************************************************************************
+ * spmd_cpu_off_handler
+ ******************************************************************************/
+static int32_t spmd_cpu_off_handler(u_register_t unused)
+{
+ spmd_spm_core_context_t *ctx = spmd_get_context();
+ unsigned int linear_id = plat_my_core_pos();
+ int64_t rc;
+
+ assert(ctx != NULL);
+ assert(ctx->state != SPMC_STATE_OFF);
+
+ /* Build an SPMD to SPMC direct message request. */
+ spmd_build_spmc_message(get_gpregs_ctx(&ctx->cpu_ctx),
+ FFA_FWK_MSG_PSCI, PSCI_CPU_OFF);
+
+ rc = spmd_spm_core_sync_entry(ctx);
+ if (rc != 0ULL) {
+ ERROR("%s failed (%" PRIu64 ") on CPU%u\n", __func__, rc, linear_id);
+ }
+
+ /* Expect a direct message response from the SPMC. */
+ u_register_t ffa_resp_func = read_ctx_reg(get_gpregs_ctx(&ctx->cpu_ctx),
+ CTX_GPREG_X0);
+ if (ffa_resp_func != FFA_MSG_SEND_DIRECT_RESP_SMC32) {
+ ERROR("%s invalid SPMC response (%lx).\n",
+ __func__, ffa_resp_func);
+ return -EINVAL;
+ }
+
+ ctx->state = SPMC_STATE_OFF;
+
+ VERBOSE("CPU %u off!\n", linear_id);
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Structure populated by the SPM Dispatcher to perform any bookkeeping before
+ * PSCI executes a power mgmt. operation.
+ ******************************************************************************/
+const spd_pm_ops_t spmd_pm = {
+ .svc_on_finish = spmd_cpu_on_finish_handler,
+ .svc_off = spmd_cpu_off_handler
+};
diff --git a/services/std_svc/spmd/spmd_private.h b/services/std_svc/spmd/spmd_private.h
new file mode 100644
index 0000000..d21a622
--- /dev/null
+++ b/services/std_svc/spmd/spmd_private.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPMD_PRIVATE_H
+#define SPMD_PRIVATE_H
+
+#include <common/bl_common.h>
+#include <context.h>
+
+/*******************************************************************************
+ * Constants that allow assembler code to preserve callee-saved registers of the
+ * C runtime context while performing a security state switch.
+ ******************************************************************************/
+#define SPMD_C_RT_CTX_X19 0x0
+#define SPMD_C_RT_CTX_X20 0x8
+#define SPMD_C_RT_CTX_X21 0x10
+#define SPMD_C_RT_CTX_X22 0x18
+#define SPMD_C_RT_CTX_X23 0x20
+#define SPMD_C_RT_CTX_X24 0x28
+#define SPMD_C_RT_CTX_X25 0x30
+#define SPMD_C_RT_CTX_X26 0x38
+#define SPMD_C_RT_CTX_X27 0x40
+#define SPMD_C_RT_CTX_X28 0x48
+#define SPMD_C_RT_CTX_X29 0x50
+#define SPMD_C_RT_CTX_X30 0x58
+
+#define SPMD_C_RT_CTX_SIZE 0x60
+#define SPMD_C_RT_CTX_ENTRIES (SPMD_C_RT_CTX_SIZE >> DWORD_SHIFT)
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+#include <lib/psci/psci_lib.h>
+#include <plat/common/platform.h>
+#include <services/ffa_svc.h>
+
+typedef enum spmc_state {
+ SPMC_STATE_RESET = 0,
+ SPMC_STATE_OFF,
+ SPMC_STATE_ON_PENDING,
+ SPMC_STATE_ON
+} spmc_state_t;
+
+/*
+ * Data structure used by the SPM dispatcher (SPMD) in EL3 to track context of
+ * the SPM core (SPMC) at the next lower EL.
+ */
+typedef struct spmd_spm_core_context {
+ uint64_t c_rt_ctx;
+ cpu_context_t cpu_ctx;
+ spmc_state_t state;
+ bool secure_interrupt_ongoing;
+} spmd_spm_core_context_t;
+
+/*
+ * Reserve ID for NS physical FFA Endpoint.
+ */
+#define FFA_NS_ENDPOINT_ID U(0)
+
+/* Define SPMD target function IDs for framework messages to the SPMC */
+#define SPMD_FWK_MSG_FFA_VERSION_REQ U(0x8)
+#define SPMD_FWK_MSG_FFA_VERSION_RESP U(0x9)
+
+/* Function to build SPMD to SPMC message */
+void spmd_build_spmc_message(gp_regs_t *gpregs, uint8_t target,
+ unsigned long long message);
+
+/* Functions used to enter/exit SPMC synchronously */
+uint64_t spmd_spm_core_sync_entry(spmd_spm_core_context_t *ctx);
+__dead2 void spmd_spm_core_sync_exit(uint64_t rc);
+
+/* Assembly helpers */
+uint64_t spmd_spm_core_enter(uint64_t *c_rt_ctx);
+void __dead2 spmd_spm_core_exit(uint64_t c_rt_ctx, uint64_t ret);
+
+/* SPMD SPD power management handlers */
+extern const spd_pm_ops_t spmd_pm;
+
+/* SPMC entry point information helper */
+entry_point_info_t *spmd_spmc_ep_info_get(void);
+
+/* SPMC ID getter */
+uint16_t spmd_spmc_id_get(void);
+
+/* SPMC context on CPU based on mpidr */
+spmd_spm_core_context_t *spmd_get_context_by_mpidr(uint64_t mpidr);
+
+/* SPMC context on current CPU get helper */
+spmd_spm_core_context_t *spmd_get_context(void);
+
+int spmd_pm_secondary_ep_register(uintptr_t entry_point);
+bool spmd_check_address_in_binary_image(uint64_t address);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* SPMD_PRIVATE_H */
diff --git a/services/std_svc/std_svc_setup.c b/services/std_svc/std_svc_setup.c
new file mode 100644
index 0000000..2884a3b
--- /dev/null
+++ b/services/std_svc/std_svc_setup.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2014-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/pmf/pmf.h>
+#include <lib/psci/psci.h>
+#include <lib/runtime_instr.h>
+#include <services/drtm_svc.h>
+#include <services/pci_svc.h>
+#include <services/rmmd_svc.h>
+#include <services/sdei.h>
+#include <services/spm_mm_svc.h>
+#include <services/spmc_svc.h>
+#include <services/spmd_svc.h>
+#include <services/std_svc.h>
+#include <services/trng_svc.h>
+#include <smccc_helpers.h>
+#include <tools_share/uuid.h>
+
+/* 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 SPM_MM
+ if (spm_mm_setup() != 0) {
+ ret = 1;
+ }
+#endif
+
+#if defined(SPD_spmd)
+ if (spmd_setup() != 0) {
+ ret = 1;
+ }
+#endif
+
+#if ENABLE_RME
+ if (rmmd_setup() != 0) {
+ ret = 1;
+ }
+#endif
+
+#if SDEI_SUPPORT
+ /* SDEI initialisation */
+ sdei_init();
+#endif
+
+#if TRNG_SUPPORT
+ /* TRNG initialisation */
+ trng_setup();
+#endif /* TRNG_SUPPORT */
+
+#if DRTM_SUPPORT
+ if (drtm_setup() != 0) {
+ ret = 1;
+ }
+#endif /* DRTM_SUPPORT */
+
+ 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)
+{
+ if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) {
+ /* 32-bit SMC function, clear top parameter bits */
+
+ x1 &= UINT32_MAX;
+ x2 &= UINT32_MAX;
+ x3 &= UINT32_MAX;
+ x4 &= UINT32_MAX;
+ }
+
+ /*
+ * 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 SPM_MM
+ /*
+ * Dispatch SPM calls to SPM SMC handler and return its return
+ * value
+ */
+ if (is_spm_mm_fid(smc_fid)) {
+ return spm_mm_smc_handler(smc_fid, x1, x2, x3, x4, cookie,
+ handle, flags);
+ }
+#endif
+
+#if defined(SPD_spmd)
+ /*
+ * Dispatch FFA calls to the FFA SMC handler implemented by the SPM
+ * dispatcher and return its return value
+ */
+ if (is_ffa_fid(smc_fid)) {
+ return spmd_ffa_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
+
+#if TRNG_SUPPORT
+ if (is_trng_fid(smc_fid)) {
+ return trng_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
+ flags);
+ }
+#endif /* TRNG_SUPPORT */
+
+#if ENABLE_RME
+
+ if (is_rmmd_el3_fid(smc_fid)) {
+ return rmmd_rmm_el3_handler(smc_fid, x1, x2, x3, x4, cookie,
+ handle, flags);
+ }
+
+ if (is_rmi_fid(smc_fid)) {
+ return rmmd_rmi_handler(smc_fid, x1, x2, x3, x4, cookie,
+ handle, flags);
+ }
+#endif
+
+#if SMC_PCI_SUPPORT
+ if (is_pci_fid(smc_fid)) {
+ return pci_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
+ flags);
+ }
+#endif
+
+#if DRTM_SUPPORT
+ if (is_drtm_fid(smc_fid)) {
+ return drtm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
+ flags);
+ }
+#endif /* DRTM_SUPPORT */
+
+ 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:
+ VERBOSE("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
+);
diff --git a/services/std_svc/trng/trng_entropy_pool.c b/services/std_svc/trng/trng_entropy_pool.c
new file mode 100644
index 0000000..30105b3
--- /dev/null
+++ b/services/std_svc/trng/trng_entropy_pool.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <lib/spinlock.h>
+#include <plat/common/plat_trng.h>
+
+/*
+ * # Entropy pool
+ * Note that the TRNG Firmware interface can request up to 192 bits of entropy
+ * in a single call or three 64bit words per call. We have 4 words in the pool
+ * so that when we have 1-63 bits in the pool, and we have a request for
+ * 192 bits of entropy, we don't have to throw out the leftover 1-63 bits of
+ * entropy.
+ */
+#define WORDS_IN_POOL (4)
+static uint64_t entropy[WORDS_IN_POOL];
+/* index in bits of the first bit of usable entropy */
+static uint32_t entropy_bit_index;
+/* then number of valid bits in the entropy pool */
+static uint32_t entropy_bit_size;
+
+static spinlock_t trng_pool_lock;
+
+#define BITS_PER_WORD (sizeof(entropy[0]) * 8)
+#define BITS_IN_POOL (WORDS_IN_POOL * BITS_PER_WORD)
+#define ENTROPY_MIN_WORD (entropy_bit_index / BITS_PER_WORD)
+#define ENTROPY_FREE_BIT (entropy_bit_size + entropy_bit_index)
+#define _ENTROPY_FREE_WORD (ENTROPY_FREE_BIT / BITS_PER_WORD)
+#define ENTROPY_FREE_INDEX (_ENTROPY_FREE_WORD % WORDS_IN_POOL)
+/* ENTROPY_WORD_INDEX(0) includes leftover bits in the lower bits */
+#define ENTROPY_WORD_INDEX(i) ((ENTROPY_MIN_WORD + i) % WORDS_IN_POOL)
+
+/*
+ * Fill the entropy pool until we have at least as many bits as requested.
+ * Returns true after filling the pool, and false if the entropy source is out
+ * of entropy and the pool could not be filled.
+ * Assumes locks are taken.
+ */
+static bool trng_fill_entropy(uint32_t nbits)
+{
+ while (nbits > entropy_bit_size) {
+ bool valid = plat_get_entropy(&entropy[ENTROPY_FREE_INDEX]);
+
+ if (valid) {
+ entropy_bit_size += BITS_PER_WORD;
+ assert(entropy_bit_size <= BITS_IN_POOL);
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ * Pack entropy into the out buffer, filling and taking locks as needed.
+ * Returns true on success, false on failure.
+ *
+ * Note: out must have enough space for nbits of entropy
+ */
+bool trng_pack_entropy(uint32_t nbits, uint64_t *out)
+{
+ bool ret = true;
+
+ spin_lock(&trng_pool_lock);
+
+ if (!trng_fill_entropy(nbits)) {
+ ret = false;
+ goto out;
+ }
+
+ const unsigned int rshift = entropy_bit_index % BITS_PER_WORD;
+ const unsigned int lshift = BITS_PER_WORD - rshift;
+ const int to_fill = ((nbits + BITS_PER_WORD - 1) / BITS_PER_WORD);
+ int word_i;
+
+ for (word_i = 0; word_i < to_fill; word_i++) {
+ /*
+ * Repack the entropy from the pool into the passed in out
+ * buffer. This takes lesser bits from the valid upper bits
+ * of word_i and more bits from the lower bits of (word_i + 1).
+ *
+ * I found the following diagram useful. note: `e` represents
+ * valid entropy, ` ` represents invalid bits (not entropy) and
+ * `x` represents valid entropy that must not end up in the
+ * packed word.
+ *
+ * |---------entropy pool----------|
+ * C var |--(word_i + 1)-|----word_i-----|
+ * bit idx |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|
+ * [x,x,e,e,e,e,e,e|e,e, , , , , , ]
+ * | [e,e,e,e,e,e,e,e] |
+ * | |--out[word_i]--| |
+ * lshift|---| |--rshift---|
+ *
+ * ==== Which is implemented as ====
+ *
+ * |---------entropy pool----------|
+ * C var |--(word_i + 1)-|----word_i-----|
+ * bit idx |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|
+ * [x,x,e,e,e,e,e,e|e,e, , , , , , ]
+ * C expr << lshift >> rshift
+ * bit idx 5 4 3 2 1 0 7 6
+ * [e,e,e,e,e,e,0,0|0,0,0,0,0,0,e,e]
+ * ==== bit-wise or ====
+ * 5 4 3 2 1 0 7 6
+ * [e,e,e,e,e,e,e,e]
+ */
+ out[word_i] = 0;
+ out[word_i] |= entropy[ENTROPY_WORD_INDEX(word_i)] >> rshift;
+
+ /*
+ * Note that a shift of 64 bits is treated as a shift of 0 bits.
+ * When the shift amount is the same as the BITS_PER_WORD, we
+ * don't want to include the next word of entropy, so we skip
+ * the `|=` operation.
+ */
+ if (lshift != BITS_PER_WORD) {
+ out[word_i] |= entropy[ENTROPY_WORD_INDEX(word_i + 1)]
+ << lshift;
+ }
+ }
+ const uint64_t mask = ~0ULL >> (BITS_PER_WORD - (nbits % BITS_PER_WORD));
+
+ out[to_fill - 1] &= mask;
+
+ entropy_bit_index = (entropy_bit_index + nbits) % BITS_IN_POOL;
+ entropy_bit_size -= nbits;
+
+out:
+ spin_unlock(&trng_pool_lock);
+
+ return ret;
+}
+
+void trng_entropy_pool_setup(void)
+{
+ int i;
+
+ for (i = 0; i < WORDS_IN_POOL; i++) {
+ entropy[i] = 0;
+ }
+ entropy_bit_index = 0;
+ entropy_bit_size = 0;
+}
diff --git a/services/std_svc/trng/trng_entropy_pool.h b/services/std_svc/trng/trng_entropy_pool.h
new file mode 100644
index 0000000..fab2367
--- /dev/null
+++ b/services/std_svc/trng/trng_entropy_pool.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TRNG_ENTROPY_POOL_H
+#define TRNG_ENTROPY_POOL_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+bool trng_pack_entropy(uint32_t nbits, uint64_t *out);
+void trng_entropy_pool_setup(void);
+
+#endif /* TRNG_ENTROPY_POOL_H */
diff --git a/services/std_svc/trng/trng_main.c b/services/std_svc/trng/trng_main.c
new file mode 100644
index 0000000..90098a8
--- /dev/null
+++ b/services/std_svc/trng/trng_main.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <arch_features.h>
+#include <lib/smccc.h>
+#include <services/trng_svc.h>
+#include <smccc_helpers.h>
+
+#include <plat/common/plat_trng.h>
+
+#include "trng_entropy_pool.h"
+
+static const uuid_t uuid_null;
+
+/* handle the RND call in SMC 32 bit mode */
+static uintptr_t trng_rnd32(uint32_t nbits, void *handle)
+{
+ uint32_t mask = ~0U;
+ uint64_t ent[2] = {0};
+
+ if (nbits == 0U || nbits > TRNG_RND32_ENTROPY_MAXBITS) {
+ SMC_RET1(handle, TRNG_E_INVALID_PARAMS);
+ }
+
+ if (!trng_pack_entropy(nbits, &ent[0])) {
+ SMC_RET1(handle, TRNG_E_NO_ENTROPY);
+ }
+
+ if ((nbits % 32U) != 0U) {
+ mask >>= 32U - (nbits % 32U);
+ }
+
+ switch ((nbits - 1U) / 32U) {
+ case 0:
+ SMC_RET4(handle, TRNG_E_SUCCESS, 0, 0, ent[0] & mask);
+ break; /* unreachable */
+ case 1:
+ SMC_RET4(handle, TRNG_E_SUCCESS, 0, (ent[0] >> 32) & mask,
+ ent[0] & 0xFFFFFFFF);
+ break; /* unreachable */
+ case 2:
+ SMC_RET4(handle, TRNG_E_SUCCESS, ent[1] & mask,
+ (ent[0] >> 32) & 0xFFFFFFFF, ent[0] & 0xFFFFFFFF);
+ break; /* unreachable */
+ default:
+ SMC_RET1(handle, TRNG_E_INVALID_PARAMS);
+ break; /* unreachable */
+ }
+}
+
+/* handle the RND call in SMC 64 bit mode */
+static uintptr_t trng_rnd64(uint32_t nbits, void *handle)
+{
+ uint64_t mask = ~0ULL;
+ uint64_t ent[3] = {0};
+
+ if (nbits == 0U || nbits > TRNG_RND64_ENTROPY_MAXBITS) {
+ SMC_RET1(handle, TRNG_E_INVALID_PARAMS);
+ }
+
+ if (!trng_pack_entropy(nbits, &ent[0])) {
+ SMC_RET1(handle, TRNG_E_NO_ENTROPY);
+ }
+
+ /* Mask off higher bits if only part of register requested */
+ if ((nbits % 64U) != 0U) {
+ mask >>= 64U - (nbits % 64U);
+ }
+
+ switch ((nbits - 1U) / 64U) {
+ case 0:
+ SMC_RET4(handle, TRNG_E_SUCCESS, 0, 0, ent[0] & mask);
+ break; /* unreachable */
+ case 1:
+ SMC_RET4(handle, TRNG_E_SUCCESS, 0, ent[1] & mask, ent[0]);
+ break; /* unreachable */
+ case 2:
+ SMC_RET4(handle, TRNG_E_SUCCESS, ent[2] & mask, ent[1], ent[0]);
+ break; /* unreachable */
+ default:
+ SMC_RET1(handle, TRNG_E_INVALID_PARAMS);
+ break; /* unreachable */
+ }
+}
+
+void trng_setup(void)
+{
+ trng_entropy_pool_setup();
+ plat_entropy_setup();
+}
+
+/* Predicate indicating that a function id is part of TRNG */
+bool is_trng_fid(uint32_t smc_fid)
+{
+ return ((smc_fid == ARM_TRNG_VERSION) ||
+ (smc_fid == ARM_TRNG_FEATURES) ||
+ (smc_fid == ARM_TRNG_GET_UUID) ||
+ (smc_fid == ARM_TRNG_RND32) ||
+ (smc_fid == ARM_TRNG_RND64));
+}
+
+uintptr_t trng_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)
+{
+ if (!memcmp(&plat_trng_uuid, &uuid_null, sizeof(uuid_t))) {
+ SMC_RET1(handle, TRNG_E_NOT_IMPLEMENTED);
+ }
+
+ switch (smc_fid) {
+ case ARM_TRNG_VERSION:
+ SMC_RET1(handle, MAKE_SMCCC_VERSION(
+ TRNG_VERSION_MAJOR, TRNG_VERSION_MINOR));
+ break; /* unreachable */
+
+ case ARM_TRNG_FEATURES:
+ if (is_trng_fid((uint32_t)x1)) {
+ SMC_RET1(handle, TRNG_E_SUCCESS);
+ } else {
+ SMC_RET1(handle, TRNG_E_NOT_SUPPORTED);
+ }
+ break; /* unreachable */
+
+ case ARM_TRNG_GET_UUID:
+ SMC_UUID_RET(handle, plat_trng_uuid);
+ break; /* unreachable */
+
+ case ARM_TRNG_RND32:
+ return trng_rnd32((uint32_t)x1, handle);
+
+ case ARM_TRNG_RND64:
+ return trng_rnd64((uint32_t)x1, handle);
+
+ default:
+ WARN("Unimplemented TRNG Service Call: 0x%x\n", smc_fid);
+ SMC_RET1(handle, TRNG_E_NOT_IMPLEMENTED);
+ break; /* unreachable */
+ }
+}
diff --git a/tools/amlogic/Makefile b/tools/amlogic/Makefile
new file mode 100644
index 0000000..1a1d1f8
--- /dev/null
+++ b/tools/amlogic/Makefile
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2019 Remi Pommarel <repk@triplefau.lt>
+#
+# 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
diff --git a/tools/amlogic/doimage.c b/tools/amlogic/doimage.c
new file mode 100644
index 0000000..b304038
--- /dev/null
+++ b/tools/amlogic/doimage.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2019, Remi Pommarel <repk@triplefau.lt>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <endian.h>
+
+#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 <bl31.bin> <bl31.img>\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;
+}
diff --git a/tools/cert_create/Makefile b/tools/cert_create/Makefile
new file mode 100644
index 0000000..042e844
--- /dev/null
+++ b/tools/cert_create/Makefile
@@ -0,0 +1,111 @@
+#
+# Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT := none
+V ?= 0
+DEBUG := 0
+CRTTOOL ?= cert_create${BIN_EXT}
+BINARY := $(notdir ${CRTTOOL})
+COT := tbbr
+
+MAKE_HELPERS_DIRECTORY := ../../make_helpers/
+include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
+include ${MAKE_HELPERS_DIRECTORY}build_env.mk
+include ${MAKE_HELPERS_DIRECTORY}defaults.mk
+
+ifneq (${PLAT},none)
+TF_PLATFORM_ROOT := ../../plat/
+include ${MAKE_HELPERS_DIRECTORY}plat_helpers.mk
+PLAT_CERT_CREATE_HELPER_MK := ${PLAT_DIR}/cert_create_tbbr.mk
+endif
+
+# Common source files.
+OBJECTS := src/cert.o \
+ src/cmd_opt.o \
+ src/ext.o \
+ src/key.o \
+ src/main.o \
+ src/sha.o
+
+# Chain of trust.
+ifeq (${COT},tbbr)
+ include src/tbbr/tbbr.mk
+else ifeq (${COT},dualroot)
+ include src/dualroot/cot.mk
+else ifeq (${COT},cca)
+ include src/cca/cot.mk
+else
+ $(error Unknown chain of trust ${COT})
+endif
+
+ifneq (,$(wildcard ${PLAT_CERT_CREATE_HELPER_MK}))
+include ${PLAT_CERT_CREATE_HELPER_MK}
+endif
+
+# Select OpenSSL version flag according to the OpenSSL build selected
+# from setting the OPENSSL_DIR path.
+$(eval $(call SELECT_OPENSSL_API_VERSION))
+
+HOSTCCFLAGS := -Wall -std=c99
+
+ifeq (${DEBUG},1)
+ HOSTCCFLAGS += -g -O0 -DDEBUG -DLOG_LEVEL=40
+else
+ HOSTCCFLAGS += -O2 -DLOG_LEVEL=20
+endif
+
+ifeq (${V},0)
+ Q := @
+else
+ Q :=
+endif
+
+HOSTCCFLAGS += ${DEFINES}
+# USING_OPENSSL3 flag will be added to the HOSTCCFLAGS variable with the proper
+# computed value.
+HOSTCCFLAGS += -DUSING_OPENSSL3=$(USING_OPENSSL3)
+
+# 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
+
+# Include library directories where OpenSSL library files are located.
+# For a normal installation (i.e.: when ${OPENSSL_DIR} = /usr or
+# /usr/local), binaries are located under the ${OPENSSL_DIR}/lib/
+# directory. However, for a local build of OpenSSL, the built binaries are
+# located under the main project directory (i.e.: ${OPENSSL_DIR}, not
+# ${OPENSSL_DIR}/lib/).
+LIB_DIR := -L ${OPENSSL_DIR}/lib -L ${OPENSSL_DIR}
+LIB := -lssl -lcrypto
+
+HOSTCC ?= gcc
+
+.PHONY: all clean realclean --openssl
+
+all: ${BINARY}
+
+${BINARY}: --openssl ${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 $@
+
+--openssl:
+ifeq ($(DEBUG),1)
+ @echo "Selected OpenSSL version: ${OPENSSL_CURRENT_VER}"
+endif
+
+clean:
+ $(call SHELL_DELETE_ALL, src/build_msg.o ${OBJECTS})
+
+realclean: clean
+ $(call SHELL_DELETE,${BINARY})
+
diff --git a/tools/cert_create/include/cca/cca_cot.h b/tools/cert_create/include/cca/cca_cot.h
new file mode 100644
index 0000000..56585fb
--- /dev/null
+++ b/tools/cert_create/include/cca/cca_cot.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CCA_COT_H
+#define CCA_COT_H
+
+/* Certificates. */
+enum {
+ /* Certificates owned by the silicon provider. */
+ CCA_CONTENT_CERT,
+ CORE_SWD_KEY_CERT,
+ SPMC_CONTENT_CERT,
+ SIP_SECURE_PARTITION_CONTENT_CERT,
+
+ /* Certificates owned by the platform owner. */
+ PLAT_KEY_CERT,
+ PLAT_SECURE_PARTITION_CONTENT_CERT,
+ NON_TRUSTED_FW_CONTENT_CERT,
+};
+
+/* Certificate extensions. */
+enum {
+ /* Extensions used in certificates owned by the silicon provider. */
+ TRUSTED_FW_NVCOUNTER_EXT,
+ TRUSTED_BOOT_FW_HASH_EXT,
+ TRUSTED_BOOT_FW_CONFIG_HASH_EXT,
+ HW_CONFIG_HASH_EXT,
+ FW_CONFIG_HASH_EXT,
+ SWD_ROT_PK_EXT,
+ CORE_SWD_PK_EXT,
+ SOC_AP_FW_HASH_EXT,
+ SOC_FW_CONFIG_HASH_EXT,
+ RMM_HASH_EXT,
+ TRUSTED_OS_FW_HASH_EXT,
+ TRUSTED_OS_FW_CONFIG_HASH_EXT,
+ SP_PKG1_HASH_EXT,
+ SP_PKG2_HASH_EXT,
+ SP_PKG3_HASH_EXT,
+ SP_PKG4_HASH_EXT,
+
+ /* Extensions used in certificates owned by the platform owner. */
+ PROT_PK_EXT,
+ PLAT_PK_EXT,
+ SP_PKG5_HASH_EXT,
+ SP_PKG6_HASH_EXT,
+ SP_PKG7_HASH_EXT,
+ SP_PKG8_HASH_EXT,
+ NON_TRUSTED_FW_NVCOUNTER_EXT,
+ NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT,
+ NON_TRUSTED_FW_CONFIG_HASH_EXT,
+};
+
+/* Keys. */
+enum {
+ /* Keys owned by the silicon provider. */
+ ROT_KEY,
+ SWD_ROT_KEY,
+ CORE_SWD_KEY,
+
+ /* Keys owned by the platform owner. */
+ PROT_KEY,
+ PLAT_KEY,
+};
+
+#endif /* CCA_COT_H */
diff --git a/tools/cert_create/include/cert.h b/tools/cert_create/include/cert.h
new file mode 100644
index 0000000..5d39a88
--- /dev/null
+++ b/tools/cert_create/include/cert.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CERT_H
+#define CERT_H
+
+#include <openssl/ossl_typ.h>
+#include <openssl/x509.h>
+#include "ext.h"
+#include "key.h"
+
+#define CERT_MAX_EXT 9
+
+/*
+ * 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);
+void cert_cleanup(void);
+
+/* Macro to register the certificates used in the CoT */
+#define REGISTER_COT(_certs) \
+ cert_t *def_certs = &_certs[0]; \
+ const unsigned int num_def_certs = sizeof(_certs)/sizeof(_certs[0])
+
+/* Macro to register the platform defined certificates used in the CoT */
+#define PLAT_REGISTER_COT(_pdef_certs) \
+ cert_t *pdef_certs = &_pdef_certs[0]; \
+ const unsigned int num_pdef_certs = sizeof(_pdef_certs)/sizeof(_pdef_certs[0])
+
+/* Exported variables */
+extern cert_t *def_certs;
+extern const unsigned int num_def_certs;
+extern cert_t *pdef_certs;
+extern const unsigned int num_pdef_certs;
+
+extern cert_t *certs;
+extern unsigned int num_certs;
+#endif /* CERT_H */
diff --git a/tools/cert_create/include/cmd_opt.h b/tools/cert_create/include/cmd_opt.h
new file mode 100644
index 0000000..10df00e
--- /dev/null
+++ b/tools/cert_create/include/cmd_opt.h
@@ -0,0 +1,33 @@
+/*
+ * 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 <getopt.h>
+
+#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 */
diff --git a/tools/cert_create/include/debug.h b/tools/cert_create/include/debug.h
new file mode 100644
index 0000000..ee8f1f5
--- /dev/null
+++ b/tools/cert_create/include/debug.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <stdio.h>
+
+/* 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 */
diff --git a/tools/cert_create/include/dualroot/cot.h b/tools/cert_create/include/dualroot/cot.h
new file mode 100644
index 0000000..3e50c89
--- /dev/null
+++ b/tools/cert_create/include/dualroot/cot.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DUALROOT_COT_H
+#define DUALROOT_COT_H
+
+/* Certificates. */
+enum {
+ /* Certificates owned by the silicon provider. */
+ 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,
+ SIP_SECURE_PARTITION_CONTENT_CERT,
+ FWU_CERT,
+
+ /* Certificates owned by the platform owner. */
+ NON_TRUSTED_FW_CONTENT_CERT,
+ PLAT_SECURE_PARTITION_CONTENT_CERT,
+};
+
+/* Certificate extensions. */
+enum {
+ /* Extensions used in certificates owned by the silicon provider. */
+ TRUSTED_FW_NVCOUNTER_EXT,
+ TRUSTED_BOOT_FW_HASH_EXT,
+ TRUSTED_BOOT_FW_CONFIG_HASH_EXT,
+ HW_CONFIG_HASH_EXT,
+ FW_CONFIG_HASH_EXT,
+ 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,
+ SP_PKG1_HASH_EXT,
+ SP_PKG2_HASH_EXT,
+ SP_PKG3_HASH_EXT,
+ SP_PKG4_HASH_EXT,
+ SP_PKG5_HASH_EXT,
+ SP_PKG6_HASH_EXT,
+ SP_PKG7_HASH_EXT,
+ SP_PKG8_HASH_EXT,
+ SCP_FWU_CFG_HASH_EXT,
+ AP_FWU_CFG_HASH_EXT,
+ FWU_HASH_EXT,
+
+ /* Extensions used in certificates owned by the platform owner. */
+ PROT_PK_EXT,
+ NON_TRUSTED_FW_NVCOUNTER_EXT,
+ NON_TRUSTED_FW_CONTENT_CERT_PK_EXT,
+ NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT,
+ NON_TRUSTED_FW_CONFIG_HASH_EXT,
+};
+
+/* Keys. */
+enum {
+ /* Keys owned by the silicon provider. */
+ ROT_KEY,
+ TRUSTED_WORLD_KEY,
+ SCP_FW_CONTENT_CERT_KEY,
+ SOC_FW_CONTENT_CERT_KEY,
+ TRUSTED_OS_FW_CONTENT_CERT_KEY,
+
+ /* Keys owned by the platform owner. */
+ PROT_KEY,
+};
+
+#endif /* DUALROOT_COT_H */
diff --git a/tools/cert_create/include/ext.h b/tools/cert_create/include/ext.h
new file mode 100644
index 0000000..0e7f3be
--- /dev/null
+++ b/tools/cert_create/include/ext.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EXT_H
+#define EXT_H
+
+#include <openssl/x509v3.h>
+#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);
+void ext_cleanup(void);
+
+/* Macro to register the extensions used in the CoT */
+#define REGISTER_EXTENSIONS(_ext) \
+ ext_t *def_extensions = &_ext[0]; \
+ const unsigned int num_def_extensions = sizeof(_ext)/sizeof(_ext[0])
+
+/* Macro to register the platform defined extensions used in the CoT */
+#define PLAT_REGISTER_EXTENSIONS(_pdef_ext) \
+ ext_t *pdef_extensions = &_pdef_ext[0]; \
+ const unsigned int num_pdef_extensions = sizeof(_pdef_ext)/sizeof(_pdef_ext[0])
+
+/* Exported variables */
+extern ext_t *def_extensions;
+extern const unsigned int num_def_extensions;
+extern ext_t *pdef_extensions;
+extern const unsigned int num_pdef_extensions;
+
+extern ext_t *extensions;
+extern unsigned int num_extensions;
+#endif /* EXT_H */
diff --git a/tools/cert_create/include/key.h b/tools/cert_create/include/key.h
new file mode 100644
index 0000000..312575b
--- /dev/null
+++ b/tools/cert_create/include/key.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef KEY_H
+#define KEY_H
+
+#include <openssl/ossl_typ.h>
+
+/* 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_NIST,
+ KEY_ALG_ECDSA_BRAINPOOL_R,
+ KEY_ALG_ECDSA_BRAINPOOL_T,
+#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_NIST */
+ {}, /* KEY_ALG_ECDSA_BRAINPOOL_R */
+ {} /* KEY_ALG_ECDSA_BRAINPOOL_T */
+#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);
+#if !USING_OPENSSL3
+int key_new(key_t *key);
+#endif
+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);
+void key_cleanup(void);
+
+/* Macro to register the keys used in the CoT */
+#define REGISTER_KEYS(_keys) \
+ key_t *def_keys = &_keys[0]; \
+ const unsigned int num_def_keys = sizeof(_keys)/sizeof(_keys[0])
+
+/* Macro to register the platform defined keys used in the CoT */
+#define PLAT_REGISTER_KEYS(_pdef_keys) \
+ key_t *pdef_keys = &_pdef_keys[0]; \
+ const unsigned int num_pdef_keys = sizeof(_pdef_keys)/sizeof(_pdef_keys[0])
+
+/* Exported variables */
+extern key_t *def_keys;
+extern const unsigned int num_def_keys;
+extern key_t *pdef_keys;
+extern const unsigned int num_pdef_keys;
+
+extern key_t *keys;
+extern unsigned int num_keys;
+#endif /* KEY_H */
diff --git a/tools/cert_create/include/sha.h b/tools/cert_create/include/sha.h
new file mode 100644
index 0000000..4c55f37
--- /dev/null
+++ b/tools/cert_create/include/sha.h
@@ -0,0 +1,12 @@
+/*
+ * 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 */
diff --git a/tools/cert_create/include/tbbr/tbb_cert.h b/tools/cert_create/include/tbbr/tbb_cert.h
new file mode 100644
index 0000000..e5fa3a2
--- /dev/null
+++ b/tools/cert_create/include/tbbr/tbb_cert.h
@@ -0,0 +1,30 @@
+/*
+ * 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,
+ SIP_SECURE_PARTITION_CONTENT_CERT,
+ FWU_CERT
+};
+
+#endif /* TBB_CERT_H */
diff --git a/tools/cert_create/include/tbbr/tbb_ext.h b/tools/cert_create/include/tbbr/tbb_ext.h
new file mode 100644
index 0000000..692b2d4
--- /dev/null
+++ b/tools/cert_create/include/tbbr/tbb_ext.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015-2020, 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,
+ FW_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,
+ SP_PKG1_HASH_EXT,
+ SP_PKG2_HASH_EXT,
+ SP_PKG3_HASH_EXT,
+ SP_PKG4_HASH_EXT,
+ SP_PKG5_HASH_EXT,
+ SP_PKG6_HASH_EXT,
+ SP_PKG7_HASH_EXT,
+ SP_PKG8_HASH_EXT,
+ SCP_FWU_CFG_HASH_EXT,
+ AP_FWU_CFG_HASH_EXT,
+ FWU_HASH_EXT
+};
+
+#endif /* TBB_EXT_H */
diff --git a/tools/cert_create/include/tbbr/tbb_key.h b/tools/cert_create/include/tbbr/tbb_key.h
new file mode 100644
index 0000000..47ad1de
--- /dev/null
+++ b/tools/cert_create/include/tbbr/tbb_key.h
@@ -0,0 +1,25 @@
+/*
+ * 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 */
diff --git a/tools/cert_create/src/cca/cot.c b/tools/cert_create/src/cca/cot.c
new file mode 100644
index 0000000..5a35ff6
--- /dev/null
+++ b/tools/cert_create/src/cca/cot.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "cca/cca_cot.h"
+
+#include <cca_oid.h>
+
+#include "cert.h"
+#include "ext.h"
+#include "key.h"
+
+/*
+ * Certificates used in the chain of trust.
+ *
+ * All certificates are self-signed so the issuer certificate field points to
+ * itself.
+ */
+static cert_t cot_certs[] = {
+ [CCA_CONTENT_CERT] = {
+ .id = CCA_CONTENT_CERT,
+ .opt = "cca-cert",
+ .help_msg = "CCA Content Certificate (output file)",
+ .cn = "CCA Content Certificate",
+ .key = ROT_KEY,
+ .issuer = CCA_CONTENT_CERT,
+ .ext = {
+ TRUSTED_FW_NVCOUNTER_EXT,
+ SOC_AP_FW_HASH_EXT,
+ SOC_FW_CONFIG_HASH_EXT,
+ RMM_HASH_EXT,
+ TRUSTED_BOOT_FW_HASH_EXT,
+ TRUSTED_BOOT_FW_CONFIG_HASH_EXT,
+ HW_CONFIG_HASH_EXT,
+ FW_CONFIG_HASH_EXT,
+ },
+ .num_ext = 8
+ },
+
+ [CORE_SWD_KEY_CERT] = {
+ .id = CORE_SWD_KEY_CERT,
+ .opt = "core-swd-cert",
+ .help_msg = "Core Secure World Key Certificate (output file)",
+ .cn = "Core Secure World Key Certificate",
+ .key = SWD_ROT_KEY,
+ .issuer = CORE_SWD_KEY_CERT,
+ .ext = {
+ TRUSTED_FW_NVCOUNTER_EXT,
+ SWD_ROT_PK_EXT,
+ CORE_SWD_PK_EXT,
+ },
+ .num_ext = 3
+ },
+
+ [SPMC_CONTENT_CERT] = {
+ .id = SPMC_CONTENT_CERT,
+ .opt = "tos-fw-cert",
+ .help_msg = "SPMC Content Certificate (output file)",
+ .cn = "SPMC Content Certificate",
+ .key = CORE_SWD_KEY,
+ .issuer = SPMC_CONTENT_CERT,
+ .ext = {
+ TRUSTED_FW_NVCOUNTER_EXT,
+ TRUSTED_OS_FW_HASH_EXT,
+ TRUSTED_OS_FW_CONFIG_HASH_EXT,
+ },
+ .num_ext = 3
+ },
+
+ [SIP_SECURE_PARTITION_CONTENT_CERT] = {
+ .id = SIP_SECURE_PARTITION_CONTENT_CERT,
+ .opt = "sip-sp-cert",
+ .help_msg = "SiP owned Secure Partition Content Certificate (output file)",
+ .cn = "SiP owned Secure Partition Content Certificate",
+ .key = CORE_SWD_KEY,
+ .issuer = SIP_SECURE_PARTITION_CONTENT_CERT,
+ .ext = {
+ TRUSTED_FW_NVCOUNTER_EXT,
+ SP_PKG1_HASH_EXT,
+ SP_PKG2_HASH_EXT,
+ SP_PKG3_HASH_EXT,
+ SP_PKG4_HASH_EXT,
+ },
+ .num_ext = 5
+ },
+
+ [PLAT_KEY_CERT] = {
+ .id = PLAT_KEY_CERT,
+ .opt = "plat-key-cert",
+ .help_msg = "Platform Key Certificate (output file)",
+ .cn = "Platform Key Certificate",
+ .key = PROT_KEY,
+ .issuer = PLAT_KEY_CERT,
+ .ext = {
+ NON_TRUSTED_FW_NVCOUNTER_EXT,
+ PROT_PK_EXT,
+ PLAT_PK_EXT,
+ },
+ .num_ext = 3
+ },
+
+ [PLAT_SECURE_PARTITION_CONTENT_CERT] = {
+ .id = PLAT_SECURE_PARTITION_CONTENT_CERT,
+ .opt = "plat-sp-cert",
+ .help_msg = "Platform owned Secure Partition Content Certificate (output file)",
+ .cn = "Platform owned Secure Partition Content Certificate",
+ .key = PLAT_KEY,
+ .issuer = PLAT_SECURE_PARTITION_CONTENT_CERT,
+ .ext = {
+ NON_TRUSTED_FW_NVCOUNTER_EXT,
+ SP_PKG5_HASH_EXT,
+ SP_PKG6_HASH_EXT,
+ SP_PKG7_HASH_EXT,
+ SP_PKG8_HASH_EXT,
+ },
+ .num_ext = 5
+ },
+
+ [NON_TRUSTED_FW_CONTENT_CERT] = {
+ .id = NON_TRUSTED_FW_CONTENT_CERT,
+ .opt = "nt-fw-cert",
+ .help_msg = "Non-Trusted Firmware Content Certificate (output file)",
+ .cn = "Non-Trusted Firmware Content Certificate",
+ .key = PLAT_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
+ },
+};
+
+REGISTER_COT(cot_certs);
+
+
+/* Certificate extensions. */
+static ext_t cot_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
+ },
+
+ [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
+ },
+
+ [FW_CONFIG_HASH_EXT] = {
+ .oid = FW_CONFIG_HASH_OID,
+ .opt = "fw-config",
+ .help_msg = "Firmware Config file",
+ .sn = "FirmwareConfigHash",
+ .ln = "Firmware Config hash",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+
+ [SWD_ROT_PK_EXT] = {
+ .oid = SWD_ROT_PK_OID,
+ .sn = "SWDRoTKey",
+ .ln = "Secure World Root of Trust Public Key",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_PKEY,
+ .attr.key = SWD_ROT_KEY
+ },
+
+ [CORE_SWD_PK_EXT] = {
+ .oid = CORE_SWD_PK_OID,
+ .sn = "CORESWDKey",
+ .ln = "Core Secure World Public Key",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_PKEY,
+ .attr.key = CORE_SWD_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
+ },
+
+ [RMM_HASH_EXT] = {
+ .oid = RMM_HASH_OID,
+ .opt = "rmm-fw",
+ .help_msg = "RMM Firmware image file",
+ .sn = "RMMFirmwareHash",
+ .ln = "RMM Firmware hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH
+ },
+
+ [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_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
+ },
+
+ [SP_PKG1_HASH_EXT] = {
+ .oid = SP_PKG1_HASH_OID,
+ .opt = "sp-pkg1",
+ .help_msg = "Secure Partition Package1 file",
+ .sn = "SPPkg1Hash",
+ .ln = "SP Pkg1 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG2_HASH_EXT] = {
+ .oid = SP_PKG2_HASH_OID,
+ .opt = "sp-pkg2",
+ .help_msg = "Secure Partition Package2 file",
+ .sn = "SPPkg2Hash",
+ .ln = "SP Pkg2 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG3_HASH_EXT] = {
+ .oid = SP_PKG3_HASH_OID,
+ .opt = "sp-pkg3",
+ .help_msg = "Secure Partition Package3 file",
+ .sn = "SPPkg3Hash",
+ .ln = "SP Pkg3 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG4_HASH_EXT] = {
+ .oid = SP_PKG4_HASH_OID,
+ .opt = "sp-pkg4",
+ .help_msg = "Secure Partition Package4 file",
+ .sn = "SPPkg4Hash",
+ .ln = "SP Pkg4 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+
+ [PROT_PK_EXT] = {
+ .oid = PROT_PK_OID,
+ .sn = "PlatformRoTKey",
+ .ln = "Platform Root of Trust Public Key",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_PKEY,
+ .attr.key = PROT_KEY
+ },
+
+ [PLAT_PK_EXT] = {
+ .oid = PLAT_PK_OID,
+ .sn = "PLATKey",
+ .ln = "Platform Public Key",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_PKEY,
+ .attr.key = PLAT_KEY
+ },
+
+ [SP_PKG5_HASH_EXT] = {
+ .oid = SP_PKG5_HASH_OID,
+ .opt = "sp-pkg5",
+ .help_msg = "Secure Partition Package5 file",
+ .sn = "SPPkg5Hash",
+ .ln = "SP Pkg5 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG6_HASH_EXT] = {
+ .oid = SP_PKG6_HASH_OID,
+ .opt = "sp-pkg6",
+ .help_msg = "Secure Partition Package6 file",
+ .sn = "SPPkg6Hash",
+ .ln = "SP Pkg6 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG7_HASH_EXT] = {
+ .oid = SP_PKG7_HASH_OID,
+ .opt = "sp-pkg7",
+ .help_msg = "Secure Partition Package7 file",
+ .sn = "SPPkg7Hash",
+ .ln = "SP Pkg7 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG8_HASH_EXT] = {
+ .oid = SP_PKG8_HASH_OID,
+ .opt = "sp-pkg8",
+ .help_msg = "Secure Partition Package8 file",
+ .sn = "SPPkg8Hash",
+ .ln = "SP Pkg8 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+
+ [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
+ },
+
+ [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
+ },
+};
+
+REGISTER_EXTENSIONS(cot_ext);
+
+/* Keys used to establish the chain of trust. */
+static key_t cot_keys[] = {
+ [ROT_KEY] = {
+ .id = ROT_KEY,
+ .opt = "rot-key",
+ .help_msg = "Root Of Trust key (input/output file)",
+ .desc = "Root Of Trust key"
+ },
+
+ [SWD_ROT_KEY] = {
+ .id = SWD_ROT_KEY,
+ .opt = "swd-rot-key",
+ .help_msg = "Secure World Root of Trust key",
+ .desc = "Secure World Root of Trust key"
+ },
+
+ [CORE_SWD_KEY] = {
+ .id = CORE_SWD_KEY,
+ .opt = "core-swd-key",
+ .help_msg = "Core Secure World key",
+ .desc = "Core Secure World key"
+ },
+
+ [PROT_KEY] = {
+ .id = PROT_KEY,
+ .opt = "prot-key",
+ .help_msg = "Platform Root of Trust key",
+ .desc = "Platform Root of Trust key"
+ },
+
+ [PLAT_KEY] = {
+ .id = PLAT_KEY,
+ .opt = "plat-key",
+ .help_msg = "Platform key",
+ .desc = "Platform key"
+ },
+};
+
+REGISTER_KEYS(cot_keys);
diff --git a/tools/cert_create/src/cca/cot.mk b/tools/cert_create/src/cca/cot.mk
new file mode 100644
index 0000000..d0c80bb
--- /dev/null
+++ b/tools/cert_create/src/cca/cot.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT_MSG := Confidential Compute Architecture root of trust
+PLAT_INCLUDE := ../../include/tools_share
+
+OBJECTS += src/cca/cot.o
diff --git a/tools/cert_create/src/cert.c b/tools/cert_create/src/cert.c
new file mode 100644
index 0000000..2513213
--- /dev/null
+++ b/tools/cert_create/src/cert.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/opensslv.h>
+#include <openssl/pem.h>
+#include <openssl/sha.h>
+#include <openssl/x509v3.h>
+
+#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
+
+cert_t *certs;
+unsigned int num_certs;
+
+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 USING_OPENSSL3
+ if (!BN_rand(btmp, SERIAL_RAND_BITS, 0, 0))
+#else
+ if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0))
+#endif
+ 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;
+
+ certs = malloc((num_def_certs * sizeof(def_certs[0]))
+#ifdef PDEF_CERTS
+ + (num_pdef_certs * sizeof(pdef_certs[0]))
+#endif
+ );
+ if (certs == NULL) {
+ ERROR("%s:%d Failed to allocate memory.\n", __func__, __LINE__);
+ return 1;
+ }
+
+ memcpy(&certs[0], &def_certs[0],
+ (num_def_certs * sizeof(def_certs[0])));
+
+#ifdef PDEF_CERTS
+ memcpy(&certs[num_def_certs], &pdef_certs[0],
+ (num_pdef_certs * sizeof(pdef_certs[0])));
+
+ num_certs = num_def_certs + num_pdef_certs;
+#else
+ num_certs = num_def_certs;
+#endif
+
+ 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;
+}
+
+void cert_cleanup(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_certs; i++) {
+ if (certs[i].fn != NULL) {
+ void *ptr = (void *)certs[i].fn;
+
+ certs[i].fn = NULL;
+ free(ptr);
+ }
+ }
+ free(certs);
+}
+
diff --git a/tools/cert_create/src/cmd_opt.c b/tools/cert_create/src/cmd_opt.c
new file mode 100644
index 0000000..64180d1
--- /dev/null
+++ b/tools/cert_create/src/cmd_opt.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <cmd_opt.h>
+#include <getopt.h>
+#include <stddef.h>
+#include <stdlib.h>
+#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];
+}
diff --git a/tools/cert_create/src/dualroot/cot.c b/tools/cert_create/src/dualroot/cot.c
new file mode 100644
index 0000000..4dd4cf0
--- /dev/null
+++ b/tools/cert_create/src/dualroot/cot.c
@@ -0,0 +1,583 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <dualroot_oid.h>
+
+#include "cert.h"
+#include "ext.h"
+#include "key.h"
+
+#include "dualroot/cot.h"
+
+/*
+ * Certificates used in the chain of trust.
+ *
+ * All certificates are self-signed so the issuer certificate field points to
+ * itself.
+ */
+static cert_t cot_certs[] = {
+ [TRUSTED_BOOT_FW_CERT] = {
+ .id = TRUSTED_BOOT_FW_CERT,
+ .opt = "tb-fw-cert",
+ .help_msg = "Trusted Boot FW Certificate (output file)",
+ .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,
+ FW_CONFIG_HASH_EXT
+ },
+ .num_ext = 5
+ },
+
+ [TRUSTED_KEY_CERT] = {
+ .id = TRUSTED_KEY_CERT,
+ .opt = "trusted-key-cert",
+ .help_msg = "Trusted Key Certificate (output file)",
+ .cn = "Trusted Key Certificate",
+ .key = ROT_KEY,
+ .issuer = TRUSTED_KEY_CERT,
+ .ext = {
+ TRUSTED_FW_NVCOUNTER_EXT,
+ TRUSTED_WORLD_PK_EXT,
+ },
+ .num_ext = 2
+ },
+
+ [SCP_FW_KEY_CERT] = {
+ .id = SCP_FW_KEY_CERT,
+ .opt = "scp-fw-key-cert",
+ .help_msg = "SCP Firmware Key Certificate (output file)",
+ .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)",
+ .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)",
+ .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)",
+ .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)",
+ .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)",
+ .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
+ },
+
+ [SIP_SECURE_PARTITION_CONTENT_CERT] = {
+ .id = SIP_SECURE_PARTITION_CONTENT_CERT,
+ .opt = "sip-sp-cert",
+ .help_msg = "SiP owned Secure Partition Content Certificate (output file)",
+ .fn = NULL,
+ .cn = "SiP owned Secure Partition Content Certificate",
+ .key = TRUSTED_WORLD_KEY,
+ .issuer = SIP_SECURE_PARTITION_CONTENT_CERT,
+ .ext = {
+ TRUSTED_FW_NVCOUNTER_EXT,
+ SP_PKG1_HASH_EXT,
+ SP_PKG2_HASH_EXT,
+ SP_PKG3_HASH_EXT,
+ SP_PKG4_HASH_EXT,
+ },
+ .num_ext = 5
+ },
+
+ [PLAT_SECURE_PARTITION_CONTENT_CERT] = {
+ .id = PLAT_SECURE_PARTITION_CONTENT_CERT,
+ .opt = "plat-sp-cert",
+ .help_msg = "Platform owned Secure Partition Content Certificate (output file)",
+ .fn = NULL,
+ .cn = "Platform owned Secure Partition Content Certificate",
+ .key = PROT_KEY,
+ .issuer = PLAT_SECURE_PARTITION_CONTENT_CERT,
+ .ext = {
+ NON_TRUSTED_FW_NVCOUNTER_EXT,
+ SP_PKG5_HASH_EXT,
+ SP_PKG6_HASH_EXT,
+ SP_PKG7_HASH_EXT,
+ SP_PKG8_HASH_EXT,
+ PROT_PK_EXT,
+ },
+ .num_ext = 6
+ },
+
+ [FWU_CERT] = {
+ .id = FWU_CERT,
+ .opt = "fwu-cert",
+ .help_msg = "Firmware Update Certificate (output file)",
+ .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
+ },
+
+ [NON_TRUSTED_FW_CONTENT_CERT] = {
+ .id = NON_TRUSTED_FW_CONTENT_CERT,
+ .opt = "nt-fw-cert",
+ .help_msg = "Non-Trusted Firmware Content Certificate (output file)",
+ .cn = "Non-Trusted Firmware Content Certificate",
+ .key = PROT_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,
+ PROT_PK_EXT,
+ },
+ .num_ext = 4
+ },
+};
+
+REGISTER_COT(cot_certs);
+
+
+/* Certificate extensions. */
+static ext_t cot_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
+ },
+
+ [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
+ },
+
+ [FW_CONFIG_HASH_EXT] = {
+ .oid = FW_CONFIG_HASH_OID,
+ .opt = "fw-config",
+ .help_msg = "Firmware Config file",
+ .sn = "FirmwareConfigHash",
+ .ln = "Firmware 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
+ },
+
+ [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
+ },
+
+ [SP_PKG1_HASH_EXT] = {
+ .oid = SP_PKG1_HASH_OID,
+ .opt = "sp-pkg1",
+ .help_msg = "Secure Partition Package1 file",
+ .sn = "SPPkg1Hash",
+ .ln = "SP Pkg1 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG2_HASH_EXT] = {
+ .oid = SP_PKG2_HASH_OID,
+ .opt = "sp-pkg2",
+ .help_msg = "Secure Partition Package2 file",
+ .sn = "SPPkg2Hash",
+ .ln = "SP Pkg2 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG3_HASH_EXT] = {
+ .oid = SP_PKG3_HASH_OID,
+ .opt = "sp-pkg3",
+ .help_msg = "Secure Partition Package3 file",
+ .sn = "SPPkg3Hash",
+ .ln = "SP Pkg3 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG4_HASH_EXT] = {
+ .oid = SP_PKG4_HASH_OID,
+ .opt = "sp-pkg4",
+ .help_msg = "Secure Partition Package4 file",
+ .sn = "SPPkg4Hash",
+ .ln = "SP Pkg4 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG5_HASH_EXT] = {
+ .oid = SP_PKG5_HASH_OID,
+ .opt = "sp-pkg5",
+ .help_msg = "Secure Partition Package5 file",
+ .sn = "SPPkg5Hash",
+ .ln = "SP Pkg5 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG6_HASH_EXT] = {
+ .oid = SP_PKG6_HASH_OID,
+ .opt = "sp-pkg6",
+ .help_msg = "Secure Partition Package6 file",
+ .sn = "SPPkg6Hash",
+ .ln = "SP Pkg6 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG7_HASH_EXT] = {
+ .oid = SP_PKG7_HASH_OID,
+ .opt = "sp-pkg7",
+ .help_msg = "Secure Partition Package7 file",
+ .sn = "SPPkg7Hash",
+ .ln = "SP Pkg7 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG8_HASH_EXT] = {
+ .oid = SP_PKG8_HASH_OID,
+ .opt = "sp-pkg8",
+ .help_msg = "Secure Partition Package8 file",
+ .sn = "SPPkg8Hash",
+ .ln = "SP Pkg8 hash (SHA256)",
+ .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
+ },
+
+ [PROT_PK_EXT] = {
+ .oid = PROT_PK_OID,
+ .sn = "PlatformRoTKey",
+ .ln = "Platform Root of Trust Public Key",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_PKEY,
+ .attr.key = PROT_KEY
+ },
+
+ [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
+ },
+
+ [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
+ },
+};
+
+REGISTER_EXTENSIONS(cot_ext);
+
+
+/* Keys used to establish the chain of trust. */
+static key_t cot_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"
+ },
+
+ [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"
+ },
+
+ [PROT_KEY] = {
+ .id = PROT_KEY,
+ .opt = "prot-key",
+ .help_msg = "Platform Root of Trust key",
+ .desc = "Platform Root of Trust key"
+ },
+};
+
+REGISTER_KEYS(cot_keys);
diff --git a/tools/cert_create/src/dualroot/cot.mk b/tools/cert_create/src/dualroot/cot.mk
new file mode 100644
index 0000000..a572484
--- /dev/null
+++ b/tools/cert_create/src/dualroot/cot.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT_MSG := Dual root of trust
+PLAT_INCLUDE := ../../include/tools_share
+
+OBJECTS += src/dualroot/cot.o
diff --git a/tools/cert_create/src/ext.c b/tools/cert_create/src/ext.c
new file mode 100644
index 0000000..acf57a4
--- /dev/null
+++ b/tools/cert_create/src/ext.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/err.h>
+#include <openssl/x509v3.h>
+
+#include "cmd_opt.h"
+#include "debug.h"
+#include "ext.h"
+
+ext_t *extensions;
+unsigned int num_extensions;
+
+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 CoT 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 CoT 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;
+
+ extensions = malloc((num_def_extensions * sizeof(def_extensions[0]))
+#ifdef PDEF_EXTS
+ + (num_pdef_extensions * sizeof(pdef_extensions[0]))
+#endif
+ );
+ if (extensions == NULL) {
+ ERROR("%s:%d Failed to allocate memory.\n", __func__, __LINE__);
+ return 1;
+ }
+
+ memcpy(&extensions[0], &def_extensions[0],
+ (num_def_extensions * sizeof(def_extensions[0])));
+#ifdef PDEF_EXTS
+ memcpy(&extensions[num_def_extensions], &pdef_extensions[0],
+ (num_pdef_extensions * sizeof(pdef_extensions[0])));
+ num_extensions = num_def_extensions + num_pdef_extensions;
+#else
+ num_extensions = num_def_extensions;
+#endif
+
+ 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;
+ HASH *hash;
+ ASN1_OBJECT *algorithm;
+ unsigned char *p = NULL;
+ int sz;
+
+ /* HASH structure containing algorithm + hash */
+ hash = HASH_new();
+ if (hash == NULL) {
+ return NULL;
+ }
+
+ /* OBJECT_IDENTIFIER with hash algorithm */
+ algorithm = OBJ_nid2obj(EVP_MD_type(md));
+ if (algorithm == NULL) {
+ HASH_free(hash);
+ return NULL;
+ }
+
+ /* Create X509_ALGOR */
+ hash->hashAlgorithm->algorithm = algorithm;
+ hash->hashAlgorithm->parameter = ASN1_TYPE_new();
+ ASN1_TYPE_set(hash->hashAlgorithm->parameter, V_ASN1_NULL, NULL);
+
+ /* OCTET_STRING with the actual hash */
+ ASN1_OCTET_STRING_set(hash->dataHash, buf, len);
+
+ /* DER encoded HASH */
+ sz = i2d_HASH(hash, &p);
+ if ((sz <= 0) || (p == NULL)) {
+ HASH_free(hash);
+ 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;
+}
+
+void ext_cleanup(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_extensions; i++) {
+ if (extensions[i].arg != NULL) {
+ void *ptr = (void *)extensions[i].arg;
+
+ extensions[i].arg = NULL;
+ free(ptr);
+ }
+ }
+ free(extensions);
+ X509V3_EXT_cleanup();
+}
+
diff --git a/tools/cert_create/src/key.c b/tools/cert_create/src/key.c
new file mode 100644
index 0000000..487777b
--- /dev/null
+++ b/tools/cert_create/src/key.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/conf.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+
+#include "cert.h"
+#include "cmd_opt.h"
+#include "debug.h"
+#include "key.h"
+#include "sha.h"
+
+#define MAX_FILENAME_LEN 1024
+
+key_t *keys;
+unsigned int num_keys;
+
+#if !USING_OPENSSL3
+/*
+ * 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;
+}
+#endif
+
+static int key_create_rsa(key_t *key, int key_bits)
+{
+#if USING_OPENSSL3
+ EVP_PKEY *rsa = EVP_RSA_gen(key_bits);
+ if (rsa == NULL) {
+ printf("Cannot generate RSA key\n");
+ return 0;
+ }
+ key->key = rsa;
+ return 1;
+#else
+ BIGNUM *e;
+ RSA *rsa = NULL;
+
+ e = BN_new();
+ if (e == NULL) {
+ printf("Cannot create RSA exponent\n");
+ return 0;
+ }
+
+ if (!BN_set_word(e, RSA_F4)) {
+ printf("Cannot assign RSA exponent\n");
+ goto err2;
+ }
+
+ rsa = RSA_new();
+ if (rsa == NULL) {
+ printf("Cannot create RSA key\n");
+ goto err2;
+ }
+
+ 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);
+err2:
+ BN_free(e);
+ return 0;
+#endif
+}
+
+#ifndef OPENSSL_NO_EC
+#if USING_OPENSSL3
+static int key_create_ecdsa(key_t *key, int key_bits, const char *curve)
+{
+ EVP_PKEY *ec = EVP_EC_gen(curve);
+ if (ec == NULL) {
+ printf("Cannot generate EC key\n");
+ return 0;
+ }
+
+ key->key = ec;
+ return 1;
+}
+
+static int key_create_ecdsa_nist(key_t *key, int key_bits)
+{
+ return key_create_ecdsa(key, key_bits, "prime256v1");
+}
+
+static int key_create_ecdsa_brainpool_r(key_t *key, int key_bits)
+{
+ return key_create_ecdsa(key, key_bits, "brainpoolP256r1");
+}
+
+static int key_create_ecdsa_brainpool_t(key_t *key, int key_bits)
+{
+ return key_create_ecdsa(key, key_bits, "brainpoolP256t1");
+}
+#else
+static int key_create_ecdsa(key_t *key, int key_bits, const int curve_id)
+{
+ EC_KEY *ec;
+
+ ec = EC_KEY_new_by_curve_name(curve_id);
+ if (ec == NULL) {
+ printf("Cannot create EC key\n");
+ return 0;
+ }
+ 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;
+}
+
+static int key_create_ecdsa_nist(key_t *key, int key_bits)
+{
+ return key_create_ecdsa(key, key_bits, NID_X9_62_prime256v1);
+}
+
+static int key_create_ecdsa_brainpool_r(key_t *key, int key_bits)
+{
+ return key_create_ecdsa(key, key_bits, NID_brainpoolP256r1);
+}
+
+static int key_create_ecdsa_brainpool_t(key_t *key, int key_bits)
+{
+ return key_create_ecdsa(key, key_bits, NID_brainpoolP256t1);
+}
+#endif /* USING_OPENSSL3 */
+#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_ALG_RSA] = key_create_rsa,
+#ifndef OPENSSL_NO_EC
+ [KEY_ALG_ECDSA_NIST] = key_create_ecdsa_nist,
+ [KEY_ALG_ECDSA_BRAINPOOL_R] = key_create_ecdsa_brainpool_r,
+ [KEY_ALG_ECDSA_BRAINPOOL_T] = key_create_ecdsa_brainpool_t,
+#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;
+
+ keys = malloc((num_def_keys * sizeof(def_keys[0]))
+#ifdef PDEF_KEYS
+ + (num_pdef_keys * sizeof(pdef_keys[0]))
+#endif
+ );
+
+ if (keys == NULL) {
+ ERROR("%s:%d Failed to allocate memory.\n", __func__, __LINE__);
+ return 1;
+ }
+
+ memcpy(&keys[0], &def_keys[0], (num_def_keys * sizeof(def_keys[0])));
+#ifdef PDEF_KEYS
+ memcpy(&keys[num_def_keys], &pdef_keys[0],
+ (num_pdef_keys * sizeof(pdef_keys[0])));
+
+ num_keys = num_def_keys + num_pdef_keys;
+#else
+ num_keys = num_def_keys;
+#endif
+ ;
+
+ 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;
+}
+
+void key_cleanup(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_keys; i++) {
+ EVP_PKEY_free(keys[i].key);
+ if (keys[i].fn != NULL) {
+ void *ptr = keys[i].fn;
+
+ free(ptr);
+ keys[i].fn = NULL;
+ }
+ }
+ free(keys);
+}
+
diff --git a/tools/cert_create/src/main.c b/tools/cert_create/src/main.c
new file mode 100644
index 0000000..2ab6bcf
--- /dev/null
+++ b/tools/cert_create/src/main.c
@@ -0,0 +1,617 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <openssl/conf.h>
+#include <openssl/engine.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/sha.h>
+#include <openssl/x509v3.h>
+
+#include "cert.h"
+#include "cmd_opt.h"
+#include "debug.h"
+#include "ext.h"
+#include "key.h"
+#include "sha.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 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_NIST] = "ecdsa",
+ [KEY_ALG_ECDSA_BRAINPOOL_R] = "ecdsa-brainpool-regular",
+ [KEY_ALG_ECDSA_BRAINPOOL_T] = "ecdsa-brainpool-twisted",
+#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 or ECC 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) ? "<arg>" : "");
+ 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', 'ecdsa-brainpool-regular', 'ecdsa-brainpool-twisted'"
+ },
+ {
+ { "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 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 !USING_OPENSSL3
+ if (!key_new(&keys[i])) {
+ ERROR("Failed to allocate key container\n");
+ exit(1);
+ }
+#endif
+
+ /* 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];
+
+ if (cert->fn == NULL) {
+ /* Certificate not requested. Skip to the next one */
+ continue;
+ }
+
+ /* 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->optional && ext->arg == NULL) {
+ /* Skip this NVCounter */
+ continue;
+ } else {
+ /* Checked by `check_cmd_params` */
+ assert(ext->arg != NULL);
+ 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 */
+ continue;
+ }
+ } 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_new(hash_alg, cert, VAL_DAYS, 0, sk)) {
+ ERROR("Cannot create %s\n", cert->cn);
+ exit(1);
+ }
+
+ for (cert_ext = sk_X509_EXTENSION_pop(sk); cert_ext != NULL;
+ cert_ext = sk_X509_EXTENSION_pop(sk)) {
+ X509_EXTENSION_free(cert_ext);
+ }
+
+ 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);
+ }
+ }
+ }
+
+ /* If we got here, then we must have filled the key array completely.
+ * We can then safely call free on all of the keys in the array
+ */
+ key_cleanup();
+
+#ifndef OPENSSL_NO_ENGINE
+ ENGINE_cleanup();
+#endif
+ CRYPTO_cleanup_all_ex_data();
+
+
+ /* We allocated strings through strdup, so now we have to free them */
+
+ ext_cleanup();
+
+ cert_cleanup();
+
+ return 0;
+}
diff --git a/tools/cert_create/src/sha.c b/tools/cert_create/src/sha.c
new file mode 100644
index 0000000..bb750d4
--- /dev/null
+++ b/tools/cert_create/src/sha.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+#include "debug.h"
+#include "key.h"
+#if USING_OPENSSL3
+#include <openssl/evp.h>
+#include <openssl/obj_mac.h>
+#else
+#include <openssl/sha.h>
+#endif
+
+#define BUFFER_SIZE 256
+
+#if USING_OPENSSL3
+static int get_algorithm_nid(int hash_alg)
+{
+ int nids[] = {NID_sha256, NID_sha384, NID_sha512};
+ if (hash_alg < 0 || hash_alg >= sizeof(nids) / sizeof(*nids)) {
+ return NID_undef;
+ }
+ return nids[hash_alg];
+}
+#endif
+
+int sha_file(int md_alg, const char *filename, unsigned char *md)
+{
+ FILE *inFile;
+ int bytes;
+ unsigned char data[BUFFER_SIZE];
+#if USING_OPENSSL3
+ EVP_MD_CTX *mdctx;
+ const EVP_MD *md_type;
+ int alg_nid;
+ unsigned int total_bytes;
+#else
+ SHA256_CTX shaContext;
+ SHA512_CTX sha512Context;
+#endif
+
+ if ((filename == NULL) || (md == NULL)) {
+ ERROR("%s(): NULL argument\n", __func__);
+ return 0;
+ }
+
+ inFile = fopen(filename, "rb");
+ if (inFile == NULL) {
+ ERROR("Cannot read %s\n", filename);
+ return 0;
+ }
+
+#if USING_OPENSSL3
+
+ mdctx = EVP_MD_CTX_new();
+ if (mdctx == NULL) {
+ fclose(inFile);
+ ERROR("%s(): Could not create EVP MD context\n", __func__);
+ return 0;
+ }
+
+ alg_nid = get_algorithm_nid(md_alg);
+ if (alg_nid == NID_undef) {
+ ERROR("%s(): Invalid hash algorithm\n", __func__);
+ goto err;
+ }
+
+ md_type = EVP_get_digestbynid(alg_nid);
+ if (EVP_DigestInit_ex(mdctx, md_type, NULL) == 0) {
+ ERROR("%s(): Could not initialize EVP MD digest\n", __func__);
+ goto err;
+ }
+
+ while ((bytes = fread(data, 1, BUFFER_SIZE, inFile)) != 0) {
+ EVP_DigestUpdate(mdctx, data, bytes);
+ }
+ EVP_DigestFinal_ex(mdctx, md, &total_bytes);
+
+ fclose(inFile);
+ EVP_MD_CTX_free(mdctx);
+ return 1;
+
+err:
+ fclose(inFile);
+ EVP_MD_CTX_free(mdctx);
+ return 0;
+
+#else
+
+ 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;
+
+#endif
+}
+
diff --git a/tools/cert_create/src/tbbr/tbb_cert.c b/tools/cert_create/src/tbbr/tbb_cert.c
new file mode 100644
index 0000000..f4fe63d
--- /dev/null
+++ b/tools/cert_create/src/tbbr/tbb_cert.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2015-2020, 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,
+ FW_CONFIG_HASH_EXT
+ },
+ .num_ext = 5
+ },
+ [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
+ },
+ [SIP_SECURE_PARTITION_CONTENT_CERT] = {
+ .id = SIP_SECURE_PARTITION_CONTENT_CERT,
+ .opt = "sip-sp-cert",
+ .help_msg = "SiP owned Secure Partition Content Certificate (output file)",
+ .fn = NULL,
+ .cn = "SiP owned Secure Partition Content Certificate",
+ .key = TRUSTED_WORLD_KEY,
+ .issuer = SIP_SECURE_PARTITION_CONTENT_CERT,
+ .ext = {
+ TRUSTED_FW_NVCOUNTER_EXT,
+ SP_PKG1_HASH_EXT,
+ SP_PKG2_HASH_EXT,
+ SP_PKG3_HASH_EXT,
+ SP_PKG4_HASH_EXT,
+ SP_PKG5_HASH_EXT,
+ SP_PKG6_HASH_EXT,
+ SP_PKG7_HASH_EXT,
+ SP_PKG8_HASH_EXT,
+ },
+ .num_ext = 9
+ },
+ [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);
diff --git a/tools/cert_create/src/tbbr/tbb_ext.c b/tools/cert_create/src/tbbr/tbb_ext.c
new file mode 100644
index 0000000..60bafb4
--- /dev/null
+++ b/tools/cert_create/src/tbbr/tbb_ext.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <openssl/err.h>
+#include <openssl/x509v3.h>
+
+#if USE_TBBR_DEFS
+#include <tbbr_oid.h>
+#else
+#include <platform_oid.h>
+#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
+ },
+ [FW_CONFIG_HASH_EXT] = {
+ .oid = FW_CONFIG_HASH_OID,
+ .opt = "fw-config",
+ .help_msg = "Firmware Config file",
+ .sn = "FirmwareConfigHash",
+ .ln = "Firmware 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
+ },
+ [SP_PKG1_HASH_EXT] = {
+ .oid = SP_PKG1_HASH_OID,
+ .opt = "sp-pkg1",
+ .help_msg = "Secure Partition Package1 file",
+ .sn = "SPPkg1Hash",
+ .ln = "SP Pkg1 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG2_HASH_EXT] = {
+ .oid = SP_PKG2_HASH_OID,
+ .opt = "sp-pkg2",
+ .help_msg = "Secure Partition Package2 file",
+ .sn = "SPPkg2Hash",
+ .ln = "SP Pkg2 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG3_HASH_EXT] = {
+ .oid = SP_PKG3_HASH_OID,
+ .opt = "sp-pkg3",
+ .help_msg = "Secure Partition Package3 file",
+ .sn = "SPPkg3Hash",
+ .ln = "SP Pkg3 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG4_HASH_EXT] = {
+ .oid = SP_PKG4_HASH_OID,
+ .opt = "sp-pkg4",
+ .help_msg = "Secure Partition Package4 file",
+ .sn = "SPPkg4Hash",
+ .ln = "SP Pkg4 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG5_HASH_EXT] = {
+ .oid = SP_PKG5_HASH_OID,
+ .opt = "sp-pkg5",
+ .help_msg = "Secure Partition Package5 file",
+ .sn = "SPPkg5Hash",
+ .ln = "SP Pkg5 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG6_HASH_EXT] = {
+ .oid = SP_PKG6_HASH_OID,
+ .opt = "sp-pkg6",
+ .help_msg = "Secure Partition Package6 file",
+ .sn = "SPPkg6Hash",
+ .ln = "SP Pkg6 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG7_HASH_EXT] = {
+ .oid = SP_PKG7_HASH_OID,
+ .opt = "sp-pkg7",
+ .help_msg = "Secure Partition Package7 file",
+ .sn = "SPPkg7Hash",
+ .ln = "SP Pkg7 hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH,
+ .optional = 1
+ },
+ [SP_PKG8_HASH_EXT] = {
+ .oid = SP_PKG8_HASH_OID,
+ .opt = "sp-pkg8",
+ .help_msg = "Secure Partition Package8 file",
+ .sn = "SPPkg8Hash",
+ .ln = "SP Pkg8 hash (SHA256)",
+ .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);
diff --git a/tools/cert_create/src/tbbr/tbb_key.c b/tools/cert_create/src/tbbr/tbb_key.c
new file mode 100644
index 0000000..a81f0e4
--- /dev/null
+++ b/tools/cert_create/src/tbbr/tbb_key.c
@@ -0,0 +1,59 @@
+/*
+ * 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);
diff --git a/tools/cert_create/src/tbbr/tbbr.mk b/tools/cert_create/src/tbbr/tbbr.mk
new file mode 100644
index 0000000..ee82d31
--- /dev/null
+++ b/tools/cert_create/src/tbbr/tbbr.mk
@@ -0,0 +1,29 @@
+#
+# Copyright (c) 2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+USE_TBBR_DEFS := 1
+$(eval $(call add_define,USE_TBBR_DEFS))
+
+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
+
+OBJECTS += src/tbbr/tbb_cert.o \
+ src/tbbr/tbb_ext.o \
+ src/tbbr/tbb_key.o
diff --git a/tools/conventional-changelog-tf-a/index.js b/tools/conventional-changelog-tf-a/index.js
new file mode 100644
index 0000000..2a9d5b4
--- /dev/null
+++ b/tools/conventional-changelog-tf-a/index.js
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* eslint-env es6 */
+
+"use strict";
+
+const Handlebars = require("handlebars");
+const Q = require("q");
+const _ = require("lodash");
+
+const ccConventionalChangelog = require("conventional-changelog-conventionalcommits/conventional-changelog");
+const ccParserOpts = require("conventional-changelog-conventionalcommits/parser-opts");
+const ccRecommendedBumpOpts = require("conventional-changelog-conventionalcommits/conventional-recommended-bump");
+const ccWriterOpts = require("conventional-changelog-conventionalcommits/writer-opts");
+
+const execa = require("execa");
+
+const readFileSync = require("fs").readFileSync;
+const resolve = require("path").resolve;
+
+/*
+ * Register a Handlebars helper that lets us generate Markdown lists that can support multi-line
+ * strings. This is driven by inconsistent formatting of breaking changes, which may be multiple
+ * lines long and can terminate the list early unintentionally.
+ */
+Handlebars.registerHelper("tf-a-mdlist", function (indent, options) {
+ const spaces = new Array(indent + 1).join(" ");
+ const first = spaces + "- ";
+ const nth = spaces + " ";
+
+ return first + options.fn(this).replace(/\n(?!\s*\n)/gm, `\n${nth}`).trim() + "\n";
+});
+
+/*
+ * Register a Handlebars helper that concatenates multiple variables. We use this to generate the
+ * title for the section partials.
+ */
+Handlebars.registerHelper("tf-a-concat", function () {
+ let argv = Array.prototype.slice.call(arguments, 0);
+
+ argv.pop();
+
+ return argv.join("");
+});
+
+function writerOpts(config) {
+ /*
+ * Flatten the configuration's sections list. This helps us iterate over all of the sections
+ * when we don't care about the hierarchy.
+ */
+
+ const flattenSections = function (sections) {
+ return sections.flatMap(section => {
+ const subsections = flattenSections(section.sections || []);
+
+ return [section].concat(subsections);
+ })
+ };
+
+ const flattenedSections = flattenSections(config.sections);
+
+ /*
+ * Register a helper to return a restructured version of the note groups that includes notes
+ * categorized by their section.
+ */
+ Handlebars.registerHelper("tf-a-notes", function (noteGroups, options) {
+ const generateTemplateData = function (sections, notes) {
+ return (sections || []).flatMap(section => {
+ const templateData = {
+ title: section.title,
+ sections: generateTemplateData(section.sections, notes),
+ notes: notes.filter(note => section.scopes?.includes(note.commit.scope)),
+ };
+
+ /*
+ * Don't return a section if it contains no notes and no sub-sections.
+ */
+ if ((templateData.sections.length == 0) && (templateData.notes.length == 0)) {
+ return [];
+ }
+
+ return [templateData];
+ });
+ };
+
+ return noteGroups.map(noteGroup => {
+ return {
+ title: noteGroup.title,
+ sections: generateTemplateData(config.sections, noteGroup.notes),
+ notes: noteGroup.notes.filter(note =>
+ !flattenedSections.some(section => section.scopes?.includes(note.commit.scope))),
+ };
+ });
+ });
+
+ /*
+ * Register a helper to return a restructured version of the commit groups that includes commits
+ * categorized by their section.
+ */
+ Handlebars.registerHelper("tf-a-commits", function (commitGroups, options) {
+ const generateTemplateData = function (sections, commits) {
+ return (sections || []).flatMap(section => {
+ const templateData = {
+ title: section.title,
+ sections: generateTemplateData(section.sections, commits),
+ commits: commits.filter(commit => section.scopes?.includes(commit.scope)),
+ };
+
+ /*
+ * Don't return a section if it contains no notes and no sub-sections.
+ */
+ if ((templateData.sections.length == 0) && (templateData.commits.length == 0)) {
+ return [];
+ }
+
+ return [templateData];
+ });
+ };
+
+ return commitGroups.map(commitGroup => {
+ return {
+ title: commitGroup.title,
+ sections: generateTemplateData(config.sections, commitGroup.commits),
+ commits: commitGroup.commits.filter(commit =>
+ !flattenedSections.some(section => section.scopes?.includes(commit.scope))),
+ };
+ });
+ });
+
+ const writerOpts = ccWriterOpts(config)
+ .then(writerOpts => {
+ const ccWriterOptsTransform = writerOpts.transform;
+
+ /*
+ * These configuration properties can't be injected directly into the template because
+ * they themselves are templates. Instead, we register them as partials, which allows
+ * them to be evaluated as part of the templates they're used in.
+ */
+ Handlebars.registerPartial("commitUrl", config.commitUrlFormat);
+ Handlebars.registerPartial("compareUrl", config.compareUrlFormat);
+ Handlebars.registerPartial("issueUrl", config.issueUrlFormat);
+
+ /*
+ * Register the partials that allow us to recursively create changelog sections.
+ */
+
+ const notePartial = readFileSync(resolve(__dirname, "./templates/note.hbs"), "utf-8");
+ const noteSectionPartial = readFileSync(resolve(__dirname, "./templates/note-section.hbs"), "utf-8");
+ const commitSectionPartial = readFileSync(resolve(__dirname, "./templates/commit-section.hbs"), "utf-8");
+
+ Handlebars.registerPartial("tf-a-note", notePartial);
+ Handlebars.registerPartial("tf-a-note-section", noteSectionPartial);
+ Handlebars.registerPartial("tf-a-commit-section", commitSectionPartial);
+
+ /*
+ * Override the base templates so that we can generate a changelog that looks at least
+ * similar to the pre-Conventional Commits TF-A changelog.
+ */
+ writerOpts.mainTemplate = readFileSync(resolve(__dirname, "./templates/template.hbs"), "utf-8");
+ writerOpts.headerPartial = readFileSync(resolve(__dirname, "./templates/header.hbs"), "utf-8");
+ writerOpts.commitPartial = readFileSync(resolve(__dirname, "./templates/commit.hbs"), "utf-8");
+ writerOpts.footerPartial = readFileSync(resolve(__dirname, "./templates/footer.hbs"), "utf-8");
+
+ writerOpts.transform = function (commit, context) {
+ /*
+ * Fix up commit trailers, which for some reason are not correctly recognized and
+ * end up showing up in the breaking changes.
+ */
+
+ commit.notes.forEach(note => {
+ const trailers = execa.sync("git", ["interpret-trailers", "--parse"], {
+ input: note.text
+ }).stdout;
+
+ note.text = note.text.replace(trailers, "").trim();
+ });
+
+ return ccWriterOptsTransform(commit, context);
+ };
+
+ return writerOpts;
+ });
+
+ return writerOpts;
+}
+
+module.exports = function (parameter) {
+ const config = parameter || {};
+
+ return Q.all([
+ ccConventionalChangelog(config),
+ ccParserOpts(config),
+ ccRecommendedBumpOpts(config),
+ writerOpts(config)
+ ]).spread((
+ conventionalChangelog,
+ parserOpts,
+ recommendedBumpOpts,
+ writerOpts
+ ) => {
+ if (_.isFunction(parameter)) {
+ return parameter(null, {
+ gitRawCommitsOpts: { noMerges: null },
+ conventionalChangelog,
+ parserOpts,
+ recommendedBumpOpts,
+ writerOpts
+ });
+ } else {
+ return {
+ conventionalChangelog,
+ parserOpts,
+ recommendedBumpOpts,
+ writerOpts
+ };
+ }
+ });
+};
diff --git a/tools/conventional-changelog-tf-a/package.json b/tools/conventional-changelog-tf-a/package.json
new file mode 100644
index 0000000..3dd9877
--- /dev/null
+++ b/tools/conventional-changelog-tf-a/package.json
@@ -0,0 +1,13 @@
+{
+ "name": "conventional-changelog-tf-a",
+ "version": "2.8.0",
+ "license": "BSD-3-Clause",
+ "private": true,
+ "main": "index.js",
+ "dependencies": {
+ "conventional-changelog-conventionalcommits": "^4.6.1",
+ "execa": "^5.1.1",
+ "lodash": "^4.17.21",
+ "q": "^1.5.1"
+ }
+}
diff --git a/tools/conventional-changelog-tf-a/templates/commit-section.hbs b/tools/conventional-changelog-tf-a/templates/commit-section.hbs
new file mode 100644
index 0000000..86b3335
--- /dev/null
+++ b/tools/conventional-changelog-tf-a/templates/commit-section.hbs
@@ -0,0 +1,17 @@
+{{#if title ~}}
+{{ header }}
+
+{{#if commits.length ~}}
+ {{#each commits ~}}
+ {{#tf-a-mdlist 0}}{{> commit root=@root showScope=../topLevel }}{{/tf-a-mdlist ~}}
+ {{/each}}
+
+{{/if ~}}
+
+{{#if sections.length ~}}
+ {{#each sections ~}}
+ {{#tf-a-mdlist 0}}{{> tf-a-commit-section root=@root header=(tf-a-concat "**" title "**") }}{{/tf-a-mdlist}}
+ {{/each}}
+{{/if ~}}
+
+{{/if}}
diff --git a/tools/conventional-changelog-tf-a/templates/commit.hbs b/tools/conventional-changelog-tf-a/templates/commit.hbs
new file mode 100644
index 0000000..faf264a
--- /dev/null
+++ b/tools/conventional-changelog-tf-a/templates/commit.hbs
@@ -0,0 +1,15 @@
+{{#if scope }}
+ {{~#if showScope }}**{{ scope }}:** {{/if}}
+{{~/if}}
+
+{{~#if subject }}
+ {{~ subject }}
+{{~else}}
+ {{~ header }}
+{{~/if}}
+
+{{~#if hash }} {{#if @root.linkReferences ~}}
+ ([{{ shortHash }}]({{> commitUrl root=@root }}))
+{{~else}}
+ {{~ shortHash }}
+{{~/if}}{{~/if}}
diff --git a/tools/conventional-changelog-tf-a/templates/footer.hbs b/tools/conventional-changelog-tf-a/templates/footer.hbs
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/conventional-changelog-tf-a/templates/footer.hbs
diff --git a/tools/conventional-changelog-tf-a/templates/header.hbs b/tools/conventional-changelog-tf-a/templates/header.hbs
new file mode 100644
index 0000000..67cb297
--- /dev/null
+++ b/tools/conventional-changelog-tf-a/templates/header.hbs
@@ -0,0 +1,13 @@
+{{#if isPatch~}}
+ ###
+{{~else~}}
+ ##
+{{~/if}} {{#if @root.linkCompare~}}
+ [{{version}}]({{> compareUrl root=@root}})
+{{~else}}
+ {{~version}}
+{{~/if}}
+{{~#if title}} "{{title}}"
+{{~/if}}
+{{~#if date}} ({{date}})
+{{/if}}
diff --git a/tools/conventional-changelog-tf-a/templates/note-section.hbs b/tools/conventional-changelog-tf-a/templates/note-section.hbs
new file mode 100644
index 0000000..f501c96
--- /dev/null
+++ b/tools/conventional-changelog-tf-a/templates/note-section.hbs
@@ -0,0 +1,13 @@
+{{ header }}
+
+{{#if notes.length ~}}
+ {{#each notes ~}}
+ {{#tf-a-mdlist 0}}{{> tf-a-note root=@root showScope=../topLevel }}{{/tf-a-mdlist}}
+ {{/each ~}}
+{{/if ~}}
+
+{{#if sections.length ~}}
+ {{#each sections ~}}
+ {{#tf-a-mdlist 0}}{{> tf-a-note-section root=@root header=(tf-a-concat "**" title "**") }}{{/tf-a-mdlist}}
+ {{/each~}}
+{{/if}}
diff --git a/tools/conventional-changelog-tf-a/templates/note.hbs b/tools/conventional-changelog-tf-a/templates/note.hbs
new file mode 100644
index 0000000..c780ee8
--- /dev/null
+++ b/tools/conventional-changelog-tf-a/templates/note.hbs
@@ -0,0 +1,3 @@
+{{ text }}
+
+**See:** {{#with commit }}{{> commit root=@root showScope=../showScope }}{{/with}}
diff --git a/tools/conventional-changelog-tf-a/templates/template.hbs b/tools/conventional-changelog-tf-a/templates/template.hbs
new file mode 100644
index 0000000..95fb68c
--- /dev/null
+++ b/tools/conventional-changelog-tf-a/templates/template.hbs
@@ -0,0 +1,9 @@
+{{> header }}
+
+{{#each (tf-a-notes noteGroups) ~}}
+{{> tf-a-note-section root=@root header=(tf-a-concat "### âš  " title) topLevel=true }}
+{{/each ~}}
+
+{{#each (tf-a-commits commitGroups) ~}}
+{{> tf-a-commit-section root=@root header=(tf-a-concat "### " title) topLevel=true }}
+{{/each ~}}
diff --git a/tools/encrypt_fw/Makefile b/tools/encrypt_fw/Makefile
new file mode 100644
index 0000000..2939b14
--- /dev/null
+++ b/tools/encrypt_fw/Makefile
@@ -0,0 +1,89 @@
+#
+# Copyright (c) 2019-2022, Linaro Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+V ?= 0
+BUILD_INFO ?= 1
+DEBUG := 0
+ENCTOOL ?= encrypt_fw${BIN_EXT}
+BINARY := $(notdir ${ENCTOOL})
+OPENSSL_DIR := /usr
+
+
+MAKE_HELPERS_DIRECTORY := ../../make_helpers/
+include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
+include ${MAKE_HELPERS_DIRECTORY}build_env.mk
+include ${MAKE_HELPERS_DIRECTORY}defaults.mk
+
+OBJECTS := src/encrypt.o \
+ src/cmd_opt.o \
+ src/main.o
+
+HOSTCCFLAGS := -Wall -std=c99
+
+# Select OpenSSL version flag according to the OpenSSL build selected
+# from setting the OPENSSL_DIR path.
+$(eval $(call SELECT_OPENSSL_API_VERSION))
+
+ifeq (${DEBUG},1)
+ HOSTCCFLAGS += -g -O0 -DDEBUG -DLOG_LEVEL=40
+else
+ifeq (${BUILD_INFO},1)
+ HOSTCCFLAGS += -O2 -DLOG_LEVEL=20
+else
+ HOSTCCFLAGS += -O2 -DLOG_LEVEL=10
+endif
+endif
+ifeq (${V},0)
+ Q := @
+else
+ Q :=
+endif
+
+HOSTCCFLAGS += ${DEFINES}
+# USING_OPENSSL3 flag will be added to the HOSTCCFLAGS variable with the proper
+# computed value.
+HOSTCCFLAGS += -DUSING_OPENSSL3=$(USING_OPENSSL3)
+
+
+# Make soft links and include from local directory otherwise wrong headers
+# could get pulled in from firmware tree.
+INC_DIR := -I ./include -I ../../include/tools_share -I ${OPENSSL_DIR}/include
+
+# Include library directories where OpenSSL library files are located.
+# For a normal installation (i.e.: when ${OPENSSL_DIR} = /usr or
+# /usr/local), binaries are located under the ${OPENSSL_DIR}/lib/
+# directory. However, for a local build of OpenSSL, the built binaries are
+# located under the main project directory (i.e.: ${OPENSSL_DIR}, not
+# ${OPENSSL_DIR}/lib/).
+LIB_DIR := -L ${OPENSSL_DIR}/lib -L ${OPENSSL_DIR}
+LIB := -lssl -lcrypto
+
+HOSTCC ?= gcc
+
+.PHONY: all clean realclean --openssl
+
+all: ${BINARY}
+
+${BINARY}: --openssl ${OBJECTS} Makefile
+ @echo " HOSTLD $@"
+ @echo 'const char build_msg[] = "Built : "__TIME__", "__DATE__;' | \
+ ${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 $@
+
+--openssl:
+ifeq ($(DEBUG),1)
+ @echo "Selected OpenSSL version: ${OPENSSL_CURRENT_VER}"
+endif
+
+clean:
+ $(call SHELL_DELETE_ALL, src/build_msg.o ${OBJECTS})
+
+realclean: clean
+ $(call SHELL_DELETE,${BINARY})
diff --git a/tools/encrypt_fw/include/cmd_opt.h b/tools/encrypt_fw/include/cmd_opt.h
new file mode 100644
index 0000000..bd7d31f
--- /dev/null
+++ b/tools/encrypt_fw/include/cmd_opt.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CMD_OPT_H
+#define CMD_OPT_H
+
+#include <getopt.h>
+
+#define CMD_OPT_MAX_NUM 64
+
+/* Supported long command line option types */
+enum {
+ CMD_OPT_FW
+};
+
+/* 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 */
diff --git a/tools/encrypt_fw/include/debug.h b/tools/encrypt_fw/include/debug.h
new file mode 100644
index 0000000..ee8f1f5
--- /dev/null
+++ b/tools/encrypt_fw/include/debug.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <stdio.h>
+
+/* 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 */
diff --git a/tools/encrypt_fw/include/encrypt.h b/tools/encrypt_fw/include/encrypt.h
new file mode 100644
index 0000000..25d3011
--- /dev/null
+++ b/tools/encrypt_fw/include/encrypt.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2019, Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ENCRYPT_H
+#define ENCRYPT_H
+
+/* Supported key algorithms */
+enum {
+ KEY_ALG_GCM /* AES-GCM (default) */
+};
+
+int encrypt_file(unsigned short fw_enc_status, int enc_alg, char *key_string,
+ char *nonce_string, const char *ip_name, const char *op_name);
+
+#endif /* ENCRYPT_H */
diff --git a/tools/encrypt_fw/src/cmd_opt.c b/tools/encrypt_fw/src/cmd_opt.c
new file mode 100644
index 0000000..64180d1
--- /dev/null
+++ b/tools/encrypt_fw/src/cmd_opt.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <cmd_opt.h>
+#include <getopt.h>
+#include <stddef.h>
+#include <stdlib.h>
+#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];
+}
diff --git a/tools/encrypt_fw/src/encrypt.c b/tools/encrypt_fw/src/encrypt.c
new file mode 100644
index 0000000..18a514c
--- /dev/null
+++ b/tools/encrypt_fw/src/encrypt.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2019, Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <firmware_encrypted.h>
+#include <openssl/evp.h>
+#include <stdio.h>
+#include <string.h>
+#include "debug.h"
+#include "encrypt.h"
+
+#define BUFFER_SIZE 256
+#define IV_SIZE 12
+#define IV_STRING_SIZE 24
+#define TAG_SIZE 16
+#define KEY_SIZE 32
+#define KEY_STRING_SIZE 64
+
+static int gcm_encrypt(unsigned short fw_enc_status, char *key_string,
+ char *nonce_string, const char *ip_name,
+ const char *op_name)
+{
+ FILE *ip_file;
+ FILE *op_file;
+ EVP_CIPHER_CTX *ctx;
+ unsigned char data[BUFFER_SIZE], enc_data[BUFFER_SIZE];
+ unsigned char key[KEY_SIZE], iv[IV_SIZE], tag[TAG_SIZE];
+ int bytes, enc_len = 0, i, j, ret = 0;
+ struct fw_enc_hdr header;
+
+ memset(&header, 0, sizeof(struct fw_enc_hdr));
+
+ if (strlen(key_string) != KEY_STRING_SIZE) {
+ ERROR("Unsupported key size: %lu\n", strlen(key_string));
+ return -1;
+ }
+
+ for (i = 0, j = 0; i < KEY_SIZE; i++, j += 2) {
+ if (sscanf(&key_string[j], "%02hhx", &key[i]) != 1) {
+ ERROR("Incorrect key format\n");
+ return -1;
+ }
+ }
+
+ if (strlen(nonce_string) != IV_STRING_SIZE) {
+ ERROR("Unsupported IV size: %lu\n", strlen(nonce_string));
+ return -1;
+ }
+
+ for (i = 0, j = 0; i < IV_SIZE; i++, j += 2) {
+ if (sscanf(&nonce_string[j], "%02hhx", &iv[i]) != 1) {
+ ERROR("Incorrect IV format\n");
+ return -1;
+ }
+ }
+
+ ip_file = fopen(ip_name, "rb");
+ if (ip_file == NULL) {
+ ERROR("Cannot read %s\n", ip_name);
+ return -1;
+ }
+
+ op_file = fopen(op_name, "wb");
+ if (op_file == NULL) {
+ ERROR("Cannot write %s\n", op_name);
+ fclose(ip_file);
+ return -1;
+ }
+
+ ret = fseek(op_file, sizeof(struct fw_enc_hdr), SEEK_SET);
+ if (ret) {
+ ERROR("fseek failed\n");
+ goto out_file;
+ }
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (ctx == NULL) {
+ ERROR("EVP_CIPHER_CTX_new failed\n");
+ ret = -1;
+ goto out_file;
+ }
+
+ ret = EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
+ if (ret != 1) {
+ ERROR("EVP_EncryptInit_ex failed\n");
+ ret = -1;
+ goto out;
+ }
+
+ ret = EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv);
+ if (ret != 1) {
+ ERROR("EVP_EncryptInit_ex failed\n");
+ goto out;
+ }
+
+ while ((bytes = fread(data, 1, BUFFER_SIZE, ip_file)) != 0) {
+ ret = EVP_EncryptUpdate(ctx, enc_data, &enc_len, data, bytes);
+ if (ret != 1) {
+ ERROR("EVP_EncryptUpdate failed\n");
+ ret = -1;
+ goto out;
+ }
+
+ fwrite(enc_data, 1, enc_len, op_file);
+ }
+
+ ret = EVP_EncryptFinal_ex(ctx, enc_data, &enc_len);
+ if (ret != 1) {
+ ERROR("EVP_EncryptFinal_ex failed\n");
+ ret = -1;
+ goto out;
+ }
+
+ ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, TAG_SIZE, tag);
+ if (ret != 1) {
+ ERROR("EVP_CIPHER_CTX_ctrl failed\n");
+ ret = -1;
+ goto out;
+ }
+
+ header.magic = ENC_HEADER_MAGIC;
+ header.flags |= fw_enc_status & FW_ENC_STATUS_FLAG_MASK;
+ header.dec_algo = KEY_ALG_GCM;
+ header.iv_len = IV_SIZE;
+ header.tag_len = TAG_SIZE;
+ memcpy(header.iv, iv, IV_SIZE);
+ memcpy(header.tag, tag, TAG_SIZE);
+
+ ret = fseek(op_file, 0, SEEK_SET);
+ if (ret) {
+ ERROR("fseek failed\n");
+ goto out;
+ }
+
+ fwrite(&header, 1, sizeof(struct fw_enc_hdr), op_file);
+
+out:
+ EVP_CIPHER_CTX_free(ctx);
+
+out_file:
+ fclose(ip_file);
+ fclose(op_file);
+
+ /*
+ * EVP_* APIs returns 1 as success but enctool considers
+ * 0 as success.
+ */
+ if (ret == 1)
+ ret = 0;
+
+ return ret;
+}
+
+int encrypt_file(unsigned short fw_enc_status, int enc_alg, char *key_string,
+ char *nonce_string, const char *ip_name, const char *op_name)
+{
+ switch (enc_alg) {
+ case KEY_ALG_GCM:
+ return gcm_encrypt(fw_enc_status, key_string, nonce_string,
+ ip_name, op_name);
+ default:
+ return -1;
+ }
+}
diff --git a/tools/encrypt_fw/src/main.c b/tools/encrypt_fw/src/main.c
new file mode 100644
index 0000000..39b7af7
--- /dev/null
+++ b/tools/encrypt_fw/src/main.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2019, Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <openssl/conf.h>
+
+#include "cmd_opt.h"
+#include "debug.h"
+#include "encrypt.h"
+#include "firmware_encrypted.h"
+
+#define NUM_ELEM(x) ((sizeof(x)) / (sizeof(x[0])))
+#define HELP_OPT_MAX_LEN 128
+
+/* Global options */
+
+/* Info messages created in the Makefile */
+extern const char build_msg[];
+
+static char *key_algs_str[] = {
+ [KEY_ALG_GCM] = "gcm",
+};
+
+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 firmware encryption tool loads the binary image and\n"
+ "outputs encrypted binary image using an encryption key\n"
+ "provided as an input hex string.\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) ? "<arg>" : "");
+ 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 (strcmp(key_alg_str, key_algs_str[i]) == 0) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static void parse_fw_enc_status_flag(const char *arg,
+ unsigned short *fw_enc_status)
+{
+ unsigned long flag;
+ char *endptr;
+
+ flag = strtoul(arg, &endptr, 16);
+ if (*endptr != '\0' || flag > FW_ENC_WITH_BSSK) {
+ ERROR("Invalid fw_enc_status flag '%s'\n", arg);
+ exit(1);
+ }
+
+ *fw_enc_status = flag & FW_ENC_STATUS_FLAG_MASK;
+}
+
+/* Common command line options */
+static const cmd_opt_t common_cmd_opt[] = {
+ {
+ { "help", no_argument, NULL, 'h' },
+ "Print this message and exit"
+ },
+ {
+ { "fw-enc-status", required_argument, NULL, 'f' },
+ "Firmware encryption status flag (with SSK=0 or BSSK=1)."
+ },
+ {
+ { "key-alg", required_argument, NULL, 'a' },
+ "Encryption key algorithm: 'gcm' (default)"
+ },
+ {
+ { "key", required_argument, NULL, 'k' },
+ "Encryption key (for supported algorithm)."
+ },
+ {
+ { "nonce", required_argument, NULL, 'n' },
+ "Nonce or Initialization Vector (for supported algorithm)."
+ },
+ {
+ { "in", required_argument, NULL, 'i' },
+ "Input filename to be encrypted."
+ },
+ {
+ { "out", required_argument, NULL, 'o' },
+ "Encrypted output filename."
+ },
+};
+
+int main(int argc, char *argv[])
+{
+ int i, key_alg, ret;
+ int c, opt_idx = 0;
+ const struct option *cmd_opt;
+ char *key = NULL;
+ char *nonce = NULL;
+ char *in_fn = NULL;
+ char *out_fn = NULL;
+ unsigned short fw_enc_status = 0;
+
+ NOTICE("Firmware Encryption Tool: %s\n", build_msg);
+
+ /* Set default options */
+ key_alg = KEY_ALG_GCM;
+
+ /* Add common command line options */
+ for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) {
+ cmd_opt_add(&common_cmd_opt[i]);
+ }
+
+ /* 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:f:hi:k:n:o:", 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 'f':
+ parse_fw_enc_status_flag(optarg, &fw_enc_status);
+ break;
+ case 'k':
+ key = optarg;
+ break;
+ case 'i':
+ in_fn = optarg;
+ break;
+ case 'o':
+ out_fn = optarg;
+ break;
+ case 'n':
+ nonce = optarg;
+ break;
+ case 'h':
+ print_help(argv[0], cmd_opt);
+ exit(0);
+ case '?':
+ default:
+ print_help(argv[0], cmd_opt);
+ exit(1);
+ }
+ }
+
+ if (!key) {
+ ERROR("Key must not be NULL\n");
+ exit(1);
+ }
+
+ if (!nonce) {
+ ERROR("Nonce must not be NULL\n");
+ exit(1);
+ }
+
+ if (!in_fn) {
+ ERROR("Input filename must not be NULL\n");
+ exit(1);
+ }
+
+ if (!out_fn) {
+ ERROR("Output filename must not be NULL\n");
+ exit(1);
+ }
+
+ ret = encrypt_file(fw_enc_status, key_alg, key, nonce, in_fn, out_fn);
+
+ CRYPTO_cleanup_all_ex_data();
+
+ return ret;
+}
diff --git a/tools/fiptool/Makefile b/tools/fiptool/Makefile
new file mode 100644
index 0000000..d7e0fe5
--- /dev/null
+++ b/tools/fiptool/Makefile
@@ -0,0 +1,86 @@
+#
+# Copyright (c) 2014-2022, 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
+include ${MAKE_HELPERS_DIRECTORY}defaults.mk
+
+FIPTOOL ?= fiptool${BIN_EXT}
+PROJECT := $(notdir ${FIPTOOL})
+OBJECTS := fiptool.o tbbr_config.o
+V ?= 0
+OPENSSL_DIR := /usr
+
+
+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
+
+# Select OpenSSL version flag according to the OpenSSL build selected
+# from setting the OPENSSL_DIR path.
+$(eval $(call SELECT_OPENSSL_API_VERSION))
+
+HOSTCCFLAGS += ${DEFINES}
+# USING_OPENSSL3 flag will be added to the HOSTCCFLAGS variable with the proper
+# computed value.
+HOSTCCFLAGS += -DUSING_OPENSSL3=$(USING_OPENSSL3)
+
+# Include library directories where OpenSSL library files are located.
+# For a normal installation (i.e.: when ${OPENSSL_DIR} = /usr or
+# /usr/local), binaries are located under the ${OPENSSL_DIR}/lib/
+# directory. However, for a local build of OpenSSL, the built binaries are
+# located under the main project directory (i.e.: ${OPENSSL_DIR}, not
+# ${OPENSSL_DIR}/lib/).
+LDLIBS := -L${OPENSSL_DIR}/lib -L${OPENSSL_DIR} -lcrypto
+
+ifeq (${V},0)
+ Q := @
+else
+ Q :=
+endif
+
+INCLUDE_PATHS := -I../../include/tools_share -I${OPENSSL_DIR}/include
+
+HOSTCC ?= gcc
+
+ifneq (${PLAT},)
+TF_PLATFORM_ROOT := ../../plat/
+include ${MAKE_HELPERS_DIRECTORY}plat_helpers.mk
+PLAT_FIPTOOL_HELPER_MK := ${PLAT_DIR}/plat_fiptool.mk
+endif
+
+ifneq (,$(wildcard ${PLAT_FIPTOOL_HELPER_MK}))
+include ${PLAT_FIPTOOL_HELPER_MK}
+endif
+
+.PHONY: all clean distclean --openssl
+
+all: ${PROJECT}
+
+${PROJECT}: --openssl ${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 $@
+
+--openssl:
+ifeq ($(DEBUG),1)
+ @echo "Selected OpenSSL version: ${OPENSSL_CURRENT_VER}"
+endif
+
+
+clean:
+ $(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS})
diff --git a/tools/fiptool/Makefile.msvc b/tools/fiptool/Makefile.msvc
new file mode 100644
index 0000000..9081bc6
--- /dev/null
+++ b/tools/fiptool/Makefile.msvc
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+CC = cl.exe
+LD = link.exe
+
+# FIPTOOLPATH and FIPTOOL are passed from the main makefile.
+
+OBJECTS = $(FIPTOOLPATH)\fiptool.obj \
+ $(FIPTOOLPATH)\tbbr_config.obj \
+ $(FIPTOOLPATH)\win_posix.obj
+
+INC = -I$(FIPTOOLPATH) -Iinclude\tools_share
+
+CFLAGS = $(CFLAGS) /nologo /Za /Zi /c /O2 /MT
+
+all: $(FIPTOOL)
+
+$(FIPTOOL): $(OBJECTS)
+ $(LD) /nologo /INCREMENTAL:NO /debug /nodefaultlib:libc.lib /out:$@ $(LIBS) $**
+
+.PHONY: clean realclean
+
+clean:
+ -@del /f /q $(OBJECTS) > nul
+ -@del /f /q $(FIPTOOLPATH)\*.pdb > nul
+
+realclean:
+ -@del /f /q $(OBJECTS) > nul
+ -@del /f /q $(FIPTOOLPATH)\*.pdb > nul
+ -@del /f /q $(FIPTOOL) > nul
+
+.c.obj:
+ $(CC) -c $(CFLAGS) $(INC) $< -Fo$@
diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c
new file mode 100644
index 0000000..5c240b5
--- /dev/null
+++ b/tools/fiptool/fiptool.c
@@ -0,0 +1,1266 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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(int);
+static int create_cmd(int argc, char *argv[]);
+static void create_usage(int);
+static int update_cmd(int argc, char *argv[]);
+static void update_usage(int);
+static int unpack_cmd(int argc, char *argv[]);
+static void unpack_usage(int);
+static int remove_cmd(int argc, char *argv[]);
+static void remove_usage(int);
+static int version_cmd(int argc, char *argv[]);
+static void version_usage(int);
+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);
+ }
+#ifdef PLAT_DEF_FIP_UUID
+ for (toc_entry = plat_def_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);
+ }
+#endif
+}
+
+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(EXIT_FAILURE);
+ 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(int exit_status)
+{
+ printf("fiptool info FIP_FILENAME\n");
+ exit(exit_status);
+}
+
+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 || (image->toc_e.size == 0ULL))
+ 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(EXIT_FAILURE);
+
+ 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(EXIT_FAILURE);
+
+ 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(EXIT_FAILURE);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ free(opts);
+
+ if (argc == 0)
+ create_usage(EXIT_SUCCESS);
+
+ update_fip();
+
+ pack_images(argv[0], toc_flags, align);
+ return 0;
+}
+
+static void create_usage(int exit_status)
+{
+ toc_entry_t *toc_entry = toc_entries;
+
+ printf("fiptool create [opts] FIP_FILENAME\n");
+ printf("\n");
+ printf("Options:\n");
+ printf(" --align <value>\t\tEach image is aligned to <value> (default: 1).\n");
+ printf(" --blob uuid=...,file=...\tAdd an image with the given UUID pointed to by file.\n");
+ printf(" --plat-toc-flags <value>\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);
+#ifdef PLAT_DEF_FIP_UUID
+ toc_entry = plat_def_toc_entries;
+ for (; toc_entry->cmdline_name != NULL; toc_entry++)
+ printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
+ toc_entry->name);
+#endif
+ exit(exit_status);
+}
+
+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(EXIT_FAILURE);
+
+ 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(EXIT_FAILURE);
+
+ 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(EXIT_FAILURE);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ free(opts);
+
+ if (argc == 0)
+ update_usage(EXIT_SUCCESS);
+
+ 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(int exit_status)
+{
+ toc_entry_t *toc_entry = toc_entries;
+
+ printf("fiptool update [opts] FIP_FILENAME\n");
+ printf("\n");
+ printf("Options:\n");
+ printf(" --align <value>\t\tEach image is aligned to <value> (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 <value>\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);
+#ifdef PLAT_DEF_FIP_UUID
+ toc_entry = plat_def_toc_entries;
+ for (; toc_entry->cmdline_name != NULL; toc_entry++)
+ printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
+ toc_entry->name);
+#endif
+ exit(exit_status);
+}
+
+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(EXIT_FAILURE);
+
+ 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(EXIT_FAILURE);
+
+ 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(EXIT_FAILURE);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ free(opts);
+
+ if (argc == 0)
+ unpack_usage(EXIT_SUCCESS);
+
+ 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(int exit_status)
+{
+ 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);
+#ifdef PLAT_DEF_FIP_UUID
+ toc_entry = plat_def_toc_entries;
+ for (; toc_entry->cmdline_name != NULL; toc_entry++)
+ printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
+ toc_entry->name);
+#endif
+ printf("\n");
+ printf("If no options are provided, all images will be unpacked.\n");
+ exit(exit_status);
+}
+
+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(EXIT_FAILURE);
+
+ 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(EXIT_FAILURE);
+
+ 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(EXIT_FAILURE);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ free(opts);
+
+ if (argc == 0)
+ remove_usage(EXIT_SUCCESS);
+
+ 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(int exit_status)
+{
+ toc_entry_t *toc_entry = toc_entries;
+
+ printf("fiptool remove [opts] FIP_FILENAME\n");
+ printf("\n");
+ printf("Options:\n");
+ printf(" --align <value>\tEach image is aligned to <value> (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);
+#ifdef PLAT_DEF_FIP_UUID
+ toc_entry = plat_def_toc_entries;
+ for (; toc_entry->cmdline_name != NULL; toc_entry++)
+ printf(" --%-16s\t%s\n", toc_entry->cmdline_name,
+ toc_entry->name);
+#endif
+ exit(exit_status);
+}
+
+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(int exit_status)
+{
+ printf("fiptool version\n");
+ exit(exit_status);
+}
+
+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(EXIT_SUCCESS);
+ }
+ if (i == NELEM(cmds))
+ printf("No help for subcommand '%s'\n", argv[0]);
+ return 0;
+}
+
+static void usage(void)
+{
+ printf("usage: fiptool [--verbose] <command> [<args>]\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(EXIT_SUCCESS);
+}
+
+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;
+}
diff --git a/tools/fiptool/fiptool.h b/tools/fiptool/fiptool.h
new file mode 100644
index 0000000..88c4a7e
--- /dev/null
+++ b/tools/fiptool/fiptool.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FIPTOOL_H
+#define FIPTOOL_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <firmware_image_package.h>
+#include <uuid.h>
+
+#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)(int);
+} cmd_t;
+
+#endif /* FIPTOOL_H */
diff --git a/tools/fiptool/fiptool_platform.h b/tools/fiptool/fiptool_platform.h
new file mode 100644
index 0000000..9bfa298
--- /dev/null
+++ b/tools/fiptool/fiptool_platform.h
@@ -0,0 +1,31 @@
+/*
+ * 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 <getopt.h>
+# include <openssl/sha.h>
+# include <unistd.h>
+
+# define BLD_PLAT_STAT stat
+
+#else
+
+/* Visual Studio. */
+# include "win_posix.h"
+
+#endif
+
+#endif /* FIPTOOL_PLATFORM_H */
diff --git a/tools/fiptool/tbbr_config.c b/tools/fiptool/tbbr_config.c
new file mode 100644
index 0000000..cdbf389
--- /dev/null
+++ b/tools/fiptool/tbbr_config.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <firmware_image_package.h>
+
+#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"
+ },
+ {
+ .name = "Realm Monitor Management Firmware",
+ .uuid = UUID_REALM_MONITOR_MGMT_FIRMWARE,
+ .cmdline_name = "rmm-fw"
+ },
+ /* Dynamic Configs */
+ {
+ .name = "FW_CONFIG",
+ .uuid = UUID_FW_CONFIG,
+ .cmdline_name = "fw-config"
+ },
+ {
+ .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 = "SiP owned Secure Partition content certificate",
+ .uuid = UUID_SIP_SECURE_PARTITION_CONTENT_CERT,
+ .cmdline_name = "sip-sp-cert"
+ },
+ {
+ .name = "Platform owned Secure Partition content certificate",
+ .uuid = UUID_PLAT_SECURE_PARTITION_CONTENT_CERT,
+ .cmdline_name = "plat-sp-cert"
+ },
+ {
+ .name = "CCA Content Certificate",
+ .uuid = UUID_CCA_CONTENT_CERT,
+ .cmdline_name = "cca-cert"
+ },
+ {
+ .name = "Core Secure World Key Certificate",
+ .uuid = UUID_CORE_SWD_KEY_CERT,
+ .cmdline_name = "core-swd-cert"
+ },
+ {
+ .name = "Platform Key Certificate",
+ .uuid = UUID_PLAT_KEY_CERT,
+ .cmdline_name = "plat-key-cert"
+ },
+ {
+ .name = NULL,
+ .uuid = { {0} },
+ .cmdline_name = NULL,
+ }
+};
diff --git a/tools/fiptool/tbbr_config.h b/tools/fiptool/tbbr_config.h
new file mode 100644
index 0000000..b926ff0
--- /dev/null
+++ b/tools/fiptool/tbbr_config.h
@@ -0,0 +1,28 @@
+/*
+ * 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 <stdint.h>
+
+#include <uuid.h>
+
+#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[];
+
+#ifdef PLAT_DEF_FIP_UUID
+extern toc_entry_t plat_def_toc_entries[];
+#endif
+
+#endif /* TBBR_CONFIG_H */
diff --git a/tools/fiptool/win_posix.c b/tools/fiptool/win_posix.c
new file mode 100644
index 0000000..33b44d4
--- /dev/null
+++ b/tools/fiptool/win_posix.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2017 - 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#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. This function does not check that the
+ * abbreviations are unique and should be handled by the caller.
+ * 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;
+ bool match_found = false;
+
+ /*
+ * Long option names may be abbreviated if the abbreviation
+ * is unique or an exact match for some defined option.
+ * To handle this:
+ * - First search for an exact match.
+ * - If exact match was not found search for a abbreviated match.
+ * By doing this an incorrect option selection can be avoided.
+ */
+
+ /* 1. Search for an exact match. */
+ while (longopts[loptn].name != NULL) {
+ if (strcmp(optname, longopts[loptn].name) == 0) {
+ match_found = true;
+ break;
+ }
+ ++loptn;
+ }
+
+ /* 2. If exact match was not found search for a abbreviated match. */
+ if (!match_found) {
+ loptn = 0;
+ while (longopts[loptn].name != NULL) {
+ if (optmatch(optname, longopts[loptn].name) == 0) {
+ match_found = true;
+ break;
+ }
+ ++loptn;
+ }
+ }
+
+ if (match_found) {
+ /* 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;
+ }
+
+ /*
+ * 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;
+}
diff --git a/tools/fiptool/win_posix.h b/tools/fiptool/win_posix.h
new file mode 100644
index 0000000..6f0d8e6
--- /dev/null
+++ b/tools/fiptool/win_posix.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2017-2020, 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 <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <direct.h>
+#include <io.h>
+
+#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 */
diff --git a/tools/marvell/doimage/Makefile b/tools/marvell/doimage/Makefile
new file mode 100644
index 0000000..9f0d89d
--- /dev/null
+++ b/tools/marvell/doimage/Makefile
@@ -0,0 +1,48 @@
+#
+# 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}
diff --git a/tools/marvell/doimage/doimage.c b/tools/marvell/doimage/doimage.c
new file mode 100644
index 0000000..e08b820
--- /dev/null
+++ b/tools/marvell/doimage/doimage.c
@@ -0,0 +1,1764 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+#include <libconfig.h> /* 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 <mbedtls/error.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/md.h>
+#include <mbedtls/pk.h>
+#include <mbedtls/sha256.h>
+#include <mbedtls/x509.h>
+#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.3"
+
+/* 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] <input_file> [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_ret(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;
+ unsigned char *pkey = (unsigned char *)pub_key;
+
+ /* 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_subpubkey(&pkey, pub_key + klen, &pk_ctx);
+ 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_ret(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_ret(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
+ */
+ bzero(out_der_key, MAX_RSA_DER_BYTE_LEN);
+ 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_ret(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 written;
+
+ written = fwrite(buf, image_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, file_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
+ * Always align the image to 16 byte boundary
+ */
+ file_size = get_file_size(in_file);
+ image_size = (file_size + AES_BLOCK_SZ - 1) & ~(AES_BLOCK_SZ - 1);
+ image_buf = calloc(image_size, 1);
+ if (image_buf == NULL) {
+ fprintf(stderr, "Error: failed allocating input buffer\n");
+ return 1;
+ }
+
+ read = fread(image_buf, file_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);
+}
diff --git a/tools/marvell/doimage/doimage.mk b/tools/marvell/doimage/doimage.mk
new file mode 100644
index 0000000..2b751d4
--- /dev/null
+++ b/tools/marvell/doimage/doimage.mk
@@ -0,0 +1,15 @@
+#
+# 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)
diff --git a/tools/marvell/doimage/secure/aes_key.txt b/tools/marvell/doimage/secure/aes_key.txt
new file mode 100644
index 0000000..3e8a888
--- /dev/null
+++ b/tools/marvell/doimage/secure/aes_key.txt
@@ -0,0 +1 @@
+ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890
diff --git a/tools/marvell/doimage/secure/csk_priv_pem0.key b/tools/marvell/doimage/secure/csk_priv_pem0.key
new file mode 100644
index 0000000..0840c2a
--- /dev/null
+++ b/tools/marvell/doimage/secure/csk_priv_pem0.key
@@ -0,0 +1,27 @@
+-----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-----
diff --git a/tools/marvell/doimage/secure/csk_priv_pem1.key b/tools/marvell/doimage/secure/csk_priv_pem1.key
new file mode 100644
index 0000000..91d1aeb
--- /dev/null
+++ b/tools/marvell/doimage/secure/csk_priv_pem1.key
@@ -0,0 +1,27 @@
+-----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-----
diff --git a/tools/marvell/doimage/secure/csk_priv_pem2.key b/tools/marvell/doimage/secure/csk_priv_pem2.key
new file mode 100644
index 0000000..ea47ac5
--- /dev/null
+++ b/tools/marvell/doimage/secure/csk_priv_pem2.key
@@ -0,0 +1,27 @@
+-----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-----
diff --git a/tools/marvell/doimage/secure/csk_priv_pem3.key b/tools/marvell/doimage/secure/csk_priv_pem3.key
new file mode 100644
index 0000000..e40a864
--- /dev/null
+++ b/tools/marvell/doimage/secure/csk_priv_pem3.key
@@ -0,0 +1,27 @@
+-----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-----
diff --git a/tools/marvell/doimage/secure/kak_priv_pem.key b/tools/marvell/doimage/secure/kak_priv_pem.key
new file mode 100644
index 0000000..dfceaba
--- /dev/null
+++ b/tools/marvell/doimage/secure/kak_priv_pem.key
@@ -0,0 +1,27 @@
+-----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-----
diff --git a/tools/marvell/doimage/secure/sec_img_7K.cfg b/tools/marvell/doimage/secure/sec_img_7K.cfg
new file mode 100644
index 0000000..459f731
--- /dev/null
+++ b/tools/marvell/doimage/secure/sec_img_7K.cfg
@@ -0,0 +1,29 @@
+# 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];
diff --git a/tools/marvell/doimage/secure/sec_img_8K.cfg b/tools/marvell/doimage/secure/sec_img_8K.cfg
new file mode 100644
index 0000000..a849dff
--- /dev/null
+++ b/tools/marvell/doimage/secure/sec_img_8K.cfg
@@ -0,0 +1,29 @@
+# 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];
diff --git a/tools/memory/print_memory_map.py b/tools/memory/print_memory_map.py
new file mode 100755
index 0000000..ef53f7e
--- /dev/null
+++ b/tools/memory/print_memory_map.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2019-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+import re
+import os
+import sys
+import operator
+
+# List of folder/map to parse
+bl_images = ['bl1', 'bl2', 'bl31']
+
+# List of symbols to search for
+blx_symbols = ['__BL1_RAM_START__', '__BL1_RAM_END__',
+ '__BL2_END__',
+ '__BL31_END__',
+ '__RO_START__', '__RO_END_UNALIGNED__', '__RO_END__',
+ '__TEXT_START__', '__TEXT_END__',
+ '__TEXT_RESIDENT_START__', '__TEXT_RESIDENT_END__',
+ '__RODATA_START__', '__RODATA_END__',
+ '__DATA_START__', '__DATA_END__',
+ '__STACKS_START__', '__STACKS_END__',
+ '__BSS_START__', '__BSS_END__',
+ '__COHERENT_RAM_START__', '__COHERENT_RAM_END__',
+ '__CPU_OPS_START__', '__CPU_OPS_END__',
+ '__FCONF_POPULATOR_START__', '__FCONF_POPULATOR_END__',
+ '__GOT_START__', '__GOT_END__',
+ '__PARSER_LIB_DESCS_START__', '__PARSER_LIB_DESCS_END__',
+ '__PMF_TIMESTAMP_START__', '__PMF_TIMESTAMP_END__',
+ '__PMF_SVC_DESCS_START__', '__PMF_SVC_DESCS_END__',
+ '__RELA_START__', '__RELA_END__',
+ '__RT_SVC_DESCS_START__', '__RT_SVC_DESCS_END__',
+ '__BASE_XLAT_TABLE_START__', '__BASE_XLAT_TABLE_END__',
+ '__XLAT_TABLE_START__', '__XLAT_TABLE_END__',
+ ]
+
+# Regex to extract address from map file
+address_pattern = re.compile(r"\b0x\w*")
+
+# List of found element: [address, symbol, file]
+address_list = []
+
+# Get the directory from command line or use a default one
+inverted_print = True
+if len(sys.argv) >= 2:
+ build_dir = sys.argv[1]
+ if len(sys.argv) >= 3:
+ inverted_print = sys.argv[2] == '0'
+else:
+ build_dir = 'build/fvp/debug'
+
+max_len = max(len(word) for word in blx_symbols) + 2
+if (max_len % 2) != 0:
+ max_len += 1
+
+# Extract all the required symbols from the map files
+for image in bl_images:
+ file_path = os.path.join(build_dir, image, '{}.map'.format(image))
+ if os.path.isfile(file_path):
+ with open (file_path, 'rt') as mapfile:
+ for line in mapfile:
+ for symbol in blx_symbols:
+ skip_symbol = 0
+ # Regex to find symbol definition
+ line_pattern = re.compile(r"\b0x\w*\s*" + symbol + "\s= .")
+ match = line_pattern.search(line)
+ if match:
+ # Extract address from line
+ match = address_pattern.search(line)
+ if match:
+ if '_END__' in symbol:
+ sym_start = symbol.replace('_END__', '_START__')
+ if [match.group(0), sym_start, image] in address_list:
+ address_list.remove([match.group(0), sym_start, image])
+ skip_symbol = 1
+ if skip_symbol == 0:
+ address_list.append([match.group(0), symbol, image])
+
+# Sort by address
+address_list.sort(key=operator.itemgetter(0))
+
+# Invert list for lower address at bottom
+if inverted_print:
+ address_list = reversed(address_list)
+
+# Generate memory view
+print(('{:-^%d}' % (max_len * 3 + 20 + 7)).format('Memory Map from: ' + build_dir))
+for address in address_list:
+ if "bl1" in address[2]:
+ print(address[0], ('+{:-^%d}+ |{:^%d}| |{:^%d}|' % (max_len, max_len, max_len)).format(address[1], '', ''))
+ elif "bl2" in address[2]:
+ print(address[0], ('|{:^%d}| +{:-^%d}+ |{:^%d}|' % (max_len, max_len, max_len)).format('', address[1], ''))
+ elif "bl31" in address[2]:
+ print(address[0], ('|{:^%d}| |{:^%d}| +{:-^%d}+' % (max_len, max_len, max_len)).format('', '', address[1]))
+ else:
+ print(address[0], ('|{:^%d}| |{:^%d}| +{:-^%d}+' % (max_len, max_len, max_len)).format('', '', address[1]))
+
+print(('{:^20}{:_^%d} {:_^%d} {:_^%d}' % (max_len, max_len, max_len)).format('', '', '', ''))
+print(('{:^20}{:^%d} {:^%d} {:^%d}' % (max_len, max_len, max_len)).format('address', 'bl1', 'bl2', 'bl31'))
diff --git a/tools/nxp/cert_create_helper/cert_create_tbbr.mk b/tools/nxp/cert_create_helper/cert_create_tbbr.mk
new file mode 100644
index 0000000..e3b2e91
--- /dev/null
+++ b/tools/nxp/cert_create_helper/cert_create_tbbr.mk
@@ -0,0 +1,31 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Compile time defines used by NXP platforms
+
+PLAT_DEF_OID := yes
+
+ifeq (${PLAT_DEF_OID},yes)
+
+$(eval $(call add_define, PLAT_DEF_OID))
+$(eval $(call add_define, PDEF_KEYS))
+$(eval $(call add_define, PDEF_CERTS))
+$(eval $(call add_define, PDEF_EXTS))
+
+
+INC_DIR += -I../../plat/nxp/common/fip_handler/common/
+
+PDEF_CERT_TOOL_PATH := ../nxp/cert_create_helper
+PLAT_INCLUDE += -I${PDEF_CERT_TOOL_PATH}/include
+
+PLAT_OBJECTS += ${PDEF_CERT_TOOL_PATH}/src/pdef_tbb_cert.o \
+ ${PDEF_CERT_TOOL_PATH}/src/pdef_tbb_ext.o \
+ ${PDEF_CERT_TOOL_PATH}/src/pdef_tbb_key.o
+
+$(shell rm ${PLAT_OBJECTS})
+
+OBJECTS += ${PLAT_OBJECTS}
+endif
diff --git a/tools/nxp/cert_create_helper/include/pdef_tbb_cert.h b/tools/nxp/cert_create_helper/include/pdef_tbb_cert.h
new file mode 100644
index 0000000..f185619
--- /dev/null
+++ b/tools/nxp/cert_create_helper/include/pdef_tbb_cert.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PDEF_TBB_CERT_H
+#define PDEF_TBB_CERT_H
+
+#include <tbbr/tbb_cert.h>
+
+/*
+ * Enumerate the certificates that are used to establish the chain of trust
+ */
+enum {
+ DDR_FW_KEY_CERT = FWU_CERT + 1,
+ DDR_UDIMM_FW_CONTENT_CERT,
+ DDR_RDIMM_FW_CONTENT_CERT
+};
+
+#endif /* PDEF_TBB_CERT_H */
diff --git a/tools/nxp/cert_create_helper/include/pdef_tbb_ext.h b/tools/nxp/cert_create_helper/include/pdef_tbb_ext.h
new file mode 100644
index 0000000..5fb349c
--- /dev/null
+++ b/tools/nxp/cert_create_helper/include/pdef_tbb_ext.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PDEF_TBB_EXT_H
+#define PDEF_TBB_EXT_H
+
+#include <tbbr/tbb_ext.h>
+
+/* Plat Defined TBBR extensions */
+enum {
+ DDR_FW_CONTENT_CERT_PK_EXT = FWU_HASH_EXT + 1,
+ DDR_IMEM_UDIMM_1D_HASH_EXT,
+ DDR_IMEM_UDIMM_2D_HASH_EXT,
+ DDR_DMEM_UDIMM_1D_HASH_EXT,
+ DDR_DMEM_UDIMM_2D_HASH_EXT,
+ DDR_IMEM_RDIMM_1D_HASH_EXT,
+ DDR_IMEM_RDIMM_2D_HASH_EXT,
+ DDR_DMEM_RDIMM_1D_HASH_EXT,
+ DDR_DMEM_RDIMM_2D_HASH_EXT
+};
+
+#endif /* PDEF_TBB_EXT_H */
diff --git a/tools/nxp/cert_create_helper/include/pdef_tbb_key.h b/tools/nxp/cert_create_helper/include/pdef_tbb_key.h
new file mode 100644
index 0000000..b26b651
--- /dev/null
+++ b/tools/nxp/cert_create_helper/include/pdef_tbb_key.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PDEF_TBB_KEY_H
+#define PDEF_TBB_KEY_H
+
+#include <tbbr/tbb_key.h>
+
+/*
+ * Enumerate the pltform defined keys that are used to establish the chain of trust
+ */
+enum {
+ DDR_FW_CONTENT_KEY = NON_TRUSTED_FW_CONTENT_CERT_KEY + 1,
+};
+#endif /* PDEF_TBB_KEY_H */
diff --git a/tools/nxp/cert_create_helper/src/pdef_tbb_cert.c b/tools/nxp/cert_create_helper/src/pdef_tbb_cert.c
new file mode 100644
index 0000000..40bd928
--- /dev/null
+++ b/tools/nxp/cert_create_helper/src/pdef_tbb_cert.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <pdef_tbb_cert.h>
+#include <pdef_tbb_ext.h>
+#include <pdef_tbb_key.h>
+
+static cert_t pdef_tbb_certs[] = {
+ [DDR_FW_KEY_CERT - DDR_FW_KEY_CERT] = {
+ .id = DDR_FW_KEY_CERT,
+ .opt = "ddr-fw-key-cert",
+ .help_msg = "DDR Firmware Key Certificate (output file)",
+ .fn = NULL,
+ .cn = "DDR Firmware Key Certificate",
+ .key = TRUSTED_WORLD_KEY,
+ .issuer = DDR_FW_KEY_CERT,
+ .ext = {
+ TRUSTED_FW_NVCOUNTER_EXT,
+ DDR_FW_CONTENT_CERT_PK_EXT,
+ },
+ .num_ext = 2
+ },
+ [DDR_UDIMM_FW_CONTENT_CERT - DDR_FW_KEY_CERT] = {
+ .id = DDR_UDIMM_FW_CONTENT_CERT,
+ .opt = "ddr-udimm-fw-cert",
+ .help_msg = "DDR UDIMM Firmware Content Certificate (output file)",
+ .fn = NULL,
+ .cn = "DDR UDIMM Firmware Content Certificate",
+ .key = DDR_FW_CONTENT_KEY,
+ .issuer = DDR_UDIMM_FW_CONTENT_CERT,
+ .ext = {
+ TRUSTED_FW_NVCOUNTER_EXT,
+ DDR_IMEM_UDIMM_1D_HASH_EXT,
+ DDR_IMEM_UDIMM_2D_HASH_EXT,
+ DDR_DMEM_UDIMM_1D_HASH_EXT,
+ DDR_DMEM_UDIMM_2D_HASH_EXT,
+ },
+ .num_ext = 5
+ },
+ [DDR_RDIMM_FW_CONTENT_CERT - DDR_FW_KEY_CERT] = {
+ .id = DDR_RDIMM_FW_CONTENT_CERT,
+ .opt = "ddr-rdimm-fw-cert",
+ .help_msg = "DDR RDIMM Firmware Content Certificate (output file)",
+ .fn = NULL,
+ .cn = "DDR RDIMM Firmware Content Certificate",
+ .key = DDR_FW_CONTENT_KEY,
+ .issuer = DDR_RDIMM_FW_CONTENT_CERT,
+ .ext = {
+ TRUSTED_FW_NVCOUNTER_EXT,
+ DDR_IMEM_RDIMM_1D_HASH_EXT,
+ DDR_IMEM_RDIMM_2D_HASH_EXT,
+ DDR_DMEM_RDIMM_1D_HASH_EXT,
+ DDR_DMEM_RDIMM_2D_HASH_EXT,
+ },
+ .num_ext = 5
+ }
+};
+
+PLAT_REGISTER_COT(pdef_tbb_certs);
diff --git a/tools/nxp/cert_create_helper/src/pdef_tbb_ext.c b/tools/nxp/cert_create_helper/src/pdef_tbb_ext.c
new file mode 100644
index 0000000..f6da6dd
--- /dev/null
+++ b/tools/nxp/cert_create_helper/src/pdef_tbb_ext.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <openssl/err.h>
+#include <openssl/x509v3.h>
+
+#if USE_TBBR_DEFS
+#include <tbbr_oid.h>
+#else
+#include <platform_oid.h>
+#endif
+
+#include "ext.h"
+#include "tbbr/tbb_ext.h"
+#include "tbbr/tbb_key.h"
+
+#include <pdef_tbb_ext.h>
+#include <pdef_tbb_key.h>
+
+static ext_t pdef_tbb_ext[] = {
+ [DDR_FW_CONTENT_CERT_PK_EXT - DDR_FW_CONTENT_CERT_PK_EXT] = {
+ .oid = DDR_FW_CONTENT_CERT_PK_OID,
+ .sn = "DDR FirmwareContentCertPK",
+ .ln = "DDR Firmware content certificate public key",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_PKEY,
+ .attr.key = DDR_FW_CONTENT_KEY
+ },
+ [DDR_IMEM_UDIMM_1D_HASH_EXT - DDR_FW_CONTENT_CERT_PK_EXT] = {
+ .oid = DDR_IMEM_UDIMM_1D_HASH_OID,
+ .opt = "ddr-immem-udimm-1d",
+ .help_msg = "DDR Firmware IMEM UDIMM 1D image file",
+ .sn = "DDR UDIMM IMEM 1D FirmwareHash",
+ .ln = "DDR UDIMM IMEM 1D Firmware hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH
+ },
+ [DDR_IMEM_UDIMM_2D_HASH_EXT - DDR_FW_CONTENT_CERT_PK_EXT] = {
+ .oid = DDR_IMEM_UDIMM_2D_HASH_OID,
+ .opt = "ddr-immem-udimm-2d",
+ .help_msg = "DDR Firmware IMEM UDIMM 2D image file",
+ .sn = "DDR UDIMM IMEM 2D FirmwareHash",
+ .ln = "DDR UDIMM IMEM 2D Firmware hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH
+ },
+ [DDR_DMEM_UDIMM_1D_HASH_EXT - DDR_FW_CONTENT_CERT_PK_EXT] = {
+ .oid = DDR_DMEM_UDIMM_1D_HASH_OID,
+ .opt = "ddr-dmmem-udimm-1d",
+ .help_msg = "DDR Firmware DMEM UDIMM 1D image file",
+ .sn = "DDR UDIMM DMEM 1D FirmwareHash",
+ .ln = "DDR UDIMM DMEM 1D Firmware hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH
+ },
+ [DDR_DMEM_UDIMM_2D_HASH_EXT - DDR_FW_CONTENT_CERT_PK_EXT] = {
+ .oid = DDR_DMEM_UDIMM_2D_HASH_OID,
+ .opt = "ddr-dmmem-udimm-2d",
+ .help_msg = "DDR Firmware DMEM UDIMM 2D image file",
+ .sn = "DDR UDIMM DMEM 2D FirmwareHash",
+ .ln = "DDR UDIMM DMEM 2D Firmware hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH
+ },
+ [DDR_IMEM_RDIMM_1D_HASH_EXT - DDR_FW_CONTENT_CERT_PK_EXT] = {
+ .oid = DDR_IMEM_RDIMM_1D_HASH_OID,
+ .opt = "ddr-immem-rdimm-1d",
+ .help_msg = "DDR Firmware IMEM RDIMM 1D image file",
+ .sn = "DDR RDIMM IMEM 1D FirmwareHash",
+ .ln = "DDR RDIMM IMEM 1D Firmware hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH
+ },
+ [DDR_IMEM_RDIMM_2D_HASH_EXT - DDR_FW_CONTENT_CERT_PK_EXT] = {
+ .oid = DDR_IMEM_RDIMM_2D_HASH_OID,
+ .opt = "ddr-immem-rdimm-2d",
+ .help_msg = "DDR Firmware IMEM RDIMM 2D image file",
+ .sn = "DDR RDIMM IMEM 2D FirmwareHash",
+ .ln = "DDR RDIMM IMEM 2D Firmware hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH
+ },
+ [DDR_DMEM_RDIMM_1D_HASH_EXT - DDR_FW_CONTENT_CERT_PK_EXT] = {
+ .oid = DDR_DMEM_RDIMM_1D_HASH_OID,
+ .opt = "ddr-dmmem-rdimm-1d",
+ .help_msg = "DDR Firmware DMEM RDIMM 1D image file",
+ .sn = "DDR RDIMM DMEM 1D FirmwareHash",
+ .ln = "DDR RDIMM DMEM 1D Firmware hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH
+ },
+ [DDR_DMEM_RDIMM_2D_HASH_EXT - DDR_FW_CONTENT_CERT_PK_EXT] = {
+ .oid = DDR_DMEM_RDIMM_2D_HASH_OID,
+ .opt = "ddr-dmmem-rdimm-2d",
+ .help_msg = "DDR Firmware DMEM RDIMM 2D image file",
+ .sn = "DDR RDIMM DMEM 2D FirmwareHash",
+ .ln = "DDR RDIMM DMEM 2D Firmware hash (SHA256)",
+ .asn1_type = V_ASN1_OCTET_STRING,
+ .type = EXT_TYPE_HASH
+ }
+};
+
+PLAT_REGISTER_EXTENSIONS(pdef_tbb_ext);
diff --git a/tools/nxp/cert_create_helper/src/pdef_tbb_key.c b/tools/nxp/cert_create_helper/src/pdef_tbb_key.c
new file mode 100644
index 0000000..cf2ebda
--- /dev/null
+++ b/tools/nxp/cert_create_helper/src/pdef_tbb_key.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <pdef_tbb_key.h>
+
+static key_t pdef_tbb_keys[] = {
+ [DDR_FW_CONTENT_KEY - DDR_FW_CONTENT_KEY] = {
+ .id = DDR_FW_CONTENT_KEY,
+ .opt = "ddr-fw-key",
+ .help_msg = "DDR Firmware Content Certificate key (input/output file)",
+ .desc = "DDR Firmware Content Certificate key"
+ }
+};
+
+PLAT_REGISTER_KEYS(pdef_tbb_keys);
diff --git a/tools/nxp/create_pbl/Makefile b/tools/nxp/create_pbl/Makefile
new file mode 100644
index 0000000..f971a74
--- /dev/null
+++ b/tools/nxp/create_pbl/Makefile
@@ -0,0 +1,61 @@
+#
+# Copyright 2018-2020 NXP
+#
+# 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_1 := create_pbl${BIN_EXT}
+OBJECTS_1 := create_pbl.o
+PROJECT_2 := byte_swap${BIN_EXT}
+OBJECTS_2 := byte_swap.o
+V ?= 0
+
+override CPPFLAGS += -D_GNU_SOURCE -D_XOPEN_SOURCE=700
+CFLAGS := -Wall -Werror -pedantic -std=c99
+ifeq (${DEBUG},1)
+ CFLAGS += -g -O0 -DDEBUG
+else
+ CFLAGS += -O2
+endif
+LDLIBS :=
+
+ifeq (${V},0)
+ Q := @
+else
+ Q :=
+endif
+
+INCLUDE_PATHS :=
+
+HOSTCC ?= gcc
+CC = gcc
+
+.PHONY: all clean distclean
+
+all: create_pbl byte_swap
+
+${PROJECT_1}: ${OBJECTS_1} Makefile
+ @echo " LD $@"
+ ${Q}${HOSTCC} ${OBJECTS_1} -o $@ ${LDLIBS}
+ @${ECHO_BLANK_LINE}
+ @echo "Built $@ successfully"
+ @${ECHO_BLANK_LINE}
+
+${PROJECT_2}: ${OBJECTS_2} Makefile
+ @echo " LD $@"
+ ${Q}${HOSTCC} ${OBJECTS_2} -o $@ ${LDLIBS}
+ @${ECHO_BLANK_LINE}
+ @echo "Built $@ successfully"
+ @${ECHO_BLANK_LINE}
+
+%.o: %.c %.h Makefile
+ @echo " CC $<"
+ ${Q}${HOSTCC} -c ${CPPFLAGS} ${CFLAGS} ${INCLUDE_PATHS} $< -o $@
+
+clean:
+ $(call SHELL_DELETE_ALL, ${PROJECT_1} ${OBJECTS_1})
+ $(call SHELL_DELETE_ALL, ${PROJECT_2} ${OBJECTS_2})
diff --git a/tools/nxp/create_pbl/README b/tools/nxp/create_pbl/README
new file mode 100644
index 0000000..3b6f854
--- /dev/null
+++ b/tools/nxp/create_pbl/README
@@ -0,0 +1,65 @@
+Description:
+------------
+Tool 'create_pbl' is a standalone tool to create the PBL images.
+ where,
+ On the basis of Chassis,
+ RCW image is placed first followed by the,
+ PBI commands to copy the,
+ Input BL2 image stored on the,
+ Specified boot source (QSPI or SD or NOR) to the,
+ Specified destination address.
+
+
+Usage in standalone way:
+-----------------------
+
+./create_pbl [options] (mentioned below):
+
+ -r <RCW file-name> - name of RCW binary file.
+ -i <BL2 Bin file-name> - file to be added to rcw file.
+ -c <SoC Number> - SoC numeric identifier, may be one of
+ 1012,1023,1026.1028,
+ 1043,1046,1088,2080,
+ 2088,2160
+ -b <boot source id> - Boot source id string, may be one of
+ "qspi", "nor", "nand", "sd", "emmc"
+ -d <Address> - Destination address where BL2
+ image is to be copied
+ -o <output filename> - Name of PBL image generated
+ as an output of the tool.
+ -e <Address> - [Optional] Entry Point Address
+ of the BL2.bin
+ -f <Address> - BL2 image offset
+ on Boot Source for block copy.
+ command for chassis >=3.)
+ (Must for Ch3, Ignored for Ch2)
+ -h Help.
+ -s Secure boot.
+
+ -s secure boot
+ -c SoC Number (see description above)
+ -b Boot source.
+ -r RCW binary file.
+ -i Input file that is to be added to rcw file.
+ -o Name of output file
+ -f Source Offset (Block Copy)
+ -d Destination address to which file has to be copied
+ -h Help.
+
+Example:
+ ./create_pbl -r <RCW file> -i <bl2.bin> -c <chassis_no> -b <boot_source = sd/qspi/nor> -d <Destination_Addr> -o <pbl_image_name>
+
+
+
+Usage at compilation time:
+--------------------------------
+
+ make <compilation command......> pbl RCW=<Path_to_RCW_File>/<rcw_file_name.bin>
+
+Example: QSPI Boot For LS1046ARDB-
+
+ make PLAT=ls1046rdb all fip BOOT_MODE=qspi SPD=opteed BL32=tee.bin BL33=u-boot-ls1046.bin pbl RCW=/home/pankaj/flexbuild/packages/firmware/dash-rcw/ls1046ardb/RR_FFSSPPPN_1133_5506/rcw_1600_qspiboot.bin
+
+Example: QSPI Boot For LX2160ARDB-
+
+ make PLAT=lx2160ardb all fip BOOT_MODE=flexspi_nor SPD=opteed BL32=tee_lx2.bin BL33=u-boot_lx2160.bin pbl RCW=plat/nxp/soc-lx2160/lx2160ardb/rcw_1900_600_1600_19_5_2.bin
diff --git a/tools/nxp/create_pbl/byte_swap.c b/tools/nxp/create_pbl/byte_swap.c
new file mode 100644
index 0000000..1d0bfce
--- /dev/null
+++ b/tools/nxp/create_pbl/byte_swap.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <getopt.h>
+#include <unistd.h>
+
+#define NUM_MEM_BLOCK 1
+#define FOUR_BYTE_ALIGN 4
+#define EIGHT_BYTE_ALIGN 8
+#define SIZE_TWO_PBL_CMD 24
+
+#define SUCCESS 0
+#define FAILURE -1
+#define BYTE_SWAP_32(word) ((((word) & 0xff000000) >> 24)| \
+ (((word) & 0x00ff0000) >> 8) | \
+ (((word) & 0x0000ff00) << 8) | \
+ (((word) & 0x000000ff) << 24))
+
+
+/*
+ * Returns:
+ * SUCCESS, on successful byte swapping.
+ * FAILURE, on failure.
+ */
+int do_byteswap(FILE *fp)
+{
+ int bytes = 0;
+ uint32_t upper_byte;
+ uint32_t lower_byte;
+ uint32_t pad = 0U;
+ /* Carries number of Padding bytes to be appended to
+ * make file size 8 byte aligned.
+ */
+ int append_bytes;
+ int ret = FAILURE;
+
+ fseek(fp, 0L, SEEK_END);
+ bytes = ftell(fp);
+
+ append_bytes = EIGHT_BYTE_ALIGN - (bytes % EIGHT_BYTE_ALIGN);
+ if (append_bytes != 0) {
+ if (fwrite(&pad, append_bytes, NUM_MEM_BLOCK, fp)
+ != NUM_MEM_BLOCK) {
+ printf("%s: Error in appending padding bytes.\n",
+ __func__);
+ goto byteswap_err;
+ }
+ bytes += append_bytes;
+ }
+
+ rewind(fp);
+ while (bytes > 0) {
+ if ((fread(&upper_byte, sizeof(upper_byte), NUM_MEM_BLOCK, fp)
+ != NUM_MEM_BLOCK) && (feof(fp) == 0)) {
+ printf("%s: Error reading upper bytes.\n", __func__);
+ goto byteswap_err;
+ }
+ if ((fread(&lower_byte, sizeof(lower_byte), NUM_MEM_BLOCK, fp)
+ != NUM_MEM_BLOCK) && (feof(fp) == 0)) {
+ printf("%s: Error reading lower bytes.\n", __func__);
+ goto byteswap_err;
+ }
+ fseek(fp, -8L, SEEK_CUR);
+ upper_byte = BYTE_SWAP_32(upper_byte);
+ lower_byte = BYTE_SWAP_32(lower_byte);
+ if (fwrite(&lower_byte, sizeof(lower_byte), NUM_MEM_BLOCK, fp)
+ != NUM_MEM_BLOCK) {
+ printf("%s: Error writing lower bytes.\n", __func__);
+ goto byteswap_err;
+ }
+ if (fwrite(&upper_byte, sizeof(upper_byte), NUM_MEM_BLOCK, fp)
+ != NUM_MEM_BLOCK) {
+ printf("%s: Error writing upper bytes.\n", __func__);
+ goto byteswap_err;
+ }
+ bytes -= EIGHT_BYTE_ALIGN;
+ }
+ ret = SUCCESS;
+
+byteswap_err:
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ FILE *fp = NULL;
+ int ret = 0;
+
+ if (argc > 2) {
+ printf("Usage format is byteswap <filename>");
+ return -1;
+ }
+
+ fp = fopen(argv[1], "rb+");
+ if (fp == NULL) {
+ printf("%s: Error opening the input file: %s\n",
+ __func__, argv[1]);
+ return -1;
+ }
+
+ ret = do_byteswap(fp);
+ fclose(fp);
+ return ret;
+}
diff --git a/tools/nxp/create_pbl/create_pbl.c b/tools/nxp/create_pbl/create_pbl.c
new file mode 100644
index 0000000..9457a00
--- /dev/null
+++ b/tools/nxp/create_pbl/create_pbl.c
@@ -0,0 +1,998 @@
+/*
+ * Copyright 2021-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <getopt.h>
+#include <unistd.h>
+
+#define NUM_MEM_BLOCK 1
+#define FOUR_BYTE_ALIGN 4
+#define EIGHT_BYTE_ALIGN 8
+#define SIZE_TWO_PBL_CMD 24
+
+/* Define for add_boot_ptr_cmd() */
+#define BOOTPTR_ADDR 0x09570604
+#define CSF_ADDR_SB 0x09ee0200
+/* CCSR write command to address 0x1e00400 i.e BOOTLOCPTR */
+#define BOOTPTR_ADDR_CH3 0x31e00400
+/* Load CSF header command */
+#define CSF_ADDR_SB_CH3 0x80220000
+
+#define MAND_ARG_MASK 0xFFF3
+#define ARG_INIT_MASK 0xFF00
+#define RCW_FILE_NAME_ARG_MASK 0x0080
+#define IN_FILE_NAME_ARG_MASK 0x0040
+#define CHASSIS_ARG_MASK 0x0020
+#define BOOT_SRC_ARG_MASK 0x0010
+#define ENTRY_POINT_ADDR_ARG_MASK 0x0008
+#define BL2_BIN_STRG_LOC_BOOT_SRC_ARG_MASK 0x0004
+#define BL2_BIN_CPY_DEST_ADDR_ARG_MASK 0x0002
+#define OP_FILE_NAME_ARG_MASK 0x0001
+
+/* Define for add_cpy_cmd() */
+#define OFFSET_MASK 0x00ffffff
+#define WRITE_CMD_BASE 0x81000000
+#define MAX_PBI_DATA_LEN_BYTE 64
+
+/* 140 Bytes = Preamble + LOAD RCW command + RCW (128 bytes) + Checksum */
+#define CHS3_CRC_PAYLOAD_START_OFFSET 140
+
+#define PBI_CRC_POLYNOMIAL 0x04c11db7
+
+typedef enum {
+ CHASSIS_UNKNOWN,
+ CHASSIS_2,
+ CHASSIS_3,
+ CHASSIS_3_2,
+ CHASSIS_MAX /* must be last item in list */
+} chassis_t;
+
+typedef enum {
+ UNKNOWN_BOOT = 0,
+ IFC_NOR_BOOT,
+ IFC_NAND_BOOT,
+ QSPI_BOOT,
+ SD_BOOT,
+ EMMC_BOOT,
+ FLXSPI_NOR_BOOT,
+ FLXSPI_NAND_BOOT,
+ FLXSPI_NAND4K_BOOT,
+ MAX_BOOT /* must be last item in list */
+} boot_src_t;
+
+/* Base Addresses where PBL image is copied depending on the boot source.
+ * Boot address map varies as per Chassis architecture.
+ */
+#define BASE_ADDR_UNDEFINED 0xFFFFFFFF
+#define BASE_ADDR_QSPI 0x20000000
+#define BASE_ADDR_SD 0x00001000
+#define BASE_ADDR_IFC_NOR 0x30000000
+#define BASE_ADDR_EMMC 0x00001000
+#define BASE_ADDR_FLX_NOR 0x20000000
+#define BASE_ADDR_NAND 0x20000000
+
+uint32_t base_addr_ch3[MAX_BOOT] = {
+ BASE_ADDR_UNDEFINED,
+ BASE_ADDR_IFC_NOR,
+ BASE_ADDR_UNDEFINED, /*IFC NAND */
+ BASE_ADDR_QSPI,
+ BASE_ADDR_SD,
+ BASE_ADDR_EMMC,
+ BASE_ADDR_UNDEFINED, /*FLXSPI NOR */
+ BASE_ADDR_UNDEFINED, /*FLXSPI NAND 2K */
+ BASE_ADDR_UNDEFINED /*FLXSPI NAND 4K */
+};
+
+uint32_t base_addr_ch32[MAX_BOOT] = {
+ BASE_ADDR_UNDEFINED,
+ BASE_ADDR_UNDEFINED, /* IFC NOR */
+ BASE_ADDR_UNDEFINED, /* IFC NAND */
+ BASE_ADDR_UNDEFINED, /* QSPI */
+ BASE_ADDR_SD,
+ BASE_ADDR_EMMC,
+ BASE_ADDR_FLX_NOR,
+ BASE_ADDR_UNDEFINED, /*FLXSPI NAND 2K */
+ BASE_ADDR_UNDEFINED /*FLXSPI NAND 4K */
+};
+
+/* for Chassis 3 */
+uint32_t blk_cpy_hdr_map_ch3[] = {
+
+ 0, /* Unknown Boot Source */
+ 0x80000020, /* NOR_BOOT */
+ 0x0, /* NAND_BOOT */
+ 0x80000062, /* QSPI_BOOT */
+ 0x80000040, /* SD_BOOT */
+ 0x80000041, /* EMMC_BOOT */
+ 0x0, /* FLEXSPI NOR_BOOT */
+ 0x0, /* FLEX SPI NAND2K BOOT */
+ 0x0, /* CHASIS3_2_NAND4K_BOOT */
+};
+
+uint32_t blk_cpy_hdr_map_ch32[] = {
+ 0, /* Unknown Boot Source */
+ 0x0, /* NOR_BOOT */
+ 0x0, /* NAND_BOOT */
+ 0x0, /* QSPI_BOOT */
+ 0x80000008, /* SD_BOOT */
+ 0x80000009, /* EMMC_BOOT */
+ 0x8000000F, /* FLEXSPI NOR_BOOT */
+ 0x8000000C, /* FLEX SPI NAND2K BOOT */
+ 0x8000000D, /* CHASIS3_2_NAND4K_BOOT */
+};
+
+char *boot_src_string[] = {
+ "UNKNOWN_BOOT",
+ "IFC_NOR_BOOT",
+ "IFC_NAND_BOOT",
+ "QSPI_BOOT",
+ "SD_BOOT",
+ "EMMC_BOOT",
+ "FLXSPI_NOR_BOOT",
+ "FLXSPI_NAND_BOOT",
+ "FLXSPI_NAND4K_BOOT",
+};
+
+enum stop_command {
+ STOP_COMMAND = 0,
+ CRC_STOP_COMMAND
+};
+
+/* Structure will get populated in the main function
+ * as part of parsing the command line arguments.
+ * All member parameters are mandatory except:
+ * -ep
+ * -src_addr
+ */
+struct pbl_image {
+ char *rcw_nm; /* Input RCW File */
+ char *sec_imgnm; /* Input BL2 binary */
+ char *imagefile; /* Generated output file */
+ boot_src_t boot_src; /* Boot Source - QSPI, SD, NOR, NAND etc */
+ uint32_t src_addr; /* Source Address */
+ uint32_t addr; /* Load address */
+ uint32_t ep; /* Entry point <opt> default is load address */
+ chassis_t chassis; /* Chassis type */
+} pblimg;
+
+#define SUCCESS 0
+#define FAILURE -1
+#define CRC_STOP_CMD_ARM 0x08610040
+#define CRC_STOP_CMD_ARM_CH3 0x808f0000
+#define STOP_CMD_ARM_CH3 0x80ff0000
+#define BYTE_SWAP_32(word) ((((word) & 0xff000000) >> 24)| \
+ (((word) & 0x00ff0000) >> 8) | \
+ (((word) & 0x0000ff00) << 8) | \
+ (((word) & 0x000000ff) << 24))
+
+#define PBI_LEN_MASK 0xFFF00000
+#define PBI_LEN_SHIFT 20
+#define NUM_RCW_WORD 35
+#define PBI_LEN_ADD 6
+
+#define MAX_CRC_ENTRIES 256
+
+/* SoC numeric identifier */
+#define SOC_LS1012 1012
+#define SOC_LS1023 1023
+#define SOC_LS1026 1026
+#define SOC_LS1028 1028
+#define SOC_LS1043 1043
+#define SOC_LS1046 1046
+#define SOC_LS1088 1088
+#define SOC_LS2080 2080
+#define SOC_LS2088 2088
+#define SOC_LX2160 2160
+
+static uint32_t pbl_size;
+bool sb_flag;
+
+/***************************************************************************
+ * Description : CRC32 Lookup Table
+ ***************************************************************************/
+static uint32_t crc32_lookup[] = {
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
+ 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
+ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
+ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
+ 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
+ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
+ 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
+ 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
+ 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
+ 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
+ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
+ 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
+ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
+ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
+ 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
+ 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
+ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
+ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
+ 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
+ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
+ 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
+ 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
+ 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
+ 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
+ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
+ 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
+ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
+ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
+ 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
+ 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
+ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+ };
+
+
+static void print_usage(void)
+{
+ printf("\nCorrect Usage of Tool is:\n");
+ printf("\n ./create_pbl [options] (mentioned below):\n\n");
+ printf("\t-r <RCW file-name> - name of RCW binary file.\n");
+ printf("\t-i <BL2 Bin file-name> - file to be added to rcw file.\n");
+ printf("\t-c <Number> - Chassis Architecture (=2 or =3\n");
+ printf("\t or =4 for 3.2).\n");
+ printf("\t-b <qspi/nor/nand/sd> - Boot source.\n");
+ printf("\t-d <Address> - Destination address where BL2\n");
+ printf("\t image is to be copied\n");
+ printf("\t-o <output filename> - Name of PBL image generated\n");
+ printf("\t as an output of the tool.\n");
+ printf("\t-f <Address> - BL2 image Src Offset\n");
+ printf("\t on Boot Source for block copy.\n");
+ printf("\t command for chassis >=3.)\n");
+ printf("\t-e <Address> - [Optional] Entry Point Address\n");
+ printf("\t of the BL2.bin\n");
+ printf("\t-s Secure Boot.\n");
+ printf("\t-h Help.\n");
+ printf("\n\n");
+ exit(0);
+
+}
+
+/***************************************************************************
+ * Function : crypto_calculate_checksum()
+ * Arguments : data - Pointer to FILE
+ * num - Number of 32 bit words for checksum
+ * Return : Checksum Value
+ * Description : Calculate Checksum over the data
+ ***************************************************************************/
+uint32_t crypto_calculate_checksum(FILE *fp_rcw_pbi_op, uint32_t num)
+{
+ uint32_t i;
+ uint64_t sum = 0;
+ uint32_t word;
+
+ fseek(fp_rcw_pbi_op, 0L, SEEK_SET);
+ for (i = 0; i < num ; i++) {
+ if ((fread(&word, sizeof(word), NUM_MEM_BLOCK, fp_rcw_pbi_op))
+ < NUM_MEM_BLOCK) {
+ printf("%s: Error reading word.\n", __func__);
+ return FAILURE;
+ }
+ sum = sum + word;
+ sum = sum & 0xFFFFFFFF;
+ }
+ return (uint32_t)sum;
+}
+
+/***************************************************************************
+ * Function : add_pbi_stop_cmd
+ * Arguments : fp_rcw_pbi_op - output rcw_pbi file pointer
+ * Return : SUCCESS or FAILURE
+ * Description : This function insert pbi stop command.
+ ***************************************************************************/
+int add_pbi_stop_cmd(FILE *fp_rcw_pbi_op, enum stop_command flag)
+{
+ int ret = FAILURE;
+ int32_t pbi_stop_cmd;
+ uint32_t pbi_crc = 0xffffffff, i, j, c;
+ uint32_t crc_table[MAX_CRC_ENTRIES];
+ uint8_t data;
+
+ switch (pblimg.chassis) {
+ case CHASSIS_2:
+ pbi_stop_cmd = BYTE_SWAP_32(CRC_STOP_CMD_ARM);
+ break;
+ case CHASSIS_3:
+ case CHASSIS_3_2:
+ /* Based on flag add the corresponsding cmd
+ * -- stop cmd or stop with CRC cmd
+ */
+ if (flag == CRC_STOP_COMMAND) {
+ pbi_stop_cmd = CRC_STOP_CMD_ARM_CH3;
+ } else {
+ pbi_stop_cmd = STOP_CMD_ARM_CH3;
+ }
+ break;
+ case CHASSIS_UNKNOWN:
+ case CHASSIS_MAX:
+ default:
+ printf("Internal Error: Invalid Chassis val = %d.\n",
+ pblimg.chassis);
+ goto pbi_stop_err;
+ }
+
+ if (fwrite(&pbi_stop_cmd, sizeof(pbi_stop_cmd), NUM_MEM_BLOCK,
+ fp_rcw_pbi_op) != NUM_MEM_BLOCK) {
+ printf("%s: Error in Writing PBI STOP CMD\n", __func__);
+ goto pbi_stop_err;
+ }
+
+ if (flag == CRC_STOP_COMMAND) {
+ for (i = 0; i < MAX_CRC_ENTRIES; i++) {
+ c = i << 24;
+ for (j = 0; j < 8; j++) {
+ c = (c & 0x80000000) ?
+ PBI_CRC_POLYNOMIAL ^ (c << 1) : c << 1;
+ }
+
+ crc_table[i] = c;
+ }
+ }
+
+ switch (pblimg.chassis) {
+ case CHASSIS_2:
+ /* Chassis 2: CRC is calculated on RCW + PBL cmd.*/
+ fseek(fp_rcw_pbi_op, 0L, SEEK_SET);
+ break;
+ case CHASSIS_3:
+ case CHASSIS_3_2:
+ /* Chassis 3: CRC is calculated on PBL cmd only. */
+ fseek(fp_rcw_pbi_op, CHS3_CRC_PAYLOAD_START_OFFSET, SEEK_SET);
+ break;
+ case CHASSIS_UNKNOWN:
+ case CHASSIS_MAX:
+ printf("%s: Unknown Chassis.\n", __func__);
+ goto pbi_stop_err;
+ }
+
+ while ((fread(&data, sizeof(data), NUM_MEM_BLOCK, fp_rcw_pbi_op))
+ == NUM_MEM_BLOCK) {
+ if (flag == CRC_STOP_COMMAND) {
+ if (pblimg.chassis == CHASSIS_2) {
+ pbi_crc = crc_table
+ [((pbi_crc >> 24) ^ (data)) & 0xff] ^
+ (pbi_crc << 8);
+ } else {
+ pbi_crc = (pbi_crc >> 8) ^
+ crc32_lookup[((pbi_crc) ^
+ (data)) & 0xff];
+ }
+ }
+ }
+
+ switch (pblimg.chassis) {
+ case CHASSIS_2:
+ pbi_crc = BYTE_SWAP_32(pbi_crc);
+ break;
+ case CHASSIS_3:
+ case CHASSIS_3_2:
+ if (flag == CRC_STOP_COMMAND) {
+ pbi_crc = pbi_crc ^ 0xFFFFFFFF;
+ } else {
+ pbi_crc = 0x00000000;
+ }
+ break;
+ case CHASSIS_UNKNOWN:
+ case CHASSIS_MAX:
+ printf("%s: Unknown Chassis.\n", __func__);
+ goto pbi_stop_err;
+ }
+
+ if (fwrite(&pbi_crc, sizeof(pbi_crc), NUM_MEM_BLOCK, fp_rcw_pbi_op)
+ != NUM_MEM_BLOCK) {
+ printf("%s: Error in Writing PBI PBI CRC\n", __func__);
+ goto pbi_stop_err;
+ }
+ ret = SUCCESS;
+
+pbi_stop_err:
+ return ret;
+}
+
+/*
+ * Returns:
+ * File size in bytes, on Success.
+ * FAILURE, on failure.
+ */
+int get_filesize(const char *c)
+{
+ FILE *fp;
+ int ret = FAILURE;
+
+ fp = fopen(c, "rb");
+ if (fp == NULL) {
+ fprintf(stderr, "%s: Error in opening the file: %s\n",
+ __func__, c);
+ goto filesize_err;
+ }
+
+ fseek(fp, 0L, SEEK_END);
+ ret = ftell(fp);
+ fclose(fp);
+
+filesize_err:
+ return ret;
+}
+
+/***************************************************************************
+ * Function : get_bootptr
+ * Arguments : fp_rcw_pbi_op - Pointer to output file
+ * Return : SUCCESS or FAILURE
+ * Description : Add bootptr pbi command to output file
+ ***************************************************************************/
+int add_boot_ptr_cmd(FILE *fp_rcw_pbi_op)
+{
+ uint32_t bootptr_addr;
+ int ret = FAILURE;
+
+ switch (pblimg.chassis) {
+ case CHASSIS_2:
+ if (sb_flag == true)
+ bootptr_addr = BYTE_SWAP_32(CSF_ADDR_SB);
+ else
+ bootptr_addr = BYTE_SWAP_32(BOOTPTR_ADDR);
+ pblimg.ep = BYTE_SWAP_32(pblimg.ep);
+ break;
+ case CHASSIS_3:
+ case CHASSIS_3_2:
+ if (sb_flag == true)
+ bootptr_addr = CSF_ADDR_SB_CH3;
+ else
+ bootptr_addr = BOOTPTR_ADDR_CH3;
+ break;
+ case CHASSIS_UNKNOWN:
+ case CHASSIS_MAX:
+ default:
+ printf("Internal Error: Invalid Chassis val = %d.\n",
+ pblimg.chassis);
+ goto bootptr_err;
+ }
+
+ if (fwrite(&bootptr_addr, sizeof(bootptr_addr), NUM_MEM_BLOCK,
+ fp_rcw_pbi_op) != NUM_MEM_BLOCK) {
+ printf("%s: Error in Writing PBI Words:[%d].\n",
+ __func__, ret);
+ goto bootptr_err;
+ }
+
+ if (pblimg.ep != 0) {
+ if (fwrite(&pblimg.ep, sizeof(pblimg.ep), NUM_MEM_BLOCK,
+ fp_rcw_pbi_op) != NUM_MEM_BLOCK) {
+ printf("%s: Error in Writing PBI Words\n", __func__);
+ goto bootptr_err;
+ }
+ }
+
+ printf("\nBoot Location Pointer= 0x%x\n",
+ pblimg.chassis == CHASSIS_2 ? BYTE_SWAP_32(pblimg.ep) :
+ pblimg.ep);
+ ret = SUCCESS;
+
+bootptr_err:
+ return ret;
+}
+
+/***************************************************************************
+ * Function : add_blk_cpy_cmd
+ * Arguments : pbi_word - pointer to pbi commands
+ * args - Command line args flag.
+ * Return : SUCCESS or FAILURE
+ * Description : Add pbi commands for block copy cmd in pbi_words
+ ***************************************************************************/
+int add_blk_cpy_cmd(FILE *fp_rcw_pbi_op, uint16_t args)
+{
+ uint32_t blk_cpy_hdr;
+ uint32_t file_size, new_file_size;
+ uint32_t align = 4;
+ int ret = FAILURE;
+ int num_pad_bytes = 0;
+
+ if ((args & BL2_BIN_STRG_LOC_BOOT_SRC_ARG_MASK) == 0) {
+ printf("ERROR: Offset not specified for Block Copy Cmd.\n");
+ printf("\tSee Usage and use -f option\n");
+ goto blk_copy_err;
+ }
+
+ switch (pblimg.chassis) {
+ case CHASSIS_3:
+ /* Block copy command */
+ blk_cpy_hdr = blk_cpy_hdr_map_ch3[pblimg.boot_src];
+ pblimg.src_addr += base_addr_ch3[pblimg.boot_src];
+ break;
+ case CHASSIS_3_2:
+ /* Block copy command */
+ blk_cpy_hdr = blk_cpy_hdr_map_ch32[pblimg.boot_src];
+ pblimg.src_addr += base_addr_ch32[pblimg.boot_src];
+ break;
+ default:
+ printf("%s: Error invalid chassis type for this command.\n",
+ __func__);
+ goto blk_copy_err;
+ }
+
+ file_size = get_filesize(pblimg.sec_imgnm);
+ if (file_size > 0) {
+ new_file_size = (file_size + (file_size % align));
+
+ /* Add Block copy command */
+ if (fwrite(&blk_cpy_hdr, sizeof(blk_cpy_hdr), NUM_MEM_BLOCK,
+ fp_rcw_pbi_op) != NUM_MEM_BLOCK) {
+ printf("%s: Error writing blk_cpy_hdr to the file.\n",
+ __func__);
+ goto blk_copy_err;
+ }
+
+ if ((args & BL2_BIN_STRG_LOC_BOOT_SRC_ARG_MASK) == 0)
+ num_pad_bytes = pblimg.src_addr % 4;
+
+ /* Add Src address word */
+ if (fwrite(&pblimg.src_addr + num_pad_bytes,
+ sizeof(pblimg.src_addr), NUM_MEM_BLOCK,
+ fp_rcw_pbi_op) != NUM_MEM_BLOCK) {
+ printf("%s: Error writing BLK SRC Addr to the file.\n",
+ __func__);
+ goto blk_copy_err;
+ }
+
+ /* Add Dest address word */
+ if (fwrite(&pblimg.addr, sizeof(pblimg.addr),
+ NUM_MEM_BLOCK, fp_rcw_pbi_op) != NUM_MEM_BLOCK) {
+ printf("%s: Error writing DST Addr to the file.\n",
+ __func__);
+ goto blk_copy_err;
+ }
+
+ /* Add size */
+ if (fwrite(&new_file_size, sizeof(new_file_size),
+ NUM_MEM_BLOCK, fp_rcw_pbi_op) != NUM_MEM_BLOCK) {
+ printf("%s: Error writing size to the file.\n",
+ __func__);
+ goto blk_copy_err;
+ }
+ }
+
+ ret = SUCCESS;
+
+blk_copy_err:
+ return ret;
+}
+
+/***************************************************************************
+ * Function : add_cpy_cmd
+ * Arguments : pbi_word - pointer to pbi commands
+ * Return : SUCCESS or FAILURE
+ * Description : Append pbi commands for copying BL2 image to the
+ * load address stored in pbl_image.addr
+ ***************************************************************************/
+int add_cpy_cmd(FILE *fp_rcw_pbi_op)
+{
+ uint32_t ALTCBAR_ADDRESS = BYTE_SWAP_32(0x09570158);
+ uint32_t WAIT_CMD_WRITE_ADDRESS = BYTE_SWAP_32(0x096100c0);
+ uint32_t WAIT_CMD = BYTE_SWAP_32(0x000FFFFF);
+ int file_size;
+ uint32_t pbi_cmd, altcbar;
+ uint8_t pbi_data[MAX_PBI_DATA_LEN_BYTE];
+ uint32_t dst_offset;
+ FILE *fp_img = NULL;
+ int ret = FAILURE;
+
+ altcbar = pblimg.addr;
+ dst_offset = pblimg.addr;
+ fp_img = fopen(pblimg.sec_imgnm, "rb");
+ if (fp_img == NULL) {
+ printf("%s: Error in opening the file: %s\n", __func__,
+ pblimg.sec_imgnm);
+ goto add_cpy_err;
+ }
+ file_size = get_filesize(pblimg.sec_imgnm);
+ altcbar = 0xfff00000 & altcbar;
+ altcbar = BYTE_SWAP_32(altcbar >> 16);
+ if (fwrite(&ALTCBAR_ADDRESS, sizeof(ALTCBAR_ADDRESS), NUM_MEM_BLOCK,
+ fp_rcw_pbi_op) != NUM_MEM_BLOCK) {
+ printf("%s: Error in writing address of ALTCFG CMD.\n",
+ __func__);
+ goto add_cpy_err;
+ }
+ if (fwrite(&altcbar, sizeof(altcbar), NUM_MEM_BLOCK, fp_rcw_pbi_op)
+ != NUM_MEM_BLOCK) {
+ printf("%s: Error in writing ALTCFG CMD.\n", __func__);
+ goto add_cpy_err;
+ }
+ if (fwrite(&WAIT_CMD_WRITE_ADDRESS, sizeof(WAIT_CMD_WRITE_ADDRESS),
+ NUM_MEM_BLOCK, fp_rcw_pbi_op) != NUM_MEM_BLOCK) {
+ printf("%s: Error in writing address of WAIT_CMD.\n",
+ __func__);
+ goto add_cpy_err;
+ }
+ if (fwrite(&WAIT_CMD, sizeof(WAIT_CMD), NUM_MEM_BLOCK, fp_rcw_pbi_op)
+ != NUM_MEM_BLOCK) {
+ printf("%s: Error in writing WAIT_CMD.\n", __func__);
+ goto add_cpy_err;
+ }
+ do {
+ memset(pbi_data, 0, MAX_PBI_DATA_LEN_BYTE);
+
+ ret = fread(&pbi_data, MAX_PBI_DATA_LEN_BYTE,
+ NUM_MEM_BLOCK, fp_img);
+ if ((ret != NUM_MEM_BLOCK) && (!feof(fp_img))) {
+ printf("%s: Error writing ALTCFG Word: [%d].\n",
+ __func__, ret);
+ goto add_cpy_err;
+ }
+
+ dst_offset &= OFFSET_MASK;
+ pbi_cmd = WRITE_CMD_BASE | dst_offset;
+ pbi_cmd = BYTE_SWAP_32(pbi_cmd);
+ if (fwrite(&pbi_cmd, sizeof(pbi_cmd), NUM_MEM_BLOCK,
+ fp_rcw_pbi_op) != NUM_MEM_BLOCK) {
+ printf("%s: Error writing ALTCFG Word write cmd.\n",
+ __func__);
+ goto add_cpy_err;
+ }
+ if (fwrite(&pbi_data, MAX_PBI_DATA_LEN_BYTE, NUM_MEM_BLOCK,
+ fp_rcw_pbi_op) != NUM_MEM_BLOCK) {
+ printf("%s: Error writing ALTCFG_Word.\n", __func__);
+ goto add_cpy_err;
+ }
+ dst_offset += MAX_PBI_DATA_LEN_BYTE;
+ file_size -= MAX_PBI_DATA_LEN_BYTE;
+ } while (!feof(fp_img));
+
+ ret = SUCCESS;
+
+add_cpy_err:
+ if (fp_img != NULL) {
+ fclose(fp_img);
+ }
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ FILE *file = NULL;
+ char *ptr;
+ int opt;
+ int tmp;
+ uint16_t args = ARG_INIT_MASK;
+ FILE *fp_rcw_pbi_ip = NULL, *fp_rcw_pbi_op = NULL;
+ uint32_t word, word_1;
+ int ret = FAILURE;
+ bool bootptr_flag = false;
+ enum stop_command flag_stop_cmd = CRC_STOP_COMMAND;
+
+ /* Initializing the global structure to zero. */
+ memset(&pblimg, 0x0, sizeof(struct pbl_image));
+
+ while ((opt = getopt(argc, argv,
+ ":b:f:r:i:e:d:c:o:h:s")) != -1) {
+ switch (opt) {
+ case 'd':
+ pblimg.addr = strtoull(optarg, &ptr, 16);
+ if (*ptr != 0) {
+ fprintf(stderr, "CMD Error: invalid load or destination address %s\n", optarg);
+ goto exit_main;
+ }
+ args |= BL2_BIN_CPY_DEST_ADDR_ARG_MASK;
+ break;
+ case 'r':
+ pblimg.rcw_nm = optarg;
+ file = fopen(pblimg.rcw_nm, "r");
+ if (file == NULL) {
+ printf("CMD Error: Opening the RCW File.\n");
+ goto exit_main;
+ } else {
+ args |= RCW_FILE_NAME_ARG_MASK;
+ fclose(file);
+ }
+ break;
+ case 'e':
+ bootptr_flag = true;
+ pblimg.ep = strtoull(optarg, &ptr, 16);
+ if (*ptr != 0) {
+ fprintf(stderr,
+ "CMD Error: Invalid entry point %s\n", optarg);
+ goto exit_main;
+ }
+ break;
+ case 'h':
+ print_usage();
+ break;
+ case 'i':
+ pblimg.sec_imgnm = optarg;
+ file = fopen(pblimg.sec_imgnm, "r");
+ if (file == NULL) {
+ printf("CMD Error: Opening Input file.\n");
+ goto exit_main;
+ } else {
+ args |= IN_FILE_NAME_ARG_MASK;
+ fclose(file);
+ }
+ break;
+ case 'c':
+ tmp = atoi(optarg);
+ switch (tmp) {
+ case SOC_LS1012:
+ case SOC_LS1023:
+ case SOC_LS1026:
+ case SOC_LS1043:
+ case SOC_LS1046:
+ pblimg.chassis = CHASSIS_2;
+ break;
+ case SOC_LS1088:
+ case SOC_LS2080:
+ case SOC_LS2088:
+ pblimg.chassis = CHASSIS_3;
+ break;
+ case SOC_LS1028:
+ case SOC_LX2160:
+ pblimg.chassis = CHASSIS_3_2;
+ break;
+ default:
+ printf("CMD Error: Invalid SoC Val = %d.\n", tmp);
+ goto exit_main;
+ }
+
+ args |= CHASSIS_ARG_MASK;
+ break;
+ case 'o':
+ pblimg.imagefile = optarg;
+ args |= OP_FILE_NAME_ARG_MASK;
+ break;
+ case 's':
+ sb_flag = true;
+ break;
+ case 'b':
+ if (strcmp(optarg, "qspi") == 0) {
+ pblimg.boot_src = QSPI_BOOT;
+ } else if (strcmp(optarg, "nor") == 0) {
+ pblimg.boot_src = IFC_NOR_BOOT;
+ } else if (strcmp(optarg, "nand") == 0) {
+ pblimg.boot_src = IFC_NAND_BOOT;
+ } else if (strcmp(optarg, "sd") == 0) {
+ pblimg.boot_src = SD_BOOT;
+ } else if (strcmp(optarg, "emmc") == 0) {
+ pblimg.boot_src = EMMC_BOOT;
+ } else if (strcmp(optarg, "flexspi_nor") == 0) {
+ pblimg.boot_src = FLXSPI_NOR_BOOT;
+ } else if (strcmp(optarg, "flexspi_nand") == 0) {
+ pblimg.boot_src = FLXSPI_NAND_BOOT;
+ } else if (strcmp(optarg, "flexspi_nand2k") == 0) {
+ pblimg.boot_src = FLXSPI_NAND4K_BOOT;
+ } else {
+ printf("CMD Error: Invalid boot source.\n");
+ goto exit_main;
+ }
+ args |= BOOT_SRC_ARG_MASK;
+ break;
+ case 'f':
+ pblimg.src_addr = strtoull(optarg, &ptr, 16);
+ if (*ptr != 0) {
+ fprintf(stderr,
+ "CMD Error: Invalid src offset %s\n", optarg);
+ goto exit_main;
+ }
+ args |= BL2_BIN_STRG_LOC_BOOT_SRC_ARG_MASK;
+ break;
+ default:
+ /* issue a warning and skip the unknown arg */
+ printf("Cmd Warning: Invalid Arg = %c.\n", opt);
+ }
+ }
+
+ if ((args & MAND_ARG_MASK) != MAND_ARG_MASK) {
+ print_usage();
+ }
+
+ fp_rcw_pbi_ip = fopen(pblimg.rcw_nm, "rb");
+ if (fp_rcw_pbi_ip == NULL) {
+ printf("%s: Error in opening the rcw file: %s\n",
+ __func__, pblimg.rcw_nm);
+ goto exit_main;
+ }
+
+ fp_rcw_pbi_op = fopen(pblimg.imagefile, "wb+");
+ if (fp_rcw_pbi_op == NULL) {
+ printf("%s: Error opening the input file: %s\n",
+ __func__, pblimg.imagefile);
+ goto exit_main;
+ }
+
+ printf("\nInput Boot Source: %s\n", boot_src_string[pblimg.boot_src]);
+ printf("Input RCW File: %s\n", pblimg.rcw_nm);
+ printf("Input BL2 Binary File: %s\n", pblimg.sec_imgnm);
+ printf("Input load address for BL2 Binary File: 0x%x\n", pblimg.addr);
+
+ printf("Chassis Type: %d\n", pblimg.chassis);
+ switch (pblimg.chassis) {
+ case CHASSIS_2:
+ if (fread(&word, sizeof(word), NUM_MEM_BLOCK, fp_rcw_pbi_ip)
+ != NUM_MEM_BLOCK) {
+ printf("%s: Error in reading word from the rcw file.\n",
+ __func__);
+ goto exit_main;
+ }
+ while (BYTE_SWAP_32(word) != 0x08610040) {
+ if (BYTE_SWAP_32(word) == 0x09550000
+ || BYTE_SWAP_32(word) == 0x000f400c) {
+ break;
+ }
+ if (fwrite(&word, sizeof(word), NUM_MEM_BLOCK,
+ fp_rcw_pbi_op) != NUM_MEM_BLOCK) {
+ printf("%s: [CH2] Error in Writing PBI Words\n",
+ __func__);
+ goto exit_main;
+ }
+ if (fread(&word, sizeof(word), NUM_MEM_BLOCK,
+ fp_rcw_pbi_ip) != NUM_MEM_BLOCK) {
+ printf("%s: [CH2] Error in Reading PBI Words\n",
+ __func__);
+ goto exit_main;
+ }
+ }
+
+ if (bootptr_flag == true) {
+ /* Add command to set boot_loc ptr */
+ ret = add_boot_ptr_cmd(fp_rcw_pbi_op);
+ if (ret != SUCCESS) {
+ goto exit_main;
+ }
+ }
+
+ /* Write acs write commands to output file */
+ ret = add_cpy_cmd(fp_rcw_pbi_op);
+ if (ret != SUCCESS) {
+ goto exit_main;
+ }
+
+ /* Add stop command after adding pbi commands
+ * For Chasis 2.0 platforms it is always CRC &
+ * Stop command
+ */
+ flag_stop_cmd = CRC_STOP_COMMAND;
+ ret = add_pbi_stop_cmd(fp_rcw_pbi_op, flag_stop_cmd);
+ if (ret != SUCCESS) {
+ goto exit_main;
+ }
+
+ break;
+
+ case CHASSIS_3:
+ case CHASSIS_3_2:
+ if (fread(&word, sizeof(word), NUM_MEM_BLOCK, fp_rcw_pbi_ip)
+ != NUM_MEM_BLOCK) {
+ printf("%s: Error reading PBI Cmd.\n", __func__);
+ goto exit_main;
+ }
+ while (word != 0x808f0000 && word != 0x80ff0000) {
+ pbl_size++;
+ /* 11th words in RCW has PBL length. Update it
+ * with new length. 2 comamnds get added
+ * Block copy + CCSR Write/CSF header write
+ */
+ if (pbl_size == 11) {
+ word_1 = (word & PBI_LEN_MASK)
+ + (PBI_LEN_ADD << 20);
+ word = word & ~PBI_LEN_MASK;
+ word = word | word_1;
+ }
+ /* Update the CRC command */
+ /* Check load command..
+ * add a check if command is Stop with CRC
+ * or stop without checksum
+ */
+ if (pbl_size == 35) {
+ word = crypto_calculate_checksum(fp_rcw_pbi_op,
+ NUM_RCW_WORD - 1);
+ if (word == FAILURE) {
+ goto exit_main;
+ }
+ }
+ if (fwrite(&word, sizeof(word), NUM_MEM_BLOCK,
+ fp_rcw_pbi_op) != NUM_MEM_BLOCK) {
+ printf("%s: [CH3] Error in Writing PBI Words\n",
+ __func__);
+ goto exit_main;
+ }
+ if (fread(&word, sizeof(word), NUM_MEM_BLOCK,
+ fp_rcw_pbi_ip) != NUM_MEM_BLOCK) {
+ printf("%s: [CH3] Error in Reading PBI Words\n",
+ __func__);
+ goto exit_main;
+ }
+
+ if (word == CRC_STOP_CMD_ARM_CH3) {
+ flag_stop_cmd = CRC_STOP_COMMAND;
+ } else if (word == STOP_CMD_ARM_CH3) {
+ flag_stop_cmd = STOP_COMMAND;
+ }
+ }
+ if (bootptr_flag == true) {
+ /* Add command to set boot_loc ptr */
+ ret = add_boot_ptr_cmd(fp_rcw_pbi_op);
+ if (ret != SUCCESS) {
+ printf("%s: add_boot_ptr_cmd return failure.\n",
+ __func__);
+ goto exit_main;
+ }
+ }
+
+ /* Write acs write commands to output file */
+ ret = add_blk_cpy_cmd(fp_rcw_pbi_op, args);
+ if (ret != SUCCESS) {
+ printf("%s: Function add_blk_cpy_cmd return failure.\n",
+ __func__);
+ goto exit_main;
+ }
+
+ /* Add stop command after adding pbi commands */
+ ret = add_pbi_stop_cmd(fp_rcw_pbi_op, flag_stop_cmd);
+ if (ret != SUCCESS) {
+ goto exit_main;
+ }
+
+ break;
+
+ default:
+ printf("%s: Unknown chassis type.\n",
+ __func__);
+ }
+
+ if (ret == SUCCESS) {
+ printf("Output file successfully created with name: %s\n\n",
+ pblimg.imagefile);
+ }
+
+exit_main:
+ if (fp_rcw_pbi_op != NULL) {
+ fclose(fp_rcw_pbi_op);
+ }
+ if (fp_rcw_pbi_ip != NULL) {
+ fclose(fp_rcw_pbi_ip);
+ }
+
+ return ret;
+}
diff --git a/tools/nxp/create_pbl/create_pbl.mk b/tools/nxp/create_pbl/create_pbl.mk
new file mode 100644
index 0000000..305c049
--- /dev/null
+++ b/tools/nxp/create_pbl/create_pbl.mk
@@ -0,0 +1,52 @@
+#
+# Copyright 2018-2020 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+
+CREATE_PBL ?= ${CREATE_PBL_TOOL_PATH}/create_pbl${BIN_EXT}
+BYTE_SWAP ?= ${CREATE_PBL_TOOL_PATH}/byte_swap${BIN_EXT}
+
+HOST_GCC := gcc
+
+#SWAP is required for Chassis 2 platforms - LS102, ls1043 and ls1046 for QSPI
+ifeq (${SOC},ls1046a)
+SOC_NUM := 1046a
+SWAP = 1
+CH = 2
+else ifeq (${SOC},ls1043a)
+SOC_NUM := 1043a
+SWAP = 1
+CH = 2
+else ifeq (${SOC},ls1012a)
+SOC_NUM := 1012a
+SWAP = 1
+CH = 2
+else ifeq (${SOC},ls1088a)
+SOC_NUM := 1088a
+CH = 3
+else ifeq (${SOC},ls2088a)
+SOC_NUM := 2088a
+CH = 3
+else ifeq (${SOC},lx2160a)
+SOC_NUM := 2160a
+CH = 3
+else ifeq (${SOC},ls1028a)
+SOC_NUM := 1028a
+CH = 3
+else
+$(error "Check SOC Not defined in create_pbl.mk.")
+endif
+
+ifeq (${CH},2)
+
+include ${CREATE_PBL_TOOL_PATH}/pbl_ch2.mk
+
+endif #CH2
+
+ifeq (${CH},3)
+
+include ${CREATE_PBL_TOOL_PATH}/pbl_ch3.mk
+
+endif #CH3
diff --git a/tools/nxp/create_pbl/pbl_ch2.mk b/tools/nxp/create_pbl/pbl_ch2.mk
new file mode 100644
index 0000000..e6f1d8b
--- /dev/null
+++ b/tools/nxp/create_pbl/pbl_ch2.mk
@@ -0,0 +1,60 @@
+#
+# Copyright 2020 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+
+CREATE_PBL ?= ${CREATE_PBL_TOOL_PATH}/create_pbl${BIN_EXT}
+BYTE_SWAP ?= ${CREATE_PBL_TOOL_PATH}/byte_swap${BIN_EXT}
+
+HOST_GCC := gcc
+
+.PHONY: pbl
+pbl: ${BUILD_PLAT}/bl2.bin
+ifeq ($(SECURE_BOOT),yes)
+pbl: ${BUILD_PLAT}/bl2.bin
+ifeq ($(RCW),"")
+ ${Q}echo "Platform ${PLAT} requires rcw file. Please set RCW to point to the right RCW file for boot mode ${BOOT_MODE}"
+else
+ # Generate header for bl2.bin
+ $(Q)$(CST_DIR)/create_hdr_isbc --in ${BUILD_PLAT}/bl2.bin --out ${BUILD_PLAT}/hdr_bl2 ${BL2_INPUT_FILE}
+ # Compile create_pbl tool
+ ${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${CREATE_PBL_TOOL_PATH};\
+ # Add bl2.bin to RCW
+ ${CREATE_PBL} -r ${RCW} -i ${BUILD_PLAT}/bl2.bin -b ${BOOT_MODE} -c ${SOC_NUM} -d ${BL2_BASE} -e ${BL2_BASE}\
+ -o ${BUILD_PLAT}/bl2_${BOOT_MODE}.pbl ;\
+ # Add header to RCW
+ ${CREATE_PBL} -r ${BUILD_PLAT}/bl2_${BOOT_MODE}.pbl -i ${BUILD_PLAT}/hdr_bl2 -b ${BOOT_MODE} -c ${SOC_NUM} \
+ -d ${BL2_HDR_LOC} -e ${BL2_HDR_LOC} -o ${BUILD_PLAT}/bl2_${BOOT_MODE}_sec.pbl -s;\
+ rm ${BUILD_PLAT}/bl2_${BOOT_MODE}.pbl
+# Swapping of RCW is required for QSPi Chassis 2 devices
+ifeq (${BOOT_MODE}, qspi)
+ifeq ($(SWAP),1)
+ ${Q}echo "Byteswapping RCW for QSPI"
+ ${BYTE_SWAP} ${BUILD_PLAT}/bl2_${BOOT_MODE}_sec.pbl;
+endif # SWAP
+endif # BOOT_MODE
+ cd ${CREATE_PBL_TOOL_PATH}; ${MAKE} clean ; cd -;
+endif
+else # NON SECURE_BOOT
+ifeq ($(RCW),"")
+ ${Q}echo "Platform ${PLAT} requires rcw file. Please set RCW to point to the right RCW file for boot mode ${BOOT_MODE}"
+else
+ # -a option appends the image for Chassis 3 devices in case of non secure boot
+ ${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${CREATE_PBL_TOOL_PATH};
+ ${CREATE_PBL} -r ${RCW} -i ${BUILD_PLAT}/bl2.bin -b ${BOOT_MODE} -c ${SOC_NUM} -d ${BL2_BASE} -e ${BL2_BASE} \
+ -o ${BUILD_PLAT}/bl2_${BOOT_MODE}.pbl ;
+# Swapping of RCW is required for QSPi Chassis 2 devices
+ifeq (${BOOT_MODE}, qspi)
+ifeq ($(SWAP),1)
+ ${Q}echo "Byteswapping RCW for QSPI"
+ ${BYTE_SWAP} ${BUILD_PLAT}/bl2_${BOOT_MODE}.pbl;
+endif # SWAP
+endif # BOOT_MODE
+ cd ${CREATE_PBL_TOOL_PATH}; ${MAKE} clean ; cd -;
+endif
+endif # SECURE_BOOT
+
+
+
diff --git a/tools/nxp/create_pbl/pbl_ch3.mk b/tools/nxp/create_pbl/pbl_ch3.mk
new file mode 100644
index 0000000..9283474
--- /dev/null
+++ b/tools/nxp/create_pbl/pbl_ch3.mk
@@ -0,0 +1,71 @@
+#
+# Copyright 2018-2022 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+SHELL=/bin/bash
+
+CREATE_PBL ?= ${CREATE_PBL_TOOL_PATH}/create_pbl${BIN_EXT}
+BYTE_SWAP ?= ${CREATE_PBL_TOOL_PATH}/byte_swap${BIN_EXT}
+
+HOST_GCC := gcc
+
+BL2_SRC_OFFSET ?= 0x9000
+BL2_HDR_SRC_OFFSET ?= 0x5000
+bl2_hdr_loc=$(shell echo $$(( $(BL2_HDR_SRC_OFFSET) / 1024 )))
+bl2_loc=$(shell echo $$(( $(BL2_SRC_OFFSET) / 1024 )))
+
+.PHONY: pbl
+pbl: ${BUILD_PLAT}/bl2.bin
+ifeq ($(SECURE_BOOT),yes)
+pbl: ${BUILD_PLAT}/bl2.bin
+ifeq ($(RCW),"")
+ ${Q}echo "Platform ${PLAT} requires rcw file. Please set RCW to point to the right RCW file for boot mode ${BOOT_MODE}"
+else
+ # Generate header for bl2.bin
+ $(Q)$(CST_DIR)/create_hdr_isbc --in ${BUILD_PLAT}/bl2.bin --out ${BUILD_PLAT}/hdr_bl2 ${BL2_INPUT_FILE}
+
+ # Compile create_pbl tool
+ ${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${CREATE_PBL_TOOL_PATH};\
+
+ # Add Block Copy command for bl2.bin to RCW
+ ${CREATE_PBL} -r ${RCW} -i ${BUILD_PLAT}/bl2.bin -b ${BOOT_MODE} -c ${SOC_NUM} -d ${BL2_BASE} -e ${BL2_BASE}\
+ -o ${BUILD_PLAT}/bl2_${BOOT_MODE}.pbl -f ${BL2_SRC_OFFSET};\
+
+ # Add Block Copy command and Load CSF header command to RCW
+ ${CREATE_PBL} -r ${BUILD_PLAT}/bl2_${BOOT_MODE}.pbl -i ${BUILD_PLAT}/hdr_bl2 -b ${BOOT_MODE} -c ${SOC_NUM} \
+ -d ${BL2_HDR_LOC} -e ${BL2_HDR_LOC} -s -f ${BL2_HDR_SRC_OFFSET} \
+ -o ${BUILD_PLAT}/rcw_sec.pbl
+
+ # Sign and add "Load Security Header command to PBI commands
+ $(Q)$(CST_DIR)/create_hdr_pbi --out ${BUILD_PLAT}/bl2_${BOOT_MODE}_sec.pbl --in ${BUILD_PLAT}/rcw_sec.pbl ${PBI_INPUT_FILE}
+
+ # Append the bl2_hdr to the RCW image
+ @echo "${bl2_hdr_loc}"
+ dd if=${BUILD_PLAT}/hdr_bl2 of=${BUILD_PLAT}/bl2_${BOOT_MODE}_sec.pbl bs=1K seek=${bl2_hdr_loc}
+
+ # Append the bl2.bin to the RCW image
+ @echo "${bl2_loc}"
+ dd if=${BUILD_PLAT}/bl2.bin of=${BUILD_PLAT}/bl2_${BOOT_MODE}_sec.pbl bs=1K seek=${bl2_loc}
+
+ rm ${BUILD_PLAT}/bl2_${BOOT_MODE}.pbl
+ cd ${CREATE_PBL_TOOL_PATH}; ${MAKE} clean ; cd -;
+endif
+else #SECURE_BOOT
+ifeq ($(RCW),"")
+ ${Q}echo "Platform ${PLAT} requires rcw file. Please set RCW to point to the right RCW file for boot mode ${BOOT_MODE}"
+else
+ ${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${CREATE_PBL_TOOL_PATH};
+
+ # Add Block Copy command and populate boot loc ptrfor bl2.bin to RCW
+ ${CREATE_PBL} -r ${RCW} -i ${BUILD_PLAT}/bl2.bin -b ${BOOT_MODE} -c ${SOC_NUM} -d ${BL2_BASE} -e ${BL2_BASE} \
+ -o ${BUILD_PLAT}/bl2_${BOOT_MODE}.pbl -f ${BL2_SRC_OFFSET};
+
+ # Append the bl2.bin to the RCW image
+ @echo "bl2_loc is ${bl2_loc} KB"
+ dd if=${BUILD_PLAT}/bl2.bin of=${BUILD_PLAT}/bl2_${BOOT_MODE}.pbl bs=1K seek=${bl2_loc}
+
+ cd ${CREATE_PBL_TOOL_PATH}; ${MAKE} clean ; cd -;
+endif
+endif # SECURE_BOOT
diff --git a/tools/nxp/plat_fiptool/plat_def_uuid_config.c b/tools/nxp/plat_fiptool/plat_def_uuid_config.c
new file mode 100644
index 0000000..fdb4b93
--- /dev/null
+++ b/tools/nxp/plat_fiptool/plat_def_uuid_config.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <firmware_image_package.h>
+
+#include "tbbr_config.h"
+
+toc_entry_t plat_def_toc_entries[] = {
+ /* DDR PHY firmwares */
+ {
+ .name = "DDR UDIMM PHY IMEM 1d FW",
+ .uuid = UUID_DDR_IMEM_UDIMM_1D,
+ .cmdline_name = "ddr-immem-udimm-1d"
+ },
+ {
+ .name = "DDR UDIMM PHY IMEM 2d FW",
+ .uuid = UUID_DDR_IMEM_UDIMM_2D,
+ .cmdline_name = "ddr-immem-udimm-2d"
+ },
+ {
+ .name = "DDR UDIMM PHY DMEM 1d FW",
+ .uuid = UUID_DDR_DMEM_UDIMM_1D,
+ .cmdline_name = "ddr-dmmem-udimm-1d"
+ },
+ {
+ .name = "DDR UDIMM PHY DMEM 2d FW",
+ .uuid = UUID_DDR_DMEM_UDIMM_2D,
+ .cmdline_name = "ddr-dmmem-udimm-2d"
+ },
+ {
+ .name = "DDR RDIMM PHY IMEM 1d FW",
+ .uuid = UUID_DDR_IMEM_RDIMM_1D,
+ .cmdline_name = "ddr-immem-rdimm-1d"
+ },
+ {
+ .name = "DDR RDIMM PHY IMEM 2d FW",
+ .uuid = UUID_DDR_IMEM_RDIMM_2D,
+ .cmdline_name = "ddr-immem-rdimm-2d"
+ },
+ {
+ .name = "DDR RDIMM PHY DMEM 1d FW",
+ .uuid = UUID_DDR_DMEM_RDIMM_1D,
+ .cmdline_name = "ddr-dmmem-rdimm-1d"
+ },
+ {
+ .name = "DDR RDIMM PHY DMEM 2d FW",
+ .uuid = UUID_DDR_DMEM_RDIMM_2D,
+ .cmdline_name = "ddr-dmmem-rdimm-2d"
+ },
+ {
+ .name = "FUSE PROV FW",
+ .uuid = UUID_FUSE_PROV,
+ .cmdline_name = "fuse-prov"
+ },
+ {
+ .name = "FUSE UPGRADE FW",
+ .uuid = UUID_FUSE_UP,
+ .cmdline_name = "fuse-upgrade"
+ },
+
+ /* Key Certificates */
+ {
+ .name = "DDR Firmware key certificate",
+ .uuid = UUID_DDR_FW_KEY_CERT,
+ .cmdline_name = "ddr-fw-key-cert"
+ },
+
+ /* Content certificates */
+ {
+ .name = "DDR UDIMM Firmware content certificate",
+ .uuid = UUID_DDR_UDIMM_FW_CONTENT_CERT,
+ .cmdline_name = "ddr-udimm-fw-cert"
+ },
+ {
+ .name = "DDR RDIMM Firmware content certificate",
+ .uuid = UUID_DDR_RDIMM_FW_CONTENT_CERT,
+ .cmdline_name = "ddr-rdimm-fw-cert"
+ },
+
+ {
+ .name = NULL,
+ .uuid = { {0} },
+ .cmdline_name = NULL,
+ }
+};
diff --git a/tools/nxp/plat_fiptool/plat_fiptool.mk b/tools/nxp/plat_fiptool/plat_fiptool.mk
new file mode 100644
index 0000000..ca2962a
--- /dev/null
+++ b/tools/nxp/plat_fiptool/plat_fiptool.mk
@@ -0,0 +1,33 @@
+#
+# Copyright (c) 2021, NXP. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Name of the platform defined source file name,
+# which contains platform defined UUID entries populated
+# in the plat_def_toc_entries[].
+PLAT_DEF_UUID_CONFIG_FILE_NAME := plat_def_uuid_config
+
+PLAT_DEF_UUID_CONFIG_FILE_PATH := ../nxp/plat_fiptool
+
+PLAT_DEF_OID := yes
+PLAT_DEF_UUID := yes
+PLAT_DEF_UUID_OID_CONFIG_PATH := ../../plat/nxp/common/fip_handler/common
+
+
+INCLUDE_PATHS += -I${PLAT_DEF_UUID_OID_CONFIG_PATH} \
+ -I./
+# Clean the stale object file.
+$(shell rm ${PLAT_DEF_UUID_CONFIG_FILE_PATH}/${PLAT_DEF_UUID_CONFIG_FILE_NAME}.o)
+
+ifeq (${PLAT_DEF_OID},yes)
+HOSTCCFLAGS += -DPLAT_DEF_OID
+endif
+
+ifeq (${PLAT_DEF_UUID},yes)
+HOSTCCFLAGS += -DPLAT_DEF_FIP_UUID
+PLAT_OBJECTS += ${PLAT_DEF_UUID_CONFIG_FILE_PATH}/${PLAT_DEF_UUID_CONFIG_FILE_NAME}.o
+endif
+
+OBJECTS += ${PLAT_OBJECTS}
diff --git a/tools/renesas/rcar_layout_create/makefile b/tools/renesas/rcar_layout_create/makefile
new file mode 100644
index 0000000..d585754
--- /dev/null
+++ b/tools/renesas/rcar_layout_create/makefile
@@ -0,0 +1,121 @@
+#
+# 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
diff --git a/tools/renesas/rcar_layout_create/sa0.c b/tools/renesas/rcar_layout_create/sa0.c
new file mode 100644
index 0000000..79354ec
--- /dev/null
+++ b/tools/renesas/rcar_layout_create/sa0.c
@@ -0,0 +1,30 @@
+/*
+ * 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;
diff --git a/tools/renesas/rcar_layout_create/sa0.ld.S b/tools/renesas/rcar_layout_create/sa0.ld.S
new file mode 100644
index 0000000..98fee23
--- /dev/null
+++ b/tools/renesas/rcar_layout_create/sa0.ld.S
@@ -0,0 +1,28 @@
+/*
+ * 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))
+ }
+
+}
diff --git a/tools/renesas/rcar_layout_create/sa6.c b/tools/renesas/rcar_layout_create/sa6.c
new file mode 100644
index 0000000..8fafdad
--- /dev/null
+++ b/tools/renesas/rcar_layout_create/sa6.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#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 (0x00080000U)
+/* 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;
diff --git a/tools/renesas/rcar_layout_create/sa6.ld.S b/tools/renesas/rcar_layout_create/sa6.ld.S
new file mode 100644
index 0000000..9ca0c1d
--- /dev/null
+++ b/tools/renesas/rcar_layout_create/sa6.ld.S
@@ -0,0 +1,114 @@
+/*
+ * 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))
+ }
+
+}
diff --git a/tools/renesas/rzg_layout_create/makefile b/tools/renesas/rzg_layout_create/makefile
new file mode 100644
index 0000000..2d438b9
--- /dev/null
+++ b/tools/renesas/rzg_layout_create/makefile
@@ -0,0 +1,118 @@
+#
+# Copyright (c) 2020, 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))
+
+RCAR_VMA_ADJUST_ADDR := 0xE6320000
+$(eval $(call add_define,RCAR_VMA_ADJUST_ADDR))
+
+
+###################################################
+
+#c compiler
+CC = $(CROSS_COMPILE)gcc
+CFLAGS += ${DEFINES}
+CFLAGS += -nostdinc \
+ -I../../../include/lib/libc \
+ -I../../../include/lib/libc/aarch64
+
+#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
diff --git a/tools/renesas/rzg_layout_create/sa0.c b/tools/renesas/rzg_layout_create/sa0.c
new file mode 100644
index 0000000..763d3a5
--- /dev/null
+++ b/tools/renesas/rzg_layout_create/sa0.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define RCAR_SA0_SIZE_SMALL (0) /* for RZ/G2E */
+#define RCAR_SA0_SIZE_NORMAL (1) /* for RZ/G2[HMN] */
+
+#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;
diff --git a/tools/renesas/rzg_layout_create/sa0.ld.S b/tools/renesas/rzg_layout_create/sa0.ld.S
new file mode 100644
index 0000000..23e2b23
--- /dev/null
+++ b/tools/renesas/rzg_layout_create/sa0.ld.S
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2020, 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))
+ }
+
+}
diff --git a/tools/renesas/rzg_layout_create/sa6.c b/tools/renesas/rzg_layout_create/sa6.c
new file mode 100644
index 0000000..76e3dc5
--- /dev/null
+++ b/tools/renesas/rzg_layout_create/sa6.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2020, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#define RCAR_SA6_TYPE_QSPIFLASH (0)
+#define RCAR_SA6_TYPE_EMMC (1)
+
+#if (RCAR_SA6_TYPE == RCAR_SA6_TYPE_QSPIFLASH)
+
+/* 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 (0x00300000U)
+/* 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_EMMC */
+
+/* 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_QSPIFLASH */
+
+/* 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;
diff --git a/tools/renesas/rzg_layout_create/sa6.ld.S b/tools/renesas/rzg_layout_create/sa6.ld.S
new file mode 100644
index 0000000..efe40b0
--- /dev/null
+++ b/tools/renesas/rzg_layout_create/sa6.ld.S
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2020, 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))
+ }
+
+}
diff --git a/tools/sptool/Makefile b/tools/sptool/Makefile
new file mode 100644
index 0000000..1fa85fb
--- /dev/null
+++ b/tools/sptool/Makefile
@@ -0,0 +1,50 @@
+#
+# Copyright (c) 2018-2020, 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
+
+SPTOOL ?= sptool${BIN_EXT}
+PROJECT := $(notdir ${SPTOOL})
+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})
diff --git a/tools/sptool/sp_mk_generator.py b/tools/sptool/sp_mk_generator.py
new file mode 100644
index 0000000..f3af584
--- /dev/null
+++ b/tools/sptool/sp_mk_generator.py
@@ -0,0 +1,232 @@
+#!/usr/bin/python3
+# Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+"""
+This script is invoked by Make system and generates secure partition makefile.
+It expects platform provided secure partition layout file which contains list
+of Secure Partition Images and Partition manifests(PM).
+Layout file can exist outside of TF-A tree and the paths of Image and PM files
+must be relative to it.
+
+This script parses the layout file and generates a make file which updates
+FDT_SOURCES, FIP_ARGS, CRT_ARGS and SPTOOL_ARGS which are used in later build
+steps.
+If the SP entry in the layout file has a "uuid" field the scripts gets the UUID
+from there, otherwise it parses the associated partition manifest and extracts
+the UUID from there.
+
+param1: Generated mk file "sp_gen.mk"
+param2: "SP_LAYOUT_FILE", json file containing platform provided information
+param3: plat out directory
+param4: CoT parameter
+
+Generated "sp_gen.mk" file contains triplet of following information for each
+Secure Partition entry
+ FDT_SOURCES += sp1.dts
+ SPTOOL_ARGS += -i sp1.bin:sp1.dtb -o sp1.pkg
+ FIP_ARGS += --blob uuid=XXXXX-XXX...,file=sp1.pkg
+ CRT_ARGS += --sp-pkg1 sp1.pkg
+
+A typical SP_LAYOUT_FILE file will look like
+{
+ "SP1" : {
+ "image": "sp1.bin",
+ "pm": "test/sp1.dts"
+ },
+
+ "SP2" : {
+ "image": "sp2.bin",
+ "pm": "test/sp2.dts",
+ "uuid": "1b1820fe-48f7-4175-8999-d51da00b7c9f"
+ }
+
+ ...
+}
+
+"""
+import json
+import os
+import re
+import sys
+import uuid
+from spactions import SpSetupActions
+
+MAX_SP = 8
+UUID_LEN = 4
+
+# Some helper functions to access args propagated to the action functions in
+# SpSetupActions framework.
+def check_sp_mk_gen(args :dict):
+ if "sp_gen_mk" not in args.keys():
+ raise Exception(f"Path to file sp_gen.mk needs to be in 'args'.")
+
+def check_out_dir(args :dict):
+ if "out_dir" not in args.keys() or not os.path.isdir(args["out_dir"]):
+ raise Exception("Define output folder with \'out_dir\' key.")
+
+def check_sp_layout_dir(args :dict):
+ if "sp_layout_dir" not in args.keys() or not os.path.isdir(args["sp_layout_dir"]):
+ raise Exception("Define output folder with \'sp_layout_dir\' key.")
+
+def write_to_sp_mk_gen(content, args :dict):
+ check_sp_mk_gen(args)
+ with open(args["sp_gen_mk"], "a") as f:
+ f.write(f"{content}\n")
+
+def get_sp_manifest_full_path(sp_node, args :dict):
+ check_sp_layout_dir(args)
+ return os.path.join(args["sp_layout_dir"], get_file_from_layout(sp_node["pm"]))
+
+def get_sp_img_full_path(sp_node, args :dict):
+ check_sp_layout_dir(args)
+ return os.path.join(args["sp_layout_dir"], get_file_from_layout(sp_node["image"]))
+
+def get_sp_pkg(sp, args :dict):
+ check_out_dir(args)
+ return os.path.join(args["out_dir"], f"{sp}.pkg")
+
+def is_line_in_sp_gen(line, args :dict):
+ with open(args["sp_gen_mk"], "r") as f:
+ sppkg_rule = [l for l in f if line in l]
+ return len(sppkg_rule) != 0
+
+def get_file_from_layout(node):
+ ''' Helper to fetch a file path from sp_layout.json. '''
+ if type(node) is dict and "file" in node.keys():
+ return node["file"]
+ return node
+
+def get_offset_from_layout(node):
+ ''' Helper to fetch an offset from sp_layout.json. '''
+ if type(node) is dict and "offset" in node.keys():
+ return int(node["offset"], 0)
+ return None
+
+def get_image_offset(node):
+ ''' Helper to fetch image offset from sp_layout.json '''
+ return get_offset_from_layout(node["image"])
+
+def get_pm_offset(node):
+ ''' Helper to fetch pm offset from sp_layout.json '''
+ return get_offset_from_layout(node["pm"])
+
+@SpSetupActions.sp_action(global_action=True)
+def check_max_sps(sp_layout, _, args :dict):
+ ''' Check validate the maximum number of SPs is respected. '''
+ if len(sp_layout.keys()) > MAX_SP:
+ raise Exception(f"Too many SPs in SP layout file. Max: {MAX_SP}")
+ return args
+
+@SpSetupActions.sp_action
+def gen_fdt_sources(sp_layout, sp, args :dict):
+ ''' Generate FDT_SOURCES values for a given SP. '''
+ manifest_path = get_sp_manifest_full_path(sp_layout[sp], args)
+ write_to_sp_mk_gen(f"FDT_SOURCES += {manifest_path}", args)
+ return args
+
+@SpSetupActions.sp_action
+def gen_sptool_args(sp_layout, sp, args :dict):
+ ''' Generate Sp Pkgs rules. '''
+ sp_pkg = get_sp_pkg(sp, args)
+ sp_dtb_name = os.path.basename(get_file_from_layout(sp_layout[sp]["pm"]))[:-1] + "b"
+ sp_dtb = os.path.join(args["out_dir"], f"fdts/{sp_dtb_name}")
+
+ # Do not generate rule if already there.
+ if is_line_in_sp_gen(f'{sp_pkg}:', args):
+ return args
+ write_to_sp_mk_gen(f"SP_PKGS += {sp_pkg}\n", args)
+
+ sptool_args = f" -i {get_sp_img_full_path(sp_layout[sp], args)}:{sp_dtb}"
+ pm_offset = get_pm_offset(sp_layout[sp])
+ sptool_args += f" --pm-offset {pm_offset}" if pm_offset is not None else ""
+ image_offset = get_image_offset(sp_layout[sp])
+ sptool_args += f" --img-offset {image_offset}" if image_offset is not None else ""
+ sptool_args += f" -o {sp_pkg}"
+ sppkg_rule = f'''
+{sp_pkg}: {sp_dtb}
+\t$(Q)echo Generating {sp_pkg}
+\t$(Q)$(PYTHON) $(SPTOOL) {sptool_args}
+'''
+ write_to_sp_mk_gen(sppkg_rule, args)
+ return args
+
+@SpSetupActions.sp_action(global_action=True, exec_order=1)
+def check_dualroot(sp_layout, _, args :dict):
+ ''' Validate the amount of SPs from SiP and Platform owners. '''
+ if not args.get("dualroot"):
+ return args
+ args["split"] = int(MAX_SP / 2)
+ owners = [sp_layout[sp].get("owner") for sp in sp_layout]
+ args["plat_max_count"] = owners.count("Plat")
+ # If it is owned by the platform owner, it is assigned to the SiP.
+ args["sip_max_count"] = len(sp_layout.keys()) - args["plat_max_count"]
+ if args["sip_max_count"] > args["split"] or args["sip_max_count"] > args["split"]:
+ print(f"WARN: SiP Secure Partitions should not be more than {args['split']}")
+ # Counters for gen_crt_args.
+ args["sip_count"] = 1
+ args["plat_count"] = 1
+ return args
+
+@SpSetupActions.sp_action
+def gen_crt_args(sp_layout, sp, args :dict):
+ ''' Append CRT_ARGS. '''
+ # If "dualroot" is configured, 'sp_pkg_idx' depends on whether the SP is owned
+ # by the "SiP" or the "Plat".
+ if args.get("dualroot"):
+ # If the owner is not specified as "Plat", default to "SiP".
+ if sp_layout[sp].get("owner") == "Plat":
+ if args["plat_count"] > args["plat_max_count"]:
+ raise ValueError("plat_count can't surpass plat_max_count in args.")
+ sp_pkg_idx = args["plat_count"] + args["split"]
+ args["plat_count"] += 1
+ else:
+ if args["sip_count"] > args["sip_max_count"]:
+ raise ValueError("sip_count can't surpass sip_max_count in args.")
+ sp_pkg_idx = args["sip_count"]
+ args["sip_count"] += 1
+ else:
+ sp_pkg_idx = [k for k in sp_layout.keys()].index(sp) + 1
+ write_to_sp_mk_gen(f"CRT_ARGS += --sp-pkg{sp_pkg_idx} {get_sp_pkg(sp, args)}\n", args)
+ return args
+
+@SpSetupActions.sp_action
+def gen_fiptool_args(sp_layout, sp, args :dict):
+ ''' Generate arguments for the FIP Tool. '''
+ if "uuid" in sp_layout[sp]:
+ # Extract the UUID from the JSON file if the SP entry has a 'uuid' field
+ uuid_std = uuid.UUID(sp_layout[sp]['uuid'])
+ else:
+ with open(get_sp_manifest_full_path(sp_layout[sp], args), "r") as pm_f:
+ uuid_lines = [l for l in pm_f if 'uuid' in l]
+ assert(len(uuid_lines) == 1)
+ # The uuid field in SP manifest is the little endian representation
+ # mapped to arguments as described in SMCCC section 5.3.
+ # Convert each unsigned integer value to a big endian representation
+ # required by fiptool.
+ uuid_parsed = re.findall("0x([0-9a-f]+)", uuid_lines[0])
+ y = list(map(bytearray.fromhex, uuid_parsed))
+ z = [int.from_bytes(i, byteorder='little', signed=False) for i in y]
+ uuid_std = uuid.UUID(f'{z[0]:08x}{z[1]:08x}{z[2]:08x}{z[3]:08x}')
+ write_to_sp_mk_gen(f"FIP_ARGS += --blob uuid={str(uuid_std)},file={get_sp_pkg(sp, args)}\n", args)
+ return args
+
+def init_sp_actions(sys):
+ sp_layout_file = os.path.abspath(sys.argv[2])
+ with open(sp_layout_file) as json_file:
+ sp_layout = json.load(json_file)
+ # Initialize arguments for the SP actions framework
+ args = {}
+ args["sp_gen_mk"] = os.path.abspath(sys.argv[1])
+ args["sp_layout_dir"] = os.path.dirname(sp_layout_file)
+ args["out_dir"] = os.path.abspath(sys.argv[3])
+ args["dualroot"] = sys.argv[4] == "dualroot"
+ #Clear content of file "sp_gen.mk".
+ with open(args["sp_gen_mk"], "w"):
+ None
+ return args, sp_layout
+
+if __name__ == "__main__":
+ args, sp_layout = init_sp_actions(sys)
+ SpSetupActions.run_actions(sp_layout, args)
diff --git a/tools/sptool/spactions.py b/tools/sptool/spactions.py
new file mode 100644
index 0000000..ff28ebb
--- /dev/null
+++ b/tools/sptool/spactions.py
@@ -0,0 +1,155 @@
+#!/usr/bin/python3
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+'''
+This is a python module for defining and executing SP setup actions, targeting
+a system deploying an SPM implementation.
+Each action consists of a function, that processes the SP layout json file and
+other provided arguments.
+At the core of this is the SpSetupActions which provides a means to register
+the functions into a table of actions, and execute them all when invoking
+SpSetupActions.run_actions.
+Registering the function is done by using the decorator '@SpSetupActions.sp_action'
+at function definition.
+
+Functions can be called:
+- once only, or per SP defined in the SP layout file;
+- following an order, from lowest to highest of their execution order.
+More information in the doc comments below.
+'''
+import bisect
+
+DEFAULT_ACTION_ORDER = 100
+
+class _ConfiguredAction:
+ """
+ Wraps action function with its configuration.
+ """
+ def __init__(self, action, exec_order=DEFAULT_ACTION_ORDER, global_action=True, log_calls = False):
+ self.exec_order = exec_order
+ self.__name__ = action.__name__
+ def logged_action(action):
+ def inner_logged_action(sp_layout, sp, args :dict):
+ print(f"Calling {action.__name__} -> {sp}")
+ return action(sp_layout, sp, args)
+ return inner_logged_action
+ self.action = logged_action(action) if log_calls is True else action
+ self.global_action = global_action
+
+ def __lt__(self, other):
+ """
+ To allow for ordered inserts in a list of actions.
+ """
+ return self.exec_order < other.exec_order
+
+ def __call__(self, sp_layout, sp, args :dict):
+ """
+ Calls action function.
+ """
+ return self.action(sp_layout, sp, args)
+
+ def __repr__(self) -> str:
+ """
+ Pretty format to show debug information about the action.
+ """
+ return f"func: {self.__name__}; global:{self.global_action}; exec_order: {self.exec_order}"
+
+class SpSetupActions:
+ actions = []
+
+ def sp_action(in_action = None, global_action = False, log_calls=False, exec_order=DEFAULT_ACTION_ORDER):
+ """
+ Function decorator that registers and configures action.
+
+ :param in_action - function to register
+ :param global_action - make the function global, i.e. make it be
+ only called once.
+ :param log_calls - at every call to action, a useful log will be printed.
+ :param exec_order - action's calling order.
+ """
+ def append_action(action):
+ action = _ConfiguredAction(action, exec_order, global_action, log_calls)
+ bisect.insort(SpSetupActions.actions, action)
+ return action
+ if in_action is not None:
+ return append_action(in_action)
+ return append_action
+
+ def run_actions(sp_layout: dict, args: dict, verbose=False):
+ """
+ Executes all actions in accordance to their registering configuration:
+ - If set as "global" it will be called once.
+ - Actions are called respecting the order established by their "exec_order" field.
+
+ :param sp_layout - dictionary containing the SP layout information.
+ :param args - arguments to be propagated through the call of actions.
+ :param verbose - prints actions information in order of execution.
+ """
+ args["called"] = [] # for debug purposes
+ def append_called(action, sp, args :dict):
+ args["called"].append(f"{action.__name__} -> {sp}")
+ return args
+
+ for action in SpSetupActions.actions:
+ if verbose:
+ print(f"Calling {action}")
+ if action.global_action:
+ scope = "global"
+ args = action(sp_layout, scope, args)
+ args = append_called(action, scope, args)
+ else:
+ # Functions that are not global called for each SP defined in
+ # the SP layout.
+ for sp in sp_layout.keys():
+ args = action(sp_layout, sp, args)
+ args = append_called(action, sp, args)
+
+if __name__ == "__main__":
+ # Executing this module will have the following test code/playground executed
+ sp_layout = {
+ "partition1" : {
+ "boot-info": True,
+ "image": {
+ "file": "partition.bin",
+ "offset":"0x2000"
+ },
+ "pm": {
+ "file": "cactus.dts",
+ "offset":"0x1000"
+ },
+ "owner": "SiP"
+ },
+ "partition2" : {
+ "image": "partition.bin",
+ "pm": "cactus-secondary.dts",
+ "owner": "Plat"
+ },
+ "partition3" : {
+ "image": "partition.bin",
+ "pm": "cactus-tertiary.dts",
+ "owner": "Plat"
+ },
+ "partition4" : {
+ "image": "ivy.bin",
+ "pm": "ivy.dts",
+ "owner": "Plat"
+ }
+ }
+
+ #Example of how to use this module
+ @SpSetupActions.sp_action(global_action=True)
+ def my_action1(sp_layout, _, args :dict):
+ print(f"inside function my_action1{sp_layout}\n\n args:{args})")
+ return args # Always return args in action function.
+ @SpSetupActions.sp_action(exec_order=1)
+ def my_action2(sp_layout, sp_name, args :dict):
+ print(f"inside function my_action2; SP: {sp_name} {sp_layout} args:{args}")
+ return args
+
+ # Example arguments to be propagated through the functions.
+ # 'args' can be extended in the action functions.
+ args = dict()
+ args["arg1"] = 0xEEE
+ args["arg2"] = 0xFF
+ SpSetupActions.run_actions(sp_layout, args)
diff --git a/tools/sptool/sptool.py b/tools/sptool/sptool.py
new file mode 100755
index 0000000..ae7df92
--- /dev/null
+++ b/tools/sptool/sptool.py
@@ -0,0 +1,145 @@
+#!/usr/bin/python3
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+#
+# Copyright 2022 The Hafnium Authors.
+#
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file or at
+# https://opensource.org/licenses/BSD-3-Clause.
+
+"""
+Script which generates a Secure Partition package.
+https://trustedfirmware-a.readthedocs.io/en/latest/components/secure-partition-manager.html#secure-partition-packages
+"""
+
+import argparse
+from collections import namedtuple
+import sys
+from shutil import copyfileobj
+import os
+
+HF_PAGE_SIZE = 0x1000 # bytes
+HEADER_ELEMENT_BYTES = 4 # bytes
+MANIFEST_IMAGE_SPLITTER=':'
+PM_OFFSET_DEFAULT = "0x1000"
+IMG_OFFSET_DEFAULT = "0x4000"
+
+def split_dtb_bin(i : str):
+ return i.split(MANIFEST_IMAGE_SPLITTER)
+
+def align_to_page(n):
+ return HF_PAGE_SIZE * \
+ (round(n / HF_PAGE_SIZE) + \
+ (1 if n % HF_PAGE_SIZE else 0))
+
+def to_bytes(value):
+ return int(value).to_bytes(HEADER_ELEMENT_BYTES, 'little')
+
+class SpPkg:
+ def __init__(self, pm_path : str, img_path : str, pm_offset: int,
+ img_offset: int):
+ if not os.path.isfile(pm_path) or not os.path.isfile(img_path):
+ raise Exception(f"Parameters should be path. \
+ manifest: {pm_path}; img: {img_path}")
+ self.pm_path = pm_path
+ self.img_path = img_path
+ self._SpPkgHeader = namedtuple("SpPkgHeader",
+ ("magic", "version",
+ "pm_offset", "pm_size",
+ "img_offset", "img_size"))
+
+ if pm_offset >= img_offset:
+ raise ValueError("pm_offset must be smaller than img_offset")
+
+ is_hfpage_aligned = lambda val : val % HF_PAGE_SIZE == 0
+ if not is_hfpage_aligned(pm_offset) or not is_hfpage_aligned(img_offset):
+ raise ValueError(f"Offsets provided need to be page aligned: pm-{pm_offset}, img-{img_offset}")
+
+ if img_offset - pm_offset < self.pm_size:
+ raise ValueError(f"pm_offset and img_offset do not fit the specified file:{pm_path})")
+
+ self.pm_offset = pm_offset
+ self.img_offset = img_offset
+
+ def __str__(self):
+ return \
+ f'''--SP package Info--
+ header:{self.header}
+ pm: {self.pm_path}
+ img: {self.img_path}
+ '''
+
+ @property
+ def magic(self):
+ return "SPKG".encode()
+
+ @property
+ def version(self):
+ return 0x2
+
+ @property
+ def pm_size(self):
+ return os.path.getsize(self.pm_path)
+
+ @property
+ def img_size(self):
+ return os.path.getsize(self.img_path)
+
+ @property
+ def header(self):
+ return self._SpPkgHeader(
+ self.magic,
+ self.version,
+ self.pm_offset,
+ self.pm_size,
+ self.img_offset,
+ self.img_size)
+
+ @property
+ def header_size(self):
+ return len(self._SpPkgHeader._fields)
+
+ def generate(self, f_out : str):
+ with open(f_out, "wb+") as output:
+ for h in self.header:
+ to_write = h if type(h) is bytes else to_bytes(h)
+ output.write(to_write)
+ output.seek(self.pm_offset)
+ with open(self.pm_path, "rb") as pm:
+ copyfileobj(pm, output)
+ output.seek(self.img_offset)
+ with open(self.img_path, "rb") as img:
+ copyfileobj(img, output)
+
+def Main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-i", required=True,
+ help="path to partition's image and manifest separated by a colon.")
+ parser.add_argument("--pm-offset", required=False, default=PM_OFFSET_DEFAULT,
+ help="set partitition manifest offset.")
+ parser.add_argument("--img-offset", required=False, default=IMG_OFFSET_DEFAULT,
+ help="set partition image offset.")
+ parser.add_argument("-o", required=True, help="set output file path.")
+ parser.add_argument("-v", required=False, action="store_true",
+ help="print package information.")
+ args = parser.parse_args()
+
+ if not os.path.exists(os.path.dirname(args.o)):
+ raise Exception("Provide a valid output file path!\n")
+
+ image_path, manifest_path = split_dtb_bin(args.i)
+ pm_offset = int(args.pm_offset, 0)
+ img_offset = int(args.img_offset, 0)
+ pkg = SpPkg(manifest_path, image_path, pm_offset, img_offset)
+ pkg.generate(args.o)
+
+ if args.v is True:
+ print(pkg)
+
+ return 0
+
+if __name__ == "__main__":
+ sys.exit(Main())
diff --git a/tools/stm32image/Makefile b/tools/stm32image/Makefile
new file mode 100644
index 0000000..9c9b7b5
--- /dev/null
+++ b/tools/stm32image/Makefile
@@ -0,0 +1,49 @@
+#
+# 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
diff --git a/tools/stm32image/stm32image.c b/tools/stm32image/stm32image.c
new file mode 100644
index 0000000..bd4720c
--- /dev/null
+++ b/tools/stm32image/stm32image.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm/byteorder.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/* 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 HEADER_VERSION_V2 0x2
+#define PADDING_HEADER_MAGIC __be32_to_cpu(0x5354FFFF)
+#define PADDING_HEADER_FLAG (1 << 31)
+#define PADDING_HEADER_LENGTH 0x180
+
+struct stm32_header_v1 {
+ 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;
+};
+
+struct stm32_header_v2 {
+ 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 extension_flags;
+ uint32_t extension_headers_length;
+ uint32_t binary_type;
+ uint8_t padding[16];
+ uint32_t extension_header_type;
+ uint32_t extension_header_length;
+ uint8_t extension_padding[376];
+};
+
+static void stm32image_default_header(void *ptr)
+{
+ struct stm32_header_v1 *header = (struct stm32_header_v1 *)ptr;
+
+ if (!header) {
+ return;
+ }
+
+ header->magic_number = HEADER_MAGIC;
+ header->version_number = __cpu_to_le32(0);
+}
+
+static uint32_t stm32image_checksum(void *start, uint32_t len,
+ uint32_t header_size)
+{
+ uint32_t csum = 0;
+ uint8_t *p;
+
+ if (len < header_size) {
+ return 0;
+ }
+
+ p = (unsigned char *)start + header_size;
+ len -= header_size;
+
+ while (len > 0) {
+ csum += *p;
+ p++;
+ len--;
+ }
+
+ return csum;
+}
+
+static void stm32image_print_header(const void *ptr)
+{
+ struct stm32_header_v1 *stm32hdr = (struct stm32_header_v1 *)ptr;
+ struct stm32_header_v2 *stm32hdr_v2 = (struct stm32_header_v2 *)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));
+
+ switch (stm32hdr->header_version[VER_MAJOR]) {
+ case HEADER_VERSION_V1:
+ printf("Option : 0x%08x\n",
+ __le32_to_cpu(stm32hdr->option_flags));
+ break;
+
+ case HEADER_VERSION_V2:
+ printf("Extension : 0x%08x\n",
+ __le32_to_cpu(stm32hdr_v2->extension_flags));
+ break;
+
+ default:
+ printf("Incorrect header version\n");
+ }
+
+ printf("Version : 0x%08x\n",
+ __le32_to_cpu(stm32hdr->version_number));
+}
+
+static int stm32image_set_header(void *ptr, struct stat *sbuf, int ifd,
+ uint32_t loadaddr, uint32_t ep, uint32_t ver,
+ uint32_t major, uint32_t minor,
+ uint32_t binary_type, uint32_t header_size)
+{
+ struct stm32_header_v1 *stm32hdr = (struct stm32_header_v1 *)ptr;
+ struct stm32_header_v2 *stm32hdr_v2 = (struct stm32_header_v2 *)ptr;
+ uint32_t ext_size = 0U;
+ uint32_t ext_flags = 0U;
+
+ stm32image_default_header(ptr);
+
+ stm32hdr->header_version[VER_MAJOR] = major;
+ stm32hdr->header_version[VER_MINOR] = minor;
+ stm32hdr->load_address = __cpu_to_le32(loadaddr);
+ stm32hdr->image_entry_point = __cpu_to_le32(ep);
+ stm32hdr->image_length = __cpu_to_le32((uint32_t)sbuf->st_size -
+ header_size);
+ stm32hdr->image_checksum =
+ __cpu_to_le32(stm32image_checksum(ptr, sbuf->st_size,
+ header_size));
+
+ switch (stm32hdr->header_version[VER_MAJOR]) {
+ case HEADER_VERSION_V1:
+ /* Default option for header v1 : bit0 => no signature */
+ stm32hdr->option_flags = __cpu_to_le32(0x00000001);
+ stm32hdr->ecdsa_algorithm = __cpu_to_le32(1);
+ stm32hdr->binary_type = (uint8_t)binary_type;
+ break;
+
+ case HEADER_VERSION_V2:
+ stm32hdr_v2->binary_type = binary_type;
+ ext_size += PADDING_HEADER_LENGTH;
+ ext_flags |= PADDING_HEADER_FLAG;
+ stm32hdr_v2->extension_flags =
+ __cpu_to_le32(ext_flags);
+ stm32hdr_v2->extension_headers_length =
+ __cpu_to_le32(ext_size);
+ stm32hdr_v2->extension_header_type = PADDING_HEADER_MAGIC;
+ stm32hdr_v2->extension_header_length =
+ __cpu_to_le32(PADDING_HEADER_LENGTH);
+ break;
+
+ default:
+ return -1;
+ }
+
+ stm32hdr->version_number = __cpu_to_le32(ver);
+
+ return 0;
+}
+
+static int stm32image_create_header_file(char *srcname, char *destname,
+ uint32_t loadaddr, uint32_t entry,
+ uint32_t version, uint32_t major,
+ uint32_t minor, uint32_t binary_type)
+{
+ int src_fd, dest_fd, header_size;
+ struct stat sbuf;
+ unsigned char *ptr;
+ void *stm32image_header;
+
+ 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;
+ }
+
+ switch (major) {
+ case HEADER_VERSION_V1:
+ stm32image_header = malloc(sizeof(struct stm32_header_v1));
+ header_size = sizeof(struct stm32_header_v1);
+ break;
+
+ case HEADER_VERSION_V2:
+ stm32image_header = malloc(sizeof(struct stm32_header_v2));
+ header_size = sizeof(struct stm32_header_v2);
+ break;
+
+ default:
+ return -1;
+ }
+
+ memset(stm32image_header, 0, header_size);
+ if (write(dest_fd, stm32image_header, header_size) !=
+ header_size) {
+ fprintf(stderr, "Write error %s: %s\n", destname,
+ strerror(errno));
+ free(stm32image_header);
+ return -1;
+ }
+
+ free(stm32image_header);
+
+ 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 write %s\n", destname);
+ return -1;
+ }
+
+ if (stm32image_set_header(ptr, &sbuf, dest_fd, loadaddr,
+ entry, version, major, minor,
+ binary_type, header_size) != 0) {
+ return -1;
+ }
+
+ stm32image_print_header(ptr);
+
+ munmap((void *)ptr, sbuf.st_size);
+ close(dest_fd);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int opt;
+ int loadaddr = -1;
+ int entry = -1;
+ int err = 0;
+ int version = 0;
+ int binary_type = -1;
+ int major = HEADER_VERSION_V2;
+ int minor = 0;
+ char *dest = NULL;
+ char *src = NULL;
+
+ while ((opt = getopt(argc, argv, ":b:s:d:l:e:v:m:n:")) != -1) {
+ switch (opt) {
+ case 'b':
+ binary_type = strtol(optarg, NULL, 0);
+ break;
+ case 's':
+ src = optarg;
+ break;
+ case 'd':
+ dest = optarg;
+ break;
+ case 'l':
+ loadaddr = strtol(optarg, NULL, 0);
+ break;
+ case 'e':
+ entry = strtol(optarg, NULL, 0);
+ break;
+ case 'v':
+ version = strtol(optarg, NULL, 0);
+ break;
+ case 'm':
+ major = strtol(optarg, NULL, 0);
+ break;
+ case 'n':
+ minor = strtol(optarg, NULL, 0);
+ break;
+ default:
+ fprintf(stderr,
+ "Usage : %s [-s srcfile] [-d destfile] [-l loadaddr] [-e entry_point] [-m major] [-n minor] [-b binary_type]\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;
+ }
+
+ if (binary_type == -1) {
+ fprintf(stderr, "Missing -b option\n");
+ return -1;
+ }
+
+ err = stm32image_create_header_file(src, dest, loadaddr,
+ entry, version, major, minor,
+ binary_type);
+
+ return err;
+}